From e59caa03ed61fb877391bd9f3fb446b7d97585c4 Mon Sep 17 00:00:00 2001 From: Greg Book Date: Tue, 28 Apr 2015 14:19:50 -0400 Subject: [PATCH] Initial commit --- .gitignore | 1 + NiDBUploader.pro | 82 + NiDBUploader.pro.user | 444 + NiDBUploader.sh | 2 + README.md | 4 + anonymize.cpp | 11 + anonymize.h | 10 + gdcm/AUTHORS | 52 + gdcm/Applications/CMakeLists.txt | 1 + gdcm/Applications/Cxx/CMakeLists.txt | 217 + gdcm/Applications/Cxx/deflate.cxx | 116 + gdcm/Applications/Cxx/gdcm.cxx | 51 + gdcm/Applications/Cxx/gdcmanon.cxx | 829 + gdcm/Applications/Cxx/gdcmcheck.cxx | 24 + gdcm/Applications/Cxx/gdcmconv.cxx | 1464 + gdcm/Applications/Cxx/gdcmdictdump.cxx | 4 + gdcm/Applications/Cxx/gdcmdiff.cxx | 255 + gdcm/Applications/Cxx/gdcmdump.cxx | 1620 + gdcm/Applications/Cxx/gdcmfile.cxx | 83 + gdcm/Applications/Cxx/gdcmgendir.cxx | 349 + gdcm/Applications/Cxx/gdcmimg.cxx | 1237 + gdcm/Applications/Cxx/gdcminfo.cxx | 747 + gdcm/Applications/Cxx/gdcmkey.cxx | 34 + gdcm/Applications/Cxx/gdcmoverlay.cxx | 192 + gdcm/Applications/Cxx/gdcmpap3.cxx | 622 + gdcm/Applications/Cxx/gdcmpdf.cxx | 666 + gdcm/Applications/Cxx/gdcmraw.cxx | 413 + gdcm/Applications/Cxx/gdcmscanner.cxx | 283 + gdcm/Applications/Cxx/gdcmscu.cxx | 745 + gdcm/Applications/Cxx/gdcmstream.cxx | 1123 + gdcm/Applications/Cxx/gdcmtar.cxx | 1300 + gdcm/Applications/Cxx/gdcmxml.cxx | 918 + gdcm/Applications/Cxx/pdf2dcm.cxx | 21 + gdcm/Applications/Cxx/puff.c | 837 + gdcm/Applications/Cxx/puff.h | 44 + gdcm/Applications/Python/README | 62 + gdcm/Applications/Python/accessdata.py | 75 + gdcm/Applications/Python/images.py | 111 + gdcm/Applications/Python/lib.py | 27 + gdcm/Applications/Python/wado.py | 189 + gdcm/Applications/README.txt | 10 + gdcm/CMake/CMakeCSharpCompiler.cmake.in | 56 + gdcm/CMake/CMakeCSharpInformation.cmake | 92 + gdcm/CMake/CMakeDetermineCSharpCompiler.cmake | 67 + gdcm/CMake/CMakeTestCSharpCompiler.cmake | 51 + gdcm/CMake/COPYING-CMAKE-SCRIPTS | 22 + gdcm/CMake/CTestCustom.ctest.in | 46 + gdcm/CMake/ExportConfiguration/CMakeLists.txt | 133 + .../ExportConfiguration/GDCMConfig.cmake.in | 55 + .../GDCMConfigVersion.cmake.in | 21 + .../ExportConfiguration/UseGDCM.cmake.in | 31 + gdcm/CMake/FindACTIVIZ.cmake | 51 + gdcm/CMake/FindCSharp.cmake | 24 + gdcm/CMake/FindCharLS.cmake | 40 + gdcm/CMake/FindDCMTK.cmake | 152 + gdcm/CMake/FindDICOM3TOOLS.cmake | 61 + gdcm/CMake/FindDotNETFrameworkSDK.cmake | 52 + gdcm/CMake/FindJNI.cmake | 83 + gdcm/CMake/FindJSON.cmake | 39 + gdcm/CMake/FindJava.cmake | 152 + gdcm/CMake/FindJavaProperties.cmake | 92 + gdcm/CMake/FindKAKADU.cmake | 19 + gdcm/CMake/FindKWStyle.cmake | 35 + gdcm/CMake/FindLJPEG.cmake | 49 + gdcm/CMake/FindMAGIC.cmake | 48 + gdcm/CMake/FindMONO.cmake | 72 + gdcm/CMake/FindMd5sum.cmake | 68 + gdcm/CMake/FindOpenJPEG.cmake | 53 + gdcm/CMake/FindOpenSSL.cmake | 123 + gdcm/CMake/FindPAPYRUS3.cmake | 37 + gdcm/CMake/FindPHP5.cmake | 47 + gdcm/CMake/FindPVRGJPEG.cmake | 38 + gdcm/CMake/FindPoppler.cmake | 40 + gdcm/CMake/FindRsync.cmake | 26 + gdcm/CMake/FindSOCKET++.cmake | 33 + gdcm/CMake/FindSQLITE3.cmake | 19 + gdcm/CMake/FindUUID.cmake | 71 + gdcm/CMake/GetSystemProperty.java | 40 + gdcm/CMake/InstallMacros.cmake | 101 + gdcm/CMake/InstallRequiredVTKLibraries.cmake | 54 + gdcm/CMake/Release/README.cygwin.in | 0 gdcm/CMake/Release/cygwin-package.sh.in | 0 gdcm/CMake/Release/cygwin-patch.diff.in | 0 gdcm/CMake/Release/cygwin-setup.hint.in | 0 .../Toolchain-gcc-arm-linux-gnueabi.cmake | 40 + gdcm/CMake/Toolchain-gcc-m32.cmake | 39 + gdcm/CMake/Toolchain-gcc-powerpc.cmake | 56 + gdcm/CMake/Toolchain-mingw32.cmake | 30 + gdcm/CMake/Toolchain-mingw64.cmake | 31 + gdcm/CMake/UseCSharp.cmake | 187 + gdcm/CMake/UseCSharpTest.cmake | 83 + gdcm/CMake/UseCopyright.cmake | 25 + gdcm/CMake/UseDebian.cmake | 176 + gdcm/CMake/UseDotNETFrameworkSDK.cmake | 6 + gdcm/CMake/UseJavaTest.cmake | 106 + gdcm/CMake/UseMONO.cmake | 45 + gdcm/CMake/UsePythonTest.cmake | 80 + gdcm/CMake/dcmqrscp.cfg.in | 20 + gdcm/CMake/gdcmValgrind.supp | 139 + gdcm/CMakeLists.txt | 1014 + gdcm/CTestConfig.cmake | 7 + gdcm/Copyright.txt | 36 + gdcm/Examples/CMakeLists.txt | 30 + gdcm/Examples/Csharp/BasicAnonymizer.cs | 127 + gdcm/Examples/Csharp/BasicImageAnonymizer.cs | 85 + gdcm/Examples/Csharp/CMakeLists.txt | 78 + .../ClinicalTrialIdentificationWorkflow.cs | 241 + gdcm/Examples/Csharp/CompressLossyJPEG.cs | 88 + gdcm/Examples/Csharp/DecompressImage.cs | 87 + .../Csharp/DecompressImageMultiframe.cs | 131 + gdcm/Examples/Csharp/DecompressJPEGFile.cs | 87 + .../Csharp/ExtractEncapsulatedFile.cs | 75 + gdcm/Examples/Csharp/ExtractImageRegion.cs | 90 + .../Csharp/ExtractImageRegionWithLUT.cs | 101 + gdcm/Examples/Csharp/ExtractOneFrame.cs | 85 + gdcm/Examples/Csharp/FileAnonymize.cs | 56 + gdcm/Examples/Csharp/FileChangeTS.cs | 188 + gdcm/Examples/Csharp/FileStreaming.cs | 59 + gdcm/Examples/Csharp/GenerateDICOMDIR.cs | 62 + gdcm/Examples/Csharp/GetArray.cs | 85 + gdcm/Examples/Csharp/ManipulateFile.cs | 61 + gdcm/Examples/Csharp/MpegVideoInfo.cs | 388 + gdcm/Examples/Csharp/NewSequence.cs | 81 + gdcm/Examples/Csharp/ReformatFile.cs | 88 + gdcm/Examples/Csharp/RescaleImage.cs | 66 + gdcm/Examples/Csharp/ScanDirectory.cs | 48 + gdcm/Examples/Csharp/SendFileSCU.cs | 41 + gdcm/Examples/Csharp/SimplePrint.cs | 79 + .../Examples/Csharp/SimplePrintPatientName.cs | 60 + gdcm/Examples/Csharp/SortImage2.cs | 37 + gdcm/Examples/Csharp/StandardizeFiles.cs | 115 + gdcm/Examples/Cxx/CMakeLists.txt | 160 + gdcm/Examples/Cxx/CStoreQtProgress.cxx | 169 + .../Examples/Cxx/ChangeSequenceUltrasound.cxx | 84 + gdcm/Examples/Cxx/CheckBigEndianBug.cxx | 114 + gdcm/Examples/Cxx/ClinicalTrialAnnotate.cxx | 81 + gdcm/Examples/Cxx/CompressImage.cxx | 81 + gdcm/Examples/Cxx/ConvertToQImage.cxx | 144 + gdcm/Examples/Cxx/CreateARGBImage.cxx | 72 + gdcm/Examples/Cxx/CreateCMYKImage.cxx | 71 + gdcm/Examples/Cxx/CreateJPIPDataSet.cxx | 82 + gdcm/Examples/Cxx/DiffFile.cxx | 75 + gdcm/Examples/Cxx/DiscriminateVolume.cxx | 282 + gdcm/Examples/Cxx/DumpADAC.cxx | 366 + gdcm/Examples/Cxx/DumpExamCard.cxx | 541 + gdcm/Examples/Cxx/DumpGEMSMovieGroup.cxx | 472 + gdcm/Examples/Cxx/DumpImageHeaderInfo.cxx | 181 + gdcm/Examples/Cxx/DumpPhilipsECHO.cxx | 414 + gdcm/Examples/Cxx/DumpToSQLITE3.cxx | 145 + gdcm/Examples/Cxx/DuplicatePCDE.cxx | 198 + gdcm/Examples/Cxx/ELSCINT1WaveToText.cxx | 113 + .../Examples/Cxx/EncapsulateFileInRawData.cxx | 81 + gdcm/Examples/Cxx/ExtractEncryptedContent.cxx | 67 + gdcm/Examples/Cxx/ExtractIconFromFile.cxx | 92 + .../Cxx/Extracting_All_Resolution.cxx | 458 + .../Fake_Image_Using_Stream_Image_Writer.cxx | 232 + gdcm/Examples/Cxx/FixBrokenJ2K.cxx | 125 + gdcm/Examples/Cxx/FixJAIBugJPEGLS.cxx | 224 + gdcm/Examples/Cxx/GenAllVR.cxx | 169 + gdcm/Examples/Cxx/GenFakeIdentifyFile.cxx | 183 + gdcm/Examples/Cxx/GenFakeImage.cxx | 126 + gdcm/Examples/Cxx/GenLongSeqs.cxx | 101 + gdcm/Examples/Cxx/GenSeqs.cxx | 107 + .../Cxx/GenerateStandardSOPClasses.cxx | 68 + gdcm/Examples/Cxx/GetJPEGSamplePrecision.cxx | 121 + gdcm/Examples/Cxx/GetSequenceUltrasound.cxx | 130 + gdcm/Examples/Cxx/GetSubSequenceData.cxx | 201 + gdcm/Examples/Cxx/HelloVizWorld.cxx | 84 + gdcm/Examples/Cxx/HelloWorld.cxx | 78 + gdcm/Examples/Cxx/LargeVRDSExplicit.cxx | 186 + gdcm/Examples/Cxx/MergeTwoFiles.cxx | 86 + gdcm/Examples/Cxx/MrProtocol.cxx | 544 + gdcm/Examples/Cxx/PatchFile.cxx | 116 + gdcm/Examples/Cxx/PublicDict.cxx | 65 + gdcm/Examples/Cxx/QIDO-RS.cxx | 51 + gdcm/Examples/Cxx/ReadAndDumpDICOMDIR.cxx | 212 + gdcm/Examples/Cxx/ReadAndPrintAttributes.cxx | 109 + gdcm/Examples/Cxx/ReadExplicitLengthSQIVR.cxx | 50 + gdcm/Examples/Cxx/ReadGEMSSDO.cxx | 176 + gdcm/Examples/Cxx/ReadMultiTimesException.cxx | 57 + gdcm/Examples/Cxx/ReadUTF8QtDir.cxx | 125 + gdcm/Examples/Cxx/SimpleScanner.cxx | 122 + gdcm/Examples/Cxx/SortImage.cxx | 118 + gdcm/Examples/Cxx/StreamImageReaderTest.cxx | 280 + gdcm/Examples/Cxx/TraverseModules.cxx | 79 + gdcm/Examples/Cxx/VolumeSorter.cxx | 198 + gdcm/Examples/Cxx/csa2img.cxx | 156 + gdcm/Examples/Cxx/iU22tomultisc.cxx | 100 + gdcm/Examples/Cxx/pmsct_rgb1.cxx | 257 + gdcm/Examples/Cxx/rle2img.cxx | 201 + gdcm/Examples/Cxx/uid_unique.cxx | 54 + gdcm/Examples/Java/CMakeLists.txt | 44 + gdcm/Examples/Java/DecompressImage.java | 66 + gdcm/Examples/Java/DecompressPixmap.java | 69 + gdcm/Examples/Java/ExtractImageRegion.java | 78 + gdcm/Examples/Java/FileAnonymize.java | 63 + gdcm/Examples/Java/HelloSimple.java | 42 + gdcm/Examples/Java/ReadFiles.java | 106 + gdcm/Examples/Java/ScanDirectory.java | 299 + gdcm/Examples/PHP/README.txt | 2 + gdcm/Examples/PHP/export_pnm.php | 45 + gdcm/Examples/PHP/hello_world.php | 86 + gdcm/Examples/PHP/modify_file.php | 52 + gdcm/Examples/PHP/qido.php | 42 + gdcm/Examples/PHP/rewrite_header.php | 37 + gdcm/Examples/Python/CMakeLists.txt | 0 gdcm/Examples/Python/ConvertMPL.py | 89 + gdcm/Examples/Python/ConvertNumpy.py | 74 + gdcm/Examples/Python/ConvertPIL.py | 88 + gdcm/Examples/Python/CreateRAWStorage.py | 159 + gdcm/Examples/Python/DecompressImage.py | 69 + gdcm/Examples/Python/DumbAnonymizer.py | 124 + gdcm/Examples/Python/FindAllPatientName.py | 50 + gdcm/Examples/Python/FixCommaBug.py | 77 + gdcm/Examples/Python/GetPortionCSAHeader.py | 68 + gdcm/Examples/Python/HelloWorld.py | 59 + gdcm/Examples/Python/ManipulateFile.py | 108 + gdcm/Examples/Python/ManipulateSequence.py | 73 + gdcm/Examples/Python/MergeFile.py | 58 + gdcm/Examples/Python/NewSequence.py | 70 + .../PhilipsPrivateRescaleInterceptSlope.py | 69 + gdcm/Examples/Python/PlaySound.py | 91 + gdcm/Examples/Python/PrivateDict.py | 35 + gdcm/Examples/Python/ReWriteSCAsMR.py | 82 + gdcm/Examples/Python/ReadAndDumpDICOMDIR.py | 187 + gdcm/Examples/Python/RemovePrivateTags.py | 51 + gdcm/Examples/Python/ScanDirectory.py | 69 + gdcm/Examples/Python/SortImage.py | 46 + gdcm/Examples/Python/WriteBuffer.py | 84 + gdcm/INSTALL.txt | 36 + gdcm/PACKAGER | 50 + gdcm/README.Copyright.txt | 9 + gdcm/README.txt | 51 + gdcm/Source/Attribute/CMakeLists.txt | 0 gdcm/Source/Attribute/README.txt | 1 + gdcm/Source/CMakeLists.txt | 10 + gdcm/Source/Common/CMakeLists.txt | 207 + gdcm/Source/Common/README.txt | 1 + gdcm/Source/Common/gdcmASN1.cxx | 137 + gdcm/Source/Common/gdcmASN1.h | 49 + gdcm/Source/Common/gdcmBase64.cxx | 173 + gdcm/Source/Common/gdcmBase64.h | 71 + gdcm/Source/Common/gdcmBoxRegion.cxx | 156 + gdcm/Source/Common/gdcmBoxRegion.h | 70 + gdcm/Source/Common/gdcmByteSwap.cxx | 20 + gdcm/Source/Common/gdcmByteSwap.h | 60 + gdcm/Source/Common/gdcmByteSwap.txx | 188 + gdcm/Source/Common/gdcmCAPICryptoFactory.cxx | 36 + gdcm/Source/Common/gdcmCAPICryptoFactory.h | 34 + .../gdcmCAPICryptographicMessageSyntax.cxx | 511 + .../gdcmCAPICryptographicMessageSyntax.h | 69 + gdcm/Source/Common/gdcmCommand.cxx | 28 + gdcm/Source/Common/gdcmCommand.h | 187 + gdcm/Source/Common/gdcmConfigure.h.in | 167 + gdcm/Source/Common/gdcmCryptoFactory.cxx | 68 + gdcm/Source/Common/gdcmCryptoFactory.h | 71 + .../Common/gdcmCryptographicMessageSyntax.cxx | 14 + .../Common/gdcmCryptographicMessageSyntax.h | 59 + gdcm/Source/Common/gdcmDataEvent.cxx | 18 + gdcm/Source/Common/gdcmDataEvent.h | 57 + gdcm/Source/Common/gdcmDeflateStream.cxx | 18 + gdcm/Source/Common/gdcmDeflateStream.h | 19 + gdcm/Source/Common/gdcmDirectory.cxx | 164 + gdcm/Source/Common/gdcmDirectory.h | 100 + .../Source/Common/gdcmDummyValueGenerator.cxx | 42 + gdcm/Source/Common/gdcmDummyValueGenerator.h | 43 + gdcm/Source/Common/gdcmEvent.cxx | 36 + gdcm/Source/Common/gdcmEvent.h | 100 + gdcm/Source/Common/gdcmException.cxx | 19 + gdcm/Source/Common/gdcmException.h | 108 + gdcm/Source/Common/gdcmFileNameEvent.cxx | 18 + gdcm/Source/Common/gdcmFileNameEvent.h | 53 + gdcm/Source/Common/gdcmFilename.cxx | 187 + gdcm/Source/Common/gdcmFilename.h | 74 + gdcm/Source/Common/gdcmFilenameGenerator.cxx | 118 + gdcm/Source/Common/gdcmFilenameGenerator.h | 75 + gdcm/Source/Common/gdcmLegacyMacro.h | 77 + gdcm/Source/Common/gdcmMD5.cxx | 181 + gdcm/Source/Common/gdcmMD5.h | 51 + gdcm/Source/Common/gdcmObject.cxx | 24 + gdcm/Source/Common/gdcmObject.h | 105 + .../Common/gdcmOpenSSLCryptoFactory.cxx | 33 + gdcm/Source/Common/gdcmOpenSSLCryptoFactory.h | 47 + .../gdcmOpenSSLCryptographicMessageSyntax.cxx | 316 + .../gdcmOpenSSLCryptographicMessageSyntax.h | 67 + .../Common/gdcmOpenSSLP7CryptoFactory.cxx | 19 + .../Common/gdcmOpenSSLP7CryptoFactory.h | 41 + ...dcmOpenSSLP7CryptographicMessageSyntax.cxx | 463 + .../gdcmOpenSSLP7CryptographicMessageSyntax.h | 70 + gdcm/Source/Common/gdcmProgressEvent.cxx | 18 + gdcm/Source/Common/gdcmProgressEvent.h | 53 + gdcm/Source/Common/gdcmRegion.cxx | 32 + gdcm/Source/Common/gdcmRegion.h | 62 + gdcm/Source/Common/gdcmSHA1.cxx | 146 + gdcm/Source/Common/gdcmSHA1.h | 50 + gdcm/Source/Common/gdcmSmartPointer.h | 115 + gdcm/Source/Common/gdcmStaticAssert.h | 52 + gdcm/Source/Common/gdcmString.cxx | 19 + gdcm/Source/Common/gdcmString.h | 137 + gdcm/Source/Common/gdcmSubject.cxx | 256 + gdcm/Source/Common/gdcmSubject.h | 77 + gdcm/Source/Common/gdcmSwapCode.cxx | 69 + gdcm/Source/Common/gdcmSwapCode.h | 58 + gdcm/Source/Common/gdcmSwapper.h | 74 + gdcm/Source/Common/gdcmSwapper.txx | 197 + gdcm/Source/Common/gdcmSystem.cxx | 1069 + gdcm/Source/Common/gdcmSystem.h | 144 + gdcm/Source/Common/gdcmTerminal.cxx | 209 + gdcm/Source/Common/gdcmTerminal.h | 66 + gdcm/Source/Common/gdcmTestDriver.h | 24 + gdcm/Source/Common/gdcmTesting.cxx | 537 + gdcm/Source/Common/gdcmTesting.h | 114 + gdcm/Source/Common/gdcmTrace.cxx | 147 + gdcm/Source/Common/gdcmTrace.h | 228 + gdcm/Source/Common/gdcmTypes.h | 57 + gdcm/Source/Common/gdcmUnpacker12Bits.cxx | 59 + gdcm/Source/Common/gdcmUnpacker12Bits.h | 49 + gdcm/Source/Common/gdcmVersion.cxx | 44 + gdcm/Source/Common/gdcmVersion.h | 51 + gdcm/Source/Common/gdcmWin32.h | 81 + gdcm/Source/Common/zipstreamimpl.h | 352 + gdcm/Source/Common/zipstreamimpl.hpp | 829 + gdcm/Source/DataDictionary/06_03_list.txt | 238 + gdcm/Source/DataDictionary/Agfa.xml | 39 + gdcm/Source/DataDictionary/CMakeLists.txt | 128 + .../DataDictionary/COPYRIGHT.dicom3tools | 28 + .../Source/DataDictionary/CSADefaultDicts.xsl | 346 + gdcm/Source/DataDictionary/CSAHeader.xml | 319 + gdcm/Source/DataDictionary/DefaultDicts.xsl | 352 + .../DataDictionary/DefaultPrivateDicts.xsl | 351 + gdcm/Source/DataDictionary/GroupName.dic | 72 + .../DataDictionary/HarvestedPrivate.xml | 2885 ++ gdcm/Source/DataDictionary/NIH.dic | 15 + gdcm/Source/DataDictionary/ParseDicts.py | 401 + gdcm/Source/DataDictionary/Part6.xml | 4007 +++ gdcm/Source/DataDictionary/Part67.xsl | 326 + gdcm/Source/DataDictionary/Part6PDF.xsl | 126 + gdcm/Source/DataDictionary/Part6todcm4che.xsl | 159 + gdcm/Source/DataDictionary/Part6togdcm1.xsl | 39 + gdcm/Source/DataDictionary/Part7.xml | 185 + gdcm/Source/DataDictionary/Part7.xsl | 32 + gdcm/Source/DataDictionary/PartToGDCM.xsl | 60 + gdcm/Source/DataDictionary/README.txt | 30 + gdcm/Source/DataDictionary/SPI.dic | 140 + gdcm/Source/DataDictionary/Siemens.xml | 68 + gdcm/Source/DataDictionary/TagKeywords.xsl | 74 + gdcm/Source/DataDictionary/TagToType.xsl | 121 + gdcm/Source/DataDictionary/TagToVR.xsl | 76 + gdcm/Source/DataDictionary/UIDToC++.xsl | 111 + gdcm/Source/DataDictionary/UIDs.xml | 283 + gdcm/Source/DataDictionary/VM.xsl | 29 + gdcm/Source/DataDictionary/cp699.xml | 261 + gdcm/Source/DataDictionary/dcmtk.xsl | 255 + gdcm/Source/DataDictionary/dicom3tools.xsl | 94 + gdcm/Source/DataDictionary/dicomhdr.html | 2840 ++ gdcm/Source/DataDictionary/dicomhdr.xsl | 49 + gdcm/Source/DataDictionary/gdcm1.xsl | 43 + gdcm/Source/DataDictionary/gdcm2html.xsl | 124 + gdcm/Source/DataDictionary/gdcm2pdf.xsl | 123 + .../gdcmCSAHeaderDefaultDicts.cxx | 355 + .../Source/DataDictionary/gdcmCSAHeaderDict.h | 98 + .../DataDictionary/gdcmCSAHeaderDictEntry.h | 97 + .../DataDictionary/gdcmDefaultDicts.cxx | 13301 +++++++ .../DataDictionary/gdcmDefaultGroupNames.cxx | 118 + gdcm/Source/DataDictionary/gdcmDict.h | 344 + .../DataDictionary/gdcmDictConverter.cxx | 423 + .../Source/DataDictionary/gdcmDictConverter.h | 83 + gdcm/Source/DataDictionary/gdcmDictEntry.cxx | 72 + gdcm/Source/DataDictionary/gdcmDictEntry.h | 146 + gdcm/Source/DataDictionary/gdcmDicts.cxx | 172 + gdcm/Source/DataDictionary/gdcmDicts.h | 91 + gdcm/Source/DataDictionary/gdcmGlobal.cxx | 194 + gdcm/Source/DataDictionary/gdcmGlobal.h | 107 + gdcm/Source/DataDictionary/gdcmGroupDict.cxx | 47 + gdcm/Source/DataDictionary/gdcmGroupDict.h | 79 + gdcm/Source/DataDictionary/gdcmPrepDict.cxx | 46 + .../DataDictionary/gdcmPrepGroupName.cxx | 120 + .../gdcmPrivateDefaultDicts.cxx | 9412 +++++ gdcm/Source/DataDictionary/gdcmRoot.cxx | 2 + .../DataDictionary/gdcmSOPClassUIDToIOD.cxx | 228 + .../DataDictionary/gdcmSOPClassUIDToIOD.h | 49 + gdcm/Source/DataDictionary/gdcmTagKeywords.h | 3685 ++ gdcm/Source/DataDictionary/gdcmTagToType.h | 25222 ++++++++++++++ gdcm/Source/DataDictionary/gdcmUIDs.cxx | 436 + gdcm/Source/DataDictionary/gdcmUIDs.h | 670 + .../DataDictionary/gdcmconformancetests.xml | 28 + gdcm/Source/DataDictionary/getname.xsl | 27 + gdcm/Source/DataDictionary/getowner.xsl | 28 + gdcm/Source/DataDictionary/getretired.xsl | 33 + gdcm/Source/DataDictionary/order.xsl | 35 + gdcm/Source/DataDictionary/priv2html.xsl | 125 + gdcm/Source/DataDictionary/privatedicts.xml | 8478 +++++ gdcm/Source/DataDictionary/redo.xsl | 88 + gdcm/Source/DataDictionary/redo2.xsl | 81 + gdcm/Source/DataDictionary/sort.xsl | 20 + gdcm/Source/DataDictionary/txt2xml.py | 396 + gdcm/Source/DataDictionary/uppercase.xsl | 46 + gdcm/Source/DataDictionary/vital.xml | 25 + .../CMakeLists.txt | 71 + .../README.txt | 2 + .../gdcmAttribute.h | 1050 + .../gdcmBasicOffsetTable.h | 126 + .../gdcmByteBuffer.h | 107 + .../gdcmByteSwapFilter.cxx | 149 + .../gdcmByteSwapFilter.h | 45 + .../gdcmByteValue.cxx | 290 + .../gdcmByteValue.h | 271 + .../gdcmCP246ExplicitDataElement.cxx | 57 + .../gdcmCP246ExplicitDataElement.h | 53 + .../gdcmCP246ExplicitDataElement.txx | 231 + .../gdcmCSAElement.h | 173 + .../gdcmCSAHeader.cxx | 1253 + .../gdcmCSAHeader.h | 141 + .../gdcmCSAHeader.txx | 34 + .../gdcmCodeString.cxx | 38 + .../gdcmCodeString.h | 105 + .../gdcmDataElement.cxx | 185 + .../gdcmDataElement.h | 277 + .../gdcmDataSet.cxx | 155 + .../gdcmDataSet.h | 340 + .../gdcmDataSet.txx | 498 + .../gdcmDataSetEvent.cxx | 18 + .../gdcmDataSetEvent.h | 52 + .../gdcmElement.h | 741 + .../gdcmExplicitDataElement.cxx | 65 + .../gdcmExplicitDataElement.h | 50 + .../gdcmExplicitDataElement.txx | 562 + .../gdcmExplicitImplicitDataElement.cxx | 57 + .../gdcmExplicitImplicitDataElement.h | 58 + .../gdcmExplicitImplicitDataElement.txx | 506 + .../gdcmFile.cxx | 32 + .../gdcmFile.h | 79 + .../gdcmFileMetaInformation.cxx | 892 + .../gdcmFileMetaInformation.h | 148 + .../gdcmFileSet.cxx | 37 + .../gdcmFileSet.h | 59 + .../gdcmFragment.cxx | 37 + .../gdcmFragment.h | 239 + .../gdcmFragment.txx | 23 + .../gdcmImplicitDataElement.cxx | 62 + .../gdcmImplicitDataElement.h | 54 + .../gdcmImplicitDataElement.txx | 584 + .../gdcmItem.cxx | 22 + .../gdcmItem.h | 329 + .../gdcmItem.txx | 57 + .../gdcmLO.h | 59 + .../gdcmMediaStorage.cxx | 604 + .../gdcmMediaStorage.h | 209 + .../gdcmPDBElement.h | 67 + .../gdcmPDBHeader.cxx | 303 + .../gdcmPDBHeader.h | 91 + .../gdcmParseException.cxx | 19 + .../gdcmParseException.h | 90 + .../gdcmParser.cxx | 113 + .../gdcmParser.h | 120 + .../gdcmPreamble.cxx | 95 + .../gdcmPreamble.h | 87 + .../gdcmPrivateTag.cxx | 94 + .../gdcmPrivateTag.h | 81 + .../gdcmReader.cxx | 1008 + .../gdcmReader.h | 133 + .../gdcmSequenceOfFragments.cxx | 149 + .../gdcmSequenceOfFragments.h | 333 + .../gdcmSequenceOfFragments.txx | 24 + .../gdcmSequenceOfItems.cxx | 63 + .../gdcmSequenceOfItems.h | 253 + .../gdcmSequenceOfItems.txx | 42 + .../gdcmTag.cxx | 91 + .../gdcmTag.h | 298 + .../gdcmTagToVR.cxx | 3653 ++ .../gdcmTagToVR.h | 23 + .../gdcmTransferSyntax.cxx | 297 + .../gdcmTransferSyntax.h | 148 + .../gdcmUNExplicitDataElement.cxx | 57 + .../gdcmUNExplicitDataElement.h | 52 + .../gdcmUNExplicitDataElement.txx | 235 + .../gdcmUNExplicitImplicitDataElement.cxx | 57 + .../gdcmUNExplicitImplicitDataElement.h | 55 + .../gdcmUNExplicitImplicitDataElement.txx | 75 + .../gdcmVL.h | 135 + .../gdcmVM.cxx | 438 + .../gdcmVM.h | 191 + .../gdcmVR.cxx | 549 + .../gdcmVR.h | 335 + .../gdcmVR16ExplicitDataElement.cxx | 57 + .../gdcmVR16ExplicitDataElement.h | 54 + .../gdcmVR16ExplicitDataElement.txx | 310 + .../gdcmValue.cxx | 26 + .../gdcmValue.h | 52 + .../gdcmValue.txx | 21 + .../gdcmValueIO.h | 37 + .../gdcmValueIO.txx | 76 + .../gdcmWriter.cxx | 182 + .../gdcmWriter.h | 96 + .../CMakeLists.txt | 79 + .../ParseAttributes.py | 555 + .../InformationObjectDefinition/Part3.xml | 28556 ++++++++++++++++ .../InformationObjectDefinition/Part3.xsl | 901 + .../InformationObjectDefinition/Part4.xml | 219 + .../InformationObjectDefinition/Part4.xsl | 98 + .../Part4ToC++.xsl | 58 + .../InformationObjectDefinition/README.txt | 11 + .../Template.xml.in | 34 + .../ValueRepresentation.xsd | 693 + .../InformationObjectDefinition/extract.xsl | 36 + .../gdcmDefinedTerms.cxx | 17 + .../gdcmDefinedTerms.h | 37 + .../InformationObjectDefinition/gdcmDefs.cxx | 369 + .../InformationObjectDefinition/gdcmDefs.h | 80 + .../gdcmEnumeratedValues.cxx | 17 + .../gdcmEnumeratedValues.h | 44 + .../InformationObjectDefinition/gdcmIOD.cxx | 52 + .../InformationObjectDefinition/gdcmIOD.h | 81 + .../gdcmIODEntry.cxx | 49 + .../gdcmIODEntry.h | 89 + .../InformationObjectDefinition/gdcmIODs.h | 78 + .../InformationObjectDefinition/gdcmMacro.cxx | 82 + .../InformationObjectDefinition/gdcmMacro.h | 97 + .../gdcmMacroEntry.h | 82 + .../gdcmMacros.cxx | 18 + .../InformationObjectDefinition/gdcmMacros.h | 78 + .../gdcmModule.cxx | 126 + .../InformationObjectDefinition/gdcmModule.h | 104 + .../gdcmModuleEntry.h | 77 + .../gdcmModules.cxx | 18 + .../InformationObjectDefinition/gdcmModules.h | 79 + .../gdcmNestedModuleEntries.cxx | 15 + .../gdcmNestedModuleEntries.h | 56 + .../gdcmPatient.cxx | 17 + .../InformationObjectDefinition/gdcmPatient.h | 39 + .../gdcmSeries.cxx | 17 + .../InformationObjectDefinition/gdcmSeries.h | 35 + .../InformationObjectDefinition/gdcmStudy.cxx | 17 + .../InformationObjectDefinition/gdcmStudy.h | 38 + .../InformationObjectDefinition/gdcmTable.cxx | 19 + .../InformationObjectDefinition/gdcmTable.h | 68 + .../gdcmTableEntry.h | 43 + .../gdcmTableReader.cxx | 574 + .../gdcmTableReader.h | 103 + .../gdcmTables.h.in | 19 + .../InformationObjectDefinition/gdcmType.cxx | 47 + .../InformationObjectDefinition/gdcmType.h | 73 + .../InformationObjectDefinition/gdcmUsage.cxx | 44 + .../InformationObjectDefinition/gdcmUsage.h | 78 + .../gdcmXMLDictReader.cxx | 232 + .../gdcmXMLDictReader.h | 55 + .../gdcmXMLPrivateDictReader.cxx | 263 + .../gdcmXMLPrivateDictReader.h | 55 + .../getelements.xsl | 75 + .../InformationObjectDefinition/ma2html.xsl | 75 + .../InformationObjectDefinition/ma2pdf.xsl | 126 + .../MediaStorageAndFileFormat/CMakeLists.txt | 224 + .../FileMetaInformation.txt | 92 + .../MediaStorageAndFileFormat/README.txt | 113 + .../gdcmAnonymizeEvent.cxx | 18 + .../gdcmAnonymizeEvent.h | 53 + .../gdcmAnonymizer.cxx | 1140 + .../gdcmAnonymizer.h | 173 + .../gdcmApplicationEntity.cxx | 17 + .../gdcmApplicationEntity.h | 62 + .../gdcmAudioCodec.cxx | 34 + .../gdcmAudioCodec.h | 37 + .../MediaStorageAndFileFormat/gdcmBitmap.cxx | 951 + .../MediaStorageAndFileFormat/gdcmBitmap.h | 184 + .../gdcmBitmapToBitmapFilter.cxx | 58 + .../gdcmBitmapToBitmapFilter.h | 48 + .../MediaStorageAndFileFormat/gdcmCodec.h | 32 + .../MediaStorageAndFileFormat/gdcmCoder.h | 46 + .../gdcmConstCharWrapper.h | 53 + .../MediaStorageAndFileFormat/gdcmCurve.cxx | 557 + .../MediaStorageAndFileFormat/gdcmCurve.h | 85 + .../gdcmDICOMDIR.cxx | 17 + .../MediaStorageAndFileFormat/gdcmDICOMDIR.h | 39 + .../gdcmDICOMDIRGenerator.cxx | 1058 + .../gdcmDICOMDIRGenerator.h | 111 + .../gdcmDataSetHelper.cxx | 311 + .../gdcmDataSetHelper.h | 46 + .../MediaStorageAndFileFormat/gdcmDecoder.h | 45 + .../gdcmDeltaEncodingCodec.cxx | 50 + .../gdcmDeltaEncodingCodec.h | 40 + .../gdcmDictPrinter.cxx | 527 + .../gdcmDictPrinter.h | 41 + .../gdcmDirectionCosines.cxx | 161 + .../gdcmDirectionCosines.h | 68 + .../gdcmDirectoryHelper.cxx | 267 + .../gdcmDirectoryHelper.h | 80 + .../MediaStorageAndFileFormat/gdcmDumper.cxx | 18 + .../MediaStorageAndFileFormat/gdcmDumper.h | 38 + .../gdcmEncapsulatedDocument.cxx | 17 + .../gdcmEncapsulatedDocument.h | 34 + .../gdcmFiducials.cxx | 17 + .../MediaStorageAndFileFormat/gdcmFiducials.h | 34 + .../gdcmFileAnonymizer.cxx | 524 + .../gdcmFileAnonymizer.h | 86 + .../gdcmFileChangeTransferSyntax.cxx | 259 + .../gdcmFileChangeTransferSyntax.h | 71 + .../gdcmFileDerivation.cxx | 496 + .../gdcmFileDerivation.h | 93 + .../gdcmFileExplicitFilter.cxx | 210 + .../gdcmFileExplicitFilter.h | 78 + .../gdcmFileStreamer.cxx | 919 + .../gdcmFileStreamer.h | 103 + .../gdcmIPPSorter.cxx | 265 + .../MediaStorageAndFileFormat/gdcmIPPSorter.h | 109 + .../gdcmIconImage.cxx | 123 + .../MediaStorageAndFileFormat/gdcmIconImage.h | 94 + .../gdcmIconImageFilter.cxx | 562 + .../gdcmIconImageFilter.h | 78 + .../gdcmIconImageGenerator.cxx | 985 + .../gdcmIconImageGenerator.h | 94 + .../MediaStorageAndFileFormat/gdcmImage.cxx | 189 + .../MediaStorageAndFileFormat/gdcmImage.h | 113 + .../gdcmImageApplyLookupTable.cxx | 84 + .../gdcmImageApplyLookupTable.h | 44 + ...cmImageChangePhotometricInterpretation.cxx | 135 + ...gdcmImageChangePhotometricInterpretation.h | 117 + .../gdcmImageChangePlanarConfiguration.cxx | 114 + .../gdcmImageChangePlanarConfiguration.h | 90 + .../gdcmImageChangeTransferSyntax.cxx | 476 + .../gdcmImageChangeTransferSyntax.h | 92 + .../gdcmImageCodec.cxx | 605 + .../gdcmImageCodec.h | 134 + .../gdcmImageConverter.cxx | 44 + .../gdcmImageConverter.h | 51 + .../gdcmImageFragmentSplitter.cxx | 113 + .../gdcmImageFragmentSplitter.h | 53 + .../gdcmImageHelper.cxx | 2200 ++ .../gdcmImageHelper.h | 133 + .../gdcmImageReader.cxx | 153 + .../gdcmImageReader.h | 59 + .../gdcmImageRegionReader.cxx | 468 + .../gdcmImageRegionReader.h | 67 + .../gdcmImageToImageFilter.cxx | 37 + .../gdcmImageToImageFilter.h | 44 + .../gdcmImageWriter.cxx | 386 + .../gdcmImageWriter.h | 50 + .../gdcmJPEG12Codec.cxx | 21 + .../gdcmJPEG12Codec.h | 49 + .../gdcmJPEG16Codec.cxx | 21 + .../gdcmJPEG16Codec.h | 49 + .../gdcmJPEG2000Codec.cxx | 1606 + .../gdcmJPEG2000Codec.h | 79 + .../gdcmJPEG8Codec.cxx | 21 + .../gdcmJPEG8Codec.h | 49 + .../gdcmJPEGBITSCodec.cxx | 1584 + .../gdcmJPEGCodec.cxx | 659 + .../MediaStorageAndFileFormat/gdcmJPEGCodec.h | 102 + .../gdcmJPEGLSCodec.cxx | 513 + .../gdcmJPEGLSCodec.h | 85 + .../MediaStorageAndFileFormat/gdcmJSON.cxx | 991 + .../MediaStorageAndFileFormat/gdcmJSON.h | 49 + .../gdcmKAKADUCodec.cxx | 243 + .../gdcmKAKADUCodec.h | 42 + .../gdcmLookupTable.cxx | 656 + .../gdcmLookupTable.h | 111 + .../gdcmMeshPrimitive.cxx | 149 + .../gdcmMeshPrimitive.h | 90 + .../gdcmOrientation.cxx | 120 + .../gdcmOrientation.h | 69 + .../MediaStorageAndFileFormat/gdcmOverlay.cxx | 501 + .../MediaStorageAndFileFormat/gdcmOverlay.h | 134 + .../gdcmPDFCodec.cxx | 34 + .../MediaStorageAndFileFormat/gdcmPDFCodec.h | 37 + .../gdcmPGXCodec.cxx | 108 + .../MediaStorageAndFileFormat/gdcmPGXCodec.h | 44 + .../gdcmPNMCodec.cxx | 309 + .../MediaStorageAndFileFormat/gdcmPNMCodec.h | 52 + .../gdcmPVRGCodec.cxx | 219 + .../MediaStorageAndFileFormat/gdcmPVRGCodec.h | 52 + .../gdcmPersonName.cxx | 18 + .../gdcmPersonName.h | 83 + .../gdcmPhotometricInterpretation.cxx | 215 + .../gdcmPhotometricInterpretation.h | 100 + .../gdcmPixelFormat.cxx | 313 + .../gdcmPixelFormat.h | 222 + .../MediaStorageAndFileFormat/gdcmPixmap.cxx | 67 + .../MediaStorageAndFileFormat/gdcmPixmap.h | 84 + .../gdcmPixmapReader.cxx | 1307 + .../gdcmPixmapReader.h | 73 + .../gdcmPixmapToPixmapFilter.cxx | 39 + .../gdcmPixmapToPixmapFilter.h | 44 + .../gdcmPixmapWriter.cxx | 680 + .../gdcmPixmapWriter.h | 70 + .../MediaStorageAndFileFormat/gdcmPrinter.cxx | 991 + .../MediaStorageAndFileFormat/gdcmPrinter.h | 104 + .../gdcmRAWCodec.cxx | 218 + .../MediaStorageAndFileFormat/gdcmRAWCodec.h | 53 + .../gdcmRLECodec.cxx | 848 + .../MediaStorageAndFileFormat/gdcmRLECodec.h | 78 + .../gdcmRescaler.cxx | 506 + .../MediaStorageAndFileFormat/gdcmRescaler.h | 134 + .../MediaStorageAndFileFormat/gdcmScanner.cxx | 418 + .../MediaStorageAndFileFormat/gdcmScanner.h | 209 + .../MediaStorageAndFileFormat/gdcmSegment.cxx | 234 + .../MediaStorageAndFileFormat/gdcmSegment.h | 126 + .../gdcmSegmentHelper.cxx | 46 + .../gdcmSegmentHelper.h | 90 + .../gdcmSegmentReader.cxx | 350 + .../gdcmSegmentReader.h | 65 + .../gdcmSegmentWriter.cxx | 434 + .../gdcmSegmentWriter.h | 63 + .../gdcmSegmentedPaletteColorLookupTable.cxx | 202 + .../gdcmSegmentedPaletteColorLookupTable.h | 41 + .../gdcmSerieHelper.cxx | 473 + .../gdcmSerieHelper.h | 121 + .../gdcmSimpleSubjectWatcher.cxx | 185 + .../gdcmSimpleSubjectWatcher.h | 87 + .../MediaStorageAndFileFormat/gdcmSorter.cxx | 169 + .../MediaStorageAndFileFormat/gdcmSorter.h | 80 + .../MediaStorageAndFileFormat/gdcmSpacing.cxx | 117 + .../MediaStorageAndFileFormat/gdcmSpacing.h | 124 + .../gdcmSpectroscopy.cxx | 17 + .../gdcmSpectroscopy.h | 34 + .../gdcmSplitMosaicFilter.cxx | 172 + .../gdcmSplitMosaicFilter.h | 67 + .../gdcmStreamImageReader.cxx | 494 + .../gdcmStreamImageReader.h | 126 + .../gdcmStreamImageWriter.cxx | 433 + .../gdcmStreamImageWriter.h | 145 + .../gdcmStringFilter.cxx | 567 + .../gdcmStringFilter.h | 80 + .../MediaStorageAndFileFormat/gdcmSurface.cxx | 533 + .../MediaStorageAndFileFormat/gdcmSurface.h | 256 + .../gdcmSurfaceHelper.cxx | 139 + .../gdcmSurfaceHelper.h | 208 + .../gdcmSurfaceReader.cxx | 597 + .../gdcmSurfaceReader.h | 52 + .../gdcmSurfaceWriter.cxx | 889 + .../gdcmSurfaceWriter.h | 62 + .../MediaStorageAndFileFormat/gdcmTagPath.cxx | 155 + .../MediaStorageAndFileFormat/gdcmTagPath.h | 58 + .../gdcmUIDGenerator.cxx | 253 + .../gdcmUIDGenerator.h | 87 + .../gdcmUUIDGenerator.cxx | 99 + .../gdcmUUIDGenerator.h | 42 + .../gdcmValidate.cxx | 43 + .../MediaStorageAndFileFormat/gdcmValidate.h | 43 + .../gdcmWaveform.cxx | 17 + .../MediaStorageAndFileFormat/gdcmWaveform.h | 34 + .../gdcmXMLPrinter.cxx | 583 + .../gdcmXMLPrinter.h | 136 + .../MediaStorageAndFileFormat/gdcm_j2k.h | 446 + .../MediaStorageAndFileFormat/gdcm_jp2.h | 176 + .../MessageExchangeDefinition/CMakeLists.txt | 99 + .../MessageExchangeDefinition/README.txt | 26 + .../gdcmAAbortPDU.cxx | 164 + .../MessageExchangeDefinition/gdcmAAbortPDU.h | 60 + .../gdcmAAssociateACPDU.cxx | 253 + .../gdcmAAssociateACPDU.h | 104 + .../gdcmAAssociateRJPDU.cxx | 166 + .../gdcmAAssociateRJPDU.h | 54 + .../gdcmAAssociateRQPDU.cxx | 314 + .../gdcmAAssociateRQPDU.h | 153 + .../gdcmARTIMTimer.cxx | 83 + .../gdcmARTIMTimer.h | 67 + .../gdcmAReleaseRPPDU.cxx | 80 + .../gdcmAReleaseRPPDU.h | 51 + .../gdcmAReleaseRQPDU.cxx | 79 + .../gdcmAReleaseRQPDU.h | 51 + .../gdcmAbstractSyntax.cxx | 128 + .../gdcmAbstractSyntax.h | 70 + .../gdcmApplicationContext.cxx | 97 + .../gdcmApplicationContext.h | 58 + .../gdcmAsynchronousOperationsWindowSub.cxx | 99 + .../gdcmAsynchronousOperationsWindowSub.h | 54 + .../gdcmBaseCompositeMessage.h | 66 + .../MessageExchangeDefinition/gdcmBasePDU.h | 67 + .../gdcmBaseRootQuery.cxx | 310 + .../gdcmBaseRootQuery.h | 139 + .../gdcmCEchoMessages.cxx | 85 + .../gdcmCEchoMessages.h | 48 + .../gdcmCFindMessages.cxx | 122 + .../gdcmCFindMessages.h | 59 + .../gdcmCMoveMessages.cxx | 133 + .../gdcmCMoveMessages.h | 57 + .../gdcmCStoreMessages.cxx | 351 + .../gdcmCStoreMessages.h | 49 + .../gdcmCommandDataSet.cxx | 35 + .../gdcmCommandDataSet.h | 68 + .../gdcmCompositeMessageFactory.cxx | 61 + .../gdcmCompositeMessageFactory.h | 58 + .../gdcmCompositeNetworkFunctions.cxx | 456 + .../gdcmCompositeNetworkFunctions.h | 124 + .../MessageExchangeDefinition/gdcmDIMSE.h | 121 + .../gdcmFindPatientRootQuery.cxx | 265 + .../gdcmFindPatientRootQuery.h | 41 + .../gdcmFindStudyRootQuery.cxx | 248 + .../gdcmFindStudyRootQuery.h | 45 + .../gdcmImplementationClassUIDSub.cxx | 85 + .../gdcmImplementationClassUIDSub.h | 53 + .../gdcmImplementationUIDSub.cxx | 40 + .../gdcmImplementationUIDSub.h | 46 + .../gdcmImplementationVersionNameSub.cxx | 84 + .../gdcmImplementationVersionNameSub.h | 51 + .../gdcmMaximumLengthSub.cxx | 95 + .../gdcmMaximumLengthSub.h | 61 + .../gdcmMovePatientRootQuery.cxx | 264 + .../gdcmMovePatientRootQuery.h | 42 + .../gdcmMoveStudyRootQuery.cxx | 235 + .../gdcmMoveStudyRootQuery.h | 42 + .../gdcmNetworkEvents.h | 60 + .../gdcmNetworkStateID.h | 89 + .../gdcmPDUFactory.cxx | 256 + .../gdcmPDUFactory.h | 62 + .../gdcmPDataTFPDU.cxx | 138 + .../gdcmPDataTFPDU.h | 74 + .../gdcmPresentationContext.cxx | 67 + .../gdcmPresentationContext.h | 69 + .../gdcmPresentationContextAC.cxx | 119 + .../gdcmPresentationContextAC.h | 70 + .../gdcmPresentationContextGenerator.cxx | 171 + .../gdcmPresentationContextGenerator.h | 93 + .../gdcmPresentationContextRQ.cxx | 199 + .../gdcmPresentationContextRQ.h | 96 + .../gdcmPresentationDataValue.cxx | 272 + .../gdcmPresentationDataValue.h | 92 + .../gdcmQueryBase.cxx | 38 + .../MessageExchangeDefinition/gdcmQueryBase.h | 92 + .../gdcmQueryFactory.cxx | 243 + .../gdcmQueryFactory.h | 89 + .../gdcmQueryImage.cxx | 95 + .../gdcmQueryImage.h | 45 + .../gdcmQueryPatient.cxx | 108 + .../gdcmQueryPatient.h | 43 + .../gdcmQuerySeries.cxx | 84 + .../gdcmQuerySeries.h | 43 + .../gdcmQueryStudy.cxx | 143 + .../gdcmQueryStudy.h | 43 + .../gdcmRoleSelectionSub.cxx | 154 + .../gdcmRoleSelectionSub.h | 57 + .../gdcmSOPClassExtendedNegociationSub.cxx | 127 + .../gdcmSOPClassExtendedNegociationSub.h | 58 + ...gdcmServiceClassApplicationInformation.cxx | 113 + .../gdcmServiceClassApplicationInformation.h | 50 + .../gdcmServiceClassUser.cxx | 1076 + .../gdcmServiceClassUser.h | 124 + .../gdcmTransferSyntaxSub.cxx | 124 + .../gdcmTransferSyntaxSub.h | 69 + .../MessageExchangeDefinition/gdcmULAction.h | 81 + .../gdcmULActionAA.cxx | 114 + .../gdcmULActionAA.h | 103 + .../gdcmULActionAE.cxx | 277 + .../gdcmULActionAE.h | 103 + .../gdcmULActionAR.cxx | 160 + .../gdcmULActionAR.h | 116 + .../gdcmULActionDT.cxx | 247 + .../gdcmULActionDT.h | 51 + .../gdcmULBasicCallback.cxx | 46 + .../gdcmULBasicCallback.h | 55 + .../gdcmULConnection.cxx | 351 + .../gdcmULConnection.h | 140 + .../gdcmULConnectionCallback.h | 58 + .../gdcmULConnectionInfo.cxx | 113 + .../gdcmULConnectionInfo.h | 76 + .../gdcmULConnectionManager.cxx | 1105 + .../gdcmULConnectionManager.h | 144 + .../MessageExchangeDefinition/gdcmULEvent.h | 76 + .../gdcmULTransitionTable.cxx | 352 + .../gdcmULTransitionTable.h | 112 + .../gdcmULWritingCallback.cxx | 72 + .../gdcmULWritingCallback.h | 50 + .../gdcmUserInformation.cxx | 328 + .../gdcmUserInformation.h | 80 + gdcm/Testing/.NoDartCoverage | 1 + gdcm/Testing/CMakeLists.txt | 40 + gdcm/Testing/Source/Attribute/CMakeLists.txt | 0 gdcm/Testing/Source/CMakeLists.txt | 19 + gdcm/Testing/Source/Common/CMakeLists.txt | 5 + gdcm/Testing/Source/Common/Cxx/CMakeLists.txt | 58 + gdcm/Testing/Source/Common/Cxx/TestASN1.cxx | 37 + gdcm/Testing/Source/Common/Cxx/TestBase64.cxx | 112 + .../Source/Common/Cxx/TestByteSwap.cxx | 145 + .../Testing/Source/Common/Cxx/TestCommand.cxx | 34 + .../Cxx/TestCryptographicMessageSyntax.cxx | 314 + .../Source/Common/Cxx/TestDirectory.cxx | 71 + .../Common/Cxx/TestDummyValueGenerator.cxx | 38 + .../Source/Common/Cxx/TestFilename.cxx | 237 + .../Common/Cxx/TestFilenameGenerator.cxx | 36 + gdcm/Testing/Source/Common/Cxx/TestMD5.cxx | 305 + gdcm/Testing/Source/Common/Cxx/TestObject.cxx | 22 + gdcm/Testing/Source/Common/Cxx/TestSHA1.cxx | 302 + .../Source/Common/Cxx/TestSmartPointer.cxx | 121 + gdcm/Testing/Source/Common/Cxx/TestString.cxx | 115 + .../Testing/Source/Common/Cxx/TestString2.cxx | 50 + .../Source/Common/Cxx/TestSwapCode.cxx | 19 + .../Testing/Source/Common/Cxx/TestSwapper.cxx | 44 + .../Testing/Source/Common/Cxx/TestSystem1.cxx | 404 + .../Testing/Source/Common/Cxx/TestSystem2.cxx | 73 + .../Testing/Source/Common/Cxx/TestSystem3.cxx | 63 + .../Source/Common/Cxx/TestTerminal.cxx | 60 + .../Testing/Source/Common/Cxx/TestTesting.cxx | 49 + gdcm/Testing/Source/Common/Cxx/TestTrace.cxx | 119 + gdcm/Testing/Source/Common/Cxx/TestTypes.cxx | 33 + .../Source/Common/Cxx/TestUnpacker12Bits.cxx | 136 + .../Testing/Source/Common/Cxx/TestVersion.cxx | 32 + .../Source/Common/Python/CMakeLists.txt | 12 + .../Source/Common/Python/TestDirectory.py | 37 + .../Source/Common/Python/TestTesting.py | 29 + gdcm/Testing/Source/Data/CMakeLists.txt | 127 + gdcm/Testing/Source/Data/NativeDICOM.rnc | 60 + gdcm/Testing/Source/Data/NativeDICOM.rng | 197 + .../Source/Data/QIDO-RS_examplesup166.json | 289 + gdcm/Testing/Source/Data/certificate.pem | 22 + gdcm/Testing/Source/Data/encrypted_text | Bin 0 -> 473 bytes .../Source/Data/gdcmDataFileNames.cxx.in | 35 + .../Source/Data/gdcmMD5DataBrokenImages.cxx | 98 + .../Testing/Source/Data/gdcmMD5DataImages.cxx | 690 + .../Source/Data/gdcmMediaStorageDataFiles.cxx | 242 + .../Data/gdcmSelectedTagsOffsetDataFiles.cxx | 233 + .../Source/Data/gdcmStreamOffsetDataFiles.cxx | 232 + gdcm/Testing/Source/Data/out.bin | Bin 0 -> 473 bytes gdcm/Testing/Source/Data/privatekey.pem | 27 + gdcm/Testing/Source/Data/text | 1 + .../Source/DataDictionary/CMakeLists.txt | 5 + .../Source/DataDictionary/Cxx/CMakeLists.txt | 36 + .../Source/DataDictionary/Cxx/TestDict.cxx | 22 + .../DataDictionary/Cxx/TestDictEntry.cxx | 87 + .../Source/DataDictionary/Cxx/TestDicts.cxx | 58 + .../Source/DataDictionary/Cxx/TestGlobal.cxx | 118 + .../DataDictionary/Cxx/TestGroupDict.cxx | 24 + .../Cxx/TestSOPClassUIDToIOD.cxx | 41 + .../DataDictionary/Cxx/TestTagKeywords.cxx | 22 + .../DataDictionary/Cxx/TestTagToType.cxx | 2668 ++ .../DataDictionary/Cxx/TestTagToType.xsl | 64 + .../Source/DataDictionary/Cxx/TestUIDs.cxx | 495 + .../DataDictionary/Python/CMakeLists.txt | 11 + .../Source/DataDictionary/Python/TestDict.py | 41 + .../DataDictionary/Python/TestGlobal.py | 34 + .../CMakeLists.txt | 9 + .../Cxx/CMakeLists.txt | 130 + .../Cxx/TestAttribute.cxx | 2644 ++ .../Cxx/TestAttribute.xsl | 64 + .../Cxx/TestAttribute1.cxx | 249 + .../Cxx/TestAttribute2.cxx | 112 + .../Cxx/TestAttribute3.cxx | 69 + .../Cxx/TestAttribute4.cxx | 41 + .../Cxx/TestAttribute5.cxx | 128 + .../Cxx/TestAttribute6.cxx | 41 + .../Cxx/TestAttribute7.cxx | 33 + .../Cxx/TestAttribute8.cxx | 80 + .../Cxx/TestBasicOffsetTable.cxx | 20 + .../Cxx/TestByteBuffer.cxx | 55 + .../Cxx/TestByteSwapFilter.cxx | 21 + .../Cxx/TestByteValue.cxx | 67 + .../Cxx/TestCSAElement.cxx | 21 + .../Cxx/TestCSAHeader.cxx | 31 + .../Cxx/TestCodeString.cxx | 148 + .../Cxx/TestComposite.cxx | 22 + .../Cxx/TestCopyValue.cxx | 78 + .../Cxx/TestDS.cxx | 458 + .../Cxx/TestDataElement.cxx | 235 + .../Cxx/TestDataSet.cxx | 72 + .../Cxx/TestElement.cxx | 204 + .../Cxx/TestElement2.cxx | 40 + .../Cxx/TestElement3.cxx | 425 + .../Cxx/TestElement4.cxx | 32 + .../Cxx/TestElement5.cxx | 64 + .../Cxx/TestExplicitDataElement.cxx | 121 + .../Cxx/TestFile.cxx | 30 + .../Cxx/TestFileMetaInformation.cxx | 22 + .../Cxx/TestFileSet.cxx | 28 + .../Cxx/TestFragment.cxx | 24 + .../Cxx/TestImplicitDataElement.cxx | 121 + .../Cxx/TestInvalidDICOMFiles.cxx | 156 + .../Cxx/TestItem.cxx | 78 + .../Cxx/TestLCNumeric.cxx | 74 + .../Cxx/TestLO.cxx | 42 + .../Cxx/TestMediaStorage.cxx | 77 + .../Cxx/TestPDBHeader.cxx | 60 + .../Cxx/TestParseException.cxx | 20 + .../Cxx/TestParser.cxx | 80 + .../Cxx/TestPreamble.cxx | 31 + .../Cxx/TestPrivateTag.cxx | 93 + .../Cxx/TestReadPatientName.cxx | 29 + .../Cxx/TestReader.cxx | 90 + .../Cxx/TestReader2.cxx | 61 + .../Cxx/TestReader3.cxx | 261 + .../Cxx/TestReader4.cxx | 51 + .../Cxx/TestReaderCanRead.cxx | 163 + .../Cxx/TestReaderSelectedPrivateGroups.cxx | 81 + .../Cxx/TestReaderSelectedTags.cxx | 146 + .../Cxx/TestReaderUpToTag.cxx | 116 + .../Cxx/TestReaderUpToTag2.cxx | 126 + .../Cxx/TestSequenceOfFragments.cxx | 22 + .../Cxx/TestSequenceOfItems.cxx | 42 + .../Cxx/TestSequenceOfItems2.cxx | 80 + .../Cxx/TestTag.cxx | 372 + .../Cxx/TestTorture.cxx | 62 + .../Cxx/TestTransferSyntax.cxx | 116 + .../Cxx/TestVL.cxx | 25 + .../Cxx/TestVM.cxx | 188 + .../Cxx/TestVR.cxx | 256 + .../Cxx/TestVRDS.cxx | 100 + .../Cxx/TestVRLT.cxx | 36 + .../Cxx/TestVRUI.cxx | 36 + .../Cxx/TestValue.cxx | 68 + .../Cxx/TestWriter.cxx | 146 + .../Cxx/TestWriter2.cxx | 121 + .../Java/CMakeLists.txt | 34 + .../Java/TestReader.java | 69 + .../Python/CMakeLists.txt | 11 + .../Python/TestReader.py | 43 + .../Python/TestTag.py | 38 + .../CMakeLists.txt | 5 + .../Cxx/CMakeLists.txt | 48 + .../Cxx/TestDefinedTerms.cxx | 20 + .../Cxx/TestDefs.cxx | 91 + .../Cxx/TestEnumeratedValues.cxx | 20 + .../Cxx/TestIOD.cxx | 57 + .../Cxx/TestIODEntry.cxx | 20 + .../Cxx/TestIODs.cxx | 20 + .../Cxx/TestModule.cxx | 21 + .../Cxx/TestModuleEntry.cxx | 20 + .../Cxx/TestModules.cxx | 21 + .../Cxx/TestNestedModuleEntries.cxx | 20 + .../Cxx/TestPatient.cxx | 20 + .../Cxx/TestSeries.cxx | 20 + .../Cxx/TestStudy.cxx | 20 + .../Cxx/TestTable.cxx | 20 + .../Cxx/TestTableEntry.cxx | 20 + .../Cxx/TestTableReader.cxx | 57 + .../Cxx/TestType.cxx | 21 + .../Cxx/TestUsage.cxx | 20 + .../Cxx/TestXMLDictReader.cxx | 30 + .../Cxx/TestXMLPrivateDictReader.cxx | 31 + .../Python/CMakeLists.txt | 10 + .../Python/TestMRModule.py | 34 + .../MediaStorageAndFileFormat/CMakeLists.txt | 6 + .../Cxx/CMakeLists.txt | 308 + .../Cxx/TestAnonymizeEvent.cxx | 20 + .../Cxx/TestAnonymizer.cxx | 120 + .../Cxx/TestAnonymizer2.cxx | 213 + .../Cxx/TestAnonymizer3.cxx | 264 + .../Cxx/TestApplicationEntity.cxx | 20 + .../Cxx/TestAudioCodec.cxx | 22 + .../Cxx/TestCodec.cxx | 32 + .../Cxx/TestCoder.cxx | 29 + .../Cxx/TestCopyDataSet.cxx | 57 + .../Cxx/TestCurve.cxx | 28 + .../Cxx/TestCurve2.cxx | 188 + .../Cxx/TestDICOMDIR.cxx | 32 + .../Cxx/TestDICOMDIRGenerator1.cxx | 90 + .../Cxx/TestDICOMDIRGenerator2.cxx | 93 + .../Cxx/TestDataElementValueAsSQ.cxx | 63 + .../Cxx/TestDecoder.cxx | 29 + .../Cxx/TestDictPrinter.cxx | 20 + .../Cxx/TestDirectionCosines.cxx | 130 + .../Cxx/TestDumper.cxx | 85 + .../Cxx/TestEncapsulatedDocument.cxx | 23 + .../Cxx/TestFiducials.cxx | 23 + .../Cxx/TestFileAnonymizer1.cxx | 128 + .../Cxx/TestFileAnonymizer2.cxx | 144 + .../Cxx/TestFileAnonymizer3.cxx | 147 + .../Cxx/TestFileChangeTransferSyntax1.cxx | 208 + .../Cxx/TestFileDerivation.cxx | 131 + .../Cxx/TestFileExplicitFilter.cxx | 116 + .../Cxx/TestFileStreamer1.cxx | 151 + .../Cxx/TestFileStreamer2.cxx | 138 + .../Cxx/TestFileStreamer3.cxx | 173 + .../Cxx/TestFileStreamer4.cxx | 183 + .../Cxx/TestFileStreamer5.cxx | 96 + .../Cxx/TestFileStreamer6.cxx | 129 + .../Cxx/TestFloatingPointDouble.cxx | 31 + .../Cxx/TestIPPSorter.cxx | 80 + .../Cxx/TestIPPSorter2.cxx | 98 + .../Cxx/TestIPPSorter3.cxx | 106 + .../Cxx/TestIconImage.cxx | 43 + .../Cxx/TestIconImageFilter.cxx | 144 + .../Cxx/TestIconImageGenerator.cxx | 359 + .../Cxx/TestIconImageGenerator2.cxx | 361 + .../Cxx/TestIconImageGenerator3.cxx | 361 + .../Cxx/TestIconImageGenerator4.cxx | 382 + .../Cxx/TestImage.cxx | 70 + .../Cxx/TestImageApplyLookupTable.cxx | 164 + ...stImageChangePhotometricInterpretation.cxx | 115 + ...tImageChangePhotometricInterpretation2.cxx | 92 + .../TestImageChangePlanarConfiguration.cxx | 101 + .../Cxx/TestImageChangeTransferSyntax1.cxx | 188 + .../Cxx/TestImageChangeTransferSyntax2.cxx | 188 + .../Cxx/TestImageChangeTransferSyntax3.cxx | 176 + .../Cxx/TestImageChangeTransferSyntax4.cxx | 180 + .../Cxx/TestImageChangeTransferSyntax5.cxx | 170 + .../Cxx/TestImageChangeTransferSyntax6.cxx | 171 + .../Cxx/TestImageChangeTransferSyntax7.cxx | 213 + .../Cxx/TestImageCodec.cxx | 22 + .../Cxx/TestImageConverter.cxx | 22 + .../Cxx/TestImageFragmentSplitter.cxx | 129 + .../Cxx/TestImageHelper.cxx | 106 + .../Cxx/TestImageReader.cxx | 153 + .../Cxx/TestImageReaderPixelSpacing.cxx | 57 + .../Cxx/TestImageReaderRandomEmpty.cxx | 117 + .../Cxx/TestImageRegionReader1.cxx | 123 + .../Cxx/TestImageRegionReader2.cxx | 129 + .../Cxx/TestImageRegionReader3.cxx | 145 + .../Cxx/TestImageRegionReader4.cxx | 142 + .../Cxx/TestImageToImageFilter.cxx | 20 + .../Cxx/TestImageWriter.cxx | 175 + .../Cxx/TestImageWriter2.cxx | 201 + .../Cxx/TestJPEGCodec.cxx | 19 + .../Cxx/TestJSON1.cxx | 55 + .../Cxx/TestLookupTable.cxx | 20 + .../Cxx/TestOrientation.cxx | 62 + .../Cxx/TestOverlay.cxx | 21 + .../Cxx/TestOverlay2.cxx | 64 + .../Cxx/TestOverlay3.cxx | 176 + .../Cxx/TestPDFCodec.cxx | 23 + .../Cxx/TestPNMCodec.cxx | 22 + .../Cxx/TestParseXPATH.cxx | 109 + .../Cxx/TestPersonName.cxx | 79 + .../Cxx/TestPhotometricInterpretation.cxx | 97 + .../Cxx/TestPixelFormat.cxx | 121 + .../Cxx/TestPrint.cxx | 65 + .../Cxx/TestPrinter.cxx | 324 + .../Cxx/TestPrinter2.cxx | 72 + .../Cxx/TestRAWCodec.cxx | 22 + .../Cxx/TestRLECodec.cxx | 21 + .../Cxx/TestRescaler.cxx | 137 + .../Cxx/TestScanner.cxx | 234 + .../TestSegmentedPaletteColorLookupTable.cxx | 20 + .../Cxx/TestSerieHelper.cxx | 20 + .../Cxx/TestSorter.cxx | 51 + .../Cxx/TestSpacing.cxx | 46 + .../Cxx/TestSpectroscopy.cxx | 23 + .../Cxx/TestSplitMosaicFilter.cxx | 131 + .../Cxx/TestStreamImageReader.cxx | 232 + .../Cxx/TestStreamImageWriter.cxx | 233 + .../Cxx/TestStringFilter.cxx | 85 + .../Cxx/TestSurfaceWriter.cxx | 123 + .../Cxx/TestSurfaceWriter2.cxx | 242 + .../Cxx/TestTagPath.cxx | 65 + .../Cxx/TestUIDGenerator.cxx | 175 + .../Cxx/TestUIDGenerator2.cxx | 83 + .../Cxx/TestUIDGenerator3.cxx | 69 + .../Cxx/TestUUIDGenerator.cxx | 46 + .../Cxx/TestValidate.cxx | 21 + .../Cxx/TestWaveform.cxx | 23 + .../Cxx/TestWriter2.cxx | 36 + .../Cxx/TestXMLPrinter.cxx | 72 + .../Python/CMakeLists.txt | 39 + .../Python/TestAnonymizer.py | 81 + .../Python/TestDCMTKMD5.py | 190 + .../Python/TestIPPSorter.py | 25 + .../Python/TestImageReader.py | 42 + .../Python/TestKakaduDecompressionMD5.py | 95 + .../Python/TestModifyFields.py | 84 + .../Python/TestOrientation.py | 56 + .../Python/TestPythonFilter.py | 64 + .../Python/TestScanner.py | 93 + .../Python/TestStringFilter.py | 63 + .../Python/TestUIDGenerator.py | 32 + .../MessageExchangeDefinition/CMakeLists.txt | 1 + .../Cxx/CMakeLists.txt | 69 + .../Cxx/TestEcho.cxx | 34 + .../Cxx/TestFind.cxx | 65 + .../Cxx/TestFindPatientRootQuery.cxx | 253 + .../Cxx/TestFindStudyRootQuery.cxx | 218 + .../Cxx/TestPresentationContextRQ.cxx | 24 + .../Cxx/TestQueryFactory.cxx | 25 + .../Cxx/TestSCUFunctions.cxx | 312 + .../Cxx/TestSCUValidation.cxx | 207 + .../Cxx/TestServiceClassUser1.cxx | 320 + .../Cxx/TestServiceClassUser2.cxx | 286 + .../Cxx/TestServiceClassUser3.cxx | 146 + .../Cxx/TestULConnectionManager.cxx | 24 + .../Cxx/TestULTransitionTable.cxx | 30 + gdcm/Utilities/C99/CMakeLists.txt | 8 + gdcm/Utilities/C99/COPYING | 30 + gdcm/Utilities/C99/README.txt | 1 + gdcm/Utilities/C99/stdint.h | 247 + gdcm/Utilities/CMakeLists.txt | 143 + gdcm/Utilities/KWStyle/CMakeLists.txt | 31 + gdcm/Utilities/KWStyle/GDCM.kws.xml.in | 11 + gdcm/Utilities/KWStyle/GDCMFiles.txt.in | 11 + gdcm/Utilities/KWStyle/GDCMHeader.h | 13 + gdcm/Utilities/KWStyle/GDCMOverwrite.txt | 1 + gdcm/Utilities/Release/README.txt | 4 + gdcm/Utilities/Release/bootstrap.sh | 75 + gdcm/Utilities/Release/config.linux | 20 + gdcm/Utilities/Release/config.win32 | 20 + gdcm/Utilities/Release/makerelease.sh | 4 + gdcm/Utilities/Release/release.bat | 73 + gdcm/Utilities/Release/release.sh | 148 + gdcm/Utilities/Tools/CMakeLists.txt | 3 + gdcm/Utilities/Tools/upsidedown.c | 46 + gdcm/Utilities/VTK/.NoDartCoverage | 1 + .../Utilities/VTK/Applications/CMakeLists.txt | 57 + gdcm/Utilities/VTK/Applications/gdcm2pnm.cxx | 98 + gdcm/Utilities/VTK/Applications/gdcm2vtk.cxx | 969 + .../Utilities/VTK/Applications/gdcmviewer.cxx | 1011 + gdcm/Utilities/VTK/AssemblyInfo.cs.in | 73 + gdcm/Utilities/VTK/CMakeLists.txt | 816 + gdcm/Utilities/VTK/CscArgs.txt.in | 1 + gdcm/Utilities/VTK/Examples/CMakeLists.txt | 12 + .../VTK/Examples/Csharp/CMakeLists.txt | 59 + .../VTK/Examples/Csharp/HelloActiviz.cs | 113 + .../VTK/Examples/Csharp/HelloActiviz2.cs | 87 + .../VTK/Examples/Csharp/HelloActiviz3.cs | 49 + .../VTK/Examples/Csharp/HelloActiviz4.cs | 49 + .../VTK/Examples/Csharp/HelloActiviz5.cs | 98 + .../VTK/Examples/Csharp/HelloVTKWorld.cs | 54 + .../VTK/Examples/Csharp/HelloVTKWorld2.cs | 47 + .../Examples/Csharp/MetaImageMD5Activiz.cs | 112 + .../VTK/Examples/Csharp/RefCounting.cs | 54 + .../Utilities/VTK/Examples/Cxx/CMakeLists.txt | 76 + .../VTK/Examples/Cxx/Convert16BitsTo8Bits.cxx | 64 + .../Cxx/ConvertMultiFrameToSingleFrame.cxx | 88 + .../Examples/Cxx/ConvertRGBToLuminance.cxx | 65 + .../Examples/Cxx/ConvertSingleBitTo8Bits.cxx | 83 + .../VTK/Examples/Cxx/GenerateRTSTRUCT.cxx | 213 + .../VTK/Examples/Cxx/MagnifyFile.cxx | 79 + .../VTK/Examples/Cxx/gdcmorthoplanes.cxx | 488 + .../VTK/Examples/Cxx/gdcmreslice.cxx | 161 + .../VTK/Examples/Cxx/gdcmrtionplan.cxx | 325 + .../Utilities/VTK/Examples/Cxx/gdcmrtplan.cxx | 298 + gdcm/Utilities/VTK/Examples/Cxx/gdcmscene.cxx | 134 + .../VTK/Examples/Cxx/gdcmtexture.cxx | 140 + .../Utilities/VTK/Examples/Cxx/gdcmvolume.cxx | 93 + .../VTK/Examples/Cxx/offscreenimage.cxx | 90 + .../VTK/Examples/Cxx/reslicesphere.cxx | 631 + .../VTK/Examples/Cxx/rtstructapp.cxx | 124 + .../Utilities/VTK/Examples/Cxx/threadgdcm.cxx | 275 + .../VTK/Examples/Java/AWTMedical3.java | 322 + .../VTK/Examples/Java/CMakeLists.txt | 51 + .../VTK/Examples/Java/HelloVTKWorld.java | 96 + .../VTK/Examples/Java/MIPViewer.java | 189 + .../VTK/Examples/Java/MPRViewer.java | 153 + .../VTK/Examples/Java/MPRViewer2.java | 336 + .../VTK/Examples/Java/ReadSeriesIntoVTK.java | 88 + .../VTK/Examples/PHP/generate_png.php | 67 + .../VTK/Examples/Python/CastConvertPhilips.py | 185 + .../VTK/Examples/Python/headsq2dcm.py | 43 + gdcm/Utilities/VTK/GDCMImageGUI.xml | 17 + gdcm/Utilities/VTK/GDCMImageReader.xml | 43 + gdcm/Utilities/VTK/JavaDependencies.cmake.in | 4 + gdcm/Utilities/VTK/MummySettings.xml.in | 196 + gdcm/Utilities/VTK/Testing/CMakeLists.txt | 11 + gdcm/Utilities/VTK/Testing/Cxx/CMakeLists.txt | 86 + .../VTK/Testing/Cxx/TestvtkGDCMImageActor.cxx | 80 + .../Testing/Cxx/TestvtkGDCMImageReader.cxx | 114 + .../Testing/Cxx/TestvtkGDCMImageReader1.cxx | 170 + .../Testing/Cxx/TestvtkGDCMImageReader2_1.cxx | 110 + .../Testing/Cxx/TestvtkGDCMImageReader2_2.cxx | 117 + .../Testing/Cxx/TestvtkGDCMImageReader3.cxx | 163 + .../Testing/Cxx/TestvtkGDCMImageReader4.cxx | 157 + .../Cxx/TestvtkGDCMImageReaderIsLossy.cxx | 84 + .../Testing/Cxx/TestvtkGDCMImageViewer.cxx | 76 + .../Testing/Cxx/TestvtkGDCMImageWriter1.cxx | 260 + .../Testing/Cxx/TestvtkGDCMImageWriter2.cxx | 185 + .../Cxx/TestvtkGDCMImageWriterIsLossy.cxx | 65 + .../Cxx/TestvtkGDCMMetaImageWriter.cxx | 166 + .../Cxx/TestvtkGDCMMetaImageWriter2.cxx | 166 + .../Testing/Cxx/TestvtkGDCMPolyDataReader.cxx | 88 + .../Cxx/TestvtkGDCMThreadedImageReader.cxx | 268 + .../Cxx/TestvtkGDCMThreadedImageReader2.cxx | 262 + .../Cxx/TestvtkImageChangeInformation.cxx | 87 + .../Utilities/VTK/Testing/Java/CMakeLists.txt | 45 + .../Testing/Java/TestvtkGDCMImageReader.java | 43 + .../VTK/Testing/Python/CMakeLists.txt | 46 + ...ayscaleWordSecondaryCaptureImageStorage.py | 46 + .../Testing/Python/TestvtkGDCMImageReader.py | 60 + .../Testing/Python/TestvtkGDCMImageReader2.py | 41 + .../Testing/Python/TestvtkGDCMImageWriter.py | 45 + .../Python/TestvtkGDCMThreadedImageReader.py | 121 + .../Python/TestvtkGDCMThreadedImageReader2.py | 95 + .../VTK/VTK4/vtkMedicalImageProperties.cxx | 1020 + .../VTK/VTK4/vtkMedicalImageProperties.h | 418 + gdcm/Utilities/VTK/VTK4/vtkStringArray.cxx | 71 + gdcm/Utilities/VTK/VTK4/vtkStringArray.h | 61 + gdcm/Utilities/VTK/dllexportconf.cs | 1 + gdcm/Utilities/VTK/gccxml.cxx.in | 16 + gdcm/Utilities/VTK/manifest.txt | 1 + gdcm/Utilities/VTK/vtkGDCMImageReader.cxx | 1531 + gdcm/Utilities/VTK/vtkGDCMImageReader.h | 316 + gdcm/Utilities/VTK/vtkGDCMImageReader2.cxx | 1248 + gdcm/Utilities/VTK/vtkGDCMImageReader2.h | 275 + .../Utilities/VTK/vtkGDCMImageReader_Extra.cs | 28 + gdcm/Utilities/VTK/vtkGDCMImageWriter.cxx | 1318 + gdcm/Utilities/VTK/vtkGDCMImageWriter.h | 188 + .../VTK/vtkGDCMMedicalImageProperties.cxx | 71 + .../VTK/vtkGDCMMedicalImageProperties.h | 374 + gdcm/Utilities/VTK/vtkGDCMPolyDataReader.cxx | 833 + gdcm/Utilities/VTK/vtkGDCMPolyDataReader.h | 84 + gdcm/Utilities/VTK/vtkGDCMPolyDataWriter.cxx | 791 + gdcm/Utilities/VTK/vtkGDCMPolyDataWriter.h | 90 + gdcm/Utilities/VTK/vtkGDCMTesting.cxx | 320 + gdcm/Utilities/VTK/vtkGDCMTesting.h | 54 + .../VTK/vtkGDCMThreadedImageReader.cxx | 613 + .../VTK/vtkGDCMThreadedImageReader.h | 93 + .../VTK/vtkGDCMThreadedImageReader2.cxx | 381 + .../VTK/vtkGDCMThreadedImageReader2.h | 150 + gdcm/Utilities/VTK/vtkImageColorViewer.cxx | 966 + gdcm/Utilities/VTK/vtkImageColorViewer.h | 249 + gdcm/Utilities/VTK/vtkImageMapToColors16.cxx | 308 + gdcm/Utilities/VTK/vtkImageMapToColors16.h | 114 + .../VTK/vtkImageMapToWindowLevelColors2.cxx | 484 + .../VTK/vtkImageMapToWindowLevelColors2.h | 91 + .../vtkImagePlanarComponentsToComponents.cxx | 149 + .../vtkImagePlanarComponentsToComponents.h | 71 + gdcm/Utilities/VTK/vtkImageRGBToYBR.cxx | 143 + gdcm/Utilities/VTK/vtkImageRGBToYBR.h | 63 + gdcm/Utilities/VTK/vtkImageYBRToRGB.cxx | 195 + gdcm/Utilities/VTK/vtkImageYBRToRGB.h | 63 + gdcm/Utilities/VTK/vtkLookupTable16.cxx | 439 + gdcm/Utilities/VTK/vtkLookupTable16.h | 87 + .../VTK/vtkRTStructSetProperties.cxx | 374 + gdcm/Utilities/VTK/vtkRTStructSetProperties.h | 132 + gdcm/Utilities/VTK/vtkgdcm.i | 534 + gdcm/Utilities/VTK/vtkgdcm.py | 62 + gdcm/Utilities/dicom3tools/process.sh | 37 + gdcm/Utilities/doxygen/CMakeLists.txt | 227 + gdcm/Utilities/doxygen/README | 15 + gdcm/Utilities/doxygen/README.txt.in | 15 + gdcm/Utilities/doxygen/TestsList.txt.in | 5 + gdcm/Utilities/doxygen/authors.xml | 58 + gdcm/Utilities/doxygen/doxyfile.in | 1652 + gdcm/Utilities/doxygen/footer.html | 31 + gdcm/Utilities/doxygen/man/gdcm2pnm.man | 71 + gdcm/Utilities/doxygen/man/gdcm2vtk.man | 187 + gdcm/Utilities/doxygen/man/gdcmanon.man | 288 + gdcm/Utilities/doxygen/man/gdcmconv.man | 396 + gdcm/Utilities/doxygen/man/gdcmdiff.man | 68 + gdcm/Utilities/doxygen/man/gdcmdump.man | 411 + gdcm/Utilities/doxygen/man/gdcmgendir.man | 92 + gdcm/Utilities/doxygen/man/gdcmimg.man | 287 + gdcm/Utilities/doxygen/man/gdcminfo.man | 164 + gdcm/Utilities/doxygen/man/gdcmpap3.man | 93 + gdcm/Utilities/doxygen/man/gdcmpdf.man | 149 + gdcm/Utilities/doxygen/man/gdcmraw.man | 213 + gdcm/Utilities/doxygen/man/gdcmscanner.man | 79 + gdcm/Utilities/doxygen/man/gdcmscu.man | 341 + gdcm/Utilities/doxygen/man/gdcmtar.man | 137 + gdcm/Utilities/doxygen/man/gdcmviewer.man | 88 + gdcm/Utilities/doxygen/man/gdcmxml.man | 77 + gdcm/Utilities/doxygen/patchtex.cmake | 10 + gdcm/Utilities/doxygen/vtk/CMakeLists.txt | 122 + gdcm/Utilities/doxygen/vtk/doc_makeall.sh.in | 318 + gdcm/Utilities/doxygen/vtk/doxyfile.in | 157 + gdcm/Utilities/gdcm_charls.h | 39 + gdcm/Utilities/gdcm_expat.h | 25 + gdcm/Utilities/gdcm_ljpeg12.h | 34 + gdcm/Utilities/gdcm_ljpeg16.h | 34 + gdcm/Utilities/gdcm_ljpeg8.h | 34 + gdcm/Utilities/gdcm_md5.h | 25 + gdcm/Utilities/gdcm_openjpeg.h | 41 + gdcm/Utilities/gdcm_openjpeg2.h | 41 + gdcm/Utilities/gdcm_uuid.h | 25 + gdcm/Utilities/gdcm_zlib.h | 27 + gdcm/Utilities/gdcmcharls/.NoDartCoverage | 1 + gdcm/Utilities/gdcmcharls/CMakeLists.txt | 92 + gdcm/Utilities/gdcmcharls/License.txt | 27 + gdcm/Utilities/gdcmcharls/README.GDCM.txt | 28 + gdcm/Utilities/gdcmcharls/colortransform.h | 180 + gdcm/Utilities/gdcmcharls/config.h | 66 + gdcm/Utilities/gdcmcharls/context.h | 122 + gdcm/Utilities/gdcmcharls/contextrunmode.h | 101 + gdcm/Utilities/gdcmcharls/decoderstrategy.h | 285 + gdcm/Utilities/gdcmcharls/defaulttraits.h | 126 + gdcm/Utilities/gdcmcharls/encoderstrategy.h | 161 + gdcm/Utilities/gdcmcharls/header.cpp | 627 + gdcm/Utilities/gdcmcharls/header.h | 62 + gdcm/Utilities/gdcmcharls/interface.cpp | 206 + gdcm/Utilities/gdcmcharls/interface.h | 52 + gdcm/Utilities/gdcmcharls/jpegls.cpp | 172 + gdcm/Utilities/gdcmcharls/lookuptable.h | 69 + gdcm/Utilities/gdcmcharls/losslesstraits.h | 120 + gdcm/Utilities/gdcmcharls/processline.h | 225 + gdcm/Utilities/gdcmcharls/publictypes.h | 76 + gdcm/Utilities/gdcmcharls/scan.h | 865 + gdcm/Utilities/gdcmcharls/stdafx.cpp | 0 gdcm/Utilities/gdcmcharls/streams.h | 156 + gdcm/Utilities/gdcmcharls/util.h | 148 + gdcm/Utilities/gdcmexpat/.NoDartCoverage | 1 + gdcm/Utilities/gdcmexpat/CMakeLists.txt | 49 + gdcm/Utilities/gdcmexpat/COPYING | 22 + gdcm/Utilities/gdcmexpat/Changes | 148 + gdcm/Utilities/gdcmexpat/README | 118 + gdcm/Utilities/gdcmexpat/doc/reference.html | 2334 ++ gdcm/Utilities/gdcmexpat/doc/style.css | 101 + gdcm/Utilities/gdcmexpat/doc/xmlwf.1 | 251 + gdcm/Utilities/gdcmexpat/doc/xmlwf.sgml | 473 + gdcm/Utilities/gdcmexpat/examples/elements.c | 67 + gdcm/Utilities/gdcmexpat/examples/outline.c | 107 + gdcm/Utilities/gdcmexpat/expat_config.h.in | 92 + gdcm/Utilities/gdcmexpat/expat_mangle.h.in | 89 + gdcm/Utilities/gdcmexpat/lib/CMakeLists.txt | 18 + gdcm/Utilities/gdcmexpat/lib/ascii.h | 85 + gdcm/Utilities/gdcmexpat/lib/asciitab.h | 36 + gdcm/Utilities/gdcmexpat/lib/expat.h | 1013 + gdcm/Utilities/gdcmexpat/lib/expat_external.h | 122 + gdcm/Utilities/gdcmexpat/lib/iasciitab.h | 37 + gdcm/Utilities/gdcmexpat/lib/internal.h | 73 + gdcm/Utilities/gdcmexpat/lib/latin1tab.h | 36 + gdcm/Utilities/gdcmexpat/lib/nametab.h | 150 + gdcm/Utilities/gdcmexpat/lib/utf8tab.h | 37 + gdcm/Utilities/gdcmexpat/lib/xmlparse.c | 6257 ++++ gdcm/Utilities/gdcmexpat/lib/xmlrole.c | 1330 + gdcm/Utilities/gdcmexpat/lib/xmlrole.h | 114 + gdcm/Utilities/gdcmexpat/lib/xmltok.c | 1639 + gdcm/Utilities/gdcmexpat/lib/xmltok.h | 316 + gdcm/Utilities/gdcmexpat/lib/xmltok_impl.c | 1779 + gdcm/Utilities/gdcmexpat/lib/xmltok_impl.h | 46 + gdcm/Utilities/gdcmexpat/lib/xmltok_ns.c | 106 + gdcm/Utilities/gdcmexpat/tests/README.txt | 14 + .../gdcmexpat/tests/benchmark/README.txt | 16 + .../gdcmexpat/tests/benchmark/benchmark.c | 114 + gdcm/Utilities/gdcmexpat/tests/chardata.c | 131 + gdcm/Utilities/gdcmexpat/tests/chardata.h | 40 + gdcm/Utilities/gdcmexpat/tests/minicheck.c | 182 + gdcm/Utilities/gdcmexpat/tests/minicheck.h | 84 + gdcm/Utilities/gdcmexpat/tests/runtests.c | 1450 + gdcm/Utilities/gdcmexpat/tests/runtestspp.cpp | 6 + gdcm/Utilities/gdcmexpat/tests/xmltest.sh | 141 + gdcm/Utilities/gdcmexpat/xmlwf/codepage.c | 68 + gdcm/Utilities/gdcmexpat/xmlwf/codepage.h | 6 + gdcm/Utilities/gdcmexpat/xmlwf/ct.c | 147 + gdcm/Utilities/gdcmexpat/xmlwf/filemap.h | 17 + gdcm/Utilities/gdcmexpat/xmlwf/readfilemap.c | 82 + gdcm/Utilities/gdcmexpat/xmlwf/unixfilemap.c | 58 + gdcm/Utilities/gdcmexpat/xmlwf/win32filemap.c | 96 + gdcm/Utilities/gdcmexpat/xmlwf/xmlfile.c | 241 + gdcm/Utilities/gdcmexpat/xmlwf/xmlfile.h | 20 + gdcm/Utilities/gdcmexpat/xmlwf/xmlmime.c | 163 + gdcm/Utilities/gdcmexpat/xmlwf/xmlmime.h | 19 + gdcm/Utilities/gdcmexpat/xmlwf/xmltchar.h | 36 + gdcm/Utilities/gdcmexpat/xmlwf/xmlurl.h | 13 + gdcm/Utilities/gdcmexpat/xmlwf/xmlwf.c | 853 + .../Utilities/gdcmexpat/xmlwf/xmlwin32url.cxx | 395 + gdcm/Utilities/gdcmjpeg/.NoDartCoverage | 1 + gdcm/Utilities/gdcmjpeg/12/CMakeLists.txt | 28 + gdcm/Utilities/gdcmjpeg/16/CMakeLists.txt | 28 + gdcm/Utilities/gdcmjpeg/8/CMakeLists.txt | 28 + gdcm/Utilities/gdcmjpeg/CMakeLists.txt | 176 + gdcm/Utilities/gdcmjpeg/COPYRIGHT.dcmtk | 257 + gdcm/Utilities/gdcmjpeg/Jfif.txt | 331 + gdcm/Utilities/gdcmjpeg/README | 385 + gdcm/Utilities/gdcmjpeg/README.GDCM.txt | 83 + gdcm/Utilities/gdcmjpeg/change.log | 217 + gdcm/Utilities/gdcmjpeg/dcmtk.sh | 20 + gdcm/Utilities/gdcmjpeg/example.c | 433 + gdcm/Utilities/gdcmjpeg/filelist.doc | 239 + gdcm/Utilities/gdcmjpeg/install.doc | 1063 + gdcm/Utilities/gdcmjpeg/jcapimin.c | 280 + gdcm/Utilities/gdcmjpeg/jcapistd.c | 161 + gdcm/Utilities/gdcmjpeg/jccoefct.c | 455 + gdcm/Utilities/gdcmjpeg/jccolor.c | 460 + gdcm/Utilities/gdcmjpeg/jcdctmgr.c | 390 + gdcm/Utilities/gdcmjpeg/jcdiffct.c | 410 + gdcm/Utilities/gdcmjpeg/jchuff.c | 274 + gdcm/Utilities/gdcmjpeg/jchuff.h | 54 + gdcm/Utilities/gdcmjpeg/jcinit.c | 57 + gdcm/Utilities/gdcmjpeg/jclhuff.c | 602 + gdcm/Utilities/gdcmjpeg/jclossls.c | 82 + gdcm/Utilities/gdcmjpeg/jclossy.c | 80 + gdcm/Utilities/gdcmjpeg/jcmainct.c | 296 + gdcm/Utilities/gdcmjpeg/jcmarker.c | 682 + gdcm/Utilities/gdcmjpeg/jcmaster.c | 657 + gdcm/Utilities/gdcmjpeg/jcodec.c | 53 + gdcm/Utilities/gdcmjpeg/jcomapi.c | 106 + gdcm/Utilities/gdcmjpeg/jconfig.doc | 155 + gdcm/Utilities/gdcmjpeg/jconfig.h | 58 + gdcm/Utilities/gdcmjpeg/jcparam.c | 687 + gdcm/Utilities/gdcmjpeg/jcphuff.c | 848 + gdcm/Utilities/gdcmjpeg/jcpred.c | 300 + gdcm/Utilities/gdcmjpeg/jcprepct.c | 354 + gdcm/Utilities/gdcmjpeg/jcsample.c | 520 + gdcm/Utilities/gdcmjpeg/jcscale.c | 64 + gdcm/Utilities/gdcmjpeg/jcshuff.c | 662 + gdcm/Utilities/gdcmjpeg/jctrans.c | 425 + gdcm/Utilities/gdcmjpeg/jdapimin.c | 401 + gdcm/Utilities/gdcmjpeg/jdapistd.c | 275 + gdcm/Utilities/gdcmjpeg/jdatadst.c | 155 + gdcm/Utilities/gdcmjpeg/jdatasrc.c | 213 + gdcm/Utilities/gdcmjpeg/jdcoefct.c | 744 + gdcm/Utilities/gdcmjpeg/jdcolor.c | 414 + gdcm/Utilities/gdcmjpeg/jdct.h | 176 + gdcm/Utilities/gdcmjpeg/jddctmgr.c | 270 + gdcm/Utilities/gdcmjpeg/jddiffct.c | 400 + gdcm/Utilities/gdcmjpeg/jdhuff.c | 344 + gdcm/Utilities/gdcmjpeg/jdhuff.h | 229 + gdcm/Utilities/gdcmjpeg/jdinput.c | 347 + gdcm/Utilities/gdcmjpeg/jdlhuff.c | 291 + gdcm/Utilities/gdcmjpeg/jdlossls.c | 98 + gdcm/Utilities/gdcmjpeg/jdlossy.c | 228 + gdcm/Utilities/gdcmjpeg/jdmainct.c | 512 + gdcm/Utilities/gdcmjpeg/jdmarker.c | 1370 + gdcm/Utilities/gdcmjpeg/jdmaster.c | 460 + gdcm/Utilities/gdcmjpeg/jdmerge.c | 402 + gdcm/Utilities/gdcmjpeg/jdphuff.c | 675 + gdcm/Utilities/gdcmjpeg/jdpostct.c | 292 + gdcm/Utilities/gdcmjpeg/jdpred.c | 312 + gdcm/Utilities/gdcmjpeg/jdsample.c | 483 + gdcm/Utilities/gdcmjpeg/jdscale.c | 119 + gdcm/Utilities/gdcmjpeg/jdshuff.c | 360 + gdcm/Utilities/gdcmjpeg/jdtrans.c | 138 + gdcm/Utilities/gdcmjpeg/jerror.c | 252 + gdcm/Utilities/gdcmjpeg/jerror.h | 307 + gdcm/Utilities/gdcmjpeg/jfdctflt.c | 168 + gdcm/Utilities/gdcmjpeg/jfdctfst.c | 224 + gdcm/Utilities/gdcmjpeg/jfdctint.c | 283 + gdcm/Utilities/gdcmjpeg/jidctflt.c | 242 + gdcm/Utilities/gdcmjpeg/jidctfst.c | 368 + gdcm/Utilities/gdcmjpeg/jidctint.c | 389 + gdcm/Utilities/gdcmjpeg/jidctred.c | 398 + gdcm/Utilities/gdcmjpeg/jinclude.h | 91 + gdcm/Utilities/gdcmjpeg/jlossls.h | 152 + gdcm/Utilities/gdcmjpeg/jlossy.h | 120 + gdcm/Utilities/gdcmjpeg/jmemmgr.c | 1174 + gdcm/Utilities/gdcmjpeg/jmemnobs.c | 117 + gdcm/Utilities/gdcmjpeg/jmemsrc.c | 173 + gdcm/Utilities/gdcmjpeg/jmemsys.h | 198 + gdcm/Utilities/gdcmjpeg/jmorecfg.h | 424 + gdcm/Utilities/gdcmjpeg/jpegcmake.h.in | 46 + gdcm/Utilities/gdcmjpeg/jpegint.h | 365 + gdcm/Utilities/gdcmjpeg/jpeglib.h | 1131 + gdcm/Utilities/gdcmjpeg/jquant1.c | 860 + gdcm/Utilities/gdcmjpeg/jquant2.c | 1312 + gdcm/Utilities/gdcmjpeg/jutils.c | 179 + gdcm/Utilities/gdcmjpeg/jversion.h | 14 + gdcm/Utilities/gdcmjpeg/libjpeg.doc | 3011 ++ gdcm/Utilities/gdcmjpeg/mangle_jpeg.h.in | 140 + gdcm/Utilities/gdcmjpeg/structure.doc | 1042 + gdcm/Utilities/gdcmjpeg/usage.doc | 562 + gdcm/Utilities/gdcmjpeg/wizard.doc | 211 + gdcm/Utilities/gdcmmd5/.NoDartCoverage | 1 + gdcm/Utilities/gdcmmd5/CMakeLists.txt | 88 + gdcm/Utilities/gdcmmd5/COPYING | 24 + gdcm/Utilities/gdcmmd5/README | 2 + gdcm/Utilities/gdcmmd5/md5.c | 381 + gdcm/Utilities/gdcmmd5/md5.h | 108 + gdcm/Utilities/gdcmmd5/md5_mangle.h.in | 36 + gdcm/Utilities/gdcmmd5/md5cmp.c | 67 + gdcm/Utilities/gdcmmd5/md5main.c | 139 + gdcm/Utilities/gdcmmd5/tst2md5.c | 104 + .../Utilities/gdcmopenjpeg-v1/.NoDartCoverage | 1 + gdcm/Utilities/gdcmopenjpeg-v1/CHANGES | 817 + .../CMake/CTestCustom.cmake.in | 21 + .../CMake/CheckHaveGetopt.cmake | 15 + .../CMake/OpenJPEGConfig.cmake.in | 48 + gdcm/Utilities/gdcmopenjpeg-v1/CMakeLists.txt | 384 + .../gdcmopenjpeg-v1/CTestConfig.cmake | 7 + .../gdcmopenjpeg-v1/CTestCustom.cmake.in | 21 + gdcm/Utilities/gdcmopenjpeg-v1/INSTALL | 105 + gdcm/Utilities/gdcmopenjpeg-v1/LICENSE | 30 + .../Utilities/gdcmopenjpeg-v1/LibOpenJPEG.dsp | 262 + .../Utilities/gdcmopenjpeg-v1/LibOpenJPEG.dsw | 41 + .../Utilities/gdcmopenjpeg-v1/LibOpenJPEG.sln | 20 + .../gdcmopenjpeg-v1/LibOpenJPEG.vcproj | 642 + .../gdcmopenjpeg-v1/OPJViewer/OPJViewer.dsp | 290 + .../gdcmopenjpeg-v1/OPJViewer/OPJViewer.dsw | 56 + .../gdcmopenjpeg-v1/OPJViewer/OPJViewer.iss | 48 + .../gdcmopenjpeg-v1/OPJViewer/Readme.txt | 100 + .../gdcmopenjpeg-v1/OPJViewer/about/about.htm | 36 + .../OPJViewer/about/opj_logo.png | Bin 0 -> 6500 bytes .../gdcmopenjpeg-v1/OPJViewer/buildupdate.bat | 15 + .../OPJViewer/source/OPJAbout.cpp | 87 + .../OPJViewer/source/OPJChild.ico | Bin 0 -> 1078 bytes .../OPJViewer/source/OPJChild16.xpm | 28 + .../OPJViewer/source/OPJDialogs.cpp | 1373 + .../OPJViewer/source/OPJThreads.cpp | 1268 + .../OPJViewer/source/OPJViewer.cpp | 1664 + .../OPJViewer/source/OPJViewer.h | 811 + .../OPJViewer/source/OPJViewer.ico | Bin 0 -> 1078 bytes .../OPJViewer/source/OPJViewer.rc | 3 + .../OPJViewer/source/OPJViewer16.xpm | 26 + .../OPJViewer/source/about_htm.h | 54 + .../gdcmopenjpeg-v1/OPJViewer/source/build.h | 1 + .../OPJViewer/source/icon1.xpm | 79 + .../OPJViewer/source/icon2.xpm | 53 + .../OPJViewer/source/icon3.xpm | 79 + .../OPJViewer/source/icon4.xpm | 43 + .../OPJViewer/source/icon5.xpm | 79 + .../OPJViewer/source/imagjpeg2000.cpp | 1464 + .../OPJViewer/source/imagjpeg2000.h | 177 + .../OPJViewer/source/imagmxf.cpp | 502 + .../OPJViewer/source/imagmxf.h | 99 + .../OPJViewer/source/license.txt | 14 + .../OPJViewer/source/opj_logo.xpm | 285 + .../OPJViewer/source/readmeafter.txt | 34 + .../OPJViewer/source/readmebefore.txt | 11 + .../OPJViewer/source/wxj2kparser.cpp | 1465 + .../OPJViewer/source/wxjp2parser.cpp | 1116 + .../OPJ_Validate/OPJ_Param_File_v0_1.txt | 100 + .../OPJ_Validate/OPJ_Validate.c | 244 + .../OPJ_Validate/OPJ_Validate.dsp | 108 + .../OPJ_Validate/OPJ_Validate.dsw | 29 + .../OPJ_Validate_Candidate_vs_Ref.bat | 8 + .../OPJ_Validate_Candidate_vs_Ref.sh | 16 + .../OPJ_Validate/OPJ_Validate_Create_Ref.bat | 4 + .../OPJ_Validate/OPJ_Validate_Create_Ref.sh | 13 + .../gdcmopenjpeg-v1/OPJ_Validate/README.txt | 46 + .../linux_OPJ_Param_File_v0_1.txt | 89 + .../gdcmopenjpeg-v1/OPJ_Validate/md5.c | 276 + .../gdcmopenjpeg-v1/OPJ_Validate/md5.h | 59 + .../OPJ_Validate/original/README.txt | 1 + gdcm/Utilities/gdcmopenjpeg-v1/OpenJPEG.rc | 109 + gdcm/Utilities/gdcmopenjpeg-v1/README | 1 + gdcm/Utilities/gdcmopenjpeg-v1/README.msvc | 40 + .../gdcmopenjpeg-v1/codec/CMakeLists.txt | 102 + gdcm/Utilities/gdcmopenjpeg-v1/codec/README | 8 + .../Utilities/gdcmopenjpeg-v1/codec/convert.c | 2686 ++ .../Utilities/gdcmopenjpeg-v1/codec/convert.h | 82 + .../gdcmopenjpeg-v1/codec/image_to_j2k.c | 1789 + .../gdcmopenjpeg-v1/codec/image_to_j2k.dsp | 118 + .../gdcmopenjpeg-v1/codec/image_to_j2k.dsw | 44 + .../gdcmopenjpeg-v1/codec/image_to_j2k.sln | Bin 0 -> 1506 bytes .../gdcmopenjpeg-v1/codec/image_to_j2k.vcproj | 292 + gdcm/Utilities/gdcmopenjpeg-v1/codec/index.c | 391 + gdcm/Utilities/gdcmopenjpeg-v1/codec/index.h | 49 + .../gdcmopenjpeg-v1/codec/j2k_dump.c | 634 + .../gdcmopenjpeg-v1/codec/j2k_to_image.c | 845 + .../gdcmopenjpeg-v1/codec/j2k_to_image.dsp | 117 + .../gdcmopenjpeg-v1/codec/j2k_to_image.dsw | 44 + .../gdcmopenjpeg-v1/codec/j2k_to_image.sln | Bin 0 -> 1506 bytes .../gdcmopenjpeg-v1/codec/j2k_to_image.vcproj | 291 + .../gdcmopenjpeg-v1/codec/windirent.h | 677 + gdcm/Utilities/gdcmopenjpeg-v1/common/color.c | 463 + gdcm/Utilities/gdcmopenjpeg-v1/common/color.h | 38 + .../gdcmopenjpeg-v1/common/format_defs.h | 48 + .../Utilities/gdcmopenjpeg-v1/common/getopt.c | 261 + .../Utilities/gdcmopenjpeg-v1/common/getopt.h | 29 + .../gdcmopenjpeg-v1/doc/CMakeLists.txt | 15 + .../gdcmopenjpeg-v1/doc/Doxyfile.dox | 234 + .../doc/man/man1/image_to_j2k.1 | 222 + .../gdcmopenjpeg-v1/doc/man/man1/j2k_dump.1 | 62 + .../doc/man/man1/j2k_to_image.1 | 109 + .../doc/man/man3/libopenjpeg.3 | 337 + .../indexer_JPIP/CMakeLists.txt | 5 + .../gdcmopenjpeg-v1/indexer_JPIP/bio.c | 125 + .../gdcmopenjpeg-v1/indexer_JPIP/bio.h | 38 + .../gdcmopenjpeg-v1/indexer_JPIP/cio.c | 129 + .../gdcmopenjpeg-v1/indexer_JPIP/cio.h | 44 + .../gdcmopenjpeg-v1/indexer_JPIP/fix.c | 44 + .../gdcmopenjpeg-v1/indexer_JPIP/fix.h | 34 + .../indexer_JPIP/index_create.c | 1219 + .../gdcmopenjpeg-v1/indexer_JPIP/int.c | 89 + .../gdcmopenjpeg-v1/indexer_JPIP/int.h | 41 + .../gdcmopenjpeg-v1/indexer_JPIP/j2k.h | 288 + .../gdcmopenjpeg-v1/indexer_JPIP/jp2.c | 302 + .../gdcmopenjpeg-v1/indexer_JPIP/jp2.h | 44 + .../gdcmopenjpeg-v1/indexer_JPIP/jpip.c | 768 + .../gdcmopenjpeg-v1/indexer_JPIP/jpip.h | 42 + .../gdcmopenjpeg-v1/indexer_JPIP/pi.c | 465 + .../gdcmopenjpeg-v1/indexer_JPIP/pi.h | 72 + .../gdcmopenjpeg-v1/indexer_JPIP/t2.c | 389 + .../gdcmopenjpeg-v1/indexer_JPIP/t2.h | 46 + .../gdcmopenjpeg-v1/indexer_JPIP/tcd.c | 285 + .../gdcmopenjpeg-v1/indexer_JPIP/tcd.h | 137 + .../gdcmopenjpeg-v1/indexer_JPIP/tgt.c | 170 + .../gdcmopenjpeg-v1/indexer_JPIP/tgt.h | 80 + .../gdcmopenjpeg-v1/jp3d/CMakeLists.txt | 15 + .../gdcmopenjpeg-v1/jp3d/DllJp3dVM.dsp | 273 + .../gdcmopenjpeg-v1/jp3d/DllJp3dVM.sln | 21 + .../gdcmopenjpeg-v1/jp3d/DllJp3dVM.vcproj | 278 + .../gdcmopenjpeg-v1/jp3d/LICENSE.txt | 30 + .../gdcmopenjpeg-v1/jp3d/LibJp3dVM.sln | 21 + .../gdcmopenjpeg-v1/jp3d/LibJp3dVM.vcproj | 249 + .../Utilities/gdcmopenjpeg-v1/jp3d/README.txt | 285 + .../gdcmopenjpeg-v1/jp3d/codec/CMakeLists.txt | 47 + .../gdcmopenjpeg-v1/jp3d/codec/convert.c | 997 + .../gdcmopenjpeg-v1/jp3d/codec/convert.h | 51 + .../gdcmopenjpeg-v1/jp3d/codec/getopt.c | 109 + .../gdcmopenjpeg-v1/jp3d/codec/getopt.h | 14 + .../jp3d/codec/jp3d_to_volume.c | 540 + .../jp3d/codec/jp3d_vm_dec.ncb | Bin 0 -> 470016 bytes .../jp3d/codec/jp3d_vm_dec.sln | 30 + .../jp3d/codec/jp3d_vm_dec.suo | Bin 0 -> 13312 bytes .../jp3d/codec/jp3d_vm_dec.vcproj | 157 + .../jp3d/codec/jp3d_vm_enc.ncb | Bin 0 -> 568320 bytes .../jp3d/codec/jp3d_vm_enc.sln | 35 + .../jp3d/codec/jp3d_vm_enc.suo | Bin 0 -> 21504 bytes .../jp3d/codec/jp3d_vm_enc.vcproj | 157 + .../jp3d/codec/volume_to_jp3d.c | 906 + .../gdcmopenjpeg-v1/jp3d/codec/windirent.h | 676 + .../jp3d/libjp3dvm/CMakeLists.txt | 39 + .../gdcmopenjpeg-v1/jp3d/libjp3dvm/bio.c | 189 + .../gdcmopenjpeg-v1/jp3d/libjp3dvm/bio.h | 132 + .../gdcmopenjpeg-v1/jp3d/libjp3dvm/cio.c | 217 + .../gdcmopenjpeg-v1/jp3d/libjp3dvm/cio.h | 100 + .../gdcmopenjpeg-v1/jp3d/libjp3dvm/dwt.c | 1016 + .../gdcmopenjpeg-v1/jp3d/libjp3dvm/dwt.h | 100 + .../gdcmopenjpeg-v1/jp3d/libjp3dvm/event.c | 181 + .../gdcmopenjpeg-v1/jp3d/libjp3dvm/event.h | 58 + .../gdcmopenjpeg-v1/jp3d/libjp3dvm/fix.h | 62 + .../gdcmopenjpeg-v1/jp3d/libjp3dvm/int.h | 122 + .../gdcmopenjpeg-v1/jp3d/libjp3dvm/jp3d.c | 2328 ++ .../gdcmopenjpeg-v1/jp3d/libjp3dvm/jp3d.h | 518 + .../gdcmopenjpeg-v1/jp3d/libjp3dvm/jp3d_lib.c | 76 + .../gdcmopenjpeg-v1/jp3d/libjp3dvm/jp3d_lib.h | 75 + .../gdcmopenjpeg-v1/jp3d/libjp3dvm/mct.c | 131 + .../gdcmopenjpeg-v1/jp3d/libjp3dvm/mct.h | 97 + .../gdcmopenjpeg-v1/jp3d/libjp3dvm/mqc.c | 548 + .../gdcmopenjpeg-v1/jp3d/libjp3dvm/mqc.h | 201 + .../gdcmopenjpeg-v1/jp3d/libjp3dvm/openjpeg.c | 207 + .../jp3d/libjp3dvm/openjpeg3d.h | 713 + .../jp3d/libjp3dvm/opj_includes.h | 81 + .../gdcmopenjpeg-v1/jp3d/libjp3dvm/pi.c | 630 + .../gdcmopenjpeg-v1/jp3d/libjp3dvm/pi.h | 145 + .../gdcmopenjpeg-v1/jp3d/libjp3dvm/raw.c | 86 + .../gdcmopenjpeg-v1/jp3d/libjp3dvm/raw.h | 99 + .../gdcmopenjpeg-v1/jp3d/libjp3dvm/t1.c | 1181 + .../gdcmopenjpeg-v1/jp3d/libjp3dvm/t1.h | 173 + .../gdcmopenjpeg-v1/jp3d/libjp3dvm/t1_3d.c | 1230 + .../gdcmopenjpeg-v1/jp3d/libjp3dvm/t1_3d.h | 173 + .../gdcmopenjpeg-v1/jp3d/libjp3dvm/t2.c | 675 + .../gdcmopenjpeg-v1/jp3d/libjp3dvm/t2.h | 101 + .../gdcmopenjpeg-v1/jp3d/libjp3dvm/tcd.c | 1738 + .../gdcmopenjpeg-v1/jp3d/libjp3dvm/tcd.h | 334 + .../gdcmopenjpeg-v1/jp3d/libjp3dvm/tgt.c | 256 + .../gdcmopenjpeg-v1/jp3d/libjp3dvm/tgt.h | 124 + .../gdcmopenjpeg-v1/jp3d/libjp3dvm/volume.c | 89 + .../gdcmopenjpeg-v1/jp3d/libjp3dvm/volume.h | 43 + .../jp3d/tcltk/LPI_JP3D_VM.tcl | 114 + .../gdcmopenjpeg-v1/jp3d/tcltk/README | 13 + .../gdcmopenjpeg-v1/jp3d/tcltk/Thumbs.db | Bin 0 -> 18944 bytes .../gdcmopenjpeg-v1/jp3d/tcltk/decoder.tcl | 272 + .../gdcmopenjpeg-v1/jp3d/tcltk/encoder.tcl | 470 + .../gdcmopenjpeg-v1/jp3d/tcltk/logoLPI.gif | Bin 0 -> 5212 bytes .../gdcmopenjpeg-v1/jpwl/CMakeLists.txt | 107 + .../jpwl/JPWL_image_to_j2k.dsp | 127 + .../jpwl/JPWL_image_to_j2k.dsw | 44 + .../jpwl/JPWL_j2k_to_image.dsp | 135 + .../jpwl/JPWL_j2k_to_image.dsw | 44 + .../gdcmopenjpeg-v1/jpwl/LibOpenJPEG_JPWL.dsp | 282 + .../Utilities/gdcmopenjpeg-v1/jpwl/README.txt | 136 + gdcm/Utilities/gdcmopenjpeg-v1/jpwl/crc.c | 160 + gdcm/Utilities/gdcmopenjpeg-v1/jpwl/crc.h | 84 + gdcm/Utilities/gdcmopenjpeg-v1/jpwl/jpwl.c | 1357 + gdcm/Utilities/gdcmopenjpeg-v1/jpwl/jpwl.h | 425 + .../Utilities/gdcmopenjpeg-v1/jpwl/jpwl_lib.c | 1796 + gdcm/Utilities/gdcmopenjpeg-v1/jpwl/rs.c | 594 + gdcm/Utilities/gdcmopenjpeg-v1/jpwl/rs.h | 111 + .../gdcmopenjpeg-v1/libopenjpeg.pc.in | 11 + .../libopenjpeg/CMakeLists.txt | 63 + .../gdcmopenjpeg-v1/libopenjpeg/bio.c | 187 + .../gdcmopenjpeg-v1/libopenjpeg/bio.h | 125 + .../gdcmopenjpeg-v1/libopenjpeg/cio.c | 191 + .../gdcmopenjpeg-v1/libopenjpeg/cio.h | 86 + .../gdcmopenjpeg-v1/libopenjpeg/dwt.c | 858 + .../gdcmopenjpeg-v1/libopenjpeg/dwt.h | 113 + .../gdcmopenjpeg-v1/libopenjpeg/event.c | 121 + .../gdcmopenjpeg-v1/libopenjpeg/event.h | 58 + .../gdcmopenjpeg-v1/libopenjpeg/fix.h | 64 + .../gdcmopenjpeg-v1/libopenjpeg/image.c | 89 + .../gdcmopenjpeg-v1/libopenjpeg/image.h | 48 + .../gdcmopenjpeg-v1/libopenjpeg/int.h | 119 + .../gdcmopenjpeg-v1/libopenjpeg/j2k.c | 2434 ++ .../gdcmopenjpeg-v1/libopenjpeg/j2k.h | 446 + .../gdcmopenjpeg-v1/libopenjpeg/j2k_lib.c | 59 + .../gdcmopenjpeg-v1/libopenjpeg/j2k_lib.h | 54 + .../gdcmopenjpeg-v1/libopenjpeg/jp2.c | 1089 + .../gdcmopenjpeg-v1/libopenjpeg/jp2.h | 231 + .../gdcmopenjpeg-v1/libopenjpeg/jpt.c | 155 + .../gdcmopenjpeg-v1/libopenjpeg/jpt.h | 75 + .../gdcmopenjpeg-v1/libopenjpeg/mct.c | 190 + .../gdcmopenjpeg-v1/libopenjpeg/mct.h | 98 + .../gdcmopenjpeg-v1/libopenjpeg/mqc.c | 593 + .../gdcmopenjpeg-v1/libopenjpeg/mqc.h | 200 + .../gdcmopenjpeg-v1/libopenjpeg/openjpeg.c | 337 + .../gdcmopenjpeg-v1/libopenjpeg/openjpeg.h | 919 + .../libopenjpeg/opj_includes.h | 136 + .../gdcmopenjpeg-v1/libopenjpeg/opj_malloc.h | 163 + .../gdcmopenjpeg-v1/libopenjpeg/pi.c | 963 + .../gdcmopenjpeg-v1/libopenjpeg/pi.h | 156 + .../gdcmopenjpeg-v1/libopenjpeg/raw.c | 87 + .../gdcmopenjpeg-v1/libopenjpeg/raw.h | 100 + .../gdcmopenjpeg-v1/libopenjpeg/t1.c | 1581 + .../gdcmopenjpeg-v1/libopenjpeg/t1.h | 147 + .../libopenjpeg/t1_generate_luts.c | 275 + .../gdcmopenjpeg-v1/libopenjpeg/t1_luts.h | 143 + .../gdcmopenjpeg-v1/libopenjpeg/t2.c | 791 + .../gdcmopenjpeg-v1/libopenjpeg/t2.h | 105 + .../gdcmopenjpeg-v1/libopenjpeg/tcd.c | 1516 + .../gdcmopenjpeg-v1/libopenjpeg/tcd.h | 286 + .../gdcmopenjpeg-v1/libopenjpeg/tgt.c | 213 + .../gdcmopenjpeg-v1/libopenjpeg/tgt.h | 114 + .../gdcmopenjpeg-v1/libs/lcms2/lcms2.h | 1722 + .../gdcmopenjpeg-v1/libs/lcms2/lcms2_plugin.h | 533 + .../libs/lcms2/lcms2_static.lib | Bin 0 -> 1312736 bytes .../gdcmopenjpeg-v1/libs/libtiff/libtiff.lib | Bin 0 -> 543310 bytes .../gdcmopenjpeg-v1/libs/libtiff/tiff.h | 645 + .../gdcmopenjpeg-v1/libs/libtiff/tiffconf.h | 128 + .../gdcmopenjpeg-v1/libs/libtiff/tiffio.h | 550 + .../gdcmopenjpeg-v1/libs/libtiff/tiffio.hxx | 49 + .../gdcmopenjpeg-v1/libs/libtiff/tiffvers.h | 9 + .../gdcmopenjpeg-v1/libs/png/libpng14.lib | Bin 0 -> 800554 bytes gdcm/Utilities/gdcmopenjpeg-v1/libs/png/png.h | 2699 ++ .../gdcmopenjpeg-v1/libs/png/pngconf.h | 1540 + .../gdcmopenjpeg-v1/libs/png/zconf.h | 332 + .../Utilities/gdcmopenjpeg-v1/libs/png/zlib.h | 1357 + .../gdcmopenjpeg-v1/libs/png/zlib.lib | Bin 0 -> 240696 bytes gdcm/Utilities/gdcmopenjpeg-v1/ltmain.sh | 8750 +++++ gdcm/Utilities/gdcmopenjpeg-v1/missing | 376 + .../gdcmopenjpeg-v1/mj2/CMakeLists.txt | 87 + .../gdcmopenjpeg-v1/mj2/MJ2_Extractor.dsp | 196 + .../gdcmopenjpeg-v1/mj2/MJ2_Extractor.dsw | 44 + .../gdcmopenjpeg-v1/mj2/MJ2_Extractor.sln | 29 + .../gdcmopenjpeg-v1/mj2/MJ2_Extractor.vcproj | 354 + .../gdcmopenjpeg-v1/mj2/MJ2_Wrapper.dsp | 195 + .../gdcmopenjpeg-v1/mj2/MJ2_Wrapper.dsw | 44 + .../gdcmopenjpeg-v1/mj2/MJ2_Wrapper.sln | 29 + .../gdcmopenjpeg-v1/mj2/MJ2_Wrapper.vcproj | 353 + .../mj2/extract_j2k_from_mj2.c | 148 + .../gdcmopenjpeg-v1/mj2/frames_to_mj2.c | 806 + .../gdcmopenjpeg-v1/mj2/frames_to_mj2.dsp | 212 + .../gdcmopenjpeg-v1/mj2/frames_to_mj2.dsw | 44 + .../gdcmopenjpeg-v1/mj2/frames_to_mj2.sln | Bin 0 -> 1508 bytes .../gdcmopenjpeg-v1/mj2/frames_to_mj2.vcproj | 406 + gdcm/Utilities/gdcmopenjpeg-v1/mj2/meta_out.c | 2181 ++ gdcm/Utilities/gdcmopenjpeg-v1/mj2/meta_out.h | 13 + gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2.c | 2911 ++ gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2.h | 391 + .../gdcmopenjpeg-v1/mj2/mj2_convert.c | 329 + .../gdcmopenjpeg-v1/mj2/mj2_convert.h | 45 + .../gdcmopenjpeg-v1/mj2/mj2_to_frames.c | 250 + .../gdcmopenjpeg-v1/mj2/mj2_to_frames.dsp | 159 + .../gdcmopenjpeg-v1/mj2/mj2_to_frames.dsw | 44 + .../gdcmopenjpeg-v1/mj2/mj2_to_frames.sln | 29 + .../gdcmopenjpeg-v1/mj2/mj2_to_frames.vcproj | 324 + .../gdcmopenjpeg-v1/mj2/mj2_to_metadata.c | 312 + .../gdcmopenjpeg-v1/mj2/mj2_to_metadata.dsp | 140 + .../gdcmopenjpeg-v1/mj2/mj2_to_metadata.dsw | 44 + .../gdcmopenjpeg-v1/mj2/mj2_to_metadata.dtd | 425 + .../gdcmopenjpeg-v1/mj2/mj2_to_metadata.h | 9 + .../gdcmopenjpeg-v1/mj2/mj2_to_metadata.sln | 29 + .../mj2/mj2_to_metadata.vcproj | 349 + .../mj2/mj2_to_metadata_Notes.doc | Bin 0 -> 35328 bytes gdcm/Utilities/gdcmopenjpeg-v1/mj2/readme.txt | 3 + .../gdcmopenjpeg-v1/mj2/wrap_j2k_in_mj2.c | 371 + .../gdcmopenjpeg-v1/openjpeg_mangle.h.in | 151 + .../Utilities/gdcmopenjpeg-v1/opj_config.h.in | 104 + .../gdcmopenjpeg-v1/opj_config.h.in.user | 41 + .../gdcmopenjpeg-v1/opj_configh.cmake.in | 31 + .../Utilities/gdcmopenjpeg-v2/.NoDartCoverage | 1 + .../CMake/CTestCustom.cmake.in | 21 + .../gdcmopenjpeg-v2/CMake/FindFreeImage.cmake | 50 + .../CMake/Free_CMakeImport.cmake | 3 + .../CMake/OpenJPEGConfig.cmake.in | 48 + .../CMake/mymachine_openjpeg.cmake | 50 + gdcm/Utilities/gdcmopenjpeg-v2/CMakeLists.txt | 195 + .../gdcmopenjpeg-v2/CTestConfig.cmake | 7 + gdcm/Utilities/gdcmopenjpeg-v2/README.cmake | 9 + gdcm/Utilities/gdcmopenjpeg-v2/README.linux | 33 + gdcm/Utilities/gdcmopenjpeg-v2/README.msvc | 36 + gdcm/Utilities/gdcmopenjpeg-v2/README.osx | 26 + gdcm/Utilities/gdcmopenjpeg-v2/README.v2 | 25 + .../gdcmopenjpeg-v2/codec/CMakeLists.txt | 94 + gdcm/Utilities/gdcmopenjpeg-v2/codec/Makefile | 14 + .../gdcmopenjpeg-v2/codec/compat/getopt.c | 257 + .../gdcmopenjpeg-v2/codec/compat/getopt.h | 29 + .../Utilities/gdcmopenjpeg-v2/codec/convert.c | 2519 ++ .../Utilities/gdcmopenjpeg-v2/codec/convert.h | 78 + gdcm/Utilities/gdcmopenjpeg-v2/codec/dirent.h | 677 + .../gdcmopenjpeg-v2/codec/image_to_j2k.c | 1797 + gdcm/Utilities/gdcmopenjpeg-v2/codec/index.c | 391 + gdcm/Utilities/gdcmopenjpeg-v2/codec/index.h | 48 + .../gdcmopenjpeg-v2/codec/j2k_dump.c | 495 + .../gdcmopenjpeg-v2/codec/j2k_to_image.c | 769 + .../gdcmopenjpeg-v2/doc/CMakeLists.txt | 12 + .../gdcmopenjpeg-v2/doc/Doxyfile.dox | 234 + .../gdcmopenjpeg-v2/jpwl/CMakeLists.txt | 54 + .../Utilities/gdcmopenjpeg-v2/jpwl/README.txt | 136 + gdcm/Utilities/gdcmopenjpeg-v2/jpwl/crc.c | 160 + gdcm/Utilities/gdcmopenjpeg-v2/jpwl/crc.h | 84 + gdcm/Utilities/gdcmopenjpeg-v2/jpwl/jpwl.c | 1356 + gdcm/Utilities/gdcmopenjpeg-v2/jpwl/jpwl.h | 424 + .../Utilities/gdcmopenjpeg-v2/jpwl/jpwl_lib.c | 1796 + gdcm/Utilities/gdcmopenjpeg-v2/jpwl/rs.c | 594 + gdcm/Utilities/gdcmopenjpeg-v2/jpwl/rs.h | 111 + .../libopenjpeg/CMakeLists.txt | 90 + .../gdcmopenjpeg-v2/libopenjpeg/bio.c | 189 + .../gdcmopenjpeg-v2/libopenjpeg/bio.h | 125 + .../gdcmopenjpeg-v2/libopenjpeg/cio.c | 825 + .../gdcmopenjpeg-v2/libopenjpeg/cio.h | 358 + .../gdcmopenjpeg-v2/libopenjpeg/dwt.c | 873 + .../gdcmopenjpeg-v2/libopenjpeg/dwt.h | 118 + .../gdcmopenjpeg-v2/libopenjpeg/event.c | 95 + .../gdcmopenjpeg-v2/libopenjpeg/event.h | 86 + .../gdcmopenjpeg-v2/libopenjpeg/fix.h | 60 + .../libopenjpeg/function_list.c | 149 + .../libopenjpeg/function_list.h | 130 + .../gdcmopenjpeg-v2/libopenjpeg/image.c | 174 + .../gdcmopenjpeg-v2/libopenjpeg/image.h | 57 + .../gdcmopenjpeg-v2/libopenjpeg/int.h | 159 + .../gdcmopenjpeg-v2/libopenjpeg/invert.c | 290 + .../gdcmopenjpeg-v2/libopenjpeg/invert.h | 39 + .../gdcmopenjpeg-v2/libopenjpeg/j2k.c | 9411 +++++ .../gdcmopenjpeg-v2/libopenjpeg/j2k.h | 737 + .../gdcmopenjpeg-v2/libopenjpeg/j2k_lib.c | 64 + .../gdcmopenjpeg-v2/libopenjpeg/j2k_lib.h | 53 + .../gdcmopenjpeg-v2/libopenjpeg/jp2.c | 2229 ++ .../gdcmopenjpeg-v2/libopenjpeg/jp2.h | 341 + .../gdcmopenjpeg-v2/libopenjpeg/jpt.c | 249 + .../gdcmopenjpeg-v2/libopenjpeg/jpt.h | 83 + .../gdcmopenjpeg-v2/libopenjpeg/mct.c | 303 + .../gdcmopenjpeg-v2/libopenjpeg/mct.h | 130 + .../gdcmopenjpeg-v2/libopenjpeg/mqc.c | 542 + .../gdcmopenjpeg-v2/libopenjpeg/mqc.h | 198 + .../gdcmopenjpeg-v2/libopenjpeg/openjpeg.c | 947 + .../gdcmopenjpeg-v2/libopenjpeg/openjpeg.h | 1072 + .../libopenjpeg/opj_configure.h | 16 + .../libopenjpeg/opj_includes.h | 124 + .../gdcmopenjpeg-v2/libopenjpeg/opj_malloc.h | 144 + .../gdcmopenjpeg-v2/libopenjpeg/pi.c | 2000 ++ .../gdcmopenjpeg-v2/libopenjpeg/pi.h | 181 + .../gdcmopenjpeg-v2/libopenjpeg/profile.c | 177 + .../gdcmopenjpeg-v2/libopenjpeg/profile.h | 83 + .../gdcmopenjpeg-v2/libopenjpeg/raw.c | 88 + .../gdcmopenjpeg-v2/libopenjpeg/raw.h | 101 + .../gdcmopenjpeg-v2/libopenjpeg/t1.c | 1284 + .../gdcmopenjpeg-v2/libopenjpeg/t1.h | 156 + .../gdcmopenjpeg-v2/libopenjpeg/t1_luts.h | 142 + .../gdcmopenjpeg-v2/libopenjpeg/t2.c | 1287 + .../gdcmopenjpeg-v2/libopenjpeg/t2.h | 120 + .../gdcmopenjpeg-v2/libopenjpeg/tcd.c | 2121 ++ .../gdcmopenjpeg-v2/libopenjpeg/tcd.h | 344 + .../gdcmopenjpeg-v2/libopenjpeg/tgt.c | 344 + .../gdcmopenjpeg-v2/libopenjpeg/tgt.h | 130 + gdcm/Utilities/gdcmopenjpeg-v2/license.txt | 30 + .../gdcmopenjpeg-v2/mj2/CMakeLists.txt | 42 + gdcm/Utilities/gdcmopenjpeg-v2/mj2/Makefile | 20 + .../mj2/extract_j2k_from_mj2.c | 148 + .../gdcmopenjpeg-v2/mj2/frames_to_mj2.c | 806 + gdcm/Utilities/gdcmopenjpeg-v2/mj2/meta_out.c | 2181 ++ gdcm/Utilities/gdcmopenjpeg-v2/mj2/meta_out.h | 12 + gdcm/Utilities/gdcmopenjpeg-v2/mj2/mj2.c | 2906 ++ gdcm/Utilities/gdcmopenjpeg-v2/mj2/mj2.h | 391 + .../gdcmopenjpeg-v2/mj2/mj2_convert.c | 329 + .../gdcmopenjpeg-v2/mj2/mj2_convert.h | 45 + .../gdcmopenjpeg-v2/mj2/mj2_to_frames.c | 225 + .../gdcmopenjpeg-v2/mj2/mj2_to_metadata.c | 312 + .../gdcmopenjpeg-v2/mj2/mj2_to_metadata.dtd | 425 + .../gdcmopenjpeg-v2/mj2/mj2_to_metadata.h | 9 + .../mj2/mj2_to_metadata_Notes.doc | Bin 0 -> 35328 bytes gdcm/Utilities/gdcmopenjpeg-v2/mj2/readme.txt | 3 + .../gdcmopenjpeg-v2/mj2/wrap_j2k_in_mj2.c | 368 + .../gdcmopenjpeg-v2/openjpeg_mangle.h.in | 278 + .../gdcmopenjpeg-v2/opj_configure.h.in | 16 + .../CMakeLists.txt | 27 + .../test2_decoder.c | 367 + .../test2_encoder.c | 486 + .../test_V2_tile_handling/CMakeLists.txt | 24 + .../test_V2_tile_handling/test_decoder.c | 247 + .../test_V2_tile_handling/test_encoder.c | 301 + gdcm/Utilities/gdcmutfcpp/README.GDCM.txt | 5 + gdcm/Utilities/gdcmutfcpp/utf8.h | 34 + gdcm/Utilities/gdcmutfcpp/utf8/checked.h | 319 + gdcm/Utilities/gdcmutfcpp/utf8/core.h | 346 + gdcm/Utilities/gdcmutfcpp/utf8/unchecked.h | 228 + gdcm/Utilities/gdcmuuid/.NoDartCoverage | 1 + gdcm/Utilities/gdcmuuid/CMakeLists.txt | 125 + gdcm/Utilities/gdcmuuid/COPYING | 31 + gdcm/Utilities/gdcmuuid/compare.c | 55 + gdcm/Utilities/gdcmuuid/gen_uuid.c | 430 + gdcm/Utilities/gdcmuuid/pack.c | 69 + gdcm/Utilities/gdcmuuid/parse.c | 80 + gdcm/Utilities/gdcmuuid/unpack.c | 63 + gdcm/Utilities/gdcmuuid/unparse.c | 77 + gdcm/Utilities/gdcmuuid/uuid.h | 129 + gdcm/Utilities/gdcmuuid/uuidP.h | 72 + gdcm/Utilities/gdcmuuid/uuid_mangle.h.in | 36 + gdcm/Utilities/gdcmuuid/uuid_time.c | 166 + gdcm/Utilities/gdcmzlib/.NoDartCoverage | 1 + gdcm/Utilities/gdcmzlib/CMakeLists.txt | 69 + gdcm/Utilities/gdcmzlib/COPYING | 30 + gdcm/Utilities/gdcmzlib/ChangeLog | 855 + gdcm/Utilities/gdcmzlib/FAQ | 339 + gdcm/Utilities/gdcmzlib/INDEX | 51 + gdcm/Utilities/gdcmzlib/README | 125 + gdcm/Utilities/gdcmzlib/adler32.c | 149 + gdcm/Utilities/gdcmzlib/algorithm.txt | 209 + gdcm/Utilities/gdcmzlib/compress.c | 79 + gdcm/Utilities/gdcmzlib/crc32.c | 423 + gdcm/Utilities/gdcmzlib/crc32.h | 441 + gdcm/Utilities/gdcmzlib/deflate.c | 1736 + gdcm/Utilities/gdcmzlib/deflate.h | 331 + gdcm/Utilities/gdcmzlib/example.c | 565 + .../gdcmzlib/examples/README.examples | 42 + gdcm/Utilities/gdcmzlib/examples/fitblk.c | 233 + gdcm/Utilities/gdcmzlib/examples/gun.c | 693 + gdcm/Utilities/gdcmzlib/examples/gzappend.c | 500 + gdcm/Utilities/gdcmzlib/examples/gzjoin.c | 448 + gdcm/Utilities/gdcmzlib/examples/gzlog.c | 413 + gdcm/Utilities/gdcmzlib/examples/gzlog.h | 58 + .../Utilities/gdcmzlib/examples/zlib_how.html | 523 + gdcm/Utilities/gdcmzlib/examples/zpipe.c | 191 + gdcm/Utilities/gdcmzlib/examples/zran.c | 404 + gdcm/Utilities/gdcmzlib/gzio.c | 1026 + gdcm/Utilities/gdcmzlib/infback.c | 623 + gdcm/Utilities/gdcmzlib/inffast.c | 318 + gdcm/Utilities/gdcmzlib/inffast.h | 11 + gdcm/Utilities/gdcmzlib/inffixed.h | 94 + gdcm/Utilities/gdcmzlib/inflate.c | 1368 + gdcm/Utilities/gdcmzlib/inflate.h | 115 + gdcm/Utilities/gdcmzlib/inftrees.c | 329 + gdcm/Utilities/gdcmzlib/inftrees.h | 55 + gdcm/Utilities/gdcmzlib/minigzip.c | 322 + gdcm/Utilities/gdcmzlib/trees.c | 1219 + gdcm/Utilities/gdcmzlib/trees.h | 128 + gdcm/Utilities/gdcmzlib/uncompr.c | 61 + gdcm/Utilities/gdcmzlib/zconf.in.h | 338 + gdcm/Utilities/gdcmzlib/zlib.3 | 159 + gdcm/Utilities/gdcmzlib/zlib.def.in | 92 + gdcm/Utilities/gdcmzlib/zlib.h | 1357 + gdcm/Utilities/gdcmzlib/zlib.rc | 32 + gdcm/Utilities/gdcmzlib/zutil.c | 318 + gdcm/Utilities/gdcmzlib/zutil.h | 269 + gdcm/Utilities/getopt/CMakeLists.txt | 79 + gdcm/Utilities/getopt/COPYING | 36 + gdcm/Utilities/getopt/README | 3 + gdcm/Utilities/getopt/ex_getopt.c | 97 + gdcm/Utilities/getopt/getopt.c | 122 + gdcm/Utilities/getopt/getopt.h | 126 + gdcm/Utilities/getopt/getopt_long.c | 547 + gdcm/Utilities/pvrg/CHANGES | 63 + gdcm/Utilities/pvrg/CMakeLists.txt | 48 + gdcm/Utilities/pvrg/COPYING | 17 + gdcm/Utilities/pvrg/PORTABILITY | 8 + gdcm/Utilities/pvrg/README | 168 + gdcm/Utilities/pvrg/SETUP | 80 + gdcm/Utilities/pvrg/chendct.c | 377 + gdcm/Utilities/pvrg/codec.c | 691 + gdcm/Utilities/pvrg/csize.h | 289 + gdcm/Utilities/pvrg/dct.h | 174 + gdcm/Utilities/pvrg/globals.h | 189 + gdcm/Utilities/pvrg/huffman.c | 833 + gdcm/Utilities/pvrg/io.c | 1169 + gdcm/Utilities/pvrg/jpeg.1 | 229 + gdcm/Utilities/pvrg/jpeg.c | 2219 ++ gdcm/Utilities/pvrg/leedct.c | 468 + gdcm/Utilities/pvrg/lexer.c | 3151 ++ gdcm/Utilities/pvrg/lexer.l | 1307 + gdcm/Utilities/pvrg/marker.c | 806 + gdcm/Utilities/pvrg/marker.h | 57 + gdcm/Utilities/pvrg/param.h | 112 + gdcm/Utilities/pvrg/prototypes.h | 198 + gdcm/Utilities/pvrg/pvrgjpeg.c | 25 + gdcm/Utilities/pvrg/stream.c | 1015 + gdcm/Utilities/pvrg/stream.h | 40 + gdcm/Utilities/pvrg/system.h | 102 + gdcm/Utilities/pvrg/tables.h | 119 + gdcm/Utilities/pvrg/transform.c | 525 + gdcm/Utilities/rle/CMakeLists.txt | 16 + gdcm/Utilities/rle/example.c | 92 + gdcm/Utilities/rle/rle.c | 35 + gdcm/Utilities/rle/rledump.c | 53 + gdcm/Utilities/rle/rlelib.c | 162 + gdcm/Utilities/rle/rlelib.h | 67 + gdcm/Utilities/socketxx/.NoDartCoverage | 1 + gdcm/Utilities/socketxx/AUTHORS | 8 + gdcm/Utilities/socketxx/CMakeLists.txt | 52 + gdcm/Utilities/socketxx/COPYING | 15 + .../socketxx/socket++/CMakeLists.txt | 103 + gdcm/Utilities/socketxx/socket++/config.h.in | 135 + gdcm/Utilities/socketxx/socket++/echo.cpp | 67 + gdcm/Utilities/socketxx/socket++/echo.h | 44 + gdcm/Utilities/socketxx/socket++/fork.cpp | 204 + gdcm/Utilities/socketxx/socket++/fork.h | 70 + gdcm/Utilities/socketxx/socket++/ftp.cpp | 339 + gdcm/Utilities/socketxx/socket++/ftp.h | 139 + gdcm/Utilities/socketxx/socket++/local.h | 136 + .../socketxx/socket++/pipestream.cpp | 157 + gdcm/Utilities/socketxx/socket++/pipestream.h | 64 + gdcm/Utilities/socketxx/socket++/protocol.cpp | 53 + gdcm/Utilities/socketxx/socket++/protocol.h | 53 + gdcm/Utilities/socketxx/socket++/sig.cpp | 221 + gdcm/Utilities/socketxx/socket++/sig.h | 140 + gdcm/Utilities/socketxx/socket++/smtp.cpp | 174 + gdcm/Utilities/socketxx/socket++/smtp.h | 69 + gdcm/Utilities/socketxx/socket++/sockinet.cpp | 437 + gdcm/Utilities/socketxx/socket++/sockinet.h | 138 + .../socketxx/socket++/sockstream.cpp | 1093 + gdcm/Utilities/socketxx/socket++/sockstream.h | 379 + gdcm/Utilities/socketxx/socket++/sockunix.cpp | 172 + gdcm/Utilities/socketxx/socket++/sockunix.h | 83 + gdcm/Utilities/wxWidgets/CMakeLists.txt | 67 + gdcm/Utilities/wxWidgets/Copyright.txt | 17 + gdcm/Utilities/wxWidgets/MyDialog.cpp | 30 + gdcm/Utilities/wxWidgets/MyDialog.h | 32 + gdcm/Utilities/wxWidgets/main.cpp | 23 + gdcm/Utilities/wxWidgets/wxGDCMFrame.cpp | 112 + gdcm/Utilities/wxWidgets/wxGDCMFrame.h | 31 + gdcm/Utilities/wxWidgets/wxGDCMFrameBase.cpp | 79 + gdcm/Utilities/wxWidgets/wxGDCMFrameBase.h | 45 + .../wxWidgets/wxVTKRenderWindowInteractor.cxx | 811 + .../wxWidgets/wxVTKRenderWindowInteractor.h | 177 + gdcm/Utilities/wxWidgets/wxgdcm.wxg | 180 + gdcm/Wrapping/CMakeLists.txt | 20 + gdcm/Wrapping/Csharp/AssemblyInfo.cs.in | 76 + gdcm/Wrapping/Csharp/CMakeLists.txt | 214 + gdcm/Wrapping/Csharp/HelloCsharpWorld.cs | 57 + gdcm/Wrapping/Csharp/Notes.txt | 9 + gdcm/Wrapping/Csharp/docstrings.i | 10007 ++++++ gdcm/Wrapping/Csharp/doxy2swig.py | 460 + gdcm/Wrapping/Csharp/gdcm.i | 836 + gdcm/Wrapping/Csharp/gdcm_arrays_csharp.i | 139 + gdcm/Wrapping/Csharp/key.snk | Bin 0 -> 596 bytes gdcm/Wrapping/Csharp/std_set.i | 156 + gdcm/Wrapping/Java/CMakeLists.txt | 102 + gdcm/Wrapping/Java/gdcm.i | 854 + gdcm/Wrapping/Java/main.java | 37 + gdcm/Wrapping/Java/std_set.i | 73 + gdcm/Wrapping/PHP/CMakeLists.txt | 91 + gdcm/Wrapping/PHP/gdcm.i | 695 + gdcm/Wrapping/Perl/CMakeLists.txt | 59 + gdcm/Wrapping/Perl/gdcm.i | 622 + gdcm/Wrapping/Python/.NoDartCoverage | 1 + gdcm/Wrapping/Python/CMakeLists.txt | 151 + gdcm/Wrapping/Python/Python.h.in | 53 + gdcm/Wrapping/Python/TestWrap.py | 216 + gdcm/Wrapping/Python/docstrings.i | 15050 ++++++++ gdcm/Wrapping/Python/doxy2swig.py | 457 + gdcm/Wrapping/Python/gdcm.pth.in | 1 + gdcm/Wrapping/Python/gdcm.py | 84 + gdcm/Wrapping/Python/gdcmPythonFilter.cxx | 285 + gdcm/Wrapping/Python/gdcmPythonFilter.h | 55 + gdcm/Wrapping/Python/gdcmswig.i | 787 + gdcm/Wrapping/SWIGCommon/gdcmcommon.i | 814 + main.cpp | 11 + mainwindow.cpp | 1923 ++ mainwindow.h | 173 + mainwindow.ui | 1970 ++ mainwindow_2.cpp | 706 + mainwindow_old.cpp | 592 + 2123 files changed, 606413 insertions(+) create mode 100644 .gitignore create mode 100644 NiDBUploader.pro create mode 100644 NiDBUploader.pro.user create mode 100644 NiDBUploader.sh create mode 100644 README.md create mode 100644 anonymize.cpp create mode 100644 anonymize.h create mode 100644 gdcm/AUTHORS create mode 100644 gdcm/Applications/CMakeLists.txt create mode 100644 gdcm/Applications/Cxx/CMakeLists.txt create mode 100644 gdcm/Applications/Cxx/deflate.cxx create mode 100644 gdcm/Applications/Cxx/gdcm.cxx create mode 100644 gdcm/Applications/Cxx/gdcmanon.cxx create mode 100644 gdcm/Applications/Cxx/gdcmcheck.cxx create mode 100644 gdcm/Applications/Cxx/gdcmconv.cxx create mode 100644 gdcm/Applications/Cxx/gdcmdictdump.cxx create mode 100644 gdcm/Applications/Cxx/gdcmdiff.cxx create mode 100644 gdcm/Applications/Cxx/gdcmdump.cxx create mode 100644 gdcm/Applications/Cxx/gdcmfile.cxx create mode 100644 gdcm/Applications/Cxx/gdcmgendir.cxx create mode 100644 gdcm/Applications/Cxx/gdcmimg.cxx create mode 100644 gdcm/Applications/Cxx/gdcminfo.cxx create mode 100644 gdcm/Applications/Cxx/gdcmkey.cxx create mode 100644 gdcm/Applications/Cxx/gdcmoverlay.cxx create mode 100644 gdcm/Applications/Cxx/gdcmpap3.cxx create mode 100644 gdcm/Applications/Cxx/gdcmpdf.cxx create mode 100644 gdcm/Applications/Cxx/gdcmraw.cxx create mode 100644 gdcm/Applications/Cxx/gdcmscanner.cxx create mode 100644 gdcm/Applications/Cxx/gdcmscu.cxx create mode 100644 gdcm/Applications/Cxx/gdcmstream.cxx create mode 100644 gdcm/Applications/Cxx/gdcmtar.cxx create mode 100644 gdcm/Applications/Cxx/gdcmxml.cxx create mode 100644 gdcm/Applications/Cxx/pdf2dcm.cxx create mode 100644 gdcm/Applications/Cxx/puff.c create mode 100644 gdcm/Applications/Cxx/puff.h create mode 100644 gdcm/Applications/Python/README create mode 100644 gdcm/Applications/Python/accessdata.py create mode 100644 gdcm/Applications/Python/images.py create mode 100644 gdcm/Applications/Python/lib.py create mode 100644 gdcm/Applications/Python/wado.py create mode 100644 gdcm/Applications/README.txt create mode 100644 gdcm/CMake/CMakeCSharpCompiler.cmake.in create mode 100644 gdcm/CMake/CMakeCSharpInformation.cmake create mode 100644 gdcm/CMake/CMakeDetermineCSharpCompiler.cmake create mode 100644 gdcm/CMake/CMakeTestCSharpCompiler.cmake create mode 100644 gdcm/CMake/COPYING-CMAKE-SCRIPTS create mode 100644 gdcm/CMake/CTestCustom.ctest.in create mode 100644 gdcm/CMake/ExportConfiguration/CMakeLists.txt create mode 100644 gdcm/CMake/ExportConfiguration/GDCMConfig.cmake.in create mode 100644 gdcm/CMake/ExportConfiguration/GDCMConfigVersion.cmake.in create mode 100644 gdcm/CMake/ExportConfiguration/UseGDCM.cmake.in create mode 100644 gdcm/CMake/FindACTIVIZ.cmake create mode 100644 gdcm/CMake/FindCSharp.cmake create mode 100644 gdcm/CMake/FindCharLS.cmake create mode 100644 gdcm/CMake/FindDCMTK.cmake create mode 100644 gdcm/CMake/FindDICOM3TOOLS.cmake create mode 100644 gdcm/CMake/FindDotNETFrameworkSDK.cmake create mode 100644 gdcm/CMake/FindJNI.cmake create mode 100644 gdcm/CMake/FindJSON.cmake create mode 100644 gdcm/CMake/FindJava.cmake create mode 100644 gdcm/CMake/FindJavaProperties.cmake create mode 100644 gdcm/CMake/FindKAKADU.cmake create mode 100644 gdcm/CMake/FindKWStyle.cmake create mode 100644 gdcm/CMake/FindLJPEG.cmake create mode 100644 gdcm/CMake/FindMAGIC.cmake create mode 100644 gdcm/CMake/FindMONO.cmake create mode 100644 gdcm/CMake/FindMd5sum.cmake create mode 100644 gdcm/CMake/FindOpenJPEG.cmake create mode 100644 gdcm/CMake/FindOpenSSL.cmake create mode 100644 gdcm/CMake/FindPAPYRUS3.cmake create mode 100644 gdcm/CMake/FindPHP5.cmake create mode 100644 gdcm/CMake/FindPVRGJPEG.cmake create mode 100644 gdcm/CMake/FindPoppler.cmake create mode 100644 gdcm/CMake/FindRsync.cmake create mode 100644 gdcm/CMake/FindSOCKET++.cmake create mode 100644 gdcm/CMake/FindSQLITE3.cmake create mode 100644 gdcm/CMake/FindUUID.cmake create mode 100644 gdcm/CMake/GetSystemProperty.java create mode 100644 gdcm/CMake/InstallMacros.cmake create mode 100644 gdcm/CMake/InstallRequiredVTKLibraries.cmake create mode 100644 gdcm/CMake/Release/README.cygwin.in create mode 100644 gdcm/CMake/Release/cygwin-package.sh.in create mode 100644 gdcm/CMake/Release/cygwin-patch.diff.in create mode 100644 gdcm/CMake/Release/cygwin-setup.hint.in create mode 100644 gdcm/CMake/Toolchain-gcc-arm-linux-gnueabi.cmake create mode 100644 gdcm/CMake/Toolchain-gcc-m32.cmake create mode 100644 gdcm/CMake/Toolchain-gcc-powerpc.cmake create mode 100644 gdcm/CMake/Toolchain-mingw32.cmake create mode 100644 gdcm/CMake/Toolchain-mingw64.cmake create mode 100644 gdcm/CMake/UseCSharp.cmake create mode 100644 gdcm/CMake/UseCSharpTest.cmake create mode 100644 gdcm/CMake/UseCopyright.cmake create mode 100644 gdcm/CMake/UseDebian.cmake create mode 100644 gdcm/CMake/UseDotNETFrameworkSDK.cmake create mode 100644 gdcm/CMake/UseJavaTest.cmake create mode 100644 gdcm/CMake/UseMONO.cmake create mode 100644 gdcm/CMake/UsePythonTest.cmake create mode 100644 gdcm/CMake/dcmqrscp.cfg.in create mode 100644 gdcm/CMake/gdcmValgrind.supp create mode 100644 gdcm/CMakeLists.txt create mode 100644 gdcm/CTestConfig.cmake create mode 100644 gdcm/Copyright.txt create mode 100644 gdcm/Examples/CMakeLists.txt create mode 100644 gdcm/Examples/Csharp/BasicAnonymizer.cs create mode 100644 gdcm/Examples/Csharp/BasicImageAnonymizer.cs create mode 100644 gdcm/Examples/Csharp/CMakeLists.txt create mode 100644 gdcm/Examples/Csharp/ClinicalTrialIdentificationWorkflow.cs create mode 100644 gdcm/Examples/Csharp/CompressLossyJPEG.cs create mode 100644 gdcm/Examples/Csharp/DecompressImage.cs create mode 100644 gdcm/Examples/Csharp/DecompressImageMultiframe.cs create mode 100644 gdcm/Examples/Csharp/DecompressJPEGFile.cs create mode 100644 gdcm/Examples/Csharp/ExtractEncapsulatedFile.cs create mode 100644 gdcm/Examples/Csharp/ExtractImageRegion.cs create mode 100644 gdcm/Examples/Csharp/ExtractImageRegionWithLUT.cs create mode 100644 gdcm/Examples/Csharp/ExtractOneFrame.cs create mode 100644 gdcm/Examples/Csharp/FileAnonymize.cs create mode 100644 gdcm/Examples/Csharp/FileChangeTS.cs create mode 100644 gdcm/Examples/Csharp/FileStreaming.cs create mode 100644 gdcm/Examples/Csharp/GenerateDICOMDIR.cs create mode 100644 gdcm/Examples/Csharp/GetArray.cs create mode 100644 gdcm/Examples/Csharp/ManipulateFile.cs create mode 100644 gdcm/Examples/Csharp/MpegVideoInfo.cs create mode 100644 gdcm/Examples/Csharp/NewSequence.cs create mode 100644 gdcm/Examples/Csharp/ReformatFile.cs create mode 100644 gdcm/Examples/Csharp/RescaleImage.cs create mode 100644 gdcm/Examples/Csharp/ScanDirectory.cs create mode 100644 gdcm/Examples/Csharp/SendFileSCU.cs create mode 100644 gdcm/Examples/Csharp/SimplePrint.cs create mode 100644 gdcm/Examples/Csharp/SimplePrintPatientName.cs create mode 100644 gdcm/Examples/Csharp/SortImage2.cs create mode 100644 gdcm/Examples/Csharp/StandardizeFiles.cs create mode 100644 gdcm/Examples/Cxx/CMakeLists.txt create mode 100644 gdcm/Examples/Cxx/CStoreQtProgress.cxx create mode 100644 gdcm/Examples/Cxx/ChangeSequenceUltrasound.cxx create mode 100644 gdcm/Examples/Cxx/CheckBigEndianBug.cxx create mode 100644 gdcm/Examples/Cxx/ClinicalTrialAnnotate.cxx create mode 100644 gdcm/Examples/Cxx/CompressImage.cxx create mode 100644 gdcm/Examples/Cxx/ConvertToQImage.cxx create mode 100644 gdcm/Examples/Cxx/CreateARGBImage.cxx create mode 100644 gdcm/Examples/Cxx/CreateCMYKImage.cxx create mode 100644 gdcm/Examples/Cxx/CreateJPIPDataSet.cxx create mode 100644 gdcm/Examples/Cxx/DiffFile.cxx create mode 100644 gdcm/Examples/Cxx/DiscriminateVolume.cxx create mode 100644 gdcm/Examples/Cxx/DumpADAC.cxx create mode 100644 gdcm/Examples/Cxx/DumpExamCard.cxx create mode 100644 gdcm/Examples/Cxx/DumpGEMSMovieGroup.cxx create mode 100644 gdcm/Examples/Cxx/DumpImageHeaderInfo.cxx create mode 100644 gdcm/Examples/Cxx/DumpPhilipsECHO.cxx create mode 100644 gdcm/Examples/Cxx/DumpToSQLITE3.cxx create mode 100644 gdcm/Examples/Cxx/DuplicatePCDE.cxx create mode 100644 gdcm/Examples/Cxx/ELSCINT1WaveToText.cxx create mode 100644 gdcm/Examples/Cxx/EncapsulateFileInRawData.cxx create mode 100644 gdcm/Examples/Cxx/ExtractEncryptedContent.cxx create mode 100644 gdcm/Examples/Cxx/ExtractIconFromFile.cxx create mode 100644 gdcm/Examples/Cxx/Extracting_All_Resolution.cxx create mode 100644 gdcm/Examples/Cxx/Fake_Image_Using_Stream_Image_Writer.cxx create mode 100644 gdcm/Examples/Cxx/FixBrokenJ2K.cxx create mode 100644 gdcm/Examples/Cxx/FixJAIBugJPEGLS.cxx create mode 100644 gdcm/Examples/Cxx/GenAllVR.cxx create mode 100644 gdcm/Examples/Cxx/GenFakeIdentifyFile.cxx create mode 100644 gdcm/Examples/Cxx/GenFakeImage.cxx create mode 100644 gdcm/Examples/Cxx/GenLongSeqs.cxx create mode 100644 gdcm/Examples/Cxx/GenSeqs.cxx create mode 100644 gdcm/Examples/Cxx/GenerateStandardSOPClasses.cxx create mode 100644 gdcm/Examples/Cxx/GetJPEGSamplePrecision.cxx create mode 100644 gdcm/Examples/Cxx/GetSequenceUltrasound.cxx create mode 100644 gdcm/Examples/Cxx/GetSubSequenceData.cxx create mode 100644 gdcm/Examples/Cxx/HelloVizWorld.cxx create mode 100644 gdcm/Examples/Cxx/HelloWorld.cxx create mode 100644 gdcm/Examples/Cxx/LargeVRDSExplicit.cxx create mode 100644 gdcm/Examples/Cxx/MergeTwoFiles.cxx create mode 100644 gdcm/Examples/Cxx/MrProtocol.cxx create mode 100644 gdcm/Examples/Cxx/PatchFile.cxx create mode 100644 gdcm/Examples/Cxx/PublicDict.cxx create mode 100644 gdcm/Examples/Cxx/QIDO-RS.cxx create mode 100644 gdcm/Examples/Cxx/ReadAndDumpDICOMDIR.cxx create mode 100644 gdcm/Examples/Cxx/ReadAndPrintAttributes.cxx create mode 100644 gdcm/Examples/Cxx/ReadExplicitLengthSQIVR.cxx create mode 100644 gdcm/Examples/Cxx/ReadGEMSSDO.cxx create mode 100644 gdcm/Examples/Cxx/ReadMultiTimesException.cxx create mode 100644 gdcm/Examples/Cxx/ReadUTF8QtDir.cxx create mode 100644 gdcm/Examples/Cxx/SimpleScanner.cxx create mode 100644 gdcm/Examples/Cxx/SortImage.cxx create mode 100644 gdcm/Examples/Cxx/StreamImageReaderTest.cxx create mode 100644 gdcm/Examples/Cxx/TraverseModules.cxx create mode 100644 gdcm/Examples/Cxx/VolumeSorter.cxx create mode 100644 gdcm/Examples/Cxx/csa2img.cxx create mode 100644 gdcm/Examples/Cxx/iU22tomultisc.cxx create mode 100644 gdcm/Examples/Cxx/pmsct_rgb1.cxx create mode 100644 gdcm/Examples/Cxx/rle2img.cxx create mode 100644 gdcm/Examples/Cxx/uid_unique.cxx create mode 100644 gdcm/Examples/Java/CMakeLists.txt create mode 100644 gdcm/Examples/Java/DecompressImage.java create mode 100644 gdcm/Examples/Java/DecompressPixmap.java create mode 100644 gdcm/Examples/Java/ExtractImageRegion.java create mode 100644 gdcm/Examples/Java/FileAnonymize.java create mode 100644 gdcm/Examples/Java/HelloSimple.java create mode 100644 gdcm/Examples/Java/ReadFiles.java create mode 100644 gdcm/Examples/Java/ScanDirectory.java create mode 100644 gdcm/Examples/PHP/README.txt create mode 100644 gdcm/Examples/PHP/export_pnm.php create mode 100644 gdcm/Examples/PHP/hello_world.php create mode 100644 gdcm/Examples/PHP/modify_file.php create mode 100644 gdcm/Examples/PHP/qido.php create mode 100644 gdcm/Examples/PHP/rewrite_header.php create mode 100644 gdcm/Examples/Python/CMakeLists.txt create mode 100644 gdcm/Examples/Python/ConvertMPL.py create mode 100644 gdcm/Examples/Python/ConvertNumpy.py create mode 100644 gdcm/Examples/Python/ConvertPIL.py create mode 100644 gdcm/Examples/Python/CreateRAWStorage.py create mode 100644 gdcm/Examples/Python/DecompressImage.py create mode 100644 gdcm/Examples/Python/DumbAnonymizer.py create mode 100644 gdcm/Examples/Python/FindAllPatientName.py create mode 100644 gdcm/Examples/Python/FixCommaBug.py create mode 100644 gdcm/Examples/Python/GetPortionCSAHeader.py create mode 100644 gdcm/Examples/Python/HelloWorld.py create mode 100644 gdcm/Examples/Python/ManipulateFile.py create mode 100644 gdcm/Examples/Python/ManipulateSequence.py create mode 100644 gdcm/Examples/Python/MergeFile.py create mode 100644 gdcm/Examples/Python/NewSequence.py create mode 100644 gdcm/Examples/Python/PhilipsPrivateRescaleInterceptSlope.py create mode 100644 gdcm/Examples/Python/PlaySound.py create mode 100644 gdcm/Examples/Python/PrivateDict.py create mode 100644 gdcm/Examples/Python/ReWriteSCAsMR.py create mode 100644 gdcm/Examples/Python/ReadAndDumpDICOMDIR.py create mode 100644 gdcm/Examples/Python/RemovePrivateTags.py create mode 100644 gdcm/Examples/Python/ScanDirectory.py create mode 100644 gdcm/Examples/Python/SortImage.py create mode 100644 gdcm/Examples/Python/WriteBuffer.py create mode 100644 gdcm/INSTALL.txt create mode 100644 gdcm/PACKAGER create mode 100644 gdcm/README.Copyright.txt create mode 100644 gdcm/README.txt create mode 100644 gdcm/Source/Attribute/CMakeLists.txt create mode 100644 gdcm/Source/Attribute/README.txt create mode 100644 gdcm/Source/CMakeLists.txt create mode 100644 gdcm/Source/Common/CMakeLists.txt create mode 100644 gdcm/Source/Common/README.txt create mode 100644 gdcm/Source/Common/gdcmASN1.cxx create mode 100644 gdcm/Source/Common/gdcmASN1.h create mode 100644 gdcm/Source/Common/gdcmBase64.cxx create mode 100644 gdcm/Source/Common/gdcmBase64.h create mode 100644 gdcm/Source/Common/gdcmBoxRegion.cxx create mode 100644 gdcm/Source/Common/gdcmBoxRegion.h create mode 100644 gdcm/Source/Common/gdcmByteSwap.cxx create mode 100644 gdcm/Source/Common/gdcmByteSwap.h create mode 100644 gdcm/Source/Common/gdcmByteSwap.txx create mode 100644 gdcm/Source/Common/gdcmCAPICryptoFactory.cxx create mode 100644 gdcm/Source/Common/gdcmCAPICryptoFactory.h create mode 100644 gdcm/Source/Common/gdcmCAPICryptographicMessageSyntax.cxx create mode 100644 gdcm/Source/Common/gdcmCAPICryptographicMessageSyntax.h create mode 100644 gdcm/Source/Common/gdcmCommand.cxx create mode 100644 gdcm/Source/Common/gdcmCommand.h create mode 100644 gdcm/Source/Common/gdcmConfigure.h.in create mode 100644 gdcm/Source/Common/gdcmCryptoFactory.cxx create mode 100644 gdcm/Source/Common/gdcmCryptoFactory.h create mode 100644 gdcm/Source/Common/gdcmCryptographicMessageSyntax.cxx create mode 100644 gdcm/Source/Common/gdcmCryptographicMessageSyntax.h create mode 100644 gdcm/Source/Common/gdcmDataEvent.cxx create mode 100644 gdcm/Source/Common/gdcmDataEvent.h create mode 100644 gdcm/Source/Common/gdcmDeflateStream.cxx create mode 100644 gdcm/Source/Common/gdcmDeflateStream.h create mode 100644 gdcm/Source/Common/gdcmDirectory.cxx create mode 100644 gdcm/Source/Common/gdcmDirectory.h create mode 100644 gdcm/Source/Common/gdcmDummyValueGenerator.cxx create mode 100644 gdcm/Source/Common/gdcmDummyValueGenerator.h create mode 100644 gdcm/Source/Common/gdcmEvent.cxx create mode 100644 gdcm/Source/Common/gdcmEvent.h create mode 100644 gdcm/Source/Common/gdcmException.cxx create mode 100644 gdcm/Source/Common/gdcmException.h create mode 100644 gdcm/Source/Common/gdcmFileNameEvent.cxx create mode 100644 gdcm/Source/Common/gdcmFileNameEvent.h create mode 100644 gdcm/Source/Common/gdcmFilename.cxx create mode 100644 gdcm/Source/Common/gdcmFilename.h create mode 100644 gdcm/Source/Common/gdcmFilenameGenerator.cxx create mode 100644 gdcm/Source/Common/gdcmFilenameGenerator.h create mode 100644 gdcm/Source/Common/gdcmLegacyMacro.h create mode 100644 gdcm/Source/Common/gdcmMD5.cxx create mode 100644 gdcm/Source/Common/gdcmMD5.h create mode 100644 gdcm/Source/Common/gdcmObject.cxx create mode 100644 gdcm/Source/Common/gdcmObject.h create mode 100644 gdcm/Source/Common/gdcmOpenSSLCryptoFactory.cxx create mode 100644 gdcm/Source/Common/gdcmOpenSSLCryptoFactory.h create mode 100644 gdcm/Source/Common/gdcmOpenSSLCryptographicMessageSyntax.cxx create mode 100644 gdcm/Source/Common/gdcmOpenSSLCryptographicMessageSyntax.h create mode 100644 gdcm/Source/Common/gdcmOpenSSLP7CryptoFactory.cxx create mode 100644 gdcm/Source/Common/gdcmOpenSSLP7CryptoFactory.h create mode 100644 gdcm/Source/Common/gdcmOpenSSLP7CryptographicMessageSyntax.cxx create mode 100644 gdcm/Source/Common/gdcmOpenSSLP7CryptographicMessageSyntax.h create mode 100644 gdcm/Source/Common/gdcmProgressEvent.cxx create mode 100644 gdcm/Source/Common/gdcmProgressEvent.h create mode 100644 gdcm/Source/Common/gdcmRegion.cxx create mode 100644 gdcm/Source/Common/gdcmRegion.h create mode 100644 gdcm/Source/Common/gdcmSHA1.cxx create mode 100644 gdcm/Source/Common/gdcmSHA1.h create mode 100644 gdcm/Source/Common/gdcmSmartPointer.h create mode 100644 gdcm/Source/Common/gdcmStaticAssert.h create mode 100644 gdcm/Source/Common/gdcmString.cxx create mode 100644 gdcm/Source/Common/gdcmString.h create mode 100644 gdcm/Source/Common/gdcmSubject.cxx create mode 100644 gdcm/Source/Common/gdcmSubject.h create mode 100644 gdcm/Source/Common/gdcmSwapCode.cxx create mode 100644 gdcm/Source/Common/gdcmSwapCode.h create mode 100644 gdcm/Source/Common/gdcmSwapper.h create mode 100644 gdcm/Source/Common/gdcmSwapper.txx create mode 100644 gdcm/Source/Common/gdcmSystem.cxx create mode 100644 gdcm/Source/Common/gdcmSystem.h create mode 100644 gdcm/Source/Common/gdcmTerminal.cxx create mode 100644 gdcm/Source/Common/gdcmTerminal.h create mode 100644 gdcm/Source/Common/gdcmTestDriver.h create mode 100644 gdcm/Source/Common/gdcmTesting.cxx create mode 100644 gdcm/Source/Common/gdcmTesting.h create mode 100644 gdcm/Source/Common/gdcmTrace.cxx create mode 100644 gdcm/Source/Common/gdcmTrace.h create mode 100644 gdcm/Source/Common/gdcmTypes.h create mode 100644 gdcm/Source/Common/gdcmUnpacker12Bits.cxx create mode 100644 gdcm/Source/Common/gdcmUnpacker12Bits.h create mode 100644 gdcm/Source/Common/gdcmVersion.cxx create mode 100644 gdcm/Source/Common/gdcmVersion.h create mode 100644 gdcm/Source/Common/gdcmWin32.h create mode 100644 gdcm/Source/Common/zipstreamimpl.h create mode 100644 gdcm/Source/Common/zipstreamimpl.hpp create mode 100644 gdcm/Source/DataDictionary/06_03_list.txt create mode 100644 gdcm/Source/DataDictionary/Agfa.xml create mode 100644 gdcm/Source/DataDictionary/CMakeLists.txt create mode 100644 gdcm/Source/DataDictionary/COPYRIGHT.dicom3tools create mode 100644 gdcm/Source/DataDictionary/CSADefaultDicts.xsl create mode 100644 gdcm/Source/DataDictionary/CSAHeader.xml create mode 100644 gdcm/Source/DataDictionary/DefaultDicts.xsl create mode 100644 gdcm/Source/DataDictionary/DefaultPrivateDicts.xsl create mode 100644 gdcm/Source/DataDictionary/GroupName.dic create mode 100644 gdcm/Source/DataDictionary/HarvestedPrivate.xml create mode 100644 gdcm/Source/DataDictionary/NIH.dic create mode 100644 gdcm/Source/DataDictionary/ParseDicts.py create mode 100644 gdcm/Source/DataDictionary/Part6.xml create mode 100644 gdcm/Source/DataDictionary/Part67.xsl create mode 100644 gdcm/Source/DataDictionary/Part6PDF.xsl create mode 100644 gdcm/Source/DataDictionary/Part6todcm4che.xsl create mode 100644 gdcm/Source/DataDictionary/Part6togdcm1.xsl create mode 100644 gdcm/Source/DataDictionary/Part7.xml create mode 100644 gdcm/Source/DataDictionary/Part7.xsl create mode 100644 gdcm/Source/DataDictionary/PartToGDCM.xsl create mode 100644 gdcm/Source/DataDictionary/README.txt create mode 100644 gdcm/Source/DataDictionary/SPI.dic create mode 100644 gdcm/Source/DataDictionary/Siemens.xml create mode 100644 gdcm/Source/DataDictionary/TagKeywords.xsl create mode 100644 gdcm/Source/DataDictionary/TagToType.xsl create mode 100644 gdcm/Source/DataDictionary/TagToVR.xsl create mode 100644 gdcm/Source/DataDictionary/UIDToC++.xsl create mode 100644 gdcm/Source/DataDictionary/UIDs.xml create mode 100644 gdcm/Source/DataDictionary/VM.xsl create mode 100644 gdcm/Source/DataDictionary/cp699.xml create mode 100644 gdcm/Source/DataDictionary/dcmtk.xsl create mode 100644 gdcm/Source/DataDictionary/dicom3tools.xsl create mode 100644 gdcm/Source/DataDictionary/dicomhdr.html create mode 100644 gdcm/Source/DataDictionary/dicomhdr.xsl create mode 100644 gdcm/Source/DataDictionary/gdcm1.xsl create mode 100644 gdcm/Source/DataDictionary/gdcm2html.xsl create mode 100644 gdcm/Source/DataDictionary/gdcm2pdf.xsl create mode 100644 gdcm/Source/DataDictionary/gdcmCSAHeaderDefaultDicts.cxx create mode 100644 gdcm/Source/DataDictionary/gdcmCSAHeaderDict.h create mode 100644 gdcm/Source/DataDictionary/gdcmCSAHeaderDictEntry.h create mode 100644 gdcm/Source/DataDictionary/gdcmDefaultDicts.cxx create mode 100644 gdcm/Source/DataDictionary/gdcmDefaultGroupNames.cxx create mode 100644 gdcm/Source/DataDictionary/gdcmDict.h create mode 100644 gdcm/Source/DataDictionary/gdcmDictConverter.cxx create mode 100644 gdcm/Source/DataDictionary/gdcmDictConverter.h create mode 100644 gdcm/Source/DataDictionary/gdcmDictEntry.cxx create mode 100644 gdcm/Source/DataDictionary/gdcmDictEntry.h create mode 100644 gdcm/Source/DataDictionary/gdcmDicts.cxx create mode 100644 gdcm/Source/DataDictionary/gdcmDicts.h create mode 100644 gdcm/Source/DataDictionary/gdcmGlobal.cxx create mode 100644 gdcm/Source/DataDictionary/gdcmGlobal.h create mode 100644 gdcm/Source/DataDictionary/gdcmGroupDict.cxx create mode 100644 gdcm/Source/DataDictionary/gdcmGroupDict.h create mode 100644 gdcm/Source/DataDictionary/gdcmPrepDict.cxx create mode 100644 gdcm/Source/DataDictionary/gdcmPrepGroupName.cxx create mode 100644 gdcm/Source/DataDictionary/gdcmPrivateDefaultDicts.cxx create mode 100644 gdcm/Source/DataDictionary/gdcmRoot.cxx create mode 100644 gdcm/Source/DataDictionary/gdcmSOPClassUIDToIOD.cxx create mode 100644 gdcm/Source/DataDictionary/gdcmSOPClassUIDToIOD.h create mode 100644 gdcm/Source/DataDictionary/gdcmTagKeywords.h create mode 100644 gdcm/Source/DataDictionary/gdcmTagToType.h create mode 100644 gdcm/Source/DataDictionary/gdcmUIDs.cxx create mode 100644 gdcm/Source/DataDictionary/gdcmUIDs.h create mode 100644 gdcm/Source/DataDictionary/gdcmconformancetests.xml create mode 100644 gdcm/Source/DataDictionary/getname.xsl create mode 100644 gdcm/Source/DataDictionary/getowner.xsl create mode 100644 gdcm/Source/DataDictionary/getretired.xsl create mode 100644 gdcm/Source/DataDictionary/order.xsl create mode 100644 gdcm/Source/DataDictionary/priv2html.xsl create mode 100644 gdcm/Source/DataDictionary/privatedicts.xml create mode 100644 gdcm/Source/DataDictionary/redo.xsl create mode 100644 gdcm/Source/DataDictionary/redo2.xsl create mode 100644 gdcm/Source/DataDictionary/sort.xsl create mode 100644 gdcm/Source/DataDictionary/txt2xml.py create mode 100644 gdcm/Source/DataDictionary/uppercase.xsl create mode 100644 gdcm/Source/DataDictionary/vital.xml create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/CMakeLists.txt create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/README.txt create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmAttribute.h create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmBasicOffsetTable.h create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmByteBuffer.h create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmByteSwapFilter.cxx create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmByteSwapFilter.h create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmByteValue.cxx create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmByteValue.h create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmCP246ExplicitDataElement.cxx create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmCP246ExplicitDataElement.h create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmCP246ExplicitDataElement.txx create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmCSAElement.h create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmCSAHeader.cxx create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmCSAHeader.h create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmCSAHeader.txx create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmCodeString.cxx create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmCodeString.h create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmDataElement.cxx create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmDataElement.h create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmDataSet.cxx create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmDataSet.h create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmDataSet.txx create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmDataSetEvent.cxx create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmDataSetEvent.h create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmElement.h create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmExplicitDataElement.cxx create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmExplicitDataElement.h create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmExplicitDataElement.txx create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmExplicitImplicitDataElement.cxx create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmExplicitImplicitDataElement.h create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmExplicitImplicitDataElement.txx create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmFile.cxx create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmFile.h create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmFileMetaInformation.cxx create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmFileMetaInformation.h create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmFileSet.cxx create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmFileSet.h create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmFragment.cxx create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmFragment.h create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmFragment.txx create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmImplicitDataElement.cxx create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmImplicitDataElement.h create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmImplicitDataElement.txx create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmItem.cxx create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmItem.h create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmItem.txx create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmLO.h create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmMediaStorage.cxx create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmMediaStorage.h create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmPDBElement.h create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmPDBHeader.cxx create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmPDBHeader.h create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmParseException.cxx create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmParseException.h create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmParser.cxx create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmParser.h create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmPreamble.cxx create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmPreamble.h create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmPrivateTag.cxx create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmPrivateTag.h create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmReader.cxx create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmReader.h create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmSequenceOfFragments.cxx create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmSequenceOfFragments.h create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmSequenceOfFragments.txx create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmSequenceOfItems.cxx create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmSequenceOfItems.h create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmSequenceOfItems.txx create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmTag.cxx create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmTag.h create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmTagToVR.cxx create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmTagToVR.h create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmTransferSyntax.cxx create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmTransferSyntax.h create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmUNExplicitDataElement.cxx create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmUNExplicitDataElement.h create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmUNExplicitDataElement.txx create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmUNExplicitImplicitDataElement.cxx create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmUNExplicitImplicitDataElement.h create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmUNExplicitImplicitDataElement.txx create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmVL.h create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmVM.cxx create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmVM.h create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmVR.cxx create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmVR.h create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmVR16ExplicitDataElement.cxx create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmVR16ExplicitDataElement.h create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmVR16ExplicitDataElement.txx create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmValue.cxx create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmValue.h create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmValue.txx create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmValueIO.h create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmValueIO.txx create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmWriter.cxx create mode 100644 gdcm/Source/DataStructureAndEncodingDefinition/gdcmWriter.h create mode 100644 gdcm/Source/InformationObjectDefinition/CMakeLists.txt create mode 100644 gdcm/Source/InformationObjectDefinition/ParseAttributes.py create mode 100644 gdcm/Source/InformationObjectDefinition/Part3.xml create mode 100644 gdcm/Source/InformationObjectDefinition/Part3.xsl create mode 100644 gdcm/Source/InformationObjectDefinition/Part4.xml create mode 100644 gdcm/Source/InformationObjectDefinition/Part4.xsl create mode 100644 gdcm/Source/InformationObjectDefinition/Part4ToC++.xsl create mode 100644 gdcm/Source/InformationObjectDefinition/README.txt create mode 100644 gdcm/Source/InformationObjectDefinition/Template.xml.in create mode 100644 gdcm/Source/InformationObjectDefinition/ValueRepresentation.xsd create mode 100644 gdcm/Source/InformationObjectDefinition/extract.xsl create mode 100644 gdcm/Source/InformationObjectDefinition/gdcmDefinedTerms.cxx create mode 100644 gdcm/Source/InformationObjectDefinition/gdcmDefinedTerms.h create mode 100644 gdcm/Source/InformationObjectDefinition/gdcmDefs.cxx create mode 100644 gdcm/Source/InformationObjectDefinition/gdcmDefs.h create mode 100644 gdcm/Source/InformationObjectDefinition/gdcmEnumeratedValues.cxx create mode 100644 gdcm/Source/InformationObjectDefinition/gdcmEnumeratedValues.h create mode 100644 gdcm/Source/InformationObjectDefinition/gdcmIOD.cxx create mode 100644 gdcm/Source/InformationObjectDefinition/gdcmIOD.h create mode 100644 gdcm/Source/InformationObjectDefinition/gdcmIODEntry.cxx create mode 100644 gdcm/Source/InformationObjectDefinition/gdcmIODEntry.h create mode 100644 gdcm/Source/InformationObjectDefinition/gdcmIODs.h create mode 100644 gdcm/Source/InformationObjectDefinition/gdcmMacro.cxx create mode 100644 gdcm/Source/InformationObjectDefinition/gdcmMacro.h create mode 100644 gdcm/Source/InformationObjectDefinition/gdcmMacroEntry.h create mode 100644 gdcm/Source/InformationObjectDefinition/gdcmMacros.cxx create mode 100644 gdcm/Source/InformationObjectDefinition/gdcmMacros.h create mode 100644 gdcm/Source/InformationObjectDefinition/gdcmModule.cxx create mode 100644 gdcm/Source/InformationObjectDefinition/gdcmModule.h create mode 100644 gdcm/Source/InformationObjectDefinition/gdcmModuleEntry.h create mode 100644 gdcm/Source/InformationObjectDefinition/gdcmModules.cxx create mode 100644 gdcm/Source/InformationObjectDefinition/gdcmModules.h create mode 100644 gdcm/Source/InformationObjectDefinition/gdcmNestedModuleEntries.cxx create mode 100644 gdcm/Source/InformationObjectDefinition/gdcmNestedModuleEntries.h create mode 100644 gdcm/Source/InformationObjectDefinition/gdcmPatient.cxx create mode 100644 gdcm/Source/InformationObjectDefinition/gdcmPatient.h create mode 100644 gdcm/Source/InformationObjectDefinition/gdcmSeries.cxx create mode 100644 gdcm/Source/InformationObjectDefinition/gdcmSeries.h create mode 100644 gdcm/Source/InformationObjectDefinition/gdcmStudy.cxx create mode 100644 gdcm/Source/InformationObjectDefinition/gdcmStudy.h create mode 100644 gdcm/Source/InformationObjectDefinition/gdcmTable.cxx create mode 100644 gdcm/Source/InformationObjectDefinition/gdcmTable.h create mode 100644 gdcm/Source/InformationObjectDefinition/gdcmTableEntry.h create mode 100644 gdcm/Source/InformationObjectDefinition/gdcmTableReader.cxx create mode 100644 gdcm/Source/InformationObjectDefinition/gdcmTableReader.h create mode 100644 gdcm/Source/InformationObjectDefinition/gdcmTables.h.in create mode 100644 gdcm/Source/InformationObjectDefinition/gdcmType.cxx create mode 100644 gdcm/Source/InformationObjectDefinition/gdcmType.h create mode 100644 gdcm/Source/InformationObjectDefinition/gdcmUsage.cxx create mode 100644 gdcm/Source/InformationObjectDefinition/gdcmUsage.h create mode 100644 gdcm/Source/InformationObjectDefinition/gdcmXMLDictReader.cxx create mode 100644 gdcm/Source/InformationObjectDefinition/gdcmXMLDictReader.h create mode 100644 gdcm/Source/InformationObjectDefinition/gdcmXMLPrivateDictReader.cxx create mode 100644 gdcm/Source/InformationObjectDefinition/gdcmXMLPrivateDictReader.h create mode 100644 gdcm/Source/InformationObjectDefinition/getelements.xsl create mode 100644 gdcm/Source/InformationObjectDefinition/ma2html.xsl create mode 100644 gdcm/Source/InformationObjectDefinition/ma2pdf.xsl create mode 100644 gdcm/Source/MediaStorageAndFileFormat/CMakeLists.txt create mode 100644 gdcm/Source/MediaStorageAndFileFormat/FileMetaInformation.txt create mode 100644 gdcm/Source/MediaStorageAndFileFormat/README.txt create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmAnonymizeEvent.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmAnonymizeEvent.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmAnonymizer.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmAnonymizer.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmApplicationEntity.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmApplicationEntity.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmAudioCodec.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmAudioCodec.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmBitmap.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmBitmap.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmBitmapToBitmapFilter.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmBitmapToBitmapFilter.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmCodec.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmCoder.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmConstCharWrapper.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmCurve.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmCurve.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmDICOMDIR.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmDICOMDIR.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmDICOMDIRGenerator.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmDICOMDIRGenerator.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmDataSetHelper.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmDataSetHelper.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmDecoder.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmDeltaEncodingCodec.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmDeltaEncodingCodec.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmDictPrinter.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmDictPrinter.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmDirectionCosines.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmDirectionCosines.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmDirectoryHelper.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmDirectoryHelper.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmDumper.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmDumper.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmEncapsulatedDocument.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmEncapsulatedDocument.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmFiducials.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmFiducials.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmFileAnonymizer.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmFileAnonymizer.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmFileChangeTransferSyntax.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmFileChangeTransferSyntax.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmFileDerivation.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmFileDerivation.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmFileExplicitFilter.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmFileExplicitFilter.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmFileStreamer.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmFileStreamer.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmIPPSorter.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmIPPSorter.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmIconImage.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmIconImage.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmIconImageFilter.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmIconImageFilter.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmIconImageGenerator.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmIconImageGenerator.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmImage.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmImage.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmImageApplyLookupTable.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmImageApplyLookupTable.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmImageChangePhotometricInterpretation.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmImageChangePhotometricInterpretation.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmImageChangePlanarConfiguration.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmImageChangePlanarConfiguration.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmImageChangeTransferSyntax.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmImageChangeTransferSyntax.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmImageCodec.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmImageCodec.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmImageConverter.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmImageConverter.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmImageFragmentSplitter.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmImageFragmentSplitter.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmImageHelper.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmImageHelper.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmImageReader.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmImageReader.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmImageRegionReader.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmImageRegionReader.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmImageToImageFilter.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmImageToImageFilter.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmImageWriter.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmImageWriter.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmJPEG12Codec.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmJPEG12Codec.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmJPEG16Codec.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmJPEG16Codec.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmJPEG2000Codec.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmJPEG2000Codec.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmJPEG8Codec.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmJPEG8Codec.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmJPEGBITSCodec.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmJPEGCodec.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmJPEGCodec.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmJPEGLSCodec.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmJPEGLSCodec.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmJSON.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmJSON.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmKAKADUCodec.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmKAKADUCodec.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmLookupTable.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmLookupTable.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmMeshPrimitive.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmMeshPrimitive.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmOrientation.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmOrientation.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmOverlay.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmOverlay.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmPDFCodec.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmPDFCodec.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmPGXCodec.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmPGXCodec.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmPNMCodec.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmPNMCodec.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmPVRGCodec.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmPVRGCodec.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmPersonName.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmPersonName.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmPhotometricInterpretation.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmPhotometricInterpretation.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmPixelFormat.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmPixelFormat.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmPixmap.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmPixmap.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmPixmapReader.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmPixmapReader.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmPixmapToPixmapFilter.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmPixmapToPixmapFilter.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmPixmapWriter.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmPixmapWriter.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmPrinter.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmPrinter.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmRAWCodec.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmRAWCodec.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmRLECodec.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmRLECodec.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmRescaler.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmRescaler.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmScanner.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmScanner.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmSegment.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmSegment.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmSegmentHelper.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmSegmentHelper.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmSegmentReader.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmSegmentReader.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmSegmentWriter.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmSegmentWriter.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmSegmentedPaletteColorLookupTable.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmSegmentedPaletteColorLookupTable.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmSerieHelper.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmSerieHelper.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmSimpleSubjectWatcher.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmSimpleSubjectWatcher.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmSorter.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmSorter.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmSpacing.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmSpacing.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmSpectroscopy.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmSpectroscopy.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmSplitMosaicFilter.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmSplitMosaicFilter.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmStreamImageReader.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmStreamImageReader.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmStreamImageWriter.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmStreamImageWriter.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmStringFilter.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmStringFilter.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmSurface.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmSurface.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmSurfaceHelper.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmSurfaceHelper.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmSurfaceReader.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmSurfaceReader.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmSurfaceWriter.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmSurfaceWriter.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmTagPath.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmTagPath.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmUIDGenerator.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmUIDGenerator.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmUUIDGenerator.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmUUIDGenerator.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmValidate.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmValidate.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmWaveform.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmWaveform.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmXMLPrinter.cxx create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcmXMLPrinter.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcm_j2k.h create mode 100644 gdcm/Source/MediaStorageAndFileFormat/gdcm_jp2.h create mode 100644 gdcm/Source/MessageExchangeDefinition/CMakeLists.txt create mode 100644 gdcm/Source/MessageExchangeDefinition/README.txt create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmAAbortPDU.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmAAbortPDU.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmAAssociateACPDU.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmAAssociateACPDU.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmAAssociateRJPDU.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmAAssociateRJPDU.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmAAssociateRQPDU.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmAAssociateRQPDU.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmARTIMTimer.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmARTIMTimer.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmAReleaseRPPDU.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmAReleaseRPPDU.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmAReleaseRQPDU.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmAReleaseRQPDU.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmAbstractSyntax.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmAbstractSyntax.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmApplicationContext.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmApplicationContext.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmAsynchronousOperationsWindowSub.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmAsynchronousOperationsWindowSub.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmBaseCompositeMessage.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmBasePDU.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmBaseRootQuery.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmBaseRootQuery.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmCEchoMessages.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmCEchoMessages.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmCFindMessages.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmCFindMessages.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmCMoveMessages.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmCMoveMessages.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmCStoreMessages.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmCStoreMessages.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmCommandDataSet.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmCommandDataSet.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmCompositeMessageFactory.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmCompositeMessageFactory.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmCompositeNetworkFunctions.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmCompositeNetworkFunctions.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmDIMSE.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmFindPatientRootQuery.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmFindPatientRootQuery.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmFindStudyRootQuery.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmFindStudyRootQuery.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmImplementationClassUIDSub.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmImplementationClassUIDSub.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmImplementationUIDSub.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmImplementationUIDSub.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmImplementationVersionNameSub.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmImplementationVersionNameSub.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmMaximumLengthSub.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmMaximumLengthSub.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmMovePatientRootQuery.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmMovePatientRootQuery.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmMoveStudyRootQuery.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmMoveStudyRootQuery.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmNetworkEvents.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmNetworkStateID.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmPDUFactory.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmPDUFactory.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmPDataTFPDU.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmPDataTFPDU.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmPresentationContext.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmPresentationContext.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmPresentationContextAC.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmPresentationContextAC.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmPresentationContextGenerator.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmPresentationContextGenerator.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmPresentationContextRQ.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmPresentationContextRQ.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmPresentationDataValue.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmPresentationDataValue.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmQueryBase.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmQueryBase.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmQueryFactory.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmQueryFactory.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmQueryImage.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmQueryImage.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmQueryPatient.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmQueryPatient.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmQuerySeries.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmQuerySeries.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmQueryStudy.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmQueryStudy.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmRoleSelectionSub.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmRoleSelectionSub.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmSOPClassExtendedNegociationSub.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmSOPClassExtendedNegociationSub.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmServiceClassApplicationInformation.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmServiceClassApplicationInformation.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmServiceClassUser.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmServiceClassUser.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmTransferSyntaxSub.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmTransferSyntaxSub.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmULAction.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmULActionAA.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmULActionAA.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmULActionAE.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmULActionAE.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmULActionAR.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmULActionAR.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmULActionDT.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmULActionDT.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmULBasicCallback.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmULBasicCallback.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmULConnection.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmULConnection.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmULConnectionCallback.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmULConnectionInfo.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmULConnectionInfo.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmULConnectionManager.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmULConnectionManager.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmULEvent.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmULTransitionTable.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmULTransitionTable.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmULWritingCallback.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmULWritingCallback.h create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmUserInformation.cxx create mode 100644 gdcm/Source/MessageExchangeDefinition/gdcmUserInformation.h create mode 100644 gdcm/Testing/.NoDartCoverage create mode 100644 gdcm/Testing/CMakeLists.txt create mode 100644 gdcm/Testing/Source/Attribute/CMakeLists.txt create mode 100644 gdcm/Testing/Source/CMakeLists.txt create mode 100644 gdcm/Testing/Source/Common/CMakeLists.txt create mode 100644 gdcm/Testing/Source/Common/Cxx/CMakeLists.txt create mode 100644 gdcm/Testing/Source/Common/Cxx/TestASN1.cxx create mode 100644 gdcm/Testing/Source/Common/Cxx/TestBase64.cxx create mode 100644 gdcm/Testing/Source/Common/Cxx/TestByteSwap.cxx create mode 100644 gdcm/Testing/Source/Common/Cxx/TestCommand.cxx create mode 100644 gdcm/Testing/Source/Common/Cxx/TestCryptographicMessageSyntax.cxx create mode 100644 gdcm/Testing/Source/Common/Cxx/TestDirectory.cxx create mode 100644 gdcm/Testing/Source/Common/Cxx/TestDummyValueGenerator.cxx create mode 100644 gdcm/Testing/Source/Common/Cxx/TestFilename.cxx create mode 100644 gdcm/Testing/Source/Common/Cxx/TestFilenameGenerator.cxx create mode 100644 gdcm/Testing/Source/Common/Cxx/TestMD5.cxx create mode 100644 gdcm/Testing/Source/Common/Cxx/TestObject.cxx create mode 100644 gdcm/Testing/Source/Common/Cxx/TestSHA1.cxx create mode 100644 gdcm/Testing/Source/Common/Cxx/TestSmartPointer.cxx create mode 100644 gdcm/Testing/Source/Common/Cxx/TestString.cxx create mode 100644 gdcm/Testing/Source/Common/Cxx/TestString2.cxx create mode 100644 gdcm/Testing/Source/Common/Cxx/TestSwapCode.cxx create mode 100644 gdcm/Testing/Source/Common/Cxx/TestSwapper.cxx create mode 100644 gdcm/Testing/Source/Common/Cxx/TestSystem1.cxx create mode 100644 gdcm/Testing/Source/Common/Cxx/TestSystem2.cxx create mode 100644 gdcm/Testing/Source/Common/Cxx/TestSystem3.cxx create mode 100644 gdcm/Testing/Source/Common/Cxx/TestTerminal.cxx create mode 100644 gdcm/Testing/Source/Common/Cxx/TestTesting.cxx create mode 100644 gdcm/Testing/Source/Common/Cxx/TestTrace.cxx create mode 100644 gdcm/Testing/Source/Common/Cxx/TestTypes.cxx create mode 100644 gdcm/Testing/Source/Common/Cxx/TestUnpacker12Bits.cxx create mode 100644 gdcm/Testing/Source/Common/Cxx/TestVersion.cxx create mode 100644 gdcm/Testing/Source/Common/Python/CMakeLists.txt create mode 100644 gdcm/Testing/Source/Common/Python/TestDirectory.py create mode 100644 gdcm/Testing/Source/Common/Python/TestTesting.py create mode 100644 gdcm/Testing/Source/Data/CMakeLists.txt create mode 100644 gdcm/Testing/Source/Data/NativeDICOM.rnc create mode 100644 gdcm/Testing/Source/Data/NativeDICOM.rng create mode 100644 gdcm/Testing/Source/Data/QIDO-RS_examplesup166.json create mode 100644 gdcm/Testing/Source/Data/certificate.pem create mode 100644 gdcm/Testing/Source/Data/encrypted_text create mode 100644 gdcm/Testing/Source/Data/gdcmDataFileNames.cxx.in create mode 100644 gdcm/Testing/Source/Data/gdcmMD5DataBrokenImages.cxx create mode 100644 gdcm/Testing/Source/Data/gdcmMD5DataImages.cxx create mode 100644 gdcm/Testing/Source/Data/gdcmMediaStorageDataFiles.cxx create mode 100644 gdcm/Testing/Source/Data/gdcmSelectedTagsOffsetDataFiles.cxx create mode 100644 gdcm/Testing/Source/Data/gdcmStreamOffsetDataFiles.cxx create mode 100644 gdcm/Testing/Source/Data/out.bin create mode 100644 gdcm/Testing/Source/Data/privatekey.pem create mode 100644 gdcm/Testing/Source/Data/text create mode 100644 gdcm/Testing/Source/DataDictionary/CMakeLists.txt create mode 100644 gdcm/Testing/Source/DataDictionary/Cxx/CMakeLists.txt create mode 100644 gdcm/Testing/Source/DataDictionary/Cxx/TestDict.cxx create mode 100644 gdcm/Testing/Source/DataDictionary/Cxx/TestDictEntry.cxx create mode 100644 gdcm/Testing/Source/DataDictionary/Cxx/TestDicts.cxx create mode 100644 gdcm/Testing/Source/DataDictionary/Cxx/TestGlobal.cxx create mode 100644 gdcm/Testing/Source/DataDictionary/Cxx/TestGroupDict.cxx create mode 100644 gdcm/Testing/Source/DataDictionary/Cxx/TestSOPClassUIDToIOD.cxx create mode 100644 gdcm/Testing/Source/DataDictionary/Cxx/TestTagKeywords.cxx create mode 100644 gdcm/Testing/Source/DataDictionary/Cxx/TestTagToType.cxx create mode 100644 gdcm/Testing/Source/DataDictionary/Cxx/TestTagToType.xsl create mode 100644 gdcm/Testing/Source/DataDictionary/Cxx/TestUIDs.cxx create mode 100644 gdcm/Testing/Source/DataDictionary/Python/CMakeLists.txt create mode 100644 gdcm/Testing/Source/DataDictionary/Python/TestDict.py create mode 100644 gdcm/Testing/Source/DataDictionary/Python/TestGlobal.py create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/CMakeLists.txt create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/CMakeLists.txt create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestAttribute.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestAttribute.xsl create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestAttribute1.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestAttribute2.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestAttribute3.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestAttribute4.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestAttribute5.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestAttribute6.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestAttribute7.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestAttribute8.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestBasicOffsetTable.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestByteBuffer.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestByteSwapFilter.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestByteValue.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestCSAElement.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestCSAHeader.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestCodeString.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestComposite.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestCopyValue.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestDS.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestDataElement.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestDataSet.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestElement.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestElement2.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestElement3.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestElement4.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestElement5.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestExplicitDataElement.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestFile.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestFileMetaInformation.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestFileSet.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestFragment.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestImplicitDataElement.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestInvalidDICOMFiles.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestItem.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestLCNumeric.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestLO.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestMediaStorage.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestPDBHeader.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestParseException.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestParser.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestPreamble.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestPrivateTag.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestReadPatientName.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestReader.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestReader2.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestReader3.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestReader4.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestReaderCanRead.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestReaderSelectedPrivateGroups.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestReaderSelectedTags.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestReaderUpToTag.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestReaderUpToTag2.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestSequenceOfFragments.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestSequenceOfItems.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestSequenceOfItems2.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestTag.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestTorture.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestTransferSyntax.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestVL.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestVM.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestVR.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestVRDS.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestVRLT.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestVRUI.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestValue.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestWriter.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestWriter2.cxx create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Java/CMakeLists.txt create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Java/TestReader.java create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Python/CMakeLists.txt create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Python/TestReader.py create mode 100644 gdcm/Testing/Source/DataStructureAndEncodingDefinition/Python/TestTag.py create mode 100644 gdcm/Testing/Source/InformationObjectDefinition/CMakeLists.txt create mode 100644 gdcm/Testing/Source/InformationObjectDefinition/Cxx/CMakeLists.txt create mode 100644 gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestDefinedTerms.cxx create mode 100644 gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestDefs.cxx create mode 100644 gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestEnumeratedValues.cxx create mode 100644 gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestIOD.cxx create mode 100644 gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestIODEntry.cxx create mode 100644 gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestIODs.cxx create mode 100644 gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestModule.cxx create mode 100644 gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestModuleEntry.cxx create mode 100644 gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestModules.cxx create mode 100644 gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestNestedModuleEntries.cxx create mode 100644 gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestPatient.cxx create mode 100644 gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestSeries.cxx create mode 100644 gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestStudy.cxx create mode 100644 gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestTable.cxx create mode 100644 gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestTableEntry.cxx create mode 100644 gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestTableReader.cxx create mode 100644 gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestType.cxx create mode 100644 gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestUsage.cxx create mode 100644 gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestXMLDictReader.cxx create mode 100644 gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestXMLPrivateDictReader.cxx create mode 100644 gdcm/Testing/Source/InformationObjectDefinition/Python/CMakeLists.txt create mode 100644 gdcm/Testing/Source/InformationObjectDefinition/Python/TestMRModule.py create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/CMakeLists.txt create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/CMakeLists.txt create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestAnonymizeEvent.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestAnonymizer.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestAnonymizer2.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestAnonymizer3.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestApplicationEntity.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestAudioCodec.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestCodec.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestCoder.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestCopyDataSet.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestCurve.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestCurve2.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestDICOMDIR.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestDICOMDIRGenerator1.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestDICOMDIRGenerator2.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestDataElementValueAsSQ.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestDecoder.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestDictPrinter.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestDirectionCosines.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestDumper.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestEncapsulatedDocument.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFiducials.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFileAnonymizer1.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFileAnonymizer2.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFileAnonymizer3.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFileChangeTransferSyntax1.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFileDerivation.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFileExplicitFilter.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFileStreamer1.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFileStreamer2.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFileStreamer3.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFileStreamer4.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFileStreamer5.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFileStreamer6.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFloatingPointDouble.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestIPPSorter.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestIPPSorter2.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestIPPSorter3.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestIconImage.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestIconImageFilter.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestIconImageGenerator.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestIconImageGenerator2.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestIconImageGenerator3.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestIconImageGenerator4.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImage.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageApplyLookupTable.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageChangePhotometricInterpretation.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageChangePhotometricInterpretation2.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageChangePlanarConfiguration.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageChangeTransferSyntax1.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageChangeTransferSyntax2.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageChangeTransferSyntax3.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageChangeTransferSyntax4.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageChangeTransferSyntax5.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageChangeTransferSyntax6.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageChangeTransferSyntax7.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageCodec.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageConverter.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageFragmentSplitter.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageHelper.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageReader.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageReaderPixelSpacing.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageReaderRandomEmpty.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageRegionReader1.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageRegionReader2.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageRegionReader3.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageRegionReader4.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageToImageFilter.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageWriter.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageWriter2.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestJPEGCodec.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestJSON1.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestLookupTable.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestOrientation.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestOverlay.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestOverlay2.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestOverlay3.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestPDFCodec.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestPNMCodec.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestParseXPATH.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestPersonName.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestPhotometricInterpretation.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestPixelFormat.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestPrint.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestPrinter.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestPrinter2.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestRAWCodec.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestRLECodec.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestRescaler.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestScanner.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestSegmentedPaletteColorLookupTable.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestSerieHelper.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestSorter.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestSpacing.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestSpectroscopy.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestSplitMosaicFilter.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestStreamImageReader.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestStreamImageWriter.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestStringFilter.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestSurfaceWriter.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestSurfaceWriter2.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestTagPath.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestUIDGenerator.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestUIDGenerator2.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestUIDGenerator3.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestUUIDGenerator.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestValidate.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestWaveform.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestWriter2.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestXMLPrinter.cxx create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Python/CMakeLists.txt create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Python/TestAnonymizer.py create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Python/TestDCMTKMD5.py create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Python/TestIPPSorter.py create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Python/TestImageReader.py create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Python/TestKakaduDecompressionMD5.py create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Python/TestModifyFields.py create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Python/TestOrientation.py create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Python/TestPythonFilter.py create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Python/TestScanner.py create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Python/TestStringFilter.py create mode 100644 gdcm/Testing/Source/MediaStorageAndFileFormat/Python/TestUIDGenerator.py create mode 100644 gdcm/Testing/Source/MessageExchangeDefinition/CMakeLists.txt create mode 100644 gdcm/Testing/Source/MessageExchangeDefinition/Cxx/CMakeLists.txt create mode 100644 gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestEcho.cxx create mode 100644 gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestFind.cxx create mode 100644 gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestFindPatientRootQuery.cxx create mode 100644 gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestFindStudyRootQuery.cxx create mode 100644 gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestPresentationContextRQ.cxx create mode 100644 gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestQueryFactory.cxx create mode 100644 gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestSCUFunctions.cxx create mode 100644 gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestSCUValidation.cxx create mode 100644 gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestServiceClassUser1.cxx create mode 100644 gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestServiceClassUser2.cxx create mode 100644 gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestServiceClassUser3.cxx create mode 100644 gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestULConnectionManager.cxx create mode 100644 gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestULTransitionTable.cxx create mode 100644 gdcm/Utilities/C99/CMakeLists.txt create mode 100644 gdcm/Utilities/C99/COPYING create mode 100644 gdcm/Utilities/C99/README.txt create mode 100644 gdcm/Utilities/C99/stdint.h create mode 100644 gdcm/Utilities/CMakeLists.txt create mode 100644 gdcm/Utilities/KWStyle/CMakeLists.txt create mode 100644 gdcm/Utilities/KWStyle/GDCM.kws.xml.in create mode 100644 gdcm/Utilities/KWStyle/GDCMFiles.txt.in create mode 100644 gdcm/Utilities/KWStyle/GDCMHeader.h create mode 100644 gdcm/Utilities/KWStyle/GDCMOverwrite.txt create mode 100644 gdcm/Utilities/Release/README.txt create mode 100644 gdcm/Utilities/Release/bootstrap.sh create mode 100644 gdcm/Utilities/Release/config.linux create mode 100644 gdcm/Utilities/Release/config.win32 create mode 100644 gdcm/Utilities/Release/makerelease.sh create mode 100644 gdcm/Utilities/Release/release.bat create mode 100644 gdcm/Utilities/Release/release.sh create mode 100644 gdcm/Utilities/Tools/CMakeLists.txt create mode 100644 gdcm/Utilities/Tools/upsidedown.c create mode 100644 gdcm/Utilities/VTK/.NoDartCoverage create mode 100644 gdcm/Utilities/VTK/Applications/CMakeLists.txt create mode 100644 gdcm/Utilities/VTK/Applications/gdcm2pnm.cxx create mode 100644 gdcm/Utilities/VTK/Applications/gdcm2vtk.cxx create mode 100644 gdcm/Utilities/VTK/Applications/gdcmviewer.cxx create mode 100644 gdcm/Utilities/VTK/AssemblyInfo.cs.in create mode 100644 gdcm/Utilities/VTK/CMakeLists.txt create mode 100644 gdcm/Utilities/VTK/CscArgs.txt.in create mode 100644 gdcm/Utilities/VTK/Examples/CMakeLists.txt create mode 100644 gdcm/Utilities/VTK/Examples/Csharp/CMakeLists.txt create mode 100644 gdcm/Utilities/VTK/Examples/Csharp/HelloActiviz.cs create mode 100644 gdcm/Utilities/VTK/Examples/Csharp/HelloActiviz2.cs create mode 100644 gdcm/Utilities/VTK/Examples/Csharp/HelloActiviz3.cs create mode 100644 gdcm/Utilities/VTK/Examples/Csharp/HelloActiviz4.cs create mode 100644 gdcm/Utilities/VTK/Examples/Csharp/HelloActiviz5.cs create mode 100644 gdcm/Utilities/VTK/Examples/Csharp/HelloVTKWorld.cs create mode 100644 gdcm/Utilities/VTK/Examples/Csharp/HelloVTKWorld2.cs create mode 100644 gdcm/Utilities/VTK/Examples/Csharp/MetaImageMD5Activiz.cs create mode 100644 gdcm/Utilities/VTK/Examples/Csharp/RefCounting.cs create mode 100644 gdcm/Utilities/VTK/Examples/Cxx/CMakeLists.txt create mode 100644 gdcm/Utilities/VTK/Examples/Cxx/Convert16BitsTo8Bits.cxx create mode 100644 gdcm/Utilities/VTK/Examples/Cxx/ConvertMultiFrameToSingleFrame.cxx create mode 100644 gdcm/Utilities/VTK/Examples/Cxx/ConvertRGBToLuminance.cxx create mode 100644 gdcm/Utilities/VTK/Examples/Cxx/ConvertSingleBitTo8Bits.cxx create mode 100644 gdcm/Utilities/VTK/Examples/Cxx/GenerateRTSTRUCT.cxx create mode 100644 gdcm/Utilities/VTK/Examples/Cxx/MagnifyFile.cxx create mode 100644 gdcm/Utilities/VTK/Examples/Cxx/gdcmorthoplanes.cxx create mode 100644 gdcm/Utilities/VTK/Examples/Cxx/gdcmreslice.cxx create mode 100644 gdcm/Utilities/VTK/Examples/Cxx/gdcmrtionplan.cxx create mode 100644 gdcm/Utilities/VTK/Examples/Cxx/gdcmrtplan.cxx create mode 100644 gdcm/Utilities/VTK/Examples/Cxx/gdcmscene.cxx create mode 100644 gdcm/Utilities/VTK/Examples/Cxx/gdcmtexture.cxx create mode 100644 gdcm/Utilities/VTK/Examples/Cxx/gdcmvolume.cxx create mode 100644 gdcm/Utilities/VTK/Examples/Cxx/offscreenimage.cxx create mode 100644 gdcm/Utilities/VTK/Examples/Cxx/reslicesphere.cxx create mode 100644 gdcm/Utilities/VTK/Examples/Cxx/rtstructapp.cxx create mode 100644 gdcm/Utilities/VTK/Examples/Cxx/threadgdcm.cxx create mode 100644 gdcm/Utilities/VTK/Examples/Java/AWTMedical3.java create mode 100644 gdcm/Utilities/VTK/Examples/Java/CMakeLists.txt create mode 100644 gdcm/Utilities/VTK/Examples/Java/HelloVTKWorld.java create mode 100644 gdcm/Utilities/VTK/Examples/Java/MIPViewer.java create mode 100644 gdcm/Utilities/VTK/Examples/Java/MPRViewer.java create mode 100644 gdcm/Utilities/VTK/Examples/Java/MPRViewer2.java create mode 100644 gdcm/Utilities/VTK/Examples/Java/ReadSeriesIntoVTK.java create mode 100644 gdcm/Utilities/VTK/Examples/PHP/generate_png.php create mode 100644 gdcm/Utilities/VTK/Examples/Python/CastConvertPhilips.py create mode 100644 gdcm/Utilities/VTK/Examples/Python/headsq2dcm.py create mode 100644 gdcm/Utilities/VTK/GDCMImageGUI.xml create mode 100644 gdcm/Utilities/VTK/GDCMImageReader.xml create mode 100644 gdcm/Utilities/VTK/JavaDependencies.cmake.in create mode 100644 gdcm/Utilities/VTK/MummySettings.xml.in create mode 100644 gdcm/Utilities/VTK/Testing/CMakeLists.txt create mode 100644 gdcm/Utilities/VTK/Testing/Cxx/CMakeLists.txt create mode 100644 gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMImageActor.cxx create mode 100644 gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMImageReader.cxx create mode 100644 gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMImageReader1.cxx create mode 100644 gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMImageReader2_1.cxx create mode 100644 gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMImageReader2_2.cxx create mode 100644 gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMImageReader3.cxx create mode 100644 gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMImageReader4.cxx create mode 100644 gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMImageReaderIsLossy.cxx create mode 100644 gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMImageViewer.cxx create mode 100644 gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMImageWriter1.cxx create mode 100644 gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMImageWriter2.cxx create mode 100644 gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMImageWriterIsLossy.cxx create mode 100644 gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMMetaImageWriter.cxx create mode 100644 gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMMetaImageWriter2.cxx create mode 100644 gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMPolyDataReader.cxx create mode 100644 gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMThreadedImageReader.cxx create mode 100644 gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMThreadedImageReader2.cxx create mode 100644 gdcm/Utilities/VTK/Testing/Cxx/TestvtkImageChangeInformation.cxx create mode 100644 gdcm/Utilities/VTK/Testing/Java/CMakeLists.txt create mode 100644 gdcm/Utilities/VTK/Testing/Java/TestvtkGDCMImageReader.java create mode 100644 gdcm/Utilities/VTK/Testing/Python/CMakeLists.txt create mode 100644 gdcm/Utilities/VTK/Testing/Python/TestMultiframeGrayscaleWordSecondaryCaptureImageStorage.py create mode 100644 gdcm/Utilities/VTK/Testing/Python/TestvtkGDCMImageReader.py create mode 100644 gdcm/Utilities/VTK/Testing/Python/TestvtkGDCMImageReader2.py create mode 100644 gdcm/Utilities/VTK/Testing/Python/TestvtkGDCMImageWriter.py create mode 100644 gdcm/Utilities/VTK/Testing/Python/TestvtkGDCMThreadedImageReader.py create mode 100644 gdcm/Utilities/VTK/Testing/Python/TestvtkGDCMThreadedImageReader2.py create mode 100644 gdcm/Utilities/VTK/VTK4/vtkMedicalImageProperties.cxx create mode 100644 gdcm/Utilities/VTK/VTK4/vtkMedicalImageProperties.h create mode 100644 gdcm/Utilities/VTK/VTK4/vtkStringArray.cxx create mode 100644 gdcm/Utilities/VTK/VTK4/vtkStringArray.h create mode 100644 gdcm/Utilities/VTK/dllexportconf.cs create mode 100644 gdcm/Utilities/VTK/gccxml.cxx.in create mode 100644 gdcm/Utilities/VTK/manifest.txt create mode 100644 gdcm/Utilities/VTK/vtkGDCMImageReader.cxx create mode 100644 gdcm/Utilities/VTK/vtkGDCMImageReader.h create mode 100644 gdcm/Utilities/VTK/vtkGDCMImageReader2.cxx create mode 100644 gdcm/Utilities/VTK/vtkGDCMImageReader2.h create mode 100644 gdcm/Utilities/VTK/vtkGDCMImageReader_Extra.cs create mode 100644 gdcm/Utilities/VTK/vtkGDCMImageWriter.cxx create mode 100644 gdcm/Utilities/VTK/vtkGDCMImageWriter.h create mode 100644 gdcm/Utilities/VTK/vtkGDCMMedicalImageProperties.cxx create mode 100644 gdcm/Utilities/VTK/vtkGDCMMedicalImageProperties.h create mode 100644 gdcm/Utilities/VTK/vtkGDCMPolyDataReader.cxx create mode 100644 gdcm/Utilities/VTK/vtkGDCMPolyDataReader.h create mode 100644 gdcm/Utilities/VTK/vtkGDCMPolyDataWriter.cxx create mode 100644 gdcm/Utilities/VTK/vtkGDCMPolyDataWriter.h create mode 100644 gdcm/Utilities/VTK/vtkGDCMTesting.cxx create mode 100644 gdcm/Utilities/VTK/vtkGDCMTesting.h create mode 100644 gdcm/Utilities/VTK/vtkGDCMThreadedImageReader.cxx create mode 100644 gdcm/Utilities/VTK/vtkGDCMThreadedImageReader.h create mode 100644 gdcm/Utilities/VTK/vtkGDCMThreadedImageReader2.cxx create mode 100644 gdcm/Utilities/VTK/vtkGDCMThreadedImageReader2.h create mode 100644 gdcm/Utilities/VTK/vtkImageColorViewer.cxx create mode 100644 gdcm/Utilities/VTK/vtkImageColorViewer.h create mode 100644 gdcm/Utilities/VTK/vtkImageMapToColors16.cxx create mode 100644 gdcm/Utilities/VTK/vtkImageMapToColors16.h create mode 100644 gdcm/Utilities/VTK/vtkImageMapToWindowLevelColors2.cxx create mode 100644 gdcm/Utilities/VTK/vtkImageMapToWindowLevelColors2.h create mode 100644 gdcm/Utilities/VTK/vtkImagePlanarComponentsToComponents.cxx create mode 100644 gdcm/Utilities/VTK/vtkImagePlanarComponentsToComponents.h create mode 100644 gdcm/Utilities/VTK/vtkImageRGBToYBR.cxx create mode 100644 gdcm/Utilities/VTK/vtkImageRGBToYBR.h create mode 100644 gdcm/Utilities/VTK/vtkImageYBRToRGB.cxx create mode 100644 gdcm/Utilities/VTK/vtkImageYBRToRGB.h create mode 100644 gdcm/Utilities/VTK/vtkLookupTable16.cxx create mode 100644 gdcm/Utilities/VTK/vtkLookupTable16.h create mode 100644 gdcm/Utilities/VTK/vtkRTStructSetProperties.cxx create mode 100644 gdcm/Utilities/VTK/vtkRTStructSetProperties.h create mode 100644 gdcm/Utilities/VTK/vtkgdcm.i create mode 100644 gdcm/Utilities/VTK/vtkgdcm.py create mode 100644 gdcm/Utilities/dicom3tools/process.sh create mode 100644 gdcm/Utilities/doxygen/CMakeLists.txt create mode 100644 gdcm/Utilities/doxygen/README create mode 100644 gdcm/Utilities/doxygen/README.txt.in create mode 100644 gdcm/Utilities/doxygen/TestsList.txt.in create mode 100644 gdcm/Utilities/doxygen/authors.xml create mode 100644 gdcm/Utilities/doxygen/doxyfile.in create mode 100644 gdcm/Utilities/doxygen/footer.html create mode 100644 gdcm/Utilities/doxygen/man/gdcm2pnm.man create mode 100644 gdcm/Utilities/doxygen/man/gdcm2vtk.man create mode 100644 gdcm/Utilities/doxygen/man/gdcmanon.man create mode 100644 gdcm/Utilities/doxygen/man/gdcmconv.man create mode 100644 gdcm/Utilities/doxygen/man/gdcmdiff.man create mode 100644 gdcm/Utilities/doxygen/man/gdcmdump.man create mode 100644 gdcm/Utilities/doxygen/man/gdcmgendir.man create mode 100644 gdcm/Utilities/doxygen/man/gdcmimg.man create mode 100644 gdcm/Utilities/doxygen/man/gdcminfo.man create mode 100644 gdcm/Utilities/doxygen/man/gdcmpap3.man create mode 100644 gdcm/Utilities/doxygen/man/gdcmpdf.man create mode 100644 gdcm/Utilities/doxygen/man/gdcmraw.man create mode 100644 gdcm/Utilities/doxygen/man/gdcmscanner.man create mode 100644 gdcm/Utilities/doxygen/man/gdcmscu.man create mode 100644 gdcm/Utilities/doxygen/man/gdcmtar.man create mode 100644 gdcm/Utilities/doxygen/man/gdcmviewer.man create mode 100644 gdcm/Utilities/doxygen/man/gdcmxml.man create mode 100644 gdcm/Utilities/doxygen/patchtex.cmake create mode 100644 gdcm/Utilities/doxygen/vtk/CMakeLists.txt create mode 100644 gdcm/Utilities/doxygen/vtk/doc_makeall.sh.in create mode 100644 gdcm/Utilities/doxygen/vtk/doxyfile.in create mode 100644 gdcm/Utilities/gdcm_charls.h create mode 100644 gdcm/Utilities/gdcm_expat.h create mode 100644 gdcm/Utilities/gdcm_ljpeg12.h create mode 100644 gdcm/Utilities/gdcm_ljpeg16.h create mode 100644 gdcm/Utilities/gdcm_ljpeg8.h create mode 100644 gdcm/Utilities/gdcm_md5.h create mode 100644 gdcm/Utilities/gdcm_openjpeg.h create mode 100644 gdcm/Utilities/gdcm_openjpeg2.h create mode 100644 gdcm/Utilities/gdcm_uuid.h create mode 100644 gdcm/Utilities/gdcm_zlib.h create mode 100644 gdcm/Utilities/gdcmcharls/.NoDartCoverage create mode 100644 gdcm/Utilities/gdcmcharls/CMakeLists.txt create mode 100644 gdcm/Utilities/gdcmcharls/License.txt create mode 100644 gdcm/Utilities/gdcmcharls/README.GDCM.txt create mode 100644 gdcm/Utilities/gdcmcharls/colortransform.h create mode 100644 gdcm/Utilities/gdcmcharls/config.h create mode 100644 gdcm/Utilities/gdcmcharls/context.h create mode 100644 gdcm/Utilities/gdcmcharls/contextrunmode.h create mode 100644 gdcm/Utilities/gdcmcharls/decoderstrategy.h create mode 100644 gdcm/Utilities/gdcmcharls/defaulttraits.h create mode 100644 gdcm/Utilities/gdcmcharls/encoderstrategy.h create mode 100644 gdcm/Utilities/gdcmcharls/header.cpp create mode 100644 gdcm/Utilities/gdcmcharls/header.h create mode 100644 gdcm/Utilities/gdcmcharls/interface.cpp create mode 100644 gdcm/Utilities/gdcmcharls/interface.h create mode 100644 gdcm/Utilities/gdcmcharls/jpegls.cpp create mode 100644 gdcm/Utilities/gdcmcharls/lookuptable.h create mode 100644 gdcm/Utilities/gdcmcharls/losslesstraits.h create mode 100644 gdcm/Utilities/gdcmcharls/processline.h create mode 100644 gdcm/Utilities/gdcmcharls/publictypes.h create mode 100644 gdcm/Utilities/gdcmcharls/scan.h create mode 100644 gdcm/Utilities/gdcmcharls/stdafx.cpp create mode 100644 gdcm/Utilities/gdcmcharls/streams.h create mode 100644 gdcm/Utilities/gdcmcharls/util.h create mode 100644 gdcm/Utilities/gdcmexpat/.NoDartCoverage create mode 100644 gdcm/Utilities/gdcmexpat/CMakeLists.txt create mode 100644 gdcm/Utilities/gdcmexpat/COPYING create mode 100644 gdcm/Utilities/gdcmexpat/Changes create mode 100644 gdcm/Utilities/gdcmexpat/README create mode 100644 gdcm/Utilities/gdcmexpat/doc/reference.html create mode 100644 gdcm/Utilities/gdcmexpat/doc/style.css create mode 100644 gdcm/Utilities/gdcmexpat/doc/xmlwf.1 create mode 100644 gdcm/Utilities/gdcmexpat/doc/xmlwf.sgml create mode 100644 gdcm/Utilities/gdcmexpat/examples/elements.c create mode 100644 gdcm/Utilities/gdcmexpat/examples/outline.c create mode 100644 gdcm/Utilities/gdcmexpat/expat_config.h.in create mode 100644 gdcm/Utilities/gdcmexpat/expat_mangle.h.in create mode 100644 gdcm/Utilities/gdcmexpat/lib/CMakeLists.txt create mode 100644 gdcm/Utilities/gdcmexpat/lib/ascii.h create mode 100644 gdcm/Utilities/gdcmexpat/lib/asciitab.h create mode 100644 gdcm/Utilities/gdcmexpat/lib/expat.h create mode 100644 gdcm/Utilities/gdcmexpat/lib/expat_external.h create mode 100644 gdcm/Utilities/gdcmexpat/lib/iasciitab.h create mode 100644 gdcm/Utilities/gdcmexpat/lib/internal.h create mode 100644 gdcm/Utilities/gdcmexpat/lib/latin1tab.h create mode 100644 gdcm/Utilities/gdcmexpat/lib/nametab.h create mode 100644 gdcm/Utilities/gdcmexpat/lib/utf8tab.h create mode 100644 gdcm/Utilities/gdcmexpat/lib/xmlparse.c create mode 100644 gdcm/Utilities/gdcmexpat/lib/xmlrole.c create mode 100644 gdcm/Utilities/gdcmexpat/lib/xmlrole.h create mode 100644 gdcm/Utilities/gdcmexpat/lib/xmltok.c create mode 100644 gdcm/Utilities/gdcmexpat/lib/xmltok.h create mode 100644 gdcm/Utilities/gdcmexpat/lib/xmltok_impl.c create mode 100644 gdcm/Utilities/gdcmexpat/lib/xmltok_impl.h create mode 100644 gdcm/Utilities/gdcmexpat/lib/xmltok_ns.c create mode 100644 gdcm/Utilities/gdcmexpat/tests/README.txt create mode 100644 gdcm/Utilities/gdcmexpat/tests/benchmark/README.txt create mode 100644 gdcm/Utilities/gdcmexpat/tests/benchmark/benchmark.c create mode 100644 gdcm/Utilities/gdcmexpat/tests/chardata.c create mode 100644 gdcm/Utilities/gdcmexpat/tests/chardata.h create mode 100644 gdcm/Utilities/gdcmexpat/tests/minicheck.c create mode 100644 gdcm/Utilities/gdcmexpat/tests/minicheck.h create mode 100644 gdcm/Utilities/gdcmexpat/tests/runtests.c create mode 100644 gdcm/Utilities/gdcmexpat/tests/runtestspp.cpp create mode 100644 gdcm/Utilities/gdcmexpat/tests/xmltest.sh create mode 100644 gdcm/Utilities/gdcmexpat/xmlwf/codepage.c create mode 100644 gdcm/Utilities/gdcmexpat/xmlwf/codepage.h create mode 100644 gdcm/Utilities/gdcmexpat/xmlwf/ct.c create mode 100644 gdcm/Utilities/gdcmexpat/xmlwf/filemap.h create mode 100644 gdcm/Utilities/gdcmexpat/xmlwf/readfilemap.c create mode 100644 gdcm/Utilities/gdcmexpat/xmlwf/unixfilemap.c create mode 100644 gdcm/Utilities/gdcmexpat/xmlwf/win32filemap.c create mode 100644 gdcm/Utilities/gdcmexpat/xmlwf/xmlfile.c create mode 100644 gdcm/Utilities/gdcmexpat/xmlwf/xmlfile.h create mode 100644 gdcm/Utilities/gdcmexpat/xmlwf/xmlmime.c create mode 100644 gdcm/Utilities/gdcmexpat/xmlwf/xmlmime.h create mode 100644 gdcm/Utilities/gdcmexpat/xmlwf/xmltchar.h create mode 100644 gdcm/Utilities/gdcmexpat/xmlwf/xmlurl.h create mode 100644 gdcm/Utilities/gdcmexpat/xmlwf/xmlwf.c create mode 100644 gdcm/Utilities/gdcmexpat/xmlwf/xmlwin32url.cxx create mode 100644 gdcm/Utilities/gdcmjpeg/.NoDartCoverage create mode 100644 gdcm/Utilities/gdcmjpeg/12/CMakeLists.txt create mode 100644 gdcm/Utilities/gdcmjpeg/16/CMakeLists.txt create mode 100644 gdcm/Utilities/gdcmjpeg/8/CMakeLists.txt create mode 100644 gdcm/Utilities/gdcmjpeg/CMakeLists.txt create mode 100644 gdcm/Utilities/gdcmjpeg/COPYRIGHT.dcmtk create mode 100644 gdcm/Utilities/gdcmjpeg/Jfif.txt create mode 100644 gdcm/Utilities/gdcmjpeg/README create mode 100644 gdcm/Utilities/gdcmjpeg/README.GDCM.txt create mode 100644 gdcm/Utilities/gdcmjpeg/change.log create mode 100644 gdcm/Utilities/gdcmjpeg/dcmtk.sh create mode 100644 gdcm/Utilities/gdcmjpeg/example.c create mode 100644 gdcm/Utilities/gdcmjpeg/filelist.doc create mode 100644 gdcm/Utilities/gdcmjpeg/install.doc create mode 100644 gdcm/Utilities/gdcmjpeg/jcapimin.c create mode 100644 gdcm/Utilities/gdcmjpeg/jcapistd.c create mode 100644 gdcm/Utilities/gdcmjpeg/jccoefct.c create mode 100644 gdcm/Utilities/gdcmjpeg/jccolor.c create mode 100644 gdcm/Utilities/gdcmjpeg/jcdctmgr.c create mode 100644 gdcm/Utilities/gdcmjpeg/jcdiffct.c create mode 100644 gdcm/Utilities/gdcmjpeg/jchuff.c create mode 100644 gdcm/Utilities/gdcmjpeg/jchuff.h create mode 100644 gdcm/Utilities/gdcmjpeg/jcinit.c create mode 100644 gdcm/Utilities/gdcmjpeg/jclhuff.c create mode 100644 gdcm/Utilities/gdcmjpeg/jclossls.c create mode 100644 gdcm/Utilities/gdcmjpeg/jclossy.c create mode 100644 gdcm/Utilities/gdcmjpeg/jcmainct.c create mode 100644 gdcm/Utilities/gdcmjpeg/jcmarker.c create mode 100644 gdcm/Utilities/gdcmjpeg/jcmaster.c create mode 100644 gdcm/Utilities/gdcmjpeg/jcodec.c create mode 100644 gdcm/Utilities/gdcmjpeg/jcomapi.c create mode 100644 gdcm/Utilities/gdcmjpeg/jconfig.doc create mode 100644 gdcm/Utilities/gdcmjpeg/jconfig.h create mode 100644 gdcm/Utilities/gdcmjpeg/jcparam.c create mode 100644 gdcm/Utilities/gdcmjpeg/jcphuff.c create mode 100644 gdcm/Utilities/gdcmjpeg/jcpred.c create mode 100644 gdcm/Utilities/gdcmjpeg/jcprepct.c create mode 100644 gdcm/Utilities/gdcmjpeg/jcsample.c create mode 100644 gdcm/Utilities/gdcmjpeg/jcscale.c create mode 100644 gdcm/Utilities/gdcmjpeg/jcshuff.c create mode 100644 gdcm/Utilities/gdcmjpeg/jctrans.c create mode 100644 gdcm/Utilities/gdcmjpeg/jdapimin.c create mode 100644 gdcm/Utilities/gdcmjpeg/jdapistd.c create mode 100644 gdcm/Utilities/gdcmjpeg/jdatadst.c create mode 100644 gdcm/Utilities/gdcmjpeg/jdatasrc.c create mode 100644 gdcm/Utilities/gdcmjpeg/jdcoefct.c create mode 100644 gdcm/Utilities/gdcmjpeg/jdcolor.c create mode 100644 gdcm/Utilities/gdcmjpeg/jdct.h create mode 100644 gdcm/Utilities/gdcmjpeg/jddctmgr.c create mode 100644 gdcm/Utilities/gdcmjpeg/jddiffct.c create mode 100644 gdcm/Utilities/gdcmjpeg/jdhuff.c create mode 100644 gdcm/Utilities/gdcmjpeg/jdhuff.h create mode 100644 gdcm/Utilities/gdcmjpeg/jdinput.c create mode 100644 gdcm/Utilities/gdcmjpeg/jdlhuff.c create mode 100644 gdcm/Utilities/gdcmjpeg/jdlossls.c create mode 100644 gdcm/Utilities/gdcmjpeg/jdlossy.c create mode 100644 gdcm/Utilities/gdcmjpeg/jdmainct.c create mode 100644 gdcm/Utilities/gdcmjpeg/jdmarker.c create mode 100644 gdcm/Utilities/gdcmjpeg/jdmaster.c create mode 100644 gdcm/Utilities/gdcmjpeg/jdmerge.c create mode 100644 gdcm/Utilities/gdcmjpeg/jdphuff.c create mode 100644 gdcm/Utilities/gdcmjpeg/jdpostct.c create mode 100644 gdcm/Utilities/gdcmjpeg/jdpred.c create mode 100644 gdcm/Utilities/gdcmjpeg/jdsample.c create mode 100644 gdcm/Utilities/gdcmjpeg/jdscale.c create mode 100644 gdcm/Utilities/gdcmjpeg/jdshuff.c create mode 100644 gdcm/Utilities/gdcmjpeg/jdtrans.c create mode 100644 gdcm/Utilities/gdcmjpeg/jerror.c create mode 100644 gdcm/Utilities/gdcmjpeg/jerror.h create mode 100644 gdcm/Utilities/gdcmjpeg/jfdctflt.c create mode 100644 gdcm/Utilities/gdcmjpeg/jfdctfst.c create mode 100644 gdcm/Utilities/gdcmjpeg/jfdctint.c create mode 100644 gdcm/Utilities/gdcmjpeg/jidctflt.c create mode 100644 gdcm/Utilities/gdcmjpeg/jidctfst.c create mode 100644 gdcm/Utilities/gdcmjpeg/jidctint.c create mode 100644 gdcm/Utilities/gdcmjpeg/jidctred.c create mode 100644 gdcm/Utilities/gdcmjpeg/jinclude.h create mode 100644 gdcm/Utilities/gdcmjpeg/jlossls.h create mode 100644 gdcm/Utilities/gdcmjpeg/jlossy.h create mode 100644 gdcm/Utilities/gdcmjpeg/jmemmgr.c create mode 100644 gdcm/Utilities/gdcmjpeg/jmemnobs.c create mode 100644 gdcm/Utilities/gdcmjpeg/jmemsrc.c create mode 100644 gdcm/Utilities/gdcmjpeg/jmemsys.h create mode 100644 gdcm/Utilities/gdcmjpeg/jmorecfg.h create mode 100644 gdcm/Utilities/gdcmjpeg/jpegcmake.h.in create mode 100644 gdcm/Utilities/gdcmjpeg/jpegint.h create mode 100644 gdcm/Utilities/gdcmjpeg/jpeglib.h create mode 100644 gdcm/Utilities/gdcmjpeg/jquant1.c create mode 100644 gdcm/Utilities/gdcmjpeg/jquant2.c create mode 100644 gdcm/Utilities/gdcmjpeg/jutils.c create mode 100644 gdcm/Utilities/gdcmjpeg/jversion.h create mode 100644 gdcm/Utilities/gdcmjpeg/libjpeg.doc create mode 100644 gdcm/Utilities/gdcmjpeg/mangle_jpeg.h.in create mode 100644 gdcm/Utilities/gdcmjpeg/structure.doc create mode 100644 gdcm/Utilities/gdcmjpeg/usage.doc create mode 100644 gdcm/Utilities/gdcmjpeg/wizard.doc create mode 100644 gdcm/Utilities/gdcmmd5/.NoDartCoverage create mode 100644 gdcm/Utilities/gdcmmd5/CMakeLists.txt create mode 100644 gdcm/Utilities/gdcmmd5/COPYING create mode 100644 gdcm/Utilities/gdcmmd5/README create mode 100644 gdcm/Utilities/gdcmmd5/md5.c create mode 100644 gdcm/Utilities/gdcmmd5/md5.h create mode 100644 gdcm/Utilities/gdcmmd5/md5_mangle.h.in create mode 100644 gdcm/Utilities/gdcmmd5/md5cmp.c create mode 100644 gdcm/Utilities/gdcmmd5/md5main.c create mode 100644 gdcm/Utilities/gdcmmd5/tst2md5.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/.NoDartCoverage create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/CHANGES create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/CMake/CTestCustom.cmake.in create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/CMake/CheckHaveGetopt.cmake create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/CMake/OpenJPEGConfig.cmake.in create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/CMakeLists.txt create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/CTestConfig.cmake create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/CTestCustom.cmake.in create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/INSTALL create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/LICENSE create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/LibOpenJPEG.dsp create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/LibOpenJPEG.dsw create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/LibOpenJPEG.sln create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/LibOpenJPEG.vcproj create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/OPJViewer.dsp create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/OPJViewer.dsw create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/OPJViewer.iss create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/Readme.txt create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/about/about.htm create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/about/opj_logo.png create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/buildupdate.bat create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/OPJAbout.cpp create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/OPJChild.ico create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/OPJChild16.xpm create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/OPJDialogs.cpp create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/OPJThreads.cpp create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/OPJViewer.cpp create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/OPJViewer.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/OPJViewer.ico create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/OPJViewer.rc create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/OPJViewer16.xpm create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/about_htm.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/build.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/icon1.xpm create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/icon2.xpm create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/icon3.xpm create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/icon4.xpm create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/icon5.xpm create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/imagjpeg2000.cpp create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/imagjpeg2000.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/imagmxf.cpp create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/imagmxf.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/license.txt create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/opj_logo.xpm create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/readmeafter.txt create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/readmebefore.txt create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/wxj2kparser.cpp create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/wxjp2parser.cpp create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/OPJ_Param_File_v0_1.txt create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/OPJ_Validate.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/OPJ_Validate.dsp create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/OPJ_Validate.dsw create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/OPJ_Validate_Candidate_vs_Ref.bat create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/OPJ_Validate_Candidate_vs_Ref.sh create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/OPJ_Validate_Create_Ref.bat create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/OPJ_Validate_Create_Ref.sh create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/README.txt create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/linux_OPJ_Param_File_v0_1.txt create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/md5.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/md5.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/original/README.txt create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/OpenJPEG.rc create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/README create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/README.msvc create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/codec/CMakeLists.txt create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/codec/README create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/codec/convert.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/codec/convert.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/codec/image_to_j2k.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/codec/image_to_j2k.dsp create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/codec/image_to_j2k.dsw create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/codec/image_to_j2k.sln create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/codec/image_to_j2k.vcproj create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/codec/index.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/codec/index.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/codec/j2k_dump.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/codec/j2k_to_image.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/codec/j2k_to_image.dsp create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/codec/j2k_to_image.dsw create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/codec/j2k_to_image.sln create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/codec/j2k_to_image.vcproj create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/codec/windirent.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/common/color.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/common/color.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/common/format_defs.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/common/getopt.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/common/getopt.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/doc/CMakeLists.txt create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/doc/Doxyfile.dox create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/doc/man/man1/image_to_j2k.1 create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/doc/man/man1/j2k_dump.1 create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/doc/man/man1/j2k_to_image.1 create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/doc/man/man3/libopenjpeg.3 create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/CMakeLists.txt create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/bio.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/bio.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/cio.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/cio.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/fix.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/fix.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/index_create.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/int.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/int.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/j2k.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/jp2.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/jp2.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/jpip.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/jpip.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/pi.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/pi.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/t2.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/t2.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/tcd.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/tcd.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/tgt.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/tgt.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/CMakeLists.txt create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/DllJp3dVM.dsp create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/DllJp3dVM.sln create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/DllJp3dVM.vcproj create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/LICENSE.txt create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/LibJp3dVM.sln create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/LibJp3dVM.vcproj create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/README.txt create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/CMakeLists.txt create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/convert.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/convert.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/getopt.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/getopt.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/jp3d_to_volume.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/jp3d_vm_dec.ncb create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/jp3d_vm_dec.sln create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/jp3d_vm_dec.suo create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/jp3d_vm_dec.vcproj create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/jp3d_vm_enc.ncb create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/jp3d_vm_enc.sln create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/jp3d_vm_enc.suo create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/jp3d_vm_enc.vcproj create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/volume_to_jp3d.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/windirent.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/CMakeLists.txt create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/bio.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/bio.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/cio.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/cio.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/dwt.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/dwt.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/event.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/event.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/fix.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/int.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/jp3d.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/jp3d.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/jp3d_lib.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/jp3d_lib.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/mct.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/mct.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/mqc.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/mqc.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/openjpeg.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/openjpeg3d.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/opj_includes.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/pi.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/pi.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/raw.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/raw.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/t1.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/t1.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/t1_3d.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/t1_3d.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/t2.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/t2.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/tcd.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/tcd.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/tgt.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/tgt.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/volume.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/volume.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/tcltk/LPI_JP3D_VM.tcl create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/tcltk/README create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/tcltk/Thumbs.db create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/tcltk/decoder.tcl create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/tcltk/encoder.tcl create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jp3d/tcltk/logoLPI.gif create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jpwl/CMakeLists.txt create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jpwl/JPWL_image_to_j2k.dsp create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jpwl/JPWL_image_to_j2k.dsw create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jpwl/JPWL_j2k_to_image.dsp create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jpwl/JPWL_j2k_to_image.dsw create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jpwl/LibOpenJPEG_JPWL.dsp create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jpwl/README.txt create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jpwl/crc.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jpwl/crc.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jpwl/jpwl.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jpwl/jpwl.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jpwl/jpwl_lib.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jpwl/rs.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/jpwl/rs.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg.pc.in create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/CMakeLists.txt create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/bio.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/bio.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/cio.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/cio.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/dwt.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/dwt.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/event.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/event.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/fix.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/image.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/image.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/int.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/j2k.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/j2k.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/j2k_lib.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/j2k_lib.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/jp2.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/jp2.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/jpt.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/jpt.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/mct.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/mct.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/mqc.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/mqc.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/openjpeg.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/openjpeg.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/opj_includes.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/opj_malloc.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/pi.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/pi.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/raw.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/raw.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/t1.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/t1.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/t1_generate_luts.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/t1_luts.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/t2.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/t2.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/tcd.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/tcd.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/tgt.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/tgt.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libs/lcms2/lcms2.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libs/lcms2/lcms2_plugin.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libs/lcms2/lcms2_static.lib create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libs/libtiff/libtiff.lib create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libs/libtiff/tiff.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libs/libtiff/tiffconf.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libs/libtiff/tiffio.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libs/libtiff/tiffio.hxx create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libs/libtiff/tiffvers.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libs/png/libpng14.lib create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libs/png/png.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libs/png/pngconf.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libs/png/zconf.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libs/png/zlib.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/libs/png/zlib.lib create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/ltmain.sh create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/missing create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/mj2/CMakeLists.txt create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/mj2/MJ2_Extractor.dsp create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/mj2/MJ2_Extractor.dsw create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/mj2/MJ2_Extractor.sln create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/mj2/MJ2_Extractor.vcproj create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/mj2/MJ2_Wrapper.dsp create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/mj2/MJ2_Wrapper.dsw create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/mj2/MJ2_Wrapper.sln create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/mj2/MJ2_Wrapper.vcproj create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/mj2/extract_j2k_from_mj2.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/mj2/frames_to_mj2.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/mj2/frames_to_mj2.dsp create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/mj2/frames_to_mj2.dsw create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/mj2/frames_to_mj2.sln create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/mj2/frames_to_mj2.vcproj create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/mj2/meta_out.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/mj2/meta_out.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_convert.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_convert.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_frames.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_frames.dsp create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_frames.dsw create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_frames.sln create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_frames.vcproj create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_metadata.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_metadata.dsp create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_metadata.dsw create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_metadata.dtd create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_metadata.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_metadata.sln create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_metadata.vcproj create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_metadata_Notes.doc create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/mj2/readme.txt create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/mj2/wrap_j2k_in_mj2.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/openjpeg_mangle.h.in create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/opj_config.h.in create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/opj_config.h.in.user create mode 100644 gdcm/Utilities/gdcmopenjpeg-v1/opj_configh.cmake.in create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/.NoDartCoverage create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/CMake/CTestCustom.cmake.in create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/CMake/FindFreeImage.cmake create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/CMake/Free_CMakeImport.cmake create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/CMake/OpenJPEGConfig.cmake.in create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/CMake/mymachine_openjpeg.cmake create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/CMakeLists.txt create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/CTestConfig.cmake create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/README.cmake create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/README.linux create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/README.msvc create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/README.osx create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/README.v2 create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/codec/CMakeLists.txt create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/codec/Makefile create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/codec/compat/getopt.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/codec/compat/getopt.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/codec/convert.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/codec/convert.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/codec/dirent.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/codec/image_to_j2k.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/codec/index.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/codec/index.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/codec/j2k_dump.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/codec/j2k_to_image.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/doc/CMakeLists.txt create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/doc/Doxyfile.dox create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/jpwl/CMakeLists.txt create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/jpwl/README.txt create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/jpwl/crc.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/jpwl/crc.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/jpwl/jpwl.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/jpwl/jpwl.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/jpwl/jpwl_lib.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/jpwl/rs.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/jpwl/rs.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/CMakeLists.txt create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/bio.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/bio.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/cio.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/cio.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/dwt.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/dwt.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/event.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/event.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/fix.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/function_list.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/function_list.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/image.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/image.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/int.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/invert.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/invert.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/j2k.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/j2k.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/j2k_lib.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/j2k_lib.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/jp2.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/jp2.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/jpt.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/jpt.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/mct.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/mct.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/mqc.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/mqc.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/openjpeg.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/openjpeg.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/opj_configure.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/opj_includes.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/opj_malloc.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/pi.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/pi.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/profile.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/profile.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/raw.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/raw.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/t1.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/t1.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/t1_luts.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/t2.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/t2.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/tcd.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/tcd.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/tgt.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/tgt.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/license.txt create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/mj2/CMakeLists.txt create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/mj2/Makefile create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/mj2/extract_j2k_from_mj2.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/mj2/frames_to_mj2.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/mj2/meta_out.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/mj2/meta_out.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/mj2/mj2.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/mj2/mj2.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/mj2/mj2_convert.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/mj2/mj2_convert.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/mj2/mj2_to_frames.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/mj2/mj2_to_metadata.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/mj2/mj2_to_metadata.dtd create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/mj2/mj2_to_metadata.h create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/mj2/mj2_to_metadata_Notes.doc create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/mj2/readme.txt create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/mj2/wrap_j2k_in_mj2.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/openjpeg_mangle.h.in create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/opj_configure.h.in create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/test_Free_image_V2_tile_handling/CMakeLists.txt create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/test_Free_image_V2_tile_handling/test2_decoder.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/test_Free_image_V2_tile_handling/test2_encoder.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/test_V2_tile_handling/CMakeLists.txt create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/test_V2_tile_handling/test_decoder.c create mode 100644 gdcm/Utilities/gdcmopenjpeg-v2/test_V2_tile_handling/test_encoder.c create mode 100644 gdcm/Utilities/gdcmutfcpp/README.GDCM.txt create mode 100644 gdcm/Utilities/gdcmutfcpp/utf8.h create mode 100644 gdcm/Utilities/gdcmutfcpp/utf8/checked.h create mode 100644 gdcm/Utilities/gdcmutfcpp/utf8/core.h create mode 100644 gdcm/Utilities/gdcmutfcpp/utf8/unchecked.h create mode 100644 gdcm/Utilities/gdcmuuid/.NoDartCoverage create mode 100644 gdcm/Utilities/gdcmuuid/CMakeLists.txt create mode 100644 gdcm/Utilities/gdcmuuid/COPYING create mode 100644 gdcm/Utilities/gdcmuuid/compare.c create mode 100644 gdcm/Utilities/gdcmuuid/gen_uuid.c create mode 100644 gdcm/Utilities/gdcmuuid/pack.c create mode 100644 gdcm/Utilities/gdcmuuid/parse.c create mode 100644 gdcm/Utilities/gdcmuuid/unpack.c create mode 100644 gdcm/Utilities/gdcmuuid/unparse.c create mode 100644 gdcm/Utilities/gdcmuuid/uuid.h create mode 100644 gdcm/Utilities/gdcmuuid/uuidP.h create mode 100644 gdcm/Utilities/gdcmuuid/uuid_mangle.h.in create mode 100644 gdcm/Utilities/gdcmuuid/uuid_time.c create mode 100644 gdcm/Utilities/gdcmzlib/.NoDartCoverage create mode 100644 gdcm/Utilities/gdcmzlib/CMakeLists.txt create mode 100644 gdcm/Utilities/gdcmzlib/COPYING create mode 100644 gdcm/Utilities/gdcmzlib/ChangeLog create mode 100644 gdcm/Utilities/gdcmzlib/FAQ create mode 100644 gdcm/Utilities/gdcmzlib/INDEX create mode 100644 gdcm/Utilities/gdcmzlib/README create mode 100644 gdcm/Utilities/gdcmzlib/adler32.c create mode 100644 gdcm/Utilities/gdcmzlib/algorithm.txt create mode 100644 gdcm/Utilities/gdcmzlib/compress.c create mode 100644 gdcm/Utilities/gdcmzlib/crc32.c create mode 100644 gdcm/Utilities/gdcmzlib/crc32.h create mode 100644 gdcm/Utilities/gdcmzlib/deflate.c create mode 100644 gdcm/Utilities/gdcmzlib/deflate.h create mode 100644 gdcm/Utilities/gdcmzlib/example.c create mode 100644 gdcm/Utilities/gdcmzlib/examples/README.examples create mode 100644 gdcm/Utilities/gdcmzlib/examples/fitblk.c create mode 100644 gdcm/Utilities/gdcmzlib/examples/gun.c create mode 100644 gdcm/Utilities/gdcmzlib/examples/gzappend.c create mode 100644 gdcm/Utilities/gdcmzlib/examples/gzjoin.c create mode 100644 gdcm/Utilities/gdcmzlib/examples/gzlog.c create mode 100644 gdcm/Utilities/gdcmzlib/examples/gzlog.h create mode 100644 gdcm/Utilities/gdcmzlib/examples/zlib_how.html create mode 100644 gdcm/Utilities/gdcmzlib/examples/zpipe.c create mode 100644 gdcm/Utilities/gdcmzlib/examples/zran.c create mode 100644 gdcm/Utilities/gdcmzlib/gzio.c create mode 100644 gdcm/Utilities/gdcmzlib/infback.c create mode 100644 gdcm/Utilities/gdcmzlib/inffast.c create mode 100644 gdcm/Utilities/gdcmzlib/inffast.h create mode 100644 gdcm/Utilities/gdcmzlib/inffixed.h create mode 100644 gdcm/Utilities/gdcmzlib/inflate.c create mode 100644 gdcm/Utilities/gdcmzlib/inflate.h create mode 100644 gdcm/Utilities/gdcmzlib/inftrees.c create mode 100644 gdcm/Utilities/gdcmzlib/inftrees.h create mode 100644 gdcm/Utilities/gdcmzlib/minigzip.c create mode 100644 gdcm/Utilities/gdcmzlib/trees.c create mode 100644 gdcm/Utilities/gdcmzlib/trees.h create mode 100644 gdcm/Utilities/gdcmzlib/uncompr.c create mode 100644 gdcm/Utilities/gdcmzlib/zconf.in.h create mode 100644 gdcm/Utilities/gdcmzlib/zlib.3 create mode 100644 gdcm/Utilities/gdcmzlib/zlib.def.in create mode 100644 gdcm/Utilities/gdcmzlib/zlib.h create mode 100644 gdcm/Utilities/gdcmzlib/zlib.rc create mode 100644 gdcm/Utilities/gdcmzlib/zutil.c create mode 100644 gdcm/Utilities/gdcmzlib/zutil.h create mode 100644 gdcm/Utilities/getopt/CMakeLists.txt create mode 100644 gdcm/Utilities/getopt/COPYING create mode 100644 gdcm/Utilities/getopt/README create mode 100644 gdcm/Utilities/getopt/ex_getopt.c create mode 100644 gdcm/Utilities/getopt/getopt.c create mode 100644 gdcm/Utilities/getopt/getopt.h create mode 100644 gdcm/Utilities/getopt/getopt_long.c create mode 100644 gdcm/Utilities/pvrg/CHANGES create mode 100644 gdcm/Utilities/pvrg/CMakeLists.txt create mode 100644 gdcm/Utilities/pvrg/COPYING create mode 100644 gdcm/Utilities/pvrg/PORTABILITY create mode 100644 gdcm/Utilities/pvrg/README create mode 100644 gdcm/Utilities/pvrg/SETUP create mode 100644 gdcm/Utilities/pvrg/chendct.c create mode 100644 gdcm/Utilities/pvrg/codec.c create mode 100644 gdcm/Utilities/pvrg/csize.h create mode 100644 gdcm/Utilities/pvrg/dct.h create mode 100644 gdcm/Utilities/pvrg/globals.h create mode 100644 gdcm/Utilities/pvrg/huffman.c create mode 100644 gdcm/Utilities/pvrg/io.c create mode 100644 gdcm/Utilities/pvrg/jpeg.1 create mode 100644 gdcm/Utilities/pvrg/jpeg.c create mode 100644 gdcm/Utilities/pvrg/leedct.c create mode 100644 gdcm/Utilities/pvrg/lexer.c create mode 100644 gdcm/Utilities/pvrg/lexer.l create mode 100644 gdcm/Utilities/pvrg/marker.c create mode 100644 gdcm/Utilities/pvrg/marker.h create mode 100644 gdcm/Utilities/pvrg/param.h create mode 100644 gdcm/Utilities/pvrg/prototypes.h create mode 100644 gdcm/Utilities/pvrg/pvrgjpeg.c create mode 100644 gdcm/Utilities/pvrg/stream.c create mode 100644 gdcm/Utilities/pvrg/stream.h create mode 100644 gdcm/Utilities/pvrg/system.h create mode 100644 gdcm/Utilities/pvrg/tables.h create mode 100644 gdcm/Utilities/pvrg/transform.c create mode 100644 gdcm/Utilities/rle/CMakeLists.txt create mode 100644 gdcm/Utilities/rle/example.c create mode 100644 gdcm/Utilities/rle/rle.c create mode 100644 gdcm/Utilities/rle/rledump.c create mode 100644 gdcm/Utilities/rle/rlelib.c create mode 100644 gdcm/Utilities/rle/rlelib.h create mode 100644 gdcm/Utilities/socketxx/.NoDartCoverage create mode 100644 gdcm/Utilities/socketxx/AUTHORS create mode 100644 gdcm/Utilities/socketxx/CMakeLists.txt create mode 100644 gdcm/Utilities/socketxx/COPYING create mode 100644 gdcm/Utilities/socketxx/socket++/CMakeLists.txt create mode 100644 gdcm/Utilities/socketxx/socket++/config.h.in create mode 100644 gdcm/Utilities/socketxx/socket++/echo.cpp create mode 100644 gdcm/Utilities/socketxx/socket++/echo.h create mode 100644 gdcm/Utilities/socketxx/socket++/fork.cpp create mode 100644 gdcm/Utilities/socketxx/socket++/fork.h create mode 100644 gdcm/Utilities/socketxx/socket++/ftp.cpp create mode 100644 gdcm/Utilities/socketxx/socket++/ftp.h create mode 100644 gdcm/Utilities/socketxx/socket++/local.h create mode 100644 gdcm/Utilities/socketxx/socket++/pipestream.cpp create mode 100644 gdcm/Utilities/socketxx/socket++/pipestream.h create mode 100644 gdcm/Utilities/socketxx/socket++/protocol.cpp create mode 100644 gdcm/Utilities/socketxx/socket++/protocol.h create mode 100644 gdcm/Utilities/socketxx/socket++/sig.cpp create mode 100644 gdcm/Utilities/socketxx/socket++/sig.h create mode 100644 gdcm/Utilities/socketxx/socket++/smtp.cpp create mode 100644 gdcm/Utilities/socketxx/socket++/smtp.h create mode 100644 gdcm/Utilities/socketxx/socket++/sockinet.cpp create mode 100644 gdcm/Utilities/socketxx/socket++/sockinet.h create mode 100644 gdcm/Utilities/socketxx/socket++/sockstream.cpp create mode 100644 gdcm/Utilities/socketxx/socket++/sockstream.h create mode 100644 gdcm/Utilities/socketxx/socket++/sockunix.cpp create mode 100644 gdcm/Utilities/socketxx/socket++/sockunix.h create mode 100644 gdcm/Utilities/wxWidgets/CMakeLists.txt create mode 100644 gdcm/Utilities/wxWidgets/Copyright.txt create mode 100644 gdcm/Utilities/wxWidgets/MyDialog.cpp create mode 100644 gdcm/Utilities/wxWidgets/MyDialog.h create mode 100644 gdcm/Utilities/wxWidgets/main.cpp create mode 100644 gdcm/Utilities/wxWidgets/wxGDCMFrame.cpp create mode 100644 gdcm/Utilities/wxWidgets/wxGDCMFrame.h create mode 100644 gdcm/Utilities/wxWidgets/wxGDCMFrameBase.cpp create mode 100644 gdcm/Utilities/wxWidgets/wxGDCMFrameBase.h create mode 100644 gdcm/Utilities/wxWidgets/wxVTKRenderWindowInteractor.cxx create mode 100644 gdcm/Utilities/wxWidgets/wxVTKRenderWindowInteractor.h create mode 100644 gdcm/Utilities/wxWidgets/wxgdcm.wxg create mode 100644 gdcm/Wrapping/CMakeLists.txt create mode 100644 gdcm/Wrapping/Csharp/AssemblyInfo.cs.in create mode 100644 gdcm/Wrapping/Csharp/CMakeLists.txt create mode 100644 gdcm/Wrapping/Csharp/HelloCsharpWorld.cs create mode 100644 gdcm/Wrapping/Csharp/Notes.txt create mode 100644 gdcm/Wrapping/Csharp/docstrings.i create mode 100644 gdcm/Wrapping/Csharp/doxy2swig.py create mode 100644 gdcm/Wrapping/Csharp/gdcm.i create mode 100644 gdcm/Wrapping/Csharp/gdcm_arrays_csharp.i create mode 100644 gdcm/Wrapping/Csharp/key.snk create mode 100644 gdcm/Wrapping/Csharp/std_set.i create mode 100644 gdcm/Wrapping/Java/CMakeLists.txt create mode 100644 gdcm/Wrapping/Java/gdcm.i create mode 100644 gdcm/Wrapping/Java/main.java create mode 100644 gdcm/Wrapping/Java/std_set.i create mode 100644 gdcm/Wrapping/PHP/CMakeLists.txt create mode 100644 gdcm/Wrapping/PHP/gdcm.i create mode 100644 gdcm/Wrapping/Perl/CMakeLists.txt create mode 100644 gdcm/Wrapping/Perl/gdcm.i create mode 100644 gdcm/Wrapping/Python/.NoDartCoverage create mode 100644 gdcm/Wrapping/Python/CMakeLists.txt create mode 100644 gdcm/Wrapping/Python/Python.h.in create mode 100644 gdcm/Wrapping/Python/TestWrap.py create mode 100644 gdcm/Wrapping/Python/docstrings.i create mode 100644 gdcm/Wrapping/Python/doxy2swig.py create mode 100644 gdcm/Wrapping/Python/gdcm.pth.in create mode 100644 gdcm/Wrapping/Python/gdcm.py create mode 100644 gdcm/Wrapping/Python/gdcmPythonFilter.cxx create mode 100644 gdcm/Wrapping/Python/gdcmPythonFilter.h create mode 100644 gdcm/Wrapping/Python/gdcmswig.i create mode 100644 gdcm/Wrapping/SWIGCommon/gdcmcommon.i create mode 100644 main.cpp create mode 100644 mainwindow.cpp create mode 100644 mainwindow.h create mode 100644 mainwindow.ui create mode 100644 mainwindow_2.cpp create mode 100644 mainwindow_old.cpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4063728 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +gdcm-win7 diff --git a/NiDBUploader.pro b/NiDBUploader.pro new file mode 100644 index 0000000..9cadefc --- /dev/null +++ b/NiDBUploader.pro @@ -0,0 +1,82 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2014-04-16T12:57:27 +# +#------------------------------------------------- + +QT += core gui +QT += network +QT += testlib + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = NiDBUploader +TEMPLATE = app + +#CONFIG += static +#CONFIG += staticlib + +SOURCES += main.cpp\ + mainwindow.cpp \ + anonymize.cpp + +HEADERS += mainwindow.h \ + anonymize.h + +FORMS += mainwindow.ui + +#win32 { +#DEFINES += BUILDTIME=\\\"$$system('echo %time%')\\\" +#DEFINES += BUILDDATE=\\\"$$system('echo %date%')\\\" +#} else { +#DEFINES += BUILDTIME=\\\"$$system(date '+%H:%M.%s')\\\" +#DEFINES += BUILDDATE=\\\"$$system(date '+%d/%m/%y')\\\" +#} + +INCLUDEPATH += $$PWD/gdcm/Source/Attribute +INCLUDEPATH += $$PWD/gdcm/Source/Common +INCLUDEPATH += $$PWD/gdcm/Source/DataDictionary +INCLUDEPATH += $$PWD/gdcm/Source/DataStructureAndEncodingDefinition +INCLUDEPATH += $$PWD/gdcm/Source/InformationObjectDefinition +INCLUDEPATH += $$PWD/gdcm/Source/MediaStorageAndFileFormat +INCLUDEPATH += $$PWD/gdcm/Source/MessageExchangeDefinition +INCLUDEPATH += $$PWD/gdcm-win7/Source/Common # for gdcmConfigure.h + +#win32-msvc*:contains(QMAKE_TARGET.arch, x86_64):{ +# win32:CONFIG(release, debug|release): LIBS += -L$$PWD/min-gdcm64-win7/bin/Release/ +# else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/min-gdcm64-win7/bin/Debug/ +#} +#else { + win32-msvc2010: { + LIBS += -LC:\Qt5\5.3\msvc2010_opengl\plugins\platforms + + LIBS += -L$$PWD/min-gdcm32-win7/bin/Debug/ + LIBS += -lopengl32 -limm32 -lwinmm -lWs2_32 -lQt5PlatformSupport + } + else { + linux-g++: { + LIBS += -L$$PWD/gdcm-centos7/bin + } + else { + win32:CONFIG(release, debug|release): LIBS += -L$$PWD/gdcm-win7/bin/Release/ + else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/gdcm-win7/bin/Debug/ + } + } +#} + +LIBS += -lgdcmMSFF \ + -lgdcmCommon \ + -lgdcmDICT \ + -lgdcmDSED \ + -lgdcmIOD \ + -lgdcmMEXD \ + -lgdcmcharls \ + -lgdcmexpat \ + -lgdcmjpeg12 \ + -lgdcmjpeg16 \ + -lgdcmjpeg8 \ + -lgdcmopenjpeg \ + -lgdcmzlib \ +# -lgdcmgetopt \ + -lsocketxx + diff --git a/NiDBUploader.pro.user b/NiDBUploader.pro.user new file mode 100644 index 0000000..e69ce9d --- /dev/null +++ b/NiDBUploader.pro.user @@ -0,0 +1,444 @@ + + + + + + EnvironmentId + {deb408f9-cde3-423c-9520-a04988756476} + + + ProjectExplorer.Project.ActiveTarget + 1 + + + ProjectExplorer.Project.EditorSettings + + true + false + true + + Cpp + + CppGlobal + + + + QmlJS + + QmlJSGlobal + + + 2 + UTF-8 + false + 4 + false + 80 + true + true + 1 + true + false + 0 + true + 0 + 8 + true + 1 + true + true + true + false + + + + ProjectExplorer.Project.PluginSettings + + + + ProjectExplorer.Project.Target.0 + + Desktop Qt 5.3.0 MSVC2010 OpenGL 32bit + Desktop Qt 5.3.0 MSVC2010 OpenGL 32bit + qt.53.win32_msvc2010_opengl_kit + 1 + 0 + 0 + + C:/projects/NiDBUploader-build/MSVC2010_32bit-Debug + + + true + qmake + + QtProjectManager.QMakeBuildStep + false + true + + false + false + + + true + Make + + Qt4ProjectManager.MakeStep + + false + + + + 2 + Build + + ProjectExplorer.BuildSteps.Build + + + + true + Make + + Qt4ProjectManager.MakeStep + + true + clean + + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Debug + + Qt4ProjectManager.Qt4BuildConfiguration + 2 + true + + + C:/projects/NiDBUploader-build/MSVC2010_32bit-Release + + + true + qmake + + QtProjectManager.QMakeBuildStep + false + true + + false + false + + + true + Make + + Qt4ProjectManager.MakeStep + + false + + + + 2 + Build + + ProjectExplorer.BuildSteps.Build + + + + true + Make + + Qt4ProjectManager.MakeStep + + true + clean + + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Release + + Qt4ProjectManager.Qt4BuildConfiguration + 0 + true + + 2 + + + 0 + Deploy + + ProjectExplorer.BuildSteps.Deploy + + 1 + Deploy locally + + ProjectExplorer.DefaultDeployConfiguration + + 1 + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + NiDBUploader + + Qt4ProjectManager.Qt4RunConfiguration:Q:/dev/NiDBUploader/NiDBUploader.pro + + NiDBUploader.pro + false + false + + 3768 + false + true + false + false + true + + 1 + + + + ProjectExplorer.Project.Target.1 + + Desktop Qt 5.3.0 MSVC2012 OpenGL 32bit + Desktop Qt 5.3.0 MSVC2012 OpenGL 32bit + qt.53.win32_msvc2012_opengl_kit + 1 + 0 + 0 + + C:/projects/NiDBUploader-build/MSVC2012_32bit-Debug + + + true + qmake + + QtProjectManager.QMakeBuildStep + false + true + + false + false + + + true + Make + + Qt4ProjectManager.MakeStep + + false + + + + 2 + Build + + ProjectExplorer.BuildSteps.Build + + + + true + Make + + Qt4ProjectManager.MakeStep + + true + clean + + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Debug + + Qt4ProjectManager.Qt4BuildConfiguration + 2 + true + + + C:/projects/NiDBUploader-build/MSVC2012_32bit-Release + + + true + qmake + + QtProjectManager.QMakeBuildStep + false + true + + false + false + + + true + Make + + Qt4ProjectManager.MakeStep + + false + + + + 2 + Build + + ProjectExplorer.BuildSteps.Build + + + + true + Make + + Qt4ProjectManager.MakeStep + + true + clean + + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Release + + Qt4ProjectManager.Qt4BuildConfiguration + 0 + true + + 2 + + + 0 + Deploy + + ProjectExplorer.BuildSteps.Deploy + + 1 + Deploy locally + + ProjectExplorer.DefaultDeployConfiguration + + 1 + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + NiDBUploader + + Qt4ProjectManager.Qt4RunConfiguration:Q:/dev/NiDBUploader/NiDBUploader.pro + + NiDBUploader.pro + false + false + + 3768 + false + true + false + false + true + + 1 + + + + ProjectExplorer.Project.TargetCount + 2 + + + ProjectExplorer.Project.Updater.FileVersion + 18 + + + Version + 18 + + diff --git a/NiDBUploader.sh b/NiDBUploader.sh new file mode 100644 index 0000000..a02a70e --- /dev/null +++ b/NiDBUploader.sh @@ -0,0 +1,2 @@ +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:. +./NiDBUploader diff --git a/README.md b/README.md new file mode 100644 index 0000000..5f3d240 --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +nidb-uploader +============= + +NiDBUploader diff --git a/anonymize.cpp b/anonymize.cpp new file mode 100644 index 0000000..5787618 --- /dev/null +++ b/anonymize.cpp @@ -0,0 +1,11 @@ +#include "anonymize.h" +#include "gdcmReader.h" +#include "gdcmImageReader.h" +#include "gdcmImageWriter.h" +#include "gdcmCSAHeader.h" +#include "gdcmAttribute.h" +#include "gdcmPrivateTag.h" + +Anonymize::Anonymize() +{ +} diff --git a/anonymize.h b/anonymize.h new file mode 100644 index 0000000..45b4a8b --- /dev/null +++ b/anonymize.h @@ -0,0 +1,10 @@ +#ifndef ANONYMIZE_H +#define ANONYMIZE_H + +class Anonymize +{ +public: + Anonymize(); +}; + +#endif // ANONYMIZE_H diff --git a/gdcm/AUTHORS b/gdcm/AUTHORS new file mode 100644 index 0000000..ced3a19 --- /dev/null +++ b/gdcm/AUTHORS @@ -0,0 +1,52 @@ +GDCM 2.x: +-------- + + Fabrice Bellet : Contributor (RPM) + Charl P. Botha : Contributor (Python, VTK) + Shane Blackett : Contributor (Win32) + Niels Dekker : Contributor (C++ guru) + Daniele E. Domenichelli : Contributor (C++) + Dean Inglis : Contributor (Win32, VTK) + Paulo Henrique Junqueira Amorim : Contributor (Python) + Pierre Le Duff : Contributor (C++, VTK) + Mathieu Malaterre : Project leader, main developer + Lars Matthaus : Contributor (Java) + Sean McBride : Contributor (C++) + Steve M. Robbins : Contributor (debian) + Mark Roden : Developer (C++, C#) + Jordi Romera : Developer (C++, RTSTRUCT) + Jean-Pierre Roux : Developer, maintain gdcmDataExtra + Christina Rossmanith : Contributor (Siemens CSA) + Christopher W Treml : Contributor (C#) + Joel Spaltenstein : Developer (MacOSX) + + +GDCM 1.x (Developpers and contributors, alphabetical order) +-------- + Aris Basic + Fabrice Bellet + Hugues Benoit-Cattin + Francois Bertel + Eric Boix + Charl P. Botha + Peter Cech + Eduardo Enrique Davila Serrano + Antonin Descampe + David Feng + Marco Feuerstein + Pierre Fillard + Leonardo Flores Valencia + Dennis Hu + Luis Ibanez + Michal Kurgan + Gianni Lazzarato + George Li + Sean McInemey + Johan Montagnat + Emmanuel Olart + Luca Picello + Parikshit Prasad + Benoit Regrain + Jean-Michel Rouet + Olivier Stern + Satomi Takeo diff --git a/gdcm/Applications/CMakeLists.txt b/gdcm/Applications/CMakeLists.txt new file mode 100644 index 0000000..ccbaece --- /dev/null +++ b/gdcm/Applications/CMakeLists.txt @@ -0,0 +1 @@ +subdirs(Cxx) diff --git a/gdcm/Applications/Cxx/CMakeLists.txt b/gdcm/Applications/Cxx/CMakeLists.txt new file mode 100644 index 0000000..1c83bc3 --- /dev/null +++ b/gdcm/Applications/Cxx/CMakeLists.txt @@ -0,0 +1,217 @@ +# Build the GDCM applications +# Namely: +# gdcmdump +# gdcminfo +# gdcmconv +# gdcmanon + + +if(WIN32 AND NOT CYGWIN) + include_directories( + "${GDCM_SOURCE_DIR}/Utilities/getopt" + ) +endif() + +# Add the include paths +include_directories( + "${GDCM_BINARY_DIR}/Source/Common" + "${GDCM_SOURCE_DIR}/Source/Common" + "${GDCM_SOURCE_DIR}/Source/DataStructureAndEncodingDefinition" + "${GDCM_SOURCE_DIR}/Source/MediaStorageAndFileFormat" + "${GDCM_SOURCE_DIR}/Source/InformationObjectDefinition" + "${GDCM_SOURCE_DIR}/Source/MessageExchangeDefinition" +# FIXME: + "${GDCM_SOURCE_DIR}/Source/DataDictionary" + "${GDCM_SOURCE_DIR}/Utilities" + + ) + +if(NOT GDCM_USE_SYSTEM_SOCKETXX) + include_directories( + "${GDCM_SOURCE_DIR}/Utilities/socketxx" + "${GDCM_SOURCE_DIR}/Utilities/socketxx/socket++" # local.h + "${GDCM_BINARY_DIR}/Utilities/socketxx/socket++" # config.h + ) +endif() + +if(WIN32) + if (BUILD_SHARED_LIBS) + add_definitions(-DGETOPT_DLL) + endif () +endif() + +set(GDCM_EXECUTABLE_NAME + gdcmdump + gdcmdiff + gdcmraw + gdcmscanner + gdcmanon + gdcmgendir + #gdcmoverlay + gdcmimg + #deflate + gdcmconv + #gdcmstream + gdcmtar + gdcminfo + gdcmscu + gdcmxml + gdcmpap3 + ) +# poppler people have the worse API backward compatibility I know of. +# there is absolutely no way to check the version of poppler +# they change the API during a minor change of the version +if(GDCM_USE_SYSTEM_POPPLER) + include(CheckCXXSourceCompiles) + set(CMAKE_REQUIRED_INCLUDES ${POPPLER_INCLUDE_DIRS}) + set(CMAKE_REQUIRED_LIBRARIES ${POPPLER_LIBRARIES}) + CHECK_CXX_SOURCE_COMPILES( + "\#include \nint main() { globalParams = new GlobalParams(0); return 0;}" + LIBPOPPLER_GLOBALPARAMS_CSTOR_HAS_PARAM) + set(libpoppler_flags) + if(LIBPOPPLER_GLOBALPARAMS_CSTOR_HAS_PARAM) + list(APPEND libpoppler_flags -DLIBPOPPLER_GLOBALPARAMS_CSTOR_HAS_PARAM) + endif() + CHECK_CXX_SOURCE_COMPILES( + "\#include \nint main() { PDFDoc d((GooString*)NULL,(GooString*)NULL,(GooString*)NULL); d.getPDFVersion(); return 0;}" + LIBPOPPLER_PDFDOC_HAS_PDFVERSION) + if(LIBPOPPLER_PDFDOC_HAS_PDFVERSION) + list(APPEND libpoppler_flags -DLIBPOPPLER_PDFDOC_HAS_PDFVERSION) + endif() + if(libpoppler_flags) + set_source_files_properties( + ${CMAKE_CURRENT_SOURCE_DIR}/gdcminfo.cxx + PROPERTIES COMPILE_FLAGS ${libpoppler_flags}) + set_source_files_properties( + ${CMAKE_CURRENT_SOURCE_DIR}/gdcmpdf.cxx + PROPERTIES COMPILE_FLAGS ${libpoppler_flags}) + endif() + include_directories(${POPPLER_INCLUDE_DIRS}) + set(GDCM_EXECUTABLE_NAME + ${GDCM_EXECUTABLE_NAME} + gdcmpdf + ) +endif() + +if(GDCM_USE_SYSTEM_LIBXML2) + include_directories(${LIBXML2_INCLUDE_DIR}) +endif() + +if(GDCM_USE_SYSTEM_OPENJPEG) + include_directories(${OPENJPEG_INCLUDE_DIRS} ) +else() + include_directories( + "${GDCM_BINARY_DIR}/Utilities/gdcmopenjpeg" + ) +endif() + +if(NOT BUILD_SHARED_LIBS) + set_source_files_properties(gdcmstream.cxx + PROPERTIES + COMPILE_FLAGS -DOPJ_STATIC + ) +endif() + +if(GDCM_USE_SYSTEM_PAPYRUS3) + include_directories( + ${PAPYRUS3_INCLUDE_DIRS} + ) +endif() + +foreach(exename ${GDCM_EXECUTABLE_NAME}) + if(${exename} STREQUAL "gdcminfo") + add_executable(${exename} ${exename}.cxx puff.c) + else() + add_executable(${exename} ${exename}.cxx) + endif() + target_link_libraries(${exename} gdcmMSFF) + if(${exename} STREQUAL "gdcmpdf") + target_link_libraries(${exename} ${POPPLER_LIBRARIES}) + elseif(${exename} STREQUAL "gdcmxml") + target_link_libraries(${exename} ${LIBXML2_LIBRARIES}) + elseif(${exename} STREQUAL "gdcmscu") + if(NOT GDCM_USE_SYSTEM_SOCKETXX) + target_link_libraries(${exename} gdcmMEXD socketxx) + else() + target_link_libraries(${exename} gdcmMEXD socket++) + endif() + elseif(${exename} STREQUAL "gdcmstream") + target_link_libraries(${exename} ${GDCM_OPENJPEG_LIBRARIES}) + elseif(${exename} STREQUAL "gdcminfo") + if(GDCM_USE_SYSTEM_POPPLER) + target_link_libraries(${exename} ${POPPLER_LIBRARIES}) + endif() + endif() + if(GDCM_EXECUTABLE_PROPERTIES) + set_target_properties(${exename} PROPERTIES ${GDCM_EXECUTABLE_PROPERTIES}) + endif() + if(WIN32 AND NOT CYGWIN) + target_link_libraries(${exename} gdcmgetopt) + endif() + if(NOT GDCM_INSTALL_NO_RUNTIME) + install(TARGETS ${exename} + EXPORT ${GDCM_TARGETS_NAME} + RUNTIME DESTINATION ${GDCM_INSTALL_BIN_DIR} COMPONENT Applications + ) + endif() +endforeach() + +if(GDCM_USE_SYSTEM_PAPYRUS3) + target_link_libraries(gdcmpap3 ${PAPYRUS3_LIBRARIES}) +endif() + +#if(BUILD_TESTING) +# if(GDCM_DATA_ROOT) +# file(MAKE_DIRECTORY ${GDCM_TEMP_DIRECTORY}/gdcmanon-gdcmdata) +# add_test(gdcmanon-gdcmdata ${EXECUTABLE_OUTPUT_PATH}/gdcmanon +# --continue # skip LIBIDO-16-ACR_NEMA-Volume.dcm +# --certificate ${GDCM_SOURCE_DIR}/Testing/Source/Data/certificate.pem +# ${GDCM_DATA_ROOT} +# ${GDCM_TEMP_DIRECTORY}/gdcmanon-gdcmdata +# ) +# endif() +#endif() + +if(BUILD_TESTING) + # http://www.na-mic.org/Wiki/index.php/CTSC:ARRA:Mockup + # http://www.dicomserver.co.uk/ + # the NAMIC server is offline, Steve Pieper has volunteered his servers, but they are intermittent + # IP Address: common.bwh.harvard.edu (155.52.248.49) + # Port: 11112 + # AE Title: CTK_AE + # and + # IP Address: joe.bwh.harvard.edu (155.52.248.50) + # Port: 5678 + # AE Title: CONQUESTSRV1 + #since these servers have no guaranteed uptime, these tests should be changed to some other, known-to-be-up server + #add_test(gdcmscu-echo-CONQUEST ${EXECUTABLE_OUTPUT_PATH}/gdcmscu --echo --call CONQUESTSRV1 joe.bwh.harvard.edu 5678) + add_test(NAME gdcmscu-echo-dicomserver COMMAND ${EXECUTABLE_OUTPUT_PATH}/gdcmscu --echo www.dicomserver.co.uk 11112) + if(GDCM_DATA_ROOT) + # CR-MONO1-10-chest.dcm gets rejected by www.dicomserver.co.uk: + # Tag 0x0,0x902 reported as Incorrect VM (1) - Minimum value is 2 : 'Array of N Elements' (error 42752) + # CR-MONO1-10-chest.dcm gets rejected by mi2b2.slicer.org + # Tag 0x0,0x902 reported as Acceptance of objects without Patient ID is disabled (error 43264) + #add_test(gdcmscu-store-CONQUEST ${EXECUTABLE_OUTPUT_PATH}/gdcmscu --store --call CONQUESTSRV1 joe.bwh.harvard.edu 11112 ${GDCM_DATA_ROOT}/SIEMENS_MAGNETOM-12-MONO2-FileSeq1.dcm) + add_test(NAME gdcmscu-store-dicomserver COMMAND ${EXECUTABLE_OUTPUT_PATH}/gdcmscu --store www.dicomserver.co.uk 11112 ${GDCM_DATA_ROOT}/SIEMENS_MAGNETOM-12-MONO2-FileSeq1.dcm) + endif() + #add_test(gdcmscu-find-CONQUEST ${EXECUTABLE_OUTPUT_PATH}/gdcmscu --find --patient --call CONQUESTSRV1 joe.bwh.harvard.edu 11112 --patientroot -k 10,10=X*) + add_test(NAME gdcmscu-find-dicomserver COMMAND ${EXECUTABLE_OUTPUT_PATH}/gdcmscu --find --patient www.dicomserver.co.uk 11112 --patientroot -k 10,20=*) + + if(GDCM_DICOM_SERVER_AETITLE) + if(GDCM_DATA_ROOT) + # Let's C-STORE a limited subset of gdcmData for now: + set(CSTORE_DATA_FILES + CR-MONO1-10-chest.dcm # Implicit VR Little Endian: Default Transfer Syntax for DICOM + 012345.002.050.dcm # JPEG Lossless, Non-Hierarchical, First-Order Prediction + ) + foreach(cstorefile ${CSTORE_DATA_FILES}) + add_test(NAME gdcmscu-echo-${cstorefile} COMMAND ${EXECUTABLE_OUTPUT_PATH}/gdcmscu --echo --aetitle ${GDCM_DICOM_CLIENT_AETITLE} --call ${GDCM_DICOM_SERVER_AETITLE} ${GDCM_DICOM_SERVER_PEER} ${GDCM_DICOM_SERVER_PORT}) + add_test(NAME gdcmscu-store-${cstorefile} COMMAND ${EXECUTABLE_OUTPUT_PATH}/gdcmscu --store --aetitle ${GDCM_DICOM_CLIENT_AETITLE} --call ${GDCM_DICOM_SERVER_AETITLE} ${GDCM_DICOM_SERVER_PEER} ${GDCM_DICOM_SERVER_PORT} ${GDCM_DATA_ROOT}/${cstorefile}) + add_test(NAME gdcmscu-find-${cstorefile} COMMAND ${EXECUTABLE_OUTPUT_PATH}/gdcmscu --find --patient --aetitle ${GDCM_DICOM_CLIENT_AETITLE} --call ${GDCM_DICOM_SERVER_AETITLE} ${GDCM_DICOM_SERVER_PEER} ${GDCM_DICOM_SERVER_PORT} --patientroot -k 10,10=A* -k 10,20) + add_test(NAME gdcmscu-move1-${cstorefile} COMMAND ${EXECUTABLE_OUTPUT_PATH}/gdcmscu --move --patient --aetitle ${GDCM_DICOM_CLIENT_AETITLE} --call ${GDCM_DICOM_SERVER_AETITLE} ${GDCM_DICOM_SERVER_PEER} ${GDCM_DICOM_SERVER_PORT} -o ${CMAKE_CURRENT_BINARY_DIR} --patientroot -k 10,10=Anonymized --port-scp ${GDCM_DICOM_CLIENT_PORT}) + add_test(NAME gdcmscu-move2-${cstorefile} COMMAND ${EXECUTABLE_OUTPUT_PATH}/gdcmscu --move --patient --aetitle ${GDCM_DICOM_CLIENT_AETITLE} --call ${GDCM_DICOM_SERVER_AETITLE} ${GDCM_DICOM_SERVER_PEER} ${GDCM_DICOM_SERVER_PORT} -o ${CMAKE_CURRENT_BINARY_DIR} --patientroot -k 10,10=X* --port-scp ${GDCM_DICOM_CLIENT_PORT}) + endforeach() + endif() + endif() + +endif() diff --git a/gdcm/Applications/Cxx/deflate.cxx b/gdcm/Applications/Cxx/deflate.cxx new file mode 100644 index 0000000..3338baf --- /dev/null +++ b/gdcm/Applications/Cxx/deflate.cxx @@ -0,0 +1,116 @@ +#include + +#include +#include +#include +#include + +#include "zlib/zlib.h" + +#define CHUNK 16384 + +/* Decompress from file source to file dest until stream ends or EOF. + inf() returns Z_OK on success, Z_MEM_ERROR if memory could not be + allocated for processing, Z_DATA_ERROR if the deflate data is + invalid or incomplete, Z_VERSION_ERROR if the version of zlib.h and + the version of the library linked do not match, or Z_ERRNO if there + is an error reading or writing the files. */ +int inf(FILE *source, FILE *dest) +{ + int ret; + unsigned have; + z_stream strm; + unsigned char in[CHUNK]; + unsigned char out[CHUNK]; + + /* allocate inflate state */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = 0; + strm.next_in = Z_NULL; + //ret = inflateInit(&strm); + ret = inflateInit2(&strm, -MAX_WBITS); + if (ret != Z_OK) + { + std::cout << "could not inflateInit" << std::endl; + return ret; + } + + /* decompress until deflate stream ends or end of file */ + do { + strm.avail_in = fread(in, 1, CHUNK, source); + if (ferror(source)) { + (void)inflateEnd(&strm); + return Z_ERRNO; + } + if (strm.avail_in == 0) + break; + strm.next_in = in; + + /* run inflate() on input until output buffer not full */ + do { + strm.avail_out = CHUNK; + strm.next_out = out; + ret = inflate(&strm, Z_NO_FLUSH); + assert(ret != Z_STREAM_ERROR); /* state not clobbered */ + switch (ret) { + case Z_NEED_DICT: + ret = Z_DATA_ERROR; /* and fall through */ + case Z_DATA_ERROR: + case Z_MEM_ERROR: + (void)inflateEnd(&strm); + return ret; + } + have = CHUNK - strm.avail_out; + if (fwrite(out, 1, have, dest) != have || ferror(dest)) { + (void)inflateEnd(&strm); + return Z_ERRNO; + } + } while (strm.avail_out == 0); + + /* done when inflate() says it's done */ + } while (ret != Z_STREAM_END); + + /* clean up and return */ + (void)inflateEnd(&strm); + return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR; +} + +void zerr(int ret) +{ + fputs("zpipe: ", stderr); + switch (ret) { + case Z_ERRNO: + if (ferror(stdin)) + fputs("error reading stdin\n", stderr); + if (ferror(stdout)) + fputs("error writing stdout\n", stderr); + break; + case Z_STREAM_ERROR: + fputs("invalid compression level\n", stderr); + break; + case Z_DATA_ERROR: + fputs("invalid or incomplete deflate data\n", stderr); + break; + case Z_MEM_ERROR: + fputs("out of memory\n", stderr); + break; + case Z_VERSION_ERROR: + fputs("zlib version mismatch!\n", stderr); + } +} + +int main() +{ + FILE *input; + FILE *output; + input = fopen("deflat.gz","r"); + output = fopen("deflat.dcm","w"); + if(!input) std::cout << "no input" << std::endl; + if(!output) std::cout << "no output" << std::endl; +int r = inf(input, output); +//std::cout << strerror( errno) << std::endl; +// zerr(r) ; + return r; +} diff --git a/gdcm/Applications/Cxx/gdcm.cxx b/gdcm/Applications/Cxx/gdcm.cxx new file mode 100644 index 0000000..5321d8d --- /dev/null +++ b/gdcm/Applications/Cxx/gdcm.cxx @@ -0,0 +1,51 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +// gdcm will convert almost anything into dicom +// - jpg +// - j2k +// - pdf +// - raw.. +// - wav +// - txt (??) +// - 2D stuff -> RT +// - new segmentation ! + +// provide a dicom2 compatible API...maybe ?? + +// For pdf: +/* +Provide a mapping for: + +Title: ITK Software Guide +Subject: Medical Image Segmentation and Registration Toolkit +Keywords: Registration,Segmentation,Guide +Author: Luis Ibanez and Will Schroeder +Creator: LaTeX with hyperref package +Producer: dvips + GPL Ghostscript 8.15 +CreationDate: Mon Nov 21 19:34:28 2005 +ModDate: Mon Nov 21 19:34:28 2005 +Tagged: no +Pages: 836 +Encrypted: no +Page size: 522 x 675 pts +File size: 5580502 bytes +Optimized: no +PDF version: 1.4 + +into DICOM elements... +*/ +int main(int argc, char *argv[]) +{ + return 0; +} diff --git a/gdcm/Applications/Cxx/gdcmanon.cxx b/gdcm/Applications/Cxx/gdcmanon.cxx new file mode 100644 index 0000000..afdbaef --- /dev/null +++ b/gdcm/Applications/Cxx/gdcmanon.cxx @@ -0,0 +1,829 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + * PS 3.15 / E.1 / Basic Application Level Confidentiality Profile + * Implementation of E.1.1 De-identify & E.1.2 Re-identify + */ + +#include + +#include "gdcmReader.h" +#include "gdcmWriter.h" +#include "gdcmVersion.h" +#include "gdcmSystem.h" +#include "gdcmCryptoFactory.h" +#include "gdcmUIDGenerator.h" +#include "gdcmAnonymizer.h" +#include "gdcmGlobal.h" +#include "gdcmDefs.h" +#include "gdcmDirectory.h" + +#include + + +static void PrintVersion() +{ + std::cout << "gdcmanon: gdcm " << gdcm::Version::GetVersion() << " "; + const char date[] = "$Date$"; + std::cout << date << std::endl; +} + +// FIXME + int deidentify = 0; + int reidentify = 0; + + +static bool AnonymizeOneFileDumb(gdcm::Anonymizer &anon, const char *filename, const char *outfilename, + std::vector const &empty_tags, std::vector const &remove_tags, std::vector< std::pair > const & replace_tags, bool continuemode = false) +{ + gdcm::Reader reader; + reader.SetFileName( filename ); + if( !reader.Read() ) + { + std::cerr << "Could not read : " << filename << std::endl; + if( continuemode ) + { + std::cerr << "Skipping from anonymization process (continue mode)." << std::endl; + return true; + } + else + { + std::cerr << "Check [--continue] option for skipping files." << std::endl; + return false; + } + } + gdcm::File &file = reader.GetFile(); + + anon.SetFile( file ); + + if( empty_tags.empty() && replace_tags.empty() && remove_tags.empty() ) + { + std::cerr << "No operation to be done." << std::endl; + return false; + } + + std::vector::const_iterator it = empty_tags.begin(); + bool success = true; + for(; it != empty_tags.end(); ++it) + { + success = success && anon.Empty( *it ); + } + it = remove_tags.begin(); + for(; it != remove_tags.end(); ++it) + { + success = success && anon.Remove( *it ); + } + + std::vector< std::pair >::const_iterator it2 = replace_tags.begin(); + for(; it2 != replace_tags.end(); ++it2) + { + success = success && anon.Replace( it2->first, it2->second.c_str() ); + } + + gdcm::Writer writer; + writer.SetFileName( outfilename ); + writer.SetFile( file ); + if( !writer.Write() ) + { + std::cerr << "Could not Write : " << outfilename << std::endl; + if( strcmp(filename,outfilename) != 0 ) + { + gdcm::System::RemoveFile( outfilename ); + } + else + { + std::cerr << "gdcmanon just corrupted: " << filename << " for you (data lost)." << std::endl; + } + + return false; + } + return success; +} + +static bool AnonymizeOneFile(gdcm::Anonymizer &anon, const char *filename, const char *outfilename, bool continuemode = false) +{ + gdcm::Reader reader; + reader.SetFileName( filename ); + if( !reader.Read() ) + { + std::cerr << "Could not read : " << filename << std::endl; + if( continuemode ) + { + std::cerr << "Skipping from anonymization process (continue mode)." << std::endl; + return true; + } + else + { + std::cerr << "Check [--continue] option for skipping files." << std::endl; + return false; + } + } + gdcm::File &file = reader.GetFile(); + gdcm::MediaStorage ms; + ms.SetFromFile(file); + if( !gdcm::Defs::GetIODNameFromMediaStorage(ms) ) + { + std::cerr << "The Media Storage Type of your file is not supported: " << ms << std::endl; + std::cerr << "Please report" << std::endl; + return false; + } + + anon.SetFile( file ); + + if( deidentify ) + { + //anon.RemovePrivateTags(); + //anon.RemoveRetired(); + if( !anon.BasicApplicationLevelConfidentialityProfile( true ) ) + { + std::cerr << "Could not De-indentify : " << filename << std::endl; + return false; + } + } + else if ( reidentify ) + { + if( !anon.BasicApplicationLevelConfidentialityProfile( false ) ) + { + std::cerr << "Could not Re-indentify : " << filename << std::endl; + return false; + } + } + + gdcm::FileMetaInformation &fmi = file.GetHeader(); + fmi.Clear(); + + gdcm::Writer writer; + writer.SetFileName( outfilename ); + writer.SetFile( file ); + if( !writer.Write() ) + { + std::cerr << "Could not Write : " << outfilename << std::endl; + if( strcmp(filename,outfilename) != 0 ) + { + gdcm::System::RemoveFile( outfilename ); + } + else + { + std::cerr << "gdcmanon just corrupted: " << filename << " for you (data lost)." << std::endl; + } + + return false; + } + return true; +} + +static bool GetRSAKeys(gdcm::CryptographicMessageSyntax &cms, const char *privpath = 0, const char *certpath = 0) +{ + if( privpath && *privpath ) + { + if( !cms.ParseKeyFile( privpath ) ) + { + std::cerr << "Could not parse Private Key: " << privpath << std::endl; + return false; + } + } + + if( certpath && *certpath ) + { + if( !cms.ParseCertificateFile( certpath ) ) + { + std::cerr << "Could not parse Certificate Key: " << certpath << std::endl; + return false; + } + } + return true; +} + +static void PrintHelp() +{ + PrintVersion(); + std::cout << "Usage: gdcmanon [OPTION]... FILE..." << std::endl; + std::cout << "PS 3.15 / E.1 / Basic Application Level Confidentiality Profile" << std::endl; + std::cout << "Implementation of E.1.1 De-identify & E.1.2 Re-identify" << std::endl; + std::cout << "Parameter (required):" << std::endl; + std::cout << " -e --de-identify (encrypt) De-identify DICOM (default)" << std::endl; + std::cout << " -d --re-identify (decrypt) Re-identify DICOM" << std::endl; + std::cout << " --dumb Dumb mode anonymizer" << std::endl; + std::cout << "Options:" << std::endl; + std::cout << " -i --input DICOM filename / directory" << std::endl; + std::cout << " -o --output DICOM filename / directory" << std::endl; + std::cout << " -r --recursive recursively process (sub-)directories." << std::endl; + std::cout << " --continue Do not stop when file found is not DICOM." << std::endl; + std::cout << " --root-uid Root UID." << std::endl; + std::cout << " --resources-path Resources path." << std::endl; + std::cout << " -k --key Path to RSA Private Key." << std::endl; + std::cout << " -c --certificate Path to Certificate." << std::endl; + std::cout << " -p --password Encryption passphrase." << std::endl; + std::cout << "Crypto Library Options:" << std::endl; + std::cout << " --crypto=" << std::endl; + std::cout << " openssl OpenSSL (default on non-Windows systems)." << std::endl; + std::cout << " capi Microsoft CryptoAPI (default on Windows systems)." << std::endl; + std::cout << " openssl-p7 Old OpenSSL implementation." << std::endl; + std::cout << "Encryption Algorithm Options:" << std::endl; + std::cout << " --des3 Triple DES." << std::endl; + std::cout << " --aes128 AES 128." << std::endl; + std::cout << " --aes192 AES 192." << std::endl; + std::cout << " --aes256 AES 256 (default)." << std::endl; + std::cout << "Dumb mode options:" << std::endl; + std::cout << " --empty %d,%d DICOM tag(s) to empty" << std::endl; + std::cout << " --remove %d,%d DICOM tag(s) to remove" << std::endl; + std::cout << " --replace %d,%d=%s DICOM tag(s) to replace" << std::endl; + std::cout << "General Options:" << std::endl; + std::cout << " -V --verbose more verbose (warning+error)." << std::endl; + std::cout << " -W --warning print warning info." << std::endl; + std::cout << " -D --debug print debug info." << std::endl; + std::cout << " -E --error print error info." << std::endl; + std::cout << " -h --help print help." << std::endl; + std::cout << " -v --version print version." << std::endl; + std::cout << "Env var:" << std::endl; + std::cout << " GDCM_ROOT_UID Root UID" << std::endl; + std::cout << " GDCM_RESOURCES_PATH path pointing to resources files (Part3.xml, ...)" << std::endl; +} + +static gdcm::CryptographicMessageSyntax::CipherTypes GetFromString( const char * str ) +{ + gdcm::CryptographicMessageSyntax::CipherTypes ciphertype; + if( strcmp( str, "des3" ) == 0 ) + { + ciphertype = gdcm::CryptographicMessageSyntax::DES3_CIPHER; + } + else if( strcmp( str, "aes128" ) == 0 ) + { + ciphertype = gdcm::CryptographicMessageSyntax::AES128_CIPHER; + } + else if( strcmp( str, "aes192" ) == 0 ) + { + ciphertype = gdcm::CryptographicMessageSyntax::AES192_CIPHER; + } + else if( strcmp( str, "aes256" ) == 0 ) + { + ciphertype = gdcm::CryptographicMessageSyntax::AES256_CIPHER; + } + else + { + // if unrecognized return aes 256... + ciphertype = gdcm::CryptographicMessageSyntax::AES256_CIPHER; + } + return ciphertype; +} + +int main(int argc, char *argv[]) +{ + int c; + //int digit_optind = 0; + + std::string filename; + gdcm::Directory::FilenamesType filenames; + std::string outfilename; + gdcm::Directory::FilenamesType outfilenames; + std::string root; + std::string xmlpath; + std::string rsa_path; + std::string cert_path; + std::string password; + int resourcespath = 0; + int dumb_mode = 0; + int des3 = 0; + int aes128 = 0; + int aes192 = 0; + int aes256 = 0; + int rootuid = 0; + int verbose = 0; + int warning = 0; + int debug = 0; + int error = 0; + int help = 0; + int version = 0; + int recursive = 0; + int continuemode = 0; + int empty_tag = 0; + int remove_tag = 0; + int replace_tag = 0; + int crypto_api = 0; + std::vector empty_tags; + std::vector remove_tags; + std::vector< std::pair > replace_tags_value; + gdcm::Tag tag; + gdcm::CryptoFactory::CryptoLib crypto_lib; + crypto_lib = gdcm::CryptoFactory::DEFAULT; + + while (1) { + //int this_option_optind = optind ? optind : 1; + int option_index = 0; + static struct option long_options[] = { + {"input", required_argument, NULL, 'i'}, // i + {"output", required_argument, NULL, 'o'}, // o + {"root-uid", required_argument, &rootuid, 1}, // specific Root (not GDCM) + {"resources-path", required_argument, &resourcespath, 1}, + {"de-identify", no_argument, NULL, 'e'}, + {"re-identify", no_argument, NULL, 'd'}, + {"key", required_argument, NULL, 'k'}, + {"certificate", required_argument, NULL, 'c'}, // 7 + {"password", required_argument, NULL, 'p'}, + + {"des3", no_argument, &des3, 1}, + {"aes128", no_argument, &aes128, 1}, + {"aes192", no_argument, &aes192, 1}, + {"aes256", no_argument, &aes256, 1}, + + {"recursive", no_argument, NULL, 'r'}, + {"dumb", no_argument, &dumb_mode, 1}, + {"empty", required_argument, &empty_tag, 1}, // 15 + {"remove", required_argument, &remove_tag, 1}, + {"replace", required_argument, &replace_tag, 1}, + {"continue", no_argument, &continuemode, 1}, + {"crypto", required_argument, &crypto_api, 1}, //19 + + {"verbose", no_argument, NULL, 'V'}, + {"warning", no_argument, NULL, 'W'}, + {"debug", no_argument, NULL, 'D'}, + {"error", no_argument, NULL, 'E'}, + {"help", no_argument, NULL, 'h'}, + {"version", no_argument, NULL, 'v'}, + + {0, 0, 0, 0} + }; + + c = getopt_long (argc, argv, "i:o:rdek:c:p:VWDEhv", + long_options, &option_index); + if (c == -1) + { + break; + } + + switch (c) + { + case 0: + { + const char *s = long_options[option_index].name; (void)s; + //printf ("option %s", s); + if (optarg) + { + //if( option_index == 0 ) /* input */ + // { + // assert( strcmp(s, "input") == 0 ); + // assert( filename.empty() ); + // filename = optarg; + // } + //else if( option_index == 1 ) /* output */ + // { + // assert( strcmp(s, "output") == 0 ); + // assert( outfilename.empty() ); + // outfilename = optarg; + // } + /*else*/ if( option_index == 2 ) /* root-uid */ + { + assert( strcmp(s, "root-uid") == 0 ); + assert( root.empty() ); + root = optarg; + } + else if( option_index == 3 ) /* resources-path */ + { + assert( strcmp(s, "resources-path") == 0 ); + assert( xmlpath.empty() ); + xmlpath = optarg; + } + //else if( option_index == 6 ) /* key */ + // { + // assert( strcmp(s, "key") == 0 ); + // assert( rsa_path.empty() ); + // rsa_path = optarg; + // } + //else if( option_index == 7 ) /* certificate */ + // { + // assert( strcmp(s, "certificate") == 0 ); + // assert( cert_path.empty() ); + // cert_path = optarg; + // } + else if( option_index == 15 ) /* empty */ + { + assert( strcmp(s, "empty") == 0 ); + if( !tag.ReadFromCommaSeparatedString(optarg) ) + { + std::cerr << "Could not read Tag: " << optarg << std::endl; + return 1; + } + empty_tags.push_back( tag ); + } + else if( option_index == 16 ) /* remove */ + { + assert( strcmp(s, "remove") == 0 ); + if( !tag.ReadFromCommaSeparatedString(optarg) ) + { + std::cerr << "Could not read Tag: " << optarg << std::endl; + return 1; + } + remove_tags.push_back( tag ); + } + else if( option_index == 17 ) /* replace */ + { + assert( strcmp(s, "replace") == 0 ); + if( !tag.ReadFromCommaSeparatedString(optarg) ) + { + std::cerr << "Could not read Tag: " << optarg << std::endl; + return 1; + } + std::stringstream ss; + ss.str( optarg ); + uint16_t dummy; + char cdummy; // comma + ss >> std::hex >> dummy; + assert( tag.GetGroup() == dummy ); + ss >> cdummy; + assert( cdummy == ',' ); + ss >> std::hex >> dummy; + assert( tag.GetElement() == dummy ); + ss >> cdummy; + assert( cdummy == ',' || cdummy == '=' ); + std::string str; + //ss >> str; + std::getline(ss, str); // do not skip whitespace + replace_tags_value.push_back( std::make_pair(tag, str) ); + } + else if( option_index == 19 ) /* crypto */ + { + assert( strcmp(s, "crypto") == 0 ); + if (strcmp(optarg, "openssl") == 0) + crypto_lib = gdcm::CryptoFactory::OPENSSL; + else if (strcmp(optarg, "capi") == 0) + crypto_lib = gdcm::CryptoFactory::CAPI; + else if (strcmp(optarg, "openssl-p7") == 0) + crypto_lib = gdcm::CryptoFactory::OPENSSLP7; + else + { + std::cerr << "Cryptography library id not recognized: " << optarg << std::endl; + return 1; + } + } + //printf (" with arg %s", optarg); + } + //printf ("\n"); + } + break; + + case 'i': + assert( filename.empty() ); + filename = optarg; + break; + + case 'o': + assert( outfilename.empty() ); + outfilename = optarg; + break; + + case 'r': + recursive = 1; + break; + + case 'k': // key + assert( rsa_path.empty() ); + rsa_path = optarg; + break; + + case 'c': // certificate + assert( cert_path.empty() ); + cert_path = optarg; + break; + + case 'p': // password + assert( password.empty() ); + password = optarg; + break; + + case 'e': // encrypt + deidentify = 1; + break; + + case 'd': // decrypt + reidentify = 1; + break; + + case 'V': + verbose = 1; + break; + + case 'W': + warning = 1; + break; + + case 'D': + debug = 1; + break; + + case 'E': + error = 1; + break; + + case 'h': + help = 1; + break; + + case 'v': + version = 1; + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + std::vector files; + while (optind < argc) + { + //printf ("%s\n", argv[optind++]); + files.push_back( argv[optind++] ); + } + //printf ("\n"); + if( files.size() == 2 + && filename.empty() + && outfilename.empty() + ) + { + filename = files[0]; + outfilename = files[1]; + } + else + { + PrintHelp(); + return 1; + } + } + + if( version ) + { + //std::cout << "version" << std::endl; + PrintVersion(); + return 0; + } + + if( help ) + { + //std::cout << "help" << std::endl; + PrintHelp(); + return 0; + } + + if( filename.empty() ) + { + //std::cerr << "Need input file (-i)\n"; + PrintHelp(); + return 1; + } + + // by default de-identify + if( !deidentify && !reidentify && !dumb_mode) + { + deidentify = 1; + } + + // one option only please + if( deidentify && reidentify ) + { + std::cerr << "One option please" << std::endl; + return 1; + } + // dumb mode vs smart mode: + if( ( deidentify || reidentify ) && dumb_mode ) + { + std::cerr << "One option please" << std::endl; + return 1; + } + + gdcm::CryptoFactory* crypto_factory = NULL; + if( deidentify || reidentify ) + { + crypto_factory = gdcm::CryptoFactory::GetFactoryInstance(crypto_lib); + if (!crypto_factory) + { + std::cerr << "Requested cryptoraphic library not configured." << std::endl; + return 1; + } + } + + // by default AES 256 + gdcm::CryptographicMessageSyntax::CipherTypes ciphertype = + gdcm::CryptographicMessageSyntax::AES256_CIPHER; + if( !dumb_mode ) + { + if( !des3 && !aes128 && !aes192 && !aes256 ) + { + aes256 = 1; + } + + if( des3 ) + { + ciphertype = GetFromString( "des3" ); + } + else if( aes128 ) + { + ciphertype = GetFromString( "aes128" ); + } + else if( aes192 ) + { + ciphertype = GetFromString( "aes192" ); + } + else if( aes256 ) + { + ciphertype = GetFromString( "aes256" ); + } + else + { + return 1; + } + } + + if( !gdcm::System::FileExists(filename.c_str()) ) + { + std::cerr << "Could not find file: " << filename << std::endl; + return 1; + } + + // Are we in single file or directory mode: + unsigned int nfiles = 1; + gdcm::Directory dir; + if( gdcm::System::FileIsDirectory(filename.c_str()) ) + { + if( !gdcm::System::FileIsDirectory(outfilename.c_str()) ) + { + if( gdcm::System::FileExists( outfilename.c_str() ) ) + { + std::cerr << "Could not create directory since " << outfilename << " is already a file" << std::endl; + return 1; + } + + } + // For now avoid user mistake + if( filename == outfilename ) + { + std::cerr << "Input directory should be different from output directory" << std::endl; + return 1; + } + nfiles = dir.Load(filename, (recursive > 0 ? true : false)); + filenames = dir.GetFilenames(); + gdcm::Directory::FilenamesType::const_iterator it = filenames.begin(); + // Prepare outfilenames + for( ; it != filenames.end(); ++it ) + { + std::string dup = *it; // make a copy + std::string &out = dup.replace(0, filename.size(), outfilename ); + outfilenames.push_back( out ); + } + // Prepare outdirectory + gdcm::Directory::FilenamesType const &dirs = dir.GetDirectories(); + gdcm::Directory::FilenamesType::const_iterator itdir = dirs.begin(); + for( ; itdir != dirs.end(); ++itdir ) + { + std::string dirdup = *itdir; // make a copy + std::string &dirout = dirdup.replace(0, filename.size(), outfilename ); + //std::cout << "Making directory: " << dirout << std::endl; + if( !gdcm::System::MakeDirectory( dirout.c_str() ) ) + { + std::cerr << "Could not create directory: " << dirout << std::endl; + return 1; + } + } + } + else + { + filenames.push_back( filename ); + outfilenames.push_back( outfilename ); + } + + if( filenames.size() != outfilenames.size() ) + { + std::cerr << "Something went really wrong" << std::endl; + return 1; + } + + // Debug is a little too verbose + gdcm::Trace::SetDebug( (debug > 0 ? true : false)); + gdcm::Trace::SetWarning( (warning > 0 ? true : false)); + gdcm::Trace::SetError( (error > 0 ? true : false)); + // when verbose is true, make sure warning+error are turned on: + if( verbose ) + { + gdcm::Trace::SetWarning( (verbose > 0 ? true : false) ); + gdcm::Trace::SetError( (verbose > 0 ? true : false) ); + } + + gdcm::FileMetaInformation::SetSourceApplicationEntityTitle( "gdcmanon" ); + gdcm::Global& g = gdcm::Global::GetInstance(); + if( !resourcespath ) + { + const char *xmlpathenv = getenv("GDCM_RESOURCES_PATH"); + if( xmlpathenv ) + { + // Make sure to look for XML dict in user explicitly specified dir first: + xmlpath = xmlpathenv; + resourcespath = 1; + } + } + if( resourcespath ) + { + // xmlpath is set either by the cmd line option or the env var + if( !g.Prepend( xmlpath.c_str() ) ) + { + std::cerr << "Specified Resources Path is not valid: " << xmlpath << std::endl; + return 1; + } + } + // All set, then load the XML files: + if( !g.LoadResourcesFiles() ) + { + std::cerr << "Could not load XML file from specified path" << std::endl; + return 1; + } + const gdcm::Defs &defs = g.GetDefs(); (void)defs; + if( !rootuid ) + { + // only read the env var if no explicit cmd line option + // maybe there is an env var defined... let's check + const char *rootuid_env = getenv("GDCM_ROOT_UID"); + if( rootuid_env ) + { + rootuid = 1; + root = rootuid_env; + } + } + if( rootuid ) + { + // root is set either by the cmd line option or the env var + if( !gdcm::UIDGenerator::IsValid( root.c_str() ) ) + { + std::cerr << "specified Root UID is not valid: " << root << std::endl; + return 1; + } + gdcm::UIDGenerator::SetRoot( root.c_str() ); + } + + // Get private key/certificate + std::auto_ptr cms_ptr; + if( crypto_factory ) + { + cms_ptr = std::auto_ptr(crypto_factory->CreateCMSProvider()); + } + if( !dumb_mode ) + { + if( !GetRSAKeys(*cms_ptr, rsa_path.c_str(), cert_path.c_str() ) ) + { + return 1; + } + if (!password.empty() && !cms_ptr->SetPassword(password.c_str(), password.length()) ) + { + std::cerr << "Could not set the password " << std::endl; + return 1; + } + cms_ptr->SetCipherType( ciphertype ); + } + + // Setup gdcm::Anonymizer + gdcm::Anonymizer anon; + if( !dumb_mode ) + { + anon.SetCryptographicMessageSyntax( cms_ptr.get() ); + } + + if( dumb_mode ) + { + for(unsigned int i = 0; i < nfiles; ++i) + { + const char *in = filenames[i].c_str(); + const char *out = outfilenames[i].c_str(); + if( !AnonymizeOneFileDumb(anon, in, out, empty_tags, remove_tags, replace_tags_value, (continuemode > 0 ? true: false)) ) + { + //std::cerr << "Could not anonymize: " << in << std::endl; + return 1; + } + } + } + else + { + for(unsigned int i = 0; i < nfiles; ++i) + { + const char *in = filenames[i].c_str(); + const char *out = outfilenames[i].c_str(); + if( !AnonymizeOneFile(anon, in, out, (continuemode > 0 ? true: false)) ) + { + //std::cerr << "Could not anonymize: " << in << std::endl; + return 1; + } + } + } + return 0; +} diff --git a/gdcm/Applications/Cxx/gdcmcheck.cxx b/gdcm/Applications/Cxx/gdcmcheck.cxx new file mode 100644 index 0000000..e1b466a --- /dev/null +++ b/gdcm/Applications/Cxx/gdcmcheck.cxx @@ -0,0 +1,24 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + * Need to move gdcminfo --deflated here + * gdcmcheck would check for improper Basic Offset Table + * JP2 in place of JPEG + * more to come ? + */ + +int main(int, char *[]) +{ + return 0; +} diff --git a/gdcm/Applications/Cxx/gdcmconv.cxx b/gdcm/Applications/Cxx/gdcmconv.cxx new file mode 100644 index 0000000..702d303 --- /dev/null +++ b/gdcm/Applications/Cxx/gdcmconv.cxx @@ -0,0 +1,1464 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + * HISTORY: + * In GDCM 1.X the prefered terms was 'ReWrite', however one author of GDCM dislike + * the term ReWrite since it is associated with the highly associated with the Rewrite + * notion in software programming where using reinvent the wheel and rewrite from scratch code + * the term convert was prefered + * + * Tools to conv. Goals being to 'purify' a DICOM file. + * For now it will do the minimum: + * - If Group Length is present, the length is guarantee to be correct + * - If Element with Group Tag 0x1, 0x3, 0x5 or 0x7 are present they are + * simply discarded (not written). + * - Elements are written in alphabetical order + * - 32bits VR have the residue bytes sets to 0x0,0x0 + * - Same goes from Item Length end delimitor, sets to 0x0,0x0 + * - All buggy files (wrong length: GE, 13 and Siemens Leonardo) are fixed + * - All size are even (no odd length from gdcm 1.x) + * + * // \todo: + * // --preamble: clean preamble + * // --meta: clean meta (meta info version...) + * // --dicomV3 (use TS unless not supported) + * // --recompute group-length + * // --undefined sq + * // --explicit sq * + * \todo in a close future: + * - Set appropriate VR from DICOM dict + * - Rewrite PMS SQ into DICOM SQ + * - Rewrite Implicit SQ with defined length as undefined length + * - PixelData with `overlay` in unused bits should be cleanup + * - Any broken JPEG file (wrong bits) should be fixed + * - DicomObject bug should be fixed + * - Meta and Dataset should have a matching UID (more generally File Meta + * should be correct (Explicit!) and consistant with DataSet) + * - User should be able to specify he wants Group Length (or remove them) + * - Media SOP should be correct (deduct from something else or set to + * SOP Secondary if all else fail). + * - Padding character should be correct + * + * \todo distant future: + * - Later on, it should run through a Validator + * which will make sure all field 1, 1C are present and those only + * - In a perfect world I should remove private tags and transform them into + * public fields. + * - DA should be correct, PN should be correct (no space!) + * - Enumerated Value should be correct + */ +/* + check-meta is ideal for image like: + + gdcmconv -C gdcmData/PICKER-16-MONO2-No_DicomV3_Preamble.dcm bla.dcm +*/ +#include "gdcmReader.h" +#include "gdcmFileDerivation.h" +#include "gdcmAnonymizer.h" +#include "gdcmVersion.h" +#include "gdcmPixmapReader.h" +#include "gdcmPixmapWriter.h" +#include "gdcmWriter.h" +#include "gdcmSystem.h" +#include "gdcmFileMetaInformation.h" +#include "gdcmDataSet.h" +#include "gdcmIconImageGenerator.h" +#include "gdcmAttribute.h" +#include "gdcmSequenceOfItems.h" +#include "gdcmUIDGenerator.h" +#include "gdcmImage.h" +#include "gdcmImageChangeTransferSyntax.h" +#include "gdcmImageApplyLookupTable.h" +#include "gdcmImageFragmentSplitter.h" +#include "gdcmImageChangePlanarConfiguration.h" +#include "gdcmImageChangePhotometricInterpretation.h" +#include "gdcmFileExplicitFilter.h" +#include "gdcmJPEG2000Codec.h" +#include "gdcmJPEGCodec.h" +#include "gdcmJPEGLSCodec.h" +#include "gdcmSequenceOfFragments.h" + +#include +#include + +#include /* for printf */ +#include /* for exit */ +#include +#include + +struct SetSQToUndefined +{ + void operator() (gdcm::DataElement &de) { + de.SetVLToUndefined(); + } +}; + +static void PrintVersion() +{ + std::cout << "gdcmconv: gdcm " << gdcm::Version::GetVersion() << " "; + const char date[] = "$Date$"; + std::cout << date << std::endl; +} + +static void PrintLossyWarning() +{ + std::cout << "You have selected a lossy compression transfer syntax." << std::endl; + std::cout << "This will degrade the quality of your input image, and can." << std::endl; + std::cout << "impact professional interpretation of the image." << std::endl; + std::cout << "Do not use if you do not understand the risk." << std::endl; + std::cout << "WARNING: this mode is very experimental." << std::endl; +} + +static void PrintHelp() +{ + PrintVersion(); + std::cout << "Usage: gdcmconv [OPTION] input.dcm output.dcm" << std::endl; + std::cout << "Convert a DICOM file into another DICOM file.\n"; + std::cout << "Parameter (required):" << std::endl; + std::cout << " -i --input DICOM filename" << std::endl; + std::cout << " -o --output DICOM filename" << std::endl; + std::cout << "Options:" << std::endl; + std::cout << " -X --explicit Change Transfer Syntax to explicit." << std::endl; + std::cout << " -M --implicit Change Transfer Syntax to implicit." << std::endl; + std::cout << " -U --use-dict Use dict for VR (only public by default)." << std::endl; + std::cout << " --with-private-dict Use private dict for VR (advanced user only)." << std::endl; + std::cout << " -C --check-meta Check File Meta Information (advanced user only)." << std::endl; + std::cout << " --root-uid Root UID." << std::endl; + std::cout << " --remove-gl Remove group length (deprecated in DICOM 2008)." << std::endl; + std::cout << " --remove-private-tags Remove private tags." << std::endl; + std::cout << " --remove-retired Remove retired tags." << std::endl; + std::cout << "Image only Options:" << std::endl; + std::cout << " -l --apply-lut Apply LUT (non-standard, advanced user only)." << std::endl; + std::cout << " -P --photometric-interpretation %s Change Photometric Interpretation (when possible)." << std::endl; + std::cout << " -w --raw Decompress image." << std::endl; + std::cout << " -d --deflated Compress using deflated (gzip)." << std::endl; + std::cout << " -J --jpeg Compress image in jpeg." << std::endl; + std::cout << " -K --j2k Compress image in j2k." << std::endl; + std::cout << " -L --jpegls Compress image in jpeg-ls." << std::endl; + std::cout << " -R --rle Compress image in rle (lossless only)." << std::endl; + std::cout << " -F --force Force decompression/merging before recompression/splitting." << std::endl; + std::cout << " --generate-icon Generate icon." << std::endl; + std::cout << " --icon-minmax %d,%d Min/Max value for icon." << std::endl; + std::cout << " --icon-auto-minmax Automatically commpute best Min/Max values for icon." << std::endl; + std::cout << " --compress-icon Decide whether icon follows main TransferSyntax or remains uncompressed." << std::endl; + std::cout << " --planar-configuration [01] Change planar configuration." << std::endl; + std::cout << " -Y --lossy Use the lossy (if possible) compressor." << std::endl; + std::cout << " -S --split %d Write 2D image with multiple fragments (using max size)" << std::endl; + std::cout << "General Options:" << std::endl; + std::cout << " -V --verbose more verbose (warning+error)." << std::endl; + std::cout << " -W --warning print warning info." << std::endl; + std::cout << " -D --debug print debug info." << std::endl; + std::cout << " -E --error print error info." << std::endl; + std::cout << " -h --help print help." << std::endl; + std::cout << " -v --version print version." << std::endl; + std::cout << " --quiet do not print to stdout." << std::endl; + std::cout << "JPEG Options:" << std::endl; + std::cout << " -q --quality %*f set quality." << std::endl; + std::cout << "JPEG-LS Options:" << std::endl; + std::cout << " -e --lossy-error %*i set error." << std::endl; + std::cout << "J2K Options:" << std::endl; + std::cout << " -r --rate %*f set rate." << std::endl; + std::cout << " -q --quality %*f set quality." << std::endl; + std::cout << " -t --tile %d,%d set tile size." << std::endl; + std::cout << " -n --number-resolution %d set number of resolution." << std::endl; + std::cout << " --irreversible set irreversible." << std::endl; + std::cout << "Special Options:" << std::endl; + std::cout << " -I --ignore-errors convert even if file is corrupted (advanced users only, see disclaimers)." << std::endl; + std::cout << "Env var:" << std::endl; + std::cout << " GDCM_ROOT_UID Root UID" << std::endl; +/* + * Default behavior for root UID is: + * By default the GDCM one is used + * If GDCM_ROOT_UID is set, then use this one instead + * If --root-uid is explicitly set on the command line, it will override any other defined behavior + */ +} + +template +static size_t readvector(std::vector &v, const char *str) +{ + if( !str ) return 0; + std::istringstream os( str ); + T f; + while( os >> f ) + { + v.push_back( f ); + os.get(); // == "," + } + return v.size(); +} + +namespace gdcm +{ +static bool derives( File & file, const Pixmap& compressed_image ) +{ +#if 1 + DataSet &ds = file.GetDataSet(); + + if( !ds.FindDataElement( Tag(0x0008,0x0016) ) + || ds.GetDataElement( Tag(0x0008,0x0016) ).IsEmpty() ) + { + return false; + } + if( !ds.FindDataElement( Tag(0x0008,0x0018) ) + || ds.GetDataElement( Tag(0x0008,0x0018) ).IsEmpty() ) + { + return false; + } + const DataElement &sopclassuid = ds.GetDataElement( Tag(0x0008,0x0016) ); + const DataElement &sopinstanceuid = ds.GetDataElement( Tag(0x0008,0x0018) ); + // Make sure that const char* pointer will be properly padded with \0 char: + std::string sopclassuid_str( sopclassuid.GetByteValue()->GetPointer(), sopclassuid.GetByteValue()->GetLength() ); + std::string sopinstanceuid_str( sopinstanceuid.GetByteValue()->GetPointer(), sopinstanceuid.GetByteValue()->GetLength() ); + ds.Remove( Tag(0x8,0x18) ); + + FileDerivation fd; + fd.SetFile( file ); + fd.AddReference( sopclassuid_str.c_str(), sopinstanceuid_str.c_str() ); + + // CID 7202 Source Image Purposes of Reference + // {"DCM",121320,"Uncompressed predecessor"}, + fd.SetPurposeOfReferenceCodeSequenceCodeValue( 121320 ); + + // CID 7203 Image Derivation + // { "DCM",113040,"Lossy Compression" }, + fd.SetDerivationCodeSequenceCodeValue( 113040 ); + fd.SetDerivationDescription( "lossy conversion" ); + if( !fd.Derive() ) + { + std::cerr << "Sorry could not derive using input info" << std::endl; + return false; + } + + +#else +/* +(0008,2111) ST [Lossy compression with JPEG extended sequential 8 bit, IJG quality... # 102, 1 DerivationDescription +(0008,2112) SQ (Sequence with explicit length #=1) # 188, 1 SourceImageSequence + (fffe,e000) na (Item with explicit length #=3) # 180, 1 Item + (0008,1150) UI =UltrasoundImageStorage # 28, 1 ReferencedSOPClassUID + (0008,1155) UI [1.2.840.1136190195280574824680000700.3.0.1.19970424140438] # 58, 1 ReferencedSOPInstanceUID + (0040,a170) SQ (Sequence with explicit length #=1) # 66, 1 PurposeOfReferenceCodeSequence + (fffe,e000) na (Item with explicit length #=3) # 58, 1 Item + (0008,0100) SH [121320] # 6, 1 CodeValue + (0008,0102) SH [DCM] # 4, 1 CodingSchemeDesignator + (0008,0104) LO [Uncompressed predecessor] # 24, 1 CodeMeaning + (fffe,e00d) na (ItemDelimitationItem for re-encoding) # 0, 0 ItemDelimitationItem + (fffe,e0dd) na (SequenceDelimitationItem for re-encod.) # 0, 0 SequenceDelimitationItem + (fffe,e00d) na (ItemDelimitationItem for re-encoding) # 0, 0 ItemDelimitationItem +(fffe,e0dd) na (SequenceDelimitationItem for re-encod.) # 0, 0 SequenceDelimitationItem +*/ + const Tag sisq(0x8,0x2112); + SequenceOfItems * sqi; + sqi = new SequenceOfItems; + DataElement de( sisq); + de.SetVR( VR::SQ ); + de.SetValue( *sqi ); + de.SetVLToUndefined(); + + DataSet &ds = file.GetDataSet(); + ds.Insert( de ); +{ + // (0008,0008) CS [ORIGINAL\SECONDARY] # 18, 2 ImageType + gdcm::Attribute<0x0008,0x0008> at3; + static const gdcm::CSComp values[] = {"DERIVED","SECONDARY"}; + at3.SetValues( values, 2, true ); // true => copy data ! + if( ds.FindDataElement( at3.GetTag() ) ) + { + const gdcm::DataElement &de = ds.GetDataElement( at3.GetTag() ); + at3.SetFromDataElement( de ); + // Make sure that value #1 is at least 'DERIVED', so override in all cases: + at3.SetValue( 0, values[0] ); + } + ds.Replace( at3.GetAsDataElement() ); + +} +{ + Attribute<0x0008,0x2111> at1; + at1.SetValue( "lossy conversion" ); + ds.Replace( at1.GetAsDataElement() ); +} + + sqi = (SequenceOfItems*)ds.GetDataElement( sisq ).GetSequenceOfItems(); + sqi->SetLengthToUndefined(); + + if( !sqi->GetNumberOfItems() ) + { + Item item; //( Tag(0xfffe,0xe000) ); + item.SetVLToUndefined(); + sqi->AddItem( item ); + } + + Item &item1 = sqi->GetItem(1); + DataSet &subds = item1.GetNestedDataSet(); +/* + (0008,1150) UI =UltrasoundImageStorage # 28, 1 ReferencedSOPClassUID + (0008,1155) UI [1.2.840.1136190195280574824680000700.3.0.1.19970424140438] # 58, 1 ReferencedSOPInstanceUID +*/ +{ + DataElement sopinstanceuid = ds.GetDataElement( Tag(0x0008,0x0016) ); + sopinstanceuid.SetTag( Tag(0x8,0x1150 ) ); + subds.Replace( sopinstanceuid ); + DataElement sopclassuid = ds.GetDataElement( Tag(0x0008,0x0018) ); + sopclassuid.SetTag( Tag(0x8,0x1155 ) ); + subds.Replace( sopclassuid ); + ds.Remove( Tag(0x8,0x18) ); +} + + const Tag prcs(0x0040,0xa170); + if( !subds.FindDataElement( prcs) ) + { + SequenceOfItems *sqi2 = new SequenceOfItems; + DataElement de( prcs ); + de.SetVR( VR::SQ ); + de.SetValue( *sqi2 ); + de.SetVLToUndefined(); + subds.Insert( de ); + } + + sqi = (SequenceOfItems*)subds.GetDataElement( prcs ).GetSequenceOfItems(); + sqi->SetLengthToUndefined(); + + if( !sqi->GetNumberOfItems() ) + { + Item item; //( Tag(0xfffe,0xe000) ); + item.SetVLToUndefined(); + sqi->AddItem( item ); + } + Item &item2 = sqi->GetItem(1); + DataSet &subds2 = item2.GetNestedDataSet(); + +/* + (0008,0100) SH [121320] # 6, 1 CodeValue + (0008,0102) SH [DCM] # 4, 1 CodingSchemeDesignator + (0008,0104) LO [Uncompressed predecessor] # 24, 1 CodeMeaning +*/ + + Attribute<0x0008,0x0100> at1; + at1.SetValue( "121320" ); + subds2.Replace( at1.GetAsDataElement() ); + Attribute<0x0008,0x0102> at2; + at2.SetValue( "DCM" ); + subds2.Replace( at2.GetAsDataElement() ); + Attribute<0x0008,0x0104> at3; + at3.SetValue( "Uncompressed predecessor" ); + subds2.Replace( at3.GetAsDataElement() ); + +/* +(0008,9215) SQ (Sequence with explicit length #=1) # 98, 1 DerivationCodeSequence + (fffe,e000) na (Item with explicit length #=3) # 90, 1 Item + (0008,0100) SH [121327] # 6, 1 CodeValue + (0008,0102) SH [DCM] # 4, 1 CodingSchemeDesignator + (0008,0104) LO [Full fidelity image, uncompressed or lossless compressed] # 56, 1 CodeMeaning + (fffe,e00d) na (ItemDelimitationItem for re-encoding) # 0, 0 ItemDelimitationItem +(fffe,e0dd) na (SequenceDelimitationItem for re-encod.) # 0, 0 SequenceDelimitationItem +*/ +{ + const Tag sisq(0x8,0x9215); + SequenceOfItems * sqi; + sqi = new SequenceOfItems; + DataElement de( sisq ); + de.SetVR( VR::SQ ); + de.SetValue( *sqi ); + de.SetVLToUndefined(); + ds.Insert( de ); + sqi = (SequenceOfItems*)ds.GetDataElement( sisq ).GetSequenceOfItems(); + sqi->SetLengthToUndefined(); + + if( !sqi->GetNumberOfItems() ) + { + Item item; //( Tag(0xfffe,0xe000) ); + item.SetVLToUndefined(); + sqi->AddItem( item ); + } + + Item &item1 = sqi->GetItem(1); + DataSet &subds3 = item1.GetNestedDataSet(); + + Attribute<0x0008,0x0100> at1; + at1.SetValue( "121327" ); + subds3.Replace( at1.GetAsDataElement() ); + Attribute<0x0008,0x0102> at2; + at2.SetValue( "DCM" ); + subds3.Replace( at2.GetAsDataElement() ); + Attribute<0x0008,0x0104> at3; + at3.SetValue( "Full fidelity image, uncompressed or lossless compressed" ); + subds3.Replace( at3.GetAsDataElement() ); +} +#endif + +{ + /* + (0028,2110) CS [01] # 2, 1 LossyImageCompression + (0028,2112) DS [15.95] # 6, 1 LossyImageCompressionRatio + (0028,2114) CS [ISO_10918_1] # 12, 1 LossyImageCompressionMethod + */ + const DataElement & pixeldata = compressed_image.GetDataElement(); + size_t len = pixeldata.GetSequenceOfFragments()->ComputeByteLength(); + size_t reflen = compressed_image.GetBufferLength(); + double ratio = (double)reflen / (double)len; + Attribute<0x0028,0x2110> at1; + at1.SetValue( "01" ); + ds.Replace( at1.GetAsDataElement() ); + Attribute<0x0028,0x2112> at2; + at2.SetValues( &ratio, 1); + ds.Replace( at2.GetAsDataElement() ); + Attribute<0x0028,0x2114> at3; + + // ImageWriter will properly set attribute 0028,2114 (Lossy Image Compression Method) +} + +return true; + +} +} // end namespace gdcm + +int main (int argc, char *argv[]) +{ + int c; + //int digit_optind = 0; + + std::string filename; + std::string outfilename; + std::string root; + int explicitts = 0; // explicit is a reserved keyword + int implicit = 0; + int quiet = 0; + int lut = 0; + int raw = 0; + int deflated = 0; + int rootuid = 0; + int checkmeta = 0; + int jpeg = 0; + int jpegls = 0; + int j2k = 0; + int lossy = 0; + int split = 0; + int fragmentsize = 0; + int rle = 0; + int force = 0; + int planarconf = 0; + int planarconfval = 0; + double iconmin = 0; + double iconmax = 0; + int usedict = 0; + int compressicon = 0; + int generateicon = 0; + int iconminmax = 0; + int iconautominmax = 0; + int removegrouplength = 0; + int removeprivate = 0; + int removeretired = 0; + int photometricinterpretation = 0; + std::string photometricinterpretation_str; + int quality = 0; + int rate = 0; + int tile = 0; + int nres = 0; + int nresvalue = 6; // ?? + std::vector qualities; + std::vector rates; + std::vector tilesize; + int irreversible = 0; + int changeprivatetags = 0; + + int verbose = 0; + int warning = 0; + int debug = 0; + int error = 0; + int help = 0; + int version = 0; + int ignoreerrors = 0; + int jpeglserror = 0; + int jpeglserror_value = 0; + + while (1) { + //int this_option_optind = optind ? optind : 1; + int option_index = 0; + static struct option long_options[] = { + {"input", 1, 0, 0}, + {"output", 1, 0, 0}, + {"group-length", 1, 0, 0}, // valid / create / remove + {"preamble", 1, 0, 0}, // valid / create / remove + {"padding", 1, 0, 0}, // valid (\0 -> space) / optimize (at most 1 byte of padding) + {"vr", 1, 0, 0}, // valid + {"sop", 1, 0, 0}, // default to SC... + {"iod", 1, 0, 0}, // valid + {"meta", 1, 0, 0}, // valid / create / remove + {"dataset", 1, 0, 0}, // valid / create / remove? + {"sequence", 1, 0, 0}, // defined / undefined + {"deflate", 1, 0, 0}, // 1 - 9 / best = 9 / fast = 1 + {"tag", 1, 0, 0}, // need to specify a tag xxxx,yyyy = value to override default + {"name", 1, 0, 0}, // same as tag but explicit use of name + {"root-uid", 1, &rootuid, 1}, // specific Root (not GDCM) + {"check-meta", 0, &checkmeta, 1}, // specific Root (not GDCM) +// Image specific options: + {"pixeldata", 1, 0, 0}, // valid + {"apply-lut", 0, &lut, 1}, // default (implicit VR, LE) / Explicit LE / Explicit BE + {"raw", 0, &raw, 1}, // default (implicit VR, LE) / Explicit LE / Explicit BE + {"deflated", 0, &deflated, 1}, // DeflatedExplicitVRLittleEndian + {"lossy", 0, &lossy, 1}, // Specify lossy comp + {"force", 0, &force, 1}, // force decompression even if target compression is identical + {"jpeg", 0, &jpeg, 1}, // JPEG lossy / lossless + {"jpegls", 0, &jpegls, 1}, // JPEG-LS: lossy / lossless + {"j2k", 0, &j2k, 1}, // J2K: lossy / lossless + {"rle", 0, &rle, 1}, // lossless ! + {"mpeg2", 0, 0, 0}, // lossy ! + {"jpip", 0, 0, 0}, // ?? + {"split", 1, &split, 1}, // split fragments + {"planar-configuration", 1, &planarconf, 1}, // Planar Configuration + {"explicit", 0, &explicitts, 1}, // + {"implicit", 0, &implicit, 1}, // + {"use-dict", 0, &usedict, 1}, // + {"generate-icon", 0, &generateicon, 1}, // + {"icon-minmax", 1, &iconminmax, 1}, // + {"icon-auto-minmax", 0, &iconautominmax, 1}, // + {"compress-icon", 0, &compressicon, 1}, // + {"remove-gl", 0, &removegrouplength, 1}, // + {"remove-private-tags", 0, &removeprivate, 1}, // + {"remove-retired", 0, &removeretired, 1}, // + {"photometric-interpretation", 1, &photometricinterpretation, 1}, // + {"with-private-dict", 0, &changeprivatetags, 1}, // +// j2k : + {"rate", 1, &rate, 1}, // + {"quality", 1, &quality, 1}, // will also work for regular jpeg compressor + {"tile", 1, &tile, 1}, // + {"number-resolution", 1, &nres, 1}, // + {"irreversible", 0, &irreversible, 1}, // + {"allowed-error", 1, &jpeglserror, 1}, // + +// General options ! + {"verbose", 0, &verbose, 1}, + {"warning", 0, &warning, 1}, + {"debug", 0, &debug, 1}, + {"error", 0, &error, 1}, + {"help", 0, &help, 1}, + {"version", 0, &version, 1}, + {"ignore-errors", 0, &ignoreerrors, 1}, + {"quiet", 0, &quiet, 1}, + + {0, 0, 0, 0} + }; + + c = getopt_long (argc, argv, "i:o:XMUClwdJKLRFYS:P:VWDEhvIr:q:t:n:e:", + long_options, &option_index); + if (c == -1) + { + break; + } + + switch (c) + { + case 0: + { + const char *s = long_options[option_index].name; (void)s; + //printf ("option %s", s); + if (optarg) + { + if( option_index == 0 ) /* input */ + { + assert( strcmp(s, "input") == 0 ); + assert( filename.empty() ); + filename = optarg; + } + else if( option_index == 14 ) /* root-uid */ + { + assert( strcmp(s, "root-uid") == 0 ); + assert( root.empty() ); + root = optarg; + } + else if( option_index == 28 ) /* split */ + { + assert( strcmp(s, "split") == 0 ); + fragmentsize = atoi(optarg); + } + else if( option_index == 29 ) /* planar conf*/ + { + assert( strcmp(s, "planar-configuration") == 0 ); + planarconfval = atoi(optarg); + } + else if( option_index == 34 ) /* icon minmax*/ + { + assert( strcmp(s, "icon-minmax") == 0 ); + std::stringstream ss; + ss.str( optarg ); + ss >> iconmin; + char comma; + ss >> comma; + ss >> iconmax; + } + else if( option_index == 40 ) /* photometricinterpretation */ + { + assert( strcmp(s, "photometric-interpretation") == 0 ); + photometricinterpretation_str = optarg; + } + else if( option_index == 42 ) /* rate */ + { + assert( strcmp(s, "rate") == 0 ); + readvector(rates, optarg); + } + else if( option_index == 43 ) /* quality */ + { + assert( strcmp(s, "quality") == 0 ); + readvector(qualities, optarg); + } + else if( option_index == 44 ) /* tile */ + { + assert( strcmp(s, "tile") == 0 ); + size_t n = readvector(tilesize, optarg); + assert( n == 2 ); (void)n; + } + else if( option_index == 45 ) /* number of resolution */ + { + assert( strcmp(s, "number-resolution") == 0 ); + nresvalue = atoi(optarg); + } + else if( option_index == 47 ) /* JPEG-LS error */ + { + assert( strcmp(s, "allowed-error") == 0 ); + jpeglserror_value = atoi(optarg); + } + //printf (" with arg %s, index = %d", optarg, option_index); + } + //printf ("\n"); + } + break; + + case 'i': + //printf ("option i with value '%s'\n", optarg); + assert( filename.empty() ); + filename = optarg; + break; + + case 'o': + //printf ("option o with value '%s'\n", optarg); + assert( outfilename.empty() ); + outfilename = optarg; + break; + + case 'X': + explicitts = 1; + break; + + case 'M': + implicit = 1; + break; + + case 'U': + usedict = 1; + break; + + case 'C': + checkmeta = 1; + break; + + // root-uid + + case 'l': + lut = 1; + break; + + case 'w': + raw = 1; + break; + + case 'e': + jpeglserror = 1; + jpeglserror_value = atoi(optarg); + break; + + case 'd': + deflated = 1; + break; + + case 'J': + jpeg = 1; + break; + + case 'K': + j2k = 1; + break; + + case 'L': + jpegls = 1; + break; + + case 'R': + rle = 1; + break; + + case 'F': + force = 1; + break; + + case 'Y': + lossy = 1; + break; + + case 'S': + split = 1; + fragmentsize = atoi(optarg); + break; + + case 'P': + photometricinterpretation = 1; + photometricinterpretation_str = optarg; + break; + + case 'r': + rate = 1; + readvector(rates, optarg); + break; + + case 'q': + quality = 1; + readvector(qualities, optarg); + break; + + case 't': + tile = 1; + readvector(tilesize, optarg); + break; + + case 'n': + nres = 1; + nresvalue = atoi(optarg); + break; + + // General option + case 'V': + verbose = 1; + break; + + case 'W': + warning = 1; + break; + + case 'D': + debug = 1; + break; + + case 'E': + error = 1; + break; + + case 'h': + help = 1; + break; + + case 'v': + version = 1; + break; + + case 'I': + ignoreerrors = 1; + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + // For now only support one input / one output + if (optind < argc) + { + //printf ("non-option ARGV-elements: "); + std::vector files; + while (optind < argc) + { + //printf ("%s\n", argv[optind++]); + files.push_back( argv[optind++] ); + } + //printf ("\n"); + if( files.size() == 2 + && filename.empty() + && outfilename.empty() + ) + { + filename = files[0]; + outfilename = files[1]; + } + else + { + PrintHelp(); + return 1; + } + } + + if( version ) + { + //std::cout << "version" << std::endl; + PrintVersion(); + return 0; + } + + if( help ) + { + //std::cout << "help" << std::endl; + PrintHelp(); + return 0; + } + + if( filename.empty() ) + { + //std::cerr << "Need input file (-i)\n"; + PrintHelp(); + return 1; + } + if( outfilename.empty() ) + { + //std::cerr << "Need output file (-o)\n"; + PrintHelp(); + return 1; + } + + // Debug is a little too verbose + gdcm::Trace::SetDebug( (debug > 0 ? true : false)); + gdcm::Trace::SetWarning( (warning > 0 ? true : false)); + gdcm::Trace::SetError( (error > 0 ? true : false)); + // when verbose is true, make sure warning+error are turned on: + if( verbose ) + { + gdcm::Trace::SetWarning( (verbose > 0 ? true : false) ); + gdcm::Trace::SetError( (verbose > 0 ? true : false) ); + } + + gdcm::FileMetaInformation::SetSourceApplicationEntityTitle( "gdcmconv" ); + if( !rootuid ) + { + // only read the env var is no explicit cmd line option + // maybe there is an env var defined... let's check + const char *rootuid_env = getenv("GDCM_ROOT_UID"); + if( rootuid_env ) + { + rootuid = 1; + root = rootuid_env; + } + } + if( rootuid ) + { + // root is set either by the cmd line option or the env var + if( !gdcm::UIDGenerator::IsValid( root.c_str() ) ) + { + std::cerr << "specified Root UID is not valid: " << root << std::endl; + return 1; + } + gdcm::UIDGenerator::SetRoot( root.c_str() ); + } + + if( removegrouplength || removeprivate || removeretired ) + { + gdcm::Reader reader; + reader.SetFileName( filename.c_str() ); + if( !reader.Read() ) + { + std::cerr << "Could not read: " << filename << std::endl; + return 1; + } + gdcm::MediaStorage ms; + ms.SetFromFile( reader.GetFile() ); + if( ms == gdcm::MediaStorage::MediaStorageDirectoryStorage ) + { + std::cerr << "Sorry DICOMDIR is not supported" << std::endl; + return 1; + } + + gdcm::Anonymizer ano; + ano.SetFile( reader.GetFile() ); + if( removegrouplength ) + { + if( !ano.RemoveGroupLength() ) + { + std::cerr << "Could not remove group length" << std::endl; + } + } + if( removeretired ) + { + if( !ano.RemoveRetired() ) + { + std::cerr << "Could not remove retired tags" << std::endl; + } + } + if( removeprivate ) + { + if( !ano.RemovePrivateTags() ) + { + std::cerr << "Could not remove private tags" << std::endl; + } + } + + gdcm::Writer writer; + writer.SetFileName( outfilename.c_str() ); + writer.SetFile( ano.GetFile() ); + if( !writer.Write() ) + { + std::cerr << "Failed to write: " << outfilename << std::endl; + return 1; + } + + return 0; + } + + // Handle here the general file (not required to be image) + if ( explicitts || implicit || deflated ) + { + if( explicitts && implicit ) return 1; // guard + if( explicitts && deflated ) return 1; // guard + if( implicit && deflated ) return 1; // guard + gdcm::Reader reader; + reader.SetFileName( filename.c_str() ); + if( !reader.Read() ) + { + std::cerr << "Could not read: " << filename << std::endl; + return 1; + } + gdcm::MediaStorage ms; + ms.SetFromFile( reader.GetFile() ); + if( ms == gdcm::MediaStorage::MediaStorageDirectoryStorage ) + { + std::cerr << "Sorry DICOMDIR is not supported" << std::endl; + return 1; + } + + gdcm::Writer writer; + writer.SetFileName( outfilename.c_str() ); + writer.SetFile( reader.GetFile() ); + gdcm::File & file = writer.GetFile(); + gdcm::FileMetaInformation &fmi = file.GetHeader(); + + const gdcm::TransferSyntax &orits = fmi.GetDataSetTransferSyntax(); + if( orits != gdcm::TransferSyntax::ExplicitVRLittleEndian + && orits != gdcm::TransferSyntax::ImplicitVRLittleEndian + && orits != gdcm::TransferSyntax::DeflatedExplicitVRLittleEndian ) + { + std::cerr << "Sorry input Transfer Syntax not supported for this conversion: " << orits << std::endl; + return 1; + } + + gdcm::TransferSyntax ts = gdcm::TransferSyntax::ImplicitVRLittleEndian; + if( explicitts ) + { + ts = gdcm::TransferSyntax::ExplicitVRLittleEndian; + } + else if( deflated ) + { + ts = gdcm::TransferSyntax::DeflatedExplicitVRLittleEndian; + } + std::string tsuid = gdcm::TransferSyntax::GetTSString( ts ); + if( tsuid.size() % 2 == 1 ) + { + tsuid.push_back( 0 ); // 0 padding + } + gdcm::DataElement de( gdcm::Tag(0x0002,0x0010) ); + de.SetByteValue( &tsuid[0], (uint32_t)tsuid.size() ); + de.SetVR( gdcm::Attribute<0x0002, 0x0010>::GetVR() ); + fmi.Clear(); + fmi.Replace( de ); + + fmi.SetDataSetTransferSyntax(ts); + + if( explicitts || deflated ) + { + gdcm::FileExplicitFilter fef; + fef.SetChangePrivateTags( (changeprivatetags > 0 ? true: false)); + fef.SetFile( reader.GetFile() ); + if( !fef.Change() ) + { + std::cerr << "Failed to change: " << filename << std::endl; + return 1; + } + } + + if( !writer.Write() ) + { + std::cerr << "Failed to write: " << outfilename << std::endl; + return 1; + } + + return 0; + } + + // split fragments + if( split ) + { + gdcm::PixmapReader reader; + reader.SetFileName( filename.c_str() ); + if( !reader.Read() ) + { + std::cerr << "Could not read (pixmap): " << filename << std::endl; + return 1; + } + const gdcm::Pixmap &image = reader.GetPixmap(); + + gdcm::ImageFragmentSplitter splitter; + splitter.SetInput( image ); + splitter.SetFragmentSizeMax( fragmentsize ); + splitter.SetForce( (force > 0 ? true: false)); + bool b = splitter.Split(); + if( !b ) + { + std::cerr << "Could not split: " << filename << std::endl; + return 1; + } + gdcm::PixmapWriter writer; + writer.SetFileName( outfilename.c_str() ); + writer.SetFile( reader.GetFile() ); + writer.SetPixmap( splitter.PixmapToPixmapFilter::GetOutput() ); + if( !writer.Write() ) + { + std::cerr << "Failed to write: " << outfilename << std::endl; + return 1; + } + } + else if( photometricinterpretation ) + { + gdcm::PixmapReader reader; + reader.SetFileName( filename.c_str() ); + if( !reader.Read() ) + { + std::cerr << "Could not read (pixmap): " << filename << std::endl; + return 1; + } + const gdcm::Pixmap &image = reader.GetPixmap(); + + // Just in case: + if( gdcm::PhotometricInterpretation::GetPIType(photometricinterpretation_str.c_str()) + == gdcm::PhotometricInterpretation::PI_END ) + { + std::cerr << "Do not handle PhotometricInterpretation: " << photometricinterpretation_str << std::endl; + return 1; + } + gdcm::PhotometricInterpretation pi ( + gdcm::PhotometricInterpretation::GetPIType(photometricinterpretation_str.c_str()) ); + gdcm::ImageChangePhotometricInterpretation pifilt; + pifilt.SetInput( image ); + pifilt.SetPhotometricInterpretation( pi ); + bool b = pifilt.Change(); + if( !b ) + { + std::cerr << "Could not apply PhotometricInterpretation: " << filename << std::endl; + return 1; + } + gdcm::PixmapWriter writer; + writer.SetFileName( outfilename.c_str() ); + writer.SetFile( reader.GetFile() ); + writer.SetPixmap( pifilt.PixmapToPixmapFilter::GetOutput() ); + if( !writer.Write() ) + { + std::cerr << "Failed to write: " << outfilename << std::endl; + return 1; + } + } + else if( lut ) + { + gdcm::PixmapReader reader; + reader.SetFileName( filename.c_str() ); + if( !reader.Read() ) + { + std::cerr << "Could not read (pixmap): " << filename << std::endl; + return 1; + } + const gdcm::Pixmap &image = reader.GetPixmap(); + + gdcm::ImageApplyLookupTable lutfilt; + lutfilt.SetInput( image ); + bool b = lutfilt.Apply(); + if( !b ) + { + std::cerr << "Could not apply LUT: " << filename << std::endl; + return 1; + } + gdcm::PixmapWriter writer; + writer.SetFileName( outfilename.c_str() ); + writer.SetFile( reader.GetFile() ); + writer.SetPixmap( lutfilt.PixmapToPixmapFilter::GetOutput() ); + if( !writer.Write() ) + { + std::cerr << "Failed to write: " << outfilename << std::endl; + return 1; + } + } + else if( jpeg || j2k || jpegls || rle || raw || force /*|| deflated*/ /*|| planarconf*/ ) + { + gdcm::PixmapReader reader; + reader.SetFileName( filename.c_str() ); + if( !reader.Read() ) + { + std::cerr << "Could not read (pixmap): " << filename << std::endl; + return 1; + } + gdcm::Pixmap &image = reader.GetPixmap(); + //const gdcm::IconImage &icon = image.GetIconImage(); + //if( !icon.IsEmpty() ) + // { + // std::cerr << "Icons are not supported" << std::endl; + // return 1; + // } + if( generateicon ) + { + gdcm::IconImageGenerator iig; + iig.SetPixmap( image ); + const unsigned int idims[2] = { 64, 64 }; + iig.SetOutputDimensions( idims ); + if( iconminmax ) + { + iig.SetPixelMinMax( iconmin, iconmax ); + } + iig.AutoPixelMinMax( iconautominmax ? true : false ); + bool b = iig.Generate(); + if( !b ) return 1; + const gdcm::IconImage &icon = iig.GetIconImage(); + image.SetIconImage( icon ); + } + + gdcm::JPEG2000Codec j2kcodec; + gdcm::JPEGCodec jpegcodec; + gdcm::JPEGLSCodec jpeglscodec; + gdcm::ImageChangeTransferSyntax change; + change.SetForce( (force > 0 ? true: false)); + change.SetCompressIconImage( (compressicon > 0 ? true: false)); + if( jpeg ) + { + if( lossy ) + { + change.SetTransferSyntax( gdcm::TransferSyntax::JPEGBaselineProcess1 ); + jpegcodec.SetLossless( false ); + if( quality ) + { + assert( qualities.size() == 1 ); + jpegcodec.SetQuality( qualities[0] ); + } + change.SetUserCodec( &jpegcodec ); + } + else + { + change.SetTransferSyntax( gdcm::TransferSyntax::JPEGLosslessProcess14_1 ); + } + } + else if( jpegls ) + { + if( lossy ) + { + change.SetTransferSyntax( gdcm::TransferSyntax::JPEGLSNearLossless ); + jpeglscodec.SetLossless( false ); + if( jpeglserror ) + { + jpeglscodec.SetLossyError( jpeglserror_value ); + } + change.SetUserCodec( &jpeglscodec ); + } + else + { + change.SetTransferSyntax( gdcm::TransferSyntax::JPEGLSLossless ); + } + } + else if( j2k ) + { + if( lossy ) + { + change.SetTransferSyntax( gdcm::TransferSyntax::JPEG2000 ); + if( rate ) + { + int i = 0; + for(std::vector::const_iterator it = rates.begin(); it != rates.end(); ++it ) + { + j2kcodec.SetRate(i++, *it ); + } + } + if( quality ) + { + int i = 0; + for(std::vector::const_iterator it = qualities.begin(); it != qualities.end(); ++it ) + { + j2kcodec.SetQuality( i++, *it ); + } + } + if( tile ) + { + j2kcodec.SetTileSize( tilesize[0], tilesize[1] ); + } + if( nres ) + { + j2kcodec.SetNumberOfResolutions( nresvalue ); + } + j2kcodec.SetReversible( !irreversible ); + change.SetUserCodec( &j2kcodec ); + } + else + { + change.SetTransferSyntax( gdcm::TransferSyntax::JPEG2000Lossless ); + } + } + else if( raw ) + { + if( lossy ) + { + std::cerr << "no such thing as raw & lossy" << std::endl; + return 1; + } + const gdcm::TransferSyntax &ts = image.GetTransferSyntax(); +#ifdef GDCM_WORDS_BIGENDIAN + (void)ts; + change.SetTransferSyntax( gdcm::TransferSyntax::ExplicitVRBigEndian ); +#else + if( ts.IsExplicit() ) + { + change.SetTransferSyntax( gdcm::TransferSyntax::ExplicitVRLittleEndian ); + } + else + { + assert( ts.IsImplicit() ); + change.SetTransferSyntax( gdcm::TransferSyntax::ImplicitVRLittleEndian ); + } +#endif + } + else if( rle ) + { + if( lossy ) + { + std::cerr << "no such thing as rle & lossy" << std::endl; + return 1; + } + change.SetTransferSyntax( gdcm::TransferSyntax::RLELossless ); + } + else if( deflated ) + { + if( lossy ) + { + std::cerr << "no such thing as deflated & lossy" << std::endl; + return 1; + } + change.SetTransferSyntax( gdcm::TransferSyntax::DeflatedExplicitVRLittleEndian ); + } + else if( force ) + { + // If image is encapsulated it will check some attribute (col/row/pi/pf) and + // some attributes... + } + else + { + std::cerr << "unhandled action" << std::endl; + return 1; + } + if( raw && planarconf ) + { + gdcm::ImageChangePlanarConfiguration icpc; + icpc.SetPlanarConfiguration( planarconfval ); + icpc.SetInput( image ); + bool b = icpc.Change(); + if( !b ) + { + std::cerr << "Could not change the Planar Configuration: " << filename << std::endl; + return 1; + } + change.SetInput( icpc.PixmapToPixmapFilter::GetOutput() ); + } + else + { + change.SetInput( image ); + } + bool b = change.Change(); + if( !b ) + { + std::cerr << "Could not change the Transfer Syntax: " << filename << std::endl; + return 1; + } + if( lossy ) + { + if(!quiet) + PrintLossyWarning(); + if( !gdcm::derives( reader.GetFile(), change.PixmapToPixmapFilter::GetOutput() ) ) + { + std::cerr << "Failed to derives: " << filename << std::endl; + return 1; + } + } + if( usedict /*ts.IsImplicit()*/ ) + { + gdcm::FileExplicitFilter fef; + fef.SetChangePrivateTags( (changeprivatetags > 0 ? true : false)); + fef.SetFile( reader.GetFile() ); + if(!fef.Change()) + { + std::cerr << "Failed to change: " << filename << std::endl; + return 1; + } + } + + gdcm::PixmapWriter writer; + writer.SetFileName( outfilename.c_str() ); + writer.SetFile( reader.GetFile() ); + //writer.SetFile( fef.GetFile() ); + + gdcm::File & file = writer.GetFile(); + gdcm::FileMetaInformation &fmi = file.GetHeader(); + fmi.Remove( gdcm::Tag(0x0002,0x0100) ); // ' ' ' // PrivateInformationCreatorUID + fmi.Remove( gdcm::Tag(0x0002,0x0102) ); // ' ' ' // PrivateInformation + + const gdcm::Pixmap &pixout = change.PixmapToPixmapFilter::GetOutput(); + writer.SetPixmap( pixout ); + if( !writer.Write() ) + { + std::cerr << "Failed to write: " << outfilename << std::endl; + return 1; + } + + } + else if( raw && false ) + { + gdcm::PixmapReader reader; + reader.SetFileName( filename.c_str() ); + if( !reader.Read() ) + { + std::cerr << "Could not read (pixmap): " << filename << std::endl; + return 1; + } + + const gdcm::Pixmap &ir = reader.GetPixmap(); + + gdcm::Pixmap image( ir ); + const gdcm::TransferSyntax &ts = ir.GetTransferSyntax(); + if( ts.IsExplicit() ) + { + image.SetTransferSyntax( gdcm::TransferSyntax::ExplicitVRLittleEndian ); + } + else + { + assert( ts.IsImplicit() ); + image.SetTransferSyntax( gdcm::TransferSyntax::ImplicitVRLittleEndian ); + } + +/* + image.SetNumberOfDimensions( ir.GetNumberOfDimensions() ); + + const unsigned int *dims = ir.GetDimensions(); + image.SetDimension(0, dims[0] ); + image.SetDimension(1, dims[1] ); + + const gdcm::PixelFormat &pixeltype = ir.GetPixelFormat(); + image.SetPixelFormat( pixeltype ); + + const gdcm::PhotometricInterpretation &pi = ir.GetPhotometricInterpretation(); + image.SetPhotometricInterpretation( pi ); +*/ + + unsigned long len = ir.GetBufferLength(); + //assert( len = ir.GetBufferLength() ); + std::vector buffer; + buffer.resize(len); // black image + + ir.GetBuffer( &buffer[0] ); + gdcm::ByteValue *bv = new gdcm::ByteValue(buffer); + gdcm::DataElement pixeldata( gdcm::Tag(0x7fe0,0x0010) ); + pixeldata.SetValue( *bv ); + image.SetDataElement( pixeldata ); + + gdcm::PixmapWriter writer; + writer.SetFile( reader.GetFile() ); + writer.SetPixmap( image ); + writer.SetFileName( outfilename.c_str() ); + + if( !writer.Write() ) + { + std::cerr << "could not write: " << outfilename << std::endl; + return 1; + } + } + else + { + gdcm::Reader reader; + reader.SetFileName( filename.c_str() ); + if( !reader.Read() ) + { + if( ignoreerrors ) + { + std::cerr << "WARNING: an error was found during the reading of your DICOM file." << std::endl; + std::cerr << "gdcmconv will still try to continue and rewrite your DICOM file." << std::endl; + std::cerr << "There is absolutely no guarantee that your output file will be valid." << std::endl; + } + else + { + std::cerr << "Failed to read: " << filename << std::endl; + return 1; + } + } + gdcm::MediaStorage ms; + ms.SetFromFile( reader.GetFile() ); + if( ms == gdcm::MediaStorage::MediaStorageDirectoryStorage ) + { + std::cerr << "Sorry DICOMDIR is not supported" << std::endl; + return 1; + } + +#if 0 + // if preamble create: + gdcm::File f(reader.GetFile()); + gdcm::Preamble p; + p.Create(); + f.SetPreamble(p); + gdcm::DataSet ds = reader.GetFile().GetDataSet(); + SetSQToUndefined undef; + ds.ExecuteOperation(undef); + + gdcm::File f(reader.GetFile()); + f.SetDataSet(ds); +#endif + +#if 0 + gdcm::DataSet& ds = reader.GetFile().GetDataSet(); + gdcm::DataElement de = ds.GetDataElement( gdcm::Tag(0x0010,0x0010) ); + const char patname[] = "John^Doe"; + de.SetByteValue(patname, strlen(patname)); + std::cout << de << std::endl; + + ds.Replace( de ); + std::cout << ds.GetDataElement( gdcm::Tag(0x0010,0x0010) ) << std::endl; +#endif + + /* + //(0020,0032) DS [-158.135803\-179.035797\-75.699997] # 34, 3 ImagePositionPatient + //(0020,0037) DS [1.000000\0.000000\0.000000\0.000000\1.000000\0.000000] # 54, 6 ImageOrientationPatient + gdcm::Attribute<0x0020,0x0032> at = { -158.135803, -179.035797, -75.699997 }; + gdcm::DataElement ipp = at.GetAsDataElement(); + ds.Remove( at.GetTag() ); + ds.Remove( ipp.GetTag() ); + ds.Replace( ipp ); + */ + + gdcm::Writer writer; + writer.SetFileName( outfilename.c_str() ); + writer.SetCheckFileMetaInformation( (checkmeta > 0 ? true : false)); + //writer.SetFile( f ); + writer.SetFile( reader.GetFile() ); + if( !writer.Write() ) + { + std::cerr << "Failed to write: " << outfilename << std::endl; + // remove file to avoid any temptation + if( filename != outfilename ) + { + gdcm::System::RemoveFile( outfilename.c_str() ); + } + else + { + std::cerr << "gdcmconv just corrupted: " << filename << " for you (data lost)." << std::endl; + } + return 1; + } + } + + return 0; +} diff --git a/gdcm/Applications/Cxx/gdcmdictdump.cxx b/gdcm/Applications/Cxx/gdcmdictdump.cxx new file mode 100644 index 0000000..5923e37 --- /dev/null +++ b/gdcm/Applications/Cxx/gdcmdictdump.cxx @@ -0,0 +1,4 @@ +/* +* TODO: Is this really usefull ? +* Dump the dict from a DICOM file. Usefull for the private dict +*/ diff --git a/gdcm/Applications/Cxx/gdcmdiff.cxx b/gdcm/Applications/Cxx/gdcmdiff.cxx new file mode 100644 index 0000000..023d5a7 --- /dev/null +++ b/gdcm/Applications/Cxx/gdcmdiff.cxx @@ -0,0 +1,255 @@ +/*========================================================================= + + Program: gdcmdiff for GDCM (Grassroots DICOM) + + Copyright (c) 2011 Andy Buckle + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmReader.h" +#include "gdcmAttribute.h" +#include "gdcmDataSet.h" +#include "gdcmDicts.h" +#include "gdcmDict.h" +#include "gdcmGlobal.h" +#include "gdcmCSAHeader.h" +#include "gdcmPrivateTag.h" + +#include + +static void usage(); +static void difference_of_datasets(const gdcm::DataSet& ds1, const gdcm::DataSet& ds2, int depthSQ); +static void display_element(std::ostream& os, const gdcm::DataElement& de, + const gdcm::DictEntry& dictentry, const char *note, int depthSQ); +static void underline(int depthSQ); +static void difference_of_sequences(const gdcm::DataElement& sqde1, + const gdcm::DataElement& sqde2, const gdcm::DictEntry& dictentry, int depthSQ); + +// previous declaration of 'int truncate(const char*, __off_t)' +static uint32_t Truncate=30; // trim dumped string values to this number of chars. zero means no trimming. +static std::stringstream sq_disp; // store SQ output while recursing through: only displayed if a difference is found within SQ + +int main( int argc, const char* argv[] ) +{ + // Check number of args + if (3 > argc) + { + std::cerr << "Must supply the filenames of 2 DICOM files\n" << std::endl; + usage(); + return 1; + } + // Check last 2 args are readable DICOM files + gdcm::Reader reader1, reader2; + reader1.SetFileName( argv[argc-2] ); + reader2.SetFileName( argv[argc-1] ); + if( !reader1.Read() || !reader2.Read() ) + { + std::cerr << "At least one of the DICOM files could not be read: " << + '\"' << argv[argc-2] << "\", \"" << argv[argc-1] << '\"' << std::endl; + return 1; + } + // Parse other args + bool include_meta = false; + for(int i=1; i<(argc-2) ;i++) + { + std::string arg = std::string(argv[i]); + if ("-h" == arg || "--help" == arg) + { + usage(); + return 0; + } + else if ("-m" == arg || "--meta" == arg) + { + include_meta = true; + } + else if ("-t" == arg || "--truncate" == arg) + { + Truncate = atoi(argv[++i]); + } + else + { + std::cerr << "Warning: command argument not understood: " + << arg << std::endl; + usage(); + return 1; + } + } + // Start comparison + const gdcm::File &file1 = reader1.GetFile(); + const gdcm::File &file2 = reader2.GetFile(); + + const gdcm::FileMetaInformation &hds1 = file1.GetHeader(); + const gdcm::FileMetaInformation &hds2 = file2.GetHeader(); + + const gdcm::DataSet &ds1 = file1.GetDataSet(); + const gdcm::DataSet &ds2 = file2.GetDataSet(); + + if(include_meta) + { + difference_of_datasets(hds1, hds2, 0); + } + difference_of_datasets(ds1, ds2, 0); + + return 0; +} + +static void usage() +{ + std::cout << + "Usage: gdcmdiff [OPTIONS] DICOM_FILE1 DICOM_FILE2\n\n" + " -h --help (This) help and exit.\n" + " -m --meta Compare metainformation. Default is off.\n" + " -t --truncate String values trimmed to n characters.\n" + " 0 means no trimmming. Default 30." << std::endl; +} + +static void difference_of_datasets(const gdcm::DataSet& ds1, const gdcm::DataSet& ds2, int depthSQ) +{ + gdcm::DataSet::ConstIterator it1 = ds1.Begin(); + gdcm::DataSet::ConstIterator it2 = ds2.Begin(); + do { + // find lowest value tag, being careful not to pick one for an iterator that has finished + const gdcm::Tag tag1 = (it1!=ds1.End()) ? it1->GetTag() : gdcm::Tag(0xffff,0xffff); + const gdcm::Tag tag2 = (it2!=ds2.End()) ? it2->GetTag() : gdcm::Tag(0xffff,0xffff); + gdcm::Tag tag= (tag1GetLength(); + // error: operands to ?: have different types 'gdcm::VL' and 'uint32_t' + uint32_t val_vl = vl; + uint32_t trimto = (Truncate > val_vl ) ? val_vl : Truncate; + if (0 == Truncate) + { + trimto = de.GetByteValue()->GetLength(); + } + os << " [" << std::string(de.GetByteValue()->GetPointer(),trimto) << ']'; + } + else + { + os << " null"; + } + } + else + { + os << " VR unknown"; + } + os << " # " << dictentry.GetName() << std::endl ; +} + +static void underline(int depthSQ) +{ + std::cout << std::string(depthSQ, ' '); //indent for SQ + std::cout << " -------------" << std::endl; +} + +static void difference_of_sequences(const gdcm::DataElement& sqde1, + const gdcm::DataElement& sqde2, const gdcm::DictEntry& dictentry, int depthSQ) +{ + gdcm::SmartPointer sqi1 = sqde1.GetValueAsSQ(); + gdcm::SmartPointer sqi2 = sqde2.GetValueAsSQ(); + size_t n1 = sqi1->GetNumberOfItems(); + size_t n2 = sqi2->GetNumberOfItems(); + size_t n = (n1 < n2) ? n1 : n2 ; + std::stringstream sq_note; + if (n1 != n2) + { + sq_note << "[sequence, file 1 has " << n1 << " datasets, file 2 has " << n2 + << " datasets]"; + } + else + { + sq_note << "[sequence]"; + } + display_element(sq_disp, sqde1, dictentry, sq_note.str().c_str(),depthSQ); + for(size_t i=1; i <= n; i++) + { + difference_of_datasets( sqi1->GetItem(i).GetNestedDataSet(), + sqi2->GetItem(i).GetNestedDataSet(), depthSQ+1); + } + sq_disp.str(std::string()); // clear stringstream +} diff --git a/gdcm/Applications/Cxx/gdcmdump.cxx b/gdcm/Applications/Cxx/gdcmdump.cxx new file mode 100644 index 0000000..b29664c --- /dev/null +++ b/gdcm/Applications/Cxx/gdcmdump.cxx @@ -0,0 +1,1620 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + * Simple command line tool to dump the layout/values of a DICOM file + * This is largely inspired by other tools available from other toolkit, namely: + * - dcdump (dicom3tools) + * - dcmdump (dcmtk) + * - dcmInfo (SIEMENS) + * - PrintFile (GDCM 1.x) + * + * For now all layout are harcoded (see --color/--xml-dict for instance) + * + * gdcmdump has some feature not described in the DICOM standard: + * --csa : to print CSA information (dcmInfo.exe compatible) + * --pdb : to print PDB information (GEMS private info) + * --elscint : to print ELSCINT information (ELSCINT private info) + * + * + * TODO: it would be nice to have custom printing, namely printing as HTML/XML + * it would be nice to have runtime dict (instead of compile time) + */ + +#include "gdcmReader.h" +#include "gdcmVersion.h" +#include "gdcmFileMetaInformation.h" +#include "gdcmDataSet.h" +#include "gdcmPrivateTag.h" +#include "gdcmPrinter.h" +#include "gdcmDumper.h" +#include "gdcmDictPrinter.h" +#include "gdcmValidate.h" +#include "gdcmWriter.h" +#include "gdcmSystem.h" +#include "gdcmDirectory.h" +#include "gdcmCSAHeader.h" +#include "gdcmPDBHeader.h" +#include "gdcmSequenceOfItems.h" +#include "gdcmASN1.h" +#include "gdcmAttribute.h" + +#include +#include + +#include /* for printf */ +#include /* for exit */ +#include +#include + +static int color = 0; + +static int ignoreerrors = 0; + +namespace cleanup +{ +// {"1.3.46.670589.11.0.0.12.2" ,"Philips Private MR Series Data Storage"}, +enum { + TYPE_FLOAT = 0, // float + TYPE_INT32 = 1, // int32 + TYPE_STRING = 2, // 80 bytes string (+1) + TYPE_UINT32 = 4 // uint32 +}; + +template +static void printvaluet(std::istream & is, uint32_t numels) +{ + T buffer; + for( uint32_t i = 0; i < numels; ++i ) + { + if( i ) std::cout << "\\"; + is.read( (char*)&buffer, sizeof(T) ); + std::cout << buffer; + } +} + +static void printvalue(std::istream &is, uint32_t type, uint32_t numels, uint32_t pos) +{ + assert( numels > 0 ); + std::streampos start = is.tellg(); + is.seekg( pos ); + std::cout << "["; + typedef char (string81)[81]; // 80'th byte == 0 + assert( sizeof( string81 ) == 81 ); + switch( type ) + { + case TYPE_FLOAT: + printvaluet(is, numels); + break; + case TYPE_INT32: + printvaluet(is, numels); + break; + case TYPE_STRING: + printvaluet(is, numels); + break; + case TYPE_UINT32: + printvaluet(is, numels); + break; + default: + assert( 0 ); + } + std::cout << "]"; + std::cout << " # " << numels; + is.seekg( start ); +} + +struct PDFElement +{ + const char *getname() const { return name; } + uint32_t gettype() const { return getvalue(0); } + uint32_t getnumelems() const { return getvalue(1); } + uint32_t getdummy() const { return getvalue(2); } + uint32_t getoffset() const { return getvalue(3); } +private: + char name[50]; + // type , numel and offset needs to be read starting from the end + // the data in between name and those value can contains garbage stuff + uint32_t getvalue(int n) const { + uint32_t val = 0; + memcpy( (char*)&val, name + 50 - 16 + n * 4, sizeof( val ) ); + return val; + } +}; + +static void printbinary(std::istream &is, PDFElement const & pdfel ) +{ + const char *bufferref = pdfel.getname(); + std::cout << " " << bufferref << " "; + uint32_t type = pdfel.gettype(); + uint32_t numels = pdfel.getnumelems(); + uint32_t dummy = pdfel.getdummy(); + assert( dummy == 0 ); (void)dummy; + uint32_t offset = pdfel.getoffset(); + uint32_t pos = (uint32_t)(offset + is.tellg() - 4); + printvalue(is, type, numels, pos); +} + +static void ProcessSDSData( std::istream & is ) +{ + // havent been able to figure out what was the begin meant for + is.seekg( 0x20 - 8 ); + uint32_t version = 0; + is.read( (char*)&version, sizeof(version) ); + assert( version == 8 ); + uint32_t numel = 0; + is.read( (char*)&numel, sizeof(numel) ); + for( uint32_t el = 0; el < numel; ++el ) + { + PDFElement pdfel; + assert( sizeof(pdfel) == 50 ); + is.read( (char*)&pdfel, 50 ); + if( *pdfel.getname() ) + { + printbinary( is, pdfel ); + std::cout << std::endl; + } + } + +} +// PMS MR Series Data Storage +static int DumpPMS_MRSDS(const gdcm::DataSet & ds) +{ + const gdcm::PrivateTag tdata(0x2005,0x32,"Philips MR Imaging DD 002"); + if( !ds.FindDataElement( tdata ) ) return 1; + const gdcm::DataElement &data = ds.GetDataElement( tdata ); + gdcm::SmartPointer sqi = data.GetValueAsSQ(); + if( !sqi ) return 1; + std::cout << "PMS Dumping info from tag " << tdata << std::endl; + gdcm::SequenceOfItems::ConstIterator it = sqi->Begin(); + for( ; it != sqi->End(); ++it ) + { + const gdcm::Item & item = *it; + const gdcm::DataSet & nestedds = item.GetNestedDataSet(); + const gdcm::PrivateTag tprotocoldataname(0x2005,0x37,"Philips MR Imaging DD 002"); + const gdcm::DataElement & protocoldataname = nestedds.GetDataElement( tprotocoldataname ); + const gdcm::ByteValue *bv1 = protocoldataname.GetByteValue(); + const gdcm::PrivateTag tprotocoldatatype(0x2005,0x39,"Philips MR Imaging DD 002"); + const gdcm::DataElement & protocoldatatype = nestedds.GetDataElement( tprotocoldatatype ); + const gdcm::ByteValue *bv2 = protocoldatatype.GetByteValue(); + const gdcm::PrivateTag tprotocoldatablock(0x2005,0x44,"Philips MR Imaging DD 002"); + const gdcm::DataElement & protocoldatablock = nestedds.GetDataElement( tprotocoldatablock ); + const gdcm::ByteValue *bv3 = protocoldatablock.GetByteValue(); + const gdcm::PrivateTag tprotocoldatabool(0x2005,0x47,"Philips MR Imaging DD 002"); + const gdcm::DataElement & protocoldatabool = nestedds.GetDataElement( tprotocoldatabool ); + const gdcm::ByteValue *bv4 = protocoldatabool.GetByteValue(); + std::string s1; + if( bv1 ) + { + s1 = std::string( bv1->GetPointer(), bv1->GetLength() ); + } + std::string s2; + if( bv2 ) + { + s2 = std::string( bv2->GetPointer(), bv2->GetLength() ); + } + std::string s3; + if( bv3 ) + { + s3 = std::string( bv3->GetPointer(), bv3->GetLength() ); + } + std::string s4; + if( bv4 ) + { + s4 = std::string( bv4->GetPointer(), bv4->GetLength() ); + } + std::istringstream is( s3 ); + std::cout << "PMS/Item name: [" << s1 << "/" << s2 << "/" << s4 << "]" << std::endl; + ProcessSDSData( is ); + } + return 0; +} + +static int DumpTOSHIBA_MEC_CT3(const gdcm::DataSet & ds) +{ + const gdcm::PrivateTag tdata(0x7005,0x10,"TOSHIBA_MEC_CT3"); + if( !ds.FindDataElement( tdata ) ) return 1; + const gdcm::DataElement &data = ds.GetDataElement( tdata ); + + const gdcm::ByteValue *bv = data.GetByteValue(); + if( !bv ) return 1; + + const int offset = 24; + if( bv->GetLength() < offset ) + { + std::cerr << "Not enough header" << std::endl; + return 1; + } + std::istringstream is0; + const std::string str0 = std::string( bv->GetPointer(), offset ); + is0.str( str0 ); + gdcm::ImplicitDataElement ide0; + ide0.Read(is0); + gdcm::ImplicitDataElement ide1; + ide1.Read(is0); + + gdcm::Attribute<0x0,0x0> at0; + at0.SetFromDataElement( ide0 ); + if( at0.GetValue() != 12 ) + { + std::cerr << "Bogus header value #0" << std::endl; + return 1; + } + gdcm::Attribute<0x0,0x1> at1; + at1.SetFromDataElement( ide1 ); + + const unsigned int dlen = bv->GetLength() - offset; + if( at1.GetValue() != dlen ) + { + std::cerr << "Bogus header value #1" << std::endl; + return 1; + } + std::istringstream is1; + const std::string str1 = std::string( bv->GetPointer() + offset, bv->GetLength() - offset); + is1.str( str1 ); + + gdcm::Reader r; + r.SetStream( is1 ); + if( !r.Read() ) + { + std::cerr << "Could not read CT Private Data 2" << std::endl; + return 1; + } + + gdcm::Printer printer; + printer.SetFile ( r.GetFile() ); + printer.SetColor( color != 0 ); + printer.Print( std::cout ); + + return 0; +} + +// VEPRO +/* +[VIMDATA2] +PrivateCreator = VEPRO VIM 5.0 DATA +Group = 0x0055 +Element = 0x0020 +Data.ID = C|0|3 +Data.Version = C|3|3 +Data.UserName = C|6|32 +Data.UserAdress1 = C|38|32 +Data.UserAdress2 = C|70|32 +Data.UserAdress3 = C|102|32 +Data.UserAdress4 = C|134|32 +Data.UserAdress5 = C|166|32 +Data.RecDate = C|198|8 +Data.RecTime = C|206|6 +Data.RecPlace = C|212|64 +Data.RecSource = C|276|64 +Data.DF1 = C|340|64 +Data.DF2 = C|404|64 +Data.DF3 = C|468|64 +Data.DF4 = C|532|64 +Data.DF5 = C|596|64 +Data.DF6 = C|660|64 +Data.DF7 = C|724|64 +Data.DF8 = C|788|64 +Data.DF9 = C|852|64 +Data.DF10 = C|916|64 +Data.DF11 = C|980|64 +Data.DF12 = C|1044|64 +Data.DF13 = C|1108|64 +Data.DF14 = C|1172|64 +Data.DF15 = C|1236|64 +Data.DF16 = C|1300|64 +Data.DF17 = C|1364|64 +Data.DF18 = C|1428|64 +Data.DF19 = C|1492|64 +Data.DF20 = C|1556|64 +Data.StudyUID = C|1642|64 +Data.SeriesUID = C|1706|64 +Data.Modality = C|1770|16 +*/ +// TYPE[C/I] / OFFSET / LENGTH (in bytes) +struct Data2 +{ + char ID[3]; // Data.ID = C|0|3 + char Version[3]; // Data.Version = C|3|3 + char UserName[32]; // Data.UserName = C|6|32 + char UserAdress1[32]; // Data.UserAdress1 = C|38|32 + char UserAdress2[32]; // Data.UserAdress2 = C|70|32 + char UserAdress3[32]; // Data.UserAdress3 = C|102|32 + char UserAdress4[32]; // Data.UserAdress4 = C|134|32 + char UserAdress5[32]; // Data.UserAdress5 = C|166|32 + char RecDate[8]; // Data.RecDate = C|198|8 + char RecTime[6]; // Data.RecTime = C|206|6 + char RecPlace[64]; // Data.RecPlace = C|212|64 + char RecSource[64];// Data.RecSource = C|276|64 + char DF1[64]; // Data.DF1 = C|340|64 + char DF2[64]; // Data.DF2 = C|404|64 + char DF3[64]; // Data.DF3 = C|468|64 + char DF4[64]; // Data.DF4 = C|532|64 + char DF5[64]; // Data.DF5 = C|596|64 + char DF6[64]; // Data.DF6 = C|660|64 + char DF7[64]; // Data.DF7 = C|724|64 + char DF8[64]; // Data.DF8 = C|788|64 + char DF9[64]; // Data.DF9 = C|852|64 + char DF10[64]; // Data.DF10 = C|916|64 + char DF11[64]; // Data.DF11 = C|980|64 + char DF12[64]; // Data.DF12 = C|1044|64 + char DF13[64]; // Data.DF13 = C|1108|64 + char DF14[64]; // Data.DF14 = C|1172|64 + char DF15[64]; // Data.DF15 = C|1236|64 + char DF16[64]; // Data.DF16 = C|1300|64 + char DF17[64]; // Data.DF17 = C|1364|64 + char DF18[64]; // Data.DF18 = C|1428|64 + char DF19[64]; // Data.DF19 = C|1492|64 + char DF20[64]; // Data.DF20 = C|1556|64 + char Padding[22]; // ????? + char StudyUID[64]; // Data.StudyUID = C|1642|64 + char SeriesUID[64]; // Data.SeriesUID = C|1706|64 + char Modality[16]; // Data.Modality = C|1770|16 + + void Print( std::ostream &os ) + { + os << " ID: " << std::string(ID,3) << "\n"; + os << " Version: " << std::string(Version,3) << "\n"; + os << " UserName: " << std::string(UserName,32) << "\n"; + os << " UserAdress1: " << std::string(UserAdress1,32) << "\n"; + os << " UserAdress2: " << std::string(UserAdress2,32) << "\n"; + os << " UserAdress3: " << std::string(UserAdress3,32) << "\n"; + os << " UserAdress4: " << std::string(UserAdress4,32) << "\n"; + os << " UserAdress5: " << std::string(UserAdress5,32) << "\n"; + os << " RecDate: " << std::string(RecDate,8) << "\n"; + os << " RecTime: " << std::string(RecTime,64) << "\n"; + os << " RecPlace: " << std::string(RecPlace,64) << "\n"; + os << " RecSource: " << std::string(RecSource,64) << "\n"; + os << " DF1: " << std::string(DF1,64) << "\n"; + os << " DF2: " << std::string(DF2,64) << "\n"; + os << " DF3: " << std::string(DF3,64) << "\n"; + os << " DF4: " << std::string(DF4,64) << "\n"; + os << " DF5: " << std::string(DF5,64) << "\n"; + os << " DF6: " << std::string(DF6,64) << "\n"; + os << " DF7: " << std::string(DF7,64) << "\n"; + os << " DF8: " << std::string(DF8,64) << "\n"; + os << " DF9: " << std::string(DF9,64) << "\n"; + os << " DF10: " << std::string(DF10,64) << "\n"; + os << " DF11: " << std::string(DF11,64) << "\n"; + os << " DF12: " << std::string(DF12,64) << "\n"; + os << " DF13: " << std::string(DF13,64) << "\n"; + os << " DF14: " << std::string(DF14,64) << "\n"; + os << " DF15: " << std::string(DF15,64) << "\n"; + os << " DF16: " << std::string(DF16,64) << "\n"; + os << " DF17: " << std::string(DF17,64) << "\n"; + os << " DF18: " << std::string(DF18,64) << "\n"; + os << " DF19: " << std::string(DF19,64) << "\n"; + os << " DF20: " << std::string(DF20,64) << "\n"; + //os << " Padding: " << std::string(Padding,22) << "\n"; + os << " StudyUID: " << std::string(StudyUID,64) << "\n"; + os << " SeriesUID: " << std::string(SeriesUID,64) << "\n"; + os << " Modality: " << std::string(Modality,16) << "\n"; + } +}; + +static bool ProcessData( const char *buf, size_t len ) +{ + Data2 data2; + const size_t s = sizeof(data2); + assert( len >= s); (void)len; + // VIMDATA2 is generally 2048 bytes, while s = 1786 + // the end is filled with \0 bytes + memcpy(&data2, buf, s); + + data2.Print( std::cout ); + return true; +} + +static int DumpVEPRO(const gdcm::DataSet & ds) +{ + // 01f7,1026 + const gdcm::ByteValue *bv2 = NULL; + const gdcm::PrivateTag tdata1(0x55,0x0020,"VEPRO VIF 3.0 DATA"); + const gdcm::PrivateTag tdata2(0x55,0x0020,"VEPRO VIM 5.0 DATA"); + // Prefer VIF over VIM ? + if( ds.FindDataElement( tdata1 ) ) + { + std::cout << "VIF DATA: " << tdata1 << "\n"; + const gdcm::DataElement &data = ds.GetDataElement( tdata1 ); + bv2 = data.GetByteValue(); + } + else if( ds.FindDataElement( tdata2 ) ) + { + std::cout << "VIMDATA2: " << tdata2 << "\n"; + const gdcm::DataElement &data = ds.GetDataElement( tdata2 ); + bv2 = data.GetByteValue(); + } + + if( bv2 ) + { + ProcessData( bv2->GetPointer(), bv2->GetLength() ); + return 0; + } + + return 1; +} + +// ELSCINT1 +static bool readastring(std::string &out, const char *input ) +{ + out.clear(); + while( *input ) + { + out.push_back( *input++ ); + } + return true; +} + +struct el +{ + std::string name; + uint32_t pad; + std::vector values; + size_t Size() const + { + size_t s = 0; + s += name.size() + 1; + s += sizeof(pad); + for( std::vector::const_iterator it = values.begin(); it != values.end(); ++it ) + s += it->size() + 1; + return s; + } + void ReadFromString( const char * input ) + { + readastring( name, input ); + const char *p = input + 1+ name.size(); + memcpy( &pad, p, sizeof( pad ) ); + //assert( pad == 1 || pad == 2 || pad == 3 || pad == 6 ); + values.resize( pad ); + const char *pp = p + sizeof(uint32_t); + for( uint32_t pidx = 0; pidx < pad; ++pidx ) + { + readastring( values[pidx], pp ); + pp = pp + values[pidx].size() + 1; + } + } + void Print() const + { + //std::cout << " " << name << " : " << pad << " : ("; + std::cout << " " << name << " ["; + { + std::vector::const_iterator it = values.begin(); + std::cout << *it++; + for(; it != values.end(); ++it ) + { + std::cout << "\\"; + std::cout << *it; + } + } + std::cout << "]" << std::endl; + } +}; + + +struct info +{ + size_t Read(const char *in ) + { + const char *m = in; + uint32_t h; + memcpy( &h, in, sizeof(h) ); + in += sizeof(h); + std::string dummy; + readastring( dummy, in ); + in += dummy.size(); + in += 1; + if( h == 432154 ) // 0x6981a + { + // Single item + uint32_t nels; + memcpy( &nels, in, sizeof(nels) ); + in += sizeof(nels); + //std::cout << " ELSCINT1/Item name: " << dummy << " : " << nels << std::endl; + std::cout << "ELSCINT1/Item name: [" << dummy << "]" << std::endl; + for( uint32_t i = 0; i < nels; ++i ) + { + el e; + e.ReadFromString( in ); + e.Print(); + in += e.Size(); + } + } + else if( h == 2341 ) // 0x925 + { + // Multiple Item(s) + uint32_t d; + memcpy( &d, in, sizeof(d) ); + in += sizeof(d); + //std::cout << " Info Name: " << dummy << " : " << d << std::endl; + std::cout << "ELSCINT1/Item name: " << dummy << std::endl; + for( uint32_t dix = 0; dix < d; ++dix ) + { + uint32_t fixme; + memcpy( &fixme, in, sizeof(fixme) ); + in += 4; // + //std::cout << " number of Subitems " << fixme << std::endl; + uint32_t nels = fixme; + if( nels ) + std::cout << " SubItems #" << dix << std::endl; + else + std::cout << " No SubItems (Empty)" << std::endl; + for( uint32_t i = 0; i < nels; ++i ) + { + el e; + e.ReadFromString( in ); + e.Print(); + in += e.Size(); + } + } + // postcondition + uint32_t fixme; + memcpy( &fixme, in, sizeof(fixme) ); + assert( fixme == 0x0006981A ); + } + else + { + assert( 0 ); + } + return in - m; + } +}; + +static int DumpEl2_new(const gdcm::DataSet & ds) +{ + // 01f7,1026 + const gdcm::PrivateTag t01f7_26(0x01f7,0x1026,"ELSCINT1"); + if( !ds.FindDataElement( t01f7_26 ) ) return 1; + const gdcm::DataElement& de01f7_26 = ds.GetDataElement( t01f7_26 ); + if ( de01f7_26.IsEmpty() ) return 1; + const gdcm::ByteValue * bv = de01f7_26.GetByteValue(); + + const char *begin = bv->GetPointer(); + uint32_t val0[3]; + memcpy( &val0, begin, sizeof( val0 ) ); + assert( val0[0] == 0xF22D ); + begin += sizeof( val0 ); + + // 1A 98 06 00 -> start element + // Next is a string (can be NULL) + // then number of (nested) elements + + std::cout << "ELSCINT1 Dumping info from tag " << t01f7_26 << std::endl; + info i; + size_t o; + assert( val0[1] == 0x1 ); + for( uint32_t idx = 0; idx < val0[2]; ++idx ) + { + o = i.Read( begin ); + std::cout << std::endl; + begin += o; + } + + return 0; +} + +} // end namespace cleanup + +template +static int DoOperation(const std::string & filename) +{ + gdcm::Reader reader; + reader.SetFileName( filename.c_str() ); + bool success = reader.Read(); + if( !success && !ignoreerrors ) + { + std::cerr << "Failed to read: " << filename << std::endl; + return 1; + } + + TPrinter printer; + printer.SetFile ( reader.GetFile() ); + printer.SetColor( color != 0); + printer.Print( std::cout ); + + // Only return success when file read succeeded not depending whether or not we printed it + return success ? 0 : 1; +} + +static int PrintASN1(const std::string & filename, bool verbose) +{ + (void)verbose; + gdcm::Reader reader; + reader.SetFileName( filename.c_str() ); + if( !reader.Read() ) + { + std::cerr << "Failed to read: " << filename << std::endl; + return 1; + } + const gdcm::DataSet& ds = reader.GetFile().GetDataSet(); + gdcm::Tag tencryptedattributessequence(0x0400,0x0500); + if( !ds.FindDataElement( tencryptedattributessequence ) ) + { + return 1; + } + const gdcm::DataElement &encryptedattributessequence = ds.GetDataElement( tencryptedattributessequence ); + //const gdcm::SequenceOfItems * sqi = encryptedattributessequence.GetSequenceOfItems(); + gdcm::SmartPointer sqi = encryptedattributessequence.GetValueAsSQ(); + if( !sqi->GetNumberOfItems() ) + { + return 1; + } + const gdcm::Item &item1 = sqi->GetItem(1); + const gdcm::DataSet &subds = item1.GetNestedDataSet(); + + gdcm::Tag tencryptedcontent(0x0400,0x0520); + if( !subds.FindDataElement( tencryptedcontent) ) + { + return 1; + } + const gdcm::DataElement &encryptedcontent = subds.GetDataElement( tencryptedcontent ); + const gdcm::ByteValue *bv = encryptedcontent.GetByteValue(); + + bool b = gdcm::ASN1::ParseDump( bv->GetPointer(), bv->GetLength() ); + if( !b ) return 1; + return 0; +} + +static int PrintELSCINT(const std::string & filename, bool verbose) +{ + (void)verbose; + gdcm::Reader reader; + reader.SetFileName( filename.c_str() ); + if( !reader.Read() ) + { + std::cerr << "Failed to read: " << filename << std::endl; + return 1; + } + + const gdcm::DataSet& ds = reader.GetFile().GetDataSet(); + int ret = cleanup::DumpEl2_new( ds ); + + return ret; +} + +static int PrintVEPRO(const std::string & filename, bool verbose) +{ + (void)verbose; + gdcm::Reader reader; + reader.SetFileName( filename.c_str() ); + if( !reader.Read() ) + { + std::cerr << "Failed to read: " << filename << std::endl; + return 1; + } + + const gdcm::DataSet& ds = reader.GetFile().GetDataSet(); + int ret = cleanup::DumpVEPRO( ds ); + + return ret; +} + +static int PrintSDS(const std::string & filename, bool verbose) +{ + (void)verbose; + gdcm::Reader reader; + reader.SetFileName( filename.c_str() ); + if( !reader.Read() ) + { + std::cerr << "Failed to read: " << filename << std::endl; + return 1; + } + + const gdcm::DataSet& ds = reader.GetFile().GetDataSet(); + int ret = cleanup::DumpPMS_MRSDS( ds ); + + return ret; +} + +static int PrintCT3(const std::string & filename, bool verbose) +{ + (void)verbose; + gdcm::Reader reader; + reader.SetFileName( filename.c_str() ); + if( !reader.Read() ) + { + std::cerr << "Failed to read: " << filename << std::endl; + return 1; + } + + const gdcm::DataSet& ds = reader.GetFile().GetDataSet(); + int ret = cleanup::DumpTOSHIBA_MEC_CT3( ds ); + + return ret; +} + +static int PrintPDB(const std::string & filename, bool verbose) +{ + (void)verbose; + gdcm::Reader reader; + reader.SetFileName( filename.c_str() ); + if( !reader.Read() ) + { + std::cerr << "Failed to read: " << filename << std::endl; + return 1; + } + + gdcm::PDBHeader pdb; + const gdcm::DataSet& ds = reader.GetFile().GetDataSet(); + + const gdcm::PrivateTag &t1 = pdb.GetPDBInfoTag(); + + bool found = false; + int ret = 0; + if( ds.FindDataElement( t1 ) ) + { + pdb.LoadFromDataElement( ds.GetDataElement( t1 ) ); + pdb.Print( std::cout ); + found = true; + } + if( !found ) + { + std::cout << "no pdb tag found" << std::endl; + ret = 1; + } + + return ret; +} + +static int PrintCSA(const std::string & filename) +{ + gdcm::Reader reader; + reader.SetFileName( filename.c_str() ); + if( !reader.Read() ) + { + std::cerr << "Failed to read: " << filename << std::endl; + return 1; + } + + gdcm::CSAHeader csa; + const gdcm::DataSet& ds = reader.GetFile().GetDataSet(); + + const gdcm::PrivateTag &t1 = csa.GetCSAImageHeaderInfoTag(); + const gdcm::PrivateTag &t2 = csa.GetCSASeriesHeaderInfoTag(); + const gdcm::PrivateTag &t3 = csa.GetCSADataInfo(); + + bool found = false; + int ret = 0; + if( ds.FindDataElement( t1 ) ) + { + csa.LoadFromDataElement( ds.GetDataElement( t1 ) ); + csa.Print( std::cout ); + found = true; + if( csa.GetFormat() == gdcm::CSAHeader::ZEROED_OUT ) + { + std::cout << "CSA Header has been zero-out (contains only 0)" << std::endl; + ret = 1; + } + else if( csa.GetFormat() == gdcm::CSAHeader::DATASET_FORMAT ) + { + gdcm::Printer p; + gdcm::File f; + f.SetDataSet( csa.GetDataSet() ); + p.SetFile( f ); + p.Print( std::cout ); + } + } + if( ds.FindDataElement( t2 ) ) + { + csa.LoadFromDataElement( ds.GetDataElement( t2 ) ); + csa.Print( std::cout ); + found = true; + if( csa.GetFormat() == gdcm::CSAHeader::ZEROED_OUT ) + { + std::cout << "CSA Header has been zero-out (contains only 0)" << std::endl; + ret = 1; + } + else if( csa.GetFormat() == gdcm::CSAHeader::DATASET_FORMAT ) + { + gdcm::Printer p; + gdcm::File f; + f.SetDataSet( csa.GetDataSet() ); + p.SetFile( f ); + p.Print( std::cout ); + } + } + if( ds.FindDataElement( t3 ) ) + { + csa.LoadFromDataElement( ds.GetDataElement( t3 ) ); + csa.Print( std::cout ); + found = true; + if( csa.GetFormat() == gdcm::CSAHeader::ZEROED_OUT ) + { + std::cout << "CSA Header has been zero-out (contains only 0)" << std::endl; + ret = 1; + } + else if( csa.GetFormat() == gdcm::CSAHeader::INTERFILE ) + { + const char *interfile = csa.GetInterfile(); + if( interfile ) std::cout << interfile << std::endl; + } + else if( csa.GetFormat() == gdcm::CSAHeader::DATASET_FORMAT ) + { + gdcm::Printer p; + gdcm::File f; + f.SetDataSet( csa.GetDataSet() ); + p.SetFile( f ); + p.Print( std::cout ); + } + } + if( !found ) + { + std::cout << "no csa tag found" << std::endl; + ret = 1; + } + + return ret; +} + + + +static void PrintVersion() +{ + std::cout << "gdcmdump: gdcm " << gdcm::Version::GetVersion() << " "; + const char date[] = "$Date$"; + std::cout << date << std::endl; +} + +static void PrintHelp() +{ + PrintVersion(); + std::cout << "Usage: gdcmdump [OPTION]... FILE..." << std::endl; + std::cout << "dumps a DICOM file, it will display the structure and values contained in the specified DICOM file\n"; + std::cout << "Parameter (required):" << std::endl; + std::cout << " -i --input DICOM filename or directory" << std::endl; + std::cout << "Options:" << std::endl; + std::cout << " -x --xml-dict generate the XML dict (only private elements for now)." << std::endl; + std::cout << " -r --recursive recursive." << std::endl; + std::cout << " -d --dump dump value (limited use)." << std::endl; + std::cout << " -p --print print value instead of simply dumping (default)." << std::endl; + std::cout << " -c --color print in color." << std::endl; + std::cout << " -C --csa print SIEMENS CSA Header (0029,[12]0,SIEMENS CSA HEADER)." << std::endl; + std::cout << " -P --pdb print GEMS Protocol Data Block (0025,1b,GEMS_SERS_01)." << std::endl; + std::cout << " --elscint print ELSCINT Protocol Information (01f7,26,ELSCINT1)." << std::endl; + std::cout << " --vepro print VEPRO Protocol Information (0055,20,VEPRO VIF 3.0 DATA)." << std::endl; + std::cout << " or VEPRO Protocol Information (0055,20,VEPRO VIM 5.0 DATA)." << std::endl; + std::cout << " --sds print Philips MR Series Data Storage (1.3.46.670589.11.0.0.12.2) Information (2005,32,Philips MR Imaging DD 002)." << std::endl; + std::cout << " --ct3 print CT Private Data 2 (7005,10,TOSHIBA_MEC_CT3)." << std::endl; + std::cout << " -A --asn1 print encapsulated ASN1 structure >(0400,0520)." << std::endl; + std::cout << " --map-uid-names map UID to names." << std::endl; + std::cout << "General Options:" << std::endl; + std::cout << " -V --verbose more verbose (warning+error)." << std::endl; + std::cout << " -W --warning print warning info." << std::endl; + std::cout << " -D --debug print debug info." << std::endl; + std::cout << " -E --error print error info." << std::endl; + std::cout << " -h --help print help." << std::endl; + std::cout << " -v --version print version." << std::endl; + std::cout << "Special Options:" << std::endl; + std::cout << " -I --ignore-errors print even if file is corrupted." << std::endl; +} + +int main (int argc, char *argv[]) +{ + int c; + //int digit_optind = 0; + + std::string filename; + int printdict = 0; + int dump = 0; + int print = 0; + int printcsa = 0; + int printpdb = 0; + int printelscint = 0; + int printvepro = 0; + int printsds = 0; // MR Series Data Storage + int printct3 = 0; // TOSHIBA_MEC_CT3 + int verbose = 0; + int warning = 0; + int debug = 0; + int error = 0; + int help = 0; + int version = 0; + int recursive = 0; + int printasn1 = 0; + int mapuidnames = 0; + while (1) { + //int this_option_optind = optind ? optind : 1; + int option_index = 0; +/* + struct option { + const char *name; + int has_arg; + int *flag; + int val; + }; +*/ + static struct option long_options[] = { + {"input", 1, 0, 0}, + {"xml-dict", 0, &printdict, 1}, + {"recursive", 0, &recursive, 1}, + {"print", 0, &print, 1}, + {"dump", 0, &dump, 1}, + {"color", 0, &color, 1}, + {"csa", 0, &printcsa, 1}, + {"pdb", 0, &printpdb, 1}, + {"verbose", 0, &verbose, 1}, + {"warning", 0, &warning, 1}, + {"debug", 0, &debug, 1}, + {"error", 0, &error, 1}, + {"help", 0, &help, 1}, + {"version", 0, &version, 1}, + {"ignore-errors", 0, &ignoreerrors, 1}, + {"asn1", 0, &printasn1, 1}, + {"map-uid-names", 0, &mapuidnames, 1}, + {"elscint", 0, &printelscint, 1}, + {"vepro", 0, &printvepro, 1}, + {"sds", 0, &printsds, 1}, + {"ct3", 0, &printct3, 1}, + {0, 0, 0, 0} // required + }; + static const char short_options[] = "i:xrpdcCPAVWDEhvI"; + c = getopt_long (argc, argv, short_options, + long_options, &option_index); + if (c == -1) + { + break; + } + + switch (c) + { + case 0: + case '-': + { + const char *s = long_options[option_index].name; (void)s; + //printf ("option %s", s); + if (optarg) + { + if( option_index == 0 ) /* input */ + { + assert( strcmp(s, "input") == 0 ); + assert( filename.empty() ); + filename = optarg; + } + //printf (" with arg %s", optarg); + } + //printf ("\n"); + } + break; + + case 'i': + //printf ("option i with value '%s'\n", optarg); + assert( filename.empty() ); + filename = optarg; + break; + + case 'x': + //printf ("option d with value '%s'\n", optarg); + printdict = 1; + break; + + case 'r': + recursive = 1; + break; + + case 'p': + //printf ("option p with value '%s'\n", optarg); + print = 1; + break; + + case 'd': + dump = 1; + break; + + case 'c': + color = 1; + break; + + case 'C': + printcsa = 1; + break; + + case 'A': + printasn1 = 1; + break; + + case 'P': + printpdb = 1; + break; + + case 'V': + verbose = 1; + break; + + case 'W': + warning = 1; + break; + + case 'D': + debug = 1; + break; + + case 'E': + error = 1; + break; + + case 'h': + help = 1; + break; + + case 'v': + version = 1; + break; + + case 'I': + ignoreerrors = 1; + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + //printf ("non-option ARGV-elements: %d", optind ); + //while (optind < argc) + // { + // printf ("%s\n", argv[optind++]); + // } + //printf ("\n"); + // Ok there is only one arg, easy, it's the filename: + int v = argc - optind; + if( v == 1 ) + { + filename = argv[optind]; + } + } + + // + //gdcm::System::SetArgv0( argv[0] ); + + if( version ) + { + //std::cout << "version" << std::endl; + PrintVersion(); + return 0; + } + + if( help ) + { + //std::cout << "help" << std::endl; + PrintHelp(); + return 0; + } + + // check if d or p are passed, only one at a time + if( print || printdict ) + { + if ( print && printdict ) + { + std::cerr << "d or p" << std::endl; + return 1; + } + } + if( filename.empty() ) + { + //std::cerr << "Need input file (-i)\n"; + PrintHelp(); + return 1; + } + // Debug is a little too verbose + gdcm::Trace::SetDebug( debug != 0); + gdcm::Trace::SetWarning( warning != 0); + gdcm::Trace::SetError( error != 0); + // when verbose is true, make sure warning+error are turned on: + if( verbose ) + { + gdcm::Trace::SetWarning( verbose != 0); + gdcm::Trace::SetError( verbose!= 0); + } + + if( mapuidnames ) + { + std::cerr << "Not handled for now" << std::endl; + } + + // else + int res = 0; + if( !gdcm::System::FileExists(filename.c_str()) ) + { + std::cerr << "no such file: " << filename << std::endl; + return 1; + } + else if( gdcm::System::FileIsDirectory( filename.c_str() ) ) + { + gdcm::Directory d; + d.Load(filename, recursive!= 0); + gdcm::Directory::FilenamesType const &filenames = d.GetFilenames(); + for( gdcm::Directory::FilenamesType::const_iterator it = filenames.begin(); it != filenames.end(); ++it ) + { + if( printdict ) + { + res += DoOperation(*it); + } + else if( printasn1 ) + { + res += PrintASN1(*it, verbose!= 0); + } + else if( printvepro ) + { + res += PrintVEPRO(*it, verbose!= 0); + } + else if( printsds ) + { + res += PrintSDS(*it, verbose!= 0); + } + else if( printct3 ) + { + res += PrintCT3(*it, verbose!= 0); + } + else if( printelscint ) + { + res += PrintELSCINT(*it, verbose!= 0); + } + else if( printpdb ) + { + res += PrintPDB(*it, verbose!= 0); + } + else if( printcsa ) + { + res += PrintCSA(*it); + } + else if( dump ) + { + res += DoOperation(*it); + } + else + { + res += DoOperation(*it); + } + if( verbose ) std::cerr << *it << std::endl; + } + if( verbose ) std::cerr << "Total: " << filenames.size() << " files were processed" << std::endl; + } + else + { + assert( gdcm::System::FileExists(filename.c_str()) ); + if( printdict ) + { + res += DoOperation(filename); + } + else if( printasn1 ) + { + res += PrintASN1(filename, verbose!= 0); + } + else if( printvepro ) + { + res += PrintVEPRO(filename, verbose!= 0); + } + else if( printsds ) + { + res += PrintSDS(filename, verbose!= 0); + } + else if( printct3 ) + { + res += PrintCT3(filename, verbose!= 0); + } + else if( printelscint ) + { + res += PrintELSCINT(filename, verbose!= 0); + } + else if( printpdb ) + { + res += PrintPDB(filename, verbose!= 0); + } + else if( printcsa ) + { + res += PrintCSA(filename); + } + else if( dump ) + { + res += DoOperation(filename); + } + else + { + res += DoOperation(filename); + } + // ... + if ( verbose ) + std::cerr << "Filename: " << filename << std::endl; + } + + return res; +} + +/* + * Harvested data: + * A lot of them are still non-obvious + +Most obvious ones: +ETL -> Echo Train Length +FLIPANG -> Flip Angle +MATRIXX / MATRIXY -> Acquisition Matrix +SLTHICK -> Slice Thickness + + ENTRY "Feet First" ++ POSITION "Supine" +-------------------- += Patient Position + + +Full list: + +ANREF "IC" +ANREF "NA" +ANREF "SN" +AUTOCF "Water" +AUTOSCIC "0" +AUTOSCIC "2" +AUTOSHIM "Auto" +AUTOSHIM "Off" +AUTOSHIM "Yes" +AUTOSUBOPTIONS "0" +AUTOTRGTYPE "0" +AUTOTRIGWIN "0" +AUTOVOICE "0" +B4PAUSE "0" +BPMMODE "0" +BWRT "0" +BWRT "-1" +CLOC1 "0.0" +CLOC1 "L4.7" +CLOC1 "L5.9" +CLOC2 "0.0" +CLOC2 "P20.0" +CLOC2 "P42.2" +CLOC2 "P44.5" +CLOC3 "0.0" +CLOC3 "S7.0" +CLOC3 "S8.2" +COIL "5GP" +COIL "8HRBRAIN" +COIL "HEAD" +COIL "LOOP2CM" +CONTAG "GAD" +CONTAM "10 GAD" +CONTAM "No " +CONTAM "Yes " +CONTRAST "No" +CONTRAST "Yes" +DELACQ "Minimum" +DUMACQ "0" +ELOC1 "L12.4" +ELOC1 "L142.9" +ELOC1 "L1.6" +ELOC1 "L2.2" +ELOC1 "L4.9" +ELOC1 "L5.9" +ELOC1 "L80.1" +ELOC1 "L84.1" +ELOC1 "L99.3" +ELOC1 "S65.4" +ELOC1 "S66.5" +ELOC1 "S89.0" +ELOC2 "0.0" +ELOC2 "A18.3" +ELOC2 "A43.5" +ELOC2 "A79.2" +ELOC2 "A87.6" +ELOC2 "L6.9" +ELOC2 "P27.4" +ELOC2 "P38.8" +ELOC2 "P48.8" +ELOC2 "P49.4" +ELOC3 "A12.8" +ELOC3 "I111.9" +ELOC3 "I27.7" +ELOC3 "I7.1" +ELOC3 "P21.2" +ELOC3 "P31.1" +ELOC3 "S12.3" +ELOC3 "S1.7" +ELOC3 "S31.8" +ELOC3 "S5.4" +ELOC3 "S7.0" +ELOC3 "S9.8" +ENTRY "Head First" +ETL "17" +ETL "2" +ETL "24" +ETL "3" +ETL "6" +ETL "8" +ETL "9" +FILTCHOICE "None" +FLDIR "Slice" +FLIPANG "12" +FLIPANG "17" +FLIPANG "20" +FLIPANG "36" +FLIPANG "8" +FLIPANG "90" +FOV "12" +FOV "14" +FOV "24" +FOV "24.0" +FOV "3" +FOV "30" +FOV "4" +FOV "6" +FOV "8" +FOVCNT1 "0.0" +FOVCNT2 "0.0" +FOVCNT2 "P21.2" +FOVCNT2 "P31.1" +GRADMODE "WHOLE" +GRADMODE "ZOOM" +GRIP_NUMPSCVOL "0" +GRIP_NUMSLGROUPS "0" +GRIP_NUMSLGROUPS "1" +GRIP_PSCVOL1 "0" +GRIP_PSCVOL2 "0" +GRIP_PSCVOLFOV "0" +GRIP_PSCVOLFOV "0.000000" +GRIP_PSCVOLTHICK "0" +GRIP_PSCVOLTHICK "0.000000" +GRIP_SATGROUP1 "0" +GRIP_SATGROUP2 "0" +GRIP_SATGROUP3 "0" +GRIP_SATGROUP4 "0" +GRIP_SATGROUP5 "0" +GRIP_SATGROUP6 "0" +GRIP_SLGROUP1 "0.000000 -21.170785 -13.463666 0.000000 0.000000 1.000000 1.000000 0.000000 0.000000 0.000000 -1.000000 0.000000 1 0.000000 1 0" +GRIP_SLGROUP1 "0.000000 -31.122005 2.926577 0.000000 0.000000 1.000000 0.000000 1.000000 0.000000 1.000000 0.000000 0.000000 26 0.000000 1 0" +GRIP_SLGROUP1 "-13.163267 0.000000 25.592358 0.005670 0.000000 -0.999984 0.999984 0.000000 0.005670 0.000000 -1.000000 0.000000 56 0.000000 1 0 1" +GRIP_SLGROUP1 "3.135807 14.667716 -32.340976 -0.997518 0.043626 0.055276 -0.056814 -0.962372 -0.265728 0.041603 -0.268209 0.962462 1 0.000000 1 0 1" +GRIP_SPECTRO "0" +GRIP_TRACKER "0" +GRXOPT "0" +GRXOPT "2" +IEC_ACCEPT "ON" +IMODE "2D" +IMODE "3D" +INITSTATE "0" +IOPT "EDR, Fast, IrP" +IOPT "EPI, FMRI" +IOPT "Fast, IrP" +IOPT "Fast, ZIP512, FR" +IOPT "FC, EDR, TRF, Fast, ZIP512" +IOPT "FC, VBw, EDR" +IOPT "None" +IOPT "NPW, Seq, VBw, TRF, Fast" +IOPT "NPW, TRF, Fast, ZIP512, FR" +IOPT "NPW, VBw, EDR, Fast, ZIP2" +IOPT "NPW, VBw, Fast" +IOPT "NPW, ZIP512" +IOPT "TRF, Fast" +IOPT "VBw, EDR, Fast" +IOPT "VBw, Fast" +MASKPAUSE "0" +MASKPHASE "0" +MATRIXX "192" +MATRIXX "256" +MATRIXX "288" +MATRIXX "320" +MATRIXX "416" +MATRIXX "512" +MATRIXX "64" +MATRIXY "128" +MATRIXY "160" +MATRIXY "192" +MATRIXY "224" +MATRIXY "256" +MATRIXY "320" +MATRIXY "64" +MONSAR "y" +NECHO "1" +NEX "1.00" +NEX "1.50" +NEX "2.00" +NEX "3.00" +NEX "4.00" +NOSLC "1" +NOSLC "12" +NOSLC "15" +NOSLC "19" +NOSLC "20" +NOSLC "21" +NOSLC "24" +NOSLC "26" +NOSLC "56" +NOTES ".pn/_2" +NOTES ".pn/_3" +NOTES ".pn/_4" +NUMACCELFACTOR "1.00" +NUMACCELFACTOR "Recommended" +NUMACQS "0" +NUMACQS "2" +NUMSHOTS "1" +OVLPLOC "0" +PAUSEDELMASKACQ "1" +PDGMSTR "None" +PHASEASSET "1.00" +PHASECORR "No" +PHASECORR "Yes" +PHASEFOV "0.75" +PHASEFOV "1.00" +PLANE "3-PLANE" +PLANE "AXIAL" +PLANE "OBLIQUE" +PLUG "0" +PLUG "11" +PLUG "14" +PLUG "22" +PLUG "23" +PLUG "45" +PLUG "5" +PLUG "6" +PLUG "9" +POSITION "Prone" +POSITION "Supine" +PRESETDELAY "0.0" +PSDNAME "fse-xl" +PSDTRIG "0" +PSEQ "FRFSE-XL" +PSEQ "FSE-XL" +PSEQ "Gradient Echo" +PSEQ "IR" +PSEQ "Localizer" +PSEQ "SPGR" +PSEQ "Spin Echo" +RBW "12.50" +RBW "14.71" +RBW "15.63" +RBW "17.86" +RBW "20.83" +RBW "22.73" +RBW "25.00" +RBW "31.25" +SATLOCZ1 "9990" +SATLOCZ2 "9990" +SATTHICKZ1 "40.0" +SATTHICKZ2 "40.0" +SEDESC "3D FSPGR IR" +SEDESC "3DIR PREP" +SEDESC "3 plane loc" +SEDESC "AX FSE T1" +SEDESC "AX FSE T2" +SEDESC "AX T2*" +SEDESC "FATSAT T2 FSE Scout" +SEDESCFLAG "1" +SEDESC "LOCALIZER-RATCOIL" +SEDESC "O-Ax FATSAT T2 FSE high Res" +SEDESC "Oblique PD AX" +SEDESC "Oblique STIR" +SEDESC "Oblique T1 AX +C" +SEDESC "Oblique T1-SAG" +SEDESC "Oblique T1-SAG+C" +SEDESC "Oblique T2 AX." +SEDESC "O-Cor T1 " +SEDESC "RUN 1" +SEDESC "SPGR3D-HRES-Brasch" +SEDESC "SPGR3D-LRES-Brasch" +SEPSERIES "0" +SL3PLANE "0" +SL3PLANE "1" +SL3PLANE1 "0" +SL3PLANE1 "5" +SL3PLANE2 "0" +SL3PLANE2 "5" +SL3PLANE3 "0" +SL3PLANE3 "5" +SLABLOC "128" +SLABLOC "144" +SLABLOC "64" +SLABLOC "80" +SLICEASSET "1.00" +SLICEORDER "1" +SLOC1 "I35.2" +SLOC1 "I59.6" +SLOC1 "I93.4" +SLOC1 "L13.9" +SLOC1 "L1.6" +SLOC1 "L2.1" +SLOC1 "L5.0" +SLOC1 "L5.9" +SLOC1 "L84.1" +SLOC1 "L85.9" +SLOC1 "L99.2" +SLOC1 "R86.3" +SLOC2 "0.0" +SLOC2 "A11.0" +SLOC2 "A115.0" +SLOC2 "A79.2" +SLOC2 "A80.8" +SLOC2 "P34.4" +SLOC2 "P37.0" +SLOC2 "P46.5" +SLOC2 "P50.2" +SLOC3 "I27.8" +SLOC3 "I37.0" +SLOC3 "I7.1" +SLOC3 "S12.3" +SLOC3 "S163.1" +SLOC3 "S1.7" +SLOC3 "S5.4" +SLOC3 "S7.0" +SLPERLOC "274" +SLTHICK "0.2" +SLTHICK "0.7" +SLTHICK "1.2" +SLTHICK "1.3" +SLTHICK "3.0" +SLTHICK "4.0" +SLTHICK "5.0" +SLTHICK "5.5" +SPC "0.0" +SPC "1.5" +SPCPERPLANE1 "0.0" +SPCPERPLANE1 "1.5" +SPCPERPLANE2 "0.0" +SPCPERPLANE2 "1.5" +SPCPERPLANE3 "0.0" +SPCPERPLANE3 "1.5" +STATION "0" +SUPPTQ "1" +SWAPPF "A/P" +SWAPPF "R/L" +SWAPPF "S/I" +SWAPPF "Unswap" +TAG_SPACE "7" +TAG_TYPE "None" +TBLDELTA "0.00" +TE "100.0" +TE "102.0" +TE "15.0" +TE "30.0" +TE "50.0" +TE "Min Full" +TE "Minimum" +TI "150" +TI "450" +TI "500" +TOTALNOSTATION "0" +TR "2000.0" +TR "3000.0" +TR "4000.0" +TR "4125.0" +TR "4575.0" +TR "475.0" +TR "500.0" +TR "5200.0" +TR "525.0" +TR "5325.0" +TR "6600.0" +TRACKLEN "200.0" +TRACKTHICK "20.0" +TRACTIVE "0" +TRACTIVE "4" +TRICKSIMG "1" +TRREST "0" +TRREST "4" +USERCV0 "0.00" +USERCV0 "1.00" +USERCV21 "0.00" +USERCV23 "100.00" +USERCV4 "0.00" +USERCV6 "0.00" +USERCV7 "0.00" +USERCV_MASK "0" +USERCV_MASK "1" +USERCV_MASK "128" +USERCV_MASK "192" +USERCV_MASK "2097344" +USERCV_MASK "6144" +USERCV_MASK "64" +USERCV_MASK "8388688" +VIEWORDER "1" + +*/ diff --git a/gdcm/Applications/Cxx/gdcmfile.cxx b/gdcm/Applications/Cxx/gdcmfile.cxx new file mode 100644 index 0000000..fc8db9f --- /dev/null +++ b/gdcm/Applications/Cxx/gdcmfile.cxx @@ -0,0 +1,83 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include +#include +#include + +// fstat +#include +#include +#include + +// open +#include +#include +#include + +// mmap +#include + +#include "gdcmFile.h" +#include "gdcmObject.h" +#include "gdcmDataSet.h" +#include "gdcmFileMetaInformation.h" +#include "gdcmSmartPointer.h" +#include "gdcmDeflateStream.h" +#include "gdcmDumper.h" +#include "gdcmDirectory.h" +#include "gdcmSystem.h" + + +int DoOperation(std::string const & path) +{ + //std::cout << path << "\n"; + std::ifstream is( path.c_str(), std::ios::binary ); + is.seekg(0, std::ios::end ); + std::streampos size = is.tellg(); + is.seekg(0,std::ios::beg); + std::vector buffer; + buffer.resize(size); + is.read(&buffer[0], size ); + char k = buffer[(size_t)size-1]; // at least read one char to avoid compiler optimization + is.close(); + + return 0; +} + +int main(int argc, char *argv[]) +{ + if( argc < 2 ) + { + return 1; + } + std::string filename = argv[1]; + + int res = 0; + if( gdcm::System::FileIsDirectory( filename.c_str() ) ) + { + gdcm::Directory d; + d.Load(filename); + gdcm::Directory::FilenamesType const &filenames = d.GetFilenames(); + for( gdcm::Directory::FilenamesType::const_iterator it = filenames.begin(); it != filenames.end(); ++it ) + { + res += DoOperation(*it); + } + } + else + { + res += DoOperation(filename); + } + + return res; +} diff --git a/gdcm/Applications/Cxx/gdcmgendir.cxx b/gdcm/Applications/Cxx/gdcmgendir.cxx new file mode 100644 index 0000000..1be3b43 --- /dev/null +++ b/gdcm/Applications/Cxx/gdcmgendir.cxx @@ -0,0 +1,349 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + * Implementation of General Purpose CD-R Interchange / STD-GEN-CD DICOMDIR in GDCM + */ +#include "gdcmReader.h" +#include "gdcmWriter.h" +#include "gdcmVersion.h" +#include "gdcmSystem.h" +#include "gdcmUIDGenerator.h" +#include "gdcmGlobal.h" +#include "gdcmDefs.h" +#include "gdcmDirectory.h" +#include "gdcmDICOMDIRGenerator.h" + +#include + + +static void PrintVersion() +{ + std::cout << "gdcmgendir: gdcm " << gdcm::Version::GetVersion() << " "; + const char date[] = "$Date$"; + std::cout << date << std::endl; +} + +static void PrintHelp() +{ + PrintVersion(); + std::cout << "Usage: gdcmgendir [OPTION]... FILE..." << std::endl; + std::cout << "create DICOMDIR" << std::endl; + std::cout << "Parameter:" << std::endl; + std::cout << "Options:" << std::endl; + std::cout << " -i --input DICOM filename or directory" << std::endl; + std::cout << " -o --output DICOM filename or directory" << std::endl; + std::cout << " -r --recursive recursive." << std::endl; + std::cout << " --descriptor descriptor." << std::endl; + std::cout << " --root-uid Root UID." << std::endl; + std::cout << "General Options:" << std::endl; + std::cout << " -V --verbose more verbose (warning+error)." << std::endl; + std::cout << " -W --warning print warning info." << std::endl; + std::cout << " -D --debug print debug info." << std::endl; + std::cout << " -E --error print error info." << std::endl; + std::cout << " -h --help print help." << std::endl; + std::cout << " -v --version print version." << std::endl; + std::cout << "Env var:" << std::endl; + std::cout << " GDCM_ROOT_UID Root UID" << std::endl; +} + +int main(int argc, char *argv[]) +{ + int c; + std::string filename; + std::string outfilename; + gdcm::Directory::FilenamesType filenames; + std::string xmlpath; + int verbose = 0; + int warning = 0; + int help = 0; + int recursive = 0; + int version = 0; + int debug = 0; + int error = 0; + int resourcespath = 0; + int rootuid = 0; + int descriptor = 0; + std::string descriptor_str; + std::string root; + while (1) { + int option_index = 0; + static struct option long_options[] = { + {"input", 1, 0, 0}, + {"output", 1, 0, 0}, // o + {"recursive", 0, &recursive, 1}, + {"root-uid", 1, &rootuid, 1}, // specific Root (not GDCM) + {"resources-path", 1, &resourcespath, 1}, + {"descriptor", 1, &descriptor, 1}, + + {"verbose", 0, &verbose, 1}, + {"warning", 0, &warning, 1}, + {"debug", 0, &debug, 1}, + {"error", 0, &error, 1}, + {"help", 0, &help, 1}, + {"version", 0, &version, 1}, + {0, 0, 0, 0} // required + }; + static const char short_options[] = "i:o:rVWDEhv"; + c = getopt_long (argc, argv, short_options, + long_options, &option_index); + if (c == -1) + { + break; + } + + switch (c) + { + case 0: + case '-': + { + const char *s = long_options[option_index].name; (void)s; + //printf ("option %s", s); + if (optarg) + { + if( option_index == 0 ) /* input */ + { + assert( strcmp(s, "input") == 0 ); + assert( filename.empty() ); + filename = optarg; + } + else if( option_index == 1 ) /* output */ + { + assert( strcmp(s, "output") == 0 ); + assert( outfilename.empty() ); + outfilename = optarg; + } + else if( option_index == 3 ) /* root-uid */ + { + assert( strcmp(s, "root-uid") == 0 ); + root = optarg; + } + else if( option_index == 4 ) /* resources-path */ + { + assert( strcmp(s, "resources-path") == 0 ); + assert( xmlpath.empty() ); + xmlpath = optarg; + } + else if( option_index == 5 ) /* descriptor */ + { + assert( strcmp(s, "descriptor") == 0 ); + assert( descriptor_str.empty() ); + descriptor_str = optarg; + } + //printf (" with arg %s", optarg); + } + //printf ("\n"); + } + break; + + case 'i': + //printf ("option i with value '%s'\n", optarg); + assert( filename.empty() ); + filename = optarg; + break; + + case 'o': + assert( outfilename.empty() ); + outfilename = optarg; + break; + + case 'r': + recursive = 1; + break; + + case 'V': + verbose = 1; + break; + + case 'W': + warning = 1; + break; + + case 'D': + debug = 1; + break; + + case 'E': + error = 1; + break; + + case 'h': + help = 1; + break; + + case 'v': + version = 1; + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + //printf ("non-option ARGV-elements: %d", optind ); + std::vector files; + while (optind < argc) + { + //printf ("%s\n", argv[optind++]); + files.push_back( argv[optind++] ); + } + //printf ("\n"); + if( files.size() >= 2 + && filename.empty() + && outfilename.empty() + ) + { + filename = files[0].c_str(); + filenames = files; + outfilename = files[ files.size() - 1 ].c_str(); + filenames.pop_back(); + } + else + { + PrintHelp(); + return 1; + } + } + + if( version ) + { + //std::cout << "version" << std::endl; + PrintVersion(); + return 0; + } + + if( help ) + { + //std::cout << "help" << std::endl; + PrintHelp(); + return 0; + } + + if( filename.empty() + || outfilename.empty() ) + { + //std::cerr << "Need input file (-i)\n"; + PrintHelp(); + return 1; + } + + // Debug is a little too verbose + gdcm::Trace::SetDebug( debug != 0 ); + gdcm::Trace::SetWarning( warning != 0 ); + gdcm::Trace::SetError( error != 0 ); + // when verbose is true, make sure warning+error are turned on: + if( verbose ) + { + gdcm::Trace::SetWarning( verbose != 0 ); + gdcm::Trace::SetError( verbose != 0); + } + + if( !gdcm::System::FileExists(filename.c_str()) ) + { + return 1; + } + +/* + gdcm::Global& g = gdcm::Global::GetInstance(); + // First thing we need to locate the XML dict + // did the user requested to look XML file in a particular directory ? + if( !resourcespath ) + { + const char *xmlpathenv = getenv("GDCM_RESOURCES_PATH"); + if( xmlpathenv ) + { + // Make sure to look for XML dict in user explicitly specified dir first: + xmlpath = xmlpathenv; + resourcespath = 1; + } + } + if( resourcespath ) + { + // xmlpath is set either by the cmd line option or the env var + if( !g.Prepend( xmlpath.c_str() ) ) + { + std::cerr << "specified Resources Path is not valid: " << xmlpath << std::endl; + return 1; + } + } + + // All set, then load the XML files: + if( !g.LoadResourcesFiles() ) + { + return 1; + } + + const gdcm::Defs &defs = g.GetDefs(); +*/ + + gdcm::FileMetaInformation::SetSourceApplicationEntityTitle( "gdcmgendir" ); + if( !rootuid ) + { + // only read the env var is no explicit cmd line option + // maybe there is an env var defined... let's check + const char *rootuid_env = getenv("GDCM_ROOT_UID"); + if( rootuid_env ) + { + rootuid = 1; + root = rootuid_env; + } + } + if( rootuid ) + { + if( !gdcm::UIDGenerator::IsValid( root.c_str() ) ) + { + std::cerr << "specified Root UID is not valid: " << root << std::endl; + return 1; + } + gdcm::UIDGenerator::SetRoot( root.c_str() ); + } + + int res = 0; + unsigned int nfiles = 1; + gdcm::DICOMDIRGenerator gen; + if( gdcm::System::FileIsDirectory(filename.c_str()) ) + { + gdcm::Directory dir; + nfiles = dir.Load(filename, recursive!= 0); (void)nfiles; + filenames = dir.GetFilenames(); + gen.SetRootDirectory( filename ); + } + else + { + // should be all set ! + } + (void)nfiles; + + gen.SetFilenames( filenames ); + gen.SetDescriptor( descriptor_str.c_str() ); + if( !gen.Generate() ) + { + std::cerr << "Problem during generation" << std::endl; + return 1; + } + + gdcm::Writer writer; + writer.SetFile( gen.GetFile() ); + writer.SetFileName( outfilename.c_str() ); + if( !writer.Write() ) + { + return 1; + } + + return res; +} diff --git a/gdcm/Applications/Cxx/gdcmimg.cxx b/gdcm/Applications/Cxx/gdcmimg.cxx new file mode 100644 index 0000000..f3c2584 --- /dev/null +++ b/gdcm/Applications/Cxx/gdcmimg.cxx @@ -0,0 +1,1237 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + * TODO: Merging (burnin) of overlay would be nice (merge 0x60xx overlay into PixelData) + * TODO: --add-thumbnail / --remove-thumbnail + * convert: -thumbnail geometry create a thumbnail of the image + * convert: -crop geometry cut out a rectangular region of the image + * -floodfill geometry color + * floodfill the image with color + * 1. Create a DICOM file from a 'raw' input: + * 2. Create a blob (jpeg,pgm/pnm,j2k,rle) from input + * - binary blob(s) (grayscale / RGB) input + * - jpeg(s) + * - j2k(s) + * + * Mapping is: + * + * DICOM RAW <-> pnm/pgm + * DICOM jpg <-> jpg + * DICOM ljpg <-> ljpg + * DICOM jls <-> jls + * DICOM j2k <-> j2k + * DICOM rle <-> Utah RLE ?? + * + * ??: + * DICOM avi <-> avi + * DICOM wav <-> wav + * DICOM pdf <-> pdf + * Todo: check compat API with jhead + */ +#include "gdcmFilename.h" +#include "gdcmDirectory.h" +#include "gdcmMediaStorage.h" +#include "gdcmSmartPointer.h" +#include "gdcmUIDGenerator.h" +#include "gdcmSequenceOfFragments.h" +#include "gdcmSystem.h" +#include "gdcmReader.h" +#include "gdcmPixmapWriter.h" +#include "gdcmPixmapReader.h" +#include "gdcmFileMetaInformation.h" +#include "gdcmDataSet.h" +#include "gdcmAttribute.h" +#include "gdcmPNMCodec.h" +#include "gdcmPGXCodec.h" +#include "gdcmJPEGCodec.h" +#include "gdcmJPEGLSCodec.h" +#include "gdcmJPEG2000Codec.h" +#include "gdcmRLECodec.h" +#include "gdcmRAWCodec.h" +#include "gdcmVersion.h" + +#include +#include + +#include /* for printf */ +#include /* for exit */ +#include +#include + +#ifdef _MSC_VER +#define atoll _atoi64 +#endif + +static unsigned int readsize(const char *str, unsigned int * size) +{ + int n = sscanf( str, "%i,%i,%i", size, size+1, size+2); + return n == EOF ? 0 : (unsigned int)n; +} + +static bool readgeometry(const char *geometry, unsigned int * region) +{ + int n = sscanf( geometry, "%i,%i,%i,%i,%i,%i", region, region+1, region+2, region+3, region+4, region+5); + if( n != 6 ) return false; + return true; +} + +template +static void FillRegionWithColor(T *p, const unsigned int *dims, const unsigned int * region, unsigned int color, unsigned int nsamples) +{ + unsigned int xmin = region[0]; + unsigned int xmax = region[1]; + unsigned int ymin = region[2]; + unsigned int ymax = region[3]; + unsigned int zmin = region[4]; + unsigned int zmax = region[5]; + + for( unsigned int x = xmin; x <= xmax; ++x) + { + for( unsigned int y = ymin; y <= ymax; ++y) + { + for( unsigned int z = zmin; z <= zmax; ++z) + { + for( unsigned int sample = 0; sample < nsamples; ++sample) + { + p[x*nsamples+y*dims[0]*nsamples+z*dims[0]*dims[1]*nsamples+sample] = (T)color; + } + } + } + } +} + +static void PrintVersion() +{ + std::cout << "gdcmimg: gdcm " << gdcm::Version::GetVersion() << " "; + const char date[] = "$Date$"; + std::cout << date << std::endl; +} + +static void PrintHelp() +{ + PrintVersion(); + std::cout << "Usage: gdcmimg [OPTION]... FILE..." << std::endl; + std::cout << "Manipulate DICOM image file:" << std::endl; + std::cout << " 1. Convert to and from other file format (jpg, jp2, pnm...)" << std::endl; + std::cout << " 2. Anonymize burn-in annotation (rect region fill with pixel value)" << std::endl; + std::cout << "Parameter (required):" << std::endl; + std::cout << " -i --input Input filename" << std::endl; + std::cout << " -o --output Output filename" << std::endl; + std::cout << "Options:" << std::endl; + std::cout << " --endian %s Endianness (LSB/MSB)." << std::endl; + std::cout << " -d --depth %d Depth (Either 8/16/32 or BitsAllocated eg. 12 when known)." << std::endl; + std::cout << " --sign %s Pixel sign (0/1)." << std::endl; + std::cout << " --spp %d Sample Per Pixel (1/3)." << std::endl; + std::cout << " --pc [01] Change planar configuration." << std::endl; + std::cout << " --pi [str] Change photometric interpretation." << std::endl; + std::cout << " --pf %d,%d,%d Change pixel format: (BA,BS,HB)." << std::endl; + std::cout << " -s --size %d,%d,%d Size." << std::endl; + std::cout << " --offset %ull Start Offset." << std::endl; + std::cout << " -C --sop-class-uid SOP Class UID (name or value)." << std::endl; + std::cout << " -T --study-uid Study UID." << std::endl; + std::cout << " -S --series-uid Series UID." << std::endl; + std::cout << " --root-uid Root UID." << std::endl; + std::cout << "Fill Options:" << std::endl; + std::cout << " -R --region %d,%d Region." << std::endl; + std::cout << " -F --fill %d Fill with pixel value specified." << std::endl; + std::cout << "General Options:" << std::endl; + std::cout << " -V --verbose more verbose (warning+error)." << std::endl; + std::cout << " -W --warning print warning info." << std::endl; + std::cout << " -D --debug print debug info." << std::endl; + std::cout << " -E --error print error info." << std::endl; + std::cout << " -h --help print help." << std::endl; + std::cout << " -v --version print version." << std::endl; + std::cout << "Env var:" << std::endl; + std::cout << " GDCM_ROOT_UID Root UID" << std::endl; +/* + * Default behavior for root UID is: + * By default the GDCM one is used + * If GDCM_ROOT_UID is set, then use this one instead + * If --root-uid is explicitly set on the command line, it will override any other defined behavior + */ +} + +static bool AddContentDateTime(gdcm::DataSet &ds, const char *filename ) +{ + time_t studydatetime = gdcm::System::FileTime( filename ); + char date[22]; + gdcm::System::FormatDateTime(date, studydatetime); + const size_t datelen = 8; + { + gdcm::DataElement de( gdcm::Tag(0x0008,0x0023) ); // Content Date + // Do not copy the whole cstring: + de.SetByteValue( date, datelen ); + de.SetVR( gdcm::Attribute<0x0008,0x0023>::GetVR() ); + ds.Insert( de ); + } + // StudyTime + const size_t timelen = 6; // get rid of milliseconds + { + gdcm::DataElement de( gdcm::Tag(0x0008,0x0033) ); // Content Time + // Do not copy the whole cstring: + de.SetByteValue( date+datelen, timelen ); + de.SetVR( gdcm::Attribute<0x0008,0x0033>::GetVR() ); + ds.Insert( de ); + } + return true; +} +// Set Study Date/Time to the file time: +static bool AddStudyDateTime(gdcm::DataSet &ds, const char *filename ) +{ + // StudyDate + char date[22]; + const size_t datelen = 8; + int res = gdcm::System::GetCurrentDateTime(date); + if( !res ) return false; + { + gdcm::DataElement de( gdcm::Tag(0x0008,0x0020) ); + // Do not copy the whole cstring: + de.SetByteValue( date, datelen ); + de.SetVR( gdcm::Attribute<0x0008,0x0020>::GetVR() ); + ds.Insert( de ); + } + // StudyTime + const size_t timelen = 6; // get rid of milliseconds + { + gdcm::DataElement de( gdcm::Tag(0x0008,0x0030) ); + // Do not copy the whole cstring: + de.SetByteValue( date+datelen, timelen ); + de.SetVR( gdcm::Attribute<0x0008,0x0030>::GetVR() ); + ds.Insert( de ); + } + return AddContentDateTime(ds, filename); +} + + +static bool AddUIDs(int sopclassuid, std::string const & sopclass, std::string const & study_uid, std::string const & series_uid, gdcm::PixmapWriter& writer) +{ + gdcm::DataSet & ds = writer.GetFile().GetDataSet(); + gdcm::MediaStorage ms = gdcm::MediaStorage::MS_END; + if( sopclassuid ) + { + // Is it by value or by name ? + if( gdcm::UIDGenerator::IsValid( sopclass.c_str() ) ) + { + ms = gdcm::MediaStorage::GetMSType( sopclass.c_str() ); + } + else + { + std::cerr << "not implemented" << std::endl; + } + if( !gdcm::MediaStorage::IsImage(ms) ) + { + std::cerr << "invalid media storage (no pixel data): " << sopclass << std::endl; + return false; + } + + const char* msstr = gdcm::MediaStorage::GetMSString(ms); + if( !msstr ) + { + std::cerr << "problem with media storage: " << sopclass << std::endl; + return false; + } + gdcm::DataElement de( gdcm::Tag(0x0008, 0x0016 ) ); + de.SetByteValue( msstr, (uint32_t)strlen(msstr) ); + de.SetVR( gdcm::Attribute<0x0008, 0x0016>::GetVR() ); + ds.Insert( de ); + } + else + { + // FIXME we are copying the default behavior of gdcm.PixmapWriter here: + ms = gdcm::MediaStorage::SecondaryCaptureImageStorage; + } + + gdcm::Pixmap &image = writer.GetPixmap(); + if( ms.GetModalityDimension() < image.GetNumberOfDimensions() ) + { + std::cerr << "Could not find Modality" << std::endl; + return false; + } + + { + gdcm::DataElement de( gdcm::Tag(0x0020,0x000d) ); // Study + de.SetByteValue( study_uid.c_str(), (uint32_t)study_uid.size() ); + de.SetVR( gdcm::Attribute<0x0020, 0x000d>::GetVR() ); + ds.Insert( de ); + } + + { + gdcm::DataElement de( gdcm::Tag(0x0020,0x000e) ); // Series + de.SetByteValue( series_uid.c_str(), (uint32_t)series_uid.size() ); + de.SetVR( gdcm::Attribute<0x0020, 0x000e>::GetVR() ); + ds.Insert( de ); + } + + return true; +} + +static bool PopulateSingeFile( gdcm::PixmapWriter & writer, gdcm::SequenceOfFragments *sq , gdcm::ImageCodec & jpeg, const char *filename, std::streampos const pos = 0 ) +{ + /* + * FIXME: when JPEG contains JFIF marker, we should only read them + * during header parsing but discard them when copying the JPG byte stream into + * the encapsulated Pixel Data Element... + */ + std::ifstream is(filename, std::ios::binary); + gdcm::TransferSyntax ts; + bool b = jpeg.GetHeaderInfo( is, ts ); + if( !b ) + { + std::cerr << "Could not read: " << filename << std::endl; + return false; + } + + gdcm::Pixmap &image = writer.GetPixmap(); + image.SetDimensions( jpeg.GetDimensions() ); + image.SetPixelFormat( jpeg.GetPixelFormat() ); + image.SetPhotometricInterpretation( jpeg.GetPhotometricInterpretation() ); + image.SetPlanarConfiguration( jpeg.GetPlanarConfiguration() ); + image.SetTransferSyntax( ts ); + + AddStudyDateTime( writer.GetFile().GetDataSet(), filename ); + + size_t len = gdcm::System::FileSize(filename); + if( ts.IsEncapsulated() ) + { + is.seekg(0, std::ios::beg );// rewind ! + } + else + { + len = image.GetBufferLength(); + // do not rewind file should be just at right offset + } + char *buf = new char[len]; + if( pos ) + { + is.seekg( pos, std::ios::beg ); + } + is.read(buf, len); + gdcm::DataElement pixeldata( gdcm::Tag(0x7fe0,0x0010) ); + + if( ts.IsEncapsulated() ) + { + gdcm::Fragment frag; + frag.SetByteValue( buf, (uint32_t)len ); + sq->AddFragment( frag ); + pixeldata.SetValue( *sq ); + } + else + { + pixeldata.SetByteValue( buf, (uint32_t)len ); + } + delete[] buf; + image.SetDataElement( pixeldata ); + + return true; +} + +static bool Populate( gdcm::PixmapWriter & writer, gdcm::ImageCodec & jpeg, gdcm::Directory::FilenamesType const & filenames, unsigned int ndim = 2, std::streampos const & pos = 0 ) +{ + std::vector::const_iterator it = filenames.begin(); + bool b = true; + gdcm::Pixmap &image = writer.GetPixmap(); + image.SetNumberOfDimensions( ndim ); + if( filenames.size() > 1 ) + { + image.SetNumberOfDimensions( 3 ); + } + + gdcm::SmartPointer sq = new gdcm::SequenceOfFragments; + for(; it != filenames.end(); ++it) + { + b = b && PopulateSingeFile( writer, sq, jpeg, it->c_str(), pos ); + } + if( filenames.size() > 1 ) + { + image.SetDimension(2, (unsigned int)filenames.size() ); + } + + return b; +} + + +static bool GetPixelFormat( gdcm::PixelFormat & pf, int depth, int bpp, int sign, int pixelsign, int spp = 0, int pixelspp = 1 ) +{ + if( depth ) + { + if( bpp <= 8 ) + { + pf = gdcm::PixelFormat::UINT8; + } + else if( bpp > 8 && bpp <= 16 ) + { + pf = gdcm::PixelFormat::UINT16; + } + else if( bpp > 16 && bpp <= 32 ) + { + pf = gdcm::PixelFormat::UINT32; + } + else + { + std::cerr << "Invalid depth: << " << bpp << std::endl; + return false; + } + pf.SetBitsStored( (short)bpp ); + } + if( sign ) + { + pf.SetPixelRepresentation( (unsigned short)pixelsign ); + } + if( spp ) + { + pf.SetSamplesPerPixel( (unsigned short)pixelspp ); + } + + return true; +} + +int main (int argc, char *argv[]) +{ + int c; + //int digit_optind = 0; + + std::string root; + int rootuid = 0; + gdcm::Filename filename; + gdcm::Directory::FilenamesType filenames; + gdcm::Filename outfilename; + unsigned int region[6] = {}; // Rows & Columns are VR=US anyway... + unsigned int color = 0; + int bregion = 0; + int fill = 0; + int sign = 0; + int spp = 0; + int pconf = 0; // planar configuration + int studyuid = 0; + int seriesuid = 0; + unsigned int size[3] = {0,0,0}; + unsigned int ndimension = 2; + int depth = 0; + int endian = 0; + int bpp = 0; + int pixelsign = 0; + int pixelspp = 0; + std::string sopclass; + std::string lsb_msb; + int sopclassuid = 0; + int pinter = 0; + std::string pinterstr; + int pformat = 0; + std::string pformatstr; + int poffset = 0; + size_t start_pos = 0; + + int verbose = 0; + int warning = 0; + int debug = 0; + int error = 0; + int help = 0; + int version = 0; + + gdcm::UIDGenerator uid; + // Too early for UID Generation + std::string series_uid; // = uid.Generate(); + std::string study_uid; // = uid.Generate(); + while (1) { + //int this_option_optind = optind ? optind : 1; + int option_index = 0; + static struct option long_options[] = { + {"input", 1, 0, 0}, + {"output", 1, 0, 0}, + // provide convert-like command line args: + {"depth", 1, &depth, 1}, + {"size", 1, 0, 0}, + {"region", 1, &bregion, 1}, + {"fill", 1, &fill, 1}, + {"study-uid", 1, &studyuid, 1}, + {"series-uid", 1, &seriesuid, 1}, + {"root-uid", 1, &rootuid, 1}, // specific Root (not GDCM) + {"sop-class-uid", 1, &sopclassuid, 1}, // specific SOP Class UID + {"endian", 1, &endian, 1}, // + {"sign", 1, &sign, 1}, // + {"spp", 1, &spp, 1}, // + {"pc", 1, &pconf, 1}, // + {"pi", 1, &pinter, 1}, // + {"pf", 1, &pformat, 1}, // + {"offset", 1, &poffset, 1}, // + +// General options ! + {"verbose", 0, &verbose, 1}, + {"warning", 0, &warning, 1}, + {"debug", 0, &debug, 1}, + {"error", 0, &error, 1}, + {"help", 0, &help, 1}, + {"version", 0, &version, 1}, + {0, 0, 0, 0} + }; + + // i -> input file + // I -> input directory + // o -> output file + // O -> output directory + c = getopt_long (argc, argv, "i:o:I:O:d:s:R:C:F:T:S:VWDEhv", + long_options, &option_index); + if (c == -1) + { + break; + } + + switch (c) + { + case 0: + { + const char *s = long_options[option_index].name; (void)s; + //printf ("option %s", s); + if (optarg) + { + if( option_index == 0 ) /* input */ + { + assert( strcmp(s, "input") == 0 ); + assert( filename.IsEmpty() ); + filename = optarg; + } + else if( option_index == 2 ) /* depth */ + { + assert( strcmp(s, "depth") == 0 ); + bpp = atoi(optarg); + } + else if( option_index == 3 ) /* size */ + { + assert( strcmp(s, "size") == 0 ); + ndimension = readsize(optarg, size); + } + else if( option_index == 4 ) /* region */ + { + assert( strcmp(s, "region") == 0 ); + readgeometry(optarg, region); + } + else if( option_index == 5 ) /* fill */ + { + assert( strcmp(s, "fill") == 0 ); + color = atoi(optarg); + } + else if( option_index == 6 ) /* study-uid */ + { + assert( strcmp(s, "study-uid") == 0 ); + study_uid = optarg; + } + else if( option_index == 7 ) /* series-uid */ + { + assert( strcmp(s, "series-uid") == 0 ); + series_uid = optarg; + } + else if( option_index == 8 ) /* root-uid */ + { + assert( strcmp(s, "root-uid") == 0 ); + root = optarg; + } + else if( option_index == 9 ) /* sop-class-uid */ + { + assert( strcmp(s, "sop-class-uid") == 0 ); + sopclass = optarg; + } + else if( option_index == 10 ) /* endian */ + { + assert( strcmp(s, "endian") == 0 ); + lsb_msb = optarg; + } + else if( option_index == 11 ) /* sign */ + { + assert( strcmp(s, "sign") == 0 ); + pixelsign = atoi(optarg); + } + else if( option_index == 12 ) /* spp */ + { + assert( strcmp(s, "spp") == 0 ); + pixelspp = atoi(optarg); + } + else if( option_index == 13 ) /* pconf */ + { + assert( strcmp(s, "pc") == 0 ); + pconf = atoi(optarg); + } + else if( option_index == 14 ) /* pinter */ + { + assert( strcmp(s, "pi") == 0 ); + pinter = 1; + pinterstr = optarg; + } + else if( option_index == 15 ) /* pformat */ + { + assert( strcmp(s, "pf") == 0 ); + pformat = 1; + pformatstr = optarg; + } + else if( option_index == 16 ) /* start_pos */ + { + assert( strcmp(s, "offset") == 0 ); + poffset = 1; + start_pos = atoll(optarg); + } + //printf (" with arg %s", optarg); + } + //printf ("\n"); + } + break; + + case 'i': + //printf ("option i with value '%s'\n", optarg); + assert( filename.IsEmpty() ); + filename = optarg; + break; + + case 'o': + //printf ("option o with value '%s'\n", optarg); + assert( outfilename.IsEmpty() ); + outfilename = optarg; + break; + + case 'd': // depth + bpp = atoi(optarg); + depth = 1; + break; + + case 's': // size + ndimension = readsize(optarg, size); + break; + + case 'T': + studyuid = 1; + study_uid = optarg; + break; + + case 'S': + seriesuid = 1; + series_uid = optarg; + break; + + case 'C': + sopclassuid = 1; + sopclass = optarg; + break; + + case 'R': // region + //outfilename = optarg; + readgeometry(optarg, region); + break; + + case 'F': // fill + color = atoi( optarg ); + fill = 1; + break; + + case 'V': + verbose = 1; + break; + + case 'W': + warning = 1; + break; + + case 'D': + debug = 1; + break; + + case 'E': + error = 1; + break; + + case 'h': + help = 1; + break; + + case 'v': + version = 1; + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + // For now only support one input / one output + if (optind < argc) + { + //printf ("non-option ARGV-elements: "); + std::vector files; + while (optind < argc) + { + //printf ("%s\n", argv[optind++]); + files.push_back( argv[optind++] ); + } + //printf ("\n"); + if( files.size() >= 2 + && filename.IsEmpty() + && outfilename.IsEmpty() + ) + { + filename = files[0].c_str(); + filenames = files; + outfilename = files[ files.size() - 1 ].c_str(); + filenames.pop_back(); + } + else + { + PrintHelp(); + return 1; + } + } + + if( version ) + { + //std::cout << "version" << std::endl; + PrintVersion(); + return 0; + } + + if( help ) + { + //std::cout << "help" << std::endl; + PrintHelp(); + return 0; + } + + if( filenames.empty() && filename.IsEmpty() ) + { + //std::cerr << "Need input file (-i)\n"; + PrintHelp(); + return 1; + } + if( outfilename.IsEmpty() ) + { + //std::cerr << "Need output file (-o)\n"; + PrintHelp(); + return 1; + } + + // Ok so we are about to write a DICOM file, do not forget to stamp it GDCM ! + gdcm::FileMetaInformation::SetSourceApplicationEntityTitle( "gdcmimg" ); + if( !rootuid ) + { + // only read the env var is no explicit cmd line option + // maybe there is an env var defined... let's check + const char *rootuid_env = getenv("GDCM_ROOT_UID"); + if( rootuid_env ) + { + rootuid = 1; + root = rootuid_env; + } + } + if( rootuid ) + { + if( !gdcm::UIDGenerator::IsValid( root.c_str() ) ) + { + std::cerr << "specified Root UID is not valid: " << root << std::endl; + return 1; + } + gdcm::UIDGenerator::SetRoot( root.c_str() ); + } + if( study_uid.empty() ) + { + study_uid = uid.Generate(); + } + if( !gdcm::UIDGenerator::IsValid( study_uid.c_str() ) ) + { + std::cerr << "Invalid UID for Study UID: " << study_uid << std::endl; + return 1; + } + + if( series_uid.empty() ) + { + series_uid = uid.Generate(); + } + if( !gdcm::UIDGenerator::IsValid( series_uid.c_str() ) ) + { + std::cerr << "Invalid UID for Series UID: " << series_uid << std::endl; + return 1; + } + + // Debug is a little too verbose + gdcm::Trace::SetDebug( (debug > 0 ? true : false)); + gdcm::Trace::SetWarning( (warning > 0 ? true : false)); + gdcm::Trace::SetError( (error > 0 ? true : false)); + // when verbose is true, make sure warning+error are turned on: + if( verbose ) + { + gdcm::Trace::SetWarning( (verbose > 0 ? true : false) ); + gdcm::Trace::SetError( (verbose > 0 ? true : false) ); + } + + if( depth ) + { + if( bpp < 1 || bpp > 32 ) + { + std::cerr << "Invalid depth for pixel: " << bpp << std::endl; + return 1; + } + } + if( sign ) + { + if( pixelsign != 0 && pixelsign != 1 ) return 1; + } + if( spp ) + { + if( pixelspp != 1 && pixelspp != 3 ) return 1; + } + if( pconf != 0 && pconf != 1 ) return 1; + if( pconf ) + { + if( pixelspp != 3 ) return 1; + } + gdcm::PixelFormat pfref = gdcm::PixelFormat::UINT8; + if( pformat ) + { + int ba, bs, hb; + int n = sscanf( pformatstr.c_str(), "%d,%d,%d", &ba, &bs, &hb ); + if( n != 3 ) return 1; + pfref.SetBitsAllocated( (unsigned short)ba ); + pfref.SetBitsStored( (unsigned short)bs ); + pfref.SetHighBit( (unsigned short)hb ); + if( spp ) + pfref.SetSamplesPerPixel( (unsigned short)pixelspp ); + if( sign ) + pfref.SetPixelRepresentation( (unsigned short)pixelsign ); + } + gdcm::PhotometricInterpretation::PIType refpi = gdcm::PhotometricInterpretation::MONOCHROME2; + if( pinter ) + { + refpi = gdcm::PhotometricInterpretation::GetPIType( pinterstr.c_str() ); + if( refpi == gdcm::PhotometricInterpretation::UNKNOW + || refpi == gdcm::PhotometricInterpretation::PI_END ) + { + std::cerr << "Invalid PI: " << pinterstr << std::endl; + return 1; + } + } + + const char *inputextension = filename.GetExtension(); + const char *outputextension = outfilename.GetExtension(); + //if( !inputextension || !outputextension ) return 1; + if( inputextension ) + { + if( gdcm::System::StrCaseCmp(inputextension,".raw") == 0 // watch out that .raw for kakadu means big-endian + || gdcm::System::StrCaseCmp(inputextension,".rawl") == 0 // kakadu convention for raw little endian + || gdcm::System::StrCaseCmp(inputextension,".gray") == 0 // imagemagick convention + || gdcm::System::StrCaseCmp(inputextension,".bin") == 0 // openjp3d convention for raw little endian + || gdcm::System::StrCaseCmp(inputextension,".rgb") == 0 ) // imagemagick convention + { + if( !size[0] || !size[1] ) + { + std::cerr << "need to specify size of image stored in RAW file" << std::endl; + return 1; + } + gdcm::RAWCodec raw; + gdcm::PixmapWriter writer; + // Because the RAW stream is not self sufficient, we need to pass in some extra + // user info: + unsigned int dims[3] = {}; + dims[0] = size[0]; + dims[1] = size[1]; + if( ndimension == 3 ) + { + dims[2] = size[2]; + } + raw.SetDimensions( dims ); + gdcm::PixelFormat pf = gdcm::PixelFormat::UINT8; + gdcm::PhotometricInterpretation pi = refpi; + if( gdcm::System::StrCaseCmp(inputextension,".rgb") == 0 ) + { + pi = gdcm::PhotometricInterpretation::RGB; + spp = 1; + pixelspp = 3; + } + if( !GetPixelFormat( pf, depth, bpp, sign, pixelsign, spp, pixelspp ) ) return 1; + raw.SetPixelFormat( pf ); + if( spp ) + { + if( pixelspp == 3 ) pi = gdcm::PhotometricInterpretation::RGB; + } + raw.SetPhotometricInterpretation( pi ); + raw.SetNeedByteSwap( false ); + raw.SetPlanarConfiguration( pconf ); + if( endian ) + { + if( lsb_msb == "LSB" || lsb_msb == "MSB" ) + { + if( lsb_msb == "MSB" ) + { + raw.SetNeedByteSwap( true ); + } + } + else + { + std::cerr << "Unrecognized endian: " << lsb_msb << std::endl; + return 1; + } + } + + if( !Populate( writer, raw, filenames, ndimension, start_pos ) ) return 1; + if( !AddUIDs(sopclassuid, sopclass, study_uid, series_uid, writer ) ) return 1; + + writer.SetFileName( outfilename ); + if( !writer.Write() ) + { + std::cerr << "Failed to write: " << outfilename << std::endl; + return 1; + } + + return 0; + } + + if( gdcm::System::StrCaseCmp(inputextension,".rle") == 0 ) + { + if( !size[0] || !size[1] ) + { + std::cerr << "need to specify size of image stored in RLE file" << std::endl; + return 1; + } + gdcm::RLECodec rle; + gdcm::PixmapWriter writer; + // Because the RLE stream is not self sufficient, we need to pass in some extra + // user info: + unsigned int dims[3] = {}; + dims[0] = size[0]; + dims[1] = size[1]; + rle.SetDimensions( dims ); + gdcm::PixelFormat pf = gdcm::PixelFormat::UINT8; + if( !GetPixelFormat( pf, depth, bpp, sign, pixelsign ) ) return 1; + rle.SetPixelFormat( pf ); + gdcm::PhotometricInterpretation pi = refpi; + rle.SetPhotometricInterpretation( pi ); + + if( !Populate( writer, rle, filenames ) ) return 1; + if( !AddUIDs(sopclassuid, sopclass, study_uid, series_uid, writer ) ) return 1; + + writer.SetFileName( outfilename ); + if( !writer.Write() ) + { + return 1; + } + + return 0; + } + + if( gdcm::System::StrCaseCmp(inputextension,".pgm") == 0 + || gdcm::System::StrCaseCmp(inputextension,".pnm") == 0 + || gdcm::System::StrCaseCmp(inputextension,".ppm") == 0 ) + { + gdcm::PNMCodec pnm; + // Let's handle the case where user really wants to specify the data: + gdcm::PixelFormat pf = gdcm::PixelFormat::UINT8; + if( !GetPixelFormat( pf, depth, bpp, sign, pixelsign ) ) return 1; + + gdcm::PixmapWriter writer; + if( !Populate( writer, pnm, filenames ) ) return 1; + // populate will guess pixel format and photometric inter from file, need + // to override after calling Populate: + if( pformat ) + { + writer.GetPixmap().SetPixelFormat( pfref ); + } + if( pinter ) + { + writer.GetPixmap().SetPhotometricInterpretation( refpi ); + } + if( !AddUIDs(sopclassuid, sopclass, study_uid, series_uid, writer ) ) return 1; + + writer.SetFileName( outfilename ); + if( !writer.Write() ) + { + return 1; + } + + return 0; + } + + if( gdcm::System::StrCaseCmp(inputextension,".pgx") == 0 ) + { + gdcm::PGXCodec pnm; + gdcm::PixmapWriter writer; + if( !Populate( writer, pnm, filenames ) ) return 1; + if( !AddUIDs(sopclassuid, sopclass, study_uid, series_uid, writer ) ) return 1; + + writer.SetFileName( outfilename ); + if( !writer.Write() ) + { + return 1; + } + + return 0; + } + + if( gdcm::System::StrCaseCmp(inputextension,".jls") == 0 ) + { + gdcm::JPEGLSCodec jpeg; + gdcm::PixmapWriter writer; + if( !Populate( writer, jpeg, filenames ) ) return 1; + if( !AddUIDs(sopclassuid, sopclass, study_uid, series_uid, writer ) ) return 1; + + writer.SetFileName( outfilename ); + if( !writer.Write() ) + { + return 1; + } + + return 0; + } + + if( gdcm::System::StrCaseCmp(inputextension,".jp2") == 0 + || gdcm::System::StrCaseCmp(inputextension,".j2k") == 0 + || gdcm::System::StrCaseCmp(inputextension,".j2c") == 0 + || gdcm::System::StrCaseCmp(inputextension,".jpx") == 0 + || gdcm::System::StrCaseCmp(inputextension,".jpc") == 0 ) + { + /* + * FIXME: Same problem as in classic JPEG: JP2 is NOT a J2K byte stream + * need to chop off all extra header information... + */ + gdcm::JPEG2000Codec jpeg; + gdcm::PixmapWriter writer; + if( !Populate( writer, jpeg, filenames ) ) return 1; + if( !AddUIDs(sopclassuid, sopclass, study_uid, series_uid, writer ) ) return 1; + + writer.SetFileName( outfilename ); + if( !writer.Write() ) + { + return 1; + } + + return 0; + + } + + if( gdcm::System::StrCaseCmp(inputextension,".jpg") == 0 + || gdcm::System::StrCaseCmp(inputextension,".jpeg") == 0 + || gdcm::System::StrCaseCmp(inputextension,".ljpg") == 0 + || gdcm::System::StrCaseCmp(inputextension,".ljpeg") == 0 ) + { + gdcm::JPEGCodec jpeg; + // Let's handle the case where user really wants to specify signess of data: + gdcm::PixelFormat pf = gdcm::PixelFormat::UINT8; + if( !GetPixelFormat( pf, depth, bpp, sign, pixelsign ) ) return 1; + jpeg.SetPixelFormat( pf ); + gdcm::PixmapWriter writer; + if( !Populate( writer, jpeg, filenames ) ) return 1; + if( !AddUIDs(sopclassuid, sopclass, study_uid, series_uid, writer ) ) return 1; + + writer.SetFileName( outfilename ); + if( !writer.Write() ) + { + std::cerr << "Problem during DICOM steps" << std::endl; + return 1; + } + + return 0; + } + } +// else safely assume that if no inputextension matched then it is a DICOM file + + gdcm::PixmapReader reader; + reader.SetFileName( filename ); + if( !reader.Read() ) + { + std::cerr << "Failed to read: " << filename << std::endl; + return 1; + } + + const gdcm::Pixmap &imageori = reader.GetPixmap(); + const gdcm::File &file = reader.GetFile(); + + if ( outputextension ) + { + if( gdcm::System::StrCaseCmp(outputextension,".pgm") == 0 + || gdcm::System::StrCaseCmp(outputextension,".pnm") == 0 + || gdcm::System::StrCaseCmp(outputextension,".ppm") == 0 ) + { + gdcm::PNMCodec pnm; + pnm.SetDimensions( imageori.GetDimensions() ); + pnm.SetPixelFormat( imageori.GetPixelFormat() ); + pnm.SetPhotometricInterpretation( imageori.GetPhotometricInterpretation() ); + pnm.SetPlanarConfiguration( imageori.GetPlanarConfiguration() ); + pnm.SetLUT( imageori.GetLUT() ); + const gdcm::DataElement& in = imageori.GetDataElement(); + bool b = pnm.Write( outfilename, in ); + if( !b ) + { + std::cerr << "Problem writing PNM file" << std::endl; + return 1; + } + + return 0; + } + if( gdcm::System::StrCaseCmp(outputextension,".pgx") == 0 ) + { + gdcm::PGXCodec pnm; + pnm.SetDimensions( imageori.GetDimensions() ); + pnm.SetPixelFormat( imageori.GetPixelFormat() ); + pnm.SetPhotometricInterpretation( imageori.GetPhotometricInterpretation() ); + pnm.SetPlanarConfiguration( imageori.GetPlanarConfiguration() ); + pnm.SetLUT( imageori.GetLUT() ); + const gdcm::DataElement& in = imageori.GetDataElement(); + bool b = pnm.Write( outfilename, in ); + if( !b ) + { + std::cerr << "Problem writing PNM file" << std::endl; + return 1; + } + + return 0; + } + } + +// else safely assume that if no outputextension matched then it is a DICOM file + + gdcm::PixmapWriter writer; + writer.SetFile( file ); + writer.SetImage( imageori ); + writer.SetFileName( outfilename ); + + + gdcm::DataSet &ds = writer.GetFile().GetDataSet(); + if( fill ) + { + const gdcm::PixelFormat &pixeltype = imageori.GetPixelFormat(); + assert( imageori.GetNumberOfDimensions() == 2 || imageori.GetNumberOfDimensions() == 3 ); + unsigned long len = imageori.GetBufferLength(); + gdcm::SmartPointer image = new gdcm::Pixmap; + image->SetNumberOfDimensions( 2 ); // good default + const unsigned int *dims = imageori.GetDimensions(); + if ( region[0] > region[1] + || region[2] > region[3] + || region[4] > region[5] + || region[1] > dims[0] + || region[3] > dims[1] + || (imageori.GetNumberOfDimensions() > 2 && region[5] > dims[2]) ) + { + if( imageori.GetNumberOfDimensions() == 2 ) + { + std::cerr << "bogus region. Should be at most: (" << dims[0] << "," << dims[1] << "," + /*<< dims[2]*/ << ")" << std::endl; + } + else + { + std::cerr << "bogus region. Should be at most: (" << dims[0] << "," << dims[1] << "," + << dims[2] << ")" << std::endl; + } + return 1; + } + image->SetDimension(0, dims[0] ); + image->SetDimension(1, dims[1] ); + if( imageori.GetNumberOfDimensions() == 3 ) + { + image->SetNumberOfDimensions( 3 ); + image->SetDimension(2, dims[2] ); + } + image->SetPhotometricInterpretation( imageori.GetPhotometricInterpretation() ); + image->SetPixelFormat( imageori.GetPixelFormat() ); + image->SetPlanarConfiguration( imageori.GetPlanarConfiguration() ); + image->SetLUT( imageori.GetLUT() ); + image->SetLossyFlag( imageori.IsLossy() ); + // FIXME what is overlay is in pixel data ? + gdcm::DataElement pixeldata( gdcm::Tag(0x7fe0,0x0010) ); + gdcm::ByteValue *bv = new gdcm::ByteValue(); + bv->SetLength( (uint32_t)len ); + //memcpy( bv->GetPointer(), imageori + imageori.GetBuffer( (char*)bv->GetPointer() ); + // Rub out pixels: + char *p = (char*)bv->GetPointer(); + switch(pixeltype) + { + case gdcm::PixelFormat::UINT8: + FillRegionWithColor ((uint8_t*)p, dims, region, color, pixeltype.GetSamplesPerPixel()); + break; + case gdcm::PixelFormat::INT8: + FillRegionWithColor ((int8_t*)p, dims, region, color, pixeltype.GetSamplesPerPixel()); + break; + case gdcm::PixelFormat::UINT16: + FillRegionWithColor((uint16_t*)p, dims, region, color, pixeltype.GetSamplesPerPixel()); + break; + case gdcm::PixelFormat::INT16: + FillRegionWithColor ((int16_t*)p, dims, region, color, pixeltype.GetSamplesPerPixel()); + break; + default: + std::cerr << "not implemented" << std::endl; + return 1; + } + + pixeldata.SetValue( *bv ); + image->SetDataElement( pixeldata ); + const gdcm::TransferSyntax &ts = imageori.GetTransferSyntax(); + // FIXME: for now we do not know how to recompress the image... + if( ts.IsExplicit() ) + { + image->SetTransferSyntax( gdcm::TransferSyntax::ExplicitVRLittleEndian ); + } + else + { + assert( ts.IsImplicit() ); + image->SetTransferSyntax( gdcm::TransferSyntax::ImplicitVRLittleEndian ); + } + //imageori.Print( std::cout ); + //image.Print( std::cout ); + + // Set our filled image instead: + writer.SetImage( *image ); +#if 0 + // + gdcm::Attribute<0x0028,0x0301> at; + at.SetValue( "NO" ); // 'YES' + ds.Replace( at.GetAsDataElement() ); + // (0008,2111) ST [MedCom Resample v] # 18, 1 DerivationDescriptio + gdcm::Attribute<0x0008,0x2111> at2; + std::ostringstream os; + os << "Fill Region [" + << region[0] << "," << region[1] << "," + << region[2] << "," << region[3] << "," + << region[4] << "," << region[5] << "] with color value=" << std::hex << (int)color; + at2.SetValue( os.str() ); + ds.Replace( at2.GetAsDataElement() ); +#else +#endif +/* +> 1. Replace Value #1 of Image Type by 'DERIVED' + +Don't do that ... leave Image Type alone (unless you are changing +the UID ... vide infra). +*/ +#if 0 + // (0008,0008) CS [ORIGINAL\SECONDARY] # 18, 2 ImageType + gdcm::Attribute<0x0008,0x0008> at3; + static const gdcm::CSComp values[] = {"DERIVED","SECONDARY"}; + at3.SetValues( values, 2, true ); // true => copy data ! + if( ds.FindDataElement( at3.GetTag() ) ) + { + const gdcm::DataElement &de = ds.GetDataElement( at3.GetTag() ); + at3.SetFromDataElement( de ); + // Make sure that value #1 is at least 'DERIVED', so override in all cases: + at3.SetValue( 0, values[0] ); + } + ds.Replace( at3.GetAsDataElement() ); +#endif + // Make sure to recompute Planar Configuration: + ds.Remove( gdcm::Tag(0x0028, 0x0004) ); + } + // ds.Remove( gdcm::Tag(0x0,0x0) ); // FIXME + + if( !writer.Write() ) + { + std::cerr << "Failed to write: " << outfilename << std::endl; + return 1; + } + + return 0; +} diff --git a/gdcm/Applications/Cxx/gdcminfo.cxx b/gdcm/Applications/Cxx/gdcminfo.cxx new file mode 100644 index 0000000..6f52cd9 --- /dev/null +++ b/gdcm/Applications/Cxx/gdcminfo.cxx @@ -0,0 +1,747 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + * TODO: + * Should implement the gdcmiodvfy here + * I need to implement gdcmoverlay here (print info on overlay / img / LUT ...) + */ +#include "gdcmReader.h" +#include "gdcmImageReader.h" +#include "gdcmMediaStorage.h" +#include "gdcmFile.h" +#include "gdcmDataSet.h" +#include "gdcmUIDs.h" +#include "gdcmGlobal.h" +#include "gdcmModules.h" +#include "gdcmDefs.h" +#include "gdcmOrientation.h" +#include "gdcmVersion.h" +#include "gdcmMD5.h" +#include "gdcmSystem.h" +#include "gdcmDirectory.h" + +#ifdef GDCM_USE_SYSTEM_POPPLER +#include +#include +#include +#include +#include +#endif // GDCM_USE_SYSTEM_POPPLER + +#include "puff.h" + +#include + +#include /* for printf */ +#include +#include /* for exit */ +#include +#include +#include +#include + + +static int checkmagick(unsigned char *input) +{ + if( input[128+0] == 'D' + && input[128+1] == 'I' + && input[128+2] == 'C' + && input[128+3] == 'M' ) + { + return 1; + } + return 0; +} + +static int checkdeflated(const char *name) +{ + int ret; + unsigned char *source; + unsigned long len, sourcelen, destlen; + + unsigned long size; + unsigned long size1; + unsigned char *buf; + FILE *in; + struct stat s; + //const char *name = 0; + union { uint32_t tag; uint16_t tags[2]; char bytes[4]; } tag; + char vr[3]; + uint16_t vl; + uint32_t value; + + //if (argc < 2) return 2; + //name = argv[1]; + + len = 0; + if (stat(name, &s)) + { + fprintf( stderr, "Cannot stat: %s\n", name ); + return 1; + } + if ((s.st_mode & S_IFMT) != S_IFREG) + { + fprintf( stderr, "not a regular file\n" ); + return 1; + } + size = (unsigned long)(s.st_size); + if (size == 0 || (off_t)size != s.st_size) + { + fprintf( stderr, "size mismatch\n" ); + return 1; + } + in = fopen(name, "r"); + if (in == NULL) + { + fprintf( stderr, "in is NULL\n" ); + return 1; + } + buf = (unsigned char*)malloc(size); + if (buf != NULL && (size1 = fread(buf, 1, size, in)) != size) { + free(buf); + buf = NULL; + fprintf( stderr, "could not fread: %lu bytes != %lu\n", size, size1 ); + fprintf( stderr, "feof: %i ferror %i\n", feof(in), ferror(in) ); + } + fclose(in); + len = size; + source = buf; + if( source == NULL ) { + fprintf( stderr, "source is NULL\n" ); + return 1; + } + sourcelen = len; + + if( !checkmagick(source) ) + { + fprintf( stderr, "checkmagick failed\n" ); + return 1; + } + // magick succeed so skip header: + source += 128 + 4; + sourcelen -= 128 + 4; + + memcpy(&tag, source, sizeof(tag) ); + fprintf( stdout,"tag: %d, %d\n", tag.tags[0], tag.tags[1] ); + source += sizeof(tag); + sourcelen -= sizeof(tag); + + vr[2] = 0; + memcpy(vr, source, 2); + printf( "vr: %s\n", vr); + + source += 2; + sourcelen -= 2; + + memcpy(&vl, source, sizeof(vl)); + printf( "vl: %d\n", vl); + + source += sizeof(vl); + sourcelen -= sizeof(vl); + + memcpy(&value, source, sizeof(value)); + printf( "value: %d\n", value); + + source += sizeof(value); + sourcelen -= sizeof(value); + + source += value; + sourcelen -= value; + + len = sourcelen; + if( len % 2 ) + { + printf( "len of bit stream is odd: %lu. Continuing anyway\n", len ); + } + else + { + printf( "deflate stream has proper length: %lu\n", len ); + } + + ret = puff(NULL, &destlen, source, &sourcelen); + + if (ret) + fprintf(stdout,"puff() failed with return code %d\n", ret); + else { + fprintf(stdout,"puff() succeeded uncompressing %lu bytes\n", destlen); + if (sourcelen < len) printf("%lu compressed bytes unused\n", + len - sourcelen); + } + free(buf); + return ret; +} + +#ifdef GDCM_USE_SYSTEM_POPPLER +static std::string getInfoDate(Dict *infoDict, const char *key) +{ + Object obj; + char *s; + int year, mon, day, hour, min, sec, n; + struct tm tmStruct; + //char buf[256]; + std::string out; + + if (infoDict->lookup((char*)key, &obj)->isString()) + { + s = obj.getString()->getCString(); + if (s[0] == 'D' && s[1] == ':') + { + s += 2; + } + if ((n = sscanf(s, "%4d%2d%2d%2d%2d%2d", + &year, &mon, &day, &hour, &min, &sec)) >= 1) + { + switch (n) + { + case 1: mon = 1; + case 2: day = 1; + case 3: hour = 0; + case 4: min = 0; + case 5: sec = 0; + } + tmStruct.tm_year = year - 1900; + tmStruct.tm_mon = mon - 1; + tmStruct.tm_mday = day; + tmStruct.tm_hour = hour; + tmStruct.tm_min = min; + tmStruct.tm_sec = sec; + tmStruct.tm_wday = -1; + tmStruct.tm_yday = -1; + tmStruct.tm_isdst = -1; +/* + // compute the tm_wday and tm_yday fields + if (mktime(&tmStruct) != (time_t)-1 && + strftime(buf, sizeof(buf), "%c", &tmStruct)) { + fputs(buf, stdout); + } else { + fputs(s, stdout); + } + } else { + fputs(s, stdout); +*/ + } + //fputc('\n', stdout); + char date[22]; + time_t t = mktime(&tmStruct); + if( t != -1 ) + { + if( gdcm::System::FormatDateTime(date, t) ) + out = date; + } + } + obj.free(); + return out; +} + +static std::string getInfoString(Dict *infoDict, const char *key, UnicodeMap *uMap) +{ + Object obj; + GooString *s1; + GBool isUnicode; + Unicode u; + char buf[8]; + int i, n; + std::string out; + + if (infoDict->lookup((char*)key, &obj)->isString()) + { + s1 = obj.getString(); + if ((s1->getChar(0) & 0xff) == 0xfe && + (s1->getChar(1) & 0xff) == 0xff) + { + isUnicode = gTrue; + i = 2; + } + else + { + isUnicode = gFalse; + i = 0; + } + while (i < obj.getString()->getLength()) + { + if (isUnicode) + { + u = ((s1->getChar(i) & 0xff) << 8) | + (s1->getChar(i+1) & 0xff); + i += 2; + } + else + { + u = pdfDocEncoding[s1->getChar(i) & 0xff]; + ++i; + } + n = uMap->mapUnicode(u, buf, sizeof(buf)); + //fwrite(buf,1,n,stdout); + out.append( std::string(buf, n) ); + } + } + obj.free(); + return out; +} +#endif + + +static void PrintVersion() +{ + std::cout << "gdcminfo: gdcm " << gdcm::Version::GetVersion() << " "; + const char date[] = "$Date$"; + std::cout << date << std::endl; +} + +static void PrintHelp() +{ + PrintVersion(); + std::cout << "Usage: gdcminfo [OPTION]... FILE..." << std::endl; + std::cout << "display meta info about the input DICOM file" << std::endl; + std::cout << "Parameter:" << std::endl; + std::cout << " -i --input DICOM filename or directory" << std::endl; + std::cout << "Options:" << std::endl; + std::cout << " -r --recursive recursive." << std::endl; + std::cout << " -d --check-deflated check if file is proper deflated syntax." << std::endl; + std::cout << " --resources-path Resources path." << std::endl; + std::cout << " --md5sum Compute md5sum of Pixel Data attribute value." << std::endl; + std::cout << " --check-compression check the encapsulated stream compression (lossless/lossy)." << std::endl; + // the following options would require an advanced MediaStorage::SetFromFile ... sigh + //std::cout << " --media-storage-uid return media storage uid only." << std::endl; + //std::cout << " --media-storage-name return media storage name only (when possible)." << std::endl; +// std::cout << " -b --check-big-endian check if file is ." << std::endl; + std::cout << "General Options:" << std::endl; + std::cout << " -V --verbose more verbose (warning+error)." << std::endl; + std::cout << " -W --warning print warning info." << std::endl; + std::cout << " -D --debug print debug info." << std::endl; + std::cout << " -E --error print error info." << std::endl; + std::cout << " -h --help print help." << std::endl; + std::cout << " -v --version print version." << std::endl; + std::cout << "Env var:" << std::endl; + std::cout << " GDCM_RESOURCES_PATH path pointing to resources files (Part3.xml, ...)" << std::endl; +} + + int deflated = 0; // check deflated + int checkcompression = 0; + int md5sum = 0; + +static int ProcessOneFile( std::string const & filename, gdcm::Defs const & defs ) +{ + (void)defs; + if( deflated ) + { + return checkdeflated(filename.c_str()); + } + + //const char *filename = argv[1]; + //std::cout << "filename: " << filename << std::endl; + gdcm::Reader reader0; + reader0.SetFileName( filename.c_str() ); + if( !reader0.Read() ) + { + std::cerr << "Failed to read: " << filename << std::endl; + return 1; + } + const gdcm::File &file = reader0.GetFile(); + gdcm::MediaStorage ms; + ms.SetFromFile(file); + /* + * Until gdcm::MediaStorage is fixed only *compile* time constant will be handled + * see -> http://chuckhahm.com/Ischem/Zurich/XX_0134 + * which make gdcm::UIDs useless :( + */ + if( ms.IsUndefined() ) + { + std::cerr << "Unknown MediaStorage" << std::endl; + return 1; + } + + gdcm::UIDs uid; + uid.SetFromUID( ms.GetString() ); + std::cout << "MediaStorage is " << ms << " [" << uid.GetName() << "]" << std::endl; + const gdcm::TransferSyntax &ts = file.GetHeader().GetDataSetTransferSyntax(); + uid.SetFromUID( ts.GetString() ); + std::cout << "TransferSyntax is " << ts << " [" << uid.GetName() << "]" << std::endl; + + if( gdcm::MediaStorage::IsImage( ms ) ) + { + gdcm::ImageReader reader; + reader.SetFileName( filename.c_str() ); + if( !reader.Read() ) + { + std::cerr << "Could not read image from: " << filename << std::endl; + return 1; + } + //const gdcm::File &file = reader.GetFile(); + //const gdcm::DataSet &ds = file.GetDataSet(); + const gdcm::Image &image = reader.GetImage(); + const double *dircos = image.GetDirectionCosines(); + gdcm::Orientation::OrientationType type = gdcm::Orientation::GetType(dircos); + const char *label = gdcm::Orientation::GetLabel( type ); + image.Print( std::cout ); + std::cout << "Orientation Label: " << label << std::endl; + if( checkcompression ) + { + bool lossy = image.IsLossy(); + std::cout << "Encapsulated Stream was found to be: " << (lossy ? "lossy" : "lossless") << std::endl; + } + + if( md5sum ) + { + char *buffer = new char[ image.GetBufferLength() ]; + if( image.GetBuffer( buffer ) ) + { + char digest[33] = {}; + gdcm::MD5::Compute( buffer, image.GetBufferLength(), digest ); + std::cout << "md5sum: " << digest << std::endl; + } + else + { + std::cout << "Problem decompressing file: " << filename << std::endl; + } + delete[] buffer; + } + } + else if ( ms == gdcm::MediaStorage::EncapsulatedPDFStorage ) + { +#ifdef GDCM_USE_SYSTEM_POPPLER + const gdcm::DataSet &ds = file.GetDataSet(); + const gdcm::DataElement& de = ds.GetDataElement( gdcm::Tag(0x42,0x11) ); + const gdcm::ByteValue* bv = de.GetByteValue(); + const char *p = bv->GetPointer(); (void)p; + Object appearDict; + //appearDict.initDict(xref); + //appearDict.dictAdd(copyString("Length"), + // obj1.initInt(appearBuf->getLength())); + //appearDict.dictAdd(copyString("Subtype"), obj1.initName("Form")); + //obj1.initArray(xref); + //obj1.arrayAdd(obj2.initReal(0)); + //obj1.arrayAdd(obj2.initReal(0)); + //obj1.arrayAdd(obj2.initReal(xMax - xMin)); + //obj1.arrayAdd(obj2.initReal(yMax - yMin)); + //appearDict.dictAdd(copyString("BBox"), &obj1); + + MemStream *appearStream; + + appearStream = new MemStream((char*)bv->GetPointer(), 0, + bv->GetLength(), &appearDict); + GooString *ownerPW, *userPW; + ownerPW = NULL; + userPW = NULL; + + PDFDoc *doc; + doc = new PDFDoc(appearStream, ownerPW, userPW); + + std::string title; + std::string subject; + std::string keywords; + std::string author; + std::string creator; + std::string producer; + std::string creationdate; + std::string moddate; + + UnicodeMap *uMap; +#ifdef LIBPOPPLER_GLOBALPARAMS_CSTOR_HAS_PARAM + globalParams = new GlobalParams(0); +#else + globalParams = new GlobalParams(); +#endif + uMap = globalParams->getTextEncoding(); + + Object info; + if (doc->isOk()) + { + doc->getDocInfo(&info); + if (info.isDict()) + { + title = getInfoString(info.getDict(), "Title", uMap); + subject = getInfoString(info.getDict(), "Subject", uMap); + keywords = getInfoString(info.getDict(), "Keywords", uMap); + author = getInfoString(info.getDict(), "Author", uMap); + creator = getInfoString(info.getDict(), "Creator", uMap); + producer = getInfoString(info.getDict(), "Producer", uMap); + creationdate = getInfoDate( info.getDict(), "CreationDate" ); + moddate = getInfoDate( info.getDict(), "ModDate" ); + info.free(); + } + const char *tagged = doc->getStructTreeRoot()->isDict() ? "yes" : "no"; + int pages = doc->getNumPages(); + const char *encrypted = doc->isEncrypted() ? "yes" : "no"; + // printf("yes (print:%s copy:%s change:%s addNotes:%s)\n", + // doc->okToPrint(gTrue) ? "yes" : "no", + // doc->okToCopy(gTrue) ? "yes" : "no", + // doc->okToChange(gTrue) ? "yes" : "no", + // doc->okToAddNotes(gTrue) ? "yes" : "no"); + + // print linearization info + const char *optimized = doc->isLinearized() ? "yes" : "no"; + + // print PDF version +#ifdef LIBPOPPLER_PDFDOC_HAS_PDFVERSION + float pdfversion = doc->getPDFVersion(); +#else + const double pdfversion = doc->getPDFMajorVersion() + 0.1 * doc->getPDFMinorVersion(); +#endif + + + // print page count + printf("Pages: %d\n", doc->getNumPages()); + + std::cout << "PDF Info:" << std::endl; + std::cout << " Title: " << title << std::endl; + std::cout << " Subject: " << subject << std::endl; + std::cout << " Keywords: " << keywords << std::endl; + std::cout << " Author: " << author << std::endl; + std::cout << " Creator: " << creator << std::endl; + std::cout << " Producer: " << producer << std::endl; + std::cout << " CreationDate: " << creationdate << std::endl; + std::cout << " ModDate: " << moddate << std::endl; + std::cout << " Tagged: " << tagged << std::endl; + std::cout << " Pages: " << pages << std::endl; + std::cout << " Encrypted: " << encrypted << std::endl; + //std::cout << "Page size: " << subject << std::endl; + std::cout << " File size: " << bv->GetLength() << std::endl; + std::cout << " Optimized: " << optimized << std::endl; + std::cout << " PDF version: " << pdfversion << std::endl; + } + else + { + std::cout << "Problem reading Encapsulated PDF " << std::endl; + } + +#else // GDCM_USE_SYSTEM_POPPLER + std::cout << " Encapsulated PDF File" << std::endl; +#endif // GDCM_USE_SYSTEM_POPPLER + } + // Do the IOD verification ! + //bool v = defs.Verify( file ); + //std::cerr << "IOD Verification: " << (v ? "succeed" : "failed") << std::endl; + + return 0; +} + + +int main(int argc, char *argv[]) +{ + int c; + std::string filename; + std::string xmlpath; + int resourcespath = 0; + int verbose = 0; + int warning = 0; + int help = 0; + int recursive = 0; + int version = 0; + int debug = 0; + int error = 0; + while (1) { + int option_index = 0; + static struct option long_options[] = { + {"input", 1, 0, 0}, + {"recursive", 0, &recursive, 1}, + {"check-deflated", 0, &deflated, 1}, + {"resources-path", 0, &resourcespath, 1}, + {"md5sum", 0, &md5sum, 1}, + {"check-compression", 0, &checkcompression, 1}, + + {"verbose", 0, &verbose, 1}, + {"warning", 0, &warning, 1}, + {"debug", 0, &debug, 1}, + {"error", 0, &error, 1}, + {"help", 0, &help, 1}, + {"version", 0, &version, 1}, + {0, 0, 0, 0} // required + }; + static const char short_options[] = "i:rdVWDEhv"; + c = getopt_long (argc, argv, short_options, + long_options, &option_index); + if (c == -1) + { + break; + } + + switch (c) + { + case 0: + case '-': + { + const char *s = long_options[option_index].name; (void)s; + //printf ("option %s", s); + if (optarg) + { + if( option_index == 0 ) /* input */ + { + assert( strcmp(s, "input") == 0 ); + assert( filename.empty() ); + filename = optarg; + } + else if( option_index == 3 ) /* resources-path */ + { + assert( strcmp(s, "resources-path") == 0 ); + assert( xmlpath.empty() ); + xmlpath = optarg; + } + //printf (" with arg %s", optarg); + } + //printf ("\n"); + } + break; + + case 'i': + //printf ("option i with value '%s'\n", optarg); + assert( filename.empty() ); + filename = optarg; + break; + + case 'r': + recursive = 1; + break; + + case 'd': + deflated = 1; + break; + + case 'V': + verbose = 1; + break; + + case 'W': + warning = 1; + break; + + case 'D': + debug = 1; + break; + + case 'E': + error = 1; + break; + + case 'h': + help = 1; + break; + + case 'v': + version = 1; + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + //printf ("non-option ARGV-elements: %d", optind ); + //while (optind < argc) + // { + // printf ("%s\n", argv[optind++]); + // } + //printf ("\n"); + // Ok there is only one arg, easy, it's the filename: + int v = argc - optind; + if( v == 1 ) + { + filename = argv[optind]; + } + } + + if( version ) + { + //std::cout << "version" << std::endl; + PrintVersion(); + return 0; + } + + if( help ) + { + //std::cout << "help" << std::endl; + PrintHelp(); + return 0; + } + + if( filename.empty() ) + { + //std::cerr << "Need input file (-i)\n"; + PrintHelp(); + return 1; + } + + // Debug is a little too verbose + gdcm::Trace::SetDebug( debug != 0); + gdcm::Trace::SetWarning( warning != 0); + gdcm::Trace::SetError( error != 0); + // when verbose is true, make sure warning+error are turned on: + if( verbose ) + { + gdcm::Trace::SetWarning( verbose != 0); + gdcm::Trace::SetError( verbose != 0); + } + + if( !gdcm::System::FileExists(filename.c_str()) ) + { + return 1; + } + + gdcm::Global& g = gdcm::Global::GetInstance(); + // First thing we need to locate the XML dict + // did the user requested to look XML file in a particular directory ? + if( !resourcespath ) + { + const char *xmlpathenv = getenv("GDCM_RESOURCES_PATH"); + if( xmlpathenv ) + { + // Make sure to look for XML dict in user explicitly specified dir first: + xmlpath = xmlpathenv; + resourcespath = 1; + } + } + if( resourcespath ) + { + // xmlpath is set either by the cmd line option or the env var + if( !g.Prepend( xmlpath.c_str() ) ) + { + std::cerr << "specified Resources Path is not valid: " << xmlpath << std::endl; + return 1; + } + } + + // All set, then load the XML files: + if( !g.LoadResourcesFiles() ) + { + std::cerr << "Could not load XML file from specified path" << std::endl; + return 1; + } + + const gdcm::Defs &defs = g.GetDefs(); + + int res = 0; + if( gdcm::System::FileIsDirectory(filename.c_str()) ) + { + gdcm::Directory d; + d.Load(filename, recursive!= 0); + gdcm::Directory::FilenamesType const &filenames = d.GetFilenames(); + for( gdcm::Directory::FilenamesType::const_iterator it = filenames.begin(); it != filenames.end(); ++it ) + { + std::cout << "filename: " << *it << std::endl; + res += ProcessOneFile(*it, defs); + } + } + else + { + res += ProcessOneFile( filename, defs ); + } + + + return res; +} diff --git a/gdcm/Applications/Cxx/gdcmkey.cxx b/gdcm/Applications/Cxx/gdcmkey.cxx new file mode 100644 index 0000000..ab829d8 --- /dev/null +++ b/gdcm/Applications/Cxx/gdcmkey.cxx @@ -0,0 +1,34 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +// DCKEY(1) DICOM PS3 - Extract attribute values DCKEY(1) +// +// NAME +// dckey - ACR/NEMA DICOM PS3 ... Extract attribute values +// +// SYNOPSIS +// dckey [ -v|verbose ] [ -describe ] [ -key|k attributename +// ] +// +// DESCRIPTION +// dckey reads the named dicom input file and displays the +// values of the selected attributes. +// +// Binary attributes are written in hexadecimal with a pre- +// ceding "0x". Numeric string attributes are written in dec- +// imal. +// +int main(int argc, char *argv[]) +{ + return 0; +} diff --git a/gdcm/Applications/Cxx/gdcmoverlay.cxx b/gdcm/Applications/Cxx/gdcmoverlay.cxx new file mode 100644 index 0000000..120874b --- /dev/null +++ b/gdcm/Applications/Cxx/gdcmoverlay.cxx @@ -0,0 +1,192 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#include "gdcmReader.h" +#include "gdcmImageReader.h" +#include "gdcmFileMetaInformation.h" +#include "gdcmDataSet.h" +#include "gdcmPrinter.h" +#include "gdcmDictPrinter.h" +#include "gdcmValidate.h" +#include "gdcmWriter.h" +#include "gdcmDumper.h" +#include "gdcmSystem.h" +#include "gdcmDirectory.h" +#include "gdcmOverlay.h" + +#include +#include + +#include /* for printf */ +#include /* for exit */ +#include +#include + +template +int DoOperation(const std::string & filename) +{ + gdcm::ImageReader reader; + reader.SetFileName( filename.c_str() ); + if( !reader.Read() ) + { + std::cerr << "Failed to read: " << filename << std::endl; + return 1; + } + + // Image part: + const gdcm::Image& img = reader.GetImage(); + img.Print( std::cout ); + + // Overlay part: + unsigned int n = reader.GetImage().GetNumberOfOverlays(); + std::cout << "Num of Overlays: " << n << std::endl; + for(unsigned int i = 0; i < n; ++i ) + { + const gdcm::Overlay& o = reader.GetImage().GetOverlay(i); + o.Print( std::cout ); + } + + return 0; +} + + + +int main (int argc, char *argv[]) +{ + int c; + //int digit_optind = 0; + + std::string filename; + bool printdict = false; + bool verbose = false; + while (1) { + //int this_option_optind = optind ? optind : 1; + int option_index = 0; + static struct option long_options[] = { + {"input", 1, 0, 0}, + {"output", 1, 0, 0}, + {"dict", 1, 0, 0}, + {"verbose", 1, 0, 0}, + {0, 0, 0, 0} + }; + + c = getopt_long (argc, argv, "i:o:dv", + long_options, &option_index); + if (c == -1) + { + break; + } + + switch (c) + { + case 0: + { + const char *s = long_options[option_index].name; + printf ("option %s", s); + if (optarg) + { + if( option_index == 0 ) /* input */ + { + assert( strcmp(s, "input") == 0 ); + assert( filename.empty() ); + filename = optarg; + } + printf (" with arg %s", optarg); + } + printf ("\n"); + } + break; + + case 'i': + //printf ("option i with value '%s'\n", optarg); + assert( filename.empty() ); + filename = optarg; + break; + + case 'o': + printf ("option o with value '%s'\n", optarg); + break; + + case 'd': + //printf ("option d with value '%s'\n", optarg); + printdict = true; + break; + + case 'v': + //printf ("option d with value '%s'\n", optarg); + verbose = true; + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + { + printf ("%s ", argv[optind++]); + } + printf ("\n"); + } + + if( filename.empty() ) + { + std::cerr << "Need input file (-i)\n"; + return 1; + } + // else + int res = 0; + if( gdcm::System::FileIsDirectory( filename.c_str() ) ) + { + gdcm::Directory d; + d.Load(filename); + gdcm::Directory::FilenamesType const &filenames = d.GetFilenames(); + for( gdcm::Directory::FilenamesType::const_iterator it = filenames.begin(); it != filenames.end(); ++it ) + { + if( printdict ) + { + res += DoOperation(*it); + } + else + { + res += DoOperation(*it); + } + if( verbose ) std::cerr << *it << std::endl; + } + if( verbose ) std::cerr << "Total: " << filenames.size() << " files were processed" << std::endl; + } + else + { + assert( gdcm::System::FileExists(filename.c_str()) ); + if( printdict ) + { + res += DoOperation(filename); + } + else + { + res += DoOperation(filename); + } + // ... + if ( verbose ) + std::cerr << "Filename: " << filename << std::endl; + } + + return res; +} diff --git a/gdcm/Applications/Cxx/gdcmpap3.cxx b/gdcm/Applications/Cxx/gdcmpap3.cxx new file mode 100644 index 0000000..00831aa --- /dev/null +++ b/gdcm/Applications/Cxx/gdcmpap3.cxx @@ -0,0 +1,622 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + * Command line tool to deal with legacy PAPYRUS 3.0 file + * The command line tool can be compiled in two flavour: + * + * 1. without papyrus 3.0 (more portable) + * 2. with papyrus 3.0 + * + * The (2) is only required when dealing with invalid JPEG Lossless compressed + * PAPYRUS 3.0 files + */ +#include "gdcmReader.h" +#include "gdcmDirectionCosines.h" +#include "gdcmUIDGenerator.h" +#include "gdcmVersion.h" +#include "gdcmWriter.h" +#include "gdcmAttribute.h" +#include "gdcmTrace.h" +#include "gdcmImageHelper.h" +#include "gdcmSequenceOfItems.h" + +#include + +#ifdef GDCM_USE_SYSTEM_PAPYRUS3 +extern "C" { +#include +} +#endif + +static void PrintVersion() +{ + std::cout << "gdcmpap3: gdcm " << gdcm::Version::GetVersion() << " "; + const char date[] = "$Date$"; + std::cout << date << std::endl; +} + +static void PrintHelp() +{ + PrintVersion(); + std::cout << "Usage: gdcmpap3 [OPTION] input.pa3 output.dcm" << std::endl; + std::cout << "Convert a PAPYRUS 3.0 file into another DICOM file.\n"; + std::cout << "Parameter (required):" << std::endl; + std::cout << " -i --input PAPYRUS 3.0 filename" << std::endl; + std::cout << " -o --output DICOM filename" << std::endl; + std::cout << "Options:" << std::endl; + std::cout << " -S --split Split single PAPYRUS 3.0 file into multiples DICOM files." << std::endl; + std::cout << " --decomp-pap3 Use PAPYRUS 3.0 for decompressing (can be combined with --split)." << std::endl; + std::cout << " --check-iop Check that the Image Orientation (Patient) Attribute is ok (see --split)." << std::endl; + std::cout << " --root-uid Specify Root UID." << std::endl; + std::cout << "General Options:" << std::endl; + std::cout << " -V --verbose more verbose (warning+error)." << std::endl; + std::cout << " -W --warning print warning info." << std::endl; + std::cout << " -D --debug print debug info." << std::endl; + std::cout << " -E --error print error info." << std::endl; + std::cout << " -h --help print help." << std::endl; + std::cout << " -v --version print version." << std::endl; + std::cout << "Env var:" << std::endl; + std::cout << " GDCM_ROOT_UID Root UID" << std::endl; +} + +static bool InitPapyrus3( const char *filename, int & outfileNb) +{ + outfileNb = -1; +#ifdef GDCM_USE_SYSTEM_PAPYRUS3 + /* initialisation of the Papyrus toolkit v3.6 */ + Papy3Init(); + + /* open the pap3 file */ + PapyShort fileNb = Papy3FileOpen ((char*)filename, (PAPY_FILE) 0, TRUE, 0); + if( fileNb < 0 ) + { + PAPY3PRINTERRMSG(); + return false; + } + outfileNb = fileNb; + return true; +#else + (void)filename; + (void)outfileNb; + std::cerr << "No PAPYRUS 3.0 library found" << std::endl; + return false; +#endif +} + +static bool DecompressPapyrus3( int pap3handle, int itemnum, gdcm::TransferSyntax const & ts, gdcm::File & file ) +{ +#ifdef GDCM_USE_SYSTEM_PAPYRUS3 + PapyShort fileNb = (PapyShort)pap3handle; + PapyShort imageNb = (PapyShort)(itemnum + 1); + + if( ts == gdcm::TransferSyntax::JPEGLosslessProcess14_1 ) + { + SElement *group; + PapyUShort *theImage; + + std::vector dims = gdcm::ImageHelper::GetDimensionsValue(file); + gdcm::PixelFormat pf = gdcm::ImageHelper::GetPixelFormatValue(file); + + gdcm::DataSet & nested = file.GetDataSet(); + + /* position the file pointer to the begining of the data set */ + PapyShort err = Papy3GotoNumber (fileNb, (PapyShort)imageNb, DataSetID); + + gdcm::DataElement pixeldata( gdcm::Tag(0x7fe0,0x0010) ); + + /* then goto group 0x7FE0 */ + if ((err = Papy3GotoGroupNb (fileNb, 0x7FE0)) == 0) + { + /* read group 0x7FE0 from the file */ + if ((err = Papy3GroupRead (fileNb, &group)) > 0) + { + /* PIXEL DATA */ + theImage = (PapyUShort *)Papy3GetPixelData (fileNb, imageNb, group, ImagePixel); + + //assert( dims[0] == 512 ); + //assert( dims[1] == 512 ); + //assert( pf.GetPixelSize() == 2 ); + const size_t imglen = dims[0] * dims[1] * pf.GetPixelSize(); + pixeldata.SetByteValue( (char*)theImage, (uint32_t)imglen ); + + /* free group 7FE0 */ + err = Papy3GroupFree (&group, TRUE); + } /* endif ...group 7FE0 read */ + else + { + PAPY3PRINTERRMSG (); + } + } /* endif ...group 7FE0 found */ + else + { + PAPY3PRINTERRMSG (); + } + nested.Replace( pixeldata ); + } + else + { + std::cerr << "TransferSyntax: " << ts << " is not handled at this point" << std::endl; + return false; + } + return true; +#else + (void)pap3handle; (void)itemnum; (void)ts; (void)file; + std::cerr << "No PAPYRUS 3.0 library found" << std::endl; + return false; +#endif +} + +static bool CleanupPapyrus3( int pap3handle ) +{ +#ifdef GDCM_USE_SYSTEM_PAPYRUS3 + PapyShort fileNb = (PapyShort)pap3handle; + /* close and free the file and the associated allocated memory */ + Papy3FileClose (fileNb, TRUE); + + /* free the allocated global value in the toolkit */ + Papy3FreeDataSetModules (); + + return true; +#else + (void)pap3handle; + return false; +#endif +} + +int main(int argc, char *argv[]) +{ + int c; + + std::string filename; + std::string outfilename; + std::string root; + int rootuid = 0; + int split = 0; + int decomp_pap3 = 0; + int check_iop = 0; + + int verbose = 0; + int warning = 0; + int debug = 0; + int error = 0; + int help = 0; + int version = 0; + + while (1) { + int option_index = 0; + static struct option long_options[] = { + {"input", 1, 0, 0}, + {"output", 1, 0, 0}, + {"root-uid", 1, &rootuid, 1}, // specific Root (not GDCM) + {"split", 0, &split, 1}, + {"decomp-pap3", 0, &decomp_pap3, 1}, + {"check-iop", 0, &check_iop, 1}, + +// General options ! + {"verbose", 0, &verbose, 1}, + {"warning", 0, &warning, 1}, + {"debug", 0, &debug, 1}, + {"error", 0, &error, 1}, + {"help", 0, &help, 1}, + {"version", 0, &version, 1}, + + {0, 0, 0, 0} + }; + + c = getopt_long (argc, argv, "i:o:S:VWDEhv", + long_options, &option_index); + if (c == -1) + { + break; + } + + switch (c) + { + case 0: + { + const char *s = long_options[option_index].name; (void)s; + //printf ("option %s", s); + if (optarg) + { + if( option_index == 0 ) /* input */ + { + assert( strcmp(s, "input") == 0 ); + assert( filename.empty() ); + filename = optarg; + } + else if( option_index == 1 ) /* output */ + { + assert( strcmp(s, "output") == 0 ); + assert( outfilename.empty() ); + outfilename = optarg; + } + else if( option_index == 2 ) /* root-uid */ + { + assert( strcmp(s, "root-uid") == 0 ); + root = optarg; + } + //printf (" with arg %s, index = %d", optarg, option_index); + } + //printf ("\n"); + } + break; + + case 'i': + //printf ("option i with value '%s'\n", optarg); + assert( filename.empty() ); + filename = optarg; + break; + + case 'o': + //printf ("option o with value '%s'\n", optarg); + assert( outfilename.empty() ); + outfilename = optarg; + break; + + // + case 'S': + split = 1; + break; + + // General option + case 'V': + verbose = 1; + break; + + case 'W': + warning = 1; + break; + + case 'D': + debug = 1; + break; + + case 'E': + error = 1; + break; + + case 'h': + help = 1; + break; + + case 'v': + version = 1; + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + // For now only support one input / one output + if (optind < argc) + { + //printf ("non-option ARGV-elements: "); + std::vector files; + while (optind < argc) + { + //printf ("%s\n", argv[optind++]); + files.push_back( argv[optind++] ); + } + //printf ("\n"); + if( files.size() == 2 + && filename.empty() + && outfilename.empty() + ) + { + filename = files[0]; + outfilename = files[1]; + } + else + { + PrintHelp(); + return 1; + } + } + + if( version ) + { + //std::cout << "version" << std::endl; + PrintVersion(); + return 0; + } + + if( help ) + { + //std::cout << "help" << std::endl; + PrintHelp(); + return 0; + } + + if( filename.empty() ) + { + //std::cerr << "Need input file (-i)\n"; + PrintHelp(); + return 1; + } + if( outfilename.empty() ) + { + //std::cerr << "Need output file (-o)\n"; + PrintHelp(); + return 1; + } + + // Debug is a little too verbose + gdcm::Trace::SetDebug( (debug > 0 ? true : false)); + gdcm::Trace::SetWarning( (warning > 0 ? true : false)); + gdcm::Trace::SetError( (error > 0 ? true : false)); + // when verbose is true, make sure warning+error are turned on: + if( verbose ) + { + gdcm::Trace::SetWarning( (verbose > 0 ? true : false) ); + gdcm::Trace::SetError( (verbose > 0 ? true : false) ); + } + + gdcm::FileMetaInformation::SetSourceApplicationEntityTitle( "gdcmpap3" ); + if( !rootuid ) + { + // only read the env var is no explicit cmd line option + // maybe there is an env var defined... let's check + const char *rootuid_env = getenv("GDCM_ROOT_UID"); + if( rootuid_env ) + { + rootuid = 1; + root = rootuid_env; + } + } + if( rootuid ) + { + // root is set either by the cmd line option or the env var + if( !gdcm::UIDGenerator::IsValid( root.c_str() ) ) + { + std::cerr << "specified Root UID is not valid: " << root << std::endl; + return 1; + } + gdcm::UIDGenerator::SetRoot( root.c_str() ); + } + + gdcm::Reader reader; + reader.SetFileName( filename.c_str() ); + if( !reader.Read() ) + { + std::cerr << "Could not read: " << filename << std::endl; + return 1; + } + + gdcm::File & file = reader.GetFile(); + gdcm::FileMetaInformation & header = file.GetHeader(); + gdcm::DataSet & ds = file.GetDataSet(); + + gdcm::MediaStorage ms = header.GetMediaStorage(); (void)ms; + const gdcm::TransferSyntax & ts = header.GetDataSetTransferSyntax(); + //std::cout << ts << std::endl; + std::string msstr = header.GetMediaStorageAsString(); + //std::cout << msstr << std::endl; + + int pap3handle; + if( decomp_pap3 ) + { + if( !InitPapyrus3( filename.c_str(), pap3handle ) ) + { + std::cerr << "Problem during init of PAPYRUS 3.0. File was: " << filename << std::endl; + return 1; + } + } + + gdcm::PrivateTag pt(0x0041,0x50,"PAPYRUS 3.0"); + const gdcm::DataElement &depap = ds.GetDataElement( pt ); + gdcm::SmartPointer sq = depap.GetValueAsSQ(); + + if( !split ) + { + gdcm::Writer w; + w.CheckFileMetaInformationOff(); + w.SetFileName( outfilename.c_str() ); + w.SetFile( reader.GetFile() ); + + if( decomp_pap3 ) + { + gdcm::TransferSyntax outts = ts; + for( gdcm::SequenceOfItems::SizeType i = 0; i < sq->GetNumberOfItems(); ++i ) + { + gdcm::Item & it = sq->GetItem( i + 1 ); + gdcm::DataSet & nested = it.GetNestedDataSet(); + gdcm::File f; + f.SetDataSet( nested ); + if( !DecompressPapyrus3( pap3handle, i, ts, f ) ) + { + std::cerr << "Could not decompress frame #" << i << " from file: " << filename << std::endl; + return 1; + } + const gdcm::DataElement & pixeldata = f.GetDataSet().GetDataElement( gdcm::Tag(0x7fe0,0x0010) ); + nested.Replace( pixeldata ); + } + + // make sq as undefined length (avoid length computation): + gdcm::DataElement de_dup = depap; + de_dup.SetValue( *sq ); + de_dup.SetVLToUndefined(); + ds.Replace( de_dup ); + + gdcm::FileMetaInformation & h = w.GetFile().GetHeader(); + // pap3 returns image as decompressed: + outts = gdcm::TransferSyntax::ExplicitVRLittleEndian; + gdcm::Attribute<0x0002, 0x0010> TransferSyntaxUID; + const char *tsstr = gdcm::TransferSyntax::GetTSString( outts ); + TransferSyntaxUID.SetValue( tsstr ); + h.Replace( TransferSyntaxUID.GetAsDataElement() ); + gdcm::Attribute<0x0002, 0x0000> filemetagrouplength; + h.Remove( filemetagrouplength.GetTag() ); // important + unsigned int glen = h.GetLength(); + filemetagrouplength.SetValue( glen ); + h.Insert( filemetagrouplength.GetAsDataElement() ); + } + + if( !w.Write() ) + { + std::cerr << "Could not write output file: " << outfilename << std::endl; + return 1; + } + } + else + { + if( !gdcm::System::FileIsDirectory(outfilename.c_str()) ) + { + std::cerr << "Output is not a directory: " << outfilename << std::endl; + return 1; + } +#if 1 + gdcm::UIDGenerator uid; + + const std::string seriesstr = uid.Generate(); + + for( gdcm::SequenceOfItems::SizeType i = 0; i < sq->GetNumberOfItems(); ++i ) + { + gdcm::Item & it = sq->GetItem( i + 1 ); + gdcm::DataSet & nested = it.GetNestedDataSet(); + + std::stringstream ss; + ss << outfilename; + ss << "/IMG"; + ss << std::setw(4) << std::setfill( '0') << i; + ss << ".dcm"; + gdcm::Writer w; + // 1.2.840.10008.1.2.4.70 + w.CheckFileMetaInformationOn(); + const std::string & outfn = ss.str(); + w.SetFileName( outfn.c_str() ); + gdcm::TransferSyntax outts; +#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + if( ts == gdcm::TransferSyntax::WeirdPapryus ) + { + outts = gdcm::TransferSyntax::ImplicitVRLittleEndian; + } + else +#endif + { + outts = ts; + } + + w.GetFile().SetDataSet( nested ); + + if( decomp_pap3 ) + { + if( !DecompressPapyrus3( pap3handle, i, ts, w.GetFile() ) ) + { + std::cerr << "Could not decompress frame #" << i << " from file: " << filename << std::endl; + return 1; + } + // pap3 returns image as decompressed: + outts = gdcm::TransferSyntax::ExplicitVRLittleEndian; + } + w.GetFile().GetHeader().SetDataSetTransferSyntax( outts ); + + if( check_iop ) + { + bool erroriop = false; + std::vector iop_orig; + iop_orig.resize( 6 ); + // gdcm::ImageHelper::GetDirectionCosinesValue( w.GetFile() ); + if( !gdcm::ImageHelper::GetDirectionCosinesFromDataSet(w.GetFile().GetDataSet(), iop_orig) ) + { + erroriop = true; + gdcm::DirectionCosines dc( &iop_orig[0] ); + assert( !dc.IsValid() ); + { + gdcm::Attribute<0x0008,0x0008> imagetype; + imagetype.Set( w.GetFile().GetDataSet() ); + if( imagetype.GetNumberOfValues() > 2 ) + { + const std::string &str = imagetype.GetValue( 2 ); + gdcm::Attribute<0x0020,0x0037> at_axial = {{1,0,0,0,1,0}}; // default value for AXIAL + if( str == "AXIAL" ) + { + w.GetFile().GetDataSet().Replace( at_axial.GetAsDataElement() ); + erroriop = false; // error has been corrected + } + else if( str == "LOCALIZER" ) + { + static const double fake_axial[] = { 1, 0, 0, 0, 0, 0 }; + assert( memcmp( &iop_orig[0], fake_axial, 6 * sizeof( double ) ) == 0 ); (void)fake_axial; + w.GetFile().GetDataSet().Replace( at_axial.GetAsDataElement() ); + erroriop = false; // error has been corrected + } + } + assert( !erroriop ); // did our heuristic failed ? + } + } + if( erroriop ) + { + std::cerr << "Error IOP (could not correct) for frame #" << i << " value : (" + << iop_orig[0] << "," + << iop_orig[1] << "," + << iop_orig[2] << "," + << iop_orig[3] << "," + << iop_orig[4] << "," + << iop_orig[5] << ")" << std::endl; + return 1; + } + } + +#if 0 + gdcm::Attribute<0x0008,0x0016> outms; + outms.SetValue( "1.2.840.10008.5.1.4.1.1.2" ); + nested.Replace( outms.GetAsDataElement() ); + + gdcm::Attribute<0x028,0x0102> highbits = { 15 }; + nested.Replace( highbits.GetAsDataElement() ); + + gdcm::Attribute<0x0028,0x0030> pixelspacing = { 0.57, 0.57 }; + nested.Replace( pixelspacing.GetAsDataElement() ); + + gdcm::Attribute<0x0020,0x000e> seriesuid; + seriesuid.SetValue( seriesstr ); + nested.Insert( seriesuid.GetAsDataElement() ); // do not replace if exists + + gdcm::Attribute<0x0008,0x0018> instanceuid; + instanceuid.SetValue( uid.Generate() ); + nested.Replace( instanceuid.GetAsDataElement() ); + + // ??? + gdcm::Attribute<0x0020,0x0032> ipp = {{0,0, i * 0.57}}; // default value + nested.Replace( ipp.GetAsDataElement() ); + + gdcm::Attribute<0x0020,0x0037> iop = {{1,0,0,0,1,0}}; // default value + nested.Replace( iop.GetAsDataElement() ); +#endif + + //std::cout << w.GetFile().GetDataSet( ) << std::endl; + if( !w.Write() ) + { + std::cerr << "Problem writing output file: " << outfn << std::endl; + return 1; + } + } +#endif + } + + if( decomp_pap3 ) + { + if( !CleanupPapyrus3( pap3handle ) ) + { + std::cerr << "Problem during PAPYRUS 3.0 cleanup" << std::endl; + return 1; + } + } + + return 0; +} diff --git a/gdcm/Applications/Cxx/gdcmpdf.cxx b/gdcm/Applications/Cxx/gdcmpdf.cxx new file mode 100644 index 0000000..4c7a7bb --- /dev/null +++ b/gdcm/Applications/Cxx/gdcmpdf.cxx @@ -0,0 +1,666 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + */ +#include "gdcmVersion.h" +#include "gdcmUIDGenerator.h" +#include "gdcmWriter.h" +#include "gdcmAttribute.h" +#include "gdcmSystem.h" + +#ifdef GDCM_USE_SYSTEM_POPPLER +#include +#include +#include +#include +#include +#endif + +#include + +#include /* for printf */ +#include /* for exit */ +#include +#include + +static std::string getInfoDate(Dict *infoDict, const char *key) +{ + Object obj; + char *s; + int year, mon, day, hour, min, sec, n; + struct tm tmStruct; + //char buf[256]; + std::string out; + + if (infoDict->lookup((char*)key, &obj)->isString()) + { + s = obj.getString()->getCString(); + if (s[0] == 'D' && s[1] == ':') + { + s += 2; + } + if ((n = sscanf(s, "%4d%2d%2d%2d%2d%2d", + &year, &mon, &day, &hour, &min, &sec)) >= 1) + { + switch (n) + { + case 1: mon = 1; + case 2: day = 1; + case 3: hour = 0; + case 4: min = 0; + case 5: sec = 0; + } + tmStruct.tm_year = year - 1900; + tmStruct.tm_mon = mon - 1; + tmStruct.tm_mday = day; + tmStruct.tm_hour = hour; + tmStruct.tm_min = min; + tmStruct.tm_sec = sec; + tmStruct.tm_wday = -1; + tmStruct.tm_yday = -1; + tmStruct.tm_isdst = -1; +/* + // compute the tm_wday and tm_yday fields + if (mktime(&tmStruct) != (time_t)-1 && + strftime(buf, sizeof(buf), "%c", &tmStruct)) { + fputs(buf, stdout); + } else { + fputs(s, stdout); + } + } else { + fputs(s, stdout); +*/ + } + //fputc('\n', stdout); + char date[22]; + time_t t = mktime(&tmStruct); + if( t != -1 ) + { + if( gdcm::System::FormatDateTime(date, t) ) + out = date; + } + } + obj.free(); + return out; +} + +static std::string getInfoString(Dict *infoDict, const char *key, UnicodeMap *uMap, GBool & unicode) +{ + Object obj; + GooString *s1; + GBool isUnicode = gFalse; + Unicode u; + char buf[8]; + int i, n; + std::string out; + + if (infoDict->lookup((char*)key, &obj)->isString()) + { + s1 = obj.getString(); + if ((s1->getChar(0) & 0xff) == 0xfe && + (s1->getChar(1) & 0xff) == 0xff) + { + isUnicode = gTrue; + i = 2; + } + else + { + isUnicode = gFalse; + i = 0; + } + while (i < obj.getString()->getLength()) + { + if (isUnicode) + { + u = ((s1->getChar(i) & 0xff) << 8) | + (s1->getChar(i+1) & 0xff); + i += 2; + } + else + { + u = pdfDocEncoding[s1->getChar(i) & 0xff]; + ++i; + } + n = uMap->mapUnicode(u, buf, sizeof(buf)); + //fwrite(buf,1,n,stdout); + out.append( std::string(buf, n) ); + } + } + obj.free(); + unicode = unicode || isUnicode; + return out; +} + +static void PrintVersion() +{ + std::cout << "gdcmpdf: gdcm " << gdcm::Version::GetVersion() << " "; + const char date[] = "$Date$"; + std::cout << date << std::endl; +} + +static void PrintHelp() +{ + PrintVersion(); + std::cout << "Usage: gdcmpdf [OPTION]... FILE..." << std::endl; + std::cout << "Convert a PDF file to DICOM/PDF\n"; + std::cout << "Parameter (required):" << std::endl; + std::cout << " -i --input PDF filename" << std::endl; + std::cout << " -o --output DICOM filename" << std::endl; + std::cout << "General Options:" << std::endl; + std::cout << " -V --verbose more verbose (warning+error)." << std::endl; + std::cout << " -W --warning print warning info." << std::endl; + std::cout << " -D --debug print debug info." << std::endl; + std::cout << " -E --error print error info." << std::endl; + std::cout << " -h --help print help." << std::endl; + std::cout << " -v --version print version." << std::endl; +} + +int main (int argc, char *argv[]) +{ + int c; + //int digit_optind = 0; + + std::string filename; + std::string outfilename; + int verbose = 0; + int warning = 0; + int debug = 0; + int error = 0; + int help = 0; + int version = 0; + while (1) { + //int this_option_optind = optind ? optind : 1; + int option_index = 0; +/* + struct option { + const char *name; + int has_arg; + int *flag; + int val; + }; +*/ + static struct option long_options[] = { + {"input", 1, 0, 0}, + {"output", 1, 0, 0}, + {"verbose", 0, &verbose, 1}, + {"warning", 0, &warning, 1}, + {"debug", 0, &debug, 1}, + {"error", 0, &error, 1}, + {"help", 0, &help, 1}, + {"version", 0, &version, 1}, + {0, 0, 0, 0} // required + }; + static const char short_options[] = "i:o:VWDEhv"; + c = getopt_long (argc, argv, short_options, + long_options, &option_index); + if (c == -1) + { + break; + } + + switch (c) + { + case 0: + case '-': + { + const char *s = long_options[option_index].name; (void)s; + //printf ("option %s", s); + if (optarg) + { + if( option_index == 0 ) /* input */ + { + assert( strcmp(s, "input") == 0 ); + assert( filename.empty() ); + filename = optarg; + } + //printf (" with arg %s", optarg); + } + //printf ("\n"); + } + break; + + case 'i': + //printf ("option i with value '%s'\n", optarg); + assert( filename.empty() ); + filename = optarg; + break; + + case 'V': + verbose = 1; + break; + + case 'W': + warning = 1; + break; + + case 'D': + debug = 1; + break; + + case 'E': + error = 1; + break; + + case 'h': + help = 1; + break; + + case 'v': + version = 1; + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + //printf ("non-option ARGV-elements: %d", optind ); + //while (optind < argc) + // { + // printf ("%s\n", argv[optind++]); + // } + //printf ("\n"); + int v = argc - optind; + if( v == 2 ) + { + filename = argv[optind]; + outfilename = argv[optind+1]; + } + else + { + PrintHelp(); + return 1; + } + } + if( filename.empty() || outfilename.empty() ) + { + PrintHelp(); + return 1; + } + + if( version ) + { + //std::cout << "version" << std::endl; + PrintVersion(); + return 0; + } + + if( help ) + { + //std::cout << "help" << std::endl; + PrintHelp(); + return 0; + } + + GooString *ownerPW, *userPW; + GooString *fileName; + PDFDoc *doc; + Object info; + UnicodeMap *uMap; + ownerPW = NULL; + userPW = NULL; +#ifdef LIBPOPPLER_GLOBALPARAMS_CSTOR_HAS_PARAM + globalParams = new GlobalParams(0); +#else + globalParams = new GlobalParams(); +#endif + uMap = globalParams->getTextEncoding(); + + //const char *filename = argv[1]; + if( !gdcm::System::FileExists(filename.c_str()) ) + { + return 1; + } + // get length of file: + size_t length = gdcm::System::FileSize(filename.c_str()); + // PDF doc is stored in an OB element, check that 32bits length is fine: + if( length > gdcm::VL::GetVL32Max() ) + { + return 1; + } + + //const char *outfilename = argv[2]; + fileName = new GooString( filename.c_str() ); + //ownerPW = new GooString( "toto" ); + Object obj; + + obj.initNull(); + doc = new PDFDoc(fileName, ownerPW, userPW); + + if (doc->isEncrypted()) + { + std::string password; + std::cout << "Enter password:" << std::endl; + // http://www.daniweb.com/code/snippet1174.html + std::cin >> password; + //std::cout << "Enter password:" << password << std::endl; +/* +#include +#include + +int mygetch(void) +{ +struct termios oldt, +newt; +int ch; +tcgetattr( STDIN_FILENO, &oldt ); +newt = oldt; +newt.c_lflag &= ~( ICANON | ECHO ); +tcsetattr( STDIN_FILENO, TCSANOW, &newt ); +ch = getchar(); +tcsetattr( STDIN_FILENO, TCSANOW, &oldt ); +return ch; + +http://msdn.microsoft.com/en-us/library/078sfkak(VS.80).aspx +} + */ + ownerPW = new GooString( password.c_str() ); + doc = new PDFDoc(fileName, ownerPW, userPW); + } + + std::string title; + std::string subject; + std::string keywords; + std::string author; + std::string creator; + std::string producer; + std::string creationdate; + std::string moddate; + + GBool isUnicode = gFalse; + if (doc->isOk()) + { + doc->getDocInfo(&info); + if (info.isDict()) + { + title = getInfoString(info.getDict(), "Title", uMap, isUnicode); + subject = getInfoString(info.getDict(), "Subject", uMap, isUnicode); + keywords = getInfoString(info.getDict(), "Keywords", uMap, isUnicode); + author = getInfoString(info.getDict(), "Author", uMap, isUnicode); + creator = getInfoString(info.getDict(), "Creator", uMap, isUnicode); + producer = getInfoString(info.getDict(), "Producer", uMap, isUnicode); + creationdate = getInfoDate( info.getDict(), "CreationDate" ); + moddate = getInfoDate( info.getDict(), "ModDate" ); + info.free(); + } + } + + gdcm::Writer writer; + gdcm::DataSet &ds = writer.GetFile().GetDataSet(); +{ + gdcm::DataElement de( gdcm::Tag(0x42,0x11) ); + de.SetVR( gdcm::VR::OB ); + std::ifstream is; + is.open (filename.c_str(), std::ios::binary ); + + char *buffer = new char [length]; + + // read data as a block: + is.read (buffer,length); + is.close(); + + de.SetByteValue( buffer, (uint32_t)length ); + delete[] buffer; + + gdcm::FileMetaInformation &fmi = writer.GetFile().GetHeader(); + gdcm::TransferSyntax ts = gdcm::TransferSyntax::ExplicitVRLittleEndian; + fmi.SetDataSetTransferSyntax( ts ); + ds.Insert( de ); +} + + +{ + char date[22]; + const size_t datelen = 8; + int res = gdcm::System::GetCurrentDateTime(date); + if( !res ) return false; + { + gdcm::DataElement de( gdcm::Tag(0x0008,0x0020) ); + // Do not copy the whole cstring: + de.SetByteValue( date, datelen ); + de.SetVR( gdcm::Attribute<0x0008,0x0020>::GetVR() ); + ds.Insert( de ); + } + // StudyTime + const size_t timelen = 6 + 1 + 6; // time + milliseconds + (void)timelen; + { + gdcm::Attribute<0x8,0x30> at; + at.SetValue( date+datelen ); + ds.Insert( at.GetAsDataElement() ); + //gdcm::DataElement de( gdcm::Tag(0x0008,0x0030) ); + // Do not copy the whole cstring: + //de.SetByteValue( date+datelen, timelen ); + //de.SetVR( gdcm::Attribute<0x0008,0x0030>::GetVR() ); + //ds.Insert( de ); + } + +} + + gdcm::UIDGenerator uid; +{ + const char *sop = uid.Generate(); + gdcm::DataElement de( gdcm::Tag(0x0008,0x0018) ); + de.SetByteValue( sop, (uint32_t)strlen(sop) ); + de.SetVR( gdcm::Attribute<0x0008, 0x0018>::GetVR() ); + ds.Insert( de ); +} + + gdcm::MediaStorage ms = gdcm::MediaStorage::EncapsulatedPDFStorage; + { + gdcm::DataElement de( gdcm::Tag(0x0008, 0x0016) ); + const char* msstr = gdcm::MediaStorage::GetMSString(ms); + de.SetByteValue( msstr, (uint32_t)strlen(msstr) ); + de.SetVR( gdcm::Attribute<0x0008, 0x0016>::GetVR() ); + ds.Insert( de ); + } + + gdcm::FileMetaInformation::SetSourceApplicationEntityTitle( "gdcmpdf" ); + + char date[22]; + const size_t datelen = 8; + bool b = gdcm::System::GetCurrentDateTime(date); (void)b; + //std::cout << date << std::endl; + +{ + gdcm::Attribute<0x0008, 0x0005> at; + const char s[] = "ISO_IR 100"; + const char s_unicode[] = "ISO_IR 192"; + at.SetNumberOfValues( 1 ); + if( isUnicode ) + at.SetValue( s_unicode ); + else + at.SetValue( s ); + ds.Insert( at.GetAsDataElement() ); +} +{ + gdcm::Attribute<0x0008, 0x0012> at; + std::string tmp( date, datelen ); + at.SetValue( tmp.c_str() ); + ds.Insert( at.GetAsDataElement() ); +} + + const size_t timelen = 6 + 1 + 6; // TM + milliseconds +{ + gdcm::Attribute<0x0008, 0x0013> at; + std::string tmp( date+datelen, timelen); + at.SetValue( tmp.c_str() ); + ds.Insert( at.GetAsDataElement() ); +} +//(0008,0020) DA (no value available) # 0, 0 StudyDate +{ + gdcm::Attribute<0x0008, 0x0020> at; + ds.Insert( at.GetAsDataElement() ); +} +//(0008,0023) DA (no value available) # 0, 0 ContentDate +{ + gdcm::Attribute<0x0008, 0x0023> at; + std::string tmp( creationdate.c_str(), datelen ); + at.SetValue( tmp.c_str() ); + ds.Insert( at.GetAsDataElement() ); +} +//(0008,002a) DT (no value available) # 0, 0 AcquisitionDatetime +{ + gdcm::Attribute<0x0008, 0x002a> at; + time_t studydatetime = gdcm::System::FileTime( filename.c_str() ); + char date2[22]; + gdcm::System::FormatDateTime(date2, studydatetime); + at.SetValue( date2 ); + ds.Insert( at.GetAsDataElement() ); +} +//(0008,0030) TM (no value available) # 0, 0 StudyTime +{ + gdcm::Attribute<0x0008, 0x0030> at; + ds.Insert( at.GetAsDataElement() ); +} +//(0008,0033) TM (no value available) # 0, 0 ContentTime +{ + gdcm::Attribute<0x0008, 0x0033> at; + std::string tmp( creationdate.c_str() + datelen, timelen); + at.SetValue( tmp.c_str() ); + ds.Insert( at.GetAsDataElement() ); +} +//(0008,0050) SH (no value available) # 0, 0 AccessionNumber +{ + gdcm::Attribute<0x0008, 0x0050> at; + ds.Insert( at.GetAsDataElement() ); +} +//(0008,0060) CS [DOC] # 2, 1 Modality +{ + gdcm::Attribute<0x0008, 0x0060> at; + at.SetValue( "DOC " ); + ds.Insert( at.GetAsDataElement() ); +} +//(0008,0064) CS [WSD] # 4, 1 ConversionType +{ + gdcm::Attribute<0x0008, 0x0064> at; + at.SetValue( "WSD" ); + ds.Insert( at.GetAsDataElement() ); +} +//(0008,0070) LO (no value available) # 0, 0 Manufacturer +{ + gdcm::Attribute<0x0008, 0x0070> at; + at.SetValue( creator.c_str() ); + ds.Insert( at.GetAsDataElement() ); +} +//(0008,0090) PN (no value available) # 0, 0 ReferringPhysiciansName +{ + gdcm::Attribute<0x0008, 0x0090> at; + ds.Insert( at.GetAsDataElement() ); +} + +// In past DICOM implementation there used to be those neat tags: +// (0088,0904) Topic Title TopicTitle LO 1 RET +// (0088,0906) Topic Subject TopicSubject ST 1 RET +// (0088,0910) Topic Author TopicAuthor LO 1 RET +// (0088,0912) Topic Keywords TopicKeywords LO 1-32 RET +// However they are now deprecated... + +//(0010,0010) PN (no value available) # 0, 0 PatientsName +{ + gdcm::Attribute<0x0010, 0x0010> at; + at.SetValue( author.c_str() ); + ds.Insert( at.GetAsDataElement() ); +} +//(0010,0020) LO (no value available) # 0, 0 PatientID +{ + gdcm::Attribute<0x0010, 0x0020> at; + ds.Insert( at.GetAsDataElement() ); +} +//(0010,0030) DA (no value available) # 0, 0 PatientsBirthDate +{ + gdcm::Attribute<0x0010, 0x0030> at; + ds.Insert( at.GetAsDataElement() ); +} +//(0010,0040) CS (no value available) # 0, 0 PatientsSex +{ + gdcm::Attribute<0x0010, 0x0040> at; + ds.Insert( at.GetAsDataElement() ); +} +{ + gdcm::Attribute<0x0018, 0x1020> at; + at.SetNumberOfValues( 1 ); + at.SetValue( producer.c_str() ); + ds.Insert( at.GetAsDataElement() ); +} +//(0020,000d) UI [1.2.276.0.7230010.3.1.4.8323329.511.1228064157.1] # 48, 1 StudyInstanceUID +{ + gdcm::Attribute<0x0020, 0x000d> at; + at.SetValue( uid.Generate() ); + ds.Insert( at.GetAsDataElement() ); +} +//(0020,000e) UI [1.2.276.0.7230010.3.1.4.8323329.511.1228064157.2] # 48, 1 SeriesInstanceUID +{ + gdcm::Attribute<0x0020, 0x000e> at; + at.SetValue( uid.Generate() ); + ds.Insert( at.GetAsDataElement() ); +} +//(0020,0010) SH (no value available) # 0, 0 StudyID +{ + gdcm::Attribute<0x0020, 0x0010> at; + ds.Insert( at.GetAsDataElement() ); +} +//(0020,0011) IS [1] # 2, 1 SeriesNumber +{ + gdcm::Attribute<0x0020, 0x0011> at = { 1 }; + ds.Insert( at.GetAsDataElement() ); +} +//(0020,0013) IS [1] # 2, 1 InstanceNumber +{ + gdcm::Attribute<0x0020, 0x0013> at = { 1 }; + ds.Insert( at.GetAsDataElement() ); +} +//(0028,0301) CS [YES] # 4, 1 BurnedInAnnotation +{ + gdcm::Attribute<0x0028, 0x0301> at; + at.SetValue( "YES" ); + ds.Insert( at.GetAsDataElement() ); +} +//(0040,a043) SQ (Sequence with explicit length #=0) # 0, 1 ConceptNameCodeSequence +//(fffe,e0dd) na (SequenceDelimitationItem for re-encod.) # 0, 0 SequenceDelimitationItem +{ + gdcm::Attribute<0x0040, 0xa043> at; + gdcm::DataElement de( at.GetTag() ); + de.SetVR( at.GetVR() ); + //ds.Insert( at.GetAsDataElement() ); + ds.Insert( de ); +} +//(0042,0010) ST (no value available) # 0, 0 DocumentTitle +{ + gdcm::Attribute<0x0042, 0x0010> at; + at.SetValue( title.c_str() ); + ds.Insert( at.GetAsDataElement() ); +} +//(0042,0011) OB 25\50\44\46\2d\31\2e\34\0a\25\e7\f3\cf\d3\0a\32\34\35\38\38\20\30... # 6861900, 1 EncapsulatedDocument +//(0042,0012) LO [application/pdf] # 16, 1 MIMETypeOfEncapsulatedDocument +{ + gdcm::Attribute<0x0042, 0x0012> at; + at.SetValue( "application/pdf" ); + ds.Insert( at.GetAsDataElement() ); +} + + + writer.SetFileName( outfilename.c_str() ); + if( !writer.Write() ) + { + return 1; + } + + return 0; +} diff --git a/gdcm/Applications/Cxx/gdcmraw.cxx b/gdcm/Applications/Cxx/gdcmraw.cxx new file mode 100644 index 0000000..594d71b --- /dev/null +++ b/gdcm/Applications/Cxx/gdcmraw.cxx @@ -0,0 +1,413 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + * gdcmraw - ACR/NEMA DICOM PS3 ... DICOM PS3 - DICOM image to raw file + * Synopsis: + * gdcmraw [ -t | --tag Tag# (default: 07fe,0010) ] -i inputfile + * Description: + * gdcmraw + * reads the named dicom or acr-nema input file and copies the raw image + * pixel data to a raw binary file without a header of any kind. + * The byte order, packing or encapsulation of the raw result is dependent + * only on the encoding of the input file and cannot be changed. +*/ + +#include "gdcmReader.h" +#include "gdcmImageReader.h" +#include "gdcmImage.h" +#include "gdcmFileMetaInformation.h" +#include "gdcmDataSet.h" +#include "gdcmTag.h" +#include "gdcmByteValue.h" +#include "gdcmSequenceOfFragments.h" +#include "gdcmFragment.h" +#include "gdcmFilename.h" +#include "gdcmFilenameGenerator.h" +#include "gdcmVersion.h" + +#include +#include + +#include /* for printf */ +#include /* for exit */ +#include +#include + +static void PrintVersion() +{ + std::cout << "gdcmraw: gdcm " << gdcm::Version::GetVersion() << " "; + const char date[] = "$Date$"; + std::cout << date << std::endl; +} + +static void PrintHelp() +{ + PrintVersion(); + std::cout << "Usage: gdcmraw [OPTION]... FILE..." << std::endl; + std::cout << "Extract Data Element Value Field" << std::endl; + std::cout << "Parameter (required):" << std::endl; + std::cout << " -i --input DICOM filename" << std::endl; + std::cout << " -o --output DICOM filename" << std::endl; + std::cout << " -t --tag Specify tag to extract value from." << std::endl; + std::cout << "Options:" << std::endl; + std::cout << " -S --split-frags Split fragments into multiple files." << std::endl; + std::cout << " -p --pattern Specify trailing file pattern (see split-frags)." << std::endl; + std::cout << " -P --pixel-data Pixel Data trailing 0." << std::endl; + std::cout << "General Options:" << std::endl; + std::cout << " -V --verbose more verbose (warning+error)." << std::endl; + std::cout << " -W --warning print warning info." << std::endl; + std::cout << " -D --debug print debug info." << std::endl; + std::cout << " -E --error print error info." << std::endl; + std::cout << " -h --help print help." << std::endl; + std::cout << " -v --version print version." << std::endl; +} + +int main(int argc, char *argv[]) +{ + int c; + //int digit_optind = 0; + + gdcm::Tag rawTag(0x7fe0, 0x0010); // Default to Pixel Data + std::string filename; + std::string outfilename; + std::string pattern; + int splitfrags = 0; + int pixeldata = 0; + int verbose = 0; + int warning = 0; + int debug = 0; + int error = 0; + int help = 0; + int version = 0; + while (1) { + //int this_option_optind = optind ? optind : 1; + int option_index = 0; + static struct option long_options[] = { + {"input", 1, 0, 0}, // i + {"output", 1, 0, 0}, // o + {"tag", 1, 0, 0}, // t + {"split-frags", 0, &splitfrags, 1}, // f +/* + * pixel-data flag is important for image like DermaColorLossLess.dcm since the bytevalue is + * 63532, because of the DICOM \0 padding, but we would rather have the image buffer instead + * which is simply one byte shorter, so add a special flag that simply mimic what TestImageReader + * would expect + */ + {"pixel-data", 0, &pixeldata, 1}, // P + {"pattern", 1, 0, 0}, // p + + {"verbose", 0, &verbose, 1}, + {"warning", 0, &warning, 1}, + {"debug", 0, &debug, 1}, + {"error", 0, &error, 1}, + {"help", 0, &help, 1}, + {"version", 0, &version, 1}, + + {0, 0, 0, 0} + }; + + c = getopt_long (argc, argv, "i:o:t:Sp:PVWDEhv", + long_options, &option_index); + if (c == -1) + { + break; + } + + switch (c) + { + case 0: + { + const char *s = long_options[option_index].name; (void)s; + //printf ("option %s", s); + if (optarg) + { + if( option_index == 0 ) /* input */ + { + assert( strcmp(s, "input") == 0 ); + assert( filename.empty() ); + filename = optarg; + } + else if( option_index == 2 ) /* tag */ + { + assert( strcmp(s, "tag") == 0 ); + rawTag.ReadFromCommaSeparatedString(optarg); + } + else if( option_index == 5 ) /* pattern */ + { + assert( strcmp(s, "pattern") == 0 ); + assert( pattern.empty() ); + pattern = optarg; + } + //printf (" with arg %s", optarg); + } + //printf ("\n"); + } + break; + + case 'i': + //printf ("option i with value '%s'\n", optarg); + assert( filename.empty() ); + filename = optarg; + break; + + case 'o': + //printf ("option o with value '%s'\n", optarg); + assert( outfilename.empty() ); + outfilename = optarg; + break; + + case 'P': + pixeldata = 1; + break; + + case 'S': + splitfrags = 1; + break; + + case 'p': + assert( pattern.empty() ); + pattern = optarg; + break; + + case 't': + //printf ("option t with value '%s'\n", optarg); + rawTag.ReadFromCommaSeparatedString(optarg); + //std::cerr << rawTag << std::endl; + break; + + case 'V': + verbose = 1; + break; + + case 'W': + warning = 1; + break; + + case 'D': + debug = 1; + break; + + case 'E': + error = 1; + break; + + case 'h': + help = 1; + break; + + case 'v': + version = 1; + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + std::vector files; + while (optind < argc) + { + //printf ("%s\n", argv[optind++]); + files.push_back( argv[optind++] ); + } + //printf ("\n"); + if( files.size() == 2 + && filename.empty() + && outfilename.empty() + ) + { + filename = files[0]; + outfilename = files[1]; + } + else + { + PrintHelp(); + return 1; + } + } + + if( version ) + { + //std::cout << "version" << std::endl; + PrintVersion(); + return 0; + } + + if( help ) + { + //std::cout << "help" << std::endl; + PrintHelp(); + return 0; + } + + if( filename.empty() ) + { + //std::cerr << "Need input file (-i)\n"; + PrintHelp(); + return 1; + } + + // Debug is a little too verbose + gdcm::Trace::SetDebug( debug != 0); + gdcm::Trace::SetWarning( warning != 0); + gdcm::Trace::SetError( error != 0); + // when verbose is true, make sure warning+error are turned on: + if( verbose ) + { + gdcm::Trace::SetWarning( verbose != 0); + gdcm::Trace::SetError( verbose!= 0); + } + + // else + //std::cout << "Filename: " << filename << std::endl; + + // very special option, handle it first: + if( pixeldata ) + { + if( rawTag != gdcm::Tag(0x7fe0,0x0010) ) + { + return 1; + } + gdcm::ImageReader reader; + reader.SetFileName( filename.c_str() ); + if( !reader.Read() ) + { + std::cerr << "Failed to read: " << filename << std::endl; + return 1; + } + const gdcm::Image& image = reader.GetImage(); + unsigned long len = image.GetBufferLength(); + char * buf = new char[len]; + image.GetBuffer( buf ); + + std::ofstream output(outfilename.c_str(), std::ios::binary); + output.write( buf, len ); + + delete[] buf; + return 0; + } + gdcm::Reader reader; + reader.SetFileName( filename.c_str() ); + if( !reader.Read() ) + { + std::cerr << "Failed to read: " << filename << std::endl; + return 1; + } + + //const gdcm::FileMetaInformation &h = reader.GetFile().GetHeader(); + //std::cout << h << std::endl; + + const gdcm::DataSet &ds = reader.GetFile().GetDataSet(); + //std::cout << ds << std::endl; + + if( !ds.FindDataElement( rawTag ) ) + { + std::cerr << "Cannot find Tag: " << rawTag << std::endl; + return 1; + } + + if( outfilename.empty() ) + { + std::cerr << "Need output file (-o)\n"; + return 1; + } + gdcm::Filename fn1(filename.c_str()), fn2(outfilename.c_str()); + if( fn1.IsIdentical(fn2) ) + { + std::cerr << "Output is Input\n"; + return 1; + } + + const gdcm::DataElement& pdde = ds.GetDataElement( rawTag ); + const gdcm::ByteValue *bv = pdde.GetByteValue(); + const gdcm::SequenceOfFragments *sf = pdde.GetSequenceOfFragments(); + if( bv ) + { + std::ofstream output(outfilename.c_str(), std::ios::binary); + bv->WriteBuffer(output); + } + else if( sf ) + { + if( splitfrags ) + { + size_t nfrags = sf->GetNumberOfFragments(); + gdcm::FilenameGenerator fg; + fg.SetNumberOfFilenames( nfrags ); + fg.SetPrefix( outfilename.c_str() ); + fg.SetPattern( pattern.c_str() ); + if(!fg.Generate()) + { + std::cerr << "Could not generate" << std::endl; + return 1; + } + for(unsigned int i = 0; i < nfrags; ++i) + { + const gdcm::Fragment& frag = sf->GetFragment(i); + const gdcm::ByteValue *fragbv = frag.GetByteValue(); + const char *outfilenamei = fg.GetFilename(i); + std::ofstream outputi(outfilenamei, std::ios::binary); + fragbv->WriteBuffer(outputi); + } + } + else + { + std::ofstream output(outfilename.c_str(), std::ios::binary); + sf->WriteBuffer(output); + } + } + else + { + const gdcm::Value &value = pdde.GetValue(); + const gdcm::Value * v = &value; + const gdcm::SequenceOfItems *sqi = dynamic_cast( v ); + if( sqi ) + { + //std::ofstream output(outfilename.c_str(), std::ios::binary); + //sqi->Write(output); + size_t nfrags = sqi->GetNumberOfItems(); + gdcm::FilenameGenerator fg; + fg.SetNumberOfFilenames( nfrags ); + fg.SetPrefix( outfilename.c_str() ); + fg.SetPattern( pattern.c_str() ); + if(!fg.Generate()) + { + std::cerr << "Could not generate" << std::endl; + return 1; + } + for(unsigned int i = 0; i < nfrags; ++i) + { + const gdcm::Item& frag = sqi->GetItem(i+1); + const gdcm::DataSet &subds = frag.GetNestedDataSet(); + const char *outfilenamei = fg.GetFilename(i); + std::ofstream outputi(outfilenamei, std::ios::binary); + // Let's imagine we found an undefined length Pixel Data attribute in + // this sequence. Let's pick ExplicitDataElement for writing out then + subds.Write(outputi); + } + + } + else + { + std::cerr << "Unhandled" << std::endl; + return 1; + } + } + + return 0; +} diff --git a/gdcm/Applications/Cxx/gdcmscanner.cxx b/gdcm/Applications/Cxx/gdcmscanner.cxx new file mode 100644 index 0000000..6b42222 --- /dev/null +++ b/gdcm/Applications/Cxx/gdcmscanner.cxx @@ -0,0 +1,283 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + * a Scanner application + * Usage: + * + * $ gdcmscanner -d /images/ -t 0020,000d -t 0020,000e + * + * Options: + * -d : directory + * -t : tag (can be specified multiple times) + * -p : print + * -r : recursive (enter subdir of main directory) + * + * TODO: + * --bench... + */ + +#include "gdcmScanner.h" +#include "gdcmTrace.h" +#include "gdcmVersion.h" +#include "gdcmSimpleSubjectWatcher.h" + +#include +#include +#include + +#include /* for printf */ +#include /* for exit */ +#include +#include + +static void PrintVersion() +{ + std::cout << "gdcmscanner: gdcm " << gdcm::Version::GetVersion() << " "; + const char date[] = "$Date$"; + std::cout << date << std::endl; +} + +static void PrintHelp() +{ + PrintVersion(); + std::cout << "Usage: gdcmscanner [OPTION] -d directory -t tag(s)" << std::endl; + std::cout << "Scan a directory containing DICOM files.\n"; + std::cout << "Parameter (required):" << std::endl; + std::cout << " -d --dir DICOM directory" << std::endl; + std::cout << " -t --tag %d,%d DICOM tag(s) to look for" << std::endl; + std::cout << " -P --private-tag %d,%d,%s DICOM private tag(s) to look for" << std::endl; + std::cout << "Options:" << std::endl; + std::cout << " -p --print Print output." << std::endl; + std::cout << " -r --recursive Recusively descend directory." << std::endl; + std::cout << "General Options:" << std::endl; + std::cout << " -V --verbose more verbose (warning+error)." << std::endl; + std::cout << " -W --warning print warning info." << std::endl; + std::cout << " -D --debug print debug info." << std::endl; + std::cout << " -E --error print error info." << std::endl; + std::cout << " -h --help print help." << std::endl; + std::cout << " -v --version print version." << std::endl; +} + +int main(int argc, char *argv[]) +{ + int c; + //int digit_optind = 0; + + bool print = false; + bool recursive = false; + std::string dirname; + typedef std::vector VectorTags; + typedef std::vector VectorPrivateTags; + VectorTags tags; + VectorPrivateTags privatetags; + gdcm::Tag tag; + gdcm::PrivateTag privatetag; + + int verbose = 0; + int warning = 0; + int debug = 0; + int error = 0; + int help = 0; + int version = 0; + + while (1) { + //int this_option_optind = optind ? optind : 1; + int option_index = 0; + static struct option long_options[] = { + {"dir", 1, 0, 0}, + {"tag", 1, 0, 0}, + {"recursive", 1, 0, 0}, + {"print", 1, 0, 0}, + {"private-tag", 1, 0, 0}, + +// General options ! + {"verbose", 0, &verbose, 1}, + {"warning", 0, &warning, 1}, + {"debug", 0, &debug, 1}, + {"error", 0, &error, 1}, + {"help", 0, &help, 1}, + {"version", 0, &version, 1}, + + {0, 0, 0, 0} + }; + + c = getopt_long (argc, argv, "d:t:rpP:VWDEhv", + long_options, &option_index); + if (c == -1) + { + break; + } + + switch (c) + { + case 0: + { + //const char *s = long_options[option_index].name; + //printf ("option %s", s); + //if (optarg) + // { + // if( option_index == 0 ) /* input */ + // { + // assert( strcmp(s, "input") == 0 ); + // } + // printf (" with arg %s", optarg); + // } + //printf ("\n"); + } + break; + + case 'd': + dirname = optarg; + break; + + case 't': + tag.ReadFromCommaSeparatedString(optarg); + tags.push_back( tag ); + //std::cerr << optarg << std::endl; + break; + + case 'P': + privatetag.ReadFromCommaSeparatedString(optarg); + privatetags.push_back( privatetag ); + //std::cerr << optarg << std::endl; + break; + + case 'r': + recursive = true; + break; + + case 'p': + print = true; + break; + + case 'V': + verbose = 1; + break; + + case 'W': + warning = 1; + break; + + case 'D': + debug = 1; + break; + + case 'E': + error = 1; + break; + + case 'h': + help = 1; + break; + + case 'v': + version = 1; + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { +/* + printf ("non-option ARGV-elements: "); + while (optind < argc) + { + printf ("%s ", argv[optind++]); + } + printf ("\n"); +*/ + PrintHelp(); + return 1; + } + + if( version ) + { + //std::cout << "version" << std::endl; + PrintVersion(); + return 0; + } + + if( help ) + { + //std::cout << "help" << std::endl; + PrintHelp(); + return 0; + } + + if( dirname.empty() ) + { + //std::cerr << "Need dir (-d)\n"; + PrintHelp(); + return 1; + } + if( tags.empty() && privatetags.empty() ) + { + //std::cerr << "Need tags (-t)\n"; + PrintHelp(); + return 1; + } + // Debug is a little too verbose + gdcm::Trace::SetDebug( (debug > 0 ? true : false)); + gdcm::Trace::SetWarning( (warning > 0 ? true : false)); + gdcm::Trace::SetError( (error > 0 ? true : false)); + // when verbose is true, make sure warning+error are turned on: + if( verbose ) + { + gdcm::Trace::SetWarning( (verbose > 0 ? true : false) ); + gdcm::Trace::SetError( (verbose > 0 ? true : false) ); + } + + if( verbose ) + { + std::cout << "Will parse: " << dirname << std::endl; + std::cout << "Looking for tags: \n"; + std::copy(tags.begin(), tags.end(), + std::ostream_iterator( std::cout, "\n")); + std::copy(privatetags.begin(), privatetags.end(), + std::ostream_iterator( std::cout, "\n")); + //std::cout << std::endl; + } + + gdcm::Directory d; + unsigned int nfiles = d.Load( dirname.c_str(), recursive ); + if( verbose ) d.Print( std::cout ); + std::cout << "done retrieving file list " << nfiles << " files found." << std::endl; + + gdcm::SmartPointer ps = new gdcm::Scanner; + gdcm::Scanner &s = *ps; + //gdcm::SimpleSubjectWatcher watcher(ps, "Scanner"); + for( VectorTags::const_iterator it = tags.begin(); it != tags.end(); ++it) + { + s.AddTag( *it ); + } + for( VectorPrivateTags::const_iterator it = privatetags.begin(); it != privatetags.end(); ++it) + { + s.AddPrivateTag( *it ); + } + bool b = s.Scan( d.GetFilenames() ); + if( !b ) + { + std::cerr << "Scanner failed" << std::endl; + return 1; + } + if (print) s.Print( std::cout ); + + return 0; +} diff --git a/gdcm/Applications/Cxx/gdcmscu.cxx b/gdcm/Applications/Cxx/gdcmscu.cxx new file mode 100644 index 0000000..d48902a --- /dev/null +++ b/gdcm/Applications/Cxx/gdcmscu.cxx @@ -0,0 +1,745 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + * Simple command line tool to echo/store/find/move DICOM using + * DICOM Query/Retrieve + * This is largely inspired by other tool available from other toolkit, namely: + * echoscu (DCMTK) + * findscu (DCMTK) + * movescu (DCMTK) + * storescu (DCMTK) + */ + +#include "gdcmCompositeNetworkFunctions.h" + +#include +#include +#include +#include +#include "gdcmVersion.h" +#include "gdcmGlobal.h" +#include "gdcmSystem.h" +#include "gdcmDirectory.h" +#include "gdcmDataSet.h" +#include "gdcmFileMetaInformation.h" +#include "gdcmUIDGenerator.h" + +#include "gdcmBaseRootQuery.h" +#include "gdcmQueryFactory.h" +#include "gdcmPrinter.h" + + +static void PrintVersion() +{ + std::cout << "gdcmscu: gdcm " << gdcm::Version::GetVersion() << " "; + const char date[] = "$Date$"; + std::cout << date << std::endl; +} + +static void PrintHelp() +{ + PrintVersion(); + std::cout << "Usage: gdcmscu [OPTION]...[OPERATION]...HOSTNAME...[PORT]..." << std::endl; + std::cout << "Execute a DICOM Q/R operation to HOSTNAME, using port PORT (104 when not specified)\n"; + std::cout << "Options:" << std::endl; + std::cout << " -H --hostname Hostname." << std::endl; + std::cout << " -p --port Port number." << std::endl; + std::cout << " --aetitle Set Calling AE Title." << std::endl; + std::cout << " --call Set Called AE Title." << std::endl; + std::cout << "Mode Options:" << std::endl; + std::cout << " --echo C-ECHO (default when none)." << std::endl; + std::cout << " --store C-STORE." << std::endl; + std::cout << " --find C-FIND." << std::endl; + std::cout << " --move C-MOVE." << std::endl; + std::cout << " --get C-GET." << std::endl; + std::cout << "C-STORE Options:" << std::endl; + std::cout << " -i --input DICOM filename" << std::endl; + std::cout << " -r --recursive recursively process (sub-)directories." << std::endl; + std::cout << " --store-query Store constructed query in file." << std::endl; + std::cout << "C-FIND Options:" << std::endl; + //std::cout << " --worklist C-FIND Worklist Model." << std::endl;//!!not supported atm + std::cout << " --patientroot C-FIND Patient Root Model." << std::endl; + std::cout << " --studyroot C-FIND Study Root Model." << std::endl; + std::cout << " --patient C-FIND Query on Patient Info (cannot be used with --studyroot)" << std::endl; + std::cout << " --study C-FIND Query on Study Info." << std::endl; + std::cout << " --series C-FIND Query on Series Info." << std::endl; + std::cout << " --image C-FIND Query on Image Info." << std::endl; + //std::cout << " --psonly C-FIND Patient/Study Only Model." << std::endl; + std::cout << " --key 0123,4567=VALUE for specifying search criteria (wildcard allowed)." << std::endl; + std::cout << " With --key, leave blank (ie, --key 10,10="") to retrieve values" << std::endl; + std::cout << "C-MOVE Options:" << std::endl; + std::cout << " -o --output DICOM output directory." << std::endl; + std::cout << " --port-scp Port used for incoming association." << std::endl; + std::cout << " --key 0123,4567=VALUE for specifying search criteria (wildcard not allowed)." << std::endl; + std::cout << " Note that C-MOVE supports the same queries as C-FIND, but no wildcards are allowed." << std::endl; + std::cout << "C-GET Options:" << std::endl; + std::cout << "General Options:" << std::endl; + std::cout << " --root-uid Root UID." << std::endl; + std::cout << " -V --verbose more verbose (warning+error)." << std::endl; + std::cout << " -W --warning print warning info." << std::endl; + std::cout << " -D --debug print debug info." << std::endl; + std::cout << " -E --error print error info." << std::endl; + std::cout << " -h --help print help." << std::endl; + std::cout << " --queryhelp print query help." << std::endl; + std::cout << " -v --version print version." << std::endl; + std::cout << " -L --log-file set log file (instead of cout)." << std::endl; + + try + { + std::locale l(""); + std::string loc = l.name(); + std::cout << std::endl; + std::cout << "Local Name: " << loc << std::endl; + } + catch( const std::exception& e) + { + std::cerr << e.what() << std::endl; + } + std::cout << "Local Character Set: " << gdcm::System::GetLocaleCharset() << std::endl; + std::vector charsettype; + charsettype.push_back( gdcm::QueryFactory::GetCharacterFromCurrentLocale() ); + gdcm::DataElement de = gdcm::QueryFactory::ProduceCharacterSetDataElement(charsettype); + const gdcm::ByteValue *bv = de.GetByteValue(); + std::string s( bv->GetPointer(), bv->GetLength() ); + std::cout << "DICOM Character Set: [" << s << "]" << std::endl; +} + +static void PrintQueryHelp(int inFindPatientRoot) +{ + gdcm::BaseRootQuery* theBase; + if (inFindPatientRoot) + { + std::cout << "To find the help for a study-level query, type" <WriteHelpFile(std::cout); + delete theBase; + } + else + { + std::cout << "To find the help for a patient-level query, type" <WriteHelpFile(std::cout); + delete theBase; + } +} + +int main(int argc, char *argv[]) +{ + int c; + //int digit_optind = 0; + + std::string shostname; + std::string callingaetitle = "GDCMSCU"; + std::string callaetitle = "ANY-SCP"; + int port = 104; // default + int portscp = 0; + int outputopt = 0; + int portscpnum = 0; + gdcm::Directory::FilenamesType filenames; + std::string outputdir; + int storequery = 0; + int verbose = 0; + int warning = 0; + int debug = 0; + int error = 0; + int help = 0; + int queryhelp = 0; + int version = 0; + int echomode = 0; + int storemode = 0; + int findmode = 0; + int movemode = 0; + int getmode = 0; + int findworklist = 0; + int findpatientroot = 0; + int findstudyroot = 0; + int patientquery = 0; + int studyquery = 0; + int seriesquery = 0; + int imagequery = 0; + int findpsonly = 0; + std::string queryfile; + std::string root; + int rootuid = 0; + int recursive = 0; + int logfile = 0; + std::string logfilename; + gdcm::Tag tag; + std::vector< std::pair > keys; + + while (1) { + //int this_option_optind = optind ? optind : 1; + int option_index = 0; + /* + struct option { + const char *name; + int has_arg; + int *flag; + int val; + }; + */ + static struct option long_options[] = { + {"verbose", 0, &verbose, 1}, + {"warning", 0, &warning, 1}, + {"debug", 0, &debug, 1}, + {"error", 0, &error, 1}, + {"help", 0, &help, 1}, + {"version", 0, &version, 1}, + {"hostname", 1, 0, 0}, // -h + {"aetitle", 1, 0, 0}, // + {"call", 1, 0, 0}, // + {"port", 0, &port, 1}, // -p + {"input", 1, 0, 0}, // dcmfile-in + {"echo", 0, &echomode, 1}, // --echo + {"store", 0, &storemode, 1}, // --store + {"find", 0, &findmode, 1}, // --find + {"move", 0, &movemode, 1}, // --move + {"key", 1, 0, 0}, // (15) --key + {"worklist", 0, &findworklist, 1}, // --worklist + {"patientroot", 0, &findpatientroot, 1}, // --patientroot + {"studyroot", 0, &findstudyroot, 1}, // --studyroot + {"psonly", 0, &findpsonly, 1}, // --psonly + {"port-scp", 1, &portscp, 1}, // (20) --port-scp + {"output", 1, &outputopt, 1}, // --output + {"recursive", 0, &recursive, 1}, + {"store-query", 1, &storequery, 1}, + {"queryhelp", 0, &queryhelp, 1}, + {"patient", 0, &patientquery, 1}, // --patient + {"study", 0, &studyquery, 1}, // --study + {"series", 0, &seriesquery, 1}, // --series + {"image", 0, &imagequery, 1}, // --image + {"log-file", 1, &logfile, 1}, // --log-file + {"get", 0, &getmode, 1}, // --get + {0, 0, 0, 0} // required + }; + static const char short_options[] = "i:H:p:L:VWDEhvk:o:r"; + c = getopt_long (argc, argv, short_options, + long_options, &option_index); + if (c == -1) + { + break; + } + + switch (c) + { + case 0: + case '-': + { + const char *s = long_options[option_index].name; (void)s; + //printf ("option %s", s); + if (optarg) + { + if( option_index == 0 ) /* input */ + { + assert( strcmp(s, "input") == 0 ); + filenames.push_back( optarg ); + } + else if( option_index == 7 ) /* calling aetitle */ + { + assert( strcmp(s, "aetitle") == 0 ); + //assert( callingaetitle.empty() ); + callingaetitle = optarg; + } + else if( option_index == 8 ) /* called aetitle */ + { + assert( strcmp(s, "call") == 0 ); + //assert( callaetitle.empty() ); + callaetitle = optarg; + } + else if( option_index == 15 ) /* key */ + { + assert( strcmp(s, "key") == 0 ); + if( !tag.ReadFromCommaSeparatedString(optarg) ) + { + std::cerr << "Could not read Tag: " << optarg << std::endl; + return 1; + } + std::stringstream ss; + ss.str( optarg ); + uint16_t dummy; + char cdummy; // comma + ss >> std::hex >> dummy; + assert( tag.GetGroup() == dummy ); + ss >> cdummy; + assert( cdummy == ',' ); + ss >> std::hex >> dummy; + assert( tag.GetElement() == dummy ); + ss >> cdummy; + assert( cdummy == ',' || cdummy == '=' ); + std::string str; + //ss >> str; + std::getline(ss, str); // do not skip whitespace + keys.push_back( std::make_pair(tag, str) ); + } + else if( option_index == 20 ) /* port-scp */ + { + assert( strcmp(s, "port-scp") == 0 ); + portscpnum = atoi(optarg); + } + else if( option_index == 21 ) /* output */ + { + assert( strcmp(s, "output") == 0 ); + outputdir = optarg; + } + else if( option_index == 23 ) /* store-query */ + { + assert( strcmp(s, "store-query") == 0 ); + queryfile = optarg; + } + else if( option_index == 29 ) /* log-file */ + { + assert( strcmp(s, "log-file") == 0 ); + logfilename = optarg; + } + else + { + // If you reach here someone mess-up the index and the argument in + // the getopt table + assert( 0 ); + } + //printf (" with arg %s", optarg); + } + //printf ("\n"); + } + break; + + case 'k': + { + if( !tag.ReadFromCommaSeparatedString(optarg) ) + { + std::cerr << "Could not read Tag: " << optarg << std::endl; + return 1; + } + std::stringstream ss; + ss.str( optarg ); + uint16_t dummy; + char cdummy; // comma + ss >> std::hex >> dummy; + assert( tag.GetGroup() == dummy ); + ss >> cdummy; + assert( cdummy == ',' ); + ss >> std::hex >> dummy; + assert( tag.GetElement() == dummy ); + ss >> cdummy; + assert( cdummy == ',' || cdummy == '=' ); + std::string str; + std::getline(ss, str); // do not skip whitespace + keys.push_back( std::make_pair(tag, str) ); + } + break; + + case 'i': + //printf ("option i with value '%s'\n", optarg); + filenames.push_back( optarg ); + break; + + case 'r': + recursive = 1; + break; + + case 'o': + assert( outputdir.empty() ); + outputdir = optarg; + break; + + case 'H': + shostname = optarg; + break; + + case 'p': + port = atoi( optarg ); + break; + + case 'L': + logfile = 1; + logfilename = optarg; + break; + + case 'V': + verbose = 1; + break; + + case 'W': + warning = 1; + break; + + case 'D': + debug = 1; + break; + + case 'E': + error = 1; + break; + + case 'h': + help = 1; + break; + + case 'q': + queryhelp = 1; + break; + + case 'v': + version = 1; + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + int v = argc - optind; + // hostname port filename + if( v == 1 ) + { + shostname = argv[optind++]; + } + else if( v == 2 ) + { + shostname = argv[optind++]; + port = atoi( argv[optind++] ); + } + else if( v >= 3 ) + { + shostname = argv[optind++]; + port = atoi( argv[optind++] ); + std::vector files; + while (optind < argc) + { + files.push_back( argv[optind++] ); + } + filenames = files; + } + else + { + return 1; + } + assert( optind == argc ); + } + + if( version ) + { + PrintVersion(); + return 0; + } + + if( help ) + { + PrintHelp(); + return 0; + } + if(queryhelp) + { + PrintQueryHelp(findpatientroot); + return 0; + } + const bool theDebug = debug != 0; + const bool theWarning = warning != 0; + const bool theError = error != 0; + const bool theVerbose = verbose != 0; + const bool theRecursive = recursive != 0; + // Debug is a little too verbose + gdcm::Trace::SetDebug( theDebug ); + gdcm::Trace::SetWarning( theWarning ); + gdcm::Trace::SetError( theError ); + // when verbose is true, make sure warning+error are turned on: + if( verbose ) + { + gdcm::Trace::SetWarning( theVerbose ); + gdcm::Trace::SetError( theVerbose); + } + if( logfile ) + { + gdcm::Trace::SetStreamToFile( logfilename.c_str() ); + } + gdcm::FileMetaInformation::SetSourceApplicationEntityTitle( callaetitle.c_str() ); + if( !rootuid ) + { + // only read the env var if no explicit cmd line option + // maybe there is an env var defined... let's check + const char *rootuid_env = getenv("GDCM_ROOT_UID"); + if( rootuid_env ) + { + rootuid = 1; + root = rootuid_env; + } + } + if( rootuid ) + { + // root is set either by the cmd line option or the env var + if( !gdcm::UIDGenerator::IsValid( root.c_str() ) ) + { + std::cerr << "specified Root UID is not valid: " << root << std::endl; + return 1; + } + gdcm::UIDGenerator::SetRoot( root.c_str() ); + } + + if( shostname.empty() ) + { + //std::cerr << "Hostname missing" << std::endl; + PrintHelp(); // needed to display help message when no arg + return 1; + } + if( port == 0 ) + { + std::cerr << "Problem with port number" << std::endl; + return 1; + } + // checkout outputdir opt: + if( outputopt ) + { + if( !gdcm::System::FileIsDirectory( outputdir.c_str()) ) + { + if( !gdcm::System::MakeDirectory( outputdir.c_str() ) ) + { + std::cerr << "Sorry: " << outputdir << " is not a valid directory."; + std::cerr << std::endl; + std::cerr << "and I could not create it."; + std::cerr << std::endl; + return 1; + } + } + } + + const char *hostname = shostname.c_str(); + std::string mode = "echo"; + if ( echomode ) + { + mode = "echo"; + } + else if ( storemode ) + { + mode = "store"; + } + else if ( findmode ) + { + mode = "find"; + } + else if ( movemode ) + { + mode = "move"; + } + else if ( getmode ) + { + mode = "get"; + } + + //this class contains the networking calls + + if ( mode == "server" ) // C-STORE SCP + { + // MM: Do not expose that to user for now (2010/10/11). + //CStoreServer( port ); + return 1; + } + else if ( mode == "echo" ) // C-ECHO SCU + { + // ./bin/gdcmscu mi2b2.slicer.org 11112 --aetitle ACME1 --call MI2B2 + // ./bin/gdcmscu --echo mi2b2.slicer.org 11112 --aetitle ACME1 --call MI2B2 + bool didItWork = gdcm::CompositeNetworkFunctions::CEcho( hostname, (uint16_t)port, + callingaetitle.c_str(), callaetitle.c_str() ); + gdcmDebugMacro( (didItWork ? "Echo succeeded." : "Echo failed.") ); + return didItWork ? 0 : 1; + } + else if ( mode == "move" ) // C-FIND SCU + { + // ./bin/gdcmscu --move --patient dhcp-67-183 5678 move + // ./bin/gdcmscu --move --patient mi2b2.slicer.org 11112 move + gdcm::ERootType theRoot = gdcm::eStudyRootType; + if (findpatientroot) + theRoot = gdcm::ePatientRootType; + gdcm::EQueryLevel theLevel = gdcm::eStudy; + if (patientquery) + theLevel = gdcm::ePatient; + if (seriesquery) + theLevel = gdcm::eSeries; + if (imagequery) + theLevel = gdcm::eImage; + + gdcm::SmartPointer theQuery = + gdcm::CompositeNetworkFunctions::ConstructQuery(theRoot, theLevel ,keys, true); + + if (findstudyroot == 0 && findpatientroot == 0) + { + if (gdcm::Trace::GetErrorFlag()) + { + std::cerr << "Need to explicitly choose query retrieve level, --patientroot or --studyroot" << std::endl; + } + std::cerr << "Move failed." << std::endl; + return 1; + } + + if( !portscp ) + { + std::cerr << "Need to set explicitly port number for SCP association" + " --port-scp" << std::endl; + //std::cerr << "Move failed." << std::endl; + return 1; + } + + if( storequery ) + { + if (!theQuery->WriteQuery(queryfile)) + { + std::cerr << "Could not write out query to: " << queryfile << std::endl; + std::cerr << "Move failed." << std::endl; + return 1; + } + } + + if (!theQuery->ValidateQuery(false)) + { + std::cerr << "You have not constructed a valid find query." + " Please try again." << std::endl; + return 1; + } + + //!!! added the boolean to 'interleave writing', which basically writes + //each file out as it comes across, rather than all at once at the end. + //Turn off the boolean to have it written all at once at the end. + bool didItWork = gdcm::CompositeNetworkFunctions::CMove( hostname, (uint16_t)port, + theQuery, (uint16_t)portscpnum, + callingaetitle.c_str(), callaetitle.c_str(), outputdir.c_str() ); + gdcmDebugMacro( (didItWork ? "Move succeeded." : "Move failed.") ); + return didItWork ? 0 : 1; + } + else if ( mode == "find" ) // C-FIND SCU + { + // Construct C-FIND DataSet: + // ./bin/gdcmscu --find --patient dhcp-67-183 5678 + // ./bin/gdcmscu --find --patient mi2b2.slicer.org 11112 --aetitle ACME1 --call MI2B2 + // findscu -aec MI2B2 -P -k 0010,0010=F* mi2b2.slicer.org 11112 patqry.dcm + + // PATIENT query: + // ./bin/gdcmscu --find --patient mi2b2.slicer.org 11112 --aetitle ACME1 --call MI2B2 --key 10,10="F*" -V + gdcm::ERootType theRoot = gdcm::eStudyRootType; + if (findpatientroot) + theRoot = gdcm::ePatientRootType; + gdcm::EQueryLevel theLevel = gdcm::eStudy; + if (patientquery) + theLevel = gdcm::ePatient; + if (seriesquery) + theLevel = gdcm::eSeries; + if (imagequery) + theLevel = gdcm::eImage; + + gdcm::SmartPointer theQuery = + gdcm::CompositeNetworkFunctions::ConstructQuery(theRoot, theLevel ,keys); + + if (findstudyroot == 0 && findpatientroot == 0) + { + if (gdcm::Trace::GetErrorFlag()) + { + std::cerr << "Need to explicitly choose query retrieve level, --patientroot or --studyroot" << std::endl; + } + std::cerr << "Find failed." << std::endl; + return 1; + } + if (!theQuery) + { + std::cerr << "Query construction failed." <WriteQuery(queryfile)) + { + std::cerr << "Could not write out query to: " << queryfile << std::endl; + return 1; + } + } + + //doing a non-strict query, the second parameter there. + //look at the base query comments + if (!theQuery->ValidateQuery(false)) + { + std::cerr << "You have not constructed a valid find query." + " Please try again." << std::endl; + return 1; + } + //the value in that tag corresponds to the query type + std::vector theDataSet; + if( !gdcm::CompositeNetworkFunctions::CFind(hostname, (uint16_t)port, theQuery, theDataSet, + callingaetitle.c_str(), callaetitle.c_str()) ) + { + gdcmDebugMacro( "Problem in CFind." ); + return 1; + } + + gdcm::Printer p; + std::ostream &os = gdcm::Trace::GetStream(); + for( std::vector::iterator itor + = theDataSet.begin(); itor != theDataSet.end(); itor++) + { + os << "Find Response: " << (itor - theDataSet.begin() + 1) << std::endl; + p.PrintDataSet( *itor, os ); + os << std::endl; + } + + if( gdcm::Trace::GetWarningFlag() ) // == verbose flag + { + os << "Find was successful." << std::endl; + } + return 0; + } + else if ( mode == "store" ) // C-STORE SCU + { + // mode == directory + gdcm::Directory::FilenamesType thefiles; + for( gdcm::Directory::FilenamesType::const_iterator file = filenames.begin(); + file != filenames.end(); ++file ) + { + if( gdcm::System::FileIsDirectory(file->c_str()) ) + { + gdcm::Directory::FilenamesType files; + gdcm::Directory dir; + dir.Load(*file, theRecursive); + files = dir.GetFilenames(); + thefiles.insert(thefiles.end(), files.begin(), files.end()); + } + else + { + // This is a file simply add it + thefiles.push_back(*file); + } + } + bool didItWork = + gdcm::CompositeNetworkFunctions::CStore(hostname, (uint16_t)port, thefiles, + callingaetitle.c_str(), callaetitle.c_str()); + + gdcmDebugMacro( (didItWork ? "Store was successful." : "Store failed.") ); + return didItWork ? 0 : 1; + } + else if ( mode == "get" ) // C-GET SCU + { + return 1; + } + else + { + assert( 0 ); + return 1; + } + + return 0; +} diff --git a/gdcm/Applications/Cxx/gdcmstream.cxx b/gdcm/Applications/Cxx/gdcmstream.cxx new file mode 100644 index 0000000..8cc5baf --- /dev/null +++ b/gdcm/Applications/Cxx/gdcmstream.cxx @@ -0,0 +1,1123 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmAttribute.h" +#include "gdcmFile.h" +#include "gdcmFilename.h" +#include "gdcmImageHelper.h" +#include "gdcmItem.h" +#include "gdcmMediaStorage.h" +#include "gdcmSequenceOfItems.h" +#include "gdcmStreamImageReader.h" +#include "gdcmStreamImageWriter.h" +#include "gdcmSystem.h" +#include "gdcmTag.h" +#include "gdcmTrace.h" +#include "gdcmTransferSyntax.h" +#include "gdcmUIDGenerator.h" +#include "gdcmVersion.h" + +#ifdef OPENJPEG_MAJOR_VERSION +#if OPENJPEG_MAJOR_VERSION == 1 +#include "gdcm_openjpeg.h" +#elif OPENJPEG_MAJOR_VERSION == 2 +#define USE_OPJ_DEPRECATED // opj_setup_decoder +#include "gdcm_openjpeg2.h" +#else +#error should not happen +#endif +#else +#error should not happen +#endif + +#include + +static void error_callback(const char *msg, void *) { + (void)msg; +} +static void warning_callback(const char *msg, void *) { + (void)msg; +} +static void info_callback(const char *msg, void *) { + (void)msg; +} + +template +static unsigned int readvector(std::vector &v, const char *str) +{ + if( !str ) return 0; + std::istringstream os( str ); + T f; + while( os >> f ) + { + v.push_back( f ); + os.get(); // == "," + } + + return (unsigned int)v.size(); +} + +static int No_Of_Resolutions(const char *filename) +{ + std::ifstream is; + is.open( filename, std::ios::binary ); + opj_dparameters_t parameters; /* decompression parameters */ + opj_event_mgr_t event_mgr; /* event manager */ + opj_dinfo_t* dinfo; /* handle to a decompressor */ + opj_cio_t *cio; + // FIXME: Do some stupid work: + is.seekg( 0, std::ios::end); + size_t buf_size = (size_t)is.tellg(); + char *dummy_buffer = new char[(unsigned int)buf_size]; + is.seekg(0, std::ios::beg); + is.read( dummy_buffer, buf_size); + unsigned char *src = (unsigned char*)dummy_buffer; + uint32_t file_length = (uint32_t)buf_size; // 32bits truncation should be ok since DICOM cannot have larger than 2Gb image + + + /* configure the event callbacks (not required) */ + memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); + event_mgr.error_handler = error_callback; + event_mgr.warning_handler = warning_callback; + event_mgr.info_handler = info_callback; + + /* set decoding parameters to default values */ + opj_set_default_decoder_parameters(¶meters); + + // default blindly copied + parameters.cp_layer=0; + parameters.cp_reduce= 0; + // parameters.decod_format=-1; + // parameters.cod_format=-1; + + const char jp2magic[] = "\x00\x00\x00\x0C\x6A\x50\x20\x20\x0D\x0A\x87\x0A"; + if( memcmp( src, jp2magic, sizeof(jp2magic) ) == 0 ) + { + /* JPEG-2000 compressed image data ... sigh */ + // gdcmData/ELSCINT1_JP2vsJ2K.dcm + // gdcmData/MAROTECH_CT_JP2Lossy.dcm + //gdcmWarningMacro( "J2K start like JPEG-2000 compressed image data instead of codestream" ); + parameters.decod_format = 1; //JP2_CFMT; + //assert(parameters.decod_format == JP2_CFMT); + } + else + { + /* JPEG-2000 codestream */ + //parameters.decod_format = J2K_CFMT; + //assert(parameters.decod_format == J2K_CFMT); + assert( 0 ); + } + parameters.cod_format = 11; // PGX_DFMT; + //assert(parameters.cod_format == PGX_DFMT); + + /* get a decoder handle */ + dinfo = opj_create_decompress(CODEC_JP2); + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, NULL); + + /* setup the decoder decoding parameters using user parameters */ + opj_setup_decoder(dinfo, ¶meters); + + /* open a byte stream */ + cio = opj_cio_open((opj_common_ptr)dinfo, src, file_length); + + /* decode the stream and fill the image structure */ + if(! opj_decode(dinfo, cio)) { + opj_destroy_decompress(dinfo); + opj_cio_close(cio); + //gdcmErrorMacro( "opj_decode failed" ); + return 1; + } + + opj_cp_t * cp = ((opj_jp2_t*)dinfo->jp2_handle)->j2k->cp; + opj_tcp_t *tcp = &cp->tcps[0]; + opj_tccp_t *tccp = &tcp->tccps[0]; + + return tccp->numresolutions; + /* std::cout << "\n No of Cols In Image" << image->x1; + std::cout << "\n No of Rows In Image" << image->y1; + std::cout << "\n No of Components in Image" << image->numcomps; + std::cout << "\n No of Resolutions"<< tccp->numresolutions << "\n"; +*/ + +} + +static bool Write_Resolution(gdcm::StreamImageWriter & theStreamWriter, const char *filename, int res, std::ostream& of, int flag, gdcm::SequenceOfItems *sq) +{ + (void)of; + std::ifstream is; + is.open( filename, std::ios::binary ); + opj_dparameters_t parameters; /* decompression parameters */ + opj_event_mgr_t event_mgr; /* event manager */ + opj_dinfo_t* dinfo; /* handle to a decompressor */ + opj_cio_t *cio; + opj_image_t *image = NULL; + // FIXME: Do some stupid work: + is.seekg( 0, std::ios::end); + size_t buf_size = (size_t)is.tellg(); + char *dummy_buffer = new char[buf_size]; + is.seekg(0, std::ios::beg); + is.read( dummy_buffer, buf_size); + unsigned char *src = (unsigned char*)dummy_buffer; + uint32_t file_length = (uint32_t)buf_size; // 32bits truncation should be ok since DICOM cannot have larger than 2Gb image + + + /* configure the event callbacks (not required) */ + memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); + event_mgr.error_handler = error_callback; + event_mgr.warning_handler = warning_callback; + event_mgr.info_handler = info_callback; + + /* set decoding parameters to default values */ + opj_set_default_decoder_parameters(¶meters); + + // default blindly copied + parameters.cp_layer=0; + parameters.cp_reduce= res; + // parameters.decod_format=-1; + // parameters.cod_format=-1; + + const char jp2magic[] = "\x00\x00\x00\x0C\x6A\x50\x20\x20\x0D\x0A\x87\x0A"; + if( memcmp( src, jp2magic, sizeof(jp2magic) ) == 0 ) + { + /* JPEG-2000 compressed image data ... sigh */ + // gdcmData/ELSCINT1_JP2vsJ2K.dcm + // gdcmData/MAROTECH_CT_JP2Lossy.dcm + //gdcmWarningMacro( "J2K start like JPEG-2000 compressed image data instead of codestream" ); + parameters.decod_format = 1; //JP2_CFMT; + //assert(parameters.decod_format == JP2_CFMT); + } + else + { + /* JPEG-2000 codestream */ + //parameters.decod_format = J2K_CFMT; + //assert(parameters.decod_format == J2K_CFMT); + assert( 0 ); + } + parameters.cod_format = 11; // PGX_DFMT; + //assert(parameters.cod_format == PGX_DFMT); + + /* get a decoder handle */ + dinfo = opj_create_decompress(CODEC_JP2); + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, NULL); + + /* setup the decoder decoding parameters using user parameters */ + opj_setup_decoder(dinfo, ¶meters); + + /* open a byte stream */ + cio = opj_cio_open((opj_common_ptr)dinfo, src, file_length); + + /* decode the stream and fill the image structure */ + image = opj_decode(dinfo, cio); + if(!image) + { + opj_destroy_decompress(dinfo); + opj_cio_close(cio); + //gdcmErrorMacro( "opj_decode failed" ); + return 1; + } + + //opj_cp_t * cp = ((opj_jp2_t*)dinfo->jp2_handle)->j2k->cp; + //opj_tcp_t *tcp = &cp->tcps[0]; + //opj_tccp_t *tccp = &tcp->tccps[0]; + /* std::cout << "\n No of Cols In Image" << image->x1; + std::cout << "\n No of Rows In Image" << image->y1; + std::cout << "\n No of Components in Image" << image->numcomps; + std::cout << "\n No of Resolutions"<< tccp->numresolutions << "\n"; + */ + //opj_j2k_t* j2k = NULL; + //opj_jp2_t* jp2 = NULL; + //jp2 = (opj_jp2_t*)dinfo->jp2_handle; + //int reversible = jp2->j2k->cp->tcps->tccps->qmfbid; + //std:: cout << reversible; + int Dimensions[2]; +{ + int compno = 0; + opj_image_comp_t *comp = &image->comps[compno]; + Dimensions[0]= comp->w; + Dimensions[1] = comp->h; + opj_cio_close(cio); +} + unsigned long rawlen = Dimensions[0]*Dimensions[1] * image->numcomps; + //std::cout << "\nTest" <comps[0].factor; + char *raw = new char[rawlen]; + + for (unsigned int compno = 0; compno < (unsigned int)image->numcomps; compno++) + { + const opj_image_comp_t *comp = &image->comps[compno]; + + int w = comp->w; + int h = comp->h; + uint8_t *data8 = (uint8_t*)raw + compno; + for (int i = 0; i < w * h ; i++) + { + int v = image->comps[compno].data[i]; + *data8 = (uint8_t)v; + data8 += image->numcomps; + } + } + + + gdcm::Writer w; + gdcm::File &file = w.GetFile(); + gdcm::DataSet &ds = file.GetDataSet(); + + file.GetHeader().SetDataSetTransferSyntax( gdcm::TransferSyntax::ExplicitVRLittleEndian ); + + gdcm::UIDGenerator uid; + gdcm::DataElement de( gdcm::Tag(0x8,0x18) ); // SOP Instance UID + de.SetVR( gdcm::VR::UI ); + const char *u = uid.Generate(); + de.SetByteValue( u, (uint32_t)strlen(u) ); + ds.Insert( de ); + + gdcm::DataElement de1( gdcm::Tag(0x8,0x16) ); + de1.SetVR( gdcm::VR::UI ); + gdcm::MediaStorage ms( gdcm::MediaStorage::VLWholeSlideMicroscopyImageStorage ); + de1.SetByteValue( ms.GetString(), (uint32_t)strlen(ms.GetString())); + ds.Insert( de1 ); + + gdcm::DataElement de2( gdcm::Tag(0x28,0x04) ); + //de.SetTag(gdcm::Tag(0x28,0x04)); + de2.SetVR( gdcm::VR::CS ); + + if(image->numcomps == 1) + { + const char mystr[] = "MONOCHROME2"; + de2.SetByteValue(mystr, (uint32_t)strlen(mystr)); + } + else + { + const char mystr1[] = "RGB"; + de2.SetByteValue(mystr1, (uint32_t)strlen(mystr1)); + } + + ds.Insert( de2 ); + + + gdcm::Attribute<0x0028,0x0100> at = {8}; + ds.Insert( at.GetAsDataElement() ); + + gdcm::Attribute<0x0028,0x0002> at1 = { (uint16_t)image->numcomps}; + ds.Insert( at1.GetAsDataElement() ); + + gdcm::Attribute<0x0028,0x0101> at2 = {8}; + ds.Insert( at2.GetAsDataElement() ); + + gdcm::Attribute<0x0028,0x0102> at3 = {7}; + ds.Insert( at3.GetAsDataElement() ); + + + if (flag == 1) //This flag is to write Image Information + { + for (int i=0; i <= res; i++) // Loop to set different dimensions of all resolution + { + int a = 1; + int b =1; + while(a!=((res+1)-i)) + { + b = b*2; + a = a+1; + } + + uint16_t row = (uint16_t)((image->y1)/b); + uint16_t col = (uint16_t)((image->x1)/b); + + gdcm::Element el2; + el2.SetValue(i+1); + gdcm::DataElement rfn = el2.GetAsDataElement(); //rfn ---> reference frame number + rfn.SetTag( gdcm::Tag(0x0008,0x1160) ); + + gdcm::Element el; + el.SetValue(1,0); + el.SetValue(1,1); + gdcm::DataElement ulr = el.GetAsDataElement(); //ulr --> upper left col/row + ulr.SetTag( gdcm::Tag(0x0048,0x0201) ); + + gdcm::Element el1; + el1.SetValue(col,0); + el1.SetValue(row,1); + gdcm::DataElement brr = el1.GetAsDataElement(); + brr.SetTag( gdcm::Tag(0x0048,0x0202) ); //brr --> bottom right col/row + + gdcm::Item it; + gdcm::DataSet &nds = it.GetNestedDataSet(); + nds.Insert( rfn ); + nds.Insert(ulr); + nds.Insert(brr); + + sq->AddItem(it); + }//For loop + + gdcm::File &file2 = w.GetFile(); + gdcm::DataSet &ds1 = file2.GetDataSet(); + + gdcm::Attribute<0x0048,0x0006> row1 = {(unsigned short)image->y1}; + ds1.Insert( row1.GetAsDataElement() ); + + gdcm::Attribute<0x0048,0x0007> col1 = {(unsigned short)image->x1}; + ds1.Insert( col1.GetAsDataElement() ); + gdcm::Attribute<0x0028,0x0008> Number_Of_Frames = {res+1}; + ds1.Insert( Number_Of_Frames.GetAsDataElement() ); + + gdcm::DataElement des( gdcm::Tag(0x0048,0x0200) ); + des.SetVR(gdcm::VR::SQ); + des.SetValue(*sq); + des.SetVLToUndefined(); + + ds1.Insert(des); + + theStreamWriter.SetFile(file2); + + if (!theStreamWriter.WriteImageInformation()) + { + std::cerr << "unable to write image information" << std::endl; + return 1; //the CanWrite function should prevent getting here, else, + //that's a test failure + } + + ds1.Remove( gdcm::Tag(0x0048,0x0006) ); + ds1.Remove( gdcm::Tag(0x0048,0x0007) ); + ds1.Remove( gdcm::Tag(0x0028,0x0008) ); + }//if (flag == 1) //This flag is to write Image Information + + gdcm::Attribute<0x0048,0x0006> row = {(unsigned short)image->comps[0].w}; + ds.Insert( row.GetAsDataElement() ); + + gdcm::Attribute<0x0048,0x0007> col = {(unsigned short)image->comps[0].h}; + ds.Insert( col.GetAsDataElement() ); + + gdcm::Attribute<0x0028,0x0008> Number_Of_Frames = {1}; + ds.Insert( Number_Of_Frames.GetAsDataElement() ); + + theStreamWriter.SetFile(file); + + if (!theStreamWriter.CanWriteFile()) + { + delete [] raw; + std::cerr << "Not able to write" << std::endl; + return 0;//this means that the file was unwritable, period. + //very similar to a ReadImageInformation failure + } + + // Important to write here + std::vector extent = gdcm::ImageHelper::GetDimensionsValue(file); + + unsigned short xmax = (uint16_t)extent[0]; + unsigned short ymax = (uint16_t)extent[1]; + unsigned short theChunkSize = 4; + unsigned short ychunk = (unsigned short)(extent[1]/theChunkSize); //go in chunk sizes of theChunkSize + unsigned short zmax = (uint16_t)extent[2]; + //std::cout << "\n"<numcomps<<"\n"; + + if (xmax == 0 || ymax == 0) + { + std::cerr << "Image has no size, unable to write zero-sized image." << std::endl; + return 0; + } + + int z, y, nexty; + unsigned long prevLen = 0; //when going through the char buffer, make sure to grab + //the bytes sequentially. So, store how far you got in the buffer with each iteration. + for (z = 0; z < zmax; ++z) + { + for (y = 0; y < ymax; y += ychunk) + { + nexty = y + ychunk; + if (nexty > ymax) nexty = ymax; + theStreamWriter.DefinePixelExtent(0, xmax, (uint16_t)y, (uint16_t)nexty, (uint16_t)z, (uint16_t)(z+1)); + unsigned long len = theStreamWriter.DefineProperBufferLength(); + //std::cout << "\n" < ymax) nexty = ymax; + reader.DefinePixelExtent(xmin, xmax, (uint16_t)y, (uint16_t)nexty, (uint16_t)z, (uint16_t)(z+1)); + unsigned long len = reader.DefineProperBufferLength(); + + char* finalBuffer = new char[len]; + if (reader.CanReadImage()) + { + bool result = reader.Read(finalBuffer, len); + if( !result ) + { + std::cerr << "res2 failure:" << std::endl; + delete [] finalBuffer; + return 1; + } + else + { + // std::cout<< "Able to read"; + //delete [] finalBuffer; + // return 0; //essentially, we're going to skip this file since it can't be read by the streamer + } + } + else + { + std::cerr<< "Not able to put in read data buffer"<< std::endl; + } + theStreamWriter.DefinePixelExtent(xmin, xmax, (uint16_t)y, (uint16_t)nexty, (uint16_t)z, (uint16_t)(z+1)); + // unsigned long len = theStreamWriter.DefineProperBufferLength(); + //std::cout << "\n" < start, std::vector end) +{ + //std::vector::const_iterator it = filenames.begin(); + gdcm::StreamImageReader reader; + reader.SetFileName( filename ); + + + if (!reader.ReadImageInformation()) + { + std::cerr << "unable to read image information" << std::endl; + return 1; //unable to read tags as expected. + } + + gdcm::File file1 = reader.GetFile(); + gdcm::DataSet ds1 = file1.GetDataSet(); + + + gdcm::Writer w; + gdcm::File &file = w.GetFile(); + gdcm::DataSet &ds = file.GetDataSet(); + + + + file.GetHeader().SetDataSetTransferSyntax( gdcm::TransferSyntax::ExplicitVRLittleEndian ); + gdcm::DataElement uid = ds1.GetDataElement( gdcm::Tag(0x0008,0x0018) ); + ds.Insert( uid ); + + gdcm::DataElement ms = ds1.GetDataElement( gdcm::Tag(0x0008,0x0016) ); + ds.Insert( ms ); + + gdcm::DataElement mystr = ds1.GetDataElement( gdcm::Tag(0x0028,0x0004) ); + ds.Insert( mystr ); + + if(res == 0) + { + gdcm::DataElement seq = ds1.GetDataElement( gdcm::Tag(0x0048,0x0200) ); + ds.Insert(seq); + } + else + { + std::vector extent = reader.GetDimensionsValueForResolution(res); + + + gdcm::SmartPointer sq = new gdcm::SequenceOfItems(); + sq->SetLengthToUndefined(); + gdcm::Element el1; + el1.SetValue(res); + gdcm::DataElement rfn = el1.GetAsDataElement(); //rfn ---> reference frame number + rfn.SetTag( gdcm::Tag(0x0008,0x1160) ); + + gdcm::Element el2; + if(tile == 1) + { + el2.SetValue((unsigned short)start[0],0); + el2.SetValue((unsigned short)start[1],1); + } + else + { + el2.SetValue(1,0); + el2.SetValue(1,1); + } + gdcm::DataElement ulr = el2.GetAsDataElement(); //ulr --> upper left col/row + ulr.SetTag( gdcm::Tag(0x0048,0x0201) ); + + + gdcm::Element el3; + if(tile == 1) + { + el3.SetValue((unsigned short)end[0],0); + el3.SetValue((unsigned short)end[1],1); + } + else + { + el3.SetValue((unsigned short)extent[0],0); + el3.SetValue((unsigned short)extent[1],1); + } + gdcm::DataElement brr = el3.GetAsDataElement(); + brr.SetTag( gdcm::Tag(0x0048,0x0202) ); //brr --> bottom right col/row + + gdcm::Item it; + gdcm::DataSet &nds = it.GetNestedDataSet(); + nds.Insert( rfn ); + nds.Insert(ulr); + nds.Insert(brr); + + sq->AddItem(it); + + gdcm::DataElement des( gdcm::Tag(0x0048,0x0200) ); + des.SetVR(gdcm::VR::SQ); + des.SetValue(*sq); + des.SetVLToUndefined(); + + ds.Insert(des); + + } + + + + + gdcm::DataElement row = ds1.GetDataElement( gdcm::Tag(0x0048,0x0006) ); + assert( row.GetVR() == gdcm::VR::UL ); + ds.Insert(row); + + gdcm::DataElement col = ds1.GetDataElement( gdcm::Tag(0x0048,0x0007) ); + ds.Insert(col); + + gdcm::DataElement Number_Of_Frames = ds1.GetDataElement( gdcm::Tag(0x0028,0x0008) ); + ds.Insert(Number_Of_Frames); + + gdcm::Element el; + el.SetFromDataElement( Number_Of_Frames ); + + + uint16_t No_Of_Resolutions = (uint16_t)el.GetValue(0); + //std::cout << "HERE NO. "<< No_Of_Resolutions; + + gdcm::DataElement BA = ds1.GetDataElement( gdcm::Tag(0x0028,0x0100) ); + ds.Insert( BA ); + + gdcm::DataElement SPP = ds1.GetDataElement( gdcm::Tag(0x0028,0x0002) ); + ds.Insert( SPP ); + + gdcm::DataElement BS = ds1.GetDataElement( gdcm::Tag(0x0028,0x0101) ); + ds.Insert( BS ); + + gdcm::DataElement HB = ds1.GetDataElement( gdcm::Tag(0x0028,0x0102) ); + ds.Insert( HB ); + + theStreamWriter.SetFile(file); + + if (!theStreamWriter.WriteImageInformation()) + { + std::cerr << "unable to write image information" << std::endl; + return 1; //the CanWrite function should prevent getting here, else, + //that's a test failure + } + + + bool b = true; + + if(res == 0) + { + for(int i = 1 ; i <= No_Of_Resolutions; ++i) + { + b = b && StreamImageRead_Write( theStreamWriter, reader, i, of, tile , start , end ); + } + } + else + b = b && StreamImageRead_Write( theStreamWriter, reader, res, of ,tile, start, end ); + + return b; +} + + + +static bool Different_Resolution_From_jp2( gdcm::StreamImageWriter & theStreamWriter, const char *filename, std::ostream& of, int nres) +{ + //std::vector::const_iterator it = filenames.begin(); + bool b = true; + int flag = 1; + + gdcm::SmartPointer sq = new gdcm::SequenceOfItems(); + sq->SetLengthToUndefined(); + + int resolutions; + + if(nres==0) + resolutions = No_Of_Resolutions(filename); + else + resolutions = nres; + + for(int i = resolutions-1 ; i>=0; --i) + { + b = b && Write_Resolution( theStreamWriter, filename, i, of ,flag,sq); + flag = 0; + } + return b; +} + + + +static void PrintVersion() +{ + std::cout << "gdcmstream: gdcm " << gdcm::Version::GetVersion() << " "; + const char date[] = "$Date$"; + std::cout << date << std::endl; +} + +static void PrintHelp() +{ + PrintVersion(); + std::cout << "Usage: gdcmstream [OPTION] input.dcm output.dcm" << std::endl; +} + +static void end_of_WSIFile(std::ostream& of) +{ + uint16_t firstTag1 = 0xfffe; + uint16_t secondTag1 = 0xe0dd; + uint32_t thirdTag1 = 0x00000000; + //uint16_t fourthTag1 = 0xffff; + const int theBufferSize1 = 2*sizeof(uint16_t)+sizeof(uint32_t); + char* tmpBuffer2 = new char[theBufferSize1]; + memcpy(&(tmpBuffer2[0]), &firstTag1, sizeof(uint16_t)); + memcpy(&(tmpBuffer2[sizeof(uint16_t)]), &secondTag1, sizeof(uint16_t)); + memcpy(&(tmpBuffer2[2*sizeof(uint16_t)]), &thirdTag1, sizeof(uint32_t)); + //memcpy(&(tmpBuffer2[3*sizeof(uint16_t)]), &fourthTag1, sizeof(uint16_t)); + assert( of && !of.eof() && of.good() ); + of.write(tmpBuffer2, theBufferSize1); + of.flush(); + assert( of ); +} + +int main (int argc, char *argv[]) +{ + int c; + //int digit_optind = 0; + //std::string filename; + //std::string outfilename; + gdcm::Filename filename; + gdcm::Filename outfilename; + + std::string root; + int rootuid = 0; + int verbose = 0; + int warning = 0; + int debug = 0; + int error = 0; + int help = 0; + int version = 0; + int nres = 0; + int res = 0; + int tile = 0; + std::vector start; + std::vector end; + + while (1) { + + //int this_option_optind = optind ? optind : 1; + int option_index = 0; + static struct option long_options[] = { + {"input", 1, 0, 0}, + {"output", 1, 0, 0}, + + // General options ! + {"verbose", 0, &verbose, 1}, + {"warning", 0, &warning, 1}, + {"debug", 0, &debug, 1}, + {"error", 0, &error, 1}, + {"help", 0, &help, 1}, + {"version", 0, &version, 1}, + {"resolution", 1, &nres, 1}, + {"resolution-only", 1, &res, 1}, + {"roi-start", 1, &tile, 1}, + {"roi-end", 1, &tile, 1}, + {0, 0, 0, 0} + }; + c = getopt_long (argc, argv, "i:o:VWDEhv:r:n:",long_options, &option_index); + + if (c == -1) + { + break; + } + + switch (c) + { + case 0: + { + const char *s = long_options[option_index].name; (void)s; + + //printf ("option %s", s); + if (optarg) + { + if( option_index == 0 ) /* input */ + { + assert( strcmp(s, "input") == 0 ); + assert( filename.IsEmpty() ); + filename = optarg; + } + //printf (" with arg %s, index = %d", optarg, option_index) + else if( option_index == 1 ) /* input */ + { + assert( strcmp(s, "output") == 0 ); + assert( outfilename.IsEmpty() ); + outfilename = optarg; + } + //printf (" with arg %s, index = %d", optarg, option_index); + + else if( option_index == 8 ) /* number of resolution */ + { + assert( strcmp(s, "resolution") == 0 ); + nres = atoi(optarg); + } + + else if( option_index == 9 ) /* number of resolution */ + { + assert( strcmp(s, "resolution-only") == 0 ); + res = atoi(optarg); + } + + else if( option_index == 10 ) /* tile */ + { + assert( strcmp(s, "roi-start") == 0 ); + tile = 1; + unsigned int n = readvector(start, optarg); + assert( n == 2 ); (void)n; + } + else if( option_index == 11 ) /* tile */ + { + assert( strcmp(s, "roi-end") == 0 ); + tile = 1; + unsigned int n = readvector(end, optarg); + assert( n == 2 ); (void)n; + } + + //printf ("\n"); + } + + } + break; + + case 'i': + assert( filename.IsEmpty() ); + filename = optarg; + break; + + case 'o': + assert( outfilename.IsEmpty() ); + outfilename = optarg; + break; + + // General option + case 'V': + verbose = 1; + break; + + case 'W': + warning = 1; + break; + + case 'D': + debug = 1; + break; + + case 'E': + error = 1; + break; + + case 'h': + help = 1; + break; + + case 'v': + version = 1; + break; + + case 'r': + nres = atoi(optarg); + break; + + case 'n': + res = atoi(optarg); + break; + + + case '?': + break; + + default: + + printf ("?? getopt returned character code 0%o ??\n", c); + + } + } + + // For now only support one input / one output + if (optind < argc) + { + //printf ("non-option ARGV-elements: "); + //std::cout << "HERE"; + std::vector files; + while (optind < argc) + { + //printf ("%s\n", argv[optind]); + files.push_back( argv[optind] ); + } + + //printf ("\n"); + if( files.size() == 2 && filename.IsEmpty() && outfilename.IsEmpty() ) + { + filename = files[0].c_str(); + outfilename = files[ files.size() - 1 ].c_str(); + } + else + { + PrintHelp(); + return 1; + } + }//if (optind < argc) + + if( version ) + { + std::cout << "version" << std::endl; + PrintVersion(); + return 0; + } + + if( help ) + { + std::cout << "help here" << std::endl; + PrintHelp(); + return 0; + } + + if( filename.IsEmpty()) + { + std::cerr << "Need input file (-i)\n"; + PrintHelp(); + return 1; + } + + if( outfilename.IsEmpty() ) + { + std::cerr << "Need output file (-o)\n"; + PrintHelp(); + return 1; + } + + // Debug is a little too verbose + + gdcm::Trace::SetDebug( (debug > 0 ? true : false)); + gdcm::Trace::SetWarning( (warning > 0 ? true : false)); + gdcm::Trace::SetError( (error > 0 ? true : false)); + // when verbose is true, make sure warningerror are turned on: + + if( verbose ) + { + gdcm::Trace::SetWarning( (verbose > 0 ? true : false) ); + gdcm::Trace::SetError( (verbose > 0 ? true : false) ); + } + + + gdcm::FileMetaInformation::SetSourceApplicationEntityTitle( "gdcmstream" ); + + if( !rootuid ) + { + // only read the env var is no explicit cmd line option + // maybe there is an env var defined... let's check + const char *rootuid_env = getenv("GDCM_ROOT_UID"); + + if( rootuid_env ) + { + rootuid = 1; + root = rootuid_env; + } + + } + + if( rootuid ) + { + // root is set either by the cmd line option or the env var + if( !gdcm::UIDGenerator::IsValid( root.c_str() ) ) + { + std::cerr << "specified Root UID is not valid: " << root << std::endl; + return 1; + } + + gdcm::UIDGenerator::SetRoot( root.c_str() ); + } + + const char *inputextension = filename.GetExtension(); + //const char *outputextension = outfilename.GetExtension(); + + gdcm::StreamImageWriter theStreamWriter; + std::ofstream of; + of.open( outfilename, std::ios::out | std::ios::binary ); + theStreamWriter.SetStream(of); + + if( inputextension ) + { + if( gdcm::System::StrCaseCmp(inputextension,".jp2") == 0 ) + { + if( !Different_Resolution_From_jp2( theStreamWriter, filename,of,nres ) ) return 1; + end_of_WSIFile(of); + } + + if( gdcm::System::StrCaseCmp(inputextension,".dcm") == 0 ) + { + Different_Resolution_From_DICOM( theStreamWriter, filename, of, res , tile , start , end); + //if(!StreamImageRead_Write( theStreamWriter, filename, 0)) return 1; + end_of_WSIFile(of); + } + } + + // gdcm::StreamImageReader ... + return 0; +} diff --git a/gdcm/Applications/Cxx/gdcmtar.cxx b/gdcm/Applications/Cxx/gdcmtar.cxx new file mode 100644 index 0000000..b27b2ed --- /dev/null +++ b/gdcm/Applications/Cxx/gdcmtar.cxx @@ -0,0 +1,1300 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + * tar is a UNIX program for archiving. + * Two types of operations are possible: concatenate / extract + * Thus the name of 'gdcmtar' to concatenate a list of 2D slices into a multi frames + * and the other way around: extract 2D slices from a multi frames image + * It also support the fake multi frame image (CSA MOSAIC) + */ + +#include "gdcmReader.h" +#include "gdcmVersion.h" +#include "gdcmImageReader.h" +#include "gdcmDataElement.h" +#include "gdcmImageWriter.h" +#include "gdcmSplitMosaicFilter.h" +#include "gdcmFilename.h" +#include "gdcmFilenameGenerator.h" +#include "gdcmDirectionCosines.h" +#include "gdcmImageHelper.h" +#include "gdcmUIDGenerator.h" +#include "gdcmUIDs.h" +#include "gdcmGlobal.h" +#include "gdcmDirectory.h" +#include "gdcmScanner.h" +#include "gdcmIPPSorter.h" +#include "gdcmAttribute.h" + +#include +#include + +#include /* for printf */ +#include /* for exit */ +#include +#include + +static void PrintVersion() +{ + std::cout << "gdcmtar: gdcm " << gdcm::Version::GetVersion() << " "; + const char date[] = "$Date$"; + std::cout << date << std::endl; +} + +static void PrintHelp() +{ + PrintVersion(); + std::cout << "Usage: gdcmtar [OPTION] [FILE]" << std::endl; + std::cout << "Concatenate/Extract DICOM files.\n"; + std::cout << "Parameter (required):" << std::endl; + std::cout << " -i --input DICOM filename" << std::endl; + std::cout << " -o --output DICOM filename" << std::endl; + std::cout << "Options:" << std::endl; + std::cout << " --enhance enhance (default)" << std::endl; + std::cout << " -U --unenhance unenhance" << std::endl; + std::cout << " -M --mosaic Split SIEMENS Mosaic image into multiple frames." << std::endl; + std::cout << " -p --pattern Specify trailing file pattern." << std::endl; + std::cout << " --root-uid Root UID." << std::endl; + //std::cout << " --resources-path Resources path." << std::endl; + std::cout << "General Options:" << std::endl; + std::cout << " -V --verbose more verbose (warning+error)." << std::endl; + std::cout << " -W --warning print warning info." << std::endl; + std::cout << " -D --debug print debug info." << std::endl; + std::cout << " -E --error print error info." << std::endl; + std::cout << " -h --help print help." << std::endl; + std::cout << " -v --version print version." << std::endl; + std::cout << "Env var:" << std::endl; + std::cout << " GDCM_ROOT_UID Root UID" << std::endl; + //std::cout << " GDCM_RESOURCES_PATH path pointing to resources files (Part3.xml, ...)" << std::endl; +} + +/* + * The following example is a basic sorted which should work in generic cases. + * It sort files based on: + * Study Instance UID + * Series Instance UID + * Frame of Reference UID + * Image Orientation (Patient) + * Image Position (Patient) (Sorting based on IPP + IOP) + */ + +namespace gdcm { + const Tag T0(0x0008,0x0016); // SOP Class UID + const Tag T1(0x0020,0x000d); // Study Instance UID + const Tag T2(0x0020,0x000e); // Series Instance UID + const Tag T3(0x0020,0x0052); // Frame of Reference UID + const Tag T4(0x0020,0x0037); // Image Orientation (Patient) + +class DiscriminateVolume +{ +private: + static const bool debuggdcmtar = false; + std::vector< Directory::FilenamesType > SortedFiles; + std::vector< Directory::FilenamesType > UnsortedFiles; + + Directory::FilenamesType GetAllFilenamesFromTagToValue( + Scanner const & s, Directory::FilenamesType const &filesubset, Tag const &t, const char *valueref) +{ + Directory::FilenamesType theReturn; + if( valueref ) + { + size_t len = strlen( valueref ); + Directory::FilenamesType::const_iterator file = filesubset.begin(); + for(; file != filesubset.end(); ++file) + { + const char *filename = file->c_str(); + const char * value = s.GetValue(filename, t); + if( value && strncmp(value, valueref, len ) == 0 ) + { + theReturn.push_back( filename ); + } + } + } + return theReturn; +} + +void ProcessAIOP(Scanner const & , Directory::FilenamesType const & subset, const char *iopval) +{ + if( debuggdcmtar ) + std::cout << "IOP: " << iopval << std::endl; + IPPSorter ipp; + ipp.SetComputeZSpacing( true ); + ipp.SetZSpacingTolerance( 1e-3 ); // ?? + bool b = ipp.Sort( subset ); + if( !b ) + { + // If you reach here this means you need one more parameter to discriminiat this + // series. Eg. T1 / T2 intertwinted. Multiple Echo (0018,0081) + if( debuggdcmtar ) + { + std::cerr << "Failed to sort: " << subset.begin()->c_str() << std::endl; + for( + Directory::FilenamesType::const_iterator file = subset.begin(); + file != subset.end(); ++file) + { + std::cerr << *file << std::endl; + } + } + UnsortedFiles.push_back( subset ); + return ; + } + if( debuggdcmtar ) + ipp.Print( std::cout ); + SortedFiles.push_back( ipp.GetFilenames() ); +} + +void ProcessAFrameOfRef(Scanner const & s, Directory::FilenamesType const & subset, const char * frameuid) +{ + // In this subset of files (belonging to same series), let's find those + // belonging to the same Frame ref UID: + Directory::FilenamesType files = GetAllFilenamesFromTagToValue( + s, subset, T3, frameuid); + + std::set< std::string > iopset; + + for( + Directory::FilenamesType::const_iterator file = files.begin(); + file != files.end(); ++file) + { + //std::cout << *file << std::endl; + const char * value = s.GetValue(file->c_str(), gdcm::T4 ); + assert( value ); + iopset.insert( value ); + } + size_t n = iopset.size(); + if ( n == 0 ) + { + assert( files.empty() ); + return; + } + + if( debuggdcmtar ) + std::cout << "Frame of Ref: " << frameuid << std::endl; + if ( n == 1 ) + { + ProcessAIOP(s, files, iopset.begin()->c_str() ); + } + else + { + const char *f = files.begin()->c_str(); + if( debuggdcmtar ) + std::cerr << "More than one IOP: " << f << std::endl; + // Make sure that there is actually 'n' different IOP + gdcm::DirectionCosines ref; + gdcm::DirectionCosines dc; + for( + std::set< std::string >::const_iterator it = iopset.begin(); + it != iopset.end(); ++it ) + { + ref.SetFromString( it->c_str() ); + for( + Directory::FilenamesType::const_iterator file = files.begin(); + file != files.end(); ++file) + { + std::string value = s.GetValue(file->c_str(), gdcm::T4 ); + if( value != it->c_str() ) + { + dc.SetFromString( value.c_str() ); + const double crossdot = ref.CrossDot(dc); + const double eps = std::fabs( 1. - crossdot ); + if( eps < 1e-6 ) + { + std::cerr << "Problem with IOP discrimination: " << file->c_str() + << " " << it->c_str() << std::endl; + return; + } + } + } + } + // If we reach here this means there is actually 'n' different IOP + for( + std::set< std::string >::const_iterator it = iopset.begin(); + it != iopset.end(); ++it ) + { + const char *iopvalue = it->c_str(); + Directory::FilenamesType iopfiles = GetAllFilenamesFromTagToValue( + s, files, T4, iopvalue ); + ProcessAIOP(s, iopfiles, iopvalue ); + } + } +} + +void ProcessASeries(Scanner const & s, const char * seriesuid) +{ + if( debuggdcmtar ) + std::cout << "Series: " << seriesuid << std::endl; + // let's find all files belonging to this series: + Directory::FilenamesType seriesfiles = GetAllFilenamesFromTagToValue( + s, s.GetFilenames(), T2, seriesuid); + + gdcm::Scanner::ValuesType vt3 = s.GetValues(T3); + for( + gdcm::Scanner::ValuesType::const_iterator it = vt3.begin() + ; it != vt3.end(); ++it ) + { + ProcessAFrameOfRef(s, seriesfiles, it->c_str()); + } +} + +void ProcessAStudy(Scanner const & s, const char * studyuid) +{ + if( debuggdcmtar ) + std::cout << "Study: " << studyuid << std::endl; + gdcm::Scanner::ValuesType vt2 = s.GetValues(T2); + if( vt2.empty() ) + std::cerr << "No Series Found" << std::endl; + for( + gdcm::Scanner::ValuesType::const_iterator it = vt2.begin() + ; it != vt2.end(); ++it ) + { + ProcessASeries(s, it->c_str()); + } +} +public: + +void Print( std::ostream & os ) +{ + os << "Sorted Files: " << std::endl; + for( + std::vector< Directory::FilenamesType >::const_iterator it = SortedFiles.begin(); + it != SortedFiles.end(); ++it ) + { + os << "Group: " << std::endl; + for( + Directory::FilenamesType::const_iterator file = it->begin(); + file != it->end(); ++file) + { + os << *file << std::endl; + } + } + os << "Unsorted Files: " << std::endl; + for( + std::vector< Directory::FilenamesType >::const_iterator it = UnsortedFiles.begin(); + it != UnsortedFiles.end(); ++it ) + { + os << "Group: " << std::endl; + for( + Directory::FilenamesType::const_iterator file = it->begin(); + file != it->end(); ++file) + { + os << *file << std::endl; + } + } + +} + + std::vector< Directory::FilenamesType > const & GetSortedFiles() const { return SortedFiles; } + std::vector< Directory::FilenamesType > const & GetUnsortedFiles() const { return UnsortedFiles; } + +void ProcessIntoVolume( Scanner const & s ) +{ + gdcm::Scanner::ValuesType vt1 = s.GetValues( gdcm::T1 ); + for( + gdcm::Scanner::ValuesType::const_iterator it = vt1.begin() + ; it != vt1.end(); ++it ) + { + ProcessAStudy( s, it->c_str() ); + } + +} + +}; + +static bool ConcatenateImages(Image &im1, Image const &im2) +{ + DataElement& de1 = im1.GetDataElement(); + if( de1.GetByteValue() ) + { + const ByteValue *bv1 = de1.GetByteValue(); + std::vector v1 = *bv1; + const DataElement& de2 = im2.GetDataElement(); + const ByteValue *bv2 = de2.GetByteValue(); + const std::vector & v2 = *bv2; + v1.insert( v1.end(), v2.begin(), v2.end() ); + + de1.SetByteValue(&v1[0], (uint32_t)v1.size()); + } + else if( de1.GetSequenceOfFragments() ) + { + SequenceOfFragments *sqf1 = de1.GetSequenceOfFragments(); + assert( sqf1 ); + const DataElement& de2 = im2.GetDataElement(); + const SequenceOfFragments *sqf2 = de2.GetSequenceOfFragments(); + assert( sqf2 ); + assert( sqf2->GetNumberOfFragments() == 1 ); + const Fragment& frag = sqf2->GetFragment(0); + sqf1->AddFragment(frag); + } + else + { + return false; + } + + // update meta info + unsigned int z = im1.GetDimension(2); + im1.SetDimension(2, z + 1 ); + return true; +} + +} // namespace gdcm + + +static int MakeImageEnhanced( std::string const & filename, std::string const &outfilename ) +{ + if( !gdcm::System::FileIsDirectory(filename.c_str()) ) + { + std::cerr << "Input needs to be directory" << std::endl; + return 1; + } + + gdcm::Directory d; + d.Load( filename.c_str(), true ); // recursive ! + + gdcm::Scanner s; + s.AddTag( gdcm::T0 ); + s.AddTag( gdcm::T1 ); + s.AddTag( gdcm::T2 ); + s.AddTag( gdcm::T3 ); + s.AddTag( gdcm::T4 ); + bool b = s.Scan( d.GetFilenames() ); + if( !b ) + { + std::cerr << "Scanner failed" << std::endl; + return 1; + } + + // For now only accept MR Image Storage + gdcm::Scanner::ValuesType vt = s.GetValues(gdcm::T0); + if( vt.size() != 1 ) return 1; + + const char *sop = vt.begin()->c_str(); + gdcm::MediaStorage msorig = gdcm::MediaStorage::GetMSType( sop ); + if( msorig != gdcm::MediaStorage::MRImageStorage + && msorig != gdcm::MediaStorage::CTImageStorage ) + { + std::cerr << "Sorry MediaStorage not supported: [" << sop << "]" << std::endl; + return 1; + } + + gdcm::DiscriminateVolume dv; + dv.ProcessIntoVolume( s ); +// dv.Print( std::cout ); + + // gdcm::DataElement &de = im.GetImage().GetDataElement(); + std::vector< gdcm::Directory::FilenamesType > const &sorted = dv.GetSortedFiles(); + if( !gdcm::System::MakeDirectory( outfilename.c_str() ) ) + { + std::cerr << "Could not create dir: " << outfilename << std::endl; + return 1; + } + for( + std::vector< gdcm::Directory::FilenamesType >::const_iterator it = sorted.begin(); + it != sorted.end(); ++it ) + { + gdcm::ImageWriter im0; + + gdcm::Directory::FilenamesType const & files = *it; + gdcm::Directory::FilenamesType::const_iterator file = files.begin(); + + const char *reffile = file->c_str(); + // construct the target dir: + const char* studyuid = s.GetValue(reffile, gdcm::T1); + const char* seriesuid = s.GetValue(reffile, gdcm::T2); + const char* frameuid = s.GetValue(reffile, gdcm::T3); + std::string targetdir = outfilename; + targetdir += '/'; + targetdir += studyuid; + targetdir += '/'; + targetdir += seriesuid; + targetdir += '/'; + targetdir += frameuid; + // construct the target name: + std::string targetname = targetdir; + + targetdir += "/old/"; + + // make sure the dir exist first: + if( !gdcm::System::MakeDirectory( targetdir.c_str() ) ) + { + std::cerr << "Could not create dir: " << targetdir << std::endl; + return 1; + } + + gdcm::FilenameGenerator fg; + fg.SetNumberOfFilenames( files.size() ); + fg.SetPrefix( targetdir.c_str() ); + fg.SetPattern( "%04d.dcm" ); + if( !fg.Generate() ) + { + assert( 0 ); + } + + gdcm::ImageReader reader0; + reader0.SetFileName( reffile ); + if( !reader0.Read() ) + { + assert( 0 ); + } + gdcm::Image ¤tim = reader0.GetImage(); + assert( currentim.GetNumberOfDimensions( ) == 2 ); + currentim.SetNumberOfDimensions( 3 ); + size_t count = 0; + + //gdcm::ImageWriter writer; + gdcm::Writer writer0; + writer0.SetFileName( fg.GetFilename( count ) ); + writer0.SetFile( reader0.GetFile() ); + writer0.GetFile().GetHeader().Clear(); + if( !writer0.Write() ) + { + assert( 0 ); + } + ++file; + ++count; + + for( ; file != files.end(); ++file, ++count ) + { + gdcm::ImageReader reader; + reader.SetFileName( file->c_str() ); + if( !reader.Read() ) + { + assert( 0 ); + } + const gdcm::Image &im = reader.GetImage(); + + //gdcm::ImageWriter writer; + gdcm::Writer writer; + writer.SetFileName( fg.GetFilename( count ) ); + writer.SetFile( reader.GetFile() ); + writer.GetFile().GetHeader().Clear(); + if( !writer.Write() ) + { + assert( 0 ); + } + + if( !ConcatenateImages(currentim, im) ) + { + assert( 0 ); + } + } + + im0.SetFileName( (targetname + "/new.dcm").c_str() ); + // im.SetFile( reader.GetFile() ); + + gdcm::DataSet &ds = im0.GetFile().GetDataSet(); + + gdcm::MediaStorage ms; + switch( msorig ) + { + case gdcm::MediaStorage::CTImageStorage: + ms = gdcm::MediaStorage::EnhancedCTImageStorage; + break; + case gdcm::MediaStorage::MRImageStorage: + ms = gdcm::MediaStorage::EnhancedMRImageStorage; + break; + default: + return 1; + } + + gdcm::DataElement de( gdcm::Tag(0x0008, 0x0016) ); + const char* msstr = gdcm::MediaStorage::GetMSString(ms); + de.SetByteValue( msstr, (uint32_t)strlen(msstr) ); + de.SetVR( gdcm::Attribute<0x0008, 0x0016>::GetVR() ); + ds.Insert( de ); + + im0.SetImage( currentim ); + if( !im0.Write() ) + { + std::cerr << "Could not write: " << std::endl; + return 1; + } + + } + + std::vector< gdcm::Directory::FilenamesType > const &unsorted = dv.GetUnsortedFiles(); + if( !unsorted.empty() ) + { + std::string targetdir3 = outfilename; + targetdir3 += "/unhandled/"; + if( !gdcm::System::MakeDirectory( targetdir3.c_str() ) ) + { + std::cerr << "Could not create dir: " << outfilename << std::endl; + return 1; + } + std::cerr << "Could not process the following files (please report): " << std::endl; + std::vector< gdcm::Directory::FilenamesType >::const_iterator it = unsorted.begin(); + for( ; it != unsorted.end(); ++it ) + { + gdcm::Directory::FilenamesType const & files = *it; + gdcm::Directory::FilenamesType::const_iterator file = files.begin(); + for( ; file != files.end(); ++file ) + { + const char *f = file->c_str(); + std::string targetdir2 = outfilename; + targetdir2 += "/unhandled/"; + gdcm::Filename fn2( f ); + const char *outfn2 = fn2.GetName(); + targetdir2 += outfn2; + //std::cerr << f << " -> " << targetdir2 << std::endl; + std::ifstream in( f, std::ios::binary ); + std::ofstream out( targetdir2.c_str() , std::ios::binary ); + out << in.rdbuf(); + } + } + } + + return 0; +} + +namespace gdcm +{ + +static const DataElement &GetNestedDataElement( const DataSet &ds, const Tag & t1, const Tag & t2 ) +{ + assert( ds.FindDataElement( t1 ) ); + SmartPointer sqi1 = ds.GetDataElement( t1 ).GetValueAsSQ(); + assert( sqi1 ); + const Item &item1 = sqi1->GetItem(1); + const DataSet & ds1 = item1.GetNestedDataSet(); + assert( ds1.FindDataElement( t2 ) ); + return ds1.GetDataElement( t2 ); +} + +static bool RemapSharedIntoOld( gdcm::DataSet & ds, + SequenceOfItems *sfgs, + SequenceOfItems *pffgs, + unsigned int index ) +{ + assert( sfgs ); + assert( pffgs ); + + assert( sfgs->GetNumberOfItems() == 1 ); + Item const &item1 = sfgs->GetItem( 1 ); + const DataSet & sfgs_ds = item1.GetNestedDataSet(); +#if 1 + // Repetition Time + ds.Replace( GetNestedDataElement(sfgs_ds, Tag(0x0018,0x9112), Tag(0x0018,0x0080) ) ); + // Echo Train Length + ds.Replace( GetNestedDataElement(sfgs_ds, Tag(0x0018,0x9112), Tag(0x0018,0x0091) ) ); + // Flip Angle + ds.Replace( GetNestedDataElement(sfgs_ds, Tag(0x0018,0x9112), Tag(0x0018,0x1314) ) ); + // Number of Averages + ds.Replace( GetNestedDataElement(sfgs_ds, Tag(0x0018,0x9119), Tag(0x0018,0x0083) ) ); + + // Percent Sampling + ds.Replace( GetNestedDataElement(sfgs_ds, Tag(0x0018,0x9125), Tag(0x0018,0x0093) ) ); + // Percent Phase Field of View + ds.Replace( GetNestedDataElement(sfgs_ds, Tag(0x0018,0x9125), Tag(0x0018,0x0094) ) ); + // Receive Coil Name + ds.Replace( GetNestedDataElement(sfgs_ds, Tag(0x0018,0x9042), Tag(0x0018,0x1250) ) ); + // Transmit Coil Name + ds.Replace( GetNestedDataElement(sfgs_ds, Tag(0x0018,0x9049), Tag(0x0018,0x1251) ) ); + // InPlanePhaseEncodingDirection + ds.Replace( GetNestedDataElement(sfgs_ds, Tag(0x0018,0x9125), Tag(0x0018,0x1312) ) ); + // TransmitterFrequency + ds.Replace( GetNestedDataElement(sfgs_ds, Tag(0x0018,0x9006), Tag(0x0018,0x9098) ) ); + // InversionRecovery + ds.Replace( GetNestedDataElement(sfgs_ds, Tag(0x0018,0x9115), Tag(0x0018,0x9009) ) ); + // FlowCompensation + ds.Replace( GetNestedDataElement(sfgs_ds, Tag(0x0018,0x9115), Tag(0x0018,0x9010) ) ); + // ReceiveCoilType + ds.Replace( GetNestedDataElement(sfgs_ds, Tag(0x0018,0x9042), Tag(0x0018,0x9043) ) ); + // QuadratureReceiveCoil + ds.Replace( GetNestedDataElement(sfgs_ds, Tag(0x0018,0x9042), Tag(0x0018,0x9044) ) ); + // SlabThickness + ds.Replace( GetNestedDataElement(sfgs_ds, Tag(0x0018,0x9107), Tag(0x0018,0x9104) ) ); + // MultiCoilDefinitionSequence + ds.Replace( GetNestedDataElement(sfgs_ds, Tag(0x0018,0x9042), Tag(0x0018,0x9045) ) ); + // SlabOrientation + ds.Replace( GetNestedDataElement(sfgs_ds, Tag(0x0018,0x9107), Tag(0x0018,0x9105) ) ); + // MidSlabPosition + ds.Replace( GetNestedDataElement(sfgs_ds, Tag(0x0018,0x9107), Tag(0x0018,0x9106) ) ); + // OperatingModeSequence + ds.Replace( GetNestedDataElement(sfgs_ds, Tag(0x0018,0x9112), Tag(0x0018,0x9176) ) ); + // MRAcquisitionPhaseEncodingStepsOutOf + ds.Replace( GetNestedDataElement(sfgs_ds, Tag(0x0018,0x9125), Tag(0x0018,0x9232) ) ); + // SpecificAbsorptionRateSequence + ds.Replace( GetNestedDataElement(sfgs_ds, Tag(0x0018,0x9112), Tag(0x0018,0x9239) ) ); + // AnatomicRegionSequence + ds.Replace( GetNestedDataElement(sfgs_ds, Tag(0x0020,0x9071), Tag(0x0008,0x2218) ) ); + // Purpose of Reference Code Sequence + // FIXME what if there is multiple purpose of rcs ? + ds.Replace( GetNestedDataElement(sfgs_ds, Tag(0x0008,0x1140), Tag(0x0040,0xa170) ) ); +#else + for( + DataSet::ConstIterator it = sfgs_ds.Begin(); + it != sfgs_ds.End(); ++it ) + { + ds.Replace( *it ); + } +#endif + + Item const &item2 = pffgs->GetItem( index + 1 ); + const DataSet & pffgs_ds = item2.GetNestedDataSet(); + +#if 1 + // Effective Echo Time + ds.Replace( GetNestedDataElement(pffgs_ds, Tag(0x0018,0x9114), Tag(0x0018,0x9082) ) ); + // -> should also be Echo Time + // Nominal Cardiac Trigger Delay Time + ds.Replace( GetNestedDataElement(pffgs_ds, Tag(0x0018,0x9118), Tag(0x0020,0x9153) ) ); + // Metabolite Map Description + ds.Replace( GetNestedDataElement(pffgs_ds, Tag(0x0018,0x9152), Tag(0x0018,0x9080) ) ); + // IPP + ds.Replace( GetNestedDataElement(pffgs_ds, Tag(0x0020,0x9113), Tag(0x0020,0x0032) ) ); + // IOP + ds.Replace( GetNestedDataElement(pffgs_ds, Tag(0x0020,0x9116), Tag(0x0020,0x0037) ) ); + // Slice Thickness + ds.Replace( GetNestedDataElement(pffgs_ds, Tag(0x0028,0x9110), Tag(0x0018,0x0050) ) ); + // Pixel Spacing + ds.Replace( GetNestedDataElement(pffgs_ds, Tag(0x0028,0x9110), Tag(0x0028,0x0030) ) ); + + // window level + ds.Replace( GetNestedDataElement(pffgs_ds, Tag(0x0028,0x9132), Tag(0x0028,0x1050) ) ); + ds.Replace( GetNestedDataElement(pffgs_ds, Tag(0x0028,0x9132), Tag(0x0028,0x1051) ) ); + + // rescale slope/intercept + ds.Replace( GetNestedDataElement(pffgs_ds, Tag(0x0028,0x9145), Tag(0x0028,0x1052) ) ); + ds.Replace( GetNestedDataElement(pffgs_ds, Tag(0x0028,0x9145), Tag(0x0028,0x1053) ) ); + ds.Replace( GetNestedDataElement(pffgs_ds, Tag(0x0028,0x9145), Tag(0x0028,0x1054) ) ); + + // FrameReferenceDateTime + ds.Replace( GetNestedDataElement(pffgs_ds, Tag(0x0020,0x9111), Tag(0x0018,0x9151) ) ); + // FrameAcquisitionDuration + ds.Replace( GetNestedDataElement(pffgs_ds, Tag(0x0020,0x9111), Tag(0x0018,0x9220) ) ); + // TemporalPositionIndex + ds.Replace( GetNestedDataElement(pffgs_ds, Tag(0x0020,0x9111), Tag(0x0020,0x9128) ) ); + // InStackPositionNumber + ds.Replace( GetNestedDataElement(pffgs_ds, Tag(0x0020,0x9111), Tag(0x0020,0x9057) ) ); + // FrameType + ds.Replace( GetNestedDataElement(pffgs_ds, Tag(0x0018,0x9226), Tag(0x0008,0x9007) ) ); + // DimensionIndexValues + ds.Replace( GetNestedDataElement(pffgs_ds, Tag(0x0020,0x9111), Tag(0x0020,0x9157) ) ); + // FrameAcquisitionDateTime + ds.Replace( GetNestedDataElement(pffgs_ds, Tag(0x0020,0x9111), Tag(0x0018,0x9074) ) ); + // Nominal Cardiac Trigger Delay Time -> Trigger Time + //const DataElement &NominalCardiacTriggerDelayTime = + // GetNestedDataElement(pffgs_ds, Tag(0x0018,0x9226), Tag(0x0008,0x9007) ); +#endif + + // (0020,9228) UL 158 # 4, 1 ConcatenationFrameOffsetNumber + gdcm::Attribute<0x0020,0x9228> at = { index }; + ds.Replace( at.GetAsDataElement() ); + + return true; +} + +} // namespace gdcm + +int main (int argc, char *argv[]) +{ + int c; + //int digit_optind = 0; + + int rootuid = 0; + std::string filename; + std::string outfilename; + std::string root; + int resourcespath = 0; + int mosaic = 0; + int enhance = 1; + int unenhance = 0; + std::string xmlpath; + + int verbose = 0; + int warning = 0; + int debug = 0; + int error = 0; + int help = 0; + int version = 0; + + std::string pattern; + while (1) { + //int this_option_optind = optind ? optind : 1; + int option_index = 0; + static struct option long_options[] = { + {"input", 1, 0, 0}, + {"output", 1, 0, 0}, + {"mosaic", 0, &mosaic, 1}, // split siemens mosaic into multiple frames + {"pattern", 1, 0, 0}, // p + {"enhance", 0, &enhance, 1}, // unenhance + {"unenhance", 0, &unenhance, 1}, // unenhance + {"root-uid", 1, &rootuid, 1}, // specific Root (not GDCM) + //{"resources-path", 0, &resourcespath, 1}, + +// General options ! + {"verbose", 0, &verbose, 1}, + {"warning", 0, &warning, 1}, + {"debug", 0, &debug, 1}, + {"error", 0, &error, 1}, + {"help", 0, &help, 1}, + {"version", 0, &version, 1}, + + {0, 0, 0, 0} + }; + + c = getopt_long (argc, argv, "i:o:MUp:VWDEhv", + long_options, &option_index); + if (c == -1) + { + break; + } + + switch (c) + { + case 0: + { + const char *s = long_options[option_index].name; (void)s; + //printf ("option %s", s); + if (optarg) + { + if( option_index == 0 ) /* input */ + { + assert( strcmp(s, "input") == 0 ); + assert( filename.empty() ); + filename = optarg; + } + else if( option_index == 3 ) /* pattern */ + { + assert( strcmp(s, "pattern") == 0 ); + assert( pattern.empty() ); + pattern = optarg; + } + else if( option_index == 6 ) /* root uid */ + { + assert( strcmp(s, "root-uid") == 0 ); + root = optarg; + } + else if( option_index == 7 ) /* resourcespath */ + { + assert( strcmp(s, "resources-path") == 0 ); + assert( xmlpath.empty() ); + xmlpath = optarg; + } + else + { + printf (" with arg %s, index = %d", optarg, option_index); + assert(0); + } + //printf (" with arg %s, index = %d", optarg, option_index); + } + //printf ("\n"); + } + break; + + case 'i': + assert( filename.empty() ); + filename = optarg; + break; + + case 'o': + assert( outfilename.empty() ); + outfilename = optarg; + break; + + case 'U': + //assert( outfilename.empty() ); + //outfilename = optarg; + //printf ("option unenhance \n"); + unenhance = 1; + break; + + case 'M': + //assert( outfilename.empty() ); + //outfilename = optarg; + mosaic = 1; + break; + + case 'p': + assert( pattern.empty() ); + pattern = optarg; + break; + + case 'V': + verbose = 1; + break; + + case 'W': + warning = 1; + break; + + case 'D': + debug = 1; + break; + + case 'E': + error = 1; + break; + + case 'h': + help = 1; + break; + + case 'v': + version = 1; + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + // For now only support one input / one output + if (optind < argc) + { + std::vector files; + while (optind < argc) + { + //printf ("%s\n", argv[optind++]); + files.push_back( argv[optind++] ); + } + //printf ("\n"); + if( files.size() == 2 + && filename.empty() + && outfilename.empty() + ) + { + filename = files[0]; + outfilename = files[1]; + } + else + { + PrintHelp(); + return 1; + } + } + + if( version ) + { + //std::cout << "version" << std::endl; + PrintVersion(); + return 0; + } + + if( help ) + { + //std::cout << "help" << std::endl; + PrintHelp(); + return 0; + } + + if( filename.empty() ) + { + //std::cerr << "Need input file (-i)\n"; + PrintHelp(); + return 1; + } + if( outfilename.empty() ) + { + //std::cerr << "Need output file (-o)\n"; + PrintHelp(); + return 1; + } + + // Debug is a little too verbose + gdcm::Trace::SetDebug( (debug > 0 ? true : false)); + gdcm::Trace::SetWarning( (warning > 0 ? true : false)); + gdcm::Trace::SetError( (error > 0 ? true : false)); + // when verbose is true, make sure warning+error are turned on: + if( verbose ) + { + gdcm::Trace::SetWarning( (verbose > 0 ? true : false) ); + gdcm::Trace::SetError( (verbose > 0 ? true : false) ); + } + + gdcm::FileMetaInformation::SetSourceApplicationEntityTitle( "gdcmtar" ); + if( !rootuid ) + { + // only read the env var is no explicit cmd line option + // maybe there is an env var defined... let's check + const char *rootuid_env = getenv("GDCM_ROOT_UID"); + if( rootuid_env ) + { + rootuid = 1; + root = rootuid_env; + } + } + if( rootuid ) + { + if( !gdcm::UIDGenerator::IsValid( root.c_str() ) ) + { + std::cerr << "specified Root UID is not valid: " << root << std::endl; + return 1; + } + gdcm::UIDGenerator::SetRoot( root.c_str() ); + } + + if( unenhance && false ) + { + gdcm::Global& g = gdcm::Global::GetInstance(); + // First thing we need to locate the XML dict + // did the user requested to look XML file in a particular directory ? + if( !resourcespath ) + { + const char *xmlpathenv = getenv("GDCM_RESOURCES_PATH"); + if( xmlpathenv ) + { + // Make sure to look for XML dict in user explicitly specified dir first: + xmlpath = xmlpathenv; + resourcespath = 1; + } + } + if( resourcespath ) + { + // xmlpath is set either by the cmd line option or the env var + if( !g.Prepend( xmlpath.c_str() ) ) + { + std::cerr << "specified Resources Path is not valid: " << xmlpath << std::endl; + return 1; + } + } + + // All set, then load the XML files: + if( !g.LoadResourcesFiles() ) + { + return 1; + } + + //const gdcm::Defs &defs = g.GetDefs(); + } + + + if( mosaic ) + { + gdcm::ImageReader reader; + reader.SetFileName( filename.c_str() ); + if( !reader.Read() ) + { + std::cerr << "could not read: " << filename << std::endl; + return 1; + } + + gdcm::SplitMosaicFilter filter; + filter.SetImage( reader.GetImage() ); + filter.SetFile( reader.GetFile() ); + bool b = filter.Split(); + if( !b ) + { + std::cerr << "Could not split : " << filename << std::endl; + return 1; + } + + const gdcm::Image &image = filter.GetImage(); + const unsigned int *dims = image.GetDimensions(); + const gdcm::DataElement &pixeldata = image.GetDataElement(); + const gdcm::ByteValue *bv = pixeldata.GetByteValue(); + unsigned long slice_len = image.GetBufferLength() / dims[2]; + //assert( image.GetBufferLength() == bv->GetLength() ); + + gdcm::FilenameGenerator fg; + fg.SetNumberOfFilenames( dims[2] ); + fg.SetPrefix( outfilename.c_str() ); + fg.SetPattern( pattern.c_str() ); + if( !fg.Generate() ) + { + std::cerr << "could not generate filenames" << std::endl; + return 1; + } + const double *cosines = image.GetDirectionCosines(); + gdcm::DirectionCosines dc( cosines ); + double normal[3]; + dc.Cross( normal ); + const double *origin = image.GetOrigin(); + double zspacing = image.GetSpacing(2); + + for(unsigned int i = 0; i < dims[2]; ++i) + { + double new_origin[3]; + for (int j = 0; j < 3; j++) + { + // the n'th slice is n * z-spacing aloung the IOP-derived + // z-axis + new_origin[j] = origin[j] + normal[j] * i * zspacing; + } + + const char *outfilenamei = fg.GetFilename(i); + gdcm::ImageWriter writer; + writer.SetFileName( outfilenamei ); + //writer.SetFile( filter.GetFile() ); + writer.SetFile( reader.GetFile() ); + + // + //writer.SetImage( filter.GetImage() ); + gdcm::Image &slice = writer.GetImage(); + slice = filter.GetImage(); + slice.SetOrigin( new_origin ); + slice.SetNumberOfDimensions( 2 ); + assert( slice.GetPixelFormat() == filter.GetImage().GetPixelFormat() ); + slice.SetSpacing(2, filter.GetImage().GetSpacing(2) ); + //slice.Print( std::cout ); + gdcm::DataElement &pd = slice.GetDataElement(); + const char *sliceptr = bv->GetPointer() + i * slice_len; + pd.SetByteValue( sliceptr, (uint32_t)slice_len); + + if( !writer.Write() ) + { + std::cerr << "Failed to write: " << outfilename << std::endl; + return 1; + } + } + + return 0; + } + else if ( unenhance ) + { + gdcm::ImageReader reader; + reader.SetFileName( filename.c_str() ); + if( !reader.Read() ) + { + std::cerr << "could not read: " << filename << std::endl; + return 1; + } + + gdcm::File &file = reader.GetFile(); + gdcm::DataSet &ds = file.GetDataSet(); + gdcm::MediaStorage ms; + ms.SetFromFile(file); + if( ms.IsUndefined() ) + { + std::cerr << "Unknown MediaStorage" << std::endl; + return 1; + } + + gdcm::UIDs uid; + uid.SetFromUID( ms.GetString() ); + + if( uid != gdcm::UIDs::EnhancedMRImageStorage ) + { + std::cerr << "MediaStorage is not handled " << ms << " [" << uid.GetName() << "]" << std::endl; + return 1; + } + + // Preserve info: + gdcm::DataElement oldsopclassuid = ds.GetDataElement( gdcm::Tag(0x8,0x16) ); + gdcm::DataElement oldinstanceuid = ds.GetDataElement( gdcm::Tag(0x8,0x18) ); + + // Ok then change it old Old MR Image Storage + gdcm::DataElement de( gdcm::Tag(0x0008, 0x0016) ); + ms = gdcm::MediaStorage::MRImageStorage; + const char* msstr = gdcm::MediaStorage::GetMSString(ms); + de.SetByteValue( msstr, (uint32_t)strlen(msstr) ); + de.SetVR( gdcm::Attribute<0x0008, 0x0016>::GetVR() ); + ds.Replace( de ); + + const gdcm::Image &image = reader.GetImage(); + const unsigned int *dims = image.GetDimensions(); + //std::cout << image << std::endl; + const gdcm::DataElement &pixeldata = image.GetDataElement(); + //const gdcm::ByteValue *bv = pixeldata.GetByteValue(); + gdcm::SmartPointer bv = (gdcm::ByteValue*)pixeldata.GetByteValue(); + unsigned long slice_len = image.GetBufferLength() / dims[2]; + assert( slice_len * dims[2] == image.GetBufferLength() ); + //assert( image.GetBufferLength() == bv->GetLength() ); + + gdcm::FilenameGenerator fg; + fg.SetNumberOfFilenames( dims[2] ); + fg.SetPrefix( outfilename.c_str() ); + fg.SetPattern( pattern.c_str() ); + if( !fg.Generate() ) + { + std::cerr << "could not generate" << std::endl; + return 1; + } + const double *cosines = image.GetDirectionCosines(); + gdcm::DirectionCosines dc( cosines ); + double normal[3]; + dc.Cross( normal ); + //const double *origin = image.GetOrigin(); + //double zspacing = image.GetSpacing(2); + + // Remove SharedFunctionalGroupsSequence + gdcm::SmartPointer sfgs = + ds.GetDataElement( gdcm::Tag( 0x5200,0x9229 ) ).GetValueAsSQ(); + ds.Remove( gdcm::Tag( 0x5200,0x9229 ) ); + assert( ds.FindDataElement( gdcm::Tag( 0x5200,0x9229 ) ) == false ); + // Remove PerFrameFunctionalGroupsSequence + gdcm::SmartPointer pffgs = + ds.GetDataElement( gdcm::Tag( 0x5200,0x9230 ) ).GetValueAsSQ(); + ds.Remove( gdcm::Tag( 0x5200,0x9230 ) ); + assert( ds.FindDataElement( gdcm::Tag( 0x5200,0x9230 ) ) == false ); + ds.Remove( gdcm::Tag( 0x28,0x8) ); + ds.Remove( gdcm::Tag( 0x7fe0,0x0010) ); + assert( ds.FindDataElement( gdcm::Tag( 0x7fe0,0x0010) ) == false ); + //ds.Remove( gdcm::Tag( 0x0008,0x0012) ); + //ds.Remove( gdcm::Tag( 0x0008,0x0013) ); + + // reference the old instance: + // PS 3.3-2009 C.7.6.16.1.3 +#if 0 + assert( ds.FindDataElement( gdcm::Tag(0x0008,0x1150) ) == false ); + assert( ds.FindDataElement( gdcm::Tag(0x0008,0x1155) ) == false ); + assert( ds.FindDataElement( gdcm::Tag(0x0008,0x1160) ) == false ); + oldsopclassuid.SetTag( gdcm::Tag(0x8,0x1150) ); + oldinstanceuid.SetTag( gdcm::Tag(0x8,0x1155) ); + ds.Insert( oldsopclassuid ); + ds.Insert( oldinstanceuid ); +#endif + + char date[22]; + const size_t datelen = 8; + //int res = gdcm::System::GetCurrentDateTime(date); + gdcm::Attribute<0x8,0x12> instcreationdate; + instcreationdate.SetValue( gdcm::DTComp( date, datelen ) ); + ds.Replace( instcreationdate.GetAsDataElement() ); + gdcm::Attribute<0x8,0x13> instcreationtime; + instcreationtime.SetValue( gdcm::DTComp( date + datelen, 13 ) ); + ds.Replace( instcreationtime.GetAsDataElement() ); + const char *offset = gdcm::System::GetTimezoneOffsetFromUTC(); + gdcm::Attribute<0x8,0x201> timezoneoffsetfromutc; + timezoneoffsetfromutc.SetValue( offset ); + ds.Replace( timezoneoffsetfromutc.GetAsDataElement() ); + + for(unsigned int i = 0; i < dims[2]; ++i) + { +#if 0 + double new_origin[3]; + for (int j = 0; j < 3; j++) + { + // the n'th slice is n * z-spacing aloung the IOP-derived + // z-axis + new_origin[j] = origin[j] + normal[j] * i * zspacing; + } +#endif + + const char *outfilenamei = fg.GetFilename(i); + //gdcm::ImageWriter writer; + gdcm::Writer writer; + writer.SetFileName( outfilenamei ); + //writer.SetFile( filter.GetFile() ); + writer.SetFile( reader.GetFile() ); + + if ( !gdcm::RemapSharedIntoOld( ds, sfgs, pffgs, i ) ) + { + return 1; + } + + // + //writer.SetImage( filter.GetImage() ); + //gdcm::Image & //slice = writer.GetImage(); + //slice = reader.GetImage(); +// slice.SetOrigin( new_origin ); +// slice.SetNumberOfDimensions( 2 ); +// assert( slice.GetPixelFormat() == reader.GetImage().GetPixelFormat() ); +// slice.SetSpacing(2, reader.GetImage().GetSpacing(2) ); + //slice.Print( std::cout ); +// gdcm::DataElement &pd = slice.GetDataElement(); + const char *sliceptr = bv->GetPointer() + i * slice_len; + gdcm::DataElement newpixeldata( gdcm::Tag(0x7fe0,0x0010) ); + newpixeldata.SetByteValue( sliceptr, (uint32_t)slice_len); // slow ! + ds.Replace( newpixeldata ); + + if( !writer.Write() ) + { + std::cerr << "Failed to write: " << outfilenamei << std::endl; + return 1; + } + //else + // { + // std::cout << "Success to write: " << outfilenamei << std::endl; + // } + } + + return 0; + } + else + { + assert( enhance ); + return MakeImageEnhanced( filename, outfilename ); +#if 0 + std::cerr << "Not implemented" << std::endl; + return 1; + gdcm::ImageReader reader; + reader.SetFileName( filename.c_str() ); + if( !reader.Read() ) + { + std::cerr << "could not read: " << filename << std::endl; + return 1; + } + + const gdcm::Image &image = reader.GetImage(); + const unsigned int *dims = image.GetDimensions(); + std::cout << image << std::endl; + const gdcm::DataElement &pixeldata = image.GetDataElement(); + const gdcm::ByteValue *bv = pixeldata.GetByteValue(); + unsigned long slice_len = image.GetBufferLength() / dims[2]; + //assert( image.GetBufferLength() == bv->GetLength() ); + + gdcm::FilenameGenerator fg; + fg.SetNumberOfFilenames( dims[2] ); + fg.SetPrefix( outfilename.c_str() ); + fg.SetPattern( pattern.c_str() ); + if( !fg.Generate() ) + { + std::cerr << "could not generate" << std::endl; + return 1; + } + const double *cosines = image.GetDirectionCosines(); + gdcm::DirectionCosines dc( cosines ); + double normal[3]; + dc.Cross( normal ); + const double *origin = image.GetOrigin(); + double zspacing = image.GetSpacing(2); + + for(unsigned int i = 0; i < dims[2]; ++i) + { + double new_origin[3]; + for (int j = 0; j < 3; j++) + { + // the n'th slice is n * z-spacing aloung the IOP-derived + // z-axis + new_origin[j] = origin[j] + normal[j] * i * zspacing; + } + + const char *outfilenamei = fg.GetFilename(i); + gdcm::ImageWriter writer; + writer.SetFileName( outfilenamei ); + //writer.SetFile( filter.GetFile() ); + writer.SetFile( reader.GetFile() ); + + // + //writer.SetImage( filter.GetImage() ); + gdcm::Image &slice = writer.GetImage(); + slice = reader.GetImage(); + slice.SetOrigin( new_origin ); + slice.SetNumberOfDimensions( 2 ); + assert( slice.GetPixelFormat() == reader.GetImage().GetPixelFormat() ); + slice.SetSpacing(2, reader.GetImage().GetSpacing(2) ); + //slice.Print( std::cout ); + gdcm::DataElement &pd = slice.GetDataElement(); + const char *sliceptr = bv->GetPointer() + i * slice_len; + pd.SetByteValue( sliceptr, slice_len); // slow ! + + if( !writer.Write() ) + { + std::cerr << "Failed to write: " << outfilenamei << std::endl; + return 1; + } + else + { + std::cout << "Success to write: " << outfilenamei << std::endl; + } + } + + return 0; +#endif + } +} diff --git a/gdcm/Applications/Cxx/gdcmxml.cxx b/gdcm/Applications/Cxx/gdcmxml.cxx new file mode 100644 index 0000000..ed061aa --- /dev/null +++ b/gdcm/Applications/Cxx/gdcmxml.cxx @@ -0,0 +1,918 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + * This is an implementation of Application Hosting: DICOM Native Model + */ +#include "gdcmFilename.h" +#include "gdcmReader.h" +#include "gdcmVersion.h" +#include "gdcmFileMetaInformation.h" +#include "gdcmDataSet.h" +#include "gdcmDataElement.h" +#include "gdcmAttribute.h" +#include "gdcmPrivateTag.h" +#include "gdcmValidate.h" +#include "gdcmWriter.h" +#include "gdcmSystem.h" +#include "gdcmDirectory.h" +#include "gdcmCSAHeader.h" +#include "gdcmPDBHeader.h" +#include "gdcmSequenceOfItems.h" +#include "gdcmASN1.h" +#include "gdcmFile.h" +#include "gdcmXMLPrinter.h" +#include "gdcmPrinter.h" + +#ifdef GDCM_USE_SYSTEM_LIBXML2 +#include +#endif + +#include +#include +#include + +#include /* for printf */ +#include /* for exit */ +#include +#include + +using namespace gdcm; + +// This is a very dumb implementation for getData handling +// by default GDCM simply drop the BulkData so we need to store +// the actual BulkData somewhere for proper implementation of getData +class SimpleFileXMLPrinter : public XMLPrinter +{ +public: + void HandleBulkData(const char *uuid, const TransferSyntax & ts, + const char *bulkdata, size_t bulklen) + { + // Store Bulk Data + std::ofstream out( uuid, std::ios::binary ); + out.write( bulkdata, bulklen ); + out.close(); + std::string tsfn = uuid; + tsfn += ".ts"; + // Need to store Transfer Syntax for later getData() implementation + // See Sup118 for details + const char *tsstring = ts.GetString(); + assert( tsstring ); + std::ofstream out2( tsfn.c_str(), std::ios::binary ); + out2.write( tsstring, strlen(tsstring) ); + out2.close(); + } +}; + +//Global Variables +int loadBulkData = 0; +int loadTransferSyntax = 0; +TransferSyntax ts; + +static void PrintVersion() +{ + std::cout << "gdcmxml: gdcm " << gdcm::Version::GetVersion() << " "; + const char date[] = "$Date$"; + std::cout << date << std::endl; +} + +static void PrintHelp() +{ + PrintVersion(); + std::cout << "Usage: gdcmxml [OPTION]... FILE..." << std::endl; + std::cout << "Convert a DICOM file into an XML file or vice-versa \n"; + std::cout << "Parameter (required):" << std::endl; + std::cout << " -i --input Filename1" << std::endl; + std::cout << " -o --output Filename2" << std::endl; + std::cout << "General Options:" << std::endl; + std::cout << " -V --verbose more verbose (warning+error)." << std::endl; + std::cout << " -W --warning print warning info." << std::endl; + std::cout << " -D --debug print debug info." << std::endl; + std::cout << " -E --error print error info." << std::endl; + std::cout << " -h --help print help." << std::endl; + std::cout << " -v --version print version." << std::endl; + std::cout << "Options for Dicom to XML:" << std::endl; + std::cout << " -B --loadBulkData Loads bulk data into a binary file named \"UUID\"(by default UUID are written)." << std::endl; + std::cout << "Options for XML to Dicom:" << std::endl; + std::cout << " -B --loadBulkData Loads bulk data from a binary file named as the \"UUID\" in XML file(by default UUID are written)."<< std::endl; + std::cout << " -T --TransferSyntax Loads transfer syntax from file (default is LittleEndianImplicit)" << std::endl; +} + +#ifdef GDCM_USE_SYSTEM_LIBXML2 + +#define CHECK_READER \ + if(ret == -1) \ + assert(0 && "unable to read"); + +#define READ_NEXT\ + ret = xmlTextReaderRead(reader);\ + CHECK_READER\ + if(xmlTextReaderNodeType(reader) == 14 || xmlTextReaderNodeType(reader) == 13)\ + ret = xmlTextReaderRead(reader);\ + CHECK_READER + +#define CHECK_NAME(value)\ + strcmp((const char*)xmlTextReaderConstName(reader),value) + +static void HandleBulkData(const char *uuid, DataElement &de) + { + // Load Bulk Data + if(loadBulkData) + { + std::ifstream file( uuid, std::ios::in|std::ios::binary|std::ios::ate );//open file with pointer at file end + + if (file.is_open()) + { + std::ifstream::pos_type size = file.tellg(); + char *bulkData = new char [size]; + file.seekg (0, std::ios::beg); + file.read (bulkData, size); + file.close(); + + ByteValue *bv = new ByteValue(bulkData,(int)size); + de.SetValue(*bv); + } + } + + if(loadTransferSyntax) + { + std::string tsfn = uuid; + tsfn += ".ts"; + std::ifstream file( tsfn.c_str(), std::ios::in|std::ios::binary|std::ios::ate );//open file with pointer at file end + if (file.is_open()) + { + std::ifstream::pos_type size = file.tellg(); + char *tsstring = new char [size]; + file.seekg (0, std::ios::beg); + file.read (tsstring, size); + file.close(); + TransferSyntax::TSType tsType = TransferSyntax::GetTSType(tsstring); + const TransferSyntax ts_temp(tsType); + + if(ts_temp.IsValid()) + { + ts = tsType; + } + } + } + } + +static void HandlePN(xmlTextReaderPtr reader,DataElement &de) +{ + if(CHECK_NAME("DicomAttribute") == 0 && xmlTextReaderNodeType(reader) == 15) + return;//empty element + else if(!(CHECK_NAME("PersonName") == 0)) + assert(0 && "Invalid XML"); + + int depth_curr = xmlTextReaderDepth(reader); + (void)depth_curr; + int ret; + std::string name; + READ_NEXT; + READ_NEXT; + while(!(CHECK_NAME("DicomAttribute") == 0 && xmlTextReaderNodeType(reader) == 15)) + { + READ_NEXT + if(xmlTextReaderNodeType(reader) == 3) + { + name += (char*)xmlTextReaderConstValue(reader); + name += "^"; + } + if((CHECK_NAME("Ideographic") == 0 || CHECK_NAME("Phonetic") == 0) && xmlTextReaderNodeType(reader) == 1) + { + name += "="; + } + + } + + de.SetByteValue( name.c_str(), (uint32_t)name.size() ); + return; + + /* + READ_NEXT//at ByteValue + + + + //char *temp_name=new char[500]; + std::string name; + int count =0; + //while(!(CHECK_NAME("PersonName") == 0 && xmlTextReaderDepth(reader) == depth_curr && xmlTextReaderNodeType(reader) == 15)) + //{ + if(CHECK_NAME("SingleByte") == 0) + { + + READ_NEXT + + if(CHECK_NAME("FamilyName") == 0) + { + READ_NEXT + if(xmlTextReaderNodeType(reader) == 3) + { + //append here + count +=strlen((char*)xmlTextReaderConstValue(reader)); + name += (char*)xmlTextReaderConstValue(reader); + name += "^"; + } + READ_NEXT//at + READ_NEXT//at + //READ_NEXT//may be new name or at + //if(CHECK_NAME("ByteValue") == 0) + //READ_NEXT + } + if(CHECK_NAME("GivenName") == 0) + { + READ_NEXT + if(xmlTextReaderNodeType(reader) == 3) + { + //append here + name += (char*)xmlTextReaderConstValue(reader); + name += "^"; + } + READ_NEXT + READ_NEXT + } + if(CHECK_NAME("MiddleName") == 0) + { + READ_NEXT + if(xmlTextReaderNodeType(reader) == 3) + { + //append here + name += (char*)xmlTextReaderConstValue(reader); + name += "^"; + } + READ_NEXT + READ_NEXT + } + if(CHECK_NAME("NamePrefix") == 0) + { + READ_NEXT + if(xmlTextReaderNodeType(reader) == 3) + { + //append here + name += (char*)xmlTextReaderConstValue(reader); + name += "^"; + } + READ_NEXT + READ_NEXT + } + if(CHECK_NAME("NameSuffix") == 0) + { + READ_NEXT + if(xmlTextReaderNodeType(reader) == 3) + { + //append here + name += (char*)xmlTextReaderConstValue(reader); + name += "^"; + } + READ_NEXT + READ_NEXT + } + READ_NEXT//starts new or end tag PersonName + //name += "="; + } + if(CHECK_NAME("Ideographic") == 0) + { + + } + if(CHECK_NAME("Phonetic") == 0) + { + } + + //Set Value in de + Element el; + el.SetValue(name.c_str(),0); + de = el.GetAsDataElement(); + + READ_NEXT//at correct place for Populate DataSet + return; + */ + +} + +static void HandleSequence(SequenceOfItems *sqi,xmlTextReaderPtr reader,int depth); + +static void PopulateDataSet(xmlTextReaderPtr reader,DataSet &DS, int depth, bool SetSQ ) +{ + (void)depth; + int ret; + const char *name = (const char*)xmlTextReaderConstName(reader); + //printf("%s\n",name); + +#define LoadValueASCII(type) \ + case type: \ + { \ + int count =0; \ + name = (const char*)xmlTextReaderConstName(reader); \ + if(strcmp(name,"DicomAttribute") == 0 && xmlTextReaderNodeType(reader) == 15)\ + break;\ + char values[10][100] = {"","","","","","","","","",""}; \ + Element el; \ + while(strcmp(name,"Value") == 0) \ + { \ + READ_NEXT \ + if(CHECK_NAME("Value") == 0)\ + {READ_NEXT;}\ + else{\ + char *value = (char*)xmlTextReaderConstValue(reader); \ + strcpy((char *)values[count++],value); \ + READ_NEXT /*Value ending tag*/ \ + name = (const char*)xmlTextReaderConstName(reader); \ + READ_NEXT \ + name = (const char*)xmlTextReaderConstName(reader); }\ + } \ + assert(CHECK_NAME("DicomAttribute") == 0);\ + el.SetLength( (count) * vr.GetSizeof() ); \ + int total = 0; \ + while(total < count) \ + { \ + el.SetValue(values[total],total); \ + total++; \ + } \ + de = el.GetAsDataElement(); \ + }break + +#define LoadValueInteger(type) \ + case type: \ + { \ + int count =0; \ + name = (const char*)xmlTextReaderConstName(reader); \ + if(strcmp(name,"DicomAttribute") == 0 && xmlTextReaderNodeType(reader) == 15)\ + break;\ + int values[10]; \ + Element el; \ + while(strcmp(name,"Value") == 0) \ + { \ + READ_NEXT \ + char *value_char = (char*)xmlTextReaderConstValue(reader); \ + int nvalue = sscanf(value_char,"%d",&(values[count++])); \ + assert( nvalue == 1 ); \ + READ_NEXT /*Value ending tag*/ \ + name = (const char*)xmlTextReaderConstName(reader); \ + READ_NEXT \ + name = (const char*)xmlTextReaderConstName(reader); \ + } \ + el.SetLength( (count) * vr.GetSizeof() ); \ + int total = 0; \ + while(total < count) \ + { \ + el.SetValue( (VRToType::Type)(values[total]),total); \ + total++; \ + } \ + de = el.GetAsDataElement(); \ + }break + +#define LoadValueFloat(type) \ + case type: \ + { \ + int count =0; \ + name = (const char*)xmlTextReaderConstName(reader); \ + if(strcmp(name,"DicomAttribute") == 0 && xmlTextReaderNodeType(reader) == 15)\ + break;\ + float values[10]; \ + Element el; \ + while(strcmp(name,"Value") == 0) \ + { \ + READ_NEXT \ + char *value_char = (char*)xmlTextReaderConstValue(reader); \ + sscanf(value_char,"%f",&(values[count++])); \ + READ_NEXT /*Value ending tag*/ \ + name = (const char*)xmlTextReaderConstName(reader); \ + READ_NEXT \ + name = (const char*)xmlTextReaderConstName(reader); \ + } \ + el.SetLength( (count) * vr.GetSizeof() ); \ + int total = 0; \ + while(total < count) \ + { \ + el.SetValue(values[total],total); \ + total++; \ + } \ + de = el.GetAsDataElement(); \ + }break + +#define LoadValueDouble(type) \ + case type: \ + { \ + int count =0; \ + name = (const char*)xmlTextReaderConstName(reader); \ + if(strcmp(name,"DicomAttribute") == 0 && xmlTextReaderNodeType(reader) == 15)\ + break;\ + double values[10]; \ + Element el; \ + while(strcmp(name,"Value") == 0) \ + { \ + READ_NEXT \ + char *value_char = (char*)xmlTextReaderConstValue(reader); \ + sscanf(value_char,"%lf",&(values[count++])); \ + READ_NEXT/*Value ending tag*/ \ + name = (const char*)xmlTextReaderConstName(reader); \ + READ_NEXT \ + name = (const char*)xmlTextReaderConstName(reader); \ + } \ + el.SetLength( (count) * vr.GetSizeof() ); \ + int total = 0; \ + while(total < count) \ + { \ + el.SetValue(values[total],total); \ + total++; \ + } \ + de = el.GetAsDataElement(); \ + }break + + +#define LoadValueAT(type)\ + case type: \ + { \ + int count =0; \ + name = (const char*)xmlTextReaderConstName(reader);\ + if(strcmp(name,"DicomAttribute") == 0 && xmlTextReaderNodeType(reader) == 15)\ + break;\ + Tag tags[10];\ + unsigned int group = 0, element = 0;\ + Element el;\ + while(strcmp(name,"Value") == 0)\ + {\ + READ_NEXT\ + char *value = (char*)xmlTextReaderConstValue(reader); \ + if( sscanf(value, "(%04x,%04x)", &group , &element) != 2 )\ + {\ + gdcmDebugMacro( "Problem reading AT: ");\ + } \ + tags[count].SetGroup( (uint16_t)group );\ + tags[count].SetElement( (uint16_t)element );count++;\ + READ_NEXT/*Value ending tag*/ \ + name = (const char*)xmlTextReaderConstName(reader); \ + READ_NEXT \ + name = (const char*)xmlTextReaderConstName(reader); \ + }\ + el.SetLength( (count) * vr.GetSizeof() ); \ + int total = 0; \ + while(total < count) \ + { \ + el.SetValue(tags[total],total); \ + total++; \ + } \ + de = el.GetAsDataElement();\ + }break + + + while( xmlTextReaderDepth(reader)!=0 ) + { + if(SetSQ && (xmlTextReaderNodeType(reader) == 15) && CHECK_NAME("Item") == 0 ) + return; + if(CHECK_NAME("DicomAttribute") == 0) + { + DataElement de; + + /* Reading Tag */ + char *tag_read =(char *)xmlTextReaderGetAttribute(reader,(const unsigned char*)"tag"); + Tag t; + if(!t.ReadFromContinuousString((const char *)tag_read)) + assert(0 && "Invalid Tag!"); + + /* Reading VR */ + char vr_read[3] = ""; + strcpy(vr_read, (const char *)xmlTextReaderGetAttribute(reader,(const unsigned char*)"vr")); + vr_read[2]='\0'; + const gdcm::VR vr = gdcm::VR::GetVRType(vr_read); + + READ_NEXT /* should be at Value tag or BulkData tag or Item Tag */ + + /* Load Value */ + switch(vr) + { + + LoadValueAT(VR::AT); + LoadValueASCII(VR::AE); + LoadValueASCII(VR::AS); + LoadValueASCII(VR::CS); + LoadValueASCII(VR::DA); + LoadValueFloat(VR::DS); + LoadValueASCII(VR::DT); + LoadValueInteger(VR::IS); + LoadValueASCII(VR::LO); + LoadValueASCII(VR::LT); + LoadValueASCII(VR::SH); + LoadValueASCII(VR::ST); + LoadValueASCII(VR::TM); + LoadValueASCII(VR::UI); + LoadValueASCII(VR::UT); + LoadValueInteger(VR::SS); + LoadValueInteger(VR::UL); + LoadValueInteger(VR::SL); + LoadValueInteger(VR::US); + LoadValueFloat(VR::FL); + LoadValueDouble(VR::FD); + case VR::SQ: + { + SequenceOfItems *sqi = new SequenceOfItems(); + HandleSequence(sqi,reader,xmlTextReaderDepth(reader)); + de.SetValue(*sqi); + }break; + + case VR::PN: + { + //Current node must be Person Name + HandlePN(reader,de); + }break; + + case VR::OF: + case VR::OB: + case VR::OW: + { + //Presently should be at BulkData + assert(((CHECK_NAME("BulkData")) == 0)); + char * uuid = (char *)xmlTextReaderGetAttribute(reader,(const unsigned char*)"uuid"); + HandleBulkData(uuid,de); + READ_NEXT + }break; + + case VR::UN: + { + int depth_UN=xmlTextReaderDepth(reader); + while(!(CHECK_NAME("DicomAttribute") == 0 && xmlTextReaderNodeType(reader) == 15 && (depth_UN-1) == xmlTextReaderDepth(reader))) + {READ_NEXT} + //assert(0 && "UN not Handled yet"); + }break; + default: + assert(0 && "Unknown VR"); + }; + + /*Modify de before insert*/ + + de.SetTag(t); + + DS.Insert(de); + + READ_NEXT // To next Element + + } + + } +} + +static void HandleSequence(SequenceOfItems *sqi, xmlTextReaderPtr reader,int depth) +{ + int ret; + while(!( CHECK_NAME("DicomAttribute") == 0 && xmlTextReaderDepth(reader) == (depth - 1) && xmlTextReaderNodeType(reader) == 15 ) ) + { + gdcmDebugMacro( "HandleSequence (while loop)" ); + if( CHECK_NAME("Item") == 0 && xmlTextReaderDepth(reader) == depth && xmlTextReaderNodeType(reader) == 1) + { + //at Item + READ_NEXT + //assert(0 && "Hi1"); + //at DicomAtt + if( CHECK_NAME("DicomAttribute") == 0 && xmlTextReaderDepth(reader) == (depth + 1) && xmlTextReaderNodeType(reader) == 1) + { + //start of an item + //Create Nested DataSet + //assert(0 && "Hi2"); + Item *item = new Item(); + DataSet *NestedDS = new DataSet() ; + PopulateDataSet(reader,*NestedDS,xmlTextReaderDepth(reader),true); + item->SetNestedDataSet(*NestedDS); + sqi->AddItem(*item); + //assert(0 && "Hi3"); + + } + else + assert("Empty Item or Invalid XML"); + + READ_NEXT + } + else + assert("Expected Item"); + } +} + +static void WriteDICOM(xmlTextReaderPtr reader, gdcm::Filename file2) +{ + int ret; + + READ_NEXT + + READ_NEXT // at first element "DicomAttribute" + + //populate DS + DataSet DS; + if(xmlTextReaderDepth(reader) == 1 && strcmp((const char*)xmlTextReaderConstName(reader),"DicomAttribute") == 0) + PopulateDataSet(reader,DS,1,false); + + //DataElement de; + //Tag t(0xFFFe,0xE0DD); + //de.SetTag(t); + //DS.Insert(de); + //add to File + + //store in heap + File *F = new File(); + F->SetDataSet(DS); + + //Validate - possibly from gdcmValidate Class + FileMetaInformation meta = F->GetHeader(); + meta.SetDataSetTransferSyntax(ts); + F->SetHeader(meta); + + //Validate - possibly from gdcmValidate Class + + //Validate V; + //V.SetFile(F); + //V.Validation(); + //F = V.GetValidatedFile(); + //add to Writer + + if(!file2.IsEmpty()) + { + Writer W; + W.SetFileName(file2.GetFileName()); + W.SetFile(*F); + + //finally write to file + W.Write(); + } + else + { + Printer printer; + printer.SetFile ( *F ); + printer.SetColor(1); + printer.Print( std::cout ); + } +} + +static void XMLtoDICOM(gdcm::Filename file1, gdcm::Filename file2) +{ + xmlTextReaderPtr reader; + FILE *in; + char *buffer; + size_t numBytes; + in = fopen(file1.GetFileName(), "r"); + + if(in == NULL) + return ; + + fseek(in, 0L, SEEK_END); + numBytes = ftell(in); + fseek(in, 0L, SEEK_SET); + buffer = (char*)calloc(numBytes, sizeof(char)); + + if(buffer == NULL) + return ; + + size_t ret = fread(buffer, sizeof(char), numBytes, in); + if( numBytes != ret ) + { + // FIXME how to return error code ? + return; + } + fclose(in); + reader = xmlReaderForMemory (buffer, (int)numBytes, NULL, NULL, 0); + //reader = xmlReaderForFile(filename, "UTF-8", 0); Not Working!! + if (reader != NULL) + { + WriteDICOM(reader, file2); + } + else + { + fprintf(stderr, "Unable to open %s\n", file1.GetFileName()); + } +} +#endif // GDCM_USE_SYSTEM_LIBXML2 + +int main (int argc, char *argv[]) +{ + int c; + //int digit_optind = 0; + gdcm::Filename file1; + gdcm::Filename file2; +// int loadTransferSyntax = 0; + int verbose = 0; + int warning = 0; + int debug = 0; + int error = 0; + int help = 0; + int version = 0; + while (1) { + + int option_index = 0; + + static struct option long_options[] = { + {"input", 1, 0, 0}, + {"output", 1, 0, 0}, + {"loadBulkData", 0, &loadBulkData, 1}, + {"TransferSyntax", 0, &loadTransferSyntax, 1}, + {"verbose", 0, &verbose, 1}, + {"warning", 0, &warning, 1}, + {"debug", 0, &debug, 1}, + {"error", 0, &error, 1}, + {"help", 0, &help, 1}, + {"version", 0, &version, 1}, + {0, 0, 0, 0} // required + }; + static const char short_options[] = "i:o:BTVWDEhv"; + c = getopt_long (argc, argv, short_options, + long_options, &option_index); + if (c == -1) + { + break; + } + + switch (c) + { + case 0: + case '-': + { + const char *s = long_options[option_index].name; (void)s; + if (optarg) + { + if( option_index == 0 ) /* input */ + { + assert( strcmp(s, "input") == 0 ); + assert( file1.IsEmpty() ); + file1 = optarg; + } + } + } + break; + + case 'i': + //printf ("option i with value '%s'\n", optarg); + assert( file1.IsEmpty() ); + file1 = optarg; + break; + + case 'o': + assert( file2.IsEmpty() ); + file2 = optarg; + break; + + case 'B': + loadBulkData = 1; + break; + + case 'T': + loadTransferSyntax = 1; + break; + + case 'V': + verbose = 1; + break; + + case 'W': + warning = 1; + break; + + case 'D': + debug = 1; + break; + + case 'E': + error = 1; + break; + + case 'h': + help = 1; + break; + + case 'v': + version = 1; + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + int v = argc - optind; + if( v == 2 ) + { + file1 = argv[optind]; + file2 = argv[optind+1]; + } + else if( v == 1 ) + { + file1 = argv[optind]; + } + else + { + PrintHelp(); + return 1; + } + } + + if( file1.IsEmpty() ) + { + PrintHelp(); + return 1; + } + + if( version ) + { + PrintVersion(); + return 0; + } + + if( help ) + { + PrintHelp(); + return 0; + } + + gdcm::Trace::SetDebug( debug != 0); + gdcm::Trace::SetWarning( warning != 0); + gdcm::Trace::SetError( error != 0); + // when verbose is true, make sure warning+error are turned on: + if( verbose ) + { + gdcm::Trace::SetWarning( verbose != 0); + gdcm::Trace::SetError( verbose!= 0); + } + + const char *file1extension = file1.GetExtension(); + //const char *file2extension = file2.GetExtension(); + + if(gdcm::System::StrCaseCmp(file1extension,".xml") != 0)// by default we assume it is a DICOM file-- as no extension is required for it + { + gdcm::Reader reader; + reader.SetFileName( file1.GetFileName() ); + bool success = reader.Read(); + if( !success )//!ignoreerrors ) + { + std::cerr << "Failed to read: " << file1 << std::endl; + return 1; + } + + if(loadBulkData) + { + SimpleFileXMLPrinter printer; + printer.SetFile ( reader.GetFile() ); + if( file2.IsEmpty() ) + { + printer.Print( std::cout ); + } + else + { + std::ofstream outfile; + outfile.open (file2.GetFileName()); + printer.Print( outfile ); + outfile.close(); + } + } + else + { + XMLPrinter printer; + printer.SetFile ( reader.GetFile() ); + if( file2.IsEmpty() ) + { + printer.Print( std::cout ); + } + else + { + std::ofstream outfile; + outfile.open (file2.GetFileName()); + printer.Print( outfile ); + outfile.close(); + } + } + return 0; + } + else + { +#ifdef GDCM_USE_SYSTEM_LIBXML2 + /* + * This initializes the library and checks potential ABI mismatches + * between the version it was compiled for and the actual shared + * library used. + */ + LIBXML_TEST_VERSION + + XMLtoDICOM(file1,file2); + + /* + * Cleanup function for the XML library. + */ + xmlCleanupParser(); + /* + * This is to debug memory for regression tests. + */ + xmlMemoryDump(); +#else + printf("\nPlease configure Cmake options with GDCM_USE_SYSTEM_LIBXML2 as ON and compile!\n"); +#endif + } +} diff --git a/gdcm/Applications/Cxx/pdf2dcm.cxx b/gdcm/Applications/Cxx/pdf2dcm.cxx new file mode 100644 index 0000000..882e28e --- /dev/null +++ b/gdcm/Applications/Cxx/pdf2dcm.cxx @@ -0,0 +1,21 @@ +/* +Provide a mapping for: + +Title: ITK Software Guide +Subject: Medical Image Segmentation and Registration Toolkit +Keywords: Registration,Segmentation,Guide +Author: Luis Ibanez and Will Schroeder +Creator: LaTeX with hyperref package +Producer: dvips + GPL Ghostscript 8.15 +CreationDate: Mon Nov 21 19:34:28 2005 +ModDate: Mon Nov 21 19:34:28 2005 +Tagged: no +Pages: 836 +Encrypted: no +Page size: 522 x 675 pts +File size: 5580502 bytes +Optimized: no +PDF version: 1.4 + +into DICOM elements... +*/ diff --git a/gdcm/Applications/Cxx/puff.c b/gdcm/Applications/Cxx/puff.c new file mode 100644 index 0000000..df8470c --- /dev/null +++ b/gdcm/Applications/Cxx/puff.c @@ -0,0 +1,837 @@ +/* + * puff.c + * Copyright (C) 2002-2010 Mark Adler + * For conditions of distribution and use, see copyright notice in puff.h + * version 2.2, 25 Apr 2010 + * + * puff.c is a simple inflate written to be an unambiguous way to specify the + * deflate format. It is not written for speed but rather simplicity. As a + * side benefit, this code might actually be useful when small code is more + * important than speed, such as bootstrap applications. For typical deflate + * data, zlib's inflate() is about four times as fast as puff(). zlib's + * inflate compiles to around 20K on my machine, whereas puff.c compiles to + * around 4K on my machine (a PowerPC using GNU cc). If the faster decode() + * function here is used, then puff() is only twice as slow as zlib's + * inflate(). + * + * All dynamically allocated memory comes from the stack. The stack required + * is less than 2K bytes. This code is compatible with 16-bit int's and + * assumes that long's are at least 32 bits. puff.c uses the short data type, + * assumed to be 16 bits, for arrays in order to to conserve memory. The code + * works whether integers are stored big endian or little endian. + * + * In the comments below are "Format notes" that describe the inflate process + * and document some of the less obvious aspects of the format. This source + * code is meant to supplement RFC 1951, which formally describes the deflate + * format: + * + * http://www.zlib.org/rfc-deflate.html + */ + +/* + * Change history: + * + * 1.0 10 Feb 2002 - First version + * 1.1 17 Feb 2002 - Clarifications of some comments and notes + * - Update puff() dest and source pointers on negative + * errors to facilitate debugging deflators + * - Remove longest from struct huffman -- not needed + * - Simplify offs[] index in construct() + * - Add input size and checking, using longjmp() to + * maintain easy readability + * - Use short data type for large arrays + * - Use pointers instead of long to specify source and + * destination sizes to avoid arbitrary 4 GB limits + * 1.2 17 Mar 2002 - Add faster version of decode(), doubles speed (!), + * but leave simple version for readabilty + * - Make sure invalid distances detected if pointers + * are 16 bits + * - Fix fixed codes table error + * - Provide a scanning mode for determining size of + * uncompressed data + * 1.3 20 Mar 2002 - Go back to lengths for puff() parameters [Gailly] + * - Add a puff.h file for the interface + * - Add braces in puff() for else do [Gailly] + * - Use indexes instead of pointers for readability + * 1.4 31 Mar 2002 - Simplify construct() code set check + * - Fix some comments + * - Add FIXLCODES #define + * 1.5 6 Apr 2002 - Minor comment fixes + * 1.6 7 Aug 2002 - Minor format changes + * 1.7 3 Mar 2003 - Added test code for distribution + * - Added zlib-like license + * 1.8 9 Jan 2004 - Added some comments on no distance codes case + * 1.9 21 Feb 2008 - Fix bug on 16-bit integer architectures [Pohland] + * - Catch missing end-of-block symbol error + * 2.0 25 Jul 2008 - Add #define to permit distance too far back + * - Add option in TEST code for puff to write the data + * - Add option in TEST code to skip input bytes + * - Allow TEST code to read from piped stdin + * 2.1 4 Apr 2010 - Avoid variable initialization for happier compilers + * - Avoid unsigned comparisons for even happier compilers + * 2.2 25 Apr 2010 - Fix bug in variable initializations [Oberhumer] + * - Add const where appropriate [Oberhumer] + * - Split if's and ?'s for coverage testing + * - Break out test code to separate file + * - Move NIL to puff.h + * - Allow incomplete code only if single code length is 1 + * - Add full code coverage test to Makefile + */ + +#include /* for setjmp(), longjmp(), and jmp_buf */ +#include "puff.h" /* prototype for puff() */ + +#define local static /* for local function definitions */ + +/* + * Maximums for allocations and loops. It is not useful to change these -- + * they are fixed by the deflate format. + */ +#define MAXBITS 15 /* maximum bits in a code */ +#define MAXLCODES 286 /* maximum number of literal/length codes */ +#define MAXDCODES 30 /* maximum number of distance codes */ +#define MAXCODES (MAXLCODES+MAXDCODES) /* maximum codes lengths to read */ +#define FIXLCODES 288 /* number of fixed literal/length codes */ + +/* input and output state */ +struct state { + /* output state */ + unsigned char *out; /* output buffer */ + unsigned long outlen; /* available space at out */ + unsigned long outcnt; /* bytes written to out so far */ + + /* input state */ + const unsigned char *in; /* input buffer */ + unsigned long inlen; /* available input at in */ + unsigned long incnt; /* bytes read so far */ + int bitbuf; /* bit buffer */ + int bitcnt; /* number of bits in bit buffer */ + + /* input limit error return state for bits() and decode() */ + jmp_buf env; +}; + +/* + * Return need bits from the input stream. This always leaves less than + * eight bits in the buffer. bits() works properly for need == 0. + * + * Format notes: + * + * - Bits are stored in bytes from the least significant bit to the most + * significant bit. Therefore bits are dropped from the bottom of the bit + * buffer, using shift right, and new bytes are appended to the top of the + * bit buffer, using shift left. + */ +local int bits(struct state *s, int need) +{ + long val; /* bit accumulator (can use up to 20 bits) */ + + /* load at least need bits into val */ + val = s->bitbuf; + while (s->bitcnt < need) { + if (s->incnt == s->inlen) + longjmp(s->env, 1); /* out of input */ + val |= (long)(s->in[s->incnt++]) << s->bitcnt; /* load eight bits */ + s->bitcnt += 8; + } + + /* drop need bits and update buffer, always zero to seven bits left */ + s->bitbuf = (int)(val >> need); + s->bitcnt -= need; + + /* return need bits, zeroing the bits above that */ + return (int)(val & ((1L << need) - 1)); +} + +/* + * Process a stored block. + * + * Format notes: + * + * - After the two-bit stored block type (00), the stored block length and + * stored bytes are byte-aligned for fast copying. Therefore any leftover + * bits in the byte that has the last bit of the type, as many as seven, are + * discarded. The value of the discarded bits are not defined and should not + * be checked against any expectation. + * + * - The second inverted copy of the stored block length does not have to be + * checked, but it's probably a good idea to do so anyway. + * + * - A stored block can have zero length. This is sometimes used to byte-align + * subsets of the compressed data for random access or partial recovery. + */ +local int stored(struct state *s) +{ + unsigned len; /* length of stored block */ + + /* discard leftover bits from current byte (assumes s->bitcnt < 8) */ + s->bitbuf = 0; + s->bitcnt = 0; + + /* get length and check against its one's complement */ + if (s->incnt + 4 > s->inlen) + return 2; /* not enough input */ + len = s->in[s->incnt++]; + len |= s->in[s->incnt++] << 8; + if (s->in[s->incnt++] != (~len & 0xff) || + s->in[s->incnt++] != ((~len >> 8) & 0xff)) + return -2; /* didn't match complement! */ + + /* copy len bytes from in to out */ + if (s->incnt + len > s->inlen) + return 2; /* not enough input */ + if (s->out != NIL) { + if (s->outcnt + len > s->outlen) + return 1; /* not enough output space */ + while (len--) + s->out[s->outcnt++] = s->in[s->incnt++]; + } + else { /* just scanning */ + s->outcnt += len; + s->incnt += len; + } + + /* done with a valid stored block */ + return 0; +} + +/* + * Huffman code decoding tables. count[1..MAXBITS] is the number of symbols of + * each length, which for a canonical code are stepped through in order. + * symbol[] are the symbol values in canonical order, where the number of + * entries is the sum of the counts in count[]. The decoding process can be + * seen in the function decode() below. + */ +struct huffman { + short *count; /* number of symbols of each length */ + short *symbol; /* canonically ordered symbols */ +}; + +/* + * Decode a code from the stream s using huffman table h. Return the symbol or + * a negative value if there is an error. If all of the lengths are zero, i.e. + * an empty code, or if the code is incomplete and an invalid code is received, + * then -10 is returned after reading MAXBITS bits. + * + * Format notes: + * + * - The codes as stored in the compressed data are bit-reversed relative to + * a simple integer ordering of codes of the same lengths. Hence below the + * bits are pulled from the compressed data one at a time and used to + * build the code value reversed from what is in the stream in order to + * permit simple integer comparisons for decoding. A table-based decoding + * scheme (as used in zlib) does not need to do this reversal. + * + * - The first code for the shortest length is all zeros. Subsequent codes of + * the same length are simply integer increments of the previous code. When + * moving up a length, a zero bit is appended to the code. For a complete + * code, the last code of the longest length will be all ones. + * + * - Incomplete codes are handled by this decoder, since they are permitted + * in the deflate format. See the format notes for fixed() and dynamic(). + */ +#ifdef SLOW +local int decode(struct state *s, const struct huffman *h) +{ + int len; /* current number of bits in code */ + int code; /* len bits being decoded */ + int first; /* first code of length len */ + int count; /* number of codes of length len */ + int index; /* index of first code of length len in symbol table */ + + code = first = index = 0; + for (len = 1; len <= MAXBITS; len++) { + code |= bits(s, 1); /* get next bit */ + count = h->count[len]; + if (code - count < first) /* if length len, return symbol */ + return h->symbol[index + (code - first)]; + index += count; /* else update for next length */ + first += count; + first <<= 1; + code <<= 1; + } + return -10; /* ran out of codes */ +} + +/* + * A faster version of decode() for real applications of this code. It's not + * as readable, but it makes puff() twice as fast. And it only makes the code + * a few percent larger. + */ +#else /* !SLOW */ +local int decode(struct state *s, const struct huffman *h) +{ + int len; /* current number of bits in code */ + int code; /* len bits being decoded */ + int first; /* first code of length len */ + int count; /* number of codes of length len */ + int index; /* index of first code of length len in symbol table */ + int bitbuf; /* bits from stream */ + int left; /* bits left in next or left to process */ + short *next; /* next number of codes */ + + bitbuf = s->bitbuf; + left = s->bitcnt; + code = first = index = 0; + len = 1; + next = h->count + 1; + while (1) { + while (left--) { + code |= bitbuf & 1; + bitbuf >>= 1; + count = *next++; + if (code - count < first) { /* if length len, return symbol */ + s->bitbuf = bitbuf; + s->bitcnt = (s->bitcnt - len) & 7; + return h->symbol[index + (code - first)]; + } + index += count; /* else update for next length */ + first += count; + first <<= 1; + code <<= 1; + len++; + } + left = (MAXBITS+1) - len; + if (left == 0) + break; + if (s->incnt == s->inlen) + longjmp(s->env, 1); /* out of input */ + bitbuf = s->in[s->incnt++]; + if (left > 8) + left = 8; + } + return -10; /* ran out of codes */ +} +#endif /* SLOW */ + +/* + * Given the list of code lengths length[0..n-1] representing a canonical + * Huffman code for n symbols, construct the tables required to decode those + * codes. Those tables are the number of codes of each length, and the symbols + * sorted by length, retaining their original order within each length. The + * return value is zero for a complete code set, negative for an over- + * subscribed code set, and positive for an incomplete code set. The tables + * can be used if the return value is zero or positive, but they cannot be used + * if the return value is negative. If the return value is zero, it is not + * possible for decode() using that table to return an error--any stream of + * enough bits will resolve to a symbol. If the return value is positive, then + * it is possible for decode() using that table to return an error for received + * codes past the end of the incomplete lengths. + * + * Not used by decode(), but used for error checking, h->count[0] is the number + * of the n symbols not in the code. So n - h->count[0] is the number of + * codes. This is useful for checking for incomplete codes that have more than + * one symbol, which is an error in a dynamic block. + * + * Assumption: for all i in 0..n-1, 0 <= length[i] <= MAXBITS + * This is assured by the construction of the length arrays in dynamic() and + * fixed() and is not verified by construct(). + * + * Format notes: + * + * - Permitted and expected examples of incomplete codes are one of the fixed + * codes and any code with a single symbol which in deflate is coded as one + * bit instead of zero bits. See the format notes for fixed() and dynamic(). + * + * - Within a given code length, the symbols are kept in ascending order for + * the code bits definition. + */ +local int construct(struct huffman *h, const short *length, int n) +{ + int symbol; /* current symbol when stepping through length[] */ + int len; /* current length when stepping through h->count[] */ + int left; /* number of possible codes left of current length */ + short offs[MAXBITS+1]; /* offsets in symbol table for each length */ + + /* count number of codes of each length */ + for (len = 0; len <= MAXBITS; len++) + h->count[len] = 0; + for (symbol = 0; symbol < n; symbol++) + (h->count[length[symbol]])++; /* assumes lengths are within bounds */ + if (h->count[0] == n) /* no codes! */ + return 0; /* complete, but decode() will fail */ + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; /* one possible code of zero length */ + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; /* one more bit, double codes left */ + left -= h->count[len]; /* deduct count from possible codes */ + if (left < 0) + return left; /* over-subscribed--return negative */ + } /* left > 0 means incomplete */ + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) + offs[len + 1] = offs[len] + h->count[len]; + + /* + * put symbols in table sorted by length, by symbol order within each + * length + */ + for (symbol = 0; symbol < n; symbol++) + if (length[symbol] != 0) + h->symbol[offs[length[symbol]]++] = symbol; + + /* return zero for complete set, positive for incomplete set */ + return left; +} + +/* + * Decode literal/length and distance codes until an end-of-block code. + * + * Format notes: + * + * - Compressed data that is after the block type if fixed or after the code + * description if dynamic is a combination of literals and length/distance + * pairs terminated by and end-of-block code. Literals are simply Huffman + * coded bytes. A length/distance pair is a coded length followed by a + * coded distance to represent a string that occurs earlier in the + * uncompressed data that occurs again at the current location. + * + * - Literals, lengths, and the end-of-block code are combined into a single + * code of up to 286 symbols. They are 256 literals (0..255), 29 length + * symbols (257..285), and the end-of-block symbol (256). + * + * - There are 256 possible lengths (3..258), and so 29 symbols are not enough + * to represent all of those. Lengths 3..10 and 258 are in fact represented + * by just a length symbol. Lengths 11..257 are represented as a symbol and + * some number of extra bits that are added as an integer to the base length + * of the length symbol. The number of extra bits is determined by the base + * length symbol. These are in the static arrays below, lens[] for the base + * lengths and lext[] for the corresponding number of extra bits. + * + * - The reason that 258 gets its own symbol is that the longest length is used + * often in highly redundant files. Note that 258 can also be coded as the + * base value 227 plus the maximum extra value of 31. While a good deflate + * should never do this, it is not an error, and should be decoded properly. + * + * - If a length is decoded, including its extra bits if any, then it is + * followed a distance code. There are up to 30 distance symbols. Again + * there are many more possible distances (1..32768), so extra bits are added + * to a base value represented by the symbol. The distances 1..4 get their + * own symbol, but the rest require extra bits. The base distances and + * corresponding number of extra bits are below in the static arrays dist[] + * and dext[]. + * + * - Literal bytes are simply written to the output. A length/distance pair is + * an instruction to copy previously uncompressed bytes to the output. The + * copy is from distance bytes back in the output stream, copying for length + * bytes. + * + * - Distances pointing before the beginning of the output data are not + * permitted. + * + * - Overlapped copies, where the length is greater than the distance, are + * allowed and common. For example, a distance of one and a length of 258 + * simply copies the last byte 258 times. A distance of four and a length of + * twelve copies the last four bytes three times. A simple forward copy + * ignoring whether the length is greater than the distance or not implements + * this correctly. You should not use memcpy() since its behavior is not + * defined for overlapped arrays. You should not use memmove() or bcopy() + * since though their behavior -is- defined for overlapping arrays, it is + * defined to do the wrong thing in this case. + */ +local int codes(struct state *s, + const struct huffman *lencode, + const struct huffman *distcode) +{ + int symbol; /* decoded symbol */ + int len; /* length for copy */ + unsigned dist; /* distance for copy */ + static const short lens[29] = { /* Size base for length codes 257..285 */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258}; + static const short lext[29] = { /* Extra bits for length codes 257..285 */ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0}; + static const short dists[30] = { /* Offset base for distance codes 0..29 */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577}; + static const short dext[30] = { /* Extra bits for distance codes 0..29 */ + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13}; + + /* decode literals and length/distance pairs */ + do { + symbol = decode(s, lencode); + if (symbol < 0) + return symbol; /* invalid symbol */ + if (symbol < 256) { /* literal: symbol is the byte */ + /* write out the literal */ + if (s->out != NIL) { + if (s->outcnt == s->outlen) + return 1; + s->out[s->outcnt] = symbol; + } + s->outcnt++; + } + else if (symbol > 256) { /* length */ + /* get and compute length */ + symbol -= 257; + if (symbol >= 29) + return -10; /* invalid fixed code */ + len = lens[symbol] + bits(s, lext[symbol]); + + /* get and check distance */ + symbol = decode(s, distcode); + if (symbol < 0) + return symbol; /* invalid symbol */ + dist = dists[symbol] + bits(s, dext[symbol]); +#ifndef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + if (dist > s->outcnt) + return -11; /* distance too far back */ +#endif + + /* copy length bytes from distance bytes back */ + if (s->out != NIL) { + if (s->outcnt + len > s->outlen) + return 1; + while (len--) { + s->out[s->outcnt] = +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + dist > s->outcnt ? + 0 : +#endif + s->out[s->outcnt - dist]; + s->outcnt++; + } + } + else + s->outcnt += len; + } + } while (symbol != 256); /* end of block symbol */ + + /* done with a valid fixed or dynamic block */ + return 0; +} + +/* + * Process a fixed codes block. + * + * Format notes: + * + * - This block type can be useful for compressing small amounts of data for + * which the size of the code descriptions in a dynamic block exceeds the + * benefit of custom codes for that block. For fixed codes, no bits are + * spent on code descriptions. Instead the code lengths for literal/length + * codes and distance codes are fixed. The specific lengths for each symbol + * can be seen in the "for" loops below. + * + * - The literal/length code is complete, but has two symbols that are invalid + * and should result in an error if received. This cannot be implemented + * simply as an incomplete code since those two symbols are in the "middle" + * of the code. They are eight bits long and the longest literal/length\ + * code is nine bits. Therefore the code must be constructed with those + * symbols, and the invalid symbols must be detected after decoding. + * + * - The fixed distance codes also have two invalid symbols that should result + * in an error if received. Since all of the distance codes are the same + * length, this can be implemented as an incomplete code. Then the invalid + * codes are detected while decoding. + */ +local int fixed(struct state *s) +{ + static int virgin = 1; + static short lencnt[MAXBITS+1], lensym[FIXLCODES]; + static short distcnt[MAXBITS+1], distsym[MAXDCODES]; + static struct huffman lencode, distcode; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + int symbol; + short lengths[FIXLCODES]; + + /* construct lencode and distcode */ + lencode.count = lencnt; + lencode.symbol = lensym; + distcode.count = distcnt; + distcode.symbol = distsym; + + /* literal/length table */ + for (symbol = 0; symbol < 144; symbol++) + lengths[symbol] = 8; + for (; symbol < 256; symbol++) + lengths[symbol] = 9; + for (; symbol < 280; symbol++) + lengths[symbol] = 7; + for (; symbol < FIXLCODES; symbol++) + lengths[symbol] = 8; + construct(&lencode, lengths, FIXLCODES); + + /* distance table */ + for (symbol = 0; symbol < MAXDCODES; symbol++) + lengths[symbol] = 5; + construct(&distcode, lengths, MAXDCODES); + + /* do this just once */ + virgin = 0; + } + + /* decode data until end-of-block code */ + return codes(s, &lencode, &distcode); +} + +/* + * Process a dynamic codes block. + * + * Format notes: + * + * - A dynamic block starts with a description of the literal/length and + * distance codes for that block. New dynamic blocks allow the compressor to + * rapidly adapt to changing data with new codes optimized for that data. + * + * - The codes used by the deflate format are "canonical", which means that + * the actual bits of the codes are generated in an unambiguous way simply + * from the number of bits in each code. Therefore the code descriptions + * are simply a list of code lengths for each symbol. + * + * - The code lengths are stored in order for the symbols, so lengths are + * provided for each of the literal/length symbols, and for each of the + * distance symbols. + * + * - If a symbol is not used in the block, this is represented by a zero as + * as the code length. This does not mean a zero-length code, but rather + * that no code should be created for this symbol. There is no way in the + * deflate format to represent a zero-length code. + * + * - The maximum number of bits in a code is 15, so the possible lengths for + * any code are 1..15. + * + * - The fact that a length of zero is not permitted for a code has an + * interesting consequence. Normally if only one symbol is used for a given + * code, then in fact that code could be represented with zero bits. However + * in deflate, that code has to be at least one bit. So for example, if + * only a single distance base symbol appears in a block, then it will be + * represented by a single code of length one, in particular one 0 bit. This + * is an incomplete code, since if a 1 bit is received, it has no meaning, + * and should result in an error. So incomplete distance codes of one symbol + * should be permitted, and the receipt of invalid codes should be handled. + * + * - It is also possible to have a single literal/length code, but that code + * must be the end-of-block code, since every dynamic block has one. This + * is not the most efficient way to create an empty block (an empty fixed + * block is fewer bits), but it is allowed by the format. So incomplete + * literal/length codes of one symbol should also be permitted. + * + * - If there are only literal codes and no lengths, then there are no distance + * codes. This is represented by one distance code with zero bits. + * + * - The list of up to 286 length/literal lengths and up to 30 distance lengths + * are themselves compressed using Huffman codes and run-length encoding. In + * the list of code lengths, a 0 symbol means no code, a 1..15 symbol means + * that length, and the symbols 16, 17, and 18 are run-length instructions. + * Each of 16, 17, and 18 are follwed by extra bits to define the length of + * the run. 16 copies the last length 3 to 6 times. 17 represents 3 to 10 + * zero lengths, and 18 represents 11 to 138 zero lengths. Unused symbols + * are common, hence the special coding for zero lengths. + * + * - The symbols for 0..18 are Huffman coded, and so that code must be + * described first. This is simply a sequence of up to 19 three-bit values + * representing no code (0) or the code length for that symbol (1..7). + * + * - A dynamic block starts with three fixed-size counts from which is computed + * the number of literal/length code lengths, the number of distance code + * lengths, and the number of code length code lengths (ok, you come up with + * a better name!) in the code descriptions. For the literal/length and + * distance codes, lengths after those provided are considered zero, i.e. no + * code. The code length code lengths are received in a permuted order (see + * the order[] array below) to make a short code length code length list more + * likely. As it turns out, very short and very long codes are less likely + * to be seen in a dynamic code description, hence what may appear initially + * to be a peculiar ordering. + * + * - Given the number of literal/length code lengths (nlen) and distance code + * lengths (ndist), then they are treated as one long list of nlen + ndist + * code lengths. Therefore run-length coding can and often does cross the + * boundary between the two sets of lengths. + * + * - So to summarize, the code description at the start of a dynamic block is + * three counts for the number of code lengths for the literal/length codes, + * the distance codes, and the code length codes. This is followed by the + * code length code lengths, three bits each. This is used to construct the + * code length code which is used to read the remainder of the lengths. Then + * the literal/length code lengths and distance lengths are read as a single + * set of lengths using the code length codes. Codes are constructed from + * the resulting two sets of lengths, and then finally you can start + * decoding actual compressed data in the block. + * + * - For reference, a "typical" size for the code description in a dynamic + * block is around 80 bytes. + */ +local int dynamic(struct state *s) +{ + int nlen, ndist, ncode; /* number of lengths in descriptor */ + int index; /* index of lengths[] */ + int err; /* construct() return value */ + short lengths[MAXCODES]; /* descriptor code lengths */ + short lencnt[MAXBITS+1], lensym[MAXLCODES]; /* lencode memory */ + short distcnt[MAXBITS+1], distsym[MAXDCODES]; /* distcode memory */ + struct huffman lencode, distcode; /* length and distance codes */ + static const short order[19] = /* permutation of code length codes */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + /* construct lencode and distcode */ + lencode.count = lencnt; + lencode.symbol = lensym; + distcode.count = distcnt; + distcode.symbol = distsym; + + /* get number of lengths in each table, check lengths */ + nlen = bits(s, 5) + 257; + ndist = bits(s, 5) + 1; + ncode = bits(s, 4) + 4; + if (nlen > MAXLCODES || ndist > MAXDCODES) + return -3; /* bad counts */ + + /* read code length code lengths (really), missing lengths are zero */ + for (index = 0; index < ncode; index++) + lengths[order[index]] = bits(s, 3); + for (; index < 19; index++) + lengths[order[index]] = 0; + + /* build huffman table for code lengths codes (use lencode temporarily) */ + err = construct(&lencode, lengths, 19); + if (err != 0) /* require complete code set here */ + return -4; + + /* read length/literal and distance code length tables */ + index = 0; + while (index < nlen + ndist) { + int symbol; /* decoded value */ + int len; /* last length to repeat */ + + symbol = decode(s, &lencode); + if (symbol < 16) /* length in 0..15 */ + lengths[index++] = symbol; + else { /* repeat instruction */ + len = 0; /* assume repeating zeros */ + if (symbol == 16) { /* repeat last length 3..6 times */ + if (index == 0) + return -5; /* no last length! */ + len = lengths[index - 1]; /* last length */ + symbol = 3 + bits(s, 2); + } + else if (symbol == 17) /* repeat zero 3..10 times */ + symbol = 3 + bits(s, 3); + else /* == 18, repeat zero 11..138 times */ + symbol = 11 + bits(s, 7); + if (index + symbol > nlen + ndist) + return -6; /* too many lengths! */ + while (symbol--) /* repeat last or zero symbol times */ + lengths[index++] = len; + } + } + + /* check for end-of-block code -- there better be one! */ + if (lengths[256] == 0) + return -9; + + /* build huffman table for literal/length codes */ + err = construct(&lencode, lengths, nlen); + if (err && (err < 0 || nlen != lencode.count[0] + lencode.count[1])) + return -7; /* incomplete code ok only for single length 1 code */ + + /* build huffman table for distance codes */ + err = construct(&distcode, lengths + nlen, ndist); + if (err && (err < 0 || ndist != distcode.count[0] + distcode.count[1])) + return -8; /* incomplete code ok only for single length 1 code */ + + /* decode data until end-of-block code */ + return codes(s, &lencode, &distcode); +} + +/* + * Inflate source to dest. On return, destlen and sourcelen are updated to the + * size of the uncompressed data and the size of the deflate data respectively. + * On success, the return value of puff() is zero. If there is an error in the + * source data, i.e. it is not in the deflate format, then a negative value is + * returned. If there is not enough input available or there is not enough + * output space, then a positive error is returned. In that case, destlen and + * sourcelen are not updated to facilitate retrying from the beginning with the + * provision of more input data or more output space. In the case of invalid + * inflate data (a negative error), the dest and source pointers are updated to + * facilitate the debugging of deflators. + * + * puff() also has a mode to determine the size of the uncompressed output with + * no output written. For this dest must be (unsigned char *)0. In this case, + * the input value of *destlen is ignored, and on return *destlen is set to the + * size of the uncompressed output. + * + * The return codes are: + * + * 2: available inflate data did not terminate + * 1: output space exhausted before completing inflate + * 0: successful inflate + * -1: invalid block type (type == 3) + * -2: stored block length did not match one's complement + * -3: dynamic block code description: too many length or distance codes + * -4: dynamic block code description: code lengths codes incomplete + * -5: dynamic block code description: repeat lengths with no first length + * -6: dynamic block code description: repeat more than specified lengths + * -7: dynamic block code description: invalid literal/length code lengths + * -8: dynamic block code description: invalid distance code lengths + * -9: dynamic block code description: missing end-of-block code + * -10: invalid literal/length or distance code in fixed or dynamic block + * -11: distance is too far back in fixed or dynamic block + * + * Format notes: + * + * - Three bits are read for each block to determine the kind of block and + * whether or not it is the last block. Then the block is decoded and the + * process repeated if it was not the last block. + * + * - The leftover bits in the last byte of the deflate data after the last + * block (if it was a fixed or dynamic block) are undefined and have no + * expected values to check. + */ +int puff(unsigned char *dest, /* pointer to destination pointer */ + unsigned long *destlen, /* amount of output space */ + const unsigned char *source, /* pointer to source data pointer */ + unsigned long *sourcelen) /* amount of input available */ +{ + struct state s; /* input/output state */ + int last, type; /* block information */ + int err; /* return value */ + + /* initialize output state */ + s.out = dest; + s.outlen = *destlen; /* ignored if dest is NIL */ + s.outcnt = 0; + + /* initialize input state */ + s.in = source; + s.inlen = *sourcelen; + s.incnt = 0; + s.bitbuf = 0; + s.bitcnt = 0; + + /* return if bits() or decode() tries to read past available input */ + if (setjmp(s.env) != 0) /* if came back here via longjmp() */ + err = 2; /* then skip do-loop, return error */ + else { + /* process blocks until last block or error */ + do { + last = bits(&s, 1); /* one if last block */ + type = bits(&s, 2); /* block type 0..3 */ + err = type == 0 ? + stored(&s) : + (type == 1 ? + fixed(&s) : + (type == 2 ? + dynamic(&s) : + -1)); /* type == 3, invalid */ + if (err != 0) + break; /* return with error */ + } while (!last); + } + + /* update the lengths and return */ + if (err <= 0) { + *destlen = s.outcnt; + *sourcelen = s.incnt; + } + return err; +} diff --git a/gdcm/Applications/Cxx/puff.h b/gdcm/Applications/Cxx/puff.h new file mode 100644 index 0000000..962ae5d --- /dev/null +++ b/gdcm/Applications/Cxx/puff.h @@ -0,0 +1,44 @@ +/* puff.h + Copyright (C) 2002-2010 Mark Adler, all rights reserved + version 2.2, 25 Apr 2010 + + This software is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Mark Adler madler@alumni.caltech.edu + */ + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/* + * See puff.c for purpose and usage. + */ +#ifndef NIL +# define NIL ((unsigned char *)0) /* for no output option */ +#endif + +int puff(unsigned char *dest, /* pointer to destination pointer */ + unsigned long *destlen, /* amount of output space */ + const unsigned char *source, /* pointer to source data pointer */ + unsigned long *sourcelen); /* amount of input available */ + +#ifdef __cplusplus +} /* end extern "C" */ +#endif diff --git a/gdcm/Applications/Python/README b/gdcm/Applications/Python/README new file mode 100644 index 0000000..7706163 --- /dev/null +++ b/gdcm/Applications/Python/README @@ -0,0 +1,62 @@ += !CherryWado = + +== About == +!CherryWado is a WADO server written in python, using the !CherryPy web framework. + +DICOM images are handled with the GDCM DICOM toolkit command line utilities. + +For information about DICOM and Web Access to persistent Dicom Objects see +http://en.wikipedia.org/wiki/DICOM. + +== Dependencies == + * !CherryPy + * flup + * Python Imaging Library (PIL) + * DICOM Toolkit - gdcm (+VTK: gdcm2pnm) + +== Installation and configuration == +Our WADO server doesn't make any assumption about how / where you store DICOM +files. Therefore, in order to use it, you need to tweak accessdata.py to specify +a way to retrieve the requested DICOM object. + +You can test the server as follows: + +$ python wado.py test + +# preparation: + +mkdir -p /tmp/dicom/1.2.840.113619.2.5.1762386977.1328.985934491.590/1.2.840.113619.2.5.1762386977.1328.985934491.643/1.2.840.113619.2.5.1762386977.1328.985934491.693 +rmdir /tmp/dicom/1.2.840.113619.2.5.1762386977.1328.985934491.590/1.2.840.113619.2.5.1762386977.1328.985934491.643/1.2.840.113619.2.5.1762386977.1328.985934491.693 +cp gdcmData/012345.002.050.dcm /tmp/dicom/1.2.840.113619.2.5.1762386977.1328.985934491.590/1.2.840.113619.2.5.1762386977.1328.985934491.643/1.2.840.113619.2.5.1762386977.1328.985934491.693 + +# Open in your favorite browser +http://127.0.0.1:8080/?requestType=WADO&studyUID=1.2.840.113619.2.5.1762386977.1328.985934491.590&seriesUID=1.2.840.113619.2.5.1762386977.1328.985934491.643&objectUID=1.2.840.113619.2.5.1762386977.1328.985934491.693&contentType=image/png + +!CherryWado uses FLUP to ease deployment with lighttpd or Apache. + +Here is a lighttpd.conf snippet for your convenience: +{{{ +$HTTP["url"] =~ "" { + fastcgi.server = ( + "/wado/" => ( + "wado" => ( + "bin-path" => "/path/to/wado.py", + "socket" => "/tmp/wado.sock", + "check-local" => "disable", + "disable-time" => 1, + "min-procs" => 1, + "max-procs" => 10, + ), + ), + ) +}}} + +Make sure you have "mod_fastcgi" in server.modules! + +== License == +!CherryWado is licensed under the Apache License, Version 2.0. + +See http://www.apache.org/licenses/LICENSE-2.0 for the full text. + +== Authors == +Emanuele Rocca, Marco De Benedetto, Mathieu Malaterre diff --git a/gdcm/Applications/Python/accessdata.py b/gdcm/Applications/Python/accessdata.py new file mode 100644 index 0000000..eddefb9 --- /dev/null +++ b/gdcm/Applications/Python/accessdata.py @@ -0,0 +1,75 @@ +# Copyright 2008 Emanuele Rocca +# Copyright 2008 Marco De Benedetto +# Copyright (c) 2006-2011 Mathieu Malaterre +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +DICOM data access layer. + +Write your own __getfile function to suit your needs. +""" + +from lib import * +import images + +def __getfile(studyUID, seriesUID, objectUID): + """Given a studyUID, a seriesUID and an objectUID, this function must + retrieve (somehow) the corresponding DICOM file and return the filename. + Take this implementation as a rough example.""" + + #tmpdir = "/var/spool/dicom" + tmpdir = "/tmp/dicom" + + import os + import errno + import tempfile + + studydir = "%s/%s" % (tmpdir, studyUID) + seriesdir = "%s/%s" % (studydir, seriesUID) + objectfile = "%s/%s" % (seriesdir, objectUID) + + if not os.path.isdir(seriesdir): + dump_file = tempfile.NamedTemporaryFile() + dump_file.write("(0008,0052) CS [STUDY]\n(0020,000d) UI [%s]" % studyUID) + dump_file.flush() + + dicom_filename = dump_file.name + ".dcm" + trycmd("dump2dcm %s %s" % (dump_file.name, dicom_filename)) + + # Si chiede all'aetitle DW_AM (PACS) di muovere su webapps + # Per come e' definito il nodo webapps sul PACS (DW_AM) lo studio + # viene inviato sulla porta 3000 + # Deve essere attivo il servizio (!!! avviato da www-data !!!) simple_storage: + # simple_storage -s -x /var/spool/dicom -n /etc/dicom/naming-convention -c webapps -f 3000 + # Le immagini DICOM vengono archiviate in /var/spool/dicom/studyUID/seriersUID/objectUID + # come descritto in /etc/dicom/naming-convention + # Il servizio simple_storage forka ed e' quindi possibile ricevere piu' + # studi contemporaneamente + + movecmd = "movescu --study --aetitle webapps --move webapps --call DW_AM pacs.ceed 3102" + trycmd("%s %s" % (movecmd, dicom_filename)) + + dump_file.close() + os.unlink(dicom_filename) + return objectfile + +def get(studyUID, seriesUID, objectUID, format='jpeg'): + """Function called by the main program to get an image.""" + objectfile = __getfile(studyUID, seriesUID, objectUID) + return images.Dicom(objectfile, format) + +if __name__ == "__main__": + print get(studyUID="1.3.76.13.10010.0.5.74.3996.1224256625.4053", + seriesUID="1.3.12.2.1107.5.4.4.1053.30000008100608242373400002493", + objectUID="1.3.12.2.1107.5.4.4.1053.30000008100608324685900001822") diff --git a/gdcm/Applications/Python/images.py b/gdcm/Applications/Python/images.py new file mode 100644 index 0000000..9bff04a --- /dev/null +++ b/gdcm/Applications/Python/images.py @@ -0,0 +1,111 @@ +# Copyright 2008 Emanuele Rocca +# Copyright 2008 Marco De Benedetto +# Copyright (c) 2006-2011 Mathieu Malaterre +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +DICOM images conversion and manipulation. + +This module uses the OFFIS DICOM toolkit command line utilities. +""" + +import os + +import Image, ImageEnhance +import StringIO + +from lib import * + +def calc_size(orig_size, max_size): + tofloat = lambda x: (float(x[0]), float(x[1])) + toint = lambda x: (int(x[0]), int(x[1])) + + orig_size = tofloat(orig_size) + max_size = tofloat(max_size) + + h_ratio = orig_size[1] / max_size[1] + new_w = orig_size[0] / h_ratio + + if new_w > max_size[0]: + w_ratio = orig_size[0] / max_size[0] + new_h = orig_size[1] / w_ratio + new_size = max_size[0], new_h + else: + new_size = new_w, max_size[1] + + return toint(new_size) + +class Dicom: + + def __init__(self, filename, format): + """DICOM filename with full path, format can be either jpeg or png""" + assert format in ('jpeg', 'png', 'dicom') + + self.format = format + self.filename = filename + if format != 'dicom': + converted = "%s.%s" % (filename, format) + + if not os.path.isfile(converted): + + quality = "" + if format == 'jpeg': + quality = '--compr-quality 100' + try: + #trycmd("gdcm2pnm --write-%s %s --use-window 1 %s %s" % (format, quality, filename, converted)) + print "gdcm2pnm %s %s" % (filename, converted) + trycmd("gdcm2pnm %s %s" % (filename, converted)) + except CmdException: + #trycmd("gdcm2pnm --write-%s %s %s %s" % (format, quality, filename, converted)) + print "gdcm2pnm %s %s" % (filename, converted) + trycmd("gdcm2pnm %s %s" % (filename, converted)) + os.unlink(filename) + + self.img = Image.open(converted) + + def dump(self): + """To be called after PIL modifications""" + destfile = StringIO.StringIO() + self.img.save(destfile, self.format.upper()) + + destfile.seek(0) + return destfile.read() + + def contrast(self, windowWidth): + enhancer = ImageEnhance.Brightness(self.img) + self.img = enhancer.enhance(float(windowWidth)) + + def brightness(self, windowCenter): + enhancer = ImageEnhance.Contrast(self.img) + self.img = enhancer.enhance(float(windowCenter)) + + def resize(self, rows, columns): + size = (int(rows), int(columns)) + newsize = calc_size(self.img.size, size) + + algorithm = Image.BICUBIC + if newsize[0] < self.img.size[0]: + algorithm = Image.ANTIALIAS + + self.img = self.img.resize(newsize, algorithm) + + def crop(self, left, upper, right, lower): + self.img = self.img.crop((left, upper, right, lower)) + + def raw(self): + return open(self.filename).read() + +if __name__ == "__main__": + + img = Dicom('/var/tmp/1.3.76.13.10010.0.5.74.3996.1224513675.10543/CT.1.2.840.113619.2.81.290.3160.35958.3.9.20081020.270228', 'png') diff --git a/gdcm/Applications/Python/lib.py b/gdcm/Applications/Python/lib.py new file mode 100644 index 0000000..6cd496c --- /dev/null +++ b/gdcm/Applications/Python/lib.py @@ -0,0 +1,27 @@ +# Copyright 2008 Emanuele Rocca +# Copyright 2008 Marco De Benedetto +# Copyright (c) 2006-2011 Mathieu Malaterre +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import commands + +class CmdException(Exception): + """Exception representing a command line error""" + pass + +def trycmd(cmd): + """Try to execute the given command, raising an Exception on errors""" + (exitstatus, outtext) = commands.getstatusoutput(cmd) + if exitstatus != 0: + raise CmdException, "cmd: %s\noutput: %s" % (cmd, outtext) diff --git a/gdcm/Applications/Python/wado.py b/gdcm/Applications/Python/wado.py new file mode 100644 index 0000000..fa16680 --- /dev/null +++ b/gdcm/Applications/Python/wado.py @@ -0,0 +1,189 @@ +#!/usr/bin/python +# Copyright 2008 Emanuele Rocca +# Copyright 2008 Marco De Benedetto +# Copyright (c) 2006-2011 Mathieu Malaterre +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +A WADO server, compliant with section 3.18 of the DICOM standard. + +See http://www.dclunie.com/dicom-status/status.html for more information about +DICOM. + +Basic usage example: + +requestType=WADO&studyUID=1.3.76.13.10010.0.5.74.6120.1224052386.1578&seriesUID=1.3.76.2.1.1.3.1.3.3115.274695982&objectUID=1.3.76.2.1.1.3.1.3.3115.274695982.26&contentType=image/png +""" + +import cherrypy + +from flup.server.fcgi import WSGIServer + +import sys +import os + +CURDIR = os.path.dirname(os.path.abspath(__file__)) + +import accessdata + +try: + testing = sys.argv[1] == "test" + BASEURL = "/" +except IndexError: + BASEURL = "/wado/" + testing = False + +REQUIRED = ( 'requestType', 'studyUID', 'seriesUID', 'objectUID' ) + +OPTIONAL = ( 'contentType', 'charset', 'anonymize', 'annotation', + 'rows', 'columns', 'region', + 'windowWidth', 'windowCenter', 'frameNumber', 'imageQuality', + 'presentationUID', 'presentationSeriesUID', 'transferSyntax' ) + +INVALID_DICOM = ( 'annotation', 'rows', 'columns', 'region', + 'windowWidth', 'windowCenter' ) + +INVALID_NONDICOM = ( 'anonymize', ) + +def err(msg): + """Function to handle errors""" + raise Exception, msg + +def check_params(kwargs): + """Validate and sanitize requests""" + # TODO: implement every check + valid = REQUIRED + OPTIONAL + + curparams = kwargs.keys() + + # WADO is the only requestType currently accepted by the standard + assert kwargs['requestType'] == "WADO" + + # checking unknown parameters + for par in curparams: + if par not in valid: + err("Unknown parameter: " + par) + + # checking missing parameters + for par in REQUIRED: + if par not in curparams: + err("Missing parameter: " + par) + + # default content type is image/jpeg + kwargs['contentType'] = kwargs.get('contentType', 'image/jpeg') + + # checking values for contentType = application/dicom + if kwargs['contentType'] == 'application/dicom': + for par in INVALID_DICOM: + if par in curparams: + err(par + " is not valid if contentType is application/dicom") + + # Validation finished + return + + # checking values for contentType != application/dicom + for par in INVALID_NONDICOM: + if par in curparams: + err(par + " is valid only if contentType is application/dicom") + + if 'annotation' in curparams: + assert kwargs['annotation'] in ('patient', 'technique') + + if 'windowWidth' in curparams: + assert 'windowCenter' in curparams + + if 'windowCenter' in curparams: + assert 'windowWidth' in curparams + + if 'region' in curparams: + region = kwargs['region'].split(',') + + assert len(region) == 4 + + for val in region: + assert 0.0 <= float(val) <= 1.0 + +class Wado: + """Wado controller""" + + @cherrypy.expose + def index(self, **kwargs): + cherrypy.log(str(kwargs)) + + check_params(kwargs) + + cherrypy.response.headers['Content-Type'] = kwargs['contentType'] + cherrypy.response.headers['Pragma'] = 'cache' + + if kwargs['contentType'] == "application/dicom": + format = "dicom" + else: + # image/png -> png, image/jpeg -> jpeg + format = kwargs['contentType'].replace('image/', '') + + # getting DICOM image from accessdata + image = accessdata.get(studyUID=kwargs['studyUID'], + seriesUID=kwargs['seriesUID'], + objectUID=kwargs['objectUID'], + format=format) + + if kwargs['contentType'] == "application/dicom": + return image.raw() + + if 'windowWidth' in kwargs: + image.brightness(kwargs['windowWidth']) + + if 'windowCenter' in kwargs: + image.contrast(kwargs['windowCenter']) + + if 'region' in kwargs: + left, upper, right, lower = [ + float(val) for val in kwargs['region'].split(",") + ] + # coordinates normalization + width, height = image.img.size + # 1 : width = left : x + image.crop(width * left, height * upper, + width * right, height * lower) + + if 'rows' in kwargs or 'columns' in kwargs: + image.resize(kwargs['rows'], kwargs['columns']) + + return image.dump() + + +if __name__ == "__main__": + cherrypy.config.update({ + #'server.socket_port': 7777, + #'server.thread_pool': 1, + #'environment': testing and 'testing' or 'production', + #'log.access_file': 'access.log', + #'log.error_file': 'errors.log', + #'tools.sessions.on': True, + 'tools.gzip.on': True, + 'tools.caching.on': True + }) + + conf = {} + + app = cherrypy.tree.mount(Wado(), BASEURL, config=conf) + + if testing: + cherrypy.quickstart(app) + else: + cherrypy.engine.start(blocking=False) + try: + WSGIServer(app).run() + finally: + cherrypy.engine.stop() diff --git a/gdcm/Applications/README.txt b/gdcm/Applications/README.txt new file mode 100644 index 0000000..3d59b12 --- /dev/null +++ b/gdcm/Applications/README.txt @@ -0,0 +1,10 @@ +I know I will regret that later, but for now Application are part of GDCM + +Naming convention, pretty much the same used for tiff (tiffinfo and tiffdump), + we have gdcmdump, gdcminfo (should I rename them dcmdump. dcminfo ? + but it will collide with dcmtk...) + +TODO: +I have this file: acc-max.dcm it's pretty much a ACR-NEMA file, +but it contains Modality. It would be great if gdcmconv would handle this file + and generate a file that would make dciodvfy happy diff --git a/gdcm/CMake/CMakeCSharpCompiler.cmake.in b/gdcm/CMake/CMakeCSharpCompiler.cmake.in new file mode 100644 index 0000000..ac5200d --- /dev/null +++ b/gdcm/CMake/CMakeCSharpCompiler.cmake.in @@ -0,0 +1,56 @@ +set(CMAKE_CSharp_COMPILER "@CMAKE_CSharp_COMPILER@") +set(CMAKE_CSharp_COMPILER_ARG1 "@CMAKE_CSharp_COMPILER_ARG1@") +#set(CMAKE_Fortran_COMPILER_ID "@CMAKE_Fortran_COMPILER_ID@") +#set(CMAKE_Fortran_PLATFORM_ID "@CMAKE_Fortran_PLATFORM_ID@") +#set(CMAKE_AR "@CMAKE_AR@") +#set(CMAKE_RANLIB "@CMAKE_RANLIB@") +# Should none on Win32, and 'mono' on unix +set(CMAKE_CSharp_RUNTIME "@CMAKE_CSharp_RUNTIME@") +set(CMAKE_CSharp_ARCHIVE "@CMAKE_CSharp_ARCHIVE@") # gacutil ?? + +set(CMAKE_CSharp_COMPILER_LOADED 1) + +set(CMAKE_CSharp_COMPILER_ENV_VAR "CSC") + +set(CMAKE_CSharp_SOURCE_FILE_EXTENSIONS cs;CS) +set(CMAKE_CSharp_IGNORE_EXTENSIONS h;H;o;O;obj;OBJ;def;DEF;rc;RC) +set(CMAKE_CSharp_LINKER_PREFERENCE 20) +set(CMAKE_STATIC_LIBRARY_PREFIX_CSharp "") +set(CMAKE_STATIC_LIBRARY_SUFFIX_CSharp ".dll") +set(CMAKE_SHARED_LIBRARY_PREFIX_CSharp "") +set(CMAKE_SHARED_LIBRARY_SUFFIX_CSharp ".dll") + +# FIXME ... where should it go +#set(CMAKE_EXECUTABLE_SUFFIX ".exe") + +set(CMAKE_STATIC_LIBRARY_CREATE_CSharp_FLAGS "/target:library") +set(CMAKE_STATIC_LIBRARY_CSharp_FLAGS "/target:library") +#CMAKE_STATIC_LIBRARY_CSharp_FLAGS + +# partial library +set(CMAKE_MODULE_LIBRARY_CREATE_CSharp_FLAGS "/target:module") +set(CMAKE_MODULE_LIBRARY_CSharp_FLAGS "/target:module") + +# static +set(CMAKE_SHARED_LIBRARY_CREATE_CSharp_FLAGS "/target:library") +set(CMAKE_SHARED_LIBRARY_CSharp_FLAGS "/target:library") +#set(CMAKE_SHARED_LIBRARY_LINK_CSharp_FLAGS "-r") +#set(CMAKE_SHARED_LIBRARY_RUNTIME_CSharp_FLAG "-r") +#set(CMAKE_SHARED_LIBRARY_LINK_CSharp_FLAGS "-r") + +# FIXME: CMAKE_LINK_LIBRARY_FILE_FLAG always add a space, so I cannot simply use "/r" because +# I would need to remove the space, but instead use the -r that tolerate a space +#set(CMAKE_LINK_LIBRARY_FILE_FLAG "") +#set(CMAKE_LINK_LIBRARY_FLAG "-r") + +#set(CMAKE_CREATE_WIN32_EXE /target:winexe) +#set(CMAKE_CREATE_CONSOLE_EXE /target:exe) + +#set(CMAKE_LINK_LIBRARY_FLAG "-l") + +#set(CMAKE_EXECUTABLE_RUNTIME_CSharp_FLAG "-foo") + +if(WIN32) +else() + set(CMAKE_CSHARP_INTERPRETER ${MONO_EXECUTABLE}) +endif() diff --git a/gdcm/CMake/CMakeCSharpInformation.cmake b/gdcm/CMake/CMakeCSharpInformation.cmake new file mode 100644 index 0000000..c6dd1b3 --- /dev/null +++ b/gdcm/CMake/CMakeCSharpInformation.cmake @@ -0,0 +1,92 @@ + +# This file sets the basic flags for the CSharp language in CMake. +# It also loads the available platform file for the system-compiler +# if it exists. + +#set(CMAKE_BASE_NAME) +#get_filename_component(CMAKE_BASE_NAME ${CMAKE_CSharp_COMPILER} NAME_WE) +#set(CMAKE_SYSTEM_AND_CSharp_COMPILER_INFO_FILE +# #${CMAKE_ROOT}/Modules/Platform/${CMAKE_SYSTEM_NAME}-${CMAKE_BASE_NAME}.cmake) +# ${CMAKE_ROOT}/Modules/Platform/${CMAKE_SYSTEM_NAME}-${CMAKE_BASE_NAME}.cmake) +#message(${CMAKE_SYSTEM_AND_CSharp_COMPILER_INFO_FILE}) +#include(Platform/${CMAKE_SYSTEM_NAME}-${CMAKE_BASE_NAME} OPTIONAL) + +# This should be included before the _INIT variables are +# used to initialize the cache. Since the rule variables +# have if blocks on them, users can still define them here. +# But, it should still be after the platform file so changes can +# be made to those values. + +if(CMAKE_USER_MAKE_RULES_OVERRIDE) + include(${CMAKE_USER_MAKE_RULES_OVERRIDE}) +endif() + +# Copy from CSharp, ref CXX ??? +if(CMAKE_USER_MAKE_RULES_OVERRIDE_CSHARP) + include(${CMAKE_USER_MAKE_RULES_OVERRIDE_CSHARP}) +endif() + +# +# the target without the suffix +# +# +# +# +# + +# this is a place holder if java needed flags for javac they would go here. +if(NOT CMAKE_CSharp_CREATE_STATIC_LIBRARY) +# if(WIN32) +# set(class_files_mask "*.class") +# else() + set(class_files_mask ".") +# endif() + + set(CMAKE_CSharp_CREATE_STATIC_LIBRARY + #" -cf -C ") + " -out:") +endif() + +# compile a CSharp file into an object file +if(NOT CMAKE_CSharp_COMPILE_OBJECT) + # there is no such thing as intermediate representation (object file) in C#. + # Instead to avoid multiple recompilation of the same src file, I could use the .dll form, since + # one can add src / .dll that same way + + # copy src version + set(CMAKE_CSharp_COMPILE_OBJECT " -E copy ") +endif() + +if(NOT CMAKE_CSharp_LINK_EXECUTABLE) + set(CMAKE_CSharp_LINK_EXECUTABLE + # I could not references 'SOURCES' so I simply copy all source to fake OBJECTS + + # .exe is required otherwise I get: + # Unhandled Exception: System.ArgumentException: Module file name + # 'cmTryCompileExec' must have file extension. + #" -out:.exe ") + " -out:.exe ") +endif() + +if(NOT CMAKE_CSharp_CREATE_SHARED_LIBRARY) + set(CMAKE_CSharp_CREATE_SHARED_LIBRARY + #" /target:library -out:") + " -out:") +endif() + +# set java include flag option and the separator for multiple include paths +#set(CMAKE_INCLUDE_FLAG_CSharp "-classpath ") +#if(WIN32 AND NOT CYGWIN) +# set(CMAKE_INCLUDE_FLAG_SEP_CSharp ";") +#else() +# set(CMAKE_INCLUDE_FLAG_SEP_CSharp ":") +#endif() + +set(CMAKE_CSharp_FLAGS_INIT "$ENV{CSFLAGS} ${CMAKE_CSharp_FLAGS_INIT}") + +# avoid just having a space as the initial value for the cache +if(CMAKE_CSharp_FLAGS_INIT STREQUAL " ") + set(CMAKE_CSharp_FLAGS_INIT) +endif() +set (CMAKE_CSharp_FLAGS "${CMAKE_CSharp_FLAGS_INIT}" CACHE STRING + "Flags used by the compiler during all build types.") diff --git a/gdcm/CMake/CMakeDetermineCSharpCompiler.cmake b/gdcm/CMake/CMakeDetermineCSharpCompiler.cmake new file mode 100644 index 0000000..dd183c6 --- /dev/null +++ b/gdcm/CMake/CMakeDetermineCSharpCompiler.cmake @@ -0,0 +1,67 @@ + +# determine the compiler to use for CSharp programs +# NOTE, a generator may set CMAKE_CSharp_COMPILER before +# loading this file to force a compiler. +# use environment variable CSHARP first if defined by user, next use +# the cmake variable CMAKE_GENERATOR_CSHARP which can be defined by a generator +# as a default compiler +# +# Sets the following variables: +# CMAKE_CSharp_COMPILER +# CMAKE_AR +# CMAKE_RANLIB +# CMAKE_COMPILER_IS_GNUGNAT + +if(NOT CMAKE_CSharp_COMPILER) + # prefer the environment variable CSHARP + if($ENV{CSHARP} MATCHES ".+") + get_filename_component(CMAKE_CSharp_COMPILER_INIT $ENV{CSHARP} PROGRAM PROGRAM_ARGS CMAKE_CSharp_FLAGS_ENV_INIT) + if(CMAKE_CSharp_FLAGS_ENV_INIT) + set(CMAKE_CSharp_COMPILER_ARG1 "${CMAKE_CSharp_FLAGS_ENV_INIT}" CACHE STRING "First argument to CSharp compiler") + endif() + if(NOT EXISTS ${CMAKE_CSharp_COMPILER_INIT}) + message(FATAL_ERROR "Could not find compiler set in environment variable CSHARP:\n$ENV{CSHARP}.") + endif() + endif() + + # next prefer the generator-specified compiler + if(CMAKE_GENERATOR_CSHARP) + if(NOT CMAKE_CSharp_COMPILER_INIT) + set(CMAKE_CSharp_COMPILER_INIT ${CMAKE_GENERATOR_CSHARP}) + endif() + endif() + + # finally list compilers to try + if(CMAKE_CSharp_COMPILER_INIT) + set(CMAKE_CSharp_COMPILER_LIST ${CMAKE_CSharp_COMPILER_INIT}) + else() + # Known compilers: + # mcs/gmcs/smcs # mono + # csc: DotNet + set(CMAKE_CSharp_COMPILER_LIST csc mcs gmcs smcs) + endif() + + # Find the compiler. + find_program(CMAKE_CSharp_COMPILER NAMES ${CMAKE_CSharp_COMPILER_LIST} DOC "CSharp compiler") + if(CMAKE_CSharp_COMPILER_INIT AND NOT CMAKE_CSharp_COMPILER) + set(CMAKE_CSharp_COMPILER "${CMAKE_CSharp_COMPILER_INIT}" CACHE FILEPATH "CSharp compiler" FORCE) + endif() +endif() +mark_as_advanced(CMAKE_CSharp_COMPILER) + +get_filename_component(COMPILER_LOCATION "${CMAKE_CSharp_COMPILER}" + PATH) + + +#include(CMakeFindBinUtils) + +# configure variables set in this file for fast reload later on +configure_file( + #${CMAKE_ROOT}/Modules/CMakeCSharpCompiler.cmake.in + ${CMAKE_MODULE_PATH}/CMakeCSharpCompiler.cmake.in + # "${CMAKE_PLATFORM_ROOT_BIN}/CMakeCSharpCompiler.cmake" + ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeCSharpCompiler.cmake + @ONLY + ) + +set(CMAKE_CSharp_COMPILER_ENV_VAR "CSC") diff --git a/gdcm/CMake/CMakeTestCSharpCompiler.cmake b/gdcm/CMake/CMakeTestCSharpCompiler.cmake new file mode 100644 index 0000000..b90e52e --- /dev/null +++ b/gdcm/CMake/CMakeTestCSharpCompiler.cmake @@ -0,0 +1,51 @@ + +# This file is used by EnableLanguage in cmGlobalGenerator to +# determine that that selected CShapr compiler can actually compile +# and link the most basic of programs. If not, a fatal error +# is set and cmake stops processing commands and will not generate +# any makefiles or projects. +if(NOT CMAKE_CSharp_COMPILER_WORKS) + message(STATUS "Check for working CSharp compiler: ${CMAKE_CSharp_COMPILER}") + file(WRITE ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/testCSharpCompiler.cs + "class Dummy {\n" + "static void Main() {\n" + "}\n}\n") + try_compile(CMAKE_CSharp_COMPILER_WORKS ${CMAKE_BINARY_DIR} + ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/testCSharpCompiler.cs + OUTPUT_VARIABLE OUTPUT) + set(C_TEST_WAS_RUN 1) +endif() + +if(NOT CMAKE_CSharp_COMPILER_WORKS) + message(STATUS "Check for working CSharp compiler: ${CMAKE_CSharp_COMPILER} -- broken") + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log + "Determining if the CSharp compiler works failed with " + "the following output:\n${OUTPUT}\n\n") + message(FATAL_ERROR "The CSharp compiler \"${CMAKE_CSharp_COMPILER}\" " + "is not able to compile a simple test program.\nIt fails " + "with the following output:\n ${OUTPUT}\n\n" + "CMake will not be able to correctly generate this project.") +else() + if(C_TEST_WAS_RUN) + message(STATUS "Check for working CSharp compiler: ${CMAKE_CSharp_COMPILER} -- works") + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log + "Determining if the CSharp compiler works passed with " + "the following output:\n${OUTPUT}\n\n") + endif() + set(CMAKE_CSharp_COMPILER_WORKS 1 CACHE INTERNAL "") + + if(CMAKE_CSharp_COMPILER_FORCED) + # The compiler configuration was forced by the user. + # Assume the user has configured all compiler information. + else() + # Try to identify the ABI and configure it into CMakeCSharpCompiler.cmake + include(${CMAKE_ROOT}/Modules/CMakeDetermineCompilerABI.cmake) + CMAKE_DETERMINE_COMPILER_ABI(C ${CMAKE_ROOT}/Modules/CMakeCSharpCompilerABI.c) + configure_file( + #${CMAKE_ROOT}/Modules/CMakeCSharpCompiler.cmake.in + ${CMAKE_MODULE_PATH}/CMakeCSharpCompiler.cmake.in + ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeCSharpCompiler.cmake + @ONLY + ) + endif() +endif() diff --git a/gdcm/CMake/COPYING-CMAKE-SCRIPTS b/gdcm/CMake/COPYING-CMAKE-SCRIPTS new file mode 100644 index 0000000..53b6b71 --- /dev/null +++ b/gdcm/CMake/COPYING-CMAKE-SCRIPTS @@ -0,0 +1,22 @@ +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/gdcm/CMake/CTestCustom.ctest.in b/gdcm/CMake/CTestCustom.ctest.in new file mode 100644 index 0000000..604cd66 --- /dev/null +++ b/gdcm/CMake/CTestCustom.ctest.in @@ -0,0 +1,46 @@ +# same as boost settings: +#SET(CTEST_CUSTOM_MAXIMUM_NUMBER_OF_ERRORS 1000) +#SET(CTEST_CUSTOM_MAXIMUM_NUMBER_OF_WARNINGS 1000) +##SET(CTEST_CUSTOM_MAXIMUM_PASSED_TEST_OUTPUT_SIZE 1000000) +#SET(CTEST_CUSTOM_MAXIMUM_PASSED_TEST_OUTPUT_SIZE 49152) +#SET(CTEST_CUSTOM_MAXIMUM_FAILED_TEST_OUTPUT_SIZE 49152) + +SET(CTEST_CUSTOM_WARNING_EXCEPTION + ${CTEST_CUSTOM_WARNING_EXCEPTION} + "Utilities" + "Utilities.gdcmopenjpeg.*warning C4101: '.*' : unreferenced local variable" + "gdcm.*.cxx.obj : warning LNK4221: no public symbols found; archive member will be inaccessible" + "/usr/bin/ranlib: for architecture: .* file: .* has no symbols" + "gdcmcharls" + "gdcmexpat" + "warning CS0114:" + "warning CS0108:" + "warning CS0109:" + "warning CS1591:" + "gdcmJAVA_wrap.cxx" # swig generated + "gdcmswigPYTHON_wrap.cxx" # swig generated + "gdcmCSHARP_wrap.cxx" # swig generated + "gdcmPythonFilter.cxx" # need some love + "puff.c" # zlib code + "/usr/bin/ld: warning: libjpeg.so.62" # needed by .*libvtkIO.so, may conflict with libjpeg.so.8 + "/usr/bin/ld: warning: libavcodec.so.52" # needed by .*libvtkIO.so, may conflict with libavcodec.so.53 + "/usr/bin/ld: warning: libavformat.so.52" #needed by libvtkIO.so, may conflict with libavformat.so.53 + "/usr/bin/ld: warning: libavutil.so.49" # needed by .*libvtkIO.so, may conflict with libavutil.so.51 + "/usr/bin/ld: warning: libswscale.so.0" # needed by .*libvtkIO.so, may conflict with libswscale.so.2 + ) + +# Disable dynamic analysis on some tests: +SET(CTEST_CUSTOM_MEMCHECK_IGNORE + ${CTEST_CUSTOM_MEMCHECK_IGNORE} + "Python" + "DCMDUMP" + "DCDUMP" + "DCMDJPEG" + "DCMDRLE" + "vtk" + ) + +# ==3201== 8 bytes in 1 blocks are still reachable in loss record 2 of 8 +# ==3201== at 0x4C20809: operator new(unsigned long) (vg_replace_malloc.c:230) +# ==3201== by 0x405E28F: DJDecoderRegistration::registerCodecs(E_DecompressionColorSpaceConversion, E_UIDCreation, E_PlanarConfiguration, bool) (in /usr/lib/libdcmjpeg.so.1.0.0) +# ==3201== by 0x402AB1: (within /usr/bin/dcmdjpeg) diff --git a/gdcm/CMake/ExportConfiguration/CMakeLists.txt b/gdcm/CMake/ExportConfiguration/CMakeLists.txt new file mode 100644 index 0000000..59d721c --- /dev/null +++ b/gdcm/CMake/ExportConfiguration/CMakeLists.txt @@ -0,0 +1,133 @@ +### Build the configuration file for external projects using GDCM and cmake: +configure_file( GDCMConfig.cmake.in + ${GDCM_BINARY_DIR}/GDCMConfig.cmake + @ONLY +) +install( FILES ${GDCM_BINARY_DIR}/GDCMConfig.cmake + DESTINATION ${GDCM_INSTALL_PACKAGE_DIR} COMPONENT Headers +) +configure_file( GDCMConfigVersion.cmake.in + ${GDCM_BINARY_DIR}/GDCMConfigVersion.cmake + @ONLY +) +install( FILES ${GDCM_BINARY_DIR}/GDCMConfigVersion.cmake + DESTINATION ${GDCM_INSTALL_PACKAGE_DIR} COMPONENT Headers +) +configure_file( UseGDCM.cmake.in + ${GDCM_BINARY_DIR}/UseGDCM.cmake + @ONLY +) +install( FILES ${GDCM_BINARY_DIR}/UseGDCM.cmake + DESTINATION ${GDCM_INSTALL_PACKAGE_DIR} COMPONENT Headers +) + +# install all targets referenced as ${GDCM_TARGETS_NAME} +if(GDCM_STANDALONE) + install(EXPORT ${GDCM_TARGETS_NAME} DESTINATION ${GDCM_INSTALL_PACKAGE_DIR} COMPONENT Headers) +endif() + +# [Prevent viral CMake dep] +# See the following ref, which explain this mess. +# http://cmake.org/Bug/view.php?id=9822 +# 0009822: Please expose: cmGlobalGenerator::GetExportSet at cmake level + +# I cannot retrieve the lists of exported targets, so read them from the file instead + +#set(gdcmtarget_cmake +# "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/Export/${GDCM_INSTALL_PACKAGE_DIR}/${GDCM_TARGETS_NAME}.cmake") + +#configure_file( +# ${GDCM_BINARY_DIR}/CMakeCache.txt +# ${CMAKE_CURRENT_BINARY_DIR}/gdcmtarget_cmake.dep +#COPYONLY +#) +# CMake Error at CMake/ExportConfiguration/CMakeLists.txt:59 (export): +# export given target "gdcmopenjpeg" which is not built by this project. +#add_custom_command( +# OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/gdcmtarget_cmake.dep +# COMMAND ${CMAKE_COMMAND} -E copy_if_different ${GDCM_BINARY_DIR}/CMakeCache.txt ${CMAKE_CURRENT_BINARY_DIR}/gdcmtarget_cmake.dep +# COMMAND ${CMAKE_COMMAND} -E remove ${gdcmtarget_cmake} +# COMMAND ${CMAKE_COMMAND} -E remove ${GDCM_BINARY_DIR}/GDCMExports.cmake +# #DEPENDS ${GDCM_BINARY_DIR}/CMakeCache.txt +# #DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/gdcmtarget_cmake.dep +# DEPENDS ${gdcmtarget_cmake} +#) +#add_custom_target(clean_t ALL +# COMMAND echo "Execute" +# #COMMAND ${CMAKE_COMMAND} -E remove ${gdcmtarget_cmake} +# COMMAND ${CMAKE_COMMAND} -E remove ${GDCM_BINARY_DIR}/GDCMExports.cmake +# DEPENDS ${gdcmtarget_cmake} ${GDCM_BINARY_DIR}/GDCMExports.cmake +# COMMENT "Crazy" +#) + + +#set( targets ) +##file(REMOVE ${gdcmtarget_cmake}) +#if(EXISTS ${gdcmtarget_cmake}) +# #message( "reading: ${gdcmtarget_cmake}" ) +# file(READ ${gdcmtarget_cmake} ENT) +# string(REGEX REPLACE "\r?\n" ";" ENT "${ENT}") +# foreach(line ${ENT}) +# string(REGEX MATCH "ADD_LIBRARY\\(.*SHARED IMPORTED\\)" m ${line}) +# if( m ) +# string(REGEX REPLACE "ADD_LIBRARY\\((.*) SHARED IMPORTED\\)" "\\1" out ${m}) +# list(APPEND targets ${out}) +# endif() +# endforeach() +#endif() +# +#set( exports ) +#set(gdcmexport_cmake ${GDCM_BINARY_DIR}/GDCMExports.cmake) +#if(EXISTS ${gdcmexport_cmake}) +# file(READ ${gdcmexport_cmake} ENT) +# string(REGEX REPLACE "\r?\n" ";" ENT "${ENT}") +# foreach(line ${ENT}) +# string(REGEX MATCH "ADD_LIBRARY\\(.*SHARED IMPORTED\\)" m ${line}) +# if( m ) +# string(REGEX REPLACE "ADD_LIBRARY\\((.*) SHARED IMPORTED\\)" "\\1" out ${m}) +# list(APPEND exports ${out}) +# endif() +# endforeach() +#endif() + +#list(LENGTH targets targets_len) +#list(LENGTH exports exports_len) +#if( ${targets_len} EQUAL ${exports_len} ) +# message("equal") +#else() +# message("diff") +# message( "${targets}" ) +# message( "${exports}" ) +##set(targets ${exports}) +## execute_process( +## COMMAND ${CMAKE_COMMAND} -E remove ${gdcmtarget_cmake} +## ) +#endif() + +set(targets + gdcmCommon + gdcmDICT + gdcmDSED + gdcmIOD + gdcmMSFF + gdcmMEXD + gdcmjpeg8 + gdcmjpeg12 + gdcmjpeg16 + gdcmexpat + gdcmopenjpeg + gdcmcharls + gdcmmd5 + gdcmzlib + gdcmuuid + socketxx + vtkgdcm + php_vtkgdcm + vtkgdcmsharpglue + ) +file(WRITE ${GDCM_BINARY_DIR}/GDCMExports.cmake "") +foreach(target ${targets}) + if(TARGET ${target}) + export(TARGETS ${target} FILE ${GDCM_BINARY_DIR}/GDCMExports.cmake APPEND) + endif() +endforeach() diff --git a/gdcm/CMake/ExportConfiguration/GDCMConfig.cmake.in b/gdcm/CMake/ExportConfiguration/GDCMConfig.cmake.in new file mode 100644 index 0000000..c5e2598 --- /dev/null +++ b/gdcm/CMake/ExportConfiguration/GDCMConfig.cmake.in @@ -0,0 +1,55 @@ +#----------------------------------------------------------------------------- +# +# GDCMConfig.cmake - CMake configuration file for external projects. +# +# This file is configured by GDCM and used by the UseGDCM.cmake +# module to load GDCM's settings for an external project. +@GDCM_CONFIG_INSTALL_ONLY@ +# The GDCM version number. +set(GDCM_MAJOR_VERSION "@GDCM_MAJOR_VERSION@") +set(GDCM_MINOR_VERSION "@GDCM_MINOR_VERSION@") +set(GDCM_BUILD_VERSION "@GDCM_BUILD_VERSION@") + +# The libraries. +set(GDCM_LIBRARIES "@GDCM_LIBRARIES@") + +# The CMake macros dir. +set(GDCM_CMAKE_DIR "@GDCM_CMAKE_DIR_CONFIG@") + +# The configuration options. +set(GDCM_BUILD_SHARED_LIBS "@GDCM_BUILD_SHARED_LIBS@") +set(GDCM_USE_VTK "@GDCM_USE_VTK@") + +# The "use" file. +set(GDCM_USE_FILE "@GDCM_USE_FILE_CONFIG@") + +# The VTK options. +if(GDCM_USE_VTK) + set(GDCM_VTK_DIR "@GDCM_VTK_DIR_CONFIG@") +endif() + +get_filename_component(SELF_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) +if(EXISTS ${SELF_DIR}/GDCMTargets.cmake) + # This is an install tree + include(${SELF_DIR}/GDCMTargets.cmake) + get_filename_component(GDCM_INCLUDE_ROOT "${SELF_DIR}/../../@GDCM_INSTALL_INCLUDE_DIR@" ABSOLUTE) + set(GDCM_INCLUDE_DIRS ${GDCM_INCLUDE_ROOT}) + get_filename_component(GDCM_LIB_ROOT "${SELF_DIR}/../../@GDCM_INSTALL_LIB_DIR@" ABSOLUTE) + set(GDCM_LIBRARY_DIRS ${GDCM_LIB_ROOT}) +else() + if(EXISTS ${SELF_DIR}/GDCMExports.cmake) + # This is a build tree + set( GDCM_INCLUDE_DIRS "@GDCM_INCLUDE_PATH@") + set(GDCM_LIBRARY_DIRS "@GDCM_LIBRARY_DIR@") + + include(${SELF_DIR}/GDCMExports.cmake) + + else() + message(FATAL_ERROR "ooops") + endif() +endif() + +set(GDCM_USE_FILE ${SELF_DIR}/UseGDCM.cmake) + +# Backward compatible part: +set(GDCM_FOUND TRUE) diff --git a/gdcm/CMake/ExportConfiguration/GDCMConfigVersion.cmake.in b/gdcm/CMake/ExportConfiguration/GDCMConfigVersion.cmake.in new file mode 100644 index 0000000..65ffbed --- /dev/null +++ b/gdcm/CMake/ExportConfiguration/GDCMConfigVersion.cmake.in @@ -0,0 +1,21 @@ +# Test config file. +# Version number +set( GDCM_MAJOR_VERSION "@GDCM_MAJOR_VERSION@") +set( GDCM_MINOR_VERSION "@GDCM_MINOR_VERSION@") +set( GDCM_BUILD_VERSION "@GDCM_BUILD_VERSION@") +set( GDCM_VERSION "@GDCM_VERSION@") + +set(PACKAGE_VERSION "${GDCM_VERSION}") +if("${PACKAGE_FIND_VERSION}" STREQUAL "") + # User did not request any particular version + set(PACKAGE_VERSION_COMPATIBLE 1) +elseif("${PACKAGE_FIND_VERSION}" VERSION_EQUAL "${PACKAGE_VERSION}") + # User did request exactly this version + set(PACKAGE_VERSION_COMPATIBLE 1) + set(PACKAGE_VERSION_EXACT 1) +elseif("${PACKAGE_FIND_VERSION}" VERSION_LESS "${PACKAGE_VERSION}") + # User requested an older version + set(PACKAGE_VERSION_COMPATIBLE 1) +else() + message("REQUESTING: [${PACKAGE_FIND_VERSION}] but found: ${PACKAGE_VERSION}") +endif() diff --git a/gdcm/CMake/ExportConfiguration/UseGDCM.cmake.in b/gdcm/CMake/ExportConfiguration/UseGDCM.cmake.in new file mode 100644 index 0000000..13e7b98 --- /dev/null +++ b/gdcm/CMake/ExportConfiguration/UseGDCM.cmake.in @@ -0,0 +1,31 @@ +# +# This module is provided as GDCM_USE_FILE by GDCMConfig.cmake. +# It can be INCLUDEd in a project to load the needed compiler and linker +# settings to use GDCM: +# find_package(GDCM REQUIRED) +# include(${GDCM_USE_FILE}) + +if(NOT GDCM_USE_FILE_INCLUDED) + set(GDCM_USE_FILE_INCLUDED 1) + + # Add include directories needed to use GDCM. + include_directories(${GDCM_INCLUDE_DIRS}) + + # Add link directories needed to use GDCM. + link_directories(${GDCM_LIBRARY_DIRS}) + + # Add cmake module path. + set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${GDCM_CMAKE_DIR}") + + # Use VTK. + if(GDCM_USE_VTK) + set(VTK_DIR ${GDCM_VTK_DIR}) + find_package(VTK) + if(VTK_FOUND) + include(${VTK_USE_FILE}) + else() + message("VTK not found in GDCM_VTK_DIR=\"${GDCM_VTK_DIR}\".") + endif() + endif() + +endif() diff --git a/gdcm/CMake/FindACTIVIZ.cmake b/gdcm/CMake/FindACTIVIZ.cmake new file mode 100644 index 0000000..4787fac --- /dev/null +++ b/gdcm/CMake/FindACTIVIZ.cmake @@ -0,0 +1,51 @@ +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + +# Testing on Linux with: +# ActiViz.NET-5.4.0.455-Linux-x86_64-Personal + +# Note: +# IMHO I cannot use FIND_LIBRARY on Linux because of the .dll extension... +# instead switch to FIND_FILE + +find_file(ACTIVIZ_KITWARE_VTK_LIBRARY + NAMES Kitware.VTK.dll + PATHS /usr/lib /usr/local/lib /usr/lib/cli/activiz-cil /usr/lib/cli/ActiViz.NET + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Kitware\\ActiVizDotNet 5.2.1]/bin" + $ENV{ACTIVIZ_ROOT}/bin + ) + +find_file(ACTIVIZ_KITWARE_MUMMY_RUNTIME_LIBRARY + NAMES Kitware.mummy.Runtime.dll + PATHS /usr/lib /usr/local/lib /usr/lib/cli/activiz-cil /usr/lib/cli/Kitware.mummy.Runtime-1.0 + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Kitware\\ActiVizDotNet 5.2.1]/bin" + $ENV{ACTIVIZ_ROOT}/bin + ) + +if (ACTIVIZ_KITWARE_VTK_LIBRARY AND ACTIVIZ_KITWARE_MUMMY_RUNTIME_LIBRARY) + set(ACTIVIZ_LIBRARIES ${ACTIVIZ_KITWARE_MUMMY_RUNTIME_LIBRARY} ${ACTIVIZ_KITWARE_VTK_LIBRARY}) + set(ACTIVIZ_FOUND "YES") +else() + set(ACTIVIZ_FOUND "NO") +endif () + + +if (ACTIVIZ_FOUND) + if (NOT ACTIVIZ_FIND_QUIETLY) + message(STATUS "Found ACTIVIZ: ${ACTIVIZ_LIBRARIES}") + endif () +else () + if (ACTIVIZ_FIND_REQUIRED) + message(FATAL_ERROR "Could not find ACTIVIZ library") + endif () +endif () + +mark_as_advanced( + ACTIVIZ_KITWARE_VTK_LIBRARY + ACTIVIZ_KITWARE_MUMMY_RUNTIME_LIBRARY + ) diff --git a/gdcm/CMake/FindCSharp.cmake b/gdcm/CMake/FindCSharp.cmake new file mode 100644 index 0000000..a612166 --- /dev/null +++ b/gdcm/CMake/FindCSharp.cmake @@ -0,0 +1,24 @@ +# A C# Module for cmake +# +# TODO: +# Should I inspect the ENV{CSC} var first ? +# +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + +if(WIN32) + find_package(DotNETFrameworkSDK) +else() + #TODO handle CSharp_FIND_QUIETLY + #TODO handle CSharp_FIND_REQUIRED + find_package(MONO) +endif() + +# http://public.kitware.com/Bug/view.php?id=7757 +get_filename_component(current_list_path ${CMAKE_CURRENT_LIST_FILE} PATH) +set(CSharp_USE_FILE ${current_list_path}/UseCSharp.cmake) diff --git a/gdcm/CMake/FindCharLS.cmake b/gdcm/CMake/FindCharLS.cmake new file mode 100644 index 0000000..b0e8df5 --- /dev/null +++ b/gdcm/CMake/FindCharLS.cmake @@ -0,0 +1,40 @@ +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + +find_path(CHARLS_INCLUDE_DIR CharLS/interface.h +/usr/local/include +/usr/include +) + +find_library(CHARLS_LIBRARY + NAMES CharLS + PATHS /usr/lib /usr/local/lib + ) + +if (CHARLS_LIBRARY AND CHARLS_INCLUDE_DIR) + set(CHARLS_LIBRARIES ${CHARLS_LIBRARY}) + set(CHARLS_INCLUDE_DIRS ${CHARLS_INCLUDE_DIR}) + set(CHARLS_FOUND "YES") +else () + set(CHARLS_FOUND "NO") +endif () + +if (CHARLS_FOUND) + if (NOT CHARLS_FIND_QUIETLY) + message(STATUS "Found CHARLS: ${CHARLS_LIBRARIES}") + endif () +else () + if (CHARLS_FIND_REQUIRED) + message(FATAL_ERROR "Could not find CHARLS library") + endif () +endif () + +mark_as_advanced( + CHARLS_LIBRARY + CHARLS_INCLUDE_DIR + ) diff --git a/gdcm/CMake/FindDCMTK.cmake b/gdcm/CMake/FindDCMTK.cmake new file mode 100644 index 0000000..d08cde5 --- /dev/null +++ b/gdcm/CMake/FindDCMTK.cmake @@ -0,0 +1,152 @@ +# - find DCMTK libraries and applications +# + +# DCMTK_INCLUDE_DIRS - Directories to include to use DCMTK +# DCMTK_LIBRARIES - Files to link against to use DCMTK +# DCMTK_FOUND - If false, don't try to use DCMTK +# DCMTK_DIR - (optional) Source directory for DCMTK +# +# DCMTK_DIR can be used to make it simpler to find the various include +# directories and compiled libraries if you've just compiled it in the +# source tree. Just set it to the root of the tree where you extracted +# the source (default to /usr/include/dcmtk/) + +#============================================================================= +# Copyright 2004-2009 Kitware, Inc. +# Copyright 2009-2011 Mathieu Malaterre +# Copyright 2010 Thomas Sondergaard +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distributed this file outside of CMake, substitute the full +# License text for the above reference.) + +# +# Written for VXL by Amitha Perera. +# Upgraded for GDCM by Mathieu Malaterre. +# Modified for EasyViz by Thomas Sondergaard. +# + +if(NOT DCMTK_FOUND AND NOT DCMTK_DIR) + set(DCMTK_DIR + "/usr/include/dcmtk/" + CACHE + PATH + "Root of DCMTK source tree (optional).") + mark_as_advanced(DCMTK_DIR) +endif() + + +foreach(lib + dcmdata + dcmimage + dcmimgle + dcmjpeg + dcmnet + dcmpstat + dcmqrdb + dcmsign + dcmsr + dcmtls + ijg12 + ijg16 + ijg8 + ofstd) + + find_library(DCMTK_${lib}_LIBRARY + ${lib} + PATHS + ${DCMTK_DIR}/${lib}/libsrc + ${DCMTK_DIR}/${lib}/libsrc/Release + ${DCMTK_DIR}/${lib}/libsrc/Debug + ${DCMTK_DIR}/${lib}/Release + ${DCMTK_DIR}/${lib}/Debug + ${DCMTK_DIR}/lib) + + mark_as_advanced(DCMTK_${lib}_LIBRARY) + + if(DCMTK_${lib}_LIBRARY) + list(APPEND DCMTK_LIBRARIES ${DCMTK_${lib}_LIBRARY}) + endif() + +endforeach() + + +set(DCMTK_config_TEST_HEADER osconfig.h) +set(DCMTK_dcmdata_TEST_HEADER dctypes.h) +set(DCMTK_dcmimage_TEST_HEADER dicoimg.h) +set(DCMTK_dcmimgle_TEST_HEADER dcmimage.h) +set(DCMTK_dcmjpeg_TEST_HEADER djdecode.h) +set(DCMTK_dcmnet_TEST_HEADER assoc.h) +set(DCMTK_dcmpstat_TEST_HEADER dcmpstat.h) +set(DCMTK_dcmqrdb_TEST_HEADER dcmqrdba.h) +set(DCMTK_dcmsign_TEST_HEADER sicert.h) +set(DCMTK_dcmsr_TEST_HEADER dsrtree.h) +set(DCMTK_dcmtls_TEST_HEADER tlslayer.h) +set(DCMTK_ofstd_TEST_HEADER ofstdinc.h) + +foreach(dir + config + dcmdata + dcmimage + dcmimgle + dcmjpeg + dcmnet + dcmpstat + dcmqrdb + dcmsign + dcmsr + dcmtls + ofstd) + find_path(DCMTK_${dir}_INCLUDE_DIR + ${DCMTK_${dir}_TEST_HEADER} + PATHS + ${DCMTK_DIR}/${dir}/include + ${DCMTK_DIR}/${dir} + ${DCMTK_DIR}/include/${dir}) + + mark_as_advanced(DCMTK_${dir}_INCLUDE_DIR) + + if(DCMTK_${dir}_INCLUDE_DIR) + list(APPEND + DCMTK_INCLUDE_DIRS + ${DCMTK_${dir}_INCLUDE_DIR}) + endif() +endforeach() + +if(WIN32) + list(APPEND DCMTK_LIBRARIES netapi32 wsock32) +endif() + +if(DCMTK_ofstd_INCLUDE_DIR) + get_filename_component(DCMTK_dcmtk_INCLUDE_DIR + ${DCMTK_ofstd_INCLUDE_DIR} + PATH + CACHE) + list(APPEND DCMTK_INCLUDE_DIRS ${DCMTK_dcmtk_INCLUDE_DIR}) + mark_as_advanced(DCMTK_dcmtk_INCLUDE_DIR) +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(DCMTK DEFAULT_MSG + DCMTK_config_INCLUDE_DIR + DCMTK_ofstd_INCLUDE_DIR + DCMTK_ofstd_LIBRARY + DCMTK_dcmdata_INCLUDE_DIR + DCMTK_dcmdata_LIBRARY + DCMTK_dcmimgle_INCLUDE_DIR + DCMTK_dcmimgle_LIBRARY) + +# Compatibility: This variable is deprecated +set(DCMTK_INCLUDE_DIR ${DCMTK_INCLUDE_DIRS}) + +foreach(executable dcmdump dcmdjpeg dcmdrle dcmdjpls storescu echoscu movescu findscu dcmqrscp) + string(TOUPPER ${executable} EXECUTABLE) + find_program(DCMTK_${EXECUTABLE}_EXECUTABLE ${executable} ${DCMTK_DIR}/bin) + mark_as_advanced(DCMTK_${EXECUTABLE}_EXECUTABLE) +endforeach() diff --git a/gdcm/CMake/FindDICOM3TOOLS.cmake b/gdcm/CMake/FindDICOM3TOOLS.cmake new file mode 100644 index 0000000..c179b47 --- /dev/null +++ b/gdcm/CMake/FindDICOM3TOOLS.cmake @@ -0,0 +1,61 @@ +# +# this module looks for Dicom3Tools, well right now only dciodvfy, dcuncat, +# dcmulti +# +# DCIODVFY_EXECUTABLE - the full path to the dciodvfy +# DCIODVFY_FOUND - If false, don't attempt to use dciodvfy + +# dicom3tools are funny to build you'll need imake +# Anyway in order not to pollute your system, you can do an in-source build and +# install which should be clean enough: +# +# ./Configure +# imake -I./config -DInstallInTopDir +# make World +# make install (will copy in ./bin) +# +# then all you need to do is export an env var DICOM3TOOLS pointing to that dir +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + +find_program(DCIODVFY_EXECUTABLE + dciodvfy + "/tmp/" + "$ENV{DICOM3TOOLS}/bin" + "$ENV{DICOM3TOOLS}/bin/1.2.6.8." + ) + +find_program(DCDUMP_EXECUTABLE + dcdump + "/tmp/" + "$ENV{DICOM3TOOLS}/bin" + "$ENV{DICOM3TOOLS}/bin/1.2.6.8." + ) + +find_program(DCUNCAT_EXECUTABLE + dcuncat + "$ENV{DICOM3TOOLS}/bin" + ) + +find_program(DCMULTI_EXECUTABLE + dcmulti + "$ENV{DICOM3TOOLS}/bin" + ) + +mark_as_advanced( + DCIODVFY_EXECUTABLE + DCDUMP_EXECUTABLE + DCUNCAT_EXECUTABLE + DCMULTI_EXECUTABLE + ) + +#if (NOT DCIODVFY_EXECUTABLE) +# set(DCIODVFY_FOUND "NO") +#else () +# set(DCIODVFY_FOUND "YES") +#endif () diff --git a/gdcm/CMake/FindDotNETFrameworkSDK.cmake b/gdcm/CMake/FindDotNETFrameworkSDK.cmake new file mode 100644 index 0000000..2b1de6f --- /dev/null +++ b/gdcm/CMake/FindDotNETFrameworkSDK.cmake @@ -0,0 +1,52 @@ +# - Find .NET Software Development Kit +# This module finds an installed .NET Software Development Kit. It sets the following variables: +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + +# Note: +# .NET Framework SDK Version 1.1 +# http://www.microsoft.com/downloads/details.aspx?FamilyID=9b3a2ca6-3647-4070-9f41-a333c6b9181d&displaylang=en +# .NET Framework 2.0 Software Development Kit (SDK) (x86) +# http://www.microsoft.com/downloads/details.aspx?FamilyID=fe6f2099-b7b4-4f47-a244-c96d69c35dec&displaylang=en +# Microsoft .NET Framework 3.5 +# http://www.microsoft.com/downloads/details.aspx?familyid=333325FD-AE52-4E35-B531-508D977D32A6&displaylang=en + +# Comparison Between C++ and C# +# http://msdn.microsoft.com/en-us/library/yyaad03b(VS.71).aspx + +# http://www.akadia.com/services/dotnet_assemblies.html + +# Visual C# Language Concepts +# Building from the Command Line +# http://msdn.microsoft.com/en-us/library/1700bbwd(VS.71).aspx + +# FIXME, path are hardcoded. +# http://www.walkernews.net/2007/07/30/how-to-verify-dot-net-framework-version/ + +find_program(CSC_v1_EXECUTABLE csc + $ENV{windir}/Microsoft.NET/Framework/v1.1.4322/ +) +find_program(CSC_v2_EXECUTABLE csc + $ENV{windir}/Microsoft.NET/Framework/v2.0.50727/ +) +find_program(CSC_v3_EXECUTABLE csc + $ENV{windir}/Microsoft.NET/Framework/v3.5/ +) +find_program(CSC_v4_EXECUTABLE csc + $ENV{windir}/Microsoft.NET/Framework/v4.0.30319/ +) + +get_filename_component(current_list_path ${CMAKE_CURRENT_LIST_FILE} PATH) +set(DotNETFrameworkSDK_USE_FILE ${current_list_path}/UseDotNETFrameworkSDK.cmake) + +mark_as_advanced( + CSC_v1_EXECUTABLE + CSC_v2_EXECUTABLE + CSC_v3_EXECUTABLE + CSC_v4_EXECUTABLE +) diff --git a/gdcm/CMake/FindJNI.cmake b/gdcm/CMake/FindJNI.cmake new file mode 100644 index 0000000..5f5b62b --- /dev/null +++ b/gdcm/CMake/FindJNI.cmake @@ -0,0 +1,83 @@ +# Copyright (c) 2006-2011 Mathieu Malaterre +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +# Make sure to not use FindJNI anymore and prefer FindJavaProperties +find_package(JavaProperties REQUIRED) +find_path(JAVA_INCLUDE_PATH jni.h + ${JavaProp_JAVA_HOME}/../include +) + +string(TOLOWER ${JavaProp_OS_NAME} include_os_name) # Linux -> linux +set(JAVA_JNI_MD_INCLUDE_DIRECTORIES + ${JAVA_INCLUDE_PATH}/${include_os_name} + ${JAVA_INCLUDE_PATH}/win32 # win32 + ${JAVA_INCLUDE_PATH}/linux # kFreeBSD + ${JAVA_INCLUDE_PATH}/solaris # SunOS + ) +find_path(JAVA_INCLUDE_PATH2 jni_md.h + ${JAVA_JNI_MD_INCLUDE_DIRECTORIES} + ) + +find_path(JAVA_AWT_INCLUDE_PATH jawt.h + ${JAVA_INCLUDE_PATH} +) + +set(JAVA_AWT_LIBRARY_DIRECTORIES + ${JavaProp_SUN_BOOT_LIBRARY_PATH} # works for linux + ${JavaProp_JAVA_HOME}/../lib # works for win32 + ) + +foreach(dir ${JAVA_AWT_LIBRARY_DIRECTORIES}) + set(JAVA_JVM_LIBRARY_DIRECTORIES + ${JAVA_JVM_LIBRARY_DIRECTORIES} + "${dir}" + "${dir}/client" + "${dir}/server" + ) +endforeach() + +find_library(JAVA_AWT_LIBRARY NAMES jawt + PATHS ${JAVA_AWT_LIBRARY_DIRECTORIES} + ) + +find_library(JAVA_JVM_LIBRARY NAMES jvm JavaVM + PATHS ${JAVA_JVM_LIBRARY_DIRECTORIES} + ) + +# on linux I get this annoying error: +# Exception in thread "main" java.lang.UnsatisfiedLinkError: libvtkgdcmJava.so: +# libmawt.so: cannot open shared object file: No such file or directory + +# let's find this lib here then +if(UNIX) + find_library(JAVA_MAWT_LIBRARY NAMES mawt + # there is one also in headless but it does not work... + PATHS ${JavaProp_SUN_BOOT_LIBRARY_PATH}/xawt + ) +endif() + +FIND_PACKAGE_HANDLE_STANDARD_ARGS(JNI DEFAULT_MSG JAVA_AWT_LIBRARY JAVA_JVM_LIBRARY + JAVA_INCLUDE_PATH JAVA_INCLUDE_PATH2 JAVA_AWT_INCLUDE_PATH) + +mark_as_advanced( + JAVA_AWT_LIBRARY + JAVA_MAWT_LIBRARY + JAVA_JVM_LIBRARY + JAVA_AWT_INCLUDE_PATH + JAVA_INCLUDE_PATH + JAVA_INCLUDE_PATH2 +) + +set(JNI_LIBRARIES + ${JAVA_AWT_LIBRARY} + ${JAVA_JVM_LIBRARY} +) + +set(JNI_INCLUDE_DIRS + ${JAVA_INCLUDE_PATH} + ${JAVA_INCLUDE_PATH2} + ${JAVA_AWT_INCLUDE_PATH} +) diff --git a/gdcm/CMake/FindJSON.cmake b/gdcm/CMake/FindJSON.cmake new file mode 100644 index 0000000..955564f --- /dev/null +++ b/gdcm/CMake/FindJSON.cmake @@ -0,0 +1,39 @@ +# - Find json +# Find the native JSON headers and libraries. +# This module defines +# JSON_INCLUDE_DIRS - the json include directory +# JSON_LIBRARIES - the libraries needed to use json +# JSON_FOUND - system has the json library +# +# Copyright (c) 2013 Mathieu Malaterre +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +# See: +# https://github.com/json-c/json-c/wiki +# $ sudo apt-get install libjson0-dev +# in sid: +# $ sudo apt-get install libjson-c-dev + +find_path(JSON_INCLUDE_DIR NAMES json-c/json.h json/json.h) +find_library(JSON_LIBRARY NAMES json-c json) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(JSON DEFAULT_MSG + JSON_LIBRARY + JSON_INCLUDE_DIR +) + +if(JSON_FOUND) + set(JSON_LIBRARIES ${JSON_LIBRARY}) + # hack to get old and new layout working: + set(JSON_INCLUDE_DIRS ${JSON_INCLUDE_DIR}/json-c + ${JSON_INCLUDE_DIR}/json) +endif() + +mark_as_advanced( + JSON_LIBRARY + JSON_INCLUDE_DIR +) diff --git a/gdcm/CMake/FindJava.cmake b/gdcm/CMake/FindJava.cmake new file mode 100644 index 0000000..ad3d75c --- /dev/null +++ b/gdcm/CMake/FindJava.cmake @@ -0,0 +1,152 @@ +# - Find Java +# This module finds if Java is installed and determines where the +# include files and libraries are. This code sets the following +# variables: +# +# Java_JAVA_EXECUTABLE = the full path to the Java runtime +# Java_JAVAC_EXECUTABLE = the full path to the Java compiler +# Java_JAR_EXECUTABLE = the full path to the Java archiver +# Java_VERSION_STRING = Version of the package found (java version), eg. 1.6.0_12 +# Java_VERSION_MAJOR = The major version of the package found. +# Java_VERSION_MINOR = The minor version of the package found. +# Java_VERSION_PATCH = The patch version of the package found. +# Java_VERSION_TWEAK = The tweak version of the package found (after '_') +# Java_VERSION = This is set to: $major.$minor.$patch(.$tweak) +# + +#============================================================================= +# Copyright 2002-2009 Kitware, Inc. +# Copyright 2009-2011 Mathieu Malaterre +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distributed this file outside of CMake, substitute the full +# License text for the above reference.) + +# The HINTS option should only be used for values computed from the system. +set(_JAVA_HINTS + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\2.0;JavaHome]/bin" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.9;JavaHome]/bin" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.8;JavaHome]/bin" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.7;JavaHome]/bin" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.6;JavaHome]/bin" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.5;JavaHome]/bin" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.4;JavaHome]/bin" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.3;JavaHome]/bin" + $ENV{JAVA_HOME}/bin + ) +# Hard-coded guesses should still go in PATHS. This ensures that the user +# environment can always override hard guesses. +set(_JAVA_PATHS + /usr/lib/java/bin + /usr/share/java/bin + /usr/local/java/bin + /usr/local/java/share/bin + /usr/java/j2sdk1.4.2_04 + /usr/lib/j2sdk1.4-sun/bin + /usr/java/j2sdk1.4.2_09/bin + /usr/lib/j2sdk1.5-sun/bin + /opt/sun-jdk-1.5.0.04/bin + ) +find_program(Java_JAVA_EXECUTABLE + NAMES java + HINTS ${_JAVA_HINTS} + PATHS ${_JAVA_PATHS} +) + +if(Java_JAVA_EXECUTABLE) + set(_java_version_acceptable TRUE) + execute_process(COMMAND ${Java_JAVA_EXECUTABLE} -version + RESULT_VARIABLE res + OUTPUT_VARIABLE var + ERROR_VARIABLE var # sun-java output to stderr + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_STRIP_TRAILING_WHITESPACE) + if( res ) + message( FATAL_ERROR "Error executing java -version. Message: ${var}" ) + else() + # extract major/minor version and patch level from "java -version" output + # Tested on linux using + # 1. Sun / Sun OEM + # 2. OpenJDK 1.6 + # 3. GCJ 1.5 + # 4. Kaffe 1.4.2 + if(var MATCHES "java version \"[0-9]+\\.[0-9]+\\.[0-9_]+[oem-]*\".*") + # This is most likely Sun / OpenJDK, or maybe GCJ-java compat layer + string( REGEX REPLACE ".* version \"([0-9]+\\.[0-9]+\\.[0-9_]+)[oem-]*\".*" + "\\1" Java_VERSION_STRING "${var}" ) + elseif(var MATCHES "java full version \"kaffe-[0-9]+\\.[0-9]+\\.[0-9_]+\".*") + # Kaffe style + string( REGEX REPLACE "java full version \"kaffe-([0-9]+\\.[0-9]+\\.[0-9_]+).*" + "\\1" Java_VERSION_STRING "${var}" ) + else() + if(NOT Java_FIND_QUIETLY) + message(WARNING "regex not supported: ${var}. Please report") + set(_java_version_acceptable FALSE) + endif() + endif() + string( REGEX REPLACE "([0-9]+).*" "\\1" Java_VERSION_MAJOR "${Java_VERSION_STRING}" ) + string( REGEX REPLACE "[0-9]+\\.([0-9]+).*" "\\1" Java_VERSION_MINOR "${Java_VERSION_STRING}" ) + string( REGEX REPLACE "[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" Java_VERSION_PATCH "${Java_VERSION_STRING}" ) + # warning tweak version can be empty: + string( REGEX REPLACE "[0-9]+\\.[0-9]+\\.[0-9]+\\_?([0-9]*)$" "\\1" Java_VERSION_TWEAK "${Java_VERSION_STRING}" ) + if( Java_VERSION_TWEAK STREQUAL "" ) # check case where tweak is not defined + set(Java_VERSION ${Java_VERSION_MAJOR}.${Java_VERSION_MINOR}.${Java_VERSION_PATCH}) + else() + set(Java_VERSION ${Java_VERSION_MAJOR}.${Java_VERSION_MINOR}.${Java_VERSION_PATCH}.${Java_VERSION_TWEAK}) + endif() + # display info + #message( STATUS "Java version ${Java_VERSION_STRING} configured successfully!" ) # keep me, used for debug + if(NOT Java_FIND_QUIETLY) + message( STATUS "Java version ${Java_VERSION} configured successfully!" ) + endif() + endif() + + # check version if requested: + if( Java_FIND_VERSION ) + if("${Java_VERSION}" VERSION_LESS "${Java_FIND_VERSION}") + set(_java_version_acceptable FALSE) + endif() + if( Java_FIND_VERSION_EXACT ) + if("${Java_VERSION}" VERSION_GREATER "${Java_FIND_VERSION}") + set(_java_version_acceptable FALSE) + endif() + endif() + endif() +endif() + +get_filename_component(Java_JAVA_PATH ${Java_JAVA_EXECUTABLE} PATH) + +# Prefer same path as java +find_program(Java_JAR_EXECUTABLE NAMES jar PATHS ${Java_JAVA_PATH} NO_DEFAULT_PATH) +find_program(Java_JAR_EXECUTABLE + NAMES jar + HINTS ${_JAVA_HINTS} + PATHS ${_JAVA_PATHS} +) + +find_program(Java_JAVAC_EXECUTABLE NAMES javac PATHS ${Java_JAVA_PATH} NO_DEFAULT_PATH) +find_program(Java_JAVAC_EXECUTABLE + NAMES javac + HINTS ${_JAVA_HINTS} + PATHS ${_JAVA_PATHS} +) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Java DEFAULT_MSG + Java_JAVA_EXECUTABLE + Java_JAR_EXECUTABLE + Java_JAVAC_EXECUTABLE + _java_version_acceptable +) + +mark_as_advanced( + Java_JAVA_EXECUTABLE + Java_JAR_EXECUTABLE + Java_JAVAC_EXECUTABLE + ) diff --git a/gdcm/CMake/FindJavaProperties.cmake b/gdcm/CMake/FindJavaProperties.cmake new file mode 100644 index 0000000..b60eb5d --- /dev/null +++ b/gdcm/CMake/FindJavaProperties.cmake @@ -0,0 +1,92 @@ +# Copyright (c) 2006-2011 Mathieu Malaterre +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + +# This module will populate the following cmake variables: +# JavaProp_JAVA_LIBRARY_PATH +# JavaProp_OS_ARCH +# JavaProp_OS_NAME +# JavaProp_JAVA_HOME +# JavaProp_SUN_BOOT_LIBRARY_PATH +# JavaProp_PATH_SEPARATOR +# JavaProp_SUN_ARCH_DATA_MODEL + +# I can't get FindJNI.cmake to work, so instead re-write one more robust +# which only requires javac and java being in the PATH + +get_filename_component(current_list_path ${CMAKE_CURRENT_LIST_FILE} PATH) +find_package(Java 1.5 REQUIRED) + +# need to re-run everytime the setting for Java has changed: +# There is technically one caveat still, when one only modify +# Java_JAVA_EXECUTABLE from cmake-gui, everything is re-run properly except the +# FIND_PATH for jar and javac +if(JavaProp_JAVA_HOME) + get_filename_component(javarealpath + ${Java_JAVA_EXECUTABLE} + REALPATH + ) + get_filename_component(javahomesubdir + ${JavaProp_JAVA_HOME} + PATH + ) + #string(FIND "${javarealpath}" "${javahomesubdir}" res) + #if(-1 EQUAL ${res}) + # message(STATUS "Need to re-execute JavaProp") + # file(REMOVE + # ${CMAKE_BINARY_DIR}/GetSystemProperty.class + # ) + #endif() + string(REGEX MATCH "${javahomesubdir}" + outputvar + "${javarealpath}" + ) + if(NOT outputvar) + message(STATUS "Need to re-execute JavaProp: ${outputvar}") + file(REMOVE + ${CMAKE_BINARY_DIR}/GetSystemProperty.class + ) + endif() +endif() + +# For some reason I have to use two execute_process instead of a chained one... +if(${current_list_path}/GetSystemProperty.java IS_NEWER_THAN ${CMAKE_BINARY_DIR}/GetSystemProperty.class) + #message("${current_list_path}/GetSystemProperty.java") + #message("${CMAKE_CURRENT_BINARY_DIR}/GetSystemProperty.class") + execute_process( + COMMAND ${Java_JAVAC_EXECUTABLE} -source 1.5 -target 1.5 + ${current_list_path}/GetSystemProperty.java -d ${CMAKE_BINARY_DIR} + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + ) + + # populate the following list of java properties into CMake properties: + set(JAVA_PROPERTY_LIST + java.library.path + os.arch + os.name + java.home + sun.boot.library.path + path.separator # : / ; + sun.arch.data.model # 32 / 64 + ) + foreach(property ${JAVA_PROPERTY_LIST}) + string(TOUPPER ${property} property_upper) + string(REPLACE "." "_" property_cmake_name ${property_upper}) + execute_process( + COMMAND ${Java_JAVA_EXECUTABLE} GetSystemProperty ${property} + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + OUTPUT_VARIABLE ${property_cmake_name} + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + #message("${property} : ${property_cmake_name} : ${${property_cmake_name}}") + set(JavaProp_${property_cmake_name} ${${property_cmake_name}} + CACHE STRING "Java Prop Value for: ${property}" FORCE + ) + mark_as_advanced( + JavaProp_${property_cmake_name} + ) + endforeach() +endif() diff --git a/gdcm/CMake/FindKAKADU.cmake b/gdcm/CMake/FindKAKADU.cmake new file mode 100644 index 0000000..3e0409d --- /dev/null +++ b/gdcm/CMake/FindKAKADU.cmake @@ -0,0 +1,19 @@ +# +# this module looks for KAKADu +# http://www.kakadusoftware.com/ +# +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + +find_program(KDU_EXPAND_EXECUTABLE + kdu_expand + ) + +mark_as_advanced( + KDU_EXPAND_EXECUTABLE + ) diff --git a/gdcm/CMake/FindKWStyle.cmake b/gdcm/CMake/FindKWStyle.cmake new file mode 100644 index 0000000..ee6cbc8 --- /dev/null +++ b/gdcm/CMake/FindKWStyle.cmake @@ -0,0 +1,35 @@ +# +# this module looks for KWStyle +# http://public.kitware.com/KWStyle +# +# +# Copyright (c) 2009-2011 Mathieu Malaterre +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + +find_program(KWSTYLE_EXECUTABLE + NAMES KWStyle + PATHS + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Kitware Inc.\\KWStyle 1.0.0]/bin" + ) + +# option(KWSTYLE_USE_VIM_FORMAT "Set KWStyle to generate errors with a VIM-compatible format." OFF) +# option(KWSTYLE_USE_MSVC_FORMAT "Set KWStyle to generate errors with a VisualStudio-compatible format." OFF) +# mark_as_advanced(KWSTYLE_USE_VIM_FORMAT) +# mark_as_advanced(KWSTYLE_USE_MSVC_FORMAT) +# +# if(KWSTYLE_USE_VIM_FORMAT) +# set(KWSTYLE_ARGUMENTS -vim ${KWSTYLE_ARGUMENTS}) +# endif() +# +# if(KWSTYLE_USE_MSVC_FORMAT) +# set(KWSTYLE_ARGUMENTS -msvc ${KWSTYLE_ARGUMENTS}) +# endif() + + +mark_as_advanced( + KWSTYLE_EXECUTABLE + ) diff --git a/gdcm/CMake/FindLJPEG.cmake b/gdcm/CMake/FindLJPEG.cmake new file mode 100644 index 0000000..214b7c7 --- /dev/null +++ b/gdcm/CMake/FindLJPEG.cmake @@ -0,0 +1,49 @@ +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + +find_path(LJPEG_INCLUDE_DIR ljpeg-62/jpeglib.h +/usr/local/include +/usr/include +) + +find_library(LJPEG8_LIBRARY + NAMES jpeg8 + PATHS /usr/lib /usr/local/lib + ) +find_library(LJPEG12_LIBRARY + NAMES jpeg12 + PATHS /usr/lib /usr/local/lib + ) +find_library(LJPEG16_LIBRARY + NAMES jpeg16 + PATHS /usr/lib /usr/local/lib + ) + +if (LJPEG8_LIBRARY AND LJPEG_INCLUDE_DIR) + set(LJPEG_LIBRARIES ${LJPEG8_LIBRARY} ${LJPEG12_LIBRARY} ${LJPEG16_LIBRARY}) + set(LJPEG_INCLUDE_DIRS ${LJPEG_INCLUDE_DIR}) + set(LJPEG_FOUND "YES") +else () + set(LJPEG_FOUND "NO") +endif () + + +if (LJPEG_FOUND) + if (NOT LJPEG_FIND_QUIETLY) + message(STATUS "Found LJPEG: ${LJPEG_LIBRARIES}") + endif () +else () + if (LJPEG_FIND_REQUIRED) + message(FATAL_ERROR "Could not find LJPEG library") + endif () +endif () + +mark_as_advanced( + LJPEG_LIBRARIES + LJPEG_INCLUDE_DIR + ) diff --git a/gdcm/CMake/FindMAGIC.cmake b/gdcm/CMake/FindMAGIC.cmake new file mode 100644 index 0000000..39b1665 --- /dev/null +++ b/gdcm/CMake/FindMAGIC.cmake @@ -0,0 +1,48 @@ +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + +# $ sudo apt-get install libmagic-dev +# $ dpkg -L libmagic-dev +# ... +# /usr/include/magic.h +# /usr/lib/libmagic.so + + +find_path(MAGIC_INCLUDE_DIR magic.h +/usr/local/include +/usr/include +) + +find_library(MAGIC_LIBRARY + NAMES magic + PATHS /usr/lib /usr/local/lib + ) + +if (MAGIC_LIBRARY AND MAGIC_INCLUDE_DIR) + set(MAGIC_LIBRARIES ${MAGIC_LIBRARY}) + set(MAGIC_INCLUDE_DIRS ${MAGIC_INCLUDE_DIR}) + set(MAGIC_FOUND "YES") +else () + set(MAGIC_FOUND "NO") +endif () + + +if (MAGIC_FOUND) + if (NOT MAGIC_FIND_QUIETLY) + message(STATUS "Found MAGIC: ${MAGIC_LIBRARIES} ${MAGIC_INCLUDE_DIR}") + endif () +else () + if (MAGIC_FIND_REQUIRED) + message(FATAL_ERROR "Could not find MAGIC library") + endif () +endif () + +mark_as_advanced( + MAGIC_LIBRARY + MAGIC_INCLUDE_DIR + ) diff --git a/gdcm/CMake/FindMONO.cmake b/gdcm/CMake/FindMONO.cmake new file mode 100644 index 0000000..df35990 --- /dev/null +++ b/gdcm/CMake/FindMONO.cmake @@ -0,0 +1,72 @@ +# - Find MONO +# This module finds an installed MONO. It sets the following variables: +# MONO_FOUND - set to true if MONO is found +# MONO_DIR - the directory where swig is installed +# MONO_EXECUTABLE - the path to the swig executable +# MONO_VERSION - the version number of the swig executable +# +# All informations are collected from the MONO_EXECUTABLE so the +# version to be found can be changed from the command line by +# means of setting MONO_EXECUTABLE +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# +set(MONO_FOUND FALSE) + +# apt-get install mono-jit mono-mcs mono-gac mono-gmcs + +# eg. +# $ gmcs HelloWorld.cs +# $ mono HelloWorld.exe + +# TODO: what are 'cscc' and 'ilrun' ? + +find_program(MONO_EXECUTABLE mono) +find_program(MCS_EXECUTABLE mcs) # 1.0 +find_program(GMCS_EXECUTABLE mono-csc gmcs) # 2.0 +find_program(SMCS_EXECUTABLE smcs) # Moonlight +# mono-gac: /usr/bin/gacutil +find_program(GACUTIL_EXECUTABLE gacutil) # gacutil - Global Assembly Cache management utility. +# mono-1.0-devel: /usr/bin/ilasm +find_program(ILASM_EXECUTABLE ilasm) # ilasm, ilasm2 - Mono IL assembler +# mono-1.0-devel: /usr/bin/sn +find_program(SN_EXECUTABLE sn) # sn - Digitally sign/verify/compare strongnames on CLR assemblies. + +# We decide to declare mono found when both interpreter and compiler 1.0 are found. +if(MONO_EXECUTABLE AND MCS_EXECUTABLE) +set(MONO_FOUND TRUE) +# TODO get version +# TODO: there are multiple 'mcs' command on unix, need to check this is Mono: +# mcs --version should return "Mono C# compiler version 1.9.1.0" +elseif(MONO_EXECUTABLE AND GMCS_EXECUTABLE) +set(MONO_FOUND TRUE) +elseif(MONO_EXECUTABLE AND SMCS_EXECUTABLE) +set(MONO_FOUND TRUE) +endif() + +if(NOT MONO_FOUND) + if(NOT MONO_FIND_QUIETLY) + if(MONO_FIND_REQUIRED) + message(FATAL_ERROR "MONO was not found. Please specify mono/mcs executable location") + else() + message(STATUS "MONO was not found. Please specify mono/mcs executable location") + endif() + endif() +endif() + +get_filename_component(current_list_path ${CMAKE_CURRENT_LIST_FILE} PATH) +set(MONO_USE_FILE ${current_list_path}/UseMONO.cmake) + +mark_as_advanced( + MONO_EXECUTABLE + MCS_EXECUTABLE + GMCS_EXECUTABLE + SMCS_EXECUTABLE + ILASM_EXECUTABLE + SN_EXECUTABLE + GACUTIL_EXECUTABLE +) diff --git a/gdcm/CMake/FindMd5sum.cmake b/gdcm/CMake/FindMd5sum.cmake new file mode 100644 index 0000000..5070930 --- /dev/null +++ b/gdcm/CMake/FindMd5sum.cmake @@ -0,0 +1,68 @@ +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + +# find md5sum + +set(Md5sum_FOUND FALSE) +find_program(Md5sum_EXECUTABLE md5sum) +mark_as_advanced(Md5sum_EXECUTABLE) + +if (Md5sum_EXECUTABLE) + set(Md5sum_FOUND TRUE) +endif () + +# Compute the md5sums file by doing a recursion of directory: `DIRECTORY` +macro(COMPUTE_MD5SUMS DIRECTORY OUTPUT_FILE) + +# Super ugly and barely readable but you need that in order to +# work around a deficiency in EXECUTE_PROCESS which does not have dependencie scanning +file(WRITE +${CMAKE_BINARY_DIR}/md5sum.cmake +" + file(GLOB_RECURSE MD5SUM_INPUT_FILES + ${DIRECTORY}/* + ) + + execute_process( + COMMAND md5sum \${MD5SUM_INPUT_FILES} + WORKING_DIRECTORY ${DIRECTORY} + OUTPUT_VARIABLE md5sum_VAR + # OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE md5sum_RES + ) + # apparently md5sums start with: usr/... + string(REPLACE ${DIRECTORY}/ + \"\" md5sum_VAR_clean + \${md5sum_VAR}) + file(WRITE ${CMAKE_BINARY_DIR}/md5sums \${md5sum_VAR_clean}) +" +) + +add_custom_command( + OUTPUT ${OUTPUT_FILE} + COMMAND cmake + ARGS -P ${CMAKE_BINARY_DIR}/md5sum.cmake + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + DEPENDS ${DIRECTORY} ${CMAKE_BINARY_DIR}/md5sum.cmake + COMMENT "Generating md5sums" + ) + +endmacro() + +# Report the results. +if(NOT Md5sum_FOUND) + set(Md5sum_DIR_MESSAGE + "Md5sum was not found. Make sure the entries Md5sum_* are set.") + if(NOT Md5sum_FIND_QUIETLY) + message(STATUS "${Md5sum_DIR_MESSAGE}") + else() + if(Md5sum_FIND_REQUIRED) + message(FATAL_ERROR "${Md5sum_DIR_MESSAGE}") + endif() + endif() +endif() diff --git a/gdcm/CMake/FindOpenJPEG.cmake b/gdcm/CMake/FindOpenJPEG.cmake new file mode 100644 index 0000000..26b169f --- /dev/null +++ b/gdcm/CMake/FindOpenJPEG.cmake @@ -0,0 +1,53 @@ +# - Try to find the OpenJPEG (JPEG 2000) library +# +# Read-Only variables: +# OPENJPEG_FOUND - system has the OpenJPEG library +# OPENJPEG_INCLUDE_DIR - the OpenJPEG include directory +# OPENJPEG_LIBRARIES - The libraries needed to use OpenJPEG + +#============================================================================= +# Copyright 2006-2011 Mathieu Malaterre +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +# Try first to locate a cmake config file +find_package(OpenJPEG QUIET NO_MODULE) + +if( NOT OpenJPEG_DIR ) +set(OPENJPEG_MAJOR_VERSION 1) # FIXME ? +find_path(OPENJPEG_INCLUDE_DIR + NAMES openjpeg.h #openjpeg-1.0/openjpeg.h + PATHS /usr/local/include + /usr/local/include/openjpeg-1.0 + /usr/include + /usr/include/openjpeg-1.0 + ) + +find_library(OPENJPEG_LIBRARY + NAMES openjpeg + ) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(OpenJPEG DEFAULT_MSG + OPENJPEG_LIBRARY + OPENJPEG_INCLUDE_DIR +) + +if(OPENJPEG_FOUND) + set(OPENJPEG_LIBRARIES ${OPENJPEG_LIBRARY}) + set(OPENJPEG_INCLUDE_DIRS ${OPENJPEG_INCLUDE_DIR}) +endif() + +mark_as_advanced( + OPENJPEG_LIBRARY + OPENJPEG_INCLUDE_DIR + ) +endif() diff --git a/gdcm/CMake/FindOpenSSL.cmake b/gdcm/CMake/FindOpenSSL.cmake new file mode 100644 index 0000000..ee71d82 --- /dev/null +++ b/gdcm/CMake/FindOpenSSL.cmake @@ -0,0 +1,123 @@ +# - Try to find the OpenSSL encryption library +# Once done this will define +# +# OPENSSL_ROOT_DIR - Set this variable to the root installation of OpenSSL +# +# Read-Only variables: +# OPENSSL_FOUND - system has the OpenSSL library +# OPENSSL_INCLUDE_DIR - the OpenSSL include directory +# OPENSSL_LIBRARIES - The libraries needed to use OpenSSL + +#============================================================================= +# Copyright 2006-2009 Kitware, Inc. +# Copyright 2006 Alexander Neundorf +# Copyright 2009-2011 Mathieu Malaterre +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distributed this file outside of CMake, substitute the full +# License text for the above reference.) + +# http://www.slproweb.com/products/Win32OpenSSL.html +set(_OPENSSL_ROOT_HINTS + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\OpenSSL (32-bit)_is1;Inno Setup: App Path]" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\OpenSSL (64-bit)_is1;Inno Setup: App Path]" + ) +set(_OPENSSL_ROOT_PATHS + "C:/OpenSSL/" + "C:/OpenSSL-Win32/" + ) +find_path(OPENSSL_ROOT_DIR + NAMES include/openssl/ssl.h + HINTS ${_OPENSSL_ROOT_HINTS} + PATHS ${_OPENSSL_ROOT_PATHS} +) +mark_as_advanced(OPENSSL_ROOT_DIR) + +# Re-use the previous path: +find_path(OPENSSL_INCLUDE_DIR openssl/ssl.h + PATHS ${OPENSSL_ROOT_DIR}/include +) + +if(WIN32 AND NOT CYGWIN) + # MINGW should go here too + if(MSVC) + # /MD and /MDd are the standard values - if someone wants to use + # others, the libnames have to change here too + # use also ssl and ssleay32 in debug as fallback for openssl < 0.9.8b + # TODO: handle /MT and static lib + # In Visual C++ naming convention each of these four kinds of Windows libraries has it's standard suffix: + # * MD for dynamic-release + # * MDd for dynamic-debug + # * MT for static-release + # * MTd for static-debug + + # Implementation details: + # We are using the libraries located in the VC subdir instead of the parent directory eventhough : + # libeay32MD.lib is identical to ../libeay32.lib, and + # ssleay32MD.lib is identical to ../ssleay32.lib + find_library(LIB_EAY_DEBUG NAMES libeay32MDd libeay32 + PATHS ${OPENSSL_ROOT_DIR}/lib/VC + ) + find_library(LIB_EAY_RELEASE NAMES libeay32MD libeay32 + PATHS ${OPENSSL_ROOT_DIR}/lib/VC + ) + find_library(SSL_EAY_DEBUG NAMES ssleay32MDd ssleay32 ssl + PATHS ${OPENSSL_ROOT_DIR}/lib/VC + ) + find_library(SSL_EAY_RELEASE NAMES ssleay32MD ssleay32 ssl + PATHS ${OPENSSL_ROOT_DIR}/lib/VC + ) + if( CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE ) + set( OPENSSL_LIBRARIES + optimized ${SSL_EAY_RELEASE} ${LIB_EAY_RELEASE} + debug ${SSL_EAY_DEBUG} ${LIB_EAY_DEBUG} + ) + else() + set( OPENSSL_LIBRARIES ${SSL_EAY_RELEASE} ${LIB_EAY_RELEASE} ) + endif() + mark_as_advanced(SSL_EAY_DEBUG SSL_EAY_RELEASE) + mark_as_advanced(LIB_EAY_DEBUG LIB_EAY_RELEASE) + elseif(MINGW) + # same player, for MingW + find_library(LIB_EAY NAMES libeay32 + PATHS ${OPENSSL_ROOT_DIR}/lib/MinGW + ) + find_library(SSL_EAY NAMES ssleay32 + PATHS ${OPENSSL_ROOT_DIR}/lib/MinGW + ) + mark_as_advanced(SSL_EAY LIB_EAY) + set( OPENSSL_LIBRARIES ${SSL_EAY} ${LIB_EAY} ) + else() + # Not sure what to pick for -say- intel, let's use the toplevel ones and hope someone report issues: + find_library(LIB_EAY NAMES libeay32 + PATHS ${OPENSSL_ROOT_DIR}/lib + ) + find_library(SSL_EAY NAMES ssleay32 + PATHS ${OPENSSL_ROOT_DIR}/lib + ) + mark_as_advanced(SSL_EAY LIB_EAY) + set( OPENSSL_LIBRARIES ${SSL_EAY} ${LIB_EAY} ) + endif() +else() + + find_library(OPENSSL_SSL_LIBRARIES NAMES ssl ssleay32 ssleay32MD) + find_library(OPENSSL_CRYPTO_LIBRARIES NAMES crypto) + mark_as_advanced(OPENSSL_CRYPTO_LIBRARIES OPENSSL_SSL_LIBRARIES) + + set(OPENSSL_LIBRARIES ${OPENSSL_SSL_LIBRARIES} ${OPENSSL_CRYPTO_LIBRARIES}) + +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(OpenSSL DEFAULT_MSG + OPENSSL_LIBRARIES + OPENSSL_INCLUDE_DIR +) + +mark_as_advanced(OPENSSL_INCLUDE_DIR OPENSSL_LIBRARIES) diff --git a/gdcm/CMake/FindPAPYRUS3.cmake b/gdcm/CMake/FindPAPYRUS3.cmake new file mode 100644 index 0000000..ff848f5 --- /dev/null +++ b/gdcm/CMake/FindPAPYRUS3.cmake @@ -0,0 +1,37 @@ +# - Find papyrus3 +# Find the native PAPYRUS3 headers and libraries. +# This module defines +# PAPYRUS3_INCLUDE_DIRS - the json include directory +# PAPYRUS3_LIBRARIES - the libraries needed to use json +# PAPYRUS3_FOUND - system has the json library +# +# Copyright (c) 2013 Mathieu Malaterre +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +set(PAPYRUS3_INCLUDE_DIRECTORIES + /usr/include/ + /usr/include/Papyrus3 + ) +find_path(PAPYRUS3_INCLUDE_DIR Papyrus3.h + ${PAPYRUS3_INCLUDE_DIRECTORIES} + ) +find_library(PAPYRUS3_LIBRARY NAMES Papyrus3) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(PAPYRUS3 DEFAULT_MSG + PAPYRUS3_LIBRARY + PAPYRUS3_INCLUDE_DIR +) + +if(PAPYRUS3_FOUND) + set(PAPYRUS3_LIBRARIES ${PAPYRUS3_LIBRARY}) + set(PAPYRUS3_INCLUDE_DIRS ${PAPYRUS3_INCLUDE_DIR}) +endif() + +mark_as_advanced( + PAPYRUS3_LIBRARY + PAPYRUS3_INCLUDE_DIR +) diff --git a/gdcm/CMake/FindPHP5.cmake b/gdcm/CMake/FindPHP5.cmake new file mode 100644 index 0000000..99820af --- /dev/null +++ b/gdcm/CMake/FindPHP5.cmake @@ -0,0 +1,47 @@ +# - Find PHP5 +# This module finds if PHP5 is installed and determines where the include files +# and libraries are. It also determines what the name of the library is. This +# code sets the following variables: +# +# PHP5_INCLUDE_PATH = path to where php.h can be found +# PHP5_EXECUTABLE = full path to the php5 binary +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + +set(PHP5_POSSIBLE_INCLUDE_PATHS + /usr/include/php5 + /usr/local/include/php5 + /usr/include/php + /usr/local/include/php + /usr/local/apache/php + ) + +set(PHP5_POSSIBLE_LIB_PATHS + /usr/lib + ) + +find_path(PHP5_FOUND_INCLUDE_PATH main/php.h + ${PHP5_POSSIBLE_INCLUDE_PATHS}) + +if(PHP5_FOUND_INCLUDE_PATH) + set(php5_paths "${PHP5_POSSIBLE_INCLUDE_PATHS}") + foreach(php5_path Zend main TSRM) + set(php5_paths ${php5_paths} "${PHP5_FOUND_INCLUDE_PATH}/${php5_path}") + endforeach() + set(PHP5_INCLUDE_PATH "${php5_paths}" CACHE INTERNAL "PHP5 include paths") +endif() + +find_program(PHP5_EXECUTABLE NAMES php5 php ) + +mark_as_advanced( + PHP5_EXECUTABLE + PHP5_FOUND_INCLUDE_PATH + ) + +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(PHP5 DEFAULT_MSG PHP5_EXECUTABLE PHP5_INCLUDE_PATH) diff --git a/gdcm/CMake/FindPVRGJPEG.cmake b/gdcm/CMake/FindPVRGJPEG.cmake new file mode 100644 index 0000000..94a20ad --- /dev/null +++ b/gdcm/CMake/FindPVRGJPEG.cmake @@ -0,0 +1,38 @@ +# +# this module looks for PVRG-JPEG +# +# PVRG_JPEG_EXECUTABLE - the full path to pvrg-jpeg +# PVRG_JPEG_FOUND - If false, don't attempt to use pvrg-jpeg +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + +find_program(PVRGJPEG_EXECUTABLE + pvrg-jpeg + ) + + +mark_as_advanced( + PVRGJPEG_EXECUTABLE + ) + + +if (PVRGJPEG_EXECUTABLE) + set(PVRGJPEG_FOUND "YES") +else () + set(PVRGJPEG_FOUND "NO") +endif () + +if (PVRGJPEG_FOUND) + if (NOT PVRGJPEG_FIND_QUIETLY) + message(STATUS "Found PVRGJPEG: ${PVRGJPEG_EXECUTABLE}") + endif () +else () + if (PVRGJPEG_FIND_REQUIRED) + message(FATAL_ERROR "Could not find PVRGJPEG exe") + endif () +endif () diff --git a/gdcm/CMake/FindPoppler.cmake b/gdcm/CMake/FindPoppler.cmake new file mode 100644 index 0000000..9fb5136 --- /dev/null +++ b/gdcm/CMake/FindPoppler.cmake @@ -0,0 +1,40 @@ +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + +find_path(POPPLER_INCLUDE_DIR poppler/poppler-config.h +/usr/local/include +/usr/include +) + +find_library(POPPLER_LIBRARY + NAMES poppler + PATHS /usr/lib /usr/local/lib + ) + +if (POPPLER_LIBRARY AND POPPLER_INCLUDE_DIR) + set(POPPLER_LIBRARIES ${POPPLER_LIBRARY}) + set(POPPLER_INCLUDE_DIRS ${POPPLER_INCLUDE_DIR} ${POPPLER_INCLUDE_DIR}/poppler) + set(POPPLER_FOUND "YES") +else () + set(POPPLER_FOUND "NO") +endif () + +if (POPPLER_FOUND) + if (NOT Poppler_FIND_QUIETLY) + message(STATUS "Found POPPLER: ${POPPLER_LIBRARIES}") + endif () +else () + if (Poppler_FIND_REQUIRED) + message(FATAL_ERROR "Could not find POPPLER library") + endif () +endif () + +mark_as_advanced( + POPPLER_LIBRARY + POPPLER_INCLUDE_DIR + ) diff --git a/gdcm/CMake/FindRsync.cmake b/gdcm/CMake/FindRsync.cmake new file mode 100644 index 0000000..929f329 --- /dev/null +++ b/gdcm/CMake/FindRsync.cmake @@ -0,0 +1,26 @@ +# +# This module finds if rsync is installed +# +# RSYNC_EXECUTABLE = full path to the pike binary +# +# Typical usage for gdcm is: +# rsync -avH --delete [options] rsync.creatis.insa-lyon.fr::module localdir +# Compression option is: -z +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + +find_program(RSYNC_EXECUTABLE + NAMES rsync + PATHS + /usr/bin + /usr/local/bin + ) + +mark_as_advanced( + RSYNC_EXECUTABLE + ) diff --git a/gdcm/CMake/FindSOCKET++.cmake b/gdcm/CMake/FindSOCKET++.cmake new file mode 100644 index 0000000..0f41059 --- /dev/null +++ b/gdcm/CMake/FindSOCKET++.cmake @@ -0,0 +1,33 @@ +# - Find socket++ +# Find the native socket++ headers and libraries. +# This module defines +# SOCKETXX_INCLUDE_DIRS - the json include directory +# SOCKETXX_LIBRARIES - the libraries needed to use json +# SOCKETXX_FOUND - system has the json library +# +# Copyright (c) 2013 Mathieu Malaterre +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +find_path(SOCKETXX_INCLUDE_DIR socket++.h + /usr/include/socket++ + ) +find_library(SOCKETXX_LIBRARY NAMES Papyrus3) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(SOCKETXX DEFAULT_MSG + SOCKETXX_LIBRARY + SOCKETXX_INCLUDE_DIR +) + +if(SOCKETXX_FOUND) + set(SOCKETXX_LIBRARIES ${SOCKETXX_LIBRARY}) + set(SOCKETXX_INCLUDE_DIRS ${SOCKETXX_INCLUDE_DIR}) +endif() + +mark_as_advanced( + SOCKETXX_LIBRARY + SOCKETXX_INCLUDE_DIR +) diff --git a/gdcm/CMake/FindSQLITE3.cmake b/gdcm/CMake/FindSQLITE3.cmake new file mode 100644 index 0000000..e3377d8 --- /dev/null +++ b/gdcm/CMake/FindSQLITE3.cmake @@ -0,0 +1,19 @@ +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + +find_path(SQLITE3_INCLUDE_DIR sqlite3.h) + +find_library(SQLITE3_LIBRARY NAMES sqlite3) + +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(SQLITE3 DEFAULT_MSG SQLITE3_LIBRARY SQLITE3_INCLUDE_DIR) + +set(SQLITE3_LIBRARIES ${SQLITE3_LIBRARY}) +set(SQLITE3_INCLUDE_DIRS ${SQLITE3_INCLUDE_DIR}) + +mark_as_advanced(SQLITE3_LIBRARY SQLITE3_INCLUDE_DIR ) diff --git a/gdcm/CMake/FindUUID.cmake b/gdcm/CMake/FindUUID.cmake new file mode 100644 index 0000000..45c7244 --- /dev/null +++ b/gdcm/CMake/FindUUID.cmake @@ -0,0 +1,71 @@ +# - Find UUID +# Find the native UUID includes and library +# This module defines +# UUID_INCLUDE_DIR, where to find jpeglib.h, etc. +# UUID_LIBRARIES, the libraries needed to use UUID. +# UUID_FOUND, If false, do not try to use UUID. +# also defined, but not for general use are +# UUID_LIBRARY, where to find the UUID library. +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + +# On MacOSX we have: +# $ nm -g /usr/lib/libSystem.dylib | grep uuid_generate +# 000b3aeb T _uuid_generate +# 0003e67e T _uuid_generate_random +# 000b37a1 T _uuid_generate_time +if(APPLE) + set(UUID_LIBRARY_VAR System) +else() + # Linux type: + set(UUID_LIBRARY_VAR uuid) +endif() + +find_library(UUID_LIBRARY + NAMES ${UUID_LIBRARY_VAR} + PATHS /lib /usr/lib /usr/local/lib + ) + +# Must be *after* the lib itself +set(CMAKE_FIND_FRAMEWORK_SAVE ${CMAKE_FIND_FRAMEWORK}) +set(CMAKE_FIND_FRAMEWORK NEVER) + +find_path(UUID_INCLUDE_DIR uuid/uuid.h +/usr/local/include +/usr/include +) + +if (UUID_LIBRARY AND UUID_INCLUDE_DIR) + set(UUID_LIBRARIES ${UUID_LIBRARY}) + set(UUID_FOUND "YES") +else () + set(UUID_FOUND "NO") +endif () + + +if (UUID_FOUND) + if (NOT UUID_FIND_QUIETLY) + message(STATUS "Found UUID: ${UUID_LIBRARIES}") + endif () +else () + if (UUID_FIND_REQUIRED) + message( "library: ${UUID_LIBRARY}" ) + message( "include: ${UUID_INCLUDE_DIR}" ) + message(FATAL_ERROR "Could not find UUID library") + endif () +endif () + +# Deprecated declarations. +#set (NATIVE_UUID_INCLUDE_PATH ${UUID_INCLUDE_DIR} ) +#get_filename_component (NATIVE_UUID_LIB_PATH ${UUID_LIBRARY} PATH) + +mark_as_advanced( + UUID_LIBRARY + UUID_INCLUDE_DIR + ) +set(CMAKE_FIND_FRAMEWORK ${CMAKE_FIND_FRAMEWORK_SAVE}) diff --git a/gdcm/CMake/GetSystemProperty.java b/gdcm/CMake/GetSystemProperty.java new file mode 100644 index 0000000..9f2d751 --- /dev/null +++ b/gdcm/CMake/GetSystemProperty.java @@ -0,0 +1,40 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +import java.util.Properties; +import java.util.Enumeration; + +/* + * Java only allows setting properties from the command line not reading them + * Let's create a small app for this specific task then: + * + * namely: + */ +public class GetSystemProperty { + public static void main(String args[]) { + if( args.length == 0 ) { + Properties p = System.getProperties(); + Enumeration keys = p.keys(); + while (keys.hasMoreElements()) { + String key = (String)keys.nextElement(); + String value = (String)p.get(key); + System.out.println(key + " : " + value); + } + } + else { + for (String key: args) { + System.out.println(System.getProperty( key )); + } + } + } +} diff --git a/gdcm/CMake/InstallMacros.cmake b/gdcm/CMake/InstallMacros.cmake new file mode 100644 index 0000000..0250302 --- /dev/null +++ b/gdcm/CMake/InstallMacros.cmake @@ -0,0 +1,101 @@ +# +# This module install PDB files. +# +# Based on users posts: +# http://www.cmake.org/pipermail/cmake/2007-October/016924.html +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + +macro(install_swig_module module_name module_type) + # The following trick permits installion of module to the right destination: + # binary path for dll (on windows) + # library for non-dll platform + if(WIN32) + set(MODDST ${GDCM_INSTALL_BIN_DIR}) + else() + set(MODDST ${GDCM_INSTALL_LIB_DIR}) + endif() + string(TOUPPER ${module_type}Module MODTYPE) + set(MODDIR GDCM_INSTALL_${MODTYPE}_DIR) + # if user sets a GDCM_INSTALL_PYTHONMODULE_DIR + if(${MODDIR}) + SET(MODDST "${${MODDIR}}") + endif() + if(NOT GDCM_INSTALL_NO_LIBRARIES) + install(TARGETS ${SWIG_MODULE_${module_name}_REAL_NAME} + RUNTIME DESTINATION ${MODDST} COMPONENT ${module_type}Module + LIBRARY DESTINATION ${MODDST} COMPONENT ${module_type}Module + ) + endif() +endmacro() + +macro(install_library library) + if(NOT GDCM_INSTALL_NO_LIBRARIES) + # Runtime + install(TARGETS ${library} + EXPORT ${GDCM_TARGETS_NAME} + RUNTIME DESTINATION ${GDCM_INSTALL_BIN_DIR} COMPONENT Applications + LIBRARY DESTINATION ${GDCM_INSTALL_LIB_DIR} COMPONENT Libraries ${NAMELINK_SKIP} + ARCHIVE DESTINATION ${GDCM_INSTALL_LIB_DIR} COMPONENT DebugDevel + ) + # need recent cmake: http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=cbe7e8fa + #export(EXPORT ${GDCM_TARGETS_NAME} APPEND FILE "${CMAKE_CURRENT_BINARY_DIR}/foo.cmake") + #Development + if(NAMELINK_ONLY) + install(TARGETS ${library} + EXPORT ${GDCM_TARGETS_NAME} + LIBRARY DESTINATION ${GDCM_INSTALL_LIB_DIR} COMPONENT DebugDevel ${NAMELINK_ONLY} + ) + endif() + endif() +endmacro() + +macro (install_pdb library) + if (MSVC) + if(CMAKE_CONFIGURATION_TYPES) + # Visual Studio + # The following does not work with LOCATION keyword. See: + # http://www.cmake.org/pipermail/cmake/2011-February/042579.html + foreach(cfg ${CMAKE_CONFIGURATION_TYPES}) + get_target_property(library_dll ${library} LOCATION_${cfg}) + string(REPLACE .dll .pdb library_pdb ${library_dll}) + string(TOLOWER ${cfg} lcfg) + if(lcfg STREQUAL "debug" OR lcfg STREQUAL "relwithdebinfo") + install (FILES ${library_pdb} + DESTINATION ${GDCM_INSTALL_BIN_DIR} + COMPONENT DebugDevel + CONFIGURATIONS ${cfg} + ) + endif() + endforeach() + else() + # nmake + # Same as above we need the explicit location_ variable to account for + # the value of CMAKE_DEBUG_POSTFIX + get_target_property(library_dll ${library} LOCATION_${CMAKE_BUILD_TYPE}) + string(REPLACE .dll .pdb library_pdb ${library_dll}) + string(TOLOWER ${CMAKE_BUILD_TYPE} lcfg) + if(lcfg STREQUAL "debug" OR lcfg STREQUAL "relwithdebinfo") + install (FILES ${library_pdb} + DESTINATION ${GDCM_INSTALL_BIN_DIR} + COMPONENT DebugDevel + ) + endif() + endif() + endif () +endmacro () + +# At least one argument is required +macro (install_includes glob_expression) + if(NOT GDCM_INSTALL_NO_DEVELOPMENT) + file(GLOB header_files ${glob_expression} ${ARGN}) + install(FILES ${header_files} + DESTINATION ${GDCM_INSTALL_INCLUDE_DIR} COMPONENT Headers + ) + endif() +endmacro () diff --git a/gdcm/CMake/InstallRequiredVTKLibraries.cmake b/gdcm/CMake/InstallRequiredVTKLibraries.cmake new file mode 100644 index 0000000..42f47f5 --- /dev/null +++ b/gdcm/CMake/InstallRequiredVTKLibraries.cmake @@ -0,0 +1,54 @@ +# - Install VTK required libs for GDCM +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + +set(vtklist + vtkCommon + vtkFiltering + vtkGraphics + vtkHybrid + vtkIO + vtkImaging + vtkRendering + vtkWidgets +# utilities + vtkDICOMParser + vtkNetCDF + vtkNetCDF_cxx + vtkexoIIc + vtkexpat + vtkfreetype + vtkftgl + vtkjpeg + vtkmetaio + vtkpng + vtksys + vtktiff + vtkverdict + vtkzlib +) + +foreach(el ${vtklist}) + list(APPEND CMAKE_INSTALL_VTK_RUNTIME_LIBS ${VTK_DIR}/bin/${el}.dll) +endforeach() + +if(CMAKE_INSTALL_VTK_RUNTIME_LIBS) + if(NOT CMAKE_INSTALL_VTK_RUNTIME_LIBS_SKIP) + if(NOT CMAKE_INSTALL_VTK_RUNTIME_DESTINATION) + if(WIN32) + set(CMAKE_INSTALL_VTK_RUNTIME_DESTINATION bin) + else() + set(CMAKE_INSTALL_VTK_RUNTIME_DESTINATION lib) + endif() + endif() + install(PROGRAMS ${CMAKE_INSTALL_VTK_RUNTIME_LIBS} + DESTINATION ${CMAKE_INSTALL_VTK_RUNTIME_DESTINATION} + COMPONENT VTKLibraries + ) + endif() +endif() diff --git a/gdcm/CMake/Release/README.cygwin.in b/gdcm/CMake/Release/README.cygwin.in new file mode 100644 index 0000000..e69de29 diff --git a/gdcm/CMake/Release/cygwin-package.sh.in b/gdcm/CMake/Release/cygwin-package.sh.in new file mode 100644 index 0000000..e69de29 diff --git a/gdcm/CMake/Release/cygwin-patch.diff.in b/gdcm/CMake/Release/cygwin-patch.diff.in new file mode 100644 index 0000000..e69de29 diff --git a/gdcm/CMake/Release/cygwin-setup.hint.in b/gdcm/CMake/Release/cygwin-setup.hint.in new file mode 100644 index 0000000..e69de29 diff --git a/gdcm/CMake/Toolchain-gcc-arm-linux-gnueabi.cmake b/gdcm/CMake/Toolchain-gcc-arm-linux-gnueabi.cmake new file mode 100644 index 0000000..e773267 --- /dev/null +++ b/gdcm/CMake/Toolchain-gcc-arm-linux-gnueabi.cmake @@ -0,0 +1,40 @@ +# http://wiki.debian.org/BuildingCrossCompilers +# Usage: +# +# $ cmake ../gdcm -DCMAKE_TOOLCHAIN_FILE=../gdcm/CMake/Toolchain-gcc-arm-linux-gnueabi.cmake +# +# For gdcm you need at least the following three packages (squeeze suite) +# +# fix /etc/apt/source.lists +# + deb http://www.emdebian.org/debian squeeze main +# +# // prebuilt Emdebian project +# sudo apt-get install g++-4.4-arm-linux-gnueabi +# +# sudo xapt -S squeeze -M http://ftp.fr.debian.org/debian/ -a armel -m zlib1g-dev uuid-dev libexpat1-dev +# +# qemu-arm -L /usr/arm-linux-gnueabi/ ./bin/gdcminfo test.acr +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + +# the name of the target operating system +set(CMAKE_SYSTEM_NAME Linux) + +# which compilers to use for C and C++ +set(CMAKE_C_COMPILER arm-linux-gnueabi-gcc-4.4) +set(CMAKE_CXX_COMPILER arm-linux-gnueabi-g++-4.4) + +# here is the target environment located +set(CMAKE_FIND_ROOT_PATH /usr/arm-linux-gnueabi) + +# adjust the default behaviour of the FIND_XXX() commands: +# search headers and libraries in the target environment, search +# programs in the host environment +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) diff --git a/gdcm/CMake/Toolchain-gcc-m32.cmake b/gdcm/CMake/Toolchain-gcc-m32.cmake new file mode 100644 index 0000000..fcd1805 --- /dev/null +++ b/gdcm/CMake/Toolchain-gcc-m32.cmake @@ -0,0 +1,39 @@ +# http://www.cmake.org/Wiki/CmakeMingw +# Usage: +# +# $ cmake ../trunk -DCMAKE_TOOLCHAIN_FILE=../trunk/CMake/Toolchain-mingw32.cmake +# +# For gdcm you need at least the following three package (2008/08/19): +# +# apt-cross --arch i386 -i zlib1g-dev +# apt-cross --arch i386 -i uuid-dev +# apt-cross --arch i386 -i libexpat1-dev +# +# Do not forget to set to on the following: +# GDCM_USE_SYSTEM_EXPAT / GDCM_USE_SYSTEM_ZLIB / GDCM_USE_SYSTEM_UUID +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + +# the name of the target operating system +set(CMAKE_SYSTEM_NAME Linux) + +# which compilers to use for C and C++ +set(CMAKE_C_COMPILER gcc) +set(CMAKE_C_FLAGS -m32) +set(CMAKE_CXX_COMPILER g++) +set(CMAKE_CXX_FLAGS -m32) + +# here is the target environment located +set(CMAKE_FIND_ROOT_PATH /usr/i486-linux-gnu ) + +# adjust the default behaviour of the FIND_XXX() commands: +# search headers and libraries in the target environment, search +# programs in the host environment +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) diff --git a/gdcm/CMake/Toolchain-gcc-powerpc.cmake b/gdcm/CMake/Toolchain-gcc-powerpc.cmake new file mode 100644 index 0000000..fa9d17e --- /dev/null +++ b/gdcm/CMake/Toolchain-gcc-powerpc.cmake @@ -0,0 +1,56 @@ +# http://www.cmake.org/Wiki/CmakeMingw +# http://doc.cliss21.com/index.php?title=QEMU +# Usage: +# +# $ cmake ../trunk -DCMAKE_TOOLCHAIN_FILE=../trunk/CMake/Toolchain-mingw32.cmake +# +# For gdcm you need at least the following three package (2008/08/19): +# +# fix /etc/apt/source.lists +# + deb http://www.emdebian.org/debian/ unstable main +# +# // prebuilt Emdebian project +# sudo apt-get install g++-4.1-powerpc-linux-gnu +# +# apt-cross --arch powerpc -i zlib1g-dev +# apt-cross --arch powerpc -i uuid-dev +# apt-cross --arch powerpc -i libexpat1-dev +# +#I was getting: +#$ qemu-ppc ./a.out +#/lib/ld.so.1: No such file or directory +# +#Two approach for solving it: +#1. +#CMAKE_EXE_LINKER_FLAGS:STRING=-static +#2. +#$ qemu-ppc -L /usr/powerpc-linux-gnu/ ./a.out +#Hello cross-compiling world! +# +# +# Do not forget to set to on the following: +# GDCM_USE_SYSTEM_EXPAT / GDCM_USE_SYSTEM_ZLIB / GDCM_USE_SYSTEM_UUID +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + +# the name of the target operating system +set(CMAKE_SYSTEM_NAME Linux) + +# which compilers to use for C and C++ +set(CMAKE_C_COMPILER powerpc-linux-gnu-gcc) +set(CMAKE_CXX_COMPILER powerpc-linux-gnu-g++) + +# here is the target environment located +set(CMAKE_FIND_ROOT_PATH /usr/powerpc-linux-gnu ) + +# adjust the default behaviour of the FIND_XXX() commands: +# search headers and libraries in the target environment, search +# programs in the host environment +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) diff --git a/gdcm/CMake/Toolchain-mingw32.cmake b/gdcm/CMake/Toolchain-mingw32.cmake new file mode 100644 index 0000000..26e1f8d --- /dev/null +++ b/gdcm/CMake/Toolchain-mingw32.cmake @@ -0,0 +1,30 @@ +# http://www.cmake.org/Wiki/CmakeMingw +# Usage: +# +# $ cmake ../gdcm -DCMAKE_TOOLCHAIN_FILE=../gdcm/CMake/Toolchain-mingw32.cmake +# +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + +# the name of the target operating system +set(CMAKE_SYSTEM_NAME Windows) + +# which compilers to use for C and C++ +set(CMAKE_C_COMPILER i586-mingw32msvc-gcc) +set(CMAKE_CXX_COMPILER i586-mingw32msvc-g++) +set(CMAKE_RC_COMPILER i586-mingw32msvc-windres) + +# here is the target environment located +set(CMAKE_FIND_ROOT_PATH /usr/i586-mingw32msvc) + +# adjust the default behaviour of the FIND_XXX() commands: +# search headers and libraries in the target environment, search +# programs in the host environment +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) diff --git a/gdcm/CMake/Toolchain-mingw64.cmake b/gdcm/CMake/Toolchain-mingw64.cmake new file mode 100644 index 0000000..41a21af --- /dev/null +++ b/gdcm/CMake/Toolchain-mingw64.cmake @@ -0,0 +1,31 @@ +# http://www.cmake.org/Wiki/CmakeMingw +# Usage: +# +# $ sudo apt-get install mingw-w64 +# $ cmake ../gdcm -DCMAKE_TOOLCHAIN_FILE=../gdcm/CMake/Toolchain-mingw64.cmake +# +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + +# the name of the target operating system +set(CMAKE_SYSTEM_NAME Windows) + +# which compilers to use for C and C++ +set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc) +set(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++) +set(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres) + +# here is the target environment located +set(CMAKE_FIND_ROOT_PATH /usr/x86_64-w64-mingw32) + +# adjust the default behaviour of the FIND_XXX() commands: +# search headers and libraries in the target environment, search +# programs in the host environment +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) diff --git a/gdcm/CMake/UseCSharp.cmake b/gdcm/CMake/UseCSharp.cmake new file mode 100644 index 0000000..9ef42fc --- /dev/null +++ b/gdcm/CMake/UseCSharp.cmake @@ -0,0 +1,187 @@ +# - C# module for CMake +# Defines the following macros: +# CSHARP_ADD_EXECUTABLE(name [ files ]) +# - Define C# executable with given name +# CSHARP_ADD_LIBRARY(name [ files ]) +# - Define C# library with given name +# CSHARP_LINK_LIBRARIES(name [ libraries ]) +# - Link libraries to csharp library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + +# TODO: +# http://www.cs.nuim.ie/~jpower/Research/csharp/Index.html + +if(WIN32) + include(${DotNETFrameworkSDK_USE_FILE}) + # remap + set(CMAKE_CSHARP1_COMPILER ${CSC_v1_EXECUTABLE}) + set(CMAKE_CSHARP2_COMPILER ${CSC_v2_EXECUTABLE}) + set(CMAKE_CSHARP3_COMPILER ${CSC_v3_EXECUTABLE}) + set(CMAKE_CSHARP4_COMPILER ${CSC_v4_EXECUTABLE}) + + #set(CMAKE_CSHARP3_INTERPRETER ${MONO_EXECUTABLE}) +else() + include(${MONO_USE_FILE}) + set(CMAKE_CSHARP1_COMPILER ${MCS_EXECUTABLE}) + set(CMAKE_CSHARP2_COMPILER ${GMCS_EXECUTABLE}) + set(CMAKE_CSHARP3_COMPILER ${SMCS_EXECUTABLE}) + set(CMAKE_CSHARP4_COMPILER ${SMCS_EXECUTABLE}) + + set(CMAKE_CSHARP_INTERPRETER ${MONO_EXECUTABLE}) +endif() + +set(DESIRED_CSHARP_COMPILER_VERSION 2 CACHE STRING "Pick a version for C# compiler to use: 1, 2 or 3") +mark_as_advanced(DESIRED_CSHARP_COMPILER_VERSION) + +# default to v1: +if(DESIRED_CSHARP_COMPILER_VERSION MATCHES 1) + set(CMAKE_CSHARP_COMPILER ${CMAKE_CSHARP1_COMPILER}) +elseif(DESIRED_CSHARP_COMPILER_VERSION MATCHES 2) + set(CMAKE_CSHARP_COMPILER ${CMAKE_CSHARP2_COMPILER}) +elseif(DESIRED_CSHARP_COMPILER_VERSION MATCHES 3) + set(CMAKE_CSHARP_COMPILER ${CMAKE_CSHARP3_COMPILER}) +elseif(DESIRED_CSHARP_COMPILER_VERSION MATCHES 4) + set(CMAKE_CSHARP_COMPILER ${CMAKE_CSHARP4_COMPILER}) +else() + message(FATAL_ERROR "Do not know this version") +endif() + +# CMAKE_CSHARP_COMPILER /platform and anycpu +if(WIN32) +# There is a subttle issue when compiling on 64bits platform using a 32bits compiler +# See bug ID: 3510023 (BadImageFormatException: An attempt was made to load a progr) + +set(CSC_ACCEPTS_PLATFORM_FLAG 0) + +if(CMAKE_CSHARP_COMPILER) + execute_process(COMMAND "${CMAKE_CSHARP_COMPILER}" "/?" OUTPUT_VARIABLE CSC_HELP) + # when cmd locale is in French it displays: "/platform:" in english: "/platform:" + # so only regex match in /platform: + if("${CSC_HELP}" MATCHES "/platform:") + set(CSC_ACCEPTS_PLATFORM_FLAG 1) + endif() +endif() + +if(NOT DEFINED CSC_PLATFORM_FLAG) + set(CSC_PLATFORM_FLAG "") + if(CSC_ACCEPTS_PLATFORM_FLAG) + set(CSC_PLATFORM_FLAG "/platform:x86") + if("${CMAKE_SIZEOF_VOID_P}" GREATER 4) + set(CSC_PLATFORM_FLAG "/platform:x64") + endif() + endif() +endif() +endif() + + +# Check something is found: +if(NOT CMAKE_CSHARP_COMPILER) + # status message only for now: + message("Sorry C# v${DESIRED_CSHARP_COMPILER_VERSION} was not found on your system") +else() + #if (NOT CSHARP_FIND_QUIETLY) + message(STATUS "Will be using C# v${DESIRED_CSHARP_COMPILER_VERSION}: ${CMAKE_CSHARP_COMPILER}") + #endif () +endif() + +macro(CSHARP_ADD_LIBRARY name) + set(csharp_cs_sources) + set(csharp_cs_sources_dep) + foreach(it ${ARGN}) + if(EXISTS ${it}) + set(csharp_cs_sources "${csharp_cs_sources} ${it}") + set(csharp_cs_sources_dep ${csharp_cs_sources_dep} ${it}) + else() + if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${it}) + set(csharp_cs_sources "${csharp_cs_sources} ${CMAKE_CURRENT_SOURCE_DIR}/${it}") + set(csharp_cs_sources_dep ${csharp_cs_sources_dep} ${CMAKE_CURRENT_SOURCE_DIR}/${it}) + else() + #message("Could not find: ${it}") + set(csharp_cs_sources "${csharp_cs_sources} ${it}") + endif() + endif() + endforeach() + + #set(SHARP #) + separate_arguments(csharp_cs_sources) + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${name}.dll + COMMAND ${CMAKE_CSHARP_COMPILER} + ARGS "/t:library" "/out:${name}.dll" ${csharp_cs_sources} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS "${csharp_cs_sources_dep}" + COMMENT "Creating Csharp library ${name}.cs" + ) + add_custom_target(CSharp_${name} ALL + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${name}.dll + ) +endmacro() + +macro(CSHARP_ADD_EXECUTABLE name) + set(csharp_cs_sources) + foreach(it ${ARGN}) + if(EXISTS ${it}) + set(csharp_cs_sources "${csharp_cs_sources} ${it}") + else() + if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${it}) + set(csharp_cs_sources "${csharp_cs_sources} ${CMAKE_CURRENT_SOURCE_DIR}/${it}") + else() + #message("Could not find: ${it}") + set(csharp_cs_sources "${csharp_cs_sources} ${it}") + endif() + endif() + endforeach() + + set(CSHARP_EXECUTABLE_${name}_ARGS + #"/out:${name}.dll" ${csharp_cs_sources} + #"/r:gdcm_csharp.dll" + "/out:${name}.exe ${csharp_cs_sources}" + ) + +endmacro() + +macro(CSHARP_LINK_LIBRARIES name) + set(csharp_libraries) + set(csharp_libraries_depends) + foreach(it ${ARGN}) + #if(EXISTS ${it}.dll) + set(csharp_libraries "${csharp_libraries} /r:${it}.dll") + # set(csharp_libraries_depends ${it}.dll) + #else() + # if(EXISTS ${CMAKE_CURRENT_BINARY_DIR}/${it}.dll) + # set(csharp_libraries "${csharp_libraries} /r:${it}.dll") + # set(csharp_libraries_depends ${CMAKE_CURRENT_BINARY_DIR}/${it}.dll) + # else() + # message("Could not find: ${it}") + # endif() + #endif() + endforeach() + set(CSHARP_EXECUTABLE_${name}_ARGS " ${csharp_libraries} ${CSHARP_EXECUTABLE_${name}_ARGS}") + #message( "DEBUG: ${CSHARP_EXECUTABLE_${name}_ARGS}" ) + + # BAD DESIGN ! + # This should be in the _ADD_EXECUTABLE... + separate_arguments(CSHARP_EXECUTABLE_${name}_ARGS) + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${name}.exe + COMMAND ${CMAKE_CSHARP_COMPILER} + #ARGS "/r:gdcm_csharp.dll" "/out:${name}.exe" ${csharp_cs_sources} + ARGS ${CSHARP_EXECUTABLE_${name}_ARGS} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + #DEPENDS ${csharp_cs_sources} + COMMENT "Create HelloWorld.exe" + ) + + #message("DEBUG2:${csharp_libraries_depends}") + add_custom_target(CSHARP_EXECUTABLE_${name} ALL + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${name}.exe + ${csharp_libraries_depends} + ) + +endmacro() diff --git a/gdcm/CMake/UseCSharpTest.cmake b/gdcm/CMake/UseCSharpTest.cmake new file mode 100644 index 0000000..9388b17 --- /dev/null +++ b/gdcm/CMake/UseCSharpTest.cmake @@ -0,0 +1,83 @@ +# Add a python test from a python file +# One cannot simply do: +# set(ENV{PYTHONPATH} ${LIBRARY_OUTPUT_PATH}) +# set(my_test "from test_mymodule import *\;test_mymodule()") +# add_test(PYTHON-TEST-MYMODULE python -c ${my_test}) +# Since cmake is only transmitting the ADD_TEST line to ctest thus you are loosing +# the env var. The only way to store the env var is to physically write in the cmake script +# whatever PYTHONPATH you want and then add the test as 'cmake -P python_test.cmake' +# +# Usage: +# set_source_files_properties(test.py PROPERTIES PYTHONPATH +# "${LIBRARY_OUTPUT_PATH}:${VTK_DIR}") +# ADD_PYTHON_TEST(PYTHON-TEST test.py) +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + +# Need python interpreter: +#find_package(PythonInterp REQUIRED) +#mark_as_advanced(PYTHON_EXECUTABLE) +# UseCSharp.cmake + +macro(ADD_CSHARP_TEST TESTNAME FILENAME) + get_source_file_property(loc ${FILENAME} LOCATION) + get_source_file_property(pyenv ${FILENAME} RUNTIMEPATH) + if(CMAKE_CONFIGURATION_TYPES) + # I cannot use CMAKE_CFG_INTDIR since it expand to "$(OutDir)" + if(pyenv) + set(pyenv "${pyenv};${LIBRARY_OUTPUT_PATH}/${CMAKE_BUILD_TYPE}") + else() + set(pyenv ${LIBRARY_OUTPUT_PATH}/${CMAKE_BUILD_TYPE}) + #set(pyenv ${LIBRARY_OUTPUT_PATH}/${CMAKE_CFG_INTDIR}) + #set(pyenv ${LIBRARY_OUTPUT_PATH}/${CMAKE_CONFIG_TYPE}) + #set(pyenv ${LIBRARY_OUTPUT_PATH}/\${CMAKE_CONFIG_TYPE}) + endif() + else() + if(pyenv) + set(pyenv ${pyenv}:${LIBRARY_OUTPUT_PATH}) + else() + set(pyenv ${LIBRARY_OUTPUT_PATH}) + endif() + endif() + string(REGEX REPLACE ";" " " wo_semicolumn "${ARGN}") + file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/${TESTNAME}.cmake +" + set(ENV{LD_LIBRARY_PATH} ${pyenv}) + set(ENV{MONO_PATH} ${pyenv}) + #message(\"pyenv: ${pyenv}\") + #message( \"wo_semicolumn: ${wo_semicolumn}\" ) + execute_process( + COMMAND ${CMAKE_CSHARP_INTERPRETER} ${loc} ${wo_semicolumn} + #WORKING_DIRECTORY @LIBRARY_OUTPUT_PATH@ + RESULT_VARIABLE import_res + OUTPUT_VARIABLE import_output + ERROR_VARIABLE import_output + ) + + # Pass the output back to ctest + if(import_output) + message("\${import_output}") + endif() + if(import_res) + message(SEND_ERROR "\${import_res}") + endif() +" +) + add_test(NAME ${TESTNAME} COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/${TESTNAME}.cmake) +endmacro() + +# Byte compile recursively a directory (DIRNAME) +#macro(ADD_PYTHON_COMPILEALL_TEST DIRNAME) +# # First get the path: +# get_filename_component(temp_path "${PYTHON_LIBRARIES}" PATH) +# # Find the python script: +# get_filename_component(PYTHON_COMPILE_ALL_PY "${temp_path}/../compileall.py" ABSOLUTE) +# # add test, use DIRNAME to create uniq name for the test: +# add_test(COMPILE_ALL-${DIRNAME} ${PYTHON_EXECUTABLE} "${PYTHON_COMPILE_ALL_PY}" -q ${DIRNAME}) +#endmacro() +# diff --git a/gdcm/CMake/UseCopyright.cmake b/gdcm/CMake/UseCopyright.cmake new file mode 100644 index 0000000..fb4fe1f --- /dev/null +++ b/gdcm/CMake/UseCopyright.cmake @@ -0,0 +1,25 @@ +# Handy macro to gather all copyright in a single file (to pass to cpack) +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + +macro(CREATE_COPYRIGHT_FILE name) + # Always cleanup the file: + file(WRITE ${name} "") + set(COPYRIGHT_MODULE_FILENAME ${name}) +endmacro() + +# Append copyright file +macro(APPEND_COPYRIGHT) + # need to raise an error if COPYRIGHT_MODULE_FILENAME is not set... + if(EXISTS ${COPYRIGHT_MODULE_FILENAME} ) + foreach(filename ${ARGN}) + file(READ ${filename} content) + file(APPEND ${COPYRIGHT_MODULE_FILENAME} ${content}) + endforeach() + endif() +endmacro() diff --git a/gdcm/CMake/UseDebian.cmake b/gdcm/CMake/UseDebian.cmake new file mode 100644 index 0000000..e1e90ba --- /dev/null +++ b/gdcm/CMake/UseDebian.cmake @@ -0,0 +1,176 @@ +# create .deb file +# You need to setup CPack first ! +# UGLY: I reuse CPACK_NSIS_CONTACT to get the contact name for the debian package... +# TODO: How do I transmit the 'Depends' line ? + +# DOCUMENTATION; You need to fill these values to set the control file: +# "Package: ${DEBIAN_PACKAGE_NAME} +# Version: ${DEBIAN_PACKAGE_VERSION} +# Architecture: ${DEBIAN_ARCHITECTURE} +# Depends: ${DEBIAN_PACKAGE_DEPENDS} +# Maintainer: ${CPACK_NSIS_CONTACT} +# Description: ${CPACK_PACKAGE_DESCRIPTION_SUMMARY} + +# Thanks: +# Eric Noulard for initial UseRpmTools used as template +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + +if(UNIX) + if (NOT CMAKE_AR) + message(STATUS "No ar, cannot proceed") + set(DEBIAN_FOUND FALSE) + else () + set(DEBIAN_FOUND TRUE) + # Detect if CPack was included or not + if (NOT DEFINED "CPACK_PACKAGE_NAME") + message(FATAL_ERROR "CPack was not included, you should include CPack before Using UseDebian") + endif () + + macro(ADD_DEBIAN_TARGETS DEBNAME) + # $ ar tv cmake_2.4.5-1_i386.deb + # rw-r--r-- 0/0 4 Dec 4 22:58 2006 debian-binary + # rw-r--r-- 0/0 8981 Dec 4 22:58 2006 control.tar.gz + # rw-r--r-- 0/0 4893146 Dec 4 22:58 2006 data.tar.gz + + # Need a newline: + # dpkg-deb: archive has no newlines in header + add_custom_command( + OUTPUT ${CMAKE_BINARY_DIR}/debian-binary + COMMAND ${CMAKE_COMMAND} + ARGS -E echo "2.0" > ${CMAKE_BINARY_DIR}/debian-binary + COMMENT "Generating debian-binary" + VERBATIM) + + # seems better to ADD_CUSTOM_COMMAND this way debian-binary may + # be regenerated when make is called. + # file(WRITE ${CMAKE_BINARY_DIR}/debian-binary "2.0 + #" ) + + # debian policy enforce lower case for package name + if(NOT DEBIAN_PACKAGE_NAME) + string(TOLOWER + ${CPACK_PACKAGE_NAME} + DEBIAN_PACKAGE_NAME + ) + endif() + if(NOT DEBIAN_PACKAGE_DEPENDS) + set(DEBIAN_PACKAGE_DEPENDS + "libc6 (>= 2.3.1-6), libgcc1 (>= 1:3.4.2-12)" + ) + endif() + if(NOT DEBIAN_ARCHITECTURE) + # There is no such thing as i686 architecture on debian, you should use i386 instead + # $ dpkg --print-architecture + set(DEBIAN_ARCHITECTURE i386) + endif() + if(NOT DEBIAN_PACKAGE_VERSION) + set(DEBIAN_PACKAGE_VERSION + ${CPACK_PACKAGE_VERSION}) + endif() + + #message(${CMAKE_SYSTEM_PROCESSOR}) + + file(WRITE ${CMAKE_BINARY_DIR}/control + "Package: ${DEBIAN_PACKAGE_NAME} + Version: ${CPACK_PACKAGE_VERSION} + Section: devel + Priority: optional + Architecture: ${DEBIAN_ARCHITECTURE} + Depends: ${DEBIAN_PACKAGE_DEPENDS} + Maintainer: ${CPACK_NSIS_CONTACT} + Description: ${CPACK_PACKAGE_DESCRIPTION_SUMMARY} + . + ${DEBIAN_PACKAGE_NAME} was packaged by UseDebian and CMake. + . + ") + + + # FIXME: + # I have no friggin clue how cpack works, let's reinvent the wheel instead + + #include(${CMAKE_BINARY_DIR}/CPackConfig.cmake) + #add_custom_target(data_tgz + # COMMAND cpack -G TGZ --config CPackConfig.cmake + ## TODO: How to get the cpack package name ? + # COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/${CPACK_PACKAGE_FILE_NAME}.tar.gz ${CMAKE_BINARY_DIR}/data.tar.gz + #) + + # let's create a temp directory to call 'DESTDIR=... make install' into: + # cleanup + file(REMOVE ${CMAKE_BINARY_DIR}/debian_package) + # make dir: + file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/debian_package) + + # calling cmake -P cmake_install.cmake is the same as calling make install: + add_custom_target(deb_destdir_install + COMMAND ${CMAKE_MAKE_PROGRAM} DESTDIR=${CMAKE_BINARY_DIR}/debian_package install + DEPENDS ${CMAKE_BINARY_DIR}/cmake_install.cmake + COMMENT "Building debian_package directory with DESTDIR" + ) + add_dependencies(deb_destdir_install all preinstall) + + # create data.tar.gz from the make install stuff + # all files starts with: ./usr + add_custom_command( + OUTPUT ${CMAKE_BINARY_DIR}/data.tar.gz + COMMAND cmake -E tar + ARGS cfz ${CMAKE_BINARY_DIR}/data.tar.gz . + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/debian_package + DEPENDS ${CMAKE_BINARY_DIR}/debian_package + COMMENT "Generating data.tar.gz" + ) + + + # get all the files to be installed: + find_package(Md5sum REQUIRED) + COMPUTE_MD5SUMS( + ${CMAKE_BINARY_DIR}/debian_package + ${CMAKE_BINARY_DIR}/md5sums + ) + + # create a tarball (control.tar.gz) of control and md5sums + # files need to be in relative path: ./md5sums ./control ... + add_custom_command( + OUTPUT ${CMAKE_BINARY_DIR}/control.tar.gz + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + COMMAND cmake -E tar + ARGS cfz ${CMAKE_BINARY_DIR}/control.tar.gz ./control ./md5sums + DEPENDS ${CMAKE_BINARY_DIR}/control ${CMAKE_BINARY_DIR}/md5sums + COMMENT "Generating control.tar.gz" + ) + + + + # Warning order is important: + # ar -r your-package-name.deb debian-binary control.tar.gz data.tar.gz + # eg: cmake_2.4.5-1_i386.deb + add_custom_command( + OUTPUT ${CMAKE_BINARY_DIR}/${DEBIAN_PACKAGE_NAME}_${CPACK_PACKAGE_VERSION}-1_${DEBIAN_ARCHITECTURE}.deb + COMMAND ${CMAKE_AR} + ARGS -r ${CMAKE_BINARY_DIR}/${DEBIAN_PACKAGE_NAME}_${CPACK_PACKAGE_VERSION}-1_${DEBIAN_ARCHITECTURE}.deb + ${CMAKE_BINARY_DIR}/debian-binary + ${CMAKE_BINARY_DIR}/control.tar.gz ${CMAKE_BINARY_DIR}/data.tar.gz + DEPENDS ${CMAKE_BINARY_DIR}/debian-binary ${CMAKE_BINARY_DIR}/control.tar.gz ${CMAKE_BINARY_DIR}/data.tar.gz + COMMENT "Generating deb package" + ) + + # the final target: + add_custom_target(${DEBNAME}_deb + DEPENDS ${CMAKE_BINARY_DIR}/${DEBIAN_PACKAGE_NAME}_${CPACK_PACKAGE_VERSION}-1_${DEBIAN_ARCHITECTURE}.deb + ) + add_dependencies(${DEBNAME}_deb deb_destdir_install) + + + # BUG: debian_package is not removed during a 'make clean': + set_directory_properties(PROPERTIES + ADDITIONAL_MAKE_CLEAN_FILES "debian-binary;control;md5sums;debian_package;") + + endmacro() + endif () +endif() diff --git a/gdcm/CMake/UseDotNETFrameworkSDK.cmake b/gdcm/CMake/UseDotNETFrameworkSDK.cmake new file mode 100644 index 0000000..78509e8 --- /dev/null +++ b/gdcm/CMake/UseDotNETFrameworkSDK.cmake @@ -0,0 +1,6 @@ +# Copyright (c) 2006-2011 Mathieu Malaterre +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# diff --git a/gdcm/CMake/UseJavaTest.cmake b/gdcm/CMake/UseJavaTest.cmake new file mode 100644 index 0000000..00e7c40 --- /dev/null +++ b/gdcm/CMake/UseJavaTest.cmake @@ -0,0 +1,106 @@ +# Add a java test from a java file +# +# Usage: +# set_source_files_properties(test.py PROPERTIES PYTHONPATH +# "${LIBRARY_OUTPUT_PATH}:${VTK_DIR}") +# ADD_PYTHON_TEST(PYTHON-TEST test.py) +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + +# Need python interpreter: +#find_package(PythonInterp REQUIRED) +#mark_as_advanced(PYTHON_EXECUTABLE) +# UseCSharp.cmake + +macro(ADD_JAVA_TEST TESTNAME FILENAME) + get_source_file_property(loc ${FILENAME}.class LOCATION) + get_source_file_property(pyenv ${FILENAME}.class RUNTIMEPATH) + get_source_file_property(theclasspath ${FILENAME}.class CLASSPATH) + get_filename_component(loc2 ${loc} NAME_WE) + + + if(CMAKE_CONFIGURATION_TYPES) + # I cannot use CMAKE_CFG_INTDIR since it expand to "$(OutDir)" + if(pyenv) + set(pyenv "${pyenv};${LIBRARY_OUTPUT_PATH}/${CMAKE_BUILD_TYPE}") + else() + set(pyenv ${LIBRARY_OUTPUT_PATH}/${CMAKE_BUILD_TYPE}) + #set(pyenv ${LIBRARY_OUTPUT_PATH}/${CMAKE_CFG_INTDIR}) + #set(pyenv ${LIBRARY_OUTPUT_PATH}/${CMAKE_CONFIG_TYPE}) + #set(pyenv ${LIBRARY_OUTPUT_PATH}/\${CMAKE_CONFIG_TYPE}) + endif() + else() + if(pyenv) + set(pyenv ${pyenv}:${LIBRARY_OUTPUT_PATH}) + else() + set(pyenv ${LIBRARY_OUTPUT_PATH}) + endif() + endif() + string(REGEX REPLACE ";" " " wo_semicolumn "${ARGN}") + + set(classpath) + if(theclasspath) + set(classpath "${theclasspath}${JavaProp_PATH_SEPARATOR}.") + else() + set(classpath ".") + endif() + set(theld_library_path $ENV{LD_LIBRARY_PATH}) + set(ld_library_path) + if(theld_library_path) + set(ld_library_path ${theld_library_path}) + endif() + if(pyenv) + set(ld_library_path ${ld_library_path}:${pyenv}) + endif() + + file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/${TESTNAME}.cmake +" + if(UNIX) + set(ENV{LD_LIBRARY_PATH} ${ld_library_path}) + set(ENV{DYLD_LIBRARY_PATH} ${ld_library_path}) + #set(ENV{CLASSPATH} ${pyenv}/gdcm.jar:.) + message(\"pyenv: ${pyenv}\") + else() + #set(the_path $ENV{PATH}) + set(ENV{PATH} "${ld_library_path}") + endif() + message(\"loc: ${loc}\") + message(\"loc2: ${loc2}\") + message(\"classpath: ${classpath}\") + message(\"java runtime: ${Java_JAVA_EXECUTABLE}\") + #message( \"wo_semicolumn: ${wo_semicolumn}\" ) + execute_process( + COMMAND ${Java_JAVA_EXECUTABLE} -classpath \"${classpath}\" ${loc2} ${wo_semicolumn} + WORKING_DIRECTORY \"${EXECUTABLE_OUTPUT_PATH}\" + RESULT_VARIABLE import_res + OUTPUT_VARIABLE import_output + ERROR_VARIABLE import_output + ) + + # Pass the output back to ctest + if(import_output) + message("\${import_output}") + endif() + if(import_res) + message(SEND_ERROR "\${import_res}") + endif() +" +) + add_test(NAME ${TESTNAME} COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/${TESTNAME}.cmake) +endmacro() + +# Byte compile recursively a directory (DIRNAME) +#macro(ADD_PYTHON_COMPILEALL_TEST DIRNAME) +# # First get the path: +# get_filename_component(temp_path "${PYTHON_LIBRARIES}" PATH) +# # Find the python script: +# get_filename_component(PYTHON_COMPILE_ALL_PY "${temp_path}/../compileall.py" ABSOLUTE) +# # add test, use DIRNAME to create uniq name for the test: +# add_test(COMPILE_ALL-${DIRNAME} ${PYTHON_EXECUTABLE} "${PYTHON_COMPILE_ALL_PY}" -q ${DIRNAME}) +#endmacro() +# diff --git a/gdcm/CMake/UseMONO.cmake b/gdcm/CMake/UseMONO.cmake new file mode 100644 index 0000000..af95f89 --- /dev/null +++ b/gdcm/CMake/UseMONO.cmake @@ -0,0 +1,45 @@ +# - MONO module for CMake +# Defines the following macros: +# MONO_ADD_MODULE(name language [ files ]) +# - Define swig module with given name and specified language +# MONO_LINK_LIBRARIES(name [ libraries ]) +# - Link libraries to swig module +# All other macros are for internal use only. +# To get the actual name of the swig module, +# use: ${MONO_MODULE_name_REAL_NAME}. +# Set Source files properties such as CPLUSPLUS and MONO_FLAGS to specify +# special behavior of MONO. Also global CMAKE_MONO_FLAGS can be used to add +# special flags to all swig calls. +# Another special variable is CMAKE_MONO_OUTDIR, it allows one to specify +# where to write all the swig generated module (swig -outdir option) +# The name-specific variable MONO_MODULE__EXTRA_DEPS may be used +# to specify extra dependencies for the generated modules. +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + +# +# Create Swig module +# +macro(MONO_ADD_MODULE name) + set(swig_dot_i_sources) + foreach(it ${ARGN}) + set(swig_dot_i_sources ${swig_dot_i_sources} "${it}") + endforeach() + +endmacro() + +# +# Like TARGET_LINK_LIBRARIES but for swig modules +# +macro(MONO_LINK_LIBRARIES name) + if(MONO_MODULE_${name}_REAL_NAME) + target_link_libraries(${MONO_MODULE_${name}_REAL_NAME} ${ARGN}) + else() + message(SEND_ERROR "Cannot find Swig library \"${name}\".") + endif() +endmacro() diff --git a/gdcm/CMake/UsePythonTest.cmake b/gdcm/CMake/UsePythonTest.cmake new file mode 100644 index 0000000..757f2b6 --- /dev/null +++ b/gdcm/CMake/UsePythonTest.cmake @@ -0,0 +1,80 @@ +# Add a python test from a python file +# One cannot simply do: +# set(ENV{PYTHONPATH} ${LIBRARY_OUTPUT_PATH}) +# set(my_test "from test_mymodule import *\;test_mymodule()") +# add_test(PYTHON-TEST-MYMODULE python -c ${my_test}) +# Since cmake is only transmitting the ADD_TEST line to ctest thus you are loosing +# the env var. The only way to store the env var is to physically write in the cmake script +# whatever PYTHONPATH you want and then add the test as 'cmake -P python_test.cmake' +# +# Usage: +# set_source_files_properties(test.py PROPERTIES PYTHONPATH +# "${LIBRARY_OUTPUT_PATH}:${VTK_DIR}") +# ADD_PYTHON_TEST(PYTHON-TEST test.py) +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + +# Need python interpreter: +find_package(PythonInterp REQUIRED) +mark_as_advanced(PYTHON_EXECUTABLE) + +macro(ADD_PYTHON_TEST TESTNAME FILENAME) + get_source_file_property(loc ${FILENAME} LOCATION) + get_source_file_property(pyenv ${FILENAME} PYTHONPATH) + if(CMAKE_CONFIGURATION_TYPES) + # I cannot use CMAKE_CFG_INTDIR since it expand to "$(OutDir)" + if(pyenv) + set(pyenv "${pyenv};${LIBRARY_OUTPUT_PATH}/${CMAKE_BUILD_TYPE}") + else() + set(pyenv ${LIBRARY_OUTPUT_PATH}/${CMAKE_BUILD_TYPE}) + #set(pyenv ${LIBRARY_OUTPUT_PATH}/${CMAKE_CFG_INTDIR}) + #set(pyenv ${LIBRARY_OUTPUT_PATH}/${CMAKE_CONFIG_TYPE}) + #set(pyenv ${LIBRARY_OUTPUT_PATH}/\${CMAKE_CONFIG_TYPE}) + endif() + else() + if(pyenv) + set(pyenv ${pyenv}:${LIBRARY_OUTPUT_PATH}) + else() + set(pyenv ${LIBRARY_OUTPUT_PATH}) + endif() + endif() + string(REGEX REPLACE ";" " " wo_semicolumn "${ARGN}") + file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/${TESTNAME}.cmake +" + set(ENV{PYTHONPATH} ${pyenv}:\$ENV{PYTHONPATH}) + set(ENV{LD_LIBRARY_PATH} ${pyenv}:\$ENV{LD_LIBRARY_PATH}) + message(\"${pyenv}\") + execute_process( + COMMAND ${PYTHON_EXECUTABLE} ${loc} ${wo_semicolumn} + #WORKING_DIRECTORY @LIBRARY_OUTPUT_PATH@ + RESULT_VARIABLE import_res + OUTPUT_VARIABLE import_output + ERROR_VARIABLE import_output + ) + + # Pass the output back to ctest + if(import_output) + message("\${import_output}") + endif() + if(import_res) + message(SEND_ERROR "\${import_res}") + endif() +" +) + add_test(NAME ${TESTNAME} COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/${TESTNAME}.cmake) +endmacro() + +# Byte compile recursively a directory (DIRNAME) +macro(ADD_PYTHON_COMPILEALL_TEST DIRNAME) + # First get the path: + get_filename_component(temp_path "${PYTHON_LIBRARIES}" PATH) + # Find the python script: + get_filename_component(PYTHON_COMPILE_ALL_PY "${temp_path}/../compileall.py" ABSOLUTE) + # add test, use DIRNAME to create uniq name for the test: + add_test(COMPILE_ALL-${DIRNAME} ${PYTHON_EXECUTABLE} "${PYTHON_COMPILE_ALL_PY}" -q ${DIRNAME}) +endmacro() diff --git a/gdcm/CMake/dcmqrscp.cfg.in b/gdcm/CMake/dcmqrscp.cfg.in new file mode 100644 index 0000000..e9fccad --- /dev/null +++ b/gdcm/CMake/dcmqrscp.cfg.in @@ -0,0 +1,20 @@ +# http://support.dcmtk.org/docs/dcmqrscp.html +# http://support.dcmtk.org/docs/file_dcmqrset.html +NetworkType = "tcp" +NetworkTCPPort = 5679 +MaxPDUSize = 16384 +MaxAssociations = 16 +Display = "no" + +HostTable BEGIN +gdcmdash = (GDCMDASH, @DCMQRSCP_HOSTNAME@, @DCMQRSCP_PORT@) +gdcmcompany = gdcmdash +HostTable END + +VendorTable BEGIN +"GDCM Company" = gdcmcompany +VendorTable END + +AETable BEGIN +GDCM_STORE @DCMQRSCP_DIRECTORY@/GDCM_STORE RW (9, 1024mb) gdcmcompany +AETable END diff --git a/gdcm/CMake/gdcmValgrind.supp b/gdcm/CMake/gdcmValgrind.supp new file mode 100644 index 0000000..3923448 --- /dev/null +++ b/gdcm/CMake/gdcmValgrind.supp @@ -0,0 +1,139 @@ +{ + + Memcheck:Param + write(buf) + fun:__write_nocancel + obj:/usr/X11R6/lib/libX11.so.6.2 + fun:_X11TransWrite + obj:/usr/X11R6/lib/libX11.so.6.2 +} +{ + + Memcheck:Free + fun:free + fun:__GI__dl_deallocate_tls + fun:vgArch_thread_exit + fun:thread_exit_wrapper +} +{ + + Memcheck:Leak + fun:malloc + fun:__cxa_get_globals + fun:_ZSt18uncaught_exceptionv + fun:_ZNSo6sentryD1Ev +} +{ + + Memcheck:Leak + fun:malloc + fun:XextCreateExtension + fun:__glXInitialize + fun:glXGetConfig +} +{ + + Memcheck:Leak + fun:calloc + fun:_dlerror_run + fun:dlsym + fun:__errno_location +} +{ + + Memcheck:Leak + fun:malloc + fun:OpenDriver + fun:__glXRegisterExtensions + fun:__glXNewIndirectAPI +} +{ + + Memcheck:Leak + fun:malloc + fun:_dl_map_object_internal + fun:openaux + fun:_dl_catch_error_internal +} +{ + + Memcheck:Leak + fun:malloc + fun:_dl_map_object_deps_internal + fun:dl_open_worker + fun:_dl_catch_error_internal +} +{ + + Memcheck:Leak + fun:malloc + fun:__glXstrdup + fun:OpenDriver + fun:__glXRegisterExtensions +} +{ + + Memcheck:Leak + fun:malloc + fun:_dl_map_object_internal + fun:dl_open_worker + fun:_dl_catch_error_internal +} +{ + + Memcheck:Leak + fun:malloc + fun:_dl_new_object + fun:_dl_map_object_from_fd + fun:_dl_map_object_internal +} +{ + + Memcheck:Leak + fun:malloc + fun:dl_open_worker + fun:_dl_catch_error_internal + fun:__GI__dl_open +} +{ + + Memcheck:Leak + fun:calloc + fun:_dl_check_map_versions_internal + fun:dl_open_worker + fun:_dl_catch_error_internal +} +{ + + Memcheck:Leak + fun:calloc + fun:_dl_new_object + fun:_dl_map_object_from_fd + fun:_dl_map_object_internal +} +{ + + Memcheck:Leak + fun:malloc + fun:__glXNewIndirectAPI + fun:glXMakeCurrent + fun:_ZN22vtkXOpenGLRenderWindow11MakeCurrentEv +} +{ + + Memcheck:Leak + fun:malloc + fun:__fgl_glapi_add_entrypoint + fun:__driRegisterExtensions + fun:__glXRegisterExtensions +} +{ + + Memcheck:Cond + obj:/lib/ld-2.3.6.so + obj:/lib/ld-2.3.6.so + obj:/lib/ld-2.3.6.so + obj:/lib/ld-2.3.6.so + obj:/lib/ld-2.3.6.so + obj:/lib/ld-2.3.6.so +} diff --git a/gdcm/CMakeLists.txt b/gdcm/CMakeLists.txt new file mode 100644 index 0000000..b5c434c --- /dev/null +++ b/gdcm/CMakeLists.txt @@ -0,0 +1,1014 @@ +cmake_minimum_required(VERSION 2.8.9) +if(POLICY CMP0025) + cmake_policy(SET CMP0025 NEW) +endif() +if(POLICY CMP0042) + cmake_policy(SET CMP0042 NEW) +endif() +project(GDCM) +mark_as_advanced(CMAKE_BACKWARDS_COMPATIBILITY CMAKE_BUILD_TYPE CMAKE_INSTALL_PREFIX) +set(GDCM_CMAKE_DIR "${GDCM_SOURCE_DIR}/CMake" CACHE INTERNAL "") +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${GDCM_CMAKE_DIR}") + +set(GDCM_PACKAGE_DESCRIPTION_SUMMARY "GDCM - Grassroots DICOM. GDCM is yet another DICOM library.") +set(GDCM_PACKAGE_CONTACT "GDCM Developers ") + +# TODO +# http://www.vtk.org/pipermail/vtkusers/2007-May/090968.html +# +# False memory leak reports are caused by VTK dlls loading *before* MFC dlls. +# You have to use the linker's /delayload flag to avoid this issue. +# +# The /delayload flag should be correct by default in the MFC examples if you +# are using CVS VTK... If you are using a previous version of VTK (5.0 or +# earlier) then you will have to figure out a way to link with that flag. +# +# See the CVS version of files in VTK/GUISupport/MFC for details. Or grep the +# VTK source tree for "DELAYLOAD" + +#----------------------------------------------------------------------------- +# Disallow insource build since I never test that +string(COMPARE EQUAL "${GDCM_SOURCE_DIR}" "${GDCM_BINARY_DIR}" INSOURCE) +get_filename_component(PARENTDIR ${GDCM_BINARY_DIR} PATH) +string(COMPARE EQUAL "${GDCM_SOURCE_DIR}" "${PARENTDIR}" INSOURCESUBDIR) +if(INSOURCE OR INSOURCESUBDIR) + message(FATAL_ERROR "GDCM requires an out of source Build. " + "Please create a separate binary directory and run CMake there.") +endif() + +#---------------------------------------------------------------------------- +set(GDCM_MAJOR_VERSION 2) +set(GDCM_MINOR_VERSION 4) +set(GDCM_BUILD_VERSION 2) +set(GDCM_VERSION + "${GDCM_MAJOR_VERSION}.${GDCM_MINOR_VERSION}.${GDCM_BUILD_VERSION}") +# let advanced user the option to define GDCM_API_VERSION: +if(NOT DEFINED GDCM_API_VERSION) + set(GDCM_API_VERSION "${GDCM_MAJOR_VERSION}.${GDCM_MINOR_VERSION}") +endif() +set(GDCM_LIBRARY_PROPERTIES ${GDCM_LIBRARY_PROPERTIES} + VERSION "${GDCM_VERSION}" + SOVERSION "${GDCM_API_VERSION}" +) +#set(GDCM_EXECUTABLE_PROPERTIES ${GDCM_EXECUTABLE_PROPERTIES} +# VERSION "${GDCM_MAJOR_VERSION}.${GDCM_MINOR_VERSION}" +#) +set(GDCM_EXECUTABLE_PROPERTIES) +if(GDCM_NO_EXECUTABLE_PROPERTIES) + set(GDCM_EXECUTABLE_PROPERTIES) + set(python_site_package "python/dist-packages") +else() + set(python_site_package "") +endif() + +set(GDCM_STANDALONE 0) +# Top level project (eg. ITK) should set GDCM_TARGETS_NAME +# to define a particular behavior where GDCM does not call +# install(EXPORT...) +# This sets the default value for GDCM_STANDALONE +if(NOT GDCM_TARGETS_NAME) + set(GDCM_TARGETS_NAME GDCMTargets) + set(GDCM_STANDALONE 1) +endif() +#----------------------------------------------------------------------------- +# PDB handling + Module handling +include(${GDCM_SOURCE_DIR}/CMake/InstallMacros.cmake) +#----------------------------------------------------------------------------- +include(${GDCM_SOURCE_DIR}/CMake/UseCopyright.cmake) +CREATE_COPYRIGHT_FILE(${CMAKE_CURRENT_BINARY_DIR}/Copyright.txt) +APPEND_COPYRIGHT(${CMAKE_CURRENT_SOURCE_DIR}/Copyright.txt) +APPEND_COPYRIGHT(${CMAKE_CURRENT_SOURCE_DIR}/CMake/COPYING-CMAKE-SCRIPTS) + +#----------------------------------------------------------------------------- +if(GDCM_MINOR_VERSION MATCHES "[02468]$") + # Are we building a release branch / tag (read: even number)? + # By default dashboard are expected to run with Design by Contract on + # to trigger any of the assert, but on the other hand no user really + # can figure out they need to change this value + # So unless the user *specifically* requested a particular cmake_build_type + # do the work internally and append the NDEBUG def flag (hopefully portable) + if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DNDEBUG") + endif() + # Since we are on a release branch, chance is that people don't care about testing + # let's disable it for them + set(GDCM_BUILD_TESTING_DEFAULT OFF) +else() + set(GDCM_BUILD_TESTING_DEFAULT ON) +endif() + +#----------------------------------------------------------------------------- +# Disable deprecation warnings for standard C and STL functions in VS2005 +# and later +if(MSVC_VERSION EQUAL 1400 OR MSVC_VERSION GREATER 1400) + add_definitions(-D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS) + add_definitions(-D_SCL_SECURE_NO_DEPRECATE -D_SCL_SECURE_NO_WARNINGS) +endif() + +#----------------------------------------------------------------------------- +# Build shared lib by default +if(GDCM_STANDALONE) + option(GDCM_BUILD_SHARED_LIBS "Build GDCM with shared libraries." OFF) + set(BUILD_SHARED_LIBS ${GDCM_BUILD_SHARED_LIBS}) +else() + set(GDCM_BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS}) +endif() + +if(BUILD_SHARED_LIBS) +if(${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.6) + set(NAMELINK_ONLY NAMELINK_ONLY) + set(NAMELINK_SKIP NAMELINK_SKIP) +else() + set(NAMELINK_ONLY) + set(NAMELINK_SKIP) +endif() +endif() + + +#----------------------------------------------------------------------------- +if(NOT EXECUTABLE_OUTPUT_PATH) + set(EXECUTABLE_OUTPUT_PATH ${GDCM_BINARY_DIR}/bin CACHE PATH "Single output directory for building all executables.") + mark_as_advanced(EXECUTABLE_OUTPUT_PATH) +endif() +if(NOT LIBRARY_OUTPUT_PATH) + set(LIBRARY_OUTPUT_PATH ${GDCM_BINARY_DIR}/bin CACHE PATH "Single output directory for building all libraries.") + mark_as_advanced(LIBRARY_OUTPUT_PATH) +endif() + +#----------------------------------------------------------------------------- +# Adding GDCM_DATA_ROOT +if(GDCM_STANDALONE) + find_path(GDCM_DATA_ROOT test.acr + ${GDCM_SOURCE_DIR}/Testing/Data + $ENV{GDCM_DATA_ROOT} + ) + mark_as_advanced(GDCM_DATA_ROOT) +# You can define a path where you extra the famous D. Clunie spacing dataset +# http://www.dclunie.com/images/pixelspacingtestimages.zip +# for example: +# find $HOME/pixelspacingtestimages +# $HOME/pixelspacingtestimages +# $HOME/pixelspacingtestimages/DISCIMG +# $HOME/pixelspacingtestimages/DISCIMG/DICOMDIR +# $HOME/pixelspacingtestimages/DISCIMG/IMAGES +# $HOME/pixelspacingtestimages/DISCIMG/IMAGES/DXIMAGE +# $HOME/pixelspacingtestimages/DISCIMG/IMAGES/MGIMAGE +# $HOME/pixelspacingtestimages/DISCIMG/IMAGES/CRIMAGE + mark_as_advanced(GDCM_PIXEL_SPACING_DATA_ROOT) + +#----------------------------------------------------------------------------- + find_path(GDCM_DATA_EXTRA_ROOT gdcmData.tar.gz + ${GDCM_SOURCE_DIR}/../gdcmDataExtra + $ENV{GDCM_DATA_EXTRA_ROOT} + $ENV{PUB_DICT_PATH}/../../gdcmDataExtra + ) + mark_as_advanced(GDCM_DATA_EXTRA_ROOT) +endif() + +# Define a temp directory in which we can output stuff +set(GDCM_TEMP_DIRECTORY "${GDCM_BINARY_DIR}/Testing/Temporary" CACHE PATH "Path to a valid temp directory") +mark_as_advanced(GDCM_TEMP_DIRECTORY) + +#----------------------------------------------------------------------------- +include(${CMAKE_ROOT}/Modules/CheckIncludeFile.cmake) +include(${CMAKE_ROOT}/Modules/CheckIncludeFiles.cmake) +# Check if header file exists and add it to the list. +macro(CHECK_INCLUDE_FILE_CONCAT FILE VARIABLE) + CHECK_INCLUDE_FILES("${UUID_INCLUDES};${FILE}" ${VARIABLE}) + if(${VARIABLE}) + set(UUID_INCLUDES ${UUID_INCLUDES} ${FILE}) + endif() +endmacro() + +CHECK_INCLUDE_FILE("stdint.h" GDCM_HAVE_STDINT_H) +if(UNIX) #Avoid polluting Win32 cmakecache + CHECK_INCLUDE_FILE("inttypes.h" GDCM_HAVE_INTTYPES_H) +endif() + +#include(${GDCM_SOURCE_DIR}/CMake/gdcmPlatformCxxTests.cmake) +# +#GDCM_PLATFORM_CXX_TEST(GDCM_CXX_HAS_FUNCTION +# "Checking whether compiler has __FUNCTION__" DIRECT) + + +#----------------------------------------------------------------------------- +# Build the main lib... +if(NOT GDCM_HAVE_STDINT_H) + if(MSVC) + include_directories( + "${GDCM_SOURCE_DIR}/Utilities/C99" + ) + # Process the install rules from C99 + subdirs(Utilities/C99) + endif() +endif() + +# -------------------------------------------------------------------------- +# Configure the export configuration + +# You will also need to define a value for the following variables: +# GDCM_INSTALL_BIN_DIR - binary dir (executables) +# GDCM_INSTALL_LIB_DIR - library dir (libs) +# GDCM_INSTALL_DATA_DIR - share dir (say, examples, data, etc) +# GDCM_INSTALL_INCLUDE_DIR - include dir (headers) +# GDCM_INSTALL_PACKAGE_DIR - package/export configuration files +# GDCM_VTK_INSTALL_PACKAGE_DIR - VTK package/export configuration files +# GDCM_INSTALL_NO_DEVELOPMENT - do not install development files +# GDCM_INSTALL_NO_RUNTIME - do not install runtime files +# GDCM_INSTALL_NO_DOCUMENTATION - do not install documentation files + +# GDCM_INSTALL_PYTHONMODULE_DIR - Python Module install dir +# GDCM_VTK_INSTALL_PYTHONMODULE_DIR - VTK/Python Module install dir +# GDCM_INSTALL_CSHARPMODULE_DIR - C# Module install dir +# GDCM_VTK_INSTALL_CSHARPMODULE_DIR - VTK/C# Module install dir +# GDCM_INSTALL_JAVAMODULE_DIR - Java Module install dir (JNI glue) +# GDCM_INSTALL_JARMODULE_DIR - Java Module install dir (JAR) +# GDCM_VTK_INSTALL_JAVAMODULE_DIR - VTK/Java Module install dir (JNI glue) +# GDCM_VTK_INSTALL_JARMODULE_DIR - VTK/Java Module install dir (JAR) + +# -------------------------------------------------------------------------- +# Install directories + +string(TOLOWER ${PROJECT_NAME} projectname) +set(subdir "${projectname}-${GDCM_MAJOR_VERSION}.${GDCM_MINOR_VERSION}") + +if(NOT GDCM_INSTALL_BIN_DIR) + set(GDCM_INSTALL_BIN_DIR "bin") +endif() + +if(NOT GDCM_INSTALL_LIB_DIR) + #set(GDCM_INSTALL_LIB_DIR "lib/${PROJECT_NAME}") + set(GDCM_INSTALL_LIB_DIR "lib") +endif() + +if(NOT GDCM_INSTALL_DATA_DIR) + set(GDCM_INSTALL_DATA_DIR "share/${subdir}") +endif() + +if(NOT GDCM_INSTALL_INCLUDE_DIR) + set(GDCM_INSTALL_INCLUDE_DIR "include/${subdir}") +endif() + +if(NOT GDCM_INSTALL_DOC_DIR) + set(GDCM_INSTALL_DOC_DIR "share/doc/${subdir}") +endif() + +if(NOT GDCM_INSTALL_MAN_DIR) + set(GDCM_INSTALL_MAN_DIR "share/man") +endif() + +if(NOT GDCM_INSTALL_PACKAGE_DIR) + set(GDCM_INSTALL_PACKAGE_DIR ${GDCM_INSTALL_LIB_DIR}/${subdir} + CACHE INTERNAL "") +endif() + +if(NOT GDCM_VTK_INSTALL_PACKAGE_DIR) + set(GDCM_VTK_INSTALL_PACKAGE_DIR ${VTK_INSTALL_PACKAGE_DIR}) +endif() + +if(NOT GDCM_INSTALL_NO_DEVELOPMENT) + set(GDCM_INSTALL_NO_DEVELOPMENT 0) +endif() + +if(NOT GDCM_INSTALL_NO_RUNTIME) + set(GDCM_INSTALL_NO_RUNTIME 0) +endif() + +if(NOT GDCM_INSTALL_NO_DOCUMENTATION) + set(GDCM_INSTALL_NO_DOCUMENTATION 0) +endif() + +set(GDCM_INSTALL_NO_LIBRARIES) +if(GDCM_BUILD_SHARED_LIBS) + if(GDCM_INSTALL_NO_RUNTIME AND GDCM_INSTALL_NO_DEVELOPMENT) + set(GDCM_INSTALL_NO_LIBRARIES 1) + endif() +else() + if(GDCM_INSTALL_NO_DEVELOPMENT) + set(GDCM_INSTALL_NO_LIBRARIES 1) + endif() +endif() + +if(NOT GDCM_INSTALL_PYTHONMODULE_DIR) + set(GDCM_INSTALL_PYTHONMODULE_DIR ${GDCM_INSTALL_LIB_DIR}/${python_site_package}) +endif() +if(NOT GDCM_VTK_INSTALL_PYTHONMODULE_DIR) + set(GDCM_VTK_INSTALL_PYTHONMODULE_DIR ${GDCM_INSTALL_PYTHONMODULE_DIR}) +endif() +if(NOT GDCM_INSTALL_CSHARPMODULE_DIR) + set(GDCM_INSTALL_CSHARPMODULE_DIR ${GDCM_INSTALL_LIB_DIR}) +endif() +if(NOT GDCM_VTK_INSTALL_CSHARPMODULE_DIR) + set(GDCM_VTK_INSTALL_CSHARPMODULE_DIR ${GDCM_INSTALL_CSHARPMODULE_DIR}) +endif() +if(NOT GDCM_INSTALL_JAVAMODULE_DIR) + set(GDCM_INSTALL_JAVAMODULE_DIR ${GDCM_INSTALL_LIB_DIR}) +endif() +if(NOT GDCM_VTK_INSTALL_JAVAMODULE_DIR) + set(GDCM_VTK_INSTALL_JAVAMODULE_DIR ${GDCM_INSTALL_JAVAMODULE_DIR}) +endif() +if(NOT GDCM_INSTALL_JARMODULE_DIR) + set(GDCM_INSTALL_JARMODULE_DIR ${GDCM_INSTALL_LIB_DIR}) +endif() +if(NOT GDCM_VTK_INSTALL_JARMODULE_DIR) + set(GDCM_VTK_INSTALL_JARMODULE_DIR ${GDCM_INSTALL_JARMODULE_DIR}) +endif() + +#----------------------------------------------------------------------------- +#System stuff, mainly for packager or paranoid people with up-to-date lib moto +option(GDCM_USE_SYSTEM_ZLIB "Use system zlib" OFF) +option(GDCM_USE_SYSTEM_OPENSSL "Use system OpenSSL" OFF) +if(UNIX) + # Will search for the uuid_generate symbols. + # Can be in libSystem.dylib or libuuid.so + option(GDCM_USE_SYSTEM_UUID "Use system uuid" OFF) +endif() +option(GDCM_USE_SYSTEM_EXPAT "Use system expat" OFF) +option(GDCM_USE_SYSTEM_JSON "Use system json" OFF) +option(GDCM_USE_SYSTEM_PAPYRUS3 "Use system papyrus3" OFF) +option(GDCM_USE_SYSTEM_SOCKETXX "Use system socket++" OFF) +option(GDCM_USE_SYSTEM_LJPEG "Use system ljpeg (ijg lib)" OFF) +option(GDCM_USE_SYSTEM_OPENJPEG "Use system openjpeg" OFF) +option(GDCM_USE_SYSTEM_CHARLS "Use system charls" OFF) +mark_as_advanced( + GDCM_USE_SYSTEM_ZLIB + GDCM_USE_SYSTEM_OPENSSL + GDCM_USE_SYSTEM_UUID + GDCM_USE_SYSTEM_EXPAT + GDCM_USE_SYSTEM_JSON + GDCM_USE_SYSTEM_PAPYRUS3 + GDCM_USE_SYSTEM_SOCKETXX + GDCM_USE_SYSTEM_LJPEG + GDCM_USE_SYSTEM_OPENJPEG + GDCM_USE_SYSTEM_CHARLS + ) +option(GDCM_USE_SYSTEM_POPPLER "Use system poppler (pdf)" OFF) +if(GDCM_USE_SYSTEM_POPPLER) + find_package(Poppler REQUIRED) +endif() +mark_as_advanced(GDCM_USE_SYSTEM_POPPLER) + +option(GDCM_USE_SYSTEM_LIBXML2 "Use LibXml2" OFF) +if(GDCM_USE_SYSTEM_LIBXML2) + find_package(LibXml2) +endif() +mark_as_advanced(GDCM_USE_SYSTEM_LIBXML2) + +if(GDCM_USE_SYSTEM_LJPEG) + find_package(LJPEG REQUIRED) + set(GDCM_LJPEG_LIBRARIES ${LJPEG_LIBRARIES}) +else() + set(GDCM_LJPEG_LIBRARIES gdcmjpeg8 gdcmjpeg12 gdcmjpeg16) +endif() + +if(GDCM_USE_SYSTEM_CHARLS) + find_package(CharLS REQUIRED) + set(GDCM_CHARLS_LIBRARIES ${CHARLS_LIBRARIES}) +else() + set(GDCM_CHARLS_LIBRARIES gdcmcharls) +endif() + +if(GDCM_USE_SYSTEM_OPENJPEG) + # For some reason I cannot specify the version I want. + # find_package(OpenJPEG 2.0 REQUIRED) + # oh well we should handle both 1.0 and 2.0 anyway... + find_package(OpenJPEG REQUIRED) + set(GDCM_OPENJPEG_LIBRARIES ${OPENJPEG_LIBRARIES}) +else() + set(GDCM_OPENJPEG_LIBRARIES gdcmopenjpeg) + option(GDCM_USE_OPENJPEG_V2 "Use openjpeg v2 version (advanced users only)." OFF) + mark_as_advanced(GDCM_USE_OPENJPEG_V2) +endif() + +# Very advanced user option: +# This will cause building of the broken JPEG library released by the Standford PVRG group: +option(GDCM_USE_PVRG "Use pvrg lib, only turn it on if you know what you are doing." OFF) +mark_as_advanced(GDCM_USE_PVRG) + +option(GDCM_USE_KAKADU "Use kakadu lib, only turn it on if you know what you are doing." OFF) +mark_as_advanced(GDCM_USE_KAKADU) + +if(GDCM_USE_PVRG) + option(GDCM_USE_SYSTEM_PVRG "Use system PVRG" OFF) + mark_as_advanced(GDCM_USE_SYSTEM_PVRG) + if(GDCM_USE_SYSTEM_PVRG) + find_package(PVRGJPEG REQUIRED) + endif() +endif() + +# Very advanced behavior only use if you want to keep backward compatible +# behavior but possibly incorrect behavior. +option(GDCMV2_0_COMPATIBILITY "Preserve compatibility with GDCM 2.0 release" ON) +mark_as_advanced(GDCMV2_0_COMPATIBILITY) + +if(GDCM_USE_KAKADU) + option(GDCM_USE_SYSTEM_KAKADU "Use system KAKADU " ON) + mark_as_advanced(GDCM_USE_SYSTEM_KAKADU) + if(GDCM_USE_SYSTEM_KAKADU) + find_package(KAKADU REQUIRED) + else() + message(FATAL_ERROR "Not Implemented") + endif() +endif() + +if(GDCM_USE_SYSTEM_ZLIB) + # If user say so, then this is a requirement ! + find_package(ZLIB REQUIRED) + set(GDCM_ZLIB_LIBRARIES ${ZLIB_LIBRARIES}) +else() + set(GDCM_ZLIB_LIBRARIES "gdcmzlib") +endif() + +if(GDCM_USE_SYSTEM_OPENSSL) + find_package(OpenSSL REQUIRED) +endif() + +if(GDCM_USE_SYSTEM_UUID) + # If user say so, then this is a requirement ! + find_package(UUID REQUIRED) + set(GDCM_UUID_LIBRARIES ${UUID_LIBRARIES}) +else() + set(GDCM_UUID_LIBRARIES "gdcmuuid") +endif() + +if(GDCM_USE_SYSTEM_EXPAT) + # If user say so, then this is a requirement ! + find_package(EXPAT REQUIRED) + set(GDCM_EXPAT_LIBRARIES ${EXPAT_LIBRARIES}) +else() + set(GDCM_EXPAT_LIBRARIES "gdcmexpat") +endif() + +if(GDCM_USE_SYSTEM_JSON) + find_package(JSON REQUIRED) +endif() +if(GDCM_USE_SYSTEM_PAPYRUS3) + find_package(PAPYRUS3 REQUIRED) +endif() + +#----------------------------------------------------------------------------- +if(GDCM_STANDALONE) + option(GDCM_BUILD_EXAMPLES "Build GDCM examples." OFF) + set(BUILD_EXAMPLES ${GDCM_BUILD_EXAMPLES}) +else() + set(GDCM_BUILD_EXAMPLES OFF) + set(BUILD_EXAMPLES OFF) +endif() +#----------------------------------------------------------------------------- +# Add the testing directories +if(GDCM_STANDALONE) + option(GDCM_BUILD_TESTING "Build testing." ${GDCM_BUILD_TESTING_DEFAULT}) + set(BUILD_TESTING ${GDCM_BUILD_TESTING}) # CACHE BOOL "" FORCE) +else() + set(GDCM_BUILD_TESTING OFF) + set(BUILD_TESTING OFF) +endif() +# Hide BUILD_TESTING as user tend to always turn all options on and then complains when something +# does not work 'by default' +mark_as_advanced(BUILD_TESTING) # GDCM_BUILD_TESTING) + +#----------------------------------------------------------------------------- +if(GDCM_TESTING_USE_LC_NUMERIC) + set(CMAKE_TESTDRIVER_BEFORE_TESTMAIN + "setlocale(LC_ALL,\"fr_FR.UTF-8\");std::locale::global(std::locale(\"fr_FR.UTF-8\"));" + ) +endif() + +#----------------------------------------------------------------------------- +# Python install +#find_package(PythonInterp REQUIRED) +#macro(GET_PYTHON_SITE_PACKAGE dir) +# execute_process( +# COMMAND ${PYTHON_EXECUTABLE} "-c" "from distutils import sysconfig; print sysconfig.get_python_lib()" +# #WORKING_DIRECTORY @LIBRARY_OUTPUT_PATH@ +# RESULT_VARIABLE import_res +# OUTPUT_VARIABLE import_output +# ERROR_VARIABLE import_error +# OUTPUT_STRIP_TRAILING_WHITESPACE +# ) +# #set(dir ${import_output}) +#endmacro() +# +# +#GET_PYTHON_SITE_PACKAGE(python_site_package) +#if(import_output) +#string(LENGTH ${import_output} len) +## let's remove the "/usr/lib" part... +#math(EXPR fileend "${len} - 9") +#string(SUBSTRING ${import_output} 9 ${fileend} dummy1) +#if(UNIX) +# set(python_site_package ${dummy1}) +# message(${python_site_package}) +#endif() +#endif() + +# On unix one have: "python2.4/site-packages" +# while on Win32: "c:/Python24/Lib/site-packages/" +# give up for now and place python modules stuff in a general 'python' subdir + +# Typical runtime env should be then +# (assuming CMAKE_INSTALL_PREFIX:PATH=/tmp/local) +# One would do: +# export PYTHONPATH=/tmp/local/lib/python/site-packages/gdcm-2.1 +# export LD_LIBRARY_PATH=/tmp/local/lib/ +# python +# > import gdcm + + +#----------------------------------------------------------------------------- +# Wrapping +if(GDCM_STANDALONE) + option(GDCM_WRAP_PYTHON "build python wrapping" OFF) + option(GDCM_WRAP_PERL "build perl wrapping (experimental !)" OFF) + option(GDCM_WRAP_PHP "build php wrapping" OFF) + option(GDCM_WRAP_JAVA "build java wrapping" OFF) + option(GDCM_WRAP_CSHARP "build csharp wrapping" OFF) + mark_as_advanced(GDCM_WRAP_PERL) + mark_as_advanced(GDCM_USE_RLE) + mark_as_advanced(GDCM_USE_ACTIVIZ) + option(GDCM_USE_JPEGLS "Build GDCM with JPEG-LS support" ON) + mark_as_advanced(GDCM_USE_JPEGLS) + if(GDCM_WRAP_CSHARP) + find_package(CSharp REQUIRED) + include(${CSharp_USE_FILE}) + endif() +endif() + +set(GDCM_LIBRARY_DIR ${LIBRARY_OUTPUT_PATH}/${CMAKE_CFG_INTDIR}) +set(GDCM_EXECUTABLE_DIR ${EXECUTABLE_OUTPUT_PATH}/${CMAKE_CFG_INTDIR}) + +#----------------------------------------------------------------------------- +# we need to link against CoreFoundation so that we can use CFBundle to get the executable path. +if(APPLE) + find_library(COREFOUNDATION_LIBRARY CoreFoundation ) +endif() + +#----------------------------------------------------------------------------- +# Allow user to set a postfix symbol to a target library name (eg. 'd') +if(WIN32) + set(GDCM_DEBUG_POSTFIX "" CACHE STRING "Globally append a debug postfix symbols on all libraries") + if(GDCM_DEBUG_POSTFIX) + set(CMAKE_DEBUG_POSTFIX "${GDCM_DEBUG_POSTFIX}") + endif() + mark_as_advanced(GDCM_DEBUG_POSTFIX) +endif() +#----------------------------------------------------------------------------- + +# Need to subdirs in Source/Common before Wrapping +# to have gdcmConfigure.h around +subdirs(Utilities) +add_subdirectory(Source) + +if(GDCM_STANDALONE) + subdirs(Wrapping) + if(GDCM_WRAP_CSHARP) + add_subdirectory(Wrapping/Csharp) + endif() +endif() + +if(GDCM_STANDALONE) + # After Wrapping please + if(BUILD_EXAMPLES) + subdirs(Examples) + endif() +endif() + +#----------------------------------------------------------------------------- +# Special CMake Module required when doing Python Testing +if(GDCM_STANDALONE) + if(BUILD_TESTING AND GDCM_WRAP_PYTHON) + include(${GDCM_SOURCE_DIR}/CMake/UsePythonTest.cmake) + endif() + +# Special CMake Module required when doing C# Testing + if(BUILD_TESTING AND GDCM_WRAP_CSHARP) + include(${GDCM_SOURCE_DIR}/CMake/UseCSharpTest.cmake) + endif() + +# Special CMake Module required when doing Java Testing + if(BUILD_TESTING AND GDCM_WRAP_JAVA) + include(${GDCM_SOURCE_DIR}/CMake/UseJavaTest.cmake) + endif() +endif() +#----------------------------------------------------------------------------- +# Need pthread for the following class: +CHECK_INCLUDE_FILE("pthread.h" GDCM_HAVE_PTHREAD_H) + +# Big endian thing: +if(GDCM_STANDALONE) + include(${CMAKE_ROOT}/Modules/TestBigEndian.cmake) + TEST_BIG_ENDIAN(GDCM_WORDS_BIGENDIAN) +endif() + +if(GDCM_STANDALONE) + if(BUILD_TESTING) + configure_file(${GDCM_SOURCE_DIR}/CMake/CTestCustom.ctest.in + ${GDCM_BINARY_DIR}/CMake/CTestCustom.ctest @ONLY) + file(WRITE ${GDCM_BINARY_DIR}/CTestCustom.cmake + "include(\"${GDCM_BINARY_DIR}/CMake/CTestCustom.ctest\")\n") + mark_as_advanced(DART_TESTING_TIMEOUT) + enable_testing() + include(CTest) + subdirs(Testing) + if(NOT GDCM_DATA_ROOT) + message("If you want to build the test suite, you must set GDCM_DATA_ROOT (advanced option) " + "to the full path name of the gdcmData directory; if you don't want, disable GDCM_BUILD_TESTING.\n" + "What is gdcmData? Please read: http://gdcm.sourceforge.net/wiki/index.php/General_questions#What_is_gdcmData_.3F") + endif() + endif() +endif() + +#----------------------------------------------------------------------------- +if(GDCM_STANDALONE) + option(GDCM_DOCUMENTATION "Build source documentation using doxygen." OFF) + if(GDCM_DOCUMENTATION) + option(GDCM_PDF_DOCUMENTATION "Build source doxygen using doxygen as pdf" ON) + mark_as_advanced(GDCM_PDF_DOCUMENTATION) + endif() +endif() + +#----------------------------------------------------------------------------- +if(GDCM_STANDALONE) + option(GDCM_USE_VTK "vtk bridge ?" OFF) + if(GDCM_USE_VTK AND GDCM_WRAP_CSHARP) + option(GDCM_USE_ACTIVIZ "vtk/Activiz bridge ?" OFF) + endif() + + if(GDCM_USE_VTK) + option(GDCM_USE_PARAVIEW "paraview plugin ?" OFF) + # needed here so that we have VTK_WRAP_PYTHON and al. available + find_package(VTK REQUIRED) + mark_as_advanced(VTK_DIR) + mark_as_advanced(GDCM_USE_PARAVIEW) + subdirs(Utilities/VTK) + endif() +endif() +#----------------------------------------------------------------------------- +option(GDCM_USE_WXWIDGETS "wxWidgets bridge ?" OFF) +mark_as_advanced(GDCM_USE_WXWIDGETS) +if(GDCM_USE_WXWIDGETS) + subdirs(Utilities/wxWidgets) +endif() + +#----------------------------------------------------------------------------- +if(GDCM_STANDALONE) + option(GDCM_BUILD_APPLICATIONS "apps ?" OFF) + set(BUILD_APPLICATIONS ${GDCM_BUILD_APPLICATIONS}) + if(BUILD_APPLICATIONS) + subdirs(Applications) + endif() +else() + set(BUILD_APPLICATIONS OFF) + set(GDCM_BUILD_APPLICATIONS OFF) +endif() +#----------------------------------------------------------------------------- +if(GDCM_USE_VTK) +if(WIN32) +include(CMake/InstallRequiredVTKLibraries.cmake) +endif() +endif() + +#----------------------------------------------------------------------------- +# CPack stuff +if(GDCM_STANDALONE) # disabled for ITK distribution of gdcm + if(EXISTS "${CMAKE_ROOT}/Modules/CPack.cmake") + if(EXISTS "${CMAKE_ROOT}/Modules/InstallRequiredSystemLibraries.cmake") + set(CMAKE_INSTALL_MFC_LIBRARIES 0) + set(CMAKE_INSTALL_DEBUG_LIBRARIES 0) + if(NOT DEFINED CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS) + set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS ON) + endif() + include(${CMAKE_ROOT}/Modules/InstallRequiredSystemLibraries.cmake) + endif() + + set(CPACK_PACKAGE_DESCRIPTION_SUMMARY ${GDCM_PACKAGE_DESCRIPTION_SUMMARY}) + set(CPACK_PACKAGE_VENDOR "GDCM") + set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_BINARY_DIR}/Copyright.txt") + set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_BINARY_DIR}/Copyright.txt") + set(CPACK_PACKAGE_VERSION_MAJOR "${GDCM_MAJOR_VERSION}") + set(CPACK_PACKAGE_VERSION_MINOR "${GDCM_MINOR_VERSION}") + set(CPACK_PACKAGE_VERSION_PATCH "${GDCM_BUILD_VERSION}") + set(CPACK_PACKAGE_INSTALL_DIRECTORY "GDCM ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}") + set(CPACK_SOURCE_PACKAGE_FILE_NAME "gdcm-${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}") + + if(WIN32 AND NOT UNIX) + # There is a bug in NSIS that does not handle full UNIX paths properly. Make + # sure there is at least one set of four (4) backlashes. + set(CPACK_NSIS_INSTALLED_ICON_NAME "bin\\\\gdcmviewer.exe") + set(CPACK_NSIS_DISPLAY_NAME "${CPACK_PACKAGE_INSTALL_DIRECTORY}") + set(CPACK_NSIS_HELP_LINK "http://gdcm.sourceforge.net") + set(CPACK_NSIS_URL_INFO_ABOUT "http://gdcm.sourceforge.net") + set(CPACK_NSIS_MODIFY_PATH ON) + # if(${CMAKE_INSTALL_PREFIX} MATCHES ${CPACK_PACKAGE_INSTALL_DIRECTORY}) + # else() + # string(REPLACE ${PROJECT_NAME} ${CPACK_PACKAGE_INSTALL_DIRECTORY} dummy ${CMAKE_INSTALL_PREFIX} ) + # set(CMAKE_INSTALL_PREFIX ${dummy} CACHE PATH "" FORCE) + # endif() + + else() + set(CPACK_STRIP_FILES TRUE) + set(CPACK_SOURCE_STRIP_FILES "") + set(CPACK_PACKAGE_EXECUTABLES "gdcmviewer" "VIEWER") + endif() + + # cygwin stff also copied from cmake + #if(NOT DEFINED CPACK_PACKAGE_FILE_NAME) + # # if the CPACK_PACKAGE_FILE_NAME is not defined by the cache + # # default to source package - system, on cygwin system is not + # # needed + # if(CYGWIN) + # set(CPACK_PACKAGE_FILE_NAME "${CPACK_SOURCE_PACKAGE_FILE_NAME}") + # else() + # set(CPACK_PACKAGE_FILE_NAME + # "${CPACK_SOURCE_PACKAGE_FILE_NAME}-${CPACK_SYSTEM_NAME}") + # endif() + #endif() + + #Cygwin stuff copied from cmake + if(NOT DEFINED CPACK_SYSTEM_NAME) + # make sure package is not Cygwin-unknown, for Cygwin just + # cygwin is good for the system name + if("${CMAKE_SYSTEM_NAME}" STREQUAL "CYGWIN") + set(CPACK_SYSTEM_NAME Cygwin) + else() + #set(CMAKE_SYSTEM_PROCESSOR "x86_64") + #set(CPACK_GENERATOR "TGZ;TBZ2") + #set(CPACK_SOURCE_GENERATOR "TGZ;TBZ2") + set(CPACK_SYSTEM_NAME ${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}) + endif() + endif() + + # Need to set the architecture for debian package + set(CPACK_PACKAGE_CONTACT ${GDCM_PACKAGE_CONTACT}) + set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6, libstdc++6 (>= 4.0.2-4), libuuid1, zlib1g (>= 1:1.2.1), libgcc1 (>= 1:4.0.2), libexpat1, swig") # bug: missing dep to python... + set(CPACK_DEBIAN_PACKAGE_SUGGESTS "dcmtk") + set(CPACK_SOURCE_IGNORE_FILES "/\\\\.gitmodules" "/\\\\.git/" "/\\\\.gitignore" "TODO" "/Testing/Data/") + set(CPACK_IGNORE_FILES ${CPACK_SOURCE_IGNORE_FILES}) + + # List executables + #set(CPACK_PACKAGE_EXECUTABLES "gdcmviewer" "VIEWER") + if(CYGWIN) + set(CPACK_CYGWIN_PATCH_NUMBER 1) + set(CPACK_CYGWIN_BUILD_SCRIPT + "${GDCM_BINARY_DIR}/@CPACK_PACKAGE_FILE_NAME@-@CPACK_CYGWIN_PATCH_NUMBER@.sh") + set(CPACK_CYGWIN_PATCH_FILE + "${GDCM_BINARY_DIR}/@CPACK_PACKAGE_FILE_NAME@-@CPACK_CYGWIN_PATCH_NUMBER@.patch") + configure_file(${GDCM_SOURCE_DIR}/CMake/Release/cygwin-patch.diff.in ${CPACK_CYGWIN_PATCH_FILE}) + configure_file(${GDCM_SOURCE_DIR}/CMake/Release/cygwin-package.sh.in ${CPACK_CYGWIN_BUILD_SCRIPT}) + endif() + + # Tell CPack all of the components to install. The "ALL" + # refers to the fact that this is the set of components that + # will be included when CPack is instructed to put everything + # into the binary installer (the default behavior). + set(components) + if(GDCM_BUILD_APPLICATIONS) + list(APPEND components Applications) + endif() + list(APPEND components Libraries) + list(APPEND components Headers) + list(APPEND components DebugDevel) + if(GDCM_WRAP_PYTHON) + list(APPEND components PythonModule) + endif() + if(GDCM_WRAP_CSHARP) + list(APPEND components CSharpModule) + endif() + if(GDCM_WRAP_JAVA) + list(APPEND components JavaModule) + endif() + if(GDCM_WRAP_PHP) + list(APPEND components PHPModule) + endif() + if(GDCM_USE_VTK) + foreach(comp ${components}) + if( "${comp}" STREQUAL "PythonModule" ) + if(VTK_WRAP_PYTHON) + list(APPEND components VTK${comp}) + endif() + elseif( "${comp}" STREQUAL "JavaModule" ) + if(VTK_WRAP_JAVA) + list(APPEND components VTK${comp}) + endif() + else() + list(APPEND components VTK${comp}) + endif() + endforeach() + endif() + if(GDCM_USE_PARAVIEW) + list(APPEND components ParaViewModule) + endif() + # Ok this is the complete list of all components: + set(CPACK_COMPONENTS_ALL ${components}) + + # Set the displayed names for each of the components to install. + # These will be displayed in the list of components inside the installer. + set(CPACK_COMPONENT_APPLICATIONS_DISPLAY_NAME "GDCM Applications") + set(CPACK_COMPONENT_LIBRARIES_DISPLAY_NAME "GDCM Libraries") + set(CPACK_COMPONENT_HEADERS_DISPLAY_NAME "GDCM C/C++ Headers") + set(CPACK_COMPONENT_DEBUGDEVEL_DISPLAY_NAME "GDCM Debug Symbols (PDB)") + set(CPACK_COMPONENT_PYTHONMODULE_DISPLAY_NAME "GDCM Python Module") + set(CPACK_COMPONENT_CSHARPMODULE_DISPLAY_NAME "GDCM C# Module") + set(CPACK_COMPONENT_JAVAMODULE_DISPLAY_NAME "GDCM Java Module") + set(CPACK_COMPONENT_PHPMODULE_DISPLAY_NAME "GDCM PHP Module") + set(CPACK_COMPONENT_VTKAPPLICATIONS_DISPLAY_NAME "VTK/GDCM Applications") + set(CPACK_COMPONENT_VTKLIBRARIES_DISPLAY_NAME "VTK/GDCM Libraries") + set(CPACK_COMPONENT_VTKHEADERS_DISPLAY_NAME "VTK/GDCM C/C++ Headers") + set(CPACK_COMPONENT_VTKPYTHONMODULE_DISPLAY_NAME "VTK/GDCM Python Module") + set(CPACK_COMPONENT_VTKCSHARPMODULE_DISPLAY_NAME "VTK/GDCM C# Module") + set(CPACK_COMPONENT_VTKJAVAMODULE_DISPLAY_NAME "VTK/GDCM Java Module") + set(CPACK_COMPONENT_VTKPHPMODULE_DISPLAY_NAME "VTK/GDCM PHP Module") + set(CPACK_COMPONENT_PARAVIEWMODULE_DISPLAY_NAME "ParaView Module") + + # Provide descriptions for each of the components to install. + # When the user hovers the mouse over the name of a component, + # the description will be shown in the "Description" box in the + # installer. If no descriptions are provided, the "Description" + # box will be removed. + set(CPACK_COMPONENT_APPLICATIONS_DESCRIPTION + "Command line applications that uses GDCM: gdcmconv, gdcmscu, gdcmdump, gdcminfo, gdcmscanner, gdcmimg, gdcmanon") + set(CPACK_COMPONENT_LIBRARIES_DESCRIPTION + "Libraries used to build programs with GDCM") + set(CPACK_COMPONENT_HEADERS_DESCRIPTION + "C/C++ header files for use with GDCM") + set(CPACK_COMPONENT_DEBUGDEVEL_DESCRIPTION + "Program Database files for use with GDCM") + set(CPACK_COMPONENT_PYTHONMODULE_DESCRIPTION + "Python Module for GDCM") + set(CPACK_COMPONENT_CSHARPMODULE_DESCRIPTION + "C# Module for GDCM") + set(CPACK_COMPONENT_JAVAMODULE_DESCRIPTION + "Java Module for GDCM") + set(CPACK_COMPONENT_PHPMODULE_DESCRIPTION + "PHP Module for GDCM") + set(CPACK_COMPONENT_VTKAPPLICATIONS_DESCRIPTION + "Command line applications that uses GDCM: gdcmviewer & gdcm2vtk") + set(CPACK_COMPONENT_VTKLIBRARIES_DESCRIPTION + "Libraries used to build programs with VTK/GDCM") + set(CPACK_COMPONENT_VTKHEADERS_DESCRIPTION + "C/C++ header files for use with VTK/GDCM") + set(CPACK_COMPONENT_VTKPYTHONMODULE_DESCRIPTION + "Python Module for VTK/GDCM") + set(CPACK_COMPONENT_VTKCSHARPMODULE_DESCRIPTION + "C# Module for VTK/GDCM") + set(CPACK_COMPONENT_VTKJAVAMODULE_DESCRIPTION + "Java Module for VTK/GDCM") + set(CPACK_COMPONENT_VTKPHPMODULE_DESCRIPTION + "PHP Module for VTK/GDCM") + set(CPACK_COMPONENT_PARAVIEWMODULE_DESCRIPTION + "ParaView Module for VTK/GDCM") + + + # Put the components into two different groups: "Runtime" and "Development" + set(CPACK_COMPONENT_APPLICATIONS_GROUP "Runtime") + set(CPACK_COMPONENT_LIBRARIES_GROUP "Development") + set(CPACK_COMPONENT_HEADERS_GROUP "Development") + set(CPACK_COMPONENT_DEBUGDEVEL_GROUP "Development") + set(CPACK_COMPONENT_PYTHONMODULE_GROUP "Runtime") + set(CPACK_COMPONENT_CSHARPMODULE_GROUP "Runtime") + set(CPACK_COMPONENT_JAVAMODULE_GROUP "Runtime") + set(CPACK_COMPONENT_PHPMODULE_GROUP "Runtime") + set(CPACK_COMPONENT_VTKAPPLICATIONS_GROUP "Runtime") + set(CPACK_COMPONENT_VTKPYTHONMODULE_GROUP "Runtime") + set(CPACK_COMPONENT_VTKCSHARPMODULE_GROUP "Runtime") + set(CPACK_COMPONENT_VTKJAVAMODULE_GROUP "Runtime") + set(CPACK_COMPONENT_VTKPHPMODULE_GROUP "Runtime") + set(CPACK_COMPONENT_VTKLIBRARIES_GROUP "Development") + set(CPACK_COMPONENT_VTKHEADERS_GROUP "Development") + set(CPACK_COMPONENT_PARAVIEWMODULE_GROUP "Runtime") + # Expand the "Development" group by default, since we have so few components. + # Also, provide this group with a description. + if(CMAKE_VERSION VERSION_EQUAL 2.8.3) + # The following is needed for CMake 2.8.3 and above to preserve backward compat + set(CPACK_MONOLITHIC_INSTALL 1) + endif() + set(CPACK_COMPONENT_GROUP_DEVELOPMENT_EXPANDED ON) + set(CPACK_COMPONENT_GROUP_DEVELOPMENT_DESCRIPTION + "All of the tools you'll ever need to develop software using GDCM") + + # It doesn't make sense to install the headers without the libraries + # (because you could never use the headers!), so make the headers component + # depend on the libraries component. + set(CPACK_COMPONENT_HEADERS_DEPENDS Libraries) + set(CPACK_COMPONENT_DEBUGDEVEL_DEPENDS Libraries) + set(CPACK_COMPONENT_APPLICATIONS_DEPENDS Libraries) + set(CPACK_COMPONENT_PYTHONMODULE_DEPENDS Libraries) + set(CPACK_COMPONENT_CSHARPMODULE_DEPENDS Libraries) + set(CPACK_COMPONENT_JAVAMODULE_DEPENDS Libraries) + set(CPACK_COMPONENT_PHPMODULE_DEPENDS Libraries) + set(CPACK_COMPONENT_VTKHEADERS_DEPENDS VTKLibraries) + set(CPACK_COMPONENT_VTKLIBRARIES_DEPENDS Libraries) + set(CPACK_COMPONENT_VTKAPPLICATIONS_DEPENDS VTKLibraries) + set(CPACK_COMPONENT_VTKPYTHONMODULE_DEPENDS VTKLibraries) + set(CPACK_COMPONENT_VTKCSHARPMODULE_DEPENDS VTKLibraries) + set(CPACK_COMPONENT_VTKJAVAMODULE_DEPENDS VTKLibraries) + set(CPACK_COMPONENT_VTKPHPMODULE_DEPENDS VTKLibraries) + set(CPACK_COMPONENT_PARAVIEWMODULE_DEPENDS VTKLibraries) + + # Create two installation types with pre-selected components. + # The "Developer" installation has just the library and headers, + # while the "Full" installation has everything. + set(CPACK_ALL_INSTALL_TYPES Full Developer) + set(CPACK_INSTALL_TYPE_FULL_DISPLAY_NAME "Everything") + set(CPACK_COMPONENT_APPLICATIONS_INSTALL_TYPES Full) + set(CPACK_COMPONENT_LIBRARIES_INSTALL_TYPES Developer Full) + set(CPACK_COMPONENT_HEADERS_INSTALL_TYPES Developer Full) + set(CPACK_COMPONENT_DEBUGDEVEL_INSTALL_TYPES Developer Full) + set(CPACK_COMPONENT_PYTHONMODULE_INSTALL_TYPES Developer Full) + set(CPACK_COMPONENT_CSHARPMODULE_INSTALL_TYPES Developer Full) + set(CPACK_COMPONENT_JAVAMODULE_INSTALL_TYPES Developer Full) + set(CPACK_COMPONENT_PHPMODULE_INSTALL_TYPES Developer Full) + set(CPACK_COMPONENT_VTKLIBRARIES_INSTALL_TYPES Developer Full) + set(CPACK_COMPONENT_VTKHEADERS_INSTALL_TYPES Developer Full) + set(CPACK_COMPONENT_VTKAPPLICATIONS_INSTALL_TYPES Full) + set(CPACK_COMPONENT_VTKPYTHONMODULE_INSTALL_TYPES Developer Full) + set(CPACK_COMPONENT_VTKCSHARPMODULE_INSTALL_TYPES Developer Full) + set(CPACK_COMPONENT_VTKJAVAMODULE_INSTALL_TYPES Developer Full) + set(CPACK_COMPONENT_VTKPHPMODULE_INSTALL_TYPES Developer Full) + set(CPACK_COMPONENT_PARAVIEWMODULE_INSTALL_TYPES Developer Full) + + include(CPack) + endif() + +endif() + + +macro(PROCESSONEDIR DIRNAME myoutput) + file(GLOB files + ${DIRNAME}/* + ) + foreach(file ${files}) + if(IS_DIRECTORY ${file}) + if("${file}" MATCHES ".git") + #message("${file} is git dir") + else() + #message("${file} is dir") + PROCESSONEDIR(${file} mytests2) + list(APPEND ${myoutput} ${mytests2}) + endif() + else() + #message("${file} is file") + get_filename_component(filename ${file} NAME) + if("${filename}" MATCHES "Test" AND ${filename} MATCHES ".cxx") + string(LENGTH ${filename} filename_length) + #message("${filename} is test, ${filename_length}") + math(EXPR fileend "${filename_length} - 4 - 4") # Need to remove 'Test' and '.cxx' + string(SUBSTRING ${filename} 4 ${fileend} classname) + #message("${classname} is tested") + list(APPEND ${myoutput} ${classname}) + endif() + endif() + endforeach() +endmacro() + +#PROCESSONEDIR( +# ${CMAKE_CURRENT_SOURCE_DIR}/Testing/Source/Common +# theoutput +#) +#message("${theoutput}") + +# For DICOM Q/R testing +if(GDCM_BUILD_TESTING) + set(GDCM_DICOM_CLIENT_AETITLE "" CACHE STRING "DICOM CLIENT AETITLE") + set(GDCM_DICOM_SERVER_AETITLE "" CACHE STRING "DICOM SERVER AETITLE") + set(GDCM_DICOM_SERVER_PEER "" CACHE STRING "DICOM SERVER PEER") + set(GDCM_DICOM_SERVER_PORT "" CACHE STRING "DICOM SERVER PORT") + set(GDCM_DICOM_CLIENT_PORT "" CACHE STRING "DICOM CLIENT PORT") + mark_as_advanced( + GDCM_DICOM_CLIENT_AETITLE + GDCM_DICOM_SERVER_AETITLE + GDCM_DICOM_SERVER_PEER + GDCM_DICOM_SERVER_PORT + GDCM_DICOM_CLIENT_PORT + ) +endif() + +#----------------------------------------------------------------------------- +# Need to be the last operation: +set(GDCM_INCLUDE_PATH + "${GDCM_SOURCE_DIR}/Source/Common" + "${GDCM_BINARY_DIR}/Source/Common" + "${GDCM_SOURCE_DIR}/Source/DataStructureAndEncodingDefinition" + "${GDCM_SOURCE_DIR}/Source/MediaStorageAndFileFormat" + "${GDCM_SOURCE_DIR}/Source/MessageExchangeDefinition" + "${GDCM_SOURCE_DIR}/Source/DataDictionary" + "${GDCM_SOURCE_DIR}/Source/InformationObjectDefinition" + ) +if(NOT GDCM_HAVE_STDINT_H) + if(MSVC) + set(GDCM_INCLUDE_PATH + ${GDCM_INCLUDE_PATH} + "${GDCM_SOURCE_DIR}/Utilities/C99" + ) + endif() +endif() +if(GDCM_USE_VTK) + set(GDCM_INCLUDE_PATH + ${GDCM_INCLUDE_PATH} + "${GDCM_SOURCE_DIR}/Utilities/VTK" + ) +endif() +set(GDCM_LIBRARY_DIRS ${LIBRARY_OUTPUT_PATH}) +if(GDCM_STANDALONE) +subdirs(CMake/ExportConfiguration) +endif() diff --git a/gdcm/CTestConfig.cmake b/gdcm/CTestConfig.cmake new file mode 100644 index 0000000..46edeeb --- /dev/null +++ b/gdcm/CTestConfig.cmake @@ -0,0 +1,7 @@ +set(CTEST_PROJECT_NAME "GDCM") +set(CTEST_NIGHTLY_START_TIME "21:00:00 EDT") + +set(CTEST_DROP_METHOD "http") +set(CTEST_DROP_SITE "www.cdash.org") +set(CTEST_DROP_LOCATION "/CDash/submit.php?project=GDCM") +set(CTEST_DROP_SITE_CDASH TRUE) diff --git a/gdcm/Copyright.txt b/gdcm/Copyright.txt new file mode 100644 index 0000000..0f5435f --- /dev/null +++ b/gdcm/Copyright.txt @@ -0,0 +1,36 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + +Copyright (c) 2006-2011 Mathieu Malaterre +Copyright (c) 1993-2005 CREATIS +(CREATIS = Centre de Recherche et d'Applications en Traitement de l'Image) +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither name of Mathieu Malaterre, or CREATIS, nor the names of any + contributors (CNRS, INSERM, UCB, Universite Lyon I), may be used to + endorse or promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=========================================================================*/ diff --git a/gdcm/Examples/CMakeLists.txt b/gdcm/Examples/CMakeLists.txt new file mode 100644 index 0000000..c74efc8 --- /dev/null +++ b/gdcm/Examples/CMakeLists.txt @@ -0,0 +1,30 @@ +cmake_minimum_required(VERSION 2.8.9) + +# Choose behavior based on whether we are building inside the GDCM tree. +if(GDCM_BINARY_DIR) +subdirs(Cxx) + +if(GDCM_WRAP_PYTHON) + subdirs(Python) +endif() + +if(GDCM_WRAP_CSHARP) + subdirs(Csharp) +endif() + +if(GDCM_WRAP_JAVA) + subdirs(Java) +endif() + +else() + + # We are building outside the GDCM tree. Build the examples directly. + project(GDCMExamples) + + # Find and load the VTK configuration. + find_package(GDCM REQUIRED) + include(${GDCM_USE_FILE}) + + subdirs(Cxx) + +endif() diff --git a/gdcm/Examples/Csharp/BasicAnonymizer.cs b/gdcm/Examples/Csharp/BasicAnonymizer.cs new file mode 100644 index 0000000..ac73bb7 --- /dev/null +++ b/gdcm/Examples/Csharp/BasicAnonymizer.cs @@ -0,0 +1,127 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +/** + * This is a minimal Anonymizer. All it does is anonymize a single file. + * When anonymizing more than a single file, one should be really careful + * to only create one single instance of a gdcm.Anonymizer and reuse it + * for the entire Series. + * See ClinicalTrialIdentificationWorkflow.cs for a more complex example + */ +/* + * Usage: + * $ export LD_LIBRARY_PATH=$HOME/Projects/gdcm/debug-gcc/bin + * $ mono bin/BasicAnonymizer.exe gdcmData/012345.002.050.dcm out.dcm + */ +using System; +using gdcm; + +public class MyWatcher : SimpleSubjectWatcher +{ + public MyWatcher(Subject s):base(s,"Override String"){} + protected override void StartFilter() { + System.Console.WriteLine( "This is my start" ); + } + protected override void EndFilter(){ + System.Console.WriteLine( "This is my end" ); + } + protected override void ShowProgress(Subject caller, Event evt){ + ProgressEvent pe = ProgressEvent.Cast(evt); + System.Console.WriteLine( "This is my progress: " + pe.GetProgress() ); + } + protected override void ShowIteration(){ + System.Console.WriteLine( "This is my iteration" ); + } + protected override void ShowAnonymization(Subject caller, Event evt){ +/* + * A couple of explanation are necessary here to understand how SWIG work + * http://www.swig.org/Doc1.3/Java.html#adding_downcasts + * + * System.Console.WriteLine( "This is my Anonymization. Type: " + evt.GetEventName() ); + * System.Type type = evt.GetType(); + * System.Console.WriteLine( "This is my Anonymization. System.Type: " + type.ToString() ); + * System.Console.WriteLine( "This is my Anonymization. CheckEvent: " + ae.CheckEvent( evt ) ); + * System.Console.WriteLine( "This is my Anonymization. Processing Tag #" + ae.GetTag().toString() ); + */ + AnonymizeEvent ae = AnonymizeEvent.Cast(evt); + if( ae != null ) + { + Tag t = ae.GetTag(); + System.Console.WriteLine( "This is my Anonymization. Processing Tag #" + t.toString() ); + } + else + { + System.Console.WriteLine( "This is my Anonymization. Unhandled Event type: " + evt.GetEventName() ); + } + } + protected override void ShowAbort(){ + System.Console.WriteLine( "This is my abort" ); + } +} + +public class BasicAnonymizer +{ + public static int Main(string[] args) + { + gdcm.Global global = gdcm.Global.GetInstance(); + if( !global.LoadResourcesFiles() ) + { + System.Console.WriteLine( "Could not LoadResourcesFiles" ); + return 1; + } + + string file1 = args[0]; + string file2 = args[1]; + Reader reader = new Reader(); + reader.SetFileName( file1 ); + bool ret = reader.Read(); + if( !ret ) + { + return 1; + } + + string certpath = gdcm.Filename.Join(gdcm.Testing.GetSourceDirectory(), "/Testing/Source/Data/certificate.pem" ); + gdcm.CryptoFactory fact = gdcm.CryptoFactory.GetFactoryInstance(); + gdcm.CryptographicMessageSyntax cms = fact.CreateCMSProvider(); + if( !cms.ParseCertificateFile( certpath ) ) + { + return 1; + } + + //Anonymizer ano = new Anonymizer(); + SmartPtrAno sano = Anonymizer.New(); + Anonymizer ano = sano.__ref__(); + + //SimpleSubjectWatcher watcher = new SimpleSubjectWatcher(ano, "Anonymizer"); + MyWatcher watcher = new MyWatcher(ano); + + ano.SetFile( reader.GetFile() ); + ano.SetCryptographicMessageSyntax( cms ); + if( !ano.BasicApplicationLevelConfidentialityProfile() ) + { + return 1; + } + + Writer writer = new Writer(); + writer.SetFileName( file2 ); + writer.SetFile( ano.GetFile() ); + ret = writer.Write(); + if( !ret ) + { + return 1; + } + + return 0; + } +} diff --git a/gdcm/Examples/Csharp/BasicImageAnonymizer.cs b/gdcm/Examples/Csharp/BasicImageAnonymizer.cs new file mode 100644 index 0000000..090eac5 --- /dev/null +++ b/gdcm/Examples/Csharp/BasicImageAnonymizer.cs @@ -0,0 +1,85 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +/* + */ +using System; +using gdcm; + +public class BasicImageAnonymizer +{ + public static int Main(string[] args) + { + string filename = args[0]; + + // instanciate the reader: + gdcm.ImageReader reader = new gdcm.ImageReader(); + reader.SetFileName( filename ); + + if (!reader.Read()) return 1; + + Image ir = reader.GetImage(); + + uint[] dims = {0, 0, 0}; + dims[0] = ir.GetDimension(0); + dims[1] = ir.GetDimension(1); + dims[2] = ir.GetDimension(2); + System.Console.WriteLine( "Dim:" + dims[0] ); + System.Console.WriteLine( "Dim:" + dims[1] ); + System.Console.WriteLine( "Dim:" + dims[2] ); + + // buffer to get the pixels + byte[] buffer = new byte[ ir.GetBufferLength()]; + System.Console.WriteLine( "Dim:" + ir.GetBufferLength() ); + ir.GetBuffer( buffer ); + + for (uint z = 0; z < dims[2]; z++) + { + for (uint y = 0; y < dims[1] / 2; y++) // only half Y + { + for (uint x = 0; x < dims[0] / 2; x++) // only half X + { + buffer[ (z * dims[1] + y) * dims[0] + x ] = 0; // works when pixel type == UINT8 + } + } + } + + DataElement pixeldata = new DataElement( new Tag(0x7fe0,0x0010) ); + pixeldata.SetByteValue( buffer, new VL( (uint)buffer.Length ) ); + ir.SetDataElement( pixeldata ); + ir.SetTransferSyntax( new TransferSyntax( TransferSyntax.TSType.ExplicitVRLittleEndian ) ); + + ImageChangeTransferSyntax change = new ImageChangeTransferSyntax(); + change.SetTransferSyntax( new TransferSyntax( TransferSyntax.TSType.JPEGLSLossless ) ); + change.SetInput( ir ); + if( !change.Change() ) + { + System.Console.WriteLine( "Could not change: " + filename ); + return 1; + } + + ImageWriter writer = new ImageWriter(); + writer.SetFileName( "out.dcm" ); + writer.SetFile( reader.GetFile() ); + writer.SetImage( change.GetOutput() ); + bool ret = writer.Write(); + if( !ret ) + { + return 1; + } + + + return 0; + } +} diff --git a/gdcm/Examples/Csharp/CMakeLists.txt b/gdcm/Examples/Csharp/CMakeLists.txt new file mode 100644 index 0000000..ceef4f6 --- /dev/null +++ b/gdcm/Examples/Csharp/CMakeLists.txt @@ -0,0 +1,78 @@ +#add_executable(ManipulateFile ManipulateFile.cs) +#target_link_libraries(ManipulateFile gdcm-sharp) + +set(CSHARP_EXAMPLES + SimplePrintPatientName + ExtractOneFrame + ExtractImageRegion + ExtractImageRegionWithLUT + ManipulateFile + RescaleImage + ExtractEncapsulatedFile + DecompressImage + DecompressImageMultiframe + DecompressJPEGFile + SimplePrint + ScanDirectory + #SortImage2 + GetArray + NewSequence + GenerateDICOMDIR + StandardizeFiles + ReformatFile + CompressLossyJPEG + SendFileSCU + MpegVideoInfo + BasicImageAnonymizer + FileAnonymize + FileStreaming + FileChangeTS + ) + +if(BUILD_TESTING) + set(CSHARP_EXAMPLES + ${CSHARP_EXAMPLES} + BasicAnonymizer + ClinicalTrialIdentificationWorkflow + ) +endif() + +set(DEP) +# http://www.cmake.org/Wiki/CMake_FAQ#How_can_I_add_a_dependency_to_a_source_file_which_is_generated_in_a_subdirectory.3F +# Tell CMake the source won't be available until build time. +set_source_files_properties(${GDCM_LIBRARY_DIR}/gdcm-sharp.dll PROPERTIES GENERATED 1) +# Make sure the source is generated before the executable builds. +foreach(example ${CSHARP_EXAMPLES}) + file(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/${example}.cs result) +# WORKING_DIRECTORY is set to the src dir because of a strange issue with CSC compiler on Win32 system: +# http://groups.google.com/group/microsoft.public.dotnet.languages.csharp/browse_thread/thread/9d3ac7eb9f7f56be + add_custom_command( + OUTPUT ${GDCM_EXECUTABLE_DIR}/${example}.exe + #COMMAND ${CMAKE_CSHARP_COMPILER} ARGS "/r:${GDCM_LIBRARY_DIR}/gdcm-sharp.dll" "/out:${GDCM_EXECUTABLE_DIR}/${example}.exe" ${CMAKE_CURRENT_SOURCE_DIR}/${example}.cs + COMMAND ${CMAKE_CSHARP_COMPILER} ARGS "${CSC_PLATFORM_FLAG}" "/r:${GDCM_LIBRARY_DIR}/gdcm-sharp.dll" "/out:${GDCM_EXECUTABLE_DIR}/${example}.exe" ${result} + #WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + DEPENDS #${GDCM_LIBRARY_DIR}/gdcm-sharp.dll + ${CMAKE_CURRENT_SOURCE_DIR}/${example}.cs + COMMENT "Create ${example}.exe" + ) + add_custom_target(gdcm_sharp_${example} DEPENDS ${GDCM_EXECUTABLE_DIR}/${example}.exe) + add_dependencies(gdcm_sharp_${example} GDCMCSharp) + + set(DEP ${DEP} ${GDCM_EXECUTABLE_DIR}/${example}.exe) +endforeach() + +add_custom_target(GDCMExampleCSharp ALL + DEPENDS ${DEP} + COMMENT "building examples" +) +add_dependencies(GDCMExampleCSharp GDCMCSharp) + +if(BUILD_TESTING) +if(GDCM_DATA_ROOT) + ADD_CSHARP_TEST(TestSimplePrintCSharp ${GDCM_EXECUTABLE_DIR}/SimplePrint.exe ${GDCM_DATA_ROOT}/012345.002.050.dcm) +# TODO: +#if(BUILD_EXAMPLES) +# ADD_CSHARP_TEST(HelloWorldCSharp ${GDCM_EXECUTABLE_DIR}/HelloWorld.exe ${GDCM_DATA_ROOT}/012345.002.050.dcm) +#endif() +endif() +endif() diff --git a/gdcm/Examples/Csharp/ClinicalTrialIdentificationWorkflow.cs b/gdcm/Examples/Csharp/ClinicalTrialIdentificationWorkflow.cs new file mode 100644 index 0000000..0f49444 --- /dev/null +++ b/gdcm/Examples/Csharp/ClinicalTrialIdentificationWorkflow.cs @@ -0,0 +1,241 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/** + * This is a simple example that show typical pipeline to setup when + * preprocessing incoming DICOM file from around the round, and making + * sur eto remove any Patient Information. + * This is actually identical to running the C++ command line tool: gdcmanon, + * except this is easily integrated into another C# environment. + * + * PS 3.17 - 2008 Annex H. + * Clinical Trial Identification Workflow Examples (Informative) + * + * This Annex was formerly located in Annex O of PS 3.3 in the 2003 and earlier + * revisions of the standard. The Clinical Trial Identification modules are + * optional. As such, there are several points in the workflow of clinical trial + * data at which the Clinical Trial Identification attributes may be added to the + * data. At the Clinical Trial Site, the attributes may be added at the scanner, a + * PACS system, a site workstation, or a workstation provided to the site by a + * Clinical Trial Coordinating Center. If not added at the site, the Clinical + * Trial Identification attributes may be added to the data after receipt by the + * Clinical Trial Coordinating Center. The addition of clinical trial attributes + * does not itself require changes to the SOP Instance UID. However, the clinical + * trial protocol or the process of de-identification may require such a change. + */ + +/* + * Typical usage on UNIX: + * $ export LD_LIBRARY_PATH=$HOME/Projects/gdcm/debug-gcc/bin + * $ mono bin/ClinicalTrialIdentificationWorkflow.exe input_dir output_dir + */ +using System; +using gdcm; + +public class MyWatcher : SimpleSubjectWatcher +{ + public MyWatcher(Subject s):base(s,"Override String"){} + protected override void StartFilter() { + System.Console.WriteLine( "This is my start" ); + } + protected override void EndFilter(){ + System.Console.WriteLine( "This is my end" ); + } + protected override void ShowProgress(Subject caller, Event evt){ + ProgressEvent pe = ProgressEvent.Cast(evt); + System.Console.WriteLine( "This is my progress: " + pe.GetProgress() ); + } + protected override void ShowIteration(){ + System.Console.WriteLine( "This is my iteration" ); + } + protected override void ShowAnonymization(Subject caller, Event evt){ +/* + * A couple of explanation are necessary here to understand how SWIG work + * http://www.swig.org/Doc1.3/Java.html#adding_downcasts + * + * System.Console.WriteLine( "This is my Anonymization. Type: " + evt.GetEventName() ); + * System.Type type = evt.GetType(); + * System.Console.WriteLine( "This is my Anonymization. System.Type: " + type.ToString() ); + * System.Console.WriteLine( "This is my Anonymization. CheckEvent: " + ae.CheckEvent( evt ) ); + * System.Console.WriteLine( "This is my Anonymization. Processing Tag #" + ae.GetTag().toString() ); + */ + AnonymizeEvent ae = AnonymizeEvent.Cast(evt); + if( ae != null ) + { + Tag t = ae.GetTag(); + System.Console.WriteLine( "This is my Anonymization. Processing Tag #" + t.toString() ); + } + else + { + System.Console.WriteLine( "This is my Anonymization. Unhandled Event type: " + evt.GetEventName() ); + } + } + protected override void ShowAbort(){ + System.Console.WriteLine( "This is my abort" ); + } +} + +public class ClinicalTrialIdentificationWorkflow +{ + public static bool ProcessOneFile( gdcm.Anonymizer ano , string filename, string outfilename ) + { + Reader reader = new Reader(); + reader.SetFileName( filename ); + bool ret = reader.Read(); + if( !ret ) + { + return false; + } + // Pass in the file: + ano.SetFile( reader.GetFile() ); + + // First step, let's protect all Patient information as per + // PS 3.15 / E.1 / Basic Application Level Confidentiality Profile + if( !ano.BasicApplicationLevelConfidentialityProfile() ) + { + return false; + } + + // Now let's pass in all Clinical Trial fields + // PS 3.3 - 2008 / C.7.1.3 Clinical Trial Subject Module + /* + Clinical Trial Sponsor Name (0012,0010) 1 The name of the clinical trial sponsor. See C.7.1.3.1.1. + Clinical Trial Protocol ID (0012,0020) 1 Identifier for the noted protocol. See C.7.1.3.1.2. + Clinical Trial Protocol Name (0012,0021) 2 The name of the clinical trial protocol. See C.7.1.3.1.3. + Clinical Trial Site ID (0012,0030) 2 The identifier of the site responsible for submitting clinical trial data. See C.7.1.3.1.4. + Clinical Trial Site Name (0012,0031) 2 Name of the site responsible for submitting clinical trial data. See C.7.1.3.1.5 + Clinical Trial Subject ID (0012,0040) 1C The assigned identifier for the clinical trial subject. See C.7.1.3.1.6. Shall be present if Clinical Trial Subject Reading ID (0012,0042) is absent. May be present otherwise. + Clinical Trial Subject Reading ID (0012,0042) 1C Identifies the subject for blinded evaluations. Shall be present if Clinical Trial Subject ID (0012,0040) is absent. May be present otherwise. See C.7.1.3.1.7. + */ + ano.Replace( new gdcm.Tag(0x0012,0x0010), "MySponsorName"); + ano.Replace( new gdcm.Tag(0x0012,0x0020), "MyProtocolID"); + ano.Replace( new gdcm.Tag(0x0012,0x0021), "MyProtocolName"); + ano.Replace( new gdcm.Tag(0x0012,0x0030), "MySiteId"); + ano.Replace( new gdcm.Tag(0x0012,0x0031), "MySiteName"); + ano.Replace( new gdcm.Tag(0x0012,0x0040), "MySponsorId"); + ano.Replace( new gdcm.Tag(0x0012,0x0050), "MyTPId"); + ano.Replace( new gdcm.Tag(0x0012,0x0051), "MyTPDescription"); + + // The following two are not required as they are guaranteed to be filled in by the + // Basic Application Level Confidentiality Profile. Only override if you understand what + // you are doing + //ano.Replace( new gdcm.Tag(0x0012,0x0062), "YES"); + //ano.Replace( new gdcm.Tag(0x0012,0x0063), "My Super Duper Anonymization Overload"); + + // We might be generating a subdirectory. Let's make sure the subdir exist: + gdcm.Filename fn = new gdcm.Filename( outfilename ); + string subdir = fn.GetPath(); + if( !gdcm.PosixEmulation.MakeDirectory( subdir ) ) + { + return false; + } + + gdcm.FileMetaInformation fmi = ano.GetFile().GetHeader(); + // The following three lines make sure to regenerate any value: + fmi.Remove( new gdcm.Tag(0x0002,0x0012) ); + fmi.Remove( new gdcm.Tag(0x0002,0x0013) ); + fmi.Remove( new gdcm.Tag(0x0002,0x0016) ); + + Writer writer = new Writer(); + writer.SetFileName( outfilename ); + writer.SetFile( ano.GetFile() ); + ret = writer.Write(); + if( !ret ) + { + return false; + } + + return true; + } + + public static int Main(string[] args) + { + gdcm.FileMetaInformation.SetSourceApplicationEntityTitle( "My ClinicalTrial App" ); + + // http://www.oid-info.com/get/1.3.6.1.4.17434 + string THERALYS_ORG_ROOT = "1.3.6.1.4.17434"; + gdcm.UIDGenerator.SetRoot( THERALYS_ORG_ROOT ); + System.Console.WriteLine( "Root dir is now: " + gdcm.UIDGenerator.GetRoot() ); + + gdcm.Global global = gdcm.Global.GetInstance(); + if( !global.LoadResourcesFiles() ) + { + System.Console.WriteLine( "Could not LoadResourcesFiles" ); + return 1; + } + + if( args.Length != 2 ) + { + System.Console.WriteLine( "Usage:" ); + System.Console.WriteLine( "ClinicalTrialIdentificationWorkflow input_dir output_dir" ); + return 1; + } + string dir1 = args[0]; + string dir2 = args[1]; + + // Check input is valid: + if( !gdcm.PosixEmulation.FileIsDirectory(dir1) ) + { + System.Console.WriteLine( "Input directory: " + dir1 + " does not exist. Sorry" ); + return 1; + } + if( !gdcm.PosixEmulation.FileIsDirectory(dir2) ) + { + System.Console.WriteLine( "Output directory: " + dir2 + " does not exist. Sorry" ); + return 1; + } + + // Recursively search all file within this toplevel directory: + Directory d = new Directory(); + uint nfiles = d.Load( dir1, true ); + if(nfiles == 0) return 1; + + // Let's use the pre-shipped certificate of GDCM. + string certpath = gdcm.Filename.Join(gdcm.Testing.GetSourceDirectory(), "/Testing/Source/Data/certificate.pem" ); + gdcm.CryptoFactory fact = gdcm.CryptoFactory.GetFactoryInstance(); + gdcm.CryptographicMessageSyntax cms = fact.CreateCMSProvider(); + if( !cms.ParseCertificateFile( certpath ) ) + { + System.Console.WriteLine( "PEM Certificate : " + certpath + " could not be read. Sorry" ); + return 1; + } + + //Anonymizer ano = new Anonymizer(); + // A reference to an actual C++ instance is required here: + SmartPtrAno sano = Anonymizer.New(); + Anonymizer ano = sano.__ref__(); + + //SimpleSubjectWatcher watcher = new SimpleSubjectWatcher(ano, "Anonymizer"); + MyWatcher watcher = new MyWatcher(ano); + + // Explicitely specify the Cryptographic Message Syntax to use: + ano.SetCryptographicMessageSyntax( cms ); + + // Process all filenames: + FilenamesType filenames = d.GetFilenames(); + for( uint i = 0; i < nfiles; ++i ) + { + string filename = filenames[ (int)i ]; + string outfilename = filename.Replace( dir1, dir2 ); + System.Console.WriteLine( "Filename: " + filename ); + System.Console.WriteLine( "Out Filename: " + outfilename ); + if( !ProcessOneFile( ano , filename, outfilename ) ) + { + System.Console.WriteLine( "Could not process filename: " + filename ); + return 1; + } + } + + return 0; + } +} diff --git a/gdcm/Examples/Csharp/CompressLossyJPEG.cs b/gdcm/Examples/Csharp/CompressLossyJPEG.cs new file mode 100644 index 0000000..19bfbb2 --- /dev/null +++ b/gdcm/Examples/Csharp/CompressLossyJPEG.cs @@ -0,0 +1,88 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + * Usage: + * $ export LD_LIBRARY_PATH=$HOME/Perso/gdcm/debug-gcc/bin + * $ mono bin/CompressLossyJPEG.exe input.dcm output.dcm + */ + +using System; +using gdcm; + +public class CompressLossyJPEG +{ + public static int Main(string[] args) + { + if( args.Length < 2 ) + { + System.Console.WriteLine( " input.dcm output.dcm" ); + return 1; + } + string filename = args[0]; + string outfilename = args[1]; + + ImageReader reader = new ImageReader(); + reader.SetFileName( filename ); + if( !reader.Read() ) + { + System.Console.WriteLine( "Could not read: " + filename ); + return 1; + } + + // The output of gdcm::Reader is a gdcm::File + File file = reader.GetFile(); + + // the dataset is the the set of element we are interested in: + DataSet ds = file.GetDataSet(); + + Image image = reader.GetImage(); + //image.Print( cout ); + + ImageChangeTransferSyntax change = new ImageChangeTransferSyntax(); + TransferSyntax targetts = new TransferSyntax( TransferSyntax.TSType.JPEGBaselineProcess1 ); + change.SetTransferSyntax( targetts ); + + // Setup our JPEGCodec, warning it should be compatible with JPEGBaselineProcess1 + JPEGCodec jpegcodec = new JPEGCodec(); + if( !jpegcodec.CanCode( targetts ) ) + { + System.Console.WriteLine( "Something went really wrong, JPEGCodec cannot handle JPEGBaselineProcess1" ); + return 1; + } + jpegcodec.SetLossless( false ); + jpegcodec.SetQuality( 50 ); // poor quality ! + change.SetUserCodec( jpegcodec ); // specify the codec to use to the ImageChangeTransferSyntax + + change.SetInput( image ); + bool b = change.Change(); + if( !b ) + { + System.Console.WriteLine( "Could not change the Transfer Syntax" ); + return 1; + } + + ImageWriter writer = new ImageWriter(); + writer.SetImage( (gdcm.Image)change.GetOutput() ); + writer.SetFile( reader.GetFile() ); + writer.SetFileName( outfilename ); + if( !writer.Write() ) + { + System.Console.WriteLine( "Could not write: " + outfilename ); + return 1; + } + + return 0; + } + +} diff --git a/gdcm/Examples/Csharp/DecompressImage.cs b/gdcm/Examples/Csharp/DecompressImage.cs new file mode 100644 index 0000000..c5800b8 --- /dev/null +++ b/gdcm/Examples/Csharp/DecompressImage.cs @@ -0,0 +1,87 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +/* + * Usage: + * $ export LD_LIBRARY_PATH=$HOME/Projects/gdcm/debug-gcc/bin + * $ mono bin/DecompressImage.exe gdcmData/012345.002.050.dcm decompress.dcm + */ +using System; +using gdcm; + +public class DecompressImage +{ + public static int Main(string[] args) + { + string file1 = args[0]; + string file2 = args[1]; + ImageReader reader = new ImageReader(); + reader.SetFileName( file1 ); + bool ret = reader.Read(); + if( !ret ) + { + return 1; + } + + Image image = new Image(); + Image ir = reader.GetImage(); + + image.SetNumberOfDimensions( ir.GetNumberOfDimensions() ); + + //Just for fun: + //int dircos = ir.GetDirectionCosines(); + //t = gdcm.Orientation.GetType(dircos); + //int l = gdcm.Orientation.GetLabel(t); + //System.Console.WriteLine( "Orientation label:" + l ); + + // Set the dimensions, + // 1. either one at a time + //image.SetDimension(0, ir.GetDimension(0) ); + //image.SetDimension(1, ir.GetDimension(1) ); + + // 2. the array at once + uint[] dims = {0, 0}; + // Just for fun let's invert the dimensions: + dims[0] = ir.GetDimension(1); + dims[1] = ir.GetDimension(0); + ir.SetDimensions( dims ); + + PixelFormat pixeltype = ir.GetPixelFormat(); + image.SetPixelFormat( pixeltype ); + + PhotometricInterpretation pi = ir.GetPhotometricInterpretation(); + image.SetPhotometricInterpretation( pi ); + + DataElement pixeldata = new DataElement( new Tag(0x7fe0,0x0010) ); + byte[] str1 = new byte[ ir.GetBufferLength()]; + ir.GetBuffer( str1 ); + //System.Console.WriteLine( ir.GetBufferLength() ); + pixeldata.SetByteValue( str1, new VL( (uint)str1.Length ) ); + //image.SetDataElement( pixeldata ); + ir.SetDataElement( pixeldata ); + + + ImageWriter writer = new ImageWriter(); + writer.SetFileName( file2 ); + writer.SetFile( reader.GetFile() ); + writer.SetImage( ir ); + ret = writer.Write(); + if( !ret ) + { + return 1; + } + + return 0; + } +} diff --git a/gdcm/Examples/Csharp/DecompressImageMultiframe.cs b/gdcm/Examples/Csharp/DecompressImageMultiframe.cs new file mode 100644 index 0000000..eacfced --- /dev/null +++ b/gdcm/Examples/Csharp/DecompressImageMultiframe.cs @@ -0,0 +1,131 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +/* +$ gdcminfo ~/Desktop/angiogram-06.dcm +MediaStorage is 1.2.840.10008.5.1.4.1.1.12.1 [X-Ray Angiographic Image Storage] +TransferSyntax is 1.2.840.10008.1.2.4.50 [JPEG Baseline (Process 1): Default Transfer Syntax for Lossy JPEG 8 Bit Image Compression] +NumberOfDimensions: 3 +Dimensions: (512,512,355) +Origin: (0,0,0) +Spacing: (1,1,40) +DirectionCosines: (1,0,0,0,1,0) +Rescale Intercept/Slope: (0,1) +SamplesPerPixel :1 +BitsAllocated :8 +BitsStored :8 +HighBit :7 +PixelRepresentation:0 +ScalarType found :UINT8 +PhotometricInterpretation: MONOCHROME2 +PlanarConfiguration: 0 +TransferSyntax: 1.2.840.10008.1.2.4.50 +Orientation Label: AXIAL +*/ + +/* + * Description: + * + * Assume we have a file angiogram-06.dcm as described above. + * the following program will decompress directly from the extracted jpeg stream. + * + * First step extract the jpeg stream (but not the Basic Offset Table): + * + * $ gdcmraw -i angiogram-06.dcm -o /tmp/output/chris --split-frags --pattern %d.jpg + * + * Check that indeed there are 355 files, while there are 356 fragments in the original DICOM file, since + * gdcmraw always skip the first fragment (Basic Offset Table). + * + * Now from those individual jpeg stream, recreate a fake gdcm.DataElement... + * + * Usage: + * + * $ export LD_LIBRARY_PATH=$HOME/Projects/gdcm/debug-gcc/bin + * $ mono ./bin/DecompressImageMultiframe.exe /tmp/output + */ +using System; +using gdcm; + +public class DecompressImageMultiframe +{ + public static int Main(string[] args) + { + string directory = args[0]; + gdcm.Directory dir = new gdcm.Directory(); + uint nfiles = dir.Load(directory); + //System.Console.WriteLine(dir.toString()); + gdcm.FilenamesType filenames = dir.GetFilenames(); + + Image image = new Image(); + image.SetNumberOfDimensions( 3 ); // important for now + DataElement pixeldata = new DataElement( new gdcm.Tag(0x7fe0,0x0010) ); + + // Create a new SequenceOfFragments C++ object, store it as a SmartPointer : + SmartPtrFrag sq = SequenceOfFragments.New(); + + // Yeah, the file are not garantee to be in order, please adapt... + for(uint i = 0; i < nfiles; ++i) + { + System.Console.WriteLine( filenames[(int)i] ); + string file = filenames[(int)i]; + System.IO.FileStream infile = + new System.IO.FileStream(file, System.IO.FileMode.Open, System.IO.FileAccess.Read); + uint fsize = gdcm.PosixEmulation.FileSize(file); + + byte[] jstream = new byte[fsize]; + infile.Read(jstream, 0 , jstream.Length); + + Fragment frag = new Fragment(); + frag.SetByteValue( jstream, new gdcm.VL( (uint)jstream.Length) ); + sq.AddFragment( frag ); + } + + // Pass by reference: + pixeldata.SetValue( sq.__ref__() ); + + // insert: + image.SetDataElement( pixeldata ); + + // JPEG use YBR to achieve better compression ratio by default (not RGB) + // FIXME hardcoded: + PhotometricInterpretation pi = new PhotometricInterpretation( PhotometricInterpretation.PIType.MONOCHROME2 ); + image.SetPhotometricInterpretation( pi ); + // FIXME hardcoded: + PixelFormat pixeltype = new PixelFormat(1,8,8,7); + image.SetPixelFormat( pixeltype ); + + // FIXME hardcoded: + image.SetTransferSyntax( new TransferSyntax( TransferSyntax.TSType.JPEGLosslessProcess14_1 ) ); + image.SetDimension(0, 512); + image.SetDimension(1, 512); + image.SetDimension(2, 355); + + // Decompress ! + byte[] decompressedData = new byte[(int)image.GetBufferLength()]; + image.GetBuffer(decompressedData); + + // Write out the decompressed bytes + System.Console.WriteLine(image.toString()); + using (System.IO.Stream stream = + System.IO.File.Open(@"/tmp/dd.raw", + System.IO.FileMode.Create)) + { + System.IO.BinaryWriter writer = new System.IO.BinaryWriter(stream); + writer.Write(decompressedData); + } + + + return 0; + } +} diff --git a/gdcm/Examples/Csharp/DecompressJPEGFile.cs b/gdcm/Examples/Csharp/DecompressJPEGFile.cs new file mode 100644 index 0000000..9e409f6 --- /dev/null +++ b/gdcm/Examples/Csharp/DecompressJPEGFile.cs @@ -0,0 +1,87 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +/* + * Usage: + * $ export LD_LIBRARY_PATH=$HOME/Projects/gdcm/debug-gcc/bin + * $ mono bin/DecompressJPEGFile.exe somejpegfile.jpg + */ +using System; +using gdcm; + +public class DecompressJPEGFile +{ + public static int Main(string[] args) + { + string file1 = args[0]; + System.IO.FileStream infile = + new System.IO.FileStream(file1, System.IO.FileMode.Open, System.IO.FileAccess.Read); + uint fsize = gdcm.PosixEmulation.FileSize(file1); + + byte[] jstream = new byte[fsize]; + infile.Read(jstream, 0 , jstream.Length); + + Trace.DebugOn(); + Image image = new Image(); + image.SetNumberOfDimensions( 2 ); // important for now + DataElement pixeldata = new DataElement( new gdcm.Tag(0x7fe0,0x0010) ); + + // DO NOT set a ByteValue here, JPEG is a particular kind of encapsulated syntax + // in which can one cannot use a simple byte array for storage. Instead, see + // gdcm.SequenceOfFragments + //pixeldata.SetByteValue( jstream, new gdcm.VL( (uint)jstream.Length ) ); + + // Create a new SequenceOfFragments C++ object, store it as a SmartPointer : + SmartPtrFrag sq = SequenceOfFragments.New(); + Fragment frag = new Fragment(); + frag.SetByteValue( jstream, new gdcm.VL( (uint)jstream.Length) ); + // Single file => single fragment + sq.AddFragment( frag ); + // Pass by reference: + pixeldata.SetValue( sq.__ref__() ); + + // insert: + image.SetDataElement( pixeldata ); + + // JPEG use YBR to achieve better compression ratio by default (not RGB) + // FIXME hardcoded: + PhotometricInterpretation pi = new PhotometricInterpretation( PhotometricInterpretation.PIType.YBR_FULL ); + image.SetPhotometricInterpretation( pi ); + // FIXME hardcoded: + PixelFormat pixeltype = new PixelFormat(3,8,8,7); + image.SetPixelFormat( pixeltype ); + + // FIXME hardcoded: + image.SetTransferSyntax( new TransferSyntax( TransferSyntax.TSType.JPEGLosslessProcess14_1 ) ); + image.SetDimension(0, 692); + image.SetDimension(1, 721); + + // Decompress ! + byte[] decompressedData = new byte[(int)image.GetBufferLength()]; + image.GetBuffer(decompressedData); + + // Write out the decompressed bytes + System.Console.WriteLine(image.toString()); + using (System.IO.Stream stream = + System.IO.File.Open(@"/tmp/dd.raw", + System.IO.FileMode.Create)) + { + System.IO.BinaryWriter writer = new System.IO.BinaryWriter(stream); + writer.Write(decompressedData); + } + + + return 0; + } +} diff --git a/gdcm/Examples/Csharp/ExtractEncapsulatedFile.cs b/gdcm/Examples/Csharp/ExtractEncapsulatedFile.cs new file mode 100644 index 0000000..23d24b9 --- /dev/null +++ b/gdcm/Examples/Csharp/ExtractEncapsulatedFile.cs @@ -0,0 +1,75 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +/* + * This example shows how one from C# context can extract a binary blob + * and write out as a file. + * This example is meant for pdf encapsulated file, but can be adapted for other type + * of binary blob. + * + * DICOM file is: + * ... + * (0042,0010) ST (no value available) # 0, 0 DocumentTitle + * (0042,0011) OB 25\50\44\46\2d\31\2e\32\20\0d\25\e2\e3\cf\d3\20\0d\31\30\20\30\20... # 40718, 1 EncapsulatedDocument + * (0042,0012) LO [application/pdf] # 16, 1 MIMETypeOfEncapsulatedDocument + * ... + * + * Usage: + * $ export LD_LIBRARY_PATH=$HOME/Projects/gdcm/debug-gcc/bin + * $ mono bin/ExtractEncapsulatedFile.exe some_pdf_encapsulated.dcm + */ +using System; +using gdcm; + +public class ExtractEncapsulatedFile +{ + public static int Main(string[] args) + { + string file = args[0]; + Reader reader = new Reader(); + reader.SetFileName( file ); + bool ret = reader.Read(); + if( !ret ) + { + return 1; + } + + File f = reader.GetFile(); + DataSet ds = f.GetDataSet(); + Tag tencapsulated_stream = new Tag(0x0042,0x0011); // Encapsulated Document + if( !ds.FindDataElement( tencapsulated_stream ) ) + { + return 1; + } + // else + DataElement de = ds.GetDataElement( tencapsulated_stream ); + ByteValue bv = de.GetByteValue(); + uint len = bv.GetLength(); + byte[] encapsulated_stream = new byte[len]; + bv.GetBuffer( encapsulated_stream, len ); + + // Write out the decompressed bytes + //System.Console.WriteLine(image.toString()); + using (System.IO.Stream stream = + System.IO.File.Open(@"/tmp/dd.pdf", + System.IO.FileMode.Create)) + { + System.IO.BinaryWriter writer = new System.IO.BinaryWriter(stream); + writer.Write( encapsulated_stream ); + } + + + return 0; + } +} diff --git a/gdcm/Examples/Csharp/ExtractImageRegion.cs b/gdcm/Examples/Csharp/ExtractImageRegion.cs new file mode 100644 index 0000000..b7ec0f8 --- /dev/null +++ b/gdcm/Examples/Csharp/ExtractImageRegion.cs @@ -0,0 +1,90 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +/* + * This small code shows how to use the gdcm.ImageRegionReader API + * In this example we are taking each frame by frame and dump them to + * /tmp/frame.raw. + * + * Usage: + * $ bin/ExtractImageRegion.exe input.dcm + * + * Example: + * $ bin/ExtractImageRegion.exe gdcmData/012345.002.050.dcm + * $ md5sum /tmp/frame.raw + * d594a5e2fde12f32b6633ca859b4d4a6 /tmp/frame.raw + * $ gdcminfo --md5sum gdcmData/012345.002.050.dcm + * [...] + * md5sum: d594a5e2fde12f32b6633ca859b4d4a6 + */ +using System; +using gdcm; + +public class ExtractImageRegion +{ + public static int Main(string[] args) + { + string filename = args[0]; + + // instantiate the reader: + gdcm.ImageRegionReader reader = new gdcm.ImageRegionReader(); + reader.SetFileName( filename ); + + // pull DICOM info: + if (!reader.ReadInformation()) return 1; + // Get file infos + gdcm.File f = reader.GetFile(); + + // get some info about image + UIntArrayType dims = ImageHelper.GetDimensionsValue(f); + PixelFormat pf = ImageHelper.GetPixelFormatValue (f); + int pixelsize = pf.GetPixelSize(); + + // buffer to get the pixels + byte[] buffer = new byte[ dims[0] * dims[1] * pixelsize ]; + + // define a simple box region. + BoxRegion box = new BoxRegion(); + for (uint z = 0; z < dims[2]; z++) + { + // Define that I want the image 0, full size (dimx x dimy pixels) + // and do that for each z: + box.SetDomain(0, dims[0] - 1, 0, dims[1] - 1, z, z); + //System.Console.WriteLine( box.toString() ); + reader.SetRegion( box ); + + // reader will try to load the uncompressed image region into buffer. + // the call returns an error when buffer.Length is too small. For instance + // one can call: + // uint buf_len = reader.ComputeBufferLength(); // take into account pixel size + // to get the exact size of minimum buffer + if (reader.ReadIntoBuffer(buffer, (uint)buffer.Length)) + { + using (System.IO.Stream stream = + System.IO.File.Open(@"/tmp/frame.raw", + System.IO.FileMode.Create)) + { + System.IO.BinaryWriter writer = new System.IO.BinaryWriter(stream); + writer.Write(buffer); + } + } + else + { + throw new Exception("can't read pixels error"); + } + } + + return 0; + } +} diff --git a/gdcm/Examples/Csharp/ExtractImageRegionWithLUT.cs b/gdcm/Examples/Csharp/ExtractImageRegionWithLUT.cs new file mode 100644 index 0000000..ce19a8e --- /dev/null +++ b/gdcm/Examples/Csharp/ExtractImageRegionWithLUT.cs @@ -0,0 +1,101 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +/* + * This small code shows how to use the gdcm.ImageRegionReader API + * In this example we are taking each frame by frame and dump them to + * /tmp/frame.raw. + * Furthermore we are applying the LUT on this image. + * Special care should be taken in case the image is not PALETTE COLOR + * + * Usage: + * $ bin/ExtractImageRegionWithLUT.exe input.dcm + * + * Example: + * $ bin/ExtractImageRegionWithLUT.exe gdcmData/rle16loo.dcm + * $ md5sum /tmp/frame_rgb.raw + * 73bf61325fdb6e2830244a2b7b0c4ae2 /tmp/frame_rgb.raw + * $ gdcmimg --depth 16 --spp 3 --size 600,430 /tmp/frame_rgb.raw rgb.dcm + * $ gdcmviewer rgb.dcm + */ +using System; +using gdcm; + +public class ExtractImageRegion +{ + public static int Main(string[] args) + { + string filename = args[0]; + + // instantiate the reader: + gdcm.ImageRegionReader reader = new gdcm.ImageRegionReader(); + reader.SetFileName( filename ); + + // pull DICOM info: + if (!reader.ReadInformation()) return 1; + // Get file infos + gdcm.File f = reader.GetFile(); + + gdcm.LookupTable lut = reader.GetImage().GetLUT(); + + // get some info about image + UIntArrayType dims = ImageHelper.GetDimensionsValue(f); + PixelFormat pf = ImageHelper.GetPixelFormatValue (f); + int pixelsize = pf.GetPixelSize(); + + // buffer to get the pixels + byte[] buffer = new byte[ dims[0] * dims[1] * pixelsize ]; + + // output buffer for the RGB decoded image: + byte[] buffer2 = new byte[ dims[0] * dims[1] * pixelsize * 3 ]; + + // define a simple box region. + BoxRegion box = new BoxRegion(); + for (uint z = 0; z < dims[2]; z++) + { + // Define that I want the image 0, full size (dimx x dimy pixels) + // and do that for each z: + box.SetDomain(0, dims[0] - 1, 0, dims[1] - 1, z, z); + //System.Console.WriteLine( box.toString() ); + reader.SetRegion( box ); + + // reader will try to load the uncompressed image region into buffer. + // the call returns an error when buffer.Length is too small. For instance + // one can call: + // uint buf_len = reader.ComputeBufferLength(); // take into account pixel size + // to get the exact size of minimum buffer + if (reader.ReadIntoBuffer(buffer, (uint)buffer.Length)) + { + if( !lut.Decode( buffer2, (uint)buffer2.Length, buffer, (uint)buffer.Length ) ) + { + throw new Exception("can't decode"); + } + + using (System.IO.Stream stream = + System.IO.File.Open(@"/tmp/frame_rgb.raw", + System.IO.FileMode.Create)) + { + System.IO.BinaryWriter writer = new System.IO.BinaryWriter(stream); + writer.Write(buffer2); + } + } + else + { + throw new Exception("can't read pixels error"); + } + } + + return 0; + } +} diff --git a/gdcm/Examples/Csharp/ExtractOneFrame.cs b/gdcm/Examples/Csharp/ExtractOneFrame.cs new file mode 100644 index 0000000..6212adb --- /dev/null +++ b/gdcm/Examples/Csharp/ExtractOneFrame.cs @@ -0,0 +1,85 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +/* + * This small code shows how to use the gdcm.StreamImageReader API + * to read a single (whole) frame at a time + * The API allow extracting a smaller extent of the frame of course. + * It will write out the extracted frame in /tmp/frame.raw + * + * Usage: + * $ bin/ExtractOneFrame.exe input.dcm + */ +using System; +using gdcm; + +public class ExtractOneFrame +{ + public static int Main(string[] args) + { + string filename = args[0]; + + gdcm.StreamImageReader reader = new gdcm.StreamImageReader(); + + reader.SetFileName( filename ); + + if (!reader.ReadImageInformation()) return 1; + // Get file infos + gdcm.File f = reader.GetFile(); + + // get some info about image + UIntArrayType extent = ImageHelper.GetDimensionsValue(f); + //System.Console.WriteLine( extent[0] ); + uint dimx = extent[0]; + //System.Console.WriteLine( extent[1] ); + uint dimy = extent[1]; + //System.Console.WriteLine( extent[2] ); + uint dimz = extent[2]; + PixelFormat pf = ImageHelper.GetPixelFormatValue (f); + int pixelsize = pf.GetPixelSize(); + //System.Console.WriteLine( pixelsize ); + + // buffer to get the pixels + byte[] buffer = new byte[ dimx * dimy * pixelsize ]; + + for (int i = 0; i < dimz; i++) + { + // Define that I want the image 0, full size (dimx x dimy pixels) + reader.DefinePixelExtent(0, (ushort)dimx, 0, (ushort)dimy, (ushort)i, (ushort)(i+1)); + uint buf_len = reader.DefineProperBufferLength(); // take into account pixel size + //System.Console.WriteLine( buf_len ); + if( buf_len > buffer.Length ) + { + throw new Exception("buffer is too small for target"); + } + + if (reader.Read(buffer, (uint)buffer.Length)) + { + using (System.IO.Stream stream = + System.IO.File.Open(@"/tmp/frame.raw", + System.IO.FileMode.Create)) + { + System.IO.BinaryWriter writer = new System.IO.BinaryWriter(stream); + writer.Write(buffer); + } + } + else + { + throw new Exception("can't read pixels error"); + } + } + + return 0; + } +} diff --git a/gdcm/Examples/Csharp/FileAnonymize.cs b/gdcm/Examples/Csharp/FileAnonymize.cs new file mode 100644 index 0000000..526aed9 --- /dev/null +++ b/gdcm/Examples/Csharp/FileAnonymize.cs @@ -0,0 +1,56 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +/* + * Simple C# example + * + * Usage: + * $ mono bin/FileAnonymize.exe input.dcm output.dcm + */ +using System; +using gdcm; + +public class FileAnonymize +{ + public static int Main(string[] args) + { + string filename = args[0]; + string outfilename = args[1]; + + gdcm.FileAnonymizer fa = new gdcm.FileAnonymizer(); + fa.SetInputFileName( filename ); + fa.SetOutputFileName( outfilename ); + + // Empty Operations + // It will create elements, since those tags are non-registered public elements (2011): + fa.Empty( new Tag(0x0008,0x1313) ); + fa.Empty( new Tag(0x0008,0x1317) ); + // Remove Operations + // The following Tag are actually carefully chosen, since they refer to SQ: + fa.Remove( new Tag(0x0008,0x2112) ); + fa.Remove( new Tag(0x0008,0x9215) ); + // Replace Operations + // do not call replace operation on SQ attribute ! + fa.Replace( new Tag(0x0018,0x5100), "MYVALUE " ); + fa.Replace( new Tag(0x0008,0x1160), "MYOTHERVAL" ); + + if( !fa.Write() ) + { + System.Console.WriteLine( "Could not write" ); + return 1; + } + + return 0; + } +} diff --git a/gdcm/Examples/Csharp/FileChangeTS.cs b/gdcm/Examples/Csharp/FileChangeTS.cs new file mode 100644 index 0000000..6cfd45f --- /dev/null +++ b/gdcm/Examples/Csharp/FileChangeTS.cs @@ -0,0 +1,188 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +/* + * Simple C# example + * + * Shows multiple steps: + * Steps 1. + * Create a fake (dummy) DICOM file, with size 512 x 512 x 2 We use a small + * image to be able to create the volume in memory Of course you can use any + * existing DICOM instead + * + * Step 2. + * Hack the DICOM file to pretend the number of frames is 1000 (instead of 2) + * At this point in time this makes the DICOM file invalid (truncated). But the + * next step will fix this. + * + * Step 3. + * Use C# to create a binary data which will represent our source object for + * image. + * + * Step 4. + * We use gdcm.FileStreamer to merge the template DICOM file from Step 2, with + * the binary data from Step 3. We decide to read a scanline at a time, but + * this can be read with any number of bytes. AppendToDataElement() will always + * do the proper computation. + * + * Step 5. + * We compress this gigantic file, into [JPEG Lossless, Non-Hierarchical, + * First-Order Prediction (Process 14 [Selection Value 1])] + * + * Usage: + * $ mono bin/FileChangeTS.exe small.dcm big.dcm raw.data merge.dcm jpeg.dcm + */ +using System; +using System.IO; +using gdcm; + +public class FileChangeTS +{ + public static byte[] StrToByteArray(string str) + { + System.Text.ASCIIEncoding encoding=new System.Text.ASCIIEncoding(); + return encoding.GetBytes(str); + } + // Create a 256 x 256 Secondary Capture Image Storage + static private void CreateSmallDICOM(string fileName) + { + using( var writer = new gdcm.PixmapWriter() ) + { + gdcm.Pixmap img = writer.GetImage(); + img.SetNumberOfDimensions( 3 ); + img.SetDimension(0, 512 ); + img.SetDimension(1, 512 ); + img.SetDimension(2, 2 ); // fake a 3d volume + PhotometricInterpretation pi = new PhotometricInterpretation( PhotometricInterpretation.PIType.MONOCHROME2 ); + img.SetPhotometricInterpretation( pi ); + gdcm.DataElement pixeldata = new gdcm.DataElement( new gdcm.Tag(0x7fe0,0x0010) ); + byte[] buffer = new byte[ 512 * 512 * 2 ]; + pixeldata.SetByteValue( buffer, new gdcm.VL((uint)buffer.Length) ); + img.SetDataElement( pixeldata ); + + gdcm.File file = writer.GetFile(); + gdcm.DataSet ds = file.GetDataSet(); + gdcm.DataElement ms = new gdcm.DataElement(new gdcm.Tag(0x0008,0x0016)); + string mediastorage = "1.2.840.10008.5.1.4.1.1.7.2"; // Multi-frame Grayscale Byte Secondary Capture Image Storage + byte[] val = StrToByteArray(mediastorage); + ms.SetByteValue( val, new gdcm.VL( (uint)val.Length) ); + ds.Insert( ms ); + + writer.SetFileName( fileName ); + writer.Write(); + } + } + static private void CreateBigDICOM(string fileName, string outfilename) + { + using( var ano = new gdcm.FileAnonymizer() ) + { + // The following is somewhat dangerous, do not try at home: + string nframes = "1000"; + ano.Replace( new gdcm.Tag(0x0028,0x0008), nframes ); + ano.SetInputFileName(fileName); + ano.SetOutputFileName(outfilename); + ano.Write(); // at this point the DICOM is invalid ! + } + } + static private void CreateDummyFile(string fileName, long length) + { + using (var fileStream = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None)) + { + // Looks like C# always init to 0 (fallocate ?) + // For the purpose of the test we could add some random noise + fileStream.SetLength(length); + } + } + static private void ReadBytesIntoArray( byte[] array, FileStream source ) + { + int numBytesToRead = array.Length; + int numBytesRead = 0; + while (numBytesToRead > 0) + { + // According to spec: Read() may return anything from 0 to numBytesToRead. + int n = source.Read(array, numBytesRead, numBytesToRead); + + // Break when the end of the file is reached. + if (n == 0) + break; + + numBytesRead += n; + numBytesToRead -= n; + } + } + static private void AssembleDICOMAndRaw(string dicomfn, string rawdata, string outfn) + { + using ( var fs = new gdcm.FileStreamer() ) + { + fs.SetTemplateFileName(dicomfn); + fs.SetOutputFileName(outfn); + gdcm.Tag pixeldata = new gdcm.Tag(0x7fe0, 0x0010); + // FileStreamer support automatic checking of pixel data length + // based on DICOM attributes, only if we say so: + fs.CheckDataElement( pixeldata ); + // Declare we are working on Pixel Data attribute: + fs.StartDataElement( pixeldata ); + using (FileStream rawSource = new FileStream(rawdata, + FileMode.Open, FileAccess.Read)) + { + byte[] bytes = new byte[512]; + // Only read one scanline at a time + // We could have been reading more at once, if this is more efficient, + // AppendToDataElement will do the logic in all cases. + for( int i = 0; i < 512 * 1000; ++i ) + { + // Read the source file into a byte array. + ReadBytesIntoArray( bytes, rawSource ); + fs.AppendToDataElement( pixeldata, bytes, (uint)bytes.Length ); + } + } + if( !fs.StopDataElement( pixeldata ) ) + { + // Most likely an issue with Pixel Data Length computation: + throw new Exception("StopDataElement failed"); + } + } + } + static private void CompressIntoJPEG(string rawdicom, string jpegdicom) + { + using( var sfcts = FileChangeTransferSyntax.New() ) + { + // Need to retrieve the actual C++ reference, to pass to + // SimpleSubjectWatcher: + FileChangeTransferSyntax fcts = sfcts.__ref__(); + SimpleSubjectWatcher watcher = new SimpleSubjectWatcher(fcts, "FileChangeTransferSyntax"); + gdcm.TransferSyntax ts = new TransferSyntax( TransferSyntax.TSType.JPEGLosslessProcess14_1 ); + fcts.SetTransferSyntax( ts ); + fcts.SetInputFileName( rawdicom ); + fcts.SetOutputFileName( jpegdicom ); + fcts.Change(); + } + } + public static int Main(string[] args) + { + string filename = args[0]; + string outfilename = args[1]; + string rawfilename = args[2]; + string mergefn = args[3]; + string jpegfn = args[4]; + + CreateSmallDICOM(filename); + CreateBigDICOM(filename, outfilename); + CreateDummyFile(rawfilename, 512 * 512 * 1000 ); + AssembleDICOMAndRaw(outfilename, rawfilename, mergefn); + CompressIntoJPEG(mergefn, jpegfn); + + return 0; + } +} diff --git a/gdcm/Examples/Csharp/FileStreaming.cs b/gdcm/Examples/Csharp/FileStreaming.cs new file mode 100644 index 0000000..a47c63c --- /dev/null +++ b/gdcm/Examples/Csharp/FileStreaming.cs @@ -0,0 +1,59 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +/* + * Simple C# example + * + * Usage: + * $ mono bin/FileStreaming.exe gdcmData/CT_16b_signed-UsedBits13.dcm output.dcm + * + * The class will take care of group handling and will use the first available group: + * (0009,0012) ?? (LO) [MYTEST] # 6,1 Private Creator + */ +using System; +using gdcm; + +public class FileStreaming +{ + public static int Main(string[] args) + { + string filename = args[0]; + string outfilename = args[1]; + + gdcm.PrivateTag pt = new gdcm.PrivateTag( new gdcm.Tag(0x9,0x10), "MYTEST" ); + + gdcm.FileStreamer fs = new gdcm.FileStreamer(); + fs.SetTemplateFileName( filename ); + fs.SetOutputFileName( outfilename ); + + byte[] buffer = new byte[ 8192 ]; + uint len = (uint)buffer.Length; + + // In this example, we want that each newly created Private Attribute + // contains at most 1000 bytes of incoming dataset. + // We are also calling the function twice to check that appending mode is + // working from one call to the other. The last element will have a length + // of (2 * 8192) % 1000 = 384 + if( !fs.StartGroupDataElement( pt, 1000, 1 ) + || !fs.AppendToGroupDataElement( pt, buffer, len ) + || !fs.AppendToGroupDataElement( pt, buffer, len ) + || !fs.StopGroupDataElement( pt ) ) + { + System.Console.WriteLine( "Could not change private group" ); + return 1; + } + + return 0; + } +} diff --git a/gdcm/Examples/Csharp/GenerateDICOMDIR.cs b/gdcm/Examples/Csharp/GenerateDICOMDIR.cs new file mode 100644 index 0000000..57cb89f --- /dev/null +++ b/gdcm/Examples/Csharp/GenerateDICOMDIR.cs @@ -0,0 +1,62 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +/* + * Simple C# example to show how to use DICOMDIRGenerator + * + * Usage: + * $ export LD_LIBRARY_PATH=$HOME/Projects/gdcm/debug-gcc/bin + * $ mono bin/GenerateDICOMDIR.exe path output_filename + */ +using System; +using gdcm; + +public class GenerateDICOMDIR +{ + public static int Main(string[] args) + { + string directory = args[0]; + string outfilename = args[1]; + + Directory d = new Directory(); + uint nfiles = d.Load( directory, true ); + if(nfiles == 0) return 1; + //System.Console.WriteLine( "Files:\n" + d.toString() ); + + // Implement fast path ? + // Scanner s = new Scanner(); + + string descriptor = "My_Descriptor"; + FilenamesType filenames = d.GetFilenames(); + + gdcm.DICOMDIRGenerator gen = new DICOMDIRGenerator(); + gen.SetFilenames( filenames ); + gen.SetDescriptor( descriptor ); + if( !gen.Generate() ) + { + return 1; + } + + gdcm.FileMetaInformation.SetSourceApplicationEntityTitle( "GenerateDICOMDIR" ); + gdcm.Writer writer = new Writer(); + writer.SetFile( gen.GetFile() ); + writer.SetFileName( outfilename ); + if( !writer.Write() ) + { + return 1; + } + + return 0; + } +} diff --git a/gdcm/Examples/Csharp/GetArray.cs b/gdcm/Examples/Csharp/GetArray.cs new file mode 100644 index 0000000..3be5b79 --- /dev/null +++ b/gdcm/Examples/Csharp/GetArray.cs @@ -0,0 +1,85 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +/* + * Usage: + * $ export LD_LIBRARY_PATH=$HOME/Projects/gdcm/debug-gcc/bin + * $ mono bin/GetArray.exe gdcmData/012345.002.050.dcm + */ +using System; +using gdcm; + +public class GetArray +{ + public static int Main(string[] args) + { + string file1 = args[0]; + ImageReader reader = new ImageReader(); + reader.SetFileName( file1 ); + bool ret = reader.Read(); + if( !ret ) + { + return 1; + } + + Image image = reader.GetImage(); + + PixelFormat pixeltype = image.GetPixelFormat(); + + if( image.GetNumberOfDimensions() != 2 ) + { + // For the purpose of the test, exit early on + return 1; + } + uint dimx = image.GetDimension(0); + uint dimy = image.GetDimension(1); + uint npixels = dimx * dimy; + //LookupTable lut = image.GetLUT(); + //uint rl = lut.GetLUTLength( LookupTable.LookupTableType.RED ); + //byte[] rbuf = new byte[ rl ]; + //uint rl2 = lut.GetLUT( LookupTable.LookupTableType.RED, rbuf ); + //assert rl == rl2; + + //byte[] str1 = new byte[ image.GetBufferLength()]; + //image.GetBuffer( str1 ); + if( pixeltype.GetScalarType() == PixelFormat.ScalarType.UINT8 ) + { + System.Console.WriteLine( "Processing UINT8 image type" ); + byte[] str1 = new byte[ npixels ]; + image.GetArray( str1 ); + } + else if( pixeltype.GetScalarType() == PixelFormat.ScalarType.INT16 ) + { + System.Console.WriteLine( "Processing INT16 image type" ); + short[] str1 = new short[ npixels ]; + image.GetArray( str1 ); + } + else if( pixeltype.GetScalarType() == PixelFormat.ScalarType.UINT16 ) + { + System.Console.WriteLine( "Processing UINT16 image type" ); + ushort[] str1 = new ushort[ npixels ]; + image.GetArray( str1 ); + } + else + { + //System.Console.WriteLine( "Default (unhandled pixel format): " + pixeltype.toString() ); + System.Console.WriteLine( "Default (unhandled pixel format): " + pixeltype.GetScalarTypeAsString() ); + // Get bytes + byte[] str1 = new byte[ image.GetBufferLength()]; + image.GetBuffer( str1 ); + } + + return 0; + } +} diff --git a/gdcm/Examples/Csharp/ManipulateFile.cs b/gdcm/Examples/Csharp/ManipulateFile.cs new file mode 100644 index 0000000..d34d07f --- /dev/null +++ b/gdcm/Examples/Csharp/ManipulateFile.cs @@ -0,0 +1,61 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +/* + * Usage: + * $ export LD_LIBRARY_PATH=$HOME/Projects/gdcm/debug-gcc/bin + * $ mono bin/ManipulateFile.exe gdcmData/012345.002.050.dcm out.dcm + */ +using System; +using gdcm; + +public class ManipulateFile +{ + public static int Main(string[] args) + { + string file1 = args[0]; + string file2 = args[1]; + Reader reader = new Reader(); + reader.SetFileName( file1 ); + bool ret = reader.Read(); + if( !ret ) + { + return 1; + } + + Anonymizer ano = new Anonymizer(); + ano.SetFile( reader.GetFile() ); + ano.RemovePrivateTags(); + ano.RemoveGroupLength(); + Tag t = new Tag(0x10,0x10); + ano.Replace( t, "GDCM^Csharp^Test^Hello^World" ); + + UIDGenerator g = new UIDGenerator(); + ano.Replace( new Tag(0x0008,0x0018), g.Generate() ); + ano.Replace( new Tag(0x0020,0x000d), g.Generate() ); + ano.Replace( new Tag(0x0020,0x000e), g.Generate() ); + ano.Replace( new Tag(0x0020,0x0052), g.Generate() ); + + Writer writer = new Writer(); + writer.SetFileName( file2 ); + writer.SetFile( ano.GetFile() ); + ret = writer.Write(); + if( !ret ) + { + return 1; + } + + return 0; + } +} diff --git a/gdcm/Examples/Csharp/MpegVideoInfo.cs b/gdcm/Examples/Csharp/MpegVideoInfo.cs new file mode 100644 index 0000000..1f71210 --- /dev/null +++ b/gdcm/Examples/Csharp/MpegVideoInfo.cs @@ -0,0 +1,388 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + * This examples takes in a MPEG2 and write out a Video Endoscopic Imagae Storage + * encoded using MPEG2 @ Main Profile + * ref: http://chrisa.wordpress.com/2007/11/21/decoding-mpeg2-information/ + * See also: + * http://dvd.sourceforge.net/dvdinfo/mpeghdrs.html#gop + * http://cvs.linux.hr/cgi-bin/viewcvs.cgi/mpeg_mod/README.infompeg?view=markup + * http://www.guru-group.fi/~too/sw/m2vmp2cut/mpeg2info.c + */ + +/* + * Provides information about an MPEG2 file, including the duration, frame rate, aspect + * ratio, and resolution. Good information about the MPEG2 file structure that helps + * explain parts of the code can be found here: + * http://dvd.sourceforge.net/dvdinfo/mpeghdrs.html#gop + * + * Copyright (c) 2007 Chris Anderson (chrisa@wordpress.com) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + */ +using System; +using System.IO; +using gdcm; + +public class Mpeg2VideoInfo +{ + #region Member Variables + private TimeSpan m_startTime = TimeSpan.Zero; + private TimeSpan m_endTime = TimeSpan.Zero; + private TimeSpan m_duration = TimeSpan.Zero; + private eAspectRatios m_aspectRatio = eAspectRatios.Invalid; + private eFrameRates m_frameRate = 0; + private int m_pictureWidth = 0; + private int m_pictureHeight = 0; + #endregion + + #region Constants + private const byte PADDING_PACKET = 0xBE; + private const byte VIDEO_PACKET = 0xE0; + private const byte AUDIO_PACKET = 0xC0; + private const byte SYSTEM_PACKET = 0xBB; + private const byte TIMESTAMP_PACKET = 0xB8; + private const byte HEADER_PACKET = 0xB3; + + private const int BUFFER_SIZE = 8162; // 8K buffer + + private readonly static TimeSpan EMPTY_TIMESPAN = new TimeSpan(0, 0, -1); + #endregion + + #region Enumerations + public enum eFrameRates + { + Invalid, + PulldownNTSC, // 24000d/1001d = 23.976 Hz + Film, // 24 Hz + PAL, // 25 Hz + NTSC, // 30000d/1001d = 29.97 Hz + DropFrameNTSC, // 30 Hz + DoubleRatePAL, // 50 Hz + DoubleRateNTSC, // 59.97 Hz + DoubleRateDropFrameNTSC // 60 Hz + } + + public enum eAspectRatios + { + Invalid, + VGA, // 1/1 + StandardTV, // 4/3 + LargeTV, // 16/9 + Cinema // 2.21/1 + } + #endregion + + #region Constructor + public Mpeg2VideoInfo(string file) + { + ParseMpeg(file); + } + #endregion + + #region Public Properties + public TimeSpan StartTime + { + get { return m_startTime; } + } + + public TimeSpan EndTime + { + get { return m_endTime; } + } + + public TimeSpan Duration + { + get { return m_duration; } + } + + public eAspectRatios AspectRatio + { + get { return m_aspectRatio; } + } + + public eFrameRates FrameRate + { + get { return m_frameRate; } + } + + public int PictureWidth + { + get { return m_pictureWidth; } + } + + public int PictureHeight + { + get { return m_pictureHeight; } + } + #endregion + + #region Private Functions + /// + /// Handles the parsing of the MPEG file and retrieving MPEG data + /// + /// The path to the MPEG file to parse + private void ParseMpeg(string file) + { + FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); + BinaryReader br = new BinaryReader(fs); + + m_startTime = GetStartTimeStampInfo(br); + m_endTime = GetEndTimeStampInfo(br); + + m_duration = m_endTime.Subtract(m_startTime); + + GetHeaderInfo(br); + + br.Close(); + fs.Close(); + } + + /// + /// Looks for the first timestamp in the file and returns the value + /// (generally 0:00:00, but get it anyway) + /// + /// The binary reader providing random access to the MPEG file data + /// The timestamp value + private TimeSpan GetStartTimeStampInfo(BinaryReader br) + { + TimeSpan startTime = EMPTY_TIMESPAN; + byte[] buffer = new byte[BUFFER_SIZE]; + + br.BaseStream.Seek(0, SeekOrigin.Begin); + + while (startTime == EMPTY_TIMESPAN && br.BaseStream.Position < br.BaseStream.Length) + { + int readBytes = br.Read(buffer, 0, BUFFER_SIZE); + + for (int offset = 0; offset < readBytes - 8; offset++) + { + if (IsStreamMarker(ref buffer, offset, TIMESTAMP_PACKET)) + { + offset += 4; // Move to the data position which follows the stream header + uint timeStampEncoded = GetData(ref buffer, offset); + startTime = DecodeTimeStamp(timeStampEncoded); + + if (startTime != EMPTY_TIMESPAN) + break; + } + } + } + + return startTime; + } + + /// + /// Looks for the first timestamp in the file and returns the value + /// (generally 0:00:00, but get it anyway) + /// + /// The binary reader providing random access to the MPEG file data + /// The timestamp value + private TimeSpan GetEndTimeStampInfo(BinaryReader br) + { + TimeSpan endTime = EMPTY_TIMESPAN; + byte[] buffer = new byte[BUFFER_SIZE]; + + br.BaseStream.Seek(-BUFFER_SIZE, SeekOrigin.End); + + while (endTime == EMPTY_TIMESPAN && br.BaseStream.Position > BUFFER_SIZE) + { + int readBytes = br.Read(buffer, 0, BUFFER_SIZE); + + for (int offset = readBytes - 8; offset >= 0; offset--) + { + if (IsStreamMarker(ref buffer, offset, TIMESTAMP_PACKET)) + { + offset += 4; // Move to the data position which follows the stream header + uint timeStampEncoded = GetData(ref buffer, offset); + endTime = DecodeTimeStamp(timeStampEncoded); + + if (endTime != EMPTY_TIMESPAN) + break; + } + } + + br.BaseStream.Seek(-BUFFER_SIZE * 2, SeekOrigin.Current); + } + + return endTime; + } + + /// + /// Decodes the timestamp data as encoded in the MPEG file and returns the value + /// + /// The encoded timestamp data + /// The decoded timestamp data + private TimeSpan DecodeTimeStamp(uint timeStampEncoded) + { + TimeSpan timeStamp = EMPTY_TIMESPAN; + + // Mask out the bits containing the property we are after, then + // shift the data to the right to get its value + int hour = (int)(timeStampEncoded & 0x7C000000) >> 26; // Bits 31 -> 27 + int minute = (int)(timeStampEncoded & 0x03F00000) >> 20; // Bits 26 -> 21 + int second = (int)(timeStampEncoded & 0x0007E000) >> 13; // Bits 19 -> 14 + int frame = (int)(timeStampEncoded & 0x00001F80) >> 7; // Bits 13 -> 8 - not used, but included for completeness + + timeStamp = new TimeSpan(hour, minute, second); + return timeStamp; + } + + /// + /// Obtains the header data located in the MPEG file and decodes it + /// + /// The binary reader providing random access to the MPEG file data + private void GetHeaderInfo(BinaryReader br) + { + byte[] buffer = new byte[BUFFER_SIZE]; + + br.BaseStream.Seek(0, SeekOrigin.Begin); + br.Read(buffer, 0, BUFFER_SIZE); + + for (int offset = 0; offset < buffer.Length - 4; offset++) + { + if (IsStreamMarker(ref buffer, offset, HEADER_PACKET)) + { + offset += 4; // Move to the data position which follows the stream header + uint headerData = GetData(ref buffer, offset); + + // Mask out the bits containing the property we are after, then + // shift the data to the right to get its value + m_pictureWidth = (int)(headerData & 0xFFF00000) >> 20; + m_pictureHeight = (int)(headerData & 0x000FFF00) >> 8; + + uint aspectRatioIndex = (headerData & 0x000000F0) >> 4; + uint fpsIndex = headerData & 0x0000000F; + + m_aspectRatio = (eAspectRatios)fpsIndex; + m_frameRate = (eFrameRates)fpsIndex; + + break; + } + } + } + + /// + /// Combine 4 bytes of data into an integer + /// + /// The buffer containing the data + /// The position within the buffer to get the required 4 bytes of data + /// An integer containing the combined 4 bytes of data + private uint GetData(ref byte[] buffer, int offset) + { + return (uint) ((buffer[offset] << 24) | + (buffer[offset + 1] << 16) | + (buffer[offset + 2] << 8) | + (buffer[offset + 3])); + } + + /// + /// The MPEG file contains numerous stream markers representing the type of + /// data to follow. This function looks at data at a position in the buffer to + /// determine whether it represents a marker of a specified type + /// + /// The buffer containing the data to identify the marker within + /// The position within the buffer to test for the marker + /// The type of marker to match against + /// Whether the specified position contains the specified marker + private bool IsStreamMarker(ref byte[] buffer, int offset, byte markerType) + { + return (buffer[offset] == 0x00 && + buffer[offset + 1] == 0x00 && + buffer[offset + 2] == 0x01 && + buffer[offset + 3] == markerType); + } + #endregion + public static int Main(string[] args) + { + string file1 = args[0]; + Mpeg2VideoInfo info = new Mpeg2VideoInfo(file1); + System.Console.WriteLine( info.StartTime ); + System.Console.WriteLine( info.EndTime ); + System.Console.WriteLine( info.Duration ); + System.Console.WriteLine( info.AspectRatio ); + System.Console.WriteLine( info.FrameRate ); + System.Console.WriteLine( info.PictureWidth ); + System.Console.WriteLine( info.PictureHeight ); + + ImageReader r = new ImageReader(); + //Image image = new Image(); + Image image = r.GetImage(); + image.SetNumberOfDimensions( 3 ); + DataElement pixeldata = new DataElement( new gdcm.Tag(0x7fe0,0x0010) ); + + System.IO.FileStream infile = + new System.IO.FileStream(file1, System.IO.FileMode.Open, System.IO.FileAccess.Read); + uint fsize = gdcm.PosixEmulation.FileSize(file1); + + byte[] jstream = new byte[fsize]; + infile.Read(jstream, 0 , jstream.Length); + + SmartPtrFrag sq = SequenceOfFragments.New(); + Fragment frag = new Fragment(); + frag.SetByteValue( jstream, new gdcm.VL( (uint)jstream.Length) ); + sq.AddFragment( frag ); + pixeldata.SetValue( sq.__ref__() ); + + // insert: + image.SetDataElement( pixeldata ); + + PhotometricInterpretation pi = new PhotometricInterpretation( PhotometricInterpretation.PIType.YBR_PARTIAL_420 ); + image.SetPhotometricInterpretation( pi ); + // FIXME hardcoded: + PixelFormat pixeltype = new PixelFormat(3,8,8,7); + image.SetPixelFormat( pixeltype ); + + // FIXME hardcoded: + TransferSyntax ts = new TransferSyntax( TransferSyntax.TSType.MPEG2MainProfile); + image.SetTransferSyntax( ts ); + + image.SetDimension(0, (uint)info.PictureWidth); + image.SetDimension(1, (uint)info.PictureHeight); + image.SetDimension(2, 721); + + ImageWriter writer = new ImageWriter(); + gdcm.File file = writer.GetFile(); + file.GetHeader().SetDataSetTransferSyntax( ts ); + Anonymizer anon = new Anonymizer(); + anon.SetFile( file ); + + MediaStorage ms = new MediaStorage( MediaStorage.MSType.VideoEndoscopicImageStorage); + + UIDGenerator gen = new UIDGenerator(); + anon.Replace( new Tag(0x0008,0x16), ms.GetString() ); + anon.Replace( new Tag(0x0018,0x40), "25" ); + anon.Replace( new Tag(0x0018,0x1063), "40.000000" ); + anon.Replace( new Tag(0x0028,0x34), "4\\3" ); + anon.Replace( new Tag(0x0028,0x2110), "01" ); + + writer.SetImage( image ); + writer.SetFileName( "dummy.dcm" ); + if( !writer.Write() ) + { + System.Console.WriteLine( "Could not write" ); + return 1; + } + + return 0; + } +} diff --git a/gdcm/Examples/Csharp/NewSequence.cs b/gdcm/Examples/Csharp/NewSequence.cs new file mode 100644 index 0000000..4f7f84b --- /dev/null +++ b/gdcm/Examples/Csharp/NewSequence.cs @@ -0,0 +1,81 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +/* + * Usage: + * $ export LD_LIBRARY_PATH=$HOME/Projects/gdcm/debug-gcc/bin + * $ mono bin/NewSequence.exe gdcmData/012345.002.050.dcm out.dcm + */ +using System; +//using gdcm; + +public class NewSequence +{ + public static byte[] StrToByteArray(string str) + { + System.Text.ASCIIEncoding encoding=new System.Text.ASCIIEncoding(); + return encoding.GetBytes(str); + } + + public static int Main(string[] argv) + { + string file1 = argv[0]; + string file2 = argv[1]; + + gdcm.Reader r = new gdcm.Reader(); + r.SetFileName( file1 ); + if ( ! r.Read() ) + { + return 1; + } + + gdcm.File f = r.GetFile(); + gdcm.DataSet ds = f.GetDataSet(); + // tsis = gdcm.Tag(0x0008,0x2112) # SourceImageSequence + + // Create a dataelement + gdcm.DataElement de = new gdcm.DataElement(new gdcm.Tag(0x0010, 0x2180)); + string occ = "Occupation"; + de.SetByteValue( StrToByteArray(occ), new gdcm.VL((uint)occ.Length)); + de.SetVR(new gdcm.VR(gdcm.VR.VRType.SH)); + + // Create an item + gdcm.Item it = new gdcm.Item(); + it.SetVLToUndefined(); // Needed to not popup error message + //it.InsertDataElement(de) + gdcm.DataSet nds = it.GetNestedDataSet(); + nds.Insert(de); + + // Create a Sequence + gdcm.SmartPtrSQ sq = gdcm.SequenceOfItems.New(); + sq.SetLengthToUndefined(); + sq.AddItem(it); + + // Insert sequence into data set + gdcm.DataElement des = new gdcm.DataElement(new gdcm.Tag(0x0400,0x0550)); + des.SetVR(new gdcm.VR(gdcm.VR.VRType.SQ)); + des.SetValue(sq.__ref__()); + des.SetVLToUndefined(); + + ds.Insert(des); + + gdcm.Writer w = new gdcm.Writer(); + w.SetFile( f ); + w.SetFileName( file2 ); + if ( !w.Write() ) + return 1; + + return 0; + } +} diff --git a/gdcm/Examples/Csharp/ReformatFile.cs b/gdcm/Examples/Csharp/ReformatFile.cs new file mode 100644 index 0000000..f0116e1 --- /dev/null +++ b/gdcm/Examples/Csharp/ReformatFile.cs @@ -0,0 +1,88 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +/* + * Simple C# example + * + * Usage: + * $ export LD_LIBRARY_PATH=$HOME/Projects/gdcm/debug-gcc/bin + * $ mono bin/ReformatFile.exe input.dcm output.dcm + */ +using System; +using gdcm; + +public class ReformatFile +{ + public static int Main(string[] args) + { + gdcm.FileMetaInformation.SetSourceApplicationEntityTitle( "My Reformat App" ); + + // http://www.oid-info.com/get/1.3.6.1.4.17434 + string THERALYS_ORG_ROOT = "1.3.6.1.4.17434"; + gdcm.UIDGenerator.SetRoot( THERALYS_ORG_ROOT ); + System.Console.WriteLine( "Root dir is now: " + gdcm.UIDGenerator.GetRoot() ); + + string filename = args[0]; + string outfilename = args[1]; + + Reader reader = new Reader(); + reader.SetFileName( filename ); + if( !reader.Read() ) + { + System.Console.WriteLine( "Could not read: " + filename ); + return 1; + } + + UIDGenerator uid = new UIDGenerator(); // helper for uid generation + FileDerivation fd = new FileDerivation(); + // For the pupose of this execise we will pretend that this image is referencing + // two source image (we need to generate fake UID for that). + string ReferencedSOPClassUID = "1.2.840.10008.5.1.4.1.1.7"; // Secondary Capture + fd.AddReference( ReferencedSOPClassUID, uid.Generate() ); + fd.AddReference( ReferencedSOPClassUID, uid.Generate() ); + + // Again for the purpose of the exercise we will pretend that the image is a + // multiplanar reformat (MPR): + // CID 7202 Source Image Purposes of Reference + // {"DCM",121322,"Source image for image processing operation"}, + fd.SetPurposeOfReferenceCodeSequenceCodeValue( 121322 ); + // CID 7203 Image Derivation + // { "DCM",113072,"Multiplanar reformatting" }, + fd.SetDerivationCodeSequenceCodeValue( 113072 ); + fd.SetFile( reader.GetFile() ); + // If all Code Value are ok the filter will execute properly + if( !fd.Derive() ) + { + return 1; + } + + gdcm.FileMetaInformation fmi = reader.GetFile().GetHeader(); + // The following three lines make sure to regenerate any value: + fmi.Remove( new gdcm.Tag(0x0002,0x0012) ); + fmi.Remove( new gdcm.Tag(0x0002,0x0013) ); + fmi.Remove( new gdcm.Tag(0x0002,0x0016) ); + + Writer writer = new Writer(); + writer.SetFileName( outfilename ); + writer.SetFile( fd.GetFile() ); + if( !writer.Write() ) + { + System.Console.WriteLine( "Could not write: " + outfilename ); + return 1; + } + + + return 0; + } +} diff --git a/gdcm/Examples/Csharp/RescaleImage.cs b/gdcm/Examples/Csharp/RescaleImage.cs new file mode 100644 index 0000000..2fd6517 --- /dev/null +++ b/gdcm/Examples/Csharp/RescaleImage.cs @@ -0,0 +1,66 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +/* + * Usage: + * $ export LD_LIBRARY_PATH=$HOME/Projects/gdcm/debug-gcc/bin + * $ mono bin/DecompressImage.exe gdcmData/012345.002.050.dcm rescaled.dcm + */ +using System; +using gdcm; + +public class DecompressImage +{ + public static int Main(string[] args) + { + string file1 = args[0]; + ImageReader reader = new ImageReader(); + reader.SetFileName( file1 ); + bool ret = reader.Read(); + if( !ret ) + { + return 1; + } + + Image image = reader.GetImage(); + PixelFormat pixeltype = image.GetPixelFormat(); + + Rescaler r = new Rescaler(); + r.SetIntercept( 0 ); + r.SetSlope( 1.2 ); + r.SetPixelFormat( pixeltype ); + PixelFormat outputpt = new PixelFormat( r.ComputeInterceptSlopePixelType() ); + + System.Console.WriteLine( "pixeltype" ); + System.Console.WriteLine( pixeltype.toString() ); + System.Console.WriteLine( "outputpt" ); + System.Console.WriteLine( outputpt.toString() ); + + uint len = image.GetBufferLength(); + short[] input = new short[ len / 2 ]; // sizeof(short) == 2 + image.GetArray( input ); + + double[] output = new double[ len / 2 ]; + r.Rescale( output, input, len ); + + // First Pixel is: + System.Console.WriteLine( "Input:" ); + System.Console.WriteLine( input[0] ); + + System.Console.WriteLine( "Output:" ); + System.Console.WriteLine( output[0] ); + + return 0; + } +} diff --git a/gdcm/Examples/Csharp/ScanDirectory.cs b/gdcm/Examples/Csharp/ScanDirectory.cs new file mode 100644 index 0000000..d82beaf --- /dev/null +++ b/gdcm/Examples/Csharp/ScanDirectory.cs @@ -0,0 +1,48 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +/* + * Usage: + * $ export LD_LIBRARY_PATH=$HOME/Projects/gdcm/debug-gcc/bin + * $ mono bin/ScanDirectory.exe /path/to/gdcmData/ + */ +using System; +using gdcm; + +public class ScanDirectory +{ + public static int Main(string[] args) + { + string directory = args[0]; + Tag t = new Tag(0x8,0x8); + + Directory d = new Directory(); + uint nfiles = d.Load( directory ); + if(nfiles == 0) return 1; + //System.Console.WriteLine( "Files:\n" + d.toString() ); + + //Scanner s = new Scanner(); + SmartPtrScan sscan = Scanner.New(); + Scanner s = sscan.__ref__(); + SimpleSubjectWatcher watcher = new SimpleSubjectWatcher(s, "MySimple"); + s.AddTag( t ); + bool b = s.Scan( d.GetFilenames() ); + if(!b) return 1; + + System.Console.WriteLine( "Scan:\n" + s.toString() ); + + System.Console.WriteLine( "success" ); + return 0; + } +} diff --git a/gdcm/Examples/Csharp/SendFileSCU.cs b/gdcm/Examples/Csharp/SendFileSCU.cs new file mode 100644 index 0000000..f28708a --- /dev/null +++ b/gdcm/Examples/Csharp/SendFileSCU.cs @@ -0,0 +1,41 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +/* + * Usage: + * $ export LD_LIBRARY_PATH=$HOME/Perso/gdcm-gcc/bin + * $ mono bin/SendFileSCU.exe server port input.dcm + */ +using System; +using gdcm; + +public class SendFileSCU +{ + public static int Main(string[] args) + { + string server = args[0]; + ushort port = ushort.Parse(args[1]); + string filename = args[2]; + + bool b = CompositeNetworkFunctions.CEcho( server, port ); + if( !b ) return 1; + + FilenamesType files = new FilenamesType(); + files.Add( filename ); + b = CompositeNetworkFunctions.CStore( server, port, files ); + if( !b ) return 1; + + return 0; + } +} diff --git a/gdcm/Examples/Csharp/SimplePrint.cs b/gdcm/Examples/Csharp/SimplePrint.cs new file mode 100644 index 0000000..63c2805 --- /dev/null +++ b/gdcm/Examples/Csharp/SimplePrint.cs @@ -0,0 +1,79 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + Convertor convertor = new Convertor(); + int a = convertor.Convert( some_int_blob ); + double b = convertor.Convert( some_double_blob ); +*/ + +/* + * Usage: + * $ export LD_LIBRARY_PATH=$HOME/Projects/gdcm/debug-gcc/bin + * $ mono bin/SimplePrint.exe gdcmData/012345.002.050.dcm + */ +using System; +using gdcm; + +public class SimplePrint +{ + public static void RecurseDataSet(File f, DataSet ds, string indent) + { + CSharpDataSet cds = new CSharpDataSet(ds); + while(!cds.IsAtEnd()) + { + DataElement de = cds.GetCurrent(); + // Compute VR from the toplevel file, and the currently processed dataset: + VR vr = DataSetHelper.ComputeVR(f, ds, de.GetTag() ); + + if( vr.Compatible( new VR(VR.VRType.SQ) ) ) + { + uint uvl = (uint)de.GetVL(); // Test cast is ok + System.Console.WriteLine( indent + de.GetTag().toString() + ":" + uvl ); // why not ? + //SequenceOfItems sq = de.GetSequenceOfItems(); + // GetValueAsSQ handle more cases than GetSequenceOfItems + SmartPtrSQ sq = de.GetValueAsSQ(); + uint n = sq.GetNumberOfItems(); + for( uint i = 1; i <= n; i++) // item starts at 1, not 0 + { + Item item = sq.GetItem( i ); + DataSet nested = item.GetNestedDataSet(); + RecurseDataSet( f, nested, indent + " " ); + } + } + else + { + System.Console.WriteLine( indent + de.toString() ); + } + cds.Next(); + } + } + + public static int Main(string[] args) + { + string filename = args[0]; + Reader reader = new Reader(); + reader.SetFileName( filename ); + bool ret = reader.Read(); + if( !ret ) + { + return 1; + } + File f = reader.GetFile(); + DataSet ds = f.GetDataSet(); + + RecurseDataSet( f, ds, "" ); + + return 0; + } +} diff --git a/gdcm/Examples/Csharp/SimplePrintPatientName.cs b/gdcm/Examples/Csharp/SimplePrintPatientName.cs new file mode 100644 index 0000000..680c831 --- /dev/null +++ b/gdcm/Examples/Csharp/SimplePrintPatientName.cs @@ -0,0 +1,60 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + * Usage: + * $ export LD_LIBRARY_PATH=$HOME/Perso/gdcm/debug-gcc/bin + * $ mono bin/SimplePrintPatientName.exe gdcmData/012345.002.050.dcm + */ +/* + This example was provided by Jonathan Morra /jonmorra gmail com/ + on the gdcm mailing list (Fri, 28 May 2010) +*/ +using System; +using gdcm; + +namespace GDCMTest +{ + class SimplePrintPatientName + { + static int Main(string[] args) + { + if (args.Length != 1) + { + Console.WriteLine("This program prints the patient name of a dicom file with gdcm"); + Console.WriteLine("Usage: [input.dcm]"); + return 1; + } + + gdcm.Reader reader = new gdcm.Reader(); + reader.SetFileName(args[0]); + bool ret = reader.Read(); + //TagSetType tst = new TagSetType(); + //tst.Add( new Tag(0x7fe0,0x10) ); + //bool ret = reader.ReadUpToTag( new Tag(0x88,0x200), tst ); + if( !ret ) + { + return 1; + } + + gdcm.File file = reader.GetFile(); + + gdcm.StringFilter filter = new gdcm.StringFilter(); + filter.SetFile(file); + string value = filter.ToString(new gdcm.Tag(0x0010, 0x0010)); + + Console.WriteLine("Patient Name: " + value); + return 0; + } + } +} diff --git a/gdcm/Examples/Csharp/SortImage2.cs b/gdcm/Examples/Csharp/SortImage2.cs new file mode 100644 index 0000000..e206e8a --- /dev/null +++ b/gdcm/Examples/Csharp/SortImage2.cs @@ -0,0 +1,37 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +/* + * Usage: + * $ export LD_LIBRARY_PATH=$HOME/Projects/gdcm/debug-gcc/bin + * $ mono bin/SortImage.exe gdcmData/012345.002.050.dcm out.dcm + */ +using System; +using gdcm; + +public class SortImage2 +{ + bool mysort(DataSet ds1, DataSet ds2) + { + return false; + } + + public static int Main(string[] args) + { + Sorter sorter = new Sorter(); + sorter.SetSortFunction( mysort ); + + return 0; + } +} diff --git a/gdcm/Examples/Csharp/StandardizeFiles.cs b/gdcm/Examples/Csharp/StandardizeFiles.cs new file mode 100644 index 0000000..5d5be4d --- /dev/null +++ b/gdcm/Examples/Csharp/StandardizeFiles.cs @@ -0,0 +1,115 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +/* + * Simple C# example to show how one would 'Standardize' a DICOM File-Set + * + * Usage: + * $ export LD_LIBRARY_PATH=$HOME/Projects/gdcm/debug-gcc/bin + * $ mono bin/StandardizeFiles.exe input_path output_path + */ +using System; +using gdcm; + +public class StandardizeFiles +{ + public static bool ProcessOneFile( string filename, string outfilename ) + { + PixmapReader reader = new PixmapReader(); + reader.SetFileName( filename ); + if( !reader.Read() ) + { + System.Console.WriteLine( "Could not read: " + filename ); + return false; + } + + ImageChangeTransferSyntax change = new ImageChangeTransferSyntax(); + change.SetForce( false ); // do we really want to recompress when input is alread compressed in same alg ? + change.SetCompressIconImage( false ); // Keep it simple + change.SetTransferSyntax( new TransferSyntax( TransferSyntax.TSType.JPEG2000Lossless ) ); + change.SetInput( reader.GetPixmap() ); + if( !change.Change() ) + { + System.Console.WriteLine( "Could not change: " + filename ); + return false; + } + + gdcm.FileMetaInformation fmi = reader.GetFile().GetHeader(); + // The following three lines make sure to regenerate any value: + fmi.Remove( new gdcm.Tag(0x0002,0x0012) ); + fmi.Remove( new gdcm.Tag(0x0002,0x0013) ); + fmi.Remove( new gdcm.Tag(0x0002,0x0016) ); + + PixmapWriter writer = new PixmapWriter(); + writer.SetFileName( outfilename ); + writer.SetFile( reader.GetFile() ); + gdcm.Pixmap pixout = ((PixmapToPixmapFilter)change).GetOutput(); + + writer.SetPixmap( pixout ); + if( !writer.Write() ) + { + System.Console.WriteLine( "Could not write: " + outfilename ); + return false; + } + + return true; + } + + public static int Main(string[] args) + { + gdcm.FileMetaInformation.SetSourceApplicationEntityTitle( "My Standardize App" ); + + // http://www.oid-info.com/get/1.3.6.1.4.17434 + string THERALYS_ORG_ROOT = "1.3.6.1.4.17434"; + gdcm.UIDGenerator.SetRoot( THERALYS_ORG_ROOT ); + System.Console.WriteLine( "Root dir is now: " + gdcm.UIDGenerator.GetRoot() ); + + string dir1 = args[0]; + string dir2 = args[1]; + + // Check input is valid: + if( !gdcm.PosixEmulation.FileIsDirectory(dir1) ) + { + System.Console.WriteLine( "Input directory: " + dir1 + " does not exist. Sorry" ); + return 1; + } + if( !gdcm.PosixEmulation.FileIsDirectory(dir2) ) + { + System.Console.WriteLine( "Output directory: " + dir2 + " does not exist. Sorry" ); + return 1; + } + + Directory d = new Directory(); + uint nfiles = d.Load( dir1, true ); + if(nfiles == 0) return 1; + + // Process all filenames: + FilenamesType filenames = d.GetFilenames(); + for( uint i = 0; i < nfiles; ++i ) + { + string filename = filenames[ (int)i ]; + string outfilename = filename.Replace( dir1, dir2 ); + System.Console.WriteLine( "Filename: " + filename ); + System.Console.WriteLine( "Out Filename: " + outfilename ); + if( !ProcessOneFile( filename, outfilename ) ) + { + System.Console.WriteLine( "Could not process filename: " + filename ); + //return 1; + } + } + + + return 0; + } +} diff --git a/gdcm/Examples/Cxx/CMakeLists.txt b/gdcm/Examples/Cxx/CMakeLists.txt new file mode 100644 index 0000000..37fd2e0 --- /dev/null +++ b/gdcm/Examples/Cxx/CMakeLists.txt @@ -0,0 +1,160 @@ +# Build the GDCM examples + +# Add the include paths +include_directories( + "${GDCM_BINARY_DIR}/Source/Common" + "${GDCM_SOURCE_DIR}/Source/Common" + "${GDCM_SOURCE_DIR}/Source/DataStructureAndEncodingDefinition" + "${GDCM_SOURCE_DIR}/Source/MediaStorageAndFileFormat" + "${GDCM_SOURCE_DIR}/Source/InformationObjectDefinition" + "${GDCM_SOURCE_DIR}/Source/MessageExchangeDefinition" + +# FIXME: + "${GDCM_SOURCE_DIR}/Source/DataDictionary" + "${GDCM_SOURCE_DIR}/Utilities" + ) +# error C1083: Cannot open include file: 'zconf.h' +if(NOT GDCM_USE_SYSTEM_ZLIB) +include_directories( + "${GDCM_BINARY_DIR}/Utilities/gdcmzlib" +) +endif() + +if(GDCM_BINARY_DIR) +find_package(SQLITE3) + +find_package(MAGIC) + +find_package(Qt4 4.4.3 COMPONENTS QtCore QtGui) +# cmake 2.6.4 does not set it to advanced +mark_as_advanced(QT_QMAKE_EXECUTABLE) + +endif() + +set(EXAMPLES_SRCS + DumpGEMSMovieGroup + QIDO-RS + DumpExamCard + DumpPhilipsECHO + ExtractIconFromFile + CreateJPIPDataSet + DumpADAC + DumpImageHeaderInfo + ReadMultiTimesException + pmsct_rgb1 + GenAllVR + ELSCINT1WaveToText + DiscriminateVolume + GetSubSequenceData + GenLongSeqs + ReadGEMSSDO + DiffFile + SimpleScanner + TraverseModules + GetSequenceUltrasound + ReadAndPrintAttributes + ChangeSequenceUltrasound + LargeVRDSExplicit + ExtractEncryptedContent + ReadAndDumpDICOMDIR + GenerateStandardSOPClasses + ClinicalTrialAnnotate + CheckBigEndianBug + DuplicatePCDE + CreateARGBImage + CreateCMYKImage + CompressImage + FixBrokenJ2K + GenFakeImage + GenFakeIdentifyFile + HelloVizWorld + HelloWorld + MergeTwoFiles + MrProtocol + PatchFile + ReadExplicitLengthSQIVR + SortImage + csa2img + iU22tomultisc + rle2img + uid_unique + PublicDict + GenSeqs + GetJPEGSamplePrecision +) +if(GDCM_USE_OPENJPEG_V2) +set(EXAMPLES_SRCS + ${EXAMPLES_SRCS} + StreamImageReaderTest + Extracting_All_Resolution + Fake_Image_Using_Stream_Image_Writer + ) +endif() +if(GDCM_USE_JPEGLS) +set(EXAMPLES_SRCS + ${EXAMPLES_SRCS} + FixJAIBugJPEGLS + ) +endif() + +if(QT4_FOUND) + include(${QT_USE_FILE}) + add_executable(ConvertToQImage ConvertToQImage.cxx) + # qtGUI will resolved QImage symbol + # qtcore will resolve qstring symbols + target_link_libraries(ConvertToQImage gdcmMSFF ${QT_LIBRARIES}) + + add_executable(ReadUTF8QtDir ReadUTF8QtDir.cxx) + target_link_libraries(ReadUTF8QtDir gdcmMSFF ${QT_LIBRARIES}) + add_executable(CStoreQtProgress CStoreQtProgress.cxx) + target_link_libraries(CStoreQtProgress gdcmMEXD gdcmMSFF ${QT_LIBRARIES}) +endif() + +if(MAGIC_FOUND) + include_directories(${MAGIC_INCLUDE_DIRS}) + add_executable(EncapsulateFileInRawData EncapsulateFileInRawData.cxx) + target_link_libraries(EncapsulateFileInRawData gdcmMSFF ${MAGIC_LIBRARIES}) +endif() + +if(SQLITE3_FOUND) + include_directories(${SQLITE3_INCLUDE_DIRS}) + add_executable(DumpToSQLITE3 DumpToSQLITE3.cxx) + target_link_libraries(DumpToSQLITE3 gdcmMSFF ${SQLITE3_LIBRARIES}) +endif() + +if(GDCM_BUILD_TESTING) +set(EXAMPLES_SRCS + ${EXAMPLES_SRCS} + VolumeSorter +) +endif() + +if(BUILD_SHARED_LIBS) + set_source_files_properties(FixJAIBugJPEGLS.cxx + PROPERTIES + COMPILE_FLAGS -DCHARLS_SHARED + ) +endif() + +foreach(example ${EXAMPLES_SRCS}) + add_executable(${example} ${example}.cxx) + if(${example} STREQUAL "FixJAIBugJPEGLS") + target_link_libraries(${example} gdcmMSFF ${GDCM_CHARLS_LIBRARIES}) + elseif(${example} STREQUAL "DumpPhilipsECHO") + target_link_libraries(${example} gdcmMSFF ${GDCM_ZLIB_LIBRARIES}) + else() + target_link_libraries(${example} gdcmMSFF) + endif() +endforeach() + +if(CMAKE_COMPILER_IS_GNUCXX AND MINGW) +#../../bin/libgdcmDSED.dll.a(d000469.o)(.text+0x0): multiple definition of `gdcm::VL gdcm::Item::GetLength() const' +#CMakeFiles/ReadExplicitLengthSQIVR.dir/ReadExplicitLengthSQIVR.obj(.text$_ZNK4gdcm4Item9GetLengthINS_19ImplicitDataElementEEENS_2VLEv[gdcm::VL gdcm::Item::GetLength() const]+0x0):ReadExplicitLengthSQIVR.cxx: first defined here +#../../bin/libgdcmDSED.dll.a(d000252.o)(.text+0x0): multiple definition of `std::istream& gdcm::DataSet::ReadNested(std::istream&)' +#CMakeFiles/ReadExplicitLengthSQIVR.dir/ReadExplicitLengthSQIVR.obj(.text$_ZN4gdcm7DataSet10ReadNestedINS_19ImplicitDataElementENS_11SwapperDoOpEEERSiS4_[std::basic_istream >& gdcm::DataSet::ReadNested(std::basic_istream >&)]+0x0):ReadExplicitLengthSQIVR.cxx: first defined here +#../../bin/libgdcmDSED.dll.a(d000253.o)(.text+0x0): multiple definition of `std::istream& gdcm::DataSet::ReadNested(std::istream&)' +#CMakeFiles/ReadExplicitLengthSQIVR.dir/ReadExplicitLengthSQIVR.obj(.text$_ZN4gdcm7DataSet10ReadNestedINS_19ImplicitDataElementENS_11SwapperNoOpEEERSiS4_[std::basic_istream >& gdcm::DataSet::ReadNested(std::basic_istream >&)]+0x0):ReadExplicitLengthSQIVR.cxx: first defined here +#../../bin/libgdcmDSED.dll.a(d000271.o)(.text+0x0): multiple definition of `std::istream& gdcm::DataSet::ReadWithLength(std::istream&, gdcm::VL&)' + + set_target_properties( ReadExplicitLengthSQIVR PROPERTIES LINK_FLAGS "-Wl,--allow-multiple-definition") +endif() diff --git a/gdcm/Examples/Cxx/CStoreQtProgress.cxx b/gdcm/Examples/Cxx/CStoreQtProgress.cxx new file mode 100644 index 0000000..e006a33 --- /dev/null +++ b/gdcm/Examples/Cxx/CStoreQtProgress.cxx @@ -0,0 +1,169 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + * This small example show how one can use the virtual function + * mechanism of the SimpleSubjectWatcher class to redirect progress + * report to a custom Qt classes + * + * http://doc.qt.nokia.com/latest/qprogressdialog.html + * + * Usage: + * CStoreQtProgress dicom.example.com 11112 gdcmData/MR_Spectroscopy_SIEMENS_OF.dcm + * + */ + +#include "gdcmServiceClassUser.h" +#include "gdcmSimpleSubjectWatcher.h" +#include "gdcmProgressEvent.h" +#include "gdcmDirectory.h" +#include "gdcmPresentationContextGenerator.h" + +#include +#include +#include + +namespace gdcm { +/* + * This class is a little more complicated than what this example demonstrate + * This watcher is capable of handling nested progress. Since the Progress + * grows from [0 to 1] on a per file basis and we only have one instance of a + * watcher per association, we need some calculation to compute the global + * (total) progress + * In fact we simply divide the per-file progress by the number of files. + * + * This QtWatcher class will then update the progress bar according to the + * progress. + */ +class MyQtWatcher : public SimpleSubjectWatcher +{ + size_t nfiles; + double progress; + size_t index; + double refprogress; + QWidget* win; + QProgressDialog* qtprogress; +public: + MyQtWatcher(Subject * s, const char *comment = "", QWidget *w = NULL, QProgressDialog* p = NULL, size_t n = 1): + SimpleSubjectWatcher(s,comment),nfiles(n),progress(0),index(0),refprogress(0),win(w),qtprogress(p){} + void ShowIteration() + { + index++; + assert( index <= nfiles ); + // update refprogess (we are moving to the next file) + refprogress = progress; + } + void ShowProgress(Subject *, const Event &evt) + { + // Retrieve the ProgressEvent: + const ProgressEvent &pe = dynamic_cast(evt); + // compute global progress: + progress = refprogress + (1. / (double)nfiles ) * pe.GetProgress(); + // Print Global and local progress to stdout: + std::cout << "Global Progress: " << progress << " per file progress " << pe.GetProgress() << std::endl; + //set progress value in the QtProgress bar + int i = (int)(progress * 100 + 0.5); // round to next int + qtprogress->setValue(i); + win->show(); + } + virtual void ShowDataSet(Subject *caller, const Event &evt) + { + (void)caller; + (void)evt; + } +}; +} // end namespace gdcm + +int main(int argc, char *argv[]) +{ + if( argc < 4 ) + { + std::cerr << argv[0] << " remote_server port filename" << std::endl; + return 1; + } + QApplication a(argc, argv); + + std::ostringstream error_log; + gdcm::Trace::SetErrorStream( error_log ); + + const char *remote = argv[1]; + int portno = atoi(argv[2]); + const char *filename = argv[3]; + + QVBoxLayout* layout = new QVBoxLayout; + QWidget* win = new QWidget; + + QProgressDialog* progress = new QProgressDialog("Sending data...", "Cancel", 0, 100); + progress->setWindowModality(Qt::WindowModal); + + layout->addWidget(progress,Qt::AlignCenter); + win->setLayout(layout); + + gdcm::SmartPointer scup = new gdcm::ServiceClassUser; + gdcm::ServiceClassUser &scu = *scup; + //gdcm::SimpleSubjectWatcher w( &scu, "TestServiceClassUser" ); + // let's use a more complicated progress reported in this example + gdcm::MyQtWatcher w( &scu, "QtWatcher", win, progress ); + + scu.SetHostname( remote ); + scu.SetPort( (uint16_t)portno ); + scu.SetTimeout( 1000 ); + scu.SetCalledAETitle( "GDCM_STORE" ); + + if( !scu.InitializeConnection() ) + { + std::cerr << "Could not InitializeConnection" << std::endl; + return 1; + } + + gdcm::Directory::FilenamesType filenames; + filenames.push_back( filename ); + + // setup the PC(s) based on the filenames: + gdcm::PresentationContextGenerator generator; + if( !generator.GenerateFromFilenames(filenames) ) + { + std::cerr << "Could not GenerateFromFilenames" << std::endl; + return 1; + } + + // Setup PresentationContext(s) + scu.SetPresentationContexts( generator.GetPresentationContexts() ); + + // Start ASSOCIATION + if( !scu.StartAssociation() ) + { + std::cerr << "Could not Start" << std::endl; + return 1; + } + + // Send C-STORE + if( !scu.SendStore( filename ) ) + { + std::cerr << "Could not Store" << std::endl; + std::cerr << "Error log is:" << std::endl; + std::cerr << error_log.str() << std::endl; + return 1; + } + + // Stop ASSOCIATION + if( !scu.StopAssociation() ) + { + std::cerr << "Could not Stop" << std::endl; + return 1; + } + + win->show(); + + return a.exec(); +} diff --git a/gdcm/Examples/Cxx/ChangeSequenceUltrasound.cxx b/gdcm/Examples/Cxx/ChangeSequenceUltrasound.cxx new file mode 100644 index 0000000..2536759 --- /dev/null +++ b/gdcm/Examples/Cxx/ChangeSequenceUltrasound.cxx @@ -0,0 +1,84 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmReader.h" +#include "gdcmWriter.h" +#include "gdcmSmartPointer.h" +#include "gdcmDataSetHelper.h" + +/* + ./ChangeSequenceUltrasound gdcmData/D_CLUNIE_CT1_J2KI.dcm myoutput.dcm + + This is the exact C++ translation of the original python example: ManipulateSequence.py + */ + +int main(int argc, char* argv[] ) +{ + if( argc < 0 ) + { + return 1; + } + const char *filename = argv[1]; + const char *outfilename = argv[2]; + + gdcm::Reader reader; + reader.SetFileName( filename ); + if (! reader.Read() ) + { + return 1; + } + + gdcm::File &file = reader.GetFile(); + gdcm::DataSet &ds = file.GetDataSet(); + gdcm::Tag tsis(0x0008,0x2112); // SourceImageSequence + if ( ds.FindDataElement( tsis ) ) + { + const gdcm::DataElement &sis = ds.GetDataElement( tsis ); + gdcm::SmartPointer sqsis = sis.GetValueAsSQ(); + if ( sqsis && sqsis->GetNumberOfItems() ) + { + gdcm::Item &item1 = sqsis->GetItem(1); + gdcm::DataSet &nestedds = item1.GetNestedDataSet(); + gdcm::Tag tprcs(0x0040,0xa170); // PurposeOfReferenceCodeSequence + if( nestedds.FindDataElement( tprcs ) ) + { + const gdcm::DataElement &prcs = nestedds.GetDataElement( tprcs ); + gdcm::SmartPointer sqprcs = prcs.GetValueAsSQ(); + if ( sqprcs && sqprcs->GetNumberOfItems() ) + { + gdcm::Item &item2 = sqprcs->GetItem(1); + gdcm::DataSet &nestedds2 = item2.GetNestedDataSet(); + // (0008,0104) LO [Uncompressed predecessor] # 24, 1 CodeMeaning + gdcm::Tag tcm(0x0008,0x0104); + if( nestedds2.FindDataElement( tcm ) ) + { + gdcm::DataElement cm = nestedds2.GetDataElement( tcm ); + std::string mystr = "GDCM was here"; + cm.SetByteValue( mystr.c_str(), (uint32_t)mystr.size() ); + nestedds2.Replace( cm ); + } + } + } + } + } + + gdcm::Writer writer; + writer.SetFile( file ); + writer.SetFileName( outfilename ); + if ( !writer.Write() ) + { + return 1; + } + + return 0; +} diff --git a/gdcm/Examples/Cxx/CheckBigEndianBug.cxx b/gdcm/Examples/Cxx/CheckBigEndianBug.cxx new file mode 100644 index 0000000..16ba445 --- /dev/null +++ b/gdcm/Examples/Cxx/CheckBigEndianBug.cxx @@ -0,0 +1,114 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + * WARNING: This is a dev tool, do not use ! + * + * Usage: after a gdcmconv, you would like to know if the conversion process is acceptable + * sometime a vbindiff is acceptable, sometime it is not. In the case of the famous Philips + * Little/Big Endian Explicit Transfer Syntax it is not easy to compare two files. However + * this only impact byte ordering, thus we can compute byte-indenpendant information to still + * compare the files. + */ + +#include "gdcmImageReader.h" +#include "gdcmImage.h" +#include "gdcmWriter.h" +#include "gdcmAttribute.h" +#include "gdcmSystem.h" + +#include +#include + +int main(int argc, char *argv[]) +{ + if( argc < 3 ) + { + std::cerr << argv[0] << " input1.dcm input2.dcm" << std::endl; + return 1; + } + const char *filename1 = argv[1]; + const char *filename2 = argv[2]; + + gdcm::ImageReader reader1; + reader1.SetFileName( filename1 ); + if( !reader1.Read() ) + { + std::cerr << "Could not read: " << filename1 << std::endl; + return 1; + } + + gdcm::ImageReader reader2; + reader2.SetFileName( filename2 ); + if( !reader2.Read() ) + { + std::cerr << "Could not read: " << filename2 << std::endl; + return 1; + } + + // TODO: need a DataSet== operator implementation + + std::cout << "Both files can be read and looks like DICOM" << std::endl; + + size_t s1 = gdcm::System::FileSize(filename1); + size_t s2 = gdcm::System::FileSize(filename2); + + if( s1 != s2 ) + { + std::cout << "Size mismatch: " << s1 << " != " << s2 << std::endl; + return 1; + } + else + { + std::cout << "Size match: " << s1 << " = " << s2 << std::endl; + } + + std::ifstream is1( filename1, std::ios::binary ); + char *buffer1 = new char[s1]; + is1.read(buffer1, s1); + + std::ifstream is2( filename2, std::ios::binary ); + char *buffer2 = new char[s2]; + is2.read(buffer2, s2); + + assert( s1 == s2 ); + if( memcmp(buffer1, buffer2, s1 ) == 0 ) + { + std::cout << "memcmp succeed ! File are bit identical" << std::endl; + } + else + { + std::cout << "memcmp failed!" << std::endl; + } + + // Hum...memcmp failed, for big endian/ little endian inversion the histogram of bytes + // should still be the same. So let's compute it + // buffer2[0] = 1; // let's make the test fail + std::multiset set1( buffer1, buffer1 + s1 ); + std::multiset set2( buffer2, buffer2 + s2 ); + + + if( set1 == set2 ) + { + std::cout << "set1 == set2. Byte histogram seems valid" << std::endl; + } + else + { + std::cout << "set1 != set2" << std::endl; + } + delete[] buffer1; + delete[] buffer2; + + + return 0; +} diff --git a/gdcm/Examples/Cxx/ClinicalTrialAnnotate.cxx b/gdcm/Examples/Cxx/ClinicalTrialAnnotate.cxx new file mode 100644 index 0000000..e9052af --- /dev/null +++ b/gdcm/Examples/Cxx/ClinicalTrialAnnotate.cxx @@ -0,0 +1,81 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + * Dummy implementation of C.7.1.3 Clinical Trial Subject Module + * + * Usage: + * ClinicalTrialAnnotate gdcmData/012345.002.050.dcm out.dcm + */ + +#include "gdcmReader.h" +#include "gdcmWriter.h" +#include "gdcmAnonymizer.h" + +int main(int argc, char *argv[]) +{ + if( argc < 3 ) + { + std::cerr << argv[0] << " input.dcm output.dcm" << std::endl; + return 1; + } + const char *filename = argv[1]; + const char *outfilename = argv[2]; + + gdcm::Reader reader; + reader.SetFileName( filename ); + if( !reader.Read() ) + { + std::cerr << "Could not read: " << filename << std::endl; + return 1; + } + + // The output of gdcm::Reader is a gdcm::File + //gdcm::File &file = reader.GetFile(); + + // the dataset is the the set of element we are interested in: + //gdcm::DataSet &ds = file.GetDataSet(); + + gdcm::Anonymizer ano; + ano.SetFile( reader.GetFile() ); + ano.RemoveGroupLength(); + ano.RemovePrivateTags(); + + // PS 3.3 - 2008 + // C.7.1.3 Clinical Trial Subject Module + // + ano.Replace( gdcm::Tag(0x12,0x10), "BigCompany name" ); + // + ano.Replace( gdcm::Tag(0x12,0x20), "My Clinical Trial Protocol ID" ); + // + ano.Replace( gdcm::Tag(0x12,0x21), "My Clinical Trial Protocol Name" ); + // + ano.Replace( gdcm::Tag(0x12,0x30), "My Clinical Trial Site ID" ); + // + ano.Replace( gdcm::Tag(0x12,0x31), "My Clinical Trial Site Name" ); + // + ano.Replace( gdcm::Tag(0x12,0x40), "My Clinical Trial Subject ID" ); + // + ano.Replace( gdcm::Tag(0x12,0x42), "My Clinical Trial Subject Reading ID" ); + + + gdcm::Writer writer; + writer.SetFile( reader.GetFile() ); + writer.SetFileName( outfilename ); + if( !writer.Write() ) + { + return 1; + } + + return 0; +} diff --git a/gdcm/Examples/Cxx/CompressImage.cxx b/gdcm/Examples/Cxx/CompressImage.cxx new file mode 100644 index 0000000..7b8c604 --- /dev/null +++ b/gdcm/Examples/Cxx/CompressImage.cxx @@ -0,0 +1,81 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + * + */ + +#include "gdcmImageReader.h" +#include "gdcmImage.h" +#include "gdcmWriter.h" +#include "gdcmAttribute.h" +#include "gdcmImageWriter.h" +#include "gdcmImageChangeTransferSyntax.h" + +#include +#include + +int main(int argc, char *argv[]) +{ + if( argc < 3 ) + { + std::cerr << argv[0] << " input.dcm output.dcm" << std::endl; + return 1; + } + const char *filename = argv[1]; + const char *outfilename = argv[2]; + + gdcm::ImageReader reader; + reader.SetFileName( filename ); + if( !reader.Read() ) + { + std::cerr << "Could not read: " << filename << std::endl; + return 1; + } + + // The output of gdcm::Reader is a gdcm::File + //gdcm::File &file = reader.GetFile(); + + // the dataset is the the set of element we are interested in: + //gdcm::DataSet &ds = file.GetDataSet(); + + const gdcm::Image &image = reader.GetImage(); + image.Print( std::cout ); + + gdcm::ImageChangeTransferSyntax change; + change.SetTransferSyntax( gdcm::TransferSyntax::JPEG2000Lossless ); + change.SetTransferSyntax( gdcm::TransferSyntax::JPEGLosslessProcess14_1 ); + //change.SetTransferSyntax( gdcm::TransferSyntax::JPEGBaselineProcess1 ); + //change.SetTransferSyntax( image.GetTransferSyntax() ); + change.SetInput( image ); + bool b = change.Change(); + if( !b ) + { + std::cerr << "Could not change the Transfer Syntax" << std::endl; + return 1; + } + + //std::ofstream out( outfilename, std::ios::binary ); + //image.GetBuffer2(out); + //out.close(); + gdcm::ImageWriter writer; + writer.SetImage( change.GetOutput() ); + writer.SetFile( reader.GetFile() ); + writer.SetFileName( outfilename ); + if( !writer.Write() ) + { + return 1; + } + + return 0; +} diff --git a/gdcm/Examples/Cxx/ConvertToQImage.cxx b/gdcm/Examples/Cxx/ConvertToQImage.cxx new file mode 100644 index 0000000..2219c1c --- /dev/null +++ b/gdcm/Examples/Cxx/ConvertToQImage.cxx @@ -0,0 +1,144 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + * This example shows how to setup the pipeline from a gdcm::ImageReader into a + * Qt QImage data structure. + * It only handles 2D image. + * + * Ref: + * http://doc.trolltech.com/4.5/qimage.html + * + * Usage: + * ConvertToQImage gdcmData/012345.002.050.dcm output.png + + * Thanks: + * Sylvain ADAM (sylvain51 hotmail com) for contributing this example + */ + +#include "gdcmImageReader.h" +#include +#include + +bool ConvertToFormat_RGB888(gdcm::Image const & gimage, char *buffer, QImage* &imageQt) +{ + const unsigned int* dimension = gimage.GetDimensions(); + + unsigned int dimX = dimension[0]; + unsigned int dimY = dimension[1]; + + gimage.GetBuffer(buffer); + + // Let's start with the easy case: + if( gimage.GetPhotometricInterpretation() == gdcm::PhotometricInterpretation::RGB ) + { + if( gimage.GetPixelFormat() != gdcm::PixelFormat::UINT8 ) + { + return false; + } + unsigned char *ubuffer = (unsigned char*)buffer; + // QImage::Format_RGB888 13 The image is stored using a 24-bit RGB format (8-8-8). + imageQt = new QImage((unsigned char *)ubuffer, dimX, dimY, 3*dimX, QImage::Format_RGB888); + } + else if( gimage.GetPhotometricInterpretation() == gdcm::PhotometricInterpretation::MONOCHROME2 ) + { + if( gimage.GetPixelFormat() == gdcm::PixelFormat::UINT8 ) + { + // We need to copy each individual 8bits into R / G and B: + unsigned char *ubuffer = new unsigned char[dimX*dimY*3]; + unsigned char *pubuffer = ubuffer; + for(unsigned int i = 0; i < dimX*dimY; i++) + { + *pubuffer++ = *buffer; + *pubuffer++ = *buffer; + *pubuffer++ = *buffer++; + } + + imageQt = new QImage(ubuffer, dimX, dimY, QImage::Format_RGB888); + } + else if( gimage.GetPixelFormat() == gdcm::PixelFormat::INT16 ) + { + // We need to copy each individual 16bits into R / G and B (truncate value) + short *buffer16 = (short*)buffer; + unsigned char *ubuffer = new unsigned char[dimX*dimY*3]; + unsigned char *pubuffer = ubuffer; + for(unsigned int i = 0; i < dimX*dimY; i++) + { + // Scalar Range of gdcmData/012345.002.050.dcm is [0,192], we could simply do: + // *pubuffer++ = *buffer16; + // *pubuffer++ = *buffer16; + // *pubuffer++ = *buffer16; + // instead do it right: + *pubuffer++ = (unsigned char)std::min(255, (32768 + *buffer16) / 255); + *pubuffer++ = (unsigned char)std::min(255, (32768 + *buffer16) / 255); + *pubuffer++ = (unsigned char)std::min(255, (32768 + *buffer16) / 255); + buffer16++; + } + + imageQt = new QImage(ubuffer, dimX, dimY, QImage::Format_RGB888); + } + else + { + std::cerr << "Pixel Format is: " << gimage.GetPixelFormat() << std::endl; + return false; + } + } + else + { + std::cerr << "Unhandled PhotometricInterpretation: " << gimage.GetPhotometricInterpretation() << std::endl; + return false; + } + + return true; +} + +int main(int argc, char *argv[]) +{ + if( argc < 2 ) + { + return 1; + } + const char *filename = argv[1]; + const char *outfilename = argv[2]; + + gdcm::ImageReader ir; + ir.SetFileName( filename ); + if(!ir.Read()) + { + //Read failed + return 1; + } + + std::cout<<"Getting image from ImageReader..."< vbuffer; + vbuffer.resize( gimage.GetBufferLength() ); + char *buffer = &vbuffer[0]; + + QImage *imageQt = NULL; + if( !ConvertToFormat_RGB888( gimage, buffer, imageQt ) ) + { + return 1; + } + + QImageWriter writer; + writer.setFormat("png"); + writer.setFileName( outfilename ); + if( !writer.write( *imageQt ) ) + { + return 1; + } + + return 0; +} diff --git a/gdcm/Examples/Cxx/CreateARGBImage.cxx b/gdcm/Examples/Cxx/CreateARGBImage.cxx new file mode 100644 index 0000000..8d47a9b --- /dev/null +++ b/gdcm/Examples/Cxx/CreateARGBImage.cxx @@ -0,0 +1,72 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + * http://www.w3.org/Graphics/PNG/inline-alpha.html + * alphatest.png: PNG image data, 380 x 287, 8-bit/color RGBA, non-interlaced + * + * $ convert alphatest.png alphatest.rgba + */ + +#include "gdcmImageReader.h" +#include "gdcmSequenceOfFragments.h" +#include "gdcmSystem.h" +#include "gdcmImageWriter.h" + +#include +#include + +int main(int argc, char *argv[]) +{ + if( argc < 3 ) + { + std::cerr << argv[0] << " input.rgba output.dcm" << std::endl; + return 1; + } + const char *filename = argv[1]; + const char *outfilename = argv[2]; + + size_t len = gdcm::System::FileSize(filename); + std::ifstream is(filename, std::ios::binary); + + char * buf = new char[len]; + is.read(buf, len); + + gdcm::ImageWriter writer; + gdcm::Image &image = writer.GetImage(); + image.SetNumberOfDimensions( 2 ); + unsigned int dims[3] = {}; + dims[0] = 380; + dims[1] = 287; + image.SetDimensions( dims ); + gdcm::PixelFormat pf = gdcm::PixelFormat::UINT8; + pf.SetSamplesPerPixel( 4 ); + image.SetPixelFormat( pf ); + gdcm::PhotometricInterpretation pi = gdcm::PhotometricInterpretation::ARGB; + image.SetPhotometricInterpretation( pi ); + image.SetTransferSyntax( gdcm::TransferSyntax::ExplicitVRLittleEndian ); + + gdcm::DataElement pixeldata( gdcm::Tag(0x7fe0,0x0010) ); + pixeldata.SetByteValue( buf, (uint32_t)len ); + image.SetDataElement( pixeldata ); + + writer.SetFileName( outfilename ); + if( !writer.Write() ) + { + return 1; + } + delete[] buf; + + + return 0; +} diff --git a/gdcm/Examples/Cxx/CreateCMYKImage.cxx b/gdcm/Examples/Cxx/CreateCMYKImage.cxx new file mode 100644 index 0000000..60a4595 --- /dev/null +++ b/gdcm/Examples/Cxx/CreateCMYKImage.cxx @@ -0,0 +1,71 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + * http://www.w3.org/Graphics/PNG/inline-alpha.html + * alphatest.png: PNG image data, 380 x 287, 8-bit/color RGBA, non-interlaced + * + * $ convert alphatest.png alphatest.cmyk + */ + +#include "gdcmImageReader.h" +#include "gdcmSequenceOfFragments.h" +#include "gdcmSystem.h" +#include "gdcmImageWriter.h" + +#include +#include + +int main(int argc, char *argv[]) +{ + if( argc < 3 ) + { + std::cerr << argv[0] << " input.cmyk output.dcm" << std::endl; + return 1; + } + const char *filename = argv[1]; + const char *outfilename = argv[2]; + + size_t len = gdcm::System::FileSize(filename); + std::ifstream is(filename, std::ios::binary); + + char * buf = new char[len]; + is.read(buf, len); + + gdcm::ImageWriter writer; + gdcm::Image &image = writer.GetImage(); + image.SetNumberOfDimensions( 2 ); + unsigned int dims[3] = {}; + dims[0] = 380; + dims[1] = 287; + image.SetDimensions( dims ); + gdcm::PixelFormat pf = gdcm::PixelFormat::UINT8; + pf.SetSamplesPerPixel( 4 ); + image.SetPixelFormat( pf ); + gdcm::PhotometricInterpretation pi = gdcm::PhotometricInterpretation::CMYK; + image.SetPhotometricInterpretation( pi ); + image.SetTransferSyntax( gdcm::TransferSyntax::ExplicitVRLittleEndian ); + + gdcm::DataElement pixeldata( gdcm::Tag(0x7fe0,0x0010) ); + pixeldata.SetByteValue( buf, (uint32_t)len ); + image.SetDataElement( pixeldata ); + + writer.SetFileName( outfilename ); + if( !writer.Write() ) + { + return 1; + } + delete[] buf; + + return 0; +} diff --git a/gdcm/Examples/Cxx/CreateJPIPDataSet.cxx b/gdcm/Examples/Cxx/CreateJPIPDataSet.cxx new file mode 100644 index 0000000..6c9d2ff --- /dev/null +++ b/gdcm/Examples/Cxx/CreateJPIPDataSet.cxx @@ -0,0 +1,82 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + * This example was created during the GSOC 2011 project for + * JPIP + */ +#include "gdcmAnonymizer.h" +#include "gdcmWriter.h" +#include "gdcmUIDGenerator.h" +#include "gdcmFile.h" +#include "gdcmTag.h" +#include "gdcmSystem.h" +#include "gdcmAttribute.h" + +int main(int argc, char *argv[]) +{ + if( argc < 2 ) + { + std::cerr << argv[0] << " output.dcm" << std::endl; + return 1; + } + const char *outfilename = argv[1]; + + gdcm::Writer w; + gdcm::File &file = w.GetFile(); + gdcm::DataSet &ds = file.GetDataSet(); + //w.SetCheckFileMetaInformation( true ); + w.SetFileName( outfilename ); + + file.GetHeader().SetDataSetTransferSyntax( gdcm::TransferSyntax::JPIPReferenced ); + + gdcm::Anonymizer anon; + anon.SetFile( file ); + + gdcm::MediaStorage ms = gdcm::MediaStorage::SecondaryCaptureImageStorage; + + gdcm::UIDGenerator gen; + anon.Replace( gdcm::Tag(0x0008,0x16), ms.GetString() ); + std::cout << ms.GetString() << std::endl; + anon.Replace( gdcm::Tag(0x0008,0x18), gen.Generate() ); + // + anon.Replace( gdcm::Tag(0x0010,0x10), "JPIP^EXAMPLE" ); + anon.Replace( gdcm::Tag(0x0010,0x20), "012345" ); + anon.Empty( gdcm::Tag(0x0010,0x30) ); + anon.Empty( gdcm::Tag(0x0010,0x40) ); + anon.Empty( gdcm::Tag(0x0008,0x20) ); + anon.Empty( gdcm::Tag(0x0008,0x30) ); + anon.Empty( gdcm::Tag(0x0008,0x90) ); + anon.Empty( gdcm::Tag(0x0020,0x10) ); + anon.Empty( gdcm::Tag(0x0020,0x11) ); + anon.Empty( gdcm::Tag(0x0008,0x50) ); + anon.Empty( gdcm::Tag(0x0020,0x0013) ); + anon.Replace( gdcm::Tag(0x0020,0xd), gen.Generate() ); + anon.Replace( gdcm::Tag(0x0020,0xe), gen.Generate() ); + anon.Replace( gdcm::Tag(0x0008,0x64), "WSD " ); + anon.Replace( gdcm::Tag(0x0008,0x60), "OT" ); + + gdcm::Attribute<0x0028,0x7FE0> at; + at.SetValue( "http://dicom.example.com/jpipserver.cgi?target=img.jp2" ); + ds.Insert( at.GetAsDataElement() ); + + // Need to retrieve the PixelFormat information from the given file + + if (!w.Write() ) + { + std::cerr << "Could not write: " << outfilename << std::endl; + return 1; + } + + return 0; +} diff --git a/gdcm/Examples/Cxx/DiffFile.cxx b/gdcm/Examples/Cxx/DiffFile.cxx new file mode 100644 index 0000000..2eee34e --- /dev/null +++ b/gdcm/Examples/Cxx/DiffFile.cxx @@ -0,0 +1,75 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmReader.h" + +int main(int argc, char *argv[]) +{ + if( argc < 3 ) + { + std::cerr << argv[0] << " input1.dcm input2.dcm" << std::endl; + return 1; + } + const char *filename1 = argv[1]; + const char *filename2 = argv[2]; + + gdcm::Reader reader1; + reader1.SetFileName( filename1 ); + if( !reader1.Read() ) + { + return 1; + } + + gdcm::Reader reader2; + reader2.SetFileName( filename2 ); + if( !reader2.Read() ) + { + return 1; + } + + const gdcm::File &file1 = reader1.GetFile(); + const gdcm::File &file2 = reader2.GetFile(); + + const gdcm::DataSet &ds1 = file1.GetDataSet(); + const gdcm::DataSet &ds2 = file2.GetDataSet(); + + gdcm::DataSet::ConstIterator it1 = ds1.Begin(); + gdcm::DataSet::ConstIterator it2 = ds2.Begin(); + + const gdcm::DataElement &de1 = *it1; + const gdcm::DataElement &de2 = *it2; + if( de1 == de2 ) + { + } + while( it1 != ds1.End() && it2 != ds2.End() && *it1 == *it2 ) + { + ++it1; + ++it2; + } + + if( it1 != ds1.End() || it2 != ds2.End() ) + { + std::cerr << "Problem with:" << std::endl; + if( it1 != ds1.End() ) + { + std::cerr << "ds1: " << *it1 << std::endl; + } + if( it2 != ds2.End() ) + { + std::cerr << "ds2: " << *it2 << std::endl; + } + return 1; + } + + return 0; +} diff --git a/gdcm/Examples/Cxx/DiscriminateVolume.cxx b/gdcm/Examples/Cxx/DiscriminateVolume.cxx new file mode 100644 index 0000000..d732181 --- /dev/null +++ b/gdcm/Examples/Cxx/DiscriminateVolume.cxx @@ -0,0 +1,282 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmScanner.h" +#include "gdcmTesting.h" +#include "gdcmIPPSorter.h" +#include "gdcmDirectionCosines.h" +#include + +/* + * The following example is a basic sorted which should work in generic cases. + * It sort files based on: + * Study Instance UID + * Series Instance UID + * Frame of Reference UID + * Image Orientation (Patient) + * Image Position (Patient) (Sorting based on IPP + IOP) + */ + +namespace gdcm { + const Tag t1(0x0020,0x000d); // Study Instance UID + const Tag t2(0x0020,0x000e); // Series Instance UID + const Tag t3(0x0020,0x0052); // Frame of Reference UID + const Tag t4(0x0020,0x0037); // Image Orientation (Patient) + +class DiscriminateVolume +{ +private: + std::vector< Directory::FilenamesType > SortedFiles; + std::vector< Directory::FilenamesType > UnsortedFiles; + + Directory::FilenamesType GetAllFilenamesFromTagToValue( + Scanner const & s, Directory::FilenamesType const &filesubset, Tag const &t, const char *valueref) +{ + Directory::FilenamesType theReturn; + if( valueref ) + { + size_t len = strlen( valueref ); + Directory::FilenamesType::const_iterator file = filesubset.begin(); + for(; file != filesubset.end(); ++file) + { + const char *filename = file->c_str(); + const char * value = s.GetValue(filename, t); + if( value && strncmp(value, valueref, len ) == 0 ) + { + theReturn.push_back( filename ); + } + } + } + return theReturn; +} + +void ProcessAIOP(Scanner const & , Directory::FilenamesType const & subset, const char *iopval) +{ + std::cout << "IOP: " << iopval << std::endl; + IPPSorter ipp; + ipp.SetComputeZSpacing( true ); + ipp.SetZSpacingTolerance( 1e-3 ); // ?? + bool b = ipp.Sort( subset ); + if( !b ) + { + // If you reach here this means you need one more parameter to discriminiat this + // series. Eg. T1 / T2 intertwinted. Multiple Echo (0018,0081) + std::cerr << "Failed to sort: " << subset.begin()->c_str() << std::endl; + for( + Directory::FilenamesType::const_iterator file = subset.begin(); + file != subset.end(); ++file) + { + std::cerr << *file << std::endl; + } + UnsortedFiles.push_back( subset ); + return ; + } + ipp.Print( std::cout ); + SortedFiles.push_back( ipp.GetFilenames() ); +} + +void ProcessAFrameOfRef(Scanner const & s, Directory::FilenamesType const & subset, const char * frameuid) +{ + // In this subset of files (belonging to same series), let's find those + // belonging to the same Frame ref UID: + Directory::FilenamesType files = GetAllFilenamesFromTagToValue( + s, subset, t3, frameuid); + + std::set< std::string > iopset; + + for( + Directory::FilenamesType::const_iterator file = files.begin(); + file != files.end(); ++file) + { + //std::cout << *file << std::endl; + const char * value = s.GetValue(file->c_str(), gdcm::t4 ); + assert( value ); + iopset.insert( value ); + } + size_t n = iopset.size(); + if ( n == 0 ) + { + assert( files.empty() ); + return; + } + + std::cout << "Frame of Ref: " << frameuid << std::endl; + if ( n == 1 ) + { + ProcessAIOP(s, files, iopset.begin()->c_str() ); + } + else + { + const char *f = files.begin()->c_str(); + std::cerr << "More than one IOP: " << f << std::endl; + // Make sure that there is actually 'n' different IOP + gdcm::DirectionCosines ref; + gdcm::DirectionCosines dc; + for( + std::set< std::string >::const_iterator it = iopset.begin(); + it != iopset.end(); ++it ) + { + ref.SetFromString( it->c_str() ); + for( + Directory::FilenamesType::const_iterator file = files.begin(); + file != files.end(); ++file) + { + std::string value = s.GetValue(file->c_str(), gdcm::t4 ); + if( value != it->c_str() ) + { + dc.SetFromString( value.c_str() ); + const double crossdot = ref.CrossDot(dc); + const double eps = std::fabs( 1. - crossdot ); + if( eps < 1e-6 ) + { + std::cerr << "Problem with IOP discrimination: " << file->c_str() + << " " << it->c_str() << std::endl; + return; + } + } + } + } + // If we reach here this means there is actually 'n' different IOP + for( + std::set< std::string >::const_iterator it = iopset.begin(); + it != iopset.end(); ++it ) + { + const char *iopvalue = it->c_str(); + Directory::FilenamesType iopfiles = GetAllFilenamesFromTagToValue( + s, files, t4, iopvalue ); + ProcessAIOP(s, iopfiles, iopvalue ); + } + } +} + +void ProcessASeries(Scanner const & s, const char * seriesuid) +{ + std::cout << "Series: " << seriesuid << std::endl; + // let's find all files belonging to this series: + Directory::FilenamesType seriesfiles = GetAllFilenamesFromTagToValue( + s, s.GetFilenames(), t2, seriesuid); + + gdcm::Scanner::ValuesType vt3 = s.GetValues(t3); + for( + gdcm::Scanner::ValuesType::const_iterator it = vt3.begin() + ; it != vt3.end(); ++it ) + { + ProcessAFrameOfRef(s, seriesfiles, it->c_str()); + } +} + +void ProcessAStudy(Scanner const & s, const char * studyuid) +{ + std::cout << "Study: " << studyuid << std::endl; + gdcm::Scanner::ValuesType vt2 = s.GetValues(t2); + for( + gdcm::Scanner::ValuesType::const_iterator it = vt2.begin() + ; it != vt2.end(); ++it ) + { + ProcessASeries(s, it->c_str()); + } +} +public: + +void Print( std::ostream & os ) +{ + os << "Sorted Files: " << std::endl; + for( + std::vector< Directory::FilenamesType >::const_iterator it = SortedFiles.begin(); + it != SortedFiles.end(); ++it ) + { + os << "Group: " << std::endl; + for( + Directory::FilenamesType::const_iterator file = it->begin(); + file != it->end(); ++file) + { + os << *file << std::endl; + } + } + os << "Unsorted Files: " << std::endl; + for( + std::vector< Directory::FilenamesType >::const_iterator it = UnsortedFiles.begin(); + it != UnsortedFiles.end(); ++it ) + { + os << "Group: " << std::endl; + for( + Directory::FilenamesType::const_iterator file = it->begin(); + file != it->end(); ++file) + { + os << *file << std::endl; + } + } + +} + + std::vector< Directory::FilenamesType > const & GetSortedFiles() const { return SortedFiles; } + std::vector< Directory::FilenamesType > const & GetUnsortedFiles() const { return UnsortedFiles; } + +void ProcessIntoVolume( Scanner const & s ) +{ + gdcm::Scanner::ValuesType vt1 = s.GetValues( gdcm::t1 ); + for( + gdcm::Scanner::ValuesType::const_iterator it = vt1.begin() + ; it != vt1.end(); ++it ) + { + ProcessAStudy( s, it->c_str() ); + } + +} + +}; + +} // namespace gdcm + +int main(int argc, char *argv[]) +{ + std::string dir1; + if( argc < 2 ) + { + const char *extradataroot = NULL; +#ifdef GDCM_BUILD_TESTING + extradataroot = gdcm::Testing::GetDataExtraRoot(); +#endif + if( !extradataroot ) + { + return 1; + } + dir1 = extradataroot; + dir1 += "/gdcmSampleData/ForSeriesTesting/VariousIncidences/ST1"; + } + else + { + dir1 = argv[1]; + } + + gdcm::Directory d; + d.Load( dir1.c_str(), true ); // recursive ! + + gdcm::Scanner s; + s.AddTag( gdcm::t1 ); + s.AddTag( gdcm::t2 ); + s.AddTag( gdcm::t3 ); + s.AddTag( gdcm::t4 ); + bool b = s.Scan( d.GetFilenames() ); + if( !b ) + { + std::cerr << "Scanner failed" << std::endl; + return 1; + } + + gdcm::DiscriminateVolume dv; + dv.ProcessIntoVolume( s ); + dv.Print( std::cout ); + + return 0; +} diff --git a/gdcm/Examples/Cxx/DumpADAC.cxx b/gdcm/Examples/Cxx/DumpADAC.cxx new file mode 100644 index 0000000..20a206a --- /dev/null +++ b/gdcm/Examples/Cxx/DumpADAC.cxx @@ -0,0 +1,366 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + * the goal of this example is to mimic the behavior of disp_img_header + * see http://www.gmecorp-usa.com/IM/NM/GC/ADAC/SV/adactechtips/Released_01Q3.pdf + */ +#include "gdcmReader.h" +#include "gdcmPrivateTag.h" +#include "gdcmAttribute.h" +#include "gdcmImageWriter.h" + +#include +#include +#include + +#include +#include +#include + +struct dict +{ + uint16_t key; + const char *name; +}; + +dict Array[] = { + { 0x01, "Patient name" }, + { 0x02, "Patient ID" }, + { 0x03, "Patient sex" }, + { 0x04, "Patient age" }, + { 0x05, "Patient height" }, + { 0x06, "Patient weight" }, + { 0x07, "Exam date" }, + { 0x08, "Dose admin. time" }, + { 0x09, "Unique exam key" }, + { 0x0a, "Exam procedure" }, + { 0x0b, "Referring physician" }, + { 0x0c, "Attending physician" }, + { 0x0d, "Imaging modality" }, + { 0x0e, "Hospital ID" }, + { 0x0f, "Histogram crv file" }, + { 0x10, "Acq. start time" }, + { 0x11, "Object data type" }, + { 0x12, "Image viewid" }, + { 0x13, "Imaging device name" }, + { 0x14, "Device serial number" }, + { 0x15, "Collimator" }, + { 0x16, "Software version" }, + { 0x17, "Radiopharmaceutical #1" }, + { 0x18, "Energy window #1 center" }, + { 0x19, "Radiopharmaceutical #2" }, + { 0x1a, "Energy window #1 width" }, + { 0x1b, "Isotope imaging mode" }, + { 0x1c, "Energy window #2 center" }, + { 0x1d, "Energy window #2 width" }, + { 0x1e, "Energy window #3 center" }, + { 0x1f, "Energy window #3 width" }, + { 0x20, "Energy window #4 center" }, + { 0x21, "Energy window #4 width" }, + { 0x22, "??Energy window #5 center" }, + { 0x23, "??Energy window #5 width" }, + { 0x24, "Patient orientation" }, + { 0x25, "Spatial resolution" }, + { 0x26, "Slice thickness" }, + { 0x27, "Image X dimension" }, + { 0x28, "Image Y dimension" }, + { 0x29, "Image Z dimension" }, + { 0x2a, "Image pixel width" }, + { 0x2b, "Uniformity corr. file" }, + { 0x2c, "Acquisition zoom factor" }, + { 0x2d, "Total counts in set" }, + { 0x2e, "Time / frame" }, + { 0x2f, "Total acq. time" }, + { 0x30, "Maximum pixel value" }, + { 0x31, "Minimum pixel value" }, + { 0x32, "R-R interval time" }, + { 0x33, "Percent of cycle imaged" }, + { 0x34, "# of cycles accepted" }, + { 0x35, "# of cycles rejected" }, + { 0x36, "Approximate ED frame" }, + { 0x37, "Approximate ES frame" }, + { 0x38, "Approximate EF" }, + { 0x39, "Starting angle" }, + { 0x3a, "Degrees of rotation" }, + { 0x3b, "Direction of rotation" }, + { 0x3c, "Cont. or step/shoot" }, + { 0x3d, "Lim recon start frame" }, + { 0x3e, "Upper window grey shade" }, + { 0x3f, "Lower lvl grey shade" }, + { 0x40, "Associated color map" }, + { 0x41, "Custom color map file" }, + { 0x42, "Manipulated image" }, + { 0x43, "Axis of rotation corr." }, + { 0x44, "Reorientation azimuth" }, + { 0x45, "Reorientation elevation" }, + { 0x46, "Filter type" }, + { 0x47, "Filter order" }, + { 0x48, "Filter cutoff frequency" }, + { 0x49, "Reconstruction type" }, + { 0x4a, "Attenuation coefficient" }, + { 0x4b, "Associated parent file" }, + { 0x4c, "Unique patient key" }, + { 0x52, "Normalization crv file" }, + { 0x53, "Unique object key" }, + { 0x54, "This phase of VFR is" }, + { 0x55, "True color value" }, + { 0x56, "# of sets of x,y,z grps" }, + { 0x57, "Scale factor of set" }, + { 0x6d, "Date of birth" }, + { 0x6e, "Directional orientation" }, + { 0x6f, "Number of VFR studies" }, + { 0x70, "R-R low tolerance" }, + { 0x71, "R-R high tolerance" }, + { 0x72, "Prog specific results:" }, + + { 0x99, NULL } +}; + +void printname( int , int , uint16_t v ) +{ + if( v == 0x1 ) + { + std::cout << "DATABASE PARAMETERS" << std::endl; + std::cout << "___________________" << std::endl; + } + else if( v == 0x27 ) + { + std::cout << "IMAGE PARAMETERS" << std::endl; + std::cout << "________________" << std::endl; + } + else if( v == 0x13 ) + { + std::cout << "EXTRA PARAMETERS" << std::endl; + std::cout << "________________" << std::endl; + } + else if( v == 0x2e ) + { + std::cout << "*** NOT CURRENTLY USED :" << std::endl; + } + static const unsigned int n = sizeof( Array ) / sizeof( *Array ) - 1; + for( unsigned int i = 0; i < n; ++i ) + { + if( v == Array[i].key ) + { + std::cout << /*"" << std::dec << len << "," << mult << " " << */ Array[i].name; + std::cout << " : "; + return; + } + } + std::cout << /*"\t# " << std::dec << len << "," << mult << */ std::hex << v << "\t: "; +} + +uint16_t readint16(std::istream &is ) +{ + uint16_t val; + is.read( (char*)&val, sizeof( val )); + return (uint16_t)((val>>8) | (val<<8)); +} + +uint32_t readint32(std::istream &is ) +{ + uint32_t val; + is.read( (char*)&val, sizeof( val )); + val= ((val<<8)&0xFF00FF00) | ((val>>8)&0x00FF00FF); + return (val>>16) | (val<<16); +} + +float readfloat32(std::istream &is ) +{ + union { uint32_t val; float f;} dual; + dual.val = readint32(is); + return dual.f; +} + +struct el +{ + uint16_t v1; + uint16_t v2; + uint16_t v3; + void read( std::istream & is ) + { + v1 = readint16(is); + v2 = readint16(is); + v3 = readint16(is); + } + void print( std::ostream & os ) + { + os << std::hex << v1 << "\t" << v2 << "\t" << v3 << std::endl; + } +}; + +std::vector Vel; + +void readelement( std::istream & is ) +{ + el e; + e.read( is ); + Vel.push_back( e ); +} + +void printascii( uint16_t tag, const char *buffer, size_t len ) +{ + std::ostream & os = std::cout; + if( tag == 0x72 ) + { + os << "\n "; + for(size_t i = 0; i < len; ++i) + { + const char &c = buffer[i]; + if( c == 0x0 ) os << "!"; + else if( c == 0x0f ) os << " "; + else if( c == 0x17 ) os << ":"; + else if( c == 0x14 ) os << ":"; + else if( c == 0x10 ) os << ":"; + else if( c == 0x16 ) os << ":"; + else if( c == 0x08 ) os << ":"; + else if( c == 0x0b ) os << ":"; + else if( c == 0x0e ) os << ":"; + else if( c == 0x07 ) os << ":"; + else os << c; + } + os << ""; + } + else + { + (void)len; + os << "" << buffer << ""; + } +} + +bool DumpADAC( std::istream & is ) +{ + std::ostream &os = std::cout; + + char magic[6 + 1]; + magic[6] = 0; + is.read( magic, 6); +// std::cout << magic << " "; + assert( strcmp( magic, "adac01" ) == 0 ); + int c = is.get(); + assert( c == 0 ); (void)c; + c = is.get(); + assert( c == 'X' ); + + uint16_t v; + v = readint16(is); +// std::cout << v << std::endl; + assert( v == 512 ); (void)v; // ?? + + int nel = 87; + for (int i = 0; i <= nel; ++i ) + { + readelement( is ); + } + + char buffer[512]; + for( int i = 0; i <= nel; ++i ) + { + const el &e = Vel[i]; + int diff; + if( i == nel ) + { + diff = 2048 - e.v3; + if( diff > 512 ) diff = 512; + } + else + { + const el &enext = Vel[i+1]; + diff = enext.v3 - e.v3; + } + is.seekg( e.v3, std::ios::beg ); + //std::cout << "(" << std::hex << std::setw( 2 ) << std::setfill( '0' ) << e.v1 << ") " << std::hex << std::setw( 3 ) << std::setfill( '0' ) << e.v2 << " "; + printname( diff, 0, e.v1 ); + int mult = 1; + if( e.v2 == 0 ) + { + is.read( buffer, diff); + buffer[ diff ] = 0; + printascii( e.v1, buffer, diff); + } + else if( e.v2 == 0x100 ) + { + mult = diff / 2; + assert( diff == 2 * mult ); + for ( int ii = 0; ii < mult; ++ii ) + { + if ( ii ) os << "\\"; + uint16_t val = readint16(is); + os << "" << std::dec << val << ""; + } + } + else if( e.v2 == 0x200 ) + { + assert( diff == 4 ); + uint32_t val = readint32(is); + os << "" << std::dec << val << ""; + } + else if( e.v2 == 0x300 ) + { + assert( diff == 4 ); + float val = readfloat32(is); + os << "" << std::dec << val << ""; + } + else + { + assert( 0 ); + } + os << std::endl; + } + return true; +} + +int main(int argc, char *argv[]) +{ + if( argc < 2 ) return 1; + const char *filename = argv[1]; + gdcm::Reader reader; + reader.SetFileName( filename ); + if( !reader.Read() ) + { + std::cerr << "Failed to read: " << filename << std::endl; + return 1; + } + const gdcm::DataSet& ds = reader.GetFile().GetDataSet(); + + // (0019,1061) UN (OB) 61\64\61\63\30 # 2048,1 Ver200 ADAC Pegasys Headers + const gdcm::PrivateTag tver200adacpegasysheaders(0x0019,0x61,"ADAC_IMG"); + if( !ds.FindDataElement( tver200adacpegasysheaders ) ) return 1; + const gdcm::DataElement& ver200adacpegasysheaders = ds.GetDataElement( tver200adacpegasysheaders ); + if ( ver200adacpegasysheaders.IsEmpty() ) return 1; + const gdcm::ByteValue * bv = ver200adacpegasysheaders.GetByteValue(); + + // (0019,1021) US 1 # 2,1 Ver200 Number of ADAC Headers + // TODO + + // (0019,1041) IS [2048\221184 ] # 12,1-n Ver200 ADAC Header/Image Size + if( bv->GetLength() != 2048 ) return 1; + + gdcm::Element el; + const gdcm::PrivateTag tver200adacheaderimagesize(0x0019,0x41,"ADAC_IMG"); + if( !ds.FindDataElement( tver200adacheaderimagesize ) ) return 1; + const gdcm::DataElement& ver200adacheaderimagesize = ds.GetDataElement( tver200adacheaderimagesize ); + el.SetFromDataElement( ver200adacheaderimagesize ); + if( el.GetValue(0) != 2048 ) return 1; + + std::istringstream is; + std::string dup( bv->GetPointer(), bv->GetLength() ); + is.str( dup ); + bool b = DumpADAC( is ); + if( !b ) return 1; + + + + return 0; +} diff --git a/gdcm/Examples/Cxx/DumpExamCard.cxx b/gdcm/Examples/Cxx/DumpExamCard.cxx new file mode 100644 index 0000000..115d0f2 --- /dev/null +++ b/gdcm/Examples/Cxx/DumpExamCard.cxx @@ -0,0 +1,541 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + + Try to extract contents of Philips RAW storage class: + +(0002,0002) UI [1.2.840.10008.5.1.4.1.1.66] # 26,1 Media Storage SOP Class UID +(0002,0003) UI [1.3.46.670589.11.17240.5.23.4.1.3012.2010032409482568018] # 56,1 Media Storage SOP Instance UID +(0002,0010) UI [1.2.840.10008.1.2.1] # 20,1 Transfer Syntax UID +(0002,0012) UI [1.3.46.670589.11.0.0.51.4.4.1] # 30,1 Implementation Class UID +(0002,0013) SH [MR DICOM 4.1] # 12,1 Implementation Version Name + + * Everything done in this code is for the sole purpose of writing interoperable + * software under Sect. 1201 (f) Reverse Engineering exception of the DMCA. + * If you believe anything in this code violates any law or any of your rights, + * please contact us (gdcm-developers@lists.sourceforge.net) so that we can + * find a solution. + * + * Everything you do with this code is at your own risk, since decompression + * algorithm was not written from specification documents. + * + * Special thanks to: + * Triplett,William T for bringing to your attention on this ExamCard stuff + */ +#include "gdcmReader.h" +#include "gdcmDataSet.h" +#include "gdcmPrivateTag.h" +#include "gdcmBase64.h" + +#include + +static bool compfn(const char *s1, const char *s2) +{ + return strcmp(s1,s2) < 0 ? true : false; +} + +static const char *PDFStrings[] = { // Keep me ordered please + "PDF_CONTROL_GEN_PARS", + "PDF_CONTROL_PREP_PARS", + "PDF_CONTROL_RECON_PARS", + "PDF_CONTROL_SCAN_PARS", + "PDF_EXAM_PARS", + "PDF_HARDWARE_PARS", + "PDF_PREP_PARS", + "PDF_SPT_PARS", +}; + +static bool isvalidpdfstring( const char *pdfstring ) +{ + assert( pdfstring ); + static const size_t n = sizeof( PDFStrings ) / sizeof( *PDFStrings ); + static const char **begin = PDFStrings; + static const char **end = begin + n; + return std::binary_search(begin, end, pdfstring, compfn); +} + +typedef enum +{ + param_float = 0, + param_integer, + param_string, + param_3, // ?? + param_enum, +} param_type; + +static const char *gettypenamefromtype( int i) +{ + const char *ret = NULL; + param_type e = (param_type)i; + switch( e ) + { + case param_float: + ret = "float"; + break; + case param_integer: + ret = "int"; + break; + case param_string: + ret = "string"; + break; + case param_3: + ret = "??"; + break; + case param_enum: + ret = "enum"; + break; + } + assert( ret ); + return ret; +} + +struct header +{ +/* + * TODO: + * Looks as if we could read all int*, float* and string* at once... + */ + int32_t v1; // offset to int pointer array ? + uint16_t nints; // number of ints (max number?) + uint16_t v3; // always 0 ? + int32_t v4; // offset to float pointer array ? + uint32_t nfloats; + int32_t v6; // offset to string pointer array ? + uint32_t nstrings; + int32_t v8; // always 8 ?? + uint32_t numparams; + uint32_t getnints() const { return nints; } + uint32_t getnfloats() const { return nfloats; } + uint32_t getnstrings() const { return nstrings; } + uint32_t getnparams() const { return numparams; } + void read( std::istream & is ) + { + is.read( (char*)&v1,sizeof(v1)); + is.read( (char*)&nints,sizeof(nints)); + is.read( (char*)&v3,sizeof(v3)); + assert( v3 == 0 ); // looks like this is always 0 + is.read( (char*)&v4,sizeof(v4)); + is.read( (char*)&nfloats,sizeof(nfloats)); + is.read( (char*)&v6,sizeof(v6)); + is.read( (char*)&nstrings,sizeof(nstrings)); + is.read( (char*)&v8,sizeof(v8)); + assert( v8 == 8 ); + is.read( (char*)&numparams,sizeof(numparams)); + } + void print( std::ostream & os ) + { + os << v1 << ","; + os << nints << ","; + os << v3 << ","; + os << v4 << ","; + os << nfloats << ","; + os << v6 << ","; + os << nstrings << ","; + os << v8 << ","; + os << numparams << std::endl; + } +}; + +struct param +{ + char name[32+1]; + int8_t boolean; + int32_t type; + uint32_t dim; + uint32_t v4; + /*int32_t*/ std::streamoff offset; + param_type gettype() const { return (param_type)type; } + uint32_t getdim() const { return dim; } + void read( std::istream & is ) + { + is.read( name, 32 + 1); + //assert( name[32] == 0 ); // fails sometimes... + // This is always the same issue the string can contains garbarge from previous run, + // we need to print only until the first \0 character: + assert( strlen( name ) <= 32 ); // sigh + is.read( (char*)&boolean,1); + assert( boolean == 0 || boolean == 1 ); // some kind of bool... + is.read( (char*)&type, sizeof( type ) ); + assert( gettypenamefromtype( type ) ); + is.read( (char*)&dim, sizeof( dim ) ); + is.read( (char*)&v4, sizeof( v4 ) ); + //assert( v4 == 0 ); // always 0 ? sometimes not... + const std::streamoff cur = is.tellg(); + is.read( (char*)&offset, sizeof( offset ) ); + offset += cur; + } + + void print( std::ostream & os ) const + { + os << name << ","; + os << (int)boolean << ","; + os << type << ","; + os << dim << ","; + os << v4 << ","; + os << offset << std::endl; + } + void printvalue( std::ostream & os, std::istream & is ) const + { + is.seekg( offset ); + switch( type ) + { + case param_float: + { + os.precision(2); + os << std::fixed; + for( uint32_t idx = 0; idx < dim; ++idx ) + { + if( idx ) os << ","; + float v; + is.read( (char*)&v, sizeof(v) ); + os << v; // what if the string contains \0 ? + } + } + break; + case param_integer: + { + for( uint32_t idx = 0; idx < dim; ++idx ) + { + if( idx ) os << ","; + int32_t v; + is.read( (char*)&v, sizeof(v) ); + os << v; + } + } + break; + case param_string: + { + std::string v; + v.resize( dim ); + is.read( &v[0], dim ); + os << v; + } + break; + case param_enum: + { + for( uint32_t idx = 0; idx < dim; ++idx ) + { + if( idx ) os << ","; + int32_t v; + is.read( (char*)&v, sizeof(v) ); + os << v; + } + } + break; + } + + } + void printxml( std::ostream & os, std::istream & is ) const + { + // 0 + os << " "; + printvalue( os, is ); + os << "\n"; + } + void printcsv( std::ostream & os, std::istream & is ) const + { + os << std::setw(32) << std::left << name << ","; + os << std::setw(7) << std::right << gettypenamefromtype(type) << ","; + os << std::setw(4) << dim << ","; + os << " "; + printvalue( os, is ); + os << ",\n"; + } +}; + +static bool ProcessNested( gdcm::DataSet & ds ) +{ + /* + TODO: + Looks like the real length of the blob is stored here: +(2005,1132) SQ # u/l,1 ? + (fffe,e000) na (Item with undefined length) + (2005,0011) LO [Philips MR Imaging DD 002 ] # 26,1 Private Creator + (2005,1143) SL 3103 # 4,1 ? + +Wotsit ? +(2005,1132) SQ # u/l,1 ? + (fffe,e000) na (Item with undefined length) + (2005,0011) LO [Philips MR Imaging DD 002 ] # 26,1 Private Creator + (2005,1147) CS [Y ] # 2,1 ? + */ + bool ret = false; + + // (2005,1137) PN (LO) [PDF_CONTROL_GEN_PARS] # 20,1 ? + const gdcm::PrivateTag pt0(0x2005,0x37,"Philips MR Imaging DD 002"); + if( !ds.FindDataElement( pt0 ) ) return false; + const gdcm::DataElement &de0 = ds.GetDataElement( pt0 ); + if( de0.IsEmpty() ) return false; + const gdcm::ByteValue * bv0 = de0.GetByteValue(); + std::string s0( bv0->GetPointer() , bv0->GetLength() ); + + // (2005,1139) LO [IEEE_PDF] # 8,1 ? + const gdcm::PrivateTag pt1(0x2005,0x39,"Philips MR Imaging DD 002"); + if( !ds.FindDataElement( pt1 ) ) return false; + const gdcm::DataElement &de1 = ds.GetDataElement( pt1 ); + + const gdcm::PrivateTag pt(0x2005,0x44,"Philips MR Imaging DD 002"); + if( !ds.FindDataElement( pt ) ) return false; + const gdcm::DataElement &de = ds.GetDataElement( pt ); + if( de.IsEmpty() ) return false; + const gdcm::ByteValue * bv = de.GetByteValue(); + + if( s0 == "ExamCardBlob" ) + { + assert( de1.IsEmpty() ); + + std::string fn = gdcm::LOComp::Trim( s0.c_str() ); // remove trailing space + fn += ".xml"; + std::ofstream out( fn.c_str() ); + + // remove trailing \0 + size_t len = strlen( bv->GetPointer() ); + out.write( bv->GetPointer() , len ); + out.close(); + + // Extract binary64 thingy (this is a ugly hack, better use an XML parser) + std::string dup( bv->GetPointer(), len ); + std::string::size_type pos1 = dup.find( "" ); + std::string::size_type pos2 = dup.find( "" ); + + std::string b64( bv->GetPointer() + pos1 + 14, pos2 - (pos1 + 14) ); + + // ulgy hack to remove \r\n from input base64: + std::string::iterator r_pos = std::remove(b64.begin(), b64.end(), '\r'); + b64.erase(r_pos, b64.end()); + std::string::iterator n_pos = std::remove(b64.begin(), b64.end(), '\n'); + b64.erase(n_pos, b64.end()); +#if 0 + std::ofstream out2( "debug" ); + out2.write( b64.c_str(), b64.size() ); + out2.close(); +#endif + + const size_t dlen = gdcm::Base64::GetDecodeLength(b64.c_str(), b64.size() ); + + std::string decoded; + decoded.resize( dlen ); + gdcm::Base64::Decode( &decoded[0], decoded.size(), b64.c_str(), b64.size() ); + + std::ofstream f64( "soap.xml" ); + f64.write( decoded.c_str(), decoded.size() ); + f64.close(); + + ret = true; + } + else + { + if( de1.IsEmpty() ) return false; + const gdcm::ByteValue * bv1 = de1.GetByteValue(); + std::string s1( bv1->GetPointer() , bv1->GetLength() ); + + if( s1 == "IEEE_PDF" ) + { + // std::cout << "Len= " << bv->GetLength() << std::endl; +#if 0 + std::string fn = gdcm::LOComp::Trim( s.c_str() ); // remove trailing space + std::ofstream out( fn.c_str() ); + out.write( bv->GetPointer(), bv->GetLength() ); + out.close(); +#endif + + std::istringstream is; + std::string dup( bv->GetPointer(), bv->GetLength() ); + is.str( dup ); + + header h; + h.read( is ); +#if 0 + std::cout << s0.c_str() << std::endl; + h.print( std::cout ); +#endif + + assert( is.tellg() == std::streampos(0x20) ); + is.seekg( 0x20 ); + + std::vector< param > params; + param p; + for( uint32_t i = 0; i < h.getnparams(); ++i ) + { + p.read( is ); + //p.print( std::cout ); + params.push_back( p ); + } + + std::string fn = gdcm::LOComp::Trim( s0.c_str() ); // remove trailing space + assert( isvalidpdfstring( fn.c_str() ) ); + fn += ".csv"; + //fn += ".xml"; + std::ofstream csv( fn.c_str() ); + + // let's do some bookeeping: + uint32_t nfloats = 0; + uint32_t nints = 0; + uint32_t nstrings = 0; + for( std::vector::const_iterator it = params.begin(); + it != params.end(); ++it ) + { + param_type type = it->gettype(); + switch( type ) + { + case param_float: + nfloats += it->getdim(); + break; + case param_integer: + nints += it->getdim(); + break; + case param_string: + nstrings += it->getdim(); + break; + default: + ; + } + } +#if 0 + std::cout << "Stats:" << std::endl; + std::cout << "nfloats:" << nfloats << std::endl; + std::cout << "nints:" << nints << std::endl; + std::cout << "nstrings:" << nstrings << std::endl; +#endif + assert( h.getnints() >= nints ); + assert( h.getnfloats() >= nfloats ); + assert( h.getnstrings() >= nstrings); + + for( uint32_t i = 0; i < h.getnparams(); ++i ) + { + params[i].printcsv( csv, is ); + //params[i].printxml( csv, is ); + } + csv.close(); + ret = true; + } + else if( s1 == "ASCII " ) + { +#if 0 + std::cerr << "ASCII is not handled" << std::endl; + std::string fn = gdcm::LOComp::Trim( s0.c_str() ); // remove trailing space + fn += ".asc"; + std::ofstream out( fn.c_str() ); + out.write( bv->GetPointer() , bv->GetLength() ); + out.close(); +#endif + std::string fn = gdcm::LOComp::Trim( s0.c_str() ); // remove trailing space + fn += ".sin"; + std::ofstream sin( fn.c_str() ); + + const char *beg = bv->GetPointer(); + const char *end = beg + bv->GetLength(); + assert( *beg == 0 ); + const char *p = beg + 1; // skip first \0 + size_t prev = 0; + for( ; p != end; ++p ) + { + if( *p == 0 ) + { + const char *s = beg + prev + 1; + if( *s ) + { + sin << s << std::endl; + } + else + { + sin << std::endl; + } + prev = p - beg; + } + } + sin.close(); + + ret = true; + } + else if( s1 == "BINARY" ) + { + std::cerr << "BINARY is not handled" << std::endl; + std::string fn = gdcm::LOComp::Trim( s0.c_str() ); // remove trailing space + fn += ".bin"; + std::ofstream out( fn.c_str() ); + //out.write( bv->GetPointer() + 512, bv->GetLength() - 512); + out.write( bv->GetPointer() , bv->GetLength() ); + out.close(); + +#if 0 + int array[ 128 ]; + memcpy( array, bv->GetPointer(), 512 ); + for( int i = 0; i < 14; ++i ) + { + std::cout << array[i] << std::endl; + } +#endif + + ret = true; + } + } + // else -> ret == false + assert( ret ); + + return ret; +} + +int main(int argc, char *argv[]) +{ + if( argc < 2 ) return 1; + const char *filename = argv[1]; + gdcm::Reader reader; + reader.SetFileName( filename ); + if( !reader.Read() ) + { + std::cerr << "Failed to read: " << filename << std::endl; + return 1; + } + const gdcm::DataSet& ds = reader.GetFile().GetDataSet(); +/* +(2005,1132) SQ # u/l,1 ? + (fffe,e000) na (Item with undefined length) + (2005,0011) LO [Philips MR Imaging DD 002 ] # 26,1 Private Creator + (2005,1137) PN (LO) [PDF_CONTROL_GEN_PARS] # 20,1 ? + (2005,1138) PN (LO) (no value) # 0,1 ? + (2005,1139) PN (LO) [IEEE_PDF] # 8,1 ? + (2005,1140) PN (LO) (no value) # 0,1 ? + (2005,1141) PN (LO) (no value) # 0,1 ? + (2005,1143) SL 3103 # 4,1 ? + (2005,1144) OW 66\05\00\00\3b\01\00\00\4a\0a\00\00\0e\00\00\00\7a\0a\00\00\95\01\00\00\08\00\00\00\1b\00\00\00\43\47\45\4e\5f\75\73\65\72\5f\64\65\66\5f\6b\65\79\5f\6e\61\6d\65\73\00\00\00\00\00\00\00\00\00 # 3104,1 ? + (2005,1147) CS [Y ] # 2,1 ? + (fffe,e00d) +*/ + const gdcm::PrivateTag pt(0x2005,0x32,"Philips MR Imaging DD 002"); + if( !ds.FindDataElement( pt ) ) return 1; + const gdcm::DataElement &de = ds.GetDataElement( pt ); + if( de.IsEmpty() ) return 1; + + gdcm::SequenceOfItems *sqi = de.GetValueAsSQ(); + if ( !sqi ) return 1; + gdcm::SequenceOfItems::SizeType s = sqi->GetNumberOfItems(); + for( gdcm::SequenceOfItems::SizeType i = 1; i <= s; ++i ) + { + gdcm::Item &item = sqi->GetItem(i); + + gdcm::DataSet &nestedds = item.GetNestedDataSet(); + + if( !ProcessNested( nestedds ) ) return 1; + } + + return 0; +} diff --git a/gdcm/Examples/Cxx/DumpGEMSMovieGroup.cxx b/gdcm/Examples/Cxx/DumpGEMSMovieGroup.cxx new file mode 100644 index 0000000..74f0023 --- /dev/null +++ b/gdcm/Examples/Cxx/DumpGEMSMovieGroup.cxx @@ -0,0 +1,472 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmReader.h" +#include "gdcmImage.h" +#include "gdcmImageWriter.h" +#include "gdcmDataElement.h" +#include "gdcmPrivateTag.h" +#include "gdcmUIDGenerator.h" + +#include +#include + +#include + +bool PrintNameValueMapping( gdcm::SequenceOfItems *sqi_values, +gdcm::SequenceOfItems *sqi_names, std::string const & indent ) +{ + using namespace gdcm; + // prepare names mapping: + typedef VRToType::Type UL; + std::map< UL, std::string > names; + assert( sqi_names ); + assert( sqi_values ); + SequenceOfItems::SizeType s = sqi_names->GetNumberOfItems(); + PrivateTag tindex(0x7fe1,0x71,"GEMS_Ultrasound_MovieGroup_001"); + PrivateTag tname (0x7fe1,0x72,"GEMS_Ultrasound_MovieGroup_001"); + // First sequence contains all possible names (this is a dict) + for( SequenceOfItems::SizeType i = 1; i <= s; ++i ) + { + const Item & item = sqi_names->GetItem( i ); + const DataSet & ds = item.GetNestedDataSet(); + if( !ds.FindDataElement( tindex ) + || !ds.FindDataElement( tname ) ) + { + assert( 0 ); + return false; + } + const DataElement & index = ds.GetDataElement( tindex ); + const DataElement & name = ds.GetDataElement( tname ); + if( index.IsEmpty() || name.IsEmpty() ) + { + assert( 0 ); + return false; + } + gdcm::Element el1; + el1.SetFromDataElement( index ); + + gdcm::Element el2; + el2.SetFromDataElement( name ); +// std::cout << el1.GetValue() << " " << el2.GetValue() << std::endl; + names.insert( std::make_pair( el1.GetValue(), el2.GetValue() ) ); + } + + SequenceOfItems::SizeType s2 = sqi_values->GetNumberOfItems(); + assert( s2 <= s ); + PrivateTag tindex2(0x7fe1,0x48,"GEMS_Ultrasound_MovieGroup_001"); + for( SequenceOfItems::SizeType i = 1; i <= s2; ++i ) + { + const Item & item = sqi_values->GetItem( i ); + const DataSet & ds = item.GetNestedDataSet(); + if( !ds.FindDataElement( tindex2 ) ) + { + assert( 0 ); + return false; + } + const DataElement & index2 = ds.GetDataElement( tindex2 ); + if( index2.IsEmpty() ) + { + assert( 0 ); + return false; + } + gdcm::Element el1; + el1.SetFromDataElement( index2 ); + + UL copy = (UL)el1.GetValue(); +#if 1 + std::cout << indent; + std::cout << "( " << names[ copy ]; +#endif + // (7fe1,1052) FD 1560 # 8,1 ? + // (7fe1,1057) LT [MscSkelSup] # 10,1 ? + //PrivateTag tvalue(0x7fe1,0x52,"GEMS_Ultrasound_MovieGroup_001"); + PrivateTag tvalueint(0x7fe1,0x49,"GEMS_Ultrasound_MovieGroup_001"); // UL + PrivateTag tvaluefloat1(0x7fe1,0x51,"GEMS_Ultrasound_MovieGroup_001"); // FL + PrivateTag tvaluefloat(0x7fe1,0x52,"GEMS_Ultrasound_MovieGroup_001"); // FD + PrivateTag tvalueul(0x7fe1,0x53,"GEMS_Ultrasound_MovieGroup_001"); // UL + PrivateTag tvaluesl(0x7fe1,0x54,"GEMS_Ultrasound_MovieGroup_001"); // SL + PrivateTag tvalueob(0x7fe1,0x55,"GEMS_Ultrasound_MovieGroup_001"); // OB + PrivateTag tvaluetext(0x7fe1,0x57,"GEMS_Ultrasound_MovieGroup_001"); // LT + PrivateTag tvaluefd(0x7fe1,0x77,"GEMS_Ultrasound_MovieGroup_001"); // FD / 1-N + PrivateTag tvaluesl3(0x7fe1,0x79,"GEMS_Ultrasound_MovieGroup_001"); // SL / 1-N + PrivateTag tvaluesl2(0x7fe1,0x86,"GEMS_Ultrasound_MovieGroup_001"); // SL ?? + PrivateTag tvaluefd1(0x7fe1,0x87,"GEMS_Ultrasound_MovieGroup_001"); // FD / 1-N + PrivateTag tvaluefloat2(0x7fe1,0x88,"GEMS_Ultrasound_MovieGroup_001"); // FD ?? +#if 1 + std::cout << " ) = "; +#endif + if( ds.FindDataElement( tvalueint ) ) + { + const DataElement & value = ds.GetDataElement( tvalueint ); + gdcm::Element el2; + el2.SetFromDataElement( value ); + std::cout << el2.GetValue() << std::endl; + } + else if( ds.FindDataElement( tvaluefloat1 ) ) + { + const DataElement & value = ds.GetDataElement( tvaluefloat1 ); + gdcm::Element el2; + el2.SetFromDataElement( value ); + std::cout << el2.GetValue() << std::endl; + } + else if( ds.FindDataElement( tvaluefloat ) ) + { + const DataElement & value = ds.GetDataElement( tvaluefloat ); + gdcm::Element el2; + el2.SetFromDataElement( value ); + std::cout << el2.GetValue() << std::endl; + } + else if( ds.FindDataElement( tvaluesl ) ) + { + const DataElement & value = ds.GetDataElement( tvaluesl ); + gdcm::Element el2; + el2.SetFromDataElement( value ); + std::cout << el2.GetValue() << std::endl; + } + else if( ds.FindDataElement( tvalueul ) ) + { + const DataElement & value = ds.GetDataElement( tvalueul ); + gdcm::Element el2; + el2.SetFromDataElement( value ); + assert( el2.GetLength() == 1 ); + std::cout << el2.GetValue() << std::endl; + } + else if( ds.FindDataElement( tvalueob ) ) + { + const DataElement & value = ds.GetDataElement( tvalueob ); +// gdcm::Element el2; +// el2.SetFromDataElement( value ); +// std::cout << el2.GetValue() << std::endl; + std::cout << value << std::endl; + } + else if( ds.FindDataElement( tvaluetext ) ) + { + const DataElement & value = ds.GetDataElement( tvaluetext ); + gdcm::Element el2; + el2.SetFromDataElement( value ); + std::cout << el2.GetValue() << std::endl; + } + else if( ds.FindDataElement( tvaluesl2 ) ) + { + const DataElement & value = ds.GetDataElement( tvaluesl2 ); + gdcm::Element el2; + el2.SetFromDataElement( value ); + el2.Print( std::cout ); + assert( el2.GetLength() == 4 ); + std::cout << std::endl; + } + else if( ds.FindDataElement( tvaluesl3 ) ) + { + const DataElement & value = ds.GetDataElement( tvaluesl3 ); + gdcm::Element el2; + el2.SetFromDataElement( value ); + el2.Print( std::cout ); +// assert( el2.GetLength() == 4 ); + std::cout << std::endl; + } + else if( ds.FindDataElement( tvaluefd ) ) + { + const DataElement & value = ds.GetDataElement( tvaluefd ); + gdcm::Element el2; + el2.SetFromDataElement( value ); + el2.Print( std::cout ); +// assert( el2.GetLength() == 4 || el2.GetLength() == 3 || el2.GetLength() == 8 ); + std::cout << std::endl; + } + else if( ds.FindDataElement( tvaluefloat2 ) ) + { + const DataElement & value = ds.GetDataElement( tvaluefloat2 ); + gdcm::Element el2; + el2.SetFromDataElement( value ); + el2.Print( std::cout ); + assert( el2.GetLength() == 2 ); + std::cout << std::endl; + } + else if( ds.FindDataElement( tvaluefd1 ) ) + { + const DataElement & value = ds.GetDataElement( tvaluefd1 ); + gdcm::Element el2; + el2.SetFromDataElement( value ); + el2.Print( std::cout ); + assert( el2.GetLength() == 4 ); + std::cout << std::endl; + } + else + { + std::cout << "(no value)" << std::endl; +// std::cout << ds << std::endl; + assert( ds.Size() == 2 ); + } + } + return true; +} + +bool PrintNameValueMapping2( gdcm::PrivateTag const & privtag, const gdcm::DataSet & ds , + gdcm::SequenceOfItems *sqi_names, std::string const & indent ) +{ + if( !ds.FindDataElement( privtag ) ) return 1; + const gdcm::DataElement& seq_values = ds.GetDataElement( privtag ); + gdcm::SmartPointer sqi = seq_values.GetValueAsSQ(); + + return PrintNameValueMapping( sqi, sqi_names, indent); +} + +bool PrintNameValueMapping3( gdcm::PrivateTag const & privtag1, gdcm::PrivateTag const & privtag2, const gdcm::DataSet & ds , +gdcm::SequenceOfItems *sqi_names, std::string const & indent ) +{ + if( !ds.FindDataElement( privtag1 ) ) + { + assert( 0 ); + return false; + } + const gdcm::DataElement& values10name = ds.GetDataElement( privtag1 ); + gdcm::Element el; + el.SetFromDataElement( values10name ); + std::cout << std::endl; + std::cout << " <" << el.GetValue().c_str() << ">" << std::endl; + + return PrintNameValueMapping2( privtag2, ds, sqi_names, indent); +} + +bool print73( gdcm::DataSet const & ds10, gdcm::SequenceOfItems *sqi_dict, std::string const & indent ) +{ + const gdcm::PrivateTag tseq_values73(0x7fe1,0x73,"GEMS_Ultrasound_MovieGroup_001"); + if( !ds10.FindDataElement( tseq_values73 ) ) + { + std::cout << indent << "No group 73" << std::endl; + return false; + } + const gdcm::DataElement& seq_values73 = ds10.GetDataElement( tseq_values73 ); + gdcm::SmartPointer sqi_values73 = seq_values73.GetValueAsSQ(); + + size_t ni3 = sqi_values73->GetNumberOfItems(); + for( size_t i3 = 1; i3 <= ni3; ++i3 ) + { + gdcm::Item &item_73 = sqi_values73->GetItem(i3); + gdcm::DataSet &ds73 = item_73.GetNestedDataSet(); + assert( ds73.Size() == 3 ); + + const gdcm::PrivateTag tseq_values74name(0x7fe1,0x74,"GEMS_Ultrasound_MovieGroup_001"); + const gdcm::PrivateTag tseq_values75(0x7fe1,0x75,"GEMS_Ultrasound_MovieGroup_001"); + PrintNameValueMapping3( tseq_values74name, tseq_values75, ds73, sqi_dict, indent); + std::cout << std::endl; + } + return true; +} + +bool print36( gdcm::DataSet const & ds10, gdcm::SequenceOfItems *sqi_dict, std::string const & indent ) +{ + const gdcm::PrivateTag tseq_values36(0x7fe1,0x36,"GEMS_Ultrasound_MovieGroup_001"); + if( !ds10.FindDataElement( tseq_values36 ) ) + { + std::cout << indent << "No group 36" << std::endl; + return false; + } + const gdcm::DataElement& seq_values36 = ds10.GetDataElement( tseq_values36 ); + gdcm::SmartPointer sqi_values36 = seq_values36.GetValueAsSQ(); + + size_t ni3 = sqi_values36->GetNumberOfItems(); + assert( ni3 == 1 ); + for( size_t i3 = 1; i3 <= ni3; ++i3 ) + { + gdcm::Item &item_36 = sqi_values36->GetItem(i3); + gdcm::DataSet &ds36 = item_36.GetNestedDataSet(); + assert( ds36.Size() == 4 ); + + // (7fe1,1037) UL 47 # 4,1 US MovieGroup Number of Frames + // (7fe1,1043) OB 40\00\1c\c4\67\2f\0b\11\40 # 376,1 ? + // (7fe1,1060) OB 4e\4e\49\4f\4e\47\46\43\2a # 4562714,1 US MovieGroup Image Data + // + const gdcm::PrivateTag timagedata(0x7fe1,0x60,"GEMS_Ultrasound_MovieGroup_001"); + assert( ds36.FindDataElement( timagedata ) ); + gdcm::DataElement const & imagedata = ds36.GetDataElement( timagedata ); + + const gdcm::ByteValue * bv = imagedata.GetByteValue(); + assert( bv ); + static int c = 0; + std::stringstream ss; + ss << "/tmp/debug"; + ss << c++; + std::ofstream os( ss.str().c_str(), std::ios::binary ); + os.write( bv->GetPointer(), bv->GetLength() ); + os.close(); + + //const gdcm::PrivateTag tseq_values85(0x7fe1,0x85,"GEMS_Ultrasound_MovieGroup_001"); + //PrintNameValueMapping3( tseq_values84name, tseq_values85, ds83, sqi_dict, indent); + //std::cout << std::endl; + } + return true; +} +bool print83( gdcm::DataSet const & ds10, gdcm::SequenceOfItems *sqi_dict, std::string const & indent ) +{ + const gdcm::PrivateTag tseq_values83(0x7fe1,0x83,"GEMS_Ultrasound_MovieGroup_001"); + if( !ds10.FindDataElement( tseq_values83 ) ) + { + std::cout << indent << "No group 83" << std::endl; + return false; + } + const gdcm::DataElement& seq_values83 = ds10.GetDataElement( tseq_values83 ); + gdcm::SmartPointer sqi_values83 = seq_values83.GetValueAsSQ(); + + size_t ni3 = sqi_values83->GetNumberOfItems(); + for( size_t i3 = 1; i3 <= ni3; ++i3 ) + { + gdcm::Item &item_83 = sqi_values83->GetItem(i3); + gdcm::DataSet &ds83 = item_83.GetNestedDataSet(); + assert( ds83.Size() == 3 ); + + const gdcm::PrivateTag tseq_values84name(0x7fe1,0x84,"GEMS_Ultrasound_MovieGroup_001"); + const gdcm::PrivateTag tseq_values85(0x7fe1,0x85,"GEMS_Ultrasound_MovieGroup_001"); + PrintNameValueMapping3( tseq_values84name, tseq_values85, ds83, sqi_dict, indent); + std::cout << std::endl; + } + return true; +} + +bool PrintNameValueMapping4( gdcm::PrivateTag const & privtag0, const gdcm::DataSet & subds, gdcm::PrivateTag const & privtag1, gdcm::PrivateTag const & privtag2, +gdcm::SequenceOfItems *sqi_dict, std::string const & indent ) +{ + (void)indent; + if( !subds.FindDataElement( privtag0 ) ) + { + assert( 0 ); + return 1; + } + const gdcm::DataElement& seq_values10 = subds.GetDataElement( privtag0 ); + gdcm::SmartPointer sqi_values10 = seq_values10.GetValueAsSQ(); + + size_t ni1 = sqi_values10->GetNumberOfItems(); +// assert( ni1 == 1 ); + for( size_t i1 = 1; i1 <= ni1; ++i1 ) + { + gdcm::Item &item_10 = sqi_values10->GetItem(i1); + gdcm::DataSet &ds10 = item_10.GetNestedDataSet(); + assert( ds10.Size() == 2 + 3 ); + // (7fe1,0010) + // (7fe1,1012) + // (7fe1,1018) + // (7fe1,1020) + // (7fe1,1083) + + PrintNameValueMapping3( privtag1, privtag2, ds10, sqi_dict, " " ); + std::cout << std::endl; + + const gdcm::PrivateTag tseq_values20(0x7fe1,0x20,"GEMS_Ultrasound_MovieGroup_001"); + if( !ds10.FindDataElement( tseq_values20 ) ) + { + assert( 0 ); + return 1; + } + const gdcm::DataElement& seq_values20 = ds10.GetDataElement( tseq_values20 ); + gdcm::SmartPointer sqi_values20 = seq_values20.GetValueAsSQ(); + + size_t ni2 = sqi_values20->GetNumberOfItems(); + //assert( ni == 1 ); + for( size_t i2 = 1; i2 <= ni2; ++i2 ) + { + gdcm::Item &item_20 = sqi_values20->GetItem(i2); + gdcm::DataSet &ds20 = item_20.GetNestedDataSet(); + size_t count = ds20.Size(); (void)count; + assert( ds20.Size() == 2 + 3 || ds20.Size() == 2 + 2 ); + // (7fe1,0010) + // (7fe1,1024) + // (7fe1,1026) + // (7fe1,1036) + // (7fe1,103a) + // (7fe1,1083) (*) + + const gdcm::PrivateTag tseq_values20name(0x7fe1,0x24,"GEMS_Ultrasound_MovieGroup_001"); + const gdcm::PrivateTag tseq_values26(0x7fe1,0x26,"GEMS_Ultrasound_MovieGroup_001"); + PrintNameValueMapping3( tseq_values20name, tseq_values26, ds20, sqi_dict, " "); + std::cout << std::endl; + + print36(ds20, sqi_dict, " "); + print83(ds20, sqi_dict, " "); + } + + print83(ds10, sqi_dict, " "); + } + return true; +} + +int main(int argc, char *argv[]) +{ + if( argc < 2 ) return 1; + using namespace gdcm; + const char *filename = argv[1]; + gdcm::Reader reader; + reader.SetFileName( filename ); + if( !reader.Read() ) return 1; + + gdcm::File &file = reader.GetFile(); + gdcm::DataSet &ds = file.GetDataSet(); + const PrivateTag tseq(0x7fe1,0x1,"GEMS_Ultrasound_MovieGroup_001"); + + if( !ds.FindDataElement( tseq ) ) return 1; + const DataElement& seq = ds.GetDataElement( tseq ); + + SmartPointer sqi = seq.GetValueAsSQ(); + assert( sqi->GetNumberOfItems() == 1 ); + + Item &item = sqi->GetItem(1); + DataSet &subds = item.GetNestedDataSet(); + + const PrivateTag tseq_dict(0x7fe1,0x70,"GEMS_Ultrasound_MovieGroup_001"); + if( !subds.FindDataElement( tseq_dict ) ) return 1; + const DataElement& seq_dict = subds.GetDataElement( tseq_dict ); + SmartPointer sqi_dict = seq_dict.GetValueAsSQ(); + + const PrivateTag tseq_values8(0x7fe1,0x8,"GEMS_Ultrasound_MovieGroup_001"); + if( !subds.FindDataElement( tseq_values8 ) ) return 1; + const DataElement& seq_values8 = subds.GetDataElement( tseq_values8 ); + SmartPointer sqi_values8 = seq_values8.GetValueAsSQ(); + + const PrivateTag tseq_values8name(0x7fe1,0x2,"GEMS_Ultrasound_MovieGroup_001"); + if( !subds.FindDataElement( tseq_values8name ) ) return 1; + const DataElement& values8name = subds.GetDataElement( tseq_values8name ); +{ + Element el; + el.SetFromDataElement( values8name ); + std::cout << el.GetValue() << std::endl; +} + size_t count = subds.Size(); (void)count; + assert( subds.Size() == 3 + 2 + 1 || subds.Size() == 3 + 2 + 2); + +// (7fe1,0010) # 30,1 Private Creator +// (7fe1,1002) # 8,1 US MovieGroup Value 0008 Name +// (7fe1,1003) # 4,1 ? +// (7fe1,1008) # 8140,1 US MovieGroup Value 0008 Sequence +// (7fe1,1010) # 1372196,1 ? +// (7fe1,1070) # 33684,1 US MovieGroup Dict +// (7fe1,1073) (*) + PrintNameValueMapping( sqi_values8, sqi_dict, " "); + + const PrivateTag tseq_values10(0x7fe1,0x10,"GEMS_Ultrasound_MovieGroup_001"); + const PrivateTag tseq_values10name(0x7fe1,0x12,"GEMS_Ultrasound_MovieGroup_001"); + const PrivateTag tseq_values18(0x7fe1,0x18,"GEMS_Ultrasound_MovieGroup_001"); + PrintNameValueMapping4( tseq_values10, subds, tseq_values10name, tseq_values18, sqi_dict," "); + + print73( subds, sqi_dict, " " ); + +#if 0 + gdcm::DataSet::ConstIterator it = subds.Begin(); + for( ; it != subds.End(); ++it ) + { + const gdcm::DataElement &de = *it; + std::cout << de.GetTag() << std::endl; + } +#endif + + return 0; +} diff --git a/gdcm/Examples/Cxx/DumpImageHeaderInfo.cxx b/gdcm/Examples/Cxx/DumpImageHeaderInfo.cxx new file mode 100644 index 0000000..9ff4e0d --- /dev/null +++ b/gdcm/Examples/Cxx/DumpImageHeaderInfo.cxx @@ -0,0 +1,181 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + * Dump TOSHIBA MDW HEADER / Image Header Info + */ +#include "gdcmReader.h" +#include "gdcmPrivateTag.h" +#include "gdcmAttribute.h" +#include "gdcmImageWriter.h" + +#include +#include +#include + +#include +#include +#include + +struct element +{ + std::istream & read( std::istream & is ); +}; + +std::istream & element::read( std::istream & is ) +{ + static const uint32_t ref = 0xe000fffe; + std::ostream &os = std::cout; + if( is.eof() ) + { + return is; + } + uint32_t magic; + if( !is.read( (char*)&magic, sizeof(magic) ) ) + { + return is; + } + //os << magic << std::endl; + assert( magic == ref ); + + uint32_t l; + is.read( (char*)&l, sizeof(l) ); + //os << l << std::endl; + + char str[17]; + str[16] = 0; + is.read( str, 16 ); + os << str << " (" << l << ")" << std::endl; + std::vector bytes; + bytes.resize( l - 16 ); + if( bytes.size() ) + { + is.read( &bytes[0], l - 16 ); + } + //os << "pos:" << is.tellg() << std::endl; + + if( strcmp(str, "TUSREMEASUREMENT" ) == 0 ) + { + const char *p = &bytes[0]; + uint32_t val; + memcpy( (char*)&val, p, sizeof(val) ); + os << " " << val << std::endl; + p += sizeof(val); + memcpy( (char*)&val, p, sizeof(val) ); + os << " " << val << std::endl; + p += sizeof(val); + memcpy( (char*)&val, p, sizeof(val) ); + os << " " << val << std::endl; + p += sizeof(val); + memcpy( (char*)&val, p, sizeof(val) ); + os << " " << val << std::endl; + p += sizeof(val); + memcpy( (char*)&val, p, sizeof(val) ); + os << " " << val << std::endl; + p += sizeof(val); + memcpy( (char*)&val, p, sizeof(val) ); + os << " " << val << std::endl; + p += sizeof(val); +#if 0 + float f; + memcpy( (char*)&f, p, sizeof(f) ); + os << " " << f << std::endl; + p += sizeof(f); +#else + memcpy( (char*)&val, p, sizeof(val) ); + os << " " << val << std::endl; + p += sizeof(val); +#endif + memcpy( (char*)&val, p, sizeof(val) ); + os << " " << val << std::endl; + p += sizeof(val); + char str2[17]; + memcpy( str2, p, 16 ); + str2[16] = 0; + os << " " << str2 << std::endl; + } + +#if 0 + std::ofstream out( str, std::ios::binary ); + out.write( (char*)&magic, sizeof( magic ) ); + out.write( (char*)&l, sizeof( l ) ); + out.write( str, 16 ); + out.write( &bytes[0], bytes.size() ); +#endif + return is; +} + +static bool DumpImageHeaderInfo( std::istream & is, size_t reflen ) +{ + // TUSNONIMAGESTAM (5176) + // TUSREMEASUREMEN (1352) + // TUSBSINGLELAYOU (16) + // TUSCLIPPARAMETE (104) + + element el; + while( el.read( is ) ) + { + } + //size_t pos = is.tellg(); + //assert( pos == reflen ); + (void)reflen; + + return true; +} + +int main(int argc, char *argv[]) +{ + if( argc < 2 ) return 1; + const char *filename = argv[1]; + gdcm::Reader reader; + reader.SetFileName( filename ); + if( !reader.Read() ) + { + std::cerr << "Failed to read: " << filename << std::endl; + return 1; + } + const gdcm::DataSet& ds = reader.GetFile().GetDataSet(); + + const gdcm::PrivateTag timageheaderinfo(0x0029,0x10,"TOSHIBA MDW HEADER"); + if( !ds.FindDataElement( timageheaderinfo) ) return 1; + const gdcm::DataElement& imageheaderinfo = ds.GetDataElement( timageheaderinfo ); + if ( imageheaderinfo.IsEmpty() ) return 1; + const gdcm::ByteValue * bv = imageheaderinfo.GetByteValue(); + + std::istringstream is; + std::string dup( bv->GetPointer(), bv->GetLength() ); + is.str( dup ); + bool b = DumpImageHeaderInfo( is, bv->GetLength() ); + if( !b ) return 1; + +#if 0 + const float d1 = 0.0041666668839752674; // 89 88 88 3B // 0x44c + //const float d1 = 0.053231674455417881; + const float d2 = 0.10828025639057159; // 0A C2 DD 3D // 0x1ac + //const float d1 = 0.17869562069272813; + //const unsigned int d2 = 4294967280; + const float d3 = 0.10828025639057159; // 0A C2 DD 3D // 0x15c + const int32_t d4 = 134; + const uint32_t d5 = 1153476; + std::ofstream t("/tmp/debug", std::ios::binary ); + //t.write( (char*)&d0, sizeof( d0 ) ); + t.write( (char*)&d1, sizeof( d1 ) ); + t.write( (char*)&d2, sizeof( d2 ) ); + t.write( (char*)&d3, sizeof( d3 ) ); + t.write( (char*)&d4, sizeof( d4 ) ); + t.write( (char*)&d5, sizeof( d5 ) ); + t.close(); +#endif + + return 0; +} diff --git a/gdcm/Examples/Cxx/DumpPhilipsECHO.cxx b/gdcm/Examples/Cxx/DumpPhilipsECHO.cxx new file mode 100644 index 0000000..60e1fb6 --- /dev/null +++ b/gdcm/Examples/Cxx/DumpPhilipsECHO.cxx @@ -0,0 +1,414 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmReader.h" +#include "gdcmDeflateStream.h" +#include "gdcm_zlib.h" + +/* + * This example extract the ZLIB compressed US image from a Philips private tag + * + * Everything done in this code is for the sole purpose of writing interoperable + * software under Sect. 1201 (f) Reverse Engineering exception of the DMCA. + * If you believe anything in this code violates any law or any of your rights, + * please contact us (gdcm-developers@lists.sourceforge.net) so that we can + * find a solution. + * + * Everything you do with this code is at your own risk, since decompression + * algorithm was not written from specification documents. + * + * Usage: + * + * $ DumpPhilipsECHO private_us.dcm raw_us_img.raw + * $ gdcmimg --sop-class-uid 1.2.840.10008.5.1.4.1.1.3.1 --size 608,427,88 raw_us_img.raw raw_us_img.dcm + */ + +// header: +struct hframe +{ + uint32_t val0; // 800 increment ? + uint16_t val1[2]; + uint16_t val2[2]; + uint32_t imgsize; + + bool operator==(const hframe &h) const + { + return val0 == h.val0 && + val1[0] == h.val1[0] && + val1[1] == h.val1[1] && + val2[0] == h.val2[0] && + val2[1] == h.val2[1] && + imgsize == h.imgsize; + } + +}; + +static bool ProcessDeflate( const char *outfilename, const int nslices, const + int buf_size, const char *buf, const std::streampos len, + const char *crcbuf, const size_t crclen ) +{ + std::vector< hframe > crcheaders; + crcheaders.reserve( nslices ); + { + std::istringstream is; + is.str( std::string( crcbuf, crclen ) ); + hframe header; + for( int r = 0; r < nslices; ++r ) + { + is.read( (char*)&header, sizeof( header )); +#if 0 + std::cout << header.val0 + << " " << header.val1[0] + << " " << header.val1[1] + << " " << header.val2[0] + << " " << header.val2[1] + << " " << header.imgsize << std::endl; +#endif + crcheaders.push_back( header ); + } + } + + std::istringstream is; + is.str( std::string( buf, len ) ); + + std::streamoff totalsize; + is.read( (char*)&totalsize, sizeof( totalsize )); + assert( totalsize == len ); + + uint32_t nframes; + is.read( (char*)&nframes, sizeof( nframes )); + assert( nframes == (uint32_t)nslices ); + + std::vector< std::streamoff > offsets; + offsets.reserve( nframes ); + for( uint32_t frame = 0; frame < nframes ; ++frame ) + { + uint32_t offset; + is.read( (char*)&offset, sizeof( offset )); + offsets.push_back( offset ); + } + + std::vector outbuf; + + const int size[2] = { 608, 427 }; // FIXME: where does it comes from ? + std::stringstream ss; + ss << outfilename; + ss << '_'; + //ss << crcheaders[0].imgsize; // FIXME: Assume all header are identical ! + ss << size[0]; + ss << '_'; + ss << size[1]; + ss << '_'; + ss << nframes; + ss << ".raw"; + std::ofstream os( ss.str().c_str(), std::ios::binary ); + + assert( buf_size >= size[0] * size[1] ); + outbuf.resize( buf_size ); + + hframe header; + //uint32_t prev = 0; + for( unsigned int r = 0; r < nframes; ++r ) + { + is.read( (char*)&header, sizeof( header )); + + assert( header == crcheaders[r] ); + assert( header.val1[0] == 2000 ); + assert( header.val1[1] == 3 ); + assert( header.val2[0] == 1 ); + assert( header.val2[1] == 1280 ); + + uLongf destLen = buf_size; // >= 608,427 + Bytef *dest = (Bytef*)&outbuf[0]; + assert( is.tellg() == offsets[r] + 16 ); + const Bytef *source = (Bytef*)buf + offsets[r] + 16; + uLong sourceLen; + if( r + 1 == nframes ) + sourceLen = totalsize - offsets[r] - 16; + else + sourceLen = offsets[r+1] - offsets[r] - 16; + // FIXME: in-memory decompression: + int ret = uncompress (dest, &destLen, source, sourceLen); + assert( ret == Z_OK ); (void)ret; + assert( destLen >= (uLongf)size[0] * size[1] ); // 16bytes padding ? + assert( header.imgsize == (uint32_t)size[0] * size[1] ); + //os.write( &outbuf[0], outbuf.size() ); + os.write( &outbuf[0], size[0] * size[1] ); + + // skip data: + is.seekg( sourceLen, std::ios::cur ); + } + os.close(); + assert( is.tellg() == totalsize ); + + return true; +} + +static bool ProcessNone( const char *outfilename, const int nslices, const + int buf_size, const char *buf, const std::streampos len, + const char *crcbuf, const size_t crclen ) +{ + std::vector< hframe > crcheaders; + crcheaders.reserve( nslices ); + { + std::istringstream is; + is.str( std::string( crcbuf, crclen ) ); + hframe header; + for( int r = 0; r < nslices; ++r ) + { + is.read( (char*)&header, sizeof( header )); +#if 0 + std::cout << header.val0 + << " " << header.val1[0] + << " " << header.val1[1] + << " " << header.val2[0] + << " " << header.val2[1] + << " " << header.imgsize << std::endl; +#endif + crcheaders.push_back( header ); + } + } + + std::istringstream is; + is.str( std::string( buf, len ) ); + + std::streampos totalsize; + is.read( (char*)&totalsize, sizeof( totalsize )); + assert( totalsize == len ); + + uint32_t nframes; + is.read( (char*)&nframes, sizeof( nframes )); + assert( nframes == (uint32_t)nslices ); + + std::vector< uint32_t > offsets; + offsets.reserve( nframes ); + for( uint32_t frame = 0; frame < nframes ; ++frame ) + { + uint32_t offset; + is.read( (char*)&offset, sizeof( offset )); + offsets.push_back( offset ); + //std::cout << offset << std::endl; + } + + std::vector outbuf; + // No idea how to present the data, I'll just append everything, and present it as 2D + std::stringstream ss; + ss << outfilename; + ss << '_'; + ss << crcheaders[0].imgsize; // FIXME: Assume all header are identical ! + ss << '_'; + ss << nframes; + ss << ".raw"; + std::ofstream os( ss.str().c_str(), std::ios::binary ); + outbuf.resize( buf_size ); // overallocated + 16 + char *buffer = &outbuf[0]; + + hframe header; + for( unsigned int r = 0; r < nframes; ++r ) + { + is.read( (char*)&header, sizeof( header )); +#if 0 + std::cout << header.val0 + << " " << header.val1[0] + << " " << header.val1[1] + << " " << header.val2[0] + << " " << header.val2[1] + << " " << header.imgsize << std::endl; +#endif + assert( header == crcheaders[r] ); + + is.read( buffer, buf_size - 16 ); + os.write( buffer, header.imgsize ); + } + assert( is.tellg() == totalsize ); + os.close(); + + return true; +} + +#ifndef NDEBUG +static const char * const UDM_USD_DATATYPE_STRINGS[] = { + "UDM_USD_DATATYPE_DIN_2D_ECHO", + "UDM_USD_DATATYPE_DIN_2D_ECHO_CONTRAST", + "UDM_USD_DATATYPE_DIN_DOPPLER_CW", + "UDM_USD_DATATYPE_DIN_DOPPLER_PW", + "UDM_USD_DATATYPE_DIN_DOPPLER_PW_TDI", + "UDM_USD_DATATYPE_DIN_2D_COLOR_FLOW", + "UDM_USD_DATATYPE_DIN_2D_COLOR_PMI", + "UDM_USD_DATATYPE_DIN_2D_COLOR_CPA", + "UDM_USD_DATATYPE_DIN_2D_COLOR_TDI", + "UDM_USD_DATATYPE_DIN_MMODE_ECHO", + "UDM_USD_DATATYPE_DIN_MMODE_COLOR", + "UDM_USD_DATATYPE_DIN_MMODE_COLOR_TDI", + "UDM_USD_DATATYPE_DIN_PARAM_BLOCK", + "UDM_USD_DATATYPE_DIN_2D_COLOR_VELOCITY", + "UDM_USD_DATATYPE_DIN_2D_COLOR_POWER", + "UDM_USD_DATATYPE_DIN_2D_COLOR_VARIANCE", + "UDM_USD_DATATYPE_DIN_DOPPLER_AUDIO", + "UDM_USD_DATATYPE_DIN_DOPPLER_HIGHQ", + "UDM_USD_DATATYPE_DIN_PHYSIO", + "UDM_USD_DATATYPE_DIN_2D_COLOR_STRAIN", + "UDM_USD_DATATYPE_DIN_COMPOSITE_RGB", + "UDM_USD_DATATYPE_DIN_XFOV_REALTIME_GRAPHICS", + "UDM_USD_DATATYPE_DIN_XFOV_MOSAIC", + "UDM_USD_DATATYPE_DIN_COMPOSITE_R", + "UDM_USD_DATATYPE_DIN_COMPOSITE_G", + "UDM_USD_DATATYPE_DIN_COMPOSITE_B", + "UDM_USD_DATATYPE_DIN_MMODE_COLOR_VELOCITY", + "UDM_USD_DATATYPE_DIN_MMODE_COLOR_POWER", + "UDM_USD_DATATYPE_DIN_MMODE_COLOR_VARIANCE", + "UDM_USD_DATATYPE_DIN_2D_ELASTO", +}; + +static inline bool is_valid( const char * datatype_str ) +{ + static const int n = sizeof( UDM_USD_DATATYPE_STRINGS ) / sizeof( *UDM_USD_DATATYPE_STRINGS ); + bool found = false; + if( datatype_str ) + { + for( int i = 0; !found && i < n; ++i ) + { + found = strcmp( datatype_str, UDM_USD_DATATYPE_STRINGS[i] ) == 0; + } + } + return found; +} +#endif + +int main(int argc, char *argv[]) +{ + if( argc < 2 ) return 1; + using namespace gdcm; + const char *filename = argv[1]; + gdcm::Reader reader; + reader.SetFileName( filename ); + if( !reader.Read() ) return 1; + + gdcm::File &file = reader.GetFile(); + gdcm::DataSet &ds1 = file.GetDataSet(); + + const PrivateTag tseq1(0x200d,0x3cf8,"Philips US Imaging DD 045"); + if( !ds1.FindDataElement( tseq1 ) ) return 1; + const DataElement& seq1 = ds1.GetDataElement( tseq1 ); + + SmartPointer sqi1 = seq1.GetValueAsSQ(); + assert( sqi1->GetNumberOfItems() >= 1 ); + + const size_t nitems = sqi1->GetNumberOfItems(); + for( size_t item = 1; item < nitems; ++item ) + { + Item &item1 = sqi1->GetItem(item); + DataSet &ds2 = item1.GetNestedDataSet(); + + // (200d,300d) LO 28 UDM_USD_DATATYPE_DIN_2D_ECHO + const PrivateTag tdatatype(0x200d,0x300d,"Philips US Imaging DD 033"); + if( !ds2.FindDataElement( tdatatype ) ) return 1; + const DataElement& datatype = ds2.GetDataElement( tdatatype ); + const ByteValue *bvdatatype = datatype.GetByteValue(); + if( !bvdatatype ) return 1; + + const PrivateTag tseq2(0x200d,0x3cf1,"Philips US Imaging DD 045"); + if( !ds2.FindDataElement( tseq2 ) ) return 1; + const DataElement& seq2 = ds2.GetDataElement( tseq2 ); + + SmartPointer sqi2 = seq2.GetValueAsSQ(); + assert( sqi2->GetNumberOfItems() >= 1 ); + + // FIXME: what if not in first Item ? + assert( sqi2->GetNumberOfItems() == 1 ); + Item &item2 = sqi2->GetItem(1); + DataSet &ds3 = item2.GetNestedDataSet(); + + const PrivateTag tzlib(0x200d,0x3cfa,"Philips US Imaging DD 045"); + if( !ds3.FindDataElement( tzlib ) ) return 1; + const DataElement& zlib = ds3.GetDataElement( tzlib ); + + const ByteValue *bv = zlib.GetByteValue(); + if( !bv ) return 1; + if( bv->GetLength() != 4 ) return 1; + + // (200d,3010) IS 2 88 + const PrivateTag tnslices(0x200d,0x3010,"Philips US Imaging DD 033"); + if( !ds3.FindDataElement( tnslices ) ) return 1; + const DataElement& nslices = ds3.GetDataElement( tnslices ); + Element elnslices; + elnslices.SetFromDataElement( nslices ); + const int nslicesref = elnslices.GetValue(); + assert( nslicesref >= 0 ); + // (200d,3011) IS 6 259648 + const PrivateTag tzalloc(0x200d,0x3011,"Philips US Imaging DD 033"); + if( !ds3.FindDataElement( tzalloc ) ) return 1; + const DataElement& zalloc = ds3.GetDataElement( tzalloc ); + Element elzalloc; + elzalloc.SetFromDataElement( zalloc ); + const int zallocref = elzalloc.GetValue(); + assert( zallocref >= 0 ); + // (200d,3021) IS 2 0 + const PrivateTag tzero(0x200d,0x3021,"Philips US Imaging DD 033"); + if( !ds3.FindDataElement( tzero ) ) return 1; + const DataElement& zero = ds3.GetDataElement( tzero ); + Element elzero; + elzero.SetFromDataElement( zero ); + const int zerocref = elzero.GetValue(); + assert( zerocref == 0 ); (void)zerocref; + + // (200d,3cf3) OB + const PrivateTag tdeflate(0x200d,0x3cf3,"Philips US Imaging DD 045"); + if( !ds3.FindDataElement( tdeflate) ) return 1; + const DataElement& deflate = ds3.GetDataElement( tdeflate ); + const ByteValue *bv2 = deflate.GetByteValue(); + + // (200d,3cfb) OB + const PrivateTag tcrc(0x200d,0x3cfb,"Philips US Imaging DD 045"); + if( !ds3.FindDataElement( tcrc ) ) return 1; + const DataElement& crc = ds3.GetDataElement( tcrc ); + const ByteValue *bv3 = crc.GetByteValue(); + + std::string outfile = std::string( bvdatatype->GetPointer(), bvdatatype->GetLength() ); + outfile = LOComp::Trim( outfile.c_str() ); + const char *outfilename = outfile.c_str(); + assert( is_valid(outfilename) ); + if( bv2 ) + { + assert( bv3 ); + assert( zallocref > 0 ); + assert( nslicesref > 0 ); + std::cout << ds2 << std::endl; + + if( strncmp(bv->GetPointer(), "ZLib", 4) == 0 ) + { + if( !ProcessDeflate( outfilename, nslicesref, zallocref, bv2->GetPointer(), + std::streampos(bv2->GetLength()), bv3->GetPointer(), bv3->GetLength() ) ) + { + return 1; + } + } + else if( strncmp(bv->GetPointer(), "None", 4) == 0 ) + { + if( !ProcessNone( outfilename, nslicesref, zallocref, bv2->GetPointer(), + std::streampos(bv2->GetLength()), bv3->GetPointer(), bv3->GetLength() ) ) + { + return 1; + } + } + else + { + std::string str( bv->GetPointer(), bv->GetLength() ); + std::cerr << "Unhandled: " << str << std::endl; + return 1; + } + } + } + + return 0; +} diff --git a/gdcm/Examples/Cxx/DumpToSQLITE3.cxx b/gdcm/Examples/Cxx/DumpToSQLITE3.cxx new file mode 100644 index 0000000..430758d --- /dev/null +++ b/gdcm/Examples/Cxx/DumpToSQLITE3.cxx @@ -0,0 +1,145 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + * Ref: + * http://massmail.spl.harvard.edu/public-archives/slicer-devel/2010/004408.html + * + * Implementation details: + * http://www.sqlite.org/c3ref/bind_blob.html + * http://www.adp-gmbh.ch/sqlite/bind_insert.html + */ +#include "gdcmScanner.h" +#include "gdcmDirectory.h" +#include "gdcmTag.h" +#include "gdcmTrace.h" + +#include "sqlite3.h" + +#include +#include + +int main(int argc, char *argv[]) +{ + if( argc < 2 ) + { + return 1; + } + time_t time_start = time(0); + + gdcm::Trace::SetDebug( false ); + gdcm::Trace::SetWarning( false ); + const char *inputdirectory = argv[1]; + + gdcm::Directory d; + unsigned int nfiles = d.Load( inputdirectory, true); + + gdcm::Scanner s; + using gdcm::Tag; + s.AddTag( Tag(0x20,0xd) ); // Study Instance UID + s.AddTag( Tag(0x20,0xe) ); // Series Instance UID + + bool b0 = s.Scan( d.GetFilenames() ); + if( !b0 ) return 1; + time_t time_scanner = time(0); + + std::cout << "Finished loading data from : " << nfiles << " files" << std::endl; + +// MappingType const &mappings = s.GetMappings(); + + + sqlite3* db; + sqlite3_open("./dicom.db", &db); + + if(db == 0) + { + std::cerr << "Could not open database." << std::endl; + return 1; + } + + const char sql_stmt[] = "create table browser (seriesuid, studyuid)"; + int ret; + + char *errmsg; + ret = sqlite3_exec(db, sql_stmt, 0, 0, &errmsg); + + if(ret != SQLITE_OK) + { + printf("Error in statement: %s [%s].\n", sql_stmt, errmsg); + return 1; + } + using gdcm::Directory; + using gdcm::Scanner; + const Directory::FilenamesType& files = d.GetFilenames(); + Directory::FilenamesType::const_iterator file = files.begin(); + + sqlite3_stmt *stmt; + if ( sqlite3_prepare( + db, + "insert into browser values (?,?)", // stmt + -1, // If than zero, then stmt is read up to the first nul terminator + &stmt, + 0 // Pointer to unused portion of stmt + ) + != SQLITE_OK) + { + printf("\nCould not prepare statement."); + return 1; + } + //printf("\nThe statement has %d wildcards\n", sqlite3_bind_parameter_count(stmt)); + for(; file != files.end(); ++file) + { + const char *filename = file->c_str(); + bool b = s.IsKey(filename); + if( b ) + { + const Scanner::TagToValue &mapping = s.GetMapping(filename); + Scanner::TagToValue::const_iterator it = mapping.begin(); + + sqlite3_reset(stmt); + + for( int index = 1; it != mapping.end(); ++it, ++index) + { + //const Tag & tag = it->first; + const char *value = it->second; + + if (sqlite3_bind_text ( + stmt, + index, // Index of wildcard + value, + (int)strlen(value), // length of text + SQLITE_STATIC // SQLite assumes that the information is in static + ) + != SQLITE_OK) + { + printf("\nCould not bind int.\n"); + return 1; + } + } + if (sqlite3_step(stmt) != SQLITE_DONE) + { + printf("\nCould not step (execute) stmt.\n"); + return 1; + } + } + } + + sqlite3_close(db); + + time_t time_sqlite = time(0); + + std::cout << "Time to scan DICOM files: " << (time_scanner - time_start) << std::endl; + std::cout << "Time to build SQLITE3: " << (time_sqlite - time_scanner) << std::endl; + + return 0; +} diff --git a/gdcm/Examples/Cxx/DuplicatePCDE.cxx b/gdcm/Examples/Cxx/DuplicatePCDE.cxx new file mode 100644 index 0000000..4f71a40 --- /dev/null +++ b/gdcm/Examples/Cxx/DuplicatePCDE.cxx @@ -0,0 +1,198 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmReader.h" +#include "gdcmWriter.h" +#include "gdcmItem.h" +#include "gdcmImageReader.h" +#include "gdcmSequenceOfItems.h" +#include "gdcmFile.h" +#include "gdcmTag.h" +/* + Usage: + DuplicatePCDE gdcmData/D_CLUNIE_CT1_J2KI.dcm out.dcm + +aka: +medical.nema.org/medical/dicom/DataSets/WG04/IMAGES/J2KI/CT1_J2KI + +See: + gdcmConformanceTests/CT1_J2KI_DuplicatePCDE.dcm + +Original thread can be found at: + +http://groups.google.com/group/comp.protocols.dicom/browse_thread/thread/82f28c4db28963af + + +Question: +1. + There is no restriction for a specific Private Creator Data Element +(PCDE) to be unique within the same group, right ? + Decoders of Private Data would have to handle the case where a PCDE +would be repeated and should NOT stop on the first instance of a +particular PCDE, right ? + + Eg. when searching for the tag associated with +(0x0029,0x0010,"SIEMENS CSA HEADER") in the following (pseudo) +dataset: + +(0029,0010) LO [SIEMENS CSA HEADER] # 18, 1 +PrivateCreator +(0029,0011) LO [SIEMENS MEDCOM HEADER] # 22, 1 +PrivateCreator +(0029,0012) LO [SIEMENS MEDCOM HEADER2] # 22, 1 +PrivateCreator +(0029,0013) LO [SIEMENS CSA HEADER] # 18, 1 +PrivateCreator +(0029,1008) CS [IMAGE NUM 4] # 12, 1 +CSAImageHeaderType +(0029,1009) LO [20050723] # 8, 1 +CSAImageHeaderVersion +(0029,1010) OB 53\56\31\30\04\03\02\01\38\00\00\00\4d +\00\00\00\45\63\68\6f\4c\69... # 6788, 1 CSAImageHeaderInfo +(0029,1018) CS [MR] # 2, 1 +CSASeriesHeaderType +(0029,1019) LO [20050723] # 8, 1 +CSASeriesHeaderVersion +(0029,1020) OB 53\56\31\30\04\03\02\01\2c\00\00\00\4d +\00\00\00\55\73\65\64\50\61... # 51520, 1 CSASeriesHeaderInfo +(0029,1131) LO [4.0.163088300] # 14, 1 +PMTFInformation1 +(0029,1132) UL 32768 # 4, 1 +PMTFInformation2 +(0029,1133) UL 0 # 4, 1 +PMTFInformation3 +(0029,1134) CS [DB TO DICOM] # 12, 1 +PMTFInformation4 +(0029,1260) ?? 63\6f\6d\20 # 4, 1 +Unknown Tag & Data +(0029,1310) OB 53\56\31\30\04\03\02\01\38\00\00\00\4d +\00\00\00\45\63\68\6f\4c\69... # 6788, 1 CSAImageHeaderInfo + + one should return two instances, correct ? + +Answer: +I would say that this is covered in principle by the PS 3.5 7.1 +"The Data Elements ... shall occur at most once in a Data Set" +rule, since the data element is defined by the tuple +(private creator,gggg,ee) where xxee is the element +number and xx is arbitrary and has no inherent meaning and +does not serve to disambiguate the data element. + +E.g.: + +(0019,0030) Private Creator ID = "Smith" +... +(0019,0032) Private Creator ID = "Smith" +... +(0019,3015) Fractal Index = "32" +... +(0019,3215) Fractal Index = "32" + +would be illegal because even though they are assigned different +(completely arbitrary) blocks, with the same group, element +number and private creator, (0019,3015) and (0019,3215) are the +"same" data element. + +*/ + +int main(int argc, char *argv[]) +{ + if( argc < 3 ) + { + std::cerr << argv[0] << " input.dcm output.dcm" << std::endl; + return 1; + } + const char *filename = argv[1]; + const char *outfilename = argv[2]; + gdcm::Reader reader; + reader.SetFileName( filename ); + if( !reader.Read() ) + { + return 1; + } + + gdcm::File &file = reader.GetFile(); + gdcm::DataSet &ds = file.GetDataSet(); + + // Let's get all private element from group 0x9: +/* +(0009,0010) LO [GEMS_IDEN_01] # 12,1 Private Creator +(0009,1001) LO [GE_GENESIS_FF ] # 14,1 Full fidelity +(0009,1002) SH [CT01] # 4,1 Suite id +(0009,1004) SH [HiSpeed CT/i] # 12,1 Product id +(0009,1027) SL 862399669 # 4,1 Image actual date +(0009,1030) SH (no value) # 0,1 Service id +(0009,1031) SH (no value) # 0,1 Mobile location number +(0009,10e6) SH [05] # 2,1 Genesis Version - now +(0009,10e7) UL 973283917 # 4,1 Exam Record checksum +(0009,10e9) SL 862399669 # 4,1 Actual series data time stamp +*/ + gdcm::Tag start(0x0009,0x0); + // Create a temporary duplicate dataset, since we cannot insert data element as we go over them (std::set + // would reorganize itself as we go over it ...) + gdcm::DataSet dup; + gdcm::Tag new_private(0x0009,0x0); + while (start.GetGroup() == 0x9 ) + { + const gdcm::DataElement& de = ds.FindNextDataElement(start); + const gdcm::Tag &t = de.GetTag(); + if( t.IsPrivateCreator() ) + { + std::cout << t << std::endl; + // Ok let's duplicate into the next available attribute: + gdcm::DataElement duplicate = de; + duplicate.GetTag().SetElement( (uint16_t)(t.GetElement() + 1) ); + dup.Insert( duplicate ); + new_private = duplicate.GetTag(); + } + else if( t.IsPrivate() && !t.IsPrivateCreator() ) + { + //std::cout << de << std::endl; + std::string owner = ds.GetPrivateCreator( de.GetTag() ); + //std::cout << owner << std::endl; + gdcm::DataElement duplicate = de; + duplicate.GetTag().SetPrivateCreator( new_private ); + if( const gdcm::ByteValue *bv = duplicate.GetByteValue() ) + { + // Warning: when doing : duplicate = de, only the pointer to the ByteValue is passed + // (to avoid large memory duplicate). We need to explicitely duplicate the bytevalue ourselves: + gdcm::ByteValue *dupbv = new gdcm::ByteValue( bv->GetPointer(), + bv->GetLength() ); + // Let's recognize the duplicated ASCII-type elements: + if( duplicate.GetVR() & gdcm::VR::VRASCII ) + dupbv->Fill( 'X' ); + duplicate.SetValue( *dupbv ); + } + dup.Insert( duplicate ); + } + start = t; + // move to next possible 'public' element + start.SetElement( (uint16_t)(start.GetElement() + 1) ); + } + + gdcm::DataSet::ConstIterator it = dup.Begin(); + for( ; it != dup.End(); ++it ) + { + ds.Insert( *it ); + } + + gdcm::Writer w; + w.SetFile( file ); + w.SetFileName( outfilename ); + if (!w.Write() ) + { + return 1; + } + + return 0; +} diff --git a/gdcm/Examples/Cxx/ELSCINT1WaveToText.cxx b/gdcm/Examples/Cxx/ELSCINT1WaveToText.cxx new file mode 100644 index 0000000..0b05636 --- /dev/null +++ b/gdcm/Examples/Cxx/ELSCINT1WaveToText.cxx @@ -0,0 +1,113 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmReader.h" +#include "gdcmPrivateTag.h" + +/* + * This example shows how to read a Wave Information tag from ELSCINT1 + * The wave information is stored in Tag (01e1,18,ELSCINT1) hidden in a + * Secondary Capture Image Storage (usually a 'N' Symbol is shown) + * + * Everything done in this code is for the sole purpose of writing interoperable + * software under Sect. 1201 (f) Reverse Engineering exception of the DMCA. + * If you believe anything in this code violates any law or any of your rights, + * please contact us (gdcm-developers@lists.sourceforge.net) so that we can + * find a solution. + * + * Everything you do with this code is at your own risk, since decompression + * algorithm was not written from specification documents. + * + * Special thanks to: + * Gauthier Bouilhol + */ + +template +bool dumpargs(std::ostream & os, T c1, T c2, T c3, T c4, T c5, T c6, T c7, T c8) +{ + static const char sep = '\t'; + os << c1 << sep << c2 << sep << c3 << sep << c4 << sep << c5 << sep << c6 << sep << c7 << sep << c8; + os << std::endl; + return true; +} + +bool wave2stream( std::ostream &text_file, const char *in, size_t len ) +{ + short * buffer = (short*)in; + size_t length = len / sizeof( short ); + text_file << "COMPLETE_WAVE" << '\t' << "MASK" << '\t' << "AQUISITION_PROFIL" << '\t' << "END-INHALE" << '\t' << "END-EXHALE" << '\t' << "AQUISITION_WAVE" << '\t' << "WAVE_STATISTICS" << '\t' << "MASK" << std::endl; + for (size_t i=0;iGetPointer(), bv->GetLength() ); + os.close(); + + return 0; +} diff --git a/gdcm/Examples/Cxx/EncapsulateFileInRawData.cxx b/gdcm/Examples/Cxx/EncapsulateFileInRawData.cxx new file mode 100644 index 0000000..b69296b --- /dev/null +++ b/gdcm/Examples/Cxx/EncapsulateFileInRawData.cxx @@ -0,0 +1,81 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmAnonymizer.h" +#include "gdcmWriter.h" +#include "gdcmUIDGenerator.h" +#include "gdcmFile.h" +#include "gdcmTag.h" +#include "gdcmSystem.h" + +#include "magic.h" // libmagic, API to file command line tool + +/* + * Let say you want to encapsulate a file type that is not defined in DICOM (exe, zip, png) + * PNG is a bad example, unless it contains transparency (which has been deprecated). + * It will take care of dispatching each chunk to an appropriate data item (pretty much like + * WaveformData) + * + * Usage: + * ./EncapsulateFileInRawData large_input_file.exe large_input_file.dcm + */ + +// TODO: +// $ file -bi /tmp/gdcm-2.1.0.pdf +int main(int argc, char *argv[]) +{ + if( argc < 3 ) + { + std::cerr << argv[0] << " inputfile output.dcm" << std::endl; + return 1; + } + const char *filename = argv[1]; + const char *outfilename = argv[2]; + + if( !gdcm::System::FileExists( filename ) ) return 1; + + size_t s = gdcm::System::FileSize(filename); + if( !s ) return 1; + + magic_t cookie = magic_open(MAGIC_NONE); + const char * file_type = magic_file(cookie, filename); + if( !file_type ) return 1; + magic_close(cookie); + + gdcm::Writer w; + gdcm::File &file = w.GetFile(); + //gdcm::DataSet &ds = file.GetDataSet(); + //w.SetCheckFileMetaInformation( true ); + w.SetFileName( outfilename ); + + file.GetHeader().SetDataSetTransferSyntax( gdcm::TransferSyntax::ImplicitVRLittleEndian ); + + gdcm::Anonymizer anon; + anon.SetFile( file ); + + gdcm::MediaStorage ms = gdcm::MediaStorage::RawDataStorage; + + gdcm::UIDGenerator gen; + anon.Replace( gdcm::Tag(0x0008,0x16), ms.GetString() ); + std::cout << ms.GetString() << std::endl; + anon.Replace( gdcm::Tag(0x0008,0x18), gen.Generate() ); + + + if (!w.Write() ) + { + std::cerr << "Could not write: " << outfilename << std::endl; + return 1; + } + + return 0; +} diff --git a/gdcm/Examples/Cxx/ExtractEncryptedContent.cxx b/gdcm/Examples/Cxx/ExtractEncryptedContent.cxx new file mode 100644 index 0000000..a697d7f --- /dev/null +++ b/gdcm/Examples/Cxx/ExtractEncryptedContent.cxx @@ -0,0 +1,67 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmReader.h" + +#include + +/* + +openssl smime -encrypt -binary -aes256 -in outputfile.dcm -inform DER -out outputfile.der -outform DER ../trunk/Testing/Source/Data/certificate.pem + +openssl smime -decrypt -binary -in out.der -inform DER -out outputfile.dcm -outform DER -inkey ../trunk/Testing/Source/Data/privatekey.pem ../trunk/Testing/Source/Data/certificate.pem + + */ + +int main(int argc, char *argv[]) +{ + if( argc < 3 ) + { + std::cerr << argv[0] << " input.dcm output.der" << std::endl; + return 1; + } + const char *filename = argv[1]; + const char *outfilename = argv[2]; + + gdcm::Reader reader; + reader.SetFileName( filename ); + if( !reader.Read() ) + { + return 1; + } + + gdcm::File &file = reader.GetFile(); + gdcm::DataSet &ds = file.GetDataSet(); + + const gdcm::DataElement &EncryptedAttributesSequence = ds.GetDataElement( gdcm::Tag( 0x0400,0x0500 ) ); + + gdcm::SequenceOfItems *sqi = EncryptedAttributesSequence.GetValueAsSQ(); + + if ( !sqi || sqi->GetNumberOfItems() != 1 ) return 1; + + gdcm::Item &item = sqi->GetItem(1); + + gdcm::DataSet &nestedds = item.GetNestedDataSet(); + + if( ! nestedds.FindDataElement( gdcm::Tag( 0x0400,0x0520) ) ) return 1; + + const gdcm::DataElement &EncryptedContent = nestedds.GetDataElement( gdcm::Tag( 0x0400,0x0520) ); + + const gdcm::ByteValue *bv = EncryptedContent.GetByteValue(); + + std::ofstream of( outfilename, std::ios::binary ); + of.write( bv->GetPointer(), bv->GetLength() ); + of.close(); + + return 0; +} diff --git a/gdcm/Examples/Cxx/ExtractIconFromFile.cxx b/gdcm/Examples/Cxx/ExtractIconFromFile.cxx new file mode 100644 index 0000000..8e366fa --- /dev/null +++ b/gdcm/Examples/Cxx/ExtractIconFromFile.cxx @@ -0,0 +1,92 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + * This example shows how to either retrieve an Icon if present somewhere + * in the file, or else generate one. + */ +#include "gdcmImageReader.h" +#include "gdcmPNMCodec.h" +#include "gdcmIconImageFilter.h" +#include "gdcmIconImageGenerator.h" + +bool WriteIconAsPNM(const char* filename, const gdcm::IconImage& icon) +{ + gdcm::PNMCodec pnm; + pnm.SetDimensions( icon.GetDimensions() ); + pnm.SetPixelFormat( icon.GetPixelFormat() ); + pnm.SetPhotometricInterpretation( icon.GetPhotometricInterpretation() ); + pnm.SetLUT( icon.GetLUT() ); + const gdcm::DataElement& in = icon.GetDataElement(); + bool b = pnm.Write( filename, in ); + assert( b ); + return b; +} + +int main(int argc, char *argv []) +{ + if( argc < 2 ) return 1; + const char *filename = argv[1]; + gdcm::ImageReader reader; + reader.SetFileName( filename ); + if( !reader.Read() ) + { + std::cerr << "Failed to read (or not image): " << filename << std::endl; + return 1; + } + + gdcm::IconImageFilter iif; + iif.SetFile( reader.GetFile() ); + bool b = iif.Extract(); + + if( b ) + { + const gdcm::IconImage &icon = iif.GetIconImage(0); + icon.Print( std::cout ); + + if( !icon.GetTransferSyntax().IsEncapsulated() ) + { + // Let's write out this icon as PNM file + WriteIconAsPNM("icon.ppm", icon); + } + else if( icon.GetTransferSyntax() == gdcm::TransferSyntax::JPEGBaselineProcess1 + || icon.GetTransferSyntax() == gdcm::TransferSyntax::JPEGExtendedProcess2_4 + ) + { + const gdcm::DataElement& in = icon.GetDataElement(); + const gdcm::ByteValue *bv = in.GetByteValue(); + assert( bv ); + std::ofstream out( "icon.jpg", std::ios::binary ); + out.write( bv->GetPointer(), bv->GetLength() ); + out.close(); + } + } + else + { + assert( iif.GetNumberOfIconImages() == 0 ); + std::cerr << "No Icon Found anywhere in file" << std::endl; + + const gdcm::Image &img = reader.GetImage(); + gdcm::IconImageGenerator iig; + iig.AutoPixelMinMax(true); + iig.SetPixmap( img ); + const unsigned int idims[2] = { 64, 64 }; + iig.SetOutputDimensions( idims ); + //iig.SetPixelMinMax(60, 868); + if( !iig.Generate() ) return 1; + const gdcm::IconImage & icon = iig.GetIconImage(); + WriteIconAsPNM("icon.ppm", icon); + } + + return 0; +} diff --git a/gdcm/Examples/Cxx/Extracting_All_Resolution.cxx b/gdcm/Examples/Cxx/Extracting_All_Resolution.cxx new file mode 100644 index 0000000..d90f525 --- /dev/null +++ b/gdcm/Examples/Cxx/Extracting_All_Resolution.cxx @@ -0,0 +1,458 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +// This work was realised during the GSOC 2011 by Manoj Alwani + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "gdcmImageReader.h" +#include "gdcmSequenceOfItems.h" +#include "gdcmSystem.h" +#include + + + +#include "gdcmMediaStorage.h" +#include "gdcmWriter.h" +#include "gdcmItem.h" +#include "gdcmImageReader.h" +#include "gdcmAttribute.h" +#include "gdcmFile.h" +#include "gdcmTag.h" +#include "gdcmTransferSyntax.h" +#include "gdcmUIDGenerator.h" +#include "gdcmAnonymizer.h" +#include "gdcmStreamImageWriter.h" +#include "gdcmImageHelper.h" +#include "gdcmTrace.h" + +void error_callback(const char *msg, void *) { + (void)msg; +} +void warning_callback(const char *msg, void *) { + (void)msg; +} +void info_callback(const char *msg, void *) { + (void)msg; +} + + +bool Write_Resolution(gdcm::StreamImageWriter & theStreamWriter, const char *filename, int res, std::ostream& of, int flag, gdcm::SequenceOfItems *sq, int No_Of_Resolutions) +{ + std::ifstream is; + is.open( filename, std::ios::binary ); + opj_dparameters_t parameters; /* decompression parameters */ + opj_event_mgr_t event_mgr; /* event manager */ + opj_dinfo_t* dinfo; /* handle to a decompressor */ + opj_cio_t *cio; + opj_image_t *image = NULL; + // FIXME: Do some stupid work: + is.seekg( 0, std::ios::end); + std::streampos buf_size = is.tellg(); + char *dummy_buffer = new char[(unsigned int)buf_size]; + is.seekg(0, std::ios::beg); + is.read( dummy_buffer, buf_size); + unsigned char *src = (unsigned char*)dummy_buffer; + uint32_t file_length = (uint32_t)buf_size; // 32bits truncation should be ok since DICOM cannot have larger than 2Gb image + + + /* configure the event callbacks (not required) */ + memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); + event_mgr.error_handler = error_callback; + event_mgr.warning_handler = warning_callback; + event_mgr.info_handler = info_callback; + + /* set decoding parameters to default values */ + opj_set_default_decoder_parameters(¶meters); + + // default blindly copied + parameters.cp_layer=0; + parameters.cp_reduce= res; + // parameters.decod_format=-1; + // parameters.cod_format=-1; + + const char jp2magic[] = "\x00\x00\x00\x0C\x6A\x50\x20\x20\x0D\x0A\x87\x0A"; + if( memcmp( src, jp2magic, sizeof(jp2magic) ) == 0 ) + { + /* JPEG-2000 compressed image data ... sigh */ + // gdcmData/ELSCINT1_JP2vsJ2K.dcm + // gdcmData/MAROTECH_CT_JP2Lossy.dcm + //gdcmWarningMacro( "J2K start like JPEG-2000 compressed image data instead of codestream" ); + parameters.decod_format = 1; //JP2_CFMT; + //assert(parameters.decod_format == JP2_CFMT); + } + else + { + /* JPEG-2000 codestream */ + //parameters.decod_format = J2K_CFMT; + //assert(parameters.decod_format == J2K_CFMT); + assert( 0 ); + } + parameters.cod_format = 11; // PGX_DFMT; + //assert(parameters.cod_format == PGX_DFMT); + + /* get a decoder handle */ + dinfo = opj_create_decompress(CODEC_JP2); + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, NULL); + + /* setup the decoder decoding parameters using user parameters */ + opj_setup_decoder(dinfo, ¶meters); + + /* open a byte stream */ + cio = opj_cio_open((opj_common_ptr)dinfo, src, file_length); + + /* decode the stream and fill the image structure */ + image = opj_decode(dinfo, cio); + if(!image) { + opj_destroy_decompress(dinfo); + opj_cio_close(cio); + //gdcmErrorMacro( "opj_decode failed" ); + return 1; + } + + opj_cp_t * cp = ((opj_jp2_t*)dinfo->jp2_handle)->j2k->cp; + opj_tcp_t *tcp = &cp->tcps[0]; + opj_tccp_t *tccp = &tcp->tccps[0]; + /* std::cout << "\n No of Cols In Image" << image->x1; + std::cout << "\n No of Rows In Image" << image->y1; + std::cout << "\n No of Components in Image" << image->numcomps; + std::cout << "\n No of Resolutions"<< tccp->numresolutions << "\n"; +*/ + opj_j2k_t* j2k = NULL; + opj_jp2_t* jp2 = NULL; + jp2 = (opj_jp2_t*)dinfo->jp2_handle; + int reversible = jp2->j2k->cp->tcps->tccps->qmfbid; + //std:: cout << reversible; + int compno = 0; + opj_image_comp_t *comp = &image->comps[compno]; + int Dimensions[2]; + Dimensions[0]= comp->w; + Dimensions[1] = comp->h; + opj_cio_close(cio); + unsigned long len = Dimensions[0]*Dimensions[1] * image->numcomps; + //std::cout << "\nTest" <comps[0].factor; + char *raw = new char[len]; + for (unsigned int compno = 0; compno < (unsigned int)image->numcomps; compno++) + { + opj_image_comp_t *comp = &image->comps[compno]; + + int w = image->comps[compno].w; + int h = image->comps[compno].h; + uint8_t *data8 = (uint8_t*)raw + compno; + for (int i = 0; i < w * h ; i++) + { + int v = image->comps[compno].data[i]; + *data8 = (uint8_t)v; + data8 += image->numcomps; + } + } + + gdcm::Writer w; + gdcm::File &file = w.GetFile(); + gdcm::DataSet &ds = file.GetDataSet(); + + file.GetHeader().SetDataSetTransferSyntax( gdcm::TransferSyntax::ExplicitVRLittleEndian ); + + gdcm::UIDGenerator uid; + gdcm::DataElement de( gdcm::Tag(0x8,0x18) ); // SOP Instance UID + de.SetVR( gdcm::VR::UI ); + const char *u = uid.Generate(); + de.SetByteValue( u, strlen(u) ); + ds.Insert( de ); + + gdcm::DataElement de1( gdcm::Tag(0x8,0x16) ); + de1.SetVR( gdcm::VR::UI ); + gdcm::MediaStorage ms( gdcm::MediaStorage::CTImageStorage ); + de1.SetByteValue( ms.GetString(), strlen(ms.GetString())); + ds.Insert( de1 ); + + const char mystr[] = "MONOCHROME2 "; + gdcm::DataElement de2( gdcm::Tag(0x28,0x04) ); + //de.SetTag(gdcm::Tag(0x28,0x04)); + de2.SetVR( gdcm::VR::CS ); + de2.SetByteValue(mystr, strlen(mystr)); + ds.Insert( de2 ); + + gdcm::Attribute<0x0028,0x0010> row = {image->comps[0].w}; + //row.SetValue(512); + ds.Insert( row.GetAsDataElement() ); + // w.SetCheckFileMetaInformation( true ); + gdcm::Attribute<0x0028,0x0011> col = {image->comps[0].h}; + ds.Insert( col.GetAsDataElement() ); + gdcm::Attribute<0x0028,0x0008> Number_Of_Frames = {1}; + ds.Insert( Number_Of_Frames.GetAsDataElement() ); + + gdcm::Attribute<0x0028,0x0100> at = {8}; + ds.Insert( at.GetAsDataElement() ); + + gdcm::Attribute<0x0028,0x0002> at1 = {image->numcomps}; + ds.Insert( at1.GetAsDataElement() ); + + gdcm::Attribute<0x0028,0x0101> at2 = {8}; + ds.Insert( at2.GetAsDataElement() ); + + gdcm::Attribute<0x0028,0x0102> at3 = {7}; + ds.Insert( at3.GetAsDataElement() ); + + + + if (flag == 1) + { + + for (int i=0; i < No_Of_Resolutions; i++) + { + + int a = 1; + int b =1; + + while(a!=((No_Of_Resolutions)-i)) + { + b = b*2; + a = a+1; + } + uint16_t row = (image->y1)/b; + uint16_t col = (image->x1)/b; + //std::cout << row; + gdcm::Element el2; + el2.SetValue(i+1); + gdcm::DataElement rfn = el2.GetAsDataElement(); //ulr --> upper left row + rfn.SetTag( gdcm::Tag(0x0008,0x1160) ); + + gdcm::Element el; + el.SetValue(1,0); + el.SetValue(1,1); + gdcm::DataElement ulr = el.GetAsDataElement(); //ulr --> upper left col/row + ulr.SetTag( gdcm::Tag(0x0048,0x0201) ); + + gdcm::Element el1; + el1.SetValue(col,0); + el1.SetValue(row,1); + gdcm::DataElement brr = el1.GetAsDataElement(); + brr.SetTag( gdcm::Tag(0x0048,0x0202) ); //brr --> bottom right col/row + gdcm::Item it; + gdcm::DataSet &nds = it.GetNestedDataSet(); + nds.Insert( rfn ); + nds.Insert(ulr); + nds.Insert(brr); + + sq->AddItem(it); + } + + gdcm::Writer w1; + gdcm::File &file1 = w1.GetFile(); + gdcm::DataSet &ds1 = file1.GetDataSet(); + file1.GetHeader().SetDataSetTransferSyntax( gdcm::TransferSyntax::ExplicitVRLittleEndian ); + + gdcm::UIDGenerator uid1; + gdcm::DataElement dea( gdcm::Tag(0x8,0x18) ); // SOP Instance UID + dea.SetVR( gdcm::VR::UI ); + const char *u1 = uid1.Generate(); + dea.SetByteValue( u1, strlen(u1) ); + ds1.Insert( dea ); + + gdcm::DataElement deb( gdcm::Tag(0x8,0x16) ); + deb.SetVR( gdcm::VR::UI ); + gdcm::MediaStorage ms1( gdcm::MediaStorage::VLWholeSlideMicroscopyImageStorage ); + deb.SetByteValue( ms1.GetString(), strlen(ms1.GetString())); + ds1.Insert( deb ); + + const char mystr1[] = "MONOCHROME2 "; + gdcm::DataElement dec( gdcm::Tag(0x28,0x04) ); + //de.SetTag(gdcm::Tag(0x28,0x04)); + dec.SetVR( gdcm::VR::CS ); + dec.SetByteValue(mystr, strlen(mystr1)); + ds1.Insert( dec ); + + gdcm::Attribute<0x0028,0x0010> row1 = {image->y1}; + //row.SetValue(512); + ds1.Insert( row1.GetAsDataElement() ); + // w.SetCheckFileMetaInformation( true ); + gdcm::Attribute<0x0028,0x0011> col1 = {image->x1}; + ds1.Insert( col1.GetAsDataElement() ); + gdcm::Attribute<0x0028,0x0008> Number_Of_Frames1 = {tccp->numresolutions}; + ds1.Insert( Number_Of_Frames1.GetAsDataElement() ); + + gdcm::Attribute<0x0028,0x0100> ata = {8}; + ds1.Insert( ata.GetAsDataElement() ); + + gdcm::Attribute<0x0028,0x0002> atb = {image->numcomps}; + ds1.Insert( atb.GetAsDataElement() ); + + gdcm::Attribute<0x0028,0x0101> atc = {8}; + ds1.Insert( atc.GetAsDataElement() ); + + gdcm::Attribute<0x0028,0x0102> atd = {7}; + ds1.Insert( atd.GetAsDataElement() ); + + theStreamWriter.SetFile(file1); + + gdcm::DataElement des( gdcm::Tag(0x0048,0x0200) ); + des.SetVR(gdcm::VR::SQ); + //des.SetVR(gdcm::VM::VM1); + des.SetValue(*sq); + des.SetVLToUndefined(); + + ds1.Insert(des); + + + if (!theStreamWriter.WriteImageInformation()){ + std::cerr << "unable to write image information" << std::endl; + return 1; //the CanWrite function should prevent getting here, else, + //that's a test failure + } + + } + + theStreamWriter.SetFile(file); + + if (!theStreamWriter.CanWriteFile()){ + delete [] raw; + std::cout << "Not able to write"; + return 0;//this means that the file was unwritable, period. + //very similar to a ReadImageInformation failure + } +else + std::cout<<"\nabletoread"; + + // Important to write here + std::vector extent = gdcm::ImageHelper::GetDimensionsValue(file); + + unsigned short xmax = extent[0]; + unsigned short ymax = extent[1]; + unsigned short theChunkSize = 4; + unsigned short ychunk = extent[1]/theChunkSize; //go in chunk sizes of theChunkSize + unsigned short zmax = extent[2]; + std::cout << "\n"<numcomps<<"\n"; + + + if (xmax == 0 || ymax == 0) + { + std::cerr << "Image has no size, unable to write zero-sized image." << std::endl; + return 0; + } + + + int z, y, nexty; + unsigned long prevLen = 0; //when going through the char buffer, make sure to grab + //the bytes sequentially. So, store how far you got in the buffer with each iteration. + for (z = 0; z < zmax; ++z){ + for (y = 0; y < ymax; y += ychunk){ + nexty = y + ychunk; + if (nexty > ymax) nexty = ymax; + theStreamWriter.DefinePixelExtent(0, xmax, y, nexty, z, z+1); + unsigned long len = theStreamWriter.DefineProperBufferLength(); + std::cout << "\n" < row = {256}; + //row.SetValue(512); + ds.Insert( row.GetAsDataElement() ); + // w.SetCheckFileMetaInformation( true ); + gdcm::Attribute<0x0028,0x0011> col = {256}; + ds.Insert( col.GetAsDataElement() ); + + gdcm::Attribute<0x0028,0x0008> Number_Of_Frames = {1}; + ds.Insert( Number_Of_Frames.GetAsDataElement() ); + + gdcm::Attribute<0x0028,0x0100> at = {8}; + ds.Insert( at.GetAsDataElement() ); + + gdcm::Attribute<0x0028,0x0002> at1 = {3}; //bits per pixel + ds.Insert( at1.GetAsDataElement() ); + + gdcm::Attribute<0x0028,0x0101> at2 = {8}; + ds.Insert( at2.GetAsDataElement() ); + + gdcm::Attribute<0x0028,0x0102> at3 = {7}; + ds.Insert( at3.GetAsDataElement() ); + + gdcm::Attribute<0x0028,0x006> at4 = {0}; + ds.Insert( at4.GetAsDataElement() ); + + gdcm::Attribute<0x0028,0x0103> at5 = {0}; + ds.Insert( at5.GetAsDataElement() ); + + //de.SetTag(gdcm::Tag(0x7fe0,0x0010)); + //ds.Insert(de); + + gdcm::StreamImageWriter theStreamWriter; +gdcm::SmartPointer sq = new gdcm::SequenceOfItems(); + sq->SetLengthToUndefined(); + + uint16_t row1 = 256; + uint16_t col1 = 256; + //std::cout << row; + + gdcm::Element el2; + el2.SetValue(1); + gdcm::DataElement rfn = el2.GetAsDataElement(); //rfn ---> reference frame number + rfn.SetTag( gdcm::Tag(0x0008,0x1160) ); + + gdcm::Element el; + el.SetValue(1,0); + el.SetValue(1,1); + gdcm::DataElement ulr = el.GetAsDataElement(); //ulr --> upper left col/row + ulr.SetTag( gdcm::Tag(0x0048,0x0201) ); + + gdcm::Element el1; + el1.SetValue(col1,0); + el1.SetValue(row1,1); + gdcm::DataElement brr = el1.GetAsDataElement(); + brr.SetTag( gdcm::Tag(0x0048,0x0202) ); //brr --> bottom right col/row + + gdcm::Item it; + gdcm::DataSet &nds = it.GetNestedDataSet(); + nds.Insert( rfn ); + nds.Insert(ulr); + nds.Insert(brr); + + sq->AddItem(it); + + gdcm::DataElement des( gdcm::Tag(0x0048,0x0200) ); + des.SetVR(gdcm::VR::SQ); + des.SetValue(*sq); + des.SetVLToUndefined(); + + ds.Insert(des); + + + theStreamWriter.SetFile(file); + + std::ofstream of; + of.open( "output.dcm", std::ios::out | std::ios::binary ); + theStreamWriter.SetStream(of); + + +if (!theStreamWriter.CanWriteFile()){ + delete [] buffer; + std::cout << "Not able to write"; + return 0;//this means that the file was unwritable, period. + //very similar to a ReadImageInformation failure + } +else + std::cout<<"\nabletoread"; + +if (!theStreamWriter.WriteImageInformation()){ + std::cerr << "unable to write image information" << std::endl; + delete [] buffer; + return 1; //the CanWrite function should prevent getting here, else, + //that's a test failure + } + + std::vector extent = + gdcm::ImageHelper::GetDimensionsValue(file); + + unsigned short xmax = extent[0]; + unsigned short ymax = extent[1]; + unsigned short theChunkSize = 1; + unsigned short ychunk = extent[1]/theChunkSize; //go in chunk sizes of theChunkSize + unsigned short zmax = extent[2]; + + std::cout << xmax << ymax << zmax; + + if (xmax == 0 || ymax == 0) + { + std::cerr << "Image has no size, unable to write zero-sized image." << std::endl; + return 0; + } + + int z, y, nexty; + unsigned long prevLen = 0; //when going through the char buffer, make sure to grab + //the bytes sequentially. So, store how far you got in the buffer with each iteration. + for (z = 0; z < zmax; ++z){ + for (y = 0; y < ymax; y += ychunk){ + nexty = y + ychunk; + if (nexty > ymax) nexty = ymax; + theStreamWriter.DefinePixelExtent(0, xmax, y, nexty, z, z+1); + unsigned long len = theStreamWriter.DefineProperBufferLength(); + std::cout << "\n" < BuggyJ2Kvvvua-fixed2-j2k.dcm + +/* + * This program attemps to fix a broken J2K/DICOM: + * It contains 2 bugs: + * 1. The first 8 bytes seems to be random bytes: remove them + * 2. YCC is set to 1, while image is grayscale need to set it back to 0 + * + * Ref: + * It's a software from http://rentgenprom.ru/ , shipped with universal digital radiographic units + * "ProScan-2000". The Ukrainian manufacturer developed own digital radiographic unit and it is + * compatible with software from "ProScan-2000". + */ +int main(int argc, char *argv[]) +{ + if( argc < 3 ) + { + std::cerr << argv[0] << " input.dcm output.dcm" << std::endl; + return 1; + } + const char *filename = argv[1]; + const char *outfilename = argv[2]; + gdcm::Reader reader; + reader.SetFileName( filename ); + if( !reader.Read() ) + { + return 1; + } + + gdcm::File &file = reader.GetFile(); + const gdcm::DataElement &pixeldata0 = file.GetDataSet().GetDataElement( gdcm::Tag(0x7fe0,0x0010) ); + const gdcm::SequenceOfFragments *sqf = pixeldata0.GetSequenceOfFragments(); + if( !sqf ) + { + return 1; + } + const gdcm::Fragment &frag0 = sqf->GetFragment(0); + + const gdcm::ByteValue *bv = frag0.GetByteValue(); + const char *ptr = bv->GetPointer(); + size_t len = bv->GetLength(); + + const char sig[] = "\x00\x00\x00\x00\x6A\x70\x32\x63"; + if( memcmp(ptr, sig, sizeof(sig)) != 0 ) + { + std::cerr << "magic random signature not found" << std::endl; + return 1; + } + + // Apparently the flag to enable a color transform on 3 color components is set in + // the COD marker. (YCC is byte[6] in the COD marker) + // we need to disable this flag; + const char *cod_marker = ptr + 0x35; /* 0x2d + 0x8 */ // FIXME + if( cod_marker[0] == (char)0xff && cod_marker[1] == 0x52 ) + { + // found start of COD + if( cod_marker[6+2] == 1 ) + { + // Change in place: + *((char*)cod_marker + 6+2) = 0; + // Prepare a new DataElement: + gdcm::DataElement pixeldata( gdcm::Tag(0x7fe0,0x0010) ); + pixeldata.SetVR( gdcm::VR::OB ); + gdcm::SmartPointer sq = new gdcm::SequenceOfFragments; + + gdcm::Fragment frag; + // remove 8 first bytes: + frag.SetByteValue( ptr + 8, (uint32_t)(len - 8) ); + sq->AddFragment( frag ); + pixeldata.SetValue( *sq ); + file.GetDataSet().Replace( pixeldata ); + } + else + { + return 1; + } + } + else + { + std::cerr << "COD not found" << (int)cod_marker[0] << std::endl; + return 1; + } + + gdcm::Writer writer; + writer.SetFile( reader.GetFile() ); + writer.SetFileName( outfilename ); + writer.CheckFileMetaInformationOff(); + if( !writer.Write() ) + { + std::cerr << "Could not write" << std::endl; + } + + // paranoid check: + gdcm::ImageReader ireader; + ireader.SetFileName( outfilename ); + if( !ireader.Read() ) + { + std::cerr << "file written is still not valid, please report" << std::endl; + return 1; + } + + + return 0; +} diff --git a/gdcm/Examples/Cxx/FixJAIBugJPEGLS.cxx b/gdcm/Examples/Cxx/FixJAIBugJPEGLS.cxx new file mode 100644 index 0000000..53ac8e6 --- /dev/null +++ b/gdcm/Examples/Cxx/FixJAIBugJPEGLS.cxx @@ -0,0 +1,224 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmReader.h" +#include "gdcmWriter.h" +#include "gdcmImageReader.h" + +#include + +#include "gdcm_charls.h" + +/* + * This small example should show how one can handle the famous JAI-JPEGLS bug + * It will take in as invalid DICOM/JAI-JPEG-LS and write out as Explicit Little + * Endian. One can use `gdcmconv --jpegls` to recompress properly + * + * References: + * http://charls.codeplex.com/discussions/230307?ProjectName=charls + * http://charls.codeplex.com/workitem/7297 + * http://www.dcm4che.org/jira/browse/DCM-442 + * http://www.dcm4che.org/jira/browse/DCMEE-1144 + * http://java.net/jira/browse/JAI_IMAGEIO_CORE-183 + * + * Explanation of the issue: + * + * Seems, the error is in the calculation of the default values for thresholds T1, + * T2, T3, in particular min(MAXVAL, 4095) is not applied in + * + * FACTOR = (min(MAXVAL, 4095) + 128)/256 + * + * as specified in http://www.itu.int/rec/T-REC-T.87-199806-I/en . + * + */ +int main(int argc, char *argv[]) +{ + if( argc < 3 ) + { + std::cerr << argv[0] << " input.dcm output.dcm" << std::endl; + return 1; + } + const char *filename = argv[1]; + const char *outfilename = argv[2]; + gdcm::FileMetaInformation::SetSourceApplicationEntityTitle( "FixJAIBugJPEGLS" ); + + gdcm::ImageReader reader; + reader.SetFileName( filename ); + if( !reader.Read() ) + { + return 1; + } + + gdcm::Image &image = reader.GetImage(); + //unsigned long len = image.GetBufferLength(); + const gdcm::DataElement & in = + reader.GetFile().GetDataSet().GetDataElement( gdcm::Tag(0x7fe0,0x0010) ); + const gdcm::SequenceOfFragments *sf = in.GetSequenceOfFragments(); + if( !sf ) + { + std::cerr << "No pixel data (or not encapsulated)" << std::endl; + return 1; + } + const unsigned int *dims = image.GetDimensions(); + if ( sf->GetNumberOfFragments() != dims[2] ) + { + std::cerr << "Unsupported" << std::endl; + return 1; + } + +// unsigned long totalLen = sf->ComputeByteLength(); + std::vector rgbyteOutall; + for(unsigned int i = 0; i < sf->GetNumberOfFragments(); ++i) + { + const gdcm::Fragment &frag = sf->GetFragment(i); + if( frag.IsEmpty() ) return 1; + const gdcm::ByteValue *bv = frag.GetByteValue(); + if( !bv ) return 1; + unsigned long totalLen = bv->GetLength(); + + std::vector vbuffer; + vbuffer.resize( totalLen ); + char *buffer = &vbuffer[0]; + bv->GetBuffer(buffer, totalLen); + const BYTE* pbyteCompressed0 = (const BYTE*)buffer; + while( totalLen > 0 && pbyteCompressed0[totalLen-1] != 0xd9 ) + { + totalLen--; + } + + JlsParameters metadata; + if (JpegLsReadHeader(buffer, totalLen, &metadata) != OK) + { + std::cerr << "Cant parse jpegls" << std::endl; + return false; + } + + std::cout << metadata.width << std::endl; + std::cout << metadata.height << std::endl; + std::cout << metadata.bitspersample << std::endl; + + gdcm::PixelFormat const & pf = image.GetPixelFormat(); + std::cout << pf << std::endl; + + // http://charls.codeplex.com/discussions/230307?ProjectName=charls + unsigned char marker_lse_13[] = { + 0xFF, 0xF8, 0x00, 0x0D, + 0x01, + 0x1F, 0xFF, + 0x00, 0x22, // T1 = 34 + 0x00, 0x83, // T2 = 131 + 0x02, 0x24, // T3 = 548 + 0x00, 0x40 + }; + + unsigned char marker_lse_14[] = { + 0xFF, 0xF8, 0x00, 0x0D, + 0x01, + 0x3F, 0xFF, + 0x00, 0x42, // T1 = 66 + 0x01, 0x03, // T2 = 259 + 0x04, 0x44, // T3 = 1092 + 0x00, 0x40 + }; + + unsigned char marker_lse_15[] = { + 0xFF, 0xF8, 0x00, 0x0D, + 0x01, + 0x7F, 0xFF, + 0x00, 0x82, // T1 = 130 + 0x02, 0x03, // T2 = 515 + 0x08, 0x84, // T3 = 2180 + 0x00, 0x40 + }; + + unsigned char marker_lse_16[] = { + 0xFF, 0xF8, 0x00, 0x0D, + 0x01, + 0xFF, 0xFF, + 0x01, 0x02, // T1 = 258 + 0x04, 0x03, // T2 = 1027 + 0x11, 0x04, // T3 = 4356 + 0x00, 0x40 + }; + + const unsigned char *marker_lse = NULL; + switch( metadata.bitspersample ) + { + case 13: + marker_lse = marker_lse_13; + break; + case 14: + marker_lse = marker_lse_14; + break; + case 15: + marker_lse = marker_lse_15; + break; + case 16: + marker_lse = marker_lse_16; + break; + } + if( !marker_lse ) + { + std::cerr << "Cant handle: " << metadata.bitspersample << std::endl; + return 1; + } + + // FIXME: One should recompute the value for 0x0F + vbuffer.insert (vbuffer.begin() + 0x0F, marker_lse, marker_lse+15); + +#if 0 + std::ofstream of( "/tmp/d.jls", std::ios::binary ); + of.write( &vbuffer[0], vbuffer.size() ); + of.close(); +#endif + + const char *pbyteCompressed = &vbuffer[0]; + size_t cbyteCompressed = vbuffer.size(); // updated legnth + + JlsParameters params; + JpegLsReadHeader(pbyteCompressed, cbyteCompressed, ¶ms); + + std::vector rgbyteOut; + //rgbyteOut.resize( image.GetBufferLength() ); + rgbyteOut.resize(params.height *params.width * ((params.bitspersample + 7) + / 8) * params.components); + + JLS_ERROR result = + JpegLsDecode(&rgbyteOut[0], rgbyteOut.size(), pbyteCompressed, cbyteCompressed, ¶ms ); + if (result != OK) + { + std::cerr << "Could not patch JAI-JPEGLS" << std::endl; + return 1; + } + rgbyteOutall.insert( rgbyteOutall.end(), rgbyteOut.begin(), rgbyteOut.end() ); + } + + gdcm::DataElement pixeldata( gdcm::Tag(0x7fe0,0x0010) ); + pixeldata.SetVR( gdcm::VR::OW ); + pixeldata.SetByteValue( (char*)&rgbyteOutall[0], (uint32_t)rgbyteOutall.size() ); + + + // Add the pixel data element + reader.GetFile().GetDataSet().Replace( pixeldata ); + reader.GetFile().GetHeader().SetDataSetTransferSyntax( + gdcm::TransferSyntax::ExplicitVRLittleEndian); + + gdcm::Writer writer; + writer.SetFileName( outfilename ); + writer.SetFile( reader.GetFile() ); + writer.Write(); + + std::cout << "Success !" << std::endl; + + return 0; +} diff --git a/gdcm/Examples/Cxx/GenAllVR.cxx b/gdcm/Examples/Cxx/GenAllVR.cxx new file mode 100644 index 0000000..cff6021 --- /dev/null +++ b/gdcm/Examples/Cxx/GenAllVR.cxx @@ -0,0 +1,169 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmReader.h" +#include "gdcmGlobal.h" +#include "gdcmDummyValueGenerator.h" +#include "gdcmMediaStorage.h" +#include "gdcmWriter.h" +#include "gdcmItem.h" +#include "gdcmImageReader.h" +#include "gdcmSequenceOfItems.h" +#include "gdcmFile.h" +#include "gdcmTag.h" +#include "gdcmDict.h" +#include "gdcmDictEntry.h" +#include "gdcmDicts.h" +#include "gdcmTransferSyntax.h" +#include "gdcmUIDGenerator.h" +#include "gdcmFileExplicitFilter.h" + +#include +#include + + +gdcm::Tag FindTagFromVR(gdcm::Dict const &dict, gdcm::VR const &vr) +{ + using gdcm::Dict; + Dict::ConstIterator beg = dict.Begin(); + Dict::ConstIterator end = dict.End(); + Dict::ConstIterator it; + for( it = beg; it != end; ++it) + { + const gdcm::Tag &t = it->first; + const gdcm::DictEntry &de = it->second; + const gdcm::VR &vr_de = de.GetVR(); + if( vr == vr_de && !de.GetRetired() && t.GetGroup() >= 0x8 ) + { + return t; + } + } + return gdcm::Tag(0xffff,0xffff); +} + +struct rnd_gen { + rnd_gen(char const* r = "abcdefghijklmnopqrstuvwxyz0123456789") + : range(r), len(std::strlen(r)) { } + + char operator ()() const { + return range[static_cast(std::rand() * (1.0 / ((double)RAND_MAX + 1.0 )) * (double)len)]; + } +private: + char const* range; + std::size_t len; +}; + +/* + */ +int main(int argc, char *argv[]) +{ + if( argc < 2 ) + { + std::cerr << argv[0] << " output.dcm" << std::endl; + return 1; + } + const char *outfilename = argv[1]; + static const gdcm::Global &g = gdcm::Global::GetInstance(); + static const gdcm::Dicts &dicts = g.GetDicts(); + static const gdcm::Dict &pubdict = dicts.GetPublicDict(); + using gdcm::VR; + using gdcm::Tag; + + gdcm::Writer w; + + gdcm::File &f = w.GetFile(); + gdcm::DataSet &ds = f.GetDataSet(); + + gdcm::FileExplicitFilter fef; + //fef.SetChangePrivateTags( true ); + fef.SetFile( w.GetFile() ); + if( !fef.Change() ) + { + std::cerr << "Failed to change" << std::endl; + return 1; + } + + gdcm::SmartPointer sq = new gdcm::SequenceOfItems(); + sq->SetLengthToUndefined(); + +// gdcm::DummyValueGenerator dvg; + + const std::size_t len = 10; + char ss[len+1]; + ss[len] = '\0'; + + const char owner_str[] = "GDCM CONFORMANCE TESTS"; + gdcm::DataElement owner( gdcm::Tag(0x4d4d, 0x10) ); + owner.SetByteValue(owner_str, (uint32_t)strlen(owner_str)); + owner.SetVR( gdcm::VR::LO ); + + // Create an item + gdcm::Item it; + it.SetVLToUndefined(); + gdcm::DataSet &nds = it.GetNestedDataSet(); + // nds.Insert(owner); + // nds.Insert(de); + + // Insert sequence into data set + gdcm::DataElement des( gdcm::Tag(0x4d4d,0x1001) ); + des.SetVR(gdcm::VR::SQ); + des.SetValue(*sq); + des.SetVLToUndefined(); + + ds.Insert(owner); + ds.Insert(des); + + // avoid INVALID = 0 + for(int i = 1; i < 27; ++i) + { + VR vr = (VR::VRType)(1 << i); + Tag t = FindTagFromVR( pubdict, vr ); + if( vr != VR::UN && vr != VR::SQ ) + { + assert( t != Tag(0xffff,0xffff) ); + gdcm::DataElement de( t ); + std::generate_n(ss, len, rnd_gen()); + de.SetVR( vr ); + de.SetByteValue( ss, (uint32_t)std::strlen( ss ) ); + nds.Insert( de ); + } + } + sq->AddItem(it); + + // Make sure to override any UID stuff + gdcm::UIDGenerator uid; + gdcm::DataElement de( Tag(0x8,0x18) ); // SOP Instance UID + de.SetVR( VR::UI ); + const char *u = uid.Generate(); + de.SetByteValue( u, (uint32_t)strlen(u) ); + ds.Insert( de ); + + de.SetTag( Tag(0x8,0x16) ); // SOP Class UID + de.SetVR( VR::UI ); + gdcm::MediaStorage ms( gdcm::MediaStorage::RawDataStorage ); + de.SetByteValue( ms.GetString(), (uint32_t)strlen(ms.GetString())); + ds.Insert( de ); + + gdcm::FileMetaInformation &fmi = f.GetHeader(); + //fmi.SetDataSetTransferSyntax( gdcm::TransferSyntax::ImplicitVRLittleEndian ); + fmi.SetDataSetTransferSyntax( gdcm::TransferSyntax::ExplicitVRLittleEndian ); + + w.SetCheckFileMetaInformation( true ); + w.SetFileName( outfilename ); + if (!w.Write() ) + { + return 1; + } + + return 0; +} diff --git a/gdcm/Examples/Cxx/GenFakeIdentifyFile.cxx b/gdcm/Examples/Cxx/GenFakeIdentifyFile.cxx new file mode 100644 index 0000000..daed698 --- /dev/null +++ b/gdcm/Examples/Cxx/GenFakeIdentifyFile.cxx @@ -0,0 +1,183 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmReader.h" +#include "gdcmGlobal.h" +#include "gdcmDummyValueGenerator.h" +#include "gdcmMediaStorage.h" +#include "gdcmWriter.h" +#include "gdcmItem.h" +#include "gdcmImageReader.h" +#include "gdcmSequenceOfItems.h" +#include "gdcmAttribute.h" +#include "gdcmFile.h" +#include "gdcmTag.h" +#include "gdcmDict.h" +#include "gdcmDictEntry.h" +#include "gdcmDicts.h" +#include "gdcmTransferSyntax.h" +#include "gdcmUIDGenerator.h" +#include "gdcmAnonymizer.h" + +#include +#include + +gdcm::DataElement CreateFakeElement(gdcm::Tag const &tag, bool toremove) +{ + static const gdcm::Global &g = gdcm::Global::GetInstance(); + static const gdcm::Dicts &dicts = g.GetDicts(); + static const gdcm::Dict &pubdict = dicts.GetPublicDict(); + static size_t countglobal = 0; + static std::vector balcptags = + gdcm::Anonymizer::GetBasicApplicationLevelConfidentialityProfileAttributes(); + size_t count = countglobal % balcptags.size(); + + const gdcm::DictEntry &dictentry = pubdict.GetDictEntry(tag); + + gdcm::DataElement de; + de.SetTag( tag ); + using gdcm::VR; + const VR &vr = dictentry.GetVR(); + //if( vr != VR::INVALID ) + if( vr.IsDual() ) + { + if( vr == VR::US_SS ) + { + de.SetVR( VR::US ); + } + else if( vr == VR::US_SS_OW ) + { + de.SetVR( VR::OW ); + } + else if( vr == VR::OB_OW ) + { + de.SetVR( VR::OB ); + } + } + else + { + de.SetVR( vr ); + } + const char str[] = "BasicApplicationLevelConfidentialityProfileAttributes"; + const char safe[] = "This is safe to keep"; + if( de.GetVR() != VR::SQ ) + { + if( toremove ) + de.SetByteValue( str, (uint32_t)strlen(str) ); + else + de.SetByteValue( safe, (uint32_t)strlen(safe) ); + } + else + { + // Create an item + gdcm::Item it; + it.SetVLToUndefined(); + gdcm::DataSet &nds = it.GetNestedDataSet(); + // Insert sequence into data set + assert(de.GetVR() == gdcm::VR::SQ ); + gdcm::SmartPointer sq = new gdcm::SequenceOfItems(); + sq->SetLengthToUndefined(); + de.SetValue(*sq); + de.SetVLToUndefined(); + //ds.Insert(de); + + if( !toremove ) + { + nds.Insert( CreateFakeElement( balcptags[count], true ) ); + countglobal++; + } + else + { + gdcm::Attribute<0x0008,0x0000> at1 = { 0 }; // This element has no reason to be 'anonymized'... + nds.Insert( at1.GetAsDataElement() ); + gdcm::Attribute<0x000a,0x0000> at2 = { 0 }; + nds.Insert( at2.GetAsDataElement() ); + } + sq->AddItem(it); + } + return de; +} + +/* + */ +int main(int argc, char *argv[]) +{ + if( argc < 2 ) + { + std::cerr << argv[0] << " output.dcm" << std::endl; + return 1; + } + using gdcm::Tag; + using gdcm::VR; + const char *outfilename = argv[1]; + + std::vector balcptags = + gdcm::Anonymizer::GetBasicApplicationLevelConfidentialityProfileAttributes(); + + gdcm::Writer w; + gdcm::File &f = w.GetFile(); + gdcm::DataSet &ds = f.GetDataSet(); + + // Add attribute that need to be anonymized: + std::vector::const_iterator it = balcptags.begin(); + for(; it != balcptags.end(); ++it) + { + ds.Insert( CreateFakeElement( *it, true ) ); + } + + // Add attribute that do NOT need to be anonymized: + static const gdcm::Global &g = gdcm::Global::GetInstance(); + static const gdcm::Dicts &dicts = g.GetDicts(); + static const gdcm::Dict &pubdict = dicts.GetPublicDict(); + + using gdcm::Dict; + Dict::ConstIterator dictit = pubdict.Begin(); + for(; dictit != pubdict.End(); ++dictit) + { + const gdcm::Tag &dicttag = dictit->first; + if( dicttag == Tag(0x6e65,0x6146) ) break; + //const gdcm::DictEntry &dictentry = dictit->second; + ds.Insert( CreateFakeElement( dicttag, false ) ); + } + ds.Remove( gdcm::Tag(0x400,0x500) ); + ds.Remove( gdcm::Tag(0x12,0x62) ); + ds.Remove( gdcm::Tag(0x12,0x63) ); + + // Make sure to override any UID stuff + gdcm::UIDGenerator uid; + gdcm::DataElement de( Tag(0x8,0x18) ); // SOP Instance UID + de.SetVR( VR::UI ); + const char *u = uid.Generate(); + de.SetByteValue( u, (uint32_t)strlen(u) ); + //ds.Insert( de ); + ds.Replace( de ); + + de.SetTag( Tag(0x8,0x16) ); // SOP Class UID + de.SetVR( VR::UI ); + gdcm::MediaStorage ms( gdcm::MediaStorage::RawDataStorage ); + de.SetByteValue( ms.GetString(), (uint32_t)strlen(ms.GetString())); + ds.Replace( de ); // replace ! + + gdcm::FileMetaInformation &fmi = f.GetHeader(); + //fmi.SetDataSetTransferSyntax( gdcm::TransferSyntax::ImplicitVRLittleEndian ); + fmi.SetDataSetTransferSyntax( gdcm::TransferSyntax::ExplicitVRLittleEndian ); + + w.SetCheckFileMetaInformation( true ); + w.SetFileName( outfilename ); + if (!w.Write() ) + { + return 1; + } + + return 0; +} diff --git a/gdcm/Examples/Cxx/GenFakeImage.cxx b/gdcm/Examples/Cxx/GenFakeImage.cxx new file mode 100644 index 0000000..705e153 --- /dev/null +++ b/gdcm/Examples/Cxx/GenFakeImage.cxx @@ -0,0 +1,126 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmImage.h" +#include "gdcmImageWriter.h" +#include "gdcmFileDerivation.h" +#include "gdcmUIDGenerator.h" +//#include "gdcmImageChangePhotometricInterpretation.h" + +/* + * This example shows two things: + * 1. How to create an image ex-nihilo + * 2. How to use the gdcm.FileDerivation filter. This filter is meant to create "DERIVED" image + * object. FileDerivation has a simple API where you can reference *all* the input image that have been + * used to generate the image. The API also allows user to specify the purpose of reference (see CID 7202, + * PS 3.16 - 2008), and the image derivation type (CID 7203, PS 3.16 - 2008). + */ +int main(int, char *[]) +{ + // Step 1: Fake Image + gdcm::SmartPointer im = new gdcm::Image; + + char * buffer = new char[ 256 * 256 * 3]; + char * p = buffer; + int b = 128; + //int ybr[3]; + int ybr2[3]; + //int rgb[3]; + + for(int r = 0; r < 256; ++r) + for(int g = 0; g < 256; ++g) + //for(int b = 0; b < 256; ++b) + { + //rgb[0] = r; + //rgb[1] = g; + //rgb[1] = 128; + //rgb[2] = b; + //ybr[0] = r; + //ybr[1] = g; + //ybr[1] = 128; + //ybr[2] = b; + + ybr2[0] = r; + ybr2[1] = g; + ybr2[1] = 128; + ybr2[2] = b; + //gdcm::ImageChangePhotometricInterpretation::YBR2RGB(rgb, ybr); + //gdcm::ImageChangePhotometricInterpretation::RGB2YBR(ybr2, rgb); + *p++ = (char)ybr2[0]; + *p++ = (char)ybr2[1]; + *p++ = (char)ybr2[2]; + } + + im->SetNumberOfDimensions( 2 ); + im->SetDimension(0, 256 ); + im->SetDimension(1, 256 ); + + im->GetPixelFormat().SetSamplesPerPixel(3); + //im->SetPhotometricInterpretation( gdcm::PhotometricInterpretation::RGB ); + im->SetPhotometricInterpretation( gdcm::PhotometricInterpretation::YBR_FULL ); + + unsigned long l = im->GetBufferLength(); + if( l != 256 * 256 * 3 ) + { + return 1; + } + gdcm::DataElement pixeldata( gdcm::Tag(0x7fe0,0x0010) ); + pixeldata.SetByteValue( buffer, (uint32_t)l ); + delete[] buffer; + im->SetDataElement( pixeldata ); + + gdcm::UIDGenerator uid; // helper for uid generation + + gdcm::SmartPointer file = new gdcm::File; // empty file + + // Step 2: DERIVED object + gdcm::FileDerivation fd; + // For the pupose of this execise we will pretend that this image is referencing + // two source image (we need to generate fake UID for that). + const char ReferencedSOPClassUID[] = "1.2.840.10008.5.1.4.1.1.7"; // Secondary Capture + fd.AddReference( ReferencedSOPClassUID, uid.Generate() ); + fd.AddReference( ReferencedSOPClassUID, uid.Generate() ); + + // Again for the purpose of the exercise we will pretend that the image is a + // multiplanar reformat (MPR): + // CID 7202 Source Image Purposes of Reference + // {"DCM",121322,"Source image for image processing operation"}, + fd.SetPurposeOfReferenceCodeSequenceCodeValue( 121322 ); + // CID 7203 Image Derivation + // { "DCM",113072,"Multiplanar reformatting" }, + fd.SetDerivationCodeSequenceCodeValue( 113072 ); + fd.SetFile( *file ); + // If all Code Value are ok the filter will execute properly + if( !fd.Derive() ) + { + std::cerr << "Sorry could not derive using input info" << std::endl; + return 1; + } + + // We pass both : + // 1. the fake generated image + // 2. the 'DERIVED' dataset object + // to the writer. + gdcm::ImageWriter w; + w.SetImage( *im ); + w.SetFile( fd.GetFile() ); + + // Set the filename: + w.SetFileName( "ybr2.dcm" ); + if( !w.Write() ) + { + return 1; + } + + return 0; +} diff --git a/gdcm/Examples/Cxx/GenLongSeqs.cxx b/gdcm/Examples/Cxx/GenLongSeqs.cxx new file mode 100644 index 0000000..01cc93a --- /dev/null +++ b/gdcm/Examples/Cxx/GenLongSeqs.cxx @@ -0,0 +1,101 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmReader.h" +#include "gdcmWriter.h" +#include "gdcmItem.h" +#include "gdcmImageReader.h" +#include "gdcmSequenceOfItems.h" +#include "gdcmFile.h" +#include "gdcmTag.h" + +/* + * This example is used to generate the file: + * + * + * There is a flaw in the DICOM design were it is assumed that Sequence can be + * either represented as undefined length or defined length. This should work + * in most case, but the undefined length is a little more general and can + * store sequence of items that a defined length cannot. + * We need to make sure that we can store numerous Item in a SQ + * + * Warning: do not try to compute the group length elements ! + * Warning: You may need a 64bits machine for this example to work. + */ +int main(int argc, char *argv[]) +{ + if( argc < 3 ) + { + std::cerr << argv[0] << " input.dcm output.dcm" << std::endl; + return 1; + } + const char *filename = argv[1]; + const char *outfilename = argv[2]; + gdcm::Reader reader; + reader.SetFileName( filename ); + if( !reader.Read() ) + { + return 1; + } + + gdcm::File &file = reader.GetFile(); + gdcm::DataSet &ds = file.GetDataSet(); + + // Create a Sequence + gdcm::SmartPointer sq = new gdcm::SequenceOfItems(); + sq->SetLengthToUndefined(); + + const char owner_str[] = "GDCM CONFORMANCE TESTS"; + gdcm::DataElement owner( gdcm::Tag(0x4d4d, 0x10) ); + owner.SetByteValue(owner_str, (uint32_t)strlen(owner_str)); + owner.SetVR( gdcm::VR::LO ); + + size_t nitems = 1000; + nitems += std::numeric_limits::max(); + for(unsigned int idx = 0; idx < nitems; ++idx) + { + // Create a dataelement + //gdcm::DataElement de( gdcm::Tag(0x4d4d, 0x1002) ); + //de.SetByteValue(ptr, ptr_len); + //de.SetVR( gdcm::VR::OB ); + + // Create an item + gdcm::Item it; + it.SetVLToUndefined(); + //gdcm::DataSet &nds = it.GetNestedDataSet(); + //nds.Insert(owner); + //nds.Insert(de); + + sq->AddItem(it); + } + + // Insert sequence into data set + gdcm::DataElement des( gdcm::Tag(0x4d4d,0x1001) ); + des.SetVR(gdcm::VR::SQ); + des.SetValue(*sq); + des.SetVLToUndefined(); + + ds.Insert(owner); + ds.Insert(des); + + gdcm::Writer w; + w.SetFile( file ); + //w.SetCheckFileMetaInformation( true ); + w.SetFileName( outfilename ); + if (!w.Write() ) + { + return 1; + } + + return 0; +} diff --git a/gdcm/Examples/Cxx/GenSeqs.cxx b/gdcm/Examples/Cxx/GenSeqs.cxx new file mode 100644 index 0000000..97ff083 --- /dev/null +++ b/gdcm/Examples/Cxx/GenSeqs.cxx @@ -0,0 +1,107 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmReader.h" +#include "gdcmWriter.h" +#include "gdcmItem.h" +#include "gdcmImageReader.h" +#include "gdcmSequenceOfItems.h" +#include "gdcmFile.h" +#include "gdcmTag.h" + +/* + * This example is used to generate the file: + * + * gdcmConformanceTests/SequenceWithUndefinedLengthNotConvertibleToDefinedLength.dcm + * + * There is a flaw in the DICOM design were it is assumed that Sequence can be + * either represented as undefined length or defined length. This should work + * in most case, but the undefined length is a little more general and can + * store sequence of items that a defined length cannot. + * Deflated syntax was used in this case since this synthetic example can be + * nicely compressed using this transfer syntax. + * + * Warning: do not try to compute the group length elements ! + * Warning: You may need a 64bits machine for this example to work. + */ +int main(int argc, char *argv[]) +{ + if( argc < 3 ) + { + std::cerr << argv[0] << " input.dcm output.dcm" << std::endl; + return 1; + } + const char *filename = argv[1]; + const char *outfilename = argv[2]; + gdcm::Reader reader; + reader.SetFileName( filename ); + if( !reader.Read() ) + { + return 1; + } + + gdcm::File &file = reader.GetFile(); + gdcm::DataSet &ds = file.GetDataSet(); + + //const unsigned int nitems = 1000; + const unsigned int ptr_len = 42; /*94967296 / nitems; */ + //assert( ptr_len == 42949672 ); + char *ptr = new char[ptr_len]; + memset(ptr,0,ptr_len); + + // Create a Sequence + gdcm::SmartPointer sq = new gdcm::SequenceOfItems(); + sq->SetLengthToUndefined(); + + const char owner_str[] = "GDCM CONFORMANCE TESTS"; + gdcm::DataElement owner( gdcm::Tag(0x4d4d, 0x10) ); + owner.SetByteValue(owner_str, (uint32_t)strlen(owner_str)); + owner.SetVR( gdcm::VR::LO ); + + for(unsigned int idx = 0; idx < 10/* nitems*/; ++idx) + { + // Create a dataelement + gdcm::DataElement de( gdcm::Tag(0x4d4d, 0x1002) ); + de.SetByteValue(ptr, ptr_len); + de.SetVR( gdcm::VR::OB ); + + // Create an item + gdcm::Item it; + it.SetVLToUndefined(); + gdcm::DataSet &nds = it.GetNestedDataSet(); + nds.Insert(owner); + nds.Insert(de); + + sq->AddItem(it); + } + + // Insert sequence into data set + gdcm::DataElement des( gdcm::Tag(0x4d4d,0x1001) ); + des.SetVR(gdcm::VR::SQ); + des.SetValue(*sq); + des.SetVLToUndefined(); + + ds.Insert(owner); + ds.Insert(des); + + gdcm::Writer w; + w.SetFile( file ); + //w.SetCheckFileMetaInformation( true ); + w.SetFileName( outfilename ); + if (!w.Write() ) + { + return 1; + } + + return 0; +} diff --git a/gdcm/Examples/Cxx/GenerateStandardSOPClasses.cxx b/gdcm/Examples/Cxx/GenerateStandardSOPClasses.cxx new file mode 100644 index 0000000..4bdf469 --- /dev/null +++ b/gdcm/Examples/Cxx/GenerateStandardSOPClasses.cxx @@ -0,0 +1,68 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + */ + +#include "gdcmDefs.h" +#include "gdcmUIDs.h" +#include "gdcmGlobal.h" +#include "gdcmMediaStorage.h" +#include "gdcmSOPClassUIDToIOD.h" + +int main(int , char *[]) +{ + using gdcm::MediaStorage; + gdcm::Global& g = gdcm::Global::GetInstance(); + if( !g.LoadResourcesFiles() ) + { + std::cerr << "Could not LoadResourcesFiles" << std::endl; + return 1; + } + + const gdcm::Defs &defs = g.GetDefs(); + + int ret = 0; + + //std::cout << "Table B.5-1 STANDARD SOP CLASSES" << std::endl; + std::cout << "SOP Class Name,SOP Class UID,IOD Specification (defined in PS 3.3)" << std::endl; + + + gdcm::MediaStorage::MSType mst; + for ( mst = gdcm::MediaStorage::MediaStorageDirectoryStorage; mst < gdcm::MediaStorage::MS_END; + mst = (gdcm::MediaStorage::MSType)(mst + 1) ) + { + const char *iod = defs.GetIODNameFromMediaStorage(mst); + gdcm::UIDs uid; + uid.SetFromUID( gdcm::MediaStorage::GetMSString(mst) /*mst.GetString()*/ ); + if( iod ) + { + const char *iod_ref = gdcm::SOPClassUIDToIOD::GetIOD(uid); + if( iod_ref ) + { + std::string iod_ref_str = iod_ref; + //iod_ref_str += " IOD Modules"; + //if( iod_ref_str != iod ) + { + //std::cout << "UID: " << uid << " "; + std::cout << '"' << uid.GetName() << '"' <<"," << '"' < +#include + +int main(int argc, char *argv[]) +{ + if( argc < 3 ) + { + std::cerr << argv[0] << " input.dcm output.jpg" << std::endl; + return 1; + } + const char *filename = argv[1]; + const char *outfilename = argv[2]; + + gdcm::ImageReader reader; + reader.SetFileName( filename ); + if( !reader.Read() ) + { + std::cerr << "Could not read: " << filename << std::endl; + return 1; + } + + // The output of gdcm::Reader is a gdcm::File + const gdcm::File &file = reader.GetFile(); + const gdcm::Image &image = reader.GetImage(); + + const gdcm::TransferSyntax &ts = file.GetHeader().GetDataSetTransferSyntax(); + + if( ts != gdcm::TransferSyntax::JPEGLosslessProcess14 && ts != gdcm::TransferSyntax::JPEGLosslessProcess14_1 ) + { + std::cerr << "Input is not a lossless JPEG" << std::endl; + return 1; + } + + // the dataset is the the set of element we are interested in: + const gdcm::DataSet &ds = file.GetDataSet(); + + const gdcm::Tag rawTag(0x7fe0, 0x0010); // Default to Pixel Data + const gdcm::DataElement& pdde = ds.GetDataElement( rawTag ); + const gdcm::SequenceOfFragments *sf = pdde.GetSequenceOfFragments(); + if( sf ) + { + std::ofstream output(outfilename, std::ios::binary); + sf->WriteBuffer(output); + } + else + { + std::cerr << "Error" << std::endl; + return 1; + } + + gdcm::JPEGCodec jpeg; + std::ifstream is(outfilename, std::ios::binary); + gdcm::PixelFormat pf ( gdcm::PixelFormat::UINT8 ); // let's pretend it's a 8bits jpeg + jpeg.SetPixelFormat( pf ); + gdcm::TransferSyntax ts_jpg; + bool b = jpeg.GetHeaderInfo( is, ts_jpg ); + if( !b ) + { + return 1; + } + + //jpeg.Print( std::cout ); + if( jpeg.GetPixelFormat().GetBitsAllocated() != image.GetPixelFormat().GetBitsAllocated() + || jpeg.GetPixelFormat().GetBitsStored() != image.GetPixelFormat().GetBitsStored() ) + { + std::cerr << "There is a mismatch in between DICOM declared Pixel Format and Sample Precision used in the JPEG stream" << std::endl; + return 0; + } + + std::cout << jpeg.GetPixelFormat() << std::endl; + std::cout << image.GetPixelFormat() << std::endl; + + return 1; +} diff --git a/gdcm/Examples/Cxx/GetSequenceUltrasound.cxx b/gdcm/Examples/Cxx/GetSequenceUltrasound.cxx new file mode 100644 index 0000000..463d1a5 --- /dev/null +++ b/gdcm/Examples/Cxx/GetSequenceUltrasound.cxx @@ -0,0 +1,130 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmReader.h" +#include "gdcmAttribute.h" + +bool Region ( char* nomefile, unsigned int* X_min, unsigned int* Y_min, unsigned int* X_max, unsigned int* Y_max ); + +int main(int argc, char* argv[] ) +{ + // Controllo del numero di argomenti introdotti da riga di comando + if( argc < 2 ) + { + std::cerr << "Usage: " << std::endl; + std::cerr << argv[0] << " inputImageFile " << std::endl; + return EXIT_FAILURE; + } + + + unsigned int x_min = 1; + unsigned int y_min = 1; + unsigned int x_max = 1; + unsigned int y_max = 1; + + if( Region ( argv[1], &x_min, &y_min, &x_max, &y_max ) ) + { + std::cout << "x_min = " << x_min << std::endl; + std::cout << "y_min = " << y_min << std::endl; + std::cout << "x_max = " << x_max << std::endl; + std::cout << "y_max = " << y_max << std::endl; + } + + else + { + std::cout << "no\n"; + } + +} + +bool Region ( char* nomefile, unsigned int* X_min, unsigned int* Y_min, unsigned int* X_max, unsigned int* Y_max ) +{ + gdcm::Reader reader; + reader.SetFileName( nomefile ); + if( !reader.Read() ) + { + std::cerr << "Could not read: " << nomefile << std::endl; + return false; + } + + gdcm::File &file = reader.GetFile(); + gdcm::DataSet &ds = file.GetDataSet(); + + gdcm::Tag tsqur(0x0018,0x6011); + if( !ds.FindDataElement( tsqur ) ) + { + return false; + } + + const gdcm::DataElement &squr= ds.GetDataElement( tsqur ); + //std::cout << squr << std::endl; + const gdcm::SequenceOfItems *sqi = squr.GetValueAsSQ(); + if( !sqi || !sqi->GetNumberOfItems() ) + { + return false; + } + //std::cout << sqi << std::endl; + + const gdcm::Item & item = sqi->GetItem(1); + //std::cout << item << std::endl; + const gdcm::DataSet& nestedds = item.GetNestedDataSet(); + //std::cout << nestedds << std::endl; + + gdcm::Tag tX0(0x0018,0x6018); + gdcm::Tag tY0(0x0018,0x601a); + gdcm::Tag tX1(0x0018,0x601c); + gdcm::Tag tY1(0x0018,0x601e); + + if( (!nestedds.FindDataElement( tX0 ))||(!nestedds.FindDataElement( tY0 ))||(!nestedds.FindDataElement( tX1 ))||(!nestedds.FindDataElement( tY1 )) ) + { + return false; + } + + const gdcm::DataElement& deX0 = nestedds.GetDataElement( tX0 ); + const gdcm::DataElement& deY0 = nestedds.GetDataElement( tY0 ); + const gdcm::DataElement& deX1 = nestedds.GetDataElement( tX1 ); + const gdcm::DataElement& deY1 = nestedds.GetDataElement( tY1 ); + //std::cout << deX0 << std::endl << deY0 << std::endl << deX1 << std::endl << deY1 << std::endl; + + //const gdcm::ByteValue *bvX0 = deX0.GetByteValue(); + //const gdcm::ByteValue *bvY0 = deY0.GetByteValue(); + //const gdcm::ByteValue *bvX1 = deX1.GetByteValue(); + //const gdcm::ByteValue *bvY1 = deY1.GetByteValue(); + //std::cout << bvX0 << std::endl << bvY0 << std::endl << bvX1 << std::endl << bvY1 << std::endl; + + gdcm::Attribute<0x0018,0x6018> atX0; + gdcm::Attribute<0x0018,0x601a> atY0; + gdcm::Attribute<0x0018,0x601c> atX1; + gdcm::Attribute<0x0018,0x601e> atY1; + atX0.SetFromDataElement( deX0 ); + atY0.SetFromDataElement( deY0 ); + atX1.SetFromDataElement( deX1 ); + atY1.SetFromDataElement( deY1 ); + uint32_t X0 = atX0.GetValue(); + uint32_t Y0 = atY0.GetValue(); + uint32_t X1 = atX1.GetValue(); + uint32_t Y1 = atY1.GetValue(); + std::cout << X0 << std::endl << Y0 << std::endl << X1 << std::endl << Y1 << std::endl; + + *X_min = static_cast(X0); + *Y_min = static_cast(Y0); + *X_max = static_cast(X1); + *Y_max = static_cast(Y1); + + //std::cout << "X_min = " << *X_min << std::endl; + //std::cout << "Y_min = " << *Y_min << std::endl; + //std::cout << "X_max = " << *X_max << std::endl; + //std::cout << "Y_max = " << *Y_max << std::endl; + + return true; +} diff --git a/gdcm/Examples/Cxx/GetSubSequenceData.cxx b/gdcm/Examples/Cxx/GetSubSequenceData.cxx new file mode 100644 index 0000000..2e424c8 --- /dev/null +++ b/gdcm/Examples/Cxx/GetSubSequenceData.cxx @@ -0,0 +1,201 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmReader.h" +#include "gdcmImage.h" +#include "gdcmImageWriter.h" +#include "gdcmDataElement.h" +#include "gdcmPrivateTag.h" +#include "gdcmUIDGenerator.h" + +#include +#include + +#include + +/* + * This example will extract the Movie from the private group of + * GEMS_Ultrasound_MovieGroup_001 See Attribute + * (7fe1,60,GEMS_Ultrasound_MovieGroup_001) + * + * The output file will be stored in `outvid.dcm` as + * MultiframeGrayscaleByteSecondaryCaptureImageStorage + */ +int main(int argc, char *argv[]) +{ + if( argc < 2 ) return 1; + using namespace gdcm; + const char *filename = argv[1]; + gdcm::Reader reader; + reader.SetFileName( filename ); + reader.Read(); + + gdcm::File &file = reader.GetFile(); + gdcm::DataSet &ds = file.GetDataSet(); + const PrivateTag tseq(0x7fe1,0x1,"GEMS_Ultrasound_MovieGroup_001"); + + if( !ds.FindDataElement( tseq ) ) return 1; + const DataElement& seq = ds.GetDataElement( tseq ); + + SmartPointer sqi = seq.GetValueAsSQ(); + assert( sqi->GetNumberOfItems() == 1 ); + Item &item = sqi->GetItem(1); + DataSet &subds = item.GetNestedDataSet(); + + const PrivateTag tseq1(0x7fe1,0x10,"GEMS_Ultrasound_MovieGroup_001"); + + if( !subds.FindDataElement( tseq1 ) ) return 1; + const DataElement& seq1 = subds.GetDataElement( tseq1 ); + + SmartPointer sqi2 = seq1.GetValueAsSQ(); + //int n = sqi2->GetNumberOfItems(); + int index = 1; + Item &item2 = sqi2->GetItem(index); + DataSet &subds2 = item2.GetNestedDataSet(); + + const PrivateTag tseq2(0x7fe1,0x20,"GEMS_Ultrasound_MovieGroup_001"); + + if( !subds2.FindDataElement( tseq2 ) ) return 1; + const DataElement& seq2 = subds2.GetDataElement( tseq2 ); + +// std::cout << seq2 << std::endl; + + SmartPointer sqi3 = seq2.GetValueAsSQ(); + size_t ni3 = sqi3->GetNumberOfItems(); (void)ni3; + assert( sqi3->GetNumberOfItems() >= 1 ); + Item &item3 = sqi3->GetItem(1); + DataSet &subds3 = item3.GetNestedDataSet(); + + const PrivateTag tseq6(0x7fe1,0x26,"GEMS_Ultrasound_MovieGroup_001"); + if( !subds3.FindDataElement( tseq6 ) ) return 1; + const DataElement& seq6 = subds3.GetDataElement( tseq6 ); + SmartPointer sqi6 = seq6.GetValueAsSQ(); + size_t ni6= sqi6->GetNumberOfItems(); + assert( sqi6->GetNumberOfItems() >= 1 ); + const PrivateTag tseq7(0x7fe1,0x86,"GEMS_Ultrasound_MovieGroup_001"); + int dimx = 0, dimy = 0; + for( size_t i6 = 1; i6 <= ni6; ++i6 ) + { + Item &item6 = sqi6->GetItem(i6); + DataSet &subds6 = item6.GetNestedDataSet(); + + if( subds6.FindDataElement( tseq7 ) ) + { + Element el; + el.SetFromDataElement( subds6.GetDataElement( tseq7 ) ); + std::cout << "El= " << el.GetValue() << std::endl; + dimx = el.GetValue(0); + dimy = el.GetValue(1); + } + } + + const PrivateTag tseq3(0x7fe1,0x36,"GEMS_Ultrasound_MovieGroup_001"); + if( !subds3.FindDataElement( tseq3 ) ) return 1; + const DataElement& seq3 = subds3.GetDataElement( tseq3 ); + +// std::cout << seq3 << std::endl; + + SmartPointer sqi4 = seq3.GetValueAsSQ(); + size_t ni4= sqi4->GetNumberOfItems(); + assert( sqi4->GetNumberOfItems() >= 1 ); + const PrivateTag tseq8(0x7fe1,0x37,"GEMS_Ultrasound_MovieGroup_001"); + const PrivateTag tseq4(0x7fe1,0x43,"GEMS_Ultrasound_MovieGroup_001"); + const PrivateTag tseq5(0x7fe1,0x60,"GEMS_Ultrasound_MovieGroup_001"); + + std::vector imbuffer; + int dimz = 0; + for( size_t i4 = 1; i4 <= ni4; ++i4 ) + { + Item &item4 = sqi4->GetItem(i4); + DataSet &subds4 = item4.GetNestedDataSet(); + + if( !subds4.FindDataElement( tseq8 ) ) return 1; + const DataElement& de8 = subds4.GetDataElement( tseq8 ); + Element ldimz; + ldimz.SetFromDataElement( de8 ); + dimz += ldimz.GetValue(); + if( !subds4.FindDataElement( tseq4 ) ) return 1; + const DataElement& seq4 = subds4.GetDataElement( tseq4 ); + if( !subds4.FindDataElement( tseq5 ) ) return 1; + const DataElement& seq5 = subds4.GetDataElement( tseq5 ); + + // std::cout << seq4 << std::endl; + // std::cout << seq5 << std::endl; + + const ByteValue *bv4 = seq4.GetByteValue(); + (void)bv4; +#if 0 + { + std::ofstream out( "/tmp/mo4", std::ios::binary ); + out.write( bv4->GetPointer(), bv4->GetLength()); + out.close(); + } +#endif + const ByteValue *bv5 = seq5.GetByteValue(); +#if 0 + { + std::ofstream out( "/tmp/mo5", std::ios::binary ); + out.write( bv5->GetPointer(), bv5->GetLength()); + out.close(); + } +#endif + + std::cout << bv5->GetLength() << std::endl; + imbuffer.insert( imbuffer.begin(), bv5->GetPointer(), bv5->GetPointer() + bv5->GetLength() ); + } + DataElement fakedata; + fakedata.SetByteValue( &imbuffer[0], (uint32_t)imbuffer.size() ); + + + gdcm::SmartPointer im = new gdcm::Image; + im->SetNumberOfDimensions( 3 ); + + im->SetDimension(0, dimx ); + im->SetDimension(1, dimy ); + im->SetDimension(2, dimz ); + size_t l1 = imbuffer.size(); + (void)l1; + size_t l2 = im->GetBufferLength(); + (void)l2; + assert( im->GetBufferLength() == imbuffer.size() ); + im->SetPhotometricInterpretation( gdcm::PhotometricInterpretation::MONOCHROME2 ); + + im->SetDataElement( fakedata ); + + gdcm::ImageWriter w; + w.SetImage( *im ); + DataSet &dataset = w.GetFile().GetDataSet(); + + gdcm::UIDGenerator uid; + gdcm::DataElement de( Tag(0x8,0x18) ); // SOP Instance UID + de.SetVR( VR::UI ); + const char *u = uid.Generate(); + de.SetByteValue( u, (uint32_t)strlen(u) ); + //ds.Insert( de ); + dataset.Replace( de ); + + de.SetTag( Tag(0x8,0x16) ); // SOP Class UID + de.SetVR( VR::UI ); + gdcm::MediaStorage ms( + gdcm::MediaStorage::MultiframeGrayscaleByteSecondaryCaptureImageStorage ); + de.SetByteValue( ms.GetString(), (uint32_t)strlen(ms.GetString())); + dataset.Replace( de ); // replace ! + + w.SetFileName( "outvid.dcm" ); + if( !w.Write() ) + { + return 1; + } + + return 0; +} diff --git a/gdcm/Examples/Cxx/HelloVizWorld.cxx b/gdcm/Examples/Cxx/HelloVizWorld.cxx new file mode 100644 index 0000000..00bae1d --- /dev/null +++ b/gdcm/Examples/Cxx/HelloVizWorld.cxx @@ -0,0 +1,84 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + * Basic example for dealing with a DICOM file that contains an Image + * (read: Pixel Data element) + */ + +#include "gdcmImageReader.h" +#include "gdcmImageWriter.h" +#include "gdcmImage.h" +#include "gdcmPhotometricInterpretation.h" + +#include + +int main(int argc, char *argv[]) +{ + if( argc < 3 ) + { + std::cerr << argv[0] << " input.dcm output.dcm" << std::endl; + return 1; + } + const char *filename = argv[1]; + const char *outfilename = argv[2]; + + // Instanciate the image reader: + gdcm::ImageReader reader; + reader.SetFileName( filename ); + if( !reader.Read() ) + { + std::cerr << "Could not read: " << filename << std::endl; + return 1; + } + // If we reach here, we know for sure 2 things: + // 1. It is a valid DICOM + // 2. And it contains an Image ! + + // The output of superclass gdcm::Reader is a gdcm::File + //gdcm::File &file = reader.GetFile(); + + // The other output of gdcm::ImageReader is a gdcm::Image + const gdcm::Image &image = reader.GetImage(); + + // Let's get some property from the image: + unsigned int ndim = image.GetNumberOfDimensions(); + // Dimensions of the image: + const unsigned int *dims = image.GetDimensions(); + // Origin + const double *origin = image.GetOrigin(); + const gdcm::PhotometricInterpretation &pi = image.GetPhotometricInterpretation(); + for(unsigned int i = 0; i < ndim; ++i) + { + std::cout << "Dim(" << i << "): " << dims[i] << std::endl; + } + for(unsigned int i = 0; i < ndim; ++i) + { + std::cout << "Origin(" << i << "): " << origin[i] << std::endl; + } + std::cout << "PhotometricInterpretation: " << pi << std::endl; + + // Write the modified DataSet back to disk + gdcm::ImageWriter writer; + writer.SetImage( image ); + writer.SetFileName( outfilename ); + //writer.SetFile( file ); // We purposely NOT copy the meta information from the input + // file, and instead only pass the image + if( !writer.Write() ) + { + std::cerr << "Could not write: " << outfilename << std::endl; + return 1; + } + + return 0; +} diff --git a/gdcm/Examples/Cxx/HelloWorld.cxx b/gdcm/Examples/Cxx/HelloWorld.cxx new file mode 100644 index 0000000..45b2d09 --- /dev/null +++ b/gdcm/Examples/Cxx/HelloWorld.cxx @@ -0,0 +1,78 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + * This example is ... guess what this is for :) + */ + +#include "gdcmReader.h" +#include "gdcmWriter.h" +#include "gdcmAttribute.h" + +#include + +int main(int argc, char *argv[]) +{ + if( argc < 3 ) + { + std::cerr << argv[0] << " input.dcm output.dcm" << std::endl; + return 1; + } + const char *filename = argv[1]; + const char *outfilename = argv[2]; + + // Instanciate the reader: + gdcm::Reader reader; + reader.SetFileName( filename ); + if( !reader.Read() ) + { + std::cerr << "Could not read: " << filename << std::endl; + return 1; + } + + // If we reach here, we know for sure only 1 thing: + // It is a valid DICOM file (potentially an old ACR-NEMA 1.0/2.0 file) + // (Maybe, it's NOT a Dicom image -could be a DICOMDIR, a RTSTRUCT, etc-) + + // The output of gdcm::Reader is a gdcm::File + gdcm::File &file = reader.GetFile(); + + // the dataset is the the set of element we are interested in: + gdcm::DataSet &ds = file.GetDataSet(); + + // Contruct a static(*) type for Image Comments : + gdcm::Attribute<0x0020,0x4000> imagecomments; + imagecomments.SetValue( "Hello, World !" ); + + // Now replace the Image Comments from the dataset with our: + ds.Replace( imagecomments.GetAsDataElement() ); + + // Write the modified DataSet back to disk + gdcm::Writer writer; + writer.CheckFileMetaInformationOff(); // Do not attempt to reconstruct the file meta to preserve the file + // as close to the original as possible. + writer.SetFileName( outfilename ); + writer.SetFile( file ); + if( !writer.Write() ) + { + std::cerr << "Could not write: " << outfilename << std::endl; + return 1; + } + + return 0; +} + +/* + * (*) static type, means that extra DICOM information VR & VM are computed at compilation time. + * The compiler is deducing those values from the template arguments of the class. + */ diff --git a/gdcm/Examples/Cxx/LargeVRDSExplicit.cxx b/gdcm/Examples/Cxx/LargeVRDSExplicit.cxx new file mode 100644 index 0000000..f5cf645 --- /dev/null +++ b/gdcm/Examples/Cxx/LargeVRDSExplicit.cxx @@ -0,0 +1,186 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmReader.h" +#include "gdcmWriter.h" +#include "gdcmAttribute.h" +#include "gdcmFileExplicitFilter.h" +#include "gdcmSequenceOfItems.h" + +/** + * This example is used to generate the file: + * + * gdcmConformanceTests/RTStruct_VRDSAsVRUN.dcm + * + * This is an advanced example. Its goal is to explain one dark corner of DICOM PS 3.10 + * file format. The idea is that when writting an Attribute in an Explicit Transfer + * Syntax one, cannot always use V:DS for writing a VR:DS attribute since dong so + * would imply using a VL:16bits. + * This example shows that converting from Implicit to Explicit should preserver VR:UN + * when the VL is larger than 16bits limit. + * + * Usage: + * ./LargeVRDSExplicit gdcmDataExtra/gdcmNonImageData/RT/RTStruct.dcm out.dcm + */ + +bool interpolate(const double * pts, size_t npts, std::vector &out ) +{ + out.clear(); + for(size_t i = 0; i < 2*npts; ++i ) + { + const size_t j = i / 2; + if( i % 2 ) + { + if( j != npts - 1 ) + { + assert( 3*j+5 < 3*npts ); + const double midpointx = (pts[3*j+0] + pts[3*j+3]) / 2; + const double midpointy = (pts[3*j+1] + pts[3*j+4]) / 2; + const double midpointz = (pts[3*j+2] + pts[3*j+5]) / 2; + out.push_back( midpointx ); + out.push_back( midpointy ); + out.push_back( midpointz ); + } + } + else + { + assert( j < npts ); + out.push_back( pts[3*j+0] ); + out.push_back( pts[3*j+1] ); + out.push_back( pts[3*j+2] ); + } + } + assert( out.size() == 2 * npts * 3 - 3 ); + return true; +} + +int main(int argc, char *argv[]) +{ + if( argc < 3 ) + { + std::cerr << argv[0] << " input.dcm output.dcm" << std::endl; + return 1; + } + const char *filename = argv[1]; + const char *outfilename = argv[2]; + gdcm::Reader reader; + reader.SetFileName( filename ); + if( !reader.Read() ) + { + return 1; + } + + gdcm::File &file = reader.GetFile(); + gdcm::DataSet &ds = file.GetDataSet(); + + gdcm::FileExplicitFilter fef; + //fef.SetChangePrivateTags( changeprivatetags ); + fef.SetFile( reader.GetFile() ); + if( !fef.Change() ) + { + std::cerr << "Failed to change: " << filename << std::endl; + return 1; + } + + // (3006,0039) SQ (Sequence with undefined length #=4) # u/l, 1 ROIContourSequence + gdcm::Tag tag(0x3006,0x0039); + + const gdcm::DataElement &roicsq = ds.GetDataElement( tag ); + gdcm::SmartPointer sqi = roicsq.GetValueAsSQ(); + //sqi->SetNumberOfItems( 1 ); + const gdcm::Item & item = sqi->GetItem(1); // Item start at #1 + const gdcm::DataSet& nestedds = item.GetNestedDataSet(); + + gdcm::Tag tcsq(0x3006,0x0040); + if( !nestedds.FindDataElement( tcsq ) ) + { + return 0; + } + const gdcm::DataElement& csq = nestedds.GetDataElement( tcsq ); + gdcm::SmartPointer sqi2 = csq.GetValueAsSQ(); + if( !sqi2 || !sqi2->GetNumberOfItems() ) + { + return 0; + } + //unsigned int nitems = sqi2->GetNumberOfItems(); + gdcm::Item & item2 = sqi2->GetItem(1); // Item start at #1 + + gdcm::DataSet& nestedds2 = item2.GetNestedDataSet(); + //item2.SetVLToUndefined(); + //std::cout << nestedds2 << std::endl; + // (3006,0050) DS [43.57636\65.52504\-10.0\46.043102\62.564945\-10.0\49.126537\60.714... # 398,48 ContourData + gdcm::Tag tcontourdata(0x3006,0x0050); + const gdcm::DataElement & contourdata = nestedds2.GetDataElement( tcontourdata ); + //std::cout << contourdata << std::endl; + + //const gdcm::ByteValue *bv = contourdata.GetByteValue(); + gdcm::Attribute<0x3006,0x0046> ncontourpoints; + ncontourpoints.Set( nestedds2 ); + + gdcm::Attribute<0x3006,0x0050> at; + at.SetFromDataElement( contourdata ); + const double* pts = at.GetValues(); + unsigned int npts = at.GetNumberOfValues() / 3; + + std::vector out( pts, pts + npts * 3 ); + std::vector out2; + + //const unsigned int niter = 7; + const unsigned int niter = 8; + for( unsigned int i = 0; i < niter; ++i) + { + //bool b = + interpolate(&out[0], out.size() / 3, out2); + //const double *pout = &out[0]; + out = out2; + out2.clear(); + } + assert( out.size() % 3 == 0 ); + + gdcm::Attribute<0x3006,0x0050> at_interpolate; + at_interpolate.SetNumberOfValues( (unsigned int)(out.size() / 3) ); + at_interpolate.SetValues( &out[0], (uint32_t)out.size() ); + + ncontourpoints.SetValue( at_interpolate.GetNumberOfValues() / 3 ); + nestedds2.Replace( at_interpolate.GetAsDataElement() ); + nestedds2.Replace( ncontourpoints.GetAsDataElement() ); + + //assert(0); + + // Let's take item one and subdivide it + + gdcm::TransferSyntax ts = gdcm::TransferSyntax::ImplicitVRLittleEndian; + ts = gdcm::TransferSyntax::ExplicitVRLittleEndian; + + gdcm::FileMetaInformation &fmi = file.GetHeader(); + const char *tsuid = gdcm::TransferSyntax::GetTSString( ts ); + // const char * is ok since padding is \0 anyway... + gdcm::DataElement de( gdcm::Tag(0x0002,0x0010) ); + de.SetByteValue( tsuid, (uint32_t)strlen(tsuid) ); + de.SetVR( gdcm::Attribute<0x0002, 0x0010>::GetVR() ); + fmi.Replace( de ); + fmi.Remove( gdcm::Tag(0x0002,0x0012) ); // will be regenerated + fmi.Remove( gdcm::Tag(0x0002,0x0013) ); // ' ' ' + fmi.SetDataSetTransferSyntax(ts); + + + gdcm::Writer w; + w.SetFile( file ); + w.SetFileName( outfilename ); + if (!w.Write() ) + { + return 1; + } + + return 0; +} diff --git a/gdcm/Examples/Cxx/MergeTwoFiles.cxx b/gdcm/Examples/Cxx/MergeTwoFiles.cxx new file mode 100644 index 0000000..567d345 --- /dev/null +++ b/gdcm/Examples/Cxx/MergeTwoFiles.cxx @@ -0,0 +1,86 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + * This example will show how one can read in two DICOM files, use the dataset + * from file1 and use image from file2 to save it in a 3rd file. + * + * Eg: + * MergeTwoFiles gdcmData/012345.002.050.dcm gdcmData/test.acr merge.dcm + */ + +#include "gdcmReader.h" +#include "gdcmImageReader.h" +#include "gdcmImageWriter.h" +#include "gdcmWriter.h" +#include "gdcmDataSet.h" +#include "gdcmAttribute.h" + +int main(int argc, char *argv[]) +{ + if( argc < 3 ) + { + return 1; + } + const char *file1 = argv[1]; + const char *file2 = argv[2]; + const char *file3 = argv[3]; + + // Read file1 + gdcm::ImageReader reader1; + reader1.SetFileName( file1 ); + if( !reader1.Read() ) + { + return 1; + } + + // Read file2 + gdcm::ImageReader reader2; + reader2.SetFileName( file2 ); + if( !reader2.Read() ) + { + return 1; + } + + // Ok now let's take the DataSet from file1 and the Image from file2 + // Warning: if file2 is -for example- a Secondary Capture Storage, then it has no + // Image Orientation (Patient) thus any Image Orientation (Patient) from file1 + // will be discarded... + + // let's be fancy. In case reader2 contains explicit, but reader1 is implicit + // we would rather see an implicit output + if( reader1.GetFile().GetHeader().GetDataSetTransferSyntax() == gdcm::TransferSyntax::ImplicitVRLittleEndian ) + { + reader2.GetImage().SetTransferSyntax( gdcm::TransferSyntax::ImplicitVRLittleEndian ); + } + + gdcm::ImageWriter writer; + writer.SetFileName( file3 ); + writer.SetFile( reader1.GetFile() ); + // ImageWriter will always use all of gdcm::Image information an override anything wrong from + // reader1.GetFile(), including the Transfer Syntax + writer.SetImage( reader2.GetImage() ); + + gdcm::DataSet &ds = reader1.GetFile().GetDataSet(); + + // Make sure that SOPInstanceUID are different + // Simply removing it is sufficient as gdcm::ImageWriter will generate one by default + // if not found. + ds.Remove( gdcm::Tag(0x0008,0x0018) ); + if( !writer.Write() ) + { + return 1; + } + + return 0; +} diff --git a/gdcm/Examples/Cxx/MrProtocol.cxx b/gdcm/Examples/Cxx/MrProtocol.cxx new file mode 100644 index 0000000..5f0a313 --- /dev/null +++ b/gdcm/Examples/Cxx/MrProtocol.cxx @@ -0,0 +1,544 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + * + */ + +/* +28 - 'MrProtocol' VM 1, VR UN, SyngoDT 0, NoOfItems 6, Data '### ASCCONV BEGIN ### +ulVersion = 0xbee332 +tSequenceFileName = "%SiemensSeq%\fl_fq_shphs" +tProtocolName = "flash+AF8-100+AF8-through-plane+AF8-V" +tReferenceImage0 = "1.3.12.2.1107.5.2.9.16041.30000007062106100181200004658" +tReferenceImage1 = "1.3.12.2.1107.5.2.9.16041.30000007062106100181200004635" +tReferenceImage2 = "1.3.12.2.1107.5.2.9.16041.30000007062106100181200004683" +ucScanRegionPosValid = 0x1 +sProtConsistencyInfo.tBaselineString = "N4_VB11A_LATEST_20031004" +sProtConsistencyInfo.flNominalB0 = 1.494 +sProtConsistencyInfo.flGMax = 22 +sProtConsistencyInfo.flRiseTime = 10 +sGRADSPEC.sEddyCompensationX.aflAmplitude[0] = 0.0141111 +sGRADSPEC.sEddyCompensationX.aflAmplitude[1] = 0.057038 +sGRADSPEC.sEddyCompensationX.aflAmplitude[2] = -0.00986504 +sGRADSPEC.sEddyCompensationX.aflAmplitude[3] = 0.00247627 +sGRADSPEC.sEddyCompensationX.aflAmplitude[4] = 0.0026377 +sGRADSPEC.sEddyCompensationX.aflTimeConstant[0] = 1.53826 +sGRADSPEC.sEddyCompensationX.aflTimeConstant[1] = 0.746617 +sGRADSPEC.sEddyCompensationX.aflTimeConstant[2] = 0.339236 +sGRADSPEC.sEddyCompensationX.aflTimeConstant[3] = 0.0309809 +sGRADSPEC.sEddyCompensationX.aflTimeConstant[4] = 0.00067694 +sGRADSPEC.sEddyCompensationY.aflAmplitude[0] = 0.0156411 +sGRADSPEC.sEddyCompensationY.aflAmplitude[1] = 0.0440623 +sGRADSPEC.sEddyCompensationY.aflAmplitude[2] = -0.00782663 +sGRADSPEC.sEddyCompensationY.aflAmplitude[3] = 0.00186828 +sGRADSPEC.sEddyCompensationY.aflAmplitude[4] = 0.00154504 +sGRADSPEC.sEddyCompensationY.aflTimeConstant[0] = 1.47145 +sGRADSPEC.sEddyCompensationY.aflTimeConstant[1] = 0.750538 +sGRADSPEC.sEddyCompensationY.aflTimeConstant[2] = 0.339397 +sGRADSPEC.sEddyCompensationY.aflTimeConstant[3] = 0.0312962 +sGRADSPEC.sEddyCompensationY.aflTimeConstant[4] = 0.000895133 +sGRADSPEC.sEddyCompensationZ.aflAmplitude[0] = 0.00618504 +sGRADSPEC.sEddyCompensationZ.aflAmplitude[1] = 0.00313121 +sGRADSPEC.sEddyCompensationZ.aflAmplitude[2] = 0.000289346 +sGRADSPEC.sEddyCompensationZ.aflAmplitude[3] = -0.00019677 +sGRADSPEC.sEddyCompensationZ.aflAmplitude[4] = 7.66445e-005 +sGRADSPEC.sEddyCompensationZ.aflTimeConstant[0] = 3.37462 +sGRADSPEC.sEddyCompensationZ.aflTimeConstant[1] = 0.999351 +sGRADSPEC.sEddyCompensationZ.aflTimeConstant[2] = 0.0174646 +sGRADSPEC.sEddyCompensationZ.aflTimeConstant[3] = 0.0110094 +sGRADSPEC.sEddyCompensationZ.aflTimeConstant[4] = 0.00199922 +sGRADSPEC.bEddyCompensationValid = 1 +sGRADSPEC.sB0CompensationX.aflAmplitude[0] = 0.307474 +sGRADSPEC.sB0CompensationX.aflAmplitude[1] = 0.029337 +sGRADSPEC.sB0CompensationX.aflAmplitude[2] = -0.187118 +sGRADSPEC.sB0CompensationX.aflTimeConstant[0] = 0.98583 +sGRADSPEC.sB0CompensationX.aflTimeConstant[1] = 0.0308443 +sGRADSPEC.sB0CompensationX.aflTimeConstant[2] = 0.000466792 +sGRADSPEC.sB0CompensationY.aflAmplitude[0] = 0.365257 +sGRADSPEC.sB0CompensationY.aflAmplitude[1] = -0.318647 +sGRADSPEC.sB0CompensationY.aflAmplitude[2] = -0.0118978 +sGRADSPEC.sB0CompensationY.aflTimeConstant[0] = 0.61535 +sGRADSPEC.sB0CompensationY.aflTimeConstant[1] = 0.488831 +sGRADSPEC.sB0CompensationY.aflTimeConstant[2] = 0.00199991 +sGRADSPEC.sB0CompensationZ.aflAmplitude[0] = -0.44647 +sGRADSPEC.sB0CompensationZ.aflAmplitude[1] = -0.0455154 +sGRADSPEC.sB0CompensationZ.aflAmplitude[2] = -0.0304901 +sGRADSPEC.sB0CompensationZ.aflTimeConstant[0] = 0.959231 +sGRADSPEC.sB0CompensationZ.aflTimeConstant[1] = 0.0720189 +sGRADSPEC.sB0CompensationZ.aflTimeConstant[2] = 0.00190141 +sGRADSPEC.bB0CompensationValid = 1 +sGRADSPEC.sCrossTermCompensationXY.aflAmplitude[0] = 0.00105046 +sGRADSPEC.sCrossTermCompensationXY.aflTimeConstant[0] = 0.842014 +sGRADSPEC.sCrossTermCompensationXZ.aflAmplitude[0] = -0.00150189 +sGRADSPEC.sCrossTermCompensationXZ.aflTimeConstant[0] = 0.736169 +sGRADSPEC.sCrossTermCompensationYX.aflAmplitude[0] = -5.5278e-005 +sGRADSPEC.sCrossTermCompensationYX.aflTimeConstant[0] = 0.228697 +sGRADSPEC.sCrossTermCompensationYZ.aflAmplitude[0] = 0.000307999 +sGRADSPEC.sCrossTermCompensationYZ.aflTimeConstant[0] = 1.19431 +sGRADSPEC.sCrossTermCompensationZX.aflAmplitude[0] = -0.000286868 +sGRADSPEC.sCrossTermCompensationZX.aflTimeConstant[0] = 0.665979 +sGRADSPEC.sCrossTermCompensationZY.aflAmplitude[0] = 0.000355175 +sGRADSPEC.sCrossTermCompensationZY.aflTimeConstant[0] = 0.844189 +sGRADSPEC.bCrossTermCompensationValid = 1 +sGRADSPEC.lOffsetX = 25 +sGRADSPEC.lOffsetY = 84 +sGRADSPEC.lOffsetZ = 47 +sGRADSPEC.bOffsetValid = 1 +sGRADSPEC.lDelayX = 12 +sGRADSPEC.lDelayY = 11 +sGRADSPEC.lDelayZ = 9 +sGRADSPEC.bDelayValid = 1 +sGRADSPEC.flSensitivityX = 0.000264087 +sGRADSPEC.flSensitivityY = 0.000272009 +sGRADSPEC.flSensitivityZ = 0.000272677 +sGRADSPEC.bSensitivityValid = 1 +sGRADSPEC.alShimCurrent[0] = 183 +sGRADSPEC.alShimCurrent[1] = -25 +sGRADSPEC.alShimCurrent[2] = -85 +sGRADSPEC.alShimCurrent[3] = 378 +sGRADSPEC.alShimCurrent[4] = 82 +sGRADSPEC.bShimCurrentValid = 1 +sGRADSPEC.ucMode = 0x2 +sTXSPEC.asNucleusInfo[0].tNucleus = "1H" +sTXSPEC.asNucleusInfo[0].lFrequency = 63684693 +sTXSPEC.asNucleusInfo[0].bFrequencyValid = 1 +sTXSPEC.asNucleusInfo[0].flReferenceAmplitude = 359.734 +sTXSPEC.asNucleusInfo[0].bReferenceAmplitudeValid = 1 +sTXSPEC.asNucleusInfo[0].flAmplitudeCorrection = 1 +sTXSPEC.asNucleusInfo[0].bAmplitudeCorrectionValid = 1 +sTXSPEC.asNucleusInfo[1].bFrequencyValid = 1 +sTXSPEC.asNucleusInfo[1].bReferenceAmplitudeValid = 1 +sTXSPEC.asNucleusInfo[1].bAmplitudeCorrectionValid = 1 +sTXSPEC.aRFPULSE[0].tName = "03GreFCE" +sTXSPEC.aRFPULSE[0].bAmplitudeValid = 0x1 +sTXSPEC.aRFPULSE[0].flAmplitude = 147.095 +sTXSPEC.aRFPULSE[1].tName = "02GreFCE" +sTXSPEC.aRFPULSE[1].bAmplitudeValid = 0x1 +sTXSPEC.aRFPULSE[1].flAmplitude = 147.095 +sTXSPEC.aRFPULSE[2].tName = "01GreFCE" +sTXSPEC.aRFPULSE[2].bAmplitudeValid = 0x1 +sTXSPEC.aRFPULSE[2].flAmplitude = 147.095 +sTXSPEC.lNoOfTraPulses = 3 +sTXSPEC.lBTB1ParallelCapacity = 2 +sTXSPEC.lBTB1SerialCapacity = 24 +sTXSPEC.lBTB2ParallelCapacity = 2 +sTXSPEC.lBTB2SerialCapacity = 26 +sTXSPEC.bBTBValid = 1 +sTXSPEC.flKDynMagnitudeMin = 0.5 +sTXSPEC.flKDynMagnitudeMax = 1.5 +sTXSPEC.flKDynMagnitudeClipLow = 0.96 +sTXSPEC.flKDynMagnitudeClipHigh = 1.04 +sTXSPEC.flKDynPhaseMax = 0.698132 +sTXSPEC.flKDynPhaseClip = 0.174533 +sTXSPEC.bKDynValid = 1 +sTXSPEC.ucRFPulseType = 0x1 +sTXSPEC.ucExcitMode = 0x1 +sTXSPEC.ucSimultaneousExcitation = 0x1 +sRXSPEC.lGain = 1 +sRXSPEC.bGainValid = 1 +sRXSPEC.aFFT_SCALE[0].lRxChannel = 1 +sRXSPEC.aFFT_SCALE[0].flFactor = 1.06857 +sRXSPEC.aFFT_SCALE[0].bValid = 1 +sRXSPEC.aFFT_SCALE[1].lRxChannel = 2 +sRXSPEC.aFFT_SCALE[1].flFactor = 1.07454 +sRXSPEC.aFFT_SCALE[1].bValid = 1 +sRXSPEC.aFFT_SCALE[2].lRxChannel = 3 +sRXSPEC.aFFT_SCALE[2].flFactor = 1.06622 +sRXSPEC.aFFT_SCALE[2].bValid = 1 +sRXSPEC.aFFT_SCALE[3].lRxChannel = 4 +sRXSPEC.aFFT_SCALE[3].flFactor = 1.06524 +sRXSPEC.aFFT_SCALE[3].bValid = 1 +sRXSPEC.aFFT_SCALE[4].lRxChannel = 5 +sRXSPEC.aFFT_SCALE[4].flFactor = 0.982692 +sRXSPEC.aFFT_SCALE[4].bValid = 1 +sRXSPEC.aFFT_SCALE[5].lRxChannel = 6 +sRXSPEC.aFFT_SCALE[5].flFactor = 0.988603 +sRXSPEC.aFFT_SCALE[5].bValid = 1 +sRXSPEC.aFFT_SCALE[6].lRxChannel = 7 +sRXSPEC.aFFT_SCALE[6].flFactor = 0.981538 +sRXSPEC.aFFT_SCALE[6].bValid = 1 +sRXSPEC.aFFT_SCALE[7].lRxChannel = 8 +sRXSPEC.aFFT_SCALE[7].flFactor = 1.00856 +sRXSPEC.aFFT_SCALE[7].bValid = 1 +sRXSPEC.bVariCapVoltagesValid = 1 +sRXSPEC.alDwellTime[0] = 8500 +sAdjFreSpec.ulMode = 0x1 +sAdjFreSpec.ucAdjWithBC = 0x1 +sAdjTraSpec.ucAdjWithBC = 0x1 +sAdjShimSpec.ulMode = 0x1 +sAdjShimSpec.ucAdjWithBC = 0x1 +sAdjWatSupSpec.ulMode = 0x1 +sAdjWatSupSpec.ucAdjWithBC = 0x1 +alTR[0] = 37000 +lContrasts = 1 +alTE[0] = 4000 +acFlowComp[0] = 1 +lCombinedEchoes = 1 +sSliceArray.asSlice[0].sPosition.dSag = 35.31199581 +sSliceArray.asSlice[0].sPosition.dCor = -8.387765754 +sSliceArray.asSlice[0].sPosition.dTra = -23.13178296 +sSliceArray.asSlice[0].sNormal.dSag = 0.771051253 +sSliceArray.asSlice[0].sNormal.dCor = 0.5863890019 +sSliceArray.asSlice[0].sNormal.dTra = -0.2482496801 +sSliceArray.asSlice[0].dThickness = 6 +sSliceArray.asSlice[0].dPhaseFOV = 187.5 +sSliceArray.asSlice[0].dReadoutFOV = 250 +sSliceArray.lSize = 1 +sSliceArray.lSag = 1 +sSliceArray.lConc = 1 +sSliceArray.ucMode = 0x1 +sSliceArray.sTSat.dThickness = 40 +sSliceArray.sTSat.dGap = 10 +sGroupArray.asGroup[0].nSize = 1 +sGroupArray.asGroup[0].dDistFact = 0.2 +sGroupArray.anMember[1] = -1 +sGroupArray.lSize = 1 +sGroupArray.sPSat.dThickness = 50 +sGroupArray.sPSat.dGap = 10 +sAutoAlign.dAAMatrix[0] = 1 +sAutoAlign.dAAMatrix[5] = 1 +sAutoAlign.dAAMatrix[10] = 1 +sAutoAlign.dAAMatrix[15] = 1 +sNavigatorPara.ucRespComp = 0x4 +sPrepPulses.ucFatSat = 0x4 +sPrepPulses.ucWaterSat = 0x4 +sPrepPulses.ucInversion = 0x4 +sPrepPulses.ucSatRecovery = 0x1 +sPrepPulses.ucFatSatMode = 0x2 +sKSpace.lBaseResolution = 256 +sKSpace.lPhaseEncodingLines = 192 +sKSpace.dPhaseResolution = 1 +sKSpace.lPartitions = 32 +sKSpace.lImagesPerSlab = 32 +sKSpace.dSliceResolution = 1 +sKSpace.ucPhasePartialFourier = 0x10 +sKSpace.ucSlicePartialFourier = 0x10 +sKSpace.ucAveragingMode = 0x2 +sKSpace.ucMultiSliceMode = 0x1 +sKSpace.ucDimension = 0x2 +sKSpace.ucAsymmetricEchoAllowed = 0x1 +sKSpace.unReordering = 0x1 +sFastImaging.lEPIFactor = 1 +sFastImaging.lTurboFactor = 1 +sFastImaging.lSegments = 3 +sFastImaging.ulEnableRFSpoiling = 0x1 +sPhysioImaging.lSignal1 = 2 +sPhysioImaging.lMethod1 = 2 +sPhysioImaging.lSignal2 = 1 +sPhysioImaging.lMethod2 = 1 +sPhysioImaging.lPhases = 21 +sPhysioImaging.lRetroGatedImages = 16 +sPhysioImaging.sPhysioECG.lScanWindow = 805 +sPhysioImaging.sPhysioECG.lTriggerPulses = 1 +sPhysioImaging.sPhysioECG.lTriggerWindow = 5 +sPhysioImaging.sPhysioECG.lArrhythmiaDetection = 1 +sPhysioImaging.sPhysioECG.lCardiacGateOnThreshold = 100000 +sPhysioImaging.sPhysioECG.lCardiacGateOffThreshold = 700000 +sPhysioImaging.sPhysioPulse.lTriggerPulses = 1 +sPhysioImaging.sPhysioPulse.lTriggerWindow = 5 +sPhysioImaging.sPhysioPulse.lCardiacGateOnThreshold = 100000 +sPhysioImaging.sPhysioPulse.lCardiacGateOffThreshold = 700000 +sPhysioImaging.sPhysioExt.lTriggerPulses = 1 +sPhysioImaging.sPhysioExt.lTriggerWindow = 5 +sPhysioImaging.sPhysioExt.lCardiacGateOnThreshold = 100000 +sPhysioImaging.sPhysioExt.lCardiacGateOffThreshold = 700000 +sPhysioImaging.sPhysioResp.lRespGateThreshold = 20 +sPhysioImaging.sPhysioResp.lRespGatePhase = 2 +sPhysioImaging.sPhysioResp.dGatingRatio = 0.3 +sSpecPara.lPhaseCyclingType = 1 +sSpecPara.lPhaseEncodingType = 1 +sSpecPara.lRFExcitationBandwidth = 1 +sSpecPara.ucRemoveOversampling = 0x1 +sSpecPara.lDecouplingType = 1 +sSpecPara.lNOEType = 1 +sSpecPara.lExcitationType = 1 +sSpecPara.lSpectralSuppression = 1 +sDiffusion.ulMode = 0x1 +sAngio.sFlowArray.asElm[0].nVelocity = 100 +sAngio.sFlowArray.asElm[0].nDir = 0x4 +sAngio.sFlowArray.lSize = 1 +sAngio.ucPCFlowMode = 0x2 +sAngio.ucTOFInflow = 0x4 +sAngio.ucRephasedImage = 0x1 +sAngio.ucPhaseImage = 0x1 +sEllipticalFilter.ucMode = 0x1 +sPat.lAccelFactPE = 1 +sPat.lAccelFact3D = 1 +sPat.ucPATMode = 0x1 +sPat.ucRefScanMode = 0x1 +ucAutoMovie = 0x1 +ucDisableChangeStoreImages = 0x1 +ucReconstructionMode = 0x1 +ucPHAPSMode = 0x1 +ucDixon = 0x1 +lAverages = 2 +adFlipAngleDegree[0] = 30 +lScanTimeSec = 103 +lTotalScanTimeSec = 112 +dRefSNR = 165404.1473 +dRefSNR_VOI = 165404.1473 +tdefaultEVAProt = "%SiemensEvaDefProt%\Inline\Inline.evp" +tcurrentEVAProt = "%CURRENTEVAPROT%\EVA2A5.tmp" +sCOIL_SELECT_MEAS.asList[0].sCoilElementID.tCoilID = "6_Ch_Body_P" +sCOIL_SELECT_MEAS.asList[0].sCoilElementID.lCoilCopy = 1 +sCOIL_SELECT_MEAS.asList[0].sCoilElementID.tElement = "PP6" +sCOIL_SELECT_MEAS.asList[0].lElementSelected = 1 +sCOIL_SELECT_MEAS.asList[0].lRxChannelConnected = 1 +sCOIL_SELECT_MEAS.asList[1].sCoilElementID.tCoilID = "6_Ch_Body_P" +sCOIL_SELECT_MEAS.asList[1].sCoilElementID.lCoilCopy = 1 +sCOIL_SELECT_MEAS.asList[1].sCoilElementID.tElement = "PP5" +sCOIL_SELECT_MEAS.asList[1].lElementSelected = 1 +sCOIL_SELECT_MEAS.asList[1].lRxChannelConnected = 1 +sCOIL_SELECT_MEAS.asList[2].sCoilElementID.tCoilID = "6_Ch_Body_P" +sCOIL_SELECT_MEAS.asList[2].sCoilElementID.lCoilCopy = 1 +sCOIL_SELECT_MEAS.asList[2].sCoilElementID.tElement = "PP3" +sCOIL_SELECT_MEAS.asList[2].lElementSelected = 1 +sCOIL_SELECT_MEAS.asList[2].lRxChannelConnected = 2 +sCOIL_SELECT_MEAS.asList[3].sCoilElementID.tCoilID = "6_Ch_Body_P" +sCOIL_SELECT_MEAS.asList[3].sCoilElementID.lCoilCopy = 1 +sCOIL_SELECT_MEAS.asList[3].sCoilElementID.tElement = "PP4" +sCOIL_SELECT_MEAS.asList[3].lElementSelected = 1 +sCOIL_SELECT_MEAS.asList[3].lRxChannelConnected = 3 +sCOIL_SELECT_MEAS.asList[4].sCoilElementID.tCoilID = "6_Ch_Body_P" +sCOIL_SELECT_MEAS.asList[4].sCoilElementID.lCoilCopy = 1 +sCOIL_SELECT_MEAS.asList[4].sCoilElementID.tElement = "PP2" +sCOIL_SELECT_MEAS.asList[4].lElementSelected = 1 +sCOIL_SELECT_MEAS.asList[4].lRxChannelConnected = 4 +sCOIL_SELECT_MEAS.asList[5].sCoilElementID.tCoilID = "6_Ch_Body_P" +sCOIL_SELECT_MEAS.asList[5].sCoilElementID.lCoilCopy = 1 +sCOIL_SELECT_MEAS.asList[5].sCoilElementID.tElement = "PP1" +sCOIL_SELECT_MEAS.asList[5].lElementSelected = 1 +sCOIL_SELECT_MEAS.asList[5].lRxChannelConnected = 4 +sCOIL_SELECT_MEAS.asList[6].sCoilElementID.tCoilID = "6_Ch_Body_A" +sCOIL_SELECT_MEAS.asList[6].sCoilElementID.lCoilCopy = 1 +sCOIL_SELECT_MEAS.asList[6].sCoilElementID.tElement = "PA6" +sCOIL_SELECT_MEAS.asList[6].lElementSelected = 1 +sCOIL_SELECT_MEAS.asList[6].lRxChannelConnected = 5 +sCOIL_SELECT_MEAS.asList[7].sCoilElementID.tCoilID = "6_Ch_Body_A" +sCOIL_SELECT_MEAS.asList[7].sCoilElementID.lCoilCopy = 1 +sCOIL_SELECT_MEAS.asList[7].sCoilElementID.tElement = "PA5" +sCOIL_SELECT_MEAS.asList[7].lElementSelected = 1 +sCOIL_SELECT_MEAS.asList[7].lRxChannelConnected = 5 +sCOIL_SELECT_MEAS.asList[8].sCoilElementID.tCoilID = "6_Ch_Body_A" +sCOIL_SELECT_MEAS.asList[8].sCoilElementID.lCoilCopy = 1 +sCOIL_SELECT_MEAS.asList[8].sCoilElementID.tElement = "PA3" +sCOIL_SELECT_MEAS.asList[8].lElementSelected = 1 +sCOIL_SELECT_MEAS.asList[8].lRxChannelConnected = 6 +sCOIL_SELECT_MEAS.asList[9].sCoilElementID.tCoilID = "6_Ch_Body_A" +sCOIL_SELECT_MEAS.asList[9].sCoilElementID.lCoilCopy = 1 +sCOIL_SELECT_MEAS.asList[9].sCoilElementID.tElement = "PA4" +sCOIL_SELECT_MEAS.asList[9].lElementSelected = 1 +sCOIL_SELECT_MEAS.asList[9].lRxChannelConnected = 7 +sCOIL_SELECT_MEAS.asList[10].sCoilElementID.tCoilID = "6_Ch_Body_A" +sCOIL_SELECT_MEAS.asList[10].sCoilElementID.lCoilCopy = 1 +sCOIL_SELECT_MEAS.asList[10].sCoilElementID.tElement = "PA2" +sCOIL_SELECT_MEAS.asList[10].lElementSelected = 1 +sCOIL_SELECT_MEAS.asList[10].lRxChannelConnected = 8 +sCOIL_SELECT_MEAS.asList[11].sCoilElementID.tCoilID = "6_Ch_Body_A" +sCOIL_SELECT_MEAS.asList[11].sCoilElementID.lCoilCopy = 1 +sCOIL_SELECT_MEAS.asList[11].sCoilElementID.tElement = "PA1" +sCOIL_SELECT_MEAS.asList[11].lElementSelected = 1 +sCOIL_SELECT_MEAS.asList[11].lRxChannelConnected = 8 +sCOIL_SELECT_MEAS.sCOILPLUGS.aulPlugId[0] = 0xff +sCOIL_SELECT_MEAS.sCOILPLUGS.aulPlugId[1] = 0x76 +sCOIL_SELECT_MEAS.sCOILPLUGS.aulPlugId[2] = 0x78 +sCOIL_SELECT_MEAS.sCOILPLUGS.aulPlugId[3] = 0x87 +sCOIL_SELECT_MEAS.sCOILPLUGS.aulPlugId[4] = 0x67 +sCOIL_SELECT_MEAS.sCOILPLUGS.auiNmbrOfNibbles[0] = 0x2 +sCOIL_SELECT_MEAS.sCOILPLUGS.auiNmbrOfNibbles[1] = 0x2 +sCOIL_SELECT_MEAS.sCOILPLUGS.auiNmbrOfNibbles[2] = 0x2 +sCOIL_SELECT_MEAS.sCOILPLUGS.auiNmbrOfNibbles[3] = 0x2 +sCOIL_SELECT_MEAS.sCOILPLUGS.auiNmbrOfNibbles[4] = 0x2 +sEFISPEC.bEFIDataValid = 1 +### ASCCONV END ### +' +*/ + +/* + * Table of equivalence: + * +ulVersion = 0xbee332 +<=> +27 - 'MrProtocolVersion' VM 1, VR IS, SyngoDT 6, NoOfItems 6, Data '12510002' +*/ + +#include "gdcmReader.h" +#include "gdcmImageReader.h" +#include "gdcmImageWriter.h" +#include "gdcmCSAHeader.h" +#include "gdcmAttribute.h" +#include "gdcmGlobal.h" +#include "gdcmDicts.h" + +#include + +#include + +int main(int argc, char *argv []) +{ + if( argc < 2 ) return 1; + const char *filename = argv[1]; + gdcm::ImageReader reader; + reader.SetFileName( filename ); + if( !reader.Read() ) + { + std::cerr << "Failed to read: " << filename << std::endl; + return 1; + } + + gdcm::CSAHeader csa; + const gdcm::DataSet& ds = reader.GetFile().GetDataSet(); + + //const gdcm::PrivateTag &t1 = csa.GetCSAImageHeaderInfoTag(); + const gdcm::PrivateTag &t2 = csa.GetCSASeriesHeaderInfoTag(); + + if( ds.FindDataElement( t2 ) ) + { + csa.LoadFromDataElement( ds.GetDataElement( t2 ) ); + //csa.Print( std::cout ); + } + + if( !csa.FindCSAElementByName( "MrProtocol" ) ) + { + return 1; + } + const gdcm::CSAElement &csael = csa.GetCSAElementByName( "MrProtocol" ); + //std::cout << csael << std::endl; + + const gdcm::ByteValue *bv = csael.GetByteValue(); + if( !bv ) + { + return 1; + } + std::string str(bv->GetPointer(), bv->GetLength()); + std::istringstream is(str); + std::string s; + typedef std::map< std::string, std::string > MyMapType; + MyMapType mymap; + while( std::getline(is, s ) ) + { + std::string::size_type pos = s.find( '=' ); + if( pos != std::string::npos ) + { + std::string sub1 = s.substr(0, pos); + sub1.erase( sub1.find_last_not_of(' ') + 1); + std::string sub2 = s.substr(pos+1); // skip the '=' char + sub2.erase( 0, sub2.find_first_not_of(' ')); + //std::cout << sub1 << std::endl; + mymap.insert( MyMapType::value_type(sub1, sub2) ); + } + else + { + // ### ASCCONV BEGIN ### + // ### ASCCONV END ### + } + } + const char fourierstr[] = "sKSpace.ucSlicePartialFourier"; + const gdcm::CSAHeaderDict &csadict = gdcm::Global::GetInstance().GetDicts().GetCSAHeaderDict(); + const gdcm::CSAHeaderDictEntry &fourier = csadict.GetCSAHeaderDictEntry( fourierstr ); + std::cout << fourier << std::endl; + MyMapType::const_iterator it = mymap.find ( fourierstr ); + if( it == mymap.end() ) return 1; + //std::cout << it->second << std::endl; + const std::string &partial_fourier = it->second; + if( partial_fourier == "0x1" ) + { + std::cout << "partial fourier is 4/8" << std::endl; + } + else if( partial_fourier == "0x2" ) + { + std::cout << "partial fourier is 5/8" << std::endl; + } + else if( partial_fourier == "0x4" ) + { + std::cout << "partial fourier is 6/8" << std::endl; + } + else if( partial_fourier == "0x8" ) + { + std::cout << "partial fourier is 7/8" << std::endl; + } + else if( partial_fourier == "0x10" ) + { + std::cout << "partial fourier is 8/8" << std::endl; + } + else + { + std::cerr << "Impossible: " << partial_fourier << std::endl; + return 1; + } +/* +This is the Flip Angle: +adFlipAngleDegree[0] = 30 + +One can find it also in the protocol: + +... + + { + ""T1mapFunctor@IceImagePostProcFunctors"" + + { } + { 16 14.7378520000000000 } +... + +*/ + // Below is an attemp to play with the CSAHeader dict: +#if 0 + const char gspec[] = "sGRADSPEC.flSensitivityX"; + it = mymap.find( gspec ); + if( it == mymap.end() ) return 1; + const std::string &dummy = it->second; + std::cout << dummy << std::endl; + + const gdcm::CSAHeaderDictEntry &csaentry = csadict.GetCSAHeaderDictEntry( gspec ); + std::cout << csaentry << std::endl; +#endif + + +/* + sSliceArray.ucMode -- should be in (1, 2, 4) + enum SeriesMode + { + ASCENDING = 0x01, + DESCENDING = 0x02, + INTERLEAVED = 0x04 + }; +*/ + const char sliceorderstr[] = "sSliceArray.ucMode"; + const gdcm::CSAHeaderDictEntry &sliceorder = csadict.GetCSAHeaderDictEntry( sliceorderstr ); + std::cout << sliceorder << std::endl; + + it = mymap.find ( sliceorderstr ); + if( it == mymap.end() ) return 1; + const std::string &slice_order = it->second; + if( slice_order == "0x1" ) + { + std::cout << "slice_order: ASCENDING" << std::endl; + } + else if( slice_order == "0x2" ) + { + std::cout << "slice_order: DESCENDING" << std::endl; + } + else if( slice_order == "0x4" ) + { + std::cout << "slice_order: INTERLEAVED" << std::endl; + } + else + { + std::cerr << "Impossible: " << slice_order << std::endl; + return 1; + } + + return 0; +} diff --git a/gdcm/Examples/Cxx/PatchFile.cxx b/gdcm/Examples/Cxx/PatchFile.cxx new file mode 100644 index 0000000..5e440f3 --- /dev/null +++ b/gdcm/Examples/Cxx/PatchFile.cxx @@ -0,0 +1,116 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + * The image was a broken file where the Pixel Data element was 8 times too big + * Apparently multiplying the BitsAllocated to 4 and multiplying the number of + * frames by 2 would solve the problem + * + * This C++ code can be used to patch the header. + */ + +#include "gdcmReader.h" +#include "gdcmImageReader.h" +#include "gdcmWriter.h" +#include "gdcmDataSet.h" +#include "gdcmAttribute.h" + +int main(int argc, char *argv[]) +{ + if( argc < 3 ) + { + return 1; + } + const char *f = argv[1]; + const char *out = argv[2]; + gdcm::Reader r; + r.SetFileName( f ); + if( !r.Read() ) + { + return 1; + } + + gdcm::File &file = r.GetFile(); + gdcm::DataSet& ds = file.GetDataSet(); + // (0028,0100) US 16 # 2, 1 BitsAllocated + // (0028,0101) US 16 # 2, 1 BitsStored + // (0028,0102) US 15 # 2, 1 HighBit + // + { + gdcm::Attribute<0x28,0x100> at; + at.SetFromDataElement( ds.GetDataElement( at.GetTag() ) ); + if( at.GetValue() != 8 ) + { + return 1; + } + at.SetValue( 32 ); + ds.Replace( at.GetAsDataElement() ); + } + { + gdcm::Attribute<0x28,0x101> at; + at.SetFromDataElement( ds.GetDataElement( at.GetTag() ) ); + if( at.GetValue() != 8 ) + { + return 1; + } + at.SetValue( 32 ); + ds.Replace( at.GetAsDataElement() ); + } + { + gdcm::Attribute<0x28,0x102> at; + at.SetFromDataElement( ds.GetDataElement( at.GetTag() ) ); + if( at.GetValue() != 7 ) + { + return 1; + } + at.SetValue( 31 ); + ds.Replace( at.GetAsDataElement() ); + } + // (0028,0008) IS [56] # 2, 1 NumberOfFrames + + { + gdcm::Attribute<0x28,0x8> at; + at.SetFromDataElement( ds.GetDataElement( at.GetTag() ) ); + at.SetValue( at.GetValue() * 2 ); + ds.Replace( at.GetAsDataElement() ); + } + + gdcm::Writer w; + w.SetFile( file ); + w.SetCheckFileMetaInformation( false ); + w.SetFileName( out ); + if( !w.Write() ) + { + return 1; + } + + // Now let's see if we can read it as an image: + gdcm::ImageReader ir; + ir.SetFileName( out ); + if(!ir.Read()) + { + return 1; + } + gdcm::Image &image = ir.GetImage(); + unsigned long len = image.GetBufferLength(); + const gdcm::ByteValue *bv = ir.GetFile().GetDataSet().GetDataElement( gdcm::Tag(0x7fe0,0x0010) ).GetByteValue(); + if( !bv || len != bv->GetLength() ) + { + return 1; + } + std::cout << bv->GetLength() << " " << len << std::endl; + + std::cout << "Sucess to rewrite image !" << std::endl; + image.Print( std::cout ); + return 0; +} diff --git a/gdcm/Examples/Cxx/PublicDict.cxx b/gdcm/Examples/Cxx/PublicDict.cxx new file mode 100644 index 0000000..b0dad08 --- /dev/null +++ b/gdcm/Examples/Cxx/PublicDict.cxx @@ -0,0 +1,65 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + * Dummy example to show GDCM Dict(s) API (Part 6) + Collected Private Attributes: + */ + +#include "gdcmGlobal.h" +#include "gdcmDicts.h" +#include "gdcmDict.h" +#include "gdcmCSAHeader.h" +#include "gdcmPrivateTag.h" + +int main(int , char *[]) +{ + const gdcm::Global& g = gdcm::Global::GetInstance(); // sum of all knowledge ! + const gdcm::Dicts &dicts = g.GetDicts(); + const gdcm::Dict &pub = dicts.GetPublicDict(); // Part 6 + + //std::cout << pub << std::endl; + + // 3 differents way to access the same information + + // 1. From the public dict only: + gdcm::Tag patient_name(0x10,0x10); + const gdcm::DictEntry &entry1 = pub.GetDictEntry(patient_name); + std::cout << entry1 << std::endl; + + // 2. From all dicts: + const gdcm::DictEntry &entry2 = dicts.GetDictEntry(patient_name); + std::cout << entry2 << std::endl; + + // 3. This solution is the most flexible solution as you can request using the same + // API either a public tag or a private tag + const char *strowner = 0; + const gdcm::DictEntry &entry3 = dicts.GetDictEntry(patient_name,strowner); + std::cout << entry3 << std::endl; + + // Private attributes: + + // try with a private tag now: + const gdcm::PrivateTag &private_tag = gdcm::CSAHeader::GetCSAImageHeaderInfoTag(); + //std::cout << private_tag << std::endl; + const gdcm::DictEntry &entry4 = dicts.GetDictEntry(private_tag,private_tag.GetOwner()); + std::cout << entry4 << std::endl; + + // Let's pretend that private lookup is on 0x10xx elements: + gdcm::PrivateTag dummy = private_tag; + dummy.SetElement( (uint16_t)(0x1000 + dummy.GetElement()) ); + const gdcm::DictEntry &entry5 = dicts.GetDictEntry(dummy,dummy.GetOwner()); + std::cout << entry5 << std::endl; + + + return 0; +} diff --git a/gdcm/Examples/Cxx/QIDO-RS.cxx b/gdcm/Examples/Cxx/QIDO-RS.cxx new file mode 100644 index 0000000..706936b --- /dev/null +++ b/gdcm/Examples/Cxx/QIDO-RS.cxx @@ -0,0 +1,51 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmReader.h" +#include "gdcmWriter.h" +#include "gdcmJSON.h" + +/* + * Simple QIDO-RS round-trip to test implementation of gdcm::JSON + * See Sup166 for details + */ +int main(int argc, char *argv[]) +{ + if( argc < 2 ) return 1; + using namespace gdcm; + const char *filename = argv[1]; + gdcm::Reader reader; + reader.SetFileName( filename ); + if( !reader.Read() ) return 1; + + gdcm::JSON json; + json.PrettyPrintOn(); + std::stringstream ss; + const gdcm::File & f = reader.GetFile(); + json.Code( f.GetDataSet(), ss); + + std::cout << ss.str() << std::endl; + + gdcm::Writer w; + gdcm::File & ff = w.GetFile(); + ff.GetHeader().SetDataSetTransferSyntax( gdcm::TransferSyntax::ExplicitVRLittleEndian ); + if( !json.Decode(ss, ff.GetDataSet() ) ) + { + std::cerr << "Could not decode" << std::endl; + return 1; + } + w.SetFileName( "/tmp/debug.dcm" ); + if( !w.Write() ) return 1; + + return 0; +} diff --git a/gdcm/Examples/Cxx/ReadAndDumpDICOMDIR.cxx b/gdcm/Examples/Cxx/ReadAndDumpDICOMDIR.cxx new file mode 100644 index 0000000..23d11f6 --- /dev/null +++ b/gdcm/Examples/Cxx/ReadAndDumpDICOMDIR.cxx @@ -0,0 +1,212 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + * This example shows how to read and dump a DICOMDIR File + * + * Thanks: + * Tom Marynowski (lordglub gmail) for contributing this example + */ +#include "gdcmReader.h" +#include "gdcmMediaStorage.h" + +typedef std::set DataElementSet; +typedef DataElementSet::const_iterator ConstIterator; + +int main(int argc, char *argv []) +{ + if( argc < 2 ) return 1; + const char *filename = argv[1]; + + gdcm::Reader reader; + reader.SetFileName( filename); + if( !reader.Read() ) + { + std::cerr << "Could not read: " << filename << std::endl; + return 1; + } + std::stringstream strm; + + gdcm::File &file = reader.GetFile(); + gdcm::DataSet &ds = file.GetDataSet(); + gdcm::FileMetaInformation &fmi = file.GetHeader(); + + gdcm::MediaStorage ms; + ms.SetFromFile(file); + if( ms != gdcm::MediaStorage::MediaStorageDirectoryStorage ) + { + std::cout << "This file is not a DICOMDIR" << std::endl; + return 1; + } + + if (fmi.FindDataElement( gdcm::Tag (0x0002, 0x0002))) + { strm.str(""); + fmi.GetDataElement( gdcm::Tag (0x0002, 0x0002) ).GetValue().Print(strm); + } + else + { + std::cerr << " Media Storage Sop Class UID not present" << std::endl; + } + + //TODO il faut trimer strm.str() avant la comparaison au cas ou... + if ("1.2.840.10008.1.3.10"!=strm.str()) + { + std::cout << "This file is not a DICOMDIR" << std::endl; + return 1; + } + + ConstIterator it = ds.GetDES().begin(); + + for( ; it != ds.GetDES().end(); ++it) + { + + if (it->GetTag()==gdcm::Tag (0x0004, 0x1220)) + { + + const gdcm::DataElement &de = (*it); + // ne pas utiliser GetSequenceOfItems pour extraire les items + gdcm::SmartPointer sqi =de.GetValueAsSQ(); + unsigned int itemused = 1; + while (itemused<=sqi->GetNumberOfItems()) + + { + strm.str(""); + + if (sqi->GetItem(itemused).FindDataElement(gdcm::Tag (0x0004, 0x1430))) + sqi->GetItem(itemused).GetDataElement(gdcm::Tag (0x0004, 0x1430)).GetValue().Print(strm); + + //TODO il faut trimer strm.str() avant la comparaison + while((strm.str()=="PATIENT")||((strm.str()=="PATIENT "))) + { + std::cout << strm.str() << std::endl; + strm.str(""); + if (sqi->GetItem(itemused).FindDataElement(gdcm::Tag (0x0010, 0x0010))) + sqi->GetItem(itemused).GetDataElement(gdcm::Tag (0x0010, 0x0010)).GetValue().Print(strm); + std::cout << "PATIENT NAME : " << strm.str() << std::endl; + + + //PATIENT ID + strm.str(""); + if (sqi->GetItem(itemused).FindDataElement(gdcm::Tag (0x0010, 0x0020))) + sqi->GetItem(itemused).GetDataElement(gdcm::Tag (0x0010, 0x0020)).GetValue().Print(strm); + std::cout << "PATIENT ID : " << strm.str() << std::endl; + + /*ADD TAG TO READ HERE*/ + std::cout << "=========================== " << std::endl; + itemused++; + strm.str(""); + if (sqi->GetItem(itemused).FindDataElement(gdcm::Tag (0x0004, 0x1430))) + sqi->GetItem(itemused).GetDataElement(gdcm::Tag (0x0004, 0x1430)).GetValue().Print(strm); + + //TODO il faut trimer strm.str() avant la comparaison + while((strm.str()=="STUDY")||((strm.str()=="STUDY "))) + { + std::cout << " " << strm.str() << std::endl; + //UID + strm.str(""); + if (sqi->GetItem(itemused).FindDataElement(gdcm::Tag (0x0020, 0x000d))) + sqi->GetItem(itemused).GetDataElement(gdcm::Tag (0x0020, 0x000d)).GetValue().Print(strm); + std::cout << " STUDY UID : " << strm.str() << std::endl; + + //STUDY DATE + strm.str(""); + if (sqi->GetItem(itemused).FindDataElement(gdcm::Tag (0x0008, 0x0020))) + sqi->GetItem(itemused).GetDataElement(gdcm::Tag (0x0008, 0x0020)).GetValue().Print(strm); + std::cout << " STUDY DATE : " << strm.str() << std::endl; + + //STUDY DESCRIPTION + strm.str(""); + if (sqi->GetItem(itemused).FindDataElement(gdcm::Tag (0x0008, 0x1030))) + sqi->GetItem(itemused).GetDataElement(gdcm::Tag (0x0008, 0x1030)).GetValue().Print(strm); + std::cout << " STUDY DESCRIPTION : " << strm.str() << std::endl; + + /*ADD TAG TO READ HERE*/ + std::cout << " " << "=========================== " << std::endl; + + itemused++; + strm.str(""); + if (sqi->GetItem(itemused).FindDataElement(gdcm::Tag (0x0004, 0x1430))) + sqi->GetItem(itemused).GetDataElement(gdcm::Tag (0x0004, 0x1430)).GetValue().Print(strm); + + //TODO il faut trimer strm.str() avant la comparaison + while((strm.str()=="SERIES")||((strm.str()=="SERIES "))) + { + std::cout << " " << strm.str() << std::endl; + strm.str(""); + if (sqi->GetItem(itemused).FindDataElement(gdcm::Tag (0x0020, 0x000e))) + sqi->GetItem(itemused).GetDataElement(gdcm::Tag (0x0020, 0x000e)).GetValue().Print(strm); + std::cout << " SERIE UID" << strm.str() << std::endl; + + //SERIE MODALITY + strm.str(""); + if (sqi->GetItem(itemused).FindDataElement(gdcm::Tag (0x0008, 0x0060))) + sqi->GetItem(itemused).GetDataElement(gdcm::Tag (0x0008, 0x0060)).GetValue().Print(strm); + std::cout << " SERIE MODALITY" << strm.str() << std::endl; + + //SERIE DESCRIPTION + strm.str(""); + if (sqi->GetItem(itemused).FindDataElement(gdcm::Tag (0x0008, 0x103e))) + sqi->GetItem(itemused).GetDataElement(gdcm::Tag (0x0008, 0x103e)).GetValue().Print(strm); + std::cout << " SERIE DESCRIPTION" << strm.str() << std::endl; + + + /*ADD TAG TO READ HERE*/ + + std::cout << " " << "=========================== " << std::endl; + itemused++; + strm.str(""); + if (sqi->GetItem(itemused).FindDataElement(gdcm::Tag (0x0004, 0x1430))) + sqi->GetItem(itemused).GetDataElement(gdcm::Tag (0x0004, 0x1430)).GetValue().Print(strm); + + + //TODO il faut trimer strm.str() avant la comparaison + while ((strm.str()=="IMAGE")||((strm.str()=="IMAGE "))) + // if(tmp=="IMAGE") + { + std::cout << " " << strm.str() << std::endl; + + + //UID + strm.str(""); + if (sqi->GetItem(itemused).FindDataElement(gdcm::Tag (0x0004, 0x1511))) + sqi->GetItem(itemused).GetDataElement(gdcm::Tag (0x0004, 0x1511)).GetValue().Print(strm); + std::cout << " IMAGE UID : " << strm.str() << std::endl; + + //PATH de l'image + strm.str(""); + if (sqi->GetItem(itemused).FindDataElement(gdcm::Tag (0x0004, 0x1500))) + sqi->GetItem(itemused).GetDataElement(gdcm::Tag (0x0004, 0x1500)).GetValue().Print(strm); + std::cout << " IMAGE PATH : " << strm.str() << std::endl; + /*ADD TAG TO READ HERE*/ + + + + if(itemused < sqi->GetNumberOfItems()) + {itemused++; + }else{break;} + + strm.str(""); + + if (sqi->GetItem(itemused).FindDataElement(gdcm::Tag (0x0004, 0x1430))) + sqi->GetItem(itemused).GetDataElement(gdcm::Tag (0x0004, 0x1430)).GetValue().Print(strm); + + } + } + } + } + itemused++; + } + } + } + return 0; +} diff --git a/gdcm/Examples/Cxx/ReadAndPrintAttributes.cxx b/gdcm/Examples/Cxx/ReadAndPrintAttributes.cxx new file mode 100644 index 0000000..475c322 --- /dev/null +++ b/gdcm/Examples/Cxx/ReadAndPrintAttributes.cxx @@ -0,0 +1,109 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + * This small example will show how one can read and print + * a DICOM Attribute using different technique (by tag or by name) + */ + +#include "gdcmReader.h" +#include "gdcmGlobal.h" +#include "gdcmDicts.h" +#include "gdcmDict.h" +#include "gdcmAttribute.h" +#include "gdcmStringFilter.h" + +#include + +int main(int argc, char *argv[]) +{ + if( argc < 2 ) + { + std::cerr << argv[0] << " input.dcm" << std::endl; + return 1; + } + const char *filename = argv[1]; + + // Instanciate the reader: + gdcm::Reader reader; + reader.SetFileName( filename ); + if( !reader.Read() ) + { + std::cerr << "Could not read: " << filename << std::endl; + return 1; + } + + // The output of gdcm::Reader is a gdcm::File + gdcm::File &file = reader.GetFile(); + + // the dataset is the the set of element we are interested in: + gdcm::DataSet &ds = file.GetDataSet(); + + const gdcm::Global& g = gdcm::Global::GetInstance(); + const gdcm::Dicts &dicts = g.GetDicts(); + const gdcm::Dict &pubdict = dicts.GetPublicDict(); + + using namespace gdcm; + + // In this example we will show why using name to lookup attribute can be + // dangerous. + Tag tPatientName(0x0,0x0); + //const DictEntry &de1 = + pubdict.GetDictEntryByName("Patient Name", tPatientName); + + std::cout << "Found: " << tPatientName << std::endl; + + // Indeed the attribute could not be found. Since DICOM 2003, Patient Name + // has become Patient's Name. + + Tag tPatientsName; + //const DictEntry &de2 = + pubdict.GetDictEntryByName("Patient's Name", tPatientsName); + + std::cout << "Found: " << tPatientsName << std::endl; + + // Let's try to read an arbitrary DICOM Attribute: + Tag tDoseGridScaling; + //const DictEntry &de3 = + pubdict.GetDictEntryByName("Dose Grid Scaling", tDoseGridScaling); + + std::cout << "Found: " << tDoseGridScaling << std::endl; + + if( ds.FindDataElement( tDoseGridScaling ) ) + { + gdcm::StringFilter sf; + sf.SetFile(file); + std::cout << "Attribute Value as String: " << sf.ToString( tDoseGridScaling ) << std::endl; + + // Let's check the name again: + std::pair pss + = sf.ToStringPair( tDoseGridScaling ); + std::cout << "Attribute Name Checked: " << pss.first << std::endl; + std::cout << "Attribute Value (string): " << pss.second << std::endl; + + //const DataElement &dgs = ds.GetDataElement( tDoseGridScaling ); + + // Let's assume for a moment we knew the tag number: + Attribute<0x3004,0x000e> at; + assert( at.GetTag() == tDoseGridScaling ); + at.SetFromDataSet( ds ); + // For the sake of long term maintenance, we will not write + // that this particular attribute is stored as a double. What if + // a user made a mistake. It is much safer to rely on GDCM internal + // mechanism to deduce the VR::DS type (represented as a ieee double) + Attribute<0x3004,0x000e>::ArrayType v = at.GetValue(); + std::cout << "DoseGridScaling=" << v << std::endl; + } + + return 0; +} diff --git a/gdcm/Examples/Cxx/ReadExplicitLengthSQIVR.cxx b/gdcm/Examples/Cxx/ReadExplicitLengthSQIVR.cxx new file mode 100644 index 0000000..f29602d --- /dev/null +++ b/gdcm/Examples/Cxx/ReadExplicitLengthSQIVR.cxx @@ -0,0 +1,50 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmReader.h" +#include "gdcmImplicitDataElement.h" +#include "gdcmDataSet.h" +#include "gdcmPrivateTag.h" +#include "gdcmPrivateTag.h" +#include "gdcmByteValue.h" +#include "gdcmSequenceOfItems.h" + +using namespace gdcm; + +int main(int argc, char *argv[]) +{ + if ( argc < 2 ) return 1; + const char *filename = argv[1]; + gdcm::Reader r; + r.SetFileName( filename ); + r.Read(); + + + //gdcm::PrivateTag pt(0xe1,0x42,"ELSCINT1"); + //gdcm::Tag pt(0x88,0x200); + gdcm::Tag pt(0x8,0x1140); + DataSet &ds = r.GetFile().GetDataSet(); + const DataElement &de = ds.GetDataElement( pt ); + + std::cout << de << std::endl; + const ByteValue *bv = de.GetByteValue(); + SmartPointer sqi = new SequenceOfItems; + sqi->SetLength( bv->GetLength() ); + std::stringstream ss; + ss.str( std::string( bv->GetPointer(), bv->GetLength() ) ); + sqi->Read( ss ); + + std::cout << *sqi << std::endl; + + return 0; +} diff --git a/gdcm/Examples/Cxx/ReadGEMSSDO.cxx b/gdcm/Examples/Cxx/ReadGEMSSDO.cxx new file mode 100644 index 0000000..47c580b --- /dev/null +++ b/gdcm/Examples/Cxx/ReadGEMSSDO.cxx @@ -0,0 +1,176 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmReader.h" +#include "gdcmDataElement.h" +#include "gdcmPrivateTag.h" + +#include +#include + +using namespace gdcm; + +struct SDOElement +{ + typedef std::vector::size_type SizeType; + const char *GetData(SizeType index) const { + return Data[index].c_str(); + } + SizeType GetNumberOfData() const { + return Data.size(); + } + void SetData(SizeType index, const char *data) { + Data[index] = data; + } + const char *GetDataFormat() const { + return DataFormat.c_str(); + } + void SetDataFormat(const char *dataformat, SizeType num) { + DataFormat = dataformat; + Data.resize( num ); + } + void Print( std::ostream &os ) const { + os << DataFormat << ":" << std::endl; + std::vector::const_iterator it = Data.begin(); + size_t s = 0; + for( ; it != Data.end(); ++it ) + { + os << " (" << s++ << ") " << *it << std::endl; + } + } +private: + std::string DataFormat; + std::vector Data; +}; + +class SDOHeader +{ +public: + typedef std::vector SDOElements; + typedef SDOElements::size_type SizeType; + SizeType GetNumberOfSDOElements() const { + return InternalSDODataSet.size(); + } + void AddSDOElement(SDOElement const &sdoelement) { + InternalSDODataSet.push_back( sdoelement ); + } + const SDOElement &GetSDOElement(SizeType index) const { + return InternalSDODataSet[index]; + } + const SDOElement &GetSDOElementByName(const char *) const { + return InternalSDODataSet[0]; + } + void LoadFromAttributes(std::string const &s1, std::string const &s2) + { + std::string tok; + std::string tok2; + std::stringstream strstr(s1); + std::stringstream strstr2(s2); + + SDOElement element; + // Do format + size_t count = 0; + while ( std::getline ( strstr2, tok, '\\' ) ) + { + //std::cout << tok << " "; + std::getline ( strstr2, tok2, '\\' ); + //std::cout << tok2 << std::endl; + count += atoi( tok2.c_str() ); + element.SetDataFormat( tok.c_str(), atoi( tok2.c_str() ) ); + for( size_t t = 0; t < element.GetNumberOfData(); ++t ) + { + std::getline ( strstr, tok, '\\' ); + element.SetData(t, tok.c_str() ); + } + AddSDOElement( element ); + } + //while ( std::getline ( strstr, tok, '^' ) ) +// while ( std::getline ( strstr, tok, '\\' ) ) +// { +// std::cout << tok << std::endl; +// count++; +// } +// std::cout << "Count: " << count << std::endl; +// count = 0; + +// std::cout << "Count: " << count << std::endl; + + } + void Print( std::ostream &os ) const { + SDOElements::const_iterator it = InternalSDODataSet.begin(); + for( ; it != InternalSDODataSet.end(); ++it ) + { + it->Print ( os ); + } + } +private: + SDOElements InternalSDODataSet; +}; + +bool sdo_decode( DataElement const &stringdata, DataElement const &stringdataformat ) +{ + const char *sd = stringdata.GetByteValue()->GetPointer(); + const size_t len_sd = stringdata.GetByteValue()->GetLength(); + + std::string s1 = std::string( sd, len_sd ); + + const char *sdf = stringdataformat.GetByteValue()->GetPointer(); + const size_t len_sdf = stringdataformat.GetByteValue()->GetLength(); + + std::string s2 = std::string( sdf, len_sdf ); + +// std::cout << s1 << std::endl; +// std::cout << s2 << std::endl; + + SDOHeader header; + header.LoadFromAttributes( s1, s2 ); + + header.Print( std::cout ); + + return true; +} + +int main(int argc, char *argv[]) +{ + if( argc < 2 ) + { + std::cerr << argv[0] << " input.dcm" << std::endl; + return 1; + } + const char *filename = argv[1]; + Reader reader; + reader.SetFileName( filename ); + if( !reader.Read() ) + { + return 1; + } + + File &file = reader.GetFile(); + DataSet &ds = file.GetDataSet(); + + // StringData (0033,xx1F) 3 "GEMS_GENIE_1" List of SDO parameters stored as + // list of strings + const PrivateTag tstringdata(0x33,0x1f,"GEMS_GENIE_1"); + // StringDataFormat (0033,xx23) 3 "GEMS_GENIE_1" Format of string parameters; + // contains information about name and number of strings in list + const PrivateTag tstringdataformat(0x33,0x23,"GEMS_GENIE_1"); + + if( !ds.FindDataElement( tstringdata ) ) return 1; + const DataElement& stringdata = ds.GetDataElement( tstringdata ); + if( !ds.FindDataElement( tstringdataformat ) ) return 1; + const DataElement& stringdataformat = ds.GetDataElement( tstringdataformat ); + + sdo_decode( stringdata, stringdataformat ); + + return 0; +} diff --git a/gdcm/Examples/Cxx/ReadMultiTimesException.cxx b/gdcm/Examples/Cxx/ReadMultiTimesException.cxx new file mode 100644 index 0000000..87fb0d7 --- /dev/null +++ b/gdcm/Examples/Cxx/ReadMultiTimesException.cxx @@ -0,0 +1,57 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +// The intention of this sample program is to provoke bad_alloc exceptions in gdcm code + +#include "gdcmImageReader.h" + +int main(int argc, char* argv[]) +{ + // We pre-allocate some memory (about 1Gb) to help the issue to show up earlier + char *dummyBuffer = new char[1024*1024*1100]; (void)dummyBuffer; + // Check the number of parameters given + if (argc < 3) + { + std::cerr << "Usage: " << argv[0] << " Filename numberOfTries" << std::endl; + return 1; + } + + std::cout << "We are going to read the file: " << argv[1] << " " << argv[2] << " times" << std::endl; + // We hold the pointers in an array to avoid the memory to be released + // We read the input file n-times + for (int i = 0; i < atoi(argv[2]); ++i) + { + gdcm::ImageReader reader; + std::cout << "Reading try: " << i << std::endl; + // Read files + reader.SetFileName(argv[1]); + try + { + reader.Read(); + gdcm::Image & img = reader.GetImage(); + unsigned long len = img.GetBufferLength(); + char *buffer = new char[ len ]; + img.GetBuffer( buffer ); // do NOT de-allocate buffer ! + } + catch (std::bad_alloc) + { + std::cerr << "BAD ALLOC Exception caught!" << std::endl; + } + catch (...) + { + std::cerr << "Exception caught!" << std::endl; + } + } + + return 0; +} diff --git a/gdcm/Examples/Cxx/ReadUTF8QtDir.cxx b/gdcm/Examples/Cxx/ReadUTF8QtDir.cxx new file mode 100644 index 0000000..318aaf3 --- /dev/null +++ b/gdcm/Examples/Cxx/ReadUTF8QtDir.cxx @@ -0,0 +1,125 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + * GDCM API expect a const char * as input for SetFileName + * In order to use this API from Qt, here is a simple test that + * shows how to do it in a portable manner: + * + * http://doc.qt.nokia.com/latest/qdir.html#navigation-and-directory-operations + */ + +#include "gdcmReader.h" +#include "gdcmDirectory.h" + +#include +#include +#include + +#include +#include + +#include // fopen + +static int TestBothFuncs(const char *info , const char *ba_str) +{ + int res = 0; + FILE *f = fopen( ba_str, "r" ); + if( f ) + { + std::cout << info << " fopen: " << ba_str << std::endl; + fclose(f); + ++res; + } + gdcm::Reader reader; + std::ifstream is( ba_str, std::ios::binary ); + if( is.is_open() ) + { + std::cout << info << " is_open: " << ba_str << std::endl; + ++res; + } + reader.SetStream( is ); + if( reader.CanRead() == true ) + { + std::cout << info << " SetStream/CanRead:" << ba_str << std::endl; + ++res; + } + is.close(); + reader.SetFileName( ba_str ); + if( reader.CanRead() == true ) + { + std::cout << info << " SetFileName/CanRead:" << ba_str << std::endl; + ++res; + } + return 4 - res; +} + +static int scanFolder(const char dirname[]) +{ + int res = 0; + gdcm::Directory dir; + unsigned int nfiles = dir.Load( dirname, true ); + const gdcm::Directory::FilenamesType &filenames = dir.GetFilenames(); + + for( unsigned int i = 0; i < nfiles; ++i ) + { + const char *ba_str = filenames[i].c_str(); + res += TestBothFuncs("GDCM",ba_str); + } + return res; +} + +static int scanFolderQt(QDir const &dir, QStringList& files) +{ + int res = 0; + QFileInfoList children = dir.entryInfoList(QDir::AllEntries|QDir::NoDotAndDotDot); + for ( int i=0; i(evt); + const char *fn = pe.GetFileName(); + std::cout << "FileName: " << fn << " FileSize: " << gdcm::System::FileSize( fn ) << std::endl; + } +}; + +int main(int argc, char *argv[]) +{ + if( argc < 2 ) + { + return 1; + } + const char *filename = argv[1]; + const char filename_invalid[] = "this is a file that may not exist on this disk.dcm"; + + + gdcm::SmartPointer sp = new gdcm::Scanner; + gdcm::Scanner &s = *sp; + //gdcm::SimpleSubjectWatcher w(&s, "TestFileName" ); + MyFileWatcher w(&s, "TestFileName" ); + + const gdcm::Tag tag_array[] = { + gdcm::Tag(0x8,0x50), + gdcm::Tag(0x8,0x51), + gdcm::Tag(0x8,0x60), + }; + s.AddTag( tag_array[0] ); + s.AddTag( tag_array[1] ); + s.AddTag( tag_array[2] ); + + gdcm::Directory::FilenamesType filenames; + filenames.push_back( filename ); + filenames.push_back( filename_invalid ); + + if( !s.Scan( filenames ) ) + { + return 1; + } + + //s.Print( std::cout ); + + + if( s.IsKey( filename ) ) + { + std::cout << "INFO:" << filename << " is a proper Key for the Scanner (this is a DICOM file)" << std::endl; + } + + if( !s.IsKey( filename_invalid ) ) + { + std::cout << "INFO:" << filename_invalid << " is not a proper Key for the Scanner (this is either not a DICOM file or file does not exist)" << std::endl; + } + + gdcm::Scanner::TagToValue const &ttv = s.GetMapping(filename); + + const gdcm::Tag *ptag = tag_array; + for( ; ptag != tag_array + 3; ++ptag ) + { + gdcm::Scanner::TagToValue::const_iterator it = ttv.find( *ptag ); + if( it != ttv.end() ) + { + std::cout << *ptag << " was properly found in this file" << std::endl; + // it contains a pair of value. the first one is the actual tag, so the following is always true: + // *ptag == it->first + // The second part is the actual value (stored as RAW strings). You will have to reinterpret this string + // if VR for *ptag is not VR::VRASCII ! + const char *value = it->second; + if( *value ) + { + std::cout << " It has the value: " << value << std::endl; + } + else + { + std::cout << " It has no value (empty)" << std::endl; + } + } + else + { + std::cout << "Sorry " << *ptag << " could not be found in this file" << std::endl; + } + } + + return 0; +} diff --git a/gdcm/Examples/Cxx/SortImage.cxx b/gdcm/Examples/Cxx/SortImage.cxx new file mode 100644 index 0000000..26190a1 --- /dev/null +++ b/gdcm/Examples/Cxx/SortImage.cxx @@ -0,0 +1,118 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + */ +#include "gdcmSorter.h" +#include "gdcmScanner.h" +#include "gdcmDataSet.h" +#include "gdcmAttribute.h" + + +bool mysort(gdcm::DataSet const & ds1, gdcm::DataSet const & ds2 ) +{ + //gdcm::Attribute<0x0020,0x0013> at1; // Instance Number + gdcm::Attribute<0x0018,0x1060> at1; // Trigger Time + gdcm::Attribute<0x0020,0x0032> at11; // Image Position (Patient) + at1.Set( ds1 ); + at11.Set( ds1 ); + //gdcm::Attribute<0x0020,0x0013> at2; + gdcm::Attribute<0x0018,0x1060> at2; + gdcm::Attribute<0x0020,0x0032> at22; + at2.Set( ds2 ); + at22.Set( ds2 ); + if( at11 == at22 ) + { + return at1 < at2; + } + return at11 < at22; +} + +bool mysort_part1(gdcm::DataSet const & ds1, gdcm::DataSet const & ds2 ) +{ + gdcm::Attribute<0x0018,0x1060> at1; + at1.Set( ds1 ); + gdcm::Attribute<0x0018,0x1060> at2; + at2.Set( ds2 ); + return at1 < at2; +} + +bool mysort_part2(gdcm::DataSet const & ds1, gdcm::DataSet const & ds2 ) +{ + gdcm::Attribute<0x0020,0x0032> at1; + at1.Set( ds1 ); + gdcm::Attribute<0x0020,0x0032> at2; + at2.Set( ds2 ); + return at1 < at2; +} + +// technically all files are in the same Frame of Reference, so this function +// should be a no-op +bool mysort_dummy(gdcm::DataSet const & ds1, gdcm::DataSet const & ds2 ) +{ + gdcm::Attribute<0x0020,0x0052> at1; // FrameOfReferenceUID + at1.Set( ds1 ); + gdcm::Attribute<0x0020,0x0052> at2; + at2.Set( ds2 ); + return at1 < at2; +} + +int main(int argc, char *argv[]) +{ + if (argc < 2 ) return 1; + const char *dirname = argv[1]; + gdcm::Directory dir; + unsigned int nfiles = dir.Load( dirname ); + + dir.Print( std::cout ); + + gdcm::Sorter sorter; + sorter.SetSortFunction( mysort ); + sorter.Sort( dir.GetFilenames() ); + + std::cout << "Sorter:" << std::endl; + sorter.Print( std::cout ); + + gdcm::Sorter sorter2; + sorter2.SetSortFunction( mysort_part1 ); + sorter2.StableSort( dir.GetFilenames() ); + sorter2.SetSortFunction( mysort_part2 ); + sorter2.StableSort( sorter2.GetFilenames() ); // IMPORTANT + sorter2.SetSortFunction( mysort_dummy ); + sorter2.StableSort( sorter2.GetFilenames() ); // IMPORTANT + + std::cout << "Sorter2:" << std::endl; + sorter2.Print( std::cout ); + + gdcm::Scanner s; + s.AddTag( gdcm::Tag(0x20,0x32) ); // Image Position (Patient) + //s.AddTag( gdcm::Tag(0x20,0x37) ); // Image Orientation (Patient) + s.Scan( dir.GetFilenames() ); + + //s.Print( std::cout ); + + // Count how many different IPP there are: + const gdcm::Scanner::ValuesType &values = s.GetValues(); + size_t nvalues = values.size(); + std::cout << "There are " << nvalues << " different type of values" << std::endl; + + //std::cout << "nfiles=" << nfiles << std::endl; + if( nfiles % nvalues != 0 ) + { + std::cerr << "Impossible: this is a not a proper series" << std::endl; + return 1; + } + std::cout << "Series is composed of " << (nfiles/nvalues) << " different 3D volumes" << std::endl; + + return 0; +} diff --git a/gdcm/Examples/Cxx/StreamImageReaderTest.cxx b/gdcm/Examples/Cxx/StreamImageReaderTest.cxx new file mode 100644 index 0000000..ad98810 --- /dev/null +++ b/gdcm/Examples/Cxx/StreamImageReaderTest.cxx @@ -0,0 +1,280 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +// This work was realised during the GSOC 2011 by Manoj Alwani + +#include "gdcmStreamImageReader.h" +#include "gdcmFileMetaInformation.h" +#include "gdcmSystem.h" +#include "gdcmFilename.h" +#include "gdcmByteSwap.h" +#include "gdcmTrace.h" +#include "gdcmTesting.h" +#include "gdcmImageHelper.h" +#include "gdcmImageReader.h" +#include "gdcmImage.h" +#include "gdcmMediaStorage.h" +#include "gdcmRAWCodec.h" +#include "gdcmJPEGLSCodec.h" +#include "gdcmUIDGenerator.h" +#include "gdcmStreamImageWriter.h" +#include "gdcmAttribute.h" +#include "gdcmFile.h" +#include "gdcmTag.h" + +bool StreamImageRead(gdcm::StreamImageWriter & theStreamWriter, + const char* filename, const char* outfilename, int resolution) +{ + gdcm::StreamImageReader reader; + + reader.SetFileName( filename ); + + if (!reader.ReadImageInformation()) + { + std::cerr << "unable to read image information" << std::endl; + return 1; //unable to read tags as expected. + } + //let's be tricky; each image will be read in portions, first the top half, then the bottom + //that way, we can test how the stream handles fragmentation of the data + //we could also loop this to get various different size combinations, but I'm not sure + //that's useful, yet. + std::vector extent = + gdcm::ImageHelper::GetDimensionsValue(reader.GetFile()); + // std::cout << extent[0]; + //at this point, these values aren't used, but may be in the future + //unsigned short xmin = 0; + //unsigned short xmax = extent[0]; + //unsigned short ymin = 0; + //unsigned short ymax = extent[1]; + //unsigned short zmin = 0; + //unsigned short zmax = extent[2]; + + std::cout<< "\n Row: "< Number_Of_Frames = {1}; + ds.Insert( Number_Of_Frames.GetAsDataElement() ); + + gdcm::Attribute<0x0028,0x0010> row = {extent[0]/a};// + ds.Insert( row.GetAsDataElement() ); + + gdcm::Attribute<0x0028,0x0011> col = {extent[1]/a};// + ds.Insert( col.GetAsDataElement() ); + + gdcm::Attribute<0x0028,0x0100> at = {8}; + ds.Insert( at.GetAsDataElement() ); + + gdcm::Attribute<0x0028,0x0002> at1 = {1};// + ds.Insert( at1.GetAsDataElement() ); + + gdcm::Attribute<0x0028,0x0101> at2 = {8}; + ds.Insert( at2.GetAsDataElement() ); + + gdcm::Attribute<0x0028,0x0102> at3 = {7}; + ds.Insert( at3.GetAsDataElement() ); + /* + ds1.Remove( gdcm::Tag(0x0028,0x0008) ); + + gdcm::Attribute<0x0028,0x0008> Number_Of_Frames = {1}; + ds1.Insert( Number_Of_Frames.GetAsDataElement() ); +*/ + theStreamWriter.SetFile(file); + + if (!theStreamWriter.WriteImageInformation()) + { + std::cerr << "unable to write image information" << std::endl; + return 1; //the CanWrite function should prevent getting here, else, + //that's a test failure + } + std::vector extent1 = gdcm::ImageHelper::GetDimensionsValue(file); + + unsigned short xmax = extent1[0]; + unsigned short ymax = extent1[1]; + unsigned short theChunkSize = 1; + unsigned short ychunk = extent1[1]/theChunkSize; //go in chunk sizes of theChunkSize + unsigned short zmax = 1; + + std::cout<< "\n Row: "< ymax) nexty = ymax; + theStreamWriter.DefinePixelExtent(0, xmax, y, nexty, z, z+1); + unsigned long len = theStreamWriter.DefineProperBufferLength(); + std::cout << "\n" < tags = gdcm::Anonymizer::GetBasicApplicationLevelConfidentialityProfileAttributes(); + for( std::vector::const_iterator tit = tags.begin(); tit != tags.end(); ++tit ) + { + const Tag &tag = *tit; + const DictEntry &dictentry = dicts.GetDictEntry(tag); + std::cout << "Processing Attribute: " << tag << " " << dictentry << std::endl; + + IODs::IODMapTypeConstIterator it = iods.Begin(); + for( ; it != iods.End(); ++it ) + { + const IODs::IODName &name = it->first; + const IOD &iod = it->second; + + const size_t niods = iod.GetNumberOfIODs(); + // Iterate over each iod entry in order: + for(unsigned int idx = 0; idx < niods; ++idx) + { + const IODEntry &iodentry = iod.GetIODEntry(idx); + const char *ref = iodentry.GetRef(); + //Usage::UsageType ut = iodentry.GetUsageType(); + + const Module &module = modules.GetModule( ref ); + if( module.FindModuleEntryInMacros(macros, tag ) ) + { + const ModuleEntry &module_entry = module.GetModuleEntryInMacros(macros,tag); + Type type = module_entry.GetType(); + std::cout << "IOD Name: " << name << std::endl; + std::cout << "Type: " << type << std::endl; + } + } + + } + } + + return 0; +} diff --git a/gdcm/Examples/Cxx/VolumeSorter.cxx b/gdcm/Examples/Cxx/VolumeSorter.cxx new file mode 100644 index 0000000..8aa377f --- /dev/null +++ b/gdcm/Examples/Cxx/VolumeSorter.cxx @@ -0,0 +1,198 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + */ +#include "gdcmSorter.h" +#include "gdcmIPPSorter.h" +#include "gdcmScanner.h" +#include "gdcmDataSet.h" +#include "gdcmAttribute.h" +#include "gdcmTesting.h" + + +bool mysort1(gdcm::DataSet const & ds1, gdcm::DataSet const & ds2 ) +{ + gdcm::Attribute<0x0020,0x000d> at1; + at1.Set( ds1 ); + gdcm::Attribute<0x0020,0x000d> at2; + at2.Set( ds2 ); + return at1 < at2; +} + +bool mysort2(gdcm::DataSet const & ds1, gdcm::DataSet const & ds2 ) +{ + gdcm::Attribute<0x0020,0x000e> at1; + at1.Set( ds1 ); + gdcm::Attribute<0x0020,0x000e> at2; + at2.Set( ds2 ); + return at1 < at2; +} + +bool mysort3(gdcm::DataSet const & ds1, gdcm::DataSet const & ds2 ) +{ + // This is a floating point number is the comparison ok ? + gdcm::Attribute<0x0020,0x0037> at1; + at1.Set( ds1 ); + gdcm::Attribute<0x0020,0x0037> at2; + at2.Set( ds2 ); + return at1 < at2; +} + +bool mysort4(gdcm::DataSet const & ds1, gdcm::DataSet const & ds2 ) +{ + // Do the IPP sorting here + gdcm::Attribute<0x0020,0x0032> ipp1; + gdcm::Attribute<0x0020,0x0037> iop1; + ipp1.Set( ds1 ); + iop1.Set( ds1 ); + gdcm::Attribute<0x0020,0x0032> ipp2; + gdcm::Attribute<0x0020,0x0037> iop2; + ipp2.Set( ds2 ); + iop2.Set( ds2 ); + if( iop1 != iop2 ) + { + return false; + } + + // else + double normal[3]; + normal[0] = iop1[1]*iop1[5] - iop1[2]*iop1[4]; + normal[1] = iop1[2]*iop1[3] - iop1[0]*iop1[5]; + normal[2] = iop1[0]*iop1[4] - iop1[1]*iop1[3]; + double dist1 = 0; + for (int i = 0; i < 3; ++i) dist1 += normal[i]*ipp1[i]; + double dist2 = 0; + for (int i = 0; i < 3; ++i) dist2 += normal[i]*ipp2[i]; + + std::cout << dist1 << "," << dist2 << std::endl; + return dist1 < dist2; + +} + + +int main(int argc, char *argv[]) +{ + const char *extradataroot = gdcm::Testing::GetDataExtraRoot(); + std::string dir1; + if( argc < 2 ) + { + if( !extradataroot ) + { + return 1; + } + dir1 = extradataroot; + dir1 += "/gdcmSampleData/ForSeriesTesting/VariousIncidences/ST1"; + } + else + { + dir1 = argv[1]; + } + + gdcm::Directory d; + d.Load( dir1.c_str(), true ); // recursive ! + const gdcm::Directory::FilenamesType &l1 = d.GetFilenames(); + const size_t nfiles = l1.size(); + std::cout << nfiles << std::endl; + + //if( nfiles != 280 ) + // { + // return 1; + // } + + //d.Print( std::cout ); + + gdcm::Scanner s0; + const gdcm::Tag t1(0x0020,0x000d); // Study Instance UID + const gdcm::Tag t2(0x0020,0x000e); // Series Instance UID + //const gdcm::Tag t3(0x0010,0x0010); // Patient's Name + s0.AddTag( t1 ); + s0.AddTag( t2 ); + //s0.AddTag( t3 ); + //s0.AddTag( t4 ); + //s0.AddTag( t5 ); + //s0.AddTag( t6 ); + bool b = s0.Scan( d.GetFilenames() ); + if( !b ) + { + std::cerr << "Scanner failed" << std::endl; + return 1; + } + + //s0.Print( std::cout ); + + // Only get the DICOM files: + gdcm::Directory::FilenamesType l2 = s0.GetKeys(); + const size_t nfiles2 = l2.size(); + std::cout << nfiles2 << std::endl; + + if ( nfiles2 > nfiles ) + { + return 1; + } + + + gdcm::Sorter sorter; + sorter.SetSortFunction( mysort1 ); + sorter.StableSort( l2 ); + + sorter.SetSortFunction( mysort2 ); + sorter.StableSort( sorter.GetFilenames() ); + + sorter.SetSortFunction( mysort3 ); + sorter.StableSort( sorter.GetFilenames() ); + + sorter.SetSortFunction( mysort4 ); + sorter.StableSort( sorter.GetFilenames() ); + + //sorter.Print( std::cout ); + + // Let's try to check our result: + // assume that IPP is precise enough so that we can test floating point equality: + size_t nvalues = 0; +{ + gdcm::Scanner s; + s.AddTag( gdcm::Tag(0x20,0x32) ); // Image Position (Patient) + //s.AddTag( gdcm::Tag(0x20,0x37) ); // Image Orientation (Patient) + s.Scan( d.GetFilenames() ); + + //s.Print( std::cout ); + + const gdcm::Scanner::ValuesType &values = s.GetValues(); + nvalues = values.size(); + std::cout << "There are " << nvalues << " different type of values" << std::endl; + assert( nfiles2 % nvalues == 0 ); + std::cout << "Series is composed of " << (nfiles/nvalues) << " different 3D volumes" << std::endl; +} + + gdcm::Directory::FilenamesType sorted_files = sorter.GetFilenames(); + + // Which means we can take nvalues files at a time and execute gdcm::IPPSorter on it: + gdcm::IPPSorter ippsorter; + gdcm::Directory::FilenamesType sub( sorted_files.begin(), sorted_files.begin() + nvalues); + std::cout << sub.size() << std::endl; + std::cout << sub[0] << std::endl; + std::cout << sub[nvalues-1] << std::endl; + ippsorter.SetComputeZSpacing( false ); + if( !ippsorter.Sort( sub ) ) + { + std::cerr << "Could not sort" << std::endl; + return 1; + } + + std::cout << "IPPSorter:" << std::endl; + ippsorter.Print( std::cout ); + + + return 0; +} diff --git a/gdcm/Examples/Cxx/csa2img.cxx b/gdcm/Examples/Cxx/csa2img.cxx new file mode 100644 index 0000000..9d0466a --- /dev/null +++ b/gdcm/Examples/Cxx/csa2img.cxx @@ -0,0 +1,156 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + * I do not know what the format is, just guessing from info found on the net: + * + * http://atonal.ucdavis.edu/matlab/fmri/spm5/spm_dicom_convert.m + * + * This example is an attempt at understanding the format used by SIEMENS + * their "SIEMENS CSA NON-IMAGE" DICOM file (1.3.12.2.1107.5.9.1) + * + * Everything done in this code is for the sole purpose of writing interoperable + * software under Sect. 1201 (f) Reverse Engineering exception of the DMCA. + * If you believe anything in this code violates any law or any of your rights, + * please contact us (gdcm-developers@lists.sourceforge.net) so that we can + * find a solution. + * + */ +#include "gdcmReader.h" +#include "gdcmImageReader.h" +#include "gdcmImageWriter.h" +#include "gdcmCSAHeader.h" +#include "gdcmAttribute.h" +#include "gdcmPrivateTag.h" + +#include + +int main(int argc, char *argv []) +{ + if( argc < 2 ) return 1; + // gdcmDataExtra/gdcmNonImageData/exCSA_Non-Image_Storage.dcm + // PHANTOM.MR.CARDIO_COEUR_S_QUENCE_DE_REP_RAGE.9.257.2008.03.20.14.53.25.578125.43151705.IMA + const char *filename = argv[1]; + + gdcm::Reader reader; // Do not use ImageReader + reader.SetFileName( filename ); + if( !reader.Read() ) + { + std::cerr << "Failed to read: " << filename << std::endl; + return 1; + } + + gdcm::CSAHeader csa; + const gdcm::DataSet& ds = reader.GetFile().GetDataSet(); + + const gdcm::PrivateTag &t1 = csa.GetCSAImageHeaderInfoTag(); + //std::cout << t1 << std::endl; + //const gdcm::PrivateTag &t2 = csa.GetCSASeriesHeaderInfoTag(); + + if( ds.FindDataElement( t1 ) ) + { + csa.LoadFromDataElement( ds.GetDataElement( t1 ) ); + csa.Print( std::cout ); + } + int dims[2] = {}; + if( csa.FindCSAElementByName( "Columns" ) ) + { + const gdcm::CSAElement &csael = csa.GetCSAElementByName( "Columns" ); + std::cout << csael << std::endl; + //const gdcm::ByteValue *bv = csael.GetByteValue(); + gdcm::Element el; + el.Set( csael.GetValue() ); + dims[0] = el.GetValue(); + std::cout << "Columns:" << el.GetValue() << std::endl; + } + + if( csa.FindCSAElementByName( "Rows" ) ) + { + const gdcm::CSAElement &csael2 = csa.GetCSAElementByName( "Rows" ); + std::cout << csael2 << std::endl; + gdcm::Element el2; + el2.Set( csael2.GetValue() ); + dims[1] = el2.GetValue(); + std::cout << "Rows:" << el2.GetValue() << std::endl; + } + + double spacing[2] = { 1. , 1. }; + bool spacingfound = false; + if( csa.FindCSAElementByName( "PixelSpacing" ) ) + { + const gdcm::CSAElement &csael3 = csa.GetCSAElementByName( "PixelSpacing" ); + if( !csael3.IsEmpty() ) + { + std::cout << csael3 << std::endl; + gdcm::Element el3; + el3.Set( csael3.GetValue() ); + spacing[0] = el3.GetValue(0); + spacing[1] = el3.GetValue(1); + std::cout << "PixelSpacing:" << el3.GetValue() << "," << el3.GetValue(1) << std::endl; + spacingfound = true; + } + } + + if( !spacingfound ) + { + std::cerr << "Problem with PixelSpacing" << std::endl; + //return 1; + } + if( !dims[0] || !dims[1] ) + { + std::cerr << "Problem with dims" << std::endl; + return 1; + } + + gdcm::ImageWriter writer; + + gdcm::Image &image = writer.GetImage(); + image.SetNumberOfDimensions( 2 ); // good default + image.SetDimension(0, dims[0] ); + image.SetDimension(1, dims[1] ); + image.SetSpacing(0, spacing[0] ); + image.SetSpacing(1, spacing[1] ); + gdcm::PixelFormat pixeltype = gdcm::PixelFormat::INT16; // bytepix = spm_type('int16','bits')/8; + + //unsigned long l = image.GetBufferLength(); + //const int p = l / (dims[0] * dims[1]); + + //image.SetNumberOfDimensions( 3 ); + //image.SetDimension(2, p / pixeltype.GetPixelSize() ); + + gdcm::PhotometricInterpretation pi; + pi = gdcm::PhotometricInterpretation::MONOCHROME2; + //pixeltype.SetSamplesPerPixel( ); + image.SetPhotometricInterpretation( pi ); + image.SetPixelFormat( pixeltype ); + //image.SetIntercept( inputimage.GetIntercept() ); + //image.SetSlope( inputimage.GetSlope() ); + + //gdcm::DataElement pixeldata( gdcm::Tag(0x7fe1,0x1010) ); + //pixeldata.SetByteValue( &outbuf[0], outbuf.size() ); + gdcm::PrivateTag csanonimaget(0x7fe1,0x10,"SIEMENS CSA NON-IMAGE"); + const gdcm::DataElement &pixeldata = ds.GetDataElement( csanonimaget ); + image.SetDataElement( pixeldata ); + + std::string outfilename = "outcsa.dcm"; + //writer.SetFile( reader.GetFile() ); + writer.SetFileName( outfilename.c_str() ); + if( !writer.Write() ) + { + std::cerr << "could not write: " << outfilename << std::endl; + return 1; + } + + + return 0; +} diff --git a/gdcm/Examples/Cxx/iU22tomultisc.cxx b/gdcm/Examples/Cxx/iU22tomultisc.cxx new file mode 100644 index 0000000..ff850e1 --- /dev/null +++ b/gdcm/Examples/Cxx/iU22tomultisc.cxx @@ -0,0 +1,100 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + * iU22 Raw Data extractor + */ +#include "gdcmReader.h" +#include "gdcmImageWriter.h" +#include "gdcmAttribute.h" +#include "gdcmPrivateTag.h" + +#include + +int main(int argc, char *argv []) +{ + if( argc < 2 ) return 1; + // IM_001 + const char *filename = argv[1]; + + gdcm::Reader reader; // Do not use ImageReader + reader.SetFileName( filename ); + if( !reader.Read() ) + { + std::cerr << "Failed to read: " << filename << std::endl; + return 1; + } + + // * The data is simply 8-bit unsigned in the obvious x/y/z order + // * 200D,300B contains the data + // * 200D,3001 contains the no. of voxels (416,412,256 in this case) + // * 200D,3003 contains the voxel sizes (0.156184527398215 / + // 0.1223749613981957 / 0.328479990704639 in this case) + + const gdcm::File &file = reader.GetFile(); + const gdcm::DataSet &ds = file.GetDataSet(); + const gdcm::PrivateTag trawdataus( 0x200d, 0x0b, "Philips US Imaging DD 033" ); + const gdcm::DataElement &rawdataus = ds.GetDataElement( trawdataus ); + + const gdcm::PrivateTag tcolsrowsframes( 0x200d, 0x01, "Philips US Imaging DD 036" ); + const gdcm::DataElement &colsrowsframes = ds.GetDataElement( tcolsrowsframes ); + // const gdcm::PrivateTag tcolsrowsframes( 0x200d, 0x02, "Philips US Imaging DD 036" ); + // this is just a duplicate previous tag. + const gdcm::PrivateTag tvoxelspacing( 0x200d, 0x03, "Philips US Imaging DD 036" ); + const gdcm::DataElement &voxelspacing = ds.GetDataElement( tvoxelspacing ); + + gdcm::Element dims; // Use DS to interpret value stored in LO + dims.SetFromDataElement( colsrowsframes ); + + gdcm::Element spacing; + spacing.SetFromDataElement( voxelspacing ); + + gdcm::ImageWriter writer; + + gdcm::Image &image = writer.GetImage(); + image.SetNumberOfDimensions( 3 ); // good default + image.SetDimension(0, (unsigned int)dims[0] ); + image.SetDimension(1, (unsigned int)dims[1] ); + image.SetDimension(2, (unsigned int)dims[2] ); + image.SetSpacing(0, spacing[0] ); + image.SetSpacing(1, spacing[1] ); + image.SetSpacing(2, spacing[2] ); + gdcm::PixelFormat pixeltype = gdcm::PixelFormat::UINT8; + + gdcm::PhotometricInterpretation pi; + pi = gdcm::PhotometricInterpretation::MONOCHROME2; + image.SetPhotometricInterpretation( pi ); + image.SetPixelFormat( pixeltype ); + + image.SetDataElement( rawdataus ); + + std::string outfilename = "outiu22.dcm"; + + gdcm::DataElement de( gdcm::Tag(0x8,0x16) ); // SOP Class UID + de.SetVR( gdcm::VR::UI ); + gdcm::MediaStorage ms( + gdcm::MediaStorage::UltrasoundMultiFrameImageStorage ); +// gdcm::MediaStorage::MultiframeGrayscaleByteSecondaryCaptureImageStorage ); + de.SetByteValue( ms.GetString(), (uint32_t)strlen(ms.GetString())); + writer.GetFile().GetDataSet().Replace( de ); + + writer.SetFileName( outfilename.c_str() ); + if( !writer.Write() ) + { + std::cerr << "could not write: " << outfilename << std::endl; + return 1; + } + + + return 0; +} diff --git a/gdcm/Examples/Cxx/pmsct_rgb1.cxx b/gdcm/Examples/Cxx/pmsct_rgb1.cxx new file mode 100644 index 0000000..0c3b821 --- /dev/null +++ b/gdcm/Examples/Cxx/pmsct_rgb1.cxx @@ -0,0 +1,257 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + * This example shows how to rewrite a ELSCINT1/PMSCT_RGB1 compressed + * image so that it is readable by most 3rd party software (DICOM does + * not specify this particular encoding). + * This is required for the sake of interoperability with any standard + * conforming DICOM system. + * + * Everything done in this code is for the sole purpose of writing interoperable + * software under Sect. 1201 (f) Reverse Engineering exception of the DMCA. + * If you believe anything in this code violates any law or any of your rights, + * please contact us (gdcm-developers@lists.sourceforge.net) so that we can + * find a solution. + * + * Everything you do with this code is at your own risk, since decompression + * algorithm was not written from specification documents. + * + * Special thanks to: + * Jean-Pierre Roux for providing the sample datasets + */ +#include "gdcmReader.h" +#include "gdcmPrivateTag.h" +#include "gdcmAttribute.h" +#include "gdcmImageWriter.h" + +void delta_decode(const unsigned char *data_in, size_t data_size, + std::vector &new_stream, unsigned short pc, size_t w, size_t h) +{ + const size_t plane_size = h * w; + const size_t outputlen = 3 * plane_size; + new_stream.resize( outputlen ); + + assert( data_size != outputlen ); + if( data_size == outputlen ) + { + return; + } + typedef unsigned char byte; + enum { + COLORMODE = 0x81, + ESCMODE = 0x82, + REPEATMODE = 0x83 + }; + + byte* src = (byte*)data_in; + byte* dest = (byte*)&new_stream[0]; + union { byte gray; byte rgb[3]; } pixel; + pixel.rgb[0] = pixel.rgb[1] = pixel.rgb[2] = 0; + // always start in grayscale mode + bool graymode = true; + size_t dx = 1; + size_t dy = 3; + // algorithm works with both planar configuration + // It does produce surprising greenish background color for planar + // configuration is 0, while the nested Icon SQ display a nice black + // background + if (pc) + { + dx = plane_size; + dy = 1; + } + size_t ps = plane_size; + + // The following is highly unoptimized as we have nested if statement in a while loop + // we need to switch from one algorithm to ther other (RGB <-> GRAY) + while (ps) + { + // next byte: + byte b = *src++; + assert( src < data_in + data_size ); + // mode selection: + switch ( b ) + { + case ESCMODE: + // Used to treat a byte 81/82/83 as a normal byte + if (graymode) + { + pixel.gray += *src++; + dest[0*dx] = pixel.gray; + dest[1*dx] = pixel.gray; + dest[2*dx] = pixel.gray; + } + else + { + pixel.rgb[0] += *src++; + pixel.rgb[1] += *src++; + pixel.rgb[2] += *src++; + dest[0*dx] = pixel.rgb[0]; + dest[1*dx] = pixel.rgb[1]; + dest[2*dx] = pixel.rgb[2]; + } + dest += dy; + ps--; + break; + case REPEATMODE: + // repeat mode (RLE) + b = *src++; + ps -= b; + if (graymode) + { + while (b-- > 0) + { + dest[0*dx] = pixel.gray; + dest[1*dx] = pixel.gray; + dest[2*dx] = pixel.gray; + dest += dy; + } + } + else + { + while (b-- > 0) + { + dest[0*dx] = pixel.rgb[0]; + dest[1*dx] = pixel.rgb[1]; + dest[2*dx] = pixel.rgb[2]; + dest += dy; + } + } + break; + case COLORMODE: + // We are swithing from one mode to the other. The stream contains an intermixed + // compression of RGB codec and GRAY codec. Each one not knowing of the other + // reset old value to 0. + if (graymode) + { + graymode = false; + pixel.rgb[0] = pixel.rgb[1] = pixel.rgb[2] = 0; + } + else + { + graymode = true; + pixel.gray = 0; + } + break; + default: + // This is identical to ESCMODE, it would be nicer to use fall-through + if (graymode) + { + pixel.gray += b; + dest[0*dx] = pixel.gray; + dest[1*dx] = pixel.gray; + dest[2*dx] = pixel.gray; + } + else + { + pixel.rgb[0] += b; + pixel.rgb[1] += *src++; + pixel.rgb[2] += *src++; + dest[0*dx] = pixel.rgb[0]; + dest[1*dx] = pixel.rgb[1]; + dest[2*dx] = pixel.rgb[2]; + } + dest += dy; + ps--; + break; + } // end switch + } // end while +} + +int main(int argc, char *argv []) +{ + if( argc < 2 ) return 1; + const char *filename = argv[1]; + gdcm::Reader reader; + reader.SetFileName( filename ); + if( !reader.Read() ) + { + std::cerr << "Failed to read: " << filename << std::endl; + return 1; + } + const gdcm::DataSet& ds = reader.GetFile().GetDataSet(); + + // (07a1,1011) CS [PMSCT_RGB1] # 10,1 Tamar Compression Type + const gdcm::PrivateTag tcompressiontype(0x07a1,0x0011,"ELSCINT1"); + if( !ds.FindDataElement( tcompressiontype ) ) return 1; + const gdcm::DataElement& compressiontype = ds.GetDataElement( tcompressiontype ); + if ( compressiontype.IsEmpty() ) return 1; + const gdcm::ByteValue * bv = compressiontype.GetByteValue(); + std::string comprle = "PMSCT_RLE1"; + std::string comprgb = "PMSCT_RGB1"; + bool isrle = false; + bool isrgb = false; + if( strncmp( bv->GetPointer(), comprle.c_str(), comprle.size() ) == 0 ) + { + isrle = true; + return 1; + } + if( strncmp( bv->GetPointer(), comprgb.c_str(), comprgb.size() ) == 0 ) + { + isrgb = true; + } + if( !isrgb && !isrle ) return 1; + + const gdcm::PrivateTag tcompressedpixeldata(0x07a1,0x000a,"ELSCINT1"); + if( !ds.FindDataElement( tcompressedpixeldata) ) return 1; + const gdcm::DataElement& compressionpixeldata = ds.GetDataElement( tcompressedpixeldata); + if ( compressionpixeldata.IsEmpty() ) return 1; + const gdcm::ByteValue * bv2 = compressionpixeldata.GetByteValue(); + + gdcm::Attribute<0x0028,0x0006> at0; + at0.SetFromDataSet( ds ); + gdcm::Attribute<0x0028,0x0010> at1; + at1.SetFromDataSet( ds ); + gdcm::Attribute<0x0028,0x0011> at2; + at2.SetFromDataSet( ds ); + + std::vector buffer; + delta_decode((const unsigned char*)bv2->GetPointer(), bv2->GetLength(), buffer, + at0.GetValue(), at1.GetValue(), at2.GetValue() ); + + gdcm::DataElement pixeldata( gdcm::Tag(0x7fe0,0x0010) ); + pixeldata.SetVR( gdcm::VR::OW ); + pixeldata.SetByteValue( (char*)&buffer[0], (uint32_t)buffer.size() ); + // TODO we should check that decompress byte buffer match the expected size (row*col*...) + + // Add the pixel data element + reader.GetFile().GetDataSet().Replace( pixeldata ); + + reader.GetFile().GetHeader().SetDataSetTransferSyntax( + gdcm::TransferSyntax::ExplicitVRLittleEndian); + gdcm::Writer writer; + writer.SetFile( reader.GetFile() ); + + // Cleanup stuff: + // remove the compressed pixel data: + // FIXME: should I remove more private tags ? all of them ? + // oh well this is just an example + // use gdcm::Anonymizer::RemovePrivateTags if needed... + writer.GetFile().GetDataSet().Remove( compressionpixeldata.GetTag() ); + std::string outfilename; + if (argc > 2) + outfilename = argv[2]; + else + outfilename = "outrgb.dcm"; + writer.SetFileName( outfilename.c_str() ); + if( !writer.Write() ) + { + std::cerr << "Failed to write" << std::endl; + return 1; + } + + std::cout << "success !" << std::endl; + + return 0; +} diff --git a/gdcm/Examples/Cxx/rle2img.cxx b/gdcm/Examples/Cxx/rle2img.cxx new file mode 100644 index 0000000..6264744 --- /dev/null +++ b/gdcm/Examples/Cxx/rle2img.cxx @@ -0,0 +1,201 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + * This example shows how to rewrite a ELSCINT1/PMSCT_RLE1 compressed + * image so that it is readable by most 3rd party software (DICOM does + * not specify this particular encoding). + * This is required for the sake of interoperability with any standard + * conforming DICOM system. + * + * Everything done in this code is for the sole purpose of writing interoperable + * software under Sect. 1201 (f) Reverse Engineering exception of the DMCA. + * If you believe anything in this code violates any law or any of your rights, + * please contact us (gdcm-developers@lists.sourceforge.net) so that we can + * find a solution. + * + * Everything you do with this code is at your own risk, since decompression + * algorithm was not written from specification documents. + * + * Special thanks to: + * Mauro Maiorca for bringing to our attention on this new ELSCINT1 + * compression algorithm : PMSCT_RLE1 (different from the 'LOSSLESS RICE') + * See post at: + * http://groups.google.com/group/comp.protocols.dicom/msg/f2b99bf706a7f8ca + * + * Thanks to Jesus Spinola, for more datasets, + * http://www.itk.org/pipermail/insight-users/2008-April/025571.html + * + * And last but not least, a very big thank to Ivo van Poorten, without + * whom we would still be looking at this compressed byte stream as if + * it was RLE compressed. + */ +#include "gdcmReader.h" +#include "gdcmPrivateTag.h" +#include "gdcmAttribute.h" +#include "gdcmImageWriter.h" + +/* FIXME: Why is PhilipsLosslessRice.dcm a 512x512 image ... */ +void delta_decode(const char *inbuffer, size_t length, std::vector &output) +{ + // RLE pass + std::vector temp; + for(size_t i = 0; i < length; ++i) + { + if( inbuffer[i] == (char)0xa5 ) + { + //unsigned char repeat = (unsigned char)inbuffer[i+1] + 1; + //assert( (unsigned char)inbuffer[i+1] != 255 ); + int repeat = (unsigned char)inbuffer[i+1] + 1; + char value = inbuffer[i+2]; + while(repeat) + { + temp.push_back( value ); + --repeat; + } + i+=2; + } + else + { + temp.push_back( inbuffer[i] ); + } + } + + // Delta encoding pass + unsigned short delta = 0; + for(size_t i = 0; i < temp.size(); ++i) + { + if( temp[i] == 0x5a ) + { + unsigned char v1 = (unsigned char)temp[i+1]; + unsigned char v2 = (unsigned char)temp[i+2]; + unsigned short value = (unsigned short)(v2 * 256 + v1); + output.push_back( value ); + delta = value; + i+=2; + } + else + { + unsigned short value = (unsigned short)(temp[i] + delta); + output.push_back( value ); + delta = value; + } + //assert( output[output.size()-1] == ref[output.size()-1] ); + } + + if ( output.size() % 2 ) + { + output.resize( output.size() - 1 ); + } + std::cout << length << " -> " << output.size() * 2 << std::endl; +} + +int main(int argc, char *argv []) +{ + if( argc < 2 ) + { + std::cerr << argv[0] << "input.dcm [output.dcm]" << std::endl; + std::cerr << "will default to 'outrle.dcm' unless output.dcm is specified." + << std::endl; + return 1; + } + const char *filename = argv[1]; + gdcm::Reader reader; + reader.SetFileName( filename ); + if( !reader.Read() ) + { + std::cerr << "Failed to read: " << filename << std::endl; + return 1; + } + const gdcm::DataSet& ds = reader.GetFile().GetDataSet(); + + // (07a1,1011) CS [PMSCT_RLE1] # 10,1 Tamar Compression Type + const gdcm::PrivateTag tcompressiontype(0x07a1,0x0011,"ELSCINT1"); + if( !ds.FindDataElement( tcompressiontype ) ) return 1; + const gdcm::DataElement& compressiontype = ds.GetDataElement( tcompressiontype ); + if ( compressiontype.IsEmpty() ) return 1; + const gdcm::ByteValue * bv = compressiontype.GetByteValue(); + std::string comprle = "PMSCT_RLE1"; + std::string comprgb = "PMSCT_RGB1"; + bool isrle = false; + bool isrgb = false; + if( strncmp( bv->GetPointer(), comprle.c_str(), comprle.size() ) == 0 ) + { + isrle = true; + } + if( strncmp( bv->GetPointer(), comprgb.c_str(), comprgb.size() ) == 0 ) + { + isrgb = true; + std::cerr << "See: pmsct_rgb1.cxx instead" << std::endl; + return 1; + } + if( !isrgb && !isrle ) return 1; + + const gdcm::PrivateTag tcompressedpixeldata(0x07a1,0x000a,"ELSCINT1"); + if( !ds.FindDataElement( tcompressedpixeldata) ) return 1; + const gdcm::DataElement& compressionpixeldata = ds.GetDataElement( tcompressedpixeldata); + if ( compressionpixeldata.IsEmpty() ) return 1; + const gdcm::ByteValue * bv2 = compressionpixeldata.GetByteValue(); + + gdcm::Attribute<0x0028,0x0010> at1; + at1.SetFromDataSet( ds ); + gdcm::Attribute<0x0028,0x0011> at2; + at2.SetFromDataSet( ds ); + + gdcm::DataElement pixeldata( gdcm::Tag(0x7fe0,0x0010) ); + pixeldata.SetVR( gdcm::VR::OW ); + gdcm::VL bv2l = bv2->GetLength(); + gdcm::VL at1l = at1.GetValue() * at2.GetValue() * 2; /* sizeof(unsigned short) == 2 */ + // Handle special case that is not compressed: + if( bv2l == at1l ) + { + pixeldata.SetByteValue( bv2->GetPointer(), bv2->GetLength() ); + } + else + { + std::vector buffer; + delta_decode(bv2->GetPointer(), bv2->GetLength(), buffer); + pixeldata.SetByteValue( (char*)&buffer[0], (uint32_t)(buffer.size() * sizeof( unsigned short )) ); + } + // TODO we should check that decompress byte buffer match the expected size (row*col*...) + + // Add the pixel data element + reader.GetFile().GetDataSet().Replace( pixeldata ); + + reader.GetFile().GetHeader().SetDataSetTransferSyntax( + gdcm::TransferSyntax::ExplicitVRLittleEndian); + gdcm::Writer writer; + writer.SetFile( reader.GetFile() ); + + // Cleanup stuff: + // remove the compressed pixel data: + // FIXME: should I remove more private tags ? all of them ? + // oh well this is just an example + // use gdcm::Anonymizer::RemovePrivateTags if needed... + writer.GetFile().GetDataSet().Remove( compressionpixeldata.GetTag() ); + std::string outfilename; + if (argc > 2) + outfilename = argv[2]; + else + outfilename = "outrle.dcm"; + writer.SetFileName( outfilename.c_str() ); + if( !writer.Write() ) + { + std::cerr << "Failed to write" << std::endl; + return 1; + } + + std::cout << "success !" << std::endl; + + return 0; +} diff --git a/gdcm/Examples/Cxx/uid_unique.cxx b/gdcm/Examples/Cxx/uid_unique.cxx new file mode 100644 index 0000000..21f0117 --- /dev/null +++ b/gdcm/Examples/Cxx/uid_unique.cxx @@ -0,0 +1,54 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmUIDGenerator.h" + +#include +#include +#include + +/** + This is a toy program just to check how good the UID are uniq. + The rule of thumb is that you should not have a long Root UID otherwise the + algorithm might find twice the same UID... + */ +int main() +{ + gdcm::UIDGenerator uid; + //const char myroot[] = "9876543210.9876543210.9876543210.9876543210.9876543210"; // fails in ~40000 tries + const char myroot[] = "9876543210.9876543210.9876543210"; + uid.SetRoot( myroot ); + std::set uids; + uint64_t wrap = 0; + uint64_t c = 0; + while(1) + { + const char *unique = uid.Generate(); + //std::cout << unique << std::endl; + if( c % 10000 == 0 ) + { + std::cout << "wrap=" << wrap << ",c=" << c << std::endl; + } + ++c; + if( c == 0 ) + { + wrap++; + } + if ( uids.count(unique) == 1 ) + { + std::cerr << "Failed with: " << unique << std::endl; + return 1; + } + uids.insert( unique ); + } +} diff --git a/gdcm/Examples/Java/CMakeLists.txt b/gdcm/Examples/Java/CMakeLists.txt new file mode 100644 index 0000000..1f25f2d --- /dev/null +++ b/gdcm/Examples/Java/CMakeLists.txt @@ -0,0 +1,44 @@ +find_package(Java REQUIRED) # javac, jar +find_package(JNI REQUIRED) +include_directories( + #${JNI_INCLUDE_PATH} + ${JAVA_INCLUDE_PATH} + ${JAVA_INCLUDE_PATH2} + ${JAVA_AWT_INCLUDE_PATH} + ) + +set(classfilesdep) +set(examples + HelloSimple + ExtractImageRegion + DecompressPixmap + DecompressImage + ScanDirectory + ReadFiles + FileAnonymize + ) +foreach(example ${examples}) + add_custom_command( + OUTPUT ${EXECUTABLE_OUTPUT_PATH}/${example}.class + COMMAND ${Java_JAVAC_EXECUTABLE} ARGS -source 1.5 -target 1.5 ${CMAKE_CURRENT_SOURCE_DIR}/${example}.java -d ${EXECUTABLE_OUTPUT_PATH} -classpath ${LIBRARY_OUTPUT_PATH}/gdcm.jar + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${example}.java + COMMENT "javac ${example}.java" + ) + list(APPEND classfilesdep ${EXECUTABLE_OUTPUT_PATH}/${example}.class) +endforeach() + +# 3. ok now add the target +add_custom_target(GDCMJavaExample ALL + DEPENDS ${classfilesdep} + COMMENT "building gdcm java example" +) +# make sure gdcm.jar is built +add_dependencies(GDCMJavaExample GDCMJavaJar) + +if(BUILD_TESTING) + if(GDCM_DATA_ROOT) + set_source_files_properties(${EXECUTABLE_OUTPUT_PATH}/HelloSimple.class PROPERTIES CLASSPATH "${EXECUTABLE_OUTPUT_PATH}/gdcm.jar") + ADD_JAVA_TEST(TestHelloSimpleJava ${EXECUTABLE_OUTPUT_PATH}/HelloSimple ${GDCM_DATA_ROOT}/012345.002.050.dcm) + endif() +endif() diff --git a/gdcm/Examples/Java/DecompressImage.java b/gdcm/Examples/Java/DecompressImage.java new file mode 100644 index 0000000..d921af8 --- /dev/null +++ b/gdcm/Examples/Java/DecompressImage.java @@ -0,0 +1,66 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +/* + * This example will take in a DICOM file, and tries to decompress it (actually write it + * as ImplicitVRLittleEndian Transfer Syntax). + * + * Compilation: + * $ CLASSPATH=gdcm.jar javac ../../gdcm/Examples/Java/DecompressImage.java -d . + * + * Usage: + * $ LD_LIBRARY_PATH=. CLASSPATH=gdcm.jar:. java DecompressImage gdcmData/012345.002.050.dcm out.dcm + */ +import gdcm.*; + +public class DecompressImage +{ + public static void main(String[] args) throws Exception + { + String file1 = args[0]; + String file2 = args[1]; + ImageReader reader = new ImageReader(); + reader.SetFileName( file1 ); + boolean ret = reader.Read(); + if( !ret ) + { + throw new Exception("Could not read: " + file1 ); + } + + ImageChangeTransferSyntax change = new ImageChangeTransferSyntax(); + change.SetTransferSyntax( new TransferSyntax(TransferSyntax.TSType.ImplicitVRLittleEndian) ); + change.SetInput( reader.GetImage() ); + if( !change.Change() ) + { + throw new Exception("Could not change: " + file1 ); + } + + Image out = change.GetOutput(); + System.out.println( out.toString() ); + + // Set the Source Application Entity Title + FileMetaInformation.SetSourceApplicationEntityTitle( "Just For Fun" ); + + ImageWriter writer = new ImageWriter(); + writer.SetFileName( file2 ); + writer.SetFile( reader.GetFile() ); + writer.SetImage( out ); + ret = writer.Write(); + if( !ret ) + { + throw new Exception("Could not write: " + file2 ); + } + + } +} diff --git a/gdcm/Examples/Java/DecompressPixmap.java b/gdcm/Examples/Java/DecompressPixmap.java new file mode 100644 index 0000000..7e15f6f --- /dev/null +++ b/gdcm/Examples/Java/DecompressPixmap.java @@ -0,0 +1,69 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +/* + * This example will take in a DICOM file, and tries to decompress it (actually write it + * as ImplicitVRLittleEndian Transfer Syntax). + * + * Compilation: + * $ CLASSPATH=gdcm.jar javac ../../gdcm/Examples/Java/DecompressPixmap.java -d . + * + * Usage: + * $ LD_LIBRARY_PATH=. CLASSPATH=gdcm.jar:. java DecompressPixmap gdcmData/012345.002.050.dcm out.dcm + */ +import gdcm.*; + +public class DecompressPixmap +{ + public static void main(String[] args) throws Exception + { + String file1 = args[0]; + String file2 = args[1]; + PixmapReader reader = new PixmapReader(); + reader.SetFileName( file1 ); + boolean ret = reader.Read(); + if( !ret ) + { + throw new Exception("Could not read: " + file1 ); + } + + ImageChangeTransferSyntax change = new ImageChangeTransferSyntax(); + change.SetTransferSyntax( new TransferSyntax(TransferSyntax.TSType.ImplicitVRLittleEndian) ); + PixmapToPixmapFilter filter = (PixmapToPixmapFilter)change; + filter.SetInput( reader.GetPixmap() ); + if( !change.Change() ) + { + throw new Exception("Could not change: " + file1 ); + } + + // The following does not work in Java/swig 2.0.7 + //Pixmap p = ((PixmapToPixmapFilter)change).GetOutput(); + Pixmap p = change.GetOutputAsPixmap(); // be explicit + //System.out.println( p.toString() ); + + // Set the Source Application Entity Title + FileMetaInformation.SetSourceApplicationEntityTitle( "Just For Fun" ); + + PixmapWriter writer = new PixmapWriter(); + writer.SetFileName( file2 ); + writer.SetFile( reader.GetFile() ); + writer.SetImage( p ); + ret = writer.Write(); + if( !ret ) + { + throw new Exception("Could not write: " + file2 ); + } + + } +} diff --git a/gdcm/Examples/Java/ExtractImageRegion.java b/gdcm/Examples/Java/ExtractImageRegion.java new file mode 100644 index 0000000..77b0478 --- /dev/null +++ b/gdcm/Examples/Java/ExtractImageRegion.java @@ -0,0 +1,78 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +/* + * This small code shows how to use the gdcm.ImageRegionReader API + * In this example we are taking each frame by frame and dump them to + * /tmp/frame.raw. + * + * Usage: + * $ LD_LIBRARY_PATH=. CLASSPATH=gdcm.jar:. java ExtractImageRegion input.dcm + */ +import gdcm.*; +import java.io.FileOutputStream; + +public class ExtractImageRegion +{ + public static void main(String[] args) throws Exception + { + String filename = args[0]; + + // instantiate the reader: + ImageRegionReader reader = new ImageRegionReader(); + reader.SetFileName( filename ); + + // pull DICOM info: + if (!reader.ReadInformation()) return; + // Get file infos + File f = reader.GetFile(); + + // get some info about image + UIntArrayType dims = ImageHelper.GetDimensionsValue(f); + PixelFormat pf = ImageHelper.GetPixelFormatValue (f); + int pixelsize = pf.GetPixelSize(); + + // buffer to get the pixels + long buffer_length = dims.get(0) * dims.get(1) * pixelsize; + byte[] buffer = new byte[ (int)buffer_length ]; + + // define a simple box region. + BoxRegion box = new BoxRegion(); + for (int z = 0; z < dims.get(2); z++) + { + // Define that I want the image 0, full size (dimx x dimy pixels) + // and do that for each z: + box.SetDomain(0, dims.get(0) - 1, 0, dims.get(1) - 1, z, z); + //System.Console.WriteLine( box.toString() ); + reader.SetRegion( box ); + + // reader will try to load the uncompressed image region into buffer. + // the call returns an error when buffer.Length is too small. For instance + // one can call: + // long buf_len = reader.ComputeBufferLength(); // take into account pixel size + // to get the exact size of minimum buffer + if (reader.ReadIntoBuffer(buffer, buffer_length)) + { + FileOutputStream fos = new FileOutputStream("/tmp/frame.raw"); + fos.write(buffer); + fos.close(); + } + else + { + throw new Exception("can't read pixels error"); + } + } + + } +} diff --git a/gdcm/Examples/Java/FileAnonymize.java b/gdcm/Examples/Java/FileAnonymize.java new file mode 100644 index 0000000..5e571d2 --- /dev/null +++ b/gdcm/Examples/Java/FileAnonymize.java @@ -0,0 +1,63 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +/** + * Usage: + * $ LD_LIBRARY_PATH=. CLASSPATH=gdcm.jar:. java FileAnonymize input.dcm output.dcm + */ +import gdcm.*; + +public class FileAnonymize +{ + public static class MyWatcher extends SimpleSubjectWatcher + { + public MyWatcher(Subject s) { super(s,"Override String"); } + protected void ShowProgress(Subject caller, Event evt) + { + ProgressEvent pe = ProgressEvent.Cast(evt); + System.out.println( "This is my progress: " + pe.GetProgress() ); + } + } + + public static void main(String[] args) throws Exception + { + String input = args[0]; + String output = args[1]; + + FileAnonymizer fa = new FileAnonymizer(); + fa.SetInputFileName( input ); + fa.SetOutputFileName( output ); + + // Empty Operations + // It will create elements, since those tags are non-registered public elements (2011): + fa.Empty( new Tag(0x0008,0x1313) ); + fa.Empty( new Tag(0x0008,0x1317) ); + // Remove Operations + // The following Tag are actually carefully chosen, since they refer to SQ: + fa.Remove( new Tag(0x0008,0x2112) ); + fa.Remove( new Tag(0x0008,0x9215) ); + // Replace Operations + // do not call replace operation on SQ attribute ! + fa.Replace( new Tag(0x0018,0x5100), "MYVALUE " ); + fa.Replace( new Tag(0x0008,0x1160), "MYOTHERVAL" ); + + if( !fa.Write() ) + { + System.out.println( "Could not write" ); + return; + } + + System.out.println( "success" ); + } +} diff --git a/gdcm/Examples/Java/HelloSimple.java b/gdcm/Examples/Java/HelloSimple.java new file mode 100644 index 0000000..8352880 --- /dev/null +++ b/gdcm/Examples/Java/HelloSimple.java @@ -0,0 +1,42 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + * Compilation: + * $ CLASSPATH=gdcm.jar javac ../../gdcm/Examples/Java/HelloSimple.java -d . + * + * Usage: + * $ LD_LIBRARY_PATH=. CLASSPATH=gdcm.jar:. java HelloSimple gdcmData/012345.002.050.dcm + */ +import gdcm.*; + +public class HelloSimple +{ + public static void main(String[] args) throws Exception + { + String filename = args[0]; + Reader reader = new Reader(); + reader.SetFileName( filename ); + boolean ret = reader.Read(); + if( !ret ) + { + throw new Exception("Could not read: " + filename ); + } + File f = reader.GetFile(); + DataSet ds = f.GetDataSet(); + + System.out.println( ds.toString() ); + + System.out.println("Success reading: " + filename ); + } +} diff --git a/gdcm/Examples/Java/ReadFiles.java b/gdcm/Examples/Java/ReadFiles.java new file mode 100644 index 0000000..6eff3d3 --- /dev/null +++ b/gdcm/Examples/Java/ReadFiles.java @@ -0,0 +1,106 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/** + * Simple example showing that Jav UTF-16 string are properly passed to + * GDCM layer as locale 8bits + * This example also explain the use of try {} finally {} in java to + * make sure the C++ RAII design of gdcm.Reader is properly used from + * Java and does not leak opened file destructor. + * + * Compilation: + * $ CLASSPATH=gdcm.jar javac ../../gdcm/Examples/Java/ReadFiles.java -d . + * + * Usage: + * $ LD_LIBRARY_PATH=. CLASSPATH=gdcm.jar:. java ReadFiles gdcmData + */ +import gdcm.*; +import java.io.File; + +public class ReadFiles +{ + static int i = 0; + public static void process(String path) + { + //String path = file.getPath(); + assert PosixEmulation.FileExists(path) : "Problem converting to 8bits"; + + System.out.println("Reading: " + path ); + System.out.println("File: " + i++); + Reader r = new Reader(); + try + { + r.SetFileName( path ); + TagSetType skip = new TagSetType(); + skip.insert( new Tag(0x7fe0,0x10) ); + boolean b = r.ReadUpToTag( new Tag(0x88,0x200), skip ); + //System.out.println("DS:\n" + r.GetFile().GetDataSet().toString() ); + } + finally + { + r.delete(); // will properly call C++ destructor and close file descriptor + } + } + + // Process only files under dir + public static void visitAllFiles(File dir) + { + if (dir.isDirectory()) + { + String[] children = dir.list(); + for (int i=0; iSetFilename( "test.dcm" ); +if( !$reader->Read() ) +{ +return; +} + +$file = $reader->GetFile(); +$pixmap = $reader->GetPixmap(); + +print $pixmap; + +$pnm = new PNMCodec(); +$pnm->SetDimensions( $pixmap->GetDimensions() ); +$pnm->SetPixelFormat( $pixmap->GetPixelFormat() ); +$pnm->SetPhotometricInterpretation( $pixmap->GetPhotometricInterpretation() ); +$in = $pixmap->GetDataElement(); +$outfilename = 'test.pnm'; +if( $pnm->Write( $outfilename, $in ) ) +{ +print "Success"; +} + +?> diff --git a/gdcm/Examples/PHP/hello_world.php b/gdcm/Examples/PHP/hello_world.php new file mode 100644 index 0000000..c8698d1 --- /dev/null +++ b/gdcm/Examples/PHP/hello_world.php @@ -0,0 +1,86 @@ +SetFilename( "test.dcm" ); +$ret=$reader->Read(); +if( !$ret ) +{ + return 1; +} + +$file = $reader->GetFile(); +// The output of gdcm::Reader is a gdcm::File + +// the dataset is the the set of element we are interested in: +$ds = $file->GetDataSet(); +print_r($ds); +$g = c_Global::getInstance(); + +$dicts = $g->GetDicts(); +$pubdict = $dicts->GetPublicDict(); + +// In this example we will show why using name to lookup attribute can be +// dangerous. +$tPatientName= new Tag(0x0,0x0); +$de1 = $pubdict->GetDictEntryByName("Patient Name", $tPatientName); + +printf("Found %s",$tPatientName); + +// Indeed the attribute could not be found. Since DICOM 2003, Patient Name +// has become Patient's Name. + +$tPatientsName = new Tag(); +$de2 = $pubdict->GetDictEntryByName("Patient's Name", $tPatientsName); + +printf("Found: %s",$tPatientsName); + +// Let's try to read an arbitrary DICOM Attribute: +$tDoseGridScaling=new Tag(); +$de3 = $pubdict->GetDictEntryByName("Dose Grid Scaling", $tDoseGridScaling); + +printf("Found: %s",$tDoseGridScaling); + +if( $ds->FindDataElement( $tDoseGridScaling ) ) +{ + $sf= new StringFilter(); + $sf->SetFile($file); + printf("Attribute Value as String: %s",$sf->ToString( $tDoseGridScaling )); + + // Let's check the name again: + $pss = $sf->ToStringPair( $tDoseGridScaling ); + printf("Attribute Name Checked: %s", $pss->first); + printf("Attribute Value (string): %s", $pss->second); + + $dgs = $ds->GetDataElement( $tDoseGridScaling ); + + // Let's assume for a moment we knew the tag number: + $at=new Tag(0x3004,0x000e); + assert( $at.GetTag() == $tDoseGridScaling ); + $at->SetFromDataSet( $ds ); + // For the sake of long term maintenance, we will not write + // that this particular attribute is stored as a double. What if + // a user made a mistake. It is much safer to rely on GDCM internal + // mechanism to deduce the VR::DS type (represented as a ieee double) + $v = $at->GetValue(); + printf("DoseGridScaling=%s",$v); +} + +?> diff --git a/gdcm/Examples/PHP/modify_file.php b/gdcm/Examples/PHP/modify_file.php new file mode 100644 index 0000000..e6781e9 --- /dev/null +++ b/gdcm/Examples/PHP/modify_file.php @@ -0,0 +1,52 @@ +SetFilename( "test.dcm" ); +$ret=$reader->Read(); +if( !$ret ) +{ + return 1; +} + +$file = $reader->GetFile(); +$ano = new Anonymizer(); +$ano->SetFile($file); +$ano->RemovePrivateTags(); +$ano->RemoveGroupLength(); +$t = new Tag(0x10,0x10); +$ano->Replace( $t, "GDCM^PHP^Test^Hello^World" ); + +$g = new UIDGenerator(); +$ano->Replace( new Tag(0x0008,0x0018), $g->Generate() ); +$ano->Replace( new Tag(0x0020,0x000d), $g->Generate() ); +$ano->Replace( new Tag(0x0020,0x000e), $g->Generate() ); +$ano->Replace( new Tag(0x0020,0x0052), $g->Generate() ); + +$writer = new Writer(); +$writer->SetFileName( "test2.dcm" ); +$writer->SetFile( $ano->GetFile() ); +$ret = $writer->Write(); +if( !$ret ) +{ + return 1; +} + +?> diff --git a/gdcm/Examples/PHP/qido.php b/gdcm/Examples/PHP/qido.php new file mode 100644 index 0000000..2781808 --- /dev/null +++ b/gdcm/Examples/PHP/qido.php @@ -0,0 +1,42 @@ +SetHostname( $remote ); +$scu->SetPort( $portno ); +$scu->SetTimeout( 1000 ); +//$scu->SetCalledAETitle( "GDCM_STORE" ); +$scu->InitializeConnection(); +$generator = new PresentationContextGenerator(); +$generator->GenerateFromUID( UIDs::VerificationSOPClass ); +$scu->SetPresentationContexts( $generator->GetPresentationContexts() ); +$scu->StartAssociation(); +$scu->SendEcho(); +$scu->StopAssociation(); + +$findds = new DataSet(); +$findquery = CompositeNetworkFunctions::ConstructQuery( + eStudyRootType, eStudy, $findds); + +// https://sourceforge.net/p/swig/bugs/1337/ +// https://sourceforge.net/p/swig/bugs/1338/ +// https://sourceforge.net/p/swig/bugs/1339/ + +?> diff --git a/gdcm/Examples/PHP/rewrite_header.php b/gdcm/Examples/PHP/rewrite_header.php new file mode 100644 index 0000000..ce85a1c --- /dev/null +++ b/gdcm/Examples/PHP/rewrite_header.php @@ -0,0 +1,37 @@ +SetFilename( "test.dcm" ); +$reader->Read(); + +$file = $reader->GetFile(); + +$header = $file->GetHeader(); +$header->Clear(); + +$writer = new Writer(); +$writer->SetFilename( "test2.dcm" ); +$writer->SetFile( $file ); +$writer->Write(); + +?> diff --git a/gdcm/Examples/Python/CMakeLists.txt b/gdcm/Examples/Python/CMakeLists.txt new file mode 100644 index 0000000..e69de29 diff --git a/gdcm/Examples/Python/ConvertMPL.py b/gdcm/Examples/Python/ConvertMPL.py new file mode 100644 index 0000000..4c32e03 --- /dev/null +++ b/gdcm/Examples/Python/ConvertMPL.py @@ -0,0 +1,89 @@ +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +""" +display a DICOM image with matPlotLib via numpy + +Caveats: +- Does not support UINT12/INT12 + +Usage: + + python ConvertNumpy.py "IM000000" + +Thanks: + plotting example - Ray Schumacher 2009 +""" + +import gdcm +import numpy +from pylab import * + + +def get_gdcm_to_numpy_typemap(): + """Returns the GDCM Pixel Format to numpy array type mapping.""" + _gdcm_np = {gdcm.PixelFormat.UINT8 :numpy.int8, + gdcm.PixelFormat.INT8 :numpy.uint8, + gdcm.PixelFormat.UINT16 :numpy.uint16, + gdcm.PixelFormat.INT16 :numpy.int16, + gdcm.PixelFormat.UINT32 :numpy.uint32, + gdcm.PixelFormat.INT32 :numpy.int32, + gdcm.PixelFormat.FLOAT32:numpy.float32, + gdcm.PixelFormat.FLOAT64:numpy.float64 } + return _gdcm_np + +def get_numpy_array_type(gdcm_pixel_format): + """Returns a numpy array typecode given a GDCM Pixel Format.""" + return get_gdcm_to_numpy_typemap()[gdcm_pixel_format] + +def gdcm_to_numpy(image): + """Converts a GDCM image to a numpy array. + """ + pf = image.GetPixelFormat().GetScalarType() + print 'pf', pf + print image.GetPixelFormat().GetScalarTypeAsString() + assert pf in get_gdcm_to_numpy_typemap().keys(), \ + "Unsupported array type %s"%pf + d = image.GetDimension(0), image.GetDimension(1) + print 'Image Size: %d x %d' % (d[0], d[1]) + dtype = get_numpy_array_type(pf) + gdcm_array = image.GetBuffer() + ## use float for accurate scaling + result = numpy.frombuffer(gdcm_array, dtype=dtype).astype(float) + ## optional gamma scaling + #maxV = float(result[result.argmax()]) + #result = result + .5*(maxV-result) + #result = numpy.log(result+50) ## apprx background level + result.shape = d + return result + +if __name__ == "__main__": + import sys + r = gdcm.ImageReader() + filename = sys.argv[1] + r.SetFileName( filename ) + if not r.Read(): sys.exit(1) + numpy_array = gdcm_to_numpy( r.GetImage() ) + + subplot(111)# one plot, on left + title(filename) + ## many colormaps are available + imshow(numpy_array, interpolation='bilinear', cmap=cm.jet) + ## set the plot sizes and placement + subplots_adjust(bottom=0.1, right=0.8, top=0.9) + cax = axes([0.85, 0.1, 0.075, 0.8]) + colorbar(cax=cax) + title('values') + get_current_fig_manager().window.title('plot') + show() diff --git a/gdcm/Examples/Python/ConvertNumpy.py b/gdcm/Examples/Python/ConvertNumpy.py new file mode 100644 index 0000000..e9db128 --- /dev/null +++ b/gdcm/Examples/Python/ConvertNumpy.py @@ -0,0 +1,74 @@ +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +""" +This module add support for converting a gdcm.Image to a numpy array. + +Caveats: +- Does not support UINT12/INT12 + +Removed: +- float16 is defined in GDCM API but no implementation exist for it ... +""" + +import gdcm +import numpy + +def get_gdcm_to_numpy_typemap(): + """Returns the GDCM Pixel Format to numpy array type mapping.""" + _gdcm_np = {gdcm.PixelFormat.UINT8 :numpy.int8, + gdcm.PixelFormat.INT8 :numpy.uint8, + #gdcm.PixelFormat.UINT12 :numpy.uint12, + #gdcm.PixelFormat.INT12 :numpy.int12, + gdcm.PixelFormat.UINT16 :numpy.uint16, + gdcm.PixelFormat.INT16 :numpy.int16, + gdcm.PixelFormat.UINT32 :numpy.uint32, + gdcm.PixelFormat.INT32 :numpy.int32, + #gdcm.PixelFormat.FLOAT16:numpy.float16, + gdcm.PixelFormat.FLOAT32:numpy.float32, + gdcm.PixelFormat.FLOAT64:numpy.float64 } + return _gdcm_np + +def get_numpy_array_type(gdcm_pixel_format): + """Returns a numpy array typecode given a GDCM Pixel Format.""" + return get_gdcm_to_numpy_typemap()[gdcm_pixel_format] + +def gdcm_to_numpy(image): + """Converts a GDCM image to a numpy array. + """ + pf = image.GetPixelFormat() + + assert pf.GetScalarType() in get_gdcm_to_numpy_typemap().keys(), \ + "Unsupported array type %s"%pf + + shape = image.GetDimension(0) * image.GetDimension(1), pf.GetSamplesPerPixel() + if image.GetNumberOfDimensions() == 3: + shape = shape[0] * image.GetDimension(2), shape[1] + + dtype = get_numpy_array_type(pf.GetScalarType()) + gdcm_array = image.GetBuffer() + result = numpy.frombuffer(gdcm_array, dtype=dtype) + result.shape = shape + return result + +if __name__ == "__main__": + import sys + r = gdcm.ImageReader() + filename = sys.argv[1] + r.SetFileName( filename ) + if not r.Read(): + sys.exit(1) + + numpy_array = gdcm_to_numpy( r.GetImage() ) + print numpy_array diff --git a/gdcm/Examples/Python/ConvertPIL.py b/gdcm/Examples/Python/ConvertPIL.py new file mode 100644 index 0000000..8e007fc --- /dev/null +++ b/gdcm/Examples/Python/ConvertPIL.py @@ -0,0 +1,88 @@ +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +""" +save a DICOM image with PIL via numpy + +Caveats: +- Does not support UINT12/INT12 + +Usage: + + python ConvertNumpy.py "IM000000" + +Thanks: + plotting example - Ray Schumacher 2009 +""" + +import gdcm +import numpy +from PIL import Image, ImageOps + + +def get_gdcm_to_numpy_typemap(): + """Returns the GDCM Pixel Format to numpy array type mapping.""" + _gdcm_np = {gdcm.PixelFormat.UINT8 :numpy.int8, + gdcm.PixelFormat.INT8 :numpy.uint8, + gdcm.PixelFormat.UINT16 :numpy.uint16, + gdcm.PixelFormat.INT16 :numpy.int16, + gdcm.PixelFormat.UINT32 :numpy.uint32, + gdcm.PixelFormat.INT32 :numpy.int32, + gdcm.PixelFormat.FLOAT32:numpy.float32, + gdcm.PixelFormat.FLOAT64:numpy.float64 } + return _gdcm_np + +def get_numpy_array_type(gdcm_pixel_format): + """Returns a numpy array typecode given a GDCM Pixel Format.""" + return get_gdcm_to_numpy_typemap()[gdcm_pixel_format] + +def gdcm_to_numpy(image): + """Converts a GDCM image to a numpy array. + """ + pf = image.GetPixelFormat().GetScalarType() + print 'pf', pf + print image.GetPixelFormat().GetScalarTypeAsString() + assert pf in get_gdcm_to_numpy_typemap().keys(), \ + "Unsupported array type %s"%pf + d = image.GetDimension(0), image.GetDimension(1) + print 'Image Size: %d x %d' % (d[0], d[1]) + dtype = get_numpy_array_type(pf) + gdcm_array = image.GetBuffer() + result = numpy.frombuffer(gdcm_array, dtype=dtype) + maxV = float(result[result.argmax()]) + ## linear gamma adjust + #result = result + .5*(maxV-result) + ## log gamma + result = numpy.log(result+50) ## 50 is apprx background level + maxV = float(result[result.argmax()]) + result = result*(2.**8/maxV) ## histogram stretch + result.shape = d + return result + +if __name__ == "__main__": + import sys + r = gdcm.ImageReader() + filename = sys.argv[1] + r.SetFileName( filename ) + if not r.Read(): sys.exit(1) + numpy_array = gdcm_to_numpy( r.GetImage() ) + ## L is 8 bit grey + ## http://www.pythonware.com/library/pil/handbook/concepts.htm + pilImage = Image.frombuffer('L', + numpy_array.shape, + numpy_array.astype(numpy.uint8), + 'raw','L',0,1) + ## cutoff removes background noise and spikes + pilImage = ImageOps.autocontrast(pilImage, cutoff=.1) + pilImage.save(sys.argv[1]+'.jpg') diff --git a/gdcm/Examples/Python/CreateRAWStorage.py b/gdcm/Examples/Python/CreateRAWStorage.py new file mode 100644 index 0000000..c882d46 --- /dev/null +++ b/gdcm/Examples/Python/CreateRAWStorage.py @@ -0,0 +1,159 @@ +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +""" + +""" + +import gdcm +import sys,os + +if __name__ == "__main__": + r = gdcm.Reader() + # Will require Testing... + dataroot = gdcm.Testing.GetDataRoot() + filename = os.path.join( dataroot, '012345.002.050.dcm' ) + r.SetFileName( filename ) + r.Read() + f = r.GetFile() + ds = f.GetDataSet() + + uid = "1.2.840.10008.5.1.4.1.1.66" +# f = gdcm.File() +# ds = f.GetDataSet() + de = gdcm.DataElement( gdcm.Tag(0x0008,0x0016) ) + de.SetByteValue( uid, gdcm.VL(len(uid)) ) + vr = gdcm.VR( gdcm.VR.UI ) + de.SetVR( vr ) + ds.Replace( de ) + + ano = gdcm.Anonymizer() + ano.SetFile( r.GetFile() ) + ano.RemovePrivateTags() + ano.RemoveGroupLength() + taglist = [ + gdcm.Tag(0x0008,0x0008), + gdcm.Tag(0x0008,0x0022), + gdcm.Tag(0x0008,0x0032), + gdcm.Tag(0x0008,0x2111), + gdcm.Tag(0x0008,0x1150), + gdcm.Tag(0x0008,0x1155), + gdcm.Tag(0x0008,0x0100), + gdcm.Tag(0x0008,0x0102), + gdcm.Tag(0x0008,0x0104), + gdcm.Tag(0x0040,0xa170), + gdcm.Tag(0x0008,0x2112), + gdcm.Tag(0x0008,0x0100), + gdcm.Tag(0x0008,0x0102), + gdcm.Tag(0x0008,0x0104), + gdcm.Tag(0x0008,0x9215), + gdcm.Tag(0x0018,0x0010), + gdcm.Tag(0x0018,0x0022), + gdcm.Tag(0x0018,0x0050), + gdcm.Tag(0x0018,0x0060), + gdcm.Tag(0x0018,0x0088), + gdcm.Tag(0x0018,0x0090), + gdcm.Tag(0x0018,0x1040), + gdcm.Tag(0x0018,0x1100), + gdcm.Tag(0x0018,0x1110), + gdcm.Tag(0x0018,0x1111), + gdcm.Tag(0x0018,0x1120), + gdcm.Tag(0x0018,0x1130), + gdcm.Tag(0x0018,0x1150), + gdcm.Tag(0x0018,0x1151), + gdcm.Tag(0x0018,0x1152), + gdcm.Tag(0x0018,0x1160), + gdcm.Tag(0x0018,0x1190), + gdcm.Tag(0x0018,0x1210), + gdcm.Tag(0x0020,0x0012), + gdcm.Tag(0x0020,0x0032), + gdcm.Tag(0x0020,0x0037), + gdcm.Tag(0x0020,0x1041), + gdcm.Tag(0x0020,0x4000), + gdcm.Tag(0x0028,0x0002), + gdcm.Tag(0x0028,0x0004), + gdcm.Tag(0x0028,0x0010), + gdcm.Tag(0x0028,0x0011), + gdcm.Tag(0x0028,0x0030), + gdcm.Tag(0x0028,0x0100), + gdcm.Tag(0x0028,0x0101), + gdcm.Tag(0x0028,0x0102), + gdcm.Tag(0x0028,0x0103), + gdcm.Tag(0x0028,0x1052), + gdcm.Tag(0x0028,0x1053), + gdcm.Tag(0x0028,0x2110), + gdcm.Tag(0x0028,0x2112), + gdcm.Tag(0x7fe0,0x0010), + gdcm.Tag(0x0018,0x0020), + gdcm.Tag(0x0018,0x0021), + gdcm.Tag(0x0018,0x0023), + gdcm.Tag(0x0018,0x0025), + gdcm.Tag(0x0018,0x0080), + gdcm.Tag(0x0018,0x0081), + gdcm.Tag(0x0018,0x0083), + gdcm.Tag(0x0018,0x0084), + gdcm.Tag(0x0018,0x0085), + gdcm.Tag(0x0018,0x0086), + gdcm.Tag(0x0018,0x0087), + gdcm.Tag(0x0018,0x0091), + gdcm.Tag(0x0018,0x0093), + gdcm.Tag(0x0018,0x0094), + gdcm.Tag(0x0018,0x0095), + gdcm.Tag(0x0018,0x1088), + gdcm.Tag(0x0018,0x1090), + gdcm.Tag(0x0018,0x1094), + gdcm.Tag(0x0018,0x1250), + gdcm.Tag(0x0018,0x1251), + gdcm.Tag(0x0018,0x1310), + gdcm.Tag(0x0018,0x1312), + gdcm.Tag(0x0018,0x1314), + gdcm.Tag(0x0018,0x1315), + gdcm.Tag(0x0018,0x1316), + gdcm.Tag(0x0020,0x0110), + gdcm.Tag(0x0028,0x0120), + gdcm.Tag(0x0028,0x1050), + gdcm.Tag(0x0028,0x1051) + ] + for tag in taglist: + #print tag + ano.Remove( tag ) + + # special handling + gen = gdcm.UIDGenerator() + ano.Replace( gdcm.Tag(0x0008,0x9123), gen.Generate() ) + #ano.Empty( gdcm.Tag(0x0040,0x0555) ) + + +# +# uid = gen.Generate() +# de.SetTag( gdcm.Tag(0x0008,0x0018) ) +# de.SetByteValue( uid, gdcm.VL(len(uid)) ) +# ds.Insert( de ) + + # init FMI now: + #fmi = f.GetHeader() + #ts = gdcm.TransferSyntax() + #print ts + #fmi.SetDataSetTransferSyntax( ts ) # default + #print fmi.GetDataSetTransferSyntax() + #de.SetTag( gdcm.Tag(0x0002,0x0010) ) + #uid = "1.2.840.10008.1.2" + #de.SetByteValue( uid, gdcm.VL(len(uid)) ) + #fmi.Insert( de ) +# f.SetHeader( r.GetFile().GetHeader() ) + + writer = gdcm.Writer() + writer.SetFile( ano.GetFile() ) + writer.SetFileName( "rawstorage.dcm" ); + writer.Write() diff --git a/gdcm/Examples/Python/DecompressImage.py b/gdcm/Examples/Python/DecompressImage.py new file mode 100644 index 0000000..c3b7018 --- /dev/null +++ b/gdcm/Examples/Python/DecompressImage.py @@ -0,0 +1,69 @@ +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +""" +Usage: + + python DecompressImage.py gdcmData/012345.002.050.dcm decompress.dcm +""" + +import gdcm +import sys + +if __name__ == "__main__": + + file1 = sys.argv[1] + file2 = sys.argv[2] + + r = gdcm.ImageReader() + r.SetFileName( file1 ) + if not r.Read(): + sys.exit(1) + + image = gdcm.Image() + ir = r.GetImage() + + image.SetNumberOfDimensions( ir.GetNumberOfDimensions() ); + dims = ir.GetDimensions(); + print ir.GetDimension(0); + print ir.GetDimension(1); + print "Dims:",dims + + # Just for fun: + dircos = ir.GetDirectionCosines() + t = gdcm.Orientation.GetType(dircos) + l = gdcm.Orientation.GetLabel(t) + print "Orientation label:",l + + image.SetDimension(0, ir.GetDimension(0) ); + image.SetDimension(1, ir.GetDimension(1) ); + + pixeltype = ir.GetPixelFormat(); + image.SetPixelFormat( pixeltype ); + + pi = ir.GetPhotometricInterpretation(); + image.SetPhotometricInterpretation( pi ); + + pixeldata = gdcm.DataElement( gdcm.Tag(0x7fe0,0x0010) ) + str1 = ir.GetBuffer() + #print ir.GetBufferLength() + pixeldata.SetByteValue( str1, gdcm.VL( len(str1) ) ) + image.SetDataElement( pixeldata ) + + w = gdcm.ImageWriter() + w.SetFileName( file2 ) + w.SetFile( r.GetFile() ) + w.SetImage( image ) + if not w.Write(): + sys.exit(1) diff --git a/gdcm/Examples/Python/DumbAnonymizer.py b/gdcm/Examples/Python/DumbAnonymizer.py new file mode 100644 index 0000000..95fa22a --- /dev/null +++ b/gdcm/Examples/Python/DumbAnonymizer.py @@ -0,0 +1,124 @@ +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +""" +This example shows how one can use the gdcm.Anonymizer in 'dumb' mode. +This class becomes really handy when one knows which particular tag to fill in. + +Usage: + + python DumbAnonymizer.py gdcmData/012345.002.050.dcm out.dcm + +""" + +import gdcm + +# http://www.oid-info.com/get/1.3.6.1.4.17434 +THERALYS_ORG_ROOT = "1.3.6.1.4.17434" + +tag_rules={ + # Value + (0x0012,0x0010):("Value","MySponsorName"), + (0x0012,0x0020):("Value","MyProtocolID"), + (0x0012,0x0021):("Value","MyProtocolName"), + (0x0012,0x0062):("Value","YES"), + (0x0012,0x0063):("Value","MyDeidentificationMethod"), + + # Method + #(0x0002,0x0003):("Method","GenerateMSOPId"), + #(0x0008,0x1155):("Method","GenerateMSOPId"), + (0x0008,0x0018):("Method","GenerateMSOPId"), + (0x0010,0x0010):("Method","GetSponsorInitials"), + (0x0010,0x0020):("Method","GetSponsorId"), + (0x0012,0x0030):("Method","GetSiteId"), + (0x0012,0x0031):("Method","GetSiteName"), + (0x0012,0x0040):("Method","GetSponsorId"), + (0x0012,0x0050):("Method","GetTPId"), + (0x0018,0x0022):("Method","KeepIfExist"), + (0x0018,0x1315):("Method","KeepIfExist"), + (0x0020,0x000d):("Method","GenerateStudyId"), + (0x0020,0x000e):("Method","GenerateSeriesId"), + (0x0020,0x1002):("Method","GetNumberOfFrames"), + (0x0020,0x0020):("Method","GetPatientOrientation"), + # Other: + (0x0012,0x0051):("Patient Field","Type Examen"), + (0x0018,0x1250):("Sequence Field","Receive Coil"), + (0x0018,0x0088):("Sequence Field","Spacing Between Slice"), + (0x0018,0x0095):("Sequence Field","Pixel Bandwidth"), + (0x0018,0x0082):("Sequence Field","Invertion Time"), +} + +class MyAnon: + def __init__(self): + self.studyuid = None + self.seriesuid = None + generator = gdcm.UIDGenerator() + if not self.studyuid: + self.studyuid = generator.Generate() + if not self.seriesuid: + self.seriesuid = generator.Generate() + def GetSponsorInitials(self): + return "dummy^foobar" + def GenerateStudyId(self): + return self.studyuid + def GenerateSeriesId(self): + return self.seriesuid + #def GenerateMSOPId(self): + def GenerateMSOPId(self): + generator = gdcm.UIDGenerator() + return generator.Generate() + def GetSiteId(self): + return "MySiteId" + def GetSiteName(self): + return "MySiteName" + def GetSponsorId(self): + return "MySponsorId" + def GetTPId(self): + return "MyTP" + +if __name__ == "__main__": + import sys + gdcm.FileMetaInformation.SetSourceApplicationEntityTitle( "DumbAnonymizer" ) + gdcm.UIDGenerator.SetRoot( THERALYS_ORG_ROOT ) + + r = gdcm.Reader() + filename = sys.argv[1] + r.SetFileName( filename ) + if not r.Read(): sys.exit(1) + + obj = MyAnon() + + w = gdcm.Writer() + ano = gdcm.Anonymizer() + ano.SetFile( r.GetFile() ) + ano.RemoveGroupLength() + for tag,rule in tag_rules.items(): + if rule[0] == 'Value': + print tag,rule + ano.Replace( gdcm.Tag( tag[0], tag[1] ), rule[1] ) + elif rule[0] == 'Method': + print tag,rule + # result = locals()[rule[1]]() + methodname = rule[1] + if hasattr(obj, methodname): + _member = getattr(obj, methodname) + result = _member() + ano.Replace( gdcm.Tag( tag[0], tag[1] ), result ) + else: + print "Problem with: ", methodname + + outfilename = sys.argv[2] + w.SetFileName( outfilename ) + w.SetFile( ano.GetFile() ) + if not w.Write(): sys.exit(1) diff --git a/gdcm/Examples/Python/FindAllPatientName.py b/gdcm/Examples/Python/FindAllPatientName.py new file mode 100644 index 0000000..7bf4f10 --- /dev/null +++ b/gdcm/Examples/Python/FindAllPatientName.py @@ -0,0 +1,50 @@ +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ +""" +This example shows how one can use the gdcm.CompositeNetworkFunctions class +for executing a C-FIND query +It will print the list of patient name found + +Usage: + + python FindAllPatientName.py + +""" + +import gdcm + +# Patient Name +tag = gdcm.Tag(0x10,0x10) +de = gdcm.DataElement(tag) + +# Search all patient name where string match 'F*' +de.SetByteValue('F*',gdcm.VL(2)) + +ds = gdcm.DataSet() +ds.Insert(de) + +cnf = gdcm.CompositeNetworkFunctions() +theQuery = cnf.ConstructQuery (gdcm.ePatientRootType,gdcm.ePatient,ds) + +#print theQuery.ValidateQuery() + +# prepare the variable for output +ret = gdcm.DataSetArrayType() + +# Execute the C-FIND query +cnf.CFind('dicom.example.com',11112,theQuery,ret,'GDCM_PYTHON','ANY-SCP') + +for i in range(0,ret.size()): + print "Patient #",i + print ret[i] diff --git a/gdcm/Examples/Python/FixCommaBug.py b/gdcm/Examples/Python/FixCommaBug.py new file mode 100644 index 0000000..d3476ca --- /dev/null +++ b/gdcm/Examples/Python/FixCommaBug.py @@ -0,0 +1,77 @@ +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +""" +Using LC_NUMERIC set to something not compatible with "C" it is possible to write out "," instead of +"." as required by the DICOM standard +Issue is still current (IMHO) with gdcm 2.0.9 +""" + +import gdcm +import sys + +filename = sys.argv[1] +outname = sys.argv[2] + +# read +r = gdcm.Reader() +r.SetFileName( filename ) +if not r.Read(): + print "not valid" + sys.exit(1) + +file = r.GetFile() +dataset = file.GetDataSet() + +ano = gdcm.Anonymizer() +ano.SetFile( file ) + +tags = [ +gdcm.Tag(0x0018,0x1164), +gdcm.Tag(0x0018,0x0088), +gdcm.Tag(0x0018,0x0050), +gdcm.Tag(0x0028,0x0030), +] + +for tag in tags: + print tag + if dataset.FindDataElement( tag ): + pixelspacing = dataset.GetDataElement( tag ) + #print pixelspacing + bv = pixelspacing.GetByteValue() + str = bv.GetBuffer() + #print bv.GetLength() + #print len(str) + new_str = str.replace(",",".") + # Need to explicitly pass bv.GetLength() to remove any trailing garbage + ano.Replace( tag, new_str, bv.GetLength() ) + +#print dataset + +w = gdcm.Writer() +w.SetFile( file ) +w.SetFileName( outname ) +if not w.Write(): + print "Cannot write" + sys.exit(1) + +# paranoid: +image_reader = gdcm.ImageReader() +image_reader.SetFileName( outname ) +if not image_reader.Read(): + print "there is still a comma" + sys.exit(1) + +print "Sucess!" +sys.exit(0) # success diff --git a/gdcm/Examples/Python/GetPortionCSAHeader.py b/gdcm/Examples/Python/GetPortionCSAHeader.py new file mode 100644 index 0000000..ec78994 --- /dev/null +++ b/gdcm/Examples/Python/GetPortionCSAHeader.py @@ -0,0 +1,68 @@ +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +""" +Usage: + + python GetPortionCSAHeader.py input.dcm + +Footnote: + SIEMENS is not publishing any information on the CSA header. So any info extracted + is at your own risk. +""" + +import sys +import gdcm + +if __name__ == "__main__": + + file = sys.argv[1] + + r = gdcm.Reader() + r.SetFileName( file ) + if not r.Read(): + sys.exit(1) + + ds = r.GetFile().GetDataSet() + csa_t1 = gdcm.CSAHeader() + csa_t2 = gdcm.CSAHeader() + #print csa + t1 = csa_t1.GetCSAImageHeaderInfoTag(); + print t1 + t2 = csa_t2.GetCSASeriesHeaderInfoTag(); + print t2 + # Let's do it for t1: + if ds.FindDataElement( t1 ): + csa_t1.LoadFromDataElement( ds.GetDataElement( t1 ) ) + print csa_t1 + + # Now let's pretend we are only interested in B_value and DiffusionGradientDirection entries: + bvalues = csa_t1.GetCSAElementByName( "B_value" ) # WARNING: it is case sensitive ! + print bvalues + + diffgraddir = csa_t1.GetCSAElementByName( "DiffusionGradientDirection" ) # WARNING: it is case sensitive ! + print diffgraddir + + # repeat for t2 if you like it: + if ds.FindDataElement( t2 ): + csa_t2.LoadFromDataElement( ds.GetDataElement( t2 ) ) + # print csa_t2 + + gdt = csa_t2.GetCSAElementByName( "GradientDelayTime" ) + print gdt + + bv = gdt.GetByteValue(); + #print bv + str = bv.GetPointer() + print str.split("\\") diff --git a/gdcm/Examples/Python/HelloWorld.py b/gdcm/Examples/Python/HelloWorld.py new file mode 100644 index 0000000..aa60ec3 --- /dev/null +++ b/gdcm/Examples/Python/HelloWorld.py @@ -0,0 +1,59 @@ +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +""" +Hello World ! +""" + +import gdcm +import sys + +if __name__ == "__main__": + + # verbosity: + #gdcm.Trace.DebugOn() + #gdcm.Trace.WarningOn() + #gdcm.Trace.ErrorOn() + + # Get the filename from the command line + filename = sys.argv[1] + + # Instanciate a gdcm.Reader + # This is the main class to handle any type of DICOM object + # You should check for gdcm.ImageReader for reading specifically DICOM Image file + r = gdcm.Reader() + r.SetFileName( filename ) + # If the reader fails to read the file, we should stop ! + if not r.Read(): + print "Not a valid DICOM file" + sys.exit(1) + + # Get the DICOM File structure + file = r.GetFile() + + # Get the DataSet part of the file + dataset = file.GetDataSet() + + # Ok let's print it ! + print dataset + + # Use StringFilter to print a particular Tag: + sf = gdcm.StringFilter() + sf.SetFile(r.GetFile()) + + # Check if Attribute exist + print dataset.FindDataElement( gdcm.Tag(0x0028,0x0010)) + + # Let's print it as string pair: + print sf.ToStringPair(gdcm.Tag(0x0028,0x0010)) diff --git a/gdcm/Examples/Python/ManipulateFile.py b/gdcm/Examples/Python/ManipulateFile.py new file mode 100644 index 0000000..8b2bcc0 --- /dev/null +++ b/gdcm/Examples/Python/ManipulateFile.py @@ -0,0 +1,108 @@ +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +""" +Usage: + + python ManipulateFile.py input.dcm output.dcm + +Footnote: + GDCM 1.2.x would create incorrect Multiframes MR Image Storage file. Try to recover from + the issues to recreate a MultiframeGrayscaleByteSecondaryCaptureImageStorage file. + e.g: + + python ManipulateFile.py Insight/Testing/Temporary/itkGDCMImageIOTest5-j2k.dcm manipulated.dcm +""" + +import sys +import gdcm + +if __name__ == "__main__": + + file1 = sys.argv[1] + file2 = sys.argv[2] + + r = gdcm.Reader() + r.SetFileName( file1 ) + if not r.Read(): + sys.exit(1) + + ano = gdcm.Anonymizer() + ano.SetFile( r.GetFile() ) + ano.RemovePrivateTags() + ano.Remove( gdcm.Tag(0x0032,0x1030) ) + ano.Remove( gdcm.Tag(0x008,0x14) ) + ano.Remove( gdcm.Tag(0x008,0x1111) ) + ano.Remove( gdcm.Tag(0x008,0x1120) ) + ano.Remove( gdcm.Tag(0x008,0x1140) ) + ano.Remove( gdcm.Tag(0x10,0x21b0) ) + ano.Empty( gdcm.Tag(0x10,0x10) ) + ano.Empty( gdcm.Tag(0x10,0x20) ) + ano.Empty( gdcm.Tag(0x10,0x30) ) + ano.Empty( gdcm.Tag(0x20,0x10) ) + ano.Empty( gdcm.Tag(0x32,0x1032) ) + ano.Empty( gdcm.Tag(0x32,0x1033) ) + ano.Empty( gdcm.Tag(0x40,0x241) ) + ano.Empty( gdcm.Tag(0x40,0x254) ) + ano.Empty( gdcm.Tag(0x40,0x253) ) + ano.Empty( gdcm.Tag(0x40,0x1001) ) + ano.Empty( gdcm.Tag(0x8,0x80) ) + ano.Empty( gdcm.Tag(0x8,0x50) ) + ano.Empty( gdcm.Tag(0x8,0x1030) ) + ano.Empty( gdcm.Tag(0x8,0x103e) ) + ano.Empty( gdcm.Tag(0x18,0x1030) ) + ano.Empty( gdcm.Tag(0x38,0x300) ) + g = gdcm.UIDGenerator() + ano.Replace( gdcm.Tag(0x0008,0x0018), g.Generate() ) + ano.Replace( gdcm.Tag(0x0020,0x00d), g.Generate() ) + ano.Replace( gdcm.Tag(0x0020,0x00e), g.Generate() ) + ano.Replace( gdcm.Tag(0x0020,0x052), g.Generate() ) + #ano.Replace( gdcm.Tag(0x0008,0x0016), "1.2.840.10008.5.1.4.1.1.7.2" ) + """ + ano.Remove( gdcm.Tag(0x0018,0x0020) ) # ScanningSequence + ano.Remove( gdcm.Tag(0x0018,0x0021) ) # SequenceVariant + ano.Remove( gdcm.Tag(0x0018,0x0022) ) # ScanOptions + ano.Remove( gdcm.Tag(0x0018,0x0023) ) # MRAcquisitionType + ano.Remove( gdcm.Tag(0x0018,0x0050) ) # SliceThickness + ano.Remove( gdcm.Tag(0x0018,0x0080) ) # RepetitionTime + ano.Remove( gdcm.Tag(0x0018,0x0081) ) # EchoTime + ano.Remove( gdcm.Tag(0x0018,0x0088) ) # SpacingBetweenSlices + ano.Remove( gdcm.Tag(0x0018,0x0091) ) # EchoTrainLength + ano.Remove( gdcm.Tag(0x0018,0x1164) ) # ImagerPixelSpacing + + ano.Remove( gdcm.Tag(0x0020,0x0032) ) # Image Position (Patient) + ano.Remove( gdcm.Tag(0x0020,0x0037) ) # Image Orientation (Patient) + ano.Remove( gdcm.Tag(0x0020,0x0052) ) # Frame of Reference UID + ano.Remove( gdcm.Tag(0x0020,0x1040) ) # Position Reference Indicator + + ano.Replace( gdcm.Tag(0x0028,0x0301), "NO" ) # Burned In Annotation + + ano.Empty( gdcm.Tag(0x0020,0x0020) ) + + ano.Remove( gdcm.Tag(0x7fe0,0x0000) ) + + #ano.Empty( gdcm.Tag(0x0028,0x0009) ) # Frame Increment Pointer + + #ano.Empty( gdcm.Tag(0x0028,0x1052) ) # + #ano.Empty( gdcm.Tag(0x0028,0x1053) ) # + #ano.Replace( gdcm.Tag(0x0028,0x1054), "US" ) # + + ano.Replace( gdcm.Tag(0x2050, 0x0020), "IDENTITY") + """ + + w = gdcm.Writer() + w.SetFile( ano.GetFile() ) + w.SetFileName( file2 ) + if not w.Write(): + sys.exit(1) diff --git a/gdcm/Examples/Python/ManipulateSequence.py b/gdcm/Examples/Python/ManipulateSequence.py new file mode 100644 index 0000000..5041ce2 --- /dev/null +++ b/gdcm/Examples/Python/ManipulateSequence.py @@ -0,0 +1,73 @@ +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +""" +Usage: + + python ManipulateSequence.py input.dcm output.dcm + +This was tested using: + + python ManipulateSequence.py gdcmData/D_CLUNIE_CT1_J2KI.dcm myoutput.dcm + +This is a dummy example on how to modify a value set in a nested-nested dataset + +WARNING: +Do not use as-is in production, this is just an example +This example works in an undefined length Item only (you need to explicitely recompute the length otherwise) +""" + +import sys +import gdcm + +if __name__ == "__main__": + + file1 = sys.argv[1] + file2 = sys.argv[2] + + r = gdcm.Reader() + r.SetFileName( file1 ) + if not r.Read(): + sys.exit(1) + + f = r.GetFile() + ds = f.GetDataSet() + tsis = gdcm.Tag(0x0008,0x2112) # SourceImageSequence + if ds.FindDataElement( tsis ): + sis = ds.GetDataElement( tsis ) + #sqsis = sis.GetSequenceOfItems() + # GetValueAsSQ handle more cases + sqsis = sis.GetValueAsSQ() + if sqsis.GetNumberOfItems(): + item1 = sqsis.GetItem(1) + nestedds = item1.GetNestedDataSet() + tprcs = gdcm.Tag(0x0040,0xa170) # PurposeOfReferenceCodeSequence + if nestedds.FindDataElement( tprcs ): + prcs = nestedds.GetDataElement( tprcs ) + sqprcs = prcs.GetSequenceOfItems() + if sqprcs.GetNumberOfItems(): + item2 = sqprcs.GetItem(1) + nestedds2 = item2.GetNestedDataSet() + # (0008,0104) LO [Uncompressed predecessor] # 24, 1 CodeMeaning + tcm = gdcm.Tag(0x0008,0x0104) + if nestedds2.FindDataElement( tcm ): + cm = nestedds2.GetDataElement( tcm ) + mystr = "GDCM was here" + cm.SetByteValue( mystr, gdcm.VL( len(mystr) ) ) + + w = gdcm.Writer() + w.SetFile( f ) + w.SetFileName( file2 ) + if not w.Write(): + sys.exit(1) diff --git a/gdcm/Examples/Python/MergeFile.py b/gdcm/Examples/Python/MergeFile.py new file mode 100644 index 0000000..824c748 --- /dev/null +++ b/gdcm/Examples/Python/MergeFile.py @@ -0,0 +1,58 @@ +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +""" +Usage: + + python MergeFile.py input1.dcm input2.dcm + + It will produce a 'merge.dcm' output file, which contains all meta information from input1.dcm + and copy the Stored Pixel values from input2.dcm + This script even works when input2.dcm is a Secondary Capture and does not contains information + such as IOP and IPP... +""" + +import sys +import gdcm + +if __name__ == "__main__": + + file1 = sys.argv[1] + file2 = sys.argv[2] + + r1 = gdcm.ImageReader() + r1.SetFileName( file1 ) + if not r1.Read(): + sys.exit(1) + + r2 = gdcm.ImageReader() + r2.SetFileName( file2 ) + if not r2.Read(): + sys.exit(1) + + # Image from r2 could be Secondary Capture and thus would not contains neither IPP nor IOP + # Instead always prefer to only copy the Raw Data Element. + # Warning ! Image need to be identical ! Only the value of Stored Pixel can be different. + r1.GetImage().SetDataElement( r2.GetImage().GetDataElement() ) + + w = gdcm.ImageWriter() + w.SetFile( r1.GetFile() ) + #w.SetImage( r2.GetImage() ) # See comment above + w.SetImage( r1.GetImage() ) + + w.SetFileName( "merge.dcm" ) + if not w.Write(): + sys.exit(1) + + sys.exit(0) diff --git a/gdcm/Examples/Python/NewSequence.py b/gdcm/Examples/Python/NewSequence.py new file mode 100644 index 0000000..df38796 --- /dev/null +++ b/gdcm/Examples/Python/NewSequence.py @@ -0,0 +1,70 @@ +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +""" +Usage: + + python NewSequence.py input.dcm output.dcm + + +Thanks to Robert Irie for code +""" + +import sys +import gdcm + +if __name__ == "__main__": + + file1 = sys.argv[1] + file2 = sys.argv[2] + + r = gdcm.Reader() + r.SetFileName( file1 ) + if not r.Read(): + sys.exit(1) + + f = r.GetFile() + ds = f.GetDataSet() + #tsis = gdcm.Tag(0x0008,0x2112) # SourceImageSequence + + # Create a dataelement + de = gdcm.DataElement(gdcm.Tag(0x0010, 0x2180)) + de.SetByteValue("Occupation", gdcm.VL(len("Occupation"))) + de.SetVR(gdcm.VR(gdcm.VR.SH)) + + # Create an item + it=gdcm.Item() + it.SetVLToUndefined() # Needed to not popup error message + #it.InsertDataElement(de) + nds=it.GetNestedDataSet() + nds.Insert(de) + + # Create a Sequence + sq=gdcm.SequenceOfItems().New() + sq.SetLengthToUndefined() + sq.AddItem(it) + + # Insert sequence into data set + des=gdcm.DataElement(gdcm.Tag(0x0400,0x0550)) + des.SetVR(gdcm.VR(gdcm.VR.SQ)) + des.SetValue(sq.__ref__()) + des.SetVLToUndefined() + + ds.Insert(des) + + w = gdcm.Writer() + w.SetFile( f ) + w.SetFileName( file2 ) + if not w.Write(): + sys.exit(1) diff --git a/gdcm/Examples/Python/PhilipsPrivateRescaleInterceptSlope.py b/gdcm/Examples/Python/PhilipsPrivateRescaleInterceptSlope.py new file mode 100644 index 0000000..9c0921a --- /dev/null +++ b/gdcm/Examples/Python/PhilipsPrivateRescaleInterceptSlope.py @@ -0,0 +1,69 @@ +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +""" +Usage: + + python +""" + +import gdcm +import sys + +filename = sys.argv[1] +tmpfile = "/tmp/philips_rescaled.dcm" + + +# Need to access some private tags, read the file : +reader = gdcm.Reader() +reader.SetFileName( filename ) +if not reader.Read(): + sys.exit(1) + +ds = reader.GetFile().GetDataSet() + +#print ds +# (2005,1409) DS 4 0.0 +# (2005,140a) DS 16 1.52283272283272 + +# (2005,0014) LO 26 Philips MR Imaging DD 005 +tag1 = gdcm.PrivateTag(0x2005,0x09,"Philips MR Imaging DD 005") +tag2 = gdcm.PrivateTag(0x2005,0x0a,"Philips MR Imaging DD 005") +print tag1 +print tag2 + +# make sure to do a copy, we want the private tag to remain +# otherwise gdcm gives us a reference +el1 = gdcm.DataElement( ds.GetDataElement( tag1 ) ) +print el1 +el2 = gdcm.DataElement( ds.GetDataElement( tag2 ) ) +print el2 + +# (0028,1052) DS [-1000] # 6, 1 RescaleIntercept +# (0028,1053) DS [1] # 2, 1 RescaleSlope + +el1.SetTag( gdcm.Tag(0x0028,0x1052) ) +el2.SetTag( gdcm.Tag(0x0028,0x1053) ) + +ds.Insert( el1 ) +ds.Insert( el2 ) + +w = gdcm.Writer() +w.SetCheckFileMetaInformation( False ) +w.SetFileName( tmpfile ) +w.SetFile( reader.GetFile() ) +if not w.Write(): + sys.exit(1) + +print "success" diff --git a/gdcm/Examples/Python/PlaySound.py b/gdcm/Examples/Python/PlaySound.py new file mode 100644 index 0000000..783033a --- /dev/null +++ b/gdcm/Examples/Python/PlaySound.py @@ -0,0 +1,91 @@ +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +""" +Usage: + + python PlaySound.py input.dcm +""" + +import gdcm +import sys + +#filename = "/home/mmalaterre/Creatis/gdcmDataExtra/gdcmNonImageData/audio_from_rafael_sanguinetti.dcm" +filename = sys.argv[1] +print filename + +r = gdcm.Reader() +r.SetFileName( filename ) +if not r.Read(): + sys.exit(1) + +ds = r.GetFile().GetDataSet() + +waveformtag = gdcm.Tag(0x5400,0x0100) +waveformsq = ds.GetDataElement( waveformtag ) +#print waveformsq + +#print dir(waveformsq) + +items = waveformsq.GetSequenceOfItems() + +if not items.GetNumberOfItems(): + sys.exit(1) + +item = items.GetItem(1) +#print item + +waveformds = item.GetNestedDataSet() +#print waveformds + +waveformdatatag = gdcm.Tag(0x5400,0x1010) +waveformdata = waveformds.GetDataElement( waveformdatatag ) + +#print waveformdata.GetPointer() +bv = waveformdata.GetByteValue() +print dir(bv) + +#print bv.GetPointer() +print bv.GetLength() +l = 116838 + +file='test.wav' +myfile = open(file, "wb") +s = bv.GetPointer() +for i in range(0, l): + myfile.write(s[i]) +myfile.close() + +# http://mail.python.org/pipermail/python-list/2004-October/288905.html +if sys.platform.startswith('win'): + from winsound import PlaySound, SND_FILENAME, SND_ASYNC + PlaySound(file, SND_FILENAME|SND_ASYNC) +elif sys.platform.find('linux')>-1: + from wave import open as waveOpen + from ossaudiodev import open as ossOpen + s = waveOpen(file,'rb') + (nc,sw,fr,nf,comptype, compname) = s.getparams( ) + dsp = ossOpen('/dev/dsp','w') + try: + from ossaudiodev import AFMT_S16_NE + except ImportError: + if byteorder == "little": + AFMT_S16_NE = ossaudiodev.AFMT_S16_LE + else: + AFMT_S16_NE = ossaudiodev.AFMT_S16_BE + dsp.setparameters(AFMT_S16_NE, nc, fr) + data = s.readframes(nf) + s.close() + dsp.write(data) + dsp.close() diff --git a/gdcm/Examples/Python/PrivateDict.py b/gdcm/Examples/Python/PrivateDict.py new file mode 100644 index 0000000..f0be4c7 --- /dev/null +++ b/gdcm/Examples/Python/PrivateDict.py @@ -0,0 +1,35 @@ +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +""" +""" + +import gdcm +import sys,os + +if __name__ == "__main__": + #gdcm.Trace.DebugOn() + globInst = gdcm.Global.GetInstance() + # Try to load Part3.xml file + # This fils is too big for being accessible directly at runtime. + globInst.LoadResourcesFiles() + + + # Get a private tag from the runtime dicts. LoadResourcesFiles could + # have failed but this has no impact on the private dict + + d = globInst.GetDicts() + print d.GetDictEntry( gdcm.Tag(0x0029,0x0010) ,"SIEMENS CSA HEADER" ) + pd = d.GetPrivateDict() + print pd.GetDictEntry( gdcm.PrivateTag(0x0029,0x0010,"SIEMENS CSA HEADER") ) diff --git a/gdcm/Examples/Python/ReWriteSCAsMR.py b/gdcm/Examples/Python/ReWriteSCAsMR.py new file mode 100644 index 0000000..2059941 --- /dev/null +++ b/gdcm/Examples/Python/ReWriteSCAsMR.py @@ -0,0 +1,82 @@ +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +""" +GDCM 1.x would write out MR Image Storage as Secondary Capture Object while still setting Rescale Slope/Intercept +and saving the Pixel Spacing in (0028,0030) +""" + +import gdcm +import sys,os + +def CheckSecondaryCaptureObjectIsMRImageStorage(r): + ds = r.GetFile().GetDataSet() + # Check Source Image Sequence + if ds.FindDataElement( gdcm.Tag(0x0008,0x2112) ): + sis = ds.GetDataElement( gdcm.Tag(0x0008,0x2112) ) + sqsis = sis.GetSequenceOfItems() + if sqsis.GetNumberOfItems(): + item1 = sqsis.GetItem(1) + nestedds = item1.GetNestedDataSet() + if nestedds.FindDataElement( gdcm.Tag(0x0008,0x1150) ): + ReferencedSOPClassUID = nestedds.GetDataElement( gdcm.Tag(0x0008,0x1150) ) + raw = ReferencedSOPClassUID.GetByteValue().GetPointer() + uids = gdcm.UIDs() + # what is the actual object we are looking at ? + ms = gdcm.MediaStorage() + ms.SetFromDataSet(ds) + msuid = ms.GetString() + uids.SetFromUID( msuid ) + msuidname = uids.GetName() # real Media Storage Name + uids.SetFromUID( raw ) + sqmsuidname = uids.GetName() # Source Image Sequence Media Storage Name + # If object is SC and Source derivation is MRImageStorage then we can assume 'Pixel Spacing' is correct + if( sqmsuidname == 'MR Image Storage' and msuidname == 'Secondary Capture Image Storage' ): + return True + # in all other case simply return the currentspacing: + return False + +if __name__ == "__main__": + r = gdcm.ImageReader() + filename = sys.argv[1] + r.SetFileName( filename ) + if not r.Read(): + sys.exit(1) + f = r.GetFile() + + if( CheckSecondaryCaptureObjectIsMRImageStorage(r) ): + # Special handling of the spacing: + # GDCM 1.2.0 would not rewrite correcly DICOM Object and would always set them as 'Secondary Capture Image Storage' + # while we would rather have 'MR Image Storage' + gdcm.ImageHelper.SetForcePixelSpacing( True ) + mrspacing = gdcm.ImageHelper.GetSpacingValue( r.GetFile() ) + # TODO: I cannot do simply the following: + #image.SetSpacing( mrspacing ) + image.SetSpacing(0, mrspacing[0] ) + image.SetSpacing(1, mrspacing[1] ) + image.SetSpacing(2, mrspacing[2] ) + gdcm.ImageHelper.SetForceRescaleInterceptSlope( True ) + ris = gdcm.ImageHelper.GetRescaleInterceptSlopeValue( r.GetFile() ) + image.SetIntercept( ris[0] ) + image.SetSlope( ris[1] ) + + outfilename = sys.argv[2] + w = gdcm.ImageWriter() + w.SetFileName( outfilename ) + w.SetFile( r.GetFile() ) + w.SetImage( image ) + if not w.Write(): + sys.exit(1) + + sys.exit(0) diff --git a/gdcm/Examples/Python/ReadAndDumpDICOMDIR.py b/gdcm/Examples/Python/ReadAndDumpDICOMDIR.py new file mode 100644 index 0000000..ff20a25 --- /dev/null +++ b/gdcm/Examples/Python/ReadAndDumpDICOMDIR.py @@ -0,0 +1,187 @@ +################################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +# File: ReadAndDumpDICOMDIR.py +# +# Author: Lukas Batteau (lbatteau gmail) +# +# This example shows how to read and dump a DICOMDIR File. +# Based on Tom Marynowski's (lordglub gmail) example. +# +# Usage: +# python ReadAndDumpDICOMDIR.py [DICOMDIR file] +############################################################################ + + + +import sys +import gdcm + +if __name__ == "__main__": + # Check arguments + if (len(sys.argv) < 2): + # No filename passed + print "No input filename found" + quit() + + filename = sys.argv[1] + + + # Read file + reader = gdcm.Reader() + reader.SetFileName(filename) + if (not reader.Read()): + print "Unable to read %s" % (filename) + quit() + + file = reader.GetFile() + + # Retrieve header information + fileMetaInformation = file.GetHeader() + print fileMetaInformation + + # Retrieve data set + dataSet = file.GetDataSet() + #print dataSet + + # Check media storage + mediaStorage = gdcm.MediaStorage() + mediaStorage.SetFromFile(file) + if (gdcm.MediaStorage.GetMSType(str(mediaStorage)) != gdcm.MediaStorage.MediaStorageDirectoryStorage): + # File is not a DICOMDIR + print "This file is not a DICOMDIR (Media storage type: %s)" % (str(mediaStorage)) + quit() + + # Check Media Storage SOP Class + if (fileMetaInformation.FindDataElement(gdcm.Tag(0x0002, 0x0002))): + sopClassUid = str(fileMetaInformation.GetDataElement(gdcm.Tag(0x0002, 0x0002)).GetValue()) + # Check SOP UID + if (sopClassUid != "1.2.840.10008.1.3.10"): + # File is not a DICOMDIR + print "This file is not a DICOMDIR" + else: + # Not present + print "Media Storage SOP Class not present" + quit() + + # Iterate through the DICOMDIR data set + iterator = dataSet.GetDES().begin() + while (not iterator.equal(dataSet.GetDES().end())): + dataElement = iterator.next() + + # Check the element tag + if (dataElement.GetTag() == gdcm.Tag(0x004, 0x1220)): + # The 'Directory Record Sequence' element + sequence = dataElement.GetValueAsSQ() + + # Loop through the sequence items + itemNr = 1 + while (itemNr < sequence.GetNumberOfItems()): + item = sequence.GetItem(itemNr) + + # Check the element tag + if (item.FindDataElement(gdcm.Tag(0x0004, 0x1430))): + # The 'Directory Record Type' element + value = str(item.GetDataElement(gdcm.Tag(0x0004, 0x1430)).GetValue()) + + # PATIENT + while (value.strip() == "PATIENT"): + print value.strip() + # Print patient name + if (item.FindDataElement(gdcm.Tag(0x0010, 0x0010))): + value = str(item.GetDataElement(gdcm.Tag(0x0010, 0x0010)).GetValue()) + print value + + # Print patient ID + if (item.FindDataElement(gdcm.Tag(0x0010, 0x0020))): + value = str(item.GetDataElement(gdcm.Tag(0x0010, 0x0020)).GetValue()) + print value + + # Next + itemNr = itemNr + 1 + item = sequence.GetItem(itemNr) + if (item.FindDataElement(gdcm.Tag(0x0004, 0x1430))): + value = str(item.GetDataElement(gdcm.Tag(0x0004, 0x1430)).GetValue()) + + # STUDY + while (value.strip() == "STUDY"): + print value.strip() + + # Print study UID + if (item.FindDataElement(gdcm.Tag(0x0020, 0x000d))): + value = str(item.GetDataElement(gdcm.Tag(0x0020, 0x000d)).GetValue()) + print value + + # Print study date + if (item.FindDataElement(gdcm.Tag(0x0008, 0x0020))): + value = str(item.GetDataElement(gdcm.Tag(0x0008, 0x0020)).GetValue()) + print value + + # Print study description + if (item.FindDataElement(gdcm.Tag(0x0008, 0x1030))): + value = str(item.GetDataElement(gdcm.Tag(0x0008, 0x1030)).GetValue()) + print value + + # Next + itemNr = itemNr + 1 + item = sequence.GetItem(itemNr) + if (item.FindDataElement(gdcm.Tag(0x0004, 0x1430))): + value = str(item.GetDataElement(gdcm.Tag(0x0004, 0x1430)).GetValue()) + + # SERIES + while (value.strip() == "SERIES"): + print value.strip() + + # Print series UID + if (item.FindDataElement(gdcm.Tag(0x0020, 0x000e))): + value = str(item.GetDataElement(gdcm.Tag(0x0020, 0x000e)).GetValue()) + print value + + # Print series modality + if (item.FindDataElement(gdcm.Tag(0x0008, 0x0060))): + value = str(item.GetDataElement(gdcm.Tag(0x0008, 0x0060)).GetValue()) + print "Modality" + print value + + # Print series description + if (item.FindDataElement(gdcm.Tag(0x0008, 0x103e))): + value = str(item.GetDataElement(gdcm.Tag(0x0008, 0x103e)).GetValue()) + print "Description" + print value + + # Next + itemNr = itemNr + 1 + item = sequence.GetItem(itemNr) + if (item.FindDataElement(gdcm.Tag(0x0004, 0x1430))): + value = str(item.GetDataElement(gdcm.Tag(0x0004, 0x1430)).GetValue()) + + # IMAGE + while (value.strip() == "IMAGE"): + print value.strip() + + # Print image UID + if (item.FindDataElement(gdcm.Tag(0x0004, 0x1511))): + value = str(item.GetDataElement(gdcm.Tag(0x0004, 0x1511)).GetValue()) + print value + + # Next + if (itemNr < sequence.GetNumberOfItems()): + itemNr = itemNr + 1 + else: + break + + item = sequence.GetItem(itemNr) + if (item.FindDataElement(gdcm.Tag(0x0004, 0x1430))): + value = str(item.GetDataElement(gdcm.Tag(0x0004, 0x1430)).GetValue()) + + # Next + itemNr = itemNr + 1 diff --git a/gdcm/Examples/Python/RemovePrivateTags.py b/gdcm/Examples/Python/RemovePrivateTags.py new file mode 100644 index 0000000..0de39d4 --- /dev/null +++ b/gdcm/Examples/Python/RemovePrivateTags.py @@ -0,0 +1,51 @@ +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +""" +Usage: + + python RemovePrivateTags.py input.dcm output.dcm +""" + +import sys +import gdcm + + +if __name__ == "__main__": + + file1 = sys.argv[1] + file2 = sys.argv[2] + + # Instanciate the reader. + r = gdcm.Reader() + r.SetFileName( file1 ) + if not r.Read(): + sys.exit(1) + + # Remove private tags + ano = gdcm.Anonymizer() + ano.SetFile( r.GetFile() ) + if not ano.RemovePrivateTags(): + sys.exit(1) + + # Write DICOM file + w = gdcm.Writer() + w.SetFile( ano.GetFile() ) + #w.CheckFileMetaInformationOff() # Do not attempt to check meta header + w.SetFileName( file2 ) + if not w.Write(): + sys.exit(1) + + # It is usually a good idea to exit the script with an error, as gdcm does not remove partial (incorrect) DICOM file + # (application level) diff --git a/gdcm/Examples/Python/ScanDirectory.py b/gdcm/Examples/Python/ScanDirectory.py new file mode 100644 index 0000000..f8fdad3 --- /dev/null +++ b/gdcm/Examples/Python/ScanDirectory.py @@ -0,0 +1,69 @@ +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +import gdcm +import sys,os + +class ProgressWatcher(gdcm.SimpleSubjectWatcher): + def ShowProgress(self, sender, event): + pe = gdcm.ProgressEvent.Cast(event) + print pe.GetProgress() + def EndFilter(self): + print "Yay ! I am done" + +if __name__ == "__main__": + directory = sys.argv[1] + + # Define the set of tags we are interested in + t1 = gdcm.Tag(0x8,0x8); + t2 = gdcm.Tag(0x10,0x10); + + # Iterate over directory + d = gdcm.Directory(); + nfiles = d.Load( directory ); + if(nfiles == 0): sys.exit(1); + # System.Console.WriteLine( "Files:\n" + d.toString() ); + + filenames = d.GetFilenames() + + # Get rid of any Warning while parsing the DICOM files + gdcm.Trace.WarningOff() + + # instanciate Scanner: + sp = gdcm.Scanner.New(); + s = sp.__ref__() + w = ProgressWatcher(s, 'Watcher') + + s.AddTag( t1 ); + s.AddTag( t2 ); + b = s.Scan( filenames ); + if(not b): sys.exit(1); + + print "success" ; + #print s + + pttv = gdcm.PythonTagToValue( s.GetMapping( filenames[1] ) ) + pttv.Start() + # iterate until the end: + while( not pttv.IsAtEnd() ): + # get current value for tag and associated value: + # if tag was not found, then it was simply not added to the internal std::map + # Warning value can be None + tag = pttv.GetCurrentTag() + value = pttv.GetCurrentValue() + print tag,"->",value + # increment iterator + pttv.Next() + + sys.exit(0) diff --git a/gdcm/Examples/Python/SortImage.py b/gdcm/Examples/Python/SortImage.py new file mode 100644 index 0000000..2a8715f --- /dev/null +++ b/gdcm/Examples/Python/SortImage.py @@ -0,0 +1,46 @@ +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +""" +Usage: + + python SortImage.py dirname +""" + +import gdcm +import sys + +def PrintProgress(object, event): + assert event == "ProgressEvent" + print "Progress:", object.GetProgress() + +def MySort(ds1, ds2): + # compare ds1 + return False + +if __name__ == "__main__": + + dirname = sys.argv[1] + d = gdcm.Directory() + d.Load( dirname ) + + print d + + sorter = gdcm.Sorter() + sorter.SetSortFunction( MySort ) + #sorter.AddObserver( "ProgressEvent", PrintProgress ) + sorter.Sort( d.GetFilenames() ) + + print "Sorter:" + print sorter diff --git a/gdcm/Examples/Python/WriteBuffer.py b/gdcm/Examples/Python/WriteBuffer.py new file mode 100644 index 0000000..f0c7419 --- /dev/null +++ b/gdcm/Examples/Python/WriteBuffer.py @@ -0,0 +1,84 @@ +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +""" +Usage: + +http://chuckhahm.com/Ischem/Zurich/XX_0134 + +(2005,1132) SQ (Sequence with undefined length #=8) # u/l, 1 Unknown Tag & Data + (fffe,e000) na (Item with undefined length #=9) # u/l, 1 Item + (2005,0011) LO [Philips MR Imaging DD 002] # 26, 1 PrivateCreator + (2005,1137) PN [PDF_CONTROL_GEN_PARS] # 20, 1 Unknown Tag & Data + (2005,1138) PN (no value available) # 0, 0 Unknown Tag & Data + (2005,1139) PN [IEEE_PDF] # 8, 1 Unknown Tag & Data + (2005,1140) PN (no value available) # 0, 0 Unknown Tag & Data + (2005,1141) PN (no value available) # 0, 0 Unknown Tag & Data + (2005,1143) SL 3103 # 4, 1 Unknown Tag & Data + (2005,1144) OW 0566\0000\013b\0000\0a4a\0000\000e\0000\0a7a\0000\0195\0000\0008... # 3104, 1 Unknown Tag & Data + (2005,1147) CS [Y] # 2, 1 Unknown Tag & Data + (fffe,e00d) na (ItemDelimitationItem) # 0, 0 ItemDelimitationItem + (fffe,e000) na (Item with undefined length #=9) # u/l, 1 Item + (2005,0011) LO [Philips MR Imaging DD 002] # 26, 1 PrivateCreator + (2005,1137) PN [PDF_CONTROL_PREP_PARS] # 22, 1 Unknown Tag & Data + (2005,1138) PN (no value available) # 0, 0 Unknown Tag & Data + (2005,1139) PN [IEEE_PDF] # 8, 1 Unknown Tag & Data + (2005,1140) PN (no value available) # 0, 0 Unknown Tag & Data + (2005,1141) PN (no value available) # 0, 0 Unknown Tag & Data + (2005,1143) SL 7934 # 4, 1 Unknown Tag & Data + (2005,1144) OW 19b6\0000\005f\0000\1b2a\0000\00f3\0000\1eee\0000\0000\0000\0008... # 7934, 1 Unknown Tag & Data + (2005,1147) CS [Y] # 2, 1 Unknown Tag & Data + (fffe,e00d) na (ItemDelimitationItem) # 0, 0 ItemDelimitationItem +... +""" + +import sys +import gdcm + +if __name__ == "__main__": + + file1 = sys.argv[1] + file2 = sys.argv[2] + + r = gdcm.Reader() + r.SetFileName( file1 ) + if not r.Read(): + sys.exit(1) + + fg = gdcm.FilenameGenerator() + f = r.GetFile() + ds = f.GetDataSet() + tsis = gdcm.Tag(0x2005,0x1132) # + if ds.FindDataElement( tsis ): + sis = ds.GetDataElement( tsis ) + #sqsis = sis.GetSequenceOfItems() + # GetValueAsSQ handle more cases + sqsis = sis.GetValueAsSQ() + if sqsis.GetNumberOfItems(): + nitems = sqsis.GetNumberOfItems(); + fg.SetNumberOfFilenames( nitems ) + fg.SetPrefix( file2 ) + if not fg.Generate(): + print "problem" + sys.exit(1) + for i in range(0,nitems): + item1 = sqsis.GetItem(i+1) # Item start at 1 + nestedds = item1.GetNestedDataSet() + tprcs = gdcm.Tag(0x2005,0x1144) # + if nestedds.FindDataElement( tprcs ): + prcs = nestedds.GetDataElement( tprcs ) + bv = prcs.GetByteValue() + print bv + f = open( fg.GetFilename(i) , "w" ) + f.write( bv.WriteBuffer() ) diff --git a/gdcm/INSTALL.txt b/gdcm/INSTALL.txt new file mode 100644 index 0000000..b87671b --- /dev/null +++ b/gdcm/INSTALL.txt @@ -0,0 +1,36 @@ +See the wiki page at: +http://gdcm.sourceforge.net/wiki/index.php/Getting_Started + +If you are reading this file, it certainly means you do not know how to build GDCM. See: +http://gdcm.sourceforge.net/wiki/index.php/Configuring_and_Building + +On UNIX (with cmake) this is simply a matter of doing: + * git clone --branch release git://git.code.sf.net/p/gdcm/gdcm + * mkdir gdcmbin + * cd gdcmbin + * ccmake ../gdcm + [select your configuration] + * Press 'c' (configure), Press 'g' (generate) + * make +The following step is not required, as gdcm will work from a build tree too: + * make install + +If you want to live on the edge, you should try the latest trunk instead: + + * git clone git://git.code.sf.net/p/gdcm/gdcm + +If you want to retrieve the gdcmData as part of your git clone, use instead: + + * git clone --recursive git://git.code.sf.net/p/gdcm/gdcm + +Major options explained: +* GDCM_BUILD_SHARED_LIBS: Turn it on if you want shared libs (instead of static libs), greatly reduce executable size, allowing code reuse. +* GDCM_WRAP_PYTHON: turn it on if you want to be able to access the GDCM API via python (required python dev files) +* GDCM_WRAP_CSHARP: turn it on if you want to be able to access the GDCM API via C# (required mono or .NET environment) +* GDCM_WRAP_JAVA: turn it on if you want to be able to access the GDCM API via java (required java sdk to compile) +* GDCM_WRAP_PHP: turn it on if you want to be able to access the GDCM API via php (experimental) +* GDCM_USE_VTK: turn if on if you want to be able to load DICOM file in VTK context (requires VTK) +* GDCM_BUILD_APPLICATIONS: turn it on if you want the build gdcm applications (gdcmdump, gdcmconv, gdcminfo ...) +* GDCM_BUILD_TESTING: Turn it on if you want to be able to exectute GDCM testing suite +* GDCM_DOCUMENTATION: turn it on if you want to generate the developer documentation (require doxygen) +* GDCM_BUILD_EXAMPLES: turn it on if you want to build simple examples that demonstrates GDCM usage. diff --git a/gdcm/PACKAGER b/gdcm/PACKAGER new file mode 100644 index 0000000..f98b849 --- /dev/null +++ b/gdcm/PACKAGER @@ -0,0 +1,50 @@ +Info for packagers: + +At a minimum you should consider the following cmake options: + +CMAKE_SKIP_RPATH:BOOL=YES +CMAKE_INSTALL_PREFIX:PATH=/usr +To build the cmd line applications: +GDCM_BUILD_APPLICATIONS:BOOL=ON +To build shared libs: +GDCM_BUILD_SHARED_LIBS:BOOL=ON +To build the documentation (need doxygen >= 1.6.1) +GDCM_DOCUMENTATION:BOOL=ON + +You should really consider: +GDCM_BUILD_TESTING:BOOL=OFF +Otherwise it build extra code only needed to run the unit test of gdcm... + +unless you have some specific compiler optimization technique you should use the cmake default one: +CMAKE_BUILD_TYPE:STRING=Release + +By default this will build pdf doc if you have all the required package, if you do not want the pdf: +GDCM_PDF_DOCUMENTATION:BOOL=ON + +Wrapping: +GDCM support the following wrapped language +GDCM_WRAP_PYTHON:BOOL=ON +GDCM_WRAP_CSHARP:BOOL=ON +GDCM_WRAP_JAVA:BOOL=ON + +There is an ongoing effort to make PHP another supported language (very experimental ATM) +GDCM_WRAP_PHP:BOOL=ON + +For VTK user: +GDCM_USE_VTK:BOOL=ON + +System libs: +- By default gdcm ships with system libs for ease of compilation on win32 system. So for most *nix system you may want: +GDCM_USE_SYSTEM_EXPAT:BOOL=ON +GDCM_USE_SYSTEM_ZLIB:BOOL=ON +GDCM_USE_SYSTEM_UUID:BOOL=ON +GDCM_USE_SYSTEM_OPENJPEG:BOOL=ON + +OpenSSL option is slightly different as not 'convenient' openssl is shipped within GDCM, so the only +way to access the openssl functionalities is to have openssl installed in the target system. +GDCM_USE_SYSTEM_OPENSSL:BOOL=ON + +Examples: +GDCM comes with some examples for user, but setting the following: +GDCM_BUILD_EXAMPLES:BOOL=ON +will not do anything since there is no install rule for examples... diff --git a/gdcm/README.Copyright.txt b/gdcm/README.Copyright.txt new file mode 100644 index 0000000..e0cb443 --- /dev/null +++ b/gdcm/README.Copyright.txt @@ -0,0 +1,9 @@ +December 28, 2008 + +Historical note: + +Starting with gdcm 2.0.11, GDCM, Grassroots DICOM is distributed +under the new simplified BSD license, approved by the Open Source Initiative (OSI) +* http://www.opensource.org/licenses/bsd-license.php + +See Copyright.txt diff --git a/gdcm/README.txt b/gdcm/README.txt new file mode 100644 index 0000000..45b588c --- /dev/null +++ b/gdcm/README.txt @@ -0,0 +1,51 @@ +This is the source code of GDCM. It is available from sf.net website. +Official GIT repository is at: + + https://sourceforge.net/p/gdcm/gdcm/ + +For a general introduction/features/limitations/requirement please +refer to + + http://gdcm.sourceforge.net/ + +Just a quick note on the build process of GDCM. GDCM build process +make use of the cmake software(*). This allow us: +1. To get rid of the autoconf/autotools insanity +2. Transparently generate Unix Makefiles, NMake Makefiles, +VS8/9/10 Solution, XCode 2.1... +3. Automatic nightly testing, one of the most important thing +for a robust library/software devlpt process. GDCM devpt is develop +based on the XP definition, and to preserve backward compatibility +make sure that code is working from one release to another: each night +we configure, we build and we test GDCM. The result are then send to +the dashboard located at: + + http://public.kitware.com/dashboard.php?name=gdcm + +A continuous dashboard make also sure that any commit did not introduce +any error on another plateform, a warning or broke a test... + +Therefore you should be able to use GDCM from the bleeding edge without +knowing too much on what is going on. All you need to do is have a look +at the GDCM dashboard, and if your plateform is 'green' then you can +update your git copy and compile safely knowing that there are very few chances +that something won't work. Cheers ! + + +(*) http://www.cmake.org for more information + +For more help you can go online in the GDCM Wiki: +* http://gdcm.sourceforge.net/ + +In Particular: +* http://gdcm.sourceforge.net/wiki/index.php/GDCM_Release_2.0 +* http://gdcm.sourceforge.net/wiki/index.php/FAQ + +And a page describing each tool can be found at: +* http://gdcm.sourceforge.net/wiki/index.php/End_User_Applications + +Eg: +* http://gdcm.sourceforge.net/wiki/index.php/Gdcminfo + +Need VTK: +* http://gdcm.sourceforge.net/wiki/index.php/Gdcmviewer diff --git a/gdcm/Source/Attribute/CMakeLists.txt b/gdcm/Source/Attribute/CMakeLists.txt new file mode 100644 index 0000000..e69de29 diff --git a/gdcm/Source/Attribute/README.txt b/gdcm/Source/Attribute/README.txt new file mode 100644 index 0000000..c6cc69f --- /dev/null +++ b/gdcm/Source/Attribute/README.txt @@ -0,0 +1 @@ +Part 3.1 diff --git a/gdcm/Source/CMakeLists.txt b/gdcm/Source/CMakeLists.txt new file mode 100644 index 0000000..7e15867 --- /dev/null +++ b/gdcm/Source/CMakeLists.txt @@ -0,0 +1,10 @@ +# ... +subdirs( + Common + Attribute + DataDictionary + DataStructureAndEncodingDefinition + InformationObjectDefinition + MediaStorageAndFileFormat + MessageExchangeDefinition + ) diff --git a/gdcm/Source/Common/CMakeLists.txt b/gdcm/Source/Common/CMakeLists.txt new file mode 100644 index 0000000..2f4e067 --- /dev/null +++ b/gdcm/Source/Common/CMakeLists.txt @@ -0,0 +1,207 @@ +#----------------------------------------------------------------------------- +# Rebuild gdcm whenever a file starting with gdcm* is modified +include_regular_expression("^gdcm.*$") + +# configure the .h file +option(GDCM_ALWAYS_TRACE_MACRO "When set to ON, gdcm::Trace macros will dumps message (override NDEBUG settings)" OFF) +option(GDCM_SUPPORT_BROKEN_IMPLEMENTATION "Handle broken DICOM" ON) +mark_as_advanced( + GDCM_ALWAYS_TRACE_MACRO + GDCM_SUPPORT_BROKEN_IMPLEMENTATION + GDCM_AUTOLOAD_GDCMJNI + ) + +#if(WIN32) +# if (BUILD_SHARED_LIBS) +# add_definitions(-DPOLARSSL_DLL) +# endif () +#endif() + + +CHECK_INCLUDE_FILE_CONCAT("sys/time.h" GDCM_HAVE_SYS_TIME_H) +CHECK_INCLUDE_FILE_CONCAT("winsock.h" GDCM_HAVE_WINSOCK_H) +CHECK_INCLUDE_FILE_CONCAT("byteswap.h" GDCM_HAVE_BYTESWAP_H) +CHECK_INCLUDE_FILE("rpc.h" GDCM_HAVE_RPC_H) +CHECK_INCLUDE_FILE("langinfo.h" GDCM_HAVE_LANGINFO_H) + +include(CheckFunctionExists) +# See http://public.kitware.com/Bug/view.php?id=8246 +include(CheckSymbolExists) +CHECK_SYMBOL_EXISTS(nl_langinfo "langinfo.h" GDCM_HAVE_NL_LANGINFO) +#C99 +#CHECK_FUNCTION_EXISTS(strcasecmp GDCM_HAVE_STRCASECMP) +CHECK_SYMBOL_EXISTS(strcasecmp "strings.h" GDCM_HAVE_STRCASECMP) +#CHECK_FUNCTION_EXISTS(strncasecmp GDCM_HAVE_STRNCASECMP) +CHECK_SYMBOL_EXISTS(strncasecmp "strings.h" GDCM_HAVE_STRNCASECMP) +#CHECK_FUNCTION_EXISTS(snprintf GDCM_HAVE_SNPRINTF) +CHECK_SYMBOL_EXISTS(snprintf "stdio.h" GDCM_HAVE_SNPRINTF) +#CHECK_SYMBOL_EXISTS(strptime "time.h" GDCM_HAVE_STRPTIME) +CHECK_FUNCTION_EXISTS(strptime GDCM_HAVE_STRPTIME) +#M$ extension: +CHECK_FUNCTION_EXISTS(_stricmp GDCM_HAVE__STRICMP) +CHECK_FUNCTION_EXISTS(_strnicmp GDCM_HAVE__STRNICMP) +CHECK_FUNCTION_EXISTS(_snprintf GDCM_HAVE__SNPRINTF) + +#include(CheckSymbolExists) +CHECK_FUNCTION_EXISTS(gettimeofday GDCM_HAVE_GETTIMEOFDAY) + +include(CheckCXXSourceCompiles) +CHECK_CXX_SOURCE_COMPILES( + "int main() { const char *f = __FUNCTION__; return 0;}" + GDCM_CXX_HAS_FUNCTION) +CHECK_CXX_SOURCE_COMPILES( + "\#include \nint main() { const wchar_t fn[10] = {}; std::ifstream is( fn ); return 0;}" + GDCM_HAVE_WCHAR_IFSTREAM) +if(GDCM_USE_SYSTEM_OPENSSL) +set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR}) +set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_LIBRARIES} + ${CMAKE_DL_LIBS} # FIXME ?? + ) +CHECK_CXX_SOURCE_COMPILES( + # "\#include \nint main() { CMS_add0_recipient_key(0); return 0;}" + #HAVE_CMS_RECIPIENT_KEY) + "\#include \nint main() { CMS_add0_recipient_password(0,0,0,0,0,0,0); return 0;}" + GDCM_HAVE_CMS_RECIPIENT_PASSWORD) +endif() + +#----------------------------------------------------------------------------- +# Provide compatibility options. +option(GDCM_LEGACY_REMOVE "Remove all legacy code completely." OFF) +option(GDCM_LEGACY_SILENT "Silence all legacy code messages." OFF) +mark_as_advanced(GDCM_LEGACY_REMOVE GDCM_LEGACY_SILENT) + + +configure_file( + "${GDCM_SOURCE_DIR}/Source/Common/gdcmConfigure.h.in" + "${GDCM_BINARY_DIR}/Source/Common/gdcmConfigure.h" + ) + +# Add the include paths +include_directories( + "${GDCM_BINARY_DIR}/Source/Common" + "${GDCM_SOURCE_DIR}/Source/Common" + "${GDCM_SOURCE_DIR}/Source/DataStructureAndEncodingDefinition" + + "${GDCM_BINARY_DIR}/Testing/Source/Data" + "${GDCM_SOURCE_DIR}/Testing/Source/Data" + + "${GDCM_SOURCE_DIR}/Utilities" + ) + +if(GDCM_BUILD_TESTING) +include_directories( + "${GDCM_BINARY_DIR}/Utilities/gdcmmd5" +) +endif() + +if(NOT GDCM_USE_SYSTEM_ZLIB) +include_directories( + "${GDCM_BINARY_DIR}/Utilities/gdcmzlib" +) +endif() +#if(NOT GDCM_USE_SYSTEM_POLARSSL) +#include_directories( +# "${GDCM_SOURCE_DIR}/Utilities/gdcmpolarssl/include" +#) +#endif() + +set(Common_SRCS + gdcmVersion.cxx + gdcmRegion.cxx + gdcmBoxRegion.cxx + gdcmEvent.cxx + gdcmDataEvent.cxx + gdcmProgressEvent.cxx + gdcmFileNameEvent.cxx + gdcmCommand.cxx + gdcmMD5.cxx + gdcmBase64.cxx + gdcmSHA1.cxx + gdcmDummyValueGenerator.cxx + #gdcmCryptographicMessageSyntax.cxx + + gdcmCryptographicMessageSyntax.cxx + gdcmCryptoFactory.cxx + + gdcmASN1.cxx + gdcmObject.cxx + gdcmSubject.cxx + gdcmDirectory.cxx + gdcmTerminal.cxx + gdcmString.cxx + gdcmFilename.cxx + gdcmFilenameGenerator.cxx + gdcmSwapCode.cxx + gdcmSystem.cxx + gdcmTrace.cxx + gdcmException.cxx + gdcmDeflateStream.cxx + gdcmByteSwap.cxx + gdcmUnpacker12Bits.cxx + ) + +if(WIN32) +set(Common_SRCS ${Common_SRCS} + gdcmCAPICryptographicMessageSyntax.cxx + gdcmCAPICryptoFactory.cxx +) +endif() + +if(GDCM_USE_SYSTEM_OPENSSL) +set(Common_SRCS ${Common_SRCS} + gdcmOpenSSLP7CryptoFactory.cxx + gdcmOpenSSLP7CryptographicMessageSyntax.cxx +) +endif() + +if(GDCM_USE_SYSTEM_OPENSSL AND GDCM_HAVE_CMS_RECIPIENT_PASSWORD) +set(Common_SRCS ${Common_SRCS} + gdcmOpenSSLCryptoFactory.cxx + gdcmOpenSSLCryptographicMessageSyntax.cxx +) +endif() + +if(GDCM_BUILD_TESTING) +set(Common_SRCS ${Common_SRCS} + gdcmTesting.cxx +) +endif() + +add_library(gdcmCommon ${Common_SRCS}) +set_target_properties(gdcmCommon PROPERTIES ${GDCM_LIBRARY_PROPERTIES} LINK_INTERFACE_LIBRARIES "") + +#target_link_libraries(gdcmCommon ${GDCM_ZLIB_LIBRARIES}) # ${GDCM_POLARSSL_LIBRARIES}) +if(GDCM_BUILD_TESTING) +target_link_libraries(gdcmCommon gdcmmd5 ) +endif() +if(APPLE) + target_link_libraries(gdcmCommon ${COREFOUNDATION_LIBRARY}) +endif() +if(UNIX) + target_link_libraries(gdcmCommon ${CMAKE_DL_LIBS}) +endif() + +if(WIN32) + target_link_libraries(gdcmCommon ws2_32) + target_link_libraries(gdcmCommon crypt32) +endif() + +if(GDCM_USE_SYSTEM_OPENSSL) + include_directories(${OPENSSL_INCLUDE_DIR}) + target_link_libraries(gdcmCommon ${OPENSSL_LIBRARIES}) +endif() + +# libs +install_library(gdcmCommon) +# PDB +install_pdb(gdcmCommon) +# include files +install_includes("*.h" "*.txx") + +# Install generated files +if(NOT GDCM_INSTALL_NO_DEVELOPMENT) + install(FILES ${header_files} + "${GDCM_BINARY_DIR}/Source/Common/gdcmConfigure.h" + DESTINATION ${GDCM_INSTALL_INCLUDE_DIR} COMPONENT Headers + ) +endif() diff --git a/gdcm/Source/Common/README.txt b/gdcm/Source/Common/README.txt new file mode 100644 index 0000000..7093b54 --- /dev/null +++ b/gdcm/Source/Common/README.txt @@ -0,0 +1 @@ +some sort of utilities. Like byte swapping not really defined in DICOM but useful diff --git a/gdcm/Source/Common/gdcmASN1.cxx b/gdcm/Source/Common/gdcmASN1.cxx new file mode 100644 index 0000000..55319ad --- /dev/null +++ b/gdcm/Source/Common/gdcmASN1.cxx @@ -0,0 +1,137 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmASN1.h" +#include "gdcmSystem.h" + +#include + +#ifdef GDCM_USE_SYSTEM_OPENSSL +#include +#include +#include +#include +#include +#include +#include +#endif + +#include + +/* + */ +namespace gdcm +{ + +class ASN1Internals +{ +public: +}; + +ASN1::ASN1() +{ + Internals = new ASN1Internals; +} + +ASN1::~ASN1() +{ + delete Internals; +} + +bool ASN1::ParseDumpFile(const char *filename) +{ + if(!filename) return false; + std::ifstream is(filename, std::ios::binary); + if( !is.good() ) return false; + size_t length = System::FileSize(filename); + char * str = new char[length]; + is.read( str, length ); + bool b = ParseDump( str, length ); + delete[] str; + return b; +} + +bool ASN1::ParseDump(const char *array, size_t length) +{ +#ifdef GDCM_USE_SYSTEM_OPENSSL + // check array pointer: + // if length == 0, then return ok. This is an empty element. + if( !array ) return !length; + + int indent = 1; // 0 is not visually nice + int dump = 0; // -1 => will print hex stuff + BIO *out=NULL; + + out=BIO_new(BIO_s_file()); + assert( out ); + BIO_set_fp(out,stdout,BIO_NOCLOSE|BIO_FP_TEXT); + if (!ASN1_parse_dump(out,(unsigned char*)array,length,indent,dump) ) + { + return false; + } + + return true; +#else + (void)array; + (void)length; + gdcmDebugMacro( "GDCM_USE_SYSTEM_OPENSSL is OFF" ); + return false; +#endif +} + +#ifdef GDCM_USE_SYSTEM_OPENSSL +static int print_hex(unsigned char *buf, int len) +{ + int i; + int n; + + for(i=0,n=0;i 7){ + printf("\n"); + n = 0; + } + printf("0x%02x, ",buf[i]); + n++; + } + printf("\n"); + + return(0); +} +#endif + + +int ASN1::TestPBKDF2() +{ +#ifdef GDCM_USE_SYSTEM_OPENSSL + const char pass[] = "password"; + const char salt[] = "12340000"; + int ic = 1; + unsigned char buf[1024]; + + ic = 1; + PKCS5_PBKDF2_HMAC_SHA1(pass, (int)strlen(pass), (unsigned char*)salt, + (int)strlen(salt), ic, 32+16, buf); + printf("PKCS5_PBKDF2_HMAC_SHA1(\"%s\", \"%s\", %d)=\n", pass, salt, ic); + print_hex(buf, 32+16); + + ic = 1; + EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(), (unsigned char*)salt, + (unsigned char*)pass, (int)strlen(pass), ic, buf, buf+32); + printf("EVP_BytesToKey(\"%s\", \"%s\", %d)=\n", pass, salt, ic); + print_hex(buf, 32+16); + +#endif + return 0; +} + +} // end namespace gdcm diff --git a/gdcm/Source/Common/gdcmASN1.h b/gdcm/Source/Common/gdcmASN1.h new file mode 100644 index 0000000..c1fe46c --- /dev/null +++ b/gdcm/Source/Common/gdcmASN1.h @@ -0,0 +1,49 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMASN1_H +#define GDCMASN1_H + +#include "gdcmTypes.h" + + +namespace gdcm +{ +//----------------------------------------------------------------------------- +class ASN1Internals; +/** + * \brief Class for ASN1 + * + */ +class GDCM_EXPORT ASN1 +{ +public : + ASN1(); + ~ASN1(); + + static bool ParseDumpFile(const char *filename); + + static bool ParseDump(const char *array, size_t length); + +protected: + int TestPBKDF2(); + +private: + ASN1Internals *Internals; +private: + ASN1(const ASN1&); // Not implemented. + void operator=(const ASN1&); // Not implemented. +}; +} // end namespace gdcm +//----------------------------------------------------------------------------- +#endif //GDCMASN1_H diff --git a/gdcm/Source/Common/gdcmBase64.cxx b/gdcm/Source/Common/gdcmBase64.cxx new file mode 100644 index 0000000..065350c --- /dev/null +++ b/gdcm/Source/Common/gdcmBase64.cxx @@ -0,0 +1,173 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmBase64.h" +#include // memcpy +#include + +namespace gdcm +{ +/* + base64.cpp and base64.h + + Copyright (C) 2004-2008 René Nyffenegger + + This source code is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this source code must not be misrepresented; you must not + claim that you wrote the original source code. If you use this source code + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original source code. + + 3. This notice may not be removed or altered from any source distribution. + + René Nyffenegger rene.nyffenegger@adp-gmbh.ch + +*/ + + +static const std::string base64_chars = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + + +static inline bool is_base64(unsigned char c) { + return (isalnum(c) || (c == '+') || (c == '/')); +} + +static std::string base64_encode(unsigned char const* bytes_to_encode, size_t in_len) +{ + std::string ret; + size_t i = 0; + size_t j = 0; + unsigned char char_array_3[3]; + unsigned char char_array_4[4]; + + while (in_len--) { + char_array_3[i++] = *(bytes_to_encode++); + if (i == 3) { + char_array_4[0] = (unsigned char)((char_array_3[0] & 0xfc) >> 2); + char_array_4[1] = (unsigned char)(((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4)); + char_array_4[2] = (unsigned char)(((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6)); + char_array_4[3] = (unsigned char)(char_array_3[2] & 0x3f); + + for(i = 0; i < 4; i++) + ret += base64_chars[char_array_4[i]]; + i = 0; + } + } + + if (i) + { + for(j = i; j < 3; j++) + char_array_3[j] = '\0'; + + char_array_4[0] = (unsigned char)((char_array_3[0] & 0xfc) >> 2); + char_array_4[1] = (unsigned char)(((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4)); + char_array_4[2] = (unsigned char)(((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6)); + char_array_4[3] = (unsigned char)(char_array_3[2] & 0x3f); + + for (j = 0; j < i + 1; j++) + ret += base64_chars[char_array_4[j]]; + + while((i++ < 3)) + ret += '='; + + } + + return ret; +} + +static std::string base64_decode(std::string const& encoded_string) +{ + size_t in_len = encoded_string.size(); + size_t i = 0; + size_t j = 0; + size_t in_ = 0; + unsigned char char_array_4[4], char_array_3[3]; + std::string ret; + + while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) { + char_array_4[i++] = encoded_string[in_]; in_++; + if (i ==4) { + for (i = 0; i <4; i++) + char_array_4[i] = (unsigned char)base64_chars.find(char_array_4[i]); + + char_array_3[0] = (unsigned char)((char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4)); + char_array_3[1] = (unsigned char)(((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2)); + char_array_3[2] = (unsigned char)(((char_array_4[2] & 0x3) << 6) + char_array_4[3]); + + for (i = 0; (i < 3); i++) + ret += char_array_3[i]; + i = 0; + } + } + + if (i) { + for (j = i; j <4; j++) + char_array_4[j] = 0; + + for (j = 0; j <4; j++) + char_array_4[j] = (unsigned char)base64_chars.find(char_array_4[j]); + + char_array_3[0] = (unsigned char)((char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4)); + char_array_3[1] = (unsigned char)(((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2)); + char_array_3[2] = (unsigned char)(((char_array_4[2] & 0x3) << 6) + char_array_4[3]); + + for (j = 0; (j < i - 1); j++) ret += char_array_3[j]; + } + + return ret; +} + +size_t Base64::GetEncodeLength(const char *src, size_t slen ) +{ + std::string ret = base64_encode((unsigned char*)src, slen); + return ret.size(); +} + +size_t Base64::Encode( char *dst, size_t dlen, const char *src, size_t slen ) +{ + const std::string & ret = base64_encode((unsigned char*)src, slen); + if( ret.size() > dlen ) + return 0; + memcpy( dst, ret.c_str(), ret.size() ); + return ret.size(); +} + +size_t Base64::GetDecodeLength( const char *src, size_t slen ) +{ + const std::string & ret = base64_decode( std::string( src, slen) ); + return ret.size(); +} + +size_t Base64::Decode( char *dst, size_t dlen, const char *src, size_t slen ) +{ + const std::string & ret = base64_decode( std::string( src, slen) ); + if( ret.size() > dlen ) + return 0; + memcpy( dst, ret.c_str(), ret.size() ); + return ret.size(); +} + +} // end namespace gdcm diff --git a/gdcm/Source/Common/gdcmBase64.h b/gdcm/Source/Common/gdcmBase64.h new file mode 100644 index 0000000..3f0f57c --- /dev/null +++ b/gdcm/Source/Common/gdcmBase64.h @@ -0,0 +1,71 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMBASE64_H +#define GDCMBASE64_H + +#include "gdcmTypes.h" + +namespace gdcm +{ +/** + * \brief Class for Base64 + * + */ +class GDCM_EXPORT Base64 +{ +public: + + /** + * Call this function to obtain the required buffer size + */ + static size_t GetEncodeLength(const char *src, size_t srclen ); + + /** + * \brief Encode a buffer into base64 format + * + * \param dst destination buffer + * \param dlen size of the buffer + * \param src source buffer + * \param slen amount of data to be encoded + * + * \return 0 if not successful, size of encoded otherwise + * + */ + static size_t Encode( char *dst, size_t dlen, const char *src, size_t slen ); + + /** + * Call this function to obtain the required buffer size + */ + static size_t GetDecodeLength( const char *src, size_t len ); + + /** + * \brief Decode a base64-formatted buffer + * + * \param dst destination buffer + * \param dlen size of the buffer + * \param src source buffer + * \param slen amount of data to be decoded + * + * \return 0 if not successful, size of decoded otherwise + */ + static size_t Decode( char *dst, size_t dlen, const char *src, size_t slen ); + +private: + Base64(const Base64&); // Not implemented. + void operator=(const Base64&); // Not implemented. +}; + +} // end namespace gdcm + +#endif // GDCMBASE64_H diff --git a/gdcm/Source/Common/gdcmBoxRegion.cxx b/gdcm/Source/Common/gdcmBoxRegion.cxx new file mode 100644 index 0000000..98c274b --- /dev/null +++ b/gdcm/Source/Common/gdcmBoxRegion.cxx @@ -0,0 +1,156 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmBoxRegion.h" + +#include +#include // req C++11 + +namespace gdcm +{ +class BoxRegionInternals +{ +public: + BoxRegionInternals() + { + XMin = YMin = ZMin = std::numeric_limits::max(); + XMax = YMax = ZMax = std::numeric_limits::min(); + } + unsigned int XMin, XMax; + unsigned int YMin, YMax; + unsigned int ZMin, ZMax; + void Print(std::ostream &os) const + { + os << "Min:" << XMin << "," << YMin << "," << ZMin << "\n"; + os << "Max:" << XMax << "," << YMax << "," << ZMax; + } + +}; + +BoxRegion::BoxRegion() +{ + Internals = new BoxRegionInternals; +} + +BoxRegion::~BoxRegion() +{ + delete Internals; +} + +void BoxRegion::SetDomain(unsigned int xmin, unsigned int xmax, + unsigned int ymin, unsigned int ymax, + unsigned int zmin, unsigned int zmax) +{ + Internals->XMin = xmin; + Internals->YMin = ymin; + Internals->ZMin = zmin; + Internals->XMax = xmax; + Internals->YMax = ymax; + Internals->ZMax = zmax; +} + +Region *BoxRegion::Clone() const +{ + BoxRegion *br = new BoxRegion( *this ); + return br; +} + +bool BoxRegion::Empty() const +{ + assert( 0 ); + return false; +} + +bool BoxRegion::IsValid() const +{ + if (Internals->XMax < Internals->XMin || + Internals->YMax < Internals->YMin || + Internals->ZMax < Internals->ZMin ) + { + return false; + } + return true; +} + +size_t BoxRegion::Area() const +{ + return (Internals->YMax - Internals->YMin + 1)* + (Internals->XMax - Internals->XMin + 1)* + (Internals->ZMax - Internals->ZMin + 1); +} + +unsigned int BoxRegion::GetXMin() const +{ + return Internals->XMin; +} +unsigned int BoxRegion::GetXMax() const +{ + return Internals->XMax; +} +unsigned int BoxRegion::GetYMin() const +{ + return Internals->YMin; +} +unsigned int BoxRegion::GetYMax() const +{ + return Internals->YMax; +} +unsigned int BoxRegion::GetZMin() const +{ + return Internals->ZMin; +} +unsigned int BoxRegion::GetZMax() const +{ + return Internals->ZMax; +} + +BoxRegion BoxRegion::BoundingBox(BoxRegion const & b1, BoxRegion const & b2 ) +{ + BoxRegion r; + unsigned int xmin = std::min( b1.GetXMin(), b2.GetXMin() ); + unsigned int xmax = std::min( b1.GetXMax(), b2.GetXMax() ); + unsigned int ymin = std::min( b1.GetYMin(), b2.GetYMin() ); + unsigned int ymax = std::min( b1.GetYMax(), b2.GetYMax() ); + unsigned int zmin = std::min( b1.GetZMin(), b2.GetZMin() ); + unsigned int zmax = std::min( b1.GetZMax(), b2.GetZMax() ); + + r.SetDomain(xmin, xmax, ymin, ymax, zmin, zmax); + return r; +} + +BoxRegion::BoxRegion(const BoxRegion& b) +{ + assert( b.Internals ); + Internals = new BoxRegionInternals; + *Internals = *b.Internals; +} + +void BoxRegion::operator=(const BoxRegion& b) +{ + assert( b.Internals ); + *Internals = *b.Internals; +} + +BoxRegion BoxRegion::ComputeBoundingBox() +{ + return *this; +} + +void BoxRegion::Print(std::ostream &os) const +{ + Region::Print( os ); + os << "Domain:\n"; + this->Internals->Print( os ); +} + +} // end namespace gdcm diff --git a/gdcm/Source/Common/gdcmBoxRegion.h b/gdcm/Source/Common/gdcmBoxRegion.h new file mode 100644 index 0000000..061daa2 --- /dev/null +++ b/gdcm/Source/Common/gdcmBoxRegion.h @@ -0,0 +1,70 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMBOXREGION_H +#define GDCMBOXREGION_H + +#include "gdcmRegion.h" + +namespace gdcm +{ +class BoxRegionInternals; +/** + * \brief Class for manipulation box region + * This is a very simple implementation of the Region class. + * It only support 3D box type region. + * It assumes the 3D Box does not have a tilt + * Origin is as (0,0,0) + */ +//----------------------------------------------------------------------------- +class GDCM_EXPORT BoxRegion : public Region +{ +public : + BoxRegion(); + ~BoxRegion(); + + /// Set domain + void SetDomain(unsigned int xmin, unsigned int xmax, + unsigned int ymin, unsigned int ymax, + unsigned int zmin, unsigned int zmax); + + /// Get domain + unsigned int GetXMin() const; + unsigned int GetXMax() const; + unsigned int GetYMin() const; + unsigned int GetYMax() const; + unsigned int GetZMin() const; + unsigned int GetZMax() const; + + // Satisfy pure virtual parent class + Region *Clone() const; + bool Empty() const; + bool IsValid() const; + size_t Area() const; + BoxRegion ComputeBoundingBox(); + + void Print(std::ostream &os = std::cout) const; + + /// Helper class to compute the bounding box of two BoxRegion + static BoxRegion BoundingBox(BoxRegion const & b1, BoxRegion const & b2 ); + + /// copy/cstor and al. + BoxRegion(const BoxRegion&); + void operator=(const BoxRegion&); +private: + BoxRegionInternals *Internals; +}; + +} // end namespace gdcm +//----------------------------------------------------------------------------- +#endif //GDCMREGION_H diff --git a/gdcm/Source/Common/gdcmByteSwap.cxx b/gdcm/Source/Common/gdcmByteSwap.cxx new file mode 100644 index 0000000..db30cd5 --- /dev/null +++ b/gdcm/Source/Common/gdcmByteSwap.cxx @@ -0,0 +1,20 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmByteSwap.h" + +namespace gdcm +{ + + +} // end namespace gdcm diff --git a/gdcm/Source/Common/gdcmByteSwap.h b/gdcm/Source/Common/gdcmByteSwap.h new file mode 100644 index 0000000..3b6b34f --- /dev/null +++ b/gdcm/Source/Common/gdcmByteSwap.h @@ -0,0 +1,60 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMBYTESWAP_H +#define GDCMBYTESWAP_H + +#include "gdcmTypes.h" +#include "gdcmSwapCode.h" + +namespace gdcm +{ + +/** + * \brief ByteSwap + * \details Perform machine dependent byte swaping (Little Endian, + * Big Endian, Bad Little Endian, Bad Big Endian). + * TODO: bswap_32 / bswap_64 ... + */ +template +class ByteSwap +{ +public: + /** Query the machine Endian-ness. */ + static bool SystemIsBigEndian (); + static bool SystemIsLittleEndian (); + + static void Swap(T &p); + static void SwapFromSwapCodeIntoSystem(T &p, SwapCode const &sc); + static void SwapRange(T *p, unsigned int num); + static void SwapRangeFromSwapCodeIntoSystem(T *p, SwapCode const &sc, + std::streamoff num); + +protected: +// ByteSwap() {} +// ~ByteSwap() {} + +private: + +}; + +/** + * \example TestByteSwap.cxx + * This is a C++ example on how to use gdcm::ByteSwap + */ + +} // end namespace gdcm + +#include "gdcmByteSwap.txx" + +#endif //GDCMBYTESWAP_H diff --git a/gdcm/Source/Common/gdcmByteSwap.txx b/gdcm/Source/Common/gdcmByteSwap.txx new file mode 100644 index 0000000..b9f1a19 --- /dev/null +++ b/gdcm/Source/Common/gdcmByteSwap.txx @@ -0,0 +1,188 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMBYTESWAP_TXX +#define GDCMBYTESWAP_TXX + +#include "gdcmByteSwap.h" +#include + +#include // abort + +namespace gdcm +{ + +/* + template (class T) +{ +void bswap(inout T i) +{ +byte* p = cast(byte*)&i; +for (int b = 0; b < T.size/2; ++b) +instance swap(byte).swap(p[b], p[T.size-1-b]); +} +} +*/ + + +// Machine definitions +#ifdef GDCM_WORDS_BIGENDIAN +template +bool ByteSwap::SystemIsBigEndian() { return true; } +template +bool ByteSwap::SystemIsLittleEndian() { return false; } +#else +template +bool ByteSwap::SystemIsBigEndian() { return false; } +template +bool ByteSwap::SystemIsLittleEndian() { return true; } +#endif + +template +void ByteSwap::Swap(T &p) +{ +#ifdef GDCM_WORDS_BIGENDIAN + ByteSwap::SwapFromSwapCodeIntoSystem(p, SwapCode::LittleEndian); +#else + ByteSwap::SwapFromSwapCodeIntoSystem(p, SwapCode::BigEndian); +#endif +} + +// Swaps the bytes so they agree with the processor order +template +void ByteSwap::SwapFromSwapCodeIntoSystem(T &a, SwapCode const &swapcode) +{ + //std::cerr << "sizeof(T)= " << sizeof(T) << " " << (int)a << std::endl; + switch(sizeof(T)) + { + case 1: + break; + case 2: + Swap4(a, swapcode); + break; + case 4: + Swap8(a, swapcode); + break; + default: + std::cerr << "Impossible" << std::endl; + abort(); + } +} + +template +void ByteSwap::SwapRange(T *p, unsigned int num) +{ + for(unsigned int i=0; i::Swap(p[i]); + } +} + +template +void ByteSwap::SwapRangeFromSwapCodeIntoSystem(T *p, SwapCode const &sc, + std::streamoff num) +{ + for( std::streamoff i=0; i::SwapFromSwapCodeIntoSystem(p[i], sc); + } +} + +// Private: +// + +template +void Swap4(T &a, SwapCode const &swapcode) +{ +#ifndef GDCM_WORDS_BIGENDIAN + if ( swapcode == 4321 || swapcode == 2143 ) + a = (T)(( a << 8 ) | ( a >> 8 )); +#else + if ( swapcode == 1234 || swapcode == 3412 ) + a = ( a << 8 ) | ( a >> 8 ); + // On big endian as long as the SwapCode is Unknown let's pretend we were + // on a LittleEndian system (might introduce overhead on those system). + else if ( swapcode == SwapCode::Unknown ) + a = ( a << 8 ) | ( a >> 8 ); +#endif +} + +//note: according to http://www.parashift.com/c++-faq-lite/templates.html#faq-35.8 +//the inlining of the template class means that the specialization doesn't cause linker errors +template +inline void Swap8(T &a, SwapCode const &swapcode) +{ + switch (swapcode) + { + case SwapCode::Unknown: +#ifdef GDCM_WORDS_BIGENDIAN + a= (( a<<24) | ((a<<8) & 0x00ff0000) | ((a>>8) & 0x0000ff00) | (a>>24) ); +#endif + break; + case 1234 : +#ifdef GDCM_WORDS_BIGENDIAN + a= (( a<<24) | ((a<<8) & 0x00ff0000) | ((a>>8) & 0x0000ff00) | (a>>24) ); +#endif + break; + case 4321 : +#ifndef GDCM_WORDS_BIGENDIAN + a= (( a<<24) | ((a<<8) & 0x00ff0000) | ((a>>8) & 0x0000ff00) | (a>>24) ); +#endif + break; + case 3412 : + a= ((a<<16) | (a>>16) ); + break; + case 2143 : + a= (((a<< 8) & 0xff00ff00) | ((a>>8) & 0x00ff00ff) ); + break; + default : + std::cerr << "Unexpected swap code:" << swapcode; + } +} + +template <> +inline void Swap8(uint16_t &a, SwapCode const &swapcode) +{ + switch (swapcode) + { + case SwapCode::Unknown: +#ifdef GDCM_WORDS_BIGENDIAN + a= (( a<<24) | ((a<<8) & 0x00ff0000) | ((a>>8) & 0x0000ff00) | (a>>24) ); +#endif + break; + case 1234 : +#ifdef GDCM_WORDS_BIGENDIAN + a= (( a<<24) | ((a<<8) & 0x00ff0000) | ((a>>8) & 0x0000ff00) | (a>>24) ); +#endif + break; + case 4321 : +#ifndef GDCM_WORDS_BIGENDIAN +// probably not really useful since the lowest 0x0000 are what's used in unsigned shorts +// a= (( a<<24) | ((a<<8) & 0x00ff0000) | ((a>>8) & 0x0000ff00) | (a>>24) ); +#endif + break; + case 3412 : + //a= ((a<<16) | (a>>16) );//do nothing, a = a + break; + case 2143 : + a= (uint16_t)(((a<< 8) & 0xff00) | ((a>>8) & 0x00ff) ); + break; + default : + std::cerr << "Unexpected swap code:" << swapcode; + } +} + + +} // end namespace gdcm + +#endif // GDCMBYTESWAP_TXX diff --git a/gdcm/Source/Common/gdcmCAPICryptoFactory.cxx b/gdcm/Source/Common/gdcmCAPICryptoFactory.cxx new file mode 100644 index 0000000..c4ed610 --- /dev/null +++ b/gdcm/Source/Common/gdcmCAPICryptoFactory.cxx @@ -0,0 +1,36 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmCAPICryptoFactory.h" +#include "gdcmCAPICryptographicMessageSyntax.h" + +namespace gdcm +{ + +CAPICryptoFactory::CAPICryptoFactory(CryptoLib id) : CryptoFactory(id) +{ + gdcmDebugMacro( "CAPI Factory registered." << std::endl ); +} + +CryptographicMessageSyntax* CAPICryptoFactory::CreateCMSProvider() +{ + CAPICryptographicMessageSyntax* capicms = new CAPICryptographicMessageSyntax(); + if (!capicms->GetInitialized()) + { + delete capicms; + return NULL; + } + return capicms; +} + +} // end namespace gdcm diff --git a/gdcm/Source/Common/gdcmCAPICryptoFactory.h b/gdcm/Source/Common/gdcmCAPICryptoFactory.h new file mode 100644 index 0000000..602afd1 --- /dev/null +++ b/gdcm/Source/Common/gdcmCAPICryptoFactory.h @@ -0,0 +1,34 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMCAPICRYPTOFACTORY_H +#define GDCMCAPICRYPTOFACTORY_H + +#include "gdcmCryptoFactory.h" + +namespace gdcm +{ + +class GDCM_EXPORT CAPICryptoFactory : public CryptoFactory +{ +public: + CAPICryptoFactory(CryptoLib id); + CryptographicMessageSyntax* CreateCMSProvider(); + +private: + CAPICryptoFactory() {} +}; + +} // end namespace gdcm + +#endif //GDCMCAPICRYPTOFACTORY_H diff --git a/gdcm/Source/Common/gdcmCAPICryptographicMessageSyntax.cxx b/gdcm/Source/Common/gdcmCAPICryptographicMessageSyntax.cxx new file mode 100644 index 0000000..74c84d8 --- /dev/null +++ b/gdcm/Source/Common/gdcmCAPICryptographicMessageSyntax.cxx @@ -0,0 +1,511 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmCAPICryptographicMessageSyntax.h" + +#include // fseek + +namespace gdcm +{ + +CAPICryptographicMessageSyntax::CAPICryptographicMessageSyntax() : hProv(0), hRsaPrivK(0), cipherType(AES128_CIPHER) +{ + initialized = Initialize(); +} + +CAPICryptographicMessageSyntax::~CAPICryptographicMessageSyntax() +{ + for (std::vector::iterator it = certifList.begin(); it != certifList.end(); ++it) + { + CertFreeCertificateContext(*it); + /*if (! CertFreeCertificateContext(*it)) + { + gdcmWarningMacro( "Error at releasing certificate context: " << std::hex << GetLastError() ); + }*/ + } + + if (hRsaPrivK) CryptDestroyKey(hRsaPrivK); + + if (!CryptReleaseContext(hProv, 0)) + { + gdcmWarningMacro("Error when releasing context: 0x" << std::hex << GetLastError()); + } +} + +// http://stackoverflow.com/questions/11709500/capi-does-not-support-password-based-encryption-pbe-encryption +bool CAPICryptographicMessageSyntax::SetPassword(const char * , size_t ) +{ + gdcmWarningMacro( "CAPI does not support Password Based Encryption." ); + return false; +} + +bool CAPICryptographicMessageSyntax::ParseCertificateFile( const char *filename ) +{ + bool ret = false; + BYTE *certHexBuf = NULL, *certBin = NULL; + DWORD certHexBufLen, certBinLen; + + if ( !LoadFile(filename, certHexBuf, certHexBufLen) ) + goto err; + + // Call to get the needed amount of space + if ( !CryptStringToBinaryA( (LPCSTR)certHexBuf, 0, CRYPT_STRING_BASE64_ANY, NULL, &certBinLen, NULL, NULL ) ) + { + gdcmErrorMacro( "CryptStringToBinary failed with error 0x" << std::hex << GetLastError() ); + goto err; + } + certBin = new BYTE[certBinLen]; + // Convert from PEM format to DER format - removes header and footer and decodes from base64 + if ( !CryptStringToBinaryA( (LPCSTR)certHexBuf, 0, CRYPT_STRING_BASE64_ANY, certBin, &certBinLen, NULL, NULL ) ) + { + gdcmErrorMacro( "CryptStringToBinary failed with error 0x" << std::hex << GetLastError() ); + goto err; + } + + PCCERT_CONTEXT certContext; + certContext = CertCreateCertificateContext(X509_ASN_ENCODING, certBin, certBinLen); + if (certContext == NULL) + { + gdcmErrorMacro( "CertCreateCertificateContext failed with error 0x" << std::hex << GetLastError() ); + goto err; + } + certifList.push_back(certContext); + + ret = true; + +err: + if (certBin) delete[] certBin; + if (certHexBuf) delete[] certHexBuf; + + return ret; +} + +bool CAPICryptographicMessageSyntax::ParseKeyFile( const char *filename ) { + bool ret = false; + BYTE *keyHexBuffer = NULL, *keyBinBuffer = NULL, *keyBlob = NULL; + DWORD keyHexBufferLen, keyBinBufferLen, keyBlobLen; + HCRYPTKEY hKey = 0; + + if (!LoadFile(filename, keyHexBuffer, keyHexBufferLen)) + goto err; + + if ( !CryptStringToBinaryA((LPCSTR)keyHexBuffer, 0, CRYPT_STRING_BASE64_ANY, NULL, &keyBinBufferLen, NULL, NULL) ) + { + gdcmErrorMacro( "Failed to convert from BASE64. CryptStringToBinary failed with error 0x" << std::hex << GetLastError() ); + goto err; + } + keyBinBuffer = new BYTE[keyBinBufferLen]; + if ( !CryptStringToBinaryA((LPCSTR)keyHexBuffer, 0, CRYPT_STRING_BASE64_ANY, keyBinBuffer, &keyBinBufferLen, NULL, NULL) ) + { + gdcmErrorMacro( "Failed to convert from BASE64. CryptStringToBinary failed with error 0x" << std::hex << GetLastError() ); + goto err; + } + + if (!CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, PKCS_RSA_PRIVATE_KEY, keyBinBuffer, keyBinBufferLen, 0, NULL, NULL, &keyBlobLen)) + { + gdcmErrorMacro( "Failed to parse private key. CryptDecodeObjectEx failed with error 0x" << std::hex << GetLastError() ); + goto err; + } + keyBlob = new BYTE[keyBlobLen]; + if (!CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, PKCS_RSA_PRIVATE_KEY, keyBinBuffer, keyBinBufferLen, 0, NULL, keyBlob, &keyBlobLen)) + { + gdcmErrorMacro( "Failed to parse private key. CryptDecodeObjectEx failed with error 0x" << std::hex << GetLastError() ); + goto err; + } + + if (!CryptImportKey(hProv, keyBlob, keyBlobLen, 0, 0, &hKey)) + { + gdcmErrorMacro( "CryptImportKey failed with error 0x" << std::hex << GetLastError() ); + goto err; + } + if (hRsaPrivK) CryptDestroyKey(hRsaPrivK); + hRsaPrivK = hKey; + + ret = true; + +err: + if (keyHexBuffer) delete[] keyHexBuffer; + if (keyBinBuffer) delete[] keyBinBuffer; + if (keyBlob) delete[] keyBlob; + return ret; +} + +void CAPICryptographicMessageSyntax::SetCipherType(CryptographicMessageSyntax::CipherTypes type) +{ + cipherType = type; +} + +CryptographicMessageSyntax::CipherTypes CAPICryptographicMessageSyntax::GetCipherType() const +{ + return cipherType; +} + +bool CAPICryptographicMessageSyntax::Encrypt(char *output, size_t &outlen, const char *array, size_t len) const +{ + CRYPT_ALGORITHM_IDENTIFIER EncryptAlgorithm = {0}; + const char *objid = GetCipherObjId(); + if( !objid ) + { + gdcmErrorMacro( "Could not GetCipherObjId" ); + return false; + } + EncryptAlgorithm.pszObjId = (char*)objid; + + CRYPT_ENCRYPT_MESSAGE_PARA EncryptParams = {0}; + EncryptParams.cbSize = sizeof(EncryptParams); + EncryptParams.dwMsgEncodingType = PKCS_7_ASN_ENCODING | X509_ASN_ENCODING; + EncryptParams.hCryptProv = hProv; + EncryptParams.ContentEncryptionAlgorithm = EncryptAlgorithm; + + if (certifList.size() == 0) + { + gdcmErrorMacro("No recipients certificates loaded."); + return false; + } + + if(! CryptEncryptMessage(&EncryptParams, certifList.size(), (PCCERT_CONTEXT *)&certifList[0], (BYTE *)array, len, (BYTE *)output, (DWORD *)&outlen) ) + { + DWORD dwResult = GetLastError(); + gdcmErrorMacro( "Couldn't encrypt message. CryptEncryptMessage failed with error 0x" << std::hex << dwResult ); + if (dwResult == CRYPT_E_UNKNOWN_ALGO) + { + gdcmErrorMacro("Unknown encryption algorithm. If on Windows XP please use only 3DES."); + } + return false; + } + return true; +} + +bool CAPICryptographicMessageSyntax::Decrypt(char *output, size_t &outlen, const char *array, size_t len) const +{ + bool ret = false; + BYTE* cek = NULL; + HCRYPTMSG hMsg = NULL; + PCMSG_CMS_RECIPIENT_INFO recipientInfo = NULL; + PCRYPT_ALGORITHM_IDENTIFIER cekAlg = NULL; + BYTE* bareContent = NULL; + struct { + BLOBHEADER header; + DWORD cbKeySize; + BYTE rgbKeyData[32]; //the maximum is 256 bit for aes + } keyBlob = {{0}}; + + if (hRsaPrivK == 0) + { + gdcmErrorMacro("No private key loaded loaded."); + return false; + } + + if (! (hMsg = CryptMsgOpenToDecode(CRYPT_ASN_ENCODING | X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CMSG_ENVELOPED_DATA_PKCS_1_5_VERSION, 0, NULL, NULL)) ) + { + gdcmErrorMacro( "MsgOpenToDecode failed with error 0x" << std::hex << GetLastError() ); + goto err; + } + + if(! CryptMsgUpdate(hMsg, (BYTE*)array, len, TRUE)) + { + gdcmErrorMacro( "MsgUpdate failed with error 0x" << std::hex << GetLastError() ); + goto err; + } + + DWORD dwMessageType, cbMessageTypeLen; + if(! CryptMsgGetParam(hMsg, CMSG_TYPE_PARAM, 0, &dwMessageType, &cbMessageTypeLen)) + { + gdcmErrorMacro( "CryptMsgGetParam CMSG_TYPE_PARAM failed with error 0x" << std::hex << GetLastError() ); + goto err; + } + + if(dwMessageType != CMSG_ENVELOPED) + { + gdcmErrorMacro("Wrong message type ( != CMSG_ENVELOPED )"); + goto err; + } + + ALG_ID kekAlg; + DWORD kekAlgLen; + if(! CryptGetKeyParam(hRsaPrivK, KP_ALGID, (BYTE*)&kekAlg, &kekAlgLen, 0)) + { + gdcmErrorMacro( "MsgGetParam KP_ALGID failed with error 0x" << std::hex << GetLastError() ); + goto err; + } + if (kekAlg != CALG_RSA_KEYX) + { + gdcmErrorMacro( "Key encryption algorithm is not RSA." ); + goto err; + } + + DWORD nrOfRecipeints, nrOfRecipientsLen; + if(! CryptMsgGetParam(hMsg, CMSG_RECIPIENT_COUNT_PARAM, 0, &nrOfRecipeints, &nrOfRecipientsLen)) + { + gdcmErrorMacro( "Decode CMSG_RECIPIENT_COUNT_PARAM failed with error 0x" << std::hex << GetLastError() ); + goto err; + } + + DWORD cekLen; +{ + BOOL foundRecipient = FALSE; + for (DWORD i=0; i < nrOfRecipeints; i++) + { + if (recipientInfo) delete[] recipientInfo; + + DWORD cbRecipientInfoLen; + if(! CryptMsgGetParam(hMsg, CMSG_CMS_RECIPIENT_INFO_PARAM, i, NULL, &cbRecipientInfoLen)) + { + gdcmErrorMacro( "MsgGetParam CMSG_CMS_RECIPIENT_INFO_PARAM size failed with error 0x" << std::hex << GetLastError() ); + goto err; + } + recipientInfo = (PCMSG_CMS_RECIPIENT_INFO) new BYTE[cbRecipientInfoLen]; + if(! CryptMsgGetParam(hMsg, CMSG_CMS_RECIPIENT_INFO_PARAM, i, recipientInfo, &cbRecipientInfoLen)) + { + gdcmErrorMacro( "MsgGetParam CMSG_CMS_RECIPIENT_INFO_PARAM failed with error 0x" << std::hex << GetLastError() ); + goto err; + } + + DWORD rsaPadding = 0; + if (strcmp(recipientInfo->pKeyTrans->KeyEncryptionAlgorithm.pszObjId, szOID_RSAES_OAEP) == 0) + { + rsaPadding = CRYPT_OAEP; + } + + //cek - content encryption key + cekLen = recipientInfo->pKeyTrans->EncryptedKey.cbData; + cek = recipientInfo->pKeyTrans->EncryptedKey.pbData; + ReverseBytes(cek, cekLen); + + if ( (foundRecipient = + CryptDecrypt(hRsaPrivK, 0, TRUE, rsaPadding, cek, &cekLen)) ) + break; + } // end loop recipients + + if (!foundRecipient) + { + gdcmErrorMacro( "No recipient found with the specified private key." ); + goto err; + } +} + + DWORD cekAlgLen; + if(! CryptMsgGetParam(hMsg, CMSG_ENVELOPE_ALGORITHM_PARAM, 0, NULL, &cekAlgLen)) + { + gdcmErrorMacro( "MsgGetParam CMSG_ENVELOPE_ALGORITHM_PARAM failed with error 0x" << std::hex << GetLastError() ); + goto err; + } + cekAlg = (PCRYPT_ALGORITHM_IDENTIFIER) new BYTE[cekAlgLen]; + if(! CryptMsgGetParam(hMsg, CMSG_ENVELOPE_ALGORITHM_PARAM, 0, cekAlg, &cekAlgLen)) + { + gdcmErrorMacro( "MsgGetParam CMSG_ENVELOPE_ALGORITHM_PARAM failed with error 0x" << std::hex << GetLastError() ); + goto err; + } + + HCRYPTKEY hCEK; + keyBlob.header.bType = PLAINTEXTKEYBLOB; + keyBlob.header.bVersion = CUR_BLOB_VERSION; + keyBlob.header.reserved = 0; + keyBlob.header.aiKeyAlg = GetAlgIdByObjId(cekAlg->pszObjId); + keyBlob.cbKeySize = cekLen; + assert(cekLen <= 32); + memcpy(keyBlob.rgbKeyData, cek, cekLen); + + if (!CryptImportKey(hProv, (BYTE*)&keyBlob, sizeof(keyBlob), 0, 0, &hCEK)) + { + gdcmErrorMacro( "CryptImportKey failed with error 0x" << std::hex << GetLastError() ); + goto err; + } + + if(! CryptSetKeyParam(hCEK, KP_IV, (BYTE *) cekAlg->Parameters.pbData+2, 0)) //+2 for ASN header ??? + { + gdcmErrorMacro( "SetKeyParam KP_IV failed with error 0x" << std::hex << GetLastError() ); + goto err; + } + +{ + DWORD dwMode = CRYPT_MODE_CBC; + if(! CryptSetKeyParam(hCEK, KP_MODE, (BYTE*) &dwMode, 0)) + { + gdcmErrorMacro( "SetKeyParam KP_MODE failed with error 0x" << std::hex << GetLastError() ); + goto err; + } +} + + DWORD bareContentLen; + if(! CryptMsgGetParam(hMsg, CMSG_CONTENT_PARAM, 0, NULL, &bareContentLen)) + { + gdcmErrorMacro( "MsgGetParam CMSG_BARE_CONTENT_PARAM size failed with error 0x" << std::hex << GetLastError() ); + goto err; + } + bareContent = new BYTE[bareContentLen]; + if(! CryptMsgGetParam(hMsg, CMSG_CONTENT_PARAM, 0, bareContent, &bareContentLen)) + { + gdcmErrorMacro( "MsgGetParam CMSG_BARE_CONTENT_PARAM failed with error 0x" << std::hex << GetLastError() ); + goto err; + } + + if (! CryptDecrypt(hCEK, 0, TRUE, 0, bareContent, &bareContentLen)) + { + gdcmErrorMacro( "CryptDecrypt failed with error 0x" << std::hex << GetLastError() ); + goto err; + } + + if (bareContentLen > outlen) + { + gdcmErrorMacro( "Supplied output buffer too small: " << bareContentLen << " bytes needed." ); + goto err; + } + + memcpy(output, bareContent, bareContentLen); + outlen = bareContentLen; + + ret = true; +err: + if (hMsg) CryptMsgClose(hMsg); + if (recipientInfo) delete[] recipientInfo; + if (bareContent) delete[] bareContent; + if (cekAlg) delete[] cekAlg; + + return ret; +} + +ALG_ID CAPICryptographicMessageSyntax::GetAlgIdByObjId(const char * pszObjId) +{ + // HACK: fix compilation on mingw64: + // See: http://sourceforge.net/tracker/?func=detail&aid=3561209&group_id=202880&atid=983354 +#ifndef szOID_NIST_AES128_CBC +#define szOID_NIST_AES128_CBC "2.16.840.1.101.3.4.1.2" +#define szOID_NIST_AES192_CBC "2.16.840.1.101.3.4.1.22" +#define szOID_NIST_AES256_CBC "2.16.840.1.101.3.4.1.42" +#endif + + if (strcmp(pszObjId, szOID_NIST_AES128_CBC) == 0) + { + return CALG_AES_128; + } + else if (strcmp(pszObjId, szOID_NIST_AES192_CBC) == 0) + { + return CALG_AES_192; + } + else if (strcmp(pszObjId, szOID_NIST_AES256_CBC) == 0) + { + return CALG_AES_256; + } + else if (strcmp(pszObjId, szOID_RSA_DES_EDE3_CBC) == 0) + { + return CALG_3DES; + } + return 0; +} + +const char *CAPICryptographicMessageSyntax::GetCipherObjId() const +{ + switch( cipherType ) + { + case AES128_CIPHER: + return szOID_NIST_AES128_CBC; + case AES192_CIPHER: + return szOID_NIST_AES192_CBC; + case AES256_CIPHER: + return szOID_NIST_AES256_CBC; + case DES3_CIPHER: + return szOID_RSA_DES_EDE3_CBC; + } + return 0; +} + +bool CAPICryptographicMessageSyntax::Initialize() +{ + DWORD dwResult; + if (!CryptAcquireContextA(&hProv, NULL, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) //CRYPT_VERIFYCONTEXT aes decr in cryptmsgcontrol not working + { + dwResult = GetLastError(); + if (dwResult == NTE_BAD_KEYSET) + { + if (!CryptAcquireContextA(&hProv, NULL, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, CRYPT_NEWKEYSET | CRYPT_VERIFYCONTEXT)) + { + dwResult = GetLastError(); + gdcmErrorMacro( "CryptAcquireContext() failed:" << std::hex << dwResult); + return false; + } + } + else if (dwResult == NTE_KEYSET_NOT_DEF) + { + //Probably WinXP + gdcmWarningMacro( "Certificate based encryption is supported on Windows XP only using 3DES." ); + if (!CryptAcquireContextA(&hProv, NULL, MS_ENH_RSA_AES_PROV_A" (Prototype)" /*"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"*/, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) //CRYPT_VERIFYCONTEXT aes decr in cryptmsgcontrol not working + { + dwResult = GetLastError(); + if (dwResult == NTE_BAD_KEYSET) + { + if (!CryptAcquireContextA(&hProv, NULL, MS_ENH_RSA_AES_PROV_A" (Prototype)" /*"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"*/, PROV_RSA_AES, CRYPT_NEWKEYSET | CRYPT_VERIFYCONTEXT)) + { + dwResult = GetLastError(); + gdcmErrorMacro( "CryptAcquireContext() failed: " << std::hex << dwResult ); + return false; + } + } + else + { + dwResult = GetLastError(); + return false; + } + } + } + else + { + dwResult = GetLastError(); + return false; + } + } + return true; +} + +void CAPICryptographicMessageSyntax::ReverseBytes(BYTE* data, DWORD len) +{ + BYTE temp; + for (DWORD i = 0; i < len/2; i++) + { + temp = data[len-i-1]; + data[len-i-1] = data[i]; + data[i] = temp; + } +} + +bool CAPICryptographicMessageSyntax::LoadFile(const char * filename, BYTE* & buffer, DWORD & bufLen) +{ + assert( !buffer ); + FILE * f = fopen(filename, "rb"); + if (f == NULL) + { + gdcmErrorMacro("Couldn't open the file: " << filename); + return false; + } + fseek(f, 0L, SEEK_END); + long sz = ftell(f); + //fseek(f, 0L, SEEK_SET); + rewind(f); + /*if (bufLen < sz) + { + printf("Buffer too small to load the file: %d < %d\n", bufLen, sz); + return false; + } + */ + buffer = new BYTE[sz]; + bufLen = sz; + + while (sz) + { + sz -= fread(buffer + bufLen - sz, sizeof(BYTE), sz, f); + } + + return true; +} + +} // end namespace gdcm diff --git a/gdcm/Source/Common/gdcmCAPICryptographicMessageSyntax.h b/gdcm/Source/Common/gdcmCAPICryptographicMessageSyntax.h new file mode 100644 index 0000000..03c0848 --- /dev/null +++ b/gdcm/Source/Common/gdcmCAPICryptographicMessageSyntax.h @@ -0,0 +1,69 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMCAPICRYPTOGRAPHICMESSAGESYNTAX_H +#define GDCMCAPICRYPTOGRAPHICMESSAGESYNTAX_H + +#include "gdcmCryptographicMessageSyntax.h" +#include +#include +#include + +namespace gdcm +{ + +class GDCM_EXPORT CAPICryptographicMessageSyntax : public CryptographicMessageSyntax +{ +public: + CAPICryptographicMessageSyntax(); + ~CAPICryptographicMessageSyntax(); + + // X.509 + bool ParseCertificateFile( const char *filename ); + bool ParseKeyFile( const char *filename ); + + // PBE + bool SetPassword(const char * pass, size_t passLen); + + void SetCipherType(CipherTypes type); + + CipherTypes GetCipherType() const; + + /// create a CMS envelopedData structure + bool Encrypt(char *output, size_t &outlen, const char *array, size_t len) const; + /// decrypt content from a CMS envelopedData structure + bool Decrypt(char *output, size_t &outlen, const char *array, size_t len) const; + + bool GetInitialized() const + { + return initialized; + } + +private: + bool Initialize(); + static ALG_ID GetAlgIdByObjId(const char * pszObjId); + const char *GetCipherObjId() const; + static void ReverseBytes(BYTE* data, DWORD len); + static bool LoadFile(const char * filename, BYTE* & buffer, DWORD & bufLen); + +private: + bool initialized; + HCRYPTPROV hProv; + std::vector certifList; + HCRYPTKEY hRsaPrivK; + CipherTypes cipherType; +}; + +} // end namespace gdcm + +#endif //GDCMCAPICRYPTOGRAPHICMESSAGESYNTAX_H diff --git a/gdcm/Source/Common/gdcmCommand.cxx b/gdcm/Source/Common/gdcmCommand.cxx new file mode 100644 index 0000000..93fccb6 --- /dev/null +++ b/gdcm/Source/Common/gdcmCommand.cxx @@ -0,0 +1,28 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmCommand.h" + +namespace gdcm +{ + +Command::Command() +{ +} + +Command::~Command() +{ +} + + +} // end namespace gdcm diff --git a/gdcm/Source/Common/gdcmCommand.h b/gdcm/Source/Common/gdcmCommand.h new file mode 100644 index 0000000..2f7b638 --- /dev/null +++ b/gdcm/Source/Common/gdcmCommand.h @@ -0,0 +1,187 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMCOMMAND_H +#define GDCMCOMMAND_H + +#include "gdcmSubject.h" + +namespace gdcm +{ +class Event; + +/** + * \brief Command superclass for callback/observer methods + * \see Subject + */ +class GDCM_EXPORT Command : public Subject +{ +public : + /// Abstract method that defines the action to be taken by the command. + virtual void Execute(Subject *caller, const Event & event ) = 0; + + /** Abstract method that defines the action to be taken by the command. + * This variant is expected to be used when requests comes from a + * const Object + */ + virtual void Execute(const Subject *caller, const Event & event ) = 0; + +protected: + Command(); + ~Command(); + +private: + Command(const Command&); // Not implemented. + void operator=(const Command&); // Not implemented. +}; + +/** \class MemberCommand + * \brief Command subclass that calls a pointer to a member function + * + * MemberCommand calls a pointer to a member function with the same + * arguments as Execute on Command. + * + */ +template +class MemberCommand : public Command +{ +public: + /** pointer to a member function that takes a Subject* and the event */ + typedef void (T::*TMemberFunctionPointer)(Subject*, const Event &); + typedef void (T::*TConstMemberFunctionPointer)(const Subject*, + const Event &); + + /** Standard class typedefs. */ + typedef MemberCommand Self; + //typedef SmartPointer Pointer; + + /** Method for creation through the object factory. */ + static SmartPointer New() + { + return new MemberCommand; + } + + /** Run-time type information (and related methods). */ + //gdcmTypeMacro(MemberCommand,Command); + + /** Set the callback function along with the object that it will + * be invoked on. */ + void SetCallbackFunction(T* object, + TMemberFunctionPointer memberFunction) + { + m_This = object; + m_MemberFunction = memberFunction; + } + void SetCallbackFunction(T* object, + TConstMemberFunctionPointer memberFunction) + { + m_This = object; + m_ConstMemberFunction = memberFunction; + } + + /** Invoke the member function. */ + virtual void Execute(Subject *caller, const Event & event ) + { + if( m_MemberFunction ) + { + ((*m_This).*(m_MemberFunction))(caller, event); + } + } + + /** Invoke the member function with a const object. */ + virtual void Execute( const Subject *caller, const Event & event ) + { + if( m_ConstMemberFunction ) + { + ((*m_This).*(m_ConstMemberFunction))(caller, event); + } + } + +protected: + + T* m_This; + TMemberFunctionPointer m_MemberFunction; + TConstMemberFunctionPointer m_ConstMemberFunction; + MemberCommand():m_MemberFunction(0),m_ConstMemberFunction(0) {} + virtual ~MemberCommand(){} + +private: + MemberCommand(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented + +}; + +/** \class SimpleMemberCommand + * \brief Command subclass that calls a pointer to a member function + * + * SimpleMemberCommand calls a pointer to a member function with no + * arguments. + */ +template +class SimpleMemberCommand : public Command +{ +public: + /** A method callback. */ + typedef void (T::*TMemberFunctionPointer)(); + + /** Standard class typedefs. */ + typedef SimpleMemberCommand Self; + //typedef SmartPointer Pointer; + + /** Run-time type information (and related methods). */ + //gdcmTypeMacro(SimpleMemberCommand,Command); + + /** Method for creation through the object factory. */ + static SmartPointer New() + { + return new SimpleMemberCommand; + } + + /** Specify the callback function. */ + void SetCallbackFunction(T* object, + TMemberFunctionPointer memberFunction) + { + m_This = object; + m_MemberFunction = memberFunction; + } + + /** Invoke the callback function. */ + virtual void Execute(Subject *,const Event & ) + { + if( m_MemberFunction ) + { + ((*m_This).*(m_MemberFunction))(); + } + } + virtual void Execute(const Subject *,const Event & ) + { + if( m_MemberFunction ) + { + ((*m_This).*(m_MemberFunction))(); + } + } + +protected: + T* m_This; + TMemberFunctionPointer m_MemberFunction; + SimpleMemberCommand():m_MemberFunction(0) {} + virtual ~SimpleMemberCommand() {} + +private: + SimpleMemberCommand(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented +}; + +} // end namespace gdcm +//----------------------------------------------------------------------------- +#endif //GDCMCOMMAND_H diff --git a/gdcm/Source/Common/gdcmConfigure.h.in b/gdcm/Source/Common/gdcmConfigure.h.in new file mode 100644 index 0000000..63a30a1 --- /dev/null +++ b/gdcm/Source/Common/gdcmConfigure.h.in @@ -0,0 +1,167 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMCONFIGURE_H +#define GDCMCONFIGURE_H + +/* This header is configured by GDCM's build process. */ + +/*--------------------------------------------------------------------------*/ +/* Platform Features */ + +/* Byte order. */ +/* All compilers that support Mac OS X define either __BIG_ENDIAN__ or + __LITTLE_ENDIAN__ to match the endianness of the architecture being + compiled for. This is not necessarily the same as the architecture of the + machine doing the building. In order to support Universal Binaries on + Mac OS X, we prefer those defines to decide the endianness. + Elsewhere use the platform check result. */ +#if !defined(__APPLE__) + #cmakedefine GDCM_WORDS_BIGENDIAN +#elif defined(__BIG_ENDIAN__) +# define GDCM_WORDS_BIGENDIAN +#endif + +/* Allow access to UINT32_MAX , cf gdcmCommon.h */ +#define __STDC_LIMIT_MACROS + +/* Hard code the path to the public dictionary */ +#define PUB_DICT_PATH "@GDCM_PUB_DICT_PATH@" + +/* Usefull in particular for loadshared where the full path + * to the lib is needed */ +#define GDCM_SOURCE_DIR "@GDCM_SOURCE_DIR@" +#define GDCM_EXECUTABLE_OUTPUT_PATH "@EXECUTABLE_OUTPUT_PATH@" +#define GDCM_LIBRARY_OUTPUT_PATH "@LIBRARY_OUTPUT_PATH@" + +#cmakedefine GDCM_BUILD_TESTING + +#cmakedefine GDCM_USE_SYSTEM_ZLIB +#cmakedefine GDCM_USE_SYSTEM_UUID +#cmakedefine GDCM_USE_SYSTEM_POPPLER +#cmakedefine GDCM_USE_SYSTEM_LIBXML2 +#cmakedefine GDCM_USE_SYSTEM_OPENSSL +#cmakedefine GDCM_USE_SYSTEM_MD5 +#cmakedefine GDCM_USE_SYSTEM_EXPAT +#cmakedefine GDCM_USE_SYSTEM_JSON +#cmakedefine GDCM_USE_SYSTEM_LJPEG +#cmakedefine GDCM_USE_SYSTEM_OPENJPEG +#cmakedefine GDCM_USE_OPENJPEG_V2 +#cmakedefine GDCM_USE_SYSTEM_CHARLS +#cmakedefine GDCM_USE_SYSTEM_KAKADU +#cmakedefine GDCM_USE_SYSTEM_PVRG +#cmakedefine GDCMV2_0_COMPATIBILITY +#cmakedefine GDCM_USE_SYSTEM_PAPYRUS3 + +#ifndef GDCM_USE_SYSTEM_OPENJPEG +#ifdef GDCM_USE_OPENJPEG_V2 +#define OPENJPEG_MAJOR_VERSION 2 +#else // GDCM_USE_OPENJPEG_V2 +#define OPENJPEG_MAJOR_VERSION 1 +#endif // GDCM_USE_OPENJPEG_V2 +#else +#define OPENJPEG_MAJOR_VERSION @OPENJPEG_MAJOR_VERSION@ +#endif //GDCM_USE_SYSTEM_OPENJPEG + +#ifndef OPENJPEG_MAJOR_VERSION +#error problem with openjpeg major version +#endif // OPENJPEG_MAJOR_VERSION + +#cmakedefine GDCM_USE_PVRG +#cmakedefine GDCM_USE_KAKADU +#cmakedefine GDCM_USE_JPEGLS + +#cmakedefine GDCM_AUTOLOAD_GDCMJNI + +/* I guess something important */ +#cmakedefine GDCM_HAVE_STDINT_H +#cmakedefine GDCM_HAVE_INTTYPES_H + +/* This variable allows you to have helpful debug statement */ +/* That are in between #ifdef / endif in the gdcm code */ +/* That means if GDCM_DEBUG is OFF there shouldn't be any 'cout' at all ! */ +/* only cerr, for instance 'invalid file' will be allowed */ +#cmakedefine GDCM_DEBUG + +#define GDCM_CMAKE_INSTALL_PREFIX "@CMAKE_INSTALL_PREFIX@" +#define GDCM_INSTALL_INCLUDE_DIR "@GDCM_INSTALL_INCLUDE_DIR@" +#define GDCM_INSTALL_DATA_DIR "@GDCM_INSTALL_DATA_DIR@" + +/* Whether we are building shared libraries. */ +#cmakedefine GDCM_BUILD_SHARED_LIBS + +/* GDCM uses __FUNCTION__ which is not ANSI C, but C99 */ +#cmakedefine GDCM_CXX_HAS_FUNCTION + +/* Special time structure support */ +#cmakedefine GDCM_HAVE_SYS_TIME_H +#cmakedefine GDCM_HAVE_WINSOCK_H +#cmakedefine GDCM_HAVE_BYTESWAP_H +#cmakedefine GDCM_HAVE_RPC_H +// CMS with PBE (added in OpenSSL 1.0.0 ~ Fri Nov 27 15:33:25 CET 2009) +#cmakedefine GDCM_HAVE_CMS_RECIPIENT_PASSWORD +#cmakedefine GDCM_HAVE_LANGINFO_H +#cmakedefine GDCM_HAVE_NL_LANGINFO + +#cmakedefine GDCM_HAVE_STRCASECMP +#cmakedefine GDCM_HAVE_STRNCASECMP +#cmakedefine GDCM_HAVE_SNPRINTF +#cmakedefine GDCM_HAVE_STRPTIME +#cmakedefine GDCM_HAVE__STRICMP +#cmakedefine GDCM_HAVE__STRNICMP +#cmakedefine GDCM_HAVE__SNPRINTF +#cmakedefine GDCM_HAVE_GETTIMEOFDAY + +// MM: I have a feeling that if GDCM_HAVE_WCHAR_IFSTREAM, then UNICODE filename +// are expected to be specified as UTF-16, but if no API exist for UTF-16 +// at std::ifstream level, then const char* of std::ifstream might accept +// UTF-8 +#cmakedefine GDCM_HAVE_WCHAR_IFSTREAM + +#cmakedefine GDCM_FORCE_BIGENDIAN_EMULATION + +/* To Remove code that support broken DICOM implementation and therefore + * add some over head. Turn Off at your own risk + */ +#cmakedefine GDCM_SUPPORT_BROKEN_IMPLEMENTATION + +#define GDCM_PVRG_JPEG_EXECUTABLE "@PVRGJPEG_EXECUTABLE@" +#define GDCM_KAKADU_EXPAND_EXECUTABLE "@KDU_EXPAND_EXECUTABLE@" + +/*--------------------------------------------------------------------------*/ +/* GDCM Versioning */ + +/* Version number. */ +#define GDCM_MAJOR_VERSION @GDCM_MAJOR_VERSION@ +#define GDCM_MINOR_VERSION @GDCM_MINOR_VERSION@ +#define GDCM_BUILD_VERSION @GDCM_BUILD_VERSION@ +#define GDCM_VERSION "@GDCM_VERSION@" +#define GDCM_API_VERSION "@GDCM_API_VERSION@" + +/* +#define GDCM_FILE_META_INFORMATION_VERSION "\0\1" +// echo "gdcm" | od -b +#define GDCM_IMPLEMENTATION_CLASS_UID "107.104.103.115"; +#define GDCM_IMPLEMENTATION_VERSION_NAME "GDCM " GDCM_VERSION +#define GDCM_SOURCE_APPLICATION_ENTITY_TITLE "GDCM" +*/ + + +/*--------------------------------------------------------------------------*/ +/* GDCM deprecation mechanism */ +#cmakedefine GDCM_LEGACY_REMOVE +#cmakedefine GDCM_LEGACY_SILENT + +#cmakedefine GDCM_ALWAYS_TRACE_MACRO + +#endif diff --git a/gdcm/Source/Common/gdcmCryptoFactory.cxx b/gdcm/Source/Common/gdcmCryptoFactory.cxx new file mode 100644 index 0000000..3ebfa0d --- /dev/null +++ b/gdcm/Source/Common/gdcmCryptoFactory.cxx @@ -0,0 +1,68 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmCryptoFactory.h" + +#ifdef WIN32 +#include "gdcmCAPICryptoFactory.h" +#endif + +#ifdef GDCM_USE_SYSTEM_OPENSSL +#ifdef GDCM_HAVE_CMS_RECIPIENT_PASSWORD +#include "gdcmOpenSSLCryptoFactory.h" +#endif +#include "gdcmOpenSSLP7CryptoFactory.h" +#endif + +namespace gdcm +{ + +CryptoFactory* CryptoFactory::GetFactoryInstance(CryptoLib id) +{ +#ifdef WIN32 + static CAPICryptoFactory capi(CryptoFactory::CAPI); +#endif +#ifdef GDCM_USE_SYSTEM_OPENSSL +#ifdef GDCM_HAVE_CMS_RECIPIENT_PASSWORD + static OpenSSLCryptoFactory ossl(CryptoFactory::OPENSSL); +#endif + static OpenSSLP7CryptoFactory osslp7(CryptoFactory::OPENSSLP7); +#endif + + // If user specified DEFAULT: + if( id == DEFAULT ) + { +#ifdef GDCM_USE_SYSTEM_OPENSSL +#ifdef GDCM_HAVE_CMS_RECIPIENT_PASSWORD + id = CryptoFactory::OPENSSL; +#else + id = CryptoFactory::OPENSSLP7; +#endif // GDCM_HAVE_CMS_RECIPIENT_PASSWORD +#endif // GDCM_USE_SYSTEM_OPENSSL +// We always prefer native API (by default): +#ifdef WIN32 + id = CryptoFactory::CAPI; +#endif // WIN32 + } + + std::map::iterator it = getInstanceMap().find(id); + if (it == getInstanceMap().end()) + { + gdcmErrorMacro( "No crypto factory registered with id " << (int)id ); + return NULL; + } + assert(it->second); + return it->second; +} + +} // end native gdcm diff --git a/gdcm/Source/Common/gdcmCryptoFactory.h b/gdcm/Source/Common/gdcmCryptoFactory.h new file mode 100644 index 0000000..5538f30 --- /dev/null +++ b/gdcm/Source/Common/gdcmCryptoFactory.h @@ -0,0 +1,71 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMCRYPTOFACTORY_H +#define GDCMCRYPTOFACTORY_H + +#include "gdcmCryptographicMessageSyntax.h" +#include + +namespace gdcm +{ + +/** + * \brief Class to do handle the crypto factory + * \details GDCM needs to access in a platform independant way + * the user specified crypto engine. It can be: + * \li CAPI (windows only) + * \li OPENSSL (portable) + * \li OPENSSLP7 (portable) + * By default the factory will try: + * CAPI if on windows + * OPENSSL if possible + * OPENSSLP7 when older OpenSSL is used. + */ +class GDCM_EXPORT CryptoFactory +{ +public: + enum CryptoLib {DEFAULT = 0, OPENSSL = 1, CAPI = 2, OPENSSLP7 = 3}; + + virtual CryptographicMessageSyntax* CreateCMSProvider() = 0; + static CryptoFactory* GetFactoryInstance(CryptoLib id = DEFAULT); + +protected: + CryptoFactory(CryptoLib id) + { + AddLib(id, this); + } + +private: + static std::map& getInstanceMap() + { + static std::map libs; + return libs; + } + + static void AddLib(CryptoLib id, CryptoFactory* f) + { + if (getInstanceMap().insert(std::pair(id, f)).second == false) + { + gdcmErrorMacro( "Library already registered under id " << (int)id ); + } + } + +protected: + CryptoFactory(){} + ~CryptoFactory(){} +}; + +} // end namespace gdcm + +#endif // GDCMCRYPTOFACTORY_H diff --git a/gdcm/Source/Common/gdcmCryptographicMessageSyntax.cxx b/gdcm/Source/Common/gdcmCryptographicMessageSyntax.cxx new file mode 100644 index 0000000..4942dbc --- /dev/null +++ b/gdcm/Source/Common/gdcmCryptographicMessageSyntax.cxx @@ -0,0 +1,14 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmCryptographicMessageSyntax.h" diff --git a/gdcm/Source/Common/gdcmCryptographicMessageSyntax.h b/gdcm/Source/Common/gdcmCryptographicMessageSyntax.h new file mode 100644 index 0000000..0a45c70 --- /dev/null +++ b/gdcm/Source/Common/gdcmCryptographicMessageSyntax.h @@ -0,0 +1,59 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMCRYPTOGRAPHICMESSAGESYNTAX_H +#define GDCMCRYPTOGRAPHICMESSAGESYNTAX_H + +#include "gdcmTypes.h" + +namespace gdcm +{ + +class GDCM_EXPORT CryptographicMessageSyntax +{ +public: + CryptographicMessageSyntax() {} + + virtual ~CryptographicMessageSyntax() {} + + typedef enum { + DES3_CIPHER, // Triple DES + AES128_CIPHER, // CBC AES + AES192_CIPHER, // ' ' + AES256_CIPHER // ' ' + } CipherTypes; + + // X.509 + virtual bool ParseCertificateFile( const char *filename ) = 0; + virtual bool ParseKeyFile( const char *filename ) = 0; + + // PBE + virtual bool SetPassword(const char * pass, size_t passLen) = 0; + + /// create a CMS envelopedData structure + virtual bool Encrypt(char *output, size_t &outlen, const char *array, size_t len) const = 0; + /// decrypt content from a CMS envelopedData structure + virtual bool Decrypt(char *output, size_t &outlen, const char *array, size_t len) const = 0; + + virtual void SetCipherType(CipherTypes type) = 0; + + virtual CipherTypes GetCipherType() const = 0; + +private: + CryptographicMessageSyntax(const CryptographicMessageSyntax&); // Not implemented. + void operator=(const CryptographicMessageSyntax&); // Not implemented. +}; + +} // end namespace gdcm + +#endif //GDCMCRYPTOGRAPHICMESSAGESYNTAX_H diff --git a/gdcm/Source/Common/gdcmDataEvent.cxx b/gdcm/Source/Common/gdcmDataEvent.cxx new file mode 100644 index 0000000..7281a11 --- /dev/null +++ b/gdcm/Source/Common/gdcmDataEvent.cxx @@ -0,0 +1,18 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmDataEvent.h" + +namespace gdcm +{ +} // end namespace gdcm diff --git a/gdcm/Source/Common/gdcmDataEvent.h b/gdcm/Source/Common/gdcmDataEvent.h new file mode 100644 index 0000000..7beb20e --- /dev/null +++ b/gdcm/Source/Common/gdcmDataEvent.h @@ -0,0 +1,57 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMDATAEVENT_H +#define GDCMDATAEVENT_H + +#include "gdcmEvent.h" + +namespace gdcm +{ + +/** + * \brief DataEvent + */ +class DataEvent : public AnyEvent +{ +public: + typedef DataEvent Self; + typedef AnyEvent Superclass; + DataEvent(const char *bytes = 0, size_t len = 0):Bytes(bytes),Length(len) {} + virtual ~DataEvent() {} + virtual const char * GetEventName() const { return "DataEvent"; } + virtual bool CheckEvent(const ::gdcm::Event* e) const + { return (dynamic_cast(e) == NULL ? false : true) ; } + virtual ::gdcm::Event* MakeObject() const + { return new Self; } + DataEvent(const Self&s) : AnyEvent(s){}; + + void SetData(const char *bytes, size_t len) { + Bytes = bytes; + Length = len; + } + size_t GetDataLength() const { return Length; } + const char *GetData() const { return Bytes; } + + //std::string GetValueAsString() const { return; } + +private: + void operator=(const Self&); + const char *Bytes; + size_t Length; +}; + + +} // end namespace gdcm + +#endif //GDCMDATAEVENT_H diff --git a/gdcm/Source/Common/gdcmDeflateStream.cxx b/gdcm/Source/Common/gdcmDeflateStream.cxx new file mode 100644 index 0000000..0a4dc72 --- /dev/null +++ b/gdcm/Source/Common/gdcmDeflateStream.cxx @@ -0,0 +1,18 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmDeflateStream.h" + +namespace gdcm +{ +} diff --git a/gdcm/Source/Common/gdcmDeflateStream.h b/gdcm/Source/Common/gdcmDeflateStream.h new file mode 100644 index 0000000..a9b9717 --- /dev/null +++ b/gdcm/Source/Common/gdcmDeflateStream.h @@ -0,0 +1,19 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMDEFLATESTREAM_H +#define GDCMDEFLATESTREAM_H + +#include "zipstreamimpl.h" + +#endif //GDCMDEFLATESTREAM_H diff --git a/gdcm/Source/Common/gdcmDirectory.cxx b/gdcm/Source/Common/gdcmDirectory.cxx new file mode 100644 index 0000000..30d2a18 --- /dev/null +++ b/gdcm/Source/Common/gdcmDirectory.cxx @@ -0,0 +1,164 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmDirectory.h" +#include "gdcmTrace.h" + +#include +#include +#include +#include //stat function +#include // strerror + +#ifdef _MSC_VER + #include + #include +#else + #include + #include +#endif + +namespace gdcm +{ + +unsigned int Directory::Explore(FilenameType const &name, bool recursive) +{ + unsigned int nFiles = 0; + std::string fileName; + std::string dirName = name; + //assert( System::FileIsDirectory( dirName ) ); + Directories.push_back( dirName ); +#ifdef _MSC_VER + WIN32_FIND_DATA fileData; + dirName.append("/"); + assert( dirName[dirName.size()-1] == '/' ); + const FilenameType firstfile = dirName+"*"; + HANDLE hFile = FindFirstFile(firstfile.c_str(), &fileData); + + for(BOOL b = (hFile != INVALID_HANDLE_VALUE); b; + b = FindNextFile(hFile, &fileData)) + { + fileName = fileData.cFileName; + if ( fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) + { + // Need to check for . and .. to avoid infinite loop + if ( fileName != "." && fileName != ".." + && fileName[0] != '.' // discard any hidden dir + && recursive ) + { + nFiles += Explore(dirName+fileName,recursive); + } + } + else + { + Filenames.push_back(dirName+fileName); + nFiles++; + } + } + DWORD dwError = GetLastError(); + if (hFile != INVALID_HANDLE_VALUE) FindClose(hFile); + if (dwError != ERROR_NO_MORE_FILES) + { + //gdcmErrorMacro("FindNextFile error. Error is " << dwError); + return 0; + } + +#else + // Real POSIX implementation: scandir is a BSD extension only, and doesn't + // work on debian for example + + DIR* dir = opendir(dirName.c_str()); + if (!dir) + { + const char *str = strerror(errno); (void)str; + gdcmErrorMacro( "Error was: " << str << " when opening directory: " << dirName ); + return 0; + } + + // According to POSIX, the dirent structure contains a field char d_name[] + // of unspecified size, with at most NAME_MAX characters preceeding the + // terminating null character. Use of other fields will harm the porta- + // bility of your programs. + + struct stat buf; + dirent *d; + dirName.append("/"); + assert( dirName[dirName.size()-1] == '/' ); + for (d = readdir(dir); d; d = readdir(dir)) + { + fileName = dirName + d->d_name; + if( stat(fileName.c_str(), &buf) != 0 ) + { + const char *str = strerror(errno); (void)str; + gdcmErrorMacro( "Last Error was: " << str << " for file: " << fileName ); + break; + } + if ( S_ISREG(buf.st_mode) ) //is it a regular file? + { + if( d->d_name[0] != '.' ) + { + Filenames.push_back( fileName ); + nFiles++; + } + } + else if ( S_ISDIR(buf.st_mode) ) //directory? + { + // discard . and .. + if( strcmp( d->d_name, "." ) == 0 + || strcmp( d->d_name, ".." ) == 0 + || d->d_name[0] == '.' ) // discard any hidden dir + continue; + assert( d->d_name[0] != '.' ); // hidden directory ?? + if ( recursive ) + { + nFiles += Explore( fileName, recursive); + } + } + else + { + gdcmErrorMacro( "Unexpected type for file: " << fileName ); + break; + } + } + if( closedir(dir) != 0 ) + { + const char *str = strerror(errno); (void)str; + gdcmErrorMacro( "Last error was: " << str << " when closing directory: " << fileName ); + } +#endif + + return nFiles; +} + +void Directory::Print(std::ostream &_os) const +{ + // FIXME Both structures are FilenamesType I could factorize the code + _os << "Directories: "; + if( Directories.empty() ) + _os << "(None)" << std::endl; + else + { + std::copy(Directories.begin(), Directories.end(), + std::ostream_iterator(_os << std::endl, "\n")); + } + _os << "Filenames: "; + if( Filenames.empty() ) + _os << "(None)" << std::endl; + else + { + std::copy(Filenames.begin(), Filenames.end(), + std::ostream_iterator(_os << std::endl, "\n")); + } +} + +} // end namespace gdcm diff --git a/gdcm/Source/Common/gdcmDirectory.h b/gdcm/Source/Common/gdcmDirectory.h new file mode 100644 index 0000000..bf84bf2 --- /dev/null +++ b/gdcm/Source/Common/gdcmDirectory.h @@ -0,0 +1,100 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMDIRECTORY_H +#define GDCMDIRECTORY_H + +#include "gdcmTypes.h" + +#include +#include +#include +#include + +namespace gdcm +{ +/** + * \brief Class for manipulation directories + * + * \note This implementation provide a cross platform implementation + * for manipulating directores: basically traversing directories + * and harvesting files + * + * \note + * will not take into account unix type hidden file + * recursive option will not look into UNIX type hidden directory (those starting with a '.') + * + * \note + * Since python or C# provide there own equivalent implementation, + * in which case gdcm::Directory does not make much sense. + */ +//----------------------------------------------------------------------------- +class GDCM_EXPORT Directory +{ + friend std::ostream& operator<<(std::ostream &_os, const Directory &d); +public : + Directory() {} + ~Directory() {} + typedef std::string FilenameType; + typedef std::vector FilenamesType; + + /// Print + void Print(std::ostream &os = std::cout) const; + + /// Get the name of the toplevel directory + FilenameType const &GetToplevel() const { return Toplevel; } + + /// Set/Get the file names within the directory + FilenamesType const &GetFilenames() const { + assert( !(Toplevel.empty()) && "Need to call Explore first" ); + return Filenames; } + + /// Return the Directories traversed + FilenamesType const &GetDirectories() const { return Directories; } + + /// construct a list of filenames and subdirectory beneath directory: name + /// \warning: hidden file and hidden directory are not loaded. + unsigned int Load(FilenameType const &name, bool recursive = false) { + Filenames.clear(); // clear previous + Directories.clear(); // clear previous + Toplevel = name; + return Explore( Toplevel, recursive ); + } + // \todo later: GLOB + // The glob() function searches for all the pathnames matching pattern according to + // the rules used by the shell (see glob(7)). No tilde expansion or parameter + // substitution is done; if you want these, use wordexp(3). + // int Glob(...); + +protected: + /// Return number of file found when 'recursive'ly exploring directory `name` + unsigned int Explore(FilenameType const &name, bool recursive); + +private : + /// List of file names + FilenamesType Filenames; + FilenamesType Directories; + + /// name of the toplevel directory to explore + FilenameType Toplevel; +}; +//----------------------------------------------------------------------------- +inline std::ostream& operator<<(std::ostream &os, const Directory &d) +{ + d.Print( os ); + return os; +} + +} // end namespace gdcm +//----------------------------------------------------------------------------- +#endif //GDCMDIRECTORY_H diff --git a/gdcm/Source/Common/gdcmDummyValueGenerator.cxx b/gdcm/Source/Common/gdcmDummyValueGenerator.cxx new file mode 100644 index 0000000..e7867ce --- /dev/null +++ b/gdcm/Source/Common/gdcmDummyValueGenerator.cxx @@ -0,0 +1,42 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmDummyValueGenerator.h" +#include "gdcmTrace.h" +#include "gdcmSystem.h" +#include "gdcmSHA1.h" +#include "gdcmMD5.h" + +#include // strlen + +namespace gdcm +{ + +const char* DummyValueGenerator::Generate(const char *input) +{ + static char digest[2*20+1] = {}; + bool b = false; + if( input ) + { + // Cannot use MD5 as it has been broken multiple time (2005) + b = MD5::Compute(input, strlen(input), digest); + //b = SHA1::Compute(input, strlen(input), digest); + } + + if( b ) + return digest; + return 0; +} + + +} // end namespace gdcm diff --git a/gdcm/Source/Common/gdcmDummyValueGenerator.h b/gdcm/Source/Common/gdcmDummyValueGenerator.h new file mode 100644 index 0000000..27a30e4 --- /dev/null +++ b/gdcm/Source/Common/gdcmDummyValueGenerator.h @@ -0,0 +1,43 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMDUMMYVALUEGENERATOR_H +#define GDCMDUMMYVALUEGENERATOR_H + +#include "gdcmTypes.h" + +namespace gdcm +{ + +/** + * \brief Class for generating dummy value + * \see Anonymizer + */ +class GDCM_EXPORT DummyValueGenerator +{ +public: + + /** Generate a dummy value from an input value. This is guarantee to always + * return the same output value when input is identical. Return an array of + * bytes that can be used for anonymization purpose, return NULL on error + * NOT THREAD SAFE + */ + static const char* Generate(const char *input); + +private: +}; + + +} // end namespace gdcm + +#endif //GDCMDUMMYVALUEGENERATOR_H diff --git a/gdcm/Source/Common/gdcmEvent.cxx b/gdcm/Source/Common/gdcmEvent.cxx new file mode 100644 index 0000000..e81f5f4 --- /dev/null +++ b/gdcm/Source/Common/gdcmEvent.cxx @@ -0,0 +1,36 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmEvent.h" + +namespace gdcm +{ + +Event::Event() +{ +} + +Event::Event(const Event&) +{ +} + +Event::~Event() +{ +} + +void Event::Print(std::ostream& os) const +{ + os << GetEventName(); +} + +} // end namespace gdcm diff --git a/gdcm/Source/Common/gdcmEvent.h b/gdcm/Source/Common/gdcmEvent.h new file mode 100644 index 0000000..935a357 --- /dev/null +++ b/gdcm/Source/Common/gdcmEvent.h @@ -0,0 +1,100 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMEVENT_H +#define GDCMEVENT_H + +#include "gdcmTypes.h" + +namespace gdcm +{ +//----------------------------------------------------------------------------- +/** + * \brief superclass for callback/observer methods + * \see Command Subject + */ +class GDCM_EXPORT Event +{ +public : + Event(); + Event(const Event&); + virtual ~Event(); + + /** Create an Event of this type This method work as a Factory for + * creating events of each particular type. */ + virtual Event* MakeObject() const = 0; + + /** Print Event information. This method can be overridden by + * specific Event subtypes. The default is to print out the type of + * the event. */ + virtual void Print(std::ostream& os) const; + + /** Return the StringName associated with the event. */ + virtual const char * GetEventName(void) const = 0; + + /** Check if given event matches or derives from this event. */ + virtual bool CheckEvent(const Event*) const = 0; + +protected: +private: + void operator=(const Event&); // Not implemented. +}; + +/// Generic inserter operator for Event and its subclasses. +inline std::ostream& operator<<(std::ostream& os, Event &e) +{ + e.Print(os); + return os; +} + +/* + * Macro for creating new Events + */ +#define gdcmEventMacro( classname , super ) \ + /** \brief classname */ \ + class classname : public super { \ + public: \ + typedef classname Self; \ + typedef super Superclass; \ + classname() {} \ + virtual ~classname() {} \ + virtual const char * GetEventName() const { return #classname; } \ + virtual bool CheckEvent(const ::gdcm::Event* e) const \ + { return dynamic_cast(e) ? true : false; } \ + virtual ::gdcm::Event* MakeObject() const \ + { return new Self; } \ + classname(const Self&s) : super(s){}; \ + private: \ + void operator=(const Self&); \ + } + +/** + * Define some common GDCM events + */ +gdcmEventMacro( NoEvent , Event ); +gdcmEventMacro( AnyEvent , Event ); +gdcmEventMacro( StartEvent , AnyEvent ); +gdcmEventMacro( EndEvent , AnyEvent ); +//gdcmEventMacro( ProgressEvent , AnyEvent ); +gdcmEventMacro( ExitEvent , AnyEvent ); +gdcmEventMacro( AbortEvent , AnyEvent ); +gdcmEventMacro( ModifiedEvent , AnyEvent ); +gdcmEventMacro( InitializeEvent , AnyEvent ); +gdcmEventMacro( IterationEvent , AnyEvent ); +//gdcmEventMacro( AnonymizeEvent , AnyEvent ); +gdcmEventMacro( UserEvent , AnyEvent ); + + +} // end namespace gdcm +//----------------------------------------------------------------------------- +#endif //GDCMEVENT_H diff --git a/gdcm/Source/Common/gdcmException.cxx b/gdcm/Source/Common/gdcmException.cxx new file mode 100644 index 0000000..d8c416a --- /dev/null +++ b/gdcm/Source/Common/gdcmException.cxx @@ -0,0 +1,19 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmException.h" + +namespace gdcm +{ + +} // end namespace gdcm diff --git a/gdcm/Source/Common/gdcmException.h b/gdcm/Source/Common/gdcmException.h new file mode 100644 index 0000000..8a31a3d --- /dev/null +++ b/gdcm/Source/Common/gdcmException.h @@ -0,0 +1,108 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMEXCEPTION_H +#define GDCMEXCEPTION_H + +#include +#include // NULL +#include +#include // ostringstream +#include // logic_error +#include + +// Disable clang warning "dynamic exception specifications are deprecated". +// We need to be C++03 and C++11 compatible, and if we remove the 'throw()' +// specifier we'll get an error in C++03 by not matching the superclass. +#if defined(__clang__) && defined(__has_warning) +# if __has_warning("-Wdeprecated") +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wdeprecated" +# endif +#endif + +namespace gdcm +{ + +/** + * \brief Exception + * \details Standard exception handling object. + * \note Its copy-constructor and assignment operator are generated by the + * compiler. + */ +class Exception : public std::exception +{ + /// std::logic_error is used to internally hold a string. + /// It has the nice property of having a copy-constructor + /// that never fails. Thereby it provides the same guarantee to + /// the copy-constructor of gdcm::Exception. + typedef std::logic_error StringHolder; + + /// Creates the text to be returned by Exception:what(). + static StringHolder CreateWhat(const char* const desc, + const char* const file, + const unsigned int lineNumber, + const char* const func) + { + assert(desc != NULL); + assert(file != NULL); + assert(func != NULL); + std::ostringstream oswhat; + oswhat << file << ":" << lineNumber << " (" << func << "):\n"; + oswhat << desc; + return StringHolder( oswhat.str() ); + } + +public: + /// Explicit constructor, initializing the description and the + /// text returned by what(). + /// \note The last parameter is ignored for the time being. + /// It may be used to specify the function where the exception + /// was thrown. + explicit Exception(const char *desc = "None", + const char *file = __FILE__, + unsigned int lineNumber = __LINE__, + // FIXME: __PRETTY_FUNCTION__ is the non-mangled version for __GNUC__ compiler + const char *func = "" /*__FUNCTION__*/) + : + What( CreateWhat(desc, file, lineNumber, func) ), + Description(desc) + { + } + + virtual ~Exception() throw() {} + + /// what implementation + const char* what() const throw() + { + return What.what(); + } + + /// Return the Description + const char * GetDescription() const { return Description.what(); } + +private: + StringHolder What; + StringHolder Description; +}; + +} // end namespace gdcm + +// Undo warning suppression. +#if defined(__clang__) && defined(__has_warning) +# if __has_warning("-Wdeprecated") +# pragma clang diagnostic pop +# endif +#endif + +#endif diff --git a/gdcm/Source/Common/gdcmFileNameEvent.cxx b/gdcm/Source/Common/gdcmFileNameEvent.cxx new file mode 100644 index 0000000..0f48144 --- /dev/null +++ b/gdcm/Source/Common/gdcmFileNameEvent.cxx @@ -0,0 +1,18 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmFileNameEvent.h" + +namespace gdcm +{ +} // end namespace gdcm diff --git a/gdcm/Source/Common/gdcmFileNameEvent.h b/gdcm/Source/Common/gdcmFileNameEvent.h new file mode 100644 index 0000000..01b45b0 --- /dev/null +++ b/gdcm/Source/Common/gdcmFileNameEvent.h @@ -0,0 +1,53 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMFILENAMEEVENT_H +#define GDCMFILENAMEEVENT_H + +#include "gdcmEvent.h" +#include "gdcmTag.h" + +namespace gdcm +{ + +/** + * \brief FileNameEvent + * Special type of event triggered during processing of FileSet + * + * \see AnyEvent + */ +class FileNameEvent : public AnyEvent +{ +public: + typedef FileNameEvent Self; + typedef AnyEvent Superclass; + FileNameEvent(const char *s = ""):m_FileName(s) {} + virtual ~FileNameEvent() {} + virtual const char * GetEventName() const { return "FileNameEvent"; } + virtual bool CheckEvent(const ::gdcm::Event* e) const + { return dynamic_cast(e) ? true : false; } + virtual ::gdcm::Event* MakeObject() const + { return new Self; } + FileNameEvent(const Self&s) : AnyEvent(s){}; + + void SetFileName(const char *f) { m_FileName = f; } + const char *GetFileName() const { return m_FileName.c_str(); } +private: + void operator=(const Self&); + std::string m_FileName; +}; + + +} // end namespace gdcm + +#endif //GDCMFILENAMEEVENT_H diff --git a/gdcm/Source/Common/gdcmFilename.cxx b/gdcm/Source/Common/gdcmFilename.cxx new file mode 100644 index 0000000..fb3a5bc --- /dev/null +++ b/gdcm/Source/Common/gdcmFilename.cxx @@ -0,0 +1,187 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmFilename.h" +#include +#include // realpath +#include +#include + +namespace gdcm +{ + +/** + * Return path of a full filename (no trailing slashes). + * Warning: returned path is converted to Unix slashes format. + */ +const char *Filename::GetPath() +{ + std::string fn = ToUnixSlashes(); + + std::string::size_type slash_pos = fn.rfind("/"); + if(slash_pos != std::string::npos) + { + Path = fn.substr(0, slash_pos); + } + else + { + Path = ""; + } + + return Path.c_str(); +} + + +/** + * Return file name of a full filename (i.e. file name without path). + */ +const char *Filename::GetName() +{ + std::string filename = FileName; + assert( !filename.empty() ); +#if defined(_WIN32) + std::string::size_type slash_pos = filename.find_last_of("/\\"); +#else + std::string::size_type slash_pos = filename.find_last_of("/"); +#endif + if(slash_pos != std::string::npos) + { + return &FileName[0] + slash_pos + 1; + } + + return &FileName[0]; +} + +const char *Filename::ToWindowsSlashes() +{ + Conversion = FileName; + //assert( !Conversion.empty() ); + for (std::string::iterator it = Conversion.begin(); it != Conversion.end(); ++it ) + { + if( *it == '/' ) + { + *it = '\\'; + } + } + + return Conversion.c_str(); +} + +// convert windows slashes to unix slashes +const char *Filename::ToUnixSlashes() +{ + Conversion = FileName; + //std::string::size_type s = Conversion.find("\\"); + //assert( s == std::string::npos ); + assert( !Conversion.empty() ); + for (std::string::iterator it = Conversion.begin(); it != Conversion.end(); ++it ) + { + if( *it == '\\' ) + { + assert( it+1 == Conversion.end() || *(it+1) != ' ' ); // is it an escaped space ? + *it = '/'; + } + } + + return Conversion.c_str(); +} + +#if defined(_WIN32) && (defined(_MSC_VER) || defined(__WATCOMC__) || defined(__BORLANDC__) || defined(__MINGW32__)) +#include + +inline void Realpath(const char *path, std::string & resolved_path) +{ + char *ptemp; + char fullpath[MAX_PATH]; + if( GetFullPathName(path, sizeof(fullpath), fullpath, &ptemp) ) + { + Filename fn( fullpath ); + resolved_path = fn.ToUnixSlashes(); + } + else + { + resolved_path = ""; + } +} +#else +/* The maximum length of a file name. */ +#if defined(PATH_MAX) +# define GDCM_FILENAME_MAXPATH PATH_MAX +#elif defined(MAXPATHLEN) +# define GDCM_FILENAME_MAXPATH MAXPATHLEN +#else +# define GDCM_FILENAME_MAXPATH 16384 +#endif + +inline void Realpath(const char *path, std::string & resolved_path) +{ + char resolved_name[GDCM_FILENAME_MAXPATH]; + + char *ret = realpath(path, resolved_name); + if( ret ) + { + resolved_path = resolved_name; + } + else + { + resolved_path = ""; + } +} +#endif + +const char *Filename::GetExtension() +{ + std::string name = GetName(); + std::string::size_type dot_pos = name.rfind("."); + if(dot_pos != std::string::npos) + { + return GetName() + dot_pos; + } + + return 0; +} + + +bool Filename::IsIdentical(Filename const &fn) const +{ + std::string realpath1; + std::string realpath2; + Realpath(FileName.c_str(), realpath1); + Realpath(fn.GetFileName(), realpath2); + gdcmDebugMacro( "IsIdentical: " << realpath1 << " vs " << realpath2 ); + return realpath1 == realpath2; +} + +const char *Filename::Join(const char *path, const char *filename) +{ + static std::string s; // warning C4640: 's' : construction of local static object is not thread-safe + s = path; + s += '/'; + s += filename; + return s.c_str(); +} + +bool Filename::EndWith(const char ending[]) const +{ + if( !ending ) return false; + const char *str = FileName.c_str(); + size_t str_len = FileName.size(); + size_t ending_len = strlen(ending); + + if(ending_len > str_len) + return false; + + return 0 == strncmp( str + str_len - ending_len, ending, ending_len ); +} + +} // end namespace gdcm diff --git a/gdcm/Source/Common/gdcmFilename.h b/gdcm/Source/Common/gdcmFilename.h new file mode 100644 index 0000000..d380371 --- /dev/null +++ b/gdcm/Source/Common/gdcmFilename.h @@ -0,0 +1,74 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMFILENAME_H +#define GDCMFILENAME_H + +#include "gdcmTypes.h" + +#include + +namespace gdcm +{ +/** + * \brief Class to manipulate file name's + * \note OS independant representation of a filename (to query path, name and extension from a filename) + */ +class GDCM_EXPORT Filename +{ +public: + Filename(const char* filename = ""):FileName(filename ? filename : ""),Path(),Conversion() {} + + /// Return the full filename + const char *GetFileName() const { return FileName.c_str(); } + /// Return only the path component of a filename + const char *GetPath(); + /// return only the name part of a filename + const char *GetName(); + /// return only the extension part of a filename + const char *GetExtension(); + /// Convert backslash (windows style) to UNIX style slash. + const char *ToUnixSlashes(); + /// Convert foward slash (UNIX style) to windows style slash. + const char *ToWindowsSlashes(); + + /// Join two paths + /// NOT THREAD SAFE + static const char *Join(const char *path, const char *filename); + + /// return whether the filename is empty + bool IsEmpty() const { return FileName.empty(); } + + /// Simple operator to allow + /// Filename myfilename( "..." ); + /// const char * s = myfilename; + operator const char * () const { return GetFileName(); } + + // FIXME: I don't like this function + // It hides the realpath call (maybe usefull) + // and it forces file to exist on the disk whereas Filename + // should be independant from file existence. + bool IsIdentical(Filename const &fn) const; + + /// Does the filename ends with a particular string ? + bool EndWith(const char ending[]) const; + +private: + std::string FileName; + std::string Path; + std::string Conversion; +}; + +} // end namespace gdcm + +#endif //GDCMFILENAME_H diff --git a/gdcm/Source/Common/gdcmFilenameGenerator.cxx b/gdcm/Source/Common/gdcmFilenameGenerator.cxx new file mode 100644 index 0000000..f063228 --- /dev/null +++ b/gdcm/Source/Common/gdcmFilenameGenerator.cxx @@ -0,0 +1,118 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmFilenameGenerator.h" +#include "gdcmTrace.h" + +#include // strchr +#include // snprintf +#ifdef _WIN32 +#define snprintf _snprintf +#endif + +namespace gdcm +{ + +//----------------------------------------------------------------------------- +FilenameGenerator::SizeType FilenameGenerator::GetNumberOfFilenames() const +{ + return Filenames.size(); +} + +//----------------------------------------------------------------------------- +void FilenameGenerator::SetNumberOfFilenames(SizeType nfiles) +{ + Filenames.resize( nfiles ); +} + +//----------------------------------------------------------------------------- +const char * FilenameGenerator::GetFilename(SizeType n) const +{ + if( n < Filenames.size() ) + return Filenames[n].c_str(); + return NULL; +} + +//----------------------------------------------------------------------------- +bool FilenameGenerator::Generate() +{ + if( Pattern.empty() && Prefix.empty() ) + { + return false; + } + else if( Pattern.empty() && !Prefix.empty() ) // no pattern but a prefix + { + const SizeType numfiles = Filenames.size(); + for( SizeType i = 0; i < numfiles; ++i) + { + std::ostringstream os; + os << Prefix; + os << i; + Filenames[i] = os.str(); + } + return true; + } + else if( !Pattern.empty() ) + { + std::string::size_type pat_len = Pattern.size(); + const SizeType padding = 10; // FIXME is this large enough for all cases ? + const SizeType internal_len = pat_len + padding; + const SizeType numfiles = Filenames.size(); + if( numfiles == 0 ) + { + gdcmDebugMacro( "Need to specify the number of files" ); + // I am pretty sure this is an error: + return false; + } + const char *pattern = Pattern.c_str(); + int num_percent = 0; + while( (pattern = strchr( pattern, '%')) ) + { + ++pattern; + ++num_percent; + } + if ( num_percent != 1 ) + { + // Bug: what if someone wants to output file such as %%%02 ... oh well + gdcmDebugMacro( "No more than one % in string formating please" ); + return false; + } + bool success = true; + char *internal = new char[internal_len]; + for( SizeType i = 0; i < numfiles && success; ++i) + { + int res = snprintf( internal, internal_len, Pattern.c_str(), i ); + assert( res >= 0 ); + success = (SizeType)res < internal_len; + if( Pattern.empty() ) + { + Filenames[i] = internal; + } + else + { + Filenames[i] = Prefix + internal; + } + //assert( Filenames[i].size() == res ); // upon success only + } + delete[] internal; + if( !success ) + { + Filenames.clear(); + // invalidate size too ?? + } + return success; + } + return false; +} + +} // namespace gdcm diff --git a/gdcm/Source/Common/gdcmFilenameGenerator.h b/gdcm/Source/Common/gdcmFilenameGenerator.h new file mode 100644 index 0000000..8624b6d --- /dev/null +++ b/gdcm/Source/Common/gdcmFilenameGenerator.h @@ -0,0 +1,75 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMFILENAMEGENERATOR_H +#define GDCMFILENAMEGENERATOR_H + +#include "gdcmTypes.h" +#include +#include + + +namespace gdcm +{ +/** + * \brief FilenameGenerator + * \details class to generate filenames based on a pattern (C-style) + * + * Output will be: + * + * for i = 0, number of filenames: + * outfilename[i] = prefix + (pattern % i) + * + * where pattern % i means C-style snprintf of Pattern using value 'i' + */ + +class GDCM_EXPORT FilenameGenerator +{ +public: + FilenameGenerator():Pattern(),Prefix(),Filenames() {} + ~FilenameGenerator() {} + // FIXME: already defines in gdcm::Directory + typedef std::string FilenameType; + typedef std::vector FilenamesType; + typedef FilenamesType::size_type SizeType; + + /// Set/Get pattern + void SetPattern(const char *pattern) { Pattern = pattern; } + const char *GetPattern() const { return Pattern.c_str(); } + + /// Set/Get prefix + void SetPrefix(const char *prefix) { Prefix = prefix; } + const char *GetPrefix() const { return Prefix.c_str(); } + + /// Generate (return success) + bool Generate(); + + /// Set/Get the number of filenames to generate + void SetNumberOfFilenames(SizeType nfiles); + SizeType GetNumberOfFilenames() const; + + /// Get a particular filename (call after Generate) + const char * GetFilename(SizeType n) const; + + /// Return all filenames + FilenamesType const & GetFilenames() const { assert( !Pattern.empty() ); return Filenames; } + +private: + FilenameType Pattern; + FilenameType Prefix; + FilenamesType Filenames; +}; + +} // end namespace gdcm + +#endif //GDCMFILENAMEGENERATOR_H diff --git a/gdcm/Source/Common/gdcmLegacyMacro.h b/gdcm/Source/Common/gdcmLegacyMacro.h new file mode 100644 index 0000000..5a8d323 --- /dev/null +++ b/gdcm/Source/Common/gdcmLegacyMacro.h @@ -0,0 +1,77 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMLEGACYMACRO_H +#define GDCMLEGACYMACRO_H + +#if !defined(GDCMTYPES_H) && !defined(SWIG) +#error you need to include gdcmTypes.h instead +#endif + +#include "gdcmException.h" + +//---------------------------------------------------------------------------- +// Setup legacy code policy. + +// Define GDCM_LEGACY macro to mark legacy methods where they are +// declared in their class. Example usage: +// +// // @deprecated Replaced by MyOtherMethod() as of GDCM 2.0. +// GDCM_LEGACY(void MyMethod()); +#if defined(GDCM_LEGACY_REMOVE) +# define GDCM_LEGACY(method) +#elif defined(GDCM_LEGACY_SILENT) || defined(SWIG) + // Provide legacy methods with no warnings. +# define GDCM_LEGACY(method) method; +#else + // Setup compile-time warnings for uses of deprecated methods if + // possible on this compiler. +# if defined(__GNUC__) && !defined(__INTEL_COMPILER) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) +# define GDCM_LEGACY(method) method __attribute__((deprecated)); +# elif defined(_MSC_VER) && _MSC_VER >= 1300 +# define GDCM_LEGACY(method) __declspec(deprecated) method; +# else +# define GDCM_LEGACY(method) method; +# endif +#endif + +// Macros to create runtime deprecation warning messages in function +// bodies. Example usage: +// +// #if !defined(GDCM_LEGACY_REMOVE) +// void gdcm::MyClass::MyOldMethod() +// { +// GDCM_LEGACY_BODY(gdcm::MyClass::MyOldMethod, "GDCM 2.0"); +// } +// #endif +// +// #if !defined(GDCM_LEGACY_REMOVE) +// void gdcm::MyClass::MyMethod() +// { +// GDCM_LEGACY_REPLACED_BODY(gdcm::MyClass::MyMethod, "GDCM 2.0", +// gdcm::MyClass::MyOtherMethod); +// } +// #endif +#if defined(GDCM_LEGACY_REMOVE) || defined(GDCM_LEGACY_SILENT) +# define GDCM_LEGACY_BODY(method, version) +# define GDCM_LEGACY_REPLACED_BODY(method, version, replace) +#else +# define GDCM_LEGACY_BODY(method, version) \ + gdcmWarningMacro(#method " was deprecated for " version " and will be removed in a future version.") +# define GDCM_LEGACY_REPLACED_BODY(method, version, replace) \ + gdcmWarningMacro(#method " was deprecated for " version " and will be removed in a future version. Use " #replace " instead.") +#endif + +#include "gdcmTrace.h" + +#endif // GDCMLEGACYMACRO_H diff --git a/gdcm/Source/Common/gdcmMD5.cxx b/gdcm/Source/Common/gdcmMD5.cxx new file mode 100644 index 0000000..7ca80c6 --- /dev/null +++ b/gdcm/Source/Common/gdcmMD5.cxx @@ -0,0 +1,181 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmMD5.h" +#include "gdcmSystem.h" + +#ifdef GDCM_USE_SYSTEM_OPENSSL +#include +#elif defined(GDCM_BUILD_TESTING) +#include "gdcm_md5.h" +#endif + +#include //memcmp +#include // malloc +#include // fopen + +/* + */ +namespace gdcm +{ + +class MD5Internals +{ +public: +}; + +MD5::MD5() +{ + Internals = new MD5Internals; +} + +MD5::~MD5() +{ + delete Internals; +} + +bool MD5::Compute(const char *buffer, unsigned long buf_len, char digest_str[33]) +{ + if( !buffer || !buf_len ) + { + return false; + } +#ifdef GDCM_USE_SYSTEM_OPENSSL + unsigned char digest[16]; + MD5_CTX ctx; + MD5_Init(&ctx); + MD5_Update(&ctx, buffer, buf_len); + MD5_Final(digest, &ctx); +#elif defined(GDCM_BUILD_TESTING) + md5_byte_t digest[16]; + md5_state_t state; + md5_init(&state); + md5_append(&state, (const md5_byte_t *)buffer, (int)buf_len); + md5_finish(&state, digest); +#else + unsigned char digest[16] = {}; + return false; +#endif + for (int di = 0; di < 16; ++di) + { + sprintf(digest_str+2*di, "%02x", digest[di]); + } + digest_str[2*16] = '\0'; + return true; +} + +#ifdef GDCM_USE_SYSTEM_OPENSSL +static bool process_file(const char *filename, unsigned char *digest) +{ + if( !filename || !digest ) return false; + + FILE *file = fopen(filename, "rb"); + if(!file) + { + return false; + } + + size_t file_size = System::FileSize(filename); + void *buffer = malloc(file_size); + if(!buffer) + { + fclose(file); + return false; + } + size_t read = fread(buffer, 1, file_size, file); + if( read != file_size ) return false; + + MD5_CTX ctx; + MD5_Init(&ctx); + MD5_Update(&ctx, buffer, file_size); + MD5_Final(digest, &ctx); + + /*printf("MD5 (\"%s\") = ", test[i]); */ + /*for (int di = 0; di < 16; ++di) + { + printf("%02x", digest[di]); + }*/ + //printf("\t%s\n", filename); + free(buffer); + fclose(file); + return true; +} +#elif defined(GDCM_BUILD_TESTING) +inline bool process_file(const char *filename, md5_byte_t *digest) +{ + if( !filename || !digest ) return false; + + FILE *file = fopen(filename, "rb"); + if(!file) + { + return false; + } + + size_t file_size = System::FileSize(filename); + void *buffer = malloc(file_size); + if(!buffer) + { + fclose(file); + return false; + } + size_t read = fread(buffer, 1, file_size, file); + if( read != file_size ) return false; + + md5_state_t state; + md5_init(&state); + md5_append(&state, (const md5_byte_t *)buffer, (int)file_size); + md5_finish(&state, digest); + /*printf("MD5 (\"%s\") = ", test[i]); */ + /*for (int di = 0; di < 16; ++di) + { + printf("%02x", digest[di]); + }*/ + //printf("\t%s\n", filename); + free(buffer); + fclose(file); + return true; +} +#else +inline bool process_file(const char *, unsigned char *) +{ + return false; +} +#endif + +bool MD5::ComputeFile(const char *filename, char digest_str[33]) +{ + // If not file exist + // return false; +#ifdef GDCM_USE_SYSTEM_OPENSSL + unsigned char digest[16]; +#elif defined(GDCM_BUILD_TESTING) + md5_byte_t digest[16]; +#else + unsigned char digest[16] = {}; +#endif + /* Do the file */ + if( !process_file(filename, digest) ) + { + return false; + } + + for (int di = 0; di < 16; ++di) + { + sprintf(digest_str+2*di, "%02x", digest[di]); + } + digest_str[2*16] = '\0'; + return true; +} + + +} // end namespace gdcm diff --git a/gdcm/Source/Common/gdcmMD5.h b/gdcm/Source/Common/gdcmMD5.h new file mode 100644 index 0000000..61abf2d --- /dev/null +++ b/gdcm/Source/Common/gdcmMD5.h @@ -0,0 +1,51 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMMD5_H +#define GDCMMD5_H + +#include "gdcmTypes.h" + +namespace gdcm +{ +//----------------------------------------------------------------------------- +class MD5Internals; +/** + * \brief Class for MD5 + * + * \warning this class is able to pick from two implementations: + * + * 1. a lightweight md5 implementation (when GDCM_BUILD_TESTING is turned ON) + * 2. the one from OpenSSL (when GDCM_USE_SYSTEM_OPENSSL is turned ON) + * + * In all other cases it will return an error + */ +class GDCM_EXPORT MD5 +{ +public : + MD5(); + ~MD5(); + + static bool Compute(const char *buffer, unsigned long buf_len, char digest_str[33]); + + static bool ComputeFile(const char *filename, char digest_str[33]); + +private: + MD5Internals *Internals; +private: + MD5(const MD5&); // Not implemented. + void operator=(const MD5&); // Not implemented. +}; +} // end namespace gdcm +//----------------------------------------------------------------------------- +#endif //GDCMMD5_H diff --git a/gdcm/Source/Common/gdcmObject.cxx b/gdcm/Source/Common/gdcmObject.cxx new file mode 100644 index 0000000..ed1e798 --- /dev/null +++ b/gdcm/Source/Common/gdcmObject.cxx @@ -0,0 +1,24 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmObject.h" + +namespace gdcm +{ + // Don't ask why, but this is EXTREMELY important on Win32 + // Apparently the compiler is doing something special the first time it compiles + // this instanciation unit + // If this fake file is not present I get an unresolved symbol for each function + // of the gdcm::Object class + +} diff --git a/gdcm/Source/Common/gdcmObject.h b/gdcm/Source/Common/gdcmObject.h new file mode 100644 index 0000000..9c150e5 --- /dev/null +++ b/gdcm/Source/Common/gdcmObject.h @@ -0,0 +1,105 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMOBJECT_H +#define GDCMOBJECT_H + +#include "gdcmTypes.h" + +#include +#include // grrrr + +//namespace std { class ostream; } +namespace gdcm +{ + +template class SmartPointer; + +/** + * \brief Object + * + * \note main superclass for object that want to use SmartPointer + * invasive ref counting system + * + * \see SmartPointer + */ +class GDCM_EXPORT Object +{ + template friend class SmartPointer; + friend std::ostream& operator<<(std::ostream &os, const Object &obj); + +public: + Object():ReferenceCount(0) {} + + // Implementation note: + // If I move ~Object in the protected section I can prevent people + // from writing: + // SmartPointer p = new Object; + // delete p; // due to SmartPointer::operator ObjectType * () const + // but on the other hand one could not define an Object on the stack + // Object obj; + // Furthermore it would not prevent anyone from doing: + // class MyObject : public Object {}; + // SmartPointer o = new MyObject; + // delete o; // grrrrrr + virtual ~Object() { + // If your debugger reach here it means you are doing something silly + // like using SmartPointer on object allocated on the stack (vs heap) + assert(ReferenceCount == 0); + } + + // http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.24 + // Set the ref count to 0 + // Do NOT copy the reference count ! + /// Special requirement for copy/cstor, assignment operator + Object(const Object&):ReferenceCount(0){} + void operator=(const Object&){} + + //static Object* New() { return new Object; } + +protected: + // For the purpose of the invasive SmartPointer implementation + void Register() { + ReferenceCount++; + assert( ReferenceCount > 0 ); + } + void UnRegister() { + assert( ReferenceCount > 0 ); + ReferenceCount--; + if(!ReferenceCount) + { + delete this; + } + } + +public: + // For dealing with printing of object and polymorphism + virtual void Print(std::ostream &) const {} + +private: + long ReferenceCount; +}; + +//---------------------------------------------------------------------------- +// function do not carry vtable. Thus define in the base class the operator +// and use the member function ->Print() to call the appropriate function +// NOTE: All subclass of Object needs to implement the Print function +inline std::ostream& operator<<(std::ostream &os, const Object &obj) +{ + obj.Print(os); + return os; +} + +} // end namespace gdcm + +#endif //GDCMOBJECT_H diff --git a/gdcm/Source/Common/gdcmOpenSSLCryptoFactory.cxx b/gdcm/Source/Common/gdcmOpenSSLCryptoFactory.cxx new file mode 100644 index 0000000..d869501 --- /dev/null +++ b/gdcm/Source/Common/gdcmOpenSSLCryptoFactory.cxx @@ -0,0 +1,33 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmOpenSSLCryptoFactory.h" + +#include +#include + +namespace gdcm +{ + +void OpenSSLCryptoFactory::InitOpenSSL() +{ + static bool Initialized = false; + if (!Initialized) + { + OpenSSL_add_all_algorithms(); + ERR_load_crypto_strings(); + Initialized = true; + } +} + +} // end namespace gdcm diff --git a/gdcm/Source/Common/gdcmOpenSSLCryptoFactory.h b/gdcm/Source/Common/gdcmOpenSSLCryptoFactory.h new file mode 100644 index 0000000..172b312 --- /dev/null +++ b/gdcm/Source/Common/gdcmOpenSSLCryptoFactory.h @@ -0,0 +1,47 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMOPENSSLCRYPTOFACTORY_H +#define GDCMOPENSSLCRYPTOFACTORY_H + +#include "gdcmCryptoFactory.h" +#include "gdcmOpenSSLCryptographicMessageSyntax.h" + +namespace gdcm +{ + +class GDCM_EXPORT OpenSSLCryptoFactory : public CryptoFactory +{ +public: + OpenSSLCryptoFactory(CryptoLib id) : CryptoFactory(id) + { + gdcmDebugMacro( "OpenSSL Factory registered." ); + } + +public: + CryptographicMessageSyntax* CreateCMSProvider() + { + InitOpenSSL(); + return new OpenSSLCryptographicMessageSyntax(); + } + +protected: + void InitOpenSSL(); + +private: + OpenSSLCryptoFactory(){} +}; + +} // end namespace gdcm + +#endif //GDCMOPENSSLCRYPTOFACTORY_H diff --git a/gdcm/Source/Common/gdcmOpenSSLCryptographicMessageSyntax.cxx b/gdcm/Source/Common/gdcmOpenSSLCryptographicMessageSyntax.cxx new file mode 100644 index 0000000..97cb06d --- /dev/null +++ b/gdcm/Source/Common/gdcmOpenSSLCryptographicMessageSyntax.cxx @@ -0,0 +1,316 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#include "gdcmOpenSSLCryptographicMessageSyntax.h" + +#include // numeric_limits +#include // memcpy + +#include +#include +#include +#include +#include +#include + +namespace gdcm +{ + +OpenSSLCryptographicMessageSyntax::OpenSSLCryptographicMessageSyntax() : + recips(sk_X509_new_null()), + pkey(NULL), + password(NULL) +{ + cipherType = AES128_CIPHER; + internalCipherType = CreateCipher(cipherType); +} + +OpenSSLCryptographicMessageSyntax::~OpenSSLCryptographicMessageSyntax() +{ + EVP_PKEY_free(pkey); + sk_X509_free(recips); + if (password) delete[] password; +} + +void OpenSSLCryptographicMessageSyntax::SetCipherType( CryptographicMessageSyntax::CipherTypes type ) +{ + internalCipherType = CreateCipher(type); + cipherType = type; +} + +CryptographicMessageSyntax::CipherTypes OpenSSLCryptographicMessageSyntax::GetCipherType() const +{ + return cipherType; +} + +bool OpenSSLCryptographicMessageSyntax::SetPassword(const char * pass, size_t passLen) + { + assert(pass); + + if (password) + { + delete[] password; + } + + passwordLength = passLen; + password = new char[passLen]; + memcpy(password, pass, passLen); + + return true; + } + +bool OpenSSLCryptographicMessageSyntax::Encrypt(char *output, size_t &outlen, const char *array, size_t len) const +{ + BIO *in = NULL, *out = NULL; + CMS_ContentInfo *cms = NULL; + int flags = CMS_BINARY | CMS_PARTIAL; + bool ret = false; + + if (!password && ::sk_X509_num(recips) == 0) + { + gdcmErrorMacro( "No password or recipients added." ); + goto err; + } + + // RAND_status() and RAND_event() return 1 if the PRNG has been seeded with + // enough data, 0 otherwise. + if( !RAND_status() ) + { + gdcmErrorMacro( "PRNG was not seeded properly" ); + goto err; + } + + if( len > (size_t)std::numeric_limits::max() ) + { + gdcmErrorMacro( "len is too big: " << len ); + goto err; + } + + in = BIO_new_mem_buf((void*)array, (int)len); + if(!in) + { + gdcmErrorMacro( "Error at creating the input memory buffer." ); + goto err; + } + + out = BIO_new(BIO_s_mem()); + if (!out) + { + gdcmErrorMacro( "Error at creating the output memory buffer." ); + goto err; + } + + + cms = CMS_encrypt(recips, in, internalCipherType, flags); + if (!cms) + { + gdcmErrorMacro( "Error at creating the CMS strucutre." ); + goto err; + } + + if (password) + { + unsigned char* pwri_tmp = (unsigned char *)BUF_memdup(password, passwordLength); + + if (!pwri_tmp) + goto err; + + if (!CMS_add0_recipient_password(cms, -1, NID_undef, NID_undef, pwri_tmp, passwordLength, NULL)) + goto err; + pwri_tmp = NULL; + } + + if (!CMS_final(cms, in, NULL, flags)) + goto err; + + if (! i2d_CMS_bio(out, cms)) + { + gdcmErrorMacro( "Error at writing CMS structure to output." ); + goto err; + } + + BUF_MEM *bptr; + BIO_get_mem_ptr(out, &bptr); + + if (bptr->length > outlen) + { + gdcmErrorMacro( "Supplied output buffer too small: " << bptr->length << " bytes needed." ); + goto err; + } + memcpy(output, bptr->data, bptr->length); + outlen = bptr->length; + + ret = true; + +err: + if (!ret) + { + outlen = 0; + gdcmErrorMacro( ERR_error_string(ERR_peek_error(), NULL) ); + } + + if (cms) + CMS_ContentInfo_free(cms); + if (in) + BIO_free(in); + if (out) + BIO_free(out); + + return ret; +} + +bool OpenSSLCryptographicMessageSyntax::Decrypt(char *output, size_t &outlen, const char *array, size_t len) const +{ + BIO *in = NULL, *out = NULL; + CMS_ContentInfo *cms = NULL; + bool ret = false; + int flags = /*CMS_DETACHED | */CMS_BINARY; + + if (!password && pkey == NULL) + { + gdcmErrorMacro( "No password or private key specified." ); + goto err; + } + + in = BIO_new_mem_buf((void*)array, (int)len); + if (!in) + { + gdcmErrorMacro( "Error at creating the input memory buffer." ); + goto err; + } + + cms = d2i_CMS_bio(in, NULL); + if (!cms) + { + gdcmErrorMacro( "Error when parsing the CMS structure." ); + goto err; + } + + out = BIO_new(BIO_s_mem()); + if (!out) + { + gdcmErrorMacro( "Error at creating the output memory buffer." ); + goto err; + } + + if (password) + if (!CMS_decrypt_set1_password(cms, (unsigned char*)password, passwordLength)) + { + gdcmErrorMacro( "Error at setting the decryption password." ); + goto err; + } + + if (!CMS_decrypt(cms, pkey, NULL, NULL, out, flags)) + { + gdcmErrorMacro( "Error at decrypting CMS structure" ); + goto err; + } + + BUF_MEM *bptr; + BIO_get_mem_ptr(out, &bptr); + + if (bptr->length > outlen) + { + gdcmErrorMacro( "Supplied output buffer too small: " << bptr->length << " bytes needed." ); + goto err; + } + memcpy(output, bptr->data, bptr->length); + outlen = bptr->length; + + ret = true; + +err: + if (!ret) + { + outlen = 0; + gdcmErrorMacro( ERR_error_string(ERR_peek_error(), NULL) ); + } + + if (cms) + CMS_ContentInfo_free(cms); + if (in) + BIO_free(in); + if (out) + BIO_free(out); + + return ret; +} + +bool OpenSSLCryptographicMessageSyntax::ParseKeyFile( const char *keyfile) +{ + ::BIO *in; + ::EVP_PKEY *new_pkey; + if ((in=::BIO_new_file(keyfile,"r")) == NULL) + { + return false; + } + (void)BIO_reset(in); + if ((new_pkey=PEM_read_bio_PrivateKey(in,NULL,NULL,NULL)) == NULL) + { + return false; + } + BIO_free(in); + + if (pkey != NULL) + { + EVP_PKEY_free(pkey); + } + + this->pkey = new_pkey; + return true; +} + +bool OpenSSLCryptographicMessageSyntax::ParseCertificateFile( const char *keyfile) +{ + assert( recips ); + ::X509 *x509 = NULL; + + ::BIO *in; + if (!(in=::BIO_new_file(keyfile,"r"))) + { + return false; + } + // -> LEAK reported by valgrind... + if (!(x509=::PEM_read_bio_X509(in,NULL,NULL,NULL))) + { + return false; + } + ::BIO_free(in); in = NULL; + ::sk_X509_push(recips, x509); + return true; +} + +const EVP_CIPHER* OpenSSLCryptographicMessageSyntax::CreateCipher( CryptographicMessageSyntax::CipherTypes ciphertype) +{ + const EVP_CIPHER *cipher = 0; + switch( ciphertype ) + { + case CryptographicMessageSyntax::DES3_CIPHER: // Triple DES + cipher = EVP_des_ede3_cbc(); + break; + case CryptographicMessageSyntax::AES128_CIPHER: // CBC AES + cipher = EVP_aes_128_cbc(); + break; + case CryptographicMessageSyntax::AES192_CIPHER: // ' ' + cipher = EVP_aes_192_cbc(); + break; + case CryptographicMessageSyntax::AES256_CIPHER: // ' ' + cipher = EVP_aes_256_cbc(); + break; + } + return cipher; +} + +} // end namespace gdcm + diff --git a/gdcm/Source/Common/gdcmOpenSSLCryptographicMessageSyntax.h b/gdcm/Source/Common/gdcmOpenSSLCryptographicMessageSyntax.h new file mode 100644 index 0000000..dc98d3e --- /dev/null +++ b/gdcm/Source/Common/gdcmOpenSSLCryptographicMessageSyntax.h @@ -0,0 +1,67 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMOPENSSLCRYPTOGRAPHICMESSAGESYNTAX_H +#define GDCMOPENSSLCRYPTOGRAPHICMESSAGESYNTAX_H + +#include "gdcmCryptographicMessageSyntax.h" +#include +#include + +namespace gdcm +{ + +class GDCM_EXPORT OpenSSLCryptographicMessageSyntax : public CryptographicMessageSyntax +{ +public: + OpenSSLCryptographicMessageSyntax(); + ~OpenSSLCryptographicMessageSyntax(); + + // X.509 + bool ParseCertificateFile( const char *filename ); + bool ParseKeyFile( const char *filename ); + + // PBE + bool SetPassword(const char * pass, size_t passLen); + + /// Set Cipher Type. + /// Default is: AES256_CIPHER + void SetCipherType(CipherTypes type); + CipherTypes GetCipherType() const; + /// create a CMS envelopedData structure + bool Encrypt(char *output, size_t &outlen, const char *array, size_t len) const; + /// decrypt content from a PKCS#7 envelopedData structure + bool Decrypt(char *output, size_t &outlen, const char *array, size_t len) const; + +private: +//#ifdef GDCM_HAVE_CMS_RECIPIENT_PASSWORD +// ::stack_st_X509 *recips; +//#else + STACK_OF(X509) *recips; +//#endif + ::EVP_PKEY *pkey; + const EVP_CIPHER *internalCipherType; + char * password; + size_t passwordLength; + CipherTypes cipherType; + +private: + OpenSSLCryptographicMessageSyntax(const OpenSSLCryptographicMessageSyntax&); // Not implemented. + void operator=(const OpenSSLCryptographicMessageSyntax&); // Not implemented. + const EVP_CIPHER *CreateCipher( CryptographicMessageSyntax::CipherTypes ciphertype); + +}; + +} // end namespace gdcm + +#endif //GDCMOPENSSLCRYPTOGRAPHICMESSAGESYNTAX_H diff --git a/gdcm/Source/Common/gdcmOpenSSLP7CryptoFactory.cxx b/gdcm/Source/Common/gdcmOpenSSLP7CryptoFactory.cxx new file mode 100644 index 0000000..e74b055 --- /dev/null +++ b/gdcm/Source/Common/gdcmOpenSSLP7CryptoFactory.cxx @@ -0,0 +1,19 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#include "gdcmOpenSSLP7CryptoFactory.h" + +//namespace gdcm{ + //gdcm::OpenSSLCryptoFactory osslf; +//} diff --git a/gdcm/Source/Common/gdcmOpenSSLP7CryptoFactory.h b/gdcm/Source/Common/gdcmOpenSSLP7CryptoFactory.h new file mode 100644 index 0000000..9532db1 --- /dev/null +++ b/gdcm/Source/Common/gdcmOpenSSLP7CryptoFactory.h @@ -0,0 +1,41 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMOPENSSLP7CRYPTOFACTORY_H +#define GDCMOPENSSLP7CRYPTOFACTORY_H + +#include "gdcmCryptoFactory.h" +#include "gdcmOpenSSLP7CryptographicMessageSyntax.h" + +namespace gdcm +{ +class GDCM_EXPORT OpenSSLP7CryptoFactory : public CryptoFactory +{ +public: + OpenSSLP7CryptoFactory(CryptoLib id) : CryptoFactory(id) + { + gdcmDebugMacro( "OpenSSL (PKCS7) Factory registered." ); + } + +public: + CryptographicMessageSyntax* CreateCMSProvider() + { + return new OpenSSLP7CryptographicMessageSyntax(); + } + +private: + OpenSSLP7CryptoFactory(){} +}; +} + +#endif //GDCMOPENSSLP7CRYPTOFACTORY_H diff --git a/gdcm/Source/Common/gdcmOpenSSLP7CryptographicMessageSyntax.cxx b/gdcm/Source/Common/gdcmOpenSSLP7CryptographicMessageSyntax.cxx new file mode 100644 index 0000000..04b0780 --- /dev/null +++ b/gdcm/Source/Common/gdcmOpenSSLP7CryptographicMessageSyntax.cxx @@ -0,0 +1,463 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +//#include "gdcmCryptographicMessageSyntax.h" +#include "gdcmOpenSSLP7CryptographicMessageSyntax.h" +#include "gdcmTrace.h" + +#include // numeric_limits + +#include // stderr +#include // strcmp +#include +#include // time() + +#ifdef GDCM_USE_SYSTEM_OPENSSL +#include +#include +#include +#include +#include +#endif + +/* + * http://en.wikipedia.org/wiki/PKCS + * PKCS#7 <=> Cryptographic Message Syntax Standard + */ +namespace gdcm +{ + +/* + * openssl genrsa -out CA_key.pem 2048 + * + * openssl req -new -key CA_key.pem -x509 -days 365 -out CA_cert.cer + */ +/* + * openssl smime -encrypt -aes256 -in inputfile.txt -out outputfile.txt -outform DER /tmp/server.pem + */ +#ifdef GDCM_USE_SYSTEM_OPENSSL +const EVP_CIPHER *CreateCipher( CryptographicMessageSyntax::CipherTypes ciphertype) +{ + const EVP_CIPHER *cipher = 0; + switch( ciphertype ) + { + case CryptographicMessageSyntax::DES3_CIPHER: // Triple DES + cipher = EVP_des_ede3_cbc(); + break; + case CryptographicMessageSyntax::AES128_CIPHER: // CBC AES + cipher = EVP_aes_128_cbc(); + break; + case CryptographicMessageSyntax::AES192_CIPHER: // ' ' + cipher = EVP_aes_192_cbc(); + break; + case CryptographicMessageSyntax::AES256_CIPHER: // ' ' + cipher = EVP_aes_256_cbc(); + break; + } + return cipher; +} +#endif + +class CryptographicMessageSyntaxInternals +{ +#ifdef GDCM_USE_SYSTEM_OPENSSL +public: + CryptographicMessageSyntaxInternals():recips(NULL),pkey(NULL),CipherType( CryptographicMessageSyntax::AES256_CIPHER ),cipher(NULL),p7(PKCS7_new()){ + recips = sk_X509_new_null(); + PKCS7_set_type(p7,NID_pkcs7_enveloped); + bio_buffer = BIO_new(BIO_s_mem()); + Initialized = false; + } + ~CryptographicMessageSyntaxInternals() { + EVP_PKEY_free(pkey); + PKCS7_free(p7); + p7 = NULL; + BIO_free_all(bio_buffer); + } + unsigned int GetNumberOfRecipients() const { + //::STACK_OF(X509) *recips = recips; + if(!recips) { + return 0; + } + return ::sk_X509_num(recips); + } + STACK_OF(X509)* GetRecipients( ) const { + return recips; + } + ::X509* GetRecipient( unsigned int i ) const { + //::STACK_OF(X509) *recips = Internals->recips; + ::X509 *ret = sk_X509_value(recips, i); + return ret; + } + void SetPrivateKey(::EVP_PKEY* thepkey) { + this->pkey = thepkey; + } + ::EVP_PKEY* GetPrivateKey() const { + return pkey; + } + void SetCipherType(CryptographicMessageSyntax::CipherTypes ciphertype) { + CipherType = ciphertype; + } + bool Initialize() + { + if(!cipher) + { + cipher = CreateCipher( GetCipherType() ); + } + if(!cipher) return false; + // The following is inspired by PKCS7_encrypt + // and openssl/crypto/pkcs7/enc.c + if( !PKCS7_set_cipher(p7,cipher) ) return false; + + for(unsigned int i = 0; i < GetNumberOfRecipients(); i++) { + ::X509* recip = GetRecipient(i); + if (!PKCS7_add_recipient(p7,recip)) return false; + } + sk_X509_pop_free(recips, X509_free); + + /* Set the content of the signed to 'data' */ + /* PKCS7_content_new(p7,NID_pkcs7_data); not used in envelope */ + + /* could be used, but not in this version :-) + if (!nodetach) PKCS7_set_detached(p7,1); + */ + + return true; + } + + bool Encrypt(char *output, size_t &outlen, const char *array, size_t len) + { + if( !Initialized ) + { + bool b = Initialize(); + if ( !b ) + { + gdcmErrorMacro( "Initialize" ); + return false; + } + Initialized = true; + } + + if( len > (size_t)std::numeric_limits::max() ) + { + gdcmErrorMacro( "len is too big: " << len ); + return false; + } + BIO *data = BIO_new_mem_buf((void*)array, (int)len); + if(!data) + { + gdcmErrorMacro( "BIO_new_mem_buf" ); + return false; + } + + char buf[256]; + BIO *p7bio; + if ((p7bio=PKCS7_dataInit(p7,NULL)) == NULL) return false; + for (;;) + { + int i = BIO_read(data,buf,sizeof(buf)); + if (i <= 0) break; + BIO_write(p7bio,buf,i); + } + // BIO_flush() returns 1 for success and 0 or -1 for failure. + int bflush = BIO_flush(p7bio); + if( bflush != 1 ) + { + gdcmErrorMacro( "BIO_flush: " << bflush ); + return false; + } + + if (!PKCS7_dataFinal(p7,p7bio)) + { + gdcmErrorMacro( "PKCS7_dataFinal" ); + return false; + } + + // WARNING: + // BIO_reset() normally returns 1 for success and 0 or -1 for failure. File + // BIOs are an exception, they return 0 for success and -1 for failure. + if( BIO_reset(bio_buffer) != 1 ) + { + gdcmErrorMacro( "BIO_reset" ); + return false; + } + + i2d_PKCS7_bio(bio_buffer,p7); + // (void)BIO_flush(wbio); + + char *binary; + long biolen = BIO_get_mem_data(bio_buffer,&binary); + gdcmAssertMacro( biolen >= 0 ); + if ( outlen < (size_t)biolen ) + { + gdcmErrorMacro( "Allocation issue: " << outlen << " vs " << biolen << " from " << len ); + return false; + } + outlen = biolen; + memcpy( output, binary, outlen ); + + BIO_free(data); + BIO_free_all(p7bio); + return true; + } + CryptographicMessageSyntax::CipherTypes GetCipherType() const { + return CipherType; + } + ::PKCS7 *GetP7() const { return p7; } +private: + STACK_OF(X509) *recips; + ::EVP_PKEY *pkey; + CryptographicMessageSyntax::CipherTypes CipherType; + const EVP_CIPHER *cipher; + ::PKCS7 *p7; + BIO *bio_buffer; + bool Initialized; +#endif +}; + +OpenSSLP7CryptographicMessageSyntax::OpenSSLP7CryptographicMessageSyntax() +{ + Internals = new CryptographicMessageSyntaxInternals; +} + +OpenSSLP7CryptographicMessageSyntax::~OpenSSLP7CryptographicMessageSyntax() +{ + delete Internals; +} + +void OpenSSLP7CryptographicMessageSyntax::SetCipherType( CryptographicMessageSyntax::CipherTypes type ) +{ +#ifdef GDCM_USE_SYSTEM_OPENSSL + Internals->SetCipherType( type ); +#else + (void)type; +#endif +} + +CryptographicMessageSyntax::CipherTypes OpenSSLP7CryptographicMessageSyntax::GetCipherType() const +{ +#ifdef GDCM_USE_SYSTEM_OPENSSL + return Internals->GetCipherType(); +#else + return AES256_CIPHER; // why not :) +#endif +} + +bool OpenSSLP7CryptographicMessageSyntax::Encrypt(char *output, size_t &outlen, const char *array, size_t len) const +{ +#ifdef GDCM_USE_SYSTEM_OPENSSL + // RAND_status() and RAND_event() return 1 if the PRNG has been seeded with + // enough data, 0 otherwise. + if( !RAND_status() ) + { + gdcmErrorMacro( "PRNG was not seeded properly" ); + outlen = 0; + return false; + } + return Internals->Encrypt(output, outlen, array, len); +#else + (void)output; + (void)array; + (void)len; + outlen = 0; + gdcmDebugMacro( "GDCM_USE_SYSTEM_OPENSSL is OFF" ); + return false; +#endif /* GDCM_USE_SYSTEM_OPENSSL */ +} + +/* + $ openssl smime -decrypt -in /tmp/debug.der -inform DER -recip /tmp/server.pem -inkey CA_key.pem +*/ +bool OpenSSLP7CryptographicMessageSyntax::Decrypt(char *output, size_t &outlen, const char *array, size_t len) const +{ +#ifdef GDCM_USE_SYSTEM_OPENSSL + CryptographicMessageSyntaxInternals *x509 = Internals; + ::PKCS7 *p7; +#undef PKCS7_SIGNER_INFO + ::PKCS7_SIGNER_INFO *si; + X509_STORE_CTX cert_ctx; + X509_STORE *cert_store=NULL; + BIO *data,*detached=NULL,*p7bio=NULL; + char buf[1024*4]; + unsigned char *pp; + int i; + STACK_OF(PKCS7_SIGNER_INFO) *sk; + char * ptr = output; + outlen = 0; + + OpenSSL_add_all_algorithms(); + //bio_err=BIO_new_fp(stderr,BIO_NOCLOSE); + + //data=BIO_new(BIO_s_file()); + pp=NULL; + + EVP_PKEY *pkey = x509->GetPrivateKey(); + + if( len > (size_t)std::numeric_limits::max() ) + { + gdcmErrorMacro( "len is too big: " << len ); + return false; + } + data = BIO_new_mem_buf((void*)array, (int)len); + if(!data) goto err; + + + if (pp == NULL) + BIO_set_fp(data,stdin,BIO_NOCLOSE); + + + /* Load the PKCS7 object from a file */ + //if ((p7=PEM_read_bio_PKCS7(data,NULL,NULL,NULL)) == NULL) goto err; + if ((p7=d2i_PKCS7_bio(data,NULL)) == NULL) goto err; + + if(!PKCS7_type_is_enveloped(p7)) { + goto err; + } + +// if(cert && !X509_check_private_key(cert, pkey)) { +// PKCS7err(PKCS7_F_PKCS7_DECRYPT, +// PKCS7_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE); +// return 0; +// } + + + /* This stuff is being setup for certificate verification. + * When using SSL, it could be replaced with a + * cert_stre=SSL_CTX_get_cert_store(ssl_ctx); */ + cert_store=X509_STORE_new(); + X509_STORE_set_default_paths(cert_store); + X509_STORE_load_locations(cert_store,NULL,"../../certs"); + //X509_STORE_set_verify_cb_func(cert_store,verify_callback); + + ERR_clear_error(); + + /* We need to process the data */ + /* We cannot support detached encryption */ + p7bio=PKCS7_dataDecode(p7,pkey,detached,NULL); + + if (p7bio == NULL) + { + printf("problems decoding\n"); + goto err; + } + + /* We now have to 'read' from p7bio to calculate digests etc. */ + for (;;) + { + i=BIO_read(p7bio,buf,sizeof(buf)); + /* print it? */ + if (i <= 0) break; + //fwrite(buf,1, i, stdout); + memcpy(ptr, buf, i); + ptr += i; + outlen += i; + } + + /* We can now verify signatures */ + sk=PKCS7_get_signer_info(p7); + if (sk == NULL) + { + //fprintf(stderr, "there are no signatures on this data\n"); + } + else + { + /* Ok, first we need to, for each subject entry, + * see if we can verify */ + ERR_clear_error(); + for (i=0; iSetPrivateKey( pkey ); + return true; +#else + (void)keyfile; + gdcmDebugMacro( "GDCM_USE_SYSTEM_OPENSSL is OFF" ); + return false; +#endif +} + +bool OpenSSLP7CryptographicMessageSyntax::ParseCertificateFile( const char *keyfile) +{ +#ifdef GDCM_USE_SYSTEM_OPENSSL + STACK_OF(X509) *recips = Internals->GetRecipients(); + assert( recips ); + ::X509 *x509 = NULL; + + ::BIO *in; + if (!(in=::BIO_new_file(keyfile,"r"))) + { + return false; + } + // -> LEAK reported by valgrind... + if (!(x509=::PEM_read_bio_X509(in,NULL,NULL,NULL))) + { + return false; + } + ::BIO_free(in); in = NULL; + ::sk_X509_push(recips, x509); + return true; +#else + (void)keyfile; + gdcmDebugMacro( "GDCM_USE_SYSTEM_OPENSSL is OFF" ); + return false; +#endif +} + + +} // end namespace gdcm diff --git a/gdcm/Source/Common/gdcmOpenSSLP7CryptographicMessageSyntax.h b/gdcm/Source/Common/gdcmOpenSSLP7CryptographicMessageSyntax.h new file mode 100644 index 0000000..2cb1192 --- /dev/null +++ b/gdcm/Source/Common/gdcmOpenSSLP7CryptographicMessageSyntax.h @@ -0,0 +1,70 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMOPENSSLP7CRYPTOGRAPHICMESSAGESYNTAX_H +#define GDCMOPENSSLP7CRYPTOGRAPHICMESSAGESYNTAX_H + +#include "gdcmCryptographicMessageSyntax.h" +#include "gdcmTypes.h" + +namespace gdcm +{ +class CryptographicMessageSyntaxInternals; +//----------------------------------------------------------------------------- + +/** + * \brief + * Class for CryptographicMessageSyntax encryption. This is just a simple + * wrapper around openssl PKCS7_encrypt functionalities + * + * See online documentation + * http://www.openssl.org/docs/crypto/PKCS7_encrypt.html + * + */ +class GDCM_EXPORT OpenSSLP7CryptographicMessageSyntax : public CryptographicMessageSyntax +{ +public: + OpenSSLP7CryptographicMessageSyntax(); + ~OpenSSLP7CryptographicMessageSyntax(); + + // X.509 + bool ParseCertificateFile( const char *filename ); + bool ParseKeyFile( const char *filename ); + + // PBE + bool SetPassword(const char * /*pass*/, size_t /*passLen*/) + { + gdcmWarningMacro( "Openssl using PKCS7 does not support Password Based Encryption." ); + return false; + } + + /// Set Cipher Type. + /// Default is: AES256_CIPHER + void SetCipherType(CipherTypes type); + CipherTypes GetCipherType() const; + + /// create a PKCS#7 envelopedData structure + bool Encrypt(char *output, size_t &outlen, const char *array, size_t len) const; + + /// decrypt content from a PKCS#7 envelopedData structure + bool Decrypt(char *output, size_t &outlen, const char *array, size_t len) const; + +private: + CryptographicMessageSyntaxInternals *Internals; +private: + OpenSSLP7CryptographicMessageSyntax(const OpenSSLP7CryptographicMessageSyntax&); // Not implemented. + void operator=(const OpenSSLP7CryptographicMessageSyntax&); // Not implemented. +}; +} // end namespace gdcm +//----------------------------------------------------------------------------- +#endif //GDCMOPENSSLP7CRYPTOGRAPHICMESSAGESYNTAX_H diff --git a/gdcm/Source/Common/gdcmProgressEvent.cxx b/gdcm/Source/Common/gdcmProgressEvent.cxx new file mode 100644 index 0000000..1ad1e26 --- /dev/null +++ b/gdcm/Source/Common/gdcmProgressEvent.cxx @@ -0,0 +1,18 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmProgressEvent.h" + +namespace gdcm +{ +} // end namespace gdcm diff --git a/gdcm/Source/Common/gdcmProgressEvent.h b/gdcm/Source/Common/gdcmProgressEvent.h new file mode 100644 index 0000000..ce8cf88 --- /dev/null +++ b/gdcm/Source/Common/gdcmProgressEvent.h @@ -0,0 +1,53 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMPROGRESSEVENT_H +#define GDCMPROGRESSEVENT_H + +#include "gdcmEvent.h" +#include "gdcmTag.h" + +namespace gdcm +{ + +/** + * \brief ProgressEvent + * Special type of event triggered during + * + * \see AnyEvent + */ +class ProgressEvent : public AnyEvent +{ +public: + typedef ProgressEvent Self; + typedef AnyEvent Superclass; + ProgressEvent(double p = 0):m_Progress(p) {} + virtual ~ProgressEvent() {} + virtual const char * GetEventName() const { return "ProgressEvent"; } + virtual bool CheckEvent(const ::gdcm::Event* e) const + { return dynamic_cast(e) ? true : false; } + virtual ::gdcm::Event* MakeObject() const + { return new Self; } + ProgressEvent(const Self&s) : AnyEvent(s){}; + + void SetProgress(double p) { m_Progress = p; } + double GetProgress() const { return m_Progress; } +private: + void operator=(const Self&); + double m_Progress; +}; + + +} // end namespace gdcm + +#endif //GDCMPROGRESSEVENT_H diff --git a/gdcm/Source/Common/gdcmRegion.cxx b/gdcm/Source/Common/gdcmRegion.cxx new file mode 100644 index 0000000..36c428c --- /dev/null +++ b/gdcm/Source/Common/gdcmRegion.cxx @@ -0,0 +1,32 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmRegion.h" +#include "gdcmBoxRegion.h" + +namespace gdcm +{ + +Region::Region() +{ +} + +Region::~Region() +{ +} + +void Region::Print(std::ostream &) const +{ +} + +} // end namespace gdcm diff --git a/gdcm/Source/Common/gdcmRegion.h b/gdcm/Source/Common/gdcmRegion.h new file mode 100644 index 0000000..557d165 --- /dev/null +++ b/gdcm/Source/Common/gdcmRegion.h @@ -0,0 +1,62 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMREGION_H +#define GDCMREGION_H + +#include "gdcmTypes.h" +#include +#include + +namespace gdcm +{ +class BoxRegion; +/** + * \brief Class for manipulation region + */ +//----------------------------------------------------------------------------- +class GDCM_EXPORT Region +{ +public : + Region(); + virtual ~Region(); + + /// Print + virtual void Print(std::ostream &os = std::cout) const; + + /// return whether this domain is empty: + virtual bool Empty() const = 0; + + /// return whether this is valid domain + virtual bool IsValid() const = 0; + + /// compute the area + virtual size_t Area() const = 0; + + // implementation detail of heterogenous container in C++ + virtual Region *Clone() const = 0; + + /// Return the Axis-Aligned minimum bounding box for all regions + virtual BoxRegion ComputeBoundingBox() = 0; +private: +}; +//----------------------------------------------------------------------------- +inline std::ostream& operator<<(std::ostream &os, const Region&r) +{ + r.Print( os ); + return os; +} + +} // end namespace gdcm +//----------------------------------------------------------------------------- +#endif //GDCMREGION_H diff --git a/gdcm/Source/Common/gdcmSHA1.cxx b/gdcm/Source/Common/gdcmSHA1.cxx new file mode 100644 index 0000000..f70d926 --- /dev/null +++ b/gdcm/Source/Common/gdcmSHA1.cxx @@ -0,0 +1,146 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmSHA1.h" +#include "gdcmSystem.h" + +#ifdef GDCM_USE_SYSTEM_OPENSSL +#include +#endif + +#include // memcmp +#include // malloc +#include // sprintf + +/* + */ +namespace gdcm +{ + +class SHA1Internals +{ +public: +#ifdef GDCM_USE_SYSTEM_OPENSSL + SHA_CTX ctx; +#endif +}; + +SHA1::SHA1() +{ + Internals = new SHA1Internals; +} + +SHA1::~SHA1() +{ + delete Internals; +} + +bool SHA1::Compute(const char *buffer, unsigned long buf_len, char digest[]) +{ +#ifdef GDCM_USE_SYSTEM_OPENSSL + if( !buffer || !buf_len ) + { + return false; + } + + unsigned char output[20]; + + SHA_CTX ctx; + SHA1_Init(&ctx); + SHA1_Update(&ctx, buffer, buf_len); + SHA1_Final(output, &ctx); + + for (int di = 0; di < 20; ++di) + { + sprintf(digest+2*di, "%02x", output[di]); + } + digest[2*20] = '\0'; + + return true; +#else + (void)buffer; + (void)buf_len; + (void)digest; + return false; +#endif +} + +#ifdef GDCM_USE_SYSTEM_OPENSSL +static bool process_file(const char *filename, unsigned char *digest) +{ + if( !filename || !digest ) return false; + + FILE *file = fopen(filename, "rb"); + if(!file) + { + return false; + } + + size_t file_size = System::FileSize(filename); + void *buffer = malloc(file_size); + if(!buffer) + { + fclose(file); + return false; + } + size_t read = fread(buffer, 1, file_size, file); + if( read != file_size ) return false; + + SHA_CTX ctx; + int ret = SHA1_Init(&ctx); + if( !ret ) return false; + ret = SHA1_Update(&ctx, buffer, file_size); + if( !ret ) return false; + ret = SHA1_Final(digest, &ctx); + if( !ret ) return false; + + /*printf("MD5 (\"%s\") = ", test[i]); */ + /*for (int di = 0; di < 16; ++di) + { + printf("%02x", digest[di]); + }*/ + //printf("\t%s\n", filename); + free(buffer); + fclose(file); + return true; +} +#endif + +bool SHA1::ComputeFile(const char *filename, char digest_str[20*2+1]) +{ +#ifdef GDCM_USE_SYSTEM_OPENSSL + // If not file exist + // return false; + unsigned char digest[20]; + + /* Do the file */ + if( !process_file(filename, digest) ) + { + return false; + } + + for (int di = 0; di < 20; ++di) + { + sprintf(digest_str+2*di, "%02x", digest[di]); + } + digest_str[2*20] = '\0'; + return true; +#else + (void)filename; + (void)digest_str; + return false; +#endif +} + + +} // end namespace gdcm diff --git a/gdcm/Source/Common/gdcmSHA1.h b/gdcm/Source/Common/gdcmSHA1.h new file mode 100644 index 0000000..c2aa1cb --- /dev/null +++ b/gdcm/Source/Common/gdcmSHA1.h @@ -0,0 +1,50 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMSHA1_H +#define GDCMSHA1_H + +#include "gdcmTypes.h" + +namespace gdcm +{ +//----------------------------------------------------------------------------- +class SHA1Internals; +/** + * \brief Class for SHA1 + * + * \warning this class is able to pick from one implementation: + * + * 1. the one from OpenSSL (when GDCM_USE_SYSTEM_OPENSSL is turned ON) + * + * In all other cases it will return an error + */ +class GDCM_EXPORT SHA1 +{ +public : + SHA1(); + ~SHA1(); + + static bool Compute(const char *buffer, unsigned long buf_len, char digest_str[20*2+1]); + + static bool ComputeFile(const char *filename, char digest_str[20*2+1]); + +private: + SHA1Internals *Internals; +private: + SHA1(const SHA1&); // Not implemented. + void operator=(const SHA1&); // Not implemented. +}; +} // end namespace gdcm +//----------------------------------------------------------------------------- +#endif //GDCMSHA1_H diff --git a/gdcm/Source/Common/gdcmSmartPointer.h b/gdcm/Source/Common/gdcmSmartPointer.h new file mode 100644 index 0000000..11afb21 --- /dev/null +++ b/gdcm/Source/Common/gdcmSmartPointer.h @@ -0,0 +1,115 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMSMARTPOINTER_H +#define GDCMSMARTPOINTER_H + +#include "gdcmObject.h" + +namespace gdcm +{ +/** + * \brief Class for Smart Pointer + * \details + * Will only work for subclass of gdcm::Object + * See tr1/shared_ptr for a more general approach (not invasive) + * #include + * { + * shared_ptr b(new Bla); + * } + * \note + * Class partly based on post by Bill Hubauer: + * http://groups.google.com/group/comp.lang.c++/msg/173ddc38a827a930 + * \see + * http://www.davethehat.com/articles/smartp.htm + * + * and itk::SmartPointer + */ +template +class SmartPointer +{ +public: + SmartPointer():Pointer(0) {} + SmartPointer(const SmartPointer& p):Pointer(p.Pointer) + { Register(); } + SmartPointer(ObjectType* p):Pointer(p) + { Register(); } + SmartPointer(ObjectType const & p) + { + Pointer = const_cast(&p); + Register(); + } + ~SmartPointer() { + UnRegister(); + Pointer = 0; + } + + /// Overload operator -> + ObjectType *operator -> () const + { return Pointer; } + + ObjectType& operator * () const + { return *Pointer; } + + /// Return pointer to object. + operator ObjectType * () const + { return Pointer; } + + /// Overload operator assignment. + SmartPointer &operator = (SmartPointer const &r) + { return operator = (r.Pointer); } + + /// Overload operator assignment. + SmartPointer &operator = (ObjectType *r) + { + // http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.22 + // DO NOT CHANGE THE ORDER OF THESE STATEMENTS! + // (This order properly handles self-assignment) + // (This order also properly handles recursion, e.g., if a ObjectType contains SmartPointers) + if( Pointer != r ) + { + ObjectType* old = Pointer; + Pointer = r; + Register(); + if ( old ) { old->UnRegister(); } + } + return *this; + } + + SmartPointer &operator = (ObjectType const &r) + { + ObjectType* tmp = const_cast(&r); + return operator = (tmp); + } + + /// Explicit function to retrieve the pointer + ObjectType *GetPointer() const + { return Pointer; } + +private: + void Register() + { + if(Pointer) Pointer->Register(); + } + + void UnRegister() + { + if(Pointer) Pointer->UnRegister(); + } + + ObjectType* Pointer; +}; + +} // end namespace gdcm + +#endif //GDCMSMARTPOINTER_H diff --git a/gdcm/Source/Common/gdcmStaticAssert.h b/gdcm/Source/Common/gdcmStaticAssert.h new file mode 100644 index 0000000..6f8c732 --- /dev/null +++ b/gdcm/Source/Common/gdcmStaticAssert.h @@ -0,0 +1,52 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMSTATICASSERT_H +#define GDCMSTATICASSERT_H + + +// the following was shamelessly borowed from BOOST static assert: +namespace gdcm +{ + template + struct STATIC_ASSERTION_FAILURE; + + template <> + struct STATIC_ASSERTION_FAILURE { enum { value = 1 }; }; + + template + struct static_assert_test {}; +} + +#define GDCM_JOIN( X, Y ) GDCM_DO_JOIN( X, Y ) +#define GDCM_DO_JOIN( X, Y ) GDCM_DO_JOIN2(X,Y) +#define GDCM_DO_JOIN2( X, Y ) X##Y + +/// The GDCM_JOIN + __LINE__ is needed to create a uniq identifier +#define GDCM_STATIC_ASSERT( B ) \ + typedef ::gdcm::static_assert_test<\ + sizeof(::gdcm::STATIC_ASSERTION_FAILURE< (bool)( B ) >)>\ + GDCM_JOIN(gdcm_static_assert_typedef_, __LINE__) + + +/* Example of use: + * + * template + * struct must_not_be_instantiated + * { + * // this will be triggered if this type is instantiated + * GDCM_STATIC_ASSERT(sizeof(T) == 0); + * }; + * + */ +#endif // GDCMSTATICASSERT_H diff --git a/gdcm/Source/Common/gdcmString.cxx b/gdcm/Source/Common/gdcmString.cxx new file mode 100644 index 0000000..8b17db3 --- /dev/null +++ b/gdcm/Source/Common/gdcmString.cxx @@ -0,0 +1,19 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmString.h" + +namespace gdcm +{ + +} // end namespace gdcm diff --git a/gdcm/Source/Common/gdcmString.h b/gdcm/Source/Common/gdcmString.h new file mode 100644 index 0000000..1af00cf --- /dev/null +++ b/gdcm/Source/Common/gdcmString.h @@ -0,0 +1,137 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMSTRING_H +#define GDCMSTRING_H + +#include "gdcmTypes.h" +#include "gdcmStaticAssert.h" + +namespace gdcm +{ + +/** + * \brief String + * + * \note TDelimiter template parameter is used to separate multiple String (VM1 >) + * TMaxLength is only a hint. Noone actually respect the max length + * TPadChar is the string padding (0 or space) + */ +template +class /*GDCM_EXPORT*/ String : public std::string /* PLEASE do not export me */ +{ + // UI wants \0 for pad character, while ASCII ones wants space char... do not allow anything else + GDCM_STATIC_ASSERT( TPadChar == ' ' || TPadChar == 0 ); + +public: + // typedef are not inherited: + typedef std::string::value_type value_type; + typedef std::string::pointer pointer; + typedef std::string::reference reference; + typedef std::string::const_reference const_reference; + typedef std::string::size_type size_type; + typedef std::string::difference_type difference_type; + typedef std::string::iterator iterator; + typedef std::string::const_iterator const_iterator; + typedef std::string::reverse_iterator reverse_iterator; + typedef std::string::const_reverse_iterator const_reverse_iterator; + + /// String constructors. + String(): std::string() {} + String(const value_type* s): std::string(s) + { + if( size() % 2 ) + { + push_back( TPadChar ); + } + } + String(const value_type* s, size_type n): std::string(s, n) + { + // We are being passed a const char* pointer, so s[n] == 0 (garanteed!) + if( n % 2 ) + { + push_back( TPadChar ); + } + } + String(const std::string& s, size_type pos=0, size_type n=npos): + std::string(s, pos, n) + { + // FIXME: some users might already have padded the string 's' with a trailing \0... + if( size() % 2 ) + { + push_back( TPadChar ); + } + } + + /// WARNING: Trailing \0 might be lost in this operation: + operator const char *() const { return this->c_str(); } + + /// return if string is valid + bool IsValid() const { + // Check Length: + size_type l = size(); + if( l > TMaxLength ) return false; + return true; + } + + gdcm::String Truncate() const { + if( IsValid() ) return *this; + std::string str = *this; // copy + str.resize( TMaxLength ); + return str; + } + + /// Trim function is required to return a std::string object, otherwise we + /// could not create a gdcm::String object with an odd number of bytes... + std::string Trim() const { + std::string str = *this; // copy + std::string::size_type pos1 = str.find_first_not_of(' '); + std::string::size_type pos2 = str.find_last_not_of(' '); + str = str.substr( (pos1 == std::string::npos) ? 0 : pos1, + (pos2 == std::string::npos) ? (str.size() - 1) : (pos2 - pos1 + 1)); + return str; + } + + static std::string Trim(const char *input) { + if( !input ) return ""; + std::string str = input; + std::string::size_type pos1 = str.find_first_not_of(' '); + std::string::size_type pos2 = str.find_last_not_of(' '); + str = str.substr( (pos1 == std::string::npos) ? 0 : pos1, + (pos2 == std::string::npos) ? (str.size() - 1) : (pos2 - pos1 + 1)); + return str; + } + +}; +template +inline std::istream& operator>>(std::istream &is, String &ms) +{ + if(is) + { + std::getline(is, ms, TDelimiter); + // no such thing as std::get where the delim char would be left, so I need to manually add it back... + // hopefully this is the right thing to do (no overhead) + is.putback( TDelimiter ); + } + return is; +} +//template +//String String::Trim() const +//{ +// String s; +// return s; +//} + +} // end namespace gdcm + +#endif //GDCMSTRING_H diff --git a/gdcm/Source/Common/gdcmSubject.cxx b/gdcm/Source/Common/gdcmSubject.cxx new file mode 100644 index 0000000..063f177 --- /dev/null +++ b/gdcm/Source/Common/gdcmSubject.cxx @@ -0,0 +1,256 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmSubject.h" + +#include "gdcmSmartPointer.h" +#include "gdcmCommand.h" +#include "gdcmEvent.h" + +#include + +namespace gdcm +{ +class Observer +{ +public: + Observer(Command* c, + const Event * event, + unsigned long tag) :m_Command(c), + m_Event(event), + m_Tag(tag) + { } + virtual ~Observer() + { delete m_Event; } + SmartPointer m_Command; + const Event * m_Event; + unsigned long m_Tag; +}; + +class SubjectInternals +{ +public: + SubjectInternals() {m_Count = 0;} + ~SubjectInternals(); + unsigned long AddObserver(const Event & event, Command* cmd); + unsigned long AddObserver(const Event & event, Command* cmd) const; + void RemoveObserver(unsigned long tag); + void RemoveAllObservers(); + void InvokeEvent( const Event & event, Subject* self); + void InvokeEvent( const Event & event, const Subject* self); + Command *GetCommand(unsigned long tag); + bool HasObserver(const Event & event) const; + bool PrintObservers(std::ostream& os, std::string indent) const; +private: + std::list m_Observers; + unsigned long m_Count; +}; + +SubjectInternals:: +~SubjectInternals() +{ + for(std::list::iterator i = m_Observers.begin(); + i != m_Observers.end(); ++i) + { + delete (*i); + } +} + + +unsigned long +SubjectInternals:: +AddObserver(const Event & event, + Command* cmd) +{ + Observer* ptr = new Observer(cmd, event.MakeObject(), m_Count); + m_Observers.push_back(ptr); + m_Count++; + return ptr->m_Tag; +} + + +unsigned long +SubjectInternals:: +AddObserver(const Event & event, + Command* cmd) const +{ + Observer* ptr = new Observer(cmd, event.MakeObject(), m_Count); + SubjectInternals * me = const_cast( this ); + me->m_Observers.push_back(ptr); + me->m_Count++; + return ptr->m_Tag; +} + + +void +SubjectInternals:: +RemoveObserver(unsigned long tag) +{ + for(std::list::iterator i = m_Observers.begin(); + i != m_Observers.end(); ++i) + { + if((*i)->m_Tag == tag) + { + delete (*i); + m_Observers.erase(i); + return; + } + } +} + + +void +SubjectInternals:: +RemoveAllObservers() +{ + for(std::list::iterator i = m_Observers.begin(); + i != m_Observers.end(); ++i) + { + delete (*i); + } + m_Observers.clear(); +} + + +void +SubjectInternals:: +InvokeEvent( const Event & event, + Subject* self) +{ + for(std::list::iterator i = m_Observers.begin(); + i != m_Observers.end(); ++i) + { + const Event * e = (*i)->m_Event; + if(e->CheckEvent(&event)) + { + (*i)->m_Command->Execute(self, event); + } + } +} + +void +SubjectInternals:: +InvokeEvent( const Event & event, + const Subject* self) +{ + for(std::list::iterator i = m_Observers.begin(); + i != m_Observers.end(); ++i) + { + const Event * e = (*i)->m_Event; + if(e->CheckEvent(&event)) + { + (*i)->m_Command->Execute(self, event); + } + } +} + + +Command* +SubjectInternals:: +GetCommand(unsigned long tag) +{ + for(std::list::iterator i = m_Observers.begin(); + i != m_Observers.end(); ++i) + { + if ( (*i)->m_Tag == tag) + { + return (*i)->m_Command; + } + } + return 0; +} + +bool +SubjectInternals:: +HasObserver(const Event & event) const +{ + for(std::list::const_iterator i = m_Observers.begin(); + i != m_Observers.end(); ++i) + { + const Event * e = (*i)->m_Event; + if(e->CheckEvent(&event)) + { + return true; + } + } + return false; +} + +bool +SubjectInternals:: +PrintObservers(std::ostream& os, std::string indent) const +{ + if(m_Observers.empty()) + { + return false; + } + + for(std::list::const_iterator i = m_Observers.begin(); + i != m_Observers.end(); ++i) + { + const Event * e = (*i)->m_Event; + const Command* c = (*i)->m_Command; (void)c; + os << indent << e->GetEventName() << "(" /*<< c->GetNameOfClass()*/ << ")\n"; + } + return true; +} + +Subject::Subject():Internals(new SubjectInternals) +{ +} + +Subject::~Subject() +{ + delete Internals; +} + +unsigned long Subject::AddObserver(const Event & event, Command *cmd) +{ + return this->Internals->AddObserver(event,cmd); +} +unsigned long Subject::AddObserver(const Event & event, Command *cmd) const +{ + return this->Internals->AddObserver(event,cmd); +} + +Command* Subject::GetCommand(unsigned long tag) +{ + return this->Internals->GetCommand(tag); +} + +void Subject::InvokeEvent( const Event & event) +{ + this->Internals->InvokeEvent(event,this); +} + +void Subject::InvokeEvent( const Event & event) const +{ + this->Internals->InvokeEvent(event,this); +} + +void Subject::RemoveObserver(unsigned long tag) +{ + this->Internals->RemoveObserver(tag); +} + +void Subject::RemoveAllObservers() +{ + this->Internals->RemoveAllObservers(); +} + +bool Subject::HasObserver( const Event & event ) const +{ + return this->Internals->HasObserver(event); +} + +} diff --git a/gdcm/Source/Common/gdcmSubject.h b/gdcm/Source/Common/gdcmSubject.h new file mode 100644 index 0000000..4eba55f --- /dev/null +++ b/gdcm/Source/Common/gdcmSubject.h @@ -0,0 +1,77 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMSUBJECT_H +#define GDCMSUBJECT_H + +#include "gdcmObject.h" + +namespace gdcm +{ +class Event; +class Command; +class SubjectInternals; +/** + * \brief Subject + * \see Command Event + */ +class GDCM_EXPORT Subject : public Object +{ +public: + Subject(); + ~Subject(); + + /** Allow people to add/remove/invoke observers (callbacks) to any GDCM + * object. This is an implementation of the subject/observer design + * pattern. An observer is added by specifying an event to respond to + * and an gdcm::Command to execute. It returns an unsigned long tag + * which can be used later to remove the event or retrieve the + * command. The memory for the Command becomes the responsibility of + * this object, so don't pass the same instance of a command to two + * different objects */ + unsigned long AddObserver(const Event & event, Command *); + unsigned long AddObserver(const Event & event, Command *) const; + + /** Get the command associated with the given tag. NOTE: This returns + * a pointer to a Command, but it is safe to asign this to a + * Command::Pointer. Since Command inherits from LightObject, at this + * point in the code, only a pointer or a reference to the Command can + * be used. */ + Command* GetCommand(unsigned long tag); + + /** Call Execute on all the Commands observing this event id. */ + void InvokeEvent( const Event & ); + + /** Call Execute on all the Commands observing this event id. + * The actions triggered by this call doesn't modify this object. */ + void InvokeEvent( const Event & ) const; + + /** Remove the observer with this tag value. */ + void RemoveObserver(unsigned long tag); + + /** Remove all observers . */ + void RemoveAllObservers(); + + /** Return true if an observer is registered for this event. */ + bool HasObserver( const Event & event ) const; + +protected: + +private: + SubjectInternals *Internals; +private: +}; + +} // end namespace gdcm + +#endif //GDCMSUBJECT_H diff --git a/gdcm/Source/Common/gdcmSwapCode.cxx b/gdcm/Source/Common/gdcmSwapCode.cxx new file mode 100644 index 0000000..8d442f2 --- /dev/null +++ b/gdcm/Source/Common/gdcmSwapCode.cxx @@ -0,0 +1,69 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmSwapCode.h" +#include + +namespace gdcm +{ + +static const char *SwapCodeStrings[] = { + "Unknown", + "LittleEndian", + "BigEndian", + "BadLittleEndian", + "BadBigEndian", + 0 +}; + +int SwapCode::GetIndex(SwapCode const & sc) +{ + int idx = 0; + switch(sc) + { + case Unknown: + idx = 0; + break; + case LittleEndian: + idx = 1; + break; + case BigEndian: + idx = 2; + break; + case BadLittleEndian: + idx = 3; + break; + case BadBigEndian: + idx = 4; + break; + default: + assert(0 && "Should not happen" ); + } + assert( idx < 5 ); + return idx; +} + +const char* SwapCode::GetSwapCodeString(SwapCode const & sc) +{ + int idx = GetIndex(sc); + return SwapCodeStrings[idx]; +} + +/* +std::ostream& operator<<(std::ostream& os, const SwapCode& sc) +{ + os << SwapCode::GetSwapCodeString(sc); + return os; +} +*/ +} // namespace gdcm diff --git a/gdcm/Source/Common/gdcmSwapCode.h b/gdcm/Source/Common/gdcmSwapCode.h new file mode 100644 index 0000000..8153008 --- /dev/null +++ b/gdcm/Source/Common/gdcmSwapCode.h @@ -0,0 +1,58 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMSWAPCODE_H +#define GDCMSWAPCODE_H + +#include "gdcmTypes.h" +#include + +namespace gdcm +{ + +/** + * \brief SwapCode representation + * \details + */ +class GDCM_EXPORT SwapCode +{ +public: + typedef enum { + Unknown = 0, + LittleEndian = 1234, + BigEndian = 4321, + BadLittleEndian = 3412, + BadBigEndian = 2143 + } SwapCodeType; + + operator SwapCode::SwapCodeType() const { return SwapCodeValue; } + SwapCode(SwapCodeType sc = Unknown):SwapCodeValue(sc) { } + static const char* GetSwapCodeString(SwapCode const & sc); + + friend std::ostream& operator<<(std::ostream& os, const SwapCode& sc); +protected: + static int GetIndex(SwapCode const & sc); + +private: + SwapCodeType SwapCodeValue; +}; +//----------------------------------------------------------------------------- +inline std::ostream& operator<<(std::ostream& os, const SwapCode& sc) +{ + os << SwapCode::GetSwapCodeString(sc); + return os; +} + +} // end namespace gdcm + +#endif //GDCMSWAPCODE_H diff --git a/gdcm/Source/Common/gdcmSwapper.h b/gdcm/Source/Common/gdcmSwapper.h new file mode 100644 index 0000000..1f1f95b --- /dev/null +++ b/gdcm/Source/Common/gdcmSwapper.h @@ -0,0 +1,74 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMSWAPPER_H +#define GDCMSWAPPER_H + +#include "gdcmSwapCode.h" + +namespace gdcm +{ + + +#ifdef GDCM_WORDS_BIGENDIAN +class SwapperDoOp +{ +public: + template static T Swap(T val) {return val;} + template static void SwapArray(T *, unsigned int ) {} +}; + +class SwapperNoOp +{ +public: + template static T Swap(T val); + template + static void SwapArray(T *array, unsigned int n) + { + // TODO: need to unroll loop: + for(unsigned int i = 0; i < n; ++i) + { + array[i] = Swap(array[i]); + } + } +}; +#else +class SwapperNoOp +{ +public: + template static T Swap(T val) {return val;} + template static void SwapArray(T *, size_t ) {} +}; + +class SwapperDoOp +{ +public: + template static T Swap(T val); + template + static void SwapArray(T *array, size_t n) + { + // TODO: need to unroll loop: + for(size_t i = 0; i < n; ++i) + { + array[i] = Swap(array[i]); + } + } +}; +#endif + + +} // end namespace gdcm + +#include "gdcmSwapper.txx" + +#endif //GDCMSWAPPER_H diff --git a/gdcm/Source/Common/gdcmSwapper.txx b/gdcm/Source/Common/gdcmSwapper.txx new file mode 100644 index 0000000..add93b5 --- /dev/null +++ b/gdcm/Source/Common/gdcmSwapper.txx @@ -0,0 +1,197 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMSWAPPER_TXX +#define GDCMSWAPPER_TXX + +#ifdef GDCM_HAVE_BYTESWAP_H +// TODO: not cross platform... +#include +#endif +#include + +#include "gdcmTag.h" + + +namespace gdcm +{ + +#ifdef GDCM_WORDS_BIGENDIAN + template <> inline uint16_t SwapperNoOp::Swap(uint16_t val) + { +#ifdef GDCM_HAVE_BYTESWAP_H + return bswap_16(val); +#else + return (val>>8) | (val<<8); +#endif + } + template <> inline int16_t SwapperNoOp::Swap(int16_t val) + { + return Swap((uint16_t)val); + } + + template <> inline uint32_t SwapperNoOp::Swap(uint32_t val) + { +#ifdef GDCM_HAVE_BYTESWAP_H + return bswap_32(val); +#else + val= ((val<<8)&0xFF00FF00) | ((val>>8)&0x00FF00FF); + val= (val>>16) | (val<<16); + return val; +#endif + } + template <> inline int32_t SwapperNoOp::Swap(int32_t val) + { + return Swap((uint32_t)val); + } + template <> inline float SwapperNoOp::Swap(float val) + { + return Swap((uint32_t)val); + } + template <> inline uint64_t SwapperNoOp::Swap(uint64_t val) + { +#ifdef GDCM_HAVE_BYTESWAP_H + return bswap_64(val); +#else + val= ((val<< 8)&0xFF00FF00FF00FF00ULL) | ((val>> 8)&0x00FF00FF00FF00FFULL); + val= ((val<<16)&0xFFFF0000FFFF0000ULL) | ((val>>16)&0x0000FFFF0000FFFFULL); + return (val>>32) | (val<<32); +#endif + } + template <> inline int64_t SwapperNoOp::Swap(int64_t val) + { + return Swap((uint64_t)val); + } + template <> inline double SwapperNoOp::Swap(double val) + { + return Swap((uint64_t)val); + } + + template <> inline Tag SwapperNoOp::Swap(Tag val) + { + return Tag( Swap(val.GetGroup()), Swap(val.GetElement()) ); + } + + template <> inline void SwapperNoOp::SwapArray(uint8_t *, unsigned int ) {} + + template <> inline void SwapperNoOp::SwapArray(float *array, unsigned int n) + { + switch( sizeof(float) ) + { + case 4: + SwapperNoOp::SwapArray((uint32_t*)array,n); + break; + default: + assert(0); + } + } + + template <> inline void SwapperNoOp::SwapArray(double *array, unsigned int n) + { + switch( sizeof(double) ) + { + case 8: + SwapperNoOp::SwapArray((uint64_t*)array,n); + break; + default: + assert(0); + } + } + +#else + template <> inline uint16_t SwapperDoOp::Swap(uint16_t val) + { +#ifdef GDCM_HAVE_BYTESWAP_H + return bswap_16(val); +#else + return (val>>8) | (val<<8); +#endif + } + template <> inline int16_t SwapperDoOp::Swap(int16_t val) + { + return Swap((uint16_t)val); + } + + template <> inline uint32_t SwapperDoOp::Swap(uint32_t val) + { +#ifdef GDCM_HAVE_BYTESWAP_H + return bswap_32(val); +#else + val= ((val<<8)&0xFF00FF00) | ((val>>8)&0x00FF00FF); + val= (val>>16) | (val<<16); + return val; +#endif + } + template <> inline int32_t SwapperDoOp::Swap(int32_t val) + { + return Swap((uint32_t)val); + } + template <> inline float SwapperDoOp::Swap(float val) + { + return static_cast(Swap((uint32_t)val)); + } + template <> inline uint64_t SwapperDoOp::Swap(uint64_t val) + { +#ifdef GDCM_HAVE_BYTESWAP_H + return bswap_64(val); +#else + val= ((val<< 8)&0xFF00FF00FF00FF00ULL) | ((val>> 8)&0x00FF00FF00FF00FFULL); + val= ((val<<16)&0xFFFF0000FFFF0000ULL) | ((val>>16)&0x0000FFFF0000FFFFULL); + return (val>>32) | (val<<32); +#endif + } + template <> inline int64_t SwapperDoOp::Swap(int64_t val) + { + return Swap((uint64_t)val); + } + template <> inline double SwapperDoOp::Swap(double val) + { + return static_cast(Swap((uint64_t)val)); + } + + template <> inline Tag SwapperDoOp::Swap(Tag val) + { + return Tag( Swap((uint32_t)val.GetElementTag()) ); + } + + template <> inline void SwapperDoOp::SwapArray(uint8_t *, size_t ) {} + + template <> inline void SwapperDoOp::SwapArray(float *array, size_t n) + { + switch( sizeof(float) ) + { + case 4: + SwapperDoOp::SwapArray((uint32_t*)array,n); + break; + default: + assert(0); + } + } + + template <> inline void SwapperDoOp::SwapArray(double *array, size_t n) + { + switch( sizeof(double) ) + { + case 8: + SwapperDoOp::SwapArray((uint64_t*)array,n); + break; + default: + assert(0); + } + } + + +#endif +} // end namespace gdcm + +#endif // GDCMSWAPPER_TXX diff --git a/gdcm/Source/Common/gdcmSystem.cxx b/gdcm/Source/Common/gdcmSystem.cxx new file mode 100644 index 0000000..1f4c863 --- /dev/null +++ b/gdcm/Source/Common/gdcmSystem.cxx @@ -0,0 +1,1069 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmSystem.h" +#include "gdcmTrace.h" +#include "gdcmFilename.h" +#include "gdcmDirectory.h" +#include "gdcmException.h" + +#include +#include + +#include +#include +#include // strspn +#include +#include +#include +#include // PATH_MAX + +// gettimeofday +#ifdef GDCM_HAVE_SYS_TIME_H +#include +#endif +#include +#ifdef GDCM_HAVE_WINSOCK_H +#include +#endif +#include // snprintf +#if defined(GDCM_HAVE_SNPRINTF) +// ok nothing to do +#elif defined(GDCM_HAVE__SNPRINTF) +#define snprintf _snprintf +#endif +#ifdef __APPLE__ +#include +#include +#include +#endif // __APPLE__ + +#if defined(_WIN32) && (defined(_MSC_VER) || defined(__WATCOMC__) ||defined(__BORLANDC__) || defined(__MINGW32__)) +#include +#include +#define _unlink unlink +#else +//#include // we want GNU extensions +#include +#include +#include +#include /* gethostname */ +#include // strncasecmp +#endif + +#if defined(GDCM_HAVE_LANGINFO_H) +#include // nl_langinfo +#endif + +// TODO: WIN32 replacement for C99 stuff: +// #if defined(_WIN32) || defined(_WIN64) +// #define snprintf _snprintf +// #define vsnprintf _vsnprintf +// #define strcasecmp _stricmp +// #define strncasecmp _strnicmp +// #endif + +namespace gdcm +{ + +#if defined(_WIN32) && (defined(_MSC_VER) || defined(__WATCOMC__) || defined(__BORLANDC__) || defined(__MINGW32__)) +inline int Mkdir(const char* dir) +{ + return _mkdir(dir); +} +inline int Rmdir(const char* dir) +{ + return _rmdir(dir); +} +inline const char* Getcwd(char* buf, unsigned int len) +{ + const char* ret = _getcwd(buf, len); + return ret; +} + +#else +inline int Mkdir(const char* dir) +{ + return mkdir(dir, 00777); +} +inline int Rmdir(const char* dir) +{ + return rmdir(dir); +} +inline const char* Getcwd(char* buf, unsigned int len) +{ + const char* ret = getcwd(buf, len); + return ret; +} +#endif + +/* +// 1.14 How can I find a process' executable file? +// http://www.faqs.org/faqs/unix-faq/programmer/faq/ +static std::string Argv0; + +void System::SetArgv0(const char *argv0) +{ + Argv0 = argv0; +//std::cout << "Set:" << Argv0 << std::endl; +} + +const char* System::GetArgv0() +{ +//std::cout << "Get:" << Argv0 << std::endl; + return Argv0.c_str(); +} +*/ + +const char * System::GetCWD() +{ + static char buf[2048]; + const char* cwd = Getcwd(buf, 2048); + return cwd; +/* + std::string path; + if ( cwd ) + { + path = cwd; + } + return path; +*/ +} + +bool System::MakeDirectory(const char *path) +{ + if(System::FileExists(path)) + { + return true; + } + Filename fn(path); + std::string dir = fn.ToUnixSlashes(); + + std::string::size_type pos = dir.find(':'); + if(pos == std::string::npos) + { + pos = 0; + } + std::string topdir; + while((pos = dir.find('/', pos)) != std::string::npos) + { + topdir = dir.substr(0, pos); + Mkdir(topdir.c_str()); + pos++; + } + if(dir[dir.size()-1] == '/') + { + topdir = dir.substr(0, dir.size()); + } + else + { + topdir = dir; + } + if(Mkdir(topdir.c_str()) != 0) + { + // There is a bug in the Borland Run time library which makes MKDIR + // return EACCES when it should return EEXISTS + // if it is some other error besides directory exists + // then return false + if( (errno != EEXIST) +#ifdef __BORLANDC__ + && (errno != EACCES) +#endif + ) + { + return false; + } + } + return true; +} + +// return true if the file exists +bool System::FileExists(const char* filename) +{ +#ifdef _MSC_VER +# define access _access +#endif +#ifndef R_OK +# define R_OK 04 +#endif + if ( access(filename, R_OK) != 0 ) + { + return false; + } + else + { + //assert( !FileIsDirectory(filename) ); + return true; + } +} + +bool System::FileIsDirectory(const char* name) +{ + struct stat fs; + if(stat(name, &fs) == 0) + { +#if _WIN32 + return ((fs.st_mode & _S_IFDIR) != 0); +#else + return S_ISDIR(fs.st_mode); +#endif + } + else + { + return false; + } +} + +bool System::FileIsSymlink(const char* name) +{ +#if defined( _WIN32 ) + (void)name; +#else + struct stat fs; + if(lstat(name, &fs) == 0) + { + return S_ISLNK(fs.st_mode); + } +#endif + return false; +} + +// TODO st_mtimensec +time_t System::FileTime(const char* filename) +{ + struct stat fs; + if(stat(filename, &fs) == 0) + { + // man 2 stat + // time_t st_atime; /* time of last access */ + // time_t st_mtime; /* time of last modification */ + // time_t st_ctime; /* time of last status change */ + return fs.st_mtime; + + // Since kernel 2.5.48, the stat structure supports nanosecond resolution + // for the three file timestamp fields. Glibc exposes the nanosecond com- + // ponent of each field using names either of the form st_atim.tv_nsec, if + // the _BSD_SOURCE or _SVID_SOURCE feature test macro is defined, or of + // the form st_atimensec, if neither of these macros is defined. On file + // systems that do not support sub-second timestamps, these nanosecond + // fields are returned with the value 0. + } + return 0; +} + +const char *System::GetLastSystemError() +{ + int e = errno; + return strerror(e); +} + +bool System::GetPermissions(const char* file, unsigned short& mode) +{ + if ( !file ) + { + return false; + } + + struct stat st; + if ( stat(file, &st) < 0 ) + { + return false; + } + mode = (short)st.st_mode; + return true; +} + +bool System::SetPermissions(const char* file, unsigned short mode) +{ + if ( !file ) + { + return false; + } + if ( !System::FileExists(file) ) + { + return false; + } + if ( chmod(file, mode) < 0 ) + { + return false; + } + + return true; +} + +bool System::RemoveFile(const char* source) +{ +#ifdef _WIN32 + unsigned short mode; + if ( !System::GetPermissions(source, mode) ) + { + return false; + } + /* Win32 unlink is stupid --- it fails if the file is read-only */ + System::SetPermissions(source, S_IWRITE); +#endif + bool res = unlink(source) != 0 ? false : true; +#ifdef _WIN32 + if ( !res ) + { + System::SetPermissions(source, mode); + } +#endif + return res; +} + +// RemoveDirectory is a WIN32 function, use different name +bool System::DeleteDirectory(const char *source) +{ + unsigned short mode; + if(System::GetPermissions(source, mode)) + { +#if defined(_WIN32) && !defined(__CYGWIN__) + mode |= S_IWRITE; +#else + mode |= S_IWUSR; +#endif + System::SetPermissions(source, mode); + } + + Directory dir; + unsigned int numfiles = dir.Load(source, false); + (void)numfiles; + Directory::FilenamesType const & files = dir.GetFilenames(); + for ( Directory::FilenamesType::const_iterator it = files.begin(); + it != files.end(); ++it ) + { + const char *filename = it->c_str(); + if( System::FileIsDirectory(filename) && + !System::FileIsSymlink(filename) ) + { + if (!System::DeleteDirectory(filename)) + { + return false; + } + } + else + { + if(!System::RemoveFile(filename)) + { + return false; + } + } + } + return Rmdir(source) == 0; +} + +// return size of file; also returns zero if no file exists +size_t System::FileSize(const char* filename) +{ +#if 0 + All of these system calls return a stat structure, which contains the + following fields: + + struct stat { + dev_t st_dev; /* ID of device containing file */ + ino_t st_ino; /* inode number */ + mode_t st_mode; /* protection */ + nlink_t st_nlink; /* number of hard links */ + uid_t st_uid; /* user ID of owner */ + gid_t st_gid; /* group ID of owner */ + dev_t st_rdev; /* device ID (if special file) */ + off_t st_size; /* total size, in bytes */ + blksize_t st_blksize; /* blocksize for filesystem I/O */ + blkcnt_t st_blocks; /* number of blocks allocated */ + time_t st_atime; /* time of last access */ + time_t st_mtime; /* time of last modification */ + time_t st_ctime; /* time of last status change */ + }; +#endif + struct stat fs; + if (stat(filename, &fs) != 0) + { + return 0; + } + off_t size = fs.st_size; + size_t size2 = size; + // off_t can be larger than size_t + if( size != (off_t)size2 ) return 0; + return size2; +} + +#if 0 +const char *System::GetCurrentDataDirectory() +{ +#ifdef _WIN32 + static char path[MAX_PATH]; + gdcm::Filename fn( GetCurrentProcessFileName() ); + if ( !fn.IsEmpty() ) + { + std::string str = fn.GetPath(); + str += "/../" GDCM_INSTALL_DATA_DIR; + strcpy(path, str.c_str()); + return path; + } +#else + + static char path[PATH_MAX]; + +#ifdef __APPLE__ + Boolean success = false; + CFURLRef pathURL = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle()); + if (pathURL != NULL) + { + success = CFURLGetFileSystemRepresentation(pathURL, true /*resolveAgainstBase*/, (unsigned char*) path, PATH_MAX); + CFRelease(pathURL); + } + if (success) + { + strncat(path, "/" GDCM_INSTALL_DATA_DIR, PATH_MAX); + return path; + } +#endif + + gdcm::Filename fn( GetCurrentProcessFileName() ); + if ( !fn.IsEmpty() ) + { + std::string str = fn.GetPath(); + str += "/../" GDCM_INSTALL_DATA_DIR; + strcpy(path, str.c_str()); + return path; + } +#endif + return 0; +} +#endif + +/* + * TODO: + * check cygwin + * check beos : get_next_image_info + * check solaris + * check hpux + * check os2: DosGetInfoBlocks / DosQueryModuleName + * check macosx : + * ProcessSerialNumber psn = {kNoProcess, kCurrentProcess}; + * GetProcessInformation -> FSMakeFSSpec + * ... + */ +const char *System::GetCurrentProcessFileName() +{ +#ifdef _WIN32 + static char buf[MAX_PATH]; + if ( ::GetModuleFileName(0, buf, sizeof(buf)) ) + { + return buf; + } +#elif defined(__APPLE__) + // _NSGetExecutablePath() + static char buf[PATH_MAX]; + Boolean success = false; + CFURLRef pathURL = CFBundleCopyExecutableURL(CFBundleGetMainBundle()); + if ( pathURL) + { + success = CFURLGetFileSystemRepresentation(pathURL, true /*resolveAgainstBase*/, (unsigned char*) buf, PATH_MAX); + CFRelease(pathURL); + } + if (success) + { + return buf; + } +#elif defined (__SVR4) && defined (__sun) + // solaris + const char *ret = getexecname(); + if( ret ) return ret; +//#elif defined(__NetBSD__) +// static char path[PATH_MAX]; +// if ( readlink ("/proc/curproc/exe", path, sizeof(path)) > 0) +// { +// return path; +// } +#elif defined(__DragonFly__) || defined(__OpenBSD__) || defined(__FreeBSD__) + static char path[PATH_MAX]; + if ( readlink ("/proc/curproc/file", path, sizeof(path)) > 0) + { + return path; + } +#elif defined(__linux__) + static char path[PATH_MAX]; + if ( readlink ("/proc/self/exe", path, sizeof(path)) > 0) // Technically 0 is not an error, but that would mean + // 0 byte were copied ... thus considered it as an error + { + return path; + } +#else + gdcmErrorMacro( "missing implementation" ); +#endif + return 0; +} + +#ifdef __USE_GNU +static void where_am_i() {} +#endif + +const char *System::GetCurrentModuleFileName() +{ +#ifdef __USE_GNU + static char path[PATH_MAX]; + Dl_info info; + if (dladdr( (void*)&where_am_i, &info ) == 0) + { + size_t len = strlen(info.dli_fname); + if( len >= PATH_MAX ) return 0; // throw error ? + // else + strcpy(path,info.dli_fname); + return path; + } +#elif defined(_WIN32) + // GetModuleFileName works the same on Win32 for library AFAIK + return System::GetCurrentProcessFileName(); +#endif + + return 0; +} + +const char *System::GetCurrentResourcesDirectory() +{ +#ifdef __APPLE__ + static char path[PATH_MAX]; + Boolean success = false; + CFURLRef pathURL = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle()); + if (pathURL != NULL) + { + success = CFURLGetFileSystemRepresentation(pathURL, true /*resolveAgainstBase*/, (unsigned char*) path, PATH_MAX); + CFRelease(pathURL); + } + if (success) + { + strncat(path, "/" GDCM_INSTALL_DATA_DIR, PATH_MAX); + return path; + } +#endif + // Is there such beast on *any* other system but APPLE ? + return 0; +} + +/** + * \brief Encode the mac address on a fixed length string of 15 characters. + * we save space this way. + */ +inline int getlastdigit(unsigned char *data, unsigned long size) +{ + int extended, carry = 0; + for(unsigned int i=0;i= 0 && carry < 10 ); + return carry; +} + +size_t System::EncodeBytes(char *out, const unsigned char *data, int size) +{ + bool zero = false; + int res; + std::string sres; + unsigned char buffer[32]; + unsigned char *addr = buffer; + memcpy(addr, data, size); + while(!zero) + { + res = getlastdigit(addr, size); + const char v = (char)('0' + res); + sres.insert(sres.begin(), v); + zero = true; + for(int i = 0; i < size; ++i) + { + zero = zero && (addr[i] == 0); + } + } + + //return sres; + strcpy(out, sres.c_str()); //, sres.size() ); + return sres.size(); +} + +#if defined(_WIN32) && !defined(GDCM_HAVE_GETTIMEOFDAY) +#include + +// http://www.openasthra.com/c-tidbits/gettimeofday-function-for-windows/ +// http://www.sisvia.com/blog/?p=24 +// -> srand + gettimeofday +// http://csl.sublevel3.org/c++/ +static int gettimeofday2(struct timeval *tv, struct timezone *tz) +{ + FILETIME ft; + const uint64_t c1 = 27111902; + const uint64_t c2 = 3577643008UL; + const uint64_t OFFSET = (c1 << 32) + c2; + uint64_t filetime = 0; + GetSystemTimeAsFileTime(&ft); + + filetime |= ft.dwHighDateTime; + filetime <<= 32; + filetime |= ft.dwLowDateTime; + filetime -= OFFSET; + + tv->tv_sec = (long)(filetime / 10000000); /* seconds since epoch */ + tv->tv_usec = (uint32_t)((filetime % 10000000) / 10); + + return 0; +} +#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS) + #define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64 +#else + #define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL +#endif + +//struct timezone +//{ +// int tz_minuteswest; /* minutes W of Greenwich */ +// int tz_dsttime; /* type of dst correction */ +//}; + +int gettimeofday(struct timeval *tv, struct timezone *tz) +{ +/* + The use of the timezone structure is obsolete; the tz argument should + normally be specified as NULL. The tz_dsttime field has never been + used under Linux; it has not been and will not be supported by libc or + glibc. Each and every occurrence of this field in the kernel source + (other than the declaration) is a bug. Thus, the following is purely of + historic interest. +*/ + assert( tz == 0 ); + FILETIME ft; + unsigned __int64 tmpres = 0; + //static int tzflag; + + if (NULL != tv) + { + GetSystemTimeAsFileTime(&ft); + + tmpres |= ft.dwHighDateTime; + tmpres <<= 32; + tmpres |= ft.dwLowDateTime; + + /*converting file time to unix epoch*/ + tmpres /= 10; /*convert into microseconds*/ + tmpres -= DELTA_EPOCH_IN_MICROSECS; + tv->tv_sec = (long)(tmpres / 1000000UL); + tv->tv_usec = (long)(tmpres % 1000000UL); + } + +// if (NULL != tz) +// { +// if (!tzflag) +// { +// _tzset(); +// tzflag++; +// } +// tz->tz_minuteswest = _timezone / 60; +// tz->tz_dsttime = _daylight; +// } + + return 0; +} +#endif + +/** + Implementation note. We internally use mktime which seems to be quite relaxed when it + comes to invalid date. It handles : + "17890714172557"; + "19891714172557"; + "19890014172557"; + While the DICOM PS 3.5-2008 would prohibit them. + I leave it this way so that we correctly read in /almost/ valid date. What we write out is + always valid anyway which is what is important. +*/ +bool System::ParseDateTime(time_t &timep, const char date[22]) +{ + long milliseconds; + return ParseDateTime(timep, milliseconds, date); +} + +bool System::ParseDateTime(time_t &timep, long &milliseconds, const char date[22]) +{ + if(!date) return false; + size_t len = strlen(date); + if( len < 4 ) return false; // need at least the full year + if( len > 21 ) return false; + + struct tm ptm; + // No such thing as strptime on some st*$^% platform +#if defined(GDCM_HAVE_STRPTIME) && 0 + char *ptr1 = strptime(date, "%Y%m%d%H%M%S", &ptm); + if( ptr1 != date + 14 ) + { + // We stopped parsing the string at some point, assume this is an error + return false; + } +#else + // instead write our own: + int year, mon, day, hour, min, sec, n; + if ((n = sscanf(date, "%4d%2d%2d%2d%2d%2d", + &year, &mon, &day, &hour, &min, &sec)) >= 1) + { + switch (n) + { + case 1: mon = 1; + case 2: day = 1; + case 3: hour = 0; + case 4: min = 0; + case 5: sec = 0; + } + ptm.tm_year = year - 1900; + if( mon < 1 || mon > 12 ) return false; + ptm.tm_mon = mon - 1; + if( day < 1 || day > 31 ) return false; + ptm.tm_mday = day; + if( hour > 24 ) return false; + ptm.tm_hour = hour; + if( min > 60 ) return false; + ptm.tm_min = min; + if( sec > 60 ) return false; + ptm.tm_sec = sec; + ptm.tm_wday = -1; + ptm.tm_yday = -1; + ptm.tm_isdst = -1; + } + else + { + return false; + } +#endif + timep = mktime(&ptm); + if( timep == (time_t)-1) return false; + + milliseconds = 0; + if( len > 14 ) // more data to process + { + const char *ptr = date + 14; + if( *ptr != '.' ) return false; + ++ptr; + if( !*ptr || sscanf( ptr, "%06ld", &milliseconds ) != 1 ) + { + // Could not parse milliseconds but date looks ok, should I return false anyway ? + // -> yes this is an error ! + return false; + } + } + + return true; +} + +const char *System::GetTimezoneOffsetFromUTC() +{ + static std::string buffer; + char outstr[10]; + time_t t = time(NULL); + struct tm *tmp = localtime(&t); + size_t l = strftime(outstr, sizeof(outstr), "%z", tmp); + assert( l == 5 ); (void)l; + buffer = outstr; + return buffer.c_str(); +} + +bool System::FormatDateTime(char date[22], time_t timep, long milliseconds) +{ + // \precondition + if( !(milliseconds >= 0 && milliseconds < 1000000) ) + { + return false; + } + + // YYYYMMDDHHMMSS.FFFFFF&ZZXX + if(!date) + { + return false; + } + const size_t maxsize = 40; + char tmp[maxsize]; + // Obtain the time of day, and convert it to a tm struct. + struct tm *ptm = localtime (&timep); + if(!ptm) + { + return false; + } + // Format the date and time, down to a single second. + size_t ret = strftime (tmp, sizeof (tmp), "%Y%m%d%H%M%S", ptm); + assert( ret == 14 ); + if( ret == 0 || ret >= maxsize ) + { + return false; + } + + // Add milliseconds + const size_t maxsizall = 22; + const int ret2 = snprintf(date,maxsizall,"%s.%06ld",tmp,milliseconds); + if( ret2 < 0 ) return false; + if( (size_t)ret2 >= maxsizall ) + { + return false; + } + + // Ok ! + return true; +} + +bool System::GetCurrentDateTime(char date[22]) +{ + long milliseconds; + time_t timep; + +#if 0 + The functions gettimeofday() and settimeofday() can get and set the + time as well as a timezone. The tv argument is a struct timeval (as + specified in ): + + struct timeval { + time_t tv_sec; /* seconds */ + suseconds_t tv_usec; /* microseconds */ + }; + + and gives the number of seconds and microseconds since the Epoch (see + time(2)). The tz argument is a struct timezone: + + struct timezone { + int tz_minuteswest; /* minutes west of Greenwich */ + int tz_dsttime; /* type of DST correction */ + }; + + If either tv or tz is NULL, the corresponding structure is not set or + returned. + + The use of the timezone structure is obsolete; the tz argument should + normally be specified as NULL. The tz_dsttime field has never been + used under Linux; it has not been and will not be supported by libc or + glibc. Each and every occurrence of this field in the kernel source + (other than the declaration) is a bug. Thus, the following is purely of + historic interest. +#endif + + // Apparently suseconds_t is defined as long on linux system... why would this be signed ? + + struct timeval tv; + gettimeofday (&tv, NULL); + timep = tv.tv_sec; + // A concatenated date-time character string in the format: + // YYYYMMDDHHMMSS.FFFFFF&ZZXX + // The components of this string, from left to right, are YYYY = Year, MM = + // Month, DD = Day, HH = Hour (range "00" - "23"), MM = Minute (range "00" - + // "59"), SS = Second (range "00" - "60"). + // FFFFFF = Fractional Second contains a fractional part of a second as small + // as 1 millionth of a second (range 000000 - 999999). + assert( tv.tv_usec >= 0 && tv.tv_usec < 1000000 ); + milliseconds = tv.tv_usec; + + return FormatDateTime(date, timep, milliseconds); +} + +int System::StrNCaseCmp(const char *s1, const char *s2, size_t n) +{ +#if defined(GDCM_HAVE_STRNCASECMP) + return strncasecmp(s1,s2,n); +#elif defined(GDCM_HAVE__STRNICMP) + return _strnicmp(s1,s2,n); +#else // default implementation +#error + assert( n ); // TODO + while (--n && *s1 && (tolower(*s1) == tolower(*s2))) + { + s1++; + s2++; + } + + return tolower(*s1) - tolower(*s2); +#endif +} + +int System::StrCaseCmp(const char *s1, const char *s2) +{ +#if defined(GDCM_HAVE_STRCASECMP) + return strcasecmp(s1,s2); +#elif defined(GDCM_HAVE__STRNICMP) + return _stricmp(s1,s2); +#else // default implementation +#error + while (*s1 && (tolower(*s1) == tolower(*s2))) + { + s1++; + s2++; + } + + return tolower(*s1) - tolower(*s2); +#endif +} + +bool System::GetHostName(char name[255]) +{ +// http://msdn.microsoft.com/en-us/library/ms738527.aspx +// WSANOTINITIALISED A successful WSAStartup call must occur before using this function. +#if _WIN32 + // Get the hostname + WORD wVersionRequested; + WSADATA wsaData; + wVersionRequested = MAKEWORD(2,0); + + if ( WSAStartup( wVersionRequested, &wsaData ) == 0 ) + { + bool ret = false; + if( gethostname(name,255) == 0 ) + { + ret = true; + } + else + { + *name = 0; + } + WSACleanup( ); + return ret; + } +#else + if( gethostname(name, 255) == 0 ) + { + return true; + } +#endif + // If reach here gethostname failed, uninit name just in case + *name = 0; + return false; +} + +char *System::StrTokR(char *str, const char *delim, char **nextp) +{ +#if 1 + // http://groups.google.com/group/comp.lang.c/msg/2ab1ecbb86646684 + // PD -> http://groups.google.com/group/comp.lang.c/msg/7c7b39328fefab9c + char *ret; + + if (str == NULL) + { + str = *nextp; + } + + str += strspn(str, delim); + + if (*str == '\0') + { + return NULL; + } + + ret = str; + + str += strcspn(str, delim); + + if (*str) + { + *str++ = '\0'; + } + + *nextp = str; + + return ret; +#else + return strtok_r(str,delim,nextp); +#endif +} + +char *System::StrSep(char **sp, const char *sep) +{ + // http://unixpapa.com/incnote/string.html + // http://stackoverflow.com/questions/8512958/is-there-a-windows-variant-of-strsep +#if 1 + char *p, *s; + if (sp == NULL || *sp == NULL || **sp == '\0') return NULL; + s = *sp; + p = s + strcspn(s, sep); + if (*p != '\0') *p++ = '\0'; + *sp = p; + return s; +#else + return strsep(sp, sep); +#endif +} + +struct CharsetAliasType +{ + const char *alias; + const char *name; +}; + +#if defined(_WIN32) +static const char *CharsetAliasToName(const char *alias) +{ + assert( alias ); + //gdcmDebugMacro( alias ); + // http://msdn.microsoft.com/en-us/library/windows/desktop/dd317756(v=vs.85).aspx + // 1252 windows-1252 ANSI Latin 1; Western European (Windows) + static CharsetAliasType aliases[] = { + { "CP1252", "ISO-8859-1" }, // mingw + debian/6.0 + { NULL, NULL }, + }; + for( CharsetAliasType *a = aliases; a->alias; a++) + { + if (strcmp (a->alias, alias) == 0) + { + return a->name; + } + } + // We need to tell the user... + return NULL; +} +#endif //_WIN32 + +const char *System::GetLocaleCharset() +{ + const char *codeset = NULL; +#if defined(GDCM_HAVE_NL_LANGINFO) + //setlocale (LC_CTYPE, NULL); + /* According to documentation nl_langinfo needs : + setlocale(3) needs to be executed with proper arguments before. + However even if CODESET only required LC_TYPE only setting LC_TYPE is not + enough to get it working on a debian/6.0 system within c++ + so instead call setlocale on LC_ALL to fix it. + */ + char *oldlocale = strdup(setlocale(LC_ALL, "")); + // TODO: what if setlocale return NULL ? + codeset = nl_langinfo (CODESET); + setlocale(LC_ALL, oldlocale); + free(oldlocale); +#endif // GDCM_HAVE_NL_LANGINFO + +#if defined(_WIN32) +#if 0 + char buf1[128]; + char buf2[128]; + const char *codeset1; + const char *codeset2; + codeset1 = buf1; + codeset2 = buf2; + sprintf(buf1, "CP%d", GetConsoleCP()); + sprintf(buf2, "CP%d", GetConsoleOutputCP()); + + // BUG: both returns 'CP437' on debian + mingw32... + // instead prefer GetACP() call: +#endif + static char buf[2+10+1]; // 2 char, 10 bytes + 0 + // GetACP: Retrieves the current Windows ANSI code page identifier for the + // operating system. + sprintf (buf, "CP%u", GetACP ()); + codeset = CharsetAliasToName(buf); +#endif + + // warning ANSI_X3.4-1968 means ASCII + return codeset; +} + +} // end namespace gdcm diff --git a/gdcm/Source/Common/gdcmSystem.h b/gdcm/Source/Common/gdcmSystem.h new file mode 100644 index 0000000..e43f099 --- /dev/null +++ b/gdcm/Source/Common/gdcmSystem.h @@ -0,0 +1,144 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMSYSTEM_H +#define GDCMSYSTEM_H + +#include "gdcmTypes.h" + +namespace gdcm +{ + +/** + * \brief Class to do system operation + * \details OS independent functionalities + */ +class GDCM_EXPORT System +{ +public: + /// Create a directory name path + static bool MakeDirectory(const char *path); + /// Check whether the specified file exist on the sytem + static bool FileExists(const char* filename); + /// Check whether the file specified is a directory: + static bool FileIsDirectory(const char* name); + /// Check whether name is a symlink + static bool FileIsSymlink(const char* name); + /// remove a file named source + static bool RemoveFile(const char* source); + /// remove a directory named source + static bool DeleteDirectory(const char *source); + + /// Return the last error + static const char *GetLastSystemError(); + + /// Return the filesize. 0 if file does not exist. + /// \warning you need to use FileExists to differentiate between empty file and missing file. + /// \warning for very large size file and on system where size_t is not appropriate to store + /// off_t value the function will return 0. + static size_t FileSize(const char* filename); + + /// Return the time of last modification of file + /// 0 if the file does not exist + static time_t FileTime(const char* filename); + + /// Return the directory the current process (executable) is located: + /// NOT THREAD SAFE + static const char *GetCurrentProcessFileName(); + + /// Return the directory the current module is located: + /// NOT THREAD SAFE + static const char *GetCurrentModuleFileName(); + + /// On some system (Apple) return the path to the current bundled 'Resources' directory + /// NOT THREAD SAFE + static const char *GetCurrentResourcesDirectory(); + + // TODO some system calls + // Chdir + // copy a file + + /// Retrieve the hostname, only the first 255 byte are copyied. + /// This may come handy to specify the Station Name + static bool GetHostName(char hostname[255]); + + // In the following the size '22' is explicitly listed. You need to pass in + // at least 22bytes of array. If the string is an output it will be + // automatically padded ( array[21] == 0 ) for you. + // Those functions: GetCurrentDateTime / FormatDateTime / ParseDateTime do + // not return the &YYZZ part of the DT structure as defined in DICOM PS 3.5 - + // 2008 In this case it is simple to split the date[22] into a DA and TM + // structure + + /// Return the current data time, and format it as ASCII text. + /// This is simply a call to gettimeofday + FormatDateTime, since WIN32 do not have an + /// implementation for gettimeofday, this is more portable. + /// The call time(0) is not precise for our resolution + static bool GetCurrentDateTime(char date[22]); + + /// format as ASCII text a time_t with milliseconds + /// See VR::DT from DICOM PS 3.5 + /// milliseconds is in the range [0, 999999] + static bool FormatDateTime(char date[22], time_t t, long milliseconds = 0); + + /// Parse a date stored as ASCII text into a time_t structured (discard millisecond if any) + static bool ParseDateTime(time_t &timep, const char date[22]); + + /// Parse a date stored as ASCII text into a time_t structured and millisecond + /// \see FormatDateTime + static bool ParseDateTime(time_t &timep, long &milliseconds, const char date[22]); + + /// Return the value for Timezone Offset From UTC as string. + /// \warning not thread safe + static const char *GetTimezoneOffsetFromUTC(); + + /// Used internally by the UIDGenerator class to convert a uuid tape to a + /// DICOM VR:UI type + static size_t EncodeBytes(char *out, const unsigned char *data, int size); + + /// consistent func for C99 spec of strcasecmp/strncasecmp + static int StrCaseCmp(const char *s1, const char *s2); + /// \pre n != 0 + static int StrNCaseCmp(const char *s1, const char *s2, size_t n); + + /// Return current working directory + /// Warning: if current working path is too long (>2048 bytes) the call will fail + /// and call will return NULL + /// NOT THREAD SAFE + static const char * GetCWD(); + + /// strtok_r + static char *StrTokR(char *ptr, const char *sep, char **end); + + /// strsep + static char *StrSep(char **stringp, const char *delim); + + /// return `locale charmap` + static const char *GetLocaleCharset(); + + /// NOT THREAD SAFE +/* + static void SetArgv0(const char *); + static const char* GetArgv0(); +*/ + +protected: + static bool GetPermissions(const char* file, unsigned short& mode); + static bool SetPermissions(const char* file, unsigned short mode); + +private: +}; + +} // end namespace gdcm + +#endif //GDCMSYSTEM_H diff --git a/gdcm/Source/Common/gdcmTerminal.cxx b/gdcm/Source/Common/gdcmTerminal.cxx new file mode 100644 index 0000000..8a8b8ca --- /dev/null +++ b/gdcm/Source/Common/gdcmTerminal.cxx @@ -0,0 +1,209 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmTerminal.h" + +#include +#include +#include + +#ifdef WIN32 +#define WIN32_LEAN_AND_MEAN +#include /* SetConsoleTextAttribute */ +#endif + +// FIXME on ming32 a couple of stuff are not defined: +#ifndef COMMON_LVB_REVERSE_VIDEO +#define COMMON_LVB_REVERSE_VIDEO 0x4000 +#endif +#ifndef COMMON_LVB_UNDERSCORE +#define COMMON_LVB_UNDERSCORE 0x8000 +#endif + +namespace gdcm +{ + +namespace terminal +{ + +class ConsoleImp +{ +private: +// console implementation details: +#ifdef WIN32 + HANDLE hConsoleHandle; + CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; + WORD wNormalAttributes; +#endif +// vt100 implementation details: + int attribute; + int fgcolor; + int bgcolor; +public: + ConsoleImp() + { +#ifdef WIN32 + hConsoleHandle = GetStdHandle(STD_OUTPUT_HANDLE); + GetConsoleScreenBufferInfo(hConsoleHandle, &ConsoleInfo); + wNormalAttributes = ConsoleInfo.wAttributes; +#endif + attribute = fgcolor = bgcolor = 9; + } + ~ConsoleImp() + { +#ifdef WIN32 + SetConsoleTextAttribute(hConsoleHandle, wNormalAttributes); + } + WORD get_attributes() { + GetConsoleScreenBufferInfo(hConsoleHandle, &ConsoleInfo); + return ConsoleInfo.wAttributes; +#endif + } + + void setattribute(int att) { attribute = att; } + void setfgcolor(int col) { fgcolor = col; } + void setbgcolor(int col) { bgcolor = col; } + //std::string resettextcolor() const { + // char command[13]; + // sprintf(command, "%c[%d;%d;%dm", 0x1B, 0, 0, 0); + // return command; + //} + std::string textcolor() const { + char command[16]; + int n = sprintf(command, "%c[%d;%d;%dm", 0x1B, attribute, fgcolor + 30, bgcolor + 40); + assert( n < 16 ); (void)n; + return command; + } + void set_attributes(int color) { +#ifdef WIN32 + static const int colors[8] = { 0, 4, 2, 6, 1, 5, 3, 7 }; + WORD wAttributes; + + wAttributes = get_attributes(); + // http://swapoff.org/browser/todo/trunk/util/Terminal.cc + // http://www.koders.com/cpp/fid5D5965EDC640274BE13A63CFEC649FA76F65A59D.aspx + // http://cvs.4suite.org/viewcvs/4Suite/Ft/Lib/Terminal.py?rev=1.1&content-type=text/vnd.viewcvs-markup + // http://linuxgazette.net/issue65/padala.html + // https://svn.linux.ncsu.edu/svn/cls/branches/ncsu-gdm/pre-gdm-2.14/Xdefaults.old + // http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/475116 + // http://techpubs.sgi.com/library/tpl/cgi-bin/getdoc.cgi?coll=linux&db=man&fname=/usr/share/catman/man4/console_codes.4.html + // http://www.columbia.edu/kermit/ftp/k95/terminal.txt + // http://www.codeproject.com/KB/cpp/Colored_Conslole_Messages.aspx + // http://www.betarun.com/Pages/ConsoleColor/ + // http://support.microsoft.com/?scid=kb%3Ben-us%3B319883&x=20&y=8 + //http://www.dreamincode.net/code/snippet921.htm + //http://www.codeproject.com/KB/cpp/Colored_Conslole_Messages.aspx + //http://fabrizio.net/ccode/Old/20070427/Console.cpp + //http://www.opensource.apple.com/darwinsource/10.4.8.x86/tcsh-46/tcsh/win32/console.c + //http://msdn2.microsoft.com/en-us/library/ms682088(VS.85).aspx + // + { + int n = color; + + if (n == 0) // Normal (default) + wAttributes = wNormalAttributes; + else if (n == 1) // Bold + wAttributes |= FOREGROUND_INTENSITY; + else if (n == 4) // Underlined + wAttributes |= COMMON_LVB_UNDERSCORE; + else if (n == 5) // Blink (appears as BACKGROUND_INTENSITY) + wAttributes |= BACKGROUND_INTENSITY; + else if (n == 7) // Inverse + wAttributes |= COMMON_LVB_REVERSE_VIDEO; + else if (n == 21) // Not bold + wAttributes &= ~FOREGROUND_INTENSITY; + else if (n == 24) // Not underlined + wAttributes &= ~COMMON_LVB_UNDERSCORE; + else if (n == 25) // Steady (not blinking) + wAttributes &= ~BACKGROUND_INTENSITY; + else if (n == 27) // Positive (not inverse) + wAttributes &= ~COMMON_LVB_REVERSE_VIDEO; + else if (30 <= n && n <= 37) // Set foreground color + wAttributes = (wAttributes & ~0x0007) | colors[n - 30]; + else if (n == 39) // Set foreground color to default + wAttributes = (wAttributes & ~0x0007) | (wNormalAttributes & 0x0007); + else if (40 <= n && n <= 47) // Set background color + wAttributes = (wAttributes & ~0x0070) | (colors[n - 40] << 4); + else if (n == 49) // Set background color to default + wAttributes = (wAttributes & ~0x0070) | (wNormalAttributes & 0x0070); + else if (90 <= n && n <= 97) // Set foreground color (bright) + wAttributes = (wAttributes & ~0x0007) | colors[n - 90] + | FOREGROUND_INTENSITY; + else if (100 <= n && n <= 107) // Set background color (bright) + wAttributes = (wAttributes & ~0x0070) | (colors[n - 100] << 4) + | BACKGROUND_INTENSITY; + else // (default) + wAttributes = wNormalAttributes; + } + + // Though Windows' console supports COMMON_LVB_REVERSE_VIDEO, + // it seems to be buggy. So we must simulate it. + if (wAttributes & COMMON_LVB_REVERSE_VIDEO) + wAttributes = (wAttributes & COMMON_LVB_UNDERSCORE) + | ((wAttributes & 0x00f0) >> 4) | ((wAttributes & 0x000f) << 4); + SetConsoleTextAttribute(hConsoleHandle, wAttributes); +#else + (void)color; +#endif //WIN32 +} + +}; +// http://linuxgazette.net/issue65/padala.html +// The Color Code: [{attr};{fg};{bg}m + +static ConsoleImp cimp; +static Mode mode; + +void setmode( Mode m) +{ + mode = m; +} +std::string setfgcolor( Color c) +{ + if( mode == VT100 ) + { + cimp.setfgcolor(c); + return cimp.textcolor(); + } + else if( mode == CONSOLE ) + cimp.set_attributes(30+c); + return ""; +} +std::string setbgcolor( Color c ) +{ + if( mode == VT100 ) + { + cimp.setbgcolor(c); + return cimp.textcolor(); + } + else if( mode == CONSOLE ) + cimp.set_attributes(40+c); + return ""; +} + +std::string setattribute( Attribute att ) +{ + if( mode == VT100 ) + { + cimp.setattribute(att); + return cimp.textcolor(); + } + else if( mode == CONSOLE ) + cimp.set_attributes(att); + return ""; +} + +} + + +} // end namespace gdcm diff --git a/gdcm/Source/Common/gdcmTerminal.h b/gdcm/Source/Common/gdcmTerminal.h new file mode 100644 index 0000000..51794e6 --- /dev/null +++ b/gdcm/Source/Common/gdcmTerminal.h @@ -0,0 +1,66 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMTERMINAL_H +#define GDCMTERMINAL_H + +#include "gdcmTypes.h" + + +namespace gdcm +{ +/** + * \brief Class for Terminal + * Allow one to print in color in a shell + * - support VT100 compatible shell + * - win32 console + */ +//----------------------------------------------------------------------------- + +namespace terminal +{ + typedef enum + { + CONSOLE = 0, + VT100 + } Mode; + typedef enum + { + black = 0, + red, + green, + yellow, // brown ?? + blue, + magenta, + cyan, + white + } Color; + typedef enum + { + reset = 0, + bright = 1, // bold + dim = 2, + underline = 3, + blink = 5, + reverse = 7, + hidden = 8 + } Attribute; + GDCM_EXPORT std::string setattribute( Attribute att ); + GDCM_EXPORT std::string setfgcolor( Color c ); + GDCM_EXPORT std::string setbgcolor( Color c ); + GDCM_EXPORT void setmode( Mode m); +} + +} // end namespace gdcm +//----------------------------------------------------------------------------- +#endif //GDCMTERMINAL_H diff --git a/gdcm/Source/Common/gdcmTestDriver.h b/gdcm/Source/Common/gdcmTestDriver.h new file mode 100644 index 0000000..453f7ef --- /dev/null +++ b/gdcm/Source/Common/gdcmTestDriver.h @@ -0,0 +1,24 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +// This header is included by all the C++ test drivers in GDCM. +#ifndef GDCMTESTDRIVER_H +#define GDCMTESTDRIVER_H + +// CREATE_TEST_SOURCELIST supports the flag EXTRA_INCLUDE but only one per call. +// So there is no way to specify we want to include two files... instead +// gather the #include in a single file and include that one... +#include // C setlocale() +#include // C++ locale + +#endif // GDCMTESTDRIVER_H diff --git a/gdcm/Source/Common/gdcmTesting.cxx b/gdcm/Source/Common/gdcmTesting.cxx new file mode 100644 index 0000000..672d968 --- /dev/null +++ b/gdcm/Source/Common/gdcmTesting.cxx @@ -0,0 +1,537 @@ + /*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmTesting.h" +#include "gdcmFilename.h" +#include "gdcmSystem.h" +#include "gdcmMD5.h" + +#include // strcmp +#include // malloc + + +namespace gdcm +{ + +#ifndef GDCM_BUILD_TESTING +#error how did that happen ? +#endif + +#include "gdcmDataFileNames.cxx" +#include "gdcmMD5DataImages.cxx" +#include "gdcmMD5DataBrokenImages.cxx" +#include "gdcmMediaStorageDataFiles.cxx" +#include "gdcmStreamOffsetDataFiles.cxx" +// After gdcmStreamOffsetDataFiles: +#include "gdcmSelectedTagsOffsetDataFiles.cxx" + +bool Testing::ComputeMD5(const char *buffer, unsigned long buf_len, + char digest_str[33]) +{ + return MD5::Compute(buffer, buf_len, digest_str); +} + +bool Testing::ComputeFileMD5(const char *filename, char *digest_str) +{ + return MD5::ComputeFile(filename, digest_str); +} + +const char * const *Testing::GetFileNames() +{ + return gdcmDataFileNames; +} + +unsigned int Testing::GetNumberOfFileNames() +{ + // Do not count NULL value: + static const unsigned int size = sizeof(gdcmDataFileNames)/sizeof(*gdcmDataFileNames) - 1; + return size; +} + +const char * Testing::GetFileName(unsigned int file) +{ + if( file < Testing::GetNumberOfFileNames() ) return gdcmDataFileNames[file]; + return NULL; +} + +Testing::MediaStorageDataFilesType Testing::GetMediaStorageDataFiles() +{ + return gdcmMediaStorageDataFiles; +} +unsigned int Testing::GetNumberOfMediaStorageDataFiles() +{ + // Do not count NULL value: + static const unsigned int size = sizeof(gdcmMediaStorageDataFiles)/sizeof(*gdcmMediaStorageDataFiles) - 1; + return size; +} +const char * const * Testing::GetMediaStorageDataFile(unsigned int file) +{ + if( file < Testing::GetNumberOfMediaStorageDataFiles() ) return gdcmMediaStorageDataFiles[file]; + // else return the {0x0, 0x0} sentinel: + assert( *gdcmMediaStorageDataFiles[ Testing::GetNumberOfMediaStorageDataFiles() ] == 0 ); + return gdcmMediaStorageDataFiles[ Testing::GetNumberOfMediaStorageDataFiles() ]; +} +const char * Testing::GetMediaStorageFromFile(const char *filepath) +{ + unsigned int i = 0; + MediaStorageDataFilesType mediastorages = GetMediaStorageDataFiles(); + const char *p = mediastorages[i][0]; + Filename comp(filepath); + const char *filename = comp.GetName(); + while( p != 0 ) + { + if( strcmp( filename, p ) == 0 ) + { + break; + } + ++i; + p = mediastorages[i][0]; + } + // \postcondition always valid (before sentinel) + assert( i <= GetNumberOfMediaStorageDataFiles() ); + return mediastorages[i][1]; +} + + +Testing::MD5DataImagesType Testing::GetMD5DataImages() +{ + return gdcmMD5DataImages; +} +unsigned int Testing::GetNumberOfMD5DataImages() +{ + // Do not count NULL value: + static const unsigned int size = sizeof(gdcmMD5DataImages)/sizeof(*gdcmMD5DataImages) - 1; + return size; +} + +const char * const * Testing::GetMD5DataImage(unsigned int file) +{ + if( file < Testing::GetNumberOfMD5DataImages() ) return gdcmMD5DataImages[file]; + // else return the {0x0, 0x0} sentinel: + assert( *gdcmMD5DataImages[ Testing::GetNumberOfMD5DataImages() ] == 0 ); + return gdcmMD5DataImages[ Testing::GetNumberOfMD5DataImages() ]; +} + +const char * Testing::GetMD5FromFile(const char *filepath) +{ + if(!filepath) return NULL; + unsigned int i = 0; + MD5DataImagesType md5s = GetMD5DataImages(); + const char *p = md5s[i][1]; + Filename comp(filepath); + const char *filename = comp.GetName(); + while( p != 0 ) + { + if( strcmp( filename, p ) == 0 ) + { + break; + } + ++i; + p = md5s[i][1]; + } + // \postcondition always valid (before sentinel) + assert( i <= GetNumberOfMD5DataImages() ); + return md5s[i][0]; +} + +const char * Testing::GetMD5FromBrokenFile(const char *filepath) +{ + int i = 0; + Testing::MD5DataImagesType md5s = gdcmMD5DataBrokenImages; //GetMD5DataImages(); + const char *p = md5s[i][1]; + Filename comp(filepath); + const char *filename = comp.GetName(); + while( p != 0 ) + { + if( strcmp( filename, p ) == 0 ) + { + break; + } + ++i; + p = md5s[i][1]; + } + return md5s[i][0]; +} + +std::streamoff Testing::GetStreamOffsetFromFile(const char *filepath) +{ + if(!filepath) return 0; + unsigned int i = 0; + const StreamOffset* so = gdcmStreamOffsetDataFiles; + const char *p = so[i].filename; + Filename comp(filepath); + const char *filename = comp.GetName(); + while( p != 0 ) + { + if( strcmp( filename, p ) == 0 ) + { + break; + } + ++i; + p = so[i].filename; + } + return so[i].offset; +} + +std::streamoff Testing::GetSelectedTagsOffsetFromFile(const char *filepath) +{ + if(!filepath) return 0; + unsigned int i = 0; + const StreamOffset* so = gdcmSelectedTagsOffsetDataFiles; + const char *p = so[i].filename; + Filename comp(filepath); + const char *filename = comp.GetName(); + while( p != 0 ) + { + if( strcmp( filename, p ) == 0 ) + { + break; + } + ++i; + p = so[i].filename; + } + return so[i].offset;} + +// See TestImageReader + lossydump = true to generate this list: +struct LossyFile +{ + int lossyflag; + const char *filename; +}; + +static const LossyFile gdcmLossyFilenames[] = { +{ 0,"SIEMENS_SOMATOM-12-ACR_NEMA-ZeroLengthUs.acr" }, +{ 0,"MR-MONO2-12-an2.acr" }, +{ 0,"gdcm-ACR-LibIDO.acr" }, +{ 0,"test.acr" }, +{ 0,"MR-MONO2-12-angio-an1.acr" }, +{ 0,"LIBIDO-8-ACR_NEMA-Lena_128_128.acr" }, +{ 0,"libido1.0-vol.acr" }, +{ 0,"gdcm-MR-SIEMENS-16-2.acr" }, +{ 0,"CT-MONO2-12-lomb-an2.acr" }, +{ 0,"LEADTOOLS_FLOWERS-8-PAL-Uncompressed.dcm" }, +{ 0,"00191113.dcm" }, +{ 0,"SignedShortLosslessBug.dcm" }, +{ 0,"gdcm-MR-PHILIPS-16-NonSquarePixels.dcm" }, +{ 0,"MARCONI_MxTWin-12-MONO2-JpegLossless-ZeroLengthSQ.dcm" }, +{ 0,"ACUSON-24-YBR_FULL-RLE.dcm" }, +{ 0,"D_CLUNIE_VL2_RLE.dcm" }, +{ 0,"MR_Philips_Intera_No_PrivateSequenceImplicitVR.dcm" }, +{ 0,"MR_Philips-Intera_BreaksNOSHADOW.dcm" }, +{ 0,"D_CLUNIE_MR2_JPLL.dcm" }, +{ 0,"D_CLUNIE_XA1_JPLL.dcm" }, +{ 1,"JPEG_LossyYBR.dcm" }, +{ 0,"ALOKA_SSD-8-MONO2-RLE-SQ.dcm" }, +{ 0,"PHILIPS_Gyroscan-12-MONO2-Jpeg_Lossless.dcm" }, +{ 0,"MR-MONO2-12-shoulder.dcm" }, +{ 1,"D_CLUNIE_RG3_JPLY.dcm" }, +{ 1,"PHILIPS_Gyroscan-12-Jpeg_Extended_Process_2_4.dcm" }, +{ 0,"MR-MONO2-8-16x-heart.dcm" }, +{ 0,"SIEMENS_ImageLocationUN.dcm" }, +{ 0,"US-PAL-8-10x-echo.dcm" }, +{ 0,"PHILIPS_Brilliance_ExtraBytesInOverlay.dcm" }, +{ 0,"SIEMENS_MAGNETOM-12-MONO2-Uncompressed.dcm" }, +{ 0,"LEADTOOLS_FLOWERS-8-PAL-RLE.dcm" }, +{ 0,"US-RGB-8-esopecho.dcm" }, +{ 0,"GE_RHAPSODE-16-MONO2-JPEG-Fragments.dcm" }, +{ 0,"CT-SIEMENS-Icone-With-PaletteColor.dcm" }, +{ 0,"LEADTOOLS_FLOWERS-16-MONO2-Uncompressed.dcm" }, +{ 0,"FUJI-10-MONO1-ACR_NEMA_2.dcm" }, +{ 0,"D_CLUNIE_CT1_RLE.dcm" }, +{ 0,"undefined_length_un_vr.dcm" }, +{ 0,"D_CLUNIE_MR4_JPLL.dcm" }, +{ 1,"DCMTK_JPEGExt_12Bits.dcm" }, +{ 0,"CT_16b_signed-UsedBits13.dcm" }, +{ 0,"DX_J2K_0Padding.dcm" }, +{ 0,"KODAK_CompressedIcon.dcm" }, +{ 0,"D_CLUNIE_CT2_JPLL.dcm" }, +{ 0,"DermaColorLossLess.dcm" }, +{ 0,"GE_GENESIS-16-MONO2-Uncompressed-UnusualVR.dcm" }, +{ 1,"D_CLUNIE_NM1_JPLY.dcm" }, +{ 0,"MR_Philips_Intera_SwitchIndianess_noLgtSQItem_in_trueLgtSeq.dcm" }, +{ 1,"LEADTOOLS_FLOWERS-24-RGB-JpegLossy.dcm" }, +{ 0,"D_CLUNIE_CT1_J2KR.dcm" }, +{ 0,"LEADTOOLS_FLOWERS-16-MONO2-RLE.dcm" }, +{ 0,"US-RGB-8-epicard.dcm" }, +{ 0,"D_CLUNIE_MR3_RLE.dcm" }, +{ 0,"LEADTOOLS_FLOWERS-8-MONO2-Uncompressed.dcm" }, +{ 0,"US-IRAD-NoPreambleStartWith0005.dcm" }, +{ 0,"D_CLUNIE_RG2_JPLL.dcm" }, +{ 0,"DMCPACS_ExplicitImplicit_BogusIOP.dcm" }, +{ 0,"MR_ELSCINT1_00e1_1042_SQ_feff_00e0_Item.dcm" }, +{ 0,"MR-SIEMENS-DICOM-WithOverlays.dcm" }, +{ 0,"SIEMENS_MOSAIC_12BitsStored-16BitsJPEG.dcm" }, +{ 0,"JDDICOM_Sample2-dcmdjpeg.dcm" }, +{ 0,"SIEMENS_MAGNETOM-12-MONO2-FileSeq2.dcm" }, +{ 1,"D_CLUNIE_MR3_JPLY.dcm" }, +{ 0,"MR_Philips_Intera_PrivateSequenceExplicitVR_in_SQ_2001_e05f_item_wrong_lgt_use_NOSHADOWSEQ.dcm" }, +{ 0,"TheralysGDCM120Bug.dcm" }, +{ 0,"PrivateGEImplicitVRBigEndianTransferSyntax16Bits.dcm" }, +{ 1,"US-GE-4AICL142.dcm" }, +{ 0,"MR16BitsAllocated_8BitsStored.dcm" }, +{ 0,"3E768EB7.dcm" }, +{ 0,"SIEMENS_Sonata-16-MONO2-Value_Multiplicity.dcm" }, +{ 0,"GE_MR_0025xx1bProtocolDataBlock.dcm" }, +{ 0,"MR_GE_with_Private_Compressed_Icon_0009_1110.dcm" }, +{ 0,"ExplicitVRforPublicElementsImplicitVRforShadowElements.dcm" }, +{ 1,"D_CLUNIE_SC1_JPLY.dcm" }, +{ 0,"CT-MONO2-16-chest.dcm" }, +{ 0,"D_CLUNIE_MR4_RLE.dcm" }, +{ 0,"SIEMENS_MAGNETOM-12-MONO2-FileSeq1.dcm" }, +{ 1,"ELSCINT1_JP2vsJ2K.dcm" }, +{ 0,"D_CLUNIE_CT2_RLE.dcm" }, +{ 0,"D_CLUNIE_MR2_RLE.dcm" }, +{ 0,"OT-MONO2-8-a7.dcm" }, +{ 0,"MR-MONO2-16-head.dcm" }, +{ 0,"PICKER-16-MONO2-No_DicomV3_Preamble.dcm" }, +{ 1,"gdcm-JPEG-Extended.dcm" }, +{ 0,"BugGDCM2_UndefItemWrongVL.dcm" }, +{ 0,"D_CLUNIE_MR1_RLE.dcm" }, +{ 0,"PICKER-16-MONO2-Nested_icon.dcm" }, +{ 0,"D_CLUNIE_VL4_RLE.dcm" }, +{ 0,"D_CLUNIE_RG1_RLE.dcm" }, +{ 1,"JDDICOM_Sample2.dcm" }, +{0,"AMIInvalidPrivateDefinedLengthSQasUN.dcm" }, +{ 0,"SIEMENS_MAGNETOM-12-MONO2-FileSeq3.dcm" }, +{ 0,"CT-MONO2-8-abdo.dcm" }, +{ 0,"D_CLUNIE_SC1_RLE.dcm" }, +{ 0,"LEADTOOLS_FLOWERS-24-RGB-JpegLossless.dcm" }, +{ 0,"D_CLUNIE_RG3_JPLL.dcm" }, +{ 0,"SIEMENS_CSA2.dcm" }, +{ 0,"LJPEG_BuginGDCM12.dcm" }, +{ 0,"CT-SIEMENS-MissingPixelDataInIconSQ.dcm" }, +{ 0,"05115014-mr-siemens-avanto-syngo-with-palette-icone.dcm" }, +{ 0,"GE_CT_With_Private_compressed-icon.dcm" }, +{ 1,"D_CLUNIE_XA1_JPLY.dcm" }, +{ 0,"012345.002.050.dcm" }, +{ 0,"TOSHIBA_MRT150-16-MONO2-ACR_NEMA_2.dcm" }, +{ 1,"LEADTOOLS_FLOWERS-8-MONO2-JpegLossy.dcm" }, +{ 0,"gdcm-US-ALOKA-16.dcm" }, +{ 0,"THERALYS-12-MONO2-Uncompressed-Even_Length_Tag.dcm" }, +{ 0,"D_CLUNIE_CT1_JPLL.dcm" }, +{ 0,"rle16loo.dcm" }, +{ 0,"D_CLUNIE_US1_RLE.dcm" }, +{ 0,"LEADTOOLS_FLOWERS-8-MONO2-RLE.dcm" }, +{ 0,"RadBWLossLess.dcm" }, +{ 1,"D_CLUNIE_MR1_JPLY.dcm" }, +{ 0,"JPEGDefinedLengthSequenceOfFragments.dcm" }, +{ 0,"GE_DLX-8-MONO2-PrivateSyntax.dcm" }, +{ 0,"gdcm-JPEG-LossLess3a.dcm" }, +{ 0,"TG18-CH-2k-01.dcm" }, +{ 0,"OT-PAL-8-face.dcm" }, +{ 0,"D_CLUNIE_NM1_RLE.dcm" }, +{ 0,"rle16sti.dcm" }, +{ 0,"GE_GENESIS-16-MONO2-WrongLengthItem.dcm" }, +{ 1,"D_CLUNIE_CT1_J2KI.dcm" }, +{ 0,"SIEMENS_MAGNETOM-12-MONO2-FileSeq0.dcm" }, +{ 0,"LEADTOOLS_FLOWERS-24-RGB-Uncompressed.dcm" }, +{ 1,"D_CLUNIE_MR4_JPLY.dcm" }, +{ 0,"OsirixFake16BitsStoredFakeSpacing.dcm" }, +{ 0,"PHILIPS_Gyroscan-8-MONO2-Odd_Sequence.dcm" }, +{ 0,"MR-SIEMENS-DICOM-WithOverlays-extracted-overlays.dcm" }, +{ 0,"D_CLUNIE_CT1_JLSL.dcm" }, +{ 1,"D_CLUNIE_CT1_JLSN.dcm" }, +{ 0,"D_CLUNIE_RG3_RLE.dcm" }, +{ 1,"SIEMENS-12-Jpeg_Process_2_4-Lossy-a.dcm" }, +{ 0,"CT-MONO2-16-brain.dcm" }, +{ 1,"D_CLUNIE_RG2_JPLY.dcm" }, +{ 1,"MAROTECH_CT_JP2Lossy.dcm" }, +{ 0,"D_CLUNIE_MR1_JPLL.dcm" }, +{ 0,"ITK_GDCM124_MultiframeSecondaryCaptureInvalid.dcm" }, +{ 0,"SIEMENS_MAGNETOM-12-ACR_NEMA_2-Modern.dcm" }, +{ 0,"MR_SIEMENS_forceLoad29-1010_29-1020.dcm" }, +{ 0,"simpleImageWithIcon.dcm" }, +{ 0,"D_CLUNIE_MR3_JPLL.dcm" }, +{ 0,"D_CLUNIE_RG1_JPLL.dcm" }, +{ 0,"US-MONO2-8-8x-execho.dcm" }, +{ 0,"XA-MONO2-8-12x-catheter.dcm" }, +{ 0,"GE_LOGIQBook-8-RGB-HugePreview.dcm" }, +{ 0,"gdcm-MR-PHILIPS-16-Multi-Seq.dcm" }, +{ 0,"D_CLUNIE_XA1_RLE.dcm" }, +{ 0,"NM-MONO2-16-13x-heart.dcm" }, +{ 0,"gdcm-JPEG-LossLessThoravision.dcm" }, +{ 0,"GE_DLX-8-MONO2-Multiframe.dcm" }, +{ 0,"PHILIPS_Intera-16-MONO2-Uncompress.dcm" }, +{ 1,"D_CLUNIE_MR2_JPLY.dcm" }, +{ 0,"05148044-mr-siemens-avanto-syngo.dcm" }, +{ 0,"D_CLUNIE_VL3_RLE.dcm" }, +{ 0,"D_CLUNIE_RG2_RLE.dcm" }, +{ 0,"SIEMENS_MAGNETOM-12-MONO2-GDCM12-VRUN.dcm" }, +{ 0,"KODAK-12-MONO1-Odd_Terminated_Sequence.dcm" }, +{ 0,"SIEMENS-MR-RGB-16Bits.dcm" }, +{ 0,"CR-MONO1-10-chest.dcm" }, +{ 0,"DX_GE_FALCON_SNOWY-VOI.dcm" }, +{ 0,"US-IRAD-NoPreambleStartWith0003.dcm" }, +{ 0,"MR-Brucker-CineTagging-NonSquarePixels.dcm" }, +{ 0,"D_CLUNIE_VL6_RLE.dcm" }, +{ 0,"MR_Philips_Intera_PrivateSequenceImplicitVR.dcm" }, +{ 0,"fffc0000UN.dcm" }, +{ 0,"SIEMENS_Sonata-12-MONO2-SQ.dcm" }, +{ 0,"ACUSON-24-YBR_FULL-RLE-b.dcm" }, +{ 0,"CT-MONO2-16-ankle.dcm" }, +{ 0,"GE_DLX-8-MONO2-Multiframe-Jpeg_Lossless.dcm" }, +{ 0,"CT-MONO2-16-ort.dcm" }, +{ 0,"LEADTOOLS_FLOWERS-16-MONO2-JpegLossless.dcm" }, +{ 0,"D_CLUNIE_NM1_JPLL.dcm" }, +{ 0,"D_CLUNIE_VL1_RLE.dcm" }, +{ 0,"SIEMENS_MAGNETOM-12-MONO2-VRUN.dcm" }, +{ 0,"00191113.dcm" }, +{ 0,"TestVRSQUN2.dcm" }, +{ 0,"PHILIPS_GDCM12xBug.dcm"}, +{ 0,"PHILIPS_GDCM12xBug2.dcm"}, +{ 0,"TestVRSQUN1.dcm"} , +{ 1,"multiframegrayscalebytescis.dcm" }, +{ 1,"multiframegrayscalewordscis.dcm" }, +{ 1,"multiframesinglebitscis.dcm" }, +{ 1,"multiframetruecolorscis.dcm" }, +{ 1, "SinglePrecisionSC.dcm" }, +{ 0, "signedtruecoloroldsc.dcm" }, +{ 0, "o.dcm" }, +{ 0, "UnexpectedSequenceDelimiterInFixedLengthSequence.dcm" }, +{ 0, "IM-0001-0066.CommandTag00.dcm" }, +{ 0, "NM_Kakadu44_SOTmarkerincons.dcm" }, +{ 0, "GDCMJ2K_TextGBR.dcm" }, +{ 0, "PhilipsInteraSeqTermInvLen.dcm" }, +{ 0, "LIBIDO-24-ACR_NEMA-Rectangle.dcm" }, +{ 0, "TOSHIBA_J2K_SIZ1_PixRep0.dcm" }, +{ 0, "TOSHIBA_J2K_SIZ0_PixRep1.dcm" }, +{ 0, "TOSHIBA_J2K_OpenJPEGv2Regression.dcm" }, +{ 0, "NM-PAL-16-PixRep1.dcm" }, +{ 0, "MEDILABInvalidCP246_EVRLESQasUN.dcm" }, +{ 0, "JPEGInvalidSecondFrag.dcm" }, +{ 0, NULL } +}; + + +int Testing::GetLossyFlagFromFile(const char *filename) +{ + if( !filename ) return 0; + gdcm::Filename fn = filename; + const char *file = fn.GetName(); + const LossyFile *pfiles = gdcmLossyFilenames; + while( pfiles->filename && strcmp(pfiles->filename, file) != 0 ) + { + ++pfiles; + } + if( !(pfiles->filename) ) + { + std::cerr << "Error: No ref table for: " << filename << std::endl; + return -1; + } + assert( pfiles->filename ); // need to update ref table + return pfiles->lossyflag; +} + +const char *Testing::GetDataRoot() +{ + return GDCM_DATA_ROOT; +} + +const char *Testing::GetDataExtraRoot() +{ + return GDCM_DATA_EXTRA_ROOT; +} + +const char *Testing::GetPixelSpacingDataRoot() +{ + return GDCM_PIXEL_SPACING_DATA_ROOT; +} + +const char *Testing::GetTempDirectory(const char * subdir) +{ + if( !subdir ) return GDCM_TEMP_DIRECTORY; + // else + static std::string buffer; + std::string tmpdir = GDCM_TEMP_DIRECTORY; + tmpdir += "/"; + tmpdir += subdir; + buffer = tmpdir; + return buffer.c_str(); +} + +const wchar_t *Testing::GetTempDirectoryW(const wchar_t * subdir) +{ + static std::wstring buffer; + wchar_t wname[4096]; // FIXME + size_t len = mbstowcs(wname,GDCM_TEMP_DIRECTORY,sizeof(wname)/sizeof(wchar_t)); + (void)len; + if( !subdir ) + { + buffer = wname; + return buffer.c_str(); + } + // else + std::wstring tmpdir = wname; + tmpdir += L"/"; + tmpdir += subdir; + buffer = tmpdir; + return buffer.c_str(); +} + +const char * Testing::GetTempFilename(const char *filename, const char * subdir) +{ + if( !filename ) return 0; + + static std::string buffer; + std::string outfilename = GetTempDirectory(subdir); + outfilename += "/"; + gdcm::Filename out(filename); + outfilename += out.GetName(); + buffer = outfilename; + + return buffer.c_str(); +} + +void Testing::Print(std::ostream &os) +{ + os << "DataFileNames:\n"; + const char * const * filenames = gdcmDataFileNames; + while( *filenames ) + { + os << *filenames << "\n"; + ++filenames; + } + + os << "MD5DataImages:\n"; + MD5DataImagesType md5s = gdcmMD5DataImages; + while( (*md5s)[0] ) + { + os << (*md5s)[0] << " -> " << (*md5s)[1] << "\n"; + ++md5s; + } +} + +const wchar_t* Testing::GetTempFilenameW(const wchar_t *filename, const wchar_t* subdir) +{ + // mbsrtowcs + // mbstowcs + if( !filename ) return 0; + + static std::wstring buffer; + std::wstring outfilename = GetTempDirectoryW(subdir); + outfilename += L"/"; + + //gdcm::Filename out(filename); + //outfilename += out.GetName(); + buffer = outfilename; + buffer += filename; + + return buffer.c_str(); +} + +const char *Testing::GetSourceDirectory() +{ + return GDCM_SOURCE_DIR; +} + +} // end of namespace gdcm diff --git a/gdcm/Source/Common/gdcmTesting.h b/gdcm/Source/Common/gdcmTesting.h new file mode 100644 index 0000000..cce67ff --- /dev/null +++ b/gdcm/Source/Common/gdcmTesting.h @@ -0,0 +1,114 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMTESTING_H +#define GDCMTESTING_H + +#include "gdcmTypes.h" + +#include + +namespace gdcm +{ +/** + * \brief class for testing + * \details this class is used for the nightly regression system for GDCM + * It makes heavily use of md5 computation + * + * \see gdcm::MD5 class for md5 computation + */ +//----------------------------------------------------------------------------- +class GDCM_EXPORT Testing +{ +public : + Testing() {}; + ~Testing() {}; + + /// MD5 stuff + /// digest_str needs to be at least : strlen = [2*16+1]; + /// string will be \0 padded. (md5 are 32 bytes long) + /// Testing is not meant to be shipped with an installed GDCM release, always + /// prefer the gdcm::MD5 API when doing md5 computation. + static bool ComputeMD5(const char *buffer, unsigned long buf_len, + char digest_str[33]); + static bool ComputeFileMD5(const char *filename, char digest_str[33]); + + /// Print + void Print(std::ostream &os = std::cout); + + /// return the table of fullpath to gdcmData DICOM files: + static const char * const * GetFileNames(); + static unsigned int GetNumberOfFileNames(); + static const char * GetFileName(unsigned int file); + + /// return the table that map the media storage (as string) of a filename (gdcmData) + typedef const char* const (*MediaStorageDataFilesType)[2]; + static MediaStorageDataFilesType GetMediaStorageDataFiles(); + static unsigned int GetNumberOfMediaStorageDataFiles(); + static const char * const * GetMediaStorageDataFile(unsigned int file); + static const char * GetMediaStorageFromFile(const char *filepath); + + /// return the table that map the md5 (as in md5sum) of the Pixel Data associated + /// to a filename + typedef const char* const (*MD5DataImagesType)[2]; + static MD5DataImagesType GetMD5DataImages(); + static unsigned int GetNumberOfMD5DataImages(); + static const char * const * GetMD5DataImage(unsigned int file); + static const char * GetMD5FromFile(const char *filepath); + + /// Return what should have been the md5 of file 'filepath' + /// This is based on current GDCM implementation to decipher a broken DICOM file. + static const char * GetMD5FromBrokenFile(const char *filepath); + + /// Return the offset of the very first pixel cell in the PixelData + /// -1 if not found + static std::streamoff GetStreamOffsetFromFile(const char *filepath); + + /// Return the offset just after Pixel Data Length (7fe0,0000) if found. + /// Otherwise the offset of the very first pixel cell in Pixel Data + /// -1 if not found + static std::streamoff GetSelectedTagsOffsetFromFile(const char *filepath); + + /// Return the lossy flag of the given filename + /// -1 -> Error + /// 0 -> Lossless + /// 1 -> Lossy + static int GetLossyFlagFromFile(const char *filepath); + + /// Return the GDCM DATA ROOT + static const char * GetDataRoot(); + + /// Return the GDCM DATA EXTRA ROOT + static const char * GetDataExtraRoot(); + + /// Return the GDCM PIXEL SPACING DATA ROOT (See David Clunie website for dataset) + static const char * GetPixelSpacingDataRoot(); + + /// NOT THREAD SAFE + /// Returns the temp directory as used in testing needing to output data: + static const char * GetTempDirectory(const char * subdir = 0); + + /// NOT THREAD SAFE + static const wchar_t *GetTempDirectoryW(const wchar_t * subdir = 0); + + /// NOT THREAD SAFE + static const char * GetTempFilename(const char *filename, const char * subdir = 0); + + /// NOT THREAD SAFE + static const wchar_t* GetTempFilenameW(const wchar_t *filename, const wchar_t* subdir = 0); + + static const char *GetSourceDirectory(); +}; +} // end namespace gdcm +//----------------------------------------------------------------------------- +#endif //GDCMTESTING_H diff --git a/gdcm/Source/Common/gdcmTrace.cxx b/gdcm/Source/Common/gdcmTrace.cxx new file mode 100644 index 0000000..d29f8f3 --- /dev/null +++ b/gdcm/Source/Common/gdcmTrace.cxx @@ -0,0 +1,147 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmTrace.h" + +#include +#include + +namespace gdcm +{ +//----------------------------------------------------------------------------- +// Warning message level to be displayed +static bool DebugFlag = false; +static bool WarningFlag = true; +static bool ErrorFlag = true; +// Stream based API: +static std::ostream * DebugStream = &std::cerr; +static std::ostream * WarningStream = &std::cerr; +static std::ostream * ErrorStream = &std::cerr; +// File based API: +static bool UseStreamToFile = false; +static std::ofstream * FileStream = NULL; + +void Trace::SetStreamToFile( const char *filename ) +{ + if( !filename ) return; + if( UseStreamToFile ) + { + assert( FileStream ); + FileStream->close(); + FileStream = NULL; + UseStreamToFile = false; + } + std::ofstream * out = new std::ofstream; + if( !out ) return; + out->open( filename ); + if( !out->good() ) return; + assert( !FileStream && !UseStreamToFile ); + FileStream = out; + UseStreamToFile = true; + DebugStream = FileStream; + WarningStream = FileStream; + ErrorStream = FileStream; +} + +void Trace::SetStream(std::ostream &os) +{ + if( !os.good() ) return; + if( UseStreamToFile ) + { + assert( FileStream ); + FileStream->close(); + FileStream = NULL; + UseStreamToFile = false; + } + DebugStream = &os; + WarningStream = &os; + ErrorStream = &os; +} + +std::ostream &Trace::GetStream() +{ + return *DebugStream; +} + +void Trace::SetDebugStream(std::ostream &os) +{ + DebugStream = &os; +} + +std::ostream &Trace::GetDebugStream() +{ + return *DebugStream; +} + +void Trace::SetWarningStream(std::ostream &os) +{ + WarningStream = &os; +} + +std::ostream &Trace::GetWarningStream() +{ + return *WarningStream; +} + +void Trace::SetErrorStream(std::ostream &os) +{ + ErrorStream = &os; +} + +std::ostream &Trace::GetErrorStream() +{ + return *ErrorStream; +} + +//----------------------------------------------------------------------------- +// Constructor / Destructor +Trace::Trace() +{ + DebugFlag = WarningFlag = ErrorFlag = false; +} + +Trace::~Trace() +{ + if( UseStreamToFile ) + { + assert( FileStream ); + FileStream->close(); + FileStream = NULL; + } +} + +void Trace::SetDebug(bool debug) { DebugFlag = debug; } +void Trace::DebugOn() { DebugFlag = true; } +void Trace::DebugOff() { DebugFlag = false; } +bool Trace::GetDebugFlag() +{ + return DebugFlag; +} + +void Trace::SetWarning(bool warning) { WarningFlag = warning; } +void Trace::WarningOn() { WarningFlag = true; } +void Trace::WarningOff() { WarningFlag = false; } +bool Trace::GetWarningFlag() +{ + return WarningFlag; +} + +void Trace::SetError(bool error) { ErrorFlag = error; } +void Trace::ErrorOn() { ErrorFlag = true; } +void Trace::ErrorOff() { ErrorFlag = false; } +bool Trace::GetErrorFlag() +{ + return ErrorFlag; +} + +} // end namespace gdcm diff --git a/gdcm/Source/Common/gdcmTrace.h b/gdcm/Source/Common/gdcmTrace.h new file mode 100644 index 0000000..3574c9f --- /dev/null +++ b/gdcm/Source/Common/gdcmTrace.h @@ -0,0 +1,228 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMTRACE_H +#define GDCMTRACE_H + +#include "gdcmTypes.h" +#include "gdcmSystem.h" + +#include +#include + +namespace gdcm +{ + +/** + * \brief Trace + * \details Debug / Warning and Error are encapsulated in this class + * by default the Trace class will redirect any debug/warning/error + * to std::cerr. Unless SetStream was specified with another (open) stream or + * SetStreamToFile was specified to a writable file on the system. + * + * \warning + * All string messages are removed during compilation time when compiled with + * CMAKE_BUILD_TYPE being set to either: + * - Release + * - MinSizeRel + * It is recommended to compile with RelWithDebInfo and/or Debug during + * prototyping of applications. + */ +class GDCM_EXPORT Trace +{ +public : + Trace(); + ~Trace(); + + /// Explicitely set the ostream for gdcm::Trace to report to + /// This will set the DebugStream, WarningStream and ErrorStream at once: + static void SetStream(std::ostream &os); + static std::ostream &GetStream(); + + /// Explicitely set the stream which receive Debug messages: + static void SetDebugStream(std::ostream &os); + static std::ostream &GetDebugStream(); + + /// Explicitely set the stream which receive Warning messages: + static void SetWarningStream(std::ostream &os); + static std::ostream &GetWarningStream(); + + /// Explicitely set the stream which receive Error messages: + static void SetErrorStream(std::ostream &os); + static std::ostream &GetErrorStream(); + + /// Explicitely set the filename for gdcm::Trace to report to + /// The file will be created (it will not append to existing file) + static void SetStreamToFile( const char *filename ); + + /// Turn debug messages on (default: false) + static void SetDebug(bool debug); + static void DebugOn(); + static void DebugOff(); + static bool GetDebugFlag(); + + /// Turn warning messages on (default: true) + static void SetWarning(bool debug); + static void WarningOn(); + static void WarningOff(); + static bool GetWarningFlag(); + + /// Turn error messages on (default: true) + static void SetError(bool debug); + static void ErrorOn(); + static void ErrorOff(); + static bool GetErrorFlag(); + +protected: +private: +}; + +// Here we define function this is the only way to be able to pass +// stuff with indirection like: +// gdcmDebug( "my message:" << i << '\t' ); +// You cannot use function unless you use vnsprintf ... + +// __FUNCTION is not always defined by preprocessor +// In c++ we should use __PRETTY_FUNCTION__ instead... +#ifdef GDCM_CXX_HAS_FUNCTION +// Handle particular case for GNU C++ which also defines __PRETTY_FUNCTION__ +// which is a lot nice in C++ +#ifdef __BORLANDC__ +# define __FUNCTION__ __FUNC__ +#endif +#ifdef __GNUC__ +# define GDCM_FUNCTION __PRETTY_FUNCTION__ +#else +# define GDCM_FUNCTION __FUNCTION__ +#endif //__GNUC__ +#else +# define GDCM_FUNCTION "" +#endif //GDCM_CXX_HAS_FUNCTION + +/** + * \brief Debug + * @param msg message part + */ +#if defined(NDEBUG) && !defined(GDCM_ALWAYS_TRACE_MACRO) +#define gdcmDebugMacro(msg) {} +#else +#define gdcmDebugMacro(msg) \ +{ \ + if( gdcm::Trace::GetDebugFlag() ) \ + { \ + std::ostringstream osmacro; \ + osmacro << "Debug: In " __FILE__ ", line " << __LINE__ \ + << ", function " << GDCM_FUNCTION << '\n' \ + << "Last system error was: " \ + << gdcm::System::GetLastSystemError() << '\n' << msg; \ + std::ostream &_os = gdcm::Trace::GetDebugStream(); \ + _os << osmacro.str() << "\n\n" << std::endl; \ + } \ +} +#endif //NDEBUG + +/** + * \brief Warning + * @param msg message part + */ +#if defined(NDEBUG) && !defined(GDCM_ALWAYS_TRACE_MACRO) +#define gdcmWarningMacro(msg) {} +#else +#define gdcmWarningMacro(msg) \ +{ \ + if( gdcm::Trace::GetWarningFlag() ) \ + { \ + std::ostringstream osmacro; \ + osmacro << "Warning: In " __FILE__ ", line " << __LINE__ \ + << ", function " << GDCM_FUNCTION << "\n" \ + << msg << "\n\n"; \ + std::ostream &_os = gdcm::Trace::GetWarningStream(); \ + _os << osmacro.str() << std::endl; \ + } \ +} +#endif //NDEBUG + +/** + * \brief Error this is pretty bad, more than just warning + * It could mean lost of data, something not handle... + * @param msg second message part + */ +#if defined(NDEBUG) && !defined(GDCM_ALWAYS_TRACE_MACRO) +#define gdcmErrorMacro(msg) {} +#else +#define gdcmErrorMacro(msg) \ +{ \ + if( gdcm::Trace::GetErrorFlag() ) \ + { \ + std::ostringstream osmacro; \ + osmacro << "Error: In " __FILE__ ", line " << __LINE__ \ + << ", function " << GDCM_FUNCTION << '\n' \ + << msg << "\n\n"; \ + std::ostream &_os = gdcm::Trace::GetErrorStream(); \ + _os << osmacro.str() << std::endl; \ + } \ +} +#endif //NDEBUG + +/** + * \brief Assert + * @param arg argument to test + * An easy solution to pass also a message is to do: + * gdcmAssertMacro( "my message" && 2 < 3 ) + */ +#if defined(NDEBUG) && !defined(GDCM_ALWAYS_TRACE_MACRO) +#define gdcmAssertMacro(arg) {} +#else +#define gdcmAssertMacro(arg) \ +{ \ + if( !(arg) ) \ + { \ + std::ostringstream osmacro; \ + osmacro << "Assert: In " __FILE__ ", line " << __LINE__ \ + << ", function " << GDCM_FUNCTION \ + << "\n\n"; \ + std::ostream &_os = gdcm::Trace::GetErrorStream(); \ + _os << osmacro.str() << std::endl; \ + assert ( arg ); \ + } \ +} +#endif //NDEBUG + +/** + * \brief AssertAlways + * @param arg argument to test + * An easy solution to pass also a message is to do: + * gdcmAssertMacro( "my message" && 2 < 3 ) + */ +#if defined(NDEBUG) && !defined(GDCM_ALWAYS_TRACE_MACRO) +// User asked for release compilation, but still need to report +// if grave issue. +#define gdcmAssertAlwaysMacro(arg) \ +{ \ + if( !(arg) ) \ + { \ + std::ostringstream osmacro; \ + osmacro << "Assert: In " __FILE__ ", line " << __LINE__ \ + << ", function " << GDCM_FUNCTION \ + << "\n\n"; \ + throw osmacro.str(); \ + } \ +} +#else +// Simply reproduce gdcmAssertMacro behavior: +#define gdcmAssertAlwaysMacro(arg) gdcmAssertMacro(arg) +#endif //NDEBUG + +} // end namespace gdcm +//----------------------------------------------------------------------------- +#endif //GDCMTRACE_H diff --git a/gdcm/Source/Common/gdcmTypes.h b/gdcm/Source/Common/gdcmTypes.h new file mode 100644 index 0000000..a8d26d4 --- /dev/null +++ b/gdcm/Source/Common/gdcmTypes.h @@ -0,0 +1,57 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMTYPES_H +#define GDCMTYPES_H + +#include "gdcmConfigure.h" +#include "gdcmWin32.h" +#include "gdcmLegacyMacro.h" + +//----------------------------------------------------------------------------- +#ifdef GDCM_HAVE_STDINT_H +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS +#endif // __STDC_LIMIT_MACROS +#include +//#undef __STDC_LIMIT_MACROS +#else +#ifdef GDCM_HAVE_INTTYPES_H +// Old system only have this +#include // For uint8_t uint16_t and uint32_t +#else +// Broken plateforms do not respect C99 and do not provide those typedef +// Special case for recent Borland compiler, comes with stdint.h +#if defined(__BORLANDC__) && (__BORLANDC__ < 0x0560) || defined(__MINGW32__) +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed int int32_t; +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned __int64 uint64_t; +#elif defined(_MSC_VER) +#include "stdint.h" +#else +#error "Sorry, your platform is not supported" +#endif // defined(_MSC_VER) || defined(__BORLANDC__) && (__BORLANDC__ < 0x0560) || defined(__MINGW32__) +#endif // GDCM_HAVE_INTTYPES_H +#endif // GDCM_HAVE_STDINT_H + +// Basically for VS6 and bcc 5.5.1: +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +//----------------------------------------------------------------------------- +#endif //GDCMTYPES_H diff --git a/gdcm/Source/Common/gdcmUnpacker12Bits.cxx b/gdcm/Source/Common/gdcmUnpacker12Bits.cxx new file mode 100644 index 0000000..d87d02e --- /dev/null +++ b/gdcm/Source/Common/gdcmUnpacker12Bits.cxx @@ -0,0 +1,59 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmUnpacker12Bits.h" + +namespace gdcm +{ + +bool Unpacker12Bits::Unpack(char *out, const char *in, size_t n) +{ + if( n % 3 ) return false; // 3bytes are actually 2 words + // http://groups.google.com/group/comp.lang.c/msg/572bc9b085c717f3 + short *q = (short*)out; + const unsigned char *p = (unsigned char*)in; + const unsigned char *end = p+n; + unsigned char b0,b1,b2; + + while (p!=end) + { + b0 = *p++; + b1 = *p++; + b2 = *p++; + *q++ = (short)(((b1 & 0xf) << 8) + b0); + *q++ = (short)((b1>>4) + (b2<<4)); + } + return true; +} + +bool Unpacker12Bits::Pack(char *out, const char *in, size_t n) +{ + if( n % 4 ) return false; // we need an even number of 'words' so that 2 words are split in 3 bytes + unsigned char *q = (unsigned char*)out; + const unsigned short *p = (unsigned short*)in; + const unsigned short *end = (unsigned short*)(in+n); + unsigned short b0,b1; + + while(p!=end) + { + b0 = *p++; + b1 = *p++; + + *q++ = (unsigned char)(b0 & 0xff); + *q++ = (unsigned char)((b0 >> 8) + ((b1 & 0xf) << 4)); + *q++ = (unsigned char)(b1 >> 4); + } + return true; +} + +} // end namespace gdcm diff --git a/gdcm/Source/Common/gdcmUnpacker12Bits.h b/gdcm/Source/Common/gdcmUnpacker12Bits.h new file mode 100644 index 0000000..38654d0 --- /dev/null +++ b/gdcm/Source/Common/gdcmUnpacker12Bits.h @@ -0,0 +1,49 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMUNPACKER12BITS_H +#define GDCMUNPACKER12BITS_H + +#include "gdcmTypes.h" + +namespace gdcm +{ +/** + * \brief Pack/Unpack 12 bits pixel into 16bits + * \li You can only pack an even number of 16bits, which means a multiple of 4 (expressed in bytes) + * \li You can only unpack a multiple of 3 bytes + * + * This class has no purpose in general purpose DICOM implementation. However + * to be able to cope with some early ACR-NEMA file generated by a well-known + * private vendor, one would need to unpack 12bits Stored Pixel Value into a + * more standard 16bits Stored Pixel Value. + * + * \see Rescaler + */ +class GDCM_EXPORT Unpacker12Bits +{ +public: + /// Pack an array of 16bits where all values are 12bits into a pack form. n + /// is the length in bytes of array in, out will be a fake 8bits array of size + /// (n / 2) * 3 + static bool Pack(char *out, const char *in, size_t n); + + /// Unpack an array of 'packed' 12bits data into a more conventional 16bits + /// array. n is the length in bytes of array in, out will be a 16bits array of + /// size (n / 3) * 2 + static bool Unpack(char *out, const char *in, size_t n); +}; + +} // end namespace gdcm + +#endif //GDCMUNPACKER12BITS_H diff --git a/gdcm/Source/Common/gdcmVersion.cxx b/gdcm/Source/Common/gdcmVersion.cxx new file mode 100644 index 0000000..8ea2f86 --- /dev/null +++ b/gdcm/Source/Common/gdcmVersion.cxx @@ -0,0 +1,44 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmVersion.h" + +namespace gdcm +{ + +void Version::Print(std::ostream &os) const +{ + os << Version::GetVersion(); +} + +const char * Version::GetVersion() +{ + return GDCM_VERSION; +} + +int Version::GetMajorVersion() +{ + return GDCM_MAJOR_VERSION; +} + +int Version::GetMinorVersion() +{ + return GDCM_MINOR_VERSION; +} + +int Version::GetBuildVersion() +{ + return GDCM_BUILD_VERSION; +} + +} diff --git a/gdcm/Source/Common/gdcmVersion.h b/gdcm/Source/Common/gdcmVersion.h new file mode 100644 index 0000000..0515fcc --- /dev/null +++ b/gdcm/Source/Common/gdcmVersion.h @@ -0,0 +1,51 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMVERSION_H +#define GDCMVERSION_H + +#include "gdcmTypes.h" +#include + +namespace gdcm +{ +/** + * \class Version + * \brief major/minor and build version + */ +//----------------------------------------------------------------------------- +class GDCM_EXPORT Version +{ + friend std::ostream& operator<<(std::ostream &_os, const Version &v); +public : + static const char *GetVersion(); + static int GetMajorVersion(); + static int GetMinorVersion(); + static int GetBuildVersion(); + + void Print(std::ostream &os = std::cout) const; + +//protected: + Version() {}; + ~Version() {}; +}; +//----------------------------------------------------------------------------- +inline std::ostream& operator<<(std::ostream &os, const Version &v) +{ + v.Print( os ); + return os; +} + +} // end namespace gdcm +//----------------------------------------------------------------------------- +#endif //GDCMVERSION_H diff --git a/gdcm/Source/Common/gdcmWin32.h b/gdcm/Source/Common/gdcmWin32.h new file mode 100644 index 0000000..1c84d71 --- /dev/null +++ b/gdcm/Source/Common/gdcmWin32.h @@ -0,0 +1,81 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#ifndef GDCMWIN32_H +#define GDCMWIN32_H + +#if !defined(GDCMTYPES_H) +#error you need to include gdcmTypes.h instead +#endif +//----------------------------------------------------------------------------- +// http://gcc.gnu.org/wiki/Visibility +#if defined(WIN32) && defined(GDCM_BUILD_SHARED_LIBS) + #if (defined(gdcmCommon_EXPORTS) || defined(gdcmDICT_EXPORTS) || defined(gdcmDSED_EXPORTS) || defined(gdcmIOD_EXPORTS) || defined(gdcmMSFF_EXPORTS) || defined(gdcmMEXD_EXPORTS)|| defined(_gdcmswig_EXPORTS)) || defined(vtkgdcm_EXPORTS) + #define GDCM_EXPORT __declspec( dllexport ) + #else + #define GDCM_EXPORT __declspec( dllimport ) + #endif +#else + #if __GNUC__ >= 4 + #define GDCM_EXPORT __attribute__ ((visibility ("default"))) + #define GDCM_LOCAL __attribute__ ((visibility ("hidden"))) + #else + #define GDCM_EXPORT + #endif +#endif + +// In VTK 4.2 vtkWrapPython does not like anything other than VTK_*EXPORT +// [ 86%] Generating vtkGDCMImageReaderPython.cxx +// syntax error +// *** SYNTAX ERROR found in parsing the header file /usr/local/src/gdcm2/tags/gdcm-2-0-11/Utilities/VTK/vtkGDCMImageReader.h before line 128*** +// make[2]: *** [Utilities/VTK/vtkGDCMImageReaderPython.cxx] Error 1 +// make[1]: *** [Utilities/VTK/CMakeFiles/vtkgdcmPythonD.dir/all] Error 2 +// make: *** [all] Error 2 + +#if defined(VTK_MAJOR_VERSION) && ( VTK_MAJOR_VERSION == 4 ) +#undef VTK_EXPORT +#define VTK_EXPORT GDCM_EXPORT +#endif + +//----------------------------------------------------------------------------- +//This is needed when compiling in debug mode +#ifdef _MSC_VER +// to allow construct such as: std::numeric_limits::max() we need the following: +// warning C4003: not enough actual parameters for macro 'max' +#define NOMINMAX +# pragma warning ( default : 4263 ) /* no override, call convention differs */ +// 'identifier' : class 'type' needs to have dll-interface to be used by +// clients of class 'type2' +#pragma warning ( disable : 4251 ) +// non dll-interface class 'type' used as base for dll-interface class 'type2' +#pragma warning ( disable : 4275 ) +// 'identifier' : identifier was truncated to 'number' characters in the +// debug information +#pragma warning ( disable : 4786 ) +//'identifier' : decorated name length exceeded, name was truncated +#pragma warning ( disable : 4503 ) +// C++ exception specification ignored except to indicate a +// function is not __declspec(nothrow) +//#pragma warning ( disable : 4290 ) +// signed/unsigned mismatch +#pragma warning ( disable : 4018 ) +// return type for 'identifier' is '' (ie; not a UDT or reference to UDT. Will +// produce errors if applied using infix notation +//#pragma warning ( disable : 4284 ) +// 'type' : forcing value to bool 'true' or 'false' (performance warning) +// //#pragma warning ( disable : 4800 ) +#endif //_MSC_VER + +//----------------------------------------------------------------------------- +#endif //GDCMWIN32_H diff --git a/gdcm/Source/Common/zipstreamimpl.h b/gdcm/Source/Common/zipstreamimpl.h new file mode 100644 index 0000000..59858b9 --- /dev/null +++ b/gdcm/Source/Common/zipstreamimpl.h @@ -0,0 +1,352 @@ +/* +zipstream Library License: +-------------------------- + +The zlib/libpng License Copyright (c) 2003 Jonathan de Halleux. + +This software is provided 'as-is', without any express or implied warranty. In +no event will the authors be held liable for any damages arising from the use +of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim + that you wrote the original software. If you use this software in a + product, an acknowledgment in the product documentation would be + appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + +3. This notice may not be removed or altered from any source distribution + +Author: Jonathan de Halleux, dehalleux@pelikhan.com, 2003 + +Altered by: Andreas Zieringer 2003 for OpenSG project + made it platform independent, gzip conform, fixed gzip footer + +Altered by: Geoffrey Hutchison 2005 for Open Babel project + minor namespace modifications, VC++ compatibility + +Altered by: Mathieu Malaterre 2008, for GDCM project + when reading deflate bit stream in DICOM special handling of \0 is needed + also when writing deflate back to disk, the add_footer must be called +*/ + +/* +Code is from: + +http://www.codeproject.com/KB/stl/zipstream.aspx + + TODO: + +zran.c + index a zlib or gzip stream and randomly access it + - illustrates the use of Z_BLOCK, inflatePrime(), and + inflateSetDictionary() to provide random access + + So I might after all be able to implement seeking :) +*/ +#ifndef _ZIPSTREAM_H_ +#define _ZIPSTREAM_H_ + +#include +#include +#include +#include +#include +#include + +#include // memcpy +#include // EOF + +#include + +#ifdef WIN32 /* Window 95 & Windows NT */ +# define OS_CODE 0x0b +#endif +#if defined(MACOS) || defined(TARGET_OS_MAC) +# define OS_CODE 0x07 +#endif +#ifndef OS_CODE +# define OS_CODE 0x03 /* assume Unix */ +#endif + +namespace zlib_stream { + +namespace detail +{ + const int gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ + + /* gzip flag byte */ + const int gz_ascii_flag = 0x01; /* bit 0 set: file probably ascii text */ + const int gz_head_crc = 0x02; /* bit 1 set: header CRC present */ + const int gz_extra_field = 0x04; /* bit 2 set: extra field present */ + const int gz_orig_name = 0x08; /* bit 3 set: original file name present */ + const int gz_comment = 0x10; /* bit 4 set: file comment present */ + const int gz_reserved = 0xE0; /* bits 5..7: reserved */ +} + +/// default gzip buffer size, +/// change this to suite your needs +const size_t zstream_default_buffer_size = 4096; + +/// Compression strategy, see zlib doc. +enum EStrategy +{ + StrategyFiltered = 1, + StrategyHuffmanOnly = 2, + DefaultStrategy = 0 +}; + +//***************************************************************************** +// template class basic_zip_streambuf +//***************************************************************************** + +/** \brief A stream decorator that takes raw input and zips it to a ostream. + +The class wraps up the inflate method of the zlib library 1.1.4 http://www.gzip.org/zlib/ +*/ +template > +class basic_zip_streambuf : public std::basic_streambuf +{ +public: + typedef std::basic_ostream& ostream_reference; + typedef unsigned char byte_type; + typedef char char_type; + typedef byte_type* byte_buffer_type; + typedef std::vector byte_vector_type; + typedef std::vector char_vector_type; + typedef int int_type; + + basic_zip_streambuf(ostream_reference ostream, + int level, + EStrategy strategy, + int window_size, + int memory_level, + size_t buffer_size); + + ~basic_zip_streambuf(void); + + int sync (void); + int_type overflow (int_type c); + std::streamsize flush (void); + inline + ostream_reference get_ostream (void) const; + inline + int get_zerr (void) const; + inline + unsigned long get_crc (void) const; + inline + unsigned long get_in_size (void) const; + inline + long get_out_size(void) const; + +private: + + bool zip_to_stream(char_type *buffer, + std::streamsize buffer_size); + + ostream_reference _ostream; + z_stream _zip_stream; + int _err; + byte_vector_type _output_buffer; + char_vector_type _buffer; + unsigned long _crc; +}; + + +//***************************************************************************** +// template class basic_unzip_streambuf +//***************************************************************************** + +/** \brief A stream decorator that takes compressed input and unzips it to a istream. + +The class wraps up the deflate method of the zlib library 1.1.4 http://www.gzip.org/zlib/ +*/ +template > +class basic_unzip_streambuf : + public std::basic_streambuf +{ +public: + typedef std::basic_istream& istream_reference; + typedef unsigned char byte_type; + typedef charT char_type; + typedef byte_type* byte_buffer_type; + typedef std::vector byte_vector_type; + typedef std::vector char_vector_type; + typedef int int_type; + + /** Construct a unzip stream + * More info on the following parameters can be found in the zlib documentation. + */ + basic_unzip_streambuf(istream_reference istream, + int window_size, + size_t read_buffer_size, + size_t input_buffer_size); + + ~basic_unzip_streambuf(void); + + int_type underflow(void); + + /// returns the compressed input istream + inline + istream_reference get_istream (void); + inline + z_stream& get_zip_stream (void); + inline + int get_zerr (void) const; + inline + unsigned long get_crc (void) const; + inline + long get_out_size (void) const; + inline + long get_in_size (void) const; + + +private: + + void put_back_from_zip_stream (void); + + std::streamsize unzip_from_stream (char_type* buffer, + std::streamsize buffer_size); + + size_t fill_input_buffer (void); + + istream_reference _istream; + z_stream _zip_stream; + int _err; + byte_vector_type _input_buffer; + char_vector_type _buffer; + unsigned long _crc; +}; + +//***************************************************************************** +// template class basic_zip_ostream +//***************************************************************************** + +template > +class basic_zip_ostream : + public basic_zip_streambuf, + public std::basic_ostream +{ +public: + + typedef char char_type; + typedef std::basic_ostream& ostream_reference; + typedef std::basic_ostream ostream_type; + + inline + explicit basic_zip_ostream(ostream_reference ostream, + bool is_gzip = false, + int level = Z_DEFAULT_COMPRESSION, + EStrategy strategy = DefaultStrategy, + int window_size = -15 /*windowBits is passed < 0 to suppress zlib header */, + int memory_level = 8, + size_t buffer_size = zstream_default_buffer_size); + + ~basic_zip_ostream(void); + + inline + bool is_gzip (void) const; + inline + basic_zip_ostream& zflush (void); + void finished (void); + +// void make_gzip() +// { add_header(); _is_gzip = true; } + +private: + + basic_zip_ostream& add_header(void); + basic_zip_ostream& add_footer(void); + + bool _is_gzip; + bool _added_footer; +}; + +//***************************************************************************** +// template class basic_zip_istream +//***************************************************************************** + +template > +class basic_zip_istream : + public basic_unzip_streambuf, + public std::basic_istream +{ +public: + typedef std::basic_istream& istream_reference; + typedef std::basic_istream istream_type; + + explicit basic_zip_istream(istream_reference istream, + int window_size = -15 /*windowBits is passed < 0 to suppress zlib header */, + size_t read_buffer_size = zstream_default_buffer_size, + size_t input_buffer_size = zstream_default_buffer_size); + + inline + bool is_gzip (void) const; + inline + bool check_crc (void); + inline + bool check_data_size (void) const; + inline + long get_gzip_crc (void) const; + inline + long get_gzip_data_size(void) const; + +protected: + + int check_header (void); + void read_footer (void); + + bool _is_gzip; + long _gzip_crc; + long _gzip_data_size; +}; + +/// A typedef for basic_zip_ostream +typedef basic_zip_ostream zip_ostream; +/// A typedef for basic_zip_istream +typedef basic_zip_istream zip_istream; + +/// A typedef for basic_zip_ostream +//typedef basic_zip_ostream zip_wostream; +/// A typedef for basic_zip_istream +//typedef basic_zip_istream zip_wistream; + +//! Helper function to check whether stream is compressed or not. +inline bool isGZip(std::istream &is) +{ + const int gz_magic[2] = {0x1f, 0x8b}; + + int c1 = is.get(); + if(c1 != gz_magic[0]) + { + is.putback((char)c1); + return false; + } + + int c2 = is.get(); + if(c2 != gz_magic[1]) + { + is.putback((char)c2); + is.putback((char)c1); + return false; + } + + is.putback((char)c2); + is.putback((char)c1); + return true; +} + +#include "zipstreamimpl.hpp" + +} + +#endif // _ZIPSTREAM_H_ diff --git a/gdcm/Source/Common/zipstreamimpl.hpp b/gdcm/Source/Common/zipstreamimpl.hpp new file mode 100644 index 0000000..8115082 --- /dev/null +++ b/gdcm/Source/Common/zipstreamimpl.hpp @@ -0,0 +1,829 @@ +/* +zipstream Library License: +-------------------------- + +The zlib/libpng License Copyright (c) 2003 Jonathan de Halleux. + +This software is provided 'as-is', without any express or implied warranty. In +no event will the authors be held liable for any damages arising from the use +of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim + that you wrote the original software. If you use this software in a + product, an acknowledgment in the product documentation would be + appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + +3. This notice may not be removed or altered from any source distribution + +Author: Jonathan de Halleux, dehalleux@pelikhan.com, 2003 + +Altered by: Andreas Zieringer 2003 for OpenSG project + made it platform independent, gzip conform, fixed gzip footer + +Altered by: Geoffrey Hutchison 2005 for Open Babel project + minor namespace modifications, VC++ compatibility + +Altered by: Mathieu Malaterre 2008, for GDCM project + when reading deflate bit stream in DICOM special handling of \0 is needed + also when writing deflate back to disk, the add_footer must be called +*/ + +//***************************************************************************** +// template class basic_zip_streambuf +//***************************************************************************** + +//----------------------------------------------------------------------------- +// PUBLIC +//----------------------------------------------------------------------------- + +/** Construct a zip stream + * More info on the following parameters can be found in the zlib documentation. + */ + +template +basic_zip_streambuf::basic_zip_streambuf(ostream_reference ostream, + int level, + EStrategy strategy, + int window_size, + int memory_level, + size_t buffer_size) + : _ostream(ostream), + _output_buffer(buffer_size, 0), + _buffer(buffer_size, 0), + _crc(0) +{ + _zip_stream.zalloc = (alloc_func) 0; + _zip_stream.zfree = (free_func) 0; + + _zip_stream.next_in = NULL; + _zip_stream.avail_in = 0; + _zip_stream.avail_out = 0; + _zip_stream.next_out = NULL; + + if(level > 9) + level = 9; + + if(memory_level > 9) + memory_level = 9; + + _err=deflateInit2(&_zip_stream, level, Z_DEFLATED, + window_size, memory_level, + static_cast(strategy)); + this->setp( &(_buffer[0]), &(_buffer[_buffer.size()-1])); +} + +/** Destructor + */ +template +basic_zip_streambuf::~basic_zip_streambuf(void) +{ + flush(); + // _ostream.flush(); CM already done in flush() + _err=deflateEnd(&_zip_stream); +} + +/** Do the synchronization + * @todo + * document correctly! + */ +template +int basic_zip_streambuf::sync(void) +{ + if(this->pptr() && this->pptr() > this->pbase()) + { + /*int c =*/ overflow(EOF); + + // ACHTUNG wenn das drin ist hoert er nach dem ersten endl auf! + /* + if ( c == EOF) + return -1; + */ + } + + return 0; +} + +/** + * @todo + * document correctly! + */ +template +typename basic_zip_streambuf::int_type +basic_zip_streambuf::overflow(int_type c) +{ + int w = static_cast(this->pptr() - this->pbase()); + if (c != EOF) + { + *this->pptr() = (char)c; + ++w; + } + if (zip_to_stream(this->pbase(), w)) + { + this->setp(this->pbase(), this->epptr() - 1); + return c; + } + else + { + return EOF; + } +} + +/** flushes the zip buffer and output buffer. + * + * This method should be called at the end of the compression. Calling flush + * multiple times, will lower the compression ratio. + */ +template +std::streamsize basic_zip_streambuf::flush(void) +{ + std::streamsize written_byte_size = 0, total_written_byte_size = 0; + + size_t remainder = 0; + + // updating crc + _crc = crc32(_crc, _zip_stream.next_in, + _zip_stream.avail_in); + + do + { + _err = deflate(&_zip_stream, Z_FINISH); + if(_err == Z_OK || _err == Z_STREAM_END) + { + written_byte_size = static_cast(_output_buffer.size()) - _zip_stream.avail_out; + total_written_byte_size += written_byte_size; + // ouput buffer is full, dumping to ostream + _ostream.write( (const char_type*) &(_output_buffer[0]), + static_cast(written_byte_size/sizeof(char_type)*sizeof(char))); + + // checking if some bytes were not written. + if((remainder = written_byte_size%sizeof(char_type)) != 0) + { + // copy to the beginning of the stream + std::streamsize theDiff = written_byte_size-remainder; + //assert (theDiff > 0 && theDiff < std::numeric_limits::max()); + + memcpy(&(_output_buffer[0]), + &(_output_buffer[(unsigned int)theDiff]), remainder); + + } + + _zip_stream.avail_out = static_cast(_output_buffer.size() - remainder); + _zip_stream.next_out = &_output_buffer[remainder]; + } + } + while(_err == Z_OK); + + _ostream.flush(); + + return total_written_byte_size; +} + +/** returns a reference to the output stream + */ +template inline +typename basic_zip_streambuf::ostream_reference +basic_zip_streambuf::get_ostream(void) const +{ + return _ostream; +} + +/** returns the latest zlib error status + */ +template inline +int basic_zip_streambuf::get_zerr(void) const +{ + return _err; +} + +/** returns the crc of the input data compressed so far. + */ +template inline +unsigned long +basic_zip_streambuf:: get_crc(void) const +{ + return _crc; +} + +/** returns the size (bytes) of the input data compressed so far. + */ +template inline +unsigned long +basic_zip_streambuf::get_in_size(void) const +{ + return _zip_stream.total_in; +} + +/** returns the size (bytes) of the compressed data so far. + */ +template inline +long +basic_zip_streambuf::get_out_size(void) const +{ + return _zip_stream.total_out; +} + +//----------------------------------------------------------------------------- +// PRIVATE +//----------------------------------------------------------------------------- + +/** + * @todo + * document! + */ +template +bool basic_zip_streambuf::zip_to_stream( + char_type *buffer, + std::streamsize buffer_size) +{ + std::streamsize written_byte_size = 0, total_written_byte_size = 0; + + _zip_stream.next_in = (byte_buffer_type) buffer; + _zip_stream.avail_in = static_cast(buffer_size * sizeof(char_type)); + _zip_stream.avail_out = static_cast(_output_buffer.size()); + _zip_stream.next_out = &_output_buffer[0]; + size_t remainder = 0; + + // updating crc + _crc = crc32(_crc, _zip_stream.next_in, + _zip_stream.avail_in); + + do + { + _err = deflate(&_zip_stream, 0); + + if (_err == Z_OK || _err == Z_STREAM_END) + { + written_byte_size= static_cast(_output_buffer.size()) - + _zip_stream.avail_out; + total_written_byte_size += written_byte_size; + // ouput buffer is full, dumping to ostream + + _ostream.write((const char_type*) &_output_buffer[0], + static_cast(written_byte_size / sizeof(char_type))); + + // checking if some bytes were not written. + if((remainder = written_byte_size % sizeof(char_type)) != 0) + { + // copy to the beginning of the stream + std::streamsize theDiff = written_byte_size-remainder; + //assert(theDiff > 0 && theDiff < std::numeric_limits::max()); + memcpy(&_output_buffer[0], + &_output_buffer[(unsigned int)theDiff], + remainder); + } + + _zip_stream.avail_out = static_cast(_output_buffer.size()-remainder); + _zip_stream.next_out = &_output_buffer[remainder]; + } + } + while(_zip_stream.avail_in != 0 && _err == Z_OK); + + return _err == Z_OK; +} + + + + + + + +//***************************************************************************** +// template class basic_unzip_streambuf +//***************************************************************************** + +//----------------------------------------------------------------------------- +// PUBLIC +//----------------------------------------------------------------------------- + +/** Constructor + */ +template +basic_unzip_streambuf::basic_unzip_streambuf(istream_reference istream, + int window_size, + size_t read_buffer_size, + size_t input_buffer_size) + : _istream(istream), + _input_buffer(input_buffer_size), + _buffer(read_buffer_size), + _crc(0) +{ + // setting zalloc, zfree and opaque + _zip_stream.zalloc = (alloc_func) 0; + _zip_stream.zfree = (free_func) 0; + + _zip_stream.next_in = NULL; + _zip_stream.avail_in = 0; + _zip_stream.avail_out = 0; + _zip_stream.next_out = NULL; + + _err = inflateInit2(&_zip_stream, window_size); + + this->setg(&_buffer[0] + 4, // beginning of putback area + &_buffer[0] + 4, // read position + &_buffer[0] + 4); // end position +} + +/** + * @todo document! + */ +template +basic_unzip_streambuf::~basic_unzip_streambuf(void) +{ + inflateEnd(&_zip_stream); +} + + +/** + * @todo document! + */ +template +typename basic_unzip_streambuf::int_type +basic_unzip_streambuf::underflow(void) +{ + if(this->gptr() && ( this->gptr() < this->egptr())) + return * reinterpret_cast(this->gptr()); + + int n_putback = static_cast(this->gptr() - this->eback()); + if(n_putback > 4) + n_putback = 4; + + memcpy(&_buffer[0] + (4 - n_putback), + this->gptr() - n_putback, + n_putback * sizeof(char_type)); + + std::streamsize num = + unzip_from_stream(&_buffer[0] + 4, + static_cast((_buffer.size() - 4) * + sizeof(char_type))); + + if(num <= 0) // ERROR or EOF + return EOF; + + // reset buffer pointers + this->setg(&_buffer[0] + (4 - n_putback), // beginning of putback area + &_buffer[0] + 4, // read position + &_buffer[0] + 4 + num); // end of buffer + + // return next character + return * reinterpret_cast(this->gptr()); +} + +/** returns the compressed input istream + */ +template inline +typename basic_unzip_streambuf::istream_reference +basic_unzip_streambuf::get_istream(void) +{ + return _istream; +} + +/** returns the zlib stream structure + */ +template inline +z_stream & +basic_unzip_streambuf::get_zip_stream(void) +{ + return _zip_stream; +} + +/** returns the latest zlib error state + */ +template inline +int +basic_unzip_streambuf::get_zerr(void) const +{ + return _err; +} + +/** returns the crc of the uncompressed data so far + */ +template inline +unsigned long +basic_unzip_streambuf::get_crc(void) const +{ + return _crc; +} + +/** returns the number of uncompressed bytes + */ +template inline +long +basic_unzip_streambuf::get_out_size(void) const +{ + return _zip_stream.total_out; +} + +/** returns the number of read compressed bytes + */ +template inline +long +basic_unzip_streambuf::get_in_size(void) const +{ + return _zip_stream.total_in; +} + + +//----------------------------------------------------------------------------- +// PRIVATE +//----------------------------------------------------------------------------- + +/** + */ +template inline +void +basic_unzip_streambuf::put_back_from_zip_stream(void) +{ + if(_zip_stream.avail_in == 0) + return; + + _istream.clear(std::ios::goodbit); + _istream.seekg(-intf(_zip_stream.avail_in), + std::ios_base::cur); + + _zip_stream.avail_in = 0; +} + +/** + */ +template inline +std::streamsize +basic_unzip_streambuf::unzip_from_stream(char_type* buffer, + std::streamsize buffer_size) +{ + _zip_stream.next_out = + (byte_buffer_type) buffer; + _zip_stream.avail_out = + static_cast(buffer_size * sizeof(char_type)); + size_t count = _zip_stream.avail_in; + + do + { + if(_zip_stream.avail_in == 0) + count=fill_input_buffer(); + + if(_zip_stream.avail_in) + { + _err = inflate(&_zip_stream, Z_SYNC_FLUSH); + } + } + while(_err==Z_OK && _zip_stream.avail_out != 0 && count != 0); + + std::streamsize theSize = buffer_size - ((std::streamsize)_zip_stream.avail_out) / sizeof(char_type); +// assert (theSize >= 0 && theSize < std::numeric_limits::max()); + + // updating crc + _crc = crc32(_crc, (byte_buffer_type) buffer,(uInt)theSize); + + std::streamsize n_read = + buffer_size - _zip_stream.avail_out / sizeof(char_type); + + // check if it is the end + if (_err == Z_STREAM_END) + put_back_from_zip_stream(); + + return n_read; +} + + +/** + */ +template inline +size_t +basic_unzip_streambuf::fill_input_buffer(void) +{ + _zip_stream.next_in = &_input_buffer[0]; + _istream.read((char_type*) &_input_buffer[0], + static_cast(_input_buffer.size() / + sizeof(char_type))); + std::streamsize nbytesread = _istream.gcount()*sizeof(char_type); + if( !_istream ) + { + if( _istream.eof() ) + { + // Ok so we reached the end of file, since we did not read no header + // we have to explicitely tell zlib the compress stream ends, therefore + // we add an extra \0 character...it may not always be needed... + assert( nbytesread < (std::streamsize)(_input_buffer.size() / sizeof(char_type)) ); + _input_buffer[ (unsigned int)nbytesread ] = 0; + ++nbytesread; + } + } + + return _zip_stream.avail_in = (uInt)nbytesread; +} + + + + + + + +//***************************************************************************** +// template class basic_zip_ostream +//***************************************************************************** + +//----------------------------------------------------------------------------- +// PUBLIC +//----------------------------------------------------------------------------- + +/** + */ +template inline +basic_zip_ostream::basic_zip_ostream(ostream_reference ostream, + bool isgzip, + int level, + EStrategy strategy, + int window_size, + int memory_level, + size_t buffer_size) : + basic_zip_streambuf(ostream, level, strategy, window_size, + memory_level, buffer_size), + std::basic_ostream(this), + _is_gzip(isgzip), + _added_footer(false) +{ + if(_is_gzip) + add_header(); +} + +/** Destructor + */ +template +basic_zip_ostream::~basic_zip_ostream(void) +{ + //if(_is_gzip) + add_footer(); +} + +/** returns true if it is a gzip + */ +template inline +bool basic_zip_ostream::is_gzip(void) const +{ + return _is_gzip; +} + +/** flush inner buffer and zipper buffer + */ + +template inline +basic_zip_ostream& basic_zip_ostream::zflush(void) +{ + static_cast *>(this)->flush(); + static_cast *>(this)->flush(); + return *this; +} + +template inline +void basic_zip_ostream::finished(void) +{ + if(_is_gzip) + add_footer(); + else + zflush(); +} + + +//----------------------------------------------------------------------------- +// PRIVATE +//----------------------------------------------------------------------------- + +/** + * @todo document! + */ +template +basic_zip_ostream& basic_zip_ostream::add_header(void) +{ + char_type zero = 0; + + this->get_ostream() << static_cast(detail::gz_magic[0]) + << static_cast(detail::gz_magic[1]) + << static_cast(Z_DEFLATED) + << zero //flags + << zero<(OS_CODE); + + return *this; +} + +/** + * @todo document! + */ +template +basic_zip_ostream& basic_zip_ostream::add_footer(void) +{ + if(_added_footer) + return *this; + + zflush(); + + _added_footer = true; + + // Writes crc and length in LSB order to the stream. + unsigned long crc = this->get_crc(); + for(int n=0;n<4;++n) + { + this->get_ostream().put((char)(crc & 0xff)); + crc >>= 8; + } + + unsigned long length = this->get_in_size(); + for(int m=0;m<4;++m) + { + this->get_ostream().put((char)(length & 0xff)); + length >>= 8; + } + + return *this; +} + + + + + + +//***************************************************************************** +// template class basic_zip_istream +//***************************************************************************** + +//----------------------------------------------------------------------------- +// PUBLIC +//----------------------------------------------------------------------------- + +/** Constructor + */ +template +basic_zip_istream::basic_zip_istream(istream_reference istream, + int window_size, + size_t read_buffer_size, + size_t input_buffer_size) + : basic_unzip_streambuf(istream, window_size, + read_buffer_size, input_buffer_size), + std::basic_istream(this), + _is_gzip(false), + _gzip_crc(0), + _gzip_data_size(0) +{ + if(this->get_zerr() == Z_OK) + { + int check = check_header();(void)check; + //std::cerr << "check_header:" << check << std::endl; + } +} + +/** returns true if it is a gzip file + */ +template inline +bool +basic_zip_istream::is_gzip(void) const +{ + return _is_gzip; +} + +/** return crc check result + * + * This must be called after the reading of compressed data is finished! This + * method compares it to the crc of the uncompressed data. + * + * \return true if crc check is succesful + */ +template inline +bool +basic_zip_istream::check_crc(void) +{ + read_footer(); + return this->get_crc() == _gzip_crc; +} + +/** return data size check + */ +template inline +bool +basic_zip_istream::check_data_size(void) const +{ + return this->get_out_size() == _gzip_data_size; +} + +/** return the crc value in the file + */ +template inline +long +basic_zip_istream::get_gzip_crc(void) const +{ + return _gzip_crc; +} + +/** return the data size in the file + */ +template inline +long +basic_zip_istream::get_gzip_data_size(void) const +{ + return _gzip_data_size; +} + +//----------------------------------------------------------------------------- +// PROTECTED +//----------------------------------------------------------------------------- + +/** + * @todo document! + */ +template +int +basic_zip_istream::check_header(void) +{ + int method; /* method byte */ + int flagsbyte; /* flags byte */ + uInt len; + int c; + int err=0; + z_stream &zip_stream = this->get_zip_stream(); + + /* Check the gzip magic header */ + for(len = 0; len < 2; len++) + { + c = (int)this->get_istream().get(); + if (c != detail::gz_magic[len]) + { + if (len != 0) + this->get_istream().unget(); + if (c!= EOF) + { + this->get_istream().unget(); + } + + err = zip_stream.avail_in != 0 ? Z_OK : Z_STREAM_END; + _is_gzip = false; + return err; + } + } + + _is_gzip = true; + method = (int)this->get_istream().get(); + flagsbyte = (int)this->get_istream().get(); + if (method != Z_DEFLATED || (flagsbyte & detail::gz_reserved) != 0) + { + err = Z_DATA_ERROR; + return err; + } + + /* Discard time, xflags and OS code: */ + for (len = 0; len < 6; len++) + this->get_istream().get(); + + if ((flagsbyte & detail::gz_extra_field) != 0) + { + /* skip the extra field */ + len = (uInt)this->get_istream().get(); + len += ((uInt)this->get_istream().get())<<8; + /* len is garbage if EOF but the loop below will quit anyway */ + while (len-- != 0 && this->get_istream().get() != EOF) ; + } + if ((flagsbyte & detail::gz_orig_name) != 0) + { + /* skip the original file name */ + while ((c = this->get_istream().get()) != 0 && c != EOF) ; + } + if ((flagsbyte & detail::gz_comment) != 0) + { + /* skip the .gz file comment */ + while ((c = this->get_istream().get()) != 0 && c != EOF) ; + } + if ((flagsbyte & detail::gz_head_crc) != 0) + { /* skip the header crc */ + for (len = 0; len < 2; len++) + this->get_istream().get(); + } + err = this->get_istream().eof() ? Z_DATA_ERROR : Z_OK; + + return err; +} + +/** + * @todo document! + */ +template +void +basic_zip_istream::read_footer(void) +{ + if(_is_gzip) + { + _gzip_crc = 0; + for(int n=0;n<4;++n) + _gzip_crc += ((((int) this->get_istream().get()) & 0xff) << (8*n)); + + _gzip_data_size = 0; + for(int n=0;n<4;++n) + _gzip_data_size += + ((((int) this->get_istream().get()) & 0xff) << (8*n)); + } +} diff --git a/gdcm/Source/DataDictionary/06_03_list.txt b/gdcm/Source/DataDictionary/06_03_list.txt new file mode 100644 index 0000000..739c8cb --- /dev/null +++ b/gdcm/Source/DataDictionary/06_03_list.txt @@ -0,0 +1,238 @@ +# Created using: +# pdftotext -raw -nopgbrk 06_03pu.pdf 06_03.txt +# grep -B 1 "Attribute Name Tag Type Attribute Description" 06_03.txt > log +# cat log | grep -v "Attribute Name Tag Type Attribute Description" | grep -v "\-\-" > 06_03_list.txt + +Person Identification Macro Attributes Description +Content Item Macro Attributes Description +IMAGE SOP INSTANCE REFERENCE MACRO ATTRIBUTES +SERIES AND INSTANCE REFERENCE MACRO ATTRIBUTES +GENERAL ANATOMY MANDATORY MACRO ATTRIBUTES +GENERAL ANATOMY REQUIRED MACRO ATTRIBUTES +GENERAL ANATOMY OPTIONAL MACRO ATTRIBUTES +REQUEST ATTRIBUTES MACRO ATTRIBUTES +BASIC PIXEL SPACING CALIBRATION MACRO ATTRIBUTES +PATIENT MODULE ATTRIBUTES +SPECIMEN IDENTIFICATION MODULE ATTRIBUTES +CLINICAL TRIAL SUBJECT MODULE ATTRIBUTES +GENERAL STUDY MODULE ATTRIBUTES +PATIENT STUDY MODULE ATTRIBUTES +CLINICAL TRIAL STUDY MODULE ATTRIBUTES +GENERAL SERIES MODULE ATTRIBUTES +CLINICAL TRIAL SERIES MODULE ATTRIBUTES +FRAME OF REFERENCE MODULE ATTRIBUTES +Synchronization Module Attributes +GENERAL EQUIPMENT MODULE ATTRIBUTES +ENHANCED GENERAL EQUIPMENT MODULE ATTRIBUTES +GENERAL IMAGE MODULE ATTRIBUTES +IMAGE PLANE MODULE ATTRIBUTES +IMAGE PIXEL MODULE ATTRIBUTES +IMAGE PIXEL MACRO ATTRIBUTES +CONTRAST/BOLUS MODULE ATTRIBUTES +ENHANCED CONTRAST/BOLUS MODULE ATTRIBUTES +CINE MODULE ATTRIBUTES +MULTI-FRAME MODULE ATTRIBUTES +FRAME POINTERS MODULE ATTRIBUTES +MASK MODULE ATTRIBUTES +DISPLAY SHUTTER MODULE ATTRIBUTES +DISPLAY SHUTTER MACRO ATTRIBUTES +DEVICE MODULE ATTRIBUTES +INTERVENTION MODULE ATTRIBUTES +Table C.7.6.14-1 - ACQUISITION CONTEXT MODULE ATTRIBUTES +BITMAP DISPLAY SHUTTER MODULE ATTRIBUTES +MULTI-FRAME FUNCTIONAL GROUPS MODULE ATTRIBUTES +PIXEL MEASURES MACRO ATTRIBUTES +FRAME CONTENT MACRO ATTRIBUTES +PLANE POSITION MACRO ATTRIBUTES +PLANE ORIENTATION MACRO ATTRIBUTES +REFERENCED IMAGE MACRO ATTRIBUTES +DERIVATION IMAGE MACRO ATTRIBUTES +CARDIAC TRIGGER MACRO ATTRIBUTES +FRAME ANATOMY MACRO ATTRIBUTES +PIXEL VALUE TRANSFORMATION MACRO ATTRIBUTES +FRAME VOI LUT MACRO ATTRIBUTES +REAL WORLD VALUE MAPPING MACRO ATTRIBUTES +CONTRAST/BOLUS USAGE FUNCTIONAL GROUP MACRO ATTRIBUTES +PIXEL INTENSITY RELATIONSHIP LUT MACRO ATTRIBUTES +FRAME PIXEL SHIFT MACRO ATTRIBUTES +PATIENT ORIENTATION IN FRAME MACRO ATTRIBUTES +FRAME DISPLAY SHUTTER MACRO ATTRIBUTES +RESPIRATORY TRIGGER MACRO ATTRIBUTES +IRRADIATION EVENT IDENTIFICATION MACRO ATTRIBUTES +MULTI-FRAME DIMENSION MODULE ATTRIBUTES +CARDIAC SYNCHRONIZATION MODULE ATTRIBUTES +RESPIRATORY SYNCHRONIZATION MODULE ATTRIBUTES +BULK MOTION SYNCHRONIZATION MODULE ATTRIBUTES +SUPPLEMENTAL PALETTE COLOR TABLE LOOKUP MODULE ATTRIBUTES +PALETTE COLOR LOOKUP MODULE +CR SERIES MODULE ATTRIBUTES +CR IMAGE MODULE ATTRIBUTES +CT IMAGE MODULE ATTRIBUTES +MR IMAGE MODULE ATTRIBUTES +NM/PET PATIENT ORIENTATION MODULE ATTRIBUTES +NM IMAGE PIXEL MODULE ATTRIBUTES +NM MULTI-FRAME MODULE ATTRIBUTES +NM IMAGE MODULE ATTRIBUTES +NM ISOTOPE MODULE ATTRIBUTES +NM DETECTOR MODULE ATTRIBUTES +NM TOMO ACQUISITION MODULE ATTRIBUTES +NM MULTI-GATED ACQUISITION MODULE ATTRIBUTES +NM PHASE MODULE ATTRIBUTES +NM RECONSTRUCTION MODULE ATTRIBUTES +US REGION CALIBRATION MODULE ATTRIBUTES +US IMAGE MODULE ATTRIBUTES +SC EQUIPMENT MODULE ATTRIBUTES +SC IMAGE MODULE ATTRIBUTES +SC MULTI-FRAME IMAGE MODULE ATTRIBUTES +SC MULTI-FRAME VECTOR MODULE ATTRIBUTES +X-RAY IMAGE MODULE ATTRIBUTES +X-RAY ACQUISITION MODULE ATTRIBUTES +X-RAY COLLIMATOR MODULE ATTRIBUTES +X-RAY TABLE MODULE ATTRIBUTES +XA POSITIONER MODULE ATTRIBUTES +XRF POSITIONER MODULE ATTRIBUTES +X-RAY TOMOGRAPHY ACQUISITION MODULE ATTRIBUTES +X-RAY ACQUISITION DOSE MODULE ATTRIBUTES +X-RAY GENERATION MODULE ATTRIBUTES +X-RAY FILTRATION MODULE ATTRIBUTES +X-RAY GRID MODULE ATTRIBUTES +Table C.8-37 - RT SERIES MODULE ATTRIBUTES +Table C.8-60 - PET SERIES MODULE ATTRIBUTES +Table C.8-61 - PET ISOTOPE MODULE ATTRIBUTES +Table C.8-62 - PET MULTI-GATED ACQUISITION MODULE ATTRIBUTES +Table C.8-63 - PET IMAGE MODULE ATTRIBUTES +DX SERIES MODULE ATTRIBUTES +DX ANATOMY IMAGED MODULE ATTRIBUTES +DX IMAGE MODULE ATTRIBUTES +DX DETECTOR MODULE ATTRIBUTES +DIGITAL X-RAY DETECTOR MACRO ATTRIBUTES +DX POSITIONING MODULE ATTRIBUTES +MAMMOGRAPHY SERIES MODULE ATTRIBUTES +MAMMOGRAPHY IMAGE MODULE ATTRIBUTES +INTRA-ORAL SERIES MODULE ATTRIBUTES +INTRA-ORAL IMAGE MODULE ATTRIBUTES +VL IMAGE MODULE ATTRIBUTES +Slide Coordinates Module Attributes +ENHANCED MR IMAGE MODULE ATTRIBUTES +MR IMAGE AND SPECTROSCOPY INSTANCE MACRO +MR IMAGE DESCRIPTION MACRO ATTRIBUTES +MR PULSE SEQUENCE MODULE ATTRIBUTES +MR IMAGE FRAME TYPE MACRO ATTRIBUTES +MR TIMING AND RELATED PARAMETERS MACRO ATTRIBUTES +MR FOV/GEOMETRY MACRO ATTRIBUTES +MR ECHO MACRO ATTRIBUTES +MR MODIFIER MACRO ATTRIBUTES +MR IMAGING MODIFIER MACRO ATTRIBUTES +MR RECEIVE COIL MACRO ATTRIBUTES +MR TRANSMIT COIL MACRO ATTRIBUTES +MR DIFFUSION MACRO ATTRIBUTES +MR AVERAGES MACRO ATTRIBUTES +MR SPATIAL SATURATION MACRO ATTRIBUTES +MR METABOLITE MAP MACRO ATTRIBUTES +MR VELOCITY ENCODING MACRO ATTRIBUTES +MR SERIES MODULE ATTRIBUTES +MR SPECTROSCOPY MODULE ATTRIBUTES +MR SPECTROSCOPY PULSE SEQUENCE MODULE ATTRIBUTES +MR SPECTROSCOPY FRAME TYPE MACRO ATTRIBUTES +MR SPECTROSCOPY FOV/GEOMETRY MACRO ATTRIBUTES +MR SPECTROSCOPY DATA MODULE ATTRIBUTES +MR SPECTROSCOPY DESCRIPTION MACRO ATTRIBUTES +CT SERIES MODULE ATTRIBUTES +ENHANCED CT IMAGE MODULE ATTRIBUTES +CT IMAGE FRAME TYPE MACRO ATTRIBUTES +CT ACQUISITION TYPE MACRO ATTRIBUTES +CT ACQUISITION DETAILS MACRO ATTRIBUTES +CT TABLE DYNAMICS MACRO ATTRIBUTES +CT GEOMETRY MACRO ATTRIBUTES +CT RECONSTRUCTION MACRO ATTRIBUTES +CT EXPOSURE MACRO ATTRIBUTES +CT X-RAY DETAILS SEQUENCE MACRO ATTRIBUTES +CT PIXEL VALUE TRANSFORMATION MACRO ATTRIBUTES +COMMON CT/MR IMAGE DESCRIPTION MACRO ATTRIBUTES +OPHTHALMIC PHOTOGRAPHY SERIES MODULE ATTRIBUTES +OPHTHALMIC PHOTOGRAPHY IMAGE MODULE ATTRIBUTES +OPHTHALMIC PHOTOGRAPHIC PARAMETERS MODULE ATTRIBUTES +OPHTHALMIC PHOTOGRAPHY ACQUISITION PARAMETERS MODULE ATTRIBUTES +OCULAR REGION IMAGED MODULE ATTRIBUTES +STEREOMETRIC SERIES MODULE ATTRIBUTES +STEREOMETRIC RELATIONSHIP MODULE ATTRIBUTES +XA/XRF SERIES MODULE ATTRIBUTES +Enhanced XA/XRF Image Module Table +XA/XRF ACQUISITION MODULE ATTRIBUTES +X-RAY IMAGE INTENSIFIER MODULE ATTRIBUTES +X-RAY DETECTOR MODULE ATTRIBUTES +XA/XRF FRAME CHARACTERISTICS MACRO ATTRIBUTES +X-RAY FIELD OF VIEW MACRO ATTRIBUTES +X-RAY EXPOSURE CONTROL SENSING REGIONS MACRO ATTRIBUTES +XA/XRF FRAME PIXEL DATA PROPERTIES MACRO ATTRIBUTES +X-RAY CALIBRATION DEVICE USAGE MACRO ATTRIBUTES +X-RAY OBJECT THICKNESS MACRO ATTRIBUTES +X-RAY FRAME ACQUISITION MACRO ATTRIBUTES +X-RAY PROJECTION PIXEL CALIBRATION MACRO ATTRIBUTES +X-RAY POSITIONER MACRO ATTRIBUTES +X-RAY TABLE POSITION MACRO ATTRIBUTES +X-RAY COLLIMATOR MACRO ATTRIBUTES +X-RAY ISOCENTER REFERENCE SYSTEM MACRO ATTRIBUTES +X-RAY GEOMETRY MACRO ATTRIBUTES +XA/XRF MULTI-FRAME PRESENTATION MODULE ATTRIBUTES +OVERLAY PLANE MODULE ATTRIBUTES +MULTI-FRAME OVERLAY MODULE ATTRIBUTES +DISPLAYED AREA MODULE ATTRIBUTES +GRAPHIC ANNOTATION MODULE ATTRIBUTES +SPATIAL TRANSFORMATION MODULE ATTRIBUTES +GRAPHIC LAYER MODULE ATTRIBUTES +Waveform Identification Module Attributes +Waveform Module Attributes +Table C.10-11 ­ Waveform Annotation Module Attributes +MODALITY LUT MODULE ATTRIBUTES +MODALITY LUT MACRO ATTRIBUTES +VOI LUT MODULE ATTRIBUTES +VOI LUT MACRO ATTRIBUTES +LUT Identification Module Attributes +OVERLAY ACTIVATION MODULE ATTRIBUTES +SOFTCOPY VOI LUT MODULE ATTRIBUTES +PRESENTATION SERIES MODULE ATTRIBUTES +PRESENTATION STATE IDENTIFICATION MODULE ATTRIBUTES +PRESENTATION STATE RELATIONSHIP MODULE ATTRIBUTES +PRESENTATION STATE RELATIONSHIP MACRO ATTRIBUTES +PRESENTATION STATE SHUTTER MODULE ATTRIBUTES +PRESENTATION STATE MASK MODULE ATTRIBUTES +PRESENTATION STATE BLENDING MODULE ATTRIBUTES +ICC PROFILE MODULE ATTRIBUTES +SOP COMMON MODULE ATTRIBUTES +ENCRYPTED ATTRIBUTES DATA SET ATTRIBUTES +COMMON INSTANCE REFERENCE MODULE ATTRIBUTES +SR DOCUMENT SERIES MODULE ATTRIBUTES +SR DOCUMENT GENERAL MODULE ATTRIBUTES +SOP INSTANCE REFERENCE MACRO ATTRIBUTES +Identified Person or Device Macro Attributes +SR DOCUMENT CONTENT MODULE ATTRIBUTES +DOCUMENT CONTENT MACRO ATTRIBUTES +DOCUMENT RELATIONSHIP MACRO ATTRIBUTES +KEY OBJECT DOCUMENT SERIES MODULE ATTRIBUTES +KEY OBJECT DOCUMENT MODULE ATTRIBUTES +NUMERIC MEASUREMENT MACRO ATTRIBUTES +CODE MACRO ATTRIBUTES +COMPOSITE OBJECT REFERENCE MACRO ATTRIBUTES +IMAGE REFERENCE MACRO ATTRIBUTES +WAVEFORM REFERENCE MACRO ATTRIBUTES +SPATIAL COORDINATES MACRO ATTRIBUTES +TEMPORAL COORDINATES MACRO ATTRIBUTES +CONTAINER MACRO ATTRIBUTES +RAW DATA MODULE ATTRIBUTES +SPATIAL REGISTRATION SERIES MODULE ATTRIBUTES +SPATIAL REGISTRATION MODULE ATTRIBUTES +SPATIAL FIDUCIALS SERIES MODULE ATTRIBUTES +SPATIAL FIDUCIALS MODULE ATTRIBUTES +Hanging Protocol Definition Module Attributes +Hanging Protocol Environment Module Attributes +Hanging Protocol Display Module Attributes +Hanging Protocol Selector Attribute Context Macro Attributes +Hanging Protocol Selector Attribute Value Macro Attributes +Encapsulated Document Series Module Attributes +Encapsulated Document Module Attributes +REAL WORLD VALUE MAPPING SERIES MODULE ATTRIBUTES +REAL WORLD VALUE MAPPING MODULE ATTRIBUTES +FILE-SET IDENTIFICATION MODULE +DIRECTORY INFORMATION MODULE +HANGING PROTOCOL KEYS diff --git a/gdcm/Source/DataDictionary/Agfa.xml b/gdcm/Source/DataDictionary/Agfa.xml new file mode 100644 index 0000000..05040af --- /dev/null +++ b/gdcm/Source/DataDictionary/Agfa.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdcm/Source/DataDictionary/CMakeLists.txt b/gdcm/Source/DataDictionary/CMakeLists.txt new file mode 100644 index 0000000..b6a4ba5 --- /dev/null +++ b/gdcm/Source/DataDictionary/CMakeLists.txt @@ -0,0 +1,128 @@ +# Define the srcs for Data Dictionary +# DICT + +# Add the include paths +include_directories( + "${GDCM_SOURCE_DIR}/Source/Common" + "${GDCM_BINARY_DIR}/Source/Common" + "${GDCM_SOURCE_DIR}/Source/DataStructureAndEncodingDefinition" + "${GDCM_SOURCE_DIR}/Source/DataDictionary" + "${GDCM_SOURCE_DIR}/Source/InformationObjectDefinition" + ) + + +#----------------------------------------------------------------------------- +# DICOM dictionary stuff +#set(PREP_DICT_SRCS +# ${GDCM_SOURCE_DIR}/Source/DataDictionary/gdcmDictConverter.cxx +# ${GDCM_SOURCE_DIR}/Source/DataDictionary/gdcmPrepDict.cxx +# ) +# +#add_executable(PrepDict ${PREP_DICT_SRCS} +# "${GDCM_SOURCE_DIR}/Source/Common/gdcmSwapCode.cxx" +# "${GDCM_SOURCE_DIR}/Source/DataStructureAndEncodingDefinition/gdcmVR.cxx" +# "${GDCM_SOURCE_DIR}/Source/DataStructureAndEncodingDefinition/gdcmVM.cxx" +# ) +# +#add_executable(PrepGroupName +# ${GDCM_SOURCE_DIR}/Source/DataDictionary/gdcmPrepGroupName.cxx +# ) +# +# get_target_property( PREP_DICT +# PrepDict +# LOCATION +# ) +# get_target_property( PREP_GROUPNAME +# PrepGroupName +# LOCATION +# ) +#set(DICT_LIST +# DICOMV3 +# NIH +# SPI +# ) +# +## List of file needed to get all dict into c++ code +#set(DICT_SRCS) +#set(DEFAULT_DICTS) +#foreach(dict ${DICT_LIST}) +# set(CXX_DICT ${GDCM_BINARY_DIR}/Source/DataDictionary/gdcm${dict}.cxx) +# set(DICT_SRCS ${DICT_SRCS} ${CXX_DICT}) +# add_custom_command( +# OUTPUT ${CXX_DICT} +# COMMAND ${PREP_DICT} +# ARGS ${GDCM_SOURCE_DIR}/Source/DataDictionary/${dict}.dic +# ${CXX_DICT} +# ${dict} +# DEPENDS ${GDCM_SOURCE_DIR}/Source/DataDictionary/${dict}.dic +# ${PREP_DICT} +# COMMENT "Generating gdcm${dict}.cxx based on ${dict}.dic" +# ) +#endforeach() +# +#add_custom_command( +# OUTPUT ${GDCM_BINARY_DIR}/Source/DataDictionary/gdcmDefaultGroupNames.cxx +# COMMAND ${PREP_GROUPNAME} +# ARGS ${GDCM_SOURCE_DIR}/Source/DataDictionary/GroupName.dic +# ${GDCM_BINARY_DIR}/Source/DataDictionary/gdcmDefaultGroupNames.cxx +# DEPENDS ${GDCM_SOURCE_DIR}/Source/DataDictionary/GroupName.dic +# ${PREP_GROUPNAME} +# COMMENT "Generating gdcmDefaultGroupNames.cxx based on GroupName.dic" +# ) +# + +# Since the file gdcmDefaultDicts.cxx does not exist, mark it as GENERATED: +#set_source_files_properties( +# "${GDCM_BINARY_DIR}/Source/gdcmDefaultDicts.cxx" GENERATED) + +#configure_file( +# ${GDCM_SOURCE_DIR}/Source/DataDictionary/gdcmDefaultDicts.cxx +# ${GDCM_BINARY_DIR}/Source/DataDictionary/gdcmDefaultDicts.cxx +# @ONLY +# ) + +set(DICT_SRCS + #${DICT_SRCS} # All the dicts cxx resources + gdcmDicts.cxx + gdcmDictEntry.cxx + gdcmDefaultDicts.cxx # pseudo generated file + gdcmPrivateDefaultDicts.cxx # pseudo generated file + gdcmGlobal.cxx + gdcmGroupDict.cxx + gdcmDefaultGroupNames.cxx + gdcmUIDs.cxx + gdcmSOPClassUIDToIOD.cxx + gdcmCSAHeaderDefaultDicts.cxx + ) + +add_library(gdcmDICT ${DICT_SRCS}) +set_target_properties(gdcmDICT PROPERTIES ${GDCM_LIBRARY_PROPERTIES} LINK_INTERFACE_LIBRARIES "") +target_link_libraries(gdcmDICT gdcmDSED gdcmIOD) + +# libs +install_library(gdcmDICT) +# PDB +install_pdb(gdcmDICT) +# include files +install_includes("*.h") + +set(XML_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/CSAHeader.xml + ${CMAKE_CURRENT_SOURCE_DIR}/Part6.xml + ${CMAKE_CURRENT_SOURCE_DIR}/Part7.xml + ${CMAKE_CURRENT_SOURCE_DIR}/UIDs.xml + ${CMAKE_CURRENT_SOURCE_DIR}/cp699.xml + ) + +set_source_files_properties( + ${XML_FILES} + PROPERTIES + MACOSX_PACKAGE_LOCATION Resources + ) + +#----------------------------------------------------------------------------- +# Install Part6.xml +install(FILES + ${XML_FILES} + DESTINATION ${GDCM_INSTALL_DATA_DIR}/XML COMPONENT Libraries +) diff --git a/gdcm/Source/DataDictionary/COPYRIGHT.dicom3tools b/gdcm/Source/DataDictionary/COPYRIGHT.dicom3tools new file mode 100644 index 0000000..c90683a --- /dev/null +++ b/gdcm/Source/DataDictionary/COPYRIGHT.dicom3tools @@ -0,0 +1,28 @@ +Copyright (c) 1993-2006, David A. Clunie DBA PixelMed Publishing. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are +permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of + conditions and the following disclaimers. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of + conditions and the following disclaimers in the documentation and/or other materials + provided with the distribution. + +3. Neither the name of PixelMed Publishing nor the names of its contributors may + be used to endorse or promote products derived from this software. + +This software is provided by the copyright holders and contributors "as is" and any +express or implied warranties, including, but not limited to, the implied warranties +of merchantability and fitness for a particular purpose are disclaimed. In no event +shall the copyright owner or contributors be liable for any direct, indirect, incidental, +special, exemplary, or consequential damages (including, but not limited to, procurement +of substitute goods or services; loss of use, data or profits; or business interruption) +however caused and on any theory of liability, whether in contract, strict liability, or +tort (including negligence or otherwise) arising in any way out of the use of this software, +even if advised of the possibility of such damage. + +This software has neither been tested nor approved for clinical use or for incorporation in +a medical device. It is the redistributor's or user's responsibility to comply with any +applicable local, state, national or international regulations. diff --git a/gdcm/Source/DataDictionary/CSADefaultDicts.xsl b/gdcm/Source/DataDictionary/CSADefaultDicts.xsl new file mode 100644 index 0000000..56f8e39 --- /dev/null +++ b/gdcm/Source/DataDictionary/CSADefaultDicts.xsl @@ -0,0 +1,346 @@ + + + + + + + + + + +// GENERATED FILE DO NOT EDIT +// $ xsltproc CSADefaultDicts.xsl CSAHeader.xml > gdcmCSAHeaderDefaultDicts.cxx + +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#ifndef GDCMCSAHEADERDICT_CXX +#define GDCMCSAHEADERDICT_CXX + +#include "gdcmCSAHeaderDict.h" +#include "gdcmCSAHeaderDictEntry.h" +#include "gdcmVR.h" +#include "gdcmVM.h" + + +namespace gdcm { +typedef struct +{ + const char *name; + const char *type; + VR::VRType vr; + VM::VMType vm; + const char *description; +} CSA_DICT_ENTRY; + +static const CSA_DICT_ENTRY CSAHeaderDataDict [] = { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Problem with element:(,) + + + + + + + + + + + + + + + + + + + + + + + {0,0,VR::INVALID,VM::VM0,0 } // Gard +}; + +void CSAHeaderDict::LoadDefault() +{ + unsigned int i = 0; + CSA_DICT_ENTRY n = CSAHeaderDataDict[i]; + while( n.name != 0 ) + { + CSAHeaderDictEntry e( n.name, n.vr, n.vm, n.description ); + AddCSAHeaderDictEntry( e ); + n = CSAHeaderDataDict[++i]; + } +} + +} // end namespace gdcm +#endif // GDCMCSAHEADERDICT_CXX + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {" + + "," + + " + + ,VR:: + + + INVALID + + + + + ,VM:: + + + + ," + + + "}, + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdcm/Source/DataDictionary/CSAHeader.xml b/gdcm/Source/DataDictionary/CSAHeader.xml new file mode 100644 index 0000000..197bdb8 --- /dev/null +++ b/gdcm/Source/DataDictionary/CSAHeader.xml @@ -0,0 +1,319 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdcm/Source/DataDictionary/DefaultDicts.xsl b/gdcm/Source/DataDictionary/DefaultDicts.xsl new file mode 100644 index 0000000..76e95bb --- /dev/null +++ b/gdcm/Source/DataDictionary/DefaultDicts.xsl @@ -0,0 +1,352 @@ + + + + + + + + + + +// GENERATED FILE DO NOT EDIT +// $ xsltproc DefaultDicts.xsl Part6.xml > gdcmDefaultDicts.cxx + +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#ifndef GDCMDEFAULTDICTS_CXX +#define GDCMDEFAULTDICTS_CXX + +#include "gdcmDicts.h" +#include "gdcmVR.h" +#include "gdcmDict.h" +#include "gdcmDictEntry.h" + +namespace gdcm { +typedef struct +{ + uint16_t group; + uint16_t element; + VR::VRType vr; + VM::VMType vm; + const char *name; + const char *keyword; + bool ret; +} DICT_ENTRY; + +static const DICT_ENTRY DICOMV3DataDict [] = { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Problem with element:(,) + + + + + + + + + + + + + + + + + + + + + // FIXME: need a dummy element + {0xffff,0xffff,VR::INVALID,VM::VM0,"","",true }, // dummy + {0xffff,0xffff,VR::INVALID,VM::VM0,0,0,true } // Gard +}; + +void Dict::LoadDefault() +{ + unsigned int i = 0; + DICT_ENTRY n = DICOMV3DataDict[i]; + while( n.name != 0 ) + { + Tag t(n.group, n.element); + DictEntry e( n.name, n.keyword, n.vr, n.vm, n.ret ); + AddDictEntry( t, e ); + n = DICOMV3DataDict[++i]; + } +} + +/* +void PrivateDict::LoadDefault() +{ + // TODO +} +*/ + +} // end namespace gdcm +#endif // GDCMDEFAULTDICTS_CXX + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {0x + + ,0x + + + + ,VR:: + + + INVALID + + + + + ,VM:: + + + + ," + + "," + + ", + + }, + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdcm/Source/DataDictionary/DefaultPrivateDicts.xsl b/gdcm/Source/DataDictionary/DefaultPrivateDicts.xsl new file mode 100644 index 0000000..313d783 --- /dev/null +++ b/gdcm/Source/DataDictionary/DefaultPrivateDicts.xsl @@ -0,0 +1,351 @@ + + + + + + + + + + +// GENERATED FILE DO NOT EDIT +// $ xsltproc DefaultPrivateDicts.xsl privatedicts.xml > gdcmPrivateDefaultDicts.cxx + +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#ifndef GDCMDEFAULTDICTS_CXX +#define GDCMDEFAULTDICTS_CXX + +#include "gdcmDicts.h" +#include "gdcmVR.h" +#include "gdcmDict.h" +#include "gdcmDictEntry.h" + +namespace gdcm { +typedef struct +{ + uint16_t group; + uint16_t element; + const char *owner; + VR::VRType vr; + VM::VMType vm; + const char *name; + bool ret; +} DICT_ENTRY; + +static const DICT_ENTRY DICOMV3DataDict [] = { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Problem with element:(,) + + + + + + + + + + + + + + + + + + + + + {0xffff,0xffff,0,VR::INVALID,VM::VM0,0,true } // Gard +}; + +void Dict::LoadDefault() +{ + unsigned int i = 0; + DICT_ENTRY n = DICOMV3DataDict[i]; + while( n.name != 0 ) + { + if( n.group % 2 == 0 ) + { + assert( n.owner == 0 ); + Tag t(n.group, n.element); + DictEntry e( n.name, n.vr, n.vm, n.ret ); + AddDictEntry( t, e ); + } + n = DICOMV3DataDict[++i]; + } +} + +void PrivateDict::LoadDefault() +{ + unsigned int i = 0; + DICT_ENTRY n = DICOMV3DataDict[i]; + while( n.name != 0 ) + { + if( n.group % 2 != 0 ) + { + assert( n.owner != 0 ); + PrivateTag t(n.group, n.element,n.owner); + DictEntry e( n.name, n.vr, n.vm, n.ret ); + AddDictEntry( t, e ); + } + n = DICOMV3DataDict[++i]; + } +} + +} // end namespace gdcm +#endif // GDCMDEFAULTDICTS_CXX + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {0x + + ,0x + + ," + + " + + ,VR:: + + + INVALID + + + + + ,VM:: + + + + ," + + ", + + }, + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdcm/Source/DataDictionary/GroupName.dic b/gdcm/Source/DataDictionary/GroupName.dic new file mode 100644 index 0000000..39a2403 --- /dev/null +++ b/gdcm/Source/DataDictionary/GroupName.dic @@ -0,0 +1,72 @@ +0000 CMD Command +0002 META Meta Element +0004 DIR Directory +0004 FST File Set +0008 ID Identifying +0009 SPII SPI Identifying +0010 PAT Patient +0012 CLI Clinical Trial +0018 ACQ Acquisition +0019 SPIA SPI Acquisition +0020 IMG Image +0021 SPIIM SPI Image +0022 OPHY Ophtalmology +0028 IMGP Image Presentation +0032 SDY Study +0038 VIS Visit +003a WAV Waveform +0040 PRC Procedure +0040 MOD Modality Worklist +0042 EDOC Encapsulated Document +0050 XAD XRay Angio Device +0050 DEV Device Informations +0054 NMI Nuclear Medicine +0060 HIS Histogram +0070 PRS Presentation State +0072 HST Hanging Protocol +0088 STO Storage +0088 MED Medicine +0100 AUTH Authorization +0400 DSIG Digital Signature +1000 COT Code Table +1010 ZMAP Zonal Map +2000 BFS Film Session +2010 BFB Film Box +2020 BIB Image Box +2030 BAB Annotation +2040 IOB Overlay Box +2050 PLUT Presentation LUT +2100 PJ Print Job +2110 PRINTER Printer +2120 QUE Queue +2130 PCT Print Content +2200 MEDIAC Media Creation +3002 RTI RT Image +3004 RTD RT Dose +3006 SSET RT StructureSet +3008 RTT RT Treatment +300A RTP RT Plan +300C RTR RT Relationship +300E RTA RT Approval +4000 TXT Text +4008 RES Results +4ffe MAC MAC Parameters +5000 CRV Curve +5002 CRV Curve +5004 CRV Curve +5006 CRV Curve +5008 CRV Curve +500a CRV Curve +500c CRV Curve +500e CRV Curve +5400 WFM Waveform Data +6000 OLY Overlays +6002 OLY Overlays +6004 OLY Overlays +6008 OLY Overlays +600a OLY Overlays +600c OLY Overlays +600e OLY Overlays +fffc GEN Generic +7fe0 PXL Pixel Data +ffff UNK Unknown diff --git a/gdcm/Source/DataDictionary/HarvestedPrivate.xml b/gdcm/Source/DataDictionary/HarvestedPrivate.xml new file mode 100644 index 0000000..16aa77f --- /dev/null +++ b/gdcm/Source/DataDictionary/HarvestedPrivate.xml @@ -0,0 +1,2885 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdcm/Source/DataDictionary/NIH.dic b/gdcm/Source/DataDictionary/NIH.dic new file mode 100644 index 0000000..038703b --- /dev/null +++ b/gdcm/Source/DataDictionary/NIH.dic @@ -0,0 +1,15 @@ +0018 106b UI 1 Synchronization Frame of Reference (RET) +0028 0013 US 1 Instants (RET) +0028 0015 US 1 UsedNbX ACR Special (RET) +0028 0016 US 1 UsedNbY ACR Special (RET) +0028 0017 US 1 UsedNbZ ACR Special (RET) +0028 0018 US 1 UsedNbT ACR Special (RET) +0028 0122 US 1 Waveform Padding Value (RET) +0028 0199 US 1 Special Code (RET) +003a 0002 SQ 1 Waveform Sequence (RET) +003a 0103 CS 1 Data Value Representation (RET) +0040 0552 SQ 1 Specimen Description Sequence (RET) +0040 0553 ST 1 Specimen Description (RET) +0040 09f8 SQ 1 Vital Stain Code Sequence (RET) +0040 a16a ST 1 Bibliographics Citation (RET) +0040 a992 ST 1 Uniform Resource Locator (RET) diff --git a/gdcm/Source/DataDictionary/ParseDicts.py b/gdcm/Source/DataDictionary/ParseDicts.py new file mode 100644 index 0000000..76abe9e --- /dev/null +++ b/gdcm/Source/DataDictionary/ParseDicts.py @@ -0,0 +1,401 @@ +#!/usr/bin/env python +""" +WARNING: This script has no meaning today (post 2008). +Since the standard is now available as .doc. If we assume +that the .doc is valid (according to standard only pdf should) +then there is not point in using this parser anymore today. + +Let's write our own python parser to clean up the pdf (after +pdftotext of course). +Instructions: run pdftotext like this: + +$ pdftotext -f 9 -l 81 -raw -nopgbrk 04_06PU.PDF 04_06PU-3.txt + +then run the python parser like this: + +$ python ParseDict.py 04_06PU.txt dicomV3.dic +""" +import re,os + +""" +PdfTextParser takes as input a text file (produced by pdftotext) +and create as output a clean file (ready to be processed) by +DicomV3Expander +Warning: PdfTextParser does not expand: +- (xxxx,xxxx to xxxx) xxxxxxxxxxxx +or +- (12xx, 3456) comment... + +""" +class PdfTextParser: + # Cstor + def __init__(self): + self._InputFilename = '' + self._OutputFilename = '' + self._Infile = 0 + self._OutLines = [] + self._PreviousBuffers = [] + + def SetInputFileName(self,s): + self._InputFilename = s + + def SetOutputFileName(self,s): + self._OutputFilename = s + + # Function returning if s is a comment for sure + def IsAComment(self,s): + #print s, len(s) + if s == "Tag Name VR VM": + return True + elif s == "PS 3.6-2003": + return True + elif s == "PS 3.6-2004": + return True + elif s == "PS 3.6-2006": + return True + elif s == "PS 3.6-2007": + return True + patt = re.compile('^Page [0-9]+$') + if( patt.match(s) ): + return True + patt = re.compile('^(.*)PS 3.6-2007(.*)$') + if( patt.match(s) ): + return True + patt = re.compile('^\s*(- Standard -)\s*') + if( patt.match(s) ): + return True + patt = re.compile('^\s*Tag\s+Name\s+VR\s+VM\s*$') + if( patt.match(s) ): + return True + return False + + def IsAStartingLine(self,s): + patt = re.compile('^\\([0-9a-fA-Fx]+,[0-9a-fA-F]+\\) (.*)$') + if( patt.match(s) ): + return True + return False + + def IsAFullLine(self,s): + #patt = re.compile('^\\([0-9a-fA-Fx]+,[0-9a-fA-F]+\\) (.*) [A-Z][A-Z] [0-9]$') + patt = re.compile('^\\([0-9a-fA-Fx]+,[0-9a-fA-F]+\\)\s+(.*)\s+[A-Z][A-Z]\s+([0-9n-]+)\s*$') + if( patt.match(s) ): + return True + patt = re.compile('^\\([0-9a-fA-Fx]+,[0-9a-fA-F]+\\)\s+(.*)\s+[A-Z][A-Z]\s+([0-9n-]+)\s+RET\s*$') + if( patt.match(s) ): + return True + print "IsAFullLine failed on", s + return False + + # FIXME this function could be avoided... + def IsSuspicious(self,s): + l = len(s) + if l > 80: + return True + return False + + def AddOutputLine(self,s): + assert not self.IsAComment(s) + self._OutLines.append(s + '\n') + + def Open(self): + self._Infile = file(self._InputFilename, 'r') + for line in self._Infile.readlines(): + line = line[:-1] # remove '\n' + if not self.IsAComment( line ): + if self.IsAStartingLine(line): + #print "Previous buffer:",self._PreviousBuffers + previousbuffer = ' '.join(self._PreviousBuffers) + if self.IsAStartingLine(previousbuffer): + if not self.IsSuspicious(previousbuffer): + self.AddOutputLine(previousbuffer) + else: + # this case should not happen if I were to rewrite the + # thing I should be able to clean that + #print "Suspicious:", previousbuffer + #print "List is:", self._PreviousBuffers + s = self._PreviousBuffers[0] + if self.IsAFullLine(s): + # That means we have a weird line that does not start + # as usual (xxxx,xxxx) therefore we tried constructing + # a buffer using a the complete previous line... + #print "Full line:", s + self.AddOutputLine(s) + s2 = ' '.join(self._PreviousBuffers[1:]) + #print "Other Full line:", s2 + self.AddOutputLine(s2) + else: + # we have a suspicioulsy long line, so what that could + # happen, let's check: + if self.IsAFullLine(previousbuffer): + self.AddOutputLine(previousbuffer) + else: + # This is the only case where we do not add + # previousbuffer to the _OutLines + print "Suspicious and Not a full line:", s + else: + if previousbuffer: + print "Not a buffer:", previousbuffer + # We can clean buffer, since only the case 'suspicious' + + # 'Not a full line' has not added buffer to the list + self._PreviousBuffers = [] + # In all cases save the line for potentially growing this line + assert not self.IsAComment(line) + self._PreviousBuffers.append(line) + else: + #print "Not a line",line + assert not self.IsAComment(line) + self._PreviousBuffers.append(line) + else: + #print "Comment:",line + previousbuffer = ' '.join(self._PreviousBuffers) + if previousbuffer and self.IsAStartingLine(previousbuffer): + #print "This line is added:", previousbuffer + self.AddOutputLine( previousbuffer ) + else: + #print "Line is comment:", line + print "Buffer is:", previousbuffer + # Ok this is a comment we can safely clean the buffer: + self._PreviousBuffers = [] + self.Write() + + def Write(self): + outfile = file(self._OutputFilename, 'w') + outfile.writelines( self._OutLines ) + outfile.close() + self._Infile.close() + + # Main function to call for parsing + def Parse(self): + self.Open() + + + +""" +This class is meant to expand line like: +- (xxxx,xxxx to xxxx) xxxxxxxxxxxx +or +- (12xx, 3456) comment... + +""" +class DicomV3Expander: + def __init__(self): + self._InputFilename = '' + self._OutputFilename = '' + self._OutLines = [] + + def SetInputFileName(self,s): + self._InputFilename = s + + def SetOutputFileName(self,s): + self._OutputFilename = s + + # Function to turn into lower case a tag: + # ex: (ABCD, EF01) -> (abcd, ef01) + def LowerCaseTag(self,s): + #print "Before:", s[:-1] + patt = re.compile('^(\\([0-9a-fA-F]+,[0-9a-fA-F]+\\))(.*)$') + m = patt.match(s) + if m: + s1 = m.group(1) + s2 = m.group(2) + return s1.lower() + s2 + else: + patt = re.compile('^[0-9a-fA-F]+ [0-9a-fA-F]+ [A-Z][A-Z] [0-9n-] .*$') + if patt.match(s): + return s + else: + print "Impossible case:", s + #os.sys.exit(1) + return "" + + def AddOutputLine(self,s): + if s.__class__ == list: + for i in s: + self._OutLines.append(i + '\n') + else: + self._OutLines.append(s + '\n') + + # Expand the line approriaetkly and also add it to the + # _OutLines list + def ExpandLine(self, s): + assert s[-1] == '\n' + s = s[:-1] # remove \n + list = [] + if self.NeedToExpansion(s, list): + self.AddOutputLine(list) # list != [] + elif self.NeedGroupXXExpansion(s, list): + self.AddOutputLine(list) # list != [] + elif self.NeedElemXXExpansion(s, list): + self.AddOutputLine(list) # list != [] + else: + self.AddOutputLine(self.LowerCaseTag(s)) + + # If line is like: + # (0020,3100 to 31FF) Source Image Ids RET + def NeedToExpansion(self,s, list): + patt = re.compile('^\\(([0-9a-fA-F]+),([0-9a-fA-F]+) to ([0-9a-fA-F]+)\\)(.*)$') + m = patt.match(s) + if m: + #print m.groups() + gr = m.group(1) + el_start = '0x'+m.group(2) + el_end = '0x'+m.group(3) + for i in range(eval(el_start), eval(el_end)): + el = hex(i)[2:] + l = '('+gr+','+el+')'+m.group(4) + list.append(l) + return True + return False + + # If line is like: + # (50xx,1200) Number of Patient Related Studies IS 1 + def NeedGroupXXExpansion(self,s,list): + patt = re.compile('^\\(([0-9a-fA-F]+)xx,([0-9a-fA-F]+)\\)(.*)$') + m = patt.match(s) + if m: + #print m.groups() + gr_start = m.group(1) + el = m.group(2) + #el_start = '0x'+m.group(2) + #el_end = '0x'+m.group(3) + start = '0x'+gr_start+'00' + end = '0x'+gr_start+'FF' + for i in range(eval(start), eval(end)): + gr = hex(i)[2:] + l = '('+gr+','+el+')'+m.group(3) + #print l + list.append(l) + return True + return False + + # If line is like: + # (2001,xx00) Number of Patient Related Studies IS 1 + def NeedElemXXExpansion(self,s,list): + patt = re.compile('^([0-9a-fA-F]+) ([0-9a-fA-F]+)xx(.*)$') + m = patt.match(s) + if m: + #print m.groups() + gr = m.group(1) + el_start = m.group(2) + start = '0x00' + end = '0xFF' + for i in range(eval(start), eval(end)): + el = '%02x'% i + l = '('+gr+','+el_start+el+')'+m.group(3) + print l + list.append(l) + return True + else: + patt = re.compile('^([0-9a-fA-F]+) xx([0-9a-fA-F]+)(.*)$') + m = patt.match(s) + if m: + #print m.groups() + gr = m.group(1) + el_start = m.group(2) + start = '0x00' + end = '0xFF' + for i in range(eval(start), eval(end)): + el = '%02x'% i + l = '('+gr+','+el+el_start+')'+m.group(3) + print l + list.append(l) + return True + return False + + def Write(self): + outfile = file(self._OutputFilename, 'w') + outfile.writelines( self._OutLines ) + outfile.close() + + def Expand(self): + infile = file(self._InputFilename,'r') + for line in infile.readlines(): + # ExpandLine also LowerCase the line + self.ExpandLine(line) # l is [1,n] lines + self.Write() + infile.close() + +""" +Converter class +Input is of type: + +(0008,0001) Length to End UL 1 RET + +output should be: + +0008 0001 UL 1 Length to End RET +""" +class Converter: + def __init__(self): + self._InputFilename = '' + self._OutputFilename = '' + self._OutLines = [] + def SetInputFileName(self,s): + self._InputFilename = s + + def SetOutputFileName(self,s): + self._OutputFilename = s + + def Open(self): + self._Infile = file(self._InputFilename, 'r') + for line in self._Infile.readlines(): + line = line[:-1] # remove '\n' + if (not self.IsAFullLine(line) ): + print "Convert pb:", line + + def IsAFullLine(self,s): + patt = re.compile('^\\(([0-9a-fA-Fx]+),([0-9a-fA-F]+)\\)\s+(.*)\s+([A-Z][A-Z])\s+([0-9n-]+)\s*$') + m = patt.match(s) + if( m ): + output = '' + output = m.group(1).lower() + ' ' + m.group(2).lower() + ' ' + m.group(4) + ' ' + m.group(5) + ' ' + m.group(3).strip() + self.AddOutputLine( output ) + return True + patt_ret = re.compile('^\\(([0-9a-fA-Fx]+),([0-9a-fA-F]+)\\)\s+(.*)\s+([A-Z][A-Z])\s+([0-9n-]+)\s+(RET)\s*$') + m = patt_ret.match(s) + if( m ): + output = '' + output = m.group(1).lower() + ' ' + m.group(2).lower() + ' ' + m.group(4) + ' ' + m.group(5) + ' ' + m.group(3).strip() + ' (' + m.group(6) + ')' + self.AddOutputLine( output ) + return True + return False + + def AddOutputLine(self,s): + self._OutLines.append(s + '\n') + + def Write(self): + outfile = file(self._OutputFilename, 'w') + outfile.writelines( self._OutLines ) + outfile.close() + self._Infile.close() + + def Convert(self): + self.Open() + self.Write() + +if __name__ == "__main__": + argc = len(os.sys.argv ) + if ( argc < 3 ): + print "Sorry, wrong list of args" + os.sys.exit(1) #error + + inputfilename = os.sys.argv[1] + outputfilename = os.sys.argv[2] + tempfile = "/tmp/mytemp" + + dp = PdfTextParser() + dp.SetInputFileName( inputfilename ) + dp.SetOutputFileName( tempfile ) + dp.Parse() + + exp = DicomV3Expander() + exp.SetInputFileName( tempfile ) + exp.SetOutputFileName( outputfilename ) + exp.Expand() + + conv = Converter() + conv.SetInputFileName( tempfile ) + conv.SetOutputFileName( '/tmp/myconv' ) + conv.Convert() + + #print dp.IsAStartingLine( "(0004,1212) File-set Consistency Flag US 1\n" ) diff --git a/gdcm/Source/DataDictionary/Part6.xml b/gdcm/Source/DataDictionary/Part6.xml new file mode 100644 index 0000000..fe0d2ba --- /dev/null +++ b/gdcm/Source/DataDictionary/Part6.xml @@ -0,0 +1,4007 @@ + + + + + ]> + + &part7; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + kVp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SHALL NOT BE USED + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SHALL NOT BE USED + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+
diff --git a/gdcm/Source/DataDictionary/Part67.xsl b/gdcm/Source/DataDictionary/Part67.xsl new file mode 100644 index 0000000..2f1969f --- /dev/null +++ b/gdcm/Source/DataDictionary/Part67.xsl @@ -0,0 +1,326 @@ + + + + + + + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ’–ï­Î¼ + '-µµ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +   + ­ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Unhandled + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/gdcm/Source/DataDictionary/Part6PDF.xsl b/gdcm/Source/DataDictionary/Part6PDF.xsl new file mode 100644 index 0000000..6ac0a2b --- /dev/null +++ b/gdcm/Source/DataDictionary/Part6PDF.xsl @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + PS 3.6-2007 +Page + + + + + - Standard - + + + + + + + + + + + + + + + Tag + + + Name + + + VR + + + VM + + + Retired + + + + + + abcdefghijklmnopqrstuvwxyz + ABCDEFGHIJKLMNOPQRSTUVWXYZ + + + + + + + + ( + + , + + ) + + + + + + + + + + + + + + + + + + + + + + RET + + + + + + + + + + + + + + diff --git a/gdcm/Source/DataDictionary/Part6todcm4che.xsl b/gdcm/Source/DataDictionary/Part6todcm4che.xsl new file mode 100644 index 0000000..459c6da --- /dev/null +++ b/gdcm/Source/DataDictionary/Part6todcm4che.xsl @@ -0,0 +1,159 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ' + + + + + + +De-identification + + + + + + + +'s + + + + + + + +Sub-operations + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + RET + + + + + + + + + + + + + diff --git a/gdcm/Source/DataDictionary/Part6togdcm1.xsl b/gdcm/Source/DataDictionary/Part6togdcm1.xsl new file mode 100644 index 0000000..92eb5f4 --- /dev/null +++ b/gdcm/Source/DataDictionary/Part6togdcm1.xsl @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + (RET) + + + + + + diff --git a/gdcm/Source/DataDictionary/Part7.xml b/gdcm/Source/DataDictionary/Part7.xml new file mode 100644 index 0000000..aa4e440 --- /dev/null +++ b/gdcm/Source/DataDictionary/Part7.xml @@ -0,0 +1,185 @@ + + + + + + The even number of bytes from the end of the value field to the beginning of the next group. + + + + + The affected SOP Class UID associated with the operation. + + + + + The requested SOP Class UID associated with the operation. + + + + + This field distinguishes the DIMSE operation conveyed by this Message. This field shall be set to one of the following values: + 0001H       C-STORE-RQ + 8001H       C-STORE-RSP + 0010H       C-GET-RQ + 8010H       C-GET-RSP + 0020H       C-FIND-RQ + 8020H       C-FIND-RSP + 0021H       C-MOVE-RQ + 8021H       C-MOVE-RSP + 0030H       C-ECHO-RQ + 8030H       C-ECHO-RSP + 0100H       N-EVENT-REPORT-RQ + 8100H       N-EVENT-REPORT-RSP + 0110H       N-GET-RQ + 8110H       N-GET-RSP + 0120H       N-SET-RQ + 8120H       N-SET-RSP + 0130H       N-ACTION-RQ + 8130H       N-ACTION-RSP + 0140H       N-CREATE-RQ + 8140H       N-CREATE-RSP + 0150H       N-DELETE-RQ + 8150H       N-DELETE-RSP + 0FFFH       C-CANCEL-RQ + + + + + Implementation-specific value that distinguishes this Message from other Messages. + + + + + Shall be set to the value of the Message ID (0000,0110) field used in associated request Message. + + + + + Shall be set to the DICOM AE Title of the destination DICOM AE to which the C-STORE sub-operations are being performed. + + + + + The priority shall be set to one of the following values: + LOW = 0002H + MEDIUM = 0000H + HIGH = 0001H + + + + + This field indicates if a Data Set is present in the Message. This field shall be set to the value of 0101H if no Data Set is present; any other value indicates a Data Set is included in the Message. + + + + + Confirmation status of the operation. See Annex C. + + + + + If status is Cxxx, then this field contains a list of +  the elements in which the error was detected. + + + + + This field contains an application-specific text description of the error detected. + + + + + This field shall optionally contain an application-specific error code. + + + + + Contains the UID of the SOP Instance for which this operation occurred. + + + + + Contains the UID of the SOP Instance for which this operation occurred. + + + + + Values for this field are application-specific. + + + + + This field contains an Attribute Tag for each of the n Attributes applicable. + + + + + Values for this field are application-specific. + + + + + The number of remaining C-STORE sub-operations to be invoked for the operation. + + + + + The number of C-STORE sub-operations associated with this operation that have completed successfully. + + + + + The number of C-STORE sub-operations associated with this operation that have failed. + + + + + The number of C-STORE sub-operations associated with this operation that generated warning responses. + + + + + Contains the DICOM AE Title of the DICOM AE that invoked the C-MOVE operation from which this C-STORE sub-operation is being performed. + + + + + Contains the Message ID (0000,0110) of the C-MOVE-RQ Message from which this C-STORE sub-operation is being performed. + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdcm/Source/DataDictionary/Part7.xsl b/gdcm/Source/DataDictionary/Part7.xsl new file mode 100644 index 0000000..3f34303 --- /dev/null +++ b/gdcm/Source/DataDictionary/Part7.xsl @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + diff --git a/gdcm/Source/DataDictionary/PartToGDCM.xsl b/gdcm/Source/DataDictionary/PartToGDCM.xsl new file mode 100644 index 0000000..ad8e60d --- /dev/null +++ b/gdcm/Source/DataDictionary/PartToGDCM.xsl @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + +This file was generated using the following commands: + + $ xsltproc PartToGDCM.xsl Part6.xml > tmp.xml + $ xsltproc order.xsl tmp.xml > DICOMV3.xml + + + Program: GDCM (Grass Root DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + + + 2009 + + + + + + + + + + + + + diff --git a/gdcm/Source/DataDictionary/README.txt b/gdcm/Source/DataDictionary/README.txt new file mode 100644 index 0000000..fc86b6d --- /dev/null +++ b/gdcm/Source/DataDictionary/README.txt @@ -0,0 +1,30 @@ +Part 3.6 + +The following files: + +acuson.xml +agfa.xml +camtron.xml +dicom3.xml +elscint.xml +gems.xml +isg.xml +other.xml +papyrus.xml +philips.xml +picker.xml +siemens.xml +spi.xml +toshiba.xml + +where all converted from the dicom3tools (see COPYRIGHT.dicom3tools) own format into an XML form + + + + + +GroupName.dic is missing the Variable Pixel Data + +Design of DICOMV3.xml +At one point in time the name attribute used to be in the character data of a description sub-element of entry. This was done to cope with case where the name would be a multi-line description. This was nice for some weird private attribute name in private dictionary...but this was adding more troubles than solving them. Indeed one would have to traverse each name to check for return line and handle them in a GUI. Therefore the attribute name in a public/private element should be single line (no \t, \n or \r) +TODO: should name be ASCII (issue with µ which is not ASCII) ? diff --git a/gdcm/Source/DataDictionary/SPI.dic b/gdcm/Source/DataDictionary/SPI.dic new file mode 100644 index 0000000..c190aca --- /dev/null +++ b/gdcm/Source/DataDictionary/SPI.dic @@ -0,0 +1,140 @@ +0009 0010 LO 1 Private Creator +0009 0011 LO 1 Private Creator +0009 0012 LO 1 Private Creator +0009 0013 LO 1 Private Creator +0009 0015 LO 1 UID +0009 0020 LO 1 Private Creator +0009 0030 LO 1 Private Creator +0009 0031 SH 1 Unknown (SIENET) +0009 0040 US 1 Data Object Type +0009 0041 SH 1 Data Object Subtype +0009 1010 LO 1 Comments +0009 1015 LO 1 SPI Image UID +0009 1040 US 1 Data Object Type +0009 1041 LO 1 Data Object Subtype +0009 1110 LO 1 Recognition Code +0009 1130 US 1 Byte Offset Of Original Header +0009 1131 US 1 Length Of Original Header +0009 1140 US 1 Byte Offset Of Pixelmatrix +0009 1141 UL 1 Length Of Pixelmatrix In Bytes +0009 1210 CS 1 Storage Mode +0009 1212 UL 1 Evaluation Mask Image +0009 1213 UN 1 TODO +0009 1214 UN 1 TODO +0009 1226 DA 1 Last Move Date +0009 1227 TM 1 Last Move Time +0009 1310 LO 1 Generator Identification Label +0009 1311 LO 1 Gantry Identification Label +0009 1314 LO 1 DAS Identification Label +0009 1315 LO 1 SMI Identification Label +0009 1316 LO 1 CPU Identification Label +0009 1320 SH 1 Header Version +0009 2010 LO 1 Private Creator +0009 2030 CS 1 Unknown (IMA) +0009 2031 SH 1 Unknown (TOPO) +0009 2032 SH 1 Unknown (NONE) +0009 2040 LO 1 Unknown (TOPO) +0009 2042 LO 1 Unknown (2.9) +0009 2050 DA 1 Unknown +0009 2051 TM 1 Unknown (093757.981000) +0009 3172 LO 1 Unknown 001S00OT002001082217540946 +0009 3175 LO 1 Unknown 001S60CT012001082209470996 +0011 0010 LO 1 Organ +0011 0011 LO 1 PrivateCreator +0011 0015 LO 1 Allergy Indication +0011 0020 LO 1 Pregnancy +0011 1010 LO 1 Organ +0011 1110 DA 1 Registration Date +0011 1111 TM 1 Registration Time +0011 1123 DS 1 Used Patient Weight +0019 0010 LO 1 PrivateCreator +0019 0012 LO 1 PrivateCreator +0019 0014 LO 1 PrivateCreator +0019 0015 LO 1 PrivateCreator +0019 1010 IS 1 Net Frequency +0019 1020 CS 1 Measurement Mode +0019 1030 CS 1 Calculation Mode +0019 1050 IS 1 Noise Level +0019 1060 IS 1 Number of Data Bytes +0019 1210 DS 1 Total Measurement Time Nominal +0019 1211 DS 1 Total Measurement Time Current +0019 1212 DS 1 Start Delay Time +0019 1213 DS 1 Dwell Time +0019 1214 IS 1 Number of Phases +0019 1216 UL 2 Sequence Control Mask +0019 1218 UL 1 Measurement Status Mask +0019 1220 IS 1 Number of Fourier Lines Nominal +0019 1221 IS 1 Number of Fourier Lines Current +0019 1226 IS 1 Number of Fourier Lines after Zero +0019 1228 IS 1 First Measured Fourier Line +0019 1230 IS 1 Acquisition Columns +0019 1231 IS 1 Reconstruction Columns +0019 1240 IS 1 Array Coil Element Number +0019 1241 UL 1 Array Coil Element Select Mask +0019 1242 UL 1 Array Coil Element Data Mask +0019 1245 IS 1 Array Coil ADC Pair Number +0019 1246 UL 1 Array Coil Combination Mask +0019 1250 IS 1 Number of Averages Current +0019 1260 DS 1 Flip Angle +0019 1270 IS 1 Number of Prescans +0019 1281 CS 1 Filter Type for Raw Data +0019 1283 CS 1 Filter Type for Image Data +0019 1285 CS 1 Filter Type for Phase Correction +0019 1287 CS 1 Normalization Filter Type for Image Data +0019 1290 IS 1 Number of Saturation Regions +0019 1294 DS 1 Image Rotation Angle +0019 1296 UL 3 Coil ID Mask +0019 1297 UL 2 Coil Class Mask +0019 1298 DS 3 Coil Position +0019 1412 DS 1 Magnetic Field Strength +0019 1414 DS 1 ADC Voltage +0019 1416 DS 1 ADC Offset +0019 1420 DS 1 Transmitter Amplitude +0019 1421 IS 1 Number of Transmitter Amplitudes +0019 1422 DS 1 Transmitter Attenuator +0019 1424 DS 1 Transmitter Calibration +0019 1426 DS 1 Transmitter Reference +0019 1450 DS 1 Receiver Total Gain +0019 1451 DS 1 Receiver Amplifier Gain +0019 1452 DS 1 Receiver Preamplifier Gain +0019 1454 DS 1 Receiver Cable Attenuation +0019 1455 DS 1 Receiver Reference Gain +0019 1456 DS 1 Receiver Filter Frequency +0019 1460 DS 1 Reconstruction Scale Factor +0019 1462 DS 1 Reference Scale Factor +0019 1470 DS 1 Phase Gradient Amplitude +0019 1471 DS 1 Readout Gradient Amplitude +0019 1472 DS 1 Selection Gradient Amplitude +0019 1480 DS 1 Gradient Delay Time +0019 1482 DS 1 Total Gradient Delay Time +0019 1490 LO 1 Sensitivity Correction Label +0019 14a0 IS 1 RF Watchdog Mask +0019 14a2 DS 1 RF Power Error Indicator +0019 14a5 DS 1 Specific Absorption Rate Whole Body +0019 14a6 DS 1 Specific Energy Dose +0019 14b0 UL 1 Adjustment Status Mask +0019 14d1 DS 1 Flow Sensitivity +0019 14d2 CS 1 Calculation Submode +0019 14d3 DS 1 Field of View Ratio +0019 14d4 IS 1 Base Raw Matrix Size +0019 14d5 IS 1 2D Oversampling Lines +0019 14d6 IS 1 3D Phase Oversampling Partitions +0019 14d7 IS 1 Echo Line Position +0019 14d8 IS 1 Echo Column Position +0019 14d9 IS 1 Lines Per Segment +0019 14da CS 1 Phase Coding Direction +0019 1510 LO 1 Parameter File Name +0019 1511 LO 1 Sequence File Name +0019 1512 LO 1 Sequence File Owner +0019 1513 LO 1 Sequence Description +0021 0010 LO 1 PrivateCreator +0021 1010 DS 1 Zoom +0021 1011 DS 1 Target +0021 1020 US 1 ROI Mask +0029 0060 LO 1 Compression Algorithm +7001 0010 LO 1 PrivateCreator +7001 1010 LO 1 Dummy +7003 0010 LO 1 PrivateCreator +7003 1010 LO 1 Header +7005 0010 LO 1 PrivateCreator +7005 1010 LO 1 Dummy diff --git a/gdcm/Source/DataDictionary/Siemens.xml b/gdcm/Source/DataDictionary/Siemens.xml new file mode 100644 index 0000000..c568ace --- /dev/null +++ b/gdcm/Source/DataDictionary/Siemens.xml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdcm/Source/DataDictionary/TagKeywords.xsl b/gdcm/Source/DataDictionary/TagKeywords.xsl new file mode 100644 index 0000000..5c1e014 --- /dev/null +++ b/gdcm/Source/DataDictionary/TagKeywords.xsl @@ -0,0 +1,74 @@ + + + + + + + // GENERATED FILE DO NOT EDIT +// $ xsltproc TagKeywords.xsl Part6.xml > gdcmTagKeywords.h + +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2012 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#ifndef GDCMTAGKEYWORDS_H +#define GDCMTAGKEYWORDS_H + +#include "gdcmAttribute.h" + +namespace gdcm { +namespace Keywords { + + + + +} +} + +#endif + + + + + + + // 0x + + , 0x + + SHALL NOT BE USED + + + + + typedef gdcm::Attribute<0x + + , 0x + + > + + ; + + + + diff --git a/gdcm/Source/DataDictionary/TagToType.xsl b/gdcm/Source/DataDictionary/TagToType.xsl new file mode 100644 index 0000000..b82d9a1 --- /dev/null +++ b/gdcm/Source/DataDictionary/TagToType.xsl @@ -0,0 +1,121 @@ + + + + + + + + + +// GENERATED FILE DO NOT EDIT +// $ xsltproc TagToType.xsl Part6.xml > gdcmTagToType.h + +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#ifndef GDCMTAGTOTYPE_H +#define GDCMTAGTOTYPE_H + +#include "gdcmVR.h" +#include "gdcmVM.h" +#include "gdcmStaticAssert.h" + +namespace gdcm { +// default template: the compiler should only pick it up when the element is private: +template <uint16_t group,uint16_t element> struct TagToType { +//GDCM_STATIC_ASSERT( group % 2 ); +enum { VRType = VR::VRALL }; +enum { VMType = VM::VM1_n }; +}; +// template for group length: +template <uint16_t group> struct TagToType<group,0x0000> { +static const char* GetVRString() { return "UL"; } +typedef VRToType<VR::UL>::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; + + + + + + + + + TagToType<0x + + ,0x + + > + + template <> struct + + { + + static const char* GetVRString() { return " + + "; } + + typedef VRToType<VR:: + + >::Type Type; + + + enum { VRType = VR:: + + }; + + + enum { VMType = VM:: + + + + }; + + + static const char* GetVMString() { return " + + "; } + + }; + + + + + + +} // end namespace gdcm +#endif // GDCMTAGTOTYPE_H + + + diff --git a/gdcm/Source/DataDictionary/TagToVR.xsl b/gdcm/Source/DataDictionary/TagToVR.xsl new file mode 100644 index 0000000..1db8949 --- /dev/null +++ b/gdcm/Source/DataDictionary/TagToVR.xsl @@ -0,0 +1,76 @@ + + + + + + + + + +// GENERATED FILE DO NOT EDIT +// $ xsltproc TagToVR.xsl Part6.xml > gdcmTagToVR.cxx + +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmVR.h" +#include "gdcmVM.h" +#include "gdcmStaticAssert.h" + +namespace gdcm { +VR::VRType GetVRFromTag( Tag const & t ) { +if( t.IsGroupLength() ) return VR::UL; +uint32_t tag = t.GetElementTag(); +switch( tag ) { + + + + + + + + + case 0x + + + : + + + return VR:: + + ; + + + + +default: +return VR::INVALID; +} +} + +} // end namespace gdcm + + + diff --git a/gdcm/Source/DataDictionary/UIDToC++.xsl b/gdcm/Source/DataDictionary/UIDToC++.xsl new file mode 100644 index 0000000..37ef7da --- /dev/null +++ b/gdcm/Source/DataDictionary/UIDToC++.xsl @@ -0,0 +1,111 @@ + + + + + + + +// GENERATED FILE DO NOT EDIT +// $ xsltproc UIDToC++.xsl Part6.xml > gdcmUIDs.cxx + +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + + + +#ifndef GDCMUIDS_H +#define GDCMUIDS_H + + typedef enum { + + + + + uid_ + + + frameref_ + + + unhandled_ + + + + = + + , // + + + + + +} TSType; + typedef enum { + + + + + // + + + + Retired + + = + + , // + + + + +} TSName; +#endif // GDCMUIDS_H + +#ifdef GDCMUIDS_CXX + static const char * const TransferSyntaxStrings[][2] = { + + + {" + + "," + + "}, + + + { 0, 0 } +}; +#endif // GDCMUIDS_CXX + + + diff --git a/gdcm/Source/DataDictionary/UIDs.xml b/gdcm/Source/DataDictionary/UIDs.xml new file mode 100644 index 0000000..d274624 --- /dev/null +++ b/gdcm/Source/DataDictionary/UIDs.xml @@ -0,0 +1,283 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+
diff --git a/gdcm/Source/DataDictionary/VM.xsl b/gdcm/Source/DataDictionary/VM.xsl new file mode 100644 index 0000000..d7e87db --- /dev/null +++ b/gdcm/Source/DataDictionary/VM.xsl @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + diff --git a/gdcm/Source/DataDictionary/cp699.xml b/gdcm/Source/DataDictionary/cp699.xml new file mode 100644 index 0000000..5afae50 --- /dev/null +++ b/gdcm/Source/DataDictionary/cp699.xml @@ -0,0 +1,261 @@ + + + + + + Corrected Image + + + Compression Recognition Code + + + Compression Code + + + Compression Originator + + + Compression Label + + + Compression Description + + + Compression Sequence + + + Compression Step Pointers + + + Repeat Interval + + + Bits Grouped + + + Perimeter Table + + + Perimeter Value + + + Predictor Rows + + + Predictor Columns + + + Predictor Constants + + + Blocked Pixels + + + Block Rows + + + Block Columns + + + Row Overlap + + + Column Overlap + + + Bits Allocated + + + Burned In Annotation + + + Transform Label + + + Transform Version Number + + + Number of Transform Steps + + + Sequence of Compressed Data + + + Details of Coefficients + + + Rows For Nth Order Coefficients + + + Columns For Nth Order Coefficients + + + Coefficient Coding + + + Coefficient Coding Pointers + + + DCT Label + + + Data Block Description + + + Data Block + + + Normalization Factor Format + + + Zonal Map Number Format + + + Zonal Map Location + + + Zonal Map Format + + + Adaptive Map Format + + + Code Number Format + + + Code Label + + + Number of Table + + + Code Table Location + + + Bits For Code Word + + + Image Data Location + + + Pixel Spacing Calibration Type + + + Pixel Spacing Calibration Description + + + Pixel Intensity Relationship + + + Pixel Intensity Relationship Sign + + + Escape Triplet + + + Run Length Triplet + + + Huffman Table Size + + + Huffman Table Triplet + + + Shift Table Size + + + Shift Table Triplet + + + Zonal Map + + + Overlay Plane Origin + + + Overlay Compression Code + + + Overlay Compression Originator + + + Overlay Compression Label + + + Overlay Compression Description + + + Overlay Compression Step Pointers + + + Overlay Repeat Interval + + + Overlay Bits Grouped + + + Overlay Bits Allocated + + + Overlay Bit Position + + + Overlay Format + + + Overlay Location + + + Overlay Code Label + + + Overlay Number of Tables + + + Overlay Code Table Location + + + Overlay Bits For Code Word + + + Overlay Activation Layer + + + Pixel Data + + + Coefficients SDVN + + + Coefficients SDHN + + + Coefficients SDDN + + + Variable Pixel Data + + + Variable Next Data Group + + + Variable Coefficients SDVN + + + Variable Coefficients SDHN + + + Variable Coefficients SDDN + + diff --git a/gdcm/Source/DataDictionary/dcmtk.xsl b/gdcm/Source/DataDictionary/dcmtk.xsl new file mode 100644 index 0000000..cedc646 --- /dev/null +++ b/gdcm/Source/DataDictionary/dcmtk.xsl @@ -0,0 +1,255 @@ + + + + + + + + + + +# +# Copyright (C) 1994-2012, OFFIS e.V. +# All rights reserved. See COPYRIGHT file for details. +# +# This software and supporting documentation were developed by +# +# OFFIS e.V. +# R&D Division Health +# Escherweg 2 +# D-26121 Oldenburg, Germany +# +# +# Module: dcmdata +# +# Author: Andrew Hewett, Marco Eichelberg, Joerg Riesmeier +# +# Purpose: This is the global standard DICOM data dictionary for the DCMTK. +# +# This file contains the complete data dictionary from the 2011 edition of the +# DICOM standard. This also includes the non-private definitions from the +# DICONDE (Digital Imaging and Communication in Nondestructive Evaluation) and +# DICOS (Digital Imaging and Communications in Security) standard. +# +# In addition, the data dictionary entries from the following final text +# supplements and correction items have been incorporated: +# - Supplement 152. +# - CP 1064, 1123, 1137, 1138, 1147, 1188, 1204. +# +# Each line represents an entry in the data dictionary. Each line has 5 fields +# (Tag, VR, Name, VM, Version). Entries need not be in ascending tag order. +# +# Entries may override existing entries. +# +# Each field must be separated by a single tab. The tag values (gggg,eeee) +# must be in hexedecimal and must be surrounded by parentheses. Repeating +# groups are represented by indicating the range (gggg-gggg,eeee). By default +# the repeating notation only represents even numbers. A range where only +# odd numbers are valid is represented using the notation (gggg-o-gggg,eeee). +# A range can represent both even and odd numbers using the notation +# (gggg-u-gggg,eeee). The element part of the tag can also be a range. +# +# Comments have a '#' at the beginning of the line. +# +# Tag VR Name VM Version +# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# +#--------------------------------------------------------------------------- +# +# Private Creator Data Elements +# +(0009-o-ffff,0000) UL PrivateGroupLength 1 PRIVATE +(0009-o-ffff,0010-u-00ff) LO PrivateCreator 1 PRIVATE +(0001-o-0007,0000) UL IllegalGroupLength 1 ILLEGAL +(0001-o-0007,0010-u-00ff) LO IllegalPrivateCreator 1 ILLEGAL +# +#--------------------------------------------------------------------------- +# +# A "catch all" for group length elements +# +(0000-u-ffff,0000) UL GenericGroupLength 1 GENERIC +# +#--------------------------------------------------------------------------- +# +# Retired data elements from ACR/NEMA 2 (1988) +# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdcm/Source/DataDictionary/dicom3tools.xsl b/gdcm/Source/DataDictionary/dicom3tools.xsl new file mode 100644 index 0000000..b777937 --- /dev/null +++ b/gdcm/Source/DataDictionary/dicom3tools.xsl @@ -0,0 +1,94 @@ + + + + + + + + + + + + ( + + , + + + + + + + + + + ) VERS=" + + + + + 3 + + + + RET + + " VR=" + + + + + + + + + + + + + + + + + + " VM=" + + " Keyword=" + ' + + + + + + + + + + + + + + + + " Name=" + + " + + + + + diff --git a/gdcm/Source/DataDictionary/dicomhdr.html b/gdcm/Source/DataDictionary/dicomhdr.html new file mode 100644 index 0000000..282af63 --- /dev/null +++ b/gdcm/Source/DataDictionary/dicomhdr.html @@ -0,0 +1,2840 @@ + + + +Dtattributeimage + + +

Image Attributes

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Attribute NameTagTypeVRVMDescriptiomCreatorUnit
General Image Attributes    
AcquisitionDate0008,00223DA1A number identifying the single continuous gathering of data over a period of time which resulted in this imageacquisition 
ContentDate0008,00232CDA1The date the image data creation started. Required if image is part of a series in which the images are temporally relatedacquisition 
AcquisitionTime0008,00323TM1The time the acquisition of data that resulted in this image startedacquisition 
ContentTime0008,00332CTM1The time the image pixrl data creation started. Required if image is part of a series in which the images are temporally relatedacquisition 
Acquisition Datetime0008,002A3DT1The date and time that the acquisition of dada that result in this image started  
DerivationDescription0008,21113ST1A text description of how this image was derivedimage creator 
AcquisitionNumber0020,00122IS1Image identification characteristicsacquisition 
InstanceNumber0020,00132IS1A number that identifies this imageacquisition 
ImageComments0020,40003LT1User-defined comments about the imageacquisition user interface 
ImageInAcquisition0020,10023IS1Number of images that resulted from this acquisition of data  
ReferencedImageSequence0008,11403link1A sequence which provides reference to a set of Image SOP Class/Instance identifying other images significantly related to this image (localizer images)acquisition 
>Referenced SOP Class UID0008,11501CUI1Uniquely identifies the referenced SOP Classacquisition 
>Referenced SOP Instance UID0008,11551CUI1Uniquely identifies the referenced SOP Instanceacquisition 
> Referenced Frame Number0008,11603IS1-nReferences one or more image frames of a Multi-frame Image SOP Instance, identifying which frames are siginificantly related to this imageacquisition 
SourceImageSequence0008,21123link1A sequence which identifies the set of Image SOP Class/Instance pairs of the images which were use to derive this imageacquisition 
>Referenced SOP Class UID0008,11501CUI1Uniquely identifies the referenced SOP Classacquisition 
>Referenced SOP Instance UID0008,11551CUI1Uniquely identifies the referenced SOP Instanceacquisition 
> Referenced Frame Number0008,11603IS1-nReferences one or more image frames of a Multi-frame Image SOP Instance, identifying which frames are siginificantly related to this imageacquisition 
ImageType0008,00083CS1-nImage identification characteristicsacquisition 
Lossy Image Compression0028,03003CS1Specifies whether an image has undergone lossy compression. +Enumerated values: +00 = image has not been subjected to lossy compression. +01 = image has been subjected to lossy compressionimage creator 
Quality Control Image0008,00051CCS1Indicates whether or not this image is a quality control or phantom image. Enumerated values: YES, NOimage creator 
PatientOrientation0020,00202CSkPatient direction of the rows and columns of the image. Not required for MR images  
MR Image Attributes    
ImageType0008,00081CS1-nImage identification characteristicsacquisition 
Samples per Pixel0028,00021US1Number of samples (planes) in this imageacquisition 
PhotometricInterpretation0028,00041CS1Specifies the intended interpretation of the pixel dataacquisition 
BitsAllocated0028,01001US1Number of bits allocated for each pixel sample. Each sample shall have the same number of bits allocatedacquisition 
Scanning Sequence0018,00201CS1-nDescription of the type of data taken. Enumerated values: SE = Spin Echo; IR = Inversion Recovery; GR = Gradient Recalled; EP = Echo Planar; RM = Research Modeacquisition 
SequenceVariant0018,00211CS1-nVariant of the Scanning Sequenceacquisition 
ScanOptions0018,00222CS1-nParameters of scanning sequenceacquisition 
MRAcquisitionType0018,00232CS1Identification of date encoding scheme. +Enumerated Values: +2D = frequency x phase +3D = frequency x phase x phaseacquisition 
        
SequenceName0018,00243SH1User defined name for the Scanning Sequence and Sequence Varaint combinationacquisition 
AngioFlag0018,00253CS1Angio image indicator. Primary image for angio processing. +Enumerated values: +Y = image is Angio +N = image is not Angioacquisition 
RepetitionTime0018,00802CDS1The period of time in msec between the beginning of a pulse sequence and the beginning of a succeeding (essentially identical) pulse sequence. Required except when Scanning Sequence is EP and Sequnece Variant is not segmented k-spaceacquisitionmsec
EchoTime0018,00812DS1Time in msec between the middle of the excitation pulse and the peak of the echo produced. In the case of segmented k-space, the TE(eff) is the time between the middle of the excitation pulse to the peak of the echo that is used to cover the center of k-space)acquisitionmsec
InversionTime0018,00822CDS1Time in msec after the middle of inverting RF pulse to middle of excitation pulse to detect the amount of longitudinal magnetization. Required if Scanning Sequence has value of IRacquisitionmsec
NumberOfAverages0018,00833DS1Number of times a given pulse sequence is repeated before any parameter has changedacquisition 
ImagingFrequency0018,00843DS1Precession frquency in MHz of the nucleus being addressedacquisitionMHz
ImagedNucleus0018,00853SH1Nucleus that is resonant at the imaging frequencyacquisition 
EchoNumbers0018,00863IS1-nThe echo number used in generating this image. In the case of segmented k-space, it is the effective Echo Numberacquisition 
MagneticFieldStrength0018,00873DS1Nominal Field strength of MR magnet, in TeslaacquisitionTesla
SpacingBetweenSlices0018,00883DS1Spacing between slices, in mm. The spacing is measured from the center-to-center of each sliceacquisitionmm
NumberOfPhaseEncodingSteps0018,00893IS1Total number of lines in k-space in the y-direction collecting during acquisitionacquisition 
EchoTrainLength0018,00912IS1Number of lines in k-space acquired per excitation per imageacquisition 
PercentSampling0018,00933DS1Fraction of acquisition matrix lines acquired, expressed as a percentacquisition 
PercentPhaseFieldOfView0018,00943DS1Ration of field of view dimension in phase direction to field of view dimension in frequency direction, expressed as a percentacquisition 
PixelBandwidth0018,00953DS1Reciprocal of the total sampling period, in hertz per pixelacquisitionhertz/pixel
BeatRejectionFlag0018,10803CS1Beat length sorting has been applied. +Enumerated values: +Y = yes +N = noacquisition 
Low R-R Value0018,10813IS1R-R interval low limit for beat rejection, in msecacquisitionmsec
High R-R Value0018,10823IS1R-R interval high limit for beat rejection, in msecacquisitionmsec
TriggerTime0018,10602CDS1Time, in msec, between peak of the R wave and the peak of the echo produced. In the case of segmented k-space, the TE(eff) is the time between the peak of the echo that is used to cover the center of k-space. Required for Scan Options which include heart gatingacquisitionmsec
NominalInterval0018,10623IS1Average R-R interval used for the scans, in msecacquisitionmsec
IntervalsAcquired0018,10833IS1Number of R-R intervals acquiredacquisition 
IntervalsRejected0018,10833IS1Number of R-R intervals rejectedacquisition 
PVC Rejection0018,10853LO1Description of type of PVC rejection criteria usedacquisition 
Skip Beats0018,10863IS1Number of beats skipped after a detected arrhythmiaacquisition 
HeartRate0018,10883IS1Beats per minuteacquisition1/min
CardiacNumberOfImages0018,10903IS1Number of imagesb per cardiac cycleacquisition 
TriggerWindow0018,10943IS1Percent of R-R interval, based on Heart Rate (0018,1088), prescriped as a window for a valid/usable trigger  
ReconstructionDiameter0018,11003DS1Diameter in mm of the region from within which data were used in creating the reconstruction of the image. Data may exist outside this region and portions of the patient may exist outside the regionacquisition 
Receive Coil0018,12503SH1Received coil usedacquisition 
TransmittingCoil0018,12513SH1Transmitted coil usedacquisition 
AcquisitionMatrix0018,13103US4Dimension of acquired frequency/phase data before reconstruction. Multi-valued: frequency rows\frequency columns\phase rows\phase columnsacquisition 
PhaseEncodingDirection0018,13123CS1The axis of phase encoding with respect to the image. +Enumerated Values: +ROW = phase encoded in rows +COL = phase encoded in columnsacquisition 
FlipAngle0018,13143DS1Steady state angle in degrees to which the magnetic vector is flipped from the magnetic vector to the primary fieldacquisitiondegree
VariableFlipAngleFlag0018,13153CS1Flip angle variation applied during image acquisition. +Enumerated Values: +Y = yes +N = noacquisition 
SAR0018,13163DS1Calculated whole body specific absortion rate in watts/kilogramacquisitionWatt/kilogram
dbdt0018,13183DS1The rate of change of the gradient coil magnetic flux density with time (T/s)acquisitionTesla/sec
Contrast Bolus Attributes    
ContrastBolusAgent0018,00102LO1Contrast or bolus agentacquisition user interface 
ContrastBolusStartTime0018,10423TM1Time of start of injectionacquisition user interface 
ContrastBolusStopTime0018,10433TM1Time of end of contrast injectionacquisition user interface 
ContrastBolusTotalDose0018,10443DS1Total amount in milliliters of the indiluted contrast agentacquisition user interfaceml
Contrast Flow Rate(s)0018,10463DS1-nRate(s) of injection(s) in millilitres/secacquisition user interfaceml/sec
ContrastBolusVolume0018,10413DS1Volume injected in milliliters of diluted +contrast agentacquisition user interface 
ContrastFlowDurations0018,10473DS1-nDuration(s) of injection(s) in seconds. Each Contrast Flow Duration value shall correspond to a value of Contrast Flow Rate (0018,1046)acquisition user interfacesec
        
Contrast/Bolus Ingredient0018,10483CS1Active ingredient of agent, Defined Terms: IODINE, GADOLIMIUM, CARBON DIOXIDE, BARIUMacquisition user interface 
Contrast/Bolus Ingredient Concentration0018,10493DS1Milligrams of active ingredient per milliliter of (diluted) agentacquisition user interfacemg/ml
Image Pixel Attributes    
SamplesPerPixel0028,00021US1Number of samples (planes) in this imageacquisition 
PhotometricInterpretation0028,00041CS1Specifies the intended interpretation of the pixel dataacquisition 
Rows0028,00101US1Number of rows in the imageacquisition 
Columns0028,00101US1Number of columns in the imageacquisition 
PixelAspectRatio0028,00341CIS2Ratio of the vertical size and horizontal size of the pixels in the image specified by a pair of integer values where the first value is the vertical pixel size, and the second value is the horizontal pixel size. Required if the aspect ratio is not 1/1 and the Image Plane Module is not applicable to this Imageacquisition 
BitsAllocated0028,01001US1Number of bits allocated for each pixel sample. Each sample shall have the same number of bits allocatedacquisition 
BitsStored0028,01011US1Number of bits stored for each pixel sample. Each sample shall have the same number of bits storedacquisition 
HighBit0028,01021US1Most significant bit for pixel sample data. Each sample shall have the same high bitacquisition 
PixelRepresentation0028,01031US1Data representation of the pixel samples. Each sample shall have the same pixel representation. Enumerated values: +0000H = unsigned integer. +0001H = 2's complement.acquisition 
PixelData7FE0,00101OW/OB1A data stream of the pixel samples which comprises the imageacquisition 
Smallest Image Pixel Value0028,01063US/SS1The minimum actual pixel value encountered in this imageacquisition 
Largest Image Pixel Value0028.01073US/SS1The maximum actual pixel value encountered in this imageacquisition 
Image Plane Attributes    
SliceThickness0018,00502DS1Nominal slice thickness, in mmacquisitionmm
ImageOrientationPatient0020,00371DS6The direction cosines of the first row and the first column with respect to the patientacquisition 
ImagePositionPatient0020,00321DS3The x,y and z coordinates of the upper left and hand corner (first pixel transmitted) of the image, in mmacquisitionmm
SliceLocation0020,10413DS1Relative position of exposure expressed in mmacquisitionmm
PixelSpacing0028,00301DS2Physical distance in the patient between the center of each pixel, specified by a numeric pair-adjacent row spacing (delimiter) adjacent column spacing in mmacquisitionmm
VOI Lookup Table    
WindowCenter0028,10503DS1-nWindow centeracquisition/application 
WindowWidth0028,10501CDS1-nWindow widthacquisition/application 
WindowCenterWidthExplanation0028,10553LO1-nFree form explanation of the meaning of the Window Center and Width. Multiple values correspond to multiple Window Center and Width valuesacquisition/application 
Equipment Attributes       
Manufacturer0008,00702LO1Manufacturer of the equipment that produced the digital imagesacquisition/application 
InstitutionName0008,0080 3LO1Institution where the equipment is located that produced the digital imagesacquisition/application 
InstitutionAddress0008,00813ST1Mailing address of the institution where the equipment is located that produced the digital imagesacquisition/application 
ManufacturersModelName0008,10903LO1Manufacturer's model number of the equipment that produced the digital imagesacquisition/application 
DeviceSerialNumber0018,10003LO1Manufacturer's seriel number of the equipment that produced the digital imagesacquisition/application 
SoftwareVersions0018,10203LO1-nManufacturer's designation of software of the equipment that produced the digital imagesacquisition/application 
Overlay Idendification Attributes       
OverlayRows60xx,00101US1Number of Rows in Overlaypost-processing applications 
OverlayColumns60xx,00111US1Number of Columns in Overlaypost-processing applications 
OverlayType60xx,00401CS1Indicates whether this overlay represents a region of interest or other graphicspost-processing applications 
Overlay Origin60xx,00501US1Location of first overlay point with respect to pixel in the image, given as row\columnpost-processing applications 
OverlayBitsAllocated60xx,01001US1Number of bits allocated in the overlaypost-processing applications 
OverlayBitPosition60xx,01021US1Bit in which overlay is storedpost-processing applications 
Overlay Data60xx,30001COB/OW1Overlay pixel datapost-processing applications 
MEDCOM Header       
HeaderType0029,xx081CCS1Medcom header characteristics. Defined Terms: MEDCOM 1acquisition 
HeaderVersion0029,xx092CLO1Version of Medcom headeracquisition 
HeaderInfo0029,xx103OB1Manufacturer header infoacquisition 
HistoryInfo0029,xx203 1Patient registration historypatient registration 
MR and SC Private Attributes       
EchoLinePositionstream1IS1Fourier line position with the maximal echo for the performed acquisitionacquisition 
EchoColumnPositionstream1IS1Echo column position for the performed acquisitionacquisition 
EchoPartitionPositionstream1IS1Echo partition position for the performed acquisitionacquisition 
UsedChannelMaskstream1UL18 bit mask of the used receiver channels for the performed acquisition. +Example: +channel 0: 00000001 +channel 3: 00000111 +·acquisition 
Actual3DImaPartNumberstream1IS1Number of a 3D partitions beginning with 0acquisition 
ICE_Dimsstream1LO1The 9 used ICE object dimensions of the performed acquisition. +Combined/unset dimensions will be marked with "X". +E.g.: X_2_1_1_1_1_2_1_1acquisition 
B_valuestream IS1Diffusion effect in s/mm*mm of the ICE program for the performed acquisitionacquisitionsec/(mm*mm)
Filter1stream1IS Context vision filteracquisition 
Filter2stream1IS not usedacquisition 
ProtocolSliceNumberstream1IS1Number of the slice beginning with 0acquisition 
RealDwellTimestream1IS1The time in ns between the beginning of sampling one data point and the beginning of sampling of next data point in the acquired signal. This means the dwell time is the sampling rate during digital conversion of an acquired signalacquisitionnanosec
PixelFilestream1UN1Used raw data file for the performed acquisitionacquisition 
PixelFileNamestream1UN1Used raw data file name for the performed acquisition  
SliceMeasurementDurationstream1DS1Time duration between two slices of the performed acquisitionacquisitionmsec
AcquisitionMatrixTextstream1SH1Used acquisition matrix descriptionacquisition 
SequenceMaskstream1UL1Parameters used for acquisition, e.g. door open, interpolation, raw filter, Siemens seqence ....acquisition 
MeasuredFourierLinesstream1IS1Number of performed fourier linesacquisition 
FlowEncodingDirectionstream IS1Flow encoding directionacquisition 
FlowVencstream FD1Flow Quant attributeacquisition 
PhaseEncodingDirectionPositivestream IS1Phase encoding direction: 0 = negative; 1 = positiveacquisition 
NumberOfImagesInMosaicstream US1Number of slices in a mosaic imageacquisition 
DiffusionGradientDirectionstream FD3Diffusion in gradient directionacquisition 
ImageGroupstream US1Group of imagesacquisition 
SliceNormalVectorstream FD3X,y and z normal vector of the slicesacquisition 
DiffusionDirectionstream CS1Diffusion directionacquisition 
TimeAfterStartstream DS1Time delay after start of measurmentacquisition 
FlipAnglestream DS1Flip angle for SC imagesacquisitiondegree
SequenceNamestream SH1Sequence name for SC imagesacquisition 
RepetitionTimestream DS1Repetition time for SC imagesacquisitionmsec
EchoTimestream DS1Echo time for SC imagesacquisitionmsec
NumberOfAveragesstream DSnNumber of averages for SC imagesacquisition 
MR NonImage (Raw Data, Spectra) Attributes       
NonimageType0029,xx081CS1Data identification characteristics. Defined terms: RAW DATA NUM 4; SPEC NUM4acquisition 
NonimageVersion0029,xx093LO1Version of Non-image dataacquisition 
NonimageInfo0029,xx103OB1Description of Non-image dataacquisition 
NonimageData7FE1,xx102OB1Binary data streamacquisition 
ImageType0008,00083CS1-nImage identification characteristicsacquisition 
AcquisitionDate0008,00223DA1The date the acquisition of data startedacquisition 
AcquisitionTime0008,00323TM1The time the acquisition of data startedacquisition 
DerivationDescription0008,21113ST1A text description of how this data set was derivedacquisition 
AcquisitionNumber0020,00122IS1A number identifying the gathering of data over a period of time which resulted in this data set acquisition 
ImageNumberstream IS1A number that identifies this imageacquisition 
ImageCommentsstream LT1User-defined comments about the imageacquisition 
ReferencedImageSequencestream UInA sequence which provides reference to a set of Image SOP Class/Instance identifying other images significantly related to this image (localizer images)acquisition 
PatientOrientationstream CS1Patient direction of the rows and columns of the image. Not required for MR imagesacquisition 
ScanningSequencestream CSnDescription of the type of data taken. Enumerated values: SE = Spin Echo; IR = Inversion Recovery; GR = Gradient Recalled; EP = Echo Planar; RM = Research Modeacquisition 
SequenceNamestream SH1User defined name for the Scanning Sequence and Sequence Varaint combinationacquisition 
RepetitionTimestream DS1The period of time in msec between the beginning of a pulse sequence and the beginning of a succeeding (essentially identical) pulse sequence. Required except when Scanning Sequence is EP and Sequnece Variant is not segmented k-spaceacquisition 
EchoTimestream DS1Time in msec between the middle of the excitation pulse and the peak of the echo produced. In the case of segmented k-space, the TE(eff) is the time between the middle of the excitation pulse to the peak of the echo that is used to cover the center of k-space)acquisition 
InversionTimestream DS1Time in msec after the middle of inverting RF pulse to middle of excitation pulse to detect the amount of longitudinal magnetization. Required if Scanning Sequence has value of IRacquisition 
NumberOfAveragesstream DS1Number of averagesacquisition 
ImagingFrequencystream DS1Precession frquency in MHz of the nucleus being addressedacquisition 
ImagedNucleusstream SH1Nucleus that is resonant at the imaging frequencyacquisition 
EchoNumbersstream IS1The echo number used in generating this image. In the case of segmented k-space, it is the effective Echo Numberacquisition 
MagneticFieldStrengthstream DS1Nominal Field strength of MR magnet, in TeslaacquisitionTesla
NumberOfPhaseEncodingStepsstream IS1Total number of lines in k-space in the y-direction collecting during acquisitionacquisition 
EchoTrainLengthstream IS1Number of lines in k-space acquired per excitation per imageacquisition 
PercentSamplingstream DS1Fraction of acquisition matrix lines acquired, expressed as a percentacquisition 
PercentPhaseFieldOfViewstream DS1Ration of field of view dimension in phase direction to field of view dimension in frequency direction, expressed as a percentacquisition 
TriggerTimestream DS1Time, in msec, between peak of the R wave and the peak of the echo produced. In the case of segmented k-space, the TE(eff) is the time between the peak of the echo that is used to cover the center of k-space. Required for Scan Options which include heart gatingacquisition 
ReceivingCoilstream SH1Received coil usedacquisition 
TransmittingColistream SH1Transmitted coil usedacquisition 
AcquisitionMatrixTextstream US4Dimension of acquired frequency/phase data before reconstruction. Multi-valued: frequency rows\frequency columns\phase rows\phase columnsacquisition 
PhaseEncodingDirectionstream CS1The axis of phase encoding with respect to the image. +Enumerated Values: +ROW = phase encoded in rows +COL = phase encoded in columnsacquisition 
FlipAnglestream DS1Steady state angle in degrees to which the magnetic vector is flipped from the magnetic vector to the primary fieldacquisitionDegree
VariableFlipAngleFlagstream CS1Flip angle variation applied during image acquisition. +Enumerated Values: +Y = yes +N = noacquisition 
SARstream DS1Calculated whole body specific absortion rate in watts/kilogramacquisitionWatt/kilogram
dBdtstream DS3The rate of change of the gradient coil magnetic flux density with time (T/s)acquisitionTesla/sec
Rowsstream US1Number of rows in the imageacquisitionmm
Columnsstream US1Number of columns in the imageacquisitionmm
SliceThicknessstream DS1Nominal slice thickness, in mmacquisitionmm
ImagePositionPatientstream DS3The direction cosines of the first row and the first column with respect to the patientacquisition 
ImageOrientationPatientstream DS6The x,y and z coordinates of the upper left and hand corner (first pixel transmitted) of the image, in mm.acquisitionmm
SliceLocationstream DS1Relative position of exposure expressed in mmacquisitionmm
EchoLinePositionstream IS1Fourier line position with the maximal echo for the performed acquisitionacquisition 
EchoColumnPositionstream IS1Echo column position for the performed acquisitionacquisition 
EchoPartitionPositionstream IS1Echo partition position for the performed acquisitionacquisition 
Actual3DImaPartNumberstream IS1Number of a 3D partitions beginning with 0acquisition 
RealDwellTimestream IS1The time in ns between the beginning of sampling one data point and the beginning of sampling of next data point in the acquired signal. This means the dwell time is the sampling rate during digital conversion of an acquired signalacquisition 
ProtocolSliceNumberstream UN1Number of the slice beginning with 0acquisition 
PixelFilestream UN1Used raw data file for the performed acquisitionacquisition 
PixelFileNamestream LO1Used raw data file name for the performed acquisitionacquisition 
ICE_Dimsstream DS1The 9 used ICE object dimensions of the performed acquisition. +Combined/unset dimensions will be marked with "X". +E.g.: X_2_1_1_1_1_2_1_1acquisition 
PixelSpacingstream DS2Physical distance in the patient between the center of each pixel, specified by a numeric pair-adjacent row spacing (delimiter) adjacent column spacing in mmacquisitionmm
SourceImageSequencestream UInA sequence which identifies the set of Image SOP Class/Instance pairs of the images which were use to derive this imageacquisition 
PixelBandwidthstream DS1Reciprocal of the total sampling period, in hertz per pixelacquisition 
SliceMeasurementDurationstream DS1Time duration between two slices of the performed acquisitionacquisition 
SequenceMaskstream UL1Parameters used for acquisition, e.g. door open, interpolation, raw filter, Siemens seqence .·acquisition 
AcquisitionMatrixTextstream SH1Used acquisition matrix descriptionacquisition 
MeasuredFourierLinesstream IS1Number of performed fourier linesacquisition 
MR Protocol       
ulVersionstream3UL1Protocol versionacquisition 
tSequenceFileNamestream3ST1Sequence file name for actual measurement protocolacquisition 
tProtocolNamestream3ST1Name of actual measurement protocolacquisition 
tReferenceImage0stream3LO1Referenced imageacquisition 
tReferenceImage1stream3LO1Referenced imageacquisition 
tReferenceImage2stream3LO1Referenced imageacquisition 
lScanRegionPosSagstream3FD1Desired table position in series block coordinate systemacquisition 
lScanRegionPosCorstream3FD1Desired table position in series block coordinate systemacquisition 
lScanRegionPosTrastream3FD1Desired table position in series block coordinate systemacquisition 
ucScanRegionPosValidstream3SH1Valid flag for desired table position in series block coordinate systemacquisition 
aucSparestream3SH1Reservedacquisition 
lScanRegionDeltastream3SL1Scan Region Position/Move [mm]acquisitionmm
sProtConsistencyInfo.tBaselineStringstream3LO1Baseline consistence infoacquisition 
sProtConsistencyInfo.tGradCoilNamestream3SH1Coil name consistence infoacquisition 
sProtConsistencyInfo.tGradAmplifierNamestream3LO1Gradient amplifier consistence infoacquisition 
sProtConsistencyInfo.flNominalB0stream3FD1Nominal Bo compensation consistenceacquisition 
sGRADSPEC.sEddyCompensationX.aflAmplitudestream3FD5Eddy compensation x amplitude gradient system specificationacquisition 
sGRADSPEC.sEddyCompensationX.aflTimeConstantstream3FD5Eddy compensation x time parameter gradient system specificationacquisition 
sGRADSPEC.sEddyCompensationY.aflAmplitudestream3FD5Eddy compensation y amplitude gradient system specificationacquisition 
sGRADSPEC.sEddyCompensationY.aflTimeConstantstream3FD5Eddy compensation y time parameter gradient system specificationacquisition 
sGRADSPEC.sEddyCompensationZ.aflAmplitudestream3FD5Eddy compensation z amplitude gradient system specificationacquisition 
sGRADSPEC.sEddyCompensationZ.aflTimeConstantstream3FD5Eddy compensation z time parameter gradient system specificationacquisition 
sGRADSPEC.bB0CompensationValidstream3SL1B0 compensation gradient system specification valid flagacquisition 
sGRADSPEC.sCrossTermCompensationXY.aflAmplitudestream3FD5Crossterm compensation xy amplitude gradient system specificationacquisition 
sGRADSPEC.sCrossTermCompensationXY.aflTimeConstantstream3FD5Crossterm compensation xy time parameter gradient system specificationacquisition 
sGRADSPEC.sCrossTermCompensationXZ.aflAmplitudestream3FD5Crossterm compensation xz amplitude gradient system specificationacquisition 
sGRADSPEC.sCrossTermCompensationXZ.aflTimeConstantstream3FD5Crossterm compensation xz time parameter gradient system specificationacquisition 
sGRADSPEC.sCrossTermCompensationYX.aflAmplitudestream3FD5Crossterm compensation xz amplitude gradient system specificationacquisition 
sGRADSPEC.sCrossTermCompensationYX.aflTimeConstantstream3FD5Crossterm compensation yx time parameter gradient system specificationacquisition 
sGRADSPEC.sCrossTermCompensationYZ.aflAmplitudestream3FD5Crossterm compensation yz amplitude gradient system specificationacquisition 
sGRADSPEC.sCrossTermCompensationYZ.aflTimeConstantstream3FD5Crossterm compensation yz time parameter gradient system specificationacquisition 
sGRADSPEC.sCrossTermCompensationZX.aflAmplitudestream3FD5Crossterm compensation zx amplitude gradient system specificationacquisition 
sGRADSPEC.sCrossTermCompensationZX.aflTimeConstantstream3FD5Crossterm compensation zx time parameter gradient system specificationacquisition 
sGRADSPEC.sCrossTermCompensationZY.aflAmplitudestream3FD5Crossterm compensation zx amplitude gradient system specificationacquisition 
sGRADSPEC.sCrossTermCompensationZY.aflTimeConstantstream3FD5Crossterm compensation zy time parameter gradient system specificationacquisition 
sGRADSPEC.bCrossTermCompensationValidstream3SL1Crossterm compensation gradient system specification valid flagacquisition 
sGRADSPEC.lOffsetXstream3SL1Gradient offset x direction [bit pattern]acquisition 
sGRADSPEC.lOffsetYstream3SL1Gradient offset y direction [bit pattern]acquisition 
sGRADSPEC.lOffsetZstream3SL1Gradient offset z direction [bit pattern]acquisition 
sGRADSPEC.bOffsetValidstream3SL1Gradient offsets valid flagacquisition 
sGRADSPEC.lDelayXstream3SL1Gradient delay x directionacquisition 
sGRADSPEC.lDelayYstream3SL1Gradient delay y directionacquisition 
sGRADSPEC.lDelayYstream3SL1Gradient delay z directionacquisition 
sGRADSPEC.bDelayValidstream3SL1Gradient delay valid flagacquisition 
sGRADSPEC.flSensitivityXstream3FD1Gradient sensitivity x direction [mT/m]acquisitionmT/m
sGRADSPEC.flSensitivityYstream3FD1Gradient sensitivity y direction [mT/m]acquisitionmT/m
sGRADSPEC.flSensitivityZstream3FD1Gradient sensitivity z direction [mT/m]acquisitionmT/m
sGRADSPEC.bSensitivityValidstream3SL1Gradient sensitivity valid flagacquisition 
sGRADSPEC.flGSWDMinRiseTimestream3FD1Minimum gradient rise time for mode GRAD_GSWD_RISETIME acquisitionmA
sGRADSPEC.alShimCurrentstream3SL15Shim current parameter [mA]acquisition 
sGRADSPEC.bShimCurrentValidstream3SL1Shim current parameter valid flagacquisition 
sGRADSPEC.ucModestream3SH1Gradient mode: fast, normal, whisperacquisition 
sGRADSPEC.ucSpare0stream3SH1Reservedacquisition 
sGRADSPEC.ucSpare1stream3SH1Reservedacquisition 
sGRADSPEC.ucSpare2stream3SH1Reservedacquisition 
sTXSPEC.asNucleusInfo[0].tNucleusstream3SH1Transmitter system nucleusacquisition 
sTXSPEC.asNucleusInfo[0].lFrequencystream3SL1Transmitter system frequency [Hz]acquisitionHz
sTXSPEC.asNucleusInfo[0].bFrequencyValidstream3SL1Frequency valid flagacquisition 
sTXSPEC.asNucleusInfo[0].lDeltaFrequencystream3SL1Offset from center frequency (lFrequency)acquisition 
sTXSPEC.asNucleusInfo[0].flReferenceAmplitudestream3FD1Transmitter reference amplitude [V]acquisitionV
sTXSPEC.asNucleusInfo[0].bReferenceAmplitudeValidstream3SL1Reference amplitude valid flagacquisition 
sTXSPEC.asNucleusInfo[0].flAmplitudeCorrectionstream3FD1Transmitter amplitude correction factor, e.g. used for water suppressionacquisition 
sTXSPEC.asNucleusInfo[0].bAmplitudeCorrectionValidstream3SL1Amplitude correction valid flagacquisition 
+ + + + +
+
Last Updated on 07.02.2002 +
+ + diff --git a/gdcm/Source/DataDictionary/dicomhdr.xsl b/gdcm/Source/DataDictionary/dicomhdr.xsl new file mode 100644 index 0000000..2246161 --- /dev/null +++ b/gdcm/Source/DataDictionary/dicomhdr.xsl @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdcm/Source/DataDictionary/gdcm1.xsl b/gdcm/Source/DataDictionary/gdcm1.xsl new file mode 100644 index 0000000..ef7e96c --- /dev/null +++ b/gdcm/Source/DataDictionary/gdcm1.xsl @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + (RET) + + + + + + diff --git a/gdcm/Source/DataDictionary/gdcm2html.xsl b/gdcm/Source/DataDictionary/gdcm2html.xsl new file mode 100644 index 0000000..5e718e5 --- /dev/null +++ b/gdcm/Source/DataDictionary/gdcm2html.xsl @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + DICOM DICTIONARY + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + italic + + + normal + + + + + + + + + + + + +
TagVRVMDescriptionVersionOwnerRetiredbla
+ + ( + + , + + ) + + + + + + + + + + + + + + + + + (RET) + + + +
+ + +
+
diff --git a/gdcm/Source/DataDictionary/gdcm2pdf.xsl b/gdcm/Source/DataDictionary/gdcm2pdf.xsl new file mode 100644 index 0000000..c252701 --- /dev/null +++ b/gdcm/Source/DataDictionary/gdcm2pdf.xsl @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + PS 3.6-2007 +Page + + + + + - Standard - + + + + + + + + + + + + + + Tag + + + Name + + + VR + + + VM + + + Retired + + + + + + abcdefghijklmnopqrstuvwxyz + ABCDEFGHIJKLMNOPQRSTUVWXYZ + + + + + + + + ( + + , + + ) + + + + + + + + + + + + + + + + + + + + + RET + + + + + + + + + + + + + diff --git a/gdcm/Source/DataDictionary/gdcmCSAHeaderDefaultDicts.cxx b/gdcm/Source/DataDictionary/gdcmCSAHeaderDefaultDicts.cxx new file mode 100644 index 0000000..a6f585c --- /dev/null +++ b/gdcm/Source/DataDictionary/gdcmCSAHeaderDefaultDicts.cxx @@ -0,0 +1,355 @@ + +// GENERATED FILE DO NOT EDIT +// $ xsltproc CSADefaultDicts.xsl CSAHeader.xml > gdcmCSAHeaderDefaultDicts.cxx + +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#ifndef GDCMCSAHEADERDEFAULTDICT_CXX +#define GDCMCSAHEADERDEFAULTDICT_CXX + +#include "gdcmCSAHeaderDict.h" +#include "gdcmCSAHeaderDictEntry.h" +#include "gdcmVR.h" +#include "gdcmVM.h" + + +namespace gdcm { +typedef struct +{ + const char *name; + const char *type; + VR::VRType vr; + VM::VMType vm; + const char *description; +} CSA_DICT_ENTRY; + +static const CSA_DICT_ENTRY CSAHeaderDataDict [] = { + {"AcquisitionDate","3",VR::DA,VM::VM1,"A number identifying the single continuous gathering of data over a period of time which resulted in this image"}, + {"ContentDate","2C",VR::DA,VM::VM1,"The date the image data creation started. Required if image is part of a series in which the images are temporally related"}, + {"AcquisitionTime","3",VR::TM,VM::VM1,"The time the acquisition of data that resulted in this image started"}, + {"ContentTime","2C",VR::TM,VM::VM1,"The time the image pixrl data creation started. Required if image is part of a series in which the images are temporally related"}, + {"Acquisition Datetime","3",VR::DT,VM::VM1,"The date and time that the acquisition of dada that result in this image started"}, + {"DerivationDescription","3",VR::ST,VM::VM1,"A text description of how this image was derived"}, + {"AcquisitionNumber","2",VR::IS,VM::VM1,"Image identification characteristics"}, + {"InstanceNumber","2",VR::IS,VM::VM1,"A number that identifies this image"}, + {"ImageComments","3",VR::LT,VM::VM1,"User-defined comments about the image"}, + {"ImageInAcquisition","3",VR::IS,VM::VM1,"Number of images that resulted from this acquisition of data"}, + {">Referenced SOP Class UID","1C",VR::UI,VM::VM1,"Uniquely identifies the referenced SOP Class"}, + {">Referenced SOP Instance UID","1C",VR::UI,VM::VM1,"Uniquely identifies the referenced SOP Instance"}, + {"> Referenced Frame Number","3",VR::IS,VM::VM1_n,"References one or more image frames of a Multi-frame Image SOP Instance, identifying which frames are siginificantly related to this image"}, + //{">Referenced SOP Class UID","1C",VR::UI,VM::VM1,"Uniquely identifies the referenced SOP Class"}, + //{">Referenced SOP Instance UID","1C",VR::UI,VM::VM1,"Uniquely identifies the referenced SOP Instance"}, + //{"> Referenced Frame Number","3",VR::IS,VM::VM1_n,"References one or more image frames of a Multi-frame Image SOP Instance, identifying which frames are siginificantly related to this image"}, + {"ImageType","3",VR::CS,VM::VM1_n,"Image identification characteristics"}, + {"Lossy Image Compression","3",VR::CS,VM::VM1,"Specifies whether an image has undergone lossy compression. Enumerated values: 00 = image has not been subjected to lossy compression. 01 = image has been subjected to lossy compression"}, + {"Quality Control Image","1C",VR::CS,VM::VM1,"Indicates whether or not this image is a quality control or phantom image. Enumerated values: YES, NO"}, + {"PatientOrientation","2",VR::CS,VM::VM1,"Patient direction of the rows and columns of the image. Not required for MR images"}, + //{"ImageType","1",VR::CS,VM::VM1_n,"Image identification characteristics"}, + {"Samples per Pixel","1",VR::US,VM::VM1,"Number of samples (planes) in this image"}, + {"PhotometricInterpretation","1",VR::CS,VM::VM1,"Specifies the intended interpretation of the pixel data"}, + {"BitsAllocated","1",VR::US,VM::VM1,"Number of bits allocated for each pixel sample. Each sample shall have the same number of bits allocated"}, + {"Scanning Sequence","1",VR::CS,VM::VM1_n,"Description of the type of data taken. Enumerated values: SE = Spin Echo; IR = Inversion Recovery; GR = Gradient Recalled; EP = Echo Planar; RM = Research Mode"}, + {"SequenceVariant","1",VR::CS,VM::VM1_n,"Variant of the Scanning Sequence"}, + {"ScanOptions","2",VR::CS,VM::VM1_n,"Parameters of scanning sequence"}, + {"MRAcquisitionType","2",VR::CS,VM::VM1,"Identification of date encoding scheme. Enumerated Values: 2D = frequency x phase 3D = frequency x phase x phase"}, + {"SequenceName","3",VR::SH,VM::VM1,"User defined name for the Scanning Sequence and Sequence Varaint combination"}, + {"AngioFlag","3",VR::CS,VM::VM1,"Angio image indicator. Primary image for angio processing. Enumerated values: Y = image is Angio N = image is not Angio"}, + {"RepetitionTime","2C",VR::DS,VM::VM1,"The period of time in msec between the beginning of a pulse sequence and the beginning of a succeeding (essentially identical) pulse sequence. Required except when Scanning Sequence is EP and Sequnece Variant is not segmented k-space"}, + {"EchoTime","2",VR::DS,VM::VM1,"Time in msec between the middle of the excitation pulse and the peak of the echo produced. In the case of segmented k-space, the TE(eff) is the time between the middle of the excitation pulse to the peak of the echo that is used to cover the center of k-space)"}, + {"InversionTime","2C",VR::DS,VM::VM1,"Time in msec after the middle of inverting RF pulse to middle of excitation pulse to detect the amount of longitudinal magnetization. Required if Scanning Sequence has value of IR"}, + {"NumberOfAverages","3",VR::DS,VM::VM1,"Number of times a given pulse sequence is repeated before any parameter has changed"}, + {"ImagingFrequency","3",VR::DS,VM::VM1,"Precession frquency in MHz of the nucleus being addressed"}, + {"ImagedNucleus","3",VR::SH,VM::VM1,"Nucleus that is resonant at the imaging frequency"}, + {"EchoNumbers","3",VR::IS,VM::VM1_n,"The echo number used in generating this image. In the case of segmented k-space, it is the effective Echo Number"}, + {"MagneticFieldStrength","3",VR::DS,VM::VM1,"Nominal Field strength of MR magnet, in Tesla"}, + {"SpacingBetweenSlices","3",VR::DS,VM::VM1,"Spacing between slices, in mm. The spacing is measured from the center-to-center of each slice"}, + {"NumberOfPhaseEncodingSteps","3",VR::IS,VM::VM1,"Total number of lines in k-space in the y-direction collecting during acquisition"}, + {"EchoTrainLength","2",VR::IS,VM::VM1,"Number of lines in k-space acquired per excitation per image"}, + {"PercentSampling","3",VR::DS,VM::VM1,"Fraction of acquisition matrix lines acquired, expressed as a percent"}, + {"PercentPhaseFieldOfView","3",VR::DS,VM::VM1,"Ration of field of view dimension in phase direction to field of view dimension in frequency direction, expressed as a percent"}, + {"PixelBandwidth","3",VR::DS,VM::VM1,"Reciprocal of the total sampling period, in hertz per pixel"}, + {"BeatRejectionFlag","3",VR::CS,VM::VM1,"Beat length sorting has been applied. Enumerated values: Y = yes N = no"}, + {"Low R-R Value","3",VR::IS,VM::VM1,"R-R interval low limit for beat rejection, in msec"}, + {"High R-R Value","3",VR::IS,VM::VM1,"R-R interval high limit for beat rejection, in msec"}, + {"TriggerTime","2C",VR::DS,VM::VM1,"Time, in msec, between peak of the R wave and the peak of the echo produced. In the case of segmented k-space, the TE(eff) is the time between the peak of the echo that is used to cover the center of k-space. Required for Scan Options which include heart gating"}, + {"NominalInterval","3",VR::IS,VM::VM1,"Average R-R interval used for the scans, in msec"}, + {"IntervalsAcquired","3",VR::IS,VM::VM1,"Number of R-R intervals acquired"}, + {"IntervalsRejected","3",VR::IS,VM::VM1,"Number of R-R intervals rejected"}, + {"PVC Rejection","3",VR::LO,VM::VM1,"Description of type of PVC rejection criteria used"}, + {"Skip Beats","3",VR::IS,VM::VM1,"Number of beats skipped after a detected arrhythmia"}, + {"HeartRate","3",VR::IS,VM::VM1,"Beats per minute"}, + {"CardiacNumberOfImages","3",VR::IS,VM::VM1,"Number of imagesb per cardiac cycle"}, + {"TriggerWindow","3",VR::IS,VM::VM1,"Percent of R-R interval, based on Heart Rate (0018,1088), prescriped as a window for a valid/usable trigger"}, + {"ReconstructionDiameter","3",VR::DS,VM::VM1,"Diameter in mm of the region from within which data were used in creating the reconstruction of the image. Data may exist outside this region and portions of the patient may exist outside the region"}, + {"Receive Coil","3",VR::SH,VM::VM1,"Received coil used"}, + {"TransmittingCoil","3",VR::SH,VM::VM1,"Transmitted coil used"}, + {"AcquisitionMatrix","3",VR::US,VM::VM4,"Dimension of acquired frequency/phase data before reconstruction. Multi-valued: frequency rows/frequency columns/phase rows/phase columns"}, + {"PhaseEncodingDirection","3",VR::CS,VM::VM1,"The axis of phase encoding with respect to the image. Enumerated Values: ROW = phase encoded in rows COL = phase encoded in columns"}, + {"FlipAngle","3",VR::DS,VM::VM1,"Steady state angle in degrees to which the magnetic vector is flipped from the magnetic vector to the primary field"}, + {"VariableFlipAngleFlag","3",VR::CS,VM::VM1,"Flip angle variation applied during image acquisition. Enumerated Values: Y = yes N = no"}, + {"SAR","3",VR::DS,VM::VM1,"Calculated whole body specific absortion rate in watts/kilogram"}, + {"dBdt","3",VR::DS,VM::VM1,"The rate of change of the gradient coil magnetic flux density with time (T/s)"}, + {"ContrastBolusAgent","2",VR::LO,VM::VM1,"Contrast or bolus agent"}, + {"ContrastBolusStartTime","3",VR::TM,VM::VM1,"Time of start of injection"}, + {"ContrastBolusStopTime","3",VR::TM,VM::VM1,"Time of end of contrast injection"}, + {"ContrastBolusTotalDose","3",VR::DS,VM::VM1,"Total amount in milliliters of the indiluted contrast agent"}, + {"Contrast Flow Rate(s)","3",VR::DS,VM::VM1_n,"Rate(s) of injection(s) in millilitres/sec"}, + {"ContrastBolusVolume","3",VR::DS,VM::VM1,"Volume injected in milliliters of diluted contrast agent"}, + {"ContrastFlowDurations","3",VR::DS,VM::VM1_n,"Duration(s) of injection(s) in seconds. Each Contrast Flow Duration value shall correspond to a value of Contrast Flow Rate (0018,1046)"}, + {"Contrast/Bolus Ingredient","3",VR::CS,VM::VM1,"Active ingredient of agent, Defined Terms: IODINE, GADOLIMIUM, CARBON DIOXIDE, BARIUM"}, + {"Contrast/Bolus Ingredient Concentration","3",VR::DS,VM::VM1,"Milligrams of active ingredient per milliliter of (diluted) agent"}, + {"SamplesPerPixel","1",VR::US,VM::VM1,"Number of samples (planes) in this image"}, + //{"PhotometricInterpretation","1",VR::CS,VM::VM1,"Specifies the intended interpretation of the pixel data"}, + {"Rows","1",VR::US,VM::VM1,"Number of rows in the image"}, + {"Columns","1",VR::US,VM::VM1,"Number of columns in the image"}, + {"PixelAspectRatio","1C",VR::IS,VM::VM2,"Ratio of the vertical size and horizontal size of the pixels in the image specified by a pair of integer values where the first value is the vertical pixel size, and the second value is the horizontal pixel size. Required if the aspect ratio is not 1/1 and the Image Plane Module is not applicable to this Image"}, + //{"BitsAllocated","1",VR::US,VM::VM1,"Number of bits allocated for each pixel sample. Each sample shall have the same number of bits allocated"}, + {"BitsStored","1",VR::US,VM::VM1,"Number of bits stored for each pixel sample. Each sample shall have the same number of bits stored"}, + {"HighBit","1",VR::US,VM::VM1,"Most significant bit for pixel sample data. Each sample shall have the same high bit"}, + {"PixelRepresentation","1",VR::US,VM::VM1,"Data representation of the pixel samples. Each sample shall have the same pixel representation. Enumerated values: 0000H = unsigned integer. 0001H = 2's complement."}, + {"PixelData","1",VR::OB_OW,VM::VM1,"A data stream of the pixel samples which comprises the image"}, + {"Smallest Image Pixel Value","3",VR::US_SS,VM::VM1,"The minimum actual pixel value encountered in this image"}, + {"Largest Image Pixel Value","3",VR::US_SS,VM::VM1,"The maximum actual pixel value encountered in this image"}, + {"SliceThickness","2",VR::DS,VM::VM1,"Nominal slice thickness, in mm"}, + {"ImageOrientationPatient","1",VR::DS,VM::VM6,"The direction cosines of the first row and the first column with respect to the patient"}, + {"ImagePositionPatient","1",VR::DS,VM::VM3,"The x,y and z coordinates of the upper left and hand corner (first pixel transmitted) of the image, in mm"}, + {"SliceLocation","3",VR::DS,VM::VM1,"Relative position of exposure expressed in mm"}, + {"PixelSpacing","1",VR::DS,VM::VM2,"Physical distance in the patient between the center of each pixel, specified by a numeric pair-adjacent row spacing (delimiter) adjacent column spacing in mm"}, + {"WindowCenter","3",VR::DS,VM::VM1_n,"Window center"}, + {"WindowWidth","1C",VR::DS,VM::VM1_n,"Window width"}, + {"WindowCenterWidthExplanation","3",VR::LO,VM::VM1_n,"Free form explanation of the meaning of the Window Center and Width. Multiple values correspond to multiple Window Center and Width values"}, + {"Manufacturer","2",VR::LO,VM::VM1,"Manufacturer of the equipment that produced the digital images"}, + {"InstitutionName","3",VR::LO,VM::VM1,"Institution where the equipment is located that produced the digital images"}, + {"InstitutionAddress","3",VR::ST,VM::VM1,"Mailing address of the institution where the equipment is located that produced the digital images"}, + {"ManufacturersModelName","3",VR::LO,VM::VM1,"Manufacturer's model number of the equipment that produced the digital images"}, + {"DeviceSerialNumber","3",VR::LO,VM::VM1,"Manufacturer's seriel number of the equipment that produced the digital images"}, + {"SoftwareVersions","3",VR::LO,VM::VM1_n,"Manufacturer's designation of software of the equipment that produced the digital images"}, + {"OverlayRows","1",VR::US,VM::VM1,"Number of Rows in Overlay"}, + {"OverlayColumns","1",VR::US,VM::VM1,"Number of Columns in Overlay"}, + {"OverlayType","1",VR::CS,VM::VM1,"Indicates whether this overlay represents a region of interest or other graphics"}, + {"Overlay Origin","1",VR::US,VM::VM1,"Location of first overlay point with respect to pixel in the image, given as row/column"}, + {"OverlayBitsAllocated","1",VR::US,VM::VM1,"Number of bits allocated in the overlay"}, + {"OverlayBitPosition","1",VR::US,VM::VM1,"Bit in which overlay is stored"}, + {"Overlay Data","1C",VR::OB_OW,VM::VM1,"Overlay pixel data"}, + {"HeaderType","1C",VR::CS,VM::VM1,"Medcom header characteristics. Defined Terms: MEDCOM 1"}, + {"HeaderVersion","2C",VR::LO,VM::VM1,"Version of Medcom header"}, + {"HeaderInfo","3",VR::OB,VM::VM1,"Manufacturer header info"}, + {"HistoryInfo","3",VR::OB,VM::VM1,"Patient registration history"}, + {"EchoLinePosition","1",VR::IS,VM::VM1,"Fourier line position with the maximal echo for the performed acquisition"}, + {"EchoColumnPosition","1",VR::IS,VM::VM1,"Echo column position for the performed acquisition"}, + {"EchoPartitionPosition","1",VR::IS,VM::VM1,"Echo partition position for the performed acquisition"}, + {"UsedChannelMask","1",VR::UL,VM::VM1,"8 bit mask of the used receiver channels for the performed acquisition. Example: channel 0: 00000001 channel 3: 00000111"}, + {"Actual3DImaPartNumber","1",VR::IS,VM::VM1,"Number of a 3D partitions beginning with 0"}, + {"ICE_Dims","1",VR::LO,VM::VM1,"The 9 used ICE object dimensions of the performed acquisition. Combined/unset dimensions will be marked with 'X'. E.g.: X_2_1_1_1_1_2_1_1"}, + {"B_value","1;",VR::IS,VM::VM1,"Diffusion effect in s/mm*mm of the ICE program for the performed acquisition"}, + {"Filter1","1",VR::IS,VM::VM1,"Context vision filter"}, + {"Filter2","1",VR::IS,VM::VM1,"not used"}, + {"ProtocolSliceNumber","1",VR::IS,VM::VM1,"Number of the slice beginning with 0"}, + {"RealDwellTime","1",VR::IS,VM::VM1,"The time in ns between the beginning of sampling one data point and the beginning of sampling of next data point in the acquired signal. This means the dwell time is the sampling rate during digital conversion of an acquired signal"}, + {"PixelFile","1",VR::UN,VM::VM1,"Used raw data file for the performed acquisition"}, + {"PixelFileName","1",VR::UN,VM::VM1,"Used raw data file name for the performed acquisition"}, + {"SliceMeasurementDuration","1",VR::DS,VM::VM1,"Time duration between two slices of the performed acquisition"}, + {"AcquisitionMatrixText","1",VR::SH,VM::VM1,"Used acquisition matrix description"}, + {"SequenceMask","1",VR::UL,VM::VM1,"Parameters used for acquisition, e.g. door open, interpolation, raw filter, Siemens seqence ...."}, + {"MeasuredFourierLines","1",VR::IS,VM::VM1,"Number of performed fourier lines"}, + {"FlowEncodingDirection","1",VR::IS,VM::VM1,"Flow encoding direction"}, + {"FlowVenc","1",VR::FD,VM::VM1,"Flow Quant attribute"}, + {"PhaseEncodingDirectionPositive","1",VR::IS,VM::VM1,"Phase encoding direction: 0 = negative; 1 = positive"}, + {"NumberOfImagesInMosaic","1",VR::US,VM::VM1,"Number of slices in a mosaic image"}, + {"DiffusionGradientDirection","1",VR::FD,VM::VM3,"Diffusion in gradient direction"}, + {"ImageGroup","1",VR::US,VM::VM1,"Group of images"}, + {"SliceNormalVector","1",VR::FD,VM::VM3,"X,y and z normal vector of the slices"}, + {"DiffusionDirection","1",VR::CS,VM::VM1,"Diffusion direction"}, + {"TimeAfterStart","1",VR::DS,VM::VM1,"Time delay after start of measurment"}, + //{"FlipAngle","1",VR::DS,VM::VM1,"Flip angle for SC images"}, + //{"SequenceName","1",VR::SH,VM::VM1,"Sequence name for SC images"}, + //{"RepetitionTime","1",VR::DS,VM::VM1,"Repetition time for SC images"}, + //{"EchoTime","1",VR::DS,VM::VM1,"Echo time for SC images"}, + //{"NumberOfAverages","1",VR::DS,VM::VM1_n,"Number of averages for SC images"}, + {"NonimageType","1",VR::CS,VM::VM1,"Data identification characteristics. Defined terms: RAW DATA NUM 4; SPEC NUM4"}, + {"NonimageVersion","3",VR::LO,VM::VM1,"Version of Non-image data"}, + {"NonimageInfo","3",VR::OB,VM::VM1,"Description of Non-image data"}, + {"NonimageData","2",VR::OB,VM::VM1,"Binary data stream"}, + //{"ImageType","3",VR::CS,VM::VM1_n,"Image identification characteristics"}, + //{"AcquisitionDate","3",VR::DA,VM::VM1,"The date the acquisition of data started"}, + //{"AcquisitionTime","3",VR::TM,VM::VM1,"The time the acquisition of data started"}, + //{"DerivationDescription","3",VR::ST,VM::VM1,"A text description of how this data set was derived"}, + //{"AcquisitionNumber","2",VR::IS,VM::VM1,"A number identifying the gathering of data over a period of time which resulted in this data set"}, + {"ImageNumber","1",VR::IS,VM::VM1,"A number that identifies this image"}, + //{"ImageComments","1",VR::LT,VM::VM1,"User-defined comments about the image"}, + {"ReferencedImageSequence","1",VR::UI,VM::VM1_n,"A sequence which provides reference to a set of Image SOP Class/Instance identifying other images significantly related to this image (localizer images)"}, + //{"PatientOrientation","1",VR::CS,VM::VM1,"Patient direction of the rows and columns of the image. Not required for MR images"}, + {"ScanningSequence","1",VR::CS,VM::VM1_n,"Description of the type of data taken. Enumerated values: SE = Spin Echo; IR = Inversion Recovery; GR = Gradient Recalled; EP = Echo Planar; RM = Research Mode"}, + //{"SequenceName","1",VR::SH,VM::VM1,"User defined name for the Scanning Sequence and Sequence Varaint combination"}, + //{"RepetitionTime","1",VR::DS,VM::VM1,"The period of time in msec between the beginning of a pulse sequence and the beginning of a succeeding (essentially identical) pulse sequence. Required except when Scanning Sequence is EP and Sequnece Variant is not segmented k-space"}, + //{"EchoTime","1",VR::DS,VM::VM1,"Time in msec between the middle of the excitation pulse and the peak of the echo produced. In the case of segmented k-space, the TE(eff) is the time between the middle of the excitation pulse to the peak of the echo that is used to cover the center of k-space)"}, + //{"InversionTime","1",VR::DS,VM::VM1,"Time in msec after the middle of inverting RF pulse to middle of excitation pulse to detect the amount of longitudinal magnetization. Required if Scanning Sequence has value of IR"}, + //{"NumberOfAverages","1",VR::DS,VM::VM1,"Number of averages"}, + //{"ImagingFrequency","1",VR::DS,VM::VM1,"Precession frquency in MHz of the nucleus being addressed"}, + //{"ImagedNucleus","1",VR::SH,VM::VM1,"Nucleus that is resonant at the imaging frequency"}, + //{"EchoNumbers","1",VR::IS,VM::VM1,"The echo number used in generating this image. In the case of segmented k-space, it is the effective Echo Number"}, + //{"MagneticFieldStrength","1",VR::DS,VM::VM1,"Nominal Field strength of MR magnet, in Tesla"}, + //{"NumberOfPhaseEncodingSteps","1",VR::IS,VM::VM1,"Total number of lines in k-space in the y-direction collecting during acquisition"}, + //{"EchoTrainLength","1",VR::IS,VM::VM1,"Number of lines in k-space acquired per excitation per image"}, + //{"PercentSampling","1",VR::DS,VM::VM1,"Fraction of acquisition matrix lines acquired, expressed as a percent"}, + //{"PercentPhaseFieldOfView","1",VR::DS,VM::VM1,"Ration of field of view dimension in phase direction to field of view dimension in frequency direction, expressed as a percent"}, + //{"TriggerTime","1",VR::DS,VM::VM1,"Time, in msec, between peak of the R wave and the peak of the echo produced. In the case of segmented k-space, the TE(eff) is the time between the peak of the echo that is used to cover the center of k-space. Required for Scan Options which include heart gating"}, + {"ReceivingCoil","1",VR::SH,VM::VM1,"Received coil used"}, + {"TransmittingColi","1",VR::SH,VM::VM1,"Transmitted coil used"}, + //{"AcquisitionMatrixText","1",VR::US,VM::VM4,"Dimension of acquired frequency/phase data before reconstruction. Multi-valued: frequency rows/frequency columns/phase rows/phase columns"}, + //{"PhaseEncodingDirection","1",VR::CS,VM::VM1,"The axis of phase encoding with respect to the image. Enumerated Values: ROW = phase encoded in rows COL = phase encoded in columns"}, + //{"FlipAngle","1",VR::DS,VM::VM1,"Steady state angle in degrees to which the magnetic vector is flipped from the magnetic vector to the primary field"}, + //{"VariableFlipAngleFlag","1",VR::CS,VM::VM1,"Flip angle variation applied during image acquisition. Enumerated Values: Y = yes N = no"}, + //{"SAR","1",VR::DS,VM::VM1,"Calculated whole body specific absortion rate in watts/kilogram"}, + //{"dBdt","1",VR::DS,VM::VM3,"The rate of change of the gradient coil magnetic flux density with time (T/s)"}, + //{"Rows","1",VR::US,VM::VM1,"Number of rows in the image"}, + //{"Columns","1",VR::US,VM::VM1,"Number of columns in the image"}, + //{"SliceThickness","1",VR::DS,VM::VM1,"Nominal slice thickness, in mm"}, + //{"ImagePositionPatient","1",VR::DS,VM::VM3,"The direction cosines of the first row and the first column with respect to the patient"}, + //{"ImageOrientationPatient","1",VR::DS,VM::VM6,"The x,y and z coordinates of the upper left and hand corner (first pixel transmitted) of the image, in mm."}, + //{"SliceLocation","1",VR::DS,VM::VM1,"Relative position of exposure expressed in mm"}, + //{"EchoLinePosition","1",VR::IS,VM::VM1,"Fourier line position with the maximal echo for the performed acquisition"}, + //{"EchoColumnPosition","1",VR::IS,VM::VM1,"Echo column position for the performed acquisition"}, + //{"EchoPartitionPosition","1",VR::IS,VM::VM1,"Echo partition position for the performed acquisition"}, + //{"Actual3DImaPartNumber","1",VR::IS,VM::VM1,"Number of a 3D partitions beginning with 0"}, + //{"RealDwellTime","1",VR::IS,VM::VM1,"The time in ns between the beginning of sampling one data point and the beginning of sampling of next data point in the acquired signal. This means the dwell time is the sampling rate during digital conversion of an acquired signal"}, + //{"ProtocolSliceNumber","1",VR::UN,VM::VM1,"Number of the slice beginning with 0"}, + //{"PixelFile","1",VR::UN,VM::VM1,"Used raw data file for the performed acquisition"}, + //{"PixelFileName","1",VR::LO,VM::VM1,"Used raw data file name for the performed acquisition"}, + //{"ICE_Dims","1",VR::DS,VM::VM1,"The 9 used ICE object dimensions of the performed acquisition. Combined/unset dimensions will be marked with 'X'. E.g.: X_2_1_1_1_1_2_1_1"}, + //{"PixelSpacing","1",VR::DS,VM::VM2,"Physical distance in the patient between the center of each pixel, specified by a numeric pair-adjacent row spacing (delimiter) adjacent column spacing in mm"}, + {"SourceImageSequence","1",VR::UI,VM::VM1_n,"A sequence which identifies the set of Image SOP Class/Instance pairs of the images which were use to derive this image"}, + //{"PixelBandwidth","1",VR::DS,VM::VM1,"Reciprocal of the total sampling period, in hertz per pixel"}, + //{"SliceMeasurementDuration","1",VR::DS,VM::VM1,"Time duration between two slices of the performed acquisition"}, + //{"SequenceMask","1",VR::UL,VM::VM1,"Parameters used for acquisition, e.g. door open, interpolation, raw filter, Siemens seqence .·"}, + //{"AcquisitionMatrixText","1",VR::SH,VM::VM1,"Used acquisition matrix description"}, + //{"MeasuredFourierLines","1",VR::IS,VM::VM1,"Number of performed fourier lines"}, + {"ulVersion","3",VR::UL,VM::VM1,"Protocol version"}, + {"tSequenceFileName","3",VR::ST,VM::VM1,"Sequence file name for actual measurement protocol"}, + {"tProtocolName","3",VR::ST,VM::VM1,"Name of actual measurement protocol"}, + {"tReferenceImage0","3",VR::LO,VM::VM1,"Referenced image"}, + {"tReferenceImage1","3",VR::LO,VM::VM1,"Referenced image"}, + {"tReferenceImage2","3",VR::LO,VM::VM1,"Referenced image"}, + {"lScanRegionPosSag","3",VR::FD,VM::VM1,"Desired table position in series block coordinate system"}, + {"lScanRegionPosCor","3",VR::FD,VM::VM1,"Desired table position in series block coordinate system"}, + {"lScanRegionPosTra","3",VR::FD,VM::VM1,"Desired table position in series block coordinate system"}, + {"ucScanRegionPosValid","3",VR::SH,VM::VM1,"Valid flag for desired table position in series block coordinate system"}, + {"aucSpare","3",VR::SH,VM::VM1,"Reserved"}, + {"lScanRegionDelta","3",VR::SL,VM::VM1,"Scan Region Position/Move [mm]"}, + {"sProtConsistencyInfo.tBaselineString","3",VR::LO,VM::VM1,"Baseline consistence info"}, + {"sProtConsistencyInfo.tGradCoilName","3",VR::SH,VM::VM1,"Coil name consistence info"}, + {"sProtConsistencyInfo.tGradAmplifierName","3",VR::LO,VM::VM1,"Gradient amplifier consistence info"}, + {"sProtConsistencyInfo.flNominalB0","3",VR::FD,VM::VM1,"Nominal Bo compensation consistence"}, + {"sGRADSPEC.sEddyCompensationX.aflAmplitude","3",VR::FD,VM::VM5,"Eddy compensation x amplitude gradient system specification"}, + {"sGRADSPEC.sEddyCompensationX.aflTimeConstant","3",VR::FD,VM::VM5,"Eddy compensation x time parameter gradient system specification"}, + {"sGRADSPEC.sEddyCompensationY.aflAmplitude","3",VR::FD,VM::VM5,"Eddy compensation y amplitude gradient system specification"}, + {"sGRADSPEC.sEddyCompensationY.aflTimeConstant","3",VR::FD,VM::VM5,"Eddy compensation y time parameter gradient system specification"}, + {"sGRADSPEC.sEddyCompensationZ.aflAmplitude","3",VR::FD,VM::VM5,"Eddy compensation z amplitude gradient system specification"}, + {"sGRADSPEC.sEddyCompensationZ.aflTimeConstant","3",VR::FD,VM::VM5,"Eddy compensation z time parameter gradient system specification"}, + {"sGRADSPEC.bB0CompensationValid","3",VR::SL,VM::VM1,"B0 compensation gradient system specification valid flag"}, + {"sGRADSPEC.sCrossTermCompensationXY.aflAmplitude","3",VR::FD,VM::VM5,"Crossterm compensation xy amplitude gradient system specification"}, + {"sGRADSPEC.sCrossTermCompensationXY.aflTimeConstant","3",VR::FD,VM::VM5,"Crossterm compensation xy time parameter gradient system specification"}, + {"sGRADSPEC.sCrossTermCompensationXZ.aflAmplitude","3",VR::FD,VM::VM5,"Crossterm compensation xz amplitude gradient system specification"}, + {"sGRADSPEC.sCrossTermCompensationXZ.aflTimeConstant","3",VR::FD,VM::VM5,"Crossterm compensation xz time parameter gradient system specification"}, + {"sGRADSPEC.sCrossTermCompensationYX.aflAmplitude","3",VR::FD,VM::VM5,"Crossterm compensation xz amplitude gradient system specification"}, + {"sGRADSPEC.sCrossTermCompensationYX.aflTimeConstant","3",VR::FD,VM::VM5,"Crossterm compensation yx time parameter gradient system specification"}, + {"sGRADSPEC.sCrossTermCompensationYZ.aflAmplitude","3",VR::FD,VM::VM5,"Crossterm compensation yz amplitude gradient system specification"}, + {"sGRADSPEC.sCrossTermCompensationYZ.aflTimeConstant","3",VR::FD,VM::VM5,"Crossterm compensation yz time parameter gradient system specification"}, + {"sGRADSPEC.sCrossTermCompensationZX.aflAmplitude","3",VR::FD,VM::VM5,"Crossterm compensation zx amplitude gradient system specification"}, + {"sGRADSPEC.sCrossTermCompensationZX.aflTimeConstant","3",VR::FD,VM::VM5,"Crossterm compensation zx time parameter gradient system specification"}, + {"sGRADSPEC.sCrossTermCompensationZY.aflAmplitude","3",VR::FD,VM::VM5,"Crossterm compensation zx amplitude gradient system specification"}, + {"sGRADSPEC.sCrossTermCompensationZY.aflTimeConstant","3",VR::FD,VM::VM5,"Crossterm compensation zy time parameter gradient system specification"}, + {"sGRADSPEC.bCrossTermCompensationValid","3",VR::SL,VM::VM1,"Crossterm compensation gradient system specification valid flag"}, + {"sGRADSPEC.lOffsetX","3",VR::SL,VM::VM1,"Gradient offset x direction [bit pattern]"}, + {"sGRADSPEC.lOffsetY","3",VR::SL,VM::VM1,"Gradient offset y direction [bit pattern]"}, + {"sGRADSPEC.lOffsetZ","3",VR::SL,VM::VM1,"Gradient offset z direction [bit pattern]"}, + {"sGRADSPEC.bOffsetValid","3",VR::SL,VM::VM1,"Gradient offsets valid flag"}, + {"sGRADSPEC.lDelayX","3",VR::SL,VM::VM1,"Gradient delay x direction"}, + {"sGRADSPEC.lDelayY","3",VR::SL,VM::VM1,"Gradient delay y direction"}, + {"sGRADSPEC.lDelayZ","3",VR::SL,VM::VM1,"Gradient delay z direction"}, + {"sGRADSPEC.bDelayValid","3",VR::SL,VM::VM1,"Gradient delay valid flag"}, + {"sGRADSPEC.flSensitivityX","3",VR::FD,VM::VM1,"Gradient sensitivity x direction [mT/m]"}, + {"sGRADSPEC.flSensitivityY","3",VR::FD,VM::VM1,"Gradient sensitivity y direction [mT/m]"}, + {"sGRADSPEC.flSensitivityZ","3",VR::FD,VM::VM1,"Gradient sensitivity z direction [mT/m]"}, + {"sGRADSPEC.bSensitivityValid","3",VR::SL,VM::VM1,"Gradient sensitivity valid flag"}, + {"sGRADSPEC.flGSWDMinRiseTime","3",VR::FD,VM::VM1,"Minimum gradient rise time for mode GRAD_GSWD_RISETIME"}, + {"sGRADSPEC.alShimCurrent","3",VR::SL,VM::VM16,"Shim current parameter [mA]"}, + {"sGRADSPEC.bShimCurrentValid","3",VR::SL,VM::VM1,"Shim current parameter valid flag"}, + {"sGRADSPEC.ucMode","3",VR::SH,VM::VM1,"Gradient mode: fast, normal, whisper"}, + {"sGRADSPEC.ucSpare0","3",VR::SH,VM::VM1,"Reserved"}, + {"sGRADSPEC.ucSpare1","3",VR::SH,VM::VM1,"Reserved"}, + {"sGRADSPEC.ucSpare2","3",VR::SH,VM::VM1,"Reserved"}, + {"sTXSPEC.asNucleusInfo[0].tNucleus","3",VR::SH,VM::VM1,"Transmitter system nucleus"}, + {"sTXSPEC.asNucleusInfo[0].lFrequency","3",VR::SL,VM::VM1,"Transmitter system frequency [Hz]"}, + {"sTXSPEC.asNucleusInfo[0].bFrequencyValid","3",VR::SL,VM::VM1,"Frequency valid flag"}, + {"sTXSPEC.asNucleusInfo[0].lDeltaFrequency","3",VR::SL,VM::VM1,"Offset from center frequency (lFrequency)"}, + {"sTXSPEC.asNucleusInfo[0].flReferenceAmplitude","3",VR::FD,VM::VM1,"Transmitter reference amplitude [V]"}, + {"sTXSPEC.asNucleusInfo[0].bReferenceAmplitudeValid","3",VR::SL,VM::VM1,"Reference amplitude valid flag"}, + {"sTXSPEC.asNucleusInfo[0].flAmplitudeCorrection","3",VR::FD,VM::VM1,"Transmitter amplitude correction factor, e.g. used for water suppression"}, + {"sTXSPEC.asNucleusInfo[0].bAmplitudeCorrectionValid","3",VR::SL,VM::VM1,"Amplitude correction valid flag"}, + +/* Manually added */ + {"sKSpace.ucSlicePartialFourier","1",VR::US,VM::VM1,"Partial Fourier Information 0x1,0x2,0x4,0x8,0x10 resp. 4/8,5/8,6/8,7/8,8/8"}, +// http://www.nmr.mgh.harvard.edu/~greve/dicom-unpack +// http://web.archiveorange.com/archive/v/AW2a1uSBsvpLmfFd9xvy +/* +ASCCONV does contain most of the good info. In particular the slice +ordering is encoded thus: + + sSliceArray.ucMode -- should be in (1, 2, 4) + enum SeriesMode + { + ASCENDING = 0x01, + DESCENDING = 0x02, + INTERLEAVED = 0x04 + }; + +And when interleaved, the slice ordering depends on whether the number +of slices is even or odd. I have it coded (counting from zero) as: + +if ODD: + slice_order = {0, 2, 4, ..., N-1, 1, 3, 5, ..., N-2} +else: + slice_order = {1, 3, 5, ..., N-1, 0, 2, 4, ..., N-2} + +which I can't immediately confirm, but I'm reasonably confident about it. + +It's all a bit of a mess, but there is some code available on the CIRL +repo in bic/trunk/recon-tools/root/scanner/siemens.py + +check out parse_siemens_hdr() in that module, where I also documented +various useful fields. And there are the helper functions ( +strip_ascconv(), condense_array() ) in siemens_utils.py. No +docstrings, so ping me if you need clarification. +*/ + {"sSliceArray.ucMode","1",VR::US,VM::VM1,"slice ordering 0x1,0x2,0x4 resp. asc,desc,inter"}, + + {0,0,VR::INVALID,VM::VM0,0 } // Gard +}; + +void CSAHeaderDict::LoadDefault() +{ + unsigned int i = 0; + CSA_DICT_ENTRY n = CSAHeaderDataDict[i]; + while( n.name != 0 ) + { + CSAHeaderDictEntry e( n.name, n.vr, n.vm, n.description ); + AddCSAHeaderDictEntry( e ); + n = CSAHeaderDataDict[++i]; + } +} + +} // end namespace gdcm +#endif // GDCMCSAHEADERDEFAULTDICT_CXX diff --git a/gdcm/Source/DataDictionary/gdcmCSAHeaderDict.h b/gdcm/Source/DataDictionary/gdcmCSAHeaderDict.h new file mode 100644 index 0000000..ae731a2 --- /dev/null +++ b/gdcm/Source/DataDictionary/gdcmCSAHeaderDict.h @@ -0,0 +1,98 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMCSAHEADERDICT_H +#define GDCMCSAHEADERDICT_H + +#include "gdcmTypes.h" +#include "gdcmTag.h" +#include "gdcmCSAHeaderDictEntry.h" + +#include +#include +#include +#include + +namespace gdcm +{ + +class GDCM_EXPORT CSAHeaderDictException : public std::exception {}; + +/** + * \brief Class to represent a map of CSAHeaderDictEntry + */ +class GDCM_EXPORT CSAHeaderDict +{ +public: + typedef std::set MapCSAHeaderDictEntry; + typedef MapCSAHeaderDictEntry::iterator Iterator; + typedef MapCSAHeaderDictEntry::const_iterator ConstIterator; + //static CSAHeaderDictEntry GroupLengthCSAHeaderDictEntry; // = CSAHeaderDictEntry("Group Length",VR::UL,VM::VM1); + + CSAHeaderDict():CSAHeaderDictInternal() { + assert( CSAHeaderDictInternal.empty() ); + } + + friend std::ostream& operator<<(std::ostream& _os, const CSAHeaderDict &_val); + + ConstIterator Begin() const { return CSAHeaderDictInternal.begin(); } + ConstIterator End() const { return CSAHeaderDictInternal.end(); } + + bool IsEmpty() const { return CSAHeaderDictInternal.empty(); } + void AddCSAHeaderDictEntry(const CSAHeaderDictEntry &de) + { +#ifndef NDEBUG + MapCSAHeaderDictEntry::size_type s = CSAHeaderDictInternal.size(); +#endif + CSAHeaderDictInternal.insert( de ); + assert( s < CSAHeaderDictInternal.size() ); + } + + const CSAHeaderDictEntry &GetCSAHeaderDictEntry(const char *name) const + { + MapCSAHeaderDictEntry::const_iterator it = CSAHeaderDictInternal.find( name ); + if( it != CSAHeaderDictInternal.end() ) + { + return *it; + } + throw CSAHeaderDictException(); + } + +protected: + friend class Dicts; + void LoadDefault(); + +private: + CSAHeaderDict &operator=(const CSAHeaderDict &_val); // purposely not implemented + CSAHeaderDict(const CSAHeaderDict &_val); // purposely not implemented + + MapCSAHeaderDictEntry CSAHeaderDictInternal; +}; +//----------------------------------------------------------------------------- +inline std::ostream& operator<<(std::ostream& os, const CSAHeaderDict &val) +{ + CSAHeaderDict::MapCSAHeaderDictEntry::const_iterator it = val.CSAHeaderDictInternal.begin(); + for(;it != val.CSAHeaderDictInternal.end(); ++it) + { + const CSAHeaderDictEntry &de = *it; + os << de << '\n'; + } + + + return os; +} + + +} // end namespace gdcm + +#endif //GDCMCSAHEADERDICT_H diff --git a/gdcm/Source/DataDictionary/gdcmCSAHeaderDictEntry.h b/gdcm/Source/DataDictionary/gdcmCSAHeaderDictEntry.h new file mode 100644 index 0000000..f01396c --- /dev/null +++ b/gdcm/Source/DataDictionary/gdcmCSAHeaderDictEntry.h @@ -0,0 +1,97 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMCSAHEADERDICTENTRY_H +#define GDCMCSAHEADERDICTENTRY_H + +#include "gdcmVR.h" +#include "gdcmVM.h" + +#include +#include +#include + +#include + +namespace gdcm +{ +/** + * \brief Class to represent an Entry in the Dict + * Does not really exist within the DICOM definition, just a way to minimize + * storage and have a mapping from gdcm::Tag to the needed information + * \note bla + * TODO FIXME: Need a PublicCSAHeaderDictEntry...indeed CSAHeaderDictEntry has a notion of retired which + * does not exist in PrivateCSAHeaderDictEntry... + * + * \see gdcm::Dict + */ +class GDCM_EXPORT CSAHeaderDictEntry +{ +public: + CSAHeaderDictEntry(const char *name = "", VR const &vr = VR::INVALID, VM const &vm = VM::VM0, const char *desc = ""):Name(name),ValueRepresentation(vr),ValueMultiplicity(vm),Description(desc) { + } + + friend std::ostream& operator<<(std::ostream& _os, const CSAHeaderDictEntry &_val); + + /// Set/Get VR + const VR &GetVR() const { return ValueRepresentation; } + void SetVR(const VR & vr) { ValueRepresentation = vr; } + + /// Set/Get VM + const VM &GetVM() const { return ValueMultiplicity; } + void SetVM(VM const & vm) { ValueMultiplicity = vm; } + + /// Set/Get Name + const char *GetName() const { return Name.c_str(); } + void SetName(const char* name) { Name = name; } + + /// Set/Get Description + const char *GetDescription() const { return Description.c_str(); } + void SetDescription(const char* desc) { Description = desc; } + + bool operator<(const CSAHeaderDictEntry &entry) const + { + return strcmp(GetName(),entry.GetName()) < 0; + } + +private: + std::string Name; + VR ValueRepresentation; + VM ValueMultiplicity; + std::string Description; + std::string Type; // TODO +}; + + +//----------------------------------------------------------------------------- +inline std::ostream& operator<<(std::ostream& os, const CSAHeaderDictEntry &val) +{ + if( val.Name.empty() ) + { + os << "[No name]"; + } + else + { + os << val.Name; + } + os << "\t" << val.ValueRepresentation << "\t" << val.ValueMultiplicity; + if( !val.Description.empty() ) + { + os << "\t" << val.Description; + } + return os; +} + +} // end namespace gdcm + +#endif //GDCMCSAHEADERDICTENTRY_H diff --git a/gdcm/Source/DataDictionary/gdcmDefaultDicts.cxx b/gdcm/Source/DataDictionary/gdcmDefaultDicts.cxx new file mode 100644 index 0000000..fd9653b --- /dev/null +++ b/gdcm/Source/DataDictionary/gdcmDefaultDicts.cxx @@ -0,0 +1,13301 @@ + +// GENERATED FILE DO NOT EDIT +// $ xsltproc DefaultDicts.xsl Part6.xml > gdcmDefaultDicts.cxx + +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#ifndef GDCMDEFAULTDICTS_CXX +#define GDCMDEFAULTDICTS_CXX + +#include "gdcmDicts.h" +#include "gdcmVR.h" +#include "gdcmDict.h" +#include "gdcmDictEntry.h" + +namespace gdcm { +typedef struct +{ + uint16_t group; + uint16_t element; + VR::VRType vr; + VM::VMType vm; + const char *name; + const char *keyword; + bool ret; +} DICT_ENTRY; + +static const DICT_ENTRY DICOMV3DataDict [] = { + {0x0000,0x0000,VR::UL,VM::VM1,"Command Group Length","CommandGroupLength",false }, + {0x0000,0x0001,VR::UL,VM::VM1,"Command Length to End","CommandLengthToEnd",true }, + {0x0000,0x0002,VR::UI,VM::VM1,"Affected SOP Class UID","AffectedSOPClassUID",false }, + {0x0000,0x0003,VR::UI,VM::VM1,"Requested SOP Class UID","RequestedSOPClassUID",false }, + {0x0000,0x0010,VR::SH,VM::VM1,"Command Recognition Code","CommandRecognitionCode",true }, + {0x0000,0x0100,VR::US,VM::VM1,"Command Field","CommandField",false }, + {0x0000,0x0110,VR::US,VM::VM1,"Message ID","MessageID",false }, + {0x0000,0x0120,VR::US,VM::VM1,"Message ID Being Responded To","MessageIDBeingRespondedTo",false }, + {0x0000,0x0200,VR::AE,VM::VM1,"Initiator","Initiator",true }, + {0x0000,0x0300,VR::AE,VM::VM1,"Receiver","Receiver",true }, + {0x0000,0x0400,VR::AE,VM::VM1,"Find Location","FindLocation",true }, + {0x0000,0x0600,VR::AE,VM::VM1,"Move Destination","MoveDestination",false }, + {0x0000,0x0700,VR::US,VM::VM1,"Priority","Priority",false }, + {0x0000,0x0800,VR::US,VM::VM1,"Command Data Set Type","CommandDataSetType",false }, + {0x0000,0x0850,VR::US,VM::VM1,"Number of Matches","NumberOfMatches",true }, + {0x0000,0x0860,VR::US,VM::VM1,"Response Sequence Number","ResponseSequenceNumber",true }, + {0x0000,0x0900,VR::US,VM::VM1,"Status","Status",false }, + {0x0000,0x0901,VR::AT,VM::VM1_n,"Offending Element","OffendingElement",false }, + {0x0000,0x0902,VR::LO,VM::VM1,"Error Comment","ErrorComment",false }, + {0x0000,0x0903,VR::US,VM::VM1,"Error ID","ErrorID",false }, + {0x0000,0x1000,VR::UI,VM::VM1,"Affected SOP Instance UID","AffectedSOPInstanceUID",false }, + {0x0000,0x1001,VR::UI,VM::VM1,"Requested SOP Instance UID","RequestedSOPInstanceUID",false }, + {0x0000,0x1002,VR::US,VM::VM1,"Event Type ID","EventTypeID",false }, + {0x0000,0x1005,VR::AT,VM::VM1_n,"Attribute Identifier List","AttributeIdentifierList",false }, + {0x0000,0x1008,VR::US,VM::VM1,"Action Type ID","ActionTypeID",false }, + {0x0000,0x1020,VR::US,VM::VM1,"Number of Remaining Sub-operations","NumberOfRemainingSuboperations",false }, + {0x0000,0x1021,VR::US,VM::VM1,"Number of Completed Sub-operations","NumberOfCompletedSuboperations",false }, + {0x0000,0x1022,VR::US,VM::VM1,"Number of Failed Sub-operations","NumberOfFailedSuboperations",false }, + {0x0000,0x1023,VR::US,VM::VM1,"Number of Warning Sub-operations","NumberOfWarningSuboperations",false }, + {0x0000,0x1030,VR::AE,VM::VM1,"Move Originator Application Entity Title","MoveOriginatorApplicationEntityTitle",false }, + {0x0000,0x1031,VR::US,VM::VM1,"Move Originator Message ID","MoveOriginatorMessageID",false }, + {0x0000,0x4000,VR::LT,VM::VM1,"Dialog Receiver","DialogReceiver",true }, + {0x0000,0x4010,VR::LT,VM::VM1,"Terminal Type","TerminalType",true }, + {0x0000,0x5010,VR::SH,VM::VM1,"Message Set ID","MessageSetID",true }, + {0x0000,0x5020,VR::SH,VM::VM1,"End Message ID","EndMessageID",true }, + {0x0000,0x5110,VR::LT,VM::VM1,"Display Format","DisplayFormat",true }, + {0x0000,0x5120,VR::LT,VM::VM1,"Page Position ID","PagePositionID",true }, + {0x0000,0x5130,VR::CS,VM::VM1,"Text Format ID","TextFormatID",true }, + {0x0000,0x5140,VR::CS,VM::VM1,"Normal/Reverse","NormalReverse",true }, + {0x0000,0x5150,VR::CS,VM::VM1,"Add Gray Scale","AddGrayScale",true }, + {0x0000,0x5160,VR::CS,VM::VM1,"Borders","Borders",true }, + {0x0000,0x5170,VR::IS,VM::VM1,"Copies","Copies",true }, + {0x0000,0x5180,VR::CS,VM::VM1,"Command Magnification Type","CommandMagnificationType",true }, + {0x0000,0x5190,VR::CS,VM::VM1,"Erase","Erase",true }, + {0x0000,0x51a0,VR::CS,VM::VM1,"Print","Print",true }, + {0x0000,0x51b0,VR::US,VM::VM1_n,"Overlays","Overlays",true }, + {0x0002,0x0000,VR::UL,VM::VM1,"File Meta Information Group Length","FileMetaInformationGroupLength",false }, + {0x0002,0x0001,VR::OB,VM::VM1,"File Meta Information Version","FileMetaInformationVersion",false }, + {0x0002,0x0002,VR::UI,VM::VM1,"Media Storage SOP Class UID","MediaStorageSOPClassUID",false }, + {0x0002,0x0003,VR::UI,VM::VM1,"Media Storage SOP Instance UID","MediaStorageSOPInstanceUID",false }, + {0x0002,0x0010,VR::UI,VM::VM1,"Transfer Syntax UID","TransferSyntaxUID",false }, + {0x0002,0x0012,VR::UI,VM::VM1,"Implementation Class UID","ImplementationClassUID",false }, + {0x0002,0x0013,VR::SH,VM::VM1,"Implementation Version Name","ImplementationVersionName",false }, + {0x0002,0x0016,VR::AE,VM::VM1,"Source Application Entity Title","SourceApplicationEntityTitle",false }, + {0x0002,0x0100,VR::UI,VM::VM1,"Private Information Creator UID","PrivateInformationCreatorUID",false }, + {0x0002,0x0102,VR::OB,VM::VM1,"Private Information","PrivateInformation",false }, + {0x0004,0x1130,VR::CS,VM::VM1,"File-set ID","FileSetID",false }, + {0x0004,0x1141,VR::CS,VM::VM1_8,"File-set Descriptor File ID","FileSetDescriptorFileID",false }, + {0x0004,0x1142,VR::CS,VM::VM1,"Specific Character Set of File-set Descriptor File","SpecificCharacterSetOfFileSetDescriptorFile",false }, + {0x0004,0x1200,VR::UL,VM::VM1,"Offset of the First Directory Record of the Root Directory Entity","OffsetOfTheFirstDirectoryRecordOfTheRootDirectoryEntity",false }, + {0x0004,0x1202,VR::UL,VM::VM1,"Offset of the Last Directory Record of the Root Directory Entity","OffsetOfTheLastDirectoryRecordOfTheRootDirectoryEntity",false }, + {0x0004,0x1212,VR::US,VM::VM1,"File-set Consistency Flag","FileSetConsistencyFlag",false }, + {0x0004,0x1220,VR::SQ,VM::VM1,"Directory Record Sequence","DirectoryRecordSequence",false }, + {0x0004,0x1400,VR::UL,VM::VM1,"Offset of the Next Directory Record","OffsetOfTheNextDirectoryRecord",false }, + {0x0004,0x1410,VR::US,VM::VM1,"Record In-use Flag","RecordInUseFlag",false }, + {0x0004,0x1420,VR::UL,VM::VM1,"Offset of Referenced Lower-Level Directory Entity","OffsetOfReferencedLowerLevelDirectoryEntity",false }, + {0x0004,0x1430,VR::CS,VM::VM1,"Directory Record Type","DirectoryRecordType",false }, + {0x0004,0x1432,VR::UI,VM::VM1,"Private Record UID","PrivateRecordUID",false }, + {0x0004,0x1500,VR::CS,VM::VM1_8,"Referenced File ID","ReferencedFileID",false }, + {0x0004,0x1504,VR::UL,VM::VM1,"MRDR Directory Record Offset","MRDRDirectoryRecordOffset",true }, + {0x0004,0x1510,VR::UI,VM::VM1,"Referenced SOP Class UID in File","ReferencedSOPClassUIDInFile",false }, + {0x0004,0x1511,VR::UI,VM::VM1,"Referenced SOP Instance UID in File","ReferencedSOPInstanceUIDInFile",false }, + {0x0004,0x1512,VR::UI,VM::VM1,"Referenced Transfer Syntax UID in File","ReferencedTransferSyntaxUIDInFile",false }, + {0x0004,0x151a,VR::UI,VM::VM1_n,"Referenced Related General SOP Class UID in File","ReferencedRelatedGeneralSOPClassUIDInFile",false }, + {0x0004,0x1600,VR::UL,VM::VM1,"Number of References","NumberOfReferences",true }, + {0x0008,0x0001,VR::UL,VM::VM1,"Length to End","LengthToEnd",true }, + {0x0008,0x0005,VR::CS,VM::VM1_n,"Specific Character Set","SpecificCharacterSet",false }, + {0x0008,0x0006,VR::SQ,VM::VM1,"Language Code Sequence","LanguageCodeSequence",false }, + {0x0008,0x0008,VR::CS,VM::VM2_n,"Image Type","ImageType",false }, + {0x0008,0x0010,VR::SH,VM::VM1,"Recognition Code","RecognitionCode",true }, + {0x0008,0x0012,VR::DA,VM::VM1,"Instance Creation Date","InstanceCreationDate",false }, + {0x0008,0x0013,VR::TM,VM::VM1,"Instance Creation Time","InstanceCreationTime",false }, + {0x0008,0x0014,VR::UI,VM::VM1,"Instance Creator UID","InstanceCreatorUID",false }, + {0x0008,0x0016,VR::UI,VM::VM1,"SOP Class UID","SOPClassUID",false }, + {0x0008,0x0018,VR::UI,VM::VM1,"SOP Instance UID","SOPInstanceUID",false }, + {0x0008,0x001a,VR::UI,VM::VM1_n,"Related General SOP Class UID","RelatedGeneralSOPClassUID",false }, + {0x0008,0x001b,VR::UI,VM::VM1,"Original Specialized SOP Class UID","OriginalSpecializedSOPClassUID",false }, + {0x0008,0x0020,VR::DA,VM::VM1,"Study Date","StudyDate",false }, + {0x0008,0x0021,VR::DA,VM::VM1,"Series Date","SeriesDate",false }, + {0x0008,0x0022,VR::DA,VM::VM1,"Acquisition Date","AcquisitionDate",false }, + {0x0008,0x0023,VR::DA,VM::VM1,"Content Date","ContentDate",false }, + {0x0008,0x0024,VR::DA,VM::VM1,"Overlay Date","OverlayDate",true }, + {0x0008,0x0025,VR::DA,VM::VM1,"Curve Date","CurveDate",true }, + {0x0008,0x002a,VR::DT,VM::VM1,"Acquisition Date Time","AcquisitionDateTime",false }, + {0x0008,0x0030,VR::TM,VM::VM1,"Study Time","StudyTime",false }, + {0x0008,0x0031,VR::TM,VM::VM1,"Series Time","SeriesTime",false }, + {0x0008,0x0032,VR::TM,VM::VM1,"Acquisition Time","AcquisitionTime",false }, + {0x0008,0x0033,VR::TM,VM::VM1,"Content Time","ContentTime",false }, + {0x0008,0x0034,VR::TM,VM::VM1,"Overlay Time","OverlayTime",true }, + {0x0008,0x0035,VR::TM,VM::VM1,"Curve Time","CurveTime",true }, + {0x0008,0x0040,VR::US,VM::VM1,"Data Set Type","DataSetType",true }, + {0x0008,0x0041,VR::LO,VM::VM1,"Data Set Subtype","DataSetSubtype",true }, + {0x0008,0x0042,VR::CS,VM::VM1,"Nuclear Medicine Series Type","NuclearMedicineSeriesType",true }, + {0x0008,0x0050,VR::SH,VM::VM1,"Accession Number","AccessionNumber",false }, + {0x0008,0x0051,VR::SQ,VM::VM1,"Issuer of Accession Number Sequence","IssuerOfAccessionNumberSequence",false }, + {0x0008,0x0052,VR::CS,VM::VM1,"Query/Retrieve Level","QueryRetrieveLevel",false }, + {0x0008,0x0054,VR::AE,VM::VM1_n,"Retrieve AE Title","RetrieveAETitle",false }, + {0x0008,0x0056,VR::CS,VM::VM1,"Instance Availability","InstanceAvailability",false }, + {0x0008,0x0058,VR::UI,VM::VM1_n,"Failed SOP Instance UID List","FailedSOPInstanceUIDList",false }, + {0x0008,0x0060,VR::CS,VM::VM1,"Modality","Modality",false }, + {0x0008,0x0061,VR::CS,VM::VM1_n,"Modalities in Study","ModalitiesInStudy",false }, + {0x0008,0x0062,VR::UI,VM::VM1_n,"SOP Classes in Study","SOPClassesInStudy",false }, + {0x0008,0x0064,VR::CS,VM::VM1,"Conversion Type","ConversionType",false }, + {0x0008,0x0068,VR::CS,VM::VM1,"Presentation Intent Type","PresentationIntentType",false }, + {0x0008,0x0070,VR::LO,VM::VM1,"Manufacturer","Manufacturer",false }, + {0x0008,0x0080,VR::LO,VM::VM1,"Institution Name","InstitutionName",false }, + {0x0008,0x0081,VR::ST,VM::VM1,"Institution Address","InstitutionAddress",false }, + {0x0008,0x0082,VR::SQ,VM::VM1,"Institution Code Sequence","InstitutionCodeSequence",false }, + {0x0008,0x0090,VR::PN,VM::VM1,"Referring Physician's Name","ReferringPhysicianName",false }, + {0x0008,0x0092,VR::ST,VM::VM1,"Referring Physician's Address","ReferringPhysicianAddress",false }, + {0x0008,0x0094,VR::SH,VM::VM1_n,"Referring Physician's Telephone Numbers","ReferringPhysicianTelephoneNumbers",false }, + {0x0008,0x0096,VR::SQ,VM::VM1,"Referring Physician Identification Sequence","ReferringPhysicianIdentificationSequence",false }, + {0x0008,0x0100,VR::SH,VM::VM1,"Code Value","CodeValue",false }, + {0x0008,0x0102,VR::SH,VM::VM1,"Coding Scheme Designator","CodingSchemeDesignator",false }, + {0x0008,0x0103,VR::SH,VM::VM1,"Coding Scheme Version","CodingSchemeVersion",false }, + {0x0008,0x0104,VR::LO,VM::VM1,"Code Meaning","CodeMeaning",false }, + {0x0008,0x0105,VR::CS,VM::VM1,"Mapping Resource","MappingResource",false }, + {0x0008,0x0106,VR::DT,VM::VM1,"Context Group Version","ContextGroupVersion",false }, + {0x0008,0x0107,VR::DT,VM::VM1,"Context Group Local Version","ContextGroupLocalVersion",false }, + {0x0008,0x010b,VR::CS,VM::VM1,"Context Group Extension Flag","ContextGroupExtensionFlag",false }, + {0x0008,0x010c,VR::UI,VM::VM1,"Coding Scheme UID","CodingSchemeUID",false }, + {0x0008,0x010d,VR::UI,VM::VM1,"Context Group Extension Creator UID","ContextGroupExtensionCreatorUID",false }, + {0x0008,0x010f,VR::CS,VM::VM1,"Context Identifier","ContextIdentifier",false }, + {0x0008,0x0110,VR::SQ,VM::VM1,"Coding Scheme Identification Sequence","CodingSchemeIdentificationSequence",false }, + {0x0008,0x0112,VR::LO,VM::VM1,"Coding Scheme Registry","CodingSchemeRegistry",false }, + {0x0008,0x0114,VR::ST,VM::VM1,"Coding Scheme External ID","CodingSchemeExternalID",false }, + {0x0008,0x0115,VR::ST,VM::VM1,"Coding Scheme Name","CodingSchemeName",false }, + {0x0008,0x0116,VR::ST,VM::VM1,"Coding Scheme Responsible Organization","CodingSchemeResponsibleOrganization",false }, + {0x0008,0x0117,VR::UI,VM::VM1,"Context UID","ContextUID",false }, + {0x0008,0x0201,VR::SH,VM::VM1,"Timezone Offset From UTC","TimezoneOffsetFromUTC",false }, + {0x0008,0x1000,VR::AE,VM::VM1,"Network ID","NetworkID",true }, + {0x0008,0x1010,VR::SH,VM::VM1,"Station Name","StationName",false }, + {0x0008,0x1030,VR::LO,VM::VM1,"Study Description","StudyDescription",false }, + {0x0008,0x1032,VR::SQ,VM::VM1,"Procedure Code Sequence","ProcedureCodeSequence",false }, + {0x0008,0x103e,VR::LO,VM::VM1,"Series Description","SeriesDescription",false }, + {0x0008,0x103f,VR::SQ,VM::VM1,"Series Description Code Sequence","SeriesDescriptionCodeSequence",false }, + {0x0008,0x1040,VR::LO,VM::VM1,"Institutional Department Name","InstitutionalDepartmentName",false }, + {0x0008,0x1048,VR::PN,VM::VM1_n,"Physician(s) of Record","PhysiciansOfRecord",false }, + {0x0008,0x1049,VR::SQ,VM::VM1,"Physician(s) of Record Identification Sequence","PhysiciansOfRecordIdentificationSequence",false }, + {0x0008,0x1050,VR::PN,VM::VM1_n,"Performing Physician's Name","PerformingPhysicianName",false }, + {0x0008,0x1052,VR::SQ,VM::VM1,"Performing Physician Identification Sequence","PerformingPhysicianIdentificationSequence",false }, + {0x0008,0x1060,VR::PN,VM::VM1_n,"Name of Physician(s) Reading Study","NameOfPhysiciansReadingStudy",false }, + {0x0008,0x1062,VR::SQ,VM::VM1,"Physician(s) Reading Study Identification Sequence","PhysiciansReadingStudyIdentificationSequence",false }, + {0x0008,0x1070,VR::PN,VM::VM1_n,"Operators' Name","OperatorsName",false }, + {0x0008,0x1072,VR::SQ,VM::VM1,"Operator Identification Sequence","OperatorIdentificationSequence",false }, + {0x0008,0x1080,VR::LO,VM::VM1_n,"Admitting Diagnoses Description","AdmittingDiagnosesDescription",false }, + {0x0008,0x1084,VR::SQ,VM::VM1,"Admitting Diagnoses Code Sequence","AdmittingDiagnosesCodeSequence",false }, + {0x0008,0x1090,VR::LO,VM::VM1,"Manufacturer's Model Name","ManufacturerModelName",false }, + {0x0008,0x1100,VR::SQ,VM::VM1,"Referenced Results Sequence","ReferencedResultsSequence",true }, + {0x0008,0x1110,VR::SQ,VM::VM1,"Referenced Study Sequence","ReferencedStudySequence",false }, + {0x0008,0x1111,VR::SQ,VM::VM1,"Referenced Performed Procedure Step Sequence","ReferencedPerformedProcedureStepSequence",false }, + {0x0008,0x1115,VR::SQ,VM::VM1,"Referenced Series Sequence","ReferencedSeriesSequence",false }, + {0x0008,0x1120,VR::SQ,VM::VM1,"Referenced Patient Sequence","ReferencedPatientSequence",false }, + {0x0008,0x1125,VR::SQ,VM::VM1,"Referenced Visit Sequence","ReferencedVisitSequence",false }, + {0x0008,0x1130,VR::SQ,VM::VM1,"Referenced Overlay Sequence","ReferencedOverlaySequence",true }, + {0x0008,0x1134,VR::SQ,VM::VM1,"Referenced Stereometric Instance Sequence","ReferencedStereometricInstanceSequence",false }, + {0x0008,0x113a,VR::SQ,VM::VM1,"Referenced Waveform Sequence","ReferencedWaveformSequence",false }, + {0x0008,0x1140,VR::SQ,VM::VM1,"Referenced Image Sequence","ReferencedImageSequence",false }, + {0x0008,0x1145,VR::SQ,VM::VM1,"Referenced Curve Sequence","ReferencedCurveSequence",true }, + {0x0008,0x114a,VR::SQ,VM::VM1,"Referenced Instance Sequence","ReferencedInstanceSequence",false }, + {0x0008,0x114b,VR::SQ,VM::VM1,"Referenced Real World Value Mapping Instance Sequence","ReferencedRealWorldValueMappingInstanceSequence",false }, + {0x0008,0x1150,VR::UI,VM::VM1,"Referenced SOP Class UID","ReferencedSOPClassUID",false }, + {0x0008,0x1155,VR::UI,VM::VM1,"Referenced SOP Instance UID","ReferencedSOPInstanceUID",false }, + {0x0008,0x115a,VR::UI,VM::VM1_n,"SOP Classes Supported","SOPClassesSupported",false }, + {0x0008,0x1160,VR::IS,VM::VM1_n,"Referenced Frame Number","ReferencedFrameNumber",false }, + {0x0008,0x1161,VR::UL,VM::VM1_n,"Simple Frame List","SimpleFrameList",false }, + {0x0008,0x1162,VR::UL,VM::VM3_3n,"Calculated Frame List","CalculatedFrameList",false }, + {0x0008,0x1163,VR::FD,VM::VM2,"Time Range","TimeRange",false }, + {0x0008,0x1164,VR::SQ,VM::VM1,"Frame Extraction Sequence","FrameExtractionSequence",false }, + {0x0008,0x1167,VR::UI,VM::VM1,"Multi-Frame Source SOP Instance UID","MultiFrameSourceSOPInstanceUID",false }, + {0x0008,0x1195,VR::UI,VM::VM1,"Transaction UID","TransactionUID",false }, + {0x0008,0x1197,VR::US,VM::VM1,"Failure Reason","FailureReason",false }, + {0x0008,0x1198,VR::SQ,VM::VM1,"Failed SOP Sequence","FailedSOPSequence",false }, + {0x0008,0x1199,VR::SQ,VM::VM1,"Referenced SOP Sequence","ReferencedSOPSequence",false }, + {0x0008,0x1200,VR::SQ,VM::VM1,"Studies Containing Other Referenced Instances Sequence","StudiesContainingOtherReferencedInstancesSequence",false }, + {0x0008,0x1250,VR::SQ,VM::VM1,"Related Series Sequence","RelatedSeriesSequence",false }, + {0x0008,0x2110,VR::CS,VM::VM1,"Lossy Image Compression (Retired)","LossyImageCompressionRetired",true }, + {0x0008,0x2111,VR::ST,VM::VM1,"Derivation Description","DerivationDescription",false }, + {0x0008,0x2112,VR::SQ,VM::VM1,"Source Image Sequence","SourceImageSequence",false }, + {0x0008,0x2120,VR::SH,VM::VM1,"Stage Name","StageName",false }, + {0x0008,0x2122,VR::IS,VM::VM1,"Stage Number","StageNumber",false }, + {0x0008,0x2124,VR::IS,VM::VM1,"Number of Stages","NumberOfStages",false }, + {0x0008,0x2127,VR::SH,VM::VM1,"View Name","ViewName",false }, + {0x0008,0x2128,VR::IS,VM::VM1,"View Number","ViewNumber",false }, + {0x0008,0x2129,VR::IS,VM::VM1,"Number of Event Timers","NumberOfEventTimers",false }, + {0x0008,0x212a,VR::IS,VM::VM1,"Number of Views in Stage","NumberOfViewsInStage",false }, + {0x0008,0x2130,VR::DS,VM::VM1_n,"Event Elapsed Time(s)","EventElapsedTimes",false }, + {0x0008,0x2132,VR::LO,VM::VM1_n,"Event Timer Name(s)","EventTimerNames",false }, + {0x0008,0x2133,VR::SQ,VM::VM1,"Event Timer Sequence","EventTimerSequence",false }, + {0x0008,0x2134,VR::FD,VM::VM1,"Event Time Offset","EventTimeOffset",false }, + {0x0008,0x2135,VR::SQ,VM::VM1,"Event Code Sequence","EventCodeSequence",false }, + {0x0008,0x2142,VR::IS,VM::VM1,"Start Trim","StartTrim",false }, + {0x0008,0x2143,VR::IS,VM::VM1,"Stop Trim","StopTrim",false }, + {0x0008,0x2144,VR::IS,VM::VM1,"Recommended Display Frame Rate","RecommendedDisplayFrameRate",false }, + {0x0008,0x2200,VR::CS,VM::VM1,"Transducer Position","TransducerPosition",true }, + {0x0008,0x2204,VR::CS,VM::VM1,"Transducer Orientation","TransducerOrientation",true }, + {0x0008,0x2208,VR::CS,VM::VM1,"Anatomic Structure","AnatomicStructure",true }, + {0x0008,0x2218,VR::SQ,VM::VM1,"Anatomic Region Sequence","AnatomicRegionSequence",false }, + {0x0008,0x2220,VR::SQ,VM::VM1,"Anatomic Region Modifier Sequence","AnatomicRegionModifierSequence",false }, + {0x0008,0x2228,VR::SQ,VM::VM1,"Primary Anatomic Structure Sequence","PrimaryAnatomicStructureSequence",false }, + {0x0008,0x2229,VR::SQ,VM::VM1,"Anatomic Structure, Space or Region Sequence","AnatomicStructureSpaceOrRegionSequence",false }, + {0x0008,0x2230,VR::SQ,VM::VM1,"Primary Anatomic Structure Modifier Sequence","PrimaryAnatomicStructureModifierSequence",false }, + {0x0008,0x2240,VR::SQ,VM::VM1,"Transducer Position Sequence","TransducerPositionSequence",true }, + {0x0008,0x2242,VR::SQ,VM::VM1,"Transducer Position Modifier Sequence","TransducerPositionModifierSequence",true }, + {0x0008,0x2244,VR::SQ,VM::VM1,"Transducer Orientation Sequence","TransducerOrientationSequence",true }, + {0x0008,0x2246,VR::SQ,VM::VM1,"Transducer Orientation Modifier Sequence","TransducerOrientationModifierSequence",true }, + {0x0008,0x2251,VR::SQ,VM::VM1,"Anatomic Structure Space Or Region Code Sequence (Trial)","AnatomicStructureSpaceOrRegionCodeSequenceTrial",true }, + {0x0008,0x2253,VR::SQ,VM::VM1,"Anatomic Portal Of Entrance Code Sequence (Trial)","AnatomicPortalOfEntranceCodeSequenceTrial",true }, + {0x0008,0x2255,VR::SQ,VM::VM1,"Anatomic Approach Direction Code Sequence (Trial)","AnatomicApproachDirectionCodeSequenceTrial",true }, + {0x0008,0x2256,VR::ST,VM::VM1,"Anatomic Perspective Description (Trial)","AnatomicPerspectiveDescriptionTrial",true }, + {0x0008,0x2257,VR::SQ,VM::VM1,"Anatomic Perspective Code Sequence (Trial)","AnatomicPerspectiveCodeSequenceTrial",true }, + {0x0008,0x2258,VR::ST,VM::VM1,"Anatomic Location Of Examining Instrument Description (Trial)","AnatomicLocationOfExaminingInstrumentDescriptionTrial",true }, + {0x0008,0x2259,VR::SQ,VM::VM1,"Anatomic Location Of Examining Instrument Code Sequence (Trial)","AnatomicLocationOfExaminingInstrumentCodeSequenceTrial",true }, + {0x0008,0x225a,VR::SQ,VM::VM1,"Anatomic Structure Space Or Region Modifier Code Sequence (Trial)","AnatomicStructureSpaceOrRegionModifierCodeSequenceTrial",true }, + {0x0008,0x225c,VR::SQ,VM::VM1,"OnAxis Background Anatomic Structure Code Sequence (Trial)","OnAxisBackgroundAnatomicStructureCodeSequenceTrial",true }, + {0x0008,0x3001,VR::SQ,VM::VM1,"Alternate Representation Sequence","AlternateRepresentationSequence",false }, + {0x0008,0x3010,VR::UI,VM::VM1,"Irradiation Event UID","IrradiationEventUID",false }, + {0x0008,0x4000,VR::LT,VM::VM1,"Identifying Comments","IdentifyingComments",true }, + {0x0008,0x9007,VR::CS,VM::VM4,"Frame Type","FrameType",false }, + {0x0008,0x9092,VR::SQ,VM::VM1,"Referenced Image Evidence Sequence","ReferencedImageEvidenceSequence",false }, + {0x0008,0x9121,VR::SQ,VM::VM1,"Referenced Raw Data Sequence","ReferencedRawDataSequence",false }, + {0x0008,0x9123,VR::UI,VM::VM1,"Creator-Version UID","CreatorVersionUID",false }, + {0x0008,0x9124,VR::SQ,VM::VM1,"Derivation Image Sequence","DerivationImageSequence",false }, + {0x0008,0x9154,VR::SQ,VM::VM1,"Source Image Evidence Sequence","SourceImageEvidenceSequence",false }, + {0x0008,0x9205,VR::CS,VM::VM1,"Pixel Presentation","PixelPresentation",false }, + {0x0008,0x9206,VR::CS,VM::VM1,"Volumetric Properties","VolumetricProperties",false }, + {0x0008,0x9207,VR::CS,VM::VM1,"Volume Based Calculation Technique","VolumeBasedCalculationTechnique",false }, + {0x0008,0x9208,VR::CS,VM::VM1,"Complex Image Component","ComplexImageComponent",false }, + {0x0008,0x9209,VR::CS,VM::VM1,"Acquisition Contrast","AcquisitionContrast",false }, + {0x0008,0x9215,VR::SQ,VM::VM1,"Derivation Code Sequence","DerivationCodeSequence",false }, + {0x0008,0x9237,VR::SQ,VM::VM1,"Referenced Presentation State Sequence","ReferencedPresentationStateSequence",false }, + {0x0008,0x9410,VR::SQ,VM::VM1,"Referenced Other Plane Sequence","ReferencedOtherPlaneSequence",false }, + {0x0008,0x9458,VR::SQ,VM::VM1,"Frame Display Sequence","FrameDisplaySequence",false }, + {0x0008,0x9459,VR::FL,VM::VM1,"Recommended Display Frame Rate in Float","RecommendedDisplayFrameRateInFloat",false }, + {0x0008,0x9460,VR::CS,VM::VM1,"Skip Frame Range Flag","SkipFrameRangeFlag",false }, + {0x0010,0x0010,VR::PN,VM::VM1,"Patient's Name","PatientName",false }, + {0x0010,0x0020,VR::LO,VM::VM1,"Patient ID","PatientID",false }, + {0x0010,0x0021,VR::LO,VM::VM1,"Issuer of Patient ID","IssuerOfPatientID",false }, + {0x0010,0x0022,VR::CS,VM::VM1,"Type of Patient ID","TypeOfPatientID",false }, + {0x0010,0x0024,VR::SQ,VM::VM1,"Issuer of Patient ID Qualifiers Sequence","IssuerOfPatientIDQualifiersSequence",false }, + {0x0010,0x0030,VR::DA,VM::VM1,"Patient's Birth Date","PatientBirthDate",false }, + {0x0010,0x0032,VR::TM,VM::VM1,"Patient's Birth Time","PatientBirthTime",false }, + {0x0010,0x0040,VR::CS,VM::VM1,"Patient's Sex","PatientSex",false }, + {0x0010,0x0050,VR::SQ,VM::VM1,"Patient's Insurance Plan Code Sequence","PatientInsurancePlanCodeSequence",false }, + {0x0010,0x0101,VR::SQ,VM::VM1,"Patient's Primary Language Code Sequence","PatientPrimaryLanguageCodeSequence",false }, + {0x0010,0x0102,VR::SQ,VM::VM1,"Patient's Primary Language Modifier Code Sequence","PatientPrimaryLanguageModifierCodeSequence",false }, + {0x0010,0x1000,VR::LO,VM::VM1_n,"Other Patient IDs","OtherPatientIDs",false }, + {0x0010,0x1001,VR::PN,VM::VM1_n,"Other Patient Names","OtherPatientNames",false }, + {0x0010,0x1002,VR::SQ,VM::VM1,"Other Patient IDs Sequence","OtherPatientIDsSequence",false }, + {0x0010,0x1005,VR::PN,VM::VM1,"Patient's Birth Name","PatientBirthName",false }, + {0x0010,0x1010,VR::AS,VM::VM1,"Patient's Age","PatientAge",false }, + {0x0010,0x1020,VR::DS,VM::VM1,"Patient's Size","PatientSize",false }, + {0x0010,0x1021,VR::SQ,VM::VM1,"Patient's Size Code Sequence","PatientSizeCodeSequence",false }, + {0x0010,0x1030,VR::DS,VM::VM1,"Patient's Weight","PatientWeight",false }, + {0x0010,0x1040,VR::LO,VM::VM1,"Patient's Address","PatientAddress",false }, + {0x0010,0x1050,VR::LO,VM::VM1_n,"Insurance Plan Identification","InsurancePlanIdentification",true }, + {0x0010,0x1060,VR::PN,VM::VM1,"Patient's Mother's Birth Name","PatientMotherBirthName",false }, + {0x0010,0x1080,VR::LO,VM::VM1,"Military Rank","MilitaryRank",false }, + {0x0010,0x1081,VR::LO,VM::VM1,"Branch of Service","BranchOfService",false }, + {0x0010,0x1090,VR::LO,VM::VM1,"Medical Record Locator","MedicalRecordLocator",false }, + {0x0010,0x2000,VR::LO,VM::VM1_n,"Medical Alerts","MedicalAlerts",false }, + {0x0010,0x2110,VR::LO,VM::VM1_n,"Allergies","Allergies",false }, + {0x0010,0x2150,VR::LO,VM::VM1,"Country of Residence","CountryOfResidence",false }, + {0x0010,0x2152,VR::LO,VM::VM1,"Region of Residence","RegionOfResidence",false }, + {0x0010,0x2154,VR::SH,VM::VM1_n,"Patient's Telephone Numbers","PatientTelephoneNumbers",false }, + {0x0010,0x2160,VR::SH,VM::VM1,"Ethnic Group","EthnicGroup",false }, + {0x0010,0x2180,VR::SH,VM::VM1,"Occupation","Occupation",false }, + {0x0010,0x21a0,VR::CS,VM::VM1,"Smoking Status","SmokingStatus",false }, + {0x0010,0x21b0,VR::LT,VM::VM1,"Additional Patient History","AdditionalPatientHistory",false }, + {0x0010,0x21c0,VR::US,VM::VM1,"Pregnancy Status","PregnancyStatus",false }, + {0x0010,0x21d0,VR::DA,VM::VM1,"Last Menstrual Date","LastMenstrualDate",false }, + {0x0010,0x21f0,VR::LO,VM::VM1,"Patient's Religious Preference","PatientReligiousPreference",false }, + {0x0010,0x2201,VR::LO,VM::VM1,"Patient Species Description","PatientSpeciesDescription",false }, + {0x0010,0x2202,VR::SQ,VM::VM1,"Patient Species Code Sequence","PatientSpeciesCodeSequence",false }, + {0x0010,0x2203,VR::CS,VM::VM1,"Patient's Sex Neutered","PatientSexNeutered",false }, + {0x0010,0x2210,VR::CS,VM::VM1,"Anatomical Orientation Type","AnatomicalOrientationType",false }, + {0x0010,0x2292,VR::LO,VM::VM1,"Patient Breed Description","PatientBreedDescription",false }, + {0x0010,0x2293,VR::SQ,VM::VM1,"Patient Breed Code Sequence","PatientBreedCodeSequence",false }, + {0x0010,0x2294,VR::SQ,VM::VM1,"Breed Registration Sequence","BreedRegistrationSequence",false }, + {0x0010,0x2295,VR::LO,VM::VM1,"Breed Registration Number","BreedRegistrationNumber",false }, + {0x0010,0x2296,VR::SQ,VM::VM1,"Breed Registry Code Sequence","BreedRegistryCodeSequence",false }, + {0x0010,0x2297,VR::PN,VM::VM1,"Responsible Person","ResponsiblePerson",false }, + {0x0010,0x2298,VR::CS,VM::VM1,"Responsible Person Role","ResponsiblePersonRole",false }, + {0x0010,0x2299,VR::LO,VM::VM1,"Responsible Organization","ResponsibleOrganization",false }, + {0x0010,0x4000,VR::LT,VM::VM1,"Patient Comments","PatientComments",false }, + {0x0010,0x9431,VR::FL,VM::VM1,"Examined Body Thickness","ExaminedBodyThickness",false }, + {0x0012,0x0010,VR::LO,VM::VM1,"Clinical Trial Sponsor Name","ClinicalTrialSponsorName",false }, + {0x0012,0x0020,VR::LO,VM::VM1,"Clinical Trial Protocol ID","ClinicalTrialProtocolID",false }, + {0x0012,0x0021,VR::LO,VM::VM1,"Clinical Trial Protocol Name","ClinicalTrialProtocolName",false }, + {0x0012,0x0030,VR::LO,VM::VM1,"Clinical Trial Site ID","ClinicalTrialSiteID",false }, + {0x0012,0x0031,VR::LO,VM::VM1,"Clinical Trial Site Name","ClinicalTrialSiteName",false }, + {0x0012,0x0040,VR::LO,VM::VM1,"Clinical Trial Subject ID","ClinicalTrialSubjectID",false }, + {0x0012,0x0042,VR::LO,VM::VM1,"Clinical Trial Subject Reading ID","ClinicalTrialSubjectReadingID",false }, + {0x0012,0x0050,VR::LO,VM::VM1,"Clinical Trial Time Point ID","ClinicalTrialTimePointID",false }, + {0x0012,0x0051,VR::ST,VM::VM1,"Clinical Trial Time Point Description","ClinicalTrialTimePointDescription",false }, + {0x0012,0x0060,VR::LO,VM::VM1,"Clinical Trial Coordinating Center Name","ClinicalTrialCoordinatingCenterName",false }, + {0x0012,0x0062,VR::CS,VM::VM1,"Patient Identity Removed","PatientIdentityRemoved",false }, + {0x0012,0x0063,VR::LO,VM::VM1_n,"De-identification Method","DeidentificationMethod",false }, + {0x0012,0x0064,VR::SQ,VM::VM1,"De-identification Method Code Sequence","DeidentificationMethodCodeSequence",false }, + {0x0012,0x0071,VR::LO,VM::VM1,"Clinical Trial Series ID","ClinicalTrialSeriesID",false }, + {0x0012,0x0072,VR::LO,VM::VM1,"Clinical Trial Series Description","ClinicalTrialSeriesDescription",false }, + {0x0012,0x0081,VR::LO,VM::VM1,"Clinical Trial Protocol Ethics Committee Name","ClinicalTrialProtocolEthicsCommitteeName",false }, + {0x0012,0x0082,VR::LO,VM::VM1,"Clinical Trial Protocol Ethics Committee Approval Number","ClinicalTrialProtocolEthicsCommitteeApprovalNumber",false }, + {0x0012,0x0083,VR::SQ,VM::VM1,"Consent for Clinical Trial Use Sequence","ConsentForClinicalTrialUseSequence",false }, + {0x0012,0x0084,VR::CS,VM::VM1,"Distribution Type","DistributionType",false }, + {0x0012,0x0085,VR::CS,VM::VM1,"Consent for Distribution Flag","ConsentForDistributionFlag",false }, + {0x0014,0x0023,VR::ST,VM::VM1_n,"CAD File Format","CADFileFormat",false }, + {0x0014,0x0024,VR::ST,VM::VM1_n,"Component Reference System","ComponentReferenceSystem",false }, + {0x0014,0x0025,VR::ST,VM::VM1_n,"Component Manufacturing Procedure","ComponentManufacturingProcedure",false }, + {0x0014,0x0028,VR::ST,VM::VM1_n,"Component Manufacturer","ComponentManufacturer",false }, + {0x0014,0x0030,VR::DS,VM::VM1_n,"Material Thickness","MaterialThickness",false }, + {0x0014,0x0032,VR::DS,VM::VM1_n,"Material Pipe Diameter","MaterialPipeDiameter",false }, + {0x0014,0x0034,VR::DS,VM::VM1_n,"Material Isolation Diameter","MaterialIsolationDiameter",false }, + {0x0014,0x0042,VR::ST,VM::VM1_n,"Material Grade","MaterialGrade",false }, + {0x0014,0x0044,VR::ST,VM::VM1_n,"Material Properties File ID","MaterialPropertiesFileID",false }, + {0x0014,0x0045,VR::ST,VM::VM1_n,"Material Properties File Format","MaterialPropertiesFileFormat",false }, + {0x0014,0x0046,VR::LT,VM::VM1,"Material Notes","MaterialNotes",false }, + {0x0014,0x0050,VR::CS,VM::VM1,"Component Shape","ComponentShape",false }, + {0x0014,0x0052,VR::CS,VM::VM1,"Curvature Type","CurvatureType",false }, + {0x0014,0x0054,VR::DS,VM::VM1,"Outer Diameter","OuterDiameter",false }, + {0x0014,0x0056,VR::DS,VM::VM1,"Inner Diameter","InnerDiameter",false }, + {0x0014,0x1010,VR::ST,VM::VM1,"Actual Environmental Conditions","ActualEnvironmentalConditions",false }, + {0x0014,0x1020,VR::DA,VM::VM1,"Expiry Date","ExpiryDate",false }, + {0x0014,0x1040,VR::ST,VM::VM1,"Environmental Conditions","EnvironmentalConditions",false }, + {0x0014,0x2002,VR::SQ,VM::VM1,"Evaluator Sequence","EvaluatorSequence",false }, + {0x0014,0x2004,VR::IS,VM::VM1,"Evaluator Number","EvaluatorNumber",false }, + {0x0014,0x2006,VR::PN,VM::VM1,"Evaluator Name","EvaluatorName",false }, + {0x0014,0x2008,VR::IS,VM::VM1,"Evaluation Attempt","EvaluationAttempt",false }, + {0x0014,0x2012,VR::SQ,VM::VM1,"Indication Sequence","IndicationSequence",false }, + {0x0014,0x2014,VR::IS,VM::VM1,"Indication Number","IndicationNumber",false }, + {0x0014,0x2016,VR::SH,VM::VM1,"Indication Label","IndicationLabel",false }, + {0x0014,0x2018,VR::ST,VM::VM1,"Indication Description","IndicationDescription",false }, + {0x0014,0x201a,VR::CS,VM::VM1_n,"Indication Type","IndicationType",false }, + {0x0014,0x201c,VR::CS,VM::VM1,"Indication Disposition","IndicationDisposition",false }, + {0x0014,0x201e,VR::SQ,VM::VM1,"Indication ROI Sequence","IndicationROISequence",false }, + {0x0014,0x2030,VR::SQ,VM::VM1,"Indication Physical Property Sequence","IndicationPhysicalPropertySequence",false }, + {0x0014,0x2032,VR::SH,VM::VM1,"Property Label","PropertyLabel",false }, + {0x0014,0x2202,VR::IS,VM::VM1,"Coordinate System Number of Axes","CoordinateSystemNumberOfAxes",false }, + {0x0014,0x2204,VR::SQ,VM::VM1,"Coordinate System Axes Sequence","CoordinateSystemAxesSequence",false }, + {0x0014,0x2206,VR::ST,VM::VM1,"Coordinate System Axis Description","CoordinateSystemAxisDescription",false }, + {0x0014,0x2208,VR::CS,VM::VM1,"Coordinate System Data Set Mapping","CoordinateSystemDataSetMapping",false }, + {0x0014,0x220a,VR::IS,VM::VM1,"Coordinate System Axis Number","CoordinateSystemAxisNumber",false }, + {0x0014,0x220c,VR::CS,VM::VM1,"Coordinate System Axis Type","CoordinateSystemAxisType",false }, + {0x0014,0x220e,VR::CS,VM::VM1,"Coordinate System Axis Units","CoordinateSystemAxisUnits",false }, + {0x0014,0x2210,VR::OB,VM::VM1,"Coordinate System Axis Values","CoordinateSystemAxisValues",false }, + {0x0014,0x2220,VR::SQ,VM::VM1,"Coordinate System Transform Sequence","CoordinateSystemTransformSequence",false }, + {0x0014,0x2222,VR::ST,VM::VM1,"Transform Description","TransformDescription",false }, + {0x0014,0x2224,VR::IS,VM::VM1,"Transform Number of Axes","TransformNumberOfAxes",false }, + {0x0014,0x2226,VR::IS,VM::VM1_n,"Transform Order of Axes","TransformOrderOfAxes",false }, + {0x0014,0x2228,VR::CS,VM::VM1,"Transformed Axis Units","TransformedAxisUnits",false }, + {0x0014,0x222a,VR::DS,VM::VM1_n,"Coordinate System Transform Rotation and Scale Matrix","CoordinateSystemTransformRotationAndScaleMatrix",false }, + {0x0014,0x222c,VR::DS,VM::VM1_n,"Coordinate System Transform Translation Matrix","CoordinateSystemTransformTranslationMatrix",false }, + {0x0014,0x3011,VR::DS,VM::VM1,"Internal Detector Frame Time","InternalDetectorFrameTime",false }, + {0x0014,0x3012,VR::DS,VM::VM1,"Number of Frames Integrated","NumberOfFramesIntegrated",false }, + {0x0014,0x3020,VR::SQ,VM::VM1,"Detector Temperature Sequence","DetectorTemperatureSequence",false }, + {0x0014,0x3022,VR::ST,VM::VM1,"Sensor Name","SensorName",false }, + {0x0014,0x3024,VR::DS,VM::VM1,"Horizontal Offset of Sensor","HorizontalOffsetOfSensor",false }, + {0x0014,0x3026,VR::DS,VM::VM1,"Vertical Offset of Sensor","VerticalOffsetOfSensor",false }, + {0x0014,0x3028,VR::DS,VM::VM1,"Sensor Temperature","SensorTemperature",false }, + {0x0014,0x3040,VR::SQ,VM::VM1,"Dark Current Sequence","DarkCurrentSequence",false }, + {0x0014,0x3050,VR::OB_OW,VM::VM1,"Dark Current Counts","DarkCurrentCounts",false }, + {0x0014,0x3060,VR::SQ,VM::VM1,"Gain Correction Reference Sequence","GainCorrectionReferenceSequence",false }, + {0x0014,0x3070,VR::OB_OW,VM::VM1,"Air Counts","AirCounts",false }, + {0x0014,0x3071,VR::DS,VM::VM1,"KV Used in Gain Calibration","KVUsedInGainCalibration",false }, + {0x0014,0x3072,VR::DS,VM::VM1,"MA Used in Gain Calibration","MAUsedInGainCalibration",false }, + {0x0014,0x3073,VR::DS,VM::VM1,"Number of Frames Used for Integration","NumberOfFramesUsedForIntegration",false }, + {0x0014,0x3074,VR::LO,VM::VM1,"Filter Material Used in Gain Calibration","FilterMaterialUsedInGainCalibration",false }, + {0x0014,0x3075,VR::DS,VM::VM1,"Filter Thickness Used in Gain Calibration","FilterThicknessUsedInGainCalibration",false }, + {0x0014,0x3076,VR::DA,VM::VM1,"Date of Gain Calibration","DateOfGainCalibration",false }, + {0x0014,0x3077,VR::TM,VM::VM1,"Time of Gain Calibration","TimeOfGainCalibration",false }, + {0x0014,0x3080,VR::OB,VM::VM1,"Bad Pixel Image","BadPixelImage",false }, + {0x0014,0x3099,VR::LT,VM::VM1,"Calibration Notes","CalibrationNotes",false }, + {0x0014,0x4002,VR::SQ,VM::VM1,"Pulser Equipment Sequence","PulserEquipmentSequence",false }, + {0x0014,0x4004,VR::CS,VM::VM1,"Pulser Type","PulserType",false }, + {0x0014,0x4006,VR::LT,VM::VM1,"Pulser Notes","PulserNotes",false }, + {0x0014,0x4008,VR::SQ,VM::VM1,"Receiver Equipment Sequence","ReceiverEquipmentSequence",false }, + {0x0014,0x400a,VR::CS,VM::VM1,"Amplifier Type","AmplifierType",false }, + {0x0014,0x400c,VR::LT,VM::VM1,"Receiver Notes","ReceiverNotes",false }, + {0x0014,0x400e,VR::SQ,VM::VM1,"Pre-Amplifier Equipment Sequence","PreAmplifierEquipmentSequence",false }, + {0x0014,0x400f,VR::LT,VM::VM1,"Pre-Amplifier Notes","PreAmplifierNotes",false }, + {0x0014,0x4010,VR::SQ,VM::VM1,"Transmit Transducer Sequence","TransmitTransducerSequence",false }, + {0x0014,0x4011,VR::SQ,VM::VM1,"Receive Transducer Sequence","ReceiveTransducerSequence",false }, + {0x0014,0x4012,VR::US,VM::VM1,"Number of Elements","NumberOfElements",false }, + {0x0014,0x4013,VR::CS,VM::VM1,"Element Shape","ElementShape",false }, + {0x0014,0x4014,VR::DS,VM::VM1,"Element Dimension A","ElementDimensionA",false }, + {0x0014,0x4015,VR::DS,VM::VM1,"Element Dimension B","ElementDimensionB",false }, + {0x0014,0x4016,VR::DS,VM::VM1,"Element Pitch","ElementPitch",false }, + {0x0014,0x4017,VR::DS,VM::VM1,"Measured Beam Dimension A","MeasuredBeamDimensionA",false }, + {0x0014,0x4018,VR::DS,VM::VM1,"Measured Beam Dimension B","MeasuredBeamDimensionB",false }, + {0x0014,0x4019,VR::DS,VM::VM1,"Location of Measured Beam Diameter","LocationOfMeasuredBeamDiameter",false }, + {0x0014,0x401a,VR::DS,VM::VM1,"Nominal Frequency","NominalFrequency",false }, + {0x0014,0x401b,VR::DS,VM::VM1,"Measured Center Frequency","MeasuredCenterFrequency",false }, + {0x0014,0x401c,VR::DS,VM::VM1,"Measured Bandwidth","MeasuredBandwidth",false }, + {0x0014,0x4020,VR::SQ,VM::VM1,"Pulser Settings Sequence","PulserSettingsSequence",false }, + {0x0014,0x4022,VR::DS,VM::VM1,"Pulse Width","PulseWidth",false }, + {0x0014,0x4024,VR::DS,VM::VM1,"Excitation Frequency","ExcitationFrequency",false }, + {0x0014,0x4026,VR::CS,VM::VM1,"Modulation Type","ModulationType",false }, + {0x0014,0x4028,VR::DS,VM::VM1,"Damping","Damping",false }, + {0x0014,0x4030,VR::SQ,VM::VM1,"Receiver Settings Sequence","ReceiverSettingsSequence",false }, + {0x0014,0x4031,VR::DS,VM::VM1,"Acquired Soundpath Length","AcquiredSoundpathLength",false }, + {0x0014,0x4032,VR::CS,VM::VM1,"Acquisition Compression Type","AcquisitionCompressionType",false }, + {0x0014,0x4033,VR::IS,VM::VM1,"Acquisition Sample Size","AcquisitionSampleSize",false }, + {0x0014,0x4034,VR::DS,VM::VM1,"Rectifier Smoothing","RectifierSmoothing",false }, + {0x0014,0x4035,VR::SQ,VM::VM1,"DAC Sequence","DACSequence",false }, + {0x0014,0x4036,VR::CS,VM::VM1,"DAC Type","DACType",false }, + {0x0014,0x4038,VR::DS,VM::VM1_n,"DAC Gain Points","DACGainPoints",false }, + {0x0014,0x403a,VR::DS,VM::VM1_n,"DAC Time Points","DACTimePoints",false }, + {0x0014,0x403c,VR::DS,VM::VM1_n,"DAC Amplitude","DACAmplitude",false }, + {0x0014,0x4040,VR::SQ,VM::VM1,"Pre-Amplifier Settings Sequence","PreAmplifierSettingsSequence",false }, + {0x0014,0x4050,VR::SQ,VM::VM1,"Transmit Transducer Settings Sequence","TransmitTransducerSettingsSequence",false }, + {0x0014,0x4051,VR::SQ,VM::VM1,"Receive Transducer Settings Sequence","ReceiveTransducerSettingsSequence",false }, + {0x0014,0x4052,VR::DS,VM::VM1,"Incident Angle","IncidentAngle",false }, + {0x0014,0x4054,VR::ST,VM::VM1,"Coupling Technique","CouplingTechnique",false }, + {0x0014,0x4056,VR::ST,VM::VM1,"Coupling Medium","CouplingMedium",false }, + {0x0014,0x4057,VR::DS,VM::VM1,"Coupling Velocity","CouplingVelocity",false }, + {0x0014,0x4058,VR::DS,VM::VM1,"Crystal Center Location X","CrystalCenterLocationX",false }, + {0x0014,0x4059,VR::DS,VM::VM1,"Crystal Center Location Z","CrystalCenterLocationZ",false }, + {0x0014,0x405a,VR::DS,VM::VM1,"Sound Path Length","SoundPathLength",false }, + {0x0014,0x405c,VR::ST,VM::VM1,"Delay Law Identifier","DelayLawIdentifier",false }, + {0x0014,0x4060,VR::SQ,VM::VM1,"Gate Settings Sequence","GateSettingsSequence",false }, + {0x0014,0x4062,VR::DS,VM::VM1,"Gate Threshold","GateThreshold",false }, + {0x0014,0x4064,VR::DS,VM::VM1,"Velocity of Sound","VelocityOfSound",false }, + {0x0014,0x4070,VR::SQ,VM::VM1,"Calibration Settings Sequence","CalibrationSettingsSequence",false }, + {0x0014,0x4072,VR::ST,VM::VM1,"Calibration Procedure","CalibrationProcedure",false }, + {0x0014,0x4074,VR::SH,VM::VM1,"Procedure Version","ProcedureVersion",false }, + {0x0014,0x4076,VR::DA,VM::VM1,"Procedure Creation Date","ProcedureCreationDate",false }, + {0x0014,0x4078,VR::DA,VM::VM1,"Procedure Expiration Date","ProcedureExpirationDate",false }, + {0x0014,0x407a,VR::DA,VM::VM1,"Procedure Last Modified Date","ProcedureLastModifiedDate",false }, + {0x0014,0x407c,VR::TM,VM::VM1_n,"Calibration Time","CalibrationTime",false }, + {0x0014,0x407e,VR::DA,VM::VM1_n,"Calibration Date","CalibrationDate",false }, + {0x0014,0x5002,VR::IS,VM::VM1,"LINAC Energy","LINACEnergy",false }, + {0x0014,0x5004,VR::IS,VM::VM1,"LINAC Output","LINACOutput",false }, + {0x0018,0x0010,VR::LO,VM::VM1,"Contrast/Bolus Agent","ContrastBolusAgent",false }, + {0x0018,0x0012,VR::SQ,VM::VM1,"Contrast/Bolus Agent Sequence","ContrastBolusAgentSequence",false }, + {0x0018,0x0014,VR::SQ,VM::VM1,"Contrast/Bolus Administration Route Sequence","ContrastBolusAdministrationRouteSequence",false }, + {0x0018,0x0015,VR::CS,VM::VM1,"Body Part Examined","BodyPartExamined",false }, + {0x0018,0x0020,VR::CS,VM::VM1_n,"Scanning Sequence","ScanningSequence",false }, + {0x0018,0x0021,VR::CS,VM::VM1_n,"Sequence Variant","SequenceVariant",false }, + {0x0018,0x0022,VR::CS,VM::VM1_n,"Scan Options","ScanOptions",false }, + {0x0018,0x0023,VR::CS,VM::VM1,"MR Acquisition Type","MRAcquisitionType",false }, + {0x0018,0x0024,VR::SH,VM::VM1,"Sequence Name","SequenceName",false }, + {0x0018,0x0025,VR::CS,VM::VM1,"Angio Flag","AngioFlag",false }, + {0x0018,0x0026,VR::SQ,VM::VM1,"Intervention Drug Information Sequence","InterventionDrugInformationSequence",false }, + {0x0018,0x0027,VR::TM,VM::VM1,"Intervention Drug Stop Time","InterventionDrugStopTime",false }, + {0x0018,0x0028,VR::DS,VM::VM1,"Intervention Drug Dose","InterventionDrugDose",false }, + {0x0018,0x0029,VR::SQ,VM::VM1,"Intervention Drug Code Sequence","InterventionDrugCodeSequence",false }, + {0x0018,0x002a,VR::SQ,VM::VM1,"Additional Drug Sequence","AdditionalDrugSequence",false }, + {0x0018,0x0030,VR::LO,VM::VM1_n,"Radionuclide","Radionuclide",true }, + {0x0018,0x0031,VR::LO,VM::VM1,"Radiopharmaceutical","Radiopharmaceutical",false }, + {0x0018,0x0032,VR::DS,VM::VM1,"Energy Window Centerline","EnergyWindowCenterline",true }, + {0x0018,0x0033,VR::DS,VM::VM1_n,"Energy Window Total Width","EnergyWindowTotalWidth",true }, + {0x0018,0x0034,VR::LO,VM::VM1,"Intervention Drug Name","InterventionDrugName",false }, + {0x0018,0x0035,VR::TM,VM::VM1,"Intervention Drug Start Time","InterventionDrugStartTime",false }, + {0x0018,0x0036,VR::SQ,VM::VM1,"Intervention Sequence","InterventionSequence",false }, + {0x0018,0x0037,VR::CS,VM::VM1,"Therapy Type","TherapyType",true }, + {0x0018,0x0038,VR::CS,VM::VM1,"Intervention Status","InterventionStatus",false }, + {0x0018,0x0039,VR::CS,VM::VM1,"Therapy Description","TherapyDescription",true }, + {0x0018,0x003a,VR::ST,VM::VM1,"Intervention Description","InterventionDescription",false }, + {0x0018,0x0040,VR::IS,VM::VM1,"Cine Rate","CineRate",false }, + {0x0018,0x0042,VR::CS,VM::VM1,"Initial Cine Run State","InitialCineRunState",false }, + {0x0018,0x0050,VR::DS,VM::VM1,"Slice Thickness","SliceThickness",false }, + {0x0018,0x0060,VR::DS,VM::VM1,"KVP","KVP",false }, + {0x0018,0x0070,VR::IS,VM::VM1,"Counts Accumulated","CountsAccumulated",false }, + {0x0018,0x0071,VR::CS,VM::VM1,"Acquisition Termination Condition","AcquisitionTerminationCondition",false }, + {0x0018,0x0072,VR::DS,VM::VM1,"Effective Duration","EffectiveDuration",false }, + {0x0018,0x0073,VR::CS,VM::VM1,"Acquisition Start Condition","AcquisitionStartCondition",false }, + {0x0018,0x0074,VR::IS,VM::VM1,"Acquisition Start Condition Data","AcquisitionStartConditionData",false }, + {0x0018,0x0075,VR::IS,VM::VM1,"Acquisition Termination Condition Data","AcquisitionTerminationConditionData",false }, + {0x0018,0x0080,VR::DS,VM::VM1,"Repetition Time","RepetitionTime",false }, + {0x0018,0x0081,VR::DS,VM::VM1,"Echo Time","EchoTime",false }, + {0x0018,0x0082,VR::DS,VM::VM1,"Inversion Time","InversionTime",false }, + {0x0018,0x0083,VR::DS,VM::VM1,"Number of Averages","NumberOfAverages",false }, + {0x0018,0x0084,VR::DS,VM::VM1,"Imaging Frequency","ImagingFrequency",false }, + {0x0018,0x0085,VR::SH,VM::VM1,"Imaged Nucleus","ImagedNucleus",false }, + {0x0018,0x0086,VR::IS,VM::VM1_n,"Echo Number(s)","EchoNumbers",false }, + {0x0018,0x0087,VR::DS,VM::VM1,"Magnetic Field Strength","MagneticFieldStrength",false }, + {0x0018,0x0088,VR::DS,VM::VM1,"Spacing Between Slices","SpacingBetweenSlices",false }, + {0x0018,0x0089,VR::IS,VM::VM1,"Number of Phase Encoding Steps","NumberOfPhaseEncodingSteps",false }, + {0x0018,0x0090,VR::DS,VM::VM1,"Data Collection Diameter","DataCollectionDiameter",false }, + {0x0018,0x0091,VR::IS,VM::VM1,"Echo Train Length","EchoTrainLength",false }, + {0x0018,0x0093,VR::DS,VM::VM1,"Percent Sampling","PercentSampling",false }, + {0x0018,0x0094,VR::DS,VM::VM1,"Percent Phase Field of View","PercentPhaseFieldOfView",false }, + {0x0018,0x0095,VR::DS,VM::VM1,"Pixel Bandwidth","PixelBandwidth",false }, + {0x0018,0x1000,VR::LO,VM::VM1,"Device Serial Number","DeviceSerialNumber",false }, + {0x0018,0x1002,VR::UI,VM::VM1,"Device UID","DeviceUID",false }, + {0x0018,0x1003,VR::LO,VM::VM1,"Device ID","DeviceID",false }, + {0x0018,0x1004,VR::LO,VM::VM1,"Plate ID","PlateID",false }, + {0x0018,0x1005,VR::LO,VM::VM1,"Generator ID","GeneratorID",false }, + {0x0018,0x1006,VR::LO,VM::VM1,"Grid ID","GridID",false }, + {0x0018,0x1007,VR::LO,VM::VM1,"Cassette ID","CassetteID",false }, + {0x0018,0x1008,VR::LO,VM::VM1,"Gantry ID","GantryID",false }, + {0x0018,0x1010,VR::LO,VM::VM1,"Secondary Capture Device ID","SecondaryCaptureDeviceID",false }, + {0x0018,0x1011,VR::LO,VM::VM1,"Hardcopy Creation Device ID","HardcopyCreationDeviceID",true }, + {0x0018,0x1012,VR::DA,VM::VM1,"Date of Secondary Capture","DateOfSecondaryCapture",false }, + {0x0018,0x1014,VR::TM,VM::VM1,"Time of Secondary Capture","TimeOfSecondaryCapture",false }, + {0x0018,0x1016,VR::LO,VM::VM1,"Secondary Capture Device Manufacturer","SecondaryCaptureDeviceManufacturer",false }, + {0x0018,0x1017,VR::LO,VM::VM1,"Hardcopy Device Manufacturer","HardcopyDeviceManufacturer",true }, + {0x0018,0x1018,VR::LO,VM::VM1,"Secondary Capture Device Manufacturer's Model Name","SecondaryCaptureDeviceManufacturerModelName",false }, + {0x0018,0x1019,VR::LO,VM::VM1_n,"Secondary Capture Device Software Versions","SecondaryCaptureDeviceSoftwareVersions",false }, + {0x0018,0x101a,VR::LO,VM::VM1_n,"Hardcopy Device Software Version","HardcopyDeviceSoftwareVersion",true }, + {0x0018,0x101b,VR::LO,VM::VM1,"Hardcopy Device Manufacturer's Model Name","HardcopyDeviceManufacturerModelName",true }, + {0x0018,0x1020,VR::LO,VM::VM1_n,"Software Version(s)","SoftwareVersions",false }, + {0x0018,0x1022,VR::SH,VM::VM1,"Video Image Format Acquired","VideoImageFormatAcquired",false }, + {0x0018,0x1023,VR::LO,VM::VM1,"Digital Image Format Acquired","DigitalImageFormatAcquired",false }, + {0x0018,0x1030,VR::LO,VM::VM1,"Protocol Name","ProtocolName",false }, + {0x0018,0x1040,VR::LO,VM::VM1,"Contrast/Bolus Route","ContrastBolusRoute",false }, + {0x0018,0x1041,VR::DS,VM::VM1,"Contrast/Bolus Volume","ContrastBolusVolume",false }, + {0x0018,0x1042,VR::TM,VM::VM1,"Contrast/Bolus Start Time","ContrastBolusStartTime",false }, + {0x0018,0x1043,VR::TM,VM::VM1,"Contrast/Bolus Stop Time","ContrastBolusStopTime",false }, + {0x0018,0x1044,VR::DS,VM::VM1,"Contrast/Bolus Total Dose","ContrastBolusTotalDose",false }, + {0x0018,0x1045,VR::IS,VM::VM1,"Syringe Counts","SyringeCounts",false }, + {0x0018,0x1046,VR::DS,VM::VM1_n,"Contrast Flow Rate","ContrastFlowRate",false }, + {0x0018,0x1047,VR::DS,VM::VM1_n,"Contrast Flow Duration","ContrastFlowDuration",false }, + {0x0018,0x1048,VR::CS,VM::VM1,"Contrast/Bolus Ingredient","ContrastBolusIngredient",false }, + {0x0018,0x1049,VR::DS,VM::VM1,"Contrast/Bolus Ingredient Concentration","ContrastBolusIngredientConcentration",false }, + {0x0018,0x1050,VR::DS,VM::VM1,"Spatial Resolution","SpatialResolution",false }, + {0x0018,0x1060,VR::DS,VM::VM1,"Trigger Time","TriggerTime",false }, + {0x0018,0x1061,VR::LO,VM::VM1,"Trigger Source or Type","TriggerSourceOrType",false }, + {0x0018,0x1062,VR::IS,VM::VM1,"Nominal Interval","NominalInterval",false }, + {0x0018,0x1063,VR::DS,VM::VM1,"Frame Time","FrameTime",false }, + {0x0018,0x1064,VR::LO,VM::VM1,"Cardiac Framing Type","CardiacFramingType",false }, + {0x0018,0x1065,VR::DS,VM::VM1_n,"Frame Time Vector","FrameTimeVector",false }, + {0x0018,0x1066,VR::DS,VM::VM1,"Frame Delay","FrameDelay",false }, + {0x0018,0x1067,VR::DS,VM::VM1,"Image Trigger Delay","ImageTriggerDelay",false }, + {0x0018,0x1068,VR::DS,VM::VM1,"Multiplex Group Time Offset","MultiplexGroupTimeOffset",false }, + {0x0018,0x1069,VR::DS,VM::VM1,"Trigger Time Offset","TriggerTimeOffset",false }, + {0x0018,0x106a,VR::CS,VM::VM1,"Synchronization Trigger","SynchronizationTrigger",false }, + {0x0018,0x106c,VR::US,VM::VM2,"Synchronization Channel","SynchronizationChannel",false }, + {0x0018,0x106e,VR::UL,VM::VM1,"Trigger Sample Position","TriggerSamplePosition",false }, + {0x0018,0x1070,VR::LO,VM::VM1,"Radiopharmaceutical Route","RadiopharmaceuticalRoute",false }, + {0x0018,0x1071,VR::DS,VM::VM1,"Radiopharmaceutical Volume","RadiopharmaceuticalVolume",false }, + {0x0018,0x1072,VR::TM,VM::VM1,"Radiopharmaceutical Start Time","RadiopharmaceuticalStartTime",false }, + {0x0018,0x1073,VR::TM,VM::VM1,"Radiopharmaceutical Stop Time","RadiopharmaceuticalStopTime",false }, + {0x0018,0x1074,VR::DS,VM::VM1,"Radionuclide Total Dose","RadionuclideTotalDose",false }, + {0x0018,0x1075,VR::DS,VM::VM1,"Radionuclide Half Life","RadionuclideHalfLife",false }, + {0x0018,0x1076,VR::DS,VM::VM1,"Radionuclide Positron Fraction","RadionuclidePositronFraction",false }, + {0x0018,0x1077,VR::DS,VM::VM1,"Radiopharmaceutical Specific Activity","RadiopharmaceuticalSpecificActivity",false }, + {0x0018,0x1078,VR::DT,VM::VM1,"Radiopharmaceutical Start DateTime","RadiopharmaceuticalStartDateTime",false }, + {0x0018,0x1079,VR::DT,VM::VM1,"Radiopharmaceutical Stop DateTime","RadiopharmaceuticalStopDateTime",false }, + {0x0018,0x1080,VR::CS,VM::VM1,"Beat Rejection Flag","BeatRejectionFlag",false }, + {0x0018,0x1081,VR::IS,VM::VM1,"Low R-R Value","LowRRValue",false }, + {0x0018,0x1082,VR::IS,VM::VM1,"High R-R Value","HighRRValue",false }, + {0x0018,0x1083,VR::IS,VM::VM1,"Intervals Acquired","IntervalsAcquired",false }, + {0x0018,0x1084,VR::IS,VM::VM1,"Intervals Rejected","IntervalsRejected",false }, + {0x0018,0x1085,VR::LO,VM::VM1,"PVC Rejection","PVCRejection",false }, + {0x0018,0x1086,VR::IS,VM::VM1,"Skip Beats","SkipBeats",false }, + {0x0018,0x1088,VR::IS,VM::VM1,"Heart Rate","HeartRate",false }, + {0x0018,0x1090,VR::IS,VM::VM1,"Cardiac Number of Images","CardiacNumberOfImages",false }, + {0x0018,0x1094,VR::IS,VM::VM1,"Trigger Window","TriggerWindow",false }, + {0x0018,0x1100,VR::DS,VM::VM1,"Reconstruction Diameter","ReconstructionDiameter",false }, + {0x0018,0x1110,VR::DS,VM::VM1,"Distance Source to Detector","DistanceSourceToDetector",false }, + {0x0018,0x1111,VR::DS,VM::VM1,"Distance Source to Patient","DistanceSourceToPatient",false }, + {0x0018,0x1114,VR::DS,VM::VM1,"Estimated Radiographic Magnification Factor","EstimatedRadiographicMagnificationFactor",false }, + {0x0018,0x1120,VR::DS,VM::VM1,"Gantry/Detector Tilt","GantryDetectorTilt",false }, + {0x0018,0x1121,VR::DS,VM::VM1,"Gantry/Detector Slew","GantryDetectorSlew",false }, + {0x0018,0x1130,VR::DS,VM::VM1,"Table Height","TableHeight",false }, + {0x0018,0x1131,VR::DS,VM::VM1,"Table Traverse","TableTraverse",false }, + {0x0018,0x1134,VR::CS,VM::VM1,"Table Motion","TableMotion",false }, + {0x0018,0x1135,VR::DS,VM::VM1_n,"Table Vertical Increment","TableVerticalIncrement",false }, + {0x0018,0x1136,VR::DS,VM::VM1_n,"Table Lateral Increment","TableLateralIncrement",false }, + {0x0018,0x1137,VR::DS,VM::VM1_n,"Table Longitudinal Increment","TableLongitudinalIncrement",false }, + {0x0018,0x1138,VR::DS,VM::VM1,"Table Angle","TableAngle",false }, + {0x0018,0x113a,VR::CS,VM::VM1,"Table Type","TableType",false }, + {0x0018,0x1140,VR::CS,VM::VM1,"Rotation Direction","RotationDirection",false }, + {0x0018,0x1141,VR::DS,VM::VM1,"Angular Position","AngularPosition",true }, + {0x0018,0x1142,VR::DS,VM::VM1_n,"Radial Position","RadialPosition",false }, + {0x0018,0x1143,VR::DS,VM::VM1,"Scan Arc","ScanArc",false }, + {0x0018,0x1144,VR::DS,VM::VM1,"Angular Step","AngularStep",false }, + {0x0018,0x1145,VR::DS,VM::VM1,"Center of Rotation Offset","CenterOfRotationOffset",false }, + {0x0018,0x1146,VR::DS,VM::VM1_n,"Rotation Offset","RotationOffset",true }, + {0x0018,0x1147,VR::CS,VM::VM1,"Field of View Shape","FieldOfViewShape",false }, + {0x0018,0x1149,VR::IS,VM::VM1_2,"Field of View Dimension(s)","FieldOfViewDimensions",false }, + {0x0018,0x1150,VR::IS,VM::VM1,"Exposure Time","ExposureTime",false }, + {0x0018,0x1151,VR::IS,VM::VM1,"X-Ray Tube Current","XRayTubeCurrent",false }, + {0x0018,0x1152,VR::IS,VM::VM1,"Exposure","Exposure",false }, + {0x0018,0x1153,VR::IS,VM::VM1,"Exposure in µAs","ExposureInuAs",false }, + {0x0018,0x1154,VR::DS,VM::VM1,"Average Pulse Width","AveragePulseWidth",false }, + {0x0018,0x1155,VR::CS,VM::VM1,"Radiation Setting","RadiationSetting",false }, + {0x0018,0x1156,VR::CS,VM::VM1,"Rectification Type","RectificationType",false }, + {0x0018,0x115a,VR::CS,VM::VM1,"Radiation Mode","RadiationMode",false }, + {0x0018,0x115e,VR::DS,VM::VM1,"Image and Fluoroscopy Area Dose Product","ImageAndFluoroscopyAreaDoseProduct",false }, + {0x0018,0x1160,VR::SH,VM::VM1,"Filter Type","FilterType",false }, + {0x0018,0x1161,VR::LO,VM::VM1_n,"Type of Filters","TypeOfFilters",false }, + {0x0018,0x1162,VR::DS,VM::VM1,"Intensifier Size","IntensifierSize",false }, + {0x0018,0x1164,VR::DS,VM::VM2,"Imager Pixel Spacing","ImagerPixelSpacing",false }, + {0x0018,0x1166,VR::CS,VM::VM1_n,"Grid","Grid",false }, + {0x0018,0x1170,VR::IS,VM::VM1,"Generator Power","GeneratorPower",false }, + {0x0018,0x1180,VR::SH,VM::VM1,"Collimator/grid Name","CollimatorGridName",false }, + {0x0018,0x1181,VR::CS,VM::VM1,"Collimator Type","CollimatorType",false }, + {0x0018,0x1182,VR::IS,VM::VM1_2,"Focal Distance","FocalDistance",false }, + {0x0018,0x1183,VR::DS,VM::VM1_2,"X Focus Center","XFocusCenter",false }, + {0x0018,0x1184,VR::DS,VM::VM1_2,"Y Focus Center","YFocusCenter",false }, + {0x0018,0x1190,VR::DS,VM::VM1_n,"Focal Spot(s)","FocalSpots",false }, + {0x0018,0x1191,VR::CS,VM::VM1,"Anode Target Material","AnodeTargetMaterial",false }, + {0x0018,0x11a0,VR::DS,VM::VM1,"Body Part Thickness","BodyPartThickness",false }, + {0x0018,0x11a2,VR::DS,VM::VM1,"Compression Force","CompressionForce",false }, + {0x0018,0x11a4,VR::LO,VM::VM1,"Paddle Description","PaddleDescription",false }, + {0x0018,0x1200,VR::DA,VM::VM1_n,"Date of Last Calibration","DateOfLastCalibration",false }, + {0x0018,0x1201,VR::TM,VM::VM1_n,"Time of Last Calibration","TimeOfLastCalibration",false }, + {0x0018,0x1210,VR::SH,VM::VM1_n,"Convolution Kernel","ConvolutionKernel",false }, + {0x0018,0x1240,VR::IS,VM::VM1_n,"Upper/Lower Pixel Values","UpperLowerPixelValues",true }, + {0x0018,0x1242,VR::IS,VM::VM1,"Actual Frame Duration","ActualFrameDuration",false }, + {0x0018,0x1243,VR::IS,VM::VM1,"Count Rate","CountRate",false }, + {0x0018,0x1244,VR::US,VM::VM1,"Preferred Playback Sequencing","PreferredPlaybackSequencing",false }, + {0x0018,0x1250,VR::SH,VM::VM1,"Receive Coil Name","ReceiveCoilName",false }, + {0x0018,0x1251,VR::SH,VM::VM1,"Transmit Coil Name","TransmitCoilName",false }, + {0x0018,0x1260,VR::SH,VM::VM1,"Plate Type","PlateType",false }, + {0x0018,0x1261,VR::LO,VM::VM1,"Phosphor Type","PhosphorType",false }, + {0x0018,0x1300,VR::DS,VM::VM1,"Scan Velocity","ScanVelocity",false }, + {0x0018,0x1301,VR::CS,VM::VM1_n,"Whole Body Technique","WholeBodyTechnique",false }, + {0x0018,0x1302,VR::IS,VM::VM1,"Scan Length","ScanLength",false }, + {0x0018,0x1310,VR::US,VM::VM4,"Acquisition Matrix","AcquisitionMatrix",false }, + {0x0018,0x1312,VR::CS,VM::VM1,"In-plane Phase Encoding Direction","InPlanePhaseEncodingDirection",false }, + {0x0018,0x1314,VR::DS,VM::VM1,"Flip Angle","FlipAngle",false }, + {0x0018,0x1315,VR::CS,VM::VM1,"Variable Flip Angle Flag","VariableFlipAngleFlag",false }, + {0x0018,0x1316,VR::DS,VM::VM1,"SAR","SAR",false }, + {0x0018,0x1318,VR::DS,VM::VM1,"dB/dt","dBdt",false }, + {0x0018,0x1400,VR::LO,VM::VM1,"Acquisition Device Processing Description","AcquisitionDeviceProcessingDescription",false }, + {0x0018,0x1401,VR::LO,VM::VM1,"Acquisition Device Processing Code","AcquisitionDeviceProcessingCode",false }, + {0x0018,0x1402,VR::CS,VM::VM1,"Cassette Orientation","CassetteOrientation",false }, + {0x0018,0x1403,VR::CS,VM::VM1,"Cassette Size","CassetteSize",false }, + {0x0018,0x1404,VR::US,VM::VM1,"Exposures on Plate","ExposuresOnPlate",false }, + {0x0018,0x1405,VR::IS,VM::VM1,"Relative X-Ray Exposure","RelativeXRayExposure",false }, + {0x0018,0x1411,VR::DS,VM::VM1,"Exposure Index","ExposureIndex",false }, + {0x0018,0x1412,VR::DS,VM::VM1,"Target Exposure Index","TargetExposureIndex",false }, + {0x0018,0x1413,VR::DS,VM::VM1,"Deviation Index","DeviationIndex",false }, + {0x0018,0x1450,VR::DS,VM::VM1,"Column Angulation","ColumnAngulation",false }, + {0x0018,0x1460,VR::DS,VM::VM1,"Tomo Layer Height","TomoLayerHeight",false }, + {0x0018,0x1470,VR::DS,VM::VM1,"Tomo Angle","TomoAngle",false }, + {0x0018,0x1480,VR::DS,VM::VM1,"Tomo Time","TomoTime",false }, + {0x0018,0x1490,VR::CS,VM::VM1,"Tomo Type","TomoType",false }, + {0x0018,0x1491,VR::CS,VM::VM1,"Tomo Class","TomoClass",false }, + {0x0018,0x1495,VR::IS,VM::VM1,"Number of Tomosynthesis Source Images","NumberOfTomosynthesisSourceImages",false }, + {0x0018,0x1500,VR::CS,VM::VM1,"Positioner Motion","PositionerMotion",false }, + {0x0018,0x1508,VR::CS,VM::VM1,"Positioner Type","PositionerType",false }, + {0x0018,0x1510,VR::DS,VM::VM1,"Positioner Primary Angle","PositionerPrimaryAngle",false }, + {0x0018,0x1511,VR::DS,VM::VM1,"Positioner Secondary Angle","PositionerSecondaryAngle",false }, + {0x0018,0x1520,VR::DS,VM::VM1_n,"Positioner Primary Angle Increment","PositionerPrimaryAngleIncrement",false }, + {0x0018,0x1521,VR::DS,VM::VM1_n,"Positioner Secondary Angle Increment","PositionerSecondaryAngleIncrement",false }, + {0x0018,0x1530,VR::DS,VM::VM1,"Detector Primary Angle","DetectorPrimaryAngle",false }, + {0x0018,0x1531,VR::DS,VM::VM1,"Detector Secondary Angle","DetectorSecondaryAngle",false }, + {0x0018,0x1600,VR::CS,VM::VM1_3,"Shutter Shape","ShutterShape",false }, + {0x0018,0x1602,VR::IS,VM::VM1,"Shutter Left Vertical Edge","ShutterLeftVerticalEdge",false }, + {0x0018,0x1604,VR::IS,VM::VM1,"Shutter Right Vertical Edge","ShutterRightVerticalEdge",false }, + {0x0018,0x1606,VR::IS,VM::VM1,"Shutter Upper Horizontal Edge","ShutterUpperHorizontalEdge",false }, + {0x0018,0x1608,VR::IS,VM::VM1,"Shutter Lower Horizontal Edge","ShutterLowerHorizontalEdge",false }, + {0x0018,0x1610,VR::IS,VM::VM2,"Center of Circular Shutter","CenterOfCircularShutter",false }, + {0x0018,0x1612,VR::IS,VM::VM1,"Radius of Circular Shutter","RadiusOfCircularShutter",false }, + {0x0018,0x1620,VR::IS,VM::VM2_2n,"Vertices of the Polygonal Shutter","VerticesOfThePolygonalShutter",false }, + {0x0018,0x1622,VR::US,VM::VM1,"Shutter Presentation Value","ShutterPresentationValue",false }, + {0x0018,0x1623,VR::US,VM::VM1,"Shutter Overlay Group","ShutterOverlayGroup",false }, + {0x0018,0x1624,VR::US,VM::VM3,"Shutter Presentation Color CIELab Value","ShutterPresentationColorCIELabValue",false }, + {0x0018,0x1700,VR::CS,VM::VM1_3,"Collimator Shape","CollimatorShape",false }, + {0x0018,0x1702,VR::IS,VM::VM1,"Collimator Left Vertical Edge","CollimatorLeftVerticalEdge",false }, + {0x0018,0x1704,VR::IS,VM::VM1,"Collimator Right Vertical Edge","CollimatorRightVerticalEdge",false }, + {0x0018,0x1706,VR::IS,VM::VM1,"Collimator Upper Horizontal Edge","CollimatorUpperHorizontalEdge",false }, + {0x0018,0x1708,VR::IS,VM::VM1,"Collimator Lower Horizontal Edge","CollimatorLowerHorizontalEdge",false }, + {0x0018,0x1710,VR::IS,VM::VM2,"Center of Circular Collimator","CenterOfCircularCollimator",false }, + {0x0018,0x1712,VR::IS,VM::VM1,"Radius of Circular Collimator","RadiusOfCircularCollimator",false }, + {0x0018,0x1720,VR::IS,VM::VM2_2n,"Vertices of the Polygonal Collimator","VerticesOfThePolygonalCollimator",false }, + {0x0018,0x1800,VR::CS,VM::VM1,"Acquisition Time Synchronized","AcquisitionTimeSynchronized",false }, + {0x0018,0x1801,VR::SH,VM::VM1,"Time Source","TimeSource",false }, + {0x0018,0x1802,VR::CS,VM::VM1,"Time Distribution Protocol","TimeDistributionProtocol",false }, + {0x0018,0x1803,VR::LO,VM::VM1,"NTP Source Address","NTPSourceAddress",false }, + {0x0018,0x2001,VR::IS,VM::VM1_n,"Page Number Vector","PageNumberVector",false }, + {0x0018,0x2002,VR::SH,VM::VM1_n,"Frame Label Vector","FrameLabelVector",false }, + {0x0018,0x2003,VR::DS,VM::VM1_n,"Frame Primary Angle Vector","FramePrimaryAngleVector",false }, + {0x0018,0x2004,VR::DS,VM::VM1_n,"Frame Secondary Angle Vector","FrameSecondaryAngleVector",false }, + {0x0018,0x2005,VR::DS,VM::VM1_n,"Slice Location Vector","SliceLocationVector",false }, + {0x0018,0x2006,VR::SH,VM::VM1_n,"Display Window Label Vector","DisplayWindowLabelVector",false }, + {0x0018,0x2010,VR::DS,VM::VM2,"Nominal Scanned Pixel Spacing","NominalScannedPixelSpacing",false }, + {0x0018,0x2020,VR::CS,VM::VM1,"Digitizing Device Transport Direction","DigitizingDeviceTransportDirection",false }, + {0x0018,0x2030,VR::DS,VM::VM1,"Rotation of Scanned Film","RotationOfScannedFilm",false }, + {0x0018,0x3100,VR::CS,VM::VM1,"IVUS Acquisition","IVUSAcquisition",false }, + {0x0018,0x3101,VR::DS,VM::VM1,"IVUS Pullback Rate","IVUSPullbackRate",false }, + {0x0018,0x3102,VR::DS,VM::VM1,"IVUS Gated Rate","IVUSGatedRate",false }, + {0x0018,0x3103,VR::IS,VM::VM1,"IVUS Pullback Start Frame Number","IVUSPullbackStartFrameNumber",false }, + {0x0018,0x3104,VR::IS,VM::VM1,"IVUS Pullback Stop Frame Number","IVUSPullbackStopFrameNumber",false }, + {0x0018,0x3105,VR::IS,VM::VM1_n,"Lesion Number","LesionNumber",false }, + {0x0018,0x4000,VR::LT,VM::VM1,"Acquisition Comments","AcquisitionComments",true }, + {0x0018,0x5000,VR::SH,VM::VM1_n,"Output Power","OutputPower",false }, + {0x0018,0x5010,VR::LO,VM::VM1_n,"Transducer Data","TransducerData",false }, + {0x0018,0x5012,VR::DS,VM::VM1,"Focus Depth","FocusDepth",false }, + {0x0018,0x5020,VR::LO,VM::VM1,"Processing Function","ProcessingFunction",false }, + {0x0018,0x5021,VR::LO,VM::VM1,"Postprocessing Function","PostprocessingFunction",true }, + {0x0018,0x5022,VR::DS,VM::VM1,"Mechanical Index","MechanicalIndex",false }, + {0x0018,0x5024,VR::DS,VM::VM1,"Bone Thermal Index","BoneThermalIndex",false }, + {0x0018,0x5026,VR::DS,VM::VM1,"Cranial Thermal Index","CranialThermalIndex",false }, + {0x0018,0x5027,VR::DS,VM::VM1,"Soft Tissue Thermal Index","SoftTissueThermalIndex",false }, + {0x0018,0x5028,VR::DS,VM::VM1,"Soft Tissue-focus Thermal Index","SoftTissueFocusThermalIndex",false }, + {0x0018,0x5029,VR::DS,VM::VM1,"Soft Tissue-surface Thermal Index","SoftTissueSurfaceThermalIndex",false }, + {0x0018,0x5030,VR::DS,VM::VM1,"Dynamic Range","DynamicRange",true }, + {0x0018,0x5040,VR::DS,VM::VM1,"Total Gain","TotalGain",true }, + {0x0018,0x5050,VR::IS,VM::VM1,"Depth of Scan Field","DepthOfScanField",false }, + {0x0018,0x5100,VR::CS,VM::VM1,"Patient Position","PatientPosition",false }, + {0x0018,0x5101,VR::CS,VM::VM1,"View Position","ViewPosition",false }, + {0x0018,0x5104,VR::SQ,VM::VM1,"Projection Eponymous Name Code Sequence","ProjectionEponymousNameCodeSequence",false }, + {0x0018,0x5210,VR::DS,VM::VM6,"Image Transformation Matrix","ImageTransformationMatrix",true }, + {0x0018,0x5212,VR::DS,VM::VM3,"Image Translation Vector","ImageTranslationVector",true }, + {0x0018,0x6000,VR::DS,VM::VM1,"Sensitivity","Sensitivity",false }, + {0x0018,0x6011,VR::SQ,VM::VM1,"Sequence of Ultrasound Regions","SequenceOfUltrasoundRegions",false }, + {0x0018,0x6012,VR::US,VM::VM1,"Region Spatial Format","RegionSpatialFormat",false }, + {0x0018,0x6014,VR::US,VM::VM1,"Region Data Type","RegionDataType",false }, + {0x0018,0x6016,VR::UL,VM::VM1,"Region Flags","RegionFlags",false }, + {0x0018,0x6018,VR::UL,VM::VM1,"Region Location Min X0","RegionLocationMinX0",false }, + {0x0018,0x601a,VR::UL,VM::VM1,"Region Location Min Y0","RegionLocationMinY0",false }, + {0x0018,0x601c,VR::UL,VM::VM1,"Region Location Max X1","RegionLocationMaxX1",false }, + {0x0018,0x601e,VR::UL,VM::VM1,"Region Location Max Y1","RegionLocationMaxY1",false }, + {0x0018,0x6020,VR::SL,VM::VM1,"Reference Pixel X0","ReferencePixelX0",false }, + {0x0018,0x6022,VR::SL,VM::VM1,"Reference Pixel Y0","ReferencePixelY0",false }, + {0x0018,0x6024,VR::US,VM::VM1,"Physical Units X Direction","PhysicalUnitsXDirection",false }, + {0x0018,0x6026,VR::US,VM::VM1,"Physical Units Y Direction","PhysicalUnitsYDirection",false }, + {0x0018,0x6028,VR::FD,VM::VM1,"Reference Pixel Physical Value X","ReferencePixelPhysicalValueX",false }, + {0x0018,0x602a,VR::FD,VM::VM1,"Reference Pixel Physical Value Y","ReferencePixelPhysicalValueY",false }, + {0x0018,0x602c,VR::FD,VM::VM1,"Physical Delta X","PhysicalDeltaX",false }, + {0x0018,0x602e,VR::FD,VM::VM1,"Physical Delta Y","PhysicalDeltaY",false }, + {0x0018,0x6030,VR::UL,VM::VM1,"Transducer Frequency","TransducerFrequency",false }, + {0x0018,0x6031,VR::CS,VM::VM1,"Transducer Type","TransducerType",false }, + {0x0018,0x6032,VR::UL,VM::VM1,"Pulse Repetition Frequency","PulseRepetitionFrequency",false }, + {0x0018,0x6034,VR::FD,VM::VM1,"Doppler Correction Angle","DopplerCorrectionAngle",false }, + {0x0018,0x6036,VR::FD,VM::VM1,"Steering Angle","SteeringAngle",false }, + {0x0018,0x6038,VR::UL,VM::VM1,"Doppler Sample Volume X Position (Retired)","DopplerSampleVolumeXPositionRetired",true }, + {0x0018,0x6039,VR::SL,VM::VM1,"Doppler Sample Volume X Position","DopplerSampleVolumeXPosition",false }, + {0x0018,0x603a,VR::UL,VM::VM1,"Doppler Sample Volume Y Position (Retired)","DopplerSampleVolumeYPositionRetired",true }, + {0x0018,0x603b,VR::SL,VM::VM1,"Doppler Sample Volume Y Position","DopplerSampleVolumeYPosition",false }, + {0x0018,0x603c,VR::UL,VM::VM1,"TM-Line Position X0 (Retired)","TMLinePositionX0Retired",true }, + {0x0018,0x603d,VR::SL,VM::VM1,"TM-Line Position X0","TMLinePositionX0",false }, + {0x0018,0x603e,VR::UL,VM::VM1,"TM-Line Position Y0 (Retired)","TMLinePositionY0Retired",true }, + {0x0018,0x603f,VR::SL,VM::VM1,"TM-Line Position Y0","TMLinePositionY0",false }, + {0x0018,0x6040,VR::UL,VM::VM1,"TM-Line Position X1 (Retired)","TMLinePositionX1Retired",true }, + {0x0018,0x6041,VR::SL,VM::VM1,"TM-Line Position X1","TMLinePositionX1",false }, + {0x0018,0x6042,VR::UL,VM::VM1,"TM-Line Position Y1 (Retired)","TMLinePositionY1Retired",true }, + {0x0018,0x6043,VR::SL,VM::VM1,"TM-Line Position Y1","TMLinePositionY1",false }, + {0x0018,0x6044,VR::US,VM::VM1,"Pixel Component Organization","PixelComponentOrganization",false }, + {0x0018,0x6046,VR::UL,VM::VM1,"Pixel Component Mask","PixelComponentMask",false }, + {0x0018,0x6048,VR::UL,VM::VM1,"Pixel Component Range Start","PixelComponentRangeStart",false }, + {0x0018,0x604a,VR::UL,VM::VM1,"Pixel Component Range Stop","PixelComponentRangeStop",false }, + {0x0018,0x604c,VR::US,VM::VM1,"Pixel Component Physical Units","PixelComponentPhysicalUnits",false }, + {0x0018,0x604e,VR::US,VM::VM1,"Pixel Component Data Type","PixelComponentDataType",false }, + {0x0018,0x6050,VR::UL,VM::VM1,"Number of Table Break Points","NumberOfTableBreakPoints",false }, + {0x0018,0x6052,VR::UL,VM::VM1_n,"Table of X Break Points","TableOfXBreakPoints",false }, + {0x0018,0x6054,VR::FD,VM::VM1_n,"Table of Y Break Points","TableOfYBreakPoints",false }, + {0x0018,0x6056,VR::UL,VM::VM1,"Number of Table Entries","NumberOfTableEntries",false }, + {0x0018,0x6058,VR::UL,VM::VM1_n,"Table of Pixel Values","TableOfPixelValues",false }, + {0x0018,0x605a,VR::FL,VM::VM1_n,"Table of Parameter Values","TableOfParameterValues",false }, + {0x0018,0x6060,VR::FL,VM::VM1_n,"R Wave Time Vector","RWaveTimeVector",false }, + {0x0018,0x7000,VR::CS,VM::VM1,"Detector Conditions Nominal Flag","DetectorConditionsNominalFlag",false }, + {0x0018,0x7001,VR::DS,VM::VM1,"Detector Temperature","DetectorTemperature",false }, + {0x0018,0x7004,VR::CS,VM::VM1,"Detector Type","DetectorType",false }, + {0x0018,0x7005,VR::CS,VM::VM1,"Detector Configuration","DetectorConfiguration",false }, + {0x0018,0x7006,VR::LT,VM::VM1,"Detector Description","DetectorDescription",false }, + {0x0018,0x7008,VR::LT,VM::VM1,"Detector Mode","DetectorMode",false }, + {0x0018,0x700a,VR::SH,VM::VM1,"Detector ID","DetectorID",false }, + {0x0018,0x700c,VR::DA,VM::VM1,"Date of Last Detector Calibration","DateOfLastDetectorCalibration",false }, + {0x0018,0x700e,VR::TM,VM::VM1,"Time of Last Detector Calibration","TimeOfLastDetectorCalibration",false }, + {0x0018,0x7010,VR::IS,VM::VM1,"Exposures on Detector Since Last Calibration","ExposuresOnDetectorSinceLastCalibration",false }, + {0x0018,0x7011,VR::IS,VM::VM1,"Exposures on Detector Since Manufactured","ExposuresOnDetectorSinceManufactured",false }, + {0x0018,0x7012,VR::DS,VM::VM1,"Detector Time Since Last Exposure","DetectorTimeSinceLastExposure",false }, + {0x0018,0x7014,VR::DS,VM::VM1,"Detector Active Time","DetectorActiveTime",false }, + {0x0018,0x7016,VR::DS,VM::VM1,"Detector Activation Offset From Exposure","DetectorActivationOffsetFromExposure",false }, + {0x0018,0x701a,VR::DS,VM::VM2,"Detector Binning","DetectorBinning",false }, + {0x0018,0x7020,VR::DS,VM::VM2,"Detector Element Physical Size","DetectorElementPhysicalSize",false }, + {0x0018,0x7022,VR::DS,VM::VM2,"Detector Element Spacing","DetectorElementSpacing",false }, + {0x0018,0x7024,VR::CS,VM::VM1,"Detector Active Shape","DetectorActiveShape",false }, + {0x0018,0x7026,VR::DS,VM::VM1_2,"Detector Active Dimension(s)","DetectorActiveDimensions",false }, + {0x0018,0x7028,VR::DS,VM::VM2,"Detector Active Origin","DetectorActiveOrigin",false }, + {0x0018,0x702a,VR::LO,VM::VM1,"Detector Manufacturer Name","DetectorManufacturerName",false }, + {0x0018,0x702b,VR::LO,VM::VM1,"Detector Manufacturer's Model Name","DetectorManufacturerModelName",false }, + {0x0018,0x7030,VR::DS,VM::VM2,"Field of View Origin","FieldOfViewOrigin",false }, + {0x0018,0x7032,VR::DS,VM::VM1,"Field of View Rotation","FieldOfViewRotation",false }, + {0x0018,0x7034,VR::CS,VM::VM1,"Field of View Horizontal Flip","FieldOfViewHorizontalFlip",false }, + {0x0018,0x7036,VR::FL,VM::VM2,"Pixel Data Area Origin Relative To FOV","PixelDataAreaOriginRelativeToFOV",false }, + {0x0018,0x7038,VR::FL,VM::VM1,"Pixel Data Area Rotation Angle Relative To FOV","PixelDataAreaRotationAngleRelativeToFOV",false }, + {0x0018,0x7040,VR::LT,VM::VM1,"Grid Absorbing Material","GridAbsorbingMaterial",false }, + {0x0018,0x7041,VR::LT,VM::VM1,"Grid Spacing Material","GridSpacingMaterial",false }, + {0x0018,0x7042,VR::DS,VM::VM1,"Grid Thickness","GridThickness",false }, + {0x0018,0x7044,VR::DS,VM::VM1,"Grid Pitch","GridPitch",false }, + {0x0018,0x7046,VR::IS,VM::VM2,"Grid Aspect Ratio","GridAspectRatio",false }, + {0x0018,0x7048,VR::DS,VM::VM1,"Grid Period","GridPeriod",false }, + {0x0018,0x704c,VR::DS,VM::VM1,"Grid Focal Distance","GridFocalDistance",false }, + {0x0018,0x7050,VR::CS,VM::VM1_n,"Filter Material","FilterMaterial",false }, + {0x0018,0x7052,VR::DS,VM::VM1_n,"Filter Thickness Minimum","FilterThicknessMinimum",false }, + {0x0018,0x7054,VR::DS,VM::VM1_n,"Filter Thickness Maximum","FilterThicknessMaximum",false }, + {0x0018,0x7056,VR::FL,VM::VM1_n,"Filter Beam Path Length Minimum","FilterBeamPathLengthMinimum",false }, + {0x0018,0x7058,VR::FL,VM::VM1_n,"Filter Beam Path Length Maximum","FilterBeamPathLengthMaximum",false }, + {0x0018,0x7060,VR::CS,VM::VM1,"Exposure Control Mode","ExposureControlMode",false }, + {0x0018,0x7062,VR::LT,VM::VM1,"Exposure Control Mode Description","ExposureControlModeDescription",false }, + {0x0018,0x7064,VR::CS,VM::VM1,"Exposure Status","ExposureStatus",false }, + {0x0018,0x7065,VR::DS,VM::VM1,"Phototimer Setting","PhototimerSetting",false }, + {0x0018,0x8150,VR::DS,VM::VM1,"Exposure Time in µS","ExposureTimeInuS",false }, + {0x0018,0x8151,VR::DS,VM::VM1,"X-Ray Tube Current in µA","XRayTubeCurrentInuA",false }, + {0x0018,0x9004,VR::CS,VM::VM1,"Content Qualification","ContentQualification",false }, + {0x0018,0x9005,VR::SH,VM::VM1,"Pulse Sequence Name","PulseSequenceName",false }, + {0x0018,0x9006,VR::SQ,VM::VM1,"MR Imaging Modifier Sequence","MRImagingModifierSequence",false }, + {0x0018,0x9008,VR::CS,VM::VM1,"Echo Pulse Sequence","EchoPulseSequence",false }, + {0x0018,0x9009,VR::CS,VM::VM1,"Inversion Recovery","InversionRecovery",false }, + {0x0018,0x9010,VR::CS,VM::VM1,"Flow Compensation","FlowCompensation",false }, + {0x0018,0x9011,VR::CS,VM::VM1,"Multiple Spin Echo","MultipleSpinEcho",false }, + {0x0018,0x9012,VR::CS,VM::VM1,"Multi-planar Excitation","MultiPlanarExcitation",false }, + {0x0018,0x9014,VR::CS,VM::VM1,"Phase Contrast","PhaseContrast",false }, + {0x0018,0x9015,VR::CS,VM::VM1,"Time of Flight Contrast","TimeOfFlightContrast",false }, + {0x0018,0x9016,VR::CS,VM::VM1,"Spoiling","Spoiling",false }, + {0x0018,0x9017,VR::CS,VM::VM1,"Steady State Pulse Sequence","SteadyStatePulseSequence",false }, + {0x0018,0x9018,VR::CS,VM::VM1,"Echo Planar Pulse Sequence","EchoPlanarPulseSequence",false }, + {0x0018,0x9019,VR::FD,VM::VM1,"Tag Angle First Axis","TagAngleFirstAxis",false }, + {0x0018,0x9020,VR::CS,VM::VM1,"Magnetization Transfer","MagnetizationTransfer",false }, + {0x0018,0x9021,VR::CS,VM::VM1,"T2 Preparation","T2Preparation",false }, + {0x0018,0x9022,VR::CS,VM::VM1,"Blood Signal Nulling","BloodSignalNulling",false }, + {0x0018,0x9024,VR::CS,VM::VM1,"Saturation Recovery","SaturationRecovery",false }, + {0x0018,0x9025,VR::CS,VM::VM1,"Spectrally Selected Suppression","SpectrallySelectedSuppression",false }, + {0x0018,0x9026,VR::CS,VM::VM1,"Spectrally Selected Excitation","SpectrallySelectedExcitation",false }, + {0x0018,0x9027,VR::CS,VM::VM1,"Spatial Pre-saturation","SpatialPresaturation",false }, + {0x0018,0x9028,VR::CS,VM::VM1,"Tagging","Tagging",false }, + {0x0018,0x9029,VR::CS,VM::VM1,"Oversampling Phase","OversamplingPhase",false }, + {0x0018,0x9030,VR::FD,VM::VM1,"Tag Spacing First Dimension","TagSpacingFirstDimension",false }, + {0x0018,0x9032,VR::CS,VM::VM1,"Geometry of k-Space Traversal","GeometryOfKSpaceTraversal",false }, + {0x0018,0x9033,VR::CS,VM::VM1,"Segmented k-Space Traversal","SegmentedKSpaceTraversal",false }, + {0x0018,0x9034,VR::CS,VM::VM1,"Rectilinear Phase Encode Reordering","RectilinearPhaseEncodeReordering",false }, + {0x0018,0x9035,VR::FD,VM::VM1,"Tag Thickness","TagThickness",false }, + {0x0018,0x9036,VR::CS,VM::VM1,"Partial Fourier Direction","PartialFourierDirection",false }, + {0x0018,0x9037,VR::CS,VM::VM1,"Cardiac Synchronization Technique","CardiacSynchronizationTechnique",false }, + {0x0018,0x9041,VR::LO,VM::VM1,"Receive Coil Manufacturer Name","ReceiveCoilManufacturerName",false }, + {0x0018,0x9042,VR::SQ,VM::VM1,"MR Receive Coil Sequence","MRReceiveCoilSequence",false }, + {0x0018,0x9043,VR::CS,VM::VM1,"Receive Coil Type","ReceiveCoilType",false }, + {0x0018,0x9044,VR::CS,VM::VM1,"Quadrature Receive Coil","QuadratureReceiveCoil",false }, + {0x0018,0x9045,VR::SQ,VM::VM1,"Multi-Coil Definition Sequence","MultiCoilDefinitionSequence",false }, + {0x0018,0x9046,VR::LO,VM::VM1,"Multi-Coil Configuration","MultiCoilConfiguration",false }, + {0x0018,0x9047,VR::SH,VM::VM1,"Multi-Coil Element Name","MultiCoilElementName",false }, + {0x0018,0x9048,VR::CS,VM::VM1,"Multi-Coil Element Used","MultiCoilElementUsed",false }, + {0x0018,0x9049,VR::SQ,VM::VM1,"MR Transmit Coil Sequence","MRTransmitCoilSequence",false }, + {0x0018,0x9050,VR::LO,VM::VM1,"Transmit Coil Manufacturer Name","TransmitCoilManufacturerName",false }, + {0x0018,0x9051,VR::CS,VM::VM1,"Transmit Coil Type","TransmitCoilType",false }, + {0x0018,0x9052,VR::FD,VM::VM1_2,"Spectral Width","SpectralWidth",false }, + {0x0018,0x9053,VR::FD,VM::VM1_2,"Chemical Shift Reference","ChemicalShiftReference",false }, + {0x0018,0x9054,VR::CS,VM::VM1,"Volume Localization Technique","VolumeLocalizationTechnique",false }, + {0x0018,0x9058,VR::US,VM::VM1,"MR Acquisition Frequency Encoding Steps","MRAcquisitionFrequencyEncodingSteps",false }, + {0x0018,0x9059,VR::CS,VM::VM1,"De-coupling","Decoupling",false }, + {0x0018,0x9060,VR::CS,VM::VM1_2,"De-coupled Nucleus","DecoupledNucleus",false }, + {0x0018,0x9061,VR::FD,VM::VM1_2,"De-coupling Frequency","DecouplingFrequency",false }, + {0x0018,0x9062,VR::CS,VM::VM1,"De-coupling Method","DecouplingMethod",false }, + {0x0018,0x9063,VR::FD,VM::VM1_2,"De-coupling Chemical Shift Reference","DecouplingChemicalShiftReference",false }, + {0x0018,0x9064,VR::CS,VM::VM1,"k-space Filtering","KSpaceFiltering",false }, + {0x0018,0x9065,VR::CS,VM::VM1_2,"Time Domain Filtering","TimeDomainFiltering",false }, + {0x0018,0x9066,VR::US,VM::VM1_2,"Number of Zero Fills","NumberOfZeroFills",false }, + {0x0018,0x9067,VR::CS,VM::VM1,"Baseline Correction","BaselineCorrection",false }, + {0x0018,0x9069,VR::FD,VM::VM1,"Parallel Reduction Factor In-plane","ParallelReductionFactorInPlane",false }, + {0x0018,0x9070,VR::FD,VM::VM1,"Cardiac R-R Interval Specified","CardiacRRIntervalSpecified",false }, + {0x0018,0x9073,VR::FD,VM::VM1,"Acquisition Duration","AcquisitionDuration",false }, + {0x0018,0x9074,VR::DT,VM::VM1,"Frame Acquisition DateTime","FrameAcquisitionDateTime",false }, + {0x0018,0x9075,VR::CS,VM::VM1,"Diffusion Directionality","DiffusionDirectionality",false }, + {0x0018,0x9076,VR::SQ,VM::VM1,"Diffusion Gradient Direction Sequence","DiffusionGradientDirectionSequence",false }, + {0x0018,0x9077,VR::CS,VM::VM1,"Parallel Acquisition","ParallelAcquisition",false }, + {0x0018,0x9078,VR::CS,VM::VM1,"Parallel Acquisition Technique","ParallelAcquisitionTechnique",false }, + {0x0018,0x9079,VR::FD,VM::VM1_n,"Inversion Times","InversionTimes",false }, + {0x0018,0x9080,VR::ST,VM::VM1,"Metabolite Map Description","MetaboliteMapDescription",false }, + {0x0018,0x9081,VR::CS,VM::VM1,"Partial Fourier","PartialFourier",false }, + {0x0018,0x9082,VR::FD,VM::VM1,"Effective Echo Time","EffectiveEchoTime",false }, + {0x0018,0x9083,VR::SQ,VM::VM1,"Metabolite Map Code Sequence","MetaboliteMapCodeSequence",false }, + {0x0018,0x9084,VR::SQ,VM::VM1,"Chemical Shift Sequence","ChemicalShiftSequence",false }, + {0x0018,0x9085,VR::CS,VM::VM1,"Cardiac Signal Source","CardiacSignalSource",false }, + {0x0018,0x9087,VR::FD,VM::VM1,"Diffusion b-value","DiffusionBValue",false }, + {0x0018,0x9089,VR::FD,VM::VM3,"Diffusion Gradient Orientation","DiffusionGradientOrientation",false }, + {0x0018,0x9090,VR::FD,VM::VM3,"Velocity Encoding Direction","VelocityEncodingDirection",false }, + {0x0018,0x9091,VR::FD,VM::VM1,"Velocity Encoding Minimum Value","VelocityEncodingMinimumValue",false }, + {0x0018,0x9092,VR::SQ,VM::VM1,"Velocity Encoding Acquisition Sequence","VelocityEncodingAcquisitionSequence",false }, + {0x0018,0x9093,VR::US,VM::VM1,"Number of k-Space Trajectories","NumberOfKSpaceTrajectories",false }, + {0x0018,0x9094,VR::CS,VM::VM1,"Coverage of k-Space","CoverageOfKSpace",false }, + {0x0018,0x9095,VR::UL,VM::VM1,"Spectroscopy Acquisition Phase Rows","SpectroscopyAcquisitionPhaseRows",false }, + {0x0018,0x9096,VR::FD,VM::VM1,"Parallel Reduction Factor In-plane (Retired)","ParallelReductionFactorInPlaneRetired",true }, + {0x0018,0x9098,VR::FD,VM::VM1_2,"Transmitter Frequency","TransmitterFrequency",false }, + {0x0018,0x9100,VR::CS,VM::VM1_2,"Resonant Nucleus","ResonantNucleus",false }, + {0x0018,0x9101,VR::CS,VM::VM1,"Frequency Correction","FrequencyCorrection",false }, + {0x0018,0x9103,VR::SQ,VM::VM1,"MR Spectroscopy FOV/Geometry Sequence","MRSpectroscopyFOVGeometrySequence",false }, + {0x0018,0x9104,VR::FD,VM::VM1,"Slab Thickness","SlabThickness",false }, + {0x0018,0x9105,VR::FD,VM::VM3,"Slab Orientation","SlabOrientation",false }, + {0x0018,0x9106,VR::FD,VM::VM3,"Mid Slab Position","MidSlabPosition",false }, + {0x0018,0x9107,VR::SQ,VM::VM1,"MR Spatial Saturation Sequence","MRSpatialSaturationSequence",false }, + {0x0018,0x9112,VR::SQ,VM::VM1,"MR Timing and Related Parameters Sequence","MRTimingAndRelatedParametersSequence",false }, + {0x0018,0x9114,VR::SQ,VM::VM1,"MR Echo Sequence","MREchoSequence",false }, + {0x0018,0x9115,VR::SQ,VM::VM1,"MR Modifier Sequence","MRModifierSequence",false }, + {0x0018,0x9117,VR::SQ,VM::VM1,"MR Diffusion Sequence","MRDiffusionSequence",false }, + {0x0018,0x9118,VR::SQ,VM::VM1,"Cardiac Synchronization Sequence","CardiacSynchronizationSequence",false }, + {0x0018,0x9119,VR::SQ,VM::VM1,"MR Averages Sequence","MRAveragesSequence",false }, + {0x0018,0x9125,VR::SQ,VM::VM1,"MR FOV/Geometry Sequence","MRFOVGeometrySequence",false }, + {0x0018,0x9126,VR::SQ,VM::VM1,"Volume Localization Sequence","VolumeLocalizationSequence",false }, + {0x0018,0x9127,VR::UL,VM::VM1,"Spectroscopy Acquisition Data Columns","SpectroscopyAcquisitionDataColumns",false }, + {0x0018,0x9147,VR::CS,VM::VM1,"Diffusion Anisotropy Type","DiffusionAnisotropyType",false }, + {0x0018,0x9151,VR::DT,VM::VM1,"Frame Reference DateTime","FrameReferenceDateTime",false }, + {0x0018,0x9152,VR::SQ,VM::VM1,"MR Metabolite Map Sequence","MRMetaboliteMapSequence",false }, + {0x0018,0x9155,VR::FD,VM::VM1,"Parallel Reduction Factor out-of-plane","ParallelReductionFactorOutOfPlane",false }, + {0x0018,0x9159,VR::UL,VM::VM1,"Spectroscopy Acquisition Out-of-plane Phase Steps","SpectroscopyAcquisitionOutOfPlanePhaseSteps",false }, + {0x0018,0x9166,VR::CS,VM::VM1,"Bulk Motion Status","BulkMotionStatus",true }, + {0x0018,0x9168,VR::FD,VM::VM1,"Parallel Reduction Factor Second In-plane","ParallelReductionFactorSecondInPlane",false }, + {0x0018,0x9169,VR::CS,VM::VM1,"Cardiac Beat Rejection Technique","CardiacBeatRejectionTechnique",false }, + {0x0018,0x9170,VR::CS,VM::VM1,"Respiratory Motion Compensation Technique","RespiratoryMotionCompensationTechnique",false }, + {0x0018,0x9171,VR::CS,VM::VM1,"Respiratory Signal Source","RespiratorySignalSource",false }, + {0x0018,0x9172,VR::CS,VM::VM1,"Bulk Motion Compensation Technique","BulkMotionCompensationTechnique",false }, + {0x0018,0x9173,VR::CS,VM::VM1,"Bulk Motion Signal Source","BulkMotionSignalSource",false }, + {0x0018,0x9174,VR::CS,VM::VM1,"Applicable Safety Standard Agency","ApplicableSafetyStandardAgency",false }, + {0x0018,0x9175,VR::LO,VM::VM1,"Applicable Safety Standard Description","ApplicableSafetyStandardDescription",false }, + {0x0018,0x9176,VR::SQ,VM::VM1,"Operating Mode Sequence","OperatingModeSequence",false }, + {0x0018,0x9177,VR::CS,VM::VM1,"Operating Mode Type","OperatingModeType",false }, + {0x0018,0x9178,VR::CS,VM::VM1,"Operating Mode","OperatingMode",false }, + {0x0018,0x9179,VR::CS,VM::VM1,"Specific Absorption Rate Definition","SpecificAbsorptionRateDefinition",false }, + {0x0018,0x9180,VR::CS,VM::VM1,"Gradient Output Type","GradientOutputType",false }, + {0x0018,0x9181,VR::FD,VM::VM1,"Specific Absorption Rate Value","SpecificAbsorptionRateValue",false }, + {0x0018,0x9182,VR::FD,VM::VM1,"Gradient Output","GradientOutput",false }, + {0x0018,0x9183,VR::CS,VM::VM1,"Flow Compensation Direction","FlowCompensationDirection",false }, + {0x0018,0x9184,VR::FD,VM::VM1,"Tagging Delay","TaggingDelay",false }, + {0x0018,0x9185,VR::ST,VM::VM1,"Respiratory Motion Compensation Technique Description","RespiratoryMotionCompensationTechniqueDescription",false }, + {0x0018,0x9186,VR::SH,VM::VM1,"Respiratory Signal Source ID","RespiratorySignalSourceID",false }, + {0x0018,0x9195,VR::FD,VM::VM1,"Chemical Shift Minimum Integration Limit in Hz","ChemicalShiftMinimumIntegrationLimitInHz",true }, + {0x0018,0x9196,VR::FD,VM::VM1,"Chemical Shift Maximum Integration Limit in Hz","ChemicalShiftMaximumIntegrationLimitInHz",true }, + {0x0018,0x9197,VR::SQ,VM::VM1,"MR Velocity Encoding Sequence","MRVelocityEncodingSequence",false }, + {0x0018,0x9198,VR::CS,VM::VM1,"First Order Phase Correction","FirstOrderPhaseCorrection",false }, + {0x0018,0x9199,VR::CS,VM::VM1,"Water Referenced Phase Correction","WaterReferencedPhaseCorrection",false }, + {0x0018,0x9200,VR::CS,VM::VM1,"MR Spectroscopy Acquisition Type","MRSpectroscopyAcquisitionType",false }, + {0x0018,0x9214,VR::CS,VM::VM1,"Respiratory Cycle Position","RespiratoryCyclePosition",false }, + {0x0018,0x9217,VR::FD,VM::VM1,"Velocity Encoding Maximum Value","VelocityEncodingMaximumValue",false }, + {0x0018,0x9218,VR::FD,VM::VM1,"Tag Spacing Second Dimension","TagSpacingSecondDimension",false }, + {0x0018,0x9219,VR::SS,VM::VM1,"Tag Angle Second Axis","TagAngleSecondAxis",false }, + {0x0018,0x9220,VR::FD,VM::VM1,"Frame Acquisition Duration","FrameAcquisitionDuration",false }, + {0x0018,0x9226,VR::SQ,VM::VM1,"MR Image Frame Type Sequence","MRImageFrameTypeSequence",false }, + {0x0018,0x9227,VR::SQ,VM::VM1,"MR Spectroscopy Frame Type Sequence","MRSpectroscopyFrameTypeSequence",false }, + {0x0018,0x9231,VR::US,VM::VM1,"MR Acquisition Phase Encoding Steps in-plane","MRAcquisitionPhaseEncodingStepsInPlane",false }, + {0x0018,0x9232,VR::US,VM::VM1,"MR Acquisition Phase Encoding Steps out-of-plane","MRAcquisitionPhaseEncodingStepsOutOfPlane",false }, + {0x0018,0x9234,VR::UL,VM::VM1,"Spectroscopy Acquisition Phase Columns","SpectroscopyAcquisitionPhaseColumns",false }, + {0x0018,0x9236,VR::CS,VM::VM1,"Cardiac Cycle Position","CardiacCyclePosition",false }, + {0x0018,0x9239,VR::SQ,VM::VM1,"Specific Absorption Rate Sequence","SpecificAbsorptionRateSequence",false }, + {0x0018,0x9240,VR::US,VM::VM1,"RF Echo Train Length","RFEchoTrainLength",false }, + {0x0018,0x9241,VR::US,VM::VM1,"Gradient Echo Train Length","GradientEchoTrainLength",false }, + {0x0018,0x9250,VR::CS,VM::VM1,"Arterial Spin Labeling Contrast","ArterialSpinLabelingContrast",false }, + {0x0018,0x9251,VR::SQ,VM::VM1,"MR Arterial Spin Labeling Sequence","MRArterialSpinLabelingSequence",false }, + {0x0018,0x9252,VR::LO,VM::VM1,"ASL Technique Description","ASLTechniqueDescription",false }, + {0x0018,0x9253,VR::US,VM::VM1,"ASL Slab Number","ASLSlabNumber",false }, + {0x0018,0x9254,VR::FD,VM::VM1,"ASL Slab Thickness","ASLSlabThickness",false }, + {0x0018,0x9255,VR::FD,VM::VM3,"ASL Slab Orientation","ASLSlabOrientation",false }, + {0x0018,0x9256,VR::FD,VM::VM3,"ASL Mid Slab Position","ASLMidSlabPosition",false }, + {0x0018,0x9257,VR::CS,VM::VM1,"ASL Context","ASLContext",false }, + {0x0018,0x9258,VR::UL,VM::VM1,"ASL Pulse Train Duration","ASLPulseTrainDuration",false }, + {0x0018,0x9259,VR::CS,VM::VM1,"ASL Crusher Flag","ASLCrusherFlag",false }, + {0x0018,0x925a,VR::FD,VM::VM1,"ASL Crusher Flow","ASLCrusherFlow",false }, + {0x0018,0x925b,VR::LO,VM::VM1,"ASL Crusher Description","ASLCrusherDescription",false }, + {0x0018,0x925c,VR::CS,VM::VM1,"ASL Bolus Cut-off Flag","ASLBolusCutoffFlag",false }, + {0x0018,0x925d,VR::SQ,VM::VM1,"ASL Bolus Cut-off Timing Sequence","ASLBolusCutoffTimingSequence",false }, + {0x0018,0x925e,VR::LO,VM::VM1,"ASL Bolus Cut-off Technique","ASLBolusCutoffTechnique",false }, + {0x0018,0x925f,VR::UL,VM::VM1,"ASL Bolus Cut-off Delay Time","ASLBolusCutoffDelayTime",false }, + {0x0018,0x9260,VR::SQ,VM::VM1,"ASL Slab Sequence","ASLSlabSequence",false }, + {0x0018,0x9295,VR::FD,VM::VM1,"Chemical Shift Minimum Integration Limit in ppm","ChemicalShiftMinimumIntegrationLimitInppm",false }, + {0x0018,0x9296,VR::FD,VM::VM1,"Chemical Shift Maximum Integration Limit in ppm","ChemicalShiftMaximumIntegrationLimitInppm",false }, + {0x0018,0x9301,VR::SQ,VM::VM1,"CT Acquisition Type Sequence","CTAcquisitionTypeSequence",false }, + {0x0018,0x9302,VR::CS,VM::VM1,"Acquisition Type","AcquisitionType",false }, + {0x0018,0x9303,VR::FD,VM::VM1,"Tube Angle","TubeAngle",false }, + {0x0018,0x9304,VR::SQ,VM::VM1,"CT Acquisition Details Sequence","CTAcquisitionDetailsSequence",false }, + {0x0018,0x9305,VR::FD,VM::VM1,"Revolution Time","RevolutionTime",false }, + {0x0018,0x9306,VR::FD,VM::VM1,"Single Collimation Width","SingleCollimationWidth",false }, + {0x0018,0x9307,VR::FD,VM::VM1,"Total Collimation Width","TotalCollimationWidth",false }, + {0x0018,0x9308,VR::SQ,VM::VM1,"CT Table Dynamics Sequence","CTTableDynamicsSequence",false }, + {0x0018,0x9309,VR::FD,VM::VM1,"Table Speed","TableSpeed",false }, + {0x0018,0x9310,VR::FD,VM::VM1,"Table Feed per Rotation","TableFeedPerRotation",false }, + {0x0018,0x9311,VR::FD,VM::VM1,"Spiral Pitch Factor","SpiralPitchFactor",false }, + {0x0018,0x9312,VR::SQ,VM::VM1,"CT Geometry Sequence","CTGeometrySequence",false }, + {0x0018,0x9313,VR::FD,VM::VM3,"Data Collection Center (Patient)","DataCollectionCenterPatient",false }, + {0x0018,0x9314,VR::SQ,VM::VM1,"CT Reconstruction Sequence","CTReconstructionSequence",false }, + {0x0018,0x9315,VR::CS,VM::VM1,"Reconstruction Algorithm","ReconstructionAlgorithm",false }, + {0x0018,0x9316,VR::CS,VM::VM1,"Convolution Kernel Group","ConvolutionKernelGroup",false }, + {0x0018,0x9317,VR::FD,VM::VM2,"Reconstruction Field of View","ReconstructionFieldOfView",false }, + {0x0018,0x9318,VR::FD,VM::VM3,"Reconstruction Target Center (Patient)","ReconstructionTargetCenterPatient",false }, + {0x0018,0x9319,VR::FD,VM::VM1,"Reconstruction Angle","ReconstructionAngle",false }, + {0x0018,0x9320,VR::SH,VM::VM1,"Image Filter","ImageFilter",false }, + {0x0018,0x9321,VR::SQ,VM::VM1,"CT Exposure Sequence","CTExposureSequence",false }, + {0x0018,0x9322,VR::FD,VM::VM2,"Reconstruction Pixel Spacing","ReconstructionPixelSpacing",false }, + {0x0018,0x9323,VR::CS,VM::VM1,"Exposure Modulation Type","ExposureModulationType",false }, + {0x0018,0x9324,VR::FD,VM::VM1,"Estimated Dose Saving","EstimatedDoseSaving",false }, + {0x0018,0x9325,VR::SQ,VM::VM1,"CT X-Ray Details Sequence","CTXRayDetailsSequence",false }, + {0x0018,0x9326,VR::SQ,VM::VM1,"CT Position Sequence","CTPositionSequence",false }, + {0x0018,0x9327,VR::FD,VM::VM1,"Table Position","TablePosition",false }, + {0x0018,0x9328,VR::FD,VM::VM1,"Exposure Time in ms","ExposureTimeInms",false }, + {0x0018,0x9329,VR::SQ,VM::VM1,"CT Image Frame Type Sequence","CTImageFrameTypeSequence",false }, + {0x0018,0x9330,VR::FD,VM::VM1,"X-Ray Tube Current in mA","XRayTubeCurrentInmA",false }, + {0x0018,0x9332,VR::FD,VM::VM1,"Exposure in mAs","ExposureInmAs",false }, + {0x0018,0x9333,VR::CS,VM::VM1,"Constant Volume Flag","ConstantVolumeFlag",false }, + {0x0018,0x9334,VR::CS,VM::VM1,"Fluoroscopy Flag","FluoroscopyFlag",false }, + {0x0018,0x9335,VR::FD,VM::VM1,"Distance Source to Data Collection Center","DistanceSourceToDataCollectionCenter",false }, + {0x0018,0x9337,VR::US,VM::VM1,"Contrast/Bolus Agent Number","ContrastBolusAgentNumber",false }, + {0x0018,0x9338,VR::SQ,VM::VM1,"Contrast/Bolus Ingredient Code Sequence","ContrastBolusIngredientCodeSequence",false }, + {0x0018,0x9340,VR::SQ,VM::VM1,"Contrast Administration Profile Sequence","ContrastAdministrationProfileSequence",false }, + {0x0018,0x9341,VR::SQ,VM::VM1,"Contrast/Bolus Usage Sequence","ContrastBolusUsageSequence",false }, + {0x0018,0x9342,VR::CS,VM::VM1,"Contrast/Bolus Agent Administered","ContrastBolusAgentAdministered",false }, + {0x0018,0x9343,VR::CS,VM::VM1,"Contrast/Bolus Agent Detected","ContrastBolusAgentDetected",false }, + {0x0018,0x9344,VR::CS,VM::VM1,"Contrast/Bolus Agent Phase","ContrastBolusAgentPhase",false }, + {0x0018,0x9345,VR::FD,VM::VM1,"CTDIvol","CTDIvol",false }, + {0x0018,0x9346,VR::SQ,VM::VM1,"CTDI Phantom Type Code Sequence","CTDIPhantomTypeCodeSequence",false }, + {0x0018,0x9351,VR::FL,VM::VM1,"Calcium Scoring Mass Factor Patient","CalciumScoringMassFactorPatient",false }, + {0x0018,0x9352,VR::FL,VM::VM3,"Calcium Scoring Mass Factor Device","CalciumScoringMassFactorDevice",false }, + {0x0018,0x9353,VR::FL,VM::VM1,"Energy Weighting Factor","EnergyWeightingFactor",false }, + {0x0018,0x9360,VR::SQ,VM::VM1,"CT Additional X-Ray Source Sequence","CTAdditionalXRaySourceSequence",false }, + {0x0018,0x9401,VR::SQ,VM::VM1,"Projection Pixel Calibration Sequence","ProjectionPixelCalibrationSequence",false }, + {0x0018,0x9402,VR::FL,VM::VM1,"Distance Source to Isocenter","DistanceSourceToIsocenter",false }, + {0x0018,0x9403,VR::FL,VM::VM1,"Distance Object to Table Top","DistanceObjectToTableTop",false }, + {0x0018,0x9404,VR::FL,VM::VM2,"Object Pixel Spacing in Center of Beam","ObjectPixelSpacingInCenterOfBeam",false }, + {0x0018,0x9405,VR::SQ,VM::VM1,"Positioner Position Sequence","PositionerPositionSequence",false }, + {0x0018,0x9406,VR::SQ,VM::VM1,"Table Position Sequence","TablePositionSequence",false }, + {0x0018,0x9407,VR::SQ,VM::VM1,"Collimator Shape Sequence","CollimatorShapeSequence",false }, + {0x0018,0x9410,VR::CS,VM::VM1,"Planes in Acquisition","PlanesInAcquisition",false }, + {0x0018,0x9412,VR::SQ,VM::VM1,"XA/XRF Frame Characteristics Sequence","XAXRFFrameCharacteristicsSequence",false }, + {0x0018,0x9417,VR::SQ,VM::VM1,"Frame Acquisition Sequence","FrameAcquisitionSequence",false }, + {0x0018,0x9420,VR::CS,VM::VM1,"X-Ray Receptor Type","XRayReceptorType",false }, + {0x0018,0x9423,VR::LO,VM::VM1,"Acquisition Protocol Name","AcquisitionProtocolName",false }, + {0x0018,0x9424,VR::LT,VM::VM1,"Acquisition Protocol Description","AcquisitionProtocolDescription",false }, + {0x0018,0x9425,VR::CS,VM::VM1,"Contrast/Bolus Ingredient Opaque","ContrastBolusIngredientOpaque",false }, + {0x0018,0x9426,VR::FL,VM::VM1,"Distance Receptor Plane to Detector Housing","DistanceReceptorPlaneToDetectorHousing",false }, + {0x0018,0x9427,VR::CS,VM::VM1,"Intensifier Active Shape","IntensifierActiveShape",false }, + {0x0018,0x9428,VR::FL,VM::VM1_2,"Intensifier Active Dimension(s)","IntensifierActiveDimensions",false }, + {0x0018,0x9429,VR::FL,VM::VM2,"Physical Detector Size","PhysicalDetectorSize",false }, + {0x0018,0x9430,VR::FL,VM::VM2,"Position of Isocenter Projection","PositionOfIsocenterProjection",false }, + {0x0018,0x9432,VR::SQ,VM::VM1,"Field of View Sequence","FieldOfViewSequence",false }, + {0x0018,0x9433,VR::LO,VM::VM1,"Field of View Description","FieldOfViewDescription",false }, + {0x0018,0x9434,VR::SQ,VM::VM1,"Exposure Control Sensing Regions Sequence","ExposureControlSensingRegionsSequence",false }, + {0x0018,0x9435,VR::CS,VM::VM1,"Exposure Control Sensing Region Shape","ExposureControlSensingRegionShape",false }, + {0x0018,0x9436,VR::SS,VM::VM1,"Exposure Control Sensing Region Left Vertical Edge","ExposureControlSensingRegionLeftVerticalEdge",false }, + {0x0018,0x9437,VR::SS,VM::VM1,"Exposure Control Sensing Region Right Vertical Edge","ExposureControlSensingRegionRightVerticalEdge",false }, + {0x0018,0x9438,VR::SS,VM::VM1,"Exposure Control Sensing Region Upper Horizontal Edge","ExposureControlSensingRegionUpperHorizontalEdge",false }, + {0x0018,0x9439,VR::SS,VM::VM1,"Exposure Control Sensing Region Lower Horizontal Edge","ExposureControlSensingRegionLowerHorizontalEdge",false }, + {0x0018,0x9440,VR::SS,VM::VM2,"Center of Circular Exposure Control Sensing Region","CenterOfCircularExposureControlSensingRegion",false }, + {0x0018,0x9441,VR::US,VM::VM1,"Radius of Circular Exposure Control Sensing Region","RadiusOfCircularExposureControlSensingRegion",false }, + {0x0018,0x9442,VR::SS,VM::VM2_n,"Vertices of the Polygonal Exposure Control Sensing Region","VerticesOfThePolygonalExposureControlSensingRegion",false }, + {0x0018,0x9445,VR::INVALID,VM::VM0,"","",true }, + {0x0018,0x9447,VR::FL,VM::VM1,"Column Angulation (Patient)","ColumnAngulationPatient",false }, + {0x0018,0x9449,VR::FL,VM::VM1,"Beam Angle","BeamAngle",false }, + {0x0018,0x9451,VR::SQ,VM::VM1,"Frame Detector Parameters Sequence","FrameDetectorParametersSequence",false }, + {0x0018,0x9452,VR::FL,VM::VM1,"Calculated Anatomy Thickness","CalculatedAnatomyThickness",false }, + {0x0018,0x9455,VR::SQ,VM::VM1,"Calibration Sequence","CalibrationSequence",false }, + {0x0018,0x9456,VR::SQ,VM::VM1,"Object Thickness Sequence","ObjectThicknessSequence",false }, + {0x0018,0x9457,VR::CS,VM::VM1,"Plane Identification","PlaneIdentification",false }, + {0x0018,0x9461,VR::FL,VM::VM1_2,"Field of View Dimension(s) in Float","FieldOfViewDimensionsInFloat",false }, + {0x0018,0x9462,VR::SQ,VM::VM1,"Isocenter Reference System Sequence","IsocenterReferenceSystemSequence",false }, + {0x0018,0x9463,VR::FL,VM::VM1,"Positioner Isocenter Primary Angle","PositionerIsocenterPrimaryAngle",false }, + {0x0018,0x9464,VR::FL,VM::VM1,"Positioner Isocenter Secondary Angle","PositionerIsocenterSecondaryAngle",false }, + {0x0018,0x9465,VR::FL,VM::VM1,"Positioner Isocenter Detector Rotation Angle","PositionerIsocenterDetectorRotationAngle",false }, + {0x0018,0x9466,VR::FL,VM::VM1,"Table X Position to Isocenter","TableXPositionToIsocenter",false }, + {0x0018,0x9467,VR::FL,VM::VM1,"Table Y Position to Isocenter","TableYPositionToIsocenter",false }, + {0x0018,0x9468,VR::FL,VM::VM1,"Table Z Position to Isocenter","TableZPositionToIsocenter",false }, + {0x0018,0x9469,VR::FL,VM::VM1,"Table Horizontal Rotation Angle","TableHorizontalRotationAngle",false }, + {0x0018,0x9470,VR::FL,VM::VM1,"Table Head Tilt Angle","TableHeadTiltAngle",false }, + {0x0018,0x9471,VR::FL,VM::VM1,"Table Cradle Tilt Angle","TableCradleTiltAngle",false }, + {0x0018,0x9472,VR::SQ,VM::VM1,"Frame Display Shutter Sequence","FrameDisplayShutterSequence",false }, + {0x0018,0x9473,VR::FL,VM::VM1,"Acquired Image Area Dose Product","AcquiredImageAreaDoseProduct",false }, + {0x0018,0x9474,VR::CS,VM::VM1,"C-arm Positioner Tabletop Relationship","CArmPositionerTabletopRelationship",false }, + {0x0018,0x9476,VR::SQ,VM::VM1,"X-Ray Geometry Sequence","XRayGeometrySequence",false }, + {0x0018,0x9477,VR::SQ,VM::VM1,"Irradiation Event Identification Sequence","IrradiationEventIdentificationSequence",false }, + {0x0018,0x9504,VR::SQ,VM::VM1,"X-Ray 3D Frame Type Sequence","XRay3DFrameTypeSequence",false }, + {0x0018,0x9506,VR::SQ,VM::VM1,"Contributing Sources Sequence","ContributingSourcesSequence",false }, + {0x0018,0x9507,VR::SQ,VM::VM1,"X-Ray 3D Acquisition Sequence","XRay3DAcquisitionSequence",false }, + {0x0018,0x9508,VR::FL,VM::VM1,"Primary Positioner Scan Arc","PrimaryPositionerScanArc",false }, + {0x0018,0x9509,VR::FL,VM::VM1,"Secondary Positioner Scan Arc","SecondaryPositionerScanArc",false }, + {0x0018,0x9510,VR::FL,VM::VM1,"Primary Positioner Scan Start Angle","PrimaryPositionerScanStartAngle",false }, + {0x0018,0x9511,VR::FL,VM::VM1,"Secondary Positioner Scan Start Angle","SecondaryPositionerScanStartAngle",false }, + {0x0018,0x9514,VR::FL,VM::VM1,"Primary Positioner Increment","PrimaryPositionerIncrement",false }, + {0x0018,0x9515,VR::FL,VM::VM1,"Secondary Positioner Increment","SecondaryPositionerIncrement",false }, + {0x0018,0x9516,VR::DT,VM::VM1,"Start Acquisition DateTime","StartAcquisitionDateTime",false }, + {0x0018,0x9517,VR::DT,VM::VM1,"End Acquisition DateTime","EndAcquisitionDateTime",false }, + {0x0018,0x9524,VR::LO,VM::VM1,"Application Name","ApplicationName",false }, + {0x0018,0x9525,VR::LO,VM::VM1,"Application Version","ApplicationVersion",false }, + {0x0018,0x9526,VR::LO,VM::VM1,"Application Manufacturer","ApplicationManufacturer",false }, + {0x0018,0x9527,VR::CS,VM::VM1,"Algorithm Type","AlgorithmType",false }, + {0x0018,0x9528,VR::LO,VM::VM1,"Algorithm Description","AlgorithmDescription",false }, + {0x0018,0x9530,VR::SQ,VM::VM1,"X-Ray 3D Reconstruction Sequence","XRay3DReconstructionSequence",false }, + {0x0018,0x9531,VR::LO,VM::VM1,"Reconstruction Description","ReconstructionDescription",false }, + {0x0018,0x9538,VR::SQ,VM::VM1,"Per Projection Acquisition Sequence","PerProjectionAcquisitionSequence",false }, + {0x0018,0x9601,VR::SQ,VM::VM1,"Diffusion b-matrix Sequence","DiffusionBMatrixSequence",false }, + {0x0018,0x9602,VR::FD,VM::VM1,"Diffusion b-value XX","DiffusionBValueXX",false }, + {0x0018,0x9603,VR::FD,VM::VM1,"Diffusion b-value XY","DiffusionBValueXY",false }, + {0x0018,0x9604,VR::FD,VM::VM1,"Diffusion b-value XZ","DiffusionBValueXZ",false }, + {0x0018,0x9605,VR::FD,VM::VM1,"Diffusion b-value YY","DiffusionBValueYY",false }, + {0x0018,0x9606,VR::FD,VM::VM1,"Diffusion b-value YZ","DiffusionBValueYZ",false }, + {0x0018,0x9607,VR::FD,VM::VM1,"Diffusion b-value ZZ","DiffusionBValueZZ",false }, + {0x0018,0x9701,VR::DT,VM::VM1,"Decay Correction DateTime","DecayCorrectionDateTime",false }, + {0x0018,0x9715,VR::FD,VM::VM1,"Start Density Threshold","StartDensityThreshold",false }, + {0x0018,0x9716,VR::FD,VM::VM1,"Start Relative Density Difference Threshold","StartRelativeDensityDifferenceThreshold",false }, + {0x0018,0x9717,VR::FD,VM::VM1,"Start Cardiac Trigger Count Threshold","StartCardiacTriggerCountThreshold",false }, + {0x0018,0x9718,VR::FD,VM::VM1,"Start Respiratory Trigger Count Threshold","StartRespiratoryTriggerCountThreshold",false }, + {0x0018,0x9719,VR::FD,VM::VM1,"Termination Counts Threshold","TerminationCountsThreshold",false }, + {0x0018,0x9720,VR::FD,VM::VM1,"Termination Density Threshold","TerminationDensityThreshold",false }, + {0x0018,0x9721,VR::FD,VM::VM1,"Termination Relative Density Threshold","TerminationRelativeDensityThreshold",false }, + {0x0018,0x9722,VR::FD,VM::VM1,"Termination Time Threshold","TerminationTimeThreshold",false }, + {0x0018,0x9723,VR::FD,VM::VM1,"Termination Cardiac Trigger Count Threshold","TerminationCardiacTriggerCountThreshold",false }, + {0x0018,0x9724,VR::FD,VM::VM1,"Termination Respiratory Trigger Count Threshold","TerminationRespiratoryTriggerCountThreshold",false }, + {0x0018,0x9725,VR::CS,VM::VM1,"Detector Geometry","DetectorGeometry",false }, + {0x0018,0x9726,VR::FD,VM::VM1,"Transverse Detector Separation","TransverseDetectorSeparation",false }, + {0x0018,0x9727,VR::FD,VM::VM1,"Axial Detector Dimension","AxialDetectorDimension",false }, + {0x0018,0x9729,VR::US,VM::VM1,"Radiopharmaceutical Agent Number","RadiopharmaceuticalAgentNumber",false }, + {0x0018,0x9732,VR::SQ,VM::VM1,"PET Frame Acquisition Sequence","PETFrameAcquisitionSequence",false }, + {0x0018,0x9733,VR::SQ,VM::VM1,"PET Detector Motion Details Sequence","PETDetectorMotionDetailsSequence",false }, + {0x0018,0x9734,VR::SQ,VM::VM1,"PET Table Dynamics Sequence","PETTableDynamicsSequence",false }, + {0x0018,0x9735,VR::SQ,VM::VM1,"PET Position Sequence","PETPositionSequence",false }, + {0x0018,0x9736,VR::SQ,VM::VM1,"PET Frame Correction Factors Sequence","PETFrameCorrectionFactorsSequence",false }, + {0x0018,0x9737,VR::SQ,VM::VM1,"Radiopharmaceutical Usage Sequence","RadiopharmaceuticalUsageSequence",false }, + {0x0018,0x9738,VR::CS,VM::VM1,"Attenuation Correction Source","AttenuationCorrectionSource",false }, + {0x0018,0x9739,VR::US,VM::VM1,"Number of Iterations","NumberOfIterations",false }, + {0x0018,0x9740,VR::US,VM::VM1,"Number of Subsets","NumberOfSubsets",false }, + {0x0018,0x9749,VR::SQ,VM::VM1,"PET Reconstruction Sequence","PETReconstructionSequence",false }, + {0x0018,0x9751,VR::SQ,VM::VM1,"PET Frame Type Sequence","PETFrameTypeSequence",false }, + {0x0018,0x9755,VR::CS,VM::VM1,"Time of Flight Information Used","TimeOfFlightInformationUsed",false }, + {0x0018,0x9756,VR::CS,VM::VM1,"Reconstruction Type","ReconstructionType",false }, + {0x0018,0x9758,VR::CS,VM::VM1,"Decay Corrected","DecayCorrected",false }, + {0x0018,0x9759,VR::CS,VM::VM1,"Attenuation Corrected","AttenuationCorrected",false }, + {0x0018,0x9760,VR::CS,VM::VM1,"Scatter Corrected","ScatterCorrected",false }, + {0x0018,0x9761,VR::CS,VM::VM1,"Dead Time Corrected","DeadTimeCorrected",false }, + {0x0018,0x9762,VR::CS,VM::VM1,"Gantry Motion Corrected","GantryMotionCorrected",false }, + {0x0018,0x9763,VR::CS,VM::VM1,"Patient Motion Corrected","PatientMotionCorrected",false }, + {0x0018,0x9764,VR::CS,VM::VM1,"Count Loss Normalization Corrected","CountLossNormalizationCorrected",false }, + {0x0018,0x9765,VR::CS,VM::VM1,"Randoms Corrected","RandomsCorrected",false }, + {0x0018,0x9766,VR::CS,VM::VM1,"Non-uniform Radial Sampling Corrected","NonUniformRadialSamplingCorrected",false }, + {0x0018,0x9767,VR::CS,VM::VM1,"Sensitivity Calibrated","SensitivityCalibrated",false }, + {0x0018,0x9768,VR::CS,VM::VM1,"Detector Normalization Correction","DetectorNormalizationCorrection",false }, + {0x0018,0x9769,VR::CS,VM::VM1,"Iterative Reconstruction Method","IterativeReconstructionMethod",false }, + {0x0018,0x9770,VR::CS,VM::VM1,"Attenuation Correction Temporal Relationship","AttenuationCorrectionTemporalRelationship",false }, + {0x0018,0x9771,VR::SQ,VM::VM1,"Patient Physiological State Sequence","PatientPhysiologicalStateSequence",false }, + {0x0018,0x9772,VR::SQ,VM::VM1,"Patient Physiological State Code Sequence","PatientPhysiologicalStateCodeSequence",false }, + {0x0018,0x9801,VR::FD,VM::VM1_n,"Depth(s) of Focus","DepthsOfFocus",false }, + {0x0018,0x9803,VR::SQ,VM::VM1,"Excluded Intervals Sequence","ExcludedIntervalsSequence",false }, + {0x0018,0x9804,VR::DT,VM::VM1,"Exclusion Start Datetime","ExclusionStartDatetime",false }, + {0x0018,0x9805,VR::FD,VM::VM1,"Exclusion Duration","ExclusionDuration",false }, + {0x0018,0x9806,VR::SQ,VM::VM1,"US Image Description Sequence","USImageDescriptionSequence",false }, + {0x0018,0x9807,VR::SQ,VM::VM1,"Image Data Type Sequence","ImageDataTypeSequence",false }, + {0x0018,0x9808,VR::CS,VM::VM1,"Data Type","DataType",false }, + {0x0018,0x9809,VR::SQ,VM::VM1,"Transducer Scan Pattern Code Sequence","TransducerScanPatternCodeSequence",false }, + {0x0018,0x980b,VR::CS,VM::VM1,"Aliased Data Type","AliasedDataType",false }, + {0x0018,0x980c,VR::CS,VM::VM1,"Position Measuring Device Used","PositionMeasuringDeviceUsed",false }, + {0x0018,0x980d,VR::SQ,VM::VM1,"Transducer Geometry Code Sequence","TransducerGeometryCodeSequence",false }, + {0x0018,0x980e,VR::SQ,VM::VM1,"Transducer Beam Steering Code Sequence","TransducerBeamSteeringCodeSequence",false }, + {0x0018,0x980f,VR::SQ,VM::VM1,"Transducer Application Code Sequence","TransducerApplicationCodeSequence",false }, + {0x0018,0xa001,VR::SQ,VM::VM1,"Contributing Equipment Sequence","ContributingEquipmentSequence",false }, + {0x0018,0xa002,VR::DT,VM::VM1,"Contribution Date Time","ContributionDateTime",false }, + {0x0018,0xa003,VR::ST,VM::VM1,"Contribution Description","ContributionDescription",false }, + {0x0020,0x000d,VR::UI,VM::VM1,"Study Instance UID","StudyInstanceUID",false }, + {0x0020,0x000e,VR::UI,VM::VM1,"Series Instance UID","SeriesInstanceUID",false }, + {0x0020,0x0010,VR::SH,VM::VM1,"Study ID","StudyID",false }, + {0x0020,0x0011,VR::IS,VM::VM1,"Series Number","SeriesNumber",false }, + {0x0020,0x0012,VR::IS,VM::VM1,"Acquisition Number","AcquisitionNumber",false }, + {0x0020,0x0013,VR::IS,VM::VM1,"Instance Number","InstanceNumber",false }, + {0x0020,0x0014,VR::IS,VM::VM1,"Isotope Number","IsotopeNumber",true }, + {0x0020,0x0015,VR::IS,VM::VM1,"Phase Number","PhaseNumber",true }, + {0x0020,0x0016,VR::IS,VM::VM1,"Interval Number","IntervalNumber",true }, + {0x0020,0x0017,VR::IS,VM::VM1,"Time Slot Number","TimeSlotNumber",true }, + {0x0020,0x0018,VR::IS,VM::VM1,"Angle Number","AngleNumber",true }, + {0x0020,0x0019,VR::IS,VM::VM1,"Item Number","ItemNumber",false }, + {0x0020,0x0020,VR::CS,VM::VM2,"Patient Orientation","PatientOrientation",false }, + {0x0020,0x0022,VR::IS,VM::VM1,"Overlay Number","OverlayNumber",true }, + {0x0020,0x0024,VR::IS,VM::VM1,"Curve Number","CurveNumber",true }, + {0x0020,0x0026,VR::IS,VM::VM1,"LUT Number","LUTNumber",true }, + {0x0020,0x0030,VR::DS,VM::VM3,"Image Position","ImagePosition",true }, + {0x0020,0x0032,VR::DS,VM::VM3,"Image Position (Patient)","ImagePositionPatient",false }, + {0x0020,0x0035,VR::DS,VM::VM6,"Image Orientation","ImageOrientation",true }, + {0x0020,0x0037,VR::DS,VM::VM6,"Image Orientation (Patient)","ImageOrientationPatient",false }, + {0x0020,0x0050,VR::DS,VM::VM1,"Location","Location",true }, + {0x0020,0x0052,VR::UI,VM::VM1,"Frame of Reference UID","FrameOfReferenceUID",false }, + {0x0020,0x0060,VR::CS,VM::VM1,"Laterality","Laterality",false }, + {0x0020,0x0062,VR::CS,VM::VM1,"Image Laterality","ImageLaterality",false }, + {0x0020,0x0070,VR::LO,VM::VM1,"Image Geometry Type","ImageGeometryType",true }, + {0x0020,0x0080,VR::CS,VM::VM1_n,"Masking Image","MaskingImage",true }, + {0x0020,0x00aa,VR::IS,VM::VM1,"Report Number","ReportNumber",true }, + {0x0020,0x0100,VR::IS,VM::VM1,"Temporal Position Identifier","TemporalPositionIdentifier",false }, + {0x0020,0x0105,VR::IS,VM::VM1,"Number of Temporal Positions","NumberOfTemporalPositions",false }, + {0x0020,0x0110,VR::DS,VM::VM1,"Temporal Resolution","TemporalResolution",false }, + {0x0020,0x0200,VR::UI,VM::VM1,"Synchronization Frame of Reference UID","SynchronizationFrameOfReferenceUID",false }, + {0x0020,0x0242,VR::UI,VM::VM1,"SOP Instance UID of Concatenation Source","SOPInstanceUIDOfConcatenationSource",false }, + {0x0020,0x1000,VR::IS,VM::VM1,"Series in Study","SeriesInStudy",true }, + {0x0020,0x1001,VR::IS,VM::VM1,"Acquisitions in Series","AcquisitionsInSeries",true }, + {0x0020,0x1002,VR::IS,VM::VM1,"Images in Acquisition","ImagesInAcquisition",false }, + {0x0020,0x1003,VR::IS,VM::VM1,"Images in Series","ImagesInSeries",true }, + {0x0020,0x1004,VR::IS,VM::VM1,"Acquisitions in Study","AcquisitionsInStudy",true }, + {0x0020,0x1005,VR::IS,VM::VM1,"Images in Study","ImagesInStudy",true }, + {0x0020,0x1020,VR::LO,VM::VM1_n,"Reference","Reference",true }, + {0x0020,0x1040,VR::LO,VM::VM1,"Position Reference Indicator","PositionReferenceIndicator",false }, + {0x0020,0x1041,VR::DS,VM::VM1,"Slice Location","SliceLocation",false }, + {0x0020,0x1070,VR::IS,VM::VM1_n,"Other Study Numbers","OtherStudyNumbers",true }, + {0x0020,0x1200,VR::IS,VM::VM1,"Number of Patient Related Studies","NumberOfPatientRelatedStudies",false }, + {0x0020,0x1202,VR::IS,VM::VM1,"Number of Patient Related Series","NumberOfPatientRelatedSeries",false }, + {0x0020,0x1204,VR::IS,VM::VM1,"Number of Patient Related Instances","NumberOfPatientRelatedInstances",false }, + {0x0020,0x1206,VR::IS,VM::VM1,"Number of Study Related Series","NumberOfStudyRelatedSeries",false }, + {0x0020,0x1208,VR::IS,VM::VM1,"Number of Study Related Instances","NumberOfStudyRelatedInstances",false }, + {0x0020,0x1209,VR::IS,VM::VM1,"Number of Series Related Instances","NumberOfSeriesRelatedInstances",false }, + {0x0020,0x3100,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3101,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3102,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3103,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3104,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3105,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3106,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3107,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3108,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3109,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x310a,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x310b,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x310c,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x310d,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x310e,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x310f,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3110,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3111,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3112,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3113,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3114,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3115,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3116,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3117,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3118,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3119,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x311a,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x311b,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x311c,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x311d,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x311e,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x311f,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3120,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3121,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3122,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3123,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3124,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3125,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3126,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3127,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3128,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3129,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x312a,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x312b,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x312c,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x312d,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x312e,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x312f,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3130,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3131,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3132,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3133,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3134,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3135,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3136,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3137,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3138,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3139,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x313a,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x313b,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x313c,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x313d,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x313e,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x313f,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3140,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3141,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3142,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3143,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3144,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3145,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3146,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3147,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3148,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3149,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x314a,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x314b,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x314c,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x314d,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x314e,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x314f,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3150,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3151,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3152,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3153,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3154,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3155,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3156,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3157,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3158,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3159,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x315a,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x315b,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x315c,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x315d,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x315e,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x315f,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3160,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3161,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3162,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3163,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3164,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3165,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3166,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3167,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3168,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3169,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x316a,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x316b,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x316c,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x316d,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x316e,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x316f,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3170,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3171,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3172,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3173,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3174,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3175,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3176,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3177,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3178,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3179,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x317a,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x317b,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x317c,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x317d,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x317e,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x317f,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3180,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3181,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3182,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3183,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3184,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3185,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3186,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3187,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3188,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3189,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x318a,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x318b,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x318c,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x318d,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x318e,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x318f,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3190,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3191,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3192,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3193,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3194,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3195,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3196,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3197,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3198,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3199,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x319a,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x319b,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x319c,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x319d,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x319e,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x319f,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31a0,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31a1,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31a2,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31a3,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31a4,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31a5,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31a6,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31a7,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31a8,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31a9,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31aa,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31ab,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31ac,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31ad,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31ae,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31af,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31b0,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31b1,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31b2,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31b3,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31b4,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31b5,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31b6,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31b7,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31b8,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31b9,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31ba,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31bb,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31bc,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31bd,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31be,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31bf,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31c0,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31c1,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31c2,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31c3,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31c4,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31c5,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31c6,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31c7,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31c8,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31c9,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31ca,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31cb,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31cc,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31cd,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31ce,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31cf,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31d0,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31d1,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31d2,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31d3,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31d4,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31d5,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31d6,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31d7,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31d8,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31d9,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31da,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31db,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31dc,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31dd,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31de,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31df,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31e0,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31e1,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31e2,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31e3,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31e4,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31e5,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31e6,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31e7,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31e8,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31e9,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31ea,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31eb,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31ec,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31ed,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31ee,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31ef,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31f0,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31f1,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31f2,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31f3,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31f4,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31f5,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31f6,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31f7,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31f8,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31f9,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31fa,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31fb,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31fc,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31fd,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31fe,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x31ff,VR::CS,VM::VM1_n,"Source Image IDs","SourceImageIDs",true }, + {0x0020,0x3401,VR::CS,VM::VM1,"Modifying Device ID","ModifyingDeviceID",true }, + {0x0020,0x3402,VR::CS,VM::VM1,"Modified Image ID","ModifiedImageID",true }, + {0x0020,0x3403,VR::DA,VM::VM1,"Modified Image Date","ModifiedImageDate",true }, + {0x0020,0x3404,VR::LO,VM::VM1,"Modifying Device Manufacturer","ModifyingDeviceManufacturer",true }, + {0x0020,0x3405,VR::TM,VM::VM1,"Modified Image Time","ModifiedImageTime",true }, + {0x0020,0x3406,VR::LO,VM::VM1,"Modified Image Description","ModifiedImageDescription",true }, + {0x0020,0x4000,VR::LT,VM::VM1,"Image Comments","ImageComments",false }, + {0x0020,0x5000,VR::AT,VM::VM1_n,"Original Image Identification","OriginalImageIdentification",true }, + {0x0020,0x5002,VR::LO,VM::VM1_n,"Original Image Identification Nomenclature","OriginalImageIdentificationNomenclature",true }, + {0x0020,0x9056,VR::SH,VM::VM1,"Stack ID","StackID",false }, + {0x0020,0x9057,VR::UL,VM::VM1,"In-Stack Position Number","InStackPositionNumber",false }, + {0x0020,0x9071,VR::SQ,VM::VM1,"Frame Anatomy Sequence","FrameAnatomySequence",false }, + {0x0020,0x9072,VR::CS,VM::VM1,"Frame Laterality","FrameLaterality",false }, + {0x0020,0x9111,VR::SQ,VM::VM1,"Frame Content Sequence","FrameContentSequence",false }, + {0x0020,0x9113,VR::SQ,VM::VM1,"Plane Position Sequence","PlanePositionSequence",false }, + {0x0020,0x9116,VR::SQ,VM::VM1,"Plane Orientation Sequence","PlaneOrientationSequence",false }, + {0x0020,0x9128,VR::UL,VM::VM1,"Temporal Position Index","TemporalPositionIndex",false }, + {0x0020,0x9153,VR::FD,VM::VM1,"Nominal Cardiac Trigger Delay Time","NominalCardiacTriggerDelayTime",false }, + {0x0020,0x9154,VR::FL,VM::VM1,"Nominal Cardiac Trigger Time Prior To R-Peak","NominalCardiacTriggerTimePriorToRPeak",false }, + {0x0020,0x9155,VR::FL,VM::VM1,"Actual Cardiac Trigger Time Prior To R-Peak","ActualCardiacTriggerTimePriorToRPeak",false }, + {0x0020,0x9156,VR::US,VM::VM1,"Frame Acquisition Number","FrameAcquisitionNumber",false }, + {0x0020,0x9157,VR::UL,VM::VM1_n,"Dimension Index Values","DimensionIndexValues",false }, + {0x0020,0x9158,VR::LT,VM::VM1,"Frame Comments","FrameComments",false }, + {0x0020,0x9161,VR::UI,VM::VM1,"Concatenation UID","ConcatenationUID",false }, + {0x0020,0x9162,VR::US,VM::VM1,"In-concatenation Number","InConcatenationNumber",false }, + {0x0020,0x9163,VR::US,VM::VM1,"In-concatenation Total Number","InConcatenationTotalNumber",false }, + {0x0020,0x9164,VR::UI,VM::VM1,"Dimension Organization UID","DimensionOrganizationUID",false }, + {0x0020,0x9165,VR::AT,VM::VM1,"Dimension Index Pointer","DimensionIndexPointer",false }, + {0x0020,0x9167,VR::AT,VM::VM1,"Functional Group Pointer","FunctionalGroupPointer",false }, + {0x0020,0x9213,VR::LO,VM::VM1,"Dimension Index Private Creator","DimensionIndexPrivateCreator",false }, + {0x0020,0x9221,VR::SQ,VM::VM1,"Dimension Organization Sequence","DimensionOrganizationSequence",false }, + {0x0020,0x9222,VR::SQ,VM::VM1,"Dimension Index Sequence","DimensionIndexSequence",false }, + {0x0020,0x9228,VR::UL,VM::VM1,"Concatenation Frame Offset Number","ConcatenationFrameOffsetNumber",false }, + {0x0020,0x9238,VR::LO,VM::VM1,"Functional Group Private Creator","FunctionalGroupPrivateCreator",false }, + {0x0020,0x9241,VR::FL,VM::VM1,"Nominal Percentage of Cardiac Phase","NominalPercentageOfCardiacPhase",false }, + {0x0020,0x9245,VR::FL,VM::VM1,"Nominal Percentage of Respiratory Phase","NominalPercentageOfRespiratoryPhase",false }, + {0x0020,0x9246,VR::FL,VM::VM1,"Starting Respiratory Amplitude","StartingRespiratoryAmplitude",false }, + {0x0020,0x9247,VR::CS,VM::VM1,"Starting Respiratory Phase","StartingRespiratoryPhase",false }, + {0x0020,0x9248,VR::FL,VM::VM1,"Ending Respiratory Amplitude","EndingRespiratoryAmplitude",false }, + {0x0020,0x9249,VR::CS,VM::VM1,"Ending Respiratory Phase","EndingRespiratoryPhase",false }, + {0x0020,0x9250,VR::CS,VM::VM1,"Respiratory Trigger Type","RespiratoryTriggerType",false }, + {0x0020,0x9251,VR::FD,VM::VM1,"R-R Interval Time Nominal","RRIntervalTimeNominal",false }, + {0x0020,0x9252,VR::FD,VM::VM1,"Actual Cardiac Trigger Delay Time","ActualCardiacTriggerDelayTime",false }, + {0x0020,0x9253,VR::SQ,VM::VM1,"Respiratory Synchronization Sequence","RespiratorySynchronizationSequence",false }, + {0x0020,0x9254,VR::FD,VM::VM1,"Respiratory Interval Time","RespiratoryIntervalTime",false }, + {0x0020,0x9255,VR::FD,VM::VM1,"Nominal Respiratory Trigger Delay Time","NominalRespiratoryTriggerDelayTime",false }, + {0x0020,0x9256,VR::FD,VM::VM1,"Respiratory Trigger Delay Threshold","RespiratoryTriggerDelayThreshold",false }, + {0x0020,0x9257,VR::FD,VM::VM1,"Actual Respiratory Trigger Delay Time","ActualRespiratoryTriggerDelayTime",false }, + {0x0020,0x9301,VR::FD,VM::VM3,"Image Position (Volume)","ImagePositionVolume",false }, + {0x0020,0x9302,VR::FD,VM::VM6,"Image Orientation (Volume)","ImageOrientationVolume",false }, + {0x0020,0x9307,VR::CS,VM::VM1,"Ultrasound Acquisition Geometry","UltrasoundAcquisitionGeometry",false }, + {0x0020,0x9308,VR::FD,VM::VM3,"Apex Position","ApexPosition",false }, + {0x0020,0x9309,VR::FD,VM::VM16,"Volume to Transducer Mapping Matrix","VolumeToTransducerMappingMatrix",false }, + {0x0020,0x930a,VR::FD,VM::VM16,"Volume to Table Mapping Matrix","VolumeToTableMappingMatrix",false }, + {0x0020,0x930c,VR::CS,VM::VM1,"Patient Frame of Reference Source","PatientFrameOfReferenceSource",false }, + {0x0020,0x930d,VR::FD,VM::VM1,"Temporal Position Time Offset","TemporalPositionTimeOffset",false }, + {0x0020,0x930e,VR::SQ,VM::VM1,"Plane Position (Volume) Sequence","PlanePositionVolumeSequence",false }, + {0x0020,0x930f,VR::SQ,VM::VM1,"Plane Orientation (Volume) Sequence","PlaneOrientationVolumeSequence",false }, + {0x0020,0x9310,VR::SQ,VM::VM1,"Temporal Position Sequence","TemporalPositionSequence",false }, + {0x0020,0x9311,VR::CS,VM::VM1,"Dimension Organization Type","DimensionOrganizationType",false }, + {0x0020,0x9312,VR::UI,VM::VM1,"Volume Frame of Reference UID","VolumeFrameOfReferenceUID",false }, + {0x0020,0x9313,VR::UI,VM::VM1,"Table Frame of Reference UID","TableFrameOfReferenceUID",false }, + {0x0020,0x9421,VR::LO,VM::VM1,"Dimension Description Label","DimensionDescriptionLabel",false }, + {0x0020,0x9450,VR::SQ,VM::VM1,"Patient Orientation in Frame Sequence","PatientOrientationInFrameSequence",false }, + {0x0020,0x9453,VR::LO,VM::VM1,"Frame Label","FrameLabel",false }, + {0x0020,0x9518,VR::US,VM::VM1_n,"Acquisition Index","AcquisitionIndex",false }, + {0x0020,0x9529,VR::SQ,VM::VM1,"Contributing SOP Instances Reference Sequence","ContributingSOPInstancesReferenceSequence",false }, + {0x0020,0x9536,VR::US,VM::VM1,"Reconstruction Index","ReconstructionIndex",false }, + {0x0022,0x0001,VR::US,VM::VM1,"Light Path Filter Pass-Through Wavelength","LightPathFilterPassThroughWavelength",false }, + {0x0022,0x0002,VR::US,VM::VM2,"Light Path Filter Pass Band","LightPathFilterPassBand",false }, + {0x0022,0x0003,VR::US,VM::VM1,"Image Path Filter Pass-Through Wavelength","ImagePathFilterPassThroughWavelength",false }, + {0x0022,0x0004,VR::US,VM::VM2,"Image Path Filter Pass Band","ImagePathFilterPassBand",false }, + {0x0022,0x0005,VR::CS,VM::VM1,"Patient Eye Movement Commanded","PatientEyeMovementCommanded",false }, + {0x0022,0x0006,VR::SQ,VM::VM1,"Patient Eye Movement Command Code Sequence","PatientEyeMovementCommandCodeSequence",false }, + {0x0022,0x0007,VR::FL,VM::VM1,"Spherical Lens Power","SphericalLensPower",false }, + {0x0022,0x0008,VR::FL,VM::VM1,"Cylinder Lens Power","CylinderLensPower",false }, + {0x0022,0x0009,VR::FL,VM::VM1,"Cylinder Axis","CylinderAxis",false }, + {0x0022,0x000a,VR::FL,VM::VM1,"Emmetropic Magnification","EmmetropicMagnification",false }, + {0x0022,0x000b,VR::FL,VM::VM1,"Intra Ocular Pressure","IntraOcularPressure",false }, + {0x0022,0x000c,VR::FL,VM::VM1,"Horizontal Field of View","HorizontalFieldOfView",false }, + {0x0022,0x000d,VR::CS,VM::VM1,"Pupil Dilated","PupilDilated",false }, + {0x0022,0x000e,VR::FL,VM::VM1,"Degree of Dilation","DegreeOfDilation",false }, + {0x0022,0x0010,VR::FL,VM::VM1,"Stereo Baseline Angle","StereoBaselineAngle",false }, + {0x0022,0x0011,VR::FL,VM::VM1,"Stereo Baseline Displacement","StereoBaselineDisplacement",false }, + {0x0022,0x0012,VR::FL,VM::VM1,"Stereo Horizontal Pixel Offset","StereoHorizontalPixelOffset",false }, + {0x0022,0x0013,VR::FL,VM::VM1,"Stereo Vertical Pixel Offset","StereoVerticalPixelOffset",false }, + {0x0022,0x0014,VR::FL,VM::VM1,"Stereo Rotation","StereoRotation",false }, + {0x0022,0x0015,VR::SQ,VM::VM1,"Acquisition Device Type Code Sequence","AcquisitionDeviceTypeCodeSequence",false }, + {0x0022,0x0016,VR::SQ,VM::VM1,"Illumination Type Code Sequence","IlluminationTypeCodeSequence",false }, + {0x0022,0x0017,VR::SQ,VM::VM1,"Light Path Filter Type Stack Code Sequence","LightPathFilterTypeStackCodeSequence",false }, + {0x0022,0x0018,VR::SQ,VM::VM1,"Image Path Filter Type Stack Code Sequence","ImagePathFilterTypeStackCodeSequence",false }, + {0x0022,0x0019,VR::SQ,VM::VM1,"Lenses Code Sequence","LensesCodeSequence",false }, + {0x0022,0x001a,VR::SQ,VM::VM1,"Channel Description Code Sequence","ChannelDescriptionCodeSequence",false }, + {0x0022,0x001b,VR::SQ,VM::VM1,"Refractive State Sequence","RefractiveStateSequence",false }, + {0x0022,0x001c,VR::SQ,VM::VM1,"Mydriatic Agent Code Sequence","MydriaticAgentCodeSequence",false }, + {0x0022,0x001d,VR::SQ,VM::VM1,"Relative Image Position Code Sequence","RelativeImagePositionCodeSequence",false }, + {0x0022,0x001e,VR::FL,VM::VM1,"Camera Angle of View","CameraAngleOfView",false }, + {0x0022,0x0020,VR::SQ,VM::VM1,"Stereo Pairs Sequence","StereoPairsSequence",false }, + {0x0022,0x0021,VR::SQ,VM::VM1,"Left Image Sequence","LeftImageSequence",false }, + {0x0022,0x0022,VR::SQ,VM::VM1,"Right Image Sequence","RightImageSequence",false }, + {0x0022,0x0030,VR::FL,VM::VM1,"Axial Length of the Eye","AxialLengthOfTheEye",false }, + {0x0022,0x0031,VR::SQ,VM::VM1,"Ophthalmic Frame Location Sequence","OphthalmicFrameLocationSequence",false }, + {0x0022,0x0032,VR::FL,VM::VM2_2n,"Reference Coordinates","ReferenceCoordinates",false }, + {0x0022,0x0035,VR::FL,VM::VM1,"Depth Spatial Resolution","DepthSpatialResolution",false }, + {0x0022,0x0036,VR::FL,VM::VM1,"Maximum Depth Distortion","MaximumDepthDistortion",false }, + {0x0022,0x0037,VR::FL,VM::VM1,"Along-scan Spatial Resolution","AlongScanSpatialResolution",false }, + {0x0022,0x0038,VR::FL,VM::VM1,"Maximum Along-scan Distortion","MaximumAlongScanDistortion",false }, + {0x0022,0x0039,VR::CS,VM::VM1,"Ophthalmic Image Orientation","OphthalmicImageOrientation",false }, + {0x0022,0x0041,VR::FL,VM::VM1,"Depth of Transverse Image","DepthOfTransverseImage",false }, + {0x0022,0x0042,VR::SQ,VM::VM1,"Mydriatic Agent Concentration Units Sequence","MydriaticAgentConcentrationUnitsSequence",false }, + {0x0022,0x0048,VR::FL,VM::VM1,"Across-scan Spatial Resolution","AcrossScanSpatialResolution",false }, + {0x0022,0x0049,VR::FL,VM::VM1,"Maximum Across-scan Distortion","MaximumAcrossScanDistortion",false }, + {0x0022,0x004e,VR::DS,VM::VM1,"Mydriatic Agent Concentration","MydriaticAgentConcentration",false }, + {0x0022,0x0055,VR::FL,VM::VM1,"Illumination Wave Length","IlluminationWaveLength",false }, + {0x0022,0x0056,VR::FL,VM::VM1,"Illumination Power","IlluminationPower",false }, + {0x0022,0x0057,VR::FL,VM::VM1,"Illumination Bandwidth","IlluminationBandwidth",false }, + {0x0022,0x0058,VR::SQ,VM::VM1,"Mydriatic Agent Sequence","MydriaticAgentSequence",false }, + {0x0022,0x1007,VR::SQ,VM::VM1,"Ophthalmic Axial Measurements Right Eye Sequence","OphthalmicAxialMeasurementsRightEyeSequence",false }, + {0x0022,0x1008,VR::SQ,VM::VM1,"Ophthalmic Axial Measurements Left Eye Sequence","OphthalmicAxialMeasurementsLeftEyeSequence",false }, + {0x0022,0x1009,VR::CS,VM::VM1,"Ophthalmic Axial Measurements Device Type","OphthalmicAxialMeasurementsDeviceType",false }, + {0x0022,0x1010,VR::CS,VM::VM1,"Ophthalmic Axial Length Measurements Type","OphthalmicAxialLengthMeasurementsType",false }, + {0x0022,0x1012,VR::SQ,VM::VM1,"Ophthalmic Axial Length Sequence","OphthalmicAxialLengthSequence",false }, + {0x0022,0x1019,VR::FL,VM::VM1,"Ophthalmic Axial Length","OphthalmicAxialLength",false }, + {0x0022,0x1024,VR::SQ,VM::VM1,"Lens Status Code Sequence","LensStatusCodeSequence",false }, + {0x0022,0x1025,VR::SQ,VM::VM1,"Vitreous Status Code Sequence","VitreousStatusCodeSequence",false }, + {0x0022,0x1028,VR::SQ,VM::VM1,"IOL Formula Code Sequence","IOLFormulaCodeSequence",false }, + {0x0022,0x1029,VR::LO,VM::VM1,"IOL Formula Detail","IOLFormulaDetail",false }, + {0x0022,0x1033,VR::FL,VM::VM1,"Keratometer Index","KeratometerIndex",false }, + {0x0022,0x1035,VR::SQ,VM::VM1,"Source of Ophthalmic Axial Length Code Sequence","SourceOfOphthalmicAxialLengthCodeSequence",false }, + {0x0022,0x1037,VR::FL,VM::VM1,"Target Refraction","TargetRefraction",false }, + {0x0022,0x1039,VR::CS,VM::VM1,"Refractive Procedure Occurred","RefractiveProcedureOccurred",false }, + {0x0022,0x1040,VR::SQ,VM::VM1,"Refractive Surgery Type Code Sequence","RefractiveSurgeryTypeCodeSequence",false }, + {0x0022,0x1044,VR::SQ,VM::VM1,"Ophthalmic Ultrasound Method Code Sequence","OphthalmicUltrasoundMethodCodeSequence",false }, + {0x0022,0x1050,VR::SQ,VM::VM1,"Ophthalmic Axial Length Measurements Sequence","OphthalmicAxialLengthMeasurementsSequence",false }, + {0x0022,0x1053,VR::FL,VM::VM1,"IOL Power","IOLPower",false }, + {0x0022,0x1054,VR::FL,VM::VM1,"Predicted Refractive Error","PredictedRefractiveError",false }, + {0x0022,0x1059,VR::FL,VM::VM1,"Ophthalmic Axial Length Velocity","OphthalmicAxialLengthVelocity",false }, + {0x0022,0x1065,VR::LO,VM::VM1,"Lens Status Description","LensStatusDescription",false }, + {0x0022,0x1066,VR::LO,VM::VM1,"Vitreous Status Description","VitreousStatusDescription",false }, + {0x0022,0x1090,VR::SQ,VM::VM1,"IOL Power Sequence","IOLPowerSequence",false }, + {0x0022,0x1092,VR::SQ,VM::VM1,"Lens Constant Sequence","LensConstantSequence",false }, + {0x0022,0x1093,VR::LO,VM::VM1,"IOL Manufacturer","IOLManufacturer",false }, + {0x0022,0x1094,VR::LO,VM::VM1,"Lens Constant Description","LensConstantDescription",false }, + {0x0022,0x1095,VR::LO,VM::VM1,"Implant Name","ImplantName",false }, + {0x0022,0x1096,VR::SQ,VM::VM1,"Keratometry Measurement Type Code Sequence","KeratometryMeasurementTypeCodeSequence",false }, + {0x0022,0x1097,VR::LO,VM::VM1,"Implant Part Number","ImplantPartNumber",false }, + {0x0022,0x1100,VR::SQ,VM::VM1,"Referenced Ophthalmic Axial Measurements Sequence","ReferencedOphthalmicAxialMeasurementsSequence",false }, + {0x0022,0x1101,VR::SQ,VM::VM1,"Ophthalmic Axial Length Measurements Segment Name Code Sequence","OphthalmicAxialLengthMeasurementsSegmentNameCodeSequence",false }, + {0x0022,0x1103,VR::SQ,VM::VM1,"Refractive Error Before Refractive Surgery Code Sequence","RefractiveErrorBeforeRefractiveSurgeryCodeSequence",false }, + {0x0022,0x1121,VR::FL,VM::VM1,"IOL Power For Exact Emmetropia","IOLPowerForExactEmmetropia",false }, + {0x0022,0x1122,VR::FL,VM::VM1,"IOL Power For Exact Target Refraction","IOLPowerForExactTargetRefraction",false }, + {0x0022,0x1125,VR::SQ,VM::VM1,"Anterior Chamber Depth Definition Code Sequence","AnteriorChamberDepthDefinitionCodeSequence",false }, + {0x0022,0x1127,VR::SQ,VM::VM1,"Lens Thickness Sequence","LensThicknessSequence",false }, + {0x0022,0x1128,VR::SQ,VM::VM1,"Anterior Chamber Depth Sequence","AnteriorChamberDepthSequence",false }, + {0x0022,0x1130,VR::FL,VM::VM1,"Lens Thickness","LensThickness",false }, + {0x0022,0x1131,VR::FL,VM::VM1,"Anterior Chamber Depth","AnteriorChamberDepth",false }, + {0x0022,0x1132,VR::SQ,VM::VM1,"Source of Lens Thickness Data Code Sequence","SourceOfLensThicknessDataCodeSequence",false }, + {0x0022,0x1133,VR::SQ,VM::VM1,"Source of Anterior Chamber Depth Data Code Sequence","SourceOfAnteriorChamberDepthDataCodeSequence",false }, + {0x0022,0x1134,VR::SQ,VM::VM1,"Source of Refractive Measurements Sequence","SourceOfRefractiveMeasurementsSequence",false }, + {0x0022,0x1135,VR::SQ,VM::VM1,"Source of Refractive Measurements Code Sequence","SourceOfRefractiveMeasurementsCodeSequence",false }, + {0x0022,0x1140,VR::CS,VM::VM1,"Ophthalmic Axial Length Measurement Modified","OphthalmicAxialLengthMeasurementModified",false }, + {0x0022,0x1150,VR::SQ,VM::VM1,"Ophthalmic Axial Length Data Source Code Sequence","OphthalmicAxialLengthDataSourceCodeSequence",false }, + {0x0022,0x1153,VR::SQ,VM::VM1,"Ophthalmic Axial Length Acquisition Method Code Sequence","OphthalmicAxialLengthAcquisitionMethodCodeSequence",false }, + {0x0022,0x1155,VR::FL,VM::VM1,"Signal to Noise Ratio","SignalToNoiseRatio",false }, + {0x0022,0x1159,VR::LO,VM::VM1,"Ophthalmic Axial Length Data Source Description","OphthalmicAxialLengthDataSourceDescription",false }, + {0x0022,0x1210,VR::SQ,VM::VM1,"Ophthalmic Axial Length Measurements Total Length Sequence","OphthalmicAxialLengthMeasurementsTotalLengthSequence",false }, + {0x0022,0x1211,VR::SQ,VM::VM1,"Ophthalmic Axial Length Measurements Segmental Length Sequence","OphthalmicAxialLengthMeasurementsSegmentalLengthSequence",false }, + {0x0022,0x1212,VR::SQ,VM::VM1,"Ophthalmic Axial Length Measurements Length Summation Sequence","OphthalmicAxialLengthMeasurementsLengthSummationSequence",false }, + {0x0022,0x1220,VR::SQ,VM::VM1,"Ultrasound Ophthalmic Axial Length Measurements Sequence","UltrasoundOphthalmicAxialLengthMeasurementsSequence",false }, + {0x0022,0x1225,VR::SQ,VM::VM1,"Optical Ophthalmic Axial Length Measurements Sequence","OpticalOphthalmicAxialLengthMeasurementsSequence",false }, + {0x0022,0x1230,VR::SQ,VM::VM1,"Ultrasound Selected Ophthalmic Axial Length Sequence","UltrasoundSelectedOphthalmicAxialLengthSequence",false }, + {0x0022,0x1250,VR::SQ,VM::VM1,"Ophthalmic Axial Length Selection Method Code Sequence","OphthalmicAxialLengthSelectionMethodCodeSequence",false }, + {0x0022,0x1255,VR::SQ,VM::VM1,"Optical Selected Ophthalmic Axial Length Sequence","OpticalSelectedOphthalmicAxialLengthSequence",false }, + {0x0022,0x1257,VR::SQ,VM::VM1,"Selected Segmental Ophthalmic Axial Length Sequence","SelectedSegmentalOphthalmicAxialLengthSequence",false }, + {0x0022,0x1260,VR::SQ,VM::VM1,"Selected Total Ophthalmic Axial Length Sequence","SelectedTotalOphthalmicAxialLengthSequence",false }, + {0x0022,0x1262,VR::SQ,VM::VM1,"Ophthalmic Axial Length Quality Metric Sequence","OphthalmicAxialLengthQualityMetricSequence",false }, + {0x0022,0x1273,VR::LO,VM::VM1,"Ophthalmic Axial Length Quality Metric Type Description","OphthalmicAxialLengthQualityMetricTypeDescription",false }, + {0x0022,0x1300,VR::SQ,VM::VM1,"Intraocular Lens Calculations Right Eye Sequence","IntraocularLensCalculationsRightEyeSequence",false }, + {0x0022,0x1310,VR::SQ,VM::VM1,"Intraocular Lens Calculations Left Eye Sequence","IntraocularLensCalculationsLeftEyeSequence",false }, + {0x0022,0x1330,VR::SQ,VM::VM1,"Referenced Ophthalmic Axial Length Measurement QC Image Sequence","ReferencedOphthalmicAxialLengthMeasurementQCImageSequence",false }, + {0x0024,0x0010,VR::FL,VM::VM1,"Visual Field Horizontal Extent","VisualFieldHorizontalExtent",false }, + {0x0024,0x0011,VR::FL,VM::VM1,"Visual Field Vertical Extent","VisualFieldVerticalExtent",false }, + {0x0024,0x0012,VR::CS,VM::VM1,"Visual Field Shape","VisualFieldShape",false }, + {0x0024,0x0016,VR::SQ,VM::VM1,"Screening Test Mode Code Sequence","ScreeningTestModeCodeSequence",false }, + {0x0024,0x0018,VR::FL,VM::VM1,"Maximum Stimulus Luminance","MaximumStimulusLuminance",false }, + {0x0024,0x0020,VR::FL,VM::VM1,"Background Luminance","BackgroundLuminance",false }, + {0x0024,0x0021,VR::SQ,VM::VM1,"Stimulus Color Code Sequence","StimulusColorCodeSequence",false }, + {0x0024,0x0024,VR::SQ,VM::VM1,"Background Illumination Color Code Sequence","BackgroundIlluminationColorCodeSequence",false }, + {0x0024,0x0025,VR::FL,VM::VM1,"Stimulus Area","StimulusArea",false }, + {0x0024,0x0028,VR::FL,VM::VM1,"Stimulus Presentation Time","StimulusPresentationTime",false }, + {0x0024,0x0032,VR::SQ,VM::VM1,"Fixation Sequence","FixationSequence",false }, + {0x0024,0x0033,VR::SQ,VM::VM1,"Fixation Monitoring Code Sequence","FixationMonitoringCodeSequence",false }, + {0x0024,0x0034,VR::SQ,VM::VM1,"Visual Field Catch Trial Sequence","VisualFieldCatchTrialSequence",false }, + {0x0024,0x0035,VR::US,VM::VM1,"Fixation Checked Quantity","FixationCheckedQuantity",false }, + {0x0024,0x0036,VR::US,VM::VM1,"Patient Not Properly Fixated Quantity","PatientNotProperlyFixatedQuantity",false }, + {0x0024,0x0037,VR::CS,VM::VM1,"Presented Visual Stimuli Data Flag","PresentedVisualStimuliDataFlag",false }, + {0x0024,0x0038,VR::US,VM::VM1,"Number of Visual Stimuli","NumberOfVisualStimuli",false }, + {0x0024,0x0039,VR::CS,VM::VM1,"Excessive Fixation Losses Data Flag","ExcessiveFixationLossesDataFlag",false }, + {0x0024,0x0040,VR::CS,VM::VM1,"Excessive Fixation Losses","ExcessiveFixationLosses",false }, + {0x0024,0x0042,VR::US,VM::VM1,"Stimuli Retesting Quantity","StimuliRetestingQuantity",false }, + {0x0024,0x0044,VR::LT,VM::VM1,"Comments on Patient's Performance of Visual Field","CommentsOnPatientPerformanceOfVisualField",false }, + {0x0024,0x0045,VR::CS,VM::VM1,"False Negatives Estimate Flag","FalseNegativesEstimateFlag",false }, + {0x0024,0x0046,VR::FL,VM::VM1,"False Negatives Estimate","FalseNegativesEstimate",false }, + {0x0024,0x0048,VR::US,VM::VM1,"Negative Catch Trials Quantity","NegativeCatchTrialsQuantity",false }, + {0x0024,0x0050,VR::US,VM::VM1,"False Negatives Quantity","FalseNegativesQuantity",false }, + {0x0024,0x0051,VR::CS,VM::VM1,"Excessive False Negatives Data Flag","ExcessiveFalseNegativesDataFlag",false }, + {0x0024,0x0052,VR::CS,VM::VM1,"Excessive False Negatives","ExcessiveFalseNegatives",false }, + {0x0024,0x0053,VR::CS,VM::VM1,"False Positives Estimate Flag","FalsePositivesEstimateFlag",false }, + {0x0024,0x0054,VR::FL,VM::VM1,"False Positives Estimate","FalsePositivesEstimate",false }, + {0x0024,0x0055,VR::CS,VM::VM1,"Catch Trials Data Flag","CatchTrialsDataFlag",false }, + {0x0024,0x0056,VR::US,VM::VM1,"Positive Catch Trials Quantity","PositiveCatchTrialsQuantity",false }, + {0x0024,0x0057,VR::CS,VM::VM1,"Test Point Normals Data Flag","TestPointNormalsDataFlag",false }, + {0x0024,0x0058,VR::SQ,VM::VM1,"Test Point Normals Sequence","TestPointNormalsSequence",false }, + {0x0024,0x0059,VR::CS,VM::VM1,"Global Deviation Probability Normals Flag","GlobalDeviationProbabilityNormalsFlag",false }, + {0x0024,0x0060,VR::US,VM::VM1,"False Positives Quantity","FalsePositivesQuantity",false }, + {0x0024,0x0061,VR::CS,VM::VM1,"Excessive False Positives Data Flag","ExcessiveFalsePositivesDataFlag",false }, + {0x0024,0x0062,VR::CS,VM::VM1,"Excessive False Positives","ExcessiveFalsePositives",false }, + {0x0024,0x0063,VR::CS,VM::VM1,"Visual Field Test Normals Flag","VisualFieldTestNormalsFlag",false }, + {0x0024,0x0064,VR::SQ,VM::VM1,"Results Normals Sequence","ResultsNormalsSequence",false }, + {0x0024,0x0065,VR::SQ,VM::VM1,"Age Corrected Sensitivity Deviation Algorithm Sequence","AgeCorrectedSensitivityDeviationAlgorithmSequence",false }, + {0x0024,0x0066,VR::FL,VM::VM1,"Global Deviation From Normal","GlobalDeviationFromNormal",false }, + {0x0024,0x0067,VR::SQ,VM::VM1,"Generalized Defect Sensitivity Deviation Algorithm Sequence","GeneralizedDefectSensitivityDeviationAlgorithmSequence",false }, + {0x0024,0x0068,VR::FL,VM::VM1,"Localized Deviation from Normal","LocalizedDeviationfromNormal",false }, + {0x0024,0x0069,VR::LO,VM::VM1,"Patient Reliability Indicator","PatientReliabilityIndicator",false }, + {0x0024,0x0070,VR::FL,VM::VM1,"Visual Field Mean Sensitivity","VisualFieldMeanSensitivity",false }, + {0x0024,0x0071,VR::FL,VM::VM1,"Global Deviation Probability","GlobalDeviationProbability",false }, + {0x0024,0x0072,VR::CS,VM::VM1,"Local Deviation Probability Normals Flag","LocalDeviationProbabilityNormalsFlag",false }, + {0x0024,0x0073,VR::FL,VM::VM1,"Localized Deviation Probability","LocalizedDeviationProbability",false }, + {0x0024,0x0074,VR::CS,VM::VM1,"Short Term Fluctuation Calculated","ShortTermFluctuationCalculated",false }, + {0x0024,0x0075,VR::FL,VM::VM1,"Short Term Fluctuation","ShortTermFluctuation",false }, + {0x0024,0x0076,VR::CS,VM::VM1,"Short Term Fluctuation Probability Calculated","ShortTermFluctuationProbabilityCalculated",false }, + {0x0024,0x0077,VR::FL,VM::VM1,"Short Term Fluctuation Probability","ShortTermFluctuationProbability",false }, + {0x0024,0x0078,VR::CS,VM::VM1,"Corrected Localized Deviation From Normal Calculated","CorrectedLocalizedDeviationFromNormalCalculated",false }, + {0x0024,0x0079,VR::FL,VM::VM1,"Corrected Localized Deviation From Normal","CorrectedLocalizedDeviationFromNormal",false }, + {0x0024,0x0080,VR::CS,VM::VM1,"Corrected Localized Deviation From Normal Probability Calculated","CorrectedLocalizedDeviationFromNormalProbabilityCalculated",false }, + {0x0024,0x0081,VR::FL,VM::VM1,"Corrected Localized Deviation From Normal Probability","CorrectedLocalizedDeviationFromNormalProbability",false }, + {0x0024,0x0083,VR::SQ,VM::VM1,"Global Deviation Probability Sequence","GlobalDeviationProbabilitySequence",false }, + {0x0024,0x0085,VR::SQ,VM::VM1,"Localized Deviation Probability Sequence","LocalizedDeviationProbabilitySequence",false }, + {0x0024,0x0086,VR::CS,VM::VM1,"Foveal Sensitivity Measured","FovealSensitivityMeasured",false }, + {0x0024,0x0087,VR::FL,VM::VM1,"Foveal Sensitivity","FovealSensitivity",false }, + {0x0024,0x0088,VR::FL,VM::VM1,"Visual Field Test Duration","VisualFieldTestDuration",false }, + {0x0024,0x0089,VR::SQ,VM::VM1,"Visual Field Test Point Sequence","VisualFieldTestPointSequence",false }, + {0x0024,0x0090,VR::FL,VM::VM1,"Visual Field Test Point X-Coordinate","VisualFieldTestPointXCoordinate",false }, + {0x0024,0x0091,VR::FL,VM::VM1,"Visual Field Test Point Y-Coordinate","VisualFieldTestPointYCoordinate",false }, + {0x0024,0x0092,VR::FL,VM::VM1,"Age Corrected Sensitivity Deviation Value","AgeCorrectedSensitivityDeviationValue",false }, + {0x0024,0x0093,VR::CS,VM::VM1,"Stimulus Results","StimulusResults",false }, + {0x0024,0x0094,VR::FL,VM::VM1,"Sensitivity Value","SensitivityValue",false }, + {0x0024,0x0095,VR::CS,VM::VM1,"Retest Stimulus Seen","RetestStimulusSeen",false }, + {0x0024,0x0096,VR::FL,VM::VM1,"Retest Sensitivity Value","RetestSensitivityValue",false }, + {0x0024,0x0097,VR::SQ,VM::VM1,"Visual Field Test Point Normals Sequence","VisualFieldTestPointNormalsSequence",false }, + {0x0024,0x0098,VR::FL,VM::VM1,"Quantified Defect","QuantifiedDefect",false }, + {0x0024,0x0100,VR::FL,VM::VM1,"Age Corrected Sensitivity Deviation Probability Value","AgeCorrectedSensitivityDeviationProbabilityValue",false }, + {0x0024,0x0102,VR::CS,VM::VM1,"Generalized Defect Corrected Sensitivity Deviation Flag","GeneralizedDefectCorrectedSensitivityDeviationFlag",false }, + {0x0024,0x0103,VR::FL,VM::VM1,"Generalized Defect Corrected Sensitivity Deviation Value","GeneralizedDefectCorrectedSensitivityDeviationValue",false }, + {0x0024,0x0104,VR::FL,VM::VM1,"Generalized Defect Corrected Sensitivity Deviation Probability Value","GeneralizedDefectCorrectedSensitivityDeviationProbabilityValue",false }, + {0x0024,0x0105,VR::FL,VM::VM1,"Minimum Sensitivity Value","MinimumSensitivityValue",false }, + {0x0024,0x0106,VR::CS,VM::VM1,"Blind Spot Localized","BlindSpotLocalized",false }, + {0x0024,0x0107,VR::FL,VM::VM1,"Blind Spot X-Coordinate","BlindSpotXCoordinate",false }, + {0x0024,0x0108,VR::FL,VM::VM1,"Blind Spot Y-Coordinate","BlindSpotYCoordinate",false }, + {0x0024,0x0110,VR::SQ,VM::VM1,"Visual Acuity Measurement Sequence","VisualAcuityMeasurementSequence",false }, + {0x0024,0x0112,VR::SQ,VM::VM1,"Refractive Parameters Used on Patient Sequence","RefractiveParametersUsedOnPatientSequence",false }, + {0x0024,0x0113,VR::CS,VM::VM1,"Measurement Laterality","MeasurementLaterality",false }, + {0x0024,0x0114,VR::SQ,VM::VM1,"Ophthalmic Patient Clinical Information Left Eye Sequence","OphthalmicPatientClinicalInformationLeftEyeSequence",false }, + {0x0024,0x0115,VR::SQ,VM::VM1,"Ophthalmic Patient Clinical Information Right Eye Sequence","OphthalmicPatientClinicalInformationRightEyeSequence",false }, + {0x0024,0x0117,VR::CS,VM::VM1,"Foveal Point Normative Data Flag","FovealPointNormativeDataFlag",false }, + {0x0024,0x0118,VR::FL,VM::VM1,"Foveal Point Probability Value","FovealPointProbabilityValue",false }, + {0x0024,0x0120,VR::CS,VM::VM1,"Screening Baseline Measured","ScreeningBaselineMeasured",false }, + {0x0024,0x0122,VR::SQ,VM::VM1,"Screening Baseline Measured Sequence","ScreeningBaselineMeasuredSequence",false }, + {0x0024,0x0124,VR::CS,VM::VM1,"Screening Baseline Type","ScreeningBaselineType",false }, + {0x0024,0x0126,VR::FL,VM::VM1,"Screening Baseline Value","ScreeningBaselineValue",false }, + {0x0024,0x0202,VR::LO,VM::VM1,"Algorithm Source","AlgorithmSource",false }, + {0x0024,0x0306,VR::LO,VM::VM1,"Data Set Name","DataSetName",false }, + {0x0024,0x0307,VR::LO,VM::VM1,"Data Set Version","DataSetVersion",false }, + {0x0024,0x0308,VR::LO,VM::VM1,"Data Set Source","DataSetSource",false }, + {0x0024,0x0309,VR::LO,VM::VM1,"Data Set Description","DataSetDescription",false }, + {0x0024,0x0317,VR::SQ,VM::VM1,"Visual Field Test Reliability Global Index Sequence","VisualFieldTestReliabilityGlobalIndexSequence",false }, + {0x0024,0x0320,VR::SQ,VM::VM1,"Visual Field Global Results Index Sequence","VisualFieldGlobalResultsIndexSequence",false }, + {0x0024,0x0325,VR::SQ,VM::VM1,"Data Observation Sequence","DataObservationSequence",false }, + {0x0024,0x0338,VR::CS,VM::VM1,"Index Normals Flag","IndexNormalsFlag",false }, + {0x0024,0x0341,VR::FL,VM::VM1,"Index Probability","IndexProbability",false }, + {0x0024,0x0344,VR::SQ,VM::VM1,"Index Probability Sequence","IndexProbabilitySequence",false }, + {0x0028,0x0002,VR::US,VM::VM1,"Samples per Pixel","SamplesPerPixel",false }, + {0x0028,0x0003,VR::US,VM::VM1,"Samples per Pixel Used","SamplesPerPixelUsed",false }, + {0x0028,0x0004,VR::CS,VM::VM1,"Photometric Interpretation","PhotometricInterpretation",false }, + {0x0028,0x0005,VR::US,VM::VM1,"Image Dimensions","ImageDimensions",true }, + {0x0028,0x0006,VR::US,VM::VM1,"Planar Configuration","PlanarConfiguration",false }, + {0x0028,0x0008,VR::IS,VM::VM1,"Number of Frames","NumberOfFrames",false }, + {0x0028,0x0009,VR::AT,VM::VM1_n,"Frame Increment Pointer","FrameIncrementPointer",false }, + {0x0028,0x000a,VR::AT,VM::VM1_n,"Frame Dimension Pointer","FrameDimensionPointer",false }, + {0x0028,0x0010,VR::US,VM::VM1,"Rows","Rows",false }, + {0x0028,0x0011,VR::US,VM::VM1,"Columns","Columns",false }, + {0x0028,0x0012,VR::US,VM::VM1,"Planes","Planes",true }, + {0x0028,0x0014,VR::US,VM::VM1,"Ultrasound Color Data Present","UltrasoundColorDataPresent",false }, + {0x0028,0x0020,VR::INVALID,VM::VM0,"","",true }, + {0x0028,0x0030,VR::DS,VM::VM2,"Pixel Spacing","PixelSpacing",false }, + {0x0028,0x0031,VR::DS,VM::VM2,"Zoom Factor","ZoomFactor",false }, + {0x0028,0x0032,VR::DS,VM::VM2,"Zoom Center","ZoomCenter",false }, + {0x0028,0x0034,VR::IS,VM::VM2,"Pixel Aspect Ratio","PixelAspectRatio",false }, + {0x0028,0x0040,VR::CS,VM::VM1,"Image Format","ImageFormat",true }, + {0x0028,0x0050,VR::LO,VM::VM1_n,"Manipulated Image","ManipulatedImage",true }, + {0x0028,0x0051,VR::CS,VM::VM1_n,"Corrected Image","CorrectedImage",false }, + {0x0028,0x005f,VR::LO,VM::VM1,"Compression Recognition Code","CompressionRecognitionCode",true }, + {0x0028,0x0060,VR::CS,VM::VM1,"Compression Code","CompressionCode",true }, + {0x0028,0x0061,VR::SH,VM::VM1,"Compression Originator","CompressionOriginator",true }, + {0x0028,0x0062,VR::LO,VM::VM1,"Compression Label","CompressionLabel",true }, + {0x0028,0x0063,VR::SH,VM::VM1,"Compression Description","CompressionDescription",true }, + {0x0028,0x0065,VR::CS,VM::VM1_n,"Compression Sequence","CompressionSequence",true }, + {0x0028,0x0066,VR::AT,VM::VM1_n,"Compression Step Pointers","CompressionStepPointers",true }, + {0x0028,0x0068,VR::US,VM::VM1,"Repeat Interval","RepeatInterval",true }, + {0x0028,0x0069,VR::US,VM::VM1,"Bits Grouped","BitsGrouped",true }, + {0x0028,0x0070,VR::US,VM::VM1_n,"Perimeter Table","PerimeterTable",true }, + {0x0028,0x0071,VR::US_SS,VM::VM1,"Perimeter Value","PerimeterValue",true }, + {0x0028,0x0080,VR::US,VM::VM1,"Predictor Rows","PredictorRows",true }, + {0x0028,0x0081,VR::US,VM::VM1,"Predictor Columns","PredictorColumns",true }, + {0x0028,0x0082,VR::US,VM::VM1_n,"Predictor Constants","PredictorConstants",true }, + {0x0028,0x0090,VR::CS,VM::VM1,"Blocked Pixels","BlockedPixels",true }, + {0x0028,0x0091,VR::US,VM::VM1,"Block Rows","BlockRows",true }, + {0x0028,0x0092,VR::US,VM::VM1,"Block Columns","BlockColumns",true }, + {0x0028,0x0093,VR::US,VM::VM1,"Row Overlap","RowOverlap",true }, + {0x0028,0x0094,VR::US,VM::VM1,"Column Overlap","ColumnOverlap",true }, + {0x0028,0x0100,VR::US,VM::VM1,"Bits Allocated","BitsAllocated",false }, + {0x0028,0x0101,VR::US,VM::VM1,"Bits Stored","BitsStored",false }, + {0x0028,0x0102,VR::US,VM::VM1,"High Bit","HighBit",false }, + {0x0028,0x0103,VR::US,VM::VM1,"Pixel Representation","PixelRepresentation",false }, + {0x0028,0x0104,VR::US_SS,VM::VM1,"Smallest Valid Pixel Value","SmallestValidPixelValue",true }, + {0x0028,0x0105,VR::US_SS,VM::VM1,"Largest Valid Pixel Value","LargestValidPixelValue",true }, + {0x0028,0x0106,VR::US_SS,VM::VM1,"Smallest Image Pixel Value","SmallestImagePixelValue",false }, + {0x0028,0x0107,VR::US_SS,VM::VM1,"Largest Image Pixel Value","LargestImagePixelValue",false }, + {0x0028,0x0108,VR::US_SS,VM::VM1,"Smallest Pixel Value in Series","SmallestPixelValueInSeries",false }, + {0x0028,0x0109,VR::US_SS,VM::VM1,"Largest Pixel Value in Series","LargestPixelValueInSeries",false }, + {0x0028,0x0110,VR::US_SS,VM::VM1,"Smallest Image Pixel Value in Plane","SmallestImagePixelValueInPlane",true }, + {0x0028,0x0111,VR::US_SS,VM::VM1,"Largest Image Pixel Value in Plane","LargestImagePixelValueInPlane",true }, + {0x0028,0x0120,VR::US_SS,VM::VM1,"Pixel Padding Value","PixelPaddingValue",false }, + {0x0028,0x0121,VR::US_SS,VM::VM1,"Pixel Padding Range Limit","PixelPaddingRangeLimit",false }, + {0x0028,0x0200,VR::US,VM::VM1,"Image Location","ImageLocation",true }, + {0x0028,0x0300,VR::CS,VM::VM1,"Quality Control Image","QualityControlImage",false }, + {0x0028,0x0301,VR::CS,VM::VM1,"Burned In Annotation","BurnedInAnnotation",false }, + {0x0028,0x0302,VR::CS,VM::VM1,"Recognizable Visual Features","RecognizableVisualFeatures",false }, + {0x0028,0x0303,VR::CS,VM::VM1,"Longitudinal Temporal Information Modified","LongitudinalTemporalInformationModified",false }, + {0x0028,0x0304,VR::UI,VM::VM1,"Referenced Color Palette Instance UID","ReferencedColorPaletteInstanceUID",false }, + {0x0028,0x0400,VR::LO,VM::VM1,"Transform Label","TransformLabel",true }, + {0x0028,0x0401,VR::LO,VM::VM1,"Transform Version Number","TransformVersionNumber",true }, + {0x0028,0x0402,VR::US,VM::VM1,"Number of Transform Steps","NumberOfTransformSteps",true }, + {0x0028,0x0403,VR::LO,VM::VM1_n,"Sequence of Compressed Data","SequenceOfCompressedData",true }, + {0x0028,0x0404,VR::AT,VM::VM1_n,"Details of Coefficients","DetailsOfCoefficients",true }, + {0x0028,0x0700,VR::LO,VM::VM1,"DCT Label","DCTLabel",true }, + {0x0028,0x0701,VR::CS,VM::VM1_n,"Data Block Description","DataBlockDescription",true }, + {0x0028,0x0702,VR::AT,VM::VM1_n,"Data Block","DataBlock",true }, + {0x0028,0x0710,VR::US,VM::VM1,"Normalization Factor Format","NormalizationFactorFormat",true }, + {0x0028,0x0720,VR::US,VM::VM1,"Zonal Map Number Format","ZonalMapNumberFormat",true }, + {0x0028,0x0721,VR::AT,VM::VM1_n,"Zonal Map Location","ZonalMapLocation",true }, + {0x0028,0x0722,VR::US,VM::VM1,"Zonal Map Format","ZonalMapFormat",true }, + {0x0028,0x0730,VR::US,VM::VM1,"Adaptive Map Format","AdaptiveMapFormat",true }, + {0x0028,0x0740,VR::US,VM::VM1,"Code Number Format","CodeNumberFormat",true }, + {0x0028,0x0a02,VR::CS,VM::VM1,"Pixel Spacing Calibration Type","PixelSpacingCalibrationType",false }, + {0x0028,0x0a04,VR::LO,VM::VM1,"Pixel Spacing Calibration Description","PixelSpacingCalibrationDescription",false }, + {0x0028,0x1040,VR::CS,VM::VM1,"Pixel Intensity Relationship","PixelIntensityRelationship",false }, + {0x0028,0x1041,VR::SS,VM::VM1,"Pixel Intensity Relationship Sign","PixelIntensityRelationshipSign",false }, + {0x0028,0x1050,VR::DS,VM::VM1_n,"Window Center","WindowCenter",false }, + {0x0028,0x1051,VR::DS,VM::VM1_n,"Window Width","WindowWidth",false }, + {0x0028,0x1052,VR::DS,VM::VM1,"Rescale Intercept","RescaleIntercept",false }, + {0x0028,0x1053,VR::DS,VM::VM1,"Rescale Slope","RescaleSlope",false }, + {0x0028,0x1054,VR::LO,VM::VM1,"Rescale Type","RescaleType",false }, + {0x0028,0x1055,VR::LO,VM::VM1_n,"Window Center & Width Explanation","WindowCenterWidthExplanation",false }, + {0x0028,0x1056,VR::CS,VM::VM1,"VOI LUT Function","VOILUTFunction",false }, + {0x0028,0x1080,VR::CS,VM::VM1,"Gray Scale","GrayScale",true }, + {0x0028,0x1090,VR::CS,VM::VM1,"Recommended Viewing Mode","RecommendedViewingMode",false }, + {0x0028,0x1100,VR::US_SS,VM::VM3,"Gray Lookup Table Descriptor","GrayLookupTableDescriptor",true }, + {0x0028,0x1101,VR::US_SS,VM::VM3,"Red Palette Color Lookup Table Descriptor","RedPaletteColorLookupTableDescriptor",false }, + {0x0028,0x1102,VR::US_SS,VM::VM3,"Green Palette Color Lookup Table Descriptor","GreenPaletteColorLookupTableDescriptor",false }, + {0x0028,0x1103,VR::US_SS,VM::VM3,"Blue Palette Color Lookup Table Descriptor","BluePaletteColorLookupTableDescriptor",false }, + {0x0028,0x1104,VR::US,VM::VM3,"Alpha Palette Color Lookup Table Descriptor","AlphaPaletteColorLookupTableDescriptor",false }, + {0x0028,0x1111,VR::US_SS,VM::VM4,"Large Red Palette Color Lookup Table Descriptor","LargeRedPaletteColorLookupTableDescriptor",true }, + {0x0028,0x1112,VR::US_SS,VM::VM4,"Large Green Palette Color Lookup Table Descriptor","LargeGreenPaletteColorLookupTableDescriptor",true }, + {0x0028,0x1113,VR::US_SS,VM::VM4,"Large Blue Palette Color Lookup Table Descriptor","LargeBluePaletteColorLookupTableDescriptor",true }, + {0x0028,0x1199,VR::UI,VM::VM1,"Palette Color Lookup Table UID","PaletteColorLookupTableUID",false }, + {0x0028,0x1200,VR::US_SS_OW,VM::VM1_n,"Gray Lookup Table Data","GrayLookupTableData",true }, + {0x0028,0x1201,VR::OW,VM::VM1,"Red Palette Color Lookup Table Data","RedPaletteColorLookupTableData",false }, + {0x0028,0x1202,VR::OW,VM::VM1,"Green Palette Color Lookup Table Data","GreenPaletteColorLookupTableData",false }, + {0x0028,0x1203,VR::OW,VM::VM1,"Blue Palette Color Lookup Table Data","BluePaletteColorLookupTableData",false }, + {0x0028,0x1204,VR::OW,VM::VM1,"Alpha Palette Color Lookup Table Data","AlphaPaletteColorLookupTableData",false }, + {0x0028,0x1211,VR::OW,VM::VM1,"Large Red Palette Color Lookup Table Data","LargeRedPaletteColorLookupTableData",true }, + {0x0028,0x1212,VR::OW,VM::VM1,"Large Green Palette Color Lookup Table Data","LargeGreenPaletteColorLookupTableData",true }, + {0x0028,0x1213,VR::OW,VM::VM1,"Large Blue Palette Color Lookup Table Data","LargeBluePaletteColorLookupTableData",true }, + {0x0028,0x1214,VR::UI,VM::VM1,"Large Palette Color Lookup Table UID","LargePaletteColorLookupTableUID",true }, + {0x0028,0x1221,VR::OW,VM::VM1,"Segmented Red Palette Color Lookup Table Data","SegmentedRedPaletteColorLookupTableData",false }, + {0x0028,0x1222,VR::OW,VM::VM1,"Segmented Green Palette Color Lookup Table Data","SegmentedGreenPaletteColorLookupTableData",false }, + {0x0028,0x1223,VR::OW,VM::VM1,"Segmented Blue Palette Color Lookup Table Data","SegmentedBluePaletteColorLookupTableData",false }, + {0x0028,0x1300,VR::CS,VM::VM1,"Breast Implant Present","BreastImplantPresent",false }, + {0x0028,0x1350,VR::CS,VM::VM1,"Partial View","PartialView",false }, + {0x0028,0x1351,VR::ST,VM::VM1,"Partial View Description","PartialViewDescription",false }, + {0x0028,0x1352,VR::SQ,VM::VM1,"Partial View Code Sequence","PartialViewCodeSequence",false }, + {0x0028,0x135a,VR::CS,VM::VM1,"Spatial Locations Preserved","SpatialLocationsPreserved",false }, + {0x0028,0x1401,VR::SQ,VM::VM1,"Data Frame Assignment Sequence","DataFrameAssignmentSequence",false }, + {0x0028,0x1402,VR::CS,VM::VM1,"Data Path Assignment","DataPathAssignment",false }, + {0x0028,0x1403,VR::US,VM::VM1,"Bits Mapped to Color Lookup Table","BitsMappedToColorLookupTable",false }, + {0x0028,0x1404,VR::SQ,VM::VM1,"Blending LUT 1 Sequence","BlendingLUT1Sequence",false }, + {0x0028,0x1405,VR::CS,VM::VM1,"Blending LUT 1 Transfer Function","BlendingLUT1TransferFunction",false }, + {0x0028,0x1406,VR::FD,VM::VM1,"Blending Weight Constant","BlendingWeightConstant",false }, + {0x0028,0x1407,VR::US,VM::VM3,"Blending Lookup Table Descriptor","BlendingLookupTableDescriptor",false }, + {0x0028,0x1408,VR::OW,VM::VM1,"Blending Lookup Table Data","BlendingLookupTableData",false }, + {0x0028,0x140b,VR::SQ,VM::VM1,"Enhanced Palette Color Lookup Table Sequence","EnhancedPaletteColorLookupTableSequence",false }, + {0x0028,0x140c,VR::SQ,VM::VM1,"Blending LUT 2 Sequence","BlendingLUT2Sequence",false }, + {0x0028,0x140d,VR::CS,VM::VM1,"Blending LUT 2 Transfer Function","BlendingLUT2TransferFunction",false }, + {0x0028,0x140e,VR::CS,VM::VM1,"Data Path ID","DataPathID",false }, + {0x0028,0x140f,VR::CS,VM::VM1,"RGB LUT Transfer Function","RGBLUTTransferFunction",false }, + {0x0028,0x1410,VR::CS,VM::VM1,"Alpha LUT Transfer Function","AlphaLUTTransferFunction",false }, + {0x0028,0x2000,VR::OB,VM::VM1,"ICC Profile","ICCProfile",false }, + {0x0028,0x2110,VR::CS,VM::VM1,"Lossy Image Compression","LossyImageCompression",false }, + {0x0028,0x2112,VR::DS,VM::VM1_n,"Lossy Image Compression Ratio","LossyImageCompressionRatio",false }, + {0x0028,0x2114,VR::CS,VM::VM1_n,"Lossy Image Compression Method","LossyImageCompressionMethod",false }, + {0x0028,0x3000,VR::SQ,VM::VM1,"Modality LUT Sequence","ModalityLUTSequence",false }, + {0x0028,0x3002,VR::US_SS,VM::VM3,"LUT Descriptor","LUTDescriptor",false }, + {0x0028,0x3003,VR::LO,VM::VM1,"LUT Explanation","LUTExplanation",false }, + {0x0028,0x3004,VR::LO,VM::VM1,"Modality LUT Type","ModalityLUTType",false }, + {0x0028,0x3006,VR::US_SS_OW,VM::VM1_n,"LUT Data","LUTData",false }, + {0x0028,0x3010,VR::SQ,VM::VM1,"VOI LUT Sequence","VOILUTSequence",false }, + {0x0028,0x3110,VR::SQ,VM::VM1,"Softcopy VOI LUT Sequence","SoftcopyVOILUTSequence",false }, + {0x0028,0x4000,VR::LT,VM::VM1,"Image Presentation Comments","ImagePresentationComments",true }, + {0x0028,0x5000,VR::SQ,VM::VM1,"Bi-Plane Acquisition Sequence","BiPlaneAcquisitionSequence",true }, + {0x0028,0x6010,VR::US,VM::VM1,"Representative Frame Number","RepresentativeFrameNumber",false }, + {0x0028,0x6020,VR::US,VM::VM1_n,"Frame Numbers of Interest (FOI)","FrameNumbersOfInterest",false }, + {0x0028,0x6022,VR::LO,VM::VM1_n,"Frame of Interest Description","FrameOfInterestDescription",false }, + {0x0028,0x6023,VR::CS,VM::VM1_n,"Frame of Interest Type","FrameOfInterestType",false }, + {0x0028,0x6030,VR::US,VM::VM1_n,"Mask Pointer(s)","MaskPointers",true }, + {0x0028,0x6040,VR::US,VM::VM1_n,"R Wave Pointer","RWavePointer",false }, + {0x0028,0x6100,VR::SQ,VM::VM1,"Mask Subtraction Sequence","MaskSubtractionSequence",false }, + {0x0028,0x6101,VR::CS,VM::VM1,"Mask Operation","MaskOperation",false }, + {0x0028,0x6102,VR::US,VM::VM2_2n,"Applicable Frame Range","ApplicableFrameRange",false }, + {0x0028,0x6110,VR::US,VM::VM1_n,"Mask Frame Numbers","MaskFrameNumbers",false }, + {0x0028,0x6112,VR::US,VM::VM1,"Contrast Frame Averaging","ContrastFrameAveraging",false }, + {0x0028,0x6114,VR::FL,VM::VM2,"Mask Sub-pixel Shift","MaskSubPixelShift",false }, + {0x0028,0x6120,VR::SS,VM::VM1,"TID Offset","TIDOffset",false }, + {0x0028,0x6190,VR::ST,VM::VM1,"Mask Operation Explanation","MaskOperationExplanation",false }, + {0x0028,0x7fe0,VR::UT,VM::VM1,"Pixel Data Provider URL","PixelDataProviderURL",false }, + {0x0028,0x9001,VR::UL,VM::VM1,"Data Point Rows","DataPointRows",false }, + {0x0028,0x9002,VR::UL,VM::VM1,"Data Point Columns","DataPointColumns",false }, + {0x0028,0x9003,VR::CS,VM::VM1,"Signal Domain Columns","SignalDomainColumns",false }, + {0x0028,0x9099,VR::US,VM::VM1,"Largest Monochrome Pixel Value","LargestMonochromePixelValue",true }, + {0x0028,0x9108,VR::CS,VM::VM1,"Data Representation","DataRepresentation",false }, + {0x0028,0x9110,VR::SQ,VM::VM1,"Pixel Measures Sequence","PixelMeasuresSequence",false }, + {0x0028,0x9132,VR::SQ,VM::VM1,"Frame VOI LUT Sequence","FrameVOILUTSequence",false }, + {0x0028,0x9145,VR::SQ,VM::VM1,"Pixel Value Transformation Sequence","PixelValueTransformationSequence",false }, + {0x0028,0x9235,VR::CS,VM::VM1,"Signal Domain Rows","SignalDomainRows",false }, + {0x0028,0x9411,VR::FL,VM::VM1,"Display Filter Percentage","DisplayFilterPercentage",false }, + {0x0028,0x9415,VR::SQ,VM::VM1,"Frame Pixel Shift Sequence","FramePixelShiftSequence",false }, + {0x0028,0x9416,VR::US,VM::VM1,"Subtraction Item ID","SubtractionItemID",false }, + {0x0028,0x9422,VR::SQ,VM::VM1,"Pixel Intensity Relationship LUT Sequence","PixelIntensityRelationshipLUTSequence",false }, + {0x0028,0x9443,VR::SQ,VM::VM1,"Frame Pixel Data Properties Sequence","FramePixelDataPropertiesSequence",false }, + {0x0028,0x9444,VR::CS,VM::VM1,"Geometrical Properties","GeometricalProperties",false }, + {0x0028,0x9445,VR::FL,VM::VM1,"Geometric Maximum Distortion","GeometricMaximumDistortion",false }, + {0x0028,0x9446,VR::CS,VM::VM1_n,"Image Processing Applied","ImageProcessingApplied",false }, + {0x0028,0x9454,VR::CS,VM::VM1,"Mask Selection Mode","MaskSelectionMode",false }, + {0x0028,0x9474,VR::CS,VM::VM1,"LUT Function","LUTFunction",false }, + {0x0028,0x9478,VR::FL,VM::VM1,"Mask Visibility Percentage","MaskVisibilityPercentage",false }, + {0x0028,0x9501,VR::SQ,VM::VM1,"Pixel Shift Sequence","PixelShiftSequence",false }, + {0x0028,0x9502,VR::SQ,VM::VM1,"Region Pixel Shift Sequence","RegionPixelShiftSequence",false }, + {0x0028,0x9503,VR::SS,VM::VM2_2n,"Vertices of the Region","VerticesOfTheRegion",false }, + {0x0028,0x9505,VR::SQ,VM::VM1,"Multi-frame Presentation Sequence","MultiFramePresentationSequence",false }, + {0x0028,0x9506,VR::US,VM::VM2_2n,"Pixel Shift Frame Range","PixelShiftFrameRange",false }, + {0x0028,0x9507,VR::US,VM::VM2_2n,"LUT Frame Range","LUTFrameRange",false }, + {0x0028,0x9520,VR::DS,VM::VM16,"Image to Equipment Mapping Matrix","ImageToEquipmentMappingMatrix",false }, + {0x0028,0x9537,VR::CS,VM::VM1,"Equipment Coordinate System Identification","EquipmentCoordinateSystemIdentification",false }, + {0x0032,0x000a,VR::CS,VM::VM1,"Study Status ID","StudyStatusID",true }, + {0x0032,0x000c,VR::CS,VM::VM1,"Study Priority ID","StudyPriorityID",true }, + {0x0032,0x0012,VR::LO,VM::VM1,"Study ID Issuer","StudyIDIssuer",true }, + {0x0032,0x0032,VR::DA,VM::VM1,"Study Verified Date","StudyVerifiedDate",true }, + {0x0032,0x0033,VR::TM,VM::VM1,"Study Verified Time","StudyVerifiedTime",true }, + {0x0032,0x0034,VR::DA,VM::VM1,"Study Read Date","StudyReadDate",true }, + {0x0032,0x0035,VR::TM,VM::VM1,"Study Read Time","StudyReadTime",true }, + {0x0032,0x1000,VR::DA,VM::VM1,"Scheduled Study Start Date","ScheduledStudyStartDate",true }, + {0x0032,0x1001,VR::TM,VM::VM1,"Scheduled Study Start Time","ScheduledStudyStartTime",true }, + {0x0032,0x1010,VR::DA,VM::VM1,"Scheduled Study Stop Date","ScheduledStudyStopDate",true }, + {0x0032,0x1011,VR::TM,VM::VM1,"Scheduled Study Stop Time","ScheduledStudyStopTime",true }, + {0x0032,0x1020,VR::LO,VM::VM1,"Scheduled Study Location","ScheduledStudyLocation",true }, + {0x0032,0x1021,VR::AE,VM::VM1_n,"Scheduled Study Location AE Title","ScheduledStudyLocationAETitle",true }, + {0x0032,0x1030,VR::LO,VM::VM1,"Reason for Study","ReasonForStudy",true }, + {0x0032,0x1031,VR::SQ,VM::VM1,"Requesting Physician Identification Sequence","RequestingPhysicianIdentificationSequence",false }, + {0x0032,0x1032,VR::PN,VM::VM1,"Requesting Physician","RequestingPhysician",false }, + {0x0032,0x1033,VR::LO,VM::VM1,"Requesting Service","RequestingService",false }, + {0x0032,0x1034,VR::SQ,VM::VM1,"Requesting Service Code Sequence","RequestingServiceCodeSequence",false }, + {0x0032,0x1040,VR::DA,VM::VM1,"Study Arrival Date","StudyArrivalDate",true }, + {0x0032,0x1041,VR::TM,VM::VM1,"Study Arrival Time","StudyArrivalTime",true }, + {0x0032,0x1050,VR::DA,VM::VM1,"Study Completion Date","StudyCompletionDate",true }, + {0x0032,0x1051,VR::TM,VM::VM1,"Study Completion Time","StudyCompletionTime",true }, + {0x0032,0x1055,VR::CS,VM::VM1,"Study Component Status ID","StudyComponentStatusID",true }, + {0x0032,0x1060,VR::LO,VM::VM1,"Requested Procedure Description","RequestedProcedureDescription",false }, + {0x0032,0x1064,VR::SQ,VM::VM1,"Requested Procedure Code Sequence","RequestedProcedureCodeSequence",false }, + {0x0032,0x1070,VR::LO,VM::VM1,"Requested Contrast Agent","RequestedContrastAgent",false }, + {0x0032,0x4000,VR::LT,VM::VM1,"Study Comments","StudyComments",true }, + {0x0038,0x0004,VR::SQ,VM::VM1,"Referenced Patient Alias Sequence","ReferencedPatientAliasSequence",false }, + {0x0038,0x0008,VR::CS,VM::VM1,"Visit Status ID","VisitStatusID",false }, + {0x0038,0x0010,VR::LO,VM::VM1,"Admission ID","AdmissionID",false }, + {0x0038,0x0011,VR::LO,VM::VM1,"Issuer of Admission ID","IssuerOfAdmissionID",true }, + {0x0038,0x0014,VR::SQ,VM::VM1,"Issuer of Admission ID Sequence","IssuerOfAdmissionIDSequence",false }, + {0x0038,0x0016,VR::LO,VM::VM1,"Route of Admissions","RouteOfAdmissions",false }, + {0x0038,0x001a,VR::DA,VM::VM1,"Scheduled Admission Date","ScheduledAdmissionDate",true }, + {0x0038,0x001b,VR::TM,VM::VM1,"Scheduled Admission Time","ScheduledAdmissionTime",true }, + {0x0038,0x001c,VR::DA,VM::VM1,"Scheduled Discharge Date","ScheduledDischargeDate",true }, + {0x0038,0x001d,VR::TM,VM::VM1,"Scheduled Discharge Time","ScheduledDischargeTime",true }, + {0x0038,0x001e,VR::LO,VM::VM1,"Scheduled Patient Institution Residence","ScheduledPatientInstitutionResidence",true }, + {0x0038,0x0020,VR::DA,VM::VM1,"Admitting Date","AdmittingDate",false }, + {0x0038,0x0021,VR::TM,VM::VM1,"Admitting Time","AdmittingTime",false }, + {0x0038,0x0030,VR::DA,VM::VM1,"Discharge Date","DischargeDate",true }, + {0x0038,0x0032,VR::TM,VM::VM1,"Discharge Time","DischargeTime",true }, + {0x0038,0x0040,VR::LO,VM::VM1,"Discharge Diagnosis Description","DischargeDiagnosisDescription",true }, + {0x0038,0x0044,VR::SQ,VM::VM1,"Discharge Diagnosis Code Sequence","DischargeDiagnosisCodeSequence",true }, + {0x0038,0x0050,VR::LO,VM::VM1,"Special Needs","SpecialNeeds",false }, + {0x0038,0x0060,VR::LO,VM::VM1,"Service Episode ID","ServiceEpisodeID",false }, + {0x0038,0x0061,VR::LO,VM::VM1,"Issuer of Service Episode ID","IssuerOfServiceEpisodeID",true }, + {0x0038,0x0062,VR::LO,VM::VM1,"Service Episode Description","ServiceEpisodeDescription",false }, + {0x0038,0x0064,VR::SQ,VM::VM1,"Issuer of Service Episode ID Sequence","IssuerOfServiceEpisodeIDSequence",false }, + {0x0038,0x0100,VR::SQ,VM::VM1,"Pertinent Documents Sequence","PertinentDocumentsSequence",false }, + {0x0038,0x0300,VR::LO,VM::VM1,"Current Patient Location","CurrentPatientLocation",false }, + {0x0038,0x0400,VR::LO,VM::VM1,"Patient's Institution Residence","PatientInstitutionResidence",false }, + {0x0038,0x0500,VR::LO,VM::VM1,"Patient State","PatientState",false }, + {0x0038,0x0502,VR::SQ,VM::VM1,"Patient Clinical Trial Participation Sequence","PatientClinicalTrialParticipationSequence",false }, + {0x0038,0x4000,VR::LT,VM::VM1,"Visit Comments","VisitComments",false }, + {0x003a,0x0004,VR::CS,VM::VM1,"Waveform Originality","WaveformOriginality",false }, + {0x003a,0x0005,VR::US,VM::VM1,"Number of Waveform Channels","NumberOfWaveformChannels",false }, + {0x003a,0x0010,VR::UL,VM::VM1,"Number of Waveform Samples","NumberOfWaveformSamples",false }, + {0x003a,0x001a,VR::DS,VM::VM1,"Sampling Frequency","SamplingFrequency",false }, + {0x003a,0x0020,VR::SH,VM::VM1,"Multiplex Group Label","MultiplexGroupLabel",false }, + {0x003a,0x0200,VR::SQ,VM::VM1,"Channel Definition Sequence","ChannelDefinitionSequence",false }, + {0x003a,0x0202,VR::IS,VM::VM1,"Waveform Channel Number","WaveformChannelNumber",false }, + {0x003a,0x0203,VR::SH,VM::VM1,"Channel Label","ChannelLabel",false }, + {0x003a,0x0205,VR::CS,VM::VM1_n,"Channel Status","ChannelStatus",false }, + {0x003a,0x0208,VR::SQ,VM::VM1,"Channel Source Sequence","ChannelSourceSequence",false }, + {0x003a,0x0209,VR::SQ,VM::VM1,"Channel Source Modifiers Sequence","ChannelSourceModifiersSequence",false }, + {0x003a,0x020a,VR::SQ,VM::VM1,"Source Waveform Sequence","SourceWaveformSequence",false }, + {0x003a,0x020c,VR::LO,VM::VM1,"Channel Derivation Description","ChannelDerivationDescription",false }, + {0x003a,0x0210,VR::DS,VM::VM1,"Channel Sensitivity","ChannelSensitivity",false }, + {0x003a,0x0211,VR::SQ,VM::VM1,"Channel Sensitivity Units Sequence","ChannelSensitivityUnitsSequence",false }, + {0x003a,0x0212,VR::DS,VM::VM1,"Channel Sensitivity Correction Factor","ChannelSensitivityCorrectionFactor",false }, + {0x003a,0x0213,VR::DS,VM::VM1,"Channel Baseline","ChannelBaseline",false }, + {0x003a,0x0214,VR::DS,VM::VM1,"Channel Time Skew","ChannelTimeSkew",false }, + {0x003a,0x0215,VR::DS,VM::VM1,"Channel Sample Skew","ChannelSampleSkew",false }, + {0x003a,0x0218,VR::DS,VM::VM1,"Channel Offset","ChannelOffset",false }, + {0x003a,0x021a,VR::US,VM::VM1,"Waveform Bits Stored","WaveformBitsStored",false }, + {0x003a,0x0220,VR::DS,VM::VM1,"Filter Low Frequency","FilterLowFrequency",false }, + {0x003a,0x0221,VR::DS,VM::VM1,"Filter High Frequency","FilterHighFrequency",false }, + {0x003a,0x0222,VR::DS,VM::VM1,"Notch Filter Frequency","NotchFilterFrequency",false }, + {0x003a,0x0223,VR::DS,VM::VM1,"Notch Filter Bandwidth","NotchFilterBandwidth",false }, + {0x003a,0x0230,VR::FL,VM::VM1,"Waveform Data Display Scale","WaveformDataDisplayScale",false }, + {0x003a,0x0231,VR::US,VM::VM3,"Waveform Display Background CIELab Value","WaveformDisplayBackgroundCIELabValue",false }, + {0x003a,0x0240,VR::SQ,VM::VM1,"Waveform Presentation Group Sequence","WaveformPresentationGroupSequence",false }, + {0x003a,0x0241,VR::US,VM::VM1,"Presentation Group Number","PresentationGroupNumber",false }, + {0x003a,0x0242,VR::SQ,VM::VM1,"Channel Display Sequence","ChannelDisplaySequence",false }, + {0x003a,0x0244,VR::US,VM::VM3,"Channel Recommended Display CIELab Value","ChannelRecommendedDisplayCIELabValue",false }, + {0x003a,0x0245,VR::FL,VM::VM1,"Channel Position","ChannelPosition",false }, + {0x003a,0x0246,VR::CS,VM::VM1,"Display Shading Flag","DisplayShadingFlag",false }, + {0x003a,0x0247,VR::FL,VM::VM1,"Fractional Channel Display Scale","FractionalChannelDisplayScale",false }, + {0x003a,0x0248,VR::FL,VM::VM1,"Absolute Channel Display Scale","AbsoluteChannelDisplayScale",false }, + {0x003a,0x0300,VR::SQ,VM::VM1,"Multiplexed Audio Channels Description Code Sequence","MultiplexedAudioChannelsDescriptionCodeSequence",false }, + {0x003a,0x0301,VR::IS,VM::VM1,"Channel Identification Code","ChannelIdentificationCode",false }, + {0x003a,0x0302,VR::CS,VM::VM1,"Channel Mode","ChannelMode",false }, + {0x0040,0x0001,VR::AE,VM::VM1_n,"Scheduled Station AE Title","ScheduledStationAETitle",false }, + {0x0040,0x0002,VR::DA,VM::VM1,"Scheduled Procedure Step Start Date","ScheduledProcedureStepStartDate",false }, + {0x0040,0x0003,VR::TM,VM::VM1,"Scheduled Procedure Step Start Time","ScheduledProcedureStepStartTime",false }, + {0x0040,0x0004,VR::DA,VM::VM1,"Scheduled Procedure Step End Date","ScheduledProcedureStepEndDate",false }, + {0x0040,0x0005,VR::TM,VM::VM1,"Scheduled Procedure Step End Time","ScheduledProcedureStepEndTime",false }, + {0x0040,0x0006,VR::PN,VM::VM1,"Scheduled Performing Physician's Name","ScheduledPerformingPhysicianName",false }, + {0x0040,0x0007,VR::LO,VM::VM1,"Scheduled Procedure Step Description","ScheduledProcedureStepDescription",false }, + {0x0040,0x0008,VR::SQ,VM::VM1,"Scheduled Protocol Code Sequence","ScheduledProtocolCodeSequence",false }, + {0x0040,0x0009,VR::SH,VM::VM1,"Scheduled Procedure Step ID","ScheduledProcedureStepID",false }, + {0x0040,0x000a,VR::SQ,VM::VM1,"Stage Code Sequence","StageCodeSequence",false }, + {0x0040,0x000b,VR::SQ,VM::VM1,"Scheduled Performing Physician Identification Sequence","ScheduledPerformingPhysicianIdentificationSequence",false }, + {0x0040,0x0010,VR::SH,VM::VM1_n,"Scheduled Station Name","ScheduledStationName",false }, + {0x0040,0x0011,VR::SH,VM::VM1,"Scheduled Procedure Step Location","ScheduledProcedureStepLocation",false }, + {0x0040,0x0012,VR::LO,VM::VM1,"Pre-Medication","PreMedication",false }, + {0x0040,0x0020,VR::CS,VM::VM1,"Scheduled Procedure Step Status","ScheduledProcedureStepStatus",false }, + {0x0040,0x0026,VR::SQ,VM::VM1,"Order Placer Identifier Sequence","OrderPlacerIdentifierSequence",false }, + {0x0040,0x0027,VR::SQ,VM::VM1,"Order Filler Identifier Sequence","OrderFillerIdentifierSequence",false }, + {0x0040,0x0031,VR::UT,VM::VM1,"Local Namespace Entity ID","LocalNamespaceEntityID",false }, + {0x0040,0x0032,VR::UT,VM::VM1,"Universal Entity ID","UniversalEntityID",false }, + {0x0040,0x0033,VR::CS,VM::VM1,"Universal Entity ID Type","UniversalEntityIDType",false }, + {0x0040,0x0035,VR::CS,VM::VM1,"Identifier Type Code","IdentifierTypeCode",false }, + {0x0040,0x0036,VR::SQ,VM::VM1,"Assigning Facility Sequence","AssigningFacilitySequence",false }, + {0x0040,0x0039,VR::SQ,VM::VM1,"Assigning Jurisdiction Code Sequence","AssigningJurisdictionCodeSequence",false }, + {0x0040,0x003a,VR::SQ,VM::VM1,"Assigning Agency or Department Code Sequence","AssigningAgencyOrDepartmentCodeSequence",false }, + {0x0040,0x0100,VR::SQ,VM::VM1,"Scheduled Procedure Step Sequence","ScheduledProcedureStepSequence",false }, + {0x0040,0x0220,VR::SQ,VM::VM1,"Referenced Non-Image Composite SOP Instance Sequence","ReferencedNonImageCompositeSOPInstanceSequence",false }, + {0x0040,0x0241,VR::AE,VM::VM1,"Performed Station AE Title","PerformedStationAETitle",false }, + {0x0040,0x0242,VR::SH,VM::VM1,"Performed Station Name","PerformedStationName",false }, + {0x0040,0x0243,VR::SH,VM::VM1,"Performed Location","PerformedLocation",false }, + {0x0040,0x0244,VR::DA,VM::VM1,"Performed Procedure Step Start Date","PerformedProcedureStepStartDate",false }, + {0x0040,0x0245,VR::TM,VM::VM1,"Performed Procedure Step Start Time","PerformedProcedureStepStartTime",false }, + {0x0040,0x0250,VR::DA,VM::VM1,"Performed Procedure Step End Date","PerformedProcedureStepEndDate",false }, + {0x0040,0x0251,VR::TM,VM::VM1,"Performed Procedure Step End Time","PerformedProcedureStepEndTime",false }, + {0x0040,0x0252,VR::CS,VM::VM1,"Performed Procedure Step Status","PerformedProcedureStepStatus",false }, + {0x0040,0x0253,VR::SH,VM::VM1,"Performed Procedure Step ID","PerformedProcedureStepID",false }, + {0x0040,0x0254,VR::LO,VM::VM1,"Performed Procedure Step Description","PerformedProcedureStepDescription",false }, + {0x0040,0x0255,VR::LO,VM::VM1,"Performed Procedure Type Description","PerformedProcedureTypeDescription",false }, + {0x0040,0x0260,VR::SQ,VM::VM1,"Performed Protocol Code Sequence","PerformedProtocolCodeSequence",false }, + {0x0040,0x0261,VR::CS,VM::VM1,"Performed Protocol Type","PerformedProtocolType",false }, + {0x0040,0x0270,VR::SQ,VM::VM1,"Scheduled Step Attributes Sequence","ScheduledStepAttributesSequence",false }, + {0x0040,0x0275,VR::SQ,VM::VM1,"Request Attributes Sequence","RequestAttributesSequence",false }, + {0x0040,0x0280,VR::ST,VM::VM1,"Comments on the Performed Procedure Step","CommentsOnThePerformedProcedureStep",false }, + {0x0040,0x0281,VR::SQ,VM::VM1,"Performed Procedure Step Discontinuation Reason Code Sequence","PerformedProcedureStepDiscontinuationReasonCodeSequence",false }, + {0x0040,0x0293,VR::SQ,VM::VM1,"Quantity Sequence","QuantitySequence",false }, + {0x0040,0x0294,VR::DS,VM::VM1,"Quantity","Quantity",false }, + {0x0040,0x0295,VR::SQ,VM::VM1,"Measuring Units Sequence","MeasuringUnitsSequence",false }, + {0x0040,0x0296,VR::SQ,VM::VM1,"Billing Item Sequence","BillingItemSequence",false }, + {0x0040,0x0300,VR::US,VM::VM1,"Total Time of Fluoroscopy","TotalTimeOfFluoroscopy",false }, + {0x0040,0x0301,VR::US,VM::VM1,"Total Number of Exposures","TotalNumberOfExposures",false }, + {0x0040,0x0302,VR::US,VM::VM1,"Entrance Dose","EntranceDose",false }, + {0x0040,0x0303,VR::US,VM::VM1_2,"Exposed Area","ExposedArea",false }, + {0x0040,0x0306,VR::DS,VM::VM1,"Distance Source to Entrance","DistanceSourceToEntrance",false }, + {0x0040,0x0307,VR::DS,VM::VM1,"Distance Source to Support","DistanceSourceToSupport",true }, + {0x0040,0x030e,VR::SQ,VM::VM1,"Exposure Dose Sequence","ExposureDoseSequence",false }, + {0x0040,0x0310,VR::ST,VM::VM1,"Comments on Radiation Dose","CommentsOnRadiationDose",false }, + {0x0040,0x0312,VR::DS,VM::VM1,"X-Ray Output","XRayOutput",false }, + {0x0040,0x0314,VR::DS,VM::VM1,"Half Value Layer","HalfValueLayer",false }, + {0x0040,0x0316,VR::DS,VM::VM1,"Organ Dose","OrganDose",false }, + {0x0040,0x0318,VR::CS,VM::VM1,"Organ Exposed","OrganExposed",false }, + {0x0040,0x0320,VR::SQ,VM::VM1,"Billing Procedure Step Sequence","BillingProcedureStepSequence",false }, + {0x0040,0x0321,VR::SQ,VM::VM1,"Film Consumption Sequence","FilmConsumptionSequence",false }, + {0x0040,0x0324,VR::SQ,VM::VM1,"Billing Supplies and Devices Sequence","BillingSuppliesAndDevicesSequence",false }, + {0x0040,0x0330,VR::SQ,VM::VM1,"Referenced Procedure Step Sequence","ReferencedProcedureStepSequence",true }, + {0x0040,0x0340,VR::SQ,VM::VM1,"Performed Series Sequence","PerformedSeriesSequence",false }, + {0x0040,0x0400,VR::LT,VM::VM1,"Comments on the Scheduled Procedure Step","CommentsOnTheScheduledProcedureStep",false }, + {0x0040,0x0440,VR::SQ,VM::VM1,"Protocol Context Sequence","ProtocolContextSequence",false }, + {0x0040,0x0441,VR::SQ,VM::VM1,"Content Item Modifier Sequence","ContentItemModifierSequence",false }, + {0x0040,0x0500,VR::SQ,VM::VM1,"Scheduled Specimen Sequence","ScheduledSpecimenSequence",false }, + {0x0040,0x050a,VR::LO,VM::VM1,"Specimen Accession Number","SpecimenAccessionNumber",true }, + {0x0040,0x0512,VR::LO,VM::VM1,"Container Identifier","ContainerIdentifier",false }, + {0x0040,0x0513,VR::SQ,VM::VM1,"Issuer of the Container Identifier Sequence","IssuerOfTheContainerIdentifierSequence",false }, + {0x0040,0x0515,VR::SQ,VM::VM1,"Alternate Container Identifier Sequence","AlternateContainerIdentifierSequence",false }, + {0x0040,0x0518,VR::SQ,VM::VM1,"Container Type Code Sequence","ContainerTypeCodeSequence",false }, + {0x0040,0x051a,VR::LO,VM::VM1,"Container Description","ContainerDescription",false }, + {0x0040,0x0520,VR::SQ,VM::VM1,"Container Component Sequence","ContainerComponentSequence",false }, + {0x0040,0x0550,VR::SQ,VM::VM1,"Specimen Sequence","SpecimenSequence",true }, + {0x0040,0x0551,VR::LO,VM::VM1,"Specimen Identifier","SpecimenIdentifier",false }, + {0x0040,0x0552,VR::SQ,VM::VM1,"Specimen Description Sequence (Trial)","SpecimenDescriptionSequenceTrial",true }, + {0x0040,0x0553,VR::ST,VM::VM1,"Specimen Description (Trial)","SpecimenDescriptionTrial",true }, + {0x0040,0x0554,VR::UI,VM::VM1,"Specimen UID","SpecimenUID",false }, + {0x0040,0x0555,VR::SQ,VM::VM1,"Acquisition Context Sequence","AcquisitionContextSequence",false }, + {0x0040,0x0556,VR::ST,VM::VM1,"Acquisition Context Description","AcquisitionContextDescription",false }, + {0x0040,0x0560,VR::SQ,VM::VM1,"Specimen Description Sequence","SpecimenDescriptionSequence",false }, + {0x0040,0x0562,VR::SQ,VM::VM1,"Issuer of the Specimen Identifier Sequence","IssuerOfTheSpecimenIdentifierSequence",false }, + {0x0040,0x059a,VR::SQ,VM::VM1,"Specimen Type Code Sequence","SpecimenTypeCodeSequence",false }, + {0x0040,0x0600,VR::LO,VM::VM1,"Specimen Short Description","SpecimenShortDescription",false }, + {0x0040,0x0602,VR::UT,VM::VM1,"Specimen Detailed Description","SpecimenDetailedDescription",false }, + {0x0040,0x0610,VR::SQ,VM::VM1,"Specimen Preparation Sequence","SpecimenPreparationSequence",false }, + {0x0040,0x0612,VR::SQ,VM::VM1,"Specimen Preparation Step Content Item Sequence","SpecimenPreparationStepContentItemSequence",false }, + {0x0040,0x0620,VR::SQ,VM::VM1,"Specimen Localization Content Item Sequence","SpecimenLocalizationContentItemSequence",false }, + {0x0040,0x06fa,VR::LO,VM::VM1,"Slide Identifier","SlideIdentifier",true }, + {0x0040,0x071a,VR::SQ,VM::VM1,"Image Center Point Coordinates Sequence","ImageCenterPointCoordinatesSequence",false }, + {0x0040,0x072a,VR::DS,VM::VM1,"X Offset in Slide Coordinate System","XOffsetInSlideCoordinateSystem",false }, + {0x0040,0x073a,VR::DS,VM::VM1,"Y Offset in Slide Coordinate System","YOffsetInSlideCoordinateSystem",false }, + {0x0040,0x074a,VR::DS,VM::VM1,"Z Offset in Slide Coordinate System","ZOffsetInSlideCoordinateSystem",false }, + {0x0040,0x08d8,VR::SQ,VM::VM1,"Pixel Spacing Sequence","PixelSpacingSequence",true }, + {0x0040,0x08da,VR::SQ,VM::VM1,"Coordinate System Axis Code Sequence","CoordinateSystemAxisCodeSequence",true }, + {0x0040,0x08ea,VR::SQ,VM::VM1,"Measurement Units Code Sequence","MeasurementUnitsCodeSequence",false }, + {0x0040,0x09f8,VR::SQ,VM::VM1,"Vital Stain Code Sequence (Trial)","VitalStainCodeSequenceTrial",true }, + {0x0040,0x1001,VR::SH,VM::VM1,"Requested Procedure ID","RequestedProcedureID",false }, + {0x0040,0x1002,VR::LO,VM::VM1,"Reason for the Requested Procedure","ReasonForTheRequestedProcedure",false }, + {0x0040,0x1003,VR::SH,VM::VM1,"Requested Procedure Priority","RequestedProcedurePriority",false }, + {0x0040,0x1004,VR::LO,VM::VM1,"Patient Transport Arrangements","PatientTransportArrangements",false }, + {0x0040,0x1005,VR::LO,VM::VM1,"Requested Procedure Location","RequestedProcedureLocation",false }, + {0x0040,0x1006,VR::SH,VM::VM1,"Placer Order Number / Procedure","PlacerOrderNumberProcedure",true }, + {0x0040,0x1007,VR::SH,VM::VM1,"Filler Order Number / Procedure","FillerOrderNumberProcedure",true }, + {0x0040,0x1008,VR::LO,VM::VM1,"Confidentiality Code","ConfidentialityCode",false }, + {0x0040,0x1009,VR::SH,VM::VM1,"Reporting Priority","ReportingPriority",false }, + {0x0040,0x100a,VR::SQ,VM::VM1,"Reason for Requested Procedure Code Sequence","ReasonForRequestedProcedureCodeSequence",false }, + {0x0040,0x1010,VR::PN,VM::VM1_n,"Names of Intended Recipients of Results","NamesOfIntendedRecipientsOfResults",false }, + {0x0040,0x1011,VR::SQ,VM::VM1,"Intended Recipients of Results Identification Sequence","IntendedRecipientsOfResultsIdentificationSequence",false }, + {0x0040,0x1012,VR::SQ,VM::VM1,"Reason For Performed Procedure Code Sequence","ReasonForPerformedProcedureCodeSequence",false }, + {0x0040,0x1060,VR::LO,VM::VM1,"Requested Procedure Description (Trial)","RequestedProcedureDescriptionTrial",true }, + {0x0040,0x1101,VR::SQ,VM::VM1,"Person Identification Code Sequence","PersonIdentificationCodeSequence",false }, + {0x0040,0x1102,VR::ST,VM::VM1,"Person's Address","PersonAddress",false }, + {0x0040,0x1103,VR::LO,VM::VM1_n,"Person's Telephone Numbers","PersonTelephoneNumbers",false }, + {0x0040,0x1400,VR::LT,VM::VM1,"Requested Procedure Comments","RequestedProcedureComments",false }, + {0x0040,0x2001,VR::LO,VM::VM1,"Reason for the Imaging Service Request","ReasonForTheImagingServiceRequest",true }, + {0x0040,0x2004,VR::DA,VM::VM1,"Issue Date of Imaging Service Request","IssueDateOfImagingServiceRequest",false }, + {0x0040,0x2005,VR::TM,VM::VM1,"Issue Time of Imaging Service Request","IssueTimeOfImagingServiceRequest",false }, + {0x0040,0x2006,VR::SH,VM::VM1,"Placer Order Number / Imaging Service Request (Retired)","PlacerOrderNumberImagingServiceRequestRetired",true }, + {0x0040,0x2007,VR::SH,VM::VM1,"Filler Order Number / Imaging Service Request (Retired)","FillerOrderNumberImagingServiceRequestRetired",true }, + {0x0040,0x2008,VR::PN,VM::VM1,"Order Entered By","OrderEnteredBy",false }, + {0x0040,0x2009,VR::SH,VM::VM1,"Order Enterer's Location","OrderEntererLocation",false }, + {0x0040,0x2010,VR::SH,VM::VM1,"Order Callback Phone Number","OrderCallbackPhoneNumber",false }, + {0x0040,0x2016,VR::LO,VM::VM1,"Placer Order Number / Imaging Service Request","PlacerOrderNumberImagingServiceRequest",false }, + {0x0040,0x2017,VR::LO,VM::VM1,"Filler Order Number / Imaging Service Request","FillerOrderNumberImagingServiceRequest",false }, + {0x0040,0x2400,VR::LT,VM::VM1,"Imaging Service Request Comments","ImagingServiceRequestComments",false }, + {0x0040,0x3001,VR::LO,VM::VM1,"Confidentiality Constraint on Patient Data Description","ConfidentialityConstraintOnPatientDataDescription",false }, + {0x0040,0x4001,VR::CS,VM::VM1,"General Purpose Scheduled Procedure Step Status","GeneralPurposeScheduledProcedureStepStatus",false }, + {0x0040,0x4002,VR::CS,VM::VM1,"General Purpose Performed Procedure Step Status","GeneralPurposePerformedProcedureStepStatus",false }, + {0x0040,0x4003,VR::CS,VM::VM1,"General Purpose Scheduled Procedure Step Priority","GeneralPurposeScheduledProcedureStepPriority",false }, + {0x0040,0x4004,VR::SQ,VM::VM1,"Scheduled Processing Applications Code Sequence","ScheduledProcessingApplicationsCodeSequence",false }, + {0x0040,0x4005,VR::DT,VM::VM1,"Scheduled Procedure Step Start DateTime","ScheduledProcedureStepStartDateTime",false }, + {0x0040,0x4006,VR::CS,VM::VM1,"Multiple Copies Flag","MultipleCopiesFlag",false }, + {0x0040,0x4007,VR::SQ,VM::VM1,"Performed Processing Applications Code Sequence","PerformedProcessingApplicationsCodeSequence",false }, + {0x0040,0x4009,VR::SQ,VM::VM1,"Human Performer Code Sequence","HumanPerformerCodeSequence",false }, + {0x0040,0x4010,VR::DT,VM::VM1,"Scheduled Procedure Step Modification Date Time","ScheduledProcedureStepModificationDateTime",false }, + {0x0040,0x4011,VR::DT,VM::VM1,"Expected Completion Date Time","ExpectedCompletionDateTime",false }, + {0x0040,0x4015,VR::SQ,VM::VM1,"Resulting General Purpose Performed Procedure Steps Sequence","ResultingGeneralPurposePerformedProcedureStepsSequence",false }, + {0x0040,0x4016,VR::SQ,VM::VM1,"Referenced General Purpose Scheduled Procedure Step Sequence","ReferencedGeneralPurposeScheduledProcedureStepSequence",false }, + {0x0040,0x4018,VR::SQ,VM::VM1,"Scheduled Workitem Code Sequence","ScheduledWorkitemCodeSequence",false }, + {0x0040,0x4019,VR::SQ,VM::VM1,"Performed Workitem Code Sequence","PerformedWorkitemCodeSequence",false }, + {0x0040,0x4020,VR::CS,VM::VM1,"Input Availability Flag","InputAvailabilityFlag",false }, + {0x0040,0x4021,VR::SQ,VM::VM1,"Input Information Sequence","InputInformationSequence",false }, + {0x0040,0x4022,VR::SQ,VM::VM1,"Relevant Information Sequence","RelevantInformationSequence",false }, + {0x0040,0x4023,VR::UI,VM::VM1,"Referenced General Purpose Scheduled Procedure Step Transaction UID","ReferencedGeneralPurposeScheduledProcedureStepTransactionUID",false }, + {0x0040,0x4025,VR::SQ,VM::VM1,"Scheduled Station Name Code Sequence","ScheduledStationNameCodeSequence",false }, + {0x0040,0x4026,VR::SQ,VM::VM1,"Scheduled Station Class Code Sequence","ScheduledStationClassCodeSequence",false }, + {0x0040,0x4027,VR::SQ,VM::VM1,"Scheduled Station Geographic Location Code Sequence","ScheduledStationGeographicLocationCodeSequence",false }, + {0x0040,0x4028,VR::SQ,VM::VM1,"Performed Station Name Code Sequence","PerformedStationNameCodeSequence",false }, + {0x0040,0x4029,VR::SQ,VM::VM1,"Performed Station Class Code Sequence","PerformedStationClassCodeSequence",false }, + {0x0040,0x4030,VR::SQ,VM::VM1,"Performed Station Geographic Location Code Sequence","PerformedStationGeographicLocationCodeSequence",false }, + {0x0040,0x4031,VR::SQ,VM::VM1,"Requested Subsequent Workitem Code Sequence","RequestedSubsequentWorkitemCodeSequence",false }, + {0x0040,0x4032,VR::SQ,VM::VM1,"Non-DICOM Output Code Sequence","NonDICOMOutputCodeSequence",false }, + {0x0040,0x4033,VR::SQ,VM::VM1,"Output Information Sequence","OutputInformationSequence",false }, + {0x0040,0x4034,VR::SQ,VM::VM1,"Scheduled Human Performers Sequence","ScheduledHumanPerformersSequence",false }, + {0x0040,0x4035,VR::SQ,VM::VM1,"Actual Human Performers Sequence","ActualHumanPerformersSequence",false }, + {0x0040,0x4036,VR::LO,VM::VM1,"Human Performer's Organization","HumanPerformerOrganization",false }, + {0x0040,0x4037,VR::PN,VM::VM1,"Human Performer's Name","HumanPerformerName",false }, + {0x0040,0x4040,VR::CS,VM::VM1,"Raw Data Handling","RawDataHandling",false }, + {0x0040,0x4041,VR::CS,VM::VM1,"Input Readiness State","InputReadinessState",false }, + {0x0040,0x4050,VR::DT,VM::VM1,"Performed Procedure Step Start DateTime","PerformedProcedureStepStartDateTime",false }, + {0x0040,0x4051,VR::DT,VM::VM1,"Performed Procedure Step End DateTime","PerformedProcedureStepEndDateTime",false }, + {0x0040,0x4052,VR::DT,VM::VM1,"Procedure Step Cancellation DateTime","ProcedureStepCancellationDateTime",false }, + {0x0040,0x8302,VR::DS,VM::VM1,"Entrance Dose in mGy","EntranceDoseInmGy",false }, + {0x0040,0x9094,VR::SQ,VM::VM1,"Referenced Image Real World Value Mapping Sequence","ReferencedImageRealWorldValueMappingSequence",false }, + {0x0040,0x9096,VR::SQ,VM::VM1,"Real World Value Mapping Sequence","RealWorldValueMappingSequence",false }, + {0x0040,0x9098,VR::SQ,VM::VM1,"Pixel Value Mapping Code Sequence","PixelValueMappingCodeSequence",false }, + {0x0040,0x9210,VR::SH,VM::VM1,"LUT Label","LUTLabel",false }, + {0x0040,0x9211,VR::US_SS,VM::VM1,"Real World Value Last Value Mapped","RealWorldValueLastValueMapped",false }, + {0x0040,0x9212,VR::FD,VM::VM1_n,"Real World Value LUT Data","RealWorldValueLUTData",false }, + {0x0040,0x9216,VR::US_SS,VM::VM1,"Real World Value First Value Mapped","RealWorldValueFirstValueMapped",false }, + {0x0040,0x9224,VR::FD,VM::VM1,"Real World Value Intercept","RealWorldValueIntercept",false }, + {0x0040,0x9225,VR::FD,VM::VM1,"Real World Value Slope","RealWorldValueSlope",false }, + {0x0040,0xa007,VR::CS,VM::VM1,"Findings Flag (Trial)","FindingsFlagTrial",true }, + {0x0040,0xa010,VR::CS,VM::VM1,"Relationship Type","RelationshipType",false }, + {0x0040,0xa020,VR::SQ,VM::VM1,"Findings Sequence (Trial)","FindingsSequenceTrial",true }, + {0x0040,0xa021,VR::UI,VM::VM1,"Findings Group UID (Trial)","FindingsGroupUIDTrial",true }, + {0x0040,0xa022,VR::UI,VM::VM1,"Referenced Findings Group UID (Trial)","ReferencedFindingsGroupUIDTrial",true }, + {0x0040,0xa023,VR::DA,VM::VM1,"Findings Group Recording Date (Trial)","FindingsGroupRecordingDateTrial",true }, + {0x0040,0xa024,VR::TM,VM::VM1,"Findings Group Recording Time (Trial)","FindingsGroupRecordingTimeTrial",true }, + {0x0040,0xa026,VR::SQ,VM::VM1,"Findings Source Category Code Sequence (Trial)","FindingsSourceCategoryCodeSequenceTrial",true }, + {0x0040,0xa027,VR::LO,VM::VM1,"Verifying Organization","VerifyingOrganization",false }, + {0x0040,0xa028,VR::SQ,VM::VM1,"Documenting Organization Identifier Code Sequence (Trial)","DocumentingOrganizationIdentifierCodeSequenceTrial",true }, + {0x0040,0xa030,VR::DT,VM::VM1,"Verification Date Time","VerificationDateTime",false }, + {0x0040,0xa032,VR::DT,VM::VM1,"Observation Date Time","ObservationDateTime",false }, + {0x0040,0xa040,VR::CS,VM::VM1,"Value Type","ValueType",false }, + {0x0040,0xa043,VR::SQ,VM::VM1,"Concept Name Code Sequence","ConceptNameCodeSequence",false }, + {0x0040,0xa047,VR::LO,VM::VM1,"Measurement Precision Description (Trial)","MeasurementPrecisionDescriptionTrial",true }, + {0x0040,0xa050,VR::CS,VM::VM1,"Continuity Of Content","ContinuityOfContent",false }, + {0x0040,0xa057,VR::CS,VM::VM1_n,"Urgency or Priority Alerts (Trial)","UrgencyOrPriorityAlertsTrial",true }, + {0x0040,0xa060,VR::LO,VM::VM1,"Sequencing Indicator (Trial)","SequencingIndicatorTrial",true }, + {0x0040,0xa066,VR::SQ,VM::VM1,"Document Identifier Code Sequence (Trial)","DocumentIdentifierCodeSequenceTrial",true }, + {0x0040,0xa067,VR::PN,VM::VM1,"Document Author (Trial)","DocumentAuthorTrial",true }, + {0x0040,0xa068,VR::SQ,VM::VM1,"Document Author Identifier Code Sequence (Trial)","DocumentAuthorIdentifierCodeSequenceTrial",true }, + {0x0040,0xa070,VR::SQ,VM::VM1,"Identifier Code Sequence (Trial)","IdentifierCodeSequenceTrial",true }, + {0x0040,0xa073,VR::SQ,VM::VM1,"Verifying Observer Sequence","VerifyingObserverSequence",false }, + {0x0040,0xa074,VR::OB,VM::VM1,"Object Binary Identifier (Trial)","ObjectBinaryIdentifierTrial",true }, + {0x0040,0xa075,VR::PN,VM::VM1,"Verifying Observer Name","VerifyingObserverName",false }, + {0x0040,0xa076,VR::SQ,VM::VM1,"Documenting Observer Identifier Code Sequence (Trial)","DocumentingObserverIdentifierCodeSequenceTrial",true }, + {0x0040,0xa078,VR::SQ,VM::VM1,"Author Observer Sequence","AuthorObserverSequence",false }, + {0x0040,0xa07a,VR::SQ,VM::VM1,"Participant Sequence","ParticipantSequence",false }, + {0x0040,0xa07c,VR::SQ,VM::VM1,"Custodial Organization Sequence","CustodialOrganizationSequence",false }, + {0x0040,0xa080,VR::CS,VM::VM1,"Participation Type","ParticipationType",false }, + {0x0040,0xa082,VR::DT,VM::VM1,"Participation DateTime","ParticipationDateTime",false }, + {0x0040,0xa084,VR::CS,VM::VM1,"Observer Type","ObserverType",false }, + {0x0040,0xa085,VR::SQ,VM::VM1,"Procedure Identifier Code Sequence (Trial)","ProcedureIdentifierCodeSequenceTrial",true }, + {0x0040,0xa088,VR::SQ,VM::VM1,"Verifying Observer Identification Code Sequence","VerifyingObserverIdentificationCodeSequence",false }, + {0x0040,0xa089,VR::OB,VM::VM1,"Object Directory Binary Identifier (Trial)","ObjectDirectoryBinaryIdentifierTrial",true }, + {0x0040,0xa090,VR::SQ,VM::VM1,"Equivalent CDA Document Sequence","EquivalentCDADocumentSequence",true }, + {0x0040,0xa0b0,VR::US,VM::VM2_2n,"Referenced Waveform Channels","ReferencedWaveformChannels",false }, + {0x0040,0xa110,VR::DA,VM::VM1,"Date of Document or Verbal Transaction (Trial)","DateOfDocumentOrVerbalTransactionTrial",true }, + {0x0040,0xa112,VR::TM,VM::VM1,"Time of Document Creation or Verbal Transaction (Trial)","TimeOfDocumentCreationOrVerbalTransactionTrial",true }, + {0x0040,0xa120,VR::DT,VM::VM1,"DateTime","DateTime",false }, + {0x0040,0xa121,VR::DA,VM::VM1,"Date","Date",false }, + {0x0040,0xa122,VR::TM,VM::VM1,"Time","Time",false }, + {0x0040,0xa123,VR::PN,VM::VM1,"Person Name","PersonName",false }, + {0x0040,0xa124,VR::UI,VM::VM1,"UID","UID",false }, + {0x0040,0xa125,VR::CS,VM::VM2,"Report Status ID (Trial)","ReportStatusIDTrial",true }, + {0x0040,0xa130,VR::CS,VM::VM1,"Temporal Range Type","TemporalRangeType",false }, + {0x0040,0xa132,VR::UL,VM::VM1_n,"Referenced Sample Positions","ReferencedSamplePositions",false }, + {0x0040,0xa136,VR::US,VM::VM1_n,"Referenced Frame Numbers","ReferencedFrameNumbers",false }, + {0x0040,0xa138,VR::DS,VM::VM1_n,"Referenced Time Offsets","ReferencedTimeOffsets",false }, + {0x0040,0xa13a,VR::DT,VM::VM1_n,"Referenced DateTime","ReferencedDateTime",false }, + {0x0040,0xa160,VR::UT,VM::VM1,"Text Value","TextValue",false }, + {0x0040,0xa167,VR::SQ,VM::VM1,"Observation Category Code Sequence (Trial)","ObservationCategoryCodeSequenceTrial",true }, + {0x0040,0xa168,VR::SQ,VM::VM1,"Concept Code Sequence","ConceptCodeSequence",false }, + {0x0040,0xa16a,VR::ST,VM::VM1,"Bibliographic Citation (Trial)","BibliographicCitationTrial",true }, + {0x0040,0xa170,VR::SQ,VM::VM1,"Purpose of Reference Code Sequence","PurposeOfReferenceCodeSequence",false }, + {0x0040,0xa171,VR::UI,VM::VM1,"Observation UID (Trial)","ObservationUIDTrial",true }, + {0x0040,0xa172,VR::UI,VM::VM1,"Referenced Observation UID (Trial)","ReferencedObservationUIDTrial",true }, + {0x0040,0xa173,VR::CS,VM::VM1,"Referenced Observation Class (Trial)","ReferencedObservationClassTrial",true }, + {0x0040,0xa174,VR::CS,VM::VM1,"Referenced Object Observation Class (Trial)","ReferencedObjectObservationClassTrial",true }, + {0x0040,0xa180,VR::US,VM::VM1,"Annotation Group Number","AnnotationGroupNumber",false }, + {0x0040,0xa192,VR::DA,VM::VM1,"Observation Date (Trial)","ObservationDateTrial",true }, + {0x0040,0xa193,VR::TM,VM::VM1,"Observation Time (Trial)","ObservationTimeTrial",true }, + {0x0040,0xa194,VR::CS,VM::VM1,"Measurement Automation (Trial)","MeasurementAutomationTrial",true }, + {0x0040,0xa195,VR::SQ,VM::VM1,"Modifier Code Sequence","ModifierCodeSequence",false }, + {0x0040,0xa224,VR::ST,VM::VM1,"Identification Description (Trial)","IdentificationDescriptionTrial",true }, + {0x0040,0xa290,VR::CS,VM::VM1,"Coordinates Set Geometric Type (Trial)","CoordinatesSetGeometricTypeTrial",true }, + {0x0040,0xa296,VR::SQ,VM::VM1,"Algorithm Code Sequence (Trial)","AlgorithmCodeSequenceTrial",true }, + {0x0040,0xa297,VR::ST,VM::VM1,"Algorithm Description (Trial)","AlgorithmDescriptionTrial",true }, + {0x0040,0xa29a,VR::SL,VM::VM2_2n,"Pixel Coordinates Set (Trial)","PixelCoordinatesSetTrial",true }, + {0x0040,0xa300,VR::SQ,VM::VM1,"Measured Value Sequence","MeasuredValueSequence",false }, + {0x0040,0xa301,VR::SQ,VM::VM1,"Numeric Value Qualifier Code Sequence","NumericValueQualifierCodeSequence",false }, + {0x0040,0xa307,VR::PN,VM::VM1,"Current Observer (Trial)","CurrentObserverTrial",true }, + {0x0040,0xa30a,VR::DS,VM::VM1_n,"Numeric Value","NumericValue",false }, + {0x0040,0xa313,VR::SQ,VM::VM1,"Referenced Accession Sequence (Trial)","ReferencedAccessionSequenceTrial",true }, + {0x0040,0xa33a,VR::ST,VM::VM1,"Report Status Comment (Trial)","ReportStatusCommentTrial",true }, + {0x0040,0xa340,VR::SQ,VM::VM1,"Procedure Context Sequence (Trial)","ProcedureContextSequenceTrial",true }, + {0x0040,0xa352,VR::PN,VM::VM1,"Verbal Source (Trial)","VerbalSourceTrial",true }, + {0x0040,0xa353,VR::ST,VM::VM1,"Address (Trial)","AddressTrial",true }, + {0x0040,0xa354,VR::LO,VM::VM1,"Telephone Number (Trial)","TelephoneNumberTrial",true }, + {0x0040,0xa358,VR::SQ,VM::VM1,"Verbal Source Identifier Code Sequence (Trial)","VerbalSourceIdentifierCodeSequenceTrial",true }, + {0x0040,0xa360,VR::SQ,VM::VM1,"Predecessor Documents Sequence","PredecessorDocumentsSequence",false }, + {0x0040,0xa370,VR::SQ,VM::VM1,"Referenced Request Sequence","ReferencedRequestSequence",false }, + {0x0040,0xa372,VR::SQ,VM::VM1,"Performed Procedure Code Sequence","PerformedProcedureCodeSequence",false }, + {0x0040,0xa375,VR::SQ,VM::VM1,"Current Requested Procedure Evidence Sequence","CurrentRequestedProcedureEvidenceSequence",false }, + {0x0040,0xa380,VR::SQ,VM::VM1,"Report Detail Sequence (Trial)","ReportDetailSequenceTrial",true }, + {0x0040,0xa385,VR::SQ,VM::VM1,"Pertinent Other Evidence Sequence","PertinentOtherEvidenceSequence",false }, + {0x0040,0xa390,VR::SQ,VM::VM1,"HL7 Structured Document Reference Sequence","HL7StructuredDocumentReferenceSequence",false }, + {0x0040,0xa402,VR::UI,VM::VM1,"Observation Subject UID (Trial)","ObservationSubjectUIDTrial",true }, + {0x0040,0xa403,VR::CS,VM::VM1,"Observation Subject Class (Trial)","ObservationSubjectClassTrial",true }, + {0x0040,0xa404,VR::SQ,VM::VM1,"Observation Subject Type Code Sequence (Trial)","ObservationSubjectTypeCodeSequenceTrial",true }, + {0x0040,0xa491,VR::CS,VM::VM1,"Completion Flag","CompletionFlag",false }, + {0x0040,0xa492,VR::LO,VM::VM1,"Completion Flag Description","CompletionFlagDescription",false }, + {0x0040,0xa493,VR::CS,VM::VM1,"Verification Flag","VerificationFlag",false }, + {0x0040,0xa494,VR::CS,VM::VM1,"Archive Requested","ArchiveRequested",false }, + {0x0040,0xa496,VR::CS,VM::VM1,"Preliminary Flag","PreliminaryFlag",false }, + {0x0040,0xa504,VR::SQ,VM::VM1,"Content Template Sequence","ContentTemplateSequence",false }, + {0x0040,0xa525,VR::SQ,VM::VM1,"Identical Documents Sequence","IdenticalDocumentsSequence",false }, + {0x0040,0xa600,VR::CS,VM::VM1,"Observation Subject Context Flag (Trial)","ObservationSubjectContextFlagTrial",true }, + {0x0040,0xa601,VR::CS,VM::VM1,"Observer Context Flag (Trial)","ObserverContextFlagTrial",true }, + {0x0040,0xa603,VR::CS,VM::VM1,"Procedure Context Flag (Trial)","ProcedureContextFlagTrial",true }, + {0x0040,0xa730,VR::SQ,VM::VM1,"Content Sequence","ContentSequence",false }, + {0x0040,0xa731,VR::SQ,VM::VM1,"Relationship Sequence (Trial)","RelationshipSequenceTrial",true }, + {0x0040,0xa732,VR::SQ,VM::VM1,"Relationship Type Code Sequence (Trial)","RelationshipTypeCodeSequenceTrial",true }, + {0x0040,0xa744,VR::SQ,VM::VM1,"Language Code Sequence (Trial)","LanguageCodeSequenceTrial",true }, + {0x0040,0xa992,VR::ST,VM::VM1,"Uniform Resource Locator (Trial)","UniformResourceLocatorTrial",true }, + {0x0040,0xb020,VR::SQ,VM::VM1,"Waveform Annotation Sequence","WaveformAnnotationSequence",false }, + {0x0040,0xdb00,VR::CS,VM::VM1,"Template Identifier","TemplateIdentifier",false }, + {0x0040,0xdb06,VR::DT,VM::VM1,"Template Version","TemplateVersion",true }, + {0x0040,0xdb07,VR::DT,VM::VM1,"Template Local Version","TemplateLocalVersion",true }, + {0x0040,0xdb0b,VR::CS,VM::VM1,"Template Extension Flag","TemplateExtensionFlag",true }, + {0x0040,0xdb0c,VR::UI,VM::VM1,"Template Extension Organization UID","TemplateExtensionOrganizationUID",true }, + {0x0040,0xdb0d,VR::UI,VM::VM1,"Template Extension Creator UID","TemplateExtensionCreatorUID",true }, + {0x0040,0xdb73,VR::UL,VM::VM1_n,"Referenced Content Item Identifier","ReferencedContentItemIdentifier",false }, + {0x0040,0xe001,VR::ST,VM::VM1,"HL7 Instance Identifier","HL7InstanceIdentifier",false }, + {0x0040,0xe004,VR::DT,VM::VM1,"HL7 Document Effective Time","HL7DocumentEffectiveTime",false }, + {0x0040,0xe006,VR::SQ,VM::VM1,"HL7 Document Type Code Sequence","HL7DocumentTypeCodeSequence",false }, + {0x0040,0xe008,VR::SQ,VM::VM1,"Document Class Code Sequence","DocumentClassCodeSequence",false }, + {0x0040,0xe010,VR::UT,VM::VM1,"Retrieve URI","RetrieveURI",false }, + {0x0040,0xe011,VR::UI,VM::VM1,"Retrieve Location UID","RetrieveLocationUID",false }, + {0x0040,0xe020,VR::CS,VM::VM1,"Type of Instances","TypeOfInstances",false }, + {0x0040,0xe021,VR::SQ,VM::VM1,"DICOM Retrieval Sequence","DICOMRetrievalSequence",false }, + {0x0040,0xe022,VR::SQ,VM::VM1,"DICOM Media Retrieval Sequence","DICOMMediaRetrievalSequence",false }, + {0x0040,0xe023,VR::SQ,VM::VM1,"WADO Retrieval Sequence","WADORetrievalSequence",false }, + {0x0040,0xe024,VR::SQ,VM::VM1,"XDS Retrieval Sequence","XDSRetrievalSequence",false }, + {0x0040,0xe030,VR::UI,VM::VM1,"Repository Unique ID","RepositoryUniqueID",false }, + {0x0040,0xe031,VR::UI,VM::VM1,"Home Community ID","HomeCommunityID",false }, + {0x0042,0x0010,VR::ST,VM::VM1,"Document Title","DocumentTitle",false }, + {0x0042,0x0011,VR::OB,VM::VM1,"Encapsulated Document","EncapsulatedDocument",false }, + {0x0042,0x0012,VR::LO,VM::VM1,"MIME Type of Encapsulated Document","MIMETypeOfEncapsulatedDocument",false }, + {0x0042,0x0013,VR::SQ,VM::VM1,"Source Instance Sequence","SourceInstanceSequence",false }, + {0x0042,0x0014,VR::LO,VM::VM1_n,"List of MIME Types","ListOfMIMETypes",false }, + {0x0044,0x0001,VR::ST,VM::VM1,"Product Package Identifier","ProductPackageIdentifier",false }, + {0x0044,0x0002,VR::CS,VM::VM1,"Substance Administration Approval","SubstanceAdministrationApproval",false }, + {0x0044,0x0003,VR::LT,VM::VM1,"Approval Status Further Description","ApprovalStatusFurtherDescription",false }, + {0x0044,0x0004,VR::DT,VM::VM1,"Approval Status DateTime","ApprovalStatusDateTime",false }, + {0x0044,0x0007,VR::SQ,VM::VM1,"Product Type Code Sequence","ProductTypeCodeSequence",false }, + {0x0044,0x0008,VR::LO,VM::VM1_n,"Product Name","ProductName",false }, + {0x0044,0x0009,VR::LT,VM::VM1,"Product Description","ProductDescription",false }, + {0x0044,0x000a,VR::LO,VM::VM1,"Product Lot Identifier","ProductLotIdentifier",false }, + {0x0044,0x000b,VR::DT,VM::VM1,"Product Expiration DateTime","ProductExpirationDateTime",false }, + {0x0044,0x0010,VR::DT,VM::VM1,"Substance Administration DateTime","SubstanceAdministrationDateTime",false }, + {0x0044,0x0011,VR::LO,VM::VM1,"Substance Administration Notes","SubstanceAdministrationNotes",false }, + {0x0044,0x0012,VR::LO,VM::VM1,"Substance Administration Device ID","SubstanceAdministrationDeviceID",false }, + {0x0044,0x0013,VR::SQ,VM::VM1,"Product Parameter Sequence","ProductParameterSequence",false }, + {0x0044,0x0019,VR::SQ,VM::VM1,"Substance Administration Parameter Sequence","SubstanceAdministrationParameterSequence",false }, + {0x0046,0x0012,VR::LO,VM::VM1,"Lens Description","LensDescription",false }, + {0x0046,0x0014,VR::SQ,VM::VM1,"Right Lens Sequence","RightLensSequence",false }, + {0x0046,0x0015,VR::SQ,VM::VM1,"Left Lens Sequence","LeftLensSequence",false }, + {0x0046,0x0016,VR::SQ,VM::VM1,"Unspecified Laterality Lens Sequence","UnspecifiedLateralityLensSequence",false }, + {0x0046,0x0018,VR::SQ,VM::VM1,"Cylinder Sequence","CylinderSequence",false }, + {0x0046,0x0028,VR::SQ,VM::VM1,"Prism Sequence","PrismSequence",false }, + {0x0046,0x0030,VR::FD,VM::VM1,"Horizontal Prism Power","HorizontalPrismPower",false }, + {0x0046,0x0032,VR::CS,VM::VM1,"Horizontal Prism Base","HorizontalPrismBase",false }, + {0x0046,0x0034,VR::FD,VM::VM1,"Vertical Prism Power","VerticalPrismPower",false }, + {0x0046,0x0036,VR::CS,VM::VM1,"Vertical Prism Base","VerticalPrismBase",false }, + {0x0046,0x0038,VR::CS,VM::VM1,"Lens Segment Type","LensSegmentType",false }, + {0x0046,0x0040,VR::FD,VM::VM1,"Optical Transmittance","OpticalTransmittance",false }, + {0x0046,0x0042,VR::FD,VM::VM1,"Channel Width","ChannelWidth",false }, + {0x0046,0x0044,VR::FD,VM::VM1,"Pupil Size","PupilSize",false }, + {0x0046,0x0046,VR::FD,VM::VM1,"Corneal Size","CornealSize",false }, + {0x0046,0x0050,VR::SQ,VM::VM1,"Autorefraction Right Eye Sequence","AutorefractionRightEyeSequence",false }, + {0x0046,0x0052,VR::SQ,VM::VM1,"Autorefraction Left Eye Sequence","AutorefractionLeftEyeSequence",false }, + {0x0046,0x0060,VR::FD,VM::VM1,"Distance Pupillary Distance","DistancePupillaryDistance",false }, + {0x0046,0x0062,VR::FD,VM::VM1,"Near Pupillary Distance","NearPupillaryDistance",false }, + {0x0046,0x0063,VR::FD,VM::VM1,"Intermediate Pupillary Distance","IntermediatePupillaryDistance",false }, + {0x0046,0x0064,VR::FD,VM::VM1,"Other Pupillary Distance","OtherPupillaryDistance",false }, + {0x0046,0x0070,VR::SQ,VM::VM1,"Keratometry Right Eye Sequence","KeratometryRightEyeSequence",false }, + {0x0046,0x0071,VR::SQ,VM::VM1,"Keratometry Left Eye Sequence","KeratometryLeftEyeSequence",false }, + {0x0046,0x0074,VR::SQ,VM::VM1,"Steep Keratometric Axis Sequence","SteepKeratometricAxisSequence",false }, + {0x0046,0x0075,VR::FD,VM::VM1,"Radius of Curvature","RadiusOfCurvature",false }, + {0x0046,0x0076,VR::FD,VM::VM1,"Keratometric Power","KeratometricPower",false }, + {0x0046,0x0077,VR::FD,VM::VM1,"Keratometric Axis","KeratometricAxis",false }, + {0x0046,0x0080,VR::SQ,VM::VM1,"Flat Keratometric Axis Sequence","FlatKeratometricAxisSequence",false }, + {0x0046,0x0092,VR::CS,VM::VM1,"Background Color","BackgroundColor",false }, + {0x0046,0x0094,VR::CS,VM::VM1,"Optotype","Optotype",false }, + {0x0046,0x0095,VR::CS,VM::VM1,"Optotype Presentation","OptotypePresentation",false }, + {0x0046,0x0097,VR::SQ,VM::VM1,"Subjective Refraction Right Eye Sequence","SubjectiveRefractionRightEyeSequence",false }, + {0x0046,0x0098,VR::SQ,VM::VM1,"Subjective Refraction Left Eye Sequence","SubjectiveRefractionLeftEyeSequence",false }, + {0x0046,0x0100,VR::SQ,VM::VM1,"Add Near Sequence","AddNearSequence",false }, + {0x0046,0x0101,VR::SQ,VM::VM1,"Add Intermediate Sequence","AddIntermediateSequence",false }, + {0x0046,0x0102,VR::SQ,VM::VM1,"Add Other Sequence","AddOtherSequence",false }, + {0x0046,0x0104,VR::FD,VM::VM1,"Add Power","AddPower",false }, + {0x0046,0x0106,VR::FD,VM::VM1,"Viewing Distance","ViewingDistance",false }, + {0x0046,0x0121,VR::SQ,VM::VM1,"Visual Acuity Type Code Sequence","VisualAcuityTypeCodeSequence",false }, + {0x0046,0x0122,VR::SQ,VM::VM1,"Visual Acuity Right Eye Sequence","VisualAcuityRightEyeSequence",false }, + {0x0046,0x0123,VR::SQ,VM::VM1,"Visual Acuity Left Eye Sequence","VisualAcuityLeftEyeSequence",false }, + {0x0046,0x0124,VR::SQ,VM::VM1,"Visual Acuity Both Eyes Open Sequence","VisualAcuityBothEyesOpenSequence",false }, + {0x0046,0x0125,VR::CS,VM::VM1,"Viewing Distance Type","ViewingDistanceType",false }, + {0x0046,0x0135,VR::SS,VM::VM2,"Visual Acuity Modifiers","VisualAcuityModifiers",false }, + {0x0046,0x0137,VR::FD,VM::VM1,"Decimal Visual Acuity","DecimalVisualAcuity",false }, + {0x0046,0x0139,VR::LO,VM::VM1,"Optotype Detailed Definition","OptotypeDetailedDefinition",false }, + {0x0046,0x0145,VR::SQ,VM::VM1,"Referenced Refractive Measurements Sequence","ReferencedRefractiveMeasurementsSequence",false }, + {0x0046,0x0146,VR::FD,VM::VM1,"Sphere Power","SpherePower",false }, + {0x0046,0x0147,VR::FD,VM::VM1,"Cylinder Power","CylinderPower",false }, + {0x0048,0x0001,VR::FL,VM::VM1,"Imaged Volume Width","ImagedVolumeWidth",false }, + {0x0048,0x0002,VR::FL,VM::VM1,"Imaged Volume Height","ImagedVolumeHeight",false }, + {0x0048,0x0003,VR::FL,VM::VM1,"Imaged Volume Depth","ImagedVolumeDepth",false }, + {0x0048,0x0006,VR::UL,VM::VM1,"Total Pixel Matrix Columns","TotalPixelMatrixColumns",false }, + {0x0048,0x0007,VR::UL,VM::VM1,"Total Pixel Matrix Rows","TotalPixelMatrixRows",false }, + {0x0048,0x0008,VR::SQ,VM::VM1,"Total Pixel Matrix Origin Sequence","TotalPixelMatrixOriginSequence",false }, + {0x0048,0x0010,VR::CS,VM::VM1,"Specimen Label in Image","SpecimenLabelInImage",false }, + {0x0048,0x0011,VR::CS,VM::VM1,"Focus Method","FocusMethod",false }, + {0x0048,0x0012,VR::CS,VM::VM1,"Extended Depth of Field","ExtendedDepthOfField",false }, + {0x0048,0x0013,VR::US,VM::VM1,"Number of Focal Planes","NumberOfFocalPlanes",false }, + {0x0048,0x0014,VR::FL,VM::VM1,"Distance Between Focal Planes","DistanceBetweenFocalPlanes",false }, + {0x0048,0x0015,VR::US,VM::VM3,"Recommended Absent Pixel CIELab Value","RecommendedAbsentPixelCIELabValue",false }, + {0x0048,0x0100,VR::SQ,VM::VM1,"Illuminator Type Code Sequence","IlluminatorTypeCodeSequence",false }, + {0x0048,0x0102,VR::DS,VM::VM6,"Image Orientation (Slide)","ImageOrientationSlide",false }, + {0x0048,0x0105,VR::SQ,VM::VM1,"Optical Path Sequence","OpticalPathSequence",false }, + {0x0048,0x0106,VR::SH,VM::VM1,"Optical Path Identifier","OpticalPathIdentifier",false }, + {0x0048,0x0107,VR::ST,VM::VM1,"Optical Path Description","OpticalPathDescription",false }, + {0x0048,0x0108,VR::SQ,VM::VM1,"Illumination Color Code Sequence","IlluminationColorCodeSequence",false }, + {0x0048,0x0110,VR::SQ,VM::VM1,"Specimen Reference Sequence","SpecimenReferenceSequence",false }, + {0x0048,0x0111,VR::DS,VM::VM1,"Condenser Lens Power","CondenserLensPower",false }, + {0x0048,0x0112,VR::DS,VM::VM1,"Objective Lens Power","ObjectiveLensPower",false }, + {0x0048,0x0113,VR::DS,VM::VM1,"Objective Lens Numerical Aperture","ObjectiveLensNumericalAperture",false }, + {0x0048,0x0120,VR::SQ,VM::VM1,"Palette Color Lookup Table Sequence","PaletteColorLookupTableSequence",false }, + {0x0048,0x0200,VR::SQ,VM::VM1,"Referenced Image Navigation Sequence","ReferencedImageNavigationSequence",false }, + {0x0048,0x0201,VR::US,VM::VM2,"Top Left Hand Corner of Localizer Area","TopLeftHandCornerOfLocalizerArea",false }, + {0x0048,0x0202,VR::US,VM::VM2,"Bottom Right Hand Corner of Localizer Area","BottomRightHandCornerOfLocalizerArea",false }, + {0x0048,0x0207,VR::SQ,VM::VM1,"Optical Path Identification Sequence","OpticalPathIdentificationSequence",false }, + {0x0048,0x021a,VR::SQ,VM::VM1,"Plane Position (Slide) Sequence","PlanePositionSlideSequence",false }, + {0x0048,0x021e,VR::SL,VM::VM1,"Column Position In Total Image Pixel Matrix","ColumnPositionInTotalImagePixelMatrix",false }, + {0x0048,0x021f,VR::SL,VM::VM1,"Row Position In Total Image Pixel Matrix","RowPositionInTotalImagePixelMatrix",false }, + {0x0048,0x0301,VR::CS,VM::VM1,"Pixel Origin Interpretation","PixelOriginInterpretation",false }, + {0x0050,0x0004,VR::CS,VM::VM1,"Calibration Image","CalibrationImage",false }, + {0x0050,0x0010,VR::SQ,VM::VM1,"Device Sequence","DeviceSequence",false }, + {0x0050,0x0012,VR::SQ,VM::VM1,"Container Component Type Code Sequence","ContainerComponentTypeCodeSequence",false }, + {0x0050,0x0013,VR::FD,VM::VM1,"Container Component Thickness","ContainerComponentThickness",false }, + {0x0050,0x0014,VR::DS,VM::VM1,"Device Length","DeviceLength",false }, + {0x0050,0x0015,VR::FD,VM::VM1,"Container Component Width","ContainerComponentWidth",false }, + {0x0050,0x0016,VR::DS,VM::VM1,"Device Diameter","DeviceDiameter",false }, + {0x0050,0x0017,VR::CS,VM::VM1,"Device Diameter Units","DeviceDiameterUnits",false }, + {0x0050,0x0018,VR::DS,VM::VM1,"Device Volume","DeviceVolume",false }, + {0x0050,0x0019,VR::DS,VM::VM1,"Inter-Marker Distance","InterMarkerDistance",false }, + {0x0050,0x001a,VR::CS,VM::VM1,"Container Component Material","ContainerComponentMaterial",false }, + {0x0050,0x001b,VR::LO,VM::VM1,"Container Component ID","ContainerComponentID",false }, + {0x0050,0x001c,VR::FD,VM::VM1,"Container Component Length","ContainerComponentLength",false }, + {0x0050,0x001d,VR::FD,VM::VM1,"Container Component Diameter","ContainerComponentDiameter",false }, + {0x0050,0x001e,VR::LO,VM::VM1,"Container Component Description","ContainerComponentDescription",false }, + {0x0050,0x0020,VR::LO,VM::VM1,"Device Description","DeviceDescription",false }, + {0x0052,0x0001,VR::FL,VM::VM1,"Contrast/Bolus Ingredient Percent by Volume","ContrastBolusIngredientPercentByVolume",false }, + {0x0052,0x0002,VR::FD,VM::VM1,"OCT Focal Distance","OCTFocalDistance",false }, + {0x0052,0x0003,VR::FD,VM::VM1,"Beam Spot Size","BeamSpotSize",false }, + {0x0052,0x0004,VR::FD,VM::VM1,"Effective Refractive Index","EffectiveRefractiveIndex",false }, + {0x0052,0x0006,VR::CS,VM::VM1,"OCT Acquisition Domain","OCTAcquisitionDomain",false }, + {0x0052,0x0007,VR::FD,VM::VM1,"OCT Optical Center Wavelength","OCTOpticalCenterWavelength",false }, + {0x0052,0x0008,VR::FD,VM::VM1,"Axial Resolution","AxialResolution",false }, + {0x0052,0x0009,VR::FD,VM::VM1,"Ranging Depth","RangingDepth",false }, + {0x0052,0x0011,VR::FD,VM::VM1,"A-line Rate","ALineRate",false }, + {0x0052,0x0012,VR::US,VM::VM1,"A-lines Per Frame","ALinesPerFrame",false }, + {0x0052,0x0013,VR::FD,VM::VM1,"Catheter Rotational Rate","CatheterRotationalRate",false }, + {0x0052,0x0014,VR::FD,VM::VM1,"A-line Pixel Spacing","ALinePixelSpacing",false }, + {0x0052,0x0016,VR::SQ,VM::VM1,"Mode of Percutaneous Access Sequence","ModeOfPercutaneousAccessSequence",false }, + {0x0052,0x0025,VR::SQ,VM::VM1,"Intravascular OCT Frame Type Sequence","IntravascularOCTFrameTypeSequence",false }, + {0x0052,0x0026,VR::CS,VM::VM1,"OCT Z Offset Applied","OCTZOffsetApplied",false }, + {0x0052,0x0027,VR::SQ,VM::VM1,"Intravascular Frame Content Sequence","IntravascularFrameContentSequence",false }, + {0x0052,0x0028,VR::FD,VM::VM1,"Intravascular Longitudinal Distance","IntravascularLongitudinalDistance",false }, + {0x0052,0x0029,VR::SQ,VM::VM1,"Intravascular OCT Frame Content Sequence","IntravascularOCTFrameContentSequence",false }, + {0x0052,0x0030,VR::SS,VM::VM1,"OCT Z Offset Correction","OCTZOffsetCorrection",false }, + {0x0052,0x0031,VR::CS,VM::VM1,"Catheter Direction of Rotation","CatheterDirectionOfRotation",false }, + {0x0052,0x0033,VR::FD,VM::VM1,"Seam Line Location","SeamLineLocation",false }, + {0x0052,0x0034,VR::FD,VM::VM1,"First A-line Location","FirstALineLocation",false }, + {0x0052,0x0036,VR::US,VM::VM1,"Seam Line Index","SeamLineIndex",false }, + {0x0052,0x0038,VR::US,VM::VM1,"Number of Padded A-lines","NumberOfPaddedAlines",false }, + {0x0052,0x0039,VR::CS,VM::VM1,"Interpolation Type","InterpolationType",false }, + {0x0052,0x003a,VR::CS,VM::VM1,"Refractive Index Applied","RefractiveIndexApplied",false }, + {0x0054,0x0010,VR::US,VM::VM1_n,"Energy Window Vector","EnergyWindowVector",false }, + {0x0054,0x0011,VR::US,VM::VM1,"Number of Energy Windows","NumberOfEnergyWindows",false }, + {0x0054,0x0012,VR::SQ,VM::VM1,"Energy Window Information Sequence","EnergyWindowInformationSequence",false }, + {0x0054,0x0013,VR::SQ,VM::VM1,"Energy Window Range Sequence","EnergyWindowRangeSequence",false }, + {0x0054,0x0014,VR::DS,VM::VM1,"Energy Window Lower Limit","EnergyWindowLowerLimit",false }, + {0x0054,0x0015,VR::DS,VM::VM1,"Energy Window Upper Limit","EnergyWindowUpperLimit",false }, + {0x0054,0x0016,VR::SQ,VM::VM1,"Radiopharmaceutical Information Sequence","RadiopharmaceuticalInformationSequence",false }, + {0x0054,0x0017,VR::IS,VM::VM1,"Residual Syringe Counts","ResidualSyringeCounts",false }, + {0x0054,0x0018,VR::SH,VM::VM1,"Energy Window Name","EnergyWindowName",false }, + {0x0054,0x0020,VR::US,VM::VM1_n,"Detector Vector","DetectorVector",false }, + {0x0054,0x0021,VR::US,VM::VM1,"Number of Detectors","NumberOfDetectors",false }, + {0x0054,0x0022,VR::SQ,VM::VM1,"Detector Information Sequence","DetectorInformationSequence",false }, + {0x0054,0x0030,VR::US,VM::VM1_n,"Phase Vector","PhaseVector",false }, + {0x0054,0x0031,VR::US,VM::VM1,"Number of Phases","NumberOfPhases",false }, + {0x0054,0x0032,VR::SQ,VM::VM1,"Phase Information Sequence","PhaseInformationSequence",false }, + {0x0054,0x0033,VR::US,VM::VM1,"Number of Frames in Phase","NumberOfFramesInPhase",false }, + {0x0054,0x0036,VR::IS,VM::VM1,"Phase Delay","PhaseDelay",false }, + {0x0054,0x0038,VR::IS,VM::VM1,"Pause Between Frames","PauseBetweenFrames",false }, + {0x0054,0x0039,VR::CS,VM::VM1,"Phase Description","PhaseDescription",false }, + {0x0054,0x0050,VR::US,VM::VM1_n,"Rotation Vector","RotationVector",false }, + {0x0054,0x0051,VR::US,VM::VM1,"Number of Rotations","NumberOfRotations",false }, + {0x0054,0x0052,VR::SQ,VM::VM1,"Rotation Information Sequence","RotationInformationSequence",false }, + {0x0054,0x0053,VR::US,VM::VM1,"Number of Frames in Rotation","NumberOfFramesInRotation",false }, + {0x0054,0x0060,VR::US,VM::VM1_n,"R-R Interval Vector","RRIntervalVector",false }, + {0x0054,0x0061,VR::US,VM::VM1,"Number of R-R Intervals","NumberOfRRIntervals",false }, + {0x0054,0x0062,VR::SQ,VM::VM1,"Gated Information Sequence","GatedInformationSequence",false }, + {0x0054,0x0063,VR::SQ,VM::VM1,"Data Information Sequence","DataInformationSequence",false }, + {0x0054,0x0070,VR::US,VM::VM1_n,"Time Slot Vector","TimeSlotVector",false }, + {0x0054,0x0071,VR::US,VM::VM1,"Number of Time Slots","NumberOfTimeSlots",false }, + {0x0054,0x0072,VR::SQ,VM::VM1,"Time Slot Information Sequence","TimeSlotInformationSequence",false }, + {0x0054,0x0073,VR::DS,VM::VM1,"Time Slot Time","TimeSlotTime",false }, + {0x0054,0x0080,VR::US,VM::VM1_n,"Slice Vector","SliceVector",false }, + {0x0054,0x0081,VR::US,VM::VM1,"Number of Slices","NumberOfSlices",false }, + {0x0054,0x0090,VR::US,VM::VM1_n,"Angular View Vector","AngularViewVector",false }, + {0x0054,0x0100,VR::US,VM::VM1_n,"Time Slice Vector","TimeSliceVector",false }, + {0x0054,0x0101,VR::US,VM::VM1,"Number of Time Slices","NumberOfTimeSlices",false }, + {0x0054,0x0200,VR::DS,VM::VM1,"Start Angle","StartAngle",false }, + {0x0054,0x0202,VR::CS,VM::VM1,"Type of Detector Motion","TypeOfDetectorMotion",false }, + {0x0054,0x0210,VR::IS,VM::VM1_n,"Trigger Vector","TriggerVector",false }, + {0x0054,0x0211,VR::US,VM::VM1,"Number of Triggers in Phase","NumberOfTriggersInPhase",false }, + {0x0054,0x0220,VR::SQ,VM::VM1,"View Code Sequence","ViewCodeSequence",false }, + {0x0054,0x0222,VR::SQ,VM::VM1,"View Modifier Code Sequence","ViewModifierCodeSequence",false }, + {0x0054,0x0300,VR::SQ,VM::VM1,"Radionuclide Code Sequence","RadionuclideCodeSequence",false }, + {0x0054,0x0302,VR::SQ,VM::VM1,"Administration Route Code Sequence","AdministrationRouteCodeSequence",false }, + {0x0054,0x0304,VR::SQ,VM::VM1,"Radiopharmaceutical Code Sequence","RadiopharmaceuticalCodeSequence",false }, + {0x0054,0x0306,VR::SQ,VM::VM1,"Calibration Data Sequence","CalibrationDataSequence",false }, + {0x0054,0x0308,VR::US,VM::VM1,"Energy Window Number","EnergyWindowNumber",false }, + {0x0054,0x0400,VR::SH,VM::VM1,"Image ID","ImageID",false }, + {0x0054,0x0410,VR::SQ,VM::VM1,"Patient Orientation Code Sequence","PatientOrientationCodeSequence",false }, + {0x0054,0x0412,VR::SQ,VM::VM1,"Patient Orientation Modifier Code Sequence","PatientOrientationModifierCodeSequence",false }, + {0x0054,0x0414,VR::SQ,VM::VM1,"Patient Gantry Relationship Code Sequence","PatientGantryRelationshipCodeSequence",false }, + {0x0054,0x0500,VR::CS,VM::VM1,"Slice Progression Direction","SliceProgressionDirection",false }, + {0x0054,0x1000,VR::CS,VM::VM2,"Series Type","SeriesType",false }, + {0x0054,0x1001,VR::CS,VM::VM1,"Units","Units",false }, + {0x0054,0x1002,VR::CS,VM::VM1,"Counts Source","CountsSource",false }, + {0x0054,0x1004,VR::CS,VM::VM1,"Reprojection Method","ReprojectionMethod",false }, + {0x0054,0x1006,VR::CS,VM::VM1,"SUV Type","SUVType",false }, + {0x0054,0x1100,VR::CS,VM::VM1,"Randoms Correction Method","RandomsCorrectionMethod",false }, + {0x0054,0x1101,VR::LO,VM::VM1,"Attenuation Correction Method","AttenuationCorrectionMethod",false }, + {0x0054,0x1102,VR::CS,VM::VM1,"Decay Correction","DecayCorrection",false }, + {0x0054,0x1103,VR::LO,VM::VM1,"Reconstruction Method","ReconstructionMethod",false }, + {0x0054,0x1104,VR::LO,VM::VM1,"Detector Lines of Response Used","DetectorLinesOfResponseUsed",false }, + {0x0054,0x1105,VR::LO,VM::VM1,"Scatter Correction Method","ScatterCorrectionMethod",false }, + {0x0054,0x1200,VR::DS,VM::VM1,"Axial Acceptance","AxialAcceptance",false }, + {0x0054,0x1201,VR::IS,VM::VM2,"Axial Mash","AxialMash",false }, + {0x0054,0x1202,VR::IS,VM::VM1,"Transverse Mash","TransverseMash",false }, + {0x0054,0x1203,VR::DS,VM::VM2,"Detector Element Size","DetectorElementSize",false }, + {0x0054,0x1210,VR::DS,VM::VM1,"Coincidence Window Width","CoincidenceWindowWidth",false }, + {0x0054,0x1220,VR::CS,VM::VM1_n,"Secondary Counts Type","SecondaryCountsType",false }, + {0x0054,0x1300,VR::DS,VM::VM1,"Frame Reference Time","FrameReferenceTime",false }, + {0x0054,0x1310,VR::IS,VM::VM1,"Primary (Prompts) Counts Accumulated","PrimaryPromptsCountsAccumulated",false }, + {0x0054,0x1311,VR::IS,VM::VM1_n,"Secondary Counts Accumulated","SecondaryCountsAccumulated",false }, + {0x0054,0x1320,VR::DS,VM::VM1,"Slice Sensitivity Factor","SliceSensitivityFactor",false }, + {0x0054,0x1321,VR::DS,VM::VM1,"Decay Factor","DecayFactor",false }, + {0x0054,0x1322,VR::DS,VM::VM1,"Dose Calibration Factor","DoseCalibrationFactor",false }, + {0x0054,0x1323,VR::DS,VM::VM1,"Scatter Fraction Factor","ScatterFractionFactor",false }, + {0x0054,0x1324,VR::DS,VM::VM1,"Dead Time Factor","DeadTimeFactor",false }, + {0x0054,0x1330,VR::US,VM::VM1,"Image Index","ImageIndex",false }, + {0x0054,0x1400,VR::CS,VM::VM1_n,"Counts Included","CountsIncluded",true }, + {0x0054,0x1401,VR::CS,VM::VM1,"Dead Time Correction Flag","DeadTimeCorrectionFlag",true }, + {0x0060,0x3000,VR::SQ,VM::VM1,"Histogram Sequence","HistogramSequence",false }, + {0x0060,0x3002,VR::US,VM::VM1,"Histogram Number of Bins","HistogramNumberOfBins",false }, + {0x0060,0x3004,VR::US_SS,VM::VM1,"Histogram First Bin Value","HistogramFirstBinValue",false }, + {0x0060,0x3006,VR::US_SS,VM::VM1,"Histogram Last Bin Value","HistogramLastBinValue",false }, + {0x0060,0x3008,VR::US,VM::VM1,"Histogram Bin Width","HistogramBinWidth",false }, + {0x0060,0x3010,VR::LO,VM::VM1,"Histogram Explanation","HistogramExplanation",false }, + {0x0060,0x3020,VR::UL,VM::VM1_n,"Histogram Data","HistogramData",false }, + {0x0062,0x0001,VR::CS,VM::VM1,"Segmentation Type","SegmentationType",false }, + {0x0062,0x0002,VR::SQ,VM::VM1,"Segment Sequence","SegmentSequence",false }, + {0x0062,0x0003,VR::SQ,VM::VM1,"Segmented Property Category Code Sequence","SegmentedPropertyCategoryCodeSequence",false }, + {0x0062,0x0004,VR::US,VM::VM1,"Segment Number","SegmentNumber",false }, + {0x0062,0x0005,VR::LO,VM::VM1,"Segment Label","SegmentLabel",false }, + {0x0062,0x0006,VR::ST,VM::VM1,"Segment Description","SegmentDescription",false }, + {0x0062,0x0008,VR::CS,VM::VM1,"Segment Algorithm Type","SegmentAlgorithmType",false }, + {0x0062,0x0009,VR::LO,VM::VM1,"Segment Algorithm Name","SegmentAlgorithmName",false }, + {0x0062,0x000a,VR::SQ,VM::VM1,"Segment Identification Sequence","SegmentIdentificationSequence",false }, + {0x0062,0x000b,VR::US,VM::VM1_n,"Referenced Segment Number","ReferencedSegmentNumber",false }, + {0x0062,0x000c,VR::US,VM::VM1,"Recommended Display Grayscale Value","RecommendedDisplayGrayscaleValue",false }, + {0x0062,0x000d,VR::US,VM::VM3,"Recommended Display CIELab Value","RecommendedDisplayCIELabValue",false }, + {0x0062,0x000e,VR::US,VM::VM1,"Maximum Fractional Value","MaximumFractionalValue",false }, + {0x0062,0x000f,VR::SQ,VM::VM1,"Segmented Property Type Code Sequence","SegmentedPropertyTypeCodeSequence",false }, + {0x0062,0x0010,VR::CS,VM::VM1,"Segmentation Fractional Type","SegmentationFractionalType",false }, + {0x0064,0x0002,VR::SQ,VM::VM1,"Deformable Registration Sequence","DeformableRegistrationSequence",false }, + {0x0064,0x0003,VR::UI,VM::VM1,"Source Frame of Reference UID","SourceFrameOfReferenceUID",false }, + {0x0064,0x0005,VR::SQ,VM::VM1,"Deformable Registration Grid Sequence","DeformableRegistrationGridSequence",false }, + {0x0064,0x0007,VR::UL,VM::VM3,"Grid Dimensions","GridDimensions",false }, + {0x0064,0x0008,VR::FD,VM::VM3,"Grid Resolution","GridResolution",false }, + {0x0064,0x0009,VR::OF,VM::VM1,"Vector Grid Data","VectorGridData",false }, + {0x0064,0x000f,VR::SQ,VM::VM1,"Pre Deformation Matrix Registration Sequence","PreDeformationMatrixRegistrationSequence",false }, + {0x0064,0x0010,VR::SQ,VM::VM1,"Post Deformation Matrix Registration Sequence","PostDeformationMatrixRegistrationSequence",false }, + {0x0066,0x0001,VR::UL,VM::VM1,"Number of Surfaces","NumberOfSurfaces",false }, + {0x0066,0x0002,VR::SQ,VM::VM1,"Surface Sequence","SurfaceSequence",false }, + {0x0066,0x0003,VR::UL,VM::VM1,"Surface Number","SurfaceNumber",false }, + {0x0066,0x0004,VR::LT,VM::VM1,"Surface Comments","SurfaceComments",false }, + {0x0066,0x0009,VR::CS,VM::VM1,"Surface Processing","SurfaceProcessing",false }, + {0x0066,0x000a,VR::FL,VM::VM1,"Surface Processing Ratio","SurfaceProcessingRatio",false }, + {0x0066,0x000b,VR::LO,VM::VM1,"Surface Processing Description","SurfaceProcessingDescription",false }, + {0x0066,0x000c,VR::FL,VM::VM1,"Recommended Presentation Opacity","RecommendedPresentationOpacity",false }, + {0x0066,0x000d,VR::CS,VM::VM1,"Recommended Presentation Type","RecommendedPresentationType",false }, + {0x0066,0x000e,VR::CS,VM::VM1,"Finite Volume","FiniteVolume",false }, + {0x0066,0x0010,VR::CS,VM::VM1,"Manifold","Manifold",false }, + {0x0066,0x0011,VR::SQ,VM::VM1,"Surface Points Sequence","SurfacePointsSequence",false }, + {0x0066,0x0012,VR::SQ,VM::VM1,"Surface Points Normals Sequence","SurfacePointsNormalsSequence",false }, + {0x0066,0x0013,VR::SQ,VM::VM1,"Surface Mesh Primitives Sequence","SurfaceMeshPrimitivesSequence",false }, + {0x0066,0x0015,VR::UL,VM::VM1,"Number of Surface Points","NumberOfSurfacePoints",false }, + {0x0066,0x0016,VR::OF,VM::VM1,"Point Coordinates Data","PointCoordinatesData",false }, + {0x0066,0x0017,VR::FL,VM::VM3,"Point Position Accuracy","PointPositionAccuracy",false }, + {0x0066,0x0018,VR::FL,VM::VM1,"Mean Point Distance","MeanPointDistance",false }, + {0x0066,0x0019,VR::FL,VM::VM1,"Maximum Point Distance","MaximumPointDistance",false }, + {0x0066,0x001a,VR::FL,VM::VM6,"Points Bounding Box Coordinates","PointsBoundingBoxCoordinates",false }, + {0x0066,0x001b,VR::FL,VM::VM3,"Axis of Rotation","AxisOfRotation",false }, + {0x0066,0x001c,VR::FL,VM::VM3,"Center of Rotation","CenterOfRotation",false }, + {0x0066,0x001e,VR::UL,VM::VM1,"Number of Vectors","NumberOfVectors",false }, + {0x0066,0x001f,VR::US,VM::VM1,"Vector Dimensionality","VectorDimensionality",false }, + {0x0066,0x0020,VR::FL,VM::VM1_n,"Vector Accuracy","VectorAccuracy",false }, + {0x0066,0x0021,VR::OF,VM::VM1,"Vector Coordinate Data","VectorCoordinateData",false }, + {0x0066,0x0023,VR::OW,VM::VM1,"Triangle Point Index List","TrianglePointIndexList",false }, + {0x0066,0x0024,VR::OW,VM::VM1,"Edge Point Index List","EdgePointIndexList",false }, + {0x0066,0x0025,VR::OW,VM::VM1,"Vertex Point Index List","VertexPointIndexList",false }, + {0x0066,0x0026,VR::SQ,VM::VM1,"Triangle Strip Sequence","TriangleStripSequence",false }, + {0x0066,0x0027,VR::SQ,VM::VM1,"Triangle Fan Sequence","TriangleFanSequence",false }, + {0x0066,0x0028,VR::SQ,VM::VM1,"Line Sequence","LineSequence",false }, + {0x0066,0x0029,VR::OW,VM::VM1,"Primitive Point Index List","PrimitivePointIndexList",false }, + {0x0066,0x002a,VR::UL,VM::VM1,"Surface Count","SurfaceCount",false }, + {0x0066,0x002b,VR::SQ,VM::VM1,"Referenced Surface Sequence","ReferencedSurfaceSequence",false }, + {0x0066,0x002c,VR::UL,VM::VM1,"Referenced Surface Number","ReferencedSurfaceNumber",false }, + {0x0066,0x002d,VR::SQ,VM::VM1,"Segment Surface Generation Algorithm Identification Sequence","SegmentSurfaceGenerationAlgorithmIdentificationSequence",false }, + {0x0066,0x002e,VR::SQ,VM::VM1,"Segment Surface Source Instance Sequence","SegmentSurfaceSourceInstanceSequence",false }, + {0x0066,0x002f,VR::SQ,VM::VM1,"Algorithm Family Code Sequence","AlgorithmFamilyCodeSequence",false }, + {0x0066,0x0030,VR::SQ,VM::VM1,"Algorithm Name Code Sequence","AlgorithmNameCodeSequence",false }, + {0x0066,0x0031,VR::LO,VM::VM1,"Algorithm Version","AlgorithmVersion",false }, + {0x0066,0x0032,VR::LT,VM::VM1,"Algorithm Parameters","AlgorithmParameters",false }, + {0x0066,0x0034,VR::SQ,VM::VM1,"Facet Sequence","FacetSequence",false }, + {0x0066,0x0035,VR::SQ,VM::VM1,"Surface Processing Algorithm Identification Sequence","SurfaceProcessingAlgorithmIdentificationSequence",false }, + {0x0066,0x0036,VR::LO,VM::VM1,"Algorithm Name","AlgorithmName",false }, + {0x0068,0x6210,VR::LO,VM::VM1,"Implant Size","ImplantSize",false }, + {0x0068,0x6221,VR::LO,VM::VM1,"Implant Template Version","ImplantTemplateVersion",false }, + {0x0068,0x6222,VR::SQ,VM::VM1,"Replaced Implant Template Sequence","ReplacedImplantTemplateSequence",false }, + {0x0068,0x6223,VR::CS,VM::VM1,"Implant Type","ImplantType",false }, + {0x0068,0x6224,VR::SQ,VM::VM1,"Derivation Implant Template Sequence","DerivationImplantTemplateSequence",false }, + {0x0068,0x6225,VR::SQ,VM::VM1,"Original Implant Template Sequence","OriginalImplantTemplateSequence",false }, + {0x0068,0x6226,VR::DT,VM::VM1,"Effective DateTime","EffectiveDateTime",false }, + {0x0068,0x6230,VR::SQ,VM::VM1,"Implant Target Anatomy Sequence","ImplantTargetAnatomySequence",false }, + {0x0068,0x6260,VR::SQ,VM::VM1,"Information From Manufacturer Sequence","InformationFromManufacturerSequence",false }, + {0x0068,0x6265,VR::SQ,VM::VM1,"Notification From Manufacturer Sequence","NotificationFromManufacturerSequence",false }, + {0x0068,0x6270,VR::DT,VM::VM1,"Information Issue DateTime","InformationIssueDateTime",false }, + {0x0068,0x6280,VR::ST,VM::VM1,"Information Summary","InformationSummary",false }, + {0x0068,0x62a0,VR::SQ,VM::VM1,"Implant Regulatory Disapproval Code Sequence","ImplantRegulatoryDisapprovalCodeSequence",false }, + {0x0068,0x62a5,VR::FD,VM::VM1,"Overall Template Spatial Tolerance","OverallTemplateSpatialTolerance",false }, + {0x0068,0x62c0,VR::SQ,VM::VM1,"HPGL Document Sequence","HPGLDocumentSequence",false }, + {0x0068,0x62d0,VR::US,VM::VM1,"HPGL Document ID","HPGLDocumentID",false }, + {0x0068,0x62d5,VR::LO,VM::VM1,"HPGL Document Label","HPGLDocumentLabel",false }, + {0x0068,0x62e0,VR::SQ,VM::VM1,"View Orientation Code Sequence","ViewOrientationCodeSequence",false }, + {0x0068,0x62f0,VR::FD,VM::VM9,"View Orientation Modifier","ViewOrientationModifier",false }, + {0x0068,0x62f2,VR::FD,VM::VM1,"HPGL Document Scaling","HPGLDocumentScaling",false }, + {0x0068,0x6300,VR::OB,VM::VM1,"HPGL Document","HPGLDocument",false }, + {0x0068,0x6310,VR::US,VM::VM1,"HPGL Contour Pen Number","HPGLContourPenNumber",false }, + {0x0068,0x6320,VR::SQ,VM::VM1,"HPGL Pen Sequence","HPGLPenSequence",false }, + {0x0068,0x6330,VR::US,VM::VM1,"HPGL Pen Number","HPGLPenNumber",false }, + {0x0068,0x6340,VR::LO,VM::VM1,"HPGL Pen Label","HPGLPenLabel",false }, + {0x0068,0x6345,VR::ST,VM::VM1,"HPGL Pen Description","HPGLPenDescription",false }, + {0x0068,0x6346,VR::FD,VM::VM2,"Recommended Rotation Point","RecommendedRotationPoint",false }, + {0x0068,0x6347,VR::FD,VM::VM4,"Bounding Rectangle","BoundingRectangle",false }, + {0x0068,0x6350,VR::US,VM::VM1_n,"Implant Template 3D Model Surface Number","ImplantTemplate3DModelSurfaceNumber",false }, + {0x0068,0x6360,VR::SQ,VM::VM1,"Surface Model Description Sequence","SurfaceModelDescriptionSequence",false }, + {0x0068,0x6380,VR::LO,VM::VM1,"Surface Model Label","SurfaceModelLabel",false }, + {0x0068,0x6390,VR::FD,VM::VM1,"Surface Model Scaling Factor","SurfaceModelScalingFactor",false }, + {0x0068,0x63a0,VR::SQ,VM::VM1,"Materials Code Sequence","MaterialsCodeSequence",false }, + {0x0068,0x63a4,VR::SQ,VM::VM1,"Coating Materials Code Sequence","CoatingMaterialsCodeSequence",false }, + {0x0068,0x63a8,VR::SQ,VM::VM1,"Implant Type Code Sequence","ImplantTypeCodeSequence",false }, + {0x0068,0x63ac,VR::SQ,VM::VM1,"Fixation Method Code Sequence","FixationMethodCodeSequence",false }, + {0x0068,0x63b0,VR::SQ,VM::VM1,"Mating Feature Sets Sequence","MatingFeatureSetsSequence",false }, + {0x0068,0x63c0,VR::US,VM::VM1,"Mating Feature Set ID","MatingFeatureSetID",false }, + {0x0068,0x63d0,VR::LO,VM::VM1,"Mating Feature Set Label","MatingFeatureSetLabel",false }, + {0x0068,0x63e0,VR::SQ,VM::VM1,"Mating Feature Sequence","MatingFeatureSequence",false }, + {0x0068,0x63f0,VR::US,VM::VM1,"Mating Feature ID","MatingFeatureID",false }, + {0x0068,0x6400,VR::SQ,VM::VM1,"Mating Feature Degree of Freedom Sequence","MatingFeatureDegreeOfFreedomSequence",false }, + {0x0068,0x6410,VR::US,VM::VM1,"Degree of Freedom ID","DegreeOfFreedomID",false }, + {0x0068,0x6420,VR::CS,VM::VM1,"Degree of Freedom Type","DegreeOfFreedomType",false }, + {0x0068,0x6430,VR::SQ,VM::VM1,"2D Mating Feature Coordinates Sequence","TwoDMatingFeatureCoordinatesSequence",false }, + {0x0068,0x6440,VR::US,VM::VM1,"Referenced HPGL Document ID","ReferencedHPGLDocumentID",false }, + {0x0068,0x6450,VR::FD,VM::VM2,"2D Mating Point","TwoDMatingPoint",false }, + {0x0068,0x6460,VR::FD,VM::VM4,"2D Mating Axes","TwoDMatingAxes",false }, + {0x0068,0x6470,VR::SQ,VM::VM1,"2D Degree of Freedom Sequence","TwoDDegreeOfFreedomSequence",false }, + {0x0068,0x6490,VR::FD,VM::VM3,"3D Degree of Freedom Axis","ThreeDDegreeOfFreedomAxis",false }, + {0x0068,0x64a0,VR::FD,VM::VM2,"Range of Freedom","RangeOfFreedom",false }, + {0x0068,0x64c0,VR::FD,VM::VM3,"3D Mating Point","ThreeDMatingPoint",false }, + {0x0068,0x64d0,VR::FD,VM::VM9,"3D Mating Axes","ThreeDMatingAxes",false }, + {0x0068,0x64f0,VR::FD,VM::VM3,"2D Degree of Freedom Axis","TwoDDegreeOfFreedomAxis",false }, + {0x0068,0x6500,VR::SQ,VM::VM1,"Planning Landmark Point Sequence","PlanningLandmarkPointSequence",false }, + {0x0068,0x6510,VR::SQ,VM::VM1,"Planning Landmark Line Sequence","PlanningLandmarkLineSequence",false }, + {0x0068,0x6520,VR::SQ,VM::VM1,"Planning Landmark Plane Sequence","PlanningLandmarkPlaneSequence",false }, + {0x0068,0x6530,VR::US,VM::VM1,"Planning Landmark ID","PlanningLandmarkID",false }, + {0x0068,0x6540,VR::LO,VM::VM1,"Planning Landmark Description","PlanningLandmarkDescription",false }, + {0x0068,0x6545,VR::SQ,VM::VM1,"Planning Landmark Identification Code Sequence","PlanningLandmarkIdentificationCodeSequence",false }, + {0x0068,0x6550,VR::SQ,VM::VM1,"2D Point Coordinates Sequence","TwoDPointCoordinatesSequence",false }, + {0x0068,0x6560,VR::FD,VM::VM2,"2D Point Coordinates","TwoDPointCoordinates",false }, + {0x0068,0x6590,VR::FD,VM::VM3,"3D Point Coordinates","ThreeDPointCoordinates",false }, + {0x0068,0x65a0,VR::SQ,VM::VM1,"2D Line Coordinates Sequence","TwoDLineCoordinatesSequence",false }, + {0x0068,0x65b0,VR::FD,VM::VM4,"2D Line Coordinates","TwoDLineCoordinates",false }, + {0x0068,0x65d0,VR::FD,VM::VM6,"3D Line Coordinates","ThreeDLineCoordinates",false }, + {0x0068,0x65e0,VR::SQ,VM::VM1,"2D Plane Coordinates Sequence","TwoDPlaneCoordinatesSequence",false }, + {0x0068,0x65f0,VR::FD,VM::VM4,"2D Plane Intersection","TwoDPlaneIntersection",false }, + {0x0068,0x6610,VR::FD,VM::VM3,"3D Plane Origin","ThreeDPlaneOrigin",false }, + {0x0068,0x6620,VR::FD,VM::VM3,"3D Plane Normal","ThreeDPlaneNormal",false }, + {0x0070,0x0001,VR::SQ,VM::VM1,"Graphic Annotation Sequence","GraphicAnnotationSequence",false }, + {0x0070,0x0002,VR::CS,VM::VM1,"Graphic Layer","GraphicLayer",false }, + {0x0070,0x0003,VR::CS,VM::VM1,"Bounding Box Annotation Units","BoundingBoxAnnotationUnits",false }, + {0x0070,0x0004,VR::CS,VM::VM1,"Anchor Point Annotation Units","AnchorPointAnnotationUnits",false }, + {0x0070,0x0005,VR::CS,VM::VM1,"Graphic Annotation Units","GraphicAnnotationUnits",false }, + {0x0070,0x0006,VR::ST,VM::VM1,"Unformatted Text Value","UnformattedTextValue",false }, + {0x0070,0x0008,VR::SQ,VM::VM1,"Text Object Sequence","TextObjectSequence",false }, + {0x0070,0x0009,VR::SQ,VM::VM1,"Graphic Object Sequence","GraphicObjectSequence",false }, + {0x0070,0x0010,VR::FL,VM::VM2,"Bounding Box Top Left Hand Corner","BoundingBoxTopLeftHandCorner",false }, + {0x0070,0x0011,VR::FL,VM::VM2,"Bounding Box Bottom Right Hand Corner","BoundingBoxBottomRightHandCorner",false }, + {0x0070,0x0012,VR::CS,VM::VM1,"Bounding Box Text Horizontal Justification","BoundingBoxTextHorizontalJustification",false }, + {0x0070,0x0014,VR::FL,VM::VM2,"Anchor Point","AnchorPoint",false }, + {0x0070,0x0015,VR::CS,VM::VM1,"Anchor Point Visibility","AnchorPointVisibility",false }, + {0x0070,0x0020,VR::US,VM::VM1,"Graphic Dimensions","GraphicDimensions",false }, + {0x0070,0x0021,VR::US,VM::VM1,"Number of Graphic Points","NumberOfGraphicPoints",false }, + {0x0070,0x0022,VR::FL,VM::VM2_n,"Graphic Data","GraphicData",false }, + {0x0070,0x0023,VR::CS,VM::VM1,"Graphic Type","GraphicType",false }, + {0x0070,0x0024,VR::CS,VM::VM1,"Graphic Filled","GraphicFilled",false }, + {0x0070,0x0040,VR::IS,VM::VM1,"Image Rotation (Retired)","ImageRotationRetired",true }, + {0x0070,0x0041,VR::CS,VM::VM1,"Image Horizontal Flip","ImageHorizontalFlip",false }, + {0x0070,0x0042,VR::US,VM::VM1,"Image Rotation","ImageRotation",false }, + {0x0070,0x0050,VR::US,VM::VM2,"Displayed Area Top Left Hand Corner (Trial)","DisplayedAreaTopLeftHandCornerTrial",true }, + {0x0070,0x0051,VR::US,VM::VM2,"Displayed Area Bottom Right Hand Corner (Trial)","DisplayedAreaBottomRightHandCornerTrial",true }, + {0x0070,0x0052,VR::SL,VM::VM2,"Displayed Area Top Left Hand Corner","DisplayedAreaTopLeftHandCorner",false }, + {0x0070,0x0053,VR::SL,VM::VM2,"Displayed Area Bottom Right Hand Corner","DisplayedAreaBottomRightHandCorner",false }, + {0x0070,0x005a,VR::SQ,VM::VM1,"Displayed Area Selection Sequence","DisplayedAreaSelectionSequence",false }, + {0x0070,0x0060,VR::SQ,VM::VM1,"Graphic Layer Sequence","GraphicLayerSequence",false }, + {0x0070,0x0062,VR::IS,VM::VM1,"Graphic Layer Order","GraphicLayerOrder",false }, + {0x0070,0x0066,VR::US,VM::VM1,"Graphic Layer Recommended Display Grayscale Value","GraphicLayerRecommendedDisplayGrayscaleValue",false }, + {0x0070,0x0067,VR::US,VM::VM3,"Graphic Layer Recommended Display RGB Value","GraphicLayerRecommendedDisplayRGBValue",true }, + {0x0070,0x0068,VR::LO,VM::VM1,"Graphic Layer Description","GraphicLayerDescription",false }, + {0x0070,0x0080,VR::CS,VM::VM1,"Content Label","ContentLabel",false }, + {0x0070,0x0081,VR::LO,VM::VM1,"Content Description","ContentDescription",false }, + {0x0070,0x0082,VR::DA,VM::VM1,"Presentation Creation Date","PresentationCreationDate",false }, + {0x0070,0x0083,VR::TM,VM::VM1,"Presentation Creation Time","PresentationCreationTime",false }, + {0x0070,0x0084,VR::PN,VM::VM1,"Content Creator's Name","ContentCreatorName",false }, + {0x0070,0x0086,VR::SQ,VM::VM1,"Content Creator's Identification Code Sequence","ContentCreatorIdentificationCodeSequence",false }, + {0x0070,0x0087,VR::SQ,VM::VM1,"Alternate Content Description Sequence","AlternateContentDescriptionSequence",false }, + {0x0070,0x0100,VR::CS,VM::VM1,"Presentation Size Mode","PresentationSizeMode",false }, + {0x0070,0x0101,VR::DS,VM::VM2,"Presentation Pixel Spacing","PresentationPixelSpacing",false }, + {0x0070,0x0102,VR::IS,VM::VM2,"Presentation Pixel Aspect Ratio","PresentationPixelAspectRatio",false }, + {0x0070,0x0103,VR::FL,VM::VM1,"Presentation Pixel Magnification Ratio","PresentationPixelMagnificationRatio",false }, + {0x0070,0x0207,VR::LO,VM::VM1,"Graphic Group Label","GraphicGroupLabel",false }, + {0x0070,0x0208,VR::ST,VM::VM1,"Graphic Group Description","GraphicGroupDescription",false }, + {0x0070,0x0209,VR::SQ,VM::VM1,"Compound Graphic Sequence","CompoundGraphicSequence",false }, + {0x0070,0x0226,VR::UL,VM::VM1,"Compound Graphic Instance ID","CompoundGraphicInstanceID",false }, + {0x0070,0x0227,VR::LO,VM::VM1,"Font Name","FontName",false }, + {0x0070,0x0228,VR::CS,VM::VM1,"Font Name Type","FontNameType",false }, + {0x0070,0x0229,VR::LO,VM::VM1,"CSS Font Name","CSSFontName",false }, + {0x0070,0x0230,VR::FD,VM::VM1,"Rotation Angle","RotationAngle",false }, + {0x0070,0x0231,VR::SQ,VM::VM1,"Text Style Sequence","TextStyleSequence",false }, + {0x0070,0x0232,VR::SQ,VM::VM1,"Line Style Sequence","LineStyleSequence",false }, + {0x0070,0x0233,VR::SQ,VM::VM1,"Fill Style Sequence","FillStyleSequence",false }, + {0x0070,0x0234,VR::SQ,VM::VM1,"Graphic Group Sequence","GraphicGroupSequence",false }, + {0x0070,0x0241,VR::US,VM::VM3,"Text Color CIELab Value","TextColorCIELabValue",false }, + {0x0070,0x0242,VR::CS,VM::VM1,"Horizontal Alignment","HorizontalAlignment",false }, + {0x0070,0x0243,VR::CS,VM::VM1,"Vertical Alignment","VerticalAlignment",false }, + {0x0070,0x0244,VR::CS,VM::VM1,"Shadow Style","ShadowStyle",false }, + {0x0070,0x0245,VR::FL,VM::VM1,"Shadow Offset X","ShadowOffsetX",false }, + {0x0070,0x0246,VR::FL,VM::VM1,"Shadow Offset Y","ShadowOffsetY",false }, + {0x0070,0x0247,VR::US,VM::VM3,"Shadow Color CIELab Value","ShadowColorCIELabValue",false }, + {0x0070,0x0248,VR::CS,VM::VM1,"Underlined","Underlined",false }, + {0x0070,0x0249,VR::CS,VM::VM1,"Bold","Bold",false }, + {0x0070,0x0250,VR::CS,VM::VM1,"Italic","Italic",false }, + {0x0070,0x0251,VR::US,VM::VM3,"Pattern On Color CIELab Value","PatternOnColorCIELabValue",false }, + {0x0070,0x0252,VR::US,VM::VM3,"Pattern Off Color CIELab Value","PatternOffColorCIELabValue",false }, + {0x0070,0x0253,VR::FL,VM::VM1,"Line Thickness","LineThickness",false }, + {0x0070,0x0254,VR::CS,VM::VM1,"Line Dashing Style","LineDashingStyle",false }, + {0x0070,0x0255,VR::UL,VM::VM1,"Line Pattern","LinePattern",false }, + {0x0070,0x0256,VR::OB,VM::VM1,"Fill Pattern","FillPattern",false }, + {0x0070,0x0257,VR::CS,VM::VM1,"Fill Mode","FillMode",false }, + {0x0070,0x0258,VR::FL,VM::VM1,"Shadow Opacity","ShadowOpacity",false }, + {0x0070,0x0261,VR::FL,VM::VM1,"Gap Length","GapLength",false }, + {0x0070,0x0262,VR::FL,VM::VM1,"Diameter of Visibility","DiameterOfVisibility",false }, + {0x0070,0x0273,VR::FL,VM::VM2,"Rotation Point","RotationPoint",false }, + {0x0070,0x0274,VR::CS,VM::VM1,"Tick Alignment","TickAlignment",false }, + {0x0070,0x0278,VR::CS,VM::VM1,"Show Tick Label","ShowTickLabel",false }, + {0x0070,0x0279,VR::CS,VM::VM1,"Tick Label Alignment","TickLabelAlignment",false }, + {0x0070,0x0282,VR::CS,VM::VM1,"Compound Graphic Units","CompoundGraphicUnits",false }, + {0x0070,0x0284,VR::FL,VM::VM1,"Pattern On Opacity","PatternOnOpacity",false }, + {0x0070,0x0285,VR::FL,VM::VM1,"Pattern Off Opacity","PatternOffOpacity",false }, + {0x0070,0x0287,VR::SQ,VM::VM1,"Major Ticks Sequence","MajorTicksSequence",false }, + {0x0070,0x0288,VR::FL,VM::VM1,"Tick Position","TickPosition",false }, + {0x0070,0x0289,VR::SH,VM::VM1,"Tick Label","TickLabel",false }, + {0x0070,0x0294,VR::CS,VM::VM1,"Compound Graphic Type","CompoundGraphicType",false }, + {0x0070,0x0295,VR::UL,VM::VM1,"Graphic Group ID","GraphicGroupID",false }, + {0x0070,0x0306,VR::CS,VM::VM1,"Shape Type","ShapeType",false }, + {0x0070,0x0308,VR::SQ,VM::VM1,"Registration Sequence","RegistrationSequence",false }, + {0x0070,0x0309,VR::SQ,VM::VM1,"Matrix Registration Sequence","MatrixRegistrationSequence",false }, + {0x0070,0x030a,VR::SQ,VM::VM1,"Matrix Sequence","MatrixSequence",false }, + {0x0070,0x030c,VR::CS,VM::VM1,"Frame of Reference Transformation Matrix Type","FrameOfReferenceTransformationMatrixType",false }, + {0x0070,0x030d,VR::SQ,VM::VM1,"Registration Type Code Sequence","RegistrationTypeCodeSequence",false }, + {0x0070,0x030f,VR::ST,VM::VM1,"Fiducial Description","FiducialDescription",false }, + {0x0070,0x0310,VR::SH,VM::VM1,"Fiducial Identifier","FiducialIdentifier",false }, + {0x0070,0x0311,VR::SQ,VM::VM1,"Fiducial Identifier Code Sequence","FiducialIdentifierCodeSequence",false }, + {0x0070,0x0312,VR::FD,VM::VM1,"Contour Uncertainty Radius","ContourUncertaintyRadius",false }, + {0x0070,0x0314,VR::SQ,VM::VM1,"Used Fiducials Sequence","UsedFiducialsSequence",false }, + {0x0070,0x0318,VR::SQ,VM::VM1,"Graphic Coordinates Data Sequence","GraphicCoordinatesDataSequence",false }, + {0x0070,0x031a,VR::UI,VM::VM1,"Fiducial UID","FiducialUID",false }, + {0x0070,0x031c,VR::SQ,VM::VM1,"Fiducial Set Sequence","FiducialSetSequence",false }, + {0x0070,0x031e,VR::SQ,VM::VM1,"Fiducial Sequence","FiducialSequence",false }, + {0x0070,0x0401,VR::US,VM::VM3,"Graphic Layer Recommended Display CIELab Value","GraphicLayerRecommendedDisplayCIELabValue",false }, + {0x0070,0x0402,VR::SQ,VM::VM1,"Blending Sequence","BlendingSequence",false }, + {0x0070,0x0403,VR::FL,VM::VM1,"Relative Opacity","RelativeOpacity",false }, + {0x0070,0x0404,VR::SQ,VM::VM1,"Referenced Spatial Registration Sequence","ReferencedSpatialRegistrationSequence",false }, + {0x0070,0x0405,VR::CS,VM::VM1,"Blending Position","BlendingPosition",false }, + {0x0072,0x0002,VR::SH,VM::VM1,"Hanging Protocol Name","HangingProtocolName",false }, + {0x0072,0x0004,VR::LO,VM::VM1,"Hanging Protocol Description","HangingProtocolDescription",false }, + {0x0072,0x0006,VR::CS,VM::VM1,"Hanging Protocol Level","HangingProtocolLevel",false }, + {0x0072,0x0008,VR::LO,VM::VM1,"Hanging Protocol Creator","HangingProtocolCreator",false }, + {0x0072,0x000a,VR::DT,VM::VM1,"Hanging Protocol Creation DateTime","HangingProtocolCreationDateTime",false }, + {0x0072,0x000c,VR::SQ,VM::VM1,"Hanging Protocol Definition Sequence","HangingProtocolDefinitionSequence",false }, + {0x0072,0x000e,VR::SQ,VM::VM1,"Hanging Protocol User Identification Code Sequence","HangingProtocolUserIdentificationCodeSequence",false }, + {0x0072,0x0010,VR::LO,VM::VM1,"Hanging Protocol User Group Name","HangingProtocolUserGroupName",false }, + {0x0072,0x0012,VR::SQ,VM::VM1,"Source Hanging Protocol Sequence","SourceHangingProtocolSequence",false }, + {0x0072,0x0014,VR::US,VM::VM1,"Number of Priors Referenced","NumberOfPriorsReferenced",false }, + {0x0072,0x0020,VR::SQ,VM::VM1,"Image Sets Sequence","ImageSetsSequence",false }, + {0x0072,0x0022,VR::SQ,VM::VM1,"Image Set Selector Sequence","ImageSetSelectorSequence",false }, + {0x0072,0x0024,VR::CS,VM::VM1,"Image Set Selector Usage Flag","ImageSetSelectorUsageFlag",false }, + {0x0072,0x0026,VR::AT,VM::VM1,"Selector Attribute","SelectorAttribute",false }, + {0x0072,0x0028,VR::US,VM::VM1,"Selector Value Number","SelectorValueNumber",false }, + {0x0072,0x0030,VR::SQ,VM::VM1,"Time Based Image Sets Sequence","TimeBasedImageSetsSequence",false }, + {0x0072,0x0032,VR::US,VM::VM1,"Image Set Number","ImageSetNumber",false }, + {0x0072,0x0034,VR::CS,VM::VM1,"Image Set Selector Category","ImageSetSelectorCategory",false }, + {0x0072,0x0038,VR::US,VM::VM2,"Relative Time","RelativeTime",false }, + {0x0072,0x003a,VR::CS,VM::VM1,"Relative Time Units","RelativeTimeUnits",false }, + {0x0072,0x003c,VR::SS,VM::VM2,"Abstract Prior Value","AbstractPriorValue",false }, + {0x0072,0x003e,VR::SQ,VM::VM1,"Abstract Prior Code Sequence","AbstractPriorCodeSequence",false }, + {0x0072,0x0040,VR::LO,VM::VM1,"Image Set Label","ImageSetLabel",false }, + {0x0072,0x0050,VR::CS,VM::VM1,"Selector Attribute VR","SelectorAttributeVR",false }, + {0x0072,0x0052,VR::AT,VM::VM1_n,"Selector Sequence Pointer","SelectorSequencePointer",false }, + {0x0072,0x0054,VR::LO,VM::VM1_n,"Selector Sequence Pointer Private Creator","SelectorSequencePointerPrivateCreator",false }, + {0x0072,0x0056,VR::LO,VM::VM1,"Selector Attribute Private Creator","SelectorAttributePrivateCreator",false }, + {0x0072,0x0060,VR::AT,VM::VM1_n,"Selector AT Value","SelectorATValue",false }, + {0x0072,0x0062,VR::CS,VM::VM1_n,"Selector CS Value","SelectorCSValue",false }, + {0x0072,0x0064,VR::IS,VM::VM1_n,"Selector IS Value","SelectorISValue",false }, + {0x0072,0x0066,VR::LO,VM::VM1_n,"Selector LO Value","SelectorLOValue",false }, + {0x0072,0x0068,VR::LT,VM::VM1,"Selector LT Value","SelectorLTValue",false }, + {0x0072,0x006a,VR::PN,VM::VM1_n,"Selector PN Value","SelectorPNValue",false }, + {0x0072,0x006c,VR::SH,VM::VM1_n,"Selector SH Value","SelectorSHValue",false }, + {0x0072,0x006e,VR::ST,VM::VM1,"Selector ST Value","SelectorSTValue",false }, + {0x0072,0x0070,VR::UT,VM::VM1,"Selector UT Value","SelectorUTValue",false }, + {0x0072,0x0072,VR::DS,VM::VM1_n,"Selector DS Value","SelectorDSValue",false }, + {0x0072,0x0074,VR::FD,VM::VM1_n,"Selector FD Value","SelectorFDValue",false }, + {0x0072,0x0076,VR::FL,VM::VM1_n,"Selector FL Value","SelectorFLValue",false }, + {0x0072,0x0078,VR::UL,VM::VM1_n,"Selector UL Value","SelectorULValue",false }, + {0x0072,0x007a,VR::US,VM::VM1_n,"Selector US Value","SelectorUSValue",false }, + {0x0072,0x007c,VR::SL,VM::VM1_n,"Selector SL Value","SelectorSLValue",false }, + {0x0072,0x007e,VR::SS,VM::VM1_n,"Selector SS Value","SelectorSSValue",false }, + {0x0072,0x0080,VR::SQ,VM::VM1,"Selector Code Sequence Value","SelectorCodeSequenceValue",false }, + {0x0072,0x0100,VR::US,VM::VM1,"Number of Screens","NumberOfScreens",false }, + {0x0072,0x0102,VR::SQ,VM::VM1,"Nominal Screen Definition Sequence","NominalScreenDefinitionSequence",false }, + {0x0072,0x0104,VR::US,VM::VM1,"Number of Vertical Pixels","NumberOfVerticalPixels",false }, + {0x0072,0x0106,VR::US,VM::VM1,"Number of Horizontal Pixels","NumberOfHorizontalPixels",false }, + {0x0072,0x0108,VR::FD,VM::VM4,"Display Environment Spatial Position","DisplayEnvironmentSpatialPosition",false }, + {0x0072,0x010a,VR::US,VM::VM1,"Screen Minimum Grayscale Bit Depth","ScreenMinimumGrayscaleBitDepth",false }, + {0x0072,0x010c,VR::US,VM::VM1,"Screen Minimum Color Bit Depth","ScreenMinimumColorBitDepth",false }, + {0x0072,0x010e,VR::US,VM::VM1,"Application Maximum Repaint Time","ApplicationMaximumRepaintTime",false }, + {0x0072,0x0200,VR::SQ,VM::VM1,"Display Sets Sequence","DisplaySetsSequence",false }, + {0x0072,0x0202,VR::US,VM::VM1,"Display Set Number","DisplaySetNumber",false }, + {0x0072,0x0203,VR::LO,VM::VM1,"Display Set Label","DisplaySetLabel",false }, + {0x0072,0x0204,VR::US,VM::VM1,"Display Set Presentation Group","DisplaySetPresentationGroup",false }, + {0x0072,0x0206,VR::LO,VM::VM1,"Display Set Presentation Group Description","DisplaySetPresentationGroupDescription",false }, + {0x0072,0x0208,VR::CS,VM::VM1,"Partial Data Display Handling","PartialDataDisplayHandling",false }, + {0x0072,0x0210,VR::SQ,VM::VM1,"Synchronized Scrolling Sequence","SynchronizedScrollingSequence",false }, + {0x0072,0x0212,VR::US,VM::VM2_n,"Display Set Scrolling Group","DisplaySetScrollingGroup",false }, + {0x0072,0x0214,VR::SQ,VM::VM1,"Navigation Indicator Sequence","NavigationIndicatorSequence",false }, + {0x0072,0x0216,VR::US,VM::VM1,"Navigation Display Set","NavigationDisplaySet",false }, + {0x0072,0x0218,VR::US,VM::VM1_n,"Reference Display Sets","ReferenceDisplaySets",false }, + {0x0072,0x0300,VR::SQ,VM::VM1,"Image Boxes Sequence","ImageBoxesSequence",false }, + {0x0072,0x0302,VR::US,VM::VM1,"Image Box Number","ImageBoxNumber",false }, + {0x0072,0x0304,VR::CS,VM::VM1,"Image Box Layout Type","ImageBoxLayoutType",false }, + {0x0072,0x0306,VR::US,VM::VM1,"Image Box Tile Horizontal Dimension","ImageBoxTileHorizontalDimension",false }, + {0x0072,0x0308,VR::US,VM::VM1,"Image Box Tile Vertical Dimension","ImageBoxTileVerticalDimension",false }, + {0x0072,0x0310,VR::CS,VM::VM1,"Image Box Scroll Direction","ImageBoxScrollDirection",false }, + {0x0072,0x0312,VR::CS,VM::VM1,"Image Box Small Scroll Type","ImageBoxSmallScrollType",false }, + {0x0072,0x0314,VR::US,VM::VM1,"Image Box Small Scroll Amount","ImageBoxSmallScrollAmount",false }, + {0x0072,0x0316,VR::CS,VM::VM1,"Image Box Large Scroll Type","ImageBoxLargeScrollType",false }, + {0x0072,0x0318,VR::US,VM::VM1,"Image Box Large Scroll Amount","ImageBoxLargeScrollAmount",false }, + {0x0072,0x0320,VR::US,VM::VM1,"Image Box Overlap Priority","ImageBoxOverlapPriority",false }, + {0x0072,0x0330,VR::FD,VM::VM1,"Cine Relative to Real-Time","CineRelativeToRealTime",false }, + {0x0072,0x0400,VR::SQ,VM::VM1,"Filter Operations Sequence","FilterOperationsSequence",false }, + {0x0072,0x0402,VR::CS,VM::VM1,"Filter-by Category","FilterByCategory",false }, + {0x0072,0x0404,VR::CS,VM::VM1,"Filter-by Attribute Presence","FilterByAttributePresence",false }, + {0x0072,0x0406,VR::CS,VM::VM1,"Filter-by Operator","FilterByOperator",false }, + {0x0072,0x0420,VR::US,VM::VM3,"Structured Display Background CIELab Value","StructuredDisplayBackgroundCIELabValue",false }, + {0x0072,0x0421,VR::US,VM::VM3,"Empty Image Box CIELab Value","EmptyImageBoxCIELabValue",false }, + {0x0072,0x0422,VR::SQ,VM::VM1,"Structured Display Image Box Sequence","StructuredDisplayImageBoxSequence",false }, + {0x0072,0x0424,VR::SQ,VM::VM1,"Structured Display Text Box Sequence","StructuredDisplayTextBoxSequence",false }, + {0x0072,0x0427,VR::SQ,VM::VM1,"Referenced First Frame Sequence","ReferencedFirstFrameSequence",false }, + {0x0072,0x0430,VR::SQ,VM::VM1,"Image Box Synchronization Sequence","ImageBoxSynchronizationSequence",false }, + {0x0072,0x0432,VR::US,VM::VM2_n,"Synchronized Image Box List","SynchronizedImageBoxList",false }, + {0x0072,0x0434,VR::CS,VM::VM1,"Type of Synchronization","TypeOfSynchronization",false }, + {0x0072,0x0500,VR::CS,VM::VM1,"Blending Operation Type","BlendingOperationType",false }, + {0x0072,0x0510,VR::CS,VM::VM1,"Reformatting Operation Type","ReformattingOperationType",false }, + {0x0072,0x0512,VR::FD,VM::VM1,"Reformatting Thickness","ReformattingThickness",false }, + {0x0072,0x0514,VR::FD,VM::VM1,"Reformatting Interval","ReformattingInterval",false }, + {0x0072,0x0516,VR::CS,VM::VM1,"Reformatting Operation Initial View Direction","ReformattingOperationInitialViewDirection",false }, + {0x0072,0x0520,VR::CS,VM::VM1_n,"3D Rendering Type","ThreeDRenderingType",false }, + {0x0072,0x0600,VR::SQ,VM::VM1,"Sorting Operations Sequence","SortingOperationsSequence",false }, + {0x0072,0x0602,VR::CS,VM::VM1,"Sort-by Category","SortByCategory",false }, + {0x0072,0x0604,VR::CS,VM::VM1,"Sorting Direction","SortingDirection",false }, + {0x0072,0x0700,VR::CS,VM::VM2,"Display Set Patient Orientation","DisplaySetPatientOrientation",false }, + {0x0072,0x0702,VR::CS,VM::VM1,"VOI Type","VOIType",false }, + {0x0072,0x0704,VR::CS,VM::VM1,"Pseudo-Color Type","PseudoColorType",false }, + {0x0072,0x0705,VR::SQ,VM::VM1,"Pseudo-Color Palette Instance Reference Sequence","PseudoColorPaletteInstanceReferenceSequence",false }, + {0x0072,0x0706,VR::CS,VM::VM1,"Show Grayscale Inverted","ShowGrayscaleInverted",false }, + {0x0072,0x0710,VR::CS,VM::VM1,"Show Image True Size Flag","ShowImageTrueSizeFlag",false }, + {0x0072,0x0712,VR::CS,VM::VM1,"Show Graphic Annotation Flag","ShowGraphicAnnotationFlag",false }, + {0x0072,0x0714,VR::CS,VM::VM1,"Show Patient Demographics Flag","ShowPatientDemographicsFlag",false }, + {0x0072,0x0716,VR::CS,VM::VM1,"Show Acquisition Techniques Flag","ShowAcquisitionTechniquesFlag",false }, + {0x0072,0x0717,VR::CS,VM::VM1,"Display Set Horizontal Justification","DisplaySetHorizontalJustification",false }, + {0x0072,0x0718,VR::CS,VM::VM1,"Display Set Vertical Justification","DisplaySetVerticalJustification",false }, + {0x0074,0x0120,VR::FD,VM::VM1,"Continuation Start Meterset","ContinuationStartMeterset",false }, + {0x0074,0x0121,VR::FD,VM::VM1,"Continuation End Meterset","ContinuationEndMeterset",false }, + {0x0074,0x1000,VR::CS,VM::VM1,"Procedure Step State","ProcedureStepState",false }, + {0x0074,0x1002,VR::SQ,VM::VM1,"Procedure Step Progress Information Sequence","ProcedureStepProgressInformationSequence",false }, + {0x0074,0x1004,VR::DS,VM::VM1,"Procedure Step Progress","ProcedureStepProgress",false }, + {0x0074,0x1006,VR::ST,VM::VM1,"Procedure Step Progress Description","ProcedureStepProgressDescription",false }, + {0x0074,0x1008,VR::SQ,VM::VM1,"Procedure Step Communications URI Sequence","ProcedureStepCommunicationsURISequence",false }, + {0x0074,0x100a,VR::ST,VM::VM1,"Contact URI","ContactURI",false }, + {0x0074,0x100c,VR::LO,VM::VM1,"Contact Display Name","ContactDisplayName",false }, + {0x0074,0x100e,VR::SQ,VM::VM1,"Procedure Step Discontinuation Reason Code Sequence","ProcedureStepDiscontinuationReasonCodeSequence",false }, + {0x0074,0x1020,VR::SQ,VM::VM1,"Beam Task Sequence","BeamTaskSequence",false }, + {0x0074,0x1022,VR::CS,VM::VM1,"Beam Task Type","BeamTaskType",false }, + {0x0074,0x1024,VR::IS,VM::VM1,"Beam Order Index (Trial)","BeamOrderIndexTrial",true }, + {0x0074,0x1026,VR::FD,VM::VM1,"Table Top Vertical Adjusted Position","TableTopVerticalAdjustedPosition",false }, + {0x0074,0x1027,VR::FD,VM::VM1,"Table Top Longitudinal Adjusted Position","TableTopLongitudinalAdjustedPosition",false }, + {0x0074,0x1028,VR::FD,VM::VM1,"Table Top Lateral Adjusted Position","TableTopLateralAdjustedPosition",false }, + {0x0074,0x102a,VR::FD,VM::VM1,"Patient Support Adjusted Angle","PatientSupportAdjustedAngle",false }, + {0x0074,0x102b,VR::FD,VM::VM1,"Table Top Eccentric Adjusted Angle","TableTopEccentricAdjustedAngle",false }, + {0x0074,0x102c,VR::FD,VM::VM1,"Table Top Pitch Adjusted Angle","TableTopPitchAdjustedAngle",false }, + {0x0074,0x102d,VR::FD,VM::VM1,"Table Top Roll Adjusted Angle","TableTopRollAdjustedAngle",false }, + {0x0074,0x1030,VR::SQ,VM::VM1,"Delivery Verification Image Sequence","DeliveryVerificationImageSequence",false }, + {0x0074,0x1032,VR::CS,VM::VM1,"Verification Image Timing","VerificationImageTiming",false }, + {0x0074,0x1034,VR::CS,VM::VM1,"Double Exposure Flag","DoubleExposureFlag",false }, + {0x0074,0x1036,VR::CS,VM::VM1,"Double Exposure Ordering","DoubleExposureOrdering",false }, + {0x0074,0x1038,VR::DS,VM::VM1,"Double Exposure Meterset (Trial)","DoubleExposureMetersetTrial",true }, + {0x0074,0x103a,VR::DS,VM::VM4,"Double Exposure Field Delta (Trial)","DoubleExposureFieldDeltaTrial",true }, + {0x0074,0x1040,VR::SQ,VM::VM1,"Related Reference RT Image Sequence","RelatedReferenceRTImageSequence",false }, + {0x0074,0x1042,VR::SQ,VM::VM1,"General Machine Verification Sequence","GeneralMachineVerificationSequence",false }, + {0x0074,0x1044,VR::SQ,VM::VM1,"Conventional Machine Verification Sequence","ConventionalMachineVerificationSequence",false }, + {0x0074,0x1046,VR::SQ,VM::VM1,"Ion Machine Verification Sequence","IonMachineVerificationSequence",false }, + {0x0074,0x1048,VR::SQ,VM::VM1,"Failed Attributes Sequence","FailedAttributesSequence",false }, + {0x0074,0x104a,VR::SQ,VM::VM1,"Overridden Attributes Sequence","OverriddenAttributesSequence",false }, + {0x0074,0x104c,VR::SQ,VM::VM1,"Conventional Control Point Verification Sequence","ConventionalControlPointVerificationSequence",false }, + {0x0074,0x104e,VR::SQ,VM::VM1,"Ion Control Point Verification Sequence","IonControlPointVerificationSequence",false }, + {0x0074,0x1050,VR::SQ,VM::VM1,"Attribute Occurrence Sequence","AttributeOccurrenceSequence",false }, + {0x0074,0x1052,VR::AT,VM::VM1,"Attribute Occurrence Pointer","AttributeOccurrencePointer",false }, + {0x0074,0x1054,VR::UL,VM::VM1,"Attribute Item Selector","AttributeItemSelector",false }, + {0x0074,0x1056,VR::LO,VM::VM1,"Attribute Occurrence Private Creator","AttributeOccurrencePrivateCreator",false }, + {0x0074,0x1057,VR::IS,VM::VM1_n,"Selector Sequence Pointer Items","SelectorSequencePointerItems",false }, + {0x0074,0x1200,VR::CS,VM::VM1,"Scheduled Procedure Step Priority","ScheduledProcedureStepPriority",false }, + {0x0074,0x1202,VR::LO,VM::VM1,"Worklist Label","WorklistLabel",false }, + {0x0074,0x1204,VR::LO,VM::VM1,"Procedure Step Label","ProcedureStepLabel",false }, + {0x0074,0x1210,VR::SQ,VM::VM1,"Scheduled Processing Parameters Sequence","ScheduledProcessingParametersSequence",false }, + {0x0074,0x1212,VR::SQ,VM::VM1,"Performed Processing Parameters Sequence","PerformedProcessingParametersSequence",false }, + {0x0074,0x1216,VR::SQ,VM::VM1,"Unified Procedure Step Performed Procedure Sequence","UnifiedProcedureStepPerformedProcedureSequence",false }, + {0x0074,0x1220,VR::SQ,VM::VM1,"Related Procedure Step Sequence","RelatedProcedureStepSequence",true }, + {0x0074,0x1222,VR::LO,VM::VM1,"Procedure Step Relationship Type","ProcedureStepRelationshipType",true }, + {0x0074,0x1224,VR::SQ,VM::VM1,"Replaced Procedure Step Sequence","ReplacedProcedureStepSequence",false }, + {0x0074,0x1230,VR::LO,VM::VM1,"Deletion Lock","DeletionLock",false }, + {0x0074,0x1234,VR::AE,VM::VM1,"Receiving AE","ReceivingAE",false }, + {0x0074,0x1236,VR::AE,VM::VM1,"Requesting AE","RequestingAE",false }, + {0x0074,0x1238,VR::LT,VM::VM1,"Reason for Cancellation","ReasonForCancellation",false }, + {0x0074,0x1242,VR::CS,VM::VM1,"SCP Status","SCPStatus",false }, + {0x0074,0x1244,VR::CS,VM::VM1,"Subscription List Status","SubscriptionListStatus",false }, + {0x0074,0x1246,VR::CS,VM::VM1,"Unified Procedure Step List Status","UnifiedProcedureStepListStatus",false }, + {0x0074,0x1324,VR::UL,VM::VM1,"Beam Order Index","BeamOrderIndex",false }, + {0x0074,0x1338,VR::FD,VM::VM1,"Double Exposure Meterset","DoubleExposureMeterset",false }, + {0x0074,0x133a,VR::FD,VM::VM4,"Double Exposure Field Delta","DoubleExposureFieldDelta",false }, + {0x0076,0x0001,VR::LO,VM::VM1,"Implant Assembly Template Name","ImplantAssemblyTemplateName",false }, + {0x0076,0x0003,VR::LO,VM::VM1,"Implant Assembly Template Issuer","ImplantAssemblyTemplateIssuer",false }, + {0x0076,0x0006,VR::LO,VM::VM1,"Implant Assembly Template Version","ImplantAssemblyTemplateVersion",false }, + {0x0076,0x0008,VR::SQ,VM::VM1,"Replaced Implant Assembly Template Sequence","ReplacedImplantAssemblyTemplateSequence",false }, + {0x0076,0x000a,VR::CS,VM::VM1,"Implant Assembly Template Type","ImplantAssemblyTemplateType",false }, + {0x0076,0x000c,VR::SQ,VM::VM1,"Original Implant Assembly Template Sequence","OriginalImplantAssemblyTemplateSequence",false }, + {0x0076,0x000e,VR::SQ,VM::VM1,"Derivation Implant Assembly Template Sequence","DerivationImplantAssemblyTemplateSequence",false }, + {0x0076,0x0010,VR::SQ,VM::VM1,"Implant Assembly Template Target Anatomy Sequence","ImplantAssemblyTemplateTargetAnatomySequence",false }, + {0x0076,0x0020,VR::SQ,VM::VM1,"Procedure Type Code Sequence","ProcedureTypeCodeSequence",false }, + {0x0076,0x0030,VR::LO,VM::VM1,"Surgical Technique","SurgicalTechnique",false }, + {0x0076,0x0032,VR::SQ,VM::VM1,"Component Types Sequence","ComponentTypesSequence",false }, + {0x0076,0x0034,VR::CS,VM::VM1,"Component Type Code Sequence","ComponentTypeCodeSequence",false }, + {0x0076,0x0036,VR::CS,VM::VM1,"Exclusive Component Type","ExclusiveComponentType",false }, + {0x0076,0x0038,VR::CS,VM::VM1,"Mandatory Component Type","MandatoryComponentType",false }, + {0x0076,0x0040,VR::SQ,VM::VM1,"Component Sequence","ComponentSequence",false }, + {0x0076,0x0055,VR::US,VM::VM1,"Component ID","ComponentID",false }, + {0x0076,0x0060,VR::SQ,VM::VM1,"Component Assembly Sequence","ComponentAssemblySequence",false }, + {0x0076,0x0070,VR::US,VM::VM1,"Component 1 Referenced ID","Component1ReferencedID",false }, + {0x0076,0x0080,VR::US,VM::VM1,"Component 1 Referenced Mating Feature Set ID","Component1ReferencedMatingFeatureSetID",false }, + {0x0076,0x0090,VR::US,VM::VM1,"Component 1 Referenced Mating Feature ID","Component1ReferencedMatingFeatureID",false }, + {0x0076,0x00a0,VR::US,VM::VM1,"Component 2 Referenced ID","Component2ReferencedID",false }, + {0x0076,0x00b0,VR::US,VM::VM1,"Component 2 Referenced Mating Feature Set ID","Component2ReferencedMatingFeatureSetID",false }, + {0x0076,0x00c0,VR::US,VM::VM1,"Component 2 Referenced Mating Feature ID","Component2ReferencedMatingFeatureID",false }, + {0x0078,0x0001,VR::LO,VM::VM1,"Implant Template Group Name","ImplantTemplateGroupName",false }, + {0x0078,0x0010,VR::ST,VM::VM1,"Implant Template Group Description","ImplantTemplateGroupDescription",false }, + {0x0078,0x0020,VR::LO,VM::VM1,"Implant Template Group Issuer","ImplantTemplateGroupIssuer",false }, + {0x0078,0x0024,VR::LO,VM::VM1,"Implant Template Group Version","ImplantTemplateGroupVersion",false }, + {0x0078,0x0026,VR::SQ,VM::VM1,"Replaced Implant Template Group Sequence","ReplacedImplantTemplateGroupSequence",false }, + {0x0078,0x0028,VR::SQ,VM::VM1,"Implant Template Group Target Anatomy Sequence","ImplantTemplateGroupTargetAnatomySequence",false }, + {0x0078,0x002a,VR::SQ,VM::VM1,"Implant Template Group Members Sequence","ImplantTemplateGroupMembersSequence",false }, + {0x0078,0x002e,VR::US,VM::VM1,"Implant Template Group Member ID","ImplantTemplateGroupMemberID",false }, + {0x0078,0x0050,VR::FD,VM::VM3,"3D Implant Template Group Member Matching Point","ThreeDImplantTemplateGroupMemberMatchingPoint",false }, + {0x0078,0x0060,VR::FD,VM::VM9,"3D Implant Template Group Member Matching Axes","ThreeDImplantTemplateGroupMemberMatchingAxes",false }, + {0x0078,0x0070,VR::SQ,VM::VM1,"Implant Template Group Member Matching 2D Coordinates Sequence","ImplantTemplateGroupMemberMatching2DCoordinatesSequence",false }, + {0x0078,0x0090,VR::FD,VM::VM2,"2D Implant Template Group Member Matching Point","TwoDImplantTemplateGroupMemberMatchingPoint",false }, + {0x0078,0x00a0,VR::FD,VM::VM4,"2D Implant Template Group Member Matching Axes","TwoDImplantTemplateGroupMemberMatchingAxes",false }, + {0x0078,0x00b0,VR::SQ,VM::VM1,"Implant Template Group Variation Dimension Sequence","ImplantTemplateGroupVariationDimensionSequence",false }, + {0x0078,0x00b2,VR::LO,VM::VM1,"Implant Template Group Variation Dimension Name","ImplantTemplateGroupVariationDimensionName",false }, + {0x0078,0x00b4,VR::SQ,VM::VM1,"Implant Template Group Variation Dimension Rank Sequence","ImplantTemplateGroupVariationDimensionRankSequence",false }, + {0x0078,0x00b6,VR::US,VM::VM1,"Referenced Implant Template Group Member ID","ReferencedImplantTemplateGroupMemberID",false }, + {0x0078,0x00b8,VR::US,VM::VM1,"Implant Template Group Variation Dimension Rank","ImplantTemplateGroupVariationDimensionRank",false }, + {0x0088,0x0130,VR::SH,VM::VM1,"Storage Media File-set ID","StorageMediaFileSetID",false }, + {0x0088,0x0140,VR::UI,VM::VM1,"Storage Media File-set UID","StorageMediaFileSetUID",false }, + {0x0088,0x0200,VR::SQ,VM::VM1,"Icon Image Sequence","IconImageSequence",false }, + {0x0088,0x0904,VR::LO,VM::VM1,"Topic Title","TopicTitle",true }, + {0x0088,0x0906,VR::ST,VM::VM1,"Topic Subject","TopicSubject",true }, + {0x0088,0x0910,VR::LO,VM::VM1,"Topic Author","TopicAuthor",true }, + {0x0088,0x0912,VR::LO,VM::VM1_32,"Topic Keywords","TopicKeywords",true }, + {0x0100,0x0410,VR::CS,VM::VM1,"SOP Instance Status","SOPInstanceStatus",false }, + {0x0100,0x0420,VR::DT,VM::VM1,"SOP Authorization DateTime","SOPAuthorizationDateTime",false }, + {0x0100,0x0424,VR::LT,VM::VM1,"SOP Authorization Comment","SOPAuthorizationComment",false }, + {0x0100,0x0426,VR::LO,VM::VM1,"Authorization Equipment Certification Number","AuthorizationEquipmentCertificationNumber",false }, + {0x0400,0x0005,VR::US,VM::VM1,"MAC ID Number","MACIDNumber",false }, + {0x0400,0x0010,VR::UI,VM::VM1,"MAC Calculation Transfer Syntax UID","MACCalculationTransferSyntaxUID",false }, + {0x0400,0x0015,VR::CS,VM::VM1,"MAC Algorithm","MACAlgorithm",false }, + {0x0400,0x0020,VR::AT,VM::VM1_n,"Data Elements Signed","DataElementsSigned",false }, + {0x0400,0x0100,VR::UI,VM::VM1,"Digital Signature UID","DigitalSignatureUID",false }, + {0x0400,0x0105,VR::DT,VM::VM1,"Digital Signature DateTime","DigitalSignatureDateTime",false }, + {0x0400,0x0110,VR::CS,VM::VM1,"Certificate Type","CertificateType",false }, + {0x0400,0x0115,VR::OB,VM::VM1,"Certificate of Signer","CertificateOfSigner",false }, + {0x0400,0x0120,VR::OB,VM::VM1,"Signature","Signature",false }, + {0x0400,0x0305,VR::CS,VM::VM1,"Certified Timestamp Type","CertifiedTimestampType",false }, + {0x0400,0x0310,VR::OB,VM::VM1,"Certified Timestamp","CertifiedTimestamp",false }, + {0x0400,0x0401,VR::SQ,VM::VM1,"Digital Signature Purpose Code Sequence","DigitalSignaturePurposeCodeSequence",false }, + {0x0400,0x0402,VR::SQ,VM::VM1,"Referenced Digital Signature Sequence","ReferencedDigitalSignatureSequence",false }, + {0x0400,0x0403,VR::SQ,VM::VM1,"Referenced SOP Instance MAC Sequence","ReferencedSOPInstanceMACSequence",false }, + {0x0400,0x0404,VR::OB,VM::VM1,"MAC","MAC",false }, + {0x0400,0x0500,VR::SQ,VM::VM1,"Encrypted Attributes Sequence","EncryptedAttributesSequence",false }, + {0x0400,0x0510,VR::UI,VM::VM1,"Encrypted Content Transfer Syntax UID","EncryptedContentTransferSyntaxUID",false }, + {0x0400,0x0520,VR::OB,VM::VM1,"Encrypted Content","EncryptedContent",false }, + {0x0400,0x0550,VR::SQ,VM::VM1,"Modified Attributes Sequence","ModifiedAttributesSequence",false }, + {0x0400,0x0561,VR::SQ,VM::VM1,"Original Attributes Sequence","OriginalAttributesSequence",false }, + {0x0400,0x0562,VR::DT,VM::VM1,"Attribute Modification DateTime","AttributeModificationDateTime",false }, + {0x0400,0x0563,VR::LO,VM::VM1,"Modifying System","ModifyingSystem",false }, + {0x0400,0x0564,VR::LO,VM::VM1,"Source of Previous Values","SourceOfPreviousValues",false }, + {0x0400,0x0565,VR::CS,VM::VM1,"Reason for the Attribute Modification","ReasonForTheAttributeModification",false }, +// {0x1010,0x0000,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0001,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0002,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0003,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0004,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0005,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0006,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0007,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0008,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0009,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x000a,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x000b,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x000c,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x000d,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x000e,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x000f,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0010,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0011,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0012,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0013,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0014,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0015,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0016,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0017,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0018,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0019,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x001a,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x001b,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x001c,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x001d,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x001e,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x001f,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0020,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0021,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0022,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0023,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0024,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0025,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0026,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0027,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0028,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0029,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x002a,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x002b,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x002c,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x002d,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x002e,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x002f,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0030,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0031,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0032,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0033,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0034,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0035,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0036,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0037,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0038,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0039,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x003a,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x003b,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x003c,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x003d,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x003e,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x003f,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0040,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0041,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0042,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0043,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0044,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0045,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0046,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0047,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0048,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0049,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x004a,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x004b,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x004c,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x004d,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x004e,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x004f,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0050,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0051,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0052,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0053,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0054,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0055,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0056,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0057,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0058,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0059,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x005a,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x005b,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x005c,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x005d,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x005e,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x005f,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0060,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0061,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0062,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0063,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0064,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0065,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0066,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0067,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0068,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0069,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x006a,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x006b,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x006c,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x006d,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x006e,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x006f,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0070,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0071,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0072,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0073,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0074,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0075,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0076,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0077,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0078,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0079,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x007a,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x007b,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x007c,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x007d,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x007e,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x007f,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0080,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0081,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0082,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0083,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0084,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0085,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0086,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0087,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0088,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0089,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x008a,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x008b,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x008c,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x008d,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x008e,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x008f,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0090,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0091,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0092,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0093,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0094,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0095,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0096,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0097,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0098,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x0099,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x009a,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x009b,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x009c,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x009d,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x009e,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x009f,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00a0,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00a1,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00a2,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00a3,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00a4,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00a5,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00a6,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00a7,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00a8,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00a9,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00aa,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00ab,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00ac,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00ad,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00ae,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00af,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00b0,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00b1,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00b2,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00b3,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00b4,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00b5,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00b6,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00b7,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00b8,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00b9,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00ba,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00bb,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00bc,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00bd,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00be,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00bf,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00c0,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00c1,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00c2,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00c3,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00c4,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00c5,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00c6,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00c7,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00c8,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00c9,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00ca,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00cb,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00cc,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00cd,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00ce,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00cf,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00d0,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00d1,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00d2,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00d3,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00d4,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00d5,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00d6,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00d7,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00d8,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00d9,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00da,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00db,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00dc,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00dd,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00de,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00df,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00e0,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00e1,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00e2,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00e3,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00e4,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00e5,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00e6,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00e7,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00e8,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00e9,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00ea,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00eb,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00ec,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00ed,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00ee,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00ef,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00f0,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00f1,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00f2,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00f3,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00f4,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00f5,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00f6,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00f7,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00f8,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00f9,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00fa,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00fb,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00fc,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00fd,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00fe,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x1010,0x00ff,VR::US,VM::VM1_n,"Zonal Map","ZonalMap",true }, + {0x2000,0x0010,VR::IS,VM::VM1,"Number of Copies","NumberOfCopies",false }, + {0x2000,0x001e,VR::SQ,VM::VM1,"Printer Configuration Sequence","PrinterConfigurationSequence",false }, + {0x2000,0x0020,VR::CS,VM::VM1,"Print Priority","PrintPriority",false }, + {0x2000,0x0030,VR::CS,VM::VM1,"Medium Type","MediumType",false }, + {0x2000,0x0040,VR::CS,VM::VM1,"Film Destination","FilmDestination",false }, + {0x2000,0x0050,VR::LO,VM::VM1,"Film Session Label","FilmSessionLabel",false }, + {0x2000,0x0060,VR::IS,VM::VM1,"Memory Allocation","MemoryAllocation",false }, + {0x2000,0x0061,VR::IS,VM::VM1,"Maximum Memory Allocation","MaximumMemoryAllocation",false }, + {0x2000,0x0062,VR::CS,VM::VM1,"Color Image Printing Flag","ColorImagePrintingFlag",true }, + {0x2000,0x0063,VR::CS,VM::VM1,"Collation Flag","CollationFlag",true }, + {0x2000,0x0065,VR::CS,VM::VM1,"Annotation Flag","AnnotationFlag",true }, + {0x2000,0x0067,VR::CS,VM::VM1,"Image Overlay Flag","ImageOverlayFlag",true }, + {0x2000,0x0069,VR::CS,VM::VM1,"Presentation LUT Flag","PresentationLUTFlag",true }, + {0x2000,0x006a,VR::CS,VM::VM1,"Image Box Presentation LUT Flag","ImageBoxPresentationLUTFlag",true }, + {0x2000,0x00a0,VR::US,VM::VM1,"Memory Bit Depth","MemoryBitDepth",false }, + {0x2000,0x00a1,VR::US,VM::VM1,"Printing Bit Depth","PrintingBitDepth",false }, + {0x2000,0x00a2,VR::SQ,VM::VM1,"Media Installed Sequence","MediaInstalledSequence",false }, + {0x2000,0x00a4,VR::SQ,VM::VM1,"Other Media Available Sequence","OtherMediaAvailableSequence",false }, + {0x2000,0x00a8,VR::SQ,VM::VM1,"Supported Image Display Formats Sequence","SupportedImageDisplayFormatsSequence",false }, + {0x2000,0x0500,VR::SQ,VM::VM1,"Referenced Film Box Sequence","ReferencedFilmBoxSequence",false }, + {0x2000,0x0510,VR::SQ,VM::VM1,"Referenced Stored Print Sequence","ReferencedStoredPrintSequence",true }, + {0x2010,0x0010,VR::ST,VM::VM1,"Image Display Format","ImageDisplayFormat",false }, + {0x2010,0x0030,VR::CS,VM::VM1,"Annotation Display Format ID","AnnotationDisplayFormatID",false }, + {0x2010,0x0040,VR::CS,VM::VM1,"Film Orientation","FilmOrientation",false }, + {0x2010,0x0050,VR::CS,VM::VM1,"Film Size ID","FilmSizeID",false }, + {0x2010,0x0052,VR::CS,VM::VM1,"Printer Resolution ID","PrinterResolutionID",false }, + {0x2010,0x0054,VR::CS,VM::VM1,"Default Printer Resolution ID","DefaultPrinterResolutionID",false }, + {0x2010,0x0060,VR::CS,VM::VM1,"Magnification Type","MagnificationType",false }, + {0x2010,0x0080,VR::CS,VM::VM1,"Smoothing Type","SmoothingType",false }, + {0x2010,0x00a6,VR::CS,VM::VM1,"Default Magnification Type","DefaultMagnificationType",false }, + {0x2010,0x00a7,VR::CS,VM::VM1_n,"Other Magnification Types Available","OtherMagnificationTypesAvailable",false }, + {0x2010,0x00a8,VR::CS,VM::VM1,"Default Smoothing Type","DefaultSmoothingType",false }, + {0x2010,0x00a9,VR::CS,VM::VM1_n,"Other Smoothing Types Available","OtherSmoothingTypesAvailable",false }, + {0x2010,0x0100,VR::CS,VM::VM1,"Border Density","BorderDensity",false }, + {0x2010,0x0110,VR::CS,VM::VM1,"Empty Image Density","EmptyImageDensity",false }, + {0x2010,0x0120,VR::US,VM::VM1,"Min Density","MinDensity",false }, + {0x2010,0x0130,VR::US,VM::VM1,"Max Density","MaxDensity",false }, + {0x2010,0x0140,VR::CS,VM::VM1,"Trim","Trim",false }, + {0x2010,0x0150,VR::ST,VM::VM1,"Configuration Information","ConfigurationInformation",false }, + {0x2010,0x0152,VR::LT,VM::VM1,"Configuration Information Description","ConfigurationInformationDescription",false }, + {0x2010,0x0154,VR::IS,VM::VM1,"Maximum Collated Films","MaximumCollatedFilms",false }, + {0x2010,0x015e,VR::US,VM::VM1,"Illumination","Illumination",false }, + {0x2010,0x0160,VR::US,VM::VM1,"Reflected Ambient Light","ReflectedAmbientLight",false }, + {0x2010,0x0376,VR::DS,VM::VM2,"Printer Pixel Spacing","PrinterPixelSpacing",false }, + {0x2010,0x0500,VR::SQ,VM::VM1,"Referenced Film Session Sequence","ReferencedFilmSessionSequence",false }, + {0x2010,0x0510,VR::SQ,VM::VM1,"Referenced Image Box Sequence","ReferencedImageBoxSequence",false }, + {0x2010,0x0520,VR::SQ,VM::VM1,"Referenced Basic Annotation Box Sequence","ReferencedBasicAnnotationBoxSequence",false }, + {0x2020,0x0010,VR::US,VM::VM1,"Image Box Position","ImageBoxPosition",false }, + {0x2020,0x0020,VR::CS,VM::VM1,"Polarity","Polarity",false }, + {0x2020,0x0030,VR::DS,VM::VM1,"Requested Image Size","RequestedImageSize",false }, + {0x2020,0x0040,VR::CS,VM::VM1,"Requested Decimate/Crop Behavior","RequestedDecimateCropBehavior",false }, + {0x2020,0x0050,VR::CS,VM::VM1,"Requested Resolution ID","RequestedResolutionID",false }, + {0x2020,0x00a0,VR::CS,VM::VM1,"Requested Image Size Flag","RequestedImageSizeFlag",false }, + {0x2020,0x00a2,VR::CS,VM::VM1,"Decimate/Crop Result","DecimateCropResult",false }, + {0x2020,0x0110,VR::SQ,VM::VM1,"Basic Grayscale Image Sequence","BasicGrayscaleImageSequence",false }, + {0x2020,0x0111,VR::SQ,VM::VM1,"Basic Color Image Sequence","BasicColorImageSequence",false }, + {0x2020,0x0130,VR::SQ,VM::VM1,"Referenced Image Overlay Box Sequence","ReferencedImageOverlayBoxSequence",true }, + {0x2020,0x0140,VR::SQ,VM::VM1,"Referenced VOI LUT Box Sequence","ReferencedVOILUTBoxSequence",true }, + {0x2030,0x0010,VR::US,VM::VM1,"Annotation Position","AnnotationPosition",false }, + {0x2030,0x0020,VR::LO,VM::VM1,"Text String","TextString",false }, + {0x2040,0x0010,VR::SQ,VM::VM1,"Referenced Overlay Plane Sequence","ReferencedOverlayPlaneSequence",true }, + {0x2040,0x0011,VR::US,VM::VM1_99,"Referenced Overlay Plane Groups","ReferencedOverlayPlaneGroups",true }, + {0x2040,0x0020,VR::SQ,VM::VM1,"Overlay Pixel Data Sequence","OverlayPixelDataSequence",true }, + {0x2040,0x0060,VR::CS,VM::VM1,"Overlay Magnification Type","OverlayMagnificationType",true }, + {0x2040,0x0070,VR::CS,VM::VM1,"Overlay Smoothing Type","OverlaySmoothingType",true }, + {0x2040,0x0072,VR::CS,VM::VM1,"Overlay or Image Magnification","OverlayOrImageMagnification",true }, + {0x2040,0x0074,VR::US,VM::VM1,"Magnify to Number of Columns","MagnifyToNumberOfColumns",true }, + {0x2040,0x0080,VR::CS,VM::VM1,"Overlay Foreground Density","OverlayForegroundDensity",true }, + {0x2040,0x0082,VR::CS,VM::VM1,"Overlay Background Density","OverlayBackgroundDensity",true }, + {0x2040,0x0090,VR::CS,VM::VM1,"Overlay Mode","OverlayMode",true }, + {0x2040,0x0100,VR::CS,VM::VM1,"Threshold Density","ThresholdDensity",true }, + {0x2040,0x0500,VR::SQ,VM::VM1,"Referenced Image Box Sequence (Retired)","ReferencedImageBoxSequenceRetired",true }, + {0x2050,0x0010,VR::SQ,VM::VM1,"Presentation LUT Sequence","PresentationLUTSequence",false }, + {0x2050,0x0020,VR::CS,VM::VM1,"Presentation LUT Shape","PresentationLUTShape",false }, + {0x2050,0x0500,VR::SQ,VM::VM1,"Referenced Presentation LUT Sequence","ReferencedPresentationLUTSequence",false }, + {0x2100,0x0010,VR::SH,VM::VM1,"Print Job ID","PrintJobID",true }, + {0x2100,0x0020,VR::CS,VM::VM1,"Execution Status","ExecutionStatus",false }, + {0x2100,0x0030,VR::CS,VM::VM1,"Execution Status Info","ExecutionStatusInfo",false }, + {0x2100,0x0040,VR::DA,VM::VM1,"Creation Date","CreationDate",false }, + {0x2100,0x0050,VR::TM,VM::VM1,"Creation Time","CreationTime",false }, + {0x2100,0x0070,VR::AE,VM::VM1,"Originator","Originator",false }, + {0x2100,0x0140,VR::AE,VM::VM1,"Destination AE","DestinationAE",true }, + {0x2100,0x0160,VR::SH,VM::VM1,"Owner ID","OwnerID",false }, + {0x2100,0x0170,VR::IS,VM::VM1,"Number of Films","NumberOfFilms",false }, + {0x2100,0x0500,VR::SQ,VM::VM1,"Referenced Print Job Sequence (Pull Stored Print)","ReferencedPrintJobSequencePullStoredPrint",true }, + {0x2110,0x0010,VR::CS,VM::VM1,"Printer Status","PrinterStatus",false }, + {0x2110,0x0020,VR::CS,VM::VM1,"Printer Status Info","PrinterStatusInfo",false }, + {0x2110,0x0030,VR::LO,VM::VM1,"Printer Name","PrinterName",false }, + {0x2110,0x0099,VR::SH,VM::VM1,"Print Queue ID","PrintQueueID",true }, + {0x2120,0x0010,VR::CS,VM::VM1,"Queue Status","QueueStatus",true }, + {0x2120,0x0050,VR::SQ,VM::VM1,"Print Job Description Sequence","PrintJobDescriptionSequence",true }, + {0x2120,0x0070,VR::SQ,VM::VM1,"Referenced Print Job Sequence","ReferencedPrintJobSequence",true }, + {0x2130,0x0010,VR::SQ,VM::VM1,"Print Management Capabilities Sequence","PrintManagementCapabilitiesSequence",true }, + {0x2130,0x0015,VR::SQ,VM::VM1,"Printer Characteristics Sequence","PrinterCharacteristicsSequence",true }, + {0x2130,0x0030,VR::SQ,VM::VM1,"Film Box Content Sequence","FilmBoxContentSequence",true }, + {0x2130,0x0040,VR::SQ,VM::VM1,"Image Box Content Sequence","ImageBoxContentSequence",true }, + {0x2130,0x0050,VR::SQ,VM::VM1,"Annotation Content Sequence","AnnotationContentSequence",true }, + {0x2130,0x0060,VR::SQ,VM::VM1,"Image Overlay Box Content Sequence","ImageOverlayBoxContentSequence",true }, + {0x2130,0x0080,VR::SQ,VM::VM1,"Presentation LUT Content Sequence","PresentationLUTContentSequence",true }, + {0x2130,0x00a0,VR::SQ,VM::VM1,"Proposed Study Sequence","ProposedStudySequence",true }, + {0x2130,0x00c0,VR::SQ,VM::VM1,"Original Image Sequence","OriginalImageSequence",true }, + {0x2200,0x0001,VR::CS,VM::VM1,"Label Using Information Extracted From Instances","LabelUsingInformationExtractedFromInstances",false }, + {0x2200,0x0002,VR::UT,VM::VM1,"Label Text","LabelText",false }, + {0x2200,0x0003,VR::CS,VM::VM1,"Label Style Selection","LabelStyleSelection",false }, + {0x2200,0x0004,VR::LT,VM::VM1,"Media Disposition","MediaDisposition",false }, + {0x2200,0x0005,VR::LT,VM::VM1,"Barcode Value","BarcodeValue",false }, + {0x2200,0x0006,VR::CS,VM::VM1,"Barcode Symbology","BarcodeSymbology",false }, + {0x2200,0x0007,VR::CS,VM::VM1,"Allow Media Splitting","AllowMediaSplitting",false }, + {0x2200,0x0008,VR::CS,VM::VM1,"Include Non-DICOM Objects","IncludeNonDICOMObjects",false }, + {0x2200,0x0009,VR::CS,VM::VM1,"Include Display Application","IncludeDisplayApplication",false }, + {0x2200,0x000a,VR::CS,VM::VM1,"Preserve Composite Instances After Media Creation","PreserveCompositeInstancesAfterMediaCreation",false }, + {0x2200,0x000b,VR::US,VM::VM1,"Total Number of Pieces of Media Created","TotalNumberOfPiecesOfMediaCreated",false }, + {0x2200,0x000c,VR::LO,VM::VM1,"Requested Media Application Profile","RequestedMediaApplicationProfile",false }, + {0x2200,0x000d,VR::SQ,VM::VM1,"Referenced Storage Media Sequence","ReferencedStorageMediaSequence",false }, + {0x2200,0x000e,VR::AT,VM::VM1_n,"Failure Attributes","FailureAttributes",false }, + {0x2200,0x000f,VR::CS,VM::VM1,"Allow Lossy Compression","AllowLossyCompression",false }, + {0x2200,0x0020,VR::CS,VM::VM1,"Request Priority","RequestPriority",false }, + {0x3002,0x0002,VR::SH,VM::VM1,"RT Image Label","RTImageLabel",false }, + {0x3002,0x0003,VR::LO,VM::VM1,"RT Image Name","RTImageName",false }, + {0x3002,0x0004,VR::ST,VM::VM1,"RT Image Description","RTImageDescription",false }, + {0x3002,0x000a,VR::CS,VM::VM1,"Reported Values Origin","ReportedValuesOrigin",false }, + {0x3002,0x000c,VR::CS,VM::VM1,"RT Image Plane","RTImagePlane",false }, + {0x3002,0x000d,VR::DS,VM::VM3,"X-Ray Image Receptor Translation","XRayImageReceptorTranslation",false }, + {0x3002,0x000e,VR::DS,VM::VM1,"X-Ray Image Receptor Angle","XRayImageReceptorAngle",false }, + {0x3002,0x0010,VR::DS,VM::VM6,"RT Image Orientation","RTImageOrientation",false }, + {0x3002,0x0011,VR::DS,VM::VM2,"Image Plane Pixel Spacing","ImagePlanePixelSpacing",false }, + {0x3002,0x0012,VR::DS,VM::VM2,"RT Image Position","RTImagePosition",false }, + {0x3002,0x0020,VR::SH,VM::VM1,"Radiation Machine Name","RadiationMachineName",false }, + {0x3002,0x0022,VR::DS,VM::VM1,"Radiation Machine SAD","RadiationMachineSAD",false }, + {0x3002,0x0024,VR::DS,VM::VM1,"Radiation Machine SSD","RadiationMachineSSD",false }, + {0x3002,0x0026,VR::DS,VM::VM1,"RT Image SID","RTImageSID",false }, + {0x3002,0x0028,VR::DS,VM::VM1,"Source to Reference Object Distance","SourceToReferenceObjectDistance",false }, + {0x3002,0x0029,VR::IS,VM::VM1,"Fraction Number","FractionNumber",false }, + {0x3002,0x0030,VR::SQ,VM::VM1,"Exposure Sequence","ExposureSequence",false }, + {0x3002,0x0032,VR::DS,VM::VM1,"Meterset Exposure","MetersetExposure",false }, + {0x3002,0x0034,VR::DS,VM::VM4,"Diaphragm Position","DiaphragmPosition",false }, + {0x3002,0x0040,VR::SQ,VM::VM1,"Fluence Map Sequence","FluenceMapSequence",false }, + {0x3002,0x0041,VR::CS,VM::VM1,"Fluence Data Source","FluenceDataSource",false }, + {0x3002,0x0042,VR::DS,VM::VM1,"Fluence Data Scale","FluenceDataScale",false }, + {0x3002,0x0050,VR::SQ,VM::VM1,"Primary Fluence Mode Sequence","PrimaryFluenceModeSequence",false }, + {0x3002,0x0051,VR::CS,VM::VM1,"Fluence Mode","FluenceMode",false }, + {0x3002,0x0052,VR::SH,VM::VM1,"Fluence Mode ID","FluenceModeID",false }, + {0x3004,0x0001,VR::CS,VM::VM1,"DVH Type","DVHType",false }, + {0x3004,0x0002,VR::CS,VM::VM1,"Dose Units","DoseUnits",false }, + {0x3004,0x0004,VR::CS,VM::VM1,"Dose Type","DoseType",false }, + {0x3004,0x0006,VR::LO,VM::VM1,"Dose Comment","DoseComment",false }, + {0x3004,0x0008,VR::DS,VM::VM3,"Normalization Point","NormalizationPoint",false }, + {0x3004,0x000a,VR::CS,VM::VM1,"Dose Summation Type","DoseSummationType",false }, + {0x3004,0x000c,VR::DS,VM::VM2_n,"Grid Frame Offset Vector","GridFrameOffsetVector",false }, + {0x3004,0x000e,VR::DS,VM::VM1,"Dose Grid Scaling","DoseGridScaling",false }, + {0x3004,0x0010,VR::SQ,VM::VM1,"RT Dose ROI Sequence","RTDoseROISequence",false }, + {0x3004,0x0012,VR::DS,VM::VM1,"Dose Value","DoseValue",false }, + {0x3004,0x0014,VR::CS,VM::VM1_3,"Tissue Heterogeneity Correction","TissueHeterogeneityCorrection",false }, + {0x3004,0x0040,VR::DS,VM::VM3,"DVH Normalization Point","DVHNormalizationPoint",false }, + {0x3004,0x0042,VR::DS,VM::VM1,"DVH Normalization Dose Value","DVHNormalizationDoseValue",false }, + {0x3004,0x0050,VR::SQ,VM::VM1,"DVH Sequence","DVHSequence",false }, + {0x3004,0x0052,VR::DS,VM::VM1,"DVH Dose Scaling","DVHDoseScaling",false }, + {0x3004,0x0054,VR::CS,VM::VM1,"DVH Volume Units","DVHVolumeUnits",false }, + {0x3004,0x0056,VR::IS,VM::VM1,"DVH Number of Bins","DVHNumberOfBins",false }, + {0x3004,0x0058,VR::DS,VM::VM2_2n,"DVH Data","DVHData",false }, + {0x3004,0x0060,VR::SQ,VM::VM1,"DVH Referenced ROI Sequence","DVHReferencedROISequence",false }, + {0x3004,0x0062,VR::CS,VM::VM1,"DVH ROI Contribution Type","DVHROIContributionType",false }, + {0x3004,0x0070,VR::DS,VM::VM1,"DVH Minimum Dose","DVHMinimumDose",false }, + {0x3004,0x0072,VR::DS,VM::VM1,"DVH Maximum Dose","DVHMaximumDose",false }, + {0x3004,0x0074,VR::DS,VM::VM1,"DVH Mean Dose","DVHMeanDose",false }, + {0x3006,0x0002,VR::SH,VM::VM1,"Structure Set Label","StructureSetLabel",false }, + {0x3006,0x0004,VR::LO,VM::VM1,"Structure Set Name","StructureSetName",false }, + {0x3006,0x0006,VR::ST,VM::VM1,"Structure Set Description","StructureSetDescription",false }, + {0x3006,0x0008,VR::DA,VM::VM1,"Structure Set Date","StructureSetDate",false }, + {0x3006,0x0009,VR::TM,VM::VM1,"Structure Set Time","StructureSetTime",false }, + {0x3006,0x0010,VR::SQ,VM::VM1,"Referenced Frame of Reference Sequence","ReferencedFrameOfReferenceSequence",false }, + {0x3006,0x0012,VR::SQ,VM::VM1,"RT Referenced Study Sequence","RTReferencedStudySequence",false }, + {0x3006,0x0014,VR::SQ,VM::VM1,"RT Referenced Series Sequence","RTReferencedSeriesSequence",false }, + {0x3006,0x0016,VR::SQ,VM::VM1,"Contour Image Sequence","ContourImageSequence",false }, + {0x3006,0x0020,VR::SQ,VM::VM1,"Structure Set ROI Sequence","StructureSetROISequence",false }, + {0x3006,0x0022,VR::IS,VM::VM1,"ROI Number","ROINumber",false }, + {0x3006,0x0024,VR::UI,VM::VM1,"Referenced Frame of Reference UID","ReferencedFrameOfReferenceUID",false }, + {0x3006,0x0026,VR::LO,VM::VM1,"ROI Name","ROIName",false }, + {0x3006,0x0028,VR::ST,VM::VM1,"ROI Description","ROIDescription",false }, + {0x3006,0x002a,VR::IS,VM::VM3,"ROI Display Color","ROIDisplayColor",false }, + {0x3006,0x002c,VR::DS,VM::VM1,"ROI Volume","ROIVolume",false }, + {0x3006,0x0030,VR::SQ,VM::VM1,"RT Related ROI Sequence","RTRelatedROISequence",false }, + {0x3006,0x0033,VR::CS,VM::VM1,"RT ROI Relationship","RTROIRelationship",false }, + {0x3006,0x0036,VR::CS,VM::VM1,"ROI Generation Algorithm","ROIGenerationAlgorithm",false }, + {0x3006,0x0038,VR::LO,VM::VM1,"ROI Generation Description","ROIGenerationDescription",false }, + {0x3006,0x0039,VR::SQ,VM::VM1,"ROI Contour Sequence","ROIContourSequence",false }, + {0x3006,0x0040,VR::SQ,VM::VM1,"Contour Sequence","ContourSequence",false }, + {0x3006,0x0042,VR::CS,VM::VM1,"Contour Geometric Type","ContourGeometricType",false }, + {0x3006,0x0044,VR::DS,VM::VM1,"Contour Slab Thickness","ContourSlabThickness",false }, + {0x3006,0x0045,VR::DS,VM::VM3,"Contour Offset Vector","ContourOffsetVector",false }, + {0x3006,0x0046,VR::IS,VM::VM1,"Number of Contour Points","NumberOfContourPoints",false }, + {0x3006,0x0048,VR::IS,VM::VM1,"Contour Number","ContourNumber",false }, + {0x3006,0x0049,VR::IS,VM::VM1_n,"Attached Contours","AttachedContours",false }, + {0x3006,0x0050,VR::DS,VM::VM3_3n,"Contour Data","ContourData",false }, + {0x3006,0x0080,VR::SQ,VM::VM1,"RT ROI Observations Sequence","RTROIObservationsSequence",false }, + {0x3006,0x0082,VR::IS,VM::VM1,"Observation Number","ObservationNumber",false }, + {0x3006,0x0084,VR::IS,VM::VM1,"Referenced ROI Number","ReferencedROINumber",false }, + {0x3006,0x0085,VR::SH,VM::VM1,"ROI Observation Label","ROIObservationLabel",false }, + {0x3006,0x0086,VR::SQ,VM::VM1,"RT ROI Identification Code Sequence","RTROIIdentificationCodeSequence",false }, + {0x3006,0x0088,VR::ST,VM::VM1,"ROI Observation Description","ROIObservationDescription",false }, + {0x3006,0x00a0,VR::SQ,VM::VM1,"Related RT ROI Observations Sequence","RelatedRTROIObservationsSequence",false }, + {0x3006,0x00a4,VR::CS,VM::VM1,"RT ROI Interpreted Type","RTROIInterpretedType",false }, + {0x3006,0x00a6,VR::PN,VM::VM1,"ROI Interpreter","ROIInterpreter",false }, + {0x3006,0x00b0,VR::SQ,VM::VM1,"ROI Physical Properties Sequence","ROIPhysicalPropertiesSequence",false }, + {0x3006,0x00b2,VR::CS,VM::VM1,"ROI Physical Property","ROIPhysicalProperty",false }, + {0x3006,0x00b4,VR::DS,VM::VM1,"ROI Physical Property Value","ROIPhysicalPropertyValue",false }, + {0x3006,0x00b6,VR::SQ,VM::VM1,"ROI Elemental Composition Sequence","ROIElementalCompositionSequence",false }, + {0x3006,0x00b7,VR::US,VM::VM1,"ROI Elemental Composition Atomic Number","ROIElementalCompositionAtomicNumber",false }, + {0x3006,0x00b8,VR::FL,VM::VM1,"ROI Elemental Composition Atomic Mass Fraction","ROIElementalCompositionAtomicMassFraction",false }, + {0x3006,0x00c0,VR::SQ,VM::VM1,"Frame of Reference Relationship Sequence","FrameOfReferenceRelationshipSequence",false }, + {0x3006,0x00c2,VR::UI,VM::VM1,"Related Frame of Reference UID","RelatedFrameOfReferenceUID",false }, + {0x3006,0x00c4,VR::CS,VM::VM1,"Frame of Reference Transformation Type","FrameOfReferenceTransformationType",false }, + {0x3006,0x00c6,VR::DS,VM::VM16,"Frame of Reference Transformation Matrix","FrameOfReferenceTransformationMatrix",false }, + {0x3006,0x00c8,VR::LO,VM::VM1,"Frame of Reference Transformation Comment","FrameOfReferenceTransformationComment",false }, + {0x3008,0x0010,VR::SQ,VM::VM1,"Measured Dose Reference Sequence","MeasuredDoseReferenceSequence",false }, + {0x3008,0x0012,VR::ST,VM::VM1,"Measured Dose Description","MeasuredDoseDescription",false }, + {0x3008,0x0014,VR::CS,VM::VM1,"Measured Dose Type","MeasuredDoseType",false }, + {0x3008,0x0016,VR::DS,VM::VM1,"Measured Dose Value","MeasuredDoseValue",false }, + {0x3008,0x0020,VR::SQ,VM::VM1,"Treatment Session Beam Sequence","TreatmentSessionBeamSequence",false }, + {0x3008,0x0021,VR::SQ,VM::VM1,"Treatment Session Ion Beam Sequence","TreatmentSessionIonBeamSequence",false }, + {0x3008,0x0022,VR::IS,VM::VM1,"Current Fraction Number","CurrentFractionNumber",false }, + {0x3008,0x0024,VR::DA,VM::VM1,"Treatment Control Point Date","TreatmentControlPointDate",false }, + {0x3008,0x0025,VR::TM,VM::VM1,"Treatment Control Point Time","TreatmentControlPointTime",false }, + {0x3008,0x002a,VR::CS,VM::VM1,"Treatment Termination Status","TreatmentTerminationStatus",false }, + {0x3008,0x002b,VR::SH,VM::VM1,"Treatment Termination Code","TreatmentTerminationCode",false }, + {0x3008,0x002c,VR::CS,VM::VM1,"Treatment Verification Status","TreatmentVerificationStatus",false }, + {0x3008,0x0030,VR::SQ,VM::VM1,"Referenced Treatment Record Sequence","ReferencedTreatmentRecordSequence",false }, + {0x3008,0x0032,VR::DS,VM::VM1,"Specified Primary Meterset","SpecifiedPrimaryMeterset",false }, + {0x3008,0x0033,VR::DS,VM::VM1,"Specified Secondary Meterset","SpecifiedSecondaryMeterset",false }, + {0x3008,0x0036,VR::DS,VM::VM1,"Delivered Primary Meterset","DeliveredPrimaryMeterset",false }, + {0x3008,0x0037,VR::DS,VM::VM1,"Delivered Secondary Meterset","DeliveredSecondaryMeterset",false }, + {0x3008,0x003a,VR::DS,VM::VM1,"Specified Treatment Time","SpecifiedTreatmentTime",false }, + {0x3008,0x003b,VR::DS,VM::VM1,"Delivered Treatment Time","DeliveredTreatmentTime",false }, + {0x3008,0x0040,VR::SQ,VM::VM1,"Control Point Delivery Sequence","ControlPointDeliverySequence",false }, + {0x3008,0x0041,VR::SQ,VM::VM1,"Ion Control Point Delivery Sequence","IonControlPointDeliverySequence",false }, + {0x3008,0x0042,VR::DS,VM::VM1,"Specified Meterset","SpecifiedMeterset",false }, + {0x3008,0x0044,VR::DS,VM::VM1,"Delivered Meterset","DeliveredMeterset",false }, + {0x3008,0x0045,VR::FL,VM::VM1,"Meterset Rate Set","MetersetRateSet",false }, + {0x3008,0x0046,VR::FL,VM::VM1,"Meterset Rate Delivered","MetersetRateDelivered",false }, + {0x3008,0x0047,VR::FL,VM::VM1_n,"Scan Spot Metersets Delivered","ScanSpotMetersetsDelivered",false }, + {0x3008,0x0048,VR::DS,VM::VM1,"Dose Rate Delivered","DoseRateDelivered",false }, + {0x3008,0x0050,VR::SQ,VM::VM1,"Treatment Summary Calculated Dose Reference Sequence","TreatmentSummaryCalculatedDoseReferenceSequence",false }, + {0x3008,0x0052,VR::DS,VM::VM1,"Cumulative Dose to Dose Reference","CumulativeDoseToDoseReference",false }, + {0x3008,0x0054,VR::DA,VM::VM1,"First Treatment Date","FirstTreatmentDate",false }, + {0x3008,0x0056,VR::DA,VM::VM1,"Most Recent Treatment Date","MostRecentTreatmentDate",false }, + {0x3008,0x005a,VR::IS,VM::VM1,"Number of Fractions Delivered","NumberOfFractionsDelivered",false }, + {0x3008,0x0060,VR::SQ,VM::VM1,"Override Sequence","OverrideSequence",false }, + {0x3008,0x0061,VR::AT,VM::VM1,"Parameter Sequence Pointer","ParameterSequencePointer",false }, + {0x3008,0x0062,VR::AT,VM::VM1,"Override Parameter Pointer","OverrideParameterPointer",false }, + {0x3008,0x0063,VR::IS,VM::VM1,"Parameter Item Index","ParameterItemIndex",false }, + {0x3008,0x0064,VR::IS,VM::VM1,"Measured Dose Reference Number","MeasuredDoseReferenceNumber",false }, + {0x3008,0x0065,VR::AT,VM::VM1,"Parameter Pointer","ParameterPointer",false }, + {0x3008,0x0066,VR::ST,VM::VM1,"Override Reason","OverrideReason",false }, + {0x3008,0x0068,VR::SQ,VM::VM1,"Corrected Parameter Sequence","CorrectedParameterSequence",false }, + {0x3008,0x006a,VR::FL,VM::VM1,"Correction Value","CorrectionValue",false }, + {0x3008,0x0070,VR::SQ,VM::VM1,"Calculated Dose Reference Sequence","CalculatedDoseReferenceSequence",false }, + {0x3008,0x0072,VR::IS,VM::VM1,"Calculated Dose Reference Number","CalculatedDoseReferenceNumber",false }, + {0x3008,0x0074,VR::ST,VM::VM1,"Calculated Dose Reference Description","CalculatedDoseReferenceDescription",false }, + {0x3008,0x0076,VR::DS,VM::VM1,"Calculated Dose Reference Dose Value","CalculatedDoseReferenceDoseValue",false }, + {0x3008,0x0078,VR::DS,VM::VM1,"Start Meterset","StartMeterset",false }, + {0x3008,0x007a,VR::DS,VM::VM1,"End Meterset","EndMeterset",false }, + {0x3008,0x0080,VR::SQ,VM::VM1,"Referenced Measured Dose Reference Sequence","ReferencedMeasuredDoseReferenceSequence",false }, + {0x3008,0x0082,VR::IS,VM::VM1,"Referenced Measured Dose Reference Number","ReferencedMeasuredDoseReferenceNumber",false }, + {0x3008,0x0090,VR::SQ,VM::VM1,"Referenced Calculated Dose Reference Sequence","ReferencedCalculatedDoseReferenceSequence",false }, + {0x3008,0x0092,VR::IS,VM::VM1,"Referenced Calculated Dose Reference Number","ReferencedCalculatedDoseReferenceNumber",false }, + {0x3008,0x00a0,VR::SQ,VM::VM1,"Beam Limiting Device Leaf Pairs Sequence","BeamLimitingDeviceLeafPairsSequence",false }, + {0x3008,0x00b0,VR::SQ,VM::VM1,"Recorded Wedge Sequence","RecordedWedgeSequence",false }, + {0x3008,0x00c0,VR::SQ,VM::VM1,"Recorded Compensator Sequence","RecordedCompensatorSequence",false }, + {0x3008,0x00d0,VR::SQ,VM::VM1,"Recorded Block Sequence","RecordedBlockSequence",false }, + {0x3008,0x00e0,VR::SQ,VM::VM1,"Treatment Summary Measured Dose Reference Sequence","TreatmentSummaryMeasuredDoseReferenceSequence",false }, + {0x3008,0x00f0,VR::SQ,VM::VM1,"Recorded Snout Sequence","RecordedSnoutSequence",false }, + {0x3008,0x00f2,VR::SQ,VM::VM1,"Recorded Range Shifter Sequence","RecordedRangeShifterSequence",false }, + {0x3008,0x00f4,VR::SQ,VM::VM1,"Recorded Lateral Spreading Device Sequence","RecordedLateralSpreadingDeviceSequence",false }, + {0x3008,0x00f6,VR::SQ,VM::VM1,"Recorded Range Modulator Sequence","RecordedRangeModulatorSequence",false }, + {0x3008,0x0100,VR::SQ,VM::VM1,"Recorded Source Sequence","RecordedSourceSequence",false }, + {0x3008,0x0105,VR::LO,VM::VM1,"Source Serial Number","SourceSerialNumber",false }, + {0x3008,0x0110,VR::SQ,VM::VM1,"Treatment Session Application Setup Sequence","TreatmentSessionApplicationSetupSequence",false }, + {0x3008,0x0116,VR::CS,VM::VM1,"Application Setup Check","ApplicationSetupCheck",false }, + {0x3008,0x0120,VR::SQ,VM::VM1,"Recorded Brachy Accessory Device Sequence","RecordedBrachyAccessoryDeviceSequence",false }, + {0x3008,0x0122,VR::IS,VM::VM1,"Referenced Brachy Accessory Device Number","ReferencedBrachyAccessoryDeviceNumber",false }, + {0x3008,0x0130,VR::SQ,VM::VM1,"Recorded Channel Sequence","RecordedChannelSequence",false }, + {0x3008,0x0132,VR::DS,VM::VM1,"Specified Channel Total Time","SpecifiedChannelTotalTime",false }, + {0x3008,0x0134,VR::DS,VM::VM1,"Delivered Channel Total Time","DeliveredChannelTotalTime",false }, + {0x3008,0x0136,VR::IS,VM::VM1,"Specified Number of Pulses","SpecifiedNumberOfPulses",false }, + {0x3008,0x0138,VR::IS,VM::VM1,"Delivered Number of Pulses","DeliveredNumberOfPulses",false }, + {0x3008,0x013a,VR::DS,VM::VM1,"Specified Pulse Repetition Interval","SpecifiedPulseRepetitionInterval",false }, + {0x3008,0x013c,VR::DS,VM::VM1,"Delivered Pulse Repetition Interval","DeliveredPulseRepetitionInterval",false }, + {0x3008,0x0140,VR::SQ,VM::VM1,"Recorded Source Applicator Sequence","RecordedSourceApplicatorSequence",false }, + {0x3008,0x0142,VR::IS,VM::VM1,"Referenced Source Applicator Number","ReferencedSourceApplicatorNumber",false }, + {0x3008,0x0150,VR::SQ,VM::VM1,"Recorded Channel Shield Sequence","RecordedChannelShieldSequence",false }, + {0x3008,0x0152,VR::IS,VM::VM1,"Referenced Channel Shield Number","ReferencedChannelShieldNumber",false }, + {0x3008,0x0160,VR::SQ,VM::VM1,"Brachy Control Point Delivered Sequence","BrachyControlPointDeliveredSequence",false }, + {0x3008,0x0162,VR::DA,VM::VM1,"Safe Position Exit Date","SafePositionExitDate",false }, + {0x3008,0x0164,VR::TM,VM::VM1,"Safe Position Exit Time","SafePositionExitTime",false }, + {0x3008,0x0166,VR::DA,VM::VM1,"Safe Position Return Date","SafePositionReturnDate",false }, + {0x3008,0x0168,VR::TM,VM::VM1,"Safe Position Return Time","SafePositionReturnTime",false }, + {0x3008,0x0200,VR::CS,VM::VM1,"Current Treatment Status","CurrentTreatmentStatus",false }, + {0x3008,0x0202,VR::ST,VM::VM1,"Treatment Status Comment","TreatmentStatusComment",false }, + {0x3008,0x0220,VR::SQ,VM::VM1,"Fraction Group Summary Sequence","FractionGroupSummarySequence",false }, + {0x3008,0x0223,VR::IS,VM::VM1,"Referenced Fraction Number","ReferencedFractionNumber",false }, + {0x3008,0x0224,VR::CS,VM::VM1,"Fraction Group Type","FractionGroupType",false }, + {0x3008,0x0230,VR::CS,VM::VM1,"Beam Stopper Position","BeamStopperPosition",false }, + {0x3008,0x0240,VR::SQ,VM::VM1,"Fraction Status Summary Sequence","FractionStatusSummarySequence",false }, + {0x3008,0x0250,VR::DA,VM::VM1,"Treatment Date","TreatmentDate",false }, + {0x3008,0x0251,VR::TM,VM::VM1,"Treatment Time","TreatmentTime",false }, + {0x300a,0x0002,VR::SH,VM::VM1,"RT Plan Label","RTPlanLabel",false }, + {0x300a,0x0003,VR::LO,VM::VM1,"RT Plan Name","RTPlanName",false }, + {0x300a,0x0004,VR::ST,VM::VM1,"RT Plan Description","RTPlanDescription",false }, + {0x300a,0x0006,VR::DA,VM::VM1,"RT Plan Date","RTPlanDate",false }, + {0x300a,0x0007,VR::TM,VM::VM1,"RT Plan Time","RTPlanTime",false }, + {0x300a,0x0009,VR::LO,VM::VM1_n,"Treatment Protocols","TreatmentProtocols",false }, + {0x300a,0x000a,VR::CS,VM::VM1,"Plan Intent","PlanIntent",false }, + {0x300a,0x000b,VR::LO,VM::VM1_n,"Treatment Sites","TreatmentSites",false }, + {0x300a,0x000c,VR::CS,VM::VM1,"RT Plan Geometry","RTPlanGeometry",false }, + {0x300a,0x000e,VR::ST,VM::VM1,"Prescription Description","PrescriptionDescription",false }, + {0x300a,0x0010,VR::SQ,VM::VM1,"Dose Reference Sequence","DoseReferenceSequence",false }, + {0x300a,0x0012,VR::IS,VM::VM1,"Dose Reference Number","DoseReferenceNumber",false }, + {0x300a,0x0013,VR::UI,VM::VM1,"Dose Reference UID","DoseReferenceUID",false }, + {0x300a,0x0014,VR::CS,VM::VM1,"Dose Reference Structure Type","DoseReferenceStructureType",false }, + {0x300a,0x0015,VR::CS,VM::VM1,"Nominal Beam Energy Unit","NominalBeamEnergyUnit",false }, + {0x300a,0x0016,VR::LO,VM::VM1,"Dose Reference Description","DoseReferenceDescription",false }, + {0x300a,0x0018,VR::DS,VM::VM3,"Dose Reference Point Coordinates","DoseReferencePointCoordinates",false }, + {0x300a,0x001a,VR::DS,VM::VM1,"Nominal Prior Dose","NominalPriorDose",false }, + {0x300a,0x0020,VR::CS,VM::VM1,"Dose Reference Type","DoseReferenceType",false }, + {0x300a,0x0021,VR::DS,VM::VM1,"Constraint Weight","ConstraintWeight",false }, + {0x300a,0x0022,VR::DS,VM::VM1,"Delivery Warning Dose","DeliveryWarningDose",false }, + {0x300a,0x0023,VR::DS,VM::VM1,"Delivery Maximum Dose","DeliveryMaximumDose",false }, + {0x300a,0x0025,VR::DS,VM::VM1,"Target Minimum Dose","TargetMinimumDose",false }, + {0x300a,0x0026,VR::DS,VM::VM1,"Target Prescription Dose","TargetPrescriptionDose",false }, + {0x300a,0x0027,VR::DS,VM::VM1,"Target Maximum Dose","TargetMaximumDose",false }, + {0x300a,0x0028,VR::DS,VM::VM1,"Target Underdose Volume Fraction","TargetUnderdoseVolumeFraction",false }, + {0x300a,0x002a,VR::DS,VM::VM1,"Organ at Risk Full-volume Dose","OrganAtRiskFullVolumeDose",false }, + {0x300a,0x002b,VR::DS,VM::VM1,"Organ at Risk Limit Dose","OrganAtRiskLimitDose",false }, + {0x300a,0x002c,VR::DS,VM::VM1,"Organ at Risk Maximum Dose","OrganAtRiskMaximumDose",false }, + {0x300a,0x002d,VR::DS,VM::VM1,"Organ at Risk Overdose Volume Fraction","OrganAtRiskOverdoseVolumeFraction",false }, + {0x300a,0x0040,VR::SQ,VM::VM1,"Tolerance Table Sequence","ToleranceTableSequence",false }, + {0x300a,0x0042,VR::IS,VM::VM1,"Tolerance Table Number","ToleranceTableNumber",false }, + {0x300a,0x0043,VR::SH,VM::VM1,"Tolerance Table Label","ToleranceTableLabel",false }, + {0x300a,0x0044,VR::DS,VM::VM1,"Gantry Angle Tolerance","GantryAngleTolerance",false }, + {0x300a,0x0046,VR::DS,VM::VM1,"Beam Limiting Device Angle Tolerance","BeamLimitingDeviceAngleTolerance",false }, + {0x300a,0x0048,VR::SQ,VM::VM1,"Beam Limiting Device Tolerance Sequence","BeamLimitingDeviceToleranceSequence",false }, + {0x300a,0x004a,VR::DS,VM::VM1,"Beam Limiting Device Position Tolerance","BeamLimitingDevicePositionTolerance",false }, + {0x300a,0x004b,VR::FL,VM::VM1,"Snout Position Tolerance","SnoutPositionTolerance",false }, + {0x300a,0x004c,VR::DS,VM::VM1,"Patient Support Angle Tolerance","PatientSupportAngleTolerance",false }, + {0x300a,0x004e,VR::DS,VM::VM1,"Table Top Eccentric Angle Tolerance","TableTopEccentricAngleTolerance",false }, + {0x300a,0x004f,VR::FL,VM::VM1,"Table Top Pitch Angle Tolerance","TableTopPitchAngleTolerance",false }, + {0x300a,0x0050,VR::FL,VM::VM1,"Table Top Roll Angle Tolerance","TableTopRollAngleTolerance",false }, + {0x300a,0x0051,VR::DS,VM::VM1,"Table Top Vertical Position Tolerance","TableTopVerticalPositionTolerance",false }, + {0x300a,0x0052,VR::DS,VM::VM1,"Table Top Longitudinal Position Tolerance","TableTopLongitudinalPositionTolerance",false }, + {0x300a,0x0053,VR::DS,VM::VM1,"Table Top Lateral Position Tolerance","TableTopLateralPositionTolerance",false }, + {0x300a,0x0055,VR::CS,VM::VM1,"RT Plan Relationship","RTPlanRelationship",false }, + {0x300a,0x0070,VR::SQ,VM::VM1,"Fraction Group Sequence","FractionGroupSequence",false }, + {0x300a,0x0071,VR::IS,VM::VM1,"Fraction Group Number","FractionGroupNumber",false }, + {0x300a,0x0072,VR::LO,VM::VM1,"Fraction Group Description","FractionGroupDescription",false }, + {0x300a,0x0078,VR::IS,VM::VM1,"Number of Fractions Planned","NumberOfFractionsPlanned",false }, + {0x300a,0x0079,VR::IS,VM::VM1,"Number of Fraction Pattern Digits Per Day","NumberOfFractionPatternDigitsPerDay",false }, + {0x300a,0x007a,VR::IS,VM::VM1,"Repeat Fraction Cycle Length","RepeatFractionCycleLength",false }, + {0x300a,0x007b,VR::LT,VM::VM1,"Fraction Pattern","FractionPattern",false }, + {0x300a,0x0080,VR::IS,VM::VM1,"Number of Beams","NumberOfBeams",false }, + {0x300a,0x0082,VR::DS,VM::VM3,"Beam Dose Specification Point","BeamDoseSpecificationPoint",false }, + {0x300a,0x0084,VR::DS,VM::VM1,"Beam Dose","BeamDose",false }, + {0x300a,0x0086,VR::DS,VM::VM1,"Beam Meterset","BeamMeterset",false }, + {0x300a,0x0088,VR::FL,VM::VM1,"Beam Dose Point Depth","BeamDosePointDepth",false }, + {0x300a,0x0089,VR::FL,VM::VM1,"Beam Dose Point Equivalent Depth","BeamDosePointEquivalentDepth",false }, + {0x300a,0x008a,VR::FL,VM::VM1,"Beam Dose Point SSD","BeamDosePointSSD",false }, + {0x300a,0x00a0,VR::IS,VM::VM1,"Number of Brachy Application Setups","NumberOfBrachyApplicationSetups",false }, + {0x300a,0x00a2,VR::DS,VM::VM3,"Brachy Application Setup Dose Specification Point","BrachyApplicationSetupDoseSpecificationPoint",false }, + {0x300a,0x00a4,VR::DS,VM::VM1,"Brachy Application Setup Dose","BrachyApplicationSetupDose",false }, + {0x300a,0x00b0,VR::SQ,VM::VM1,"Beam Sequence","BeamSequence",false }, + {0x300a,0x00b2,VR::SH,VM::VM1,"Treatment Machine Name","TreatmentMachineName",false }, + {0x300a,0x00b3,VR::CS,VM::VM1,"Primary Dosimeter Unit","PrimaryDosimeterUnit",false }, + {0x300a,0x00b4,VR::DS,VM::VM1,"Source-Axis Distance","SourceAxisDistance",false }, + {0x300a,0x00b6,VR::SQ,VM::VM1,"Beam Limiting Device Sequence","BeamLimitingDeviceSequence",false }, + {0x300a,0x00b8,VR::CS,VM::VM1,"RT Beam Limiting Device Type","RTBeamLimitingDeviceType",false }, + {0x300a,0x00ba,VR::DS,VM::VM1,"Source to Beam Limiting Device Distance","SourceToBeamLimitingDeviceDistance",false }, + {0x300a,0x00bb,VR::FL,VM::VM1,"Isocenter to Beam Limiting Device Distance","IsocenterToBeamLimitingDeviceDistance",false }, + {0x300a,0x00bc,VR::IS,VM::VM1,"Number of Leaf/Jaw Pairs","NumberOfLeafJawPairs",false }, + {0x300a,0x00be,VR::DS,VM::VM3_n,"Leaf Position Boundaries","LeafPositionBoundaries",false }, + {0x300a,0x00c0,VR::IS,VM::VM1,"Beam Number","BeamNumber",false }, + {0x300a,0x00c2,VR::LO,VM::VM1,"Beam Name","BeamName",false }, + {0x300a,0x00c3,VR::ST,VM::VM1,"Beam Description","BeamDescription",false }, + {0x300a,0x00c4,VR::CS,VM::VM1,"Beam Type","BeamType",false }, + {0x300a,0x00c6,VR::CS,VM::VM1,"Radiation Type","RadiationType",false }, + {0x300a,0x00c7,VR::CS,VM::VM1,"High-Dose Technique Type","HighDoseTechniqueType",false }, + {0x300a,0x00c8,VR::IS,VM::VM1,"Reference Image Number","ReferenceImageNumber",false }, + {0x300a,0x00ca,VR::SQ,VM::VM1,"Planned Verification Image Sequence","PlannedVerificationImageSequence",false }, + {0x300a,0x00cc,VR::LO,VM::VM1_n,"Imaging Device-Specific Acquisition Parameters","ImagingDeviceSpecificAcquisitionParameters",false }, + {0x300a,0x00ce,VR::CS,VM::VM1,"Treatment Delivery Type","TreatmentDeliveryType",false }, + {0x300a,0x00d0,VR::IS,VM::VM1,"Number of Wedges","NumberOfWedges",false }, + {0x300a,0x00d1,VR::SQ,VM::VM1,"Wedge Sequence","WedgeSequence",false }, + {0x300a,0x00d2,VR::IS,VM::VM1,"Wedge Number","WedgeNumber",false }, + {0x300a,0x00d3,VR::CS,VM::VM1,"Wedge Type","WedgeType",false }, + {0x300a,0x00d4,VR::SH,VM::VM1,"Wedge ID","WedgeID",false }, + {0x300a,0x00d5,VR::IS,VM::VM1,"Wedge Angle","WedgeAngle",false }, + {0x300a,0x00d6,VR::DS,VM::VM1,"Wedge Factor","WedgeFactor",false }, + {0x300a,0x00d7,VR::FL,VM::VM1,"Total Wedge Tray Water-Equivalent Thickness","TotalWedgeTrayWaterEquivalentThickness",false }, + {0x300a,0x00d8,VR::DS,VM::VM1,"Wedge Orientation","WedgeOrientation",false }, + {0x300a,0x00d9,VR::FL,VM::VM1,"Isocenter to Wedge Tray Distance","IsocenterToWedgeTrayDistance",false }, + {0x300a,0x00da,VR::DS,VM::VM1,"Source to Wedge Tray Distance","SourceToWedgeTrayDistance",false }, + {0x300a,0x00db,VR::FL,VM::VM1,"Wedge Thin Edge Position","WedgeThinEdgePosition",false }, + {0x300a,0x00dc,VR::SH,VM::VM1,"Bolus ID","BolusID",false }, + {0x300a,0x00dd,VR::ST,VM::VM1,"Bolus Description","BolusDescription",false }, + {0x300a,0x00e0,VR::IS,VM::VM1,"Number of Compensators","NumberOfCompensators",false }, + {0x300a,0x00e1,VR::SH,VM::VM1,"Material ID","MaterialID",false }, + {0x300a,0x00e2,VR::DS,VM::VM1,"Total Compensator Tray Factor","TotalCompensatorTrayFactor",false }, + {0x300a,0x00e3,VR::SQ,VM::VM1,"Compensator Sequence","CompensatorSequence",false }, + {0x300a,0x00e4,VR::IS,VM::VM1,"Compensator Number","CompensatorNumber",false }, + {0x300a,0x00e5,VR::SH,VM::VM1,"Compensator ID","CompensatorID",false }, + {0x300a,0x00e6,VR::DS,VM::VM1,"Source to Compensator Tray Distance","SourceToCompensatorTrayDistance",false }, + {0x300a,0x00e7,VR::IS,VM::VM1,"Compensator Rows","CompensatorRows",false }, + {0x300a,0x00e8,VR::IS,VM::VM1,"Compensator Columns","CompensatorColumns",false }, + {0x300a,0x00e9,VR::DS,VM::VM2,"Compensator Pixel Spacing","CompensatorPixelSpacing",false }, + {0x300a,0x00ea,VR::DS,VM::VM2,"Compensator Position","CompensatorPosition",false }, + {0x300a,0x00eb,VR::DS,VM::VM1_n,"Compensator Transmission Data","CompensatorTransmissionData",false }, + {0x300a,0x00ec,VR::DS,VM::VM1_n,"Compensator Thickness Data","CompensatorThicknessData",false }, + {0x300a,0x00ed,VR::IS,VM::VM1,"Number of Boli","NumberOfBoli",false }, + {0x300a,0x00ee,VR::CS,VM::VM1,"Compensator Type","CompensatorType",false }, + {0x300a,0x00f0,VR::IS,VM::VM1,"Number of Blocks","NumberOfBlocks",false }, + {0x300a,0x00f2,VR::DS,VM::VM1,"Total Block Tray Factor","TotalBlockTrayFactor",false }, + {0x300a,0x00f3,VR::FL,VM::VM1,"Total Block Tray Water-Equivalent Thickness","TotalBlockTrayWaterEquivalentThickness",false }, + {0x300a,0x00f4,VR::SQ,VM::VM1,"Block Sequence","BlockSequence",false }, + {0x300a,0x00f5,VR::SH,VM::VM1,"Block Tray ID","BlockTrayID",false }, + {0x300a,0x00f6,VR::DS,VM::VM1,"Source to Block Tray Distance","SourceToBlockTrayDistance",false }, + {0x300a,0x00f7,VR::FL,VM::VM1,"Isocenter to Block Tray Distance","IsocenterToBlockTrayDistance",false }, + {0x300a,0x00f8,VR::CS,VM::VM1,"Block Type","BlockType",false }, + {0x300a,0x00f9,VR::LO,VM::VM1,"Accessory Code","AccessoryCode",false }, + {0x300a,0x00fa,VR::CS,VM::VM1,"Block Divergence","BlockDivergence",false }, + {0x300a,0x00fb,VR::CS,VM::VM1,"Block Mounting Position","BlockMountingPosition",false }, + {0x300a,0x00fc,VR::IS,VM::VM1,"Block Number","BlockNumber",false }, + {0x300a,0x00fe,VR::LO,VM::VM1,"Block Name","BlockName",false }, + {0x300a,0x0100,VR::DS,VM::VM1,"Block Thickness","BlockThickness",false }, + {0x300a,0x0102,VR::DS,VM::VM1,"Block Transmission","BlockTransmission",false }, + {0x300a,0x0104,VR::IS,VM::VM1,"Block Number of Points","BlockNumberOfPoints",false }, + {0x300a,0x0106,VR::DS,VM::VM2_2n,"Block Data","BlockData",false }, + {0x300a,0x0107,VR::SQ,VM::VM1,"Applicator Sequence","ApplicatorSequence",false }, + {0x300a,0x0108,VR::SH,VM::VM1,"Applicator ID","ApplicatorID",false }, + {0x300a,0x0109,VR::CS,VM::VM1,"Applicator Type","ApplicatorType",false }, + {0x300a,0x010a,VR::LO,VM::VM1,"Applicator Description","ApplicatorDescription",false }, + {0x300a,0x010c,VR::DS,VM::VM1,"Cumulative Dose Reference Coefficient","CumulativeDoseReferenceCoefficient",false }, + {0x300a,0x010e,VR::DS,VM::VM1,"Final Cumulative Meterset Weight","FinalCumulativeMetersetWeight",false }, + {0x300a,0x0110,VR::IS,VM::VM1,"Number of Control Points","NumberOfControlPoints",false }, + {0x300a,0x0111,VR::SQ,VM::VM1,"Control Point Sequence","ControlPointSequence",false }, + {0x300a,0x0112,VR::IS,VM::VM1,"Control Point Index","ControlPointIndex",false }, + {0x300a,0x0114,VR::DS,VM::VM1,"Nominal Beam Energy","NominalBeamEnergy",false }, + {0x300a,0x0115,VR::DS,VM::VM1,"Dose Rate Set","DoseRateSet",false }, + {0x300a,0x0116,VR::SQ,VM::VM1,"Wedge Position Sequence","WedgePositionSequence",false }, + {0x300a,0x0118,VR::CS,VM::VM1,"Wedge Position","WedgePosition",false }, + {0x300a,0x011a,VR::SQ,VM::VM1,"Beam Limiting Device Position Sequence","BeamLimitingDevicePositionSequence",false }, + {0x300a,0x011c,VR::DS,VM::VM2_2n,"Leaf/Jaw Positions","LeafJawPositions",false }, + {0x300a,0x011e,VR::DS,VM::VM1,"Gantry Angle","GantryAngle",false }, + {0x300a,0x011f,VR::CS,VM::VM1,"Gantry Rotation Direction","GantryRotationDirection",false }, + {0x300a,0x0120,VR::DS,VM::VM1,"Beam Limiting Device Angle","BeamLimitingDeviceAngle",false }, + {0x300a,0x0121,VR::CS,VM::VM1,"Beam Limiting Device Rotation Direction","BeamLimitingDeviceRotationDirection",false }, + {0x300a,0x0122,VR::DS,VM::VM1,"Patient Support Angle","PatientSupportAngle",false }, + {0x300a,0x0123,VR::CS,VM::VM1,"Patient Support Rotation Direction","PatientSupportRotationDirection",false }, + {0x300a,0x0124,VR::DS,VM::VM1,"Table Top Eccentric Axis Distance","TableTopEccentricAxisDistance",false }, + {0x300a,0x0125,VR::DS,VM::VM1,"Table Top Eccentric Angle","TableTopEccentricAngle",false }, + {0x300a,0x0126,VR::CS,VM::VM1,"Table Top Eccentric Rotation Direction","TableTopEccentricRotationDirection",false }, + {0x300a,0x0128,VR::DS,VM::VM1,"Table Top Vertical Position","TableTopVerticalPosition",false }, + {0x300a,0x0129,VR::DS,VM::VM1,"Table Top Longitudinal Position","TableTopLongitudinalPosition",false }, + {0x300a,0x012a,VR::DS,VM::VM1,"Table Top Lateral Position","TableTopLateralPosition",false }, + {0x300a,0x012c,VR::DS,VM::VM3,"Isocenter Position","IsocenterPosition",false }, + {0x300a,0x012e,VR::DS,VM::VM3,"Surface Entry Point","SurfaceEntryPoint",false }, + {0x300a,0x0130,VR::DS,VM::VM1,"Source to Surface Distance","SourceToSurfaceDistance",false }, + {0x300a,0x0134,VR::DS,VM::VM1,"Cumulative Meterset Weight","CumulativeMetersetWeight",false }, + {0x300a,0x0140,VR::FL,VM::VM1,"Table Top Pitch Angle","TableTopPitchAngle",false }, + {0x300a,0x0142,VR::CS,VM::VM1,"Table Top Pitch Rotation Direction","TableTopPitchRotationDirection",false }, + {0x300a,0x0144,VR::FL,VM::VM1,"Table Top Roll Angle","TableTopRollAngle",false }, + {0x300a,0x0146,VR::CS,VM::VM1,"Table Top Roll Rotation Direction","TableTopRollRotationDirection",false }, + {0x300a,0x0148,VR::FL,VM::VM1,"Head Fixation Angle","HeadFixationAngle",false }, + {0x300a,0x014a,VR::FL,VM::VM1,"Gantry Pitch Angle","GantryPitchAngle",false }, + {0x300a,0x014c,VR::CS,VM::VM1,"Gantry Pitch Rotation Direction","GantryPitchRotationDirection",false }, + {0x300a,0x014e,VR::FL,VM::VM1,"Gantry Pitch Angle Tolerance","GantryPitchAngleTolerance",false }, + {0x300a,0x0180,VR::SQ,VM::VM1,"Patient Setup Sequence","PatientSetupSequence",false }, + {0x300a,0x0182,VR::IS,VM::VM1,"Patient Setup Number","PatientSetupNumber",false }, + {0x300a,0x0183,VR::LO,VM::VM1,"Patient Setup Label","PatientSetupLabel",false }, + {0x300a,0x0184,VR::LO,VM::VM1,"Patient Additional Position","PatientAdditionalPosition",false }, + {0x300a,0x0190,VR::SQ,VM::VM1,"Fixation Device Sequence","FixationDeviceSequence",false }, + {0x300a,0x0192,VR::CS,VM::VM1,"Fixation Device Type","FixationDeviceType",false }, + {0x300a,0x0194,VR::SH,VM::VM1,"Fixation Device Label","FixationDeviceLabel",false }, + {0x300a,0x0196,VR::ST,VM::VM1,"Fixation Device Description","FixationDeviceDescription",false }, + {0x300a,0x0198,VR::SH,VM::VM1,"Fixation Device Position","FixationDevicePosition",false }, + {0x300a,0x0199,VR::FL,VM::VM1,"Fixation Device Pitch Angle","FixationDevicePitchAngle",false }, + {0x300a,0x019a,VR::FL,VM::VM1,"Fixation Device Roll Angle","FixationDeviceRollAngle",false }, + {0x300a,0x01a0,VR::SQ,VM::VM1,"Shielding Device Sequence","ShieldingDeviceSequence",false }, + {0x300a,0x01a2,VR::CS,VM::VM1,"Shielding Device Type","ShieldingDeviceType",false }, + {0x300a,0x01a4,VR::SH,VM::VM1,"Shielding Device Label","ShieldingDeviceLabel",false }, + {0x300a,0x01a6,VR::ST,VM::VM1,"Shielding Device Description","ShieldingDeviceDescription",false }, + {0x300a,0x01a8,VR::SH,VM::VM1,"Shielding Device Position","ShieldingDevicePosition",false }, + {0x300a,0x01b0,VR::CS,VM::VM1,"Setup Technique","SetupTechnique",false }, + {0x300a,0x01b2,VR::ST,VM::VM1,"Setup Technique Description","SetupTechniqueDescription",false }, + {0x300a,0x01b4,VR::SQ,VM::VM1,"Setup Device Sequence","SetupDeviceSequence",false }, + {0x300a,0x01b6,VR::CS,VM::VM1,"Setup Device Type","SetupDeviceType",false }, + {0x300a,0x01b8,VR::SH,VM::VM1,"Setup Device Label","SetupDeviceLabel",false }, + {0x300a,0x01ba,VR::ST,VM::VM1,"Setup Device Description","SetupDeviceDescription",false }, + {0x300a,0x01bc,VR::DS,VM::VM1,"Setup Device Parameter","SetupDeviceParameter",false }, + {0x300a,0x01d0,VR::ST,VM::VM1,"Setup Reference Description","SetupReferenceDescription",false }, + {0x300a,0x01d2,VR::DS,VM::VM1,"Table Top Vertical Setup Displacement","TableTopVerticalSetupDisplacement",false }, + {0x300a,0x01d4,VR::DS,VM::VM1,"Table Top Longitudinal Setup Displacement","TableTopLongitudinalSetupDisplacement",false }, + {0x300a,0x01d6,VR::DS,VM::VM1,"Table Top Lateral Setup Displacement","TableTopLateralSetupDisplacement",false }, + {0x300a,0x0200,VR::CS,VM::VM1,"Brachy Treatment Technique","BrachyTreatmentTechnique",false }, + {0x300a,0x0202,VR::CS,VM::VM1,"Brachy Treatment Type","BrachyTreatmentType",false }, + {0x300a,0x0206,VR::SQ,VM::VM1,"Treatment Machine Sequence","TreatmentMachineSequence",false }, + {0x300a,0x0210,VR::SQ,VM::VM1,"Source Sequence","SourceSequence",false }, + {0x300a,0x0212,VR::IS,VM::VM1,"Source Number","SourceNumber",false }, + {0x300a,0x0214,VR::CS,VM::VM1,"Source Type","SourceType",false }, + {0x300a,0x0216,VR::LO,VM::VM1,"Source Manufacturer","SourceManufacturer",false }, + {0x300a,0x0218,VR::DS,VM::VM1,"Active Source Diameter","ActiveSourceDiameter",false }, + {0x300a,0x021a,VR::DS,VM::VM1,"Active Source Length","ActiveSourceLength",false }, + {0x300a,0x0222,VR::DS,VM::VM1,"Source Encapsulation Nominal Thickness","SourceEncapsulationNominalThickness",false }, + {0x300a,0x0224,VR::DS,VM::VM1,"Source Encapsulation Nominal Transmission","SourceEncapsulationNominalTransmission",false }, + {0x300a,0x0226,VR::LO,VM::VM1,"Source Isotope Name","SourceIsotopeName",false }, + {0x300a,0x0228,VR::DS,VM::VM1,"Source Isotope Half Life","SourceIsotopeHalfLife",false }, + {0x300a,0x0229,VR::CS,VM::VM1,"Source Strength Units","SourceStrengthUnits",false }, + {0x300a,0x022a,VR::DS,VM::VM1,"Reference Air Kerma Rate","ReferenceAirKermaRate",false }, + {0x300a,0x022b,VR::DS,VM::VM1,"Source Strength","SourceStrength",false }, + {0x300a,0x022c,VR::DA,VM::VM1,"Source Strength Reference Date","SourceStrengthReferenceDate",false }, + {0x300a,0x022e,VR::TM,VM::VM1,"Source Strength Reference Time","SourceStrengthReferenceTime",false }, + {0x300a,0x0230,VR::SQ,VM::VM1,"Application Setup Sequence","ApplicationSetupSequence",false }, + {0x300a,0x0232,VR::CS,VM::VM1,"Application Setup Type","ApplicationSetupType",false }, + {0x300a,0x0234,VR::IS,VM::VM1,"Application Setup Number","ApplicationSetupNumber",false }, + {0x300a,0x0236,VR::LO,VM::VM1,"Application Setup Name","ApplicationSetupName",false }, + {0x300a,0x0238,VR::LO,VM::VM1,"Application Setup Manufacturer","ApplicationSetupManufacturer",false }, + {0x300a,0x0240,VR::IS,VM::VM1,"Template Number","TemplateNumber",false }, + {0x300a,0x0242,VR::SH,VM::VM1,"Template Type","TemplateType",false }, + {0x300a,0x0244,VR::LO,VM::VM1,"Template Name","TemplateName",false }, + {0x300a,0x0250,VR::DS,VM::VM1,"Total Reference Air Kerma","TotalReferenceAirKerma",false }, + {0x300a,0x0260,VR::SQ,VM::VM1,"Brachy Accessory Device Sequence","BrachyAccessoryDeviceSequence",false }, + {0x300a,0x0262,VR::IS,VM::VM1,"Brachy Accessory Device Number","BrachyAccessoryDeviceNumber",false }, + {0x300a,0x0263,VR::SH,VM::VM1,"Brachy Accessory Device ID","BrachyAccessoryDeviceID",false }, + {0x300a,0x0264,VR::CS,VM::VM1,"Brachy Accessory Device Type","BrachyAccessoryDeviceType",false }, + {0x300a,0x0266,VR::LO,VM::VM1,"Brachy Accessory Device Name","BrachyAccessoryDeviceName",false }, + {0x300a,0x026a,VR::DS,VM::VM1,"Brachy Accessory Device Nominal Thickness","BrachyAccessoryDeviceNominalThickness",false }, + {0x300a,0x026c,VR::DS,VM::VM1,"Brachy Accessory Device Nominal Transmission","BrachyAccessoryDeviceNominalTransmission",false }, + {0x300a,0x0280,VR::SQ,VM::VM1,"Channel Sequence","ChannelSequence",false }, + {0x300a,0x0282,VR::IS,VM::VM1,"Channel Number","ChannelNumber",false }, + {0x300a,0x0284,VR::DS,VM::VM1,"Channel Length","ChannelLength",false }, + {0x300a,0x0286,VR::DS,VM::VM1,"Channel Total Time","ChannelTotalTime",false }, + {0x300a,0x0288,VR::CS,VM::VM1,"Source Movement Type","SourceMovementType",false }, + {0x300a,0x028a,VR::IS,VM::VM1,"Number of Pulses","NumberOfPulses",false }, + {0x300a,0x028c,VR::DS,VM::VM1,"Pulse Repetition Interval","PulseRepetitionInterval",false }, + {0x300a,0x0290,VR::IS,VM::VM1,"Source Applicator Number","SourceApplicatorNumber",false }, + {0x300a,0x0291,VR::SH,VM::VM1,"Source Applicator ID","SourceApplicatorID",false }, + {0x300a,0x0292,VR::CS,VM::VM1,"Source Applicator Type","SourceApplicatorType",false }, + {0x300a,0x0294,VR::LO,VM::VM1,"Source Applicator Name","SourceApplicatorName",false }, + {0x300a,0x0296,VR::DS,VM::VM1,"Source Applicator Length","SourceApplicatorLength",false }, + {0x300a,0x0298,VR::LO,VM::VM1,"Source Applicator Manufacturer","SourceApplicatorManufacturer",false }, + {0x300a,0x029c,VR::DS,VM::VM1,"Source Applicator Wall Nominal Thickness","SourceApplicatorWallNominalThickness",false }, + {0x300a,0x029e,VR::DS,VM::VM1,"Source Applicator Wall Nominal Transmission","SourceApplicatorWallNominalTransmission",false }, + {0x300a,0x02a0,VR::DS,VM::VM1,"Source Applicator Step Size","SourceApplicatorStepSize",false }, + {0x300a,0x02a2,VR::IS,VM::VM1,"Transfer Tube Number","TransferTubeNumber",false }, + {0x300a,0x02a4,VR::DS,VM::VM1,"Transfer Tube Length","TransferTubeLength",false }, + {0x300a,0x02b0,VR::SQ,VM::VM1,"Channel Shield Sequence","ChannelShieldSequence",false }, + {0x300a,0x02b2,VR::IS,VM::VM1,"Channel Shield Number","ChannelShieldNumber",false }, + {0x300a,0x02b3,VR::SH,VM::VM1,"Channel Shield ID","ChannelShieldID",false }, + {0x300a,0x02b4,VR::LO,VM::VM1,"Channel Shield Name","ChannelShieldName",false }, + {0x300a,0x02b8,VR::DS,VM::VM1,"Channel Shield Nominal Thickness","ChannelShieldNominalThickness",false }, + {0x300a,0x02ba,VR::DS,VM::VM1,"Channel Shield Nominal Transmission","ChannelShieldNominalTransmission",false }, + {0x300a,0x02c8,VR::DS,VM::VM1,"Final Cumulative Time Weight","FinalCumulativeTimeWeight",false }, + {0x300a,0x02d0,VR::SQ,VM::VM1,"Brachy Control Point Sequence","BrachyControlPointSequence",false }, + {0x300a,0x02d2,VR::DS,VM::VM1,"Control Point Relative Position","ControlPointRelativePosition",false }, + {0x300a,0x02d4,VR::DS,VM::VM3,"Control Point 3D Position","ControlPoint3DPosition",false }, + {0x300a,0x02d6,VR::DS,VM::VM1,"Cumulative Time Weight","CumulativeTimeWeight",false }, + {0x300a,0x02e0,VR::CS,VM::VM1,"Compensator Divergence","CompensatorDivergence",false }, + {0x300a,0x02e1,VR::CS,VM::VM1,"Compensator Mounting Position","CompensatorMountingPosition",false }, + {0x300a,0x02e2,VR::DS,VM::VM1_n,"Source to Compensator Distance","SourceToCompensatorDistance",false }, + {0x300a,0x02e3,VR::FL,VM::VM1,"Total Compensator Tray Water-Equivalent Thickness","TotalCompensatorTrayWaterEquivalentThickness",false }, + {0x300a,0x02e4,VR::FL,VM::VM1,"Isocenter to Compensator Tray Distance","IsocenterToCompensatorTrayDistance",false }, + {0x300a,0x02e5,VR::FL,VM::VM1,"Compensator Column Offset","CompensatorColumnOffset",false }, + {0x300a,0x02e6,VR::FL,VM::VM1_n,"Isocenter to Compensator Distances","IsocenterToCompensatorDistances",false }, + {0x300a,0x02e7,VR::FL,VM::VM1,"Compensator Relative Stopping Power Ratio","CompensatorRelativeStoppingPowerRatio",false }, + {0x300a,0x02e8,VR::FL,VM::VM1,"Compensator Milling Tool Diameter","CompensatorMillingToolDiameter",false }, + {0x300a,0x02ea,VR::SQ,VM::VM1,"Ion Range Compensator Sequence","IonRangeCompensatorSequence",false }, + {0x300a,0x02eb,VR::LT,VM::VM1,"Compensator Description","CompensatorDescription",false }, + {0x300a,0x0302,VR::IS,VM::VM1,"Radiation Mass Number","RadiationMassNumber",false }, + {0x300a,0x0304,VR::IS,VM::VM1,"Radiation Atomic Number","RadiationAtomicNumber",false }, + {0x300a,0x0306,VR::SS,VM::VM1,"Radiation Charge State","RadiationChargeState",false }, + {0x300a,0x0308,VR::CS,VM::VM1,"Scan Mode","ScanMode",false }, + {0x300a,0x030a,VR::FL,VM::VM2,"Virtual Source-Axis Distances","VirtualSourceAxisDistances",false }, + {0x300a,0x030c,VR::SQ,VM::VM1,"Snout Sequence","SnoutSequence",false }, + {0x300a,0x030d,VR::FL,VM::VM1,"Snout Position","SnoutPosition",false }, + {0x300a,0x030f,VR::SH,VM::VM1,"Snout ID","SnoutID",false }, + {0x300a,0x0312,VR::IS,VM::VM1,"Number of Range Shifters","NumberOfRangeShifters",false }, + {0x300a,0x0314,VR::SQ,VM::VM1,"Range Shifter Sequence","RangeShifterSequence",false }, + {0x300a,0x0316,VR::IS,VM::VM1,"Range Shifter Number","RangeShifterNumber",false }, + {0x300a,0x0318,VR::SH,VM::VM1,"Range Shifter ID","RangeShifterID",false }, + {0x300a,0x0320,VR::CS,VM::VM1,"Range Shifter Type","RangeShifterType",false }, + {0x300a,0x0322,VR::LO,VM::VM1,"Range Shifter Description","RangeShifterDescription",false }, + {0x300a,0x0330,VR::IS,VM::VM1,"Number of Lateral Spreading Devices","NumberOfLateralSpreadingDevices",false }, + {0x300a,0x0332,VR::SQ,VM::VM1,"Lateral Spreading Device Sequence","LateralSpreadingDeviceSequence",false }, + {0x300a,0x0334,VR::IS,VM::VM1,"Lateral Spreading Device Number","LateralSpreadingDeviceNumber",false }, + {0x300a,0x0336,VR::SH,VM::VM1,"Lateral Spreading Device ID","LateralSpreadingDeviceID",false }, + {0x300a,0x0338,VR::CS,VM::VM1,"Lateral Spreading Device Type","LateralSpreadingDeviceType",false }, + {0x300a,0x033a,VR::LO,VM::VM1,"Lateral Spreading Device Description","LateralSpreadingDeviceDescription",false }, + {0x300a,0x033c,VR::FL,VM::VM1,"Lateral Spreading Device Water Equivalent Thickness","LateralSpreadingDeviceWaterEquivalentThickness",false }, + {0x300a,0x0340,VR::IS,VM::VM1,"Number of Range Modulators","NumberOfRangeModulators",false }, + {0x300a,0x0342,VR::SQ,VM::VM1,"Range Modulator Sequence","RangeModulatorSequence",false }, + {0x300a,0x0344,VR::IS,VM::VM1,"Range Modulator Number","RangeModulatorNumber",false }, + {0x300a,0x0346,VR::SH,VM::VM1,"Range Modulator ID","RangeModulatorID",false }, + {0x300a,0x0348,VR::CS,VM::VM1,"Range Modulator Type","RangeModulatorType",false }, + {0x300a,0x034a,VR::LO,VM::VM1,"Range Modulator Description","RangeModulatorDescription",false }, + {0x300a,0x034c,VR::SH,VM::VM1,"Beam Current Modulation ID","BeamCurrentModulationID",false }, + {0x300a,0x0350,VR::CS,VM::VM1,"Patient Support Type","PatientSupportType",false }, + {0x300a,0x0352,VR::SH,VM::VM1,"Patient Support ID","PatientSupportID",false }, + {0x300a,0x0354,VR::LO,VM::VM1,"Patient Support Accessory Code","PatientSupportAccessoryCode",false }, + {0x300a,0x0356,VR::FL,VM::VM1,"Fixation Light Azimuthal Angle","FixationLightAzimuthalAngle",false }, + {0x300a,0x0358,VR::FL,VM::VM1,"Fixation Light Polar Angle","FixationLightPolarAngle",false }, + {0x300a,0x035a,VR::FL,VM::VM1,"Meterset Rate","MetersetRate",false }, + {0x300a,0x0360,VR::SQ,VM::VM1,"Range Shifter Settings Sequence","RangeShifterSettingsSequence",false }, + {0x300a,0x0362,VR::LO,VM::VM1,"Range Shifter Setting","RangeShifterSetting",false }, + {0x300a,0x0364,VR::FL,VM::VM1,"Isocenter to Range Shifter Distance","IsocenterToRangeShifterDistance",false }, + {0x300a,0x0366,VR::FL,VM::VM1,"Range Shifter Water Equivalent Thickness","RangeShifterWaterEquivalentThickness",false }, + {0x300a,0x0370,VR::SQ,VM::VM1,"Lateral Spreading Device Settings Sequence","LateralSpreadingDeviceSettingsSequence",false }, + {0x300a,0x0372,VR::LO,VM::VM1,"Lateral Spreading Device Setting","LateralSpreadingDeviceSetting",false }, + {0x300a,0x0374,VR::FL,VM::VM1,"Isocenter to Lateral Spreading Device Distance","IsocenterToLateralSpreadingDeviceDistance",false }, + {0x300a,0x0380,VR::SQ,VM::VM1,"Range Modulator Settings Sequence","RangeModulatorSettingsSequence",false }, + {0x300a,0x0382,VR::FL,VM::VM1,"Range Modulator Gating Start Value","RangeModulatorGatingStartValue",false }, + {0x300a,0x0384,VR::FL,VM::VM1,"Range Modulator Gating Stop Value","RangeModulatorGatingStopValue",false }, + {0x300a,0x0386,VR::FL,VM::VM1,"Range Modulator Gating Start Water Equivalent Thickness","RangeModulatorGatingStartWaterEquivalentThickness",false }, + {0x300a,0x0388,VR::FL,VM::VM1,"Range Modulator Gating Stop Water Equivalent Thickness","RangeModulatorGatingStopWaterEquivalentThickness",false }, + {0x300a,0x038a,VR::FL,VM::VM1,"Isocenter to Range Modulator Distance","IsocenterToRangeModulatorDistance",false }, + {0x300a,0x0390,VR::SH,VM::VM1,"Scan Spot Tune ID","ScanSpotTuneID",false }, + {0x300a,0x0392,VR::IS,VM::VM1,"Number of Scan Spot Positions","NumberOfScanSpotPositions",false }, + {0x300a,0x0394,VR::FL,VM::VM1_n,"Scan Spot Position Map","ScanSpotPositionMap",false }, + {0x300a,0x0396,VR::FL,VM::VM1_n,"Scan Spot Meterset Weights","ScanSpotMetersetWeights",false }, + {0x300a,0x0398,VR::FL,VM::VM2,"Scanning Spot Size","ScanningSpotSize",false }, + {0x300a,0x039a,VR::IS,VM::VM1,"Number of Paintings","NumberOfPaintings",false }, + {0x300a,0x03a0,VR::SQ,VM::VM1,"Ion Tolerance Table Sequence","IonToleranceTableSequence",false }, + {0x300a,0x03a2,VR::SQ,VM::VM1,"Ion Beam Sequence","IonBeamSequence",false }, + {0x300a,0x03a4,VR::SQ,VM::VM1,"Ion Beam Limiting Device Sequence","IonBeamLimitingDeviceSequence",false }, + {0x300a,0x03a6,VR::SQ,VM::VM1,"Ion Block Sequence","IonBlockSequence",false }, + {0x300a,0x03a8,VR::SQ,VM::VM1,"Ion Control Point Sequence","IonControlPointSequence",false }, + {0x300a,0x03aa,VR::SQ,VM::VM1,"Ion Wedge Sequence","IonWedgeSequence",false }, + {0x300a,0x03ac,VR::SQ,VM::VM1,"Ion Wedge Position Sequence","IonWedgePositionSequence",false }, + {0x300a,0x0401,VR::SQ,VM::VM1,"Referenced Setup Image Sequence","ReferencedSetupImageSequence",false }, + {0x300a,0x0402,VR::ST,VM::VM1,"Setup Image Comment","SetupImageComment",false }, + {0x300a,0x0410,VR::SQ,VM::VM1,"Motion Synchronization Sequence","MotionSynchronizationSequence",false }, + {0x300a,0x0412,VR::FL,VM::VM3,"Control Point Orientation","ControlPointOrientation",false }, + {0x300a,0x0420,VR::SQ,VM::VM1,"General Accessory Sequence","GeneralAccessorySequence",false }, + {0x300a,0x0421,VR::SH,VM::VM1,"General Accessory ID","GeneralAccessoryID",false }, + {0x300a,0x0422,VR::ST,VM::VM1,"General Accessory Description","GeneralAccessoryDescription",false }, + {0x300a,0x0423,VR::CS,VM::VM1,"General Accessory Type","GeneralAccessoryType",false }, + {0x300a,0x0424,VR::IS,VM::VM1,"General Accessory Number","GeneralAccessoryNumber",false }, + {0x300a,0x0431,VR::SQ,VM::VM1,"Applicator Geometry Sequence","ApplicatorGeometrySequence",false }, + {0x300a,0x0432,VR::CS,VM::VM1,"Applicator Aperture Shape","ApplicatorApertureShape",false }, + {0x300a,0x0433,VR::FL,VM::VM1,"Applicator Opening","ApplicatorOpening",false }, + {0x300a,0x0434,VR::FL,VM::VM1,"Applicator Opening X","ApplicatorOpeningX",false }, + {0x300a,0x0435,VR::FL,VM::VM1,"Applicator Opening Y","ApplicatorOpeningY",false }, + {0x300a,0x0436,VR::FL,VM::VM1,"Source to Applicator Mounting Position Distance","SourceToApplicatorMountingPositionDistance",false }, + {0x300c,0x0002,VR::SQ,VM::VM1,"Referenced RT Plan Sequence","ReferencedRTPlanSequence",false }, + {0x300c,0x0004,VR::SQ,VM::VM1,"Referenced Beam Sequence","ReferencedBeamSequence",false }, + {0x300c,0x0006,VR::IS,VM::VM1,"Referenced Beam Number","ReferencedBeamNumber",false }, + {0x300c,0x0007,VR::IS,VM::VM1,"Referenced Reference Image Number","ReferencedReferenceImageNumber",false }, + {0x300c,0x0008,VR::DS,VM::VM1,"Start Cumulative Meterset Weight","StartCumulativeMetersetWeight",false }, + {0x300c,0x0009,VR::DS,VM::VM1,"End Cumulative Meterset Weight","EndCumulativeMetersetWeight",false }, + {0x300c,0x000a,VR::SQ,VM::VM1,"Referenced Brachy Application Setup Sequence","ReferencedBrachyApplicationSetupSequence",false }, + {0x300c,0x000c,VR::IS,VM::VM1,"Referenced Brachy Application Setup Number","ReferencedBrachyApplicationSetupNumber",false }, + {0x300c,0x000e,VR::IS,VM::VM1,"Referenced Source Number","ReferencedSourceNumber",false }, + {0x300c,0x0020,VR::SQ,VM::VM1,"Referenced Fraction Group Sequence","ReferencedFractionGroupSequence",false }, + {0x300c,0x0022,VR::IS,VM::VM1,"Referenced Fraction Group Number","ReferencedFractionGroupNumber",false }, + {0x300c,0x0040,VR::SQ,VM::VM1,"Referenced Verification Image Sequence","ReferencedVerificationImageSequence",false }, + {0x300c,0x0042,VR::SQ,VM::VM1,"Referenced Reference Image Sequence","ReferencedReferenceImageSequence",false }, + {0x300c,0x0050,VR::SQ,VM::VM1,"Referenced Dose Reference Sequence","ReferencedDoseReferenceSequence",false }, + {0x300c,0x0051,VR::IS,VM::VM1,"Referenced Dose Reference Number","ReferencedDoseReferenceNumber",false }, + {0x300c,0x0055,VR::SQ,VM::VM1,"Brachy Referenced Dose Reference Sequence","BrachyReferencedDoseReferenceSequence",false }, + {0x300c,0x0060,VR::SQ,VM::VM1,"Referenced Structure Set Sequence","ReferencedStructureSetSequence",false }, + {0x300c,0x006a,VR::IS,VM::VM1,"Referenced Patient Setup Number","ReferencedPatientSetupNumber",false }, + {0x300c,0x0080,VR::SQ,VM::VM1,"Referenced Dose Sequence","ReferencedDoseSequence",false }, + {0x300c,0x00a0,VR::IS,VM::VM1,"Referenced Tolerance Table Number","ReferencedToleranceTableNumber",false }, + {0x300c,0x00b0,VR::SQ,VM::VM1,"Referenced Bolus Sequence","ReferencedBolusSequence",false }, + {0x300c,0x00c0,VR::IS,VM::VM1,"Referenced Wedge Number","ReferencedWedgeNumber",false }, + {0x300c,0x00d0,VR::IS,VM::VM1,"Referenced Compensator Number","ReferencedCompensatorNumber",false }, + {0x300c,0x00e0,VR::IS,VM::VM1,"Referenced Block Number","ReferencedBlockNumber",false }, + {0x300c,0x00f0,VR::IS,VM::VM1,"Referenced Control Point Index","ReferencedControlPointIndex",false }, + {0x300c,0x00f2,VR::SQ,VM::VM1,"Referenced Control Point Sequence","ReferencedControlPointSequence",false }, + {0x300c,0x00f4,VR::IS,VM::VM1,"Referenced Start Control Point Index","ReferencedStartControlPointIndex",false }, + {0x300c,0x00f6,VR::IS,VM::VM1,"Referenced Stop Control Point Index","ReferencedStopControlPointIndex",false }, + {0x300c,0x0100,VR::IS,VM::VM1,"Referenced Range Shifter Number","ReferencedRangeShifterNumber",false }, + {0x300c,0x0102,VR::IS,VM::VM1,"Referenced Lateral Spreading Device Number","ReferencedLateralSpreadingDeviceNumber",false }, + {0x300c,0x0104,VR::IS,VM::VM1,"Referenced Range Modulator Number","ReferencedRangeModulatorNumber",false }, + {0x300e,0x0002,VR::CS,VM::VM1,"Approval Status","ApprovalStatus",false }, + {0x300e,0x0004,VR::DA,VM::VM1,"Review Date","ReviewDate",false }, + {0x300e,0x0005,VR::TM,VM::VM1,"Review Time","ReviewTime",false }, + {0x300e,0x0008,VR::PN,VM::VM1,"Reviewer Name","ReviewerName",false }, + {0x4000,0x0010,VR::LT,VM::VM1,"Arbitrary","Arbitrary",true }, + {0x4000,0x4000,VR::LT,VM::VM1,"Text Comments","TextComments",true }, + {0x4008,0x0040,VR::SH,VM::VM1,"Results ID","ResultsID",true }, + {0x4008,0x0042,VR::LO,VM::VM1,"Results ID Issuer","ResultsIDIssuer",true }, + {0x4008,0x0050,VR::SQ,VM::VM1,"Referenced Interpretation Sequence","ReferencedInterpretationSequence",true }, + {0x4008,0x00ff,VR::CS,VM::VM1,"Report Production Status (Trial)","ReportProductionStatusTrial",true }, + {0x4008,0x0100,VR::DA,VM::VM1,"Interpretation Recorded Date","InterpretationRecordedDate",true }, + {0x4008,0x0101,VR::TM,VM::VM1,"Interpretation Recorded Time","InterpretationRecordedTime",true }, + {0x4008,0x0102,VR::PN,VM::VM1,"Interpretation Recorder","InterpretationRecorder",true }, + {0x4008,0x0103,VR::LO,VM::VM1,"Reference to Recorded Sound","ReferenceToRecordedSound",true }, + {0x4008,0x0108,VR::DA,VM::VM1,"Interpretation Transcription Date","InterpretationTranscriptionDate",true }, + {0x4008,0x0109,VR::TM,VM::VM1,"Interpretation Transcription Time","InterpretationTranscriptionTime",true }, + {0x4008,0x010a,VR::PN,VM::VM1,"Interpretation Transcriber","InterpretationTranscriber",true }, + {0x4008,0x010b,VR::ST,VM::VM1,"Interpretation Text","InterpretationText",true }, + {0x4008,0x010c,VR::PN,VM::VM1,"Interpretation Author","InterpretationAuthor",true }, + {0x4008,0x0111,VR::SQ,VM::VM1,"Interpretation Approver Sequence","InterpretationApproverSequence",true }, + {0x4008,0x0112,VR::DA,VM::VM1,"Interpretation Approval Date","InterpretationApprovalDate",true }, + {0x4008,0x0113,VR::TM,VM::VM1,"Interpretation Approval Time","InterpretationApprovalTime",true }, + {0x4008,0x0114,VR::PN,VM::VM1,"Physician Approving Interpretation","PhysicianApprovingInterpretation",true }, + {0x4008,0x0115,VR::LT,VM::VM1,"Interpretation Diagnosis Description","InterpretationDiagnosisDescription",true }, + {0x4008,0x0117,VR::SQ,VM::VM1,"Interpretation Diagnosis Code Sequence","InterpretationDiagnosisCodeSequence",true }, + {0x4008,0x0118,VR::SQ,VM::VM1,"Results Distribution List Sequence","ResultsDistributionListSequence",true }, + {0x4008,0x0119,VR::PN,VM::VM1,"Distribution Name","DistributionName",true }, + {0x4008,0x011a,VR::LO,VM::VM1,"Distribution Address","DistributionAddress",true }, + {0x4008,0x0200,VR::SH,VM::VM1,"Interpretation ID","InterpretationID",true }, + {0x4008,0x0202,VR::LO,VM::VM1,"Interpretation ID Issuer","InterpretationIDIssuer",true }, + {0x4008,0x0210,VR::CS,VM::VM1,"Interpretation Type ID","InterpretationTypeID",true }, + {0x4008,0x0212,VR::CS,VM::VM1,"Interpretation Status ID","InterpretationStatusID",true }, + {0x4008,0x0300,VR::ST,VM::VM1,"Impressions","Impressions",true }, + {0x4008,0x4000,VR::ST,VM::VM1,"Results Comments","ResultsComments",true }, + {0x4010,0x0001,VR::CS,VM::VM1,"Low Energy Detectors","LowEnergyDetectors",false }, + {0x4010,0x0002,VR::CS,VM::VM1,"High Energy Detectors","HighEnergyDetectors",false }, + {0x4010,0x0004,VR::SQ,VM::VM1,"Detector Geometry Sequence","DetectorGeometrySequence",false }, + {0x4010,0x1001,VR::SQ,VM::VM1,"Threat ROI Voxel Sequence","ThreatROIVoxelSequence",false }, + {0x4010,0x1004,VR::FL,VM::VM3,"Threat ROI Base","ThreatROIBase",false }, + {0x4010,0x1005,VR::FL,VM::VM3,"Threat ROI Extents","ThreatROIExtents",false }, + {0x4010,0x1006,VR::OB,VM::VM1,"Threat ROI Bitmap","ThreatROIBitmap",false }, + {0x4010,0x1007,VR::SH,VM::VM1,"Route Segment ID","RouteSegmentID",false }, + {0x4010,0x1008,VR::CS,VM::VM1,"Gantry Type","GantryType",false }, + {0x4010,0x1009,VR::CS,VM::VM1,"OOI Owner Type","OOIOwnerType",false }, + {0x4010,0x100a,VR::SQ,VM::VM1,"Route Segment Sequence","RouteSegmentSequence",false }, + {0x4010,0x1010,VR::US,VM::VM1,"Potential Threat Object ID","PotentialThreatObjectID",false }, + {0x4010,0x1011,VR::SQ,VM::VM1,"Threat Sequence","ThreatSequence",false }, + {0x4010,0x1012,VR::CS,VM::VM1,"Threat Category","ThreatCategory",false }, + {0x4010,0x1013,VR::LT,VM::VM1,"Threat Category Description","ThreatCategoryDescription",false }, + {0x4010,0x1014,VR::CS,VM::VM1,"ATD Ability Assessment","ATDAbilityAssessment",false }, + {0x4010,0x1015,VR::CS,VM::VM1,"ATD Assessment Flag","ATDAssessmentFlag",false }, + {0x4010,0x1016,VR::FL,VM::VM1,"ATD Assessment Probability","ATDAssessmentProbability",false }, + {0x4010,0x1017,VR::FL,VM::VM1,"Mass","Mass",false }, + {0x4010,0x1018,VR::FL,VM::VM1,"Density","Density",false }, + {0x4010,0x1019,VR::FL,VM::VM1,"Z Effective","ZEffective",false }, + {0x4010,0x101a,VR::SH,VM::VM1,"Boarding Pass ID","BoardingPassID",false }, + {0x4010,0x101b,VR::FL,VM::VM3,"Center of Mass","CenterOfMass",false }, + {0x4010,0x101c,VR::FL,VM::VM3,"Center of PTO","CenterOfPTO",false }, + {0x4010,0x101d,VR::FL,VM::VM6_6n,"Bounding Polygon","BoundingPolygon",false }, + {0x4010,0x101e,VR::SH,VM::VM1,"Route Segment Start Location ID","RouteSegmentStartLocationID",false }, + {0x4010,0x101f,VR::SH,VM::VM1,"Route Segment End Location ID","RouteSegmentEndLocationID",false }, + {0x4010,0x1020,VR::CS,VM::VM1,"Route Segment Location ID Type","RouteSegmentLocationIDType",false }, + {0x4010,0x1021,VR::CS,VM::VM1_n,"Abort Reason","AbortReason",false }, + {0x4010,0x1023,VR::FL,VM::VM1,"Volume of PTO","VolumeOfPTO",false }, + {0x4010,0x1024,VR::CS,VM::VM1,"Abort Flag","AbortFlag",false }, + {0x4010,0x1025,VR::DT,VM::VM1,"Route Segment Start Time","RouteSegmentStartTime",false }, + {0x4010,0x1026,VR::DT,VM::VM1,"Route Segment End Time","RouteSegmentEndTime",false }, + {0x4010,0x1027,VR::CS,VM::VM1,"TDR Type","TDRType",false }, + {0x4010,0x1028,VR::CS,VM::VM1,"International Route Segment","InternationalRouteSegment",false }, + {0x4010,0x1029,VR::LO,VM::VM1_n,"Threat Detection Algorithm and Version","ThreatDetectionAlgorithmandVersion",false }, + {0x4010,0x102a,VR::SH,VM::VM1,"Assigned Location","AssignedLocation",false }, + {0x4010,0x102b,VR::DT,VM::VM1,"Alarm Decision Time","AlarmDecisionTime",false }, + {0x4010,0x1031,VR::CS,VM::VM1,"Alarm Decision","AlarmDecision",false }, + {0x4010,0x1033,VR::US,VM::VM1,"Number of Total Objects","NumberOfTotalObjects",false }, + {0x4010,0x1034,VR::US,VM::VM1,"Number of Alarm Objects","NumberOfAlarmObjects",false }, + {0x4010,0x1037,VR::SQ,VM::VM1,"PTO Representation Sequence","PTORepresentationSequence",false }, + {0x4010,0x1038,VR::SQ,VM::VM1,"ATD Assessment Sequence","ATDAssessmentSequence",false }, + {0x4010,0x1039,VR::CS,VM::VM1,"TIP Type","TIPType",false }, + {0x4010,0x103a,VR::CS,VM::VM1,"DICOS Version","DICOSVersion",false }, + {0x4010,0x1041,VR::DT,VM::VM1,"OOI Owner Creation Time","OOIOwnerCreationTime",false }, + {0x4010,0x1042,VR::CS,VM::VM1,"OOI Type","OOIType",false }, + {0x4010,0x1043,VR::FL,VM::VM3,"OOI Size","OOISize",false }, + {0x4010,0x1044,VR::CS,VM::VM1,"Acquisition Status","AcquisitionStatus",false }, + {0x4010,0x1045,VR::SQ,VM::VM1,"Basis Materials Code Sequence","BasisMaterialsCodeSequence",false }, + {0x4010,0x1046,VR::CS,VM::VM1,"Phantom Type","PhantomType",false }, + {0x4010,0x1047,VR::SQ,VM::VM1,"OOI Owner Sequence","OOIOwnerSequence",false }, + {0x4010,0x1048,VR::CS,VM::VM1,"Scan Type","ScanType",false }, + {0x4010,0x1051,VR::LO,VM::VM1,"Itinerary ID","ItineraryID",false }, + {0x4010,0x1052,VR::SH,VM::VM1,"Itinerary ID Type","ItineraryIDType",false }, + {0x4010,0x1053,VR::LO,VM::VM1,"Itinerary ID Assigning Authority","ItineraryIDAssigningAuthority",false }, + {0x4010,0x1054,VR::SH,VM::VM1,"Route ID","RouteID",false }, + {0x4010,0x1055,VR::SH,VM::VM1,"Route ID Assigning Authority","RouteIDAssigningAuthority",false }, + {0x4010,0x1056,VR::CS,VM::VM1,"Inbound Arrival Type","InboundArrivalType",false }, + {0x4010,0x1058,VR::SH,VM::VM1,"Carrier ID","CarrierID",false }, + {0x4010,0x1059,VR::CS,VM::VM1,"Carrier ID Assigning Authority","CarrierIDAssigningAuthority",false }, + {0x4010,0x1060,VR::FL,VM::VM3,"Source Orientation","SourceOrientation",false }, + {0x4010,0x1061,VR::FL,VM::VM3,"Source Position","SourcePosition",false }, + {0x4010,0x1062,VR::FL,VM::VM1,"Belt Height","BeltHeight",false }, + {0x4010,0x1064,VR::SQ,VM::VM1,"Algorithm Routing Code Sequence","AlgorithmRoutingCodeSequence",false }, + {0x4010,0x1067,VR::CS,VM::VM1,"Transport Classification","TransportClassification",false }, + {0x4010,0x1068,VR::LT,VM::VM1,"OOI Type Descriptor","OOITypeDescriptor",false }, + {0x4010,0x1069,VR::FL,VM::VM1,"Total Processing Time","TotalProcessingTime",false }, + {0x4010,0x106c,VR::OB,VM::VM1,"Detector Calibration Data","DetectorCalibrationData",false }, + {0x4ffe,0x0001,VR::SQ,VM::VM1,"MAC Parameters Sequence","MACParametersSequence",false }, + {0x5000,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x5002,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x5004,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x5006,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x5008,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x500a,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x500c,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x500e,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x5010,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x5012,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x5014,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x5016,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x5018,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x501a,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x501c,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x501e,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x5020,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x5022,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x5024,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x5026,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x5028,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x502a,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x502c,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x502e,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x5030,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x5032,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x5034,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x5036,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x5038,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x503a,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x503c,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x503e,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x5040,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x5042,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x5044,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x5046,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x5048,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x504a,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x504c,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x504e,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x5050,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x5052,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x5054,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x5056,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x5058,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x505a,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x505c,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x505e,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x5060,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x5062,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x5064,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x5066,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x5068,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x506a,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x506c,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x506e,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x5070,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x5072,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x5074,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x5076,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x5078,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x507a,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x507c,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x507e,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x5080,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x5082,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x5084,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x5086,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x5088,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x508a,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x508c,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x508e,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x5090,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x5092,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x5094,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x5096,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x5098,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x509a,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x509c,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x509e,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x50a0,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x50a2,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x50a4,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x50a6,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x50a8,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x50aa,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x50ac,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x50ae,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x50b0,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x50b2,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x50b4,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x50b6,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x50b8,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x50ba,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x50bc,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x50be,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x50c0,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x50c2,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x50c4,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x50c6,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x50c8,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x50ca,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x50cc,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x50ce,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x50d0,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x50d2,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x50d4,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x50d6,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x50d8,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x50da,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x50dc,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x50de,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x50e0,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x50e2,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x50e4,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x50e6,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x50e8,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x50ea,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x50ec,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x50ee,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x50f0,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x50f2,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x50f4,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x50f6,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x50f8,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x50fa,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x50fc,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x50fe,0x0005,VR::US,VM::VM1,"Curve Dimensions","CurveDimensions",true }, + {0x5000,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x5002,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x5004,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x5006,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x5008,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x500a,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x500c,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x500e,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x5010,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x5012,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x5014,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x5016,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x5018,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x501a,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x501c,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x501e,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x5020,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x5022,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x5024,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x5026,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x5028,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x502a,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x502c,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x502e,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x5030,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x5032,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x5034,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x5036,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x5038,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x503a,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x503c,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x503e,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x5040,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x5042,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x5044,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x5046,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x5048,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x504a,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x504c,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x504e,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x5050,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x5052,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x5054,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x5056,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x5058,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x505a,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x505c,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x505e,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x5060,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x5062,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x5064,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x5066,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x5068,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x506a,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x506c,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x506e,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x5070,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x5072,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x5074,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x5076,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x5078,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x507a,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x507c,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x507e,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x5080,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x5082,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x5084,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x5086,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x5088,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x508a,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x508c,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x508e,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x5090,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x5092,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x5094,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x5096,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x5098,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x509a,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x509c,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x509e,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x50a0,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x50a2,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x50a4,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x50a6,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x50a8,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x50aa,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x50ac,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x50ae,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x50b0,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x50b2,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x50b4,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x50b6,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x50b8,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x50ba,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x50bc,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x50be,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x50c0,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x50c2,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x50c4,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x50c6,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x50c8,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x50ca,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x50cc,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x50ce,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x50d0,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x50d2,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x50d4,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x50d6,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x50d8,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x50da,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x50dc,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x50de,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x50e0,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x50e2,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x50e4,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x50e6,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x50e8,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x50ea,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x50ec,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x50ee,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x50f0,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x50f2,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x50f4,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x50f6,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x50f8,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x50fa,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x50fc,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x50fe,0x0010,VR::US,VM::VM1,"Number of Points","NumberOfPoints",true }, + {0x5000,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x5002,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x5004,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x5006,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x5008,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x500a,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x500c,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x500e,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x5010,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x5012,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x5014,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x5016,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x5018,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x501a,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x501c,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x501e,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x5020,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x5022,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x5024,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x5026,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x5028,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x502a,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x502c,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x502e,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x5030,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x5032,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x5034,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x5036,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x5038,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x503a,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x503c,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x503e,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x5040,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x5042,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x5044,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x5046,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x5048,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x504a,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x504c,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x504e,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x5050,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x5052,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x5054,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x5056,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x5058,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x505a,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x505c,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x505e,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x5060,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x5062,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x5064,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x5066,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x5068,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x506a,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x506c,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x506e,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x5070,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x5072,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x5074,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x5076,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x5078,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x507a,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x507c,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x507e,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x5080,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x5082,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x5084,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x5086,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x5088,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x508a,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x508c,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x508e,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x5090,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x5092,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x5094,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x5096,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x5098,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x509a,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x509c,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x509e,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x50a0,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x50a2,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x50a4,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x50a6,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x50a8,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x50aa,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x50ac,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x50ae,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x50b0,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x50b2,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x50b4,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x50b6,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x50b8,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x50ba,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x50bc,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x50be,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x50c0,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x50c2,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x50c4,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x50c6,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x50c8,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x50ca,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x50cc,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x50ce,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x50d0,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x50d2,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x50d4,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x50d6,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x50d8,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x50da,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x50dc,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x50de,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x50e0,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x50e2,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x50e4,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x50e6,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x50e8,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x50ea,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x50ec,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x50ee,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x50f0,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x50f2,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x50f4,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x50f6,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x50f8,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x50fa,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x50fc,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x50fe,0x0020,VR::CS,VM::VM1,"Type of Data","TypeOfData",true }, + {0x5000,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x5002,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x5004,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x5006,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x5008,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x500a,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x500c,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x500e,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x5010,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x5012,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x5014,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x5016,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x5018,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x501a,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x501c,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x501e,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x5020,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x5022,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x5024,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x5026,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x5028,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x502a,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x502c,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x502e,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x5030,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x5032,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x5034,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x5036,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x5038,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x503a,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x503c,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x503e,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x5040,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x5042,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x5044,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x5046,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x5048,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x504a,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x504c,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x504e,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x5050,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x5052,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x5054,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x5056,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x5058,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x505a,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x505c,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x505e,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x5060,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x5062,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x5064,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x5066,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x5068,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x506a,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x506c,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x506e,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x5070,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x5072,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x5074,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x5076,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x5078,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x507a,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x507c,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x507e,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x5080,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x5082,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x5084,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x5086,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x5088,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x508a,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x508c,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x508e,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x5090,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x5092,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x5094,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x5096,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x5098,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x509a,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x509c,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x509e,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x50a0,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x50a2,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x50a4,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x50a6,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x50a8,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x50aa,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x50ac,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x50ae,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x50b0,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x50b2,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x50b4,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x50b6,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x50b8,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x50ba,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x50bc,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x50be,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x50c0,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x50c2,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x50c4,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x50c6,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x50c8,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x50ca,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x50cc,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x50ce,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x50d0,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x50d2,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x50d4,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x50d6,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x50d8,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x50da,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x50dc,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x50de,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x50e0,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x50e2,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x50e4,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x50e6,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x50e8,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x50ea,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x50ec,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x50ee,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x50f0,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x50f2,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x50f4,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x50f6,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x50f8,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x50fa,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x50fc,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x50fe,0x0022,VR::LO,VM::VM1,"Curve Description","CurveDescription",true }, + {0x5000,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x5002,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x5004,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x5006,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x5008,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x500a,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x500c,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x500e,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x5010,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x5012,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x5014,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x5016,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x5018,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x501a,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x501c,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x501e,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x5020,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x5022,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x5024,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x5026,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x5028,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x502a,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x502c,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x502e,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x5030,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x5032,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x5034,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x5036,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x5038,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x503a,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x503c,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x503e,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x5040,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x5042,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x5044,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x5046,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x5048,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x504a,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x504c,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x504e,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x5050,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x5052,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x5054,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x5056,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x5058,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x505a,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x505c,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x505e,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x5060,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x5062,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x5064,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x5066,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x5068,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x506a,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x506c,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x506e,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x5070,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x5072,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x5074,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x5076,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x5078,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x507a,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x507c,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x507e,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x5080,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x5082,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x5084,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x5086,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x5088,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x508a,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x508c,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x508e,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x5090,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x5092,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x5094,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x5096,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x5098,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x509a,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x509c,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x509e,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x50a0,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x50a2,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x50a4,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x50a6,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x50a8,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x50aa,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x50ac,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x50ae,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x50b0,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x50b2,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x50b4,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x50b6,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x50b8,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x50ba,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x50bc,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x50be,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x50c0,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x50c2,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x50c4,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x50c6,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x50c8,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x50ca,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x50cc,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x50ce,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x50d0,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x50d2,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x50d4,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x50d6,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x50d8,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x50da,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x50dc,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x50de,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x50e0,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x50e2,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x50e4,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x50e6,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x50e8,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x50ea,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x50ec,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x50ee,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x50f0,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x50f2,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x50f4,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x50f6,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x50f8,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x50fa,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x50fc,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x50fe,0x0030,VR::SH,VM::VM1_n,"Axis Units","AxisUnits",true }, + {0x5000,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x5002,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x5004,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x5006,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x5008,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x500a,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x500c,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x500e,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x5010,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x5012,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x5014,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x5016,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x5018,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x501a,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x501c,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x501e,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x5020,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x5022,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x5024,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x5026,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x5028,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x502a,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x502c,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x502e,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x5030,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x5032,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x5034,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x5036,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x5038,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x503a,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x503c,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x503e,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x5040,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x5042,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x5044,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x5046,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x5048,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x504a,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x504c,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x504e,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x5050,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x5052,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x5054,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x5056,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x5058,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x505a,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x505c,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x505e,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x5060,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x5062,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x5064,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x5066,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x5068,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x506a,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x506c,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x506e,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x5070,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x5072,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x5074,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x5076,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x5078,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x507a,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x507c,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x507e,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x5080,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x5082,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x5084,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x5086,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x5088,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x508a,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x508c,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x508e,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x5090,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x5092,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x5094,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x5096,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x5098,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x509a,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x509c,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x509e,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x50a0,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x50a2,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x50a4,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x50a6,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x50a8,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x50aa,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x50ac,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x50ae,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x50b0,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x50b2,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x50b4,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x50b6,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x50b8,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x50ba,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x50bc,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x50be,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x50c0,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x50c2,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x50c4,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x50c6,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x50c8,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x50ca,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x50cc,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x50ce,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x50d0,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x50d2,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x50d4,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x50d6,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x50d8,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x50da,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x50dc,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x50de,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x50e0,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x50e2,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x50e4,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x50e6,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x50e8,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x50ea,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x50ec,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x50ee,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x50f0,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x50f2,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x50f4,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x50f6,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x50f8,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x50fa,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x50fc,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x50fe,0x0040,VR::SH,VM::VM1_n,"Axis Labels","AxisLabels",true }, + {0x5000,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x5002,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x5004,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x5006,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x5008,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x500a,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x500c,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x500e,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x5010,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x5012,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x5014,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x5016,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x5018,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x501a,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x501c,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x501e,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x5020,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x5022,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x5024,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x5026,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x5028,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x502a,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x502c,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x502e,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x5030,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x5032,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x5034,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x5036,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x5038,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x503a,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x503c,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x503e,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x5040,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x5042,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x5044,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x5046,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x5048,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x504a,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x504c,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x504e,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x5050,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x5052,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x5054,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x5056,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x5058,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x505a,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x505c,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x505e,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x5060,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x5062,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x5064,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x5066,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x5068,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x506a,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x506c,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x506e,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x5070,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x5072,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x5074,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x5076,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x5078,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x507a,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x507c,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x507e,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x5080,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x5082,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x5084,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x5086,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x5088,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x508a,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x508c,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x508e,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x5090,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x5092,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x5094,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x5096,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x5098,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x509a,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x509c,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x509e,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x50a0,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x50a2,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x50a4,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x50a6,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x50a8,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x50aa,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x50ac,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x50ae,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x50b0,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x50b2,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x50b4,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x50b6,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x50b8,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x50ba,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x50bc,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x50be,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x50c0,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x50c2,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x50c4,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x50c6,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x50c8,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x50ca,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x50cc,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x50ce,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x50d0,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x50d2,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x50d4,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x50d6,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x50d8,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x50da,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x50dc,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x50de,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x50e0,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x50e2,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x50e4,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x50e6,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x50e8,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x50ea,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x50ec,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x50ee,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x50f0,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x50f2,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x50f4,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x50f6,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x50f8,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x50fa,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x50fc,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x50fe,0x0103,VR::US,VM::VM1,"Data Value Representation","DataValueRepresentation",true }, + {0x5000,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x5002,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x5004,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x5006,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x5008,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x500a,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x500c,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x500e,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x5010,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x5012,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x5014,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x5016,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x5018,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x501a,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x501c,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x501e,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x5020,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x5022,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x5024,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x5026,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x5028,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x502a,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x502c,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x502e,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x5030,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x5032,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x5034,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x5036,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x5038,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x503a,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x503c,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x503e,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x5040,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x5042,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x5044,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x5046,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x5048,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x504a,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x504c,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x504e,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x5050,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x5052,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x5054,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x5056,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x5058,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x505a,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x505c,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x505e,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x5060,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x5062,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x5064,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x5066,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x5068,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x506a,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x506c,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x506e,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x5070,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x5072,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x5074,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x5076,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x5078,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x507a,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x507c,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x507e,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x5080,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x5082,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x5084,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x5086,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x5088,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x508a,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x508c,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x508e,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x5090,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x5092,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x5094,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x5096,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x5098,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x509a,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x509c,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x509e,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x50a0,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x50a2,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x50a4,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x50a6,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x50a8,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x50aa,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x50ac,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x50ae,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x50b0,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x50b2,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x50b4,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x50b6,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x50b8,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x50ba,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x50bc,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x50be,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x50c0,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x50c2,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x50c4,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x50c6,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x50c8,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x50ca,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x50cc,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x50ce,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x50d0,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x50d2,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x50d4,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x50d6,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x50d8,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x50da,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x50dc,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x50de,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x50e0,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x50e2,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x50e4,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x50e6,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x50e8,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x50ea,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x50ec,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x50ee,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x50f0,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x50f2,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x50f4,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x50f6,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x50f8,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x50fa,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x50fc,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x50fe,0x0104,VR::US,VM::VM1_n,"Minimum Coordinate Value","MinimumCoordinateValue",true }, + {0x5000,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x5002,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x5004,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x5006,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x5008,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x500a,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x500c,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x500e,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x5010,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x5012,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x5014,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x5016,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x5018,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x501a,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x501c,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x501e,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x5020,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x5022,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x5024,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x5026,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x5028,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x502a,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x502c,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x502e,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x5030,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x5032,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x5034,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x5036,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x5038,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x503a,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x503c,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x503e,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x5040,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x5042,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x5044,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x5046,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x5048,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x504a,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x504c,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x504e,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x5050,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x5052,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x5054,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x5056,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x5058,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x505a,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x505c,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x505e,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x5060,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x5062,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x5064,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x5066,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x5068,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x506a,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x506c,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x506e,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x5070,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x5072,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x5074,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x5076,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x5078,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x507a,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x507c,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x507e,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x5080,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x5082,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x5084,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x5086,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x5088,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x508a,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x508c,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x508e,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x5090,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x5092,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x5094,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x5096,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x5098,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x509a,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x509c,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x509e,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x50a0,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x50a2,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x50a4,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x50a6,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x50a8,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x50aa,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x50ac,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x50ae,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x50b0,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x50b2,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x50b4,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x50b6,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x50b8,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x50ba,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x50bc,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x50be,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x50c0,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x50c2,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x50c4,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x50c6,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x50c8,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x50ca,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x50cc,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x50ce,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x50d0,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x50d2,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x50d4,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x50d6,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x50d8,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x50da,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x50dc,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x50de,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x50e0,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x50e2,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x50e4,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x50e6,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x50e8,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x50ea,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x50ec,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x50ee,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x50f0,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x50f2,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x50f4,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x50f6,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x50f8,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x50fa,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x50fc,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x50fe,0x0105,VR::US,VM::VM1_n,"Maximum Coordinate Value","MaximumCoordinateValue",true }, + {0x5000,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x5002,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x5004,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x5006,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x5008,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x500a,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x500c,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x500e,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x5010,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x5012,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x5014,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x5016,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x5018,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x501a,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x501c,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x501e,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x5020,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x5022,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x5024,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x5026,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x5028,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x502a,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x502c,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x502e,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x5030,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x5032,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x5034,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x5036,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x5038,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x503a,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x503c,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x503e,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x5040,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x5042,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x5044,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x5046,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x5048,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x504a,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x504c,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x504e,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x5050,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x5052,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x5054,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x5056,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x5058,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x505a,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x505c,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x505e,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x5060,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x5062,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x5064,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x5066,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x5068,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x506a,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x506c,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x506e,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x5070,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x5072,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x5074,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x5076,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x5078,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x507a,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x507c,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x507e,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x5080,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x5082,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x5084,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x5086,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x5088,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x508a,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x508c,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x508e,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x5090,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x5092,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x5094,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x5096,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x5098,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x509a,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x509c,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x509e,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x50a0,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x50a2,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x50a4,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x50a6,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x50a8,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x50aa,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x50ac,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x50ae,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x50b0,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x50b2,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x50b4,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x50b6,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x50b8,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x50ba,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x50bc,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x50be,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x50c0,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x50c2,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x50c4,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x50c6,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x50c8,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x50ca,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x50cc,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x50ce,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x50d0,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x50d2,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x50d4,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x50d6,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x50d8,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x50da,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x50dc,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x50de,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x50e0,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x50e2,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x50e4,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x50e6,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x50e8,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x50ea,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x50ec,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x50ee,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x50f0,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x50f2,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x50f4,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x50f6,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x50f8,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x50fa,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x50fc,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x50fe,0x0106,VR::SH,VM::VM1_n,"Curve Range","CurveRange",true }, + {0x5000,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x5002,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x5004,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x5006,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x5008,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x500a,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x500c,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x500e,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x5010,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x5012,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x5014,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x5016,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x5018,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x501a,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x501c,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x501e,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x5020,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x5022,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x5024,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x5026,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x5028,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x502a,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x502c,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x502e,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x5030,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x5032,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x5034,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x5036,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x5038,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x503a,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x503c,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x503e,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x5040,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x5042,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x5044,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x5046,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x5048,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x504a,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x504c,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x504e,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x5050,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x5052,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x5054,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x5056,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x5058,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x505a,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x505c,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x505e,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x5060,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x5062,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x5064,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x5066,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x5068,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x506a,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x506c,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x506e,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x5070,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x5072,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x5074,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x5076,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x5078,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x507a,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x507c,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x507e,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x5080,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x5082,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x5084,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x5086,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x5088,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x508a,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x508c,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x508e,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x5090,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x5092,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x5094,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x5096,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x5098,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x509a,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x509c,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x509e,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x50a0,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x50a2,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x50a4,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x50a6,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x50a8,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x50aa,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x50ac,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x50ae,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x50b0,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x50b2,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x50b4,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x50b6,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x50b8,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x50ba,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x50bc,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x50be,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x50c0,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x50c2,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x50c4,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x50c6,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x50c8,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x50ca,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x50cc,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x50ce,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x50d0,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x50d2,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x50d4,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x50d6,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x50d8,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x50da,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x50dc,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x50de,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x50e0,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x50e2,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x50e4,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x50e6,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x50e8,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x50ea,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x50ec,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x50ee,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x50f0,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x50f2,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x50f4,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x50f6,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x50f8,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x50fa,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x50fc,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x50fe,0x0110,VR::US,VM::VM1_n,"Curve Data Descriptor","CurveDataDescriptor",true }, + {0x5000,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x5002,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x5004,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x5006,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x5008,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x500a,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x500c,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x500e,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x5010,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x5012,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x5014,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x5016,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x5018,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x501a,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x501c,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x501e,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x5020,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x5022,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x5024,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x5026,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x5028,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x502a,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x502c,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x502e,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x5030,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x5032,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x5034,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x5036,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x5038,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x503a,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x503c,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x503e,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x5040,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x5042,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x5044,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x5046,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x5048,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x504a,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x504c,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x504e,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x5050,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x5052,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x5054,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x5056,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x5058,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x505a,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x505c,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x505e,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x5060,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x5062,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x5064,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x5066,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x5068,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x506a,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x506c,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x506e,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x5070,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x5072,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x5074,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x5076,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x5078,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x507a,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x507c,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x507e,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x5080,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x5082,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x5084,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x5086,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x5088,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x508a,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x508c,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x508e,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x5090,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x5092,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x5094,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x5096,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x5098,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x509a,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x509c,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x509e,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x50a0,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x50a2,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x50a4,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x50a6,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x50a8,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x50aa,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x50ac,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x50ae,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x50b0,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x50b2,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x50b4,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x50b6,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x50b8,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x50ba,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x50bc,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x50be,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x50c0,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x50c2,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x50c4,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x50c6,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x50c8,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x50ca,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x50cc,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x50ce,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x50d0,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x50d2,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x50d4,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x50d6,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x50d8,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x50da,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x50dc,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x50de,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x50e0,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x50e2,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x50e4,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x50e6,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x50e8,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x50ea,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x50ec,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x50ee,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x50f0,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x50f2,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x50f4,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x50f6,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x50f8,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x50fa,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x50fc,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x50fe,0x0112,VR::US,VM::VM1_n,"Coordinate Start Value","CoordinateStartValue",true }, + {0x5000,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x5002,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x5004,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x5006,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x5008,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x500a,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x500c,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x500e,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x5010,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x5012,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x5014,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x5016,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x5018,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x501a,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x501c,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x501e,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x5020,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x5022,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x5024,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x5026,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x5028,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x502a,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x502c,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x502e,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x5030,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x5032,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x5034,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x5036,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x5038,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x503a,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x503c,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x503e,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x5040,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x5042,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x5044,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x5046,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x5048,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x504a,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x504c,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x504e,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x5050,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x5052,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x5054,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x5056,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x5058,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x505a,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x505c,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x505e,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x5060,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x5062,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x5064,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x5066,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x5068,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x506a,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x506c,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x506e,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x5070,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x5072,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x5074,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x5076,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x5078,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x507a,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x507c,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x507e,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x5080,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x5082,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x5084,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x5086,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x5088,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x508a,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x508c,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x508e,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x5090,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x5092,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x5094,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x5096,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x5098,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x509a,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x509c,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x509e,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x50a0,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x50a2,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x50a4,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x50a6,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x50a8,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x50aa,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x50ac,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x50ae,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x50b0,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x50b2,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x50b4,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x50b6,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x50b8,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x50ba,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x50bc,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x50be,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x50c0,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x50c2,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x50c4,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x50c6,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x50c8,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x50ca,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x50cc,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x50ce,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x50d0,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x50d2,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x50d4,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x50d6,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x50d8,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x50da,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x50dc,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x50de,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x50e0,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x50e2,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x50e4,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x50e6,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x50e8,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x50ea,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x50ec,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x50ee,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x50f0,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x50f2,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x50f4,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x50f6,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x50f8,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x50fa,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x50fc,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x50fe,0x0114,VR::US,VM::VM1_n,"Coordinate Step Value","CoordinateStepValue",true }, + {0x5000,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x5002,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x5004,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x5006,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x5008,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x500a,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x500c,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x500e,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x5010,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x5012,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x5014,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x5016,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x5018,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x501a,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x501c,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x501e,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x5020,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x5022,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x5024,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x5026,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x5028,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x502a,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x502c,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x502e,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x5030,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x5032,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x5034,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x5036,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x5038,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x503a,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x503c,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x503e,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x5040,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x5042,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x5044,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x5046,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x5048,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x504a,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x504c,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x504e,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x5050,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x5052,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x5054,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x5056,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x5058,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x505a,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x505c,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x505e,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x5060,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x5062,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x5064,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x5066,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x5068,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x506a,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x506c,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x506e,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x5070,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x5072,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x5074,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x5076,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x5078,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x507a,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x507c,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x507e,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x5080,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x5082,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x5084,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x5086,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x5088,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x508a,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x508c,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x508e,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x5090,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x5092,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x5094,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x5096,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x5098,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x509a,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x509c,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x509e,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x50a0,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x50a2,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x50a4,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x50a6,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x50a8,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x50aa,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x50ac,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x50ae,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x50b0,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x50b2,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x50b4,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x50b6,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x50b8,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x50ba,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x50bc,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x50be,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x50c0,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x50c2,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x50c4,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x50c6,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x50c8,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x50ca,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x50cc,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x50ce,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x50d0,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x50d2,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x50d4,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x50d6,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x50d8,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x50da,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x50dc,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x50de,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x50e0,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x50e2,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x50e4,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x50e6,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x50e8,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x50ea,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x50ec,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x50ee,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x50f0,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x50f2,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x50f4,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x50f6,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x50f8,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x50fa,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x50fc,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x50fe,0x1001,VR::CS,VM::VM1,"Curve Activation Layer","CurveActivationLayer",true }, + {0x5000,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x5002,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x5004,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x5006,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x5008,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x500a,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x500c,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x500e,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x5010,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x5012,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x5014,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x5016,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x5018,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x501a,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x501c,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x501e,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x5020,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x5022,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x5024,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x5026,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x5028,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x502a,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x502c,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x502e,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x5030,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x5032,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x5034,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x5036,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x5038,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x503a,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x503c,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x503e,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x5040,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x5042,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x5044,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x5046,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x5048,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x504a,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x504c,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x504e,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x5050,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x5052,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x5054,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x5056,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x5058,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x505a,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x505c,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x505e,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x5060,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x5062,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x5064,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x5066,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x5068,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x506a,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x506c,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x506e,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x5070,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x5072,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x5074,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x5076,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x5078,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x507a,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x507c,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x507e,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x5080,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x5082,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x5084,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x5086,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x5088,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x508a,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x508c,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x508e,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x5090,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x5092,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x5094,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x5096,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x5098,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x509a,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x509c,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x509e,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x50a0,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x50a2,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x50a4,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x50a6,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x50a8,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x50aa,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x50ac,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x50ae,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x50b0,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x50b2,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x50b4,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x50b6,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x50b8,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x50ba,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x50bc,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x50be,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x50c0,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x50c2,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x50c4,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x50c6,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x50c8,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x50ca,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x50cc,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x50ce,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x50d0,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x50d2,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x50d4,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x50d6,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x50d8,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x50da,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x50dc,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x50de,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x50e0,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x50e2,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x50e4,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x50e6,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x50e8,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x50ea,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x50ec,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x50ee,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x50f0,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x50f2,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x50f4,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x50f6,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x50f8,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x50fa,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x50fc,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x50fe,0x2000,VR::US,VM::VM1,"Audio Type","AudioType",true }, + {0x5000,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x5002,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x5004,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x5006,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x5008,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x500a,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x500c,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x500e,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x5010,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x5012,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x5014,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x5016,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x5018,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x501a,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x501c,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x501e,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x5020,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x5022,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x5024,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x5026,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x5028,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x502a,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x502c,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x502e,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x5030,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x5032,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x5034,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x5036,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x5038,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x503a,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x503c,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x503e,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x5040,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x5042,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x5044,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x5046,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x5048,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x504a,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x504c,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x504e,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x5050,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x5052,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x5054,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x5056,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x5058,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x505a,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x505c,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x505e,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x5060,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x5062,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x5064,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x5066,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x5068,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x506a,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x506c,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x506e,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x5070,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x5072,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x5074,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x5076,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x5078,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x507a,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x507c,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x507e,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x5080,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x5082,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x5084,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x5086,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x5088,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x508a,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x508c,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x508e,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x5090,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x5092,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x5094,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x5096,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x5098,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x509a,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x509c,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x509e,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x50a0,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x50a2,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x50a4,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x50a6,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x50a8,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x50aa,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x50ac,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x50ae,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x50b0,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x50b2,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x50b4,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x50b6,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x50b8,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x50ba,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x50bc,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x50be,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x50c0,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x50c2,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x50c4,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x50c6,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x50c8,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x50ca,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x50cc,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x50ce,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x50d0,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x50d2,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x50d4,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x50d6,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x50d8,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x50da,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x50dc,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x50de,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x50e0,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x50e2,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x50e4,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x50e6,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x50e8,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x50ea,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x50ec,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x50ee,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x50f0,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x50f2,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x50f4,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x50f6,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x50f8,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x50fa,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x50fc,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x50fe,0x2002,VR::US,VM::VM1,"Audio Sample Format","AudioSampleFormat",true }, + {0x5000,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x5002,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x5004,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x5006,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x5008,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x500a,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x500c,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x500e,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x5010,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x5012,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x5014,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x5016,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x5018,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x501a,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x501c,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x501e,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x5020,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x5022,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x5024,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x5026,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x5028,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x502a,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x502c,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x502e,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x5030,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x5032,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x5034,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x5036,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x5038,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x503a,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x503c,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x503e,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x5040,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x5042,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x5044,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x5046,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x5048,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x504a,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x504c,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x504e,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x5050,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x5052,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x5054,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x5056,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x5058,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x505a,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x505c,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x505e,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x5060,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x5062,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x5064,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x5066,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x5068,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x506a,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x506c,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x506e,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x5070,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x5072,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x5074,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x5076,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x5078,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x507a,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x507c,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x507e,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x5080,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x5082,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x5084,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x5086,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x5088,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x508a,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x508c,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x508e,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x5090,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x5092,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x5094,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x5096,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x5098,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x509a,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x509c,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x509e,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x50a0,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x50a2,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x50a4,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x50a6,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x50a8,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x50aa,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x50ac,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x50ae,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x50b0,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x50b2,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x50b4,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x50b6,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x50b8,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x50ba,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x50bc,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x50be,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x50c0,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x50c2,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x50c4,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x50c6,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x50c8,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x50ca,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x50cc,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x50ce,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x50d0,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x50d2,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x50d4,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x50d6,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x50d8,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x50da,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x50dc,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x50de,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x50e0,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x50e2,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x50e4,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x50e6,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x50e8,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x50ea,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x50ec,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x50ee,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x50f0,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x50f2,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x50f4,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x50f6,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x50f8,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x50fa,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x50fc,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x50fe,0x2004,VR::US,VM::VM1,"Number of Channels","NumberOfChannels",true }, + {0x5000,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x5002,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x5004,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x5006,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x5008,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x500a,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x500c,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x500e,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x5010,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x5012,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x5014,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x5016,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x5018,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x501a,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x501c,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x501e,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x5020,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x5022,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x5024,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x5026,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x5028,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x502a,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x502c,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x502e,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x5030,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x5032,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x5034,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x5036,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x5038,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x503a,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x503c,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x503e,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x5040,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x5042,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x5044,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x5046,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x5048,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x504a,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x504c,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x504e,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x5050,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x5052,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x5054,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x5056,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x5058,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x505a,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x505c,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x505e,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x5060,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x5062,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x5064,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x5066,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x5068,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x506a,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x506c,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x506e,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x5070,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x5072,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x5074,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x5076,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x5078,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x507a,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x507c,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x507e,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x5080,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x5082,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x5084,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x5086,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x5088,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x508a,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x508c,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x508e,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x5090,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x5092,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x5094,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x5096,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x5098,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x509a,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x509c,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x509e,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x50a0,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x50a2,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x50a4,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x50a6,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x50a8,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x50aa,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x50ac,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x50ae,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x50b0,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x50b2,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x50b4,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x50b6,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x50b8,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x50ba,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x50bc,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x50be,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x50c0,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x50c2,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x50c4,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x50c6,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x50c8,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x50ca,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x50cc,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x50ce,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x50d0,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x50d2,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x50d4,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x50d6,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x50d8,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x50da,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x50dc,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x50de,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x50e0,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x50e2,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x50e4,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x50e6,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x50e8,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x50ea,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x50ec,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x50ee,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x50f0,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x50f2,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x50f4,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x50f6,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x50f8,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x50fa,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x50fc,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x50fe,0x2006,VR::UL,VM::VM1,"Number of Samples","NumberOfSamples",true }, + {0x5000,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x5002,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x5004,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x5006,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x5008,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x500a,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x500c,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x500e,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x5010,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x5012,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x5014,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x5016,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x5018,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x501a,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x501c,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x501e,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x5020,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x5022,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x5024,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x5026,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x5028,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x502a,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x502c,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x502e,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x5030,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x5032,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x5034,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x5036,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x5038,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x503a,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x503c,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x503e,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x5040,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x5042,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x5044,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x5046,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x5048,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x504a,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x504c,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x504e,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x5050,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x5052,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x5054,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x5056,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x5058,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x505a,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x505c,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x505e,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x5060,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x5062,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x5064,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x5066,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x5068,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x506a,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x506c,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x506e,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x5070,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x5072,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x5074,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x5076,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x5078,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x507a,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x507c,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x507e,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x5080,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x5082,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x5084,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x5086,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x5088,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x508a,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x508c,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x508e,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x5090,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x5092,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x5094,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x5096,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x5098,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x509a,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x509c,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x509e,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x50a0,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x50a2,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x50a4,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x50a6,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x50a8,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x50aa,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x50ac,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x50ae,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x50b0,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x50b2,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x50b4,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x50b6,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x50b8,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x50ba,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x50bc,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x50be,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x50c0,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x50c2,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x50c4,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x50c6,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x50c8,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x50ca,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x50cc,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x50ce,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x50d0,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x50d2,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x50d4,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x50d6,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x50d8,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x50da,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x50dc,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x50de,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x50e0,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x50e2,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x50e4,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x50e6,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x50e8,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x50ea,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x50ec,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x50ee,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x50f0,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x50f2,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x50f4,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x50f6,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x50f8,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x50fa,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x50fc,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x50fe,0x2008,VR::UL,VM::VM1,"Sample Rate","SampleRate",true }, + {0x5000,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x5002,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x5004,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x5006,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x5008,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x500a,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x500c,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x500e,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x5010,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x5012,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x5014,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x5016,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x5018,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x501a,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x501c,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x501e,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x5020,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x5022,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x5024,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x5026,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x5028,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x502a,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x502c,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x502e,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x5030,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x5032,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x5034,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x5036,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x5038,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x503a,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x503c,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x503e,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x5040,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x5042,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x5044,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x5046,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x5048,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x504a,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x504c,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x504e,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x5050,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x5052,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x5054,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x5056,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x5058,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x505a,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x505c,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x505e,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x5060,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x5062,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x5064,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x5066,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x5068,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x506a,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x506c,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x506e,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x5070,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x5072,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x5074,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x5076,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x5078,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x507a,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x507c,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x507e,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x5080,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x5082,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x5084,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x5086,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x5088,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x508a,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x508c,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x508e,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x5090,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x5092,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x5094,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x5096,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x5098,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x509a,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x509c,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x509e,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x50a0,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x50a2,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x50a4,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x50a6,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x50a8,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x50aa,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x50ac,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x50ae,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x50b0,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x50b2,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x50b4,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x50b6,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x50b8,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x50ba,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x50bc,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x50be,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x50c0,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x50c2,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x50c4,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x50c6,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x50c8,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x50ca,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x50cc,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x50ce,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x50d0,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x50d2,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x50d4,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x50d6,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x50d8,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x50da,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x50dc,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x50de,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x50e0,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x50e2,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x50e4,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x50e6,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x50e8,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x50ea,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x50ec,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x50ee,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x50f0,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x50f2,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x50f4,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x50f6,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x50f8,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x50fa,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x50fc,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x50fe,0x200a,VR::UL,VM::VM1,"Total Time","TotalTime",true }, + {0x5000,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x5002,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x5004,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x5006,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x5008,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x500a,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x500c,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x500e,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x5010,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x5012,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x5014,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x5016,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x5018,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x501a,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x501c,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x501e,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x5020,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x5022,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x5024,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x5026,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x5028,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x502a,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x502c,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x502e,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x5030,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x5032,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x5034,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x5036,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x5038,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x503a,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x503c,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x503e,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x5040,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x5042,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x5044,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x5046,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x5048,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x504a,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x504c,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x504e,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x5050,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x5052,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x5054,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x5056,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x5058,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x505a,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x505c,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x505e,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x5060,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x5062,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x5064,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x5066,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x5068,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x506a,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x506c,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x506e,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x5070,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x5072,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x5074,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x5076,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x5078,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x507a,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x507c,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x507e,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x5080,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x5082,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x5084,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x5086,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x5088,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x508a,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x508c,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x508e,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x5090,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x5092,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x5094,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x5096,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x5098,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x509a,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x509c,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x509e,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x50a0,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x50a2,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x50a4,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x50a6,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x50a8,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x50aa,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x50ac,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x50ae,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x50b0,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x50b2,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x50b4,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x50b6,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x50b8,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x50ba,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x50bc,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x50be,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x50c0,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x50c2,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x50c4,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x50c6,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x50c8,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x50ca,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x50cc,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x50ce,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x50d0,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x50d2,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x50d4,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x50d6,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x50d8,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x50da,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x50dc,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x50de,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x50e0,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x50e2,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x50e4,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x50e6,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x50e8,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x50ea,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x50ec,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x50ee,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x50f0,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x50f2,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x50f4,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x50f6,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x50f8,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x50fa,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x50fc,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x50fe,0x200c,VR::OB_OW,VM::VM1,"Audio Sample Data","AudioSampleData",true }, + {0x5000,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x5002,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x5004,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x5006,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x5008,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x500a,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x500c,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x500e,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x5010,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x5012,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x5014,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x5016,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x5018,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x501a,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x501c,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x501e,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x5020,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x5022,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x5024,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x5026,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x5028,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x502a,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x502c,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x502e,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x5030,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x5032,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x5034,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x5036,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x5038,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x503a,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x503c,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x503e,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x5040,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x5042,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x5044,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x5046,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x5048,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x504a,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x504c,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x504e,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x5050,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x5052,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x5054,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x5056,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x5058,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x505a,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x505c,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x505e,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x5060,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x5062,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x5064,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x5066,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x5068,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x506a,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x506c,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x506e,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x5070,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x5072,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x5074,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x5076,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x5078,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x507a,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x507c,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x507e,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x5080,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x5082,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x5084,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x5086,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x5088,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x508a,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x508c,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x508e,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x5090,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x5092,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x5094,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x5096,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x5098,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x509a,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x509c,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x509e,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x50a0,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x50a2,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x50a4,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x50a6,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x50a8,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x50aa,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x50ac,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x50ae,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x50b0,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x50b2,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x50b4,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x50b6,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x50b8,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x50ba,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x50bc,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x50be,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x50c0,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x50c2,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x50c4,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x50c6,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x50c8,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x50ca,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x50cc,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x50ce,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x50d0,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x50d2,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x50d4,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x50d6,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x50d8,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x50da,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x50dc,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x50de,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x50e0,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x50e2,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x50e4,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x50e6,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x50e8,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x50ea,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x50ec,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x50ee,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x50f0,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x50f2,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x50f4,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x50f6,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x50f8,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x50fa,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x50fc,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x50fe,0x200e,VR::LT,VM::VM1,"Audio Comments","AudioComments",true }, + {0x5000,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x5002,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x5004,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x5006,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x5008,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x500a,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x500c,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x500e,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x5010,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x5012,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x5014,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x5016,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x5018,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x501a,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x501c,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x501e,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x5020,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x5022,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x5024,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x5026,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x5028,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x502a,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x502c,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x502e,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x5030,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x5032,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x5034,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x5036,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x5038,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x503a,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x503c,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x503e,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x5040,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x5042,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x5044,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x5046,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x5048,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x504a,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x504c,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x504e,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x5050,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x5052,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x5054,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x5056,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x5058,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x505a,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x505c,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x505e,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x5060,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x5062,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x5064,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x5066,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x5068,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x506a,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x506c,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x506e,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x5070,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x5072,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x5074,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x5076,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x5078,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x507a,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x507c,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x507e,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x5080,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x5082,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x5084,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x5086,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x5088,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x508a,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x508c,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x508e,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x5090,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x5092,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x5094,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x5096,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x5098,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x509a,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x509c,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x509e,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x50a0,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x50a2,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x50a4,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x50a6,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x50a8,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x50aa,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x50ac,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x50ae,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x50b0,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x50b2,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x50b4,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x50b6,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x50b8,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x50ba,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x50bc,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x50be,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x50c0,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x50c2,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x50c4,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x50c6,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x50c8,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x50ca,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x50cc,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x50ce,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x50d0,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x50d2,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x50d4,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x50d6,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x50d8,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x50da,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x50dc,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x50de,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x50e0,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x50e2,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x50e4,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x50e6,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x50e8,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x50ea,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x50ec,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x50ee,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x50f0,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x50f2,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x50f4,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x50f6,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x50f8,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x50fa,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x50fc,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x50fe,0x2500,VR::LO,VM::VM1,"Curve Label","CurveLabel",true }, + {0x5000,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x5002,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x5004,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x5006,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x5008,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x500a,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x500c,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x500e,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x5010,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x5012,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x5014,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x5016,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x5018,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x501a,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x501c,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x501e,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x5020,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x5022,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x5024,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x5026,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x5028,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x502a,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x502c,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x502e,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x5030,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x5032,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x5034,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x5036,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x5038,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x503a,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x503c,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x503e,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x5040,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x5042,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x5044,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x5046,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x5048,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x504a,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x504c,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x504e,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x5050,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x5052,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x5054,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x5056,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x5058,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x505a,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x505c,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x505e,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x5060,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x5062,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x5064,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x5066,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x5068,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x506a,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x506c,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x506e,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x5070,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x5072,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x5074,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x5076,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x5078,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x507a,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x507c,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x507e,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x5080,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x5082,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x5084,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x5086,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x5088,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x508a,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x508c,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x508e,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x5090,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x5092,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x5094,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x5096,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x5098,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x509a,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x509c,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x509e,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x50a0,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x50a2,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x50a4,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x50a6,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x50a8,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x50aa,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x50ac,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x50ae,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x50b0,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x50b2,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x50b4,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x50b6,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x50b8,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x50ba,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x50bc,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x50be,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x50c0,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x50c2,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x50c4,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x50c6,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x50c8,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x50ca,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x50cc,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x50ce,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x50d0,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x50d2,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x50d4,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x50d6,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x50d8,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x50da,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x50dc,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x50de,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x50e0,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x50e2,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x50e4,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x50e6,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x50e8,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x50ea,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x50ec,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x50ee,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x50f0,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x50f2,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x50f4,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x50f6,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x50f8,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x50fa,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x50fc,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x50fe,0x2600,VR::SQ,VM::VM1,"Curve Referenced Overlay Sequence","CurveReferencedOverlaySequence",true }, + {0x5000,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x5002,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x5004,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x5006,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x5008,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x500a,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x500c,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x500e,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x5010,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x5012,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x5014,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x5016,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x5018,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x501a,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x501c,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x501e,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x5020,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x5022,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x5024,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x5026,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x5028,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x502a,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x502c,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x502e,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x5030,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x5032,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x5034,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x5036,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x5038,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x503a,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x503c,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x503e,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x5040,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x5042,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x5044,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x5046,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x5048,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x504a,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x504c,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x504e,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x5050,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x5052,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x5054,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x5056,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x5058,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x505a,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x505c,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x505e,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x5060,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x5062,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x5064,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x5066,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x5068,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x506a,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x506c,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x506e,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x5070,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x5072,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x5074,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x5076,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x5078,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x507a,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x507c,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x507e,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x5080,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x5082,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x5084,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x5086,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x5088,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x508a,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x508c,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x508e,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x5090,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x5092,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x5094,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x5096,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x5098,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x509a,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x509c,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x509e,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x50a0,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x50a2,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x50a4,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x50a6,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x50a8,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x50aa,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x50ac,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x50ae,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x50b0,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x50b2,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x50b4,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x50b6,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x50b8,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x50ba,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x50bc,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x50be,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x50c0,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x50c2,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x50c4,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x50c6,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x50c8,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x50ca,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x50cc,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x50ce,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x50d0,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x50d2,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x50d4,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x50d6,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x50d8,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x50da,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x50dc,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x50de,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x50e0,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x50e2,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x50e4,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x50e6,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x50e8,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x50ea,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x50ec,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x50ee,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x50f0,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x50f2,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x50f4,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x50f6,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x50f8,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x50fa,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x50fc,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x50fe,0x2610,VR::US,VM::VM1,"Curve Referenced Overlay Group","CurveReferencedOverlayGroup",true }, + {0x5000,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x5002,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x5004,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x5006,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x5008,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x500a,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x500c,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x500e,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x5010,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x5012,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x5014,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x5016,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x5018,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x501a,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x501c,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x501e,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x5020,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x5022,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x5024,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x5026,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x5028,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x502a,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x502c,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x502e,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x5030,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x5032,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x5034,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x5036,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x5038,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x503a,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x503c,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x503e,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x5040,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x5042,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x5044,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x5046,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x5048,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x504a,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x504c,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x504e,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x5050,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x5052,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x5054,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x5056,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x5058,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x505a,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x505c,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x505e,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x5060,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x5062,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x5064,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x5066,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x5068,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x506a,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x506c,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x506e,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x5070,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x5072,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x5074,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x5076,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x5078,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x507a,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x507c,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x507e,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x5080,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x5082,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x5084,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x5086,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x5088,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x508a,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x508c,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x508e,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x5090,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x5092,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x5094,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x5096,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x5098,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x509a,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x509c,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x509e,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x50a0,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x50a2,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x50a4,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x50a6,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x50a8,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x50aa,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x50ac,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x50ae,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x50b0,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x50b2,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x50b4,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x50b6,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x50b8,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x50ba,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x50bc,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x50be,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x50c0,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x50c2,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x50c4,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x50c6,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x50c8,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x50ca,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x50cc,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x50ce,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x50d0,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x50d2,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x50d4,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x50d6,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x50d8,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x50da,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x50dc,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x50de,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x50e0,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x50e2,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x50e4,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x50e6,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x50e8,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x50ea,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x50ec,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x50ee,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x50f0,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x50f2,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x50f4,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x50f6,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x50f8,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x50fa,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x50fc,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x50fe,0x3000,VR::OB_OW,VM::VM1,"Curve Data","CurveData",true }, + {0x5200,0x9229,VR::SQ,VM::VM1,"Shared Functional Groups Sequence","SharedFunctionalGroupsSequence",false }, + {0x5200,0x9230,VR::SQ,VM::VM1,"Per-frame Functional Groups Sequence","PerFrameFunctionalGroupsSequence",false }, + {0x5400,0x0100,VR::SQ,VM::VM1,"Waveform Sequence","WaveformSequence",false }, + {0x5400,0x0110,VR::OB_OW,VM::VM1,"Channel Minimum Value","ChannelMinimumValue",false }, + {0x5400,0x0112,VR::OB_OW,VM::VM1,"Channel Maximum Value","ChannelMaximumValue",false }, + {0x5400,0x1004,VR::US,VM::VM1,"Waveform Bits Allocated","WaveformBitsAllocated",false }, + {0x5400,0x1006,VR::CS,VM::VM1,"Waveform Sample Interpretation","WaveformSampleInterpretation",false }, + {0x5400,0x100a,VR::OB_OW,VM::VM1,"Waveform Padding Value","WaveformPaddingValue",false }, + {0x5400,0x1010,VR::OB_OW,VM::VM1,"Waveform Data","WaveformData",false }, + {0x5600,0x0010,VR::OF,VM::VM1,"First Order Phase Correction Angle","FirstOrderPhaseCorrectionAngle",false }, + {0x5600,0x0020,VR::OF,VM::VM1,"Spectroscopy Data","SpectroscopyData",false }, + {0x6000,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x6002,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x6004,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x6006,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x6008,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x600a,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x600c,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x600e,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x6010,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x6012,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x6014,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x6016,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x6018,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x601a,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x601c,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x601e,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x6020,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x6022,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x6024,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x6026,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x6028,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x602a,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x602c,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x602e,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x6030,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x6032,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x6034,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x6036,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x6038,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x603a,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x603c,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x603e,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x6040,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x6042,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x6044,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x6046,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x6048,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x604a,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x604c,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x604e,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x6050,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x6052,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x6054,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x6056,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x6058,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x605a,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x605c,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x605e,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x6060,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x6062,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x6064,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x6066,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x6068,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x606a,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x606c,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x606e,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x6070,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x6072,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x6074,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x6076,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x6078,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x607a,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x607c,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x607e,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x6080,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x6082,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x6084,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x6086,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x6088,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x608a,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x608c,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x608e,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x6090,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x6092,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x6094,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x6096,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x6098,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x609a,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x609c,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x609e,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x60a0,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x60a2,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x60a4,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x60a6,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x60a8,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x60aa,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x60ac,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x60ae,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x60b0,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x60b2,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x60b4,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x60b6,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x60b8,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x60ba,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x60bc,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x60be,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x60c0,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x60c2,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x60c4,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x60c6,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x60c8,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x60ca,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x60cc,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x60ce,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x60d0,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x60d2,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x60d4,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x60d6,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x60d8,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x60da,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x60dc,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x60de,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x60e0,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x60e2,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x60e4,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x60e6,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x60e8,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x60ea,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x60ec,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x60ee,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x60f0,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x60f2,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x60f4,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x60f6,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x60f8,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x60fa,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x60fc,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x60fe,0x0010,VR::US,VM::VM1,"Overlay Rows","OverlayRows",false }, + {0x6000,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x6002,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x6004,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x6006,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x6008,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x600a,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x600c,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x600e,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x6010,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x6012,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x6014,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x6016,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x6018,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x601a,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x601c,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x601e,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x6020,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x6022,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x6024,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x6026,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x6028,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x602a,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x602c,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x602e,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x6030,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x6032,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x6034,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x6036,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x6038,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x603a,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x603c,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x603e,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x6040,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x6042,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x6044,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x6046,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x6048,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x604a,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x604c,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x604e,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x6050,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x6052,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x6054,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x6056,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x6058,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x605a,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x605c,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x605e,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x6060,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x6062,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x6064,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x6066,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x6068,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x606a,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x606c,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x606e,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x6070,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x6072,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x6074,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x6076,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x6078,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x607a,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x607c,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x607e,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x6080,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x6082,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x6084,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x6086,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x6088,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x608a,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x608c,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x608e,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x6090,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x6092,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x6094,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x6096,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x6098,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x609a,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x609c,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x609e,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x60a0,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x60a2,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x60a4,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x60a6,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x60a8,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x60aa,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x60ac,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x60ae,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x60b0,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x60b2,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x60b4,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x60b6,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x60b8,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x60ba,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x60bc,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x60be,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x60c0,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x60c2,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x60c4,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x60c6,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x60c8,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x60ca,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x60cc,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x60ce,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x60d0,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x60d2,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x60d4,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x60d6,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x60d8,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x60da,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x60dc,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x60de,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x60e0,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x60e2,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x60e4,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x60e6,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x60e8,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x60ea,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x60ec,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x60ee,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x60f0,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x60f2,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x60f4,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x60f6,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x60f8,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x60fa,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x60fc,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x60fe,0x0011,VR::US,VM::VM1,"Overlay Columns","OverlayColumns",false }, + {0x6000,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x6002,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x6004,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x6006,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x6008,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x600a,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x600c,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x600e,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x6010,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x6012,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x6014,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x6016,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x6018,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x601a,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x601c,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x601e,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x6020,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x6022,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x6024,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x6026,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x6028,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x602a,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x602c,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x602e,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x6030,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x6032,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x6034,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x6036,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x6038,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x603a,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x603c,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x603e,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x6040,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x6042,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x6044,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x6046,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x6048,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x604a,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x604c,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x604e,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x6050,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x6052,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x6054,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x6056,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x6058,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x605a,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x605c,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x605e,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x6060,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x6062,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x6064,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x6066,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x6068,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x606a,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x606c,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x606e,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x6070,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x6072,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x6074,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x6076,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x6078,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x607a,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x607c,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x607e,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x6080,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x6082,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x6084,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x6086,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x6088,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x608a,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x608c,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x608e,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x6090,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x6092,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x6094,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x6096,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x6098,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x609a,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x609c,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x609e,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x60a0,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x60a2,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x60a4,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x60a6,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x60a8,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x60aa,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x60ac,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x60ae,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x60b0,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x60b2,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x60b4,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x60b6,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x60b8,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x60ba,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x60bc,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x60be,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x60c0,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x60c2,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x60c4,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x60c6,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x60c8,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x60ca,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x60cc,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x60ce,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x60d0,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x60d2,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x60d4,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x60d6,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x60d8,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x60da,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x60dc,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x60de,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x60e0,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x60e2,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x60e4,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x60e6,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x60e8,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x60ea,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x60ec,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x60ee,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x60f0,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x60f2,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x60f4,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x60f6,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x60f8,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x60fa,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x60fc,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x60fe,0x0012,VR::US,VM::VM1,"Overlay Planes","OverlayPlanes",true }, + {0x6000,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x6002,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x6004,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x6006,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x6008,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x600a,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x600c,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x600e,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x6010,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x6012,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x6014,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x6016,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x6018,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x601a,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x601c,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x601e,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x6020,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x6022,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x6024,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x6026,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x6028,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x602a,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x602c,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x602e,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x6030,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x6032,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x6034,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x6036,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x6038,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x603a,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x603c,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x603e,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x6040,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x6042,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x6044,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x6046,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x6048,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x604a,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x604c,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x604e,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x6050,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x6052,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x6054,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x6056,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x6058,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x605a,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x605c,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x605e,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x6060,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x6062,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x6064,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x6066,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x6068,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x606a,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x606c,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x606e,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x6070,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x6072,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x6074,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x6076,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x6078,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x607a,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x607c,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x607e,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x6080,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x6082,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x6084,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x6086,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x6088,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x608a,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x608c,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x608e,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x6090,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x6092,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x6094,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x6096,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x6098,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x609a,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x609c,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x609e,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x60a0,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x60a2,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x60a4,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x60a6,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x60a8,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x60aa,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x60ac,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x60ae,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x60b0,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x60b2,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x60b4,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x60b6,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x60b8,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x60ba,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x60bc,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x60be,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x60c0,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x60c2,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x60c4,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x60c6,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x60c8,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x60ca,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x60cc,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x60ce,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x60d0,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x60d2,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x60d4,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x60d6,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x60d8,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x60da,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x60dc,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x60de,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x60e0,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x60e2,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x60e4,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x60e6,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x60e8,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x60ea,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x60ec,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x60ee,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x60f0,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x60f2,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x60f4,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x60f6,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x60f8,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x60fa,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x60fc,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x60fe,0x0015,VR::IS,VM::VM1,"Number of Frames in Overlay","NumberOfFramesInOverlay",false }, + {0x6000,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x6002,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x6004,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x6006,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x6008,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x600a,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x600c,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x600e,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x6010,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x6012,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x6014,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x6016,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x6018,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x601a,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x601c,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x601e,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x6020,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x6022,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x6024,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x6026,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x6028,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x602a,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x602c,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x602e,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x6030,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x6032,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x6034,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x6036,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x6038,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x603a,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x603c,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x603e,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x6040,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x6042,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x6044,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x6046,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x6048,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x604a,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x604c,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x604e,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x6050,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x6052,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x6054,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x6056,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x6058,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x605a,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x605c,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x605e,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x6060,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x6062,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x6064,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x6066,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x6068,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x606a,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x606c,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x606e,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x6070,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x6072,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x6074,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x6076,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x6078,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x607a,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x607c,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x607e,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x6080,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x6082,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x6084,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x6086,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x6088,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x608a,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x608c,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x608e,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x6090,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x6092,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x6094,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x6096,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x6098,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x609a,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x609c,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x609e,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x60a0,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x60a2,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x60a4,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x60a6,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x60a8,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x60aa,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x60ac,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x60ae,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x60b0,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x60b2,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x60b4,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x60b6,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x60b8,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x60ba,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x60bc,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x60be,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x60c0,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x60c2,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x60c4,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x60c6,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x60c8,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x60ca,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x60cc,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x60ce,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x60d0,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x60d2,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x60d4,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x60d6,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x60d8,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x60da,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x60dc,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x60de,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x60e0,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x60e2,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x60e4,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x60e6,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x60e8,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x60ea,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x60ec,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x60ee,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x60f0,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x60f2,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x60f4,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x60f6,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x60f8,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x60fa,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x60fc,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x60fe,0x0022,VR::LO,VM::VM1,"Overlay Description","OverlayDescription",false }, + {0x6000,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x6002,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x6004,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x6006,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x6008,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x600a,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x600c,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x600e,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x6010,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x6012,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x6014,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x6016,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x6018,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x601a,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x601c,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x601e,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x6020,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x6022,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x6024,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x6026,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x6028,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x602a,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x602c,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x602e,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x6030,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x6032,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x6034,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x6036,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x6038,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x603a,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x603c,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x603e,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x6040,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x6042,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x6044,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x6046,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x6048,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x604a,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x604c,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x604e,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x6050,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x6052,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x6054,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x6056,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x6058,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x605a,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x605c,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x605e,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x6060,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x6062,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x6064,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x6066,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x6068,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x606a,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x606c,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x606e,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x6070,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x6072,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x6074,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x6076,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x6078,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x607a,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x607c,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x607e,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x6080,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x6082,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x6084,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x6086,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x6088,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x608a,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x608c,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x608e,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x6090,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x6092,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x6094,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x6096,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x6098,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x609a,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x609c,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x609e,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x60a0,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x60a2,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x60a4,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x60a6,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x60a8,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x60aa,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x60ac,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x60ae,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x60b0,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x60b2,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x60b4,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x60b6,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x60b8,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x60ba,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x60bc,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x60be,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x60c0,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x60c2,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x60c4,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x60c6,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x60c8,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x60ca,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x60cc,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x60ce,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x60d0,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x60d2,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x60d4,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x60d6,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x60d8,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x60da,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x60dc,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x60de,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x60e0,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x60e2,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x60e4,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x60e6,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x60e8,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x60ea,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x60ec,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x60ee,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x60f0,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x60f2,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x60f4,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x60f6,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x60f8,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x60fa,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x60fc,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x60fe,0x0040,VR::CS,VM::VM1,"Overlay Type","OverlayType",false }, + {0x6000,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x6002,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x6004,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x6006,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x6008,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x600a,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x600c,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x600e,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x6010,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x6012,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x6014,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x6016,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x6018,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x601a,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x601c,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x601e,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x6020,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x6022,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x6024,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x6026,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x6028,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x602a,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x602c,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x602e,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x6030,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x6032,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x6034,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x6036,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x6038,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x603a,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x603c,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x603e,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x6040,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x6042,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x6044,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x6046,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x6048,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x604a,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x604c,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x604e,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x6050,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x6052,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x6054,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x6056,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x6058,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x605a,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x605c,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x605e,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x6060,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x6062,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x6064,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x6066,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x6068,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x606a,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x606c,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x606e,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x6070,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x6072,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x6074,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x6076,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x6078,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x607a,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x607c,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x607e,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x6080,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x6082,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x6084,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x6086,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x6088,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x608a,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x608c,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x608e,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x6090,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x6092,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x6094,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x6096,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x6098,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x609a,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x609c,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x609e,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x60a0,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x60a2,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x60a4,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x60a6,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x60a8,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x60aa,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x60ac,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x60ae,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x60b0,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x60b2,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x60b4,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x60b6,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x60b8,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x60ba,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x60bc,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x60be,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x60c0,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x60c2,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x60c4,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x60c6,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x60c8,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x60ca,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x60cc,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x60ce,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x60d0,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x60d2,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x60d4,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x60d6,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x60d8,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x60da,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x60dc,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x60de,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x60e0,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x60e2,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x60e4,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x60e6,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x60e8,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x60ea,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x60ec,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x60ee,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x60f0,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x60f2,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x60f4,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x60f6,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x60f8,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x60fa,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x60fc,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x60fe,0x0045,VR::LO,VM::VM1,"Overlay Subtype","OverlaySubtype",false }, + {0x6000,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x6002,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x6004,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x6006,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x6008,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x600a,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x600c,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x600e,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x6010,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x6012,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x6014,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x6016,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x6018,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x601a,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x601c,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x601e,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x6020,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x6022,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x6024,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x6026,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x6028,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x602a,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x602c,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x602e,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x6030,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x6032,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x6034,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x6036,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x6038,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x603a,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x603c,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x603e,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x6040,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x6042,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x6044,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x6046,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x6048,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x604a,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x604c,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x604e,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x6050,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x6052,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x6054,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x6056,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x6058,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x605a,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x605c,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x605e,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x6060,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x6062,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x6064,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x6066,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x6068,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x606a,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x606c,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x606e,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x6070,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x6072,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x6074,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x6076,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x6078,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x607a,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x607c,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x607e,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x6080,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x6082,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x6084,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x6086,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x6088,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x608a,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x608c,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x608e,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x6090,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x6092,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x6094,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x6096,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x6098,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x609a,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x609c,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x609e,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x60a0,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x60a2,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x60a4,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x60a6,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x60a8,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x60aa,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x60ac,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x60ae,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x60b0,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x60b2,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x60b4,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x60b6,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x60b8,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x60ba,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x60bc,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x60be,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x60c0,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x60c2,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x60c4,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x60c6,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x60c8,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x60ca,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x60cc,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x60ce,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x60d0,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x60d2,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x60d4,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x60d6,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x60d8,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x60da,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x60dc,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x60de,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x60e0,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x60e2,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x60e4,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x60e6,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x60e8,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x60ea,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x60ec,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x60ee,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x60f0,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x60f2,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x60f4,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x60f6,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x60f8,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x60fa,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x60fc,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x60fe,0x0050,VR::SS,VM::VM2,"Overlay Origin","OverlayOrigin",false }, + {0x6000,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x6002,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x6004,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x6006,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x6008,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x600a,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x600c,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x600e,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x6010,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x6012,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x6014,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x6016,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x6018,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x601a,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x601c,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x601e,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x6020,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x6022,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x6024,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x6026,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x6028,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x602a,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x602c,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x602e,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x6030,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x6032,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x6034,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x6036,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x6038,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x603a,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x603c,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x603e,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x6040,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x6042,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x6044,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x6046,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x6048,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x604a,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x604c,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x604e,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x6050,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x6052,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x6054,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x6056,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x6058,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x605a,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x605c,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x605e,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x6060,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x6062,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x6064,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x6066,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x6068,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x606a,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x606c,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x606e,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x6070,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x6072,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x6074,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x6076,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x6078,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x607a,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x607c,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x607e,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x6080,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x6082,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x6084,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x6086,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x6088,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x608a,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x608c,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x608e,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x6090,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x6092,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x6094,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x6096,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x6098,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x609a,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x609c,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x609e,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x60a0,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x60a2,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x60a4,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x60a6,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x60a8,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x60aa,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x60ac,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x60ae,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x60b0,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x60b2,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x60b4,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x60b6,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x60b8,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x60ba,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x60bc,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x60be,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x60c0,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x60c2,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x60c4,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x60c6,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x60c8,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x60ca,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x60cc,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x60ce,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x60d0,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x60d2,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x60d4,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x60d6,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x60d8,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x60da,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x60dc,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x60de,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x60e0,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x60e2,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x60e4,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x60e6,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x60e8,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x60ea,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x60ec,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x60ee,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x60f0,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x60f2,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x60f4,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x60f6,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x60f8,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x60fa,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x60fc,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x60fe,0x0051,VR::US,VM::VM1,"Image Frame Origin","ImageFrameOrigin",false }, + {0x6000,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x6002,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x6004,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x6006,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x6008,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x600a,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x600c,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x600e,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x6010,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x6012,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x6014,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x6016,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x6018,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x601a,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x601c,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x601e,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x6020,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x6022,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x6024,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x6026,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x6028,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x602a,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x602c,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x602e,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x6030,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x6032,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x6034,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x6036,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x6038,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x603a,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x603c,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x603e,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x6040,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x6042,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x6044,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x6046,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x6048,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x604a,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x604c,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x604e,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x6050,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x6052,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x6054,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x6056,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x6058,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x605a,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x605c,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x605e,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x6060,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x6062,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x6064,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x6066,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x6068,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x606a,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x606c,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x606e,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x6070,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x6072,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x6074,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x6076,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x6078,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x607a,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x607c,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x607e,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x6080,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x6082,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x6084,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x6086,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x6088,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x608a,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x608c,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x608e,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x6090,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x6092,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x6094,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x6096,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x6098,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x609a,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x609c,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x609e,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x60a0,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x60a2,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x60a4,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x60a6,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x60a8,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x60aa,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x60ac,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x60ae,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x60b0,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x60b2,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x60b4,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x60b6,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x60b8,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x60ba,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x60bc,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x60be,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x60c0,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x60c2,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x60c4,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x60c6,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x60c8,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x60ca,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x60cc,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x60ce,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x60d0,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x60d2,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x60d4,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x60d6,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x60d8,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x60da,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x60dc,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x60de,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x60e0,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x60e2,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x60e4,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x60e6,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x60e8,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x60ea,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x60ec,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x60ee,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x60f0,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x60f2,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x60f4,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x60f6,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x60f8,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x60fa,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x60fc,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x60fe,0x0052,VR::US,VM::VM1,"Overlay Plane Origin","OverlayPlaneOrigin",true }, + {0x6000,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x6002,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x6004,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x6006,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x6008,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x600a,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x600c,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x600e,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x6010,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x6012,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x6014,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x6016,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x6018,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x601a,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x601c,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x601e,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x6020,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x6022,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x6024,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x6026,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x6028,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x602a,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x602c,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x602e,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x6030,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x6032,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x6034,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x6036,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x6038,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x603a,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x603c,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x603e,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x6040,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x6042,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x6044,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x6046,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x6048,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x604a,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x604c,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x604e,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x6050,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x6052,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x6054,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x6056,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x6058,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x605a,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x605c,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x605e,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x6060,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x6062,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x6064,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x6066,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x6068,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x606a,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x606c,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x606e,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x6070,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x6072,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x6074,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x6076,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x6078,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x607a,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x607c,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x607e,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x6080,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x6082,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x6084,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x6086,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x6088,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x608a,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x608c,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x608e,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x6090,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x6092,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x6094,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x6096,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x6098,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x609a,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x609c,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x609e,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x60a0,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x60a2,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x60a4,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x60a6,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x60a8,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x60aa,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x60ac,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x60ae,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x60b0,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x60b2,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x60b4,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x60b6,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x60b8,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x60ba,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x60bc,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x60be,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x60c0,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x60c2,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x60c4,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x60c6,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x60c8,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x60ca,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x60cc,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x60ce,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x60d0,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x60d2,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x60d4,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x60d6,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x60d8,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x60da,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x60dc,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x60de,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x60e0,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x60e2,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x60e4,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x60e6,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x60e8,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x60ea,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x60ec,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x60ee,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x60f0,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x60f2,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x60f4,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x60f6,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x60f8,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x60fa,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x60fc,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x60fe,0x0060,VR::CS,VM::VM1,"Overlay Compression Code","OverlayCompressionCode",true }, + {0x6000,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x6002,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x6004,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x6006,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x6008,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x600a,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x600c,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x600e,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x6010,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x6012,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x6014,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x6016,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x6018,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x601a,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x601c,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x601e,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x6020,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x6022,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x6024,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x6026,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x6028,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x602a,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x602c,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x602e,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x6030,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x6032,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x6034,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x6036,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x6038,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x603a,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x603c,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x603e,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x6040,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x6042,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x6044,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x6046,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x6048,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x604a,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x604c,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x604e,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x6050,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x6052,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x6054,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x6056,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x6058,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x605a,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x605c,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x605e,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x6060,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x6062,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x6064,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x6066,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x6068,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x606a,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x606c,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x606e,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x6070,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x6072,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x6074,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x6076,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x6078,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x607a,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x607c,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x607e,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x6080,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x6082,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x6084,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x6086,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x6088,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x608a,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x608c,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x608e,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x6090,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x6092,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x6094,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x6096,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x6098,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x609a,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x609c,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x609e,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x60a0,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x60a2,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x60a4,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x60a6,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x60a8,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x60aa,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x60ac,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x60ae,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x60b0,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x60b2,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x60b4,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x60b6,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x60b8,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x60ba,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x60bc,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x60be,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x60c0,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x60c2,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x60c4,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x60c6,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x60c8,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x60ca,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x60cc,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x60ce,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x60d0,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x60d2,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x60d4,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x60d6,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x60d8,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x60da,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x60dc,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x60de,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x60e0,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x60e2,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x60e4,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x60e6,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x60e8,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x60ea,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x60ec,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x60ee,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x60f0,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x60f2,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x60f4,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x60f6,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x60f8,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x60fa,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x60fc,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x60fe,0x0061,VR::SH,VM::VM1,"Overlay Compression Originator","OverlayCompressionOriginator",true }, + {0x6000,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x6002,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x6004,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x6006,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x6008,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x600a,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x600c,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x600e,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x6010,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x6012,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x6014,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x6016,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x6018,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x601a,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x601c,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x601e,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x6020,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x6022,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x6024,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x6026,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x6028,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x602a,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x602c,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x602e,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x6030,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x6032,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x6034,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x6036,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x6038,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x603a,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x603c,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x603e,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x6040,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x6042,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x6044,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x6046,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x6048,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x604a,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x604c,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x604e,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x6050,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x6052,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x6054,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x6056,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x6058,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x605a,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x605c,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x605e,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x6060,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x6062,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x6064,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x6066,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x6068,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x606a,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x606c,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x606e,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x6070,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x6072,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x6074,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x6076,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x6078,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x607a,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x607c,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x607e,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x6080,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x6082,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x6084,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x6086,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x6088,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x608a,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x608c,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x608e,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x6090,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x6092,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x6094,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x6096,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x6098,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x609a,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x609c,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x609e,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x60a0,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x60a2,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x60a4,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x60a6,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x60a8,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x60aa,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x60ac,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x60ae,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x60b0,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x60b2,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x60b4,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x60b6,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x60b8,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x60ba,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x60bc,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x60be,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x60c0,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x60c2,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x60c4,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x60c6,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x60c8,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x60ca,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x60cc,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x60ce,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x60d0,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x60d2,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x60d4,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x60d6,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x60d8,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x60da,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x60dc,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x60de,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x60e0,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x60e2,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x60e4,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x60e6,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x60e8,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x60ea,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x60ec,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x60ee,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x60f0,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x60f2,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x60f4,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x60f6,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x60f8,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x60fa,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x60fc,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x60fe,0x0062,VR::SH,VM::VM1,"Overlay Compression Label","OverlayCompressionLabel",true }, + {0x6000,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x6002,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x6004,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x6006,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x6008,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x600a,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x600c,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x600e,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x6010,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x6012,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x6014,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x6016,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x6018,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x601a,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x601c,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x601e,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x6020,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x6022,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x6024,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x6026,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x6028,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x602a,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x602c,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x602e,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x6030,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x6032,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x6034,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x6036,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x6038,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x603a,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x603c,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x603e,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x6040,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x6042,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x6044,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x6046,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x6048,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x604a,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x604c,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x604e,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x6050,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x6052,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x6054,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x6056,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x6058,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x605a,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x605c,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x605e,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x6060,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x6062,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x6064,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x6066,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x6068,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x606a,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x606c,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x606e,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x6070,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x6072,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x6074,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x6076,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x6078,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x607a,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x607c,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x607e,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x6080,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x6082,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x6084,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x6086,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x6088,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x608a,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x608c,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x608e,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x6090,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x6092,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x6094,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x6096,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x6098,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x609a,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x609c,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x609e,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x60a0,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x60a2,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x60a4,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x60a6,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x60a8,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x60aa,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x60ac,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x60ae,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x60b0,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x60b2,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x60b4,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x60b6,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x60b8,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x60ba,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x60bc,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x60be,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x60c0,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x60c2,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x60c4,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x60c6,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x60c8,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x60ca,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x60cc,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x60ce,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x60d0,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x60d2,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x60d4,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x60d6,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x60d8,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x60da,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x60dc,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x60de,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x60e0,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x60e2,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x60e4,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x60e6,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x60e8,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x60ea,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x60ec,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x60ee,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x60f0,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x60f2,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x60f4,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x60f6,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x60f8,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x60fa,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x60fc,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x60fe,0x0063,VR::CS,VM::VM1,"Overlay Compression Description","OverlayCompressionDescription",true }, + {0x6000,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x6002,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x6004,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x6006,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x6008,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x600a,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x600c,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x600e,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x6010,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x6012,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x6014,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x6016,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x6018,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x601a,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x601c,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x601e,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x6020,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x6022,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x6024,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x6026,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x6028,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x602a,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x602c,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x602e,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x6030,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x6032,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x6034,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x6036,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x6038,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x603a,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x603c,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x603e,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x6040,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x6042,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x6044,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x6046,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x6048,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x604a,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x604c,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x604e,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x6050,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x6052,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x6054,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x6056,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x6058,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x605a,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x605c,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x605e,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x6060,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x6062,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x6064,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x6066,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x6068,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x606a,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x606c,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x606e,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x6070,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x6072,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x6074,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x6076,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x6078,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x607a,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x607c,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x607e,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x6080,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x6082,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x6084,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x6086,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x6088,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x608a,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x608c,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x608e,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x6090,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x6092,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x6094,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x6096,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x6098,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x609a,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x609c,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x609e,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x60a0,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x60a2,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x60a4,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x60a6,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x60a8,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x60aa,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x60ac,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x60ae,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x60b0,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x60b2,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x60b4,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x60b6,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x60b8,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x60ba,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x60bc,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x60be,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x60c0,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x60c2,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x60c4,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x60c6,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x60c8,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x60ca,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x60cc,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x60ce,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x60d0,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x60d2,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x60d4,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x60d6,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x60d8,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x60da,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x60dc,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x60de,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x60e0,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x60e2,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x60e4,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x60e6,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x60e8,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x60ea,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x60ec,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x60ee,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x60f0,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x60f2,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x60f4,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x60f6,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x60f8,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x60fa,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x60fc,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x60fe,0x0066,VR::AT,VM::VM1_n,"Overlay Compression Step Pointers","OverlayCompressionStepPointers",true }, + {0x6000,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x6002,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x6004,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x6006,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x6008,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x600a,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x600c,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x600e,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x6010,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x6012,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x6014,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x6016,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x6018,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x601a,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x601c,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x601e,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x6020,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x6022,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x6024,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x6026,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x6028,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x602a,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x602c,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x602e,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x6030,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x6032,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x6034,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x6036,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x6038,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x603a,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x603c,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x603e,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x6040,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x6042,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x6044,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x6046,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x6048,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x604a,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x604c,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x604e,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x6050,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x6052,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x6054,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x6056,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x6058,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x605a,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x605c,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x605e,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x6060,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x6062,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x6064,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x6066,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x6068,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x606a,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x606c,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x606e,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x6070,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x6072,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x6074,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x6076,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x6078,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x607a,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x607c,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x607e,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x6080,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x6082,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x6084,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x6086,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x6088,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x608a,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x608c,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x608e,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x6090,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x6092,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x6094,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x6096,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x6098,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x609a,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x609c,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x609e,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x60a0,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x60a2,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x60a4,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x60a6,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x60a8,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x60aa,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x60ac,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x60ae,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x60b0,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x60b2,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x60b4,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x60b6,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x60b8,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x60ba,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x60bc,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x60be,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x60c0,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x60c2,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x60c4,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x60c6,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x60c8,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x60ca,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x60cc,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x60ce,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x60d0,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x60d2,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x60d4,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x60d6,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x60d8,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x60da,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x60dc,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x60de,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x60e0,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x60e2,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x60e4,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x60e6,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x60e8,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x60ea,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x60ec,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x60ee,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x60f0,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x60f2,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x60f4,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x60f6,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x60f8,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x60fa,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x60fc,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x60fe,0x0068,VR::US,VM::VM1,"Overlay Repeat Interval","OverlayRepeatInterval",true }, + {0x6000,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x6002,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x6004,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x6006,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x6008,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x600a,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x600c,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x600e,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x6010,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x6012,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x6014,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x6016,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x6018,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x601a,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x601c,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x601e,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x6020,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x6022,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x6024,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x6026,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x6028,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x602a,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x602c,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x602e,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x6030,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x6032,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x6034,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x6036,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x6038,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x603a,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x603c,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x603e,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x6040,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x6042,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x6044,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x6046,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x6048,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x604a,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x604c,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x604e,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x6050,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x6052,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x6054,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x6056,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x6058,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x605a,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x605c,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x605e,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x6060,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x6062,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x6064,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x6066,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x6068,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x606a,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x606c,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x606e,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x6070,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x6072,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x6074,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x6076,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x6078,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x607a,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x607c,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x607e,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x6080,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x6082,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x6084,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x6086,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x6088,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x608a,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x608c,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x608e,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x6090,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x6092,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x6094,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x6096,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x6098,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x609a,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x609c,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x609e,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x60a0,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x60a2,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x60a4,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x60a6,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x60a8,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x60aa,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x60ac,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x60ae,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x60b0,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x60b2,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x60b4,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x60b6,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x60b8,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x60ba,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x60bc,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x60be,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x60c0,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x60c2,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x60c4,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x60c6,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x60c8,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x60ca,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x60cc,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x60ce,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x60d0,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x60d2,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x60d4,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x60d6,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x60d8,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x60da,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x60dc,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x60de,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x60e0,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x60e2,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x60e4,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x60e6,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x60e8,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x60ea,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x60ec,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x60ee,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x60f0,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x60f2,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x60f4,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x60f6,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x60f8,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x60fa,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x60fc,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x60fe,0x0069,VR::US,VM::VM1,"Overlay Bits Grouped","OverlayBitsGrouped",true }, + {0x6000,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x6002,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x6004,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x6006,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x6008,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x600a,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x600c,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x600e,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x6010,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x6012,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x6014,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x6016,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x6018,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x601a,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x601c,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x601e,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x6020,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x6022,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x6024,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x6026,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x6028,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x602a,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x602c,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x602e,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x6030,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x6032,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x6034,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x6036,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x6038,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x603a,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x603c,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x603e,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x6040,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x6042,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x6044,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x6046,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x6048,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x604a,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x604c,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x604e,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x6050,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x6052,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x6054,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x6056,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x6058,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x605a,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x605c,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x605e,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x6060,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x6062,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x6064,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x6066,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x6068,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x606a,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x606c,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x606e,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x6070,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x6072,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x6074,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x6076,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x6078,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x607a,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x607c,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x607e,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x6080,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x6082,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x6084,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x6086,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x6088,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x608a,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x608c,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x608e,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x6090,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x6092,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x6094,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x6096,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x6098,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x609a,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x609c,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x609e,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x60a0,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x60a2,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x60a4,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x60a6,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x60a8,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x60aa,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x60ac,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x60ae,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x60b0,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x60b2,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x60b4,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x60b6,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x60b8,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x60ba,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x60bc,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x60be,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x60c0,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x60c2,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x60c4,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x60c6,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x60c8,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x60ca,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x60cc,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x60ce,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x60d0,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x60d2,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x60d4,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x60d6,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x60d8,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x60da,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x60dc,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x60de,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x60e0,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x60e2,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x60e4,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x60e6,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x60e8,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x60ea,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x60ec,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x60ee,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x60f0,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x60f2,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x60f4,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x60f6,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x60f8,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x60fa,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x60fc,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x60fe,0x0100,VR::US,VM::VM1,"Overlay Bits Allocated","OverlayBitsAllocated",false }, + {0x6000,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x6002,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x6004,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x6006,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x6008,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x600a,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x600c,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x600e,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x6010,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x6012,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x6014,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x6016,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x6018,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x601a,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x601c,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x601e,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x6020,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x6022,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x6024,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x6026,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x6028,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x602a,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x602c,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x602e,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x6030,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x6032,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x6034,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x6036,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x6038,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x603a,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x603c,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x603e,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x6040,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x6042,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x6044,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x6046,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x6048,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x604a,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x604c,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x604e,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x6050,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x6052,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x6054,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x6056,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x6058,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x605a,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x605c,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x605e,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x6060,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x6062,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x6064,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x6066,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x6068,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x606a,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x606c,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x606e,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x6070,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x6072,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x6074,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x6076,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x6078,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x607a,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x607c,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x607e,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x6080,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x6082,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x6084,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x6086,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x6088,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x608a,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x608c,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x608e,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x6090,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x6092,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x6094,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x6096,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x6098,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x609a,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x609c,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x609e,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x60a0,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x60a2,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x60a4,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x60a6,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x60a8,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x60aa,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x60ac,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x60ae,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x60b0,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x60b2,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x60b4,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x60b6,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x60b8,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x60ba,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x60bc,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x60be,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x60c0,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x60c2,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x60c4,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x60c6,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x60c8,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x60ca,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x60cc,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x60ce,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x60d0,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x60d2,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x60d4,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x60d6,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x60d8,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x60da,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x60dc,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x60de,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x60e0,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x60e2,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x60e4,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x60e6,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x60e8,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x60ea,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x60ec,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x60ee,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x60f0,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x60f2,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x60f4,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x60f6,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x60f8,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x60fa,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x60fc,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x60fe,0x0102,VR::US,VM::VM1,"Overlay Bit Position","OverlayBitPosition",false }, + {0x6000,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x6002,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x6004,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x6006,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x6008,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x600a,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x600c,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x600e,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x6010,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x6012,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x6014,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x6016,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x6018,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x601a,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x601c,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x601e,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x6020,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x6022,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x6024,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x6026,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x6028,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x602a,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x602c,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x602e,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x6030,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x6032,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x6034,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x6036,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x6038,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x603a,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x603c,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x603e,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x6040,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x6042,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x6044,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x6046,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x6048,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x604a,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x604c,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x604e,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x6050,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x6052,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x6054,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x6056,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x6058,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x605a,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x605c,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x605e,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x6060,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x6062,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x6064,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x6066,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x6068,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x606a,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x606c,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x606e,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x6070,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x6072,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x6074,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x6076,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x6078,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x607a,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x607c,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x607e,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x6080,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x6082,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x6084,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x6086,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x6088,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x608a,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x608c,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x608e,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x6090,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x6092,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x6094,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x6096,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x6098,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x609a,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x609c,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x609e,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x60a0,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x60a2,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x60a4,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x60a6,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x60a8,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x60aa,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x60ac,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x60ae,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x60b0,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x60b2,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x60b4,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x60b6,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x60b8,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x60ba,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x60bc,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x60be,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x60c0,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x60c2,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x60c4,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x60c6,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x60c8,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x60ca,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x60cc,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x60ce,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x60d0,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x60d2,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x60d4,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x60d6,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x60d8,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x60da,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x60dc,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x60de,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x60e0,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x60e2,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x60e4,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x60e6,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x60e8,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x60ea,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x60ec,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x60ee,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x60f0,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x60f2,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x60f4,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x60f6,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x60f8,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x60fa,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x60fc,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x60fe,0x0110,VR::CS,VM::VM1,"Overlay Format","OverlayFormat",true }, + {0x6000,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x6002,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x6004,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x6006,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x6008,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x600a,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x600c,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x600e,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x6010,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x6012,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x6014,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x6016,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x6018,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x601a,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x601c,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x601e,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x6020,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x6022,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x6024,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x6026,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x6028,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x602a,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x602c,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x602e,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x6030,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x6032,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x6034,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x6036,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x6038,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x603a,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x603c,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x603e,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x6040,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x6042,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x6044,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x6046,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x6048,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x604a,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x604c,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x604e,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x6050,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x6052,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x6054,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x6056,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x6058,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x605a,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x605c,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x605e,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x6060,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x6062,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x6064,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x6066,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x6068,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x606a,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x606c,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x606e,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x6070,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x6072,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x6074,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x6076,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x6078,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x607a,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x607c,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x607e,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x6080,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x6082,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x6084,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x6086,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x6088,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x608a,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x608c,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x608e,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x6090,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x6092,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x6094,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x6096,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x6098,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x609a,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x609c,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x609e,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x60a0,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x60a2,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x60a4,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x60a6,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x60a8,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x60aa,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x60ac,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x60ae,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x60b0,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x60b2,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x60b4,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x60b6,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x60b8,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x60ba,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x60bc,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x60be,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x60c0,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x60c2,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x60c4,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x60c6,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x60c8,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x60ca,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x60cc,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x60ce,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x60d0,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x60d2,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x60d4,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x60d6,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x60d8,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x60da,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x60dc,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x60de,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x60e0,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x60e2,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x60e4,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x60e6,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x60e8,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x60ea,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x60ec,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x60ee,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x60f0,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x60f2,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x60f4,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x60f6,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x60f8,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x60fa,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x60fc,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x60fe,0x0200,VR::US,VM::VM1,"Overlay Location","OverlayLocation",true }, + {0x6000,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x6002,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x6004,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x6006,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x6008,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x600a,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x600c,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x600e,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x6010,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x6012,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x6014,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x6016,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x6018,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x601a,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x601c,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x601e,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x6020,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x6022,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x6024,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x6026,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x6028,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x602a,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x602c,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x602e,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x6030,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x6032,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x6034,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x6036,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x6038,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x603a,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x603c,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x603e,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x6040,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x6042,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x6044,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x6046,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x6048,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x604a,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x604c,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x604e,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x6050,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x6052,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x6054,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x6056,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x6058,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x605a,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x605c,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x605e,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x6060,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x6062,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x6064,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x6066,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x6068,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x606a,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x606c,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x606e,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x6070,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x6072,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x6074,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x6076,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x6078,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x607a,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x607c,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x607e,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x6080,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x6082,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x6084,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x6086,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x6088,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x608a,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x608c,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x608e,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x6090,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x6092,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x6094,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x6096,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x6098,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x609a,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x609c,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x609e,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x60a0,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x60a2,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x60a4,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x60a6,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x60a8,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x60aa,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x60ac,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x60ae,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x60b0,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x60b2,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x60b4,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x60b6,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x60b8,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x60ba,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x60bc,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x60be,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x60c0,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x60c2,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x60c4,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x60c6,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x60c8,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x60ca,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x60cc,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x60ce,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x60d0,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x60d2,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x60d4,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x60d6,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x60d8,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x60da,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x60dc,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x60de,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x60e0,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x60e2,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x60e4,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x60e6,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x60e8,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x60ea,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x60ec,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x60ee,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x60f0,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x60f2,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x60f4,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x60f6,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x60f8,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x60fa,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x60fc,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x60fe,0x0800,VR::CS,VM::VM1_n,"Overlay Code Label","OverlayCodeLabel",true }, + {0x6000,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x6002,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x6004,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x6006,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x6008,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x600a,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x600c,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x600e,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x6010,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x6012,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x6014,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x6016,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x6018,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x601a,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x601c,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x601e,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x6020,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x6022,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x6024,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x6026,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x6028,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x602a,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x602c,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x602e,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x6030,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x6032,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x6034,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x6036,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x6038,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x603a,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x603c,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x603e,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x6040,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x6042,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x6044,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x6046,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x6048,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x604a,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x604c,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x604e,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x6050,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x6052,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x6054,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x6056,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x6058,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x605a,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x605c,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x605e,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x6060,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x6062,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x6064,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x6066,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x6068,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x606a,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x606c,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x606e,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x6070,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x6072,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x6074,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x6076,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x6078,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x607a,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x607c,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x607e,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x6080,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x6082,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x6084,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x6086,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x6088,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x608a,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x608c,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x608e,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x6090,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x6092,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x6094,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x6096,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x6098,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x609a,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x609c,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x609e,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x60a0,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x60a2,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x60a4,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x60a6,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x60a8,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x60aa,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x60ac,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x60ae,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x60b0,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x60b2,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x60b4,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x60b6,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x60b8,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x60ba,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x60bc,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x60be,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x60c0,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x60c2,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x60c4,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x60c6,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x60c8,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x60ca,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x60cc,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x60ce,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x60d0,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x60d2,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x60d4,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x60d6,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x60d8,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x60da,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x60dc,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x60de,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x60e0,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x60e2,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x60e4,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x60e6,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x60e8,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x60ea,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x60ec,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x60ee,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x60f0,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x60f2,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x60f4,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x60f6,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x60f8,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x60fa,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x60fc,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x60fe,0x0802,VR::US,VM::VM1,"Overlay Number of Tables","OverlayNumberOfTables",true }, + {0x6000,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x6002,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x6004,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x6006,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x6008,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x600a,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x600c,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x600e,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x6010,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x6012,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x6014,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x6016,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x6018,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x601a,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x601c,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x601e,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x6020,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x6022,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x6024,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x6026,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x6028,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x602a,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x602c,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x602e,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x6030,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x6032,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x6034,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x6036,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x6038,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x603a,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x603c,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x603e,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x6040,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x6042,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x6044,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x6046,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x6048,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x604a,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x604c,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x604e,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x6050,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x6052,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x6054,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x6056,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x6058,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x605a,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x605c,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x605e,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x6060,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x6062,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x6064,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x6066,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x6068,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x606a,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x606c,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x606e,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x6070,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x6072,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x6074,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x6076,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x6078,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x607a,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x607c,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x607e,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x6080,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x6082,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x6084,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x6086,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x6088,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x608a,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x608c,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x608e,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x6090,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x6092,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x6094,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x6096,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x6098,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x609a,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x609c,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x609e,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x60a0,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x60a2,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x60a4,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x60a6,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x60a8,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x60aa,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x60ac,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x60ae,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x60b0,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x60b2,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x60b4,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x60b6,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x60b8,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x60ba,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x60bc,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x60be,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x60c0,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x60c2,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x60c4,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x60c6,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x60c8,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x60ca,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x60cc,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x60ce,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x60d0,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x60d2,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x60d4,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x60d6,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x60d8,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x60da,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x60dc,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x60de,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x60e0,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x60e2,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x60e4,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x60e6,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x60e8,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x60ea,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x60ec,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x60ee,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x60f0,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x60f2,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x60f4,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x60f6,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x60f8,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x60fa,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x60fc,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x60fe,0x0803,VR::AT,VM::VM1_n,"Overlay Code Table Location","OverlayCodeTableLocation",true }, + {0x6000,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x6002,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x6004,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x6006,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x6008,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x600a,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x600c,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x600e,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x6010,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x6012,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x6014,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x6016,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x6018,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x601a,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x601c,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x601e,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x6020,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x6022,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x6024,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x6026,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x6028,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x602a,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x602c,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x602e,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x6030,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x6032,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x6034,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x6036,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x6038,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x603a,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x603c,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x603e,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x6040,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x6042,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x6044,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x6046,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x6048,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x604a,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x604c,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x604e,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x6050,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x6052,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x6054,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x6056,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x6058,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x605a,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x605c,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x605e,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x6060,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x6062,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x6064,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x6066,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x6068,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x606a,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x606c,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x606e,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x6070,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x6072,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x6074,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x6076,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x6078,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x607a,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x607c,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x607e,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x6080,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x6082,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x6084,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x6086,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x6088,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x608a,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x608c,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x608e,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x6090,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x6092,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x6094,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x6096,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x6098,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x609a,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x609c,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x609e,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x60a0,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x60a2,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x60a4,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x60a6,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x60a8,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x60aa,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x60ac,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x60ae,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x60b0,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x60b2,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x60b4,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x60b6,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x60b8,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x60ba,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x60bc,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x60be,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x60c0,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x60c2,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x60c4,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x60c6,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x60c8,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x60ca,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x60cc,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x60ce,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x60d0,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x60d2,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x60d4,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x60d6,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x60d8,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x60da,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x60dc,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x60de,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x60e0,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x60e2,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x60e4,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x60e6,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x60e8,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x60ea,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x60ec,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x60ee,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x60f0,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x60f2,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x60f4,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x60f6,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x60f8,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x60fa,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x60fc,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x60fe,0x0804,VR::US,VM::VM1,"Overlay Bits For Code Word","OverlayBitsForCodeWord",true }, + {0x6000,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x6002,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x6004,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x6006,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x6008,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x600a,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x600c,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x600e,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x6010,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x6012,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x6014,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x6016,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x6018,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x601a,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x601c,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x601e,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x6020,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x6022,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x6024,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x6026,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x6028,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x602a,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x602c,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x602e,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x6030,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x6032,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x6034,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x6036,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x6038,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x603a,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x603c,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x603e,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x6040,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x6042,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x6044,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x6046,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x6048,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x604a,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x604c,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x604e,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x6050,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x6052,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x6054,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x6056,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x6058,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x605a,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x605c,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x605e,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x6060,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x6062,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x6064,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x6066,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x6068,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x606a,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x606c,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x606e,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x6070,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x6072,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x6074,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x6076,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x6078,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x607a,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x607c,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x607e,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x6080,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x6082,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x6084,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x6086,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x6088,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x608a,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x608c,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x608e,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x6090,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x6092,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x6094,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x6096,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x6098,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x609a,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x609c,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x609e,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x60a0,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x60a2,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x60a4,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x60a6,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x60a8,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x60aa,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x60ac,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x60ae,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x60b0,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x60b2,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x60b4,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x60b6,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x60b8,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x60ba,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x60bc,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x60be,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x60c0,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x60c2,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x60c4,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x60c6,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x60c8,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x60ca,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x60cc,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x60ce,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x60d0,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x60d2,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x60d4,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x60d6,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x60d8,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x60da,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x60dc,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x60de,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x60e0,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x60e2,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x60e4,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x60e6,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x60e8,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x60ea,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x60ec,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x60ee,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x60f0,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x60f2,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x60f4,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x60f6,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x60f8,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x60fa,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x60fc,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x60fe,0x1001,VR::CS,VM::VM1,"Overlay Activation Layer","OverlayActivationLayer",false }, + {0x6000,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x6002,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x6004,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x6006,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x6008,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x600a,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x600c,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x600e,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x6010,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x6012,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x6014,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x6016,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x6018,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x601a,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x601c,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x601e,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x6020,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x6022,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x6024,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x6026,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x6028,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x602a,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x602c,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x602e,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x6030,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x6032,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x6034,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x6036,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x6038,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x603a,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x603c,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x603e,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x6040,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x6042,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x6044,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x6046,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x6048,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x604a,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x604c,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x604e,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x6050,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x6052,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x6054,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x6056,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x6058,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x605a,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x605c,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x605e,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x6060,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x6062,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x6064,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x6066,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x6068,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x606a,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x606c,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x606e,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x6070,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x6072,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x6074,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x6076,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x6078,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x607a,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x607c,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x607e,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x6080,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x6082,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x6084,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x6086,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x6088,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x608a,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x608c,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x608e,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x6090,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x6092,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x6094,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x6096,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x6098,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x609a,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x609c,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x609e,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x60a0,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x60a2,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x60a4,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x60a6,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x60a8,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x60aa,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x60ac,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x60ae,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x60b0,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x60b2,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x60b4,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x60b6,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x60b8,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x60ba,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x60bc,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x60be,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x60c0,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x60c2,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x60c4,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x60c6,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x60c8,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x60ca,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x60cc,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x60ce,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x60d0,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x60d2,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x60d4,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x60d6,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x60d8,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x60da,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x60dc,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x60de,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x60e0,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x60e2,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x60e4,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x60e6,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x60e8,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x60ea,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x60ec,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x60ee,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x60f0,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x60f2,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x60f4,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x60f6,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x60f8,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x60fa,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x60fc,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x60fe,0x1100,VR::US,VM::VM1,"Overlay Descriptor - Gray","OverlayDescriptorGray",true }, + {0x6000,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x6002,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x6004,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x6006,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x6008,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x600a,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x600c,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x600e,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x6010,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x6012,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x6014,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x6016,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x6018,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x601a,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x601c,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x601e,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x6020,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x6022,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x6024,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x6026,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x6028,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x602a,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x602c,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x602e,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x6030,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x6032,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x6034,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x6036,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x6038,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x603a,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x603c,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x603e,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x6040,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x6042,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x6044,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x6046,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x6048,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x604a,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x604c,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x604e,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x6050,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x6052,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x6054,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x6056,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x6058,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x605a,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x605c,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x605e,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x6060,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x6062,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x6064,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x6066,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x6068,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x606a,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x606c,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x606e,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x6070,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x6072,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x6074,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x6076,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x6078,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x607a,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x607c,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x607e,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x6080,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x6082,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x6084,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x6086,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x6088,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x608a,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x608c,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x608e,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x6090,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x6092,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x6094,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x6096,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x6098,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x609a,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x609c,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x609e,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x60a0,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x60a2,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x60a4,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x60a6,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x60a8,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x60aa,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x60ac,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x60ae,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x60b0,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x60b2,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x60b4,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x60b6,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x60b8,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x60ba,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x60bc,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x60be,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x60c0,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x60c2,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x60c4,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x60c6,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x60c8,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x60ca,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x60cc,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x60ce,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x60d0,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x60d2,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x60d4,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x60d6,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x60d8,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x60da,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x60dc,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x60de,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x60e0,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x60e2,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x60e4,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x60e6,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x60e8,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x60ea,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x60ec,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x60ee,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x60f0,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x60f2,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x60f4,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x60f6,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x60f8,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x60fa,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x60fc,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x60fe,0x1101,VR::US,VM::VM1,"Overlay Descriptor - Red","OverlayDescriptorRed",true }, + {0x6000,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x6002,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x6004,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x6006,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x6008,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x600a,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x600c,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x600e,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x6010,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x6012,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x6014,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x6016,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x6018,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x601a,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x601c,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x601e,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x6020,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x6022,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x6024,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x6026,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x6028,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x602a,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x602c,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x602e,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x6030,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x6032,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x6034,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x6036,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x6038,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x603a,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x603c,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x603e,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x6040,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x6042,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x6044,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x6046,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x6048,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x604a,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x604c,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x604e,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x6050,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x6052,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x6054,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x6056,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x6058,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x605a,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x605c,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x605e,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x6060,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x6062,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x6064,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x6066,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x6068,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x606a,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x606c,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x606e,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x6070,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x6072,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x6074,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x6076,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x6078,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x607a,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x607c,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x607e,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x6080,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x6082,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x6084,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x6086,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x6088,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x608a,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x608c,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x608e,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x6090,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x6092,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x6094,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x6096,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x6098,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x609a,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x609c,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x609e,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x60a0,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x60a2,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x60a4,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x60a6,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x60a8,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x60aa,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x60ac,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x60ae,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x60b0,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x60b2,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x60b4,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x60b6,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x60b8,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x60ba,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x60bc,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x60be,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x60c0,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x60c2,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x60c4,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x60c6,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x60c8,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x60ca,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x60cc,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x60ce,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x60d0,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x60d2,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x60d4,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x60d6,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x60d8,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x60da,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x60dc,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x60de,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x60e0,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x60e2,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x60e4,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x60e6,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x60e8,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x60ea,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x60ec,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x60ee,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x60f0,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x60f2,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x60f4,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x60f6,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x60f8,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x60fa,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x60fc,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x60fe,0x1102,VR::US,VM::VM1,"Overlay Descriptor - Green","OverlayDescriptorGreen",true }, + {0x6000,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x6002,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x6004,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x6006,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x6008,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x600a,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x600c,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x600e,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x6010,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x6012,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x6014,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x6016,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x6018,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x601a,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x601c,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x601e,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x6020,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x6022,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x6024,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x6026,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x6028,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x602a,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x602c,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x602e,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x6030,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x6032,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x6034,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x6036,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x6038,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x603a,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x603c,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x603e,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x6040,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x6042,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x6044,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x6046,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x6048,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x604a,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x604c,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x604e,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x6050,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x6052,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x6054,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x6056,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x6058,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x605a,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x605c,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x605e,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x6060,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x6062,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x6064,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x6066,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x6068,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x606a,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x606c,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x606e,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x6070,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x6072,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x6074,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x6076,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x6078,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x607a,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x607c,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x607e,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x6080,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x6082,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x6084,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x6086,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x6088,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x608a,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x608c,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x608e,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x6090,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x6092,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x6094,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x6096,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x6098,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x609a,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x609c,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x609e,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x60a0,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x60a2,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x60a4,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x60a6,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x60a8,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x60aa,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x60ac,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x60ae,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x60b0,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x60b2,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x60b4,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x60b6,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x60b8,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x60ba,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x60bc,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x60be,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x60c0,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x60c2,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x60c4,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x60c6,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x60c8,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x60ca,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x60cc,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x60ce,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x60d0,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x60d2,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x60d4,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x60d6,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x60d8,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x60da,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x60dc,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x60de,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x60e0,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x60e2,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x60e4,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x60e6,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x60e8,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x60ea,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x60ec,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x60ee,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x60f0,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x60f2,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x60f4,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x60f6,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x60f8,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x60fa,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x60fc,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x60fe,0x1103,VR::US,VM::VM1,"Overlay Descriptor - Blue","OverlayDescriptorBlue",true }, + {0x6000,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x6002,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x6004,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x6006,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x6008,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x600a,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x600c,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x600e,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x6010,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x6012,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x6014,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x6016,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x6018,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x601a,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x601c,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x601e,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x6020,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x6022,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x6024,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x6026,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x6028,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x602a,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x602c,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x602e,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x6030,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x6032,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x6034,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x6036,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x6038,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x603a,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x603c,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x603e,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x6040,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x6042,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x6044,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x6046,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x6048,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x604a,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x604c,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x604e,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x6050,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x6052,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x6054,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x6056,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x6058,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x605a,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x605c,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x605e,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x6060,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x6062,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x6064,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x6066,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x6068,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x606a,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x606c,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x606e,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x6070,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x6072,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x6074,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x6076,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x6078,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x607a,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x607c,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x607e,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x6080,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x6082,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x6084,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x6086,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x6088,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x608a,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x608c,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x608e,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x6090,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x6092,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x6094,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x6096,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x6098,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x609a,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x609c,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x609e,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x60a0,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x60a2,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x60a4,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x60a6,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x60a8,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x60aa,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x60ac,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x60ae,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x60b0,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x60b2,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x60b4,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x60b6,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x60b8,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x60ba,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x60bc,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x60be,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x60c0,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x60c2,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x60c4,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x60c6,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x60c8,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x60ca,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x60cc,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x60ce,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x60d0,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x60d2,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x60d4,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x60d6,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x60d8,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x60da,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x60dc,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x60de,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x60e0,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x60e2,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x60e4,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x60e6,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x60e8,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x60ea,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x60ec,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x60ee,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x60f0,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x60f2,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x60f4,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x60f6,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x60f8,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x60fa,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x60fc,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x60fe,0x1200,VR::US,VM::VM1_n,"Overlays - Gray","OverlaysGray",true }, + {0x6000,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x6002,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x6004,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x6006,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x6008,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x600a,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x600c,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x600e,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x6010,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x6012,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x6014,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x6016,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x6018,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x601a,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x601c,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x601e,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x6020,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x6022,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x6024,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x6026,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x6028,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x602a,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x602c,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x602e,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x6030,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x6032,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x6034,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x6036,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x6038,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x603a,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x603c,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x603e,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x6040,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x6042,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x6044,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x6046,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x6048,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x604a,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x604c,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x604e,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x6050,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x6052,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x6054,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x6056,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x6058,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x605a,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x605c,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x605e,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x6060,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x6062,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x6064,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x6066,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x6068,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x606a,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x606c,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x606e,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x6070,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x6072,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x6074,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x6076,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x6078,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x607a,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x607c,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x607e,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x6080,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x6082,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x6084,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x6086,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x6088,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x608a,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x608c,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x608e,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x6090,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x6092,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x6094,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x6096,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x6098,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x609a,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x609c,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x609e,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x60a0,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x60a2,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x60a4,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x60a6,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x60a8,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x60aa,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x60ac,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x60ae,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x60b0,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x60b2,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x60b4,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x60b6,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x60b8,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x60ba,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x60bc,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x60be,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x60c0,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x60c2,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x60c4,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x60c6,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x60c8,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x60ca,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x60cc,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x60ce,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x60d0,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x60d2,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x60d4,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x60d6,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x60d8,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x60da,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x60dc,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x60de,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x60e0,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x60e2,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x60e4,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x60e6,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x60e8,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x60ea,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x60ec,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x60ee,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x60f0,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x60f2,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x60f4,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x60f6,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x60f8,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x60fa,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x60fc,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x60fe,0x1201,VR::US,VM::VM1_n,"Overlays - Red","OverlaysRed",true }, + {0x6000,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x6002,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x6004,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x6006,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x6008,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x600a,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x600c,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x600e,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x6010,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x6012,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x6014,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x6016,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x6018,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x601a,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x601c,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x601e,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x6020,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x6022,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x6024,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x6026,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x6028,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x602a,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x602c,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x602e,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x6030,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x6032,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x6034,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x6036,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x6038,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x603a,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x603c,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x603e,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x6040,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x6042,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x6044,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x6046,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x6048,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x604a,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x604c,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x604e,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x6050,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x6052,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x6054,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x6056,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x6058,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x605a,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x605c,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x605e,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x6060,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x6062,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x6064,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x6066,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x6068,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x606a,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x606c,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x606e,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x6070,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x6072,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x6074,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x6076,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x6078,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x607a,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x607c,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x607e,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x6080,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x6082,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x6084,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x6086,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x6088,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x608a,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x608c,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x608e,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x6090,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x6092,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x6094,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x6096,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x6098,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x609a,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x609c,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x609e,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x60a0,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x60a2,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x60a4,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x60a6,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x60a8,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x60aa,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x60ac,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x60ae,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x60b0,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x60b2,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x60b4,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x60b6,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x60b8,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x60ba,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x60bc,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x60be,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x60c0,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x60c2,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x60c4,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x60c6,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x60c8,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x60ca,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x60cc,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x60ce,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x60d0,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x60d2,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x60d4,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x60d6,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x60d8,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x60da,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x60dc,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x60de,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x60e0,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x60e2,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x60e4,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x60e6,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x60e8,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x60ea,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x60ec,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x60ee,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x60f0,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x60f2,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x60f4,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x60f6,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x60f8,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x60fa,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x60fc,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x60fe,0x1202,VR::US,VM::VM1_n,"Overlays - Green","OverlaysGreen",true }, + {0x6000,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x6002,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x6004,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x6006,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x6008,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x600a,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x600c,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x600e,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x6010,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x6012,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x6014,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x6016,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x6018,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x601a,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x601c,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x601e,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x6020,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x6022,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x6024,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x6026,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x6028,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x602a,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x602c,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x602e,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x6030,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x6032,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x6034,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x6036,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x6038,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x603a,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x603c,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x603e,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x6040,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x6042,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x6044,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x6046,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x6048,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x604a,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x604c,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x604e,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x6050,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x6052,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x6054,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x6056,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x6058,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x605a,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x605c,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x605e,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x6060,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x6062,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x6064,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x6066,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x6068,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x606a,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x606c,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x606e,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x6070,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x6072,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x6074,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x6076,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x6078,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x607a,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x607c,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x607e,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x6080,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x6082,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x6084,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x6086,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x6088,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x608a,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x608c,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x608e,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x6090,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x6092,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x6094,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x6096,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x6098,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x609a,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x609c,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x609e,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x60a0,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x60a2,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x60a4,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x60a6,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x60a8,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x60aa,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x60ac,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x60ae,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x60b0,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x60b2,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x60b4,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x60b6,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x60b8,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x60ba,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x60bc,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x60be,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x60c0,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x60c2,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x60c4,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x60c6,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x60c8,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x60ca,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x60cc,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x60ce,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x60d0,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x60d2,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x60d4,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x60d6,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x60d8,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x60da,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x60dc,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x60de,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x60e0,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x60e2,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x60e4,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x60e6,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x60e8,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x60ea,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x60ec,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x60ee,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x60f0,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x60f2,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x60f4,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x60f6,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x60f8,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x60fa,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x60fc,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x60fe,0x1203,VR::US,VM::VM1_n,"Overlays - Blue","OverlaysBlue",true }, + {0x6000,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x6002,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x6004,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x6006,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x6008,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x600a,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x600c,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x600e,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x6010,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x6012,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x6014,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x6016,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x6018,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x601a,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x601c,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x601e,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x6020,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x6022,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x6024,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x6026,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x6028,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x602a,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x602c,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x602e,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x6030,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x6032,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x6034,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x6036,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x6038,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x603a,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x603c,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x603e,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x6040,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x6042,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x6044,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x6046,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x6048,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x604a,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x604c,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x604e,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x6050,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x6052,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x6054,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x6056,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x6058,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x605a,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x605c,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x605e,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x6060,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x6062,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x6064,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x6066,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x6068,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x606a,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x606c,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x606e,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x6070,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x6072,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x6074,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x6076,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x6078,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x607a,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x607c,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x607e,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x6080,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x6082,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x6084,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x6086,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x6088,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x608a,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x608c,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x608e,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x6090,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x6092,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x6094,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x6096,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x6098,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x609a,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x609c,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x609e,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x60a0,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x60a2,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x60a4,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x60a6,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x60a8,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x60aa,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x60ac,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x60ae,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x60b0,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x60b2,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x60b4,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x60b6,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x60b8,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x60ba,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x60bc,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x60be,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x60c0,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x60c2,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x60c4,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x60c6,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x60c8,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x60ca,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x60cc,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x60ce,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x60d0,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x60d2,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x60d4,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x60d6,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x60d8,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x60da,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x60dc,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x60de,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x60e0,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x60e2,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x60e4,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x60e6,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x60e8,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x60ea,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x60ec,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x60ee,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x60f0,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x60f2,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x60f4,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x60f6,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x60f8,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x60fa,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x60fc,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x60fe,0x1301,VR::IS,VM::VM1,"ROI Area","ROIArea",false }, + {0x6000,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x6002,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x6004,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x6006,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x6008,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x600a,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x600c,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x600e,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x6010,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x6012,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x6014,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x6016,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x6018,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x601a,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x601c,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x601e,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x6020,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x6022,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x6024,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x6026,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x6028,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x602a,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x602c,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x602e,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x6030,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x6032,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x6034,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x6036,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x6038,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x603a,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x603c,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x603e,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x6040,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x6042,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x6044,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x6046,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x6048,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x604a,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x604c,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x604e,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x6050,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x6052,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x6054,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x6056,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x6058,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x605a,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x605c,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x605e,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x6060,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x6062,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x6064,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x6066,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x6068,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x606a,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x606c,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x606e,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x6070,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x6072,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x6074,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x6076,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x6078,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x607a,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x607c,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x607e,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x6080,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x6082,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x6084,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x6086,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x6088,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x608a,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x608c,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x608e,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x6090,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x6092,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x6094,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x6096,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x6098,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x609a,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x609c,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x609e,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x60a0,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x60a2,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x60a4,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x60a6,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x60a8,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x60aa,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x60ac,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x60ae,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x60b0,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x60b2,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x60b4,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x60b6,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x60b8,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x60ba,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x60bc,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x60be,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x60c0,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x60c2,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x60c4,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x60c6,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x60c8,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x60ca,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x60cc,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x60ce,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x60d0,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x60d2,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x60d4,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x60d6,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x60d8,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x60da,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x60dc,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x60de,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x60e0,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x60e2,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x60e4,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x60e6,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x60e8,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x60ea,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x60ec,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x60ee,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x60f0,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x60f2,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x60f4,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x60f6,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x60f8,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x60fa,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x60fc,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x60fe,0x1302,VR::DS,VM::VM1,"ROI Mean","ROIMean",false }, + {0x6000,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x6002,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x6004,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x6006,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x6008,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x600a,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x600c,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x600e,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x6010,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x6012,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x6014,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x6016,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x6018,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x601a,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x601c,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x601e,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x6020,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x6022,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x6024,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x6026,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x6028,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x602a,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x602c,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x602e,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x6030,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x6032,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x6034,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x6036,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x6038,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x603a,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x603c,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x603e,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x6040,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x6042,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x6044,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x6046,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x6048,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x604a,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x604c,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x604e,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x6050,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x6052,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x6054,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x6056,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x6058,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x605a,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x605c,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x605e,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x6060,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x6062,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x6064,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x6066,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x6068,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x606a,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x606c,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x606e,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x6070,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x6072,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x6074,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x6076,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x6078,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x607a,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x607c,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x607e,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x6080,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x6082,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x6084,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x6086,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x6088,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x608a,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x608c,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x608e,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x6090,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x6092,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x6094,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x6096,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x6098,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x609a,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x609c,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x609e,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x60a0,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x60a2,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x60a4,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x60a6,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x60a8,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x60aa,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x60ac,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x60ae,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x60b0,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x60b2,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x60b4,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x60b6,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x60b8,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x60ba,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x60bc,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x60be,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x60c0,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x60c2,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x60c4,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x60c6,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x60c8,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x60ca,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x60cc,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x60ce,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x60d0,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x60d2,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x60d4,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x60d6,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x60d8,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x60da,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x60dc,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x60de,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x60e0,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x60e2,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x60e4,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x60e6,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x60e8,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x60ea,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x60ec,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x60ee,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x60f0,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x60f2,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x60f4,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x60f6,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x60f8,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x60fa,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x60fc,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x60fe,0x1303,VR::DS,VM::VM1,"ROI Standard Deviation","ROIStandardDeviation",false }, + {0x6000,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x6002,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x6004,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x6006,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x6008,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x600a,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x600c,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x600e,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x6010,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x6012,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x6014,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x6016,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x6018,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x601a,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x601c,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x601e,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x6020,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x6022,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x6024,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x6026,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x6028,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x602a,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x602c,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x602e,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x6030,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x6032,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x6034,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x6036,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x6038,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x603a,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x603c,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x603e,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x6040,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x6042,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x6044,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x6046,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x6048,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x604a,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x604c,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x604e,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x6050,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x6052,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x6054,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x6056,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x6058,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x605a,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x605c,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x605e,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x6060,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x6062,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x6064,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x6066,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x6068,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x606a,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x606c,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x606e,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x6070,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x6072,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x6074,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x6076,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x6078,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x607a,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x607c,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x607e,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x6080,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x6082,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x6084,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x6086,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x6088,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x608a,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x608c,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x608e,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x6090,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x6092,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x6094,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x6096,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x6098,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x609a,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x609c,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x609e,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x60a0,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x60a2,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x60a4,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x60a6,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x60a8,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x60aa,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x60ac,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x60ae,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x60b0,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x60b2,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x60b4,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x60b6,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x60b8,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x60ba,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x60bc,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x60be,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x60c0,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x60c2,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x60c4,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x60c6,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x60c8,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x60ca,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x60cc,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x60ce,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x60d0,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x60d2,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x60d4,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x60d6,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x60d8,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x60da,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x60dc,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x60de,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x60e0,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x60e2,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x60e4,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x60e6,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x60e8,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x60ea,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x60ec,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x60ee,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x60f0,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x60f2,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x60f4,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x60f6,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x60f8,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x60fa,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x60fc,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x60fe,0x1500,VR::LO,VM::VM1,"Overlay Label","OverlayLabel",false }, + {0x6000,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x6002,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x6004,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x6006,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x6008,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x600a,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x600c,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x600e,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x6010,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x6012,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x6014,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x6016,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x6018,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x601a,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x601c,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x601e,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x6020,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x6022,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x6024,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x6026,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x6028,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x602a,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x602c,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x602e,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x6030,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x6032,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x6034,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x6036,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x6038,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x603a,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x603c,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x603e,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x6040,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x6042,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x6044,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x6046,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x6048,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x604a,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x604c,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x604e,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x6050,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x6052,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x6054,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x6056,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x6058,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x605a,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x605c,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x605e,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x6060,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x6062,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x6064,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x6066,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x6068,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x606a,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x606c,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x606e,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x6070,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x6072,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x6074,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x6076,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x6078,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x607a,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x607c,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x607e,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x6080,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x6082,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x6084,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x6086,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x6088,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x608a,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x608c,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x608e,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x6090,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x6092,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x6094,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x6096,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x6098,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x609a,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x609c,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x609e,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x60a0,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x60a2,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x60a4,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x60a6,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x60a8,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x60aa,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x60ac,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x60ae,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x60b0,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x60b2,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x60b4,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x60b6,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x60b8,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x60ba,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x60bc,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x60be,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x60c0,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x60c2,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x60c4,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x60c6,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x60c8,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x60ca,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x60cc,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x60ce,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x60d0,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x60d2,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x60d4,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x60d6,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x60d8,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x60da,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x60dc,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x60de,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x60e0,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x60e2,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x60e4,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x60e6,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x60e8,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x60ea,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x60ec,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x60ee,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x60f0,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x60f2,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x60f4,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x60f6,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x60f8,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x60fa,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x60fc,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x60fe,0x3000,VR::OB_OW,VM::VM1,"Overlay Data","OverlayData",false }, + {0x6000,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x6002,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x6004,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x6006,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x6008,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x600a,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x600c,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x600e,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x6010,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x6012,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x6014,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x6016,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x6018,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x601a,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x601c,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x601e,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x6020,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x6022,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x6024,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x6026,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x6028,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x602a,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x602c,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x602e,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x6030,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x6032,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x6034,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x6036,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x6038,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x603a,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x603c,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x603e,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x6040,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x6042,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x6044,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x6046,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x6048,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x604a,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x604c,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x604e,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x6050,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x6052,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x6054,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x6056,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x6058,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x605a,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x605c,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x605e,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x6060,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x6062,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x6064,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x6066,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x6068,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x606a,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x606c,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x606e,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x6070,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x6072,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x6074,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x6076,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x6078,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x607a,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x607c,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x607e,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x6080,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x6082,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x6084,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x6086,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x6088,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x608a,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x608c,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x608e,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x6090,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x6092,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x6094,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x6096,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x6098,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x609a,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x609c,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x609e,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x60a0,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x60a2,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x60a4,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x60a6,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x60a8,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x60aa,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x60ac,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x60ae,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x60b0,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x60b2,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x60b4,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x60b6,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x60b8,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x60ba,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x60bc,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x60be,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x60c0,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x60c2,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x60c4,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x60c6,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x60c8,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x60ca,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x60cc,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x60ce,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x60d0,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x60d2,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x60d4,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x60d6,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x60d8,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x60da,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x60dc,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x60de,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x60e0,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x60e2,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x60e4,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x60e6,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x60e8,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x60ea,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x60ec,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x60ee,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x60f0,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x60f2,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x60f4,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x60f6,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x60f8,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x60fa,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x60fc,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x60fe,0x4000,VR::LT,VM::VM1,"Overlay Comments","OverlayComments",true }, + {0x7fe0,0x0010,VR::OB_OW,VM::VM1,"Pixel Data","PixelData",false }, + {0x7fe0,0x0020,VR::OW,VM::VM1,"Coefficients SDVN","CoefficientsSDVN",true }, + {0x7fe0,0x0030,VR::OW,VM::VM1,"Coefficients SDHN","CoefficientsSDHN",true }, + {0x7fe0,0x0040,VR::OW,VM::VM1,"Coefficients SDDN","CoefficientsSDDN",true }, + {0x7f00,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f02,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f04,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f06,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f08,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f0a,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f0c,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f0e,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f10,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f12,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f14,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f16,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f18,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f1a,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f1c,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f1e,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f20,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f22,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f24,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f26,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f28,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f2a,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f2c,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f2e,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f30,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f32,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f34,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f36,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f38,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f3a,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f3c,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f3e,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f40,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f42,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f44,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f46,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f48,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f4a,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f4c,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f4e,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f50,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f52,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f54,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f56,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f58,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f5a,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f5c,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f5e,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f60,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f62,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f64,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f66,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f68,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f6a,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f6c,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f6e,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f70,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f72,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f74,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f76,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f78,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f7a,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f7c,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f7e,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f80,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f82,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f84,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f86,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f88,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f8a,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f8c,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f8e,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f90,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f92,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f94,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f96,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f98,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f9a,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f9c,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f9e,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7fa0,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7fa2,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7fa4,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7fa6,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7fa8,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7faa,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7fac,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7fae,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7fb0,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7fb2,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7fb4,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7fb6,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7fb8,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7fba,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7fbc,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7fbe,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7fc0,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7fc2,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7fc4,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7fc6,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7fc8,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7fca,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7fcc,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7fce,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7fd0,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7fd2,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7fd4,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7fd6,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7fd8,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7fda,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7fdc,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7fde,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, +// {0x7fe0,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7fe2,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7fe4,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7fe6,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7fe8,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7fea,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7fec,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7fee,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7ff0,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7ff2,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7ff4,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7ff6,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7ff8,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7ffa,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7ffc,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7ffe,0x0010,VR::OB_OW,VM::VM1,"Variable Pixel Data","VariablePixelData",true }, + {0x7f00,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f02,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f04,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f06,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f08,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f0a,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f0c,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f0e,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f10,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f12,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f14,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f16,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f18,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f1a,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f1c,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f1e,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f20,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f22,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f24,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f26,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f28,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f2a,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f2c,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f2e,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f30,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f32,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f34,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f36,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f38,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f3a,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f3c,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f3e,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f40,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f42,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f44,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f46,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f48,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f4a,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f4c,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f4e,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f50,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f52,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f54,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f56,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f58,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f5a,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f5c,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f5e,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f60,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f62,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f64,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f66,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f68,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f6a,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f6c,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f6e,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f70,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f72,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f74,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f76,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f78,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f7a,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f7c,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f7e,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f80,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f82,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f84,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f86,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f88,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f8a,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f8c,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f8e,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f90,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f92,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f94,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f96,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f98,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f9a,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f9c,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f9e,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7fa0,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7fa2,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7fa4,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7fa6,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7fa8,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7faa,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7fac,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7fae,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7fb0,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7fb2,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7fb4,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7fb6,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7fb8,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7fba,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7fbc,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7fbe,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7fc0,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7fc2,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7fc4,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7fc6,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7fc8,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7fca,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7fcc,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7fce,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7fd0,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7fd2,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7fd4,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7fd6,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7fd8,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7fda,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7fdc,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7fde,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7fe0,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7fe2,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7fe4,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7fe6,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7fe8,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7fea,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7fec,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7fee,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7ff0,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7ff2,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7ff4,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7ff6,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7ff8,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7ffa,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7ffc,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7ffe,0x0011,VR::US,VM::VM1,"Variable Next Data Group","VariableNextDataGroup",true }, + {0x7f00,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f02,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f04,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f06,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f08,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f0a,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f0c,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f0e,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f10,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f12,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f14,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f16,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f18,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f1a,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f1c,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f1e,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f20,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f22,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f24,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f26,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f28,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f2a,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f2c,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f2e,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f30,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f32,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f34,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f36,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f38,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f3a,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f3c,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f3e,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f40,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f42,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f44,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f46,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f48,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f4a,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f4c,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f4e,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f50,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f52,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f54,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f56,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f58,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f5a,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f5c,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f5e,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f60,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f62,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f64,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f66,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f68,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f6a,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f6c,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f6e,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f70,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f72,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f74,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f76,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f78,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f7a,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f7c,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f7e,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f80,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f82,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f84,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f86,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f88,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f8a,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f8c,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f8e,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f90,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f92,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f94,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f96,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f98,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f9a,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f9c,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f9e,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7fa0,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7fa2,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7fa4,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7fa6,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7fa8,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7faa,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7fac,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7fae,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7fb0,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7fb2,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7fb4,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7fb6,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7fb8,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7fba,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7fbc,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7fbe,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7fc0,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7fc2,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7fc4,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7fc6,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7fc8,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7fca,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7fcc,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7fce,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7fd0,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7fd2,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7fd4,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7fd6,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7fd8,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7fda,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7fdc,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7fde,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, +// {0x7fe0,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7fe2,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7fe4,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7fe6,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7fe8,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7fea,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7fec,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7fee,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7ff0,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7ff2,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7ff4,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7ff6,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7ff8,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7ffa,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7ffc,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7ffe,0x0020,VR::OW,VM::VM1,"Variable Coefficients SDVN","VariableCoefficientsSDVN",true }, + {0x7f00,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f02,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f04,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f06,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f08,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f0a,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f0c,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f0e,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f10,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f12,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f14,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f16,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f18,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f1a,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f1c,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f1e,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f20,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f22,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f24,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f26,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f28,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f2a,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f2c,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f2e,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f30,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f32,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f34,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f36,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f38,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f3a,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f3c,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f3e,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f40,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f42,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f44,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f46,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f48,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f4a,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f4c,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f4e,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f50,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f52,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f54,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f56,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f58,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f5a,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f5c,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f5e,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f60,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f62,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f64,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f66,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f68,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f6a,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f6c,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f6e,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f70,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f72,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f74,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f76,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f78,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f7a,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f7c,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f7e,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f80,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f82,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f84,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f86,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f88,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f8a,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f8c,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f8e,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f90,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f92,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f94,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f96,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f98,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f9a,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f9c,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f9e,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7fa0,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7fa2,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7fa4,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7fa6,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7fa8,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7faa,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7fac,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7fae,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7fb0,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7fb2,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7fb4,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7fb6,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7fb8,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7fba,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7fbc,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7fbe,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7fc0,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7fc2,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7fc4,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7fc6,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7fc8,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7fca,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7fcc,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7fce,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7fd0,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7fd2,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7fd4,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7fd6,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7fd8,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7fda,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7fdc,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7fde,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, +// {0x7fe0,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7fe2,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7fe4,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7fe6,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7fe8,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7fea,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7fec,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7fee,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7ff0,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7ff2,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7ff4,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7ff6,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7ff8,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7ffa,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7ffc,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7ffe,0x0030,VR::OW,VM::VM1,"Variable Coefficients SDHN","VariableCoefficientsSDHN",true }, + {0x7f00,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f02,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f04,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f06,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f08,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f0a,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f0c,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f0e,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f10,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f12,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f14,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f16,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f18,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f1a,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f1c,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f1e,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f20,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f22,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f24,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f26,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f28,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f2a,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f2c,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f2e,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f30,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f32,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f34,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f36,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f38,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f3a,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f3c,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f3e,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f40,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f42,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f44,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f46,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f48,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f4a,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f4c,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f4e,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f50,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f52,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f54,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f56,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f58,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f5a,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f5c,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f5e,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f60,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f62,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f64,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f66,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f68,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f6a,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f6c,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f6e,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f70,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f72,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f74,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f76,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f78,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f7a,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f7c,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f7e,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f80,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f82,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f84,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f86,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f88,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f8a,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f8c,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f8e,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f90,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f92,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f94,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f96,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f98,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f9a,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f9c,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7f9e,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7fa0,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7fa2,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7fa4,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7fa6,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7fa8,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7faa,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7fac,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7fae,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7fb0,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7fb2,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7fb4,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7fb6,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7fb8,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7fba,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7fbc,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7fbe,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7fc0,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7fc2,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7fc4,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7fc6,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7fc8,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7fca,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7fcc,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7fce,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7fd0,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7fd2,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7fd4,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7fd6,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7fd8,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7fda,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7fdc,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7fde,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, +// {0x7fe0,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7fe2,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7fe4,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7fe6,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7fe8,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7fea,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7fec,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7fee,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7ff0,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7ff2,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7ff4,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7ff6,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7ff8,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7ffa,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7ffc,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0x7ffe,0x0040,VR::OW,VM::VM1,"Variable Coefficients SDDN","VariableCoefficientsSDDN",true }, + {0xfffa,0xfffa,VR::SQ,VM::VM1,"Digital Signatures Sequence","DigitalSignaturesSequence",false }, + {0xfffc,0xfffc,VR::OB,VM::VM1,"Data Set Trailing Padding","DataSetTrailingPadding",false }, + {0xfffe,0xe000,VR::INVALID,VM::VM1,"Item","Item",false }, + {0xfffe,0xe00d,VR::INVALID,VM::VM1,"Item Delimitation Item","ItemDelimitationItem",false }, + {0xfffe,0xe0dd,VR::INVALID,VM::VM1,"Sequence Delimitation Item","SequenceDelimitationItem",false }, +// {0x0004,0x0000,VR::UL,VM::VM1,"Group Length 0004","",true }, +// {0x0008,0x0000,VR::UL,VM::VM1,"Group Length 0008","",true }, +// {0x0010,0x0000,VR::UL,VM::VM1,"Group Length 0010","",true }, +// {0x0012,0x0000,VR::UL,VM::VM1,"Group Length 0012","",true }, +// {0x0014,0x0000,VR::UL,VM::VM1,"Group Length 0014","",true }, +// {0x0018,0x0000,VR::UL,VM::VM1,"Group Length 0018","",true }, +// {0x0020,0x0000,VR::UL,VM::VM1,"Group Length 0020","",true }, +// {0x0022,0x0000,VR::UL,VM::VM1,"Group Length 0022","",true }, +// {0x0024,0x0000,VR::UL,VM::VM1,"Group Length 0024","",true }, +// {0x0028,0x0000,VR::UL,VM::VM1,"Group Length 0028","",true }, +// {0x0032,0x0000,VR::UL,VM::VM1,"Group Length 0032","",true }, +// {0x0038,0x0000,VR::UL,VM::VM1,"Group Length 0038","",true }, +// {0x003a,0x0000,VR::UL,VM::VM1,"Group Length 003a","",true }, +// {0x0040,0x0000,VR::UL,VM::VM1,"Group Length 0040","",true }, +// {0x0042,0x0000,VR::UL,VM::VM1,"Group Length 0042","",true }, +// {0x0044,0x0000,VR::UL,VM::VM1,"Group Length 0044","",true }, +// {0x0046,0x0000,VR::UL,VM::VM1,"Group Length 0046","",true }, +// {0x0048,0x0000,VR::UL,VM::VM1,"Group Length 0048","",true }, +// {0x0050,0x0000,VR::UL,VM::VM1,"Group Length 0050","",true }, +// {0x0052,0x0000,VR::UL,VM::VM1,"Group Length 0052","",true }, +// {0x0054,0x0000,VR::UL,VM::VM1,"Group Length 0054","",true }, +// {0x0060,0x0000,VR::UL,VM::VM1,"Group Length 0060","",true }, +// {0x0062,0x0000,VR::UL,VM::VM1,"Group Length 0062","",true }, +// {0x0064,0x0000,VR::UL,VM::VM1,"Group Length 0064","",true }, +// {0x0066,0x0000,VR::UL,VM::VM1,"Group Length 0066","",true }, +// {0x0068,0x0000,VR::UL,VM::VM1,"Group Length 0068","",true }, +// {0x0070,0x0000,VR::UL,VM::VM1,"Group Length 0070","",true }, +// {0x0072,0x0000,VR::UL,VM::VM1,"Group Length 0072","",true }, +// {0x0074,0x0000,VR::UL,VM::VM1,"Group Length 0074","",true }, +// {0x0076,0x0000,VR::UL,VM::VM1,"Group Length 0076","",true }, +// {0x0078,0x0000,VR::UL,VM::VM1,"Group Length 0078","",true }, +// {0x0088,0x0000,VR::UL,VM::VM1,"Group Length 0088","",true }, +// {0x0100,0x0000,VR::UL,VM::VM1,"Group Length 0100","",true }, +// {0x0400,0x0000,VR::UL,VM::VM1,"Group Length 0400","",true }, +// {0x1000,0x0000,VR::UL,VM::VM1,"Group Length 1000","",true }, +// {0x1010,0x0000,VR::UL,VM::VM1,"Group Length 1010","",true }, +// {0x2000,0x0000,VR::UL,VM::VM1,"Group Length 2000","",true }, +// {0x2010,0x0000,VR::UL,VM::VM1,"Group Length 2010","",true }, +// {0x2020,0x0000,VR::UL,VM::VM1,"Group Length 2020","",true }, +// {0x2030,0x0000,VR::UL,VM::VM1,"Group Length 2030","",true }, +// {0x2040,0x0000,VR::UL,VM::VM1,"Group Length 2040","",true }, +// {0x2050,0x0000,VR::UL,VM::VM1,"Group Length 2050","",true }, +// {0x2100,0x0000,VR::UL,VM::VM1,"Group Length 2100","",true }, +// {0x2110,0x0000,VR::UL,VM::VM1,"Group Length 2110","",true }, +// {0x2120,0x0000,VR::UL,VM::VM1,"Group Length 2120","",true }, +// {0x2130,0x0000,VR::UL,VM::VM1,"Group Length 2130","",true }, +// {0x2200,0x0000,VR::UL,VM::VM1,"Group Length 2200","",true }, +// {0x3002,0x0000,VR::UL,VM::VM1,"Group Length 3002","",true }, +// {0x3004,0x0000,VR::UL,VM::VM1,"Group Length 3004","",true }, +// {0x3006,0x0000,VR::UL,VM::VM1,"Group Length 3006","",true }, +// {0x3008,0x0000,VR::UL,VM::VM1,"Group Length 3008","",true }, +// {0x300a,0x0000,VR::UL,VM::VM1,"Group Length 300a","",true }, +// {0x300c,0x0000,VR::UL,VM::VM1,"Group Length 300c","",true }, +// {0x300e,0x0000,VR::UL,VM::VM1,"Group Length 300e","",true }, +// {0x4000,0x0000,VR::UL,VM::VM1,"Group Length 4000","",true }, +// {0x4008,0x0000,VR::UL,VM::VM1,"Group Length 4008","",true }, +// {0x4010,0x0000,VR::UL,VM::VM1,"Group Length 4010","",true }, +// {0x4ffe,0x0000,VR::UL,VM::VM1,"Group Length 4ffe","",true }, +// {0x5200,0x0000,VR::UL,VM::VM1,"Group Length 5200","",true }, +// {0x5400,0x0000,VR::UL,VM::VM1,"Group Length 5400","",true }, +// {0x5600,0x0000,VR::UL,VM::VM1,"Group Length 5600","",true }, +// {0x7fe0,0x0000,VR::UL,VM::VM1,"Group Length 7fe0","",true }, +// {0xfffa,0x0000,VR::UL,VM::VM1,"Group Length fffa","",true }, +// {0xfffc,0x0000,VR::UL,VM::VM1,"Group Length fffc","",true }, +// {0xfffe,0x0000,VR::UL,VM::VM1,"Group Length fffe","",true }, + + // FIXME: need a dummy element + {0xffff,0xffff,VR::INVALID,VM::VM0,"","",true }, // dummy + {0xffff,0xffff,VR::INVALID,VM::VM0,0,0,true } // Gard +}; + +void Dict::LoadDefault() +{ + unsigned int i = 0; + DICT_ENTRY n = DICOMV3DataDict[i]; + while( n.name != 0 ) + { + Tag t(n.group, n.element); + DictEntry e( n.name, n.keyword, n.vr, n.vm, n.ret ); + assert( DictEntry::CheckKeywordAgainstName(n.name, n.keyword) ); + AddDictEntry( t, e ); + n = DICOMV3DataDict[++i]; + } +} + +/* +void PrivateDict::LoadDefault() +{ + // TODO +} +*/ + +} // end namespace gdcm +#endif // GDCMDEFAULTDICTS_CXX diff --git a/gdcm/Source/DataDictionary/gdcmDefaultGroupNames.cxx b/gdcm/Source/DataDictionary/gdcmDefaultGroupNames.cxx new file mode 100644 index 0000000..c664377 --- /dev/null +++ b/gdcm/Source/DataDictionary/gdcmDefaultGroupNames.cxx @@ -0,0 +1,118 @@ + +// GENERATED FILE DO NOT EDIT + +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + + +#include "gdcmTypes.h" +#include "gdcmGroupDict.h" + +namespace gdcm { + +typedef struct +{ + uint16_t group; + const char *abbreviation; + const char *name; +} GROUP_ENTRY; + +static GROUP_ENTRY groupname[] = { + {0x0000,"CMD","Command"}, + {0x0002,"META","Meta Element"}, + {0x0004,"DIR","Directory"}, + {0x0004,"FST","File Set"}, + {0x0008,"ID","Identifying"}, + {0x0009,"SPII","SPI Identifying"}, + {0x0010,"PAT","Patient"}, + {0x0012,"CLI","Clinical Trial"}, + {0x0018,"ACQ","Acquisition"}, + {0x0019,"SPIA","SPI Acquisition"}, + {0x0020,"IMG","Image"}, + {0x0021,"SPIIM","SPI Image"}, + {0x0022,"OPHY","Ophtalmology"}, + {0x0028,"IMGP","Image Presentation"}, + {0x0032,"SDY","Study"}, + {0x0038,"VIS","Visit"}, + {0x003a,"WAV","Waveform"}, + {0x0040,"PRC","Procedure"}, + {0x0040,"MOD","Modality Worklist"}, + {0x0042,"EDOC","Encapsulated Document"}, + {0x0050,"XAD","XRay Angio Device"}, + {0x0050,"DEV","Device Information"}, + {0x0054,"NMI","Nuclear Medicine"}, + {0x0060,"HIS","Histogram"}, + {0x0070,"PRS","Presentation State"}, + {0x0072,"HST","Hanging Protocol"}, + {0x0088,"STO","Storage"}, + {0x0088,"MED","Medicine"}, + {0x0100,"AUTH","Authorization"}, + {0x0400,"DSIG","Digital Signature"}, + {0x1000,"COT","Code Table"}, + {0x1010,"ZMAP","Zonal Map"}, + {0x2000,"BFS","Film Session"}, + {0x2010,"BFB","Film Box"}, + {0x2020,"BIB","Image Box"}, + {0x2030,"BAB","Annotation"}, + {0x2040,"IOB","Overlay Box"}, + {0x2050,"PLUT","Presentation LUT"}, + {0x2100,"PJ","Print Job"}, + {0x2110,"PRINTER","Printer"}, + {0x2120,"QUE","Queue"}, + {0x2130,"PCT","Print Content"}, + {0x2200,"MEDIAC","Media Creation"}, + {0x3002,"RTI","RT Image"}, + {0x3004,"RTD","RT Dose"}, + {0x3006,"SSET","RT StructureSet"}, + {0x3008,"RTT","RT Treatment"}, + {0x300a,"RTP","RT Plan"}, + {0x300c,"RTR","RT Relationship"}, + {0x300e,"RTA","RT Approval"}, + {0x4000,"TXT","Text"}, + {0x4008,"RES","Results"}, + {0x4ffe,"MAC","MAC Parameters"}, + {0x5000,"CRV","Curve"}, + {0x5002,"CRV","Curve"}, + {0x5004,"CRV","Curve"}, + {0x5006,"CRV","Curve"}, + {0x5008,"CRV","Curve"}, + {0x500a,"CRV","Curve"}, + {0x500c,"CRV","Curve"}, + {0x500e,"CRV","Curve"}, + {0x5400,"WFM","Waveform Data"}, + {0x6000,"OLY","Overlays"}, + {0x6002,"OLY","Overlays"}, + {0x6004,"OLY","Overlays"}, + {0x6008,"OLY","Overlays"}, + {0x600a,"OLY","Overlays"}, + {0x600c,"OLY","Overlays"}, + {0x600e,"OLY","Overlays"}, + {0xfffc,"GEN","Generic"}, + {0x7fe0,"PXL","Pixel Data"}, + {0xffff,"UNK","Unknown"}, + {0,0,0} // will not be added to the dict +}; + +void GroupDict::FillDefaultGroupName() +{ + unsigned int i = 0; + GROUP_ENTRY n = groupname[i]; + while( n.name != 0 ) + { + Insert( n.group, n.abbreviation, n.name ); + n = groupname[++i]; + } +} + +} // namespace gdcm diff --git a/gdcm/Source/DataDictionary/gdcmDict.h b/gdcm/Source/DataDictionary/gdcmDict.h new file mode 100644 index 0000000..2e81026 --- /dev/null +++ b/gdcm/Source/DataDictionary/gdcmDict.h @@ -0,0 +1,344 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMDICT_H +#define GDCMDICT_H + +#include "gdcmTypes.h" +#include "gdcmTag.h" +#include "gdcmPrivateTag.h" +#include "gdcmDictEntry.h" +#include "gdcmSystem.h" + +#include +#include +#include + +/* + * FIXME / TODO + * I need to seriously rewrite this mess. a class template should work for both a public + * and a private dict + */ + +namespace gdcm +{ +// Data Element Tag +/** + * \brief Class to represent a map of DictEntry + * \note bla + * TODO FIXME: For Element == 0x0 need to return + * Name = Group Length + * ValueRepresentation = UL + * ValueMultiplicity = 1 + */ +class GDCM_EXPORT Dict +{ +public: + typedef std::map MapDictEntry; + typedef MapDictEntry::iterator Iterator; + typedef MapDictEntry::const_iterator ConstIterator; + //static DictEntry GroupLengthDictEntry; // = DictEntry("Group Length",VR::UL,VM::VM1); + + Dict():DictInternal() { + assert( DictInternal.empty() ); + } + + friend std::ostream& operator<<(std::ostream& _os, const Dict &_val); + + ConstIterator Begin() const { return DictInternal.begin(); } + ConstIterator End() const { return DictInternal.end(); } + + bool IsEmpty() const { return DictInternal.empty(); } + void AddDictEntry(const Tag &tag, const DictEntry &de) + { +#ifndef NDEBUG + MapDictEntry::size_type s = DictInternal.size(); +#endif + DictInternal.insert( + MapDictEntry::value_type(tag, de)); + assert( s < DictInternal.size() ); + } + + const DictEntry &GetDictEntry(const Tag &tag) const + { + MapDictEntry::const_iterator it = + DictInternal.find(tag); + if (it == DictInternal.end()) + { +#ifdef UNKNOWNPUBLICTAG + // test.acr + if( tag != Tag(0x28,0x15) + && tag != Tag(0x28,0x16) + && tag != Tag(0x28,0x199) + // gdcmData/TheralysGDCM1.dcm + && tag != Tag(0x20,0x1) + // gdcmData/0019004_Baseline_IMG1.dcm + && tag != Tag(0x8348,0x339) + && tag != Tag(0xb5e8,0x338) + // gdcmData/dicomdir_Acusson_WithPrivate_WithSR + && tag != Tag(0x40,0xa125) + ) + { + assert( 0 && "Impossible" ); + } +#endif + it = DictInternal.find( Tag(0xffff,0xffff) ); + return it->second; + } + assert( DictInternal.count(tag) == 1 ); + return it->second; + } + + /// Function to return the Keyword from a Tag + const char *GetKeywordFromTag(Tag const & tag) const + { + MapDictEntry::const_iterator it = + DictInternal.find(tag); + if (it == DictInternal.end()) + { + return NULL; + } + assert( DictInternal.count(tag) == 1 ); + return it->second.GetKeyword(); + } + + /// Lookup DictEntry by keyword. Even if DICOM standard defines keyword + /// as being unique. The lookup table is built on Tag. Therefore + /// looking up a DictEntry by Keyword is more inefficient than looking up + /// by Tag. + const DictEntry &GetDictEntryByKeyword(const char *keyword, Tag & tag) const + { + MapDictEntry::const_iterator it = + DictInternal.begin(); + if( keyword ) + { + for(; it != DictInternal.end(); ++it) + { + if( strcmp( keyword, it->second.GetKeyword() ) == 0 ) + { + // Found a match ! + tag = it->first; + break; + } + } + } + else + { + it = DictInternal.end(); + } + if (it == DictInternal.end()) + { + tag = Tag(0xffff,0xffff); + it = DictInternal.find( tag ); + return it->second; + } + assert( DictInternal.count(tag) == 1 ); + return it->second; + } + + /// Inefficient way of looking up tag by name. Technically DICOM + /// does not garantee uniqueness (and Curve / Overlay are there to prove it). But + /// most of the time name is in fact uniq and can be uniquely link to a tag + const DictEntry &GetDictEntryByName(const char *name, Tag & tag) const + { + MapDictEntry::const_iterator it = + DictInternal.begin(); + if( name ) + { + for(; it != DictInternal.end(); ++it) + { + if( strcmp( name, it->second.GetName() ) == 0 ) + { + // Found a match ! + tag = it->first; + break; + } + } + } + else + { + it = DictInternal.end(); + } + if (it == DictInternal.end()) + { + tag = Tag(0xffff,0xffff); + it = DictInternal.find( tag ); + return it->second; + } + assert( DictInternal.count(tag) == 1 ); + return it->second; + } + +protected: + friend class Dicts; + void LoadDefault(); + +private: + Dict &operator=(const Dict &_val); // purposely not implemented + Dict(const Dict &_val); // purposely not implemented + + MapDictEntry DictInternal; +}; +//----------------------------------------------------------------------------- +inline std::ostream& operator<<(std::ostream& os, const Dict &val) +{ + Dict::MapDictEntry::const_iterator it = val.DictInternal.begin(); + for(;it != val.DictInternal.end(); ++it) + { + const Tag &t = it->first; + const DictEntry &de = it->second; + os << t << " " << de << '\n'; + } + + return os; +} + +// TODO +// For private dict, element < 0x10 should automatically defined: +// Name = "Private Creator" +// ValueRepresentation = LO +// ValueMultiplicity = 1 +// Owner = "" + +/** + * \brief Private Dict + */ +class GDCM_EXPORT PrivateDict +{ + typedef std::map MapDictEntry; + friend std::ostream& operator<<(std::ostream& os, const PrivateDict &val); +public: + PrivateDict() {} + ~PrivateDict() {} + void AddDictEntry(const PrivateTag &tag, const DictEntry &de) + { +#ifndef NDEBUG + MapDictEntry::size_type s = DictInternal.size(); +#endif + DictInternal.insert( + MapDictEntry::value_type(tag, de)); +// The following code should only be used when manually constructing a Private.xml file by hand +// it will get rid of VR::UN duplicate (ie. if a VR != VR::Un can be found) +#if defined(NDEBUG) && 0 + if( s == DictInternal.size() ) + { + MapDictEntry::iterator it = + DictInternal.find(tag); + assert( it != DictInternal.end() ); + DictEntry &duplicate = it->second; + assert( de.GetVR() == VR::UN || duplicate.GetVR() == VR::UN ); + assert( de.GetVR() != duplicate.GetVR() ); + if( duplicate.GetVR() == VR::UN ) + { + assert( de.GetVR() != VR::UN ); + duplicate.SetVR( de.GetVR() ); + duplicate.SetVM( de.GetVM() ); + assert( GetDictEntry(tag).GetVR() != VR::UN ); + assert( GetDictEntry(tag).GetVR() == de.GetVR() ); + assert( GetDictEntry(tag).GetVM() == de.GetVM() ); + } + return; + } +#endif + assert( s < DictInternal.size() /*&& std::cout << tag << "," << de << std::endl*/ ); + } + /// Remove entry 'tag'. Return true on success (element was found + /// and remove). return false if element was not found. + bool RemoveDictEntry(const PrivateTag &tag) + { + MapDictEntry::size_type s = + DictInternal.erase(tag); + assert( s == 1 || s == 0 ); + return s == 1; + } + bool FindDictEntry(const PrivateTag &tag) const + { + MapDictEntry::const_iterator it = + DictInternal.find(tag); + if (it == DictInternal.end()) + { + return false; + } + return true; + } + const DictEntry &GetDictEntry(const PrivateTag &tag) const + { + // if 0x10 -> return Private Creator + MapDictEntry::const_iterator it = + DictInternal.find(tag); + if (it == DictInternal.end()) + { + //assert( 0 && "Impossible" ); + it = DictInternal.find( PrivateTag(0xffff,0xffff,"GDCM Private Sentinel" ) ); + assert (it != DictInternal.end()); + return it->second; + } + assert( DictInternal.count(tag) == 1 ); + return it->second; + } + + + void PrintXML() const + { + MapDictEntry::const_iterator it = DictInternal.begin(); + std::cout << "\n"; + for(;it != DictInternal.end(); ++it) + { + const PrivateTag &t = it->first; + const DictEntry &de = it->second; + std::cout << " \n"; + } + else + { + std::cout << "\" name=\"" << de.GetName() << "\"/>\n"; + } + } + std::cout << "\n"; + } + + bool IsEmpty() const { return DictInternal.empty(); } +protected: + friend class Dicts; + void LoadDefault(); + +private: + PrivateDict &operator=(const PrivateDict &_val); // purposely not implemented + PrivateDict(const PrivateDict &_val); // purposely not implemented + + MapDictEntry DictInternal; +}; +//----------------------------------------------------------------------------- +inline std::ostream& operator<<(std::ostream& os, const PrivateDict &val) +{ + PrivateDict::MapDictEntry::const_iterator it = val.DictInternal.begin(); + for(;it != val.DictInternal.end(); ++it) + { + const PrivateTag &t = it->first; + const DictEntry &de = it->second; + os << t << " " << de << '\n'; + } + + return os; +} + +} // end namespace gdcm + +#endif //GDCMDICT_H diff --git a/gdcm/Source/DataDictionary/gdcmDictConverter.cxx b/gdcm/Source/DataDictionary/gdcmDictConverter.cxx new file mode 100644 index 0000000..1cdc739 --- /dev/null +++ b/gdcm/Source/DataDictionary/gdcmDictConverter.cxx @@ -0,0 +1,423 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmDictConverter.h" + +#include +#include +#include +#include + +#include +#include // isdigit +#include // for strncmp +#include // for sscanf + +namespace gdcm +{ + +// PIMPL Implementation +struct DictConverterInternal +{ + // Filename to the .dic file + std::string InputFilename; + // Path to the output file (either XML or CXX code) + std::string OutputFilename; + // + std::ifstream InputStream; + std::ofstream OutputStream; + + std::string DictName; +}; + + +DictConverter::DictConverter() +{ + Internal = new DictConverterInternal; + Internal->DictName = "Default"; + OutputType = DICT_DEFAULT; +} + +DictConverter::~DictConverter() +{ + delete Internal; +} + +const std::string &DictConverter::GetDictName() const +{ + return Internal->DictName; +} + +void DictConverter::SetDictName(const char *name) +{ + Internal->DictName = name; +} + +void DictConverter::SetInputFileName(const char* filename) +{ + Internal->InputFilename = filename; +} + +const std::string &DictConverter::GetInputFilename() const +{ + return Internal->InputFilename; +} + +void DictConverter::SetOutputFileName(const char* filename) +{ + Internal->OutputFilename = filename; +} + +const std::string &DictConverter::GetOutputFilename() const +{ + return Internal->OutputFilename; +} + +// \TODO this code reexecute... +void DictConverter::Convert() +{ + // Open files: + std::ifstream &from = Internal->InputStream; //(filename, std::ios::binary); + // Keep binary mode !!! + from.open( Internal->InputFilename.c_str(), std::ios::binary); + std::ofstream &into = Internal->OutputStream; //(outfilename); + into.open( Internal->OutputFilename.c_str(), std::ios::binary ); + + WriteHeader(); + + std::string line; + std::ostringstream os; + while(std::getline(from, line)) + { + if( !line.empty() ) + { + std::string::iterator e(line.end()-1); + if( *e == '\r' ) line.erase(e); + } + if( *(line.c_str()) == '\0' ) + { + // If an empty line is found then a new group starts + AddGroupLength(); + continue; + } + if( line[2] == 'x' && line[3] == 'x' ) + { + if(line[0] == '5') + { + uint16_t start = 0x5000; + uint16_t end = 0x50ff; + for(uint16_t i= start; i<=end; i+=2) + { + std::string s1 = line.c_str()+4; + os.str(""); + os << std::hex << i << s1; + if( OutputType == DICT_XML ) + { + ConvertToXML(os.str().c_str(), s1); + } + else + { + ConvertToCXX(os.str().c_str(), s1); + } + into << s1 << std::endl; + } + } + else if(line[0] == '6') + { + uint16_t start = 0x6000; + uint16_t end = 0x60ff; + for(uint16_t i= start; i<=end; i+=2) + { + std::string s1 = line.c_str()+4; + os.str(""); + os << std::hex << i << s1; + if( OutputType == DICT_XML ) + { + ConvertToXML(os.str().c_str(), s1); + } + else + { + ConvertToCXX(os.str().c_str(), s1); + } + into << s1 << std::endl; + } + } + else + assert(0); + } + else if ( line[7] == 'x' && line[8] == 'x' ) + { + if( line[5] == '3' && line[6] == '1' ) + { + uint16_t start = 0x3100; + uint16_t end = 0x31ff; + for(uint16_t i= start; i<=end; ++i) + { + std::string s1(line.c_str(), line.c_str()+5); + std::string s = line.c_str()+9; + os.str(""); + os << s1 << std::hex << i << s; + if( OutputType == DICT_XML ) + { + ConvertToXML(os.str().c_str(), s); + } + else + { + ConvertToCXX(os.str().c_str(), s); + } + into << s << std::endl; + } + } + else + assert(0); + } + else + { + std::string s; + if( OutputType == DICT_XML ) + { + ConvertToXML(line.c_str(), s); + } + else + { + ConvertToCXX(line.c_str(), s); + } + into << s << std::endl; + } + } + + WriteFooter(); +} + +bool DictConverter::ReadVR(const char *raw, VR::VRType &type) +{ + int i = 0; + while( !isdigit(*(raw+i))) + ++i; + std::string vm(raw, raw+i-1); + type = VR::GetVRType(vm.c_str()); + assert( type != VR::VR_END ); + return true; +} + +bool DictConverter::ReadVM(const char *raw, VM::VMType &type) +{ + char vm[8]; + int r = sscanf(raw, "%s", vm); + assert( r == 1 ); + type = VM::GetVMType(vm); + assert( type != VM::VM_END ); + return true; +} + +bool DictConverter::Readuint16(const char *raw, uint16_t &ov) +{ + unsigned int v; + int r = sscanf(raw, "%04x", &v); + assert( r == 1 && "Wrong Value read for uint16"); + char sv[4+1]; + r = sprintf(sv, "%04x", v); + assert( r == 4 && "Wrong Value printed for uint16"); + assert( strncmp(raw, sv, 4) == 0 ); + ov = v; + return true; +} + +void DictConverter::WriteHeader() +{ + std::ofstream &of = Internal->OutputStream; + const std::string &name = Internal->DictName; + of << "#ifndef __gdcm" << name << "Dicts_cxx\n"; + of << "#define __gdcm" << name << "Dicts_cxx\n\n"; + of << "#include \"gdcmVR.h\"\n"; + of << "#include \"gdcmDict.h\"\n"; + of << "#include \"gdcmDictEntry.h\"\n\n"; + of << "namespace gdcm\n{\n\n"; + of << "typedef struct\n{\n"; + of << " uint16_t group;\n"; + of << " uint16_t element;\n"; + if( OutputType == DICT_DEBUG ) + { + of << " const char *vr;\n"; + of << " const char *vm;\n"; + } + else + { + of << " VR::VRType vr;\n"; + of << " VM::VMType vm;\n"; + } + of << " const char *name;\n"; + of << "} DICT_ENTRY;\n\n"; + of << "static const DICT_ENTRY " << name << "DataDict [] = {\n"; +} + +void DictConverter::WriteFooter() +{ + std::ofstream &of = Internal->OutputStream; + const std::string &name = Internal->DictName; + if(OutputType == DICT_DEBUG ) + of << " {0,0,0,0,0}\n"; + else + of << " {0,0,VR::VR_END,VM::VM_END,0}\n"; + of << "};\n\n"; + of << "void Dict::Fill" << name << "DataDict()\n"; + of << "{\n"; + of << " unsigned int i = 0;\n"; + of << " DICT_ENTRY n = " << name << "DataDict[i];\n"; + of << " while( n.name != 0 )\n"; + of << " { \n"; + of << " Tag t(n.group, n.element);\n"; + of << " DictEntry e( n.name, n.vr, n.vm );\n"; + of << " AddDictEntry( t, e );\n"; + of << " n = " << name << "DataDict[++i];\n"; + of << " }\n"; + of << " //Tag t(0, 0);\n"; + of << " //DictEntry e( \"\", (VR::VRType)0, (VM::VMType)0);\n"; + of << " //AddDictEntry( t, e );\n"; + of << "}\n\n"; + of << "} //end gdcm namespace\n"; + of << "\n#endif\n"; +} + +// Takes as input a raw text file, and converts it into a xml line +// Template is: +// From +// 0000 0000 UL 1 Group Length +// into: +// +bool DictConverter::ConvertToXML(const char *raw, std::string &cxx) +{ + uint16_t group; + uint16_t element; + VR::VRType vr; + VM::VMType vm; + Readuint16(raw, group); + assert( !(group%2) ); + Readuint16(raw+5, element); + ReadVR(raw+10, vr); + int len = 11+strlen(VR::GetVRString(vr)); + ReadVM(raw+len, vm); + len += strlen(VM::GetVMString(vm))+1; + std::ostringstream os; + os << " "; + cxx = os.str(); + return true; +} + +// Takes as input a raw text file, and converts it into a c++ line +// Template is: +// From +// 0000 0000 UL 1 Group Length +// into: +// {0x0000, 0x0000, "UL" , "1" , "Group Length"}, +bool DictConverter::ConvertToCXX(const char *raw, std::string &cxx) +{ + uint16_t group; + uint16_t element; + VR::VRType vr; + VM::VMType vm; + Readuint16(raw, group); + //assert( !(group%2) ); + // + Readuint16(raw+5, element); + ReadVR(raw+10, vr); + int len = 11+strlen(VR::GetVRString(vr)); + ReadVM(raw+len, vm); + len += strlen(VM::GetVMString(vm))+1; + std::ostringstream os; + os << " {0x" << std::hex << std::setw(4) << std::setfill('0') + << group << ", 0x" + << std::setw(4) << std::setfill('0'); + if( OutputType == DICT_DEBUG ) + { + os << element << ", \"" << vr << "\" , \"" << vm << "\" , \"" + << (raw+len) << "\"}, "; + } + else + { + os << element << std::dec << ",(VR::VRType)" << (int)vr + << ",(VM::VMType)" << (int)vm << ",\"" << (raw+len) << "\"},"; + } + cxx = os.str(); + return true; +} + + +void DictConverter::AddGroupLength() +{ + std::ifstream &from = Internal->InputStream; + std::ofstream &into = Internal->OutputStream; + + std::streampos p = from.tellg(); + char group[5]; + from.get(group, 5); + std::string in = group; + const char group_str[] = " 0000 UL 1 Group Length"; + std::ostringstream os; + std::string out; + if( in[2] == 'x' && in[3] == 'x' ) + { + std::string line = in; + if(line[0] == '5') + { + uint16_t start = 0x5000; + uint16_t end = 0x50ff; + for(uint16_t i= start; i<=end; i+=2) + { + os.str(""); + os << std::hex << i << group_str; + if( OutputType != DICT_XML ) + { + ConvertToCXX(os.str().c_str(), out); + into << out << std::endl; + } + } + } + else if(line[0] == '6') + { + uint16_t start = 0x6000; + uint16_t end = 0x60ff; + for(uint16_t i= start; i<=end; i+=2) + { + os.str(""); + os << std::hex << i << group_str; + if( OutputType != DICT_XML ) + { + ConvertToCXX(os.str().c_str(), out); + into << out << std::endl; + } + } + } + } + else + { + in += group_str; + if( OutputType == DICT_XML ) + { + ConvertToXML(in.c_str(), out); + } + else + { + ConvertToCXX(in.c_str(), out); + } + into << out << std::endl; + } + // seek back + from.seekg(p); +} + +} // end namespace gdcm diff --git a/gdcm/Source/DataDictionary/gdcmDictConverter.h b/gdcm/Source/DataDictionary/gdcmDictConverter.h new file mode 100644 index 0000000..7ca1552 --- /dev/null +++ b/gdcm/Source/DataDictionary/gdcmDictConverter.h @@ -0,0 +1,83 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#ifndef GDCMDICTCONVERTER_H +#define GDCMDICTCONVERTER_H + +#include "gdcmTypes.h" +#include "gdcmVR.h" +#include "gdcmVM.h" + +#include + +namespace gdcm +{ + +class DictConverterInternal; +/** + * \brief Class to convert a .dic file into something else: + * - CXX code : embeded dict into shared lib (DICT_DEFAULT) + * - Debug mode (DICT_DEBUG) + * - XML dict (DICT_XML) + * \note + */ +class GDCM_EXPORT DictConverter +{ +public: + DictConverter(); + ~DictConverter(); + void SetInputFileName(const char* filename); + const std::string &GetInputFilename() const; + void SetOutputFileName(const char* filename); + const std::string &GetOutputFilename() const; + + int GetOutputType() const { + return OutputType; + } + void SetOutputType(int type) { + OutputType = type; + } + const std::string &GetDictName() const; + void SetDictName(const char *name); + + void Convert(); + + // Leaving them public for now. Not really user oriented but may be + // usefull + static bool ReadVR(const char *raw, VR::VRType &type); + static bool ReadVM(const char *raw, VM::VMType &type); + static bool Readuint16(const char *raw, uint16_t &ov); + + enum OutputTypes { + DICT_DEFAULT = 0, + DICT_DEBUG, + DICT_XML + }; + +protected: + void WriteHeader(); + void WriteFooter(); + bool ConvertToXML(const char *raw, std::string &cxx); + bool ConvertToCXX(const char *raw, std::string &cxx); + void AddGroupLength(); + +private: + DictConverterInternal *Internal; + + int OutputType; +}; + +} // end namespace gdcm + +#endif //GDCMDICTCONVERTER_H diff --git a/gdcm/Source/DataDictionary/gdcmDictEntry.cxx b/gdcm/Source/DataDictionary/gdcmDictEntry.cxx new file mode 100644 index 0000000..8933858 --- /dev/null +++ b/gdcm/Source/DataDictionary/gdcmDictEntry.cxx @@ -0,0 +1,72 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmDictEntry.h" +#include "gdcmSystem.h" + +#include // remove_if + +namespace gdcm +{ + +bool IsToBeRemoved(int c) +{ + if ( isspace ( c ) ) return true; + if( c == '-' ) return true; + if( c == '/' ) return true; + if( c == '\'' ) return true; + if( c == '(' ) return true; + if( c == ')' ) return true; + if( c == '&' ) return true; + if( c == ',' ) return true; + return false; +} + +bool DictEntry::CheckKeywordAgainstName(const char *name, const char *keyword) +{ + /* MM / Wed Aug 11 18:55:26 CEST 2010 + I cannot get the following working: + +Problem with: LengthtoEnd vs CommandLengthToEnd +Problem with: RecognitionCode vs CommandRecognitionCode +Problem with: DataSetType vs CommandDataSetType +Problem with: MagnificationType vs CommandMagnificationType +Problem with: FrameNumbersofInterestFOI vs FrameNumbersOfInterest +Problem with: 3DRenderingType vs ThreeDRenderingType + + */ + if( !name ) return false; + if( !keyword ) return false; + std::string str = name; + std::string::size_type found = str.find( "'s " ); + while( found != std::string::npos ) + { + str.erase( found, 3 ); + found = str.find( "'s " ); + } + std::string::size_type found_mu = str.find( "µ" ); + while( found_mu != std::string::npos ) + { + str.replace( found_mu, 2, "u", 1 ); + found_mu = str.find( "µ" ); + } + + str.erase(remove_if(str.begin(), str.end(), IsToBeRemoved), str.end()); + + if( System::StrCaseCmp(str.c_str(), keyword) == 0 ) return true; + + // std::cerr << "Problem with: " << str << " vs " << keyword << std::endl; + return true; +} + +} diff --git a/gdcm/Source/DataDictionary/gdcmDictEntry.h b/gdcm/Source/DataDictionary/gdcmDictEntry.h new file mode 100644 index 0000000..c184632 --- /dev/null +++ b/gdcm/Source/DataDictionary/gdcmDictEntry.h @@ -0,0 +1,146 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMDICTENTRY_H +#define GDCMDICTENTRY_H + +#include "gdcmVR.h" +#include "gdcmVM.h" + +#include +#include +#include + +namespace gdcm +{ +/** + * \brief Class to represent an Entry in the Dict + * Does not really exist within the DICOM definition, just a way to minimize + * storage and have a mapping from gdcm::Tag to the needed information + * \note bla + * TODO FIXME: Need a PublicDictEntry...indeed DictEntry has a notion of retired which + * does not exist in PrivateDictEntry... + * + * \see gdcm::Dict + */ +class GDCM_EXPORT DictEntry +{ +public: + DictEntry(const char *name = "", const char *keyword = "", VR const &vr = VR::INVALID, VM const &vm = VM::VM0, bool ret = false): + Name(name), + Keyword(keyword), + ValueRepresentation(vr), + ValueMultiplicity(vm), + Retired(ret), + GroupXX(false), + ElementXX(false) + { + } + + friend std::ostream& operator<<(std::ostream& _os, const DictEntry &_val); + + /// Set/Get VR + const VR &GetVR() const { return ValueRepresentation; } + void SetVR(const VR & vr) { ValueRepresentation = vr; } +// bool IsValid() const { return ValueRepresentation != VR::VR_END; } +// !Name.empty() /*&& ValueRepresentation && ValueMultiplicity*/; } + + /// Set/Get VM + const VM &GetVM() const { return ValueMultiplicity; } + void SetVM(VM const & vm) { ValueMultiplicity = vm; } + + /// Set/Get Name + const char *GetName() const { return Name.c_str(); } + void SetName(const char* name) { Name = name; } + + /// same as GetName but without spaces... + const char *GetKeyword() const { return Keyword.c_str(); } + void SetKeyword(const char* keyword) { Keyword = keyword; } + + /// Set/Get Retired flag + bool GetRetired() const { return Retired; } + void SetRetired(bool retired) { Retired = retired; } + + // + /// Set whether element is shared in multiple groups (Curve/Overlay typically) + void SetGroupXX(bool v) { GroupXX = v; } + + // + /// Set whether element is shared in multiple elements (Source Image IDs typically) + void SetElementXX(bool v) { ElementXX = v; } + + /// Return whether the name of the DataElement can be considered to be unique. + /// As of 2008 all elements name were unique (except the expclitely 'XX' ones) + bool IsUnique() const { return ElementXX == false && GroupXX == false; } + +private: + // + friend class Dict; + static bool CheckKeywordAgainstName(const char *name, const char *keyword); + +private: + std::string Name; + std::string Keyword; + VR ValueRepresentation; + VM ValueMultiplicity; + bool Retired : 1; + bool GroupXX : 1; + bool ElementXX : 1; +}; + +#if 0 +class GDCM_EXPORT PrivateDictEntry : public DictEntry +{ +public: + PrivateDictEntry(const char *name = "", VR::VRType const &vr = VR::INVALID, VM::VMType const &vm = VM::VM0 , bool ret = false, const char *owner = ""):DictEntry(name,vr,vm,ret),Owner(owner) {} + PrivateDictEntry(const char *name, const char *vr, const char *vm):DictEntry(name,vr,vm) {} + + const char *GetOwner() const { return Owner.c_str(); } + void SetOwner(const char *owner) { Owner = owner; } + +private: + // SIEMENS MED, GEMS_PETD_01 ... + std::string Owner; +}; +#endif + +//----------------------------------------------------------------------------- +inline std::ostream& operator<<(std::ostream& os, const DictEntry &val) +{ + if( val.Name.empty() ) + { + os << "[No name]"; + } + else + { + os << val.Name; + } + if( val.Keyword.empty() ) + { + os << "[No keyword]"; + } + else + { + os << val.Keyword; + } + os << "\t" << val.ValueRepresentation << "\t" << val.ValueMultiplicity; + if( val.Retired ) + { + os << "\t(RET)"; + } + return os; +} + +} // end namespace gdcm + +#endif //GDCMDICTENTRY_H diff --git a/gdcm/Source/DataDictionary/gdcmDicts.cxx b/gdcm/Source/DataDictionary/gdcmDicts.cxx new file mode 100644 index 0000000..f090da6 --- /dev/null +++ b/gdcm/Source/DataDictionary/gdcmDicts.cxx @@ -0,0 +1,172 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmDicts.h" + +namespace gdcm +{ + +Dicts::Dicts():PublicDict(),ShadowDict() +{ + //PublicType = DICOMV3_DICT; + //PublicDicts.resize(3, Dict() ); +} + +Dicts::~Dicts() +{ +} + +//void Dicts::AddPublicDict(const Dict& dict) +//{ +// (void)dict; +// //PublicDicts.push_back( dict ); +//} + +//void Dicts::SetPublicType(int type) +//{ +// PublicType = type; +//} + +const DictEntry &Dicts::GetDictEntry(const Tag& tag, const char *owner) const +{ + static DictEntry Dummy; + if( tag.IsGroupLength() ) + { + const DictEntry & de = PublicDict.GetDictEntry(tag); + const char *name = de.GetName(); + if( name && *name ) + { + return de; + } + else + { + Dummy.SetName( "Generic Group Length" ); + Dummy.SetKeyword( "GenericGroupLength" ); + bool retired = true; // Since DICOM 2008, all (but 0002,0004) group length are retired + Dummy.SetVR( VR::UL ); + Dummy.SetVM( VM::VM1 ); + Dummy.SetRetired( retired ); + return Dummy; + } + } + else if( tag.IsPublic() ) + { + assert( owner == NULL ); + return PublicDict.GetDictEntry(tag); + } + else + { + assert( tag.IsPrivate() ); + if( owner && *owner ) + { + size_t len = strlen(owner); (void)len; + PrivateTag ptag(tag.GetGroup(), (uint16_t)(((uint16_t)(tag.GetElement() << 8)) >> 8), owner); + const DictEntry &de = GetPrivateDict().GetDictEntry(ptag); + return de; + } + else + { + // Check special private element: 0x0000 and [0x1,0xFF] are special cases: + if( tag.IsIllegal() ) + { + std::string pc ( "Illegal Element" ); + Dummy.SetName( pc.c_str() ); + std::string kw ( "IllegalElement" ); + Dummy.SetKeyword( kw.c_str() ); + Dummy.SetVR( VR::INVALID ); + Dummy.SetVM( VM::VM0 ); + Dummy.SetRetired( false ); // ?? + return Dummy; + } + else if( tag.IsPrivateCreator() ) + { + assert( !tag.IsIllegal() ); + assert( tag.GetElement() ); // Not a group length ! + assert( tag.IsPrivate() ); + assert( owner == 0x0 ); + { + static const char pc[] = "Private Creator"; + static const char kw[] = "PrivateCreator"; + Dummy.SetName( pc ); + Dummy.SetKeyword( kw ); + } + Dummy.SetVR( VR::LO ); + Dummy.SetVM( VM::VM1 ); + Dummy.SetRetired( false ); + return Dummy; + } + else + { + if( owner && *owner ) + { + static const char pc[] = "Private Element Without Private Creator"; + static const char kw[] = "PrivateElementWithoutPrivateCreator"; + Dummy.SetName( pc ); + Dummy.SetKeyword( kw ); + } + else + { + static const char pc[] = "Private Element With Empty Private Creator"; + static const char kw[] = "PrivateElementWithEmptyPrivateCreator"; + Dummy.SetName( pc ); + Dummy.SetKeyword( kw ); + } + Dummy.SetVR( VR::INVALID ); + Dummy.SetVM( VM::VM0 ); + return Dummy; + } + } + } +} + +const DictEntry &Dicts::GetDictEntry(const PrivateTag& tag) const +{ + return GetDictEntry(tag, tag.GetOwner() ); +} + + +const char *Dicts::GetConstructorString(ConstructorType type) +{ + (void)type; + return ""; +} + +const Dict &Dicts::GetPublicDict() const +{ + //assert( PublicType < PublicDicts.size() ); + return PublicDict; //[PublicType]; +} + +const PrivateDict &Dicts::GetPrivateDict() const +{ + return ShadowDict; +} +PrivateDict &Dicts::GetPrivateDict() +{ + return ShadowDict; +} + +const CSAHeaderDict &Dicts::GetCSAHeaderDict() const +{ + return CSADict; +} + +void Dicts::LoadDefaults() +{ + // TODO: should the user be able to control which dict to load ? + PublicDict.LoadDefault(); + ShadowDict.LoadDefault(); + CSADict.LoadDefault(); +} + +} // end namespace gdcm diff --git a/gdcm/Source/DataDictionary/gdcmDicts.h b/gdcm/Source/DataDictionary/gdcmDicts.h new file mode 100644 index 0000000..3d0dd66 --- /dev/null +++ b/gdcm/Source/DataDictionary/gdcmDicts.h @@ -0,0 +1,91 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMDICTS_H +#define GDCMDICTS_H + +#include "gdcmDict.h" +#include "gdcmCSAHeaderDict.h" + +#include + +namespace gdcm +{ +/** + * \brief Class to manipulate the sum of knowledge (all the dict user load) + * \note bla + */ +class GDCM_EXPORT Dicts +{ + friend std::ostream& operator<<(std::ostream &_os, const Dicts &d); +public: + Dicts(); + ~Dicts(); + + /// works for both public and private dicts: + /// owner is null for public dict + /// \warning owner need to be set to appropriate owner for call to work. see + // DataSet::GetPrivateCreator + /// NOT THREAD SAFE + const DictEntry &GetDictEntry(const Tag& tag, const char *owner = NULL) const; + + const DictEntry &GetDictEntry(const PrivateTag& tag) const; + + //enum PublicTypes { + // DICOMV3_DICT, + // ACRNEMA_DICT, + // NIH_DICT + //}; + const Dict &GetPublicDict() const; + + const PrivateDict &GetPrivateDict() const; + PrivateDict &GetPrivateDict(); + + const CSAHeaderDict &GetCSAHeaderDict() const; + + bool IsEmpty() const { return GetPublicDict().IsEmpty(); } + +protected: + typedef enum { + PHILIPS, + GEMS, + SIEMENS + // ... + } ConstructorType; + static const char *GetConstructorString(ConstructorType type); + + friend class Global; + void LoadDefaults(); + +private: + // Public dict: + Dict PublicDict; + + // Private Dicts: + PrivateDict ShadowDict; + + CSAHeaderDict CSADict; + Dicts &operator=(const Dicts &_val); // purposely not implemented + Dicts(const Dicts &_val); // purposely not implemented +}; +//----------------------------------------------------------------------------- +inline std::ostream& operator<<(std::ostream &os, const Dicts &d) +{ + (void)d; + return os; +} + + +} // end namespace gdcm + +#endif //GDCMDICTS_H diff --git a/gdcm/Source/DataDictionary/gdcmGlobal.cxx b/gdcm/Source/DataDictionary/gdcmGlobal.cxx new file mode 100644 index 0000000..54d2c93 --- /dev/null +++ b/gdcm/Source/DataDictionary/gdcmGlobal.cxx @@ -0,0 +1,194 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmGlobal.h" +#include "gdcmDicts.h" +#include "gdcmDefs.h" +#include "gdcmFilename.h" + +#include // PATH_MAX +#include // strcpy +#ifdef _WIN32 +#include // MAX_PATH +#endif + +namespace gdcm +{ + +// Must NOT be initialized. Default initialization to zero is +// necessary. +unsigned int GlobalCount; + +class GlobalInternal +{ +public: + GlobalInternal():GlobalDicts(),GlobalDefs() {} + Dicts GlobalDicts; // Part 6 + Part 4 elements +// TODO need H table for TransferSyntax / MediaStorage / Part 3 ... + Defs GlobalDefs; + + // Ressource paths: + // By default only construct two paths: + // - The official install dir (need to keep in sinc with cmakelist variable + // - a dynamic one, so that gdcm is somewhat rellocatable + // - on some system where it make sense the path where the Resource should be located + void LoadDefaultPaths() + { + assert( RessourcePaths.empty() ); + const char filename2[] = GDCM_CMAKE_INSTALL_PREFIX "/" GDCM_INSTALL_DATA_DIR "/XML/"; + RessourcePaths.push_back( filename2 ); + const char filename3[] = GDCM_CMAKE_INSTALL_PREFIX " " GDCM_API_VERSION "/" GDCM_INSTALL_DATA_DIR "/XML/"; + RessourcePaths.push_back( filename3 ); + const char *curprocfn = System::GetCurrentProcessFileName(); + if( curprocfn ) + { + Filename fn( curprocfn ); + std::string str = fn.GetPath(); + str += "/../" GDCM_INSTALL_DATA_DIR "/XML/"; + RessourcePaths.push_back( str ); + } + const char *respath = System::GetCurrentResourcesDirectory(); + if( respath ) + { + RessourcePaths.push_back( respath ); + } +#ifdef GDCM_BUILD_TESTING + // Needed for backward compat and dashboard + const char src_path[] = GDCM_SOURCE_DIR "/Source/InformationObjectDefinition/"; + RessourcePaths.push_back( src_path ); +#endif + } + std::vector RessourcePaths; +}; + +Global::Global() +{ + if(++GlobalCount == 1) + { + assert( Internals == NULL ); // paranoid + Internals = new GlobalInternal; + assert( Internals->GlobalDicts.IsEmpty() ); + // Fill in with default values now ! + // at startup time is safer as later call might be from different thread + // thus initialization of std::map would be all skrew up + Internals->GlobalDicts.LoadDefaults(); + assert( Internals->GlobalDefs.IsEmpty() ); + // Same goes for GlobalDefs: + //Internals->GlobalDefs.LoadDefaults(); + Internals->LoadDefaultPaths(); + } +} + +Global::~Global() +{ + if(--GlobalCount == 0) + { + //Internals->GlobalDicts.Unload(); + delete Internals; + Internals = NULL; // paranoid + } +} + +bool Global::LoadResourcesFiles() +{ + assert( Internals != NULL ); // paranoid + const char *filename = Locate( "Part3.xml" ); + if( filename ) + { + if( Internals->GlobalDefs.IsEmpty() ) + Internals->GlobalDefs.LoadFromFile(filename); + return true; + } + // resource manager was not set properly + return false; +} + +bool Global::Append(const char *path) +{ + if( !System::FileIsDirectory(path) ) + { + return false; + } + Internals->RessourcePaths.push_back( path ); + return true; +} + +bool Global::Prepend(const char *path) +{ + if( !System::FileIsDirectory(path) ) + { + return false; + } + Internals->RessourcePaths.insert( Internals->RessourcePaths.begin(), path ); + return true; +} + +const char *Global::Locate(const char *resfile) const +{ +#ifdef _WIN32 + static char path[MAX_PATH]; +#else + static char path[PATH_MAX]; +#endif + + std::vector::const_iterator it = Internals->RessourcePaths.begin(); + for( ; it != Internals->RessourcePaths.end(); ++it) + { + const std::string &p = *it; + gdcmDebugMacro( "Trying to locate in: " << p ); + std::string fullpath = p + "/" + resfile; + if( System::FileExists(fullpath.c_str()) ) + { + // we found a match + // check no invalid write access possible: + if( fullpath.size() >= sizeof(path) ) + { + gdcmDebugMacro( "Impossible happen: path is too long" ); + return NULL; + } + strcpy(path, fullpath.c_str() ); + return path; + } + } + // no match sorry :( + return NULL; +} + +Dicts const &Global::GetDicts() const +{ + assert( !Internals->GlobalDicts.IsEmpty() ); + return Internals->GlobalDicts; +} + +Dicts &Global::GetDicts() +{ + assert( !Internals->GlobalDicts.IsEmpty() ); + return Internals->GlobalDicts; +} + +Defs const &Global::GetDefs() const +{ + assert( !Internals->GlobalDefs.IsEmpty() ); + return Internals->GlobalDefs; +} + +Global& Global::GetInstance() +{ + return GlobalInstance; +} + +// Purposely not initialized. ClassInitialize will handle it. +GlobalInternal * Global::Internals; + + +} // end namespace gdcm diff --git a/gdcm/Source/DataDictionary/gdcmGlobal.h b/gdcm/Source/DataDictionary/gdcmGlobal.h new file mode 100644 index 0000000..c99a78e --- /dev/null +++ b/gdcm/Source/DataDictionary/gdcmGlobal.h @@ -0,0 +1,107 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +// Implementation detail was shamelessly borowed from the VTK excellent +// implementation of debug leak manager singleton: +/*========================================================================= + + Program: Visualization Toolkit + Module: $RCSfile: vtkDebugLeaks.cxx,v $ + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMGLOBAL_H +#define GDCMGLOBAL_H + +#include "gdcmTypes.h" + +namespace gdcm +{ +class GlobalInternal; +class Dicts; +class Defs; +/** + * \brief Global + * \note + * Global should be included in any translation unit + * that will use Dict or that implements the singleton + * pattern. It makes sure that the Dict singleton is created + * before and destroyed after all other singletons in GDCM. + * + */ +class GDCM_EXPORT Global // why expose the symbol I think I only need to expose the instance... +{ + friend std::ostream& operator<<(std::ostream &_os, const Global &g); +public: + Global(); + ~Global(); + + /// retrieve the default/internal dicts (Part 6) + /// This dict is filled up at load time + Dicts const &GetDicts() const; + Dicts &GetDicts(); + + /// retrieve the default/internal (Part 3) + /// You need to explicitely call LoadResourcesFiles before + Defs const &GetDefs() const; + + /// return the singleton instance + static Global& GetInstance(); + + /// Load all internal XML files, resource path need to have been + /// set before calling this member function (see Append/Prepend members func) + /// \warning not thread safe ! + bool LoadResourcesFiles(); + + /// Append path at the end of the path list + /// \warning not thread safe ! + bool Append(const char *path); + + /// Prepend path at the beginning of the path list + /// \warning not thread safe ! + bool Prepend(const char *path); + +protected: + /// Locate a resource file + const char *Locate(const char *resfile) const; + +private: + Global &operator=(const Global &_val); // purposely not implemented + Global(const Global &_val); // purposely not implemented + // PIMPL: + // but we could have also directly exposed a Dicts *Internals; + static GlobalInternal *Internals; +}; +//----------------------------------------------------------------------------- +inline std::ostream& operator<<(std::ostream &os, const Global &g) +{ + (void)g; + return os; +} + +// This instance will show up in any translation unit that uses +// Global or that has a singleton. It will make sure +// Global is initialized before it is used and is the last +// static object destroyed. +static Global GlobalInstance; + +} // end namespace gdcm + +#endif //GDCMGLOBAL_H diff --git a/gdcm/Source/DataDictionary/gdcmGroupDict.cxx b/gdcm/Source/DataDictionary/gdcmGroupDict.cxx new file mode 100644 index 0000000..3083bbd --- /dev/null +++ b/gdcm/Source/DataDictionary/gdcmGroupDict.cxx @@ -0,0 +1,47 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmGroupDict.h" + +namespace gdcm +{ + +std::string const &GroupDict::GetAbbreviation(uint16_t num) const +{ + assert(num < Abbreviations.size()); + return Abbreviations[num]; +} + +std::string const &GroupDict::GetName(uint16_t num) const +{ + assert(num < Names.size()); + return Names[num]; +} + +void GroupDict::Add(std::string const &abbreviation, std::string const &name) +{ + Abbreviations.push_back(abbreviation); + Names.push_back(name); +} + +void GroupDict::Insert(uint16_t num, std::string const &abbreviation, + std::string const &name) +{ + Abbreviations.resize(num+1); + Names.resize(num+1); + Abbreviations.insert(Abbreviations.begin()+num, abbreviation); + Names.insert(Names.begin()+num, name); +} + + +} // end namespace gdcm diff --git a/gdcm/Source/DataDictionary/gdcmGroupDict.h b/gdcm/Source/DataDictionary/gdcmGroupDict.h new file mode 100644 index 0000000..c3b9249 --- /dev/null +++ b/gdcm/Source/DataDictionary/gdcmGroupDict.h @@ -0,0 +1,79 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#ifndef GDCMGROUPDICT_H +#define GDCMGROUPDICT_H + +#include "gdcmTypes.h" + +#include +#include +#include +#include +#include + +namespace gdcm +{ +/** + * \brief Class to represent the mapping from group number to its abbreviation and name + * \note Should I rewrite this class to use a std::map instead of std::vector for problem of + * memory consumption ? + */ +class GDCM_EXPORT GroupDict +{ +public: + typedef std::vector GroupStringVector; + GroupDict() { FillDefaultGroupName(); } + ~GroupDict() {} + + friend std::ostream& operator<<(std::ostream& _os, const GroupDict &_val); + + size_t Size() const + { + assert( Names.size() == Abbreviations.size() ); + return Names.size(); } + + std::string const &GetAbbreviation(uint16_t num) const; + + std::string const &GetName(uint16_t num) const; + +protected: + void Add(std::string const &abbreviation, std::string const &name); + void Insert(uint16_t num, std::string const &abbreviation, std::string const &name); + +private: + // Generated implementation, see gdcmDefaultGroupNames + void FillDefaultGroupName(); + + GroupDict &operator=(const GroupDict &_val); // purposely not implemented + GroupDict(const GroupDict &_val); // purposely not implemented + + GroupStringVector Abbreviations; + GroupStringVector Names; +}; +//----------------------------------------------------------------------------- +inline std::ostream& operator<<(std::ostream& _os, const GroupDict &_val) +{ + size_t size = _val.Size(); + for(size_t i=0; i +#include +#include // for std::getline +#include +#include +#include // std::setw + +void write_header(std::ofstream &of) +{ + of << "#include \"gdcmTypes.h\"\n" + "#include \"gdcmGroupDict.h\"\n\n" + "namespace gdcm {\n\n" + "typedef struct\n{\n" + " uint16_t group;\n" + " const char *abbreviation;\n" + " const char *name;\n" + "} GROUP_ENTRY;\n\n" + "static GROUP_ENTRY groupname[] = {\n"; +} + +void write_footer(std::ofstream &of) +{ + of << "\t{0,0,0} // will not be added to the dict \n" + "};\n\n" + "void GroupDict::FillDefaultGroupName()\n" + "{\n" + " unsigned int i = 0;\n" + " GROUP_ENTRY n = groupname[i];\n" + " while( n.name != 0 )\n" + " {\n" + " Insert( n.group, n.abbreviation, n.name );\n" + " n = groupname[++i];\n" + " }\n" + "}\n\n" + "} // namespace gdcm\n"; +} + +bool check_abbr(std::string &abbr) +{ + std::string::const_iterator it = abbr.begin(); + for(; it != abbr.end(); ++it) + { + if ( *it < 'A' || *it > 'Z' ) return false; + } + return true; +} + +int main(int argc, char *argv[]) +{ + if( argc < 3 ) + return 1; + + const char *filename = argv[1]; // Full path to the dict + const char *outfilename = argv[2]; // Full path to output the dict + //std::cerr << "open: " << filename << std::endl; + std::ifstream from(filename, std::ios::binary); + std::ofstream into(outfilename,std::ios::binary); + if(!from) + { + std::cerr << "Problem opening the from file" << std::endl; + return 1; + } + if(!into) + { + std::cerr << "Problem opening the into file" << std::endl; + return 1; + } + + write_header(into); + int error = 0; + std::string line; + while(std::getline(from, line)) + { + if( !line.empty() ) + { + std::string::iterator e(line.end()-1); + if( *e == '\r' ) line.erase(e); + } + unsigned int group; // Group Number + std::string abbr; // NHI Abbreviation (when known) - not part of DICOM standard - + std::string meaning; // Meaning (when known) - not part of DICOM standard - + std::istringstream is(line); + is >> std::hex >> group; + if ( group > 0xffff) + return 1; + is >> abbr; + if( !check_abbr(abbr) ) + return 1; + // skip any whitespace before calling getline + is >> std::ws; + // get all the remaining characters + std::getline(is,meaning); + into << "\t{0x" << std::hex << std::setw(4) << std::setfill('0') << group << ",\"" << abbr << "\",\"" << meaning << "\"},\n"; + } + write_footer(into); + + from.close(); + into.close(); + + return error; +} diff --git a/gdcm/Source/DataDictionary/gdcmPrivateDefaultDicts.cxx b/gdcm/Source/DataDictionary/gdcmPrivateDefaultDicts.cxx new file mode 100644 index 0000000..9803140 --- /dev/null +++ b/gdcm/Source/DataDictionary/gdcmPrivateDefaultDicts.cxx @@ -0,0 +1,9412 @@ + +// GENERATED FILE DO NOT EDIT +// $ xsltproc DefaultDicts.xsl DICOMV3.xml > gdcmDefaultDicts.cxx + +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#ifndef GDCMPRIVATEDEFAULTDICTS_CXX +#define GDCMPRIVATEDEFAULTDICTS_CXX + +#include "gdcmDicts.h" +#include "gdcmVR.h" +#include "gdcmDict.h" +#include "gdcmDictEntry.h" + +namespace gdcm { +typedef struct +{ + uint16_t group; + uint16_t element; + const char *owner; + VR::VRType vr; + VM::VMType vm; + const char *name; + bool ret; +} DICT_ENTRY; + +static const DICT_ENTRY DICOMV3DataDict [] = { + {0x6301,0x0001,"KRETZ_PRIVATE",VR::IS,VM::VM1,"?",false }, + {0x6301,0x0002,"KRETZ_PRIVATE",VR::IS,VM::VM1,"?",false }, + {0x0029,0x0000,"VOLCANO-PCDE 1.0",VR::DS,VM::VM1,"Pullback Rate",false }, + {0x0029,0x0001,"VOLCANO-PCDE 1.0",VR::FD,VM::VM1,"B Gain",false }, + {0x0029,0x0002,"VOLCANO-PCDE 1.0",VR::US,VM::VM1,"B Persistence Index",false }, + {0x0029,0x0003,"VOLCANO-PCDE 1.0",VR::FD,VM::VM1,"B ROI Diameter",false }, + {0x0029,0x0004,"VOLCANO-PCDE 1.0",VR::US,VM::VM1,"CF Sensitivity Index",false }, + {0x0029,0x0005,"VOLCANO-PCDE 1.0",VR::FD,VM::VM1,"CF ROI Diameter",false }, + {0x0029,0x0006,"VOLCANO-PCDE 1.0",VR::US,VM::VM1,"Frame Capture Interleave Rate",false }, + {0x0029,0x0007,"VOLCANO-PCDE 1.0",VR::US,VM::VM1,"Ringdown Subtraction",false }, + {0x0029,0x0008,"VOLCANO-PCDE 1.0",VR::US,VM::VM1,"Graticule Spacing",false }, + {0x0029,0x0010,"VOLCANO-PCDE 1.0",VR::SH,VM::VM1,"PIM Serial Number",false }, + {0x0029,0x0016,"VOLCANO-PCDE 1.0",VR::US,VM::VM1,"Video Loop Number",false }, + {0x0029,0x0030,"VOLCANO-PCDE 1.0",VR::SS,VM::VM1,"Catheter Boot Mode",false }, + {0x0029,0x0010,"ShowcaseAppearance",VR::DS,VM::VM1,"?",false }, + {0x0029,0x0011,"ShowcaseAppearance",VR::DS,VM::VM1,"?",false }, + {0x0029,0x0012,"ShowcaseAppearance",VR::DS,VM::VM1,"?",false }, + {0x0029,0x0013,"ShowcaseAppearance",VR::DS,VM::VM1,"?",false }, + {0x0029,0x0014,"ShowcaseAppearance",VR::SQ,VM::VM1,"?",false }, + {0x2111,0x0010,"Viztek OPALRAD PrivateGroup",VR::UT,VM::VM1,"XML annotations",false }, + {0x0caf,0x0011,"Xinapse Systems",VR::LO,VM::VM1,"Private attributes Identification Code",false }, + {0x0caf,0x0001,"Xinapse Systems",VR::OB,VM::VM1,"Regions of interest",false }, + {0x0043,0x0014,"dcm4che/archive",VR::AE,VM::VM1,"ae name 1",false }, + {0x0043,0x0015,"dcm4che/archive",VR::AE,VM::VM1,"ae name 2",false }, + {0x0009,0x0001,"DicomUtils 20100512",VR::SQ,VM::VM1,"DICOMUTILS_PROCESSING_METHODS",false }, + {0x0009,0x0002,"DicomUtils 20100512",VR::LO,VM::VM1,"DICOMUTILS_VERSION",false }, + {0x0009,0x0003,"DicomUtils 20100512",VR::LT,VM::VM1,"DICOMUTILS_ARGS",false }, + {0x0009,0x0004,"DicomUtils 20100512",VR::LT,VM::VM1,"DICOMUTILS_COMMENT",false }, + {0x0009,0x0005,"DicomUtils 20100512",VR::LT,VM::VM1,"DICOMUTILS_SITE",false }, + {0x0053,0x0001,"3Z_IMAGE_IMPORT_CLIENT_INFO",VR::LO,VM::VM1,"?Date+Time?",false }, + {0x0053,0x0002,"3Z_IMAGE_IMPORT_CLIENT_INFO",VR::LO,VM::VM1,"?Org Name?",false }, + {0x0053,0x0003,"3Z_IMAGE_IMPORT_CLIENT_INFO",VR::LO,VM::VM1,"?Software Version?",false }, + {0x0053,0x0004,"3Z_IMAGE_IMPORT_CLIENT_INFO",VR::LO,VM::VM1,"?ID?",false }, + {0x0053,0x0005,"3Z_IMAGE_IMPORT_CLIENT_INFO",VR::LO,VM::VM1,"?IP Address?",false }, + {0x0053,0x0006,"3Z_IMAGE_IMPORT_CLIENT_INFO",VR::LO,VM::VM1,"?AE Title?",false }, + {0x0055,0x0001,"3Z_IMAGE_IMPORT_GENERAL_HIST",VR::LO,VM::VM1_n,"Copy of Specific Character Set (0008,0005)",false }, + {0x0055,0x0003,"3Z_IMAGE_IMPORT_GENERAL_HIST",VR::LO,VM::VM3,"Copy of Study Instance UID (0020,000d)",false }, + {0x0055,0x0004,"3Z_IMAGE_IMPORT_GENERAL_HIST",VR::LO,VM::VM3,"Copy of Series Instance UID (0020,000e)",false }, + {0x0055,0x0005,"3Z_IMAGE_IMPORT_GENERAL_HIST",VR::LO,VM::VM3,"Copy of SOP Instance UID (0008,0018)",false }, + {0x0055,0x0006,"3Z_IMAGE_IMPORT_GENERAL_HIST",VR::LO,VM::VM3,"Copy of Patient ID (0010,0010)",false }, + {0x0055,0x0007,"3Z_IMAGE_IMPORT_GENERAL_HIST",VR::LO,VM::VM3,"Copy of Patient's Name (0010,0010)",false }, + {0x0055,0x0008,"3Z_IMAGE_IMPORT_GENERAL_HIST",VR::LO,VM::VM3,"Copy of Patient's Birth Date (0010,1030)",false }, + {0x0055,0x0009,"3Z_IMAGE_IMPORT_GENERAL_HIST",VR::LO,VM::VM3,"Copy of Patient's Sex (0010,0040)",false }, + {0x0055,0x0012,"3Z_IMAGE_IMPORT_GENERAL_HIST",VR::LO,VM::VM3,"Copy of Study Description (0008,1030)",false }, + {0x0055,0x0013,"3Z_IMAGE_IMPORT_GENERAL_HIST",VR::LO,VM::VM3,"Copy of Accession Number (0008,0050)",false }, + {0x0029,0x0000,"1.2.840.113663.1",VR::US,VM::VM1,"?",false }, + {0x0029,0x0001,"1.2.840.113663.1",VR::US,VM::VM1,"?",false }, + {0x0019,0x0010,"1.2.840.113681",VR::ST,VM::VM1,"CR Image Params Common",false }, + {0x0019,0x0011,"1.2.840.113681",VR::ST,VM::VM1,"CR Image IP Params Single",false }, + {0x0019,0x0012,"1.2.840.113681",VR::ST,VM::VM1,"CR Image IP Params Left",false }, + {0x0019,0x0013,"1.2.840.113681",VR::ST,VM::VM1,"CR Image IP Params Right",false }, + {0x0087,0x0010,"1.2.840.113708.794.1.1.2.0",VR::CS,VM::VM1,"Media Type",false }, + {0x0087,0x0020,"1.2.840.113708.794.1.1.2.0",VR::CS,VM::VM1,"Media Location",false }, + {0x0087,0x0030,"1.2.840.113708.794.1.1.2.0",VR::ST,VM::VM1,"Storage File ID",false }, + {0x0087,0x0040,"1.2.840.113708.794.1.1.2.0",VR::DS,VM::VM1,"Study or Image Size in MB",false }, + {0x0087,0x0050,"1.2.840.113708.794.1.1.2.0",VR::IS,VM::VM1,"Estimated Retrieve Time",false }, + {0x0029,0x0020,"2.16.840.1.114059.1.1.6.1.50.1",VR::LT,VM::VM1,"Description",false }, + {0x0029,0x0021,"2.16.840.1.114059.1.1.6.1.50.1",VR::ST,VM::VM1,"Orientation",false }, + {0x0029,0x0022,"2.16.840.1.114059.1.1.6.1.50.1",VR::ST,VM::VM1,"Parameter 1",false }, + {0x0029,0x0023,"2.16.840.1.114059.1.1.6.1.50.1",VR::ST,VM::VM1,"Parameter 2",false }, + {0x0029,0x0024,"2.16.840.1.114059.1.1.6.1.50.1",VR::LO,VM::VM1,"Teeth",false }, + {0x0029,0x0025,"2.16.840.1.114059.1.1.6.1.50.1",VR::LO,VM::VM1,"Jaw",false }, + {0x0029,0x0026,"2.16.840.1.114059.1.1.6.1.50.1",VR::LO,VM::VM1,"Quadrant",false }, + {0x0029,0x0027,"2.16.840.1.114059.1.1.6.1.50.1",VR::LO,VM::VM1,"CRC",false }, + {0x3711,0x0001,"A.L.I. Technologies, Inc.",VR::LO,VM::VM1,"Filename",false }, + {0x3711,0x0002,"A.L.I. Technologies, Inc.",VR::OB,VM::VM1,"Data Blob of a Visit",false }, + {0x3711,0x0003,"A.L.I. Technologies, Inc.",VR::US,VM::VM1,"Revision Number",false }, + {0x3711,0x0004,"A.L.I. Technologies, Inc.",VR::UL,VM::VM1,"Unix Timestamp",false }, + {0x3711,0x0005,"A.L.I. Technologies, Inc.",VR::IS,VM::VM1,"Bag ID",false }, + {0x3711,0x000c,"A.L.I. Technologies, Inc.",VR::UI,VM::VM1,"Original Study UID",false }, + {0x3711,0x000d,"A.L.I. Technologies, Inc.",VR::US,VM::VM1,"Overlay Grayscale Value",false }, + {0x3711,0x000e,"A.L.I. Technologies, Inc.",VR::CS,VM::VM1,"Anonymization Status",false }, + {0x0009,0x0000,"ACUSON",VR::IS,VM::VM1,"?",false }, + {0x0009,0x0001,"ACUSON",VR::IS,VM::VM1,"?",false }, + {0x0009,0x0002,"ACUSON",VR::UN,VM::VM1,"?",false }, + {0x0009,0x0003,"ACUSON",VR::UN,VM::VM1,"?",false }, + {0x0009,0x0004,"ACUSON",VR::UN,VM::VM1,"?",false }, + {0x0009,0x0005,"ACUSON",VR::UN,VM::VM1,"?",false }, + {0x0009,0x0006,"ACUSON",VR::UN,VM::VM1,"?",false }, + {0x0009,0x0007,"ACUSON",VR::UN,VM::VM1,"?",false }, + {0x0009,0x0008,"ACUSON",VR::LT,VM::VM1,"?",false }, + {0x0009,0x0009,"ACUSON",VR::LT,VM::VM1,"?",false }, + {0x0009,0x000a,"ACUSON",VR::IS,VM::VM1,"?",false }, + {0x0009,0x000b,"ACUSON",VR::IS,VM::VM1,"?",false }, + {0x0009,0x000c,"ACUSON",VR::IS,VM::VM1,"?",false }, + {0x0009,0x000d,"ACUSON",VR::IS,VM::VM1,"?",false }, + {0x0009,0x000e,"ACUSON",VR::IS,VM::VM1,"?",false }, + {0x0009,0x000f,"ACUSON",VR::UN,VM::VM1,"?",false }, + {0x0009,0x0010,"ACUSON",VR::IS,VM::VM1,"?",false }, + {0x0009,0x0011,"ACUSON",VR::UN,VM::VM1,"?",false }, + {0x0009,0x0012,"ACUSON",VR::IS,VM::VM1,"?",false }, + {0x0009,0x0013,"ACUSON",VR::IS,VM::VM1,"?",false }, + {0x0009,0x0014,"ACUSON",VR::LT,VM::VM1,"?",false }, + {0x0009,0x0015,"ACUSON",VR::UN,VM::VM1,"?",false }, + {0x7fdf,0x0000,"ACUSON: 1.2.840.11386.1.0",VR::IS,VM::VM1,"Lossy Compression Ratio",false }, + {0x7fdf,0x0001,"ACUSON: 1.2.840.11386.1.0",VR::US,VM::VM1,"Image Format",false }, + {0x7fdf,0x0002,"ACUSON: 1.2.840.11386.1.0",VR::US,VM::VM1,"Acuson Region Type",false }, + {0x7fdf,0x000b,"ACUSON: 1.2.840.11386.1.0",VR::UL,VM::VM1,"Acuson Image Apex X",false }, + {0x7fdf,0x000c,"ACUSON: 1.2.840.11386.1.0",VR::UL,VM::VM1,"Acuson Image Apex Y",false }, + {0x7fdf,0x000d,"ACUSON: 1.2.840.11386.1.0",VR::IS,VM::VM1,"B-Color-On Flag",false }, + {0x0009,0x0020,"ACUSON:1.2.840.113680.1.0:0921",VR::UN,VM::VM1,"View Name",false }, + {0x0009,0x002a,"ACUSON:1.2.840.113680.1.0:0921",VR::UN,VM::VM1,"View List",false }, + {0x7fdf,0x0000,"ACUSON:1.2.840.113680.1.0:7f10",VR::IS,VM::VM1,"Lossy Compression Ratio",false }, + {0x7fdf,0x0001,"ACUSON:1.2.840.113680.1.0:7f10",VR::US,VM::VM1,"Image Format",false }, + {0x7fdf,0x0002,"ACUSON:1.2.840.113680.1.0:7f10",VR::US,VM::VM1,"Acuson Region Type",false }, + {0x7fdf,0x000b,"ACUSON:1.2.840.113680.1.0:7f10",VR::UL,VM::VM1,"Acuson Image Apex X",false }, + {0x7fdf,0x000c,"ACUSON:1.2.840.113680.1.0:7f10",VR::UL,VM::VM1,"Acuson Image Apex Y",false }, + {0x7fdf,0x000d,"ACUSON:1.2.840.113680.1.0:7f10",VR::IS,VM::VM1,"B-Color-On Flag",false }, + {0x7fdf,0x000e,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"Acuson Mechanical Apex X",false }, + {0x7fdf,0x000f,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"Acuson Mechanical Apex Y",false }, + {0x7fdf,0x0010,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"Acquisition Type:",false }, + {0x7fdf,0x0018,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"Transformation Matrix Sequence",false }, + {0x7fdf,0x0020,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"Left angle",false }, + {0x7fdf,0x0022,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"Right angle",false }, + {0x7fdf,0x0024,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"Color Map Family",false }, + {0x7fdf,0x0025,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"Full Colormap.",false }, + {0x7fdf,0x0026,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"Color Invert",false }, + {0x7fdf,0x0027,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"Color Baseline",false }, + {0x7fdf,0x0028,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"CD Color Mix Points X1",false }, + {0x7fdf,0x0029,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"CD Color Mix Points Y1",false }, + {0x7fdf,0x002a,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"CD Color Mix Points X2",false }, + {0x7fdf,0x002b,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"CD Color Mix Points Y2",false }, + {0x7fdf,0x002c,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"Color Accent",false }, + {0x7fdf,0x0030,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"Persistence SQ",false }, + {0x7fdf,0x0031,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"Persistence Mode",false }, + {0x7fdf,0x0032,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"Persistence Coefficient Mode",false }, + {0x7fdf,0x0033,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"Alpha coefficient",false }, + {0x7fdf,0x0034,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"Gamma coefficient",false }, + {0x7fdf,0x0035,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"Persistence Time Flag",false }, + {0x7fdf,0x0036,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"Persistence adaptive flag",false }, + {0x7fdf,0x0037,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"Persistence Frame Rate",false }, + {0x7fdf,0x0038,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"Persistence ID",false }, + {0x7fdf,0x0040,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"Observation Date Time SQ",false }, + {0x7fdf,0x0050,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"Capture Type Name",false }, + {0x7fdf,0x0052,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"Capture Type Number",false }, + {0x7fdf,0x0054,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"Number of Capture Types",false }, + {0x7fdf,0x0060,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"CD Steering Angle",false }, + {0x7fdf,0x0061,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"CD PRI",false }, + {0x7fdf,0x0062,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"CD Dynamic Range",false }, + {0x7fdf,0x0063,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"CD Velocity Scale Min",false }, + {0x7fdf,0x0064,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"CD Velocity Scale Max",false }, + {0x7fdf,0x0065,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"CD Color Mode",false }, + {0x7fdf,0x0066,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"CD Frequency",false }, + {0x7fdf,0x0067,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"CD Balance",false }, + {0x7fdf,0x0068,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"CD Delta",false }, + {0x7fdf,0x0069,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"CD Pan Box Min X0",false }, + {0x7fdf,0x006a,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"CD Pan Box Min Y0",false }, + {0x7fdf,0x006b,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"CD Pan Box Min X1",false }, + {0x7fdf,0x006c,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"CD Pan Box Min Y1",false }, + {0x7fdf,0x006d,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"CPS Map Type",false }, + {0x7fdf,0x006e,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"CPS Map Data",false }, + {0x7fdf,0x006f,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"CPS Balance Setting",false }, + {0x7fdf,0x0070,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"3DCard Step Angle",false }, + {0x7fdf,0x0071,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"3DCard Xdcr Angle",false }, + {0x7fdf,0x0072,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"B-mode Frequency",false }, + {0x7fdf,0x0073,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"B-mode Dynamic Range",false }, + {0x7fdf,0x0074,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"B-mode Frame Rate",false }, + {0x7fdf,0x0075,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"B-mode Space Time",false }, + {0x7fdf,0x0076,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"B-mode Persistence",false }, + {0x7fdf,0x0077,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"B-mode Display Depth Start",false }, + {0x7fdf,0x0078,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"B-mode Display Depth End",false }, + {0x7fdf,0x0079,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"B-mode Res Mode",false }, + {0x7fdf,0x007a,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"B-mode Preset Application",false }, + {0x7fdf,0x007b,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"Image Spec Name",false }, + {0x7fdf,0x007c,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"B Preset Image Look",false }, + {0x7fdf,0x007d,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"B-mode Post Processing",false }, + {0x7fdf,0x007e,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"B Edge",false }, + {0x7fdf,0x007f,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"B Delta",false }, + {0x7fdf,0x0080,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"B-mode 1D Post Processing Curve",false }, + {0x7fdf,0x0081,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"B-mode Delta (ECRI) Map Diagonal",false }, + {0x7fdf,0x0082,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"Bytes Per Timestamp",false }, + {0x7fdf,0x0083,"ACUSON:1.2.840.113680.1.0:7f10",VR::UL,VM::VM1,"Microseconds in unit timestamp",false }, + {0x7fdf,0x0084,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"Start Stopwatch Timestamp",false }, + {0x7fdf,0x0085,"ACUSON:1.2.840.113680.1.0:7f10",VR::OB,VM::VM1,"Acoustic Frame Timestamp",false }, + {0x7fdf,0x0086,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"R-Wave Timestamp",false }, + {0x7fdf,0x0087,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"Last Destruction Timestamp",false }, + {0x7fdf,0x0088,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"Pixels Per Second",false }, + {0x7fdf,0x0089,"ACUSON:1.2.840.113680.1.0:7f10",VR::OB,VM::VM1,"ECG Reference Timestamp",false }, + {0x7fdf,0x008a,"ACUSON:1.2.840.113680.1.0:7f10",VR::FD,VM::VM1,"ECG Sampling Interval (milliseconds)",false }, + {0x7fdf,0x008b,"ACUSON:1.2.840.113680.1.0:7f10",VR::UL,VM::VM1,"ECG Sample Count",false }, + {0x7fdf,0x008c,"ACUSON:1.2.840.113680.1.0:7f10",VR::UL,VM::VM1,"ECG Sample Size",false }, + {0x7fdf,0x008d,"ACUSON:1.2.840.113680.1.0:7f10",VR::OB,VM::VM1,"ECG Data Value",false }, + {0x7fdf,0x008e,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"Contrast/Active Image Indicator",false }, + {0x7fdf,0x008f,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"Live Dual Mode Indicator",false }, + {0x7fdf,0x0090,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"3DCard Clipset ID",false }, + {0x7fdf,0x0091,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"3DCard HRWave Min",false }, + {0x7fdf,0x0092,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"3DCard HRWave Max",false }, + {0x7fdf,0x0093,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"Perspective Capture Type",false }, + {0x7fdf,0x00f1,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"Trigger Mask.",false }, + {0x7fdf,0x00f2,"ACUSON:1.2.840.113680.1.0:7f10",VR::LO,VM::VM1,"Study Directory",false }, + {0x7fdf,0x00f3,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"Last Modify Date",false }, + {0x7fdf,0x00f4,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"Last Modify Time",false }, + {0x7fdf,0x00f5,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"Teaching Study",false }, + {0x7fdf,0x00f6,"ACUSON:1.2.840.113680.1.0:7f10",VR::UN,VM::VM1,"Series Base UID",false }, + {0x7fdf,0x0000,"ACUSON:1.2.840.113680.1.0:7ffe",VR::OB,VM::VM1,"Data Padding",false }, + {0x0019,0x0002,"ADAC_IMG",VR::IS,VM::VM1,"Ver200 ADAC Pegasys File Size",false }, + {0x0019,0x0010,"ADAC_IMG",VR::LO,VM::VM2,"ADAC Header Signature",false }, + {0x0019,0x0011,"ADAC_IMG",VR::US,VM::VM1,"Number of ADAC Headers",false }, + {0x0019,0x0012,"ADAC_IMG",VR::IS,VM::VM1_n,"ADAC Header/Image Sizes",false }, + {0x0019,0x0020,"ADAC_IMG",VR::OB,VM::VM1,"ADAC Pegasys Headers",false }, + {0x0019,0x0021,"ADAC_IMG",VR::US,VM::VM1,"Ver200 Number of ADAC Headers",false }, + {0x0019,0x0041,"ADAC_IMG",VR::IS,VM::VM1_n,"Ver200 ADAC Header/Image Size",false }, + {0x0019,0x0061,"ADAC_IMG",VR::OB,VM::VM1,"Ver200 ADAC Pegasys Headers",false }, + {0x7043,0x0000,"ADAC_IMG",VR::SH,VM::VM1,"Cardiac Stress State",false }, + {0x7043,0x0010,"ADAC_IMG",VR::LO,VM::VM1,"Philips NM Private Group",false }, + {0x0003,0x0000,"AEGIS_DICOM_2.00",VR::US,VM::VM1_n,"?",false }, + {0x0005,0x0000,"AEGIS_DICOM_2.00",VR::US,VM::VM1_n,"?",false }, + {0x0009,0x0000,"AEGIS_DICOM_2.00",VR::US,VM::VM1_n,"?",false }, + {0x0019,0x0000,"AEGIS_DICOM_2.00",VR::US,VM::VM1_n,"?",false }, + {0x0029,0x0000,"AEGIS_DICOM_2.00",VR::US,VM::VM1_n,"?",false }, + {0x1369,0x0000,"AEGIS_DICOM_2.00",VR::US,VM::VM1_n,"?",false }, + {0x0009,0x0010,"AGFA",VR::LO,VM::VM1,"?",false }, + {0x0009,0x0011,"AGFA",VR::LO,VM::VM1,"?",false }, + {0x0009,0x0013,"AGFA",VR::LO,VM::VM1,"?",false }, + {0x0009,0x0014,"AGFA",VR::LO,VM::VM1,"?",false }, + {0x0009,0x0015,"AGFA",VR::LO,VM::VM1,"?",false }, + {0x0019,0x0010,"AGFA",VR::SH,VM::VM1,"Private Identification Code",false }, + {0x0019,0x0011,"AGFA",VR::LO,VM::VM3,"Identification Data (Note 2)",false }, + {0x0019,0x0013,"AGFA",VR::LO,VM::VM1,"Sensitometry Name",false }, + {0x0019,0x0014,"AGFA",VR::ST,VM::VM3,"Window/Level List (Note 3)",false }, + {0x0019,0x0015,"AGFA",VR::LO,VM::VM1,"Dose Monitoring List",false }, + {0x0019,0x0016,"AGFA",VR::LO,VM::VM3,"Other Info (Note 5)",false }, + {0x0019,0x001a,"AGFA",VR::LO,VM::VM1,"Clipped Exposure Deviation",false }, + {0x0019,0x001b,"AGFA",VR::LO,VM::VM1,"Logarithmic PLT Full Scale",false }, + {0x0019,0x0060,"AGFA",VR::US,VM::VM1,"Total number of series",false }, + {0x0019,0x0061,"AGFA",VR::SH,VM::VM1,"Session Number",false }, + {0x0019,0x0062,"AGFA",VR::SH,VM::VM1,"ID Station name",false }, + {0x0019,0x0065,"AGFA",VR::US,VM::VM1,"Number of images in study to be transmitted (only sent with autoverify: on)",false }, + {0x0019,0x0070,"AGFA",VR::US,VM::VM1,"Total number of images",false }, + {0x0019,0x0080,"AGFA",VR::ST,VM::VM1,"Geometrical Transformations",false }, + {0x0019,0x0081,"AGFA",VR::ST,VM::VM1,"Roam Origin",false }, + {0x0019,0x0082,"AGFA",VR::US,VM::VM1,"Zoom factor",false }, + {0x0019,0x0093,"AGFA",VR::CS,VM::VM1,"Status",false }, + {0x0031,0x0000,"AGFA PACS Archive Mirroring 1.0",VR::CS,VM::VM1,"?",false }, + {0x0031,0x0001,"AGFA PACS Archive Mirroring 1.0",VR::UL,VM::VM1,"?",false }, + {0x0071,0x0018,"AGFA-AG_HPState",VR::SQ,VM::VM1,"?",false }, + {0x0071,0x0019,"AGFA-AG_HPState",VR::SQ,VM::VM1,"?",false }, + {0x0071,0x001a,"AGFA-AG_HPState",VR::SQ,VM::VM1,"?",false }, + {0x0071,0x001c,"AGFA-AG_HPState",VR::SQ,VM::VM1,"?",false }, + {0x0071,0x001e,"AGFA-AG_HPState",VR::SQ,VM::VM1,"?",false }, + {0x0071,0x0020,"AGFA-AG_HPState",VR::FL,VM::VM1_n,"?",false }, + {0x0071,0x0021,"AGFA-AG_HPState",VR::FD,VM::VM1_n,"?",false }, + {0x0071,0x0022,"AGFA-AG_HPState",VR::FD,VM::VM1_n,"?",false }, + {0x0071,0x0023,"AGFA-AG_HPState",VR::FD,VM::VM1_n,"?",false }, + {0x0071,0x0024,"AGFA-AG_HPState",VR::FD,VM::VM1,"?",false }, + {0x0073,0x0023,"AGFA-AG_HPState",VR::SH,VM::VM1,"?",false }, + {0x0073,0x0024,"AGFA-AG_HPState",VR::SQ,VM::VM1,"?",false }, + {0x0073,0x0028,"AGFA-AG_HPState",VR::SQ,VM::VM1,"?",false }, + {0x0073,0x0080,"AGFA-AG_HPState",VR::FL,VM::VM1,"?",false }, + {0x0075,0x0010,"AGFA-AG_HPState",VR::LO,VM::VM1,"?",false }, + {0x0087,0x0001,"AGFA-AG_HPState",VR::LO,VM::VM1,"?",false }, + {0x0087,0x0002,"AGFA-AG_HPState",VR::LO,VM::VM1,"?",false }, + {0x0019,0x0005,"AGFA_ADC_Compact",VR::ST,VM::VM1,"Data stream from cassette",false }, + {0x0019,0x0010,"AGFA_ADC_Compact",VR::LO,VM::VM1,"Private Identification Code",false }, + {0x0019,0x0030,"AGFA_ADC_Compact",VR::ST,VM::VM1,"Set of destination types",false }, + {0x0019,0x0040,"AGFA_ADC_Compact",VR::ST,VM::VM1,"Set of destination Ids",false }, + {0x0019,0x0050,"AGFA_ADC_Compact",VR::ST,VM::VM1,"Set of processing codes",false }, + {0x0019,0x0060,"AGFA_ADC_Compact",VR::US,VM::VM1,"Number of series in study",false }, + {0x0019,0x0061,"AGFA_ADC_Compact",VR::US,VM::VM1,"Session Number",false }, + {0x0019,0x0062,"AGFA_ADC_Compact",VR::SH,VM::VM1,"ID station name",false }, + {0x0019,0x0070,"AGFA_ADC_Compact",VR::US,VM::VM1,"Number of images in series",false }, + {0x0019,0x0071,"AGFA_ADC_Compact",VR::US,VM::VM1,"Break condition",false }, + {0x0019,0x0072,"AGFA_ADC_Compact",VR::US,VM::VM1,"Wait (or Hold) flag",false }, + {0x0019,0x0073,"AGFA_ADC_Compact",VR::US,VM::VM1,"ScanRes flag",false }, + {0x0019,0x0074,"AGFA_ADC_Compact",VR::SH,VM::VM1,"Operation code",false }, + {0x0019,0x0095,"AGFA_ADC_Compact",VR::CS,VM::VM1,"Image quality",false }, + {0x0009,0x0000,"ALOKA:1.2.392.200039.103.2",VR::SH,VM::VM1,"?",false }, + {0x0009,0x0004,"ALOKA:1.2.392.200039.103.2",VR::US,VM::VM1_n,"?",false }, + {0x0009,0x0006,"ALOKA:1.2.392.200039.103.2",VR::US,VM::VM1_n,"?",false }, + {0x0009,0x000a,"ALOKA:1.2.392.200039.103.2",VR::SH,VM::VM1,"?",false }, + {0x0009,0x0020,"ALOKA:1.2.392.200039.103.2",VR::CS,VM::VM1,"?",false }, + {0x0009,0x0022,"ALOKA:1.2.392.200039.103.2",VR::CS,VM::VM1,"?",false }, + {0x0009,0x0024,"ALOKA:1.2.392.200039.103.2",VR::CS,VM::VM1,"?",false }, + {0x0009,0x0026,"ALOKA:1.2.392.200039.103.2",VR::IS,VM::VM1,"?",false }, + {0x0009,0x0028,"ALOKA:1.2.392.200039.103.2",VR::IS,VM::VM1,"?",false }, + {0x0009,0x002a,"ALOKA:1.2.392.200039.103.2",VR::DS,VM::VM1,"?",false }, + {0x0009,0x0030,"ALOKA:1.2.392.200039.103.2",VR::FD,VM::VM1,"?",false }, + {0x0009,0x0032,"ALOKA:1.2.392.200039.103.2",VR::DS,VM::VM1,"?",false }, + {0x0009,0x0034,"ALOKA:1.2.392.200039.103.2",VR::CS,VM::VM1,"?",false }, + {0x0019,0x0008,"ALOKA:1.2.392.200039.103.2",VR::FD,VM::VM1,"?",false }, + {0x0019,0x000c,"ALOKA:1.2.392.200039.103.2",VR::CS,VM::VM1,"?",false }, + {0x0019,0x000e,"ALOKA:1.2.392.200039.103.2",VR::DS,VM::VM1,"?",false }, + {0x0019,0x0018,"ALOKA:1.2.392.200039.103.2",VR::SL,VM::VM1,"?",false }, + {0x0019,0x001a,"ALOKA:1.2.392.200039.103.2",VR::SL,VM::VM1,"?",false }, + {0x0019,0x0040,"ALOKA:1.2.392.200039.103.2",VR::SS,VM::VM1,"?",false }, + {0x0019,0x0046,"ALOKA:1.2.392.200039.103.2",VR::US,VM::VM1,"?",false }, + {0x0019,0x0050,"ALOKA:1.2.392.200039.103.2",VR::SL,VM::VM1,"?",false }, + {0x0019,0x0052,"ALOKA:1.2.392.200039.103.2",VR::DS,VM::VM1,"?",false }, + {0x0019,0x0054,"ALOKA:1.2.392.200039.103.2",VR::DS,VM::VM1,"?",false }, + {0x0019,0x0056,"ALOKA:1.2.392.200039.103.2",VR::FD,VM::VM1,"?",false }, + {0x3101,0x0010,"AMI Annotations_01",VR::SQ,VM::VM1,"AMI Annotation Sequence (RET)",false }, + {0x3101,0x0020,"AMI Annotations_02",VR::SQ,VM::VM1,"AMI Annotation Sequence (RET)",false }, + {0x3107,0x00a0,"AMI ImageContextExt_01",VR::CS,VM::VM1,"AMI Window Function (RET)",false }, + {0x3107,0x00b0,"AMI ImageContextExt_01",VR::DS,VM::VM1,"AMI Window Slope (RET)",false }, + {0x3109,0x0010,"AMI ImageContext_01",VR::CS,VM::VM1,"AMI Window Invert (RET)",false }, + {0x3109,0x0020,"AMI ImageContext_01",VR::IS,VM::VM1,"AMI Window Center (RET)",false }, + {0x3109,0x0030,"AMI ImageContext_01",VR::IS,VM::VM1,"AMI Window Widith (RET)",false }, + {0x3109,0x0040,"AMI ImageContext_01",VR::CS,VM::VM1,"AMI Pixel Aspect Ratio Swap (RET)",false }, + {0x3109,0x0050,"AMI ImageContext_01",VR::CS,VM::VM1,"AMI Enable Averaging (RET)",false }, + {0x3109,0x0060,"AMI ImageContext_01",VR::CS,VM::VM1,"AMI Quality (RET)",false }, + {0x3109,0x0070,"AMI ImageContext_01",VR::CS,VM::VM1,"AMI Viewport Annotation Level (RET)",false }, + {0x3109,0x0080,"AMI ImageContext_01",VR::CS,VM::VM1,"AMI Show Image Annotation (RET)",false }, + {0x3109,0x0090,"AMI ImageContext_01",VR::CS,VM::VM1,"AMI Show Image Overlay (RET)",false }, + {0x3107,0x0010,"AMI ImageTransform_01",VR::DS,VM::VM1,"AMI Transformation Matrix (RET)",false }, + {0x3107,0x0020,"AMI ImageTransform_01",VR::DS,VM::VM1,"AMI Center Offset (RET)",false }, + {0x3107,0x0030,"AMI ImageTransform_01",VR::DS,VM::VM1,"AMI Magnification (RET)",false }, + {0x3107,0x0040,"AMI ImageTransform_01",VR::CS,VM::VM1,"AMI Magnification Type (RET)",false }, + {0x3107,0x0050,"AMI ImageTransform_01",VR::DS,VM::VM1,"AMI Displayed Area (RET)",false }, + {0x3107,0x0060,"AMI ImageTransform_01",VR::DS,VM::VM1,"AMI Calibration Factor (RET)",false }, + {0x3105,0x0010,"AMI Sequence AnnotElements_01",VR::DS,VM::VM1,"AMI Annotation Element Position",false }, + {0x3105,0x0020,"AMI Sequence AnnotElements_01",VR::LT,VM::VM1,"AMI Annotation Element Text",false }, + {0x3103,0x0010,"AMI Sequence Annotations_01",VR::CS,VM::VM1,"AMI Annotation Sequence (RET)",false }, + {0x3103,0x0020,"AMI Sequence Annotations_01",VR::UI,VM::VM1,"AMI Annotation UID (RET)",false }, + {0x3103,0x0030,"AMI Sequence Annotations_01",VR::US,VM::VM1,"AMI Annotation Color (RET)",false }, + {0x3103,0x0040,"AMI Sequence Annotations_01",VR::FD,VM::VM1,"FontSize",false }, + {0x3103,0x0050,"AMI Sequence Annotations_01",VR::CS,VM::VM1,"AMI Annotation Line Style (RET)",false }, + {0x3103,0x0060,"AMI Sequence Annotations_01",VR::SQ,VM::VM1,"AMI Annotation Elements (RET)",false }, + {0x3103,0x0070,"AMI Sequence Annotations_01",VR::SH,VM::VM1,"AMI Annotation Label (RET)",false }, + {0x3103,0x0080,"AMI Sequence Annotations_01",VR::PN,VM::VM1,"AMI Annotation Creator (RET)",false }, + {0x3103,0x0090,"AMI Sequence Annotations_01",VR::PN,VM::VM1,"AMI Annotation Modifiers (RET)",false }, + {0x3103,0x00a0,"AMI Sequence Annotations_01",VR::DA,VM::VM1,"AMI Annotation Creation Date (RET)",false }, + {0x3103,0x00b0,"AMI Sequence Annotations_01",VR::TM,VM::VM1,"AMI Annotation Creation Time (RET)",false }, + {0x3103,0x00c0,"AMI Sequence Annotations_01",VR::DA,VM::VM1,"AMI Annotation Modification Dates (RET)",false }, + {0x3103,0x00d0,"AMI Sequence Annotations_01",VR::TM,VM::VM1,"AMI Annotation Mofification Times (RET)",false }, + {0x3103,0x00e0,"AMI Sequence Annotations_01",VR::US,VM::VM1,"AMI Annotation Frame Number (RET)",false }, + {0x3103,0x0010,"AMI Sequence Annotations_02",VR::CS,VM::VM1,"AMI Annotation Sequence (RET)",false }, + {0x3103,0x0020,"AMI Sequence Annotations_02",VR::UI,VM::VM1,"AMI Annotation UID (RET)",false }, + {0x3103,0x0030,"AMI Sequence Annotations_02",VR::US,VM::VM1,"AMI Annotation Color (RET)",false }, + {0x3103,0x0050,"AMI Sequence Annotations_02",VR::CS,VM::VM1,"AMI Annotation Line Style (RET)",false }, + {0x3103,0x0060,"AMI Sequence Annotations_02",VR::SQ,VM::VM1,"AMI Annotation Elements (RET)",false }, + {0x3103,0x0070,"AMI Sequence Annotations_02",VR::SH,VM::VM1,"AMI Annotation Label (RET)",false }, + {0x3103,0x0080,"AMI Sequence Annotations_02",VR::PN,VM::VM1,"AMI Annotation Creator (RET)",false }, + {0x3103,0x0090,"AMI Sequence Annotations_02",VR::PN,VM::VM1,"AMI Annotation Modifiers (RET)",false }, + {0x3103,0x00a0,"AMI Sequence Annotations_02",VR::DA,VM::VM1,"AMI Annotation Creation Date (RET)",false }, + {0x3103,0x00b0,"AMI Sequence Annotations_02",VR::TM,VM::VM1,"AMI Annotation Creation Time (RET)",false }, + {0x3103,0x00c0,"AMI Sequence Annotations_02",VR::DA,VM::VM1,"AMI Annotation Modification Dates (RET)",false }, + {0x3103,0x00d0,"AMI Sequence Annotations_02",VR::TM,VM::VM1,"AMI Annotation Modification Times (RET)",false }, + {0x3103,0x00e0,"AMI Sequence Annotations_02",VR::US,VM::VM1,"AMI Annotation Frame Number (RET)",false }, + {0x3111,0x0001,"AMI StudyExtensions_01",VR::UL,VM::VM1,"AMI Last Released Annot Label (RET)",false }, + {0x0023,0x0001,"AMICAS0",VR::UI,VM::VM1,"",false }, + {0x0023,0x0008,"AMICAS0",VR::US,VM::VM1,"",false }, + {0x0023,0x0010,"AMICAS0",VR::US,VM::VM1,"",false }, + {0x0023,0x0016,"AMICAS0",VR::SL,VM::VM1,"",false }, + {0x0027,0x0010,"APEX_PRIVATE",VR::LO,VM::VM1,"Private Creator",false }, + {0x0027,0x0011,"APEX_PRIVATE",VR::DS,VM::VM1,"Bed Position",false }, + {0x0009,0x0000,"ATL HDI V1.0",VR::UN,VM::VM1,"Private",false }, + {0x0009,0x0010,"ATL HDI V1.0",VR::UN,VM::VM1,"Private",false }, + {0x0009,0x0020,"ATL HDI V1.0",VR::UN,VM::VM1,"Private",false }, + {0x0009,0x0030,"ATL HDI V1.0",VR::UN,VM::VM1,"Private",false }, + {0x0009,0x0040,"ATL HDI V1.0",VR::UN,VM::VM1,"Private",false }, + {0x0009,0x0050,"ATL HDI V1.0",VR::UN,VM::VM1,"Private",false }, + {0x0009,0x0060,"ATL HDI V1.0",VR::UN,VM::VM1,"Private",false }, + {0x0009,0x0070,"ATL HDI V1.0",VR::UN,VM::VM1,"Private",false }, + {0x0009,0x0080,"ATL HDI V1.0",VR::UN,VM::VM1,"Private",false }, + {0x0009,0x0090,"ATL HDI V1.0",VR::UN,VM::VM1,"Private",false }, + {0x0009,0x0091,"ATL HDI V1.0",VR::UN,VM::VM1,"Private",false }, + {0x0029,0x0030,"ATL HDI V1.0",VR::UN,VM::VM1,"Loop Mode",false }, + {0x0029,0x0031,"ATL HDI V1.0",VR::UN,VM::VM1,"Trigger mode",false }, + {0x0029,0x0032,"ATL HDI V1.0",VR::UN,VM::VM1,"Number of Loops",false }, + {0x0029,0x0033,"ATL HDI V1.0",VR::UN,VM::VM1,"Loop Indexes",false }, + {0x0029,0x0034,"ATL HDI V1.0",VR::UN,VM::VM1,"Loop Heart Rates",false }, + {0x0029,0x0035,"ATL HDI V1.0",VR::UN,VM::VM1,"Medications",false }, + {0x0029,0x0030,"ATL PRIVATE TAGS",VR::UL,VM::VM1,"Loop Mode",false }, + {0x0029,0x0031,"ATL PRIVATE TAGS",VR::UL,VM::VM1,"Trigger mode",false }, + {0x0029,0x0032,"ATL PRIVATE TAGS",VR::UL,VM::VM1,"Number of Loops",false }, + {0x0029,0x0033,"ATL PRIVATE TAGS",VR::DS,VM::VM1_n,"Loop Indexes",false }, + {0x0029,0x0034,"ATL PRIVATE TAGS",VR::DS,VM::VM1_n,"Loop Heart Rates",false }, + {0x0029,0x0035,"ATL PRIVATE TAGS",VR::LO,VM::VM1,"Medications",false }, + {0x0009,0x0020,"Acuson X500",VR::UN,VM::VM1,"(a)View Name",false }, + {0x0009,0x002a,"Acuson X500",VR::UN,VM::VM1,"View List",false }, + {0x0011,0x0010,"Acuson X500",VR::UN,VM::VM1,"Siemens Medical",false }, + {0x0011,0x0011,"Acuson X500",VR::UN,VM::VM1,"DIMAQ Software",false }, + {0x0011,0x0020,"Acuson X500",VR::UN,VM::VM1,"Private Data",false }, + {0x0011,0x0021,"Acuson X500",VR::UN,VM::VM1,"Private Data",false }, + {0x0013,0x0010,"Acuson X500",VR::UN,VM::VM1,"Siemens Medical",false }, + {0x0013,0x0011,"Acuson X500",VR::UN,VM::VM1,"DIMAQ Software",false }, + {0x0013,0x0020,"Acuson X500",VR::UN,VM::VM1,"Private Data",false }, + {0x0015,0x0010,"Acuson X500",VR::UN,VM::VM1,"Siemens Medical",false }, + {0x0015,0x0011,"Acuson X500",VR::UN,VM::VM1,"DIMAQ Software",false }, + {0x0015,0x0020,"Acuson X500",VR::UN,VM::VM1,"Private Data",false }, + {0x0017,0x0010,"Acuson X500",VR::UN,VM::VM1,"Siemens Medical",false }, + {0x0017,0x0011,"Acuson X500",VR::UN,VM::VM1,"DIMAQ Software",false }, + {0x0017,0x0020,"Acuson X500",VR::UN,VM::VM1,"Private Data",false }, + {0x0019,0x0020,"Acuson X500",VR::UN,VM::VM1,"Import Structured",false }, + {0x0019,0x0007,"Agfa ADC NX",VR::CS,VM::VM1,"Is Speedclass Free ",false }, + {0x0019,0x0009,"Agfa ADC NX",VR::SQ,VM::VM1,"Collimator shape sequence ",false }, + {0x0019,0x0021,"Agfa ADC NX",VR::FL,VM::VM1,"Calibration Factor ",false }, + {0x0019,0x0028,"Agfa ADC NX",VR::CS,VM::VM1,"Is IPSR enabled",false }, + {0x0019,0x00f5,"Agfa ADC NX",VR::CS,VM::VM1,"Cassette orientation",false }, + {0x0019,0x00f6,"Agfa ADC NX",VR::DS,VM::VM1,"Image plate sensitivity",false }, + {0x0019,0x00f7,"Agfa ADC NX",VR::DS,VM::VM1,"Image plate erasability",false }, + {0x0019,0x00f8,"Agfa ADC NX",VR::IS,VM::VM1,"Breast density percentage",false }, + {0x0019,0x00fa,"Agfa ADC NX",VR::IS,VM::VM1,"Exposure index",false }, + {0x0019,0x00fb,"Agfa ADC NX",VR::FL,VM::VM1,"Deviation index",false }, + {0x0019,0x00fc,"Agfa ADC NX",VR::IS,VM::VM1,"Target exposure index",false }, + {0x0019,0x00fd,"Agfa ADC NX",VR::CS,VM::VM1,"Is overexposed",false }, + {0x0019,0x00fe,"Agfa ADC NX",VR::CS,VM::VM1,"Study Priority ID",false }, + {0x0029,0x0011,"AgilityRuntime",VR::CS,VM::VM1,"?",false }, + {0x0029,0x0012,"AgilityRuntime",VR::US,VM::VM1,"?",false }, + {0x0029,0x0013,"AgilityRuntime",VR::US,VM::VM1,"?",false }, + {0x0029,0x0014,"AgilityRuntime",VR::US,VM::VM1,"?",false }, + {0x0029,0x001f,"AgilityRuntime",VR::US,VM::VM1,"?",false }, + {0x4109,0x0001,"Applicare/Centricity Radiology Web/Version 1.0",VR::SH,VM::VM1,"Mammography Laterality",false }, + {0x4109,0x0002,"Applicare/Centricity Radiology Web/Version 1.0",VR::SH,VM::VM1,"Mammography View Name",false }, + {0x4109,0x0003,"Applicare/Centricity Radiology Web/Version 1.0",VR::SH,VM::VM1,"Mammography View Modifier",false }, + {0x4111,0x0001,"Applicare/Centricity Radiology Web/Version 2.0",VR::CS,VM::VM1,"Secondary Spine Label",false }, + {0x4111,0x0002,"Applicare/Centricity Radiology Web/Version 2.0",VR::IS,VM::VM1,"Additional tags for Presentation State",false }, + {0x4101,0x0001,"Applicare/Print/Version 5.1",VR::UL,VM::VM1," DS + {0x0043,0x006e,"GEMS_PARM_01",VR::SH,VM::VM1,"Auto mA Mode",false }, + {0x0043,0x006f,"GEMS_PARM_01",VR::DS,VM::VM3_4,"Scanner Table Entry (single gradient coil systems only)/Scanner Table Entry + Gradient Coil Selected",false }, + {0x0043,0x0070,"GEMS_PARM_01",VR::LO,VM::VM1,"Paradigm Name",false }, + {0x0043,0x0071,"GEMS_PARM_01",VR::ST,VM::VM1,"Paradigm Description",false }, + {0x0043,0x0072,"GEMS_PARM_01",VR::UI,VM::VM1,"Paradigm UID",false }, + {0x0043,0x0073,"GEMS_PARM_01",VR::US,VM::VM1,"Experiment Type",false }, + {0x0043,0x0074,"GEMS_PARM_01",VR::US,VM::VM1,"#rest volumes",false }, + {0x0043,0x0075,"GEMS_PARM_01",VR::US,VM::VM1,"#active volumes",false }, + {0x0043,0x0076,"GEMS_PARM_01",VR::US,VM::VM1,"#dummy scans",false }, + {0x0043,0x0077,"GEMS_PARM_01",VR::SH,VM::VM1,"Application Name",false }, + {0x0043,0x0078,"GEMS_PARM_01",VR::SH,VM::VM1,"Application Version",false }, + {0x0043,0x0079,"GEMS_PARM_01",VR::US,VM::VM1,"Slices Per Volume",false }, + {0x0043,0x007a,"GEMS_PARM_01",VR::US,VM::VM1,"Expected Time Points",false }, + {0x0043,0x007b,"GEMS_PARM_01",VR::FL,VM::VM1_n,"Regressor Values",false }, + {0x0043,0x007c,"GEMS_PARM_01",VR::FL,VM::VM1,"Delay after slice group",false }, + {0x0043,0x007d,"GEMS_PARM_01",VR::US,VM::VM1,"Recon mode flag word",false }, + {0x0043,0x007e,"GEMS_PARM_01",VR::LO,VM::VM1_n,"PACC specific information",false }, + {0x0043,0x007f,"GEMS_PARM_01",VR::DS,VM::VM1_n,"Reserved",false }, + {0x0043,0x0080,"GEMS_PARM_01",VR::LO,VM::VM1_n,"Coil ID Data",false }, + {0x0043,0x0081,"GEMS_PARM_01",VR::LO,VM::VM1,"GE Coil Name",false }, + {0x0043,0x0082,"GEMS_PARM_01",VR::LO,VM::VM1_n,"System Configuration Information",false }, + {0x0043,0x0083,"GEMS_PARM_01",VR::DS,VM::VM1_2,"Asset R Factors",false }, + {0x0043,0x0084,"GEMS_PARM_01",VR::LO,VM::VM1_n,"Additional Asset Data",false }, + {0x0043,0x0085,"GEMS_PARM_01",VR::UT,VM::VM1,"Debug Data (text format)",false }, + {0x0043,0x0086,"GEMS_PARM_01",VR::OB,VM::VM1,"Debug Data (binary format)",false }, + {0x0043,0x0087,"GEMS_PARM_01",VR::UT,VM::VM1,"Reserved",false }, + {0x0043,0x0088,"GEMS_PARM_01",VR::UI,VM::VM1,"PURE Acquisition Calibration Series UID",false }, + {0x0043,0x0089,"GEMS_PARM_01",VR::LO,VM::VM3,"Governing Body, dB/dt, and SAR definition",false }, + {0x0043,0x008a,"GEMS_PARM_01",VR::CS,VM::VM1,"Private In-Plane Phase Encoding Direction",false }, + {0x0043,0x008b,"GEMS_PARM_01",VR::OB,VM::VM1,"FMRI Binary Data Block",false }, + {0x0043,0x008c,"GEMS_PARM_01",VR::DS,VM::VM6,"Voxel Location",false }, + {0x0043,0x008d,"GEMS_PARM_01",VR::DS,VM::VM7_7n,"SAT Band Locations",false }, + {0x0043,0x008e,"GEMS_PARM_01",VR::DS,VM::VM3,"Spectro Prescan Values",false }, + {0x0043,0x008f,"GEMS_PARM_01",VR::DS,VM::VM3,"Spectro Parameters",false }, + {0x0043,0x0090,"GEMS_PARM_01",VR::LO,VM::VM1_n,"SAR Definition",false }, + {0x0043,0x0091,"GEMS_PARM_01",VR::DS,VM::VM1_n,"SAR value",false }, + {0x0043,0x0092,"GEMS_PARM_01",VR::LO,VM::VM1,"Image Error Text",false }, + {0x0043,0x0093,"GEMS_PARM_01",VR::DS,VM::VM1_n,"Spectro Quantitation Values",false }, + {0x0043,0x0094,"GEMS_PARM_01",VR::DS,VM::VM1_n,"Spectro Ratio Values",false }, + {0x0043,0x0095,"GEMS_PARM_01",VR::LO,VM::VM1,"Prescan Reuse String",false }, + {0x0043,0x0096,"GEMS_PARM_01",VR::CS,VM::VM1,"Content Qualification",false }, + {0x0043,0x0097,"GEMS_PARM_01",VR::LO,VM::VM1_n,"Image Filtering Parameters",false }, + {0x0043,0x0098,"GEMS_PARM_01",VR::UI,VM::VM1,"ASSET Acquisition Calibration Series UID",false }, + {0x0043,0x0099,"GEMS_PARM_01",VR::LO,VM::VM1_n,"Extended Options",false }, + {0x0043,0x009a,"GEMS_PARM_01",VR::IS,VM::VM1,"Rx Stack Identification",false }, + {0x0043,0x009b,"GEMS_PARM_01",VR::DS,VM::VM1,"NPW factor",false }, + {0x0043,0x009c,"GEMS_PARM_01",VR::OB,VM::VM1,"Research Tag 1",false }, + {0x0043,0x009d,"GEMS_PARM_01",VR::OB,VM::VM1,"Research Tag 2",false }, + {0x0043,0x009e,"GEMS_PARM_01",VR::OB,VM::VM1,"Research Tag 3",false }, + {0x0043,0x009f,"GEMS_PARM_01",VR::OB,VM::VM1,"Research Tag 4",false }, + {0x0043,0x00a0,"GEMS_PARM_01",VR::SQ,VM::VM1,"Spectroscopy Pixel Sequence",false }, + {0x0043,0x00a1,"GEMS_PARM_01",VR::SQ,VM::VM1,"Spectroscopy Default Display Sequence",false }, + {0x0043,0x00a2,"GEMS_PARM_01",VR::DS,VM::VM1_n,"MEG Data",false }, + {0x0043,0x00a3,"GEMS_PARM_01",VR::CS,VM::VM1,"ASL Contrast technique",false }, + {0x0043,0x00a4,"GEMS_PARM_01",VR::LO,VM::VM1,"Detailed text for ASL labeling technique",false }, + {0x0043,0x00a5,"GEMS_PARM_01",VR::IS,VM::VM1,"Duration of the label or control pulse",false }, + {0x0051,0x000a,"GEMS_PARM_01",VR::SL,VM::VM1,"Store level of Functional Image",false }, + {0x0051,0x000b,"GEMS_PARM_01",VR::FL,VM::VM1,"Store B-Value with Functional Image",false }, + {0x2001,0x0010,"GEMS_PARM_01",VR::UI,VM::VM1,"DICOM Implementation UID",false }, + {0x2001,0x0011,"GEMS_PARM_01",VR::SH,VM::VM1,"DICOM Implementation Version",false }, + {0x2001,0x0012,"GEMS_PARM_01",VR::UI,VM::VM1,"Within-DICOM-Implementation SOP Instance UID",false }, + {0x2001,0x0013,"GEMS_PARM_01",VR::SH,VM::VM1,"Application Name",false }, + {0x2001,0x0014,"GEMS_PARM_01",VR::SH,VM::VM1,"Application Version",false }, + {0x2001,0x0015,"GEMS_PARM_01",VR::SH,VM::VM1,"Compatibility Version",false }, + {0x2001,0x0021,"GEMS_PARM_01",VR::UI,VM::VM1_n,"Referenced Series UID",false }, + {0x2001,0x0031,"GEMS_PARM_01",VR::US,VM::VM1,"Number of Objects Averaged",false }, + {0x2001,0x0041,"GEMS_PARM_01",VR::US,VM::VM1,"Number of Expected Time Points",false }, + {0x2001,0x0051,"GEMS_PARM_01",VR::US,VM::VM1,"Number of Slices Per Volume",false }, + {0x2001,0x0060,"GEMS_PARM_01",VR::US,VM::VM1,"BW Image Type",false }, + {0x2001,0x0061,"GEMS_PARM_01",VR::US,VM::VM1,"Experiment Type",false }, + {0x2001,0x0071,"GEMS_PARM_01",VR::UI,VM::VM1,"Paradigm UID",false }, + {0x2001,0x0072,"GEMS_PARM_01",VR::LO,VM::VM1,"Paradigm Name",false }, + {0x2001,0x0073,"GEMS_PARM_01",VR::ST,VM::VM1,"Paradigm Description",false }, + {0x2001,0x0080,"GEMS_PARM_01",VR::OB,VM::VM1,"Contrast",false }, + {0x2001,0x0081,"GEMS_PARM_01",VR::FL,VM::VM1_n,"Regressor Values",false }, + {0x2001,0x0086,"GEMS_PARM_01",VR::US,VM::VM1,"Number of Degrees of Freedom",false }, + {0x2001,0x008a,"GEMS_PARM_01",VR::FL,VM::VM1,"Z Threshold",false }, + {0x2001,0x008b,"GEMS_PARM_01",VR::FL,VM::VM1,"p Threshold",false }, + {0x2001,0x0090,"GEMS_PARM_01",VR::OB,VM::VM1,"Processing parameters",false }, + {0x2001,0x0091,"GEMS_PARM_01",VR::OB,VM::VM1,"Motion Plot",false }, + {0x2001,0x0092,"GEMS_PARM_01",VR::OB,VM::VM1,"ROIs",false }, + {0x2001,0x0093,"GEMS_PARM_01",VR::OB,VM::VM1,"Tracts",false }, + {0x2001,0x0094,"GEMS_PARM_01",VR::OB,VM::VM1,"Report",false }, + {0x2001,0x0095,"GEMS_PARM_01",VR::OB,VM::VM1,"Response Data",false }, + {0x2001,0x00a0,"GEMS_PARM_01",VR::FL,VM::VM1_n,"Motion Parameters",false }, + {0x2001,0x00a1,"GEMS_PARM_01",VR::FL,VM::VM1_n,"Registration Parameters",false }, + {0x2001,0x00a2,"GEMS_PARM_01",VR::FL,VM::VM1_n,"Subject Data",false }, + {0x2001,0x00b0,"GEMS_PARM_01",VR::OB,VM::VM1,"DTI Parameters",false }, + {0x2001,0x00c0,"GEMS_PARM_01",VR::OB,VM::VM1,"Paradigm Info",false }, + {0x0011,0x0010,"GEMS_PATI_01",VR::SS,VM::VM1,"Patient Status",false }, + {0x0009,0x0001,"GEMS_PETD_01",VR::LO,VM::VM2,"GE Discovery PET Implementation Version Name",false }, + {0x0009,0x0002,"GEMS_PETD_01",VR::LO,VM::VM1,"PET patient_id",false }, + {0x0009,0x0003,"GEMS_PETD_01",VR::SH,VM::VM1,"PET compatible_version",false }, + {0x0009,0x0004,"GEMS_PETD_01",VR::SH,VM::VM1,"GE Advance Patient.software_version",false }, + {0x0009,0x0005,"GEMS_PETD_01",VR::DT,VM::VM1,"PET patient_datetime",false }, + {0x0009,0x0006,"GEMS_PETD_01",VR::SL,VM::VM1,"PET type",false }, + {0x0009,0x0007,"GEMS_PETD_01",VR::UI,VM::VM1,"PET exam_id",false }, + {0x0009,0x0008,"GEMS_PETD_01",VR::SH,VM::VM1,"PET compatible_version",false }, + {0x0009,0x0009,"GEMS_PETD_01",VR::SH,VM::VM1,"PET software_version",false }, + {0x0009,0x000a,"GEMS_PETD_01",VR::UI,VM::VM1,"PET scan_id",false }, + {0x0009,0x000b,"GEMS_PETD_01",VR::SH,VM::VM1,"PET compatible_version",false }, + {0x0009,0x000c,"GEMS_PETD_01",VR::SH,VM::VM1,"PET software_version",false }, + {0x0009,0x000d,"GEMS_PETD_01",VR::DT,VM::VM1,"PET scan_datetime",false }, + {0x0009,0x000e,"GEMS_PETD_01",VR::DT,VM::VM1,"PET scan_ready",false }, + {0x0009,0x000f,"GEMS_PETD_01",VR::ST,VM::VM1,"PET scan_description",false }, + {0x0009,0x0010,"GEMS_PETD_01",VR::LO,VM::VM1,"PET hospital_name",false }, + {0x0009,0x0011,"GEMS_PETD_01",VR::LO,VM::VM1,"PET scanner_desc",false }, + {0x0009,0x0012,"GEMS_PETD_01",VR::LO,VM::VM1,"PET manufacturer",false }, + {0x0009,0x0013,"GEMS_PETD_01",VR::UI,VM::VM1,"PET for_identifier",false }, + {0x0009,0x0014,"GEMS_PETD_01",VR::LO,VM::VM1,"PET landmark_name",false }, + {0x0009,0x0015,"GEMS_PETD_01",VR::SH,VM::VM1,"PET landmark_abbrev",false }, + {0x0009,0x0016,"GEMS_PETD_01",VR::SL,VM::VM1,"PET patient_position",false }, + {0x0009,0x0017,"GEMS_PETD_01",VR::SL,VM::VM1,"PET scan_perspective",false }, + {0x0009,0x0018,"GEMS_PETD_01",VR::SL,VM::VM1,"PET scan_type",false }, + {0x0009,0x0019,"GEMS_PETD_01",VR::SL,VM::VM1,"PET scan_mode",false }, + {0x0009,0x001a,"GEMS_PETD_01",VR::SL,VM::VM1,"PET start_condition",false }, + {0x0009,0x001b,"GEMS_PETD_01",VR::SL,VM::VM1,"PET start_cond_data",false }, + {0x0009,0x001c,"GEMS_PETD_01",VR::SL,VM::VM1,"PET sel_stop_cond",false }, + {0x0009,0x001d,"GEMS_PETD_01",VR::SL,VM::VM1,"PET sel_stop_cond_data",false }, + {0x0009,0x001e,"GEMS_PETD_01",VR::SL,VM::VM1,"PET collect_deadtime",false }, + {0x0009,0x001f,"GEMS_PETD_01",VR::SL,VM::VM1,"PET collect_singles",false }, + {0x0009,0x0020,"GEMS_PETD_01",VR::SL,VM::VM1,"PET collect_countrate",false }, + {0x0009,0x0021,"GEMS_PETD_01",VR::SL,VM::VM1,"PET countrate_period",false }, + {0x0009,0x0022,"GEMS_PETD_01",VR::SL,VM::VM1,"PET delayed_events",false }, + {0x0009,0x0023,"GEMS_PETD_01",VR::SL,VM::VM1,"PET delayed_bias",false }, + {0x0009,0x0024,"GEMS_PETD_01",VR::SL,VM::VM1,"PET word_size",false }, + {0x0009,0x0025,"GEMS_PETD_01",VR::SL,VM::VM1,"PET axial_acceptance",false }, + {0x0009,0x0026,"GEMS_PETD_01",VR::SL,VM::VM1,"PET axial_angle_3d",false }, + {0x0009,0x0027,"GEMS_PETD_01",VR::SL,VM::VM1,"PET theta_compression",false }, + {0x0009,0x0028,"GEMS_PETD_01",VR::SL,VM::VM1,"PET axial_compression",false }, + {0x0009,0x0029,"GEMS_PETD_01",VR::FL,VM::VM1,"PET gantry_tilt_angle",false }, + {0x0009,0x002a,"GEMS_PETD_01",VR::SL,VM::VM1,"PET collimation",false }, + {0x0009,0x002b,"GEMS_PETD_01",VR::SL,VM::VM1,"PET scan_fov",false }, + {0x0009,0x002c,"GEMS_PETD_01",VR::SL,VM::VM1,"PET axial_fov",false }, + {0x0009,0x002d,"GEMS_PETD_01",VR::SL,VM::VM1,"PET event_separation",false }, + {0x0009,0x002e,"GEMS_PETD_01",VR::SL,VM::VM1,"PET mask_width",false }, + {0x0009,0x002f,"GEMS_PETD_01",VR::SL,VM::VM1,"PET binning_mode",false }, + {0x0009,0x0030,"GEMS_PETD_01",VR::SL,VM::VM1,"PET trig_rej_method",false }, + {0x0009,0x0031,"GEMS_PETD_01",VR::SL,VM::VM1,"PET number_for_reject",false }, + {0x0009,0x0032,"GEMS_PETD_01",VR::SL,VM::VM1,"PET lower_reject_limit",false }, + {0x0009,0x0033,"GEMS_PETD_01",VR::SL,VM::VM1,"PET upper_reject_limit",false }, + {0x0009,0x0034,"GEMS_PETD_01",VR::SL,VM::VM1,"PET triggers_acquired",false }, + {0x0009,0x0035,"GEMS_PETD_01",VR::SL,VM::VM1,"PET triggers_rejected",false }, + {0x0009,0x0036,"GEMS_PETD_01",VR::LO,VM::VM1,"PET tracer_name",false }, + {0x0009,0x0037,"GEMS_PETD_01",VR::LO,VM::VM1,"PET batch_description",false }, + {0x0009,0x0038,"GEMS_PETD_01",VR::FL,VM::VM1,"PET tracer_activity",false }, + {0x0009,0x0039,"GEMS_PETD_01",VR::DT,VM::VM1,"PET meas_datetime",false }, + {0x0009,0x003a,"GEMS_PETD_01",VR::FL,VM::VM1,"PET pre_inj_volume",false }, + {0x0009,0x003b,"GEMS_PETD_01",VR::DT,VM::VM1,"PET admin_datetime",false }, + {0x0009,0x003c,"GEMS_PETD_01",VR::FL,VM::VM1,"PET post_inj_activity",false }, + {0x0009,0x003d,"GEMS_PETD_01",VR::DT,VM::VM1,"PET post_inj_datetime",false }, + {0x0009,0x003e,"GEMS_PETD_01",VR::SH,VM::VM1,"PET radionuclide_name",false }, + {0x0009,0x003f,"GEMS_PETD_01",VR::FL,VM::VM1,"PET half_life",false }, + {0x0009,0x0040,"GEMS_PETD_01",VR::FL,VM::VM1,"PET positron_fraction",false }, + {0x0009,0x0041,"GEMS_PETD_01",VR::SL,VM::VM1,"PET source1_holder",false }, + {0x0009,0x0042,"GEMS_PETD_01",VR::FL,VM::VM1,"PET source1_activity",false }, + {0x0009,0x0043,"GEMS_PETD_01",VR::DT,VM::VM1,"PET source1_meas_dt",false }, + {0x0009,0x0044,"GEMS_PETD_01",VR::SH,VM::VM1,"PET source1_radnuclide",false }, + {0x0009,0x0045,"GEMS_PETD_01",VR::FL,VM::VM1,"PET source1_half_life",false }, + {0x0009,0x0046,"GEMS_PETD_01",VR::SL,VM::VM1,"PET source2_holder",false }, + {0x0009,0x0047,"GEMS_PETD_01",VR::FL,VM::VM1,"PET source2_activity",false }, + {0x0009,0x0048,"GEMS_PETD_01",VR::DT,VM::VM1,"PET source2_meas_dt",false }, + {0x0009,0x0049,"GEMS_PETD_01",VR::SH,VM::VM1,"PET source2_radnuclide",false }, + {0x0009,0x004a,"GEMS_PETD_01",VR::FL,VM::VM1,"PET source2_half_life",false }, + {0x0009,0x004b,"GEMS_PETD_01",VR::SL,VM::VM1,"PET source_speed",false }, + {0x0009,0x004c,"GEMS_PETD_01",VR::FL,VM::VM1,"PET source_location",false }, + {0x0009,0x004d,"GEMS_PETD_01",VR::SL,VM::VM1,"PET emission_present",false }, + {0x0009,0x004e,"GEMS_PETD_01",VR::SL,VM::VM1,"PET lower_axial_acc",false }, + {0x0009,0x004f,"GEMS_PETD_01",VR::SL,VM::VM1,"PET upper_axial_acc",false }, + {0x0009,0x0050,"GEMS_PETD_01",VR::SL,VM::VM1,"PET lower_coinc_limit",false }, + {0x0009,0x0051,"GEMS_PETD_01",VR::SL,VM::VM1,"PET upper_coinc_limit",false }, + {0x0009,0x0052,"GEMS_PETD_01",VR::SL,VM::VM1,"PET coinc_delay_offset",false }, + {0x0009,0x0053,"GEMS_PETD_01",VR::SL,VM::VM1,"PET coinc_output_mode",false }, + {0x0009,0x0054,"GEMS_PETD_01",VR::SL,VM::VM1,"PET upper_energy_limit",false }, + {0x0009,0x0055,"GEMS_PETD_01",VR::SL,VM::VM1,"PET lower_energy_limit",false }, + {0x0009,0x0056,"GEMS_PETD_01",VR::UI,VM::VM1,"PET normal_cal_id",false }, + {0x0009,0x0057,"GEMS_PETD_01",VR::UI,VM::VM1,"PET normal_2d_cal_id",false }, + {0x0009,0x0058,"GEMS_PETD_01",VR::UI,VM::VM1,"PET blank_cal_id",false }, + {0x0009,0x0059,"GEMS_PETD_01",VR::UI,VM::VM1,"PET wc_cal_id",false }, + {0x0009,0x005a,"GEMS_PETD_01",VR::SL,VM::VM1,"PET derived",false }, + {0x0009,0x005b,"GEMS_PETD_01",VR::LO,VM::VM1,"PET contrast_agent",false }, + {0x0009,0x005c,"GEMS_PETD_01",VR::UI,VM::VM1,"PET frame_id",false }, + {0x0009,0x005d,"GEMS_PETD_01",VR::UI,VM::VM1,"PET scan_id",false }, + {0x0009,0x005e,"GEMS_PETD_01",VR::UI,VM::VM1,"PET exam_id",false }, + {0x0009,0x005f,"GEMS_PETD_01",VR::LO,VM::VM1,"PET patient_id",false }, + {0x0009,0x0060,"GEMS_PETD_01",VR::SH,VM::VM1,"PET compatible_version",false }, + {0x0009,0x0061,"GEMS_PETD_01",VR::SH,VM::VM1,"PET software_version",false }, + {0x0009,0x0062,"GEMS_PETD_01",VR::ST,VM::VM1,"PET where_is_frame",false }, + {0x0009,0x0063,"GEMS_PETD_01",VR::SL,VM::VM1,"PET frame_size",false }, + {0x0009,0x0064,"GEMS_PETD_01",VR::SL,VM::VM1,"PET file_exists",false }, + {0x0009,0x0065,"GEMS_PETD_01",VR::SL,VM::VM1,"PET patient_entry",false }, + {0x0009,0x0066,"GEMS_PETD_01",VR::FL,VM::VM1,"PET table_height",false }, + {0x0009,0x0067,"GEMS_PETD_01",VR::FL,VM::VM1,"PET table_z_position",false }, + {0x0009,0x0068,"GEMS_PETD_01",VR::DT,VM::VM1,"PET landmark_datetime",false }, + {0x0009,0x0069,"GEMS_PETD_01",VR::SL,VM::VM1,"PET slice_count",false }, + {0x0009,0x006a,"GEMS_PETD_01",VR::FL,VM::VM1,"PET start_location",false }, + {0x0009,0x006b,"GEMS_PETD_01",VR::SL,VM::VM1,"PET acq_delay",false }, + {0x0009,0x006c,"GEMS_PETD_01",VR::DT,VM::VM1,"PET acq_start",false }, + {0x0009,0x006d,"GEMS_PETD_01",VR::SL,VM::VM1,"PET acq_duration",false }, + {0x0009,0x006e,"GEMS_PETD_01",VR::SL,VM::VM1,"PET acq_bin_dur",false }, + {0x0009,0x006f,"GEMS_PETD_01",VR::SL,VM::VM1,"PET acq_bin_start",false }, + {0x0009,0x0070,"GEMS_PETD_01",VR::SL,VM::VM1,"PET actual_stop_cond",false }, + {0x0009,0x0071,"GEMS_PETD_01",VR::FD,VM::VM1,"PET total_prompts",false }, + {0x0009,0x0072,"GEMS_PETD_01",VR::FD,VM::VM1,"PET total_delays",false }, + {0x0009,0x0073,"GEMS_PETD_01",VR::SL,VM::VM1,"PET frame_valid",false }, + {0x0009,0x0074,"GEMS_PETD_01",VR::SL,VM::VM1,"PET validity_info",false }, + {0x0009,0x0075,"GEMS_PETD_01",VR::SL,VM::VM1,"PET archived",false }, + {0x0009,0x0076,"GEMS_PETD_01",VR::SL,VM::VM1,"PET compression",false }, + {0x0009,0x0077,"GEMS_PETD_01",VR::SL,VM::VM1,"PET uncompressed_size",false }, + {0x0009,0x0078,"GEMS_PETD_01",VR::SL,VM::VM1,"PET accum_bin_dur",false }, + {0x0009,0x0079,"GEMS_PETD_01",VR::SH,VM::VM1,"PET compatible_version",false }, + {0x0009,0x007a,"GEMS_PETD_01",VR::SH,VM::VM1,"PET software_version",false }, + {0x0009,0x007b,"GEMS_PETD_01",VR::DT,VM::VM1,"PET is_datetime",false }, + {0x0009,0x007c,"GEMS_PETD_01",VR::SL,VM::VM1,"PET is_source",false }, + {0x0009,0x007d,"GEMS_PETD_01",VR::SL,VM::VM1,"PET is_contents",false }, + {0x0009,0x007e,"GEMS_PETD_01",VR::SL,VM::VM1,"PET is_type",false }, + {0x0009,0x007f,"GEMS_PETD_01",VR::DS,VM::VM3,"PET is_reference",false }, + {0x0009,0x0080,"GEMS_PETD_01",VR::SL,VM::VM1,"PET multi_patient",false }, + {0x0009,0x0081,"GEMS_PETD_01",VR::SL,VM::VM1,"PET number_of_normals",false }, + {0x0009,0x0082,"GEMS_PETD_01",VR::UI,VM::VM1,"PET color_map_id",false }, + {0x0009,0x0083,"GEMS_PETD_01",VR::SL,VM::VM1,"PET window_level_type",false }, + {0x0009,0x0084,"GEMS_PETD_01",VR::FL,VM::VM1,"PET rotate",false }, + {0x0009,0x0085,"GEMS_PETD_01",VR::SL,VM::VM1,"PET flip",false }, + {0x0009,0x0086,"GEMS_PETD_01",VR::FL,VM::VM1,"PET zoom",false }, + {0x0009,0x0087,"GEMS_PETD_01",VR::SL,VM::VM1,"PET pan_x",false }, + {0x0009,0x0088,"GEMS_PETD_01",VR::SL,VM::VM1,"PET pan_y",false }, + {0x0009,0x0089,"GEMS_PETD_01",VR::FL,VM::VM1,"PET window_level_min",false }, + {0x0009,0x008a,"GEMS_PETD_01",VR::FL,VM::VM1,"PET window_level_max",false }, + {0x0009,0x008b,"GEMS_PETD_01",VR::SL,VM::VM1,"PET recon_method",false }, + {0x0009,0x008c,"GEMS_PETD_01",VR::SL,VM::VM1,"PET attenuation",false }, + {0x0009,0x008d,"GEMS_PETD_01",VR::FL,VM::VM1,"PET atten_coefficient",false }, + {0x0009,0x008e,"GEMS_PETD_01",VR::SL,VM::VM1,"PET bp_filter",false }, + {0x0009,0x008f,"GEMS_PETD_01",VR::FL,VM::VM1,"PET bp_filter_cutoff",false }, + {0x0009,0x0090,"GEMS_PETD_01",VR::SL,VM::VM1,"PET bp_filter_order",false }, + {0x0009,0x0091,"GEMS_PETD_01",VR::FL,VM::VM1,"PET bp_center_l",false }, + {0x0009,0x0092,"GEMS_PETD_01",VR::FL,VM::VM1,"PET bp_center_p",false }, + {0x0009,0x0093,"GEMS_PETD_01",VR::SL,VM::VM1,"PET atten_smooth",false }, + {0x0009,0x0094,"GEMS_PETD_01",VR::SL,VM::VM1,"PET atten_smooth_param",false }, + {0x0009,0x0095,"GEMS_PETD_01",VR::SL,VM::VM1,"PET angle_smooth_param",false }, + {0x0009,0x0096,"GEMS_PETD_01",VR::UI,VM::VM1,"PET wellcountercal_id",false }, + {0x0009,0x0097,"GEMS_PETD_01",VR::UI,VM::VM1,"PET trans_scan_id",false }, + {0x0009,0x0098,"GEMS_PETD_01",VR::UI,VM::VM1,"PET norm_cal_id",false }, + {0x0009,0x0099,"GEMS_PETD_01",VR::UI,VM::VM1,"PET blnk_cal_id",false }, + {0x0009,0x009a,"GEMS_PETD_01",VR::FL,VM::VM1,"PET cac_edge_threshold",false }, + {0x0009,0x009b,"GEMS_PETD_01",VR::FL,VM::VM1,"PET cac_skull_offset",false }, + {0x0009,0x009c,"GEMS_PETD_01",VR::UI,VM::VM1,"PET emiss_sub_id",false }, + {0x0009,0x009d,"GEMS_PETD_01",VR::SL,VM::VM1,"PET radial_filter_3d",false }, + {0x0009,0x009e,"GEMS_PETD_01",VR::FL,VM::VM1,"PET radial_cutoff_3d",false }, + {0x0009,0x009f,"GEMS_PETD_01",VR::SL,VM::VM1,"PET axial_filter_3d",false }, + {0x0009,0x00a0,"GEMS_PETD_01",VR::FL,VM::VM1,"PET axial_cutoff_3d",false }, + {0x0009,0x00a1,"GEMS_PETD_01",VR::FL,VM::VM1,"PET axial_start",false }, + {0x0009,0x00a2,"GEMS_PETD_01",VR::FL,VM::VM1,"PET axial_spacing",false }, + {0x0009,0x00a3,"GEMS_PETD_01",VR::SL,VM::VM1,"PET axial_angles_used",false }, + {0x0009,0x00a4,"GEMS_PETD_01",VR::SH,VM::VM1,"PET compatible_version",false }, + {0x0009,0x00a5,"GEMS_PETD_01",VR::SH,VM::VM1,"PET software_version",false }, + {0x0009,0x00a6,"GEMS_PETD_01",VR::SL,VM::VM1,"PET slice_number",false }, + {0x0009,0x00a7,"GEMS_PETD_01",VR::FL,VM::VM1,"PET total_counts",false }, + {0x0009,0x00a8,"GEMS_PETD_01",VR::OB,VM::VM1,"PET other_atts",false }, + {0x0009,0x00a9,"GEMS_PETD_01",VR::SL,VM::VM1,"PET other_atts_size",false }, + {0x0009,0x00aa,"GEMS_PETD_01",VR::SL,VM::VM1,"PET archived",false }, + {0x0009,0x00ab,"GEMS_PETD_01",VR::FL,VM::VM1,"PET bp_center_x",false }, + {0x0009,0x00ac,"GEMS_PETD_01",VR::FL,VM::VM1,"PET bp_center_y",false }, + {0x0009,0x00ad,"GEMS_PETD_01",VR::UI,VM::VM1,"PET trans_frame_id",false }, + {0x0009,0x00ae,"GEMS_PETD_01",VR::UI,VM::VM1,"PET tpluse_frame_id",false }, + {0x0009,0x00b1,"GEMS_PETD_01",VR::FL,VM::VM1,"PET profile_spacing",false }, + {0x0009,0x00b2,"GEMS_PETD_01",VR::SL,VM::VM1,"PET ir_num_iterations",false }, + {0x0009,0x00b3,"GEMS_PETD_01",VR::SL,VM::VM1,"PET ir_num_subsets",false }, + {0x0009,0x00b4,"GEMS_PETD_01",VR::FL,VM::VM1,"PET ir_recon_fov",false }, + {0x0009,0x00b5,"GEMS_PETD_01",VR::SL,VM::VM1,"PET ir_corr_model",false }, + {0x0009,0x00b6,"GEMS_PETD_01",VR::SL,VM::VM1,"PET ir_loop_filter",false }, + {0x0009,0x00b7,"GEMS_PETD_01",VR::FL,VM::VM1,"PET ir_pre_filt_parm",false }, + {0x0009,0x00b8,"GEMS_PETD_01",VR::SL,VM::VM1,"PET ir_loop_filt_parm",false }, + {0x0009,0x00b9,"GEMS_PETD_01",VR::FL,VM::VM1,"PET response_filt_parm",false }, + {0x0009,0x00ba,"GEMS_PETD_01",VR::SL,VM::VM1,"PET post_filter",false }, + {0x0009,0x00bb,"GEMS_PETD_01",VR::FL,VM::VM1,"PET post_filt_parm",false }, + {0x0009,0x00bc,"GEMS_PETD_01",VR::SL,VM::VM1,"PET ir_regularize",false }, + {0x0009,0x00bd,"GEMS_PETD_01",VR::FL,VM::VM1,"PET regularize_parm",false }, + {0x0009,0x00be,"GEMS_PETD_01",VR::SL,VM::VM1,"PET ac_bp_filter",false }, + {0x0009,0x00bf,"GEMS_PETD_01",VR::FL,VM::VM1,"PET ac_bp_filt_cut_off",false }, + {0x0009,0x00c0,"GEMS_PETD_01",VR::SL,VM::VM1,"PET ac_bp_filt_order",false }, + {0x0009,0x00c1,"GEMS_PETD_01",VR::SL,VM::VM1,"PET ac_img_smooth",false }, + {0x0009,0x00c2,"GEMS_PETD_01",VR::FL,VM::VM1,"PET ac_img_smooth_parm",false }, + {0x0009,0x00c3,"GEMS_PETD_01",VR::SL,VM::VM1,"PET scatter_method",false }, + {0x0009,0x00c4,"GEMS_PETD_01",VR::SL,VM::VM1,"PET scatter_num_iter",false }, + {0x0009,0x00c5,"GEMS_PETD_01",VR::FL,VM::VM1,"PET scatter_parm",false }, + {0x0009,0x00c6,"GEMS_PETD_01",VR::FL,VM::VM1,"PET seg_qc_parm",false }, + {0x0009,0x00c7,"GEMS_PETD_01",VR::SL,VM::VM1,"PET overlap",false }, + {0x0009,0x00c8,"GEMS_PETD_01",VR::UI,VM::VM1,"PET ovlp_frm_id",false }, + {0x0009,0x00c9,"GEMS_PETD_01",VR::UI,VM::VM1,"PET ovlp_trans_frm_id",false }, + {0x0009,0x00ca,"GEMS_PETD_01",VR::UI,VM::VM1,"PET ovlp_tpulse_frm_id",false }, + {0x0009,0x00cb,"GEMS_PETD_01",VR::FL,VM::VM1,"PET vqc_x_axis_trans",false }, + {0x0009,0x00cc,"GEMS_PETD_01",VR::FL,VM::VM1,"PET vqc_x_axis_tilt",false }, + {0x0009,0x00cd,"GEMS_PETD_01",VR::FL,VM::VM1,"PET vqc_y_axis_trans",false }, + {0x0009,0x00ce,"GEMS_PETD_01",VR::FL,VM::VM1,"PET vqc_y_axis_swivel",false }, + {0x0009,0x00cf,"GEMS_PETD_01",VR::FL,VM::VM1,"PET vqc_z_axis_trans",false }, + {0x0009,0x00d0,"GEMS_PETD_01",VR::FL,VM::VM1,"PET vqc_z_axis_roll",false }, + {0x0009,0x00d1,"GEMS_PETD_01",VR::LO,VM::VM1,"PET ctac_conv_scale",false }, + {0x0009,0x00d2,"GEMS_PETD_01",VR::UI,VM::VM1,"PET image_set_id",false }, + {0x0009,0x00d3,"GEMS_PETD_01",VR::SL,VM::VM1,"PET constrast_route",false }, + {0x0009,0x00d4,"GEMS_PETD_01",VR::LO,VM::VM1,"PET ctac_conv_scale",false }, + {0x0009,0x00d5,"GEMS_PETD_01",VR::FL,VM::VM1,"PET loop_filter_parm",false }, + {0x0009,0x00d6,"GEMS_PETD_01",VR::FL,VM::VM1,"PET image_one_loc",false }, + {0x0009,0x00d7,"GEMS_PETD_01",VR::FL,VM::VM1,"PET image_index_loc",false }, + {0x0009,0x00d8,"GEMS_PETD_01",VR::SL,VM::VM1,"PET frame_number",false }, + {0x0009,0x00d9,"GEMS_PETD_01",VR::SL,VM::VM1,"PET list_file_exists",false }, + {0x0009,0x00da,"GEMS_PETD_01",VR::ST,VM::VM1,"PET where_is_list_frame",false }, + {0x0009,0x00db,"GEMS_PETD_01",VR::SL,VM::VM1,"PET ir_z_filter_flag",false }, + {0x0009,0x00dc,"GEMS_PETD_01",VR::FL,VM::VM1,"PET ir_z_filter_ratio",false }, + {0x0009,0x00dd,"GEMS_PETD_01",VR::US,VM::VM1,"PET num_of_rr_interval",false }, + {0x0009,0x00de,"GEMS_PETD_01",VR::US,VM::VM1,"PET num_of_time_slots",false }, + {0x0009,0x00df,"GEMS_PETD_01",VR::US,VM::VM1,"PET num_of_slices",false }, + {0x0009,0x00e0,"GEMS_PETD_01",VR::US,VM::VM1,"PET num_of_time_slices",false }, + {0x0009,0x00e1,"GEMS_PETD_01",VR::SL,VM::VM1,"PET unlisted_scan",false }, + {0x0009,0x00e2,"GEMS_PETD_01",VR::SL,VM::VM1,"PET rest_stress",false }, + {0x0009,0x00e3,"GEMS_PETD_01",VR::FL,VM::VM1,"PET phase percentage",false }, + {0x0009,0x00e4,"GEMS_PETD_01",VR::ST,VM::VM1,"Recon Protocol",false }, + {0x0009,0x00e5,"GEMS_PETD_01",VR::FL,VM::VM1,"PET left shift",false }, + {0x0009,0x00e6,"GEMS_PETD_01",VR::FL,VM::VM1,"PET posterior shift",false }, + {0x0009,0x00e7,"GEMS_PETD_01",VR::FL,VM::VM1,"PET superior shift",false }, + {0x0009,0x00e8,"GEMS_PETD_01",VR::SL,VM::VM1,"PET acq_bin_num",false }, + {0x0009,0x00e9,"GEMS_PETD_01",VR::FL,VM::VM1,"PET acq_bin_dur_percent",false }, + {0x0009,0x00ea,"GEMS_PETD_01",VR::SL,VM::VM1,"3D Filter flag",false }, + {0x0009,0x00eb,"GEMS_PETD_01",VR::FL,VM::VM1,"3D Filter cutoff",false }, + {0x0009,0x00ec,"GEMS_PETD_01",VR::SL,VM::VM1,"3D Filter order",false }, + {0x0009,0x00f0,"GEMS_PETD_01",VR::UI,VM::VM1,"Reformat group",false }, + {0x0011,0x0001,"GEMS_PETD_01",VR::SQ,VM::VM1,"GE Advance ROI Sequence",false }, + {0x0011,0x0002,"GEMS_PETD_01",VR::UI,VM::VM1,"GE Advance ROI.roi_id",false }, + {0x0011,0x0003,"GEMS_PETD_01",VR::UI,VM::VM1,"GE Advance ROI.image_id",false }, + {0x0011,0x0004,"GEMS_PETD_01",VR::SH,VM::VM1,"GE Advance ROI.compatible_version",false }, + {0x0011,0x0005,"GEMS_PETD_01",VR::SH,VM::VM1,"GE Advance ROI.software_version",false }, + {0x0011,0x0006,"GEMS_PETD_01",VR::LO,VM::VM1,"GE Advance ROI.roi_name",false }, + {0x0011,0x0007,"GEMS_PETD_01",VR::DT,VM::VM1,"GE Advance ROI.roi_datetime",false }, + {0x0011,0x0008,"GEMS_PETD_01",VR::SL,VM::VM1,"GE Advance ROI.roi_type",false }, + {0x0011,0x0009,"GEMS_PETD_01",VR::FL,VM::VM1,"GE Advance ROI.center_x",false }, + {0x0011,0x000a,"GEMS_PETD_01",VR::FL,VM::VM1,"GE Advance ROI.center_y",false }, + {0x0011,0x000b,"GEMS_PETD_01",VR::FL,VM::VM1,"GE Advance ROI.width",false }, + {0x0011,0x000c,"GEMS_PETD_01",VR::FL,VM::VM1,"GE Advance ROI.height",false }, + {0x0011,0x000d,"GEMS_PETD_01",VR::FL,VM::VM1,"GE Advance ROI.angle",false }, + {0x0011,0x000e,"GEMS_PETD_01",VR::SL,VM::VM1,"GE Advance ROI.number_of_points",false }, + {0x0011,0x000f,"GEMS_PETD_01",VR::OB,VM::VM1,"GE Advance ROI.roi_data",false }, + {0x0011,0x0010,"GEMS_PETD_01",VR::SL,VM::VM1,"GE Advance ROI.roi_size",false }, + {0x0011,0x0011,"GEMS_PETD_01",VR::LO,VM::VM1,"GE Advance ROI.color",false }, + {0x0011,0x0012,"GEMS_PETD_01",VR::SL,VM::VM1,"GE Advance ROI.line_type",false }, + {0x0011,0x0013,"GEMS_PETD_01",VR::SL,VM::VM1,"GE Advance ROI.line_width",false }, + {0x0011,0x0014,"GEMS_PETD_01",VR::SL,VM::VM1,"GE Advance ROI.roi_number",false }, + {0x0011,0x0015,"GEMS_PETD_01",VR::SL,VM::VM1,"GE Advance ROI.convex",false }, + {0x0011,0x0016,"GEMS_PETD_01",VR::SL,VM::VM1,"GE Advance ROI.atten_corr_flag",false }, + {0x0011,0x0018,"GEMS_PETD_01",VR::OB,VM::VM1,"?",false }, + {0x0013,0x0001,"GEMS_PETD_01",VR::SQ,VM::VM1,"GE Advance Annotation Sequence",false }, + {0x0013,0x0002,"GEMS_PETD_01",VR::UI,VM::VM1,"GE Advance Annotation.annotation_id",false }, + {0x0013,0x0003,"GEMS_PETD_01",VR::UI,VM::VM1,"GE Advance Annotation.image_id",false }, + {0x0013,0x0004,"GEMS_PETD_01",VR::SH,VM::VM1,"GE Advance Annotation.compatible_version",false }, + {0x0013,0x0005,"GEMS_PETD_01",VR::SH,VM::VM1,"GE Advance Annotation.software_version",false }, + {0x0013,0x0006,"GEMS_PETD_01",VR::SL,VM::VM1,"GE Advance Annotation.type",false }, + {0x0013,0x0007,"GEMS_PETD_01",VR::LO,VM::VM1,"GE Advance Annotation.font_name",false }, + {0x0013,0x0008,"GEMS_PETD_01",VR::SH,VM::VM1,"GE Advance Annotation.font_size",false }, + {0x0013,0x0009,"GEMS_PETD_01",VR::LO,VM::VM1,"GE Advance Annotation.foreground_color",false }, + {0x0013,0x000a,"GEMS_PETD_01",VR::LO,VM::VM1,"GE Advance Annotation.background_color",false }, + {0x0013,0x000b,"GEMS_PETD_01",VR::SL,VM::VM1,"GE Advance Annotation.coordinate_system",false }, + {0x0013,0x000c,"GEMS_PETD_01",VR::FL,VM::VM1,"GE Advance Annotation.start_x",false }, + {0x0013,0x000d,"GEMS_PETD_01",VR::FL,VM::VM1,"GE Advance Annotation.start_y",false }, + {0x0013,0x000e,"GEMS_PETD_01",VR::FL,VM::VM1,"GE Advance Annotation.end_x",false }, + {0x0013,0x000f,"GEMS_PETD_01",VR::FL,VM::VM1,"GE Advance Annotation.end_y",false }, + {0x0013,0x0010,"GEMS_PETD_01",VR::SL,VM::VM1,"GE Advance Annotation.start_symbol",false }, + {0x0013,0x0011,"GEMS_PETD_01",VR::SL,VM::VM1,"GE Advance Annotation.end_symbol",false }, + {0x0013,0x0012,"GEMS_PETD_01",VR::OB,VM::VM1,"GE Advance Annotation.annotation_data",false }, + {0x0013,0x0013,"GEMS_PETD_01",VR::SL,VM::VM1,"GE Advance Annotation.annotation_size",false }, + {0x0013,0x0014,"GEMS_PETD_01",VR::LO,VM::VM1,"GE Advance Annotation.label_id",false }, + {0x0017,0x0001,"GEMS_PETD_01",VR::UI,VM::VM1,"PET correction_cal_id",false }, + {0x0017,0x0002,"GEMS_PETD_01",VR::SH,VM::VM1,"PET compatible_version",false }, + {0x0017,0x0003,"GEMS_PETD_01",VR::SH,VM::VM1,"PET software_version",false }, + {0x0017,0x0004,"GEMS_PETD_01",VR::DT,VM::VM1,"PET cal_datetime",false }, + {0x0017,0x0005,"GEMS_PETD_01",VR::LO,VM::VM1,"PET cal_description",false }, + {0x0017,0x0006,"GEMS_PETD_01",VR::SL,VM::VM1,"PET cal_type",false }, + {0x0017,0x0007,"GEMS_PETD_01",VR::ST,VM::VM1,"PET where_is_corr",false }, + {0x0017,0x0008,"GEMS_PETD_01",VR::SL,VM::VM1,"PET corr_file_size",false }, + {0x0017,0x0009,"GEMS_PETD_01",VR::LO,VM::VM1,"PET scan_id",false }, + {0x0017,0x000a,"GEMS_PETD_01",VR::DT,VM::VM1,"PET scan_datetime",false }, + {0x0017,0x000b,"GEMS_PETD_01",VR::LO,VM::VM1,"PET norm_2d_cal_id",false }, + {0x0017,0x000c,"GEMS_PETD_01",VR::SH,VM::VM1,"PET hosp_identifier",false }, + {0x0017,0x000d,"GEMS_PETD_01",VR::SL,VM::VM1,"PET archived",false }, + {0x0019,0x0001,"GEMS_PETD_01",VR::UI,VM::VM1,"PET wc_cal_id",false }, + {0x0019,0x0002,"GEMS_PETD_01",VR::SH,VM::VM1,"PET compatible_version",false }, + {0x0019,0x0003,"GEMS_PETD_01",VR::SH,VM::VM1,"PET software_version",false }, + {0x0019,0x0004,"GEMS_PETD_01",VR::DT,VM::VM1,"PET cal_datetime",false }, + {0x0019,0x0005,"GEMS_PETD_01",VR::SL,VM::VM1,"PET cal_type",false }, + {0x0019,0x0006,"GEMS_PETD_01",VR::LO,VM::VM1,"PET cal_description",false }, + {0x0019,0x0007,"GEMS_PETD_01",VR::LO,VM::VM1,"PET cal_hardware",false }, + {0x0019,0x0008,"GEMS_PETD_01",VR::OB,VM::VM1,"PET coefficients",false }, + {0x0019,0x0009,"GEMS_PETD_01",VR::FL,VM::VM1,"PET activity_factor_hr",false }, + {0x0019,0x000a,"GEMS_PETD_01",VR::FL,VM::VM1,"PET activity_factor_hs",false }, + {0x0019,0x000b,"GEMS_PETD_01",VR::FL,VM::VM1,"PET activity_factor_3d",false }, + {0x0019,0x000c,"GEMS_PETD_01",VR::LO,VM::VM1,"PET scan_id",false }, + {0x0019,0x000d,"GEMS_PETD_01",VR::DT,VM::VM1,"PET scan_datetime",false }, + {0x0019,0x000e,"GEMS_PETD_01",VR::SH,VM::VM1,"PET hosp_identifier",false }, + {0x0019,0x000f,"GEMS_PETD_01",VR::FL,VM::VM1,"PET meas_activity",false }, + {0x0019,0x0010,"GEMS_PETD_01",VR::DT,VM::VM1,"PET meas_datetime",false }, + {0x0019,0x0011,"GEMS_PETD_01",VR::SL,VM::VM1,"PET axial_filter_3d",false }, + {0x0019,0x0012,"GEMS_PETD_01",VR::FL,VM::VM1,"PET axial_cutoff_3d",false }, + {0x0019,0x0013,"GEMS_PETD_01",VR::SL,VM::VM1,"PET default_flag",false }, + {0x0019,0x0014,"GEMS_PETD_01",VR::SL,VM::VM1,"PET archived",false }, + {0x0019,0x0015,"GEMS_PETD_01",VR::SL,VM::VM1,"PET wc_cal_rec_method",false }, + {0x0019,0x0016,"GEMS_PETD_01",VR::SL,VM::VM1,"PET activity_factor_2d",false }, + {0x0019,0x0017,"GEMS_PETD_01",VR::SL,VM::VM1,"PET isotope",false }, + {0x0021,0x0001,"GEMS_PETD_01",VR::US,VM::VM1,"PET raw_data_type",false }, + {0x0021,0x0002,"GEMS_PETD_01",VR::UL,VM::VM1,"PET raw_data_size",false }, + {0x0023,0x0001,"GEMS_PETD_01",VR::OB,VM::VM1,"raw_data_blob",false }, + {0x0023,0x0002,"GEMS_PETD_01",VR::OB,VM::VM1,"PET raw_data_blob",false }, + {0x5001,0x0001,"GEMS_PETD_01",VR::UI,VM::VM1,"GE Advance Curve.curve_id",false }, + {0x5001,0x0002,"GEMS_PETD_01",VR::SH,VM::VM1,"GE Advance Curve.compatible_version",false }, + {0x5001,0x0003,"GEMS_PETD_01",VR::SH,VM::VM1,"GE Advance Curve.software_version",false }, + {0x5001,0x0004,"GEMS_PETD_01",VR::SL,VM::VM1,"GE Advance Curve.statistics_type",false }, + {0x5001,0x0005,"GEMS_PETD_01",VR::LT,VM::VM1,"GE Advance Curve.how_derived",false }, + {0x5001,0x0006,"GEMS_PETD_01",VR::SL,VM::VM1,"GE Advance Curve.how_derived_size",false }, + {0x5001,0x0007,"GEMS_PETD_01",VR::SL,VM::VM1,"GE Advance Curve.multi_patient",false }, + {0x5001,0x0008,"GEMS_PETD_01",VR::SL,VM::VM1,"GE Advance Curve.deadtime",false }, + {0x5003,0x0001,"GEMS_PETD_01",VR::SQ,VM::VM1,"GE Advance Graph Sequence",false }, + {0x5003,0x0002,"GEMS_PETD_01",VR::UI,VM::VM1,"GE Advance Graph.graph_id",false }, + {0x5003,0x0003,"GEMS_PETD_01",VR::SH,VM::VM1,"GE Advance Graph.compatible_version",false }, + {0x5003,0x0004,"GEMS_PETD_01",VR::SH,VM::VM1,"GE Advance Graph.software_version",false }, + {0x5003,0x0005,"GEMS_PETD_01",VR::LO,VM::VM1,"GE Advance Graph.title",false }, + {0x5003,0x0006,"GEMS_PETD_01",VR::DT,VM::VM1,"GE Advance Graph.graph_datetime",false }, + {0x5003,0x0007,"GEMS_PETD_01",VR::ST,VM::VM1,"GE Advance Graph.graph_description",false }, + {0x5003,0x0008,"GEMS_PETD_01",VR::LO,VM::VM1,"GE Advance Graph.title_font_name",false }, + {0x5003,0x0009,"GEMS_PETD_01",VR::SH,VM::VM1,"GE Advance Graph.title_font_size",false }, + {0x5003,0x000a,"GEMS_PETD_01",VR::LO,VM::VM1,"GE Advance Graph.footer",false }, + {0x5003,0x000b,"GEMS_PETD_01",VR::SH,VM::VM1,"GE Advance Graph.footer_font_size",false }, + {0x5003,0x000c,"GEMS_PETD_01",VR::LO,VM::VM1,"GE Advance Graph.foreground_color",false }, + {0x5003,0x000d,"GEMS_PETD_01",VR::LO,VM::VM1,"GE Advance Graph.background_color",false }, + {0x5003,0x000e,"GEMS_PETD_01",VR::SL,VM::VM1,"GE Advance Graph.graph_border",false }, + {0x5003,0x000f,"GEMS_PETD_01",VR::SL,VM::VM1,"GE Advance Graph.graph_width",false }, + {0x5003,0x0010,"GEMS_PETD_01",VR::SL,VM::VM1,"GE Advance Graph.graph_height",false }, + {0x5003,0x0011,"GEMS_PETD_01",VR::SL,VM::VM1,"GE Advance Graph.grid",false }, + {0x5003,0x0012,"GEMS_PETD_01",VR::LO,VM::VM1,"GE Advance Graph.label_font_name",false }, + {0x5003,0x0013,"GEMS_PETD_01",VR::SH,VM::VM1,"GE Advance Graph.label_font_size",false }, + {0x5003,0x0014,"GEMS_PETD_01",VR::LO,VM::VM1,"GE Advance Graph.axes_color",false }, + {0x5003,0x0015,"GEMS_PETD_01",VR::LO,VM::VM1,"GE Advance Graph.x_axis_label",false }, + {0x5003,0x0016,"GEMS_PETD_01",VR::SL,VM::VM1,"GE Advance Graph.x_axis_units",false }, + {0x5003,0x0017,"GEMS_PETD_01",VR::FL,VM::VM1,"GE Advance Graph.x_major_tics",false }, + {0x5003,0x0018,"GEMS_PETD_01",VR::FL,VM::VM1,"GE Advance Graph.x_axis_min",false }, + {0x5003,0x0019,"GEMS_PETD_01",VR::FL,VM::VM1,"GE Advance Graph.x_axis_max",false }, + {0x5003,0x001a,"GEMS_PETD_01",VR::LO,VM::VM1,"GE Advance Graph.y_axis_label",false }, + {0x5003,0x001b,"GEMS_PETD_01",VR::SL,VM::VM1,"GE Advance Graph.y_axis_units",false }, + {0x5003,0x001c,"GEMS_PETD_01",VR::FL,VM::VM1,"GE Advance Graph.y_major_tics",false }, + {0x5003,0x001d,"GEMS_PETD_01",VR::FL,VM::VM1,"GE Advance Graph.y_axis_min",false }, + {0x5003,0x001e,"GEMS_PETD_01",VR::FL,VM::VM1,"GE Advance Graph.y_axis_max",false }, + {0x5003,0x001f,"GEMS_PETD_01",VR::LO,VM::VM1,"GE Advance Graph.legend_font_name",false }, + {0x5003,0x0020,"GEMS_PETD_01",VR::SH,VM::VM1,"GE Advance Graph.legend_font_size",false }, + {0x5003,0x0021,"GEMS_PETD_01",VR::SL,VM::VM1,"GE Advance Graph.legend_location_x",false }, + {0x5003,0x0022,"GEMS_PETD_01",VR::SL,VM::VM1,"GE Advance Graph.legend_location_y",false }, + {0x5003,0x0023,"GEMS_PETD_01",VR::SL,VM::VM1,"GE Advance Graph.legend_width",false }, + {0x5003,0x0024,"GEMS_PETD_01",VR::SL,VM::VM1,"GE Advance Graph.legend_height",false }, + {0x5003,0x0025,"GEMS_PETD_01",VR::SL,VM::VM1,"GE Advance Graph.legend_border",false }, + {0x5003,0x0026,"GEMS_PETD_01",VR::SL,VM::VM1,"GE Advance Graph.multi_patient",false }, + {0x5005,0x0001,"GEMS_PETD_01",VR::SQ,VM::VM1,"GE Advance CurvePresentation Sequence",false }, + {0x5005,0x0002,"GEMS_PETD_01",VR::UI,VM::VM1,"GE Advance CurvePresentation.curvepresent_id",false }, + {0x5005,0x0003,"GEMS_PETD_01",VR::UI,VM::VM1,"GE Advance CurvePresentation.graph_id",false }, + {0x5005,0x0004,"GEMS_PETD_01",VR::UI,VM::VM1,"GE Advance CurvePresentation.curve_id",false }, + {0x5005,0x0005,"GEMS_PETD_01",VR::SH,VM::VM1,"GE Advance CurvePresentation.compatible_version",false }, + {0x5005,0x0006,"GEMS_PETD_01",VR::SH,VM::VM1,"GE Advance CurvePresentation.software_version",false }, + {0x5005,0x0007,"GEMS_PETD_01",VR::LO,VM::VM1,"GE Advance CurvePresentation.curve_label",false }, + {0x5005,0x0008,"GEMS_PETD_01",VR::LO,VM::VM1,"GE Advance CurvePresentation.color",false }, + {0x5005,0x0009,"GEMS_PETD_01",VR::SL,VM::VM1,"GE Advance CurvePresentation.line_type",false }, + {0x5005,0x000a,"GEMS_PETD_01",VR::SL,VM::VM1,"GE Advance CurvePresentation.line_width",false }, + {0x5005,0x000b,"GEMS_PETD_01",VR::SL,VM::VM1,"GE Advance CurvePresentation.point_symbol",false }, + {0x5005,0x000c,"GEMS_PETD_01",VR::SL,VM::VM1,"GE Advance CurvePresentation.point_symbol_dim",false }, + {0x5005,0x000d,"GEMS_PETD_01",VR::LO,VM::VM1,"GE Advance CurvePresentation.point_color",false }, + {0x0009,0x0060,"GEMS_QVA_PHOTO_01",VR::FL,VM::VM1,"Dodge End Diastolic Volume ml",false }, + {0x0009,0x0061,"GEMS_QVA_PHOTO_01",VR::FL,VM::VM1,"Dodge End Systolic Volume ml",false }, + {0x0009,0x0062,"GEMS_QVA_PHOTO_01",VR::FL,VM::VM1,"Dodge Stroke Volume ml",false }, + {0x0009,0x0063,"GEMS_QVA_PHOTO_01",VR::IS,VM::VM1,"Dodge Ejection Fraction",false }, + {0x0009,0x0064,"GEMS_QVA_PHOTO_01",VR::FL,VM::VM1,"Simpson End Diastolic Volume ml",false }, + {0x0009,0x0065,"GEMS_QVA_PHOTO_01",VR::FL,VM::VM1,"Simpson End Systolic Volume ml",false }, + {0x0009,0x0066,"GEMS_QVA_PHOTO_01",VR::FL,VM::VM1,"Simpson Stroke Volume ml",false }, + {0x0009,0x0067,"GEMS_QVA_PHOTO_01",VR::IS,VM::VM1,"Simpson Ejection Fraction",false }, + {0x0009,0x0068,"GEMS_QVA_PHOTO_01",VR::FL,VM::VM1,"CFX Single Hypokinesia in Region",false }, + {0x0009,0x0069,"GEMS_QVA_PHOTO_01",VR::FL,VM::VM1,"CFX Single Hyperkinesia in Opposite Region",false }, + {0x0009,0x006a,"GEMS_QVA_PHOTO_01",VR::IS,VM::VM1,"CFX Single Total LV contour Percent",false }, + {0x0009,0x006b,"GEMS_QVA_PHOTO_01",VR::FL,VM::VM1,"CFX Multiple Hypokinesia in Region",false }, + {0x0009,0x006c,"GEMS_QVA_PHOTO_01",VR::FL,VM::VM1,"CFX Multiple Hyperkinesia in Opposite Region",false }, + {0x0009,0x006d,"GEMS_QVA_PHOTO_01",VR::IS,VM::VM1,"CFX Multiple Total LV contour Percent",false }, + {0x0009,0x006e,"GEMS_QVA_PHOTO_01",VR::FL,VM::VM1,"RCA Single Hypokinesia in Region",false }, + {0x0009,0x006f,"GEMS_QVA_PHOTO_01",VR::FL,VM::VM1,"RCA Single Hyperkinesia in Opposite Region",false }, + {0x0009,0x0070,"GEMS_QVA_PHOTO_01",VR::IS,VM::VM1,"RCA Single Total LV contour Percent",false }, + {0x0009,0x0071,"GEMS_QVA_PHOTO_01",VR::FL,VM::VM1,"RCA Multiple Hypokinesia in Region",false }, + {0x0009,0x0072,"GEMS_QVA_PHOTO_01",VR::FL,VM::VM1,"RCA Multiple Hyperkinesia in Opposite Region",false }, + {0x0009,0x0073,"GEMS_QVA_PHOTO_01",VR::IS,VM::VM1,"RCA Multiple Total LV contour Percent",false }, + {0x0009,0x0074,"GEMS_QVA_PHOTO_01",VR::FL,VM::VM1,"LAD Single Hypokinesia in Region",false }, + {0x0009,0x0075,"GEMS_QVA_PHOTO_01",VR::FL,VM::VM1,"LAD Single Hyperkinesia in Opposite Region",false }, + {0x0009,0x0076,"GEMS_QVA_PHOTO_01",VR::IS,VM::VM1,"LAD Single Total LV contour Percent",false }, + {0x0009,0x0077,"GEMS_QVA_PHOTO_01",VR::FL,VM::VM1,"LAD Multiple Hypokinesia in Region",false }, + {0x0009,0x0078,"GEMS_QVA_PHOTO_01",VR::FL,VM::VM1,"LAD Multiple Hyperkinesia in Opposite Region",false }, + {0x0009,0x0079,"GEMS_QVA_PHOTO_01",VR::IS,VM::VM1,"LAD Multiple Total LV contour Percent",false }, + {0x0009,0x007a,"GEMS_QVA_PHOTO_01",VR::FL,VM::VM1,"Dodge End Diastolic Volume ml/m2",false }, + {0x0009,0x007c,"GEMS_QVA_PHOTO_01",VR::FL,VM::VM1,"Dodge End Systolic Volume ml/m2",false }, + {0x0009,0x007e,"GEMS_QVA_PHOTO_01",VR::FL,VM::VM1,"Dodge Stroke Volume ml/m2",false }, + {0x0009,0x0080,"GEMS_QVA_PHOTO_01",VR::FL,VM::VM1,"Simpson End Diastolic Volume ml/m2",false }, + {0x0009,0x0082,"GEMS_QVA_PHOTO_01",VR::FL,VM::VM1,"Simpson End Systolic Volume ml/m2",false }, + {0x0009,0x0084,"GEMS_QVA_PHOTO_01",VR::FL,VM::VM1,"Simpson Stroke Volume ml/m2",false }, + {0x0021,0x0003,"GEMS_RELA_01",VR::SS,VM::VM1,"Series from which Prescribed",false }, + {0x0021,0x0005,"GEMS_RELA_01",VR::SH,VM::VM1,"Genesis Version - now",false }, + {0x0021,0x0007,"GEMS_RELA_01",VR::UL,VM::VM1,"Series Record checksum",false }, + {0x0021,0x0015,"GEMS_RELA_01",VR::US,VM::VM1,"?",false }, + {0x0021,0x0016,"GEMS_RELA_01",VR::SS,VM::VM1,"?",false }, + {0x0021,0x0018,"GEMS_RELA_01",VR::SH,VM::VM1,"Genesis version - Now",false }, + {0x0021,0x0019,"GEMS_RELA_01",VR::UL,VM::VM1,"Acq recon record checksum",false }, + {0x0021,0x0020,"GEMS_RELA_01",VR::DS,VM::VM1,"Table start location",false }, + {0x0021,0x0035,"GEMS_RELA_01",VR::SS,VM::VM1,"Series from which prescribed",false }, + {0x0021,0x0036,"GEMS_RELA_01",VR::SS,VM::VM1,"Image from which prescribed",false }, + {0x0021,0x0037,"GEMS_RELA_01",VR::SS,VM::VM1,"Screen Format",false }, + {0x0021,0x004a,"GEMS_RELA_01",VR::LO,VM::VM1,"Anatomical reference for scout",false }, + {0x0021,0x004e,"GEMS_RELA_01",VR::US,VM::VM1,"?",false }, + {0x0021,0x004f,"GEMS_RELA_01",VR::SS,VM::VM1,"Locations in acquisition",false }, + {0x0021,0x0050,"GEMS_RELA_01",VR::SS,VM::VM1,"Graphically prescribed",false }, + {0x0021,0x0051,"GEMS_RELA_01",VR::DS,VM::VM1,"Rotation from source x rot",false }, + {0x0021,0x0052,"GEMS_RELA_01",VR::DS,VM::VM1,"Rotation from source y rot",false }, + {0x0021,0x0053,"GEMS_RELA_01",VR::DS,VM::VM1,"Rotation from source z rot",false }, + {0x0021,0x0054,"GEMS_RELA_01",VR::SH,VM::VM3,"Image position",false }, + {0x0021,0x0055,"GEMS_RELA_01",VR::SH,VM::VM6,"Image orientation",false }, + {0x0021,0x0056,"GEMS_RELA_01",VR::SL,VM::VM1,"Num 3D slabs",false }, + {0x0021,0x0057,"GEMS_RELA_01",VR::SL,VM::VM1,"Locs per 3D slab",false }, + {0x0021,0x0058,"GEMS_RELA_01",VR::SL,VM::VM1,"Overlaps",false }, + {0x0021,0x0059,"GEMS_RELA_01",VR::SL,VM::VM1,"Image Filtering 0.5/0.2T",false }, + {0x0021,0x005a,"GEMS_RELA_01",VR::SL,VM::VM1,"Diffusion direction",false }, + {0x0021,0x005b,"GEMS_RELA_01",VR::DS,VM::VM1,"Tagging Flip Angle",false }, + {0x0021,0x005c,"GEMS_RELA_01",VR::DS,VM::VM1,"Tagging Orientation",false }, + {0x0021,0x005d,"GEMS_RELA_01",VR::DS,VM::VM1,"Tag Spacing",false }, + {0x0021,0x005e,"GEMS_RELA_01",VR::DS,VM::VM1,"RTIA_timer",false }, + {0x0021,0x005f,"GEMS_RELA_01",VR::DS,VM::VM1,"Fps",false }, + {0x0021,0x0070,"GEMS_RELA_01",VR::LT,VM::VM1,"?",false }, + {0x0021,0x0071,"GEMS_RELA_01",VR::LT,VM::VM1,"?",false }, + {0x0021,0x0081,"GEMS_RELA_01",VR::DS,VM::VM1,"Auto window/level alpha",false }, + {0x0021,0x0082,"GEMS_RELA_01",VR::DS,VM::VM1,"Auto window/level beta",false }, + {0x0021,0x0083,"GEMS_RELA_01",VR::DS,VM::VM1,"Auto window/level window",false }, + {0x0021,0x0084,"GEMS_RELA_01",VR::DS,VM::VM1,"Auto window/level level",false }, + {0x0021,0x0090,"GEMS_RELA_01",VR::SS,VM::VM1,"Tube focal spot position",false }, + {0x0021,0x0091,"GEMS_RELA_01",VR::SS,VM::VM1,"Biopsy position",false }, + {0x0021,0x0092,"GEMS_RELA_01",VR::FL,VM::VM1,"Biopsy T location",false }, + {0x0021,0x0093,"GEMS_RELA_01",VR::FL,VM::VM1,"Biopsy ref location",false }, + {0x0249,0x0011,"GEMS_RTEN_01",VR::DA,VM::VM1,"Plan Creation Date",false }, + {0x0249,0x0013,"GEMS_RTEN_01",VR::TM,VM::VM1,"Plan Creation Time",false }, + {0x0249,0x0014,"GEMS_RTEN_01",VR::PN,VM::VM1,"Operator Name",false }, + {0x0249,0x0016,"GEMS_RTEN_01",VR::LO,VM::VM1,"Plan Comment",false }, + {0x0249,0x0018,"GEMS_RTEN_01",VR::SQ,VM::VM1,"Plan Image Sequence",false }, + {0x0249,0x001a,"GEMS_RTEN_01",VR::LO,VM::VM1,"Exam/Series/Image Identifier",false }, + {0x0249,0x001b,"GEMS_RTEN_01",VR::IS,VM::VM1,"Additional Image Identifier",false }, + {0x0249,0x001c,"GEMS_RTEN_01",VR::CS,VM::VM1,"Build Resolution",false }, + {0x0249,0x0020,"GEMS_RTEN_01",VR::SQ,VM::VM1,"Structure Sequence",false }, + {0x0249,0x0022,"GEMS_RTEN_01",VR::SH,VM::VM1,"Structure Name",false }, + {0x0249,0x0024,"GEMS_RTEN_01",VR::CS,VM::VM1,"Structure Type",false }, + {0x0249,0x0028,"GEMS_RTEN_01",VR::CS,VM::VM1,"Structure Color",false }, + {0x0249,0x0030,"GEMS_RTEN_01",VR::SQ,VM::VM1,"Slab Sequence",false }, + {0x0249,0x0032,"GEMS_RTEN_01",VR::SQ,VM::VM1,"Slab Image Sequence",false }, + {0x0249,0x0036,"GEMS_RTEN_01",VR::DS,VM::VM1,"Z Plus Thickness",false }, + {0x0249,0x0038,"GEMS_RTEN_01",VR::DS,VM::VM1,"Z Minus Thickness",false }, + {0x0249,0x003a,"GEMS_RTEN_01",VR::DS,VM::VM3_n,"Slab Shape",false }, + {0x0249,0x0040,"GEMS_RTEN_01",VR::SQ,VM::VM1,"Marker Sequence",false }, + {0x0249,0x0042,"GEMS_RTEN_01",VR::SH,VM::VM1,"Marker Name",false }, + {0x0249,0x0044,"GEMS_RTEN_01",VR::CS,VM::VM1,"Marker Color",false }, + {0x0249,0x0046,"GEMS_RTEN_01",VR::DS,VM::VM3,"Marker Position",false }, + {0x0249,0x0050,"GEMS_RTEN_01",VR::SQ,VM::VM1,"Beam Group Sequence",false }, + {0x0249,0x0051,"GEMS_RTEN_01",VR::SH,VM::VM1,"Group Name",false }, + {0x0249,0x0052,"GEMS_RTEN_01",VR::CS,VM::VM1_n,"Group Properties",false }, + {0x0249,0x0054,"GEMS_RTEN_01",VR::SQ,VM::VM1,"Beam Sequence",false }, + {0x0249,0x0060,"GEMS_RTEN_01",VR::SQ,VM::VM1,"Machine Reference Sequence",false }, + {0x0249,0x0062,"GEMS_RTEN_01",VR::SH,VM::VM1,"Machine Name",false }, + {0x0249,0x0064,"GEMS_RTEN_01",VR::SH,VM::VM1,"Beam Name",false }, + {0x0249,0x0066,"GEMS_RTEN_01",VR::CS,VM::VM1,"Particle Type",false }, + {0x0249,0x0068,"GEMS_RTEN_01",VR::DS,VM::VM1,"Nominal Particle Energy",false }, + {0x0249,0x0070,"GEMS_RTEN_01",VR::SQ,VM::VM1,"Block Sequence",false }, + {0x0249,0x0072,"GEMS_RTEN_01",VR::LO,VM::VM1,"Block Name",false }, + {0x0249,0x0074,"GEMS_RTEN_01",VR::DS,VM::VM2_n,"Block Shape",false }, + {0x0249,0x0080,"GEMS_RTEN_01",VR::SQ,VM::VM1,"Cutout Sequence",false }, + {0x0249,0x0082,"GEMS_RTEN_01",VR::LO,VM::VM1,"Cutout Name",false }, + {0x0249,0x0084,"GEMS_RTEN_01",VR::DS,VM::VM2_n,"Cutout Shape",false }, + {0x0249,0x0090,"GEMS_RTEN_01",VR::SH,VM::VM1,"Collimator Name",false }, + {0x0249,0x0092,"GEMS_RTEN_01",VR::CS,VM::VM1,"Collimator Type",false }, + {0x0249,0x00a0,"GEMS_RTEN_01",VR::SQ,VM::VM1,"Dynamic Segment Sequence",false }, + {0x0249,0x00a2,"GEMS_RTEN_01",VR::DS,VM::VM1,"Table Angle",false }, + {0x0249,0x00a4,"GEMS_RTEN_01",VR::DS,VM::VM1,"Gantry Angle",false }, + {0x0249,0x00a6,"GEMS_RTEN_01",VR::DS,VM::VM1,"Collimator Angle",false }, + {0x0249,0x00a8,"GEMS_RTEN_01",VR::DS,VM::VM3,"Isocenter Position",false }, + {0x0249,0x00a9,"GEMS_RTEN_01",VR::DS,VM::VM1,"Source-Surface Distance",false }, + {0x0249,0x00aa,"GEMS_RTEN_01",VR::DS,VM::VM1,"X Symmetric Opening",false }, + {0x0249,0x00ac,"GEMS_RTEN_01",VR::DS,VM::VM1,"Y Symmetric Opening",false }, + {0x0249,0x00ae,"GEMS_RTEN_01",VR::DS,VM::VM1,"X Positive Jaw Position",false }, + {0x0249,0x00b0,"GEMS_RTEN_01",VR::DS,VM::VM1,"X Negative Jaw Position",false }, + {0x0249,0x00b2,"GEMS_RTEN_01",VR::DS,VM::VM1,"Y Positive Jaw Position",false }, + {0x0249,0x00b4,"GEMS_RTEN_01",VR::DS,VM::VM1,"Y Negative Jaw Position",false }, + {0x0249,0x00b6,"GEMS_RTEN_01",VR::DS,VM::VM2_n,"Leaf Positions",false }, + {0x0249,0x00d0,"GEMS_RTEN_01",VR::CS,VM::VM1,"Treatment Position",false }, + {0x0045,0x0004,"GEMS_SENO_02",VR::CS,VM::VM1,"AES",false }, + {0x0045,0x0006,"GEMS_SENO_02",VR::DS,VM::VM1,"Stereo angle",false }, + {0x0045,0x0009,"GEMS_SENO_02",VR::DS,VM::VM1,"Real Magnification Factor",false }, + {0x0045,0x000b,"GEMS_SENO_02",VR::CS,VM::VM1,"Senograph Type",false }, + {0x0045,0x000c,"GEMS_SENO_02",VR::DS,VM::VM1,"Integration Time",false }, + {0x0045,0x000d,"GEMS_SENO_02",VR::DS,VM::VM1,"ROI Origin X and Y",false }, + {0x0045,0x0011,"GEMS_SENO_02",VR::DS,VM::VM2,"Receptor Size cm X and Y",false }, + {0x0045,0x0012,"GEMS_SENO_02",VR::IS,VM::VM2,"Receptor Size Pixels X and Y",false }, + {0x0045,0x0013,"GEMS_SENO_02",VR::ST,VM::VM1,"Screen",false }, + {0x0045,0x0014,"GEMS_SENO_02",VR::DS,VM::VM1,"Pixel Pitch Microns",false }, + {0x0045,0x0015,"GEMS_SENO_02",VR::IS,VM::VM1,"Pixel Depth Bits",false }, + {0x0045,0x0016,"GEMS_SENO_02",VR::IS,VM::VM2,"Binning Factor X and Y",false }, + {0x0045,0x001b,"GEMS_SENO_02",VR::LO,VM::VM1,"Clinical View",false }, + {0x0045,0x001d,"GEMS_SENO_02",VR::DS,VM::VM1,"Mean Of Raw Gray Levels",false }, + {0x0045,0x001e,"GEMS_SENO_02",VR::DS,VM::VM1,"Mean Of Offset Gray Levels",false }, + {0x0045,0x001f,"GEMS_SENO_02",VR::DS,VM::VM1,"Mean Of Corrected Gray Levels",false }, + {0x0045,0x0020,"GEMS_SENO_02",VR::DS,VM::VM1,"Estimated Anat mean",false }, + {0x0045,0x0021,"GEMS_SENO_02",VR::DS,VM::VM1,"Mean Of Log Region Gray Levels",false }, + {0x0045,0x0022,"GEMS_SENO_02",VR::DS,VM::VM1,"Standard Deviation Of Raw Gray Levels",false }, + {0x0045,0x0023,"GEMS_SENO_02",VR::DS,VM::VM1,"Standard Deviation Of Corrected Gray Levels",false }, + {0x0045,0x0024,"GEMS_SENO_02",VR::DS,VM::VM1,"Standard Deviation Of Region Gray Levels",false }, + {0x0045,0x0025,"GEMS_SENO_02",VR::DS,VM::VM1,"Standard Deviation Of Log Region Gray Levels",false }, + {0x0045,0x0026,"GEMS_SENO_02",VR::OB,VM::VM1,"MAO Buffer",false }, + {0x0045,0x0027,"GEMS_SENO_02",VR::IS,VM::VM1,"Set Number",false }, + {0x0045,0x0028,"GEMS_SENO_02",VR::CS,VM::VM1,"WindowingType (LINEAR or GAMMA)",false }, + {0x0045,0x0029,"GEMS_SENO_02",VR::DS,VM::VM2,"Windowing parameters",false }, + {0x0045,0x002a,"GEMS_SENO_02",VR::IS,VM::VM1,"2DLocX",false }, + {0x0045,0x002b,"GEMS_SENO_02",VR::IS,VM::VM1,"2DLocY",false }, + {0x0045,0x0039,"GEMS_SENO_02",VR::US,VM::VM1,"Vignette Rows",false }, + {0x0045,0x003a,"GEMS_SENO_02",VR::US,VM::VM1,"Vignette Columns",false }, + {0x0045,0x003b,"GEMS_SENO_02",VR::US,VM::VM1,"Vignette Bits Allocated",false }, + {0x0045,0x003c,"GEMS_SENO_02",VR::US,VM::VM1,"Vignette Bits Stored",false }, + {0x0045,0x003d,"GEMS_SENO_02",VR::US,VM::VM1,"Vignette High Bit",false }, + {0x0045,0x003e,"GEMS_SENO_02",VR::US,VM::VM1,"Vignette Pixel Representation",false }, + {0x0045,0x003f,"GEMS_SENO_02",VR::OB,VM::VM1,"Vignette Pixel Data",false }, + {0x0045,0x0049,"GEMS_SENO_02",VR::DS,VM::VM1,"Radiological Thickness",false }, + {0x0045,0x0050,"GEMS_SENO_02",VR::UI,VM::VM1,"SC Instance UID",false }, + {0x0045,0x0051,"GEMS_SENO_02",VR::UI,VM::VM1,"SC series UID",false }, + {0x0045,0x0052,"GEMS_SENO_02",VR::IS,VM::VM1,"Raw Diagnostic Low",false }, + {0x0045,0x0053,"GEMS_SENO_02",VR::IS,VM::VM1,"Raw Diagnostic High",false }, + {0x0045,0x0054,"GEMS_SENO_02",VR::DS,VM::VM1,"Exponent",false }, + {0x0045,0x0055,"GEMS_SENO_02",VR::IS,VM::VM1,"A Coefficients",false }, + {0x0045,0x0056,"GEMS_SENO_02",VR::DS,VM::VM1,"Noise Reduction Sensitivity",false }, + {0x0045,0x0057,"GEMS_SENO_02",VR::DS,VM::VM1,"Noise Reduction Threshold",false }, + {0x0045,0x0058,"GEMS_SENO_02",VR::DS,VM::VM1,"mu",false }, + {0x0045,0x0059,"GEMS_SENO_02",VR::IS,VM::VM1,"Threshold",false }, + {0x0045,0x0060,"GEMS_SENO_02",VR::IS,VM::VM4,"Breast ROI X",false }, + {0x0045,0x0061,"GEMS_SENO_02",VR::IS,VM::VM4,"Breast ROI Y",false }, + {0x0045,0x0062,"GEMS_SENO_02",VR::IS,VM::VM1,"User Window Center",false }, + {0x0045,0x0063,"GEMS_SENO_02",VR::IS,VM::VM1,"User Window Width",false }, + {0x0045,0x0064,"GEMS_SENO_02",VR::IS,VM::VM1,"Segm Threshold",false }, + {0x0045,0x0065,"GEMS_SENO_02",VR::IS,VM::VM1,"Detector Entrance Dose",false }, + {0x0045,0x0066,"GEMS_SENO_02",VR::IS,VM::VM1,"Asymmetrical Collimation Information",false }, + {0x0045,0x0071,"GEMS_SENO_02",VR::OB,VM::VM1,"STX buffer",false }, + {0x0045,0x0072,"GEMS_SENO_02",VR::DS,VM::VM2,"Image Crop point",false }, + {0x0025,0x0006,"GEMS_SERS_01",VR::SS,VM::VM1,"Last pulse sequence used",false }, + {0x0025,0x0007,"GEMS_SERS_01",VR::SL,VM::VM1,"Images in Series",false }, + {0x0025,0x0010,"GEMS_SERS_01",VR::SL,VM::VM1,"Landmark Counter",false }, + {0x0025,0x0011,"GEMS_SERS_01",VR::SS,VM::VM1,"Number of Acquisitions",false }, + {0x0025,0x0014,"GEMS_SERS_01",VR::SL,VM::VM1,"Indicates no. of updates to header",false }, + {0x0025,0x0017,"GEMS_SERS_01",VR::SL,VM::VM1,"Series Complete Flag",false }, + {0x0025,0x0018,"GEMS_SERS_01",VR::SL,VM::VM1,"Number of images archived",false }, + {0x0025,0x0019,"GEMS_SERS_01",VR::SL,VM::VM1,"Last image number used",false }, + {0x0025,0x001a,"GEMS_SERS_01",VR::SH,VM::VM1,"Primary Receiver Suite and Host",false }, + {0x0025,0x001b,"GEMS_SERS_01",VR::OB,VM::VM1,"Protocol Data Block (compressed)",false }, + {0x0023,0x0001,"GEMS_STDY_01",VR::SL,VM::VM1,"Number of series in Study",false }, + {0x0023,0x0002,"GEMS_STDY_01",VR::SL,VM::VM1,"Number of unarchived Series",false }, + {0x0023,0x0010,"GEMS_STDY_01",VR::SS,VM::VM1,"Reference image field",false }, + {0x0023,0x0050,"GEMS_STDY_01",VR::SS,VM::VM1,"Summary image",false }, + {0x0023,0x0070,"GEMS_STDY_01",VR::FD,VM::VM1,"Start time(secs) in first axial",false }, + {0x0023,0x0074,"GEMS_STDY_01",VR::SL,VM::VM1,"No. of updates to header",false }, + {0x0023,0x007d,"GEMS_STDY_01",VR::SS,VM::VM1,"Indicates study has complete info (DICOM/genesis)",false }, + {0x0023,0x0080,"GEMS_STDY_01",VR::SQ,VM::VM1,"Has MPPS related tags",false }, + {0x6003,0x0005,"GEMS_Ultrasound_ImageGroup_001",VR::LT,VM::VM1_n,"GEMS Image Information",false }, + {0x6003,0x0010,"GEMS_Ultrasound_ImageGroup_001",VR::SQ,VM::VM1,"GEMS Image Thumbnail Sequence",false }, + {0x6003,0x0011,"GEMS_Ultrasound_ImageGroup_001",VR::OB,VM::VM1,"GEMS Thumbnail Pixel Data (uncompressed)",false }, + {0x7fe1,0x0001,"GEMS_Ultrasound_MovieGroup_001",VR::SQ,VM::VM1,"?",false }, + {0x7fe1,0x0002,"GEMS_Ultrasound_MovieGroup_001",VR::LO,VM::VM1,"US MovieGroup Value 0008 Name",false }, + {0x7fe1,0x0003,"GEMS_Ultrasound_MovieGroup_001",VR::UL,VM::VM1,"?",false }, + {0x7fe1,0x0008,"GEMS_Ultrasound_MovieGroup_001",VR::SQ,VM::VM1,"US MovieGroup Value 0008 Sequence",false }, + {0x7fe1,0x0010,"GEMS_Ultrasound_MovieGroup_001",VR::SQ,VM::VM1,"?",false }, + {0x7fe1,0x0012,"GEMS_Ultrasound_MovieGroup_001",VR::LO,VM::VM1,"US MovieGroup Value 0018 Name",false }, + {0x7fe1,0x0018,"GEMS_Ultrasound_MovieGroup_001",VR::SQ,VM::VM1,"US MovieGroup Value 0018 Sequence",false }, + {0x7fe1,0x0020,"GEMS_Ultrasound_MovieGroup_001",VR::SQ,VM::VM1,"?",false }, + {0x7fe1,0x0024,"GEMS_Ultrasound_MovieGroup_001",VR::SH,VM::VM1,"US MovieGroup Value 0026 Name",false }, + {0x7fe1,0x0026,"GEMS_Ultrasound_MovieGroup_001",VR::SQ,VM::VM1,"US MovieGroup Value 0026 Sequence",false }, + {0x7fe1,0x0030,"GEMS_Ultrasound_MovieGroup_001",VR::LO,VM::VM1,"?",false }, + {0x7fe1,0x0032,"GEMS_Ultrasound_MovieGroup_001",VR::UL,VM::VM1,"?",false }, + {0x7fe1,0x0036,"GEMS_Ultrasound_MovieGroup_001",VR::SQ,VM::VM1,"?",false }, + {0x7fe1,0x0037,"GEMS_Ultrasound_MovieGroup_001",VR::UL,VM::VM1,"US MovieGroup Number of Frames",false }, + {0x7fe1,0x003a,"GEMS_Ultrasound_MovieGroup_001",VR::SQ,VM::VM1,"?",false }, + {0x7fe1,0x003c,"GEMS_Ultrasound_MovieGroup_001",VR::FD,VM::VM1,"?",false }, + {0x7fe1,0x0043,"GEMS_Ultrasound_MovieGroup_001",VR::OB,VM::VM1,"?",false }, + {0x7fe1,0x0048,"GEMS_Ultrasound_MovieGroup_001",VR::FD,VM::VM1_2,"US MovieGroup Value Index",false }, + {0x7fe1,0x0049,"GEMS_Ultrasound_MovieGroup_001",VR::UL,VM::VM1,"US MovieGroup Value UL/1",false }, + {0x7fe1,0x0051,"GEMS_Ultrasound_MovieGroup_001",VR::FL,VM::VM1,"US MovieGroup Value FL/1",false }, + {0x7fe1,0x0052,"GEMS_Ultrasound_MovieGroup_001",VR::FD,VM::VM1,"US MovieGroup Value FD/1",false }, + {0x7fe1,0x0053,"GEMS_Ultrasound_MovieGroup_001",VR::UL,VM::VM1,"US MovieGroup Value UL/1",false }, + {0x7fe1,0x0054,"GEMS_Ultrasound_MovieGroup_001",VR::SL,VM::VM1,"US MovieGroup Value SL/1",false }, + {0x7fe1,0x0055,"GEMS_Ultrasound_MovieGroup_001",VR::OB,VM::VM1,"US MovieGroup Value OB/1",false }, + {0x7fe1,0x0057,"GEMS_Ultrasound_MovieGroup_001",VR::LT,VM::VM1,"US MovieGroup Value LT/1",false }, + {0x7fe1,0x0060,"GEMS_Ultrasound_MovieGroup_001",VR::OB,VM::VM1,"US MovieGroup Image Data",false }, + {0x7fe1,0x0061,"GEMS_Ultrasound_MovieGroup_001",VR::OW,VM::VM1,"?",false }, + {0x7fe1,0x0069,"GEMS_Ultrasound_MovieGroup_001",VR::OW,VM::VM1,"?",false }, + {0x7fe1,0x0070,"GEMS_Ultrasound_MovieGroup_001",VR::SQ,VM::VM1,"US MovieGroup Dict",false }, + {0x7fe1,0x0071,"GEMS_Ultrasound_MovieGroup_001",VR::UL,VM::VM1,"US MovieGroup Dict Index",false }, + {0x7fe1,0x0072,"GEMS_Ultrasound_MovieGroup_001",VR::LO,VM::VM1,"US MovieGroup Dict Name",false }, + {0x7fe1,0x0073,"GEMS_Ultrasound_MovieGroup_001",VR::SQ,VM::VM1,"?",false }, + {0x7fe1,0x0074,"GEMS_Ultrasound_MovieGroup_001",VR::LO,VM::VM1,"?",false }, + {0x7fe1,0x0075,"GEMS_Ultrasound_MovieGroup_001",VR::SQ,VM::VM1,"?",false }, + {0x7fe1,0x0077,"GEMS_Ultrasound_MovieGroup_001",VR::FD,VM::VM1_n,"US MovieGroup Value FD/1-N",false }, + {0x7fe1,0x0079,"GEMS_Ultrasound_MovieGroup_001",VR::SL,VM::VM1_n,"US MovieGroup Value SL/1-N",false }, + {0x7fe1,0x0083,"GEMS_Ultrasound_MovieGroup_001",VR::SQ,VM::VM1,"?",false }, + {0x7fe1,0x0084,"GEMS_Ultrasound_MovieGroup_001",VR::LO,VM::VM1,"US MovieGroup Value 0085 Name",false }, + {0x7fe1,0x0085,"GEMS_Ultrasound_MovieGroup_001",VR::SQ,VM::VM1,"US MovieGroup Value 0085 Sequence",false }, + {0x7fe1,0x0086,"GEMS_Ultrasound_MovieGroup_001",VR::SL,VM::VM4,"US MovieGroup Value SL/4",false }, + {0x7fe1,0x0087,"GEMS_Ultrasound_MovieGroup_001",VR::FD,VM::VM4,"US MovieGroup Value FD/4",false }, + {0x7fe1,0x0088,"GEMS_Ultrasound_MovieGroup_001",VR::FD,VM::VM2,"US MovieGroup Value FD/2",false }, + {0x0057,0x0005,"GEMS_VXTLSTATE_001",VR::SQ,VM::VM1,"Volumes_info",false }, + {0x0057,0x0006,"GEMS_VXTLSTATE_001",VR::SQ,VM::VM1,"Image_UIDs",false }, + {0x0057,0x0007,"GEMS_VXTLSTATE_001",VR::DT,VM::VM1,"SUV_ScanTime",false }, + {0x0057,0x0008,"GEMS_VXTLSTATE_001",VR::DT,VM::VM1,"SUV_AdministredTime",false }, + {0x0057,0x0009,"GEMS_VXTLSTATE_001",VR::DT,VM::VM1,"SUV_MeasuredTime",false }, + {0x0057,0x0010,"GEMS_VXTLSTATE_001",VR::DT,VM::VM1,"SUV_PostInjectedTime",false }, + {0x0057,0x0011,"GEMS_VXTLSTATE_001",VR::FL,VM::VM1,"SUV_TracerActivity",false }, + {0x0057,0x0012,"GEMS_VXTLSTATE_001",VR::FL,VM::VM1,"SUV_PostInjectedActivity",false }, + {0x0057,0x0013,"GEMS_VXTLSTATE_001",VR::FL,VM::VM1,"SUV_HalfLife",false }, + {0x0057,0x0014,"GEMS_VXTLSTATE_001",VR::LO,VM::VM1,"SState_Version",false }, + {0x0057,0x0015,"GEMS_VXTLSTATE_001",VR::SQ,VM::VM1,"SegList_Seq",false }, + {0x0057,0x0016,"GEMS_VXTLSTATE_001",VR::IS,VM::VM1,"SegList_Count",false }, + {0x0057,0x0017,"GEMS_VXTLSTATE_001",VR::OB,VM::VM1,"SegList_List",false }, + {0x0057,0x0018,"GEMS_VXTLSTATE_001",VR::LO,VM::VM1,"SegList_Name",false }, + {0x0057,0x0019,"GEMS_VXTLSTATE_001",VR::LO,VM::VM1,"Volume_Filename",false }, + {0x0057,0x0020,"GEMS_VXTLSTATE_001",VR::LO,VM::VM1,"SegList_Label",false }, + {0x0057,0x0021,"GEMS_VXTLSTATE_001",VR::SQ,VM::VM1,"Bookmark_Seq",false }, + {0x0057,0x0022,"GEMS_VXTLSTATE_001",VR::LT,VM::VM1,"Bookmark",false }, + {0x0057,0x0023,"GEMS_VXTLSTATE_001",VR::FL,VM::VM3,"Cursor_position",false }, + {0x0057,0x0024,"GEMS_VXTLSTATE_001",VR::UL,VM::VM3_n,"Color_Value_Field",false }, + {0x0057,0x0025,"GEMS_VXTLSTATE_001",VR::IS,VM::VM1,"Count",false }, + {0x0057,0x0026,"GEMS_VXTLSTATE_001",VR::SQ,VM::VM1,"Views_info",false }, + {0x0057,0x0027,"GEMS_VXTLSTATE_001",VR::LT,VM::VM1,"View_Slot",false }, + {0x0057,0x0028,"GEMS_VXTLSTATE_001",VR::IS,VM::VM1,"Wireframe_Size",false }, + {0x0057,0x0029,"GEMS_VXTLSTATE_001",VR::UT,VM::VM1,"Wireframe",false }, + {0x0057,0x0030,"GEMS_VXTLSTATE_001",VR::IS,VM::VM1,"Annotation_Size",false }, + {0x0057,0x0031,"GEMS_VXTLSTATE_001",VR::LT,VM::VM1,"Annotation",false }, + {0x0057,0x0032,"GEMS_VXTLSTATE_001",VR::IS,VM::VM1,"Slider_State",false }, + {0x0057,0x0033,"GEMS_VXTLSTATE_001",VR::LO,VM::VM1,"Proto_Name",false }, + {0x0057,0x0034,"GEMS_VXTLSTATE_001",VR::LO,VM::VM1,"Proto_Title",false }, + {0x0057,0x0035,"GEMS_VXTLSTATE_001",VR::LO,VM::VM1,"Proto_FilmName",false }, + {0x0057,0x0036,"GEMS_VXTLSTATE_001",VR::LO,VM::VM1,"Proto_Step",false }, + {0x0057,0x0038,"GEMS_VXTLSTATE_001",VR::LT,VM::VM1,"SegList_Slots",false }, + {0x0057,0x0039,"GEMS_VXTLSTATE_001",VR::IS,VM::VM1,"VT_Points_Size",false }, + {0x0057,0x0040,"GEMS_VXTLSTATE_001",VR::LT,VM::VM1,"VT_Points",false }, + {0x0057,0x0041,"GEMS_VXTLSTATE_001",VR::IS,VM::VM1,"VT_Meas_Size",false }, + {0x0057,0x0042,"GEMS_VXTLSTATE_001",VR::LT,VM::VM1,"VT_Meas",false }, + {0x0057,0x0043,"GEMS_VXTLSTATE_001",VR::IS,VM::VM1,"VT_Tree_Size",false }, + {0x0057,0x0044,"GEMS_VXTLSTATE_001",VR::UT,VM::VM1,"VT_Tree",false }, + {0x0057,0x0046,"GEMS_VXTLSTATE_001",VR::IS,VM::VM1,"VT_Preset_Size",false }, + {0x0057,0x0047,"GEMS_VXTLSTATE_001",VR::LT,VM::VM1,"VT_Preset",false }, + {0x0057,0x0048,"GEMS_VXTLSTATE_001",VR::IS,VM::VM1,"VT_State_Size",false }, + {0x0057,0x0049,"GEMS_VXTLSTATE_001",VR::LT,VM::VM1,"VT_State",false }, + {0x0057,0x0050,"GEMS_VXTLSTATE_001",VR::IS,VM::VM1,"Preferences_Size",false }, + {0x0057,0x0051,"GEMS_VXTLSTATE_001",VR::LT,VM::VM1,"Preferences",false }, + {0x0057,0x0052,"GEMS_VXTLSTATE_001",VR::IS,VM::VM1,"Volume_ZComb_Filter",false }, + {0x0057,0x0053,"GEMS_VXTLSTATE_001",VR::IS,VM::VM1,"HTML_Page_Size",false }, + {0x0057,0x0054,"GEMS_VXTLSTATE_001",VR::LT,VM::VM1,"HTML_Page",false }, + {0x0057,0x0055,"GEMS_VXTLSTATE_001",VR::FL,VM::VM3,"Camera_Position",false }, + {0x0057,0x0056,"GEMS_VXTLSTATE_001",VR::IS,VM::VM1,"Slider_Size",false }, + {0x0057,0x0057,"GEMS_VXTLSTATE_001",VR::LT,VM::VM1,"Slider",false }, + {0x0057,0x0058,"GEMS_VXTLSTATE_001",VR::LO,VM::VM1,"SegList_Pretty_Name",false }, + {0x0047,0x0011,"GEMS_VXTL_USERDATA_01",VR::LT,VM::VM1,"?",false }, + {0x0033,0x0008,"GEMS_XELPRV_01",VR::CS,VM::VM1,"Object Type",false }, + {0x0033,0x0010,"GEMS_XELPRV_01",VR::SL,VM::VM1,"Modified",false }, + {0x0033,0x0011,"GEMS_XELPRV_01",VR::LO,VM::VM1,"Name",false }, + {0x0033,0x0014,"GEMS_XELPRV_01",VR::LO,VM::VM1,"StudyId",false }, + {0x0033,0x0016,"GEMS_XELPRV_01",VR::LO,VM::VM1,"ProtocolDataUID",false }, + {0x0033,0x0017,"GEMS_XELPRV_01",VR::SH,VM::VM1,"Date",false }, + {0x0033,0x0018,"GEMS_XELPRV_01",VR::SH,VM::VM1,"Time",false }, + {0x0033,0x0019,"GEMS_XELPRV_01",VR::UL,VM::VM1,"ProtocoldataFlags",false }, + {0x0033,0x001a,"GEMS_XELPRV_01",VR::LO,VM::VM1,"ProtocolName",false }, + {0x0033,0x001b,"GEMS_XELPRV_01",VR::LO,VM::VM1,"StudyId",false }, + {0x0033,0x001c,"GEMS_XELPRV_01",VR::OB,VM::VM1,"BulkData",false }, + {0x0033,0x001d,"GEMS_XELPRV_01",VR::SL,VM::VM1_n,"IntData",false }, + {0x0033,0x001e,"GEMS_XELPRV_01",VR::FD,VM::VM1_n,"DoubleData",false }, + {0x0033,0x001f,"GEMS_XELPRV_01",VR::OB,VM::VM1,"StringData",false }, + {0x0033,0x0020,"GEMS_XELPRV_01",VR::OB,VM::VM1,"BulkDataFormat",false }, + {0x0033,0x0021,"GEMS_XELPRV_01",VR::OB,VM::VM1,"IntDataFormat",false }, + {0x0033,0x0022,"GEMS_XELPRV_01",VR::OB,VM::VM1,"DoubleDataFormat",false }, + {0x0033,0x0023,"GEMS_XELPRV_01",VR::OB,VM::VM1,"StringDataFormat",false }, + {0x0033,0x0024,"GEMS_XELPRV_01",VR::LT,VM::VM1,"Description",false }, + {0x0033,0x0028,"GEMS_XELPRV_01",VR::LO,VM::VM1,"RTName",false }, + {0x0033,0x0029,"GEMS_XELPRV_01",VR::LT,VM::VM1,"RTSpecification",false }, + {0x0033,0x002a,"GEMS_XELPRV_01",VR::UL,VM::VM1,"ReviewTemplatesFlags",false }, + {0x0033,0x002b,"GEMS_XELPRV_01",VR::LT,VM::VM1,"DataValidationSpec",false }, + {0x0033,0x002c,"GEMS_XELPRV_01",VR::LT,VM::VM1,"Description",false }, + {0x0033,0x002d,"GEMS_XELPRV_01",VR::LT,VM::VM1,"IconDescription",false }, + {0x0033,0x0050,"GEMS_XELPRV_01",VR::SQ,VM::VM1,"ProtocoldataSQ",false }, + {0x0033,0x0051,"GEMS_XELPRV_01",VR::UI,VM::VM1,"PDOSOPClassUID",false }, + {0x0033,0x0052,"GEMS_XELPRV_01",VR::UI,VM::VM1,"PDOSOPInstanceUID",false }, + {0x0033,0x0060,"GEMS_XELPRV_01",VR::SQ,VM::VM1,"ReviewtemplateSQ",false }, + {0x0033,0x0061,"GEMS_XELPRV_01",VR::UI,VM::VM1,"RTOSOPClassUID",false }, + {0x0033,0x0062,"GEMS_XELPRV_01",VR::UI,VM::VM1,"RTOSOPInstanceUID",false }, + {0x0033,0x0070,"GEMS_XELPRV_01",VR::SQ,VM::VM1,"SeriesdataSQ",false }, + {0x0033,0x0071,"GEMS_XELPRV_01",VR::UI,VM::VM1,"SDOSOPClassUID",false }, + {0x0033,0x0072,"GEMS_XELPRV_01",VR::UI,VM::VM1,"SDOSOPInstanceUID",false }, + {0x0033,0x0073,"GEMS_XELPRV_01",VR::SQ,VM::VM1,"SDODoubleDataSQ",false }, + {0x0057,0x0001,"GEMS_XELPRV_01",VR::SQ,VM::VM1,"ROISQ",false }, + {0x0057,0x0002,"GEMS_XELPRV_01",VR::UI,VM::VM1,"SOPClassUID",false }, + {0x0057,0x0003,"GEMS_XELPRV_01",VR::UI,VM::VM1,"SOPInstanceUID",false }, + {0x0057,0x0010,"GEMS_XELPRV_01",VR::IS,VM::VM1,"ROINumber",false }, + {0x0057,0x0011,"GEMS_XELPRV_01",VR::UI,VM::VM1,"Dimentions",false }, + {0x0057,0x0012,"GEMS_XELPRV_01",VR::UI,VM::VM1,"Points",false }, + {0x0057,0x0013,"GEMS_XELPRV_01",VR::UI,VM::VM1,"Type",false }, + {0x0057,0x0014,"GEMS_XELPRV_01",VR::UI,VM::VM1,"Description",false }, + {0x0057,0x0015,"GEMS_XELPRV_01",VR::UI,VM::VM1,"Data value Representation",false }, + {0x0057,0x0016,"GEMS_XELPRV_01",VR::UI,VM::VM1,"Label",false }, + {0x0057,0x0017,"GEMS_XELPRV_01",VR::UI,VM::VM1,"Data",false }, + {0x0057,0x0041,"GEMS_XELPRV_01",VR::SL,VM::VM1,"Modified",false }, + {0x0057,0x0042,"GEMS_XELPRV_01",VR::LO,VM::VM1,"Name",false }, + {0x0057,0x0043,"GEMS_XELPRV_01",VR::SL,VM::VM1,"Rid",false }, + {0x0057,0x0045,"GEMS_XELPRV_01",VR::LO,VM::VM1,"SOPClassUID",false }, + {0x0057,0x0046,"GEMS_XELPRV_01",VR::LO,VM::VM1,"SOPInstanceUID",false }, + {0x0057,0x0047,"GEMS_XELPRV_01",VR::LO,VM::VM1,"Normal Colour",false }, + {0x0057,0x0048,"GEMS_XELPRV_01",VR::LT,VM::VM1,"NameFont",false }, + {0x0057,0x0049,"GEMS_XELPRV_01",VR::SL,VM::VM1,"FillPattern",false }, + {0x0057,0x004a,"GEMS_XELPRV_01",VR::SL,VM::VM1,"LineStyle",false }, + {0x0057,0x004b,"GEMS_XELPRV_01",VR::SL,VM::VM1,"LineDashLength",false }, + {0x0057,0x004c,"GEMS_XELPRV_01",VR::SL,VM::VM1,"LineThickness",false }, + {0x0057,0x004d,"GEMS_XELPRV_01",VR::SL,VM::VM1,"Interactivity",false }, + {0x0057,0x004e,"GEMS_XELPRV_01",VR::SL,VM::VM1,"NamePos",false }, + {0x0057,0x004f,"GEMS_XELPRV_01",VR::SL,VM::VM1,"NameDisplay",false }, + {0x0057,0x0050,"GEMS_XELPRV_01",VR::LO,VM::VM1,"Label",false }, + {0x0057,0x0051,"GEMS_XELPRV_01",VR::SL,VM::VM1_n,"BpSeg",false }, + {0x0057,0x0052,"GEMS_XELPRV_01",VR::US,VM::VM1_n,"BpSegpairs",false }, + {0x0057,0x0053,"GEMS_XELPRV_01",VR::SL,VM::VM1,"SeedSpace",false }, + {0x0057,0x0054,"GEMS_XELPRV_01",VR::FD,VM::VM1_n,"Seeds",false }, + {0x0057,0x0055,"GEMS_XELPRV_01",VR::SL,VM::VM1_n,"Shape",false }, + {0x0057,0x0056,"GEMS_XELPRV_01",VR::FD,VM::VM1_n,"ShapeTilt",false }, + {0x0057,0x0059,"GEMS_XELPRV_01",VR::SL,VM::VM1_n,"ShapePtsSpace",false }, + {0x0057,0x005a,"GEMS_XELPRV_01",VR::SL,VM::VM1_n,"ShapeCtrlPtsCount",false }, + {0x0057,0x005b,"GEMS_XELPRV_01",VR::FD,VM::VM1_n,"Shap CtrlPts",false }, + {0x0057,0x005c,"GEMS_XELPRV_01",VR::SL,VM::VM1,"ShapeCPSpace",false }, + {0x0057,0x005d,"GEMS_XELPRV_01",VR::UL,VM::VM1_n,"ROIFlags",false }, + {0x0057,0x005e,"GEMS_XELPRV_01",VR::UL,VM::VM1,"FrameNumber",false }, + {0x0057,0x0060,"GEMS_XELPRV_01",VR::LO,VM::VM1_n,"DatasetROIMapping",false }, + {0x0021,0x0001,"GEMS_XR3DCAL_01",VR::IS,VM::VM1,"3Dcal image rows",false }, + {0x0021,0x0002,"GEMS_XR3DCAL_01",VR::IS,VM::VM1,"3Dcal image columns",false }, + {0x0021,0x0003,"GEMS_XR3DCAL_01",VR::FL,VM::VM1,"3Dcal field of view",false }, + {0x0021,0x0004,"GEMS_XR3DCAL_01",VR::DA,VM::VM1,"3Dcal acquisition date",false }, + {0x0021,0x0005,"GEMS_XR3DCAL_01",VR::TM,VM::VM1,"3Dcal acquisition time",false }, + {0x0021,0x0006,"GEMS_XR3DCAL_01",VR::DA,VM::VM1,"3Dcal calibration processing date",false }, + {0x0021,0x0007,"GEMS_XR3DCAL_01",VR::TM,VM::VM1,"3Dcal calibration processing time",false }, + {0x0021,0x0008,"GEMS_XR3DCAL_01",VR::FL,VM::VM1,"3Dcal L arm angle",false }, + {0x0021,0x0009,"GEMS_XR3DCAL_01",VR::FL,VM::VM1_n,"3Dcal Pivot angle vector",false }, + {0x0021,0x000a,"GEMS_XR3DCAL_01",VR::FL,VM::VM1,"3Dcal C arm angle",false }, + {0x0021,0x000b,"GEMS_XR3DCAL_01",VR::SQ,VM::VM1,"3Dcal matrix sequence",false }, + {0x0021,0x000c,"GEMS_XR3DCAL_01",VR::LO,VM::VM1_n,"3Dcal matrix elements",false }, + {0x0021,0x000d,"GEMS_XR3DCAL_01",VR::LO,VM::VM1,"3Dcal algorithm version",false }, + {0x0021,0x000e,"GEMS_XR3DCAL_01",VR::FL,VM::VM1,"3Dcal 3D frame unit size",false }, + {0x0021,0x000f,"GEMS_XR3DCAL_01",VR::LO,VM::VM1,"3Dcal calibration mode",false }, + {0x0021,0x0010,"GEMS_XR3DCAL_01",VR::FL,VM::VM1,"3Dcal image frame origin row",false }, + {0x0021,0x0011,"GEMS_XR3DCAL_01",VR::FL,VM::VM1,"3Dcal image frame origin column",false }, + {0x0021,0x0012,"GEMS_XR3DCAL_01",VR::IS,VM::VM1,"3Dcal positioner pivot rotation speed",false }, + {0x0021,0x0013,"GEMS_XR3DCAL_01",VR::IS,VM::VM1,"3Dcal number of images",false }, + {0x0021,0x0014,"GEMS_XR3DCAL_01",VR::UI,VM::VM1,"3Dcal Instance UID",false }, + {0x0021,0x0015,"GEMS_XR3DCAL_01",VR::FL,VM::VM2,"3Dcal image pixel spacing",false }, + {0x0021,0x0016,"GEMS_XR3DCAL_01",VR::CS,VM::VM1,"3Dcal centering mode",false }, + {0x0033,0x0005,"GEMS_YMHD_01",VR::UN,VM::VM1,"?",false }, + {0x0033,0x0006,"GEMS_YMHD_01",VR::UN,VM::VM1,"?",false }, + {0x0019,0x0039,"GE_GENESIS_REV3.0",VR::SS,VM::VM1,"Axial Type",false }, + {0x0019,0x008f,"GE_GENESIS_REV3.0",VR::SS,VM::VM1,"Swap Phase / Frequency Axis",false }, + {0x0019,0x009c,"GE_GENESIS_REV3.0",VR::SS,VM::VM1,"Pulse Sequence Name",false }, + {0x0019,0x009f,"GE_GENESIS_REV3.0",VR::SS,VM::VM1,"Coil Type",false }, + {0x0019,0x00a4,"GE_GENESIS_REV3.0",VR::SS,VM::VM1,"SAT fat/water/none",false }, + {0x0019,0x00c0,"GE_GENESIS_REV3.0",VR::SS,VM::VM1,"Bitmap of SAT Selections",false }, + {0x0019,0x00c1,"GE_GENESIS_REV3.0",VR::SS,VM::VM1,"Surfacel Coil Iintensity Correction Flag",false }, + {0x0019,0x00cb,"GE_GENESIS_REV3.0",VR::SS,VM::VM1,"Phase Contrast Flow Axis",false }, + {0x0019,0x00cc,"GE_GENESIS_REV3.0",VR::SS,VM::VM1,"Phase Contrast Velocity Encoding",false }, + {0x0019,0x00d5,"GE_GENESIS_REV3.0",VR::SS,VM::VM1,"Fractional Echo",false }, + {0x0019,0x00d8,"GE_GENESIS_REV3.0",VR::SS,VM::VM1,"Variable Echo Flag",false }, + {0x0019,0x00d9,"GE_GENESIS_REV3.0",VR::DS,VM::VM1,"Concatenated Sat",false }, + {0x0019,0x00f2,"GE_GENESIS_REV3.0",VR::SS,VM::VM1,"Number of Phases",false }, + {0x0043,0x001e,"GE_GENESIS_REV3.0",VR::DS,VM::VM1,"Delta Start Time",false }, + {0x0043,0x0027,"GE_GENESIS_REV3.0",VR::SH,VM::VM1,"Pitch Ratio",false }, + {0x6005,0x0010,"GE_GROUP",VR::UT,VM::VM1,"?",false }, + {0x0009,0x0000,"HMC - CT - ID",VR::UN,VM::VM1,"Image ID Information (e.g. Patient Name, Patient ID)",false }, + {0x0009,0x0001,"HMC - CT - ID",VR::UN,VM::VM1,"Image ID Information (e.g. Patient Comment)",false }, + {0x0011,0x0000,"HOLOGIC",VR::LO,VM::VM1,"Hx Questionnaire",false }, + {0x0021,0x0001,"HOLOGIC",VR::LT,VM::VM1,"Image Analysis Data in XML",false }, + {0x0023,0x0000,"HOLOGIC",VR::LO,VM::VM1,"Encoding Scheme Version",false }, + {0x0023,0x0001,"HOLOGIC",VR::LO,VM::VM1,"P File Name",false }, + {0x0023,0x0002,"HOLOGIC",VR::OB,VM::VM1,"P File Data",false }, + {0x0023,0x0003,"HOLOGIC",VR::UL,VM::VM1,"P File Length",false }, + {0x0023,0x0004,"HOLOGIC",VR::OB,VM::VM1,"R File Data",false }, + {0x0023,0x0005,"HOLOGIC",VR::UL,VM::VM1,"R File Length",false }, + {0x0019,0x0006,"HOLOGIC, Inc.",VR::LO,VM::VM1,"?",false }, + {0x0019,0x0007,"HOLOGIC, Inc.",VR::SH,VM::VM1,"?",false }, + {0x0019,0x0008,"HOLOGIC, Inc.",VR::LO,VM::VM1,"?",false }, + {0x0019,0x0016,"HOLOGIC, Inc.",VR::DS,VM::VM1,"?",false }, + {0x0019,0x0025,"HOLOGIC, Inc.",VR::SH,VM::VM1,"?",false }, + {0x0019,0x0026,"HOLOGIC, Inc.",VR::LO,VM::VM1,"?",false }, + {0x0019,0x0027,"HOLOGIC, Inc.",VR::SH,VM::VM1,"?",false }, + {0x0019,0x0028,"HOLOGIC, Inc.",VR::LO,VM::VM1,"?",false }, + {0x0019,0x0029,"HOLOGIC, Inc.",VR::LO,VM::VM1,"?",false }, + {0x0019,0x0030,"HOLOGIC, Inc.",VR::US,VM::VM1,"?",false }, + {0x0019,0x0031,"HOLOGIC, Inc.",VR::US,VM::VM1,"?",false }, + {0x0019,0x0032,"HOLOGIC, Inc.",VR::US,VM::VM1,"?",false }, + {0x0019,0x0033,"HOLOGIC, Inc.",VR::US,VM::VM1,"?",false }, + {0x0019,0x0034,"HOLOGIC, Inc.",VR::US,VM::VM1,"?",false }, + {0x0019,0x0035,"HOLOGIC, Inc.",VR::US,VM::VM1,"?",false }, + {0x0019,0x0037,"HOLOGIC, Inc.",VR::LO,VM::VM1,"?",false }, + {0x0019,0x0040,"HOLOGIC, Inc.",VR::DS,VM::VM1,"?",false }, + {0x0019,0x0041,"HOLOGIC, Inc.",VR::DS,VM::VM1,"?",false }, + {0x0019,0x0042,"HOLOGIC, Inc.",VR::IS,VM::VM1,"?",false }, + {0x0019,0x0043,"HOLOGIC, Inc.",VR::DS,VM::VM1,"?",false }, + {0x0019,0x0044,"HOLOGIC, Inc.",VR::DS,VM::VM1,"?",false }, + {0x0019,0x0045,"HOLOGIC, Inc.",VR::IS,VM::VM1,"?",false }, + {0x0019,0x0046,"HOLOGIC, Inc.",VR::IS,VM::VM1,"?",false }, + {0x0019,0x0060,"HOLOGIC, Inc.",VR::LT,VM::VM1,"?",false }, + {0x0019,0x0061,"HOLOGIC, Inc.",VR::OB,VM::VM1,"?",false }, + {0x0019,0x0062,"HOLOGIC, Inc.",VR::LT,VM::VM1,"?",false }, + {0x0019,0x0070,"HOLOGIC, Inc.",VR::DS,VM::VM1,"?",false }, + {0x0019,0x0085,"HOLOGIC, Inc.",VR::SH,VM::VM1,"?",false }, + {0x0019,0x0087,"HOLOGIC, Inc.",VR::LO,VM::VM1,"?",false }, + {0x0019,0x0088,"HOLOGIC, Inc.",VR::LO,VM::VM1,"?",false }, + {0x0019,0x0089,"HOLOGIC, Inc.",VR::DS,VM::VM2,"?",false }, + {0x0019,0x008a,"HOLOGIC, Inc.",VR::SQ,VM::VM1,"?",false }, + {0x0019,0x0090,"HOLOGIC, Inc.",VR::DS,VM::VM1,"?",false }, + {0x7e01,0x0001,"HOLOGIC, Inc.",VR::LO,VM::VM1,"?",false }, + {0x7e01,0x0002,"HOLOGIC, Inc.",VR::LO,VM::VM1,"?",false }, + {0x7e01,0x0010,"HOLOGIC, Inc.",VR::SQ,VM::VM1,"?",false }, + {0x7e01,0x0011,"HOLOGIC, Inc.",VR::SQ,VM::VM1,"?",false }, + {0x7e01,0x0012,"HOLOGIC, Inc.",VR::OB,VM::VM1,"?",false }, + {0x7f01,0x0001,"HOLOGIC, Inc.",VR::LO,VM::VM1,"?",false }, + {0x7f01,0x0002,"HOLOGIC, Inc.",VR::SH,VM::VM1,"?",false }, + {0x7f01,0x0010,"HOLOGIC, Inc.",VR::SQ,VM::VM1,"?",false }, + {0x7f01,0x0012,"HOLOGIC, Inc.",VR::OB,VM::VM1,"?",false }, +/* {0x0011,0x0000,"Hologic",VR::LO,VM::VM1,"Hx Questionnaire",false }, + {0x0021,0x0001,"Hologic",VR::LT,VM::VM1,"Image Analysis Data in XML",false }, + {0x0023,0x0000,"Hologic",VR::LO,VM::VM1,"Encoding Scheme Version",false }, + {0x0023,0x0001,"Hologic",VR::LO,VM::VM1,"P File Name",false }, + {0x0023,0x0002,"Hologic",VR::OB,VM::VM1,"P File Data",false }, + {0x0023,0x0003,"Hologic",VR::UL,VM::VM1,"P File Length",false }, + {0x0023,0x0004,"Hologic",VR::OB,VM::VM1,"R File Data",false }, + {0x0023,0x0005,"Hologic",VR::UL,VM::VM1,"R File Length",false }, */ + {0x0011,0x0000,"IDEXX",VR::LO,VM::VM1,"Breed Name",false }, + {0x0011,0x0001,"IDEXX",VR::LO,VM::VM1,"Species Name",false }, + {0x0011,0x0002,"IDEXX",VR::PN,VM::VM1,"Owner",false }, + {0x300b,0x0002,"IMPAC",VR::FL,VM::VM1,"?",false }, + {0x300b,0x0004,"IMPAC",VR::FL,VM::VM1,"?",false }, + {0x300b,0x000e,"IMPAC",VR::FL,VM::VM1,"?",false }, + {0x1269,0x0001,"IMS s.r.l. Biopsy Private Code",VR::IS,VM::VM1,"Biopsy Image",false }, + {0x1269,0x0010,"IMS s.r.l. Biopsy Private Code",VR::IS,VM::VM1_n,"Biopsy Markers X",false }, + {0x1269,0x0011,"IMS s.r.l. Biopsy Private Code",VR::IS,VM::VM1_n,"Biopsy Markers Y",false }, + {0x1269,0x0012,"IMS s.r.l. Biopsy Private Code",VR::IS,VM::VM1,"Biopsy Markers Number",false }, + {0x1269,0x0020,"IMS s.r.l. Biopsy Private Code",VR::IS,VM::VM1,"Biopsy Area Left Border",false }, + {0x1269,0x0021,"IMS s.r.l. Biopsy Private Code",VR::IS,VM::VM1,"Biopsy Area Right Border",false }, + {0x1269,0x0022,"IMS s.r.l. Biopsy Private Code",VR::IS,VM::VM1,"Biopsy Area Top Border",false }, + {0x1269,0x0023,"IMS s.r.l. Biopsy Private Code",VR::IS,VM::VM1,"Biopsy Area Bottom Border",false }, + {0x1271,0x0001,"IMS s.r.l. Mammography Private Code",VR::IS,VM::VM1,"?",false }, + {0x1271,0x0002,"IMS s.r.l. Mammography Private Code",VR::IS,VM::VM1,"?",false }, + {0x1271,0x0010,"IMS s.r.l. Mammography Private Code",VR::IS,VM::VM1,"?",false }, + {0x1271,0x0011,"IMS s.r.l. Mammography Private Code",VR::IS,VM::VM1,"?",false }, + {0x1271,0x0012,"IMS s.r.l. Mammography Private Code",VR::IS,VM::VM1,"?",false }, + {0x1271,0x0013,"IMS s.r.l. Mammography Private Code",VR::IS,VM::VM1,"?",false }, + {0x1271,0x0020,"IMS s.r.l. Mammography Private Code",VR::IS,VM::VM1,"?",false }, + {0x1271,0x0021,"IMS s.r.l. Mammography Private Code",VR::IS,VM::VM1,"?",false }, + {0x1271,0x0022,"IMS s.r.l. Mammography Private Code",VR::IS,VM::VM1,"?",false }, + {0x1271,0x0038,"IMS s.r.l. Mammography Private Code",VR::LO,VM::VM1,"?",false }, + {0x1271,0x0039,"IMS s.r.l. Mammography Private Code",VR::US,VM::VM1,"?",false }, + {0x1271,0x0040,"IMS s.r.l. Mammography Private Code",VR::US,VM::VM1,"?",false }, + {0x1271,0x0041,"IMS s.r.l. Mammography Private Code",VR::LO,VM::VM1,"?",false }, + {0x1271,0x0042,"IMS s.r.l. Mammography Private Code",VR::LT,VM::VM1,"?",false }, + {0x1271,0x0045,"IMS s.r.l. Mammography Private Code",VR::IS,VM::VM1,"?",false }, + {0x1271,0x0046,"IMS s.r.l. Mammography Private Code",VR::IS,VM::VM1,"?",false }, + {0x1271,0x0047,"IMS s.r.l. Mammography Private Code",VR::IS,VM::VM1,"?",false }, + {0x1271,0x0048,"IMS s.r.l. Mammography Private Code",VR::IS,VM::VM1,"?",false }, + {0x1271,0x0049,"IMS s.r.l. Mammography Private Code",VR::IS,VM::VM1,"?",false }, + {0x1271,0x0050,"IMS s.r.l. Mammography Private Code",VR::IS,VM::VM1,"?",false }, + {0x1271,0x0051,"IMS s.r.l. Mammography Private Code",VR::IS,VM::VM1,"?",false }, + {0x1271,0x0052,"IMS s.r.l. Mammography Private Code",VR::IS,VM::VM1,"?",false }, + {0x1271,0x0053,"IMS s.r.l. Mammography Private Code",VR::LO,VM::VM1,"?",false }, + {0x1271,0x0054,"IMS s.r.l. Mammography Private Code",VR::IS,VM::VM1,"?",false }, + {0x0015,0x0010,"INFINITT_FMX",VR::LO,VM::VM1,"?",false }, + {0x0015,0x0011,"INFINITT_FMX",VR::LO,VM::VM1,"?",false }, + {0x0009,0x0008,"INTEGRIS 1.0",VR::CS,VM::VM1,"Exposure Channel",false }, + {0x0009,0x0032,"INTEGRIS 1.0",VR::TM,VM::VM1,"Exposure Start Time",false }, + {0x0019,0x0000,"INTEGRIS 1.0",VR::LO,VM::VM1,"APR Name",false }, + {0x0019,0x0040,"INTEGRIS 1.0",VR::DS,VM::VM1,"Frame Rate",false }, + {0x0021,0x0012,"INTEGRIS 1.0",VR::IS,VM::VM1,"Exposure Number",false }, + {0x0029,0x0000,"INTEGRIS 1.0",VR::SQ,VM::VM1,"Edge Enhancement Sequence",false }, + {0x0029,0x0001,"INTEGRIS 1.0",VR::US,VM::VM2,"Convolution Kernel Size",false }, + {0x0029,0x0002,"INTEGRIS 1.0",VR::US,VM::VM1_n,"Convolution Kernel Coefficients",false }, + {0x0029,0x0003,"INTEGRIS 1.0",VR::FL,VM::VM1,"Edge Enhancement Gain",false }, + {0x0029,0x0008,"INTEGRIS 1.0",VR::IS,VM::VM1,"Number of Exposure Results",false }, + {0x0041,0x0020,"INTEGRIS 1.0",VR::DS,VM::VM1,"Accumulated Fluoroscopy Dose",false }, + {0x0041,0x0030,"INTEGRIS 1.0",VR::DS,VM::VM1,"Accumulated Exposure Dose",false }, + {0x0041,0x0040,"INTEGRIS 1.0",VR::DS,VM::VM1,"Total Dose",false }, + {0x0041,0x0041,"INTEGRIS 1.0",VR::US,VM::VM1,"Total Number of Frames",false }, + {0x0041,0x0050,"INTEGRIS 1.0",VR::SQ,VM::VM1,"Exposure Information Sequence",false }, + {0x0029,0x0010,"INTELERAD MEDICAL SYSTEMS",VR::CS,VM::VM1,"?",false }, + {0x0029,0x0011,"INTELERAD MEDICAL SYSTEMS",VR::US,VM::VM1,"?",false }, + {0x0029,0x0012,"INTELERAD MEDICAL SYSTEMS",VR::US,VM::VM1,"?",false }, + {0x0029,0x0013,"INTELERAD MEDICAL SYSTEMS",VR::US,VM::VM1,"?",false }, + {0x0029,0x0015,"INTELERAD MEDICAL SYSTEMS",VR::DS,VM::VM1,"?",false }, + {0x0029,0x0016,"INTELERAD MEDICAL SYSTEMS",VR::US,VM::VM1,"?",false }, + {0x0029,0x0017,"INTELERAD MEDICAL SYSTEMS",VR::US,VM::VM1,"?",false }, + {0x0029,0x0020,"INTELERAD MEDICAL SYSTEMS",VR::LO,VM::VM1,"MD5Sum",false }, + {0x0029,0x0021,"INTELERAD MEDICAL SYSTEMS",VR::US,VM::VM6,"?",false }, + {0x0029,0x0022,"INTELERAD MEDICAL SYSTEMS",VR::US,VM::VM24,"?",false }, + {0x3f01,0x0001,"INTELERAD MEDICAL SYSTEMS",VR::LO,VM::VM1,"Institution Code",false }, + {0x3f01,0x0002,"INTELERAD MEDICAL SYSTEMS",VR::LO,VM::VM1,"Routed Transfer AE",false }, + {0x3f01,0x0003,"INTELERAD MEDICAL SYSTEMS",VR::AE,VM::VM1,"Source AE",false }, + {0x3f01,0x0004,"INTELERAD MEDICAL SYSTEMS",VR::LO,VM::VM1,"Deferred Validation",false }, + {0x3f01,0x0005,"INTELERAD MEDICAL SYSTEMS",VR::AE,VM::VM1,"Series Owner",false }, + {0x3f01,0x0007,"INTELERAD MEDICAL SYSTEMS",VR::LO,VM::VM1,"?",false }, + {0x3f01,0x0009,"INTELERAD MEDICAL SYSTEMS",VR::LO,VM::VM1,"?",false }, + {0x3f01,0x000a,"INTELERAD MEDICAL SYSTEMS",VR::DA,VM::VM1,"?",false }, + {0x3f01,0x000b,"INTELERAD MEDICAL SYSTEMS",VR::TM,VM::VM1,"?",false }, +// {0x3f01,0x0010,"INTELERAD MEDICAL SYSTEMS",VR::TM,VM::VM1,"?",false }, + {0x3f03,0x0001,"INTELERAD MEDICAL SYSTEMS",VR::SQ,VM::VM1,"Rescale Slope Sequence",false }, + {0x3f03,0x0002,"INTELERAD MEDICAL SYSTEMS",VR::DT,VM::VM1,"?",false }, + {0x3f03,0x0003,"INTELERAD MEDICAL SYSTEMS",VR::LO,VM::VM1,"?",false }, + {0x3f03,0x0004,"INTELERAD MEDICAL SYSTEMS",VR::LO,VM::VM1,"?",false }, + {0x0065,0x0011,"ISG Image",VR::UL,VM::VM1,"Length in Byte of Image",false }, + {0x0029,0x0070,"ISG shadow",VR::IS,VM::VM1,"?",false }, + {0x0029,0x0080,"ISG shadow",VR::IS,VM::VM1,"?",false }, + {0x0029,0x0090,"ISG shadow",VR::IS,VM::VM1,"?",false }, + {0x0009,0x0001,"ISI",VR::SQ,VM::VM1,"SIENET General Purpose IMGF",false }, + {0x8003,0x0000,"Image (ID, Version, Size, Dump, GUID)",VR::LO,VM::VM1,"ID",false }, + {0x8003,0x0010,"Image (ID, Version, Size, Dump, GUID)",VR::LO,VM::VM1,"Version",false }, + {0x8003,0x0020,"Image (ID, Version, Size, Dump, GUID)",VR::UL,VM::VM1,"Size",false }, + {0x8003,0x0030,"Image (ID, Version, Size, Dump, GUID)",VR::OB,VM::VM1,"Dump",false }, + {0x8003,0x0040,"Image (ID, Version, Size, Dump, GUID)",VR::LO,VM::VM1,"GUID",false }, + {0x4321,0x0005,"Imaging Dynamics Company Ltd.",VR::UN,VM::VM1,"Custom Tag",false }, + {0x4321,0x0010,"Imaging Dynamics Company Ltd.",VR::UN,VM::VM1,"Custom Tag",false }, + {0x4321,0x0041,"Imaging Dynamics Company Ltd.",VR::CS,VM::VM1,"?",false }, + {0x4321,0x0042,"Imaging Dynamics Company Ltd.",VR::US,VM::VM1,"?",false }, + {0x4321,0x0050,"Imaging Dynamics Company Ltd.",VR::DS,VM::VM1,"Custom Tag",false }, + {0x4321,0x0051,"Imaging Dynamics Company Ltd.",VR::DS,VM::VM1,"Custom Tag",false }, + {0x4321,0x0064,"Imaging Dynamics Company Ltd.",VR::LO,VM::VM1,"Custom Tag",false }, + {0x0021,0x00a5,"KINETDX",VR::US,VM::VM1,"?",false }, + {0x0021,0x00a8,"KINETDX",VR::LO,VM::VM1,"?",false }, + {0x0021,0x00aa,"KINETDX",VR::OB,VM::VM1,"?",false }, + {0x0021,0x00a4,"KINETDX_GRAPHICS",VR::LT,VM::VM1,"?",false }, + {0x7fe1,0x0001,"KRETZ_US",VR::OB,VM::VM1,"?",false }, + {0x0029,0x0015,"Kodak Image Information",VR::LO,VM::VM1,"?",false }, + {0x0029,0x0016,"Kodak Image Information",VR::LO,VM::VM1,"?",false }, + {0x0029,0x0017,"Kodak Image Information",VR::LO,VM::VM1,"?",false }, + {0x0029,0x0018,"Kodak Image Information",VR::UT,VM::VM1,"?",false }, + {0x0029,0x0019,"Kodak Image Information",VR::IS,VM::VM1,"?",false }, + {0x0029,0x001a,"Kodak Image Information",VR::IS,VM::VM1,"?",false }, + {0x0019,0x0001,"LODOX_STATSCAN",VR::IS,VM::VM1_n,"?",false }, + {0x0019,0x0002,"LODOX_STATSCAN",VR::IS,VM::VM1,"?",false }, + {0x0019,0x0003,"LODOX_STATSCAN",VR::DS,VM::VM1,"?",false }, + {0x0019,0x0004,"LODOX_STATSCAN",VR::DS,VM::VM1,"?",false }, + {0x0019,0x0005,"LODOX_STATSCAN",VR::DS,VM::VM1,"?",false }, + {0x0019,0x0006,"LODOX_STATSCAN",VR::DS,VM::VM1,"?",false }, + {0x0019,0x0007,"LODOX_STATSCAN",VR::DS,VM::VM1,"?",false }, + {0x0019,0x0008,"LODOX_STATSCAN",VR::DS,VM::VM1,"?",false }, + {0x0019,0x0006,"LORAD Selenia",VR::OB,VM::VM1,"Paddle ID",false }, + {0x0019,0x0007,"LORAD Selenia",VR::OB,VM::VM1,"Paddle Position",false }, + {0x0019,0x0008,"LORAD Selenia",VR::OB,VM::VM1,"Collimation Size",false }, + {0x0019,0x0026,"LORAD Selenia",VR::OB,VM::VM1,"?",false }, + {0x0019,0x0027,"LORAD Selenia",VR::OB,VM::VM1,"?",false }, + {0x0019,0x0028,"LORAD Selenia",VR::OB,VM::VM1,"?",false }, + {0x0019,0x0029,"LORAD Selenia",VR::OB,VM::VM1,"?",false }, + {0x0019,0x0030,"LORAD Selenia",VR::OB,VM::VM1,"?",false }, + {0x0019,0x0031,"LORAD Selenia",VR::OB,VM::VM1,"?",false }, + {0x0019,0x0032,"LORAD Selenia",VR::OB,VM::VM1,"?",false }, + {0x0019,0x0033,"LORAD Selenia",VR::OB,VM::VM1,"?",false }, + {0x0019,0x0034,"LORAD Selenia",VR::OB,VM::VM1,"?",false }, + {0x0019,0x0035,"LORAD Selenia",VR::OB,VM::VM1,"?",false }, + {0x0019,0x0040,"LORAD Selenia",VR::OB,VM::VM1,"?",false }, + {0x0019,0x0041,"LORAD Selenia",VR::OB,VM::VM1,"?",false }, + {0x0019,0x0050,"LORAD Selenia",VR::OB,VM::VM1,"?",false }, + {0x0019,0x0051,"LORAD Selenia",VR::OB,VM::VM1,"?",false }, + {0x0019,0x0052,"LORAD Selenia",VR::OB,VM::VM1,"?",false }, + {0x0019,0x0053,"LORAD Selenia",VR::OB,VM::VM1,"?",false }, + {0x0019,0x0070,"LORAD Selenia",VR::OB,VM::VM1,"?",false }, + {0x0019,0x0071,"LORAD Selenia",VR::OB,VM::VM1,"?",false }, + {0x0037,0x0001,"MAROTECH Inc.",VR::LO,VM::VM1,"Some kind of version number",false }, + {0x0037,0x0021,"MAROTECH Inc.",VR::US,VM::VM1,"Icon Row",false }, + {0x0037,0x0022,"MAROTECH Inc.",VR::US,VM::VM1,"Icon Col",false }, + {0x0037,0x0023,"MAROTECH Inc.",VR::OB,VM::VM1,"JPEG Compressed Icon",false }, + {0x3005,0x0000,"MDS NORDION OTP ANATOMY MODELLING",VR::SQ,VM::VM1,"?",false }, + {0x3005,0x0002,"MDS NORDION OTP ANATOMY MODELLING",VR::CS,VM::VM1,"?",false }, + {0x3005,0x0004,"MDS NORDION OTP ANATOMY MODELLING",VR::DS,VM::VM1,"?",false }, + {0x3005,0x0006,"MDS NORDION OTP ANATOMY MODELLING",VR::DS,VM::VM1,"?",false }, + {0x3005,0x0008,"MDS NORDION OTP ANATOMY MODELLING",VR::DS,VM::VM1,"?",false }, + {0x3005,0x000a,"MDS NORDION OTP ANATOMY MODELLING",VR::CS,VM::VM1,"?",false }, + {0x3005,0x000c,"MDS NORDION OTP ANATOMY MODELLING",VR::CS,VM::VM1,"?",false }, + {0x3005,0x000e,"MDS NORDION OTP ANATOMY MODELLING",VR::CS,VM::VM1,"?",false }, + {0x3005,0x0010,"MDS NORDION OTP ANATOMY MODELLING",VR::DS,VM::VM1,"?",false }, + {0x3005,0x0012,"MDS NORDION OTP ANATOMY MODELLING",VR::DS,VM::VM1,"?",false }, + {0x0021,0x0001,"MEDIFACE",VR::SL,VM::VM1,"?",false }, + {0x0021,0x0010,"MEDIFACE",VR::SH,VM::VM1,"?",false }, + {0x0021,0x0011,"MEDIFACE",VR::LO,VM::VM1,"?",false }, + {0x0021,0x0012,"MEDIFACE",VR::UL,VM::VM1,"?",false }, + {0x0021,0x0021,"MEDIFACE",VR::LO,VM::VM1,"?",false }, + {0x0021,0x0022,"MEDIFACE",VR::LO,VM::VM1,"?",false }, + {0x0021,0x0030,"MEDIFACE",VR::DA,VM::VM1,"?",false }, + {0x0021,0x0031,"MEDIFACE",VR::IS,VM::VM1,"?",false }, + {0x0021,0x0040,"MEDIFACE",VR::SQ,VM::VM1,"?",false }, + {0x0021,0x0041,"MEDIFACE",VR::SH,VM::VM1,"?",false }, + {0x0021,0x0042,"MEDIFACE",VR::LO,VM::VM1,"?",false }, + {0x0021,0x0050,"MEDIFACE",VR::SQ,VM::VM1,"?",false }, + {0x0021,0x0051,"MEDIFACE",VR::SH,VM::VM1,"?",false }, + {0x0021,0x0052,"MEDIFACE",VR::LO,VM::VM1,"?",false }, + {0x0021,0x0060,"MEDIFACE",VR::SQ,VM::VM1,"?",false }, + {0x0021,0x00f1,"MEDIFACE",VR::LO,VM::VM1,"?",false }, + {0x0021,0x00f2,"MEDIFACE",VR::LO,VM::VM1,"?",false }, + {0x0029,0x0001,"MEDIFACE",VR::UL,VM::VM1,"?",false }, + {0x0029,0x0010,"MEDIFACE",VR::DS,VM::VM1,"Window Center",false }, + {0x0029,0x0011,"MEDIFACE",VR::DS,VM::VM1,"Window Width",false }, + {0x0029,0x0020,"MEDIFACE",VR::DS,VM::VM1,"?",false }, + {0x0029,0x0021,"MEDIFACE",VR::UL,VM::VM1,"?",false }, + {0x0029,0x0022,"MEDIFACE",VR::DS,VM::VM2,"MEDIFACE Pixel Spacing",false }, + {0x0029,0x0030,"MEDIFACE",VR::LT,VM::VM1,"?",false }, + {0x0003,0x0000,"MEDIS_IS&C 1.0",VR::US,VM::VM1,"?",false }, + {0x0003,0x0003,"MEDIS_IS&C 1.0",VR::US,VM::VM1,"?",false }, + {0x0003,0x0004,"MEDIS_IS&C 1.0",VR::CS,VM::VM1,"?",false }, + {0x0003,0x0010,"MEDIS_IS&C 1.0",VR::DS,VM::VM1_n,"?",false }, + {0x0003,0x0020,"MEDIS_IS&C 1.0",VR::UL,VM::VM1,"?",false }, + {0x0003,0x0022,"MEDIS_IS&C 1.0",VR::UL,VM::VM1,"?",false }, + {0x0003,0x0030,"MEDIS_IS&C 1.0",VR::US,VM::VM1,"?",false }, + {0x0009,0x0000,"MERGE TECHNOLOGIES, INC.",VR::OB,VM::VM1,"?",false }, + {0x0031,0x0020,"MITRA LINKED ATTRIBUTES 1.0",VR::IS,VM::VM1,"?",false }, +/* {0x0029,0x0000,"MITRA MARKUP 1.0",VR::LO,VM::VM1_n,"?",false }, + {0x0029,0x0001,"MITRA MARKUP 1.0",VR::LO,VM::VM1_n,"?",false },*/ + {0x0033,0x0002,"MITRA OBJECT ATTRIBUTES 1.0",VR::LO,VM::VM1,"?",false }, + {0x0033,0x0004,"MITRA OBJECT ATTRIBUTES 1.0",VR::LO,VM::VM1,"?",false }, + {0x0033,0x0006,"MITRA OBJECT ATTRIBUTES 1.0",VR::LO,VM::VM1,"?",false }, + {0x0033,0x0008,"MITRA OBJECT ATTRIBUTES 1.0",VR::LO,VM::VM1,"?",false }, + {0x0033,0x000a,"MITRA OBJECT ATTRIBUTES 1.0",VR::LO,VM::VM1,"?",false }, +// {0x0029,0x0000,"MITRA OBJECT DOCUMENT 1.0",VR::OB,VM::VM1,"?",false }, + {0x0033,0x0002,"MITRA OBJECT UTF8 ATTRIBUTES 1.0",VR::OB,VM::VM1,"?",false }, + {0x0033,0x0004,"MITRA OBJECT UTF8 ATTRIBUTES 1.0",VR::CS,VM::VM1,"Study Description",false }, + {0x0033,0x0006,"MITRA OBJECT UTF8 ATTRIBUTES 1.0",VR::OB,VM::VM1,"?",false }, + {0x0033,0x0008,"MITRA OBJECT UTF8 ATTRIBUTES 1.0",VR::OB,VM::VM1,"?",false }, + {0x0033,0x000a,"MITRA OBJECT UTF8 ATTRIBUTES 1.0",VR::OB,VM::VM1,"?",false }, + {0x0033,0x000c,"MITRA OBJECT UTF8 ATTRIBUTES 1.0",VR::LO,VM::VM1,"Reason for Study",false }, + {0x0033,0x000e,"MITRA OBJECT UTF8 ATTRIBUTES 1.0",VR::OB,VM::VM1,"?",false }, + {0x0033,0x0013,"MITRA OBJECT UTF8 ATTRIBUTES 1.0",VR::PN,VM::VM1,"Patient's Name",false }, + {0x0033,0x0014,"MITRA OBJECT UTF8 ATTRIBUTES 1.0",VR::OB,VM::VM1,"?",false }, + {0x0033,0x0015,"MITRA OBJECT UTF8 ATTRIBUTES 1.0",VR::OB,VM::VM1,"?",false }, + {0x0033,0x0016,"MITRA OBJECT UTF8 ATTRIBUTES 1.0",VR::CS,VM::VM1,"?",false }, + {0x0033,0x0019,"MITRA OBJECT UTF8 ATTRIBUTES 1.0",VR::CS,VM::VM1,"?",false }, + {0x0033,0x001c,"MITRA OBJECT UTF8 ATTRIBUTES 1.0",VR::PN,VM::VM1,"Referring Physician's Name",false }, +/* {0x0029,0x0000,"MITRA PRESENTATION 1.0",VR::LO,VM::VM1,"?",false }, + {0x0029,0x0001,"MITRA PRESENTATION 1.0",VR::UN,VM::VM1,"?",false }, + {0x0029,0x0002,"MITRA PRESENTATION 1.0",VR::UN,VM::VM1,"?",false }, + {0x0029,0x0003,"MITRA PRESENTATION 1.0",VR::LO,VM::VM1,"?",false },*/ + {0x0009,0x0048,"MMCPrivate",VR::LO,VM::VM1,"?",false }, + {0x0009,0x004e,"MMCPrivate",VR::LO,VM::VM1,"?",false }, + {0x0011,0x0001,"MMCPrivate",VR::LO,VM::VM1,"?",false }, + {0x0019,0x0001,"MMCPrivate",VR::LO,VM::VM1,"?",false }, + {0x0019,0x0002,"MMCPrivate",VR::LO,VM::VM1,"?",false }, + {0x0019,0x0003,"MMCPrivate",VR::SH,VM::VM1,"?",false }, + {0x0019,0x0004,"MMCPrivate",VR::DS,VM::VM1,"?",false }, + {0x0019,0x0005,"MMCPrivate",VR::LO,VM::VM1,"?",false }, + {0x0019,0x0008,"MMCPrivate",VR::DS,VM::VM1,"?",false }, + {0x0019,0x0009,"MMCPrivate",VR::DS,VM::VM1,"?",false }, + {0x0019,0x000a,"MMCPrivate",VR::LO,VM::VM1,"?",false }, + {0x0019,0x000b,"MMCPrivate",VR::DS,VM::VM1,"?",false }, + {0x0019,0x000c,"MMCPrivate",VR::LO,VM::VM1,"?",false }, + {0x0019,0x000f,"MMCPrivate",VR::IS,VM::VM1,"?",false }, + {0x0019,0x0010,"MMCPrivate",VR::LO,VM::VM1,"?",false }, + {0x0029,0x0001,"MMCPrivate",VR::IS,VM::VM1,"?",false }, + {0x0029,0x0002,"MMCPrivate",VR::IS,VM::VM1,"?",false }, + {0x0029,0x0005,"MMCPrivate",VR::LO,VM::VM1,"?",false }, + {0x0029,0x0006,"MMCPrivate",VR::LO,VM::VM1,"?",false }, + {0x0029,0x0008,"MMCPrivate",VR::LO,VM::VM1,"?",false }, + {0x0029,0x0009,"MMCPrivate",VR::LO,VM::VM1,"?",false }, + {0x0029,0x000a,"MMCPrivate",VR::LO,VM::VM1,"?",false }, + {0x0029,0x000b,"MMCPrivate",VR::LO,VM::VM1,"?",false }, + {0x0029,0x000c,"MMCPrivate",VR::LO,VM::VM1,"?",false }, + {0x0029,0x000d,"MMCPrivate",VR::LO,VM::VM1,"?",false }, + {0x0029,0x000e,"MMCPrivate",VR::LO,VM::VM1,"?",false }, + {0x0029,0x000f,"MMCPrivate",VR::LO,VM::VM1,"?",false }, + {0x0029,0x0010,"MMCPrivate",VR::LO,VM::VM1,"?",false }, + {0x0029,0x0011,"MMCPrivate",VR::LO,VM::VM1,"?",false }, + {0x0029,0x0012,"MMCPrivate",VR::LO,VM::VM1,"?",false }, + {0x0029,0x0013,"MMCPrivate",VR::LO,VM::VM1,"?",false }, + {0x0029,0x0014,"MMCPrivate",VR::LO,VM::VM1,"?",false }, + {0x0029,0x0015,"MMCPrivate",VR::LO,VM::VM1,"?",false }, + {0x0029,0x0016,"MMCPrivate",VR::LO,VM::VM1,"?",false }, + {0x0029,0x0017,"MMCPrivate",VR::LO,VM::VM1,"?",false }, + {0x0029,0x0018,"MMCPrivate",VR::LO,VM::VM1,"?",false }, + {0x0029,0x001c,"MMCPrivate",VR::LO,VM::VM1,"?",false }, + {0x0029,0x0020,"MMCPrivate",VR::IS,VM::VM1,"?",false }, + {0x0029,0x0021,"MMCPrivate",VR::DS,VM::VM1,"?",false }, + {0x0029,0x0022,"MMCPrivate",VR::ST,VM::VM1,"?",false }, + {0x0029,0x0023,"MMCPrivate",VR::LO,VM::VM1,"?",false }, + {0x0029,0x0024,"MMCPrivate",VR::DS,VM::VM1,"?",false }, + {0x0029,0x0025,"MMCPrivate",VR::DS,VM::VM1,"?",false }, + {0x0029,0x0026,"MMCPrivate",VR::DS,VM::VM1,"?",false }, + {0x0029,0x0027,"MMCPrivate",VR::DS,VM::VM1,"?",false }, + {0x0029,0x0028,"MMCPrivate",VR::DS,VM::VM1,"?",false }, + {0x0029,0x0029,"MMCPrivate",VR::DS,VM::VM1,"?",false }, + {0x0029,0x002a,"MMCPrivate",VR::DS,VM::VM1,"?",false }, + {0x0029,0x002b,"MMCPrivate",VR::DS,VM::VM1,"?",false }, + {0x0029,0x002c,"MMCPrivate",VR::DS,VM::VM1,"?",false }, + {0x0029,0x002d,"MMCPrivate",VR::DS,VM::VM1,"?",false }, + {0x0029,0x002e,"MMCPrivate",VR::DS,VM::VM1,"?",false }, + {0x0029,0x002f,"MMCPrivate",VR::OB,VM::VM1,"?",false }, + {0x0021,0x0001,"Mayo/IBM Archive Project",VR::UN,VM::VM1,"?",false }, + {0x0021,0x0010,"Mayo/IBM Archive Project",VR::UN,VM::VM1,"?",false }, + {0x0021,0x0011,"Mayo/IBM Archive Project",VR::UN,VM::VM1,"?",false }, + {0x0021,0x0012,"Mayo/IBM Archive Project",VR::UN,VM::VM1,"?",false }, + {0x0021,0x0013,"Mayo/IBM Archive Project",VR::UN,VM::VM1,"?",false }, + {0x0021,0x0014,"Mayo/IBM Archive Project",VR::UN,VM::VM1,"?",false }, + {0x0021,0x0015,"Mayo/IBM Archive Project",VR::UN,VM::VM1,"?",false }, + {0x0021,0x0016,"Mayo/IBM Archive Project",VR::UN,VM::VM1,"?",false }, + {0x0021,0x0017,"Mayo/IBM Archive Project",VR::UN,VM::VM1,"?",false }, + {0x0021,0x0018,"Mayo/IBM Archive Project",VR::UN,VM::VM1,"?",false }, + {0x0021,0x0019,"Mayo/IBM Archive Project",VR::UN,VM::VM1,"?",false }, + {0x0021,0x001a,"Mayo/IBM Archive Project",VR::UN,VM::VM1,"?",false }, + {0x0021,0x001b,"Mayo/IBM Archive Project",VR::UN,VM::VM1,"?",false }, + {0x0021,0x001c,"Mayo/IBM Archive Project",VR::UN,VM::VM1,"?",false }, + {0x0021,0x001d,"Mayo/IBM Archive Project",VR::UN,VM::VM1,"?",false }, + {0x0021,0x001e,"Mayo/IBM Archive Project",VR::UN,VM::VM1,"?",false }, + {0x0021,0x001f,"Mayo/IBM Archive Project",VR::UN,VM::VM1,"?",false }, + {0x0021,0x0020,"Mayo/IBM Archive Project",VR::UN,VM::VM1,"?",false }, + {0x0021,0x0040,"Mayo/IBM Archive Project",VR::UN,VM::VM1,"?",false }, + {0x0021,0x0041,"Mayo/IBM Archive Project",VR::UN,VM::VM1,"?",false }, + {0x0021,0x0050,"Mayo/IBM Archive Project",VR::UN,VM::VM1,"?",false }, + {0x0021,0x0060,"Mayo/IBM Archive Project",VR::UN,VM::VM1,"?",false }, + {0x0021,0x0065,"Mayo/IBM Archive Project",VR::UN,VM::VM1,"?",false }, + {0x0019,0x0001,"MeVis BreastCare",VR::LO,VM::VM1,"?",false }, + {0x0071,0x0001,"MeVis BreastCare",VR::LO,VM::VM1,"?",false }, + {0x0009,0x0011,"MeVis eD: Geometry Information",VR::UN,VM::VM1,"GeoScannerOrigin",false }, + {0x0009,0x0021,"MeVis eD: Geometry Information",VR::UN,VM::VM1,"SlicesID",false }, + {0x0009,0x0010,"MeVis eD: Slice Information",VR::UN,VM::VM1,"SlicesSOPInstanceUID",false }, + {0x0009,0x0010,"MeVis eD: Timepoint Information",VR::UN,VM::VM1,"TPDateTime",false }, + {0x0009,0x0011,"MeVis eD: Timepoint Information",VR::UN,VM::VM1,"TPDateTimeType",false }, + {0x0009,0x0012,"MeVis eD: Timepoint Information",VR::UN,VM::VM1,"TPSeriesDescription",false }, + {0x0009,0x0013,"MeVis eD: Timepoint Information",VR::UN,VM::VM1,"TPGradientDirections",false }, + {0x0009,0x0021,"MeVis eD: Timepoint Information",VR::UN,VM::VM1,"GeometryID",false }, + {0x0009,0x0010,"MeVis eatDicom",VR::UN,VM::VM1,"EatDicomVersion",false }, + {0x0009,0x0011,"MeVis eatDicom",VR::UN,VM::VM1,"EatDicomOptions",false }, + {0x0009,0x0021,"MeVis eatDicom",VR::UN,VM::VM1,"TimepointsID",false }, + {0x5473,0x0003,"MedIns HP Extensions",VR::LO,VM::VM1,"?",false }, + {0x0029,0x0000,"Mitra Markup 1.0",VR::OB,VM::VM1_n,"Markup1",false }, + {0x0029,0x0001,"Mitra Markup 1.0",VR::OB,VM::VM1_n,"Markup2",false }, + {0x0029,0x0002,"Mitra Markup 1.0",VR::OB,VM::VM1_n,"Markup3",false }, + {0x0029,0x0003,"Mitra Markup 1.0",VR::OB,VM::VM1_n,"Markup4",false }, + {0x0029,0x0004,"Mitra Markup 1.0",VR::OB,VM::VM1_n,"Markup5",false }, + {0x0029,0x0005,"Mitra Markup 1.0",VR::OB,VM::VM1_n,"Markup6",false }, + {0x0029,0x0006,"Mitra Markup 1.0",VR::OB,VM::VM1_n,"Markup7",false }, + {0x0029,0x0007,"Mitra Markup 1.0",VR::OB,VM::VM1_n,"Markup8",false }, + {0x0029,0x0008,"Mitra Markup 1.0",VR::OB,VM::VM1_n,"Markup9",false }, + {0x0029,0x0009,"Mitra Markup 1.0",VR::OB,VM::VM1_n,"Markup10",false }, + {0x0029,0x0010,"Mitra Markup 1.0",VR::OB,VM::VM1_n,"Markup11",false }, + {0x0029,0x0011,"Mitra Markup 1.0",VR::OB,VM::VM1_n,"Markup12",false }, + {0x0029,0x0012,"Mitra Markup 1.0",VR::OB,VM::VM1,"Markup13",false }, + {0x0029,0x0013,"Mitra Markup 1.0",VR::OB,VM::VM1,"Markup14",false }, + {0x0029,0x0014,"Mitra Markup 1.0",VR::OB,VM::VM1,"Markup15",false }, + {0x0029,0x0000,"Mitra Object Document 1.0",VR::OB,VM::VM1,"IMPAX object document",false }, + {0x0029,0x0010,"Mitra Object Document 1.0",VR::OB,VM::VM1,"IMPAX markup XML stored",false }, + {0x0029,0x0000,"Mitra Presentation 1.0",VR::CS,VM::VM1,"Mitra Rotation",false }, + {0x0029,0x0001,"Mitra Presentation 1.0",VR::LO,VM::VM1,"Mitra Window Width",false }, + {0x0029,0x0002,"Mitra Presentation 1.0",VR::LO,VM::VM1,"Mitra Window Centre",false }, + {0x0029,0x0003,"Mitra Presentation 1.0",VR::IS,VM::VM1,"Mitra Invert",false }, + {0x0029,0x0004,"Mitra Presentation 1.0",VR::IS,VM::VM1,"Mitra Has Tabstop",false }, + {0x0029,0x0005,"Mitra Presentation 1.0",VR::CS,VM::VM1,"Smooth Rotation",false }, + {0x1455,0x0000,"Mortara_Inc",VR::OW,VM::VM1,"ELI Interpretation Vector",false }, + {0x1455,0x0001,"Mortara_Inc",VR::UN,VM::VM1,"Custom ID",false }, + {0x1455,0x0002,"Mortara_Inc",VR::UT,VM::VM1,"Race",false }, + {0x1455,0x0003,"Mortara_Inc",VR::UT,VM::VM1,"Social Security Number",false }, + {0x1455,0x0004,"Mortara_Inc",VR::UT,VM::VM1,"Attending Physician",false }, + {0x1455,0x0005,"Mortara_Inc",VR::UT,VM::VM1,"Procedural Diagnosis",false }, + {0x1455,0x0006,"Mortara_Inc",VR::UT,VM::VM1,"Note1",false }, + {0x1455,0x0007,"Mortara_Inc",VR::UT,VM::VM1,"Note2",false }, + {0x1455,0x0008,"Mortara_Inc",VR::LO,VM::VM1,"Order Request Number",false }, + {0x1455,0x0010,"Mortara_Inc",VR::LO,VM::VM1,"Manufacturer Name",false }, + {0x7777,0x0002,"NUD_PRIVATE",VR::UT,VM::VM1,"Interfile",false }, + {0x7777,0x0005,"NUD_PRIVATE",VR::IS,VM::VM1,"?",false }, + {0x8101,0x0000,"ObjectModel (ID, Version, Place, PlaceDescription)",VR::LO,VM::VM1,"ID",false }, + {0x8101,0x0010,"ObjectModel (ID, Version, Place, PlaceDescription)",VR::LO,VM::VM1,"Version",false }, + {0x0009,0x0000,"PAPYRUS",VR::LT,VM::VM1,"Original File Name",false }, + {0x0009,0x0010,"PAPYRUS",VR::LT,VM::VM1,"Original File Location",false }, + {0x0009,0x0018,"PAPYRUS",VR::LT,VM::VM1,"Data Set Identifier",false }, + {0x0041,0x0000,"PAPYRUS",VR::LT,VM::VM1_n,"Papyrus Comments",false }, + {0x0041,0x0010,"PAPYRUS",VR::US,VM::VM1,"Folder Type",false }, + {0x0041,0x0011,"PAPYRUS",VR::LT,VM::VM1,"Patient Folder Data Set ID",false }, + {0x0041,0x0020,"PAPYRUS",VR::LT,VM::VM1,"Folder Name",false }, + {0x0041,0x0030,"PAPYRUS",VR::DA,VM::VM1,"Creation Date",false }, + {0x0041,0x0032,"PAPYRUS",VR::TM,VM::VM1,"Creation Time",false }, + {0x0041,0x0034,"PAPYRUS",VR::DA,VM::VM1,"Modified Date",false }, + {0x0041,0x0036,"PAPYRUS",VR::TM,VM::VM1,"Modified Time",false }, + {0x0041,0x0040,"PAPYRUS",VR::LT,VM::VM1_n,"Owner Name",false }, + {0x0041,0x0050,"PAPYRUS",VR::LT,VM::VM1,"Folder Status",false }, + {0x0041,0x0060,"PAPYRUS",VR::UL,VM::VM1,"Number of Images",false }, + {0x0041,0x0062,"PAPYRUS",VR::UL,VM::VM1,"Number of Other",false }, + {0x0041,0x00a0,"PAPYRUS",VR::LT,VM::VM1_n,"External Folder Element DSID",false }, + {0x0041,0x00a1,"PAPYRUS",VR::US,VM::VM1_n,"External Folder Element Data Set Type",false }, + {0x0041,0x00a2,"PAPYRUS",VR::LT,VM::VM1_n,"External Folder Element File Location",false }, + {0x0041,0x00a3,"PAPYRUS",VR::UL,VM::VM1_n,"External Folder Element Length",false }, + {0x0041,0x00b0,"PAPYRUS",VR::LT,VM::VM1_n,"Internal Folder Element DSID",false }, + {0x0041,0x00b1,"PAPYRUS",VR::US,VM::VM1_n,"Internal Folder Element Data Set Type",false }, + {0x0041,0x00b2,"PAPYRUS",VR::UL,VM::VM1_n,"Internal Offset To Data Set",false }, + {0x0041,0x00b3,"PAPYRUS",VR::UL,VM::VM1_n,"Internal Offset To Image",false }, + {0x0041,0x0000,"PAPYRUS 3.0",VR::LT,VM::VM1,"Comments",false }, + {0x0041,0x0010,"PAPYRUS 3.0",VR::SQ,VM::VM1,"Pointer Sequence",false }, + {0x0041,0x0011,"PAPYRUS 3.0",VR::UL,VM::VM1,"Image Pointer",false }, + {0x0041,0x0012,"PAPYRUS 3.0",VR::UL,VM::VM1,"Pixel Offset",false }, + {0x0041,0x0013,"PAPYRUS 3.0",VR::SQ,VM::VM1,"Image Identifier Sequence",false }, + {0x0041,0x0014,"PAPYRUS 3.0",VR::SQ,VM::VM1,"External PAPYRUS-File Reference Sequence",false }, + {0x0041,0x0015,"PAPYRUS 3.0",VR::US,VM::VM1,"Number of images",false }, + {0x0041,0x0021,"PAPYRUS 3.0",VR::UI,VM::VM1,"Referenced SOP Class UID",false }, + {0x0041,0x0022,"PAPYRUS 3.0",VR::UI,VM::VM1,"Referenced SOP Instance UID",false }, + {0x0041,0x0031,"PAPYRUS 3.0",VR::LO,VM::VM1,"Referenced File Name",false }, + {0x0041,0x0032,"PAPYRUS 3.0",VR::LO,VM::VM1_n,"Referenced File Path",false }, + {0x0041,0x0041,"PAPYRUS 3.0",VR::UI,VM::VM1,"Referenced Image SOP Class UID",false }, + {0x0041,0x0042,"PAPYRUS 3.0",VR::UI,VM::VM1,"Referenced Image SOP Instance UID",false }, + {0x0041,0x0050,"PAPYRUS 3.0",VR::SQ,VM::VM1,"Image Sequence",false }, + // UIN: + {0x6001,0x0000,"PAPYRUS 3.0",VR::IS,VM::VM1,"Overlay ID",false }, + {0x6001,0x0001,"PAPYRUS 3.0",VR::LT,VM::VM1_n,"Linked Overlays",false }, + {0x6001,0x0010,"PAPYRUS 3.0",VR::US,VM::VM1,"Overlays Rows",false }, + {0x6001,0x0011,"PAPYRUS 3.0",VR::US,VM::VM1,"Overlays Cols",false }, + {0x6001,0x0040,"PAPYRUS 3.0",VR::LO,VM::VM1,"Overlays Type",false }, + {0x6001,0x0050,"PAPYRUS 3.0",VR::US,VM::VM1,"Overlays Origin",false }, + {0x6001,0x0060,"PAPYRUS 3.0",VR::LO,VM::VM1,"Editable",false }, + {0x6001,0x0070,"PAPYRUS 3.0",VR::LO,VM::VM1,"Overlay Font",false }, + {0x6001,0x0072,"PAPYRUS 3.0",VR::LO,VM::VM1,"Overlay Style",false }, + {0x6001,0x0074,"PAPYRUS 3.0",VR::US,VM::VM1,"Overlay Font Size",false }, + {0x6001,0x0076,"PAPYRUS 3.0",VR::LO,VM::VM1,"Overlay Color",false }, + {0x6001,0x0078,"PAPYRUS 3.0",VR::US,VM::VM1,"Shadow Size",false }, + {0x6001,0x0080,"PAPYRUS 3.0",VR::LO,VM::VM1,"Fill Pattern",false }, + {0x6001,0x0082,"PAPYRUS 3.0",VR::US,VM::VM1,"Overlay Pen Size",false }, + {0x6001,0x00A0,"PAPYRUS 3.0",VR::LO,VM::VM1,"Label",false }, + {0x6001,0x00A2,"PAPYRUS 3.0",VR::LT,VM::VM1,"Post It Text",false }, + {0x6001,0x00A4,"PAPYRUS 3.0",VR::US,VM::VM1,"Anchor Point",false }, + {0x6001,0x00b0,"PAPYRUS 3.0",VR::LO,VM::VM1,"ROI Type",false }, + {0x6001,0x00b2,"PAPYRUS 3.0",VR::LT,VM::VM1,"Attached Annotation",false }, + {0x6001,0x00ba,"PAPYRUS 3.0",VR::US,VM::VM1_n,"Contour Points",false }, + {0x6001,0x00bc,"PAPYRUS 3.0",VR::US,VM::VM1_n,"Mask Data",false }, + {0x6001,0x00c0,"PAPYRUS 3.0",VR::SQ,VM::VM1,"UIN Overlay Sequence",false }, + {0x0009,0x0010,"PHILIPS MR",VR::LO,VM::VM1,"SPI Release",false }, + {0x0009,0x0012,"PHILIPS MR",VR::DA,VM::VM1,"date",false }, + {0x0019,0x0000,"PHILIPS MR R5.5/PART",VR::DS,VM::VM1,"Field of View",false }, + {0x0019,0x0000,"PHILIPS MR R5.6/PART",VR::DS,VM::VM1,"Field of View",false }, + {0x0019,0x0001,"PHILIPS MR SPECTRO;1",VR::US,VM::VM1,"?",false }, + {0x0019,0x0002,"PHILIPS MR SPECTRO;1",VR::US,VM::VM1,"?",false }, + {0x0019,0x0003,"PHILIPS MR SPECTRO;1",VR::US,VM::VM1,"?",false }, + {0x0019,0x0004,"PHILIPS MR SPECTRO;1",VR::US,VM::VM1,"?",false }, + {0x0019,0x0005,"PHILIPS MR SPECTRO;1",VR::US,VM::VM1,"?",false }, + {0x0019,0x0006,"PHILIPS MR SPECTRO;1",VR::US,VM::VM1,"?",false }, + {0x0019,0x0007,"PHILIPS MR SPECTRO;1",VR::IS,VM::VM1,"?",false }, + {0x0019,0x0008,"PHILIPS MR SPECTRO;1",VR::IS,VM::VM1,"?",false }, + {0x0019,0x0009,"PHILIPS MR SPECTRO;1",VR::IS,VM::VM1,"?",false }, + {0x0019,0x0010,"PHILIPS MR SPECTRO;1",VR::IS,VM::VM1,"?",false }, + {0x0019,0x0012,"PHILIPS MR SPECTRO;1",VR::IS,VM::VM1,"?",false }, + {0x0019,0x0013,"PHILIPS MR SPECTRO;1",VR::IS,VM::VM1,"?",false }, + {0x0019,0x0014,"PHILIPS MR SPECTRO;1",VR::US,VM::VM1,"?",false }, + {0x0019,0x0015,"PHILIPS MR SPECTRO;1",VR::US,VM::VM1_n,"?",false }, + {0x0019,0x0016,"PHILIPS MR SPECTRO;1",VR::IS,VM::VM1,"?",false }, + {0x0019,0x0017,"PHILIPS MR SPECTRO;1",VR::IS,VM::VM1,"?",false }, + {0x0019,0x0018,"PHILIPS MR SPECTRO;1",VR::UN,VM::VM1,"?",false }, + {0x0019,0x0020,"PHILIPS MR SPECTRO;1",VR::IS,VM::VM1,"?",false }, + {0x0019,0x0021,"PHILIPS MR SPECTRO;1",VR::IS,VM::VM1,"?",false }, + {0x0019,0x0022,"PHILIPS MR SPECTRO;1",VR::IS,VM::VM1,"?",false }, + {0x0019,0x0023,"PHILIPS MR SPECTRO;1",VR::IS,VM::VM1,"?",false }, + {0x0019,0x0024,"PHILIPS MR SPECTRO;1",VR::IS,VM::VM1,"?",false }, + {0x0019,0x0025,"PHILIPS MR SPECTRO;1",VR::IS,VM::VM1,"?",false }, + {0x0019,0x0026,"PHILIPS MR SPECTRO;1",VR::IS,VM::VM1,"?",false }, + {0x0019,0x0027,"PHILIPS MR SPECTRO;1",VR::IS,VM::VM1,"?",false }, + {0x0019,0x0028,"PHILIPS MR SPECTRO;1",VR::IS,VM::VM1,"?",false }, + {0x0019,0x0029,"PHILIPS MR SPECTRO;1",VR::IS,VM::VM1_n,"?",false }, + {0x0019,0x0031,"PHILIPS MR SPECTRO;1",VR::US,VM::VM1,"?",false }, + {0x0019,0x0032,"PHILIPS MR SPECTRO;1",VR::US,VM::VM1,"?",false }, + {0x0019,0x0041,"PHILIPS MR SPECTRO;1",VR::LT,VM::VM1,"?",false }, + {0x0019,0x0042,"PHILIPS MR SPECTRO;1",VR::IS,VM::VM2,"?",false }, + {0x0019,0x0043,"PHILIPS MR SPECTRO;1",VR::IS,VM::VM2,"?",false }, + {0x0019,0x0045,"PHILIPS MR SPECTRO;1",VR::US,VM::VM1,"?",false }, + {0x0019,0x0046,"PHILIPS MR SPECTRO;1",VR::US,VM::VM1,"?",false }, + {0x0019,0x0047,"PHILIPS MR SPECTRO;1",VR::IS,VM::VM1,"?",false }, + {0x0019,0x0048,"PHILIPS MR SPECTRO;1",VR::IS,VM::VM1,"?",false }, + {0x0019,0x0049,"PHILIPS MR SPECTRO;1",VR::US,VM::VM1,"?",false }, + {0x0019,0x0050,"PHILIPS MR SPECTRO;1",VR::UN,VM::VM1,"?",false }, + {0x0019,0x0060,"PHILIPS MR SPECTRO;1",VR::US,VM::VM1,"?",false }, + {0x0019,0x0061,"PHILIPS MR SPECTRO;1",VR::US,VM::VM1,"?",false }, + {0x0019,0x0070,"PHILIPS MR SPECTRO;1",VR::UN,VM::VM1,"?",false }, + {0x0019,0x0071,"PHILIPS MR SPECTRO;1",VR::IS,VM::VM1_n,"?",false }, + {0x0019,0x0072,"PHILIPS MR SPECTRO;1",VR::US,VM::VM1,"?",false }, + {0x0019,0x0073,"PHILIPS MR SPECTRO;1",VR::US,VM::VM1,"?",false }, + {0x0019,0x0074,"PHILIPS MR SPECTRO;1",VR::US,VM::VM1,"?",false }, + {0x0019,0x0076,"PHILIPS MR SPECTRO;1",VR::US,VM::VM1,"?",false }, + {0x0019,0x0077,"PHILIPS MR SPECTRO;1",VR::US,VM::VM1,"?",false }, + {0x0019,0x0078,"PHILIPS MR SPECTRO;1",VR::US,VM::VM1,"?",false }, + {0x0019,0x0079,"PHILIPS MR SPECTRO;1",VR::US,VM::VM1,"?",false }, + {0x0019,0x0080,"PHILIPS MR SPECTRO;1",VR::IS,VM::VM1,"?",false }, + {0x0019,0x0009,"PHILIPS MR/LAST",VR::DS,VM::VM1,"Main Magnetic Field",false }, + {0x0019,0x000e,"PHILIPS MR/LAST",VR::IS,VM::VM1,"Flow Compensation",false }, + {0x0019,0x00b1,"PHILIPS MR/LAST",VR::IS,VM::VM1,"Minimum RR Interval",false }, + {0x0019,0x00b2,"PHILIPS MR/LAST",VR::IS,VM::VM1,"Maximum RR Interval",false }, + {0x0019,0x00b3,"PHILIPS MR/LAST",VR::IS,VM::VM1,"Number of Rejections",false }, + {0x0019,0x00b4,"PHILIPS MR/LAST",VR::IS,VM::VM1_n,"Number of RR Intervals",false }, + {0x0019,0x00b5,"PHILIPS MR/LAST",VR::IS,VM::VM1,"Arrhythmia Rejection",false }, + {0x0019,0x00b7,"PHILIPS MR/LAST",VR::IS,VM::VM1,"?",false }, + {0x0019,0x00c0,"PHILIPS MR/LAST",VR::DS,VM::VM1_n,"?",false }, + {0x0019,0x00c6,"PHILIPS MR/LAST",VR::IS,VM::VM1,"Cycled Multiple Slice",false }, + {0x0019,0x00ce,"PHILIPS MR/LAST",VR::IS,VM::VM1,"REST",false }, + {0x0019,0x00d5,"PHILIPS MR/LAST",VR::DS,VM::VM1,"?",false }, + {0x0019,0x00d6,"PHILIPS MR/LAST",VR::IS,VM::VM1,"Fourier Interpolation",false }, + {0x0019,0x00d9,"PHILIPS MR/LAST",VR::IS,VM::VM1_n,"?",false }, + {0x0019,0x00e0,"PHILIPS MR/LAST",VR::IS,VM::VM1,"Prepulse",false }, + {0x0019,0x00e1,"PHILIPS MR/LAST",VR::DS,VM::VM1,"Prepulse Delay",false }, + {0x0019,0x00e2,"PHILIPS MR/LAST",VR::IS,VM::VM1,"?",false }, + {0x0019,0x00e3,"PHILIPS MR/LAST",VR::DS,VM::VM3,"?",false }, + {0x0019,0x00e4,"PHILIPS MR/LAST",VR::IS,VM::VM1,"?",false }, + {0x0019,0x00e5,"PHILIPS MR/LAST",VR::DS,VM::VM1,"?",false }, + {0x0019,0x00f0,"PHILIPS MR/LAST",VR::LT,VM::VM1,"WS Protocol String 1",false }, + {0x0019,0x00f1,"PHILIPS MR/LAST",VR::LT,VM::VM1,"WS Protocol String 2",false }, + {0x0019,0x00f2,"PHILIPS MR/LAST",VR::LT,VM::VM1,"WS Protocol String 3",false }, + {0x0019,0x00f3,"PHILIPS MR/LAST",VR::LT,VM::VM1,"WS Protocol String 4",false }, + {0x0021,0x0000,"PHILIPS MR/LAST",VR::IS,VM::VM1,"?",false }, + {0x0021,0x0010,"PHILIPS MR/LAST",VR::IS,VM::VM1,"?",false }, + {0x0021,0x0020,"PHILIPS MR/LAST",VR::IS,VM::VM1,"?",false }, + {0x0021,0x0021,"PHILIPS MR/LAST",VR::DS,VM::VM1,"Slice Gap",false }, + {0x0021,0x0022,"PHILIPS MR/LAST",VR::DS,VM::VM1,"Stack Radial Angle",false }, + {0x0027,0x0000,"PHILIPS MR/LAST",VR::US,VM::VM1,"?",false }, + {0x0027,0x0011,"PHILIPS MR/LAST",VR::US,VM::VM1_n,"?",false }, + {0x0027,0x0012,"PHILIPS MR/LAST",VR::DS,VM::VM1_n,"?",false }, + {0x0027,0x0013,"PHILIPS MR/LAST",VR::DS,VM::VM1_n,"?",false }, + {0x0027,0x0014,"PHILIPS MR/LAST",VR::DS,VM::VM1_n,"?",false }, + {0x0027,0x0015,"PHILIPS MR/LAST",VR::DS,VM::VM1_n,"?",false }, + {0x0027,0x0016,"PHILIPS MR/LAST",VR::LO,VM::VM1,"?",false }, + {0x0029,0x0010,"PHILIPS MR/LAST",VR::DS,VM::VM1,"FP Min",false }, + {0x0029,0x0020,"PHILIPS MR/LAST",VR::DS,VM::VM1,"FP Max",false }, + {0x0029,0x0030,"PHILIPS MR/LAST",VR::DS,VM::VM1,"Scaled Minimum",false }, + {0x0029,0x0040,"PHILIPS MR/LAST",VR::DS,VM::VM1,"Scaled Maximum",false }, + {0x0029,0x0050,"PHILIPS MR/LAST",VR::DS,VM::VM1,"Window Minimum",false }, + {0x0029,0x0060,"PHILIPS MR/LAST",VR::DS,VM::VM1,"Window Maximum",false }, + {0x0029,0x0061,"PHILIPS MR/LAST",VR::IS,VM::VM1,"?",false }, + {0x0029,0x0062,"PHILIPS MR/LAST",VR::IS,VM::VM1,"?",false }, + {0x0029,0x0070,"PHILIPS MR/LAST",VR::DS,VM::VM1,"?",false }, + {0x0029,0x0071,"PHILIPS MR/LAST",VR::DS,VM::VM1,"?",false }, + {0x0029,0x0072,"PHILIPS MR/LAST",VR::IS,VM::VM1,"?",false }, + {0x0029,0x0080,"PHILIPS MR/LAST",VR::IS,VM::VM2,"View Center",false }, + {0x0029,0x0081,"PHILIPS MR/LAST",VR::IS,VM::VM2,"View Size",false }, + {0x0029,0x0082,"PHILIPS MR/LAST",VR::IS,VM::VM1,"View Zoom",false }, + {0x0029,0x0083,"PHILIPS MR/LAST",VR::IS,VM::VM1,"View Transform",false }, + {0x0041,0x0007,"PHILIPS MR/LAST",VR::LO,VM::VM1,"?",false }, + {0x0041,0x0009,"PHILIPS MR/LAST",VR::DS,VM::VM1,"?",false }, + {0x6001,0x0000,"PHILIPS MR/LAST",VR::LT,VM::VM1,"?",false }, + {0x0019,0x0000,"PHILIPS MR/PART",VR::DS,VM::VM1_2,"Field of View",false }, + {0x0019,0x0001,"PHILIPS MR/PART",VR::DS,VM::VM1_n,"Stack Type",false }, + {0x0019,0x0002,"PHILIPS MR/PART",VR::DS,VM::VM1_n,"?",false }, + {0x0019,0x0003,"PHILIPS MR/PART",VR::DS,VM::VM1,"?",false }, + {0x0019,0x0005,"PHILIPS MR/PART",VR::DS,VM::VM1,"CC Angulation",false }, + {0x0019,0x0006,"PHILIPS MR/PART",VR::DS,VM::VM1,"AP Angulation",false }, + {0x0019,0x0007,"PHILIPS MR/PART",VR::DS,VM::VM1,"LR Angulation",false }, + {0x0019,0x0008,"PHILIPS MR/PART",VR::IS,VM::VM1,"Patient Orientation 1",false }, + {0x0019,0x0009,"PHILIPS MR/PART",VR::IS,VM::VM1,"Patient Orientation",false }, + {0x0019,0x000a,"PHILIPS MR/PART",VR::IS,VM::VM1,"Slice Orientation",false }, + {0x0019,0x000b,"PHILIPS MR/PART",VR::DS,VM::VM1,"LR Offcenter",false }, + {0x0019,0x000c,"PHILIPS MR/PART",VR::DS,VM::VM1,"CC Offcenter",false }, + {0x0019,0x000d,"PHILIPS MR/PART",VR::DS,VM::VM1,"AP Offcenter",false }, + {0x0019,0x000e,"PHILIPS MR/PART",VR::DS,VM::VM1,"?",false }, + {0x0019,0x000f,"PHILIPS MR/PART",VR::IS,VM::VM1,"Number of Slices",false }, + {0x0019,0x0010,"PHILIPS MR/PART",VR::DS,VM::VM1,"Slice Factor",false }, + {0x0019,0x0011,"PHILIPS MR/PART",VR::DS,VM::VM1_n,"Echo Times",false }, + {0x0019,0x0014,"PHILIPS MR/PART",VR::CS,VM::VM1,"?",false }, + {0x0019,0x0015,"PHILIPS MR/PART",VR::IS,VM::VM1,"Dynamic Study",false }, + {0x0019,0x0018,"PHILIPS MR/PART",VR::DS,VM::VM1,"Heartbeat Interval",false }, + {0x0019,0x0019,"PHILIPS MR/PART",VR::DS,VM::VM1,"Repetition Time FFE",false }, + {0x0019,0x001a,"PHILIPS MR/PART",VR::DS,VM::VM1,"FFE Flip Angle",false }, + {0x0019,0x001b,"PHILIPS MR/PART",VR::IS,VM::VM1,"Number of Scans",false }, + {0x0019,0x001c,"PHILIPS MR/PART",VR::CS,VM::VM1,"?",false }, + {0x0019,0x001d,"PHILIPS MR/PART",VR::CS,VM::VM1,"?",false }, + {0x0019,0x001e,"PHILIPS MR/PART",VR::DS,VM::VM1,"?",false }, + {0x0019,0x0021,"PHILIPS MR/PART",VR::DS,VM::VM1_n,"?",false }, + {0x0019,0x0022,"PHILIPS MR/PART",VR::DS,VM::VM1,"Dynamic Scan Time Begin",false }, + {0x0019,0x0023,"PHILIPS MR/PART",VR::DS,VM::VM1_n,"?",false }, + {0x0019,0x0024,"PHILIPS MR/PART",VR::IS,VM::VM1_n,"?",false }, + {0x0019,0x0025,"PHILIPS MR/PART",VR::DS,VM::VM1_n,"?",false }, + {0x0019,0x0026,"PHILIPS MR/PART",VR::DS,VM::VM1_n,"?",false }, + {0x0019,0x0027,"PHILIPS MR/PART",VR::DS,VM::VM1_n,"?",false }, + {0x0019,0x0028,"PHILIPS MR/PART",VR::LO,VM::VM1_n,"?",false }, + {0x0019,0x0029,"PHILIPS MR/PART",VR::DS,VM::VM1_n,"?",false }, + {0x0019,0x0030,"PHILIPS MR/PART",VR::LO,VM::VM1_n,"?",false }, + {0x0019,0x0031,"PHILIPS MR/PART",VR::DS,VM::VM1_n,"?",false }, + {0x0019,0x0040,"PHILIPS MR/PART",VR::US,VM::VM1,"?",false }, + {0x0019,0x0045,"PHILIPS MR/PART",VR::IS,VM::VM1,"Reconstruction Resolution",false }, + {0x0019,0x0050,"PHILIPS MR/PART",VR::DS,VM::VM1,"?",false }, + {0x0019,0x0051,"PHILIPS MR/PART",VR::DS,VM::VM1,"?",false }, + {0x0019,0x0052,"PHILIPS MR/PART",VR::DS,VM::VM1,"?",false }, + {0x0019,0x0053,"PHILIPS MR/PART",VR::IS,VM::VM1,"?",false }, + {0x0019,0x0054,"PHILIPS MR/PART",VR::DS,VM::VM1,"?",false }, + {0x0019,0x0055,"PHILIPS MR/PART",VR::DS,VM::VM1,"?",false }, + {0x0019,0x0056,"PHILIPS MR/PART",VR::DS,VM::VM1,"?",false }, + {0x0019,0x0057,"PHILIPS MR/PART",VR::US,VM::VM1,"?",false }, + {0x0019,0x0058,"PHILIPS MR/PART",VR::DS,VM::VM1,"?",false }, + {0x0019,0x0059,"PHILIPS MR/PART",VR::US,VM::VM1,"?",false }, + {0x0019,0x0060,"PHILIPS MR/PART",VR::DS,VM::VM1,"?",false }, + {0x0019,0x0061,"PHILIPS MR/PART",VR::DS,VM::VM1,"?",false }, + {0x0019,0x0062,"PHILIPS MR/PART",VR::DS,VM::VM1,"?",false }, + {0x0019,0x0063,"PHILIPS MR/PART",VR::DS,VM::VM1,"?",false }, + {0x0019,0x0064,"PHILIPS MR/PART",VR::DS,VM::VM1,"Repetition Time SE",false }, + {0x0019,0x0065,"PHILIPS MR/PART",VR::DS,VM::VM1,"Repetition Time IR",false }, + {0x0019,0x0066,"PHILIPS MR/PART",VR::US,VM::VM1,"?",false }, + {0x0019,0x0067,"PHILIPS MR/PART",VR::DS,VM::VM1,"?",false }, + {0x0019,0x0069,"PHILIPS MR/PART",VR::IS,VM::VM1,"Number of Phases",false }, + {0x0019,0x006a,"PHILIPS MR/PART",VR::IS,VM::VM1,"Cardiac Frequency",false }, + {0x0019,0x006b,"PHILIPS MR/PART",VR::DS,VM::VM1,"Inversion Delay",false }, + {0x0019,0x006c,"PHILIPS MR/PART",VR::DS,VM::VM1,"Gate Delay",false }, + {0x0019,0x006d,"PHILIPS MR/PART",VR::DS,VM::VM1,"Gate Width",false }, + {0x0019,0x006e,"PHILIPS MR/PART",VR::DS,VM::VM1,"Trigger Delay Time",false }, + {0x0019,0x0070,"PHILIPS MR/PART",VR::DS,VM::VM1_n,"?",false }, + {0x0019,0x0080,"PHILIPS MR/PART",VR::IS,VM::VM1,"Number of Chemical Shifts",false }, + {0x0019,0x0081,"PHILIPS MR/PART",VR::DS,VM::VM1,"Chemical Shift",false }, + {0x0019,0x0084,"PHILIPS MR/PART",VR::IS,VM::VM1,"Number of Rows",false }, + {0x0019,0x0085,"PHILIPS MR/PART",VR::IS,VM::VM1,"Number of Samples",false }, + {0x0019,0x008a,"PHILIPS MR/PART",VR::CS,VM::VM1,"?",false }, + {0x0019,0x008b,"PHILIPS MR/PART",VR::CS,VM::VM1,"?",false }, + {0x0019,0x008c,"PHILIPS MR/PART",VR::CS,VM::VM1,"?",false }, + {0x0019,0x008d,"PHILIPS MR/PART",VR::CS,VM::VM1,"?",false }, + {0x0019,0x008e,"PHILIPS MR/PART",VR::CS,VM::VM1,"?",false }, + {0x0019,0x008f,"PHILIPS MR/PART",VR::CS,VM::VM1,"?",false }, + {0x0019,0x0090,"PHILIPS MR/PART",VR::IS,VM::VM1,"?",false }, + {0x0019,0x0091,"PHILIPS MR/PART",VR::IS,VM::VM1,"?",false }, + {0x0019,0x0092,"PHILIPS MR/PART",VR::IS,VM::VM1,"?",false }, + {0x0019,0x0093,"PHILIPS MR/PART",VR::IS,VM::VM1,"?",false }, + {0x0019,0x0094,"PHILIPS MR/PART",VR::LO,VM::VM1,"Magnetization Transfer Contrast",false }, + {0x0019,0x0095,"PHILIPS MR/PART",VR::LO,VM::VM1,"Spectral Presaturation With Inversion Recovery",false }, + {0x0019,0x0096,"PHILIPS MR/PART",VR::IS,VM::VM1,"?",false }, + {0x0019,0x0097,"PHILIPS MR/PART",VR::LO,VM::VM1,"?",false }, + {0x0019,0x0099,"PHILIPS MR/PART",VR::LO,VM::VM1,"?",false }, + {0x0019,0x00a0,"PHILIPS MR/PART",VR::IS,VM::VM1,"?",false }, + {0x0019,0x00a1,"PHILIPS MR/PART",VR::DS,VM::VM1,"?",false }, + {0x0019,0x00a3,"PHILIPS MR/PART",VR::DS,VM::VM1,"?",false }, + {0x0019,0x00a4,"PHILIPS MR/PART",VR::CS,VM::VM1,"?",false }, + {0x0019,0x00b4,"PHILIPS MR/PART",VR::DS,VM::VM1,"?",false }, + {0x0019,0x00b5,"PHILIPS MR/PART",VR::DS,VM::VM1,"?",false }, + {0x0019,0x00b6,"PHILIPS MR/PART",VR::DS,VM::VM1,"?",false }, + {0x0019,0x00c0,"PHILIPS MR/PART",VR::DS,VM::VM1,"Trigger Delay Times",false }, + {0x0019,0x00c8,"PHILIPS MR/PART",VR::IS,VM::VM1,"?",false }, + {0x0019,0x00c9,"PHILIPS MR/PART",VR::IS,VM::VM1,"Foldover Direction Transverse",false }, + {0x0019,0x00ca,"PHILIPS MR/PART",VR::IS,VM::VM1,"Foldover Direction Sagittal",false }, + {0x0019,0x00cb,"PHILIPS MR/PART",VR::IS,VM::VM1,"Foldover Direction Coronal",false }, + {0x0019,0x00cc,"PHILIPS MR/PART",VR::IS,VM::VM1,"?",false }, + {0x0019,0x00cd,"PHILIPS MR/PART",VR::IS,VM::VM1,"?",false }, + {0x0019,0x00ce,"PHILIPS MR/PART",VR::IS,VM::VM1,"?",false }, + {0x0019,0x00cf,"PHILIPS MR/PART",VR::IS,VM::VM1,"Number of Echoes",false }, + {0x0019,0x00d0,"PHILIPS MR/PART",VR::IS,VM::VM1,"Scan Resolution",false }, + {0x0019,0x00d1,"PHILIPS MR/PART",VR::US,VM::VM1,"?",false }, + {0x0019,0x00d2,"PHILIPS MR/PART",VR::LO,VM::VM2,"Water Fat Shift",false }, + {0x0019,0x00d3,"PHILIPS MR/PART",VR::DS,VM::VM1,"?",false }, + {0x0019,0x00d4,"PHILIPS MR/PART",VR::IS,VM::VM1,"Artifact Reduction",false }, + {0x0019,0x00d5,"PHILIPS MR/PART",VR::IS,VM::VM1,"?",false }, + {0x0019,0x00d6,"PHILIPS MR/PART",VR::IS,VM::VM1,"?",false }, + {0x0019,0x00d7,"PHILIPS MR/PART",VR::DS,VM::VM1,"Scan Percentage",false }, + {0x0019,0x00d8,"PHILIPS MR/PART",VR::IS,VM::VM1,"Halfscan",false }, + {0x0019,0x00d9,"PHILIPS MR/PART",VR::IS,VM::VM1,"EPI Factor",false }, + {0x0019,0x00da,"PHILIPS MR/PART",VR::IS,VM::VM1,"Turbo Factor",false }, + {0x0019,0x00db,"PHILIPS MR/PART",VR::IS,VM::VM1,"?",false }, + {0x0019,0x00e0,"PHILIPS MR/PART",VR::IS,VM::VM1,"Percentage of Scan Completed",false }, + {0x0019,0x00e1,"PHILIPS MR/PART",VR::IS,VM::VM1,"Prepulse Delay",false }, + {0x0019,0x00e3,"PHILIPS MR/PART",VR::DS,VM::VM1,"Phase Contrast Velocity",false }, + {0x0019,0x00f0,"PHILIPS MR/PART",VR::IS,VM::VM1,"?",false }, + {0x0019,0x00f6,"PHILIPS MR/PART",VR::CS,VM::VM1,"?",false }, + {0x0019,0x00f7,"PHILIPS MR/PART",VR::CS,VM::VM1,"?",false }, + {0x0019,0x00f8,"PHILIPS MR/PART",VR::CS,VM::VM1,"?",false }, + {0x0019,0x00f9,"PHILIPS MR/PART",VR::CS,VM::VM1,"?",false }, + {0x0019,0x00fa,"PHILIPS MR/PART",VR::CS,VM::VM1,"?",false }, + {0x0019,0x00fb,"PHILIPS MR/PART",VR::CS,VM::VM1,"?",false }, + {0x0019,0x00fc,"PHILIPS MR/PART",VR::CS,VM::VM1,"Resonance Frequency",false }, + {0x0019,0x00fe,"PHILIPS MR/PART",VR::CS,VM::VM1,"Resonance Frequency",false }, + {0x0021,0x0000,"PHILIPS MR/PART",VR::DA,VM::VM1,"Scan Date",false }, + {0x0021,0x0006,"PHILIPS MR/PART",VR::LO,VM::VM1,"?",false }, + {0x0021,0x0007,"PHILIPS MR/PART",VR::DT,VM::VM1,"?",false }, + {0x0021,0x0008,"PHILIPS MR/PART",VR::LO,VM::VM1,"?",false }, + {0x0021,0x0009,"PHILIPS MR/PART",VR::CS,VM::VM1,"?",false }, + {0x0021,0x000a,"PHILIPS MR/PART",VR::CS,VM::VM1,"?",false }, + {0x0021,0x000f,"PHILIPS MR/PART",VR::LO,VM::VM1,"?",false }, + {0x0021,0x0010,"PHILIPS MR/PART",VR::IS,VM::VM1,"Image Type",false }, + {0x0021,0x0013,"PHILIPS MR/PART",VR::CS,VM::VM1,"?",false }, + {0x0021,0x0014,"PHILIPS MR/PART",VR::LO,VM::VM1,"?",false }, + {0x0021,0x0015,"PHILIPS MR/PART",VR::US,VM::VM1,"?",false }, + {0x0021,0x0020,"PHILIPS MR/PART",VR::IS,VM::VM1,"Slice Number",false }, + {0x0021,0x0021,"PHILIPS MR/PART",VR::IS,VM::VM1,"Slice Gap",false }, + {0x0021,0x0030,"PHILIPS MR/PART",VR::IS,VM::VM1,"Echo Number",false }, + {0x0021,0x0031,"PHILIPS MR/PART",VR::DS,VM::VM1,"Patient Reference ID",false }, + {0x0021,0x0035,"PHILIPS MR/PART",VR::IS,VM::VM1,"Chemical Shift Number",false }, + {0x0021,0x0040,"PHILIPS MR/PART",VR::IS,VM::VM1,"Phase Number",false }, + {0x0021,0x0050,"PHILIPS MR/PART",VR::IS,VM::VM1,"Dynamic Scan Number",false }, + {0x0021,0x0060,"PHILIPS MR/PART",VR::IS,VM::VM1,"Number of Rows In Object",false }, + {0x0021,0x0061,"PHILIPS MR/PART",VR::IS,VM::VM1_n,"Row Number",false }, + {0x0021,0x0062,"PHILIPS MR/PART",VR::IS,VM::VM1_n,"?",false }, + {0x0029,0x0000,"PHILIPS MR/PART",VR::DS,VM::VM2,"?",false }, + {0x0029,0x0004,"PHILIPS MR/PART",VR::US,VM::VM1,"?",false }, + {0x0029,0x0010,"PHILIPS MR/PART",VR::DS,VM::VM1,"?",false }, + {0x0029,0x0011,"PHILIPS MR/PART",VR::DS,VM::VM1,"?",false }, + {0x0029,0x0020,"PHILIPS MR/PART",VR::LO,VM::VM1,"?",false }, + {0x0029,0x0031,"PHILIPS MR/PART",VR::DS,VM::VM2,"?",false }, + {0x0029,0x0032,"PHILIPS MR/PART",VR::DS,VM::VM2,"?",false }, + {0x0029,0x0050,"PHILIPS MR/PART",VR::DS,VM::VM1,"?",false }, + {0x0029,0x0051,"PHILIPS MR/PART",VR::DS,VM::VM1,"?",false }, + {0x0029,0x0052,"PHILIPS MR/PART",VR::DS,VM::VM1,"?",false }, + {0x0029,0x0053,"PHILIPS MR/PART",VR::DS,VM::VM1,"?",false }, + {0x0029,0x00c3,"PHILIPS MR/PART",VR::IS,VM::VM1,"Scan Resolution",false }, + {0x0029,0x00c4,"PHILIPS MR/PART",VR::IS,VM::VM1,"Field of View",false }, + {0x0029,0x00d5,"PHILIPS MR/PART",VR::LT,VM::VM1,"Slice Thickness",false }, + {0x0009,0x0010,"PHILIPS MR/PART 12",VR::US,VM::VM1,"?",false }, + {0x0019,0x0010,"PHILIPS MR/PART 6",VR::IS,VM::VM1,"?",false }, + {0x0019,0x0000,"PHILIPS MR/PART 7",VR::IS,VM::VM1,"?",false }, + {0x7051,0x0000,"PHILIPS NM -Private",VR::US,VM::VM1,"Current Segment",false }, + {0x7051,0x0001,"PHILIPS NM -Private",VR::US,VM::VM1,"Number of Segments",false }, + {0x7051,0x0002,"PHILIPS NM -Private",VR::FL,VM::VM1,"Segment Start Position",false }, + {0x7051,0x0003,"PHILIPS NM -Private",VR::FL,VM::VM1,"Segment Stop Position",false }, + {0x7051,0x0004,"PHILIPS NM -Private",VR::FL,VM::VM1,"Rel. COR offset - X dir.",false }, + {0x7051,0x0005,"PHILIPS NM -Private",VR::FL,VM::VM1,"Rel. COR offset - Z dir.",false }, + {0x7051,0x0006,"PHILIPS NM -Private",VR::US,VM::VM1,"Current Rotation Number",false }, + {0x7051,0x0007,"PHILIPS NM -Private",VR::US,VM::VM1,"Number of Rotations",false }, + {0x7051,0x0010,"PHILIPS NM -Private",VR::DS,VM::VM3,"Alignment Translations",false }, + {0x7051,0x0011,"PHILIPS NM -Private",VR::DS,VM::VM3,"Alignment Rotations",false }, + {0x7051,0x0012,"PHILIPS NM -Private",VR::DS,VM::VM1,"Alignment Timestamp",false }, + {0x7051,0x0015,"PHILIPS NM -Private",VR::UI,VM::VM1,"Related Xray Series Instance UID",false }, + {0x7051,0x0016,"PHILIPS NM -Private",VR::UI,VM::VM1,"?UID?",false }, + {0x7051,0x0025,"PHILIPS NM -Private",VR::LO,VM::VM1,"??",false }, + {0x7051,0x0026,"PHILIPS NM -Private",VR::DS,VM::VM1,"??",false }, + {0x7051,0x0027,"PHILIPS NM -Private",VR::DS,VM::VM1,"??",false }, + {0x7051,0x0028,"PHILIPS NM -Private",VR::IS,VM::VM1,"??",false }, + {0x7051,0x0029,"PHILIPS NM -Private",VR::IS,VM::VM1,"??",false }, + {0x7051,0x0001,"PHILIPS XCT -Private",VR::DS,VM::VM1,"Attenuation threshold",false }, + {0x7051,0x0002,"PHILIPS XCT -Private",VR::DS,VM::VM1,"DLP Estimate",false }, + {0x7051,0x0003,"PHILIPS XCT -Private",VR::LO,VM::VM1,"??",false }, + {0x5503,0x0012,"PHILIPS UNDOCUMENTED",VR::SL,VM::VM1,"Slice Thickness",false }, + {0x5503,0x0024,"PHILIPS UNDOCUMENTED",VR::UT,VM::VM1,"Plane",false }, + {0x5503,0x0030,"PHILIPS UNDOCUMENTED",VR::SS,VM::VM1,"Number of Slices",false }, + {0x5503,0x00a5,"PHILIPS UNDOCUMENTED",VR::UT,VM::VM1,"Prepulse",false }, + {0x5503,0x00ae,"PHILIPS UNDOCUMENTED",VR::SS,VM::VM1,"Contrast Agent Flag",false }, + {0x5503,0x00bb,"PHILIPS UNDOCUMENTED",VR::SL,VM::VM1,"Coil ID",false }, + {0x5503,0x00c2,"PHILIPS UNDOCUMENTED",VR::UT,VM::VM1,"Anatomy",false }, + {0x5503,0x00c3,"PHILIPS UNDOCUMENTED",VR::UT,VM::VM1,"Indication",false }, + {0x2001,0x0001,"PHILIPS UNKNOWN",VR::UN,VM::VM1,"MRSeriesNrOfEchoes",false }, + {0x2001,0x0002,"PHILIPS UNKNOWN",VR::UN,VM::VM1,"MRSeriesScanningTechniqueDescription",false }, + {0x2001,0x0005,"PHILIPS UNKNOWN",VR::UN,VM::VM1,"StackSequence",false }, + {0x2001,0x0006,"PHILIPS UNKNOWN",VR::UN,VM::VM1,"Examination Source",false }, + {0x2001,0x0007,"PHILIPS UNKNOWN",VR::UN,VM::VM1,"MRSeriesAcquisitionNumber",false }, + {0x2001,0x0008,"PHILIPS UNKNOWN",VR::UN,VM::VM1,"MRSeriesNrOfDynamicScans",false }, + {0x2005,0x0002,"PHILIPS UNKNOWN",VR::UN,VM::VM1,"MRSeriesNrOfChemicalShifts",false }, + {0x2005,0x0003,"PHILIPS UNKNOWN",VR::UN,VM::VM1,"MRSeriesRepetitionTime",false }, + {0x2005,0x0036,"PHILIPS UNKNOWN",VR::UN,VM::VM1,"MRVolumeSelection",false }, + {0x0019,0x0011,"PHILIPS-MR-1",VR::IS,VM::VM1,"Chemical Shift Number",false }, + {0x0019,0x0012,"PHILIPS-MR-1",VR::IS,VM::VM1,"Phase Number (Philips)",false }, + {0x0021,0x0001,"PHILIPS-MR-1",VR::IS,VM::VM1,"Reconstruction Number",false }, + {0x0021,0x0002,"PHILIPS-MR-1",VR::IS,VM::VM1,"Slice Number",false }, + {0x0055,0x0001,"PMOD_1",VR::FD,VM::VM1_n,"Frame Start Times Vector",false }, + {0x0055,0x0002,"PMOD_1",VR::FD,VM::VM3_3n,"Frame Positions Vector",false }, + {0x0055,0x0003,"PMOD_1",VR::FD,VM::VM6_6n,"Frame Orientations Vector",false }, + {0x0055,0x0004,"PMOD_1",VR::FD,VM::VM1_n,"Frame Durations (ms) Vector",false }, + {0x0055,0x0005,"PMOD_1",VR::FD,VM::VM1_n,"Frame Rescale Slope Vector",false }, + {0x7fe1,0x0001,"PMOD_GENPET",VR::UT,VM::VM1,"Slices Names",false }, + {0x7fe1,0x0002,"PMOD_GENPET",VR::UT,VM::VM1,"Gene Codes",false }, + {0x7fe1,0x0003,"PMOD_GENPET",VR::UT,VM::VM1,"Gene Labels",false }, + {0x0089,0x0020,"PMS-THORA-5.1",VR::SQ,VM::VM1,"Stamp Image Sequence",false }, + {0x0029,0x0001,"PMTF INFORMATION DATA",VR::SQ,VM::VM1,"?",false }, + {0x0029,0x0031,"PMTF INFORMATION DATA",VR::LO,VM::VM1,"PMTF Information 1",false }, + {0x0029,0x0032,"PMTF INFORMATION DATA",VR::UL,VM::VM1,"PMTF Information 2",false }, + {0x0029,0x0033,"PMTF INFORMATION DATA",VR::UL,VM::VM1,"PMTF Information 3",false }, + {0x0029,0x0034,"PMTF INFORMATION DATA",VR::CS,VM::VM1,"PMTF Information 4",false }, + {0x0029,0x0089,"PMTF INFORMATION DATA",VR::LO,VM::VM1,"?",false }, + {0x0029,0x0090,"PMTF INFORMATION DATA",VR::OB,VM::VM1,"?",false }, + {0x7015,0x0073,"PMTF INFORMATION DATA",VR::SQ,VM::VM1,"?",false }, + {0x0009,0x0002,"POLYTRON-SMS 2.5",VR::UN,VM::VM1,"Private Data 1",false }, + {0x0009,0x0003,"POLYTRON-SMS 2.5",VR::UN,VM::VM1,"Private Data 2",false }, + {0x0009,0x0004,"POLYTRON-SMS 2.5",VR::UN,VM::VM1,"Private Data 3",false }, + {0x0009,0x0006,"POLYTRON-SMS 2.5",VR::UN,VM::VM1,"Private Data 3",false }, + {0x0009,0x0010,"POLYTRON-SMS 2.5",VR::UN,VM::VM1,"Private Data 4",false }, + {0x0009,0x0011,"POLYTRON-SMS 2.5",VR::UN,VM::VM1,"Private Data 5",false }, + {0x0009,0x0012,"POLYTRON-SMS 2.5",VR::UN,VM::VM1,"Private Data 6",false }, + {0x0089,0x0010,"POLYTRON-SMS 2.5",VR::UN,VM::VM1,"Private Data",false }, + {0x0021,0x0001,"PRIVATE ORIGINAL ATTRIBUTES",VR::SQ,VM::VM1,"Private Original Attribute Sequence",false }, + {0x0021,0x0005,"PRIVATE ORIGINAL ATTRIBUTES",VR::DT,VM::VM1,"Replacement Date and Time",false }, + {0x0021,0x0010,"PRIVATE ORIGINAL ATTRIBUTES",VR::LO,VM::VM1,"Replacement Originator Name",false }, + {0x0021,0x0012,"PRIVATE ORIGINAL ATTRIBUTES",VR::LO,VM::VM1,"Replacement Reason",false }, + {0x0021,0x0070,"PRIVATE ORIGINAL ATTRIBUTES",VR::PN,VM::VM1_n,"Original Operators'Name",false }, + {0x2007,0x00c1,"Philips EV Imaging DD 017",VR::UI,VM::VM1,"? SOP Instance UID ?",false }, + {0x2007,0x00c2,"Philips EV Imaging DD 017",VR::DA,VM::VM1,"?",false }, + {0x2007,0x00c3,"Philips EV Imaging DD 017",VR::TM,VM::VM1,"?",false }, + {0x2007,0x00c4,"Philips EV Imaging DD 017",VR::UL,VM::VM1,"?",false }, + {0x2007,0x0000,"Philips EV Imaging DD 019",VR::LO,VM::VM1,"?",false }, + {0x2007,0x0001,"Philips EV Imaging DD 019",VR::UT,VM::VM1,"?",false }, + {0x2007,0x0004,"Philips EV Imaging DD 021",VR::SL,VM::VM1,"Vol Seg Edit Connectivity",false }, + //{0x2007,0x0051,"Philips EV Imaging DD 021",VR::SS,VM::VM1,"??",false }, + {0x2007,0x0000,"Philips EV Imaging DD 022",VR::ST,VM::VM1,"",false }, + {0x2007,0x0012,"Philips EV Imaging DD 022",VR::LO,VM::VM1,"Volume Sequence Capture",false }, + {0x2007,0x0017,"Philips EV Imaging DD 022",VR::UI,VM::VM1,"Original SOP Instance",false }, + {0x2007,0x0033,"Philips EV Imaging DD 022",VR::LO,VM::VM1,"",false }, + {0x2007,0x0034,"Philips EV Imaging DD 022",VR::CS,VM::VM1,"",false }, + {0x7777,0x0001,"Philips EnVisor",VR::DA,VM::VM1,"Date 3D/PanView internal 'dataset' file was acquired",false }, + {0x7777,0x0002,"Philips EnVisor",VR::CS,VM::VM1,"Type of 3D or PanView",false }, + {0x7777,0x0003,"Philips EnVisor",VR::LO,VM::VM1,"Internal 3D/PanView software version number",false }, + {0x7777,0x0014,"Philips EnVisor",VR::LT,VM::VM1,"Private string",false }, + {0x2001,0x0001,"PHILIPS IMAGING DD 001",VR::FL,VM::VM1,"Chemical Shift",false }, + {0x2001,0x0002,"PHILIPS IMAGING DD 001",VR::IS,VM::VM1,"Chemical Shift Number MR",false }, + {0x2001,0x0003,"PHILIPS IMAGING DD 001",VR::FL,VM::VM1,"Diffusion B-Factor",false }, + {0x2001,0x0004,"PHILIPS IMAGING DD 001",VR::CS,VM::VM1,"Diffusion Direction",false }, + {0x2001,0x0005,"PHILIPS IMAGING DD 001",VR::SS,VM::VM1,"?",false }, + {0x2001,0x0006,"PHILIPS IMAGING DD 001",VR::CS,VM::VM1,"Image Enhanced",false }, + {0x2001,0x0007,"PHILIPS IMAGING DD 001",VR::CS,VM::VM1,"Image Type ED ES",false }, + {0x2001,0x0008,"PHILIPS IMAGING DD 001",VR::IS,VM::VM1,"Phase Number",false }, + {0x2001,0x0009,"PHILIPS IMAGING DD 001",VR::FL,VM::VM1,"?",false }, + {0x2001,0x000a,"PHILIPS IMAGING DD 001",VR::IS,VM::VM1,"Slice Number MR",false }, + {0x2001,0x000b,"PHILIPS IMAGING DD 001",VR::CS,VM::VM1,"Slice Orientation",false }, + {0x2001,0x000c,"PHILIPS IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2001,0x000e,"PHILIPS IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2001,0x000f,"PHILIPS IMAGING DD 001",VR::SS,VM::VM1,"?",false }, + {0x2001,0x0010,"PHILIPS IMAGING DD 001",VR::CS,VM::VM1,"Cardiac Sync",false }, + {0x2001,0x0011,"PHILIPS IMAGING DD 001",VR::FL,VM::VM1,"Diffusion Echo Time",false }, + {0x2001,0x0012,"PHILIPS IMAGING DD 001",VR::CS,VM::VM1,"Dynamic Series",false }, + {0x2001,0x0013,"PHILIPS IMAGING DD 001",VR::SL,VM::VM1,"EPI Factor",false }, + {0x2001,0x0014,"PHILIPS IMAGING DD 001",VR::SL,VM::VM1,"Number of Echoes",false }, + {0x2001,0x0015,"PHILIPS IMAGING DD 001",VR::SS,VM::VM1,"Number of Locations",false }, + {0x2001,0x0016,"PHILIPS IMAGING DD 001",VR::SS,VM::VM1,"Number of PC Directions",false }, + {0x2001,0x0017,"PHILIPS IMAGING DD 001",VR::SL,VM::VM1,"Number of Phases MR",false }, + {0x2001,0x0018,"PHILIPS IMAGING DD 001",VR::SL,VM::VM1,"Number of Slices MR",false }, + {0x2001,0x0019,"PHILIPS IMAGING DD 001",VR::CS,VM::VM1,"Partial Matrix Scanned",false }, + {0x2001,0x001a,"PHILIPS IMAGING DD 001",VR::FL,VM::VM1_n,"PC Velocity",false }, + {0x2001,0x001b,"PHILIPS IMAGING DD 001",VR::FL,VM::VM1,"Prepulse Delay",false }, + {0x2001,0x001c,"PHILIPS IMAGING DD 001",VR::CS,VM::VM1,"Prepulse Type",false }, + {0x2001,0x001d,"PHILIPS IMAGING DD 001",VR::IS,VM::VM1,"Reconstruction Number MR",false }, + {0x2001,0x001e,"PHILIPS IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2001,0x001f,"PHILIPS IMAGING DD 001",VR::CS,VM::VM1,"Respiration Sync",false }, + {0x2001,0x0020,"PHILIPS IMAGING DD 001",VR::LO,VM::VM1,"Scanning Technique Description MR",false }, + {0x2001,0x0021,"PHILIPS IMAGING DD 001",VR::CS,VM::VM1,"SPIR",false }, + {0x2001,0x0022,"PHILIPS IMAGING DD 001",VR::FL,VM::VM1,"Water Fat Shift",false }, + {0x2001,0x0023,"PHILIPS IMAGING DD 001",VR::DS,VM::VM1,"Flip Angle Philips",false }, + {0x2001,0x0024,"PHILIPS IMAGING DD 001",VR::CS,VM::VM1,"Interactive",false }, + {0x2001,0x0025,"PHILIPS IMAGING DD 001",VR::SH,VM::VM1,"Echo Time Display MR",false }, + {0x2001,0x0026,"PHILIPS IMAGING DD 001",VR::CS,VM::VM1,"Presentation State Subtraction Active",false }, + {0x2001,0x0028,"PHILIPS IMAGING DD 001",VR::FL,VM::VM1,"Edge Enhancement Gain Factor Sub",false }, + {0x2001,0x0029,"PHILIPS IMAGING DD 001",VR::FL,VM::VM1,"Edge Enhancement Gain Factor Non Sub",false }, + {0x2001,0x002a,"PHILIPS IMAGING DD 001",VR::CS,VM::VM1,"Edge Enhancement Taste Adapt Sub",false }, + {0x2001,0x002b,"PHILIPS IMAGING DD 001",VR::CS,VM::VM1,"Edge Enhancement Taste Non Sub",false }, + {0x2001,0x002c,"PHILIPS IMAGING DD 001",VR::FL,VM::VM1,"Harmonization Factor",false }, + {0x2001,0x002d,"PHILIPS IMAGING DD 001",VR::SS,VM::VM1,"Number of Stack Slices",false }, + {0x2001,0x002f,"PHILIPS IMAGING DD 001",VR::FL,VM::VM1,"Harmonization Gain",false }, + {0x2001,0x0030,"PHILIPS IMAGING DD 001",VR::UL,VM::VM1,"Log Subtraction Gain Step",false }, + {0x2001,0x0031,"PHILIPS IMAGING DD 001",VR::US,VM::VM1,"Mixing NR of Mask Image Numbers",false }, + {0x2001,0x0032,"PHILIPS IMAGING DD 001",VR::FL,VM::VM1_n,"Stack Radial Angle",false }, + {0x2001,0x0033,"PHILIPS IMAGING DD 001",VR::CS,VM::VM1_n,"Stack Radial Axis",false }, + {0x2001,0x0034,"PHILIPS IMAGING DD 001",VR::CS,VM::VM1,"Mixing Mask Operation",false }, + {0x2001,0x0035,"PHILIPS IMAGING DD 001",VR::SS,VM::VM1_n,"Stack Slice Number",false }, + {0x2001,0x0036,"PHILIPS IMAGING DD 001",VR::CS,VM::VM1_n,"Stack Type",false }, + {0x2001,0x0037,"PHILIPS IMAGING DD 001",VR::CS,VM::VM1,"Mixing Operation Type",false }, + {0x2001,0x0039,"PHILIPS IMAGING DD 001",VR::FL,VM::VM1,"?",false }, + {0x2001,0x003a,"PHILIPS IMAGING DD 001",VR::CS,VM::VM1,"Pixel Shift",false }, + {0x2001,0x003d,"PHILIPS IMAGING DD 001",VR::UL,VM::VM1,"?",false }, + {0x2001,0x003f,"PHILIPS IMAGING DD 001",VR::CS,VM::VM1,"Interpolation Method",false }, + {0x2001,0x0042,"PHILIPS IMAGING DD 001",VR::CS,VM::VM1,"Substraction Land Marking Active",false }, + {0x2001,0x0046,"PHILIPS IMAGING DD 001",VR::CS,VM::VM1,"Graphic Line Style",false }, + {0x2001,0x0047,"PHILIPS IMAGING DD 001",VR::FL,VM::VM1,"Graphic Line Width",false }, + {0x2001,0x0048,"PHILIPS IMAGING DD 001",VR::SS,VM::VM1,"Graphic Annotation ID",false }, + {0x2001,0x004b,"PHILIPS IMAGING DD 001",VR::CS,VM::VM1,"Poly Line Interpolation Method",false }, + {0x2001,0x004c,"PHILIPS IMAGING DD 001",VR::CS,VM::VM1,"Poly Line Begin Point Style",false }, + {0x2001,0x004d,"PHILIPS IMAGING DD 001",VR::CS,VM::VM1,"Poly Line End Point Style",false }, + {0x2001,0x004e,"PHILIPS IMAGING DD 001",VR::CS,VM::VM1,"Window Smoothing Taste",false }, + {0x2001,0x004f,"PHILIPS IMAGING DD 001",VR::FD,VM::VM1,"Harmonization Offset",false }, + {0x2001,0x0050,"PHILIPS IMAGING DD 001",VR::LO,VM::VM1,"?",false }, + {0x2001,0x0052,"PHILIPS IMAGING DD 001",VR::UI,VM::VM1,"?",false }, + {0x2001,0x0053,"PHILIPS IMAGING DD 001",VR::CS,VM::VM1,"Window Invert",false }, + {0x2001,0x0055,"PHILIPS IMAGING DD 001",VR::CS,VM::VM1,"Graphic Line Color",false }, + {0x2001,0x0056,"PHILIPS IMAGING DD 001",VR::CS,VM::VM1,"Graphic Type (Private)",false }, + {0x2001,0x005a,"PHILIPS IMAGING DD 001",VR::ST,VM::VM1,"Graphic Annotation Model",false }, + {0x2001,0x005d,"PHILIPS IMAGING DD 001",VR::ST,VM::VM1,"Measurement Text Units",false }, + {0x2001,0x005e,"PHILIPS IMAGING DD 001",VR::ST,VM::VM1,"Measurement Text Type",false }, + {0x2001,0x005f,"PHILIPS IMAGING DD 001",VR::SQ,VM::VM1,"Stack Sequence",false }, + {0x2001,0x0060,"PHILIPS IMAGING DD 001",VR::SL,VM::VM1,"Number of Stacks",false }, + {0x2001,0x0061,"PHILIPS IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2001,0x0062,"PHILIPS IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2001,0x0063,"PHILIPS IMAGING DD 001",VR::CS,VM::VM1,"Examination Source",false }, + {0x2001,0x0064,"PHILIPS IMAGING DD 001",VR::SH,VM::VM1,"Text Type",false }, + {0x2001,0x0065,"PHILIPS IMAGING DD 001",VR::SQ,VM::VM1,"?",false }, + {0x2001,0x0067,"PHILIPS IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2001,0x0068,"PHILIPS IMAGING DD 001",VR::SQ,VM::VM1,"?",false }, + {0x2001,0x0069,"PHILIPS IMAGING DD 001",VR::SQ,VM::VM1,"Display Shutter Sequence",false }, + {0x2001,0x006a,"PHILIPS IMAGING DD 001",VR::SQ,VM::VM1,"?",false }, + {0x2001,0x006b,"PHILIPS IMAGING DD 001",VR::SQ,VM::VM1,"Has Edge Enhancement Sequence",false }, + {0x2001,0x006d,"PHILIPS IMAGING DD 001",VR::LO,VM::VM1,"Text Font",false }, + {0x2001,0x006e,"PHILIPS IMAGING DD 001",VR::SH,VM::VM1,"Series Type",false }, + {0x2001,0x006f,"PHILIPS IMAGING DD 001",VR::SQ,VM::VM1,"Mixing Sequence",false }, + {0x2001,0x0071,"PHILIPS IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2001,0x0073,"PHILIPS IMAGING DD 001",VR::SQ,VM::VM1,"Referenced Mask Image Sequence",false }, + {0x2001,0x0074,"PHILIPS IMAGING DD 001",VR::DS,VM::VM1_n,"Window Center Sub",false }, + {0x2001,0x0075,"PHILIPS IMAGING DD 001",VR::DS,VM::VM1_n,"Window Width Sub",false }, + {0x2001,0x0076,"PHILIPS IMAGING DD 001",VR::UL,VM::VM1,"?",false }, + {0x2001,0x0077,"PHILIPS IMAGING DD 001",VR::CS,VM::VM1,"GL TrafoType",false }, + {0x2001,0x0079,"PHILIPS IMAGING DD 001",VR::SQ,VM::VM1,"Harmonisation Sequence",false }, + {0x2001,0x007a,"PHILIPS IMAGING DD 001",VR::FL,VM::VM1,"?",false }, + {0x2001,0x007b,"PHILIPS IMAGING DD 001",VR::IS,VM::VM1,"Acquisition Number",false }, + {0x2001,0x007e,"PHILIPS IMAGING DD 001",VR::US,VM::VM1,"Edge Enhancement Gain Taste",false }, + {0x2001,0x007f,"PHILIPS IMAGING DD 001",VR::US,VM::VM1,"Edge Enhancement Gain Taste Sub",false }, + {0x2001,0x0080,"PHILIPS IMAGING DD 001",VR::LO,VM::VM1,"Text Anchor Point Alignment",false }, + {0x2001,0x0081,"PHILIPS IMAGING DD 001",VR::IS,VM::VM1,"Number of Dynamic Scans",false }, + {0x2001,0x0082,"PHILIPS IMAGING DD 001",VR::IS,VM::VM1,"Echo Train Length",false }, + {0x2001,0x0083,"PHILIPS IMAGING DD 001",VR::DS,VM::VM1,"Imaging Frequency",false }, + {0x2001,0x0084,"PHILIPS IMAGING DD 001",VR::DS,VM::VM1,"Inversion Time",false }, + {0x2001,0x0085,"PHILIPS IMAGING DD 001",VR::DS,VM::VM1,"Magnetic Field Strength",false }, + {0x2001,0x0086,"PHILIPS IMAGING DD 001",VR::IS,VM::VM1,"?",false }, + {0x2001,0x0087,"PHILIPS IMAGING DD 001",VR::SH,VM::VM1,"Imaged Nucleus",false }, + {0x2001,0x0088,"PHILIPS IMAGING DD 001",VR::DS,VM::VM1,"Number of Averages",false }, + {0x2001,0x0089,"PHILIPS IMAGING DD 001",VR::DS,VM::VM1,"Phase FOV Percent",false }, + {0x2001,0x008a,"PHILIPS IMAGING DD 001",VR::DS,VM::VM1,"Sampling Percent",false }, + {0x2001,0x008b,"PHILIPS IMAGING DD 001",VR::SH,VM::VM1,"?",false }, + {0x2001,0x0093,"PHILIPS IMAGING DD 001",VR::LO,VM::VM1,"Text Style",false }, + {0x2001,0x0094,"PHILIPS IMAGING DD 001",VR::LO,VM::VM1,"Processing Order Specialization",false }, + {0x2001,0x0097,"PHILIPS IMAGING DD 001",VR::SH,VM::VM1,"Nucleus",false }, + {0x2001,0x009a,"PHILIPS IMAGING DD 001",VR::SQ,VM::VM1,"Graphic Number Sequence",false }, + {0x2001,0x009b,"PHILIPS IMAGING DD 001",VR::UL,VM::VM1,"Graphic Number",false }, + {0x2001,0x009c,"PHILIPS IMAGING DD 001",VR::LO,VM::VM1,"?",false }, + {0x2001,0x009d,"PHILIPS IMAGING DD 001",VR::LO,VM::VM1,"PIIM Substraction Type",false }, + {0x2001,0x009f,"PHILIPS IMAGING DD 001",VR::US,VM::VM2,"Pixel Processing Kernel Size",false }, + {0x2001,0x00a1,"PHILIPS IMAGING DD 001",VR::CS,VM::VM1,"Is Raw Image",false }, + {0x2001,0x00a2,"PHILIPS IMAGING DD 001",VR::US,VM::VM1,"LOG Substraction Curve Taste",false }, + {0x2001,0x00a3,"PHILIPS IMAGING DD 001",VR::UL,VM::VM1,"Text Color Foreground",false }, + {0x2001,0x00a4,"PHILIPS IMAGING DD 001",VR::UL,VM::VM1,"Text Color Background",false }, + {0x2001,0x00a5,"PHILIPS IMAGING DD 001",VR::UL,VM::VM1,"Text Color Shadow",false }, + {0x2001,0x00c1,"PHILIPS IMAGING DD 001",VR::LO,VM::VM1,"Nested Object Type Name",false }, + {0x2001,0x00c8,"PHILIPS IMAGING DD 001",VR::LO,VM::VM1,"?",false }, + {0x2001,0x00cc,"PHILIPS IMAGING DD 001",VR::ST,VM::VM1,"?",false }, + {0x2001,0x00da,"PHILIPS IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2001,0x00f1,"PHILIPS IMAGING DD 001",VR::FL,VM::VM1_n,"Prospective Motion Correction",false }, + {0x2001,0x00f2,"PHILIPS IMAGING DD 001",VR::FL,VM::VM1,"Retrospective Motion Correction",false }, +// {0x2005,0x0014,"PHILIPS IMAGING DD 001",VR::CS,VM::VM1,"Diffusion",false }, +// {0x2005,0x0020,"PHILIPS IMAGING DD 001",VR::SL,VM::VM1,"Number of Chemical Shifts",false }, +// {0x2005,0x0030,"PHILIPS IMAGING DD 001",VR::FL,VM::VM1,"Repetition Time",false }, +// {0x2005,0x0033,"PHILIPS IMAGING DD 001",VR::FL,VM::VM1,"Scan Duration",false }, +// {0x2005,0x0035,"PHILIPS IMAGING DD 001",VR::CS,VM::VM1,"Data Type",false }, +// {0x2005,0x008b,"PHILIPS IMAGING DD 001",VR::SH,VM::VM1,"Transmitting Coil",false }, +// {0x2005,0x009f,"PHILIPS IMAGING DD 001",VR::CS,VM::VM1,"Spectral Selective Excitation Pulse",false }, +// {0x2005,0x00a1,"PHILIPS IMAGING DD 001",VR::CS,VM::VM1,"Syncra Scan Type",false }, + + {0x2001,0x0001,"Philips Imaging DD 001",VR::FL,VM::VM1,"Chemical Shift",false }, + {0x2001,0x0002,"Philips Imaging DD 001",VR::IS,VM::VM1,"Chemical Shift Number MR",false }, + {0x2001,0x0003,"Philips Imaging DD 001",VR::FL,VM::VM1,"Diffusion B-Factor",false }, + {0x2001,0x0004,"Philips Imaging DD 001",VR::CS,VM::VM1,"Diffusion Direction",false }, + {0x2001,0x0005,"Philips Imaging DD 001",VR::SS,VM::VM1,"?",false }, + {0x2001,0x0006,"Philips Imaging DD 001",VR::CS,VM::VM1,"Image Enhanced",false }, + {0x2001,0x0007,"Philips Imaging DD 001",VR::CS,VM::VM1,"Image Type ED ES",false }, + {0x2001,0x0008,"Philips Imaging DD 001",VR::IS,VM::VM1,"Phase Number",false }, + {0x2001,0x0009,"Philips Imaging DD 001",VR::FL,VM::VM1,"?",false }, + {0x2001,0x000a,"Philips Imaging DD 001",VR::IS,VM::VM1,"Slice Number MR",false }, + {0x2001,0x000b,"Philips Imaging DD 001",VR::CS,VM::VM1,"Slice Orientation",false }, + {0x2001,0x000c,"Philips Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2001,0x000e,"Philips Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2001,0x000f,"Philips Imaging DD 001",VR::SS,VM::VM1,"?",false }, + {0x2001,0x0010,"Philips Imaging DD 001",VR::CS,VM::VM1,"Cardiac Sync",false }, + {0x2001,0x0011,"Philips Imaging DD 001",VR::FL,VM::VM1,"Diffusion Echo Time",false }, + {0x2001,0x0012,"Philips Imaging DD 001",VR::CS,VM::VM1,"Dynamic Series",false }, + {0x2001,0x0013,"Philips Imaging DD 001",VR::SL,VM::VM1,"EPI Factor",false }, + {0x2001,0x0014,"Philips Imaging DD 001",VR::SL,VM::VM1,"Number of Echoes",false }, + {0x2001,0x0015,"Philips Imaging DD 001",VR::SS,VM::VM1,"Number of Locations",false }, + {0x2001,0x0016,"Philips Imaging DD 001",VR::SS,VM::VM1,"Number of PC Directions",false }, + {0x2001,0x0017,"Philips Imaging DD 001",VR::SL,VM::VM1,"Number of Phases MR",false }, + {0x2001,0x0018,"Philips Imaging DD 001",VR::SL,VM::VM1,"Number of Slices MR",false }, + {0x2001,0x0019,"Philips Imaging DD 001",VR::CS,VM::VM1,"Partial Matrix Scanned",false }, + {0x2001,0x001a,"Philips Imaging DD 001",VR::FL,VM::VM1_n,"PC Velocity",false }, + {0x2001,0x001b,"Philips Imaging DD 001",VR::FL,VM::VM1,"Prepulse Delay",false }, + {0x2001,0x001c,"Philips Imaging DD 001",VR::CS,VM::VM1,"Prepulse Type",false }, + {0x2001,0x001d,"Philips Imaging DD 001",VR::IS,VM::VM1,"Reconstruction Number MR",false }, + {0x2001,0x001e,"Philips Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2001,0x001f,"Philips Imaging DD 001",VR::CS,VM::VM1,"Respiration Sync",false }, + {0x2001,0x0020,"Philips Imaging DD 001",VR::LO,VM::VM1,"Scanning Technique Description MR",false }, + {0x2001,0x0021,"Philips Imaging DD 001",VR::CS,VM::VM1,"SPIR",false }, + {0x2001,0x0022,"Philips Imaging DD 001",VR::FL,VM::VM1,"Water Fat Shift",false }, + {0x2001,0x0023,"Philips Imaging DD 001",VR::DS,VM::VM1,"Flip Angle Philips",false }, + {0x2001,0x0024,"Philips Imaging DD 001",VR::CS,VM::VM1,"Interactive",false }, + {0x2001,0x0025,"Philips Imaging DD 001",VR::SH,VM::VM1,"Echo Time Display MR",false }, + {0x2001,0x0026,"Philips Imaging DD 001",VR::CS,VM::VM1,"Presentation State Subtraction Active",false }, + {0x2001,0x0028,"Philips Imaging DD 001",VR::FL,VM::VM1,"Edge Enhancement Gain Factor Sub",false }, + {0x2001,0x0029,"Philips Imaging DD 001",VR::FL,VM::VM1,"Edge Enhancement Gain Factor Non Sub",false }, + {0x2001,0x002a,"Philips Imaging DD 001",VR::CS,VM::VM1,"Edge Enhancement Taste Adapt Sub",false }, + {0x2001,0x002b,"Philips Imaging DD 001",VR::CS,VM::VM1,"Edge Enhancement Taste Non Sub",false }, + {0x2001,0x002c,"Philips Imaging DD 001",VR::FL,VM::VM1,"Harmonization Factor",false }, + {0x2001,0x002d,"Philips Imaging DD 001",VR::SS,VM::VM1,"Number of Stack Slices",false }, + {0x2001,0x002f,"Philips Imaging DD 001",VR::FL,VM::VM1,"Harmonization Gain",false }, + {0x2001,0x0030,"Philips Imaging DD 001",VR::UL,VM::VM1,"Log Subtraction Gain Step",false }, + {0x2001,0x0031,"Philips Imaging DD 001",VR::US,VM::VM1,"Mixing NR of Mask Image Numbers",false }, + {0x2001,0x0032,"Philips Imaging DD 001",VR::FL,VM::VM1_n,"Stack Radial Angle",false }, + {0x2001,0x0033,"Philips Imaging DD 001",VR::CS,VM::VM1_n,"Stack Radial Axis",false }, + {0x2001,0x0034,"Philips Imaging DD 001",VR::CS,VM::VM1,"Mixing Mask Operation",false }, + {0x2001,0x0035,"Philips Imaging DD 001",VR::SS,VM::VM1_n,"Stack Slice Number",false }, + {0x2001,0x0036,"Philips Imaging DD 001",VR::CS,VM::VM1_n,"Stack Type",false }, + {0x2001,0x0037,"Philips Imaging DD 001",VR::CS,VM::VM1,"Mixing Operation Type",false }, + {0x2001,0x0039,"Philips Imaging DD 001",VR::FL,VM::VM1,"?",false }, + {0x2001,0x003a,"Philips Imaging DD 001",VR::CS,VM::VM1,"Pixel Shift",false }, + {0x2001,0x003d,"Philips Imaging DD 001",VR::UL,VM::VM1,"?",false }, + {0x2001,0x003f,"Philips Imaging DD 001",VR::CS,VM::VM1,"Interpolation Method",false }, + {0x2001,0x0042,"Philips Imaging DD 001",VR::CS,VM::VM1,"Substraction Land Marking Active",false }, + {0x2001,0x0046,"Philips Imaging DD 001",VR::CS,VM::VM1,"Graphic Line Style",false }, + {0x2001,0x0047,"Philips Imaging DD 001",VR::FL,VM::VM1,"Graphic Line Width",false }, + {0x2001,0x0048,"Philips Imaging DD 001",VR::SS,VM::VM1,"Graphic Annotation ID",false }, + {0x2001,0x004b,"Philips Imaging DD 001",VR::CS,VM::VM1,"Poly Line Interpolation Method",false }, + {0x2001,0x004c,"Philips Imaging DD 001",VR::CS,VM::VM1,"Poly Line Begin Point Style",false }, + {0x2001,0x004d,"Philips Imaging DD 001",VR::CS,VM::VM1,"Poly Line End Point Style",false }, + {0x2001,0x004e,"Philips Imaging DD 001",VR::CS,VM::VM1,"Window Smoothing Taste",false }, + {0x2001,0x004f,"Philips Imaging DD 001",VR::FD,VM::VM1,"Harmonization Offset",false }, + {0x2001,0x0050,"Philips Imaging DD 001",VR::LO,VM::VM1,"?",false }, + {0x2001,0x0052,"Philips Imaging DD 001",VR::UI,VM::VM1,"?",false }, + {0x2001,0x0053,"Philips Imaging DD 001",VR::CS,VM::VM1,"Window Invert",false }, + {0x2001,0x0055,"Philips Imaging DD 001",VR::CS,VM::VM1,"Graphic Line Color",false }, + {0x2001,0x0056,"Philips Imaging DD 001",VR::CS,VM::VM1,"Graphic Type (Private)",false }, + {0x2001,0x005a,"Philips Imaging DD 001",VR::ST,VM::VM1,"Graphic Annotation Model",false }, + {0x2001,0x005d,"Philips Imaging DD 001",VR::ST,VM::VM1,"Measurement Text Units",false }, + {0x2001,0x005e,"Philips Imaging DD 001",VR::ST,VM::VM1,"Measurement Text Type",false }, + {0x2001,0x005f,"Philips Imaging DD 001",VR::SQ,VM::VM1,"Stack Sequence",false }, + {0x2001,0x0060,"Philips Imaging DD 001",VR::SL,VM::VM1,"Number of Stacks",false }, + {0x2001,0x0061,"Philips Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2001,0x0062,"Philips Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2001,0x0063,"Philips Imaging DD 001",VR::CS,VM::VM1,"Examination Source",false }, + {0x2001,0x0064,"Philips Imaging DD 001",VR::SH,VM::VM1,"Text Type",false }, + {0x2001,0x0065,"Philips Imaging DD 001",VR::SQ,VM::VM1,"?",false }, + {0x2001,0x0067,"Philips Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2001,0x0068,"Philips Imaging DD 001",VR::SQ,VM::VM1,"?",false }, + {0x2001,0x0069,"Philips Imaging DD 001",VR::SQ,VM::VM1,"Display Shutter Sequence",false }, + {0x2001,0x006a,"Philips Imaging DD 001",VR::SQ,VM::VM1,"?",false }, + {0x2001,0x006b,"Philips Imaging DD 001",VR::SQ,VM::VM1,"Has Edge Enhancement Sequence",false }, + {0x2001,0x006d,"Philips Imaging DD 001",VR::LO,VM::VM1,"Text Font",false }, + {0x2001,0x006e,"Philips Imaging DD 001",VR::SH,VM::VM1,"Series Type",false }, + {0x2001,0x006f,"Philips Imaging DD 001",VR::SQ,VM::VM1,"Mixing Sequence",false }, + {0x2001,0x0071,"Philips Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2001,0x0073,"Philips Imaging DD 001",VR::SQ,VM::VM1,"Referenced Mask Image Sequence",false }, + {0x2001,0x0074,"Philips Imaging DD 001",VR::DS,VM::VM1_n,"Window Center Sub",false }, + {0x2001,0x0075,"Philips Imaging DD 001",VR::DS,VM::VM1_n,"Window Width Sub",false }, + {0x2001,0x0076,"Philips Imaging DD 001",VR::UL,VM::VM1,"?",false }, + {0x2001,0x0077,"Philips Imaging DD 001",VR::CS,VM::VM1,"GL TrafoType",false }, + {0x2001,0x0079,"Philips Imaging DD 001",VR::SQ,VM::VM1,"Harmonisation Sequence",false }, + {0x2001,0x007a,"Philips Imaging DD 001",VR::FL,VM::VM1,"?",false }, + {0x2001,0x007b,"Philips Imaging DD 001",VR::IS,VM::VM1,"Acquisition Number",false }, + {0x2001,0x007e,"Philips Imaging DD 001",VR::US,VM::VM1,"Edge Enhancement Gain Taste",false }, + {0x2001,0x007f,"Philips Imaging DD 001",VR::US,VM::VM1,"Edge Enhancement Gain Taste Sub",false }, + {0x2001,0x0080,"Philips Imaging DD 001",VR::LO,VM::VM1,"Text Anchor Point Alignment",false }, + {0x2001,0x0081,"Philips Imaging DD 001",VR::IS,VM::VM1,"Number of Dynamic Scans",false }, + {0x2001,0x0082,"Philips Imaging DD 001",VR::IS,VM::VM1,"Echo Train Length",false }, + {0x2001,0x0083,"Philips Imaging DD 001",VR::DS,VM::VM1,"Imaging Frequency",false }, + {0x2001,0x0084,"Philips Imaging DD 001",VR::DS,VM::VM1,"Inversion Time",false }, + {0x2001,0x0085,"Philips Imaging DD 001",VR::DS,VM::VM1,"Magnetic Field Strength",false }, + {0x2001,0x0086,"Philips Imaging DD 001",VR::IS,VM::VM1,"?",false }, + {0x2001,0x0087,"Philips Imaging DD 001",VR::SH,VM::VM1,"Imaged Nucleus",false }, + {0x2001,0x0088,"Philips Imaging DD 001",VR::DS,VM::VM1,"Number of Averages",false }, + {0x2001,0x0089,"Philips Imaging DD 001",VR::DS,VM::VM1,"Phase FOV Percent",false }, + {0x2001,0x008a,"Philips Imaging DD 001",VR::DS,VM::VM1,"Sampling Percent",false }, + {0x2001,0x008b,"Philips Imaging DD 001",VR::SH,VM::VM1,"?",false }, + {0x2001,0x0093,"Philips Imaging DD 001",VR::LO,VM::VM1,"Text Style",false }, + {0x2001,0x0094,"Philips Imaging DD 001",VR::LO,VM::VM1,"Processing Order Specialization",false }, + {0x2001,0x0097,"Philips Imaging DD 001",VR::SH,VM::VM1,"Nucleus",false }, + {0x2001,0x009a,"Philips Imaging DD 001",VR::SQ,VM::VM1,"Graphic Number Sequence",false }, + {0x2001,0x009b,"Philips Imaging DD 001",VR::UL,VM::VM1,"Graphic Number",false }, + {0x2001,0x009c,"Philips Imaging DD 001",VR::LO,VM::VM1,"?",false }, + {0x2001,0x009d,"Philips Imaging DD 001",VR::LO,VM::VM1,"PIIM Substraction Type",false }, + {0x2001,0x009f,"Philips Imaging DD 001",VR::US,VM::VM2,"Pixel Processing Kernel Size",false }, + {0x2001,0x00a1,"Philips Imaging DD 001",VR::CS,VM::VM1,"Is Raw Image",false }, + {0x2001,0x00a2,"Philips Imaging DD 001",VR::US,VM::VM1,"LOG Substraction Curve Taste",false }, + {0x2001,0x00a3,"Philips Imaging DD 001",VR::UL,VM::VM1,"Text Color Foreground",false }, + {0x2001,0x00a4,"Philips Imaging DD 001",VR::UL,VM::VM1,"Text Color Background",false }, + {0x2001,0x00a5,"Philips Imaging DD 001",VR::UL,VM::VM1,"Text Color Shadow",false }, + {0x2001,0x00c1,"Philips Imaging DD 001",VR::LO,VM::VM1,"Nested Object Type Name",false }, + {0x2001,0x00c8,"Philips Imaging DD 001",VR::LO,VM::VM1,"?",false }, + {0x2001,0x00cc,"Philips Imaging DD 001",VR::ST,VM::VM1,"?",false }, + {0x2001,0x00da,"Philips Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2001,0x00f1,"Philips Imaging DD 001",VR::FL,VM::VM1_n,"Prospective Motion Correction",false }, + {0x2001,0x00f2,"Philips Imaging DD 001",VR::FL,VM::VM1,"Retrospective Motion Correction",false }, + {0x2005,0x0014,"Philips Imaging DD 001",VR::CS,VM::VM1,"Diffusion",false }, + {0x2005,0x0020,"Philips Imaging DD 001",VR::SL,VM::VM1,"Number of Chemical Shifts",false }, + {0x2005,0x0030,"Philips Imaging DD 001",VR::FL,VM::VM1,"Repetition Time",false }, + {0x2005,0x0033,"Philips Imaging DD 001",VR::FL,VM::VM1,"Scan Duration",false }, + {0x2005,0x0035,"Philips Imaging DD 001",VR::CS,VM::VM1,"Data Type",false }, + {0x2005,0x008b,"Philips Imaging DD 001",VR::SH,VM::VM1,"Transmitting Coil",false }, + {0x2005,0x009f,"Philips Imaging DD 001",VR::CS,VM::VM1,"Spectral Selective Excitation Pulse",false }, + {0x2005,0x00a1,"Philips Imaging DD 001",VR::CS,VM::VM1,"Syncra Scan Type",false }, + {0x2001,0x0001,"Philips Imaging DD 002",VR::US,VM::VM1,"?",false }, + {0x2001,0x0002,"Philips Imaging DD 002",VR::FD,VM::VM1,"?",false }, + {0x2001,0x0013,"Philips Imaging DD 002",VR::SS,VM::VM1,"?",false }, + {0x2001,0x0014,"Philips Imaging DD 002",VR::FD,VM::VM1,"?",false }, + {0x2001,0x0015,"Philips Imaging DD 002",VR::FD,VM::VM1,"?",false }, + {0x2001,0x0016,"Philips Imaging DD 002",VR::FD,VM::VM1,"?",false }, + {0x2001,0x0017,"Philips Imaging DD 002",VR::FD,VM::VM1,"?",false }, + {0x2001,0x0018,"Philips Imaging DD 002",VR::CS,VM::VM1,"?",false }, + {0x2001,0x0019,"Philips Imaging DD 002",VR::FD,VM::VM1,"?",false }, + {0x2001,0x001a,"Philips Imaging DD 002",VR::FD,VM::VM1,"?",false }, + {0x2001,0x001b,"Philips Imaging DD 002",VR::FD,VM::VM1,"?",false }, + {0x2001,0x001c,"Philips Imaging DD 002",VR::FD,VM::VM1,"?",false }, + {0x2001,0x001d,"Philips Imaging DD 002",VR::FD,VM::VM1,"?",false }, + {0x2001,0x001e,"Philips Imaging DD 002",VR::FD,VM::VM1,"?",false }, + {0x2001,0x001f,"Philips Imaging DD 002",VR::FD,VM::VM1,"?",false }, + {0x2001,0x0020,"Philips Imaging DD 002",VR::FD,VM::VM1,"?",false }, + {0x2001,0x0021,"Philips Imaging DD 002",VR::FD,VM::VM1,"?",false }, + {0x2001,0x0022,"Philips Imaging DD 002",VR::FD,VM::VM1,"?",false }, + {0x2001,0x0023,"Philips Imaging DD 002",VR::FD,VM::VM1,"?",false }, + {0x2001,0x0024,"Philips Imaging DD 002",VR::FD,VM::VM1,"?",false }, + {0x2001,0x0025,"Philips Imaging DD 002",VR::FD,VM::VM1,"?",false }, + {0x2001,0x0026,"Philips Imaging DD 002",VR::FD,VM::VM1,"?",false }, + {0x2001,0x0027,"Philips Imaging DD 002",VR::FD,VM::VM1,"?",false }, + {0x2001,0x0028,"Philips Imaging DD 002",VR::US,VM::VM1,"?",false }, + {0x2001,0x0029,"Philips Imaging DD 002",VR::US,VM::VM1,"?",false }, + {0x2001,0x002a,"Philips Imaging DD 002",VR::US,VM::VM1,"?",false }, + {0x2001,0x002b,"Philips Imaging DD 002",VR::SS,VM::VM1,"?",false }, + {0x2001,0x002c,"Philips Imaging DD 002",VR::FD,VM::VM1,"?",false }, + {0x2001,0x002d,"Philips Imaging DD 002",VR::FD,VM::VM1,"?",false }, + {0x2001,0x002e,"Philips Imaging DD 002",VR::SS,VM::VM1,"?",false }, + {0x2001,0x002f,"Philips Imaging DD 002",VR::SS,VM::VM1,"?",false }, + {0x2001,0x0030,"Philips Imaging DD 002",VR::SS,VM::VM1,"?",false }, + {0x2001,0x0031,"Philips Imaging DD 002",VR::SS,VM::VM1,"?",false }, + {0x2001,0x0032,"Philips Imaging DD 002",VR::SS,VM::VM1,"?",false }, + {0x2001,0x0033,"Philips Imaging DD 002",VR::SS,VM::VM1,"?",false }, + {0x2001,0x0034,"Philips Imaging DD 002",VR::SS,VM::VM1,"?",false }, + {0x2001,0x0035,"Philips Imaging DD 002",VR::FD,VM::VM1,"?",false }, + {0x2001,0x0036,"Philips Imaging DD 002",VR::FD,VM::VM1,"?",false }, + {0x2001,0x0037,"Philips Imaging DD 002",VR::FD,VM::VM1,"?",false }, + {0x2001,0x0039,"Philips Imaging DD 002",VR::CS,VM::VM1,"?",false }, + {0x2001,0x003a,"Philips Imaging DD 002",VR::SQ,VM::VM1,"?",false }, + {0x2001,0x003b,"Philips Imaging DD 002",VR::SQ,VM::VM1,"?",false }, + {0x2001,0x003c,"Philips Imaging DD 002",VR::SQ,VM::VM1,"?",false }, + {0x2001,0x003d,"Philips Imaging DD 002",VR::SQ,VM::VM1,"?",false }, + {0x2001,0x003e,"Philips Imaging DD 002",VR::SS,VM::VM1,"?",false }, + {0x2001,0x003f,"Philips Imaging DD 002",VR::SS,VM::VM1,"?",false }, + {0x2001,0x0040,"Philips Imaging DD 002",VR::SS,VM::VM1,"?",false }, + {0x4007,0x0000,"Philips Imaging DD 065",VR::CS,VM::VM1,"?",false }, + {0x4001,0x0000,"Philips Imaging DD 067",VR::SQ,VM::VM1,"?",false }, + {0x4001,0x0001,"Philips Imaging DD 067",VR::CS,VM::VM1,"?",false }, + {0x4001,0x0008,"Philips Imaging DD 067",VR::CS,VM::VM1,"?",false }, + {0x4001,0x0010,"Philips Imaging DD 070",VR::SQ,VM::VM1,"?",false }, + {0x4001,0x0011,"Philips Imaging DD 070",VR::SQ,VM::VM1,"?",false }, + {0x4001,0x0012,"Philips Imaging DD 070",VR::SQ,VM::VM1,"?",false }, + {0x4001,0x0016,"Philips Imaging DD 070",VR::ST,VM::VM1,"?",false }, + {0x4001,0x0017,"Philips Imaging DD 070",VR::ST,VM::VM1,"?",false }, + {0x4001,0x0018,"Philips Imaging DD 070",VR::ST,VM::VM1,"?",false }, + {0x4001,0x001c,"Philips Imaging DD 070",VR::SQ,VM::VM1,"?",false }, + {0x4001,0x001d,"Philips Imaging DD 070",VR::LT,VM::VM1,"?",false }, + {0x4007,0x0048,"Philips Imaging DD 073",VR::FL,VM::VM1,"?",false }, + {0x1001,0x0003,"Philips Imaging DD 124",VR::LO,VM::VM1,"?",false }, /* MR Import Filter 3/21/2014 1:57:35 PM */ + {0x2001,0x0000,"Philips Imaging DD 129",VR::SQ,VM::VM1,"?",false }, + {0x2001,0x0001,"Philips Imaging DD 129",VR::SQ,VM::VM1,"?",false }, + {0x2005,0x0000,"PHILIPS MR IMAGING DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0001,"PHILIPS MR IMAGING DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0002,"PHILIPS MR IMAGING DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0003,"PHILIPS MR IMAGING DD 001",VR::IS,VM::VM1,"?",false }, + {0x2005,0x0004,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0005,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"Synergy Reconstruction Type",false }, + {0x2005,0x0006,"PHILIPS MR IMAGING DD 001",VR::UI,VM::VM1,"?",false }, + {0x2005,0x0007,"PHILIPS MR IMAGING DD 001",VR::IS,VM::VM1,"?",false }, + {0x2005,0x0008,"PHILIPS MR IMAGING DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0009,"PHILIPS MR IMAGING DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x000a,"PHILIPS MR IMAGING DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x000b,"PHILIPS MR IMAGING DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x000c,"PHILIPS MR IMAGING DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x000d,"PHILIPS MR IMAGING DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x000e,"PHILIPS MR IMAGING DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x000f,"PHILIPS MR IMAGING DD 001",VR::DS,VM::VM1,"Window Center Philips",false }, + {0x2005,0x0010,"PHILIPS MR IMAGING DD 001",VR::DS,VM::VM1,"Window Width Philips",false }, + {0x2005,0x0011,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0012,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0013,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0014,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"Diffusion",false }, + {0x2005,0x0015,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0016,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0017,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0018,"PHILIPS MR IMAGING DD 001",VR::LO,VM::VM1,"?",false }, + {0x2005,0x0019,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x001a,"PHILIPS MR IMAGING DD 001",VR::SS,VM::VM1,"?",false }, + {0x2005,0x001b,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x001c,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x001d,"PHILIPS MR IMAGING DD 001",VR::SS,VM::VM1,"?",false }, + {0x2005,0x001e,"PHILIPS MR IMAGING DD 001",VR::SH,VM::VM1,"?",false }, + {0x2005,0x001f,"PHILIPS MR IMAGING DD 001",VR::SH,VM::VM1,"?",false }, + {0x2005,0x0020,"PHILIPS MR IMAGING DD 001",VR::SL,VM::VM1,"Number of Chemical Shift",false }, + {0x2005,0x0021,"PHILIPS MR IMAGING DD 001",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0022,"PHILIPS MR IMAGING DD 001",VR::IS,VM::VM1,"?",false }, + {0x2005,0x0023,"PHILIPS MR IMAGING DD 001",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0025,"PHILIPS MR IMAGING DD 001",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0026,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0027,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0028,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0029,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x002a,"PHILIPS MR IMAGING DD 001",VR::IS,VM::VM1,"?",false }, + {0x2005,0x002b,"PHILIPS MR IMAGING DD 001",VR::SS,VM::VM1,"?",false }, + {0x2005,0x002c,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x002d,"PHILIPS MR IMAGING DD 001",VR::IS,VM::VM1,"?",false }, + {0x2005,0x002e,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x002f,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0030,"PHILIPS MR IMAGING DD 001",VR::FL,VM::VM1,"Repetition Time",false }, + {0x2005,0x0031,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0032,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0033,"PHILIPS MR IMAGING DD 001",VR::FL,VM::VM1,"Scan Duration",false }, + {0x2005,0x0034,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0035,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"Data Type",false }, + {0x2005,0x0036,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0037,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0038,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0039,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x003a,"PHILIPS MR IMAGING DD 001",VR::SH,VM::VM1,"?",false }, + {0x2005,0x003b,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x003c,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x003d,"PHILIPS MR IMAGING DD 001",VR::SS,VM::VM1,"?",false }, + {0x2005,0x003e,"PHILIPS MR IMAGING DD 001",VR::SL,VM::VM1_n,"?",false }, + {0x2005,0x003f,"PHILIPS MR IMAGING DD 001",VR::SL,VM::VM1,"?",false }, + {0x2005,0x0040,"PHILIPS MR IMAGING DD 001",VR::SL,VM::VM1,"?",false }, + {0x2005,0x0041,"PHILIPS MR IMAGING DD 001",VR::SL,VM::VM1,"?",false }, + {0x2005,0x0042,"PHILIPS MR IMAGING DD 001",VR::SL,VM::VM1,"?",false }, + {0x2005,0x0043,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0044,"PHILIPS MR IMAGING DD 001",VR::SL,VM::VM1,"?",false }, + {0x2005,0x0045,"PHILIPS MR IMAGING DD 001",VR::SL,VM::VM1,"?",false }, + {0x2005,0x0046,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0047,"PHILIPS MR IMAGING DD 001",VR::SL,VM::VM1,"?",false }, + {0x2005,0x0048,"PHILIPS MR IMAGING DD 001",VR::IS,VM::VM1,"?",false }, + {0x2005,0x0049,"PHILIPS MR IMAGING DD 001",VR::IS,VM::VM1,"?",false }, + {0x2005,0x004a,"PHILIPS MR IMAGING DD 001",VR::IS,VM::VM1,"?",false }, + {0x2005,0x004b,"PHILIPS MR IMAGING DD 001",VR::IS,VM::VM1,"?",false }, + {0x2005,0x004c,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x004d,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x004e,"PHILIPS MR IMAGING DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x004f,"PHILIPS MR IMAGING DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0050,"PHILIPS MR IMAGING DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0051,"PHILIPS MR IMAGING DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0052,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0053,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0054,"PHILIPS MR IMAGING DD 001",VR::FL,VM::VM1,"SVS Voxel Angulation AP (deg)",false }, + {0x2005,0x0055,"PHILIPS MR IMAGING DD 001",VR::FL,VM::VM1,"SVS Voxel Angulation FH (deg)",false }, + {0x2005,0x0056,"PHILIPS MR IMAGING DD 001",VR::FL,VM::VM1,"SVS Voxel Angulation LR (deg)",false }, + {0x2005,0x0057,"PHILIPS MR IMAGING DD 001",VR::FL,VM::VM1,"SVS Voxel Size AP (mm)",false }, + {0x2005,0x0058,"PHILIPS MR IMAGING DD 001",VR::FL,VM::VM1,"SVS Voxel Size FH (mm)",false }, + {0x2005,0x0059,"PHILIPS MR IMAGING DD 001",VR::FL,VM::VM1,"SVS Voxel Size LR (mm)",false }, + {0x2005,0x005a,"PHILIPS MR IMAGING DD 001",VR::FL,VM::VM1,"SVS Voxel Offcenter AP (mm)",false }, + {0x2005,0x005b,"PHILIPS MR IMAGING DD 001",VR::FL,VM::VM1,"SVS Voxel Offcenter FH (mm)",false }, + {0x2005,0x005c,"PHILIPS MR IMAGING DD 001",VR::FL,VM::VM1,"SVS Voxel Offcenter LR (mm)",false }, + {0x2005,0x005d,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x005e,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x005f,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0060,"PHILIPS MR IMAGING DD 001",VR::IS,VM::VM1,"?",false }, + {0x2005,0x0061,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0063,"PHILIPS MR IMAGING DD 001",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0064,"PHILIPS MR IMAGING DD 001",VR::IS,VM::VM1,"?",false }, + {0x2005,0x0065,"PHILIPS MR IMAGING DD 001",VR::IS,VM::VM1,"?",false }, + {0x2005,0x0066,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0067,"PHILIPS MR IMAGING DD 001",VR::IS,VM::VM1,"?",false }, + {0x2005,0x0068,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0069,"PHILIPS MR IMAGING DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x006a,"PHILIPS MR IMAGING DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x006b,"PHILIPS MR IMAGING DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x006c,"PHILIPS MR IMAGING DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x006d,"PHILIPS MR IMAGING DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x006e,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x006f,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0070,"PHILIPS MR IMAGING DD 001",VR::LO,VM::VM1,"?",false }, + {0x2005,0x0071,"PHILIPS MR IMAGING DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0072,"PHILIPS MR IMAGING DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0073,"PHILIPS MR IMAGING DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0074,"PHILIPS MR IMAGING DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0075,"PHILIPS MR IMAGING DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0076,"PHILIPS MR IMAGING DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0078,"PHILIPS MR IMAGING DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0079,"PHILIPS MR IMAGING DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x007a,"PHILIPS MR IMAGING DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x007b,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x007e,"PHILIPS MR IMAGING DD 001",VR::FL,VM::VM1,"Z-Spacing (Philips)",false }, + {0x2005,0x0080,"PHILIPS MR IMAGING DD 001",VR::SQ,VM::VM1,"?",false }, + {0x2005,0x0081,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0083,"PHILIPS MR IMAGING DD 001",VR::SQ,VM::VM1,"?",false }, + {0x2005,0x0084,"PHILIPS MR IMAGING DD 001",VR::SQ,VM::VM1,"?",false }, + {0x2005,0x0085,"PHILIPS MR IMAGING DD 001",VR::SQ,VM::VM1,"?",false }, + {0x2005,0x0086,"PHILIPS MR IMAGING DD 001",VR::SS,VM::VM1,"?",false }, + {0x2005,0x009e,"PHILIPS MR IMAGING DD 001",VR::SQ,VM::VM1,"?",false }, + {0x2005,0x009f,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x00a0,"PHILIPS MR IMAGING DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x00a1,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"Syncra Scan Type",false }, + {0x2005,0x00a2,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x00a3,"PHILIPS MR IMAGING DD 001",VR::IS,VM::VM1,"?",false }, + {0x2005,0x00a4,"PHILIPS MR IMAGING DD 001",VR::IS,VM::VM1,"?",false }, + {0x2005,0x00a5,"PHILIPS MR IMAGING DD 001",VR::IS,VM::VM1,"?",false }, + {0x2005,0x00a6,"PHILIPS MR IMAGING DD 001",VR::IS,VM::VM1,"?",false }, + {0x2005,0x00a7,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x00a8,"PHILIPS MR IMAGING DD 001",VR::DS,VM::VM1,"?",false }, + {0x2005,0x00a9,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x00b0,"PHILIPS MR IMAGING DD 001",VR::FL,VM::VM1,"Diffusion Direction RL",false }, + {0x2005,0x00b1,"PHILIPS MR IMAGING DD 001",VR::FL,VM::VM1,"Diffusion Direction AP",false }, + {0x2005,0x00b2,"PHILIPS MR IMAGING DD 001",VR::FL,VM::VM1,"Diffusion Direction FH",false }, + {0x2005,0x00c0,"PHILIPS MR IMAGING DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0000,"Philips MR Imaging DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0001,"Philips MR Imaging DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0002,"Philips MR Imaging DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0003,"Philips MR Imaging DD 001",VR::IS,VM::VM1,"?",false }, + {0x2005,0x0004,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0005,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"Synergy Reconstruction Type",false }, + {0x2005,0x0006,"Philips MR Imaging DD 001",VR::UI,VM::VM1,"?",false }, + {0x2005,0x0007,"Philips MR Imaging DD 001",VR::IS,VM::VM1,"?",false }, + {0x2005,0x0008,"Philips MR Imaging DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0009,"Philips MR Imaging DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x000a,"Philips MR Imaging DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x000b,"Philips MR Imaging DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x000c,"Philips MR Imaging DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x000d,"Philips MR Imaging DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x000e,"Philips MR Imaging DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x000f,"Philips MR Imaging DD 001",VR::DS,VM::VM1,"Window Center Philips",false }, + {0x2005,0x0010,"Philips MR Imaging DD 001",VR::DS,VM::VM1,"Window Width Philips",false }, + {0x2005,0x0011,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0012,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0013,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0014,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"Diffusion",false }, + {0x2005,0x0015,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0016,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0017,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0018,"Philips MR Imaging DD 001",VR::LO,VM::VM1,"?",false }, + {0x2005,0x0019,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x001a,"Philips MR Imaging DD 001",VR::SS,VM::VM1,"?",false }, + {0x2005,0x001b,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x001c,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x001d,"Philips MR Imaging DD 001",VR::SS,VM::VM1,"?",false }, + {0x2005,0x001e,"Philips MR Imaging DD 001",VR::SH,VM::VM1,"?",false }, + {0x2005,0x001f,"Philips MR Imaging DD 001",VR::SH,VM::VM1,"?",false }, + {0x2005,0x0020,"Philips MR Imaging DD 001",VR::SL,VM::VM1,"Number of Chemical Shift",false }, + {0x2005,0x0021,"Philips MR Imaging DD 001",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0022,"Philips MR Imaging DD 001",VR::IS,VM::VM1,"?",false }, + {0x2005,0x0023,"Philips MR Imaging DD 001",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0025,"Philips MR Imaging DD 001",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0026,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0027,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0028,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0029,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x002a,"Philips MR Imaging DD 001",VR::IS,VM::VM1,"?",false }, + {0x2005,0x002b,"Philips MR Imaging DD 001",VR::SS,VM::VM1,"?",false }, + {0x2005,0x002c,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x002d,"Philips MR Imaging DD 001",VR::IS,VM::VM1,"?",false }, + {0x2005,0x002e,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x002f,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0030,"Philips MR Imaging DD 001",VR::FL,VM::VM1,"Repetition Time",false }, + {0x2005,0x0031,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0032,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0033,"Philips MR Imaging DD 001",VR::FL,VM::VM1,"Scan Duration",false }, + {0x2005,0x0034,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0035,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"Data Type",false }, + {0x2005,0x0036,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0037,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0038,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0039,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x003a,"Philips MR Imaging DD 001",VR::SH,VM::VM1,"?",false }, + {0x2005,0x003b,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x003c,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x003d,"Philips MR Imaging DD 001",VR::SS,VM::VM1,"?",false }, + {0x2005,0x003e,"Philips MR Imaging DD 001",VR::SL,VM::VM1_n,"?",false }, + {0x2005,0x003f,"Philips MR Imaging DD 001",VR::SL,VM::VM1,"?",false }, + {0x2005,0x0040,"Philips MR Imaging DD 001",VR::SL,VM::VM1,"?",false }, + {0x2005,0x0041,"Philips MR Imaging DD 001",VR::SL,VM::VM1,"?",false }, + {0x2005,0x0042,"Philips MR Imaging DD 001",VR::SL,VM::VM1,"?",false }, + {0x2005,0x0043,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0044,"Philips MR Imaging DD 001",VR::SL,VM::VM1,"?",false }, + {0x2005,0x0045,"Philips MR Imaging DD 001",VR::SL,VM::VM1,"?",false }, + {0x2005,0x0046,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0047,"Philips MR Imaging DD 001",VR::SL,VM::VM1,"?",false }, + {0x2005,0x0048,"Philips MR Imaging DD 001",VR::IS,VM::VM1,"?",false }, + {0x2005,0x0049,"Philips MR Imaging DD 001",VR::IS,VM::VM1,"?",false }, + {0x2005,0x004a,"Philips MR Imaging DD 001",VR::IS,VM::VM1,"?",false }, + {0x2005,0x004b,"Philips MR Imaging DD 001",VR::IS,VM::VM1,"?",false }, + {0x2005,0x004c,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x004d,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x004e,"Philips MR Imaging DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x004f,"Philips MR Imaging DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0050,"Philips MR Imaging DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0051,"Philips MR Imaging DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0052,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0053,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0054,"Philips MR Imaging DD 001",VR::FL,VM::VM1,"SVS Voxel Angulation AP (deg)",false }, + {0x2005,0x0055,"Philips MR Imaging DD 001",VR::FL,VM::VM1,"SVS Voxel Angulation FH (deg)",false }, + {0x2005,0x0056,"Philips MR Imaging DD 001",VR::FL,VM::VM1,"SVS Voxel Angulation LR (deg)",false }, + {0x2005,0x0057,"Philips MR Imaging DD 001",VR::FL,VM::VM1,"SVS Voxel Size AP (mm)",false }, + {0x2005,0x0058,"Philips MR Imaging DD 001",VR::FL,VM::VM1,"SVS Voxel Size FH (mm)",false }, + {0x2005,0x0059,"Philips MR Imaging DD 001",VR::FL,VM::VM1,"SVS Voxel Size LR (mm)",false }, + {0x2005,0x005a,"Philips MR Imaging DD 001",VR::FL,VM::VM1,"SVS Voxel Offcenter AP (mm)",false }, + {0x2005,0x005b,"Philips MR Imaging DD 001",VR::FL,VM::VM1,"SVS Voxel Offcenter FH (mm)",false }, + {0x2005,0x005c,"Philips MR Imaging DD 001",VR::FL,VM::VM1,"SVS Voxel Offcenter LR (mm)",false }, + {0x2005,0x005d,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x005e,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x005f,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0060,"Philips MR Imaging DD 001",VR::IS,VM::VM1,"?",false }, + {0x2005,0x0061,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0063,"Philips MR Imaging DD 001",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0064,"Philips MR Imaging DD 001",VR::IS,VM::VM1,"?",false }, + {0x2005,0x0065,"Philips MR Imaging DD 001",VR::IS,VM::VM1,"?",false }, + {0x2005,0x0066,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0067,"Philips MR Imaging DD 001",VR::IS,VM::VM1,"?",false }, + {0x2005,0x0068,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0069,"Philips MR Imaging DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x006a,"Philips MR Imaging DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x006b,"Philips MR Imaging DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x006c,"Philips MR Imaging DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x006d,"Philips MR Imaging DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x006e,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x006f,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0070,"Philips MR Imaging DD 001",VR::LO,VM::VM1,"?",false }, + {0x2005,0x0071,"Philips MR Imaging DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0072,"Philips MR Imaging DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0073,"Philips MR Imaging DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0074,"Philips MR Imaging DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0075,"Philips MR Imaging DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0076,"Philips MR Imaging DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0078,"Philips MR Imaging DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0079,"Philips MR Imaging DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x007a,"Philips MR Imaging DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x007b,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x007e,"Philips MR Imaging DD 001",VR::FL,VM::VM1,"Z-Spacing (Philips)",false }, + {0x2005,0x0080,"Philips MR Imaging DD 001",VR::SQ,VM::VM1,"?",false }, + {0x2005,0x0081,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0083,"Philips MR Imaging DD 001",VR::SQ,VM::VM1,"?",false }, + {0x2005,0x0084,"Philips MR Imaging DD 001",VR::SQ,VM::VM1,"?",false }, + {0x2005,0x0085,"Philips MR Imaging DD 001",VR::SQ,VM::VM1,"?",false }, + {0x2005,0x0086,"Philips MR Imaging DD 001",VR::SS,VM::VM1,"?",false }, + {0x2005,0x009e,"Philips MR Imaging DD 001",VR::SQ,VM::VM1,"?",false }, + {0x2005,0x009f,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x00a0,"Philips MR Imaging DD 001",VR::FL,VM::VM1,"?",false }, + {0x2005,0x00a1,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"Syncra Scan Type",false }, + {0x2005,0x00a2,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x00a3,"Philips MR Imaging DD 001",VR::IS,VM::VM1,"?",false }, + {0x2005,0x00a4,"Philips MR Imaging DD 001",VR::IS,VM::VM1,"?",false }, + {0x2005,0x00a5,"Philips MR Imaging DD 001",VR::IS,VM::VM1,"?",false }, + {0x2005,0x00a6,"Philips MR Imaging DD 001",VR::IS,VM::VM1,"?",false }, + {0x2005,0x00a7,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x00a8,"Philips MR Imaging DD 001",VR::DS,VM::VM1,"?",false }, + {0x2005,0x00a9,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x00b0,"Philips MR Imaging DD 001",VR::FL,VM::VM1,"Diffusion Direction RL",false }, + {0x2005,0x00b1,"Philips MR Imaging DD 001",VR::FL,VM::VM1,"Diffusion Direction AP",false }, + {0x2005,0x00b2,"Philips MR Imaging DD 001",VR::FL,VM::VM1,"Diffusion Direction FH",false }, + {0x2005,0x00c0,"Philips MR Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0032,"Philips MR Imaging DD 002",VR::SQ,VM::VM1,"Protocol Data Sequence",false }, + {0x2005,0x0034,"Philips MR Imaging DD 002",VR::LT,VM::VM1,"?",false }, + {0x2005,0x0037,"Philips MR Imaging DD 002",VR::PN,VM::VM1,"Protocol Data Name",false }, + {0x2005,0x0038,"Philips MR Imaging DD 002",VR::PN,VM::VM1,"?",false }, + {0x2005,0x0039,"Philips MR Imaging DD 002",VR::PN,VM::VM1,"Protocol Data Type",false }, + {0x2005,0x0040,"Philips MR Imaging DD 002",VR::PN,VM::VM1,"?",false }, + {0x2005,0x0041,"Philips MR Imaging DD 002",VR::PN,VM::VM1,"?",false }, + {0x2005,0x0043,"Philips MR Imaging DD 002",VR::SL,VM::VM1,"Protocol Data Block Length (non-padded)",false }, + {0x2005,0x0044,"Philips MR Imaging DD 002",VR::OW,VM::VM1,"Protocol Data Block",false }, + {0x2005,0x0047,"Philips MR Imaging DD 002",VR::CS,VM::VM1,"Protocol Data Boolean",false }, + {0x2005,0x0099,"Philips MR Imaging DD 002",VR::UL,VM::VM1,"?",false }, + {0x2005,0x0000,"Philips MR Imaging DD 003",VR::UL,VM::VM1,"?",false }, + {0x2005,0x0001,"Philips MR Imaging DD 003",VR::UL,VM::VM1,"?",false }, + {0x2005,0x0013,"Philips MR Imaging DD 003",VR::UL,VM::VM1,"?",false }, + {0x2005,0x0034,"Philips MR Imaging DD 003",VR::SL,VM::VM1,"?",false }, + {0x2005,0x0043,"Philips MR Imaging DD 003",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0044,"Philips MR Imaging DD 003",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0045,"Philips MR Imaging DD 003",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0046,"Philips MR Imaging DD 003",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0047,"Philips MR Imaging DD 003",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0048,"Philips MR Imaging DD 003",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0049,"Philips MR Imaging DD 003",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0050,"Philips MR Imaging DD 003",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0051,"Philips MR Imaging DD 003",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0052,"Philips MR Imaging DD 003",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0053,"Philips MR Imaging DD 003",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0054,"Philips MR Imaging DD 003",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0055,"Philips MR Imaging DD 003",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0056,"Philips MR Imaging DD 003",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0057,"Philips MR Imaging DD 003",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0070,"Philips MR Imaging DD 003",VR::OW,VM::VM1,"FID storage (array of ieee floats)",false }, + {0x2005,0x0081,"Philips MR Imaging DD 003",VR::UI,VM::VM1,"?",false }, + {0x2005,0x0082,"Philips MR Imaging DD 003",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0000,"Philips MR Imaging DD 004",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0001,"Philips MR Imaging DD 004",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0002,"Philips MR Imaging DD 004",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0003,"Philips MR Imaging DD 004",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0004,"Philips MR Imaging DD 004",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0005,"Philips MR Imaging DD 004",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0006,"Philips MR Imaging DD 004",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0007,"Philips MR Imaging DD 004",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0008,"Philips MR Imaging DD 004",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0009,"Philips MR Imaging DD 004",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0010,"Philips MR Imaging DD 004",VR::FL,VM::VM1,"Echo Time (ms) (Spectroscopy only)",false }, + {0x2005,0x0012,"Philips MR Imaging DD 004",VR::FL,VM::VM1,"Inversion Time (ms) (Spectroscopy only)",false }, + {0x2005,0x0013,"Philips MR Imaging DD 004",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0014,"Philips MR Imaging DD 004",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0015,"Philips MR Imaging DD 004",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0016,"Philips MR Imaging DD 004",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0017,"Philips MR Imaging DD 004",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0018,"Philips MR Imaging DD 004",VR::SQ,VM::VM1,"?",false }, + {0x2005,0x0025,"Philips MR Imaging DD 004",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0026,"Philips MR Imaging DD 004",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0027,"Philips MR Imaging DD 004",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0028,"Philips MR Imaging DD 004",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0029,"Philips MR Imaging DD 004",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0030,"Philips MR Imaging DD 004",VR::CS,VM::VM1_n,"?",false }, + {0x2005,0x0031,"Philips MR Imaging DD 004",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0033,"Philips MR Imaging DD 004",VR::FL,VM::VM3,"?",false }, + {0x2005,0x0034,"Philips MR Imaging DD 004",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0035,"Philips MR Imaging DD 004",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0036,"Philips MR Imaging DD 004",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0037,"Philips MR Imaging DD 004",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0038,"Philips MR Imaging DD 004",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0039,"Philips MR Imaging DD 004",VR::SS,VM::VM2,"?",false }, + {0x2005,0x0040,"Philips MR Imaging DD 004",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0041,"Philips MR Imaging DD 004",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0042,"Philips MR Imaging DD 004",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0043,"Philips MR Imaging DD 004",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0044,"Philips MR Imaging DD 004",VR::SS,VM::VM1_n,"?",false }, + {0x2005,0x0045,"Philips MR Imaging DD 004",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0046,"Philips MR Imaging DD 004",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0047,"Philips MR Imaging DD 004",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0048,"Philips MR Imaging DD 004",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0049,"Philips MR Imaging DD 004",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0050,"Philips MR Imaging DD 004",VR::FL,VM::VM2,"?",false }, + {0x2005,0x0051,"Philips MR Imaging DD 004",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0052,"Philips MR Imaging DD 004",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0053,"Philips MR Imaging DD 004",VR::LO,VM::VM1_n,"?",false }, + {0x2005,0x0054,"Philips MR Imaging DD 004",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0055,"Philips MR Imaging DD 004",VR::FL,VM::VM1_n,"?",false }, + {0x2005,0x0056,"Philips MR Imaging DD 004",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0057,"Philips MR Imaging DD 004",VR::SS,VM::VM1,"Sampling Frequency",false }, + {0x2005,0x0058,"Philips MR Imaging DD 004",VR::LO,VM::VM1,"?",false }, + {0x2005,0x0059,"Philips MR Imaging DD 004",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0060,"Philips MR Imaging DD 004",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0061,"Philips MR Imaging DD 004",VR::FL,VM::VM2,"?",false }, + {0x2005,0x0062,"Philips MR Imaging DD 004",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0063,"Philips MR Imaging DD 004",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0064,"Philips MR Imaging DD 004",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0070,"Philips MR Imaging DD 004",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0071,"Philips MR Imaging DD 004",VR::SQ,VM::VM1,"?",false }, + {0x2005,0x0072,"Philips MR Imaging DD 004",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0073,"Philips MR Imaging DD 004",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0074,"Philips MR Imaging DD 004",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0075,"Philips MR Imaging DD 004",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0076,"Philips MR Imaging DD 004",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0077,"Philips MR Imaging DD 004",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0078,"Philips MR Imaging DD 004",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0079,"Philips MR Imaging DD 004",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0081,"Philips MR Imaging DD 004",VR::IS,VM::VM1,"?",false }, + {0x2005,0x0082,"Philips MR Imaging DD 004",VR::UL,VM::VM1,"?",false }, + {0x2005,0x0083,"Philips MR Imaging DD 004",VR::CS,VM::VM1_n,"?",false }, + {0x2005,0x0085,"Philips MR Imaging DD 004",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0086,"Philips MR Imaging DD 004",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0087,"Philips MR Imaging DD 004",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0088,"Philips MR Imaging DD 004",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0089,"Philips MR Imaging DD 004",VR::SQ,VM::VM1,"?",false }, + {0x2005,0x0090,"Philips MR Imaging DD 004",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0091,"Philips MR Imaging DD 004",VR::PN,VM::VM1,"?",false }, + {0x2005,0x0092,"Philips MR Imaging DD 004",VR::IS,VM::VM1,"?",false }, + {0x2005,0x0093,"Philips MR Imaging DD 004",VR::IS,VM::VM1,"?",false }, + {0x2005,0x0095,"Philips MR Imaging DD 004",VR::ST,VM::VM1,"?",false }, + {0x2005,0x0096,"Philips MR Imaging DD 004",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0097,"Philips MR Imaging DD 004",VR::LO,VM::VM1,"?",false }, + {0x2005,0x0098,"Philips MR Imaging DD 004",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0099,"Philips MR Imaging DD 004",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0000,"Philips MR Imaging DD 005",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0001,"Philips MR Imaging DD 005",VR::UL,VM::VM1,"?",false }, + {0x2005,0x0002,"Philips MR Imaging DD 005",VR::SQ,VM::VM1,"?",false }, + {0x2005,0x0003,"Philips MR Imaging DD 005",VR::UL,VM::VM1,"?",false }, + {0x2005,0x0006,"Philips MR Imaging DD 005",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0007,"Philips MR Imaging DD 005",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0009,"Philips MR Imaging DD 005",VR::DS,VM::VM1,"Rescale Intercept Philips",false }, + {0x2005,0x000a,"Philips MR Imaging DD 005",VR::DS,VM::VM1,"Rescale Slope Philips",false }, + {0x2005,0x000b,"Philips MR Imaging DD 005",VR::LO,VM::VM1,"Rescale Type Philips",false }, + {0x2005,0x000e,"Philips MR Imaging DD 005",VR::SQ,VM::VM1,"?",false }, + {0x2005,0x000f,"Philips MR Imaging DD 005",VR::SQ,VM::VM1,"Acquisition Parameters (Philips) Sequence",false }, + {0x2005,0x0010,"Philips MR Imaging DD 005",VR::IS,VM::VM1,"?",false }, + {0x2005,0x0011,"Philips MR Imaging DD 005",VR::UI,VM::VM1,"?",false }, + {0x2005,0x0012,"Philips MR Imaging DD 005",VR::IS,VM::VM1,"?",false }, + {0x2005,0x0013,"Philips MR Imaging DD 005",VR::IS,VM::VM1,"?",false }, + {0x2005,0x0014,"Philips MR Imaging DD 005",VR::SL,VM::VM1,"?",false }, + {0x2005,0x0015,"Philips MR Imaging DD 005",VR::SL,VM::VM1,"?",false }, + {0x2005,0x0016,"Philips MR Imaging DD 005",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0018,"Philips MR Imaging DD 005",VR::CS,VM::VM3,"?",false }, + {0x2005,0x0019,"Philips MR Imaging DD 005",VR::CS,VM::VM3,"?",false }, + {0x2005,0x001a,"Philips MR Imaging DD 005",VR::CS,VM::VM1,"?",false }, + {0x2005,0x001b,"Philips MR Imaging DD 005",VR::IS,VM::VM1,"?",false }, + {0x2005,0x001c,"Philips MR Imaging DD 005",VR::IS,VM::VM1,"?",false }, + {0x2005,0x001d,"Philips MR Imaging DD 005",VR::IS,VM::VM1,"?",false }, + {0x2005,0x001e,"Philips MR Imaging DD 005",VR::UL,VM::VM1,"?",false }, + {0x2005,0x001f,"Philips MR Imaging DD 005",VR::UL,VM::VM1,"?",false }, + {0x2005,0x0020,"Philips MR Imaging DD 005",VR::UL,VM::VM1,"?",false }, + {0x2005,0x0021,"Philips MR Imaging DD 005",VR::UL,VM::VM1,"?",false }, + {0x2005,0x0022,"Philips MR Imaging DD 005",VR::UL,VM::VM1,"?",false }, + {0x2005,0x0023,"Philips MR Imaging DD 005",VR::UL,VM::VM1,"?",false }, + {0x2005,0x0024,"Philips MR Imaging DD 005",VR::UL,VM::VM1,"?",false }, + {0x2005,0x0025,"Philips MR Imaging DD 005",VR::UL,VM::VM1,"?",false }, + {0x2005,0x0026,"Philips MR Imaging DD 005",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0027,"Philips MR Imaging DD 005",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0028,"Philips MR Imaging DD 005",VR::SL,VM::VM1,"?",false }, + {0x2005,0x002a,"Philips MR Imaging DD 005",VR::CS,VM::VM1,"?",false }, + {0x2005,0x002b,"Philips MR Imaging DD 005",VR::CS,VM::VM1,"?",false }, + {0x2005,0x002c,"Philips MR Imaging DD 005",VR::CS,VM::VM1,"?",false }, + {0x2005,0x002d,"Philips MR Imaging DD 005",VR::CS,VM::VM1,"?",false }, + {0x2005,0x002e,"Philips MR Imaging DD 005",VR::FL,VM::VM1,"?",false }, + {0x2005,0x002f,"Philips MR Imaging DD 005",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0030,"Philips MR Imaging DD 005",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0031,"Philips MR Imaging DD 005",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0032,"Philips MR Imaging DD 005",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0035,"Philips MR Imaging DD 005",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0036,"Philips MR Imaging DD 005",VR::UI,VM::VM1,"?",false }, + {0x2005,0x0037,"Philips MR Imaging DD 005",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0038,"Philips MR Imaging DD 005",VR::LT,VM::VM1,"?",false }, + {0x2005,0x0039,"Philips MR Imaging DD 005",VR::LT,VM::VM1,"?",false }, + {0x2005,0x003a,"Philips MR Imaging DD 005",VR::LT,VM::VM1,"?",false }, + {0x2005,0x003b,"Philips MR Imaging DD 005",VR::CS,VM::VM1,"?",false }, + {0x2005,0x003c,"Philips MR Imaging DD 005",VR::FL,VM::VM1,"?",false }, + {0x2005,0x003d,"Philips MR Imaging DD 005",VR::FL,VM::VM1,"?",false }, + {0x2005,0x003e,"Philips MR Imaging DD 005",VR::FL,VM::VM1,"?",false }, + {0x2005,0x003f,"Philips MR Imaging DD 005",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0040,"Philips MR Imaging DD 005",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0041,"Philips MR Imaging DD 005",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0042,"Philips MR Imaging DD 005",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0043,"Philips MR Imaging DD 005",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0044,"Philips MR Imaging DD 005",VR::IS,VM::VM1,"?",false }, + {0x2005,0x0045,"Philips MR Imaging DD 005",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0046,"Philips MR Imaging DD 005",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0047,"Philips MR Imaging DD 005",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0048,"Philips MR Imaging DD 005",VR::FL,VM::VM1,"?",false }, + {0x2005,0x0049,"Philips MR Imaging DD 005",VR::FL,VM::VM1,"?",false }, + {0x2005,0x004a,"Philips MR Imaging DD 005",VR::FL,VM::VM1,"?",false }, + {0x2005,0x004b,"Philips MR Imaging DD 005",VR::FL,VM::VM1,"?",false }, + {0x2005,0x004c,"Philips MR Imaging DD 005",VR::FL,VM::VM1,"?",false }, + {0x2005,0x004d,"Philips MR Imaging DD 005",VR::CS,VM::VM1,"?",false }, + {0x2005,0x004e,"Philips MR Imaging DD 005",VR::CS,VM::VM1,"?",false }, + {0x2005,0x004f,"Philips MR Imaging DD 005",VR::CS,VM::VM1,"?",false }, + {0x2005,0x0050,"Philips MR Imaging DD 005",VR::SS,VM::VM1,"?",false }, + {0x2005,0x0055,"Philips MR Imaging DD 005",VR::FD,VM::VM3,"?",false }, + {0x7043,0x0000,"Philips NM Private Group",VR::SH,VM::VM1,"?",false }, + {0x0511,0x0000,"Philips PET Private Group",VR::US,VM::VM1,"?",false }, + {0x0511,0x0001,"Philips PET Private Group",VR::US,VM::VM1,"?",false }, + {0x0511,0x0002,"Philips PET Private Group",VR::OB,VM::VM1,"?",false }, + {0x0511,0x0003,"Philips PET Private Group",VR::OB,VM::VM1,"?",false }, + {0x0511,0x0032,"Philips PET Private Group",VR::DS,VM::VM1,"?",false }, + {0x0511,0x0050,"Philips PET Private Group",VR::DS,VM::VM1,"?",false }, + {0x7053,0x0000,"Philips PET Private Group",VR::DS,VM::VM1,"SUV Scale Factor",false }, + {0x7053,0x0001,"Philips PET Private Group",VR::OB,VM::VM1,"Private",false }, + {0x7053,0x0002,"Philips PET Private Group",VR::OB,VM::VM1,"Private",false }, + {0x7053,0x0003,"Philips PET Private Group",VR::ST,VM::VM1,"Original image file name",false }, + {0x7053,0x0004,"Philips PET Private Group",VR::OB,VM::VM1,"File Data",false }, + {0x7053,0x0005,"Philips PET Private Group",VR::LO,VM::VM1,"Worklist Info File Name",false }, + {0x7053,0x0006,"Philips PET Private Group",VR::OB,VM::VM1,"Private",false }, + {0x7053,0x0007,"Philips PET Private Group",VR::SQ,VM::VM1,"Acquisition File Sequence",false }, + {0x7053,0x0008,"Philips PET Private Group",VR::SQ,VM::VM1,"?",false }, + {0x7053,0x0009,"Philips PET Private Group",VR::DS,VM::VM1,"Activity Concentration Scale Factor",false }, + {0x7053,0x000f,"Philips PET Private Group",VR::UL,VM::VM1,"Segment Size",false }, + {0x7053,0x0010,"Philips PET Private Group",VR::US,VM::VM1,"Segment Number",false }, + {0x7053,0x0011,"Philips PET Private Group",VR::US,VM::VM1,"Number of Segments",false }, + {0x7053,0x0012,"Philips PET Private Group",VR::SQ,VM::VM1,"File Data Sequence",false }, + {0x7053,0x0013,"Philips PET Private Group",VR::SS,VM::VM1,"Private",false }, + {0x7053,0x0014,"Philips PET Private Group",VR::SS,VM::VM1,"Private",false }, + {0x7053,0x0015,"Philips PET Private Group",VR::SS,VM::VM1,"Private",false }, + {0x7053,0x0016,"Philips PET Private Group",VR::SS,VM::VM1,"Private",false }, + {0x7053,0x0017,"Philips PET Private Group",VR::SS,VM::VM1,"Private",false }, + {0x7053,0x0018,"Philips PET Private Group",VR::SS,VM::VM1,"Private",false }, + {0x7053,0x00c2,"Philips PET Private Group",VR::UI,VM::VM1,"PET-CT Multi Modality Name",false }, + {0x200b,0x0000,"Philips RAD Imaging DD 001",VR::PN,VM::VM1,"?",false }, + {0x200b,0x0001,"Philips RAD Imaging DD 001",VR::US,VM::VM1,"?",false }, + {0x200b,0x0002,"Philips RAD Imaging DD 001",VR::US,VM::VM1,"?",false }, + {0x200b,0x0005,"Philips RAD Imaging DD 001",VR::IS,VM::VM1,"?",false }, + {0x200b,0x0011,"Philips RAD Imaging DD 001",VR::LO,VM::VM1,"?",false }, + {0x200b,0x0027,"Philips RAD Imaging DD 001",VR::DT,VM::VM1,"?",false }, + {0x200b,0x0028,"Philips RAD Imaging DD 001",VR::DS,VM::VM1,"?",false }, + {0x200b,0x0029,"Philips RAD Imaging DD 001",VR::DS,VM::VM1,"?",false }, + {0x200b,0x002a,"Philips RAD Imaging DD 001",VR::UL,VM::VM1,"?",false }, + {0x200b,0x002b,"Philips RAD Imaging DD 001",VR::DA,VM::VM1,"?",false }, + {0x200b,0x002c,"Philips RAD Imaging DD 001",VR::TM,VM::VM1,"?",false }, + {0x200b,0x002d,"Philips RAD Imaging DD 001",VR::LO,VM::VM1,"?",false }, + {0x200b,0x003b,"Philips RAD Imaging DD 001",VR::LO,VM::VM1,"?",false }, + {0x200b,0x0040,"Philips RAD Imaging DD 001",VR::SH,VM::VM1,"?",false }, + {0x200b,0x0041,"Philips RAD Imaging DD 001",VR::SH,VM::VM1,"?",false }, + {0x200b,0x0042,"Philips RAD Imaging DD 001",VR::UI,VM::VM1,"?",false }, + {0x200b,0x0043,"Philips RAD Imaging DD 001",VR::UI,VM::VM1,"?",false }, + {0x200b,0x0047,"Philips RAD Imaging DD 001",VR::DA,VM::VM1,"?",false }, + {0x200b,0x0048,"Philips RAD Imaging DD 001",VR::SH,VM::VM1,"?",false }, + {0x200b,0x004c,"Philips RAD Imaging DD 001",VR::SH,VM::VM1,"?",false }, + {0x200b,0x004d,"Philips RAD Imaging DD 001",VR::SH,VM::VM1,"?",false }, + {0x200b,0x004f,"Philips RAD Imaging DD 001",VR::DT,VM::VM1,"?",false }, + {0x200b,0x0052,"Philips RAD Imaging DD 001",VR::SH,VM::VM1,"?",false }, + {0x200b,0x0000,"Philips RAD Imaging DD 097",VR::ST,VM::VM1,"?",false }, + {0x200b,0x0001,"Philips RAD Imaging DD 097",VR::CS,VM::VM1,"?",false }, + {0x200b,0x0002,"Philips RAD Imaging DD 097",VR::SS,VM::VM1,"?",false }, + {0x200b,0x0050,"Philips RAD Imaging DD 097",VR::SS,VM::VM1,"?",false }, + {0x200b,0x0051,"Philips RAD Imaging DD 097",VR::SS,VM::VM1,"?",false }, + {0x200b,0x0052,"Philips RAD Imaging DD 097",VR::SS,VM::VM1,"?",false }, + {0x200b,0x0053,"Philips RAD Imaging DD 097",VR::SS,VM::VM1,"?",false }, + {0x200b,0x0054,"Philips RAD Imaging DD 097",VR::ST,VM::VM1,"?",false }, + {0x200b,0x0060,"Philips RAD Imaging DD 097",VR::LO,VM::VM1,"?",false }, + {0x200b,0x0063,"Philips RAD Imaging DD 097",VR::LT,VM::VM1,"?",false }, + {0x200b,0x0065,"Philips RAD Imaging DD 097",VR::SS,VM::VM1,"?",false }, + {0x200b,0x006e,"Philips RAD Imaging DD 097",VR::US,VM::VM1,"?",false }, + {0x200b,0x006f,"Philips RAD Imaging DD 097",VR::UI,VM::VM1,"?",false }, + {0x200b,0x0072,"Philips RAD Imaging DD 097",VR::FD,VM::VM1,"?",false }, + {0x200b,0x0073,"Philips RAD Imaging DD 097",VR::SS,VM::VM1,"?",false }, + {0x200b,0x0074,"Philips RAD Imaging DD 097",VR::IS,VM::VM1,"?",false }, + {0x200b,0x0075,"Philips RAD Imaging DD 097",VR::CS,VM::VM1,"?",false }, + {0x200b,0x0076,"Philips RAD Imaging DD 097",VR::SH,VM::VM1,"?",false }, + {0x200b,0x0078,"Philips RAD Imaging DD 097",VR::IS,VM::VM1_n,"?",false }, + {0x200b,0x0079,"Philips RAD Imaging DD 097",VR::IS,VM::VM1,"?",false }, + {0x200b,0x007a,"Philips RAD Imaging DD 097",VR::IS,VM::VM1,"?",false }, + {0x200b,0x007b,"Philips RAD Imaging DD 097",VR::US,VM::VM1,"?",false }, + {0x200b,0x007c,"Philips RAD Imaging DD 097",VR::US,VM::VM1,"?",false }, + {0x200b,0x007d,"Philips RAD Imaging DD 097",VR::IS,VM::VM1_n,"?",false }, + {0x200b,0x007e,"Philips RAD Imaging DD 097",VR::UI,VM::VM1,"?",false }, + {0x200b,0x0081,"Philips RAD Imaging DD 097",VR::SH,VM::VM1,"?",false }, + {0x200b,0x0082,"Philips RAD Imaging DD 097",VR::SH,VM::VM1,"?",false }, + {0x200b,0x0085,"Philips RAD Imaging DD 097",VR::IS,VM::VM1,"?",false }, + {0x200b,0x0086,"Philips RAD Imaging DD 097",VR::CS,VM::VM1,"?",false }, + {0x200b,0x0088,"Philips RAD Imaging DD 097",VR::CS,VM::VM1,"?",false }, + {0x200b,0x0089,"Philips RAD Imaging DD 097",VR::LO,VM::VM1,"?",false }, + {0x200b,0x0090,"Philips RAD Imaging DD 097",VR::DS,VM::VM1,"?",false }, + {0x200b,0x0096,"Philips RAD Imaging DD 097",VR::SH,VM::VM1,"?",false }, + {0x200b,0x0099,"Philips RAD Imaging DD 097",VR::SH,VM::VM1,"?",false }, + {0x200b,0x009a,"Philips RAD Imaging DD 097",VR::FD,VM::VM1,"?",false }, + {0x200b,0x009b,"Philips RAD Imaging DD 097",VR::FD,VM::VM1,"?",false }, + {0x200b,0x00a0,"Philips RAD Imaging DD 097",VR::LT,VM::VM1,"?",false }, + {0x0031,0x0030,"Philips US Imaging 60",VR::UL,VM::VM1,"Private data",false }, + {0x0031,0x0031,"Philips US Imaging 60",VR::UL,VM::VM1,"Private data",false }, + {0x200d,0x0005,"Philips US Imaging DD 017",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0037,"Philips US Imaging DD 023",VR::DA,VM::VM1,"?",false }, + {0x200d,0x0038,"Philips US Imaging DD 023",VR::TM,VM::VM1,"?",false }, + {0x200d,0x0045,"Philips US Imaging DD 023",VR::IS,VM::VM1,"?",false }, + {0x200d,0x0000,"Philips US Imaging DD 033",VR::OB,VM::VM1,"Philips Confidential v.1",false }, + {0x200d,0x0001,"Philips US Imaging DD 033",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0002,"Philips US Imaging DD 033",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0003,"Philips US Imaging DD 033",VR::LO,VM::VM6,"?",false }, + {0x200d,0x0004,"Philips US Imaging DD 033",VR::LO,VM::VM6,"?",false }, + {0x200d,0x0005,"Philips US Imaging DD 033",VR::LO,VM::VM1_n,"?",false }, + {0x200d,0x0006,"Philips US Imaging DD 033",VR::LO,VM::VM6,"?",false }, + {0x200d,0x0007,"Philips US Imaging DD 033",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0008,"Philips US Imaging DD 033",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0009,"Philips US Imaging DD 033",VR::LO,VM::VM1,"?",false }, + {0x200d,0x000a,"Philips US Imaging DD 033",VR::LO,VM::VM1,"?",false }, + {0x200d,0x000b,"Philips US Imaging DD 033",VR::OB,VM::VM1,"Raw Data US",false }, + {0x200d,0x000d,"Philips US Imaging DD 033",VR::LO,VM::VM1,"UDM USD DATATYPE DIN",false }, + {0x200d,0x000f,"Philips US Imaging DD 033",VR::OB,VM::VM1,"XML: UAA / CaptureContext",false }, + {0x200d,0x0010,"Philips US Imaging DD 033",VR::IS,VM::VM1,"Number of Frames",false }, + {0x200d,0x0011,"Philips US Imaging DD 033",VR::IS,VM::VM1,"Max Alloc Buffer (Zlib)",false }, + {0x200d,0x0014,"Philips US Imaging DD 033",VR::IS,VM::VM1,"?",false }, + {0x200d,0x0021,"Philips US Imaging DD 033",VR::IS,VM::VM1,"?Zero?",false }, + {0x200d,0x0001,"Philips US Imaging DD 034",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0002,"Philips US Imaging DD 034",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0003,"Philips US Imaging DD 034",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0004,"Philips US Imaging DD 034",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0005,"Philips US Imaging DD 034",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0006,"Philips US Imaging DD 034",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0007,"Philips US Imaging DD 034",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0008,"Philips US Imaging DD 034",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0009,"Philips US Imaging DD 034",VR::LO,VM::VM1,"?",false }, + {0x200d,0x000a,"Philips US Imaging DD 034",VR::LO,VM::VM1,"?",false }, + {0x200d,0x000b,"Philips US Imaging DD 034",VR::LO,VM::VM1,"?",false }, + {0x200d,0x000c,"Philips US Imaging DD 034",VR::LO,VM::VM1,"?",false }, + {0x200d,0x000d,"Philips US Imaging DD 034",VR::LO,VM::VM1,"?",false }, + {0x200d,0x000e,"Philips US Imaging DD 034",VR::LO,VM::VM1,"?",false }, + {0x200d,0x000f,"Philips US Imaging DD 034",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0010,"Philips US Imaging DD 034",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0021,"Philips US Imaging DD 034",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0022,"Philips US Imaging DD 034",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0023,"Philips US Imaging DD 034",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0024,"Philips US Imaging DD 034",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0001,"Philips US Imaging DD 035",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0002,"Philips US Imaging DD 035",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0003,"Philips US Imaging DD 035",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0004,"Philips US Imaging DD 035",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0005,"Philips US Imaging DD 035",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0007,"Philips US Imaging DD 035",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0008,"Philips US Imaging DD 035",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0009,"Philips US Imaging DD 035",VR::LO,VM::VM1,"?",false }, + {0x200d,0x000a,"Philips US Imaging DD 035",VR::LO,VM::VM1,"?",false }, + {0x200d,0x000b,"Philips US Imaging DD 035",VR::LO,VM::VM1,"?",false }, + {0x200d,0x000c,"Philips US Imaging DD 035",VR::LO,VM::VM1,"?",false }, + {0x200d,0x000d,"Philips US Imaging DD 035",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0001,"Philips US Imaging DD 036",VR::LO,VM::VM3,"Cols/Rows/Frames",false }, + {0x200d,0x0002,"Philips US Imaging DD 036",VR::LO,VM::VM3,"Cols/Rows/Frames",false }, + {0x200d,0x0003,"Philips US Imaging DD 036",VR::LO,VM::VM3,"Voxel Spacing",false }, + {0x200d,0x0004,"Philips US Imaging DD 036",VR::LO,VM::VM3,"?",false }, + {0x200d,0x0001,"Philips US Imaging DD 038",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0001,"Philips US Imaging DD 039",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0004,"Philips US Imaging DD 039",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0005,"Philips US Imaging DD 039",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0006,"Philips US Imaging DD 039",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0007,"Philips US Imaging DD 039",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0008,"Philips US Imaging DD 039",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0009,"Philips US Imaging DD 039",VR::LO,VM::VM1,"?",false }, + {0x200d,0x000a,"Philips US Imaging DD 039",VR::LO,VM::VM1,"?",false }, + {0x200d,0x000b,"Philips US Imaging DD 039",VR::LO,VM::VM1,"?",false }, + {0x200d,0x000c,"Philips US Imaging DD 039",VR::LO,VM::VM1,"?",false }, + {0x200d,0x000d,"Philips US Imaging DD 039",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0001,"Philips US Imaging DD 040",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0002,"Philips US Imaging DD 040",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0003,"Philips US Imaging DD 040",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0004,"Philips US Imaging DD 040",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0005,"Philips US Imaging DD 040",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0006,"Philips US Imaging DD 040",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0007,"Philips US Imaging DD 040",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0020,"Philips US Imaging DD 040",VR::LO,VM::VM1,"?",false }, + {0x200d,0x001e,"Philips US Imaging DD 041",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0015,"Philips US Imaging DD 042",VR::IS,VM::VM1,"?",false }, + {0x200d,0x0016,"Philips US Imaging DD 042",VR::FD,VM::VM1,"?",false }, + {0x200d,0x0050,"Philips US Imaging DD 042",VR::LO,VM::VM3,"?",false }, + {0x200d,0x0051,"Philips US Imaging DD 042",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0052,"Philips US Imaging DD 042",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0053,"Philips US Imaging DD 042",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0054,"Philips US Imaging DD 042",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0055,"Philips US Imaging DD 042",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0056,"Philips US Imaging DD 042",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0057,"Philips US Imaging DD 042",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0058,"Philips US Imaging DD 042",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0059,"Philips US Imaging DD 042",VR::LO,VM::VM1,"?",false }, + {0x200d,0x005a,"Philips US Imaging DD 042",VR::LO,VM::VM1,"?",false }, + {0x200d,0x005b,"Philips US Imaging DD 042",VR::LO,VM::VM1,"?",false }, + {0x200d,0x005c,"Philips US Imaging DD 042",VR::LO,VM::VM1,"?",false }, + {0x200d,0x005d,"Philips US Imaging DD 042",VR::LO,VM::VM1,"?",false }, + {0x200d,0x005e,"Philips US Imaging DD 042",VR::LO,VM::VM1,"?",false }, + {0x200d,0x005f,"Philips US Imaging DD 042",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0060,"Philips US Imaging DD 042",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0070,"Philips US Imaging DD 042",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0071,"Philips US Imaging DD 042",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0072,"Philips US Imaging DD 042",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0073,"Philips US Imaging DD 042",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0074,"Philips US Imaging DD 042",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0075,"Philips US Imaging DD 042",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0076,"Philips US Imaging DD 042",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0077,"Philips US Imaging DD 042",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0005,"Philips US Imaging DD 043",VR::SH,VM::VM1,"?",false }, + {0x200d,0x00f1,"Philips US Imaging DD 045",VR::SQ,VM::VM1,"Private DataType Image Sequence",false }, + {0x200d,0x00f3,"Philips US Imaging DD 045",VR::OB,VM::VM1,"image buffer (Zlib/none compressed)",false }, + {0x200d,0x00f8,"Philips US Imaging DD 045",VR::SQ,VM::VM1,"Private DataType Image Groups Sequence",false }, + {0x200d,0x00fa,"Philips US Imaging DD 045",VR::CS,VM::VM1,"ZLib/None",false }, + {0x200d,0x00fb,"Philips US Imaging DD 045",VR::OB,VM::VM1,"Frames header array",false }, + {0x200d,0x0000,"Philips US Imaging DD 066",VR::OB,VM::VM1,"Philips Confidential v.1",false }, + {0x200d,0x0000,"Philips US Imaging DD 109",VR::US,VM::VM1,"?",false }, + {0x200d,0x0001,"Philips US Imaging DD 109",VR::SQ,VM::VM1,"?",false }, + {0x200d,0x0002,"Philips US Imaging DD 109",VR::ST,VM::VM1,"?",false }, + {0x200d,0x0003,"Philips US Imaging DD 109",VR::CS,VM::VM1,"?",false }, + {0x200d,0x0004,"Philips US Imaging DD 109",VR::SL,VM::VM4,"?",false }, + {0x200d,0x0005,"Philips US Imaging DD 109",VR::UL,VM::VM3,"?",false }, + {0x200d,0x0006,"Philips US Imaging DD 109",VR::UL,VM::VM3,"?",false }, + {0x200d,0x0007,"Philips US Imaging DD 109",VR::CS,VM::VM1,"?",false }, + {0x200d,0x0008,"Philips US Imaging DD 109",VR::CS,VM::VM1,"?",false }, + {0x200d,0x0009,"Philips US Imaging DD 109",VR::OB,VM::VM1,"?",false }, + {0x200d,0x000a,"Philips US Imaging DD 109",VR::UL,VM::VM1,"?",false }, + {0x200d,0x000b,"Philips US Imaging DD 109",VR::OB,VM::VM1,"?",false }, + {0x200d,0x000c,"Philips US Imaging DD 109",VR::UL,VM::VM1,"?",false }, + {0x200d,0x000d,"Philips US Imaging DD 109",VR::SQ,VM::VM1,"?",false }, + {0x200d,0x000e,"Philips US Imaging DD 109",VR::CS,VM::VM1,"?",false }, + {0x200d,0x000f,"Philips US Imaging DD 109",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0010,"Philips US Imaging DD 109",VR::SL,VM::VM1,"?",false }, + {0x200d,0x0011,"Philips US Imaging DD 109",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0012,"Philips US Imaging DD 109",VR::SL,VM::VM1,"?",false }, + {0x200d,0x0001,"Philips US Imaging DD 113",VR::LO,VM::VM1,"?",false }, + {0x200d,0x0002,"Philips US Imaging DD 113",VR::UL,VM::VM1,"?",false }, + {0x200d,0x0003,"Philips US Imaging DD 113",VR::UL,VM::VM1,"?",false }, + {0x200d,0x0004,"Philips US Imaging DD 113",VR::UL,VM::VM1,"?",false }, + {0x200d,0x0005,"Philips US Imaging DD 113",VR::UL,VM::VM1,"?",false }, + {0x200d,0x0006,"Philips US Imaging DD 113",VR::UL,VM::VM1,"?",false }, + {0x200d,0x0007,"Philips US Imaging DD 113",VR::CS,VM::VM1,"?",false }, + {0x200d,0x0009,"Philips US Imaging DD 113",VR::UL,VM::VM1,"?",false }, + {0x200d,0x000b,"Philips US Imaging DD 113",VR::CS,VM::VM1,"?",false }, + {0x200d,0x000c,"Philips US Imaging DD 113",VR::UL,VM::VM1,"?",false }, + {0x200d,0x000d,"Philips US Imaging DD 113",VR::UL,VM::VM1,"?",false }, + {0x200d,0x000e,"Philips US Imaging DD 113",VR::UL,VM::VM1,"?",false }, + {0x200d,0x000f,"Philips US Imaging DD 113",VR::DS,VM::VM1,"?",false }, + {0x200d,0x0010,"Philips US Imaging DD 113",VR::DS,VM::VM1,"?",false }, + {0x200d,0x0011,"Philips US Imaging DD 113",VR::SL,VM::VM1,"?",false }, + {0x200d,0x0012,"Philips US Imaging DD 113",VR::UL,VM::VM1,"?",false }, + {0x200d,0x0013,"Philips US Imaging DD 113",VR::FL,VM::VM1_n,"?",false }, + {0x200d,0x0014,"Philips US Imaging DD 113",VR::US,VM::VM1,"?",false }, + {0x200d,0x0015,"Philips US Imaging DD 113",VR::UL,VM::VM1,"?",false }, + {0x200d,0x0017,"Philips US Imaging DD 113",VR::FD,VM::VM1,"?",false }, + {0x200d,0x0018,"Philips US Imaging DD 113",VR::FD,VM::VM1,"?",false }, + {0x200d,0x0019,"Philips US Imaging DD 113",VR::FD,VM::VM1,"?",false }, + {0x200d,0x001a,"Philips US Imaging DD 113",VR::FD,VM::VM1,"?",false }, + {0x200d,0x001b,"Philips US Imaging DD 113",VR::FD,VM::VM1,"?",false }, + {0x200d,0x001c,"Philips US Imaging DD 113",VR::FD,VM::VM1,"?",false }, + {0x200d,0x001d,"Philips US Imaging DD 113",VR::UL,VM::VM1,"?",false }, + {0x200d,0x001e,"Philips US Imaging DD 113",VR::UL,VM::VM1,"?",false }, + {0x200d,0x001f,"Philips US Imaging DD 113",VR::FD,VM::VM1,"?",false }, + {0x200d,0x0020,"Philips US Imaging DD 113",VR::FD,VM::VM1,"?",false }, + {0x200d,0x0021,"Philips US Imaging DD 113",VR::FD,VM::VM1,"?",false }, + {0x200d,0x0002,"Philips US Private 3D",VR::IS,VM::VM1,"Threedpr Echo Vision Setting",false }, + {0x200d,0x0003,"Philips US Private 3D",VR::IS,VM::VM1,"Threedpr Color Vision Setting",false }, + {0x200d,0x0004,"Philips US Private 3D",VR::IS,VM::VM1,"Threedpr Transparency",false }, + {0x200d,0x0006,"Philips US Private 3D",VR::FD,VM::VM1,"Threedpr Vision Vol Brightness",false }, + {0x200d,0x0008,"Philips US Private 3D",VR::IS,VM::VM1,"Threedpr Low Threshold",false }, + {0x200d,0x0009,"Philips US Private 3D",VR::IS,VM::VM1,"Threedpr Image Layout",false }, + {0x200d,0x000a,"Philips US Private 3D",VR::IS,VM::VM1,"Threedpr Xres Filtering Enabled",false }, + {0x200d,0x000b,"Philips US Private 3D",VR::IS,VM::VM1,"Threedpr Echo Twod Chroma Map Enabled",false }, + {0x200d,0x000c,"Philips US Private 3D",VR::IS,VM::VM1,"Threedpr Box Outlined Enabled",false }, + {0x200d,0x000d,"Philips US Private 3D",VR::IS,VM::VM1,"Threedpr Smoothing Enabled",false }, + {0x200d,0x000e,"Philips US Private 3D",VR::IS,VM::VM1,"Threedpr Reference Graphic Enabled",false }, + {0x200d,0x000f,"Philips US Private 3D",VR::IS,VM::VM1,"Threedpr Map Inverted",false }, + {0x200d,0x0010,"Philips US Private 3D",VR::IS,VM::VM1,"Threedpr Color Stream Display Enabled",false }, + {0x200d,0x0011,"Philips US Private 3D",VR::IS,VM::VM1,"Threedpr Echo Stream Display Enabled",false }, + {0x200d,0x0012,"Philips US Private 3D",VR::LO,VM::VM1,"Vdb Param Color 3d Estimate Scale(2)",false }, + {0x200d,0x0013,"Philips US Private 3D",VR::LO,VM::VM1,"Vdb Param Color 3d Estimate Apex Position (1)",false }, + {0x200d,0x0014,"Philips US Private 3D",VR::LO,VM::VM1,"Vdb Param Color 3d Estimate Color Offset",false }, + {0x200d,0x0015,"Philips US Private 3D",VR::LO,VM::VM1,"Vdb Param Echo 3d Estimate Dimension(2)",false }, + {0x200d,0x0016,"Philips US Private 3D",VR::SQ,VM::VM1,"Private Native Threed Data Sequence(1)",false }, + {0x200d,0x0017,"Philips US Private 3D",VR::IS,VM::VM1,"Threedpr Basic Vol Brightness",false }, + {0x200d,0x0018,"Philips US Private 3D",VR::LO,VM::VM1,"Vdb Param Echo 3d Estimate Apex Position (2)",false }, + {0x200d,0x001a,"Philips US Private 3D",VR::IS,VM::VM1,"Threedpr Echo Smoothing",false }, + {0x200d,0x001b,"Philips US Private 3D",VR::IS,VM::VM1,"Threedpr Color Smoothing",false }, + {0x200d,0x001e,"Philips US Private 3D",VR::IS,VM::VM1,"Threedpr Num Completed Trim Planes",false }, + {0x200d,0x001f,"Philips US Private 3D",VR::IS,VM::VM1,"Threedpr Depth",false }, + {0x200d,0x0020,"Philips US Private 3D",VR::SQ,VM::VM1,"Private Native Data Stream Array",false }, + {0x200d,0x0021,"Philips US Private 3D",VR::IS,VM::VM1,"Threedpr Wall Filter",false }, + {0x200d,0x0023,"Philips US Private 3D",VR::FD,VM::VM1,"Threedpr Baseline",false }, + {0x200d,0x0024,"Philips US Private 3D",VR::FD,VM::VM1,"Threedpr Gain",false }, + {0x200d,0x0025,"Philips US Private 3D",VR::FD,VM::VM1,"Threedpr Compress",false }, + {0x200d,0x0026,"Philips US Private 3D",VR::FD,VM::VM1,"Threedpr Light Brightness",false }, + {0x200d,0x0027,"Philips US Private 3D",VR::FD,VM::VM1,"Threedpr Elevation Scale Factor",false }, + {0x200d,0x0028,"Philips US Private 3D",VR::FD,VM::VM1,"Threedpr Zoom Factor",false }, + {0x200d,0x0029,"Philips US Private 3D",VR::FD,VM::VM1,"Threedpr Color Write Priority",false }, + {0x200d,0x002a,"Philips US Private 3D",VR::FD,VM::VM1,"Threedpr Rotation Angle X",false }, + {0x200d,0x002b,"Philips US Private 3D",VR::FD,VM::VM1,"Threedpr Rotation Angle Y",false }, + {0x200d,0x002c,"Philips US Private 3D",VR::FD,VM::VM1,"Threedpr Data Voi Center",false }, + {0x200d,0x002d,"Philips US Private 3D",VR::FD,VM::VM1,"Threedpr View Translation",false }, + {0x200d,0x002e,"Philips US Private 3D",VR::FD,VM::VM1,"Threedpr Data Voi Min Point",false }, + {0x200d,0x002f,"Philips US Private 3D",VR::FD,VM::VM1,"Threedpr Data Voi Max Point",false }, + {0x200d,0x0030,"Philips US Private 3D",VR::FD,VM::VM1,"Threedpr Box Crop Min Point",false }, + {0x200d,0x0031,"Philips US Private 3D",VR::FD,VM::VM1,"Threedpr Box Crop Max Point",false }, + {0x200d,0x0032,"Philips US Private 3D",VR::FD,VM::VM1,"Threedpr Mpr Rotation Matrix",false }, + {0x200d,0x0033,"Philips US Private 3D",VR::FD,VM::VM1,"Threedpr Vol Rotation Matrix",false }, + {0x200d,0x0034,"Philips US Private 3D",VR::FD,VM::VM1,"Threedpr Trim Plane Equation",false }, + {0x200d,0x0035,"Philips US Private 3D",VR::IS,VM::VM1,"Threedpr Subpage Data Version",false }, + {0x200d,0x0036,"Philips US Private 3D",VR::IS,VM::VM1,"Threedpr Is Arbitrary Crop",false }, + {0x200d,0x0037,"Philips US Private 3D",VR::IS,VM::VM1,"Threedpr Arbitrary Crop Dist From Center",false }, + {0x200d,0x0038,"Philips US Private 3D",VR::FD,VM::VM1,"Threedpr Arbitrary Crop Rotation Matrix",false }, + {0x200d,0x0039,"Philips US Private 3D",VR::FD,VM::VM1,"Threedpr Color Gain",false }, + {0x200d,0x0040,"Philips US Private 3D",VR::IS,VM::VM1,"Threedpr Color Wall Filter Index",false }, + {0x200d,0x0041,"Philips US Private 3D",VR::IS,VM::VM1,"Threedpr Cursor Enabled",false }, + {0x200d,0x0042,"Philips US Private 3D",VR::IS,VM::VM1,"Threedpr Bondbox Graphic Enabled",false }, + {0x2003,0x0000,"Philips X-ray Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2003,0x0001,"Philips X-ray Imaging DD 001",VR::LO,VM::VM1,"?",false }, + {0x2003,0x0002,"Philips X-ray Imaging DD 001",VR::FD,VM::VM3,"?",false }, + {0x2003,0x0003,"Philips X-ray Imaging DD 001",VR::LO,VM::VM1,"?",false }, + {0x2003,0x0004,"Philips X-ray Imaging DD 001",VR::SQ,VM::VM1,"Private enhanced Table Sequence",false }, + {0x2003,0x0006,"Philips X-ray Imaging DD 001",VR::SL,VM::VM1,"?",false }, + {0x2003,0x0009,"Philips X-ray Imaging DD 001",VR::SL,VM::VM1,"?",false }, + {0x2003,0x0010,"Philips X-ray Imaging DD 001",VR::LO,VM::VM1,"?",false }, + {0x2003,0x0011,"Philips X-ray Imaging DD 001",VR::SL,VM::VM1,"?",false }, + {0x2003,0x0012,"Philips X-ray Imaging DD 001",VR::SL,VM::VM1,"?",false }, + {0x2003,0x0013,"Philips X-ray Imaging DD 001",VR::SL,VM::VM1,"?",false }, + {0x2003,0x0014,"Philips X-ray Imaging DD 001",VR::FD,VM::VM1,"?",false }, + {0x2003,0x0015,"Philips X-ray Imaging DD 001",VR::FD,VM::VM1,"?",false }, + {0x2003,0x0016,"Philips X-ray Imaging DD 001",VR::SL,VM::VM1,"?",false }, + {0x2003,0x0017,"Philips X-ray Imaging DD 001",VR::SL,VM::VM1,"?",false }, + {0x2003,0x0018,"Philips X-ray Imaging DD 001",VR::SL,VM::VM1,"?",false }, + {0x2003,0x0019,"Philips X-ray Imaging DD 001",VR::SL,VM::VM1,"?",false }, + {0x2003,0x0022,"Philips X-ray Imaging DD 001",VR::SL,VM::VM1,"?",false }, + {0x2003,0x0024,"Philips X-ray Imaging DD 001",VR::FD,VM::VM4,"?",false }, + {0x2003,0x0025,"Philips X-ray Imaging DD 001",VR::SL,VM::VM1,"?",false }, + {0x2003,0x0026,"Philips X-ray Imaging DD 001",VR::SL,VM::VM1,"?",false }, + {0x2003,0x0027,"Philips X-ray Imaging DD 001",VR::SH,VM::VM1,"?",false }, + {0x2003,0x0028,"Philips X-ray Imaging DD 001",VR::SH,VM::VM1,"?",false }, + {0x2003,0x0029,"Philips X-ray Imaging DD 001",VR::FD,VM::VM1,"?",false }, + {0x2003,0x002a,"Philips X-ray Imaging DD 001",VR::LO,VM::VM1,"?",false }, + {0x2003,0x002b,"Philips X-ray Imaging DD 001",VR::FD,VM::VM1,"?",false }, + {0x2003,0x002c,"Philips X-ray Imaging DD 001",VR::SH,VM::VM1,"?",false }, + {0x2003,0x002d,"Philips X-ray Imaging DD 001",VR::SL,VM::VM1_n,"?",false }, + {0x2003,0x002e,"Philips X-ray Imaging DD 001",VR::SQ,VM::VM1,"?",false }, + {0x2003,0x002f,"Philips X-ray Imaging DD 001",VR::CS,VM::VM1,"IsResolvePatientMixApplied",false }, + {0x2003,0x0030,"Philips X-ray Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2003,0x0031,"Philips X-ray Imaging DD 001",VR::CS,VM::VM1,"?",false }, + {0x2003,0x0032,"Philips X-ray Imaging DD 001",VR::UI,VM::VM1,"?",false }, + {0x7101,0x0000,"Picker MR Private Group",VR::OB,VM::VM1,"?",false }, + {0x7101,0x0001,"Picker MR Private Group",VR::SL,VM::VM1,"?",false }, + {0x7101,0x0002,"Picker MR Private Group",VR::OB,VM::VM1,"?",false }, + {0x7101,0x0003,"Picker MR Private Group",VR::SL,VM::VM1,"?",false }, + {0x7101,0x0004,"Picker MR Private Group",VR::SH,VM::VM1,"?",false }, + {0x7101,0x0005,"Picker MR Private Group",VR::SH,VM::VM2,"?",false }, + {0x7101,0x0006,"Picker MR Private Group",VR::SH,VM::VM4,"?",false }, + {0x7101,0x0010,"Picker MR Private Group",VR::DS,VM::VM1,"?",false }, + {0x7001,0x0001,"Picker NM Private Group",VR::UI,VM::VM1,"Private",false }, + {0x7001,0x0002,"Picker NM Private Group",VR::OB,VM::VM1,"Private",false }, + {0x7001,0x0003,"Picker NM Private Group",VR::OB,VM::VM1,"Private",false }, + {0x7001,0x0004,"Picker NM Private Group",VR::OB,VM::VM1,"Private",false }, + {0x7001,0x0005,"Picker NM Private Group",VR::OB,VM::VM1,"Private",false }, + {0x7001,0x0006,"Picker NM Private Group",VR::OB,VM::VM1,"Private",false }, + {0x7001,0x0007,"Picker NM Private Group",VR::OB,VM::VM1,"Private",false }, + {0x7001,0x0008,"Picker NM Private Group",VR::OB,VM::VM1,"Private",false }, + {0x7001,0x0009,"Picker NM Private Group",VR::OB,VM::VM1,"Private",false }, + {0x7001,0x0010,"Picker NM Private Group",VR::SQ,VM::VM1,"Private",false }, + {0x7001,0x0011,"Picker NM Private Group",VR::LO,VM::VM1,"Private",false }, + {0x7001,0x0012,"Picker NM Private Group",VR::OB,VM::VM1,"Private",false }, + {0x7001,0x0013,"Picker NM Private Group",VR::US,VM::VM1,"Private",false }, + {0x7001,0x0014,"Picker NM Private Group",VR::OB,VM::VM1,"Private",false }, + {0x7001,0x0015,"Picker NM Private Group",VR::OB,VM::VM1,"Private",false }, + {0x7001,0x0016,"Picker NM Private Group",VR::OB,VM::VM1,"Private",false }, + {0x7001,0x0017,"Picker NM Private Group",VR::LO,VM::VM1,"Contains a text string that includes some of the same information that appears on the Odyssey Clinical Index (image directory) for this Image.",false }, + {0x7043,0x0000,"Picker NM Private Group",VR::SH,VM::VM1,"Private.",false }, + {0x0009,0x0000,"QCA",VR::CS,VM::VM1,"Analysis Type",false }, + {0x0009,0x0004,"QCA",VR::LO,VM::VM1,"Segment Name",false }, + {0x0009,0x0012,"QCA",VR::DS,VM::VM1,"Pre Catheter size",false }, + {0x0009,0x0013,"QCA",VR::DS,VM::VM1,"Pre Reference Diameter",false }, + {0x0009,0x0014,"QCA",VR::DS,VM::VM1,"Pre Minimum Lumen Diameter",false }, + {0x0009,0x0015,"QCA",VR::DS,VM::VM1,"Pre Average Diameter",false }, + {0x0009,0x0016,"QCA",VR::DS,VM::VM1,"Pre Stenosis Length",false }, + {0x0009,0x0017,"QCA",VR::DS,VM::VM1,"Pre Stenosis %",false }, + {0x0009,0x0018,"QCA",VR::DS,VM::VM1,"Pre Geometric Area Reduction %",false }, + {0x0009,0x0022,"QCA",VR::DS,VM::VM1,"Post Catheter Size",false }, + {0x0009,0x0023,"QCA",VR::DS,VM::VM1,"Post Reference Diameter",false }, + {0x0009,0x0024,"QCA",VR::DS,VM::VM1,"Post Minimum Lumen Diameter",false }, + {0x0009,0x0025,"QCA",VR::DS,VM::VM1,"Post Average Diameter",false }, + {0x0009,0x0026,"QCA",VR::DS,VM::VM1,"Post Stenosis Length",false }, + {0x0009,0x0027,"QCA",VR::DS,VM::VM1,"Post Stenosis %",false }, + {0x0009,0x0028,"QCA",VR::DS,VM::VM1,"Post Geometric Area Reduction %",false }, + {0x0009,0x0000,"QCA_RESULTS",VR::CS,VM::VM1,"Analysis Views",false }, + {0x0009,0x0010,"QCA_RESULTS",VR::LO,VM::VM1,"Segment",false }, + {0x0009,0x0011,"QCA_RESULTS",VR::LO,VM::VM1,"Pre Catheter Name",false }, + {0x0009,0x0012,"QCA_RESULTS",VR::DS,VM::VM1,"Pre Catheter Size",false }, + {0x0009,0x0013,"QCA_RESULTS",VR::DS,VM::VM1,"Pre Reference Diameter",false }, + {0x0009,0x0014,"QCA_RESULTS",VR::DS,VM::VM1,"Pre Minimum Lumen Diameter",false }, + {0x0009,0x0015,"QCA_RESULTS",VR::DS,VM::VM1,"Pre Average Diameter",false }, + {0x0009,0x0016,"QCA_RESULTS",VR::DS,VM::VM1,"Pre Stenosis Length",false }, + {0x0009,0x0017,"QCA_RESULTS",VR::IS,VM::VM1,"Pre Stenosis %",false }, + {0x0009,0x0018,"QCA_RESULTS",VR::IS,VM::VM1,"Pre Geometric Area Reduction %",false }, + {0x0009,0x0021,"QCA_RESULTS",VR::LO,VM::VM1,"Post Catheter Name",false }, + {0x0009,0x0022,"QCA_RESULTS",VR::DS,VM::VM1,"Post Catheter Size",false }, + {0x0009,0x0023,"QCA_RESULTS",VR::DS,VM::VM1,"Post Reference Diameter",false }, + {0x0009,0x0024,"QCA_RESULTS",VR::DS,VM::VM1,"Post Minimum Lumen Diameter",false }, + {0x0009,0x0025,"QCA_RESULTS",VR::DS,VM::VM1,"Post Average Diameter",false }, + {0x0009,0x0026,"QCA_RESULTS",VR::DS,VM::VM1,"Post Stenosis Length",false }, + {0x0009,0x0027,"QCA_RESULTS",VR::IS,VM::VM1,"Post Stenosis %",false }, + {0x0009,0x0028,"QCA_RESULTS",VR::IS,VM::VM1,"Post Geometric Area Reduction %",false }, + {0x0009,0x0040,"QCA_RESULTS",VR::IS,VM::VM1,"Calibration Frame",false }, + {0x0009,0x0041,"QCA_RESULTS",VR::IS,VM::VM1,"End Diastolic Frame",false }, + {0x0009,0x0042,"QCA_RESULTS",VR::IS,VM::VM1,"End Systolic Frame",false }, + {0x0009,0x0043,"QCA_RESULTS",VR::DS,VM::VM1,"End Diastolic Volume",false }, + {0x0009,0x0044,"QCA_RESULTS",VR::DS,VM::VM1,"End Systolic Volume",false }, + {0x0009,0x0045,"QCA_RESULTS",VR::DS,VM::VM1,"Stroke Volume",false }, + {0x0009,0x0047,"QCA_RESULTS",VR::DS,VM::VM1,"Ejection Fraction",false }, + {0x0009,0x0048,"QCA_RESULTS",VR::DS,VM::VM1,"Body Surface Area",false }, + {0x0009,0x0049,"QCA_RESULTS",VR::SH,VM::VM1,"Artery Territory Region",false }, + {0x0009,0x0050,"QCA_RESULTS",VR::IS,VM::VM1,"Number of Diseased Vessels",false }, + {0x0009,0x0051,"QCA_RESULTS",VR::DS,VM::VM1,"Hypokinesis in Region",false }, + {0x0009,0x0052,"QCA_RESULTS",VR::DS,VM::VM1,"Hyperkinesis in Opposite Region",false }, + {0x0009,0x0053,"QCA_RESULTS",VR::IS,VM::VM1,"Percent Total LV Hypokinesis",false }, + {0x0009,0x0055,"QCA_RESULTS",VR::DS,VM::VM1,"Calibration Factor",false }, + {0x0009,0x0001,"QUASAR_INTERNAL_USE",VR::UL,VM::VM1_n,"Rate Vector",false }, + {0x0009,0x0002,"QUASAR_INTERNAL_USE",VR::UL,VM::VM1_n,"Count Vector",false }, + {0x0009,0x0003,"QUASAR_INTERNAL_USE",VR::UL,VM::VM1_n,"Time Vector",false }, + {0x0009,0x0007,"QUASAR_INTERNAL_USE",VR::US,VM::VM1_n,"Angle Vector",false }, + {0x0009,0x0008,"QUASAR_INTERNAL_USE",VR::US,VM::VM1,"Camera Shape",false }, + {0x0009,0x0010,"QUASAR_INTERNAL_USE",VR::US,VM::VM1,"WholeBody Spots",false }, + {0x0009,0x0011,"QUASAR_INTERNAL_USE",VR::US,VM::VM1,"Worklist Flag",false }, + {0x0009,0x0012,"QUASAR_INTERNAL_USE",VR::LO,VM::VM1,"?",false }, + {0x0009,0x0013,"QUASAR_INTERNAL_USE",VR::ST,VM::VM1,"Sequence Type",false }, + {0x0009,0x0014,"QUASAR_INTERNAL_USE",VR::ST,VM::VM1,"Sequence Name",false }, + {0x0009,0x0015,"QUASAR_INTERNAL_USE",VR::UL,VM::VM1,"Avr RR Time Vector",false }, + {0x0009,0x0016,"QUASAR_INTERNAL_USE",VR::UL,VM::VM1,"Low Limit Vector",false }, + {0x0009,0x0017,"QUASAR_INTERNAL_USE",VR::UL,VM::VM1,"High Limit Vector",false }, + {0x0009,0x0018,"QUASAR_INTERNAL_USE",VR::UL,VM::VM1,"Begin Index Vector",false }, + {0x0009,0x0019,"QUASAR_INTERNAL_USE",VR::UL,VM::VM1,"End Index Vector",false }, + {0x0009,0x001a,"QUASAR_INTERNAL_USE",VR::UL,VM::VM1,"Raw Time Vector",false }, + {0x0009,0x001b,"QUASAR_INTERNAL_USE",VR::LO,VM::VM1,"Image Type String",false }, + {0x0009,0x001d,"QUASAR_INTERNAL_USE",VR::US,VM::VM1,"?",false }, + {0x0009,0x001e,"QUASAR_INTERNAL_USE",VR::ST,VM::VM1,"?",false }, + {0x0009,0x0022,"QUASAR_INTERNAL_USE",VR::FL,VM::VM1,"?",false }, + {0x0009,0x0023,"QUASAR_INTERNAL_USE",VR::US,VM::VM1,"?",false }, + {0x0009,0x0039,"QUASAR_INTERNAL_USE",VR::UI,VM::VM1,"?",false }, + {0x0009,0x0040,"QUASAR_INTERNAL_USE",VR::DA,VM::VM1,"?",false }, + {0x0009,0x0041,"QUASAR_INTERNAL_USE",VR::TM,VM::VM1,"?",false }, + {0x0009,0x0042,"QUASAR_INTERNAL_USE",VR::LO,VM::VM1,"?",false }, + {0x0009,0x0044,"QUASAR_INTERNAL_USE",VR::SH,VM::VM1,"?",false }, + {0x0037,0x0010,"QUASAR_INTERNAL_USE",VR::SQ,VM::VM1,"?",false }, + {0x0037,0x001b,"QUASAR_INTERNAL_USE",VR::LO,VM::VM1,"?",false }, + {0x0037,0x0030,"QUASAR_INTERNAL_USE",VR::LO,VM::VM1,"?",false }, + {0x0037,0x0040,"QUASAR_INTERNAL_USE",VR::LO,VM::VM1,"?",false }, + {0x0037,0x0050,"QUASAR_INTERNAL_USE",VR::LO,VM::VM1,"?",false }, + {0x0037,0x0060,"QUASAR_INTERNAL_USE",VR::LO,VM::VM1,"?",false }, + {0x0037,0x0070,"QUASAR_INTERNAL_USE",VR::LO,VM::VM1,"?",false }, + {0x0009,0x0040,"QVA",VR::IS,VM::VM1,"Calibration Frame",false }, + {0x0009,0x0041,"QVA",VR::IS,VM::VM1,"End Diastolic Frame",false }, + {0x0009,0x0042,"QVA",VR::IS,VM::VM1,"End Systolic Frame",false }, + {0x0009,0x0043,"QVA",VR::DS,VM::VM1,"End Diastolic Volume",false }, + {0x0009,0x0044,"QVA",VR::DS,VM::VM1,"End Systolic Volume",false }, + {0x0009,0x0045,"QVA",VR::DS,VM::VM1,"Stroke Volume",false }, + {0x0009,0x0046,"QVA",VR::DS,VM::VM1,"Cardiac Output",false }, + {0x0009,0x0047,"QVA",VR::DS,VM::VM1,"Ejection Fraction",false }, + {0x0009,0x0048,"QVA",VR::DS,VM::VM1,"Body Surface Area",false }, + {0x0009,0x0049,"QVA",VR::SH,VM::VM1,"Artery Territory Region",false }, + {0x0009,0x0050,"QVA",VR::IS,VM::VM1,"Number of Diseased Vessels",false }, + {0x0009,0x0051,"QVA",VR::DS,VM::VM1,"Hypokinesis in Region",false }, + {0x0009,0x0052,"QVA",VR::DS,VM::VM1,"Hyperkinesis in Region",false }, + {0x0009,0x0053,"QVA",VR::IS,VM::VM1,"percent of chords with hyperkinesis <- 2 SD",false }, + {0x0009,0x0054,"QVA",VR::IS,VM::VM1,"percent of chords with alkinesis/dyskinesis",false }, + {0x0009,0x0055,"QVA",VR::DS,VM::VM1,"Calibration Factor",false }, + {0x0039,0x0095,"REPORT_FROM_APP",VR::LO,VM::VM1,"?",false }, + {0x0029,0x0024,"RadWorksMarconi",VR::US,VM::VM1," + +namespace gdcm +{ + static const char * const SOPClassUIDToIODStrings[][2] = { +{"1.2.840.10008.1.3.10" , "Basic Directory IOD Modules"}, // IOD defined in PS 3.3 +{"1.2.840.10008.5.1.4.1.1.1" , "CR Image IOD Modules"}, +{"1.2.840.10008.5.1.4.1.1.1.1" , "Digital X Ray Image IOD Modules"}, // DX IOD (see B.5.1.1) +{"1.2.840.10008.5.1.4.1.1.1.1.1" , "Digital X Ray Image IOD Modules"}, // DX IOD (see B.5.1.1) +{"1.2.840.10008.5.1.4.1.1.1.2" , "Digital Mammography X Ray Image IOD Modules"}, // (see B.5.1.2) +{"1.2.840.10008.5.1.4.1.1.1.2.1" , "Digital Mammography X Ray Image IOD Modules"}, // (see B.5.1.2) +{"1.2.840.10008.5.1.4.1.1.1.3" , "Digital Intra Oral X Ray Image IOD Modules"}, // (see B.5.1.3) +{"1.2.840.10008.5.1.4.1.1.1.3.1" , "Digital Intra Oral X Ray Image IOD Modules"}, // (see B.5.1.3) +{"1.2.840.10008.5.1.4.1.1.2" , "CT Image IOD Modules"}, +{"1.2.840.10008.5.1.4.1.1.2.1" , "Enhanced CT Image IOD Modules"}, // (see B.5.1.7) +{"1.2.840.10008.5.1.4.1.1.3.1" , "US Multi Frame Image IOD Modules"}, +{"1.2.840.10008.5.1.4.1.1.4" , "MR Image IOD Modules"}, +{"1.2.840.10008.5.1.4.1.1.4.1" , "Enhanced MR Image IOD Modules"}, // (see B.5.1.6) +{"1.2.840.10008.5.1.4.1.1.4.2" , "MR Spectroscopy IOD Modules"}, +{"1.2.840.10008.5.1.4.1.1.4.3" , "Enhanced MR Color Image"}, +{"1.2.840.10008.5.1.4.1.1.6.1" , "US Image IOD Modules"}, +{"1.2.840.10008.5.1.4.1.1.6.2" , "Enhanced US Volume"}, +{"1.2.840.10008.5.1.4.1.1.7" , "SC Image IOD Modules"}, +{"1.2.840.10008.5.1.4.1.1.7.1" , "Multi Frame Single Bit SC Image IOD Modules"}, +{"1.2.840.10008.5.1.4.1.1.7.2" , "Multi Frame Grayscale Byte SC Image IOD Modules"}, +{"1.2.840.10008.5.1.4.1.1.7.3" , "Multi Frame Grayscale Word SC Image IOD Modules"}, +{"1.2.840.10008.5.1.4.1.1.7.4" , "Multi Frame True Color SC Image IOD Modules"}, +{"1.2.840.10008.5.1.4.1.1.9.1.1" , "12 Lead ECG IOD Modules"}, +{"1.2.840.10008.5.1.4.1.1.9.1.2" , "General ECG IOD Modules"}, +{"1.2.840.10008.5.1.4.1.1.9.1.3" , "Ambulatory ECG IOD Modules"}, +{"1.2.840.10008.5.1.4.1.1.9.2.1" , "Hemodynamic IOD Modules"}, +{"1.2.840.10008.5.1.4.1.1.9.3.1" , "Basic Cardiac EP IOD Modules"}, // Cardiac Electrophysiology Waveform +{"1.2.840.10008.5.1.4.1.1.9.4.1" , "Basic Voice Audio IOD Modules"}, +{"1.2.840.10008.5.1.4.1.1.9.4.2" , "General Audio Waveform"}, +{"1.2.840.10008.5.1.4.1.1.9.5.1" , "Arterial Pulse Waveform"}, +{"1.2.840.10008.5.1.4.1.1.9.6.1" , "Respiratory Waveform"}, +{"1.2.840.10008.5.1.4.1.1.11.1" , "Grayscale Softcopy Presentation State IOD Modules"}, +{"1.2.840.10008.5.1.4.1.1.11.2" , "Color Softcopy Presentation State"}, +{"1.2.840.10008.5.1.4.1.1.11.3" , "Pseudo-Color Softcopy Presentation State"}, +{"1.2.840.10008.5.1.4.1.1.11.4" , "Blending Softcopy Presentation State"}, +{"1.2.840.10008.5.1.4.1.1.11.5" , "IOD defined in PS 3.3"}, +{"1.2.840.10008.5.1.4.1.1.12.1" , "X Ray Angiographic Image IOD Modules"}, +{"1.2.840.10008.5.1.4.1.1.12.1.1" , "Enhanced X Ray Angiographic Image IOD Modules"}, +{"1.2.840.10008.5.1.4.1.1.12.2" , "XRF Image IOD Modules"}, +{"1.2.840.10008.5.1.4.1.1.12.2.1" , "Enhanced X Ray RF Image IOD Modules"}, +{"1.2.840.10008.5.1.4.1.1.13.1.1" , "X Ray 3D Angiographic Image IOD Modules"}, +{"1.2.840.10008.5.1.4.1.1.13.1.2" , "X-Ray 3D Craniofacial Image"}, +{"1.2.840.10008.5.1.4.1.1.13.1.3" , "IOD defined in PS 3.3"}, +{"1.2.840.10008.5.1.4.1.1.20" , "NM Image IOD Modules"}, +{"1.2.840.10008.5.1.4.1.1.66" , "Raw Data IOD Modules"}, +{"1.2.840.10008.5.1.4.1.1.66.1" , "Spatial Registration IOD Modules"}, +{"1.2.840.10008.5.1.4.1.1.66.2" , "Spatial Fiducials IOD Modules"}, +{"1.2.840.10008.5.1.4.1.1.66.3" , "Deformable Spatial Registration"}, +{"1.2.840.10008.5.1.4.1.1.66.4" , "Segmentation IOD Modules"}, +{"1.2.840.10008.5.1.4.1.1.66.5" , "Surface Segmentation"}, +{"1.2.840.10008.5.1.4.1.1.67" , "Real World Value Mapping"}, +{"1.2.840.10008.5.1.4.1.1.77.1.1" , "VL Endoscopic Image IOD Modules"}, +{"1.2.840.10008.5.1.4.1.1.77.1.1.1" , "Video Endoscopic Image IOD Modules"}, +{"1.2.840.10008.5.1.4.1.1.77.1.2" , "VL Microscopic Image"}, +{"1.2.840.10008.5.1.4.1.1.77.1.2.1" , "Video Microscopic Image"}, +{"1.2.840.10008.5.1.4.1.1.77.1.3" , "VL Slide-Coordinates Microscopic Image"}, +{"1.2.840.10008.5.1.4.1.1.77.1.4" , "VL Photographic Image IOD Modules"}, +{"1.2.840.10008.5.1.4.1.1.77.1.4.1" , "Video Photographic Image"}, +{"1.2.840.10008.5.1.4.1.1.77.1.5.1" , "Ophthalmic Photography 8 Bit Image"}, +{"1.2.840.10008.5.1.4.1.1.77.1.5.2" , "Ophthalmic Photography 16 Bit Image"}, +{"1.2.840.10008.5.1.4.1.1.77.1.5.3" , "Stereometric Relationship"}, +{"1.2.840.10008.5.1.4.1.1.77.1.5.4" , "Ophthalmic Tomography Image"}, +{"1.2.840.10008.5.1.4.1.1.78.1" , "Lensometry Measurements"}, +{"1.2.840.10008.5.1.4.1.1.78.2" , "Autorefraction Measurements"}, +{"1.2.840.10008.5.1.4.1.1.78.3" , "Keratometry Measurements"}, +{"1.2.840.10008.5.1.4.1.1.78.4" , "Subjective Refraction Measurements"}, +{"1.2.840.10008.5.1.4.1.1.78.5" , "Visual Acuity Measurements"}, +{"1.2.840.10008.5.1.4.1.1.78.6" , "Spectacle Prescription Report"}, +{"1.2.840.10008.5.1.4.1.1.79.1" , "Macular Grid Thickness and Volume Report"}, +{"1.2.840.10008.5.1.4.1.1.88.11" , "Basic Text SR IOD Modules"}, +{"1.2.840.10008.5.1.4.1.1.88.22" , "Enhanced SR IOD Modules"}, +{"1.2.840.10008.5.1.4.1.1.88.33" , "Comprehensive SR IOD Modules"}, +{"1.2.840.10008.5.1.4.1.1.88.40" , "Procedure Log"}, +{"1.2.840.10008.5.1.4.1.1.88.50" , "Mammography CAD SR IOD Modules"}, +{"1.2.840.10008.5.1.4.1.1.88.59" , "Key Object Selection Document IOD Modules"}, +{"1.2.840.10008.5.1.4.1.1.88.65" , "Chest CAD SR IOD"}, +{"1.2.840.10008.5.1.4.1.1.88.67" , "X Ray Radiation Dose SR IOD Modules"}, +{"1.2.840.10008.5.1.4.1.1.88.69" , "Colon CAD SR IOD"}, +{"1.2.840.10008.5.1.4.1.1.104.1" , "Encapsulated PDF IOD Modules"}, +{"1.2.840.10008.5.1.4.1.1.104.2" , "Encapsulated CDA IOD Modules"}, +{"1.2.840.10008.5.1.4.1.1.128" , "PET Image IOD Modules"}, +{"1.2.840.10008.5.1.4.1.1.130" , "IOD defined in PS 3.3"}, +{"1.2.840.10008.5.1.4.1.1.131" , "Basic Structured Display IOD"}, +{"1.2.840.10008.5.1.4.1.1.481.1" , "RT Image IOD Modules"}, +{"1.2.840.10008.5.1.4.1.1.481.2" , "RT Dose IOD Modules"}, +{"1.2.840.10008.5.1.4.1.1.481.3" , "RT Structure Set IOD Modules"}, +{"1.2.840.10008.5.1.4.1.1.481.4" , "RT Beams Treatment Record IOD Modules"}, +{"1.2.840.10008.5.1.4.1.1.481.5" , "RT Plan IOD Modules"}, +{"1.2.840.10008.5.1.4.1.1.481.6" , "RT Brachy Treatment Record IOD Modules"}, +{"1.2.840.10008.5.1.4.1.1.481.7" , "RT Treatment Summary Record IOD Modules"}, +{"1.2.840.10008.5.1.4.1.1.481.8" , "RT Ion Plan IOD Modules"}, +{"1.2.840.10008.5.1.4.1.1.481.9" , "RT Ion Beams Treatment Record IOD Modules"}, +{"1.2.840.10008.5.1.4.38.1" , "Hanging Protocol IOD Modules"}, +{"1.2.840.10008.5.1.4.39.1" , "Color Palette IOD"}, +// Deprecated: +{"1.2.840.10008.3.1.2.3.3" , "Modality Performed Procedure Step IOD Modules" }, +{"1.2.840.10008.5.1.4.1.1.5" , "NM Image IOD Modules"}, +{"1.2.840.10008.5.1.4.1.1.6" , "US Image IOD Modules"}, +{"1.2.840.10008.5.1.4.1.1.3" , "US Multi Frame Image IOD Modules"}, +{"1.2.840.10008.5.1.4.1.1.12.3" , ""}, // XRayAngiographicBiplaneImageStorage +// private: +{ "1.3.12.2.1107.5.9.1" , "Siemens Non-image IOD Modules"}, // CSA Non-Image Storage + +{ 0, 0 } +}; + +unsigned int SOPClassUIDToIOD::GetNumberOfSOPClassToIOD() +{ + static const unsigned int n = sizeof( SOPClassUIDToIODStrings ) / sizeof( *SOPClassUIDToIODStrings ); + assert( n > 0 ); + return n - 1; +} + +const char *SOPClassUIDToIOD::GetIOD(UIDs const & uid) +{ +// std::ifstream is( ); +// +// char buf[BUFSIZ]; +// XML_Parser parser = XML_ParserCreate(NULL); +// int done; +// //int depth = 0; +// XML_SetUserData(parser, this); +// XML_SetElementHandler(parser, startElement, endElement); +// XML_SetCharacterDataHandler(parser, characterDataHandler); +// int ret = 0; +// do { +// is.read(buf, sizeof(buf)); +// size_t len = is.gcount(); +// done = len < sizeof(buf); +// if (XML_Parse(parser, buf, len, done) == XML_STATUS_ERROR) { +// fprintf(stderr, +// "%s at line %" XML_FMT_INT_MOD "u\n", +// XML_ErrorString(XML_GetErrorCode(parser)), +// XML_GetCurrentLineNumber(parser)); +// ret = 1; // Mark as error +// done = 1; // exit while +// } +// } while (!done); +// XML_ParserFree(parser); +// is.close(); + //typedef const char* const (*SOPClassUIDToIODType)[2]; + SOPClassUIDToIOD::SOPClassUIDToIODType *p = SOPClassUIDToIODStrings; + const char *sopclassuid = uid.GetString(); + + // FIXME I think we can do binary search + while( (*p)[0] && strcmp( (*p)[0] , sopclassuid ) != 0 ) + { + ++p; + } + return (*p)[1]; +} + +SOPClassUIDToIOD::SOPClassUIDToIODType *SOPClassUIDToIOD::GetSOPClassUIDToIODs() +{ + return SOPClassUIDToIODStrings; +} + +SOPClassUIDToIOD::SOPClassUIDToIODType& SOPClassUIDToIOD::GetSOPClassUIDToIOD(unsigned int i) +{ + if( i < SOPClassUIDToIOD::GetNumberOfSOPClassToIOD() ) + return SOPClassUIDToIODStrings[i]; + // else return the {0x0, 0x0} sentinel: + assert( *SOPClassUIDToIODStrings[ SOPClassUIDToIOD::GetNumberOfSOPClassToIOD() ] == 0 ); + return SOPClassUIDToIODStrings[ SOPClassUIDToIOD::GetNumberOfSOPClassToIOD() ]; + +} + +const char *SOPClassUIDToIOD::GetSOPClassUIDFromIOD(const char *iod) +{ + if(!iod) return NULL; + unsigned int i = 0; + SOPClassUIDToIODType *sopclassuidtoiods = GetSOPClassUIDToIODs(); + const char *p = sopclassuidtoiods[i][1]; + while( p != 0 ) + { + if( strcmp( iod, p ) == 0 ) + { + break; + } + ++i; + p = sopclassuidtoiods[i][1]; + } + // \postcondition always valid (before sentinel) + assert( i <= GetNumberOfSOPClassToIOD() ); + return sopclassuidtoiods[i][0]; +} + +const char *SOPClassUIDToIOD::GetIODFromSOPClassUID(const char *sopclassuid) +{ + if(!sopclassuid) return NULL; + unsigned int i = 0; + SOPClassUIDToIODType *sopclassuidtoiods = GetSOPClassUIDToIODs(); + const char *p = sopclassuidtoiods[i][0]; + while( p != 0 ) + { + if( strcmp( sopclassuid, p ) == 0 ) + { + break; + } + ++i; + p = sopclassuidtoiods[i][0]; + } + // \postcondition always valid (before sentinel) + assert( i <= GetNumberOfSOPClassToIOD() ); + return sopclassuidtoiods[i][1]; +} + +} diff --git a/gdcm/Source/DataDictionary/gdcmSOPClassUIDToIOD.h b/gdcm/Source/DataDictionary/gdcmSOPClassUIDToIOD.h new file mode 100644 index 0000000..173167f --- /dev/null +++ b/gdcm/Source/DataDictionary/gdcmSOPClassUIDToIOD.h @@ -0,0 +1,49 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#ifndef GDCMSOPCLASSUIDTOIOD_H +#define GDCMSOPCLASSUIDTOIOD_H + +#include "gdcmUIDs.h" + +namespace gdcm +{ + +/** + * \brief Class convert a class SOP Class UID into IOD + * + * Reference PS 3.4 Table B.5-1 STANDARD SOP CLASSES + */ +class GDCM_EXPORT SOPClassUIDToIOD +{ +public: + /// Return the associated IOD based on a SOP Class UID uid + /// (there is a one-to-one mapping from SOP Class UID to matching IOD) + static const char *GetIOD(UIDs const & uid); + + /// Return the number of SOP Class UID listed internally + static unsigned int GetNumberOfSOPClassToIOD(); + + typedef const char* const (SOPClassUIDToIODType)[2]; + static SOPClassUIDToIODType* GetSOPClassUIDToIODs(); + + static SOPClassUIDToIODType& GetSOPClassUIDToIOD(unsigned int i); + + static const char *GetSOPClassUIDFromIOD(const char *iod); + static const char *GetIODFromSOPClassUID(const char *sopclassuid); +}; + +} // end namespace gdcm + +#endif //GDCMSOPCLASSUIDTOIOD_H diff --git a/gdcm/Source/DataDictionary/gdcmTagKeywords.h b/gdcm/Source/DataDictionary/gdcmTagKeywords.h new file mode 100644 index 0000000..e68c9a4 --- /dev/null +++ b/gdcm/Source/DataDictionary/gdcmTagKeywords.h @@ -0,0 +1,3685 @@ +// GENERATED FILE DO NOT EDIT +// $ xsltproc TagKeywords.xsl Part6.xml > gdcmTagKeywords.h + +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2012 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#ifndef GDCMTAGKEYWORDS_H +#define GDCMTAGKEYWORDS_H + +#include "gdcmAttribute.h" + +namespace gdcm { +namespace Keywords { + + typedef gdcm::Attribute<0x0000, 0x0000> CommandGroupLength; + typedef gdcm::Attribute<0x0000, 0x0002> AffectedSOPClassUID; + typedef gdcm::Attribute<0x0000, 0x0003> RequestedSOPClassUID; + typedef gdcm::Attribute<0x0000, 0x0100> CommandField; + typedef gdcm::Attribute<0x0000, 0x0110> MessageID; + typedef gdcm::Attribute<0x0000, 0x0120> MessageIDBeingRespondedTo; + typedef gdcm::Attribute<0x0000, 0x0600> MoveDestination; + typedef gdcm::Attribute<0x0000, 0x0700> Priority; + typedef gdcm::Attribute<0x0000, 0x0800> CommandDataSetType; + typedef gdcm::Attribute<0x0000, 0x0900> Status; + typedef gdcm::Attribute<0x0000, 0x0901> OffendingElement; + typedef gdcm::Attribute<0x0000, 0x0902> ErrorComment; + typedef gdcm::Attribute<0x0000, 0x0903> ErrorID; + typedef gdcm::Attribute<0x0000, 0x1000> AffectedSOPInstanceUID; + typedef gdcm::Attribute<0x0000, 0x1001> RequestedSOPInstanceUID; + typedef gdcm::Attribute<0x0000, 0x1002> EventTypeID; + typedef gdcm::Attribute<0x0000, 0x1005> AttributeIdentifierList; + typedef gdcm::Attribute<0x0000, 0x1008> ActionTypeID; + typedef gdcm::Attribute<0x0000, 0x1020> NumberOfRemainingSuboperations; + typedef gdcm::Attribute<0x0000, 0x1021> NumberOfCompletedSuboperations; + typedef gdcm::Attribute<0x0000, 0x1022> NumberOfFailedSuboperations; + typedef gdcm::Attribute<0x0000, 0x1023> NumberOfWarningSuboperations; + typedef gdcm::Attribute<0x0000, 0x1030> MoveOriginatorApplicationEntityTitle; + typedef gdcm::Attribute<0x0000, 0x1031> MoveOriginatorMessageID; + typedef gdcm::Attribute<0x0000, 0x0001> CommandLengthToEnd; + typedef gdcm::Attribute<0x0000, 0x0010> CommandRecognitionCode; + typedef gdcm::Attribute<0x0000, 0x0200> Initiator; + typedef gdcm::Attribute<0x0000, 0x0300> Receiver; + typedef gdcm::Attribute<0x0000, 0x0400> FindLocation; + typedef gdcm::Attribute<0x0000, 0x0850> NumberOfMatches; + typedef gdcm::Attribute<0x0000, 0x0860> ResponseSequenceNumber; + typedef gdcm::Attribute<0x0000, 0x4000> DialogReceiver; + typedef gdcm::Attribute<0x0000, 0x4010> TerminalType; + typedef gdcm::Attribute<0x0000, 0x5010> MessageSetID; + typedef gdcm::Attribute<0x0000, 0x5020> EndMessageID; + typedef gdcm::Attribute<0x0000, 0x5110> DisplayFormat; + typedef gdcm::Attribute<0x0000, 0x5120> PagePositionID; + typedef gdcm::Attribute<0x0000, 0x5130> TextFormatID; + typedef gdcm::Attribute<0x0000, 0x5140> NormalReverse; + typedef gdcm::Attribute<0x0000, 0x5150> AddGrayScale; + typedef gdcm::Attribute<0x0000, 0x5160> Borders; + typedef gdcm::Attribute<0x0000, 0x5170> Copies; + typedef gdcm::Attribute<0x0000, 0x5180> CommandMagnificationType; + typedef gdcm::Attribute<0x0000, 0x5190> Erase; + typedef gdcm::Attribute<0x0000, 0x51a0> Print; + typedef gdcm::Attribute<0x0000, 0x51b0> Overlays; + typedef gdcm::Attribute<0x0008, 0x0001> LengthToEnd; + typedef gdcm::Attribute<0x0008, 0x0005> SpecificCharacterSet; + typedef gdcm::Attribute<0x0008, 0x0006> LanguageCodeSequence; + typedef gdcm::Attribute<0x0008, 0x0008> ImageType; + typedef gdcm::Attribute<0x0008, 0x0010> RecognitionCode; + typedef gdcm::Attribute<0x0008, 0x0012> InstanceCreationDate; + typedef gdcm::Attribute<0x0008, 0x0013> InstanceCreationTime; + typedef gdcm::Attribute<0x0008, 0x0014> InstanceCreatorUID; + typedef gdcm::Attribute<0x0008, 0x0016> SOPClassUID; + typedef gdcm::Attribute<0x0008, 0x0018> SOPInstanceUID; + typedef gdcm::Attribute<0x0008, 0x001a> RelatedGeneralSOPClassUID; + typedef gdcm::Attribute<0x0008, 0x001b> OriginalSpecializedSOPClassUID; + typedef gdcm::Attribute<0x0008, 0x0020> StudyDate; + typedef gdcm::Attribute<0x0008, 0x0021> SeriesDate; + typedef gdcm::Attribute<0x0008, 0x0022> AcquisitionDate; + typedef gdcm::Attribute<0x0008, 0x0023> ContentDate; + typedef gdcm::Attribute<0x0008, 0x0024> OverlayDate; + typedef gdcm::Attribute<0x0008, 0x0025> CurveDate; + typedef gdcm::Attribute<0x0008, 0x002a> AcquisitionDateTime; + typedef gdcm::Attribute<0x0008, 0x0030> StudyTime; + typedef gdcm::Attribute<0x0008, 0x0031> SeriesTime; + typedef gdcm::Attribute<0x0008, 0x0032> AcquisitionTime; + typedef gdcm::Attribute<0x0008, 0x0033> ContentTime; + typedef gdcm::Attribute<0x0008, 0x0034> OverlayTime; + typedef gdcm::Attribute<0x0008, 0x0035> CurveTime; + typedef gdcm::Attribute<0x0008, 0x0040> DataSetType; + typedef gdcm::Attribute<0x0008, 0x0041> DataSetSubtype; + typedef gdcm::Attribute<0x0008, 0x0042> NuclearMedicineSeriesType; + typedef gdcm::Attribute<0x0008, 0x0050> AccessionNumber; + typedef gdcm::Attribute<0x0008, 0x0051> IssuerOfAccessionNumberSequence; + typedef gdcm::Attribute<0x0008, 0x0052> QueryRetrieveLevel; + typedef gdcm::Attribute<0x0008, 0x0054> RetrieveAETitle; + typedef gdcm::Attribute<0x0008, 0x0056> InstanceAvailability; + typedef gdcm::Attribute<0x0008, 0x0058> FailedSOPInstanceUIDList; + typedef gdcm::Attribute<0x0008, 0x0060> Modality; + typedef gdcm::Attribute<0x0008, 0x0061> ModalitiesInStudy; + typedef gdcm::Attribute<0x0008, 0x0062> SOPClassesInStudy; + typedef gdcm::Attribute<0x0008, 0x0064> ConversionType; + typedef gdcm::Attribute<0x0008, 0x0068> PresentationIntentType; + typedef gdcm::Attribute<0x0008, 0x0070> Manufacturer; + typedef gdcm::Attribute<0x0008, 0x0080> InstitutionName; + typedef gdcm::Attribute<0x0008, 0x0081> InstitutionAddress; + typedef gdcm::Attribute<0x0008, 0x0082> InstitutionCodeSequence; + typedef gdcm::Attribute<0x0008, 0x0090> ReferringPhysicianName; + typedef gdcm::Attribute<0x0008, 0x0092> ReferringPhysicianAddress; + typedef gdcm::Attribute<0x0008, 0x0094> ReferringPhysicianTelephoneNumbers; + typedef gdcm::Attribute<0x0008, 0x0096> ReferringPhysicianIdentificationSequence; + typedef gdcm::Attribute<0x0008, 0x0100> CodeValue; + typedef gdcm::Attribute<0x0008, 0x0102> CodingSchemeDesignator; + typedef gdcm::Attribute<0x0008, 0x0103> CodingSchemeVersion; + typedef gdcm::Attribute<0x0008, 0x0104> CodeMeaning; + typedef gdcm::Attribute<0x0008, 0x0105> MappingResource; + typedef gdcm::Attribute<0x0008, 0x0106> ContextGroupVersion; + typedef gdcm::Attribute<0x0008, 0x0107> ContextGroupLocalVersion; + typedef gdcm::Attribute<0x0008, 0x010b> ContextGroupExtensionFlag; + typedef gdcm::Attribute<0x0008, 0x010c> CodingSchemeUID; + typedef gdcm::Attribute<0x0008, 0x010d> ContextGroupExtensionCreatorUID; + typedef gdcm::Attribute<0x0008, 0x010f> ContextIdentifier; + typedef gdcm::Attribute<0x0008, 0x0110> CodingSchemeIdentificationSequence; + typedef gdcm::Attribute<0x0008, 0x0112> CodingSchemeRegistry; + typedef gdcm::Attribute<0x0008, 0x0114> CodingSchemeExternalID; + typedef gdcm::Attribute<0x0008, 0x0115> CodingSchemeName; + typedef gdcm::Attribute<0x0008, 0x0116> CodingSchemeResponsibleOrganization; + typedef gdcm::Attribute<0x0008, 0x0117> ContextUID; + typedef gdcm::Attribute<0x0008, 0x0201> TimezoneOffsetFromUTC; + typedef gdcm::Attribute<0x0008, 0x1000> NetworkID; + typedef gdcm::Attribute<0x0008, 0x1010> StationName; + typedef gdcm::Attribute<0x0008, 0x1030> StudyDescription; + typedef gdcm::Attribute<0x0008, 0x1032> ProcedureCodeSequence; + typedef gdcm::Attribute<0x0008, 0x103e> SeriesDescription; + typedef gdcm::Attribute<0x0008, 0x103f> SeriesDescriptionCodeSequence; + typedef gdcm::Attribute<0x0008, 0x1040> InstitutionalDepartmentName; + typedef gdcm::Attribute<0x0008, 0x1048> PhysiciansOfRecord; + typedef gdcm::Attribute<0x0008, 0x1049> PhysiciansOfRecordIdentificationSequence; + typedef gdcm::Attribute<0x0008, 0x1050> PerformingPhysicianName; + typedef gdcm::Attribute<0x0008, 0x1052> PerformingPhysicianIdentificationSequence; + typedef gdcm::Attribute<0x0008, 0x1060> NameOfPhysiciansReadingStudy; + typedef gdcm::Attribute<0x0008, 0x1062> PhysiciansReadingStudyIdentificationSequence; + typedef gdcm::Attribute<0x0008, 0x1070> OperatorsName; + typedef gdcm::Attribute<0x0008, 0x1072> OperatorIdentificationSequence; + typedef gdcm::Attribute<0x0008, 0x1080> AdmittingDiagnosesDescription; + typedef gdcm::Attribute<0x0008, 0x1084> AdmittingDiagnosesCodeSequence; + typedef gdcm::Attribute<0x0008, 0x1090> ManufacturerModelName; + typedef gdcm::Attribute<0x0008, 0x1100> ReferencedResultsSequence; + typedef gdcm::Attribute<0x0008, 0x1110> ReferencedStudySequence; + typedef gdcm::Attribute<0x0008, 0x1111> ReferencedPerformedProcedureStepSequence; + typedef gdcm::Attribute<0x0008, 0x1115> ReferencedSeriesSequence; + typedef gdcm::Attribute<0x0008, 0x1120> ReferencedPatientSequence; + typedef gdcm::Attribute<0x0008, 0x1125> ReferencedVisitSequence; + typedef gdcm::Attribute<0x0008, 0x1130> ReferencedOverlaySequence; + typedef gdcm::Attribute<0x0008, 0x1134> ReferencedStereometricInstanceSequence; + typedef gdcm::Attribute<0x0008, 0x113a> ReferencedWaveformSequence; + typedef gdcm::Attribute<0x0008, 0x1140> ReferencedImageSequence; + typedef gdcm::Attribute<0x0008, 0x1145> ReferencedCurveSequence; + typedef gdcm::Attribute<0x0008, 0x114a> ReferencedInstanceSequence; + typedef gdcm::Attribute<0x0008, 0x114b> ReferencedRealWorldValueMappingInstanceSequence; + typedef gdcm::Attribute<0x0008, 0x1150> ReferencedSOPClassUID; + typedef gdcm::Attribute<0x0008, 0x1155> ReferencedSOPInstanceUID; + typedef gdcm::Attribute<0x0008, 0x115a> SOPClassesSupported; + typedef gdcm::Attribute<0x0008, 0x1160> ReferencedFrameNumber; + typedef gdcm::Attribute<0x0008, 0x1161> SimpleFrameList; + typedef gdcm::Attribute<0x0008, 0x1162> CalculatedFrameList; + typedef gdcm::Attribute<0x0008, 0x1163> TimeRange; + typedef gdcm::Attribute<0x0008, 0x1164> FrameExtractionSequence; + typedef gdcm::Attribute<0x0008, 0x1167> MultiFrameSourceSOPInstanceUID; + typedef gdcm::Attribute<0x0008, 0x1195> TransactionUID; + typedef gdcm::Attribute<0x0008, 0x1197> FailureReason; + typedef gdcm::Attribute<0x0008, 0x1198> FailedSOPSequence; + typedef gdcm::Attribute<0x0008, 0x1199> ReferencedSOPSequence; + typedef gdcm::Attribute<0x0008, 0x1200> StudiesContainingOtherReferencedInstancesSequence; + typedef gdcm::Attribute<0x0008, 0x1250> RelatedSeriesSequence; + typedef gdcm::Attribute<0x0008, 0x2110> LossyImageCompressionRetired; + typedef gdcm::Attribute<0x0008, 0x2111> DerivationDescription; + typedef gdcm::Attribute<0x0008, 0x2112> SourceImageSequence; + typedef gdcm::Attribute<0x0008, 0x2120> StageName; + typedef gdcm::Attribute<0x0008, 0x2122> StageNumber; + typedef gdcm::Attribute<0x0008, 0x2124> NumberOfStages; + typedef gdcm::Attribute<0x0008, 0x2127> ViewName; + typedef gdcm::Attribute<0x0008, 0x2128> ViewNumber; + typedef gdcm::Attribute<0x0008, 0x2129> NumberOfEventTimers; + typedef gdcm::Attribute<0x0008, 0x212a> NumberOfViewsInStage; + typedef gdcm::Attribute<0x0008, 0x2130> EventElapsedTimes; + typedef gdcm::Attribute<0x0008, 0x2132> EventTimerNames; + typedef gdcm::Attribute<0x0008, 0x2133> EventTimerSequence; + typedef gdcm::Attribute<0x0008, 0x2134> EventTimeOffset; + typedef gdcm::Attribute<0x0008, 0x2135> EventCodeSequence; + typedef gdcm::Attribute<0x0008, 0x2142> StartTrim; + typedef gdcm::Attribute<0x0008, 0x2143> StopTrim; + typedef gdcm::Attribute<0x0008, 0x2144> RecommendedDisplayFrameRate; + typedef gdcm::Attribute<0x0008, 0x2200> TransducerPosition; + typedef gdcm::Attribute<0x0008, 0x2204> TransducerOrientation; + typedef gdcm::Attribute<0x0008, 0x2208> AnatomicStructure; + typedef gdcm::Attribute<0x0008, 0x2218> AnatomicRegionSequence; + typedef gdcm::Attribute<0x0008, 0x2220> AnatomicRegionModifierSequence; + typedef gdcm::Attribute<0x0008, 0x2228> PrimaryAnatomicStructureSequence; + typedef gdcm::Attribute<0x0008, 0x2229> AnatomicStructureSpaceOrRegionSequence; + typedef gdcm::Attribute<0x0008, 0x2230> PrimaryAnatomicStructureModifierSequence; + typedef gdcm::Attribute<0x0008, 0x2240> TransducerPositionSequence; + typedef gdcm::Attribute<0x0008, 0x2242> TransducerPositionModifierSequence; + typedef gdcm::Attribute<0x0008, 0x2244> TransducerOrientationSequence; + typedef gdcm::Attribute<0x0008, 0x2246> TransducerOrientationModifierSequence; + typedef gdcm::Attribute<0x0008, 0x2251> AnatomicStructureSpaceOrRegionCodeSequenceTrial; + typedef gdcm::Attribute<0x0008, 0x2253> AnatomicPortalOfEntranceCodeSequenceTrial; + typedef gdcm::Attribute<0x0008, 0x2255> AnatomicApproachDirectionCodeSequenceTrial; + typedef gdcm::Attribute<0x0008, 0x2256> AnatomicPerspectiveDescriptionTrial; + typedef gdcm::Attribute<0x0008, 0x2257> AnatomicPerspectiveCodeSequenceTrial; + typedef gdcm::Attribute<0x0008, 0x2258> AnatomicLocationOfExaminingInstrumentDescriptionTrial; + typedef gdcm::Attribute<0x0008, 0x2259> AnatomicLocationOfExaminingInstrumentCodeSequenceTrial; + typedef gdcm::Attribute<0x0008, 0x225a> AnatomicStructureSpaceOrRegionModifierCodeSequenceTrial; + typedef gdcm::Attribute<0x0008, 0x225c> OnAxisBackgroundAnatomicStructureCodeSequenceTrial; + typedef gdcm::Attribute<0x0008, 0x3001> AlternateRepresentationSequence; + typedef gdcm::Attribute<0x0008, 0x3010> IrradiationEventUID; + typedef gdcm::Attribute<0x0008, 0x4000> IdentifyingComments; + typedef gdcm::Attribute<0x0008, 0x9007> FrameType; + typedef gdcm::Attribute<0x0008, 0x9092> ReferencedImageEvidenceSequence; + typedef gdcm::Attribute<0x0008, 0x9121> ReferencedRawDataSequence; + typedef gdcm::Attribute<0x0008, 0x9123> CreatorVersionUID; + typedef gdcm::Attribute<0x0008, 0x9124> DerivationImageSequence; + typedef gdcm::Attribute<0x0008, 0x9154> SourceImageEvidenceSequence; + typedef gdcm::Attribute<0x0008, 0x9205> PixelPresentation; + typedef gdcm::Attribute<0x0008, 0x9206> VolumetricProperties; + typedef gdcm::Attribute<0x0008, 0x9207> VolumeBasedCalculationTechnique; + typedef gdcm::Attribute<0x0008, 0x9208> ComplexImageComponent; + typedef gdcm::Attribute<0x0008, 0x9209> AcquisitionContrast; + typedef gdcm::Attribute<0x0008, 0x9215> DerivationCodeSequence; + typedef gdcm::Attribute<0x0008, 0x9237> ReferencedPresentationStateSequence; + typedef gdcm::Attribute<0x0008, 0x9410> ReferencedOtherPlaneSequence; + typedef gdcm::Attribute<0x0008, 0x9458> FrameDisplaySequence; + typedef gdcm::Attribute<0x0008, 0x9459> RecommendedDisplayFrameRateInFloat; + typedef gdcm::Attribute<0x0008, 0x9460> SkipFrameRangeFlag; + typedef gdcm::Attribute<0x0010, 0x0010> PatientName; + typedef gdcm::Attribute<0x0010, 0x0020> PatientID; + typedef gdcm::Attribute<0x0010, 0x0021> IssuerOfPatientID; + typedef gdcm::Attribute<0x0010, 0x0022> TypeOfPatientID; + typedef gdcm::Attribute<0x0010, 0x0024> IssuerOfPatientIDQualifiersSequence; + typedef gdcm::Attribute<0x0010, 0x0030> PatientBirthDate; + typedef gdcm::Attribute<0x0010, 0x0032> PatientBirthTime; + typedef gdcm::Attribute<0x0010, 0x0040> PatientSex; + typedef gdcm::Attribute<0x0010, 0x0050> PatientInsurancePlanCodeSequence; + typedef gdcm::Attribute<0x0010, 0x0101> PatientPrimaryLanguageCodeSequence; + typedef gdcm::Attribute<0x0010, 0x0102> PatientPrimaryLanguageModifierCodeSequence; + typedef gdcm::Attribute<0x0010, 0x1000> OtherPatientIDs; + typedef gdcm::Attribute<0x0010, 0x1001> OtherPatientNames; + typedef gdcm::Attribute<0x0010, 0x1002> OtherPatientIDsSequence; + typedef gdcm::Attribute<0x0010, 0x1005> PatientBirthName; + typedef gdcm::Attribute<0x0010, 0x1010> PatientAge; + typedef gdcm::Attribute<0x0010, 0x1020> PatientSize; + typedef gdcm::Attribute<0x0010, 0x1021> PatientSizeCodeSequence; + typedef gdcm::Attribute<0x0010, 0x1030> PatientWeight; + typedef gdcm::Attribute<0x0010, 0x1040> PatientAddress; + typedef gdcm::Attribute<0x0010, 0x1050> InsurancePlanIdentification; + typedef gdcm::Attribute<0x0010, 0x1060> PatientMotherBirthName; + typedef gdcm::Attribute<0x0010, 0x1080> MilitaryRank; + typedef gdcm::Attribute<0x0010, 0x1081> BranchOfService; + typedef gdcm::Attribute<0x0010, 0x1090> MedicalRecordLocator; + typedef gdcm::Attribute<0x0010, 0x2000> MedicalAlerts; + typedef gdcm::Attribute<0x0010, 0x2110> Allergies; + typedef gdcm::Attribute<0x0010, 0x2150> CountryOfResidence; + typedef gdcm::Attribute<0x0010, 0x2152> RegionOfResidence; + typedef gdcm::Attribute<0x0010, 0x2154> PatientTelephoneNumbers; + typedef gdcm::Attribute<0x0010, 0x2160> EthnicGroup; + typedef gdcm::Attribute<0x0010, 0x2180> Occupation; + typedef gdcm::Attribute<0x0010, 0x21a0> SmokingStatus; + typedef gdcm::Attribute<0x0010, 0x21b0> AdditionalPatientHistory; + typedef gdcm::Attribute<0x0010, 0x21c0> PregnancyStatus; + typedef gdcm::Attribute<0x0010, 0x21d0> LastMenstrualDate; + typedef gdcm::Attribute<0x0010, 0x21f0> PatientReligiousPreference; + typedef gdcm::Attribute<0x0010, 0x2201> PatientSpeciesDescription; + typedef gdcm::Attribute<0x0010, 0x2202> PatientSpeciesCodeSequence; + typedef gdcm::Attribute<0x0010, 0x2203> PatientSexNeutered; + typedef gdcm::Attribute<0x0010, 0x2210> AnatomicalOrientationType; + typedef gdcm::Attribute<0x0010, 0x2292> PatientBreedDescription; + typedef gdcm::Attribute<0x0010, 0x2293> PatientBreedCodeSequence; + typedef gdcm::Attribute<0x0010, 0x2294> BreedRegistrationSequence; + typedef gdcm::Attribute<0x0010, 0x2295> BreedRegistrationNumber; + typedef gdcm::Attribute<0x0010, 0x2296> BreedRegistryCodeSequence; + typedef gdcm::Attribute<0x0010, 0x2297> ResponsiblePerson; + typedef gdcm::Attribute<0x0010, 0x2298> ResponsiblePersonRole; + typedef gdcm::Attribute<0x0010, 0x2299> ResponsibleOrganization; + typedef gdcm::Attribute<0x0010, 0x4000> PatientComments; + typedef gdcm::Attribute<0x0010, 0x9431> ExaminedBodyThickness; + typedef gdcm::Attribute<0x0012, 0x0010> ClinicalTrialSponsorName; + typedef gdcm::Attribute<0x0012, 0x0020> ClinicalTrialProtocolID; + typedef gdcm::Attribute<0x0012, 0x0021> ClinicalTrialProtocolName; + typedef gdcm::Attribute<0x0012, 0x0030> ClinicalTrialSiteID; + typedef gdcm::Attribute<0x0012, 0x0031> ClinicalTrialSiteName; + typedef gdcm::Attribute<0x0012, 0x0040> ClinicalTrialSubjectID; + typedef gdcm::Attribute<0x0012, 0x0042> ClinicalTrialSubjectReadingID; + typedef gdcm::Attribute<0x0012, 0x0050> ClinicalTrialTimePointID; + typedef gdcm::Attribute<0x0012, 0x0051> ClinicalTrialTimePointDescription; + typedef gdcm::Attribute<0x0012, 0x0060> ClinicalTrialCoordinatingCenterName; + typedef gdcm::Attribute<0x0012, 0x0062> PatientIdentityRemoved; + typedef gdcm::Attribute<0x0012, 0x0063> DeidentificationMethod; + typedef gdcm::Attribute<0x0012, 0x0064> DeidentificationMethodCodeSequence; + typedef gdcm::Attribute<0x0012, 0x0071> ClinicalTrialSeriesID; + typedef gdcm::Attribute<0x0012, 0x0072> ClinicalTrialSeriesDescription; + typedef gdcm::Attribute<0x0012, 0x0081> ClinicalTrialProtocolEthicsCommitteeName; + typedef gdcm::Attribute<0x0012, 0x0082> ClinicalTrialProtocolEthicsCommitteeApprovalNumber; + typedef gdcm::Attribute<0x0012, 0x0083> ConsentForClinicalTrialUseSequence; + typedef gdcm::Attribute<0x0012, 0x0084> DistributionType; + typedef gdcm::Attribute<0x0012, 0x0085> ConsentForDistributionFlag; + typedef gdcm::Attribute<0x0014, 0x0023> CADFileFormat; + typedef gdcm::Attribute<0x0014, 0x0024> ComponentReferenceSystem; + typedef gdcm::Attribute<0x0014, 0x0025> ComponentManufacturingProcedure; + typedef gdcm::Attribute<0x0014, 0x0028> ComponentManufacturer; + typedef gdcm::Attribute<0x0014, 0x0030> MaterialThickness; + typedef gdcm::Attribute<0x0014, 0x0032> MaterialPipeDiameter; + typedef gdcm::Attribute<0x0014, 0x0034> MaterialIsolationDiameter; + typedef gdcm::Attribute<0x0014, 0x0042> MaterialGrade; + typedef gdcm::Attribute<0x0014, 0x0044> MaterialPropertiesFileID; + typedef gdcm::Attribute<0x0014, 0x0045> MaterialPropertiesFileFormat; + typedef gdcm::Attribute<0x0014, 0x0046> MaterialNotes; + typedef gdcm::Attribute<0x0014, 0x0050> ComponentShape; + typedef gdcm::Attribute<0x0014, 0x0052> CurvatureType; + typedef gdcm::Attribute<0x0014, 0x0054> OuterDiameter; + typedef gdcm::Attribute<0x0014, 0x0056> InnerDiameter; + typedef gdcm::Attribute<0x0014, 0x1010> ActualEnvironmentalConditions; + typedef gdcm::Attribute<0x0014, 0x1020> ExpiryDate; + typedef gdcm::Attribute<0x0014, 0x1040> EnvironmentalConditions; + typedef gdcm::Attribute<0x0014, 0x2002> EvaluatorSequence; + typedef gdcm::Attribute<0x0014, 0x2004> EvaluatorNumber; + typedef gdcm::Attribute<0x0014, 0x2006> EvaluatorName; + typedef gdcm::Attribute<0x0014, 0x2008> EvaluationAttempt; + typedef gdcm::Attribute<0x0014, 0x2012> IndicationSequence; + typedef gdcm::Attribute<0x0014, 0x2014> IndicationNumber; + typedef gdcm::Attribute<0x0014, 0x2016> IndicationLabel; + typedef gdcm::Attribute<0x0014, 0x2018> IndicationDescription; + typedef gdcm::Attribute<0x0014, 0x201a> IndicationType; + typedef gdcm::Attribute<0x0014, 0x201c> IndicationDisposition; + typedef gdcm::Attribute<0x0014, 0x201e> IndicationROISequence; + typedef gdcm::Attribute<0x0014, 0x2030> IndicationPhysicalPropertySequence; + typedef gdcm::Attribute<0x0014, 0x2032> PropertyLabel; + typedef gdcm::Attribute<0x0014, 0x2202> CoordinateSystemNumberOfAxes; + typedef gdcm::Attribute<0x0014, 0x2204> CoordinateSystemAxesSequence; + typedef gdcm::Attribute<0x0014, 0x2206> CoordinateSystemAxisDescription; + typedef gdcm::Attribute<0x0014, 0x2208> CoordinateSystemDataSetMapping; + typedef gdcm::Attribute<0x0014, 0x220a> CoordinateSystemAxisNumber; + typedef gdcm::Attribute<0x0014, 0x220c> CoordinateSystemAxisType; + typedef gdcm::Attribute<0x0014, 0x220e> CoordinateSystemAxisUnits; + typedef gdcm::Attribute<0x0014, 0x2210> CoordinateSystemAxisValues; + typedef gdcm::Attribute<0x0014, 0x2220> CoordinateSystemTransformSequence; + typedef gdcm::Attribute<0x0014, 0x2222> TransformDescription; + typedef gdcm::Attribute<0x0014, 0x2224> TransformNumberOfAxes; + typedef gdcm::Attribute<0x0014, 0x2226> TransformOrderOfAxes; + typedef gdcm::Attribute<0x0014, 0x2228> TransformedAxisUnits; + typedef gdcm::Attribute<0x0014, 0x222a> CoordinateSystemTransformRotationAndScaleMatrix; + typedef gdcm::Attribute<0x0014, 0x222c> CoordinateSystemTransformTranslationMatrix; + typedef gdcm::Attribute<0x0014, 0x3011> InternalDetectorFrameTime; + typedef gdcm::Attribute<0x0014, 0x3012> NumberOfFramesIntegrated; + typedef gdcm::Attribute<0x0014, 0x3020> DetectorTemperatureSequence; + typedef gdcm::Attribute<0x0014, 0x3022> SensorName; + typedef gdcm::Attribute<0x0014, 0x3024> HorizontalOffsetOfSensor; + typedef gdcm::Attribute<0x0014, 0x3026> VerticalOffsetOfSensor; + typedef gdcm::Attribute<0x0014, 0x3028> SensorTemperature; + typedef gdcm::Attribute<0x0014, 0x3040> DarkCurrentSequence; + typedef gdcm::Attribute<0x0014, 0x3050> DarkCurrentCounts; + typedef gdcm::Attribute<0x0014, 0x3060> GainCorrectionReferenceSequence; + typedef gdcm::Attribute<0x0014, 0x3070> AirCounts; + typedef gdcm::Attribute<0x0014, 0x3071> KVUsedInGainCalibration; + typedef gdcm::Attribute<0x0014, 0x3072> MAUsedInGainCalibration; + typedef gdcm::Attribute<0x0014, 0x3073> NumberOfFramesUsedForIntegration; + typedef gdcm::Attribute<0x0014, 0x3074> FilterMaterialUsedInGainCalibration; + typedef gdcm::Attribute<0x0014, 0x3075> FilterThicknessUsedInGainCalibration; + typedef gdcm::Attribute<0x0014, 0x3076> DateOfGainCalibration; + typedef gdcm::Attribute<0x0014, 0x3077> TimeOfGainCalibration; + typedef gdcm::Attribute<0x0014, 0x3080> BadPixelImage; + typedef gdcm::Attribute<0x0014, 0x3099> CalibrationNotes; + typedef gdcm::Attribute<0x0014, 0x4002> PulserEquipmentSequence; + typedef gdcm::Attribute<0x0014, 0x4004> PulserType; + typedef gdcm::Attribute<0x0014, 0x4006> PulserNotes; + typedef gdcm::Attribute<0x0014, 0x4008> ReceiverEquipmentSequence; + typedef gdcm::Attribute<0x0014, 0x400a> AmplifierType; + typedef gdcm::Attribute<0x0014, 0x400c> ReceiverNotes; + typedef gdcm::Attribute<0x0014, 0x400e> PreAmplifierEquipmentSequence; + typedef gdcm::Attribute<0x0014, 0x400f> PreAmplifierNotes; + typedef gdcm::Attribute<0x0014, 0x4010> TransmitTransducerSequence; + typedef gdcm::Attribute<0x0014, 0x4011> ReceiveTransducerSequence; + typedef gdcm::Attribute<0x0014, 0x4012> NumberOfElements; + typedef gdcm::Attribute<0x0014, 0x4013> ElementShape; + typedef gdcm::Attribute<0x0014, 0x4014> ElementDimensionA; + typedef gdcm::Attribute<0x0014, 0x4015> ElementDimensionB; + typedef gdcm::Attribute<0x0014, 0x4016> ElementPitch; + typedef gdcm::Attribute<0x0014, 0x4017> MeasuredBeamDimensionA; + typedef gdcm::Attribute<0x0014, 0x4018> MeasuredBeamDimensionB; + typedef gdcm::Attribute<0x0014, 0x4019> LocationOfMeasuredBeamDiameter; + typedef gdcm::Attribute<0x0014, 0x401a> NominalFrequency; + typedef gdcm::Attribute<0x0014, 0x401b> MeasuredCenterFrequency; + typedef gdcm::Attribute<0x0014, 0x401c> MeasuredBandwidth; + typedef gdcm::Attribute<0x0014, 0x4020> PulserSettingsSequence; + typedef gdcm::Attribute<0x0014, 0x4022> PulseWidth; + typedef gdcm::Attribute<0x0014, 0x4024> ExcitationFrequency; + typedef gdcm::Attribute<0x0014, 0x4026> ModulationType; + typedef gdcm::Attribute<0x0014, 0x4028> Damping; + typedef gdcm::Attribute<0x0014, 0x4030> ReceiverSettingsSequence; + typedef gdcm::Attribute<0x0014, 0x4031> AcquiredSoundpathLength; + typedef gdcm::Attribute<0x0014, 0x4032> AcquisitionCompressionType; + typedef gdcm::Attribute<0x0014, 0x4033> AcquisitionSampleSize; + typedef gdcm::Attribute<0x0014, 0x4034> RectifierSmoothing; + typedef gdcm::Attribute<0x0014, 0x4035> DACSequence; + typedef gdcm::Attribute<0x0014, 0x4036> DACType; + typedef gdcm::Attribute<0x0014, 0x4038> DACGainPoints; + typedef gdcm::Attribute<0x0014, 0x403a> DACTimePoints; + typedef gdcm::Attribute<0x0014, 0x403c> DACAmplitude; + typedef gdcm::Attribute<0x0014, 0x4040> PreAmplifierSettingsSequence; + typedef gdcm::Attribute<0x0014, 0x4050> TransmitTransducerSettingsSequence; + typedef gdcm::Attribute<0x0014, 0x4051> ReceiveTransducerSettingsSequence; + typedef gdcm::Attribute<0x0014, 0x4052> IncidentAngle; + typedef gdcm::Attribute<0x0014, 0x4054> CouplingTechnique; + typedef gdcm::Attribute<0x0014, 0x4056> CouplingMedium; + typedef gdcm::Attribute<0x0014, 0x4057> CouplingVelocity; + typedef gdcm::Attribute<0x0014, 0x4058> CrystalCenterLocationX; + typedef gdcm::Attribute<0x0014, 0x4059> CrystalCenterLocationZ; + typedef gdcm::Attribute<0x0014, 0x405a> SoundPathLength; + typedef gdcm::Attribute<0x0014, 0x405c> DelayLawIdentifier; + typedef gdcm::Attribute<0x0014, 0x4060> GateSettingsSequence; + typedef gdcm::Attribute<0x0014, 0x4062> GateThreshold; + typedef gdcm::Attribute<0x0014, 0x4064> VelocityOfSound; + typedef gdcm::Attribute<0x0014, 0x4070> CalibrationSettingsSequence; + typedef gdcm::Attribute<0x0014, 0x4072> CalibrationProcedure; + typedef gdcm::Attribute<0x0014, 0x4074> ProcedureVersion; + typedef gdcm::Attribute<0x0014, 0x4076> ProcedureCreationDate; + typedef gdcm::Attribute<0x0014, 0x4078> ProcedureExpirationDate; + typedef gdcm::Attribute<0x0014, 0x407a> ProcedureLastModifiedDate; + typedef gdcm::Attribute<0x0014, 0x407c> CalibrationTime; + typedef gdcm::Attribute<0x0014, 0x407e> CalibrationDate; + typedef gdcm::Attribute<0x0014, 0x5002> LINACEnergy; + typedef gdcm::Attribute<0x0014, 0x5004> LINACOutput; + typedef gdcm::Attribute<0x0018, 0x0010> ContrastBolusAgent; + typedef gdcm::Attribute<0x0018, 0x0012> ContrastBolusAgentSequence; + typedef gdcm::Attribute<0x0018, 0x0014> ContrastBolusAdministrationRouteSequence; + typedef gdcm::Attribute<0x0018, 0x0015> BodyPartExamined; + typedef gdcm::Attribute<0x0018, 0x0020> ScanningSequence; + typedef gdcm::Attribute<0x0018, 0x0021> SequenceVariant; + typedef gdcm::Attribute<0x0018, 0x0022> ScanOptions; + typedef gdcm::Attribute<0x0018, 0x0023> MRAcquisitionType; + typedef gdcm::Attribute<0x0018, 0x0024> SequenceName; + typedef gdcm::Attribute<0x0018, 0x0025> AngioFlag; + typedef gdcm::Attribute<0x0018, 0x0026> InterventionDrugInformationSequence; + typedef gdcm::Attribute<0x0018, 0x0027> InterventionDrugStopTime; + typedef gdcm::Attribute<0x0018, 0x0028> InterventionDrugDose; + typedef gdcm::Attribute<0x0018, 0x0029> InterventionDrugCodeSequence; + typedef gdcm::Attribute<0x0018, 0x002a> AdditionalDrugSequence; + typedef gdcm::Attribute<0x0018, 0x0030> Radionuclide; + typedef gdcm::Attribute<0x0018, 0x0031> Radiopharmaceutical; + typedef gdcm::Attribute<0x0018, 0x0032> EnergyWindowCenterline; + typedef gdcm::Attribute<0x0018, 0x0033> EnergyWindowTotalWidth; + typedef gdcm::Attribute<0x0018, 0x0034> InterventionDrugName; + typedef gdcm::Attribute<0x0018, 0x0035> InterventionDrugStartTime; + typedef gdcm::Attribute<0x0018, 0x0036> InterventionSequence; + typedef gdcm::Attribute<0x0018, 0x0037> TherapyType; + typedef gdcm::Attribute<0x0018, 0x0038> InterventionStatus; + typedef gdcm::Attribute<0x0018, 0x0039> TherapyDescription; + typedef gdcm::Attribute<0x0018, 0x003a> InterventionDescription; + typedef gdcm::Attribute<0x0018, 0x0040> CineRate; + typedef gdcm::Attribute<0x0018, 0x0042> InitialCineRunState; + typedef gdcm::Attribute<0x0018, 0x0050> SliceThickness; + typedef gdcm::Attribute<0x0018, 0x0060> KVP; + typedef gdcm::Attribute<0x0018, 0x0070> CountsAccumulated; + typedef gdcm::Attribute<0x0018, 0x0071> AcquisitionTerminationCondition; + typedef gdcm::Attribute<0x0018, 0x0072> EffectiveDuration; + typedef gdcm::Attribute<0x0018, 0x0073> AcquisitionStartCondition; + typedef gdcm::Attribute<0x0018, 0x0074> AcquisitionStartConditionData; + typedef gdcm::Attribute<0x0018, 0x0075> AcquisitionTerminationConditionData; + typedef gdcm::Attribute<0x0018, 0x0080> RepetitionTime; + typedef gdcm::Attribute<0x0018, 0x0081> EchoTime; + typedef gdcm::Attribute<0x0018, 0x0082> InversionTime; + typedef gdcm::Attribute<0x0018, 0x0083> NumberOfAverages; + typedef gdcm::Attribute<0x0018, 0x0084> ImagingFrequency; + typedef gdcm::Attribute<0x0018, 0x0085> ImagedNucleus; + typedef gdcm::Attribute<0x0018, 0x0086> EchoNumbers; + typedef gdcm::Attribute<0x0018, 0x0087> MagneticFieldStrength; + typedef gdcm::Attribute<0x0018, 0x0088> SpacingBetweenSlices; + typedef gdcm::Attribute<0x0018, 0x0089> NumberOfPhaseEncodingSteps; + typedef gdcm::Attribute<0x0018, 0x0090> DataCollectionDiameter; + typedef gdcm::Attribute<0x0018, 0x0091> EchoTrainLength; + typedef gdcm::Attribute<0x0018, 0x0093> PercentSampling; + typedef gdcm::Attribute<0x0018, 0x0094> PercentPhaseFieldOfView; + typedef gdcm::Attribute<0x0018, 0x0095> PixelBandwidth; + typedef gdcm::Attribute<0x0018, 0x1000> DeviceSerialNumber; + typedef gdcm::Attribute<0x0018, 0x1002> DeviceUID; + typedef gdcm::Attribute<0x0018, 0x1003> DeviceID; + typedef gdcm::Attribute<0x0018, 0x1004> PlateID; + typedef gdcm::Attribute<0x0018, 0x1005> GeneratorID; + typedef gdcm::Attribute<0x0018, 0x1006> GridID; + typedef gdcm::Attribute<0x0018, 0x1007> CassetteID; + typedef gdcm::Attribute<0x0018, 0x1008> GantryID; + typedef gdcm::Attribute<0x0018, 0x1010> SecondaryCaptureDeviceID; + typedef gdcm::Attribute<0x0018, 0x1011> HardcopyCreationDeviceID; + typedef gdcm::Attribute<0x0018, 0x1012> DateOfSecondaryCapture; + typedef gdcm::Attribute<0x0018, 0x1014> TimeOfSecondaryCapture; + typedef gdcm::Attribute<0x0018, 0x1016> SecondaryCaptureDeviceManufacturer; + typedef gdcm::Attribute<0x0018, 0x1017> HardcopyDeviceManufacturer; + typedef gdcm::Attribute<0x0018, 0x1018> SecondaryCaptureDeviceManufacturerModelName; + typedef gdcm::Attribute<0x0018, 0x1019> SecondaryCaptureDeviceSoftwareVersions; + typedef gdcm::Attribute<0x0018, 0x101a> HardcopyDeviceSoftwareVersion; + typedef gdcm::Attribute<0x0018, 0x101b> HardcopyDeviceManufacturerModelName; + typedef gdcm::Attribute<0x0018, 0x1020> SoftwareVersions; + typedef gdcm::Attribute<0x0018, 0x1022> VideoImageFormatAcquired; + typedef gdcm::Attribute<0x0018, 0x1023> DigitalImageFormatAcquired; + typedef gdcm::Attribute<0x0018, 0x1030> ProtocolName; + typedef gdcm::Attribute<0x0018, 0x1040> ContrastBolusRoute; + typedef gdcm::Attribute<0x0018, 0x1041> ContrastBolusVolume; + typedef gdcm::Attribute<0x0018, 0x1042> ContrastBolusStartTime; + typedef gdcm::Attribute<0x0018, 0x1043> ContrastBolusStopTime; + typedef gdcm::Attribute<0x0018, 0x1044> ContrastBolusTotalDose; + typedef gdcm::Attribute<0x0018, 0x1045> SyringeCounts; + typedef gdcm::Attribute<0x0018, 0x1046> ContrastFlowRate; + typedef gdcm::Attribute<0x0018, 0x1047> ContrastFlowDuration; + typedef gdcm::Attribute<0x0018, 0x1048> ContrastBolusIngredient; + typedef gdcm::Attribute<0x0018, 0x1049> ContrastBolusIngredientConcentration; + typedef gdcm::Attribute<0x0018, 0x1050> SpatialResolution; + typedef gdcm::Attribute<0x0018, 0x1060> TriggerTime; + typedef gdcm::Attribute<0x0018, 0x1061> TriggerSourceOrType; + typedef gdcm::Attribute<0x0018, 0x1062> NominalInterval; + typedef gdcm::Attribute<0x0018, 0x1063> FrameTime; + typedef gdcm::Attribute<0x0018, 0x1064> CardiacFramingType; + typedef gdcm::Attribute<0x0018, 0x1065> FrameTimeVector; + typedef gdcm::Attribute<0x0018, 0x1066> FrameDelay; + typedef gdcm::Attribute<0x0018, 0x1067> ImageTriggerDelay; + typedef gdcm::Attribute<0x0018, 0x1068> MultiplexGroupTimeOffset; + typedef gdcm::Attribute<0x0018, 0x1069> TriggerTimeOffset; + typedef gdcm::Attribute<0x0018, 0x106a> SynchronizationTrigger; + typedef gdcm::Attribute<0x0018, 0x106c> SynchronizationChannel; + typedef gdcm::Attribute<0x0018, 0x106e> TriggerSamplePosition; + typedef gdcm::Attribute<0x0018, 0x1070> RadiopharmaceuticalRoute; + typedef gdcm::Attribute<0x0018, 0x1071> RadiopharmaceuticalVolume; + typedef gdcm::Attribute<0x0018, 0x1072> RadiopharmaceuticalStartTime; + typedef gdcm::Attribute<0x0018, 0x1073> RadiopharmaceuticalStopTime; + typedef gdcm::Attribute<0x0018, 0x1074> RadionuclideTotalDose; + typedef gdcm::Attribute<0x0018, 0x1075> RadionuclideHalfLife; + typedef gdcm::Attribute<0x0018, 0x1076> RadionuclidePositronFraction; + typedef gdcm::Attribute<0x0018, 0x1077> RadiopharmaceuticalSpecificActivity; + typedef gdcm::Attribute<0x0018, 0x1078> RadiopharmaceuticalStartDateTime; + typedef gdcm::Attribute<0x0018, 0x1079> RadiopharmaceuticalStopDateTime; + typedef gdcm::Attribute<0x0018, 0x1080> BeatRejectionFlag; + typedef gdcm::Attribute<0x0018, 0x1081> LowRRValue; + typedef gdcm::Attribute<0x0018, 0x1082> HighRRValue; + typedef gdcm::Attribute<0x0018, 0x1083> IntervalsAcquired; + typedef gdcm::Attribute<0x0018, 0x1084> IntervalsRejected; + typedef gdcm::Attribute<0x0018, 0x1085> PVCRejection; + typedef gdcm::Attribute<0x0018, 0x1086> SkipBeats; + typedef gdcm::Attribute<0x0018, 0x1088> HeartRate; + typedef gdcm::Attribute<0x0018, 0x1090> CardiacNumberOfImages; + typedef gdcm::Attribute<0x0018, 0x1094> TriggerWindow; + typedef gdcm::Attribute<0x0018, 0x1100> ReconstructionDiameter; + typedef gdcm::Attribute<0x0018, 0x1110> DistanceSourceToDetector; + typedef gdcm::Attribute<0x0018, 0x1111> DistanceSourceToPatient; + typedef gdcm::Attribute<0x0018, 0x1114> EstimatedRadiographicMagnificationFactor; + typedef gdcm::Attribute<0x0018, 0x1120> GantryDetectorTilt; + typedef gdcm::Attribute<0x0018, 0x1121> GantryDetectorSlew; + typedef gdcm::Attribute<0x0018, 0x1130> TableHeight; + typedef gdcm::Attribute<0x0018, 0x1131> TableTraverse; + typedef gdcm::Attribute<0x0018, 0x1134> TableMotion; + typedef gdcm::Attribute<0x0018, 0x1135> TableVerticalIncrement; + typedef gdcm::Attribute<0x0018, 0x1136> TableLateralIncrement; + typedef gdcm::Attribute<0x0018, 0x1137> TableLongitudinalIncrement; + typedef gdcm::Attribute<0x0018, 0x1138> TableAngle; + typedef gdcm::Attribute<0x0018, 0x113a> TableType; + typedef gdcm::Attribute<0x0018, 0x1140> RotationDirection; + typedef gdcm::Attribute<0x0018, 0x1141> AngularPosition; + typedef gdcm::Attribute<0x0018, 0x1142> RadialPosition; + typedef gdcm::Attribute<0x0018, 0x1143> ScanArc; + typedef gdcm::Attribute<0x0018, 0x1144> AngularStep; + typedef gdcm::Attribute<0x0018, 0x1145> CenterOfRotationOffset; + typedef gdcm::Attribute<0x0018, 0x1146> RotationOffset; + typedef gdcm::Attribute<0x0018, 0x1147> FieldOfViewShape; + typedef gdcm::Attribute<0x0018, 0x1149> FieldOfViewDimensions; + typedef gdcm::Attribute<0x0018, 0x1150> ExposureTime; + typedef gdcm::Attribute<0x0018, 0x1151> XRayTubeCurrent; + typedef gdcm::Attribute<0x0018, 0x1152> Exposure; + typedef gdcm::Attribute<0x0018, 0x1153> ExposureInuAs; + typedef gdcm::Attribute<0x0018, 0x1154> AveragePulseWidth; + typedef gdcm::Attribute<0x0018, 0x1155> RadiationSetting; + typedef gdcm::Attribute<0x0018, 0x1156> RectificationType; + typedef gdcm::Attribute<0x0018, 0x115a> RadiationMode; + typedef gdcm::Attribute<0x0018, 0x115e> ImageAndFluoroscopyAreaDoseProduct; + typedef gdcm::Attribute<0x0018, 0x1160> FilterType; + typedef gdcm::Attribute<0x0018, 0x1161> TypeOfFilters; + typedef gdcm::Attribute<0x0018, 0x1162> IntensifierSize; + typedef gdcm::Attribute<0x0018, 0x1164> ImagerPixelSpacing; + typedef gdcm::Attribute<0x0018, 0x1166> Grid; + typedef gdcm::Attribute<0x0018, 0x1170> GeneratorPower; + typedef gdcm::Attribute<0x0018, 0x1180> CollimatorGridName; + typedef gdcm::Attribute<0x0018, 0x1181> CollimatorType; + typedef gdcm::Attribute<0x0018, 0x1182> FocalDistance; + typedef gdcm::Attribute<0x0018, 0x1183> XFocusCenter; + typedef gdcm::Attribute<0x0018, 0x1184> YFocusCenter; + typedef gdcm::Attribute<0x0018, 0x1190> FocalSpots; + typedef gdcm::Attribute<0x0018, 0x1191> AnodeTargetMaterial; + typedef gdcm::Attribute<0x0018, 0x11a0> BodyPartThickness; + typedef gdcm::Attribute<0x0018, 0x11a2> CompressionForce; + typedef gdcm::Attribute<0x0018, 0x1200> DateOfLastCalibration; + typedef gdcm::Attribute<0x0018, 0x1201> TimeOfLastCalibration; + typedef gdcm::Attribute<0x0018, 0x1210> ConvolutionKernel; + typedef gdcm::Attribute<0x0018, 0x1240> UpperLowerPixelValues; + typedef gdcm::Attribute<0x0018, 0x1242> ActualFrameDuration; + typedef gdcm::Attribute<0x0018, 0x1243> CountRate; + typedef gdcm::Attribute<0x0018, 0x1244> PreferredPlaybackSequencing; + typedef gdcm::Attribute<0x0018, 0x1250> ReceiveCoilName; + typedef gdcm::Attribute<0x0018, 0x1251> TransmitCoilName; + typedef gdcm::Attribute<0x0018, 0x1260> PlateType; + typedef gdcm::Attribute<0x0018, 0x1261> PhosphorType; + typedef gdcm::Attribute<0x0018, 0x1300> ScanVelocity; + typedef gdcm::Attribute<0x0018, 0x1301> WholeBodyTechnique; + typedef gdcm::Attribute<0x0018, 0x1302> ScanLength; + typedef gdcm::Attribute<0x0018, 0x1310> AcquisitionMatrix; + typedef gdcm::Attribute<0x0018, 0x1312> InPlanePhaseEncodingDirection; + typedef gdcm::Attribute<0x0018, 0x1314> FlipAngle; + typedef gdcm::Attribute<0x0018, 0x1315> VariableFlipAngleFlag; + typedef gdcm::Attribute<0x0018, 0x1316> SAR; + typedef gdcm::Attribute<0x0018, 0x1318> dBdt; + typedef gdcm::Attribute<0x0018, 0x1400> AcquisitionDeviceProcessingDescription; + typedef gdcm::Attribute<0x0018, 0x1401> AcquisitionDeviceProcessingCode; + typedef gdcm::Attribute<0x0018, 0x1402> CassetteOrientation; + typedef gdcm::Attribute<0x0018, 0x1403> CassetteSize; + typedef gdcm::Attribute<0x0018, 0x1404> ExposuresOnPlate; + typedef gdcm::Attribute<0x0018, 0x1405> RelativeXRayExposure; + typedef gdcm::Attribute<0x0018, 0x1411> ExposureIndex; + typedef gdcm::Attribute<0x0018, 0x1412> TargetExposureIndex; + typedef gdcm::Attribute<0x0018, 0x1413> DeviationIndex; + typedef gdcm::Attribute<0x0018, 0x1450> ColumnAngulation; + typedef gdcm::Attribute<0x0018, 0x1460> TomoLayerHeight; + typedef gdcm::Attribute<0x0018, 0x1470> TomoAngle; + typedef gdcm::Attribute<0x0018, 0x1480> TomoTime; + typedef gdcm::Attribute<0x0018, 0x1490> TomoType; + typedef gdcm::Attribute<0x0018, 0x1491> TomoClass; + typedef gdcm::Attribute<0x0018, 0x1495> NumberOfTomosynthesisSourceImages; + typedef gdcm::Attribute<0x0018, 0x1500> PositionerMotion; + typedef gdcm::Attribute<0x0018, 0x1508> PositionerType; + typedef gdcm::Attribute<0x0018, 0x1510> PositionerPrimaryAngle; + typedef gdcm::Attribute<0x0018, 0x1511> PositionerSecondaryAngle; + typedef gdcm::Attribute<0x0018, 0x1520> PositionerPrimaryAngleIncrement; + typedef gdcm::Attribute<0x0018, 0x1521> PositionerSecondaryAngleIncrement; + typedef gdcm::Attribute<0x0018, 0x1530> DetectorPrimaryAngle; + typedef gdcm::Attribute<0x0018, 0x1531> DetectorSecondaryAngle; + typedef gdcm::Attribute<0x0018, 0x1600> ShutterShape; + typedef gdcm::Attribute<0x0018, 0x1602> ShutterLeftVerticalEdge; + typedef gdcm::Attribute<0x0018, 0x1604> ShutterRightVerticalEdge; + typedef gdcm::Attribute<0x0018, 0x1606> ShutterUpperHorizontalEdge; + typedef gdcm::Attribute<0x0018, 0x1608> ShutterLowerHorizontalEdge; + typedef gdcm::Attribute<0x0018, 0x1610> CenterOfCircularShutter; + typedef gdcm::Attribute<0x0018, 0x1612> RadiusOfCircularShutter; + typedef gdcm::Attribute<0x0018, 0x1620> VerticesOfThePolygonalShutter; + typedef gdcm::Attribute<0x0018, 0x1622> ShutterPresentationValue; + typedef gdcm::Attribute<0x0018, 0x1623> ShutterOverlayGroup; + typedef gdcm::Attribute<0x0018, 0x1624> ShutterPresentationColorCIELabValue; + typedef gdcm::Attribute<0x0018, 0x1700> CollimatorShape; + typedef gdcm::Attribute<0x0018, 0x1702> CollimatorLeftVerticalEdge; + typedef gdcm::Attribute<0x0018, 0x1704> CollimatorRightVerticalEdge; + typedef gdcm::Attribute<0x0018, 0x1706> CollimatorUpperHorizontalEdge; + typedef gdcm::Attribute<0x0018, 0x1708> CollimatorLowerHorizontalEdge; + typedef gdcm::Attribute<0x0018, 0x1710> CenterOfCircularCollimator; + typedef gdcm::Attribute<0x0018, 0x1712> RadiusOfCircularCollimator; + typedef gdcm::Attribute<0x0018, 0x1720> VerticesOfThePolygonalCollimator; + typedef gdcm::Attribute<0x0018, 0x1800> AcquisitionTimeSynchronized; + typedef gdcm::Attribute<0x0018, 0x1801> TimeSource; + typedef gdcm::Attribute<0x0018, 0x1802> TimeDistributionProtocol; + typedef gdcm::Attribute<0x0018, 0x1803> NTPSourceAddress; + typedef gdcm::Attribute<0x0018, 0x2001> PageNumberVector; + typedef gdcm::Attribute<0x0018, 0x2002> FrameLabelVector; + typedef gdcm::Attribute<0x0018, 0x2003> FramePrimaryAngleVector; + typedef gdcm::Attribute<0x0018, 0x2004> FrameSecondaryAngleVector; + typedef gdcm::Attribute<0x0018, 0x2005> SliceLocationVector; + typedef gdcm::Attribute<0x0018, 0x2006> DisplayWindowLabelVector; + typedef gdcm::Attribute<0x0018, 0x2010> NominalScannedPixelSpacing; + typedef gdcm::Attribute<0x0018, 0x2020> DigitizingDeviceTransportDirection; + typedef gdcm::Attribute<0x0018, 0x2030> RotationOfScannedFilm; + typedef gdcm::Attribute<0x0018, 0x3100> IVUSAcquisition; + typedef gdcm::Attribute<0x0018, 0x3101> IVUSPullbackRate; + typedef gdcm::Attribute<0x0018, 0x3102> IVUSGatedRate; + typedef gdcm::Attribute<0x0018, 0x3103> IVUSPullbackStartFrameNumber; + typedef gdcm::Attribute<0x0018, 0x3104> IVUSPullbackStopFrameNumber; + typedef gdcm::Attribute<0x0018, 0x3105> LesionNumber; + typedef gdcm::Attribute<0x0018, 0x4000> AcquisitionComments; + typedef gdcm::Attribute<0x0018, 0x5000> OutputPower; + typedef gdcm::Attribute<0x0018, 0x5010> TransducerData; + typedef gdcm::Attribute<0x0018, 0x5012> FocusDepth; + typedef gdcm::Attribute<0x0018, 0x5020> ProcessingFunction; + typedef gdcm::Attribute<0x0018, 0x5021> PostprocessingFunction; + typedef gdcm::Attribute<0x0018, 0x5022> MechanicalIndex; + typedef gdcm::Attribute<0x0018, 0x5024> BoneThermalIndex; + typedef gdcm::Attribute<0x0018, 0x5026> CranialThermalIndex; + typedef gdcm::Attribute<0x0018, 0x5027> SoftTissueThermalIndex; + typedef gdcm::Attribute<0x0018, 0x5028> SoftTissueFocusThermalIndex; + typedef gdcm::Attribute<0x0018, 0x5029> SoftTissueSurfaceThermalIndex; + typedef gdcm::Attribute<0x0018, 0x5030> DynamicRange; + typedef gdcm::Attribute<0x0018, 0x5040> TotalGain; + typedef gdcm::Attribute<0x0018, 0x5050> DepthOfScanField; + typedef gdcm::Attribute<0x0018, 0x5100> PatientPosition; + typedef gdcm::Attribute<0x0018, 0x5101> ViewPosition; + typedef gdcm::Attribute<0x0018, 0x5104> ProjectionEponymousNameCodeSequence; + typedef gdcm::Attribute<0x0018, 0x5210> ImageTransformationMatrix; + typedef gdcm::Attribute<0x0018, 0x5212> ImageTranslationVector; + typedef gdcm::Attribute<0x0018, 0x6000> Sensitivity; + typedef gdcm::Attribute<0x0018, 0x6011> SequenceOfUltrasoundRegions; + typedef gdcm::Attribute<0x0018, 0x6012> RegionSpatialFormat; + typedef gdcm::Attribute<0x0018, 0x6014> RegionDataType; + typedef gdcm::Attribute<0x0018, 0x6016> RegionFlags; + typedef gdcm::Attribute<0x0018, 0x6018> RegionLocationMinX0; + typedef gdcm::Attribute<0x0018, 0x601a> RegionLocationMinY0; + typedef gdcm::Attribute<0x0018, 0x601c> RegionLocationMaxX1; + typedef gdcm::Attribute<0x0018, 0x601e> RegionLocationMaxY1; + typedef gdcm::Attribute<0x0018, 0x6020> ReferencePixelX0; + typedef gdcm::Attribute<0x0018, 0x6022> ReferencePixelY0; + typedef gdcm::Attribute<0x0018, 0x6024> PhysicalUnitsXDirection; + typedef gdcm::Attribute<0x0018, 0x6026> PhysicalUnitsYDirection; + typedef gdcm::Attribute<0x0018, 0x6028> ReferencePixelPhysicalValueX; + typedef gdcm::Attribute<0x0018, 0x602a> ReferencePixelPhysicalValueY; + typedef gdcm::Attribute<0x0018, 0x602c> PhysicalDeltaX; + typedef gdcm::Attribute<0x0018, 0x602e> PhysicalDeltaY; + typedef gdcm::Attribute<0x0018, 0x6030> TransducerFrequency; + typedef gdcm::Attribute<0x0018, 0x6031> TransducerType; + typedef gdcm::Attribute<0x0018, 0x6032> PulseRepetitionFrequency; + typedef gdcm::Attribute<0x0018, 0x6034> DopplerCorrectionAngle; + typedef gdcm::Attribute<0x0018, 0x6036> SteeringAngle; + typedef gdcm::Attribute<0x0018, 0x6038> DopplerSampleVolumeXPositionRetired; + typedef gdcm::Attribute<0x0018, 0x6039> DopplerSampleVolumeXPosition; + typedef gdcm::Attribute<0x0018, 0x603a> DopplerSampleVolumeYPositionRetired; + typedef gdcm::Attribute<0x0018, 0x603b> DopplerSampleVolumeYPosition; + typedef gdcm::Attribute<0x0018, 0x603c> TMLinePositionX0Retired; + typedef gdcm::Attribute<0x0018, 0x603d> TMLinePositionX0; + typedef gdcm::Attribute<0x0018, 0x603e> TMLinePositionY0Retired; + typedef gdcm::Attribute<0x0018, 0x603f> TMLinePositionY0; + typedef gdcm::Attribute<0x0018, 0x6040> TMLinePositionX1Retired; + typedef gdcm::Attribute<0x0018, 0x6041> TMLinePositionX1; + typedef gdcm::Attribute<0x0018, 0x6042> TMLinePositionY1Retired; + typedef gdcm::Attribute<0x0018, 0x6043> TMLinePositionY1; + typedef gdcm::Attribute<0x0018, 0x6044> PixelComponentOrganization; + typedef gdcm::Attribute<0x0018, 0x6046> PixelComponentMask; + typedef gdcm::Attribute<0x0018, 0x6048> PixelComponentRangeStart; + typedef gdcm::Attribute<0x0018, 0x604a> PixelComponentRangeStop; + typedef gdcm::Attribute<0x0018, 0x604c> PixelComponentPhysicalUnits; + typedef gdcm::Attribute<0x0018, 0x604e> PixelComponentDataType; + typedef gdcm::Attribute<0x0018, 0x6050> NumberOfTableBreakPoints; + typedef gdcm::Attribute<0x0018, 0x6052> TableOfXBreakPoints; + typedef gdcm::Attribute<0x0018, 0x6054> TableOfYBreakPoints; + typedef gdcm::Attribute<0x0018, 0x6056> NumberOfTableEntries; + typedef gdcm::Attribute<0x0018, 0x6058> TableOfPixelValues; + typedef gdcm::Attribute<0x0018, 0x605a> TableOfParameterValues; + typedef gdcm::Attribute<0x0018, 0x6060> RWaveTimeVector; + typedef gdcm::Attribute<0x0018, 0x7000> DetectorConditionsNominalFlag; + typedef gdcm::Attribute<0x0018, 0x7001> DetectorTemperature; + typedef gdcm::Attribute<0x0018, 0x7004> DetectorType; + typedef gdcm::Attribute<0x0018, 0x7005> DetectorConfiguration; + typedef gdcm::Attribute<0x0018, 0x7006> DetectorDescription; + typedef gdcm::Attribute<0x0018, 0x7008> DetectorMode; + typedef gdcm::Attribute<0x0018, 0x700a> DetectorID; + typedef gdcm::Attribute<0x0018, 0x700c> DateOfLastDetectorCalibration; + typedef gdcm::Attribute<0x0018, 0x700e> TimeOfLastDetectorCalibration; + typedef gdcm::Attribute<0x0018, 0x7010> ExposuresOnDetectorSinceLastCalibration; + typedef gdcm::Attribute<0x0018, 0x7011> ExposuresOnDetectorSinceManufactured; + typedef gdcm::Attribute<0x0018, 0x7012> DetectorTimeSinceLastExposure; + typedef gdcm::Attribute<0x0018, 0x7014> DetectorActiveTime; + typedef gdcm::Attribute<0x0018, 0x7016> DetectorActivationOffsetFromExposure; + typedef gdcm::Attribute<0x0018, 0x701a> DetectorBinning; + typedef gdcm::Attribute<0x0018, 0x7020> DetectorElementPhysicalSize; + typedef gdcm::Attribute<0x0018, 0x7022> DetectorElementSpacing; + typedef gdcm::Attribute<0x0018, 0x7024> DetectorActiveShape; + typedef gdcm::Attribute<0x0018, 0x7026> DetectorActiveDimensions; + typedef gdcm::Attribute<0x0018, 0x7028> DetectorActiveOrigin; + typedef gdcm::Attribute<0x0018, 0x702a> DetectorManufacturerName; + typedef gdcm::Attribute<0x0018, 0x702b> DetectorManufacturerModelName; + typedef gdcm::Attribute<0x0018, 0x7030> FieldOfViewOrigin; + typedef gdcm::Attribute<0x0018, 0x7032> FieldOfViewRotation; + typedef gdcm::Attribute<0x0018, 0x7034> FieldOfViewHorizontalFlip; + typedef gdcm::Attribute<0x0018, 0x7036> PixelDataAreaOriginRelativeToFOV; + typedef gdcm::Attribute<0x0018, 0x7038> PixelDataAreaRotationAngleRelativeToFOV; + typedef gdcm::Attribute<0x0018, 0x7040> GridAbsorbingMaterial; + typedef gdcm::Attribute<0x0018, 0x7041> GridSpacingMaterial; + typedef gdcm::Attribute<0x0018, 0x7042> GridThickness; + typedef gdcm::Attribute<0x0018, 0x7044> GridPitch; + typedef gdcm::Attribute<0x0018, 0x7046> GridAspectRatio; + typedef gdcm::Attribute<0x0018, 0x7048> GridPeriod; + typedef gdcm::Attribute<0x0018, 0x704c> GridFocalDistance; + typedef gdcm::Attribute<0x0018, 0x7050> FilterMaterial; + typedef gdcm::Attribute<0x0018, 0x7052> FilterThicknessMinimum; + typedef gdcm::Attribute<0x0018, 0x7054> FilterThicknessMaximum; + typedef gdcm::Attribute<0x0018, 0x7056> FilterBeamPathLengthMinimum; + typedef gdcm::Attribute<0x0018, 0x7058> FilterBeamPathLengthMaximum; + typedef gdcm::Attribute<0x0018, 0x7060> ExposureControlMode; + typedef gdcm::Attribute<0x0018, 0x7062> ExposureControlModeDescription; + typedef gdcm::Attribute<0x0018, 0x7064> ExposureStatus; + typedef gdcm::Attribute<0x0018, 0x7065> PhototimerSetting; + typedef gdcm::Attribute<0x0018, 0x8150> ExposureTimeInuS; + typedef gdcm::Attribute<0x0018, 0x8151> XRayTubeCurrentInuA; + typedef gdcm::Attribute<0x0018, 0x9004> ContentQualification; + typedef gdcm::Attribute<0x0018, 0x9005> PulseSequenceName; + typedef gdcm::Attribute<0x0018, 0x9006> MRImagingModifierSequence; + typedef gdcm::Attribute<0x0018, 0x9008> EchoPulseSequence; + typedef gdcm::Attribute<0x0018, 0x9009> InversionRecovery; + typedef gdcm::Attribute<0x0018, 0x9010> FlowCompensation; + typedef gdcm::Attribute<0x0018, 0x9011> MultipleSpinEcho; + typedef gdcm::Attribute<0x0018, 0x9012> MultiPlanarExcitation; + typedef gdcm::Attribute<0x0018, 0x9014> PhaseContrast; + typedef gdcm::Attribute<0x0018, 0x9015> TimeOfFlightContrast; + typedef gdcm::Attribute<0x0018, 0x9016> Spoiling; + typedef gdcm::Attribute<0x0018, 0x9017> SteadyStatePulseSequence; + typedef gdcm::Attribute<0x0018, 0x9018> EchoPlanarPulseSequence; + typedef gdcm::Attribute<0x0018, 0x9019> TagAngleFirstAxis; + typedef gdcm::Attribute<0x0018, 0x9020> MagnetizationTransfer; + typedef gdcm::Attribute<0x0018, 0x9021> T2Preparation; + typedef gdcm::Attribute<0x0018, 0x9022> BloodSignalNulling; + typedef gdcm::Attribute<0x0018, 0x9024> SaturationRecovery; + typedef gdcm::Attribute<0x0018, 0x9025> SpectrallySelectedSuppression; + typedef gdcm::Attribute<0x0018, 0x9026> SpectrallySelectedExcitation; + typedef gdcm::Attribute<0x0018, 0x9027> SpatialPresaturation; + typedef gdcm::Attribute<0x0018, 0x9028> Tagging; + typedef gdcm::Attribute<0x0018, 0x9029> OversamplingPhase; + typedef gdcm::Attribute<0x0018, 0x9030> TagSpacingFirstDimension; + typedef gdcm::Attribute<0x0018, 0x9032> GeometryOfKSpaceTraversal; + typedef gdcm::Attribute<0x0018, 0x9033> SegmentedKSpaceTraversal; + typedef gdcm::Attribute<0x0018, 0x9034> RectilinearPhaseEncodeReordering; + typedef gdcm::Attribute<0x0018, 0x9035> TagThickness; + typedef gdcm::Attribute<0x0018, 0x9036> PartialFourierDirection; + typedef gdcm::Attribute<0x0018, 0x9037> CardiacSynchronizationTechnique; + typedef gdcm::Attribute<0x0018, 0x9041> ReceiveCoilManufacturerName; + typedef gdcm::Attribute<0x0018, 0x9042> MRReceiveCoilSequence; + typedef gdcm::Attribute<0x0018, 0x9043> ReceiveCoilType; + typedef gdcm::Attribute<0x0018, 0x9044> QuadratureReceiveCoil; + typedef gdcm::Attribute<0x0018, 0x9045> MultiCoilDefinitionSequence; + typedef gdcm::Attribute<0x0018, 0x9046> MultiCoilConfiguration; + typedef gdcm::Attribute<0x0018, 0x9047> MultiCoilElementName; + typedef gdcm::Attribute<0x0018, 0x9048> MultiCoilElementUsed; + typedef gdcm::Attribute<0x0018, 0x9049> MRTransmitCoilSequence; + typedef gdcm::Attribute<0x0018, 0x9050> TransmitCoilManufacturerName; + typedef gdcm::Attribute<0x0018, 0x9051> TransmitCoilType; + typedef gdcm::Attribute<0x0018, 0x9052> SpectralWidth; + typedef gdcm::Attribute<0x0018, 0x9053> ChemicalShiftReference; + typedef gdcm::Attribute<0x0018, 0x9054> VolumeLocalizationTechnique; + typedef gdcm::Attribute<0x0018, 0x9058> MRAcquisitionFrequencyEncodingSteps; + typedef gdcm::Attribute<0x0018, 0x9059> Decoupling; + typedef gdcm::Attribute<0x0018, 0x9060> DecoupledNucleus; + typedef gdcm::Attribute<0x0018, 0x9061> DecouplingFrequency; + typedef gdcm::Attribute<0x0018, 0x9062> DecouplingMethod; + typedef gdcm::Attribute<0x0018, 0x9063> DecouplingChemicalShiftReference; + typedef gdcm::Attribute<0x0018, 0x9064> KSpaceFiltering; + typedef gdcm::Attribute<0x0018, 0x9065> TimeDomainFiltering; + typedef gdcm::Attribute<0x0018, 0x9066> NumberOfZeroFills; + typedef gdcm::Attribute<0x0018, 0x9067> BaselineCorrection; + typedef gdcm::Attribute<0x0018, 0x9069> ParallelReductionFactorInPlane; + typedef gdcm::Attribute<0x0018, 0x9070> CardiacRRIntervalSpecified; + typedef gdcm::Attribute<0x0018, 0x9073> AcquisitionDuration; + typedef gdcm::Attribute<0x0018, 0x9074> FrameAcquisitionDateTime; + typedef gdcm::Attribute<0x0018, 0x9075> DiffusionDirectionality; + typedef gdcm::Attribute<0x0018, 0x9076> DiffusionGradientDirectionSequence; + typedef gdcm::Attribute<0x0018, 0x9077> ParallelAcquisition; + typedef gdcm::Attribute<0x0018, 0x9078> ParallelAcquisitionTechnique; + typedef gdcm::Attribute<0x0018, 0x9079> InversionTimes; + typedef gdcm::Attribute<0x0018, 0x9080> MetaboliteMapDescription; + typedef gdcm::Attribute<0x0018, 0x9081> PartialFourier; + typedef gdcm::Attribute<0x0018, 0x9082> EffectiveEchoTime; + typedef gdcm::Attribute<0x0018, 0x9083> MetaboliteMapCodeSequence; + typedef gdcm::Attribute<0x0018, 0x9084> ChemicalShiftSequence; + typedef gdcm::Attribute<0x0018, 0x9085> CardiacSignalSource; + typedef gdcm::Attribute<0x0018, 0x9087> DiffusionBValue; + typedef gdcm::Attribute<0x0018, 0x9089> DiffusionGradientOrientation; + typedef gdcm::Attribute<0x0018, 0x9090> VelocityEncodingDirection; + typedef gdcm::Attribute<0x0018, 0x9091> VelocityEncodingMinimumValue; + typedef gdcm::Attribute<0x0018, 0x9092> VelocityEncodingAcquisitionSequence; + typedef gdcm::Attribute<0x0018, 0x9093> NumberOfKSpaceTrajectories; + typedef gdcm::Attribute<0x0018, 0x9094> CoverageOfKSpace; + typedef gdcm::Attribute<0x0018, 0x9095> SpectroscopyAcquisitionPhaseRows; + typedef gdcm::Attribute<0x0018, 0x9096> ParallelReductionFactorInPlaneRetired; + typedef gdcm::Attribute<0x0018, 0x9098> TransmitterFrequency; + typedef gdcm::Attribute<0x0018, 0x9100> ResonantNucleus; + typedef gdcm::Attribute<0x0018, 0x9101> FrequencyCorrection; + typedef gdcm::Attribute<0x0018, 0x9103> MRSpectroscopyFOVGeometrySequence; + typedef gdcm::Attribute<0x0018, 0x9104> SlabThickness; + typedef gdcm::Attribute<0x0018, 0x9105> SlabOrientation; + typedef gdcm::Attribute<0x0018, 0x9106> MidSlabPosition; + typedef gdcm::Attribute<0x0018, 0x9107> MRSpatialSaturationSequence; + typedef gdcm::Attribute<0x0018, 0x9112> MRTimingAndRelatedParametersSequence; + typedef gdcm::Attribute<0x0018, 0x9114> MREchoSequence; + typedef gdcm::Attribute<0x0018, 0x9115> MRModifierSequence; + typedef gdcm::Attribute<0x0018, 0x9117> MRDiffusionSequence; + typedef gdcm::Attribute<0x0018, 0x9118> CardiacSynchronizationSequence; + typedef gdcm::Attribute<0x0018, 0x9119> MRAveragesSequence; + typedef gdcm::Attribute<0x0018, 0x9125> MRFOVGeometrySequence; + typedef gdcm::Attribute<0x0018, 0x9126> VolumeLocalizationSequence; + typedef gdcm::Attribute<0x0018, 0x9127> SpectroscopyAcquisitionDataColumns; + typedef gdcm::Attribute<0x0018, 0x9147> DiffusionAnisotropyType; + typedef gdcm::Attribute<0x0018, 0x9151> FrameReferenceDateTime; + typedef gdcm::Attribute<0x0018, 0x9152> MRMetaboliteMapSequence; + typedef gdcm::Attribute<0x0018, 0x9155> ParallelReductionFactorOutOfPlane; + typedef gdcm::Attribute<0x0018, 0x9159> SpectroscopyAcquisitionOutOfPlanePhaseSteps; + typedef gdcm::Attribute<0x0018, 0x9166> BulkMotionStatus; + typedef gdcm::Attribute<0x0018, 0x9168> ParallelReductionFactorSecondInPlane; + typedef gdcm::Attribute<0x0018, 0x9169> CardiacBeatRejectionTechnique; + typedef gdcm::Attribute<0x0018, 0x9170> RespiratoryMotionCompensationTechnique; + typedef gdcm::Attribute<0x0018, 0x9171> RespiratorySignalSource; + typedef gdcm::Attribute<0x0018, 0x9172> BulkMotionCompensationTechnique; + typedef gdcm::Attribute<0x0018, 0x9173> BulkMotionSignalSource; + typedef gdcm::Attribute<0x0018, 0x9174> ApplicableSafetyStandardAgency; + typedef gdcm::Attribute<0x0018, 0x9175> ApplicableSafetyStandardDescription; + typedef gdcm::Attribute<0x0018, 0x9176> OperatingModeSequence; + typedef gdcm::Attribute<0x0018, 0x9177> OperatingModeType; + typedef gdcm::Attribute<0x0018, 0x9178> OperatingMode; + typedef gdcm::Attribute<0x0018, 0x9179> SpecificAbsorptionRateDefinition; + typedef gdcm::Attribute<0x0018, 0x9180> GradientOutputType; + typedef gdcm::Attribute<0x0018, 0x9181> SpecificAbsorptionRateValue; + typedef gdcm::Attribute<0x0018, 0x9182> GradientOutput; + typedef gdcm::Attribute<0x0018, 0x9183> FlowCompensationDirection; + typedef gdcm::Attribute<0x0018, 0x9184> TaggingDelay; + typedef gdcm::Attribute<0x0018, 0x9185> RespiratoryMotionCompensationTechniqueDescription; + typedef gdcm::Attribute<0x0018, 0x9186> RespiratorySignalSourceID; + typedef gdcm::Attribute<0x0018, 0x9195> ChemicalShiftMinimumIntegrationLimitInHz; + typedef gdcm::Attribute<0x0018, 0x9196> ChemicalShiftMaximumIntegrationLimitInHz; + typedef gdcm::Attribute<0x0018, 0x9197> MRVelocityEncodingSequence; + typedef gdcm::Attribute<0x0018, 0x9198> FirstOrderPhaseCorrection; + typedef gdcm::Attribute<0x0018, 0x9199> WaterReferencedPhaseCorrection; + typedef gdcm::Attribute<0x0018, 0x9200> MRSpectroscopyAcquisitionType; + typedef gdcm::Attribute<0x0018, 0x9214> RespiratoryCyclePosition; + typedef gdcm::Attribute<0x0018, 0x9217> VelocityEncodingMaximumValue; + typedef gdcm::Attribute<0x0018, 0x9218> TagSpacingSecondDimension; + typedef gdcm::Attribute<0x0018, 0x9219> TagAngleSecondAxis; + typedef gdcm::Attribute<0x0018, 0x9220> FrameAcquisitionDuration; + typedef gdcm::Attribute<0x0018, 0x9226> MRImageFrameTypeSequence; + typedef gdcm::Attribute<0x0018, 0x9227> MRSpectroscopyFrameTypeSequence; + typedef gdcm::Attribute<0x0018, 0x9231> MRAcquisitionPhaseEncodingStepsInPlane; + typedef gdcm::Attribute<0x0018, 0x9232> MRAcquisitionPhaseEncodingStepsOutOfPlane; + typedef gdcm::Attribute<0x0018, 0x9234> SpectroscopyAcquisitionPhaseColumns; + typedef gdcm::Attribute<0x0018, 0x9236> CardiacCyclePosition; + typedef gdcm::Attribute<0x0018, 0x9239> SpecificAbsorptionRateSequence; + typedef gdcm::Attribute<0x0018, 0x9240> RFEchoTrainLength; + typedef gdcm::Attribute<0x0018, 0x9241> GradientEchoTrainLength; + typedef gdcm::Attribute<0x0018, 0x9250> ArterialSpinLabelingContrast; + typedef gdcm::Attribute<0x0018, 0x9251> MRArterialSpinLabelingSequence; + typedef gdcm::Attribute<0x0018, 0x9252> ASLTechniqueDescription; + typedef gdcm::Attribute<0x0018, 0x9253> ASLSlabNumber; + typedef gdcm::Attribute<0x0018, 0x9254> ASLSlabThickness; + typedef gdcm::Attribute<0x0018, 0x9255> ASLSlabOrientation; + typedef gdcm::Attribute<0x0018, 0x9256> ASLMidSlabPosition; + typedef gdcm::Attribute<0x0018, 0x9257> ASLContext; + typedef gdcm::Attribute<0x0018, 0x9258> ASLPulseTrainDuration; + typedef gdcm::Attribute<0x0018, 0x9259> ASLCrusherFlag; + typedef gdcm::Attribute<0x0018, 0x925a> ASLCrusherFlow; + typedef gdcm::Attribute<0x0018, 0x925b> ASLCrusherDescription; + typedef gdcm::Attribute<0x0018, 0x925c> ASLBolusCutoffFlag; + typedef gdcm::Attribute<0x0018, 0x925d> ASLBolusCutoffTimingSequence; + typedef gdcm::Attribute<0x0018, 0x925e> ASLBolusCutoffTechnique; + typedef gdcm::Attribute<0x0018, 0x925f> ASLBolusCutoffDelayTime; + typedef gdcm::Attribute<0x0018, 0x9260> ASLSlabSequence; + typedef gdcm::Attribute<0x0018, 0x9295> ChemicalShiftMinimumIntegrationLimitInppm; + typedef gdcm::Attribute<0x0018, 0x9296> ChemicalShiftMaximumIntegrationLimitInppm; + typedef gdcm::Attribute<0x0018, 0x9301> CTAcquisitionTypeSequence; + typedef gdcm::Attribute<0x0018, 0x9302> AcquisitionType; + typedef gdcm::Attribute<0x0018, 0x9303> TubeAngle; + typedef gdcm::Attribute<0x0018, 0x9304> CTAcquisitionDetailsSequence; + typedef gdcm::Attribute<0x0018, 0x9305> RevolutionTime; + typedef gdcm::Attribute<0x0018, 0x9306> SingleCollimationWidth; + typedef gdcm::Attribute<0x0018, 0x9307> TotalCollimationWidth; + typedef gdcm::Attribute<0x0018, 0x9308> CTTableDynamicsSequence; + typedef gdcm::Attribute<0x0018, 0x9309> TableSpeed; + typedef gdcm::Attribute<0x0018, 0x9310> TableFeedPerRotation; + typedef gdcm::Attribute<0x0018, 0x9311> SpiralPitchFactor; + typedef gdcm::Attribute<0x0018, 0x9312> CTGeometrySequence; + typedef gdcm::Attribute<0x0018, 0x9313> DataCollectionCenterPatient; + typedef gdcm::Attribute<0x0018, 0x9314> CTReconstructionSequence; + typedef gdcm::Attribute<0x0018, 0x9315> ReconstructionAlgorithm; + typedef gdcm::Attribute<0x0018, 0x9316> ConvolutionKernelGroup; + typedef gdcm::Attribute<0x0018, 0x9317> ReconstructionFieldOfView; + typedef gdcm::Attribute<0x0018, 0x9318> ReconstructionTargetCenterPatient; + typedef gdcm::Attribute<0x0018, 0x9319> ReconstructionAngle; + typedef gdcm::Attribute<0x0018, 0x9320> ImageFilter; + typedef gdcm::Attribute<0x0018, 0x9321> CTExposureSequence; + typedef gdcm::Attribute<0x0018, 0x9322> ReconstructionPixelSpacing; + typedef gdcm::Attribute<0x0018, 0x9323> ExposureModulationType; + typedef gdcm::Attribute<0x0018, 0x9324> EstimatedDoseSaving; + typedef gdcm::Attribute<0x0018, 0x9325> CTXRayDetailsSequence; + typedef gdcm::Attribute<0x0018, 0x9326> CTPositionSequence; + typedef gdcm::Attribute<0x0018, 0x9327> TablePosition; + typedef gdcm::Attribute<0x0018, 0x9328> ExposureTimeInms; + typedef gdcm::Attribute<0x0018, 0x9329> CTImageFrameTypeSequence; + typedef gdcm::Attribute<0x0018, 0x9330> XRayTubeCurrentInmA; + typedef gdcm::Attribute<0x0018, 0x9332> ExposureInmAs; + typedef gdcm::Attribute<0x0018, 0x9333> ConstantVolumeFlag; + typedef gdcm::Attribute<0x0018, 0x9334> FluoroscopyFlag; + typedef gdcm::Attribute<0x0018, 0x9335> DistanceSourceToDataCollectionCenter; + typedef gdcm::Attribute<0x0018, 0x9337> ContrastBolusAgentNumber; + typedef gdcm::Attribute<0x0018, 0x9338> ContrastBolusIngredientCodeSequence; + typedef gdcm::Attribute<0x0018, 0x9340> ContrastAdministrationProfileSequence; + typedef gdcm::Attribute<0x0018, 0x9341> ContrastBolusUsageSequence; + typedef gdcm::Attribute<0x0018, 0x9342> ContrastBolusAgentAdministered; + typedef gdcm::Attribute<0x0018, 0x9343> ContrastBolusAgentDetected; + typedef gdcm::Attribute<0x0018, 0x9344> ContrastBolusAgentPhase; + typedef gdcm::Attribute<0x0018, 0x9345> CTDIvol; + typedef gdcm::Attribute<0x0018, 0x9346> CTDIPhantomTypeCodeSequence; + typedef gdcm::Attribute<0x0018, 0x9351> CalciumScoringMassFactorPatient; + typedef gdcm::Attribute<0x0018, 0x9352> CalciumScoringMassFactorDevice; + typedef gdcm::Attribute<0x0018, 0x9353> EnergyWeightingFactor; + typedef gdcm::Attribute<0x0018, 0x9360> CTAdditionalXRaySourceSequence; + typedef gdcm::Attribute<0x0018, 0x9401> ProjectionPixelCalibrationSequence; + typedef gdcm::Attribute<0x0018, 0x9402> DistanceSourceToIsocenter; + typedef gdcm::Attribute<0x0018, 0x9403> DistanceObjectToTableTop; + typedef gdcm::Attribute<0x0018, 0x9404> ObjectPixelSpacingInCenterOfBeam; + typedef gdcm::Attribute<0x0018, 0x9405> PositionerPositionSequence; + typedef gdcm::Attribute<0x0018, 0x9406> TablePositionSequence; + typedef gdcm::Attribute<0x0018, 0x9407> CollimatorShapeSequence; + typedef gdcm::Attribute<0x0018, 0x9410> PlanesInAcquisition; + typedef gdcm::Attribute<0x0018, 0x9412> XAXRFFrameCharacteristicsSequence; + typedef gdcm::Attribute<0x0018, 0x9417> FrameAcquisitionSequence; + typedef gdcm::Attribute<0x0018, 0x9420> XRayReceptorType; + typedef gdcm::Attribute<0x0018, 0x9423> AcquisitionProtocolName; + typedef gdcm::Attribute<0x0018, 0x9424> AcquisitionProtocolDescription; + typedef gdcm::Attribute<0x0018, 0x9425> ContrastBolusIngredientOpaque; + typedef gdcm::Attribute<0x0018, 0x9426> DistanceReceptorPlaneToDetectorHousing; + typedef gdcm::Attribute<0x0018, 0x9427> IntensifierActiveShape; + typedef gdcm::Attribute<0x0018, 0x9428> IntensifierActiveDimensions; + typedef gdcm::Attribute<0x0018, 0x9429> PhysicalDetectorSize; + typedef gdcm::Attribute<0x0018, 0x9430> PositionOfIsocenterProjection; + typedef gdcm::Attribute<0x0018, 0x9432> FieldOfViewSequence; + typedef gdcm::Attribute<0x0018, 0x9433> FieldOfViewDescription; + typedef gdcm::Attribute<0x0018, 0x9434> ExposureControlSensingRegionsSequence; + typedef gdcm::Attribute<0x0018, 0x9435> ExposureControlSensingRegionShape; + typedef gdcm::Attribute<0x0018, 0x9436> ExposureControlSensingRegionLeftVerticalEdge; + typedef gdcm::Attribute<0x0018, 0x9437> ExposureControlSensingRegionRightVerticalEdge; + typedef gdcm::Attribute<0x0018, 0x9438> ExposureControlSensingRegionUpperHorizontalEdge; + typedef gdcm::Attribute<0x0018, 0x9439> ExposureControlSensingRegionLowerHorizontalEdge; + typedef gdcm::Attribute<0x0018, 0x9440> CenterOfCircularExposureControlSensingRegion; + typedef gdcm::Attribute<0x0018, 0x9441> RadiusOfCircularExposureControlSensingRegion; + typedef gdcm::Attribute<0x0018, 0x9442> VerticesOfThePolygonalExposureControlSensingRegion; + // 0x0018, 0x9445 SHALL NOT BE USED + typedef gdcm::Attribute<0x0018, 0x9447> ColumnAngulationPatient; + typedef gdcm::Attribute<0x0018, 0x9449> BeamAngle; + typedef gdcm::Attribute<0x0018, 0x9451> FrameDetectorParametersSequence; + typedef gdcm::Attribute<0x0018, 0x9452> CalculatedAnatomyThickness; + typedef gdcm::Attribute<0x0018, 0x9455> CalibrationSequence; + typedef gdcm::Attribute<0x0018, 0x9456> ObjectThicknessSequence; + typedef gdcm::Attribute<0x0018, 0x9457> PlaneIdentification; + typedef gdcm::Attribute<0x0018, 0x9461> FieldOfViewDimensionsInFloat; + typedef gdcm::Attribute<0x0018, 0x9462> IsocenterReferenceSystemSequence; + typedef gdcm::Attribute<0x0018, 0x9463> PositionerIsocenterPrimaryAngle; + typedef gdcm::Attribute<0x0018, 0x9464> PositionerIsocenterSecondaryAngle; + typedef gdcm::Attribute<0x0018, 0x9465> PositionerIsocenterDetectorRotationAngle; + typedef gdcm::Attribute<0x0018, 0x9466> TableXPositionToIsocenter; + typedef gdcm::Attribute<0x0018, 0x9467> TableYPositionToIsocenter; + typedef gdcm::Attribute<0x0018, 0x9468> TableZPositionToIsocenter; + typedef gdcm::Attribute<0x0018, 0x9469> TableHorizontalRotationAngle; + typedef gdcm::Attribute<0x0018, 0x9470> TableHeadTiltAngle; + typedef gdcm::Attribute<0x0018, 0x9471> TableCradleTiltAngle; + typedef gdcm::Attribute<0x0018, 0x9472> FrameDisplayShutterSequence; + typedef gdcm::Attribute<0x0018, 0x9473> AcquiredImageAreaDoseProduct; + typedef gdcm::Attribute<0x0018, 0x9474> CArmPositionerTabletopRelationship; + typedef gdcm::Attribute<0x0018, 0x9476> XRayGeometrySequence; + typedef gdcm::Attribute<0x0018, 0x9477> IrradiationEventIdentificationSequence; + typedef gdcm::Attribute<0x0018, 0x9504> XRay3DFrameTypeSequence; + typedef gdcm::Attribute<0x0018, 0x9506> ContributingSourcesSequence; + typedef gdcm::Attribute<0x0018, 0x9507> XRay3DAcquisitionSequence; + typedef gdcm::Attribute<0x0018, 0x9508> PrimaryPositionerScanArc; + typedef gdcm::Attribute<0x0018, 0x9509> SecondaryPositionerScanArc; + typedef gdcm::Attribute<0x0018, 0x9510> PrimaryPositionerScanStartAngle; + typedef gdcm::Attribute<0x0018, 0x9511> SecondaryPositionerScanStartAngle; + typedef gdcm::Attribute<0x0018, 0x9514> PrimaryPositionerIncrement; + typedef gdcm::Attribute<0x0018, 0x9515> SecondaryPositionerIncrement; + typedef gdcm::Attribute<0x0018, 0x9516> StartAcquisitionDateTime; + typedef gdcm::Attribute<0x0018, 0x9517> EndAcquisitionDateTime; + typedef gdcm::Attribute<0x0018, 0x9524> ApplicationName; + typedef gdcm::Attribute<0x0018, 0x9525> ApplicationVersion; + typedef gdcm::Attribute<0x0018, 0x9526> ApplicationManufacturer; + typedef gdcm::Attribute<0x0018, 0x9527> AlgorithmType; + typedef gdcm::Attribute<0x0018, 0x9528> AlgorithmDescription; + typedef gdcm::Attribute<0x0018, 0x9530> XRay3DReconstructionSequence; + typedef gdcm::Attribute<0x0018, 0x9531> ReconstructionDescription; + typedef gdcm::Attribute<0x0018, 0x9538> PerProjectionAcquisitionSequence; + typedef gdcm::Attribute<0x0018, 0x9601> DiffusionBMatrixSequence; + typedef gdcm::Attribute<0x0018, 0x9602> DiffusionBValueXX; + typedef gdcm::Attribute<0x0018, 0x9603> DiffusionBValueXY; + typedef gdcm::Attribute<0x0018, 0x9604> DiffusionBValueXZ; + typedef gdcm::Attribute<0x0018, 0x9605> DiffusionBValueYY; + typedef gdcm::Attribute<0x0018, 0x9606> DiffusionBValueYZ; + typedef gdcm::Attribute<0x0018, 0x9607> DiffusionBValueZZ; + typedef gdcm::Attribute<0x0018, 0x9701> DecayCorrectionDateTime; + typedef gdcm::Attribute<0x0018, 0x9715> StartDensityThreshold; + typedef gdcm::Attribute<0x0018, 0x9716> StartRelativeDensityDifferenceThreshold; + typedef gdcm::Attribute<0x0018, 0x9717> StartCardiacTriggerCountThreshold; + typedef gdcm::Attribute<0x0018, 0x9718> StartRespiratoryTriggerCountThreshold; + typedef gdcm::Attribute<0x0018, 0x9719> TerminationCountsThreshold; + typedef gdcm::Attribute<0x0018, 0x9720> TerminationDensityThreshold; + typedef gdcm::Attribute<0x0018, 0x9721> TerminationRelativeDensityThreshold; + typedef gdcm::Attribute<0x0018, 0x9722> TerminationTimeThreshold; + typedef gdcm::Attribute<0x0018, 0x9723> TerminationCardiacTriggerCountThreshold; + typedef gdcm::Attribute<0x0018, 0x9724> TerminationRespiratoryTriggerCountThreshold; + typedef gdcm::Attribute<0x0018, 0x9725> DetectorGeometry; + typedef gdcm::Attribute<0x0018, 0x9726> TransverseDetectorSeparation; + typedef gdcm::Attribute<0x0018, 0x9727> AxialDetectorDimension; + typedef gdcm::Attribute<0x0018, 0x9729> RadiopharmaceuticalAgentNumber; + typedef gdcm::Attribute<0x0018, 0x9732> PETFrameAcquisitionSequence; + typedef gdcm::Attribute<0x0018, 0x9733> PETDetectorMotionDetailsSequence; + typedef gdcm::Attribute<0x0018, 0x9734> PETTableDynamicsSequence; + typedef gdcm::Attribute<0x0018, 0x9735> PETPositionSequence; + typedef gdcm::Attribute<0x0018, 0x9736> PETFrameCorrectionFactorsSequence; + typedef gdcm::Attribute<0x0018, 0x9737> RadiopharmaceuticalUsageSequence; + typedef gdcm::Attribute<0x0018, 0x9738> AttenuationCorrectionSource; + typedef gdcm::Attribute<0x0018, 0x9739> NumberOfIterations; + typedef gdcm::Attribute<0x0018, 0x9740> NumberOfSubsets; + typedef gdcm::Attribute<0x0018, 0x9749> PETReconstructionSequence; + typedef gdcm::Attribute<0x0018, 0x9751> PETFrameTypeSequence; + typedef gdcm::Attribute<0x0018, 0x9755> TimeOfFlightInformationUsed; + typedef gdcm::Attribute<0x0018, 0x9756> ReconstructionType; + typedef gdcm::Attribute<0x0018, 0x9758> DecayCorrected; + typedef gdcm::Attribute<0x0018, 0x9759> AttenuationCorrected; + typedef gdcm::Attribute<0x0018, 0x9760> ScatterCorrected; + typedef gdcm::Attribute<0x0018, 0x9761> DeadTimeCorrected; + typedef gdcm::Attribute<0x0018, 0x9762> GantryMotionCorrected; + typedef gdcm::Attribute<0x0018, 0x9763> PatientMotionCorrected; + typedef gdcm::Attribute<0x0018, 0x9764> CountLossNormalizationCorrected; + typedef gdcm::Attribute<0x0018, 0x9765> RandomsCorrected; + typedef gdcm::Attribute<0x0018, 0x9766> NonUniformRadialSamplingCorrected; + typedef gdcm::Attribute<0x0018, 0x9767> SensitivityCalibrated; + typedef gdcm::Attribute<0x0018, 0x9768> DetectorNormalizationCorrection; + typedef gdcm::Attribute<0x0018, 0x9769> IterativeReconstructionMethod; + typedef gdcm::Attribute<0x0018, 0x9770> AttenuationCorrectionTemporalRelationship; + typedef gdcm::Attribute<0x0018, 0x9771> PatientPhysiologicalStateSequence; + typedef gdcm::Attribute<0x0018, 0x9772> PatientPhysiologicalStateCodeSequence; + typedef gdcm::Attribute<0x0018, 0x9801> DepthsOfFocus; + typedef gdcm::Attribute<0x0018, 0x9803> ExcludedIntervalsSequence; + typedef gdcm::Attribute<0x0018, 0x9804> ExclusionStartDatetime; + typedef gdcm::Attribute<0x0018, 0x9805> ExclusionDuration; + typedef gdcm::Attribute<0x0018, 0x9806> USImageDescriptionSequence; + typedef gdcm::Attribute<0x0018, 0x9807> ImageDataTypeSequence; + typedef gdcm::Attribute<0x0018, 0x9808> DataType; + typedef gdcm::Attribute<0x0018, 0x9809> TransducerScanPatternCodeSequence; + typedef gdcm::Attribute<0x0018, 0x980b> AliasedDataType; + typedef gdcm::Attribute<0x0018, 0x980c> PositionMeasuringDeviceUsed; + typedef gdcm::Attribute<0x0018, 0x980d> TransducerGeometryCodeSequence; + typedef gdcm::Attribute<0x0018, 0x980e> TransducerBeamSteeringCodeSequence; + typedef gdcm::Attribute<0x0018, 0x980f> TransducerApplicationCodeSequence; + typedef gdcm::Attribute<0x0018, 0xa001> ContributingEquipmentSequence; + typedef gdcm::Attribute<0x0018, 0xa002> ContributionDateTime; + typedef gdcm::Attribute<0x0018, 0xa003> ContributionDescription; + typedef gdcm::Attribute<0x0020, 0x000d> StudyInstanceUID; + typedef gdcm::Attribute<0x0020, 0x000e> SeriesInstanceUID; + typedef gdcm::Attribute<0x0020, 0x0010> StudyID; + typedef gdcm::Attribute<0x0020, 0x0011> SeriesNumber; + typedef gdcm::Attribute<0x0020, 0x0012> AcquisitionNumber; + typedef gdcm::Attribute<0x0020, 0x0013> InstanceNumber; + typedef gdcm::Attribute<0x0020, 0x0014> IsotopeNumber; + typedef gdcm::Attribute<0x0020, 0x0015> PhaseNumber; + typedef gdcm::Attribute<0x0020, 0x0016> IntervalNumber; + typedef gdcm::Attribute<0x0020, 0x0017> TimeSlotNumber; + typedef gdcm::Attribute<0x0020, 0x0018> AngleNumber; + typedef gdcm::Attribute<0x0020, 0x0019> ItemNumber; + typedef gdcm::Attribute<0x0020, 0x0020> PatientOrientation; + typedef gdcm::Attribute<0x0020, 0x0022> OverlayNumber; + typedef gdcm::Attribute<0x0020, 0x0024> CurveNumber; + typedef gdcm::Attribute<0x0020, 0x0026> LUTNumber; + typedef gdcm::Attribute<0x0020, 0x0030> ImagePosition; + typedef gdcm::Attribute<0x0020, 0x0032> ImagePositionPatient; + typedef gdcm::Attribute<0x0020, 0x0035> ImageOrientation; + typedef gdcm::Attribute<0x0020, 0x0037> ImageOrientationPatient; + typedef gdcm::Attribute<0x0020, 0x0050> Location; + typedef gdcm::Attribute<0x0020, 0x0052> FrameOfReferenceUID; + typedef gdcm::Attribute<0x0020, 0x0060> Laterality; + typedef gdcm::Attribute<0x0020, 0x0062> ImageLaterality; + typedef gdcm::Attribute<0x0020, 0x0070> ImageGeometryType; + typedef gdcm::Attribute<0x0020, 0x0080> MaskingImage; + typedef gdcm::Attribute<0x0020, 0x00aa> ReportNumber; + typedef gdcm::Attribute<0x0020, 0x0100> TemporalPositionIdentifier; + typedef gdcm::Attribute<0x0020, 0x0105> NumberOfTemporalPositions; + typedef gdcm::Attribute<0x0020, 0x0110> TemporalResolution; + typedef gdcm::Attribute<0x0020, 0x0200> SynchronizationFrameOfReferenceUID; + typedef gdcm::Attribute<0x0020, 0x0242> SOPInstanceUIDOfConcatenationSource; + typedef gdcm::Attribute<0x0020, 0x1000> SeriesInStudy; + typedef gdcm::Attribute<0x0020, 0x1001> AcquisitionsInSeries; + typedef gdcm::Attribute<0x0020, 0x1002> ImagesInAcquisition; + typedef gdcm::Attribute<0x0020, 0x1003> ImagesInSeries; + typedef gdcm::Attribute<0x0020, 0x1004> AcquisitionsInStudy; + typedef gdcm::Attribute<0x0020, 0x1005> ImagesInStudy; + typedef gdcm::Attribute<0x0020, 0x1020> Reference; + typedef gdcm::Attribute<0x0020, 0x1040> PositionReferenceIndicator; + typedef gdcm::Attribute<0x0020, 0x1041> SliceLocation; + typedef gdcm::Attribute<0x0020, 0x1070> OtherStudyNumbers; + typedef gdcm::Attribute<0x0020, 0x1200> NumberOfPatientRelatedStudies; + typedef gdcm::Attribute<0x0020, 0x1202> NumberOfPatientRelatedSeries; + typedef gdcm::Attribute<0x0020, 0x1204> NumberOfPatientRelatedInstances; + typedef gdcm::Attribute<0x0020, 0x1206> NumberOfStudyRelatedSeries; + typedef gdcm::Attribute<0x0020, 0x1208> NumberOfStudyRelatedInstances; + typedef gdcm::Attribute<0x0020, 0x1209> NumberOfSeriesRelatedInstances; + typedef gdcm::Attribute<0x0020, 0x3100> SourceImageIDs; + typedef gdcm::Attribute<0x0020, 0x3401> ModifyingDeviceID; + typedef gdcm::Attribute<0x0020, 0x3402> ModifiedImageID; + typedef gdcm::Attribute<0x0020, 0x3403> ModifiedImageDate; + typedef gdcm::Attribute<0x0020, 0x3404> ModifyingDeviceManufacturer; + typedef gdcm::Attribute<0x0020, 0x3405> ModifiedImageTime; + typedef gdcm::Attribute<0x0020, 0x3406> ModifiedImageDescription; + typedef gdcm::Attribute<0x0020, 0x4000> ImageComments; + typedef gdcm::Attribute<0x0020, 0x5000> OriginalImageIdentification; + typedef gdcm::Attribute<0x0020, 0x5002> OriginalImageIdentificationNomenclature; + typedef gdcm::Attribute<0x0020, 0x9056> StackID; + typedef gdcm::Attribute<0x0020, 0x9057> InStackPositionNumber; + typedef gdcm::Attribute<0x0020, 0x9071> FrameAnatomySequence; + typedef gdcm::Attribute<0x0020, 0x9072> FrameLaterality; + typedef gdcm::Attribute<0x0020, 0x9111> FrameContentSequence; + typedef gdcm::Attribute<0x0020, 0x9113> PlanePositionSequence; + typedef gdcm::Attribute<0x0020, 0x9116> PlaneOrientationSequence; + typedef gdcm::Attribute<0x0020, 0x9128> TemporalPositionIndex; + typedef gdcm::Attribute<0x0020, 0x9153> NominalCardiacTriggerDelayTime; + typedef gdcm::Attribute<0x0020, 0x9154> NominalCardiacTriggerTimePriorToRPeak; + typedef gdcm::Attribute<0x0020, 0x9155> ActualCardiacTriggerTimePriorToRPeak; + typedef gdcm::Attribute<0x0020, 0x9156> FrameAcquisitionNumber; + typedef gdcm::Attribute<0x0020, 0x9157> DimensionIndexValues; + typedef gdcm::Attribute<0x0020, 0x9158> FrameComments; + typedef gdcm::Attribute<0x0020, 0x9161> ConcatenationUID; + typedef gdcm::Attribute<0x0020, 0x9162> InConcatenationNumber; + typedef gdcm::Attribute<0x0020, 0x9163> InConcatenationTotalNumber; + typedef gdcm::Attribute<0x0020, 0x9164> DimensionOrganizationUID; + typedef gdcm::Attribute<0x0020, 0x9165> DimensionIndexPointer; + typedef gdcm::Attribute<0x0020, 0x9167> FunctionalGroupPointer; + typedef gdcm::Attribute<0x0020, 0x9213> DimensionIndexPrivateCreator; + typedef gdcm::Attribute<0x0020, 0x9221> DimensionOrganizationSequence; + typedef gdcm::Attribute<0x0020, 0x9222> DimensionIndexSequence; + typedef gdcm::Attribute<0x0020, 0x9228> ConcatenationFrameOffsetNumber; + typedef gdcm::Attribute<0x0020, 0x9238> FunctionalGroupPrivateCreator; + typedef gdcm::Attribute<0x0020, 0x9241> NominalPercentageOfCardiacPhase; + typedef gdcm::Attribute<0x0020, 0x9245> NominalPercentageOfRespiratoryPhase; + typedef gdcm::Attribute<0x0020, 0x9246> StartingRespiratoryAmplitude; + typedef gdcm::Attribute<0x0020, 0x9247> StartingRespiratoryPhase; + typedef gdcm::Attribute<0x0020, 0x9248> EndingRespiratoryAmplitude; + typedef gdcm::Attribute<0x0020, 0x9249> EndingRespiratoryPhase; + typedef gdcm::Attribute<0x0020, 0x9250> RespiratoryTriggerType; + typedef gdcm::Attribute<0x0020, 0x9251> RRIntervalTimeNominal; + typedef gdcm::Attribute<0x0020, 0x9252> ActualCardiacTriggerDelayTime; + typedef gdcm::Attribute<0x0020, 0x9253> RespiratorySynchronizationSequence; + typedef gdcm::Attribute<0x0020, 0x9254> RespiratoryIntervalTime; + typedef gdcm::Attribute<0x0020, 0x9255> NominalRespiratoryTriggerDelayTime; + typedef gdcm::Attribute<0x0020, 0x9256> RespiratoryTriggerDelayThreshold; + typedef gdcm::Attribute<0x0020, 0x9257> ActualRespiratoryTriggerDelayTime; + typedef gdcm::Attribute<0x0020, 0x9301> ImagePositionVolume; + typedef gdcm::Attribute<0x0020, 0x9302> ImageOrientationVolume; + typedef gdcm::Attribute<0x0020, 0x9307> UltrasoundAcquisitionGeometry; + typedef gdcm::Attribute<0x0020, 0x9308> ApexPosition; + typedef gdcm::Attribute<0x0020, 0x9309> VolumeToTransducerMappingMatrix; + typedef gdcm::Attribute<0x0020, 0x930a> VolumeToTableMappingMatrix; + typedef gdcm::Attribute<0x0020, 0x930c> PatientFrameOfReferenceSource; + typedef gdcm::Attribute<0x0020, 0x930d> TemporalPositionTimeOffset; + typedef gdcm::Attribute<0x0020, 0x930e> PlanePositionVolumeSequence; + typedef gdcm::Attribute<0x0020, 0x930f> PlaneOrientationVolumeSequence; + typedef gdcm::Attribute<0x0020, 0x9310> TemporalPositionSequence; + typedef gdcm::Attribute<0x0020, 0x9311> DimensionOrganizationType; + typedef gdcm::Attribute<0x0020, 0x9312> VolumeFrameOfReferenceUID; + typedef gdcm::Attribute<0x0020, 0x9313> TableFrameOfReferenceUID; + typedef gdcm::Attribute<0x0020, 0x9421> DimensionDescriptionLabel; + typedef gdcm::Attribute<0x0020, 0x9450> PatientOrientationInFrameSequence; + typedef gdcm::Attribute<0x0020, 0x9453> FrameLabel; + typedef gdcm::Attribute<0x0020, 0x9518> AcquisitionIndex; + typedef gdcm::Attribute<0x0020, 0x9529> ContributingSOPInstancesReferenceSequence; + typedef gdcm::Attribute<0x0020, 0x9536> ReconstructionIndex; + typedef gdcm::Attribute<0x0022, 0x0001> LightPathFilterPassThroughWavelength; + typedef gdcm::Attribute<0x0022, 0x0002> LightPathFilterPassBand; + typedef gdcm::Attribute<0x0022, 0x0003> ImagePathFilterPassThroughWavelength; + typedef gdcm::Attribute<0x0022, 0x0004> ImagePathFilterPassBand; + typedef gdcm::Attribute<0x0022, 0x0005> PatientEyeMovementCommanded; + typedef gdcm::Attribute<0x0022, 0x0006> PatientEyeMovementCommandCodeSequence; + typedef gdcm::Attribute<0x0022, 0x0007> SphericalLensPower; + typedef gdcm::Attribute<0x0022, 0x0008> CylinderLensPower; + typedef gdcm::Attribute<0x0022, 0x0009> CylinderAxis; + typedef gdcm::Attribute<0x0022, 0x000a> EmmetropicMagnification; + typedef gdcm::Attribute<0x0022, 0x000b> IntraOcularPressure; + typedef gdcm::Attribute<0x0022, 0x000c> HorizontalFieldOfView; + typedef gdcm::Attribute<0x0022, 0x000d> PupilDilated; + typedef gdcm::Attribute<0x0022, 0x000e> DegreeOfDilation; + typedef gdcm::Attribute<0x0022, 0x0010> StereoBaselineAngle; + typedef gdcm::Attribute<0x0022, 0x0011> StereoBaselineDisplacement; + typedef gdcm::Attribute<0x0022, 0x0012> StereoHorizontalPixelOffset; + typedef gdcm::Attribute<0x0022, 0x0013> StereoVerticalPixelOffset; + typedef gdcm::Attribute<0x0022, 0x0014> StereoRotation; + typedef gdcm::Attribute<0x0022, 0x0015> AcquisitionDeviceTypeCodeSequence; + typedef gdcm::Attribute<0x0022, 0x0016> IlluminationTypeCodeSequence; + typedef gdcm::Attribute<0x0022, 0x0017> LightPathFilterTypeStackCodeSequence; + typedef gdcm::Attribute<0x0022, 0x0018> ImagePathFilterTypeStackCodeSequence; + typedef gdcm::Attribute<0x0022, 0x0019> LensesCodeSequence; + typedef gdcm::Attribute<0x0022, 0x001a> ChannelDescriptionCodeSequence; + typedef gdcm::Attribute<0x0022, 0x001b> RefractiveStateSequence; + typedef gdcm::Attribute<0x0022, 0x001c> MydriaticAgentCodeSequence; + typedef gdcm::Attribute<0x0022, 0x001d> RelativeImagePositionCodeSequence; + typedef gdcm::Attribute<0x0022, 0x001e> CameraAngleOfView; + typedef gdcm::Attribute<0x0022, 0x0020> StereoPairsSequence; + typedef gdcm::Attribute<0x0022, 0x0021> LeftImageSequence; + typedef gdcm::Attribute<0x0022, 0x0022> RightImageSequence; + typedef gdcm::Attribute<0x0022, 0x0030> AxialLengthOfTheEye; + typedef gdcm::Attribute<0x0022, 0x0031> OphthalmicFrameLocationSequence; + typedef gdcm::Attribute<0x0022, 0x0032> ReferenceCoordinates; + typedef gdcm::Attribute<0x0022, 0x0035> DepthSpatialResolution; + typedef gdcm::Attribute<0x0022, 0x0036> MaximumDepthDistortion; + typedef gdcm::Attribute<0x0022, 0x0037> AlongScanSpatialResolution; + typedef gdcm::Attribute<0x0022, 0x0038> MaximumAlongScanDistortion; + typedef gdcm::Attribute<0x0022, 0x0039> OphthalmicImageOrientation; + typedef gdcm::Attribute<0x0022, 0x0041> DepthOfTransverseImage; + typedef gdcm::Attribute<0x0022, 0x0042> MydriaticAgentConcentrationUnitsSequence; + typedef gdcm::Attribute<0x0022, 0x0048> AcrossScanSpatialResolution; + typedef gdcm::Attribute<0x0022, 0x0049> MaximumAcrossScanDistortion; + typedef gdcm::Attribute<0x0022, 0x004e> MydriaticAgentConcentration; + typedef gdcm::Attribute<0x0022, 0x0055> IlluminationWaveLength; + typedef gdcm::Attribute<0x0022, 0x0056> IlluminationPower; + typedef gdcm::Attribute<0x0022, 0x0057> IlluminationBandwidth; + typedef gdcm::Attribute<0x0022, 0x0058> MydriaticAgentSequence; + typedef gdcm::Attribute<0x0022, 0x1007> OphthalmicAxialMeasurementsRightEyeSequence; + typedef gdcm::Attribute<0x0022, 0x1008> OphthalmicAxialMeasurementsLeftEyeSequence; + typedef gdcm::Attribute<0x0022, 0x1009> OphthalmicAxialMeasurementsDeviceType; + typedef gdcm::Attribute<0x0022, 0x1010> OphthalmicAxialLengthMeasurementsType; + typedef gdcm::Attribute<0x0022, 0x1012> OphthalmicAxialLengthSequence; + typedef gdcm::Attribute<0x0022, 0x1019> OphthalmicAxialLength; + typedef gdcm::Attribute<0x0022, 0x1024> LensStatusCodeSequence; + typedef gdcm::Attribute<0x0022, 0x1025> VitreousStatusCodeSequence; + typedef gdcm::Attribute<0x0022, 0x1028> IOLFormulaCodeSequence; + typedef gdcm::Attribute<0x0022, 0x1029> IOLFormulaDetail; + typedef gdcm::Attribute<0x0022, 0x1033> KeratometerIndex; + typedef gdcm::Attribute<0x0022, 0x1035> SourceOfOphthalmicAxialLengthCodeSequence; + typedef gdcm::Attribute<0x0022, 0x1037> TargetRefraction; + typedef gdcm::Attribute<0x0022, 0x1039> RefractiveProcedureOccurred; + typedef gdcm::Attribute<0x0022, 0x1040> RefractiveSurgeryTypeCodeSequence; + typedef gdcm::Attribute<0x0022, 0x1044> OphthalmicUltrasoundMethodCodeSequence; + typedef gdcm::Attribute<0x0022, 0x1050> OphthalmicAxialLengthMeasurementsSequence; + typedef gdcm::Attribute<0x0022, 0x1053> IOLPower; + typedef gdcm::Attribute<0x0022, 0x1054> PredictedRefractiveError; + typedef gdcm::Attribute<0x0022, 0x1059> OphthalmicAxialLengthVelocity; + typedef gdcm::Attribute<0x0022, 0x1065> LensStatusDescription; + typedef gdcm::Attribute<0x0022, 0x1066> VitreousStatusDescription; + typedef gdcm::Attribute<0x0022, 0x1090> IOLPowerSequence; + typedef gdcm::Attribute<0x0022, 0x1092> LensConstantSequence; + typedef gdcm::Attribute<0x0022, 0x1093> IOLManufacturer; + typedef gdcm::Attribute<0x0022, 0x1094> LensConstantDescription; + typedef gdcm::Attribute<0x0022, 0x1095> ImplantName; + typedef gdcm::Attribute<0x0022, 0x1096> KeratometryMeasurementTypeCodeSequence; + typedef gdcm::Attribute<0x0022, 0x1097> ImplantPartNumber; + typedef gdcm::Attribute<0x0022, 0x1100> ReferencedOphthalmicAxialMeasurementsSequence; + typedef gdcm::Attribute<0x0022, 0x1101> OphthalmicAxialLengthMeasurementsSegmentNameCodeSequence; + typedef gdcm::Attribute<0x0022, 0x1103> RefractiveErrorBeforeRefractiveSurgeryCodeSequence; + typedef gdcm::Attribute<0x0022, 0x1121> IOLPowerForExactEmmetropia; + typedef gdcm::Attribute<0x0022, 0x1122> IOLPowerForExactTargetRefraction; + typedef gdcm::Attribute<0x0022, 0x1125> AnteriorChamberDepthDefinitionCodeSequence; + typedef gdcm::Attribute<0x0022, 0x1127> LensThicknessSequence; + typedef gdcm::Attribute<0x0022, 0x1128> AnteriorChamberDepthSequence; + typedef gdcm::Attribute<0x0022, 0x1130> LensThickness; + typedef gdcm::Attribute<0x0022, 0x1131> AnteriorChamberDepth; + typedef gdcm::Attribute<0x0022, 0x1132> SourceOfLensThicknessDataCodeSequence; + typedef gdcm::Attribute<0x0022, 0x1133> SourceOfAnteriorChamberDepthDataCodeSequence; + typedef gdcm::Attribute<0x0022, 0x1134> SourceOfRefractiveMeasurementsSequence; + typedef gdcm::Attribute<0x0022, 0x1135> SourceOfRefractiveMeasurementsCodeSequence; + typedef gdcm::Attribute<0x0022, 0x1140> OphthalmicAxialLengthMeasurementModified; + typedef gdcm::Attribute<0x0022, 0x1150> OphthalmicAxialLengthDataSourceCodeSequence; + typedef gdcm::Attribute<0x0022, 0x1153> OphthalmicAxialLengthAcquisitionMethodCodeSequence; + typedef gdcm::Attribute<0x0022, 0x1155> SignalToNoiseRatio; + typedef gdcm::Attribute<0x0022, 0x1159> OphthalmicAxialLengthDataSourceDescription; + typedef gdcm::Attribute<0x0022, 0x1210> OphthalmicAxialLengthMeasurementsTotalLengthSequence; + typedef gdcm::Attribute<0x0022, 0x1211> OphthalmicAxialLengthMeasurementsSegmentalLengthSequence; + typedef gdcm::Attribute<0x0022, 0x1212> OphthalmicAxialLengthMeasurementsLengthSummationSequence; + typedef gdcm::Attribute<0x0022, 0x1220> UltrasoundOphthalmicAxialLengthMeasurementsSequence; + typedef gdcm::Attribute<0x0022, 0x1225> OpticalOphthalmicAxialLengthMeasurementsSequence; + typedef gdcm::Attribute<0x0022, 0x1230> UltrasoundSelectedOphthalmicAxialLengthSequence; + typedef gdcm::Attribute<0x0022, 0x1250> OphthalmicAxialLengthSelectionMethodCodeSequence; + typedef gdcm::Attribute<0x0022, 0x1255> OpticalSelectedOphthalmicAxialLengthSequence; + typedef gdcm::Attribute<0x0022, 0x1257> SelectedSegmentalOphthalmicAxialLengthSequence; + typedef gdcm::Attribute<0x0022, 0x1260> SelectedTotalOphthalmicAxialLengthSequence; + typedef gdcm::Attribute<0x0022, 0x1262> OphthalmicAxialLengthQualityMetricSequence; + typedef gdcm::Attribute<0x0022, 0x1273> OphthalmicAxialLengthQualityMetricTypeDescription; + typedef gdcm::Attribute<0x0022, 0x1300> IntraocularLensCalculationsRightEyeSequence; + typedef gdcm::Attribute<0x0022, 0x1310> IntraocularLensCalculationsLeftEyeSequence; + typedef gdcm::Attribute<0x0022, 0x1330> ReferencedOphthalmicAxialLengthMeasurementQCImageSequence; + typedef gdcm::Attribute<0x0024, 0x0010> VisualFieldHorizontalExtent; + typedef gdcm::Attribute<0x0024, 0x0011> VisualFieldVerticalExtent; + typedef gdcm::Attribute<0x0024, 0x0012> VisualFieldShape; + typedef gdcm::Attribute<0x0024, 0x0016> ScreeningTestModeCodeSequence; + typedef gdcm::Attribute<0x0024, 0x0018> MaximumStimulusLuminance; + typedef gdcm::Attribute<0x0024, 0x0020> BackgroundLuminance; + typedef gdcm::Attribute<0x0024, 0x0021> StimulusColorCodeSequence; + typedef gdcm::Attribute<0x0024, 0x0024> BackgroundIlluminationColorCodeSequence; + typedef gdcm::Attribute<0x0024, 0x0025> StimulusArea; + typedef gdcm::Attribute<0x0024, 0x0028> StimulusPresentationTime; + typedef gdcm::Attribute<0x0024, 0x0032> FixationSequence; + typedef gdcm::Attribute<0x0024, 0x0033> FixationMonitoringCodeSequence; + typedef gdcm::Attribute<0x0024, 0x0034> VisualFieldCatchTrialSequence; + typedef gdcm::Attribute<0x0024, 0x0035> FixationCheckedQuantity; + typedef gdcm::Attribute<0x0024, 0x0036> PatientNotProperlyFixatedQuantity; + typedef gdcm::Attribute<0x0024, 0x0037> PresentedVisualStimuliDataFlag; + typedef gdcm::Attribute<0x0024, 0x0038> NumberOfVisualStimuli; + typedef gdcm::Attribute<0x0024, 0x0039> ExcessiveFixationLossesDataFlag; + typedef gdcm::Attribute<0x0024, 0x0040> ExcessiveFixationLosses; + typedef gdcm::Attribute<0x0024, 0x0042> StimuliRetestingQuantity; + typedef gdcm::Attribute<0x0024, 0x0044> CommentsOnPatientPerformanceOfVisualField; + typedef gdcm::Attribute<0x0024, 0x0045> FalseNegativesEstimateFlag; + typedef gdcm::Attribute<0x0024, 0x0046> FalseNegativesEstimate; + typedef gdcm::Attribute<0x0024, 0x0048> NegativeCatchTrialsQuantity; + typedef gdcm::Attribute<0x0024, 0x0050> FalseNegativesQuantity; + typedef gdcm::Attribute<0x0024, 0x0051> ExcessiveFalseNegativesDataFlag; + typedef gdcm::Attribute<0x0024, 0x0052> ExcessiveFalseNegatives; + typedef gdcm::Attribute<0x0024, 0x0053> FalsePositivesEstimateFlag; + typedef gdcm::Attribute<0x0024, 0x0054> FalsePositivesEstimate; + typedef gdcm::Attribute<0x0024, 0x0055> CatchTrialsDataFlag; + typedef gdcm::Attribute<0x0024, 0x0056> PositiveCatchTrialsQuantity; + typedef gdcm::Attribute<0x0024, 0x0057> TestPointNormalsDataFlag; + typedef gdcm::Attribute<0x0024, 0x0058> TestPointNormalsSequence; + typedef gdcm::Attribute<0x0024, 0x0059> GlobalDeviationProbabilityNormalsFlag; + typedef gdcm::Attribute<0x0024, 0x0060> FalsePositivesQuantity; + typedef gdcm::Attribute<0x0024, 0x0061> ExcessiveFalsePositivesDataFlag; + typedef gdcm::Attribute<0x0024, 0x0062> ExcessiveFalsePositives; + typedef gdcm::Attribute<0x0024, 0x0063> VisualFieldTestNormalsFlag; + typedef gdcm::Attribute<0x0024, 0x0064> ResultsNormalsSequence; + typedef gdcm::Attribute<0x0024, 0x0065> AgeCorrectedSensitivityDeviationAlgorithmSequence; + typedef gdcm::Attribute<0x0024, 0x0066> GlobalDeviationFromNormal; + typedef gdcm::Attribute<0x0024, 0x0067> GeneralizedDefectSensitivityDeviationAlgorithmSequence; + typedef gdcm::Attribute<0x0024, 0x0068> LocalizedDeviationfromNormal; + typedef gdcm::Attribute<0x0024, 0x0069> PatientReliabilityIndicator; + typedef gdcm::Attribute<0x0024, 0x0070> VisualFieldMeanSensitivity; + typedef gdcm::Attribute<0x0024, 0x0071> GlobalDeviationProbability; + typedef gdcm::Attribute<0x0024, 0x0072> LocalDeviationProbabilityNormalsFlag; + typedef gdcm::Attribute<0x0024, 0x0073> LocalizedDeviationProbability; + typedef gdcm::Attribute<0x0024, 0x0074> ShortTermFluctuationCalculated; + typedef gdcm::Attribute<0x0024, 0x0075> ShortTermFluctuation; + typedef gdcm::Attribute<0x0024, 0x0076> ShortTermFluctuationProbabilityCalculated; + typedef gdcm::Attribute<0x0024, 0x0077> ShortTermFluctuationProbability; + typedef gdcm::Attribute<0x0024, 0x0078> CorrectedLocalizedDeviationFromNormalCalculated; + typedef gdcm::Attribute<0x0024, 0x0079> CorrectedLocalizedDeviationFromNormal; + typedef gdcm::Attribute<0x0024, 0x0080> CorrectedLocalizedDeviationFromNormalProbabilityCalculated; + typedef gdcm::Attribute<0x0024, 0x0081> CorrectedLocalizedDeviationFromNormalProbability; + typedef gdcm::Attribute<0x0024, 0x0083> GlobalDeviationProbabilitySequence; + typedef gdcm::Attribute<0x0024, 0x0085> LocalizedDeviationProbabilitySequence; + typedef gdcm::Attribute<0x0024, 0x0086> FovealSensitivityMeasured; + typedef gdcm::Attribute<0x0024, 0x0087> FovealSensitivity; + typedef gdcm::Attribute<0x0024, 0x0088> VisualFieldTestDuration; + typedef gdcm::Attribute<0x0024, 0x0089> VisualFieldTestPointSequence; + typedef gdcm::Attribute<0x0024, 0x0090> VisualFieldTestPointXCoordinate; + typedef gdcm::Attribute<0x0024, 0x0091> VisualFieldTestPointYCoordinate; + typedef gdcm::Attribute<0x0024, 0x0092> AgeCorrectedSensitivityDeviationValue; + typedef gdcm::Attribute<0x0024, 0x0093> StimulusResults; + typedef gdcm::Attribute<0x0024, 0x0094> SensitivityValue; + typedef gdcm::Attribute<0x0024, 0x0095> RetestStimulusSeen; + typedef gdcm::Attribute<0x0024, 0x0096> RetestSensitivityValue; + typedef gdcm::Attribute<0x0024, 0x0097> VisualFieldTestPointNormalsSequence; + typedef gdcm::Attribute<0x0024, 0x0098> QuantifiedDefect; + typedef gdcm::Attribute<0x0024, 0x0100> AgeCorrectedSensitivityDeviationProbabilityValue; + typedef gdcm::Attribute<0x0024, 0x0102> GeneralizedDefectCorrectedSensitivityDeviationFlag; + typedef gdcm::Attribute<0x0024, 0x0103> GeneralizedDefectCorrectedSensitivityDeviationValue; + typedef gdcm::Attribute<0x0024, 0x0104> GeneralizedDefectCorrectedSensitivityDeviationProbabilityValue; + typedef gdcm::Attribute<0x0024, 0x0105> MinimumSensitivityValue; + typedef gdcm::Attribute<0x0024, 0x0106> BlindSpotLocalized; + typedef gdcm::Attribute<0x0024, 0x0107> BlindSpotXCoordinate; + typedef gdcm::Attribute<0x0024, 0x0108> BlindSpotYCoordinate; + typedef gdcm::Attribute<0x0024, 0x0110> VisualAcuityMeasurementSequence; + typedef gdcm::Attribute<0x0024, 0x0112> RefractiveParametersUsedOnPatientSequence; + typedef gdcm::Attribute<0x0024, 0x0113> MeasurementLaterality; + typedef gdcm::Attribute<0x0024, 0x0114> OphthalmicPatientClinicalInformationLeftEyeSequence; + typedef gdcm::Attribute<0x0024, 0x0115> OphthalmicPatientClinicalInformationRightEyeSequence; + typedef gdcm::Attribute<0x0024, 0x0117> FovealPointNormativeDataFlag; + typedef gdcm::Attribute<0x0024, 0x0118> FovealPointProbabilityValue; + typedef gdcm::Attribute<0x0024, 0x0120> ScreeningBaselineMeasured; + typedef gdcm::Attribute<0x0024, 0x0122> ScreeningBaselineMeasuredSequence; + typedef gdcm::Attribute<0x0024, 0x0124> ScreeningBaselineType; + typedef gdcm::Attribute<0x0024, 0x0126> ScreeningBaselineValue; + typedef gdcm::Attribute<0x0024, 0x0202> AlgorithmSource; + typedef gdcm::Attribute<0x0024, 0x0306> DataSetName; + typedef gdcm::Attribute<0x0024, 0x0307> DataSetVersion; + typedef gdcm::Attribute<0x0024, 0x0308> DataSetSource; + typedef gdcm::Attribute<0x0024, 0x0309> DataSetDescription; + typedef gdcm::Attribute<0x0024, 0x0317> VisualFieldTestReliabilityGlobalIndexSequence; + typedef gdcm::Attribute<0x0024, 0x0320> VisualFieldGlobalResultsIndexSequence; + typedef gdcm::Attribute<0x0024, 0x0325> DataObservationSequence; + typedef gdcm::Attribute<0x0024, 0x0338> IndexNormalsFlag; + typedef gdcm::Attribute<0x0024, 0x0341> IndexProbability; + typedef gdcm::Attribute<0x0024, 0x0344> IndexProbabilitySequence; + typedef gdcm::Attribute<0x0028, 0x0002> SamplesPerPixel; + typedef gdcm::Attribute<0x0028, 0x0003> SamplesPerPixelUsed; + typedef gdcm::Attribute<0x0028, 0x0004> PhotometricInterpretation; + typedef gdcm::Attribute<0x0028, 0x0005> ImageDimensions; + typedef gdcm::Attribute<0x0028, 0x0006> PlanarConfiguration; + typedef gdcm::Attribute<0x0028, 0x0008> NumberOfFrames; + typedef gdcm::Attribute<0x0028, 0x0009> FrameIncrementPointer; + typedef gdcm::Attribute<0x0028, 0x000a> FrameDimensionPointer; + typedef gdcm::Attribute<0x0028, 0x0010> Rows; + typedef gdcm::Attribute<0x0028, 0x0011> Columns; + typedef gdcm::Attribute<0x0028, 0x0012> Planes; + typedef gdcm::Attribute<0x0028, 0x0014> UltrasoundColorDataPresent; + // 0x0028, 0x0020 SHALL NOT BE USED + typedef gdcm::Attribute<0x0028, 0x0030> PixelSpacing; + typedef gdcm::Attribute<0x0028, 0x0031> ZoomFactor; + typedef gdcm::Attribute<0x0028, 0x0032> ZoomCenter; + typedef gdcm::Attribute<0x0028, 0x0034> PixelAspectRatio; + typedef gdcm::Attribute<0x0028, 0x0040> ImageFormat; + typedef gdcm::Attribute<0x0028, 0x0050> ManipulatedImage; + typedef gdcm::Attribute<0x0028, 0x0051> CorrectedImage; + typedef gdcm::Attribute<0x0028, 0x005f> CompressionRecognitionCode; + typedef gdcm::Attribute<0x0028, 0x0060> CompressionCode; + typedef gdcm::Attribute<0x0028, 0x0061> CompressionOriginator; + typedef gdcm::Attribute<0x0028, 0x0062> CompressionLabel; + typedef gdcm::Attribute<0x0028, 0x0063> CompressionDescription; + typedef gdcm::Attribute<0x0028, 0x0065> CompressionSequence; + typedef gdcm::Attribute<0x0028, 0x0066> CompressionStepPointers; + typedef gdcm::Attribute<0x0028, 0x0068> RepeatInterval; + typedef gdcm::Attribute<0x0028, 0x0069> BitsGrouped; + typedef gdcm::Attribute<0x0028, 0x0070> PerimeterTable; + typedef gdcm::Attribute<0x0028, 0x0071> PerimeterValue; + typedef gdcm::Attribute<0x0028, 0x0080> PredictorRows; + typedef gdcm::Attribute<0x0028, 0x0081> PredictorColumns; + typedef gdcm::Attribute<0x0028, 0x0082> PredictorConstants; + typedef gdcm::Attribute<0x0028, 0x0090> BlockedPixels; + typedef gdcm::Attribute<0x0028, 0x0091> BlockRows; + typedef gdcm::Attribute<0x0028, 0x0092> BlockColumns; + typedef gdcm::Attribute<0x0028, 0x0093> RowOverlap; + typedef gdcm::Attribute<0x0028, 0x0094> ColumnOverlap; + typedef gdcm::Attribute<0x0028, 0x0100> BitsAllocated; + typedef gdcm::Attribute<0x0028, 0x0101> BitsStored; + typedef gdcm::Attribute<0x0028, 0x0102> HighBit; + typedef gdcm::Attribute<0x0028, 0x0103> PixelRepresentation; + typedef gdcm::Attribute<0x0028, 0x0104> SmallestValidPixelValue; + typedef gdcm::Attribute<0x0028, 0x0105> LargestValidPixelValue; + typedef gdcm::Attribute<0x0028, 0x0106> SmallestImagePixelValue; + typedef gdcm::Attribute<0x0028, 0x0107> LargestImagePixelValue; + typedef gdcm::Attribute<0x0028, 0x0108> SmallestPixelValueInSeries; + typedef gdcm::Attribute<0x0028, 0x0109> LargestPixelValueInSeries; + typedef gdcm::Attribute<0x0028, 0x0110> SmallestImagePixelValueInPlane; + typedef gdcm::Attribute<0x0028, 0x0111> LargestImagePixelValueInPlane; + typedef gdcm::Attribute<0x0028, 0x0120> PixelPaddingValue; + typedef gdcm::Attribute<0x0028, 0x0121> PixelPaddingRangeLimit; + typedef gdcm::Attribute<0x0028, 0x0200> ImageLocation; + typedef gdcm::Attribute<0x0028, 0x0300> QualityControlImage; + typedef gdcm::Attribute<0x0028, 0x0301> BurnedInAnnotation; + typedef gdcm::Attribute<0x0028, 0x0302> RecognizableVisualFeatures; + typedef gdcm::Attribute<0x0028, 0x0303> LongitudinalTemporalInformationModified; + typedef gdcm::Attribute<0x0028, 0x0304> ReferencedColorPaletteInstanceUID; + typedef gdcm::Attribute<0x0028, 0x0400> TransformLabel; + typedef gdcm::Attribute<0x0028, 0x0401> TransformVersionNumber; + typedef gdcm::Attribute<0x0028, 0x0402> NumberOfTransformSteps; + typedef gdcm::Attribute<0x0028, 0x0403> SequenceOfCompressedData; + typedef gdcm::Attribute<0x0028, 0x0404> DetailsOfCoefficients; + typedef gdcm::Attribute<0x0028, 0x0400> RowsForNthOrderCoefficients; + typedef gdcm::Attribute<0x0028, 0x0401> ColumnsForNthOrderCoefficients; + typedef gdcm::Attribute<0x0028, 0x0402> CoefficientCoding; + typedef gdcm::Attribute<0x0028, 0x0403> CoefficientCodingPointers; + typedef gdcm::Attribute<0x0028, 0x0700> DCTLabel; + typedef gdcm::Attribute<0x0028, 0x0701> DataBlockDescription; + typedef gdcm::Attribute<0x0028, 0x0702> DataBlock; + typedef gdcm::Attribute<0x0028, 0x0710> NormalizationFactorFormat; + typedef gdcm::Attribute<0x0028, 0x0720> ZonalMapNumberFormat; + typedef gdcm::Attribute<0x0028, 0x0721> ZonalMapLocation; + typedef gdcm::Attribute<0x0028, 0x0722> ZonalMapFormat; + typedef gdcm::Attribute<0x0028, 0x0730> AdaptiveMapFormat; + typedef gdcm::Attribute<0x0028, 0x0740> CodeNumberFormat; + typedef gdcm::Attribute<0x0028, 0x0800> CodeLabel; + typedef gdcm::Attribute<0x0028, 0x0802> NumberOfTables; + typedef gdcm::Attribute<0x0028, 0x0803> CodeTableLocation; + typedef gdcm::Attribute<0x0028, 0x0804> BitsForCodeWord; + typedef gdcm::Attribute<0x0028, 0x0808> ImageDataLocation; + typedef gdcm::Attribute<0x0028, 0x0a02> PixelSpacingCalibrationType; + typedef gdcm::Attribute<0x0028, 0x0a04> PixelSpacingCalibrationDescription; + typedef gdcm::Attribute<0x0028, 0x1040> PixelIntensityRelationship; + typedef gdcm::Attribute<0x0028, 0x1041> PixelIntensityRelationshipSign; + typedef gdcm::Attribute<0x0028, 0x1050> WindowCenter; + typedef gdcm::Attribute<0x0028, 0x1051> WindowWidth; + typedef gdcm::Attribute<0x0028, 0x1052> RescaleIntercept; + typedef gdcm::Attribute<0x0028, 0x1053> RescaleSlope; + typedef gdcm::Attribute<0x0028, 0x1054> RescaleType; + typedef gdcm::Attribute<0x0028, 0x1055> WindowCenterWidthExplanation; + typedef gdcm::Attribute<0x0028, 0x1056> VOILUTFunction; + typedef gdcm::Attribute<0x0028, 0x1080> GrayScale; + typedef gdcm::Attribute<0x0028, 0x1090> RecommendedViewingMode; + typedef gdcm::Attribute<0x0028, 0x1100> GrayLookupTableDescriptor; + typedef gdcm::Attribute<0x0028, 0x1101> RedPaletteColorLookupTableDescriptor; + typedef gdcm::Attribute<0x0028, 0x1102> GreenPaletteColorLookupTableDescriptor; + typedef gdcm::Attribute<0x0028, 0x1103> BluePaletteColorLookupTableDescriptor; + typedef gdcm::Attribute<0x0028, 0x1104> AlphaPaletteColorLookupTableDescriptor; + typedef gdcm::Attribute<0x0028, 0x1111> LargeRedPaletteColorLookupTableDescriptor; + typedef gdcm::Attribute<0x0028, 0x1112> LargeGreenPaletteColorLookupTableDescriptor; + typedef gdcm::Attribute<0x0028, 0x1113> LargeBluePaletteColorLookupTableDescriptor; + typedef gdcm::Attribute<0x0028, 0x1199> PaletteColorLookupTableUID; + typedef gdcm::Attribute<0x0028, 0x1200> GrayLookupTableData; + typedef gdcm::Attribute<0x0028, 0x1201> RedPaletteColorLookupTableData; + typedef gdcm::Attribute<0x0028, 0x1202> GreenPaletteColorLookupTableData; + typedef gdcm::Attribute<0x0028, 0x1203> BluePaletteColorLookupTableData; + typedef gdcm::Attribute<0x0028, 0x1204> AlphaPaletteColorLookupTableData; + typedef gdcm::Attribute<0x0028, 0x1211> LargeRedPaletteColorLookupTableData; + typedef gdcm::Attribute<0x0028, 0x1212> LargeGreenPaletteColorLookupTableData; + typedef gdcm::Attribute<0x0028, 0x1213> LargeBluePaletteColorLookupTableData; + typedef gdcm::Attribute<0x0028, 0x1214> LargePaletteColorLookupTableUID; + typedef gdcm::Attribute<0x0028, 0x1221> SegmentedRedPaletteColorLookupTableData; + typedef gdcm::Attribute<0x0028, 0x1222> SegmentedGreenPaletteColorLookupTableData; + typedef gdcm::Attribute<0x0028, 0x1223> SegmentedBluePaletteColorLookupTableData; + typedef gdcm::Attribute<0x0028, 0x1300> BreastImplantPresent; + typedef gdcm::Attribute<0x0028, 0x1350> PartialView; + typedef gdcm::Attribute<0x0028, 0x1351> PartialViewDescription; + typedef gdcm::Attribute<0x0028, 0x1352> PartialViewCodeSequence; + typedef gdcm::Attribute<0x0028, 0x135a> SpatialLocationsPreserved; + typedef gdcm::Attribute<0x0028, 0x1401> DataFrameAssignmentSequence; + typedef gdcm::Attribute<0x0028, 0x1402> DataPathAssignment; + typedef gdcm::Attribute<0x0028, 0x1403> BitsMappedToColorLookupTable; + typedef gdcm::Attribute<0x0028, 0x1404> BlendingLUT1Sequence; + typedef gdcm::Attribute<0x0028, 0x1405> BlendingLUT1TransferFunction; + typedef gdcm::Attribute<0x0028, 0x1406> BlendingWeightConstant; + typedef gdcm::Attribute<0x0028, 0x1407> BlendingLookupTableDescriptor; + typedef gdcm::Attribute<0x0028, 0x1408> BlendingLookupTableData; + typedef gdcm::Attribute<0x0028, 0x140b> EnhancedPaletteColorLookupTableSequence; + typedef gdcm::Attribute<0x0028, 0x140c> BlendingLUT2Sequence; + typedef gdcm::Attribute<0x0028, 0x140d> BlendingLUT2TransferFunction; + typedef gdcm::Attribute<0x0028, 0x140e> DataPathID; + typedef gdcm::Attribute<0x0028, 0x140f> RGBLUTTransferFunction; + typedef gdcm::Attribute<0x0028, 0x1410> AlphaLUTTransferFunction; + typedef gdcm::Attribute<0x0028, 0x2000> ICCProfile; + typedef gdcm::Attribute<0x0028, 0x2110> LossyImageCompression; + typedef gdcm::Attribute<0x0028, 0x2112> LossyImageCompressionRatio; + typedef gdcm::Attribute<0x0028, 0x2114> LossyImageCompressionMethod; + typedef gdcm::Attribute<0x0028, 0x3000> ModalityLUTSequence; + typedef gdcm::Attribute<0x0028, 0x3002> LUTDescriptor; + typedef gdcm::Attribute<0x0028, 0x3003> LUTExplanation; + typedef gdcm::Attribute<0x0028, 0x3004> ModalityLUTType; + typedef gdcm::Attribute<0x0028, 0x3006> LUTData; + typedef gdcm::Attribute<0x0028, 0x3010> VOILUTSequence; + typedef gdcm::Attribute<0x0028, 0x3110> SoftcopyVOILUTSequence; + typedef gdcm::Attribute<0x0028, 0x4000> ImagePresentationComments; + typedef gdcm::Attribute<0x0028, 0x5000> BiPlaneAcquisitionSequence; + typedef gdcm::Attribute<0x0028, 0x6010> RepresentativeFrameNumber; + typedef gdcm::Attribute<0x0028, 0x6020> FrameNumbersOfInterest; + typedef gdcm::Attribute<0x0028, 0x6022> FrameOfInterestDescription; + typedef gdcm::Attribute<0x0028, 0x6023> FrameOfInterestType; + typedef gdcm::Attribute<0x0028, 0x6030> MaskPointers; + typedef gdcm::Attribute<0x0028, 0x6040> RWavePointer; + typedef gdcm::Attribute<0x0028, 0x6100> MaskSubtractionSequence; + typedef gdcm::Attribute<0x0028, 0x6101> MaskOperation; + typedef gdcm::Attribute<0x0028, 0x6102> ApplicableFrameRange; + typedef gdcm::Attribute<0x0028, 0x6110> MaskFrameNumbers; + typedef gdcm::Attribute<0x0028, 0x6112> ContrastFrameAveraging; + typedef gdcm::Attribute<0x0028, 0x6114> MaskSubPixelShift; + typedef gdcm::Attribute<0x0028, 0x6120> TIDOffset; + typedef gdcm::Attribute<0x0028, 0x6190> MaskOperationExplanation; + typedef gdcm::Attribute<0x0028, 0x7fe0> PixelDataProviderURL; + typedef gdcm::Attribute<0x0028, 0x9001> DataPointRows; + typedef gdcm::Attribute<0x0028, 0x9002> DataPointColumns; + typedef gdcm::Attribute<0x0028, 0x9003> SignalDomainColumns; + typedef gdcm::Attribute<0x0028, 0x9099> LargestMonochromePixelValue; + typedef gdcm::Attribute<0x0028, 0x9108> DataRepresentation; + typedef gdcm::Attribute<0x0028, 0x9110> PixelMeasuresSequence; + typedef gdcm::Attribute<0x0028, 0x9132> FrameVOILUTSequence; + typedef gdcm::Attribute<0x0028, 0x9145> PixelValueTransformationSequence; + typedef gdcm::Attribute<0x0028, 0x9235> SignalDomainRows; + typedef gdcm::Attribute<0x0028, 0x9411> DisplayFilterPercentage; + typedef gdcm::Attribute<0x0028, 0x9415> FramePixelShiftSequence; + typedef gdcm::Attribute<0x0028, 0x9416> SubtractionItemID; + typedef gdcm::Attribute<0x0028, 0x9422> PixelIntensityRelationshipLUTSequence; + typedef gdcm::Attribute<0x0028, 0x9443> FramePixelDataPropertiesSequence; + typedef gdcm::Attribute<0x0028, 0x9444> GeometricalProperties; + typedef gdcm::Attribute<0x0028, 0x9445> GeometricMaximumDistortion; + typedef gdcm::Attribute<0x0028, 0x9446> ImageProcessingApplied; + typedef gdcm::Attribute<0x0028, 0x9454> MaskSelectionMode; + typedef gdcm::Attribute<0x0028, 0x9474> LUTFunction; + typedef gdcm::Attribute<0x0028, 0x9478> MaskVisibilityPercentage; + typedef gdcm::Attribute<0x0028, 0x9501> PixelShiftSequence; + typedef gdcm::Attribute<0x0028, 0x9502> RegionPixelShiftSequence; + typedef gdcm::Attribute<0x0028, 0x9503> VerticesOfTheRegion; + typedef gdcm::Attribute<0x0028, 0x9505> MultiFramePresentationSequence; + typedef gdcm::Attribute<0x0028, 0x9506> PixelShiftFrameRange; + typedef gdcm::Attribute<0x0028, 0x9507> LUTFrameRange; + typedef gdcm::Attribute<0x0028, 0x9520> ImageToEquipmentMappingMatrix; + typedef gdcm::Attribute<0x0028, 0x9537> EquipmentCoordinateSystemIdentification; + typedef gdcm::Attribute<0x0032, 0x000a> StudyStatusID; + typedef gdcm::Attribute<0x0032, 0x000c> StudyPriorityID; + typedef gdcm::Attribute<0x0032, 0x0012> StudyIDIssuer; + typedef gdcm::Attribute<0x0032, 0x0032> StudyVerifiedDate; + typedef gdcm::Attribute<0x0032, 0x0033> StudyVerifiedTime; + typedef gdcm::Attribute<0x0032, 0x0034> StudyReadDate; + typedef gdcm::Attribute<0x0032, 0x0035> StudyReadTime; + typedef gdcm::Attribute<0x0032, 0x1000> ScheduledStudyStartDate; + typedef gdcm::Attribute<0x0032, 0x1001> ScheduledStudyStartTime; + typedef gdcm::Attribute<0x0032, 0x1010> ScheduledStudyStopDate; + typedef gdcm::Attribute<0x0032, 0x1011> ScheduledStudyStopTime; + typedef gdcm::Attribute<0x0032, 0x1020> ScheduledStudyLocation; + typedef gdcm::Attribute<0x0032, 0x1021> ScheduledStudyLocationAETitle; + typedef gdcm::Attribute<0x0032, 0x1030> ReasonForStudy; + typedef gdcm::Attribute<0x0032, 0x1031> RequestingPhysicianIdentificationSequence; + typedef gdcm::Attribute<0x0032, 0x1032> RequestingPhysician; + typedef gdcm::Attribute<0x0032, 0x1033> RequestingService; + typedef gdcm::Attribute<0x0032, 0x1034> RequestingServiceCodeSequence; + typedef gdcm::Attribute<0x0032, 0x1040> StudyArrivalDate; + typedef gdcm::Attribute<0x0032, 0x1041> StudyArrivalTime; + typedef gdcm::Attribute<0x0032, 0x1050> StudyCompletionDate; + typedef gdcm::Attribute<0x0032, 0x1051> StudyCompletionTime; + typedef gdcm::Attribute<0x0032, 0x1055> StudyComponentStatusID; + typedef gdcm::Attribute<0x0032, 0x1060> RequestedProcedureDescription; + typedef gdcm::Attribute<0x0032, 0x1064> RequestedProcedureCodeSequence; + typedef gdcm::Attribute<0x0032, 0x1070> RequestedContrastAgent; + typedef gdcm::Attribute<0x0032, 0x4000> StudyComments; + typedef gdcm::Attribute<0x0038, 0x0004> ReferencedPatientAliasSequence; + typedef gdcm::Attribute<0x0038, 0x0008> VisitStatusID; + typedef gdcm::Attribute<0x0038, 0x0010> AdmissionID; + typedef gdcm::Attribute<0x0038, 0x0011> IssuerOfAdmissionID; + typedef gdcm::Attribute<0x0038, 0x0014> IssuerOfAdmissionIDSequence; + typedef gdcm::Attribute<0x0038, 0x0016> RouteOfAdmissions; + typedef gdcm::Attribute<0x0038, 0x001a> ScheduledAdmissionDate; + typedef gdcm::Attribute<0x0038, 0x001b> ScheduledAdmissionTime; + typedef gdcm::Attribute<0x0038, 0x001c> ScheduledDischargeDate; + typedef gdcm::Attribute<0x0038, 0x001d> ScheduledDischargeTime; + typedef gdcm::Attribute<0x0038, 0x001e> ScheduledPatientInstitutionResidence; + typedef gdcm::Attribute<0x0038, 0x0020> AdmittingDate; + typedef gdcm::Attribute<0x0038, 0x0021> AdmittingTime; + typedef gdcm::Attribute<0x0038, 0x0030> DischargeDate; + typedef gdcm::Attribute<0x0038, 0x0032> DischargeTime; + typedef gdcm::Attribute<0x0038, 0x0040> DischargeDiagnosisDescription; + typedef gdcm::Attribute<0x0038, 0x0044> DischargeDiagnosisCodeSequence; + typedef gdcm::Attribute<0x0038, 0x0050> SpecialNeeds; + typedef gdcm::Attribute<0x0038, 0x0060> ServiceEpisodeID; + typedef gdcm::Attribute<0x0038, 0x0061> IssuerOfServiceEpisodeID; + typedef gdcm::Attribute<0x0038, 0x0062> ServiceEpisodeDescription; + typedef gdcm::Attribute<0x0038, 0x0064> IssuerOfServiceEpisodeIDSequence; + typedef gdcm::Attribute<0x0038, 0x0100> PertinentDocumentsSequence; + typedef gdcm::Attribute<0x0038, 0x0300> CurrentPatientLocation; + typedef gdcm::Attribute<0x0038, 0x0400> PatientInstitutionResidence; + typedef gdcm::Attribute<0x0038, 0x0500> PatientState; + typedef gdcm::Attribute<0x0038, 0x0502> PatientClinicalTrialParticipationSequence; + typedef gdcm::Attribute<0x0038, 0x4000> VisitComments; + typedef gdcm::Attribute<0x003a, 0x0004> WaveformOriginality; + typedef gdcm::Attribute<0x003a, 0x0005> NumberOfWaveformChannels; + typedef gdcm::Attribute<0x003a, 0x0010> NumberOfWaveformSamples; + typedef gdcm::Attribute<0x003a, 0x001a> SamplingFrequency; + typedef gdcm::Attribute<0x003a, 0x0020> MultiplexGroupLabel; + typedef gdcm::Attribute<0x003a, 0x0200> ChannelDefinitionSequence; + typedef gdcm::Attribute<0x003a, 0x0202> WaveformChannelNumber; + typedef gdcm::Attribute<0x003a, 0x0203> ChannelLabel; + typedef gdcm::Attribute<0x003a, 0x0205> ChannelStatus; + typedef gdcm::Attribute<0x003a, 0x0208> ChannelSourceSequence; + typedef gdcm::Attribute<0x003a, 0x0209> ChannelSourceModifiersSequence; + typedef gdcm::Attribute<0x003a, 0x020a> SourceWaveformSequence; + typedef gdcm::Attribute<0x003a, 0x020c> ChannelDerivationDescription; + typedef gdcm::Attribute<0x003a, 0x0210> ChannelSensitivity; + typedef gdcm::Attribute<0x003a, 0x0211> ChannelSensitivityUnitsSequence; + typedef gdcm::Attribute<0x003a, 0x0212> ChannelSensitivityCorrectionFactor; + typedef gdcm::Attribute<0x003a, 0x0213> ChannelBaseline; + typedef gdcm::Attribute<0x003a, 0x0214> ChannelTimeSkew; + typedef gdcm::Attribute<0x003a, 0x0215> ChannelSampleSkew; + typedef gdcm::Attribute<0x003a, 0x0218> ChannelOffset; + typedef gdcm::Attribute<0x003a, 0x021a> WaveformBitsStored; + typedef gdcm::Attribute<0x003a, 0x0220> FilterLowFrequency; + typedef gdcm::Attribute<0x003a, 0x0221> FilterHighFrequency; + typedef gdcm::Attribute<0x003a, 0x0222> NotchFilterFrequency; + typedef gdcm::Attribute<0x003a, 0x0223> NotchFilterBandwidth; + typedef gdcm::Attribute<0x003a, 0x0230> WaveformDataDisplayScale; + typedef gdcm::Attribute<0x003a, 0x0231> WaveformDisplayBackgroundCIELabValue; + typedef gdcm::Attribute<0x003a, 0x0240> WaveformPresentationGroupSequence; + typedef gdcm::Attribute<0x003a, 0x0241> PresentationGroupNumber; + typedef gdcm::Attribute<0x003a, 0x0242> ChannelDisplaySequence; + typedef gdcm::Attribute<0x003a, 0x0244> ChannelRecommendedDisplayCIELabValue; + typedef gdcm::Attribute<0x003a, 0x0245> ChannelPosition; + typedef gdcm::Attribute<0x003a, 0x0246> DisplayShadingFlag; + typedef gdcm::Attribute<0x003a, 0x0247> FractionalChannelDisplayScale; + typedef gdcm::Attribute<0x003a, 0x0248> AbsoluteChannelDisplayScale; + typedef gdcm::Attribute<0x003a, 0x0300> MultiplexedAudioChannelsDescriptionCodeSequence; + typedef gdcm::Attribute<0x003a, 0x0301> ChannelIdentificationCode; + typedef gdcm::Attribute<0x003a, 0x0302> ChannelMode; + typedef gdcm::Attribute<0x0040, 0x0001> ScheduledStationAETitle; + typedef gdcm::Attribute<0x0040, 0x0002> ScheduledProcedureStepStartDate; + typedef gdcm::Attribute<0x0040, 0x0003> ScheduledProcedureStepStartTime; + typedef gdcm::Attribute<0x0040, 0x0004> ScheduledProcedureStepEndDate; + typedef gdcm::Attribute<0x0040, 0x0005> ScheduledProcedureStepEndTime; + typedef gdcm::Attribute<0x0040, 0x0006> ScheduledPerformingPhysicianName; + typedef gdcm::Attribute<0x0040, 0x0007> ScheduledProcedureStepDescription; + typedef gdcm::Attribute<0x0040, 0x0008> ScheduledProtocolCodeSequence; + typedef gdcm::Attribute<0x0040, 0x0009> ScheduledProcedureStepID; + typedef gdcm::Attribute<0x0040, 0x000a> StageCodeSequence; + typedef gdcm::Attribute<0x0040, 0x000b> ScheduledPerformingPhysicianIdentificationSequence; + typedef gdcm::Attribute<0x0040, 0x0010> ScheduledStationName; + typedef gdcm::Attribute<0x0040, 0x0011> ScheduledProcedureStepLocation; + typedef gdcm::Attribute<0x0040, 0x0012> PreMedication; + typedef gdcm::Attribute<0x0040, 0x0020> ScheduledProcedureStepStatus; + typedef gdcm::Attribute<0x0040, 0x0026> OrderPlacerIdentifierSequence; + typedef gdcm::Attribute<0x0040, 0x0027> OrderFillerIdentifierSequence; + typedef gdcm::Attribute<0x0040, 0x0031> LocalNamespaceEntityID; + typedef gdcm::Attribute<0x0040, 0x0032> UniversalEntityID; + typedef gdcm::Attribute<0x0040, 0x0033> UniversalEntityIDType; + typedef gdcm::Attribute<0x0040, 0x0035> IdentifierTypeCode; + typedef gdcm::Attribute<0x0040, 0x0036> AssigningFacilitySequence; + typedef gdcm::Attribute<0x0040, 0x0039> AssigningJurisdictionCodeSequence; + typedef gdcm::Attribute<0x0040, 0x003a> AssigningAgencyOrDepartmentCodeSequence; + typedef gdcm::Attribute<0x0040, 0x0100> ScheduledProcedureStepSequence; + typedef gdcm::Attribute<0x0040, 0x0220> ReferencedNonImageCompositeSOPInstanceSequence; + typedef gdcm::Attribute<0x0040, 0x0241> PerformedStationAETitle; + typedef gdcm::Attribute<0x0040, 0x0242> PerformedStationName; + typedef gdcm::Attribute<0x0040, 0x0243> PerformedLocation; + typedef gdcm::Attribute<0x0040, 0x0244> PerformedProcedureStepStartDate; + typedef gdcm::Attribute<0x0040, 0x0245> PerformedProcedureStepStartTime; + typedef gdcm::Attribute<0x0040, 0x0250> PerformedProcedureStepEndDate; + typedef gdcm::Attribute<0x0040, 0x0251> PerformedProcedureStepEndTime; + typedef gdcm::Attribute<0x0040, 0x0252> PerformedProcedureStepStatus; + typedef gdcm::Attribute<0x0040, 0x0253> PerformedProcedureStepID; + typedef gdcm::Attribute<0x0040, 0x0254> PerformedProcedureStepDescription; + typedef gdcm::Attribute<0x0040, 0x0255> PerformedProcedureTypeDescription; + typedef gdcm::Attribute<0x0040, 0x0260> PerformedProtocolCodeSequence; + typedef gdcm::Attribute<0x0040, 0x0261> PerformedProtocolType; + typedef gdcm::Attribute<0x0040, 0x0270> ScheduledStepAttributesSequence; + typedef gdcm::Attribute<0x0040, 0x0275> RequestAttributesSequence; + typedef gdcm::Attribute<0x0040, 0x0280> CommentsOnThePerformedProcedureStep; + typedef gdcm::Attribute<0x0040, 0x0281> PerformedProcedureStepDiscontinuationReasonCodeSequence; + typedef gdcm::Attribute<0x0040, 0x0293> QuantitySequence; + typedef gdcm::Attribute<0x0040, 0x0294> Quantity; + typedef gdcm::Attribute<0x0040, 0x0295> MeasuringUnitsSequence; + typedef gdcm::Attribute<0x0040, 0x0296> BillingItemSequence; + typedef gdcm::Attribute<0x0040, 0x0300> TotalTimeOfFluoroscopy; + typedef gdcm::Attribute<0x0040, 0x0301> TotalNumberOfExposures; + typedef gdcm::Attribute<0x0040, 0x0302> EntranceDose; + typedef gdcm::Attribute<0x0040, 0x0303> ExposedArea; + typedef gdcm::Attribute<0x0040, 0x0306> DistanceSourceToEntrance; + typedef gdcm::Attribute<0x0040, 0x0307> DistanceSourceToSupport; + typedef gdcm::Attribute<0x0040, 0x030e> ExposureDoseSequence; + typedef gdcm::Attribute<0x0040, 0x0310> CommentsOnRadiationDose; + typedef gdcm::Attribute<0x0040, 0x0312> XRayOutput; + typedef gdcm::Attribute<0x0040, 0x0314> HalfValueLayer; + typedef gdcm::Attribute<0x0040, 0x0316> OrganDose; + typedef gdcm::Attribute<0x0040, 0x0318> OrganExposed; + typedef gdcm::Attribute<0x0040, 0x0320> BillingProcedureStepSequence; + typedef gdcm::Attribute<0x0040, 0x0321> FilmConsumptionSequence; + typedef gdcm::Attribute<0x0040, 0x0324> BillingSuppliesAndDevicesSequence; + typedef gdcm::Attribute<0x0040, 0x0330> ReferencedProcedureStepSequence; + typedef gdcm::Attribute<0x0040, 0x0340> PerformedSeriesSequence; + typedef gdcm::Attribute<0x0040, 0x0400> CommentsOnTheScheduledProcedureStep; + typedef gdcm::Attribute<0x0040, 0x0440> ProtocolContextSequence; + typedef gdcm::Attribute<0x0040, 0x0441> ContentItemModifierSequence; + typedef gdcm::Attribute<0x0040, 0x0500> ScheduledSpecimenSequence; + typedef gdcm::Attribute<0x0040, 0x050a> SpecimenAccessionNumber; + typedef gdcm::Attribute<0x0040, 0x0512> ContainerIdentifier; + typedef gdcm::Attribute<0x0040, 0x0513> IssuerOfTheContainerIdentifierSequence; + typedef gdcm::Attribute<0x0040, 0x0515> AlternateContainerIdentifierSequence; + typedef gdcm::Attribute<0x0040, 0x0518> ContainerTypeCodeSequence; + typedef gdcm::Attribute<0x0040, 0x051a> ContainerDescription; + typedef gdcm::Attribute<0x0040, 0x0520> ContainerComponentSequence; + typedef gdcm::Attribute<0x0040, 0x0550> SpecimenSequence; + typedef gdcm::Attribute<0x0040, 0x0551> SpecimenIdentifier; + typedef gdcm::Attribute<0x0040, 0x0552> SpecimenDescriptionSequenceTrial; + typedef gdcm::Attribute<0x0040, 0x0553> SpecimenDescriptionTrial; + typedef gdcm::Attribute<0x0040, 0x0554> SpecimenUID; + typedef gdcm::Attribute<0x0040, 0x0555> AcquisitionContextSequence; + typedef gdcm::Attribute<0x0040, 0x0556> AcquisitionContextDescription; + typedef gdcm::Attribute<0x0040, 0x059a> SpecimenTypeCodeSequence; + typedef gdcm::Attribute<0x0040, 0x0560> SpecimenDescriptionSequence; + typedef gdcm::Attribute<0x0040, 0x0562> IssuerOfTheSpecimenIdentifierSequence; + typedef gdcm::Attribute<0x0040, 0x0600> SpecimenShortDescription; + typedef gdcm::Attribute<0x0040, 0x0602> SpecimenDetailedDescription; + typedef gdcm::Attribute<0x0040, 0x0610> SpecimenPreparationSequence; + typedef gdcm::Attribute<0x0040, 0x0612> SpecimenPreparationStepContentItemSequence; + typedef gdcm::Attribute<0x0040, 0x0620> SpecimenLocalizationContentItemSequence; + typedef gdcm::Attribute<0x0040, 0x06fa> SlideIdentifier; + typedef gdcm::Attribute<0x0040, 0x071a> ImageCenterPointCoordinatesSequence; + typedef gdcm::Attribute<0x0040, 0x072a> XOffsetInSlideCoordinateSystem; + typedef gdcm::Attribute<0x0040, 0x073a> YOffsetInSlideCoordinateSystem; + typedef gdcm::Attribute<0x0040, 0x074a> ZOffsetInSlideCoordinateSystem; + typedef gdcm::Attribute<0x0040, 0x08d8> PixelSpacingSequence; + typedef gdcm::Attribute<0x0040, 0x08da> CoordinateSystemAxisCodeSequence; + typedef gdcm::Attribute<0x0040, 0x08ea> MeasurementUnitsCodeSequence; + typedef gdcm::Attribute<0x0040, 0x09f8> VitalStainCodeSequenceTrial; + typedef gdcm::Attribute<0x0040, 0x1001> RequestedProcedureID; + typedef gdcm::Attribute<0x0040, 0x1002> ReasonForTheRequestedProcedure; + typedef gdcm::Attribute<0x0040, 0x1003> RequestedProcedurePriority; + typedef gdcm::Attribute<0x0040, 0x1004> PatientTransportArrangements; + typedef gdcm::Attribute<0x0040, 0x1005> RequestedProcedureLocation; + typedef gdcm::Attribute<0x0040, 0x1006> PlacerOrderNumberProcedure; + typedef gdcm::Attribute<0x0040, 0x1007> FillerOrderNumberProcedure; + typedef gdcm::Attribute<0x0040, 0x1008> ConfidentialityCode; + typedef gdcm::Attribute<0x0040, 0x1009> ReportingPriority; + typedef gdcm::Attribute<0x0040, 0x100a> ReasonForRequestedProcedureCodeSequence; + typedef gdcm::Attribute<0x0040, 0x1010> NamesOfIntendedRecipientsOfResults; + typedef gdcm::Attribute<0x0040, 0x1011> IntendedRecipientsOfResultsIdentificationSequence; + typedef gdcm::Attribute<0x0040, 0x1012> ReasonForPerformedProcedureCodeSequence; + typedef gdcm::Attribute<0x0040, 0x1060> RequestedProcedureDescriptionTrial; + typedef gdcm::Attribute<0x0040, 0x1101> PersonIdentificationCodeSequence; + typedef gdcm::Attribute<0x0040, 0x1102> PersonAddress; + typedef gdcm::Attribute<0x0040, 0x1103> PersonTelephoneNumbers; + typedef gdcm::Attribute<0x0040, 0x1400> RequestedProcedureComments; + typedef gdcm::Attribute<0x0040, 0x2001> ReasonForTheImagingServiceRequest; + typedef gdcm::Attribute<0x0040, 0x2004> IssueDateOfImagingServiceRequest; + typedef gdcm::Attribute<0x0040, 0x2005> IssueTimeOfImagingServiceRequest; + typedef gdcm::Attribute<0x0040, 0x2006> PlacerOrderNumberImagingServiceRequestRetired; + typedef gdcm::Attribute<0x0040, 0x2007> FillerOrderNumberImagingServiceRequestRetired; + typedef gdcm::Attribute<0x0040, 0x2008> OrderEnteredBy; + typedef gdcm::Attribute<0x0040, 0x2009> OrderEntererLocation; + typedef gdcm::Attribute<0x0040, 0x2010> OrderCallbackPhoneNumber; + typedef gdcm::Attribute<0x0040, 0x2016> PlacerOrderNumberImagingServiceRequest; + typedef gdcm::Attribute<0x0040, 0x2017> FillerOrderNumberImagingServiceRequest; + typedef gdcm::Attribute<0x0040, 0x2400> ImagingServiceRequestComments; + typedef gdcm::Attribute<0x0040, 0x3001> ConfidentialityConstraintOnPatientDataDescription; + typedef gdcm::Attribute<0x0040, 0x4001> GeneralPurposeScheduledProcedureStepStatus; + typedef gdcm::Attribute<0x0040, 0x4002> GeneralPurposePerformedProcedureStepStatus; + typedef gdcm::Attribute<0x0040, 0x4003> GeneralPurposeScheduledProcedureStepPriority; + typedef gdcm::Attribute<0x0040, 0x4004> ScheduledProcessingApplicationsCodeSequence; + typedef gdcm::Attribute<0x0040, 0x4005> ScheduledProcedureStepStartDateTime; + typedef gdcm::Attribute<0x0040, 0x4006> MultipleCopiesFlag; + typedef gdcm::Attribute<0x0040, 0x4007> PerformedProcessingApplicationsCodeSequence; + typedef gdcm::Attribute<0x0040, 0x4009> HumanPerformerCodeSequence; + typedef gdcm::Attribute<0x0040, 0x4010> ScheduledProcedureStepModificationDateTime; + typedef gdcm::Attribute<0x0040, 0x4011> ExpectedCompletionDateTime; + typedef gdcm::Attribute<0x0040, 0x4015> ResultingGeneralPurposePerformedProcedureStepsSequence; + typedef gdcm::Attribute<0x0040, 0x4016> ReferencedGeneralPurposeScheduledProcedureStepSequence; + typedef gdcm::Attribute<0x0040, 0x4018> ScheduledWorkitemCodeSequence; + typedef gdcm::Attribute<0x0040, 0x4019> PerformedWorkitemCodeSequence; + typedef gdcm::Attribute<0x0040, 0x4020> InputAvailabilityFlag; + typedef gdcm::Attribute<0x0040, 0x4021> InputInformationSequence; + typedef gdcm::Attribute<0x0040, 0x4022> RelevantInformationSequence; + typedef gdcm::Attribute<0x0040, 0x4023> ReferencedGeneralPurposeScheduledProcedureStepTransactionUID; + typedef gdcm::Attribute<0x0040, 0x4025> ScheduledStationNameCodeSequence; + typedef gdcm::Attribute<0x0040, 0x4026> ScheduledStationClassCodeSequence; + typedef gdcm::Attribute<0x0040, 0x4027> ScheduledStationGeographicLocationCodeSequence; + typedef gdcm::Attribute<0x0040, 0x4028> PerformedStationNameCodeSequence; + typedef gdcm::Attribute<0x0040, 0x4029> PerformedStationClassCodeSequence; + typedef gdcm::Attribute<0x0040, 0x4030> PerformedStationGeographicLocationCodeSequence; + typedef gdcm::Attribute<0x0040, 0x4031> RequestedSubsequentWorkitemCodeSequence; + typedef gdcm::Attribute<0x0040, 0x4032> NonDICOMOutputCodeSequence; + typedef gdcm::Attribute<0x0040, 0x4033> OutputInformationSequence; + typedef gdcm::Attribute<0x0040, 0x4034> ScheduledHumanPerformersSequence; + typedef gdcm::Attribute<0x0040, 0x4035> ActualHumanPerformersSequence; + typedef gdcm::Attribute<0x0040, 0x4036> HumanPerformerOrganization; + typedef gdcm::Attribute<0x0040, 0x4037> HumanPerformerName; + typedef gdcm::Attribute<0x0040, 0x4040> RawDataHandling; + typedef gdcm::Attribute<0x0040, 0x4041> InputReadinessState; + typedef gdcm::Attribute<0x0040, 0x4050> PerformedProcedureStepStartDateTime; + typedef gdcm::Attribute<0x0040, 0x4051> PerformedProcedureStepEndDateTime; + typedef gdcm::Attribute<0x0040, 0x4052> ProcedureStepCancellationDateTime; + typedef gdcm::Attribute<0x0040, 0x8302> EntranceDoseInmGy; + typedef gdcm::Attribute<0x0040, 0x9094> ReferencedImageRealWorldValueMappingSequence; + typedef gdcm::Attribute<0x0040, 0x9096> RealWorldValueMappingSequence; + typedef gdcm::Attribute<0x0040, 0x9098> PixelValueMappingCodeSequence; + typedef gdcm::Attribute<0x0040, 0x9210> LUTLabel; + typedef gdcm::Attribute<0x0040, 0x9211> RealWorldValueLastValueMapped; + typedef gdcm::Attribute<0x0040, 0x9212> RealWorldValueLUTData; + typedef gdcm::Attribute<0x0040, 0x9216> RealWorldValueFirstValueMapped; + typedef gdcm::Attribute<0x0040, 0x9224> RealWorldValueIntercept; + typedef gdcm::Attribute<0x0040, 0x9225> RealWorldValueSlope; + typedef gdcm::Attribute<0x0040, 0xa007> FindingsFlagTrial; + typedef gdcm::Attribute<0x0040, 0xa010> RelationshipType; + typedef gdcm::Attribute<0x0040, 0xa020> FindingsSequenceTrial; + typedef gdcm::Attribute<0x0040, 0xa021> FindingsGroupUIDTrial; + typedef gdcm::Attribute<0x0040, 0xa022> ReferencedFindingsGroupUIDTrial; + typedef gdcm::Attribute<0x0040, 0xa023> FindingsGroupRecordingDateTrial; + typedef gdcm::Attribute<0x0040, 0xa024> FindingsGroupRecordingTimeTrial; + typedef gdcm::Attribute<0x0040, 0xa026> FindingsSourceCategoryCodeSequenceTrial; + typedef gdcm::Attribute<0x0040, 0xa027> VerifyingOrganization; + typedef gdcm::Attribute<0x0040, 0xa028> DocumentingOrganizationIdentifierCodeSequenceTrial; + typedef gdcm::Attribute<0x0040, 0xa030> VerificationDateTime; + typedef gdcm::Attribute<0x0040, 0xa032> ObservationDateTime; + typedef gdcm::Attribute<0x0040, 0xa040> ValueType; + typedef gdcm::Attribute<0x0040, 0xa043> ConceptNameCodeSequence; + typedef gdcm::Attribute<0x0040, 0xa047> MeasurementPrecisionDescriptionTrial; + typedef gdcm::Attribute<0x0040, 0xa050> ContinuityOfContent; + typedef gdcm::Attribute<0x0040, 0xa057> UrgencyOrPriorityAlertsTrial; + typedef gdcm::Attribute<0x0040, 0xa060> SequencingIndicatorTrial; + typedef gdcm::Attribute<0x0040, 0xa066> DocumentIdentifierCodeSequenceTrial; + typedef gdcm::Attribute<0x0040, 0xa067> DocumentAuthorTrial; + typedef gdcm::Attribute<0x0040, 0xa068> DocumentAuthorIdentifierCodeSequenceTrial; + typedef gdcm::Attribute<0x0040, 0xa070> IdentifierCodeSequenceTrial; + typedef gdcm::Attribute<0x0040, 0xa073> VerifyingObserverSequence; + typedef gdcm::Attribute<0x0040, 0xa074> ObjectBinaryIdentifierTrial; + typedef gdcm::Attribute<0x0040, 0xa075> VerifyingObserverName; + typedef gdcm::Attribute<0x0040, 0xa076> DocumentingObserverIdentifierCodeSequenceTrial; + typedef gdcm::Attribute<0x0040, 0xa078> AuthorObserverSequence; + typedef gdcm::Attribute<0x0040, 0xa07a> ParticipantSequence; + typedef gdcm::Attribute<0x0040, 0xa07c> CustodialOrganizationSequence; + typedef gdcm::Attribute<0x0040, 0xa080> ParticipationType; + typedef gdcm::Attribute<0x0040, 0xa082> ParticipationDateTime; + typedef gdcm::Attribute<0x0040, 0xa084> ObserverType; + typedef gdcm::Attribute<0x0040, 0xa085> ProcedureIdentifierCodeSequenceTrial; + typedef gdcm::Attribute<0x0040, 0xa088> VerifyingObserverIdentificationCodeSequence; + typedef gdcm::Attribute<0x0040, 0xa089> ObjectDirectoryBinaryIdentifierTrial; + typedef gdcm::Attribute<0x0040, 0xa090> EquivalentCDADocumentSequence; + typedef gdcm::Attribute<0x0040, 0xa0b0> ReferencedWaveformChannels; + typedef gdcm::Attribute<0x0040, 0xa110> DateOfDocumentOrVerbalTransactionTrial; + typedef gdcm::Attribute<0x0040, 0xa112> TimeOfDocumentCreationOrVerbalTransactionTrial; + typedef gdcm::Attribute<0x0040, 0xa120> DateTime; + typedef gdcm::Attribute<0x0040, 0xa121> Date; + typedef gdcm::Attribute<0x0040, 0xa122> Time; + typedef gdcm::Attribute<0x0040, 0xa123> PersonName; + typedef gdcm::Attribute<0x0040, 0xa124> UID; + typedef gdcm::Attribute<0x0040, 0xa125> ReportStatusIDTrial; + typedef gdcm::Attribute<0x0040, 0xa130> TemporalRangeType; + typedef gdcm::Attribute<0x0040, 0xa132> ReferencedSamplePositions; + typedef gdcm::Attribute<0x0040, 0xa136> ReferencedFrameNumbers; + typedef gdcm::Attribute<0x0040, 0xa138> ReferencedTimeOffsets; + typedef gdcm::Attribute<0x0040, 0xa13a> ReferencedDateTime; + typedef gdcm::Attribute<0x0040, 0xa160> TextValue; + typedef gdcm::Attribute<0x0040, 0xa167> ObservationCategoryCodeSequenceTrial; + typedef gdcm::Attribute<0x0040, 0xa168> ConceptCodeSequence; + typedef gdcm::Attribute<0x0040, 0xa16a> BibliographicCitationTrial; + typedef gdcm::Attribute<0x0040, 0xa170> PurposeOfReferenceCodeSequence; + typedef gdcm::Attribute<0x0040, 0xa171> ObservationUIDTrial; + typedef gdcm::Attribute<0x0040, 0xa172> ReferencedObservationUIDTrial; + typedef gdcm::Attribute<0x0040, 0xa173> ReferencedObservationClassTrial; + typedef gdcm::Attribute<0x0040, 0xa174> ReferencedObjectObservationClassTrial; + typedef gdcm::Attribute<0x0040, 0xa180> AnnotationGroupNumber; + typedef gdcm::Attribute<0x0040, 0xa192> ObservationDateTrial; + typedef gdcm::Attribute<0x0040, 0xa193> ObservationTimeTrial; + typedef gdcm::Attribute<0x0040, 0xa194> MeasurementAutomationTrial; + typedef gdcm::Attribute<0x0040, 0xa195> ModifierCodeSequence; + typedef gdcm::Attribute<0x0040, 0xa224> IdentificationDescriptionTrial; + typedef gdcm::Attribute<0x0040, 0xa290> CoordinatesSetGeometricTypeTrial; + typedef gdcm::Attribute<0x0040, 0xa296> AlgorithmCodeSequenceTrial; + typedef gdcm::Attribute<0x0040, 0xa297> AlgorithmDescriptionTrial; + typedef gdcm::Attribute<0x0040, 0xa29a> PixelCoordinatesSetTrial; + typedef gdcm::Attribute<0x0040, 0xa300> MeasuredValueSequence; + typedef gdcm::Attribute<0x0040, 0xa301> NumericValueQualifierCodeSequence; + typedef gdcm::Attribute<0x0040, 0xa307> CurrentObserverTrial; + typedef gdcm::Attribute<0x0040, 0xa30a> NumericValue; + typedef gdcm::Attribute<0x0040, 0xa313> ReferencedAccessionSequenceTrial; + typedef gdcm::Attribute<0x0040, 0xa33a> ReportStatusCommentTrial; + typedef gdcm::Attribute<0x0040, 0xa340> ProcedureContextSequenceTrial; + typedef gdcm::Attribute<0x0040, 0xa352> VerbalSourceTrial; + typedef gdcm::Attribute<0x0040, 0xa353> AddressTrial; + typedef gdcm::Attribute<0x0040, 0xa354> TelephoneNumberTrial; + typedef gdcm::Attribute<0x0040, 0xa358> VerbalSourceIdentifierCodeSequenceTrial; + typedef gdcm::Attribute<0x0040, 0xa360> PredecessorDocumentsSequence; + typedef gdcm::Attribute<0x0040, 0xa370> ReferencedRequestSequence; + typedef gdcm::Attribute<0x0040, 0xa372> PerformedProcedureCodeSequence; + typedef gdcm::Attribute<0x0040, 0xa375> CurrentRequestedProcedureEvidenceSequence; + typedef gdcm::Attribute<0x0040, 0xa380> ReportDetailSequenceTrial; + typedef gdcm::Attribute<0x0040, 0xa385> PertinentOtherEvidenceSequence; + typedef gdcm::Attribute<0x0040, 0xa390> HL7StructuredDocumentReferenceSequence; + typedef gdcm::Attribute<0x0040, 0xa402> ObservationSubjectUIDTrial; + typedef gdcm::Attribute<0x0040, 0xa403> ObservationSubjectClassTrial; + typedef gdcm::Attribute<0x0040, 0xa404> ObservationSubjectTypeCodeSequenceTrial; + typedef gdcm::Attribute<0x0040, 0xa491> CompletionFlag; + typedef gdcm::Attribute<0x0040, 0xa492> CompletionFlagDescription; + typedef gdcm::Attribute<0x0040, 0xa493> VerificationFlag; + typedef gdcm::Attribute<0x0040, 0xa494> ArchiveRequested; + typedef gdcm::Attribute<0x0040, 0xa496> PreliminaryFlag; + typedef gdcm::Attribute<0x0040, 0xa504> ContentTemplateSequence; + typedef gdcm::Attribute<0x0040, 0xa525> IdenticalDocumentsSequence; + typedef gdcm::Attribute<0x0040, 0xa600> ObservationSubjectContextFlagTrial; + typedef gdcm::Attribute<0x0040, 0xa601> ObserverContextFlagTrial; + typedef gdcm::Attribute<0x0040, 0xa603> ProcedureContextFlagTrial; + typedef gdcm::Attribute<0x0040, 0xa730> ContentSequence; + typedef gdcm::Attribute<0x0040, 0xa731> RelationshipSequenceTrial; + typedef gdcm::Attribute<0x0040, 0xa732> RelationshipTypeCodeSequenceTrial; + typedef gdcm::Attribute<0x0040, 0xa744> LanguageCodeSequenceTrial; + typedef gdcm::Attribute<0x0040, 0xa992> UniformResourceLocatorTrial; + typedef gdcm::Attribute<0x0040, 0xb020> WaveformAnnotationSequence; + typedef gdcm::Attribute<0x0040, 0xdb00> TemplateIdentifier; + typedef gdcm::Attribute<0x0040, 0xdb06> TemplateVersion; + typedef gdcm::Attribute<0x0040, 0xdb07> TemplateLocalVersion; + typedef gdcm::Attribute<0x0040, 0xdb0b> TemplateExtensionFlag; + typedef gdcm::Attribute<0x0040, 0xdb0c> TemplateExtensionOrganizationUID; + typedef gdcm::Attribute<0x0040, 0xdb0d> TemplateExtensionCreatorUID; + typedef gdcm::Attribute<0x0040, 0xdb73> ReferencedContentItemIdentifier; + typedef gdcm::Attribute<0x0040, 0xe001> HL7InstanceIdentifier; + typedef gdcm::Attribute<0x0040, 0xe004> HL7DocumentEffectiveTime; + typedef gdcm::Attribute<0x0040, 0xe006> HL7DocumentTypeCodeSequence; + typedef gdcm::Attribute<0x0040, 0xe008> DocumentClassCodeSequence; + typedef gdcm::Attribute<0x0040, 0xe010> RetrieveURI; + typedef gdcm::Attribute<0x0040, 0xe011> RetrieveLocationUID; + typedef gdcm::Attribute<0x0040, 0xe020> TypeOfInstances; + typedef gdcm::Attribute<0x0040, 0xe021> DICOMRetrievalSequence; + typedef gdcm::Attribute<0x0040, 0xe022> DICOMMediaRetrievalSequence; + typedef gdcm::Attribute<0x0040, 0xe023> WADORetrievalSequence; + typedef gdcm::Attribute<0x0040, 0xe024> XDSRetrievalSequence; + typedef gdcm::Attribute<0x0040, 0xe030> RepositoryUniqueID; + typedef gdcm::Attribute<0x0040, 0xe031> HomeCommunityID; + typedef gdcm::Attribute<0x0042, 0x0010> DocumentTitle; + typedef gdcm::Attribute<0x0042, 0x0011> EncapsulatedDocument; + typedef gdcm::Attribute<0x0042, 0x0012> MIMETypeOfEncapsulatedDocument; + typedef gdcm::Attribute<0x0042, 0x0013> SourceInstanceSequence; + typedef gdcm::Attribute<0x0042, 0x0014> ListOfMIMETypes; + typedef gdcm::Attribute<0x0044, 0x0001> ProductPackageIdentifier; + typedef gdcm::Attribute<0x0044, 0x0002> SubstanceAdministrationApproval; + typedef gdcm::Attribute<0x0044, 0x0003> ApprovalStatusFurtherDescription; + typedef gdcm::Attribute<0x0044, 0x0004> ApprovalStatusDateTime; + typedef gdcm::Attribute<0x0044, 0x0007> ProductTypeCodeSequence; + typedef gdcm::Attribute<0x0044, 0x0008> ProductName; + typedef gdcm::Attribute<0x0044, 0x0009> ProductDescription; + typedef gdcm::Attribute<0x0044, 0x000a> ProductLotIdentifier; + typedef gdcm::Attribute<0x0044, 0x000b> ProductExpirationDateTime; + typedef gdcm::Attribute<0x0044, 0x0010> SubstanceAdministrationDateTime; + typedef gdcm::Attribute<0x0044, 0x0011> SubstanceAdministrationNotes; + typedef gdcm::Attribute<0x0044, 0x0012> SubstanceAdministrationDeviceID; + typedef gdcm::Attribute<0x0044, 0x0013> ProductParameterSequence; + typedef gdcm::Attribute<0x0044, 0x0019> SubstanceAdministrationParameterSequence; + typedef gdcm::Attribute<0x0046, 0x0012> LensDescription; + typedef gdcm::Attribute<0x0046, 0x0014> RightLensSequence; + typedef gdcm::Attribute<0x0046, 0x0015> LeftLensSequence; + typedef gdcm::Attribute<0x0046, 0x0016> UnspecifiedLateralityLensSequence; + typedef gdcm::Attribute<0x0046, 0x0018> CylinderSequence; + typedef gdcm::Attribute<0x0046, 0x0028> PrismSequence; + typedef gdcm::Attribute<0x0046, 0x0030> HorizontalPrismPower; + typedef gdcm::Attribute<0x0046, 0x0032> HorizontalPrismBase; + typedef gdcm::Attribute<0x0046, 0x0034> VerticalPrismPower; + typedef gdcm::Attribute<0x0046, 0x0036> VerticalPrismBase; + typedef gdcm::Attribute<0x0046, 0x0038> LensSegmentType; + typedef gdcm::Attribute<0x0046, 0x0040> OpticalTransmittance; + typedef gdcm::Attribute<0x0046, 0x0042> ChannelWidth; + typedef gdcm::Attribute<0x0046, 0x0044> PupilSize; + typedef gdcm::Attribute<0x0046, 0x0046> CornealSize; + typedef gdcm::Attribute<0x0046, 0x0050> AutorefractionRightEyeSequence; + typedef gdcm::Attribute<0x0046, 0x0052> AutorefractionLeftEyeSequence; + typedef gdcm::Attribute<0x0046, 0x0060> DistancePupillaryDistance; + typedef gdcm::Attribute<0x0046, 0x0062> NearPupillaryDistance; + typedef gdcm::Attribute<0x0046, 0x0063> IntermediatePupillaryDistance; + typedef gdcm::Attribute<0x0046, 0x0064> OtherPupillaryDistance; + typedef gdcm::Attribute<0x0046, 0x0070> KeratometryRightEyeSequence; + typedef gdcm::Attribute<0x0046, 0x0071> KeratometryLeftEyeSequence; + typedef gdcm::Attribute<0x0046, 0x0074> SteepKeratometricAxisSequence; + typedef gdcm::Attribute<0x0046, 0x0075> RadiusOfCurvature; + typedef gdcm::Attribute<0x0046, 0x0076> KeratometricPower; + typedef gdcm::Attribute<0x0046, 0x0077> KeratometricAxis; + typedef gdcm::Attribute<0x0046, 0x0080> FlatKeratometricAxisSequence; + typedef gdcm::Attribute<0x0046, 0x0092> BackgroundColor; + typedef gdcm::Attribute<0x0046, 0x0094> Optotype; + typedef gdcm::Attribute<0x0046, 0x0095> OptotypePresentation; + typedef gdcm::Attribute<0x0046, 0x0097> SubjectiveRefractionRightEyeSequence; + typedef gdcm::Attribute<0x0046, 0x0098> SubjectiveRefractionLeftEyeSequence; + typedef gdcm::Attribute<0x0046, 0x0100> AddNearSequence; + typedef gdcm::Attribute<0x0046, 0x0101> AddIntermediateSequence; + typedef gdcm::Attribute<0x0046, 0x0102> AddOtherSequence; + typedef gdcm::Attribute<0x0046, 0x0104> AddPower; + typedef gdcm::Attribute<0x0046, 0x0106> ViewingDistance; + typedef gdcm::Attribute<0x0046, 0x0121> VisualAcuityTypeCodeSequence; + typedef gdcm::Attribute<0x0046, 0x0122> VisualAcuityRightEyeSequence; + typedef gdcm::Attribute<0x0046, 0x0123> VisualAcuityLeftEyeSequence; + typedef gdcm::Attribute<0x0046, 0x0124> VisualAcuityBothEyesOpenSequence; + typedef gdcm::Attribute<0x0046, 0x0125> ViewingDistanceType; + typedef gdcm::Attribute<0x0046, 0x0135> VisualAcuityModifiers; + typedef gdcm::Attribute<0x0046, 0x0137> DecimalVisualAcuity; + typedef gdcm::Attribute<0x0046, 0x0139> OptotypeDetailedDefinition; + typedef gdcm::Attribute<0x0046, 0x0145> ReferencedRefractiveMeasurementsSequence; + typedef gdcm::Attribute<0x0046, 0x0146> SpherePower; + typedef gdcm::Attribute<0x0046, 0x0147> CylinderPower; + typedef gdcm::Attribute<0x0048, 0x0001> ImagedVolumeWidth; + typedef gdcm::Attribute<0x0048, 0x0002> ImagedVolumeHeight; + typedef gdcm::Attribute<0x0048, 0x0003> ImagedVolumeDepth; + typedef gdcm::Attribute<0x0048, 0x0006> TotalPixelMatrixColumns; + typedef gdcm::Attribute<0x0048, 0x0007> TotalPixelMatrixRows; + typedef gdcm::Attribute<0x0048, 0x0008> TotalPixelMatrixOriginSequence; + typedef gdcm::Attribute<0x0048, 0x0010> SpecimenLabelInImage; + typedef gdcm::Attribute<0x0048, 0x0011> FocusMethod; + typedef gdcm::Attribute<0x0048, 0x0012> ExtendedDepthOfField; + typedef gdcm::Attribute<0x0048, 0x0013> NumberOfFocalPlanes; + typedef gdcm::Attribute<0x0048, 0x0014> DistanceBetweenFocalPlanes; + typedef gdcm::Attribute<0x0048, 0x0015> RecommendedAbsentPixelCIELabValue; + typedef gdcm::Attribute<0x0048, 0x0100> IlluminatorTypeCodeSequence; + typedef gdcm::Attribute<0x0048, 0x0102> ImageOrientationSlide; + typedef gdcm::Attribute<0x0048, 0x0105> OpticalPathSequence; + typedef gdcm::Attribute<0x0048, 0x0106> OpticalPathIdentifier; + typedef gdcm::Attribute<0x0048, 0x0107> OpticalPathDescription; + typedef gdcm::Attribute<0x0048, 0x0108> IlluminationColorCodeSequence; + typedef gdcm::Attribute<0x0048, 0x0110> SpecimenReferenceSequence; + typedef gdcm::Attribute<0x0048, 0x0111> CondenserLensPower; + typedef gdcm::Attribute<0x0048, 0x0112> ObjectiveLensPower; + typedef gdcm::Attribute<0x0048, 0x0113> ObjectiveLensNumericalAperture; + typedef gdcm::Attribute<0x0048, 0x0120> PaletteColorLookupTableSequence; + typedef gdcm::Attribute<0x0048, 0x0200> ReferencedImageNavigationSequence; + typedef gdcm::Attribute<0x0048, 0x0201> TopLeftHandCornerOfLocalizerArea; + typedef gdcm::Attribute<0x0048, 0x0202> BottomRightHandCornerOfLocalizerArea; + typedef gdcm::Attribute<0x0048, 0x0207> OpticalPathIdentificationSequence; + typedef gdcm::Attribute<0x0048, 0x021a> PlanePositionSlideSequence; + typedef gdcm::Attribute<0x0048, 0x021e> ColumnPositionInTotalImagePixelMatrix; + typedef gdcm::Attribute<0x0048, 0x021f> RowPositionInTotalImagePixelMatrix; + typedef gdcm::Attribute<0x0048, 0x0301> PixelOriginInterpretation; + typedef gdcm::Attribute<0x0050, 0x0004> CalibrationImage; + typedef gdcm::Attribute<0x0050, 0x0010> DeviceSequence; + typedef gdcm::Attribute<0x0050, 0x0012> ContainerComponentTypeCodeSequence; + typedef gdcm::Attribute<0x0050, 0x0013> ContainerComponentThickness; + typedef gdcm::Attribute<0x0050, 0x0014> DeviceLength; + typedef gdcm::Attribute<0x0050, 0x0015> ContainerComponentWidth; + typedef gdcm::Attribute<0x0050, 0x0016> DeviceDiameter; + typedef gdcm::Attribute<0x0050, 0x0017> DeviceDiameterUnits; + typedef gdcm::Attribute<0x0050, 0x0018> DeviceVolume; + typedef gdcm::Attribute<0x0050, 0x0019> InterMarkerDistance; + typedef gdcm::Attribute<0x0050, 0x001a> ContainerComponentMaterial; + typedef gdcm::Attribute<0x0050, 0x001b> ContainerComponentID; + typedef gdcm::Attribute<0x0050, 0x001c> ContainerComponentLength; + typedef gdcm::Attribute<0x0050, 0x001d> ContainerComponentDiameter; + typedef gdcm::Attribute<0x0050, 0x001e> ContainerComponentDescription; + typedef gdcm::Attribute<0x0050, 0x0020> DeviceDescription; + typedef gdcm::Attribute<0x0052, 0x0001> ContrastBolusIngredientPercentByVolume; + typedef gdcm::Attribute<0x0052, 0x0002> OCTFocalDistance; + typedef gdcm::Attribute<0x0052, 0x0003> BeamSpotSize; + typedef gdcm::Attribute<0x0052, 0x0004> EffectiveRefractiveIndex; + typedef gdcm::Attribute<0x0052, 0x0006> OCTAcquisitionDomain; + typedef gdcm::Attribute<0x0052, 0x0007> OCTOpticalCenterWavelength; + typedef gdcm::Attribute<0x0052, 0x0008> AxialResolution; + typedef gdcm::Attribute<0x0052, 0x0009> RangingDepth; + typedef gdcm::Attribute<0x0052, 0x0011> ALineRate; + typedef gdcm::Attribute<0x0052, 0x0012> ALinesPerFrame; + typedef gdcm::Attribute<0x0052, 0x0013> CatheterRotationalRate; + typedef gdcm::Attribute<0x0052, 0x0014> ALinePixelSpacing; + typedef gdcm::Attribute<0x0052, 0x0016> ModeOfPercutaneousAccessSequence; + typedef gdcm::Attribute<0x0052, 0x0025> IntravascularOCTFrameTypeSequence; + typedef gdcm::Attribute<0x0052, 0x0026> OCTZOffsetApplied; + typedef gdcm::Attribute<0x0052, 0x0027> IntravascularFrameContentSequence; + typedef gdcm::Attribute<0x0052, 0x0028> IntravascularLongitudinalDistance; + typedef gdcm::Attribute<0x0052, 0x0029> IntravascularOCTFrameContentSequence; + typedef gdcm::Attribute<0x0052, 0x0030> OCTZOffsetCorrection; + typedef gdcm::Attribute<0x0052, 0x0031> CatheterDirectionOfRotation; + typedef gdcm::Attribute<0x0052, 0x0033> SeamLineLocation; + typedef gdcm::Attribute<0x0052, 0x0034> FirstALineLocation; + typedef gdcm::Attribute<0x0052, 0x0036> SeamLineIndex; + typedef gdcm::Attribute<0x0052, 0x0038> NumberOfPaddedAlines; + typedef gdcm::Attribute<0x0052, 0x0039> InterpolationType; + typedef gdcm::Attribute<0x0052, 0x003a> RefractiveIndexApplied; + typedef gdcm::Attribute<0x0054, 0x0010> EnergyWindowVector; + typedef gdcm::Attribute<0x0054, 0x0011> NumberOfEnergyWindows; + typedef gdcm::Attribute<0x0054, 0x0012> EnergyWindowInformationSequence; + typedef gdcm::Attribute<0x0054, 0x0013> EnergyWindowRangeSequence; + typedef gdcm::Attribute<0x0054, 0x0014> EnergyWindowLowerLimit; + typedef gdcm::Attribute<0x0054, 0x0015> EnergyWindowUpperLimit; + typedef gdcm::Attribute<0x0054, 0x0016> RadiopharmaceuticalInformationSequence; + typedef gdcm::Attribute<0x0054, 0x0017> ResidualSyringeCounts; + typedef gdcm::Attribute<0x0054, 0x0018> EnergyWindowName; + typedef gdcm::Attribute<0x0054, 0x0020> DetectorVector; + typedef gdcm::Attribute<0x0054, 0x0021> NumberOfDetectors; + typedef gdcm::Attribute<0x0054, 0x0022> DetectorInformationSequence; + typedef gdcm::Attribute<0x0054, 0x0030> PhaseVector; + typedef gdcm::Attribute<0x0054, 0x0031> NumberOfPhases; + typedef gdcm::Attribute<0x0054, 0x0032> PhaseInformationSequence; + typedef gdcm::Attribute<0x0054, 0x0033> NumberOfFramesInPhase; + typedef gdcm::Attribute<0x0054, 0x0036> PhaseDelay; + typedef gdcm::Attribute<0x0054, 0x0038> PauseBetweenFrames; + typedef gdcm::Attribute<0x0054, 0x0039> PhaseDescription; + typedef gdcm::Attribute<0x0054, 0x0050> RotationVector; + typedef gdcm::Attribute<0x0054, 0x0051> NumberOfRotations; + typedef gdcm::Attribute<0x0054, 0x0052> RotationInformationSequence; + typedef gdcm::Attribute<0x0054, 0x0053> NumberOfFramesInRotation; + typedef gdcm::Attribute<0x0054, 0x0060> RRIntervalVector; + typedef gdcm::Attribute<0x0054, 0x0061> NumberOfRRIntervals; + typedef gdcm::Attribute<0x0054, 0x0062> GatedInformationSequence; + typedef gdcm::Attribute<0x0054, 0x0063> DataInformationSequence; + typedef gdcm::Attribute<0x0054, 0x0070> TimeSlotVector; + typedef gdcm::Attribute<0x0054, 0x0071> NumberOfTimeSlots; + typedef gdcm::Attribute<0x0054, 0x0072> TimeSlotInformationSequence; + typedef gdcm::Attribute<0x0054, 0x0073> TimeSlotTime; + typedef gdcm::Attribute<0x0054, 0x0080> SliceVector; + typedef gdcm::Attribute<0x0054, 0x0081> NumberOfSlices; + typedef gdcm::Attribute<0x0054, 0x0090> AngularViewVector; + typedef gdcm::Attribute<0x0054, 0x0100> TimeSliceVector; + typedef gdcm::Attribute<0x0054, 0x0101> NumberOfTimeSlices; + typedef gdcm::Attribute<0x0054, 0x0200> StartAngle; + typedef gdcm::Attribute<0x0054, 0x0202> TypeOfDetectorMotion; + typedef gdcm::Attribute<0x0054, 0x0210> TriggerVector; + typedef gdcm::Attribute<0x0054, 0x0211> NumberOfTriggersInPhase; + typedef gdcm::Attribute<0x0054, 0x0220> ViewCodeSequence; + typedef gdcm::Attribute<0x0054, 0x0222> ViewModifierCodeSequence; + typedef gdcm::Attribute<0x0054, 0x0300> RadionuclideCodeSequence; + typedef gdcm::Attribute<0x0054, 0x0302> AdministrationRouteCodeSequence; + typedef gdcm::Attribute<0x0054, 0x0304> RadiopharmaceuticalCodeSequence; + typedef gdcm::Attribute<0x0054, 0x0306> CalibrationDataSequence; + typedef gdcm::Attribute<0x0054, 0x0308> EnergyWindowNumber; + typedef gdcm::Attribute<0x0054, 0x0400> ImageID; + typedef gdcm::Attribute<0x0054, 0x0410> PatientOrientationCodeSequence; + typedef gdcm::Attribute<0x0054, 0x0412> PatientOrientationModifierCodeSequence; + typedef gdcm::Attribute<0x0054, 0x0414> PatientGantryRelationshipCodeSequence; + typedef gdcm::Attribute<0x0054, 0x0500> SliceProgressionDirection; + typedef gdcm::Attribute<0x0054, 0x1000> SeriesType; + typedef gdcm::Attribute<0x0054, 0x1001> Units; + typedef gdcm::Attribute<0x0054, 0x1002> CountsSource; + typedef gdcm::Attribute<0x0054, 0x1004> ReprojectionMethod; + typedef gdcm::Attribute<0x0054, 0x1006> SUVType; + typedef gdcm::Attribute<0x0054, 0x1100> RandomsCorrectionMethod; + typedef gdcm::Attribute<0x0054, 0x1101> AttenuationCorrectionMethod; + typedef gdcm::Attribute<0x0054, 0x1102> DecayCorrection; + typedef gdcm::Attribute<0x0054, 0x1103> ReconstructionMethod; + typedef gdcm::Attribute<0x0054, 0x1104> DetectorLinesOfResponseUsed; + typedef gdcm::Attribute<0x0054, 0x1105> ScatterCorrectionMethod; + typedef gdcm::Attribute<0x0054, 0x1200> AxialAcceptance; + typedef gdcm::Attribute<0x0054, 0x1201> AxialMash; + typedef gdcm::Attribute<0x0054, 0x1202> TransverseMash; + typedef gdcm::Attribute<0x0054, 0x1203> DetectorElementSize; + typedef gdcm::Attribute<0x0054, 0x1210> CoincidenceWindowWidth; + typedef gdcm::Attribute<0x0054, 0x1220> SecondaryCountsType; + typedef gdcm::Attribute<0x0054, 0x1300> FrameReferenceTime; + typedef gdcm::Attribute<0x0054, 0x1310> PrimaryPromptsCountsAccumulated; + typedef gdcm::Attribute<0x0054, 0x1311> SecondaryCountsAccumulated; + typedef gdcm::Attribute<0x0054, 0x1320> SliceSensitivityFactor; + typedef gdcm::Attribute<0x0054, 0x1321> DecayFactor; + typedef gdcm::Attribute<0x0054, 0x1322> DoseCalibrationFactor; + typedef gdcm::Attribute<0x0054, 0x1323> ScatterFractionFactor; + typedef gdcm::Attribute<0x0054, 0x1324> DeadTimeFactor; + typedef gdcm::Attribute<0x0054, 0x1330> ImageIndex; + typedef gdcm::Attribute<0x0054, 0x1400> CountsIncluded; + typedef gdcm::Attribute<0x0054, 0x1401> DeadTimeCorrectionFlag; + typedef gdcm::Attribute<0x0060, 0x3000> HistogramSequence; + typedef gdcm::Attribute<0x0060, 0x3002> HistogramNumberOfBins; + typedef gdcm::Attribute<0x0060, 0x3004> HistogramFirstBinValue; + typedef gdcm::Attribute<0x0060, 0x3006> HistogramLastBinValue; + typedef gdcm::Attribute<0x0060, 0x3008> HistogramBinWidth; + typedef gdcm::Attribute<0x0060, 0x3010> HistogramExplanation; + typedef gdcm::Attribute<0x0060, 0x3020> HistogramData; + typedef gdcm::Attribute<0x0062, 0x0001> SegmentationType; + typedef gdcm::Attribute<0x0062, 0x0002> SegmentSequence; + typedef gdcm::Attribute<0x0062, 0x0003> SegmentedPropertyCategoryCodeSequence; + typedef gdcm::Attribute<0x0062, 0x0004> SegmentNumber; + typedef gdcm::Attribute<0x0062, 0x0005> SegmentLabel; + typedef gdcm::Attribute<0x0062, 0x0006> SegmentDescription; + typedef gdcm::Attribute<0x0062, 0x0008> SegmentAlgorithmType; + typedef gdcm::Attribute<0x0062, 0x0009> SegmentAlgorithmName; + typedef gdcm::Attribute<0x0062, 0x000a> SegmentIdentificationSequence; + typedef gdcm::Attribute<0x0062, 0x000b> ReferencedSegmentNumber; + typedef gdcm::Attribute<0x0062, 0x000c> RecommendedDisplayGrayscaleValue; + typedef gdcm::Attribute<0x0062, 0x000d> RecommendedDisplayCIELabValue; + typedef gdcm::Attribute<0x0062, 0x000e> MaximumFractionalValue; + typedef gdcm::Attribute<0x0062, 0x000f> SegmentedPropertyTypeCodeSequence; + typedef gdcm::Attribute<0x0062, 0x0010> SegmentationFractionalType; + typedef gdcm::Attribute<0x0064, 0x0002> DeformableRegistrationSequence; + typedef gdcm::Attribute<0x0064, 0x0003> SourceFrameOfReferenceUID; + typedef gdcm::Attribute<0x0064, 0x0005> DeformableRegistrationGridSequence; + typedef gdcm::Attribute<0x0064, 0x0007> GridDimensions; + typedef gdcm::Attribute<0x0064, 0x0008> GridResolution; + typedef gdcm::Attribute<0x0064, 0x0009> VectorGridData; + typedef gdcm::Attribute<0x0064, 0x000f> PreDeformationMatrixRegistrationSequence; + typedef gdcm::Attribute<0x0064, 0x0010> PostDeformationMatrixRegistrationSequence; + typedef gdcm::Attribute<0x0066, 0x0001> NumberOfSurfaces; + typedef gdcm::Attribute<0x0066, 0x0002> SurfaceSequence; + typedef gdcm::Attribute<0x0066, 0x0003> SurfaceNumber; + typedef gdcm::Attribute<0x0066, 0x0004> SurfaceComments; + typedef gdcm::Attribute<0x0066, 0x0009> SurfaceProcessing; + typedef gdcm::Attribute<0x0066, 0x000a> SurfaceProcessingRatio; + typedef gdcm::Attribute<0x0066, 0x000b> SurfaceProcessingDescription; + typedef gdcm::Attribute<0x0066, 0x000c> RecommendedPresentationOpacity; + typedef gdcm::Attribute<0x0066, 0x000d> RecommendedPresentationType; + typedef gdcm::Attribute<0x0066, 0x000e> FiniteVolume; + typedef gdcm::Attribute<0x0066, 0x0010> Manifold; + typedef gdcm::Attribute<0x0066, 0x0011> SurfacePointsSequence; + typedef gdcm::Attribute<0x0066, 0x0012> SurfacePointsNormalsSequence; + typedef gdcm::Attribute<0x0066, 0x0013> SurfaceMeshPrimitivesSequence; + typedef gdcm::Attribute<0x0066, 0x0015> NumberOfSurfacePoints; + typedef gdcm::Attribute<0x0066, 0x0016> PointCoordinatesData; + typedef gdcm::Attribute<0x0066, 0x0017> PointPositionAccuracy; + typedef gdcm::Attribute<0x0066, 0x0018> MeanPointDistance; + typedef gdcm::Attribute<0x0066, 0x0019> MaximumPointDistance; + typedef gdcm::Attribute<0x0066, 0x001a> PointsBoundingBoxCoordinates; + typedef gdcm::Attribute<0x0066, 0x001b> AxisOfRotation; + typedef gdcm::Attribute<0x0066, 0x001c> CenterOfRotation; + typedef gdcm::Attribute<0x0066, 0x001e> NumberOfVectors; + typedef gdcm::Attribute<0x0066, 0x001f> VectorDimensionality; + typedef gdcm::Attribute<0x0066, 0x0020> VectorAccuracy; + typedef gdcm::Attribute<0x0066, 0x0021> VectorCoordinateData; + typedef gdcm::Attribute<0x0066, 0x0023> TrianglePointIndexList; + typedef gdcm::Attribute<0x0066, 0x0024> EdgePointIndexList; + typedef gdcm::Attribute<0x0066, 0x0025> VertexPointIndexList; + typedef gdcm::Attribute<0x0066, 0x0026> TriangleStripSequence; + typedef gdcm::Attribute<0x0066, 0x0027> TriangleFanSequence; + typedef gdcm::Attribute<0x0066, 0x0028> LineSequence; + typedef gdcm::Attribute<0x0066, 0x0029> PrimitivePointIndexList; + typedef gdcm::Attribute<0x0066, 0x002a> SurfaceCount; + typedef gdcm::Attribute<0x0066, 0x002b> ReferencedSurfaceSequence; + typedef gdcm::Attribute<0x0066, 0x002c> ReferencedSurfaceNumber; + typedef gdcm::Attribute<0x0066, 0x002d> SegmentSurfaceGenerationAlgorithmIdentificationSequence; + typedef gdcm::Attribute<0x0066, 0x002e> SegmentSurfaceSourceInstanceSequence; + typedef gdcm::Attribute<0x0066, 0x002f> AlgorithmFamilyCodeSequence; + typedef gdcm::Attribute<0x0066, 0x0030> AlgorithmNameCodeSequence; + typedef gdcm::Attribute<0x0066, 0x0031> AlgorithmVersion; + typedef gdcm::Attribute<0x0066, 0x0032> AlgorithmParameters; + typedef gdcm::Attribute<0x0066, 0x0034> FacetSequence; + typedef gdcm::Attribute<0x0066, 0x0035> SurfaceProcessingAlgorithmIdentificationSequence; + typedef gdcm::Attribute<0x0066, 0x0036> AlgorithmName; + typedef gdcm::Attribute<0x0068, 0x6210> ImplantSize; + typedef gdcm::Attribute<0x0068, 0x6221> ImplantTemplateVersion; + typedef gdcm::Attribute<0x0068, 0x6222> ReplacedImplantTemplateSequence; + typedef gdcm::Attribute<0x0068, 0x6223> ImplantType; + typedef gdcm::Attribute<0x0068, 0x6224> DerivationImplantTemplateSequence; + typedef gdcm::Attribute<0x0068, 0x6225> OriginalImplantTemplateSequence; + typedef gdcm::Attribute<0x0068, 0x6226> EffectiveDateTime; + typedef gdcm::Attribute<0x0068, 0x6230> ImplantTargetAnatomySequence; + typedef gdcm::Attribute<0x0068, 0x6260> InformationFromManufacturerSequence; + typedef gdcm::Attribute<0x0068, 0x6265> NotificationFromManufacturerSequence; + typedef gdcm::Attribute<0x0068, 0x6270> InformationIssueDateTime; + typedef gdcm::Attribute<0x0068, 0x6280> InformationSummary; + typedef gdcm::Attribute<0x0068, 0x62a0> ImplantRegulatoryDisapprovalCodeSequence; + typedef gdcm::Attribute<0x0068, 0x62a5> OverallTemplateSpatialTolerance; + typedef gdcm::Attribute<0x0068, 0x62c0> HPGLDocumentSequence; + typedef gdcm::Attribute<0x0068, 0x62d0> HPGLDocumentID; + typedef gdcm::Attribute<0x0068, 0x62d5> HPGLDocumentLabel; + typedef gdcm::Attribute<0x0068, 0x62e0> ViewOrientationCodeSequence; + typedef gdcm::Attribute<0x0068, 0x62f0> ViewOrientationModifier; + typedef gdcm::Attribute<0x0068, 0x62f2> HPGLDocumentScaling; + typedef gdcm::Attribute<0x0068, 0x6300> HPGLDocument; + typedef gdcm::Attribute<0x0068, 0x6310> HPGLContourPenNumber; + typedef gdcm::Attribute<0x0068, 0x6320> HPGLPenSequence; + typedef gdcm::Attribute<0x0068, 0x6330> HPGLPenNumber; + typedef gdcm::Attribute<0x0068, 0x6340> HPGLPenLabel; + typedef gdcm::Attribute<0x0068, 0x6345> HPGLPenDescription; + typedef gdcm::Attribute<0x0068, 0x6346> RecommendedRotationPoint; + typedef gdcm::Attribute<0x0068, 0x6347> BoundingRectangle; + typedef gdcm::Attribute<0x0068, 0x6350> ImplantTemplate3DModelSurfaceNumber; + typedef gdcm::Attribute<0x0068, 0x6360> SurfaceModelDescriptionSequence; + typedef gdcm::Attribute<0x0068, 0x6380> SurfaceModelLabel; + typedef gdcm::Attribute<0x0068, 0x6390> SurfaceModelScalingFactor; + typedef gdcm::Attribute<0x0068, 0x63a0> MaterialsCodeSequence; + typedef gdcm::Attribute<0x0068, 0x63a4> CoatingMaterialsCodeSequence; + typedef gdcm::Attribute<0x0068, 0x63a8> ImplantTypeCodeSequence; + typedef gdcm::Attribute<0x0068, 0x63ac> FixationMethodCodeSequence; + typedef gdcm::Attribute<0x0068, 0x63b0> MatingFeatureSetsSequence; + typedef gdcm::Attribute<0x0068, 0x63c0> MatingFeatureSetID; + typedef gdcm::Attribute<0x0068, 0x63d0> MatingFeatureSetLabel; + typedef gdcm::Attribute<0x0068, 0x63e0> MatingFeatureSequence; + typedef gdcm::Attribute<0x0068, 0x63f0> MatingFeatureID; + typedef gdcm::Attribute<0x0068, 0x6400> MatingFeatureDegreeOfFreedomSequence; + typedef gdcm::Attribute<0x0068, 0x6410> DegreeOfFreedomID; + typedef gdcm::Attribute<0x0068, 0x6420> DegreeOfFreedomType; + typedef gdcm::Attribute<0x0068, 0x6430> TwoDMatingFeatureCoordinatesSequence; + typedef gdcm::Attribute<0x0068, 0x6440> ReferencedHPGLDocumentID; + typedef gdcm::Attribute<0x0068, 0x6450> TwoDMatingPoint; + typedef gdcm::Attribute<0x0068, 0x6460> TwoDMatingAxes; + typedef gdcm::Attribute<0x0068, 0x6470> TwoDDegreeOfFreedomSequence; + typedef gdcm::Attribute<0x0068, 0x6490> ThreeDDegreeOfFreedomAxis; + typedef gdcm::Attribute<0x0068, 0x64a0> RangeOfFreedom; + typedef gdcm::Attribute<0x0068, 0x64c0> ThreeDMatingPoint; + typedef gdcm::Attribute<0x0068, 0x64d0> ThreeDMatingAxes; + typedef gdcm::Attribute<0x0068, 0x64f0> TwoDDegreeOfFreedomAxis; + typedef gdcm::Attribute<0x0068, 0x6500> PlanningLandmarkPointSequence; + typedef gdcm::Attribute<0x0068, 0x6510> PlanningLandmarkLineSequence; + typedef gdcm::Attribute<0x0068, 0x6520> PlanningLandmarkPlaneSequence; + typedef gdcm::Attribute<0x0068, 0x6530> PlanningLandmarkID; + typedef gdcm::Attribute<0x0068, 0x6540> PlanningLandmarkDescription; + typedef gdcm::Attribute<0x0068, 0x6545> PlanningLandmarkIdentificationCodeSequence; + typedef gdcm::Attribute<0x0068, 0x6550> TwoDPointCoordinatesSequence; + typedef gdcm::Attribute<0x0068, 0x6560> TwoDPointCoordinates; + typedef gdcm::Attribute<0x0068, 0x6590> ThreeDPointCoordinates; + typedef gdcm::Attribute<0x0068, 0x65a0> TwoDLineCoordinatesSequence; + typedef gdcm::Attribute<0x0068, 0x65b0> TwoDLineCoordinates; + typedef gdcm::Attribute<0x0068, 0x65d0> ThreeDLineCoordinates; + typedef gdcm::Attribute<0x0068, 0x65e0> TwoDPlaneCoordinatesSequence; + typedef gdcm::Attribute<0x0068, 0x65f0> TwoDPlaneIntersection; + typedef gdcm::Attribute<0x0068, 0x6610> ThreeDPlaneOrigin; + typedef gdcm::Attribute<0x0068, 0x6620> ThreeDPlaneNormal; + typedef gdcm::Attribute<0x0070, 0x0001> GraphicAnnotationSequence; + typedef gdcm::Attribute<0x0070, 0x0002> GraphicLayer; + typedef gdcm::Attribute<0x0070, 0x0003> BoundingBoxAnnotationUnits; + typedef gdcm::Attribute<0x0070, 0x0004> AnchorPointAnnotationUnits; + typedef gdcm::Attribute<0x0070, 0x0005> GraphicAnnotationUnits; + typedef gdcm::Attribute<0x0070, 0x0006> UnformattedTextValue; + typedef gdcm::Attribute<0x0070, 0x0008> TextObjectSequence; + typedef gdcm::Attribute<0x0070, 0x0009> GraphicObjectSequence; + typedef gdcm::Attribute<0x0070, 0x0010> BoundingBoxTopLeftHandCorner; + typedef gdcm::Attribute<0x0070, 0x0011> BoundingBoxBottomRightHandCorner; + typedef gdcm::Attribute<0x0070, 0x0012> BoundingBoxTextHorizontalJustification; + typedef gdcm::Attribute<0x0070, 0x0014> AnchorPoint; + typedef gdcm::Attribute<0x0070, 0x0015> AnchorPointVisibility; + typedef gdcm::Attribute<0x0070, 0x0020> GraphicDimensions; + typedef gdcm::Attribute<0x0070, 0x0021> NumberOfGraphicPoints; + typedef gdcm::Attribute<0x0070, 0x0022> GraphicData; + typedef gdcm::Attribute<0x0070, 0x0023> GraphicType; + typedef gdcm::Attribute<0x0070, 0x0024> GraphicFilled; + typedef gdcm::Attribute<0x0070, 0x0040> ImageRotationRetired; + typedef gdcm::Attribute<0x0070, 0x0041> ImageHorizontalFlip; + typedef gdcm::Attribute<0x0070, 0x0042> ImageRotation; + typedef gdcm::Attribute<0x0070, 0x0050> DisplayedAreaTopLeftHandCornerTrial; + typedef gdcm::Attribute<0x0070, 0x0051> DisplayedAreaBottomRightHandCornerTrial; + typedef gdcm::Attribute<0x0070, 0x0052> DisplayedAreaTopLeftHandCorner; + typedef gdcm::Attribute<0x0070, 0x0053> DisplayedAreaBottomRightHandCorner; + typedef gdcm::Attribute<0x0070, 0x005a> DisplayedAreaSelectionSequence; + typedef gdcm::Attribute<0x0070, 0x0060> GraphicLayerSequence; + typedef gdcm::Attribute<0x0070, 0x0062> GraphicLayerOrder; + typedef gdcm::Attribute<0x0070, 0x0066> GraphicLayerRecommendedDisplayGrayscaleValue; + typedef gdcm::Attribute<0x0070, 0x0067> GraphicLayerRecommendedDisplayRGBValue; + typedef gdcm::Attribute<0x0070, 0x0068> GraphicLayerDescription; + typedef gdcm::Attribute<0x0070, 0x0080> ContentLabel; + typedef gdcm::Attribute<0x0070, 0x0081> ContentDescription; + typedef gdcm::Attribute<0x0070, 0x0082> PresentationCreationDate; + typedef gdcm::Attribute<0x0070, 0x0083> PresentationCreationTime; + typedef gdcm::Attribute<0x0070, 0x0084> ContentCreatorName; + typedef gdcm::Attribute<0x0070, 0x0086> ContentCreatorIdentificationCodeSequence; + typedef gdcm::Attribute<0x0070, 0x0087> AlternateContentDescriptionSequence; + typedef gdcm::Attribute<0x0070, 0x0100> PresentationSizeMode; + typedef gdcm::Attribute<0x0070, 0x0101> PresentationPixelSpacing; + typedef gdcm::Attribute<0x0070, 0x0102> PresentationPixelAspectRatio; + typedef gdcm::Attribute<0x0070, 0x0103> PresentationPixelMagnificationRatio; + typedef gdcm::Attribute<0x0070, 0x0207> GraphicGroupLabel; + typedef gdcm::Attribute<0x0070, 0x0208> GraphicGroupDescription; + typedef gdcm::Attribute<0x0070, 0x0209> CompoundGraphicSequence; + typedef gdcm::Attribute<0x0070, 0x0226> CompoundGraphicInstanceID; + typedef gdcm::Attribute<0x0070, 0x0227> FontName; + typedef gdcm::Attribute<0x0070, 0x0228> FontNameType; + typedef gdcm::Attribute<0x0070, 0x0229> CSSFontName; + typedef gdcm::Attribute<0x0070, 0x0230> RotationAngle; + typedef gdcm::Attribute<0x0070, 0x0231> TextStyleSequence; + typedef gdcm::Attribute<0x0070, 0x0232> LineStyleSequence; + typedef gdcm::Attribute<0x0070, 0x0233> FillStyleSequence; + typedef gdcm::Attribute<0x0070, 0x0234> GraphicGroupSequence; + typedef gdcm::Attribute<0x0070, 0x0241> TextColorCIELabValue; + typedef gdcm::Attribute<0x0070, 0x0242> HorizontalAlignment; + typedef gdcm::Attribute<0x0070, 0x0243> VerticalAlignment; + typedef gdcm::Attribute<0x0070, 0x0244> ShadowStyle; + typedef gdcm::Attribute<0x0070, 0x0245> ShadowOffsetX; + typedef gdcm::Attribute<0x0070, 0x0246> ShadowOffsetY; + typedef gdcm::Attribute<0x0070, 0x0247> ShadowColorCIELabValue; + typedef gdcm::Attribute<0x0070, 0x0248> Underlined; + typedef gdcm::Attribute<0x0070, 0x0249> Bold; + typedef gdcm::Attribute<0x0070, 0x0250> Italic; + typedef gdcm::Attribute<0x0070, 0x0251> PatternOnColorCIELabValue; + typedef gdcm::Attribute<0x0070, 0x0252> PatternOffColorCIELabValue; + typedef gdcm::Attribute<0x0070, 0x0253> LineThickness; + typedef gdcm::Attribute<0x0070, 0x0254> LineDashingStyle; + typedef gdcm::Attribute<0x0070, 0x0255> LinePattern; + typedef gdcm::Attribute<0x0070, 0x0256> FillPattern; + typedef gdcm::Attribute<0x0070, 0x0257> FillMode; + typedef gdcm::Attribute<0x0070, 0x0258> ShadowOpacity; + typedef gdcm::Attribute<0x0070, 0x0261> GapLength; + typedef gdcm::Attribute<0x0070, 0x0262> DiameterOfVisibility; + typedef gdcm::Attribute<0x0070, 0x0273> RotationPoint; + typedef gdcm::Attribute<0x0070, 0x0274> TickAlignment; + typedef gdcm::Attribute<0x0070, 0x0278> ShowTickLabel; + typedef gdcm::Attribute<0x0070, 0x0279> TickLabelAlignment; + typedef gdcm::Attribute<0x0070, 0x0282> CompoundGraphicUnits; + typedef gdcm::Attribute<0x0070, 0x0284> PatternOnOpacity; + typedef gdcm::Attribute<0x0070, 0x0285> PatternOffOpacity; + typedef gdcm::Attribute<0x0070, 0x0287> MajorTicksSequence; + typedef gdcm::Attribute<0x0070, 0x0288> TickPosition; + typedef gdcm::Attribute<0x0070, 0x0289> TickLabel; + typedef gdcm::Attribute<0x0070, 0x0294> CompoundGraphicType; + typedef gdcm::Attribute<0x0070, 0x0295> GraphicGroupID; + typedef gdcm::Attribute<0x0070, 0x0306> ShapeType; + typedef gdcm::Attribute<0x0070, 0x0308> RegistrationSequence; + typedef gdcm::Attribute<0x0070, 0x0309> MatrixRegistrationSequence; + typedef gdcm::Attribute<0x0070, 0x030a> MatrixSequence; + typedef gdcm::Attribute<0x0070, 0x030c> FrameOfReferenceTransformationMatrixType; + typedef gdcm::Attribute<0x0070, 0x030d> RegistrationTypeCodeSequence; + typedef gdcm::Attribute<0x0070, 0x030f> FiducialDescription; + typedef gdcm::Attribute<0x0070, 0x0310> FiducialIdentifier; + typedef gdcm::Attribute<0x0070, 0x0311> FiducialIdentifierCodeSequence; + typedef gdcm::Attribute<0x0070, 0x0312> ContourUncertaintyRadius; + typedef gdcm::Attribute<0x0070, 0x0314> UsedFiducialsSequence; + typedef gdcm::Attribute<0x0070, 0x0318> GraphicCoordinatesDataSequence; + typedef gdcm::Attribute<0x0070, 0x031a> FiducialUID; + typedef gdcm::Attribute<0x0070, 0x031c> FiducialSetSequence; + typedef gdcm::Attribute<0x0070, 0x031e> FiducialSequence; + typedef gdcm::Attribute<0x0070, 0x0401> GraphicLayerRecommendedDisplayCIELabValue; + typedef gdcm::Attribute<0x0070, 0x0402> BlendingSequence; + typedef gdcm::Attribute<0x0070, 0x0403> RelativeOpacity; + typedef gdcm::Attribute<0x0070, 0x0404> ReferencedSpatialRegistrationSequence; + typedef gdcm::Attribute<0x0070, 0x0405> BlendingPosition; + typedef gdcm::Attribute<0x0072, 0x0002> HangingProtocolName; + typedef gdcm::Attribute<0x0072, 0x0004> HangingProtocolDescription; + typedef gdcm::Attribute<0x0072, 0x0006> HangingProtocolLevel; + typedef gdcm::Attribute<0x0072, 0x0008> HangingProtocolCreator; + typedef gdcm::Attribute<0x0072, 0x000a> HangingProtocolCreationDateTime; + typedef gdcm::Attribute<0x0072, 0x000c> HangingProtocolDefinitionSequence; + typedef gdcm::Attribute<0x0072, 0x000e> HangingProtocolUserIdentificationCodeSequence; + typedef gdcm::Attribute<0x0072, 0x0010> HangingProtocolUserGroupName; + typedef gdcm::Attribute<0x0072, 0x0012> SourceHangingProtocolSequence; + typedef gdcm::Attribute<0x0072, 0x0014> NumberOfPriorsReferenced; + typedef gdcm::Attribute<0x0072, 0x0020> ImageSetsSequence; + typedef gdcm::Attribute<0x0072, 0x0022> ImageSetSelectorSequence; + typedef gdcm::Attribute<0x0072, 0x0024> ImageSetSelectorUsageFlag; + typedef gdcm::Attribute<0x0072, 0x0026> SelectorAttribute; + typedef gdcm::Attribute<0x0072, 0x0028> SelectorValueNumber; + typedef gdcm::Attribute<0x0072, 0x0030> TimeBasedImageSetsSequence; + typedef gdcm::Attribute<0x0072, 0x0032> ImageSetNumber; + typedef gdcm::Attribute<0x0072, 0x0034> ImageSetSelectorCategory; + typedef gdcm::Attribute<0x0072, 0x0038> RelativeTime; + typedef gdcm::Attribute<0x0072, 0x003a> RelativeTimeUnits; + typedef gdcm::Attribute<0x0072, 0x003c> AbstractPriorValue; + typedef gdcm::Attribute<0x0072, 0x003e> AbstractPriorCodeSequence; + typedef gdcm::Attribute<0x0072, 0x0040> ImageSetLabel; + typedef gdcm::Attribute<0x0072, 0x0050> SelectorAttributeVR; + typedef gdcm::Attribute<0x0072, 0x0052> SelectorSequencePointer; + typedef gdcm::Attribute<0x0072, 0x0054> SelectorSequencePointerPrivateCreator; + typedef gdcm::Attribute<0x0072, 0x0056> SelectorAttributePrivateCreator; + typedef gdcm::Attribute<0x0072, 0x0060> SelectorATValue; + typedef gdcm::Attribute<0x0072, 0x0062> SelectorCSValue; + typedef gdcm::Attribute<0x0072, 0x0064> SelectorISValue; + typedef gdcm::Attribute<0x0072, 0x0066> SelectorLOValue; + typedef gdcm::Attribute<0x0072, 0x0068> SelectorLTValue; + typedef gdcm::Attribute<0x0072, 0x006a> SelectorPNValue; + typedef gdcm::Attribute<0x0072, 0x006c> SelectorSHValue; + typedef gdcm::Attribute<0x0072, 0x006e> SelectorSTValue; + typedef gdcm::Attribute<0x0072, 0x0070> SelectorUTValue; + typedef gdcm::Attribute<0x0072, 0x0072> SelectorDSValue; + typedef gdcm::Attribute<0x0072, 0x0074> SelectorFDValue; + typedef gdcm::Attribute<0x0072, 0x0076> SelectorFLValue; + typedef gdcm::Attribute<0x0072, 0x0078> SelectorULValue; + typedef gdcm::Attribute<0x0072, 0x007a> SelectorUSValue; + typedef gdcm::Attribute<0x0072, 0x007c> SelectorSLValue; + typedef gdcm::Attribute<0x0072, 0x007e> SelectorSSValue; + typedef gdcm::Attribute<0x0072, 0x0080> SelectorCodeSequenceValue; + typedef gdcm::Attribute<0x0072, 0x0100> NumberOfScreens; + typedef gdcm::Attribute<0x0072, 0x0102> NominalScreenDefinitionSequence; + typedef gdcm::Attribute<0x0072, 0x0104> NumberOfVerticalPixels; + typedef gdcm::Attribute<0x0072, 0x0106> NumberOfHorizontalPixels; + typedef gdcm::Attribute<0x0072, 0x0108> DisplayEnvironmentSpatialPosition; + typedef gdcm::Attribute<0x0072, 0x010a> ScreenMinimumGrayscaleBitDepth; + typedef gdcm::Attribute<0x0072, 0x010c> ScreenMinimumColorBitDepth; + typedef gdcm::Attribute<0x0072, 0x010e> ApplicationMaximumRepaintTime; + typedef gdcm::Attribute<0x0072, 0x0200> DisplaySetsSequence; + typedef gdcm::Attribute<0x0072, 0x0202> DisplaySetNumber; + typedef gdcm::Attribute<0x0072, 0x0203> DisplaySetLabel; + typedef gdcm::Attribute<0x0072, 0x0204> DisplaySetPresentationGroup; + typedef gdcm::Attribute<0x0072, 0x0206> DisplaySetPresentationGroupDescription; + typedef gdcm::Attribute<0x0072, 0x0208> PartialDataDisplayHandling; + typedef gdcm::Attribute<0x0072, 0x0210> SynchronizedScrollingSequence; + typedef gdcm::Attribute<0x0072, 0x0212> DisplaySetScrollingGroup; + typedef gdcm::Attribute<0x0072, 0x0214> NavigationIndicatorSequence; + typedef gdcm::Attribute<0x0072, 0x0216> NavigationDisplaySet; + typedef gdcm::Attribute<0x0072, 0x0218> ReferenceDisplaySets; + typedef gdcm::Attribute<0x0072, 0x0300> ImageBoxesSequence; + typedef gdcm::Attribute<0x0072, 0x0302> ImageBoxNumber; + typedef gdcm::Attribute<0x0072, 0x0304> ImageBoxLayoutType; + typedef gdcm::Attribute<0x0072, 0x0306> ImageBoxTileHorizontalDimension; + typedef gdcm::Attribute<0x0072, 0x0308> ImageBoxTileVerticalDimension; + typedef gdcm::Attribute<0x0072, 0x0310> ImageBoxScrollDirection; + typedef gdcm::Attribute<0x0072, 0x0312> ImageBoxSmallScrollType; + typedef gdcm::Attribute<0x0072, 0x0314> ImageBoxSmallScrollAmount; + typedef gdcm::Attribute<0x0072, 0x0316> ImageBoxLargeScrollType; + typedef gdcm::Attribute<0x0072, 0x0318> ImageBoxLargeScrollAmount; + typedef gdcm::Attribute<0x0072, 0x0320> ImageBoxOverlapPriority; + typedef gdcm::Attribute<0x0072, 0x0330> CineRelativeToRealTime; + typedef gdcm::Attribute<0x0072, 0x0400> FilterOperationsSequence; + typedef gdcm::Attribute<0x0072, 0x0402> FilterByCategory; + typedef gdcm::Attribute<0x0072, 0x0404> FilterByAttributePresence; + typedef gdcm::Attribute<0x0072, 0x0406> FilterByOperator; + typedef gdcm::Attribute<0x0072, 0x0420> StructuredDisplayBackgroundCIELabValue; + typedef gdcm::Attribute<0x0072, 0x0421> EmptyImageBoxCIELabValue; + typedef gdcm::Attribute<0x0072, 0x0422> StructuredDisplayImageBoxSequence; + typedef gdcm::Attribute<0x0072, 0x0424> StructuredDisplayTextBoxSequence; + typedef gdcm::Attribute<0x0072, 0x0427> ReferencedFirstFrameSequence; + typedef gdcm::Attribute<0x0072, 0x0430> ImageBoxSynchronizationSequence; + typedef gdcm::Attribute<0x0072, 0x0432> SynchronizedImageBoxList; + typedef gdcm::Attribute<0x0072, 0x0434> TypeOfSynchronization; + typedef gdcm::Attribute<0x0072, 0x0500> BlendingOperationType; + typedef gdcm::Attribute<0x0072, 0x0510> ReformattingOperationType; + typedef gdcm::Attribute<0x0072, 0x0512> ReformattingThickness; + typedef gdcm::Attribute<0x0072, 0x0514> ReformattingInterval; + typedef gdcm::Attribute<0x0072, 0x0516> ReformattingOperationInitialViewDirection; + typedef gdcm::Attribute<0x0072, 0x0520> ThreeDRenderingType; + typedef gdcm::Attribute<0x0072, 0x0600> SortingOperationsSequence; + typedef gdcm::Attribute<0x0072, 0x0602> SortByCategory; + typedef gdcm::Attribute<0x0072, 0x0604> SortingDirection; + typedef gdcm::Attribute<0x0072, 0x0700> DisplaySetPatientOrientation; + typedef gdcm::Attribute<0x0072, 0x0702> VOIType; + typedef gdcm::Attribute<0x0072, 0x0704> PseudoColorType; + typedef gdcm::Attribute<0x0072, 0x0705> PseudoColorPaletteInstanceReferenceSequence; + typedef gdcm::Attribute<0x0072, 0x0706> ShowGrayscaleInverted; + typedef gdcm::Attribute<0x0072, 0x0710> ShowImageTrueSizeFlag; + typedef gdcm::Attribute<0x0072, 0x0712> ShowGraphicAnnotationFlag; + typedef gdcm::Attribute<0x0072, 0x0714> ShowPatientDemographicsFlag; + typedef gdcm::Attribute<0x0072, 0x0716> ShowAcquisitionTechniquesFlag; + typedef gdcm::Attribute<0x0072, 0x0717> DisplaySetHorizontalJustification; + typedef gdcm::Attribute<0x0072, 0x0718> DisplaySetVerticalJustification; + typedef gdcm::Attribute<0x0074, 0x0120> ContinuationStartMeterset; + typedef gdcm::Attribute<0x0074, 0x0121> ContinuationEndMeterset; + typedef gdcm::Attribute<0x0074, 0x1000> ProcedureStepState; + typedef gdcm::Attribute<0x0074, 0x1002> ProcedureStepProgressInformationSequence; + typedef gdcm::Attribute<0x0074, 0x1004> ProcedureStepProgress; + typedef gdcm::Attribute<0x0074, 0x1006> ProcedureStepProgressDescription; + typedef gdcm::Attribute<0x0074, 0x1008> ProcedureStepCommunicationsURISequence; + typedef gdcm::Attribute<0x0074, 0x100a> ContactURI; + typedef gdcm::Attribute<0x0074, 0x100c> ContactDisplayName; + typedef gdcm::Attribute<0x0074, 0x100e> ProcedureStepDiscontinuationReasonCodeSequence; + typedef gdcm::Attribute<0x0074, 0x1020> BeamTaskSequence; + typedef gdcm::Attribute<0x0074, 0x1022> BeamTaskType; + typedef gdcm::Attribute<0x0074, 0x1024> BeamOrderIndexTrial; + typedef gdcm::Attribute<0x0074, 0x1026> TableTopVerticalAdjustedPosition; + typedef gdcm::Attribute<0x0074, 0x1027> TableTopLongitudinalAdjustedPosition; + typedef gdcm::Attribute<0x0074, 0x1028> TableTopLateralAdjustedPosition; + typedef gdcm::Attribute<0x0074, 0x102a> PatientSupportAdjustedAngle; + typedef gdcm::Attribute<0x0074, 0x102b> TableTopEccentricAdjustedAngle; + typedef gdcm::Attribute<0x0074, 0x102c> TableTopPitchAdjustedAngle; + typedef gdcm::Attribute<0x0074, 0x102d> TableTopRollAdjustedAngle; + typedef gdcm::Attribute<0x0074, 0x1030> DeliveryVerificationImageSequence; + typedef gdcm::Attribute<0x0074, 0x1032> VerificationImageTiming; + typedef gdcm::Attribute<0x0074, 0x1034> DoubleExposureFlag; + typedef gdcm::Attribute<0x0074, 0x1036> DoubleExposureOrdering; + typedef gdcm::Attribute<0x0074, 0x1038> DoubleExposureMetersetTrial; + typedef gdcm::Attribute<0x0074, 0x103a> DoubleExposureFieldDeltaTrial; + typedef gdcm::Attribute<0x0074, 0x1040> RelatedReferenceRTImageSequence; + typedef gdcm::Attribute<0x0074, 0x1042> GeneralMachineVerificationSequence; + typedef gdcm::Attribute<0x0074, 0x1044> ConventionalMachineVerificationSequence; + typedef gdcm::Attribute<0x0074, 0x1046> IonMachineVerificationSequence; + typedef gdcm::Attribute<0x0074, 0x1048> FailedAttributesSequence; + typedef gdcm::Attribute<0x0074, 0x104a> OverriddenAttributesSequence; + typedef gdcm::Attribute<0x0074, 0x104c> ConventionalControlPointVerificationSequence; + typedef gdcm::Attribute<0x0074, 0x104e> IonControlPointVerificationSequence; + typedef gdcm::Attribute<0x0074, 0x1050> AttributeOccurrenceSequence; + typedef gdcm::Attribute<0x0074, 0x1052> AttributeOccurrencePointer; + typedef gdcm::Attribute<0x0074, 0x1054> AttributeItemSelector; + typedef gdcm::Attribute<0x0074, 0x1056> AttributeOccurrencePrivateCreator; + typedef gdcm::Attribute<0x0074, 0x1057> SelectorSequencePointerItems; + typedef gdcm::Attribute<0x0074, 0x1200> ScheduledProcedureStepPriority; + typedef gdcm::Attribute<0x0074, 0x1202> WorklistLabel; + typedef gdcm::Attribute<0x0074, 0x1204> ProcedureStepLabel; + typedef gdcm::Attribute<0x0074, 0x1210> ScheduledProcessingParametersSequence; + typedef gdcm::Attribute<0x0074, 0x1212> PerformedProcessingParametersSequence; + typedef gdcm::Attribute<0x0074, 0x1216> UnifiedProcedureStepPerformedProcedureSequence; + typedef gdcm::Attribute<0x0074, 0x1220> RelatedProcedureStepSequence; + typedef gdcm::Attribute<0x0074, 0x1222> ProcedureStepRelationshipType; + typedef gdcm::Attribute<0x0074, 0x1224> ReplacedProcedureStepSequence; + typedef gdcm::Attribute<0x0074, 0x1230> DeletionLock; + typedef gdcm::Attribute<0x0074, 0x1234> ReceivingAE; + typedef gdcm::Attribute<0x0074, 0x1236> RequestingAE; + typedef gdcm::Attribute<0x0074, 0x1238> ReasonForCancellation; + typedef gdcm::Attribute<0x0074, 0x1242> SCPStatus; + typedef gdcm::Attribute<0x0074, 0x1244> SubscriptionListStatus; + typedef gdcm::Attribute<0x0074, 0x1246> UnifiedProcedureStepListStatus; + typedef gdcm::Attribute<0x0074, 0x1324> BeamOrderIndex; + typedef gdcm::Attribute<0x0074, 0x1338> DoubleExposureMeterset; + typedef gdcm::Attribute<0x0074, 0x133a> DoubleExposureFieldDelta; + typedef gdcm::Attribute<0x0076, 0x0001> ImplantAssemblyTemplateName; + typedef gdcm::Attribute<0x0076, 0x0003> ImplantAssemblyTemplateIssuer; + typedef gdcm::Attribute<0x0076, 0x0006> ImplantAssemblyTemplateVersion; + typedef gdcm::Attribute<0x0076, 0x0008> ReplacedImplantAssemblyTemplateSequence; + typedef gdcm::Attribute<0x0076, 0x000a> ImplantAssemblyTemplateType; + typedef gdcm::Attribute<0x0076, 0x000c> OriginalImplantAssemblyTemplateSequence; + typedef gdcm::Attribute<0x0076, 0x000e> DerivationImplantAssemblyTemplateSequence; + typedef gdcm::Attribute<0x0076, 0x0010> ImplantAssemblyTemplateTargetAnatomySequence; + typedef gdcm::Attribute<0x0076, 0x0020> ProcedureTypeCodeSequence; + typedef gdcm::Attribute<0x0076, 0x0030> SurgicalTechnique; + typedef gdcm::Attribute<0x0076, 0x0032> ComponentTypesSequence; + typedef gdcm::Attribute<0x0076, 0x0034> ComponentTypeCodeSequence; + typedef gdcm::Attribute<0x0076, 0x0036> ExclusiveComponentType; + typedef gdcm::Attribute<0x0076, 0x0038> MandatoryComponentType; + typedef gdcm::Attribute<0x0076, 0x0040> ComponentSequence; + typedef gdcm::Attribute<0x0076, 0x0055> ComponentID; + typedef gdcm::Attribute<0x0076, 0x0060> ComponentAssemblySequence; + typedef gdcm::Attribute<0x0076, 0x0070> Component1ReferencedID; + typedef gdcm::Attribute<0x0076, 0x0080> Component1ReferencedMatingFeatureSetID; + typedef gdcm::Attribute<0x0076, 0x0090> Component1ReferencedMatingFeatureID; + typedef gdcm::Attribute<0x0076, 0x00a0> Component2ReferencedID; + typedef gdcm::Attribute<0x0076, 0x00b0> Component2ReferencedMatingFeatureSetID; + typedef gdcm::Attribute<0x0076, 0x00c0> Component2ReferencedMatingFeatureID; + typedef gdcm::Attribute<0x0078, 0x0001> ImplantTemplateGroupName; + typedef gdcm::Attribute<0x0078, 0x0010> ImplantTemplateGroupDescription; + typedef gdcm::Attribute<0x0078, 0x0020> ImplantTemplateGroupIssuer; + typedef gdcm::Attribute<0x0078, 0x0024> ImplantTemplateGroupVersion; + typedef gdcm::Attribute<0x0078, 0x0026> ReplacedImplantTemplateGroupSequence; + typedef gdcm::Attribute<0x0078, 0x0028> ImplantTemplateGroupTargetAnatomySequence; + typedef gdcm::Attribute<0x0078, 0x002a> ImplantTemplateGroupMembersSequence; + typedef gdcm::Attribute<0x0078, 0x002e> ImplantTemplateGroupMemberID; + typedef gdcm::Attribute<0x0078, 0x0050> ThreeDImplantTemplateGroupMemberMatchingPoint; + typedef gdcm::Attribute<0x0078, 0x0060> ThreeDImplantTemplateGroupMemberMatchingAxes; + typedef gdcm::Attribute<0x0078, 0x0070> ImplantTemplateGroupMemberMatching2DCoordinatesSequence; + typedef gdcm::Attribute<0x0078, 0x0090> TwoDImplantTemplateGroupMemberMatchingPoint; + typedef gdcm::Attribute<0x0078, 0x00a0> TwoDImplantTemplateGroupMemberMatchingAxes; + typedef gdcm::Attribute<0x0078, 0x00b0> ImplantTemplateGroupVariationDimensionSequence; + typedef gdcm::Attribute<0x0078, 0x00b2> ImplantTemplateGroupVariationDimensionName; + typedef gdcm::Attribute<0x0078, 0x00b4> ImplantTemplateGroupVariationDimensionRankSequence; + typedef gdcm::Attribute<0x0078, 0x00b6> ReferencedImplantTemplateGroupMemberID; + typedef gdcm::Attribute<0x0078, 0x00b8> ImplantTemplateGroupVariationDimensionRank; + typedef gdcm::Attribute<0x0088, 0x0130> StorageMediaFileSetID; + typedef gdcm::Attribute<0x0088, 0x0140> StorageMediaFileSetUID; + typedef gdcm::Attribute<0x0088, 0x0200> IconImageSequence; + typedef gdcm::Attribute<0x0088, 0x0904> TopicTitle; + typedef gdcm::Attribute<0x0088, 0x0906> TopicSubject; + typedef gdcm::Attribute<0x0088, 0x0910> TopicAuthor; + typedef gdcm::Attribute<0x0088, 0x0912> TopicKeywords; + typedef gdcm::Attribute<0x0100, 0x0410> SOPInstanceStatus; + typedef gdcm::Attribute<0x0100, 0x0420> SOPAuthorizationDateTime; + typedef gdcm::Attribute<0x0100, 0x0424> SOPAuthorizationComment; + typedef gdcm::Attribute<0x0100, 0x0426> AuthorizationEquipmentCertificationNumber; + typedef gdcm::Attribute<0x0400, 0x0005> MACIDNumber; + typedef gdcm::Attribute<0x0400, 0x0010> MACCalculationTransferSyntaxUID; + typedef gdcm::Attribute<0x0400, 0x0015> MACAlgorithm; + typedef gdcm::Attribute<0x0400, 0x0020> DataElementsSigned; + typedef gdcm::Attribute<0x0400, 0x0100> DigitalSignatureUID; + typedef gdcm::Attribute<0x0400, 0x0105> DigitalSignatureDateTime; + typedef gdcm::Attribute<0x0400, 0x0110> CertificateType; + typedef gdcm::Attribute<0x0400, 0x0115> CertificateOfSigner; + typedef gdcm::Attribute<0x0400, 0x0120> Signature; + typedef gdcm::Attribute<0x0400, 0x0305> CertifiedTimestampType; + typedef gdcm::Attribute<0x0400, 0x0310> CertifiedTimestamp; + typedef gdcm::Attribute<0x0400, 0x0401> DigitalSignaturePurposeCodeSequence; + typedef gdcm::Attribute<0x0400, 0x0402> ReferencedDigitalSignatureSequence; + typedef gdcm::Attribute<0x0400, 0x0403> ReferencedSOPInstanceMACSequence; + typedef gdcm::Attribute<0x0400, 0x0404> MAC; + typedef gdcm::Attribute<0x0400, 0x0500> EncryptedAttributesSequence; + typedef gdcm::Attribute<0x0400, 0x0510> EncryptedContentTransferSyntaxUID; + typedef gdcm::Attribute<0x0400, 0x0520> EncryptedContent; + typedef gdcm::Attribute<0x0400, 0x0550> ModifiedAttributesSequence; + typedef gdcm::Attribute<0x0400, 0x0561> OriginalAttributesSequence; + typedef gdcm::Attribute<0x0400, 0x0562> AttributeModificationDateTime; + typedef gdcm::Attribute<0x0400, 0x0563> ModifyingSystem; + typedef gdcm::Attribute<0x0400, 0x0564> SourceOfPreviousValues; + typedef gdcm::Attribute<0x0400, 0x0565> ReasonForTheAttributeModification; + typedef gdcm::Attribute<0x1000, 0x0000> EscapeTriplet; + typedef gdcm::Attribute<0x1000, 0x0001> RunLengthTriplet; + typedef gdcm::Attribute<0x1000, 0x0002> HuffmanTableSize; + typedef gdcm::Attribute<0x1000, 0x0003> HuffmanTableTriplet; + typedef gdcm::Attribute<0x1000, 0x0004> ShiftTableSize; + typedef gdcm::Attribute<0x1000, 0x0005> ShiftTableTriplet; + typedef gdcm::Attribute<0x1010, 0x0000> ZonalMap; + typedef gdcm::Attribute<0x2000, 0x0010> NumberOfCopies; + typedef gdcm::Attribute<0x2000, 0x001e> PrinterConfigurationSequence; + typedef gdcm::Attribute<0x2000, 0x0020> PrintPriority; + typedef gdcm::Attribute<0x2000, 0x0030> MediumType; + typedef gdcm::Attribute<0x2000, 0x0040> FilmDestination; + typedef gdcm::Attribute<0x2000, 0x0050> FilmSessionLabel; + typedef gdcm::Attribute<0x2000, 0x0060> MemoryAllocation; + typedef gdcm::Attribute<0x2000, 0x0061> MaximumMemoryAllocation; + typedef gdcm::Attribute<0x2000, 0x0062> ColorImagePrintingFlag; + typedef gdcm::Attribute<0x2000, 0x0063> CollationFlag; + typedef gdcm::Attribute<0x2000, 0x0065> AnnotationFlag; + typedef gdcm::Attribute<0x2000, 0x0067> ImageOverlayFlag; + typedef gdcm::Attribute<0x2000, 0x0069> PresentationLUTFlag; + typedef gdcm::Attribute<0x2000, 0x006a> ImageBoxPresentationLUTFlag; + typedef gdcm::Attribute<0x2000, 0x00a0> MemoryBitDepth; + typedef gdcm::Attribute<0x2000, 0x00a1> PrintingBitDepth; + typedef gdcm::Attribute<0x2000, 0x00a2> MediaInstalledSequence; + typedef gdcm::Attribute<0x2000, 0x00a4> OtherMediaAvailableSequence; + typedef gdcm::Attribute<0x2000, 0x00a8> SupportedImageDisplayFormatsSequence; + typedef gdcm::Attribute<0x2000, 0x0500> ReferencedFilmBoxSequence; + typedef gdcm::Attribute<0x2000, 0x0510> ReferencedStoredPrintSequence; + typedef gdcm::Attribute<0x2010, 0x0010> ImageDisplayFormat; + typedef gdcm::Attribute<0x2010, 0x0030> AnnotationDisplayFormatID; + typedef gdcm::Attribute<0x2010, 0x0040> FilmOrientation; + typedef gdcm::Attribute<0x2010, 0x0050> FilmSizeID; + typedef gdcm::Attribute<0x2010, 0x0052> PrinterResolutionID; + typedef gdcm::Attribute<0x2010, 0x0054> DefaultPrinterResolutionID; + typedef gdcm::Attribute<0x2010, 0x0060> MagnificationType; + typedef gdcm::Attribute<0x2010, 0x0080> SmoothingType; + typedef gdcm::Attribute<0x2010, 0x00a6> DefaultMagnificationType; + typedef gdcm::Attribute<0x2010, 0x00a7> OtherMagnificationTypesAvailable; + typedef gdcm::Attribute<0x2010, 0x00a8> DefaultSmoothingType; + typedef gdcm::Attribute<0x2010, 0x00a9> OtherSmoothingTypesAvailable; + typedef gdcm::Attribute<0x2010, 0x0100> BorderDensity; + typedef gdcm::Attribute<0x2010, 0x0110> EmptyImageDensity; + typedef gdcm::Attribute<0x2010, 0x0120> MinDensity; + typedef gdcm::Attribute<0x2010, 0x0130> MaxDensity; + typedef gdcm::Attribute<0x2010, 0x0140> Trim; + typedef gdcm::Attribute<0x2010, 0x0150> ConfigurationInformation; + typedef gdcm::Attribute<0x2010, 0x0152> ConfigurationInformationDescription; + typedef gdcm::Attribute<0x2010, 0x0154> MaximumCollatedFilms; + typedef gdcm::Attribute<0x2010, 0x015e> Illumination; + typedef gdcm::Attribute<0x2010, 0x0160> ReflectedAmbientLight; + typedef gdcm::Attribute<0x2010, 0x0376> PrinterPixelSpacing; + typedef gdcm::Attribute<0x2010, 0x0500> ReferencedFilmSessionSequence; + typedef gdcm::Attribute<0x2010, 0x0510> ReferencedImageBoxSequence; + typedef gdcm::Attribute<0x2010, 0x0520> ReferencedBasicAnnotationBoxSequence; + typedef gdcm::Attribute<0x2020, 0x0010> ImageBoxPosition; + typedef gdcm::Attribute<0x2020, 0x0020> Polarity; + typedef gdcm::Attribute<0x2020, 0x0030> RequestedImageSize; + typedef gdcm::Attribute<0x2020, 0x0040> RequestedDecimateCropBehavior; + typedef gdcm::Attribute<0x2020, 0x0050> RequestedResolutionID; + typedef gdcm::Attribute<0x2020, 0x00a0> RequestedImageSizeFlag; + typedef gdcm::Attribute<0x2020, 0x00a2> DecimateCropResult; + typedef gdcm::Attribute<0x2020, 0x0110> BasicGrayscaleImageSequence; + typedef gdcm::Attribute<0x2020, 0x0111> BasicColorImageSequence; + typedef gdcm::Attribute<0x2020, 0x0130> ReferencedImageOverlayBoxSequence; + typedef gdcm::Attribute<0x2020, 0x0140> ReferencedVOILUTBoxSequence; + typedef gdcm::Attribute<0x2030, 0x0010> AnnotationPosition; + typedef gdcm::Attribute<0x2030, 0x0020> TextString; + typedef gdcm::Attribute<0x2040, 0x0010> ReferencedOverlayPlaneSequence; + typedef gdcm::Attribute<0x2040, 0x0011> ReferencedOverlayPlaneGroups; + typedef gdcm::Attribute<0x2040, 0x0020> OverlayPixelDataSequence; + typedef gdcm::Attribute<0x2040, 0x0060> OverlayMagnificationType; + typedef gdcm::Attribute<0x2040, 0x0070> OverlaySmoothingType; + typedef gdcm::Attribute<0x2040, 0x0072> OverlayOrImageMagnification; + typedef gdcm::Attribute<0x2040, 0x0074> MagnifyToNumberOfColumns; + typedef gdcm::Attribute<0x2040, 0x0080> OverlayForegroundDensity; + typedef gdcm::Attribute<0x2040, 0x0082> OverlayBackgroundDensity; + typedef gdcm::Attribute<0x2040, 0x0090> OverlayMode; + typedef gdcm::Attribute<0x2040, 0x0100> ThresholdDensity; + typedef gdcm::Attribute<0x2040, 0x0500> ReferencedImageBoxSequenceRetired; + typedef gdcm::Attribute<0x2050, 0x0010> PresentationLUTSequence; + typedef gdcm::Attribute<0x2050, 0x0020> PresentationLUTShape; + typedef gdcm::Attribute<0x2050, 0x0500> ReferencedPresentationLUTSequence; + typedef gdcm::Attribute<0x2100, 0x0010> PrintJobID; + typedef gdcm::Attribute<0x2100, 0x0020> ExecutionStatus; + typedef gdcm::Attribute<0x2100, 0x0030> ExecutionStatusInfo; + typedef gdcm::Attribute<0x2100, 0x0040> CreationDate; + typedef gdcm::Attribute<0x2100, 0x0050> CreationTime; + typedef gdcm::Attribute<0x2100, 0x0070> Originator; + typedef gdcm::Attribute<0x2100, 0x0140> DestinationAE; + typedef gdcm::Attribute<0x2100, 0x0160> OwnerID; + typedef gdcm::Attribute<0x2100, 0x0170> NumberOfFilms; + typedef gdcm::Attribute<0x2100, 0x0500> ReferencedPrintJobSequencePullStoredPrint; + typedef gdcm::Attribute<0x2110, 0x0010> PrinterStatus; + typedef gdcm::Attribute<0x2110, 0x0020> PrinterStatusInfo; + typedef gdcm::Attribute<0x2110, 0x0030> PrinterName; + typedef gdcm::Attribute<0x2110, 0x0099> PrintQueueID; + typedef gdcm::Attribute<0x2120, 0x0010> QueueStatus; + typedef gdcm::Attribute<0x2120, 0x0050> PrintJobDescriptionSequence; + typedef gdcm::Attribute<0x2120, 0x0070> ReferencedPrintJobSequence; + typedef gdcm::Attribute<0x2130, 0x0010> PrintManagementCapabilitiesSequence; + typedef gdcm::Attribute<0x2130, 0x0015> PrinterCharacteristicsSequence; + typedef gdcm::Attribute<0x2130, 0x0030> FilmBoxContentSequence; + typedef gdcm::Attribute<0x2130, 0x0040> ImageBoxContentSequence; + typedef gdcm::Attribute<0x2130, 0x0050> AnnotationContentSequence; + typedef gdcm::Attribute<0x2130, 0x0060> ImageOverlayBoxContentSequence; + typedef gdcm::Attribute<0x2130, 0x0080> PresentationLUTContentSequence; + typedef gdcm::Attribute<0x2130, 0x00a0> ProposedStudySequence; + typedef gdcm::Attribute<0x2130, 0x00c0> OriginalImageSequence; + typedef gdcm::Attribute<0x2200, 0x0001> LabelUsingInformationExtractedFromInstances; + typedef gdcm::Attribute<0x2200, 0x0002> LabelText; + typedef gdcm::Attribute<0x2200, 0x0003> LabelStyleSelection; + typedef gdcm::Attribute<0x2200, 0x0004> MediaDisposition; + typedef gdcm::Attribute<0x2200, 0x0005> BarcodeValue; + typedef gdcm::Attribute<0x2200, 0x0006> BarcodeSymbology; + typedef gdcm::Attribute<0x2200, 0x0007> AllowMediaSplitting; + typedef gdcm::Attribute<0x2200, 0x0008> IncludeNonDICOMObjects; + typedef gdcm::Attribute<0x2200, 0x0009> IncludeDisplayApplication; + typedef gdcm::Attribute<0x2200, 0x000a> PreserveCompositeInstancesAfterMediaCreation; + typedef gdcm::Attribute<0x2200, 0x000b> TotalNumberOfPiecesOfMediaCreated; + typedef gdcm::Attribute<0x2200, 0x000c> RequestedMediaApplicationProfile; + typedef gdcm::Attribute<0x2200, 0x000d> ReferencedStorageMediaSequence; + typedef gdcm::Attribute<0x2200, 0x000e> FailureAttributes; + typedef gdcm::Attribute<0x2200, 0x000f> AllowLossyCompression; + typedef gdcm::Attribute<0x2200, 0x0020> RequestPriority; + typedef gdcm::Attribute<0x3002, 0x0002> RTImageLabel; + typedef gdcm::Attribute<0x3002, 0x0003> RTImageName; + typedef gdcm::Attribute<0x3002, 0x0004> RTImageDescription; + typedef gdcm::Attribute<0x3002, 0x000a> ReportedValuesOrigin; + typedef gdcm::Attribute<0x3002, 0x000c> RTImagePlane; + typedef gdcm::Attribute<0x3002, 0x000d> XRayImageReceptorTranslation; + typedef gdcm::Attribute<0x3002, 0x000e> XRayImageReceptorAngle; + typedef gdcm::Attribute<0x3002, 0x0010> RTImageOrientation; + typedef gdcm::Attribute<0x3002, 0x0011> ImagePlanePixelSpacing; + typedef gdcm::Attribute<0x3002, 0x0012> RTImagePosition; + typedef gdcm::Attribute<0x3002, 0x0020> RadiationMachineName; + typedef gdcm::Attribute<0x3002, 0x0022> RadiationMachineSAD; + typedef gdcm::Attribute<0x3002, 0x0024> RadiationMachineSSD; + typedef gdcm::Attribute<0x3002, 0x0026> RTImageSID; + typedef gdcm::Attribute<0x3002, 0x0028> SourceToReferenceObjectDistance; + typedef gdcm::Attribute<0x3002, 0x0029> FractionNumber; + typedef gdcm::Attribute<0x3002, 0x0030> ExposureSequence; + typedef gdcm::Attribute<0x3002, 0x0032> MetersetExposure; + typedef gdcm::Attribute<0x3002, 0x0034> DiaphragmPosition; + typedef gdcm::Attribute<0x3002, 0x0040> FluenceMapSequence; + typedef gdcm::Attribute<0x3002, 0x0041> FluenceDataSource; + typedef gdcm::Attribute<0x3002, 0x0042> FluenceDataScale; + typedef gdcm::Attribute<0x3002, 0x0050> PrimaryFluenceModeSequence; + typedef gdcm::Attribute<0x3002, 0x0051> FluenceMode; + typedef gdcm::Attribute<0x3002, 0x0052> FluenceModeID; + typedef gdcm::Attribute<0x3004, 0x0001> DVHType; + typedef gdcm::Attribute<0x3004, 0x0002> DoseUnits; + typedef gdcm::Attribute<0x3004, 0x0004> DoseType; + typedef gdcm::Attribute<0x3004, 0x0006> DoseComment; + typedef gdcm::Attribute<0x3004, 0x0008> NormalizationPoint; + typedef gdcm::Attribute<0x3004, 0x000a> DoseSummationType; + typedef gdcm::Attribute<0x3004, 0x000c> GridFrameOffsetVector; + typedef gdcm::Attribute<0x3004, 0x000e> DoseGridScaling; + typedef gdcm::Attribute<0x3004, 0x0010> RTDoseROISequence; + typedef gdcm::Attribute<0x3004, 0x0012> DoseValue; + typedef gdcm::Attribute<0x3004, 0x0014> TissueHeterogeneityCorrection; + typedef gdcm::Attribute<0x3004, 0x0040> DVHNormalizationPoint; + typedef gdcm::Attribute<0x3004, 0x0042> DVHNormalizationDoseValue; + typedef gdcm::Attribute<0x3004, 0x0050> DVHSequence; + typedef gdcm::Attribute<0x3004, 0x0052> DVHDoseScaling; + typedef gdcm::Attribute<0x3004, 0x0054> DVHVolumeUnits; + typedef gdcm::Attribute<0x3004, 0x0056> DVHNumberOfBins; + typedef gdcm::Attribute<0x3004, 0x0058> DVHData; + typedef gdcm::Attribute<0x3004, 0x0060> DVHReferencedROISequence; + typedef gdcm::Attribute<0x3004, 0x0062> DVHROIContributionType; + typedef gdcm::Attribute<0x3004, 0x0070> DVHMinimumDose; + typedef gdcm::Attribute<0x3004, 0x0072> DVHMaximumDose; + typedef gdcm::Attribute<0x3004, 0x0074> DVHMeanDose; + typedef gdcm::Attribute<0x3006, 0x0002> StructureSetLabel; + typedef gdcm::Attribute<0x3006, 0x0004> StructureSetName; + typedef gdcm::Attribute<0x3006, 0x0006> StructureSetDescription; + typedef gdcm::Attribute<0x3006, 0x0008> StructureSetDate; + typedef gdcm::Attribute<0x3006, 0x0009> StructureSetTime; + typedef gdcm::Attribute<0x3006, 0x0010> ReferencedFrameOfReferenceSequence; + typedef gdcm::Attribute<0x3006, 0x0012> RTReferencedStudySequence; + typedef gdcm::Attribute<0x3006, 0x0014> RTReferencedSeriesSequence; + typedef gdcm::Attribute<0x3006, 0x0016> ContourImageSequence; + typedef gdcm::Attribute<0x3006, 0x0020> StructureSetROISequence; + typedef gdcm::Attribute<0x3006, 0x0022> ROINumber; + typedef gdcm::Attribute<0x3006, 0x0024> ReferencedFrameOfReferenceUID; + typedef gdcm::Attribute<0x3006, 0x0026> ROIName; + typedef gdcm::Attribute<0x3006, 0x0028> ROIDescription; + typedef gdcm::Attribute<0x3006, 0x002a> ROIDisplayColor; + typedef gdcm::Attribute<0x3006, 0x002c> ROIVolume; + typedef gdcm::Attribute<0x3006, 0x0030> RTRelatedROISequence; + typedef gdcm::Attribute<0x3006, 0x0033> RTROIRelationship; + typedef gdcm::Attribute<0x3006, 0x0036> ROIGenerationAlgorithm; + typedef gdcm::Attribute<0x3006, 0x0038> ROIGenerationDescription; + typedef gdcm::Attribute<0x3006, 0x0039> ROIContourSequence; + typedef gdcm::Attribute<0x3006, 0x0040> ContourSequence; + typedef gdcm::Attribute<0x3006, 0x0042> ContourGeometricType; + typedef gdcm::Attribute<0x3006, 0x0044> ContourSlabThickness; + typedef gdcm::Attribute<0x3006, 0x0045> ContourOffsetVector; + typedef gdcm::Attribute<0x3006, 0x0046> NumberOfContourPoints; + typedef gdcm::Attribute<0x3006, 0x0048> ContourNumber; + typedef gdcm::Attribute<0x3006, 0x0049> AttachedContours; + typedef gdcm::Attribute<0x3006, 0x0050> ContourData; + typedef gdcm::Attribute<0x3006, 0x0080> RTROIObservationsSequence; + typedef gdcm::Attribute<0x3006, 0x0082> ObservationNumber; + typedef gdcm::Attribute<0x3006, 0x0084> ReferencedROINumber; + typedef gdcm::Attribute<0x3006, 0x0085> ROIObservationLabel; + typedef gdcm::Attribute<0x3006, 0x0086> RTROIIdentificationCodeSequence; + typedef gdcm::Attribute<0x3006, 0x0088> ROIObservationDescription; + typedef gdcm::Attribute<0x3006, 0x00a0> RelatedRTROIObservationsSequence; + typedef gdcm::Attribute<0x3006, 0x00a4> RTROIInterpretedType; + typedef gdcm::Attribute<0x3006, 0x00a6> ROIInterpreter; + typedef gdcm::Attribute<0x3006, 0x00b0> ROIPhysicalPropertiesSequence; + typedef gdcm::Attribute<0x3006, 0x00b2> ROIPhysicalProperty; + typedef gdcm::Attribute<0x3006, 0x00b4> ROIPhysicalPropertyValue; + typedef gdcm::Attribute<0x3006, 0x00b6> ROIElementalCompositionSequence; + typedef gdcm::Attribute<0x3006, 0x00b7> ROIElementalCompositionAtomicNumber; + typedef gdcm::Attribute<0x3006, 0x00b8> ROIElementalCompositionAtomicMassFraction; + typedef gdcm::Attribute<0x3006, 0x00c0> FrameOfReferenceRelationshipSequence; + typedef gdcm::Attribute<0x3006, 0x00c2> RelatedFrameOfReferenceUID; + typedef gdcm::Attribute<0x3006, 0x00c4> FrameOfReferenceTransformationType; + typedef gdcm::Attribute<0x3006, 0x00c6> FrameOfReferenceTransformationMatrix; + typedef gdcm::Attribute<0x3006, 0x00c8> FrameOfReferenceTransformationComment; + typedef gdcm::Attribute<0x3008, 0x0010> MeasuredDoseReferenceSequence; + typedef gdcm::Attribute<0x3008, 0x0012> MeasuredDoseDescription; + typedef gdcm::Attribute<0x3008, 0x0014> MeasuredDoseType; + typedef gdcm::Attribute<0x3008, 0x0016> MeasuredDoseValue; + typedef gdcm::Attribute<0x3008, 0x0020> TreatmentSessionBeamSequence; + typedef gdcm::Attribute<0x3008, 0x0021> TreatmentSessionIonBeamSequence; + typedef gdcm::Attribute<0x3008, 0x0022> CurrentFractionNumber; + typedef gdcm::Attribute<0x3008, 0x0024> TreatmentControlPointDate; + typedef gdcm::Attribute<0x3008, 0x0025> TreatmentControlPointTime; + typedef gdcm::Attribute<0x3008, 0x002a> TreatmentTerminationStatus; + typedef gdcm::Attribute<0x3008, 0x002b> TreatmentTerminationCode; + typedef gdcm::Attribute<0x3008, 0x002c> TreatmentVerificationStatus; + typedef gdcm::Attribute<0x3008, 0x0030> ReferencedTreatmentRecordSequence; + typedef gdcm::Attribute<0x3008, 0x0032> SpecifiedPrimaryMeterset; + typedef gdcm::Attribute<0x3008, 0x0033> SpecifiedSecondaryMeterset; + typedef gdcm::Attribute<0x3008, 0x0036> DeliveredPrimaryMeterset; + typedef gdcm::Attribute<0x3008, 0x0037> DeliveredSecondaryMeterset; + typedef gdcm::Attribute<0x3008, 0x003a> SpecifiedTreatmentTime; + typedef gdcm::Attribute<0x3008, 0x003b> DeliveredTreatmentTime; + typedef gdcm::Attribute<0x3008, 0x0040> ControlPointDeliverySequence; + typedef gdcm::Attribute<0x3008, 0x0041> IonControlPointDeliverySequence; + typedef gdcm::Attribute<0x3008, 0x0042> SpecifiedMeterset; + typedef gdcm::Attribute<0x3008, 0x0044> DeliveredMeterset; + typedef gdcm::Attribute<0x3008, 0x0045> MetersetRateSet; + typedef gdcm::Attribute<0x3008, 0x0046> MetersetRateDelivered; + typedef gdcm::Attribute<0x3008, 0x0047> ScanSpotMetersetsDelivered; + typedef gdcm::Attribute<0x3008, 0x0048> DoseRateDelivered; + typedef gdcm::Attribute<0x3008, 0x0050> TreatmentSummaryCalculatedDoseReferenceSequence; + typedef gdcm::Attribute<0x3008, 0x0052> CumulativeDoseToDoseReference; + typedef gdcm::Attribute<0x3008, 0x0054> FirstTreatmentDate; + typedef gdcm::Attribute<0x3008, 0x0056> MostRecentTreatmentDate; + typedef gdcm::Attribute<0x3008, 0x005a> NumberOfFractionsDelivered; + typedef gdcm::Attribute<0x3008, 0x0060> OverrideSequence; + typedef gdcm::Attribute<0x3008, 0x0061> ParameterSequencePointer; + typedef gdcm::Attribute<0x3008, 0x0062> OverrideParameterPointer; + typedef gdcm::Attribute<0x3008, 0x0063> ParameterItemIndex; + typedef gdcm::Attribute<0x3008, 0x0064> MeasuredDoseReferenceNumber; + typedef gdcm::Attribute<0x3008, 0x0065> ParameterPointer; + typedef gdcm::Attribute<0x3008, 0x0066> OverrideReason; + typedef gdcm::Attribute<0x3008, 0x0068> CorrectedParameterSequence; + typedef gdcm::Attribute<0x3008, 0x006a> CorrectionValue; + typedef gdcm::Attribute<0x3008, 0x0070> CalculatedDoseReferenceSequence; + typedef gdcm::Attribute<0x3008, 0x0072> CalculatedDoseReferenceNumber; + typedef gdcm::Attribute<0x3008, 0x0074> CalculatedDoseReferenceDescription; + typedef gdcm::Attribute<0x3008, 0x0076> CalculatedDoseReferenceDoseValue; + typedef gdcm::Attribute<0x3008, 0x0078> StartMeterset; + typedef gdcm::Attribute<0x3008, 0x007a> EndMeterset; + typedef gdcm::Attribute<0x3008, 0x0080> ReferencedMeasuredDoseReferenceSequence; + typedef gdcm::Attribute<0x3008, 0x0082> ReferencedMeasuredDoseReferenceNumber; + typedef gdcm::Attribute<0x3008, 0x0090> ReferencedCalculatedDoseReferenceSequence; + typedef gdcm::Attribute<0x3008, 0x0092> ReferencedCalculatedDoseReferenceNumber; + typedef gdcm::Attribute<0x3008, 0x00a0> BeamLimitingDeviceLeafPairsSequence; + typedef gdcm::Attribute<0x3008, 0x00b0> RecordedWedgeSequence; + typedef gdcm::Attribute<0x3008, 0x00c0> RecordedCompensatorSequence; + typedef gdcm::Attribute<0x3008, 0x00d0> RecordedBlockSequence; + typedef gdcm::Attribute<0x3008, 0x00e0> TreatmentSummaryMeasuredDoseReferenceSequence; + typedef gdcm::Attribute<0x3008, 0x00f0> RecordedSnoutSequence; + typedef gdcm::Attribute<0x3008, 0x00f2> RecordedRangeShifterSequence; + typedef gdcm::Attribute<0x3008, 0x00f4> RecordedLateralSpreadingDeviceSequence; + typedef gdcm::Attribute<0x3008, 0x00f6> RecordedRangeModulatorSequence; + typedef gdcm::Attribute<0x3008, 0x0100> RecordedSourceSequence; + typedef gdcm::Attribute<0x3008, 0x0105> SourceSerialNumber; + typedef gdcm::Attribute<0x3008, 0x0110> TreatmentSessionApplicationSetupSequence; + typedef gdcm::Attribute<0x3008, 0x0116> ApplicationSetupCheck; + typedef gdcm::Attribute<0x3008, 0x0120> RecordedBrachyAccessoryDeviceSequence; + typedef gdcm::Attribute<0x3008, 0x0122> ReferencedBrachyAccessoryDeviceNumber; + typedef gdcm::Attribute<0x3008, 0x0130> RecordedChannelSequence; + typedef gdcm::Attribute<0x3008, 0x0132> SpecifiedChannelTotalTime; + typedef gdcm::Attribute<0x3008, 0x0134> DeliveredChannelTotalTime; + typedef gdcm::Attribute<0x3008, 0x0136> SpecifiedNumberOfPulses; + typedef gdcm::Attribute<0x3008, 0x0138> DeliveredNumberOfPulses; + typedef gdcm::Attribute<0x3008, 0x013a> SpecifiedPulseRepetitionInterval; + typedef gdcm::Attribute<0x3008, 0x013c> DeliveredPulseRepetitionInterval; + typedef gdcm::Attribute<0x3008, 0x0140> RecordedSourceApplicatorSequence; + typedef gdcm::Attribute<0x3008, 0x0142> ReferencedSourceApplicatorNumber; + typedef gdcm::Attribute<0x3008, 0x0150> RecordedChannelShieldSequence; + typedef gdcm::Attribute<0x3008, 0x0152> ReferencedChannelShieldNumber; + typedef gdcm::Attribute<0x3008, 0x0160> BrachyControlPointDeliveredSequence; + typedef gdcm::Attribute<0x3008, 0x0162> SafePositionExitDate; + typedef gdcm::Attribute<0x3008, 0x0164> SafePositionExitTime; + typedef gdcm::Attribute<0x3008, 0x0166> SafePositionReturnDate; + typedef gdcm::Attribute<0x3008, 0x0168> SafePositionReturnTime; + typedef gdcm::Attribute<0x3008, 0x0200> CurrentTreatmentStatus; + typedef gdcm::Attribute<0x3008, 0x0202> TreatmentStatusComment; + typedef gdcm::Attribute<0x3008, 0x0220> FractionGroupSummarySequence; + typedef gdcm::Attribute<0x3008, 0x0223> ReferencedFractionNumber; + typedef gdcm::Attribute<0x3008, 0x0224> FractionGroupType; + typedef gdcm::Attribute<0x3008, 0x0230> BeamStopperPosition; + typedef gdcm::Attribute<0x3008, 0x0240> FractionStatusSummarySequence; + typedef gdcm::Attribute<0x3008, 0x0250> TreatmentDate; + typedef gdcm::Attribute<0x3008, 0x0251> TreatmentTime; + typedef gdcm::Attribute<0x300a, 0x0002> RTPlanLabel; + typedef gdcm::Attribute<0x300a, 0x0003> RTPlanName; + typedef gdcm::Attribute<0x300a, 0x0004> RTPlanDescription; + typedef gdcm::Attribute<0x300a, 0x0006> RTPlanDate; + typedef gdcm::Attribute<0x300a, 0x0007> RTPlanTime; + typedef gdcm::Attribute<0x300a, 0x0009> TreatmentProtocols; + typedef gdcm::Attribute<0x300a, 0x000a> PlanIntent; + typedef gdcm::Attribute<0x300a, 0x000b> TreatmentSites; + typedef gdcm::Attribute<0x300a, 0x000c> RTPlanGeometry; + typedef gdcm::Attribute<0x300a, 0x000e> PrescriptionDescription; + typedef gdcm::Attribute<0x300a, 0x0010> DoseReferenceSequence; + typedef gdcm::Attribute<0x300a, 0x0012> DoseReferenceNumber; + typedef gdcm::Attribute<0x300a, 0x0013> DoseReferenceUID; + typedef gdcm::Attribute<0x300a, 0x0014> DoseReferenceStructureType; + typedef gdcm::Attribute<0x300a, 0x0015> NominalBeamEnergyUnit; + typedef gdcm::Attribute<0x300a, 0x0016> DoseReferenceDescription; + typedef gdcm::Attribute<0x300a, 0x0018> DoseReferencePointCoordinates; + typedef gdcm::Attribute<0x300a, 0x001a> NominalPriorDose; + typedef gdcm::Attribute<0x300a, 0x0020> DoseReferenceType; + typedef gdcm::Attribute<0x300a, 0x0021> ConstraintWeight; + typedef gdcm::Attribute<0x300a, 0x0022> DeliveryWarningDose; + typedef gdcm::Attribute<0x300a, 0x0023> DeliveryMaximumDose; + typedef gdcm::Attribute<0x300a, 0x0025> TargetMinimumDose; + typedef gdcm::Attribute<0x300a, 0x0026> TargetPrescriptionDose; + typedef gdcm::Attribute<0x300a, 0x0027> TargetMaximumDose; + typedef gdcm::Attribute<0x300a, 0x0028> TargetUnderdoseVolumeFraction; + typedef gdcm::Attribute<0x300a, 0x002a> OrganAtRiskFullVolumeDose; + typedef gdcm::Attribute<0x300a, 0x002b> OrganAtRiskLimitDose; + typedef gdcm::Attribute<0x300a, 0x002c> OrganAtRiskMaximumDose; + typedef gdcm::Attribute<0x300a, 0x002d> OrganAtRiskOverdoseVolumeFraction; + typedef gdcm::Attribute<0x300a, 0x0040> ToleranceTableSequence; + typedef gdcm::Attribute<0x300a, 0x0042> ToleranceTableNumber; + typedef gdcm::Attribute<0x300a, 0x0043> ToleranceTableLabel; + typedef gdcm::Attribute<0x300a, 0x0044> GantryAngleTolerance; + typedef gdcm::Attribute<0x300a, 0x0046> BeamLimitingDeviceAngleTolerance; + typedef gdcm::Attribute<0x300a, 0x0048> BeamLimitingDeviceToleranceSequence; + typedef gdcm::Attribute<0x300a, 0x004a> BeamLimitingDevicePositionTolerance; + typedef gdcm::Attribute<0x300a, 0x004b> SnoutPositionTolerance; + typedef gdcm::Attribute<0x300a, 0x004c> PatientSupportAngleTolerance; + typedef gdcm::Attribute<0x300a, 0x004e> TableTopEccentricAngleTolerance; + typedef gdcm::Attribute<0x300a, 0x004f> TableTopPitchAngleTolerance; + typedef gdcm::Attribute<0x300a, 0x0050> TableTopRollAngleTolerance; + typedef gdcm::Attribute<0x300a, 0x0051> TableTopVerticalPositionTolerance; + typedef gdcm::Attribute<0x300a, 0x0052> TableTopLongitudinalPositionTolerance; + typedef gdcm::Attribute<0x300a, 0x0053> TableTopLateralPositionTolerance; + typedef gdcm::Attribute<0x300a, 0x0055> RTPlanRelationship; + typedef gdcm::Attribute<0x300a, 0x0070> FractionGroupSequence; + typedef gdcm::Attribute<0x300a, 0x0071> FractionGroupNumber; + typedef gdcm::Attribute<0x300a, 0x0072> FractionGroupDescription; + typedef gdcm::Attribute<0x300a, 0x0078> NumberOfFractionsPlanned; + typedef gdcm::Attribute<0x300a, 0x0079> NumberOfFractionPatternDigitsPerDay; + typedef gdcm::Attribute<0x300a, 0x007a> RepeatFractionCycleLength; + typedef gdcm::Attribute<0x300a, 0x007b> FractionPattern; + typedef gdcm::Attribute<0x300a, 0x0080> NumberOfBeams; + typedef gdcm::Attribute<0x300a, 0x0082> BeamDoseSpecificationPoint; + typedef gdcm::Attribute<0x300a, 0x0084> BeamDose; + typedef gdcm::Attribute<0x300a, 0x0086> BeamMeterset; + typedef gdcm::Attribute<0x300a, 0x0088> BeamDosePointDepth; + typedef gdcm::Attribute<0x300a, 0x0089> BeamDosePointEquivalentDepth; + typedef gdcm::Attribute<0x300a, 0x008a> BeamDosePointSSD; + typedef gdcm::Attribute<0x300a, 0x00a0> NumberOfBrachyApplicationSetups; + typedef gdcm::Attribute<0x300a, 0x00a2> BrachyApplicationSetupDoseSpecificationPoint; + typedef gdcm::Attribute<0x300a, 0x00a4> BrachyApplicationSetupDose; + typedef gdcm::Attribute<0x300a, 0x00b0> BeamSequence; + typedef gdcm::Attribute<0x300a, 0x00b2> TreatmentMachineName; + typedef gdcm::Attribute<0x300a, 0x00b3> PrimaryDosimeterUnit; + typedef gdcm::Attribute<0x300a, 0x00b4> SourceAxisDistance; + typedef gdcm::Attribute<0x300a, 0x00b6> BeamLimitingDeviceSequence; + typedef gdcm::Attribute<0x300a, 0x00b8> RTBeamLimitingDeviceType; + typedef gdcm::Attribute<0x300a, 0x00ba> SourceToBeamLimitingDeviceDistance; + typedef gdcm::Attribute<0x300a, 0x00bb> IsocenterToBeamLimitingDeviceDistance; + typedef gdcm::Attribute<0x300a, 0x00bc> NumberOfLeafJawPairs; + typedef gdcm::Attribute<0x300a, 0x00be> LeafPositionBoundaries; + typedef gdcm::Attribute<0x300a, 0x00c0> BeamNumber; + typedef gdcm::Attribute<0x300a, 0x00c2> BeamName; + typedef gdcm::Attribute<0x300a, 0x00c3> BeamDescription; + typedef gdcm::Attribute<0x300a, 0x00c4> BeamType; + typedef gdcm::Attribute<0x300a, 0x00c6> RadiationType; + typedef gdcm::Attribute<0x300a, 0x00c7> HighDoseTechniqueType; + typedef gdcm::Attribute<0x300a, 0x00c8> ReferenceImageNumber; + typedef gdcm::Attribute<0x300a, 0x00ca> PlannedVerificationImageSequence; + typedef gdcm::Attribute<0x300a, 0x00cc> ImagingDeviceSpecificAcquisitionParameters; + typedef gdcm::Attribute<0x300a, 0x00ce> TreatmentDeliveryType; + typedef gdcm::Attribute<0x300a, 0x00d0> NumberOfWedges; + typedef gdcm::Attribute<0x300a, 0x00d1> WedgeSequence; + typedef gdcm::Attribute<0x300a, 0x00d2> WedgeNumber; + typedef gdcm::Attribute<0x300a, 0x00d3> WedgeType; + typedef gdcm::Attribute<0x300a, 0x00d4> WedgeID; + typedef gdcm::Attribute<0x300a, 0x00d5> WedgeAngle; + typedef gdcm::Attribute<0x300a, 0x00d6> WedgeFactor; + typedef gdcm::Attribute<0x300a, 0x00d7> TotalWedgeTrayWaterEquivalentThickness; + typedef gdcm::Attribute<0x300a, 0x00d8> WedgeOrientation; + typedef gdcm::Attribute<0x300a, 0x00d9> IsocenterToWedgeTrayDistance; + typedef gdcm::Attribute<0x300a, 0x00da> SourceToWedgeTrayDistance; + typedef gdcm::Attribute<0x300a, 0x00db> WedgeThinEdgePosition; + typedef gdcm::Attribute<0x300a, 0x00dc> BolusID; + typedef gdcm::Attribute<0x300a, 0x00dd> BolusDescription; + typedef gdcm::Attribute<0x300a, 0x00e0> NumberOfCompensators; + typedef gdcm::Attribute<0x300a, 0x00e1> MaterialID; + typedef gdcm::Attribute<0x300a, 0x00e2> TotalCompensatorTrayFactor; + typedef gdcm::Attribute<0x300a, 0x00e3> CompensatorSequence; + typedef gdcm::Attribute<0x300a, 0x00e4> CompensatorNumber; + typedef gdcm::Attribute<0x300a, 0x00e5> CompensatorID; + typedef gdcm::Attribute<0x300a, 0x00e6> SourceToCompensatorTrayDistance; + typedef gdcm::Attribute<0x300a, 0x00e7> CompensatorRows; + typedef gdcm::Attribute<0x300a, 0x00e8> CompensatorColumns; + typedef gdcm::Attribute<0x300a, 0x00e9> CompensatorPixelSpacing; + typedef gdcm::Attribute<0x300a, 0x00ea> CompensatorPosition; + typedef gdcm::Attribute<0x300a, 0x00eb> CompensatorTransmissionData; + typedef gdcm::Attribute<0x300a, 0x00ec> CompensatorThicknessData; + typedef gdcm::Attribute<0x300a, 0x00ed> NumberOfBoli; + typedef gdcm::Attribute<0x300a, 0x00ee> CompensatorType; + typedef gdcm::Attribute<0x300a, 0x00f0> NumberOfBlocks; + typedef gdcm::Attribute<0x300a, 0x00f2> TotalBlockTrayFactor; + typedef gdcm::Attribute<0x300a, 0x00f3> TotalBlockTrayWaterEquivalentThickness; + typedef gdcm::Attribute<0x300a, 0x00f4> BlockSequence; + typedef gdcm::Attribute<0x300a, 0x00f5> BlockTrayID; + typedef gdcm::Attribute<0x300a, 0x00f6> SourceToBlockTrayDistance; + typedef gdcm::Attribute<0x300a, 0x00f7> IsocenterToBlockTrayDistance; + typedef gdcm::Attribute<0x300a, 0x00f8> BlockType; + typedef gdcm::Attribute<0x300a, 0x00f9> AccessoryCode; + typedef gdcm::Attribute<0x300a, 0x00fa> BlockDivergence; + typedef gdcm::Attribute<0x300a, 0x00fb> BlockMountingPosition; + typedef gdcm::Attribute<0x300a, 0x00fc> BlockNumber; + typedef gdcm::Attribute<0x300a, 0x00fe> BlockName; + typedef gdcm::Attribute<0x300a, 0x0100> BlockThickness; + typedef gdcm::Attribute<0x300a, 0x0102> BlockTransmission; + typedef gdcm::Attribute<0x300a, 0x0104> BlockNumberOfPoints; + typedef gdcm::Attribute<0x300a, 0x0106> BlockData; + typedef gdcm::Attribute<0x300a, 0x0107> ApplicatorSequence; + typedef gdcm::Attribute<0x300a, 0x0108> ApplicatorID; + typedef gdcm::Attribute<0x300a, 0x0109> ApplicatorType; + typedef gdcm::Attribute<0x300a, 0x010a> ApplicatorDescription; + typedef gdcm::Attribute<0x300a, 0x010c> CumulativeDoseReferenceCoefficient; + typedef gdcm::Attribute<0x300a, 0x010e> FinalCumulativeMetersetWeight; + typedef gdcm::Attribute<0x300a, 0x0110> NumberOfControlPoints; + typedef gdcm::Attribute<0x300a, 0x0111> ControlPointSequence; + typedef gdcm::Attribute<0x300a, 0x0112> ControlPointIndex; + typedef gdcm::Attribute<0x300a, 0x0114> NominalBeamEnergy; + typedef gdcm::Attribute<0x300a, 0x0115> DoseRateSet; + typedef gdcm::Attribute<0x300a, 0x0116> WedgePositionSequence; + typedef gdcm::Attribute<0x300a, 0x0118> WedgePosition; + typedef gdcm::Attribute<0x300a, 0x011a> BeamLimitingDevicePositionSequence; + typedef gdcm::Attribute<0x300a, 0x011c> LeafJawPositions; + typedef gdcm::Attribute<0x300a, 0x011e> GantryAngle; + typedef gdcm::Attribute<0x300a, 0x011f> GantryRotationDirection; + typedef gdcm::Attribute<0x300a, 0x0120> BeamLimitingDeviceAngle; + typedef gdcm::Attribute<0x300a, 0x0121> BeamLimitingDeviceRotationDirection; + typedef gdcm::Attribute<0x300a, 0x0122> PatientSupportAngle; + typedef gdcm::Attribute<0x300a, 0x0123> PatientSupportRotationDirection; + typedef gdcm::Attribute<0x300a, 0x0124> TableTopEccentricAxisDistance; + typedef gdcm::Attribute<0x300a, 0x0125> TableTopEccentricAngle; + typedef gdcm::Attribute<0x300a, 0x0126> TableTopEccentricRotationDirection; + typedef gdcm::Attribute<0x300a, 0x0128> TableTopVerticalPosition; + typedef gdcm::Attribute<0x300a, 0x0129> TableTopLongitudinalPosition; + typedef gdcm::Attribute<0x300a, 0x012a> TableTopLateralPosition; + typedef gdcm::Attribute<0x300a, 0x012c> IsocenterPosition; + typedef gdcm::Attribute<0x300a, 0x012e> SurfaceEntryPoint; + typedef gdcm::Attribute<0x300a, 0x0130> SourceToSurfaceDistance; + typedef gdcm::Attribute<0x300a, 0x0134> CumulativeMetersetWeight; + typedef gdcm::Attribute<0x300a, 0x0140> TableTopPitchAngle; + typedef gdcm::Attribute<0x300a, 0x0142> TableTopPitchRotationDirection; + typedef gdcm::Attribute<0x300a, 0x0144> TableTopRollAngle; + typedef gdcm::Attribute<0x300a, 0x0146> TableTopRollRotationDirection; + typedef gdcm::Attribute<0x300a, 0x0148> HeadFixationAngle; + typedef gdcm::Attribute<0x300a, 0x014a> GantryPitchAngle; + typedef gdcm::Attribute<0x300a, 0x014c> GantryPitchRotationDirection; + typedef gdcm::Attribute<0x300a, 0x014e> GantryPitchAngleTolerance; + typedef gdcm::Attribute<0x300a, 0x0180> PatientSetupSequence; + typedef gdcm::Attribute<0x300a, 0x0182> PatientSetupNumber; + typedef gdcm::Attribute<0x300a, 0x0183> PatientSetupLabel; + typedef gdcm::Attribute<0x300a, 0x0184> PatientAdditionalPosition; + typedef gdcm::Attribute<0x300a, 0x0190> FixationDeviceSequence; + typedef gdcm::Attribute<0x300a, 0x0192> FixationDeviceType; + typedef gdcm::Attribute<0x300a, 0x0194> FixationDeviceLabel; + typedef gdcm::Attribute<0x300a, 0x0196> FixationDeviceDescription; + typedef gdcm::Attribute<0x300a, 0x0198> FixationDevicePosition; + typedef gdcm::Attribute<0x300a, 0x0199> FixationDevicePitchAngle; + typedef gdcm::Attribute<0x300a, 0x019a> FixationDeviceRollAngle; + typedef gdcm::Attribute<0x300a, 0x01a0> ShieldingDeviceSequence; + typedef gdcm::Attribute<0x300a, 0x01a2> ShieldingDeviceType; + typedef gdcm::Attribute<0x300a, 0x01a4> ShieldingDeviceLabel; + typedef gdcm::Attribute<0x300a, 0x01a6> ShieldingDeviceDescription; + typedef gdcm::Attribute<0x300a, 0x01a8> ShieldingDevicePosition; + typedef gdcm::Attribute<0x300a, 0x01b0> SetupTechnique; + typedef gdcm::Attribute<0x300a, 0x01b2> SetupTechniqueDescription; + typedef gdcm::Attribute<0x300a, 0x01b4> SetupDeviceSequence; + typedef gdcm::Attribute<0x300a, 0x01b6> SetupDeviceType; + typedef gdcm::Attribute<0x300a, 0x01b8> SetupDeviceLabel; + typedef gdcm::Attribute<0x300a, 0x01ba> SetupDeviceDescription; + typedef gdcm::Attribute<0x300a, 0x01bc> SetupDeviceParameter; + typedef gdcm::Attribute<0x300a, 0x01d0> SetupReferenceDescription; + typedef gdcm::Attribute<0x300a, 0x01d2> TableTopVerticalSetupDisplacement; + typedef gdcm::Attribute<0x300a, 0x01d4> TableTopLongitudinalSetupDisplacement; + typedef gdcm::Attribute<0x300a, 0x01d6> TableTopLateralSetupDisplacement; + typedef gdcm::Attribute<0x300a, 0x0200> BrachyTreatmentTechnique; + typedef gdcm::Attribute<0x300a, 0x0202> BrachyTreatmentType; + typedef gdcm::Attribute<0x300a, 0x0206> TreatmentMachineSequence; + typedef gdcm::Attribute<0x300a, 0x0210> SourceSequence; + typedef gdcm::Attribute<0x300a, 0x0212> SourceNumber; + typedef gdcm::Attribute<0x300a, 0x0214> SourceType; + typedef gdcm::Attribute<0x300a, 0x0216> SourceManufacturer; + typedef gdcm::Attribute<0x300a, 0x0218> ActiveSourceDiameter; + typedef gdcm::Attribute<0x300a, 0x021a> ActiveSourceLength; + typedef gdcm::Attribute<0x300a, 0x0222> SourceEncapsulationNominalThickness; + typedef gdcm::Attribute<0x300a, 0x0224> SourceEncapsulationNominalTransmission; + typedef gdcm::Attribute<0x300a, 0x0226> SourceIsotopeName; + typedef gdcm::Attribute<0x300a, 0x0228> SourceIsotopeHalfLife; + typedef gdcm::Attribute<0x300a, 0x0229> SourceStrengthUnits; + typedef gdcm::Attribute<0x300a, 0x022a> ReferenceAirKermaRate; + typedef gdcm::Attribute<0x300a, 0x022b> SourceStrength; + typedef gdcm::Attribute<0x300a, 0x022c> SourceStrengthReferenceDate; + typedef gdcm::Attribute<0x300a, 0x022e> SourceStrengthReferenceTime; + typedef gdcm::Attribute<0x300a, 0x0230> ApplicationSetupSequence; + typedef gdcm::Attribute<0x300a, 0x0232> ApplicationSetupType; + typedef gdcm::Attribute<0x300a, 0x0234> ApplicationSetupNumber; + typedef gdcm::Attribute<0x300a, 0x0236> ApplicationSetupName; + typedef gdcm::Attribute<0x300a, 0x0238> ApplicationSetupManufacturer; + typedef gdcm::Attribute<0x300a, 0x0240> TemplateNumber; + typedef gdcm::Attribute<0x300a, 0x0242> TemplateType; + typedef gdcm::Attribute<0x300a, 0x0244> TemplateName; + typedef gdcm::Attribute<0x300a, 0x0250> TotalReferenceAirKerma; + typedef gdcm::Attribute<0x300a, 0x0260> BrachyAccessoryDeviceSequence; + typedef gdcm::Attribute<0x300a, 0x0262> BrachyAccessoryDeviceNumber; + typedef gdcm::Attribute<0x300a, 0x0263> BrachyAccessoryDeviceID; + typedef gdcm::Attribute<0x300a, 0x0264> BrachyAccessoryDeviceType; + typedef gdcm::Attribute<0x300a, 0x0266> BrachyAccessoryDeviceName; + typedef gdcm::Attribute<0x300a, 0x026a> BrachyAccessoryDeviceNominalThickness; + typedef gdcm::Attribute<0x300a, 0x026c> BrachyAccessoryDeviceNominalTransmission; + typedef gdcm::Attribute<0x300a, 0x0280> ChannelSequence; + typedef gdcm::Attribute<0x300a, 0x0282> ChannelNumber; + typedef gdcm::Attribute<0x300a, 0x0284> ChannelLength; + typedef gdcm::Attribute<0x300a, 0x0286> ChannelTotalTime; + typedef gdcm::Attribute<0x300a, 0x0288> SourceMovementType; + typedef gdcm::Attribute<0x300a, 0x028a> NumberOfPulses; + typedef gdcm::Attribute<0x300a, 0x028c> PulseRepetitionInterval; + typedef gdcm::Attribute<0x300a, 0x0290> SourceApplicatorNumber; + typedef gdcm::Attribute<0x300a, 0x0291> SourceApplicatorID; + typedef gdcm::Attribute<0x300a, 0x0292> SourceApplicatorType; + typedef gdcm::Attribute<0x300a, 0x0294> SourceApplicatorName; + typedef gdcm::Attribute<0x300a, 0x0296> SourceApplicatorLength; + typedef gdcm::Attribute<0x300a, 0x0298> SourceApplicatorManufacturer; + typedef gdcm::Attribute<0x300a, 0x029c> SourceApplicatorWallNominalThickness; + typedef gdcm::Attribute<0x300a, 0x029e> SourceApplicatorWallNominalTransmission; + typedef gdcm::Attribute<0x300a, 0x02a0> SourceApplicatorStepSize; + typedef gdcm::Attribute<0x300a, 0x02a2> TransferTubeNumber; + typedef gdcm::Attribute<0x300a, 0x02a4> TransferTubeLength; + typedef gdcm::Attribute<0x300a, 0x02b0> ChannelShieldSequence; + typedef gdcm::Attribute<0x300a, 0x02b2> ChannelShieldNumber; + typedef gdcm::Attribute<0x300a, 0x02b3> ChannelShieldID; + typedef gdcm::Attribute<0x300a, 0x02b4> ChannelShieldName; + typedef gdcm::Attribute<0x300a, 0x02b8> ChannelShieldNominalThickness; + typedef gdcm::Attribute<0x300a, 0x02ba> ChannelShieldNominalTransmission; + typedef gdcm::Attribute<0x300a, 0x02c8> FinalCumulativeTimeWeight; + typedef gdcm::Attribute<0x300a, 0x02d0> BrachyControlPointSequence; + typedef gdcm::Attribute<0x300a, 0x02d2> ControlPointRelativePosition; + typedef gdcm::Attribute<0x300a, 0x02d4> ControlPoint3DPosition; + typedef gdcm::Attribute<0x300a, 0x02d6> CumulativeTimeWeight; + typedef gdcm::Attribute<0x300a, 0x02e0> CompensatorDivergence; + typedef gdcm::Attribute<0x300a, 0x02e1> CompensatorMountingPosition; + typedef gdcm::Attribute<0x300a, 0x02e2> SourceToCompensatorDistance; + typedef gdcm::Attribute<0x300a, 0x02e3> TotalCompensatorTrayWaterEquivalentThickness; + typedef gdcm::Attribute<0x300a, 0x02e4> IsocenterToCompensatorTrayDistance; + typedef gdcm::Attribute<0x300a, 0x02e5> CompensatorColumnOffset; + typedef gdcm::Attribute<0x300a, 0x02e6> IsocenterToCompensatorDistances; + typedef gdcm::Attribute<0x300a, 0x02e7> CompensatorRelativeStoppingPowerRatio; + typedef gdcm::Attribute<0x300a, 0x02e8> CompensatorMillingToolDiameter; + typedef gdcm::Attribute<0x300a, 0x02ea> IonRangeCompensatorSequence; + typedef gdcm::Attribute<0x300a, 0x02eb> CompensatorDescription; + typedef gdcm::Attribute<0x300a, 0x0302> RadiationMassNumber; + typedef gdcm::Attribute<0x300a, 0x0304> RadiationAtomicNumber; + typedef gdcm::Attribute<0x300a, 0x0306> RadiationChargeState; + typedef gdcm::Attribute<0x300a, 0x0308> ScanMode; + typedef gdcm::Attribute<0x300a, 0x030a> VirtualSourceAxisDistances; + typedef gdcm::Attribute<0x300a, 0x030c> SnoutSequence; + typedef gdcm::Attribute<0x300a, 0x030d> SnoutPosition; + typedef gdcm::Attribute<0x300a, 0x030f> SnoutID; + typedef gdcm::Attribute<0x300a, 0x0312> NumberOfRangeShifters; + typedef gdcm::Attribute<0x300a, 0x0314> RangeShifterSequence; + typedef gdcm::Attribute<0x300a, 0x0316> RangeShifterNumber; + typedef gdcm::Attribute<0x300a, 0x0318> RangeShifterID; + typedef gdcm::Attribute<0x300a, 0x0320> RangeShifterType; + typedef gdcm::Attribute<0x300a, 0x0322> RangeShifterDescription; + typedef gdcm::Attribute<0x300a, 0x0330> NumberOfLateralSpreadingDevices; + typedef gdcm::Attribute<0x300a, 0x0332> LateralSpreadingDeviceSequence; + typedef gdcm::Attribute<0x300a, 0x0334> LateralSpreadingDeviceNumber; + typedef gdcm::Attribute<0x300a, 0x0336> LateralSpreadingDeviceID; + typedef gdcm::Attribute<0x300a, 0x0338> LateralSpreadingDeviceType; + typedef gdcm::Attribute<0x300a, 0x033a> LateralSpreadingDeviceDescription; + typedef gdcm::Attribute<0x300a, 0x033c> LateralSpreadingDeviceWaterEquivalentThickness; + typedef gdcm::Attribute<0x300a, 0x0340> NumberOfRangeModulators; + typedef gdcm::Attribute<0x300a, 0x0342> RangeModulatorSequence; + typedef gdcm::Attribute<0x300a, 0x0344> RangeModulatorNumber; + typedef gdcm::Attribute<0x300a, 0x0346> RangeModulatorID; + typedef gdcm::Attribute<0x300a, 0x0348> RangeModulatorType; + typedef gdcm::Attribute<0x300a, 0x034a> RangeModulatorDescription; + typedef gdcm::Attribute<0x300a, 0x034c> BeamCurrentModulationID; + typedef gdcm::Attribute<0x300a, 0x0350> PatientSupportType; + typedef gdcm::Attribute<0x300a, 0x0352> PatientSupportID; + typedef gdcm::Attribute<0x300a, 0x0354> PatientSupportAccessoryCode; + typedef gdcm::Attribute<0x300a, 0x0356> FixationLightAzimuthalAngle; + typedef gdcm::Attribute<0x300a, 0x0358> FixationLightPolarAngle; + typedef gdcm::Attribute<0x300a, 0x035a> MetersetRate; + typedef gdcm::Attribute<0x300a, 0x0360> RangeShifterSettingsSequence; + typedef gdcm::Attribute<0x300a, 0x0362> RangeShifterSetting; + typedef gdcm::Attribute<0x300a, 0x0364> IsocenterToRangeShifterDistance; + typedef gdcm::Attribute<0x300a, 0x0366> RangeShifterWaterEquivalentThickness; + typedef gdcm::Attribute<0x300a, 0x0370> LateralSpreadingDeviceSettingsSequence; + typedef gdcm::Attribute<0x300a, 0x0372> LateralSpreadingDeviceSetting; + typedef gdcm::Attribute<0x300a, 0x0374> IsocenterToLateralSpreadingDeviceDistance; + typedef gdcm::Attribute<0x300a, 0x0380> RangeModulatorSettingsSequence; + typedef gdcm::Attribute<0x300a, 0x0382> RangeModulatorGatingStartValue; + typedef gdcm::Attribute<0x300a, 0x0384> RangeModulatorGatingStopValue; + typedef gdcm::Attribute<0x300a, 0x0386> RangeModulatorGatingStartWaterEquivalentThickness; + typedef gdcm::Attribute<0x300a, 0x0388> RangeModulatorGatingStopWaterEquivalentThickness; + typedef gdcm::Attribute<0x300a, 0x038a> IsocenterToRangeModulatorDistance; + typedef gdcm::Attribute<0x300a, 0x0390> ScanSpotTuneID; + typedef gdcm::Attribute<0x300a, 0x0392> NumberOfScanSpotPositions; + typedef gdcm::Attribute<0x300a, 0x0394> ScanSpotPositionMap; + typedef gdcm::Attribute<0x300a, 0x0396> ScanSpotMetersetWeights; + typedef gdcm::Attribute<0x300a, 0x0398> ScanningSpotSize; + typedef gdcm::Attribute<0x300a, 0x039a> NumberOfPaintings; + typedef gdcm::Attribute<0x300a, 0x03a0> IonToleranceTableSequence; + typedef gdcm::Attribute<0x300a, 0x03a2> IonBeamSequence; + typedef gdcm::Attribute<0x300a, 0x03a4> IonBeamLimitingDeviceSequence; + typedef gdcm::Attribute<0x300a, 0x03a6> IonBlockSequence; + typedef gdcm::Attribute<0x300a, 0x03a8> IonControlPointSequence; + typedef gdcm::Attribute<0x300a, 0x03aa> IonWedgeSequence; + typedef gdcm::Attribute<0x300a, 0x03ac> IonWedgePositionSequence; + typedef gdcm::Attribute<0x300a, 0x0401> ReferencedSetupImageSequence; + typedef gdcm::Attribute<0x300a, 0x0402> SetupImageComment; + typedef gdcm::Attribute<0x300a, 0x0410> MotionSynchronizationSequence; + typedef gdcm::Attribute<0x300a, 0x0412> ControlPointOrientation; + typedef gdcm::Attribute<0x300a, 0x0420> GeneralAccessorySequence; + typedef gdcm::Attribute<0x300a, 0x0421> GeneralAccessoryID; + typedef gdcm::Attribute<0x300a, 0x0422> GeneralAccessoryDescription; + typedef gdcm::Attribute<0x300a, 0x0423> GeneralAccessoryType; + typedef gdcm::Attribute<0x300a, 0x0424> GeneralAccessoryNumber; + typedef gdcm::Attribute<0x300a, 0x0431> ApplicatorGeometrySequence; + typedef gdcm::Attribute<0x300a, 0x0432> ApplicatorApertureShape; + typedef gdcm::Attribute<0x300a, 0x0433> ApplicatorOpening; + typedef gdcm::Attribute<0x300a, 0x0434> ApplicatorOpeningX; + typedef gdcm::Attribute<0x300a, 0x0435> ApplicatorOpeningY; + typedef gdcm::Attribute<0x300a, 0x0436> SourceToApplicatorMountingPositionDistance; + typedef gdcm::Attribute<0x300c, 0x0002> ReferencedRTPlanSequence; + typedef gdcm::Attribute<0x300c, 0x0004> ReferencedBeamSequence; + typedef gdcm::Attribute<0x300c, 0x0006> ReferencedBeamNumber; + typedef gdcm::Attribute<0x300c, 0x0007> ReferencedReferenceImageNumber; + typedef gdcm::Attribute<0x300c, 0x0008> StartCumulativeMetersetWeight; + typedef gdcm::Attribute<0x300c, 0x0009> EndCumulativeMetersetWeight; + typedef gdcm::Attribute<0x300c, 0x000a> ReferencedBrachyApplicationSetupSequence; + typedef gdcm::Attribute<0x300c, 0x000c> ReferencedBrachyApplicationSetupNumber; + typedef gdcm::Attribute<0x300c, 0x000e> ReferencedSourceNumber; + typedef gdcm::Attribute<0x300c, 0x0020> ReferencedFractionGroupSequence; + typedef gdcm::Attribute<0x300c, 0x0022> ReferencedFractionGroupNumber; + typedef gdcm::Attribute<0x300c, 0x0040> ReferencedVerificationImageSequence; + typedef gdcm::Attribute<0x300c, 0x0042> ReferencedReferenceImageSequence; + typedef gdcm::Attribute<0x300c, 0x0050> ReferencedDoseReferenceSequence; + typedef gdcm::Attribute<0x300c, 0x0051> ReferencedDoseReferenceNumber; + typedef gdcm::Attribute<0x300c, 0x0055> BrachyReferencedDoseReferenceSequence; + typedef gdcm::Attribute<0x300c, 0x0060> ReferencedStructureSetSequence; + typedef gdcm::Attribute<0x300c, 0x006a> ReferencedPatientSetupNumber; + typedef gdcm::Attribute<0x300c, 0x0080> ReferencedDoseSequence; + typedef gdcm::Attribute<0x300c, 0x00a0> ReferencedToleranceTableNumber; + typedef gdcm::Attribute<0x300c, 0x00b0> ReferencedBolusSequence; + typedef gdcm::Attribute<0x300c, 0x00c0> ReferencedWedgeNumber; + typedef gdcm::Attribute<0x300c, 0x00d0> ReferencedCompensatorNumber; + typedef gdcm::Attribute<0x300c, 0x00e0> ReferencedBlockNumber; + typedef gdcm::Attribute<0x300c, 0x00f0> ReferencedControlPointIndex; + typedef gdcm::Attribute<0x300c, 0x00f2> ReferencedControlPointSequence; + typedef gdcm::Attribute<0x300c, 0x00f4> ReferencedStartControlPointIndex; + typedef gdcm::Attribute<0x300c, 0x00f6> ReferencedStopControlPointIndex; + typedef gdcm::Attribute<0x300c, 0x0100> ReferencedRangeShifterNumber; + typedef gdcm::Attribute<0x300c, 0x0102> ReferencedLateralSpreadingDeviceNumber; + typedef gdcm::Attribute<0x300c, 0x0104> ReferencedRangeModulatorNumber; + typedef gdcm::Attribute<0x300e, 0x0002> ApprovalStatus; + typedef gdcm::Attribute<0x300e, 0x0004> ReviewDate; + typedef gdcm::Attribute<0x300e, 0x0005> ReviewTime; + typedef gdcm::Attribute<0x300e, 0x0008> ReviewerName; + typedef gdcm::Attribute<0x4000, 0x0010> Arbitrary; + typedef gdcm::Attribute<0x4000, 0x4000> TextComments; + typedef gdcm::Attribute<0x4008, 0x0040> ResultsID; + typedef gdcm::Attribute<0x4008, 0x0042> ResultsIDIssuer; + typedef gdcm::Attribute<0x4008, 0x0050> ReferencedInterpretationSequence; + typedef gdcm::Attribute<0x4008, 0x00ff> ReportProductionStatusTrial; + typedef gdcm::Attribute<0x4008, 0x0100> InterpretationRecordedDate; + typedef gdcm::Attribute<0x4008, 0x0101> InterpretationRecordedTime; + typedef gdcm::Attribute<0x4008, 0x0102> InterpretationRecorder; + typedef gdcm::Attribute<0x4008, 0x0103> ReferenceToRecordedSound; + typedef gdcm::Attribute<0x4008, 0x0108> InterpretationTranscriptionDate; + typedef gdcm::Attribute<0x4008, 0x0109> InterpretationTranscriptionTime; + typedef gdcm::Attribute<0x4008, 0x010a> InterpretationTranscriber; + typedef gdcm::Attribute<0x4008, 0x010b> InterpretationText; + typedef gdcm::Attribute<0x4008, 0x010c> InterpretationAuthor; + typedef gdcm::Attribute<0x4008, 0x0111> InterpretationApproverSequence; + typedef gdcm::Attribute<0x4008, 0x0112> InterpretationApprovalDate; + typedef gdcm::Attribute<0x4008, 0x0113> InterpretationApprovalTime; + typedef gdcm::Attribute<0x4008, 0x0114> PhysicianApprovingInterpretation; + typedef gdcm::Attribute<0x4008, 0x0115> InterpretationDiagnosisDescription; + typedef gdcm::Attribute<0x4008, 0x0117> InterpretationDiagnosisCodeSequence; + typedef gdcm::Attribute<0x4008, 0x0118> ResultsDistributionListSequence; + typedef gdcm::Attribute<0x4008, 0x0119> DistributionName; + typedef gdcm::Attribute<0x4008, 0x011a> DistributionAddress; + typedef gdcm::Attribute<0x4008, 0x0200> InterpretationID; + typedef gdcm::Attribute<0x4008, 0x0202> InterpretationIDIssuer; + typedef gdcm::Attribute<0x4008, 0x0210> InterpretationTypeID; + typedef gdcm::Attribute<0x4008, 0x0212> InterpretationStatusID; + typedef gdcm::Attribute<0x4008, 0x0300> Impressions; + typedef gdcm::Attribute<0x4008, 0x4000> ResultsComments; + typedef gdcm::Attribute<0x4010, 0x0001> LowEnergyDetectors; + typedef gdcm::Attribute<0x4010, 0x0002> HighEnergyDetectors; + typedef gdcm::Attribute<0x4010, 0x0004> DetectorGeometrySequence; + typedef gdcm::Attribute<0x4010, 0x1001> ThreatROIVoxelSequence; + typedef gdcm::Attribute<0x4010, 0x1004> ThreatROIBase; + typedef gdcm::Attribute<0x4010, 0x1005> ThreatROIExtents; + typedef gdcm::Attribute<0x4010, 0x1006> ThreatROIBitmap; + typedef gdcm::Attribute<0x4010, 0x1007> RouteSegmentID; + typedef gdcm::Attribute<0x4010, 0x1008> GantryType; + typedef gdcm::Attribute<0x4010, 0x1009> OOIOwnerType; + typedef gdcm::Attribute<0x4010, 0x100a> RouteSegmentSequence; + typedef gdcm::Attribute<0x4010, 0x1010> PotentialThreatObjectID; + typedef gdcm::Attribute<0x4010, 0x1011> ThreatSequence; + typedef gdcm::Attribute<0x4010, 0x1012> ThreatCategory; + typedef gdcm::Attribute<0x4010, 0x1013> ThreatCategoryDescription; + typedef gdcm::Attribute<0x4010, 0x1014> ATDAbilityAssessment; + typedef gdcm::Attribute<0x4010, 0x1015> ATDAssessmentFlag; + typedef gdcm::Attribute<0x4010, 0x1016> ATDAssessmentProbability; + typedef gdcm::Attribute<0x4010, 0x1017> Mass; + typedef gdcm::Attribute<0x4010, 0x1018> Density; + typedef gdcm::Attribute<0x4010, 0x1019> ZEffective; + typedef gdcm::Attribute<0x4010, 0x101a> BoardingPassID; + typedef gdcm::Attribute<0x4010, 0x101b> CenterOfMass; + typedef gdcm::Attribute<0x4010, 0x101c> CenterOfPTO; + typedef gdcm::Attribute<0x4010, 0x101d> BoundingPolygon; + typedef gdcm::Attribute<0x4010, 0x101e> RouteSegmentStartLocationID; + typedef gdcm::Attribute<0x4010, 0x101f> RouteSegmentEndLocationID; + typedef gdcm::Attribute<0x4010, 0x1020> RouteSegmentLocationIDType; + typedef gdcm::Attribute<0x4010, 0x1021> AbortReason; + typedef gdcm::Attribute<0x4010, 0x1023> VolumeOfPTO; + typedef gdcm::Attribute<0x4010, 0x1024> AbortFlag; + typedef gdcm::Attribute<0x4010, 0x1025> RouteSegmentStartTime; + typedef gdcm::Attribute<0x4010, 0x1026> RouteSegmentEndTime; + typedef gdcm::Attribute<0x4010, 0x1027> TDRType; + typedef gdcm::Attribute<0x4010, 0x1028> InternationalRouteSegment; + typedef gdcm::Attribute<0x4010, 0x1029> ThreatDetectionAlgorithmandVersion; + typedef gdcm::Attribute<0x4010, 0x102a> AssignedLocation; + typedef gdcm::Attribute<0x4010, 0x102b> AlarmDecisionTime; + typedef gdcm::Attribute<0x4010, 0x1031> AlarmDecision; + typedef gdcm::Attribute<0x4010, 0x1033> NumberOfTotalObjects; + typedef gdcm::Attribute<0x4010, 0x1034> NumberOfAlarmObjects; + typedef gdcm::Attribute<0x4010, 0x1037> PTORepresentationSequence; + typedef gdcm::Attribute<0x4010, 0x1038> ATDAssessmentSequence; + typedef gdcm::Attribute<0x4010, 0x1039> TIPType; + typedef gdcm::Attribute<0x4010, 0x103a> DICOSVersion; + typedef gdcm::Attribute<0x4010, 0x1041> OOIOwnerCreationTime; + typedef gdcm::Attribute<0x4010, 0x1042> OOIType; + typedef gdcm::Attribute<0x4010, 0x1043> OOISize; + typedef gdcm::Attribute<0x4010, 0x1044> AcquisitionStatus; + typedef gdcm::Attribute<0x4010, 0x1045> BasisMaterialsCodeSequence; + typedef gdcm::Attribute<0x4010, 0x1046> PhantomType; + typedef gdcm::Attribute<0x4010, 0x1047> OOIOwnerSequence; + typedef gdcm::Attribute<0x4010, 0x1048> ScanType; + typedef gdcm::Attribute<0x4010, 0x1051> ItineraryID; + typedef gdcm::Attribute<0x4010, 0x1052> ItineraryIDType; + typedef gdcm::Attribute<0x4010, 0x1053> ItineraryIDAssigningAuthority; + typedef gdcm::Attribute<0x4010, 0x1054> RouteID; + typedef gdcm::Attribute<0x4010, 0x1055> RouteIDAssigningAuthority; + typedef gdcm::Attribute<0x4010, 0x1056> InboundArrivalType; + typedef gdcm::Attribute<0x4010, 0x1058> CarrierID; + typedef gdcm::Attribute<0x4010, 0x1059> CarrierIDAssigningAuthority; + typedef gdcm::Attribute<0x4010, 0x1060> SourceOrientation; + typedef gdcm::Attribute<0x4010, 0x1061> SourcePosition; + typedef gdcm::Attribute<0x4010, 0x1062> BeltHeight; + typedef gdcm::Attribute<0x4010, 0x1064> AlgorithmRoutingCodeSequence; + typedef gdcm::Attribute<0x4010, 0x1067> TransportClassification; + typedef gdcm::Attribute<0x4010, 0x1068> OOITypeDescriptor; + typedef gdcm::Attribute<0x4010, 0x1069> TotalProcessingTime; + typedef gdcm::Attribute<0x4010, 0x106c> DetectorCalibrationData; + typedef gdcm::Attribute<0x4ffe, 0x0001> MACParametersSequence; + typedef gdcm::Attribute<0x5000, 0x0005> CurveDimensions; + typedef gdcm::Attribute<0x5000, 0x0010> NumberOfPoints; + typedef gdcm::Attribute<0x5000, 0x0020> TypeOfData; + typedef gdcm::Attribute<0x5000, 0x0022> CurveDescription; + typedef gdcm::Attribute<0x5000, 0x0030> AxisUnits; + typedef gdcm::Attribute<0x5000, 0x0040> AxisLabels; + typedef gdcm::Attribute<0x5000, 0x0103> DataValueRepresentation; + typedef gdcm::Attribute<0x5000, 0x0104> MinimumCoordinateValue; + typedef gdcm::Attribute<0x5000, 0x0105> MaximumCoordinateValue; + typedef gdcm::Attribute<0x5000, 0x0106> CurveRange; + typedef gdcm::Attribute<0x5000, 0x0110> CurveDataDescriptor; + typedef gdcm::Attribute<0x5000, 0x0112> CoordinateStartValue; + typedef gdcm::Attribute<0x5000, 0x0114> CoordinateStepValue; + typedef gdcm::Attribute<0x5000, 0x1001> CurveActivationLayer; + typedef gdcm::Attribute<0x5000, 0x2000> AudioType; + typedef gdcm::Attribute<0x5000, 0x2002> AudioSampleFormat; + typedef gdcm::Attribute<0x5000, 0x2004> NumberOfChannels; + typedef gdcm::Attribute<0x5000, 0x2006> NumberOfSamples; + typedef gdcm::Attribute<0x5000, 0x2008> SampleRate; + typedef gdcm::Attribute<0x5000, 0x200a> TotalTime; + typedef gdcm::Attribute<0x5000, 0x200c> AudioSampleData; + typedef gdcm::Attribute<0x5000, 0x200e> AudioComments; + typedef gdcm::Attribute<0x5000, 0x2500> CurveLabel; + typedef gdcm::Attribute<0x5000, 0x2600> CurveReferencedOverlaySequence; + typedef gdcm::Attribute<0x5000, 0x2610> CurveReferencedOverlayGroup; + typedef gdcm::Attribute<0x5000, 0x3000> CurveData; + typedef gdcm::Attribute<0x5200, 0x9229> SharedFunctionalGroupsSequence; + typedef gdcm::Attribute<0x5200, 0x9230> PerFrameFunctionalGroupsSequence; + typedef gdcm::Attribute<0x5400, 0x0100> WaveformSequence; + typedef gdcm::Attribute<0x5400, 0x0110> ChannelMinimumValue; + typedef gdcm::Attribute<0x5400, 0x0112> ChannelMaximumValue; + typedef gdcm::Attribute<0x5400, 0x1004> WaveformBitsAllocated; + typedef gdcm::Attribute<0x5400, 0x1006> WaveformSampleInterpretation; + typedef gdcm::Attribute<0x5400, 0x100a> WaveformPaddingValue; + typedef gdcm::Attribute<0x5400, 0x1010> WaveformData; + typedef gdcm::Attribute<0x5600, 0x0010> FirstOrderPhaseCorrectionAngle; + typedef gdcm::Attribute<0x5600, 0x0020> SpectroscopyData; + typedef gdcm::Attribute<0x6000, 0x0010> OverlayRows; + typedef gdcm::Attribute<0x6000, 0x0011> OverlayColumns; + typedef gdcm::Attribute<0x6000, 0x0012> OverlayPlanes; + typedef gdcm::Attribute<0x6000, 0x0015> NumberOfFramesInOverlay; + typedef gdcm::Attribute<0x6000, 0x0022> OverlayDescription; + typedef gdcm::Attribute<0x6000, 0x0040> OverlayType; + typedef gdcm::Attribute<0x6000, 0x0045> OverlaySubtype; + typedef gdcm::Attribute<0x6000, 0x0050> OverlayOrigin; + typedef gdcm::Attribute<0x6000, 0x0051> ImageFrameOrigin; + typedef gdcm::Attribute<0x6000, 0x0052> OverlayPlaneOrigin; + typedef gdcm::Attribute<0x6000, 0x0060> OverlayCompressionCode; + typedef gdcm::Attribute<0x6000, 0x0061> OverlayCompressionOriginator; + typedef gdcm::Attribute<0x6000, 0x0062> OverlayCompressionLabel; + typedef gdcm::Attribute<0x6000, 0x0063> OverlayCompressionDescription; + typedef gdcm::Attribute<0x6000, 0x0066> OverlayCompressionStepPointers; + typedef gdcm::Attribute<0x6000, 0x0068> OverlayRepeatInterval; + typedef gdcm::Attribute<0x6000, 0x0069> OverlayBitsGrouped; + typedef gdcm::Attribute<0x6000, 0x0100> OverlayBitsAllocated; + typedef gdcm::Attribute<0x6000, 0x0102> OverlayBitPosition; + typedef gdcm::Attribute<0x6000, 0x0110> OverlayFormat; + typedef gdcm::Attribute<0x6000, 0x0200> OverlayLocation; + typedef gdcm::Attribute<0x6000, 0x0800> OverlayCodeLabel; + typedef gdcm::Attribute<0x6000, 0x0802> OverlayNumberOfTables; + typedef gdcm::Attribute<0x6000, 0x0803> OverlayCodeTableLocation; + typedef gdcm::Attribute<0x6000, 0x0804> OverlayBitsForCodeWord; + typedef gdcm::Attribute<0x6000, 0x1001> OverlayActivationLayer; + typedef gdcm::Attribute<0x6000, 0x1100> OverlayDescriptorGray; + typedef gdcm::Attribute<0x6000, 0x1101> OverlayDescriptorRed; + typedef gdcm::Attribute<0x6000, 0x1102> OverlayDescriptorGreen; + typedef gdcm::Attribute<0x6000, 0x1103> OverlayDescriptorBlue; + typedef gdcm::Attribute<0x6000, 0x1200> OverlaysGray; + typedef gdcm::Attribute<0x6000, 0x1201> OverlaysRed; + typedef gdcm::Attribute<0x6000, 0x1202> OverlaysGreen; + typedef gdcm::Attribute<0x6000, 0x1203> OverlaysBlue; + typedef gdcm::Attribute<0x6000, 0x1301> ROIArea; + typedef gdcm::Attribute<0x6000, 0x1302> ROIMean; + typedef gdcm::Attribute<0x6000, 0x1303> ROIStandardDeviation; + typedef gdcm::Attribute<0x6000, 0x1500> OverlayLabel; + typedef gdcm::Attribute<0x6000, 0x3000> OverlayData; + typedef gdcm::Attribute<0x6000, 0x4000> OverlayComments; + typedef gdcm::Attribute<0x7fe0, 0x0010> PixelData; + typedef gdcm::Attribute<0x7fe0, 0x0020> CoefficientsSDVN; + typedef gdcm::Attribute<0x7fe0, 0x0030> CoefficientsSDHN; + typedef gdcm::Attribute<0x7fe0, 0x0040> CoefficientsSDDN; + typedef gdcm::Attribute<0x7f00, 0x0010> VariablePixelData; + typedef gdcm::Attribute<0x7f00, 0x0011> VariableNextDataGroup; + typedef gdcm::Attribute<0x7f00, 0x0020> VariableCoefficientsSDVN; + typedef gdcm::Attribute<0x7f00, 0x0030> VariableCoefficientsSDHN; + typedef gdcm::Attribute<0x7f00, 0x0040> VariableCoefficientsSDDN; + typedef gdcm::Attribute<0xfffa, 0xfffa> DigitalSignaturesSequence; + typedef gdcm::Attribute<0xfffc, 0xfffc> DataSetTrailingPadding; + typedef gdcm::Attribute<0xfffe, 0xe000> Item; + typedef gdcm::Attribute<0xfffe, 0xe00d> ItemDelimitationItem; + typedef gdcm::Attribute<0xfffe, 0xe0dd> SequenceDelimitationItem; + typedef gdcm::Attribute<0x0002, 0x0000> FileMetaInformationGroupLength; + typedef gdcm::Attribute<0x0002, 0x0001> FileMetaInformationVersion; + typedef gdcm::Attribute<0x0002, 0x0002> MediaStorageSOPClassUID; + typedef gdcm::Attribute<0x0002, 0x0003> MediaStorageSOPInstanceUID; + typedef gdcm::Attribute<0x0002, 0x0010> TransferSyntaxUID; + typedef gdcm::Attribute<0x0002, 0x0012> ImplementationClassUID; + typedef gdcm::Attribute<0x0002, 0x0013> ImplementationVersionName; + typedef gdcm::Attribute<0x0002, 0x0016> SourceApplicationEntityTitle; + typedef gdcm::Attribute<0x0002, 0x0100> PrivateInformationCreatorUID; + typedef gdcm::Attribute<0x0002, 0x0102> PrivateInformation; + typedef gdcm::Attribute<0x0004, 0x1130> FileSetID; + typedef gdcm::Attribute<0x0004, 0x1141> FileSetDescriptorFileID; + typedef gdcm::Attribute<0x0004, 0x1142> SpecificCharacterSetOfFileSetDescriptorFile; + typedef gdcm::Attribute<0x0004, 0x1200> OffsetOfTheFirstDirectoryRecordOfTheRootDirectoryEntity; + typedef gdcm::Attribute<0x0004, 0x1202> OffsetOfTheLastDirectoryRecordOfTheRootDirectoryEntity; + typedef gdcm::Attribute<0x0004, 0x1212> FileSetConsistencyFlag; + typedef gdcm::Attribute<0x0004, 0x1220> DirectoryRecordSequence; + typedef gdcm::Attribute<0x0004, 0x1400> OffsetOfTheNextDirectoryRecord; + typedef gdcm::Attribute<0x0004, 0x1410> RecordInUseFlag; + typedef gdcm::Attribute<0x0004, 0x1420> OffsetOfReferencedLowerLevelDirectoryEntity; + typedef gdcm::Attribute<0x0004, 0x1430> DirectoryRecordType; + typedef gdcm::Attribute<0x0004, 0x1432> PrivateRecordUID; + typedef gdcm::Attribute<0x0004, 0x1500> ReferencedFileID; + typedef gdcm::Attribute<0x0004, 0x1504> MRDRDirectoryRecordOffset; + typedef gdcm::Attribute<0x0004, 0x1510> ReferencedSOPClassUIDInFile; + typedef gdcm::Attribute<0x0004, 0x1511> ReferencedSOPInstanceUIDInFile; + typedef gdcm::Attribute<0x0004, 0x1512> ReferencedTransferSyntaxUIDInFile; + typedef gdcm::Attribute<0x0004, 0x151a> ReferencedRelatedGeneralSOPClassUIDInFile; + typedef gdcm::Attribute<0x0004, 0x1600> NumberOfReferences; + +} +} + +#endif diff --git a/gdcm/Source/DataDictionary/gdcmTagToType.h b/gdcm/Source/DataDictionary/gdcmTagToType.h new file mode 100644 index 0000000..175ad85 --- /dev/null +++ b/gdcm/Source/DataDictionary/gdcmTagToType.h @@ -0,0 +1,25222 @@ + +// GENERATED FILE DO NOT EDIT +// $ xsltproc TagToType.xsl Part6.xml > gdcmTagToType.h + +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#ifndef GDCMTAGTOTYPE_H +#define GDCMTAGTOTYPE_H + +#include "gdcmVR.h" +#include "gdcmVM.h" +#include "gdcmStaticAssert.h" + +namespace gdcm { +// default template: the compiler should only pick it up when the element is private: +template struct TagToType { +//GDCM_STATIC_ASSERT( group % 2 ); +enum { VRType = VR::VRALL }; +enum { VMType = VM::VM1_n }; +}; +// template for group length: +template struct TagToType { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0000,0x0000> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0000,0x0001> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0000,0x0002> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0000,0x0003> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0000,0x0010> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0000,0x0100> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0000,0x0110> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0000,0x0120> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0000,0x0200> { +static const char* GetVRString() { return "AE"; } +typedef VRToType::Type Type; +enum { VRType = VR::AE }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0000,0x0300> { +static const char* GetVRString() { return "AE"; } +typedef VRToType::Type Type; +enum { VRType = VR::AE }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0000,0x0400> { +static const char* GetVRString() { return "AE"; } +typedef VRToType::Type Type; +enum { VRType = VR::AE }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0000,0x0600> { +static const char* GetVRString() { return "AE"; } +typedef VRToType::Type Type; +enum { VRType = VR::AE }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0000,0x0700> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0000,0x0800> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0000,0x0850> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0000,0x0860> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0000,0x0900> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0000,0x0901> { +static const char* GetVRString() { return "AT"; } +typedef VRToType::Type Type; +enum { VRType = VR::AT }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0000,0x0902> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0000,0x0903> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0000,0x1000> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0000,0x1001> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0000,0x1002> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0000,0x1005> { +static const char* GetVRString() { return "AT"; } +typedef VRToType::Type Type; +enum { VRType = VR::AT }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0000,0x1008> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0000,0x1020> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0000,0x1021> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0000,0x1022> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0000,0x1023> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0000,0x1030> { +static const char* GetVRString() { return "AE"; } +typedef VRToType::Type Type; +enum { VRType = VR::AE }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0000,0x1031> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0000,0x4000> { +static const char* GetVRString() { return "LT"; } +typedef VRToType::Type Type; +enum { VRType = VR::LT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0000,0x4010> { +static const char* GetVRString() { return "LT"; } +typedef VRToType::Type Type; +enum { VRType = VR::LT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0000,0x5010> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0000,0x5020> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0000,0x5110> { +static const char* GetVRString() { return "LT"; } +typedef VRToType::Type Type; +enum { VRType = VR::LT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0000,0x5120> { +static const char* GetVRString() { return "LT"; } +typedef VRToType::Type Type; +enum { VRType = VR::LT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0000,0x5130> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0000,0x5140> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0000,0x5150> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0000,0x5160> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0000,0x5170> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0000,0x5180> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0000,0x5190> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0000,0x51a0> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0000,0x51b0> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0002,0x0000> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0002,0x0001> { +static const char* GetVRString() { return "OB"; } +typedef VRToType::Type Type; +enum { VRType = VR::OB }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0002,0x0002> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0002,0x0003> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0002,0x0010> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0002,0x0012> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0002,0x0013> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0002,0x0016> { +static const char* GetVRString() { return "AE"; } +typedef VRToType::Type Type; +enum { VRType = VR::AE }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0002,0x0100> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0002,0x0102> { +static const char* GetVRString() { return "OB"; } +typedef VRToType::Type Type; +enum { VRType = VR::OB }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0004,0x1130> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0004,0x1141> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1_8 }; +static const char* GetVMString() { return "1-8"; } +}; +template <> struct TagToType<0x0004,0x1142> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0004,0x1200> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0004,0x1202> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0004,0x1212> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0004,0x1220> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0004,0x1400> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0004,0x1410> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0004,0x1420> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0004,0x1430> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0004,0x1432> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0004,0x1500> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1_8 }; +static const char* GetVMString() { return "1-8"; } +}; +template <> struct TagToType<0x0004,0x1504> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0004,0x1510> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0004,0x1511> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0004,0x1512> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0004,0x151a> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0004,0x1600> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0001> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0005> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0008,0x0006> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0008> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM2_n }; +static const char* GetVMString() { return "2-n"; } +}; +template <> struct TagToType<0x0008,0x0010> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0012> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0013> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0014> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0016> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0018> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x001a> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0008,0x001b> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0020> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0021> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0022> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0023> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0024> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0025> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x002a> { +static const char* GetVRString() { return "DT"; } +typedef VRToType::Type Type; +enum { VRType = VR::DT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0030> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0031> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0032> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0033> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0034> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0035> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0040> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0041> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0042> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0050> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0051> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0052> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0054> { +static const char* GetVRString() { return "AE"; } +typedef VRToType::Type Type; +enum { VRType = VR::AE }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0008,0x0056> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0058> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0008,0x0060> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0061> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0008,0x0062> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0008,0x0064> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0068> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0070> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0080> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0081> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0082> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0090> { +static const char* GetVRString() { return "PN"; } +typedef VRToType::Type Type; +enum { VRType = VR::PN }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0092> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0094> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0008,0x0096> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0100> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0102> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0103> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0104> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0105> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0106> { +static const char* GetVRString() { return "DT"; } +typedef VRToType::Type Type; +enum { VRType = VR::DT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0107> { +static const char* GetVRString() { return "DT"; } +typedef VRToType::Type Type; +enum { VRType = VR::DT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x010b> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x010c> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x010d> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x010f> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0110> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0112> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0114> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0115> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0116> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0117> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x0201> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x1000> { +static const char* GetVRString() { return "AE"; } +typedef VRToType::Type Type; +enum { VRType = VR::AE }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x1010> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x1030> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x1032> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x103e> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x103f> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x1040> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x1048> { +static const char* GetVRString() { return "PN"; } +typedef VRToType::Type Type; +enum { VRType = VR::PN }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0008,0x1049> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x1050> { +static const char* GetVRString() { return "PN"; } +typedef VRToType::Type Type; +enum { VRType = VR::PN }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0008,0x1052> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x1060> { +static const char* GetVRString() { return "PN"; } +typedef VRToType::Type Type; +enum { VRType = VR::PN }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0008,0x1062> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x1070> { +static const char* GetVRString() { return "PN"; } +typedef VRToType::Type Type; +enum { VRType = VR::PN }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0008,0x1072> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x1080> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0008,0x1084> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x1090> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x1100> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x1110> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x1111> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x1115> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x1120> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x1125> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x1130> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x1134> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x113a> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x1140> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x1145> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x114a> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x114b> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x1150> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x1155> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x115a> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0008,0x1160> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0008,0x1161> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0008,0x1162> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM3_3n }; +static const char* GetVMString() { return "3-3n"; } +}; +template <> struct TagToType<0x0008,0x1163> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0008,0x1164> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x1167> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x1195> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x1197> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x1198> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x1199> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x1200> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x1250> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x2110> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x2111> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x2112> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x2120> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x2122> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x2124> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x2127> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x2128> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x2129> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x212a> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x2130> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0008,0x2132> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0008,0x2133> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x2134> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x2135> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x2142> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x2143> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x2144> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x2200> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x2204> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x2208> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x2218> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x2220> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x2228> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x2229> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x2230> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x2240> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x2242> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x2244> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x2246> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x2251> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x2253> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x2255> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x2256> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x2257> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x2258> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x2259> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x225a> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x225c> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x3001> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x3010> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x4000> { +static const char* GetVRString() { return "LT"; } +typedef VRToType::Type Type; +enum { VRType = VR::LT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x9007> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM4 }; +static const char* GetVMString() { return "4"; } +}; +template <> struct TagToType<0x0008,0x9092> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x9121> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x9123> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x9124> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x9154> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x9205> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x9206> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x9207> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x9208> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x9209> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x9215> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x9237> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x9410> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x9458> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x9459> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0008,0x9460> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0010,0x0010> { +static const char* GetVRString() { return "PN"; } +typedef VRToType::Type Type; +enum { VRType = VR::PN }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0010,0x0020> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0010,0x0021> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0010,0x0022> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0010,0x0024> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0010,0x0030> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0010,0x0032> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0010,0x0040> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0010,0x0050> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0010,0x0101> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0010,0x0102> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0010,0x1000> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0010,0x1001> { +static const char* GetVRString() { return "PN"; } +typedef VRToType::Type Type; +enum { VRType = VR::PN }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0010,0x1002> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0010,0x1005> { +static const char* GetVRString() { return "PN"; } +typedef VRToType::Type Type; +enum { VRType = VR::PN }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0010,0x1010> { +static const char* GetVRString() { return "AS"; } +typedef VRToType::Type Type; +enum { VRType = VR::AS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0010,0x1020> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0010,0x1021> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0010,0x1030> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0010,0x1040> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0010,0x1050> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0010,0x1060> { +static const char* GetVRString() { return "PN"; } +typedef VRToType::Type Type; +enum { VRType = VR::PN }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0010,0x1080> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0010,0x1081> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0010,0x1090> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0010,0x2000> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0010,0x2110> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0010,0x2150> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0010,0x2152> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0010,0x2154> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0010,0x2160> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0010,0x2180> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0010,0x21a0> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0010,0x21b0> { +static const char* GetVRString() { return "LT"; } +typedef VRToType::Type Type; +enum { VRType = VR::LT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0010,0x21c0> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0010,0x21d0> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0010,0x21f0> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0010,0x2201> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0010,0x2202> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0010,0x2203> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0010,0x2210> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0010,0x2292> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0010,0x2293> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0010,0x2294> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0010,0x2295> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0010,0x2296> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0010,0x2297> { +static const char* GetVRString() { return "PN"; } +typedef VRToType::Type Type; +enum { VRType = VR::PN }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0010,0x2298> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0010,0x2299> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0010,0x4000> { +static const char* GetVRString() { return "LT"; } +typedef VRToType::Type Type; +enum { VRType = VR::LT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0010,0x9431> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0012,0x0010> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0012,0x0020> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0012,0x0021> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0012,0x0030> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0012,0x0031> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0012,0x0040> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0012,0x0042> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0012,0x0050> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0012,0x0051> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0012,0x0060> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0012,0x0062> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0012,0x0063> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0012,0x0064> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0012,0x0071> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0012,0x0072> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0012,0x0081> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0012,0x0082> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0012,0x0083> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0012,0x0084> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0012,0x0085> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x0023> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0014,0x0024> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0014,0x0025> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0014,0x0028> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0014,0x0030> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0014,0x0032> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0014,0x0034> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0014,0x0042> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0014,0x0044> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0014,0x0045> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0014,0x0046> { +static const char* GetVRString() { return "LT"; } +typedef VRToType::Type Type; +enum { VRType = VR::LT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x0050> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x0052> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x0054> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x0056> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x1010> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x1020> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x1040> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x2002> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x2004> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x2006> { +static const char* GetVRString() { return "PN"; } +typedef VRToType::Type Type; +enum { VRType = VR::PN }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x2008> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x2012> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x2014> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x2016> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x2018> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x201a> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0014,0x201c> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x201e> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x2030> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x2032> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x2202> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x2204> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x2206> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x2208> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x220a> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x220c> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x220e> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x2210> { +static const char* GetVRString() { return "OB"; } +typedef VRToType::Type Type; +enum { VRType = VR::OB }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x2220> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x2222> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x2224> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x2226> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0014,0x2228> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x222a> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0014,0x222c> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0014,0x3011> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x3012> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x3020> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x3022> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x3024> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x3026> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x3028> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x3040> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x3060> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x3071> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x3072> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x3073> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x3074> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x3075> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x3076> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x3077> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x3080> { +static const char* GetVRString() { return "OB"; } +typedef VRToType::Type Type; +enum { VRType = VR::OB }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x3099> { +static const char* GetVRString() { return "LT"; } +typedef VRToType::Type Type; +enum { VRType = VR::LT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x4002> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x4004> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x4006> { +static const char* GetVRString() { return "LT"; } +typedef VRToType::Type Type; +enum { VRType = VR::LT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x4008> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x400a> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x400c> { +static const char* GetVRString() { return "LT"; } +typedef VRToType::Type Type; +enum { VRType = VR::LT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x400e> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x400f> { +static const char* GetVRString() { return "LT"; } +typedef VRToType::Type Type; +enum { VRType = VR::LT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x4010> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x4011> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x4012> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x4013> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x4014> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x4015> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x4016> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x4017> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x4018> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x4019> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x401a> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x401b> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x401c> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x4020> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x4022> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x4024> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x4026> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x4028> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x4030> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x4031> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x4032> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x4033> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x4034> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x4035> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x4036> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x4038> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0014,0x403a> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0014,0x403c> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0014,0x4040> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x4050> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x4051> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x4052> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x4054> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x4056> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x4057> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x4058> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x4059> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x405a> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x405c> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x4060> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x4062> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x4064> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x4070> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x4072> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x4074> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x4076> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x4078> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x407a> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x407c> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0014,0x407e> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0014,0x5002> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0014,0x5004> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x0010> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x0012> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x0014> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x0015> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x0020> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0018,0x0021> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0018,0x0022> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0018,0x0023> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x0024> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x0025> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x0026> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x0027> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x0028> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x0029> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x002a> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x0030> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0018,0x0031> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x0032> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x0033> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0018,0x0034> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x0035> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x0036> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x0037> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x0038> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x0039> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x003a> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x0040> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x0042> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x0050> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x0060> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x0070> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x0071> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x0072> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x0073> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x0074> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x0075> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x0080> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x0081> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x0082> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x0083> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x0084> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x0085> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x0086> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0018,0x0087> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x0088> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x0089> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x0090> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x0091> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x0093> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x0094> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x0095> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1000> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1002> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1003> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1004> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1005> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1006> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1007> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1008> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1010> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1011> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1012> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1014> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1016> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1017> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1018> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1019> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0018,0x101a> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0018,0x101b> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1020> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0018,0x1022> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1023> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1030> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1040> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1041> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1042> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1043> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1044> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1045> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1046> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0018,0x1047> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0018,0x1048> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1049> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1050> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1060> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1061> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1062> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1063> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1064> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1065> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0018,0x1066> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1067> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1068> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1069> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x106a> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x106c> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0018,0x106e> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1070> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1071> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1072> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1073> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1074> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1075> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1076> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1077> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1078> { +static const char* GetVRString() { return "DT"; } +typedef VRToType::Type Type; +enum { VRType = VR::DT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1079> { +static const char* GetVRString() { return "DT"; } +typedef VRToType::Type Type; +enum { VRType = VR::DT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1080> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1081> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1082> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1083> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1084> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1085> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1086> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1088> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1090> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1094> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1100> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1110> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1111> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1114> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1120> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1121> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1130> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1131> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1134> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1135> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0018,0x1136> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0018,0x1137> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0018,0x1138> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x113a> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1140> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1141> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1142> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0018,0x1143> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1144> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1145> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1146> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0018,0x1147> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1149> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1_2 }; +static const char* GetVMString() { return "1-2"; } +}; +template <> struct TagToType<0x0018,0x1150> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1151> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1152> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1153> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1154> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1155> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1156> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x115a> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x115e> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1160> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1161> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0018,0x1162> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1164> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0018,0x1166> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0018,0x1170> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1180> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1181> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1182> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1_2 }; +static const char* GetVMString() { return "1-2"; } +}; +template <> struct TagToType<0x0018,0x1183> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1_2 }; +static const char* GetVMString() { return "1-2"; } +}; +template <> struct TagToType<0x0018,0x1184> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1_2 }; +static const char* GetVMString() { return "1-2"; } +}; +template <> struct TagToType<0x0018,0x1190> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0018,0x1191> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x11a0> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x11a2> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1200> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0018,0x1201> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0018,0x1210> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0018,0x1240> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0018,0x1242> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1243> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1244> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1250> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1251> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1260> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1261> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1300> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1301> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0018,0x1302> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1310> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM4 }; +static const char* GetVMString() { return "4"; } +}; +template <> struct TagToType<0x0018,0x1312> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1314> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1315> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1316> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1318> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1400> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1401> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1402> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1403> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1404> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1405> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1411> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1412> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1413> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1450> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1460> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1470> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1480> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1490> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1491> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1495> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1500> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1508> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1510> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1511> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1520> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0018,0x1521> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0018,0x1530> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1531> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1600> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1_3 }; +static const char* GetVMString() { return "1-3"; } +}; +template <> struct TagToType<0x0018,0x1602> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1604> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1606> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1608> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1610> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0018,0x1612> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1620> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM2_2n }; +static const char* GetVMString() { return "2-2n"; } +}; +template <> struct TagToType<0x0018,0x1622> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1623> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1624> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x0018,0x1700> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1_3 }; +static const char* GetVMString() { return "1-3"; } +}; +template <> struct TagToType<0x0018,0x1702> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1704> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1706> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1708> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1710> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0018,0x1712> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1720> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM2_2n }; +static const char* GetVMString() { return "2-2n"; } +}; +template <> struct TagToType<0x0018,0x1800> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1801> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1802> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x1803> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x2001> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0018,0x2002> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0018,0x2003> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0018,0x2004> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0018,0x2005> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0018,0x2006> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0018,0x2010> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0018,0x2020> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x2030> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x3100> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x3101> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x3102> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x3103> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x3104> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x3105> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0018,0x4000> { +static const char* GetVRString() { return "LT"; } +typedef VRToType::Type Type; +enum { VRType = VR::LT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x5000> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0018,0x5010> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0018,0x5012> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x5020> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x5021> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x5022> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x5024> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x5026> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x5027> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x5028> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x5029> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x5030> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x5040> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x5050> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x5100> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x5101> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x5104> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x5210> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM6 }; +static const char* GetVMString() { return "6"; } +}; +template <> struct TagToType<0x0018,0x5212> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x0018,0x6000> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x6011> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x6012> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x6014> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x6016> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x6018> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x601a> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x601c> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x601e> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x6020> { +static const char* GetVRString() { return "SL"; } +typedef VRToType::Type Type; +enum { VRType = VR::SL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x6022> { +static const char* GetVRString() { return "SL"; } +typedef VRToType::Type Type; +enum { VRType = VR::SL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x6024> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x6026> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x6028> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x602a> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x602c> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x602e> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x6030> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x6031> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x6032> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x6034> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x6036> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x6038> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x6039> { +static const char* GetVRString() { return "SL"; } +typedef VRToType::Type Type; +enum { VRType = VR::SL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x603a> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x603b> { +static const char* GetVRString() { return "SL"; } +typedef VRToType::Type Type; +enum { VRType = VR::SL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x603c> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x603d> { +static const char* GetVRString() { return "SL"; } +typedef VRToType::Type Type; +enum { VRType = VR::SL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x603e> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x603f> { +static const char* GetVRString() { return "SL"; } +typedef VRToType::Type Type; +enum { VRType = VR::SL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x6040> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x6041> { +static const char* GetVRString() { return "SL"; } +typedef VRToType::Type Type; +enum { VRType = VR::SL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x6042> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x6043> { +static const char* GetVRString() { return "SL"; } +typedef VRToType::Type Type; +enum { VRType = VR::SL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x6044> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x6046> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x6048> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x604a> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x604c> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x604e> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x6050> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x6052> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0018,0x6054> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0018,0x6056> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x6058> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0018,0x605a> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0018,0x6060> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0018,0x7000> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x7001> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x7004> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x7005> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x7006> { +static const char* GetVRString() { return "LT"; } +typedef VRToType::Type Type; +enum { VRType = VR::LT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x7008> { +static const char* GetVRString() { return "LT"; } +typedef VRToType::Type Type; +enum { VRType = VR::LT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x700a> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x700c> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x700e> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x7010> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x7011> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x7012> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x7014> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x7016> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x701a> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0018,0x7020> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0018,0x7022> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0018,0x7024> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x7026> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1_2 }; +static const char* GetVMString() { return "1-2"; } +}; +template <> struct TagToType<0x0018,0x7028> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0018,0x702a> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x702b> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x7030> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0018,0x7032> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x7034> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x7036> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0018,0x7038> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x7040> { +static const char* GetVRString() { return "LT"; } +typedef VRToType::Type Type; +enum { VRType = VR::LT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x7041> { +static const char* GetVRString() { return "LT"; } +typedef VRToType::Type Type; +enum { VRType = VR::LT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x7042> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x7044> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x7046> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0018,0x7048> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x704c> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x7050> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0018,0x7052> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0018,0x7054> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0018,0x7056> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0018,0x7058> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0018,0x7060> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x7062> { +static const char* GetVRString() { return "LT"; } +typedef VRToType::Type Type; +enum { VRType = VR::LT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x7064> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x7065> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x8150> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x8151> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9004> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9005> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9006> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9008> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9009> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9010> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9011> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9012> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9014> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9015> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9016> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9017> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9018> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9019> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9020> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9021> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9022> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9024> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9025> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9026> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9027> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9028> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9029> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9030> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9032> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9033> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9034> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9035> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9036> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9037> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9041> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9042> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9043> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9044> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9045> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9046> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9047> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9048> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9049> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9050> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9051> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9052> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1_2 }; +static const char* GetVMString() { return "1-2"; } +}; +template <> struct TagToType<0x0018,0x9053> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1_2 }; +static const char* GetVMString() { return "1-2"; } +}; +template <> struct TagToType<0x0018,0x9054> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9058> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9059> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9060> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1_2 }; +static const char* GetVMString() { return "1-2"; } +}; +template <> struct TagToType<0x0018,0x9061> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1_2 }; +static const char* GetVMString() { return "1-2"; } +}; +template <> struct TagToType<0x0018,0x9062> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9063> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1_2 }; +static const char* GetVMString() { return "1-2"; } +}; +template <> struct TagToType<0x0018,0x9064> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9065> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1_2 }; +static const char* GetVMString() { return "1-2"; } +}; +template <> struct TagToType<0x0018,0x9066> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1_2 }; +static const char* GetVMString() { return "1-2"; } +}; +template <> struct TagToType<0x0018,0x9067> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9069> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9070> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9073> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9074> { +static const char* GetVRString() { return "DT"; } +typedef VRToType::Type Type; +enum { VRType = VR::DT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9075> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9076> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9077> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9078> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9079> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0018,0x9080> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9081> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9082> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9083> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9084> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9085> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9087> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9089> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x0018,0x9090> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x0018,0x9091> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9092> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9093> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9094> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9095> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9096> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9098> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1_2 }; +static const char* GetVMString() { return "1-2"; } +}; +template <> struct TagToType<0x0018,0x9100> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1_2 }; +static const char* GetVMString() { return "1-2"; } +}; +template <> struct TagToType<0x0018,0x9101> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9103> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9104> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9105> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x0018,0x9106> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x0018,0x9107> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9112> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9114> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9115> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9117> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9118> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9119> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9125> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9126> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9127> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9147> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9151> { +static const char* GetVRString() { return "DT"; } +typedef VRToType::Type Type; +enum { VRType = VR::DT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9152> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9155> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9159> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9166> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9168> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9169> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9170> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9171> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9172> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9173> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9174> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9175> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9176> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9177> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9178> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9179> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9180> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9181> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9182> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9183> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9184> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9185> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9186> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9195> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9196> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9197> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9198> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9199> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9200> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9214> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9217> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9218> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9219> { +static const char* GetVRString() { return "SS"; } +typedef VRToType::Type Type; +enum { VRType = VR::SS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9220> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9226> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9227> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9231> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9232> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9234> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9236> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9239> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9240> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9241> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9250> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9251> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9252> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9253> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9254> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9255> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x0018,0x9256> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x0018,0x9257> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9258> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9259> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x925a> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x925b> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x925c> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x925d> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x925e> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x925f> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9260> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9295> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9296> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9301> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9302> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9303> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9304> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9305> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9306> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9307> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9308> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9309> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9310> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9311> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9312> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9313> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x0018,0x9314> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9315> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9316> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9317> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0018,0x9318> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x0018,0x9319> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9320> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9321> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9322> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0018,0x9323> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9324> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9325> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9326> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9327> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9328> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9329> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9330> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9332> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9333> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9334> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9335> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9337> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9338> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9340> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9341> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9342> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9343> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9344> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9345> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9346> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9351> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9352> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x0018,0x9353> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9360> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9401> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9402> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9403> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9404> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0018,0x9405> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9406> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9407> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9410> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9412> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9417> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9420> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9423> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9424> { +static const char* GetVRString() { return "LT"; } +typedef VRToType::Type Type; +enum { VRType = VR::LT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9425> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9426> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9427> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9428> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1_2 }; +static const char* GetVMString() { return "1-2"; } +}; +template <> struct TagToType<0x0018,0x9429> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0018,0x9430> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0018,0x9432> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9433> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9434> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9435> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9436> { +static const char* GetVRString() { return "SS"; } +typedef VRToType::Type Type; +enum { VRType = VR::SS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9437> { +static const char* GetVRString() { return "SS"; } +typedef VRToType::Type Type; +enum { VRType = VR::SS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9438> { +static const char* GetVRString() { return "SS"; } +typedef VRToType::Type Type; +enum { VRType = VR::SS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9439> { +static const char* GetVRString() { return "SS"; } +typedef VRToType::Type Type; +enum { VRType = VR::SS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9440> { +static const char* GetVRString() { return "SS"; } +typedef VRToType::Type Type; +enum { VRType = VR::SS }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0018,0x9441> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9442> { +static const char* GetVRString() { return "SS"; } +typedef VRToType::Type Type; +enum { VRType = VR::SS }; +enum { VMType = VM::VM2_n }; +static const char* GetVMString() { return "2-n"; } +}; +template <> struct TagToType<0x0018,0x9447> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9449> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9451> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9452> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9455> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9456> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9457> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9461> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1_2 }; +static const char* GetVMString() { return "1-2"; } +}; +template <> struct TagToType<0x0018,0x9462> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9463> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9464> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9465> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9466> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9467> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9468> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9469> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9470> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9471> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9472> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9473> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9474> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9476> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9477> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9504> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9506> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9507> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9508> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9509> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9510> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9511> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9514> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9515> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9516> { +static const char* GetVRString() { return "DT"; } +typedef VRToType::Type Type; +enum { VRType = VR::DT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9517> { +static const char* GetVRString() { return "DT"; } +typedef VRToType::Type Type; +enum { VRType = VR::DT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9524> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9525> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9526> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9527> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9528> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9530> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9531> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9538> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9601> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9602> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9603> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9604> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9605> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9606> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9607> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9701> { +static const char* GetVRString() { return "DT"; } +typedef VRToType::Type Type; +enum { VRType = VR::DT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9715> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9716> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9717> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9718> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9719> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9720> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9721> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9722> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9723> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9724> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9725> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9726> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9727> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9729> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9732> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9733> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9734> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9735> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9736> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9737> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9738> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9739> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9740> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9749> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9751> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9755> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9756> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9758> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9759> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9760> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9761> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9762> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9763> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9764> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9765> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9766> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9767> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9768> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9769> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9770> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9771> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9772> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9801> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0018,0x9803> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9804> { +static const char* GetVRString() { return "DT"; } +typedef VRToType::Type Type; +enum { VRType = VR::DT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9805> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9806> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9807> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9808> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x9809> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x980b> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x980c> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x980d> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x980e> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0x980f> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0xa001> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0xa002> { +static const char* GetVRString() { return "DT"; } +typedef VRToType::Type Type; +enum { VRType = VR::DT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0018,0xa003> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x000d> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x000e> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x0010> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x0011> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x0012> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x0013> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x0014> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x0015> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x0016> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x0017> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x0018> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x0019> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x0020> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0020,0x0022> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x0024> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x0026> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x0030> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x0020,0x0032> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x0020,0x0035> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM6 }; +static const char* GetVMString() { return "6"; } +}; +template <> struct TagToType<0x0020,0x0037> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM6 }; +static const char* GetVMString() { return "6"; } +}; +template <> struct TagToType<0x0020,0x0050> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x0052> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x0060> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x0062> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x0070> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x0080> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0020,0x00aa> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x0100> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x0105> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x0110> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x0200> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x0242> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x1000> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x1001> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x1002> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x1003> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x1004> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x1005> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x1020> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0020,0x1040> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x1041> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x1070> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0020,0x1200> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x1202> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x1204> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x1206> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x1208> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x1209> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x3401> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x3402> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x3403> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x3404> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x3405> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x3406> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x4000> { +static const char* GetVRString() { return "LT"; } +typedef VRToType::Type Type; +enum { VRType = VR::LT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x5000> { +static const char* GetVRString() { return "AT"; } +typedef VRToType::Type Type; +enum { VRType = VR::AT }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0020,0x5002> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0020,0x9056> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x9057> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x9071> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x9072> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x9111> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x9113> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x9116> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x9128> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x9153> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x9154> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x9155> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x9156> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x9157> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0020,0x9158> { +static const char* GetVRString() { return "LT"; } +typedef VRToType::Type Type; +enum { VRType = VR::LT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x9161> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x9162> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x9163> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x9164> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x9165> { +static const char* GetVRString() { return "AT"; } +typedef VRToType::Type Type; +enum { VRType = VR::AT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x9167> { +static const char* GetVRString() { return "AT"; } +typedef VRToType::Type Type; +enum { VRType = VR::AT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x9213> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x9221> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x9222> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x9228> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x9238> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x9241> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x9245> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x9246> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x9247> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x9248> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x9249> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x9250> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x9251> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x9252> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x9253> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x9254> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x9255> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x9256> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x9257> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x9301> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x0020,0x9302> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM6 }; +static const char* GetVMString() { return "6"; } +}; +template <> struct TagToType<0x0020,0x9307> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x9308> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x0020,0x9309> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM16 }; +static const char* GetVMString() { return "16"; } +}; +template <> struct TagToType<0x0020,0x930a> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM16 }; +static const char* GetVMString() { return "16"; } +}; +template <> struct TagToType<0x0020,0x930c> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x930d> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x930e> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x930f> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x9310> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x9311> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x9312> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x9313> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x9421> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x9450> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x9453> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x9518> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0020,0x9529> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0020,0x9536> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x0001> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x0002> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0022,0x0003> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x0004> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0022,0x0005> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x0006> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x0007> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x0008> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x0009> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x000a> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x000b> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x000c> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x000d> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x000e> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x0010> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x0011> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x0012> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x0013> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x0014> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x0015> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x0016> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x0017> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x0018> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x0019> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x001a> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x001b> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x001c> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x001d> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x001e> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x0020> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x0021> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x0022> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x0030> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x0031> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x0032> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM2_2n }; +static const char* GetVMString() { return "2-2n"; } +}; +template <> struct TagToType<0x0022,0x0035> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x0036> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x0037> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x0038> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x0039> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x0041> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x0042> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x0048> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x0049> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x004e> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x0055> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x0056> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x0057> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x0058> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1007> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1008> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1009> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1010> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1012> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1019> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1024> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1025> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1028> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1029> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1033> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1035> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1037> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1039> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1040> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1044> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1050> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1053> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1054> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1059> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1065> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1066> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1090> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1092> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1093> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1094> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1095> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1096> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1097> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1100> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1101> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1103> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1121> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1122> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1125> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1127> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1128> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1130> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1131> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1132> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1133> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1134> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1135> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1140> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1150> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1153> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1155> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1159> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1210> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1211> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1212> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1220> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1225> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1230> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1250> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1255> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1257> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1260> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1262> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1273> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1300> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1310> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0022,0x1330> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0010> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0011> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0012> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0016> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0018> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0020> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0021> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0024> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0025> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0028> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0032> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0033> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0034> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0035> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0036> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0037> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0038> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0039> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0040> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0042> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0044> { +static const char* GetVRString() { return "LT"; } +typedef VRToType::Type Type; +enum { VRType = VR::LT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0045> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0046> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0048> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0050> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0051> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0052> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0053> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0054> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0055> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0056> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0057> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0058> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0059> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0060> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0061> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0062> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0063> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0064> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0065> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0066> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0067> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0068> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0069> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0070> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0071> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0072> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0073> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0074> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0075> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0076> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0077> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0078> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0079> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0080> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0081> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0083> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0085> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0086> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0087> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0088> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0089> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0090> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0091> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0092> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0093> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0094> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0095> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0096> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0097> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0098> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0100> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0102> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0103> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0104> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0105> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0106> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0107> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0108> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0110> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0112> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0113> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0114> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0115> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0117> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0118> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0120> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0122> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0124> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0126> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0202> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0306> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0307> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0308> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0309> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0317> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0320> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0325> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0338> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0341> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0024,0x0344> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x0002> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x0003> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x0004> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x0005> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x0006> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x0008> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x0009> { +static const char* GetVRString() { return "AT"; } +typedef VRToType::Type Type; +enum { VRType = VR::AT }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0028,0x000a> { +static const char* GetVRString() { return "AT"; } +typedef VRToType::Type Type; +enum { VRType = VR::AT }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0028,0x0010> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x0011> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x0012> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x0014> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x0030> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0028,0x0031> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0028,0x0032> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0028,0x0034> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0028,0x0040> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x0050> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0028,0x0051> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0028,0x005f> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x0060> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x0061> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x0062> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x0063> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x0065> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0028,0x0066> { +static const char* GetVRString() { return "AT"; } +typedef VRToType::Type Type; +enum { VRType = VR::AT }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0028,0x0068> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x0069> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x0070> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0028,0x0080> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x0081> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x0082> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0028,0x0090> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x0091> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x0092> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x0093> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x0094> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x0100> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x0101> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x0102> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x0103> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x0200> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x0300> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x0301> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x0302> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x0303> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x0304> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x0400> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x0401> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x0402> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x0403> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0028,0x0404> { +static const char* GetVRString() { return "AT"; } +typedef VRToType::Type Type; +enum { VRType = VR::AT }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0028,0x0700> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x0701> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0028,0x0702> { +static const char* GetVRString() { return "AT"; } +typedef VRToType::Type Type; +enum { VRType = VR::AT }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0028,0x0710> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x0720> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x0721> { +static const char* GetVRString() { return "AT"; } +typedef VRToType::Type Type; +enum { VRType = VR::AT }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0028,0x0722> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x0730> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x0740> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x0a02> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x0a04> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x1040> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x1041> { +static const char* GetVRString() { return "SS"; } +typedef VRToType::Type Type; +enum { VRType = VR::SS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x1050> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0028,0x1051> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0028,0x1052> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x1053> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x1054> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x1055> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0028,0x1056> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x1080> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x1090> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x1104> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x0028,0x1199> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x1201> { +static const char* GetVRString() { return "OW"; } +typedef VRToType::Type Type; +enum { VRType = VR::OW }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x1202> { +static const char* GetVRString() { return "OW"; } +typedef VRToType::Type Type; +enum { VRType = VR::OW }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x1203> { +static const char* GetVRString() { return "OW"; } +typedef VRToType::Type Type; +enum { VRType = VR::OW }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x1204> { +static const char* GetVRString() { return "OW"; } +typedef VRToType::Type Type; +enum { VRType = VR::OW }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x1211> { +static const char* GetVRString() { return "OW"; } +typedef VRToType::Type Type; +enum { VRType = VR::OW }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x1212> { +static const char* GetVRString() { return "OW"; } +typedef VRToType::Type Type; +enum { VRType = VR::OW }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x1213> { +static const char* GetVRString() { return "OW"; } +typedef VRToType::Type Type; +enum { VRType = VR::OW }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x1214> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x1221> { +static const char* GetVRString() { return "OW"; } +typedef VRToType::Type Type; +enum { VRType = VR::OW }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x1222> { +static const char* GetVRString() { return "OW"; } +typedef VRToType::Type Type; +enum { VRType = VR::OW }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x1223> { +static const char* GetVRString() { return "OW"; } +typedef VRToType::Type Type; +enum { VRType = VR::OW }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x1300> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x1350> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x1351> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x1352> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x135a> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x1401> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x1402> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x1403> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x1404> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x1405> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x1406> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x1407> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x0028,0x1408> { +static const char* GetVRString() { return "OW"; } +typedef VRToType::Type Type; +enum { VRType = VR::OW }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x140b> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x140c> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x140d> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x140e> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x140f> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x1410> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x2000> { +static const char* GetVRString() { return "OB"; } +typedef VRToType::Type Type; +enum { VRType = VR::OB }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x2110> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x2112> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0028,0x2114> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0028,0x3000> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x3003> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x3004> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x3010> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x3110> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x4000> { +static const char* GetVRString() { return "LT"; } +typedef VRToType::Type Type; +enum { VRType = VR::LT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x5000> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x6010> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x6020> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0028,0x6022> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0028,0x6023> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0028,0x6030> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0028,0x6040> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0028,0x6100> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x6101> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x6102> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM2_2n }; +static const char* GetVMString() { return "2-2n"; } +}; +template <> struct TagToType<0x0028,0x6110> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0028,0x6112> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x6114> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0028,0x6120> { +static const char* GetVRString() { return "SS"; } +typedef VRToType::Type Type; +enum { VRType = VR::SS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x6190> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x7fe0> { +static const char* GetVRString() { return "UT"; } +typedef VRToType::Type Type; +enum { VRType = VR::UT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x9001> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x9002> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x9003> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x9099> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x9108> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x9110> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x9132> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x9145> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x9235> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x9411> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x9415> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x9416> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x9422> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x9443> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x9444> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x9445> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x9446> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0028,0x9454> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x9474> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x9478> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x9501> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x9502> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x9503> { +static const char* GetVRString() { return "SS"; } +typedef VRToType::Type Type; +enum { VRType = VR::SS }; +enum { VMType = VM::VM2_2n }; +static const char* GetVMString() { return "2-2n"; } +}; +template <> struct TagToType<0x0028,0x9505> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0028,0x9506> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM2_2n }; +static const char* GetVMString() { return "2-2n"; } +}; +template <> struct TagToType<0x0028,0x9507> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM2_2n }; +static const char* GetVMString() { return "2-2n"; } +}; +template <> struct TagToType<0x0028,0x9520> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM16 }; +static const char* GetVMString() { return "16"; } +}; +template <> struct TagToType<0x0028,0x9537> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0032,0x000a> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0032,0x000c> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0032,0x0012> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0032,0x0032> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0032,0x0033> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0032,0x0034> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0032,0x0035> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0032,0x1000> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0032,0x1001> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0032,0x1010> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0032,0x1011> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0032,0x1020> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0032,0x1021> { +static const char* GetVRString() { return "AE"; } +typedef VRToType::Type Type; +enum { VRType = VR::AE }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0032,0x1030> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0032,0x1031> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0032,0x1032> { +static const char* GetVRString() { return "PN"; } +typedef VRToType::Type Type; +enum { VRType = VR::PN }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0032,0x1033> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0032,0x1034> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0032,0x1040> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0032,0x1041> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0032,0x1050> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0032,0x1051> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0032,0x1055> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0032,0x1060> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0032,0x1064> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0032,0x1070> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0032,0x4000> { +static const char* GetVRString() { return "LT"; } +typedef VRToType::Type Type; +enum { VRType = VR::LT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0038,0x0004> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0038,0x0008> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0038,0x0010> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0038,0x0011> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0038,0x0014> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0038,0x0016> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0038,0x001a> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0038,0x001b> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0038,0x001c> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0038,0x001d> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0038,0x001e> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0038,0x0020> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0038,0x0021> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0038,0x0030> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0038,0x0032> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0038,0x0040> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0038,0x0044> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0038,0x0050> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0038,0x0060> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0038,0x0061> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0038,0x0062> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0038,0x0064> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0038,0x0100> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0038,0x0300> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0038,0x0400> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0038,0x0500> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0038,0x0502> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0038,0x4000> { +static const char* GetVRString() { return "LT"; } +typedef VRToType::Type Type; +enum { VRType = VR::LT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x003a,0x0004> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x003a,0x0005> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x003a,0x0010> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x003a,0x001a> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x003a,0x0020> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x003a,0x0200> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x003a,0x0202> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x003a,0x0203> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x003a,0x0205> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x003a,0x0208> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x003a,0x0209> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x003a,0x020a> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x003a,0x020c> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x003a,0x0210> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x003a,0x0211> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x003a,0x0212> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x003a,0x0213> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x003a,0x0214> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x003a,0x0215> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x003a,0x0218> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x003a,0x021a> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x003a,0x0220> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x003a,0x0221> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x003a,0x0222> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x003a,0x0223> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x003a,0x0230> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x003a,0x0231> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x003a,0x0240> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x003a,0x0241> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x003a,0x0242> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x003a,0x0244> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x003a,0x0245> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x003a,0x0246> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x003a,0x0247> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x003a,0x0248> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x003a,0x0300> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x003a,0x0301> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x003a,0x0302> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0001> { +static const char* GetVRString() { return "AE"; } +typedef VRToType::Type Type; +enum { VRType = VR::AE }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0040,0x0002> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0003> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0004> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0005> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0006> { +static const char* GetVRString() { return "PN"; } +typedef VRToType::Type Type; +enum { VRType = VR::PN }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0007> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0008> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0009> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x000a> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x000b> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0010> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0040,0x0011> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0012> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0020> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0026> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0027> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0031> { +static const char* GetVRString() { return "UT"; } +typedef VRToType::Type Type; +enum { VRType = VR::UT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0032> { +static const char* GetVRString() { return "UT"; } +typedef VRToType::Type Type; +enum { VRType = VR::UT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0033> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0035> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0036> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0039> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x003a> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0100> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0220> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0241> { +static const char* GetVRString() { return "AE"; } +typedef VRToType::Type Type; +enum { VRType = VR::AE }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0242> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0243> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0244> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0245> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0250> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0251> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0252> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0253> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0254> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0255> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0260> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0261> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0270> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0275> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0280> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0281> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0293> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0294> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0295> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0296> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0300> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0301> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0302> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0303> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1_2 }; +static const char* GetVMString() { return "1-2"; } +}; +template <> struct TagToType<0x0040,0x0306> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0307> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x030e> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0310> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0312> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0314> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0316> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0318> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0320> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0321> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0324> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0330> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0340> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0400> { +static const char* GetVRString() { return "LT"; } +typedef VRToType::Type Type; +enum { VRType = VR::LT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0440> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0441> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0500> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x050a> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0512> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0513> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0515> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0518> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x051a> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0520> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0550> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0551> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0552> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0553> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0554> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0555> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0556> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0560> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0562> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x059a> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0600> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0602> { +static const char* GetVRString() { return "UT"; } +typedef VRToType::Type Type; +enum { VRType = VR::UT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0610> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0612> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x0620> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x06fa> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x071a> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x072a> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x073a> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x074a> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x08d8> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x08da> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x08ea> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x09f8> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x1001> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x1002> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x1003> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x1004> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x1005> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x1006> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x1007> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x1008> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x1009> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x100a> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x1010> { +static const char* GetVRString() { return "PN"; } +typedef VRToType::Type Type; +enum { VRType = VR::PN }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0040,0x1011> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x1012> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x1060> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x1101> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x1102> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x1103> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0040,0x1400> { +static const char* GetVRString() { return "LT"; } +typedef VRToType::Type Type; +enum { VRType = VR::LT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x2001> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x2004> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x2005> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x2006> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x2007> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x2008> { +static const char* GetVRString() { return "PN"; } +typedef VRToType::Type Type; +enum { VRType = VR::PN }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x2009> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x2010> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x2016> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x2017> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x2400> { +static const char* GetVRString() { return "LT"; } +typedef VRToType::Type Type; +enum { VRType = VR::LT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x3001> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x4001> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x4002> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x4003> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x4004> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x4005> { +static const char* GetVRString() { return "DT"; } +typedef VRToType::Type Type; +enum { VRType = VR::DT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x4006> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x4007> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x4009> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x4010> { +static const char* GetVRString() { return "DT"; } +typedef VRToType::Type Type; +enum { VRType = VR::DT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x4011> { +static const char* GetVRString() { return "DT"; } +typedef VRToType::Type Type; +enum { VRType = VR::DT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x4015> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x4016> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x4018> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x4019> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x4020> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x4021> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x4022> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x4023> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x4025> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x4026> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x4027> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x4028> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x4029> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x4030> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x4031> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x4032> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x4033> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x4034> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x4035> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x4036> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x4037> { +static const char* GetVRString() { return "PN"; } +typedef VRToType::Type Type; +enum { VRType = VR::PN }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x4040> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x4041> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x4050> { +static const char* GetVRString() { return "DT"; } +typedef VRToType::Type Type; +enum { VRType = VR::DT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x4051> { +static const char* GetVRString() { return "DT"; } +typedef VRToType::Type Type; +enum { VRType = VR::DT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x4052> { +static const char* GetVRString() { return "DT"; } +typedef VRToType::Type Type; +enum { VRType = VR::DT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x8302> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x9094> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x9096> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x9098> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x9210> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x9212> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0040,0x9224> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0x9225> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa007> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa010> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa020> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa021> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa022> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa023> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa024> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa026> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa027> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa028> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa030> { +static const char* GetVRString() { return "DT"; } +typedef VRToType::Type Type; +enum { VRType = VR::DT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa032> { +static const char* GetVRString() { return "DT"; } +typedef VRToType::Type Type; +enum { VRType = VR::DT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa040> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa043> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa047> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa050> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa057> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0040,0xa060> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa066> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa067> { +static const char* GetVRString() { return "PN"; } +typedef VRToType::Type Type; +enum { VRType = VR::PN }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa068> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa070> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa073> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa074> { +static const char* GetVRString() { return "OB"; } +typedef VRToType::Type Type; +enum { VRType = VR::OB }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa075> { +static const char* GetVRString() { return "PN"; } +typedef VRToType::Type Type; +enum { VRType = VR::PN }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa076> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa078> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa07a> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa07c> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa080> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa082> { +static const char* GetVRString() { return "DT"; } +typedef VRToType::Type Type; +enum { VRType = VR::DT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa084> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa085> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa088> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa089> { +static const char* GetVRString() { return "OB"; } +typedef VRToType::Type Type; +enum { VRType = VR::OB }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa090> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa0b0> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM2_2n }; +static const char* GetVMString() { return "2-2n"; } +}; +template <> struct TagToType<0x0040,0xa110> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa112> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa120> { +static const char* GetVRString() { return "DT"; } +typedef VRToType::Type Type; +enum { VRType = VR::DT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa121> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa122> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa123> { +static const char* GetVRString() { return "PN"; } +typedef VRToType::Type Type; +enum { VRType = VR::PN }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa124> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa125> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0040,0xa130> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa132> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0040,0xa136> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0040,0xa138> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0040,0xa13a> { +static const char* GetVRString() { return "DT"; } +typedef VRToType::Type Type; +enum { VRType = VR::DT }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0040,0xa160> { +static const char* GetVRString() { return "UT"; } +typedef VRToType::Type Type; +enum { VRType = VR::UT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa167> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa168> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa16a> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa170> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa171> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa172> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa173> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa174> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa180> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa192> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa193> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa194> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa195> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa224> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa290> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa296> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa297> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa29a> { +static const char* GetVRString() { return "SL"; } +typedef VRToType::Type Type; +enum { VRType = VR::SL }; +enum { VMType = VM::VM2_2n }; +static const char* GetVMString() { return "2-2n"; } +}; +template <> struct TagToType<0x0040,0xa300> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa301> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa307> { +static const char* GetVRString() { return "PN"; } +typedef VRToType::Type Type; +enum { VRType = VR::PN }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa30a> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0040,0xa313> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa33a> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa340> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa352> { +static const char* GetVRString() { return "PN"; } +typedef VRToType::Type Type; +enum { VRType = VR::PN }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa353> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa354> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa358> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa360> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa370> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa372> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa375> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa380> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa385> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa390> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa402> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa403> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa404> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa491> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa492> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa493> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa494> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa496> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa504> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa525> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa600> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa601> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa603> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa730> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa731> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa732> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa744> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xa992> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xb020> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xdb00> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xdb06> { +static const char* GetVRString() { return "DT"; } +typedef VRToType::Type Type; +enum { VRType = VR::DT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xdb07> { +static const char* GetVRString() { return "DT"; } +typedef VRToType::Type Type; +enum { VRType = VR::DT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xdb0b> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xdb0c> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xdb0d> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xdb73> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0040,0xe001> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xe004> { +static const char* GetVRString() { return "DT"; } +typedef VRToType::Type Type; +enum { VRType = VR::DT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xe006> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xe008> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xe010> { +static const char* GetVRString() { return "UT"; } +typedef VRToType::Type Type; +enum { VRType = VR::UT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xe011> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xe020> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xe021> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xe022> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xe023> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xe024> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xe030> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0040,0xe031> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0042,0x0010> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0042,0x0011> { +static const char* GetVRString() { return "OB"; } +typedef VRToType::Type Type; +enum { VRType = VR::OB }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0042,0x0012> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0042,0x0013> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0042,0x0014> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0044,0x0001> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0044,0x0002> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0044,0x0003> { +static const char* GetVRString() { return "LT"; } +typedef VRToType::Type Type; +enum { VRType = VR::LT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0044,0x0004> { +static const char* GetVRString() { return "DT"; } +typedef VRToType::Type Type; +enum { VRType = VR::DT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0044,0x0007> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0044,0x0008> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0044,0x0009> { +static const char* GetVRString() { return "LT"; } +typedef VRToType::Type Type; +enum { VRType = VR::LT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0044,0x000a> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0044,0x000b> { +static const char* GetVRString() { return "DT"; } +typedef VRToType::Type Type; +enum { VRType = VR::DT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0044,0x0010> { +static const char* GetVRString() { return "DT"; } +typedef VRToType::Type Type; +enum { VRType = VR::DT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0044,0x0011> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0044,0x0012> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0044,0x0013> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0044,0x0019> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0046,0x0012> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0046,0x0014> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0046,0x0015> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0046,0x0016> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0046,0x0018> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0046,0x0028> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0046,0x0030> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0046,0x0032> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0046,0x0034> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0046,0x0036> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0046,0x0038> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0046,0x0040> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0046,0x0042> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0046,0x0044> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0046,0x0046> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0046,0x0050> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0046,0x0052> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0046,0x0060> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0046,0x0062> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0046,0x0063> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0046,0x0064> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0046,0x0070> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0046,0x0071> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0046,0x0074> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0046,0x0075> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0046,0x0076> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0046,0x0077> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0046,0x0080> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0046,0x0092> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0046,0x0094> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0046,0x0095> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0046,0x0097> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0046,0x0098> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0046,0x0100> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0046,0x0101> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0046,0x0102> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0046,0x0104> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0046,0x0106> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0046,0x0121> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0046,0x0122> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0046,0x0123> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0046,0x0124> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0046,0x0125> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0046,0x0135> { +static const char* GetVRString() { return "SS"; } +typedef VRToType::Type Type; +enum { VRType = VR::SS }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0046,0x0137> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0046,0x0139> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0046,0x0145> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0046,0x0146> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0046,0x0147> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0048,0x0001> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0048,0x0002> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0048,0x0003> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0048,0x0006> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0048,0x0007> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0048,0x0008> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0048,0x0010> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0048,0x0011> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0048,0x0012> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0048,0x0013> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0048,0x0014> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0048,0x0015> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x0048,0x0100> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0048,0x0102> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM6 }; +static const char* GetVMString() { return "6"; } +}; +template <> struct TagToType<0x0048,0x0105> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0048,0x0106> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0048,0x0107> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0048,0x0108> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0048,0x0110> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0048,0x0111> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0048,0x0112> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0048,0x0113> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0048,0x0120> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0048,0x0200> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0048,0x0201> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0048,0x0202> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0048,0x0207> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0048,0x021a> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0048,0x021e> { +static const char* GetVRString() { return "SL"; } +typedef VRToType::Type Type; +enum { VRType = VR::SL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0048,0x021f> { +static const char* GetVRString() { return "SL"; } +typedef VRToType::Type Type; +enum { VRType = VR::SL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0048,0x0301> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0050,0x0004> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0050,0x0010> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0050,0x0012> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0050,0x0013> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0050,0x0014> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0050,0x0015> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0050,0x0016> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0050,0x0017> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0050,0x0018> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0050,0x0019> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0050,0x001a> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0050,0x001b> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0050,0x001c> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0050,0x001d> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0050,0x001e> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0050,0x0020> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0052,0x0001> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0052,0x0002> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0052,0x0003> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0052,0x0004> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0052,0x0006> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0052,0x0007> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0052,0x0008> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0052,0x0009> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0052,0x0011> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0052,0x0012> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0052,0x0013> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0052,0x0014> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0052,0x0016> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0052,0x0025> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0052,0x0026> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0052,0x0027> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0052,0x0028> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0052,0x0029> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0052,0x0030> { +static const char* GetVRString() { return "SS"; } +typedef VRToType::Type Type; +enum { VRType = VR::SS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0052,0x0031> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0052,0x0033> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0052,0x0034> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0052,0x0036> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0052,0x0038> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0052,0x0039> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0052,0x003a> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x0010> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0054,0x0011> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x0012> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x0013> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x0014> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x0015> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x0016> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x0017> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x0018> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x0020> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0054,0x0021> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x0022> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x0030> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0054,0x0031> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x0032> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x0033> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x0036> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x0038> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x0039> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x0050> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0054,0x0051> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x0052> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x0053> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x0060> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0054,0x0061> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x0062> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x0063> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x0070> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0054,0x0071> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x0072> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x0073> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x0080> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0054,0x0081> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x0090> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0054,0x0100> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0054,0x0101> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x0200> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x0202> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x0210> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0054,0x0211> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x0220> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x0222> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x0300> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x0302> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x0304> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x0306> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x0308> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x0400> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x0410> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x0412> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x0414> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x0500> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x1000> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0054,0x1001> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x1002> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x1004> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x1006> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x1100> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x1101> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x1102> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x1103> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x1104> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x1105> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x1200> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x1201> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0054,0x1202> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x1203> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0054,0x1210> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x1220> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0054,0x1300> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x1310> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x1311> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0054,0x1320> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x1321> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x1322> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x1323> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x1324> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x1330> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0054,0x1400> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0054,0x1401> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0060,0x3000> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0060,0x3002> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0060,0x3008> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0060,0x3010> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0060,0x3020> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0062,0x0001> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0062,0x0002> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0062,0x0003> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0062,0x0004> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0062,0x0005> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0062,0x0006> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0062,0x0008> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0062,0x0009> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0062,0x000a> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0062,0x000b> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0062,0x000c> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0062,0x000d> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x0062,0x000e> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0062,0x000f> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0062,0x0010> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0064,0x0002> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0064,0x0003> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0064,0x0005> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0064,0x0007> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x0064,0x0008> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x0064,0x0009> { +static const char* GetVRString() { return "OF"; } +typedef VRToType::Type Type; +enum { VRType = VR::OF }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0064,0x000f> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0064,0x0010> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0066,0x0001> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0066,0x0002> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0066,0x0003> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0066,0x0004> { +static const char* GetVRString() { return "LT"; } +typedef VRToType::Type Type; +enum { VRType = VR::LT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0066,0x0009> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0066,0x000a> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0066,0x000b> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0066,0x000c> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0066,0x000d> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0066,0x000e> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0066,0x0010> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0066,0x0011> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0066,0x0012> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0066,0x0013> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0066,0x0015> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0066,0x0016> { +static const char* GetVRString() { return "OF"; } +typedef VRToType::Type Type; +enum { VRType = VR::OF }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0066,0x0017> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x0066,0x0018> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0066,0x0019> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0066,0x001a> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM6 }; +static const char* GetVMString() { return "6"; } +}; +template <> struct TagToType<0x0066,0x001b> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x0066,0x001c> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x0066,0x001e> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0066,0x001f> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0066,0x0020> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0066,0x0021> { +static const char* GetVRString() { return "OF"; } +typedef VRToType::Type Type; +enum { VRType = VR::OF }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0066,0x0023> { +static const char* GetVRString() { return "OW"; } +typedef VRToType::Type Type; +enum { VRType = VR::OW }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0066,0x0024> { +static const char* GetVRString() { return "OW"; } +typedef VRToType::Type Type; +enum { VRType = VR::OW }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0066,0x0025> { +static const char* GetVRString() { return "OW"; } +typedef VRToType::Type Type; +enum { VRType = VR::OW }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0066,0x0026> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0066,0x0027> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0066,0x0028> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0066,0x0029> { +static const char* GetVRString() { return "OW"; } +typedef VRToType::Type Type; +enum { VRType = VR::OW }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0066,0x002a> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0066,0x002b> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0066,0x002c> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0066,0x002d> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0066,0x002e> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0066,0x002f> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0066,0x0030> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0066,0x0031> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0066,0x0032> { +static const char* GetVRString() { return "LT"; } +typedef VRToType::Type Type; +enum { VRType = VR::LT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0066,0x0034> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0066,0x0035> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0066,0x0036> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x6210> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x6221> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x6222> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x6223> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x6224> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x6225> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x6226> { +static const char* GetVRString() { return "DT"; } +typedef VRToType::Type Type; +enum { VRType = VR::DT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x6230> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x6260> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x6265> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x6270> { +static const char* GetVRString() { return "DT"; } +typedef VRToType::Type Type; +enum { VRType = VR::DT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x6280> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x62a0> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x62a5> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x62c0> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x62d0> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x62d5> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x62e0> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x62f0> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM9 }; +static const char* GetVMString() { return "9"; } +}; +template <> struct TagToType<0x0068,0x62f2> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x6300> { +static const char* GetVRString() { return "OB"; } +typedef VRToType::Type Type; +enum { VRType = VR::OB }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x6310> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x6320> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x6330> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x6340> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x6345> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x6346> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0068,0x6347> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM4 }; +static const char* GetVMString() { return "4"; } +}; +template <> struct TagToType<0x0068,0x6350> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0068,0x6360> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x6380> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x6390> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x63a0> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x63a4> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x63a8> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x63ac> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x63b0> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x63c0> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x63d0> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x63e0> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x63f0> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x6400> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x6410> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x6420> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x6430> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x6440> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x6450> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0068,0x6460> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM4 }; +static const char* GetVMString() { return "4"; } +}; +template <> struct TagToType<0x0068,0x6470> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x6490> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x0068,0x64a0> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0068,0x64c0> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x0068,0x64d0> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM9 }; +static const char* GetVMString() { return "9"; } +}; +template <> struct TagToType<0x0068,0x64f0> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x0068,0x6500> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x6510> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x6520> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x6530> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x6540> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x6545> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x6550> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x6560> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0068,0x6590> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x0068,0x65a0> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x65b0> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM4 }; +static const char* GetVMString() { return "4"; } +}; +template <> struct TagToType<0x0068,0x65d0> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM6 }; +static const char* GetVMString() { return "6"; } +}; +template <> struct TagToType<0x0068,0x65e0> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0068,0x65f0> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM4 }; +static const char* GetVMString() { return "4"; } +}; +template <> struct TagToType<0x0068,0x6610> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x0068,0x6620> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x0070,0x0001> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0002> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0003> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0004> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0005> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0006> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0008> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0009> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0010> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0070,0x0011> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0070,0x0012> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0014> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0070,0x0015> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0020> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0021> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0022> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM2_n }; +static const char* GetVMString() { return "2-n"; } +}; +template <> struct TagToType<0x0070,0x0023> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0024> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0040> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0041> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0042> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0050> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0070,0x0051> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0070,0x0052> { +static const char* GetVRString() { return "SL"; } +typedef VRToType::Type Type; +enum { VRType = VR::SL }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0070,0x0053> { +static const char* GetVRString() { return "SL"; } +typedef VRToType::Type Type; +enum { VRType = VR::SL }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0070,0x005a> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0060> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0062> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0066> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0067> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x0070,0x0068> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0080> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0081> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0082> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0083> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0084> { +static const char* GetVRString() { return "PN"; } +typedef VRToType::Type Type; +enum { VRType = VR::PN }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0086> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0087> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0100> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0101> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0070,0x0102> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0070,0x0103> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0207> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0208> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0209> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0226> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0227> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0228> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0229> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0230> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0231> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0232> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0233> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0234> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0241> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x0070,0x0242> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0243> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0244> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0245> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0246> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0247> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x0070,0x0248> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0249> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0250> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0251> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x0070,0x0252> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x0070,0x0253> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0254> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0255> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0256> { +static const char* GetVRString() { return "OB"; } +typedef VRToType::Type Type; +enum { VRType = VR::OB }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0257> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0258> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0261> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0262> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0273> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0070,0x0274> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0278> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0279> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0282> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0284> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0285> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0287> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0288> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0289> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0294> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0295> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0306> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0308> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0309> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x030a> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x030c> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x030d> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x030f> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0310> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0311> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0312> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0314> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0318> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x031a> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x031c> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x031e> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0401> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x0070,0x0402> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0403> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0404> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0070,0x0405> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0002> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0004> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0006> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0008> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x000a> { +static const char* GetVRString() { return "DT"; } +typedef VRToType::Type Type; +enum { VRType = VR::DT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x000c> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x000e> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0010> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0012> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0014> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0020> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0022> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0024> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0026> { +static const char* GetVRString() { return "AT"; } +typedef VRToType::Type Type; +enum { VRType = VR::AT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0028> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0030> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0032> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0034> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0038> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0072,0x003a> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x003c> { +static const char* GetVRString() { return "SS"; } +typedef VRToType::Type Type; +enum { VRType = VR::SS }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0072,0x003e> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0040> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0050> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0052> { +static const char* GetVRString() { return "AT"; } +typedef VRToType::Type Type; +enum { VRType = VR::AT }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0072,0x0054> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0072,0x0056> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0060> { +static const char* GetVRString() { return "AT"; } +typedef VRToType::Type Type; +enum { VRType = VR::AT }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0072,0x0062> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0072,0x0064> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0072,0x0066> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0072,0x0068> { +static const char* GetVRString() { return "LT"; } +typedef VRToType::Type Type; +enum { VRType = VR::LT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x006a> { +static const char* GetVRString() { return "PN"; } +typedef VRToType::Type Type; +enum { VRType = VR::PN }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0072,0x006c> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0072,0x006e> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0070> { +static const char* GetVRString() { return "UT"; } +typedef VRToType::Type Type; +enum { VRType = VR::UT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0072> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0072,0x0074> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0072,0x0076> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0072,0x0078> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0072,0x007a> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0072,0x007c> { +static const char* GetVRString() { return "SL"; } +typedef VRToType::Type Type; +enum { VRType = VR::SL }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0072,0x007e> { +static const char* GetVRString() { return "SS"; } +typedef VRToType::Type Type; +enum { VRType = VR::SS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0072,0x0080> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0100> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0102> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0104> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0106> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0108> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM4 }; +static const char* GetVMString() { return "4"; } +}; +template <> struct TagToType<0x0072,0x010a> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x010c> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x010e> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0200> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0202> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0203> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0204> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0206> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0208> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0210> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0212> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM2_n }; +static const char* GetVMString() { return "2-n"; } +}; +template <> struct TagToType<0x0072,0x0214> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0216> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0218> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0072,0x0300> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0302> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0304> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0306> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0308> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0310> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0312> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0314> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0316> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0318> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0320> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0330> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0400> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0402> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0404> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0406> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0420> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x0072,0x0421> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x0072,0x0422> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0424> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0427> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0430> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0432> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM2_n }; +static const char* GetVMString() { return "2-n"; } +}; +template <> struct TagToType<0x0072,0x0434> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0500> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0510> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0512> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0514> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0516> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0520> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0072,0x0600> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0602> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0604> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0700> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0072,0x0702> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0704> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0705> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0706> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0710> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0712> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0714> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0716> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0717> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0072,0x0718> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x0120> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x0121> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x1000> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x1002> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x1004> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x1006> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x1008> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x100a> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x100c> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x100e> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x1020> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x1022> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x1024> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x1026> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x1027> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x1028> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x102a> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x102b> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x102c> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x102d> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x1030> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x1032> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x1034> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x1036> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x1038> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x103a> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM4 }; +static const char* GetVMString() { return "4"; } +}; +template <> struct TagToType<0x0074,0x1040> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x1042> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x1044> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x1046> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x1048> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x104a> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x104c> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x104e> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x1050> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x1052> { +static const char* GetVRString() { return "AT"; } +typedef VRToType::Type Type; +enum { VRType = VR::AT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x1054> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x1056> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x1057> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0074,0x1200> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x1202> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x1204> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x1210> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x1212> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x1216> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x1220> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x1222> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x1224> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x1230> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x1234> { +static const char* GetVRString() { return "AE"; } +typedef VRToType::Type Type; +enum { VRType = VR::AE }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x1236> { +static const char* GetVRString() { return "AE"; } +typedef VRToType::Type Type; +enum { VRType = VR::AE }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x1238> { +static const char* GetVRString() { return "LT"; } +typedef VRToType::Type Type; +enum { VRType = VR::LT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x1242> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x1244> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x1246> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x1324> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x1338> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0074,0x133a> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM4 }; +static const char* GetVMString() { return "4"; } +}; +template <> struct TagToType<0x0076,0x0001> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0076,0x0003> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0076,0x0006> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0076,0x0008> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0076,0x000a> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0076,0x000c> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0076,0x000e> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0076,0x0010> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0076,0x0020> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0076,0x0030> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0076,0x0032> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0076,0x0034> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0076,0x0036> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0076,0x0038> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0076,0x0040> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0076,0x0055> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0076,0x0060> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0076,0x0070> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0076,0x0080> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0076,0x0090> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0076,0x00a0> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0076,0x00b0> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0076,0x00c0> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0078,0x0001> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0078,0x0010> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0078,0x0020> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0078,0x0024> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0078,0x0026> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0078,0x0028> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0078,0x002a> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0078,0x002e> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0078,0x0050> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x0078,0x0060> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM9 }; +static const char* GetVMString() { return "9"; } +}; +template <> struct TagToType<0x0078,0x0070> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0078,0x0090> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x0078,0x00a0> { +static const char* GetVRString() { return "FD"; } +typedef VRToType::Type Type; +enum { VRType = VR::FD }; +enum { VMType = VM::VM4 }; +static const char* GetVMString() { return "4"; } +}; +template <> struct TagToType<0x0078,0x00b0> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0078,0x00b2> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0078,0x00b4> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0078,0x00b6> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0078,0x00b8> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0088,0x0130> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0088,0x0140> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0088,0x0200> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0088,0x0904> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0088,0x0906> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0088,0x0910> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0088,0x0912> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1_32 }; +static const char* GetVMString() { return "1-32"; } +}; +template <> struct TagToType<0x0100,0x0410> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0100,0x0420> { +static const char* GetVRString() { return "DT"; } +typedef VRToType::Type Type; +enum { VRType = VR::DT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0100,0x0424> { +static const char* GetVRString() { return "LT"; } +typedef VRToType::Type Type; +enum { VRType = VR::LT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0100,0x0426> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0400,0x0005> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0400,0x0010> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0400,0x0015> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0400,0x0020> { +static const char* GetVRString() { return "AT"; } +typedef VRToType::Type Type; +enum { VRType = VR::AT }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x0400,0x0100> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0400,0x0105> { +static const char* GetVRString() { return "DT"; } +typedef VRToType::Type Type; +enum { VRType = VR::DT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0400,0x0110> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0400,0x0115> { +static const char* GetVRString() { return "OB"; } +typedef VRToType::Type Type; +enum { VRType = VR::OB }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0400,0x0120> { +static const char* GetVRString() { return "OB"; } +typedef VRToType::Type Type; +enum { VRType = VR::OB }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0400,0x0305> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0400,0x0310> { +static const char* GetVRString() { return "OB"; } +typedef VRToType::Type Type; +enum { VRType = VR::OB }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0400,0x0401> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0400,0x0402> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0400,0x0403> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0400,0x0404> { +static const char* GetVRString() { return "OB"; } +typedef VRToType::Type Type; +enum { VRType = VR::OB }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0400,0x0500> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0400,0x0510> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0400,0x0520> { +static const char* GetVRString() { return "OB"; } +typedef VRToType::Type Type; +enum { VRType = VR::OB }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0400,0x0550> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0400,0x0561> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0400,0x0562> { +static const char* GetVRString() { return "DT"; } +typedef VRToType::Type Type; +enum { VRType = VR::DT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0400,0x0563> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0400,0x0564> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x0400,0x0565> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2000,0x0010> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2000,0x001e> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2000,0x0020> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2000,0x0030> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2000,0x0040> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2000,0x0050> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2000,0x0060> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2000,0x0061> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2000,0x0062> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2000,0x0063> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2000,0x0065> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2000,0x0067> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2000,0x0069> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2000,0x006a> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2000,0x00a0> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2000,0x00a1> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2000,0x00a2> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2000,0x00a4> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2000,0x00a8> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2000,0x0500> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2000,0x0510> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2010,0x0010> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2010,0x0030> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2010,0x0040> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2010,0x0050> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2010,0x0052> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2010,0x0054> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2010,0x0060> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2010,0x0080> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2010,0x00a6> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2010,0x00a7> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x2010,0x00a8> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2010,0x00a9> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x2010,0x0100> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2010,0x0110> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2010,0x0120> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2010,0x0130> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2010,0x0140> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2010,0x0150> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2010,0x0152> { +static const char* GetVRString() { return "LT"; } +typedef VRToType::Type Type; +enum { VRType = VR::LT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2010,0x0154> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2010,0x015e> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2010,0x0160> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2010,0x0376> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x2010,0x0500> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2010,0x0510> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2010,0x0520> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2020,0x0010> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2020,0x0020> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2020,0x0030> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2020,0x0040> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2020,0x0050> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2020,0x00a0> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2020,0x00a2> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2020,0x0110> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2020,0x0111> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2020,0x0130> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2020,0x0140> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2030,0x0010> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2030,0x0020> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2040,0x0010> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2040,0x0011> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1_99 }; +static const char* GetVMString() { return "1-99"; } +}; +template <> struct TagToType<0x2040,0x0020> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2040,0x0060> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2040,0x0070> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2040,0x0072> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2040,0x0074> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2040,0x0080> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2040,0x0082> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2040,0x0090> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2040,0x0100> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2040,0x0500> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2050,0x0010> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2050,0x0020> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2050,0x0500> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2100,0x0010> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2100,0x0020> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2100,0x0030> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2100,0x0040> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2100,0x0050> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2100,0x0070> { +static const char* GetVRString() { return "AE"; } +typedef VRToType::Type Type; +enum { VRType = VR::AE }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2100,0x0140> { +static const char* GetVRString() { return "AE"; } +typedef VRToType::Type Type; +enum { VRType = VR::AE }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2100,0x0160> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2100,0x0170> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2100,0x0500> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2110,0x0010> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2110,0x0020> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2110,0x0030> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2110,0x0099> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2120,0x0010> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2120,0x0050> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2120,0x0070> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2130,0x0010> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2130,0x0015> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2130,0x0030> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2130,0x0040> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2130,0x0050> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2130,0x0060> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2130,0x0080> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2130,0x00a0> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2130,0x00c0> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2200,0x0001> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2200,0x0002> { +static const char* GetVRString() { return "UT"; } +typedef VRToType::Type Type; +enum { VRType = VR::UT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2200,0x0003> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2200,0x0004> { +static const char* GetVRString() { return "LT"; } +typedef VRToType::Type Type; +enum { VRType = VR::LT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2200,0x0005> { +static const char* GetVRString() { return "LT"; } +typedef VRToType::Type Type; +enum { VRType = VR::LT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2200,0x0006> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2200,0x0007> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2200,0x0008> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2200,0x0009> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2200,0x000a> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2200,0x000b> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2200,0x000c> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2200,0x000d> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2200,0x000e> { +static const char* GetVRString() { return "AT"; } +typedef VRToType::Type Type; +enum { VRType = VR::AT }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x2200,0x000f> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x2200,0x0020> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3002,0x0002> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3002,0x0003> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3002,0x0004> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3002,0x000a> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3002,0x000c> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3002,0x000d> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x3002,0x000e> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3002,0x0010> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM6 }; +static const char* GetVMString() { return "6"; } +}; +template <> struct TagToType<0x3002,0x0011> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x3002,0x0012> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x3002,0x0020> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3002,0x0022> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3002,0x0024> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3002,0x0026> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3002,0x0028> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3002,0x0029> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3002,0x0030> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3002,0x0032> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3002,0x0034> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM4 }; +static const char* GetVMString() { return "4"; } +}; +template <> struct TagToType<0x3002,0x0040> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3002,0x0041> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3002,0x0042> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3002,0x0050> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3002,0x0051> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3002,0x0052> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3004,0x0001> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3004,0x0002> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3004,0x0004> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3004,0x0006> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3004,0x0008> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x3004,0x000a> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3004,0x000c> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM2_n }; +static const char* GetVMString() { return "2-n"; } +}; +template <> struct TagToType<0x3004,0x000e> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3004,0x0010> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3004,0x0012> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3004,0x0014> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1_3 }; +static const char* GetVMString() { return "1-3"; } +}; +template <> struct TagToType<0x3004,0x0040> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x3004,0x0042> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3004,0x0050> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3004,0x0052> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3004,0x0054> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3004,0x0056> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3004,0x0058> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM2_2n }; +static const char* GetVMString() { return "2-2n"; } +}; +template <> struct TagToType<0x3004,0x0060> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3004,0x0062> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3004,0x0070> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3004,0x0072> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3004,0x0074> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3006,0x0002> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3006,0x0004> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3006,0x0006> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3006,0x0008> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3006,0x0009> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3006,0x0010> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3006,0x0012> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3006,0x0014> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3006,0x0016> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3006,0x0020> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3006,0x0022> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3006,0x0024> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3006,0x0026> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3006,0x0028> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3006,0x002a> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x3006,0x002c> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3006,0x0030> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3006,0x0033> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3006,0x0036> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3006,0x0038> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3006,0x0039> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3006,0x0040> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3006,0x0042> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3006,0x0044> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3006,0x0045> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x3006,0x0046> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3006,0x0048> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3006,0x0049> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x3006,0x0050> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM3_3n }; +static const char* GetVMString() { return "3-3n"; } +}; +template <> struct TagToType<0x3006,0x0080> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3006,0x0082> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3006,0x0084> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3006,0x0085> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3006,0x0086> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3006,0x0088> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3006,0x00a0> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3006,0x00a4> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3006,0x00a6> { +static const char* GetVRString() { return "PN"; } +typedef VRToType::Type Type; +enum { VRType = VR::PN }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3006,0x00b0> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3006,0x00b2> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3006,0x00b4> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3006,0x00b6> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3006,0x00b7> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3006,0x00b8> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3006,0x00c0> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3006,0x00c2> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3006,0x00c4> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3006,0x00c6> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM16 }; +static const char* GetVMString() { return "16"; } +}; +template <> struct TagToType<0x3006,0x00c8> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0010> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0012> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0014> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0016> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0020> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0021> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0022> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0024> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0025> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x002a> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x002b> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x002c> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0030> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0032> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0033> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0036> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0037> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x003a> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x003b> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0040> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0041> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0042> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0044> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0045> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0046> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0047> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x3008,0x0048> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0050> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0052> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0054> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0056> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x005a> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0060> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0061> { +static const char* GetVRString() { return "AT"; } +typedef VRToType::Type Type; +enum { VRType = VR::AT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0062> { +static const char* GetVRString() { return "AT"; } +typedef VRToType::Type Type; +enum { VRType = VR::AT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0063> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0064> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0065> { +static const char* GetVRString() { return "AT"; } +typedef VRToType::Type Type; +enum { VRType = VR::AT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0066> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0068> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x006a> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0070> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0072> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0074> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0076> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0078> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x007a> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0080> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0082> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0090> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0092> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x00a0> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x00b0> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x00c0> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x00d0> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x00e0> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x00f0> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x00f2> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x00f4> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x00f6> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0100> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0105> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0110> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0116> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0120> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0122> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0130> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0132> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0134> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0136> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0138> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x013a> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x013c> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0140> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0142> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0150> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0152> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0160> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0162> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0164> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0166> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0168> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0200> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0202> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0220> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0223> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0224> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0230> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0240> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0250> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x3008,0x0251> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0002> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0003> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0004> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0006> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0007> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0009> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x300a,0x000a> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x000b> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x300a,0x000c> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x000e> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0010> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0012> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0013> { +static const char* GetVRString() { return "UI"; } +typedef VRToType::Type Type; +enum { VRType = VR::UI }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0014> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0015> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0016> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0018> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x300a,0x001a> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0020> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0021> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0022> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0023> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0025> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0026> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0027> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0028> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x002a> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x002b> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x002c> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x002d> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0040> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0042> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0043> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0044> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0046> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0048> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x004a> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x004b> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x004c> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x004e> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x004f> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0050> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0051> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0052> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0053> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0055> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0070> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0071> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0072> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0078> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0079> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x007a> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x007b> { +static const char* GetVRString() { return "LT"; } +typedef VRToType::Type Type; +enum { VRType = VR::LT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0080> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0082> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x300a,0x0084> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0086> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0088> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0089> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x008a> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00a0> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00a2> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x300a,0x00a4> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00b0> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00b2> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00b3> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00b4> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00b6> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00b8> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00ba> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00bb> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00bc> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00be> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM3_n }; +static const char* GetVMString() { return "3-n"; } +}; +template <> struct TagToType<0x300a,0x00c0> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00c2> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00c3> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00c4> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00c6> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00c7> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00c8> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00ca> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00cc> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x300a,0x00ce> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00d0> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00d1> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00d2> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00d3> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00d4> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00d5> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00d6> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00d7> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00d8> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00d9> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00da> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00db> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00dc> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00dd> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00e0> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00e1> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00e2> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00e3> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00e4> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00e5> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00e6> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00e7> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00e8> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00e9> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x300a,0x00ea> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x300a,0x00eb> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x300a,0x00ec> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x300a,0x00ed> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00ee> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00f0> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00f2> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00f3> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00f4> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00f5> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00f6> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00f7> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00f8> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00f9> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00fa> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00fb> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00fc> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x00fe> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0100> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0102> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0104> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0106> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM2_2n }; +static const char* GetVMString() { return "2-2n"; } +}; +template <> struct TagToType<0x300a,0x0107> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0108> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0109> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x010a> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x010c> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x010e> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0110> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0111> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0112> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0114> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0115> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0116> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0118> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x011a> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x011c> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM2_2n }; +static const char* GetVMString() { return "2-2n"; } +}; +template <> struct TagToType<0x300a,0x011e> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x011f> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0120> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0121> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0122> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0123> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0124> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0125> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0126> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0128> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0129> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x012a> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x012c> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x300a,0x012e> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x300a,0x0130> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0134> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0140> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0142> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0144> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0146> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0148> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x014a> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x014c> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x014e> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0180> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0182> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0183> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0184> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0190> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0192> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0194> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0196> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0198> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0199> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x019a> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x01a0> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x01a2> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x01a4> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x01a6> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x01a8> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x01b0> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x01b2> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x01b4> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x01b6> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x01b8> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x01ba> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x01bc> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x01d0> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x01d2> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x01d4> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x01d6> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0200> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0202> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0206> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0210> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0212> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0214> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0216> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0218> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x021a> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0222> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0224> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0226> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0228> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0229> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x022a> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x022b> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x022c> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x022e> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0230> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0232> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0234> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0236> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0238> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0240> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0242> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0244> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0250> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0260> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0262> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0263> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0264> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0266> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x026a> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x026c> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0280> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0282> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0284> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0286> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0288> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x028a> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x028c> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0290> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0291> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0292> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0294> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0296> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0298> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x029c> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x029e> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x02a0> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x02a2> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x02a4> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x02b0> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x02b2> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x02b3> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x02b4> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x02b8> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x02ba> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x02c8> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x02d0> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x02d2> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x02d4> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x300a,0x02d6> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x02e0> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x02e1> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x02e2> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x300a,0x02e3> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x02e4> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x02e5> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x02e6> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x300a,0x02e7> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x02e8> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x02ea> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x02eb> { +static const char* GetVRString() { return "LT"; } +typedef VRToType::Type Type; +enum { VRType = VR::LT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0302> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0304> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0306> { +static const char* GetVRString() { return "SS"; } +typedef VRToType::Type Type; +enum { VRType = VR::SS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0308> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x030a> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x300a,0x030c> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x030d> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x030f> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0312> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0314> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0316> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0318> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0320> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0322> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0330> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0332> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0334> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0336> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0338> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x033a> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x033c> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0340> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0342> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0344> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0346> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0348> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x034a> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x034c> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0350> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0352> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0354> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0356> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0358> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x035a> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0360> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0362> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0364> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0366> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0370> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0372> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0374> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0380> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0382> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0384> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0386> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0388> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x038a> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0390> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0392> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0394> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x300a,0x0396> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x300a,0x0398> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x300a,0x039a> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x03a0> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x03a2> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x03a4> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x03a6> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x03a8> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x03aa> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x03ac> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0401> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0402> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0410> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0412> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x300a,0x0420> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0421> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0422> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0423> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0424> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0431> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0432> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0433> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0434> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0435> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300a,0x0436> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300c,0x0002> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300c,0x0004> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300c,0x0006> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300c,0x0007> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300c,0x0008> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300c,0x0009> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300c,0x000a> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300c,0x000c> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300c,0x000e> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300c,0x0020> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300c,0x0022> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300c,0x0040> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300c,0x0042> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300c,0x0050> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300c,0x0051> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300c,0x0055> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300c,0x0060> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300c,0x006a> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300c,0x0080> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300c,0x00a0> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300c,0x00b0> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300c,0x00c0> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300c,0x00d0> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300c,0x00e0> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300c,0x00f0> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300c,0x00f2> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300c,0x00f4> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300c,0x00f6> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300c,0x0100> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300c,0x0102> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300c,0x0104> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300e,0x0002> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300e,0x0004> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300e,0x0005> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x300e,0x0008> { +static const char* GetVRString() { return "PN"; } +typedef VRToType::Type Type; +enum { VRType = VR::PN }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4000,0x0010> { +static const char* GetVRString() { return "LT"; } +typedef VRToType::Type Type; +enum { VRType = VR::LT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4000,0x4000> { +static const char* GetVRString() { return "LT"; } +typedef VRToType::Type Type; +enum { VRType = VR::LT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4008,0x0040> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4008,0x0042> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4008,0x0050> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4008,0x00ff> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4008,0x0100> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4008,0x0101> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4008,0x0102> { +static const char* GetVRString() { return "PN"; } +typedef VRToType::Type Type; +enum { VRType = VR::PN }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4008,0x0103> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4008,0x0108> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4008,0x0109> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4008,0x010a> { +static const char* GetVRString() { return "PN"; } +typedef VRToType::Type Type; +enum { VRType = VR::PN }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4008,0x010b> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4008,0x010c> { +static const char* GetVRString() { return "PN"; } +typedef VRToType::Type Type; +enum { VRType = VR::PN }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4008,0x0111> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4008,0x0112> { +static const char* GetVRString() { return "DA"; } +typedef VRToType::Type Type; +enum { VRType = VR::DA }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4008,0x0113> { +static const char* GetVRString() { return "TM"; } +typedef VRToType::Type Type; +enum { VRType = VR::TM }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4008,0x0114> { +static const char* GetVRString() { return "PN"; } +typedef VRToType::Type Type; +enum { VRType = VR::PN }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4008,0x0115> { +static const char* GetVRString() { return "LT"; } +typedef VRToType::Type Type; +enum { VRType = VR::LT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4008,0x0117> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4008,0x0118> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4008,0x0119> { +static const char* GetVRString() { return "PN"; } +typedef VRToType::Type Type; +enum { VRType = VR::PN }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4008,0x011a> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4008,0x0200> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4008,0x0202> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4008,0x0210> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4008,0x0212> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4008,0x0300> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4008,0x4000> { +static const char* GetVRString() { return "ST"; } +typedef VRToType::Type Type; +enum { VRType = VR::ST }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x0001> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x0002> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x0004> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x1001> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x1004> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x4010,0x1005> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x4010,0x1006> { +static const char* GetVRString() { return "OB"; } +typedef VRToType::Type Type; +enum { VRType = VR::OB }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x1007> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x1008> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x1009> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x100a> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x1010> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x1011> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x1012> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x1013> { +static const char* GetVRString() { return "LT"; } +typedef VRToType::Type Type; +enum { VRType = VR::LT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x1014> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x1015> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x1016> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x1017> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x1018> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x1019> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x101a> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x101b> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x4010,0x101c> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x4010,0x101d> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM6_6n }; +static const char* GetVMString() { return "6-n"; } +}; +template <> struct TagToType<0x4010,0x101e> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x101f> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x1020> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x1021> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x4010,0x1023> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x1024> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x1025> { +static const char* GetVRString() { return "DT"; } +typedef VRToType::Type Type; +enum { VRType = VR::DT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x1026> { +static const char* GetVRString() { return "DT"; } +typedef VRToType::Type Type; +enum { VRType = VR::DT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x1027> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x1028> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x1029> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x4010,0x102a> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x102b> { +static const char* GetVRString() { return "DT"; } +typedef VRToType::Type Type; +enum { VRType = VR::DT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x1031> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x1033> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x1034> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x1037> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x1038> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x1039> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x103a> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x1041> { +static const char* GetVRString() { return "DT"; } +typedef VRToType::Type Type; +enum { VRType = VR::DT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x1042> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x1043> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x4010,0x1044> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x1045> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x1046> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x1047> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x1048> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x1051> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x1052> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x1053> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x1054> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x1055> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x1056> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x1058> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x1059> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x1060> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x4010,0x1061> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM3 }; +static const char* GetVMString() { return "3"; } +}; +template <> struct TagToType<0x4010,0x1062> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x1064> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x1067> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x1068> { +static const char* GetVRString() { return "LT"; } +typedef VRToType::Type Type; +enum { VRType = VR::LT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x1069> { +static const char* GetVRString() { return "FL"; } +typedef VRToType::Type Type; +enum { VRType = VR::FL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4010,0x106c> { +static const char* GetVRString() { return "OB"; } +typedef VRToType::Type Type; +enum { VRType = VR::OB }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x4ffe,0x0001> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x5000,0x0005> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x5000,0x0010> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x5000,0x0020> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x5000,0x0022> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x5000,0x0030> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x5000,0x0040> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x5000,0x0103> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x5000,0x0104> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x5000,0x0105> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x5000,0x0106> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x5000,0x0110> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x5000,0x0112> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x5000,0x0114> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x5000,0x1001> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x5000,0x2000> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x5000,0x2002> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x5000,0x2004> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x5000,0x2006> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x5000,0x2008> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x5000,0x200a> { +static const char* GetVRString() { return "UL"; } +typedef VRToType::Type Type; +enum { VRType = VR::UL }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x5000,0x200e> { +static const char* GetVRString() { return "LT"; } +typedef VRToType::Type Type; +enum { VRType = VR::LT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x5000,0x2500> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x5000,0x2600> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x5000,0x2610> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x5200,0x9229> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x5200,0x9230> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x5400,0x0100> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x5400,0x1004> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x5400,0x1006> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x5600,0x0010> { +static const char* GetVRString() { return "OF"; } +typedef VRToType::Type Type; +enum { VRType = VR::OF }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x5600,0x0020> { +static const char* GetVRString() { return "OF"; } +typedef VRToType::Type Type; +enum { VRType = VR::OF }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x6000,0x0010> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x6000,0x0011> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x6000,0x0012> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x6000,0x0015> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x6000,0x0022> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x6000,0x0040> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x6000,0x0045> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x6000,0x0050> { +static const char* GetVRString() { return "SS"; } +typedef VRToType::Type Type; +enum { VRType = VR::SS }; +enum { VMType = VM::VM2 }; +static const char* GetVMString() { return "2"; } +}; +template <> struct TagToType<0x6000,0x0051> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x6000,0x0052> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x6000,0x0060> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x6000,0x0061> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x6000,0x0062> { +static const char* GetVRString() { return "SH"; } +typedef VRToType::Type Type; +enum { VRType = VR::SH }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x6000,0x0063> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x6000,0x0066> { +static const char* GetVRString() { return "AT"; } +typedef VRToType::Type Type; +enum { VRType = VR::AT }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x6000,0x0068> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x6000,0x0069> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x6000,0x0100> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x6000,0x0102> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x6000,0x0110> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x6000,0x0200> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x6000,0x0800> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x6000,0x0802> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x6000,0x0803> { +static const char* GetVRString() { return "AT"; } +typedef VRToType::Type Type; +enum { VRType = VR::AT }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x6000,0x0804> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x6000,0x1001> { +static const char* GetVRString() { return "CS"; } +typedef VRToType::Type Type; +enum { VRType = VR::CS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x6000,0x1100> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x6000,0x1101> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x6000,0x1102> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x6000,0x1103> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x6000,0x1200> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x6000,0x1201> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x6000,0x1202> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x6000,0x1203> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1_n }; +static const char* GetVMString() { return "1-n"; } +}; +template <> struct TagToType<0x6000,0x1301> { +static const char* GetVRString() { return "IS"; } +typedef VRToType::Type Type; +enum { VRType = VR::IS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x6000,0x1302> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x6000,0x1303> { +static const char* GetVRString() { return "DS"; } +typedef VRToType::Type Type; +enum { VRType = VR::DS }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x6000,0x1500> { +static const char* GetVRString() { return "LO"; } +typedef VRToType::Type Type; +enum { VRType = VR::LO }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x6000,0x4000> { +static const char* GetVRString() { return "LT"; } +typedef VRToType::Type Type; +enum { VRType = VR::LT }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x7fe0,0x0020> { +static const char* GetVRString() { return "OW"; } +typedef VRToType::Type Type; +enum { VRType = VR::OW }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x7fe0,0x0030> { +static const char* GetVRString() { return "OW"; } +typedef VRToType::Type Type; +enum { VRType = VR::OW }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x7fe0,0x0040> { +static const char* GetVRString() { return "OW"; } +typedef VRToType::Type Type; +enum { VRType = VR::OW }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x7f00,0x0011> { +static const char* GetVRString() { return "US"; } +typedef VRToType::Type Type; +enum { VRType = VR::US }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x7f00,0x0020> { +static const char* GetVRString() { return "OW"; } +typedef VRToType::Type Type; +enum { VRType = VR::OW }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x7f00,0x0030> { +static const char* GetVRString() { return "OW"; } +typedef VRToType::Type Type; +enum { VRType = VR::OW }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0x7f00,0x0040> { +static const char* GetVRString() { return "OW"; } +typedef VRToType::Type Type; +enum { VRType = VR::OW }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0xfffa,0xfffa> { +static const char* GetVRString() { return "SQ"; } +typedef VRToType::Type Type; +enum { VRType = VR::SQ }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; +template <> struct TagToType<0xfffc,0xfffc> { +static const char* GetVRString() { return "OB"; } +typedef VRToType::Type Type; +enum { VRType = VR::OB }; +enum { VMType = VM::VM1 }; +static const char* GetVMString() { return "1"; } +}; + +} // end namespace gdcm +#endif // GDCMTAGTOTYPE_H diff --git a/gdcm/Source/DataDictionary/gdcmUIDs.cxx b/gdcm/Source/DataDictionary/gdcmUIDs.cxx new file mode 100644 index 0000000..6d76dff --- /dev/null +++ b/gdcm/Source/DataDictionary/gdcmUIDs.cxx @@ -0,0 +1,436 @@ + +// GENERATED FILE DO NOT EDIT +// $ xsltproc UIDToC++.xsl Part6.xml > gdcmUIDs.cxx + +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmUIDs.h" +#include // strcmp + +namespace gdcm +{ + static const char * const TransferSyntaxStrings[][2] = { +{NULL,NULL}, // Starts a 1, not 0 +{"1.2.840.10008.1.1","Verification SOP Class"}, +{"1.2.840.10008.1.2","Implicit VR Little Endian: Default Transfer Syntax for DICOM"}, +{"1.2.840.10008.1.2.1","Explicit VR Little Endian"}, +{"1.2.840.10008.1.2.1.99","Deflated Explicit VR Little Endian"}, +{"1.2.840.10008.1.2.2","Explicit VR Big Endian"}, +{"1.2.840.10008.1.2.4.50","JPEG Baseline (Process 1): Default Transfer Syntax for Lossy JPEG 8 Bit Image Compression"}, +{"1.2.840.10008.1.2.4.51","JPEG Extended (Process 2 & 4): Default Transfer Syntax for Lossy JPEG 12 Bit Image Compression (Process 4 only)"}, +{"1.2.840.10008.1.2.4.52","JPEG Extended (Process 3 & 5)"}, +{"1.2.840.10008.1.2.4.53","JPEG Spectral Selection, Non-Hierarchical (Process 6 & 8)"}, +{"1.2.840.10008.1.2.4.54","JPEG Spectral Selection, Non-Hierarchical (Process 7 & 9)"}, +{"1.2.840.10008.1.2.4.55","JPEG Full Progression, Non-Hierarchical (Process 10 & 12)"}, +{"1.2.840.10008.1.2.4.56","JPEG Full Progression, Non-Hierarchical (Process 11 & 13)"}, +{"1.2.840.10008.1.2.4.57","JPEG Lossless, Non-Hierarchical (Process 14)"}, +{"1.2.840.10008.1.2.4.58","JPEG Lossless, Non-Hierarchical (Process 15)"}, +{"1.2.840.10008.1.2.4.59","JPEG Extended, Hierarchical (Process 16 & 18)"}, +{"1.2.840.10008.1.2.4.60","JPEG Extended, Hierarchical (Process 17 & 19)"}, +{"1.2.840.10008.1.2.4.61","JPEG Spectral Selection, Hierarchical (Process 20 & 22)"}, +{"1.2.840.10008.1.2.4.62","JPEG Spectral Selection, Hierarchical (Process 21 & 23)"}, +{"1.2.840.10008.1.2.4.63","JPEG Full Progression, Hierarchical (Process 24 & 26)"}, +{"1.2.840.10008.1.2.4.64","JPEG Full Progression, Hierarchical (Process 25 & 27)"}, +{"1.2.840.10008.1.2.4.65","JPEG Lossless, Hierarchical (Process 28)"}, +{"1.2.840.10008.1.2.4.66","JPEG Lossless, Hierarchical (Process 29)"}, +{"1.2.840.10008.1.2.4.70","JPEG Lossless, Non-Hierarchical, First-Order Prediction (Process 14 [Selection Value 1]): Default Transfer Syntax for Lossless JPEG Image Compression"}, +{"1.2.840.10008.1.2.4.80","JPEG-LS Lossless Image Compression"}, +{"1.2.840.10008.1.2.4.81","JPEG-LS Lossy (Near-Lossless) Image Compression"}, +{"1.2.840.10008.1.2.4.90","JPEG 2000 Image Compression (Lossless Only)"}, +{"1.2.840.10008.1.2.4.91","JPEG 2000 Image Compression"}, +{"1.2.840.10008.1.2.4.92","JPEG 2000 Part 2 Multi-component Image Compression (Lossless Only)"}, +{"1.2.840.10008.1.2.4.93","JPEG 2000 Part 2 Multi-component Image Compression"}, +{"1.2.840.10008.1.2.4.94","JPIP Referenced"}, +{"1.2.840.10008.1.2.4.95","JPIP Referenced Deflate"}, +{"1.2.840.10008.1.2.4.100","MPEG2 Main Profile @ Main Level"}, +{"1.2.840.10008.1.2.5","RLE Lossless"}, +{"1.2.840.10008.1.2.6.1","RFC 2557 MIME encapsulation"}, +{"1.2.840.10008.1.2.6.2","XML Encoding"}, +{"1.2.840.10008.1.3.10","Media Storage Directory Storage"}, +{"1.2.840.10008.1.4.1.1","Talairach Brain Atlas Frame of Reference"}, +{"1.2.840.10008.1.4.1.2","SPM2 T1 Frame of Reference"}, +{"1.2.840.10008.1.4.1.3","SPM2 T2 Frame of Reference"}, +{"1.2.840.10008.1.4.1.4","SPM2 PD Frame of Reference"}, +{"1.2.840.10008.1.4.1.5","SPM2 EPI Frame of Reference"}, +{"1.2.840.10008.1.4.1.6","SPM2 FIL T1 Frame of Reference"}, +{"1.2.840.10008.1.4.1.7","SPM2 PET Frame of Reference"}, +{"1.2.840.10008.1.4.1.8","SPM2 TRANSM Frame of Reference"}, +{"1.2.840.10008.1.4.1.9","SPM2 SPECT Frame of Reference"}, +{"1.2.840.10008.1.4.1.10","SPM2 GRAY Frame of Reference"}, +{"1.2.840.10008.1.4.1.11","SPM2 WHITE Frame of Reference"}, +{"1.2.840.10008.1.4.1.12","SPM2 CSF Frame of Reference"}, +{"1.2.840.10008.1.4.1.13","SPM2 BRAINMASK Frame of Reference"}, +{"1.2.840.10008.1.4.1.14","SPM2 AVG305T1 Frame of Reference"}, +{"1.2.840.10008.1.4.1.15","SPM2 AVG152T1 Frame of Reference"}, +{"1.2.840.10008.1.4.1.16","SPM2 AVG152T2 Frame of Reference"}, +{"1.2.840.10008.1.4.1.17","SPM2 AVG152PD Frame of Reference"}, +{"1.2.840.10008.1.4.1.18","SPM2 SINGLESUBJT1 Frame of Reference"}, +{"1.2.840.10008.1.4.2.1","ICBM 452 T1 Frame of Reference"}, +{"1.2.840.10008.1.4.2.2","ICBM Single Subject MRI Frame of Reference"}, +{"1.2.840.10008.1.9","Basic Study Content Notification SOP Class"}, +{"1.2.840.10008.1.20.1","Storage Commitment Push Model SOP Class"}, +{"1.2.840.10008.1.20.1.1","Storage Commitment Push Model SOP Instance"}, +{"1.2.840.10008.1.20.2","Storage Commitment Pull Model SOP Class"}, +{"1.2.840.10008.1.20.2.1","Storage Commitment Pull Model SOP Instance"}, +{"1.2.840.10008.1.40","Procedural Event Logging SOP Class"}, +{"1.2.840.10008.1.40.1","Procedural Event Logging SOP Instance"}, +{"1.2.840.10008.1.42","Substance Administration Logging SOP Class"}, +{"1.2.840.10008.1.42.1","Substance Administration Logging SOP Instance"}, +{"1.2.840.10008.2.6.1","DICOM UID Registry"}, +{"1.2.840.10008.2.16.4","DICOM Controlled Terminology"}, +{"1.2.840.10008.3.1.1.1","DICOM Application Context Name"}, +{"1.2.840.10008.3.1.2.1.1","Detached Patient Management SOP Class"}, +{"1.2.840.10008.3.1.2.1.4","Detached Patient Management Meta SOP Class"}, +{"1.2.840.10008.3.1.2.2.1","Detached Visit Management SOP Class"}, +{"1.2.840.10008.3.1.2.3.1","Detached Study Management SOP Class"}, +{"1.2.840.10008.3.1.2.3.2","Study Component Management SOP Class"}, +{"1.2.840.10008.3.1.2.3.3","Modality Performed Procedure Step SOP Class"}, +{"1.2.840.10008.3.1.2.3.4","Modality Performed Procedure Step Retrieve SOP Class"}, +{"1.2.840.10008.3.1.2.3.5","Modality Performed Procedure Step Notification SOP Class"}, +{"1.2.840.10008.3.1.2.5.1","Detached Results Management SOP Class"}, +{"1.2.840.10008.3.1.2.5.4","Detached Results Management Meta SOP Class"}, +{"1.2.840.10008.3.1.2.5.5","Detached Study Management Meta SOP Class"}, +{"1.2.840.10008.3.1.2.6.1","Detached Interpretation Management SOP Class"}, +{"1.2.840.10008.4.2","Storage Service Class"}, +{"1.2.840.10008.5.1.1.1","Basic Film Session SOP Class"}, +{"1.2.840.10008.5.1.1.2","Basic Film Box SOP Class"}, +{"1.2.840.10008.5.1.1.4","Basic Grayscale Image Box SOP Class"}, +{"1.2.840.10008.5.1.1.4.1","Basic Color Image Box SOP Class"}, +{"1.2.840.10008.5.1.1.4.2","Referenced Image Box SOP Class"}, +{"1.2.840.10008.5.1.1.9","Basic Grayscale Print Management Meta SOP Class"}, +{"1.2.840.10008.5.1.1.9.1","Referenced Grayscale Print Management Meta SOP Class"}, +{"1.2.840.10008.5.1.1.14","Print Job SOP Class"}, +{"1.2.840.10008.5.1.1.15","Basic Annotation Box SOP Class"}, +{"1.2.840.10008.5.1.1.16","Printer SOP Class"}, +{"1.2.840.10008.5.1.1.16.376","Printer Configuration Retrieval SOP Class"}, +{"1.2.840.10008.5.1.1.17","Printer SOP Instance"}, +{"1.2.840.10008.5.1.1.17.376","Printer Configuration Retrieval SOP Instance"}, +{"1.2.840.10008.5.1.1.18","Basic Color Print Management Meta SOP Class"}, +{"1.2.840.10008.5.1.1.18.1","Referenced Color Print Management Meta SOP Class"}, +{"1.2.840.10008.5.1.1.22","VOI LUT Box SOP Class"}, +{"1.2.840.10008.5.1.1.23","Presentation LUT SOP Class"}, +{"1.2.840.10008.5.1.1.24","Image Overlay Box SOP Class"}, +{"1.2.840.10008.5.1.1.24.1","Basic Print Image Overlay Box SOP Class"}, +{"1.2.840.10008.5.1.1.25","Print Queue SOP Instance"}, +{"1.2.840.10008.5.1.1.26","Print Queue Management SOP Class"}, +{"1.2.840.10008.5.1.1.27","Stored Print Storage SOP Class"}, +{"1.2.840.10008.5.1.1.29","Hardcopy Grayscale Image Storage SOP Class"}, +{"1.2.840.10008.5.1.1.30","Hardcopy Color Image Storage SOP Class"}, +{"1.2.840.10008.5.1.1.31","Pull Print Request SOP Class"}, +{"1.2.840.10008.5.1.1.32","Pull Stored Print Management Meta SOP Class"}, +{"1.2.840.10008.5.1.1.33","Media Creation Management SOP Class UID"}, +{"1.2.840.10008.5.1.4.1.1.1","Computed Radiography Image Storage"}, +{"1.2.840.10008.5.1.4.1.1.1.1","Digital X-Ray Image Storage - For Presentation"}, +{"1.2.840.10008.5.1.4.1.1.1.1.1","Digital X-Ray Image Storage - For Processing"}, +{"1.2.840.10008.5.1.4.1.1.1.2","Digital Mammography X-Ray Image Storage - For Presentation"}, +{"1.2.840.10008.5.1.4.1.1.1.2.1","Digital Mammography X-Ray Image Storage - For Processing"}, +{"1.2.840.10008.5.1.4.1.1.1.3","Digital Intra-oral X-Ray Image Storage - For Presentation"}, +{"1.2.840.10008.5.1.4.1.1.1.3.1","Digital Intra-oral X-Ray Image Storage - For Processing"}, +{"1.2.840.10008.5.1.4.1.1.2","CT Image Storage"}, +{"1.2.840.10008.5.1.4.1.1.2.1","Enhanced CT Image Storage"}, +{"1.2.840.10008.5.1.4.1.1.3","Ultrasound Multi-frame Image Storage"}, +{"1.2.840.10008.5.1.4.1.1.3.1","Ultrasound Multi-frame Image Storage"}, +{"1.2.840.10008.5.1.4.1.1.4","MR Image Storage"}, +{"1.2.840.10008.5.1.4.1.1.4.1","Enhanced MR Image Storage"}, +{"1.2.840.10008.5.1.4.1.1.4.2","MR Spectroscopy Storage"}, +{"1.2.840.10008.5.1.4.1.1.5","Nuclear Medicine Image Storage"}, +{"1.2.840.10008.5.1.4.1.1.6","Ultrasound Image Storage"}, +{"1.2.840.10008.5.1.4.1.1.6.1","Ultrasound Image Storage"}, +{"1.2.840.10008.5.1.4.1.1.7","Secondary Capture Image Storage"}, +{"1.2.840.10008.5.1.4.1.1.7.1","Multi-frame Single Bit Secondary Capture Image Storage"}, +{"1.2.840.10008.5.1.4.1.1.7.2","Multi-frame Grayscale Byte Secondary Capture Image Storage"}, +{"1.2.840.10008.5.1.4.1.1.7.3","Multi-frame Grayscale Word Secondary Capture Image Storage"}, +{"1.2.840.10008.5.1.4.1.1.7.4","Multi-frame True Color Secondary Capture Image Storage"}, +{"1.2.840.10008.5.1.4.1.1.8","Standalone Overlay Storage"}, +{"1.2.840.10008.5.1.4.1.1.9","Standalone Curve Storage"}, +{"1.2.840.10008.5.1.4.1.1.9.1","Waveform Storage - Trial"}, +{"1.2.840.10008.5.1.4.1.1.9.1.1","12-lead ECG Waveform Storage"}, +{"1.2.840.10008.5.1.4.1.1.9.1.2","General ECG Waveform Storage"}, +{"1.2.840.10008.5.1.4.1.1.9.1.3","Ambulatory ECG Waveform Storage"}, +{"1.2.840.10008.5.1.4.1.1.9.2.1","Hemodynamic Waveform Storage"}, +{"1.2.840.10008.5.1.4.1.1.9.3.1","Cardiac Electrophysiology Waveform Storage"}, +{"1.2.840.10008.5.1.4.1.1.9.4.1","Basic Voice Audio Waveform Storage"}, +{"1.2.840.10008.5.1.4.1.1.10","Standalone Modality LUT Storage"}, +{"1.2.840.10008.5.1.4.1.1.11","Standalone VOI LUT Storage"}, +{"1.2.840.10008.5.1.4.1.1.11.1","Grayscale Softcopy Presentation State Storage SOP Class"}, +{"1.2.840.10008.5.1.4.1.1.11.2","Color Softcopy Presentation State Storage SOP Class"}, +{"1.2.840.10008.5.1.4.1.1.11.3","Pseudo-Color Softcopy Presentation State Storage SOP Class"}, +{"1.2.840.10008.5.1.4.1.1.11.4","Blending Softcopy Presentation State Storage SOP Class"}, +{"1.2.840.10008.5.1.4.1.1.12.1","X-Ray Angiographic Image Storage"}, +{"1.2.840.10008.5.1.4.1.1.12.1.1","Enhanced XA Image Storage"}, +{"1.2.840.10008.5.1.4.1.1.12.2","X-Ray Radiofluoroscopic Image Storage"}, +{"1.2.840.10008.5.1.4.1.1.12.2.1","Enhanced XRF Image Storage"}, +{"1.2.840.10008.5.1.4.1.1.13.1.1","X-Ray 3D Angiographic Image Storage"}, +{"1.2.840.10008.5.1.4.1.1.13.1.2","X-Ray 3D Craniofacial Image Storage"}, +{"1.2.840.10008.5.1.4.1.1.12.3","X-Ray Angiographic Bi-Plane Image Storage"}, +{"1.2.840.10008.5.1.4.1.1.20","Nuclear Medicine Image Storage"}, +{"1.2.840.10008.5.1.4.1.1.66","Raw Data Storage"}, +{"1.2.840.10008.5.1.4.1.1.66.1","Spatial Registration Storage"}, +{"1.2.840.10008.5.1.4.1.1.66.2","Spatial Fiducials Storage"}, +{"1.2.840.10008.5.1.4.1.1.66.3","Deformable Spatial Registration Storage"}, +{"1.2.840.10008.5.1.4.1.1.66.4","Segmentation Storage"}, +{"1.2.840.10008.5.1.4.1.1.67","Real World Value Mapping Storage"}, +{"1.2.840.10008.5.1.4.1.1.77.1","VL Image Storage - Trial"}, +{"1.2.840.10008.5.1.4.1.1.77.2","VL Multi-frame Image Storage - Trial"}, +{"1.2.840.10008.5.1.4.1.1.77.1.1","VL Endoscopic Image Storage"}, +{"1.2.840.10008.5.1.4.1.1.77.1.1.1","Video Endoscopic Image Storage"}, +{"1.2.840.10008.5.1.4.1.1.77.1.2","VL Microscopic Image Storage"}, +{"1.2.840.10008.5.1.4.1.1.77.1.2.1","Video Microscopic Image Storage"}, +{"1.2.840.10008.5.1.4.1.1.77.1.3","VL Slide-Coordinates Microscopic Image Storage"}, +{"1.2.840.10008.5.1.4.1.1.77.1.4","VL Photographic Image Storage"}, +{"1.2.840.10008.5.1.4.1.1.77.1.4.1","Video Photographic Image Storage"}, +{"1.2.840.10008.5.1.4.1.1.77.1.5.1","Ophthalmic Photography 8 Bit Image Storage"}, +{"1.2.840.10008.5.1.4.1.1.77.1.5.2","Ophthalmic Photography 16 Bit Image Storage"}, +{"1.2.840.10008.5.1.4.1.1.77.1.5.3","Stereometric Relationship Storage"}, +{"1.2.840.10008.5.1.4.1.1.77.1.5.4","Ophthalmic Tomography Image Storage"}, +{"1.2.840.10008.5.1.4.1.1.88.1","Text SR Storage - Trial"}, +{"1.2.840.10008.5.1.4.1.1.88.2","Audio SR Storage - Trial"}, +{"1.2.840.10008.5.1.4.1.1.88.3","Detail SR Storage - Trial"}, +{"1.2.840.10008.5.1.4.1.1.88.4","Comprehensive SR Storage - Trial"}, +{"1.2.840.10008.5.1.4.1.1.88.11","Basic Text SR Storage"}, +{"1.2.840.10008.5.1.4.1.1.88.22","Enhanced SR Storage"}, +{"1.2.840.10008.5.1.4.1.1.88.33","Comprehensive SR Storage"}, +{"1.2.840.10008.5.1.4.1.1.88.40","Procedure Log Storage"}, +{"1.2.840.10008.5.1.4.1.1.88.50","Mammography CAD SR Storage"}, +{"1.2.840.10008.5.1.4.1.1.88.59","Key Object Selection Document Storage"}, +{"1.2.840.10008.5.1.4.1.1.88.65","Chest CAD SR Storage"}, +{"1.2.840.10008.5.1.4.1.1.88.67","X-Ray Radiation Dose SR Storage"}, +{"1.2.840.10008.5.1.4.1.1.104.1","Encapsulated PDF Storage"}, +{"1.2.840.10008.5.1.4.1.1.104.2","Encapsulated CDA Storage"}, +{"1.2.840.10008.5.1.4.1.1.128","Positron Emission Tomography Image Storage"}, +{"1.2.840.10008.5.1.4.1.1.129","Standalone PET Curve Storage"}, +{"1.2.840.10008.5.1.4.1.1.481.1","RT Image Storage"}, +{"1.2.840.10008.5.1.4.1.1.481.2","RT Dose Storage"}, +{"1.2.840.10008.5.1.4.1.1.481.3","RT Structure Set Storage"}, +{"1.2.840.10008.5.1.4.1.1.481.4","RT Beams Treatment Record Storage"}, +{"1.2.840.10008.5.1.4.1.1.481.5","RT Plan Storage"}, +{"1.2.840.10008.5.1.4.1.1.481.6","RT Brachy Treatment Record Storage"}, +{"1.2.840.10008.5.1.4.1.1.481.7","RT Treatment Summary Record Storage"}, +{"1.2.840.10008.5.1.4.1.1.481.8","RT Ion Plan Storage"}, +{"1.2.840.10008.5.1.4.1.1.481.9","RT Ion Beams Treatment Record Storage"}, +{"1.2.840.10008.5.1.4.1.2.1.1","Patient Root Query/Retrieve Information Model - FIND"}, +{"1.2.840.10008.5.1.4.1.2.1.2","Patient Root Query/Retrieve Information Model - MOVE"}, +{"1.2.840.10008.5.1.4.1.2.1.3","Patient Root Query/Retrieve Information Model - GET"}, +{"1.2.840.10008.5.1.4.1.2.2.1","Study Root Query/Retrieve Information Model - FIND"}, +{"1.2.840.10008.5.1.4.1.2.2.2","Study Root Query/Retrieve Information Model - MOVE"}, +{"1.2.840.10008.5.1.4.1.2.2.3","Study Root Query/Retrieve Information Model - GET"}, +{"1.2.840.10008.5.1.4.1.2.3.1","Patient/Study Only Query/Retrieve Information Model - FIND"}, +{"1.2.840.10008.5.1.4.1.2.3.2","Patient/Study Only Query/Retrieve Information Model - MOVE"}, +{"1.2.840.10008.5.1.4.1.2.3.3","Patient/Study Only Query/Retrieve Information Model - GET"}, +{"1.2.840.10008.5.1.4.31","Modality Worklist Information Model - FIND"}, +{"1.2.840.10008.5.1.4.32.1","General Purpose Worklist Information Model - FIND"}, +{"1.2.840.10008.5.1.4.32.2","General Purpose Scheduled Procedure Step SOP Class"}, +{"1.2.840.10008.5.1.4.32.3","General Purpose Performed Procedure Step SOP Class"}, +{"1.2.840.10008.5.1.4.32","General Purpose Worklist Management Meta SOP Class"}, +{"1.2.840.10008.5.1.4.33","Instance Availability Notification SOP Class"}, +{"1.2.840.10008.5.1.4.34.1","RT Beams Delivery Instruction Storage (Supplement 74 Frozen Draft)"}, +{"1.2.840.10008.5.1.4.34.2","RT Conventional Machine Verification (Supplement 74 Frozen Draft)"}, +{"1.2.840.10008.5.1.4.34.3","RT Ion Machine Verification (Supplement 74 Frozen Draft)"}, +{"1.2.840.10008.5.1.4.34.4","Unified Worklist and Procedure Step Service Class"}, +{"1.2.840.10008.5.1.4.34.4.1","Unified Procedure Step - Push SOP Class"}, +{"1.2.840.10008.5.1.4.34.4.2","Unified Procedure Step - Watch SOP Class"}, +{"1.2.840.10008.5.1.4.34.4.3","Unified Procedure Step - Pull SOP Class"}, +{"1.2.840.10008.5.1.4.34.4.4","Unified Procedure Step - Event SOP Class"}, +{"1.2.840.10008.5.1.4.34.5","Unified Worklist and Procedure Step SOP Instance"}, +{"1.2.840.10008.5.1.4.37.1","General Relevant Patient Information Query"}, +{"1.2.840.10008.5.1.4.37.2","Breast Imaging Relevant Patient Information Query"}, +{"1.2.840.10008.5.1.4.37.3","Cardiac Relevant Patient Information Query"}, +{"1.2.840.10008.5.1.4.38.1","Hanging Protocol Storage"}, +{"1.2.840.10008.5.1.4.38.2","Hanging Protocol Information Model - FIND"}, +{"1.2.840.10008.5.1.4.38.3","Hanging Protocol Information Model - MOVE"}, +{"1.2.840.10008.5.1.4.41","Product Characteristics Query SOP Class"}, +{"1.2.840.10008.5.1.4.42","Substance Approval Query SOP Class"}, +{"1.2.840.10008.15.0.3.1","dicomDeviceName"}, +{"1.2.840.10008.15.0.3.2","dicomDescription"}, +{"1.2.840.10008.15.0.3.3","dicomManufacturer"}, +{"1.2.840.10008.15.0.3.4","dicomManufacturerModelName"}, +{"1.2.840.10008.15.0.3.5","dicomSoftwareVersion"}, +{"1.2.840.10008.15.0.3.6","dicomVendorData"}, +{"1.2.840.10008.15.0.3.7","dicomAETitle"}, +{"1.2.840.10008.15.0.3.8","dicomNetworkConnectionReference"}, +{"1.2.840.10008.15.0.3.9","dicomApplicationCluster"}, +{"1.2.840.10008.15.0.3.10","dicomAssociationInitiator"}, +{"1.2.840.10008.15.0.3.11","dicomAssociationAcceptor"}, +{"1.2.840.10008.15.0.3.12","dicomHostname"}, +{"1.2.840.10008.15.0.3.13","dicomPort"}, +{"1.2.840.10008.15.0.3.14","dicomSOPClass"}, +{"1.2.840.10008.15.0.3.15","dicomTransferRole"}, +{"1.2.840.10008.15.0.3.16","dicomTransferSyntax"}, +{"1.2.840.10008.15.0.3.17","dicomPrimaryDeviceType"}, +{"1.2.840.10008.15.0.3.18","dicomRelatedDeviceReference"}, +{"1.2.840.10008.15.0.3.19","dicomPreferredCalledAETitle"}, +{"1.2.840.10008.15.0.3.20","dicomTLSCyphersuite"}, +{"1.2.840.10008.15.0.3.21","dicomAuthorizedNodeCertificateReference"}, +{"1.2.840.10008.15.0.3.22","dicomThisNodeCertificateReference"}, +{"1.2.840.10008.15.0.3.23","dicomInstalled"}, +{"1.2.840.10008.15.0.3.24","dicomStationName"}, +{"1.2.840.10008.15.0.3.25","dicomDeviceSerialNumber"}, +{"1.2.840.10008.15.0.3.26","dicomInstitutionName"}, +{"1.2.840.10008.15.0.3.27","dicomInstitutionAddress"}, +{"1.2.840.10008.15.0.3.28","dicomInstitutionDepartmentName"}, +{"1.2.840.10008.15.0.3.29","dicomIssuerOfPatientID"}, +{"1.2.840.10008.15.0.3.30","dicomPreferredCallingAETitle"}, +{"1.2.840.10008.15.0.3.31","dicomSupportedCharacterSet"}, +{"1.2.840.10008.15.0.4.1","dicomConfigurationRoot"}, +{"1.2.840.10008.15.0.4.2","dicomDevicesRoot"}, +{"1.2.840.10008.15.0.4.3","dicomUniqueAETitlesRegistryRoot"}, +{"1.2.840.10008.15.0.4.4","dicomDevice"}, +{"1.2.840.10008.15.0.4.5","dicomNetworkAE"}, +{"1.2.840.10008.15.0.4.6","dicomNetworkConnection"}, +{"1.2.840.10008.15.0.4.7","dicomUniqueAETitle"}, +{"1.2.840.10008.15.0.4.8","dicomTransferCapability"}, +{"1.2.840.10008.5.1.4.1.1.77.1.6","VL Whole Slide Microscopy Image Storage"}, +{"1.2.840.10008.5.1.4.1.1.6.2", "Enhanced US Volume Storage" }, +{"1.2.840.10008.5.1.4.1.1.66.5","Surface Segmentation Storage"}, // Sup 132 +{"1.2.840.10008.5.1.4.1.1.13.1.3","Breast Tomosynthesis Image Storage"}, +//{"1.2.840.10008.1.4.1.1","Talairach Brain Atlas Frame of Reference"}, +//{"1.2.840.10008.1.4.1.2","SPM2 T1 Frame of Reference"}, +//{"1.2.840.10008.1.4.1.3","SPM2 T2 Frame of Reference"}, +//{"1.2.840.10008.1.4.1.4","SPM2 PD Frame of Reference"}, +//{"1.2.840.10008.1.4.1.5","SPM2 EPI Frame of Reference"}, +//{"1.2.840.10008.1.4.1.6","SPM2 FIL T1 Frame of Reference"}, +//{"1.2.840.10008.1.4.1.7","SPM2 PET Frame of Reference"}, +//{"1.2.840.10008.1.4.1.8","SPM2 TRANSM Frame of Reference"}, +//{"1.2.840.10008.1.4.1.9","SPM2 SPECT Frame of Reference"}, +//{"1.2.840.10008.1.4.1.10","SPM2 GRAY Frame of Reference"}, +//{"1.2.840.10008.1.4.1.11","SPM2 WHITE Frame of Reference"}, +//{"1.2.840.10008.1.4.1.12","SPM2 CSF Frame of Reference"}, +//{"1.2.840.10008.1.4.1.13","SPM2 BRAINMASK Frame of Reference"}, +//{"1.2.840.10008.1.4.1.14","SPM2 AVG305T1 Frame of Reference"}, +//{"1.2.840.10008.1.4.1.15","SPM2 AVG152T1 Frame of Reference"}, +//{"1.2.840.10008.1.4.1.16","SPM2 AVG152T2 Frame of Reference"}, +//{"1.2.840.10008.1.4.1.17","SPM2 AVG152PD Frame of Reference"}, +//{"1.2.840.10008.1.4.1.18","SPM2 SINGLESUBJT1 Frame of Reference"}, +//{"1.2.840.10008.1.4.2.1","ICBM 452 T1 Frame of Reference"}, +//{"1.2.840.10008.1.4.2.2","ICBM Single Subject MRI Frame of Reference"}, +{"1.2.840.113619.4.2","General Electric Magnetic Resonance Image Storage"}, +{"1.2.840.113619.4.3","General Electric Computed Tomography Image Storage"}, +{"1.3.12.2.1107.5.9.1","CSA Non-Image Storage"}, +// iis_fp_10282r2.pdf +{"1.2.840.113619.4.26" , "GE Private 3D Model Storage" }, +{"1.2.840.113619.4.30" , "GE Advance (PET) Raw Data Storage" }, +{"2.16.840.1.113709.1.5.1" , "GEPACS_PRIVATE_IMS_INFO Storage" }, +{"2.16.840.1.113709.1.2.2" , "COMPRESS_EXPRESS TRANSFER SYNTAX" }, +{"1.2.840.113543.6.6.1.3.10002", "Unregistred (?) Philips3D" }, +{"1.2.392.200036.9116.7.8.1.1.1", "Toshiba Private Data Storage" }, +// business.fujifilm.co.uk/medical/downloads/DICOM_xg1.pdf +{"1.2.392.200036.9125.1.1.2" , "Fuji Private CR Image Storage"}, +/* CREF4.09-80_iSite4.1DICOMConformance.pdf +Correction: 1.2.840113619.4.27 -> 1.2.840.113619.4.27 ... sigh +DICOM_Conformance_Statement_MR_R2.6.pdf +*/ +{"1.2.840.113619.4.27" ,"GE Nuclear Medicine private SOP Class"}, +{"1.3.46.670589.11.0.0.12.1" ,"Philips Private MR Spectrum Storage"}, +{"1.3.46.670589.11.0.0.12.2" ,"Philips Private MR Series Data Storage"}, +{"1.3.46.670589.11.0.0.12.4" ,"Philips Private MR Examcard Storage"}, +{"1.3.46.670589.2.3.1.1" ,"Philips Private Specialized XA Image"}, +{"1.3.46.670589.2.4.1.1" ,"Philips Private CX Image Storage"}, +{"1.3.46.670589.2.5.1.1" ,"Philips iE33 private 3D Object Storage"}, +{"1.3.46.670589.5.0.1" ,"Philips Private Volume Storage"}, +{"1.3.46.670589.5.0.1.1" ,"Philips Private Volume Image Reference"}, +{"1.3.46.670589.5.0.10" ,"Philips Private MR Synthetic Image Storage"}, +{"1.3.46.670589.5.0.11" ,"Philips Private MR Cardio Analysis Storage"}, +{"1.3.46.670589.5.0.11.1" ,"Philips Private MR Cardio Analysis Data"}, +{"1.3.46.670589.5.0.12" ,"Philips Private CX Synthetic Image Storage"}, +{"1.3.46.670589.5.0.13" ,"Philips Private Perfusion Image Reference"}, +{"1.3.46.670589.5.0.14" ,"Philips Private Perfusion Analysis Data"}, +{"1.3.46.670589.5.0.2" ,"Philips Private 3D Object Storage"}, +{"1.3.46.670589.5.0.2.1" ,"Philips Private 3D Object 2 Storage"}, +{"1.3.46.670589.5.0.3" ,"Philips Private Surface Storage"}, +{"1.3.46.670589.5.0.3.1" ,"Philips Private Surface 2 Storage"}, +{"1.3.46.670589.5.0.4" ,"Philips Private Composite Object Storage"}, +{"1.3.46.670589.5.0.7" ,"Philips Private MR Cardio Profile"}, +{"1.3.46.670589.5.0.8" ,"Philips Private MR Cardio"}, +{"1.3.46.670589.5.0.9" ,"Philips Private CT Synthetic Image Storage"}, +/* PACS_conformance_statement_10.2P2.pdf */ +{"1.2.752.24.3.7.6","Sectra Compression (Private Syntax)"}, +{"1.2.752.24.3.7.7","Sectra Compression LS (Private Syntax)"}, +{"1.2.840.113619.5.2", "Implicit VR Big Endian DLX (G.E Private)"}, +/*DICOM_Conformance_Statement_GEMINI_R3.5_R3.6.pdf */ +{"1.3.46.670589.33.1.4.1","CT-private-ELE"}, +{ 0, 0 } +}; + + +unsigned int UIDs::GetNumberOfTransferSyntaxStrings() +{ + // Do not count NULL sentinels at end + static const unsigned int size = sizeof(TransferSyntaxStrings)/sizeof(*TransferSyntaxStrings) - 2; + return size; +} + +const char * const * UIDs::GetTransferSyntaxString(unsigned int ts) +{ + if( ts > 0 && ts <= UIDs::GetNumberOfTransferSyntaxStrings() ) return TransferSyntaxStrings[ts]; + // else return the {0x0, 0x0} sentinel (begin or end) + assert( *TransferSyntaxStrings[ UIDs::GetNumberOfTransferSyntaxStrings() + 1 ] == 0 ); + assert( *TransferSyntaxStrings[ 0 ] == 0 ); + return TransferSyntaxStrings[ UIDs::GetNumberOfTransferSyntaxStrings() + 1 ]; +} + +const char* UIDs::GetUIDString(/*TSType*/ unsigned int ts) +{ + return UIDs::GetTransferSyntaxString(ts)[0]; +} + +const char* UIDs::GetUIDName(/*TSType*/ unsigned int ts) +{ + return UIDs::GetTransferSyntaxString(ts)[1]; +} + +UIDs::TransferSyntaxStringsType UIDs::GetTransferSyntaxStrings() +{ + return TransferSyntaxStrings; +} + +bool UIDs::SetFromUID(const char *str) +{ + TSField = (TSType)0; + if(!str) return false; + //static const unsigned int size = sizeof(TransferSyntaxStrings) / sizeof(*TransferSyntaxStrings) - 1; + TransferSyntaxStringsType uids = GetTransferSyntaxStrings(); + + int i = 1; // Start at 1, not 0 + const char *p = uids[i][0]; + while( p != 0 ) + { + if( strcmp( p, str ) == 0 ) + { + break; + } + ++i; + p = uids[i][0]; + } + //const char * found = uids[i][1]; + if( p ) + { + TSField = TSType(i); + assert( TSField != (TSType)0 ); + return true; + } + + assert( TSField == (TSType)0 ); + return false; +} + +const char *UIDs::GetString() const +{ + return GetUIDString(TSField); +} +const char *UIDs::GetName() const +{ + return GetUIDName(TSField); +} + +} // end namespace gdcm diff --git a/gdcm/Source/DataDictionary/gdcmUIDs.h b/gdcm/Source/DataDictionary/gdcmUIDs.h new file mode 100644 index 0000000..8051b71 --- /dev/null +++ b/gdcm/Source/DataDictionary/gdcmUIDs.h @@ -0,0 +1,670 @@ + +// GENERATED FILE DO NOT EDIT +// $ xsltproc UIDToC++.xsl Part6.xml > gdcmUIDs.h + +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#ifndef GDCMUIDS_H +#define GDCMUIDS_H + +#include "gdcmTypes.h" + +namespace gdcm +{ + +/** + * \brief all known uids + */ +class GDCM_EXPORT UIDs +{ +public: + typedef enum { +uid_1_2_840_10008_1_1 = 1, // Verification SOP Class +uid_1_2_840_10008_1_2 = 2, // Implicit VR Little Endian: Default Transfer Syntax for DICOM +uid_1_2_840_10008_1_2_1 = 3, // Explicit VR Little Endian +uid_1_2_840_10008_1_2_1_99 = 4, // Deflated Explicit VR Little Endian +uid_1_2_840_10008_1_2_2 = 5, // Explicit VR Big Endian +uid_1_2_840_10008_1_2_4_50 = 6, // JPEG Baseline (Process 1): Default Transfer Syntax for Lossy JPEG 8 Bit Image Compression +uid_1_2_840_10008_1_2_4_51 = 7, // JPEG Extended (Process 2 & 4): Default Transfer Syntax for Lossy JPEG 12 Bit Image Compression (Process 4 only) +uid_1_2_840_10008_1_2_4_52 = 8, // JPEG Extended (Process 3 & 5) +uid_1_2_840_10008_1_2_4_53 = 9, // JPEG Spectral Selection, Non-Hierarchical (Process 6 & 8) +uid_1_2_840_10008_1_2_4_54 = 10, // JPEG Spectral Selection, Non-Hierarchical (Process 7 & 9) +uid_1_2_840_10008_1_2_4_55 = 11, // JPEG Full Progression, Non-Hierarchical (Process 10 & 12) +uid_1_2_840_10008_1_2_4_56 = 12, // JPEG Full Progression, Non-Hierarchical (Process 11 & 13) +uid_1_2_840_10008_1_2_4_57 = 13, // JPEG Lossless, Non-Hierarchical (Process 14) +uid_1_2_840_10008_1_2_4_58 = 14, // JPEG Lossless, Non-Hierarchical (Process 15) +uid_1_2_840_10008_1_2_4_59 = 15, // JPEG Extended, Hierarchical (Process 16 & 18) +uid_1_2_840_10008_1_2_4_60 = 16, // JPEG Extended, Hierarchical (Process 17 & 19) +uid_1_2_840_10008_1_2_4_61 = 17, // JPEG Spectral Selection, Hierarchical (Process 20 & 22) +uid_1_2_840_10008_1_2_4_62 = 18, // JPEG Spectral Selection, Hierarchical (Process 21 & 23) +uid_1_2_840_10008_1_2_4_63 = 19, // JPEG Full Progression, Hierarchical (Process 24 & 26) +uid_1_2_840_10008_1_2_4_64 = 20, // JPEG Full Progression, Hierarchical (Process 25 & 27) +uid_1_2_840_10008_1_2_4_65 = 21, // JPEG Lossless, Hierarchical (Process 28) +uid_1_2_840_10008_1_2_4_66 = 22, // JPEG Lossless, Hierarchical (Process 29) +uid_1_2_840_10008_1_2_4_70 = 23, // JPEG Lossless, Non-Hierarchical, First-Order Prediction (Process 14 [Selection Value 1]): Default Transfer Syntax for Lossless JPEG Image Compression +uid_1_2_840_10008_1_2_4_80 = 24, // JPEG-LS Lossless Image Compression +uid_1_2_840_10008_1_2_4_81 = 25, // JPEG-LS Lossy (Near-Lossless) Image Compression +uid_1_2_840_10008_1_2_4_90 = 26, // JPEG 2000 Image Compression (Lossless Only) +uid_1_2_840_10008_1_2_4_91 = 27, // JPEG 2000 Image Compression +uid_1_2_840_10008_1_2_4_92 = 28, // JPEG 2000 Part 2 Multi-component Image Compression (Lossless Only) +uid_1_2_840_10008_1_2_4_93 = 29, // JPEG 2000 Part 2 Multi-component Image Compression +uid_1_2_840_10008_1_2_4_94 = 30, // JPIP Referenced +uid_1_2_840_10008_1_2_4_95 = 31, // JPIP Referenced Deflate +uid_1_2_840_10008_1_2_4_100 = 32, // MPEG2 Main Profile @ Main Level +uid_1_2_840_10008_1_2_5 = 33, // RLE Lossless +uid_1_2_840_10008_1_2_6_1 = 34, // RFC 2557 MIME encapsulation +uid_1_2_840_10008_1_2_6_2 = 35, // XML Encoding +uid_1_2_840_10008_1_3_10 = 36, // Media Storage Directory Storage +uid_1_2_840_10008_1_4_1_1 = 37, // Talairach Brain Atlas Frame of Reference +uid_1_2_840_10008_1_4_1_2 = 38, // SPM2 T1 Frame of Reference +uid_1_2_840_10008_1_4_1_3 = 39, // SPM2 T2 Frame of Reference +uid_1_2_840_10008_1_4_1_4 = 40, // SPM2 PD Frame of Reference +uid_1_2_840_10008_1_4_1_5 = 41, // SPM2 EPI Frame of Reference +uid_1_2_840_10008_1_4_1_6 = 42, // SPM2 FIL T1 Frame of Reference +uid_1_2_840_10008_1_4_1_7 = 43, // SPM2 PET Frame of Reference +uid_1_2_840_10008_1_4_1_8 = 44, // SPM2 TRANSM Frame of Reference +uid_1_2_840_10008_1_4_1_9 = 45, // SPM2 SPECT Frame of Reference +uid_1_2_840_10008_1_4_1_10 = 46, // SPM2 GRAY Frame of Reference +uid_1_2_840_10008_1_4_1_11 = 47, // SPM2 WHITE Frame of Reference +uid_1_2_840_10008_1_4_1_12 = 48, // SPM2 CSF Frame of Reference +uid_1_2_840_10008_1_4_1_13 = 49, // SPM2 BRAINMASK Frame of Reference +uid_1_2_840_10008_1_4_1_14 = 50, // SPM2 AVG305T1 Frame of Reference +uid_1_2_840_10008_1_4_1_15 = 51, // SPM2 AVG152T1 Frame of Reference +uid_1_2_840_10008_1_4_1_16 = 52, // SPM2 AVG152T2 Frame of Reference +uid_1_2_840_10008_1_4_1_17 = 53, // SPM2 AVG152PD Frame of Reference +uid_1_2_840_10008_1_4_1_18 = 54, // SPM2 SINGLESUBJT1 Frame of Reference +uid_1_2_840_10008_1_4_2_1 = 55, // ICBM 452 T1 Frame of Reference +uid_1_2_840_10008_1_4_2_2 = 56, // ICBM Single Subject MRI Frame of Reference +uid_1_2_840_10008_1_9 = 57, // Basic Study Content Notification SOP Class +uid_1_2_840_10008_1_20_1 = 58, // Storage Commitment Push Model SOP Class +uid_1_2_840_10008_1_20_1_1 = 59, // Storage Commitment Push Model SOP Instance +uid_1_2_840_10008_1_20_2 = 60, // Storage Commitment Pull Model SOP Class +uid_1_2_840_10008_1_20_2_1 = 61, // Storage Commitment Pull Model SOP Instance +uid_1_2_840_10008_1_40 = 62, // Procedural Event Logging SOP Class +uid_1_2_840_10008_1_40_1 = 63, // Procedural Event Logging SOP Instance +uid_1_2_840_10008_1_42 = 64, // Substance Administration Logging SOP Class +uid_1_2_840_10008_1_42_1 = 65, // Substance Administration Logging SOP Instance +uid_1_2_840_10008_2_6_1 = 66, // DICOM UID Registry +uid_1_2_840_10008_2_16_4 = 67, // DICOM Controlled Terminology +uid_1_2_840_10008_3_1_1_1 = 68, // DICOM Application Context Name +uid_1_2_840_10008_3_1_2_1_1 = 69, // Detached Patient Management SOP Class +uid_1_2_840_10008_3_1_2_1_4 = 70, // Detached Patient Management Meta SOP Class +uid_1_2_840_10008_3_1_2_2_1 = 71, // Detached Visit Management SOP Class +uid_1_2_840_10008_3_1_2_3_1 = 72, // Detached Study Management SOP Class +uid_1_2_840_10008_3_1_2_3_2 = 73, // Study Component Management SOP Class +uid_1_2_840_10008_3_1_2_3_3 = 74, // Modality Performed Procedure Step SOP Class +uid_1_2_840_10008_3_1_2_3_4 = 75, // Modality Performed Procedure Step Retrieve SOP Class +uid_1_2_840_10008_3_1_2_3_5 = 76, // Modality Performed Procedure Step Notification SOP Class +uid_1_2_840_10008_3_1_2_5_1 = 77, // Detached Results Management SOP Class +uid_1_2_840_10008_3_1_2_5_4 = 78, // Detached Results Management Meta SOP Class +uid_1_2_840_10008_3_1_2_5_5 = 79, // Detached Study Management Meta SOP Class +uid_1_2_840_10008_3_1_2_6_1 = 80, // Detached Interpretation Management SOP Class +uid_1_2_840_10008_4_2 = 81, // Storage Service Class +uid_1_2_840_10008_5_1_1_1 = 82, // Basic Film Session SOP Class +uid_1_2_840_10008_5_1_1_2 = 83, // Basic Film Box SOP Class +uid_1_2_840_10008_5_1_1_4 = 84, // Basic Grayscale Image Box SOP Class +uid_1_2_840_10008_5_1_1_4_1 = 85, // Basic Color Image Box SOP Class +uid_1_2_840_10008_5_1_1_4_2 = 86, // Referenced Image Box SOP Class +uid_1_2_840_10008_5_1_1_9 = 87, // Basic Grayscale Print Management Meta SOP Class +uid_1_2_840_10008_5_1_1_9_1 = 88, // Referenced Grayscale Print Management Meta SOP Class +uid_1_2_840_10008_5_1_1_14 = 89, // Print Job SOP Class +uid_1_2_840_10008_5_1_1_15 = 90, // Basic Annotation Box SOP Class +uid_1_2_840_10008_5_1_1_16 = 91, // Printer SOP Class +uid_1_2_840_10008_5_1_1_16_376 = 92, // Printer Configuration Retrieval SOP Class +uid_1_2_840_10008_5_1_1_17 = 93, // Printer SOP Instance +uid_1_2_840_10008_5_1_1_17_376 = 94, // Printer Configuration Retrieval SOP Instance +uid_1_2_840_10008_5_1_1_18 = 95, // Basic Color Print Management Meta SOP Class +uid_1_2_840_10008_5_1_1_18_1 = 96, // Referenced Color Print Management Meta SOP Class +uid_1_2_840_10008_5_1_1_22 = 97, // VOI LUT Box SOP Class +uid_1_2_840_10008_5_1_1_23 = 98, // Presentation LUT SOP Class +uid_1_2_840_10008_5_1_1_24 = 99, // Image Overlay Box SOP Class +uid_1_2_840_10008_5_1_1_24_1 = 100, // Basic Print Image Overlay Box SOP Class +uid_1_2_840_10008_5_1_1_25 = 101, // Print Queue SOP Instance +uid_1_2_840_10008_5_1_1_26 = 102, // Print Queue Management SOP Class +uid_1_2_840_10008_5_1_1_27 = 103, // Stored Print Storage SOP Class +uid_1_2_840_10008_5_1_1_29 = 104, // Hardcopy Grayscale Image Storage SOP Class +uid_1_2_840_10008_5_1_1_30 = 105, // Hardcopy Color Image Storage SOP Class +uid_1_2_840_10008_5_1_1_31 = 106, // Pull Print Request SOP Class +uid_1_2_840_10008_5_1_1_32 = 107, // Pull Stored Print Management Meta SOP Class +uid_1_2_840_10008_5_1_1_33 = 108, // Media Creation Management SOP Class UID +uid_1_2_840_10008_5_1_4_1_1_1 = 109, // Computed Radiography Image Storage +uid_1_2_840_10008_5_1_4_1_1_1_1 = 110, // Digital X-Ray Image Storage - For Presentation +uid_1_2_840_10008_5_1_4_1_1_1_1_1 = 111, // Digital X-Ray Image Storage - For Processing +uid_1_2_840_10008_5_1_4_1_1_1_2 = 112, // Digital Mammography X-Ray Image Storage - For Presentation +uid_1_2_840_10008_5_1_4_1_1_1_2_1 = 113, // Digital Mammography X-Ray Image Storage - For Processing +uid_1_2_840_10008_5_1_4_1_1_1_3 = 114, // Digital Intra-oral X-Ray Image Storage - For Presentation +uid_1_2_840_10008_5_1_4_1_1_1_3_1 = 115, // Digital Intra-oral X-Ray Image Storage - For Processing +uid_1_2_840_10008_5_1_4_1_1_2 = 116, // CT Image Storage +uid_1_2_840_10008_5_1_4_1_1_2_1 = 117, // Enhanced CT Image Storage +uid_1_2_840_10008_5_1_4_1_1_3 = 118, // Ultrasound Multi-frame Image Storage +uid_1_2_840_10008_5_1_4_1_1_3_1 = 119, // Ultrasound Multi-frame Image Storage +uid_1_2_840_10008_5_1_4_1_1_4 = 120, // MR Image Storage +uid_1_2_840_10008_5_1_4_1_1_4_1 = 121, // Enhanced MR Image Storage +uid_1_2_840_10008_5_1_4_1_1_4_2 = 122, // MR Spectroscopy Storage +uid_1_2_840_10008_5_1_4_1_1_5 = 123, // Nuclear Medicine Image Storage +uid_1_2_840_10008_5_1_4_1_1_6 = 124, // Ultrasound Image Storage +uid_1_2_840_10008_5_1_4_1_1_6_1 = 125, // Ultrasound Image Storage +uid_1_2_840_10008_5_1_4_1_1_7 = 126, // Secondary Capture Image Storage +uid_1_2_840_10008_5_1_4_1_1_7_1 = 127, // Multi-frame Single Bit Secondary Capture Image Storage +uid_1_2_840_10008_5_1_4_1_1_7_2 = 128, // Multi-frame Grayscale Byte Secondary Capture Image Storage +uid_1_2_840_10008_5_1_4_1_1_7_3 = 129, // Multi-frame Grayscale Word Secondary Capture Image Storage +uid_1_2_840_10008_5_1_4_1_1_7_4 = 130, // Multi-frame True Color Secondary Capture Image Storage +uid_1_2_840_10008_5_1_4_1_1_8 = 131, // Standalone Overlay Storage +uid_1_2_840_10008_5_1_4_1_1_9 = 132, // Standalone Curve Storage +uid_1_2_840_10008_5_1_4_1_1_9_1 = 133, // Waveform Storage - Trial +uid_1_2_840_10008_5_1_4_1_1_9_1_1 = 134, // 12-lead ECG Waveform Storage +uid_1_2_840_10008_5_1_4_1_1_9_1_2 = 135, // General ECG Waveform Storage +uid_1_2_840_10008_5_1_4_1_1_9_1_3 = 136, // Ambulatory ECG Waveform Storage +uid_1_2_840_10008_5_1_4_1_1_9_2_1 = 137, // Hemodynamic Waveform Storage +uid_1_2_840_10008_5_1_4_1_1_9_3_1 = 138, // Cardiac Electrophysiology Waveform Storage +uid_1_2_840_10008_5_1_4_1_1_9_4_1 = 139, // Basic Voice Audio Waveform Storage +uid_1_2_840_10008_5_1_4_1_1_10 = 140, // Standalone Modality LUT Storage +uid_1_2_840_10008_5_1_4_1_1_11 = 141, // Standalone VOI LUT Storage +uid_1_2_840_10008_5_1_4_1_1_11_1 = 142, // Grayscale Softcopy Presentation State Storage SOP Class +uid_1_2_840_10008_5_1_4_1_1_11_2 = 143, // Color Softcopy Presentation State Storage SOP Class +uid_1_2_840_10008_5_1_4_1_1_11_3 = 144, // Pseudo-Color Softcopy Presentation State Storage SOP Class +uid_1_2_840_10008_5_1_4_1_1_11_4 = 145, // Blending Softcopy Presentation State Storage SOP Class +uid_1_2_840_10008_5_1_4_1_1_12_1 = 146, // X-Ray Angiographic Image Storage +uid_1_2_840_10008_5_1_4_1_1_12_1_1 = 147, // Enhanced XA Image Storage +uid_1_2_840_10008_5_1_4_1_1_12_2 = 148, // X-Ray Radiofluoroscopic Image Storage +uid_1_2_840_10008_5_1_4_1_1_12_2_1 = 149, // Enhanced XRF Image Storage +uid_1_2_840_10008_5_1_4_1_1_13_1_1 = 150, // X-Ray 3D Angiographic Image Storage +uid_1_2_840_10008_5_1_4_1_1_13_1_2 = 151, // X-Ray 3D Craniofacial Image Storage +uid_1_2_840_10008_5_1_4_1_1_12_3 = 152, // X-Ray Angiographic Bi-Plane Image Storage +uid_1_2_840_10008_5_1_4_1_1_20 = 153, // Nuclear Medicine Image Storage +uid_1_2_840_10008_5_1_4_1_1_66 = 154, // Raw Data Storage +uid_1_2_840_10008_5_1_4_1_1_66_1 = 155, // Spatial Registration Storage +uid_1_2_840_10008_5_1_4_1_1_66_2 = 156, // Spatial Fiducials Storage +uid_1_2_840_10008_5_1_4_1_1_66_3 = 157, // Deformable Spatial Registration Storage +uid_1_2_840_10008_5_1_4_1_1_66_4 = 158, // Segmentation Storage +uid_1_2_840_10008_5_1_4_1_1_67 = 159, // Real World Value Mapping Storage +uid_1_2_840_10008_5_1_4_1_1_77_1 = 160, // VL Image Storage - Trial +uid_1_2_840_10008_5_1_4_1_1_77_2 = 161, // VL Multi-frame Image Storage - Trial +uid_1_2_840_10008_5_1_4_1_1_77_1_1 = 162, // VL Endoscopic Image Storage +uid_1_2_840_10008_5_1_4_1_1_77_1_1_1 = 163, // Video Endoscopic Image Storage +uid_1_2_840_10008_5_1_4_1_1_77_1_2 = 164, // VL Microscopic Image Storage +uid_1_2_840_10008_5_1_4_1_1_77_1_2_1 = 165, // Video Microscopic Image Storage +uid_1_2_840_10008_5_1_4_1_1_77_1_3 = 166, // VL Slide-Coordinates Microscopic Image Storage +uid_1_2_840_10008_5_1_4_1_1_77_1_4 = 167, // VL Photographic Image Storage +uid_1_2_840_10008_5_1_4_1_1_77_1_4_1 = 168, // Video Photographic Image Storage +uid_1_2_840_10008_5_1_4_1_1_77_1_5_1 = 169, // Ophthalmic Photography 8 Bit Image Storage +uid_1_2_840_10008_5_1_4_1_1_77_1_5_2 = 170, // Ophthalmic Photography 16 Bit Image Storage +uid_1_2_840_10008_5_1_4_1_1_77_1_5_3 = 171, // Stereometric Relationship Storage +uid_1_2_840_10008_5_1_4_1_1_77_1_5_4 = 172, // Ophthalmic Tomography Image Storage +uid_1_2_840_10008_5_1_4_1_1_88_1 = 173, // Text SR Storage - Trial +uid_1_2_840_10008_5_1_4_1_1_88_2 = 174, // Audio SR Storage - Trial +uid_1_2_840_10008_5_1_4_1_1_88_3 = 175, // Detail SR Storage - Trial +uid_1_2_840_10008_5_1_4_1_1_88_4 = 176, // Comprehensive SR Storage - Trial +uid_1_2_840_10008_5_1_4_1_1_88_11 = 177, // Basic Text SR Storage +uid_1_2_840_10008_5_1_4_1_1_88_22 = 178, // Enhanced SR Storage +uid_1_2_840_10008_5_1_4_1_1_88_33 = 179, // Comprehensive SR Storage +uid_1_2_840_10008_5_1_4_1_1_88_40 = 180, // Procedure Log Storage +uid_1_2_840_10008_5_1_4_1_1_88_50 = 181, // Mammography CAD SR Storage +uid_1_2_840_10008_5_1_4_1_1_88_59 = 182, // Key Object Selection Document Storage +uid_1_2_840_10008_5_1_4_1_1_88_65 = 183, // Chest CAD SR Storage +uid_1_2_840_10008_5_1_4_1_1_88_67 = 184, // X-Ray Radiation Dose SR Storage +uid_1_2_840_10008_5_1_4_1_1_104_1 = 185, // Encapsulated PDF Storage +uid_1_2_840_10008_5_1_4_1_1_104_2 = 186, // Encapsulated CDA Storage +uid_1_2_840_10008_5_1_4_1_1_128 = 187, // Positron Emission Tomography Image Storage +uid_1_2_840_10008_5_1_4_1_1_129 = 188, // Standalone PET Curve Storage +uid_1_2_840_10008_5_1_4_1_1_481_1 = 189, // RT Image Storage +uid_1_2_840_10008_5_1_4_1_1_481_2 = 190, // RT Dose Storage +uid_1_2_840_10008_5_1_4_1_1_481_3 = 191, // RT Structure Set Storage +uid_1_2_840_10008_5_1_4_1_1_481_4 = 192, // RT Beams Treatment Record Storage +uid_1_2_840_10008_5_1_4_1_1_481_5 = 193, // RT Plan Storage +uid_1_2_840_10008_5_1_4_1_1_481_6 = 194, // RT Brachy Treatment Record Storage +uid_1_2_840_10008_5_1_4_1_1_481_7 = 195, // RT Treatment Summary Record Storage +uid_1_2_840_10008_5_1_4_1_1_481_8 = 196, // RT Ion Plan Storage +uid_1_2_840_10008_5_1_4_1_1_481_9 = 197, // RT Ion Beams Treatment Record Storage +uid_1_2_840_10008_5_1_4_1_2_1_1 = 198, // Patient Root Query/Retrieve Information Model - FIND +uid_1_2_840_10008_5_1_4_1_2_1_2 = 199, // Patient Root Query/Retrieve Information Model - MOVE +uid_1_2_840_10008_5_1_4_1_2_1_3 = 200, // Patient Root Query/Retrieve Information Model - GET +uid_1_2_840_10008_5_1_4_1_2_2_1 = 201, // Study Root Query/Retrieve Information Model - FIND +uid_1_2_840_10008_5_1_4_1_2_2_2 = 202, // Study Root Query/Retrieve Information Model - MOVE +uid_1_2_840_10008_5_1_4_1_2_2_3 = 203, // Study Root Query/Retrieve Information Model - GET +uid_1_2_840_10008_5_1_4_1_2_3_1 = 204, // Patient/Study Only Query/Retrieve Information Model - FIND +uid_1_2_840_10008_5_1_4_1_2_3_2 = 205, // Patient/Study Only Query/Retrieve Information Model - MOVE +uid_1_2_840_10008_5_1_4_1_2_3_3 = 206, // Patient/Study Only Query/Retrieve Information Model - GET +uid_1_2_840_10008_5_1_4_31 = 207, // Modality Worklist Information Model - FIND +uid_1_2_840_10008_5_1_4_32_1 = 208, // General Purpose Worklist Information Model - FIND +uid_1_2_840_10008_5_1_4_32_2 = 209, // General Purpose Scheduled Procedure Step SOP Class +uid_1_2_840_10008_5_1_4_32_3 = 210, // General Purpose Performed Procedure Step SOP Class +uid_1_2_840_10008_5_1_4_32 = 211, // General Purpose Worklist Management Meta SOP Class +uid_1_2_840_10008_5_1_4_33 = 212, // Instance Availability Notification SOP Class +uid_1_2_840_10008_5_1_4_34_1 = 213, // RT Beams Delivery Instruction Storage (Supplement 74 Frozen Draft) +uid_1_2_840_10008_5_1_4_34_2 = 214, // RT Conventional Machine Verification (Supplement 74 Frozen Draft) +uid_1_2_840_10008_5_1_4_34_3 = 215, // RT Ion Machine Verification (Supplement 74 Frozen Draft) +uid_1_2_840_10008_5_1_4_34_4 = 216, // Unified Worklist and Procedure Step Service Class +uid_1_2_840_10008_5_1_4_34_4_1 = 217, // Unified Procedure Step - Push SOP Class +uid_1_2_840_10008_5_1_4_34_4_2 = 218, // Unified Procedure Step - Watch SOP Class +uid_1_2_840_10008_5_1_4_34_4_3 = 219, // Unified Procedure Step - Pull SOP Class +uid_1_2_840_10008_5_1_4_34_4_4 = 220, // Unified Procedure Step - Event SOP Class +uid_1_2_840_10008_5_1_4_34_5 = 221, // Unified Worklist and Procedure Step SOP Instance +uid_1_2_840_10008_5_1_4_37_1 = 222, // General Relevant Patient Information Query +uid_1_2_840_10008_5_1_4_37_2 = 223, // Breast Imaging Relevant Patient Information Query +uid_1_2_840_10008_5_1_4_37_3 = 224, // Cardiac Relevant Patient Information Query +uid_1_2_840_10008_5_1_4_38_1 = 225, // Hanging Protocol Storage +uid_1_2_840_10008_5_1_4_38_2 = 226, // Hanging Protocol Information Model - FIND +uid_1_2_840_10008_5_1_4_38_3 = 227, // Hanging Protocol Information Model - MOVE +uid_1_2_840_10008_5_1_4_41 = 228, // Product Characteristics Query SOP Class +uid_1_2_840_10008_5_1_4_42 = 229, // Substance Approval Query SOP Class +uid_1_2_840_10008_15_0_3_1 = 230, // dicomDeviceName +uid_1_2_840_10008_15_0_3_2 = 231, // dicomDescription +uid_1_2_840_10008_15_0_3_3 = 232, // dicomManufacturer +uid_1_2_840_10008_15_0_3_4 = 233, // dicomManufacturerModelName +uid_1_2_840_10008_15_0_3_5 = 234, // dicomSoftwareVersion +uid_1_2_840_10008_15_0_3_6 = 235, // dicomVendorData +uid_1_2_840_10008_15_0_3_7 = 236, // dicomAETitle +uid_1_2_840_10008_15_0_3_8 = 237, // dicomNetworkConnectionReference +uid_1_2_840_10008_15_0_3_9 = 238, // dicomApplicationCluster +uid_1_2_840_10008_15_0_3_10 = 239, // dicomAssociationInitiator +uid_1_2_840_10008_15_0_3_11 = 240, // dicomAssociationAcceptor +uid_1_2_840_10008_15_0_3_12 = 241, // dicomHostname +uid_1_2_840_10008_15_0_3_13 = 242, // dicomPort +uid_1_2_840_10008_15_0_3_14 = 243, // dicomSOPClass +uid_1_2_840_10008_15_0_3_15 = 244, // dicomTransferRole +uid_1_2_840_10008_15_0_3_16 = 245, // dicomTransferSyntax +uid_1_2_840_10008_15_0_3_17 = 246, // dicomPrimaryDeviceType +uid_1_2_840_10008_15_0_3_18 = 247, // dicomRelatedDeviceReference +uid_1_2_840_10008_15_0_3_19 = 248, // dicomPreferredCalledAETitle +uid_1_2_840_10008_15_0_3_20 = 249, // dicomTLSCyphersuite +uid_1_2_840_10008_15_0_3_21 = 250, // dicomAuthorizedNodeCertificateReference +uid_1_2_840_10008_15_0_3_22 = 251, // dicomThisNodeCertificateReference +uid_1_2_840_10008_15_0_3_23 = 252, // dicomInstalled +uid_1_2_840_10008_15_0_3_24 = 253, // dicomStationName +uid_1_2_840_10008_15_0_3_25 = 254, // dicomDeviceSerialNumber +uid_1_2_840_10008_15_0_3_26 = 255, // dicomInstitutionName +uid_1_2_840_10008_15_0_3_27 = 256, // dicomInstitutionAddress +uid_1_2_840_10008_15_0_3_28 = 257, // dicomInstitutionDepartmentName +uid_1_2_840_10008_15_0_3_29 = 258, // dicomIssuerOfPatientID +uid_1_2_840_10008_15_0_3_30 = 259, // dicomPreferredCallingAETitle +uid_1_2_840_10008_15_0_3_31 = 260, // dicomSupportedCharacterSet +uid_1_2_840_10008_15_0_4_1 = 261, // dicomConfigurationRoot +uid_1_2_840_10008_15_0_4_2 = 262, // dicomDevicesRoot +uid_1_2_840_10008_15_0_4_3 = 263, // dicomUniqueAETitlesRegistryRoot +uid_1_2_840_10008_15_0_4_4 = 264, // dicomDevice +uid_1_2_840_10008_15_0_4_5 = 265, // dicomNetworkAE +uid_1_2_840_10008_15_0_4_6 = 266, // dicomNetworkConnection +uid_1_2_840_10008_15_0_4_7 = 267, // dicomUniqueAETitle +uid_1_2_840_10008_15_0_4_8 = 268, // dicomTransferCapability +//frameref_1_2_840_10008_1_4_1_1 = 269, // Talairach Brain Atlas Frame of Reference +//frameref_1_2_840_10008_1_4_1_2 = 270, // SPM2 T1 Frame of Reference +//frameref_1_2_840_10008_1_4_1_3 = 271, // SPM2 T2 Frame of Reference +//frameref_1_2_840_10008_1_4_1_4 = 272, // SPM2 PD Frame of Reference +//frameref_1_2_840_10008_1_4_1_5 = 273, // SPM2 EPI Frame of Reference +//frameref_1_2_840_10008_1_4_1_6 = 274, // SPM2 FIL T1 Frame of Reference +//frameref_1_2_840_10008_1_4_1_7 = 275, // SPM2 PET Frame of Reference +//frameref_1_2_840_10008_1_4_1_8 = 276, // SPM2 TRANSM Frame of Reference +//frameref_1_2_840_10008_1_4_1_9 = 277, // SPM2 SPECT Frame of Reference +//frameref_1_2_840_10008_1_4_1_10 = 278, // SPM2 GRAY Frame of Reference +//frameref_1_2_840_10008_1_4_1_11 = 279, // SPM2 WHITE Frame of Reference +//frameref_1_2_840_10008_1_4_1_12 = 280, // SPM2 CSF Frame of Reference +//frameref_1_2_840_10008_1_4_1_13 = 281, // SPM2 BRAINMASK Frame of Reference +//frameref_1_2_840_10008_1_4_1_14 = 282, // SPM2 AVG305T1 Frame of Reference +//frameref_1_2_840_10008_1_4_1_15 = 283, // SPM2 AVG152T1 Frame of Reference +//frameref_1_2_840_10008_1_4_1_16 = 284, // SPM2 AVG152T2 Frame of Reference +//frameref_1_2_840_10008_1_4_1_17 = 285, // SPM2 AVG152PD Frame of Reference +//frameref_1_2_840_10008_1_4_1_18 = 286, // SPM2 SINGLESUBJT1 Frame of Reference +//frameref_1_2_840_10008_1_4_2_1 = 287, // ICBM 452 T1 Frame of Reference +//frameref_1_2_840_10008_1_4_2_2 = 288, // ICBM Single Subject MRI Frame of Reference +//uid_1_2_840_113619_4_2 = 500, +//uid_1_2_840_113619_4_3 = 501, +//uid_1_3_12_2_1107_5_9_1 = 502, +//uid_1_2_840_113619_4_26 = 503, +//uid_1_2_840_113619_4_30 = 504, +//uid_2_16_840_1_113709_1_5_1 = 505, +//uid_1_2_840_113543_6_6_1_3_10002 = 506, +//uid_1_2_392_200036_9116_7_8_1_1_1 = 507, +//uid_end = 1000 +uid_1_2_840_10008_5_1_4_1_1_77_1_6, // VL Whole Slide Microscopy Image Storage +uid_1_2_840_10008_5_1_4_1_1_6_2, // EnhancedUSVolumeStorage +uid_1_2_840_10008_5_1_4_1_1_66_5, // Surface Segmentation Storage +uid_1_2_840_10008_5_1_4_1_1_13_1_3 // Breast Tomosynthesis Image Storage + +} TSType; + typedef enum { +VerificationSOPClass = 1, // Verification SOP Class +ImplicitVRLittleEndianDefaultTransferSyntaxforDICOM = 2, // Implicit VR Little Endian: Default Transfer Syntax for DICOM +ExplicitVRLittleEndian = 3, // Explicit VR Little Endian +DeflatedExplicitVRLittleEndian = 4, // Deflated Explicit VR Little Endian +ExplicitVRBigEndian = 5, // Explicit VR Big Endian +JPEGBaselineProcess1DefaultTransferSyntaxforLossyJPEG8BitImageCompression = 6, // JPEG Baseline (Process 1): Default Transfer Syntax for Lossy JPEG 8 Bit Image Compression +JPEGExtendedProcess24DefaultTransferSyntaxforLossyJPEG12BitImageCompressionProcess4only = 7, // JPEG Extended (Process 2 & 4): Default Transfer Syntax for Lossy JPEG 12 Bit Image Compression (Process 4 only) +JPEGExtendedProcess35Retired = 8, // JPEG Extended (Process 3 & 5) +JPEGSpectralSelectionNonHierarchicalProcess68Retired = 9, // JPEG Spectral Selection, Non-Hierarchical (Process 6 & 8) +JPEGSpectralSelectionNonHierarchicalProcess79Retired = 10, // JPEG Spectral Selection, Non-Hierarchical (Process 7 & 9) +JPEGFullProgressionNonHierarchicalProcess1012Retired = 11, // JPEG Full Progression, Non-Hierarchical (Process 10 & 12) +JPEGFullProgressionNonHierarchicalProcess1113Retired = 12, // JPEG Full Progression, Non-Hierarchical (Process 11 & 13) +JPEGLosslessNonHierarchicalProcess14 = 13, // JPEG Lossless, Non-Hierarchical (Process 14) +JPEGLosslessNonHierarchicalProcess15Retired = 14, // JPEG Lossless, Non-Hierarchical (Process 15) +JPEGExtendedHierarchicalProcess1618Retired = 15, // JPEG Extended, Hierarchical (Process 16 & 18) +JPEGExtendedHierarchicalProcess1719Retired = 16, // JPEG Extended, Hierarchical (Process 17 & 19) +JPEGSpectralSelectionHierarchicalProcess2022Retired = 17, // JPEG Spectral Selection, Hierarchical (Process 20 & 22) +JPEGSpectralSelectionHierarchicalProcess2123Retired = 18, // JPEG Spectral Selection, Hierarchical (Process 21 & 23) +JPEGFullProgressionHierarchicalProcess2426Retired = 19, // JPEG Full Progression, Hierarchical (Process 24 & 26) +JPEGFullProgressionHierarchicalProcess2527Retired = 20, // JPEG Full Progression, Hierarchical (Process 25 & 27) +JPEGLosslessHierarchicalProcess28Retired = 21, // JPEG Lossless, Hierarchical (Process 28) +JPEGLosslessHierarchicalProcess29Retired = 22, // JPEG Lossless, Hierarchical (Process 29) +JPEGLosslessNonHierarchicalFirstOrderPredictionProcess14SelectionValue1DefaultTransferSyntaxforLosslessJPEGImageCompression = 23, // JPEG Lossless, Non-Hierarchical, First-Order Prediction (Process 14 [Selection Value 1]): Default Transfer Syntax for Lossless JPEG Image Compression +JPEGLSLosslessImageCompression = 24, // JPEG-LS Lossless Image Compression +JPEGLSLossyNearLosslessImageCompression = 25, // JPEG-LS Lossy (Near-Lossless) Image Compression +JPEG2000ImageCompressionLosslessOnly = 26, // JPEG 2000 Image Compression (Lossless Only) +JPEG2000ImageCompression = 27, // JPEG 2000 Image Compression +JPEG2000Part2MulticomponentImageCompressionLosslessOnly = 28, // JPEG 2000 Part 2 Multi-component Image Compression (Lossless Only) +JPEG2000Part2MulticomponentImageCompression = 29, // JPEG 2000 Part 2 Multi-component Image Compression +JPIPReferenced = 30, // JPIP Referenced +JPIPReferencedDeflate = 31, // JPIP Referenced Deflate +MPEG2MainProfileMainLevel = 32, // MPEG2 Main Profile @ Main Level +RLELossless = 33, // RLE Lossless +RFC2557MIMEencapsulation = 34, // RFC 2557 MIME encapsulation +XMLEncoding = 35, // XML Encoding +MediaStorageDirectoryStorage = 36, // Media Storage Directory Storage +TalairachBrainAtlasFrameofReference = 37, // Talairach Brain Atlas Frame of Reference +SPM2T1FrameofReference = 38, // SPM2 T1 Frame of Reference +SPM2T2FrameofReference = 39, // SPM2 T2 Frame of Reference +SPM2PDFrameofReference = 40, // SPM2 PD Frame of Reference +SPM2EPIFrameofReference = 41, // SPM2 EPI Frame of Reference +SPM2FILT1FrameofReference = 42, // SPM2 FIL T1 Frame of Reference +SPM2PETFrameofReference = 43, // SPM2 PET Frame of Reference +SPM2TRANSMFrameofReference = 44, // SPM2 TRANSM Frame of Reference +SPM2SPECTFrameofReference = 45, // SPM2 SPECT Frame of Reference +SPM2GRAYFrameofReference = 46, // SPM2 GRAY Frame of Reference +SPM2WHITEFrameofReference = 47, // SPM2 WHITE Frame of Reference +SPM2CSFFrameofReference = 48, // SPM2 CSF Frame of Reference +SPM2BRAINMASKFrameofReference = 49, // SPM2 BRAINMASK Frame of Reference +SPM2AVG305T1FrameofReference = 50, // SPM2 AVG305T1 Frame of Reference +SPM2AVG152T1FrameofReference = 51, // SPM2 AVG152T1 Frame of Reference +SPM2AVG152T2FrameofReference = 52, // SPM2 AVG152T2 Frame of Reference +SPM2AVG152PDFrameofReference = 53, // SPM2 AVG152PD Frame of Reference +SPM2SINGLESUBJT1FrameofReference = 54, // SPM2 SINGLESUBJT1 Frame of Reference +ICBM452T1FrameofReference = 55, // ICBM 452 T1 Frame of Reference +ICBMSingleSubjectMRIFrameofReference = 56, // ICBM Single Subject MRI Frame of Reference +BasicStudyContentNotificationSOPClassRetired = 57, // Basic Study Content Notification SOP Class +StorageCommitmentPushModelSOPClass = 58, // Storage Commitment Push Model SOP Class +StorageCommitmentPushModelSOPInstance = 59, // Storage Commitment Push Model SOP Instance +StorageCommitmentPullModelSOPClassRetired = 60, // Storage Commitment Pull Model SOP Class +StorageCommitmentPullModelSOPInstanceRetired = 61, // Storage Commitment Pull Model SOP Instance +ProceduralEventLoggingSOPClass = 62, // Procedural Event Logging SOP Class +ProceduralEventLoggingSOPInstance = 63, // Procedural Event Logging SOP Instance +SubstanceAdministrationLoggingSOPClass = 64, // Substance Administration Logging SOP Class +SubstanceAdministrationLoggingSOPInstance = 65, // Substance Administration Logging SOP Instance +DICOMUIDRegistry = 66, // DICOM UID Registry +DICOMControlledTerminology = 67, // DICOM Controlled Terminology +DICOMApplicationContextName = 68, // DICOM Application Context Name +DetachedPatientManagementSOPClassRetired = 69, // Detached Patient Management SOP Class +DetachedPatientManagementMetaSOPClassRetired = 70, // Detached Patient Management Meta SOP Class +DetachedVisitManagementSOPClassRetired = 71, // Detached Visit Management SOP Class +DetachedStudyManagementSOPClassRetired = 72, // Detached Study Management SOP Class +StudyComponentManagementSOPClassRetired = 73, // Study Component Management SOP Class +ModalityPerformedProcedureStepSOPClass = 74, // Modality Performed Procedure Step SOP Class +ModalityPerformedProcedureStepRetrieveSOPClass = 75, // Modality Performed Procedure Step Retrieve SOP Class +ModalityPerformedProcedureStepNotificationSOPClass = 76, // Modality Performed Procedure Step Notification SOP Class +DetachedResultsManagementSOPClassRetired = 77, // Detached Results Management SOP Class +DetachedResultsManagementMetaSOPClassRetired = 78, // Detached Results Management Meta SOP Class +DetachedStudyManagementMetaSOPClassRetired = 79, // Detached Study Management Meta SOP Class +DetachedInterpretationManagementSOPClassRetired = 80, // Detached Interpretation Management SOP Class +StorageServiceClass = 81, // Storage Service Class +BasicFilmSessionSOPClass = 82, // Basic Film Session SOP Class +BasicFilmBoxSOPClass = 83, // Basic Film Box SOP Class +BasicGrayscaleImageBoxSOPClass = 84, // Basic Grayscale Image Box SOP Class +BasicColorImageBoxSOPClass = 85, // Basic Color Image Box SOP Class +ReferencedImageBoxSOPClassRetired = 86, // Referenced Image Box SOP Class +BasicGrayscalePrintManagementMetaSOPClass = 87, // Basic Grayscale Print Management Meta SOP Class +ReferencedGrayscalePrintManagementMetaSOPClassRetired = 88, // Referenced Grayscale Print Management Meta SOP Class +PrintJobSOPClass = 89, // Print Job SOP Class +BasicAnnotationBoxSOPClass = 90, // Basic Annotation Box SOP Class +PrinterSOPClass = 91, // Printer SOP Class +PrinterConfigurationRetrievalSOPClass = 92, // Printer Configuration Retrieval SOP Class +PrinterSOPInstance = 93, // Printer SOP Instance +PrinterConfigurationRetrievalSOPInstance = 94, // Printer Configuration Retrieval SOP Instance +BasicColorPrintManagementMetaSOPClass = 95, // Basic Color Print Management Meta SOP Class +ReferencedColorPrintManagementMetaSOPClassRetired = 96, // Referenced Color Print Management Meta SOP Class +VOILUTBoxSOPClass = 97, // VOI LUT Box SOP Class +PresentationLUTSOPClass = 98, // Presentation LUT SOP Class +ImageOverlayBoxSOPClassRetired = 99, // Image Overlay Box SOP Class +BasicPrintImageOverlayBoxSOPClassRetired = 100, // Basic Print Image Overlay Box SOP Class +PrintQueueSOPInstanceRetired = 101, // Print Queue SOP Instance +PrintQueueManagementSOPClassRetired = 102, // Print Queue Management SOP Class +StoredPrintStorageSOPClassRetired = 103, // Stored Print Storage SOP Class +HardcopyGrayscaleImageStorageSOPClassRetired = 104, // Hardcopy Grayscale Image Storage SOP Class +HardcopyColorImageStorageSOPClassRetired = 105, // Hardcopy Color Image Storage SOP Class +PullPrintRequestSOPClassRetired = 106, // Pull Print Request SOP Class +PullStoredPrintManagementMetaSOPClassRetired = 107, // Pull Stored Print Management Meta SOP Class +MediaCreationManagementSOPClassUID = 108, // Media Creation Management SOP Class UID +ComputedRadiographyImageStorage = 109, // Computed Radiography Image Storage +DigitalXRayImageStorageForPresentation = 110, // Digital X-Ray Image Storage - For Presentation +DigitalXRayImageStorageForProcessing = 111, // Digital X-Ray Image Storage - For Processing +DigitalMammographyXRayImageStorageForPresentation = 112, // Digital Mammography X-Ray Image Storage - For Presentation +DigitalMammographyXRayImageStorageForProcessing = 113, // Digital Mammography X-Ray Image Storage - For Processing +DigitalIntraoralXRayImageStorageForPresentation = 114, // Digital Intra-oral X-Ray Image Storage - For Presentation +DigitalIntraoralXRayImageStorageForProcessing = 115, // Digital Intra-oral X-Ray Image Storage - For Processing +CTImageStorage = 116, // CT Image Storage +EnhancedCTImageStorage = 117, // Enhanced CT Image Storage +UltrasoundMultiframeImageStorageRetired = 118, // Ultrasound Multi-frame Image Storage +UltrasoundMultiframeImageStorage = 119, // Ultrasound Multi-frame Image Storage +MRImageStorage = 120, // MR Image Storage +EnhancedMRImageStorage = 121, // Enhanced MR Image Storage +MRSpectroscopyStorage = 122, // MR Spectroscopy Storage +NuclearMedicineImageStorageRetired = 123, // Nuclear Medicine Image Storage +UltrasoundImageStorageRetired = 124, // Ultrasound Image Storage +UltrasoundImageStorage = 125, // Ultrasound Image Storage +SecondaryCaptureImageStorage = 126, // Secondary Capture Image Storage +MultiframeSingleBitSecondaryCaptureImageStorage = 127, // Multi-frame Single Bit Secondary Capture Image Storage +MultiframeGrayscaleByteSecondaryCaptureImageStorage = 128, // Multi-frame Grayscale Byte Secondary Capture Image Storage +MultiframeGrayscaleWordSecondaryCaptureImageStorage = 129, // Multi-frame Grayscale Word Secondary Capture Image Storage +MultiframeTrueColorSecondaryCaptureImageStorage = 130, // Multi-frame True Color Secondary Capture Image Storage +StandaloneOverlayStorageRetired = 131, // Standalone Overlay Storage +StandaloneCurveStorageRetired = 132, // Standalone Curve Storage +WaveformStorageTrialRetired = 133, // Waveform Storage - Trial +//12leadECGWaveformStorage = 134, // 12-lead ECG Waveform Storage +GeneralECGWaveformStorage = 135, // General ECG Waveform Storage +AmbulatoryECGWaveformStorage = 136, // Ambulatory ECG Waveform Storage +HemodynamicWaveformStorage = 137, // Hemodynamic Waveform Storage +CardiacElectrophysiologyWaveformStorage = 138, // Cardiac Electrophysiology Waveform Storage +BasicVoiceAudioWaveformStorage = 139, // Basic Voice Audio Waveform Storage +StandaloneModalityLUTStorageRetired = 140, // Standalone Modality LUT Storage +StandaloneVOILUTStorageRetired = 141, // Standalone VOI LUT Storage +GrayscaleSoftcopyPresentationStateStorageSOPClass = 142, // Grayscale Softcopy Presentation State Storage SOP Class +ColorSoftcopyPresentationStateStorageSOPClass = 143, // Color Softcopy Presentation State Storage SOP Class +PseudoColorSoftcopyPresentationStateStorageSOPClass = 144, // Pseudo-Color Softcopy Presentation State Storage SOP Class +BlendingSoftcopyPresentationStateStorageSOPClass = 145, // Blending Softcopy Presentation State Storage SOP Class +XRayAngiographicImageStorage = 146, // X-Ray Angiographic Image Storage +EnhancedXAImageStorage = 147, // Enhanced XA Image Storage +XRayRadiofluoroscopicImageStorage = 148, // X-Ray Radiofluoroscopic Image Storage +EnhancedXRFImageStorage = 149, // Enhanced XRF Image Storage +XRay3DAngiographicImageStorage = 150, // X-Ray 3D Angiographic Image Storage +XRay3DCraniofacialImageStorage = 151, // X-Ray 3D Craniofacial Image Storage +XRayAngiographicBiPlaneImageStorageRetired = 152, // X-Ray Angiographic Bi-Plane Image Storage +NuclearMedicineImageStorage = 153, // Nuclear Medicine Image Storage +RawDataStorage = 154, // Raw Data Storage +SpatialRegistrationStorage = 155, // Spatial Registration Storage +SpatialFiducialsStorage = 156, // Spatial Fiducials Storage +DeformableSpatialRegistrationStorage = 157, // Deformable Spatial Registration Storage +SegmentationStorage = 158, // Segmentation Storage +RealWorldValueMappingStorage = 159, // Real World Value Mapping Storage +VLImageStorageTrialRetired = 160, // VL Image Storage - Trial +VLMultiframeImageStorageTrialRetired = 161, // VL Multi-frame Image Storage - Trial +VLEndoscopicImageStorage = 162, // VL Endoscopic Image Storage +VideoEndoscopicImageStorage = 163, // Video Endoscopic Image Storage +VLMicroscopicImageStorage = 164, // VL Microscopic Image Storage +VideoMicroscopicImageStorage = 165, // Video Microscopic Image Storage +VLSlideCoordinatesMicroscopicImageStorage = 166, // VL Slide-Coordinates Microscopic Image Storage +VLPhotographicImageStorage = 167, // VL Photographic Image Storage +VideoPhotographicImageStorage = 168, // Video Photographic Image Storage +OphthalmicPhotography8BitImageStorage = 169, // Ophthalmic Photography 8 Bit Image Storage +OphthalmicPhotography16BitImageStorage = 170, // Ophthalmic Photography 16 Bit Image Storage +StereometricRelationshipStorage = 171, // Stereometric Relationship Storage +OphthalmicTomographyImageStorage = 172, // Ophthalmic Tomography Image Storage +TextSRStorageTrialRetired = 173, // Text SR Storage - Trial +AudioSRStorageTrialRetired = 174, // Audio SR Storage - Trial +DetailSRStorageTrialRetired = 175, // Detail SR Storage - Trial +ComprehensiveSRStorageTrialRetired = 176, // Comprehensive SR Storage - Trial +BasicTextSRStorage = 177, // Basic Text SR Storage +EnhancedSRStorage = 178, // Enhanced SR Storage +ComprehensiveSRStorage = 179, // Comprehensive SR Storage +ProcedureLogStorage = 180, // Procedure Log Storage +MammographyCADSRStorage = 181, // Mammography CAD SR Storage +KeyObjectSelectionDocumentStorage = 182, // Key Object Selection Document Storage +ChestCADSRStorage = 183, // Chest CAD SR Storage +XRayRadiationDoseSRStorage = 184, // X-Ray Radiation Dose SR Storage +EncapsulatedPDFStorage = 185, // Encapsulated PDF Storage +EncapsulatedCDAStorage = 186, // Encapsulated CDA Storage +PositronEmissionTomographyImageStorage = 187, // Positron Emission Tomography Image Storage +StandalonePETCurveStorageRetired = 188, // Standalone PET Curve Storage +RTImageStorage = 189, // RT Image Storage +RTDoseStorage = 190, // RT Dose Storage +RTStructureSetStorage = 191, // RT Structure Set Storage +RTBeamsTreatmentRecordStorage = 192, // RT Beams Treatment Record Storage +RTPlanStorage = 193, // RT Plan Storage +RTBrachyTreatmentRecordStorage = 194, // RT Brachy Treatment Record Storage +RTTreatmentSummaryRecordStorage = 195, // RT Treatment Summary Record Storage +RTIonPlanStorage = 196, // RT Ion Plan Storage +RTIonBeamsTreatmentRecordStorage = 197, // RT Ion Beams Treatment Record Storage +PatientRootQueryRetrieveInformationModelFIND = 198, // Patient Root Query/Retrieve Information Model - FIND +PatientRootQueryRetrieveInformationModelMOVE = 199, // Patient Root Query/Retrieve Information Model - MOVE +PatientRootQueryRetrieveInformationModelGET = 200, // Patient Root Query/Retrieve Information Model - GET +StudyRootQueryRetrieveInformationModelFIND = 201, // Study Root Query/Retrieve Information Model - FIND +StudyRootQueryRetrieveInformationModelMOVE = 202, // Study Root Query/Retrieve Information Model - MOVE +StudyRootQueryRetrieveInformationModelGET = 203, // Study Root Query/Retrieve Information Model - GET +PatientStudyOnlyQueryRetrieveInformationModelFINDRetired = 204, // Patient/Study Only Query/Retrieve Information Model - FIND +PatientStudyOnlyQueryRetrieveInformationModelMOVERetired = 205, // Patient/Study Only Query/Retrieve Information Model - MOVE +PatientStudyOnlyQueryRetrieveInformationModelGETRetired = 206, // Patient/Study Only Query/Retrieve Information Model - GET +ModalityWorklistInformationModelFIND = 207, // Modality Worklist Information Model - FIND +GeneralPurposeWorklistInformationModelFIND = 208, // General Purpose Worklist Information Model - FIND +GeneralPurposeScheduledProcedureStepSOPClass = 209, // General Purpose Scheduled Procedure Step SOP Class +GeneralPurposePerformedProcedureStepSOPClass = 210, // General Purpose Performed Procedure Step SOP Class +GeneralPurposeWorklistManagementMetaSOPClass = 211, // General Purpose Worklist Management Meta SOP Class +InstanceAvailabilityNotificationSOPClass = 212, // Instance Availability Notification SOP Class +RTBeamsDeliveryInstructionStorageSupplement74FrozenDraft = 213, // RT Beams Delivery Instruction Storage (Supplement 74 Frozen Draft) +RTConventionalMachineVerificationSupplement74FrozenDraft = 214, // RT Conventional Machine Verification (Supplement 74 Frozen Draft) +RTIonMachineVerificationSupplement74FrozenDraft = 215, // RT Ion Machine Verification (Supplement 74 Frozen Draft) +UnifiedWorklistandProcedureStepServiceClass = 216, // Unified Worklist and Procedure Step Service Class +UnifiedProcedureStepPushSOPClass = 217, // Unified Procedure Step - Push SOP Class +UnifiedProcedureStepWatchSOPClass = 218, // Unified Procedure Step - Watch SOP Class +UnifiedProcedureStepPullSOPClass = 219, // Unified Procedure Step - Pull SOP Class +UnifiedProcedureStepEventSOPClass = 220, // Unified Procedure Step - Event SOP Class +UnifiedWorklistandProcedureStepSOPInstance = 221, // Unified Worklist and Procedure Step SOP Instance +GeneralRelevantPatientInformationQuery = 222, // General Relevant Patient Information Query +BreastImagingRelevantPatientInformationQuery = 223, // Breast Imaging Relevant Patient Information Query +CardiacRelevantPatientInformationQuery = 224, // Cardiac Relevant Patient Information Query +HangingProtocolStorage = 225, // Hanging Protocol Storage +HangingProtocolInformationModelFIND = 226, // Hanging Protocol Information Model - FIND +HangingProtocolInformationModelMOVE = 227, // Hanging Protocol Information Model - MOVE +ProductCharacteristicsQuerySOPClass = 228, // Product Characteristics Query SOP Class +SubstanceApprovalQuerySOPClass = 229, // Substance Approval Query SOP Class +dicomDeviceName = 230, // dicomDeviceName +dicomDescription = 231, // dicomDescription +dicomManufacturer = 232, // dicomManufacturer +dicomManufacturerModelName = 233, // dicomManufacturerModelName +dicomSoftwareVersion = 234, // dicomSoftwareVersion +dicomVendorData = 235, // dicomVendorData +dicomAETitle = 236, // dicomAETitle +dicomNetworkConnectionReference = 237, // dicomNetworkConnectionReference +dicomApplicationCluster = 238, // dicomApplicationCluster +dicomAssociationInitiator = 239, // dicomAssociationInitiator +dicomAssociationAcceptor = 240, // dicomAssociationAcceptor +dicomHostname = 241, // dicomHostname +dicomPort = 242, // dicomPort +dicomSOPClass = 243, // dicomSOPClass +dicomTransferRole = 244, // dicomTransferRole +dicomTransferSyntax = 245, // dicomTransferSyntax +dicomPrimaryDeviceType = 246, // dicomPrimaryDeviceType +dicomRelatedDeviceReference = 247, // dicomRelatedDeviceReference +dicomPreferredCalledAETitle = 248, // dicomPreferredCalledAETitle +dicomTLSCyphersuite = 249, // dicomTLSCyphersuite +dicomAuthorizedNodeCertificateReference = 250, // dicomAuthorizedNodeCertificateReference +dicomThisNodeCertificateReference = 251, // dicomThisNodeCertificateReference +dicomInstalled = 252, // dicomInstalled +dicomStationName = 253, // dicomStationName +dicomDeviceSerialNumber = 254, // dicomDeviceSerialNumber +dicomInstitutionName = 255, // dicomInstitutionName +dicomInstitutionAddress = 256, // dicomInstitutionAddress +dicomInstitutionDepartmentName = 257, // dicomInstitutionDepartmentName +dicomIssuerOfPatientID = 258, // dicomIssuerOfPatientID +dicomPreferredCallingAETitle = 259, // dicomPreferredCallingAETitle +dicomSupportedCharacterSet = 260, // dicomSupportedCharacterSet +dicomConfigurationRoot = 261, // dicomConfigurationRoot +dicomDevicesRoot = 262, // dicomDevicesRoot +dicomUniqueAETitlesRegistryRoot = 263, // dicomUniqueAETitlesRegistryRoot +dicomDevice = 264, // dicomDevice +dicomNetworkAE = 265, // dicomNetworkAE +dicomNetworkConnection = 266, // dicomNetworkConnection +dicomUniqueAETitle = 267, // dicomUniqueAETitle +dicomTransferCapability = 268, // dicomTransferCapability +//TalairachBrainAtlasFrameofReference = 269, // Talairach Brain Atlas Frame of Reference +//SPM2T1FrameofReference = 270, // SPM2 T1 Frame of Reference +//SPM2T2FrameofReference = 271, // SPM2 T2 Frame of Reference +//SPM2PDFrameofReference = 272, // SPM2 PD Frame of Reference +//SPM2EPIFrameofReference = 273, // SPM2 EPI Frame of Reference +//SPM2FILT1FrameofReference = 274, // SPM2 FIL T1 Frame of Reference +//SPM2PETFrameofReference = 275, // SPM2 PET Frame of Reference +//SPM2TRANSMFrameofReference = 276, // SPM2 TRANSM Frame of Reference +//SPM2SPECTFrameofReference = 277, // SPM2 SPECT Frame of Reference +//SPM2GRAYFrameofReference = 278, // SPM2 GRAY Frame of Reference +//SPM2WHITEFrameofReference = 279, // SPM2 WHITE Frame of Reference +//SPM2CSFFrameofReference = 280, // SPM2 CSF Frame of Reference +//SPM2BRAINMASKFrameofReference = 281, // SPM2 BRAINMASK Frame of Reference +//SPM2AVG305T1FrameofReference = 282, // SPM2 AVG305T1 Frame of Reference +//SPM2AVG152T1FrameofReference = 283, // SPM2 AVG152T1 Frame of Reference +//SPM2AVG152T2FrameofReference = 284, // SPM2 AVG152T2 Frame of Reference +//SPM2AVG152PDFrameofReference = 285, // SPM2 AVG152PD Frame of Reference +//SPM2SINGLESUBJT1FrameofReference = 286, // SPM2 SINGLESUBJT1 Frame of Reference +//ICBM452T1FrameofReference = 287, // ICBM 452 T1 Frame of Reference +//ICBMSingleSubjectMRIFrameofReference = 288, // ICBM Single Subject MRI Frame of Reference +VLWholeSlideMicroscopyImageStorage, +EnhancedUSVolumeStorage, +SurfaceSegmentationStorage, +BreastTomosynthesisImageStorage +} TSName; + + + typedef const char* const (*TransferSyntaxStringsType)[2]; + static TransferSyntaxStringsType GetTransferSyntaxStrings(); + static const char * const *GetTransferSyntaxString(unsigned int ts); + static unsigned int GetNumberOfTransferSyntaxStrings(); + + + // TODO: Because I would like a dual signature for TSType and TSName, C++ won't let me do it... + static const char* GetUIDString(/*TSType*/ unsigned int ts); + static const char* GetUIDName(/*TSType*/ unsigned int ts); + + /// Initialize object from a string (a uid number) + /// return false on error, and internal state is set to 0 + bool SetFromUID(const char *str); + + /// When object is Initialize function return the well known name associated with uid + /// return NULL when not initialized + const char *GetName() const; + + /// When object is Initialize function return the uid + /// return NULL when not initialized + const char *GetString() const; + + operator TSType () const { return TSField; } + +private: + TSType TSField; +}; +//----------------------------------------------------------------------------- +inline std::ostream &operator<<(std::ostream &_os, const UIDs &uid) +{ + _os << uid.GetString() << " -> " << uid.GetName(); + return _os; + +} + +} // end namespace gdcm + +#endif //GDCMUIDS_H diff --git a/gdcm/Source/DataDictionary/gdcmconformancetests.xml b/gdcm/Source/DataDictionary/gdcmconformancetests.xml new file mode 100644 index 0000000..8f2cb8f --- /dev/null +++ b/gdcm/Source/DataDictionary/gdcmconformancetests.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + diff --git a/gdcm/Source/DataDictionary/getname.xsl b/gdcm/Source/DataDictionary/getname.xsl new file mode 100644 index 0000000..9505990 --- /dev/null +++ b/gdcm/Source/DataDictionary/getname.xsl @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + diff --git a/gdcm/Source/DataDictionary/getowner.xsl b/gdcm/Source/DataDictionary/getowner.xsl new file mode 100644 index 0000000..7de003a --- /dev/null +++ b/gdcm/Source/DataDictionary/getowner.xsl @@ -0,0 +1,28 @@ + + + + + + + + + {" + + "," + + "}, + + + + + diff --git a/gdcm/Source/DataDictionary/getretired.xsl b/gdcm/Source/DataDictionary/getretired.xsl new file mode 100644 index 0000000..78de23d --- /dev/null +++ b/gdcm/Source/DataDictionary/getretired.xsl @@ -0,0 +1,33 @@ + + + + + + + +abcdefghijklmnopqrstuvwxyz +ABCDEFGHIJKLMNOPQRSTUVWXYZ + + , + + + + + + + + + + + + diff --git a/gdcm/Source/DataDictionary/order.xsl b/gdcm/Source/DataDictionary/order.xsl new file mode 100644 index 0000000..fca5efc --- /dev/null +++ b/gdcm/Source/DataDictionary/order.xsl @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdcm/Source/DataDictionary/priv2html.xsl b/gdcm/Source/DataDictionary/priv2html.xsl new file mode 100644 index 0000000..8e09220 --- /dev/null +++ b/gdcm/Source/DataDictionary/priv2html.xsl @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + DICOM DICTIONARY + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + italic + + + normal + + + + + + + + + + + + +
TagVRVMDescriptionVersionOwnerRetiredbla
+ + ( + + , + + ) + + + + + + + + + + + + + + + + + (RET) + + + +
+ + +
+
diff --git a/gdcm/Source/DataDictionary/privatedicts.xml b/gdcm/Source/DataDictionary/privatedicts.xml new file mode 100644 index 0000000..39df187 --- /dev/null +++ b/gdcm/Source/DataDictionary/privatedicts.xml @@ -0,0 +1,8478 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdcm/Source/DataDictionary/redo.xsl b/gdcm/Source/DataDictionary/redo.xsl new file mode 100644 index 0000000..fc2469e --- /dev/null +++ b/gdcm/Source/DataDictionary/redo.xsl @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +type="text/xsl" href="gdcm2html.xsl" + + to produce output use: +$ xsltproc gdcm2html.xsl GDCM2.xml + + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdcm/Source/DataDictionary/redo2.xsl b/gdcm/Source/DataDictionary/redo2.xsl new file mode 100644 index 0000000..79a930d --- /dev/null +++ b/gdcm/Source/DataDictionary/redo2.xsl @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + +type="text/xsl" href="gdcm2html.xsl" + + to produce output use: +$ xsltproc gdcm2html.xsl GDCM2.xml + + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdcm/Source/DataDictionary/sort.xsl b/gdcm/Source/DataDictionary/sort.xsl new file mode 100644 index 0000000..fd47fff --- /dev/null +++ b/gdcm/Source/DataDictionary/sort.xsl @@ -0,0 +1,20 @@ + + + + + + + + + + diff --git a/gdcm/Source/DataDictionary/txt2xml.py b/gdcm/Source/DataDictionary/txt2xml.py new file mode 100644 index 0000000..4c9f045 --- /dev/null +++ b/gdcm/Source/DataDictionary/txt2xml.py @@ -0,0 +1,396 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import re,os + +""" +GEMS +This parser parse a table formatted like this: +Attribute Name Tag VR VM +""" +class TextParser: + def __init__(self, inputfilename, outputfilename): + self._InputFilename = '' + self._OutputFilename = '' + def Parse(self): + infile = file(inputfilename, 'r') + outLines = [] + for line in infile.readlines(): + patt = re.compile("^\s*([A-Za-z0-9&{}=+ «»%;#()./,_:<>-]+)\s+\(?([0-9A-Fa-fn]+),\s?([0-9A-Fa-fyxX]+)\)?\s+([A-Z][A-Z])\s+([0-9Nn-]+)\s*$") + patt1 = re.compile("^\s*([A-Za-z0-9&{}=+ ;%#\[\]()./,_:<>-]+)\s+\(?([0-9A-Fa-f]+),\s?([0-9A-Fa-fyxX]+)\)?\s+([1-3C]+)\s+([A-Z][A-Z])\s+([0-9Nn-]+)\s*$") + patt2 = re.compile( "^\s*([Table ]*[A-Z1-9.:-]+)\s+([A-Za-z -]+)\s+\(([A-Z0-9_]+)\)\s*$") + #patt3 = re.compile( '^\s*Private Creator Identification\s*\((["A-Za-z0-9() ./])\)\s*$' ) + patt3 = re.compile( '^\s*Private Creator Identification\s*\("?(.*)"?\)\)?\s*$' ) + patt4 = re.compile( '^\s*Private Creator Identification\s*([A-Z0-9_]+)\s*$' ) + m = patt.match(line) + m1 = patt1.match(line) + m2 = patt2.match(line) + m3 = patt3.match(line) + m4 = patt4.match(line) + #print line + if m: + # + dicom = ""%(m.group(2),m.group(3),m.group(4),m.group(5),m.group(1).rstrip()) + #dicom = m.group(1) + ' ' + m.group(2) + ' ' + m.group(3) + ' ' + m.group(4) + #print dicom + outLines.append( dicom ) + elif m1: + # + dicom = ""%(m1.group(2),m1.group(3),m1.group(5),m1.group(6),m1.group(4),m1.group(1).rstrip()) + #dicom = m.group(1) + ' ' + m.group(2) + ' ' + m.group(3) + ' ' + m.group(4) + #print dicom + outLines.append( dicom ) + elif m2: + # + s = ""%(m2.group(1),m2.group(2).rstrip(),m2.group(3)) + s += '\n' + outLines.append( s ) + elif m3: + s = ""%("??","??",m3.group(1)) + s += '\n' + outLines.append( s ) + elif m4: + s = ""%("??","??",m4.group(1)) + s += '\n' + outLines.append( s ) + else: + print line + #print self.Reformat(line) + #outLines.append( self.Reformat(line) + '\n' ) + outfile = file(outputfilename, 'w') + outfile.writelines( outLines ) + outfile.close() + +""" +GEMS +This parser parse a table formatted like this: +Grp Elm VR VM Type Definition +""" +class TextParser2: + def __init__(self, inputfilename, outputfilename): + self._InputFilename = '' + self._OutputFilename = '' + def Parse(self): + infile = file(inputfilename, 'r') + outLines = [] + for line in infile.readlines(): + patt = re.compile("^\s*([0-9A-Z]+)\s+([0-9A-Zx]+)\s+([A-Z][A-Z])\s+([1-9SNn-]+)\s+([1-9])\s+([A-Za-z0-9 ()._,/#>-]+)\s*$") + patt2 = re.compile( "^\s*([A-Z1-9.-]+)\s*([A-Za-z -]+)\s*$") + m = patt.match(line) + m2 = patt2.match(line) + #print line + if m: + # + dicom = ""%(m.group(1),m.group(2),m.group(3),m.group(4),m.group(5),m.group(6).rstrip()) + #dicom = m.group(1) + ' ' + m.group(2) + ' ' + m.group(3) + ' ' + m.group(4) + #print dicom + outLines.append( dicom ) + elif m2: + # + s = ""%(m2.group(1),m2.group(2).rstrip(),"") + s += '\n' + outLines.append( s ) + else: + print line + #print self.Reformat(line) + #outLines.append( self.Reformat(line) + '\n' ) + outfile = file(outputfilename, 'w') + outfile.writelines( outLines ) + outfile.close() + +""" +SIEMENS: +This parser parse a table formatted like this: +Tag Private Owner Code Name VR VM +""" +class TextParser3: + def __init__(self, inputfilename, outputfilename): + self._InputFilename = '' + self._OutputFilename = '' + def Parse(self): + infile = file(inputfilename, 'r') + outLines = [] + for line in infile.readlines(): + patt = re.compile("^\s*\(([0-9A-Z]+),([0-9A-Zx]+)\)\s+([A-Za-z0-9./:_ -]+)\s+\|\s+([A-Za-z0-9 ()._,/#>-]+)\s+([A-Z][A-Z]_?O?W?)\s+([0-9n-]+)\s*$") + patt2 = re.compile( "^\s*([A-Z1-9.-]+)\s*([A-Za-z -]+)\s*$") + m = patt.match(line) + m2 = patt2.match(line) + #print line + if m: + # + dicom = ""%(m.group(1),m.group(2),m.group(5),m.group(6),m.group(3).rstrip(),m.group(4).rstrip()) + #dicom = m.group(1) + ' ' + m.group(2) + ' ' + m.group(3) + ' ' + m.group(4) + #print dicom + outLines.append( dicom ) + elif m2: + # + s = ""%(m2.group(1),m2.group(2).rstrip(),"") + s += '\n' + outLines.append( s ) + else: + print line + #print self.Reformat(line) + #outLines.append( self.Reformat(line) + '\n' ) + outfile = file(outputfilename, 'w') + outfile.writelines( outLines ) + outfile.close() + +""" +PHILIPS: (see mr91.pdf) + Diffusion B-Factor 2001,xx03 VR = FL, VM = 1 Dimension: s/mm2 + Indicates the Diffusion coefficient. +""" +class TextParser4: + def __init__(self, inputfilename, outputfilename): + self._InputFilename = '' + self._OutputFilename = '' + def Parse(self): + infile = file(inputfilename, 'r') + outLines = [] + for line in infile.readlines(): + patt = re.compile("^\s*([A-Za-z0-9> -]+)\s+([0-9]+),([0-9A-Fx]+)\s+VR = ([A-Z][A-Z]), VM = ([0-9n-]+)\s+(.*)\s*$") + patt1 = re.compile("^\s*([A-Za-z0-9()> -]+)\s+([0-9]+),([0-9A-Fx]+)\s+Value Representation = ([A-Z][A-Z]), Multiplicity = ([0-9n-]+)(.*)\s*$") + patt2 = re.compile("^\s*[STUDYSERIES]+\s+\(([0-9]+),([0-9]+)\)\s+([A-Za-z ]+)\s*$") + m = patt.match(line) + m1 = patt1.match(line) + m2 = patt2.match(line) + if m: + # + dicom = ""%(m.group(2),m.group(3),m.group(4),m.group(5),m.group(1).rstrip()) + #print dicom + outLines.append( dicom ) + elif m1: + # + dicom = ""%(m1.group(2),m1.group(3),m1.group(4),m1.group(5),m1.group(1).rstrip()) + #print dicom + outLines.append( dicom ) + elif m2: + # + dicom = ""%(m2.group(1),m2.group(2),m2.group(3).rstrip()) + #print dicom + outLines.append( dicom ) + else: + print line + #print self.Reformat(line) + #outLines.append( self.Reformat(line) + '\n' ) + outfile = file(outputfilename, 'w') + outfile.writelines( outLines ) + outfile.close() + +""" +PHILIPS: (see 453567994381_B.pdf) + 7053,0010 LO Private Creator Data element 1 +""" +class TextParser5: + def __init__(self, inputfilename, outputfilename): + self._InputFilename = '' + self._OutputFilename = '' + def Parse(self): + infile = file(inputfilename, 'r') + outLines = [] + for line in infile.readlines(): + patt = re.compile("^([\s>]*)([0-9]+),([0-9A-Fx]+)\s+([A-Z][A-Z])\s+([A-Za-z0-9.?(,)> -]+)\s+([0-9n-]+)\s*$") + m = patt.match(line) + if m: + # + dicom = "\n"%(m.group(2),m.group(3),m.group(4),m.group(6),m.group(1).lstrip(),m.group(5).rstrip()) + #print dicom + outLines.append( dicom ) + else: + print line + #print self.Reformat(line) + #outLines.append( self.Reformat(line) + '\n' ) + outfile = file(outputfilename, 'w') + outfile.writelines( outLines ) + outfile.close() + +""" +PHILIPS: (see 9605_0132RevC.pdf) + Attribute Tag Type VR VM + ADAC Header Signature 0019, 0010 3 LO 2 +""" +class TextParser6: + def __init__(self, inputfilename, outputfilename): + self._InputFilename = '' + self._OutputFilename = '' + def Parse(self): + infile = file(inputfilename, 'r') + outLines = [] + for line in infile.readlines(): + patt = re.compile("^\s*([A-Za-z0-9 #()./,_:>-]+)\s+([0-9A-Z]+),\s?([0-9A-ZxX]+)\s+([1-3C]+)\s+([A-Z][A-Z])\s+([0-9Nn-]+)\s*$") + m = patt.match(line) + if m: + # + dicom = ""%(m.group(2),m.group(3),m.group(5),m.group(6),m.group(4),m.group(1).rstrip()) + #print dicom + outLines.append( dicom ) + else: + print line + #print self.Reformat(line) + #outLines.append( self.Reformat(line) + '\n' ) + outfile = file(outputfilename, 'w') + outfile.writelines( outLines ) + outfile.close() + +""" +PHILIPS: (see MR_System_R1_5_dcs.pdf + Number of PC Directions 2001,1016 SS 2, USER - +""" +class TextParser7: + def __init__(self, inputfilename, outputfilename): + self._InputFilename = '' + self._OutputFilename = '' + def Parse(self): + infile = file(inputfilename, 'r') + outLines = [] + for line in infile.readlines(): + patt = re.compile("^\s*([A-Za-z0-9'./> -]+)\s+\(?([0-9A-F]+),([0-9A-FxXY]+)\)?\s+([A-Z][A-Z])\s+([1-3C]+)?,?.*\s*$") + m = patt.match(line) + if m: + # + dicom = ""%(m.group(2),m.group(3),m.group(4),m.group(5),m.group(1).rstrip()) + #print dicom + outLines.append( dicom ) + else: + print line + #print self.Reformat(line) + #outLines.append( self.Reformat(line) + '\n' ) + outfile = file(outputfilename, 'w') + outfile.writelines( outLines ) + outfile.close() + +""" +AGFA +IMPAX object document (0029,xx00) OB 1 Mitra Object Document 1.0 +""" +class TextParser8: + def __init__(self, inputfilename, outputfilename): + self._InputFilename = '' + self._OutputFilename = '' + def Parse(self): + infile = file(inputfilename, 'r') + outLines = [] + for line in infile.readlines(): + patt = re.compile("^\s*([A-Za-z0-9()> -]+)\s+\(([0-9]+),([0-9A-Fx]+)\)\s+([A-Z][A-Z])\s+([1-9n-]+)\s+([A-Za-z_0-9. ]+)\s*$") + m = patt.match(line) + if m: + # + dicom = ""%(m.group(2),m.group(3),m.group(4),m.group(5),m.group(6),m.group(1).rstrip()) + #print dicom + outLines.append( dicom ) + else: + print line + #print self.Reformat(line) + #outLines.append( self.Reformat(line) + '\n' ) + outfile = file(outputfilename, 'w') + outfile.writelines( outLines ) + outfile.close() + +""" +SIEMENS +Parse a diction.pfl file +Pixel Overflow Flag 1 Pixel Overflow,7FE3,SIEMENS MED NM,1B,SS,1 +""" +class TextParser9: + def __init__(self, inputfilename, outputfilename): + self._InputFilename = '' + self._OutputFilename = '' + def Parse(self): + infile = file(inputfilename, 'r') + outLines = [] + for line in infile.readlines(): + patt = re.compile("^([A-Z0-9a-z()=/:%. -]+),([0-9A-F]+),([A-Za-z0-9. -]+),([0-9A-F][0-9A-F]),([A-Z][A-Z]),([1-9N-]+)$") + patt1 = re.compile("^[^,]+,([0-9A-F]+),.*$") + m = patt.match(line) + m1 = patt1.match(line) + if m: + # + dicom = ""%(m.group(2),m.group(4),m.group(5),m.group(6),m.group(3),m.group(1).rstrip()) + #print dicom + outLines.append( dicom ) + else: + #print line + n = eval( '0x' + m1.group(1) ) + #print m1.group(1) + if( not (n % 2 == 0) ): + print n + print line + #print self.Reformat(line) + #outLines.append( self.Reformat(line) + '\n' ) + outfile = file(outputfilename, 'w') + outfile.writelines( outLines ) + outfile.close() + +""" +Storage.pdf +Attribute Name Group Byte Type VR Attribute Description +""" +class TextParser10: + def __init__(self, inputfilename, outputfilename): + self._InputFilename = '' + self._OutputFilename = '' + def Parse(self): + infile = file(inputfilename, 'r') + outLines = [] + for line in infile.readlines(): + patt = re.compile("^\s*([A-Z.a-z -]+[1-2]?)\s+([0-9A-Z]+)\s+([0-9A-Zx]+)\s+([1-3])\s+([A-Z][A-Z])\s+.*$") + m = patt.match(line) + #print line + if m: + # + dicom = ""%(m.group(2),m.group(3),m.group(5),m.group(4)) + #dicom = m.group(1) + ' ' + m.group(2) + ' ' + m.group(3) + ' ' + m.group(4) + #print dicom + dicom += '\n' + dicom += "%s\n\n"%m.group(1).rstrip() + outLines.append( dicom ) + else: + print line + #print self.Reformat(line) + #outLines.append( self.Reformat(line) + '\n' ) + outfile = file(outputfilename, 'w') + outfile.writelines( outLines ) + outfile.close() + +""" +S2000_1.5_DCS_public.pdf +Attribute Name (Group,Element) Type Attribute Description +""" +class TextParser11: + def __init__(self, inputfilename, outputfilename): + self._InputFilename = '' + self._OutputFilename = '' + def Parse(self): + infile = file(inputfilename, 'r') + outLines = [] + for line in infile.readlines(): + #patt = re.compile("^\s*([A-Za-z ]+)\s+\(([0-9A-F]+),([0-9A-F]+)\)\s+([1-3])\s+([A-Za-z0-9=,. ])\s*$") + patt = re.compile("^\s*([A-Za-z0-9 '/-]+)\s+\(([0-9]+),([0-9A-Fa-fx]+)\)\s+([1-3])\s+.*$") + m = patt.match(line) + #print line + if m: + # + dicom = ""%(m.group(1).rstrip(),m.group(2),m.group(3),m.group(4)) + #dicom = m.group(1) + ' ' + m.group(2) + ' ' + m.group(3) + ' ' + m.group(4) + #print dicom + dicom += '\n' + #dicom += "%s\n\n"% + outLines.append( dicom ) + else: + print "no:",line + #print self.Reformat(line) + #outLines.append( self.Reformat(line) + '\n' ) + outfile = file(outputfilename, 'w') + outfile.writelines( outLines ) + outfile.close() + +if __name__ == "__main__": + argc = len(os.sys.argv ) + if ( argc < 3 ): + print "Sorry, wrong list of args" + os.sys.exit(1) #error + + inputfilename = os.sys.argv[1] + outputfilename = os.sys.argv[2] + tp = TextParser(inputfilename,outputfilename); + tp.Parse() diff --git a/gdcm/Source/DataDictionary/uppercase.xsl b/gdcm/Source/DataDictionary/uppercase.xsl new file mode 100644 index 0000000..d0fc429 --- /dev/null +++ b/gdcm/Source/DataDictionary/uppercase.xsl @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdcm/Source/DataDictionary/vital.xml b/gdcm/Source/DataDictionary/vital.xml new file mode 100644 index 0000000..544a964 --- /dev/null +++ b/gdcm/Source/DataDictionary/vital.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/CMakeLists.txt b/gdcm/Source/DataStructureAndEncodingDefinition/CMakeLists.txt new file mode 100644 index 0000000..e593ca6 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/CMakeLists.txt @@ -0,0 +1,71 @@ +# Define the srcs for Data Structure and Encoding Definitions +# DSED +set(DSED_SRCS + gdcmTag.cxx + gdcmTagToVR.cxx + gdcmPrivateTag.cxx + gdcmCodeString.cxx + gdcmByteValue.cxx + gdcmValue.cxx + gdcmFileSet.cxx + gdcmDataSet.cxx + gdcmByteSwapFilter.cxx + gdcmUNExplicitImplicitDataElement.cxx + gdcmExplicitDataElement.cxx + gdcmFileMetaInformation.cxx + gdcmFragment.cxx + gdcmImplicitDataElement.cxx + gdcmItem.cxx + gdcmReader.cxx + gdcmWriter.cxx + #gdcmParser.cxx + gdcmCSAHeader.cxx + gdcmPDBHeader.cxx + gdcmSequenceOfFragments.cxx + gdcmSequenceOfItems.cxx + gdcmTransferSyntax.cxx + gdcmMediaStorage.cxx + gdcmVM.cxx + gdcmVR.cxx + gdcmFile.cxx + gdcmPreamble.cxx + gdcmParseException.cxx + gdcmDataElement.cxx + gdcmUNExplicitDataElement.cxx + gdcmCP246ExplicitDataElement.cxx + gdcmExplicitImplicitDataElement.cxx + gdcmVR16ExplicitDataElement.cxx + ) + +# Add the include paths +include_directories( + # Bin: + "${GDCM_BINARY_DIR}/Source/Common" + + # src: + "${GDCM_SOURCE_DIR}/Source/Common" + "${GDCM_SOURCE_DIR}/Source/DataDictionary" + "${GDCM_SOURCE_DIR}/Source/DataStructureAndEncodingDefinition/" + + "${GDCM_SOURCE_DIR}/Utilities" + ) + +if(NOT GDCM_USE_SYSTEM_ZLIB) + include_directories( + "${GDCM_BINARY_DIR}/Utilities/gdcmzlib" + ) +endif() + + +add_library(gdcmDSED ${DSED_SRCS}) +target_link_libraries(gdcmDSED gdcmCommon) +# zlib stuff are actually included (template) so we need to link them here. +target_link_libraries(gdcmDSED ${GDCM_ZLIB_LIBRARIES}) +set_target_properties(gdcmDSED PROPERTIES ${GDCM_LIBRARY_PROPERTIES} LINK_INTERFACE_LIBRARIES "gdcmCommon") + +# libs +install_library(gdcmDSED) +# PDB +install_pdb(gdcmDSED) +# include files +install_includes("*.h" "*.txx") diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/README.txt b/gdcm/Source/DataStructureAndEncodingDefinition/README.txt new file mode 100644 index 0000000..80a4e20 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/README.txt @@ -0,0 +1,2 @@ +DICOM Data Structure and Encoding Definitions +Part 3.5 diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmAttribute.h b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmAttribute.h new file mode 100644 index 0000000..af1e9aa --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmAttribute.h @@ -0,0 +1,1050 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMATTRIBUTE_H +#define GDCMATTRIBUTE_H + +#include "gdcmTypes.h" +#include "gdcmVR.h" +#include "gdcmTagToType.h" +#include "gdcmVM.h" +#include "gdcmElement.h" +#include "gdcmDataElement.h" +#include "gdcmDataSet.h" +#include "gdcmStaticAssert.h" + +#include +#include +#include + +namespace gdcm +{ + +struct void_; + +// Declaration, also serve as forward declaration +template class VRVLSize; + +// Implementation when VL is coded on 16 bits: +template<> class VRVLSize<0> { +public: + static inline uint16_t Read(std::istream &_is) { + uint16_t l; + _is.read((char*)&l, 2); + return l; + } + + static inline void Write(std::ostream &os) { (void)os; + } +}; +// Implementation when VL is coded on 32 bits: +template<> class VRVLSize<1> { +public: + static inline uint32_t Read(std::istream &_is) { + char dummy[2]; + _is.read(dummy, 2); + + uint32_t l; + _is.read((char*)&l, 4); + return l; + } + + static inline void Write(std::ostream &os) { (void)os; + } +}; + +/** + * \brief Attribute class + * This class use template metaprograming tricks to let the user know when the template + * instanciation does not match the public dictionary. + * + * Typical example that compile is: + * Attribute<0x0008,0x9007> a = {"ORIGINAL","PRIMARY","T1","NONE"}; + * + * Examples that will NOT compile are: + * + * Attribute<0x0018,0x1182, VR::IS, VM::VM1> fd1 = {}; // not enough parameters + * Attribute<0x0018,0x1182, VR::IS, VM::VM2> fd2 = {0,1,2}; // too many initializers + * Attribute<0x0018,0x1182, VR::IS, VM::VM3> fd3 = {0,1,2}; // VM3 is not valid + * Attribute<0x0018,0x1182, VR::UL, VM::VM2> fd3 = {0,1}; // UL is not valid VR + */ +template::VRType, // can the user override this value ? + int TVM = TagToType::VMType // can the user override this value ? + /*typename SQAttribute = void_*/ > // if only I had variadic template... +class Attribute +{ +public: + typedef typename VRToType::Type ArrayType; + enum { VMType = VMToLength::Length }; + ArrayType Internal[VMToLength::Length]; + + // Make sure that user specified VR/VM are compatible with the public dictionary: + GDCM_STATIC_ASSERT( ((VR::VRType)TVR & (VR::VRType)(TagToType::VRType)) ); + GDCM_STATIC_ASSERT( ((VM::VMType)TVM & (VM::VMType)(TagToType::VMType)) ); + GDCM_STATIC_ASSERT( ((((VR::VRType)TVR & VR::VR_VM1) && ((VM::VMType)TVM == VM::VM1) ) + || !((VR::VRType)TVR & VR::VR_VM1) ) ); + + static Tag GetTag() { return Tag(Group,Element); } + static VR GetVR() { return (VR::VRType)TVR; } + static VM GetVM() { return (VM::VMType)TVM; } + + // The following two methods do make sense only in case of public element, + // when the template is intanciated with private element the VR/VM are simply + // defaulted to allow everything (see gdcmTagToType.h default template for TagToType) + static VR GetDictVR() { return (VR::VRType)(TagToType::VRType); } + static VM GetDictVM() { return (VM::VMType)(TagToType::VMType); } + + // Some extra dummy checks: + // Data Elements with a VR of SQ, OF, OW, OB or UN shall always have a Value Multiplicity of one. + + unsigned int GetNumberOfValues() const { + return VMToLength::Length; + } + // Implementation of Print is common to all Mode (ASCII/Binary) + // TODO: Can we print a \ when in ASCII...well I don't think so + // it would mean we used a bad VM then, right ? + void Print(std::ostream &os) const { + os << GetTag() << " "; + os << TagToType::GetVRString() << " "; + os << TagToType::GetVMString() << " "; + os << Internal[0]; // VM is at least garantee to be one + for(unsigned int i=1; i::Mode>::Write(Internal, + GetNumberOfValues(),os); + ret.SetVR( GetVR() ); + assert( ret.GetVR() != VR::SQ ); + if( (VR::VRType)VRToEncoding::Mode == VR::VRASCII ) + { + if( GetVR() != VR::UI ) + { + if( os.str().size() % 2 ) + { + os << " "; + } + } + } + VL::Type osStrSize = (VL::Type)os.str().size(); + ret.SetByteValue( os.str().c_str(), osStrSize ); + return ret; + } + + void SetFromDataElement(DataElement const &de) { + // This is kind of hackish but since I do not generate other element than the first one: 0x6000 I should be ok: + assert( GetTag() == de.GetTag() || GetTag().GetGroup() == 0x6000 || GetTag().GetGroup() == 0x5000 ); + assert( GetVR() != VR::INVALID ); + assert( GetVR().Compatible( de.GetVR() ) || de.GetVR() == VR::INVALID ); // In case of VR::INVALID cannot use the & operator + if( de.IsEmpty() ) return; + const ByteValue *bv = de.GetByteValue(); +#ifdef GDCM_WORDS_BIGENDIAN + if( de.GetVR() == VR::UN /*|| de.GetVR() == VR::INVALID*/ ) +#else + if( de.GetVR() == VR::UN || de.GetVR() == VR::INVALID ) +#endif + { + SetByteValue(bv); + } + else + { + SetByteValueNoSwap(bv); + } + } + void Set(DataSet const &ds) { + SetFromDataElement( ds.GetDataElement( GetTag() ) ); + } + void SetFromDataSet(DataSet const &ds) { + if( ds.FindDataElement( GetTag() ) && + !ds.GetDataElement( GetTag() ).IsEmpty() ) + { + SetFromDataElement( ds.GetDataElement( GetTag() ) ); + } + } +protected: + void SetByteValueNoSwap(const ByteValue *bv) { + if( !bv ) return; // That would be bad... + assert( bv->GetPointer() && bv->GetLength() ); // [123]C element can be empty + //if( VRToEncoding::Mode == VR::VRBINARY ) + // { + // // always do a copy ! + // SetValues(bv->GetPointer(), bv->GetLength()); + // } + //else + { + std::stringstream ss; + std::string s = std::string( bv->GetPointer(), bv->GetLength() ); + ss.str( s ); + EncodingImplementation::Mode>::ReadNoSwap(Internal, + GetNumberOfValues(),ss); + } + } + void SetByteValue(const ByteValue *bv) { + if( !bv ) return; // That would be bad... + assert( bv->GetPointer() && bv->GetLength() ); // [123]C element can be empty + //if( VRToEncoding::Mode == VR::VRBINARY ) + // { + // // always do a copy ! + // SetValues(bv->GetPointer(), bv->GetLength()); + // } + //else + { + std::stringstream ss; + std::string s = std::string( bv->GetPointer(), bv->GetLength() ); + ss.str( s ); + EncodingImplementation::Mode>::Read(Internal, + GetNumberOfValues(),ss); + } + } +#if 0 // TODO FIXME the implicit way: + // explicit: + void Read(std::istream &_is) { + const uint16_t cref[] = { Group, Element }; + uint16_t c[2]; + _is.read((char*)&c, sizeof(c)); + assert( c[0] == cref[0] && c[1] == cref[1] ); + char vr[2]; + _is.read(vr, 2); // Check consistency ? + const uint32_t lref = GetLength() * sizeof( typename VRToType::Type ); + uint32_t l = VRVLSize< (TVR & VR::VL32) >::Read(_is); + l /= sizeof( typename VRToType::Type ); + return EncodingImplementation::Mode>::Read(Internal, + l,_is); + } + void Write(std::ostream &_os) const { + uint16_t c[] = { Group, Element }; + _os.write((char*)&c, 4); + uint32_t l = GetLength() * sizeof( typename VRToType::Type ); + _os.write((char*)&l, 4); + return EncodingImplementation::Mode>::Write(Internal, + GetLength(),_os); + } + void Read(std::istream &_is) { + uint16_t cref[] = { Group, Element }; + uint16_t c[2]; + _is.read((char*)&c, 4); + const uint32_t lref = GetLength() * sizeof( typename VRToType::Type ); + uint32_t l; + _is.read((char*)&l, 4); + l /= sizeof( typename VRToType::Type ); + return EncodingImplementation::Mode>::Read(Internal, + l,_is); + } + void Write(std::ostream &_os) const { + uint16_t c[] = { Group, Element }; + _os.write((char*)&c, 4); + uint32_t l = GetLength() * sizeof( typename VRToType::Type ); + _os.write((char*)&l, 4); + return EncodingImplementation::Mode>::Write(Internal, + GetLength(),_os); + } +#endif + +}; + +template +class Attribute +{ +public: + typedef typename VRToType::Type ArrayType; + enum { VMType = VMToLength::Length }; + //ArrayType Internal[VMToLength::Length]; + ArrayType Internal; + GDCM_STATIC_ASSERT( VMToLength::Length == 1 ); + + // Make sure that user specified VR/VM are compatible with the public dictionary: + GDCM_STATIC_ASSERT( ((VR::VRType)TVR & (VR::VRType)(TagToType::VRType)) ); + GDCM_STATIC_ASSERT( ((VM::VMType)VM::VM1 & (VM::VMType)(TagToType::VMType)) ); + GDCM_STATIC_ASSERT( ((((VR::VRType)TVR & VR::VR_VM1) && ((VM::VMType)VM::VM1 == VM::VM1) ) + || !((VR::VRType)TVR & VR::VR_VM1) ) ); + + static Tag GetTag() { return Tag(Group,Element); } + static VR GetVR() { return (VR::VRType)TVR; } + static VM GetVM() { return (VM::VMType)VM::VM1; } + + // The following two methods do make sense only in case of public element, + // when the template is intanciated with private element the VR/VM are simply + // defaulted to allow everything (see gdcmTagToType.h default template for TagToType) + static VR GetDictVR() { return (VR::VRType)(TagToType::VRType); } + static VM GetDictVM() { return (VM::VMType)(TagToType::VMType); } + + // Some extra dummy checks: + // Data Elements with a VR of SQ, OF, OW, OB or UN shall always have a Value Multiplicity of one. + + unsigned int GetNumberOfValues() const { + return VMToLength::Length; + } + // Implementation of Print is common to all Mode (ASCII/Binary) + // TODO: Can we print a \ when in ASCII...well I don't think so + // it would mean we used a bad VM then, right ? + void Print(std::ostream &os) const { + os << GetTag() << " "; + os << TagToType::GetVRString() << " "; + os << TagToType::GetVMString() << " "; + os << Internal; // VM is at least garantee to be one + } + // copy: + //ArrayType GetValue(unsigned int idx = 0) { + // assert( idx < GetNumberOfValues() ); + // return Internal[idx]; + //} + //ArrayType operator[] (unsigned int idx) { + // return GetValue(idx); + //} + // FIXME: is this always a good idea ? + // I do not think so, I prefer operator + //operator ArrayType () const { return Internal[0]; } + + bool operator==(const Attribute &att) const + { + return std::equal(&Internal, &Internal+GetNumberOfValues(), + att.GetValues()); + } + bool operator!=(const Attribute &att) const + { + return !std::equal(&Internal, &Internal+GetNumberOfValues(), + att.GetValues()); + } + bool operator<(const Attribute &att) const + { + return std::lexicographical_compare(&Internal, &Internal+GetNumberOfValues(), + att.GetValues(), att.GetValues() + att.GetNumberOfValues() ); + } + + ArrayType &GetValue() { +// assert( idx < GetNumberOfValues() ); + return Internal; + } +// ArrayType & operator[] (unsigned int idx) { +// return GetValue(idx); +// } + // const reference + ArrayType const &GetValue() const { + //assert( idx < GetNumberOfValues() ); + return Internal; + } + //ArrayType const & operator[] () const { + // return GetValue(); + //} + void SetValue(ArrayType v) { +// assert( idx < GetNumberOfValues() ); + Internal = v; + } +/* void SetValues(const ArrayType* array, unsigned int numel = VMType ) { + assert( array && numel && numel == GetNumberOfValues() ); + // std::copy is smarted than a memcpy, and will call memcpy when POD type + std::copy(array, array+numel, Internal); + } +*/ + + // FIXME Should we remove this function ? + const ArrayType* GetValues() const { + return &Internal; + } + + // API to talk to the run-time layer: gdcm::DataElement + DataElement GetAsDataElement() const { + DataElement ret( GetTag() ); + std::ostringstream os; + // os.imbue(std::locale::classic()); // This is not required AFAIK + EncodingImplementation::Mode>::Write(&Internal, + GetNumberOfValues(),os); + ret.SetVR( GetVR() ); + assert( ret.GetVR() != VR::SQ ); + if( (VR::VRType)VRToEncoding::Mode == VR::VRASCII ) + { + if( GetVR() != VR::UI ) + { + if( os.str().size() % 2 ) + { + os << " "; + } + } + } + VL::Type osStrSize = (VL::Type)os.str().size(); + ret.SetByteValue( os.str().c_str(), osStrSize ); + return ret; + } + + void SetFromDataElement(DataElement const &de) { + // This is kind of hackish but since I do not generate other element than the first one: 0x6000 I should be ok: + assert( GetTag() == de.GetTag() || GetTag().GetGroup() == 0x6000 || GetTag().GetGroup() == 0x5000 ); + assert( GetVR() != VR::INVALID ); + assert( GetVR().Compatible( de.GetVR() ) || de.GetVR() == VR::INVALID ); // In case of VR::INVALID cannot use the & operator + if( de.IsEmpty() ) return; + const ByteValue *bv = de.GetByteValue(); +#ifdef GDCM_WORDS_BIGENDIAN + if( de.GetVR() == VR::UN /*|| de.GetVR() == VR::INVALID*/ ) +#else + if( de.GetVR() == VR::UN || de.GetVR() == VR::INVALID ) +#endif + { + SetByteValue(bv); + } + else + { + SetByteValueNoSwap(bv); + } + } + void Set(DataSet const &ds) { + SetFromDataElement( ds.GetDataElement( GetTag() ) ); + } + void SetFromDataSet(DataSet const &ds) { + if( ds.FindDataElement( GetTag() ) && + !ds.GetDataElement( GetTag() ).IsEmpty() ) + { + SetFromDataElement( ds.GetDataElement( GetTag() ) ); + } + } +protected: + void SetByteValueNoSwap(const ByteValue *bv) { + if( !bv ) return; // That would be bad... + assert( bv->GetPointer() && bv->GetLength() ); // [123]C element can be empty + //if( VRToEncoding::Mode == VR::VRBINARY ) + // { + // // always do a copy ! + // SetValues(bv->GetPointer(), bv->GetLength()); + // } + //else + { + std::stringstream ss; + std::string s = std::string( bv->GetPointer(), bv->GetLength() ); + ss.str( s ); + EncodingImplementation::Mode>::ReadNoSwap(&Internal, + GetNumberOfValues(),ss); + } + } + void SetByteValue(const ByteValue *bv) { + if( !bv ) return; // That would be bad... + assert( bv->GetPointer() && bv->GetLength() ); // [123]C element can be empty + //if( VRToEncoding::Mode == VR::VRBINARY ) + // { + // // always do a copy ! + // SetValues(bv->GetPointer(), bv->GetLength()); + // } + //else + { + std::stringstream ss; + std::string s = std::string( bv->GetPointer(), bv->GetLength() ); + ss.str( s ); + EncodingImplementation::Mode>::Read(&Internal, + GetNumberOfValues(),ss); + } + } +#if 0 // TODO FIXME the implicit way: + // explicit: + void Read(std::istream &_is) { + const uint16_t cref[] = { Group, Element }; + uint16_t c[2]; + _is.read((char*)&c, sizeof(c)); + assert( c[0] == cref[0] && c[1] == cref[1] ); + char vr[2]; + _is.read(vr, 2); // Check consistency ? + const uint32_t lref = GetLength() * sizeof( typename VRToType::Type ); + uint32_t l = VRVLSize< (TVR & VR::VL32) >::Read(_is); + l /= sizeof( typename VRToType::Type ); + return EncodingImplementation::Mode>::Read(Internal, + l,_is); + } + void Write(std::ostream &_os) const { + uint16_t c[] = { Group, Element }; + _os.write((char*)&c, 4); + uint32_t l = GetLength() * sizeof( typename VRToType::Type ); + _os.write((char*)&l, 4); + return EncodingImplementation::Mode>::Write(Internal, + GetLength(),_os); + } + void Read(std::istream &_is) { + uint16_t cref[] = { Group, Element }; + uint16_t c[2]; + _is.read((char*)&c, 4); + const uint32_t lref = GetLength() * sizeof( typename VRToType::Type ); + uint32_t l; + _is.read((char*)&l, 4); + l /= sizeof( typename VRToType::Type ); + return EncodingImplementation::Mode>::Read(Internal, + l,_is); + } + void Write(std::ostream &_os) const { + uint16_t c[] = { Group, Element }; + _os.write((char*)&c, 4); + uint32_t l = GetLength() * sizeof( typename VRToType::Type ); + _os.write((char*)&l, 4); + return EncodingImplementation::Mode>::Write(Internal, + GetLength(),_os); + } +#endif + +}; + +// No need to repeat default template arg, since primary template +// will be used to generate the default arguments +template +class Attribute +{ +public: + typedef typename VRToType::Type ArrayType; + + // Make sure that user specified VR/VM are compatible with the public dictionary: + GDCM_STATIC_ASSERT( ((VR::VRType)TVR & (VR::VRType)(TagToType::VRType)) ); + GDCM_STATIC_ASSERT( (VM::VM1_n & (VM::VMType)(TagToType::VMType)) ); + GDCM_STATIC_ASSERT( ((((VR::VRType)TVR & VR::VR_VM1) && ((VM::VMType)TagToType::VMType == VM::VM1) ) + || !((VR::VRType)TVR & VR::VR_VM1) ) ); + + static Tag GetTag() { return Tag(Group,Element); } + static VR GetVR() { return (VR::VRType)TVR; } + static VM GetVM() { return VM::VM1_n; } + + static VR GetDictVR() { return (VR::VRType)(TagToType::VRType); } + static VM GetDictVM() { return GetVM(); } + + // This the way to prevent default initialization + explicit Attribute() { Internal=0; Length=0; Own = true; } + ~Attribute() { + if( Own ) { + delete[] Internal; + } + Internal = 0; // paranoid + } + + unsigned int GetNumberOfValues() const { return Length; } + + void SetNumberOfValues(unsigned int numel) + { + SetValues(NULL, numel, true); + } + + const ArrayType* GetValues() const { + return Internal; + } + void Print(std::ostream &os) const { + os << GetTag() << " "; + os << GetVR() << " "; + os << GetVM() << " "; + os << Internal[0]; // VM is at least garantee to be one + for(unsigned int i=1; i(array); + } + // postcondition + assert( numel == GetNumberOfValues() ); + } + + DataElement GetAsDataElement() const { + DataElement ret( GetTag() ); + std::ostringstream os; + if( Internal ) + { + EncodingImplementation::Mode>::Write(Internal, + GetNumberOfValues(),os); + if( (VR::VRType)VRToEncoding::Mode == VR::VRASCII ) + { + if( GetVR() != VR::UI ) + { + if( os.str().size() % 2 ) + { + os << " "; + } + } + } + } + ret.SetVR( GetVR() ); + assert( ret.GetVR() != VR::SQ ); + VL::Type osStrSize = (VL::Type) os.str().size(); + ret.SetByteValue( os.str().c_str(), osStrSize); + return ret; + } + void SetFromDataElement(DataElement const &de) { + // This is kind of hackish but since I do not generate other element than the first one: 0x6000 I should be ok: + assert( GetTag() == de.GetTag() || GetTag().GetGroup() == 0x6000 + || GetTag().GetGroup() == 0x5000 ); + assert( GetVR().Compatible( de.GetVR() ) ); // In case of VR::INVALID cannot use the & operator + assert( !de.IsEmpty() ); + const ByteValue *bv = de.GetByteValue(); + SetByteValue(bv); + } + void Set(DataSet const &ds) { + SetFromDataElement( ds.GetDataElement( GetTag() ) ); + } + void SetFromDataSet(DataSet const &ds) { + if( ds.FindDataElement( GetTag() ) && + !ds.GetDataElement( GetTag() ).IsEmpty() ) + { + SetFromDataElement( ds.GetDataElement( GetTag() ) ); + } + } +protected: + void SetByteValue(const ByteValue *bv) { + assert( bv ); // FIXME + std::stringstream ss; + std::string s = std::string( bv->GetPointer(), bv->GetLength() ); + Length = bv->GetLength(); // HACK FIXME + ss.str( s ); + ArrayType *internal; + ArrayType buffer[256]; + if( bv->GetLength() < 256 ) + { + internal = buffer; + } + else + { + internal = new ArrayType[(VL::Type)bv->GetLength()]; // over allocation + } + EncodingImplementation::Mode>::ReadComputeLength(internal, Length, ss); + SetValues( internal, Length, true ); + if( !(bv->GetLength() < 256) ) + { + delete[] internal; + } + //EncodingImplementation::Mode>::Read(Internal, + // GetNumberOfValues(),ss); + } + +private: + ArrayType *Internal; + unsigned int Length; + bool Own : 1; +}; + +template +class Attribute : public Attribute +{ +public: + VM GetVM() const { return VM::VM1_3; } +}; + +template +class Attribute : public Attribute +{ +public: + VM GetVM() const { return VM::VM1_8; } +}; + +template +class Attribute : public Attribute +{ +public: + VM GetVM() const { return VM::VM2_n; } +}; + +template +class Attribute : public Attribute +{ +public: + static VM GetVM() { return VM::VM2_2n; } +}; + +template +class Attribute : public Attribute +{ +public: + static VM GetVM() { return VM::VM3_n; } +}; + +template +class Attribute : public Attribute +{ +public: + static VM GetVM() { return VM::VM3_3n; } +}; + + +// For particular case for ASCII string +// WARNING: This template explicitely instanciates a particular +// EncodingImplementation THEREFORE it is required to be declared after the +// EncodingImplementation is needs (doh!) +#if 0 +template +class Attribute +{ +public: + Attribute(const char array[]) + { + unsigned int i = 0; + const char sep = '\\'; + std::string sarray = array; + std::string::size_type pos1 = 0; + std::string::size_type pos2 = sarray.find(sep, pos1+1); + while(pos2 != std::string::npos) + { + Internal[i++] = sarray.substr(pos1, pos2-pos1); + pos1 = pos2+1; + pos2 = sarray.find(sep, pos1+1); + } + Internal[i] = sarray.substr(pos1, pos2-pos1); + // Shouldn't we do the contrary, since we know how many separators + // (and default behavior is to discard anything after the VM declared + assert( GetLength()-1 == i ); + } + + unsigned long GetLength() const { + return VMToLength::Length; + } + // Implementation of Print is common to all Mode (ASCII/Binary) + void Print(std::ostream &_os) const { + _os << Internal[0]; // VM is at least garantee to be one + for(int i=1; i::Length; ++i) + _os << "," << Internal[i]; + } + + void Read(std::istream &_is) { + EncodingImplementation::Read(Internal, GetLength(),_is); + } + void Write(std::ostream &_os) const { + EncodingImplementation::Write(Internal, GetLength(),_os); + } +private: + typename String Internal[VMToLength::Length]; +}; + +template< int TVM> +class Attribute : public StringAttribute +{ +}; +#endif + +#if 0 + +// Implementation for the undefined length (dynamically allocated array) +template +class Attribute +{ +public: + // This the way to prevent default initialization + explicit Attribute() { Internal=0; Length=0; } + ~Attribute() { + delete[] Internal; + Internal = 0; + } + + // Length manipulation + // SetLength should really be protected anyway...all operation + // should go through SetArray + unsigned long GetLength() const { return Length; } + typedef typename VRToType::Type ArrayType; + void SetLength(unsigned long len) { + const unsigned int size = sizeof(ArrayType); + if( len ) { + if( len > Length ) { + // perform realloc + assert( (len / size) * size == len ); + ArrayType *internal = new ArrayType[len / size]; + memcpy(internal, Internal, Length * size); + delete[] Internal; + Internal = internal; + } + } + Length = len / size; + } + + // If save is set to zero user should not delete the pointer + //void SetArray(const typename VRToType::Type *array, int len, bool save = false) + void SetArray(const ArrayType *array, unsigned long len, + bool save = false) { + if( save ) { + SetLength(len); // realloc + memcpy(Internal, array, len/*/sizeof(ArrayType)*/); + } + else { + // TODO rewrite this stupid code: + Length = len; + //Internal = array; + assert(0); + } + } + // Implementation of Print is common to all Mode (ASCII/Binary) + void Print(std::ostream &_os) const { + assert( Length ); + assert( Internal ); + _os << Internal[0]; // VM is at least garantee to be one + const unsigned long length = GetLength() < 25 ? GetLength() : 25; + for(unsigned long i=1; i::Mode>::Read(Internal, + GetLength(),_is); + } + void Write(std::ostream &_os) const { + EncodingImplementation::Mode>::Write(Internal, + GetLength(),_os); + } + + Attribute(const Attribute&_val) { + if( this != &_val) { + *this = _val; + } + } + + Attribute &operator=(const Attribute &_val) { + Length = 0; // SYITF + Internal = 0; + SetArray(_val.Internal, _val.Length, true); + return *this; + } + +private: + typename VRToType::Type *Internal; + unsigned long Length; // unsigned int ?? +}; + +//template +//class Attribute : public Attribute {}; + +// Partial specialization for derivatives of 1-n : 2-n, 3-n ... +template +class Attribute : public Attribute +{ +public: + typedef Attribute Parent; + void SetLength(int len) { + if( len <= 1 ) return; + Parent::SetLength(len); + } +}; +template +class Attribute : public Attribute +{ +public: + typedef Attribute Parent; + void SetLength(int len) { + if( len % 2 ) return; + Parent::SetLength(len); + } +}; +template +class Attribute : public Attribute +{ +public: + typedef Attribute Parent; + void SetLength(int len) { + if( len <= 2 ) return; + Parent::SetLength(len); + } +}; +template +class Attribute : public Attribute +{ +public: + typedef Attribute Parent; + void SetLength(int len) { + if( len % 3 ) return; + Parent::SetLength(len); + } +}; + + +//template struct VRToLength; +//template <> struct VRToLength +//{ enum { Length = VM::VM1 }; } +//template<> +//class Attribute : public Attribute::Length > + +// only 0010 1010 AS 1 Patient’s Age +template<> +class Attribute +{ +public: + char Internal[VMToLength::Length]; + void Print(std::ostream &_os) const { + _os << Internal; + } +}; + +template <> +class Attribute : public Attribute {}; +// Make it impossible to compile any other cases: +template class Attribute; + +// Same for OW: +template <> +class Attribute : public Attribute {}; +// Make it impossible to compile any other cases: +template class Attribute; +#endif + +#if 0 +template<> +class Attribute<0x7fe0,0x0010, VR::OW, VM::VM1> +{ +public: + char *Internal; + unsigned long Length; // unsigned int ?? + + void Print(std::ostream &_os) const { + _os << Internal[0]; + } + void SetBytes(char *bytes, unsigned long length) { + Internal = bytes; + Length = length; + } + void Read(std::istream &_is) { + uint16_t c[2]; + _is.read((char*)&c, 4); + uint32_t l; + _is.read((char*)&l, 4); + Length = l; + _is.read( Internal, Length ); + } + void Write(std::ostream &_os) const { + uint16_t c[] = {0x7fe0, 0x0010}; + _os.write((char*)&c, 4); + _os.write((char*)&Length, 4); + _os.write( Internal, Length ); + } +}; +#endif + +/* +// Removing Attribute for SQ for now... +template +class Attribute +{ +public: + SQA sqa; + void Print(std::ostream &_os) const { + _os << Tag(Group,Element); + sqa.Print(_os << std::endl << '\t'); + } + void Write(std::ostream &_os) const { + uint16_t c[] = {Group, Element}; + _os.write((char*)&c, 4); + uint32_t undef = 0xffffffff; + _os.write((char*)&undef, 4); + uint16_t item_beg[] = {0xfffe,0xe000}; + _os.write((char*)&item_beg, 4); + _os.write((char*)&undef, 4); + sqa.Write(_os); + uint16_t item_end[] = {0xfffe,0xe00d}; + _os.write((char*)&item_end, 4); + uint32_t zero = 0x0; + _os.write((char*)&zero, 4); + uint16_t seq_end[] = {0xfffe, 0xe0dd}; + _os.write((char*)&seq_end, 4); + _os.write((char*)&zero, 4); + } +}; +*/ + +/** + * \example PatchFile.cxx + * This is a C++ example on how to use gdcm::Attribute + */ + +} // namespace gdcm + +#endif //GDCMATTRIBUTE_H diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmBasicOffsetTable.h b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmBasicOffsetTable.h new file mode 100644 index 0000000..7f667f7 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmBasicOffsetTable.h @@ -0,0 +1,126 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#ifndef GDCMBASICOFFSETTABLE_H +#define GDCMBASICOFFSETTABLE_H + +#include "gdcmFragment.h" + +namespace gdcm +{ +/** + * \brief Class to represent a BasicOffsetTable + */ + +class GDCM_EXPORT BasicOffsetTable : public Fragment +{ +//protected: +// void SetTag(const Tag &t); +public: + BasicOffsetTable() : Fragment() {} + friend std::ostream &operator<<(std::ostream &os, const BasicOffsetTable &val); + +/* + VL GetLength() const { + assert( !ValueLengthField.IsUndefined() ); + assert( !ValueField || ValueField->GetLength() == ValueLengthField ); + return TagField.GetLength() + ValueLengthField.GetLength() + + ValueLengthField; + } +*/ + + template + std::istream &Read(std::istream &is) { + // Superclass + const Tag itemStart(0xfffe, 0xe000); + const Tag seqDelItem(0xfffe,0xe0dd); + if( !TagField.Read(is) ) + { + assert(0 && "Should not happen"); + return is; + } + //assert( TagField == itemStart ); + if( TagField != itemStart ) + { + // Bug_Siemens_PrivateIconNoItem.dcm + gdcmDebugMacro( "Could be Bug_Siemens_PrivateIconNoItem.dcm" ); + throw "SIEMENS Icon thingy"; + } + if( !ValueLengthField.Read(is) ) + { + assert(0 && "Should not happen"); + return is; + } + // Self + SmartPointer bv = new ByteValue; + bv->SetLength(ValueLengthField); + if( !bv->Read(is) ) + { + assert(0 && "Should not happen"); + return is; + } + ValueField = bv; + return is; + } + +/* + template + std::ostream &Write(std::ostream &os) const { + const Tag itemStart(0xfffe, 0xe000); + const Tag seqDelItem(0xfffe,0xe0dd); + if( !TagField.Write(os) ) + { + assert(0 && "Should not happen"); + return os; + } + assert( TagField == itemStart ); + if( !ValueLengthField.Write(os) ) + { + assert(0 && "Should not happen"); + return os; + } + if( ValueLengthField ) + { + // Self + const ByteValue *bv = GetByteValue(); + assert( bv ); + assert( bv->GetLength() == ValueLengthField ); + if( !bv->Write(os) ) + { + assert(0 && "Should not happen"); + return os; + } + } + return os; + } +*/ +}; +//----------------------------------------------------------------------------- +inline std::ostream &operator<<(std::ostream &os, const BasicOffsetTable &val) +{ + os << " BasicOffsetTable Length=" << val.ValueLengthField << std::endl; + if( val.ValueField ) + { + const ByteValue *bv = val.GetByteValue(); + assert( bv ); + os << *bv; + } + + return os; +} + + +} // end namespace gdcm + +#endif //GDCMBASICOFFSETTABLE_H diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmByteBuffer.h b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmByteBuffer.h new file mode 100644 index 0000000..ce78287 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmByteBuffer.h @@ -0,0 +1,107 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMBYTEBUFFER_H +#define GDCMBYTEBUFFER_H + +#include "gdcmTypes.h" +#include +#include +#include // memmove + +#error should not be used + +namespace gdcm +{ +/** + * \brief ByteBuffer + * + * Detailled description here + * \note + * looks like a std::streambuf or std::filebuf class with the get and + * peek pointer + */ +class ByteBuffer +{ + static const int InitBufferSize = 1024; +public: + ByteBuffer() : Start(0), End(0),Limit(0) {} + char *Get(int len) + { + char *buffer = &Internal[0]; + if (len > Limit - End) + { + // FIXME avoid integer overflow + int neededSize = len + (End - Start); + if (neededSize <= Limit - buffer) + { + memmove(buffer, Start, End - Start); + End = buffer + (End - Start); + Start = buffer; + } + else + { + char *newBuf; + int bufferSize = Limit - Start; + if ( bufferSize == 0 ) + { + bufferSize = InitBufferSize; + } + do + { + bufferSize *= 2; + } while (bufferSize < neededSize); + //newBuf = malloc(bufferSize); + try + { + Internal.reserve(bufferSize); + newBuf = &Internal[0]; + } + catch(...) + { + //errorCode = NoMemoryError; + return 0; + } + Limit = newBuf + bufferSize; + + if (Start) + { + memcpy(newBuf, Start, End - Start); + } + End = newBuf + (End - Start); + Start = /*buffer =*/ newBuf; + } + } + assert( (int)Internal.capacity() >= len ); + return End; + } + + void UpdatePosition() {} + void ShiftEnd(int len) { + End += len; + } + const char *GetStart() const { + return Start; + } + +private: + typedef std::vector CharVector; + const char *Start; + char *End; + const char *Limit; + CharVector Internal; +}; + +} // end namespace gdcm + +#endif //GDCMBYTEBUFFER_H diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmByteSwapFilter.cxx b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmByteSwapFilter.cxx new file mode 100644 index 0000000..4135bcc --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmByteSwapFilter.cxx @@ -0,0 +1,149 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmByteSwapFilter.h" + +#include "gdcmElement.h" +#include "gdcmByteValue.h" +#include "gdcmSequenceOfFragments.h" +#include "gdcmSequenceOfItems.h" +#include "gdcmSwapper.h" + +namespace gdcm +{ + +//----------------------------------------------------------------------------- +//ByteSwapFilter::ByteSwapFilter() +//{ +//} +//----------------------------------------------------------------------------- +ByteSwapFilter::~ByteSwapFilter() +{ +} + +bool ByteSwapFilter::ByteSwap() +{ + for( + DataSet::ConstIterator it = DS.Begin(); + it != DS.End(); ++it) + { + const DataElement &de = *it; + VR const & vr = de.GetVR(); + //assert( vr & VR::VRASCII || vr & VR::VRBINARY ); + const ByteValue *bv = de.GetByteValue(); + gdcm::SmartPointer si = de.GetValueAsSQ(); + if( de.IsEmpty() ) + { + } + else if( bv && !si ) + { + assert( !si ); + // ASCII do not need byte swap + if( vr & VR::VRBINARY /*&& de.GetTag().IsPrivate()*/ ) + { + //assert( de.GetTag().IsPrivate() ); + switch(vr) + { + case VR::AT: + assert( 0 && "Should not happen" ); + break; + case VR::FL: + // FIXME: Technically FL should not be byte-swapped... + //std::cerr << "ByteSwap FL:" << de.GetTag() << std::endl; + SwapperDoOp::SwapArray((uint32_t*)bv->GetPointer(), bv->GetLength() / sizeof(uint32_t) ); + break; + case VR::FD: + assert( 0 && "Should not happen" ); + break; + case VR::OB: + // I think we are fine, unless this is one of those OB_OW thingy + break; + case VR::OF: + assert( 0 && "Should not happen" ); + break; + case VR::OW: + assert( 0 && "Should not happen" ); + break; + case VR::SL: + SwapperDoOp::SwapArray((uint32_t*)bv->GetPointer(), bv->GetLength() / sizeof(uint32_t) ); + break; + case VR::SQ: + assert( 0 && "Should not happen" ); + break; + case VR::SS: + SwapperDoOp::SwapArray((uint16_t*)bv->GetPointer(), bv->GetLength() / sizeof(uint16_t) ); + break; + case VR::UL: + SwapperDoOp::SwapArray((uint32_t*)bv->GetPointer(), bv->GetLength() / sizeof(uint32_t) ); + break; + case VR::UN: + assert( 0 && "Should not happen" ); + break; + case VR::US: + SwapperDoOp::SwapArray((uint16_t*)bv->GetPointer(), bv->GetLength() / sizeof(uint16_t) ); + break; + case VR::UT: + assert( 0 && "Should not happen" ); + break; + default: + assert( 0 && "Should not happen" ); + } + } + } + //else if( const SequenceOfItems *si = de.GetSequenceOfItems() ) + else if( si ) + { + //if( de.GetTag().IsPrivate() ) + { + //std::cerr << "ByteSwap SQ:" << de.GetTag() << std::endl; + SequenceOfItems::ConstIterator it2 = si->Begin(); + for( ; it2 != si->End(); ++it2) + { + const Item &item = *it2; + DataSet &ds = const_cast(item.GetNestedDataSet()); // FIXME + ByteSwapFilter bsf(ds); + bsf.ByteSwap(); + } + } + } + else if( const SequenceOfFragments *sf = de.GetSequenceOfFragments() ) + { + (void)sf; + assert( 0 && "Should not happen" ); + } + else + { + assert( 0 && "error" ); + } + + } + if( ByteSwapTag ) + { + DataSet copy; + DataSet::ConstIterator it = DS.Begin(); + for( ; it != DS.End(); ++it) + { + DataElement de = *it; + const Tag& tag = de.GetTag(); + de.SetTag( + Tag( SwapperDoOp::Swap( tag.GetGroup() ), SwapperDoOp::Swap( tag.GetElement() ) ) ); + copy.Insert( de ); + DS.Remove( de.GetTag() ); + } + DS = copy; + } + + return true; +} + +} diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmByteSwapFilter.h b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmByteSwapFilter.h new file mode 100644 index 0000000..bc650c0 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmByteSwapFilter.h @@ -0,0 +1,45 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMBYTESWAPFILTER_H +#define GDCMBYTESWAPFILTER_H + +#include "gdcmDataSet.h" + +namespace gdcm +{ + +/** + * \brief ByteSwapFilter + * In place byte-swapping of a dataset + * FIXME: FL status ?? + */ +class GDCM_EXPORT ByteSwapFilter +{ +public: + ByteSwapFilter(DataSet& ds):DS(ds),ByteSwapTag(false) {} + ~ByteSwapFilter(); + + bool ByteSwap(); + void SetByteSwapTag(bool b) { ByteSwapTag = b; } + +private: + DataSet &DS; + bool ByteSwapTag; + + ByteSwapFilter& operator=(const ByteSwapFilter &); +}; + +} // end namespace gdcm + +#endif //GDCMBYTESWAPFILTER_H diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmByteValue.cxx b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmByteValue.cxx new file mode 100644 index 0000000..c503884 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmByteValue.cxx @@ -0,0 +1,290 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmByteValue.h" + +#include // req C++11 +#include // memcpy + +namespace gdcm +{ + + void ByteValue::PrintASCII(std::ostream &os, VL maxlength ) const { + VL length = std::min(maxlength, Length); + // Special case for VR::UI, do not print the trailing \0 + if( length && length == Length ) + { + if( Internal[length-1] == 0 ) + { + length = length - 1; + } + } + // I cannot check IsPrintable some file contains \2 or \0 in a VR::LO element + // See: acr_image_with_non_printable_in_0051_1010.acr + //assert( IsPrintable(length) ); + std::vector::const_iterator it = Internal.begin(); + for(; it != Internal.begin()+length; ++it) + { + const char &c = *it; + if ( !( isprint((unsigned char)c) || isspace((unsigned char)c) ) ) os << "."; + else os << c; + } + } + void ByteValue::PrintHex(std::ostream &os, VL maxlength ) const { + VL length = std::min(maxlength, Length); + // WARNING: Internal.end() != Internal.begin()+Length + std::vector::const_iterator it = Internal.begin(); + os << std::hex; + for(; it != Internal.begin()+length; ++it) + { + //const char &c = *it; + uint8_t v = *it; + if( it != Internal.begin() ) os << "\\"; + os << std::setw( 2 ) << std::setfill( '0' ) << (uint16_t)v; + //++it; + //os << std::setw( 1 ) << std::setfill( '0' ) << (int)*it; + } + os << std::dec; + } + + bool ByteValue::GetBuffer(char *buffer, unsigned long length) const { + // SIEMENS_GBS_III-16-ACR_NEMA_1.acr has a weird pixel length + // so we need an inequality + if( length <= Internal.size() ) + { + memcpy(buffer, &Internal[0], length); + return true; + } + gdcmDebugMacro( "Could not handle length= " << length ); + return false; + } + + void ByteValue::PrintPNXML(std::ostream &os) const + { + /* + PersonName = element PersonName { + Number, + element SingleByte { NameComponents }?, + element Ideographic { NameComponents }?, + element Phonetic { NameComponents }? + } + + NameComponents = + element FamilyName {xsd:string}?, + element GivenName {xsd:string}?, + element MiddleName {xsd:string}?, + element NamePrefix {xsd:string}?, + element NameSuffix {xsd:string}? + */ + int count1 , count2; + count1=count2=1; + os << "\n" ; + os << "\n " ; + std::vector::const_iterator it = Internal.begin(); + for(; it != (Internal.begin() + Length); ++it) + { + const char &c = *it; + if ( c == '^' ) + { + if(count2==1) + { + os << "\n"; + os << " "; + count2++; + } + if(count2==2) + { + os << "\n"; + os << " "; + count2++; + } + else if(count2==3) + { + os << "\n"; + os << " "; + count2++; + } + else if(count2==4) + { + os << "\n"; + os << " "; + count2++; + } + else + { + //in the rare case there are more ^ characters + assert("Name components exceeded"); + } + } + else if ( c == '=' ) + { + if(count2==1) + { + os << "\n"; + } + if(count2==2) + { + os << "\n"; + } + else if(count2==3) + { + os << "\n"; + } + else if(count2==4) + { + os << "\n"; + } + else if(count2==5) + { + os << "\n"; + } + /*----------------------------------------------------------------*/ + if(count1==1) + { + os << "\n"; + os << " \n "; + count1++; + } + else if(count1==2) + { + os << "\n"; + os << " \n "; + count1++; + } + else if(count1==3) + { + os << " \n \n"; + count1++; + } + else + { + assert("Impossible - only 3 names allowed"); + } + count2=1; + } + else if ( !( isprint((unsigned char)c) ) ) + os << "."; + else if(c == '&') + os << "&"; + else if(c == '<') + os << "<"; + else if(c == '>') + os << ">"; + else if(c == '\'') + os << "'"; + else if(c == '\"') + os << """; + else + os << c; + } + if(count2==1) + { + os << "\n"; + } + if(count2==2) + { + os << "\n"; + } + else if(count2==3) + { + os << "\n"; + } + else if(count2==4) + { + os << "\n"; + } + else if(count2==5) + { + os << "\n"; + } + if(count1==1) + { + os << "\n"; + } + else if(count1==2) + { + os << "\n"; + } + else if(count1==3) + { + os << "\n"; + } + os << ""; + } + + void ByteValue::PrintASCIIXML(std::ostream &os) const + { + //VL length = std::min(maxlength, Length); + // Special case for VR::UI, do not print the trailing \0 + + /*if(Length && Internal[Length-1] == 0 ) + { + Length = Length - 1; + } + */ + // Check for non printable characters + + int count = 1; + os << ""; + std::vector::const_iterator it = Internal.begin(); + + for(; it != (Internal.begin() + Length); ++it) + { + const char &c = *it; + if ( c == '\\' ) + { + count++; + os << "\n"; + os << ""; + } + else if ( !c ) + { + // \0 is found ... + } + else if(c == '&') + os << "&"; + else if(c == '<') + os << "<"; + else if(c == '>') + os << ">"; + else if(c == '\'') + os << "'"; + else if(c == '\"') + os << """; + else + os << c; + } + os << "\n"; + } + + void ByteValue::PrintHexXML(std::ostream &os ) const + { + //VL length = std::min(maxlength, Length); + // WARNING: Internal.end() != Internal.begin()+Length + + std::vector::const_iterator it = Internal.begin(); + os << std::hex; + for(; it != Internal.begin() + Length; ++it) + { + //const char &c = *it; + uint8_t v = *it; + if( it != Internal.begin() ) os << "\\"; + os << std::setw( 2 ) << std::setfill( '0' ) << (uint16_t)v; + //++it; + //os << std::setw( 1 ) << std::setfill( '0' ) << (int)*it; + } + os << std::dec; + } + + +} diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmByteValue.h b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmByteValue.h new file mode 100644 index 0000000..6340f2b --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmByteValue.h @@ -0,0 +1,271 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMBYTEVALUE_H +#define GDCMBYTEVALUE_H + +#include "gdcmValue.h" +#include "gdcmTrace.h" +#include "gdcmVL.h" + +#include +#include +#include + +//#include // abort + +namespace gdcm +{ +/** + * \brief Class to represent binary value (array of bytes) + * \note + */ +class GDCM_EXPORT ByteValue : public Value +{ +public: + ByteValue(const char* array = 0, VL const &vl = 0): + Internal(array, array+vl),Length(vl) { + if( vl.IsOdd() ) + { + gdcmDebugMacro( "Odd length" ); + Internal.resize(vl+1); + Length++; + } + } + + /// \warning casting to uint32_t + ByteValue(std::vector &v):Internal(v),Length((uint32_t)v.size()) {} + //ByteValue(std::ostringstream const &os) { + // (void)os; + // assert(0); // TODO + //} + ~ByteValue() { + Internal.clear(); + } + + // When 'dumping' dicom file we still have some information from + // Either the VR: eg LO (private tag) + void PrintASCII(std::ostream &os, VL maxlength ) const; + + void PrintHex(std::ostream &os, VL maxlength) const; + + // Either from Element Number (== 0x0000) + void PrintGroupLength(std::ostream &os) { + assert( Length == 2 ); + (void)os; + } + + bool IsEmpty() const { +#if 0 + if( Internal.empty() ) assert( Length == 0 ); + return Internal.empty(); +#else + return Length == 0; +#endif + } + VL GetLength() const { return Length; } + + VL ComputeLength() const { return Length + Length % 2; } + // Does a reallocation + void SetLength(VL vl) { + VL l(vl); +#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + // CompressedLossy.dcm + if( l.IsUndefined() ) throw Exception( "Impossible" ); + if ( l.IsOdd() ) { + gdcmDebugMacro( + "BUGGY HEADER: Your dicom contain odd length value field." ); + ++l; + } +#else + assert( !l.IsUndefined() && !l.IsOdd() ); +#endif + // I cannot use reserve for now. I need to implement: + // STL - vector<> and istream + // http://groups.google.com/group/comp.lang.c++/msg/37ec052ed8283e74 +//#define SHORT_READ_HACK + try + { +#ifdef SHORT_READ_HACK + if( l <= 0xff ) +#endif + Internal.resize(l); + //Internal.reserve(l); + } + catch(...) + { + //throw Exception("Impossible to allocate: " << l << " bytes." ); + throw Exception("Impossible to allocate" ); + } + // Keep the exact length + Length = vl; + } + + operator const std::vector& () const { return Internal; } + + ByteValue &operator=(const ByteValue &val) { + Internal = val.Internal; + Length = val.Length; + return *this; + } + + bool operator==(const ByteValue &val) const { + if( Length != val.Length ) + return false; + if( Internal == val.Internal ) + return true; + return false; + } + bool operator==(const Value &val) const + { + const ByteValue &bv = dynamic_cast(val); + return Length == bv.Length && Internal == bv.Internal; + } + + + void Clear() { + Internal.clear(); + } + // Use that only if you understand what you are doing + const char *GetPointer() const { + if(!Internal.empty()) return &Internal[0]; + return 0; + } + void Fill(char c) { + //if( Internal.empty() ) return; + std::vector::iterator it = Internal.begin(); + for(; it != Internal.end(); ++it) *it = c; + } + bool GetBuffer(char *buffer, unsigned long length) const; + bool WriteBuffer(std::ostream &os) const { + if( Length ) { + //assert( Internal.size() <= Length ); + assert( !(Internal.size() % 2) ); + os.write(&Internal[0], Internal.size() ); + } + return true; + } + + template + std::istream &Read(std::istream &is, bool readvalues = true) { + // If Length is odd we have detected that in SetLength + // and calling std::vector::resize make sure to allocate *AND* + // initialize values to 0 so we are sure to have a \0 at the end + // even in this case + if(Length) + { + if( readvalues ) + { + is.read(&Internal[0], Length); + assert( Internal.size() == Length || Internal.size() == Length + 1 ); + TSwap::SwapArray((TType*)&Internal[0], Internal.size() / sizeof(TType) ); + } + else + { + is.seekg(Length, std::ios::cur); + } + } + return is; + } + + template + std::istream &Read(std::istream &is) { + return Read(is); + } + + + template + std::ostream const &Write(std::ostream &os) const { + assert( !(Internal.size() % 2) ); + if( !Internal.empty() ) { + //os.write(&Internal[0], Internal.size()); + std::vector copy = Internal; + TSwap::SwapArray((TType*)©[0], Internal.size() / sizeof(TType) ); + os.write(©[0], copy.size()); + } + return os; + } + + template + std::ostream const &Write(std::ostream &os) const { + return Write(os); + } + + /** + * \brief Checks whether a 'ByteValue' is printable or not (in order + * to avoid corrupting the terminal of invocation when printing) + * I don't think this function is working since it does not handle + * UNICODE or character set... + */ + bool IsPrintable(VL length) const { + assert( length <= Length ); + for(unsigned int i=0; i::size_type length = Length; + if( Internal.back() == 0 ) --length; + std::copy(Internal.begin(), Internal.begin()+length, + std::ostream_iterator(os)); + } + else + os << "Loaded:" << Internal.size(); + } + else + { + //os << "Not Loaded"; + os << "(no value available)"; + } + } +/* +//Introduce check for invalid XML characters +friend std::ostream& operator<<(std::ostream &os,const char c); +*/ + + void SetLengthOnly(VL vl) { + Length = vl; + } + +private: + std::vector Internal; + + // WARNING Length IS NOT Internal.size() some *featured* DICOM + // implementation define odd length, we always load them as even number + // of byte, so we need to keep the right Length + VL Length; +}; + +} // end namespace gdcm + +#endif //GDCMBYTEVALUE_H diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmCP246ExplicitDataElement.cxx b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmCP246ExplicitDataElement.cxx new file mode 100644 index 0000000..c4d8be6 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmCP246ExplicitDataElement.cxx @@ -0,0 +1,57 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmCP246ExplicitDataElement.h" +#include "gdcmSequenceOfItems.h" +#include "gdcmSequenceOfFragments.h" + +namespace gdcm +{ + +//----------------------------------------------------------------------------- + +VL CP246ExplicitDataElement::GetLength() const +{ + if( ValueLengthField.IsUndefined() ) + { + assert( ValueField->GetLength().IsUndefined() ); + Value *p = ValueField; + // If this is a SQ we need to compute it's proper length + SequenceOfItems *sq = dynamic_cast(p); + // TODO can factor the code: + if( sq ) + { + return TagField.GetLength() + VRField.GetLength() + + ValueLengthField.GetLength() + sq->ComputeLength(); + } + SequenceOfFragments *sf = dynamic_cast(p); + if( sf ) + { + assert( VRField & VR::OB_OW ); + return TagField.GetLength() + VRField.GetLength() + + ValueLengthField.GetLength() + sf->ComputeLength(); + } + assert(0); + return 0; + } + else + { + // Each time VR::GetLength() is 2 then Value Length is coded in 2 + // 4 then Value Length is coded in 4 + assert( !ValueField || ValueField->GetLength() == ValueLengthField ); + return TagField.GetLength() + 2*VRField.GetLength() + ValueLengthField; + } +} + + +} // end namespace gdcm diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmCP246ExplicitDataElement.h b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmCP246ExplicitDataElement.h new file mode 100644 index 0000000..340fc3f --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmCP246ExplicitDataElement.h @@ -0,0 +1,53 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMCP246EXPLICITDATAELEMENT_H +#define GDCMCP246EXPLICITDATAELEMENT_H + +#include "gdcmDataElement.h" + +namespace gdcm +{ +// Data Element (CP246Explicit) +/** + * \brief Class to read/write a DataElement as CP246Explicit Data Element + * \note Some system are producing SQ, declare them as UN, but encode the SQ as 'Explicit' + * instead of Implicit + */ +class GDCM_EXPORT CP246ExplicitDataElement : public DataElement +{ +public: + VL GetLength() const; + + template + std::istream &Read(std::istream &is); + + template + std::istream &ReadPreValue(std::istream &is); + + template + std::istream &ReadValue(std::istream &is, bool readvalues = true); + + template + std::istream &ReadWithLength(std::istream &is, VL & length); + + // PURPOSELY do not provide an implementation for writing ! + //template + //const std::ostream &Write(std::ostream &os) const; +}; + +} // end namespace gdcm + +#include "gdcmCP246ExplicitDataElement.txx" + +#endif //GDCMCP246EXPLICITDATAELEMENT_H diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmCP246ExplicitDataElement.txx b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmCP246ExplicitDataElement.txx new file mode 100644 index 0000000..b03ae7e --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmCP246ExplicitDataElement.txx @@ -0,0 +1,231 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#ifndef GDCMCP246EXPLICITDATAELEMENT_TXX +#define GDCMCP246EXPLICITDATAELEMENT_TXX + +#include "gdcmSequenceOfItems.h" +#include "gdcmSequenceOfFragments.h" +#include "gdcmVL.h" +#include "gdcmParseException.h" +#include "gdcmImplicitDataElement.h" + +#include "gdcmValueIO.h" +#include "gdcmSwapper.h" + +namespace gdcm +{ +//----------------------------------------------------------------------------- +template +std::istream &CP246ExplicitDataElement::Read(std::istream &is) +{ + ReadPreValue(is); + return ReadValue(is); +} +//----------------------------------------------------------------------------- +template +std::istream &CP246ExplicitDataElement::ReadPreValue(std::istream &is) +{ + TagField.Read(is); + // See PS 3.5, Data Element Structure With CP246Explicit VR + // Read Tag + if( !is ) + { + if( !is.eof() ) // FIXME This should not be needed + { + assert(0 && "Should not happen" ); + } + return is; + } + assert( TagField != Tag(0xfffe,0xe0dd) ); + const Tag itemDelItem(0xfffe,0xe00d); + if( TagField == itemDelItem ) + { + if( !ValueLengthField.Read(is) ) + { + assert(0 && "Should not happen"); + return is; + } + if( ValueLengthField != 0 ) + { + gdcmDebugMacro( + "Item Delimitation Item has a length different from 0" ); + } + // Set pointer to NULL to avoid user error + ValueField = 0; + return is; + } + + // Read VR + try + { + if( !VRField.Read(is) ) + { + assert(0 && "Should not happen" ); + return is; + } + } + catch( std::exception & ) + { + // gdcm-MR-PHILIPS-16-Multi-Seq.dcm + // assert( TagField == Tag(0xfffe, 0xe000) ); + // -> For some reason VR is written as {44,0} well I guess this is a VR... + // Technically there is a second bug, dcmtk assume other things when reading this tag, + // so I need to change this tag too, if I ever want dcmtk to read this file. oh well + // 0019004_Baseline_IMG1.dcm + // -> VR is garbage also... + // assert( TagField == Tag(8348,0339) || TagField == Tag(b5e8,0338)) + gdcmWarningMacro( "Assuming 16 bits VR for Tag=" << + TagField << " in order to read a buggy DICOM file." ); + VRField = VR::INVALID; + } + // Read Value Length + if( VR::GetLength(VRField) == 4 ) + { + if( !ValueLengthField.Read(is) ) + { + assert(0 && "Should not happen"); + return is; + } + } + else + { + // 16bits only + if( !ValueLengthField.template Read16(is) ) + { + //gdcmAssertAlwaysMacro(0 && "Should not happen"); + // The following is occurs with gdcm 2.0.17 when two + // seq del item marker are found + // See UnexpectedSequenceDelimiterInFixedLengthSequence.dcm + throw Exception("Should not happen CP246"); + return is; + } + } + return is; +} +//----------------------------------------------------------------------------- +template +std::istream &CP246ExplicitDataElement::ReadValue(std::istream &is, bool readvalues) +{ + if( is.eof() ) return is; + if( ValueLengthField == 0 ) + { + // Simple fast path + ValueField = 0; + return is; + } + + //std::cerr << "exp cur tag=" << TagField << " VR=" << VRField << " VL=" << ValueLengthField << std::endl; + // Read the Value + //assert( ValueField == 0 ); + if( VRField == VR::SQ ) + { + // Check wether or not this is an undefined length sequence + assert( TagField != Tag(0x7fe0,0x0010) ); + ValueField = new SequenceOfItems; + } + else if( ValueLengthField.IsUndefined() ) + { + if( VRField == VR::UN ) + { + // Support cp246 conforming file: + // Enhanced_MR_Image_Storage_PixelSpacingNotIn_0028_0030.dcm (illegal) + // vs + // undefined_length_un_vr.dcm + assert( TagField != Tag(0x7fe0,0x0010) ); + ValueField = new SequenceOfItems; + ValueField->SetLength(ValueLengthField); // perform realloc + try + { + if( !ValueIO::Read(is,*ValueField,readvalues) ) // non cp246 + { + assert(0); + } + } + catch( std::exception &) + { + // Must be one of those non-cp246 file... + // but for some reason seekg back to previous offset + Read + // as CP246Explicit does not work... + ParseException pe; + pe.SetLastElement(*this); + throw pe; + } + return is; + } + else + { + // Ok this is Pixel Data fragmented... + assert( TagField == Tag(0x7fe0,0x0010) ); + assert( VRField & VR::OB_OW ); + ValueField = new SequenceOfFragments; + } + } + else + { + //assert( TagField != Tag(0x7fe0,0x0010) ); + ValueField = new ByteValue; + } + // We have the length we should be able to read the value + ValueField->SetLength(ValueLengthField); // perform realloc +#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + if( TagField == Tag(0x2001,0xe05f) + || TagField == Tag(0x2001,0xe100) + || TagField == Tag(0x2005,0xe080) + || TagField == Tag(0x2005,0xe083) + || TagField == Tag(0x2005,0xe084) + //TagField.IsPrivate() && VRField == VR::SQ + //-> Does not work for 0029 + //we really need to read item marker + ) + { + gdcmWarningMacro( "ByteSwaping Private SQ: " << TagField ); + assert( VRField == VR::SQ ); + try + { + if( !ValueIO::Read(is,*ValueField,readvalues) ) + { + assert(0 && "Should not happen"); + } + } + catch( std::exception & ) + { + ValueLengthField = ValueField->GetLength(); + } + return is; + } +#endif + //if( !ValueField->Read(is) ) + if( !ValueIO::Read(is,*ValueField,readvalues) ) + { + // Might be the famous UN 16bits + ParseException pe; + pe.SetLastElement( *this ); + throw pe; + return is; + } + + return is; +} + +template +std::istream &CP246ExplicitDataElement::ReadWithLength(std::istream &is, VL & length) +{ + return Read(is); (void)length; +} + + +} // end namespace gdcm + +#endif // GDCMCP246EXPLICITDATAELEMENT_TXX diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmCSAElement.h b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmCSAElement.h new file mode 100644 index 0000000..6885e2d --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmCSAElement.h @@ -0,0 +1,173 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMCSAELEMENT_H +#define GDCMCSAELEMENT_H + +#include "gdcmTag.h" +#include "gdcmVM.h" +#include "gdcmVR.h" +#include "gdcmByteValue.h" +#include "gdcmSmartPointer.h" + +namespace gdcm +{ +/** + * \brief Class to represent a CSA Element + * \see CSAHeader + */ +class GDCM_EXPORT CSAElement +{ +public: + CSAElement(unsigned int kf = 0):KeyField(kf) {} + + friend std::ostream& operator<<(std::ostream &os, const CSAElement &val); + + /// Set/Get Key + unsigned int GetKey() const { return KeyField; } + void SetKey(unsigned int key) { KeyField = key; } + + /// Set/Get Name + const char *GetName() const { return NameField.c_str(); } + void SetName(const char *name) { NameField = name; } + + /// Set/Get VM + const VM& GetVM() const { return ValueMultiplicityField; } + void SetVM(const VM &vm) { ValueMultiplicityField = vm; } + + /// Set/Get VR + VR const &GetVR() const { return VRField; } + void SetVR(VR const &vr) { VRField = vr; } + + /// Set/Get SyngoDT + unsigned int GetSyngoDT() const { return SyngoDTField; } + void SetSyngoDT(unsigned int syngodt) { SyngoDTField = syngodt; } + + /// Set/Get NoOfItems + unsigned int GetNoOfItems() const { return NoOfItemsField; } + void SetNoOfItems(unsigned int items) { NoOfItemsField = items; } + + /// Set/Get Value (bytes array, SQ of items, SQ of fragments): + Value const &GetValue() const { return *DataField; } + Value &GetValue() { return *DataField; } + void SetValue(Value const & vl) { + //assert( DataField == 0 ); + DataField = vl; + } + /// Check if CSA Element is empty + bool IsEmpty() const { return DataField == 0; } + + /// Set + void SetByteValue(const char *array, VL length) + { + ByteValue *bv = new ByteValue(array,length); + SetValue( *bv ); + } + /// Return the Value of CSAElement as a ByteValue (if possible) + /// \warning: You need to check for NULL return value + const ByteValue* GetByteValue() const { + // Get the raw pointer from the gdcm::SmartPointer + const ByteValue *bv = dynamic_cast(DataField.GetPointer()); + return bv; // Will return NULL if not ByteValue + } + + CSAElement(const CSAElement &_val) + { + if( this != &_val) + { + *this = _val; + } + } + + bool operator<(const CSAElement &de) const + { + return GetKey() < de.GetKey(); + } + CSAElement &operator=(const CSAElement &de) + { + KeyField = de.KeyField; + NameField = de.NameField; + ValueMultiplicityField = de.ValueMultiplicityField; + VRField = de.VRField; + SyngoDTField = de.SyngoDTField; + NoOfItemsField = de.NoOfItemsField; + DataField = de.DataField; // Pointer copy + return *this; + } + + bool operator==(const CSAElement &de) const + { + return KeyField == de.KeyField + && NameField == de.NameField + && ValueMultiplicityField == de.ValueMultiplicityField + && VRField == de.VRField + && SyngoDTField == de.SyngoDTField + //&& ValueField == de.ValueField; + ; + } + +protected: + unsigned int KeyField; + std::string NameField; + VM ValueMultiplicityField; + VR VRField; + unsigned int SyngoDTField; + unsigned int NoOfItemsField; + typedef SmartPointer DataPtr; + DataPtr DataField; +}; +//----------------------------------------------------------------------------- +inline std::ostream& operator<<(std::ostream &os, const CSAElement &val) +{ + os << val.KeyField; + os << " - '" << val.NameField; + os << "' VM " << val.ValueMultiplicityField; + os << ", VR " << val.VRField; + os << ", SyngoDT " << val.SyngoDTField; + os << ", NoOfItems " << val.NoOfItemsField; + os << ", Data "; + if( val.DataField ) + { + //val.DataField->Print( os << "'" ); + const ByteValue * bv = dynamic_cast(&*val.DataField); + assert( bv ); + const char * p = bv->GetPointer(); + std::string str(p, p + bv->GetLength() ); + if( val.ValueMultiplicityField == VM::VM1 ) + { + os << "'" << str.c_str() << "'"; + } + else + { + std::istringstream is( str ); + std::string s; + bool sep = false; + while( std::getline(is, s, '\\' ) ) + { + if( sep ) + { + os << '\\'; + } + sep = true; + os << "'" << s.c_str() << "'"; + } + //bv->Print( os << "'" ); + //os << "'"; + } + } + return os; +} + +} // end namespace gdcm + +#endif //GDCMCSAELEMENT_H diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmCSAHeader.cxx b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmCSAHeader.cxx new file mode 100644 index 0000000..c412bcc --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmCSAHeader.cxx @@ -0,0 +1,1253 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmCSAHeader.h" +#include "gdcmPrivateTag.h" +#include "gdcmDataElement.h" +#include "gdcmCSAElement.h" +#include "gdcmDataSet.h" +#include "gdcmExplicitDataElement.h" +#include "gdcmSwapper.h" + +namespace gdcm +{ +CSAElement CSAHeader::CSAEEnd = CSAElement((unsigned int)-1); + + const CSAElement& CSAHeader::GetCSAEEnd() const + { + return CSAEEnd; + } + + +/* + * (0029,1110) OB 53\54\45\50\3b\0a... # 5342,1 MedCom OOG Info + * -> MEDCOM Object Oriented Graphics (OOG) data. + * I think this is the STEP-File, aka ISO standard (10303) + * http://sourceforge.net/projects/stepmod + * + * $ ./bin/gdcmraw -i MR-SIEMENS-DICOM-WithOverlays.dcm -t 0029,1110 -o 0029_1110.raw + * $ gvim 0029_1110.raw +STEP; +HEADER; + FILE_IDENTIFICATION( + '', + 'Wed Nov 30 15:11:24 2005', + ('meduser'), + (''), + '1.0', + '1.0', + 'Exchangeboard'); + FILE_DESCRIPTION('STEP format'); + IMP_LEVEL('1.0'); +ENDSEC; +DATA; +@329 = CsaGraDoubleVec3DArray(0, ()); +@331 = CsaGraDoubleVec3DArray(0, (69.0, 246.0, 0.0, 67.0, 245.0, 0.0, 66.0, 244.0, 0.0, 64.0, 244.0, 0.0, 62.0, 243.0, 0.0, 61.0, 243.0, 0.0, 59.0, 243.0, 0.0, 57.0, 243.0, 0.0, 56.0, 243.0, 0.0, 55.0, 243.0, 0.0, 53.0, 243.0, 0.0, 52.0, 243.0, 0.0, 51.0, 243.0, 0.0, 50.0, 243.0, 0.0, 49.0, 243.0, 0.0, 48.0, 243.0, 0.0, 48.0, 244.0, 0.0, 47.0, 244.0, 0.0, 46.0, 245.0, 0.0, 46.0, 247.0, 0.0, 46.0, 248.0, 0.0, 46.0, 249.0, 0.0, 46.0, 250.0, 0.0, 46.0, 251.0, 0.0, 46.0, 252.0, 0.0, 46.0, 253.0, 0.0, 46.0, 255.0, 0.0, 46.0, 257.0, 0.0, 47.0, 258.0, 0.0, 47.0, 259.0, 0.0, 48.0, 261.0, 0.0, 49.0, 261.0, 0.0, 50.0, 263.0, 0.0, 50.0, 264.0, 0.0, 51.0, 266.0, 0.0, 53.0, 267.0, 0.0, 54.0, 268.0, 0.0, 55.0, 270.0, 0.0, 56.0, 270.0, 0.0, 56.0, 271.0, 0.0, 57.0, 271.0, 0.0, 58.0, 271.0, 0.0, 59.0, 272.0, 0.0, 61.0, 272.0, 0.0, 62.0, 272.0, 0.0, 62.0, 273.0, 0.0, 63.0, 273.0, 0.0, 64.0, 273.0, 0.0, 65.0, 273.0, 0.0, 66.0, 273.0, 0.0, 67.0, 273.0, 0.0, 69.0, 273.0, 0.0, 69.0, 272.0, 0.0, 71.0, 271.0, 0.0, 72.0, 270.0, 0.0, 73.0, 269.0, 0.0, 73.0, 268.0, 0.0, 73.0, 267.0, 0.0, 74.0, 267.0, 0.0, 75.0, 266.0, 0.0, 75.0, 265.0, 0.0, 76.0, 265.0, 0.0, 77.0, 263.0, 0.0, 77.0, 261.0, 0.0, 78.0, 261.0, 0.0, 78.0, 259.0, 0.0, 78.0, 258.0, 0.0, 79.0, 257.0, 0.0, 79.0, 256.0, 0.0, 80.0, 256.0, 0.0, 80.0, 255.0, 0.0, 80.0, 254.0, 0.0, 80.0, 253.0, 0.0, 80.0, 252.0, 0.0, 80.0, 251.0, 0.0, 80.0, 250.0, 0.0, 79.0, 248.0, 0.0, 77.0, 247.0, 0.0, 77.0, 246.0, 0.0, 77.0, 245.0, 0.0, 77.0, 244.0, 0.0, 75.0, 244.0, 0.0, 75.0, 243.0, 0.0, 74.0, 242.0, 0.0, 73.0, 242.0, 0.0, 72.0, 241.0, 0.0, 71.0, 240.0, 0.0, 71.0, 239.0, 0.0, 70.0, 239.0, 0.0, 69.0, 239.0, 0.0, 68.0, 239.0, 0.0, 66.0, 239.0, 0.0, 64.0, 239.0, 0.0, 63.0, 239.0, 0.0, 64.0, 242.0, 0.0)); +@333 = CsaImageOverlay(0, (), (), '', 0, 0, 0, $, (), (), (), (), (), (#332), 0, 0, (), '', '', (), '', (), 0, 0, $, 0, 0.0, 0.0, (), '', 0, 0, 'CAP_3D_MEANING', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, ); +@332 = CsaGraphicPrimGroup(0, 0, 0, 0, 0.0, 0, #329, 1, 1, 0, 0, $, #333, $, $, $, (#330)); +@335 = CsaUVString(0, (67, 111, 110, 116, 111, 117, 114, 77, 97, 110, 105, 112, 49, 54, 56, 49, 55, 100, 101, 48, 45, 97, 50, 48, 102, 45, 52, 50, 102, 99, 45, 97, 102, 102, 49, 45, 48, 55, 99, 49, 99, 51, 54, 48, 57, 102, 56, 102, 0)); +@336 = CsaGraphicFrameApplContainer(0, (), 0); +@334 = CsaGraVVIDictionary(0, (#335), (#336), (-1, -1, -1, -1, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), (-1)); +@330 = CsaGraphicPolygon(0, 0, 0, 0, 0.0, 0, #331, 0, 1, 0, 0, #332, $, #334, $, $, 0, 63.0, 256.0, 0.0, 0, 0, 0, 0, 0, 65535, 1.0, 0.0, 1.0, 0.0, 0, 0.29899999999999999, 0.58699999999999997, 0.114, 0, 65535, 0.0, 0.0, 0.0, 0.0, 0, 0.29899999999999999, 0.58699999999999997, 0.114, 1, 0, '', 1, 0, 0, 0, 65535, 1.0, 1.0, 1.0, 0.0, 0, 0.29899999999999999, 0.58699999999999997, 0.114, 0, 65535, 0.0, 0.0, 0.0, 0.0, 0, 0.29899999999999999, 0.58699999999999997, 0.114, 2, $, $, 1); +@337 = CsaGraDoubleVec3DArray(0, ()); +@339 = CsaGraDoubleVec3DArray(0, (0.84375, 0.84375, 0.0)); +@341 = CsaImageOverlay(0, (), (), '', 0, 0, 0, $, (), (), (), (), (), (#340), 0, 0, (), '', '', (), '', (), 0, 0, $, 0, 0.0, 0.0, (), '', 0, 0, 'CAP_3D_MEANING', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, ); +@343 = CsaGraDoubleVec3DArray(0, (0.90234375, 0.29296875, 0.0)); +@345 = CsaUVString(0, (68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 77, 97, 110, 105, 112, 35, 51, 95, 48, 98, 51, 57, 97, 54, 98, 53, 51, 45, 56, 53, 97, 50, 45, 52, 54, 102, 48, 45, 56, 99, 49, 52, 45, 97, 55, 102, 48, 51, 99, 100, 48, 53, 51, 56, 99, 0)); +@346 = CsaGraphicFrameApplContainer(0, (), 0); +@344 = CsaGraVVIDictionary(0, (#345), (#346), (-1, -1, -1, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), (-1)); +@342 = CsaGraphicText(0, 0, 0, 0, 0.0, 0, #343, 4, 1, 1, 1, #340, $, #344, $, $, 0, 0.0, 0.0, 0.0, 0, 0, 0, 0, 65535, 1.0, 1.0, 1.0, 0.0, 0, 0.29899999999999999, 0.58699999999999997, 0.114, 0, 65535, 0.0, 0.0, 0.0, 0.0, 0, 0.29899999999999999, 0.58699999999999997, 0.114, (84, 114, 97, 0), 1, -1, 0, 100, -16, 0, 0, 0, 400, 0, 0, 0, 0, 3, 2, 1, 34, 77, 77, 105, 110, 99, 104, 111, 32, 102, 111, 114, 32, 83, 105, 101, 109, 101, 110, 115, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2); +@340 = CsaGraphicPrimGroup(0, 0, 0, 0, 0.0, 0, #337, 1, 1, 0, 0, $, #341, $, $, $, (#338, #342)); +@348 = CsaUVString(0, (79, 114, 105, 101, 110, 116, 73, 110, 100, 105, 35, 51, 95, 48, 56, 54, 97, 100, 54, 52, 102, 50, 45, 50, 56, 49, 55, 45, 52, 102, 102, 50, 45, 57, 56, 52, 100, 45, 55, 49, 49, 101, 54, 55, 99, 52, 48, 53, 56, 57, 0)); +@349 = CsaGraphicFrameApplContainer(0, (), 0); +@347 = CsaGraVVIDictionary(0, (#348), (#349), (-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1), (-1)); +@338 = CsaGraphicCube(0, 0, 0, 0, 0.0, 0, #339, 4, 1, 0, 0, #340, $, #347, $, $, 0, 0.84375, 0.84375, 0.0, 0, 0, 0, 0, 0, 65535, 1.0, 1.0, 0.0, 0.0, 0, 0.29899999999999999, 0.58699999999999997, 0.114, 0, 65535, 0.0, 0.0, 0.0, 0.0, 0, 0.29899999999999999, 0.58699999999999997, 0.114, 1, 0, '', 1, 0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.05859375); +ENDSEC; +ENDSTEP; +9 + */ + +/* + * http://www.enac.northwestern.edu/~tew/archives/2003/02/25/incomplete-dicom-headers/ + * http://www.nmr.mgh.harvard.edu/~rudolph/software/vox2ras/download/vox2ras_rsolve.m + * http://www.mail-archive.com/freesurfer@nmr.mgh.harvard.edu/msg03409.html + * + * Pretty good link: + * http://www.mmrrcc.upenn.edu/CAMRIS/cfn/dicomhdr.html + */ + +/* + * SIEMENS-JPEG-CorruptFragClean.dcm (0029,xx10): + * (0000,0005) FD (??) 337.625 # 8,? (1) + * (0000,0006) FD (??) 4.665 # 8,? (1) + * (0000,0007) SL (??) 955 # 4,? (1) + * (0000,0008) SL (??) 200 # 4,? (1) + * (0000,000c) FD (??) 4 # 8,? (1) + * (0000,000d) SL (??) 2 # 4,? (1) + * (0000,0013) SL (??) 337 # 4,? (1) + * (0000,0014) SL (??) 0 # 4,? (1) + * (0000,0016) SL (??) 50 # 4,? (1) + * (0000,0018) SL (??) 672 # 4,? (1) + * (0000,001d) LT (??) [N.E.C.K] # 8,? (1) + * (0000,001e) FD (??) 160 # 8,? (1) + * (0000,001f) FD (??) 0 # 8,? (1) + * (0000,0020) FD (??) 3 # 8,? (1) + * (0000,0021) SL (??) 1 # 4,? (1) + * (0000,0022) SL (??) 11 # 4,? (1) + * (0000,0025) SL (??) 8 # 4,? (1) + * (0000,0027) FD (??) 60 # 8,? (1) + * (0000,0028) SL (??) 292 # 4,? (1) + * (0000,0029) SL (??) 0 # 4,? (1) + * (0000,002c) SL (??) 200 # 4,? (1) + * (0000,002d) SL (??) 0 # 4,? (1) + * (0000,002e) SL (??) 0 # 4,? (1) + * (0000,002f) FD (??) 1 # 8,? (1) + * (ffff,ffff) CS (??) [END! ] # 10,? (1) + */ + +/* + +Example of (29,10,SIEMENS CSA NON-IMAGE) / 0000,0a01 + +MlScanProtocol_Begin: 112 + +MlScanProtocolAttributes_Begin: 112 + +ActiveEntry: 0 +AEC_SlopeObese: 0.33 +AEC_SlopeSmall: 0.50 +AutoReferenceLinesMode: MlAutoReferenceLinesModeOff +BodySizeOld: MlAdult +BreathHold: 99.000 +BreathingDefault: 15.000 +Cardiac: 1 +CustomProtocol: 1 +Ident: 21003100 +Partial: 1 +PatientID: "4.0.201300074" +PatientName: "DQ" +PatientPosition: MlPositionUndefined +PreCond4Displ: 65535 +ProtocolName: "PETCT_DailyQC" +Region: MlPET +Service: 0 +StudyDescription: "PET^PETCT_DailyQC (Adult)" +StudyID: "4.0.311400557" +TotalmAs: 139 +TotalNoOfScans: 1 + +CursorPos: 0 + + +MlScanProtocolAttributes_End: 112 + +PROTOCOL_ENTRY_NO: 1 + +MlModeEntry_Begin: 112 + +MlModeEntryAttributes_Begin: 112 + +AutoRange: MlAutoRangeNone +EntrySelected: 1 +PatientPositionFoR: MlFaceUpHeadFirst +Visible: 1 +BodySize: MlAdult +ModeEntryUID: 3 + + +MlModeEntryAttributes_End: 112 + +MlModeScanNotNULL: + +MlModeScan_Begin: 112 + +CardioTriggerDelay: "" +Comment1: "" +Comment1Source: MlInherited +Comment2: "" +Comment2Source: MlInherited +ReconMode: MlReconSliceMode +SliceEffective: 5.00 +SliceEffectiveTiltCorrected: 5 +SlicesPerScan: 16 +SpiralPrePostRotation: 1.057 +AddScan: 0 +AEC_Aref: 600 +AEC_AttenuationDataAP: "" +AEC_AttenuationDataLat: "" +AEC_BeginPos: 68.000 +AEC_CurrentDOMmax: 0 +AEC_CurrentMean: 0 +AEC_CurrentProfileAP: "" +AEC_CurrentProfileLat: "" +AEC_DoseProfile: "" +AEC_EndPos: -127.000 +AEC_MDS: "" +AEC_PDS: "" +AEC_PDSMean: 0 +AEC_PositionExceed: 0 +AEC_PowerExceed: 0 +AEC_Range: -1.9697 +AEC_TopoExceed: 0 +AECDoseModulationType: MlAutomaticExposureControl +AECReferenceMAs: 20 +AngleType: MlTubePosLateral +ApiId: -1 +ASICCont1: 15 +ASICCont2: 135 +AssignmentTest: 0 +AutoFeed: 0 +AutoLoad: 0 +AutoTilt: 0 +AverageRawData: MlAverageRDOff +BaseReconRangeBegin: 71.500 +BaseReconRangeEnd: -184.500 +BeginPos: 71.500 +Biopsy: 0 +BodyRegion: MlBodyRegionBody +Breathing: 18.000 +Capacitor: MlCapacitorNotused +Cardio: 0 +CardioAverage: MlCardioAverageLast3 +CardioSyntheticTrigger: 0 +Care: MlOff +CareDoseType: MlCareDoseAEC +CareVisionTableMode: MlTableMoveContinuous +CareVisionTableStep: 2.5 +Clustered: 0 +ClusteredUsed: 0 +Contrast: 0 +CoolingTime: 0.000 +CTDIw: 7.8 +CTDIwEffective: 7.8 +Current: 250 +CurrentCorrection: 1.25 +CurrentEffective: 250 +CurrentPeak: 250 +CurrentStd: 200 +CustomMAs: 100 +CycleTime: 0.000 +CycleTimeMin: 0.000 +CycleTimeUser: 0.000 +DASCont1: 79 +DASCont2: 0 +DestinationRequestID: "ct48501---------------------20071113-071740-0021-1044D480-00000" +DiscCheckSource: MlDiscCheckNone +Displayed: 1 +DLPEffective: 157.56 +DoseModulationType: MlNoModulation +ECGPulsing: MlOff +EffectiveMAs: 100 +EndPos: -130.500 +FeedLastScan: 0.0 +FeedScan: 0.0 +Focus: MlSmallFocus +FrameOfReferenceUID: "1.3.12.2.1107.5.1.4.48501.30000007111306074039000000021" +FuseBolusModes: 0 +GantryRotating: 1 +HandCare: MlNone +InterPosHori: 71.500 +InterPosTilt: 0.0 +IrsAcceptsMissingTables: 0 +KeepFBAD: 0 +Kind: MlSpiral +mAs: 100 +MasterAdjustOrTestNumber: 0 +MasterAsymmetricStartAngle: 0 +MasterCombActive: 0 +MasterCompensatorActive: 1 +MasterDataTransfer: 1 +MasterDose: 1755 +MasterDoseAmplification: 0 +MasterDoseControl: 1 +MasterDynamicFocusDeflection: 0 +MasterFilament: 1 +MasterFilamentCurrent: 7016 +MasterFixedReadings: 0 +MasterFocusAmplitude: 0 +MasterFocusDelay: 0 +MasterFocusOffset: -7 +MasterGantryDisplay: 1 +MasterGantryRotation: 1 +MasterIgnoreTubeArcing: 1 +MasterIntegrationMode: 4 +MasterIntegrationTime: 431 +MasterITControl: 0 +MasterLateralPosition: 0 +MasterLightMarkerInScanExecute: 0 +MasterMoveAllowedInScanExecute: 0 +MasterPhiControl: 1 +MasterRotAnodeFrequency: 50 +MasterRotAnodeFrequencyChanged: 1 +MasterRotatingAnode: 1 +MasterSyntheticTrigger: 0 +MasterTestPattern: 0 +MasterTubeCollimatorMovement: 1 +MasterTubeCurrent: 199 +MasterTubeVoltage: 120000 +MasterUseNominalValues: 1 +MasterUseStartAngle: 0 +MasterXray: 1 +MasterZControl: 1 +MasterZControlDynamic: 0 +MBH: 0 +MultiScanTime: 1.000 +NoOfClustersPerRange: 1 +NoOfScans: 1 +NoOfScansDone: 0 +NoOfScansInLastCluster: 0 +NoOfScansPerCluster: 1 +NoOfSlicesAfterPrep: 16 +NoOfSlicesDetector: 16 +NoOfSlicesPrep: 16 +OfflineReconstruction: 1 +OrganCharacteristicOverride: MlOff +OrganCharacteristics: MlOrgCharThorax +Pitch: 20.0 +PitchFactor: 1.2500000 +PitchLowerLimit: 7.0 +PitchUpperLimit: 8.0 +Power: 30000 +PreLoad: 0 +ProcessSteps: 4294967295 +ProspectiveDoseSaving: 0 +RangeName: "CT" +RangeStart: MlRangeStartConsole +RawDataFile: "0001_RCT" +RawDataLoid: "4.0.311407191" +Readings: 15150 +ReconRangeBeginPos: 51.500 +ReconRangeBeginTime: 0.000 +ReconRangeEndPos: -110.500 +ReconRangeEndTime: 0.000 +ReconRangeFirstImageTime: "0" +ReconRangeLastImageTime: "0" +RevolAngle: 360 +RotKind: MlRotNormal +RotNum: 13.029 +RotTime: 0.500 +RPP: MlRpp1 +ScanLabel: "" +ScanNumber: 1 +ScanState: MlStateScanned +ScanTime: 6.530 +ScanTrigger: MlScanTriggerAuto +SequenceGap: 0.0 +SequenceReconRangeEndPos: 142.000 +SequenceRotTime: 0.500 +SequenceScanTime: 0.750 +Serio: 0 +SliceDetector: 0.75 +SliceGain: 0.000 +SlicePhysical: 0.75 +SliceSelect: 128 +SourceRequestID: "" +SpecialMeas: MlSpecialMeasNone +SpiralFeedRot: 15.0 +SpiralLength: 162.0 +SpiralReconRangeEndPos: -110.500 +SpiralRotTime: 0.500 +SpiralScanTime: 6.530 +StartAngleNumber: 90.0 +StartDelay: 4.000 +StartDelayCalc: 2.000 +StartDelayUser: 4.000 +StaticRotTime: 0.500 +StaticTime: 1.000 +TableDirection: MlIn +TableDirectionPatient: MlCraniocaudal +TiltPos: 0.0 +TopoLength: 0.0 +TopoLengthList: 512.0 +TopoLoid: "4.0.311400561" +TopoReconRangeEndPos: 142.000 +TopoScanTime: 0.000 +TubeCollimator: 5100 +TubeCollimatorClosed: 0 +TubeNotify: 0 +TubePosition: 0.0 +UHR: MlOff +UseAdjustAirCal: 0 +UseAdjustBeamHard: 0 +UseMasterGeneratorSettings: 0 +VertPos: 106.0 +VertPosValid: 1 +Voltage: 120.000 + + +MlModeScan_End: 112 + +First_MlModeRecon_Is_NULL: + +No_Of_Valid_Recons: 1 + +MlModeRecon_Begin: 112 + +CardioTriggerDelay: "" +Comment1: "" +Comment1Source: MlInherited +Comment2: "" +Comment2Source: MlInherited +ReconMode: MlReconSliceMode +SliceEffective: 5.00 +SliceEffectiveTiltCorrected: 5 +SlicesPerScan: 16 +SpiralPrePostRotation: 1.057 +AdaptFilter: 1 +Algorithm: MlSlim +AutoRecon: 0 +AutoReferenceLinesActive: MlOff +Balancing: 1 +BalancingSteps: 5 +BodyPartExamined: "CHEST" +CardioBiPhase: 1 +CardioListOfEditSyncs: "" +CardioListOfTimeStamps: "" +CardioMultiPhase: 0 +CardioMultiPhaseTriggerDelay: "" +CardioNoOfMultiPhase: 0 +CardioNoOfTimeStampLists: "0" +CardioReadyForRecon: 0 +CareViewHead: MlLeft +CenterX: 0 +CenterY: 0 +CrossSectionChanged: 0 +CTScale: MlCTScaleStandard +ExtendedFOV: 1 +FilmImageInterval: 1 +Filming: 0 +FirstReconSlice: 0 +FOV: 0 +FoVHorLength: 700 +FoVHorVec: 1.000;0.000;0.000 +FoVVertLength: 700 +FoVVertVec: 0.000;1.000;0.000 +FuseModesP30: 1 +ImaDisplay: 1 +ImageMatrix: 512 +ImageOrder: MlIO_Craniocaudal +ImageReconType: MlPrimary +ImaStore: 1 +IRSReconTime: 6.999 +Kernel: "B30f medium smooth" +MCA: 0 +Mirror: MlMirrorNone +ModeReconJMUID: "" +ModeReconUID: 4 +MPPSDescription: "" +MultiReconIncr: 1.000 +NonLinearLookUpTable: 0 +NoOfImages: 33 +NoOfImagesEntryDone: 0 +Obese: 1 +OnlineReconPossible: 1 +ORAFilter: 0 +OrganFoV: 380 +PFO: MlOff +PostProcessingCommand: "NON" +PostProcessingID: "Ml3DNone" +ReconBeginPos: 0.000 +ReconBeginTime: 0.000 +ReconBeginVec: 0.000;0.000;51.500 +ReconDirection: MlAxial +ReconEndPos: 0.000 +ReconEndTime: 0.000 +ReconEndVec: 0.000;0.000;-110.500 +ReconIncrementManualChange: MlUnchanged +ReconKind: MlMetroRecon +ReconLabel: "" +ReconPriority: 0 +ReconSelected: 1 +ReconState: MlReconStateActive +ReconStateJM: MlReconStateJMCreated +ReconstructionVolumeBeginVec: 0.000;0.000;0.000 +ReconstructionVolumeEndVec: 0.000;0.000;0.000 +ReconTaskNumber: 1 +ReconType: MlAxialRJ +ReferenceSeriesLoid: "" +Resolution: ResModeUltraFast +SeriesDescription: "CT 5.0 eFoV " +SeriesLoid: "" +SeriesLoidKind: MlSeriesNew +SpiralBaseFunction: MlSpiralBaseTrapezium06 +SpiralPrePostLengthCorrection: 0.000 +SpiralReconIncr: 5.000 +ToBeReconBeginPos: 0.000 +ToBeReconBeginTime: 0.000 +ToBeReconBeginVec: 0.000;0.000;51.500 +ToBeReconEndPos: 0.000 +ToBeReconEndTime: 0.000 +ToBeReconEndVec: 0.000;0.000;-110.500 +TopoZoom: 1 +Transfer: MlOff +Transfer1: "" +Transfer2: "" +Transfer3: "" +Ui3DViewCurrentPlanningVolumeLoid: "" +Ui3DViewCutlineDirectionVec: 0.000;0.000;0.000 +Ui3DViewFoVSegmentIndex: 0 +Ui3DViewPanX: 0.000;0.000;0.000 +Ui3DViewPanY: 0.000;0.000;0.000 +Ui3DViewPivotVec: 0.000;0.000;0.000 +Ui3DViewPVImageType: MlMPR +Ui3DViewTopographicsSegmentIndex: 0 +Ui3DViewTransformationVec1: 0.000;0.000;0.000 +Ui3DViewTransformationVec2: 0.000;0.000;0.000 +Ui3DViewWindowCenter1: 40.000;40.000;40.000 +Ui3DViewWindowCenter2: 40.000;40.000;40.000 +Ui3DViewWindowWidth1: 400.000;400.000;400.000 +Ui3DViewWindowWidth2: 400.000;400.000;400.000 +Ui3DViewZoomX: 1.000;1.000;1.000 +Ui3DViewZoomY: 1.000;1.000;1.000 +Viewing: MlOff +ViewingDirection: MlIO_Craniocaudal +Window[READ_ONLY]: "Mediastinum" +Window.ResID: 33 +Window1Center: 40 +Window1Width: 400 +Window2Center: -600 +Window2Width: 1200 +WindowImageLoid: "" + + +MlModeRecon_End: 112 + + +MlModeEntry_End: 112 + +MlScanProtocol_End: 112 + + + */ + +struct DataSetFormatEntry +{ + Tag t; + VR vr; +}; + +static DataSetFormatEntry DataSetFormatDict[] = { + { Tag(0x0000,0x0004),VR::LT }, + { Tag(0x0000,0x0005),VR::FD }, + { Tag(0x0000,0x0006),VR::FD }, + { Tag(0x0000,0x0007),VR::SL }, + { Tag(0x0000,0x0008),VR::SL }, + { Tag(0x0000,0x000c),VR::FD }, + { Tag(0x0000,0x000d),VR::SL }, + { Tag(0x0000,0x000e),VR::SL }, + { Tag(0x0000,0x0012),VR::FD }, + { Tag(0x0000,0x0013),VR::SL }, + { Tag(0x0000,0x0014),VR::SL }, + { Tag(0x0000,0x0016),VR::SL }, + { Tag(0x0000,0x0018),VR::SL }, + { Tag(0x0000,0x001a),VR::SL }, + { Tag(0x0000,0x001d),VR::LT }, // Defined Terms: [A.B.D.O.M.E.N], [C.H.E.S.T], [E.X.T.R.E.M.I.T.Y], [H.E.A.D], [N.E.C.K], [P.E.L.V.I.S], [S.P.I.N.E] + { Tag(0x0000,0x001e),VR::FD }, + { Tag(0x0000,0x001f),VR::FD }, + { Tag(0x0000,0x0020),VR::FD }, + { Tag(0x0000,0x0021),VR::SL }, + { Tag(0x0000,0x0022),VR::SL }, + { Tag(0x0000,0x0025),VR::SL }, + { Tag(0x0000,0x0026),VR::FD }, + { Tag(0x0000,0x0027),VR::FD }, + { Tag(0x0000,0x0028),VR::SL }, + { Tag(0x0000,0x0029),VR::SL }, + { Tag(0x0000,0x002b),VR::LT }, + { Tag(0x0000,0x002c),VR::SL }, + { Tag(0x0000,0x002d),VR::SL }, + { Tag(0x0000,0x002e),VR::SL }, + { Tag(0x0000,0x002f),VR::FD }, + { Tag(0x0000,0x0030),VR::LT }, + { Tag(0x0000,0x0033),VR::SL }, + { Tag(0x0000,0x0035),VR::SL }, + { Tag(0x0000,0x0036),VR::CS }, + { Tag(0x0000,0x0037),VR::SL }, + { Tag(0x0000,0x0038),VR::SL }, + { Tag(0x0000,0x0039),VR::SL }, + { Tag(0x0000,0x003a),VR::FD }, + { Tag(0x0000,0x003b),VR::SL }, + { Tag(0x0000,0x003c),VR::SL }, + { Tag(0x0000,0x003d),VR::FD }, + { Tag(0x0000,0x003e),VR::SL }, + { Tag(0x0000,0x003f),VR::SL }, + { Tag(0x0000,0x0101),VR::FD }, + { Tag(0x0000,0x0102),VR::FD }, + { Tag(0x0000,0x0103),VR::FD }, + { Tag(0x0000,0x0105),VR::IS }, + { Tag(0x0006,0x0006),VR::FD }, + { Tag(0x0006,0x0007),VR::FD }, + { Tag(0x0006,0x0008),VR::CS }, + { Tag(0x0006,0x000a),VR::LT }, + { Tag(0x0006,0x000b),VR::CS }, + { Tag(0x0006,0x000c),VR::FD }, + { Tag(0x0006,0x000e),VR::CS }, + { Tag(0x0006,0x000f),VR::SL }, + { Tag(0x0006,0x0024),VR::FD }, + { Tag(0xffff,0xffff),VR::CS }, // ENDS! +}; + +/* +Apparently tag <-> vr has no relation ... it must be derived from something else + +(0000,0003) FD 500 # 8, 1 RequestedSOPClassUID +(0000,0004) FD 1040 # 8, 1 Unknown Tag & Data +(0000,0005) FD 570 # 8, 1 Unknown Tag & Data +(0000,0008) LT [0] # 2, 1 Unknown Tag & Data +(0000,0010) DT [20071113071752.765000] # 22, 1 ACR_NEMA_CommandRecognitionCode +(0000,0020) SL 2 # 4, 1 Unknown Tag & Data +(0000,0025) FD (no value available) # 0, 0 Unknown Tag & Data +(0000,0026) FD 0.7 # 8, 1 Unknown Tag & Data +(0000,0028) ?? (no value available) # 0, 1 Unknown Tag & Data +(0000,0030) SL 30 # 4, 1 Unknown Tag & Data +(0000,0040) LT [C] # 4, 1 Unknown Tag & Data +(0000,0a01) ?? 4d\6c\53\63\61\6e\50\72\6f\74\6f\63\6f\6c\5f\42\65\67\69\6e\3a\09... # 8788, 1 Unknown Tag & Data +(0000,fe10) CS [SCANPROT] # 10, 1 Unknown Tag & Data +(ffff,ffff) CS [END!] # 10, 1 Unknown Tag & Data +*/ + +VR GetVRFromDataSetFormatDict( const Tag& t ) +{ + static const unsigned int nentries = sizeof(DataSetFormatDict) / sizeof(*DataSetFormatDict); + VR ret = VR::VR_END; + //static const Tag tend = Tag(0xffff,0xffff); + for( unsigned int i = 0; i < nentries; ++i) + { + const DataSetFormatEntry &entry = DataSetFormatDict[i]; + if( entry.t == t ) + { + ret = entry.vr; + break; + } + } + return ret; +} + +/* + * http://www.healthcare.siemens.com/magnetom/phoenix-gallery/orthopedics/images/phoenix/29642762.ima +Image shadow data (0029,xx10) + +0 - 'EchoLinePosition' VM 1, VR IS, SyngoDT 6, NoOfItems 6, Data '427 ' +1 - 'EchoColumnPosition' VM 1, VR IS, SyngoDT 6, NoOfItems 6, Data '224 ' +2 - 'EchoPartitionPosition' VM 1, VR IS, SyngoDT 6, NoOfItems 6, Data '8 ' +3 - 'UsedChannelMask' VM 1, VR UL, SyngoDT 9, NoOfItems 6, Data '63 ' +4 - 'Actual3DImaPartNumber' VM 1, VR IS, SyngoDT 6, NoOfItems 0, Data +5 - 'ICE_Dims' VM 1, VR LO, SyngoDT 19, NoOfItems 6, Data 'X_1_1_1_1_1_1_1_1_1_1_1_41' +6 - 'B_value' VM 1, VR IS, SyngoDT 6, NoOfItems 0, Data +7 - 'Filter1' VM 1, VR IS, SyngoDT 6, NoOfItems 0, Data +8 - 'Filter2' VM 1, VR IS, SyngoDT 6, NoOfItems 0, Data +9 - 'ProtocolSliceNumber' VM 1, VR IS, SyngoDT 6, NoOfItems 6, Data '6 ' +10 - 'RealDwellTime' VM 1, VR IS, SyngoDT 6, NoOfItems 6, Data '8600 ' +11 - 'PixelFile' VM 1, VR UN, SyngoDT 0, NoOfItems 0, Data +12 - 'PixelFileName' VM 1, VR UN, SyngoDT 0, NoOfItems 0, Data +13 - 'SliceMeasurementDuration' VM 1, VR DS, SyngoDT 3, NoOfItems 6, Data '338142.50000000' +14 - 'SequenceMask' VM 1, VR UL, SyngoDT 9, NoOfItems 6, Data '134217728' +15 - 'AcquisitionMatrixText' VM 1, VR SH, SyngoDT 22, NoOfItems 6, Data '421*448s' +16 - 'MeasuredFourierLines' VM 1, VR IS, SyngoDT 6, NoOfItems 6, Data '0 ' +17 - 'FlowEncodingDirection' VM 1, VR IS, SyngoDT 6, NoOfItems 0, Data +18 - 'FlowVenc' VM 1, VR FD, SyngoDT 4, NoOfItems 0, Data +19 - 'PhaseEncodingDirectionPositive' VM 1, VR IS, SyngoDT 6, NoOfItems 6, Data '1 ' +20 - 'NumberOfImagesInMosaic' VM 1, VR US, SyngoDT 10, NoOfItems 0, Data +21 - 'DiffusionGradientDirection' VM 3, VR FD, SyngoDT 4, NoOfItems 0, Data +22 - 'ImageGroup' VM 1, VR US, SyngoDT 10, NoOfItems 0, Data +23 - 'SliceNormalVector' VM 3, VR FD, SyngoDT 4, NoOfItems 0, Data +24 - 'DiffusionDirectionality' VM 1, VR CS, SyngoDT 16, NoOfItems 0, Data +25 - 'TimeAfterStart' VM 1, VR DS, SyngoDT 3, NoOfItems 6, Data '0.00000000' +26 - 'FlipAngle' VM 1, VR DS, SyngoDT 3, NoOfItems 0, Data +27 - 'SequenceName' VM 1, VR SH, SyngoDT 22, NoOfItems 0, Data +28 - 'RepetitionTime' VM 1, VR DS, SyngoDT 3, NoOfItems 0, Data +29 - 'EchoTime' VM 1, VR DS, SyngoDT 3, NoOfItems 0, Data +30 - 'NumberOfAverages' VM 1, VR DS, SyngoDT 3, NoOfItems 0, Data +31 - 'VoxelThickness' VM 1, VR DS, SyngoDT 3, NoOfItems 0, Data +32 - 'VoxelPhaseFOV' VM 1, VR DS, SyngoDT 3, NoOfItems 0, Data +33 - 'VoxelReadoutFOV' VM 1, VR DS, SyngoDT 3, NoOfItems 0, Data +34 - 'VoxelPositionSag' VM 1, VR DS, SyngoDT 3, NoOfItems 0, Data +35 - 'VoxelPositionCor' VM 1, VR DS, SyngoDT 3, NoOfItems 0, Data +36 - 'VoxelPositionTra' VM 1, VR DS, SyngoDT 3, NoOfItems 0, Data +37 - 'VoxelNormalSag' VM 1, VR DS, SyngoDT 3, NoOfItems 0, Data +38 - 'VoxelNormalCor' VM 1, VR DS, SyngoDT 3, NoOfItems 0, Data +39 - 'VoxelNormalTra' VM 1, VR DS, SyngoDT 3, NoOfItems 0, Data +40 - 'VoxelInPlaneRot' VM 1, VR DS, SyngoDT 3, NoOfItems 0, Data +41 - 'ImagePositionPatient' VM 3, VR DS, SyngoDT 3, NoOfItems 0, Data +42 - 'ImageOrientationPatient' VM 6, VR DS, SyngoDT 3, NoOfItems 0, Data +43 - 'PixelSpacing' VM 2, VR DS, SyngoDT 3, NoOfItems 0, Data +44 - 'SliceLocation' VM 1, VR DS, SyngoDT 3, NoOfItems 0, Data +45 - 'SliceThickness' VM 1, VR DS, SyngoDT 3, NoOfItems 0, Data +46 - 'SpectrumTextRegionLabel' VM 1, VR SH, SyngoDT 22, NoOfItems 0, Data +47 - 'Comp_Algorithm' VM 1, VR IS, SyngoDT 6, NoOfItems 0, Data +48 - 'Comp_Blended' VM 1, VR IS, SyngoDT 6, NoOfItems 0, Data +49 - 'Comp_ManualAdjusted' VM 1, VR IS, SyngoDT 6, NoOfItems 0, Data +50 - 'Comp_AutoParam' VM 1, VR LT, SyngoDT 20, NoOfItems 0, Data +51 - 'Comp_AdjustedParam' VM 1, VR LT, SyngoDT 20, NoOfItems 0, Data +52 - 'Comp_JobID' VM 1, VR LT, SyngoDT 20, NoOfItems 0, Data +53 - 'FMRIStimulInfo' VM 1, VR IS, SyngoDT 6, NoOfItems 0, Data +54 - 'FlowEncodingDirectionString' VM 1, VR SH, SyngoDT 22, NoOfItems 0, Data +55 - 'RepetitionTimeEffective' VM 1, VR DS, SyngoDT 3, NoOfItems 0, Data +56 - 'CsiImagePositionPatient' VM 3, VR DS, SyngoDT 3, NoOfItems 0, Data +57 - 'CsiImageOrientationPatient' VM 6, VR DS, SyngoDT 3, NoOfItems 0, Data +58 - 'CsiPixelSpacing' VM 2, VR DS, SyngoDT 3, NoOfItems 0, Data +59 - 'CsiSliceLocation' VM 1, VR DS, SyngoDT 3, NoOfItems 0, Data +60 - 'CsiSliceThickness' VM 1, VR DS, SyngoDT 3, NoOfItems 0, Data +61 - 'OriginalSeriesNumber' VM 1, VR IS, SyngoDT 6, NoOfItems 0, Data +62 - 'OriginalImageNumber' VM 1, VR IS, SyngoDT 6, NoOfItems 0, Data +63 - 'ImaAbsTablePosition' VM 3, VR SL, SyngoDT 7, NoOfItems 6, Data '0 '\'0 '\'-1952 ' +64 - 'NonPlanarImage' VM 1, VR US, SyngoDT 10, NoOfItems 6, Data '1 ' +65 - 'MoCoQMeasure' VM 1, VR US, SyngoDT 10, NoOfItems 0, Data +66 - 'LQAlgorithm' VM 1, VR SH, SyngoDT 22, NoOfItems 0, Data +67 - 'SlicePosition_PCS' VM 3, VR FD, SyngoDT 4, NoOfItems 6, Data '-47.43732992'\'-135.75159147'\'19.57638496' +68 - 'RBMoCoTrans' VM 3, VR FD, SyngoDT 4, NoOfItems 0, Data +69 - 'RBMoCoRot' VM 3, VR FD, SyngoDT 4, NoOfItems 0, Data +70 - 'MultistepIndex' VM 1, VR IS, SyngoDT 6, NoOfItems 6, Data '0 ' +71 - 'ImaRelTablePosition' VM 3, VR IS, SyngoDT 6, NoOfItems 6, Data '0 '\'0 '\'39 ' +72 - 'ImaCoilString' VM 1, VR LO, SyngoDT 19, NoOfItems 6, Data 'T:BO1,2' +73 - 'RFSWDDataType' VM 1, VR SH, SyngoDT 22, NoOfItems 6, Data 'measured' +74 - 'GSWDDataType' VM 1, VR SH, SyngoDT 22, NoOfItems 6, Data 'measured' +75 - 'NormalizeManipulated' VM 1, VR IS, SyngoDT 6, NoOfItems 0, Data +76 - 'ImaPATModeText' VM 1, VR LO, SyngoDT 19, NoOfItems 6, Data 'p2' +77 - 'B_matrix' VM 6, VR FD, SyngoDT 4, NoOfItems 0, Data +78 - 'BandwidthPerPixelPhaseEncode' VM 1, VR FD, SyngoDT 4, NoOfItems 0, Data +79 - 'FMRIStimulLevel' VM 1, VR FD, SyngoDT 4, NoOfItems 0, Data +Series shadow data (0029,xx20) + +0 - 'UsedPatientWeight' VM 1, VR IS, SyngoDT 6, NoOfItems 6, Data '72 ' +1 - 'NumberOfPrescans' VM 1, VR IS, SyngoDT 6, NoOfItems 6, Data '0 ' +2 - 'TransmitterCalibration' VM 1, VR DS, SyngoDT 3, NoOfItems 6, Data '541.65400000' +3 - 'PhaseGradientAmplitude' VM 1, VR DS, SyngoDT 3, NoOfItems 6, Data '0.00000000' +4 - 'ReadoutGradientAmplitude' VM 1, VR DS, SyngoDT 3, NoOfItems 6, Data '0.00000000' +5 - 'SelectionGradientAmplitude' VM 1, VR DS, SyngoDT 3, NoOfItems 6, Data '0.00000000' +6 - 'GradientDelayTime' VM 3, VR DS, SyngoDT 3, NoOfItems 6, Data '13.00000000'\'14.00000000'\'10.00000000' +7 - 'RfWatchdogMask' VM 1, VR IS, SyngoDT 6, NoOfItems 6, Data '0 ' +8 - 'RfPowerErrorIndicator' VM 1, VR DS, SyngoDT 3, NoOfItems 0, Data +9 - 'SarWholeBody' VM 3, VR DS, SyngoDT 3, NoOfItems 0, Data +10 - 'Sed' VM 3, VR DS, SyngoDT 3, NoOfItems 6, Data '1000000.00000000'\'725.84052985'\'725.71234997' +11 - 'SequenceFileOwner' VM 1, VR SH, SyngoDT 22, NoOfItems 6, Data 'SIEMENS' +12 - 'Stim_mon_mode' VM 1, VR IS, SyngoDT 6, NoOfItems 6, Data '2 ' +13 - 'Operation_mode_flag' VM 1, VR IS, SyngoDT 6, NoOfItems 6, Data '2 ' +14 - 'dBdt_max' VM 1, VR DS, SyngoDT 3, NoOfItems 6, Data '0.00000000' +15 - 't_puls_max' VM 1, VR DS, SyngoDT 3, NoOfItems 6, Data '0.00000000' +16 - 'dBdt_thresh' VM 1, VR DS, SyngoDT 3, NoOfItems 6, Data '0.00000000' +17 - 'dBdt_limit' VM 1, VR DS, SyngoDT 3, NoOfItems 6, Data '0.00000000' +18 - 'SW_korr_faktor' VM 1, VR DS, SyngoDT 3, NoOfItems 6, Data '1.00000000' +19 - 'Stim_max_online' VM 3, VR DS, SyngoDT 3, NoOfItems 6, Data '2.14339137'\'17.54720879'\'0.45053142' +20 - 'Stim_max_ges_norm_online' VM 1, VR DS, SyngoDT 3, NoOfItems 6, Data '0.63422704' +21 - 'Stim_lim' VM 3, VR DS, SyngoDT 3, NoOfItems 6, Data '45.73709869'\'27.64929962'\'31.94370079' +22 - 'Stim_faktor' VM 1, VR DS, SyngoDT 3, NoOfItems 6, Data '1.00000000' +23 - 'CoilForGradient' VM 1, VR SH, SyngoDT 22, NoOfItems 6, Data 'void' +24 - 'CoilForGradient2' VM 1, VR SH, SyngoDT 22, NoOfItems 6, Data 'AS092' +25 - 'CoilTuningReflection' VM 2, VR DS, SyngoDT 3, NoOfItems 0, Data +26 - 'CoilId' VM 0, VR IS, SyngoDT 6, NoOfItems 12, Data '255 '\'83 '\'238 '\'238 '\'238 '\'238 '\'238 '\'177 '\'238 '\'178 '\'238 ' +27 - 'MiscSequenceParam' VM 38, VR IS, SyngoDT 6, NoOfItems 42, Data '0 '\'0 '\'0 '\'0 '\'0 '\'0 '\'0 '\'0 '\'0 '\'0 '\'0 '\'0 '\'0 '\'0 '\'0 '\'0 '\'0 '\'0 '\'0 '\'0 '\'0 '\'0 '\'0 '\'0 '\'0 '\'0 '\'0 '\'0 '\'0 '\'0 '\'0 '\'1086 '\'0 '\'0 '\'0 '\'0 '\'0 '\'0 ' +28 - 'MrProtocolVersion' VM 1, VR IS, SyngoDT 6, NoOfItems 6, Data '0 ' +29 - 'DataFileName' VM 1, VR LO, SyngoDT 19, NoOfItems 0, Data +30 - 'RepresentativeImage' VM 1, VR UI, SyngoDT 25, NoOfItems 0, Data +31 - 'PositivePCSDirections' VM 1, VR SH, SyngoDT 22, NoOfItems 6, Data '+LPH' +32 - 'RelTablePosition' VM 3, VR IS, SyngoDT 6, NoOfItems 6, Data '0 '\'0 '\'39 ' +33 - 'ReadoutOS' VM 1, VR FD, SyngoDT 4, NoOfItems 6, Data '2.00000000' +34 - 'LongModelName' VM 1, VR LO, SyngoDT 19, NoOfItems 6, Data 'TrioTim' +35 - 'SliceArrayConcatenations' VM 1, VR IS, SyngoDT 6, NoOfItems 6, Data '1 ' +36 - 'SliceResolution' VM 1, VR DS, SyngoDT 3, NoOfItems 6, Data '1.00000000' +37 - 'AbsTablePosition' VM 1, VR IS, SyngoDT 6, NoOfItems 6, Data '-1952 ' +38 - 'AutoAlignMatrix' VM 16, VR FL, SyngoDT 5, NoOfItems 0, Data +39 - 'MeasurementIndex' VM 1, VR FL, SyngoDT 5, NoOfItems 0, Data +40 - 'CoilString' VM 1, VR LO, SyngoDT 19, NoOfItems 6, Data 'T:BO1,2' +41 - 'PATModeText' VM 1, VR LO, SyngoDT 19, NoOfItems 6, Data 'p2' +42 - 'PatReinPattern' VM 1, VR ST, SyngoDT 23, NoOfItems 6, Data '1;HFS;72.00;15.00;2;0;2;-794520928' +43 - 'ProtocolChangeHistory' VM 1, VR US, SyngoDT 10, NoOfItems 6, Data '0 ' +44 - 'Isocentered' VM 1, VR US, SyngoDT 10, NoOfItems 6, Data '1 ' +45 - 'MrPhoenixProtocol' VM 1, VR UN, SyngoDT 0, NoOfItems 6, Data ' +<...> +46 - 'GradientMode' VM 1, VR SH, SyngoDT 22, NoOfItems 6, Data 'Fast' +47 - 'FlowCompensation' VM 1, VR SH, SyngoDT 22, NoOfItems 6, Data 'No' +48 - 'PostProcProtocol' VM 1, VR UT, SyngoDT 27, NoOfItems 0, Data +49 - 'RFSWDOperationMode' VM 1, VR SS, SyngoDT 8, NoOfItems 6, Data '+0 ' +50 - 'RFSWDMostCriticalAspect' VM 1, VR SH, SyngoDT 22, NoOfItems 6, Data 'Whole Body' +51 - 'SARMostCriticalAspect' VM 3, VR DS, SyngoDT 3, NoOfItems 6, Data '2.00000000'\'1.02534234'\'0.97963309' +52 - 'TablePositionOrigin' VM 3, VR SL, SyngoDT 7, NoOfItems 6, Data '0 '\'0 '\'-1991 ' +53 - 'MrProtocol' VM 1, VR UN, SyngoDT 0, NoOfItems 0, Data +54 - 'MrEvaProtocol' VM 1, VR UN, SyngoDT 0, NoOfItems 0, Data +* +* +WARNING: I think this is context dependant so 0029,1010 and 0029,1110 are not supposed to mean the same thing, eg: +(CSA image data) + +(0029,0010)siemens csa header +Image shadow data (0029,xx10) + +0 - 'ImageNumber' VM 1, VR IS, SyngoDT 6, NoOfItems 0, Data +1 - 'ImageComments' VM 1, VR LT, SyngoDT 20, NoOfItems 0, Data +2 - 'ReferencedImageSequence' VM 0, VR UI, SyngoDT 25, NoOfItems 6, Data '1.2.840.10008.5.1.4.1.1.4'\'1.3.12.2.1107.5.2.30.25299.3.200803181402241188330606'\'1.2.840.10008.5.1.4.1.1.4'\'1.3.12.2.1107.5.2.30.25299.3.2008031814031374741230990'\'1.2.840.10008.5.1.4.1.1.4'\'1.3.12.2.1107.5.2.30.25299.3.200803181402241589130608' +3 - 'PatientOrientation' VM 1, VR CS, SyngoDT 16, NoOfItems 0, Data +4 - 'ScanningSequence' VM 0, VR CS, SyngoDT 16, NoOfItems 6, Data 'RM' +5 - 'SequenceName' VM 1, VR SH, SyngoDT 22, NoOfItems 6, Data 'tfi2d1_20' +6 - 'RepetitionTime' VM 1, VR DS, SyngoDT 3, NoOfItems 6, Data '29.60000000' +7 - 'EchoTime' VM 1, VR DS, SyngoDT 3, NoOfItems 6, Data '1.25000000' +8 - 'InversionTime' VM 1, VR DS, SyngoDT 3, NoOfItems 0, Data +9 - 'NumberOfAverages' VM 1, VR DS, SyngoDT 3, NoOfItems 6, Data '1.00000000' +10 - 'ImagingFrequency' VM 1, VR DS, SyngoDT 3, NoOfItems 6, Data '63.61952800' +11 - 'ImagedNucleus' VM 1, VR SH, SyngoDT 22, NoOfItems 6, Data '1H' +12 - 'EchoNumbers' VM 1, VR IS, SyngoDT 6, NoOfItems 6, Data '1 ' +13 - 'MagneticFieldStrength' VM 1, VR DS, SyngoDT 3, NoOfItems 6, Data '1.50000000' +14 - 'NumberOfPhaseEncodingSteps' VM 1, VR IS, SyngoDT 6, NoOfItems 6, Data '100 ' +15 - 'EchoTrainLength' VM 1, VR IS, SyngoDT 6, NoOfItems 6, Data '1 ' +16 - 'PercentSampling' VM 1, VR DS, SyngoDT 3, NoOfItems 6, Data '32.00000000' +17 - 'PercentPhaseFieldOfView' VM 1, VR DS, SyngoDT 3, NoOfItems 6, Data '100.00000000' +18 - 'TriggerTime' VM 1, VR DS, SyngoDT 3, NoOfItems 6, Data '82.50000000' +19 - 'ReceivingCoil' VM 1, VR SH, SyngoDT 22, NoOfItems 0, Data +20 - 'TransmittingCoil' VM 1, VR SH, SyngoDT 22, NoOfItems 6, Data 'Body' +21 - 'AcquisitionMatrix' VM 4, VR US, SyngoDT 10, NoOfItems 6, Data '256 '\'0 '\'0 '\'82 ' +22 - 'PhaseEncodingDirection' VM 1, VR CS, SyngoDT 16, NoOfItems 6, Data 'COL' +23 - 'FlipAngle' VM 1, VR DS, SyngoDT 3, NoOfItems 6, Data '20.00000000' +24 - 'VariableFlipAngleFlag' VM 1, VR CS, SyngoDT 16, NoOfItems 6, Data 'N' +25 - 'SAR' VM 1, VR DS, SyngoDT 3, NoOfItems 6, Data '0.21757985' +26 - 'dBdt' VM 3, VR DS, SyngoDT 3, NoOfItems 6, Data '0.00000000' +27 - 'SliceThickness' VM 1, VR DS, SyngoDT 3, NoOfItems 6, Data '7.00000000' +28 - 'ImagePositionPatient' VM 3, VR DS, SyngoDT 3, NoOfItems 6, Data '117.38499069'\'-48.94067860'\'0.00000000' +29 - 'ImageOrientationPatient' VM 6, VR DS, SyngoDT 3, NoOfItems 6, Data '-1.00000000'\'0.00000000'\'0.00000000'\'0.00000000'\'1.00000000'\'0.00000000' +30 - 'SliceLocation' VM 1, VR DS, SyngoDT 3, NoOfItems 6, Data '0.00000000' +31 - 'EchoLinePosition' VM 1, VR IS, SyngoDT 6, NoOfItems 6, Data '50 ' +32 - 'EchoColumnPosition' VM 1, VR IS, SyngoDT 6, NoOfItems 6, Data '128 ' +33 - 'EchoPartitionPosition' VM 1, VR IS, SyngoDT 6, NoOfItems 6, Data '8 ' +34 - 'Actual3DImaPartNumber' VM 1, VR IS, SyngoDT 6, NoOfItems 0, Data +35 - 'RealDwellTime' VM 1, VR IS, SyngoDT 6, NoOfItems 6, Data '2300 ' +36 - 'ProtocolSliceNumber' VM 1, VR IS, SyngoDT 6, NoOfItems 6, Data '0 ' +37 - 'DataFile' VM 1, VR UN, SyngoDT 0, NoOfItems 0, Data +38 - 'DataFileName' VM 1, VR UN, SyngoDT 0, NoOfItems 0, Data +39 - 'ICE_Dims' VM 1, VR LO, SyngoDT 19, NoOfItems 6, Data '1_1_2_1_4_1_1_1_1_1_1_1_259' +40 - 'PixelSpacing' VM 2, VR DS, SyngoDT 3, NoOfItems 6, Data '1.25000000'\'1.25000000' +41 - 'SourceImageSequence' VM 0, VR UI, SyngoDT 25, NoOfItems 0, Data +42 - 'PixelBandwidth' VM 1, VR DS, SyngoDT 3, NoOfItems 6, Data '850.00000000' +43 - 'SliceMeasurementDuration' VM 1, VR DS, SyngoDT 3, NoOfItems 6, Data '4112.50000000' +44 - 'SequenceMask' VM 1, VR UL, SyngoDT 9, NoOfItems 6, Data '0 ' +45 - 'AcquisitionMatrixText' VM 1, VR SH, SyngoDT 22, NoOfItems 6, Data '82*256s' +46 - 'MeasuredFourierLines' VM 1, VR IS, SyngoDT 6, NoOfItems 0, Data +47 - 'CsiGridshiftVector' VM 3, VR DS, SyngoDT 3, NoOfItems 0, Data +48 - 'MultistepIndex' VM 1, VR IS, SyngoDT 6, NoOfItems 6, Data '0 ' +49 - 'SpectroscopyAcquisitionPhaseColumns' VM 1, VR UL, SyngoDT 9, NoOfItems 0, Data +50 - 'SpectroscopyAcquisitionPhaseRows' VM 1, VR UL, SyngoDT 9, NoOfItems 0, Data +51 - 'SpectroscopyAcquisitionOut-of-planePhaseSteps' VM 1, VR UL, SyngoDT 9, NoOfItems 0, Data +52 - 'SpectroscopyAcquisitionDataColumns' VM 1, VR UL, SyngoDT 9, NoOfItems 0, Data +53 - 'DataPointRows' VM 1, VR UL, SyngoDT 9, NoOfItems 0, Data +54 - 'DataPointColumns' VM 1, VR UL, SyngoDT 9, NoOfItems 0, Data +55 - 'DataRepresentation' VM 1, VR CS, SyngoDT 16, NoOfItems 0, Data +56 - 'SignalDomainColumns' VM 1, VR CS, SyngoDT 16, NoOfItems 0, Data +57 - 'Columns' VM 1, VR US, SyngoDT 10, NoOfItems 6, Data '256 ' +58 - 'Rows' VM 1, VR US, SyngoDT 10, NoOfItems 6, Data '100 ' +59 - 'NumberOfFrames' VM 1, VR IS, SyngoDT 6, NoOfItems 0, Data +60 - 'MixingTime' VM 1, VR DS, SyngoDT 3, NoOfItems 0, Data +61 - 'k-spaceFiltering' VM 1, VR CS, SyngoDT 16, NoOfItems 0, Data +62 - 'HammingFilterWidth' VM 1, VR DS, SyngoDT 3, NoOfItems 0, Data +63 - 'TransmitterReferenceAmplitude' VM 1, VR FD, SyngoDT 4, NoOfItems 0, Data +64 - 'ResonantNucleus' VM 1, VR CS, SyngoDT 16, NoOfItems 0, Data +65 - 'VoiThickness' VM 1, VR FD, SyngoDT 4, NoOfItems 0, Data +66 - 'VoiPhaseFoV' VM 1, VR FD, SyngoDT 4, NoOfItems 0, Data +67 - 'VoiReadoutFoV' VM 1, VR FD, SyngoDT 4, NoOfItems 0, Data +68 - 'VoiOrientation' VM 3, VR FD, SyngoDT 4, NoOfItems 0, Data +69 - 'VoiPosition' VM 3, VR FD, SyngoDT 4, NoOfItems 0, Data +70 - 'VoiInPlaneRotation' VM 1, VR FD, SyngoDT 4, NoOfItems 0, Data +71 - 'RSatThickness' VM 0, VR FD, SyngoDT 4, NoOfItems 0, Data +72 - 'RSatOrientationSag' VM 0, VR FD, SyngoDT 4, NoOfItems 0, Data +73 - 'RSatOrientationCor' VM 0, VR FD, SyngoDT 4, NoOfItems 0, Data +74 - 'RSatOrientationTra' VM 0, VR FD, SyngoDT 4, NoOfItems 0, Data +75 - 'RSatPositionSag' VM 0, VR FD, SyngoDT 4, NoOfItems 0, Data +76 - 'RSatPositionCor' VM 0, VR FD, SyngoDT 4, NoOfItems 0, Data +77 - 'RSatPositionTra' VM 0, VR FD, SyngoDT 4, NoOfItems 0, Data +78 - 'SpacingBetweenSlices' VM 1, VR FD, SyngoDT 4, NoOfItems 0, Data +79 - 'DataSetInfo' VM 1, VR UN, SyngoDT 0, NoOfItems 0, Data +80 - 'ImaCoilString' VM 1, VR LO, SyngoDT 19, NoOfItems 6, Data 'BO1' +81 - 'BandwidthPerPixelPhaseEncode' VM 1, VR FD, SyngoDT 4, NoOfItems 0, Data + + + +*/ +struct equ +{ + uint32_t syngodt; + const char vr[2+1]; +}; + +// Looks like there is mapping in between syngodt and vr... +// O <=> UN +// 3 <=> DS +// 4 <=> FD +// 5 <=> FL +// 6 <=> IS +// 9 <=> UL +// 10 <=> US +// 16 <=> CS +// 19 <=> LO +// 20 <=> LT +// 22 <=> SH +// 25 <=> UI +static equ mapping[] = { + { 0 , "UN" }, + { 3 , "DS" }, + { 4 , "FD" }, + { 5 , "FL" }, + { 6 , "IS" }, + { 7 , "SL" }, + { 8 , "SS" }, + { 9 , "UL" }, + { 10 , "US" }, + { 16 , "CS" }, + { 19 , "LO" }, + { 20 , "LT" }, + { 22 , "SH" }, + { 23 , "ST" }, + { 25 , "UI" }, + { 27 , "UT" } +}; + +bool check_mapping(uint32_t syngodt, const char *vr) +{ + static const unsigned int max = sizeof(mapping) / sizeof(equ); + const equ *p = mapping; + assert( syngodt <= mapping[max-1].syngodt ); (void)max; + while(p->syngodt < syngodt ) + { + //std::cout << "mapping:" << p->vr << std::endl; + ++p; + } + assert( p->syngodt == syngodt ); // or else need to update mapping + const char* lvr = p->vr; + int check = strcmp(vr, lvr) == 0; + assert( check ); (void)check; + return true; +} + +bool checkallzero(std::istream &is) +{ + bool res = true; + char c; + while( is >> c ) + { + if( c != 0 ) + { + res = false; + break; + } + } + return res; +} + +CSAHeader::CSAHeaderType CSAHeader::GetFormat() const +{ + return InternalType; +} + +// dcmInfo.exe print like this: +// 67 - 'SlicePosition_PCS' VM 3, VR FD, SyngoDT 4, NoOfItems 6, Data '-185.77913332'\'-163.80459213'\'72.73944092' +bool CSAHeader::LoadFromDataElement(DataElement const &de) +{ + if( de.IsEmpty() ) return false; + + InternalCSADataSet.clear(); + InternalDataSet.Clear(); + gdcmDebugMacro( "Entering print" ); + InternalType = UNKNOWN; // reset + gdcm::Tag t1(0x0029,0x0010); + gdcm::Tag t2(0x0029,0x0020); + uint16_t v = (uint16_t)(de.GetTag().GetElement() << 8); + uint16_t v2 = (uint16_t)(v >> 8); + //if( de.GetTag().GetPrivateCreator() == t1 ) + if( v2 == t1.GetElement() ) + { + //std::cout << "Image shadow data (0029,xx10)\n\n"; + DataElementTag = t1;; + } + //else if( de.GetTag().GetPrivateCreator() == t2 ) + else if( v2 == t2.GetElement() ) + { + //std::cout << "Series shadow data (0029,xx20)\n\n"; + DataElementTag = t2;; + } + else + { + // std::cerr << "Unhandled tag: " << de.GetTag() << std::endl; + DataElementTag = de.GetTag(); + } + gdcmDebugMacro( "found type" ); + + const ByteValue *bv = de.GetByteValue(); + assert( bv ); + const char *p = bv->GetPointer(); + assert( p ); + std::string s( bv->GetPointer(), bv->GetLength() ); + std::stringstream ss; + ss.str( s ); + char signature[4+1]; + signature[4] = 0; + if( !ss.read(signature, 4) ) + { + gdcmErrorMacro( "Too short" ); + return false; + } + //std::cout << signature << std::endl; + // 1. NEW FORMAT + // 2. OLD FORMAT + // 3. Zero out + // 4. DATASET FORMAT (Explicit Little Endian), with group=0x0 elements: + if( strcmp( signature, "SV10" ) != 0 ) + { + if( checkallzero(ss) ) + { + //std::cout << "Zeroed out" << std::endl; + InternalType = ZEROED_OUT; + return true; + } + else if( strcmp(signature, "!INT" ) == 0 ) + { + InternalType = INTERFILE; + InterfileData = p; + return true; + } + // cannot use strcmp / strncmp in the following ... doh ! + else if( memcmp(signature, "\0\0" , 2 ) == 0 + || memcmp(signature, "\6\0" , 2 ) == 0 ) + { + // Most often start with an element (0000,xxxx) + // And ends with element: + // (ffff,ffff) CS 10 END! + ss.seekg( 0, std::ios::beg ); + // SIEMENS-JPEG-CorruptFragClean.dcm + InternalType = DATASET_FORMAT; + DataSet &ds = InternalDataSet; + DataElement xde; + try + { + while( xde.Read( ss ) ) + { + ds.InsertDataElement( xde ); // Cannot use Insert since Group = 0x0 (< 0x8) + //VR refvr = GetVRFromDataSetFormatDict( xde.GetTag() ); + //assert( xde.GetVR() == refvr ); + } + //std::cout << ds << std::endl; + assert( ss.eof() ); + } + catch(std::exception &) + { + gdcmErrorMacro( "Something went wrong while decoding... please report" ); + return false; + } + return true; + } + else + { + //assert(0); + ss.seekg( 0, std::ios::beg ); + // No magic number for this one: + // SIEMENS_Sonata-16-MONO2-Value_Multiplicity.dcm + InternalType = NOMAGIC; + } + } + if( strcmp( signature, "SV10" ) == 0 ) + { + // NEW FORMAT ! + ss.read(signature, 4); + assert( strcmp( signature, "\4\3\2\1" ) == 0 ); + InternalType = SV10; + } + assert( InternalType != UNKNOWN ); + gdcmDebugMacro( "Found Type: " << (int)InternalType ); + + uint32_t n; + ss.read((char*)&n, sizeof(n)); + SwapperNoOp::SwapArray(&n,1); + uint32_t unused; + ss.read((char*)&unused, sizeof(unused)); + SwapperNoOp::SwapArray(&unused,1); + if( unused != 77 ) + { + gdcmErrorMacro( "Must be a new format. Giving up" ); + return false; + } + assert( unused == 77 ); // 'M' character... + + for(uint32_t i = 0; i < n; ++i) + { + CSAElement csael; + //std::cout << i; + csael.SetKey( i ); + //std::cout << " - "; + char name[64+1]; + name[64] = 0; // security + ss.read(name, 64); + csael.SetName( name ); + //std::cout << "'" << name << "' "; + uint32_t vm; + ss.read((char*)&vm, sizeof(vm)); + SwapperNoOp::SwapArray(&vm,1); + csael.SetVM( VM::GetVMTypeFromLength(vm,1) ); + //assert( csael.GetVM() != VM::VM0 ); + //std::cout << "VM " << vm << ", "; + char vr[4]; + ss.read(vr, 4); + // In dataset without magic signature (OLD FORMAT) vr[3] is garbage... + assert( /*vr[3] == 0 &&*/ vr[2] == 0 ); + csael.SetVR( VR::GetVRTypeFromFile(vr) ); + //std::cout << "VR " << vr << ", "; + uint32_t syngodt; + ss.read((char*)&syngodt, sizeof(syngodt)); + SwapperNoOp::SwapArray(&syngodt,1); + bool cm = check_mapping(syngodt, vr); + if( !cm ) + { + gdcmErrorMacro( "SyngoDT is not handled, please submit bug report" ); + return false; + } + csael.SetSyngoDT( syngodt ); + //std::cout << "SyngoDT " << syngodt << ", "; + uint32_t nitems; + ss.read((char*)&nitems, sizeof(nitems)); + SwapperNoOp::SwapArray(&nitems,1); + csael.SetNoOfItems( nitems ); + //std::cout << "NoOfItems " << nitems << ", "; + uint32_t xx; + ss.read((char*)&xx, sizeof(xx)); + SwapperNoOp::SwapArray(&xx,1); + //std::cout << "xx=" << xx<< std::endl; + assert( xx == 77 || xx == 205 ); + + //std::cout << "Data "; + std::ostringstream os; + for( uint32_t j = 0; j < nitems; ++j) + { + uint32_t item_xx[4]; + ss.read((char*)&item_xx, 4*sizeof(uint32_t)); + SwapperNoOp::SwapArray(item_xx,4); + assert( item_xx[2] == 77 || item_xx[2] == 205 ); + uint32_t len = item_xx[1]; // 2nd element + assert( item_xx[0] == item_xx[1] && item_xx[1] == item_xx[3] ); + if( len ) + { + char *val = new char[len+1]; + val[len] = 0; // security + ss.read(val,len); + // WARNING vr does not means anything AFAIK, + // simply print the value as if it was IS/DS or LO (ASCII) + if( j ) + { + //std::cout << '\\'; + os << '\\'; + } + //std::cout << "'" << val << "'"; + os << val; + + char dummy[4]; + uint32_t dummy_len = (4 - len % 4) % 4; + ss.read(dummy, dummy_len ); + + for(uint32_t d= 0; d < dummy_len; ++d) + { + // dummy[d] is zero in the NEW format + //assert( dummy[d] == 0 ); + //for the old format there appears to be some garbage: + if( dummy[d] ) + { + //std::cout << "dummy=" << (int)dummy[d] << std::endl; + } + } + delete[] val; + } + } + std::string str = os.str(); + if( !str.empty() ) + csael.SetByteValue( &str[0], (uint32_t)str.size()); + //std::cout << std::endl; + InternalCSADataSet.insert( csael ); + } + return true; +} + +void CSAHeader::Print(std::ostream &os) const +{ + std::set::const_iterator it = InternalCSADataSet.begin(); + gdcm::Tag t1(0x0029,0x0010); + gdcm::Tag t2(0x0029,0x0020); + if( DataElementTag == t1 ) + { + os << "Image shadow data (0029,xx10)\n\n"; + } + else if( DataElementTag == t2 ) + { + os << "Series shadow data (0029,xx20)\n\n"; + } + else + { + std::cerr << "Unhandled tag: " << DataElementTag << std::endl; + } + + for(; it != InternalCSADataSet.end(); ++it) + { + std::cout << *it << std::endl; + } +} + +const CSAElement &CSAHeader::GetCSAElementByName(const char *name) +{ + if( name ) + { + //int s = InternalCSADataSet.size(); + std::set::const_iterator it = InternalCSADataSet.begin(); + for(; it != InternalCSADataSet.end(); ++it) + { + const char *itname = it->GetName(); + assert( itname ); + if( strcmp(name, itname) == 0 ) + { + return *it; + } + } + } + return GetCSAEEnd(); +} + +bool CSAHeader::FindCSAElementByName(const char *name) +{ + if( name ) + { + std::set::const_iterator it = InternalCSADataSet.begin(); + for(; it != InternalCSADataSet.end(); ++it) + { + const char *itname = it->GetName(); + assert( itname ); + if( strcmp(name, itname) == 0 ) + { + return true; + } + } + } + return false; +} + +static const char csaheader[] = "SIEMENS CSA HEADER"; +static const gdcm::PrivateTag t1(0x0029,0x0010,csaheader); // CSA Image Header Info +static const gdcm::PrivateTag t2(0x0029,0x0020,csaheader); // CSA Series Header Info + +static const char csanonimage[] = "SIEMENS CSA NON-IMAGE"; +static const gdcm::PrivateTag t3(0x0029,0x0010,csanonimage); // CSA Data Info + +const PrivateTag & CSAHeader::GetCSAImageHeaderInfoTag() +{ + return t1; +} + +const PrivateTag & CSAHeader::GetCSASeriesHeaderInfoTag() +{ + return t2; +} + +const PrivateTag & CSAHeader::GetCSADataInfo() +{ + return t3; +} + +} // end namespace gdcm diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmCSAHeader.h b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmCSAHeader.h new file mode 100644 index 0000000..a886efa --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmCSAHeader.h @@ -0,0 +1,141 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMCSAHEADER_H +#define GDCMCSAHEADER_H + +#include "gdcmTypes.h" +#include "gdcmDataSet.h" +#include "gdcmCSAElement.h" + +namespace gdcm +{ +/* + * Everything done in this code is for the sole purpose of writing interoperable + * software under Sect. 1201 (f) Reverse Engineering exception of the DMCA. + * If you believe anything in this code violates any law or any of your rights, + * please contact us (gdcm-developers@lists.sourceforge.net) so that we can + * find a solution. + */ +//----------------------------------------------------------------------------- + +class DataElement; +class PrivateTag; +/** + * \brief Class for CSAHeader + * \details SIEMENS store private information in tag (0x0029,0x10,"SIEMENS CSA + * HEADER") this class is meant for user wishing to access values stored within + * this private attribute. + * There are basically two main 'format' for this attribute : SV10/NOMAGIC and + * DATASET_FORMAT SV10 and NOMAGIC are from a user prospective identical, see + * CSAHeader.xml for possible name / value stored in this format. + * DATASET_FORMAT is in fact simply just another DICOM dataset (implicit) with + * -currently unknown- value. This can be only be printed for now. + * + * \warning + * Everything you do with this code is at your own risk, since decoding process + * was not written from specification documents. + * + * \warning the API of this class might change. + * + * \todo + * MrEvaProtocol in 29,1020 contains ^M that would be nice to get rid of on UNIX system... + * + * \see PDBHeader + * + * External references: + * 5.1.3.2.4.1 MEDCOM History Information + * and 5.1.4.3 CSA Non-Image Module + * in + * http://tamsinfo.toshiba.com/docrequest/pdf/E.Soft_v2.0.pdf + */ +class GDCM_EXPORT CSAHeader +{ + friend std::ostream& operator<<(std::ostream &_os, const CSAHeader &d); +public : + CSAHeader():InternalDataSet(),InternalType(UNKNOWN),InterfileData(0) {}; + ~CSAHeader() {}; + + /// Divers format of CSAHeader as found 'in the wild' + typedef enum { + UNKNOWN = 0, + SV10, + NOMAGIC, + DATASET_FORMAT, + INTERFILE, + ZEROED_OUT + } CSAHeaderType; + + template + std::istream &Read(std::istream &is); + + template + const std::ostream &Write(std::ostream &os) const; + + /// Decode the CSAHeader from element 'de' + bool LoadFromDataElement(DataElement const &de); + + /// Print the CSAHeader (use only if Format == SV10 or NOMAGIC) + void Print(std::ostream &os) const; + + /// Return the DataSet output (use only if Format == DATASET_FORMAT ) + const DataSet& GetDataSet() const { return InternalDataSet; } + + /// Return the string output (use only if Format == Interfile) + const char * GetInterfile() const { return InterfileData; } + + /// return the format of the CSAHeader + /// SV10 and NOMAGIC are equivalent. + CSAHeaderType GetFormat() const; + + /// Return the private tag used by SIEMENS to store the CSA Image Header + /// This is: PrivateTag(0x0029,0x0010,"SIEMENS CSA HEADER"); + static const PrivateTag & GetCSAImageHeaderInfoTag(); + + /// Return the private tag used by SIEMENS to store the CSA Series Header + /// This is: PrivateTag(0x0029,0x0020,"SIEMENS CSA HEADER"); + static const PrivateTag & GetCSASeriesHeaderInfoTag(); + + /// Return the private tag used by SIEMENS to store the CSA Data Info + /// This is: PrivateTag(0x0029,0x0010,"SIEMENS CSA NON-IMAGE"); + static const PrivateTag & GetCSADataInfo(); + + /// Return the CSAElement corresponding to name 'name' + /// \warning Case Sensitive + const CSAElement &GetCSAElementByName(const char *name); + + /// Return true if the CSA element matching 'name' is found or not + /// \warning Case Sensitive + bool FindCSAElementByName(const char *name); + +protected: + const CSAElement& GetCSAEEnd() const; + +private: + std::set InternalCSADataSet; + DataSet InternalDataSet; + CSAHeaderType InternalType; + Tag DataElementTag; + static CSAElement CSAEEnd; + const char *InterfileData; +}; +//----------------------------------------------------------------------------- +inline std::ostream& operator<<(std::ostream &os, const CSAHeader &d) +{ + d.Print( os ); + return os; +} + +} // end namespace gdcm +//----------------------------------------------------------------------------- +#endif //GDCMCSAHEADER_H diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmCSAHeader.txx b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmCSAHeader.txx new file mode 100644 index 0000000..3e8c407 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmCSAHeader.txx @@ -0,0 +1,34 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMCSAHEADER_TXX +#define GDCMCSAHEADER_TXX + +#include "gdcmByteValue.h" + +namespace gdcm +{ + + template + std::istream &CSAHeader::Read(std::istream &is) { + return is; + } + + + template + std::ostream const &CSAHeader::Write(std::ostream &os) const { + return os; + } +} // end namespace gdcm + +#endif // GDCMCSAHEADER_TXX diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmCodeString.cxx b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmCodeString.cxx new file mode 100644 index 0000000..9796415 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmCodeString.cxx @@ -0,0 +1,38 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmCodeString.h" + +namespace gdcm +{ + bool CodeString::IsValid() const { + if( !Internal.IsValid() ) return false; + // Implementation specific: + + /* + * Uppercase characters, 0-9, the SPACE character, and underscore _, of the + * Default Character Repertoire + */ + const_iterator it = Internal.begin(); + for( ; it != Internal.end(); ++it ) + { + int c = *it; + if( !isupper(c) && !isdigit(c) && c != ' ' && c != '_' ) + { + return false; + } + } + return true; + } + +} // end namespace gdcm diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmCodeString.h b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmCodeString.h new file mode 100644 index 0000000..cfd9e52 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmCodeString.h @@ -0,0 +1,105 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMCODESTRING_H +#define GDCMCODESTRING_H + +#include "gdcmString.h" + +namespace gdcm +{ + +/** + * \brief CodeString + * This is an implementation of DICOM VR: CS + * The cstor will properly Trim so that operator== is correct. + * + * \note the cstor of CodeString will Trim the string on the fly so as + * to remove the extra leading and ending spaces. However it will not + * perform validation on the fly (CodeString obj can contains invalid + * char such as lower cases). This design was chosen to be a little tolerant + * to broken DICOM implementation, and thus allow user to compare lower + * case CS from there input file without the need to first rewrite them + * to get rid of invalid character (validation is a different operation from + * searching, querying). + * \warning when writing out DICOM file it is highly recommended to perform + * the IsValid() call, at least to check that the length of the string match + * the definition in the standard. + */ +// Note to myself: because note all wrapped language support exception +// we could not support throwing an exception during object construction. +class GDCM_EXPORT CodeString +{ + friend std::ostream& operator<< (std::ostream& os, const CodeString& str); + friend bool operator==(const CodeString &ref, const CodeString& cs); + friend bool operator!=(const CodeString &ref, const CodeString& cs); + typedef String<'\\',16> InternalClass; +public: + typedef InternalClass::value_type value_type; + typedef InternalClass::pointer pointer; + typedef InternalClass::reference reference; + typedef InternalClass::const_reference const_reference; + typedef InternalClass::size_type size_type; + typedef InternalClass::difference_type difference_type; + typedef InternalClass::iterator iterator; + typedef InternalClass::const_iterator const_iterator; + typedef InternalClass::reverse_iterator reverse_iterator; + typedef InternalClass::const_reverse_iterator const_reverse_iterator; + + /// CodeString constructors. + CodeString(): Internal() {} + CodeString(const value_type* s): Internal(s) { Internal = Internal.Trim(); } + CodeString(const value_type* s, size_type n): Internal(s, n) { + Internal = Internal.Trim(); } + CodeString(const InternalClass& s, size_type pos=0, size_type n=InternalClass::npos): + Internal(s, pos, n) { Internal = Internal.Trim(); } + + /// Check if CodeString obj is correct.. + bool IsValid() const; + + /// Return the full code string as std::string + std::string GetAsString() const { + return Internal; + } + + /// Return the size of the string + size_type Size() const { return Internal.size(); } + +protected: + std::string TrimInternal() const { + return Internal.Trim(); + } + +private: + String<'\\',16> Internal; +}; + +inline std::ostream& operator<< (std::ostream& os, const CodeString& str) +{ + os << str.Internal; + return os; +} + +inline bool operator==(const CodeString &ref, const CodeString& cs) +{ + return ref.Internal == cs.Internal; +} +inline bool operator!=(const CodeString &ref, const CodeString& cs) +{ + return ref.Internal != cs.Internal; +} + + +} // end namespace gdcm + +#endif //GDCMCODESTRING_H diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmDataElement.cxx b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmDataElement.cxx new file mode 100644 index 0000000..328272e --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmDataElement.cxx @@ -0,0 +1,185 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmDataElement.h" + +#include "gdcmByteValue.h" +#include "gdcmAttribute.h" +#include "gdcmSequenceOfFragments.h" +#include "gdcmSequenceOfItems.h" +#include "gdcmImplicitDataElement.h" +#include "gdcmTrace.h" + +namespace gdcm +{ + void DataElement::SetVLToUndefined() { + assert( VRField == VR::SQ || VRField == VR::INVALID + || (VRField == VR::UN /*&& IsUndefinedLength()*/ ) ); + SequenceOfItems *sqi = dynamic_cast(ValueField.GetPointer()); + if( sqi ) + { + sqi->SetLengthToUndefined(); + assert( GetValueAsSQ()->IsUndefinedLength() ); + } + ValueLengthField.SetToUndefined(); + } + + const SequenceOfFragments* DataElement::GetSequenceOfFragments() const { + const SequenceOfFragments *sqf = dynamic_cast(ValueField.GetPointer()); + return sqf; + } + SequenceOfFragments* DataElement::GetSequenceOfFragments() { + SequenceOfFragments *sqf = dynamic_cast(ValueField.GetPointer()); + return sqf; + } + + /* + * Two cases are handled: + * - Simple ones: + * Explicit file with VR::SQ (defined or undefined length) + * Implicit file with undefined length (clearly a SQ) + * - If not in the previous case then we are in the second case: complex one (hidden SQ) + * Implicit file with defined length SQ + * Explicit file with SQ declared as UN + undefined length + */ + SmartPointer DataElement::GetValueAsSQ() const + { + if( IsEmpty() /*|| GetByteValue()*/ || GetSequenceOfFragments() ) + { + return 0; + } + SequenceOfItems *sq = dynamic_cast(ValueField.GetPointer()); + if( sq ) // all set ! + { + //assert( GetVR() == VR::SQ ); + SmartPointer sqi = sq; + return sqi; + } + + const Tag itemStart(0xfffe, 0xe000); + { + { + if( GetVR() == VR::INVALID ) + { + const ByteValue *bv = GetByteValue(); + assert( bv ); + SequenceOfItems *sqi = new SequenceOfItems; + sqi->SetLength( bv->GetLength() ); + std::string s( bv->GetPointer(), bv->GetLength() ); + try + { + std::stringstream ss; + ss.str( s ); + sqi->Read( ss, true ); + } + catch(Exception &ex) + { + const Tag itemPMSStart(0xfeff, 0x00e0); + const Tag itemPMSStart2(0x3f3f, 0x3f00); + + // same player ... + //this to fix a broken dicom implementation + //for philips medical systems + std::stringstream ss; + ss.str(s); + Tag item; + item.Read(ss); + assert( item == itemPMSStart ); + ss.seekg(-4,std::ios::cur); + sqi->Read( ss, true ); + gdcmWarningMacro(ex.what()); + (void)ex; //to avoid unreferenced variable warning on release + } + return sqi; + } + else if ( GetVR() == VR::UN ) // cp 246, IVRLE SQ + { + assert( GetVR() == VR::UN ); // cp 246, IVRLE SQ + const ByteValue *bv = GetByteValue(); + assert( bv ); + SequenceOfItems *sqi = new SequenceOfItems; + sqi->SetLength( bv->GetLength() ); + std::string s( bv->GetPointer(), bv->GetLength() ); + try + { + std::stringstream ss; + ss.str( s ); + sqi->Read( ss, true ); + } + catch ( Exception &ex0 ) + { + // Some people like to skew things up and write invalid SQ in VR:UN field + // if conversion fails, simply keep the binary VR:UN stuff as-is + // eg. AMIInvalidPrivateDefinedLengthSQasUN.dcm + //const char *s = e.what(); + // s -> gdcm::ImplicitDataElement -> Impossible (more) + try + { + std::stringstream ss; + ss.str(s); + sqi->Read( ss, true ); + gdcmWarningMacro(ex0.what()); (void)ex0; + } + catch ( Exception &ex1 ) + { + // Let's try again this time but without the byte swapping option: + // eg. MEDILABInvalidCP246_EVRLESQasUN.dcm + try + { + std::stringstream ss; + ss.str(s); + sqi->Read( ss, true ); + gdcmWarningMacro(ex1.what()); (void)ex1; + } + catch ( Exception &ex2 ) + { + gdcmErrorMacro( "Could not read SQ. Giving up" ); + gdcmErrorMacro(ex2.what()); (void)ex2; + throw "Could not decode this SQ"; + return NULL; + } + } + } + return sqi; + } + else + { + assert( GetVR().IsVRFile() ); + assert( GetByteValue() ); + return 0; + } + } + } + // catch( ParseException &pex ) + // { + // gdcmDebugMacro( pex.what() ); + // } + // catch( Exception &ex ) + // { + // gdcmDebugMacro( ex.what() ); + // } + // catch( ... ) + // { + // gdcmWarningMacro( "Unknown exception" ); + // } + } + +void DataElement::SetValueFieldLength( VL vl, bool readvalues ) +{ + if( readvalues ) + ValueField->SetLength(vl); // perform realloc + else + ValueField->SetLengthOnly(vl); // do not perform realloc +} + +} // end namespace gdcm diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmDataElement.h b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmDataElement.h new file mode 100644 index 0000000..3029bb6 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmDataElement.h @@ -0,0 +1,277 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMDATAELEMENT_H +#define GDCMDATAELEMENT_H + +#include "gdcmTag.h" +#include "gdcmVL.h" +#include "gdcmVR.h" +#include "gdcmByteValue.h" +#include "gdcmSmartPointer.h" + +#include + +namespace gdcm +{ +// Data Element +// Contains multiple fields: +// -> Tag +// -> Optional VR (Explicit Transfer Syntax) +// -> ValueLength +// -> Value +// TODO: This class SHOULD be pure virtual. I don't want a user +// to shoot himself in the foot. + +class SequenceOfItems; +class SequenceOfFragments; +/** + * \brief Class to represent a Data Element + * either Implicit or Explicit + * + * \details + * DATA ELEMENT: + * A unit of information as defined by a single entry in the data dictionary. + * An encoded Information Object Definition (IOD) Attribute that is composed + * of, at a minimum, three fields: a Data Element Tag, a Value Length, and a + * Value Field. For some specific Transfer Syntaxes, a Data Element also + * contains a VR Field where the Value Representation of that Data Element is + * specified explicitly. + * + * Design: + * \li A DataElement in GDCM always store VL (Value Length) on a 32 bits integer even when VL is 16 bits + * \li A DataElement always store the VR even for Implicit TS, in which case VR is defaulted to VR::INVALID + * \li For Item start/end (See 0xfffe tags), Value is NULL + * + * \see ExplicitDataElement ImplicitDataElement + */ +class GDCM_EXPORT DataElement +{ +public: + DataElement(const Tag& t = Tag(0), const VL& vl = 0, const VR &vr = VR::INVALID):TagField(t),ValueLengthField(vl),VRField(vr),ValueField(0) {} + //DataElement( Attribute const &att ); + + friend std::ostream& operator<<(std::ostream &_os, const DataElement &_val); + + /// Get Tag + const Tag& GetTag() const { return TagField; } + Tag& GetTag() { return TagField; } + /// Set Tag + /// Use with cautious (need to match Part 6) + void SetTag(const Tag &t) { TagField = t; } + + /// Get VL + const VL& GetVL() const { return ValueLengthField; } + VL& GetVL() { return ValueLengthField; } + /// Set VL + /// Use with cautious (need to match Part 6), advanced user only + /// \see SetByteValue + void SetVL(const VL &vl) { ValueLengthField = vl; } + void SetVLToUndefined(); + + /// Get VR + /// do not set VR::SQ on bytevalue data element + VR const &GetVR() const { return VRField; } + /// Set VR + /// Use with cautious (need to match Part 6), advanced user only + /// \pre vr is a VR::VRALL (not a dual one such as OB_OW) + void SetVR(VR const &vr) { + if( vr.IsVRFile() ) + VRField = vr; + } + + /// Set/Get Value (bytes array, SQ of items, SQ of fragments): + Value const &GetValue() const { return *ValueField; } + Value &GetValue() { return *ValueField; } + /// \warning you need to set the ValueLengthField explicitely + void SetValue(Value const & vl) { + //assert( ValueField == 0 ); + ValueField = vl; + ValueLengthField = vl.GetLength(); + } + /// Check if Data Element is empty + bool IsEmpty() const { return ValueField == 0 || (GetByteValue() && GetByteValue()->IsEmpty()); } + + /// Make Data Element empty (no Value) + void Empty() { ValueField = 0; ValueLengthField = 0; } + + /// Clear Data Element (make Value empty and invalidate Tag & VR) + void Clear() + { + TagField = 0; + VRField = VR::INVALID; + ValueField = 0; + ValueLengthField = 0; + } + + // Helper: + /// Set the byte value + /// \warning user need to read DICOM standard for an understanding of: + /// * even padding + /// * \0 vs space padding + /// By default even padding is achieved using \0 regardless of the of VR + void SetByteValue(const char *array, VL length) + { + ByteValue *bv = new ByteValue(array,length); + SetValue( *bv ); + } + /// Return the Value of DataElement as a ByteValue (if possible) + /// \warning: You need to check for NULL return value + const ByteValue* GetByteValue() const { + // Get the raw pointer from the gdcm::SmartPointer + const ByteValue *bv = dynamic_cast(ValueField.GetPointer()); + return bv; // Will return NULL if not ByteValue + } + + /// Interpret the Value stored in the DataElement. This is more robust (but also more + /// expensive) to call this function rather than the simpliest form: GetSequenceOfItems() + /// It also return NULL when the Value is NOT of type SequenceOfItems + /// \warning in case GetSequenceOfItems() succeed the function return this value, otherwise + /// it creates a new SequenceOfItems, you should handle that in your case, for instance: + /// SmartPointer sqi = de.GetValueAsSQ(); + SmartPointer GetValueAsSQ() const; + + /// Return the Value of DataElement as a Sequence Of Fragments (if possible) + /// \warning: You need to check for NULL return value + const SequenceOfFragments* GetSequenceOfFragments() const; + SequenceOfFragments* GetSequenceOfFragments(); + + /// return if Value Length if of undefined length + bool IsUndefinedLength() const { + return ValueLengthField.IsUndefined(); + } + + DataElement(const DataElement &_val) + { + if( this != &_val) + { + *this = _val; + } + } + + bool operator<(const DataElement &de) const + { + return GetTag() < de.GetTag(); + } + DataElement &operator=(const DataElement &de) + { + TagField = de.TagField; + ValueLengthField = de.ValueLengthField; + VRField = de.VRField; + ValueField = de.ValueField; // Pointer copy + return *this; + } + + bool operator==(const DataElement &de) const + { + bool b = TagField == de.TagField + && ValueLengthField == de.ValueLengthField + && VRField == de.VRField; + if( !ValueField && !de.ValueField ) + { + return b; + } + if( ValueField && de.ValueField ) + { + return b && (*ValueField == *de.ValueField); + } + // ValueField != de.ValueField + return false; + } + + // The following fonctionalities are dependant on: + // # The Transfer Syntax: Explicit or Implicit + // # The Byte encoding: Little Endian / Big Endian + + /* + * The following was inspired by a C++ idiom: Curiously Recurring Template Pattern + * Ref: http://en.wikipedia.org/wiki/Curiously_Recurring_Template_Pattern + * The typename TDE is typically a derived class *without* any data + * while TSwap is a simple template parameter to achieve byteswapping (and allow factorization of + * highly identical code) + */ + template + VL GetLength() const { + return static_cast(this)->GetLength(); + } + + template + std::istream &Read(std::istream &is) { + return static_cast(this)->template Read(is); + } + + template + std::istream &ReadOrSkip(std::istream &is, std::set const &skiptags) { + (void)skiptags; + return static_cast(this)->template Read(is); + } + + template + std::istream &ReadPreValue(std::istream &is, std::set const &skiptags) { + (void)skiptags; + return static_cast(this)->template ReadPreValue(is); + } + template + std::istream &ReadValue(std::istream &is, std::set const &skiptags) { + (void)skiptags; + return static_cast(this)->template ReadValue(is); + } + template + std::istream &ReadValueWithLength(std::istream &is, VL & length, std::set const &skiptags) { + (void)skiptags; + return static_cast(this)->template ReadValueWithLength(is, length); + } + + template + std::istream &ReadWithLength(std::istream &is, VL &length) { + return static_cast(this)->template ReadWithLength(is,length); + } + + template + const std::ostream &Write(std::ostream &os) const { + return static_cast(this)->template Write(os); + } + +protected: + Tag TagField; + // This is the value read from the file, might be different from the length of Value Field + VL ValueLengthField; // Can be 0xFFFFFFFF + + // Value Representation + VR VRField; + typedef SmartPointer ValuePtr; + ValuePtr ValueField; + + void SetValueFieldLength( VL vl, bool readvalues ); +}; +//----------------------------------------------------------------------------- +inline std::ostream& operator<<(std::ostream &os, const DataElement &val) +{ + os << val.TagField; + os << "\t" << val.VRField; + os << "\t" << val.ValueLengthField; + if( val.ValueField ) + { + val.ValueField->Print( os << "\t" ); + } + return os; +} + +inline bool operator!=(const DataElement& lhs, const DataElement& rhs) +{ + return ! ( lhs == rhs ); +} + +} // end namespace gdcm + +#endif //GDCMDATAELEMENT_H diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmDataSet.cxx b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmDataSet.cxx new file mode 100644 index 0000000..fcddbed --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmDataSet.cxx @@ -0,0 +1,155 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmDataSet.h" +#include "gdcmPrivateTag.h" + +namespace gdcm +{ +DataElement DataSet::DEEnd = DataElement( Tag(0xffff,0xffff) ); + +const DataElement& DataSet::GetDEEnd() const +{ + return DEEnd; +} + +std::string DataSet::GetPrivateCreator(const Tag &t) const +{ + if( t.IsPrivate() && !t.IsPrivateCreator() ) + { + Tag pc = t.GetPrivateCreator(); + if( pc.GetElement() ) + { + const DataElement r(pc); + ConstIterator it = DES.find(r); + if( it == DES.end() ) + { + // FIXME, could this happen ? + return ""; + } + const DataElement &de = *it; + if( de.IsEmpty() ) return ""; + const ByteValue *bv = de.GetByteValue(); + assert( bv ); + std::string owner = std::string(bv->GetPointer(),bv->GetLength()); + // There should not be any trailing space character... + // TODO: tmp.erase(tmp.find_last_not_of(' ') + 1); + while( owner.size() && owner[owner.size()-1] == ' ' ) + { + // osirix/AbdominalCT/36382443 + owner.erase(owner.size()-1,1); + } + assert( owner.size() == 0 || owner[owner.size()-1] != ' ' ); + return owner; + } + } + return ""; +} + +Tag DataSet::ComputeDataElement(const PrivateTag & t) const +{ + gdcmDebugMacro( "Entering ComputeDataElement" ); + //assert( t.IsPrivateCreator() ); // No this is wrong to do the assert: eg. (0x07a1,0x000a,"ELSCINT1") + // is valid because we have not yet done the mapping, so 0xa < 0x10 fails but might not later on + const Tag start(t.GetGroup(), 0x0010 ); // First possible private creator (0x0 -> 0x9 are reserved...) + const DataElement r(start); + ConstIterator it = DES.lower_bound(r); + const char *refowner = t.GetOwner(); + assert( refowner ); + bool found = false; + while( it != DES.end() && it->GetTag().GetGroup() == t.GetGroup() && it->GetTag().GetElement() < 0x100 ) + { + //assert( it->GetTag().GetOwner() ); + const ByteValue * bv = it->GetByteValue(); + assert( bv ); + //std::cout << std::string(bv->GetPointer(), bv->GetLength() ) << std::endl; + //if( strcmp( bv->GetPointer(), refowner ) == 0 ) + std::string tmp(bv->GetPointer(),bv->GetLength()); + // trim trailing whitespaces: + tmp.erase(tmp.find_last_not_of(' ') + 1); + assert( tmp.size() == 0 || tmp[ tmp.size() - 1 ] != ' ' ); // FIXME + if( System::StrCaseCmp( tmp.c_str(), refowner ) == 0 ) + { + // found ! + found = true; + break; + } + ++it; + } + gdcmDebugMacro( "In compute found is:" << found ); + if (!found) return GetDEEnd().GetTag(); + // else + // ok we found the Private Creator Data Element, let's construct the proper data element + Tag copy = t; + copy.SetPrivateCreator( it->GetTag() ); + gdcmDebugMacro( "Compute found:" << copy ); + return copy; +} + +bool DataSet::FindDataElement(const PrivateTag &t) const +{ + return FindDataElement( ComputeDataElement(t) ); +} + +const DataElement& DataSet::GetDataElement(const PrivateTag &t) const +{ + return GetDataElement( ComputeDataElement(t) ); +} + +MediaStorage DataSet::GetMediaStorage() const +{ + // Let's check 0008,0016: + // D 0008|0016 [UI] [SOP Class UID] [1.2.840.10008.5.1.4.1.1.7 ] + // ==> [Secondary Capture Image Storage] + const Tag tsopclassuid(0x0008, 0x0016); + if( !FindDataElement( tsopclassuid) ) + { + gdcmDebugMacro( "No SOP Class UID" ); + return MediaStorage::MS_END; + } + const DataElement &de = GetDataElement(tsopclassuid); + if( de.IsEmpty() ) + { + gdcmDebugMacro( "Empty SOP Class UID" ); + return MediaStorage::MS_END; + } + std::string ts; + { + const ByteValue *bv = de.GetByteValue(); + assert( bv ); + if( bv->GetPointer() && bv->GetLength() ) + { + // Pad string with a \0 + ts = std::string(bv->GetPointer(), bv->GetLength()); + } + } + // Paranoid check: if last character of a VR=UI is space let's pretend this is a \0 + if( ts.size() ) + { + char &last = ts[ts.size()-1]; + if( last == ' ' ) + { + gdcmWarningMacro( "Media Storage Class UID: " << ts << " contained a trailing space character" ); + last = '\0'; + } + } + gdcmDebugMacro( "TS: " << ts ); + MediaStorage ms = MediaStorage::GetMSType(ts.c_str()); + if( ms == MediaStorage::MS_END ) + { + gdcmWarningMacro( "Media Storage Class UID: " << ts << " is unknow" ); + } + return ms; +} + +} // end namespace gdcm diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmDataSet.h b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmDataSet.h new file mode 100644 index 0000000..3ab6272 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmDataSet.h @@ -0,0 +1,340 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMDATASET_H +#define GDCMDATASET_H + +#include "gdcmDataElement.h" +#include "gdcmTag.h" +#include "gdcmVR.h" +#include "gdcmElement.h" +#include "gdcmMediaStorage.h" + +#include +#include + +namespace gdcm +{ +class GDCM_EXPORT DataElementException : public std::exception {}; + +class PrivateTag; +/** + * \brief Class to represent a Data Set (which contains Data Elements) + * A Data Set represents an instance of a real world Information Object + * \note + * DATA SET: + * Exchanged information consisting of a structured set of Attribute values + * directly or indirectly related to Information Objects. The value of each + * Attribute in a Data Set is expressed as a Data Element. + * A collection of Data Elements ordered by increasing Data Element Tag + * number that is an encoding of the values of Attributes of a real world + * object. + * \note + * Implementation note. If one do: + * DataSet ds; + * ds.SetLength(0); + * ds.Read(is); + * setting length to 0 actually means try to read is as if it was a root + * DataSet. Other value are undefined (nested dataset with undefined length) + * or defined length (different from 0) means nested dataset with defined + * length. + * + * \warning + * a DataSet does not have a Transfer Syntax type, only a File does. + */ +class GDCM_EXPORT DataSet +{ + friend class CSAHeader; +public: + typedef std::set DataElementSet; + typedef DataElementSet::const_iterator ConstIterator; + typedef DataElementSet::iterator Iterator; + typedef DataElementSet::size_type SizeType; + //typedef typename DataElementSet::iterator iterator; + ConstIterator Begin() const { return DES.begin(); } + Iterator Begin() { return DES.begin(); } + ConstIterator End() const { return DES.end(); } + Iterator End() { return DES.end(); } + const DataElementSet &GetDES() const { return DES; } + DataElementSet &GetDES() { return DES; } + void Clear() { + DES.clear(); + assert( DES.empty() ); + } + + SizeType Size() const { + return DES.size(); + } + + void Print(std::ostream &os, std::string const &indent = "") const { + // CT_Phillips_JPEG2K_Decompr_Problem.dcm has a SQ of length == 0 + //int s = DES.size(); + //assert( s ); + //std::copy(DES.begin(), DES.end(), + // std::ostream_iterator(os, "\n")); + ConstIterator it = DES.begin(); + for( ; it != DES.end(); ++it) + { + os << indent << *it << "\n"; + } + } + + template + unsigned int ComputeGroupLength(Tag const &tag) const + { + assert( tag.GetElement() == 0x0 ); + const DataElement r(tag); + ConstIterator it = DES.find(r); + unsigned int res = 0; + for( ++it; it != DES.end() + && it->GetTag().GetGroup() == tag.GetGroup(); ++it) + { + assert( it->GetTag().GetElement() != 0x0 ); + assert( it->GetTag().GetGroup() == tag.GetGroup() ); + res += it->GetLength(); + } + return res; + } + + template + VL GetLength() const { + if( DES.empty() ) return 0; + assert( !DES.empty() ); + VL ll = 0; + assert( ll == 0 ); + ConstIterator it = DES.begin(); + for( ; it != DES.end(); ++it) + { + assert( !(it->GetLength().IsUndefined()) ); + if ( it->GetTag() != Tag(0xfffe,0xe00d) ) + { + ll += it->GetLength(); + } + } + return ll; + } + /// Insert a DataElement in the DataSet. + /// \warning: Tag need to be >= 0x8 to be considered valid data element + void Insert(const DataElement& de) { + // FIXME: there is a special case where a dataset can have value < 0x8, see: + // $ gdcmdump --csa gdcmData/SIEMENS-JPEG-CorruptFrag.dcm + if( de.GetTag().GetGroup() >= 0x0008 || de.GetTag().GetGroup() == 0x4 ) + { + // prevent user error: + if( de.GetTag() == Tag(0xfffe,0xe00d) + || de.GetTag() == Tag(0xfffe,0xe0dd) + || de.GetTag() == Tag(0xfffe,0xe000) ) + { + } + else + { + InsertDataElement( de ); + } + } + else + { + gdcmErrorMacro( "Cannot add element with group < 0x0008 and != 0x4 in the dataset: " << de.GetTag() ); + } + } + /// Replace a dataelement with another one + void Replace(const DataElement& de) { + if( DES.find(de) != DES.end() ) DES.erase(de); + Insert(de); + } + /// Only replace a DICOM attribute when it is missing or empty + void ReplaceEmpty(const DataElement& de) { + ConstIterator it = DES.find(de); + if( it != DES.end() && it->IsEmpty() ) + DES.erase(de); + Insert(de); + } + /// Completely remove a dataelement from the dataset + SizeType Remove(const Tag& tag) { + DataElementSet::size_type count = DES.erase(tag); + assert( count == 0 || count == 1 ); + return count; + } + + /// Return the DataElement with Tag 't' + /// \warning: + /// This only search at the 'root level' of the DataSet + //DataElement& GetDataElement(const Tag &t) { + // DataElement r(t); + // Iterator it = DES.find(r); + // if( it != DES.end() ) + // return *it; + // return GetDEEnd(); + // } + const DataElement& GetDataElement(const Tag &t) const { + const DataElement r(t); + ConstIterator it = DES.find(r); + if( it != DES.end() ) + return *it; + return GetDEEnd(); + } + const DataElement& operator[] (const Tag &t) const { return GetDataElement(t); } + const DataElement& operator() (uint16_t group, uint16_t element) const { return GetDataElement( Tag(group,element) ); } + + /// Return the private creator of the private tag 't': + std::string GetPrivateCreator(const Tag &t) const; + + /// Look up if private tag 't' is present in the dataset: + bool FindDataElement(const PrivateTag &t) const; + /// Return the dataelement + const DataElement& GetDataElement(const PrivateTag &t) const; + + // DUMB: this only search within the level of the current DataSet + bool FindDataElement(const Tag &t) const { + const DataElement r(t); + //ConstIterator it = DES.find(r); + if( DES.find(r) != DES.end() ) + { + return true; + } + return false; + } + + // WARNING: + // This only search at the same level as the DataSet is ! + const DataElement& FindNextDataElement(const Tag &t) const { + const DataElement r(t); + ConstIterator it = DES.lower_bound(r); + if( it != DES.end() ) + return *it; + return GetDEEnd(); + } + + /// Returns if the dataset is empty + bool IsEmpty() const { return DES.empty(); }; + + DataSet& operator=(DataSet const &val) + { + DES = val.DES; + return *this; + } + +/* + template + void ExecuteOperation(TOperation & operation) { + assert( !DES.empty() ); + DataElementSet::iterator it = Begin(); + for( ; it != End(); ++it) + { + DataElement &de = (DataElement&)*it; + operation( de ); + } + } +*/ + + template + std::istream &ReadNested(std::istream &is); + + template + std::istream &Read(std::istream &is); + + template + std::istream &ReadUpToTag(std::istream &is, const Tag &t, std::set const & skiptags); + + template + std::istream &ReadUpToTagWithLength(std::istream &is, const Tag &t, std::set const & skiptags, VL & length); + + template + std::istream &ReadSelectedTags(std::istream &is, const std::set & tags, bool readvalues = true); + template + std::istream &ReadSelectedTagsWithLength(std::istream &is, const std::set & tags, VL & length, bool readvalues = true); + + template + std::istream &ReadSelectedPrivateTags(std::istream &is, const std::set & tags, bool readvalues = true); + template + std::istream &ReadSelectedPrivateTagsWithLength(std::istream &is, const std::set & tags, VL & length, bool readvalues = true); + + template + std::ostream const &Write(std::ostream &os) const; + + template + std::istream &ReadWithLength(std::istream &is, VL &length); + + MediaStorage GetMediaStorage() const; + +protected: + /* GetDEEnd is a Win32 only issue, one cannot use a dllexported + * static member data in an inline function, otherwise symbol + * will get reported as missing in any dll using the inlined function + */ + const DataElement& GetDEEnd() const; + + // This function is not safe, it does not check for the value of the tag + // so depending whether we are getting called from a dataset or file meta header + // the condition is different + void InsertDataElement(const DataElement& de) { + //if( de.GetTag() == Tag(0xfffe,0xe00d) ) return; + //if( de.GetTag() == Tag(0xfffe,0xe0dd) ) return; +#ifndef NDEBUG + std::pair pr = DES.insert(de); + if( pr.second == false ) + { + gdcmWarningMacro( "DataElement: " << de << " was already found, skipping duplicate entry.\n" + "Original entry kept is: " << *pr.first ); + } +#else + DES.insert(de); +#endif + assert( de.IsEmpty() || de.GetVL() == de.GetValue().GetLength() ); + } + +protected: + // Internal function, that will compute the actual Tag (if found) of + // a requested Private Tag (XXXX,YY,"PRIVATE") + Tag ComputeDataElement(const PrivateTag & t) const; + +private: + DataElementSet DES; + static DataElement DEEnd; + friend std::ostream& operator<<(std::ostream &_os, const DataSet &val); +}; +//----------------------------------------------------------------------------- +inline std::ostream& operator<<(std::ostream &os, const DataSet &val) +{ + val.Print(os); + return os; +} + +#if defined(SWIGPYTHON) || defined(SWIGCSHARP) || defined(SWIGJAVA) +/* + * HACK: I need this temp class to be able to manipulate a std::set from python, + * swig does not support wrapping of simple class like std::set... + */ +class SWIGDataSet +{ +public: + SWIGDataSet(DataSet &des):Internal(des),it(des.Begin()) {} + const DataElement& GetCurrent() const { return *it; } + void Start() { it = Internal.Begin(); } + bool IsAtEnd() const { return it == Internal.End(); } + void Next() { ++it; } +private: + DataSet & Internal; + DataSet::ConstIterator it; +}; +#endif /* SWIG */ + +/** + * \example SimplePrint.cs + * This is a C# example on how to use gdcm::SWIGDataSet + */ + +} // end namespace gdcm + +#include "gdcmDataSet.txx" + +#endif //GDCMDATASET_H diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmDataSet.txx b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmDataSet.txx new file mode 100644 index 0000000..beeb727 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmDataSet.txx @@ -0,0 +1,498 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMDATASET_TXX +#define GDCMDATASET_TXX + +#include "gdcmByteValue.h" +#include "gdcmPrivateTag.h" +#include "gdcmParseException.h" + +#include + +namespace gdcm +{ + template + std::istream &DataSet::ReadNested(std::istream &is) { + DataElement de; + const Tag itemDelItem(0xfffe,0xe00d); + assert( de.GetTag() != itemDelItem ); // precondition before while loop + try + { + while( de.Read(is) && de.GetTag() != itemDelItem ) // Keep that order please ! + { + //std::cerr << "DEBUG Nested: " << de << std::endl; + InsertDataElement( de ); + } + } + catch(ParseException &pe) + { + if( pe.GetLastElement().GetTag() == Tag(0xfffe,0xe0dd) ) + { + // BogusItemStartItemEnd.dcm + gdcmWarningMacro( "SQ End found but no Item end found" ); + de.SetTag( itemDelItem ); + is.seekg( -4, std::ios::cur ); + } + else + { + // MR_Philips_Intera_PrivateSequenceExplicitVR_in_SQ_2001_e05f_item_wrong_lgt_use_NOSHADOWSEQ.dcm + // Need to rethrow the exception...sigh + throw pe; + } + } + assert( de.GetTag() == itemDelItem ); + return is; + } + + template + std::istream &DataSet::Read(std::istream &is) { + DataElement de; + while( !is.eof() && de.Read(is) ) + { + //std::cerr << "DEBUG:" << de << std::endl; + InsertDataElement( de ); + } + return is; + } + + template + std::istream &DataSet::ReadUpToTag(std::istream &is, const Tag &t, const std::set & skiptags) { + DataElement de; + while( !is.eof() && de.template ReadPreValue(is, skiptags) ) + { + // If tag read was in skiptags then we should NOT add it: + if( skiptags.count( de.GetTag() ) == 0 ) + { + de.template ReadValue(is, skiptags); + InsertDataElement( de ); + } + else + { + assert( is.good() ); + if( de.GetTag() != t ) + is.seekg( de.GetVL(), std::ios::cur ); + } + // tag was found, we can exit the loop: + if ( t <= de.GetTag() ) + { + assert( is.good() ); + break; + } + } + return is; + } + + template + std::istream &DataSet::ReadUpToTagWithLength(std::istream &is, const Tag &t, std::set const & skiptags, VL & length) { + DataElement de; + while( !is.eof() && de.template ReadPreValue(is, skiptags) ) + { + // If tag read was in skiptags then we should NOT add it: + if( skiptags.count( de.GetTag() ) == 0 ) + { + de.template ReadValueWithLength(is, length, skiptags); + InsertDataElement( de ); + } + else + { + assert( is.good() ); + if( de.GetTag() != t ) + is.seekg( de.GetVL(), std::ios::cur ); + } + // tag was found, we can exit the loop: + if ( t <= de.GetTag() ) + { + assert( is.good() ); + break; + } + } + return is; + } + + template + std::istream &DataSet::ReadSelectedTags(std::istream &inputStream, const std::set & selectedTags, bool readvalues ) { + if ( ! (selectedTags.empty() || inputStream.fail()) ) + { + const Tag maxTag = *(selectedTags.rbegin()); + std::set tags = selectedTags; + DataElement dataElem; + + while( !inputStream.eof() ) + { + static_cast(dataElem).template ReadPreValue(inputStream); + const Tag& tag = dataElem.GetTag(); + if ( inputStream.fail() || maxTag < tag ) + { + if( inputStream.good() ) + { + const int l = dataElem.GetVR().GetLength(); + inputStream.seekg( - 4 - 2 * l, std::ios::cur ); + } + else + { + inputStream.clear(); + inputStream.seekg( 0, std::ios::end ); + } + // Failed to read the tag, or the read tag exceeds the maximum. + // As we assume ascending tag ordering, we can exit the loop. + break; + } + static_cast(dataElem).template ReadValue(inputStream, readvalues); + + const std::set::iterator found = tags.find(tag); + + if ( found != tags.end() ) + { + InsertDataElement( dataElem ); + tags.erase(found); + + if ( tags.empty() ) + { + // All selected tags were found, we can exit the loop: + break; + } + } + if ( ! (tag < maxTag ) ) + { + // The maximum tag was encountered, and as we assume + // ascending tag ordering, we can exit the loop: + break; + } + } + } + assert( inputStream.good() ); + return inputStream; + } + + template + std::istream &DataSet::ReadSelectedPrivateTags(std::istream &inputStream, const std::set & selectedPTags, bool readvalues) { + if ( ! (selectedPTags.empty() || inputStream.fail()) ) + { + assert( selectedPTags.size() == 1 ); + const PrivateTag refPTag = *(selectedPTags.rbegin()); + PrivateTag nextPTag = refPTag; + nextPTag.SetElement( (uint16_t)(nextPTag.GetElement() + 0x1) ); + assert( nextPTag.GetElement() & 0x00ff ); // no wrap please + Tag maxTag; + maxTag.SetPrivateCreator( nextPTag ); + DataElement dataElem; + + while( !inputStream.eof() ) + { + static_cast(dataElem).template ReadPreValue(inputStream); + const Tag& tag = dataElem.GetTag(); + if ( inputStream.fail() || maxTag < tag ) + { + if( inputStream.good() ) + { + const int l = dataElem.GetVR().GetLength(); + inputStream.seekg( - 4 - 2 * l, std::ios::cur ); + } + else + { + inputStream.clear(); + inputStream.seekg( 0, std::ios::end ); + } + // Failed to read the tag, or the read tag exceeds the maximum. + // As we assume ascending tag ordering, we can exit the loop. + break; + } + static_cast(dataElem).template ReadValue(inputStream, readvalues); + + if ( inputStream.fail() ) + { + // Failed to read the value. + break; + } + + if( tag.GetPrivateCreator() == refPTag ) + { + DES.insert( dataElem ); + } + if ( ! (tag < maxTag ) ) + { + // The maximum group was encountered, and as we assume + // ascending tag ordering, we can exit the loop: + break; + } + } + } + return inputStream; + } + + + template + std::istream &DataSet::ReadSelectedTagsWithLength(std::istream &inputStream, const std::set & selectedTags, VL & length, bool readvalues ) + { + (void)length; + if ( ! selectedTags.empty() ) + { + const Tag maxTag = *(selectedTags.rbegin()); + std::set tags = selectedTags; + DataElement dataElem; + + while( !inputStream.eof() ) + { + static_cast(dataElem).template ReadPreValue(inputStream); + const Tag tag = dataElem.GetTag(); + if ( inputStream.fail() || maxTag < tag ) + { + if( inputStream.good() ) + { + const int l = dataElem.GetVR().GetLength(); + inputStream.seekg( - 4 - 2 * l, std::ios::cur ); + } + else + { + inputStream.clear(); + inputStream.seekg( 0, std::ios::end ); + } + // Failed to read the tag, or the read tag exceeds the maximum. + // As we assume ascending tag ordering, we can exit the loop. + break; + } + static_cast(dataElem).template ReadValue(inputStream, readvalues); + + if ( inputStream.fail() ) + { + // Failed to read the value. + break; + } + + const std::set::iterator found = tags.find(tag); + + if ( found != tags.end() ) + { + InsertDataElement( dataElem ); + tags.erase(found); + + if ( tags.empty() ) + { + // All selected tags were found, we can exit the loop: + break; + } + } + if ( ! (tag < maxTag ) ) + { + // The maximum tag was encountered, and as we assume + // ascending tag ordering, we can exit the loop: + break; + } + } + } + return inputStream; + } + + template + std::istream &DataSet::ReadSelectedPrivateTagsWithLength(std::istream &inputStream, const std::set & selectedPTags, VL & length, bool readvalues ) { + (void)length; + if ( ! (selectedPTags.empty() || inputStream.fail()) ) + { + assert( selectedPTags.size() == 1 ); + const PrivateTag refPTag = *(selectedPTags.rbegin()); + PrivateTag nextPTag = refPTag; + nextPTag.SetElement( (uint16_t)(nextPTag.GetElement() + 0x1) ); + assert( nextPTag.GetElement() ); // no wrap please + Tag maxTag; + maxTag.SetPrivateCreator( nextPTag ); + DataElement dataElem; + + while( !inputStream.eof() ) + { + static_cast(dataElem).template ReadPreValue(inputStream); + const Tag& tag = dataElem.GetTag(); + if ( inputStream.fail() || maxTag < tag ) + { + if( inputStream.good() ) + { + const int l = dataElem.GetVR().GetLength(); + inputStream.seekg( - 4 - 2 * l, std::ios::cur ); + } + else + { + inputStream.clear(); + inputStream.seekg( 0, std::ios::end ); + } + // Failed to read the tag, or the read tag exceeds the maximum. + // As we assume ascending tag ordering, we can exit the loop. + break; + } + static_cast(dataElem).template ReadValue(inputStream, readvalues); + + if ( inputStream.fail() ) + { + // Failed to read the value. + break; + } + + //const std::set::iterator found = selectedPTags.find(tag.GetGroup()); + + //if ( found != groups.end() ) + if( tag.GetPrivateCreator() == refPTag ) + { + InsertDataElement( dataElem ); + } + if ( ! (tag < maxTag ) ) + { + // The maximum group was encountered, and as we assume + // ascending tag ordering, we can exit the loop: + break; + } + } + } + return inputStream; + } + + template + std::istream &DataSet::ReadWithLength(std::istream &is, VL &length) { + DataElement de; + VL l = 0; + //std::cout << "ReadWithLength Length: " << length << std::endl; + VL locallength = length; + const std::streampos startpos = is.tellg(); + try + { + while( l != locallength && de.ReadWithLength(is, locallength)) + { + //std::cout << "Nested: " << de << std::endl; +#ifndef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + assert( de.GetTag() != Tag(0xfffe,0xe000) ); // We should not be reading the next item... +#endif + InsertDataElement( de ); + const VL oflen = de.GetLength(); + l += oflen; + const std::streampos curpos = is.tellg(); + //assert( (curpos - startpos) == l || (curpos - startpos) + 1 == l ); + + //std::cout << "l:" << l << std::endl; + //assert( !de.GetVL().IsUndefined() ); + //std::cerr << "DEBUG: " << de.GetTag() << " "<< de.GetLength() << + // "," << de.GetVL() << "," << l << std::endl; + // Bug_Philips_ItemTag_3F3F + // (0x2005, 0x1080): for some reason computation of length fails... + if( l == 70 && locallength == 63 ) + { + gdcmWarningMacro( "PMS: Super bad hack. Changing length" ); + length = locallength = 140; + } + if( (curpos - startpos) + 1 == l ) + { + gdcmDebugMacro( "Papyrus odd padding detected" ); + throw Exception( "Papyrus odd padding" ); + } + if( l > locallength ) + { + if( (curpos - startpos) == locallength ) + { + // this means that something went wrong somewhere, and upon recomputing the length + // we found a discrepandy with own vendor made its layout. + // update the length directly + locallength = length = l; + throw Exception( "Changed Length" ); + } + else + { + gdcmDebugMacro( "Out of Range SQ detected: " << l << " while max: " << locallength ); + throw Exception( "Out of Range" ); + } + } + } + } + catch(ParseException &pe) + { + if( pe.GetLastElement().GetTag() == Tag(0xfffe,0xe000) ) + { + // gdcm-MR-PHILIPS-16-Multi-Seq.dcm + // Long story short, I think Philips engineer inserted 0xfffe,0x0000 instead of an item start element + // assert( FindDataElement( Tag(0xfffe,0x0000) ) == false ); + is.seekg(-6, std::ios::cur ); + length = locallength = l; + } + else + { + // Could be the famous : + // gdcmDataExtra/gdcmBreakers/BuggedDicomWorksImage_Hopeless.dcm + // let's just give up: + gdcmErrorMacro( "Last Tag is : " << pe.GetLastElement().GetTag() ); + throw Exception( "Unhandled" ); + } + } + catch(Exception &pe) + { + if( strcmp( pe.GetDescription(), "Out of Range" ) == 0 ) + { + // BogugsItemAndSequenceLength.dcm + // This is most likely the "Out of Range" one + // Cautiously read until we find the next item starter and then stop. + //std::cout << "Length read was:" << l << " should be at most:" << locallength ; + while( de.Read(is) && de.GetTag() != Tag(0xfffe,0xe000) && de.GetTag().GetElement() != 0x0 ) + { + //std::cout << "Nested2: " << de << std::endl; + InsertDataElement( de ); + l += de.GetLength(); + //std::cout << l << std::endl; + } + // seek back since we read the next item starter: + int iteml = de.GetLength(); + //assert( de.GetTag().GetElement() ); + if( !de.GetTag().GetElement() ) + { + assert( iteml == 12 ); (void)iteml; + is.seekg( -12, std::ios::cur ); + } + else + { + //assert( de.GetTag() == Tag(0xfffe,0xe000) ); + is.seekg( -4, std::ios::cur ); + } + // let's fix the length now: + length = locallength = l; + gdcmWarningMacro( "Item length is wrong" ); + throw Exception( "Changed Length" ); + } + else if( strcmp( pe.GetDescription(), "Papyrus odd padding" ) == 0 ) + { + is.get(); + throw Exception( "Changed Length" ); + } + else + { + // re throw + throw pe; + } + } + + // technically we could only do this assert if the dataset did not contains + // duplicate data elements so only do a <= instead: + //assert( l == locallength ); + assert( l <= locallength ); + return is; + } + + template + std::ostream const &DataSet::Write(std::ostream &os) const { + typename DataSet::ConstIterator it = DES.begin(); + for( ; it != DES.end(); ++it) + { + const DataElement & de = *it; + //if( de.GetTag().GetGroup() >= 0x0008 || de.GetTag().GetGroup() == 0x0002 ) + { + de.Write(os); + } + } + return os; + } +} // end namespace gdcm + +#endif // GDCMDATASET_TXX diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmDataSetEvent.cxx b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmDataSetEvent.cxx new file mode 100644 index 0000000..f6684a9 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmDataSetEvent.cxx @@ -0,0 +1,18 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmDataSetEvent.h" + +namespace gdcm +{ +} // end namespace gdcm diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmDataSetEvent.h b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmDataSetEvent.h new file mode 100644 index 0000000..debf762 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmDataSetEvent.h @@ -0,0 +1,52 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMDATASETEVENT_H +#define GDCMDATASETEVENT_H + +#include "gdcmEvent.h" +#include "gdcmDataSet.h" + +namespace gdcm +{ + +/** + * \brief DataSetEvent + * Special type of event triggered during the DataSet store/move process + * + * \see + */ +class DataSetEvent : public AnyEvent +{ +public: + typedef DataSetEvent Self; + typedef AnyEvent Superclass; + DataSetEvent(DataSet const *ds = NULL):m_DataSet(ds) {} + virtual ~DataSetEvent() {} + virtual const char * GetEventName() const { return "DataSetEvent"; } + virtual bool CheckEvent(const ::gdcm::Event* e) const + { return (dynamic_cast(e) == NULL ? false : true) ; } + virtual ::gdcm::Event* MakeObject() const + { return new Self; } + DataSetEvent(const Self&s) : AnyEvent(s){}; + + DataSet const & GetDataSet() const { return *m_DataSet; } +private: + void operator=(const Self&); + const DataSet *m_DataSet; +}; + + +} // end namespace gdcm + +#endif //GDCMANONYMIZEEVENT_H diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmElement.h b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmElement.h new file mode 100644 index 0000000..0d70b9d --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmElement.h @@ -0,0 +1,741 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMELEMENT_H +#define GDCMELEMENT_H + +#include "gdcmTypes.h" +#include "gdcmVR.h" +#include "gdcmTag.h" +#include "gdcmVM.h" +#include "gdcmByteValue.h" +#include "gdcmDataElement.h" +#include "gdcmSwapper.h" + +#include +#include +#include +#include +#include +#include + +namespace gdcm +{ + +// Forward declaration +/** + * \brief EncodingImplementation + * + * \note TODO + */ +template class EncodingImplementation; + + +/** + * \brief A class which is used to produce compile errors for an + * invalid combination of template parameters. + * + * Invalid combinations have specialized declarations with no + * definition. + */ +template +class ElementDisableCombinations {}; +template <> +class ElementDisableCombinations {}; +template <> +class ElementDisableCombinations {}; +// Make it impossible to compile these other cases +template +class ElementDisableCombinations; +template +class ElementDisableCombinations; + +/** + * \brief Element class + * + * \note TODO + */ +template +class Element +{ + enum { ElementDisableCombinationsCheck = sizeof ( ElementDisableCombinations ) }; +public: + typename VRToType::Type Internal[VMToLength::Length]; + typedef typename VRToType::Type Type; + + static VR GetVR() { return (VR::VRType)TVR; } + static VM GetVM() { return (VM::VMType)TVM; } + + unsigned long GetLength() const { + return VMToLength::Length; + } + // Implementation of Print is common to all Mode (ASCII/Binary) + // TODO: Can we print a \ when in ASCII...well I don't think so + // it would mean we used a bad VM then, right ? + void Print(std::ostream &_os) const { + _os << Internal[0]; // VM is at least garantee to be one + for(int i=1; i::Length; ++i) + _os << "," << Internal[i]; + } + + const typename VRToType::Type *GetValues() const { + return Internal; + } + const typename VRToType::Type &GetValue(unsigned int idx = 0) const { + assert( idx < VMToLength::Length ); + return Internal[idx]; + } + typename VRToType::Type &GetValue(unsigned int idx = 0) { + assert( idx < VMToLength::Length ); + return Internal[idx]; + } + typename VRToType::Type operator[] (unsigned int idx) const { + return GetValue(idx); + } + void SetValue(typename VRToType::Type v, unsigned int idx = 0) { + assert( idx < VMToLength::Length ); + Internal[idx] = v; + } + + void SetFromDataElement(DataElement const &de) { + const ByteValue *bv = de.GetByteValue(); + if( !bv ) return; +#ifdef GDCM_WORDS_BIGENDIAN + if( de.GetVR() == VR::UN /*|| de.GetVR() == VR::INVALID*/ ) +#else + if( de.GetVR() == VR::UN || de.GetVR() == VR::INVALID ) +#endif + { + Set(de.GetValue()); + } + else + { + SetNoSwap(de.GetValue()); + } + } + + DataElement GetAsDataElement() const { + DataElement ret; + std::ostringstream os; + EncodingImplementation::Mode>::Write(Internal, + GetLength(),os); + ret.SetVR( (VR::VRType)TVR ); + assert( ret.GetVR() != VR::SQ ); + if( (VR::VRType)VRToEncoding::Mode == VR::VRASCII ) + { + if( GetVR() != VR::UI ) + { + if( os.str().size() % 2 ) + { + os << " "; + } + } + } + VL::Type osStrSize = (VL::Type)os.str().size(); + ret.SetByteValue( os.str().c_str(), osStrSize ); + + return ret; + } + + void Read(std::istream &_is) { + return EncodingImplementation::Mode>::Read(Internal, + GetLength(),_is); + } + void Write(std::ostream &_os) const { + return EncodingImplementation::Mode>::Write(Internal, + GetLength(),_os); + } + + // FIXME: remove this function + // this is only used in gdcm::SplitMosaicFilter / to pass value of a CSAElement + void Set(Value const &v) { + const ByteValue *bv = dynamic_cast(&v); + if( bv ) { + //memcpy(Internal, bv->GetPointer(), bv->GetLength()); + std::stringstream ss; + std::string s = std::string( bv->GetPointer(), bv->GetLength() ); + ss.str( s ); + EncodingImplementation::Mode>::Read(Internal, + GetLength(),ss); + } + } +protected: + void SetNoSwap(Value const &v) { + const ByteValue *bv = dynamic_cast(&v); + assert( bv ); // That would be bad... + //memcpy(Internal, bv->GetPointer(), bv->GetLength()); + std::stringstream ss; + std::string s = std::string( bv->GetPointer(), bv->GetLength() ); + ss.str( s ); + EncodingImplementation::Mode>::ReadNoSwap(Internal, + GetLength(),ss); + } +}; + +struct ignore_char { + ignore_char(char c): m_char(c) {} + char m_char; +}; +ignore_char const backslash('\\'); + + inline std::istream& operator>> (std::istream& in, ignore_char const& ic) { + if (!in.eof()) + in.clear(in.rdstate() & ~std::ios_base::failbit); + if (in.get() != ic.m_char) + in.setstate(std::ios_base::failbit); + return in; + } + + +// Implementation to perform formatted read and write +template<> class EncodingImplementation { +public: + template // FIXME this should be VRToType::Type + static inline void ReadComputeLength(T* data, unsigned int &length, + std::istream &_is) { + assert( data ); + //assert( length ); // != 0 + length = 0; + assert( _is ); +#if 0 + char sep; + while( _is >> data[length++] ) + { + // Get the separator in between the values + assert( _is ); + _is.get(sep); + assert( sep == '\\' || sep == ' ' ); // FIXME: Bad use of assert + if( sep == ' ' ) length--; // FIXME + } +#else + while( _is >> std::ws >> data[length++] >> std::ws >> backslash ) + { + } +#endif + } + + template // FIXME this should be VRToType::Type + static inline void Read(T* data, unsigned long length, + std::istream &_is) { + assert( data ); + assert( length ); // != 0 + assert( _is ); + // FIXME BUG: what if >> operation fails ? + // gdcmData/MR00010001.dcm / SpacingBetweenSlices + _is >> std::ws >> data[0]; + char sep; + //std::cout << "GetLength: " << af->GetLength() << std::endl; + for(unsigned long i=1; i> std::ws >> sep; //_is.get(sep); + assert( sep == '\\' ); // FIXME: Bad use of assert + _is >> std::ws >> data[i]; + } + } + + template + static inline void ReadNoSwap(T* data, unsigned long length, + std::istream &_is) { + Read(data,length,_is); +} + template + static inline void Write(const T* data, unsigned long length, + std::ostream &_os) { + assert( data ); + assert( length ); + assert( _os ); + _os << data[0]; + for(unsigned long i=1; i +std::string to_string ( Float data ) { + std::stringstream in; + // in.imbue(std::locale::classic()); // This is not required AFAIK + int const digits = + static_cast< int >( + - std::log( std::numeric_limits::epsilon() ) + / std::log( 10.0 ) ); + if ( in << std::dec << std::setprecision(/*2+*/digits) << data ) { + return ( in.str() ); + } else { + throw "Impossible Conversion"; // should not happen ... + } +} + +/* Writing VR::DS is not that easy after all */ +// http://groups.google.com/group/comp.lang.c++/browse_thread/thread/69ccd26f000a0802 +template<> inline void EncodingImplementation::Write(const float * data, unsigned long length, std::ostream &_os) { + assert( data ); + assert( length ); + assert( _os ); + _os << to_string(data[0]); + for(unsigned long i=1; i inline void EncodingImplementation::Write(const double* data, unsigned long length, std::ostream &_os) { + assert( data ); + assert( length ); + assert( _os ); + _os << to_string(data[0]); + for(unsigned long i=1; i class EncodingImplementation { +public: + template // FIXME this should be VRToType::Type + static inline void ReadComputeLength(T* data, unsigned int &length, + std::istream &_is) { + const unsigned int type_size = sizeof(T); + assert( data ); // Can we read from pointer ? + //assert( length ); + length /= type_size; + assert( _is ); // Is stream valid ? + _is.read( reinterpret_cast(data+0), type_size); + for(unsigned long i=1; i(data+i), type_size ); + } + } + template + static inline void ReadNoSwap(T* data, unsigned long length, + std::istream &_is) { + const unsigned int type_size = sizeof(T); + assert( data ); // Can we read from pointer ? + assert( length ); + assert( _is ); // Is stream valid ? + _is.read( reinterpret_cast(data+0), type_size); + for(unsigned long i=1; i(data+i), type_size ); + } + //ByteSwap::SwapRangeFromSwapCodeIntoSystem(data, + // _is.GetSwapCode(), length); + //SwapperNoOp::SwapArray(data,length); + } + template + static inline void Read(T* data, unsigned long length, + std::istream &_is) { + const unsigned int type_size = sizeof(T); + assert( data ); // Can we read from pointer ? + assert( length ); + assert( _is ); // Is stream valid ? + _is.read( reinterpret_cast(data+0), type_size); + for(unsigned long i=1; i(data+i), type_size ); + } + //ByteSwap::SwapRangeFromSwapCodeIntoSystem(data, + // _is.GetSwapCode(), length); + SwapperNoOp::SwapArray(data,length); + } + template + static inline void Write(const T* data, unsigned long length, + std::ostream &_os) { + const unsigned int type_size = sizeof(T); + assert( data ); // Can we write into pointer ? + assert( length ); + assert( _os ); // Is stream valid ? + //ByteSwap::SwapRangeFromSwapCodeIntoSystem((T*)data, + // _os.GetSwapCode(), length); + T swappedData = SwapperNoOp::Swap(data[0]); + _os.write( reinterpret_cast(&swappedData), type_size); + for(unsigned long i=1; i(&swappedData), type_size ); + } + //ByteSwap::SwapRangeFromSwapCodeIntoSystem((T*)data, + // _os.GetSwapCode(), length); + } +}; + +// For particular case for ASCII string +// WARNING: This template explicitely instanciates a particular +// EncodingImplementation THEREFORE it is required to be declared after the +// EncodingImplementation is needs (doh!) +#if 0 +template +class Element +{ +public: + Element(const char array[]) + { + unsigned int i = 0; + const char sep = '\\'; + std::string sarray = array; + std::string::size_type pos1 = 0; + std::string::size_type pos2 = sarray.find(sep, pos1+1); + while(pos2 != std::string::npos) + { + Internal[i++] = sarray.substr(pos1, pos2-pos1); + pos1 = pos2+1; + pos2 = sarray.find(sep, pos1+1); + } + Internal[i] = sarray.substr(pos1, pos2-pos1); + // Shouldn't we do the contrary, since we know how many separators + // (and default behavior is to discard anything after the VM declared + assert( GetLength()-1 == i ); + } + + unsigned long GetLength() const { + return VMToLength::Length; + } + // Implementation of Print is common to all Mode (ASCII/Binary) + void Print(std::ostream &_os) const { + _os << Internal[0]; // VM is at least garantee to be one + for(int i=1; i::Length; ++i) + _os << "," << Internal[i]; + } + + void Read(std::istream &_is) { + EncodingImplementation::Read(Internal, GetLength(),_is); + } + void Write(std::ostream &_os) const { + EncodingImplementation::Write(Internal, GetLength(),_os); + } +private: + typename String Internal[VMToLength::Length]; +}; + +template< int TVM> +class Element : public StringElement +{ + enum { ElementDisableCombinationsCheck = sizeof ( ElementDisableCombinations ) }; +}; +#endif + +// Implementation for the undefined length (dynamically allocated array) +template +class Element +{ + enum { ElementDisableCombinationsCheck = sizeof ( ElementDisableCombinations ) }; +public: + // This the way to prevent default initialization + explicit Element() { Internal=0; Length=0; Save = false; } + ~Element() { + if( Save ) { + delete[] Internal; + } + Internal = 0; + } + + static VR GetVR() { return (VR::VRType)TVR; } + static VM GetVM() { return VM::VM1_n; } + + // Length manipulation + // SetLength should really be protected anyway...all operation + // should go through SetArray + unsigned long GetLength() const { return Length; } + typedef typename VRToType::Type Type; + + void SetLength(unsigned long len) { + const unsigned int size = sizeof(Type); + if( len ) { + if( len > Length ) { + // perform realloc + assert( (len / size) * size == len ); + Type *internal = new Type[len / size]; + assert( Save == false ); + Save = true; // ???? + if( Internal ) + { + memcpy(internal, Internal, len); + delete[] Internal; + } + Internal = internal; + } + } + Length = len / size; + } + + // If save is set to zero user should not delete the pointer + //void SetArray(const typename VRToType::Type *array, int len, bool save = false) + void SetArray(const Type *array, unsigned long len, + bool save = false) { + if( save ) { + SetLength(len); // realloc + memcpy(Internal, array, len/*/sizeof(Type)*/); + assert( Save == false ); + } + else { + // TODO rewrite this stupid code: + assert( Length == 0 ); + assert( Internal == 0 ); + assert( Save == false ); + Length = len / sizeof(Type); + //assert( (len / sizeof(Type)) * sizeof(Type) == len ); + // MR00010001.dcm is a tough kid: 0019,105a is supposed to be VR::FL, VM::VM3 but + // length is 14 bytes instead of 12 bytes. Simply consider value is total garbage. + if( (len / sizeof(Type)) * sizeof(Type) != len ) { Internal = 0; Length = 0; } + else Internal = const_cast(array); + } + Save = save; + } + void SetValue(typename VRToType::Type v, unsigned int idx = 0) { + assert( idx < Length ); + Internal[idx] = v; + } + const typename VRToType::Type &GetValue(unsigned int idx = 0) const { + assert( idx < Length ); + return Internal[idx]; + } + typename VRToType::Type &GetValue(unsigned int idx = 0) { + //assert( idx < Length ); + return Internal[idx]; + } + typename VRToType::Type operator[] (unsigned int idx) const { + return GetValue(idx); + } + void Set(Value const &v) { + const ByteValue *bv = dynamic_cast(&v); + assert( bv ); // That would be bad... + if( (VR::VRType)(VRToEncoding::Mode) == VR::VRBINARY ) + { + const Type* array = (Type*)bv->GetPointer(); + if( array ) { + assert( array ); // That would be bad... + assert( Internal == 0 ); + SetArray(array, bv->GetLength() ); } + } + else + { + std::stringstream ss; + std::string s = std::string( bv->GetPointer(), bv->GetLength() ); + ss.str( s ); + EncodingImplementation::Mode>::Read(Internal, + GetLength(),ss); + } + } + void SetFromDataElement(DataElement const &de) { + const ByteValue *bv = de.GetByteValue(); + if( !bv ) return; +#ifdef GDCM_WORDS_BIGENDIAN + if( de.GetVR() == VR::UN /*|| de.GetVR() == VR::INVALID*/ ) +#else + if( de.GetVR() == VR::UN || de.GetVR() == VR::INVALID ) +#endif + { + Set(de.GetValue()); + } + else + { + SetNoSwap(de.GetValue()); + } + } + + + // Need to be placed after definition of EncodingImplementation + void WriteASCII(std::ostream &os) const { + return EncodingImplementation::Write(Internal, GetLength(), os); + } + + // Implementation of Print is common to all Mode (ASCII/Binary) + void Print(std::ostream &_os) const { + assert( Length ); + assert( Internal ); + _os << Internal[0]; // VM is at least garantee to be one + const unsigned long length = GetLength() < 25 ? GetLength() : 25; + for(unsigned long i=1; i::Mode>::Read(Internal, + GetLength(),_is); + } + //void ReadComputeLength(std::istream &_is) { + // if( !Internal ) return; + // EncodingImplementation::Mode>::ReadComputeLength(Internal, + // Length,_is); + // } + void Write(std::ostream &_os) const { + EncodingImplementation::Mode>::Write(Internal, + GetLength(),_os); + } + + DataElement GetAsDataElement() const { + DataElement ret; + ret.SetVR( (VR::VRType)TVR ); + assert( ret.GetVR() != VR::SQ ); + if( Internal ) + { + std::ostringstream os; + EncodingImplementation::Mode>::Write(Internal, + GetLength(),os); + if( (VR::VRType)VRToEncoding::Mode == VR::VRASCII ) + { + if( GetVR() != VR::UI ) + { + if( os.str().size() % 2 ) + { + os << " "; + } + } + } + VL::Type osStrSize = (VL::Type)os.str().size(); + ret.SetByteValue( os.str().c_str(), osStrSize ); + } + return ret; + } + + Element(const Element&_val) { + if( this != &_val) { + *this = _val; + } + } + + Element &operator=(const Element &_val) { + Length = 0; // SYITF + Internal = 0; + SetArray(_val.Internal, _val.Length, true); + return *this; + } +protected: + void SetNoSwap(Value const &v) { + const ByteValue *bv = dynamic_cast(&v); + assert( bv ); // That would be bad... + if( (VR::VRType)(VRToEncoding::Mode) == VR::VRBINARY ) + { + const Type* array = (Type*)bv->GetPointer(); + if( array ) { + assert( array ); // That would be bad... + assert( Internal == 0 ); + SetArray(array, bv->GetLength() ); } + } + else + { + std::stringstream ss; + std::string s = std::string( bv->GetPointer(), bv->GetLength() ); + ss.str( s ); + EncodingImplementation::Mode>::ReadNoSwap(Internal, + GetLength(),ss); + } + } + +private: + typename VRToType::Type *Internal; + unsigned long Length; // unsigned int ?? + bool Save; +}; + +//template +//class Element : public Element {}; + +// Partial specialization for derivatives of 1-n : 2-n, 3-n ... +template +class Element : public Element +{ +public: + typedef Element Parent; + void SetLength(int len) { + if( len != 1 || len != 2 ) return; + Parent::SetLength(len); + } +}; +template +class Element : public Element +{ + enum { ElementDisableCombinationsCheck = sizeof ( ElementDisableCombinations ) }; +public: + typedef Element Parent; + void SetLength(int len) { + if( len <= 1 ) return; + Parent::SetLength(len); + } +}; +template +class Element : public Element +{ + enum { ElementDisableCombinationsCheck = sizeof ( ElementDisableCombinations ) }; +public: + typedef Element Parent; + void SetLength(int len) { + if( len % 2 ) return; + Parent::SetLength(len); + } +}; +template +class Element : public Element +{ + enum { ElementDisableCombinationsCheck = sizeof ( ElementDisableCombinations ) }; +public: + typedef Element Parent; + void SetLength(int len) { + if( len <= 2 ) return; + Parent::SetLength(len); + } +}; +template +class Element : public Element +{ + enum { ElementDisableCombinationsCheck = sizeof ( ElementDisableCombinations ) }; +public: + typedef Element Parent; + void SetLength(int len) { + if( len % 3 ) return; + Parent::SetLength(len); + } +}; + + +//template struct VRToLength; +//template <> struct VRToLength +//{ enum { Length = VM::VM1 }; } +//template<> +//class Element : public Element::Length > + +// only 0010 1010 AS 1 Patient's Age +template<> +class Element +{ + enum { ElementDisableCombinationsCheck = sizeof ( ElementDisableCombinations ) }; +public: + char Internal[VMToLength::Length * sizeof( VRToType::Type )]; + void Print(std::ostream &_os) const { + _os << Internal; + } + unsigned long GetLength() const { + return VMToLength::Length; + } +}; + + +template <> +class Element : public Element {}; + +// Same for OW: +template <> +class Element : public Element {}; + + +} // namespace gdcm + +#endif //GDCMELEMENT_H diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmExplicitDataElement.cxx b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmExplicitDataElement.cxx new file mode 100644 index 0000000..3235833 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmExplicitDataElement.cxx @@ -0,0 +1,65 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmExplicitDataElement.h" +#include "gdcmSequenceOfItems.h" +#include "gdcmSequenceOfFragments.h" + +namespace gdcm +{ + +//----------------------------------------------------------------------------- + +VL ExplicitDataElement::GetLength() const +{ + if( ValueLengthField.IsUndefined() ) + { + assert( ValueField->GetLength().IsUndefined() ); + Value *p = ValueField; + // If this is a SQ we need to compute it's proper length + SequenceOfItems *sq = dynamic_cast(p); + // TODO can factor the code: + if( sq ) + { + const VL sqlen = sq->ComputeLength(); + assert( sqlen % 2 == 0 ); + return TagField.GetLength() + VRField.GetLength() + + ValueLengthField.GetLength() + sqlen; + } + SequenceOfFragments *sf = dynamic_cast(p); + if( sf ) + { + assert( VRField & VR::OB_OW ); // VR::INVALID is not possible AFAIK... + const VL sflen = sf->ComputeLength(); + assert( sflen % 2 == 0 ); + return TagField.GetLength() + VRField.GetLength() + + ValueLengthField.GetLength() + sflen; + } + assert(0); + return 0; + } + else + { + // Each time VR::GetLength() is 2 then Value Length is coded in 2 + // 4 then Value Length is coded in 4 + assert( !ValueField || ValueField->GetLength() == ValueLengthField ); + const bool vr16bitsimpossible = (VRField & VR::VL16) && (ValueLengthField > (uint32_t)VL::GetVL16Max()); + + if( vr16bitsimpossible || VRField == VR::INVALID ) + return TagField.GetLength() + 2*VR::GetLength(VR::UN) + ValueLengthField; + return TagField.GetLength() + 2*VRField.GetLength() + ValueLengthField; + } +} + + +} // end namespace gdcm diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmExplicitDataElement.h b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmExplicitDataElement.h new file mode 100644 index 0000000..e9818b2 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmExplicitDataElement.h @@ -0,0 +1,50 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMEXPLICITDATAELEMENT_H +#define GDCMEXPLICITDATAELEMENT_H + +#include "gdcmDataElement.h" + +namespace gdcm +{ +/** + * \brief Class to read/write a DataElement as Explicit Data Element + * \note bla + */ +class GDCM_EXPORT ExplicitDataElement : public DataElement +{ +public: + VL GetLength() const; + + template + std::istream &Read(std::istream &is); + + template + std::istream &ReadPreValue(std::istream &is); + + template + std::istream &ReadValue(std::istream &is, bool readvalues = true); + + template + std::istream &ReadWithLength(std::istream &is, VL & length); + + template + const std::ostream &Write(std::ostream &os) const; +}; + +} // end namespace gdcm + +#include "gdcmExplicitDataElement.txx" + +#endif //GDCMEXPLICITDATAELEMENT_H diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmExplicitDataElement.txx b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmExplicitDataElement.txx new file mode 100644 index 0000000..0759266 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmExplicitDataElement.txx @@ -0,0 +1,562 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMEXPLICITDATAELEMENT_TXX +#define GDCMEXPLICITDATAELEMENT_TXX + +#include "gdcmSequenceOfItems.h" +#include "gdcmSequenceOfFragments.h" +#include "gdcmVL.h" +#include "gdcmParseException.h" +#include "gdcmImplicitDataElement.h" + +#include "gdcmValueIO.h" +#include "gdcmSwapper.h" + +namespace gdcm +{ +//----------------------------------------------------------------------------- +template +std::istream &ExplicitDataElement::Read(std::istream &is) +{ + ReadPreValue(is); + return ReadValue(is); +} + +template +std::istream &ExplicitDataElement::ReadPreValue(std::istream &is) +{ + TagField.Read(is); + // See PS 3.5, Data Element Structure With Explicit VR + // Read Tag + if( !is ) + { + if( !is.eof() ) // FIXME This should not be needed + { + assert(0 && "Should not happen" ); + } + return is; + } + if( TagField == Tag(0xfffe,0xe0dd) ) + { + ParseException pe; + pe.SetLastElement( *this ); + throw pe; + } + //assert( TagField != Tag(0xfeff,0xdde0) ); + const Tag itemDelItem(0xfffe,0xe00d); + if( TagField == itemDelItem ) + { + if( !ValueLengthField.Read(is) ) + { + assert(0 && "Should not happen"); + return is; + } + if( ValueLengthField ) + { + gdcmDebugMacro( + "Item Delimitation Item has a length different from 0 and is: " << ValueLengthField ); + } + // Reset ValueLengthField to avoid user error + ValueLengthField = 0; + // Set pointer to NULL to avoid user error + ValueField = 0; + VRField = VR::INVALID; + return is; + } + +#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + if( TagField == Tag(0x00ff, 0x4aa5) ) + { + //assert(0 && "Should not happen" ); + // gdcmDataExtra/gdcmBreakers/DigitexAlpha_no_7FE0.dcm + is.seekg( -4, std::ios::cur ); + TagField = Tag(0x7fe0,0x0010); + VRField = VR::OW; + ValueField = new ByteValue; + std::streampos s = is.tellg(); + is.seekg( 0, std::ios::end); + std::streampos e = is.tellg(); + is.seekg( s, std::ios::beg ); + ValueField->SetLength( (int32_t)(e - s) ); + ValueLengthField = ValueField->GetLength(); + bool failed = !ValueIO::Read(is,*ValueField,true); + gdcmAssertAlwaysMacro( !failed ); + return is; + //throw Exception( "Unhandled" ); + } +#endif + // Read VR + try + { + if( !VRField.Read(is) ) + { + assert(0 && "Should not happen" ); + return is; + } + } + catch( Exception &ex ) + { +#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + // gdcm-MR-PHILIPS-16-Multi-Seq.dcm + // assert( TagField == Tag(0xfffe, 0xe000) ); + // -> For some reason VR is written as {44,0} well I guess this is a VR... + // Technically there is a second bug, dcmtk assume other things when reading this tag, + // so I need to change this tag too, if I ever want dcmtk to read this file. oh well + // 0019004_Baseline_IMG1.dcm + // -> VR is garbage also... + // assert( TagField == Tag(8348,0339) || TagField == Tag(b5e8,0338)) + //gdcmWarningMacro( "Assuming 16 bits VR for Tag=" << + // TagField << " in order to read a buggy DICOM file." ); + //VRField = VR::INVALID; + (void)ex; //compiler warning + ParseException pe; + pe.SetLastElement( *this ); + throw pe; +#else + throw ex; +#endif /* GDCM_SUPPORT_BROKEN_IMPLEMENTATION */ + } + // Read Value Length + if( VR::GetLength(VRField) == 4 ) + { + if( !ValueLengthField.Read(is) ) + { + assert(0 && "Should not happen"); + return is; + } + } + else + { + // 16bits only + if( !ValueLengthField.template Read16(is) ) + { + assert(0 && "Should not happen"); + return is; + } +#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + // HACK for SIEMENS Leonardo + if( ValueLengthField == 0x0006 + && VRField == VR::UL + && TagField.GetGroup() == 0x0009 ) + { + gdcmWarningMacro( "Replacing VL=0x0006 with VL=0x0004, for Tag=" << + TagField << " in order to read a buggy DICOM file." ); + ValueLengthField = 0x0004; + } +#endif + } + //std::cerr << "exp cur tag=" << TagField << " VR=" << VRField << " VL=" << ValueLengthField << std::endl; + // + // I don't like the following 3 lines, what if 0000,0000 was indeed -wrongly- sent, we should be able to continue + // chances is that 99% of times there is now way we can reach here, so safely throw an exception + if( TagField == Tag(0x0000,0x0000) && ValueLengthField == 0 && VRField == VR::INVALID ) + { + ParseException pe; + pe.SetLastElement( *this ); + throw pe; + } + +#ifdef ELSCINT1_01F7_1070 + if( TagField == Tag(0x01f7,0x1070) ) + { + ValueLengthField = ValueLengthField - 7; + } +#endif + return is; +} + +template +std::istream &ExplicitDataElement::ReadValue(std::istream &is, bool readvalues) +{ + if( is.eof() ) return is; + if( ValueLengthField == 0 ) + { + // Simple fast path + ValueField = 0; + return is; + } + + // Read the Value + //assert( ValueField == 0 ); + if( VRField == VR::SQ ) + { + // Check wether or not this is an undefined length sequence + assert( TagField != Tag(0x7fe0,0x0010) ); + ValueField = new SequenceOfItems; + } + else if( ValueLengthField.IsUndefined() ) + { + if( TagField == Tag(0x7fe0,0x0010) ) + { + // Ok this is Pixel Data fragmented... + assert( VRField & VR::OB_OW || VRField == VR::UN ); + ValueField = new SequenceOfFragments; + } + else + { + // Support cp246 conforming file: + // Enhanced_MR_Image_Storage_PixelSpacingNotIn_0028_0030.dcm (illegal) + // vs + // undefined_length_un_vr.dcm + assert( TagField != Tag(0x7fe0,0x0010) ); + assert( VRField == VR::UN ); + ValueField = new SequenceOfItems; + ValueField->SetLength(ValueLengthField); // perform realloc + try + { + //if( !ValueIO::Read(is,*ValueField) ) // non cp246 + if( !ValueIO::Read(is,*ValueField,readvalues) ) // cp246 compliant + { + assert(0); + } + } + catch( std::exception &) + { + // Must be one of those non-cp246 file... + // but for some reason seekg back to previous offset + Read + // as Explicit does not work... + ParseException pe; + pe.SetLastElement(*this); + throw pe; + } + return is; + } + } + else + { + //assert( TagField != Tag(0x7fe0,0x0010) ); + ValueField = new ByteValue; + } + // We have the length we should be able to read the value + this->SetValueFieldLength( ValueLengthField, readvalues ); +#if defined(GDCM_SUPPORT_BROKEN_IMPLEMENTATION) && 0 + // PHILIPS_Intera-16-MONO2-Uncompress.dcm + if( TagField == Tag(0x2001,0xe05f) + || TagField == Tag(0x2001,0xe100) + || TagField == Tag(0x2005,0xe080) + || TagField == Tag(0x2005,0xe083) + || TagField == Tag(0x2005,0xe084) + || TagField == Tag(0x2005,0xe402) + //TagField.IsPrivate() && VRField == VR::SQ + //-> Does not work for 0029 + //we really need to read item marker + ) + { + gdcmWarningMacro( "ByteSwaping Private SQ: " << TagField ); + assert( VRField == VR::SQ ); + assert( TagField.IsPrivate() ); + try + { + if( !ValueIO::Read(is,*ValueField,readvalues) ) + { + assert(0 && "Should not happen"); + } + Value* v = &*ValueField; + SequenceOfItems *sq = dynamic_cast(v); + assert( sq ); + SequenceOfItems::Iterator it = sq->Begin(); + for( ; it != sq->End(); ++it) + { + Item &item = *it; + DataSet &ds = item.GetNestedDataSet(); + ByteSwapFilter bsf(ds); + bsf.ByteSwap(); + } + } + catch( std::exception &ex ) + { + ValueLengthField = ValueField->GetLength(); + } + return is; + } +#endif + + bool failed; + //assert( VRField != VR::UN ); + if( VRField & VR::VRASCII ) + { + //assert( VRField.GetSize() == 1 ); + failed = !ValueIO::Read(is,*ValueField,readvalues); + } + else + { + assert( VRField & VR::VRBINARY ); + unsigned int vrsize = VRField.GetSize(); + assert( vrsize == 1 || vrsize == 2 || vrsize == 4 || vrsize == 8 ); + if(VRField==VR::AT) vrsize = 2; + switch(vrsize) + { + case 1: + failed = !ValueIO::Read(is,*ValueField,readvalues); + break; + case 2: + failed = !ValueIO::Read(is,*ValueField,readvalues); + break; + case 4: + failed = !ValueIO::Read(is,*ValueField,readvalues); + break; + case 8: + failed = !ValueIO::Read(is,*ValueField,readvalues); + break; + default: + failed = true; + assert(0); + } + } + if( failed ) + { +#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + if( TagField == Tag(0x7fe0,0x0010) ) + { + // BUG this should be moved to the ImageReader class, only this class + // knows what 7fe0 actually is, and should tolerate partial Pixel Data + // element... PMS-IncompletePixelData.dcm + gdcmWarningMacro( "Incomplete Pixel Data found, use file at own risk" ); + is.clear(); + } + else +#endif /* GDCM_SUPPORT_BROKEN_IMPLEMENTATION */ + { + // Might be the famous UN 16bits + ParseException pe; + pe.SetLastElement( *this ); + throw pe; + } + return is; + } + +#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + if( SequenceOfItems *sqi = dynamic_cast(&GetValue()) ) + { + assert( ValueField->GetLength() == ValueLengthField ); + // Recompute the total length: + if( !ValueLengthField.IsUndefined() ) + { + // PhilipsInteraSeqTermInvLen.dcm + // contains an extra seq del item marker, which we are not loading. Therefore the + // total length needs to be recomputed when sqi is expressed in defined length + VL dummy = sqi->template ComputeLength(); + ValueLengthField = dummy; + sqi->SetLength( dummy ); + gdcmAssertAlwaysMacro( dummy == ValueLengthField ); + } + } + else if( SequenceOfFragments *sqf = dynamic_cast(&GetValue()) ) + { + assert( ValueField->GetLength() == ValueLengthField ); + assert( sqf->GetLength() == ValueLengthField ); (void)sqf; + assert( ValueLengthField.IsUndefined() ); + } +#endif + + return is; +} + +template +std::istream &ExplicitDataElement::ReadWithLength(std::istream &is, VL & length) +{ + return Read(is); (void)length; +} + +//----------------------------------------------------------------------------- +template +const std::ostream &ExplicitDataElement::Write(std::ostream &os) const +{ + if( TagField == Tag(0xfffe,0xe0dd) ) throw Exception( "Impossible" ); + //if( TagField == Tag(0xfffe,0xe0dd) ) return os; + if( !TagField.Write(os) ) + { + assert( 0 && "Should not happen" ); + return os; + } + const Tag itemDelItem(0xfffe,0xe00d); + if( TagField == itemDelItem ) + { + assert(0); + assert( ValueField == 0 ); +#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + if( ValueLengthField != 0 ) + { + gdcmWarningMacro( + "Item Delimitation Item had a length different from 0." ); + VL zero = 0; + zero.Write(os); + return os; + } +#endif + // else + assert( ValueLengthField == 0 ); + if( !ValueLengthField.Write(os) ) + { + assert( 0 && "Should not happen" ); + return os; + } + return os; + } + bool vr16bitsimpossible = (VRField & VR::VL16) && (ValueLengthField > (uint32_t)VL::GetVL16Max()); + if( VRField == VR::INVALID || vr16bitsimpossible ) + { + if ( TagField.IsPrivateCreator() ) + { + gdcmAssertAlwaysMacro( !vr16bitsimpossible ); + VR lo = VR::LO; + if( TagField.IsGroupLength() ) + { + lo = VR::UL; + } + lo.Write(os); + ValueLengthField.Write16(os); + } + else + { + const VR un = VR::UN; + un.Write(os); + Value* v = &*ValueField; + if( dynamic_cast(v) ) + { + VL vl = 0xFFFFFFFF; + assert( vl.IsUndefined() ); + vl.Write(os); + } + else + ValueLengthField.Write(os); + } + } + else + { + assert( VRField.IsVRFile() && VRField != VR::INVALID ); + if( !VRField.Write(os) ) + { + assert( 0 && "Should not happen" ); + return os; + } + if( VRField & VR::VL32 ) + { + if( !ValueLengthField.Write(os) ) + { + assert( 0 && "Should not happen" ); + return os; + } + } + else + { + // 16bits only + if( !ValueLengthField.template Write16(os) ) + { + assert( 0 && "Should not happen" ); + return os; + } + } + } + if( ValueLengthField ) + { + // Special case, check SQ + if ( GetVR() == VR::SQ ) + { + gdcmAssertAlwaysMacro( dynamic_cast(&GetValue()) ); + } +//#ifndef NDEBUG + // check consistency in Length: + if( GetByteValue() ) + { + assert( ValueField->GetLength() == ValueLengthField ); + } + //else if( GetSequenceOfItems() ) + else if( const SequenceOfItems *sqi = dynamic_cast(&GetValue()) ) + { + assert( ValueField->GetLength() == ValueLengthField ); + // Recompute the total length: + if( !ValueLengthField.IsUndefined() ) + { + VL dummy = sqi->template ComputeLength(); + gdcmAssertAlwaysMacro( dummy == ValueLengthField ); + } + } + else if( GetSequenceOfFragments() ) + { + assert( ValueField->GetLength() == ValueLengthField ); + } +//#endif + // We have the length we should be able to write the value + if( VRField == VR::UN && ValueLengthField.IsUndefined() ) + { + assert( TagField == Tag(0x7fe0,0x0010) || GetValueAsSQ() ); + ValueIO::Write(os,*ValueField); + } +#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + else if( VRField == VR::INVALID && dynamic_cast(&*ValueField) ) + { + // We have pretended so far that the Sequence was encoded as UN. Well the real + // troubles is that we cannot store the length as explicit length, otherwise + // we will loose the SQ, therefore change the length into undefined length + // and add a seq del item: + ValueIO::Write(os,*ValueField); + if( !ValueLengthField.IsUndefined() ) + { + // eg. TestWriter with ExplicitVRforPublicElementsImplicitVRforShadowElements.dcm + // seq del item is not stored, write it ! + const Tag seqDelItem(0xfffe,0xe0dd); + seqDelItem.Write(os); + VL zero = 0; + zero.Write(os); + } + } +#endif + else + { + bool failed; + if( VRField & VR::VRASCII || VRField == VR::INVALID ) + { + failed = !ValueIO::Write(os,*ValueField); + } + else + { + assert( VRField & VR::VRBINARY ); + unsigned int vrsize = VRField.GetSize(); + assert( vrsize == 1 || vrsize == 2 || vrsize == 4 || vrsize == 8 ); + if(VRField == VR::AT) vrsize = 2; + switch(vrsize) + { + case 1: + failed = !ValueIO::Write(os,*ValueField); + break; + case 2: + failed = !ValueIO::Write(os,*ValueField); + break; + case 4: + failed = !ValueIO::Write(os,*ValueField); + break; + case 8: + failed = !ValueIO::Write(os,*ValueField); + break; + default: + failed = true; + assert(0); + } + } + if( failed ) + { + assert( 0 && "Should not happen" ); + } + } + } + + return os; +} + + + +} // end namespace gdcm + +#endif // GDCMEXPLICITDATAELEMENT_TXX diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmExplicitImplicitDataElement.cxx b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmExplicitImplicitDataElement.cxx new file mode 100644 index 0000000..e98a690 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmExplicitImplicitDataElement.cxx @@ -0,0 +1,57 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmExplicitImplicitDataElement.h" +#include "gdcmSequenceOfItems.h" +#include "gdcmSequenceOfFragments.h" + +namespace gdcm +{ + +//----------------------------------------------------------------------------- + +VL ExplicitImplicitDataElement::GetLength() const +{ + if( ValueLengthField.IsUndefined() ) + { + assert( ValueField->GetLength().IsUndefined() ); + Value *p = ValueField; + // If this is a SQ we need to compute it's proper length + SequenceOfItems *sq = dynamic_cast(p); + // TODO can factor the code: + if( sq ) + { + return TagField.GetLength() + VRField.GetLength() + + ValueLengthField.GetLength() + sq->ComputeLength(); + } + SequenceOfFragments *sf = dynamic_cast(p); + if( sf ) + { + assert( VRField & (VR::OB | VR::OW) ); + return TagField.GetLength() + VRField.GetLength() + + ValueLengthField.GetLength() + sf->ComputeLength(); + } + assert(0); + return 0; + } + else + { + // Each time VR::GetLength() is 2 then Value Length is coded in 2 + // 4 then Value Length is coded in 4 + assert( !ValueField || ValueField->GetLength() == ValueLengthField ); + return TagField.GetLength() + 2*VRField.GetLength() + ValueLengthField; + } +} + + +} // end namespace gdcm diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmExplicitImplicitDataElement.h b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmExplicitImplicitDataElement.h new file mode 100644 index 0000000..4bf09d7 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmExplicitImplicitDataElement.h @@ -0,0 +1,58 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMEXPLICITIMPLICITDATAELEMENT_H +#define GDCMEXPLICITIMPLICITDATAELEMENT_H + +#include "gdcmDataElement.h" + +namespace gdcm +{ +// Data Element (ExplicitImplicit) +/** + * \brief Class to read/write a DataElement as ExplicitImplicit Data Element + * \note This only happen for some Philips images + * Should I derive from ExplicitDataElement instead ? + * This is the class that is the closest the GDCM1.x parser. At each element we try first + * to read it as explicit, if this fails, then we try again as an implicit element. + */ +class GDCM_EXPORT ExplicitImplicitDataElement : public DataElement +{ +public: + VL GetLength() const; + + template + std::istream &Read(std::istream &is); + + template + std::istream &ReadPreValue(std::istream &is); + + template + std::istream &ReadValue(std::istream &is, bool readvalues = true); + + template + std::istream &ReadWithLength(std::istream &is, VL & length) + { + return Read(is); (void)length; + } + + // PURPOSELY do not provide an implementation for writing ! + //template + //const std::ostream &Write(std::ostream &os) const; +}; + +} // end namespace gdcm + +#include "gdcmExplicitImplicitDataElement.txx" + +#endif //GDCMEXPLICITIMPLICITDATAELEMENT_H diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmExplicitImplicitDataElement.txx b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmExplicitImplicitDataElement.txx new file mode 100644 index 0000000..2cdc1a1 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmExplicitImplicitDataElement.txx @@ -0,0 +1,506 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMEXPLICITIMPLICITDATAELEMENT_TXX +#define GDCMEXPLICITIMPLICITDATAELEMENT_TXX + +#include "gdcmExplicitImplicitDataElement.h" + +#include "gdcmSequenceOfItems.h" +#include "gdcmSequenceOfFragments.h" +#include "gdcmVL.h" +#include "gdcmExplicitDataElement.h" +#include "gdcmImplicitDataElement.h" +#include "gdcmValueIO.h" +#include "gdcmSwapper.h" + +namespace gdcm +{ +//----------------------------------------------------------------------------- +template +std::istream &ExplicitImplicitDataElement::Read(std::istream &is) +{ + ReadPreValue(is); + return ReadValue(is); +} + +template +std::istream &ExplicitImplicitDataElement::ReadPreValue(std::istream &is) +{ + TagField.Read(is); + // See PS 3.5, Data Element Structure With Explicit VR + // Read Tag + if( !is ) + { + if( !is.eof() ) // FIXME This should not be needed + { + assert(0 && "Should not happen" ); + } + return is; + } + if( TagField == Tag(0xfffe,0xe0dd) ) + { + ParseException pe; + pe.SetLastElement( *this ); + throw pe; + } + //assert( TagField != Tag(0xfeff,0xdde0) ); + const Tag itemDelItem(0xfffe,0xe00d); + if( TagField == itemDelItem ) + { + //ParseException pe; + //pe.SetLastElement( *this ); + //throw pe; + if( !ValueLengthField.Read(is) ) + { + assert(0 && "Should not happen"); + return is; + } + if( ValueLengthField ) + { + gdcmDebugMacro( + "Item Delimitation Item has a length different from 0 and is: " << ValueLengthField ); + } + // Set pointer to NULL to avoid user error + ValueField = 0; + VRField = VR::INVALID; + return is; + } + +#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + if( TagField == Tag(0x00ff, 0x4aa5) ) + { + //assert(0 && "Should not happen" ); + // gdcmDataExtra/gdcmBreakers/DigitexAlpha_no_7FE0.dcm + is.seekg( -4, std::ios::cur ); + TagField = Tag(0x7fe0,0x0010); + VRField = VR::OW; + ValueField = new ByteValue; + std::streampos s = is.tellg(); + is.seekg( 0, std::ios::end); + std::streampos e = is.tellg(); + is.seekg( s, std::ios::beg ); + ValueField->SetLength( (int32_t)(e - s) ); + ValueLengthField = ValueField->GetLength(); + bool failed = !ValueIO::Read(is,*ValueField,true); + gdcmAssertAlwaysMacro( !failed ); + return is; + //throw Exception( "Unhandled" ); + } +#endif + // Read VR + try + { + if( !VRField.Read(is) ) + { + assert(0 && "Should not happen" ); + return is; + } + // Read Value Length + if( VR::GetLength(VRField) == 4 ) + { + if( !ValueLengthField.Read(is) ) + { + assert(0 && "Should not happen"); + return is; + } + } + else + { + // 16bits only + if( !ValueLengthField.template Read16(is) ) + { + assert(0 && "Should not happen"); + return is; + } +#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + // HACK for SIEMENS Leonardo + if( ValueLengthField == 0x0006 + && VRField == VR::UL + && TagField.GetGroup() == 0x0009 ) + { + gdcmWarningMacro( "Replacing VL=0x0006 with VL=0x0004, for Tag=" << + TagField << " in order to read a buggy DICOM file." ); + ValueLengthField = 0x0004; + } +#endif + } + } + catch( Exception &ex ) + { + (void)ex; + VRField = VR::INVALID; + is.seekg( -2, std::ios::cur ); + + const Tag itemStartItem(0xfffe,0xe000); + if( TagField == itemStartItem ) return is; + + //assert( TagField != Tag(0xfffe,0xe0dd) ); + // Read Value Length + if( !ValueLengthField.Read(is) ) + { + //assert(0 && "Should not happen"); + throw Exception("Impossible"); + return is; + } + //std::cerr << "imp cur tag=" << TagField << " VL=" << ValueLengthField << std::endl; + if( ValueLengthField == 0 ) + { + // Simple fast path + ValueField = 0; + return is; + } + else if( ValueLengthField.IsUndefined() ) + { + //assert( de.GetVR() == VR::SQ ); + // FIXME what if I am reading the pixel data... + //assert( TagField != Tag(0x7fe0,0x0010) ); + if( TagField != Tag(0x7fe0,0x0010) ) + { + ValueField = new SequenceOfItems; + } + else + { + gdcmErrorMacro( "Undefined value length is impossible in non-encapsulated Transfer Syntax" ); + ValueField = new SequenceOfFragments; + } + //VRField = VR::SQ; + } + else + { + if( true /*ValueLengthField < 8 */ ) + { + ValueField = new ByteValue; + } + else + { + // In the following we read 4 more bytes in the Value field + // to find out if this is a SQ or not + // there is still work to do to handle the PMS featured SQ + // where item Start is in fact 0xfeff, 0x00e0 ... sigh + const Tag itemStart(0xfffe, 0xe000); +#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + const Tag itemPMSStart(0xfeff, 0x00e0); + const Tag itemPMSStart2(0x3f3f, 0x3f00); +#endif + Tag item; + // TODO FIXME + // This is pretty dumb to actually read to later on seekg back, why not `peek` directly ? + item.Read(is); + // Maybe this code can later be rewritten as I believe that seek back + // is very slow... + is.seekg(-4, std::ios::cur ); + if( item == itemStart ) + { + assert( TagField != Tag(0x7fe0,0x0010) ); + ValueField = new SequenceOfItems; + } +#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + else if ( item == itemPMSStart ) + { + // MR_Philips_Intera_No_PrivateSequenceImplicitVR.dcm + gdcmWarningMacro( "Illegal: Explicit SQ found in a file with " + "TransferSyntax=Implicit for tag: " << TagField ); + // TODO: We READ Explicit ok...but we store Implicit ! + // Indeed when copying the VR will be saved... pretty cool eh ? + ValueField = new SequenceOfItems; + ValueField->SetLength(ValueLengthField); // perform realloc + try + { + if( !ValueIO::Read(is,*ValueField,true) ) + { + assert(0 && "Should not happen"); + } + } + catch( std::exception &ex2 ) + { + (void)ex2; + ValueLengthField = ValueField->GetLength(); + } + return is; + } + else if ( item == itemPMSStart2 && false ) + { + gdcmWarningMacro( "Illegal: SQ start with " << itemPMSStart2 + << " instead of " << itemStart << " for tag: " << TagField ); + ValueField = new SequenceOfItems; + ValueField->SetLength(ValueLengthField); // perform realloc + if( !ValueIO::Read(is,*ValueField,true) ) + { + assert(0 && "Should not happen"); + } + return is; + } +#endif + else + { + ValueField = new ByteValue; + } + } + } +#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + // THE WORST BUG EVER. From GE Workstation + if( ValueLengthField == 13 ) + { + // Historically gdcm did not enforce proper length + // thus Theralys started writing illegal DICOM images: + const Tag theralys1(0x0008,0x0070); + const Tag theralys2(0x0008,0x0080); + if( TagField != theralys1 + && TagField != theralys2 ) + { + gdcmWarningMacro( "GE,13: Replacing VL=0x000d with VL=0x000a, for Tag=" + << TagField << " in order to read a buggy DICOM file." ); + ValueLengthField = 10; + } + } +#endif +#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + if( ValueLengthField == 0x31f031c && TagField == Tag(0x031e,0x0324) ) + { + // TestImages/elbow.pap + gdcmWarningMacro( "Replacing a VL. To be able to read a supposively" + "broken Payrus file." ); + ValueLengthField = 202; // 0xca + } +#endif + // We have the length we should be able to read the value + ValueField->SetLength(ValueLengthField); // perform realloc + if( !ValueIO::Read(is,*ValueField,true) ) + { + // Special handling for PixelData tag: +#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + if( TagField == Tag(0x7fe0,0x0010) ) + { + gdcmWarningMacro( "Incomplete Pixel Data found, use file at own risk" ); + is.clear(); + } + else +#endif /* GDCM_SUPPORT_BROKEN_IMPLEMENTATION */ + { + throw Exception("Should not happen (imp)"); + } + return is; + } + +#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + // dcmtk 3.5.4 is resilient to broken explicit SQ length and will properly recompute it + // as long as each of the Item lengths are correct + VL dummy = ValueField->GetLength(); + if( ValueLengthField != dummy ) + { + gdcmWarningMacro( "ValueLengthField was bogus" ); assert(0); + ValueLengthField = dummy; + } +#else + assert( ValueLengthField == ValueField->GetLength() ); + assert( VRField == VR::INVALID ); +#endif + + return is; + + } + //std::cerr << "exp cur tag=" << TagField << " VR=" << VRField << " VL=" << ValueLengthField << std::endl; + // + // I don't like the following 3 lines, what if 0000,0000 was indeed -wrongly- sent, we should be able to continue + // chances is that 99% of times there is now way we can reach here, so safely throw an exception + if( TagField == Tag(0x0000,0x0000) && ValueLengthField == 0 && VRField == VR::INVALID ) + { + ParseException pe; + pe.SetLastElement( *this ); + throw pe; + } + +#ifdef ELSCINT1_01F7_1070 + if( TagField == Tag(0x01f7,0x1070) ) + { + ValueLengthField = ValueLengthField - 7; + } +#endif + + return is; +} + +template +std::istream &ExplicitImplicitDataElement::ReadValue(std::istream &is, bool readvalues) +{ + if( is.eof() ) return is; + /* thechnically the following is bad + it assumes that in the case of explicit/implicit dataset + we are not handle the prevalue call properly for buggy implicit attribute + */ + if( VRField == VR::INVALID ) return is; + + if( ValueLengthField == 0 ) + { + // Simple fast path + ValueField = 0; + return is; + } + + // Read the Value + //assert( ValueField == 0 ); + if( VRField == VR::SQ ) + { + // Check wether or not this is an undefined length sequence + assert( TagField != Tag(0x7fe0,0x0010) ); + ValueField = new SequenceOfItems; + } + else if( ValueLengthField.IsUndefined() ) + { + if( VRField == VR::UN ) + { + // Support cp246 conforming file: + // Enhanced_MR_Image_Storage_PixelSpacingNotIn_0028_0030.dcm (illegal) + // vs + // undefined_length_un_vr.dcm + assert( TagField != Tag(0x7fe0,0x0010) ); + ValueField = new SequenceOfItems; + ValueField->SetLength(ValueLengthField); // perform realloc + try + { + //if( !ValueIO::Read(is,*ValueField) ) // non cp246 + if( !ValueIO::Read(is,*ValueField,readvalues) ) // cp246 compliant + { + assert(0); + } + } + catch( std::exception &) + { + // Must be one of those non-cp246 file... + // but for some reason seekg back to previous offset + Read + // as Explicit does not work... + ParseException pe; + pe.SetLastElement(*this); + throw pe; + } + return is; + } + else + { + // Ok this is Pixel Data fragmented... + assert( TagField == Tag(0x7fe0,0x0010) ); + assert( VRField & VR::OB_OW ); + ValueField = new SequenceOfFragments; + } + } + else + { + //assert( TagField != Tag(0x7fe0,0x0010) ); + ValueField = new ByteValue; + } + // We have the length we should be able to read the value + this->SetValueFieldLength( ValueLengthField, readvalues ); +#if defined(GDCM_SUPPORT_BROKEN_IMPLEMENTATION) && 0 + // PHILIPS_Intera-16-MONO2-Uncompress.dcm + if( TagField == Tag(0x2001,0xe05f) + || TagField == Tag(0x2001,0xe100) + || TagField == Tag(0x2005,0xe080) + || TagField == Tag(0x2005,0xe083) + || TagField == Tag(0x2005,0xe084) + || TagField == Tag(0x2005,0xe402) + //TagField.IsPrivate() && VRField == VR::SQ + //-> Does not work for 0029 + //we really need to read item marker + ) + { + gdcmWarningMacro( "ByteSwaping Private SQ: " << TagField ); + assert( VRField == VR::SQ ); + assert( TagField.IsPrivate() ); + try + { + if( !ValueIO::Read(is,*ValueField,readvalues) ) + { + assert(0 && "Should not happen"); + } + Value* v = &*ValueField; + SequenceOfItems *sq = dynamic_cast(v); + assert( sq ); + SequenceOfItems::Iterator it = sq->Begin(); + for( ; it != sq->End(); ++it) + { + Item &item = *it; + DataSet &ds = item.GetNestedDataSet(); + ByteSwapFilter bsf(ds); + bsf.ByteSwap(); + } + } + catch( std::exception &ex ) + { + ValueLengthField = ValueField->GetLength(); + } + return is; + } +#endif + + bool failed; + //assert( VRField != VR::UN ); + if( VRField & VR::VRASCII ) + { + //assert( VRField.GetSize() == 1 ); + failed = !ValueIO::Read(is,*ValueField,readvalues); + } + else + { + assert( VRField & VR::VRBINARY ); + unsigned int vrsize = VRField.GetSize(); + assert( vrsize == 1 || vrsize == 2 || vrsize == 4 || vrsize == 8 ); + if(VRField==VR::AT) vrsize = 2; + switch(vrsize) + { + case 1: + failed = !ValueIO::Read(is,*ValueField,readvalues); + break; + case 2: + failed = !ValueIO::Read(is,*ValueField,readvalues); + break; + case 4: + failed = !ValueIO::Read(is,*ValueField,readvalues); + break; + case 8: + failed = !ValueIO::Read(is,*ValueField,readvalues); + break; + default: + failed = true; + assert(0); + } + } + if( failed ) + { +#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + if( TagField == Tag(0x7fe0,0x0010) ) + { + // BUG this should be moved to the ImageReader class, only this class knows + // what 7fe0 actually is, and should tolerate partial Pixel Data element... + // PMS-IncompletePixelData.dcm + gdcmWarningMacro( "Incomplete Pixel Data found, use file at own risk" ); + is.clear(); + } + else +#endif /* GDCM_SUPPORT_BROKEN_IMPLEMENTATION */ + { + // Might be the famous UN 16bits + ParseException pe; + pe.SetLastElement( *this ); + throw pe; + } + return is; + } + return is; + +} + + +} // end namespace gdcm + +#endif // GDCMEXPLICITIMPLICITDATAELEMENT_TXX diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmFile.cxx b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmFile.cxx new file mode 100644 index 0000000..7eba4fa --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmFile.cxx @@ -0,0 +1,32 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmFile.h" + + +namespace gdcm +{ + +std::istream &File::Read(std::istream &is) +{ + assert(0); + return is; +} + +std::ostream const &File::Write(std::ostream &os) const +{ + assert(0); + return os; +} + +} // end namespace gdcm diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmFile.h b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmFile.h new file mode 100644 index 0000000..215c79b --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmFile.h @@ -0,0 +1,79 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMFILE_H +#define GDCMFILE_H + +#include "gdcmObject.h" +#include "gdcmDataSet.h" +#include "gdcmFileMetaInformation.h" + +namespace gdcm +{ + +/** + * \brief a DICOM File + * See PS 3.10 File: A File is an ordered string of zero or more bytes, where + * the first byte is at the beginning of the file and the last byte at the end + * of the File. Files are identified by a unique File ID and may by written, + * read and/or deleted. + * + * \see Reader Writer + */ +class GDCM_EXPORT File : public Object +{ +public: + File() {}; + + friend std::ostream &operator<<(std::ostream &os, const File &val); + + /// Read + std::istream &Read(std::istream &is); + + /// Write + std::ostream const &Write(std::ostream &os) const; + + /// Get File Meta Information + const FileMetaInformation &GetHeader() const { return Header; } + + /// Get File Meta Information + FileMetaInformation &GetHeader() { return Header; } + + /// Set File Meta Information + void SetHeader( const FileMetaInformation &fmi ) { Header = fmi; } + + /// Get Data Set + const DataSet &GetDataSet() const { return DS; } + + /// Get Data Set + DataSet &GetDataSet() { return DS; } + + /// Set Data Set + void SetDataSet( const DataSet &ds) { DS = ds; } + +private: + FileMetaInformation Header; + DataSet DS; +}; +//----------------------------------------------------------------------------- +inline std::ostream& operator<<(std::ostream &os, const File &val) +{ + os << val.GetHeader() << std::endl; + //os << val.GetDataSet() << std::endl; // FIXME + assert(0); + return os; +} + +} // end namespace gdcm + +#endif //GDCMFILE_H diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmFileMetaInformation.cxx b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmFileMetaInformation.cxx new file mode 100644 index 0000000..f2cf14d --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmFileMetaInformation.cxx @@ -0,0 +1,892 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmFileMetaInformation.h" +#include "gdcmAttribute.h" +#include "gdcmVR.h" +#include "gdcmExplicitDataElement.h" +#include "gdcmImplicitDataElement.h" +#include "gdcmByteValue.h" +#include "gdcmSwapper.h" +#include "gdcmException.h" +#include "gdcmTagToType.h" +//#include "gdcmUIDGenerator.h" + +#include "gdcmTag.h" + +namespace gdcm +{ + +const char FileMetaInformation::GDCM_FILE_META_INFORMATION_VERSION[] = "\0\1"; + +const char FileMetaInformation::GDCM_IMPLEMENTATION_CLASS_UID[] = "1.2.826.0.1.3680043.2.1143.107.104.103.115." GDCM_VERSION; +const char FileMetaInformation::GDCM_IMPLEMENTATION_VERSION_NAME[] = "GDCM " GDCM_VERSION; +const char FileMetaInformation::GDCM_SOURCE_APPLICATION_ENTITY_TITLE[] = "GDCM"; +// Default initialize those static std::string, with GDCM values: +std::string FileMetaInformation::ImplementationClassUID = GetGDCMImplementationClassUID(); +std::string FileMetaInformation::ImplementationVersionName = GetGDCMImplementationVersionName(); +std::string FileMetaInformation::SourceApplicationEntityTitle = GetGDCMSourceApplicationEntityTitle(); + +const char * FileMetaInformation::GetFileMetaInformationVersion() +{ + return GDCM_FILE_META_INFORMATION_VERSION; +} +const char * FileMetaInformation::GetGDCMImplementationClassUID() +{ + return GDCM_IMPLEMENTATION_CLASS_UID; +} +const char * FileMetaInformation::GetGDCMImplementationVersionName() +{ + return GDCM_IMPLEMENTATION_VERSION_NAME; +} +const char * FileMetaInformation::GetGDCMSourceApplicationEntityTitle() +{ + return GDCM_SOURCE_APPLICATION_ENTITY_TITLE; +} + +void FileMetaInformation::SetImplementationClassUID(const char * imp) +{ + // TODO: it would be nice to make sure imp is actually a valid UID + if( imp ) + { + ImplementationClassUID = imp; + } +} + +void FileMetaInformation::AppendImplementationClassUID(const char * imp) +{ + if( imp ) + { + ImplementationClassUID = GetGDCMImplementationClassUID(); + ImplementationClassUID += "."; + ImplementationClassUID += imp; + } +} + +void FileMetaInformation::SetImplementationVersionName(const char * version) +{ + if( version ) + { + // Simply override the value since we cannot have more than 16bytes... + assert( strlen(version) <= 16 ); + //ImplementationVersionName = GetGDCMImplementationVersionName(); + //ImplementationVersionName += "-"; + //ImplementationVersionName += version; + ImplementationVersionName = version; + } +} +void FileMetaInformation::SetSourceApplicationEntityTitle(const char * title) +{ + if( title ) + { + //SourceApplicationEntityTitle = GetGDCMSourceApplicationEntityTitle(); + //SourceApplicationEntityTitle += "/"; + AEComp ae( title ); + SourceApplicationEntityTitle = ae.Truncate(); + } +} +const char *FileMetaInformation::GetImplementationClassUID() +{ + return ImplementationClassUID.c_str(); +} +const char *FileMetaInformation::GetImplementationVersionName() +{ + return ImplementationVersionName.c_str(); +} +const char *FileMetaInformation::GetSourceApplicationEntityTitle() +{ + return SourceApplicationEntityTitle.c_str(); +} + +void FileMetaInformation::FillFromDataSet(DataSet const &ds) +{ + // Example: CR-MONO1-10-chest.dcm is missing a file meta header: + DataElement xde; + // File Meta Information Version (0002,0001) -> computed + if( !FindDataElement( Tag(0x0002, 0x0001) ) ) + { + xde.SetTag( Tag(0x0002, 0x0001) ); + xde.SetVR( VR::OB ); + const char *version = FileMetaInformation::GetFileMetaInformationVersion(); + xde.SetByteValue( version, 2 /*strlen(version)*/ ); + Insert( xde ); + } + else + { + const DataElement &de = GetDataElement( Tag(0x0002,0x0001) ); + const ByteValue *bv = de.GetByteValue(); + if( bv->GetLength() != 2 + || memcmp( bv->GetPointer(), FileMetaInformation::GetFileMetaInformationVersion(), 2 ) != 0 ) + { + xde.SetTag( Tag(0x0002, 0x0001) ); + xde.SetVR( VR::OB ); + const char *version = FileMetaInformation::GetFileMetaInformationVersion(); + xde.SetByteValue( version, 2 /*strlen(version)*/ ); + Replace( xde ); + } + } + // Media Storage SOP Class UID (0002,0002) -> see (0008,0016) + if( !FindDataElement( Tag(0x0002, 0x0002) ) || GetDataElement( Tag(0x0002,0x0002) ).IsEmpty() ) + { + if( !ds.FindDataElement( Tag(0x0008, 0x0016) ) || ds.GetDataElement( Tag(0x0008,0x0016) ).IsEmpty() ) + { + gdcm::MediaStorage ms; + ms.SetFromModality(ds); + const char *msstr = ms.GetString(); + if( msstr ) + { + VL::Type strlenMsstr = (VL::Type) strlen(msstr); + xde.SetByteValue( msstr, strlenMsstr ); + xde.SetTag( Tag(0x0002, 0x0002) ); + { + xde.SetVR( VR::UI ); + } + Insert( xde ); + } + else + { + gdcmErrorMacro( "Could not find MediaStorage" ); + } + } + else + { + const DataElement& msclass = ds.GetDataElement( Tag(0x0008, 0x0016) ); + xde = msclass; + xde.SetTag( Tag(0x0002, 0x0002) ); + if( msclass.GetVR() == VR::UN || msclass.GetVR() == VR::INVALID ) + { + xde.SetVR( VR::UI ); + } + Insert( xde ); + } + } + else // Ok there is a value in (0002,0002) let see if it match (0008,0016) + { + bool dicomdir = ds.FindDataElement( Tag(0x0004, 0x1220) ); // Directory Record Sequence + (void)dicomdir; + //if( !dicomdir ) + { + if( !ds.FindDataElement( Tag(0x0008, 0x0016) ) ) + { + // What should I do here ?? + gdcmWarningMacro( "Missing SOPClassUID in DataSet but found in FileMeta" ); + } + else + { + const DataElement& sopclass = ds.GetDataElement( Tag(0x0008, 0x0016) ); + DataElement mssopclass = GetDataElement( Tag(0x0002, 0x0002) ); + assert( !mssopclass.IsEmpty() ); + const ByteValue *bv = sopclass.GetByteValue(); + if( bv ) + { + mssopclass.SetByteValue( bv->GetPointer(), bv->GetLength() ); + } + else + { + throw gdcm::Exception( "SOP Class is empty sorry" ); + } + Replace( mssopclass ); + } + } + } + // Media Storage SOP Instance UID (0002,0003) -> see (0008,0018) + const DataElement &dummy = GetDataElement(Tag(0x0002,0x0003)); (void)dummy; + if( !FindDataElement( Tag(0x0002, 0x0003) ) || GetDataElement( Tag(0x0002,0x0003) ).IsEmpty() ) + { + if( ds.FindDataElement( Tag(0x0008, 0x0018) ) ) + { + const DataElement& msinst = ds.GetDataElement( Tag(0x0008, 0x0018) ); + if( msinst.IsEmpty() ) + { + // Ok there is nothing... + //UIDGenerator uid; + //const char *s = uid.Generate(); + //xde.SetByteValue( s, strlen(s) ); + // FIXME somebody before should make sure there is something... + xde = msinst; + } + else + { + xde = msinst; + } + xde.SetTag( Tag(0x0002, 0x0003) ); + if( msinst.GetVR() == VR::UN || msinst.GetVR() == VR::INVALID ) + { + xde.SetVR( VR::UI ); + } + Replace( xde ); + } + else + { + //assert(0); + throw gdcm::Exception( "No 2,3 and 8,18 element sorry" ); + } + } + else // Ok there is a value in (0002,0003) let see if it match (0008,0018) + { + bool dirrecsq = ds.FindDataElement( Tag(0x0004, 0x1220) ); // Directory Record Sequence + MediaStorage ms; + ms.SetFromHeader( *this ); + bool dicomdir = (ms == MediaStorage::MediaStorageDirectoryStorage && dirrecsq); + if( !dicomdir ) + { + if( !ds.FindDataElement( Tag(0x0008, 0x0018) ) || ds.GetDataElement( Tag(0x0008, 0x0018) ).IsEmpty() ) + { + throw gdcm::Exception( "No 8,18 element sorry" ); + //assert(0); + } + const DataElement& sopinst = ds.GetDataElement( Tag(0x0008, 0x0018) ); + //const DataElement & foo = GetDataElement( Tag(0x0002, 0x0003) ); + assert( !GetDataElement( Tag(0x0002, 0x0003) ).IsEmpty() ); + DataElement mssopinst = GetDataElement( Tag(0x0002, 0x0003) ); + const ByteValue *bv = sopinst.GetByteValue(); + assert( bv ); + mssopinst.SetByteValue( bv->GetPointer(), bv->GetLength() ); + Replace( mssopinst ); + } + } + //assert( !GetDataElement( Tag(0x0002,0x0003) ).IsEmpty() ); + // Transfer Syntax UID (0002,0010) -> ??? (computed at write time at most) + if( FindDataElement( Tag(0x0002, 0x0010) ) && !GetDataElement( Tag(0x0002,0x0010) ).IsEmpty() ) + { + DataElement tsuid = GetDataElement( Tag(0x0002, 0x0010) ); + const char * datasetts = DataSetTS.GetString(); + const ByteValue * bv = tsuid.GetByteValue(); + assert( bv ); + std::string currentts( bv->GetPointer(), bv->GetPointer() + bv->GetLength() ); + if( strlen(currentts.c_str()) != strlen(datasetts) + || strcmp( currentts.c_str(), datasetts ) != 0 ) + { + xde = tsuid; + VL::Type strlenDatasetts = (VL::Type) strlen(datasetts); + xde.SetByteValue( datasetts, strlenDatasetts ); + Replace( xde ); + } + if( tsuid.GetVR() != VR::UI ) + { + xde = tsuid; + xde.SetVR( VR::UI ); + Replace( xde ); + } + } + else + { + // Very bad !! + //throw Exception( "No (0002,0010) element found" ); + // Constuct it from DataSetTS + if( DataSetTS == TransferSyntax::TS_END ) + { + throw gdcm::Exception( "No TransferSyntax specified." ); + } + const char* str = TransferSyntax::GetTSString(DataSetTS); + VL::Type strlenStr = (VL::Type) strlen(str); + xde.SetByteValue( str, strlenStr ); + xde.SetVR( VR::UI ); + xde.SetTag( Tag(0x0002,0x0010) ); + Insert( xde ); + } + // Implementation Class UID (0002,0012) -> ?? + if( !FindDataElement( Tag(0x0002, 0x0012) ) ) + { + xde.SetTag( Tag(0x0002, 0x0012) ); + xde.SetVR( VR::UI ); + //const char implementation[] = GDCM_IMPLEMENTATION_CLASS_UID; + const char *implementation = FileMetaInformation::GetImplementationClassUID(); + VL::Type strlenImplementation = (VL::Type) strlen(implementation); + xde.SetByteValue( implementation, strlenImplementation ); + Insert( xde ); + } + else + { + // TODO: Need to check Implementation UID is actually a valid UID... + //const DataElement& impuid = GetDataElement( Tag(0x0002, 0x0012) ); + //const ByteValue *bv = impuid.GetByteValue(); + //assert( bv ); + //std::string copy( bv->GetPointer(), bv->GetLength() ); + //if( !UIDGenerator::IsValid( copy.c_str() ) ) + // { + //const char *implementation = FileMetaInformation::GetImplementationClassUID(); + //impuid.SetByteValue( implementation, strlen(implementation) ); + // } + } + // Implementation Version Name (0002,0013) -> ?? + if( !FindDataElement( Tag(0x0002, 0x0013) ) ) + { + xde.SetTag( Tag(0x0002, 0x0013) ); + xde.SetVR( VR::SH ); + //const char version[] = GDCM_IMPLEMENTATION_VERSION_NAME; + SHComp version = FileMetaInformation::GetImplementationVersionName(); + VL::Type strlenVersion = (VL::Type)strlen(version); + xde.SetByteValue( version, strlenVersion ); + Insert( xde ); + } + // Source Application Entity Title (0002,0016) -> ?? + if( !FindDataElement( Tag(0x0002, 0x0016) ) ) + { + xde.SetTag( Tag(0x0002, 0x0016) ); + xde.SetVR( VR::AE ); + //const char title[] = GDCM_SOURCE_APPLICATION_ENTITY_TITLE; + const char *title = FileMetaInformation::GetSourceApplicationEntityTitle(); + VL::Type strlenTitle = (VL::Type)strlen(title); + xde.SetByteValue( title, strlenTitle ); + Insert( xde ); + } + // Do this one last ! + // (Meta) Group Length (0002,0000) -> computed + Attribute<0x0002, 0x0000> filemetagrouplength; + Remove( filemetagrouplength.GetTag() ); + unsigned int glen = GetLength(); + assert( (glen % 2) == 0 ); + filemetagrouplength.SetValue( glen ); + Insert( filemetagrouplength.GetAsDataElement() ); + + assert( !IsEmpty() ); +} + +// FIXME +// This code should clearly be rewritten with some template meta programing to +// enable reuse of code... +// +// \postcondition after the file meta information (well before the dataset...) +template +bool ReadExplicitDataElement(std::istream &is, ExplicitDataElement &de) +{ + // Read Tag + std::streampos start = is.tellg(); + //std::cout << "Start: " << start << std::endl; + Tag t; + if( !t.template Read(is) ) + { + assert(0 && "Should not happen" ); + return false; + } + //std::cout << "Tag: " << t << std::endl; + if( t.GetGroup() != 0x0002 ) + { + //gdcmDebugMacro( "Done reading File Meta Information" ); + std::streampos currentpos = is.tellg(); + // old code was fseeking from the beginning of file + // which seems to be quite different than fseeking in reverse from + // the current position... ??? + //is.seekg( start, std::ios::beg ); + assert( (start - currentpos) <= 0); + assert( (int)(start - currentpos) == -4 ); + is.seekg( (start - currentpos), std::ios::cur ); + return false; + } + // Read VR + VR vr; + if( !vr.Read(is) ) + { + is.seekg( start, std::ios::beg ); + return false; + } + //std::cout << "VR : " << vr << std::endl; + // Read Value Length + VL vl; + if( vr & VR::VL32 ) + { + if( !vl.template Read(is) ) + { + assert(0 && "Should not happen"); + return false; + } + } + else + { + // Value Length is stored on 16bits only + vl.template Read16(is); + } + //gdcmDebugMacro( "VL : " << vl ); + // Read the Value + ByteValue *bv = NULL; + if( vr == VR::SQ ) + { + assert(0 && "Should not happen"); + return false; + } + else if( vl.IsUndefined() ) + { + assert(0 && "Should not happen"); + return false; + } + else + { + bv = new ByteValue; + } + // We have the length we should be able to read the value + bv->SetLength(vl); // perform realloc + if( !bv->template Read(is) ) + { + assert(0 && "Should not happen"); + return false; + } + //std::cout << "Value : "; + //bv->Print( std::cout ); + //std::cout << std::endl; + assert( bv->GetLength() == vl ); + + de.SetTag(t); + de.SetVR(vr); + de.SetVL(vl); + // FIXME: There should be a way to set the Value to the NULL pointer... + de.SetValue(*bv); + +// if( vl == 0 ) +// { +// assert( de.IsEmpty() ); +// } + + return true; +} + +template +bool ReadImplicitDataElement(std::istream &is, ImplicitDataElement &de) +{ + // See PS 3.5, 7.1.3 Data Element Structure With Implicit VR + std::streampos start = is.tellg(); + // Read Tag + Tag t; + if( !t.template Read(is) ) + { + assert(0 && "Should not happen"); + return false; + } + //std::cout << "Tag: " << t << std::endl; + if( t.GetGroup() != 0x0002 ) + { + gdcmDebugMacro( "Done reading File Meta Information" ); + is.seekg( start, std::ios::beg ); + return false; + } + // Read Value Length + VL vl; + if( !vl.template Read(is) ) + { + assert(0 && "Should not happen"); + return false; + } + ByteValue *bv = 0; + if( vl.IsUndefined() ) + { + assert(0 && "Should not happen"); + return false; + } + else + { + bv = new ByteValue; + } + // We have the length we should be able to read the value + bv->SetLength(vl); // perform realloc + if( !bv->template Read(is) ) + { + assert(0 && "Should not happen"); + return false; + } + de.SetTag(t); + de.SetVL(vl); + de.SetValue(*bv); + + return true; +} + +/* + * Except for the 128 bytes preamble and the 4 bytes prefix, the File Meta + * Information shall be encoded using the Explicit VR Little Endian Transfer + * Syntax (UID=1.2.840.10008.1.2.1) as defined in DICOM PS 3.5. + * Values of each File Meta Element shall be padded when necessary to achieve + * an even length as specified in PS 3.5 by their corresponding Value + * Representation. For compatibility with future versions of this Standard, + * any Tag (0002,xxxx) not defined in Table 7.1-1 shall be ignored. + * Values of all Tags (0002,xxxx) are reserved for use by this Standard and + * later versions of DICOM. + * Note: PS 3.5 specifies that Elements with Tags (0001,xxxx), (0003,xxxx), + * (0005,xxxx), and (0007,xxxx) shall not be used. + */ +/// \TODO FIXME +/// For now I do a Seek back of 6 bytes. It would be better to finish reading +/// the first element of the FMI so that I can read the group length and +/// therefore compare it against the actual value we found... +std::istream &FileMetaInformation::Read(std::istream &is) +{ + //ExplicitAttribute<0x0002,0x0000> metagl; + //metagl.Read(is); + + // TODO: Can now load data from std::ios::cur to std::ios::cur + metagl.GetValue() + + ExplicitDataElement xde; + Tag gl; + gl.Read(is); + if( gl.GetGroup() != 0x2 ) throw Exception( "INVALID" ); + if( gl.GetElement() != 0x0 ) throw Exception( "INVALID" ); + VR vr; + vr.Read(is); + if( vr == VR::INVALID ) throw Exception( "INVALID" ); + if( vr != VR::UL ) throw Exception( "INVALID" ); + // TODO FIXME: I should not do seekg for valid file this is costly + is.seekg(-6,std::ios::cur); +// /opt/ibmcmp/vacpp/9.0/bin/xlC: 1501-230 (S) Internal compiler error; please contact your Service Representative +//#if !defined(__xlC__) + xde.Read(is); +//#endif + Insert( xde ); + // See PS 3.5, Data Element Structure With Explicit VR + while( ReadExplicitDataElement(is, xde ) ) + { + Insert( xde ); + } + + // Now is a good time to compute the transfer syntax: + ComputeDataSetTransferSyntax(); + + // we are at the end of the meta file information and before the dataset + return is; +} + +std::istream &FileMetaInformation::ReadCompat(std::istream &is) +{ + // \precondition + assert( is.good() ); + // First off save position in case we fail (no File Meta Information) + // See PS 3.5, Data Element Structure With Explicit VR + if( !IsEmpty() ) + { + throw Exception( "Serious bug" ); + } + Tag t; + if( !t.Read(is) ) + { + throw Exception( "Cannot read very first tag" ); + } + if( t.GetGroup() == 0x0002 ) + { + // GE_DLX-8-MONO2-PrivateSyntax.dcm is in Implicit... + return ReadCompatInternal(is); + } + else if( t.GetGroup() == 0x0008 ) // + { + char vr_str[3]; + is.read(vr_str, 2); + vr_str[2] = '\0'; + VR::VRType vr = VR::GetVRType(vr_str); + if( vr != VR::VR_END ) + { + // File start with a 0x0008 element but no FileMetaInfo and is Explicit + DataSetTS = TransferSyntax::ExplicitVRLittleEndian; + } + else + { + // File start with a 0x0008 element but no FileMetaInfo and is Implicit + DataSetTS = TransferSyntax::ImplicitVRLittleEndian; + } + is.seekg(-6, std::ios::cur); // Seek back + } + else if( t.GetGroup() == 0x0800 ) // Good ol' ACR NEMA + { + char vr_str[3]; + is.read(vr_str, 2); + vr_str[2] = '\0'; + VR::VRType vr = VR::GetVRType(vr_str); + if( vr != VR::VR_END ) + { + // File start with a 0x0008 element but no FileMetaInfo and is Explicit + DataSetTS = TransferSyntax::ExplicitVRBigEndian; + } + else + { + // File start with a 0x0008 element but no FileMetaInfo and is Implicit + DataSetTS = TransferSyntax::ImplicitVRBigEndianACRNEMA; + } + is.seekg(-6, std::ios::cur); // Seek back + } + else if( t.GetElement() == 0x0010 ) // Hum, is it a private creator ? + { + is.seekg(-4, std::ios::cur); // Seek back + DataSetTS = TransferSyntax::ImplicitVRLittleEndian; + } + else + { + //assert( t.GetElement() == 0x0 ); + char vr_str[3]; + VR::VRType vr = VR::VR_END; + if( is.read(vr_str, 2) ) + { + vr_str[2] = '\0'; + vr = VR::GetVRType(vr_str); + } + else + { + throw Exception( "Impossible: cannot read 2bytes for VR" ); + } + is.seekg(-6, std::ios::cur); // Seek back + if( vr != VR::VR_END ) + { + // Ok we found a VR, this is 99% likely to be our safe bet + if( t.GetGroup() > 0xff || t.GetElement() > 0xff ) + DataSetTS = TransferSyntax::ExplicitVRBigEndian; + else + DataSetTS = TransferSyntax::ExplicitVRLittleEndian; + } + else + { + DataElement null( Tag(0x0,0x0), 0); + ImplicitDataElement ide; + ide.ReadPreValue(is); + if( ide.GetTag() == null.GetTag() && ide.GetVL() == 4 ) + { + // This is insane, we are actually reading an attribute with tag (0,0) ! + // something like IM-0001-0066.CommandTag00.dcm was crafted + ide.ReadValue(is); + ReadCompat(is); // this will read the next element + assert( DataSetTS == TransferSyntax::ImplicitVRLittleEndian ); + is.seekg(-12, std::ios::cur); // Seek back + return is; + } + // else + throw Exception( "Cannot find DICOM type. Giving up." ); + } + } + return is; +} + +#define ADDVRIMPLICIT( element ) \ + case element: \ + de.SetVR( (VR::VRType)TagToType<0x0002,element>::VRType ); \ + break; + +bool AddVRToDataElement(DataElement &de) +{ + switch(de.GetTag().GetElement()) + { + ADDVRIMPLICIT(0x0000); + ADDVRIMPLICIT(0x0001); + ADDVRIMPLICIT(0x0002); + ADDVRIMPLICIT(0x0003); + ADDVRIMPLICIT(0x0010); + ADDVRIMPLICIT(0x0012); + ADDVRIMPLICIT(0x0013); + ADDVRIMPLICIT(0x0016); + ADDVRIMPLICIT(0x0100); + ADDVRIMPLICIT(0x0102); + default: + return false; + } + return true; +} + +template +std::istream &FileMetaInformation::ReadCompatInternal(std::istream &is) +{ + //assert( t.GetGroup() == 0x0002 ); +// if( t.GetGroup() == 0x0002 ) + { + // Purposely not Re-use ReadVR since we can read VR_END + char vr_str[2]; + is.read(vr_str, 2); + if( VR::IsValid(vr_str) ) + { + MetaInformationTS = TransferSyntax::Explicit; + // Hourah ! + // Looks like an Explicit File Meta Information Header. + is.seekg(-6, std::ios::cur); // Seek back + //is.seekg(start, std::ios::beg); // Seek back + //std::streampos dpos = is.tellg(); + ExplicitDataElement xde; + while( ReadExplicitDataElement(is, xde ) ) + { + //std::cout << xde << std::endl; + if( xde.GetVR() == VR::UN ) + { + gdcmWarningMacro( "VR::UN found in file Meta header. " + "VR::UN will be replaced with proper VR for tag: " << xde.GetTag() ); + AddVRToDataElement(xde); + } + Insert( xde ); + } + // Now is a good time to find out the dataset transfer syntax + ComputeDataSetTransferSyntax(); + } + else + { + MetaInformationTS = TransferSyntax::Implicit; + gdcmWarningMacro( "File Meta Information is implicit. VR will be explicitely added" ); + // Ok this might be an implicit encoded Meta File Information header... + // GE_DLX-8-MONO2-PrivateSyntax.dcm + is.seekg(-6, std::ios::cur); // Seek back + ImplicitDataElement ide; + while( ReadImplicitDataElement(is, ide ) ) + { + if( AddVRToDataElement(ide) ) + { + Insert(ide); + } + else + { + gdcmWarningMacro( "Unknown element found in Meta Header: " << ide.GetTag() ); + } + } + // Now is a good time to find out the dataset transfer syntax + ComputeDataSetTransferSyntax(); + } + } +// else +// { +// gdcmDebugMacro( "No File Meta Information. Start with Tag: " << t ); +// is.seekg(-4, std::ios::cur); // Seek back +// } + + // we are at the end of the meta file information and before the dataset + return is; +} + +//void FileMetaInformation::SetTransferSyntaxType(TS const &ts) +//{ +// //assert( DS == 0 ); +// //InternalTS = ts; +//} + +// FIXME: If any boozoo ever write a SQ in the meta header +// we are in bad shape... +void FileMetaInformation::ComputeDataSetTransferSyntax() +{ + const Tag t(0x0002,0x0010); + const DataElement &de = GetDataElement(t); + std::string ts; + const ByteValue *bv = de.GetByteValue(); + if( !bv ) + { + throw Exception( "Unknown Transfer syntax" ); + } + // Pad string with a \0 + ts = std::string(bv->GetPointer(), bv->GetLength()); + TransferSyntax tst(TransferSyntax::GetTSType(ts.c_str())); + if( tst == TransferSyntax::TS_END ) + { + throw Exception( "Unknown Transfer syntax" ); + } + DataSetTS = tst; + + // postcondition + DataSetTS.IsValid(); +} + +void FileMetaInformation::SetDataSetTransferSyntax(const TransferSyntax &ts) +{ + DataSetTS = ts; +} + +std::string FileMetaInformation::GetMediaStorageAsString() const +{ + // D 0002|0002 [UI] [Media Storage SOP Class UID] + // [1.2.840.10008.5.1.4.1.1.12.1] + // ==> [X-Ray Angiographic Image Storage] + const Tag t(0x0002,0x0002); + if( !FindDataElement( t ) ) + { + gdcmDebugMacro( "File Meta information is present but does not" + " contains " << t ); + return ""; + } + const DataElement &de = GetDataElement(t); + std::string ts; + { + const ByteValue *bv = de.GetByteValue(); + assert( bv ); + if( bv->GetPointer() && bv->GetLength() ) + { + // Pad string with a \0 + ts = std::string(bv->GetPointer(), bv->GetLength()); + } + } + // Paranoid check: if last character of a VR=UI is space let's pretend this is a \0 + if( ts.size() ) + { + char &last = ts[ts.size()-1]; + if( last == ' ' ) + { + gdcmWarningMacro( "Media Storage Class UID: " << ts << " contained a trailing space character" ); + last = '\0'; + } + } + return ts; +} + +MediaStorage FileMetaInformation::GetMediaStorage() const +{ + const std::string &ts = GetMediaStorageAsString(); + if( ts.empty() ) return MediaStorage::MS_END; + + MediaStorage ms = MediaStorage::GetMSType(ts.c_str()); + if( ms == MediaStorage::MS_END ) + { + gdcmWarningMacro( "Media Storage Class UID: " << ts << " is unknow" ); + } + return ms; +} + +void FileMetaInformation::Default() +{ +} + +std::ostream &FileMetaInformation::Write(std::ostream &os) const +{ +// if( !IsValid() ) +// { +// gdcmErrorMacro( "File is not valid" ); +// return os; +// } + P.Write(os); + +// if( IsEmpty() ) +// { +// std::cerr << "IsEmpty" << std::endl; +// FileMetaInformation fmi; +// fmi.Default(); +// //fmi.Write(os); +// IOSerialize::Write(os,fmi); +// } +// else if( IsValid() ) + { + this->DataSet::Write(os); + } +// else +// { +// assert(0); +// } +#if 0 + // At least make sure to have group length + //if( !DS->FindDataElement( Tag(0x0002, 0x0000) ) ) + { + //if( DS->GetNegociatedType() == TransferSyntax::Explicit ) + { + ExplicitDataElement xde( Tag(0x0002, 0x0000), 4, VR::UL ); + SmartPointer bv = new ByteValue; + bv->SetLength( 4 ); + uint32_t len = DS->GetLength(); + Element el = + reinterpret_cast< Element& > ( len ); + std::stringstream ss; + el.Write( ss ); + bv->Read( ss ); + xde.SetValue( *bv ); + // This is the first element, so simply write the element and + // then start writing the remaining of the File Meta Information + xde.Write(os); + } + } + +#endif + return os; +} + +} // end namespace gdcm diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmFileMetaInformation.h b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmFileMetaInformation.h new file mode 100644 index 0000000..199431d --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmFileMetaInformation.h @@ -0,0 +1,148 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMFILEMETAINFORMATION_H +#define GDCMFILEMETAINFORMATION_H + +#include "gdcmPreamble.h" +#include "gdcmDataSet.h" +#include "gdcmDataElement.h" +#include "gdcmMediaStorage.h" +#include "gdcmTransferSyntax.h" +#include "gdcmExplicitDataElement.h" + +namespace gdcm +{ +/** + * \brief Class to represent a File Meta Information + * + * \details FileMetaInformation is a Explicit Structured Set. Whenever the + * file contains an ImplicitDataElement DataSet, a conversion will take place. + * + * Definition: + * The File Meta Information includes identifying information on the + * encapsulated Data Set. This header consists of a 128 byte File Preamble, + * followed by a 4 byte DICOM prefix, followed by the File Meta Elements shown + * in Table 7.1-1. This header shall be present in every DICOM file. + * + * \see Writer Reader + */ +class GDCM_EXPORT FileMetaInformation : public DataSet +{ +public: + // FIXME: TransferSyntax::TS_END -> TransferSyntax::ImplicitDataElement + FileMetaInformation():DataSetTS(TransferSyntax::TS_END),MetaInformationTS(TransferSyntax::Unknown),DataSetMS(MediaStorage::MS_END) {} + + friend std::ostream &operator<<(std::ostream &_os, const FileMetaInformation &_val); + + bool IsValid() const { return true; } + + TransferSyntax::NegociatedType GetMetaInformationTS() const { return MetaInformationTS; } + void SetDataSetTransferSyntax(const TransferSyntax &ts); + const TransferSyntax &GetDataSetTransferSyntax() const { return DataSetTS; } + MediaStorage GetMediaStorage() const; + std::string GetMediaStorageAsString() const; + + // FIXME: no virtual function means: duplicate code... + void Insert(const DataElement& de) { + if( de.GetTag().GetGroup() == 0x0002 ) + { + InsertDataElement( de ); + } + else + { + gdcmErrorMacro( "Cannot add element with group != 0x0002 in the file meta header: " << de ); + } + } + void Replace(const DataElement& de) { + Remove(de.GetTag()); + Insert(de); + } + + /// Read + std::istream &Read(std::istream &is); + std::istream &ReadCompat(std::istream &is); + + /// Write + std::ostream &Write(std::ostream &os) const; + + /// Construct a FileMetaInformation from an already existing DataSet: + void FillFromDataSet(DataSet const &ds); + + /// Get Preamble + const Preamble &GetPreamble() const { return P; } + Preamble &GetPreamble() { return P; } + void SetPreamble(const Preamble &p) { P = p; } + + /// Override the GDCM default values: + static void SetImplementationClassUID(const char * imp); + static void AppendImplementationClassUID(const char * imp); + static const char *GetImplementationClassUID(); + static void SetImplementationVersionName(const char * version); + static const char *GetImplementationVersionName(); + static void SetSourceApplicationEntityTitle(const char * title); + static const char *GetSourceApplicationEntityTitle(); + + FileMetaInformation(FileMetaInformation const &fmi):DataSet(fmi) + { + DataSetTS = fmi.DataSetTS; + MetaInformationTS = fmi.MetaInformationTS; + DataSetMS = fmi.DataSetMS; + } + + VL GetFullLength() const { + return P.GetLength() + DataSet::GetLength(); + } + +protected: + void ComputeDataSetTransferSyntax(); // FIXME + + template + std::istream &ReadCompatInternal(std::istream &is); + + void Default(); + void ComputeDataSetMediaStorageSOPClass(); + + TransferSyntax DataSetTS; + TransferSyntax::NegociatedType MetaInformationTS; + MediaStorage::MSType DataSetMS; + +protected: + static const char * GetFileMetaInformationVersion(); + static const char * GetGDCMImplementationClassUID(); + static const char * GetGDCMImplementationVersionName(); + static const char * GetGDCMSourceApplicationEntityTitle(); + +private: + Preamble P; + +//static stuff: + static const char GDCM_FILE_META_INFORMATION_VERSION[]; + static const char GDCM_IMPLEMENTATION_CLASS_UID[]; + static const char GDCM_IMPLEMENTATION_VERSION_NAME[]; + static const char GDCM_SOURCE_APPLICATION_ENTITY_TITLE[]; + static std::string ImplementationClassUID; + static std::string ImplementationVersionName; + static std::string SourceApplicationEntityTitle; +}; +//----------------------------------------------------------------------------- +inline std::ostream& operator<<(std::ostream &os, const FileMetaInformation &val) +{ + os << val.GetPreamble() << std::endl; + val.Print( os ); + return os; +} + +} // end namespace gdcm + +#endif //GDCMFILEMETAINFORMATION_H diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmFileSet.cxx b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmFileSet.cxx new file mode 100644 index 0000000..120d4be --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmFileSet.cxx @@ -0,0 +1,37 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmFileSet.h" +#include "gdcmSystem.h" + +namespace gdcm +{ + bool FileSet::AddFile(const char *filename) + { + if( System::FileExists(filename) ) + { + Files.push_back( filename ); + return true; + } + return false; + } + void FileSet::SetFiles(FilesType const &files) + { + FilesType::const_iterator it = files.begin(); + for( ; it != files.end(); ++it ) + { + AddFile( it->c_str() ); + } + } + +} diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmFileSet.h b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmFileSet.h new file mode 100644 index 0000000..2a6b8f8 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmFileSet.h @@ -0,0 +1,59 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMFILESET_H +#define GDCMFILESET_H + +#include "gdcmFile.h" +#include + +namespace gdcm +{ +/** + * \brief + * File-set: A File-set is a collection of DICOM Files (and possibly non-DICOM Files) + * that share a common naming space within which File IDs are unique. + */ +class GDCM_EXPORT FileSet +{ + friend std::ostream& operator<<(std::ostream &_os, const FileSet &d); +public: + FileSet():Files() {} + typedef std::string FileType; + typedef std::vector FilesType; + + /// \deprecated. Does nothing + void AddFile(File const & ) {} + + /// Add a file 'filename' to the list of files. Return true on success, false in case filename could not + /// be found on system. + bool AddFile(const char *filename); + + void SetFiles(FilesType const &files); + FilesType const &GetFiles() const { + return Files; + } + +private: + FilesType Files; +}; +//----------------------------------------------------------------------------- +inline std::ostream& operator<<(std::ostream &os, const FileSet &f) +{ + (void)f; // FIXME + return os; +} + +} // end namespace gdcm + +#endif //GDCMFILESET_H diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmFragment.cxx b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmFragment.cxx new file mode 100644 index 0000000..eb2785d --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmFragment.cxx @@ -0,0 +1,37 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmFragment.h" + +namespace gdcm +{ + +VL Fragment::GetLength() const +{ + assert( !ValueLengthField.IsUndefined() ); + assert( !ValueField || ValueField->GetLength() == ValueLengthField ); + return TagField.GetLength() + ValueLengthField.GetLength() + + ValueLengthField; +} + +VL Fragment::ComputeLength() const +{ + const ByteValue *bv = GetByteValue(); + assert( bv ); + assert( !ValueLengthField.IsUndefined() ); + //assert( !ValueField || ValueField->GetLength() == ValueLengthField ); + return TagField.GetLength() + ValueLengthField.GetLength() + + bv->ComputeLength() /*ValueLengthField*/; +} + +} // end namespace gdcm diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmFragment.h b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmFragment.h new file mode 100644 index 0000000..a56e5aa --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmFragment.h @@ -0,0 +1,239 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMFRAGMENT_H +#define GDCMFRAGMENT_H + +#include "gdcmDataElement.h" +#include "gdcmByteValue.h" +#include "gdcmSmartPointer.h" +#include "gdcmParseException.h" + +namespace gdcm +{ + +// Implementation detail: +// I think Fragment should be a protected subclass of DataElement: +// looking somewhat like this: +/* +class GDCM_EXPORT Fragment : protected DataElement +{ +public: + using DataElement::GetTag; + using DataElement::GetVL; + using DataElement::SetByteValue; + using DataElement::GetByteValue; + using DataElement::GetValue; +*/ +// Instead I am only hiding the SetTag member... + +/** + * \brief Class to represent a Fragment + */ +class GDCM_EXPORT Fragment : public DataElement +{ +//protected: +// void SetTag(const Tag &t); +public: + Fragment() : DataElement(Tag(0xfffe, 0xe000), 0) {} + friend std::ostream &operator<<(std::ostream &os, const Fragment &val); + + VL GetLength() const; + + VL ComputeLength() const; + + template + std::istream &Read(std::istream &is) + { + ReadPreValue(is); + return ReadValue(is); + } + + template + std::istream &ReadPreValue(std::istream &is) + { + const Tag itemStart(0xfffe, 0xe000); + const Tag seqDelItem(0xfffe,0xe0dd); + + TagField.Read(is); + if( !is ) + { + // BogusItemStartItemEnd.dcm + throw Exception( "Problem #1" ); + return is; + } + if( !ValueLengthField.Read(is) ) + { + // GENESIS_SIGNA-JPEG-CorruptFrag.dcm + // JPEG fragment is declared to have 61902, but infact really is only 61901 + // so we end up reading 0xddff,0x00e0, and VL = 0x0 (1 byte) + throw Exception( "Problem #2" ); + return is; + } +#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + if( TagField != itemStart && TagField != seqDelItem ) + { + throw Exception( "Problem #3" ); + } +#endif + return is; + } + + template + std::istream &ReadValue(std::istream &is) + { + // Superclass + const Tag itemStart(0xfffe, 0xe000); + const Tag seqDelItem(0xfffe,0xe0dd); + // Self + SmartPointer bv = new ByteValue; + bv->SetLength(ValueLengthField); + if( !bv->Read(is) ) + { + // Fragment is incomplete, but is a itemStart, let's try to push it anyway... + gdcmWarningMacro( "Fragment could not be read" ); + //bv->SetLength(is.gcount()); + ValueField = bv; + ParseException pe; + pe.SetLastElement( *this ); + throw pe; + return is; + } + ValueField = bv; + return is; + } + + template + std::istream &ReadBacktrack(std::istream &is) + { + const Tag itemStart(0xfffe, 0xe000); + const Tag seqDelItem(0xfffe,0xe0dd); + + bool cont = true; + const std::streampos start = is.tellg(); + const int max = 10; + int offset = 0; + while( cont ) + { + TagField.Read(is); + assert( is ); + if( TagField != itemStart && TagField != seqDelItem ) + { + ++offset; + is.seekg( (std::streampos)((size_t)start - offset) ); + gdcmWarningMacro( "Fuzzy Search, backtrack: " << (start - is.tellg()) << " Offset: " << is.tellg() ); + if( offset > max ) + { + gdcmErrorMacro( "Giving up" ); + throw "Impossible to backtrack"; + return is; + } + } + else + { + cont = false; + } + } + assert( TagField == itemStart || TagField == seqDelItem ); + if( !ValueLengthField.Read(is) ) + { + return is; + } + + // Self + SmartPointer bv = new ByteValue; + bv->SetLength(ValueLengthField); + if( !bv->Read(is) ) + { + // Fragment is incomplete, but is a itemStart, let's try to push it anyway... + gdcmWarningMacro( "Fragment could not be read" ); + //bv->SetLength(is.gcount()); + ValueField = bv; + ParseException pe; + pe.SetLastElement( *this ); + throw pe; + return is; + } + ValueField = bv; + return is; + } + + + template + std::ostream &Write(std::ostream &os) const { + const Tag itemStart(0xfffe, 0xe000); + const Tag seqDelItem(0xfffe,0xe0dd); + if( !TagField.Write(os) ) + { + assert(0 && "Should not happen"); + return os; + } + assert( TagField == itemStart + || TagField == seqDelItem ); + const ByteValue *bv = GetByteValue(); + // VL + // The following piece of code is hard to read in order to support such broken file as: + // CompressedLossy.dcm + if( IsEmpty() ) + { + //assert( bv ); + VL zero = 0; + if( !zero.Write(os) ) + { + assert(0 && "Should not happen"); + return os; + } + } + else + { + assert( ValueLengthField ); + assert( !ValueLengthField.IsUndefined() ); + const VL actuallen = bv->ComputeLength(); + assert( actuallen == ValueLengthField || actuallen == ValueLengthField + 1 ); + if( !actuallen.Write(os) ) + { + assert(0 && "Should not happen"); + return os; + } + } + // Value + if( ValueLengthField && bv ) + { + // Self + assert( bv ); + assert( bv->GetLength() == ValueLengthField ); + if( !bv->Write(os) ) + { + assert(0 && "Should not happen"); + return os; + } + } + return os; + } +}; +//----------------------------------------------------------------------------- +inline std::ostream &operator<<(std::ostream &os, const Fragment &val) +{ + os << "Tag: " << val.TagField; + os << "\tVL: " << val.ValueLengthField; + if( val.ValueField ) + { + os << "\t" << *(val.ValueField); + } + + return os; +} + +} // end namespace gdcm + +#endif //GDCMFRAGMENT_H diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmFragment.txx b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmFragment.txx new file mode 100644 index 0000000..23ebf78 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmFragment.txx @@ -0,0 +1,23 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMFRAGMENT_TXX +#define GDCMFRAGMENT_TXX + +#include "gdcmFragment.h" + +namespace gdcm +{ +} // end namespace gdcm + +#endif // GDCMFRAGMENT_TXX diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmImplicitDataElement.cxx b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmImplicitDataElement.cxx new file mode 100644 index 0000000..984ea20 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmImplicitDataElement.cxx @@ -0,0 +1,62 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmImplicitDataElement.h" + +#include "gdcmByteValue.h" +#include "gdcmSequenceOfItems.h" + +namespace gdcm +{ + +VL ImplicitDataElement::GetLength() const +{ + const Value &v = GetValue(); + if( ValueLengthField.IsUndefined() ) + { + assert( ValueField->GetLength().IsUndefined() ); + Value *p = ValueField; + SequenceOfItems *sq = dynamic_cast(p); + if( sq ) + { + return TagField.GetLength() + ValueLengthField.GetLength() + + sq->ComputeLength(); + } +#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + SequenceOfFragments *sf = dynamic_cast(p); + if( sf ) + { + //assert( VRField & VR::OB_OW ); // VR::INVALID is not possible AFAIK... + return TagField.GetLength() /*+ VRField.GetLength()*/ + + ValueLengthField.GetLength() + sf->ComputeLength(); + } +#endif + assert( !ValueLengthField.IsUndefined() ); + return ValueLengthField; + } + //else if( const SequenceOfItems *sqi = GetSequenceOfItems() ) + else if( const SequenceOfItems *sqi = dynamic_cast(&v) ) + { + // TestWrite2 + return TagField.GetLength() + ValueLengthField.GetLength() + + sqi->ComputeLength(); + } + else + { + assert( !ValueField || ValueField->GetLength() == ValueLengthField ); + return TagField.GetLength() + ValueLengthField.GetLength() + + ValueLengthField; + } +} + +} // end namespace gdcm diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmImplicitDataElement.h b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmImplicitDataElement.h new file mode 100644 index 0000000..d255b9f --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmImplicitDataElement.h @@ -0,0 +1,54 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMIMPLICITDATAELEMENT_H +#define GDCMIMPLICITDATAELEMENT_H + +#include "gdcmDataElement.h" + +namespace gdcm +{ + +/** + * \brief Class to represent an *Implicit VR* Data Element + * \note bla + */ +class GDCM_EXPORT ImplicitDataElement : public DataElement +{ +public: + VL GetLength() const; + + template + std::istream &Read(std::istream& is); + + template + std::istream &ReadPreValue(std::istream& is); + + template + std::istream &ReadValue(std::istream& is, bool readvalues = true); + + template + std::istream &ReadWithLength(std::istream& is, VL & length, bool readvalues = true); + + template + std::istream &ReadValueWithLength(std::istream& is, VL & length, bool readvalues = true); + + template + const std::ostream &Write(std::ostream& os) const; +}; + +} // end namespace gdcm + +#include "gdcmImplicitDataElement.txx" + +#endif //GDCMIMPLICITDATAELEMENT_H diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmImplicitDataElement.txx b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmImplicitDataElement.txx new file mode 100644 index 0000000..2cd8768 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmImplicitDataElement.txx @@ -0,0 +1,584 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMIMPLICITDATAELEMENT_TXX +#define GDCMIMPLICITDATAELEMENT_TXX + +#include "gdcmSequenceOfItems.h" +#include "gdcmValueIO.h" +#include "gdcmSwapper.h" +#ifdef GDCM_WORDS_BIGENDIAN +#include "gdcmTagToVR.h" +#endif + +namespace gdcm +{ + +//----------------------------------------------------------------------------- +template +std::istream &ImplicitDataElement::Read(std::istream &is) +{ + ReadPreValue(is); + return ReadValue(is); +} + +template +std::istream &ImplicitDataElement::ReadPreValue(std::istream& is) +{ + TagField.Read(is); + // See PS 3.5, 7.1.3 Data Element Structure With Implicit VR + // Read Tag + if( !is ) + { + if( !is.eof() ) // FIXME This should not be needed + assert(0 && "Should not happen"); + return is; + } + const Tag itemStartItem(0xfffe,0xe000); + if( TagField == itemStartItem ) return is; + + //assert( TagField != Tag(0xfffe,0xe0dd) ); + // Read Value Length + if( !ValueLengthField.Read(is) ) + { + //assert(0 && "Should not happen"); + throw Exception("Impossible ValueLengthField"); + return is; + } + return is; +} + +template +std::istream &ImplicitDataElement::ReadValue(std::istream &is, bool readvalues) +{ + if( is.eof() ) return is; + const Tag itemStartItem(0xfffe,0xe000); + assert( TagField != itemStartItem ); + + /* + * technically this should not be needed, but what if an implementor, forgot + * to set VL = 0, then we should make sure to exit early + */ + const Tag itemDelItem(0xfffe,0xe00d); + if( TagField == itemDelItem ) + { + if( ValueLengthField != 0 ) + { + gdcmWarningMacro( "VL should be set to 0" ); + } + ValueField = 0; + return is; + } + //std::cerr << "imp cur tag=" << TagField << " VL=" << ValueLengthField << std::endl; + //if( ValueLengthField > length && !ValueLengthField.IsUndefined() ) + // { + // gdcmWarningMacro( "Cannot read more length than what is remaining in the file" ); + // throw Exception( "Impossible" ); + // } + if( ValueLengthField == 0 ) + { + // Simple fast path + ValueField = 0; + return is; + } + else if( ValueLengthField.IsUndefined() ) + { + //assert( de.GetVR() == VR::SQ ); + // FIXME what if I am reading the pixel data... + //assert( TagField != Tag(0x7fe0,0x0010) ); + if( TagField != Tag(0x7fe0,0x0010) ) + { + ValueField = new SequenceOfItems; + } + else + { + gdcmErrorMacro( "Undefined value length is impossible in non-encapsulated Transfer Syntax. Proceeding with caution" ); + ValueField = new SequenceOfFragments; + } + //VRField = VR::SQ; + } + else + { + if( true /*ValueLengthField < 8 */ ) + { + ValueField = new ByteValue; + } + else + { + // In the following we read 4 more bytes in the Value field + // to find out if this is a SQ or not + // there is still work to do to handle the PMS featured SQ + // where item Start is in fact 0xfeff, 0x00e0 ... sigh + const Tag itemStart(0xfffe, 0xe000); +#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + const Tag itemPMSStart(0xfeff, 0x00e0); + const Tag itemPMSStart2(0x3f3f, 0x3f00); +#endif + Tag item; + // TODO FIXME + // This is pretty dumb to actually read to later on seekg back, why not `peek` directly ? + item.Read(is); + // Maybe this code can later be rewritten as I believe that seek back + // is very slow... + is.seekg(-4, std::ios::cur ); + if( item == itemStart ) + { + assert( TagField != Tag(0x7fe0,0x0010) ); + ValueField = new SequenceOfItems; + } +#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + else if ( item == itemPMSStart ) + { + // MR_Philips_Intera_No_PrivateSequenceImplicitVR.dcm + gdcmWarningMacro( "Illegal Tag for Item starter: " << TagField << " should be: " << itemStart ); + // TODO: We READ Explicit ok...but we store Implicit ! + // Indeed when copying the VR will be saved... pretty cool eh ? + ValueField = new SequenceOfItems; + ValueField->SetLength(ValueLengthField); // perform realloc + std::streampos start = is.tellg(); + try + { + if( !ValueIO::Read(is,*ValueField,readvalues) ) + { + assert(0 && "Should not happen"); + } + gdcmWarningMacro( "Illegal: Explicit SQ found in a file with " + "TransferSyntax=Implicit for tag: " << TagField ); + } + catch( Exception & ) + { + // MR_ELSCINT1_00e1_1042_SQ_feff_00e0_Item.dcm + std::streampos current = is.tellg(); + std::streamoff diff = start - current; + is.seekg( diff, std::ios::cur ); + assert( diff == -14 ); + ValueIO::Read(is,*ValueField,readvalues); + } + catch( std::exception & ) + { + ValueLengthField = ValueField->GetLength(); + } + return is; + } + else if ( item == itemPMSStart2 && false ) + { + gdcmWarningMacro( "Illegal: SQ start with " << itemPMSStart2 + << " instead of " << itemStart << " for tag: " << TagField ); + ValueField = new SequenceOfItems; + ValueField->SetLength(ValueLengthField); // perform realloc + if( !ValueIO::Read(is,*ValueField,readvalues) ) + { + assert(0 && "Should not happen"); + } + return is; + } +#endif + else + { + ValueField = new ByteValue; + } + } + } +#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + // THE WORST BUG EVER. From GE Workstation + if( ValueLengthField == 13 ) + { + // Historically gdcm did not enforce proper length + // thus Theralys started writing illegal DICOM images: + const Tag theralys1(0x0008,0x0070); + const Tag theralys2(0x0008,0x0080); + if( TagField != theralys1 + && TagField != theralys2 ) + { + gdcmWarningMacro( "GE,13: Replacing VL=0x000d with VL=0x000a, for Tag=" + << TagField << " in order to read a buggy DICOM file." ); + ValueLengthField = 10; + } + } +#endif +#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + if( ValueLengthField == 0x31f031c && TagField == Tag(0x031e,0x0324) ) + { + // TestImages/elbow.pap + gdcmWarningMacro( "Replacing a VL. To be able to read a supposively " + "broken Payrus file." ); + ValueLengthField = 202; // 0xca + } +#endif + // We have the length we should be able to read the value + this->SetValueFieldLength( ValueLengthField, readvalues ); + bool failed; +#ifdef GDCM_WORDS_BIGENDIAN + VR vrfield = GetVRFromTag( TagField ); + if( vrfield & VR::VRASCII || vrfield == VR::INVALID ) + { + //assert( VRField.GetSize() == 1 ); + failed = !ValueIO::Read(is,*ValueField,readvalues); + } + else + { + assert( vrfield & VR::VRBINARY ); + unsigned int vrsize = vrfield.GetSize(); + assert( vrsize == 1 || vrsize == 2 || vrsize == 4 || vrsize == 8 ); + if(vrfield==VR::AT) vrsize = 2; + switch(vrsize) + { + case 1: + failed = !ValueIO::Read(is,*ValueField,readvalues); + break; + case 2: + failed = !ValueIO::Read(is,*ValueField,readvalues); + break; + case 4: + failed = !ValueIO::Read(is,*ValueField,readvalues); + break; + case 8: + failed = !ValueIO::Read(is,*ValueField,readvalues); + break; + default: + failed = true; + assert(0); + } + } +#else + failed = !ValueIO::Read(is,*ValueField,readvalues); +#endif + if( failed ) + { + // Special handling for PixelData tag: +#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + if( TagField == Tag(0x7fe0,0x0010) ) + { + gdcmWarningMacro( "Incomplete Pixel Data found, use file at own risk" ); + is.clear(); + } + else +#endif /* GDCM_SUPPORT_BROKEN_IMPLEMENTATION */ + { + throw Exception("Should not happen (imp)"); + } + return is; + } + +#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + // dcmtk 3.5.4 is resilient to broken explicit SQ length and will properly + // recompute it as long as each of the Item lengths are correct + VL dummy = ValueField->GetLength(); + if( ValueLengthField != dummy ) + { + gdcmWarningMacro( "ValueLengthField was bogus" ); assert(0); + ValueLengthField = dummy; + } +#else + assert( ValueLengthField == ValueField->GetLength() ); + assert( VRField == VR::INVALID ); +#endif + + return is; +} + +//----------------------------------------------------------------------------- +template +std::istream &ImplicitDataElement::ReadWithLength(std::istream &is, VL & length, bool readvalues) +{ + ReadPreValue(is); + return ReadValueWithLength(is, length, readvalues); +} + +template +std::istream &ImplicitDataElement::ReadValueWithLength(std::istream& is, VL & length, bool readvalues) +{ + if( is.eof() ) return is; + const Tag itemStartItem(0xfffe,0xe000); + if( TagField == itemStartItem ) return is; + + /* + * technically this should not be needed, but what if an implementor, forgot + * to set VL = 0, then we should make sure to exit early + */ + const Tag itemDelItem(0xfffe,0xe00d); + if( TagField == itemDelItem ) + { + if( ValueLengthField != 0 ) + { + gdcmWarningMacro( "VL should be set to 0" ); + } + ValueField = 0; + return is; + } + //std::cerr << "imp cur tag=" << TagField << " VL=" << ValueLengthField << std::endl; + if( ValueLengthField > length && !ValueLengthField.IsUndefined() ) + { + gdcmWarningMacro( "Cannot read more length than what is remaining in the file" ); + throw Exception( "Impossible (more)" ); + } + if( ValueLengthField == 0 ) + { + // Simple fast path + ValueField = 0; + return is; + } + else if( ValueLengthField.IsUndefined() ) + { + //assert( de.GetVR() == VR::SQ ); + // FIXME what if I am reading the pixel data... + //assert( TagField != Tag(0x7fe0,0x0010) ); + if( TagField != Tag(0x7fe0,0x0010) ) + { + ValueField = new SequenceOfItems; + } + else + { + gdcmErrorMacro( "Undefined value length is impossible in non-encapsulated Transfer Syntax. Proceeding with caution" ); + ValueField = new SequenceOfFragments; + } + //VRField = VR::SQ; + } + else + { + if( true /*ValueLengthField < 8*/ ) + { + ValueField = new ByteValue; + } + else + { + // In the following we read 4 more bytes in the Value field + // to find out if this is a SQ or not + // there is still work to do to handle the PMS featured SQ + // where item Start is in fact 0xfeff, 0x00e0 ... sigh + const Tag itemStart(0xfffe, 0xe000); +#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + const Tag itemPMSStart(0xfeff, 0x00e0); + const Tag itemPMSStart2(0x3f3f, 0x3f00); +#endif + Tag item; + // TODO FIXME + // This is pretty dumb to actually read to later on seekg back, why not `peek` directly ? + item.Read(is); + // Maybe this code can later be rewritten as I believe that seek back + // is very slow... + is.seekg(-4, std::ios::cur ); + if( item == itemStart ) + { + assert( TagField != Tag(0x7fe0,0x0010) ); + ValueField = new SequenceOfItems; + } +#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + else if ( item == itemPMSStart ) + { + // MR_Philips_Intera_No_PrivateSequenceImplicitVR.dcm + gdcmWarningMacro( "Illegal Tag for Item starter: " << TagField << " should be: " << itemStart ); + // TODO: We READ Explicit ok...but we store Implicit ! + // Indeed when copying the VR will be saved... pretty cool eh ? + ValueField = new SequenceOfItems; + ValueField->SetLength(ValueLengthField); // perform realloc + std::streampos start = is.tellg(); + try + { + if( !ValueIO::Read(is,*ValueField,readvalues) ) + { + assert(0 && "Should not happen"); + } + gdcmWarningMacro( "Illegal: Explicit SQ found in a file with " + "TransferSyntax=Implicit for tag: " << TagField ); + } + catch( Exception &) + { + // MR_ELSCINT1_00e1_1042_SQ_feff_00e0_Item.dcm + std::streampos current = is.tellg(); + std::streamoff diff = start - current;//could be bad, if the specific implementation does not support negative streamoff values. + is.seekg( diff, std::ios::cur ); + assert( diff == -14 ); + ValueIO::Read(is,*ValueField,readvalues); + } + catch( std::exception & ) + { + ValueLengthField = ValueField->GetLength(); + } + return is; + } + else if ( item == itemPMSStart2 ) + { + assert( 0 ); // FIXME: Sync Read/ReadWithLength + gdcmWarningMacro( "Illegal: SQ start with " << itemPMSStart2 + << " instead of " << itemStart << " for tag: " << TagField ); + ValueField = new SequenceOfItems; + ValueField->SetLength(ValueLengthField); // perform realloc + if( !ValueIO::Read(is,*ValueField,readvalues) ) + { + assert(0 && "Should not happen"); + } + return is; + } +#endif + else + { + ValueField = new ByteValue; + } + } + } +#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + // THE WORST BUG EVER. From GE Workstation + if( ValueLengthField == 13 ) + { + // Historically gdcm did not enforce proper length + // thus Theralys started writing illegal DICOM images: + const Tag theralys1(0x0008,0x0070); + const Tag theralys2(0x0008,0x0080); + if( TagField != theralys1 + && TagField != theralys2 ) + { + gdcmWarningMacro( "GE,13: Replacing VL=0x000d with VL=0x000a, for Tag=" + << TagField << " in order to read a buggy DICOM file." ); + ValueLengthField = 10; + } + } +#endif +#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + if( ValueLengthField == 0x31f031c && TagField == Tag(0x031e,0x0324) ) + { + // TestImages/elbow.pap + gdcmWarningMacro( "Replacing a VL. To be able to read a supposively" + "broken Payrus file." ); + ValueLengthField = 202; // 0xca + } +#endif + // We have the length we should be able to read the value + ValueField->SetLength(ValueLengthField); // perform realloc + bool failed; +#ifdef GDCM_WORDS_BIGENDIAN + VR vrfield = GetVRFromTag( TagField ); + if( vrfield & VR::VRASCII || vrfield == VR::INVALID ) + { + //assert( VRField.GetSize() == 1 ); + failed = !ValueIO::Read(is,*ValueField,readvalues); + } + else + { + assert( vrfield & VR::VRBINARY ); + unsigned int vrsize = vrfield.GetSize(); + assert( vrsize == 1 || vrsize == 2 || vrsize == 4 || vrsize == 8 ); + if(vrfield==VR::AT) vrsize = 2; + switch(vrsize) + { + case 1: + failed = !ValueIO::Read(is,*ValueField,readvalues); + break; + case 2: + failed = !ValueIO::Read(is,*ValueField,readvalues); + break; + case 4: + failed = !ValueIO::Read(is,*ValueField,readvalues); + break; + case 8: + failed = !ValueIO::Read(is,*ValueField,readvalues); + break; + default: + failed = true; + assert(0); + } + } +#else + failed = !ValueIO::Read(is,*ValueField,readvalues); +#endif + if( failed ) + //if( !ValueIO::Read(is,*ValueField) ) + { + // Special handling for PixelData tag: +#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + if( TagField == Tag(0x7fe0,0x0010) ) + { + gdcmWarningMacro( "Incomplete Pixel Data found, use file at own risk" ); + is.clear(); + } + else +#endif /* GDCM_SUPPORT_BROKEN_IMPLEMENTATION */ + { + throw Exception("Should not happen (imp)"); + } + return is; + } + +#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + // dcmtk 3.5.4 is resilient to broken explicit SQ length and will properly recompute it + // as long as each of the Item lengths are correct + VL dummy = ValueField->GetLength(); + if( ValueLengthField != dummy ) + { + gdcmWarningMacro( "ValueLengthField was bogus" ); + ValueLengthField = dummy; + } +#else + assert( ValueLengthField == ValueField->GetLength() ); + assert( VRField == VR::INVALID ); +#endif + + return is; +} + +//----------------------------------------------------------------------------- +template +const std::ostream &ImplicitDataElement::Write(std::ostream &os) const +{ + // See PS 3.5, 7.1.3 Data Element Structure With Implicit VR + // Write Tag + if( !TagField.Write(os) ) + { + assert(0 && "Should not happen"); + return os; + } + // Write Value Length + const SequenceOfItems *sqi = dynamic_cast(&GetValue()); //GetSequenceOfItems(); + if( sqi && !ValueLengthField.IsUndefined() ) + { + // Hum, we might have to recompute the length: + // See TestWriter2, where an explicit SQ is converted to implicit SQ + VL len = sqi->template ComputeLength(); + //assert( len == ValueLengthField ); + if( !len.Write(os) ) + { + assert(0 && "Should not happen"); + return os; + } + } + else // It should be safe to simply use the ValueLengthField as stored: + { + // Do not allow writing file such as: dcm4che_UndefinedValueLengthInImplicitTS.dcm + if( TagField == Tag(0x7fe0,0x0010) && ValueLengthField.IsUndefined() ) throw Exception( "VL u/f Impossible" ); + if( !ValueLengthField.Write(os) ) + { + assert(0 && "Should not happen"); + return os; + } + } + // Write Value + if( ValueLengthField ) + { + assert( ValueField ); + gdcmAssertAlwaysMacro( ValueLengthField == ValueField->GetLength() ); + assert( TagField != Tag(0xfffe, 0xe00d) + && TagField != Tag(0xfffe, 0xe0dd) ); + if( !ValueIO::Write(os,*ValueField) ) + { + assert(0 && "Should not happen"); + return os; + } + } + return os; +} + + +} // end namespace gdcm + + +#endif // GDCMIMPLICITDATAELEMENT_TXX diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmItem.cxx b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmItem.cxx new file mode 100644 index 0000000..522832f --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmItem.cxx @@ -0,0 +1,22 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmItem.h" + +#include + +namespace gdcm +{ + + +} // end namespace gdcm diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmItem.h b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmItem.h new file mode 100644 index 0000000..e4b8590 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmItem.h @@ -0,0 +1,329 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#ifndef GDCMITEM_H +#define GDCMITEM_H + +#include "gdcmDataElement.h" +#include "gdcmDataSet.h" +#include "gdcmParseException.h" +#include "gdcmSwapper.h" + +#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION +#include "gdcmByteSwapFilter.h" +#endif + +namespace gdcm +{ + +class DataSet; +/** + * \brief Class to represent an Item + * A component of the value of a Data Element that is of Value Representation + * Sequence of Items. + * An Item contains a Data Set . + * See PS 3.5 7.5.1 Item Encoding Rules + * Each Item of a Data Element of VR SQ shall be encoded as a DICOM Standart + * Data Element with a specific Data Element Tag of Value (FFFE,E000). The Item + * Tag is followed by a 4 byte Item Length field encoded in one of the + * following two ways Explicit/ Implicit + * \note + * ITEM: A component of the Value of a Data Element that is of Value + * Representation Sequence of Items. An Item contains a Data Set. + */ +class GDCM_EXPORT Item : public DataElement +{ +public: + Item() : DataElement(Tag(0xfffe, 0xe000), 0xFFFFFFFF), NestedDataSet() {} + friend std::ostream& operator<< (std::ostream &os, const Item &val); + + void Clear() { + this->DataElement::Clear(); + NestedDataSet.Clear(); + } + + template + VL GetLength() const; + + void InsertDataElement(const DataElement & de) { + NestedDataSet.Insert(de); + // Update the length + if( !IsUndefinedLength() ) + { + assert( 0 && "InsertDataElement" ); + //ValueLengthField += de.GetLength(); + } + } + const DataElement& GetDataElement(const Tag& t) const + { + return NestedDataSet.GetDataElement(t); + } + + // Completely defines it with the nested dataset + // destroy anything present + void SetNestedDataSet(const DataSet& nested) + { + NestedDataSet = nested; + } + // Return a const ref to the Nested Data Set + const DataSet &GetNestedDataSet() const + { + return NestedDataSet; + } + DataSet &GetNestedDataSet() + { + return NestedDataSet; + } + + //Value const & GetValue() const { return *NestedDataSet; } + + Item(Item const &val):DataElement(val) + { + NestedDataSet = val.NestedDataSet; + } + + template + std::istream &Read(std::istream &is) { + // Superclass + { + DataSet &nested = NestedDataSet; + nested.Clear(); + assert( nested.IsEmpty() ); + } + if( !TagField.Read(is) ) + { + throw Exception("Should not happen (item)"); + return is; + } +#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + // MR_Philips_Intera_SwitchIndianess_noLgtSQItem_in_trueLgtSeq.dcm + if( TagField == Tag(0xfeff, 0x00e0) + || TagField == Tag(0xfeff, 0xdde0) ) + { + gdcmWarningMacro( "ByteSwaping Private SQ: " << TagField ); + // Invert previously read TagField since wrong endianess: + TagField = Tag( SwapperDoOp::Swap( TagField.GetGroup() ), SwapperDoOp::Swap( TagField.GetElement() ) ); + assert ( TagField == Tag(0xfffe, 0xe000) + || TagField == Tag(0xfffe, 0xe0dd) ); + + if( !ValueLengthField.Read(is) ) + { + assert(0 && "Should not happen"); + return is; + } + // Self + // Some file written by GDCM 1.0 we writting 0xFFFFFFFF instead of 0x0 + if( TagField == Tag(0xfffe,0xe0dd) ) + { + if( ValueLengthField ) + { + gdcmErrorMacro( "ValueLengthField is not 0" ); + } + } + //else if( ValueLengthField == 0 ) + // { + // //assert( TagField == Tag( 0xfffe, 0xe0dd) ); + // if( TagField != Tag( 0xfffe, 0xe0dd) ) + // { + // gdcmErrorMacro( "SQ: " << TagField << " has a length of 0" ); + // } + // } + else if( ValueLengthField.IsUndefined() ) + { + DataSet &nested = NestedDataSet; + nested.Clear(); + assert( nested.IsEmpty() ); + std::streampos start = is.tellg(); + try + { + nested.template ReadNested(is); + ByteSwapFilter bsf(nested); + bsf.ByteSwap(); + } + catch(ParseException &pe) + { + (void)pe; + // MR_Philips_Intera_PrivateSequenceExplicitVR_in_SQ_2001_e05f_item_wrong_lgt_use_NOSHADOWSEQ.dcm + // You have to byteswap the length but not the tag...sigh + gdcmWarningMacro( "Attempt to read nested Item without byteswapping the Value Length." ); + start -= is.tellg(); + assert( start < 0 ); + is.seekg( start, std::ios::cur ); + nested.Clear(); + nested.template ReadNested(is); + ByteSwapFilter bsf(nested); + // Tag are read in big endian, need to byteswap them back... + bsf.SetByteSwapTag(true); + bsf.ByteSwap(); + } + catch(Exception &e) + { + // MR_Philips_Intera_No_PrivateSequenceImplicitVR.dcm + throw e; + } + catch(...) + { + assert(0); + } + } + else /* if( ValueLengthField.IsUndefined() ) */ + { + DataSet &nested = NestedDataSet; + nested.Clear(); + assert( nested.IsEmpty() ); + nested.template ReadWithLength(is, ValueLengthField); + ByteSwapFilter bsf(nested); + bsf.ByteSwap(); + } + return is; + } + // http://groups.google.com/group/comp.protocols.dicom/msg/c07efcf5e759fc83 + // Bug_Philips_ItemTag_3F3F.dcm + if( TagField == Tag(0x3f3f, 0x3f00) ) + { + //TagField = Tag(0xfffe, 0xe000); + } +#endif + if( TagField != Tag(0xfffe, 0xe000) && TagField != Tag(0xfffe, 0xe0dd) ) + { + gdcmDebugMacro( "Invalid Item, found tag: " << TagField); + throw Exception( "Not a valid Item" ); + } + assert( TagField == Tag(0xfffe, 0xe000) || TagField == Tag(0xfffe, 0xe0dd) ); + + if( !ValueLengthField.Read(is) ) + { + assert(0 && "Should not happen"); + return is; + } + // Self + if( TagField == Tag(0xfffe,0xe0dd) ) + { + // Some file written by GDCM 1.0 were written with 0xFFFFFFFF instead of 0x0 + if( ValueLengthField ) + { + gdcmDebugMacro( "ValueLengthField is not 0 but " << ValueLengthField ); + } + } + else if( ValueLengthField.IsUndefined() ) + { + DataSet &nested = NestedDataSet; + nested.Clear(); + assert( nested.IsEmpty() ); + nested.template ReadNested(is); + } + else /* if( ValueLengthField.IsUndefined() ) */ + { + assert( !ValueLengthField.IsUndefined() ); + DataSet &nested = NestedDataSet; + nested.Clear(); + assert( nested.IsEmpty() ); + nested.template ReadWithLength(is, ValueLengthField); + } + + return is; + } + + template + const std::ostream &Write(std::ostream &os) const { +#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + if( TagField == Tag(0x3f3f,0x3f00) && false ) + { + Tag t(0xfffe, 0xe000); + t.Write(os); + } + else +#endif + { + assert ( TagField == Tag(0xfffe, 0xe000) + || TagField == Tag(0xfffe, 0xe0dd) ); + // Not sure how this happen + if( TagField == Tag(0xfffe, 0xe0dd) ) + { + gdcmWarningMacro( "SegDelItem found in defined length Sequence" ); + assert( ValueLengthField == 0 ); + assert( NestedDataSet.Size() == 0 ); + } + if( !TagField.Write(os) ) + { + assert(0 && "Should not happen"); + return os; + } + } + if( ValueLengthField.IsUndefined() ) + { + if( !ValueLengthField.Write(os) ) + { + assert(0 && "Should not happen"); + return os; + } + } + else + { + const VL dummy = NestedDataSet.GetLength(); + assert( dummy % 2 == 0 ); + //assert( ValueLengthField == dummy ); + if( !dummy.Write(os) ) + { + assert(0 && "Should not happen"); + return os; + } + } + // Self + NestedDataSet.Write(os); + if( ValueLengthField.IsUndefined() ) + { + const Tag itemDelItem(0xfffe,0xe00d); + itemDelItem.Write(os); + VL zero = 0; + zero.Write(os); + } + + return os; + } + +/* +There are three special SQ related Data Elements that are not ruled by the VR encoding rules conveyed +by the Transfer Syntax. They shall be encoded as Implicit VR. These special Data Elements are Item +(FFFE,E000), Item Delimitation Item (FFFE,E00D), and Sequence Delimitation Item (FFFE,E0DD). +However, the Data Set within the Value Field of the Data Element Item (FFFE,E000) shall be encoded +according to the rules conveyed by the Transfer Syntax. +*/ + bool FindDataElement(const Tag &t) const { + return NestedDataSet.FindDataElement( t ); + } + +private: + /* NESTED DATA SET a Data Set contained within a Data Element of an other Data Set. + * May be nested recursively. + * Only Data Elements with VR = SQ may, themselves, contain Data Sets + */ + DataSet NestedDataSet; +}; +//----------------------------------------------------------------------------- +inline std::ostream& operator<<(std::ostream& os, const Item &val) +{ + os << val.TagField; + os << "\t" << val.ValueLengthField << "\n"; + val.NestedDataSet.Print( os, "\t" ); + + return os; +} + + +} // end namespace gdcm + +#include "gdcmItem.txx" + +#endif //GDCMITEM_H diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmItem.txx b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmItem.txx new file mode 100644 index 0000000..cf9c41f --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmItem.txx @@ -0,0 +1,57 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMITEM_TXX +#define GDCMITEM_TXX + +#include "gdcmItem.h" + +namespace gdcm +{ + +template +VL Item::GetLength() const +{ + if( ValueLengthField.IsUndefined() ) + { + assert( !NestedDataSet.GetLength().IsUndefined() ); + // Item Start 4 + // Item Length 4 + // DataSet ? + // Item End Delimitation 4 + // Item End Length 4 + assert( NestedDataSet.GetLength() % 2 == 0 ); + return TagField.GetLength() /* 4 */ + ValueLengthField.GetLength() /* 4 */ + + NestedDataSet.GetLength() + 4 + 4; + } + else + { + // Item Start 4 + // Item Length 4 + // DataSet ? + const VL nestedlen = NestedDataSet.GetLength(); + // The following line is commented out, since we could be in the case where + // we are computing the actual length of an implicit dataset, from an + // initially read explicit dataset in which case the two length cannot + // related to each other + //gdcmAssertAlwaysMacro( ValueLengthField == nestedlen ); + assert( nestedlen % 2 == 0 ); + return TagField.GetLength() /* 4 */ + ValueLengthField.GetLength() /* 4 */ + //+ ValueLengthField; + + nestedlen; + } +} + +} // end namespace gdcm + +#endif // GDCMITEM_TXX diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmLO.h b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmLO.h new file mode 100644 index 0000000..adb4834 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmLO.h @@ -0,0 +1,59 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMLO_H +#define GDCMLO_H + +#include "gdcmString.h" + +namespace gdcm +{ + +/** + * \brief LO + * + * \note TODO + */ +class /*GDCM_EXPORT*/ LO : public String<'\\',64> /* PLEASE do not export me */ +{ +public: + // typedef are not inherited: + typedef String<'\\',64> Superclass; + typedef Superclass::value_type value_type; + typedef Superclass::pointer pointer; + typedef Superclass::reference reference; + typedef Superclass::const_reference const_reference; + typedef Superclass::size_type size_type; + typedef Superclass::difference_type difference_type; + typedef Superclass::iterator iterator; + typedef Superclass::const_iterator const_iterator; + typedef Superclass::reverse_iterator reverse_iterator; + typedef Superclass::const_reverse_iterator const_reverse_iterator; + + // LO constructors. + LO(): Superclass() {} + LO(const value_type* s): Superclass(s) {} + LO(const value_type* s, size_type n): Superclass(s, n) {} + LO(const Superclass& s, size_type pos=0, size_type n=npos): + Superclass(s, pos, n) {} + + bool IsValid() const { + if( !Superclass::IsValid() ) return false; + // Implementation specific: + return true; + } +}; + +} // end namespace gdcm + +#endif //GDCMLO_H diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmMediaStorage.cxx b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmMediaStorage.cxx new file mode 100644 index 0000000..bd5259a --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmMediaStorage.cxx @@ -0,0 +1,604 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmMediaStorage.h" +#include "gdcmTag.h" +#include "gdcmByteValue.h" +#include "gdcmDataSet.h" +#include "gdcmFileMetaInformation.h" +#include "gdcmFile.h" +#include "gdcmSequenceOfItems.h" +#include "gdcmCodeString.h" + +namespace gdcm +{ + +static const char *MSStrings[] = { + "1.2.840.10008.1.3.10", + "1.2.840.10008.5.1.4.1.1.1", + "1.2.840.10008.5.1.4.1.1.1.1", + "1.2.840.10008.5.1.4.1.1.1.1.1", + "1.2.840.10008.5.1.4.1.1.1.2", + "1.2.840.10008.5.1.4.1.1.1.2.1", + "1.2.840.10008.5.1.4.1.1.1.3", + "1.2.840.10008.5.1.4.1.1.1.3.1", + "1.2.840.10008.5.1.4.1.1.2", + "1.2.840.10008.5.1.4.1.1.2.1", + "1.2.840.10008.5.1.4.1.1.6", + "1.2.840.10008.5.1.4.1.1.6.1", // Ultrasound Image Storage + "1.2.840.10008.5.1.4.1.1.3", + "1.2.840.10008.5.1.4.1.1.3.1", + "1.2.840.10008.5.1.4.1.1.4", + "1.2.840.10008.5.1.4.1.1.4.1", + "1.2.840.10008.5.1.4.1.1.4.2", + "1.2.840.10008.5.1.4.1.1.5", // NuclearMedicineImageStorageRetired + "1.2.840.10008.5.1.4.1.1.7", + "1.2.840.10008.5.1.4.1.1.7.1", + "1.2.840.10008.5.1.4.1.1.7.2", + "1.2.840.10008.5.1.4.1.1.7.3", + "1.2.840.10008.5.1.4.1.1.7.4", + "1.2.840.10008.5.1.4.1.1.8", + "1.2.840.10008.5.1.4.1.1.9", + "1.2.840.10008.5.1.4.1.1.9.1.1", + "1.2.840.10008.5.1.4.1.1.9.1.2", + "1.2.840.10008.5.1.4.1.1.9.1.3", + "1.2.840.10008.5.1.4.1.1.9.2.1", + "1.2.840.10008.5.1.4.1.1.9.3.1", + "1.2.840.10008.5.1.4.1.1.9.4.1", + "1.2.840.10008.5.1.4.1.1.10", + "1.2.840.10008.5.1.4.1.1.11", + "1.2.840.10008.5.1.4.1.1.11.1", + "1.2.840.10008.5.1.4.1.1.12.1", + "1.2.840.10008.5.1.4.1.1.12.2", + "1.2.840.10008.5.1.4.1.1.12.3", + "1.2.840.10008.5.1.4.1.1.20", + "1.2.840.10008.5.1.4.1.1.66", + "1.2.840.10008.5.1.4.1.1.66.1", + "1.2.840.10008.5.1.4.1.1.66.2", + + // See PETAt001_PT001.dcm + "1.2.840.10008.5.1.4.1.1.128", + // SYNGORTImage.dcm + "1.2.840.10008.5.1.4.1.1.481.1", + // eclipse_dose.dcm + "1.2.840.10008.5.1.4.1.1.481.2", + // exRT_Structure_Set_Storage.dcm + "1.2.840.10008.5.1.4.1.1.481.3", + // eclipse_plan.dcm + "1.2.840.10008.5.1.4.1.1.481.5", + // exCSA_Non-Image_Storage.dcm + "1.3.12.2.1107.5.9.1", + // 3DDCM011.dcm + "1.2.840.113543.6.6.1.3.10002", + // EnhancedSR + "1.2.840.10008.5.1.4.1.1.88.22", + // BasicTextSR: + "1.2.840.10008.5.1.4.1.1.88.11", + // HardcopyGrayscaleImageStorage + "1.2.840.10008.5.1.1.29", + // ComprehensiveSR + "1.2.840.10008.5.1.4.1.1.88.33", + // DetachedStudyManagementSOPClass, + "1.2.840.10008.3.1.2.3.1", + // EncapsulatedPDFStorage + "1.2.840.10008.5.1.4.1.1.104.1", + // EncapsulatedCDAStorage + "1.2.840.10008.5.1.4.1.1.104.2", + // StudyComponentManagementSOPClass + "1.2.840.10008.3.1.2.3.2", + // DetachedVisitManagementSOPClass + "1.2.840.10008.3.1.2.2.1", + // DetachedPatientManagementSOPClass + "1.2.840.10008.3.1.2.1.1", + // VideoEndoscopicImageStorage + "1.2.840.10008.5.1.4.1.1.77.1.1.1", + // GeneralElectricMagneticResonanceImageStorage + "1.2.840.113619.4.2", + // GEPrivate3DModelStorage + "1.2.840.113619.4.26", + // Toshiba Private Data Storage + "1.2.392.200036.9116.7.8.1.1.1", + // MammographyCADSR, + "1.2.840.10008.5.1.4.1.1.88.50", + // KeyObjectSelectionDocument + "1.2.840.10008.5.1.4.1.1.88.59", + // HangingProtocolStorage + "1.2.840.10008.5.1.4.38.1", + // Modality Performed Procedure Step SOP Class + "1.2.840.10008.3.1.2.3.3", + // Philips Private MR Synthetic Image Storage + "1.3.46.670589.5.0.10", + "1.2.840.10008.5.1.4.1.1.77.1.4", // "VL Photographic Image Storage", + "1.2.840.10008.5.1.4.1.1.66.4", // Segmentation Storage + "1.2.840.10008.5.1.4.1.1.481.8", // RT Ion Plan Storage + "1.2.840.10008.5.1.4.1.1.13.1.1", // XRay3DAngiographicImageStorage, + "1.2.840.10008.5.1.4.1.1.12.1.1", // Enhanced XA Image Storage + "1.2.840.10008.5.1.4.1.1.481.9", // RTIonBeamsTreatmentRecordStorage + "1.2.840.10008.5.1.4.1.1.66.5", // Surface Segmentation Storage + "1.2.840.10008.5.1.4.1.1.77.1.6", // VLWholeSlideMicroscopyImageStorage + "1.2.840.10008.5.1.4.1.1.481.7", // RTTreatmentSummaryRecordStorage + "1.2.840.10008.5.1.4.1.1.6.2", // EnhancedUSVolumeStorage + "1.2.840.10008.5.1.4.1.1.88.67", // XRayRadiationDoseSR + "1.2.840.10008.5.1.4.1.1.77.1.1", // VLEndoscopicImageStorage + "1.2.840.10008.5.1.4.1.1.13.1.3", // BreastTomosynthesisImageStorage + "1.2.392.200036.9125.1.1.2", // FujiPrivateCRImageStorage + "1.2.840.10008.5.1.4.1.1.77.1.5.1", // OphthalmicPhotography8BitImageStorage + "1.2.840.10008.5.1.4.1.1.77.1.5.4", // OphthalmicTomographyImageStorage + "1.2.840.10008.5.1.4.1.1.77.1.2", // VL Microscopic Image Storage + 0 +}; + +MediaStorage::MSType MediaStorage::GetMSType(const char *str) +{ + if(!str) return MS_END; + + for(unsigned int i = 0; MSStrings[i] != 0; ++i) + { + if( strcmp(str, MSStrings[i]) == 0 ) + { + return (MSType)i; + } + } + // Ouch ! We did not find anything, that's pretty bad, let's hope that + // the toolkit which wrote the image is buggy and tolerate space padded binary + // string + CodeString codestring = str; + std::string cs = codestring.GetAsString(); + for(unsigned int i = 0; MSStrings[i] != 0; ++i) + { + if( strcmp(cs.c_str(), MSStrings[i]) == 0 ) + { + return (MSType)i; + } + } + + //assert(0); + return MS_END; +} + +const char* MediaStorage::GetMSString(MSType ms) +{ + assert( ms <= MS_END ); + return MSStrings[(int)ms]; +} + +const char* MediaStorage::GetString() const +{ + return GetMSString(MSField); +} + +// FIXME +// Currently the implementation is bogus it only define the TS which +// are associated with an image so indeed the implementation of IsImage +// is only the verification of TSType is != TS_END +bool MediaStorage::IsImage(MSType ms) +{ + if ( ms == MS_END // most frequent first + // lexicographical order then... + || ms == BasicVoiceAudioWaveformStorage + || ms == CSANonImageStorage + || ms == HemodynamicWaveformStorage + || ms == MediaStorageDirectoryStorage + || ms == RTPlanStorage + || ms == GrayscaleSoftcopyPresentationStateStorageSOPClass + || ms == CardiacElectrophysiologyWaveformStorage + || ms == ToshibaPrivateDataStorage // not an image I think... + || ms == EnhancedSR + || ms == BasicTextSR + || ms == ComprehensiveSR + || ms == StudyComponentManagementSOPClass + || ms == DetachedVisitManagementSOPClass + || ms == DetachedStudyManagementSOPClass + || ms == EncapsulatedPDFStorage + || ms == EncapsulatedCDAStorage + || ms == XRayRadiationDoseSR + || ms == KeyObjectSelectionDocument + || ms == HangingProtocolStorage + || ms == MRSpectroscopyStorage + || ms == ModalityPerformedProcedureStepSOPClass + || ms == RawDataStorage + || ms == RTIonPlanStorage + || ms == LeadECGWaveformStorage + || ms == GeneralECGWaveformStorage + || ms == RTIonBeamsTreatmentRecordStorage + || ms == RTStructureSetStorage + || ms == MammographyCADSR + || ms == SurfaceSegmentationStorage ) + { + return false; + } + return true; +} + +struct MSModalityType +{ + const char *Modality; + const unsigned char Dimension; + const bool Retired; +}; + +static const MSModalityType MSModalityTypes[] = { + {"00", 0, 0},//MediaStorageDirectoryStorage, + {"CR", 2, 0},//ComputedRadiographyImageStorage, + {"DX", 2, 0},//DigitalXRayImageStorageForPresentation, + {"DX", 2, 0},//DigitalXRayImageStorageForProcessing, + {" ", 2, 0},//DigitalMammographyImageStorageForPresentation, + {"MG", 2, 0},//DigitalMammographyImageStorageForProcessing, + {" ", 2, 0},//DigitalIntraoralXrayImageStorageForPresentation, + {" ", 2, 0},//DigitalIntraoralXRayImageStorageForProcessing, + {"CT", 2, 0},//CTImageStorage, + {"CT", 3, 0},//EnhancedCTImageStorage, + {"US", 2, 1},//UltrasoundImageStorageRetired, + {"US", 2, 0},//UltrasoundImageStorage, + {"US", 3, 1},//UltrasoundMultiFrameImageStorageRetired, + {"US", 3, 0},//UltrasoundMultiFrameImageStorage, + {"MR", 2, 0},//MRImageStorage, + {"MR", 3, 0},//EnhancedMRImageStorage, + {"MR", 2, 0},//MRSpectroscopyStorage, + {" ", 2, 1},//NuclearMedicineImageStorageRetired, + {"OT", 2, 0},//SecondaryCaptureImageStorage, + {"OT", 3, 0},//MultiframeSingleBitSecondaryCaptureImageStorage, + {"OT", 3, 0},//MultiframeGrayscaleByteSecondaryCaptureImageStorage, + {"OT", 3, 0},//MultiframeGrayscaleWordSecondaryCaptureImageStorage, + {"OT", 3, 0},//MultiframeTrueColorSecondaryCaptureImageStorage, + {" ", 2, 0},//StandaloneOverlayStorage, + {" ", 2, 0},//StandaloneCurveStorage, + {" ", 2, 0},//LeadECGWaveformStorage, // 12- + {" ", 2, 0},//GeneralECGWaveformStorage, + {" ", 2, 0},//AmbulatoryECGWaveformStorage, + {" ", 2, 0},//HemodynamicWaveformStorage, + {" ", 2, 0},//CardiacElectrophysiologyWaveformStorage, + {" ", 2, 0},//BasicVoiceAudioWaveformStorage, + {" ", 2, 0},//StandaloneModalityLUTStorage, + {" ", 2, 0},//StandaloneVOILUTStorage, + {" ", 2, 0},//GrayscaleSoftcopyPresentationStateStorageSOPClass, + {"XA", 3, 0},//XRayAngiographicImageStorage, + {"RF", 2, 0},//XRayRadiofluoroscopingImageStorage, + {" ", 2, 0},//XRayAngiographicBiPlaneImageStorageRetired, + {"NM", 3, 0},//NuclearMedicineImageStorage, + {" ", 2, 0},//RawDataStorage, + {" ", 2, 0},//SpacialRegistrationStorage, + {" ", 2, 0},//SpacialFiducialsStorage, + {"PT", 2, 0},//PETImageStorage, + {"RTIMAGE ", 2, 0},//RTImageStorage, // FIXME + {"RTDOSE", 3, 0},//RTDoseStorage, + {" ", 2, 0},//RTStructureSetStorage, + {" ", 2, 0},//RTPlanStorage, + {" ", 2, 0},//CSANonImageStorage, + {" ", 2, 0},//Philips3D, + {" ", 2, 0},//EnhancedSR + {" ", 2, 0},//BasicTextSR + {" ", 2, 0},//HardcopyGrayscaleImageStorage + {" ", 2, 0},//ComprehensiveSR + {" ", 2, 0},//DetachedStudyManagementSOPClass + {" ", 2, 0},//EncapsulatedPDFStorage + {" ", 2, 0},//EncapsulatedCDAStorage + {" ", 2, 0},//StudyComponentManagementSOPClass + {" ", 2, 0},//DetachedVisitManagementSOPClass + {" ", 2, 0},//DetachedPatientManagementSOPClass + {"ES", 3, 0},//VideoEndoscopicImageStorage + {" ", 2, 0},//GeneralElectricMagneticResonanceImageStorage + {" ", 2, 0},//GEPrivate3DModelStorage + {" ", 2, 0},//ToshibaPrivateDataStorage + {" ", 2, 0},//MammographyCADSR + {" ", 2, 0},//KeyObjectSelectionDocument + {" ", 2, 0},//HangingProtocolStorage + {" ", 2, 0},//ModalityPerformedProcedureStepSOPClass + {" ", 2, 0},//PhilipsPrivateMRSyntheticImageStorage + {"XC", 2, 0},//VLPhotographicImageStorage + {"SEG ", 3, 0},// Segmentation Storage + {" ", 2, 0},// RT Ion Plan Storage + {"XA", 3, 0},// XRay3DAngiographicImageStorage, + {"XA", 3, 0},// Enhanced XA Image Storage + {" ", 2, 0},// RTIonBeamsTreatmentRecordStorage + {"SEG", 3, 0},// Surface Segmentation Storage + {"SM", 2, 0},// VLWholeSlideMicroscopyImageStorage + {"RTRECORD", 2, 0},//RTTreatmentSummaryRecordStorage + {"US", 3, 0},// EnhancedUSVolumeStorage + {" ", 2, 0},// XRayRadiationDoseSR + {"ES", 2, 0},// VLEndoscopicImageStorage + {"MG", 3, 0},// BreastTomosynthesisImageStorage + {"CR", 2, 0},// FujiPrivateCRImageStorage + {"OP", 2, 0},// OphthalmicPhotography8BitImageStorage + {"OPT", 3, 0},// OphthalmicTomographyImageStorage + {"GM", 3, 0},// VLMicroscopicImageStorage + + {NULL, 0, 0} //MS_END +}; + +unsigned int MediaStorage::GetNumberOfMSType() +{ + const unsigned int n = MS_END; + assert( n > 0 ); + return n; +} + +unsigned int MediaStorage::GetNumberOfMSString() +{ + static const unsigned int n = sizeof( MSStrings ) / sizeof( *MSStrings ); + assert( n > 0 ); + return n - 1; +} + +unsigned int MediaStorage::GetNumberOfModality() +{ + static const unsigned int n = sizeof( MSModalityTypes ) / sizeof( *MSModalityTypes ); + assert( n > 0 ); + return n - 1; +} + +const char *MediaStorage::GetModality() const +{ + if (!MSModalityTypes[MSField].Modality) + return NULL; + assert( MSModalityTypes[MSField].Modality[0] != ' ' ); // FIXME + return MSModalityTypes[MSField].Modality; +} + +unsigned int MediaStorage::GetModalityDimension() const +{ + if (!MSModalityTypes[MSField].Modality) + return 0; + assert( MSModalityTypes[MSField].Dimension ); + return MSModalityTypes[MSField].Dimension; +} + +void MediaStorage::GuessFromModality(const char *modality, unsigned int dim) +{ + // no default value is set, it is up to the user to decide initial value + if( !modality || !dim ) return; + //if( strlen(modality) != 2 ) return; + int i = 0; + while( MSModalityTypes[i].Modality && + (strcmp(modality, MSModalityTypes[i].Modality) != 0 + || MSModalityTypes[i].Retired + || MSModalityTypes[i].Dimension < dim )) + { + ++i; + } + if( MSModalityTypes[i].Modality ) + { + // Ok we found something... + MSField = (MSType)i; + } +} + +const char* MediaStorage::GetFromDataSetOrHeader(DataSet const &ds, const Tag & tag) +{ + static std::string ret; + if( ds.FindDataElement( tag ) ) + { + const ByteValue *sopclassuid = ds.GetDataElement( tag ).GetByteValue(); + // Empty SOP Class UID: + // lifetechmed/A0038329.DCM + if( !sopclassuid || !sopclassuid->GetPointer() ) return 0; + std::string sopclassuid_str( + sopclassuid->GetPointer(), + sopclassuid->GetLength() ); + if( sopclassuid_str.find( ' ' ) != std::string::npos ) + { + gdcmWarningMacro( "UI contains a space character discarding" ); + std::string::size_type pos = sopclassuid_str.find_last_of(' '); + sopclassuid_str = sopclassuid_str.substr(0,pos); + } + ret = sopclassuid_str.c_str(); + return ret.c_str(); + } + return 0; +} + +bool MediaStorage::SetFromDataSetOrHeader(DataSet const &ds, const Tag & tag) +{ + const char * ms_str = GetFromDataSetOrHeader(ds,tag); + if( ms_str ) + { + MediaStorage ms = MediaStorage::GetMSType(ms_str); + MSField = ms; + if( ms == MS_END ) + { + // weird something was found, but we not find the MS anyway... + gdcmWarningMacro( "Does not know what: " << ms_str << " is..." ); + } + return true; + } + return false; +} + +const char* MediaStorage::GetFromHeader(FileMetaInformation const &fmi) +{ + const Tag tmediastoragesopclassuid(0x0002, 0x0002); + return GetFromDataSetOrHeader(fmi, tmediastoragesopclassuid); +} + +bool MediaStorage::SetFromHeader(FileMetaInformation const &fmi) +{ + const Tag tmediastoragesopclassuid(0x0002, 0x0002); + return SetFromDataSetOrHeader(fmi, tmediastoragesopclassuid); +} + +const char* MediaStorage::GetFromDataSet(DataSet const &ds) +{ + const Tag tsopclassuid(0x0008, 0x0016); + return GetFromDataSetOrHeader(ds, tsopclassuid); +} + + +bool MediaStorage::SetFromDataSet(DataSet const &ds) +{ + const Tag tsopclassuid(0x0008, 0x0016); + return SetFromDataSetOrHeader(ds, tsopclassuid); +} + +void MediaStorage::SetFromSourceImageSequence(DataSet const &ds) +{ + const Tag sourceImageSequenceTag(0x0008,0x2112); + if( ds.FindDataElement( sourceImageSequenceTag ) ) + { + const DataElement &sourceImageSequencesq = ds.GetDataElement( sourceImageSequenceTag ); + //const SequenceOfItems* sq = sourceImageSequencesq.GetSequenceOfItems(); + SmartPointer sq = sourceImageSequencesq.GetValueAsSQ(); + if( !sq ) return; + SequenceOfItems::ConstIterator it = sq->Begin(); + const DataSet &subds = it->GetNestedDataSet(); + // (0008,1150) UI =MRImageStorage # 26, 1 ReferencedSOPClassUID + const Tag referencedSOPClassUIDTag(0x0008,0x1150); + if( subds.FindDataElement( referencedSOPClassUIDTag ) ) + { + const DataElement& de = subds.GetDataElement( referencedSOPClassUIDTag ); + const ByteValue *sopclassuid = de.GetByteValue(); + // LEADTOOLS_FLOWERS-8-PAL-Uncompressed.dcm + //assert( sopclassuid ); + if( sopclassuid ) + { + std::string sopclassuid_str( + sopclassuid->GetPointer(), + sopclassuid->GetLength() ); + if( sopclassuid_str.find( ' ' ) != std::string::npos ) + { + gdcmWarningMacro( "UI contains a space character discarding" ); + std::string::size_type pos = sopclassuid_str.find_last_of(' '); + sopclassuid_str = sopclassuid_str.substr(0,pos); + } + MediaStorage ms = MediaStorage::GetMSType(sopclassuid_str.c_str()); + assert( ms != MS_END ); + MSField = ms; + } + } + } +} + +bool MediaStorage::SetFromModality(DataSet const &ds) +{ + // Ok let's try againg with little luck it contains a pixel data... + if( ds.FindDataElement( Tag(0x7fe0,0x0010) ) ) + { + // Pixel Data found ! + // Attempt to recover from the modality (0008,0060): + if( ds.FindDataElement( Tag(0x0008,0x0060) ) ) + { + // gdcm-CR-DCMTK-16-NonSamplePerPix.dcm + // Someone defined the Transfer Syntax but I have no clue what + // it is. Since there is Pixel Data element, let's try to read + // that as a buggy DICOM Image file... + const ByteValue *bv = ds.GetDataElement( Tag(0x0008,0x0060) ).GetByteValue(); + if( bv ) + { + std::string modality = std::string( bv->GetPointer(), bv->GetLength() ); + GuessFromModality( modality.c_str() ); + } + } + // We know there is a Pixel Data element, so make sure not to return without a default + // to SC Object: + if( MSField == MediaStorage::MS_END ) + { + gdcmWarningMacro( "Unknown/Unhandle MediaStorage, but Pixel Data element found" ); + // BUG: Need to check Col*Row*Bit*NSample == PixelSize (uncompressed) + MSField = MediaStorage::SecondaryCaptureImageStorage; + return false; + } + } + return true; +} + +bool MediaStorage::SetFromFile(File const &file) +{ + /* + * DICOMDIR usually have group 0002 present, but no 0008,0016 (doh!) + * So we first check in header, if found, assumed it is ok (we should + * check that consistent with 0008,0016 ...) + * A lot of DICOM image file are still missing the group header + * this is why we check 0008,0016, and to preserve compat with ACR-NEMA + * we also check Modality element to guess a fake Media Storage UID + * file such as: + * gdcmData/SIEMENS-MR-RGB-16Bits.dcm + * are a pain to handle ... + */ + const FileMetaInformation &header = file.GetHeader(); + const char* header_ms_ptr = GetFromHeader(header); + std::string copy1; + const char *header_ms_str = 0; + if( header_ms_ptr ) + { + copy1 = header_ms_ptr; + header_ms_str = copy1.c_str(); + } + const DataSet &ds = file.GetDataSet(); + const char* ds_ms_ptr = GetFromDataSet(ds); + std::string copy2; + const char *ds_ms_str = 0; + if( ds_ms_ptr ) + { + copy2 = ds_ms_ptr; + ds_ms_str = copy2.c_str(); + } + + // Easy case: + if( header_ms_str && ds_ms_str && strcmp(header_ms_str, ds_ms_str) == 0 ) + { + return SetFromHeader( header ); + } + + if( ds_ms_str ) + { + // means either no header ms or different, take from dataset just in case + return SetFromDataSet( ds ); + } + + // Looks suspicious or DICOMDIR... + if( header_ms_str ) + { + return SetFromHeader( header ); + } + + // old fall back + if( !SetFromHeader( header ) ) + { + // try again but from dataset this time: + gdcmDebugMacro( "No MediaStorage found in Header, looking up in DataSet" ); + if( !SetFromDataSet( ds ) ) + { + // ACR-NEMA compat: + gdcmDebugMacro( "No MediaStorage found neither in DataSet nor in FileMetaInformation, trying from Modality" ); + // Attempt to read what's in Modality: + if( !SetFromModality( ds ) ) + { + return false; + } + } + } +// BEGIN SPECIAL HANDLING FOR GDCM 1.2.x 'ReWrite'n files +#if 0 + else if( MSField == MediaStorage::SecondaryCaptureImageStorage ) + { + /* + * BEGIN HACK: + * Technically it should be enough to know that the image is a SecondaryCaptureImageStorage ... BUT GDCM 1.x + * used to rewrite everything by default as SecondaryCaptureImageStorage so when you would look carefully + * this DataSet would in fact contains *everything* from the MR Image Storage, therefore, we prefer to use + * the Source Image Sequence to detect the *real* IOD...I am pretty sure this will bite us one day... + */ + MediaStorage ms2; + ms2.SetFromSourceImageSequence(ds); + if( MSField != ms2 && ms2 != MediaStorage::MS_END ) + { + assert( MediaStorage::IsImage( ms2 ) ); + gdcmWarningMacro( "Object is declared as SecondaryCaptureImageStorage but according" + " to Source Image Sequence it was derived from " << ms2 << ". Using it instead" ); + MSField = ms2; + } + } +#endif + return true; +} + +} // end namespace gdcm diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmMediaStorage.h b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmMediaStorage.h new file mode 100644 index 0000000..bc578d1 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmMediaStorage.h @@ -0,0 +1,209 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMMEDIASTORAGE_H +#define GDCMMEDIASTORAGE_H + +#include "gdcmTransferSyntax.h" + +namespace gdcm +{ + +class DataSet; +class Tag; +class FileMetaInformation; +class File; + +// WARNING: This class will be deprecated in the future. There is no reason to extend this class. +// Please check the gdcm::UIDs class if adding new well known UID. + +/** + * \brief MediaStorage + * + * \note + * FIXME There should not be any notion of Image and/or PDF at that point + * Only the codec can answer yes I support this Media Storage or not... + * For instance an ImageCodec will answer yes to most of them + * while a PDFCodec will answer only for the Encapsulated PDF + * + * \see UIDs + */ +class GDCM_EXPORT MediaStorage +{ +public: + typedef enum { + MediaStorageDirectoryStorage = 0, + ComputedRadiographyImageStorage, + DigitalXRayImageStorageForPresentation, + DigitalXRayImageStorageForProcessing, + DigitalMammographyImageStorageForPresentation, + DigitalMammographyImageStorageForProcessing, + DigitalIntraoralXrayImageStorageForPresentation, + DigitalIntraoralXRayImageStorageForProcessing, + CTImageStorage, + EnhancedCTImageStorage, + UltrasoundImageStorageRetired, + UltrasoundImageStorage, + UltrasoundMultiFrameImageStorageRetired, + UltrasoundMultiFrameImageStorage, + MRImageStorage, + EnhancedMRImageStorage, + MRSpectroscopyStorage, + NuclearMedicineImageStorageRetired, + SecondaryCaptureImageStorage, + MultiframeSingleBitSecondaryCaptureImageStorage, + MultiframeGrayscaleByteSecondaryCaptureImageStorage, + MultiframeGrayscaleWordSecondaryCaptureImageStorage, + MultiframeTrueColorSecondaryCaptureImageStorage, + StandaloneOverlayStorage, + StandaloneCurveStorage, + LeadECGWaveformStorage, // 12- + GeneralECGWaveformStorage, + AmbulatoryECGWaveformStorage, + HemodynamicWaveformStorage, + CardiacElectrophysiologyWaveformStorage, + BasicVoiceAudioWaveformStorage, + StandaloneModalityLUTStorage, + StandaloneVOILUTStorage, + GrayscaleSoftcopyPresentationStateStorageSOPClass, + XRayAngiographicImageStorage, + XRayRadiofluoroscopingImageStorage, + XRayAngiographicBiPlaneImageStorageRetired, + NuclearMedicineImageStorage, + RawDataStorage, + SpacialRegistrationStorage, // Spatial + SpacialFiducialsStorage, // Spatial.. + PETImageStorage, + RTImageStorage, + RTDoseStorage, + RTStructureSetStorage, + RTPlanStorage, + CSANonImageStorage, + Philips3D, + EnhancedSR, + BasicTextSR, + HardcopyGrayscaleImageStorage, + ComprehensiveSR, + DetachedStudyManagementSOPClass, + EncapsulatedPDFStorage, + EncapsulatedCDAStorage, + StudyComponentManagementSOPClass, + DetachedVisitManagementSOPClass, + DetachedPatientManagementSOPClass, + VideoEndoscopicImageStorage, + GeneralElectricMagneticResonanceImageStorage, + GEPrivate3DModelStorage, + ToshibaPrivateDataStorage, + MammographyCADSR, + KeyObjectSelectionDocument, + HangingProtocolStorage, + ModalityPerformedProcedureStepSOPClass, + PhilipsPrivateMRSyntheticImageStorage, + VLPhotographicImageStorage, + SegmentationStorage, // "1.2.840.10008.5.1.4.1.1.66.4" + RTIonPlanStorage, // 1.2.840.10008.5.1.4.1.1.481.8 + XRay3DAngiographicImageStorage, // 1.2.840.10008.5.1.4.1.1.13.1.1 + EnhancedXAImageStorage, + RTIonBeamsTreatmentRecordStorage, // 1.2.840.10008.5.1.4.1.1.481.9 + SurfaceSegmentationStorage, // "1.2.840.10008.5.1.4.1.1.66.5" + VLWholeSlideMicroscopyImageStorage, // 1.2.840.10008.5.1.4.1.1.77.1.6 + RTTreatmentSummaryRecordStorage, // 1.2.840.10008.5.1.4.1.1.481.7 + EnhancedUSVolumeStorage, // 1.2.840.10008.5.1.4.1.1.6.2 + XRayRadiationDoseSR, // 1.2.840.10008.5.1.4.1.1.88.67 + VLEndoscopicImageStorage, // 1.2.840.10008.5.1.4.1.1.77.1.1 + BreastTomosynthesisImageStorage, // 1.2.840.10008.5.1.4.1.1.13.1.3 + FujiPrivateCRImageStorage, // 1.2.392.200036.9125.1.1.2 + OphthalmicPhotography8BitImageStorage, // 1.2.840.10008.5.1.4.1.1.77.1.5.1 + OphthalmicTomographyImageStorage, // 1.2.840.10008.5.1.4.1.1.77.1.5.4 + VLMicroscopicImageStorage, + MS_END + } MSType; // Media Storage Type + +typedef enum { + NoObject = 0, // DICOMDIR + Video, // Most common, include image, video and volume + Waveform, // Isn't it simply a 1D video ? + Audio, // ??? + PDF, + URI, // URL... + Segmentation, // TODO + ObjectEnd + } ObjectType; + + /// Return the Media String associated. Will return NULL for MS_END + static const char* GetMSString(MSType ts); + + /// Return the Media String of the object. + const char* GetString() const; + static MSType GetMSType(const char *str); + + MediaStorage(MSType type = MS_END):MSField(type) {} + + /// Returns whether DICOM has a Pixel Data element (7fe0,0010) + /// \warning MRSpectroscopyStorage could be image but are not + static bool IsImage(MSType ts); + + operator MSType () const { return MSField; } + + const char *GetModality() const; + unsigned int GetModalityDimension() const; + + static unsigned int GetNumberOfMSType(); + static unsigned int GetNumberOfMSString(); + static unsigned int GetNumberOfModality(); + + + /// Attempt to set the MediaStorage from a file: + /// WARNING: When no MediaStorage & Modality are found BUT a PixelData element is found + /// then MediaStorage is set to the default SecondaryCaptureImageStorage (return value is + /// false in this case) + bool SetFromFile(File const &file); + + /// Advanced user only (functions should be protected level...) + /// Those function are lower level than SetFromFile + bool SetFromDataSet(DataSet const &ds); // Will get the SOP Class UID + bool SetFromHeader(FileMetaInformation const &fmi); // Will get the Media Storage SOP Class UID + bool SetFromModality(DataSet const &ds); + void GuessFromModality(const char *modality, unsigned int dimension = 2); + + friend std::ostream &operator<<(std::ostream &os, const MediaStorage &ms); + + bool IsUndefined() const { return MSField == MS_END; } + +protected: + void SetFromSourceImageSequence(DataSet const &ds); + +private: + bool SetFromDataSetOrHeader(DataSet const &ds, const Tag & tag); + /// NOT THREAD SAFE + const char* GetFromDataSetOrHeader(DataSet const &ds, const Tag & tag); + /// NOT THREAD SAFE + const char* GetFromHeader(FileMetaInformation const &fmi); + /// NOT THREAD SAFE + const char* GetFromDataSet(DataSet const &ds); + +private: + MSType MSField; +}; +//----------------------------------------------------------------------------- +inline std::ostream &operator<<(std::ostream &_os, const MediaStorage &ms) +{ + const char *msstring = MediaStorage::GetMSString(ms); + _os << (msstring ? msstring : "INVALID MEDIA STORAGE"); + return _os; + +} + +} // end namespace gdcm + +#endif // GDCMMEDIASTORAGE_H diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmPDBElement.h b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmPDBElement.h new file mode 100644 index 0000000..9db1f42 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmPDBElement.h @@ -0,0 +1,67 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMPDBELEMENT_H +#define GDCMPDBELEMENT_H + +#include "gdcmTag.h" +#include "gdcmVM.h" +#include "gdcmVR.h" +#include "gdcmByteValue.h" +#include "gdcmSmartPointer.h" + +namespace gdcm +{ +/** + * \brief Class to represent a PDB Element + * \see PDBHeader + */ +class GDCM_EXPORT PDBElement +{ +public: + PDBElement() {} + + friend std::ostream& operator<<(std::ostream &os, const PDBElement &val); + + /// Set/Get Name + const char *GetName() const { return NameField.c_str(); } + void SetName(const char *name) { NameField = name; } + + /// Set/Get Value + const char *GetValue() const { return ValueField.c_str(); } + void SetValue(const char *value) { ValueField = value; } + + bool operator==(const PDBElement &de) const + { + return ValueField == de.ValueField + && NameField == de.NameField; + } + +protected: + std::string NameField; + std::string ValueField; +}; +//----------------------------------------------------------------------------- +inline std::ostream& operator<<(std::ostream &os, const PDBElement &val) +{ + os << val.NameField; + os << " \""; + os << val.ValueField; + os << "\""; + + return os; +} + +} // end namespace gdcm + +#endif //GDCMPDBELEMENT_H diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmPDBHeader.cxx b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmPDBHeader.cxx new file mode 100644 index 0000000..c79e7c1 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmPDBHeader.cxx @@ -0,0 +1,303 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmPDBHeader.h" +#include "gdcmPrivateTag.h" +#include "gdcmDataElement.h" +#include "gdcmDataSet.h" +#include "gdcmExplicitDataElement.h" +#include "gdcmSwapper.h" +#include "gdcmDeflateStream.h" + +namespace gdcm +{ + +/* + * In some GE MEDICAL SYSTEMS image one can find a Data Element: 0025,xx1b,GEMS_SERS_01 + * which is documented as Protocol Data Block (compressed). + * in fact this is a simple text format compressed using the gzip algorithm + * + * Typically one could do: + * + * $ gdcmraw -i input.dcm -o output.raw -t 0025,101b + * + * Skip the binary length (little endian encoding): + * + * $ dd bs=4 skip=1 if=output.raw of=foo + * + * Check file type: + * + * $ file foo + * foo: gzip compressed data, was "Ex421Ser8Scan1", from Unix + * + * Gunzip ! + * $ gzip -dc < foo > bar + * $ cat bar + * + * THANKS to: John Reiser (BitWagon.com) for hints + * + * For sample see: + * GE_MR_0025xx1bProtocolDataBlock.dcm + * ( <=> http://server.oersted.dtu.dk/personal/jw/jwpublic/courses/31540/mri/second_set/dicom/t2/b17.dcm) + */ + +/* Typical output: + * + * ENTRY "Head First" + * POSITION "Supine" + * ANREF "NA" + * COIL "HEAD" + * PLANE "OBLIQUE" + * SEDESCFLAG "1" + * SEDESC "AX FSE T2" + * IMODE "2D" + * PSEQ "FSE-XL" + * IOPT "FC, EDR, TRF, Fast" + * PLUG "22" + * FILTCHOICE "None" + * BWRT "-1" + * TRICKSIMG "1" + * TAG_SPACE "7" + * TAG_TYPE "None" + * USERCV0 "0.00" + * USERCV6 "0.00" + * USERCV7 "0.00" + * USERCV21 "0.00" + * USERCV_MASK "2097344" + * TE "102.0" + * NECHO "1" + * TR "5720.0" + * NUMACQS "1" + * ETL "17" + * BPMMODE "0" + * AUTOTRGTYPE "0" + * PSDTRIG "0" + * SLICEORDER "1" + * VIEWORDER "1" + * TRREST "0" + * TRACTIVE "0" + * SLICEASSET "1.00" + * PHASEASSET "1.00" + * SEPSERIES "0" + * AUTOTRIGWIN "0" + * FOV "24.0" + * SLTHICK "2.0" + * SPC "2.0" + * GRXOPT "0" + * SLOC1 "L11.8" + * SLOC2 "P29.9" + * SLOC3 "I50.0" + * ELOC1 "L11.6" + * ELOC2 "P29.4" + * ELOC3 "S53.9" + * NOSLC "27" + * SL3PLANE "0" + * SL3PLANE1 "0" + * SL3PLANE2 "0" + * SL3PLANE3 "0" + * SPCPERPLANE1 "0.0" + * SPCPERPLANE2 "0.0" + * SPCPERPLANE3 "0.0" + * MATRIXX "448" + * MATRIXY "224" + * SWAPPF "A/P" + * NEX "4.00" + * CONTRAST "No" + * CONTAM "Yes " + * TBLDELTA "0.00" + * PHASEFOV "0.75" + * RBW "31.25" + * AUTOSHIM "Auto" + * PHASECORR "Yes" + * FLDIR "Freq" + * NUMACCELFACTOR "1.00" + * PAUSEDELMASKACQ "1" + * NOTES ".pn/_3" + * GRIP_NUMSLGROUPS "1" + * GRIP_SLGROUP1 "-11.703952 -29.677423 1.949659 0.002380 0.004775 0.999985 0.999997 0.000175 -0.002380 0.000186 -0.999988 0.004775 27 0.000000 1 0 0" + * GRIP_SATGROUP1 "0" + * GRIP_SATGROUP2 "0" + * GRIP_SATGROUP3 "0" + * GRIP_SATGROUP4 "0" + * GRIP_SATGROUP5 "0" + * GRIP_SATGROUP6 "0" + * GRIP_TRACKER "0" + * GRIP_SPECTRO "0" + * GRIP_NUMPSCVOL "0" + * GRIP_PSCVOL1 "0" + * GRIP_PSCVOL2 "0" + * GRIP_PSCVOLFOV "0.000000" + * GRIP_PSCVOLTHICK "0.000000" + * AUTOSUBOPTIONS "0" + * AUTOSCIC "0" + * AUTOVOICE "0" + * PRESETDELAY "0.0" + * MASKPHASE "0" + * MASKPAUSE "0" + * TOTALNOSTATION "0" + * STATION "0" + */ + +PDBElement PDBHeader::PDBEEnd = PDBElement( ); + + const PDBElement& PDBHeader::GetPDBEEnd() const + { + return PDBEEnd; + } + +int PDBHeader::readprotocoldatablock(const char *input, size_t inputlen, bool verbose) +{ + (void)verbose; + // First 4 bytes are the length (again) + uint32_t len = *(uint32_t*)input; + SwapperNoOp::SwapArray(&len,1); + //if( verbose ) + // std::cout << len << "," << inputlen << std::endl; + if( len + 4 + 1 == inputlen ) + { + //if( verbose ) + // std::cout << "gzip stream was padded with an extra 0 \n"; + } + else if( len + 4 == inputlen ) + { + //if( verbose ) + // std::cout << "gzip stream was not padded with an extra 0 \n"; + } + else + { + //std::cerr << "Found the Protocol Data Block but could not read length..." << std::endl; + return 1; + } + // Alright we need to check if the binary blob was padded, if padded we need to + // discard the trailing \0 to please gzip: + std::string str( input + 4, input + len ); + std::istringstream is( str ); + + zlib_stream::zip_istream gzis( is ); + +// if (gzis.is_gzip()) +// { +// std::cout<<"crc check: "<<( gzis.check_crc() ? "ok" : "failed"); +// std::cout << std::endl; +// } + + std::string out; + //while( gzis >> out ) + while( std::getline(gzis , out ) ) + { + PDBElement pdbel; + //std::cout << out << std::endl; + std::istringstream is2( out ); + std::string name, value; + is2 >> name; + std::getline(is2, value); + pdbel.SetName( name.c_str() ); + // remove the first space character and the first & last " character + std::string value2( value.begin()+2, value.end()-1); + pdbel.SetValue( value2.c_str() ); + InternalPDBDataSet.push_back( pdbel ); + } + //std::cout << out.size(); + + return 0; +} + +/* +int DumpProtocolDataBlock(const std::string & filename, bool verbose) +{ + gdcm::Reader reader; + reader.SetFileName( filename.c_str() ); + if( !reader.Read() ) + { + std::cerr << "Failed to read: " << filename << std::endl; + return 1; + } + const gdcm::DataSet& ds = reader.GetFile().GetDataSet(); + + const gdcm::PrivateTag tprotocoldatablock(0x0025,0x1b,"GEMS_SERS_01"); + if( !ds.FindDataElement( tprotocoldatablock) ) + { + std::cerr << "Could not find tag: " << tprotocoldatablock << std::endl; + return 1; + } + const gdcm::DataElement& protocoldatablock= ds.GetDataElement( tprotocoldatablock); + if ( protocoldatablock.IsEmpty() ) return 1; + const gdcm::ByteValue * bv = protocoldatablock.GetByteValue(); + + std::cout << "Dumping: " << tprotocoldatablock << std::endl; + int ret = readprotocoldatablock( bv->GetPointer(), bv->GetLength(), verbose ); + + return ret; +} +*/ + +bool PDBHeader::LoadFromDataElement(DataElement const &protocoldatablock) +{ + InternalPDBDataSet.clear(); + if ( protocoldatablock.IsEmpty() ) return false; + const gdcm::ByteValue * bv = protocoldatablock.GetByteValue(); + + //std::cout << "Dumping: " << tprotocoldatablock << std::endl; + int ret = readprotocoldatablock( bv->GetPointer(), bv->GetLength(), false); + + if(ret) return false; + return true; +} + +void PDBHeader::Print(std::ostream &os) const +{ + std::vector::const_iterator it = InternalPDBDataSet.begin(); + + for(; it != InternalPDBDataSet.end(); ++it) + { + os << *it << std::endl; + } +} + +const PDBElement &PDBHeader::GetPDBElementByName(const char *name) +{ + std::vector::const_iterator it = InternalPDBDataSet.begin(); + for(; it != InternalPDBDataSet.end(); ++it) + { + const char *itname = it->GetName(); + if( strcmp(name, itname) == 0 ) + { + return *it; + } + } + return GetPDBEEnd(); +} + +bool PDBHeader::FindPDBElementByName(const char *name) +{ + std::vector::const_iterator it = InternalPDBDataSet.begin(); + for(; it != InternalPDBDataSet.end(); ++it) + { + const char *itname = it->GetName(); + if( strcmp(name, itname) == 0 ) + { + return true; + } + } + return false; +} + +static const char pdbheader[] = "GEMS_SERS_01"; +static const gdcm::PrivateTag t1(0x0025,0x001b,pdbheader); + +const PrivateTag & PDBHeader::GetPDBInfoTag() +{ + return t1; +} + +} // end namespace gdcm diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmPDBHeader.h b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmPDBHeader.h new file mode 100644 index 0000000..3a86338 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmPDBHeader.h @@ -0,0 +1,91 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMPDBHEADER_H +#define GDCMPDBHEADER_H + +#include "gdcmTypes.h" +#include "gdcmDataSet.h" +#include "gdcmPDBElement.h" + +namespace gdcm +{ + +/* + * Everything done in this code is for the sole purpose of writing interoperable + * software under Sect. 1201 (f) Reverse Engineering exception of the DMCA. + * If you believe anything in this code violates any law or any of your rights, + * please contact us (gdcm-developers@lists.sourceforge.net) so that we can + * find a solution. + */ +//----------------------------------------------------------------------------- + +class DataElement; +class PrivateTag; +/** + * \brief Class for PDBHeader + * + * GEMS MR Image have an Attribute (0025,1b,GEMS_SERS_01) which store the + * Acquisition parameter of the MR Image. It is compressed and can therefore + * not be used as is. This class de-encapsulated the Protocol Data Block and + * allow users to query element by name. + * + * \warning + * Everything you do with this code is at your own risk, since decoding process + * was not written from specification documents. + * + * \warning: the API of this class might change. + * + * \see CSAHeader + */ +class GDCM_EXPORT PDBHeader +{ + friend std::ostream& operator<<(std::ostream &_os, const PDBHeader &d); +public : + PDBHeader() {} + ~PDBHeader() {} + + /// Load the PDB Header from a DataElement of a DataSet + bool LoadFromDataElement(DataElement const &de); + + /// Print + void Print(std::ostream &os) const; + + /// Return the Private Tag where the PDB header is stored within a DICOM DataSet + static const PrivateTag & GetPDBInfoTag(); + + /// Lookup in the PDB header if a PDB element match the name 'name': + /// \warning Case Sensitive + const PDBElement &GetPDBElementByName(const char *name); + + /// Return true if the PDB element matching name is found or not + bool FindPDBElementByName(const char *name); + +protected: + const PDBElement& GetPDBEEnd() const; + +private: + int readprotocoldatablock(const char *input, size_t inputlen, bool verbose); + std::vector InternalPDBDataSet; + static PDBElement PDBEEnd; +}; +//----------------------------------------------------------------------------- +inline std::ostream& operator<<(std::ostream &os, const PDBHeader &d) +{ + d.Print( os ); + return os; +} + +} // end namespace gdcm +//----------------------------------------------------------------------------- +#endif //GDCMPDBHEADER_H diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmParseException.cxx b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmParseException.cxx new file mode 100644 index 0000000..ed8044f --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmParseException.cxx @@ -0,0 +1,19 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmParseException.h" + +namespace gdcm +{ + +} // end namespace gdcm diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmParseException.h b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmParseException.h new file mode 100644 index 0000000..5b6a5e4 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmParseException.h @@ -0,0 +1,90 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMPARSEEXCEPTION_H +#define GDCMPARSEEXCEPTION_H + +#include "gdcmException.h" +#include "gdcmDataElement.h" + +// Disable clang warning "dynamic exception specifications are deprecated". +// We need to be C++03 and C++11 compatible, and if we remove the 'throw()' +// specifier we'll get an error in C++03 by not matching the superclass. +#if defined(__clang__) && defined(__has_warning) +# if __has_warning("-Wdeprecated") +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wdeprecated" +# endif +#endif + +namespace gdcm +{ +/** + * \brief ParseException Standard exception handling object. + * + */ +class ParseException : public Exception +{ +public: + ParseException() + { + } + virtual ~ParseException() throw() {} + + /** Assignment operator. */ + ParseException &operator= ( const ParseException &orig ) + { + (void)orig; + //TODO + return *this; + } + + /** Equivalence operator. */ +/* virtual bool operator==( const ParseException &orig ) + { + return true; + }*/ + +/* + // Multiple calls to what ?? + const char* what() const throw() + { + static std::string strwhat; + std::ostringstream oswhat; + oswhat << File << ":" << Line << ":\n"; + oswhat << Description; + strwhat = oswhat.str(); + return strwhat.c_str(); + } +*/ + void SetLastElement(DataElement& de) + { + LastElement = de; + } + const DataElement& GetLastElement() const { return LastElement; } + +private: + // Store last parsed element before error: + DataElement LastElement; +}; + +} // end namespace gdcm + +// Undo warning suppression. +#if defined(__clang__) && defined(__has_warning) +# if __has_warning("-Wdeprecated") +# pragma clang diagnostic pop +# endif +#endif + +#endif diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmParser.cxx b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmParser.cxx new file mode 100644 index 0000000..149cabd --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmParser.cxx @@ -0,0 +1,113 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmParser.h" + +namespace gdcm +{ + +static const char *ErrorStrings[] = +{ + "FATAL", + NULL +}; + +bool Parser::Parse(const char *buffer, int len, bool isFinal) +{ + if (len == 0) + { + if (!isFinal) + { + return true; + } + //PositionPtr = BufferPtr; + //ErrorCode = processor(BufferPtr, ParseEndPtr = BufferEnd, 0); + //if (ErrorCode == NoError) + // return true; + //EventEndPtr = EventPtr; + //ProcessorPtr = ErrorProcessor; + return false; + } + else + { + memcpy(GetBuffer(len), buffer, len); + return ParseBuffer(len, isFinal); + } +} + + +char *Parser::GetBuffer(int len) +{ + return Buffer.Get(len); +} + +Parser::ErrorType Parser::Process() +{ + return Parser::NoError; +} + +bool Parser::ParseBuffer(int len, bool isFinal) +{ + const char *start = Buffer.GetStart(); + const char *positionPtr = start; + (void)positionPtr; + Buffer.ShiftEnd(len); //bufferEnd += len; + //parseEndByteIndex += len; + ErrorCode = Process(); + if (ErrorCode == Parser::NoError) + { + if (!isFinal) + Buffer.UpdatePosition(); + return 1; + } + //else + { + //eventEndPtr = eventPtr; + //processor = errorProcessor; + } + return 0; +} + + +void Parser::SetUserData(void *userData) +{ + (void)userData; +} + +void * Parser::GetUserData() const +{ + return UserData; +} + +void Parser::SetElementHandler(StartElementHandler start, EndElementHandler end) +{ + StartElement = start; + EndElement = end; +} + +unsigned long Parser::GetCurrentByteIndex() const +{ + return 0; +} + +Parser::ErrorType Parser::GetErrorCode() const +{ + return ErrorCode; +} + +const char *Parser::GetErrorString(ErrorType const &err) +{ + return ErrorStrings[(int)err]; +} + +} // end namespace gdcm diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmParser.h b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmParser.h new file mode 100644 index 0000000..e9d3a92 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmParser.h @@ -0,0 +1,120 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#ifndef GDCMPARSER_H +#define GDCMPARSER_H + +#include "gdcmTag.h" +#error do not use +#include "gdcmByteBuffer.h" + +#include // std::ifstream + +namespace gdcm +{ +/** + * \brief Parser ala XML_Parser from expat (SAX) + * + * Detailled description here + * \note Simple API for DICOM + */ +class GDCM_EXPORT Parser /*: private IStream*/ +{ +public: + typedef enum { + NoError, + NoMemoryError, + SyntaxError, + NoElementsError, + TagMismatchError, + DuplicateAttributeError, + JunkAfterDocElementError, + UndefinedEntityError, + UnexpectedStateError + } ErrorType; + + Parser() : UserData(0),Buffer(),ErrorCode(NoError) {} + ~Parser() {} + + // Parse some more of the document. The string s is a buffer containing + // part (or perhaps all) of the document. The number of bytes of s that + // are part of the document is indicated by len. This means that s + // doesn't have to be null terminated. It also means that if len is + // larger than the number of bytes in the block of memory that s points + // at, then a memory fault is likely. The isFinal parameter informs the + // parser that this is the last piece of the document. Frequently, the + // last piece is empty (i.e. len is zero.) If a parse error occurred, + // it returns 0. Otherwise it returns a non-zero value. + bool Parse(const char* s, int len, bool isFinal); + + // Set handlers for start and end tags. Attributes are passed to the + // start handler as a pointer to a vector of char pointers. Each + // attribute seen in a start (or empty) tag occupies 2 consecutive places + // in this vector: the attribute name followed by the attribute value. + // These pairs are terminated by a null pointer. + typedef void (*StartElementHandler) (void *userData, + const Tag &tag, + const char *atts[]); + typedef void (*EndElementHandler) (void *userData, const Tag &name); + void SetElementHandler(StartElementHandler start, EndElementHandler end); + + // Return what type of error has occurred. + ErrorType GetErrorCode() const; + + // Return a string describing the error corresponding to code. + // The code should be one of the enums that can be returned from + // GetErrorCode. + static const char *GetErrorString(ErrorType const &err); + + // Return the byte offset of the position. + unsigned long GetCurrentByteIndex() const; + + // Miscellaneous functions + + // The functions in this section either obtain state information from + // the parser or can be used to dynamically set parser options. + + // This sets the user data pointer that gets passed to handlers. + void SetUserData(void *userData); + + // This returns the user data pointer that gets passed to handlers. + void * GetUserData() const; + +protected: + + // This is just like Parse, except in this case expat provides the buffer. + // By obtaining the buffer from expat with the GetBuffer function, + // the application can avoid double copying of the input. + bool ParseBuffer(int len, bool isFinal); + + // Obtain a buffer of size len to read a piece of the document into. + // A NULL value is returned if expat can't allocate enough memory for + // this buffer. This has to be called prior to every call to ParseBuffer. + char *GetBuffer(int len); + + ErrorType Process(); + +private: + std::ifstream Stream; + void* UserData; + ByteBuffer Buffer; + ErrorType ErrorCode; + + StartElementHandler StartElement; + EndElementHandler EndElement; +}; + +} // end namespace gdcm + +#endif //GDCMPARSER_H diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmPreamble.cxx b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmPreamble.cxx new file mode 100644 index 0000000..d69c3ac --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmPreamble.cxx @@ -0,0 +1,95 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmPreamble.h" +#include // memset + +namespace gdcm +{ + +Preamble::Preamble():Internal(0) +{ + Create(); +} + +Preamble::~Preamble() +{ + delete[] Internal; +} + +std::istream &Preamble::Read(std::istream &is) +{ + // \precondition: we are at beg of Preamble + assert ( !IsEmpty() /*&& is.tellg() == 0*/ ); + if( is.read(Internal, 128+4) ) + { + if( Internal[128+0] == 'D' + && Internal[128+1] == 'I' + && Internal[128+2] == 'C' + && Internal[128+3] == 'M') + { + return is; + } + } + + // else reset everything ! + delete[] Internal; + Internal = 0; + throw Exception( "Not a DICOM V3 file (No Preamble)" ); + + // \postcondition we are after the Preamble (or at beg of file if none) +} + +void Preamble::Valid() +{ + if( !Internal ) Internal = new char[128+4]; + memset( Internal, 0, 128 ); + strncpy( Internal+128, "DICM", 4); +} + +void Preamble::Create() +{ + if( !Internal ) Internal = new char[128+4]; + memset( Internal, 0, 128 ); + strncpy( Internal+128, "DICM", 4); +} + +void Preamble::Remove() +{ + delete[] Internal; + Internal = 0; // important +} + +// \precondition we are at the beginning of file +std::ostream const &Preamble::Write(std::ostream &os) const +{ +// assert ( os.tellg()+0 == 0 ); + if( Internal ) + { + os.write( Internal, 128+4); + } + + // \postcondition a valid Preamble has been writen to stream + return os; +} + +void Preamble::Clear() +{ +} + +void Preamble::Print(std::ostream &os) const +{ +(void)os; +} + +} // end namespace gdcm diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmPreamble.h b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmPreamble.h new file mode 100644 index 0000000..4e6d2e3 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmPreamble.h @@ -0,0 +1,87 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#ifndef GDCMPREAMBLE_H +#define GDCMPREAMBLE_H + +#include "gdcmTypes.h" +#include "gdcmVL.h" + +namespace gdcm +{ + +/** + * \brief DICOM Preamble (Part 10) + */ +class GDCM_EXPORT Preamble +{ +public: + Preamble(); + ~Preamble(); + + friend std::ostream &operator<<(std::ostream &_os, const Preamble &_val); + + // Clear + void Clear(); + + // Set Preamble to the default one + void Valid(); + void Create(); + void Remove(); + + // Read + std::istream &Read(std::istream &is); + + // Write + std::ostream const &Write(std::ostream &os) const; + + void Print(std::ostream &os) const; + + const char *GetInternal() const { return Internal; } + + bool IsEmpty() const { return !Internal; } + + VL GetLength() const { return 128 + 4; } + + Preamble(Preamble const &) + { + Create(); + } + Preamble& operator=(Preamble const &) + { + Create(); + return *this; + } +protected: + // + bool IsValid() const { + // is (IsValid == true) => Internal was read + return true; + } + + +private: + char *Internal; +}; +//----------------------------------------------------------------------------- +inline std::ostream& operator<<(std::ostream &os, const Preamble &val) +{ + os << val.Internal; + return os; +} + + +} // end namespace gdcm + +#endif //GDCMPREAMBLE_H diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmPrivateTag.cxx b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmPrivateTag.cxx new file mode 100644 index 0000000..f794ea8 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmPrivateTag.cxx @@ -0,0 +1,94 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmPrivateTag.h" +#include "gdcmTrace.h" +#include "gdcmSystem.h" // FIXME + +#include // sscanf +#include // numeric_limits + +namespace gdcm +{ + bool PrivateTag::ReadFromCommaSeparatedString(const char *str) + { + if( !str ) return false; + unsigned int group = 0, element = 0; + std::string owner; + owner.resize( strlen(str) ); // str != NULL + if( sscanf(str, "%04x,%04x,%[^\"]", &group , &element, &owner[0] ) != 3 + || group > std::numeric_limits::max() + || element > std::numeric_limits::max() + /*|| strlen(owner.c_str()) == 0*/ ) // can't use owner.empty() + { + gdcmDebugMacro( "Problem reading Private Tag: " << str ); + return false; + } + SetGroup( (uint16_t)group ); + // This is not considered an error to specify element as 1010 for example. + // just keep the lower bits of element: + SetElement( (uint8_t)element ); + SetOwner( owner.c_str() ); + if( !*GetOwner() ) + { + gdcmDebugMacro( ": " << str ); + return false; + } + return true; + } + + bool PrivateTag::operator<(const PrivateTag &_val) const + { + const Tag & t1 = *this; + const Tag & t2 = _val; + if( t1 == t2 ) + { + const char *s1 = Owner.c_str(); + const char *s2 = _val.GetOwner(); + assert( s1 ); + assert( s2 ); + if( *s1 ) + assert( s1[strlen(s1)-1] != ' ' ); + if( *s2 ) + assert( s2[strlen(s2)-1] != ' ' ); + bool res = strcmp(s1, s2) < 0; +#ifdef DEBUG_DUPLICATE + if( *s1 && *s2 && gdcm::System::StrCaseCmp(s1,s2) == 0 && strcmp(s1,s2) != 0 ) + { + // FIXME: + // Typically this should only happen with the "Philips MR Imaging DD 001" vs "PHILIPS MR IMAGING DD 001" + // or "Philips Imaging DD 001" vr "PHILIPS IMAGING DD 001" + //assert( strcmp(Owner.c_str(), _val.GetOwner()) == 0 ); + //return true; + const bool res2 = gdcm::System::StrCaseCmp(s1,s2) < 0; + res = res2; + assert( 0 ); + } +#endif + return res; + } + else return t1 < t2; + } + +DataElement PrivateTag::GetAsDataElement() const +{ + DataElement de; + de.SetTag( *this ); + de.SetVR( VR::LO ); + std::string copy = Owner; + if( copy.size() % 2 ) copy.push_back( ' ' ); + de.SetByteValue( copy.c_str(), (uint32_t)copy.size() ); + return de; +} + +} // end namespace gdcm diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmPrivateTag.h b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmPrivateTag.h new file mode 100644 index 0000000..9c08ace --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmPrivateTag.h @@ -0,0 +1,81 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMPRIVATETAG_H +#define GDCMPRIVATETAG_H + +#include "gdcmTag.h" +#include "gdcmVR.h" +#include "gdcmDataElement.h" + +#include +#include +#include +#include + +#include // strlen +#include // tolower + +namespace gdcm +{ + +/** + * \brief Class to represent a Private DICOM Data Element (Attribute) Tag (Group, Element, Owner) + * \note private tag have element value in: [0x10,0xff], for instance 0x0009,0x0000 is NOT a private tag + */ + +// TODO: We could save some space since we only store 8bits for element +class GDCM_EXPORT PrivateTag : public Tag +{ + friend std::ostream& operator<<(std::ostream &_os, const PrivateTag &_val); +public: + PrivateTag(uint16_t group = 0, uint16_t element = 0, const char *owner = ""):Tag(group,element),Owner(owner ? LOComp::Trim(owner) : "") { + // truncate the high bits + SetElement( (uint8_t)element ); + } + PrivateTag( Tag const & t, const char *owner = ""):Tag(t),Owner(owner ? LOComp::Trim(owner) : "") { + // truncate the high bits + SetElement( (uint8_t)t.GetElement()); + } + + const char *GetOwner() const { return Owner.c_str(); } + void SetOwner(const char *owner) { if(owner) Owner = LOComp::Trim(owner); } + + bool operator<(const PrivateTag &_val) const; + + /// Read PrivateTag from a string. Element number will be truncated + /// to 8bits. Eg: "1234,5678,GDCM" is private tag: (1234,78,"GDCM") + bool ReadFromCommaSeparatedString(const char *str); + + DataElement GetAsDataElement() const; + +private: + // SIEMENS MED, GEMS_PETD_01 ... + std::string Owner; +}; + +inline std::ostream& operator<<(std::ostream &os, const PrivateTag &val) +{ + //assert( !val.Owner.empty() ); + os.setf( std::ios::right ); + os << std::hex << '(' << std::setw( 4 ) << std::setfill( '0' ) + << val[0] << ',' << std::setw( 2 ) << std::setfill( '0' ) + << val[1] << ','; + os << val.Owner; + os << ')' << std::setfill( ' ' ) << std::dec; + return os; +} + +} // end namespace gdcm + +#endif //GDCMPRIVATETAG_H diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmReader.cxx b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmReader.cxx new file mode 100644 index 0000000..4d78d74 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmReader.cxx @@ -0,0 +1,1008 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmReader.h" +#include "gdcmTrace.h" +#include "gdcmVR.h" +#include "gdcmFileMetaInformation.h" +#include "gdcmSwapper.h" + +#include "gdcmDeflateStream.h" +#include "gdcmSystem.h" + +#include "gdcmExplicitDataElement.h" +#include "gdcmImplicitDataElement.h" + +#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION +#include "gdcmUNExplicitDataElement.h" +#include "gdcmCP246ExplicitDataElement.h" +#include "gdcmExplicitImplicitDataElement.h" +#include "gdcmUNExplicitImplicitDataElement.h" +#include "gdcmVR16ExplicitDataElement.h" +#endif + + +namespace gdcm +{ + +Reader::~Reader() +{ + if (Ifstream) + { + Ifstream->close(); + delete Ifstream; + Ifstream = NULL; + Stream = NULL; + } +} + +/// \brief tells us if "DICM" is found as position 128 +/// (i.e. the file is a 'true dicom' one) +/// If not found then seek back at beginning of file (could be Mallinckrodt +/// or old ACRNEMA with no preamble) +/// \precondition we are at the beginning of file +/// \postcondition we are at the beginning of the DataSet or +/// Meta Information Header +bool Reader::ReadPreamble() +{ + return true; +} + +/// \brief read the DICOM Meta Information Header +/// Find out the TransferSyntax used (default: Little Endian Explicit) +/// \precondition we are at the start of group 0x0002 (well after preamble) +/// \postcondition we are at the beginning of the DataSet +bool Reader::ReadMetaInformation() +{ + return true; +} + +bool Reader::ReadDataSet() +{ + return true; +} + +TransferSyntax Reader::GuessTransferSyntax() +{ + // Don't call this function if you have a meta file info + //assert( Header->GetTransferSyntaxType() == TransferSyntax::TS_END ); + std::streampos start = Stream->tellg(); + SwapCode sc = SwapCode::Unknown; + TransferSyntax::NegociatedType nts = TransferSyntax::Unknown; + TransferSyntax ts (TransferSyntax::TS_END); + Tag t; + t.Read(*Stream); + if( ! (t.GetGroup() % 2) ) + { + switch( t.GetGroup() ) + { + case 0x0008: + sc = SwapCode::LittleEndian; + break; + case 0x0800: + sc = SwapCode::BigEndian; + break; + default: + assert(0); + } + // Purposely not Re-use ReadVR since we can read VR_END + char vr_str[3]; + Stream->read(vr_str, 2); + vr_str[2] = '\0'; + // Cannot use GetVRTypeFromFile since is assert ... + VR::VRType vr = VR::GetVRType(vr_str); + if( vr != VR::VR_END ) + { + nts = TransferSyntax::Explicit; + } + else + { + assert( !(VR::IsSwap(vr_str))); + Stream->seekg(-2, std::ios::cur); // Seek back + if( t.GetElement() == 0x0000 ) + { + VL gl; // group length + gl.Read(*Stream); + switch(gl) + { + case 0x00000004 : + sc = SwapCode::LittleEndian; // 1234 + break; + case 0x04000000 : + sc = SwapCode::BigEndian; // 4321 + break; + case 0x00040000 : + sc = SwapCode::BadLittleEndian; // 3412 + gdcmWarningMacro( "Bad Little Endian" ); + break; + case 0x00000400 : + sc = SwapCode::BadBigEndian; // 2143 + gdcmWarningMacro( "Bad Big Endian" ); + break; + default: + assert(0); + } + } + nts = TransferSyntax::Implicit; + } + } + else + { + gdcmWarningMacro( "Start with a private tag creator" ); + assert( t.GetGroup() > 0x0002 ); + switch( t.GetElement() ) + { + case 0x0010: + sc = SwapCode::LittleEndian; + break; + default: + assert(0); + } + // Purposely not Re-use ReadVR since we can read VR_END + char vr_str[3]; + Stream->read(vr_str, 2); + vr_str[2] = '\0'; + // Cannot use GetVRTypeFromFile since is assert ... + VR::VRType vr = VR::GetVRType(vr_str); + if( vr != VR::VR_END ) + { + nts = TransferSyntax::Explicit; + } + else + { + nts = TransferSyntax::Implicit; + // We are reading a private creator (0x0010) so it's LO, it's + // difficult to come up with someting to check, maybe that + // VL < 256 ... + gdcmWarningMacro( "Very dangerous assertion needs some work" ); + } + } + assert( nts != TransferSyntax::Unknown ); + assert( sc != SwapCode::Unknown ); + if( nts == TransferSyntax::Implicit ) + { + if( sc == SwapCode::BigEndian ) + { + ts = TransferSyntax::ImplicitVRBigEndianACRNEMA; + } + else if ( sc == SwapCode::LittleEndian ) + { + ts = TransferSyntax::ImplicitVRLittleEndian; + } + else + { + assert(0); + } + } + else + { + assert(0); + } + Stream->seekg( start, std::ios::beg ); + assert( ts != TransferSyntax::TS_END ); + return ts; +} + +namespace details +{ + class DefaultCaller + { + private: + gdcm::DataSet & m_dataSet; + public: + DefaultCaller(gdcm::DataSet &ds): m_dataSet(ds){} + template + void ReadCommon(std::istream & is) const + { + m_dataSet.template Read(is); + } + template + void ReadCommonWithLength(std::istream & is, VL & length) const + { + m_dataSet.template ReadWithLength(is,length); + // manually set eofbit: + // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/yTW4ESh1IL8 + is.setstate( std::ios::eofbit ); + } + static void Check(bool b, std::istream &stream) + { + (void)stream; + if( b ) assert( stream.eof() ); + } + }; + + class ReadUpToTagCaller + { + private: + gdcm::DataSet & m_dataSet; + const gdcm::Tag & m_tag; + std::set const & m_skipTags; + public: + ReadUpToTagCaller(gdcm::DataSet &ds,const gdcm::Tag & tag, std::set const & skiptags) + : + m_dataSet(ds),m_tag(tag),m_skipTags(skiptags) + { + } + + template + void ReadCommon(std::istream & is) const + { + m_dataSet.template ReadUpToTag(is,m_tag,m_skipTags); + } + template + void ReadCommonWithLength(std::istream & is, VL & length) const + { + m_dataSet.template ReadUpToTagWithLength(is,m_tag,m_skipTags,length); + } + static void Check(bool , std::istream &) {} + }; + + class ReadSelectedTagsCaller + { + private: + DataSet & m_dataSet; + std::set const & m_tags; + bool m_readvalues; + public: + ReadSelectedTagsCaller(DataSet &ds, std::set const & tags, const bool readvalues) + : + m_dataSet(ds),m_tags(tags),m_readvalues(readvalues) + { + } + + template + void ReadCommon(std::istream & is) const + { + m_dataSet.template ReadSelectedTags(is,m_tags,m_readvalues); + } + template + void ReadCommonWithLength(std::istream & is, VL & length) const + { + m_dataSet.template ReadSelectedTagsWithLength(is,m_tags,length,m_readvalues); + } + static void Check(bool , std::istream &) {} + }; + + class ReadSelectedPrivateTagsCaller + { + private: + DataSet & m_dataSet; + std::set const & m_groups; + bool m_readvalues; + public: + ReadSelectedPrivateTagsCaller(DataSet &ds, std::set const & groups, const bool readvalues) + : + m_dataSet(ds),m_groups(groups),m_readvalues(readvalues) + { + } + + template + void ReadCommon(std::istream & is) const + { + m_dataSet.template ReadSelectedPrivateTags(is,m_groups,m_readvalues); + } + template + void ReadCommonWithLength(std::istream & is, VL & length) const + { + m_dataSet.template ReadSelectedPrivateTagsWithLength(is,m_groups,length,m_readvalues); + } + static void Check(bool , std::istream &) {} + }; +} + +bool Reader::Read() +{ + details::DefaultCaller caller(F->GetDataSet()); + return InternalReadCommon(caller); +} + +bool Reader::ReadUpToTag(const Tag & tag, std::set const & skiptags) +{ + details::ReadUpToTagCaller caller(F->GetDataSet(),tag,skiptags); + return InternalReadCommon(caller); +} + +bool Reader::ReadSelectedTags( std::set const & selectedTags, bool readvalues ) +{ + details::ReadSelectedTagsCaller caller(F->GetDataSet(), selectedTags,readvalues); + return InternalReadCommon(caller); +} + +bool Reader::ReadSelectedPrivateTags( std::set const & selectedPTags, bool readvalues ) +{ + details::ReadSelectedPrivateTagsCaller caller(F->GetDataSet(), selectedPTags,readvalues); + return InternalReadCommon(caller); +} + +template +bool Reader::InternalReadCommon(const T_Caller &caller) +{ + if( !Stream || !*Stream ) + { + gdcmErrorMacro( "No File" ); + return false; + } + bool success = true; + + try + { + std::istream &is = *Stream; + + bool haspreamble = true; + try + { + F->GetHeader().GetPreamble().Read( is ); + } + catch( std::exception & ) + { + // return to beginning of file, hopefully this file is simply missing preamble + is.clear(); + is.seekg(0, std::ios::beg); + haspreamble = false; + } + catch( ... ) + { + assert(0); + } + + bool hasmetaheader = false; + try + { + if( haspreamble ) + { + try + { + F->GetHeader().Read( is ); + hasmetaheader = true; + assert( !F->GetHeader().IsEmpty() ); + } + catch( std::exception &ex ) + { + (void)ex; //to avoid unreferenced variable warning on release + gdcmWarningMacro(ex.what()); + // Weird implicit meta header: + is.seekg(128+4, std::ios::beg ); + assert( is.good() ); + try + { + F->GetHeader().ReadCompat(is); + } + catch( std::exception &ex2 ) + { + (void)ex2; //to avoid unreferenced variable warning on release + // Ok I get it now... there is absolutely no meta header, giving up + //hasmetaheader = false; + gdcmErrorMacro(ex2.what()); + } + } + } + else + { + F->GetHeader().ReadCompat(is); + } + } + catch( std::exception & ) + { + // Same player play again: + is.seekg(0, std::ios::beg ); + hasmetaheader = false; + } + catch( ... ) + { + // Ooops.. + assert(0); + } + if( F->GetHeader().IsEmpty() ) + { + hasmetaheader = false; + gdcmDebugMacro( "no file meta info found" ); + } + + const TransferSyntax &ts = F->GetHeader().GetDataSetTransferSyntax(); + if( !ts.IsValid() ) + { + throw Exception( "Meta Header issue" ); + } + + //std::cerr << ts.GetNegociatedType() << std::endl; + //std::cerr << TransferSyntax::GetTSString(ts) << std::endl; + // Special case where the dataset was compressed using the deflate + // algorithm + if( ts == TransferSyntax::DeflatedExplicitVRLittleEndian ) + { +#if 0 + std::ofstream out( "/tmp/deflate.raw", std::ios::binary ); + out << is.rdbuf(); + out.close(); +#endif + zlib_stream::zip_istream gzis( is ); + // FIXME: we also know in this case that we are dealing with Explicit: + assert( ts.GetNegociatedType() == TransferSyntax::Explicit ); + //F->GetDataSet().ReadUpToTag(gzis,tag, skiptags); + caller.template ReadCommon(gzis); + // I need the following hack to read: srwithgraphdeflated.dcm + //is.clear(); + // well not anymore, see special handling of trailing \0 in: + // basic_unzip_streambuf::fill_input_buffer(void) + return is.good(); + } + + try + { + if( ts.GetSwapCode() == SwapCode::BigEndian ) + { + //US-RGB-8-epicard.dcm is big endian + if( ts.GetNegociatedType() == TransferSyntax::Implicit ) + { + // There is no such thing as Implicit Big Endian... oh well + // LIBIDO-16-ACR_NEMA-Volume.dcm + //F->GetDataSet().ReadUpToTag(is,tag, skiptags); + //caller.template ReadCommon(is); + gdcmErrorMacro( "VirtualBigEndianNotHandled" ); + throw "Virtual Big Endian Implicit is not defined by DICOM"; + } + else + { + //F->GetDataSet().ReadUpToTag(is,tag, skiptags); + caller.template ReadCommon(is); + } + } + else // LittleEndian + { + if( ts.GetNegociatedType() == TransferSyntax::Implicit ) + { + if( hasmetaheader && haspreamble ) + { + //F->GetDataSet().ReadUpToTag(is,tag, skiptags); + caller.template ReadCommon(is); + } + else + { + std::streampos start = is.tellg(); + is.seekg( 0, std::ios::end); + std::streampos end = is.tellg(); + assert( !is.eof() ); + assert( is.good() ); + std::streamoff theOffset = end-start; + assert (theOffset > 0 || (uint32_t)theOffset < std::numeric_limits::max()); + VL l = (uint32_t)(theOffset); + is.seekg( start, std::ios::beg ); + assert( is.good() ); + assert( !is.eof() ); + caller.template ReadCommonWithLength(is,l); + } + } + else + { + caller.template ReadCommon(is); + } + } + } + // Only catch parse exception at this point + catch( ParseException &ex ) + { +#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + if( ex.GetLastElement().GetVR() == VR::UN && ex.GetLastElement().IsUndefinedLength() ) + { + // non CP 246 + // P.Read( is ); + is.clear(); + if( haspreamble ) + { + is.seekg(128+4, std::ios::beg); + } + else + { + is.seekg(0, std::ios::beg); + } + if( hasmetaheader ) + { + // FIXME: we are reading twice the same meta-header, we succedeed the first time... + // We should be able to seek to proper place instead of re-reading + FileMetaInformation header; + header.Read(is); + } + + // GDCM 1.X + gdcmWarningMacro( "Attempt to read non CP 246" ); + F->GetDataSet().Clear(); // remove garbage from 1st attempt... + //F->GetDataSet().ReadUpToTag(is,tag, skiptags); + caller.template ReadCommon(is); + } + else if( ex.GetLastElement().GetVR() == VR::UN ) + { + // P.Read( is ); + is.clear(); + if( haspreamble ) + { + is.seekg(128+4, std::ios::beg); + } + else + { + is.seekg(0, std::ios::beg); + } + if( hasmetaheader ) + { + // FIXME: we are reading twice the same meta-header, we succedeed the first time... + // We should be able to seek to proper place instead of re-reading + FileMetaInformation header; + header.Read(is); + } + + // GDCM 1.X + gdcmWarningMacro( "Attempt to read GDCM 1.X wrongly encoded"); + F->GetDataSet().Clear(); // remove garbage from 1st attempt... + //F->GetDataSet().ReadUpToTag(is,tag, skiptags); + caller.template ReadCommon(is); + // This file can only be rewritten as implicit... + } + else if ( ex.GetLastElement().GetTag() == Tag(0xfeff,0x00e0) ) + { + // Famous philips where some private sequence were byteswapped ! + // eg. PHILIPS_Intera-16-MONO2-Uncompress.dcm + // P.Read( is ); + is.clear(); + if( haspreamble ) + { + is.seekg(128+4, std::ios::beg); + } + else + { + is.seekg(0, std::ios::beg); + } + if( hasmetaheader ) + { + // FIXME: we are reading twice the same meta-header, we succedeed the first time... + // We should be able to seek to proper place instead of re-reading + FileMetaInformation header; + header.Read(is); + } + + // + gdcmWarningMacro( "Attempt to read Philips with ByteSwap private sequence wrongly encoded"); + F->GetDataSet().Clear(); // remove garbage from 1st attempt... + assert(0); // TODO FIXME + } + else if( ex.GetLastElement().GetVR() == VR::INVALID ) + { + if( ts.GetNegociatedType() == TransferSyntax::Explicit ) + { + try + { + gdcmWarningMacro( "Attempt to read file with VR16bits" ); + // We could not read the VR in an explicit dataset + // seek back tag + vr: + is.seekg( -6, std::ios::cur ); + VR16ExplicitDataElement ide; + ide.template Read( is ); + // If we are here it means we succeeded in reading the implicit data element: + F->GetDataSet().Insert( ide ); + //F->GetDataSet().template Read(is); + caller.template ReadCommon(is); + // This file can only be rewritten as implicit... + } + catch ( Exception & ) + { + try + { + // Ouch ! the file is neither: + // 1. An Explicit encoded + // 2. I could not reread it using the VR16Explicit reader, last option is + // that the file is explicit/implicit + is.clear(); + if( haspreamble ) + { + is.seekg(128+4, std::ios::beg); + } + else + { + is.seekg(0, std::ios::beg); + } + if( hasmetaheader ) + { + // FIXME: we are reading twice the same meta-header, we succedeed the first time... + // We should be able to seek to proper place instead of re-reading + FileMetaInformation header; + header.Read(is); + } + + // Explicit/Implicit + // gdcmData/c_vf1001.dcm falls into that category, while in fact the fmi could simply + // be inverted and all would be perfect... + gdcmWarningMacro( "Attempt to read file with explicit/implicit" ); + F->GetDataSet().Clear(); // remove garbage from 1st attempt... + //F->GetDataSet().template Read(is); + caller.template ReadCommon(is); + } + catch ( Exception &ex2 ) + { + (void)ex2; + // Mon Jan 24 10:59:25 CET 2011 + // MM: UNExplicitImplicitDataElement does not seems to be used anymore to read + // gdcmData/TheralysGDCM120Bug.dcm, instead the code path goes into + // ExplicitImplicitDataElement class instead. + // Simply rethrow the exception for now. + throw; +#if 0 + is.clear(); + if( haspreamble ) + { + is.seekg(128+4, std::ios::beg); + } + else + { + is.seekg(0, std::ios::beg); + } + if( hasmetaheader ) + { + // FIXME: we are reading twice the same meta-header, we succedeed the first time... + // We should be able to seek to proper place instead of re-reading + FileMetaInformation header; + header.Read(is); + } + + // Explicit/Implicit + gdcmWarningMacro( "Attempt to read file with explicit/implicit" ); + F->GetDataSet().Clear(); // remove garbage from 1st attempt... + //F->GetDataSet().template Read(is); + caller.template ReadCommon(is); +#endif + } + } + } + } + else + { + gdcmWarningMacro( "Attempt to read the file as mixture of explicit/implicit"); + // Let's try again with an ExplicitImplicitDataElement: + if( ts.GetSwapCode() == SwapCode::LittleEndian && + ts.GetNegociatedType() == TransferSyntax::Explicit ) + { + // P.Read( is ); + if( haspreamble ) + { + is.seekg(128+4, std::ios::beg); + } + else + { + is.seekg(0, std::ios::beg); + } + if( hasmetaheader ) + { + // FIXME: we are reading twice the same meta-header, we succedeed the first time... + // We should be able to seek to proper place instead of re-reading + FileMetaInformation header; + header.ReadCompat(is); + } + + // Philips + F->GetDataSet().Clear(); // remove garbage from 1st attempt... + //F->GetDataSet().ReadUpToTag(is,tag, skiptags); + caller.template ReadCommon(is); + // This file can only be rewritten as implicit... + } + } +#else + gdcmDebugMacro( ex.what() ); + success = false; +#endif /* GDCM_SUPPORT_BROKEN_IMPLEMENTATION */ + } + catch( Exception &ex ) + { + (void)ex; //to avoid unreferenced variable warning on release + gdcmDebugMacro( ex.what() ); + success = false; + } + catch( ... ) + { + gdcmWarningMacro( "Unknown exception" ); + success = false; + } + + //if( success ) assert( Stream->eof() ); + caller.Check(success, *Stream ); + } + catch( Exception &ex ) + { + (void)ex; //to avoid unreferenced variable warning on release + gdcmDebugMacro( ex.what() ); + success = false; + } + catch( ... ) + { + gdcmWarningMacro( "Unknown exception" ); + success = false; + } + // if( !success ) + // { + // F->GetHeader().Clear(); + // F->GetDataSet().Clear(); + // } + + // FIXME : call this function twice... + if (Ifstream && Ifstream->is_open()) + { + //Ifstream->close(); + //delete Ifstream; + //Ifstream = NULL; + //Stream = NULL; + } + + return success; +} + +// This function re-implements code from: +// http://www.dclunie.com/medical-image-faq/html/part2.html#DICOMTransferSyntaxDetermination +// The above code does not work well for random file. It implicitly assumes we +// are trying to read a DICOM file in the first place, while our goal is indeed +// to detect whether or not the file can be assimilated as DICOM. So we +// extended it. Of course this function only returns a 'maybe DICOM', since we +// are not guaranteed that the stream is not truncated, but this is outside the +// scope of this function. +bool Reader::CanRead() const +{ + // fastpath + std::istream &is = *Stream; + assert( is.good() ); + assert( is.tellg() == std::streampos(0) ); + { + is.seekg( 128, std::ios::beg ); // we ignore return value as we test is.good() + char b[4]; + if (is.good() && is.read(b,4) && strncmp(b,"DICM",4) == 0) + { + is.seekg(0, std::ios::beg); + return true; + } + } + + // Start overhead for backward compatibility + bool bigendian = false; + bool explicitvr = false; + is.clear(); + //is.seekg(0, std::ios::end); + //std::streampos filelen = is.tellg(); + is.seekg(0, std::ios::beg); + + char b[8]; + if (is.good() && is.read(b,8)) + { + // examine probable group number ... assume <= 0x00ff + if (b[0] < b[1]) bigendian=true; + else if (b[0] == 0 && b[1] == 0) + { + // blech ... group number is zero + // no point in looking at element number + // as it will probably be zero too (group length) + // try the 32 bit value length of implicit vr + if (b[4] < b[7]) bigendian=true; + } + // else littleendian + if (isupper(b[4]) && isupper(b[5])) explicitvr=true; + } + SwapCode sc = SwapCode::Unknown; + TransferSyntax::NegociatedType nts = TransferSyntax::Unknown; + + std::stringstream ss( std::string(b, 8) ); + + Tag t; + if (bigendian) + { + t.Read(ss); + //assert( t.GetGroup() != 0x2 ); + if( t.GetGroup() <= 0xff ) + sc = SwapCode::BigEndian; + } + else + { + t.Read(ss); + //assert( t.GetGroup() != 0x2 ); + if( t.GetGroup() <= 0xff ) + sc = SwapCode::LittleEndian; + } + + VL vl; + VR::VRType vr = VR::VR_END; + if (explicitvr) + { + char vr_str[3]; + vr_str[0] = b[4]; + vr_str[1] = b[5]; + vr_str[2] = '\0'; + vr = VR::GetVRType(vr_str); + if( vr != VR::VR_END ) + nts = TransferSyntax::Explicit; + } + else + { + if( bigendian ) + vl.Read( ss ); + else + vl.Read( ss ); + if( vl < 0xff ) + nts = TransferSyntax::Implicit; + } + +#if 0 + is.clear(); + is.seekg(0, std::ios::end); + std::streampos filelen = is.tellg(); + is.seekg(0, std::ios::beg); + Tag t; + VL gl; // group length + if( bigendian ) + { + if( !t.Read(is) ) + { + is.clear(); + is.seekg(0, std::ios::beg); + return false; + } + } + else + { + if( !t.Read(is) ) + { + is.clear(); + is.seekg(0, std::ios::beg); + return false; + } + } + if( t.GetGroup() % 2 == 0 ) + { + switch( t.GetGroup() ) + { + case 0x0002: + //case 0x0004: // DICOMDIR is for media, thus FMI is compulsory + case 0x0008: + sc = SwapCode::LittleEndian; + break; + //case 0x0200: // FMI is Explicit VR Little Endian... + case 0x0800: + sc = SwapCode::BigEndian; + break; + default: + ; + } + if( sc != SwapCode::Unknown ) + { + // Purposely not Re-use ReadVR since we can read VR_END + char vr_str[3]; + is.read(vr_str, 2); + vr_str[2] = '\0'; + // Cannot use GetVRTypeFromFile since is assert ... + VR::VRType vr = VR::GetVRType(vr_str); + if( vr != VR::VR_END ) + { + nts = TransferSyntax::Explicit; + } + else + { + assert( !(VR::IsSwap(vr_str))); + is.seekg(-2, std::ios::cur); // Seek back + gl.Read(is); + + if( t.GetElement() == 0x0000 ) + { + switch(gl) + { + case 0x00000004 : + assert( sc == SwapCode::LittleEndian); // 1234 + sc = SwapCode::LittleEndian; // 1234 + break; + case 0x04000000 : + assert( sc == SwapCode::BigEndian); // 1234 + sc = SwapCode::BigEndian; // 4321 + break; + case 0x00040000 : + sc = SwapCode::BadLittleEndian; // 3412 + gdcmWarningMacro( "Bad Little Endian" ); + break; + case 0x00000400 : + sc = SwapCode::BadBigEndian; // 2143 + gdcmWarningMacro( "Bad Big Endian" ); + break; + default: + ; + } + } + if( gl && gl < filelen ) + nts = TransferSyntax::Implicit; + } + } + } + else + { + // US-IRAD-NoPreambleStartWith0003.dcm + gdcmDebugMacro( "Start with a private tag creator" ); + if( t.GetGroup() > 0x0002 && t.GetGroup() < 0x8 ) + { + switch( t.GetElement() ) + { + case 0x0010: + sc = SwapCode::LittleEndian; + break; + default: + ; + } + } + if( sc != SwapCode::Unknown ) + { + // Purposely not Re-use ReadVR since we can read VR_END + char vr_str[3]; + is.read(vr_str, 2); + vr_str[2] = '\0'; + // Cannot use GetVRTypeFromFile since is assert ... + VR::VRType vr = VR::GetVRType(vr_str); + if( vr != VR::VR_END ) + { + nts = TransferSyntax::Explicit; + } + else + { + assert( !(VR::IsSwap(vr_str))); + is.seekg(-2, std::ios::cur); // Seek back + gl.Read(is); + if( t.GetElement() == 0x0000 ) + { + assert( gl == 0x4 || gl == 0x04000000 ); + } + if( gl && gl < filelen ) + nts = TransferSyntax::Implicit; + } + } + } + +#endif + // reset in all other cases: + is.clear(); + is.seekg(0, std::ios::beg); + + // Implicit Little Endian + if( nts == TransferSyntax::Implicit && sc == SwapCode::LittleEndian ) return true; + if( nts == TransferSyntax::Implicit && sc == SwapCode::BigEndian ) return false; + if( nts == TransferSyntax::Explicit && sc == SwapCode::LittleEndian ) return true; + if( nts == TransferSyntax::Explicit && sc == SwapCode::BigEndian ) return true; + +// assert( nts == TransferSyntax::Unknown ); +// if( sc != SwapCode::Unknown ) +// { +// gdcm::Reader r; +// r.SetStream( is ); +// is.clear(); +// is.seekg(0, std::ios::beg); +// return r.Read(); +// } + + return false; +} + +void Reader::SetFileName(const char *filename) +{ + if(Ifstream) delete Ifstream; + Ifstream = new std::ifstream(); + Ifstream->open(filename, std::ios::binary); + if( Ifstream->is_open() ) + { + Stream = Ifstream; + assert( Stream && *Stream ); + } + else + { + delete Ifstream; + Ifstream = NULL; + Stream = NULL; + } +} + + +} // end namespace gdcm diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmReader.h b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmReader.h new file mode 100644 index 0000000..3df12f9 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmReader.h @@ -0,0 +1,133 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMREADER_H +#define GDCMREADER_H + +#include "gdcmFile.h" + +#include + +namespace gdcm +{ + class StreamImageReader; +/** + * \brief Reader ala DOM (Document Object Model) + * + * \details This class is a non-validating reader, it will only performs well- + * formedness check only, and to some extent catch known error (non + * well-formed document). + * + * Detailled description here + * + * A DataSet DOES NOT contains group 0x0002 (see FileMetaInformation) + * + * This is really a DataSet reader. This will not make sure the dataset conform + * to any IOD at all. This is a completely different step. The reasoning was + * that user could control the IOD there lib would handle and thus we would not + * be able to read a DataSet if the IOD was not found Instead we separate the + * reading from the validation. + * + * \note + * From GDCM1.x. Users will realize that one feature is missing + * from this DOM implementation. In GDCM 1.x user used to be able to + * control the size of the Value to be read. By default it was 0xfff. + * The main author of GDCM2 thought this was too dangerous and harmful and + * therefore this feature did not make it into GDCM2 + * + * \warning + * GDCM will not produce warning for unorder (non-alphabetical order). + * + * \see Writer FileMetaInformation DataSet File + */ +class GDCM_EXPORT Reader +{ +public: + Reader():F(new File){ + Stream = NULL; + Ifstream = NULL; + } + virtual ~Reader(); + + /// Main function to read a file + virtual bool Read(); // Execute() + + /// Set the filename to open. This will create a std::ifstream internally + /// See SetStream if you are dealing with different std::istream object + void SetFileName(const char *filename_native); + + /// Set the open-ed stream directly + void SetStream(std::istream &input_stream) { + Stream = &input_stream; + } + + /// Set/Get File + const File &GetFile() const { return *F; } + + /// Set/Get File + File &GetFile() { return *F; } + + /// Set/Get File + void SetFile(File& file) { F = &file; } + + /// Will read only up to Tag \param tag and skipping any tag specified in + /// \param skiptags + bool ReadUpToTag(const Tag & tag, std::set const & skiptags = std::set() ); + + /// Will only read the specified selected tags. + bool ReadSelectedTags(std::set const & tags, bool readvalues = true); + + /// Will only read the specified selected private tags. + bool ReadSelectedPrivateTags(std::set const & ptags, bool readvalues = true); + + /// Test whether this is a DICOM file + /// \warning need to call either SetFileName or SetStream first + bool CanRead() const; + +protected: + bool ReadPreamble(); + bool ReadMetaInformation(); + bool ReadDataSet(); + + SmartPointer F; + + friend class StreamImageReader; //need to be friended to be able to grab the GetStreamPtr + + //this function is added for the StreamImageReader, which needs to read + //up to the pixel data and then stops right before reading the pixel data. + //it's used to get that position, so that reading can continue + //apace once the read function is called. + //so, this function gets the stream directly, and then allows for position information + //from the tellg function, and allows for stream/pointer manip in order + //to read the pixel data. Note, of course, that reading pixel elements + //will still have to be subject to endianness swaps, if necessary. + std::istream* GetStreamPtr() const { return Stream; } + +private: + template + bool InternalReadCommon(const T_Caller &caller); + TransferSyntax GuessTransferSyntax(); + std::istream *Stream; + std::ifstream *Ifstream; +}; + +/** + * \example TestReader.cxx + * \example TestReader.py + * This is a C++ example on how to use gdcm::Reader + */ + +} // end namespace gdcm + + +#endif //GDCMREADER_H diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmSequenceOfFragments.cxx b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmSequenceOfFragments.cxx new file mode 100644 index 0000000..cb1bf01 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmSequenceOfFragments.cxx @@ -0,0 +1,149 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmSequenceOfFragments.h" +#include "gdcmImplicitDataElement.h" +#include "gdcmByteValue.h" + +namespace gdcm +{ + +void SequenceOfFragments::Clear() +{ + Table.SetByteValue( "", 0 ); + Fragments.clear(); +} + +SequenceOfFragments::SizeType SequenceOfFragments::GetNumberOfFragments() const +{ + // Do not count the last fragment + //assert( SequenceLengthField.IsUndefined() ); + return Fragments.size(); +} + +void SequenceOfFragments::AddFragment(Fragment const &item) +{ + Fragments.push_back(item); +} + +VL SequenceOfFragments::ComputeLength() const +{ + VL length = 0; + // First the table + length += Table.GetLength(); + // Then all the fragments + FragmentVector::const_iterator it = Fragments.begin(); + for(;it != Fragments.end(); ++it) + { + const VL fraglen = it->ComputeLength(); + assert( fraglen % 2 == 0 ); + length += fraglen; + } + assert( SequenceLengthField.IsUndefined() ); + length += 8; // seq end delimitor (tag + vl) + return length; +} + +unsigned long SequenceOfFragments::ComputeByteLength() const +{ + unsigned long r = 0; + FragmentVector::const_iterator it = Fragments.begin(); + for(;it != Fragments.end(); ++it) + { + assert( !it->GetVL().IsUndefined() ); + r += it->GetVL(); + } + return r; +} + +bool SequenceOfFragments::GetFragBuffer(unsigned int fragNb, char *buffer, unsigned long &length) const +{ + FragmentVector::const_iterator it = Fragments.begin(); + { + const Fragment &frag = *(it+fragNb); + const ByteValue &bv = dynamic_cast(frag.GetValue()); + const VL len = frag.GetVL(); + bv.GetBuffer(buffer, len); + length = len; + } + return true; +} + +const Fragment& SequenceOfFragments::GetFragment(SizeType num) const +{ + assert( num < Fragments.size() ); + FragmentVector::const_iterator it = Fragments.begin(); + const Fragment &frag = *(it+num); + return frag; +} + +bool SequenceOfFragments::GetBuffer(char *buffer, unsigned long length) const +{ + FragmentVector::const_iterator it = Fragments.begin(); + unsigned long total = 0; + for(;it != Fragments.end(); ++it) + { + const Fragment &frag = *it; + const ByteValue &bv = dynamic_cast(frag.GetValue()); + const VL len = frag.GetVL(); + bv.GetBuffer(buffer, len); + buffer += len; + total += len; + } + if( total != length ) + { + //std::cerr << " DEBUG: " << total << " " << length << std::endl; + assert(0); + return false; + } + return true; +} + +bool SequenceOfFragments::WriteBuffer(std::ostream &os) const +{ + FragmentVector::const_iterator it = Fragments.begin(); + unsigned long total = 0; + for(;it != Fragments.end(); ++it) + { + const Fragment &frag = *it; + const ByteValue *bv = frag.GetByteValue(); + assert( bv ); + const VL len = frag.GetVL(); + bv->WriteBuffer(os); + total += len; + } + //if( total != length ) + // { + // //std::cerr << " DEBUG: " << total << " " << length << std::endl; + // assert(0); + // return false; + // } + return true; +} + +bool SequenceOfFragments::FillFragmentWithJPEG( Fragment & frag, std::istream & is ) +{ + std::vector jfif; + unsigned char byte; + // begin /simple/ JPEG parser: + while( is.read( (char*)&byte, 1 ) ) + { + jfif.push_back( byte ); + if( byte == 0xd9 && jfif[ jfif.size() - 2 ] == 0xff ) break; + } + const uint32_t len = static_cast(jfif.size()); + frag.SetByteValue( (char*)&jfif[0], len ); + return true; +} + +} // end namespace gdcm diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmSequenceOfFragments.h b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmSequenceOfFragments.h new file mode 100644 index 0000000..5c9d502 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmSequenceOfFragments.h @@ -0,0 +1,333 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMSEQUENCEOFFRAGMENTS_H +#define GDCMSEQUENCEOFFRAGMENTS_H + +#include "gdcmValue.h" +#include "gdcmVL.h" +#include "gdcmFragment.h" +#include "gdcmBasicOffsetTable.h" + +namespace gdcm +{ + + // FIXME gdcmSequenceOfItems and gdcmSequenceOfFragments + // should be rethink (duplicate code) +/** + * \brief Class to represent a Sequence Of Fragments + * \todo I do not enforce that Sequence of Fragments ends with a SQ end del + */ +class GDCM_EXPORT SequenceOfFragments : public Value +{ +public: + // Typdefs: + typedef std::vector FragmentVector; + typedef FragmentVector::size_type SizeType; + typedef FragmentVector::iterator Iterator; + typedef FragmentVector::const_iterator ConstIterator; + Iterator Begin() { return Fragments.begin(); } + Iterator End() { return Fragments.end(); } + ConstIterator Begin() const { return Fragments.begin(); } + ConstIterator End() const { return Fragments.end(); } + +/// \brief constructor (UndefinedLength by default) + SequenceOfFragments():Table(),SequenceLengthField(0xFFFFFFFF) { } + + /// \brief Returns the SQ length, as read from disk + VL GetLength() const { + return SequenceLengthField; + } + + /// \brief Sets the actual SQ length + void SetLength(VL length) { + SequenceLengthField = length; + } + + /// \brief Clear + void Clear(); + + /// \brief Appends a Fragment to the already added ones + void AddFragment(Fragment const &item); + + // Compute the length of all fragments (and framents only!). + // Basically the size of the PixelData as stored (in bytes). + unsigned long ComputeByteLength() const; + + // Compute the length of fragments (in bytes)+ length of tag... + // to be used for computation of Group Length + VL ComputeLength() const; + + // Get the buffer + bool GetBuffer(char *buffer, unsigned long length) const; + bool GetFragBuffer(unsigned int fragNb, char *buffer, unsigned long &length) const; + + SizeType GetNumberOfFragments() const; + const Fragment& GetFragment(SizeType num) const; + + // Write the buffer of each fragment (call WriteBuffer on all Fragments, which are + // ByteValue). No Table information is written. + bool WriteBuffer(std::ostream &os) const; + + const BasicOffsetTable &GetTable() const { return Table; } + BasicOffsetTable &GetTable() { return Table; } + +template +std::istream& Read(std::istream &is, bool readvalues = true) +{ + assert( SequenceLengthField.IsUndefined() ); + ReadPreValue(is); + return ReadValue(is, readvalues); +} + +template +std::istream& ReadPreValue(std::istream &is) +{ + //if( SequenceLengthField.IsUndefined() ) + // First item is the basic offset table: + try + { + Table.Read(is); + gdcmDebugMacro( "Table: " << Table ); + } + catch(...) + { + // throw "SIEMENS Icon thingy"; + // Bug_Siemens_PrivateIconNoItem.dcm + // First thing first let's rewind + is.seekg(-4, std::ios::cur); + // FF D8 <=> Start of Image (SOI) marker + // FF E0 <=> APP0 Reserved for Application Use + if ( Table.GetTag() == Tag(0xd8ff,0xe0ff) ) + { + Table = BasicOffsetTable(); // clear up stuff + //Table.SetByteValue( "", 0 ); + Fragment frag; + if( FillFragmentWithJPEG( frag, is ) ) + { + Fragments.push_back( frag ); + } + return is; + } + else + { + throw "Catch me if you can"; + //assert(0); + } + } + return is; +} + +template +std::istream& ReadValue(std::istream &is, bool /*readvalues*/) +{ + const Tag seqDelItem(0xfffe,0xe0dd); + // not used for now... + Fragment frag; + try + { + while( frag.Read(is) && frag.GetTag() != seqDelItem ) + { + //gdcmDebugMacro( "Frag: " << frag ); + Fragments.push_back( frag ); + } + assert( frag.GetTag() == seqDelItem && frag.GetVL() == 0 ); + } + catch(Exception &ex) + { + (void)ex; +#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + // that's ok ! In all cases the whole file was read, because + // Fragment::Read only fail on eof() reached 1. + // SIEMENS-JPEG-CorruptFrag.dcm is more difficult to deal with, we have a + // partial fragment, read we decide to add it anyway to the stack of + // fragments (eof was reached so we need to clear error bit) + if( frag.GetTag() == Tag(0xfffe,0xe000) ) + { + gdcmWarningMacro( "Pixel Data Fragment could be corrupted. Use file at own risk" ); + Fragments.push_back( frag ); + is.clear(); // clear the error bit + } + // 2. GENESIS_SIGNA-JPEG-CorruptFrag.dcm + else if ( frag.GetTag() == Tag(0xddff,0x00e0) ) + { + assert( Fragments.size() == 1 ); + const ByteValue *bv = Fragments[0].GetByteValue(); + assert( (unsigned char)bv->GetPointer()[ bv->GetLength() - 1 ] == 0xfe ); + // Yes this is an extra copy, this is a bug anyway, go fix YOUR code + Fragments[0].SetByteValue( bv->GetPointer(), bv->GetLength() - 1 ); + gdcmWarningMacro( "JPEG Fragment length was declared with an extra byte" + " at the end: stripped !" ); + is.clear(); // clear the error bit + } + // 3. LEICA/WSI + else if ( (frag.GetTag().GetGroup() == 0x00ff) + && ((frag.GetTag().GetElement() & 0x00ff) == 0xe0) ) + { + // Looks like there is a mess with offset and odd byte array + // We are going first to backtrack one byte back, and then use a + // ReadBacktrack function which in turn may backtrack up to 10 bytes + // backward. This appears to be working on a set of DICOM/WSI files from + // LEICA + gdcmWarningMacro( "Trying to fix the even-but-odd value length bug #1" ); + assert( Fragments.size() ); + const size_t lastf = Fragments.size() - 1; + const ByteValue *bv = Fragments[ lastf ].GetByteValue(); + const char *a = bv->GetPointer(); + gdcmAssertAlwaysMacro( (unsigned char)a[ bv->GetLength() - 1 ] == 0xfe ); + Fragments[ lastf ].SetByteValue( bv->GetPointer(), bv->GetLength() - 1 ); + is.seekg( -9, std::ios::cur ); + assert( is.good() ); + while( frag.ReadBacktrack(is) && frag.GetTag() != seqDelItem ) + { + gdcmDebugMacro( "Frag: " << frag ); + Fragments.push_back( frag ); + } + assert( frag.GetTag() == seqDelItem && frag.GetVL() == 0 ); + } + // 4. LEICA/WSI (bis) + else if ( frag.GetTag().GetGroup() == 0xe000 ) + { + // Looks like there is a mess with offset and odd byte array + // We are going first to backtrack one byte back, and then use a + // ReadBacktrack function which in turn may backtrack up to 10 bytes + // backward. This appears to be working on a set of DICOM/WSI files from + // LEICA + gdcmWarningMacro( "Trying to fix the even-but-odd value length bug #2" ); + assert( Fragments.size() ); + const size_t lastf = Fragments.size() - 1; + const ByteValue *bv = Fragments[ lastf ].GetByteValue(); + const char *a = bv->GetPointer(); + gdcmAssertAlwaysMacro( (unsigned char)a[ bv->GetLength() - 2 ] == 0xfe ); + Fragments[ lastf ].SetByteValue( bv->GetPointer(), bv->GetLength() - 2 ); + is.seekg( -10, std::ios::cur ); + assert( is.good() ); + while( frag.ReadBacktrack(is) && frag.GetTag() != seqDelItem ) + { + gdcmDebugMacro( "Frag: " << frag ); + Fragments.push_back( frag ); + } + assert( frag.GetTag() == seqDelItem && frag.GetVL() == 0 ); + } + // 5. LEICA/WSI (ter) + else if ( (frag.GetTag().GetGroup() & 0x00ff) == 0x00e0 + && (frag.GetTag().GetElement() & 0xff00) == 0x0000 ) + { + // Looks like there is a mess with offset and odd byte array + // We are going first to backtrack one byte back, and then use a + // ReadBacktrack function which in turn may backtrack up to 10 bytes + // backward. This appears to be working on a set of DICOM/WSI files from + // LEICA + gdcmWarningMacro( "Trying to fix the even-but-odd value length bug #3" ); + assert( Fragments.size() ); + const size_t lastf = Fragments.size() - 1; + const ByteValue *bv = Fragments[ lastf ].GetByteValue(); + const char *a = bv->GetPointer(); + gdcmAssertAlwaysMacro( (unsigned char)a[ bv->GetLength() - 3 ] == 0xfe ); + Fragments[ lastf ].SetByteValue( bv->GetPointer(), bv->GetLength() - 3 ); + is.seekg( -11, std::ios::cur ); + assert( is.good() ); + while( frag.ReadBacktrack(is) && frag.GetTag() != seqDelItem ) + { + gdcmDebugMacro( "Frag: " << frag ); + Fragments.push_back( frag ); + } + assert( frag.GetTag() == seqDelItem && frag.GetVL() == 0 ); + } + else + { + // 3. gdcm-JPEG-LossLess3a.dcm: easy case, an extra tag was found + // instead of terminator (eof is the next char) + gdcmWarningMacro( "Reading failed at Tag:" << frag.GetTag() << " Index #" + << Fragments.size() << " Offset " << is.tellg() << ". Use file at own risk." + << ex.what() ); + } +#endif /* GDCM_SUPPORT_BROKEN_IMPLEMENTATION */ + } + + return is; +} + +template +std::ostream const &Write(std::ostream &os) const +{ + if( !Table.Write(os) ) + { + assert(0 && "Should not happen"); + return os; + } + for(ConstIterator it = Begin();it != End(); ++it) + { + it->Write(os); + } + // seq del item is not stored, write it ! + const Tag seqDelItem(0xfffe,0xe0dd); + seqDelItem.Write(os); + VL zero = 0; + zero.Write(os); + + return os; +} + +//#if defined(SWIGPYTHON) || defined(SWIGCSHARP) || defined(SWIGJAVA) + // For now leave it there, this does not make sense in the C++ layer + // Create a new object + static SmartPointer New() + { + return new SequenceOfFragments(); + } +//#endif + +protected: +public: + void Print(std::ostream &os) const { + os << "SQ L= " << SequenceLengthField << "\n"; + os << "Table:" << Table << "\n"; + for(ConstIterator it = Begin();it != End(); ++it) + { + os << " " << *it << "\n"; + } + assert( SequenceLengthField.IsUndefined() ); + { + const Tag seqDelItem(0xfffe,0xe0dd); + VL zero = 0; + os << seqDelItem; + os << "\t" << zero; + } + } + bool operator==(const Value &val) const + { + const SequenceOfFragments &sqf = dynamic_cast(val); + return Table == sqf.Table && + SequenceLengthField == sqf.SequenceLengthField && + Fragments == sqf.Fragments; + } + +private: + BasicOffsetTable Table; + VL SequenceLengthField; + /// \brief Vector of Sequence Fragments + FragmentVector Fragments; + +private: + bool FillFragmentWithJPEG( Fragment & frag, std::istream & is ); +}; + +/** + * \example DecompressJPEGFile.cs + * This is a C# example on how to use gdcm::SequenceOfFragments + */ + +} // end namespace gdcm + +#endif //GDCMSEQUENCEOFFRAGMENTS_H diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmSequenceOfFragments.txx b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmSequenceOfFragments.txx new file mode 100644 index 0000000..e3aca44 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmSequenceOfFragments.txx @@ -0,0 +1,24 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMSEQUENCEOFFRAGMENTS_TXX +#define GDCMSEQUENCEOFFRAGMENTS_TXX + +#include "gdcmSequenceOfFragments.h" + +namespace gdcm +{ + +} // end namespace gdcm + +#endif // GDCMSEQUENCEOFFRAGMENTS_TXX diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmSequenceOfItems.cxx b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmSequenceOfItems.cxx new file mode 100644 index 0000000..339cd52 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmSequenceOfItems.cxx @@ -0,0 +1,63 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmSequenceOfItems.h" + +namespace gdcm +{ + +void SequenceOfItems::AddItem(Item const &item) +{ + Items.push_back( item ); + if( !SequenceLengthField.IsUndefined() ) + { + assert(0); // TODO + } +} + +Item &SequenceOfItems::GetItem(SizeType position) +{ + if( position < 1 || position > Items.size() ) + { + throw Exception( "Out of Range" ); + } + return Items[position-1]; +} + +const Item &SequenceOfItems::GetItem(SizeType position) const +{ + if( position < 1 || position > Items.size() ) + { + throw Exception( "Out of Range" ); + } + return Items[position-1]; +} + +void SequenceOfItems::SetLengthToUndefined() +{ + SequenceLengthField = 0xFFFFFFFF; +} + +bool SequenceOfItems::FindDataElement(const Tag &t) const +{ + ConstIterator it = Begin(); + bool found = false; + for(; it != End() && !found; ++it) + { + const Item & item = *it; + found = item.FindDataElement( t ); + } + return found; +} + +} // end namespace gdcm diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmSequenceOfItems.h b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmSequenceOfItems.h new file mode 100644 index 0000000..f90f0ab --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmSequenceOfItems.h @@ -0,0 +1,253 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#ifndef GDCMSEQUENCEOFITEMS_H +#define GDCMSEQUENCEOFITEMS_H + +#include "gdcmValue.h" +#include "gdcmItem.h" + +#include +#include // strcmp + +namespace gdcm +{ + +/** + * \brief Class to represent a Sequence Of Items + * (value representation : SQ) + * - a Value Representation for Data Elements that contains a sequence of Data Sets. + * - Sequence of Item allows for Nested Data Sets + * + * See PS 3.5, 7.4.6 Data Element Type Within a Sequence + * \note + * SEQUENCE OF ITEMS (VALUE REPRESENTATION SQ) + * A Value Representation for Data Elements that contain a sequence of + * Data Sets. Sequence of Items allows for Nested Data Sets. + */ +class GDCM_EXPORT SequenceOfItems : public Value +{ +public: + // Typdefs: + typedef std::vector< Item > ItemVector; + typedef ItemVector::size_type SizeType; + typedef ItemVector::iterator Iterator; + typedef ItemVector::const_iterator ConstIterator; + Iterator Begin() { return Items.begin(); } + Iterator End() { return Items.end(); } + ConstIterator Begin() const { return Items.begin(); } + ConstIterator End() const { return Items.end(); } + + /// \brief constructor (UndefinedLength by default) + SequenceOfItems():SequenceLengthField(0xFFFFFFFF) { } + //SequenceOfItems(VL const &vl = 0xFFFFFFFF):SequenceLengthField(vl),NType(type) { } + + /// \brief Returns the SQ length, as read from disk + VL GetLength() const { return SequenceLengthField; } + /// \brief Sets the actual SQ length + void SetLength(VL length) { + SequenceLengthField = length; + } + /// \brief Properly set the Sequence of Item to be undefined length + void SetLengthToUndefined(); + /// return if Value Length if of undefined length + bool IsUndefinedLength() const { + return SequenceLengthField.IsUndefined(); + } + + template + VL ComputeLength() const; + void Clear() {} + + /// \brief Appends an Item to the already added ones + void AddItem(Item const &item); + + SizeType GetNumberOfItems() const { return Items.size(); } + void SetNumberOfItems(SizeType n) { Items.resize(n); } + + /* WARNING: first item is #1 (see DICOM standard) + * Each Item shall be implicitly assigned an ordinal position starting with the value 1 for the + * first Item in the Sequence, and incremented by 1 with each subsequent Item. The last Item in the + * Sequence shall have an ordinal position equal to the number of Items in the Sequence. + */ + const Item &GetItem(SizeType position) const; + Item &GetItem(SizeType position); + + SequenceOfItems &operator=(const SequenceOfItems &val) { + SequenceLengthField = val.SequenceLengthField; + Items = val.Items; + return *this; + } + + template + std::istream &Read(std::istream &is, bool readvalues = true) + { + (void)readvalues; + const Tag seqDelItem(0xfffe,0xe0dd); + if( SequenceLengthField.IsUndefined() ) + { + Item item; + while( item.Read(is) && item.GetTag() != seqDelItem ) + { + //gdcmDebugMacro( "Item: " << item ); + assert( item.GetTag() != seqDelItem ); + Items.push_back( item ); + item.Clear(); + } + //assert( item.GetTag() == seqDelItem && item.GetVL() == 0 ); + } + else + { + Item item; + VL l = 0; + //is.seekg( SequenceLengthField, std::ios::cur ); return is; + while( l != SequenceLengthField ) + { + try + { + item.Read(is); + } + catch( Exception &ex ) + { + if( strcmp( ex.GetDescription(), "Changed Length" ) == 0 ) + { + VL newlength = l + item.template GetLength(); + if( newlength > SequenceLengthField ) + { + // BogugsItemAndSequenceLength.dcm + gdcmWarningMacro( "SQ length is wrong" ); + SequenceLengthField = newlength; + } + } + else + { + throw ex; + } + } +#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + if( item.GetTag() == seqDelItem ) + { + gdcmWarningMacro( "SegDelItem found in defined length Sequence. Skipping" ); + assert( item.GetVL() == 0 ); + assert( item.GetNestedDataSet().Size() == 0 ); + // we need to pay attention that the length of the Sequence of Items will be wrong + // this way. Indeed by not adding this item we are changing the size of this sqi + } + else // Not a seq del item marker +#endif + { + // By design we never load them. If we were to load those attribute + // as normal item it would become very complex to convert a sequence + // from defined length to undefined length with the risk to write two + // seq del marker + Items.push_back( item ); + } + l += item.template GetLength(); + if( l > SequenceLengthField ) + { + gdcmDebugMacro( "Found: Length of Item larger than expected" ) + throw "Length of Item larger than expected"; + } + assert( l <= SequenceLengthField ); + //std::cerr << "sqi debug len: " << is.tellg() << " " << l << " " << SequenceLengthField << std::endl; +#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + // MR_Philips_Intera_No_PrivateSequenceImplicitVR.dcm + // (0x2005, 0x1080): for some reason computation of length fails... + if( SequenceLengthField == 778 && l == 774 ) + { + gdcmWarningMacro( "PMS: Super bad hack" ); + SequenceLengthField = l; + throw Exception( "Wrong Length" ); + //l = SequenceLengthField; + } + // Bug_Philips_ItemTag_3F3F + // (0x2005, 0x1080): Because we do not handle fully the bug at the item + // level we need to check here too + else if ( SequenceLengthField == 444 && l == 3*71 ) + { + // This one is a double bug. Item length is wrong and impact SQ length + gdcmWarningMacro( "PMS: Super bad hack" ); + l = SequenceLengthField; + } +#endif + } + assert( l == SequenceLengthField ); + } + return is; + } + + template + std::ostream const &Write(std::ostream &os) const + { + typename ItemVector::const_iterator it = Items.begin(); + for(;it != Items.end(); ++it) + { + it->Write(os); + } + if( SequenceLengthField.IsUndefined() ) + { + // seq del item is not stored, write it ! + const Tag seqDelItem(0xfffe,0xe0dd); + seqDelItem.Write(os); + VL zero = 0; + zero.Write(os); + } + + return os; + } + +//protected: + void Print(std::ostream &os) const { + os << "\t(" << SequenceLengthField << ")\n"; + ItemVector::const_iterator it = + Items.begin(); + for(;it != Items.end(); ++it) + { + os << " " << *it; + } + if( SequenceLengthField.IsUndefined() ) + { + const Tag seqDelItem(0xfffe,0xe0dd); + VL zero = 0; + os << seqDelItem; + os << "\t" << zero; + } + } + + static SmartPointer New() + { + return new SequenceOfItems; + } + bool FindDataElement(const Tag &t) const; + + bool operator==(const Value &val) const + { + const SequenceOfItems &sqi = dynamic_cast(val); + return SequenceLengthField == sqi.SequenceLengthField && + Items == sqi.Items; + } + +private: +public: + /// \brief Total length of the Sequence (or 0xffffffff) if undefined + VL SequenceLengthField; + /// \brief Vector of Sequence Items + ItemVector Items; +}; + +} // end namespace gdcm + +#include "gdcmSequenceOfItems.txx" + +#endif //GDCMSEQUENCEOFITEMS_H diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmSequenceOfItems.txx b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmSequenceOfItems.txx new file mode 100644 index 0000000..66479f1 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmSequenceOfItems.txx @@ -0,0 +1,42 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMSEQUENCEOFITEMS_TXX +#define GDCMSEQUENCEOFITEMS_TXX + +namespace gdcm +{ + +template +VL SequenceOfItems::ComputeLength() const +{ + typename ItemVector::const_iterator it = Items.begin(); + VL length = 0; + for(;it != Items.end(); ++it) + { + length += it->template GetLength(); + } + if( SequenceLengthField.IsUndefined() ) + { + length += 8; // item end delimitor (tag + vl) + } + // For defined length SQ, make sure computation is correct (compare + // to original length) + //assert( SequenceLengthField.IsUndefined() + // || length == SequenceLengthField ); + return length; +} + +} // end namespace gdcm + +#endif // GDCMSEQUENCEOFITEMS_TXX diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmTag.cxx b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmTag.cxx new file mode 100644 index 0000000..b55879f --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmTag.cxx @@ -0,0 +1,91 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmTag.h" +#include "gdcmTrace.h" + +#include // sscanf + +namespace gdcm +{ + bool Tag::ReadFromCommaSeparatedString(const char *str) + { + unsigned int group = 0, element = 0; + if( !str || sscanf(str, "%04x,%04x", &group , &element) != 2 ) + { + gdcmDebugMacro( "Problem reading Tag: " << str ); + return false; + } + SetGroup( (uint16_t)group ); + SetElement( (uint16_t)element ); + return true; + } + bool Tag::ReadFromContinuousString(const char *str) + { + unsigned int group = 0, element = 0; + if( !str || sscanf(str, "%04x%04x", &group , &element) != 2 ) + { + gdcmDebugMacro( "Problem reading Tag: " << str ); + return false; + } + SetGroup( (uint16_t)group ); + SetElement( (uint16_t)element ); + return true; + } + bool Tag::ReadFromPipeSeparatedString(const char *str) + { + unsigned int group = 0, element = 0; + if( !str || sscanf(str, "%04x|%04x", &group , &element) != 2 ) + { + gdcmDebugMacro( "Problem reading Tag: " << str ); + return false; + } + SetGroup( (uint16_t)group ); + SetElement( (uint16_t)element ); + return true; + } + + std::string Tag::PrintAsContinuousString() const + { + std::ostringstream os; + const Tag &val = *this; + os.setf( std::ios::right); + os << std::hex << std::setw( 4 ) << std::setfill( '0' ) + << val[0] << std::setw( 4 ) << std::setfill( '0' ) + << val[1] << std::setfill( ' ' ) << std::dec; + return os.str(); + } + + std::string Tag::PrintAsContinuousUpperCaseString() const + { + std::ostringstream os; + const Tag &val = *this; + os.setf( std::ios::right); + os << std::uppercase << std::hex << std::setw( 4 ) << std::setfill( '0' ) + << val[0] << std::setw( 4 ) << std::setfill( '0' ) + << val[1] << std::setfill( ' ' ) << std::dec; + return os.str(); + } + + std::string Tag::PrintAsPipeSeparatedString() const + { + std::ostringstream _os; + const Tag &_val = *this; + _os.setf( std::ios::right); + _os << std::hex << std::setw( 4 ) << std::setfill( '0' ) + << _val[0] << '|' << std::setw( 4 ) << std::setfill( '0' ) + << _val[1] << std::setfill( ' ' ) << std::dec; + return _os.str(); + } + +} // end namespace gdcm diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmTag.h b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmTag.h new file mode 100644 index 0000000..4104090 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmTag.h @@ -0,0 +1,298 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMTAG_H +#define GDCMTAG_H + +#include "gdcmTypes.h" + +#include +#include + +namespace gdcm +{ + +/** + * \brief Class to represent a DICOM Data Element (Attribute) Tag (Group, Element). + * Basically an uint32_t which can also be expressed as two uint16_t (group and + * element) + * \note + * DATA ELEMENT TAG: + * A unique identifier for a Data Element composed of an ordered pair of + * numbers (a Group Number followed by an Element Number). GROUP NUMBER: The + * first number in the ordered pair of numbers that makes up a Data Element + * Tag. + * ELEMENT NUMBER: The second number in the ordered pair of numbers that + * makes up a Data Element Tag. + */ +class GDCM_EXPORT Tag +{ +public: + /// \brief Constructor with 2*uint16_t + Tag(uint16_t group, uint16_t element) { + ElementTag.tags[0] = group; ElementTag.tags[1] = element; + } + /// \brief Constructor with 1*uint32_t + /// Prefer the cstor that takes two uint16_t + Tag(uint32_t tag = 0) { + SetElementTag(tag); + } + + friend std::ostream& operator<<(std::ostream &_os, const Tag &_val); + friend std::istream& operator>>(std::istream &_is, Tag &_val); + + /// \brief Returns the 'Group number' of the given Tag + uint16_t GetGroup() const { return ElementTag.tags[0]; } + /// \brief Returns the 'Element number' of the given Tag + uint16_t GetElement() const { return ElementTag.tags[1]; } + /// \brief Sets the 'Group number' of the given Tag + void SetGroup(uint16_t group) { ElementTag.tags[0] = group; } + /// \brief Sets the 'Element number' of the given Tag + void SetElement(uint16_t element) { ElementTag.tags[1] = element; } + /// \brief Sets the 'Group number' & 'Element number' of the given Tag + void SetElementTag(uint16_t group, uint16_t element) { + ElementTag.tags[0] = group; ElementTag.tags[1] = element; + } + + /// \brief Returns the full tag value of the given Tag + uint32_t GetElementTag() const { +#ifndef GDCM_WORDS_BIGENDIAN + return (ElementTag.tag<<16) | (ElementTag.tag>>16); +#else + return ElementTag.tag; +#endif + } + + /// \brief Sets the full tag value of the given Tag + void SetElementTag(uint32_t tag) { +#ifndef GDCM_WORDS_BIGENDIAN + tag = ( (tag<<16) | (tag>>16) ); +#endif + ElementTag.tag = tag; + } + + /// Returns the Group or Element of the given Tag, depending on id (0/1) + const uint16_t &operator[](const unsigned int &_id) const + { + assert(_id<2); + return ElementTag.tags[_id]; + } + /// Returns the Group or Element of the given Tag, depending on id (0/1) + uint16_t &operator[](const unsigned int &_id) + { + assert(_id<2); + return ElementTag.tags[_id]; + } + + Tag &operator=(const Tag &_val) + { + ElementTag.tag = _val.ElementTag.tag; + return *this; + } + + bool operator==(const Tag &_val) const + { + return ElementTag.tag == _val.ElementTag.tag; + } + bool operator!=(const Tag &_val) const + { + return ElementTag.tag != _val.ElementTag.tag; + } + + /// DICOM Standard expects the Data Element to be sorted by Tags + /// All other comparison can be constructed from this one and operator == + // FIXME FIXME FIXME TODO + // the following is pretty dumb. Since we have control over who is group + // and who is element, we should reverse them in little endian and big endian case + // since what we really want is fast comparison and not garantee that group is in #0 + // ... + bool operator<(const Tag &_val) const + { +#ifndef GDCM_WORDS_BIGENDIAN + if( ElementTag.tags[0] < _val.ElementTag.tags[0] ) + return true; + if( ElementTag.tags[0] == _val.ElementTag.tags[0] + && ElementTag.tags[1] < _val.ElementTag.tags[1] ) + return true; + return false; +#else + // Plain comparison is enough! + return ( ElementTag.tag < _val.ElementTag.tag ); +#endif + } + bool operator<=(const Tag &t2) const + { + const Tag &t1 = *this; + return t1 == t2 || t1 < t2; + } + + Tag(const Tag &_val) + { + ElementTag.tag = _val.ElementTag.tag; + } + /// return the length of tag (read: size on disk) + uint32_t GetLength() const { return 4; } + + /// STANDARD DATA ELEMENT: A Data Element defined in the DICOM Standard, + /// and therefore listed in the DICOM Data Element Dictionary in PS 3.6. + /// Is the Tag from the Public dict...well the implementation is buggy + /// it does not prove the element is indeed in the dict... + bool IsPublic() const { return !(ElementTag.tags[0] % 2); } + + /// PRIVATE DATA ELEMENT: Additional Data Element, defined by an + /// implementor, to communicate information that is not contained in + /// Standard Data Elements. Private Data elements have odd Group Numbers. + bool IsPrivate() const { return !IsPublic(); } + + //----------------------------------------------------------------------------- + /// Read a tag from binary representation + template + std::istream &Read(std::istream &is) + { + if( is.read(ElementTag.bytes, 4) ) + TSwap::SwapArray(ElementTag.tags, 2); + return is; + } + + /// Write a tag in binary rep + template + const std::ostream &Write(std::ostream &os) const + { + uint16_t copy[2]; + copy[0]= ElementTag.tags[0]; + copy[1]= ElementTag.tags[1]; + TSwap::SwapArray(copy, 2); + return os.write((char*)(©), 4); + } + + /// Return the Private Creator Data Element tag of a private data element + Tag GetPrivateCreator() const + { + // See PS 3.5 - 7.8.1 PRIVATE DATA ELEMENT TAGS + // eg: 0x0123,0x1425 -> 0x0123,0x0014 + if( IsPrivate() && !IsPrivateCreator() ) + { + Tag r = *this; + r.SetElement( (uint16_t)(GetElement() >> 8) ); + return r; + } + if( IsPrivateCreator() ) return *this; + return Tag(0x0,0x0); + } + /// Set private creator: + void SetPrivateCreator(Tag const &t) + { + // See PS 3.5 - 7.8.1 PRIVATE DATA ELEMENT TAGS + // eg: 0x0123,0x0045 -> 0x0123,0x4567 + assert( t.IsPrivate() /*&& t.IsPrivateCreator()*/ ); + const uint16_t element = (uint16_t)(t.GetElement() << 8); + const uint16_t base = (uint16_t)(GetElement() << 8); + SetElement( (uint16_t)((base >> 8) + element) ); + SetGroup( t.GetGroup() ); + } + + /// Returns if tag is a Private Creator (xxxx,00yy), where xxxx is odd number + /// and yy in [0x10,0xFF] + bool IsPrivateCreator() const + { + return IsPrivate() && (GetElement() <= 0xFF && GetElement() >= 0x10); + } + + /// return if the tag is considered to be an illegal tag + bool IsIllegal() const + { + // DICOM reserved those groups: + return GetGroup() == 0x0001 || GetGroup() == 0x0003 || GetGroup() == 0x0005 || GetGroup() == 0x0007 + // This is a very special case, in private group, one cannot use element [0x01,0x09] ... +// || (IsPrivate() && !IsPrivateCreator() && !IsGroupLength()); + || (IsPrivate() && GetElement() > 0x0 && GetElement() < 0x10 ); + } + + /// return whether the tag correspond to a group length tag: + bool IsGroupLength() const + { + return GetElement() == 0x0; + } + + /// e.g 6002,3000 belong to groupXX: 6000,3000 + bool IsGroupXX(const Tag &t) const + { + if( t.GetElement() == GetElement() ) + { + if( t.IsPrivate() ) return false; + uint16_t group = (uint16_t)((GetGroup() >> 8 ) << 8); + return group == t.GetGroup(); + } + return false; + } + + /// Read from a comma separated string. + /// This is a highly user oriented function, the string should be formated as: + /// 1234,5678 to specify the tag (0x1234,0x5678) + /// The notation comes from the DICOM standard, and is handy to use from a + /// command line program + bool ReadFromCommaSeparatedString(const char *str); + + /// Read From XML formatted tag value eg. tag = "12345678" + /// It comes in useful when reading tag values from XML file(in NativeDICOMModel) + bool ReadFromContinuousString(const char *str); + + /// Print tag value with no separating comma: eg. tag = "12345678" + /// It comes in useful when reading tag values from XML file(in NativeDICOMModel) + std::string PrintAsContinuousString() const; + + /// Same as PrintAsContinuousString, but hexadecimal [a-f] are printed using upper case + std::string PrintAsContinuousUpperCaseString() const; + + /// Read from a pipe separated string (GDCM 1.x compat only). Do not use in newer code + /// \see ReadFromCommaSeparatedString + bool ReadFromPipeSeparatedString(const char *str); + + /// Print as a pipe separated string (GDCM 1.x compat only). Do not use in newer code + /// \see ReadFromPipeSeparatedString + std::string PrintAsPipeSeparatedString() const; + +private: + union { uint32_t tag; uint16_t tags[2]; char bytes[4]; } ElementTag; +}; +//----------------------------------------------------------------------------- +inline std::istream& operator>>(std::istream &_is, Tag &_val) +{ + char c; + _is >> c; + uint16_t a, b; + _is >> std::hex >> a; + //_is >> std::hex >> _val[0]; + //_is >> std::hex >> _val.ElementTag.tags[0]; + _is >> c; + //_is >> _val[1]; + //_is >> std::hex >> _val.ElementTag.tags[1]; + _is >> std::hex >> b; + _is >> c; + _val.SetGroup( a ); + _val.SetElement( b ); + return _is; +} + +inline std::ostream& operator<<(std::ostream &_os, const Tag &_val) +{ + _os.setf( std::ios::right); + _os << std::hex << '(' << std::setw( 4 ) << std::setfill( '0' ) + << _val[0] << ',' << std::setw( 4 ) << std::setfill( '0' ) + << _val[1] << ')' << std::setfill( ' ' ) << std::dec; + return _os; +} + +} // end namespace gdcm + +#endif //GDCMTAG_H diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmTagToVR.cxx b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmTagToVR.cxx new file mode 100644 index 0000000..57085b1 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmTagToVR.cxx @@ -0,0 +1,3653 @@ + +// GENERATED FILE DO NOT EDIT +// $ xsltproc TagToVR.xsl Part6.xml > gdcmTagToVR.cxx + +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmVR.h" +#include "gdcmVM.h" +#include "gdcmStaticAssert.h" + +namespace gdcm { +VR::VRType GetVRFromTag( Tag const & t ) { +if( t.IsGroupLength() ) return VR::UL; +uint32_t tag = t.GetElementTag(); +switch( tag ) { +case 0x00000000:return VR::UL; +case 0x00000001:return VR::UL; +case 0x00000002:return VR::UI; +case 0x00000003:return VR::UI; +case 0x00000010:return VR::SH; +case 0x00000100:return VR::US; +case 0x00000110:return VR::US; +case 0x00000120:return VR::US; +case 0x00000200:return VR::AE; +case 0x00000300:return VR::AE; +case 0x00000400:return VR::AE; +case 0x00000600:return VR::AE; +case 0x00000700:return VR::US; +case 0x00000800:return VR::US; +case 0x00000850:return VR::US; +case 0x00000860:return VR::US; +case 0x00000900:return VR::US; +case 0x00000901:return VR::AT; +case 0x00000902:return VR::LO; +case 0x00000903:return VR::US; +case 0x00001000:return VR::UI; +case 0x00001001:return VR::UI; +case 0x00001002:return VR::US; +case 0x00001005:return VR::AT; +case 0x00001008:return VR::US; +case 0x00001020:return VR::US; +case 0x00001021:return VR::US; +case 0x00001022:return VR::US; +case 0x00001023:return VR::US; +case 0x00001030:return VR::AE; +case 0x00001031:return VR::US; +case 0x00004000:return VR::LT; +case 0x00004010:return VR::LT; +case 0x00005010:return VR::SH; +case 0x00005020:return VR::SH; +case 0x00005110:return VR::LT; +case 0x00005120:return VR::LT; +case 0x00005130:return VR::CS; +case 0x00005140:return VR::CS; +case 0x00005150:return VR::CS; +case 0x00005160:return VR::CS; +case 0x00005170:return VR::IS; +case 0x00005180:return VR::CS; +case 0x00005190:return VR::CS; +case 0x000051a0:return VR::CS; +case 0x000051b0:return VR::US; +case 0x00020000:return VR::UL; +case 0x00020001:return VR::OB; +case 0x00020002:return VR::UI; +case 0x00020003:return VR::UI; +case 0x00020010:return VR::UI; +case 0x00020012:return VR::UI; +case 0x00020013:return VR::SH; +case 0x00020016:return VR::AE; +case 0x00020100:return VR::UI; +case 0x00020102:return VR::OB; +case 0x00041130:return VR::CS; +case 0x00041141:return VR::CS; +case 0x00041142:return VR::CS; +case 0x00041200:return VR::UL; +case 0x00041202:return VR::UL; +case 0x00041212:return VR::US; +case 0x00041220:return VR::SQ; +case 0x00041400:return VR::UL; +case 0x00041410:return VR::US; +case 0x00041420:return VR::UL; +case 0x00041430:return VR::CS; +case 0x00041432:return VR::UI; +case 0x00041500:return VR::CS; +case 0x00041504:return VR::UL; +case 0x00041510:return VR::UI; +case 0x00041511:return VR::UI; +case 0x00041512:return VR::UI; +case 0x0004151a:return VR::UI; +case 0x00041600:return VR::UL; +case 0x00080001:return VR::UL; +case 0x00080005:return VR::CS; +case 0x00080006:return VR::SQ; +case 0x00080008:return VR::CS; +case 0x00080010:return VR::SH; +case 0x00080012:return VR::DA; +case 0x00080013:return VR::TM; +case 0x00080014:return VR::UI; +case 0x00080016:return VR::UI; +case 0x00080018:return VR::UI; +case 0x0008001a:return VR::UI; +case 0x0008001b:return VR::UI; +case 0x00080020:return VR::DA; +case 0x00080021:return VR::DA; +case 0x00080022:return VR::DA; +case 0x00080023:return VR::DA; +case 0x00080024:return VR::DA; +case 0x00080025:return VR::DA; +case 0x0008002a:return VR::DT; +case 0x00080030:return VR::TM; +case 0x00080031:return VR::TM; +case 0x00080032:return VR::TM; +case 0x00080033:return VR::TM; +case 0x00080034:return VR::TM; +case 0x00080035:return VR::TM; +case 0x00080040:return VR::US; +case 0x00080041:return VR::LO; +case 0x00080042:return VR::CS; +case 0x00080050:return VR::SH; +case 0x00080051:return VR::SQ; +case 0x00080052:return VR::CS; +case 0x00080054:return VR::AE; +case 0x00080056:return VR::CS; +case 0x00080058:return VR::UI; +case 0x00080060:return VR::CS; +case 0x00080061:return VR::CS; +case 0x00080062:return VR::UI; +case 0x00080064:return VR::CS; +case 0x00080068:return VR::CS; +case 0x00080070:return VR::LO; +case 0x00080080:return VR::LO; +case 0x00080081:return VR::ST; +case 0x00080082:return VR::SQ; +case 0x00080090:return VR::PN; +case 0x00080092:return VR::ST; +case 0x00080094:return VR::SH; +case 0x00080096:return VR::SQ; +case 0x00080100:return VR::SH; +case 0x00080102:return VR::SH; +case 0x00080103:return VR::SH; +case 0x00080104:return VR::LO; +case 0x00080105:return VR::CS; +case 0x00080106:return VR::DT; +case 0x00080107:return VR::DT; +case 0x0008010b:return VR::CS; +case 0x0008010c:return VR::UI; +case 0x0008010d:return VR::UI; +case 0x0008010f:return VR::CS; +case 0x00080110:return VR::SQ; +case 0x00080112:return VR::LO; +case 0x00080114:return VR::ST; +case 0x00080115:return VR::ST; +case 0x00080116:return VR::ST; +case 0x00080117:return VR::UI; +case 0x00080201:return VR::SH; +case 0x00081000:return VR::AE; +case 0x00081010:return VR::SH; +case 0x00081030:return VR::LO; +case 0x00081032:return VR::SQ; +case 0x0008103e:return VR::LO; +case 0x0008103f:return VR::SQ; +case 0x00081040:return VR::LO; +case 0x00081048:return VR::PN; +case 0x00081049:return VR::SQ; +case 0x00081050:return VR::PN; +case 0x00081052:return VR::SQ; +case 0x00081060:return VR::PN; +case 0x00081062:return VR::SQ; +case 0x00081070:return VR::PN; +case 0x00081072:return VR::SQ; +case 0x00081080:return VR::LO; +case 0x00081084:return VR::SQ; +case 0x00081090:return VR::LO; +case 0x00081100:return VR::SQ; +case 0x00081110:return VR::SQ; +case 0x00081111:return VR::SQ; +case 0x00081115:return VR::SQ; +case 0x00081120:return VR::SQ; +case 0x00081125:return VR::SQ; +case 0x00081130:return VR::SQ; +case 0x00081134:return VR::SQ; +case 0x0008113a:return VR::SQ; +case 0x00081140:return VR::SQ; +case 0x00081145:return VR::SQ; +case 0x0008114a:return VR::SQ; +case 0x0008114b:return VR::SQ; +case 0x00081150:return VR::UI; +case 0x00081155:return VR::UI; +case 0x0008115a:return VR::UI; +case 0x00081160:return VR::IS; +case 0x00081161:return VR::UL; +case 0x00081162:return VR::UL; +case 0x00081163:return VR::FD; +case 0x00081164:return VR::SQ; +case 0x00081167:return VR::UI; +case 0x00081195:return VR::UI; +case 0x00081197:return VR::US; +case 0x00081198:return VR::SQ; +case 0x00081199:return VR::SQ; +case 0x00081200:return VR::SQ; +case 0x00081250:return VR::SQ; +case 0x00082110:return VR::CS; +case 0x00082111:return VR::ST; +case 0x00082112:return VR::SQ; +case 0x00082120:return VR::SH; +case 0x00082122:return VR::IS; +case 0x00082124:return VR::IS; +case 0x00082127:return VR::SH; +case 0x00082128:return VR::IS; +case 0x00082129:return VR::IS; +case 0x0008212a:return VR::IS; +case 0x00082130:return VR::DS; +case 0x00082132:return VR::LO; +case 0x00082133:return VR::SQ; +case 0x00082134:return VR::FD; +case 0x00082135:return VR::SQ; +case 0x00082142:return VR::IS; +case 0x00082143:return VR::IS; +case 0x00082144:return VR::IS; +case 0x00082200:return VR::CS; +case 0x00082204:return VR::CS; +case 0x00082208:return VR::CS; +case 0x00082218:return VR::SQ; +case 0x00082220:return VR::SQ; +case 0x00082228:return VR::SQ; +case 0x00082229:return VR::SQ; +case 0x00082230:return VR::SQ; +case 0x00082240:return VR::SQ; +case 0x00082242:return VR::SQ; +case 0x00082244:return VR::SQ; +case 0x00082246:return VR::SQ; +case 0x00082251:return VR::SQ; +case 0x00082253:return VR::SQ; +case 0x00082255:return VR::SQ; +case 0x00082256:return VR::ST; +case 0x00082257:return VR::SQ; +case 0x00082258:return VR::ST; +case 0x00082259:return VR::SQ; +case 0x0008225a:return VR::SQ; +case 0x0008225c:return VR::SQ; +case 0x00083001:return VR::SQ; +case 0x00083010:return VR::UI; +case 0x00084000:return VR::LT; +case 0x00089007:return VR::CS; +case 0x00089092:return VR::SQ; +case 0x00089121:return VR::SQ; +case 0x00089123:return VR::UI; +case 0x00089124:return VR::SQ; +case 0x00089154:return VR::SQ; +case 0x00089205:return VR::CS; +case 0x00089206:return VR::CS; +case 0x00089207:return VR::CS; +case 0x00089208:return VR::CS; +case 0x00089209:return VR::CS; +case 0x00089215:return VR::SQ; +case 0x00089237:return VR::SQ; +case 0x00089410:return VR::SQ; +case 0x00089458:return VR::SQ; +case 0x00089459:return VR::FL; +case 0x00089460:return VR::CS; +case 0x00100010:return VR::PN; +case 0x00100020:return VR::LO; +case 0x00100021:return VR::LO; +case 0x00100022:return VR::CS; +case 0x00100024:return VR::SQ; +case 0x00100030:return VR::DA; +case 0x00100032:return VR::TM; +case 0x00100040:return VR::CS; +case 0x00100050:return VR::SQ; +case 0x00100101:return VR::SQ; +case 0x00100102:return VR::SQ; +case 0x00101000:return VR::LO; +case 0x00101001:return VR::PN; +case 0x00101002:return VR::SQ; +case 0x00101005:return VR::PN; +case 0x00101010:return VR::AS; +case 0x00101020:return VR::DS; +case 0x00101021:return VR::SQ; +case 0x00101030:return VR::DS; +case 0x00101040:return VR::LO; +case 0x00101050:return VR::LO; +case 0x00101060:return VR::PN; +case 0x00101080:return VR::LO; +case 0x00101081:return VR::LO; +case 0x00101090:return VR::LO; +case 0x00102000:return VR::LO; +case 0x00102110:return VR::LO; +case 0x00102150:return VR::LO; +case 0x00102152:return VR::LO; +case 0x00102154:return VR::SH; +case 0x00102160:return VR::SH; +case 0x00102180:return VR::SH; +case 0x001021a0:return VR::CS; +case 0x001021b0:return VR::LT; +case 0x001021c0:return VR::US; +case 0x001021d0:return VR::DA; +case 0x001021f0:return VR::LO; +case 0x00102201:return VR::LO; +case 0x00102202:return VR::SQ; +case 0x00102203:return VR::CS; +case 0x00102210:return VR::CS; +case 0x00102292:return VR::LO; +case 0x00102293:return VR::SQ; +case 0x00102294:return VR::SQ; +case 0x00102295:return VR::LO; +case 0x00102296:return VR::SQ; +case 0x00102297:return VR::PN; +case 0x00102298:return VR::CS; +case 0x00102299:return VR::LO; +case 0x00104000:return VR::LT; +case 0x00109431:return VR::FL; +case 0x00120010:return VR::LO; +case 0x00120020:return VR::LO; +case 0x00120021:return VR::LO; +case 0x00120030:return VR::LO; +case 0x00120031:return VR::LO; +case 0x00120040:return VR::LO; +case 0x00120042:return VR::LO; +case 0x00120050:return VR::LO; +case 0x00120051:return VR::ST; +case 0x00120060:return VR::LO; +case 0x00120062:return VR::CS; +case 0x00120063:return VR::LO; +case 0x00120064:return VR::SQ; +case 0x00120071:return VR::LO; +case 0x00120072:return VR::LO; +case 0x00120081:return VR::LO; +case 0x00120082:return VR::LO; +case 0x00120083:return VR::SQ; +case 0x00120084:return VR::CS; +case 0x00120085:return VR::CS; +case 0x00140023:return VR::ST; +case 0x00140024:return VR::ST; +case 0x00140025:return VR::ST; +case 0x00140028:return VR::ST; +case 0x00140030:return VR::DS; +case 0x00140032:return VR::DS; +case 0x00140034:return VR::DS; +case 0x00140042:return VR::ST; +case 0x00140044:return VR::ST; +case 0x00140045:return VR::ST; +case 0x00140046:return VR::LT; +case 0x00140050:return VR::CS; +case 0x00140052:return VR::CS; +case 0x00140054:return VR::DS; +case 0x00140056:return VR::DS; +case 0x00141010:return VR::ST; +case 0x00141020:return VR::DA; +case 0x00141040:return VR::ST; +case 0x00142002:return VR::SQ; +case 0x00142004:return VR::IS; +case 0x00142006:return VR::PN; +case 0x00142008:return VR::IS; +case 0x00142012:return VR::SQ; +case 0x00142014:return VR::IS; +case 0x00142016:return VR::SH; +case 0x00142018:return VR::ST; +case 0x0014201a:return VR::CS; +case 0x0014201c:return VR::CS; +case 0x0014201e:return VR::SQ; +case 0x00142030:return VR::SQ; +case 0x00142032:return VR::SH; +case 0x00142202:return VR::IS; +case 0x00142204:return VR::SQ; +case 0x00142206:return VR::ST; +case 0x00142208:return VR::CS; +case 0x0014220a:return VR::IS; +case 0x0014220c:return VR::CS; +case 0x0014220e:return VR::CS; +case 0x00142210:return VR::OB; +case 0x00142220:return VR::SQ; +case 0x00142222:return VR::ST; +case 0x00142224:return VR::IS; +case 0x00142226:return VR::IS; +case 0x00142228:return VR::CS; +case 0x0014222a:return VR::DS; +case 0x0014222c:return VR::DS; +case 0x00143011:return VR::DS; +case 0x00143012:return VR::DS; +case 0x00143020:return VR::SQ; +case 0x00143022:return VR::ST; +case 0x00143024:return VR::DS; +case 0x00143026:return VR::DS; +case 0x00143028:return VR::DS; +case 0x00143040:return VR::SQ; +case 0x00143060:return VR::SQ; +case 0x00143071:return VR::DS; +case 0x00143072:return VR::DS; +case 0x00143073:return VR::DS; +case 0x00143074:return VR::LO; +case 0x00143075:return VR::DS; +case 0x00143076:return VR::DA; +case 0x00143077:return VR::TM; +case 0x00143080:return VR::OB; +case 0x00143099:return VR::LT; +case 0x00144002:return VR::SQ; +case 0x00144004:return VR::CS; +case 0x00144006:return VR::LT; +case 0x00144008:return VR::SQ; +case 0x0014400a:return VR::CS; +case 0x0014400c:return VR::LT; +case 0x0014400e:return VR::SQ; +case 0x0014400f:return VR::LT; +case 0x00144010:return VR::SQ; +case 0x00144011:return VR::SQ; +case 0x00144012:return VR::US; +case 0x00144013:return VR::CS; +case 0x00144014:return VR::DS; +case 0x00144015:return VR::DS; +case 0x00144016:return VR::DS; +case 0x00144017:return VR::DS; +case 0x00144018:return VR::DS; +case 0x00144019:return VR::DS; +case 0x0014401a:return VR::DS; +case 0x0014401b:return VR::DS; +case 0x0014401c:return VR::DS; +case 0x00144020:return VR::SQ; +case 0x00144022:return VR::DS; +case 0x00144024:return VR::DS; +case 0x00144026:return VR::CS; +case 0x00144028:return VR::DS; +case 0x00144030:return VR::SQ; +case 0x00144031:return VR::DS; +case 0x00144032:return VR::CS; +case 0x00144033:return VR::IS; +case 0x00144034:return VR::DS; +case 0x00144035:return VR::SQ; +case 0x00144036:return VR::CS; +case 0x00144038:return VR::DS; +case 0x0014403a:return VR::DS; +case 0x0014403c:return VR::DS; +case 0x00144040:return VR::SQ; +case 0x00144050:return VR::SQ; +case 0x00144051:return VR::SQ; +case 0x00144052:return VR::DS; +case 0x00144054:return VR::ST; +case 0x00144056:return VR::ST; +case 0x00144057:return VR::DS; +case 0x00144058:return VR::DS; +case 0x00144059:return VR::DS; +case 0x0014405a:return VR::DS; +case 0x0014405c:return VR::ST; +case 0x00144060:return VR::SQ; +case 0x00144062:return VR::DS; +case 0x00144064:return VR::DS; +case 0x00144070:return VR::SQ; +case 0x00144072:return VR::ST; +case 0x00144074:return VR::SH; +case 0x00144076:return VR::DA; +case 0x00144078:return VR::DA; +case 0x0014407a:return VR::DA; +case 0x0014407c:return VR::TM; +case 0x0014407e:return VR::DA; +case 0x00145002:return VR::IS; +case 0x00145004:return VR::IS; +case 0x00180010:return VR::LO; +case 0x00180012:return VR::SQ; +case 0x00180014:return VR::SQ; +case 0x00180015:return VR::CS; +case 0x00180020:return VR::CS; +case 0x00180021:return VR::CS; +case 0x00180022:return VR::CS; +case 0x00180023:return VR::CS; +case 0x00180024:return VR::SH; +case 0x00180025:return VR::CS; +case 0x00180026:return VR::SQ; +case 0x00180027:return VR::TM; +case 0x00180028:return VR::DS; +case 0x00180029:return VR::SQ; +case 0x0018002a:return VR::SQ; +case 0x00180030:return VR::LO; +case 0x00180031:return VR::LO; +case 0x00180032:return VR::DS; +case 0x00180033:return VR::DS; +case 0x00180034:return VR::LO; +case 0x00180035:return VR::TM; +case 0x00180036:return VR::SQ; +case 0x00180037:return VR::CS; +case 0x00180038:return VR::CS; +case 0x00180039:return VR::CS; +case 0x0018003a:return VR::ST; +case 0x00180040:return VR::IS; +case 0x00180042:return VR::CS; +case 0x00180050:return VR::DS; +case 0x00180060:return VR::DS; +case 0x00180070:return VR::IS; +case 0x00180071:return VR::CS; +case 0x00180072:return VR::DS; +case 0x00180073:return VR::CS; +case 0x00180074:return VR::IS; +case 0x00180075:return VR::IS; +case 0x00180080:return VR::DS; +case 0x00180081:return VR::DS; +case 0x00180082:return VR::DS; +case 0x00180083:return VR::DS; +case 0x00180084:return VR::DS; +case 0x00180085:return VR::SH; +case 0x00180086:return VR::IS; +case 0x00180087:return VR::DS; +case 0x00180088:return VR::DS; +case 0x00180089:return VR::IS; +case 0x00180090:return VR::DS; +case 0x00180091:return VR::IS; +case 0x00180093:return VR::DS; +case 0x00180094:return VR::DS; +case 0x00180095:return VR::DS; +case 0x00181000:return VR::LO; +case 0x00181002:return VR::UI; +case 0x00181003:return VR::LO; +case 0x00181004:return VR::LO; +case 0x00181005:return VR::LO; +case 0x00181006:return VR::LO; +case 0x00181007:return VR::LO; +case 0x00181008:return VR::LO; +case 0x00181010:return VR::LO; +case 0x00181011:return VR::LO; +case 0x00181012:return VR::DA; +case 0x00181014:return VR::TM; +case 0x00181016:return VR::LO; +case 0x00181017:return VR::LO; +case 0x00181018:return VR::LO; +case 0x00181019:return VR::LO; +case 0x0018101a:return VR::LO; +case 0x0018101b:return VR::LO; +case 0x00181020:return VR::LO; +case 0x00181022:return VR::SH; +case 0x00181023:return VR::LO; +case 0x00181030:return VR::LO; +case 0x00181040:return VR::LO; +case 0x00181041:return VR::DS; +case 0x00181042:return VR::TM; +case 0x00181043:return VR::TM; +case 0x00181044:return VR::DS; +case 0x00181045:return VR::IS; +case 0x00181046:return VR::DS; +case 0x00181047:return VR::DS; +case 0x00181048:return VR::CS; +case 0x00181049:return VR::DS; +case 0x00181050:return VR::DS; +case 0x00181060:return VR::DS; +case 0x00181061:return VR::LO; +case 0x00181062:return VR::IS; +case 0x00181063:return VR::DS; +case 0x00181064:return VR::LO; +case 0x00181065:return VR::DS; +case 0x00181066:return VR::DS; +case 0x00181067:return VR::DS; +case 0x00181068:return VR::DS; +case 0x00181069:return VR::DS; +case 0x0018106a:return VR::CS; +case 0x0018106c:return VR::US; +case 0x0018106e:return VR::UL; +case 0x00181070:return VR::LO; +case 0x00181071:return VR::DS; +case 0x00181072:return VR::TM; +case 0x00181073:return VR::TM; +case 0x00181074:return VR::DS; +case 0x00181075:return VR::DS; +case 0x00181076:return VR::DS; +case 0x00181077:return VR::DS; +case 0x00181078:return VR::DT; +case 0x00181079:return VR::DT; +case 0x00181080:return VR::CS; +case 0x00181081:return VR::IS; +case 0x00181082:return VR::IS; +case 0x00181083:return VR::IS; +case 0x00181084:return VR::IS; +case 0x00181085:return VR::LO; +case 0x00181086:return VR::IS; +case 0x00181088:return VR::IS; +case 0x00181090:return VR::IS; +case 0x00181094:return VR::IS; +case 0x00181100:return VR::DS; +case 0x00181110:return VR::DS; +case 0x00181111:return VR::DS; +case 0x00181114:return VR::DS; +case 0x00181120:return VR::DS; +case 0x00181121:return VR::DS; +case 0x00181130:return VR::DS; +case 0x00181131:return VR::DS; +case 0x00181134:return VR::CS; +case 0x00181135:return VR::DS; +case 0x00181136:return VR::DS; +case 0x00181137:return VR::DS; +case 0x00181138:return VR::DS; +case 0x0018113a:return VR::CS; +case 0x00181140:return VR::CS; +case 0x00181141:return VR::DS; +case 0x00181142:return VR::DS; +case 0x00181143:return VR::DS; +case 0x00181144:return VR::DS; +case 0x00181145:return VR::DS; +case 0x00181146:return VR::DS; +case 0x00181147:return VR::CS; +case 0x00181149:return VR::IS; +case 0x00181150:return VR::IS; +case 0x00181151:return VR::IS; +case 0x00181152:return VR::IS; +case 0x00181153:return VR::IS; +case 0x00181154:return VR::DS; +case 0x00181155:return VR::CS; +case 0x00181156:return VR::CS; +case 0x0018115a:return VR::CS; +case 0x0018115e:return VR::DS; +case 0x00181160:return VR::SH; +case 0x00181161:return VR::LO; +case 0x00181162:return VR::DS; +case 0x00181164:return VR::DS; +case 0x00181166:return VR::CS; +case 0x00181170:return VR::IS; +case 0x00181180:return VR::SH; +case 0x00181181:return VR::CS; +case 0x00181182:return VR::IS; +case 0x00181183:return VR::DS; +case 0x00181184:return VR::DS; +case 0x00181190:return VR::DS; +case 0x00181191:return VR::CS; +case 0x001811a0:return VR::DS; +case 0x001811a2:return VR::DS; +case 0x00181200:return VR::DA; +case 0x00181201:return VR::TM; +case 0x00181210:return VR::SH; +case 0x00181240:return VR::IS; +case 0x00181242:return VR::IS; +case 0x00181243:return VR::IS; +case 0x00181244:return VR::US; +case 0x00181250:return VR::SH; +case 0x00181251:return VR::SH; +case 0x00181260:return VR::SH; +case 0x00181261:return VR::LO; +case 0x00181300:return VR::DS; +case 0x00181301:return VR::CS; +case 0x00181302:return VR::IS; +case 0x00181310:return VR::US; +case 0x00181312:return VR::CS; +case 0x00181314:return VR::DS; +case 0x00181315:return VR::CS; +case 0x00181316:return VR::DS; +case 0x00181318:return VR::DS; +case 0x00181400:return VR::LO; +case 0x00181401:return VR::LO; +case 0x00181402:return VR::CS; +case 0x00181403:return VR::CS; +case 0x00181404:return VR::US; +case 0x00181405:return VR::IS; +case 0x00181411:return VR::DS; +case 0x00181412:return VR::DS; +case 0x00181413:return VR::DS; +case 0x00181450:return VR::DS; +case 0x00181460:return VR::DS; +case 0x00181470:return VR::DS; +case 0x00181480:return VR::DS; +case 0x00181490:return VR::CS; +case 0x00181491:return VR::CS; +case 0x00181495:return VR::IS; +case 0x00181500:return VR::CS; +case 0x00181508:return VR::CS; +case 0x00181510:return VR::DS; +case 0x00181511:return VR::DS; +case 0x00181520:return VR::DS; +case 0x00181521:return VR::DS; +case 0x00181530:return VR::DS; +case 0x00181531:return VR::DS; +case 0x00181600:return VR::CS; +case 0x00181602:return VR::IS; +case 0x00181604:return VR::IS; +case 0x00181606:return VR::IS; +case 0x00181608:return VR::IS; +case 0x00181610:return VR::IS; +case 0x00181612:return VR::IS; +case 0x00181620:return VR::IS; +case 0x00181622:return VR::US; +case 0x00181623:return VR::US; +case 0x00181624:return VR::US; +case 0x00181700:return VR::CS; +case 0x00181702:return VR::IS; +case 0x00181704:return VR::IS; +case 0x00181706:return VR::IS; +case 0x00181708:return VR::IS; +case 0x00181710:return VR::IS; +case 0x00181712:return VR::IS; +case 0x00181720:return VR::IS; +case 0x00181800:return VR::CS; +case 0x00181801:return VR::SH; +case 0x00181802:return VR::CS; +case 0x00181803:return VR::LO; +case 0x00182001:return VR::IS; +case 0x00182002:return VR::SH; +case 0x00182003:return VR::DS; +case 0x00182004:return VR::DS; +case 0x00182005:return VR::DS; +case 0x00182006:return VR::SH; +case 0x00182010:return VR::DS; +case 0x00182020:return VR::CS; +case 0x00182030:return VR::DS; +case 0x00183100:return VR::CS; +case 0x00183101:return VR::DS; +case 0x00183102:return VR::DS; +case 0x00183103:return VR::IS; +case 0x00183104:return VR::IS; +case 0x00183105:return VR::IS; +case 0x00184000:return VR::LT; +case 0x00185000:return VR::SH; +case 0x00185010:return VR::LO; +case 0x00185012:return VR::DS; +case 0x00185020:return VR::LO; +case 0x00185021:return VR::LO; +case 0x00185022:return VR::DS; +case 0x00185024:return VR::DS; +case 0x00185026:return VR::DS; +case 0x00185027:return VR::DS; +case 0x00185028:return VR::DS; +case 0x00185029:return VR::DS; +case 0x00185030:return VR::DS; +case 0x00185040:return VR::DS; +case 0x00185050:return VR::IS; +case 0x00185100:return VR::CS; +case 0x00185101:return VR::CS; +case 0x00185104:return VR::SQ; +case 0x00185210:return VR::DS; +case 0x00185212:return VR::DS; +case 0x00186000:return VR::DS; +case 0x00186011:return VR::SQ; +case 0x00186012:return VR::US; +case 0x00186014:return VR::US; +case 0x00186016:return VR::UL; +case 0x00186018:return VR::UL; +case 0x0018601a:return VR::UL; +case 0x0018601c:return VR::UL; +case 0x0018601e:return VR::UL; +case 0x00186020:return VR::SL; +case 0x00186022:return VR::SL; +case 0x00186024:return VR::US; +case 0x00186026:return VR::US; +case 0x00186028:return VR::FD; +case 0x0018602a:return VR::FD; +case 0x0018602c:return VR::FD; +case 0x0018602e:return VR::FD; +case 0x00186030:return VR::UL; +case 0x00186031:return VR::CS; +case 0x00186032:return VR::UL; +case 0x00186034:return VR::FD; +case 0x00186036:return VR::FD; +case 0x00186038:return VR::UL; +case 0x00186039:return VR::SL; +case 0x0018603a:return VR::UL; +case 0x0018603b:return VR::SL; +case 0x0018603c:return VR::UL; +case 0x0018603d:return VR::SL; +case 0x0018603e:return VR::UL; +case 0x0018603f:return VR::SL; +case 0x00186040:return VR::UL; +case 0x00186041:return VR::SL; +case 0x00186042:return VR::UL; +case 0x00186043:return VR::SL; +case 0x00186044:return VR::US; +case 0x00186046:return VR::UL; +case 0x00186048:return VR::UL; +case 0x0018604a:return VR::UL; +case 0x0018604c:return VR::US; +case 0x0018604e:return VR::US; +case 0x00186050:return VR::UL; +case 0x00186052:return VR::UL; +case 0x00186054:return VR::FD; +case 0x00186056:return VR::UL; +case 0x00186058:return VR::UL; +case 0x0018605a:return VR::FL; +case 0x00186060:return VR::FL; +case 0x00187000:return VR::CS; +case 0x00187001:return VR::DS; +case 0x00187004:return VR::CS; +case 0x00187005:return VR::CS; +case 0x00187006:return VR::LT; +case 0x00187008:return VR::LT; +case 0x0018700a:return VR::SH; +case 0x0018700c:return VR::DA; +case 0x0018700e:return VR::TM; +case 0x00187010:return VR::IS; +case 0x00187011:return VR::IS; +case 0x00187012:return VR::DS; +case 0x00187014:return VR::DS; +case 0x00187016:return VR::DS; +case 0x0018701a:return VR::DS; +case 0x00187020:return VR::DS; +case 0x00187022:return VR::DS; +case 0x00187024:return VR::CS; +case 0x00187026:return VR::DS; +case 0x00187028:return VR::DS; +case 0x0018702a:return VR::LO; +case 0x0018702b:return VR::LO; +case 0x00187030:return VR::DS; +case 0x00187032:return VR::DS; +case 0x00187034:return VR::CS; +case 0x00187036:return VR::FL; +case 0x00187038:return VR::FL; +case 0x00187040:return VR::LT; +case 0x00187041:return VR::LT; +case 0x00187042:return VR::DS; +case 0x00187044:return VR::DS; +case 0x00187046:return VR::IS; +case 0x00187048:return VR::DS; +case 0x0018704c:return VR::DS; +case 0x00187050:return VR::CS; +case 0x00187052:return VR::DS; +case 0x00187054:return VR::DS; +case 0x00187056:return VR::FL; +case 0x00187058:return VR::FL; +case 0x00187060:return VR::CS; +case 0x00187062:return VR::LT; +case 0x00187064:return VR::CS; +case 0x00187065:return VR::DS; +case 0x00188150:return VR::DS; +case 0x00188151:return VR::DS; +case 0x00189004:return VR::CS; +case 0x00189005:return VR::SH; +case 0x00189006:return VR::SQ; +case 0x00189008:return VR::CS; +case 0x00189009:return VR::CS; +case 0x00189010:return VR::CS; +case 0x00189011:return VR::CS; +case 0x00189012:return VR::CS; +case 0x00189014:return VR::CS; +case 0x00189015:return VR::CS; +case 0x00189016:return VR::CS; +case 0x00189017:return VR::CS; +case 0x00189018:return VR::CS; +case 0x00189019:return VR::FD; +case 0x00189020:return VR::CS; +case 0x00189021:return VR::CS; +case 0x00189022:return VR::CS; +case 0x00189024:return VR::CS; +case 0x00189025:return VR::CS; +case 0x00189026:return VR::CS; +case 0x00189027:return VR::CS; +case 0x00189028:return VR::CS; +case 0x00189029:return VR::CS; +case 0x00189030:return VR::FD; +case 0x00189032:return VR::CS; +case 0x00189033:return VR::CS; +case 0x00189034:return VR::CS; +case 0x00189035:return VR::FD; +case 0x00189036:return VR::CS; +case 0x00189037:return VR::CS; +case 0x00189041:return VR::LO; +case 0x00189042:return VR::SQ; +case 0x00189043:return VR::CS; +case 0x00189044:return VR::CS; +case 0x00189045:return VR::SQ; +case 0x00189046:return VR::LO; +case 0x00189047:return VR::SH; +case 0x00189048:return VR::CS; +case 0x00189049:return VR::SQ; +case 0x00189050:return VR::LO; +case 0x00189051:return VR::CS; +case 0x00189052:return VR::FD; +case 0x00189053:return VR::FD; +case 0x00189054:return VR::CS; +case 0x00189058:return VR::US; +case 0x00189059:return VR::CS; +case 0x00189060:return VR::CS; +case 0x00189061:return VR::FD; +case 0x00189062:return VR::CS; +case 0x00189063:return VR::FD; +case 0x00189064:return VR::CS; +case 0x00189065:return VR::CS; +case 0x00189066:return VR::US; +case 0x00189067:return VR::CS; +case 0x00189069:return VR::FD; +case 0x00189070:return VR::FD; +case 0x00189073:return VR::FD; +case 0x00189074:return VR::DT; +case 0x00189075:return VR::CS; +case 0x00189076:return VR::SQ; +case 0x00189077:return VR::CS; +case 0x00189078:return VR::CS; +case 0x00189079:return VR::FD; +case 0x00189080:return VR::ST; +case 0x00189081:return VR::CS; +case 0x00189082:return VR::FD; +case 0x00189083:return VR::SQ; +case 0x00189084:return VR::SQ; +case 0x00189085:return VR::CS; +case 0x00189087:return VR::FD; +case 0x00189089:return VR::FD; +case 0x00189090:return VR::FD; +case 0x00189091:return VR::FD; +case 0x00189092:return VR::SQ; +case 0x00189093:return VR::US; +case 0x00189094:return VR::CS; +case 0x00189095:return VR::UL; +case 0x00189096:return VR::FD; +case 0x00189098:return VR::FD; +case 0x00189100:return VR::CS; +case 0x00189101:return VR::CS; +case 0x00189103:return VR::SQ; +case 0x00189104:return VR::FD; +case 0x00189105:return VR::FD; +case 0x00189106:return VR::FD; +case 0x00189107:return VR::SQ; +case 0x00189112:return VR::SQ; +case 0x00189114:return VR::SQ; +case 0x00189115:return VR::SQ; +case 0x00189117:return VR::SQ; +case 0x00189118:return VR::SQ; +case 0x00189119:return VR::SQ; +case 0x00189125:return VR::SQ; +case 0x00189126:return VR::SQ; +case 0x00189127:return VR::UL; +case 0x00189147:return VR::CS; +case 0x00189151:return VR::DT; +case 0x00189152:return VR::SQ; +case 0x00189155:return VR::FD; +case 0x00189159:return VR::UL; +case 0x00189166:return VR::CS; +case 0x00189168:return VR::FD; +case 0x00189169:return VR::CS; +case 0x00189170:return VR::CS; +case 0x00189171:return VR::CS; +case 0x00189172:return VR::CS; +case 0x00189173:return VR::CS; +case 0x00189174:return VR::CS; +case 0x00189175:return VR::LO; +case 0x00189176:return VR::SQ; +case 0x00189177:return VR::CS; +case 0x00189178:return VR::CS; +case 0x00189179:return VR::CS; +case 0x00189180:return VR::CS; +case 0x00189181:return VR::FD; +case 0x00189182:return VR::FD; +case 0x00189183:return VR::CS; +case 0x00189184:return VR::FD; +case 0x00189185:return VR::ST; +case 0x00189186:return VR::SH; +case 0x00189195:return VR::FD; +case 0x00189196:return VR::FD; +case 0x00189197:return VR::SQ; +case 0x00189198:return VR::CS; +case 0x00189199:return VR::CS; +case 0x00189200:return VR::CS; +case 0x00189214:return VR::CS; +case 0x00189217:return VR::FD; +case 0x00189218:return VR::FD; +case 0x00189219:return VR::SS; +case 0x00189220:return VR::FD; +case 0x00189226:return VR::SQ; +case 0x00189227:return VR::SQ; +case 0x00189231:return VR::US; +case 0x00189232:return VR::US; +case 0x00189234:return VR::UL; +case 0x00189236:return VR::CS; +case 0x00189239:return VR::SQ; +case 0x00189240:return VR::US; +case 0x00189241:return VR::US; +case 0x00189250:return VR::CS; +case 0x00189251:return VR::SQ; +case 0x00189252:return VR::LO; +case 0x00189253:return VR::US; +case 0x00189254:return VR::FD; +case 0x00189255:return VR::FD; +case 0x00189256:return VR::FD; +case 0x00189257:return VR::CS; +case 0x00189258:return VR::UL; +case 0x00189259:return VR::CS; +case 0x0018925a:return VR::FD; +case 0x0018925b:return VR::LO; +case 0x0018925c:return VR::CS; +case 0x0018925d:return VR::SQ; +case 0x0018925e:return VR::LO; +case 0x0018925f:return VR::UL; +case 0x00189260:return VR::SQ; +case 0x00189295:return VR::FD; +case 0x00189296:return VR::FD; +case 0x00189301:return VR::SQ; +case 0x00189302:return VR::CS; +case 0x00189303:return VR::FD; +case 0x00189304:return VR::SQ; +case 0x00189305:return VR::FD; +case 0x00189306:return VR::FD; +case 0x00189307:return VR::FD; +case 0x00189308:return VR::SQ; +case 0x00189309:return VR::FD; +case 0x00189310:return VR::FD; +case 0x00189311:return VR::FD; +case 0x00189312:return VR::SQ; +case 0x00189313:return VR::FD; +case 0x00189314:return VR::SQ; +case 0x00189315:return VR::CS; +case 0x00189316:return VR::CS; +case 0x00189317:return VR::FD; +case 0x00189318:return VR::FD; +case 0x00189319:return VR::FD; +case 0x00189320:return VR::SH; +case 0x00189321:return VR::SQ; +case 0x00189322:return VR::FD; +case 0x00189323:return VR::CS; +case 0x00189324:return VR::FD; +case 0x00189325:return VR::SQ; +case 0x00189326:return VR::SQ; +case 0x00189327:return VR::FD; +case 0x00189328:return VR::FD; +case 0x00189329:return VR::SQ; +case 0x00189330:return VR::FD; +case 0x00189332:return VR::FD; +case 0x00189333:return VR::CS; +case 0x00189334:return VR::CS; +case 0x00189335:return VR::FD; +case 0x00189337:return VR::US; +case 0x00189338:return VR::SQ; +case 0x00189340:return VR::SQ; +case 0x00189341:return VR::SQ; +case 0x00189342:return VR::CS; +case 0x00189343:return VR::CS; +case 0x00189344:return VR::CS; +case 0x00189345:return VR::FD; +case 0x00189346:return VR::SQ; +case 0x00189351:return VR::FL; +case 0x00189352:return VR::FL; +case 0x00189353:return VR::FL; +case 0x00189360:return VR::SQ; +case 0x00189401:return VR::SQ; +case 0x00189402:return VR::FL; +case 0x00189403:return VR::FL; +case 0x00189404:return VR::FL; +case 0x00189405:return VR::SQ; +case 0x00189406:return VR::SQ; +case 0x00189407:return VR::SQ; +case 0x00189410:return VR::CS; +case 0x00189412:return VR::SQ; +case 0x00189417:return VR::SQ; +case 0x00189420:return VR::CS; +case 0x00189423:return VR::LO; +case 0x00189424:return VR::LT; +case 0x00189425:return VR::CS; +case 0x00189426:return VR::FL; +case 0x00189427:return VR::CS; +case 0x00189428:return VR::FL; +case 0x00189429:return VR::FL; +case 0x00189430:return VR::FL; +case 0x00189432:return VR::SQ; +case 0x00189433:return VR::LO; +case 0x00189434:return VR::SQ; +case 0x00189435:return VR::CS; +case 0x00189436:return VR::SS; +case 0x00189437:return VR::SS; +case 0x00189438:return VR::SS; +case 0x00189439:return VR::SS; +case 0x00189440:return VR::SS; +case 0x00189441:return VR::US; +case 0x00189442:return VR::SS; +case 0x00189447:return VR::FL; +case 0x00189449:return VR::FL; +case 0x00189451:return VR::SQ; +case 0x00189452:return VR::FL; +case 0x00189455:return VR::SQ; +case 0x00189456:return VR::SQ; +case 0x00189457:return VR::CS; +case 0x00189461:return VR::FL; +case 0x00189462:return VR::SQ; +case 0x00189463:return VR::FL; +case 0x00189464:return VR::FL; +case 0x00189465:return VR::FL; +case 0x00189466:return VR::FL; +case 0x00189467:return VR::FL; +case 0x00189468:return VR::FL; +case 0x00189469:return VR::FL; +case 0x00189470:return VR::FL; +case 0x00189471:return VR::FL; +case 0x00189472:return VR::SQ; +case 0x00189473:return VR::FL; +case 0x00189474:return VR::CS; +case 0x00189476:return VR::SQ; +case 0x00189477:return VR::SQ; +case 0x00189504:return VR::SQ; +case 0x00189506:return VR::SQ; +case 0x00189507:return VR::SQ; +case 0x00189508:return VR::FL; +case 0x00189509:return VR::FL; +case 0x00189510:return VR::FL; +case 0x00189511:return VR::FL; +case 0x00189514:return VR::FL; +case 0x00189515:return VR::FL; +case 0x00189516:return VR::DT; +case 0x00189517:return VR::DT; +case 0x00189524:return VR::LO; +case 0x00189525:return VR::LO; +case 0x00189526:return VR::LO; +case 0x00189527:return VR::CS; +case 0x00189528:return VR::LO; +case 0x00189530:return VR::SQ; +case 0x00189531:return VR::LO; +case 0x00189538:return VR::SQ; +case 0x00189601:return VR::SQ; +case 0x00189602:return VR::FD; +case 0x00189603:return VR::FD; +case 0x00189604:return VR::FD; +case 0x00189605:return VR::FD; +case 0x00189606:return VR::FD; +case 0x00189607:return VR::FD; +case 0x00189701:return VR::DT; +case 0x00189715:return VR::FD; +case 0x00189716:return VR::FD; +case 0x00189717:return VR::FD; +case 0x00189718:return VR::FD; +case 0x00189719:return VR::FD; +case 0x00189720:return VR::FD; +case 0x00189721:return VR::FD; +case 0x00189722:return VR::FD; +case 0x00189723:return VR::FD; +case 0x00189724:return VR::FD; +case 0x00189725:return VR::CS; +case 0x00189726:return VR::FD; +case 0x00189727:return VR::FD; +case 0x00189729:return VR::US; +case 0x00189732:return VR::SQ; +case 0x00189733:return VR::SQ; +case 0x00189734:return VR::SQ; +case 0x00189735:return VR::SQ; +case 0x00189736:return VR::SQ; +case 0x00189737:return VR::SQ; +case 0x00189738:return VR::CS; +case 0x00189739:return VR::US; +case 0x00189740:return VR::US; +case 0x00189749:return VR::SQ; +case 0x00189751:return VR::SQ; +case 0x00189755:return VR::CS; +case 0x00189756:return VR::CS; +case 0x00189758:return VR::CS; +case 0x00189759:return VR::CS; +case 0x00189760:return VR::CS; +case 0x00189761:return VR::CS; +case 0x00189762:return VR::CS; +case 0x00189763:return VR::CS; +case 0x00189764:return VR::CS; +case 0x00189765:return VR::CS; +case 0x00189766:return VR::CS; +case 0x00189767:return VR::CS; +case 0x00189768:return VR::CS; +case 0x00189769:return VR::CS; +case 0x00189770:return VR::CS; +case 0x00189771:return VR::SQ; +case 0x00189772:return VR::SQ; +case 0x00189801:return VR::FD; +case 0x00189803:return VR::SQ; +case 0x00189804:return VR::DT; +case 0x00189805:return VR::FD; +case 0x00189806:return VR::SQ; +case 0x00189807:return VR::SQ; +case 0x00189808:return VR::CS; +case 0x00189809:return VR::SQ; +case 0x0018980b:return VR::CS; +case 0x0018980c:return VR::CS; +case 0x0018980d:return VR::SQ; +case 0x0018980e:return VR::SQ; +case 0x0018980f:return VR::SQ; +case 0x0018a001:return VR::SQ; +case 0x0018a002:return VR::DT; +case 0x0018a003:return VR::ST; +case 0x0020000d:return VR::UI; +case 0x0020000e:return VR::UI; +case 0x00200010:return VR::SH; +case 0x00200011:return VR::IS; +case 0x00200012:return VR::IS; +case 0x00200013:return VR::IS; +case 0x00200014:return VR::IS; +case 0x00200015:return VR::IS; +case 0x00200016:return VR::IS; +case 0x00200017:return VR::IS; +case 0x00200018:return VR::IS; +case 0x00200019:return VR::IS; +case 0x00200020:return VR::CS; +case 0x00200022:return VR::IS; +case 0x00200024:return VR::IS; +case 0x00200026:return VR::IS; +case 0x00200030:return VR::DS; +case 0x00200032:return VR::DS; +case 0x00200035:return VR::DS; +case 0x00200037:return VR::DS; +case 0x00200050:return VR::DS; +case 0x00200052:return VR::UI; +case 0x00200060:return VR::CS; +case 0x00200062:return VR::CS; +case 0x00200070:return VR::LO; +case 0x00200080:return VR::CS; +case 0x002000aa:return VR::IS; +case 0x00200100:return VR::IS; +case 0x00200105:return VR::IS; +case 0x00200110:return VR::DS; +case 0x00200200:return VR::UI; +case 0x00200242:return VR::UI; +case 0x00201000:return VR::IS; +case 0x00201001:return VR::IS; +case 0x00201002:return VR::IS; +case 0x00201003:return VR::IS; +case 0x00201004:return VR::IS; +case 0x00201005:return VR::IS; +case 0x00201020:return VR::LO; +case 0x00201040:return VR::LO; +case 0x00201041:return VR::DS; +case 0x00201070:return VR::IS; +case 0x00201200:return VR::IS; +case 0x00201202:return VR::IS; +case 0x00201204:return VR::IS; +case 0x00201206:return VR::IS; +case 0x00201208:return VR::IS; +case 0x00201209:return VR::IS; +case 0x00203401:return VR::CS; +case 0x00203402:return VR::CS; +case 0x00203403:return VR::DA; +case 0x00203404:return VR::LO; +case 0x00203405:return VR::TM; +case 0x00203406:return VR::LO; +case 0x00204000:return VR::LT; +case 0x00205000:return VR::AT; +case 0x00205002:return VR::LO; +case 0x00209056:return VR::SH; +case 0x00209057:return VR::UL; +case 0x00209071:return VR::SQ; +case 0x00209072:return VR::CS; +case 0x00209111:return VR::SQ; +case 0x00209113:return VR::SQ; +case 0x00209116:return VR::SQ; +case 0x00209128:return VR::UL; +case 0x00209153:return VR::FD; +case 0x00209154:return VR::FL; +case 0x00209155:return VR::FL; +case 0x00209156:return VR::US; +case 0x00209157:return VR::UL; +case 0x00209158:return VR::LT; +case 0x00209161:return VR::UI; +case 0x00209162:return VR::US; +case 0x00209163:return VR::US; +case 0x00209164:return VR::UI; +case 0x00209165:return VR::AT; +case 0x00209167:return VR::AT; +case 0x00209213:return VR::LO; +case 0x00209221:return VR::SQ; +case 0x00209222:return VR::SQ; +case 0x00209228:return VR::UL; +case 0x00209238:return VR::LO; +case 0x00209241:return VR::FL; +case 0x00209245:return VR::FL; +case 0x00209246:return VR::FL; +case 0x00209247:return VR::CS; +case 0x00209248:return VR::FL; +case 0x00209249:return VR::CS; +case 0x00209250:return VR::CS; +case 0x00209251:return VR::FD; +case 0x00209252:return VR::FD; +case 0x00209253:return VR::SQ; +case 0x00209254:return VR::FD; +case 0x00209255:return VR::FD; +case 0x00209256:return VR::FD; +case 0x00209257:return VR::FD; +case 0x00209301:return VR::FD; +case 0x00209302:return VR::FD; +case 0x00209307:return VR::CS; +case 0x00209308:return VR::FD; +case 0x00209309:return VR::FD; +case 0x0020930a:return VR::FD; +case 0x0020930c:return VR::CS; +case 0x0020930d:return VR::FD; +case 0x0020930e:return VR::SQ; +case 0x0020930f:return VR::SQ; +case 0x00209310:return VR::SQ; +case 0x00209311:return VR::CS; +case 0x00209312:return VR::UI; +case 0x00209313:return VR::UI; +case 0x00209421:return VR::LO; +case 0x00209450:return VR::SQ; +case 0x00209453:return VR::LO; +case 0x00209518:return VR::US; +case 0x00209529:return VR::SQ; +case 0x00209536:return VR::US; +case 0x00220001:return VR::US; +case 0x00220002:return VR::US; +case 0x00220003:return VR::US; +case 0x00220004:return VR::US; +case 0x00220005:return VR::CS; +case 0x00220006:return VR::SQ; +case 0x00220007:return VR::FL; +case 0x00220008:return VR::FL; +case 0x00220009:return VR::FL; +case 0x0022000a:return VR::FL; +case 0x0022000b:return VR::FL; +case 0x0022000c:return VR::FL; +case 0x0022000d:return VR::CS; +case 0x0022000e:return VR::FL; +case 0x00220010:return VR::FL; +case 0x00220011:return VR::FL; +case 0x00220012:return VR::FL; +case 0x00220013:return VR::FL; +case 0x00220014:return VR::FL; +case 0x00220015:return VR::SQ; +case 0x00220016:return VR::SQ; +case 0x00220017:return VR::SQ; +case 0x00220018:return VR::SQ; +case 0x00220019:return VR::SQ; +case 0x0022001a:return VR::SQ; +case 0x0022001b:return VR::SQ; +case 0x0022001c:return VR::SQ; +case 0x0022001d:return VR::SQ; +case 0x0022001e:return VR::FL; +case 0x00220020:return VR::SQ; +case 0x00220021:return VR::SQ; +case 0x00220022:return VR::SQ; +case 0x00220030:return VR::FL; +case 0x00220031:return VR::SQ; +case 0x00220032:return VR::FL; +case 0x00220035:return VR::FL; +case 0x00220036:return VR::FL; +case 0x00220037:return VR::FL; +case 0x00220038:return VR::FL; +case 0x00220039:return VR::CS; +case 0x00220041:return VR::FL; +case 0x00220042:return VR::SQ; +case 0x00220048:return VR::FL; +case 0x00220049:return VR::FL; +case 0x0022004e:return VR::DS; +case 0x00220055:return VR::FL; +case 0x00220056:return VR::FL; +case 0x00220057:return VR::FL; +case 0x00220058:return VR::SQ; +case 0x00221007:return VR::SQ; +case 0x00221008:return VR::SQ; +case 0x00221009:return VR::CS; +case 0x00221010:return VR::CS; +case 0x00221012:return VR::SQ; +case 0x00221019:return VR::FL; +case 0x00221024:return VR::SQ; +case 0x00221025:return VR::SQ; +case 0x00221028:return VR::SQ; +case 0x00221029:return VR::LO; +case 0x00221033:return VR::FL; +case 0x00221035:return VR::SQ; +case 0x00221037:return VR::FL; +case 0x00221039:return VR::CS; +case 0x00221040:return VR::SQ; +case 0x00221044:return VR::SQ; +case 0x00221050:return VR::SQ; +case 0x00221053:return VR::FL; +case 0x00221054:return VR::FL; +case 0x00221059:return VR::FL; +case 0x00221065:return VR::LO; +case 0x00221066:return VR::LO; +case 0x00221090:return VR::SQ; +case 0x00221092:return VR::SQ; +case 0x00221093:return VR::LO; +case 0x00221094:return VR::LO; +case 0x00221095:return VR::LO; +case 0x00221096:return VR::SQ; +case 0x00221097:return VR::LO; +case 0x00221100:return VR::SQ; +case 0x00221101:return VR::SQ; +case 0x00221103:return VR::SQ; +case 0x00221121:return VR::FL; +case 0x00221122:return VR::FL; +case 0x00221125:return VR::SQ; +case 0x00221127:return VR::SQ; +case 0x00221128:return VR::SQ; +case 0x00221130:return VR::FL; +case 0x00221131:return VR::FL; +case 0x00221132:return VR::SQ; +case 0x00221133:return VR::SQ; +case 0x00221134:return VR::SQ; +case 0x00221135:return VR::SQ; +case 0x00221140:return VR::CS; +case 0x00221150:return VR::SQ; +case 0x00221153:return VR::SQ; +case 0x00221155:return VR::FL; +case 0x00221159:return VR::LO; +case 0x00221210:return VR::SQ; +case 0x00221211:return VR::SQ; +case 0x00221212:return VR::SQ; +case 0x00221220:return VR::SQ; +case 0x00221225:return VR::SQ; +case 0x00221230:return VR::SQ; +case 0x00221250:return VR::SQ; +case 0x00221255:return VR::SQ; +case 0x00221257:return VR::SQ; +case 0x00221260:return VR::SQ; +case 0x00221262:return VR::SQ; +case 0x00221273:return VR::LO; +case 0x00221300:return VR::SQ; +case 0x00221310:return VR::SQ; +case 0x00221330:return VR::SQ; +case 0x00240010:return VR::FL; +case 0x00240011:return VR::FL; +case 0x00240012:return VR::CS; +case 0x00240016:return VR::SQ; +case 0x00240018:return VR::FL; +case 0x00240020:return VR::FL; +case 0x00240021:return VR::SQ; +case 0x00240024:return VR::SQ; +case 0x00240025:return VR::FL; +case 0x00240028:return VR::FL; +case 0x00240032:return VR::SQ; +case 0x00240033:return VR::SQ; +case 0x00240034:return VR::SQ; +case 0x00240035:return VR::US; +case 0x00240036:return VR::US; +case 0x00240037:return VR::CS; +case 0x00240038:return VR::US; +case 0x00240039:return VR::CS; +case 0x00240040:return VR::CS; +case 0x00240042:return VR::US; +case 0x00240044:return VR::LT; +case 0x00240045:return VR::CS; +case 0x00240046:return VR::FL; +case 0x00240048:return VR::US; +case 0x00240050:return VR::US; +case 0x00240051:return VR::CS; +case 0x00240052:return VR::CS; +case 0x00240053:return VR::CS; +case 0x00240054:return VR::FL; +case 0x00240055:return VR::CS; +case 0x00240056:return VR::US; +case 0x00240057:return VR::CS; +case 0x00240058:return VR::SQ; +case 0x00240059:return VR::CS; +case 0x00240060:return VR::US; +case 0x00240061:return VR::CS; +case 0x00240062:return VR::CS; +case 0x00240063:return VR::CS; +case 0x00240064:return VR::SQ; +case 0x00240065:return VR::SQ; +case 0x00240066:return VR::FL; +case 0x00240067:return VR::SQ; +case 0x00240068:return VR::FL; +case 0x00240069:return VR::LO; +case 0x00240070:return VR::FL; +case 0x00240071:return VR::FL; +case 0x00240072:return VR::CS; +case 0x00240073:return VR::FL; +case 0x00240074:return VR::CS; +case 0x00240075:return VR::FL; +case 0x00240076:return VR::CS; +case 0x00240077:return VR::FL; +case 0x00240078:return VR::CS; +case 0x00240079:return VR::FL; +case 0x00240080:return VR::CS; +case 0x00240081:return VR::FL; +case 0x00240083:return VR::SQ; +case 0x00240085:return VR::SQ; +case 0x00240086:return VR::CS; +case 0x00240087:return VR::FL; +case 0x00240088:return VR::FL; +case 0x00240089:return VR::SQ; +case 0x00240090:return VR::FL; +case 0x00240091:return VR::FL; +case 0x00240092:return VR::FL; +case 0x00240093:return VR::CS; +case 0x00240094:return VR::FL; +case 0x00240095:return VR::CS; +case 0x00240096:return VR::FL; +case 0x00240097:return VR::SQ; +case 0x00240098:return VR::FL; +case 0x00240100:return VR::FL; +case 0x00240102:return VR::CS; +case 0x00240103:return VR::FL; +case 0x00240104:return VR::FL; +case 0x00240105:return VR::FL; +case 0x00240106:return VR::CS; +case 0x00240107:return VR::FL; +case 0x00240108:return VR::FL; +case 0x00240110:return VR::SQ; +case 0x00240112:return VR::SQ; +case 0x00240113:return VR::CS; +case 0x00240114:return VR::SQ; +case 0x00240115:return VR::SQ; +case 0x00240117:return VR::CS; +case 0x00240118:return VR::FL; +case 0x00240120:return VR::CS; +case 0x00240122:return VR::SQ; +case 0x00240124:return VR::CS; +case 0x00240126:return VR::FL; +case 0x00240202:return VR::LO; +case 0x00240306:return VR::LO; +case 0x00240307:return VR::LO; +case 0x00240308:return VR::LO; +case 0x00240309:return VR::LO; +case 0x00240317:return VR::SQ; +case 0x00240320:return VR::SQ; +case 0x00240325:return VR::SQ; +case 0x00240338:return VR::CS; +case 0x00240341:return VR::FL; +case 0x00240344:return VR::SQ; +case 0x00280002:return VR::US; +case 0x00280003:return VR::US; +case 0x00280004:return VR::CS; +case 0x00280005:return VR::US; +case 0x00280006:return VR::US; +case 0x00280008:return VR::IS; +case 0x00280009:return VR::AT; +case 0x0028000a:return VR::AT; +case 0x00280010:return VR::US; +case 0x00280011:return VR::US; +case 0x00280012:return VR::US; +case 0x00280014:return VR::US; +case 0x00280030:return VR::DS; +case 0x00280031:return VR::DS; +case 0x00280032:return VR::DS; +case 0x00280034:return VR::IS; +case 0x00280040:return VR::CS; +case 0x00280050:return VR::LO; +case 0x00280051:return VR::CS; +case 0x0028005f:return VR::LO; +case 0x00280060:return VR::CS; +case 0x00280061:return VR::SH; +case 0x00280062:return VR::LO; +case 0x00280063:return VR::SH; +case 0x00280065:return VR::CS; +case 0x00280066:return VR::AT; +case 0x00280068:return VR::US; +case 0x00280069:return VR::US; +case 0x00280070:return VR::US; +case 0x00280071:return VR::US_SS; +case 0x00280080:return VR::US; +case 0x00280081:return VR::US; +case 0x00280082:return VR::US; +case 0x00280090:return VR::CS; +case 0x00280091:return VR::US; +case 0x00280092:return VR::US; +case 0x00280093:return VR::US; +case 0x00280094:return VR::US; +case 0x00280100:return VR::US; +case 0x00280101:return VR::US; +case 0x00280102:return VR::US; +case 0x00280103:return VR::US; +case 0x00280104:return VR::US_SS; +case 0x00280105:return VR::US_SS; +case 0x00280106:return VR::US_SS; +case 0x00280107:return VR::US_SS; +case 0x00280108:return VR::US_SS; +case 0x00280109:return VR::US_SS; +case 0x00280110:return VR::US_SS; +case 0x00280111:return VR::US_SS; +case 0x00280120:return VR::US_SS; +case 0x00280121:return VR::US_SS; +case 0x00280200:return VR::US; +case 0x00280300:return VR::CS; +case 0x00280301:return VR::CS; +case 0x00280302:return VR::CS; +case 0x00280303:return VR::CS; +case 0x00280304:return VR::UI; +case 0x00280400:return VR::LO; +case 0x00280401:return VR::LO; +case 0x00280402:return VR::US; +case 0x00280403:return VR::LO; +case 0x00280404:return VR::AT; +case 0x00280700:return VR::LO; +case 0x00280701:return VR::CS; +case 0x00280702:return VR::AT; +case 0x00280710:return VR::US; +case 0x00280720:return VR::US; +case 0x00280721:return VR::AT; +case 0x00280722:return VR::US; +case 0x00280730:return VR::US; +case 0x00280740:return VR::US; +case 0x00280a02:return VR::CS; +case 0x00280a04:return VR::LO; +case 0x00281040:return VR::CS; +case 0x00281041:return VR::SS; +case 0x00281050:return VR::DS; +case 0x00281051:return VR::DS; +case 0x00281052:return VR::DS; +case 0x00281053:return VR::DS; +case 0x00281054:return VR::LO; +case 0x00281055:return VR::LO; +case 0x00281056:return VR::CS; +case 0x00281080:return VR::CS; +case 0x00281090:return VR::CS; +case 0x00281100:return VR::US_SS; +case 0x00281101:return VR::US_SS; +case 0x00281102:return VR::US_SS; +case 0x00281103:return VR::US_SS; +case 0x00281104:return VR::US; +case 0x00281111:return VR::US_SS; +case 0x00281112:return VR::US_SS; +case 0x00281113:return VR::US_SS; +case 0x00281199:return VR::UI; +case 0x00281201:return VR::OW; +case 0x00281202:return VR::OW; +case 0x00281203:return VR::OW; +case 0x00281204:return VR::OW; +case 0x00281211:return VR::OW; +case 0x00281212:return VR::OW; +case 0x00281213:return VR::OW; +case 0x00281214:return VR::UI; +case 0x00281221:return VR::OW; +case 0x00281222:return VR::OW; +case 0x00281223:return VR::OW; +case 0x00281300:return VR::CS; +case 0x00281350:return VR::CS; +case 0x00281351:return VR::ST; +case 0x00281352:return VR::SQ; +case 0x0028135a:return VR::CS; +case 0x00281401:return VR::SQ; +case 0x00281402:return VR::CS; +case 0x00281403:return VR::US; +case 0x00281404:return VR::SQ; +case 0x00281405:return VR::CS; +case 0x00281406:return VR::FD; +case 0x00281407:return VR::US; +case 0x00281408:return VR::OW; +case 0x0028140b:return VR::SQ; +case 0x0028140c:return VR::SQ; +case 0x0028140d:return VR::CS; +case 0x0028140e:return VR::CS; +case 0x0028140f:return VR::CS; +case 0x00281410:return VR::CS; +case 0x00282000:return VR::OB; +case 0x00282110:return VR::CS; +case 0x00282112:return VR::DS; +case 0x00282114:return VR::CS; +case 0x00283000:return VR::SQ; +case 0x00283002:return VR::US_SS; +case 0x00283003:return VR::LO; +case 0x00283004:return VR::LO; +case 0x00283010:return VR::SQ; +case 0x00283110:return VR::SQ; +case 0x00284000:return VR::LT; +case 0x00285000:return VR::SQ; +case 0x00286010:return VR::US; +case 0x00286020:return VR::US; +case 0x00286022:return VR::LO; +case 0x00286023:return VR::CS; +case 0x00286030:return VR::US; +case 0x00286040:return VR::US; +case 0x00286100:return VR::SQ; +case 0x00286101:return VR::CS; +case 0x00286102:return VR::US; +case 0x00286110:return VR::US; +case 0x00286112:return VR::US; +case 0x00286114:return VR::FL; +case 0x00286120:return VR::SS; +case 0x00286190:return VR::ST; +case 0x00287fe0:return VR::UT; +case 0x00289001:return VR::UL; +case 0x00289002:return VR::UL; +case 0x00289003:return VR::CS; +case 0x00289099:return VR::US; +case 0x00289108:return VR::CS; +case 0x00289110:return VR::SQ; +case 0x00289132:return VR::SQ; +case 0x00289145:return VR::SQ; +case 0x00289235:return VR::CS; +case 0x00289411:return VR::FL; +case 0x00289415:return VR::SQ; +case 0x00289416:return VR::US; +case 0x00289422:return VR::SQ; +case 0x00289443:return VR::SQ; +case 0x00289444:return VR::CS; +case 0x00289445:return VR::FL; +case 0x00289446:return VR::CS; +case 0x00289454:return VR::CS; +case 0x00289474:return VR::CS; +case 0x00289478:return VR::FL; +case 0x00289501:return VR::SQ; +case 0x00289502:return VR::SQ; +case 0x00289503:return VR::SS; +case 0x00289505:return VR::SQ; +case 0x00289506:return VR::US; +case 0x00289507:return VR::US; +case 0x00289520:return VR::DS; +case 0x00289537:return VR::CS; +case 0x0032000a:return VR::CS; +case 0x0032000c:return VR::CS; +case 0x00320012:return VR::LO; +case 0x00320032:return VR::DA; +case 0x00320033:return VR::TM; +case 0x00320034:return VR::DA; +case 0x00320035:return VR::TM; +case 0x00321000:return VR::DA; +case 0x00321001:return VR::TM; +case 0x00321010:return VR::DA; +case 0x00321011:return VR::TM; +case 0x00321020:return VR::LO; +case 0x00321021:return VR::AE; +case 0x00321030:return VR::LO; +case 0x00321031:return VR::SQ; +case 0x00321032:return VR::PN; +case 0x00321033:return VR::LO; +case 0x00321034:return VR::SQ; +case 0x00321040:return VR::DA; +case 0x00321041:return VR::TM; +case 0x00321050:return VR::DA; +case 0x00321051:return VR::TM; +case 0x00321055:return VR::CS; +case 0x00321060:return VR::LO; +case 0x00321064:return VR::SQ; +case 0x00321070:return VR::LO; +case 0x00324000:return VR::LT; +case 0x00380004:return VR::SQ; +case 0x00380008:return VR::CS; +case 0x00380010:return VR::LO; +case 0x00380011:return VR::LO; +case 0x00380014:return VR::SQ; +case 0x00380016:return VR::LO; +case 0x0038001a:return VR::DA; +case 0x0038001b:return VR::TM; +case 0x0038001c:return VR::DA; +case 0x0038001d:return VR::TM; +case 0x0038001e:return VR::LO; +case 0x00380020:return VR::DA; +case 0x00380021:return VR::TM; +case 0x00380030:return VR::DA; +case 0x00380032:return VR::TM; +case 0x00380040:return VR::LO; +case 0x00380044:return VR::SQ; +case 0x00380050:return VR::LO; +case 0x00380060:return VR::LO; +case 0x00380061:return VR::LO; +case 0x00380062:return VR::LO; +case 0x00380064:return VR::SQ; +case 0x00380100:return VR::SQ; +case 0x00380300:return VR::LO; +case 0x00380400:return VR::LO; +case 0x00380500:return VR::LO; +case 0x00380502:return VR::SQ; +case 0x00384000:return VR::LT; +case 0x003a0004:return VR::CS; +case 0x003a0005:return VR::US; +case 0x003a0010:return VR::UL; +case 0x003a001a:return VR::DS; +case 0x003a0020:return VR::SH; +case 0x003a0200:return VR::SQ; +case 0x003a0202:return VR::IS; +case 0x003a0203:return VR::SH; +case 0x003a0205:return VR::CS; +case 0x003a0208:return VR::SQ; +case 0x003a0209:return VR::SQ; +case 0x003a020a:return VR::SQ; +case 0x003a020c:return VR::LO; +case 0x003a0210:return VR::DS; +case 0x003a0211:return VR::SQ; +case 0x003a0212:return VR::DS; +case 0x003a0213:return VR::DS; +case 0x003a0214:return VR::DS; +case 0x003a0215:return VR::DS; +case 0x003a0218:return VR::DS; +case 0x003a021a:return VR::US; +case 0x003a0220:return VR::DS; +case 0x003a0221:return VR::DS; +case 0x003a0222:return VR::DS; +case 0x003a0223:return VR::DS; +case 0x003a0230:return VR::FL; +case 0x003a0231:return VR::US; +case 0x003a0240:return VR::SQ; +case 0x003a0241:return VR::US; +case 0x003a0242:return VR::SQ; +case 0x003a0244:return VR::US; +case 0x003a0245:return VR::FL; +case 0x003a0246:return VR::CS; +case 0x003a0247:return VR::FL; +case 0x003a0248:return VR::FL; +case 0x003a0300:return VR::SQ; +case 0x003a0301:return VR::IS; +case 0x003a0302:return VR::CS; +case 0x00400001:return VR::AE; +case 0x00400002:return VR::DA; +case 0x00400003:return VR::TM; +case 0x00400004:return VR::DA; +case 0x00400005:return VR::TM; +case 0x00400006:return VR::PN; +case 0x00400007:return VR::LO; +case 0x00400008:return VR::SQ; +case 0x00400009:return VR::SH; +case 0x0040000a:return VR::SQ; +case 0x0040000b:return VR::SQ; +case 0x00400010:return VR::SH; +case 0x00400011:return VR::SH; +case 0x00400012:return VR::LO; +case 0x00400020:return VR::CS; +case 0x00400026:return VR::SQ; +case 0x00400027:return VR::SQ; +case 0x00400031:return VR::UT; +case 0x00400032:return VR::UT; +case 0x00400033:return VR::CS; +case 0x00400035:return VR::CS; +case 0x00400036:return VR::SQ; +case 0x00400039:return VR::SQ; +case 0x0040003a:return VR::SQ; +case 0x00400100:return VR::SQ; +case 0x00400220:return VR::SQ; +case 0x00400241:return VR::AE; +case 0x00400242:return VR::SH; +case 0x00400243:return VR::SH; +case 0x00400244:return VR::DA; +case 0x00400245:return VR::TM; +case 0x00400250:return VR::DA; +case 0x00400251:return VR::TM; +case 0x00400252:return VR::CS; +case 0x00400253:return VR::SH; +case 0x00400254:return VR::LO; +case 0x00400255:return VR::LO; +case 0x00400260:return VR::SQ; +case 0x00400261:return VR::CS; +case 0x00400270:return VR::SQ; +case 0x00400275:return VR::SQ; +case 0x00400280:return VR::ST; +case 0x00400281:return VR::SQ; +case 0x00400293:return VR::SQ; +case 0x00400294:return VR::DS; +case 0x00400295:return VR::SQ; +case 0x00400296:return VR::SQ; +case 0x00400300:return VR::US; +case 0x00400301:return VR::US; +case 0x00400302:return VR::US; +case 0x00400303:return VR::US; +case 0x00400306:return VR::DS; +case 0x00400307:return VR::DS; +case 0x0040030e:return VR::SQ; +case 0x00400310:return VR::ST; +case 0x00400312:return VR::DS; +case 0x00400314:return VR::DS; +case 0x00400316:return VR::DS; +case 0x00400318:return VR::CS; +case 0x00400320:return VR::SQ; +case 0x00400321:return VR::SQ; +case 0x00400324:return VR::SQ; +case 0x00400330:return VR::SQ; +case 0x00400340:return VR::SQ; +case 0x00400400:return VR::LT; +case 0x00400440:return VR::SQ; +case 0x00400441:return VR::SQ; +case 0x00400500:return VR::SQ; +case 0x0040050a:return VR::LO; +case 0x00400512:return VR::LO; +case 0x00400513:return VR::SQ; +case 0x00400515:return VR::SQ; +case 0x00400518:return VR::SQ; +case 0x0040051a:return VR::LO; +case 0x00400520:return VR::SQ; +case 0x00400550:return VR::SQ; +case 0x00400551:return VR::LO; +case 0x00400552:return VR::SQ; +case 0x00400553:return VR::ST; +case 0x00400554:return VR::UI; +case 0x00400555:return VR::SQ; +case 0x00400556:return VR::ST; +case 0x0040059a:return VR::SQ; +case 0x00400560:return VR::SQ; +case 0x00400562:return VR::SQ; +case 0x00400600:return VR::LO; +case 0x00400602:return VR::UT; +case 0x00400610:return VR::SQ; +case 0x00400612:return VR::SQ; +case 0x00400620:return VR::SQ; +case 0x004006fa:return VR::LO; +case 0x0040071a:return VR::SQ; +case 0x0040072a:return VR::DS; +case 0x0040073a:return VR::DS; +case 0x0040074a:return VR::DS; +case 0x004008d8:return VR::SQ; +case 0x004008da:return VR::SQ; +case 0x004008ea:return VR::SQ; +case 0x004009f8:return VR::SQ; +case 0x00401001:return VR::SH; +case 0x00401002:return VR::LO; +case 0x00401003:return VR::SH; +case 0x00401004:return VR::LO; +case 0x00401005:return VR::LO; +case 0x00401006:return VR::SH; +case 0x00401007:return VR::SH; +case 0x00401008:return VR::LO; +case 0x00401009:return VR::SH; +case 0x0040100a:return VR::SQ; +case 0x00401010:return VR::PN; +case 0x00401011:return VR::SQ; +case 0x00401012:return VR::SQ; +case 0x00401060:return VR::LO; +case 0x00401101:return VR::SQ; +case 0x00401102:return VR::ST; +case 0x00401103:return VR::LO; +case 0x00401400:return VR::LT; +case 0x00402001:return VR::LO; +case 0x00402004:return VR::DA; +case 0x00402005:return VR::TM; +case 0x00402006:return VR::SH; +case 0x00402007:return VR::SH; +case 0x00402008:return VR::PN; +case 0x00402009:return VR::SH; +case 0x00402010:return VR::SH; +case 0x00402016:return VR::LO; +case 0x00402017:return VR::LO; +case 0x00402400:return VR::LT; +case 0x00403001:return VR::LO; +case 0x00404001:return VR::CS; +case 0x00404002:return VR::CS; +case 0x00404003:return VR::CS; +case 0x00404004:return VR::SQ; +case 0x00404005:return VR::DT; +case 0x00404006:return VR::CS; +case 0x00404007:return VR::SQ; +case 0x00404009:return VR::SQ; +case 0x00404010:return VR::DT; +case 0x00404011:return VR::DT; +case 0x00404015:return VR::SQ; +case 0x00404016:return VR::SQ; +case 0x00404018:return VR::SQ; +case 0x00404019:return VR::SQ; +case 0x00404020:return VR::CS; +case 0x00404021:return VR::SQ; +case 0x00404022:return VR::SQ; +case 0x00404023:return VR::UI; +case 0x00404025:return VR::SQ; +case 0x00404026:return VR::SQ; +case 0x00404027:return VR::SQ; +case 0x00404028:return VR::SQ; +case 0x00404029:return VR::SQ; +case 0x00404030:return VR::SQ; +case 0x00404031:return VR::SQ; +case 0x00404032:return VR::SQ; +case 0x00404033:return VR::SQ; +case 0x00404034:return VR::SQ; +case 0x00404035:return VR::SQ; +case 0x00404036:return VR::LO; +case 0x00404037:return VR::PN; +case 0x00404040:return VR::CS; +case 0x00404041:return VR::CS; +case 0x00404050:return VR::DT; +case 0x00404051:return VR::DT; +case 0x00404052:return VR::DT; +case 0x00408302:return VR::DS; +case 0x00409094:return VR::SQ; +case 0x00409096:return VR::SQ; +case 0x00409098:return VR::SQ; +case 0x00409210:return VR::SH; +case 0x00409211:return VR::US_SS; +case 0x00409212:return VR::FD; +case 0x00409216:return VR::US_SS; +case 0x00409224:return VR::FD; +case 0x00409225:return VR::FD; +case 0x0040a007:return VR::CS; +case 0x0040a010:return VR::CS; +case 0x0040a020:return VR::SQ; +case 0x0040a021:return VR::UI; +case 0x0040a022:return VR::UI; +case 0x0040a023:return VR::DA; +case 0x0040a024:return VR::TM; +case 0x0040a026:return VR::SQ; +case 0x0040a027:return VR::LO; +case 0x0040a028:return VR::SQ; +case 0x0040a030:return VR::DT; +case 0x0040a032:return VR::DT; +case 0x0040a040:return VR::CS; +case 0x0040a043:return VR::SQ; +case 0x0040a047:return VR::LO; +case 0x0040a050:return VR::CS; +case 0x0040a057:return VR::CS; +case 0x0040a060:return VR::LO; +case 0x0040a066:return VR::SQ; +case 0x0040a067:return VR::PN; +case 0x0040a068:return VR::SQ; +case 0x0040a070:return VR::SQ; +case 0x0040a073:return VR::SQ; +case 0x0040a074:return VR::OB; +case 0x0040a075:return VR::PN; +case 0x0040a076:return VR::SQ; +case 0x0040a078:return VR::SQ; +case 0x0040a07a:return VR::SQ; +case 0x0040a07c:return VR::SQ; +case 0x0040a080:return VR::CS; +case 0x0040a082:return VR::DT; +case 0x0040a084:return VR::CS; +case 0x0040a085:return VR::SQ; +case 0x0040a088:return VR::SQ; +case 0x0040a089:return VR::OB; +case 0x0040a090:return VR::SQ; +case 0x0040a0b0:return VR::US; +case 0x0040a110:return VR::DA; +case 0x0040a112:return VR::TM; +case 0x0040a120:return VR::DT; +case 0x0040a121:return VR::DA; +case 0x0040a122:return VR::TM; +case 0x0040a123:return VR::PN; +case 0x0040a124:return VR::UI; +case 0x0040a125:return VR::CS; +case 0x0040a130:return VR::CS; +case 0x0040a132:return VR::UL; +case 0x0040a136:return VR::US; +case 0x0040a138:return VR::DS; +case 0x0040a13a:return VR::DT; +case 0x0040a160:return VR::UT; +case 0x0040a167:return VR::SQ; +case 0x0040a168:return VR::SQ; +case 0x0040a16a:return VR::ST; +case 0x0040a170:return VR::SQ; +case 0x0040a171:return VR::UI; +case 0x0040a172:return VR::UI; +case 0x0040a173:return VR::CS; +case 0x0040a174:return VR::CS; +case 0x0040a180:return VR::US; +case 0x0040a192:return VR::DA; +case 0x0040a193:return VR::TM; +case 0x0040a194:return VR::CS; +case 0x0040a195:return VR::SQ; +case 0x0040a224:return VR::ST; +case 0x0040a290:return VR::CS; +case 0x0040a296:return VR::SQ; +case 0x0040a297:return VR::ST; +case 0x0040a29a:return VR::SL; +case 0x0040a300:return VR::SQ; +case 0x0040a301:return VR::SQ; +case 0x0040a307:return VR::PN; +case 0x0040a30a:return VR::DS; +case 0x0040a313:return VR::SQ; +case 0x0040a33a:return VR::ST; +case 0x0040a340:return VR::SQ; +case 0x0040a352:return VR::PN; +case 0x0040a353:return VR::ST; +case 0x0040a354:return VR::LO; +case 0x0040a358:return VR::SQ; +case 0x0040a360:return VR::SQ; +case 0x0040a370:return VR::SQ; +case 0x0040a372:return VR::SQ; +case 0x0040a375:return VR::SQ; +case 0x0040a380:return VR::SQ; +case 0x0040a385:return VR::SQ; +case 0x0040a390:return VR::SQ; +case 0x0040a402:return VR::UI; +case 0x0040a403:return VR::CS; +case 0x0040a404:return VR::SQ; +case 0x0040a491:return VR::CS; +case 0x0040a492:return VR::LO; +case 0x0040a493:return VR::CS; +case 0x0040a494:return VR::CS; +case 0x0040a496:return VR::CS; +case 0x0040a504:return VR::SQ; +case 0x0040a525:return VR::SQ; +case 0x0040a600:return VR::CS; +case 0x0040a601:return VR::CS; +case 0x0040a603:return VR::CS; +case 0x0040a730:return VR::SQ; +case 0x0040a731:return VR::SQ; +case 0x0040a732:return VR::SQ; +case 0x0040a744:return VR::SQ; +case 0x0040a992:return VR::ST; +case 0x0040b020:return VR::SQ; +case 0x0040db00:return VR::CS; +case 0x0040db06:return VR::DT; +case 0x0040db07:return VR::DT; +case 0x0040db0b:return VR::CS; +case 0x0040db0c:return VR::UI; +case 0x0040db0d:return VR::UI; +case 0x0040db73:return VR::UL; +case 0x0040e001:return VR::ST; +case 0x0040e004:return VR::DT; +case 0x0040e006:return VR::SQ; +case 0x0040e008:return VR::SQ; +case 0x0040e010:return VR::UT; +case 0x0040e011:return VR::UI; +case 0x0040e020:return VR::CS; +case 0x0040e021:return VR::SQ; +case 0x0040e022:return VR::SQ; +case 0x0040e023:return VR::SQ; +case 0x0040e024:return VR::SQ; +case 0x0040e030:return VR::UI; +case 0x0040e031:return VR::UI; +case 0x00420010:return VR::ST; +case 0x00420011:return VR::OB; +case 0x00420012:return VR::LO; +case 0x00420013:return VR::SQ; +case 0x00420014:return VR::LO; +case 0x00440001:return VR::ST; +case 0x00440002:return VR::CS; +case 0x00440003:return VR::LT; +case 0x00440004:return VR::DT; +case 0x00440007:return VR::SQ; +case 0x00440008:return VR::LO; +case 0x00440009:return VR::LT; +case 0x0044000a:return VR::LO; +case 0x0044000b:return VR::DT; +case 0x00440010:return VR::DT; +case 0x00440011:return VR::LO; +case 0x00440012:return VR::LO; +case 0x00440013:return VR::SQ; +case 0x00440019:return VR::SQ; +case 0x00460012:return VR::LO; +case 0x00460014:return VR::SQ; +case 0x00460015:return VR::SQ; +case 0x00460016:return VR::SQ; +case 0x00460018:return VR::SQ; +case 0x00460028:return VR::SQ; +case 0x00460030:return VR::FD; +case 0x00460032:return VR::CS; +case 0x00460034:return VR::FD; +case 0x00460036:return VR::CS; +case 0x00460038:return VR::CS; +case 0x00460040:return VR::FD; +case 0x00460042:return VR::FD; +case 0x00460044:return VR::FD; +case 0x00460046:return VR::FD; +case 0x00460050:return VR::SQ; +case 0x00460052:return VR::SQ; +case 0x00460060:return VR::FD; +case 0x00460062:return VR::FD; +case 0x00460063:return VR::FD; +case 0x00460064:return VR::FD; +case 0x00460070:return VR::SQ; +case 0x00460071:return VR::SQ; +case 0x00460074:return VR::SQ; +case 0x00460075:return VR::FD; +case 0x00460076:return VR::FD; +case 0x00460077:return VR::FD; +case 0x00460080:return VR::SQ; +case 0x00460092:return VR::CS; +case 0x00460094:return VR::CS; +case 0x00460095:return VR::CS; +case 0x00460097:return VR::SQ; +case 0x00460098:return VR::SQ; +case 0x00460100:return VR::SQ; +case 0x00460101:return VR::SQ; +case 0x00460102:return VR::SQ; +case 0x00460104:return VR::FD; +case 0x00460106:return VR::FD; +case 0x00460121:return VR::SQ; +case 0x00460122:return VR::SQ; +case 0x00460123:return VR::SQ; +case 0x00460124:return VR::SQ; +case 0x00460125:return VR::CS; +case 0x00460135:return VR::SS; +case 0x00460137:return VR::FD; +case 0x00460139:return VR::LO; +case 0x00460145:return VR::SQ; +case 0x00460146:return VR::FD; +case 0x00460147:return VR::FD; +case 0x00480001:return VR::FL; +case 0x00480002:return VR::FL; +case 0x00480003:return VR::FL; +case 0x00480006:return VR::UL; +case 0x00480007:return VR::UL; +case 0x00480008:return VR::SQ; +case 0x00480010:return VR::CS; +case 0x00480011:return VR::CS; +case 0x00480012:return VR::CS; +case 0x00480013:return VR::US; +case 0x00480014:return VR::FL; +case 0x00480015:return VR::US; +case 0x00480100:return VR::SQ; +case 0x00480102:return VR::DS; +case 0x00480105:return VR::SQ; +case 0x00480106:return VR::SH; +case 0x00480107:return VR::ST; +case 0x00480108:return VR::SQ; +case 0x00480110:return VR::SQ; +case 0x00480111:return VR::DS; +case 0x00480112:return VR::DS; +case 0x00480113:return VR::DS; +case 0x00480120:return VR::SQ; +case 0x00480200:return VR::SQ; +case 0x00480201:return VR::US; +case 0x00480202:return VR::US; +case 0x00480207:return VR::SQ; +case 0x0048021a:return VR::SQ; +case 0x0048021e:return VR::SL; +case 0x0048021f:return VR::SL; +case 0x00480301:return VR::CS; +case 0x00500004:return VR::CS; +case 0x00500010:return VR::SQ; +case 0x00500012:return VR::SQ; +case 0x00500013:return VR::FD; +case 0x00500014:return VR::DS; +case 0x00500015:return VR::FD; +case 0x00500016:return VR::DS; +case 0x00500017:return VR::CS; +case 0x00500018:return VR::DS; +case 0x00500019:return VR::DS; +case 0x0050001a:return VR::CS; +case 0x0050001b:return VR::LO; +case 0x0050001c:return VR::FD; +case 0x0050001d:return VR::FD; +case 0x0050001e:return VR::LO; +case 0x00500020:return VR::LO; +case 0x00520001:return VR::FL; +case 0x00520002:return VR::FD; +case 0x00520003:return VR::FD; +case 0x00520004:return VR::FD; +case 0x00520006:return VR::CS; +case 0x00520007:return VR::FD; +case 0x00520008:return VR::FD; +case 0x00520009:return VR::FD; +case 0x00520011:return VR::FD; +case 0x00520012:return VR::US; +case 0x00520013:return VR::FD; +case 0x00520014:return VR::FD; +case 0x00520016:return VR::SQ; +case 0x00520025:return VR::SQ; +case 0x00520026:return VR::CS; +case 0x00520027:return VR::SQ; +case 0x00520028:return VR::FD; +case 0x00520029:return VR::SQ; +case 0x00520030:return VR::SS; +case 0x00520031:return VR::CS; +case 0x00520033:return VR::FD; +case 0x00520034:return VR::FD; +case 0x00520036:return VR::US; +case 0x00520038:return VR::US; +case 0x00520039:return VR::CS; +case 0x0052003a:return VR::CS; +case 0x00540010:return VR::US; +case 0x00540011:return VR::US; +case 0x00540012:return VR::SQ; +case 0x00540013:return VR::SQ; +case 0x00540014:return VR::DS; +case 0x00540015:return VR::DS; +case 0x00540016:return VR::SQ; +case 0x00540017:return VR::IS; +case 0x00540018:return VR::SH; +case 0x00540020:return VR::US; +case 0x00540021:return VR::US; +case 0x00540022:return VR::SQ; +case 0x00540030:return VR::US; +case 0x00540031:return VR::US; +case 0x00540032:return VR::SQ; +case 0x00540033:return VR::US; +case 0x00540036:return VR::IS; +case 0x00540038:return VR::IS; +case 0x00540039:return VR::CS; +case 0x00540050:return VR::US; +case 0x00540051:return VR::US; +case 0x00540052:return VR::SQ; +case 0x00540053:return VR::US; +case 0x00540060:return VR::US; +case 0x00540061:return VR::US; +case 0x00540062:return VR::SQ; +case 0x00540063:return VR::SQ; +case 0x00540070:return VR::US; +case 0x00540071:return VR::US; +case 0x00540072:return VR::SQ; +case 0x00540073:return VR::DS; +case 0x00540080:return VR::US; +case 0x00540081:return VR::US; +case 0x00540090:return VR::US; +case 0x00540100:return VR::US; +case 0x00540101:return VR::US; +case 0x00540200:return VR::DS; +case 0x00540202:return VR::CS; +case 0x00540210:return VR::IS; +case 0x00540211:return VR::US; +case 0x00540220:return VR::SQ; +case 0x00540222:return VR::SQ; +case 0x00540300:return VR::SQ; +case 0x00540302:return VR::SQ; +case 0x00540304:return VR::SQ; +case 0x00540306:return VR::SQ; +case 0x00540308:return VR::US; +case 0x00540400:return VR::SH; +case 0x00540410:return VR::SQ; +case 0x00540412:return VR::SQ; +case 0x00540414:return VR::SQ; +case 0x00540500:return VR::CS; +case 0x00541000:return VR::CS; +case 0x00541001:return VR::CS; +case 0x00541002:return VR::CS; +case 0x00541004:return VR::CS; +case 0x00541006:return VR::CS; +case 0x00541100:return VR::CS; +case 0x00541101:return VR::LO; +case 0x00541102:return VR::CS; +case 0x00541103:return VR::LO; +case 0x00541104:return VR::LO; +case 0x00541105:return VR::LO; +case 0x00541200:return VR::DS; +case 0x00541201:return VR::IS; +case 0x00541202:return VR::IS; +case 0x00541203:return VR::DS; +case 0x00541210:return VR::DS; +case 0x00541220:return VR::CS; +case 0x00541300:return VR::DS; +case 0x00541310:return VR::IS; +case 0x00541311:return VR::IS; +case 0x00541320:return VR::DS; +case 0x00541321:return VR::DS; +case 0x00541322:return VR::DS; +case 0x00541323:return VR::DS; +case 0x00541324:return VR::DS; +case 0x00541330:return VR::US; +case 0x00541400:return VR::CS; +case 0x00541401:return VR::CS; +case 0x00603000:return VR::SQ; +case 0x00603002:return VR::US; +case 0x00603004:return VR::US_SS; +case 0x00603006:return VR::US_SS; +case 0x00603008:return VR::US; +case 0x00603010:return VR::LO; +case 0x00603020:return VR::UL; +case 0x00620001:return VR::CS; +case 0x00620002:return VR::SQ; +case 0x00620003:return VR::SQ; +case 0x00620004:return VR::US; +case 0x00620005:return VR::LO; +case 0x00620006:return VR::ST; +case 0x00620008:return VR::CS; +case 0x00620009:return VR::LO; +case 0x0062000a:return VR::SQ; +case 0x0062000b:return VR::US; +case 0x0062000c:return VR::US; +case 0x0062000d:return VR::US; +case 0x0062000e:return VR::US; +case 0x0062000f:return VR::SQ; +case 0x00620010:return VR::CS; +case 0x00640002:return VR::SQ; +case 0x00640003:return VR::UI; +case 0x00640005:return VR::SQ; +case 0x00640007:return VR::UL; +case 0x00640008:return VR::FD; +case 0x00640009:return VR::OF; +case 0x0064000f:return VR::SQ; +case 0x00640010:return VR::SQ; +case 0x00660001:return VR::UL; +case 0x00660002:return VR::SQ; +case 0x00660003:return VR::UL; +case 0x00660004:return VR::LT; +case 0x00660009:return VR::CS; +case 0x0066000a:return VR::FL; +case 0x0066000b:return VR::LO; +case 0x0066000c:return VR::FL; +case 0x0066000d:return VR::CS; +case 0x0066000e:return VR::CS; +case 0x00660010:return VR::CS; +case 0x00660011:return VR::SQ; +case 0x00660012:return VR::SQ; +case 0x00660013:return VR::SQ; +case 0x00660015:return VR::UL; +case 0x00660016:return VR::OF; +case 0x00660017:return VR::FL; +case 0x00660018:return VR::FL; +case 0x00660019:return VR::FL; +case 0x0066001a:return VR::FL; +case 0x0066001b:return VR::FL; +case 0x0066001c:return VR::FL; +case 0x0066001e:return VR::UL; +case 0x0066001f:return VR::US; +case 0x00660020:return VR::FL; +case 0x00660021:return VR::OF; +case 0x00660023:return VR::OW; +case 0x00660024:return VR::OW; +case 0x00660025:return VR::OW; +case 0x00660026:return VR::SQ; +case 0x00660027:return VR::SQ; +case 0x00660028:return VR::SQ; +case 0x00660029:return VR::OW; +case 0x0066002a:return VR::UL; +case 0x0066002b:return VR::SQ; +case 0x0066002c:return VR::UL; +case 0x0066002d:return VR::SQ; +case 0x0066002e:return VR::SQ; +case 0x0066002f:return VR::SQ; +case 0x00660030:return VR::SQ; +case 0x00660031:return VR::LO; +case 0x00660032:return VR::LT; +case 0x00660034:return VR::SQ; +case 0x00660035:return VR::SQ; +case 0x00660036:return VR::LO; +case 0x00686210:return VR::LO; +case 0x00686221:return VR::LO; +case 0x00686222:return VR::SQ; +case 0x00686223:return VR::CS; +case 0x00686224:return VR::SQ; +case 0x00686225:return VR::SQ; +case 0x00686226:return VR::DT; +case 0x00686230:return VR::SQ; +case 0x00686260:return VR::SQ; +case 0x00686265:return VR::SQ; +case 0x00686270:return VR::DT; +case 0x00686280:return VR::ST; +case 0x006862a0:return VR::SQ; +case 0x006862a5:return VR::FD; +case 0x006862c0:return VR::SQ; +case 0x006862d0:return VR::US; +case 0x006862d5:return VR::LO; +case 0x006862e0:return VR::SQ; +case 0x006862f0:return VR::FD; +case 0x006862f2:return VR::FD; +case 0x00686300:return VR::OB; +case 0x00686310:return VR::US; +case 0x00686320:return VR::SQ; +case 0x00686330:return VR::US; +case 0x00686340:return VR::LO; +case 0x00686345:return VR::ST; +case 0x00686346:return VR::FD; +case 0x00686347:return VR::FD; +case 0x00686350:return VR::US; +case 0x00686360:return VR::SQ; +case 0x00686380:return VR::LO; +case 0x00686390:return VR::FD; +case 0x006863a0:return VR::SQ; +case 0x006863a4:return VR::SQ; +case 0x006863a8:return VR::SQ; +case 0x006863ac:return VR::SQ; +case 0x006863b0:return VR::SQ; +case 0x006863c0:return VR::US; +case 0x006863d0:return VR::LO; +case 0x006863e0:return VR::SQ; +case 0x006863f0:return VR::US; +case 0x00686400:return VR::SQ; +case 0x00686410:return VR::US; +case 0x00686420:return VR::CS; +case 0x00686430:return VR::SQ; +case 0x00686440:return VR::US; +case 0x00686450:return VR::FD; +case 0x00686460:return VR::FD; +case 0x00686470:return VR::SQ; +case 0x00686490:return VR::FD; +case 0x006864a0:return VR::FD; +case 0x006864c0:return VR::FD; +case 0x006864d0:return VR::FD; +case 0x006864f0:return VR::FD; +case 0x00686500:return VR::SQ; +case 0x00686510:return VR::SQ; +case 0x00686520:return VR::SQ; +case 0x00686530:return VR::US; +case 0x00686540:return VR::LO; +case 0x00686545:return VR::SQ; +case 0x00686550:return VR::SQ; +case 0x00686560:return VR::FD; +case 0x00686590:return VR::FD; +case 0x006865a0:return VR::SQ; +case 0x006865b0:return VR::FD; +case 0x006865d0:return VR::FD; +case 0x006865e0:return VR::SQ; +case 0x006865f0:return VR::FD; +case 0x00686610:return VR::FD; +case 0x00686620:return VR::FD; +case 0x00700001:return VR::SQ; +case 0x00700002:return VR::CS; +case 0x00700003:return VR::CS; +case 0x00700004:return VR::CS; +case 0x00700005:return VR::CS; +case 0x00700006:return VR::ST; +case 0x00700008:return VR::SQ; +case 0x00700009:return VR::SQ; +case 0x00700010:return VR::FL; +case 0x00700011:return VR::FL; +case 0x00700012:return VR::CS; +case 0x00700014:return VR::FL; +case 0x00700015:return VR::CS; +case 0x00700020:return VR::US; +case 0x00700021:return VR::US; +case 0x00700022:return VR::FL; +case 0x00700023:return VR::CS; +case 0x00700024:return VR::CS; +case 0x00700040:return VR::IS; +case 0x00700041:return VR::CS; +case 0x00700042:return VR::US; +case 0x00700050:return VR::US; +case 0x00700051:return VR::US; +case 0x00700052:return VR::SL; +case 0x00700053:return VR::SL; +case 0x0070005a:return VR::SQ; +case 0x00700060:return VR::SQ; +case 0x00700062:return VR::IS; +case 0x00700066:return VR::US; +case 0x00700067:return VR::US; +case 0x00700068:return VR::LO; +case 0x00700080:return VR::CS; +case 0x00700081:return VR::LO; +case 0x00700082:return VR::DA; +case 0x00700083:return VR::TM; +case 0x00700084:return VR::PN; +case 0x00700086:return VR::SQ; +case 0x00700087:return VR::SQ; +case 0x00700100:return VR::CS; +case 0x00700101:return VR::DS; +case 0x00700102:return VR::IS; +case 0x00700103:return VR::FL; +case 0x00700207:return VR::LO; +case 0x00700208:return VR::ST; +case 0x00700209:return VR::SQ; +case 0x00700226:return VR::UL; +case 0x00700227:return VR::LO; +case 0x00700228:return VR::CS; +case 0x00700229:return VR::LO; +case 0x00700230:return VR::FD; +case 0x00700231:return VR::SQ; +case 0x00700232:return VR::SQ; +case 0x00700233:return VR::SQ; +case 0x00700234:return VR::SQ; +case 0x00700241:return VR::US; +case 0x00700242:return VR::CS; +case 0x00700243:return VR::CS; +case 0x00700244:return VR::CS; +case 0x00700245:return VR::FL; +case 0x00700246:return VR::FL; +case 0x00700247:return VR::US; +case 0x00700248:return VR::CS; +case 0x00700249:return VR::CS; +case 0x00700250:return VR::CS; +case 0x00700251:return VR::US; +case 0x00700252:return VR::US; +case 0x00700253:return VR::FL; +case 0x00700254:return VR::CS; +case 0x00700255:return VR::UL; +case 0x00700256:return VR::OB; +case 0x00700257:return VR::CS; +case 0x00700258:return VR::FL; +case 0x00700261:return VR::FL; +case 0x00700262:return VR::FL; +case 0x00700273:return VR::FL; +case 0x00700274:return VR::CS; +case 0x00700278:return VR::CS; +case 0x00700279:return VR::CS; +case 0x00700282:return VR::CS; +case 0x00700284:return VR::FL; +case 0x00700285:return VR::FL; +case 0x00700287:return VR::SQ; +case 0x00700288:return VR::FL; +case 0x00700289:return VR::SH; +case 0x00700294:return VR::CS; +case 0x00700295:return VR::UL; +case 0x00700306:return VR::CS; +case 0x00700308:return VR::SQ; +case 0x00700309:return VR::SQ; +case 0x0070030a:return VR::SQ; +case 0x0070030c:return VR::CS; +case 0x0070030d:return VR::SQ; +case 0x0070030f:return VR::ST; +case 0x00700310:return VR::SH; +case 0x00700311:return VR::SQ; +case 0x00700312:return VR::FD; +case 0x00700314:return VR::SQ; +case 0x00700318:return VR::SQ; +case 0x0070031a:return VR::UI; +case 0x0070031c:return VR::SQ; +case 0x0070031e:return VR::SQ; +case 0x00700401:return VR::US; +case 0x00700402:return VR::SQ; +case 0x00700403:return VR::FL; +case 0x00700404:return VR::SQ; +case 0x00700405:return VR::CS; +case 0x00720002:return VR::SH; +case 0x00720004:return VR::LO; +case 0x00720006:return VR::CS; +case 0x00720008:return VR::LO; +case 0x0072000a:return VR::DT; +case 0x0072000c:return VR::SQ; +case 0x0072000e:return VR::SQ; +case 0x00720010:return VR::LO; +case 0x00720012:return VR::SQ; +case 0x00720014:return VR::US; +case 0x00720020:return VR::SQ; +case 0x00720022:return VR::SQ; +case 0x00720024:return VR::CS; +case 0x00720026:return VR::AT; +case 0x00720028:return VR::US; +case 0x00720030:return VR::SQ; +case 0x00720032:return VR::US; +case 0x00720034:return VR::CS; +case 0x00720038:return VR::US; +case 0x0072003a:return VR::CS; +case 0x0072003c:return VR::SS; +case 0x0072003e:return VR::SQ; +case 0x00720040:return VR::LO; +case 0x00720050:return VR::CS; +case 0x00720052:return VR::AT; +case 0x00720054:return VR::LO; +case 0x00720056:return VR::LO; +case 0x00720060:return VR::AT; +case 0x00720062:return VR::CS; +case 0x00720064:return VR::IS; +case 0x00720066:return VR::LO; +case 0x00720068:return VR::LT; +case 0x0072006a:return VR::PN; +case 0x0072006c:return VR::SH; +case 0x0072006e:return VR::ST; +case 0x00720070:return VR::UT; +case 0x00720072:return VR::DS; +case 0x00720074:return VR::FD; +case 0x00720076:return VR::FL; +case 0x00720078:return VR::UL; +case 0x0072007a:return VR::US; +case 0x0072007c:return VR::SL; +case 0x0072007e:return VR::SS; +case 0x00720080:return VR::SQ; +case 0x00720100:return VR::US; +case 0x00720102:return VR::SQ; +case 0x00720104:return VR::US; +case 0x00720106:return VR::US; +case 0x00720108:return VR::FD; +case 0x0072010a:return VR::US; +case 0x0072010c:return VR::US; +case 0x0072010e:return VR::US; +case 0x00720200:return VR::SQ; +case 0x00720202:return VR::US; +case 0x00720203:return VR::LO; +case 0x00720204:return VR::US; +case 0x00720206:return VR::LO; +case 0x00720208:return VR::CS; +case 0x00720210:return VR::SQ; +case 0x00720212:return VR::US; +case 0x00720214:return VR::SQ; +case 0x00720216:return VR::US; +case 0x00720218:return VR::US; +case 0x00720300:return VR::SQ; +case 0x00720302:return VR::US; +case 0x00720304:return VR::CS; +case 0x00720306:return VR::US; +case 0x00720308:return VR::US; +case 0x00720310:return VR::CS; +case 0x00720312:return VR::CS; +case 0x00720314:return VR::US; +case 0x00720316:return VR::CS; +case 0x00720318:return VR::US; +case 0x00720320:return VR::US; +case 0x00720330:return VR::FD; +case 0x00720400:return VR::SQ; +case 0x00720402:return VR::CS; +case 0x00720404:return VR::CS; +case 0x00720406:return VR::CS; +case 0x00720420:return VR::US; +case 0x00720421:return VR::US; +case 0x00720422:return VR::SQ; +case 0x00720424:return VR::SQ; +case 0x00720427:return VR::SQ; +case 0x00720430:return VR::SQ; +case 0x00720432:return VR::US; +case 0x00720434:return VR::CS; +case 0x00720500:return VR::CS; +case 0x00720510:return VR::CS; +case 0x00720512:return VR::FD; +case 0x00720514:return VR::FD; +case 0x00720516:return VR::CS; +case 0x00720520:return VR::CS; +case 0x00720600:return VR::SQ; +case 0x00720602:return VR::CS; +case 0x00720604:return VR::CS; +case 0x00720700:return VR::CS; +case 0x00720702:return VR::CS; +case 0x00720704:return VR::CS; +case 0x00720705:return VR::SQ; +case 0x00720706:return VR::CS; +case 0x00720710:return VR::CS; +case 0x00720712:return VR::CS; +case 0x00720714:return VR::CS; +case 0x00720716:return VR::CS; +case 0x00720717:return VR::CS; +case 0x00720718:return VR::CS; +case 0x00740120:return VR::FD; +case 0x00740121:return VR::FD; +case 0x00741000:return VR::CS; +case 0x00741002:return VR::SQ; +case 0x00741004:return VR::DS; +case 0x00741006:return VR::ST; +case 0x00741008:return VR::SQ; +case 0x0074100a:return VR::ST; +case 0x0074100c:return VR::LO; +case 0x0074100e:return VR::SQ; +case 0x00741020:return VR::SQ; +case 0x00741022:return VR::CS; +case 0x00741024:return VR::IS; +case 0x00741026:return VR::FD; +case 0x00741027:return VR::FD; +case 0x00741028:return VR::FD; +case 0x0074102a:return VR::FD; +case 0x0074102b:return VR::FD; +case 0x0074102c:return VR::FD; +case 0x0074102d:return VR::FD; +case 0x00741030:return VR::SQ; +case 0x00741032:return VR::CS; +case 0x00741034:return VR::CS; +case 0x00741036:return VR::CS; +case 0x00741038:return VR::DS; +case 0x0074103a:return VR::DS; +case 0x00741040:return VR::SQ; +case 0x00741042:return VR::SQ; +case 0x00741044:return VR::SQ; +case 0x00741046:return VR::SQ; +case 0x00741048:return VR::SQ; +case 0x0074104a:return VR::SQ; +case 0x0074104c:return VR::SQ; +case 0x0074104e:return VR::SQ; +case 0x00741050:return VR::SQ; +case 0x00741052:return VR::AT; +case 0x00741054:return VR::UL; +case 0x00741056:return VR::LO; +case 0x00741057:return VR::IS; +case 0x00741200:return VR::CS; +case 0x00741202:return VR::LO; +case 0x00741204:return VR::LO; +case 0x00741210:return VR::SQ; +case 0x00741212:return VR::SQ; +case 0x00741216:return VR::SQ; +case 0x00741220:return VR::SQ; +case 0x00741222:return VR::LO; +case 0x00741224:return VR::SQ; +case 0x00741230:return VR::LO; +case 0x00741234:return VR::AE; +case 0x00741236:return VR::AE; +case 0x00741238:return VR::LT; +case 0x00741242:return VR::CS; +case 0x00741244:return VR::CS; +case 0x00741246:return VR::CS; +case 0x00741324:return VR::UL; +case 0x00741338:return VR::FD; +case 0x0074133a:return VR::FD; +case 0x00760001:return VR::LO; +case 0x00760003:return VR::LO; +case 0x00760006:return VR::LO; +case 0x00760008:return VR::SQ; +case 0x0076000a:return VR::CS; +case 0x0076000c:return VR::SQ; +case 0x0076000e:return VR::SQ; +case 0x00760010:return VR::SQ; +case 0x00760020:return VR::SQ; +case 0x00760030:return VR::LO; +case 0x00760032:return VR::SQ; +case 0x00760034:return VR::CS; +case 0x00760036:return VR::CS; +case 0x00760038:return VR::CS; +case 0x00760040:return VR::SQ; +case 0x00760055:return VR::US; +case 0x00760060:return VR::SQ; +case 0x00760070:return VR::US; +case 0x00760080:return VR::US; +case 0x00760090:return VR::US; +case 0x007600a0:return VR::US; +case 0x007600b0:return VR::US; +case 0x007600c0:return VR::US; +case 0x00780001:return VR::LO; +case 0x00780010:return VR::ST; +case 0x00780020:return VR::LO; +case 0x00780024:return VR::LO; +case 0x00780026:return VR::SQ; +case 0x00780028:return VR::SQ; +case 0x0078002a:return VR::SQ; +case 0x0078002e:return VR::US; +case 0x00780050:return VR::FD; +case 0x00780060:return VR::FD; +case 0x00780070:return VR::SQ; +case 0x00780090:return VR::FD; +case 0x007800a0:return VR::FD; +case 0x007800b0:return VR::SQ; +case 0x007800b2:return VR::LO; +case 0x007800b4:return VR::SQ; +case 0x007800b6:return VR::US; +case 0x007800b8:return VR::US; +case 0x00880130:return VR::SH; +case 0x00880140:return VR::UI; +case 0x00880200:return VR::SQ; +case 0x00880904:return VR::LO; +case 0x00880906:return VR::ST; +case 0x00880910:return VR::LO; +case 0x00880912:return VR::LO; +case 0x01000410:return VR::CS; +case 0x01000420:return VR::DT; +case 0x01000424:return VR::LT; +case 0x01000426:return VR::LO; +case 0x04000005:return VR::US; +case 0x04000010:return VR::UI; +case 0x04000015:return VR::CS; +case 0x04000020:return VR::AT; +case 0x04000100:return VR::UI; +case 0x04000105:return VR::DT; +case 0x04000110:return VR::CS; +case 0x04000115:return VR::OB; +case 0x04000120:return VR::OB; +case 0x04000305:return VR::CS; +case 0x04000310:return VR::OB; +case 0x04000401:return VR::SQ; +case 0x04000402:return VR::SQ; +case 0x04000403:return VR::SQ; +case 0x04000404:return VR::OB; +case 0x04000500:return VR::SQ; +case 0x04000510:return VR::UI; +case 0x04000520:return VR::OB; +case 0x04000550:return VR::SQ; +case 0x04000561:return VR::SQ; +case 0x04000562:return VR::DT; +case 0x04000563:return VR::LO; +case 0x04000564:return VR::LO; +case 0x04000565:return VR::CS; +case 0x20000010:return VR::IS; +case 0x2000001e:return VR::SQ; +case 0x20000020:return VR::CS; +case 0x20000030:return VR::CS; +case 0x20000040:return VR::CS; +case 0x20000050:return VR::LO; +case 0x20000060:return VR::IS; +case 0x20000061:return VR::IS; +case 0x20000062:return VR::CS; +case 0x20000063:return VR::CS; +case 0x20000065:return VR::CS; +case 0x20000067:return VR::CS; +case 0x20000069:return VR::CS; +case 0x2000006a:return VR::CS; +case 0x200000a0:return VR::US; +case 0x200000a1:return VR::US; +case 0x200000a2:return VR::SQ; +case 0x200000a4:return VR::SQ; +case 0x200000a8:return VR::SQ; +case 0x20000500:return VR::SQ; +case 0x20000510:return VR::SQ; +case 0x20100010:return VR::ST; +case 0x20100030:return VR::CS; +case 0x20100040:return VR::CS; +case 0x20100050:return VR::CS; +case 0x20100052:return VR::CS; +case 0x20100054:return VR::CS; +case 0x20100060:return VR::CS; +case 0x20100080:return VR::CS; +case 0x201000a6:return VR::CS; +case 0x201000a7:return VR::CS; +case 0x201000a8:return VR::CS; +case 0x201000a9:return VR::CS; +case 0x20100100:return VR::CS; +case 0x20100110:return VR::CS; +case 0x20100120:return VR::US; +case 0x20100130:return VR::US; +case 0x20100140:return VR::CS; +case 0x20100150:return VR::ST; +case 0x20100152:return VR::LT; +case 0x20100154:return VR::IS; +case 0x2010015e:return VR::US; +case 0x20100160:return VR::US; +case 0x20100376:return VR::DS; +case 0x20100500:return VR::SQ; +case 0x20100510:return VR::SQ; +case 0x20100520:return VR::SQ; +case 0x20200010:return VR::US; +case 0x20200020:return VR::CS; +case 0x20200030:return VR::DS; +case 0x20200040:return VR::CS; +case 0x20200050:return VR::CS; +case 0x202000a0:return VR::CS; +case 0x202000a2:return VR::CS; +case 0x20200110:return VR::SQ; +case 0x20200111:return VR::SQ; +case 0x20200130:return VR::SQ; +case 0x20200140:return VR::SQ; +case 0x20300010:return VR::US; +case 0x20300020:return VR::LO; +case 0x20400010:return VR::SQ; +case 0x20400011:return VR::US; +case 0x20400020:return VR::SQ; +case 0x20400060:return VR::CS; +case 0x20400070:return VR::CS; +case 0x20400072:return VR::CS; +case 0x20400074:return VR::US; +case 0x20400080:return VR::CS; +case 0x20400082:return VR::CS; +case 0x20400090:return VR::CS; +case 0x20400100:return VR::CS; +case 0x20400500:return VR::SQ; +case 0x20500010:return VR::SQ; +case 0x20500020:return VR::CS; +case 0x20500500:return VR::SQ; +case 0x21000010:return VR::SH; +case 0x21000020:return VR::CS; +case 0x21000030:return VR::CS; +case 0x21000040:return VR::DA; +case 0x21000050:return VR::TM; +case 0x21000070:return VR::AE; +case 0x21000140:return VR::AE; +case 0x21000160:return VR::SH; +case 0x21000170:return VR::IS; +case 0x21000500:return VR::SQ; +case 0x21100010:return VR::CS; +case 0x21100020:return VR::CS; +case 0x21100030:return VR::LO; +case 0x21100099:return VR::SH; +case 0x21200010:return VR::CS; +case 0x21200050:return VR::SQ; +case 0x21200070:return VR::SQ; +case 0x21300010:return VR::SQ; +case 0x21300015:return VR::SQ; +case 0x21300030:return VR::SQ; +case 0x21300040:return VR::SQ; +case 0x21300050:return VR::SQ; +case 0x21300060:return VR::SQ; +case 0x21300080:return VR::SQ; +case 0x213000a0:return VR::SQ; +case 0x213000c0:return VR::SQ; +case 0x22000001:return VR::CS; +case 0x22000002:return VR::UT; +case 0x22000003:return VR::CS; +case 0x22000004:return VR::LT; +case 0x22000005:return VR::LT; +case 0x22000006:return VR::CS; +case 0x22000007:return VR::CS; +case 0x22000008:return VR::CS; +case 0x22000009:return VR::CS; +case 0x2200000a:return VR::CS; +case 0x2200000b:return VR::US; +case 0x2200000c:return VR::LO; +case 0x2200000d:return VR::SQ; +case 0x2200000e:return VR::AT; +case 0x2200000f:return VR::CS; +case 0x22000020:return VR::CS; +case 0x30020002:return VR::SH; +case 0x30020003:return VR::LO; +case 0x30020004:return VR::ST; +case 0x3002000a:return VR::CS; +case 0x3002000c:return VR::CS; +case 0x3002000d:return VR::DS; +case 0x3002000e:return VR::DS; +case 0x30020010:return VR::DS; +case 0x30020011:return VR::DS; +case 0x30020012:return VR::DS; +case 0x30020020:return VR::SH; +case 0x30020022:return VR::DS; +case 0x30020024:return VR::DS; +case 0x30020026:return VR::DS; +case 0x30020028:return VR::DS; +case 0x30020029:return VR::IS; +case 0x30020030:return VR::SQ; +case 0x30020032:return VR::DS; +case 0x30020034:return VR::DS; +case 0x30020040:return VR::SQ; +case 0x30020041:return VR::CS; +case 0x30020042:return VR::DS; +case 0x30020050:return VR::SQ; +case 0x30020051:return VR::CS; +case 0x30020052:return VR::SH; +case 0x30040001:return VR::CS; +case 0x30040002:return VR::CS; +case 0x30040004:return VR::CS; +case 0x30040006:return VR::LO; +case 0x30040008:return VR::DS; +case 0x3004000a:return VR::CS; +case 0x3004000c:return VR::DS; +case 0x3004000e:return VR::DS; +case 0x30040010:return VR::SQ; +case 0x30040012:return VR::DS; +case 0x30040014:return VR::CS; +case 0x30040040:return VR::DS; +case 0x30040042:return VR::DS; +case 0x30040050:return VR::SQ; +case 0x30040052:return VR::DS; +case 0x30040054:return VR::CS; +case 0x30040056:return VR::IS; +case 0x30040058:return VR::DS; +case 0x30040060:return VR::SQ; +case 0x30040062:return VR::CS; +case 0x30040070:return VR::DS; +case 0x30040072:return VR::DS; +case 0x30040074:return VR::DS; +case 0x30060002:return VR::SH; +case 0x30060004:return VR::LO; +case 0x30060006:return VR::ST; +case 0x30060008:return VR::DA; +case 0x30060009:return VR::TM; +case 0x30060010:return VR::SQ; +case 0x30060012:return VR::SQ; +case 0x30060014:return VR::SQ; +case 0x30060016:return VR::SQ; +case 0x30060020:return VR::SQ; +case 0x30060022:return VR::IS; +case 0x30060024:return VR::UI; +case 0x30060026:return VR::LO; +case 0x30060028:return VR::ST; +case 0x3006002a:return VR::IS; +case 0x3006002c:return VR::DS; +case 0x30060030:return VR::SQ; +case 0x30060033:return VR::CS; +case 0x30060036:return VR::CS; +case 0x30060038:return VR::LO; +case 0x30060039:return VR::SQ; +case 0x30060040:return VR::SQ; +case 0x30060042:return VR::CS; +case 0x30060044:return VR::DS; +case 0x30060045:return VR::DS; +case 0x30060046:return VR::IS; +case 0x30060048:return VR::IS; +case 0x30060049:return VR::IS; +case 0x30060050:return VR::DS; +case 0x30060080:return VR::SQ; +case 0x30060082:return VR::IS; +case 0x30060084:return VR::IS; +case 0x30060085:return VR::SH; +case 0x30060086:return VR::SQ; +case 0x30060088:return VR::ST; +case 0x300600a0:return VR::SQ; +case 0x300600a4:return VR::CS; +case 0x300600a6:return VR::PN; +case 0x300600b0:return VR::SQ; +case 0x300600b2:return VR::CS; +case 0x300600b4:return VR::DS; +case 0x300600b6:return VR::SQ; +case 0x300600b7:return VR::US; +case 0x300600b8:return VR::FL; +case 0x300600c0:return VR::SQ; +case 0x300600c2:return VR::UI; +case 0x300600c4:return VR::CS; +case 0x300600c6:return VR::DS; +case 0x300600c8:return VR::LO; +case 0x30080010:return VR::SQ; +case 0x30080012:return VR::ST; +case 0x30080014:return VR::CS; +case 0x30080016:return VR::DS; +case 0x30080020:return VR::SQ; +case 0x30080021:return VR::SQ; +case 0x30080022:return VR::IS; +case 0x30080024:return VR::DA; +case 0x30080025:return VR::TM; +case 0x3008002a:return VR::CS; +case 0x3008002b:return VR::SH; +case 0x3008002c:return VR::CS; +case 0x30080030:return VR::SQ; +case 0x30080032:return VR::DS; +case 0x30080033:return VR::DS; +case 0x30080036:return VR::DS; +case 0x30080037:return VR::DS; +case 0x3008003a:return VR::DS; +case 0x3008003b:return VR::DS; +case 0x30080040:return VR::SQ; +case 0x30080041:return VR::SQ; +case 0x30080042:return VR::DS; +case 0x30080044:return VR::DS; +case 0x30080045:return VR::FL; +case 0x30080046:return VR::FL; +case 0x30080047:return VR::FL; +case 0x30080048:return VR::DS; +case 0x30080050:return VR::SQ; +case 0x30080052:return VR::DS; +case 0x30080054:return VR::DA; +case 0x30080056:return VR::DA; +case 0x3008005a:return VR::IS; +case 0x30080060:return VR::SQ; +case 0x30080061:return VR::AT; +case 0x30080062:return VR::AT; +case 0x30080063:return VR::IS; +case 0x30080064:return VR::IS; +case 0x30080065:return VR::AT; +case 0x30080066:return VR::ST; +case 0x30080068:return VR::SQ; +case 0x3008006a:return VR::FL; +case 0x30080070:return VR::SQ; +case 0x30080072:return VR::IS; +case 0x30080074:return VR::ST; +case 0x30080076:return VR::DS; +case 0x30080078:return VR::DS; +case 0x3008007a:return VR::DS; +case 0x30080080:return VR::SQ; +case 0x30080082:return VR::IS; +case 0x30080090:return VR::SQ; +case 0x30080092:return VR::IS; +case 0x300800a0:return VR::SQ; +case 0x300800b0:return VR::SQ; +case 0x300800c0:return VR::SQ; +case 0x300800d0:return VR::SQ; +case 0x300800e0:return VR::SQ; +case 0x300800f0:return VR::SQ; +case 0x300800f2:return VR::SQ; +case 0x300800f4:return VR::SQ; +case 0x300800f6:return VR::SQ; +case 0x30080100:return VR::SQ; +case 0x30080105:return VR::LO; +case 0x30080110:return VR::SQ; +case 0x30080116:return VR::CS; +case 0x30080120:return VR::SQ; +case 0x30080122:return VR::IS; +case 0x30080130:return VR::SQ; +case 0x30080132:return VR::DS; +case 0x30080134:return VR::DS; +case 0x30080136:return VR::IS; +case 0x30080138:return VR::IS; +case 0x3008013a:return VR::DS; +case 0x3008013c:return VR::DS; +case 0x30080140:return VR::SQ; +case 0x30080142:return VR::IS; +case 0x30080150:return VR::SQ; +case 0x30080152:return VR::IS; +case 0x30080160:return VR::SQ; +case 0x30080162:return VR::DA; +case 0x30080164:return VR::TM; +case 0x30080166:return VR::DA; +case 0x30080168:return VR::TM; +case 0x30080200:return VR::CS; +case 0x30080202:return VR::ST; +case 0x30080220:return VR::SQ; +case 0x30080223:return VR::IS; +case 0x30080224:return VR::CS; +case 0x30080230:return VR::CS; +case 0x30080240:return VR::SQ; +case 0x30080250:return VR::DA; +case 0x30080251:return VR::TM; +case 0x300a0002:return VR::SH; +case 0x300a0003:return VR::LO; +case 0x300a0004:return VR::ST; +case 0x300a0006:return VR::DA; +case 0x300a0007:return VR::TM; +case 0x300a0009:return VR::LO; +case 0x300a000a:return VR::CS; +case 0x300a000b:return VR::LO; +case 0x300a000c:return VR::CS; +case 0x300a000e:return VR::ST; +case 0x300a0010:return VR::SQ; +case 0x300a0012:return VR::IS; +case 0x300a0013:return VR::UI; +case 0x300a0014:return VR::CS; +case 0x300a0015:return VR::CS; +case 0x300a0016:return VR::LO; +case 0x300a0018:return VR::DS; +case 0x300a001a:return VR::DS; +case 0x300a0020:return VR::CS; +case 0x300a0021:return VR::DS; +case 0x300a0022:return VR::DS; +case 0x300a0023:return VR::DS; +case 0x300a0025:return VR::DS; +case 0x300a0026:return VR::DS; +case 0x300a0027:return VR::DS; +case 0x300a0028:return VR::DS; +case 0x300a002a:return VR::DS; +case 0x300a002b:return VR::DS; +case 0x300a002c:return VR::DS; +case 0x300a002d:return VR::DS; +case 0x300a0040:return VR::SQ; +case 0x300a0042:return VR::IS; +case 0x300a0043:return VR::SH; +case 0x300a0044:return VR::DS; +case 0x300a0046:return VR::DS; +case 0x300a0048:return VR::SQ; +case 0x300a004a:return VR::DS; +case 0x300a004b:return VR::FL; +case 0x300a004c:return VR::DS; +case 0x300a004e:return VR::DS; +case 0x300a004f:return VR::FL; +case 0x300a0050:return VR::FL; +case 0x300a0051:return VR::DS; +case 0x300a0052:return VR::DS; +case 0x300a0053:return VR::DS; +case 0x300a0055:return VR::CS; +case 0x300a0070:return VR::SQ; +case 0x300a0071:return VR::IS; +case 0x300a0072:return VR::LO; +case 0x300a0078:return VR::IS; +case 0x300a0079:return VR::IS; +case 0x300a007a:return VR::IS; +case 0x300a007b:return VR::LT; +case 0x300a0080:return VR::IS; +case 0x300a0082:return VR::DS; +case 0x300a0084:return VR::DS; +case 0x300a0086:return VR::DS; +case 0x300a0088:return VR::FL; +case 0x300a0089:return VR::FL; +case 0x300a008a:return VR::FL; +case 0x300a00a0:return VR::IS; +case 0x300a00a2:return VR::DS; +case 0x300a00a4:return VR::DS; +case 0x300a00b0:return VR::SQ; +case 0x300a00b2:return VR::SH; +case 0x300a00b3:return VR::CS; +case 0x300a00b4:return VR::DS; +case 0x300a00b6:return VR::SQ; +case 0x300a00b8:return VR::CS; +case 0x300a00ba:return VR::DS; +case 0x300a00bb:return VR::FL; +case 0x300a00bc:return VR::IS; +case 0x300a00be:return VR::DS; +case 0x300a00c0:return VR::IS; +case 0x300a00c2:return VR::LO; +case 0x300a00c3:return VR::ST; +case 0x300a00c4:return VR::CS; +case 0x300a00c6:return VR::CS; +case 0x300a00c7:return VR::CS; +case 0x300a00c8:return VR::IS; +case 0x300a00ca:return VR::SQ; +case 0x300a00cc:return VR::LO; +case 0x300a00ce:return VR::CS; +case 0x300a00d0:return VR::IS; +case 0x300a00d1:return VR::SQ; +case 0x300a00d2:return VR::IS; +case 0x300a00d3:return VR::CS; +case 0x300a00d4:return VR::SH; +case 0x300a00d5:return VR::IS; +case 0x300a00d6:return VR::DS; +case 0x300a00d7:return VR::FL; +case 0x300a00d8:return VR::DS; +case 0x300a00d9:return VR::FL; +case 0x300a00da:return VR::DS; +case 0x300a00db:return VR::FL; +case 0x300a00dc:return VR::SH; +case 0x300a00dd:return VR::ST; +case 0x300a00e0:return VR::IS; +case 0x300a00e1:return VR::SH; +case 0x300a00e2:return VR::DS; +case 0x300a00e3:return VR::SQ; +case 0x300a00e4:return VR::IS; +case 0x300a00e5:return VR::SH; +case 0x300a00e6:return VR::DS; +case 0x300a00e7:return VR::IS; +case 0x300a00e8:return VR::IS; +case 0x300a00e9:return VR::DS; +case 0x300a00ea:return VR::DS; +case 0x300a00eb:return VR::DS; +case 0x300a00ec:return VR::DS; +case 0x300a00ed:return VR::IS; +case 0x300a00ee:return VR::CS; +case 0x300a00f0:return VR::IS; +case 0x300a00f2:return VR::DS; +case 0x300a00f3:return VR::FL; +case 0x300a00f4:return VR::SQ; +case 0x300a00f5:return VR::SH; +case 0x300a00f6:return VR::DS; +case 0x300a00f7:return VR::FL; +case 0x300a00f8:return VR::CS; +case 0x300a00f9:return VR::LO; +case 0x300a00fa:return VR::CS; +case 0x300a00fb:return VR::CS; +case 0x300a00fc:return VR::IS; +case 0x300a00fe:return VR::LO; +case 0x300a0100:return VR::DS; +case 0x300a0102:return VR::DS; +case 0x300a0104:return VR::IS; +case 0x300a0106:return VR::DS; +case 0x300a0107:return VR::SQ; +case 0x300a0108:return VR::SH; +case 0x300a0109:return VR::CS; +case 0x300a010a:return VR::LO; +case 0x300a010c:return VR::DS; +case 0x300a010e:return VR::DS; +case 0x300a0110:return VR::IS; +case 0x300a0111:return VR::SQ; +case 0x300a0112:return VR::IS; +case 0x300a0114:return VR::DS; +case 0x300a0115:return VR::DS; +case 0x300a0116:return VR::SQ; +case 0x300a0118:return VR::CS; +case 0x300a011a:return VR::SQ; +case 0x300a011c:return VR::DS; +case 0x300a011e:return VR::DS; +case 0x300a011f:return VR::CS; +case 0x300a0120:return VR::DS; +case 0x300a0121:return VR::CS; +case 0x300a0122:return VR::DS; +case 0x300a0123:return VR::CS; +case 0x300a0124:return VR::DS; +case 0x300a0125:return VR::DS; +case 0x300a0126:return VR::CS; +case 0x300a0128:return VR::DS; +case 0x300a0129:return VR::DS; +case 0x300a012a:return VR::DS; +case 0x300a012c:return VR::DS; +case 0x300a012e:return VR::DS; +case 0x300a0130:return VR::DS; +case 0x300a0134:return VR::DS; +case 0x300a0140:return VR::FL; +case 0x300a0142:return VR::CS; +case 0x300a0144:return VR::FL; +case 0x300a0146:return VR::CS; +case 0x300a0148:return VR::FL; +case 0x300a014a:return VR::FL; +case 0x300a014c:return VR::CS; +case 0x300a014e:return VR::FL; +case 0x300a0180:return VR::SQ; +case 0x300a0182:return VR::IS; +case 0x300a0183:return VR::LO; +case 0x300a0184:return VR::LO; +case 0x300a0190:return VR::SQ; +case 0x300a0192:return VR::CS; +case 0x300a0194:return VR::SH; +case 0x300a0196:return VR::ST; +case 0x300a0198:return VR::SH; +case 0x300a0199:return VR::FL; +case 0x300a019a:return VR::FL; +case 0x300a01a0:return VR::SQ; +case 0x300a01a2:return VR::CS; +case 0x300a01a4:return VR::SH; +case 0x300a01a6:return VR::ST; +case 0x300a01a8:return VR::SH; +case 0x300a01b0:return VR::CS; +case 0x300a01b2:return VR::ST; +case 0x300a01b4:return VR::SQ; +case 0x300a01b6:return VR::CS; +case 0x300a01b8:return VR::SH; +case 0x300a01ba:return VR::ST; +case 0x300a01bc:return VR::DS; +case 0x300a01d0:return VR::ST; +case 0x300a01d2:return VR::DS; +case 0x300a01d4:return VR::DS; +case 0x300a01d6:return VR::DS; +case 0x300a0200:return VR::CS; +case 0x300a0202:return VR::CS; +case 0x300a0206:return VR::SQ; +case 0x300a0210:return VR::SQ; +case 0x300a0212:return VR::IS; +case 0x300a0214:return VR::CS; +case 0x300a0216:return VR::LO; +case 0x300a0218:return VR::DS; +case 0x300a021a:return VR::DS; +case 0x300a0222:return VR::DS; +case 0x300a0224:return VR::DS; +case 0x300a0226:return VR::LO; +case 0x300a0228:return VR::DS; +case 0x300a0229:return VR::CS; +case 0x300a022a:return VR::DS; +case 0x300a022b:return VR::DS; +case 0x300a022c:return VR::DA; +case 0x300a022e:return VR::TM; +case 0x300a0230:return VR::SQ; +case 0x300a0232:return VR::CS; +case 0x300a0234:return VR::IS; +case 0x300a0236:return VR::LO; +case 0x300a0238:return VR::LO; +case 0x300a0240:return VR::IS; +case 0x300a0242:return VR::SH; +case 0x300a0244:return VR::LO; +case 0x300a0250:return VR::DS; +case 0x300a0260:return VR::SQ; +case 0x300a0262:return VR::IS; +case 0x300a0263:return VR::SH; +case 0x300a0264:return VR::CS; +case 0x300a0266:return VR::LO; +case 0x300a026a:return VR::DS; +case 0x300a026c:return VR::DS; +case 0x300a0280:return VR::SQ; +case 0x300a0282:return VR::IS; +case 0x300a0284:return VR::DS; +case 0x300a0286:return VR::DS; +case 0x300a0288:return VR::CS; +case 0x300a028a:return VR::IS; +case 0x300a028c:return VR::DS; +case 0x300a0290:return VR::IS; +case 0x300a0291:return VR::SH; +case 0x300a0292:return VR::CS; +case 0x300a0294:return VR::LO; +case 0x300a0296:return VR::DS; +case 0x300a0298:return VR::LO; +case 0x300a029c:return VR::DS; +case 0x300a029e:return VR::DS; +case 0x300a02a0:return VR::DS; +case 0x300a02a2:return VR::IS; +case 0x300a02a4:return VR::DS; +case 0x300a02b0:return VR::SQ; +case 0x300a02b2:return VR::IS; +case 0x300a02b3:return VR::SH; +case 0x300a02b4:return VR::LO; +case 0x300a02b8:return VR::DS; +case 0x300a02ba:return VR::DS; +case 0x300a02c8:return VR::DS; +case 0x300a02d0:return VR::SQ; +case 0x300a02d2:return VR::DS; +case 0x300a02d4:return VR::DS; +case 0x300a02d6:return VR::DS; +case 0x300a02e0:return VR::CS; +case 0x300a02e1:return VR::CS; +case 0x300a02e2:return VR::DS; +case 0x300a02e3:return VR::FL; +case 0x300a02e4:return VR::FL; +case 0x300a02e5:return VR::FL; +case 0x300a02e6:return VR::FL; +case 0x300a02e7:return VR::FL; +case 0x300a02e8:return VR::FL; +case 0x300a02ea:return VR::SQ; +case 0x300a02eb:return VR::LT; +case 0x300a0302:return VR::IS; +case 0x300a0304:return VR::IS; +case 0x300a0306:return VR::SS; +case 0x300a0308:return VR::CS; +case 0x300a030a:return VR::FL; +case 0x300a030c:return VR::SQ; +case 0x300a030d:return VR::FL; +case 0x300a030f:return VR::SH; +case 0x300a0312:return VR::IS; +case 0x300a0314:return VR::SQ; +case 0x300a0316:return VR::IS; +case 0x300a0318:return VR::SH; +case 0x300a0320:return VR::CS; +case 0x300a0322:return VR::LO; +case 0x300a0330:return VR::IS; +case 0x300a0332:return VR::SQ; +case 0x300a0334:return VR::IS; +case 0x300a0336:return VR::SH; +case 0x300a0338:return VR::CS; +case 0x300a033a:return VR::LO; +case 0x300a033c:return VR::FL; +case 0x300a0340:return VR::IS; +case 0x300a0342:return VR::SQ; +case 0x300a0344:return VR::IS; +case 0x300a0346:return VR::SH; +case 0x300a0348:return VR::CS; +case 0x300a034a:return VR::LO; +case 0x300a034c:return VR::SH; +case 0x300a0350:return VR::CS; +case 0x300a0352:return VR::SH; +case 0x300a0354:return VR::LO; +case 0x300a0356:return VR::FL; +case 0x300a0358:return VR::FL; +case 0x300a035a:return VR::FL; +case 0x300a0360:return VR::SQ; +case 0x300a0362:return VR::LO; +case 0x300a0364:return VR::FL; +case 0x300a0366:return VR::FL; +case 0x300a0370:return VR::SQ; +case 0x300a0372:return VR::LO; +case 0x300a0374:return VR::FL; +case 0x300a0380:return VR::SQ; +case 0x300a0382:return VR::FL; +case 0x300a0384:return VR::FL; +case 0x300a0386:return VR::FL; +case 0x300a0388:return VR::FL; +case 0x300a038a:return VR::FL; +case 0x300a0390:return VR::SH; +case 0x300a0392:return VR::IS; +case 0x300a0394:return VR::FL; +case 0x300a0396:return VR::FL; +case 0x300a0398:return VR::FL; +case 0x300a039a:return VR::IS; +case 0x300a03a0:return VR::SQ; +case 0x300a03a2:return VR::SQ; +case 0x300a03a4:return VR::SQ; +case 0x300a03a6:return VR::SQ; +case 0x300a03a8:return VR::SQ; +case 0x300a03aa:return VR::SQ; +case 0x300a03ac:return VR::SQ; +case 0x300a0401:return VR::SQ; +case 0x300a0402:return VR::ST; +case 0x300a0410:return VR::SQ; +case 0x300a0412:return VR::FL; +case 0x300a0420:return VR::SQ; +case 0x300a0421:return VR::SH; +case 0x300a0422:return VR::ST; +case 0x300a0423:return VR::CS; +case 0x300a0424:return VR::IS; +case 0x300a0431:return VR::SQ; +case 0x300a0432:return VR::CS; +case 0x300a0433:return VR::FL; +case 0x300a0434:return VR::FL; +case 0x300a0435:return VR::FL; +case 0x300a0436:return VR::FL; +case 0x300c0002:return VR::SQ; +case 0x300c0004:return VR::SQ; +case 0x300c0006:return VR::IS; +case 0x300c0007:return VR::IS; +case 0x300c0008:return VR::DS; +case 0x300c0009:return VR::DS; +case 0x300c000a:return VR::SQ; +case 0x300c000c:return VR::IS; +case 0x300c000e:return VR::IS; +case 0x300c0020:return VR::SQ; +case 0x300c0022:return VR::IS; +case 0x300c0040:return VR::SQ; +case 0x300c0042:return VR::SQ; +case 0x300c0050:return VR::SQ; +case 0x300c0051:return VR::IS; +case 0x300c0055:return VR::SQ; +case 0x300c0060:return VR::SQ; +case 0x300c006a:return VR::IS; +case 0x300c0080:return VR::SQ; +case 0x300c00a0:return VR::IS; +case 0x300c00b0:return VR::SQ; +case 0x300c00c0:return VR::IS; +case 0x300c00d0:return VR::IS; +case 0x300c00e0:return VR::IS; +case 0x300c00f0:return VR::IS; +case 0x300c00f2:return VR::SQ; +case 0x300c00f4:return VR::IS; +case 0x300c00f6:return VR::IS; +case 0x300c0100:return VR::IS; +case 0x300c0102:return VR::IS; +case 0x300c0104:return VR::IS; +case 0x300e0002:return VR::CS; +case 0x300e0004:return VR::DA; +case 0x300e0005:return VR::TM; +case 0x300e0008:return VR::PN; +case 0x40000010:return VR::LT; +case 0x40004000:return VR::LT; +case 0x40080040:return VR::SH; +case 0x40080042:return VR::LO; +case 0x40080050:return VR::SQ; +case 0x400800ff:return VR::CS; +case 0x40080100:return VR::DA; +case 0x40080101:return VR::TM; +case 0x40080102:return VR::PN; +case 0x40080103:return VR::LO; +case 0x40080108:return VR::DA; +case 0x40080109:return VR::TM; +case 0x4008010a:return VR::PN; +case 0x4008010b:return VR::ST; +case 0x4008010c:return VR::PN; +case 0x40080111:return VR::SQ; +case 0x40080112:return VR::DA; +case 0x40080113:return VR::TM; +case 0x40080114:return VR::PN; +case 0x40080115:return VR::LT; +case 0x40080117:return VR::SQ; +case 0x40080118:return VR::SQ; +case 0x40080119:return VR::PN; +case 0x4008011a:return VR::LO; +case 0x40080200:return VR::SH; +case 0x40080202:return VR::LO; +case 0x40080210:return VR::CS; +case 0x40080212:return VR::CS; +case 0x40080300:return VR::ST; +case 0x40084000:return VR::ST; +case 0x40100001:return VR::CS; +case 0x40100002:return VR::CS; +case 0x40100004:return VR::SQ; +case 0x40101001:return VR::SQ; +case 0x40101004:return VR::FL; +case 0x40101005:return VR::FL; +case 0x40101006:return VR::OB; +case 0x40101007:return VR::SH; +case 0x40101008:return VR::CS; +case 0x40101009:return VR::CS; +case 0x4010100a:return VR::SQ; +case 0x40101010:return VR::US; +case 0x40101011:return VR::SQ; +case 0x40101012:return VR::CS; +case 0x40101013:return VR::LT; +case 0x40101014:return VR::CS; +case 0x40101015:return VR::CS; +case 0x40101016:return VR::FL; +case 0x40101017:return VR::FL; +case 0x40101018:return VR::FL; +case 0x40101019:return VR::FL; +case 0x4010101a:return VR::SH; +case 0x4010101b:return VR::FL; +case 0x4010101c:return VR::FL; +case 0x4010101d:return VR::FL; +case 0x4010101e:return VR::SH; +case 0x4010101f:return VR::SH; +case 0x40101020:return VR::CS; +case 0x40101021:return VR::CS; +case 0x40101023:return VR::FL; +case 0x40101024:return VR::CS; +case 0x40101025:return VR::DT; +case 0x40101026:return VR::DT; +case 0x40101027:return VR::CS; +case 0x40101028:return VR::CS; +case 0x40101029:return VR::LO; +case 0x4010102a:return VR::SH; +case 0x4010102b:return VR::DT; +case 0x40101031:return VR::CS; +case 0x40101033:return VR::US; +case 0x40101034:return VR::US; +case 0x40101037:return VR::SQ; +case 0x40101038:return VR::SQ; +case 0x40101039:return VR::CS; +case 0x4010103a:return VR::CS; +case 0x40101041:return VR::DT; +case 0x40101042:return VR::CS; +case 0x40101043:return VR::FL; +case 0x40101044:return VR::CS; +case 0x40101045:return VR::SQ; +case 0x40101046:return VR::CS; +case 0x40101047:return VR::SQ; +case 0x40101048:return VR::CS; +case 0x40101051:return VR::LO; +case 0x40101052:return VR::SH; +case 0x40101053:return VR::LO; +case 0x40101054:return VR::SH; +case 0x40101055:return VR::SH; +case 0x40101056:return VR::CS; +case 0x40101058:return VR::SH; +case 0x40101059:return VR::CS; +case 0x40101060:return VR::FL; +case 0x40101061:return VR::FL; +case 0x40101062:return VR::FL; +case 0x40101064:return VR::SQ; +case 0x40101067:return VR::CS; +case 0x40101068:return VR::LT; +case 0x40101069:return VR::FL; +case 0x4010106c:return VR::OB; +case 0x4ffe0001:return VR::SQ; +case 0x50000005:return VR::US; +case 0x50000010:return VR::US; +case 0x50000020:return VR::CS; +case 0x50000022:return VR::LO; +case 0x50000030:return VR::SH; +case 0x50000040:return VR::SH; +case 0x50000103:return VR::US; +case 0x50000104:return VR::US; +case 0x50000105:return VR::US; +case 0x50000106:return VR::SH; +case 0x50000110:return VR::US; +case 0x50000112:return VR::US; +case 0x50000114:return VR::US; +case 0x50001001:return VR::CS; +case 0x50002000:return VR::US; +case 0x50002002:return VR::US; +case 0x50002004:return VR::US; +case 0x50002006:return VR::UL; +case 0x50002008:return VR::UL; +case 0x5000200a:return VR::UL; +case 0x5000200e:return VR::LT; +case 0x50002500:return VR::LO; +case 0x50002600:return VR::SQ; +case 0x50002610:return VR::US; +case 0x52009229:return VR::SQ; +case 0x52009230:return VR::SQ; +case 0x54000100:return VR::SQ; +case 0x54001004:return VR::US; +case 0x54001006:return VR::CS; +case 0x56000010:return VR::OF; +case 0x56000020:return VR::OF; +case 0x60000010:return VR::US; +case 0x60000011:return VR::US; +case 0x60000012:return VR::US; +case 0x60000015:return VR::IS; +case 0x60000022:return VR::LO; +case 0x60000040:return VR::CS; +case 0x60000045:return VR::LO; +case 0x60000050:return VR::SS; +case 0x60000051:return VR::US; +case 0x60000052:return VR::US; +case 0x60000060:return VR::CS; +case 0x60000061:return VR::SH; +case 0x60000062:return VR::SH; +case 0x60000063:return VR::CS; +case 0x60000066:return VR::AT; +case 0x60000068:return VR::US; +case 0x60000069:return VR::US; +case 0x60000100:return VR::US; +case 0x60000102:return VR::US; +case 0x60000110:return VR::CS; +case 0x60000200:return VR::US; +case 0x60000800:return VR::CS; +case 0x60000802:return VR::US; +case 0x60000803:return VR::AT; +case 0x60000804:return VR::US; +case 0x60001001:return VR::CS; +case 0x60001100:return VR::US; +case 0x60001101:return VR::US; +case 0x60001102:return VR::US; +case 0x60001103:return VR::US; +case 0x60001200:return VR::US; +case 0x60001201:return VR::US; +case 0x60001202:return VR::US; +case 0x60001203:return VR::US; +case 0x60001301:return VR::IS; +case 0x60001302:return VR::DS; +case 0x60001303:return VR::DS; +case 0x60001500:return VR::LO; +case 0x60004000:return VR::LT; +case 0x7fe00020:return VR::OW; +case 0x7fe00030:return VR::OW; +case 0x7fe00040:return VR::OW; +case 0x7f000011:return VR::US; +case 0x7f000020:return VR::OW; +case 0x7f000030:return VR::OW; +case 0x7f000040:return VR::OW; +case 0xfffafffa:return VR::SQ; +case 0xfffcfffc:return VR::OB; + +default: +return VR::INVALID; +} +} + +} // end namespace gdcm diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmTagToVR.h b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmTagToVR.h new file mode 100644 index 0000000..7d1e584 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmTagToVR.h @@ -0,0 +1,23 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMTAGTOVR_H +#define GDCMTAGTOVR_H + +namespace gdcm +{ + class Tag; + VR::VRType GetVRFromTag( Tag const & tag ); +} + +#endif // GDCMTAGTOVR_H diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmTransferSyntax.cxx b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmTransferSyntax.cxx new file mode 100644 index 0000000..756b267 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmTransferSyntax.cxx @@ -0,0 +1,297 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmTransferSyntax.h" +#include "gdcmTrace.h" + +#include +#include + +#include +#include + +namespace gdcm +{ + +//#include "gdcmUIDs.cxx" + +static const char *TSStrings[] = { + // Implicit VR Little Endian + "1.2.840.10008.1.2", + // Implicit VR Big Endian DLX (G.E Private) + "1.2.840.113619.5.2", + // Explicit VR Little Endian + "1.2.840.10008.1.2.1", + // Deflated Explicit VR Little Endian + "1.2.840.10008.1.2.1.99", + // Explicit VR Big Endian + "1.2.840.10008.1.2.2", + // JPEG Baseline (Process 1) + "1.2.840.10008.1.2.4.50", + // JPEG Extended (Process 2 & 4) + "1.2.840.10008.1.2.4.51", + // JPEG Extended (Process 3 & 5) + "1.2.840.10008.1.2.4.52", + // JPEG Spectral Selection, Non-Hierarchical (Process 6 & 8) + "1.2.840.10008.1.2.4.53", + // JPEG Full Progression, Non-Hierarchical (Process 10 & 12) + "1.2.840.10008.1.2.4.55", + // JPEG Lossless, Non-Hierarchical (Process 14) + "1.2.840.10008.1.2.4.57", + // JPEG Lossless, Non-Hierarchical, First-Order Prediction (Process 14, + // [Selection Value 1]) + "1.2.840.10008.1.2.4.70", + // JPEG-LS Lossless Image Compression + "1.2.840.10008.1.2.4.80", + // JPEG-LS Lossy (Near-Lossless) Image Compression + "1.2.840.10008.1.2.4.81", + // JPEG 2000 Lossless + "1.2.840.10008.1.2.4.90", + // JPEG 2000 + "1.2.840.10008.1.2.4.91", + // JPEG 2000 Part 2 Lossless + "1.2.840.10008.1.2.4.92", + // JPEG 2000 Part 2 + "1.2.840.10008.1.2.4.93", + // RLE Lossless + "1.2.840.10008.1.2.5", + // MPEG2 Main Profile @ Main Level + "1.2.840.10008.1.2.4.100", + // Old ACR NEMA, fake a TS + "ImplicitVRBigEndianACRNEMA", +#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + // Weird Papyrus + "1.2.840.10008.1.20", +#endif + "1.3.46.670589.33.1.4.1", + // JPIP Referenced + "1.2.840.10008.1.2.4.94", + // Unknown + "Unknown Transfer Syntax", // Pretty sure we never use this case... + 0 // Compilers have no obligation to finish by NULL, do it ourself +}; + +TransferSyntax::TSType TransferSyntax::GetTSType(const char *cstr) +{ + // trim trailing whitespace + std::string str = cstr; + std::string::size_type notspace = str.find_last_not_of(" ") + 1; + if( notspace != str.size() ) + { + gdcmDebugMacro( "BUGGY HEADER: TS contains " << + str.size()-notspace << " whitespace character(s)" ); + str.erase(notspace); + } + + int i = 0; + while(TSStrings[i] != 0) + //while(TransferSyntaxStrings[i] != 0) + { + if( str == TSStrings[i] ) + //if( str == TransferSyntaxStrings[i] ) + return (TSType)i; + ++i; + } + return TS_END; +} + +const char* TransferSyntax::GetTSString(TSType ts) +{ + assert( ts <= TS_END ); + return TSStrings[(int)ts]; + //return TransferSyntaxStrings[(int)ts]; +} + +bool TransferSyntax::IsImplicit(TSType ts) const +{ + assert( ts != TS_END ); + return ts == ImplicitVRLittleEndian + || ts == ImplicitVRBigEndianACRNEMA + || ts == ImplicitVRBigEndianPrivateGE +#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + || ts == WeirdPapryus +#endif + ; +} + +bool TransferSyntax::IsImplicit() const +{ + if ( TSField == TS_END ) return false; + return TSField == ImplicitVRLittleEndian + || TSField == ImplicitVRBigEndianACRNEMA + || TSField == ImplicitVRBigEndianPrivateGE +#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + || TSField == WeirdPapryus +#endif + ; +} + +bool TransferSyntax::IsExplicit() const +{ + if ( TSField == TS_END ) return false; // important ! + return !IsImplicit(); +} + +bool TransferSyntax::IsLossy() const +{ + if ( + TSField == JPEGBaselineProcess1 || + TSField == JPEGExtendedProcess2_4 || + TSField == JPEGExtendedProcess3_5 || + TSField == JPEGSpectralSelectionProcess6_8 || + TSField == JPEGFullProgressionProcess10_12 || + TSField == JPEGLSNearLossless || + TSField == JPEG2000 || + TSField == JPEG2000Part2 || + TSField == JPIPReferenced || + TSField == MPEG2MainProfile + ) + { + return true; + } + return false; + +} + +// This function really test the kind of compression algorithm and the matching +// transfer syntax. If you use the JPEG compression algorithm (ITU-T T.81, +// ISO/IEC IS 10918-1), You will not be able to declare a lossy compress pixel +// data using JPEGLosslessProcess14_1 For the same reason using J2K (ITU-T +// T.800, ISO/IEC IS 15444-1), you shoult not be allowed to stored an +// irreversible wavelet compressed pixel data in a file declared with transfer +// syntax JPEG2000Lossless. +// Same goes for JPEG-LS (ITU-T T.87, ISO/IEC IS 14495-1), and to some extent +// RLE which does not even allow lossy compression... +bool TransferSyntax::CanStoreLossy() const +{ + if ( + TSField == JPEGLosslessProcess14 || + TSField == JPEGLosslessProcess14_1 || + TSField == JPEGLSLossless || + TSField == JPEG2000Lossless || + TSField == JPEG2000Part2Lossless || + TSField == RLELossless + ) + { + return false; + } + return true; +} + +bool TransferSyntax::IsLossless() const +{ + if ( + TSField == JPEGBaselineProcess1 || + TSField == JPEGExtendedProcess2_4 || + TSField == JPEGExtendedProcess3_5 || + TSField == JPEGSpectralSelectionProcess6_8 || + TSField == JPEGFullProgressionProcess10_12 || + // TSField == JPEGLSNearLossless || -> can be lossy & lossless + // TSField == JPEG2000 || -> can be lossy & lossless + // TSField == JPEG2000Part2 || -> can be lossy & lossless + // TSField == JPIPReferenced || -> can be lossy & lossless + TSField == MPEG2MainProfile + ) + { + return false; + } + return true; +} + +// By implementation those two functions form a partition +bool TransferSyntax::IsExplicit(TSType ts) const +{ + assert( ts != TS_END ); + return !IsImplicit(ts); +} + +TransferSyntax::NegociatedType TransferSyntax::GetNegociatedType() const +{ + if( TSField == TS_END ) + { + return TransferSyntax::Unknown; + } + else if( IsImplicit(TSField) ) + { + return TransferSyntax::Implicit; + } + return TransferSyntax::Explicit; +} + +bool TransferSyntax::IsLittleEndian(TSType ts) const +{ + assert( ts != TS_END ); + return !IsBigEndian(ts); +} + +bool TransferSyntax::IsBigEndian(TSType ts) const +{ + assert( ts != TS_END ); + return ts == ExplicitVRBigEndian +// || ts == ImplicitVRBigEndianPrivateGE // Indeed this is LittleEndian + || ts == ImplicitVRBigEndianACRNEMA; +} + +SwapCode TransferSyntax::GetSwapCode() const +{ + assert( TSField != TS_END ); + if( IsBigEndian( TSField ) ) + { + return SwapCode::BigEndian; + } + assert( IsLittleEndian( TSField ) ); + return SwapCode::LittleEndian; +} + +bool TransferSyntax::IsEncoded() const +{ + return TSField == DeflatedExplicitVRLittleEndian; +} + +bool TransferSyntax::IsEncapsulated() const +{ + bool ret = false; + switch( TSField ) + { + //case ImplicitVRLittleEndian: + //case ImplicitVRBigEndianPrivateGE: + //case ExplicitVRLittleEndian: + //case DeflatedExplicitVRLittleEndian: + //case ExplicitVRBigEndian: + case JPEGBaselineProcess1: + case JPEGExtendedProcess2_4: + case JPEGExtendedProcess3_5: + case JPEGSpectralSelectionProcess6_8: + case JPEGFullProgressionProcess10_12: + case JPEGLosslessProcess14: + case JPEGLosslessProcess14_1: + case JPEGLSLossless: + case JPEGLSNearLossless: + case JPEG2000Lossless: + case JPEG2000: + case JPEG2000Part2Lossless: + case JPEG2000Part2: + case JPIPReferenced: + case RLELossless: + case MPEG2MainProfile: + //case ImplicitVRBigEndianACRNEMA: + //case WeirdPapryus: + ret = true; + break; + default: + ; + } + return ret; +} + +} // end namespace gdcm diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmTransferSyntax.h b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmTransferSyntax.h new file mode 100644 index 0000000..8069e94 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmTransferSyntax.h @@ -0,0 +1,148 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMTRANSFERSYNTAX_H +#define GDCMTRANSFERSYNTAX_H + +#include "gdcmSwapCode.h" + +namespace gdcm +{ + +/** + * \brief Class to manipulate Transfer Syntax + * \note + * TRANSFER SYNTAX (Standard and Private): A set of encoding rules that allow + * Application Entities to unambiguously negotiate the encoding techniques + * (e.g., Data Element structure, byte ordering, compression) they are able to + * support, thereby allowing these Application Entities to communicate. + * + * \todo: The implementation is completely retarded -> see gdcm::UIDs for a replacement + * We need: IsSupported + * We need preprocess of raw/xml file + * We need GetFullName() + * + * Need a notion of Private Syntax. As defined in PS 3.5. Section 9.2 + * + * \see UIDs + */ +class GDCM_EXPORT TransferSyntax +{ +public: + typedef enum { + Unknown = 0, + Explicit, + Implicit + } NegociatedType; + +#if 0 + //NOT FLEXIBLE, since force user to update lib everytime new module + //comes out... + // TODO + typedef enum { + NoSpacing = 0, + PixelSpacing, + ImagerPixelSpacing, + PixelAspectRatio + } ImageSpacingType; + ImageSpacingType GetImageSpacing(); +#endif + + typedef enum { + ImplicitVRLittleEndian = 0, + ImplicitVRBigEndianPrivateGE, + ExplicitVRLittleEndian, + DeflatedExplicitVRLittleEndian, + ExplicitVRBigEndian, + JPEGBaselineProcess1, + JPEGExtendedProcess2_4, + JPEGExtendedProcess3_5, + JPEGSpectralSelectionProcess6_8, + JPEGFullProgressionProcess10_12, + JPEGLosslessProcess14, + JPEGLosslessProcess14_1, + JPEGLSLossless, + JPEGLSNearLossless, + JPEG2000Lossless, + JPEG2000, + JPEG2000Part2Lossless, + JPEG2000Part2, + RLELossless, + MPEG2MainProfile, + ImplicitVRBigEndianACRNEMA, +#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + WeirdPapryus, +#endif + CT_private_ELE, + JPIPReferenced, + TS_END + } TSType; + + // Return the string as written in the official DICOM dict from + // a custom enum type + static const char* GetTSString(TSType ts); + static TSType GetTSType(const char *str); + + NegociatedType GetNegociatedType() const; + + /// \deprecated Return the SwapCode associated with the Transfer Syntax. Be careful with + /// the special GE private syntax the DataSet is written in little endian but + /// the Pixel Data is in Big Endian. + SwapCode GetSwapCode() const; + + bool IsValid() const { return TSField != TS_END; } + + operator TSType () const { return TSField; } + + // FIXME: ImplicitVRLittleEndian used to be the default, but nowadays + // this is rather the ExplicitVRLittleEndian instead...should be change the default ? + TransferSyntax(TSType type = ImplicitVRLittleEndian):TSField(type) {} + + // return if dataset is encoded or not (Deflate Explicit VR) + bool IsEncoded() const; + + bool IsImplicit() const; + bool IsExplicit() const; + + bool IsEncapsulated() const; + + /** Return if the transfer syntax algorithm is a lossy algorithm */ + bool IsLossy() const; + /** Return if the transfer syntax algorithm is a lossless algorithm */ + bool IsLossless() const; + /** return if TransFer Syntax Allow storing of Lossy Pixel Data */ + bool CanStoreLossy() const; + + const char *GetString() const { return TransferSyntax::GetTSString(TSField); } + + friend std::ostream &operator<<(std::ostream &os, const TransferSyntax &ts); +private: + // DO NOT EXPOSE the following. Internal details of TransferSyntax +bool IsImplicit(TSType ts) const; +bool IsExplicit(TSType ts) const; +bool IsLittleEndian(TSType ts) const; +bool IsBigEndian(TSType ts) const; + + TSType TSField; +}; +//----------------------------------------------------------------------------- +inline std::ostream &operator<<(std::ostream &_os, const TransferSyntax &ts) +{ + _os << TransferSyntax::GetTSString(ts); + return _os; + +} + +} // end namespace gdcm + +#endif //GDCMTRANSFERSYNTAX_H diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmUNExplicitDataElement.cxx b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmUNExplicitDataElement.cxx new file mode 100644 index 0000000..9e8519e --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmUNExplicitDataElement.cxx @@ -0,0 +1,57 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmUNExplicitDataElement.h" +#include "gdcmSequenceOfItems.h" +#include "gdcmSequenceOfFragments.h" + +namespace gdcm +{ + +//----------------------------------------------------------------------------- + +VL UNExplicitDataElement::GetLength() const +{ + if( ValueLengthField.IsUndefined() ) + { + assert( ValueField->GetLength().IsUndefined() ); + Value *p = ValueField; + // If this is a SQ we need to compute it's proper length + SequenceOfItems *sq = dynamic_cast(p); + // TODO can factor the code: + if( sq ) + { + return TagField.GetLength() + VRField.GetLength() + + ValueLengthField.GetLength() + sq->ComputeLength(); + } + SequenceOfFragments *sf = dynamic_cast(p); + if( sf ) + { + assert( VRField & (VR::OB | VR::OW) ); + return TagField.GetLength() + VRField.GetLength() + + ValueLengthField.GetLength() + sf->ComputeLength(); + } + assert(0); + return 0; + } + else + { + // Each time VR::GetLength() is 2 then Value Length is coded in 2 + // 4 then Value Length is coded in 4 + assert( !ValueField || ValueField->GetLength() == ValueLengthField ); + return TagField.GetLength() + 2*VRField.GetLength() + ValueLengthField; + } +} + + +} // end namespace gdcm diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmUNExplicitDataElement.h b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmUNExplicitDataElement.h new file mode 100644 index 0000000..6faef70 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmUNExplicitDataElement.h @@ -0,0 +1,52 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMUNEXPLICITDATAELEMENT_H +#define GDCMUNEXPLICITDATAELEMENT_H + +#include "gdcmDataElement.h" + +namespace gdcm +{ +// Data Element (UNExplicit) +/** + * \brief Class to read/write a DataElement as UNExplicit Data Element + * \note bla + */ +class GDCM_EXPORT UNExplicitDataElement : public DataElement +{ +public: + VL GetLength() const; + + template + std::istream &Read(std::istream &is); + + template + std::istream &ReadPreValue(std::istream &is); + + template + std::istream &ReadValue(std::istream &is, bool readvalues = true); + + template + std::istream &ReadWithLength(std::istream &is, VL & length); + + // PURPOSELY do not provide an implementation for writing ! + //template + //const std::ostream &Write(std::ostream &os) const; +}; + +} // end namespace gdcm + +#include "gdcmUNExplicitDataElement.txx" + +#endif //GDCMUNEXPLICITDATAELEMENT_H diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmUNExplicitDataElement.txx b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmUNExplicitDataElement.txx new file mode 100644 index 0000000..799e275 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmUNExplicitDataElement.txx @@ -0,0 +1,235 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#ifndef GDCMUNEXPLICITDATAELEMENT_TXX +#define GDCMUNEXPLICITDATAELEMENT_TXX + +#include "gdcmSequenceOfItems.h" +#include "gdcmSequenceOfFragments.h" +#include "gdcmVL.h" +#include "gdcmParseException.h" + +#include "gdcmValueIO.h" +#include "gdcmSwapper.h" + +namespace gdcm +{ + +//----------------------------------------------------------------------------- +template +std::istream &UNExplicitDataElement::Read(std::istream &is) +{ + ReadPreValue(is); + return ReadValue(is); +} + +template +std::istream &UNExplicitDataElement::ReadPreValue(std::istream &is) +{ + TagField.Read(is); + // See PS 3.5, Data Element Structure With UNExplicit VR + // Read Tag + if( !is ) + { + if( !is.eof() ) // FIXME This should not be needed + { + assert(0 && "Should not happen" ); + } + return is; + } + if( TagField == Tag(0xfffe,0xe0dd) ) + { + ParseException pe; + pe.SetLastElement( *this ); + throw pe; + } + assert( TagField != Tag(0xfffe,0xe0dd) ); + + const Tag itemDelItem(0xfffe,0xe00d); + if( TagField == itemDelItem ) + { + if( !ValueLengthField.Read(is) ) + { + assert(0 && "Should not happen"); + return is; + } + if( ValueLengthField != 0 ) + { + gdcmDebugMacro( + "Item Delimitation Item has a length different from 0" ); + } + // Set pointer to NULL to avoid user error + ValueField = 0; + VRField = VR::INVALID; + return is; + } + + // Read VR + try + { + if( !VRField.Read(is) ) + { + assert(0 && "Should not happen" ); + return is; + } + } + catch( Exception &ex ) + { +#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + // gdcm-MR-PHILIPS-16-Multi-Seq.dcm + // assert( TagField == Tag(0xfffe, 0xe000) ); + // -> For some reason VR is written as {44,0} well I guess this is a VR... + // Technically there is a second bug, dcmtk assume other things when reading this tag, + // so I need to change this tag too, if I ever want dcmtk to read this file. oh well + // 0019004_Baseline_IMG1.dcm + // -> VR is garbage also... + // assert( TagField == Tag(8348,0339) || TagField == Tag(b5e8,0338)) + //gdcmWarningMacro( "Assuming 16 bits VR for Tag=" << + // TagField << " in order to read a buggy DICOM file." ); + //VRField = VR::INVALID; + (void)ex; + ParseException pe; + pe.SetLastElement( *this ); + throw pe; +#else + throw ex; +#endif /* GDCM_SUPPORT_BROKEN_IMPLEMENTATION */ + } + + if( VRField == VR::UN ) + { + // backtrack ... + is.seekg(-2, std::ios::cur); + } + // Read Value Length + if( VR::GetLength(VRField) == 4 && VRField != VR::UN ) + { + if( !ValueLengthField.Read(is) ) + { + assert(0 && "Should not happen"); + return is; + } + } + else + { + // 16bits only + if( !ValueLengthField.template Read16(is) ) + { + assert(0 && "Should not happen"); + return is; + } + } + return is; +} + +template +std::istream &UNExplicitDataElement::ReadValue(std::istream &is, bool readvalues) +{ + if( is.eof() ) return is; + if( ValueLengthField == 0 ) + { + // Simple fast path + ValueField = 0; + return is; + } + + //std::cerr << "exp cur tag=" << TagField << " VR=" << VRField << " VL=" << ValueLengthField << std::endl; + // Read the Value + //assert( ValueField == 0 ); + if( VRField == VR::SQ ) + { + // Check wether or not this is an undefined length sequence + assert( TagField != Tag(0x7fe0,0x0010) ); + ValueField = new SequenceOfItems; + } + else if( ValueLengthField.IsUndefined() ) + { + if( VRField == VR::UN ) + { + // Support cp246 conforming file: + // Enhanced_MR_Image_Storage_PixelSpacingNotIn_0028_0030.dcm (illegal) + // vs + // undefined_length_un_vr.dcm + assert( TagField != Tag(0x7fe0,0x0010) ); + ValueField = new SequenceOfItems; + ValueField->SetLength(ValueLengthField); // perform realloc + try + { + //if( !ValueIO::Read(is,*ValueField) ) // non cp246 + if( !ValueIO::Read(is,*ValueField,readvalues) ) // cp246 compliant + { + assert(0); + } + } + catch( std::exception &) + { + // Must be one of those non-cp246 file... + // but for some reason seekg back to previous offset + Read + // as UNExplicit does not work... + throw Exception( "CP 246" ); + } + return is; + } + else + { + // Ok this is Pixel Data fragmented... + assert( TagField == Tag(0x7fe0,0x0010) ); + assert( VRField & VR::OB_OW ); + ValueField = new SequenceOfFragments; + } + } + else + { + //assert( TagField != Tag(0x7fe0,0x0010) ); + ValueField = new ByteValue; + } + // We have the length we should be able to read the value + ValueField->SetLength(ValueLengthField); // perform realloc + + + if( TagField == Tag(0x2001,0xe05f) + || TagField == Tag(0x2001,0xe100) + || TagField == Tag(0x2005,0xe080) + || TagField == Tag(0x2005,0xe083) + || TagField == Tag(0x2005,0xe084) + || TagField == Tag(0x2005,0xe402) + //TagField.IsPrivate() && VRField == VR::SQ + //-> Does not work for 0029 + //we really need to read item marker + ) + { + assert(0); // Could we possibly be so unlucky to have this mixture of bugs... + } + + if( !ValueIO::Read(is,*ValueField,readvalues) ) + { + ParseException pe; + pe.SetLastElement( *this ); + throw pe; + return is; + } + + return is; +} + +template +std::istream &UNExplicitDataElement::ReadWithLength(std::istream &is, VL & length) +{ + return Read(is); (void)length; +} + + +} // end namespace gdcm + +#endif // GDCMUNEXPLICITDATAELEMENT_TXX diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmUNExplicitImplicitDataElement.cxx b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmUNExplicitImplicitDataElement.cxx new file mode 100644 index 0000000..43d5c2d --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmUNExplicitImplicitDataElement.cxx @@ -0,0 +1,57 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmUNExplicitImplicitDataElement.h" +#include "gdcmSequenceOfItems.h" +#include "gdcmSequenceOfFragments.h" + +namespace gdcm +{ + +//----------------------------------------------------------------------------- + +VL UNExplicitImplicitDataElement::GetLength() const +{ + if( ValueLengthField.IsUndefined() ) + { + assert( ValueField->GetLength().IsUndefined() ); + Value *p = ValueField; + // If this is a SQ we need to compute it's proper length + SequenceOfItems *sq = dynamic_cast(p); + // TODO can factor the code: + if( sq ) + { + return TagField.GetLength() + VRField.GetLength() + + ValueLengthField.GetLength() + sq->ComputeLength(); + } + SequenceOfFragments *sf = dynamic_cast(p); + if( sf ) + { + assert( VRField & (VR::OB | VR::OW) ); + return TagField.GetLength() + VRField.GetLength() + + ValueLengthField.GetLength() + sf->ComputeLength(); + } + assert(0); + return 0; + } + else + { + // Each time VR::GetLength() is 2 then Value Length is coded in 2 + // 4 then Value Length is coded in 4 + assert( !ValueField || ValueField->GetLength() == ValueLengthField ); + return TagField.GetLength() + 2*VRField.GetLength() + ValueLengthField; + } +} + + +} // end namespace gdcm diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmUNExplicitImplicitDataElement.h b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmUNExplicitImplicitDataElement.h new file mode 100644 index 0000000..ee03e8e --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmUNExplicitImplicitDataElement.h @@ -0,0 +1,55 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMUNEXPLICITIMPLICITDATAELEMENT_H +#define GDCMUNEXPLICITIMPLICITDATAELEMENT_H + +#include "gdcmDataElement.h" + +namespace gdcm +{ +// Data Element (ExplicitImplicit) +/** + * \brief Class to read/write a DataElement as ExplicitImplicit Data Element + * This class gather two known bugs: + * 1. GDCM 1.2.0 would rewrite VR=UN Value Length on 2 bytes instead of 4 bytes + * 2. GDCM 1.2.0 would also rewrite DataElement as Implicit when the VR would not be known + * this would only happen in some very rare cases. + * gdcm 2.X design could handle bug #1 or #2 exclusively, this class can now handle + * file which have both issues. + * See: gdcmData/TheralysGDCM120Bug.dcm + */ +class GDCM_EXPORT UNExplicitImplicitDataElement : public DataElement +{ +public: + VL GetLength() const; + + template + std::istream &Read(std::istream &is); + + template + std::istream &ReadPreValue(std::istream &is); + + template + std::istream &ReadValue(std::istream &is); + + // PURPOSELY do not provide an implementation for writing ! + //template + //const std::ostream &Write(std::ostream &os) const; +}; + +} // end namespace gdcm + +#include "gdcmUNExplicitImplicitDataElement.txx" + +#endif //GDCMUNEXPLICITIMPLICITDATAELEMENT_H diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmUNExplicitImplicitDataElement.txx b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmUNExplicitImplicitDataElement.txx new file mode 100644 index 0000000..e1bc51e --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmUNExplicitImplicitDataElement.txx @@ -0,0 +1,75 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#ifndef GDCMUNEXPLICITIMPLICITDATAELEMENT_TXX +#define GDCMUNEXPLICITIMPLICITDATAELEMENT_TXX + +#include "gdcmSequenceOfItems.h" +#include "gdcmSequenceOfFragments.h" +#include "gdcmVL.h" +#include "gdcmUNExplicitDataElement.h" +#include "gdcmImplicitDataElement.h" + +#include "gdcmValueIO.h" +#include "gdcmSwapper.h" + +namespace gdcm +{ +//----------------------------------------------------------------------------- +template +std::istream &UNExplicitImplicitDataElement::Read(std::istream &is) +{ + ReadPreValue(is); + return ReadValue(is); +} + +template +std::istream &UNExplicitImplicitDataElement::ReadPreValue(std::istream &is) +{ + assert(0); + //DataElement &de = *this;//unused de, fires a warning on macos + //de.template ReadPreValue( is ); + return is; +} + +template +std::istream &UNExplicitImplicitDataElement::ReadValue(std::istream &is) +{ + if( is.eof() ) return is; + DataElement &de = *this; + try + { + //de.template ReadValue( is ); + } + catch(ParseException &ex) + { + de.SetVR( VR::INVALID ); // EXTREMELY IMPORTANT ! + if( ex.GetLastElement().GetTag() == Tag(0xfffe,0xe0dd) ) + { + // We have never read the 2 bytes for the VR, since exception raised earlier + is.seekg( -4, std::ios::cur ); + } + else + { + is.seekg( -6, std::ios::cur ); + } + //de.template ReadValue( is ); + } + return is; +} + + +} // end namespace gdcm + +#endif // GDCMUNEXPLICITIMPLICITDATAELEMENT_TXX diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmVL.h b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmVL.h new file mode 100644 index 0000000..c4d5ec5 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmVL.h @@ -0,0 +1,135 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMVL_H +#define GDCMVL_H + +#include "gdcmTypes.h" + +#include + +namespace gdcm +{ + +/** + * \brief Value Length + * \warning this is a 4bytes value ! Do not try to use it for 2bytes value + * length + */ +class GDCM_EXPORT VL +{ +public: + typedef uint32_t Type; + VL(uint32_t vl = 0) : ValueLength(vl) { } + + // FIXME: ugly + static uint32_t GetVL32Max() { return 0xFFFFFFFF; } + static uint16_t GetVL16Max() { return 0xFFFF; } + + bool IsUndefined() const { + return ValueLength == 0xFFFFFFFF; + } + void SetToUndefined() { + ValueLength = 0xFFFFFFFF; + } + + /// Return whether or not the VL is odd or not. + bool IsOdd() const { + return !IsUndefined() && ValueLength % 2; + } + + /// += operator + VL& operator+=(VL const &vl) { + ValueLength += vl.ValueLength; + return *this; + } + VL& operator++() { + ++ValueLength; + return *this; + } + VL operator++(int) { + uint32_t tmp(ValueLength); + ++ValueLength; + return tmp; + } + + operator uint32_t () const { return ValueLength; } + + VL GetLength() const { + // VL cannot know it's length...well in implicit yes... + // TODO: need to check we cannot call this function from an Explicit element + return 4; + } + + friend std::ostream& operator<<(std::ostream& os, const VL& vl); + + // PURPOSELY not implemented (could not differenciate 16bits vs 32bits VL) + //friend std::istream& operator>>(std::istream& is, VL& n); + + template + std::istream &Read(std::istream &is) + { + is.read((char*)(&ValueLength), sizeof(uint32_t)); + TSwap::SwapArray(&ValueLength,1); + return is; + } + + template + std::istream &Read16(std::istream &is) + { + uint16_t copy; + is.read((char*)(©), sizeof(uint16_t)); + TSwap::SwapArray(©,1); + ValueLength = copy; + assert( ValueLength <= 65535 /*UINT16_MAX*/ ); // ?? doh ! + return is; + } + + template + const std::ostream &Write(std::ostream &os) const + { + uint32_t copy = ValueLength; + if( IsOdd() ) + { + ++copy; + } + TSwap::SwapArray(©,1); + return os.write((char*)(©), sizeof(uint32_t)); + } + + template + const std::ostream &Write16(std::ostream &os) const + { + assert( ValueLength <= 65535 /*UINT16_MAX*/ ); + uint16_t copy = (uint16_t)ValueLength; + if( IsOdd() ) + { + ++copy; + } + TSwap::SwapArray(©,1); + return os.write((char*)(©), sizeof(uint16_t)); + } + +private: + uint32_t ValueLength; +}; +//---------------------------------------------------------------------------- +inline std::ostream& operator<<(std::ostream& os, const VL& val) +{ + os << /*std::hex <<*/ val.ValueLength; + return os; +} + +} // end namespace gdcm + +#endif //GDCMVL_H diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmVM.cxx b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmVM.cxx new file mode 100644 index 0000000..d46bbfd --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmVM.cxx @@ -0,0 +1,438 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmVM.h" +#include +#include // abort +#include // strcmp + +namespace gdcm +{ + +static const char *VMStrings[] = { + "INVALID", + "1", + "2", + "3", + "4", + "5", + "6", + "8", + "9", + "10", + "12", + "16", + "18", + "24", + "28", + "32", + "35", + "99", + "256", + "1-2", + "1-3", + "1-4", + "1-5", + "1-8", + "1-32", + "1-99", + "1-n", + "2-2n", + "2-n", + "3-4", + "3-3n", + "3-n", + "4-4n", + "6-6n", + "7-7n", + "30-30n", + "47-47n", + 0 +}; + +unsigned int VM::GetLength() const +{ + unsigned int len; + switch(VMField) + { + case VM::VM1: + len = VMToLength::Length; + break; + case VM::VM2: + len = VMToLength::Length; + break; + case VM::VM3: + len = VMToLength::Length; + break; + case VM::VM4: + len = VMToLength::Length; + break; + case VM::VM5: + len = VMToLength::Length; + break; + case VM::VM6: + len = VMToLength::Length; + break; + case VM::VM8: + len = VMToLength::Length; + break; + case VM::VM9: + len = VMToLength::Length; + break; + case VM::VM10: + len = VMToLength::Length; + break; + case VM::VM12: + len = VMToLength::Length; + break; + case VM::VM16: + len = VMToLength::Length; + break; + case VM::VM18: + len = VMToLength::Length; + break; + case VM::VM24: + len = VMToLength::Length; + break; + case VM::VM28: + len = VMToLength::Length; + break; + case VM::VM32: + len = VMToLength::Length; + break; + case VM::VM35: + len = VMToLength::Length; + break; + case VM::VM99: + len = VMToLength::Length; + break; + case VM::VM256: + len = VMToLength::Length; + break; + case VM::VM1_2: + case VM::VM1_3: + case VM::VM1_4: + case VM::VM1_5: + case VM::VM1_8: + case VM::VM1_32: + case VM::VM1_99: + case VM::VM1_n: + case VM::VM2_2n: + case VM::VM2_n: + case VM::VM3_4: + case VM::VM3_3n: + case VM::VM3_n: + case VM::VM4_4n: + case VM::VM6_6n: + case VM::VM7_7n: + return 0; + default: + len = 0; + assert(0); + } + assert( len ); + return len; +} + +unsigned int VM::GetIndex(VMType vm) +{ + assert( vm <= VM_END ); + unsigned int l; + switch(vm) + { + case VM0: + l = 0; + break; + case VM1_2: + l = 19; + break; + case VM1_3: + l = 20; + break; + case VM1_4: + l = 21; + break; + case VM1_5: + l = 22; + break; + case VM1_8: + l = 23; + break; + case VM1_32: + l = 24; + break; + case VM1_99: + l = 25; + break; + case VM1_n: + l = 26; + break; + case VM2_2n: + l = 27; + break; + case VM2_n: + l = 28; + break; + case VM3_4: + l = 29; + break; + case VM3_3n: + l = 30; + break; + case VM3_n: + l = 31; + break; + case VM4_4n: + l = 32; + break; + case VM6_6n: + l = 33; + break; + case VM7_7n: + l = 34; + break; + case VM30_30n: + l = 35; + break; + case VM47_47n: + l = 36; + break; + case VM_END: + l = 37; + break; + default: + { + unsigned int a = (unsigned int)vm; + for (l = 0; a > 1; ++l) + a >>= 1; + l++; + } + } + return l; +} + +const char *VM::GetVMString(VMType vm) +{ + unsigned int idx = GetIndex(vm); + assert( idx < sizeof(VMStrings) / sizeof(VMStrings[0]) ); + //assert( idx ); + return VMStrings[idx]; +} + +VM::VMType VM::GetVMType(const char *vm) +{ + if(!vm) return VM::VM_END; + if(!*vm) return VM::VM0; // ?? + for (int i = 0; VMStrings[i] != NULL; i++) + { + //if (strncmp(VMStrings[i],vm,strlen(VMStrings[i])) == 0) + if (strcmp(VMStrings[i],vm) == 0) + { + return (VM::VMType)(i); + } + } + + return VM::VM_END; +} + +// FIXME IsValid will only work for VM defined in public dict... +bool VM::IsValid(int vm1, VMType vm2) +{ + bool r = false; + assert( vm1 >= 0 ); // Still need to check Part 3 + // If you update the VMType, you need to update this code. Hopefully a compiler is + // able to tell when a case is missing + switch(vm2) + { + case VM1: + r = vm1 == 1; + break; + case VM2: + r = vm1 == 2; + break; + case VM3: + r = vm1 == 3; + break; + case VM4: + r = vm1 == 4; + break; + case VM5: + r = vm1 == 5; + break; + case VM6: + r = vm1 == 6; + break; + case VM8: + r = vm1 == 8; + break; + case VM16: + r = vm1 == 16; + break; + case VM24: + r = vm1 == 24; + break; + case VM1_2: + r = (vm1 == 1 || vm1 == 2); + break; + case VM1_3: + r = (vm1 >= 1 && vm1 <= 3); + break; + case VM1_8: + r = (vm1 >= 1 && vm1 <= 8); + break; + case VM1_32: + r = (vm1 >= 1 && vm1 <= 32); + break; + case VM1_99: + r = (vm1 >= 1 && vm1 <= 99); + break; + case VM1_n: + r = (vm1 >= 1); + break; + case VM2_2n: + r = (vm1 >= 2 && !(vm1%2) ); + break; + case VM2_n: + r = (vm1 >= 2); + break; + case VM3_3n: + r = (vm1 >= 3 && !(vm1%3) ); + break; + case VM3_n: + r = (vm1 >= 3); + break; + default: + assert(0); // should not happen + } + return r; +} + +// TODO write some ugly macro to expand the template +//int VM::GetLength() +//{ +//} + +// This function should not be used in production code. +// Indeed this only return a 'guess' at the VM (ie. a lower bound) +VM::VMType VM::GetVMTypeFromLength(unsigned int length, unsigned int size) +{ + // Check first of length is a indeed a multiple of size and that length is != 0 + if ( !length || length % size ) return VM::VM0; + const unsigned int ratio = length / size; + //std::cerr << "RATIO=" << ratio << std::endl; + switch( ratio ) + { + case 1: return VM::VM1; + case 2: return VM::VM2; + case 3: return VM::VM3; + case 4: return VM::VM4; + case 5: return VM::VM5; + case 6: return VM::VM6; + case 8: return VM::VM8; + case 9: return VM::VM9; + case 16: return VM::VM16; + case 24: return VM::VM24; + case 32: return VM::VM32; + default: + return VM::VM1_n; + } +} + +unsigned int VM::GetNumberOfElementsFromArray(const char *array, unsigned int length) +{ + unsigned int c=0; + if( !length || !array ) return 0; + const char *parray = array; + const char *end = array + length; + bool valuefound = false; + for(; parray != end; ++parray) + { + if( *parray == ' ' ) + { + // space char do not count + } + else if( *parray == '\\' ) + { + if( valuefound ) + { + ++c; + valuefound = false; // reset counter + } + } + else + { + valuefound = true; + } + } + if( valuefound ) ++c; + return c; +} + +bool VM::Compatible(VM const &vm) const +{ + // make sure that vm is a numeric value + //assert( vm.VMField <= VM256 ); + if ( VMField == VM::VM0 ) return false; // nothing was found in the dict + if ( vm == VM::VM0 ) return true; // the user was not able to compute the vm from the empty bytevalue + // let's start with the easy case: + if ( VMField == vm.VMField ) return true; + bool r; + switch(VMField) + { + case VM1_2: + r = vm.VMField >= VM::VM1 && vm.VMField <= VM::VM2; + break; + case VM1_3: + r = vm.VMField >= VM::VM1 && vm.VMField <= VM::VM3; + break; + case VM1_8: + r = vm.VMField >= VM::VM1 && vm.VMField <= VM::VM8; + break; + case VM1_32: + r = vm.VMField >= VM::VM1 && vm.VMField <= VM::VM32; + break; + case VM1_99: + r = vm.VMField >= VM::VM1 && vm.VMField <= VM::VM99; + break; + case VM1_n: + r = vm.VMField >= VM::VM1; + break; + case VM2_2n: + { + if( vm == VM1_n ) r = true; // FIXME + else r = vm.VMField >= VM::VM2 && !(vm.GetLength() % 2); + } + break; + case VM2_n: + r = vm.VMField >= VM::VM2; + break; + case VM3_4: + r = vm.VMField == VM::VM3 || vm.VMField == VM::VM4; + break; + case VM3_3n: + r = vm.VMField >= VM::VM3 && !(vm.GetLength() % 3); + break; + case VM3_n: + r = vm.VMField >= VM::VM3; + break; + default: + r = VMField == vm.VMField; + } + if( r ) + { + assert( VMField & vm.VMField ); + } + return r; +} + +} // end namespace gdcm diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmVM.h b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmVM.h new file mode 100644 index 0000000..b63531a --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmVM.h @@ -0,0 +1,191 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMVM_H +#define GDCMVM_H + +#include "gdcmTypes.h" +#include + +namespace gdcm +{ + +/** + * \brief Value Multiplicity + * Looking at the DICOMV3 dict only there is very few cases: + * 1 + * 2 + * 3 + * 4 + * 5 + * 6 + * 8 + * 16 + * 24 + * 1-2 + * 1-3 + * 1-8 + * 1-32 + * 1-99 + * 1-n + * 2-2n + * 2-n + * 3-3n + * 3-n + * + * Some private dict define some more: + * 4-4n + * 1-4 + * 1-5 + * 256 + * 9 + * 3-4 + * + * even more: + * + * 7-7n + * 10 + * 18 + * 12 + * 35 + * 47_47n + * 30_30n + * 28 + * + * 6-6n + */ +class GDCM_EXPORT VM +{ +public: + typedef enum { + VM0 = 0, // aka the invalid VM + VM1 = 1, + VM2 = 2, + VM3 = 4, + VM4 = 8, + VM5 = 16, + VM6 = 32, + VM8 = 64, + VM9 = 128, + VM10 = 256, + VM12 = 512, //1024, + VM16 = 1024, //2048, + VM18 = 2048, //4096, + VM24 = 4096, //8192, + VM28 = 8192, //16384, + VM32 = 16384, //32768, + VM35 = 32768, //65536, + VM99 = 65536, //131072, + VM256 = 131072, //262144, + VM1_2 = VM1 | VM2, + VM1_3 = VM1 | VM2 | VM3, + VM1_4 = VM1 | VM2 | VM3 | VM4, + VM1_5 = VM1 | VM2 | VM3 | VM4 | VM5, + VM1_8 = VM1 | VM2 | VM3 | VM4 | VM5 | VM6 | VM8, +// The following need some work: + VM1_32 = VM1 | VM2 | VM3 | VM4 | VM5 | VM6 | VM8 | VM9 | VM16 | VM24 | VM32, + VM1_99 = VM1 | VM2 | VM3 | VM4 | VM5 | VM6 | VM8 | VM9 | VM16 | VM24 | VM32 | VM99, + VM1_n = VM1 | VM2 | VM3 | VM4 | VM5 | VM6 | VM8 | VM9 | VM16 | VM24 | VM32 | VM99 | VM256, + VM2_2n = VM2 | VM4 | VM6 | VM8 | VM16 | VM24 | VM32 | VM256, + VM2_n = VM2 | VM3 | VM4 | VM5 | VM6 | VM8 | VM9 | VM16 | VM24 | VM32 | VM99 | VM256, + VM3_4 = VM3 | VM4, + VM3_3n = VM3 | VM6 | VM9 | VM24 | VM99 | VM256, + VM3_n = VM3 | VM4 | VM5 | VM6 | VM8 | VM9 | VM16 | VM24 | VM32 | VM99 | VM256, + VM4_4n = VM4 | VM16 | VM24 | VM32 | VM256, + VM6_6n = VM6 | VM12 | VM18 | VM24 , + VM7_7n, + VM30_30n, + VM47_47n, + VM_END = VM1_n + 1 // Custom tag to count number of entry + } VMType; + + /// Return the string as written in the official DICOM dict from + /// a custom enum type + static const char* GetVMString(VMType vm); + static VMType GetVMType(const char *vm); + + /// Check if vm1 is valid compare to vm2, i.e vm1 is element of vm2 + /// vm1 is typically deduce from counting in a ValueField + static bool IsValid(int vm1, VMType vm2); + //bool IsValid() { return VMField != VM0 && VMField < VM_END; } + + /// WARNING: Implementation deficiency + /// The Compatible function is poorly implemented, the reference vm should be coming from + /// the dictionary, while the passed in value is the value guess from the file. + bool Compatible(VM const &vm) const; + + /// + static VMType GetVMTypeFromLength(unsigned int length, unsigned int size); + static unsigned int GetNumberOfElementsFromArray(const char *array, unsigned int length); + + VM(VMType type = VM0):VMField(type) {} + operator VMType () const { return VMField; } + unsigned int GetLength() const; + + friend std::ostream &operator<<(std::ostream &os, const VM &vm); +protected: + static unsigned int GetIndex(VMType vm); + +private: + VMType VMField; +}; +//----------------------------------------------------------------------------- +inline std::ostream& operator<<(std::ostream& _os, const VM &_val) +{ + assert( VM::GetVMString(_val) ); + _os << VM::GetVMString(_val); + return _os; +} + +//template struct LengthToVM; +//template <> struct LengthToVM<1> +//{ enum { TVM = VM::VM1 }; }; + +template struct VMToLength; +#define TYPETOLENGTH(type,length) \ + template<> struct VMToLength \ + { enum { Length = length }; }; +// TODO: Could be generated from XML file +//TYPETOLENGTH(VM0,1) +TYPETOLENGTH(VM1,1) +TYPETOLENGTH(VM2,2) +TYPETOLENGTH(VM3,3) +TYPETOLENGTH(VM4,4) +TYPETOLENGTH(VM5,5) +TYPETOLENGTH(VM6,6) +TYPETOLENGTH(VM8,8) +TYPETOLENGTH(VM9,9) +TYPETOLENGTH(VM10,10) +TYPETOLENGTH(VM12,12) +TYPETOLENGTH(VM16,16) +TYPETOLENGTH(VM18,18) +TYPETOLENGTH(VM24,24) +TYPETOLENGTH(VM28,28) +TYPETOLENGTH(VM32,32) +TYPETOLENGTH(VM35,35) +TYPETOLENGTH(VM99,99) +TYPETOLENGTH(VM256,256) +//TYPETOLENGTH(VM1_2,2) +//TYPETOLENGTH(VM1_3,3) +//TYPETOLENGTH(VM1_8,8) +//TYPETOLENGTH(VM1_32,32) +//TYPETOLENGTH(VM1_99,99) +//TYPETOLENGTH(VM1_n, +//TYPETOLENGTH(VM2_2n, +//TYPETOLENGTH(VM2_n, +//TYPETOLENGTH(VM3_3n, +//TYPETOLENGTH(VM3_n, + +} // end namespace gdcm + +#endif //GDCMVM_H diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmVR.cxx b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmVR.cxx new file mode 100644 index 0000000..7432f77 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmVR.cxx @@ -0,0 +1,549 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmVR.h" +#include // for std::lower_bound +#include +#include + +namespace gdcm +{ + +static const char *VRStrings[] = { + "??", // 0 + "AE", // 1 + "AS", // 2 + "AT", // 3 + "CS", // 4 + "DA", // 5 + "DS", // 6 + "DT", // 7 + "FD", // 8 + "FL", // 9 + "IS", // 10 + "LO", // 11 + "LT", // 12 + "OB", // 13 + "OF", // 14 + "OW", // 15 + "PN", // 16 + "SH", // 17 + "SL", // 18 + "SQ", // 19 + "SS", // 20 + "ST", // 21 + "TM", // 22 + "UI", // 23 + "UL", // 24 + "UN", // 25 + "US", // 26 + "UT", // 27 + "OB or OW", // 28 + "US or SS", // 29 + "US or SS or OW", //30 + 0 +}; + +static VR::VRType VRValue[] = { + VR::INVALID , + VR::AE , + VR::AS , + VR::AT , + VR::CS , + VR::DA , + VR::DS , + VR::DT , + VR::FD , + VR::FL , + VR::IS , + VR::LO , + VR::LT , + VR::OB , + VR::OF , + VR::OW , + VR::PN , + VR::SH , + VR::SL , + VR::SQ , + VR::SS , + VR::ST , + VR::TM , + VR::UI , + VR::UL , + VR::UN , + VR::US , + VR::UT +}; + +bool VR::IsVRFile() const +{ + switch(VRField) + { + case VR::INVALID: + case VR::AE: + case VR::AS: + case VR::AT: + case VR::CS: + case VR::DA: + case VR::DS: + case VR::DT: + case VR::FD: + case VR::FL: + case VR::IS: + case VR::LO: + case VR::LT: + case VR::OB: + case VR::OF: + case VR::OW: + case VR::PN: + case VR::SH: + case VR::SL: + case VR::SQ: + case VR::SS: + case VR::ST: + case VR::TM: + case VR::UI: + case VR::UL: + case VR::UN: + case VR::US: + case VR::UT: + return true; + default: + return false; + } +} + + +unsigned int VR::GetSizeof() const +{ + unsigned int size; + // Question: Should I move all ASCII type VR down to the bottom ? + switch(VRField) + { + case VR::AE: + size = sizeof(VRToType::Type); + break; + case VR::AS: + size = sizeof(VRToType::Type); + break; + case VR::AT: + size = sizeof(VRToType::Type); + break; + case VR::CS: + size = sizeof(VRToType::Type); + break; + case VR::DA: + size = sizeof(VRToType::Type); + break; + case VR::DS: + size = sizeof(VRToType::Type); + break; + case VR::DT: + size = sizeof(VRToType::Type); + break; + case VR::FD: + size = sizeof(VRToType::Type); + break; + case VR::FL: + size = sizeof(VRToType::Type); + break; + case VR::IS: + size = sizeof(VRToType::Type); + break; + case VR::LO: + size = sizeof(VRToType::Type); + break; + case VR::LT: + size = sizeof(VRToType::Type); + break; + case VR::OB: + size = sizeof(VRToType::Type); + break; + case VR::OF: + size = sizeof(VRToType::Type); + break; + case VR::OW: + size = sizeof(VRToType::Type); + break; + case VR::PN: + size = sizeof(VRToType::Type); + break; + case VR::SH: + size = sizeof(VRToType::Type); + break; + case VR::SL: + size = sizeof(VRToType::Type); + break; + case VR::SQ: + size = sizeof(VRToType::Type); + break; + case VR::SS: + size = sizeof(VRToType::Type); + break; + case VR::ST: + size = sizeof(VRToType::Type); + break; + case VR::TM: + size = sizeof(VRToType::Type); + break; + case VR::UI: + size = sizeof(VRToType::Type); + break; + case VR::UL: + size = sizeof(VRToType::Type); + break; + case VR::UN: + size = sizeof(VRToType::Type); + break; + case VR::US: + size = sizeof(VRToType::Type); + break; + case VR::UT: + size = sizeof(VRToType::Type); + break; + case VR::US_SS: + size = sizeof(VRToType::Type); // why not ? + break; + default: + size = 0; + } + assert( size ); + return size; +} + +int VR::GetIndex(VRType vr) +{ + assert( vr <= VR_END ); + int l; + switch(vr) + { + case INVALID: + l = 0; + break; + case OB_OW: + l = 28; + break; + case US_SS: + l = 29; + break; + case US_SS_OW: + l = 30; + break; + case VR_END: + l = 31; + break; + default: + { + int a = (int)vr; + for (l = 0; a > 1; ++l) + a >>= 1; + l++; + } + } + return l; +} + +const char *VR::GetVRString(VRType vr) +{ + int idx = GetIndex(vr); + return VRStrings[idx]; +} + +const char *VR::GetVRStringFromFile(VRType vr) +{ +#if 1 + static const int N = sizeof(VRValue) / sizeof(VRType); + assert( N == 28 ); + static VRType *start = VRValue; + static VRType *end = VRValue+N; + const VRType *p = + std::lower_bound(start, end, vr); + assert( *p == vr ); + assert( (p - start) == GetIndex(vr) ); + return VRStrings[p-start]; +#else + int idx = GetIndex(vr); + return VRStrings[idx]; +#endif +} + +class MySort +{ +public: + bool operator() (const char *a, const char *b) + { + if( a[0] == b[0] ) + return a[1] < b[1]; + return a[0] < b[0]; + } +}; + +// Optimized version for transforming a read VR from DICOM file +// into a VRType (does not support OB_OW for instance) +VR::VRType VR::GetVRTypeFromFile(const char *vr) +{ +/* + * You need to compile with -DNDEBUG + * Running TestReader on gdcmData, leads to 2.2% improvement + */ +#if 1 + static const int N = sizeof(VRValue) / sizeof(VRType); + assert( N == 28 ); + static const char **start = VRStrings+1; + static const char **end = VRStrings+N; + //std::cerr << "VR=" << vr << std::endl; + const char **p = + std::lower_bound(start, end, vr, MySort()); + if( (*p)[0] != vr[0] || (*p)[1] != vr[1] ) + { + return VR::INVALID; + } + assert( (*p)[0] == vr[0] && (*p)[1] == vr[1] ); + VRType r = VRValue[p-start+1]; + assert( r == (VR::VRType)(1 << (p-start)) ); +#else // old version not optimized + VRType r = VR::VR_END; + for (int i = 1; VRStrings[i] != NULL; i++) + { + const char *ref = VRStrings[i]; + // Use lazy evaluation instead of strncmp + if (ref[0] == vr[0] && ref[1] == vr[1] ) + { + r = (VR::VRType)(1 << (i-1)); + break; + } + } +#endif + // postcondition + assert( r != VR::INVALID + && r != VR::OB_OW + && r != VR::US_SS + && r != VR::US_SS_OW + && r != VR::VR_END ); + return r; +} + +VR::VRType VR::GetVRType(const char *vr) +{ + VRType r = VR::VR_END; + if(!vr) return r; + for (int i = 0; VRStrings[i] != NULL; i++) + //if (strncmp(VRStrings[i],vr, strlen(VRStrings[i])) == 0) + if (strcmp(VRStrings[i],vr) == 0) + { + switch(i) + { + case 0: + r = INVALID; + break; + case 28: + r = OB_OW; + break; + case 29: + r = US_SS; + break; + case 30: + r = US_SS_OW; + break; + case 31: + r = VR_END; assert(0); + break; + default: + assert( vr[2] == 0 ); + r = (VR::VRType)(1 << (i-1)); + } + break; // found one value, we can exit the for loop + } + + return r; +} + +bool VR::IsValid(const char *vr) +{ + for (int i = 1; VRStrings[i] != NULL; i++) + { + const char *ref = VRStrings[i]; + // Use lazy evaluation instead of strncmp + if (ref[0] == vr[0] && ref[1] == vr[1] ) + { + assert( i < 28 ); // FIXME + return true; + } + } + return false; +} + +bool VR::IsValid(const char *vr1, VRType vr2) +{ + assert( strlen(vr1) == 2 ); + VR::VRType vr = GetVRType(vr1); + return ((vr & vr2) != 0 ? true : false); +} + +bool VR::IsSwap(const char *vr) +{ + assert( vr[2] == '\0' ); + char vr_swap[3]; + vr_swap[0] = vr[1]; + vr_swap[1] = vr[0]; + vr_swap[2] = '\0'; + assert( GetVRType(vr_swap) != SS ); + return GetVRType(vr_swap) != VR_END; +} + +#define VRTemplateCase(type, rep) \ + case VR::type: \ + return (VR::VRType)VRToEncoding::Mode \ + == VR::rep; +#define VRTemplate(rep) \ +VRTemplateCase(AE,rep) \ +VRTemplateCase(AS,rep) \ +VRTemplateCase(AT,rep) \ +VRTemplateCase(CS,rep) \ +VRTemplateCase(DA,rep) \ +VRTemplateCase(DS,rep) \ +VRTemplateCase(DT,rep) \ +VRTemplateCase(FL,rep) \ +VRTemplateCase(FD,rep) \ +VRTemplateCase(IS,rep) \ +VRTemplateCase(LO,rep) \ +VRTemplateCase(LT,rep) \ +VRTemplateCase(OB,rep) \ +VRTemplateCase(OF,rep) \ +VRTemplateCase(OW,rep) \ +VRTemplateCase(PN,rep) \ +VRTemplateCase(SH,rep) \ +VRTemplateCase(SL,rep) \ +VRTemplateCase(SQ,rep) \ +VRTemplateCase(SS,rep) \ +VRTemplateCase(ST,rep) \ +VRTemplateCase(TM,rep) \ +VRTemplateCase(UI,rep) \ +VRTemplateCase(UL,rep) \ +VRTemplateCase(UN,rep) \ +VRTemplateCase(US,rep) \ +VRTemplateCase(UT,rep) + +bool VR::IsASCII(VRType vr) +{ + //assert( vr != VR::INVALID ); + switch(vr) + { + VRTemplate(VRASCII) + default: + // 1.3.12.2.1107.5.1.4.54035.30000005100516290423400005768-no-phi.dcm has a VR=RT + //assert(0); + return false; + } +} + +bool VR::IsASCII2(VRType vr) +{ + assert( vr != VR::INVALID ); + return + vr == AE || + vr == AS || + vr == CS || + vr == DA || + vr == DS || + vr == DT || + vr == IS || + vr == LO || + vr == LT || + vr == PN || + vr == SH || + vr == ST || + vr == TM || + vr == UI; +} + +bool VR::IsBinary(VRType vr) +{ + //assert( vr != VR::INVALID ); + switch(vr) + { + VRTemplate(VRBINARY) +// TODO FIXME FIXME: + case US_SS_OW: + return true; + case US_SS: + return true; + case OB_OW: + return true; + default: + // 1.3.12.2.1107.5.1.4.54035.30000005100516290423400005768-no-phi.dcm has a VR=RT + //assert(0); + return false; + } +} + +bool VR::IsBinary2(VRType vr) +{ + //assert( vr != OF ); + return + vr == OB || + vr == OW || + vr == OB_OW || + vr == UN || + vr == SQ ; +} + +bool VR::CanDisplay(VRType vr) +{ + return + vr == AE || + vr == AS || + vr == AT || + vr == CS || + vr == DA || + vr == DS || + vr == FL || + vr == FD || + vr == IS || + vr == LO || + vr == LT || + vr == PN || + vr == SH || + vr == SL || + vr == SS || + vr == ST || + vr == TM || + vr == UI || + vr == UL || + vr == US || + vr == UT; +} + +bool VR::Compatible(VR const &vr) const +{ + //if( VRField == VR::INVALID && vr.VRField == VR::INVALID ) return true; + if( vr.VRField == VR::INVALID ) return true; + else if( vr.VRField == VR::UN ) return true; + else return ((VRField & vr.VRField) > 0 ? true : false); +} + +bool VR::IsDual() const +{ + switch(VRField) + { + case OB_OW : + case US_SS : + case US_SS_OW : + return true; + default: + return false; + } +} + + +} // end of namespace gdcm diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmVR.h b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmVR.h new file mode 100644 index 0000000..8c6d513 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmVR.h @@ -0,0 +1,335 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMVR_H +#define GDCMVR_H + +#include "gdcmTag.h" +#include "gdcmTrace.h" +#include "gdcmString.h" + +#include +#include +#include + +//these defines are here to ensure compilation on sunos gcc +#if defined (CS) +# undef CS +#endif +#if defined (DS) +# undef DS +#endif +#if defined (SS) +# undef SS +#endif + + +namespace gdcm +{ + +/** + * \brief VR class + * This is adapted from DICOM standard + * The biggest difference is the INVALID VR + * and the composite one that differ from standard (more like an addition) + * This allow us to represent all the possible case express in the DICOMV3 dict + * \note + * VALUE REPRESENTATION (VR) + * Specifies the data type and format of the Value(s) contained in the + * Value Field of a Data Element. + * VALUE REPRESENTATION FIELD: + * The field where the Value Representation of a Data Element is + * stored in the encoding of a Data Element structure with explicit VR. + */ +class GDCM_EXPORT VR +{ +public: + typedef enum { + // Warning: Do not write if ( vr & VR::INVALID ) but if ( vr == VR::INVALID ) + INVALID = 0, // For Item/(Seq) Item Delimitation Item + AE = 1, + AS = 2, + AT = 4, + CS = 8, + DA = 16, + DS = 32, + DT = 64, + FD = 128, + FL = 256, + IS = 512, + LO = 1024, + LT = 2048, + OB = 4096, + OD = 134217728, // 2^27 + OF = 8192, + OW = 16384, + PN = 32768, + SH = 65536, + SL = 131072, + SQ = 262144, + SS = 524288, + ST = 1048576, + TM = 2097152, + UI = 4194304, + UL = 8388608, + UN = 16777216, + US = 33554432, + UT = 67108864, + OB_OW = OB | OW, + US_SS = US | SS, + US_SS_OW = US | SS | OW, + // The following do not have a VRString equivalent (ie cannot be found in PS 3.6) + VL16 = AE | AS | AT | CS | DA | DS | DT | FD | FL | IS | LO | LT | PN | SH | SL | SS | ST | TM | UI | UL | US, // if( VR & VL16 ) => VR has its VL coded over 16bits + VL32 = OB | OW | OD | OF | SQ | UN | UT, // if( VR & VL32 ) => VR has its VL coded over 32bits + VRASCII = AE | AS | CS | DA | DS | DT | IS | LO | LT | PN | SH | ST | TM | UI | UT, + VRBINARY = AT | FL | FD | OB | OD | OF | OW | SL | SQ | SS | UL | UN | US, // FIXME: UN ? + // PS 3.5: + // Data Elements with a VR of SQ, OD, OF, OW, OB or UN shall always have a Value Multiplicity of one. + // GDCM is adding a couple more: AS, LT, ST, UT + VR_VM1 = AS | LT | ST | UT | SQ | OF | OD | OW | OB | UN, // All those VR have a VM1 + VRALL = VRASCII | VRBINARY, + VR_END = UT+1 // Invalid VR, need to be max(VRType)+1 + } VRType; + + static const char *GetVRString(VRType vr); + + // This function will only look at the very first two chars nothing else + static VRType GetVRTypeFromFile(const char *vr); + + // You need to make sure end of string is \0 + static VRType GetVRType(const char *vr); + static const char *GetVRStringFromFile(VRType vr); + + static bool IsValid(const char *vr); + // Check if vr1 is valid against vr2, + // Typically vr1 is read from the file and vr2 is taken from the dict + static bool IsValid(const char *vr1, VRType vr2); + //static bool IsValid(const VRType &vr1, const VRType &vr2); + // Find out if the string read is byte swapped + static bool IsSwap(const char *vr); + + // Size read on disk + // FIXME: int ? + int GetLength() const { + return VR::GetLength(VRField); + } + unsigned int GetSizeof() const; + static uint32_t GetLength(VRType vr) { + //if( vr == VR::INVALID ) return 4; + if( vr & VL32 ) + { + return 4; + } + else + return 2; + } + + // Some use of template metaprograming with ugly macro + static bool IsBinary(VRType vr); + static bool IsASCII(VRType vr); + // TODO: REMOVE ME + static bool CanDisplay(VRType vr); + // TODO: REMOVE ME + static bool IsBinary2(VRType vr); + // TODO: REMOVE ME + static bool IsASCII2(VRType vr); + + VR(VRType vr = INVALID):VRField(vr) { } + //VR(VR const &vr):VRField(vr.VRField) { } + std::istream &Read(std::istream &is) + { + char vr[2]; + is.read(vr, 2); + VRField = GetVRTypeFromFile(vr); + assert( VRField != VR::VR_END ); + //assert( VRField != VR::INVALID ); + if( VRField == VR::INVALID ) throw Exception( "INVALID VR" ); + if( VRField & VL32 ) + { +#if 0 + // For some reason this seems slower on my linux box... + is.seekg(2, std::ios::cur ); +#else + char dum[2]; + is.read(dum, 2); + if( !(dum[0] == 0 && dum[1] == 0 )) + { + // JDDICOM_Sample4.dcm + gdcmDebugMacro( "32bits VR contains non zero bytes. Skipped" ); + } +#endif + } + return is; + } + + const std::ostream &Write(std::ostream &os) const + { + VRType vrfield = VRField; + gdcmAssertAlwaysMacro( !IsDual() ); + if( vrfield == VR::INVALID ) + { + //vrfield = VR::UN; + } + const char *vr = GetVRString(vrfield); + //assert( strlen( vr ) == 2 ); + assert( vr[0] && vr[1] && vr[2] == 0 ); + os.write(vr, 2); + // See PS 3.5, Data Element Structure With Explicit VR + if( vrfield & VL32 ) + { + const char dum[2] = {0, 0}; + os.write(dum,2); + } + return os; + } + friend std::ostream &operator<<(std::ostream &os, const VR &vr); + + operator VRType () const { return VRField; } + + unsigned int GetSize() const; + + bool Compatible(VR const &vr) const; + + bool IsVRFile() const; + + bool IsDual() const; + +private: + // Internal function that map a VRType to an index in the VRStrings table + static int GetIndex(VRType vr); + VRType VRField; +}; +//----------------------------------------------------------------------------- +inline std::ostream &operator<<(std::ostream &_os, const VR &val) +{ + //_os << VR::GetVRStringFromFile(val.VRField); + _os << VR::GetVRString(val.VRField); + return _os; +} + +// Apparently SWIG is not happy with something, somewhere below... +#ifndef SWIG + +// Tells whether VR Type is ASCII or Binary +template struct VRToEncoding; +// Convert from VR Type to real underlying type +template struct VRToType; +#define TYPETOENCODING(type,rep, rtype) \ + template<> struct VRToEncoding \ + { enum { Mode = VR::rep }; }; \ + template<> struct VRToType \ + { typedef rtype Type; }; + + +// Do not use me +struct UI { char Internal[64+1]; + friend std::ostream& operator<<(std::ostream &_os, const UI &_val); +}; +inline std::ostream& operator<<(std::ostream &_os, const UI &_val) +{ + _os << _val.Internal; + return _os; +} + +typedef String<'\\',16> AEComp; +typedef String<'\\',64> ASComp; +typedef String<'\\',16> CSComp; +typedef String<'\\',64> DAComp; +typedef String<'\\',64> DTComp; +typedef String<'\\',64> LOComp; +typedef String<'\\',64> LTComp; +typedef String<'\\',64> PNComp; +typedef String<'\\',64> SHComp; +typedef String<'\\',64> STComp; +typedef String<'\\',16> TMComp; +typedef String<'\\',64,0> UIComp; +typedef String<'\\',64> UTComp; + + +// TODO: Could be generated from XML file +TYPETOENCODING(AE,VRASCII ,AEComp) +TYPETOENCODING(AS,VRASCII ,ASComp) +TYPETOENCODING(AT,VRBINARY,Tag) +TYPETOENCODING(CS,VRASCII ,CSComp) +TYPETOENCODING(DA,VRASCII ,DAComp) +TYPETOENCODING(DS,VRASCII ,double) +TYPETOENCODING(DT,VRASCII ,DTComp) +TYPETOENCODING(FL,VRBINARY,float) +TYPETOENCODING(FD,VRBINARY,double) +TYPETOENCODING(IS,VRASCII ,int32_t) +TYPETOENCODING(LO,VRASCII ,LOComp) +TYPETOENCODING(LT,VRASCII ,LTComp) +TYPETOENCODING(OB,VRBINARY,uint8_t) +TYPETOENCODING(OF,VRBINARY,float) +TYPETOENCODING(OW,VRBINARY,uint16_t) +TYPETOENCODING(PN,VRASCII ,PNComp) +TYPETOENCODING(SH,VRASCII ,SHComp) +TYPETOENCODING(SL,VRBINARY,int32_t) +TYPETOENCODING(SQ,VRBINARY,unsigned char) // FIXME +TYPETOENCODING(SS,VRBINARY,int16_t) +TYPETOENCODING(ST,VRASCII ,STComp) +TYPETOENCODING(TM,VRASCII ,TMComp) +TYPETOENCODING(UI,VRASCII ,UIComp) +TYPETOENCODING(UL,VRBINARY,uint32_t) +TYPETOENCODING(UN,VRBINARY,uint8_t) // FIXME ? +TYPETOENCODING(US,VRBINARY,uint16_t) +TYPETOENCODING(UT,VRASCII ,UTComp) + +#define VRTypeTemplateCase(type) \ + case VR::type: \ + return sizeof ( VRToType::Type ); + +inline unsigned int VR::GetSize() const +{ + switch(VRField) + { + VRTypeTemplateCase(AE) + VRTypeTemplateCase(AS) + VRTypeTemplateCase(AT) + VRTypeTemplateCase(CS) + VRTypeTemplateCase(DA) + VRTypeTemplateCase(DS) + VRTypeTemplateCase(DT) + VRTypeTemplateCase(FL) + VRTypeTemplateCase(FD) + VRTypeTemplateCase(IS) + VRTypeTemplateCase(LO) + VRTypeTemplateCase(LT) + VRTypeTemplateCase(OB) + VRTypeTemplateCase(OF) + VRTypeTemplateCase(OW) + VRTypeTemplateCase(PN) + VRTypeTemplateCase(SH) + VRTypeTemplateCase(SL) + VRTypeTemplateCase(SQ) + VRTypeTemplateCase(SS) + VRTypeTemplateCase(ST) + VRTypeTemplateCase(TM) + VRTypeTemplateCase(UI) + VRTypeTemplateCase(UL) + VRTypeTemplateCase(UN) + VRTypeTemplateCase(US) + VRTypeTemplateCase(UT) + case VR::US_SS: + return 2; + default: + assert( 0 && "should not" ); + } + return 0; +} +#endif // SWIG + + +} // end namespace gdcm + +#endif //GDCMVR_H diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmVR16ExplicitDataElement.cxx b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmVR16ExplicitDataElement.cxx new file mode 100644 index 0000000..f25f43e --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmVR16ExplicitDataElement.cxx @@ -0,0 +1,57 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmVR16ExplicitDataElement.h" +#include "gdcmSequenceOfItems.h" +#include "gdcmSequenceOfFragments.h" + +namespace gdcm +{ + +//----------------------------------------------------------------------------- + +VL VR16ExplicitDataElement::GetLength() const +{ + if( ValueLengthField.IsUndefined() ) + { + assert( ValueField->GetLength().IsUndefined() ); + Value *p = ValueField; + // If this is a SQ we need to compute it's proper length + SequenceOfItems *sq = dynamic_cast(p); + // TODO can factor the code: + if( sq ) + { + return TagField.GetLength() + VRField.GetLength() + + ValueLengthField.GetLength() + sq->ComputeLength(); + } + SequenceOfFragments *sf = dynamic_cast(p); + if( sf ) + { + assert( VRField & (VR::OB | VR::OW) ); + return TagField.GetLength() + VRField.GetLength() + + ValueLengthField.GetLength() + sf->ComputeLength(); + } + assert(0); + return 0; + } + else + { + // Each time VR::GetLength() is 2 then Value Length is coded in 2 + // 4 then Value Length is coded in 4 + assert( !ValueField || ValueField->GetLength() == ValueLengthField ); + return TagField.GetLength() + 2*VRField.GetLength() + ValueLengthField; + } +} + + +} // end namespace gdcm diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmVR16ExplicitDataElement.h b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmVR16ExplicitDataElement.h new file mode 100644 index 0000000..035c2e9 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmVR16ExplicitDataElement.h @@ -0,0 +1,54 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMVR16EXPLICITDATAELEMENT_H +#define GDCMVR16EXPLICITDATAELEMENT_H + +#include "gdcmDataElement.h" + +namespace gdcm +{ +// Data Element (Explicit) +/** + * \brief Class to read/write a DataElement as Explicit Data Element + * \note This class support 16 bits when finding an unkown VR: + * For instance: + * Siemens_CT_Sensation64_has_VR_RT.dcm + */ +class GDCM_EXPORT VR16ExplicitDataElement : public DataElement +{ +public: + VL GetLength() const; + + template + std::istream &Read(std::istream &is); + + template + std::istream &ReadPreValue(std::istream &is); + + template + std::istream &ReadValue(std::istream &is, bool readvalues = true); + + template + std::istream &ReadWithLength(std::istream &is, VL & length); + + // PURPOSELY do not provide an implementation for writing ! + //template + //const std::ostream &Write(std::ostream &os) const; +}; + +} // end namespace gdcm + +#include "gdcmVR16ExplicitDataElement.txx" + +#endif //GDCMVR16EXPLICITDATAELEMENT_H diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmVR16ExplicitDataElement.txx b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmVR16ExplicitDataElement.txx new file mode 100644 index 0000000..ea03c32 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmVR16ExplicitDataElement.txx @@ -0,0 +1,310 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMVR16EXPLICITDATAELEMENT_TXX +#define GDCMVR16EXPLICITDATAELEMENT_TXX + +#include "gdcmSequenceOfItems.h" +#include "gdcmSequenceOfFragments.h" +#include "gdcmVL.h" +#include "gdcmParseException.h" +#include "gdcmImplicitDataElement.h" + +#include "gdcmValueIO.h" +#include "gdcmSwapper.h" + +namespace gdcm +{ +//----------------------------------------------------------------------------- +template +std::istream &VR16ExplicitDataElement::Read(std::istream &is) +{ + ReadPreValue(is); + return ReadValue(is); +} + +template +std::istream &VR16ExplicitDataElement::ReadPreValue(std::istream &is) +{ + TagField.Read(is); + // See PS 3.5, Data Element Structure With Explicit VR + // Read Tag + if( !is ) + { + if( !is.eof() ) // FIXME This should not be needed + { + assert(0 && "Should not happen" ); + } + return is; + } + assert( TagField != Tag(0xfffe,0xe0dd) ); + //assert( TagField != Tag(0xfeff,0xdde0) ); + const Tag itemDelItem(0xfffe,0xe00d); + const Tag itemStartItem(0xfffe,0x0000); + assert( TagField != itemStartItem ); + if( TagField == itemDelItem ) + { + if( !ValueLengthField.Read(is) ) + { + assert(0 && "Should not happen"); + return is; + } + if( ValueLengthField ) + { + gdcmWarningMacro( + "Item Delimitation Item has a length different from 0 and is: " << ValueLengthField ); + } + // Set pointer to NULL to avoid user error + ValueField = 0; + return is; + } + +#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + if( TagField == Tag(0x00ff, 0x4aa5) ) + { + assert(0 && "Should not happen" ); + // char c; + // is.read(&c, 1); + // std::cerr << "Debug: " << c << std::endl; + } +#endif + // Read VR + // FIXME + // Special hack for KONICA_VROX.dcm where in fact the VR=OX, in Pixel Data element + // in which case we need to assume a 32bits VR...for now this is a big phat hack ! + bool OX_hack = false; + try + { + if( !VRField.Read(is) ) + { + assert(0 && "Should not happen" ); + return is; + } + } + catch( Exception & ) + { + VRField = VR::INVALID; + // gdcm-MR-PHILIPS-16-Multi-Seq.dcm + if( TagField == Tag(0xfffe, 0xe000) ) + { + gdcmWarningMacro( "Found item delimitor in item" ); + ParseException pe; + pe.SetLastElement( *this ); + throw pe; + } + // -> For some reason VR is written as {44,0} well I guess this is a VR... + // Technically there is a second bug, dcmtk assume other things when reading this tag, + // so I need to change this tag too, if I ever want dcmtk to read this file. oh well + // 0019004_Baseline_IMG1.dcm + // -> VR is garbage also... + // assert( TagField == Tag(8348,0339) || TagField == Tag(b5e8,0338)) + if( TagField == Tag(0x7fe0,0x0010) ) + { + OX_hack = true; + VRField = VR::UN; // make it a fake 32bits for now... + char dummy[2]; + is.read(dummy,2); + assert( dummy[0] == 0 && dummy[1] == 0 ); + gdcmWarningMacro( "Assuming 32 bits VR for Tag=" << + TagField << " in order to read a buggy DICOM file." ); + } + else + { + gdcmWarningMacro( "Assuming 16 bits VR for Tag=" << + TagField << " in order to read a buggy DICOM file." ); + } + } + // Read Value Length + if( VR::GetLength(VRField) == 4 ) + { + if( !ValueLengthField.Read(is) ) + { + assert(0 && "Should not happen"); + return is; + } + if( OX_hack ) + { + VRField = VR::INVALID; // revert to a pseudo unknown VR... + } + } + else + { + assert( OX_hack == false ); + // 16bits only + if( !ValueLengthField.template Read16(is) ) + { + assert(0 && "Should not happen"); + return is; + } +#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + // HACK for SIEMENS Leonardo + if( ValueLengthField == 0x0006 + && VRField == VR::UL + && TagField.GetGroup() == 0x0009 ) + { + gdcmWarningMacro( "Replacing VL=0x0006 with VL=0x0004, for Tag=" << + TagField << " in order to read a buggy DICOM file." ); + ValueLengthField = 0x0004; + } +#endif + } + //std::cerr << "exp cur tag=" << TagField << " VR=" << VRField << " VL=" << ValueLengthField << std::endl; + // + // I don't like the following 3 lines, what if 0000,0000 was indeed -wrongly- sent, we should be able to continue + // chances is that 99% of times there is now way we can reach here, so safely throw an exception + if( TagField == Tag(0x0000,0x0000) && ValueLengthField == 0 && VRField == VR::INVALID ) + { + // This handles DMCPACS_ExplicitImplicit_BogusIOP.dcm + ParseException pe; + pe.SetLastElement( *this ); + throw pe; + } + return is; +} + +template +std::istream &VR16ExplicitDataElement::ReadValue(std::istream &is, bool readvalues ) +{ + if( is.eof() ) return is; + + if( ValueLengthField == 0 ) + { + // Simple fast path + ValueField = 0; + return is; + } + + // Read the Value + //assert( ValueField == 0 ); + if( VRField == VR::SQ ) + { + // Check wether or not this is an undefined length sequence + assert( TagField != Tag(0x7fe0,0x0010) ); + ValueField = new SequenceOfItems; + } + else if( ValueLengthField.IsUndefined() ) + { + if( VRField == VR::UN ) + { + // Support cp246 conforming file: + // Enhanced_MR_Image_Storage_PixelSpacingNotIn_0028_0030.dcm (illegal) + // vs + // undefined_length_un_vr.dcm + assert( TagField != Tag(0x7fe0,0x0010) ); + ValueField = new SequenceOfItems; + ValueField->SetLength(ValueLengthField); // perform realloc + try + { + //if( !ValueIO::Read(is,*ValueField) ) // non cp246 + if( !ValueIO::Read(is,*ValueField,readvalues) ) // cp246 compliant + { + assert(0); + } + } + catch( std::exception &) + { + // Must be one of those non-cp246 file... + // but for some reason seekg back to previous offset + Read + // as Explicit does not work... + ParseException pe; + pe.SetLastElement(*this); + throw pe; + } + return is; + } + else + { + if( TagField != Tag(0x7fe0,0x0010) ) + { + // gdcmSampleData/ForSeriesTesting/Perfusion/DICOMDIR + ParseException pe; + pe.SetLastElement(*this); + throw pe; + } + // Ok this is Pixel Data fragmented... + assert( TagField == Tag(0x7fe0,0x0010) ); + assert( VRField & VR::OB_OW ); + ValueField = new SequenceOfFragments; + } + } + else + { + //assert( TagField != Tag(0x7fe0,0x0010) ); + ValueField = new ByteValue; + } + // We have the length we should be able to read the value + ValueField->SetLength(ValueLengthField); // perform realloc +#if defined(GDCM_SUPPORT_BROKEN_IMPLEMENTATION) && 0 + // PHILIPS_Intera-16-MONO2-Uncompress.dcm + if( TagField == Tag(0x2001,0xe05f) + || TagField == Tag(0x2001,0xe100) + || TagField == Tag(0x2005,0xe080) + || TagField == Tag(0x2005,0xe083) + || TagField == Tag(0x2005,0xe084) + || TagField == Tag(0x2005,0xe402) + //TagField.IsPrivate() && VRField == VR::SQ + //-> Does not work for 0029 + //we really need to read item marker + ) + { + gdcmWarningMacro( "ByteSwaping Private SQ: " << TagField ); + assert( VRField == VR::SQ ); + assert( TagField.IsPrivate() ); + try + { + if( !ValueIO::Read(is,*ValueField,readvalues) ) + { + assert(0 && "Should not happen"); + } + Value* v = &*ValueField; + SequenceOfItems *sq = dynamic_cast(v); + assert( sq ); + SequenceOfItems::Iterator it = sq->Begin(); + for( ; it != sq->End(); ++it) + { + Item &item = *it; + DataSet &ds = item.GetNestedDataSet(); + ByteSwapFilter bsf(ds); + bsf.ByteSwap(); + } + } + catch( std::exception &ex ) + { + ValueLengthField = ValueField->GetLength(); + } + return is; + } +#endif + + if( !ValueIO::Read(is,*ValueField,readvalues) ) + { + // Might be the famous UN 16bits + ParseException pe; + pe.SetLastElement( *this ); + throw pe; + return is; + } + + return is; +} + +template +std::istream &VR16ExplicitDataElement::ReadWithLength(std::istream &is, VL & length) +{ + return Read(is); (void)length; +} + + +} // end namespace gdcm + +#endif // GDCMVR16EXPLICITDATAELEMENT_TXX diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmValue.cxx b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmValue.cxx new file mode 100644 index 0000000..0671587 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmValue.cxx @@ -0,0 +1,26 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#include "gdcmValue.h" +#include "gdcmVL.h" + +namespace gdcm +{ + + void Value::SetLengthOnly(VL l) + { + SetLength( l ); + } + +} // end namespace gdcm diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmValue.h b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmValue.h new file mode 100644 index 0000000..e45da89 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmValue.h @@ -0,0 +1,52 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMVALUE_H +#define GDCMVALUE_H + +#include "gdcmObject.h" + +namespace gdcm +{ + +class VL; +/** + * \brief Class to represent the value of a Data Element. + * \note + * VALUE: A component of a Value Field. A Value Field may consist of one + * or more of these components. + */ +class GDCM_EXPORT Value : public Object +{ +public: + Value() {} + ~Value() {} + + virtual VL GetLength() const = 0; + virtual void SetLength(VL l) = 0; + + virtual void Clear() = 0; + + virtual bool operator==(const Value &val) const = 0; + +protected: + friend class DataElement; + virtual void SetLengthOnly(VL l); +}; + + +} // end namespace gdcm + +#include "gdcmValue.txx" + +#endif //GDCMVALUE_H diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmValue.txx b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmValue.txx new file mode 100644 index 0000000..7435eb3 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmValue.txx @@ -0,0 +1,21 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMVALUE_TXX +#define GDCMVALUE_TXX + +namespace gdcm +{ +} // end namespace gdcm + +#endif // GDCMVALUE_TXX diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmValueIO.h b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmValueIO.h new file mode 100644 index 0000000..7f1b72a --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmValueIO.h @@ -0,0 +1,37 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMVALUEIO_H +#define GDCMVALUEIO_H + +#include "gdcmTypes.h" + +namespace gdcm +{ +/** + * \brief Class to dispatch template calls + */ +template +class /*GDCM_EXPORT*/ ValueIO +{ +public: + static std::istream &Read(std::istream &is, Value& v, bool readvalues); + + static const std::ostream &Write(std::ostream &os, const Value& v); +}; + +} // end namespace gdcm + +#include "gdcmValueIO.txx" + +#endif //GDCMVALUEIO_H diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmValueIO.txx b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmValueIO.txx new file mode 100644 index 0000000..2cc6791 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmValueIO.txx @@ -0,0 +1,76 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMVALUEIO_TXX +#define GDCMVALUEIO_TXX + +#include "gdcmValueIO.h" + +#include "gdcmExplicitDataElement.h" +#include "gdcmImplicitDataElement.h" +#include "gdcmSequenceOfFragments.h" +#include "gdcmSequenceOfItems.h" +#include "gdcmByteValue.h" + +namespace gdcm +{ + + template + std::istream &ValueIO::Read(std::istream &is, Value& _v, bool readvalues) { + Value* v = &_v; + if( ByteValue *bv = dynamic_cast(v) ) + { + bv->template Read(is,readvalues); + } + else if( SequenceOfItems *si = dynamic_cast(v) ) + { + si->template Read(is,readvalues); + } + else if( SequenceOfFragments *sf = dynamic_cast(v) ) + { + sf->template Read(is,readvalues); + } + else + { + assert( 0 && "error" ); + } + return is; + } + + template + const std::ostream &ValueIO::Write(std::ostream &os, const Value& _v) { + const Value* v = &_v; + if( const ByteValue *bv = dynamic_cast(v) ) + { + bv->template Write(os); + } + else if( const SequenceOfItems *si = dynamic_cast(v) ) + { + //VL dummy = si->ComputeLength(); + //assert( /*dummy.IsUndefined() ||*/ dummy == si->GetLength() ); + si->template Write(os); + } + else if( const SequenceOfFragments *sf = dynamic_cast(v) ) + { + sf->template Write(os); + } + else + { + assert( 0 && "error" ); + } + return os; + } + +} // end namespace gdcm + +#endif // GDCMVALUEIO_TXX diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmWriter.cxx b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmWriter.cxx new file mode 100644 index 0000000..144e907 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmWriter.cxx @@ -0,0 +1,182 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmWriter.h" +#include "gdcmFileMetaInformation.h" +#include "gdcmDataSet.h" +#include "gdcmTrace.h" + +#include "gdcmSwapper.h" +#include "gdcmDataSet.h" +#include "gdcmExplicitDataElement.h" +#include "gdcmImplicitDataElement.h" +#include "gdcmValue.h" + +#include "gdcmValue.h" +#include "gdcmItem.h" +#include "gdcmSequenceOfItems.h" +#include "gdcmParseException.h" + +#include "gdcmDeflateStream.h" + +namespace gdcm +{ + +Writer::Writer():Stream(NULL),Ofstream(NULL),F(new File),CheckFileMetaInformation(true),WriteDataSetOnly(false) +{ +} + +Writer::~Writer() +{ + if (Ofstream) + { + delete Ofstream; + Ofstream = NULL; + Stream = NULL; + } +} + +bool Writer::Write() +{ + if( !Stream || !*Stream ) + { + gdcmErrorMacro( "No Filename" ); + return false; + } + + std::ostream &os = *Stream; + FileMetaInformation &Header = F->GetHeader(); + DataSet &DS = F->GetDataSet(); + + if( DS.IsEmpty() ) + { + gdcmErrorMacro( "DS empty" ); + return false; + } + + // Should I check that 0002,0002 / 0008,0016 and 0002,0003 / 0008,0018 match ? + + if( !WriteDataSetOnly ) + { + if( CheckFileMetaInformation ) + { + FileMetaInformation duplicate( Header ); + try + { + duplicate.FillFromDataSet( DS ); + } + catch(gdcm::Exception &ex) + { + (void)ex; //to avoid unreferenced variable warning on release + gdcmErrorMacro( "Could not recreate the File Meta Header, please report:" << ex.what() ); + return false; + } + duplicate.Write(os); + } + else + { + Header.Write(os); + } + } + + const TransferSyntax &ts = Header.GetDataSetTransferSyntax(); + if( !ts.IsValid() ) + { + gdcmErrorMacro( "Invalid Transfer Syntax" ); + return false; + } + + if( ts == TransferSyntax::DeflatedExplicitVRLittleEndian ) + { + //gzostream gzos(os.rdbuf()); + try { + zlib_stream::zip_ostream gzos( os ); + assert( ts.GetNegociatedType() == TransferSyntax::Explicit ); + DS.Write(gzos); + //gzos.flush(); + } catch (...){ + return false; + } + + return true;//os; + } + + try + { + if( ts.GetSwapCode() == SwapCode::BigEndian ) + { + //US-RGB-8-epicard.dcm is big endian + if( ts.GetNegociatedType() == TransferSyntax::Implicit ) + { + // There is no such thing as Implicit Big Endian... oh well + // LIBIDO-16-ACR_NEMA-Volume.dcm + DS.Write(os); + } + else + { + assert( ts.GetNegociatedType() == TransferSyntax::Explicit ); + DS.Write(os); + } + } + else // LittleEndian + { + if( ts.GetNegociatedType() == TransferSyntax::Implicit ) + { + DS.Write(os); + } + else + { + assert( ts.GetNegociatedType() == TransferSyntax::Explicit ); + DS.Write(os); + } + } + } + catch(std::exception &ex) + { + (void)ex; //to avoid unreferenced variable warning on release + gdcmErrorMacro( ex.what() ); + return false; + } + catch(...) + { + gdcmErrorMacro( "what the hell" ); + return false; + } + + os.flush(); + if (Ofstream) + { + Ofstream->close(); + } + + return true; +} + +void Writer::SetFileName(const char *filename) +{ + //std::cerr << "Stream: " << filename << std::endl; + //std::cerr << "Ofstream: " << Ofstream << std::endl; + if (Ofstream && Ofstream->is_open()) + { + Ofstream->close(); + delete Ofstream; + } + Ofstream = new std::ofstream(); + Ofstream->open(filename, std::ios::out | std::ios::binary ); + assert( Ofstream->is_open() ); + assert( !Ofstream->fail() ); + //std::cerr << Stream.is_open() << std::endl; + Stream = Ofstream; + } + +} // end namespace gdcm diff --git a/gdcm/Source/DataStructureAndEncodingDefinition/gdcmWriter.h b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmWriter.h new file mode 100644 index 0000000..8c5c276 --- /dev/null +++ b/gdcm/Source/DataStructureAndEncodingDefinition/gdcmWriter.h @@ -0,0 +1,96 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#ifndef GDCMWRITER_H +#define GDCMWRITER_H + +#include "gdcmFile.h" + +namespace gdcm +{ + +class FileMetaInformation; +/** + * \brief Writer ala DOM (Document Object Model) + * This class is a non-validating writer, it will only performs well- + * formedness check only. + * + * \details Detailled description here + * To avoid GDCM being yet another broken DICOM lib we try to + * be user level and avoid writing illegal stuff (odd length, + * non-zero value for Item start/end length ...) + * Therefore you cannot (well unless you are really smart) write + * DICOM with even length tag. + * All the checks are consider basics: + * - Correct Meta Information Header (see gdcm::FileMetaInformation) + * - Zero value for Item Length (0xfffe, 0xe00d/0xe0dd) + * - Even length for any elements + * - Alphabetical order for elements (garanteed by design of internals) + * - 32bits VR will be rewritten with 00 + * + * \warning + * gdcm::Writer cannot write a DataSet if no SOP Instance UID (0008,0018) is found, + * unless a DICOMDIR is being written out + * + * \see Reader DataSet File + */ +class GDCM_EXPORT Writer +{ +public: + Writer(); + virtual ~Writer(); + + /// Main function to tell the writer to write + virtual bool Write(); // Execute() + + /// Set the filename of DICOM file to write: + void SetFileName(const char *filename_native); + + /// Set user ostream buffer + void SetStream(std::ostream &output_stream) { + Stream = &output_stream; + } + + /// Set/Get the DICOM file (DataSet + Header) + void SetFile(const File& f) { F = f; } + File &GetFile() { return *F; } + + /// Undocumented function, do not use (= leave default) + void SetCheckFileMetaInformation(bool b) { CheckFileMetaInformation = b; } + void CheckFileMetaInformationOff() { CheckFileMetaInformation = false; } + void CheckFileMetaInformationOn() { CheckFileMetaInformation = true; } + +protected: + void SetWriteDataSetOnly(bool b) { WriteDataSetOnly = b; } + +protected: + friend class StreamImageWriter; + //this function is added for the StreamImageWriter, which needs to write + //up to the pixel data and then stops right before writing the pixel data. + //after that, for the raw codec at least, zeros are written for the length of the data + std::ostream* GetStreamPtr() const { return Stream; } + +protected: + std::ostream *Stream; + std::ofstream *Ofstream; + +private: + SmartPointer F; + bool CheckFileMetaInformation; + bool WriteDataSetOnly; +}; + +} // end namespace gdcm + +#endif //GDCMWRITER_H diff --git a/gdcm/Source/InformationObjectDefinition/CMakeLists.txt b/gdcm/Source/InformationObjectDefinition/CMakeLists.txt new file mode 100644 index 0000000..41c3de5 --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/CMakeLists.txt @@ -0,0 +1,79 @@ +# Define the srcs for the Information Object Definition +# IOD +set(IOD_SRCS + gdcmModule.cxx + gdcmMacro.cxx + gdcmModules.cxx + gdcmMacros.cxx + gdcmNestedModuleEntries.cxx + gdcmIODEntry.cxx + gdcmTableReader.cxx + gdcmTable.cxx + gdcmSeries.cxx + gdcmDefs.cxx + gdcmDefinedTerms.cxx + gdcmEnumeratedValues.cxx + gdcmStudy.cxx + gdcmPatient.cxx + gdcmType.cxx + gdcmUsage.cxx + gdcmIOD.cxx + #gdcmXMLDictReader.cxx + #gdcmXMLPrivateDictReader.cxx + ) + +# expat stuff +if(NOT BUILD_SHARED_LIBS) + set_source_files_properties(gdcmTableReader.cxx + PROPERTIES + COMPILE_FLAGS -DXML_STATIC + ) +endif() + +# Add the include paths +include_directories( + "${GDCM_SOURCE_DIR}/Source/Common" + "${GDCM_BINARY_DIR}/Source/Common" + "${GDCM_SOURCE_DIR}/Source/DataStructureAndEncodingDefinition" + "${GDCM_SOURCE_DIR}/Source/DataDictionary" + "${GDCM_SOURCE_DIR}/Utilities" + ) +if(GDCM_USE_SYSTEM_EXPAT) + include_directories( + ${EXPAT_INCLUDE_DIRS} + ) +endif() + +add_library(gdcmIOD ${IOD_SRCS}) +target_link_libraries(gdcmIOD gdcmDSED gdcmCommon ${GDCM_EXPAT_LIBRARIES}) +set_target_properties(gdcmIOD PROPERTIES ${GDCM_LIBRARY_PROPERTIES} LINK_INTERFACE_LIBRARIES "gdcmDSED;gdcmCommon") + +# libs +install_library(gdcmIOD) +# PDB +install_pdb(gdcmIOD) +# include files +install_includes("*.h" "*.txx") + +#----------------------------------------------------------------------------- +# Install Part3.xml / Part4.xml +install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/Part3.xml + ${CMAKE_CURRENT_SOURCE_DIR}/Part4.xml + DESTINATION ${GDCM_INSTALL_DATA_DIR}/XML COMPONENT Libraries +) + +#----------------------------------------------------------------------------- +file(GLOB GDCM_XML_TABLES_GLOB + "${CMAKE_CURRENT_SOURCE_DIR}/*.xml" + ) + +set(GDCM_XML_TABLES) +foreach(filename ${GDCM_XML_TABLES_GLOB}) + set(GDCM_XML_TABLES "${GDCM_XML_TABLES}\n\"${filename}\",") +endforeach() + +# Populate GDCM_DATA_IMAGES: +configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/gdcmTables.h.in" + "${CMAKE_CURRENT_BINARY_DIR}/gdcmTables.h" + ) diff --git a/gdcm/Source/InformationObjectDefinition/ParseAttributes.py b/gdcm/Source/InformationObjectDefinition/ParseAttributes.py new file mode 100644 index 0000000..7e04d68 --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/ParseAttributes.py @@ -0,0 +1,555 @@ +#!/usr/bin/env python +# vim: set fileencoding=iso-8859-1 + +""" +$ pdftotext -layout -nopgbrk -f 303 -l 305 07_03pu.pdf page303.txt + +$ python ParseAttributes.py page273-1000.txt out.txt > log2 +$ grep ADD log2 | grep -v "Notes:" | grep -v "Note:" | grep -v "C.8" | grep -v "C.7" + +""" +import re,os + +""" + +""" +class Attribute: + # Cstor + def __init__(self): + self._Name = '' + self._Tag = '(0000,0000)' + self._Type = '' + self._Description= '' + def SetInit(self,s): + # Should be something like: + # Blue Palette Color Lookup Table (0028,1103) 1C Specifies the format of the Blue Palette + patt = re.compile("^(.*)(\\([0-9A-Fx]+,[0-9A-F]+\\))\s+([1-3C]+)\s+(.*)\s*$") + m = patt.match(s) + if not m: + print s + assert 0 + self._Name = m.group(1).strip() + self._Tag = m.group(2).strip() + self._Type = m.group(3).strip() + self._Description = m.group(4).strip() + def SetName(self,s): + self._Name = s + def AppendName(self,s): + self._Name += " " + self._Name += s.strip() + def SetTag(self,s): + self._Tag = s + def SetType(self,s): + self._Type = s + def SetDescription(self,s): + self._Description = s + def AppendDescription(self,s): + self._Description += " " + self._Description += s.strip() + def GetAsXML(self): + description = self._Description.replace('"','"') + description = description.replace('&','&') + return "" + def Print(self): + print self.GetAsXML() + +class Part3Parser: + # Cstor + def __init__(self): + self._InputFilename = '' + self._OutputFilename = '' + self._Buffer = '' + self._CurrentAttribute = Attribute() + self._IsInTable = False + self._Shift = 0 + + def SetInputFileName(self,s): + self._InputFilename = s + + def SetOutputFileName(self,s): + self._OutputFilename = s + + def IsComment(self,s): + if len(s) == 0: + return True + patt1 = re.compile("^\s+- Standard -\s*$") + patt2 = re.compile("^\s*PS 3.3 - 2007\s*") + patt3 = re.compile("^\s*Page\s+[0-9]+\s*$") + patt4 = re.compile("^\s*Notes:$") + m1 = patt1.match(s) + m2 = patt2.match(s) + m3 = patt3.match(s) + m4 = patt4.match(s) + if(m1 or m2 or m3 or m4): + print "Comment:", s + return True + if self.IsTableDescription(s): + return True + return False + + def IsStartTable(self,s): + #patt = re.compile("^\s+Table C[0-9a-z\.-]+.*\s+$") + patt = re.compile("^\s+Table\s+C.[0-9A-Za-z-.]+\s*$") + m = patt.match(s) + assert self._IsInTable != True + self._IsInTable = False + if s.strip() == 'Table C.7-23' or s.strip() == 'Table C.7-24' \ + or s.strip() == 'Table C.7.6.10-1' \ + or s.strip() == 'Table C.7-25' \ + or s.strip() == 'Table C.7-26' \ + or s.strip() == 'Table C.7-27' \ + or s.strip() == 'Table C.8-8' \ + or s.strip() == 'Table C.8-19' \ + or s.strip() == 'Table C.8-20' \ + or s.strip() == 'Table C.8-21' \ + or s.strip() == 'Table C.8-22' \ + or s.strip() == 'Table C.8-23' \ + or s.strip() == 'Table C.8-80' \ + or s.strip() == 'Table C.8-83' \ + or s.strip() == 'Table C.8-84' \ + or s.strip() == 'Table C.8-85' \ + or s.strip() == 'Table C.8-86' \ + or s.strip() == 'Table C.8-108' \ + or s.strip() == 'Table C.8-109' \ + or s.strip() == 'Table C.8-110' \ + or s.strip() == 'Table C.8-111' \ + or s.strip() == 'Table C.8-112' \ + or s.strip() == 'Table C.8-115' \ + or s.strip() == 'Table C.8-116' \ + or s.strip() == 'Table C.8-127' \ + or s.strip() == 'Table C.8-128' \ + or s.strip() == 'Table C.8-129' \ + or s.strip() == 'Table C.8-130' \ + or s.strip() == 'Table C.8-131' \ + or s.strip() == 'Table C.8-132' \ + or s.strip() == 'Table C.8-133' \ + or s.strip() == 'Table C.8-134' \ + or s.strip() == 'Table C.8.19.2-2' \ + or s.strip() == 'Table C.10-10' \ + or s.strip() == 'Table C.11-4' \ + or s.strip() == 'Table C.12-2' \ + or s.strip() == 'Table C.12-3' \ + or s.strip() == 'Table C.12-4' \ + or s.strip() == 'Table C.12-5' \ + or s.strip() == 'Table C.12-7' \ + or s.strip() == 'Table C.13-1' \ + or s.strip() == 'Table C.13-2' \ + or s.strip() == 'Table C.13-3' \ + or s.strip() == 'Table C.13-4' \ + or s.strip() == 'Table C.13-5' \ + or s.strip() == 'Table C.13-7' \ + or s.strip() == 'Table C.13-8' \ + or s.strip() == 'Table C.13-9' \ + or s.strip() == 'Table C.13-13' \ + or s.strip() == 'Table C.14-1' \ + or s.strip() == 'Table C.17.3-7' \ + or s.strip() == 'Table C.17.3-8' \ + or s.strip() == 'Table C.22.1-1': + # C.11-4, C.13-*, C.22.1-1: Does not even comes with column type !!! + # C.12-7 is difficult to parse + # C.7.6.16-1 is insane... + # TODO: Last line of C.19-1... + return False + if(m): + print "Start", s + self._IsInTable = True + return True + # grrrrr: Table C.8-37 - RT SERIES MODULE ATTRIBUTES + patt = re.compile("^\s+Table\s+C.[0-9A-Za-z-]+\s*[-]*\s*([A-Z/\s-]+)\s*$") + #patt = re.compile("^\s+Table\s+C.[0-9A-Za-z-]+[-\s]+([A-Z/\s-]+)\s*$") + m = patt.match(s) + if(m): + print "Start", s + self._IsInTable = True + return True + print "IsTable failed with:", s + return False + + def IsEndTable(self,s): + assert self._IsInTable == True + assert not self.IsComment(s) + self._IsInTable = False + return True + + def IsTableName(self,s): + patt = re.compile("^\s*[A-Z/\s-]+ATTRIBUTES\s*$") #MACRO/MODULE + m = patt.match(s) + if(m): + print "Table Name", s + return True + patt = re.compile("^\s+[A-Za-z\s]+Attributes\s*$") #MACRO/MODULE + m = patt.match(s) + if(m): + print "Table Name", s + return True + # PALETTE COLOR LOOKUP MODULE + patt = re.compile("^\s+[A-Z\s]+MODULE\s*$") #MACRO/MODULE + m = patt.match(s) + if(m): + print "Table Name", s + return True + # MR IMAGE AND SPECTROSCOPY INSTANCE MACRO + patt = re.compile("^\s+[A-Z\s]+MACRO\s*$") #MACRO/MODULE + m = patt.match(s) + if(m): + print "Table Name", s + return True + # Enhanced XA/XRF Image Module Table + patt = re.compile("^\s+[A-Z/a-z\s]+Module Table\s*$") + m = patt.match(s) + if(m): + print "Table Name", s + return True + # Presentation LUT Module + #patt = re.compile("^\s+Presentation LUT Module\s*$") + #m = patt.match(s) + #if(m): + # print "Table Name", s + # return True + print "TableName failed with:", s + return False + + def IsTableName2(self,s): + # grrrrr: Table C.8-37 - RT SERIES MODULE ATTRIBUTES + # Table C.8-39--RT DOSE MODULE ATTRIBUTES + patt = re.compile("^\s+Table\s+C.[0-9A-Za-z-]+\s*[-]*\s*([A-Z/\s-]+)\s*$") + m = patt.match(s) + # The previous regex would think : Table C.7-17A + # is correct...I don't know how to fix the regex, so discard result if + # len(m.group(1)) <= 1 + if(m and len(m.group(1)) > 1): + print "Table Name:", m.group(1) + assert self.IsTableName( m.group(1) ) + return True + print "TableName2 failed with:", s + return False + + def IsTableDescription(self,s): + patt = re.compile("^\s*Attribute Name\s+Tag\s+Type\s+Attribute Description\s*$") + m = patt.match(s) + if(m): + print "Table Description:", s + return True + # Around page 574 + patt = re.compile("^\s*Attribute [Nn]ame\s+Tag\s+Type\s+Description\s*$") + m = patt.match(s) + if(m): + print "Table Description:", s + return True + return False + + def IsFirstLineAttribute(self,s): + # Line should look like: + # Bits Stored ... (0028,0101) ... 1 ... Number of bits stored for each pixel + patt = re.compile("^\s*(.*)\\([0-9A-Fx]+,[0-9A-F]+\\)\s+([1-3C]+).*\s*$") #MACRO/MODULE + m = patt.match(s) + if(m): + s1 = m.group(1).strip() + if s1 == '': + return False + #print "First Line Attribute:", s1, s + return True + #print "No:", s + return False + + def IsIncludeTable(self,s): + # Need to support : "Include `Image Pixel Macro' Table C.7-11b" + #assert self._Shift == 0 + #print "Include:", s + #patt = re.compile("^>*Include `(.*)' Table [A-Z0-9a-z-.]+$") + #m = patt.match(s) + #if m: + # return True + #patt = re.compile("^>*Include [`|'](.*)' Table [A-Z0-9a-z-.]+\s+Defined Context ID is.*$") + #m = patt.match(s) + #return m + #print "FALLBACK" + patt = re.compile("^>*\s*Include [`'\"]*([A-Za-z/ -]*)['\"]* \\(*Table [A-Z0-9a-z-.]+\\)*.*$") + m = patt.match(s) + #if not m: + # print "FAIL", s + return m + + def IsNextLineAttribute(self,s): + if self._Shift == 0: + print "IsNextLineAttribute failed with", s + return False + if len(s) <= self._Shift: + print "IsNextLineAttribute failed with", s + return False + blank = s[0:self._Shift] + blank = blank.strip() + #print "BLANK:", blank + if blank == '': + self._CurrentAttribute.AppendDescription( s ) + return True + # The following is really ugly ... need to be fixed + if blank == 'Descriptor' or blank == 'Data' or blank == 'Center Name' \ + or blank == 'Description' \ + or blank == 'Sequence' \ + or blank == 'Distance' \ + or blank == 'Index' \ + or blank == 'Reordering' \ + or blank == 'Time' \ + or blank == 'Device Number' \ + or blank == 'Justification' \ + or blank == 'Shape' \ + or blank == 'Relationship' \ + or blank == 'in Float' \ + or blank == 'Displacement' \ + or blank == 'Technique Description' \ + or blank == 'Left Vertical Edge' \ + or blank == 'State Sequence' \ + or blank == 'In-plane' \ + or blank == 'Certification Number' \ + or blank == 'Right Vertical Edge' \ + or blank == 'Accumulated' \ + or blank == 'Equivalent Thickness' \ + or blank == 'Distances' \ + or blank == 'Definition' \ + or blank == 'Upper Horizontal Edge' \ + or blank == 'Modification' \ + or blank == 'Power Ratio' \ + or blank == 'Lower Horizontal Edge' \ + or blank == 'Device Distance' \ + or blank == 'Sensing Region' \ + or blank == 'Control Sensing Region' \ + or blank == 'Water Equivalent Thickness' \ + or blank == 'Columns' \ + or blank == 'Rows' \ + or blank == 'Ratio' \ + or blank == 'Display Grayscale Value' \ + or blank == 'Display CIELab Value' \ + or blank == 'UID' \ + or blank == 'Units' \ + or blank == 'Pointer' \ + or blank == 'Value' \ + or blank == 'Annotation' \ + or blank == 'Pointer Private Creator' \ + or blank == 'Creator' \ + or blank == 'Value Mapping Sequence' \ + or blank == 'Performed Procedure' \ + or blank == 'MAC Sequence' \ + or blank == 'Class UID' \ + or blank == 'Instance UID' \ + or blank == 'Syntax UID' \ + or blank == 'Used' \ + or blank == 'Identifier' \ + or blank == 'Datetime' \ + or blank == 'plane Phase Steps' \ + or blank == '(Patient)' \ + or blank == 'Collection Center' \ + or blank == 'Technique' \ + or blank == 'Interpretation' \ + or blank == 'Representation' \ + or blank == 'Configuration' \ + or blank == 'Compression' \ + or blank == 'Reference Code' \ + or blank == 'Encoding Steps' \ + or blank == 'Steps in-plane' \ + or blank == 'Steps out-of-plane' \ + or blank == 'Type' \ + or blank == 'Explanation' \ + or blank == 'Mapped' \ + or blank == 'Calibration' \ + or blank == 'Manufactured' \ + or blank == 'Thickness' \ + or blank == 'Reference Sequence' \ + or blank == 'Reference Number' \ + or blank == 'Transmission' \ + or blank == 'Matrix' \ + or blank == 'Comment' \ + or blank == 'Setup Sequence' \ + or blank == 'Setup Number' \ + or blank == 'Fraction' \ + or blank == 'Tolerance' \ + or blank == 'Number' \ + or blank == 'Day' \ + or blank == 'Parameters' \ + or blank == 'Coefficient' \ + or blank == 'Specification Point' \ + or blank == 'Identification Sequence' \ + or blank == 'Reference UID' \ + or blank == 'Synchronized' \ + or blank == 'Description Code Sequence' \ + or blank == 'Concentration' \ + or blank == 'Procedure Step' \ + or blank == 'Manufacturer' \ + or blank == 'Lookup Table Data' \ + or blank == 'Version' \ + or blank == 'Images' \ + or blank == 'Wavelength' \ + or blank == 'Code Sequence' \ + or blank == 'Housing' \ + or blank == 'Exposure' \ + or blank == 'Beam' \ + or blank == 'Angle' \ + or blank == 'Rotation Angle' \ + or blank == 'Corner' \ + or blank == 'Factor' \ + or blank == 'Product' \ + or blank == "Manufacturer's Model Name" \ + or blank == 'Qualifier Code' \ + or blank == 'Mapping Instance Sequence' \ + or blank == 'Channels' \ + or blank == 'Samples' \ + or blank == 'Transformation Comment' \ + or blank == 'Pixels' \ + or blank == 'Correction Factor' \ + or blank == 'Group' \ + or blank == 'Amount' \ + or blank == 'Priority' \ + or blank == 'Group Name' \ + or blank == 'Frame Rate' \ + or blank == 'Presence' \ + or blank == 'Sequencing' \ + or blank == 'Orientation' \ + or blank == 'Inverted' \ + or blank == 'Numbers' \ + or blank == 'Flag' \ + or blank == 'Annotation Flag' \ + or blank == 'Demographics Flag' \ + or blank == 'Techniques Flag' \ + or blank == 'Group Description' \ + or blank == 'Handling' \ + or blank == 'Initial View Direction' \ + or blank == 'Identification Code Sequence' \ + or blank == 'Identification Code' \ + or blank == 'Category' \ + or blank == 'Spatial Position' \ + or blank == 'Creation Datetime' \ + or blank == 'Grayscale Bit Depth' \ + or blank == 'Bit Depth' \ + or blank == 'Repaint Time' \ + or blank == 'Definition Sequence' \ + or blank == 'Procedure Code' \ + or blank == 'Referenced' \ + or blank == 'Reference' \ + or blank == 'Usage Flag' \ + or blank == 'Horizontal Dimension' \ + or blank == 'Dimension' \ + or blank == 'Direction' \ + or blank == 'Registration Sequence' \ + or blank == 'Transformation Matrix' \ + or blank == 'Transformation Matrix Type' \ + or blank == 'Step Sequence': + self._CurrentAttribute.AppendName( blank ) + self._CurrentAttribute.AppendDescription( s[self._Shift:] ) + return True + else: + print "ADD KEYWORD:", blank + return False + + def FindShiftValue(self,s): + # Line should look like: + # Bits Stored ... (0028,0101) ... 1 ... Number of bits stored for each pixel + patt = re.compile("^[A-Za-z0-9µ /()'>-]+\s+\\([0-9A-Fx]+,[0-9A-F]+\\)\s+[1-3][C]*\s+(.*)$") + m = patt.match(s) + if(m): + # worse case happen around page 448 with `Required` + # worse case happen around page 475 with `LOG`... + self._Shift = s.find( m.group(1) ) - 17 + return self._Shift + print "OUCH:", s + return 0 + + def Open(self): + #self._Infile = file(self._InputFilename, 'r') + #for line in self._Infile.readlines(): + # line = line[:-1] # remove '\n' + # if( self.IsStartTable(line) ): + # print line.next() + cmd_input = open(self._InputFilename,'r') + outfile = open(self._OutputFilename, 'w') + # To support some weird output from pdftotext + outfile.write( '' ) + outfile.write( '' ) + for line_ori in cmd_input: + #while line.startswith('%') : # skip comment lines + #print "!!!",line + #line= cmd_input.next() + line = line_ori[:-1] + if( self.IsStartTable(line) ): + table_name_found = self.IsTableName2(line) + line2 = line + # Okay table is on next line: + if ( not table_name_found ): + line2 = cmd_input.next()[:-1] + table_name_found = self.IsTableName(line2) + # Either way we need to find the table name + assert table_name_found + if( table_name_found ): + line3 = cmd_input.next()[:-1] + if( self.IsTableDescription(line3) ): + # Ok we found a table + outfile.write( + "" + ) + buffer = '' + self._CurrentAttribute = Attribute() + self._Shift = 0 + for subline_ori in cmd_input: + subline = subline_ori[:-1] + if( self.IsIncludeTable(subline)): + # BUG DO NOT SUPPORT MULTI_LINE INCLUDE + #print "Include Table:", subline + if( subline != '' ): + outfile.write( "" ) + outfile.write( '\n' ) + elif( self.IsFirstLineAttribute(subline)): + #print "Previous Buffer was: ", buffer + if( buffer != '' ): + outfile.write( self._CurrentAttribute.GetAsXML() ) + outfile.write( '\n' ) + self._CurrentAttribute.SetInit(subline) + self.FindShiftValue(subline) + assert self._Shift != 0 + buffer = subline + else: + if( not self.IsComment(subline) ): + #print "Found Comment: ", subline + if( self.IsNextLineAttribute(subline) ): + buffer += ' ' + subline.strip() + else: + print "Wotsit:", subline + self._Shift = 0 + self._IsInTable = False + if( buffer != '' ): + outfile.write( self._CurrentAttribute.GetAsXML() ) + outfile.write( '\n' ) + outfile.write( '
' ) + break + #print "Working on: ", subline + if not subline_ori: + break + else: + print "Problem with:", line, line2 + #line = cmd_input.next() + if not line_ori: break + cmd_input.close() + outfile.write( '
' ) + self.Write() + + def Write(self): + print "Write" + + # Main function to call for parsing + def Parse(self): + self.Open() + + +if __name__ == "__main__": + argc = len(os.sys.argv ) + if ( argc < 3 ): + print "Sorry, wrong list of args" + os.sys.exit(1) #error + + inputfilename = os.sys.argv[1] + outputfilename = os.sys.argv[2] + tempfile = "/tmp/mytemp2" + + dp = Part3Parser() + dp.SetInputFileName( inputfilename ) + dp.SetOutputFileName( tempfile ) + dp.Parse() diff --git a/gdcm/Source/InformationObjectDefinition/Part3.xml b/gdcm/Source/InformationObjectDefinition/Part3.xml new file mode 100644 index 0000000..0bab6fa --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/Part3.xml @@ -0,0 +1,28556 @@ + + + + + + + + + See Section 8.1. + + + See Section 8.2. + + + See Section 8.2. Required if the value of Coding Scheme Designator (0008,0102) is not sufficient to identify the Code Value (0008,0100) unambiguously. + + + See Section 8.3. + + + See Section 8.6. + + + See Section 8.4. Required if Context Identifier (0008,010F) is present. + + + See Section 8.5. Required if Context Identifier (0008,010F) is present. + + + Indicates whether the Code Value/Coding Scheme/Code Meaning is selected from a private extension of the Context Group identified in Context Identifier (0008,010F). See Section 8.7 of this Part. +Enumerated Values: "Y", "N" + + + + See Section 8.7. Required if the value of Context Group Extension Flag (0008,010B) is "Y". +. + + + Identifies the person or organization who created an extension to the Context Group. See Section 8.7. +Required if the value of Context Group Extension Flag (0008,010B) is "Y". + + + + + A coded entry which identifies a person. +The Code Meaning attribute, though it will be encoded with a VR of LO, may be encoded according to the rules of the PN VR (e.g. caret ‘^' delimiters shall separate name components), except that a single component (i.e. the whole name unseparated by caret delimiters) is not permitted. Name component groups for use with multi-byte character sets are permitted, as long as they fit within the 64 characters (the length of the LO VR). +One or more Items may be permitted in this Sequence. + + + + Person's mailing address + + + Person's telephone number(s) + + + Institution or organization to which the identified individual is responsible or accountable. Required if Institution Code Sequence (0008,0082) is not present. + + + Mailing address of the institution or organization to which the identified individual is responsible or accountable. + + + Institution or organization to which the identified individual is responsible or accountable. Required if Institution Name (0008,0080) is not present. +Only a single Item shall be permitted in this Sequence. + + + + + + The type of the value encoded in this name-value Item. +Defined Terms: +DATETIME +DATE +TIME +PNAME +UIDREF +TEXT +CODE +NUMERIC + + + Coded concept name of this name-value Item. Only a single Item shall be permitted in this Sequence. + + + + DateTime value for this name-value Item. +Required if Value Type (0040,A040) is DATETIME. + + + Date value for this name-value Item. +Required if Value Type (0040,A040) is DATE. + + + Time value for this name-value Item. +Required if Value Type (0040,A040) is TIME. + + + Person name value for this name-value Item. +Required if Value Type (0040,A040) is PNAME. + + + UID value for this name-value Item. +Required if Value Type (0040,A040) is UIDREF. + + + Text value for this name-value Item. +Required if Value Type (0040,A040) is TEXT. + + + Coded concept value of this name-value Item. Only a single Item shall be permitted in this Sequence. +Required if Value Type (0040,A040) is CODE. + + + + Numeric value for this name-value Item. +Required if Value Type (0040,A040) is NUMERIC. + + + Units of measurement for a numeric value in this name-value Item. Only a single Item shall be permitted in this Sequence. +Required if Value Type (0040,A040) is NUMERIC. + + + + + + + Identifies the frame numbers within the Referenced SOP Instance to which the reference applies. The first frame shall be denoted as frame number 1. +Note: This Attribute may be multi-valued. +Required if the Referenced SOP Instance is a multi-frame image and the reference does not apply to all frames, and Referenced Segment Number (0062,000B) is not present. + + + Identifies the Segment Number to which the reference applies. Required if the Referenced SOP Instance is a Segmentation and the reference does not apply to all segments and Referenced Frame Number (0008,1160) is not present. + + + + + Sequence of Items each of which includes the Attributes of one Series. One or more Items shall be present. + + + Unique identifier of the Series containing the referenced Instances. + + + Sequence of Items each providing a reference to an Instance that is part of the Series defined by Series Instance UID (0020,000E) in the enclosing Item. One or more Items shall be present. + + + + + + Sequence that identifies the anatomic region of interest in this Instance (i.e. external anatomy, surface anatomy, or general region of the body). +Only a single Item shall be permitted in this sequence. + + + + Sequence of Items that modifies the anatomic region of interest of this Instance +One or more Items may be included in this Sequence. + + + + + + + Sequence that identifies the anatomic region of interest in this Instance (i.e. external anatomy, surface anatomy, or general region of the body). +Zero or one Item may be present in this Sequence. + + + + Sequence of Items that modifies the anatomic region of interest of this Instance +One or more Items may be included in this Sequence. + + + + + + + Sequence that identifies the anatomic region of interest in this Instance (i.e. external anatomy, surface anatomy, or general region of the body). +Only a single Item shall be permitted in this sequence. + + + + Sequence of Items that modifies the anatomic region of interest of this Instance +One or more Items may be included in this Sequence. + + + + + + + Sequence of Items that identifies the primary anatomic structure(s) of interest in this Instance. +One or more Items may be included in this Sequence. + + + + Sequence of Items that modifies the primary anatomic structure of interest in this Instance. +One or more Items may be included in this Sequence. + + + + + + Identifier that identifies the Requested Procedure in the Imaging Service Request. +Required if procedure was scheduled. May be present otherwise. +Note: The condition is to allow the contents of this macro to be present (e.g., to convey the reason for the procedure, such as whether a mammogram is for screening or diagnostic purposes) even when the procedure was not formally scheduled and a value for this identifier is unknown, rather than making up a dummy value. + + + An identifier of the Imaging Service Request for this Requested Procedure. + + + The unique identifier for the Study provided for this Requested Procedure. + + + Uniquely identifies the Study SOP Instances associated with this SOP Instance. One or more items may be included. + + + + Institution-generated administrative description or classification of Requested Procedure. + + + A sequence that conveys the Procedure Type of the requested procedure. The Requested Procedure Code Sequence shall contain only a single item. + + + + Reason for requesting this procedure. + + + Coded Reason for requesting this procedure. +One or more sequence items may be present. + + + + Identifier that identifies the Scheduled Procedure Step. +Required if procedure was scheduled. +Note: The condition is to allow the contents of this macro to be present (e.g., to convey the reason for the procedure, such as whether a mammogram is for screening or diagnostic purposes) even when the procedure step was not formally scheduled and a value for this identifier is unknown, rather than making up a dummy value. + + + Institution-generated description or classification of the Scheduled Procedure Step to be performed. + + + Sequence describing the Scheduled Protocol following a specific coding scheme. This sequence contains one or more Items. + + + + Sequence that specifies the context for the Scheduled Protocol Code Sequence Item. One or more items may be included in this sequence. + + + + Sequence that specifies modifiers for a Protocol Context Content Item. One or more items may be included in this sequence. See Section C.4.10.1. +
The Protocol Context Sequence (0040,0440) allows the specification of parameters that further qualify the scheduled protocol, provided through a set of generic name/value pairs of context Content Items. +Note: This allows the specification of clinical, acquisition, or procedural qualifiers for the scheduled protocol, such as a specific body part, imaging technique, or parameters of a preparatory event (e.g., radionuclide injection). Specific uses of this Sequence may be documented in a Template defined in accordance with PS3.16. + +
+
+ +
+ + + Physical distance in the patient between the center of each pixel, specified by a numeric pair - adjacent row spacing (delimiter) adjacent column spacing in mm. See 10.7.1.1 and 10.7.1.3. Required if the image has been calibrated. May be present otherwise. + + + The type of correction for the effect of geometric magnification or calibration against an object of known size, if any. See 10.7.1.2. + + + A free text description of the type of correction or calibration performed. +Notes: 1. In the case of correction, the text might include description of the assumptions made about the body part and geometry and depth within the patient. +2. in the case of calibration, the text might include a description of the fiducial and where it is located (e.g., "XYZ device applied to the skin over the greater trochanter"). +3. Though it is not required, the Device Module may be used to describe the specific characteristics and size of the calibration device. +Required if Pixel Spacing Calibration Type (0028,0A02) is present. + + + + + Uniquely identifies the referenced SOP Class. + + + Uniquely identifies the referenced SOP Instance. + + + + + A number that identifies this SOP Instance. + + + A label that is used to identify this SOP Instance. + + + A description of the content of the SOP Instance. + + + Name of operator (such as a technologist or physician) creating the content of the SOP Instance. + + + Identification of the person who created the real world value mapping. Only a single item shall be present in this sequence. + + + + + + A sequence that identifies the contributing SOP Instances. +Required if this SOP Instance is created from other DICOM SOP Instances. +Note: The attribute is absent in the case where the sources used to create this SOP Instance are not SOP Instances, e.g., a volume that was directly generated by an acquisition system. +One or more Items may be present. + + + Unique identifier for the Study of the Contributing SOP Instances. + + + Sequence of Items each of which includes the Attributes of one Series. +One or more Items may be present. + + + Unique identifier of the Series containing the referenced Instances. + + + A number that identifies this Series. + + + Sequence of Items each providing a reference to an Instance that is part of the Series defined by Series Instance UID (0020,000E) in the enclosing Item. +One or more Items may be present. + + + + A number that identifies this instance. + + + Manufacturer of the equipment that produced the sources. + + + Manufacturer's model name of the equipment that produced the sources. +Required if present and consistent in the contributing SOP Instances. + + + Manufacturer's serial number of the equipment that produced the sources. +Required if present and consistent in the contributing SOP Instances. + + + Manufacturer's designation of software version of the equipment that produced the sources. +Required if present and consistent in the contributing SOP Instances. + + + The time the acquisition of data that resulted in sources started. +The value shall be the start date and time of the first contributing SOP Instance of the group specified by the Contributing SOP Instances Reference Sequence (0020,9529). +Required if present and consistent in the contributing SOP Instances. +Note: The Acquisition DateTime may be created by combining the values of Acquisition Date (0008,0022) and Acquisition Time (0008,0032) attributes in the contributing SOP Instances. + + + User defined name identifying the machine that produced the sources. +Required if present and consistent in the contributing SOP Instances. + + + Name(s) of the operator(s) supporting the Series. +Required if present and consistent in the contributing SOP Instances. + + + Identification of the operator(s) supporting the Series. One or more items shall be included in this sequence. If more than one Item, the number and order shall correspond to the value of Operators' Name (0008,1070), if present. +Required if present and consistent in the contributing SOP Instances. + + + + User-defined description of the conditions under which the Series was performed. +Required if present and consistent in the contributing SOP Instances. +Note: This attribute conveys series-specific protocol identification and may or may not be identical to the one presented in the Performed Protocol Code Sequence (0040,0260). + + + Sequence describing the Protocol performed for the Procedure Step creating the sources. One or more Items may be included in this Sequence. +Required if present and consistent in the contributing SOP Instances. + + + + User defined name of the protocol used to acquire this image. +Required if present and consistent in the contributing SOP Instances. + + + + + Number of rows in the images. + + + Number of columns in the images. + + + Number of bits stored for each pixel sample. Each sample shall have the same number of bits stored. See PS 3.5 for further explanation. + + + Specifies whether the Source Images have undergone lossy compression. Enumerated Values: +00 = Image has NOT been subjected to lossy compression. +01 = Image has been subjected to lossy compression. +See C.7.6.1.1.5 for further explanation. +Required if it is known whether or not Lossy Compression has been performed on the Images. +Note: In some SOP Class definitions the Lossy Image Compression attribute is optional. +
The Attribute Lossy Image Compression (0028,2110) conveys that the Image has undergone lossy compression. It provides a means to record that the Image has been compressed (at a point in its lifetime) with a lossy algorithm and changes have been introduced into the pixel data. Once the value has been set to “01â€, it shall not be reset. +Note: If an image is compressed with a lossy algorithm, the attribute Lossy Image Compression (0028,2110) is set to “01â€. Subsequently, if the image is decompressed and transferred in uncompressed format, this attribute value remains “01â€. + +The value of the Lossy Image Compression (0028,2110) Attribute in SOP Instances containing multiple frames in which one or more of the frames have undergone lossy compression shall be “01â€. +Note: It is recommended that the applicable frames be noted in the Attribute Derivation Description (0008,2111). + +If an image is originally obtained as a lossy compressed image from the sensor, then Lossy Image Compression (0028,2110) is set to “01†and Value 1 of the Attribute Image Type (0008,0008) shall be set to ORIGINAL. +If an image is a compressed version of another image, Lossy Image Compression (0028,2110) is set to “01â€, Value 1 of the Attribute Image Type (0008,0008) shall be set to DERIVED, and if the predecessor was a DICOM image, then the Image shall receive a new SOP Instance UID. +Note: 1. It is recommended that the approximate compression ratio be provided in the Attribute Derivation Description (0008,2111). Furthermore, it is recommended that Derivation Description (0008,2111) be used to indicate when pixel data changes might affect professional interpretation. (see C.7.6.1.1.3). + 2. The attribute Lossy Image Compression (0028,2110) is defined as Type 3 for backward compatibility with existing IODs. It is expected to be required (i.e., defined as Type 1C) for new Image IODs and for existing IODs that undergo a major revision (e.g. a new IOD is specified). +The Defined Terms for Lossy Image Compression Method (0028,2114) are: +ISO_10918_1 = JPEG Lossy Compression +ISO_14495_1 = JPEG-LS Near-lossless Compression +ISO_15444_1 = JPEG 2000 Irreversible Compression +ISO_13818_2 = MPEG2 Compression + +
+
+ + See C.7.6.1.1.5 for further explanation. +Required if Lossy Image Compression (0028,2110) equals 01. +
The Attribute Lossy Image Compression (0028,2110) conveys that the Image has undergone lossy compression. It provides a means to record that the Image has been compressed (at a point in its lifetime) with a lossy algorithm and changes have been introduced into the pixel data. Once the value has been set to “01â€, it shall not be reset. +Note: If an image is compressed with a lossy algorithm, the attribute Lossy Image Compression (0028,2110) is set to “01â€. Subsequently, if the image is decompressed and transferred in uncompressed format, this attribute value remains “01â€. + +The value of the Lossy Image Compression (0028,2110) Attribute in SOP Instances containing multiple frames in which one or more of the frames have undergone lossy compression shall be “01â€. +Note: It is recommended that the applicable frames be noted in the Attribute Derivation Description (0008,2111). + +If an image is originally obtained as a lossy compressed image from the sensor, then Lossy Image Compression (0028,2110) is set to “01†and Value 1 of the Attribute Image Type (0008,0008) shall be set to ORIGINAL. +If an image is a compressed version of another image, Lossy Image Compression (0028,2110) is set to “01â€, Value 1 of the Attribute Image Type (0008,0008) shall be set to DERIVED, and if the predecessor was a DICOM image, then the Image shall receive a new SOP Instance UID. +Note: 1. It is recommended that the approximate compression ratio be provided in the Attribute Derivation Description (0008,2111). Furthermore, it is recommended that Derivation Description (0008,2111) be used to indicate when pixel data changes might affect professional interpretation. (see C.7.6.1.1.3). + 2. The attribute Lossy Image Compression (0028,2110) is defined as Type 3 for backward compatibility with existing IODs. It is expected to be required (i.e., defined as Type 1C) for new Image IODs and for existing IODs that undergo a major revision (e.g. a new IOD is specified). +The Defined Terms for Lossy Image Compression Method (0028,2114) are: +ISO_10918_1 = JPEG Lossy Compression +ISO_14495_1 = JPEG-LS Near-lossless Compression +ISO_15444_1 = JPEG 2000 Irreversible Compression +ISO_13818_2 = MPEG2 Compression + +
+
+ + A label for the lossy compression method(s) that have been applied to the source images. +See C.7.6.1.1.5 for further explanation. +May be multi-valued if successive lossy compression steps have been applied; the value order shall correspond to the values of Lossy Image Compression Ratio (0028,2112). +Note: For historical reasons, the lossy compression method may also be described in Derivation Description (0008,2111). +Required if Lossy Image Compression (0028,2110) equals 01. +
The Attribute Lossy Image Compression (0028,2110) conveys that the Image has undergone lossy compression. It provides a means to record that the Image has been compressed (at a point in its lifetime) with a lossy algorithm and changes have been introduced into the pixel data. Once the value has been set to “01â€, it shall not be reset. +Note: If an image is compressed with a lossy algorithm, the attribute Lossy Image Compression (0028,2110) is set to “01â€. Subsequently, if the image is decompressed and transferred in uncompressed format, this attribute value remains “01â€. + +The value of the Lossy Image Compression (0028,2110) Attribute in SOP Instances containing multiple frames in which one or more of the frames have undergone lossy compression shall be “01â€. +Note: It is recommended that the applicable frames be noted in the Attribute Derivation Description (0008,2111). + +If an image is originally obtained as a lossy compressed image from the sensor, then Lossy Image Compression (0028,2110) is set to “01†and Value 1 of the Attribute Image Type (0008,0008) shall be set to ORIGINAL. +If an image is a compressed version of another image, Lossy Image Compression (0028,2110) is set to “01â€, Value 1 of the Attribute Image Type (0008,0008) shall be set to DERIVED, and if the predecessor was a DICOM image, then the Image shall receive a new SOP Instance UID. +Note: 1. It is recommended that the approximate compression ratio be provided in the Attribute Derivation Description (0008,2111). Furthermore, it is recommended that Derivation Description (0008,2111) be used to indicate when pixel data changes might affect professional interpretation. (see C.7.6.1.1.3). + 2. The attribute Lossy Image Compression (0028,2110) is defined as Type 3 for backward compatibility with existing IODs. It is expected to be required (i.e., defined as Type 1C) for new Image IODs and for existing IODs that undergo a major revision (e.g. a new IOD is specified). +The Defined Terms for Lossy Image Compression Method (0028,2114) are: +ISO_10918_1 = JPEG Lossy Compression +ISO_14495_1 = JPEG-LS Near-lossless Compression +ISO_15444_1 = JPEG 2000 Irreversible Compression +ISO_13818_2 = MPEG2 Compression + +
+
+
+ + + Sequence that describes the orientation of the patient with respect to gravity. +See C.8.11.5.1.2 for further explanation. +Only a single Item shall be permitted in this Sequence. +
This Attribute is not related to Patient Orientation (0020,0020) and conveys a different concept entirely. +
+
+ + + Patient orientation modifier. +Required if needed to fully specify the orientation of the patient with respect to gravity. +Only a single Item shall be permitted in this Sequence. + + + + Sequence that describes the orientation of the patient with respect to the head of the table. See Section C.8.4.6.1.3 for further explanation. +Only a single Item shall be permitted in this Sequence. +
Patient Gantry Relationship Code Sequence (0054,0414) is used to describe the patient direction within the gantry, such as head-first or feet-first. When imaging the extremities, these directions are related to normal anatomic position. +Example: In normal anatomic position, the fingers point towards the feet. +
+
+ +
+ + + User or equipment generated identifier of that part of a Procedure that has been carried out within this step. + + + Date on which the Performed Procedure Step started. + + + Time on which the Performed Procedure Step started. + + + Institution-generated description or classification of the Procedure Step that was performed. + + + Sequence describing the Protocol performed for this Procedure Step. One or more Items may be included in this Sequence. + + + + Sequence that specifies the context for the Performed Protocol Code Sequence Item. One or more items may be included in this sequence. + + + + Sequence that specifies modifiers for a Protocol Context Content Item. One or more items may be included in this sequence. See Section C.4.10.1. +
The Protocol Context Sequence (0040,0440) allows the specification of parameters that further qualify the scheduled protocol, provided through a set of generic name/value pairs of context Content Items. +Note: This allows the specification of clinical, acquisition, or procedural qualifiers for the scheduled protocol, such as a specific body part, imaging technique, or parameters of a preparatory event (e.g., radionuclide injection). Specific uses of this Sequence may be documented in a Template defined in accordance with PS3.16. + +
+
+ + + User-defined comments on the Performed Procedure Step. + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Uniquely identifies the Study SOP Instances associated with the Patient SOP Instance. One or more Items may be included in this Sequence. + + + + Uniquely identifies the Visit SOP Instances associated with this Patient SOP Instance. One or more Items may be included in this Sequence. + + + + Uniquely identifies any Patient SOP Instances that also describe this patient. These SOP Instances are aliases. Zero or more Items may be included in this Sequence. + + + + + + Patient's full name + + + Primary hospital identification number or code for the patient. + + + Identifier of the Assigning Authority (system, organization, agency, or department) that issued the Patient ID. +Note: Issuer of Patient ID (0010,0021) is equivalent to HL7 v2 PID-3 component 4. + + + Other identification numbers or codes used to identify the patient. + + + A sequence of identification numbers or codes used to identify the patient, which may or may not be human readable, and may or may not have been obtained from an implanted or attached device such as an RFID or barcode. + + + An identification number or code used to identify the patient + + + Identifier of the Assigning Authority that issued the Patient ID. + + + The type of identifier in this item. Defined Terms: +TEXT +RFID +BARCODE +Note: The identifier is coded as a string regardless of the type, not as a binary value. + + + Other names used to identify the patient. + + + Patient's birth name. + + + Birth name of patient's mother. + + + An identifier used to find the patient's existing medical record (e.g. film jacket). + + + + + Age of the Patient. + + + Occupation of the Patient. + + + Special indication to the modality operator about confidentiality of patient information (e.g., that he should not use the patients name where other patients are present). + + + Date of birth of the named patient + + + Time of birth of the named patient + + + Sex of the named patient. Enumerated Values: +M = male +F = female +O = other + + + A sequence that conveys the patient's insurance plan. Zero or more Items may be included in this Sequence. + + + + The languages that can be used to communicate with the patient. +Zero or more Items may be included in the sequence. The sequence items are ordered by preference (most preferred language to least preferred language). + + + + A modifer for a Patient's Primary Language. Can be used to specify a national language variant. +Exactly one Item may be included in the sequence. + + + + Patient's height or length in meters + + + Weight of the patient in kilograms + + + Legal address of the named patient + + + Military rank of patient + + + Branch of the military. The country allegiance may also be included (e.g. U.S. Army). + + + Country in which patient currently resides + + + Region within patient's country of residence + + + Telephone numbers at which the patient can be reached + + + Ethnic group or race of patient + + + The religious preference of the patient + + + User-defined comments about the patient + + + Name of person with medical decision making authority for the patient. + + + Relationship of Responsible Person to the patient. +Defined Terms: +OWNER + + + Name of organization with medical decision making authority for the patient. + + + The species of the patient. + + + The species of the patient. + + + + The breed of the patient. + + + The breed of the patient. + + + + Information identifying an animal within a breed registry. + + + Identification number of a veterinary patient within the registry. + + + Identification of the organization with which an animal is registered. + + + + + + Conditions to which medical staff should be alerted (e.g. contagious condition, drug allergies, etc.) + + + Description of prior reaction to contrast agents, or other patient allergies or adverse reactions. + + + Indicates whether patient smokes. +Enumerated Values: +YES +NO +UNKNOWN + + + Additional information about the patient's medical history + + + Describes pregnancy state of patient. +Enumerated Values: +0001 = not pregnant +0002 = possibly pregnant +0003 = definitely pregnant +0004 = unknown + + + Date of onset of last menstrual period + + + Whether or not a procedure has been performed in an effort to render the patient sterile. +Enumerated value: +ALTERED = Altered/Neutered +UNALTERED = Unaltered/intact + + + Medical and social needs (e.g. wheelchair, oxygen, translator, etc.) + + + Description of patient state (comatose, disoriented, vision impaired, etc.) + + + List of Documents (e.g., SR, or CDA) that contain information considered pertinent for the patient medical condition. +Zero or more Items may be included in this sequence. + + + + Describes the purpose for which the document reference is made. Zero or more Items may be present. + + + + Title of the referenced document. + + + Sequence of identifiers for clinical trials in which the patient participates. +Zero or more Items may be included in this sequence. + + + The name of the clinical trial sponsor, responsible for conducting the clinical trial and for defining the Clinical Trial Protocol. + + + Identifier for the noted protocol, used by the Clinical Trial Sponsor to uniquely identify the investigational protocol. + + + The name or title of the clinical trial protocol. + + + The identifier, issued by the Clinical Trial Sponsor, of the site responsible for submitting clinical trial data. + + + Name of the site responsible for submitting clinical trial data. + + + The assigned identifier for the patient as a clinical trial subject. + + + Identifies the patient as a clinical trial subject for blinded evaluations. + + + + + Uniquely identifies the Study SOP Instances associated with the Visit SOP Instance. One or more Items may be included in this Sequence. + + + + Uniquely identifies the Patient SOP Instance that relates to the Visit SOP Instance. Only a single Item shall be permitted in this Sequence. + + + + + + Institution where the equipment is located + + + Mailing Address of the institution where the equipment is located + + + A sequence that conveys the healthcare facility identification. Only a single Item shall be permitted in this Sequence. + + + + Identification number of the visit as assigned by the healthcare provider + + + Name of healthcare provider which issued the Admission ID + + + Identifier of the Service Episode as assigned by the healthcare provider + + + Name of healthcare provider that issued the Service Episode ID + + + Description of the type of service episode. + + + + + Identifies the state of the visit. Defined Terms: +CREATED = Created but not yet scheduled +SCHEDULED = Scheduled but not yet admitted +ADMITTED = Patient admitted to institution +DISCHARGED = Patient Discharged + + + Describes the current known location of the patient + + + Primary location where patient resides (ward, floor, room, etc. or outpatient) + + + User-defined comments about the visit + + + + + Patient's primary referring physician for this visit + + + Referring physician's address + + + Referring physician's telephone numbers + + + Identification of the patient's referring physician. Only a single item shall be permitted in this sequence. + + + + Description of admitting diagnosis (diagnoses). + + + A sequence that conveys the admitting diagnosis (diagnoses). One or more Items may be included in this Sequence. + + + + Mode of admission: emergency, normal + + + Date patient visit began + + + Time patient visit began + + + + + One or more Scheduled Procedure Steps for one Requested Procedure. + + + The AE title of the modality on which the Scheduled Procedure Step is scheduled to be performed. + + + An institution defined name for the modality on which the Scheduled Procedure Step is scheduled to be performed. + + + The location at which the Procedure Step is scheduled to be performed. + + + Date on which the Scheduled Procedure Step is scheduled to start. + + + Time at which the Scheduled Procedure Step is scheduled to start. + + + Date on which the Scheduled Procedure Step is scheduled to end. + + + Time at which the Scheduled Procedure Step is scheduled to end. + + + Name of the physician scheduled to administer the Scheduled Procedure Step. + + + Identification of the physician scheduled to administer the Scheduled Procedure Step. Only a single item shall be permitted in this sequence. + + + + Institution-generated description or classification of the Scheduled Procedure Step to be performed. +Note: The purpose of this attribute is to store a description or classification that is used at a local level (e.g., a hospital or a managed care network), and this description need not comply to an accepted standard. + + + Sequence describing the Scheduled Protocol following a specified coding scheme. This sequence contains one or more Items. + + + + Sequence that specifies the context for the Scheduled Protocol Code Sequence Item. One or more items may be included in this sequence. See Section C.4.10.1. +
The Protocol Context Sequence (0040,0440) allows the specification of parameters that further qualify the scheduled protocol, provided through a set of generic name/value pairs of context Content Items. +Note: This allows the specification of clinical, acquisition, or procedural qualifiers for the scheduled protocol, such as a specific body part, imaging technique, or parameters of a preparatory event (e.g., radionuclide injection). Specific uses of this Sequence may be documented in a Template defined in accordance with PS3.16. + +
+
+ + + Sequence that specifies modifiers for a Protocol Context Content Item. One or more items may be included in this sequence. See Section C.4.10.1. +
The Protocol Context Sequence (0040,0440) allows the specification of parameters that further qualify the scheduled protocol, provided through a set of generic name/value pairs of context Content Items. +Note: This allows the specification of clinical, acquisition, or procedural qualifiers for the scheduled protocol, such as a specific body part, imaging technique, or parameters of a preparatory event (e.g., radionuclide injection). Specific uses of this Sequence may be documented in a Template defined in accordance with PS3.16. + +
+
+ + + Identifier that identifies the Scheduled Procedure Step. + + + A real world condition that may affect the selection of of the Scheduled Procedure Step. Defined Terms: +SCHEDULED - Procedure Step scheduled +ARRIVED - patient is available for the Scheduled Procedure Step +READY - all patient and other necessary preparation for this step has been completed +STARTED - at least one Performed Procedure Step has been created that references this Scheduled Procedure Step + + + User-defined comments on the Scheduled Procedure Step. +Note: The Comments attribute is intended to transmit non-structured information, which can be displayed to the operator of the Modality. + + + Source equipment for the image. See Section C.7.3.1.1.1 for Defined Terms. +
Defined Terms for the Modality (0008,0060) are: + +Retired Defined Terms for the Modality (0008,0060) are: + +Note: 1. The XA modality incorporates the retired modality DS. + 2. The RF modality incorporates the retired modalities CF, DF, VF. + 3. The modality listed in the Modality Data Element (0008,0060) may not match the name of the IOD in which it appears. For example, a SOP instance from XA IOD may list the RF modality when an RF implementation produces an XA object. + 4. The MR modality incorporates the retired modalities MA and MS. + +
+
+ + Contrast agent requested for use in the Scheduled Procedure Step. + + + Medication to be administered at the beginning of the Scheduled Procedure Step, e.g. Nuclear Medicine radiopharmaceutical. + +
+ + + Identifier that identifies the Requested Procedure in the Imaging Service Request. + + + Reason for requesting this imaging procedure. +Note: This reason is more specific to the requested procedure than the reason mentioned in the imaging service request (0040,2001). + + + User-defined comments on the Requested Procedure. + + + Coded Reason for requesting this procedure. +One or more sequence items may be present. + + + + A sequence that conveys the Requested Procedure of one Procedure Type. + + + + Unique identifier to be used to identify the Study + + + Date the Study started, if any previous procedure steps within the same study have already been performed. + + + Time the Study started, if any previous procedure steps within the same study have already been performed. + + + Uniquely identifies the Study SOP Instances associated with this SOP Instance. + + + + Institution-generated administrative description or classification of Requested Procedure + + + Requested Procedure Type Urgency. Defined Terms: +STAT, HIGH, ROUTINE, MEDIUM, LOW + + + Mode of transportation of the patient to the location of examination. + + + Physical location at which the Requested Procedure is to be performed. + + + Confidentiality Constraints on the Requested Procedure by the party filling the order. + + + Requested Reporting Priority. Defined Terms: +HIGH, ROUTINE, MEDIUM, LOW + + + Names of the physicians, who are intended recipients of results. + + + Identification of the physicians who are intended recipients of results. One or more items shall be included in this sequence. If more than one Item, the number and order shall correspond to the value of Names of Intended Recipients of Results (0040,1010), if present. + + + + + + User-defined comments on the Imaging Service Request. +Note: The Comments attribute is intended to transmit non-structured information, which can be displayed to the operator of the equipment (e.g. Modality). + + + Name of the physician who requested the Imaging Service Request. + + + Identification of the physician who requested the Imaging Service Request. Only a single item shall be permitted in this sequence. + + + + Name of the patient's referring physician for this Imaging Service Request. + + + Identification of the patient's referring physician. Only a single item shall be permitted in this sequence. + + + + Institutional department where the request initiated. + + + A departmental IS generated number that identifies the order for the Imaging Service Request. + + + Date on which the Imaging Service Request was issued by the requester. + + + Time at which the Imaging Service Request was issued by the requester. + + + The order number assigned to the Imaging Service Request by the party placing the order. + + + The order number assigned to the Imaging Service Request by the party filling the order. + + + The person who entered the Imaging Service Request into an Information System. + + + The location at which the Imaging Service Request was entered. + + + Telephone Number at which additional information can be retrieved. + + + Identification number of the visit as assigned by the healthcare provider + + + Name of healthcare provider that issued the Admission ID + + + + + Patient's full legal name. + + + Primary hospital identification number or code for the patient. + + + Identifier of the Assigning Authority that issued the Patient ID. + + + Date of birth of the named patient + + + Sex of the named Patient. Enumerated Values: +M = male +F = female +O = other + + + Uniquely identifies the Patient SOP Instance. + + + + Identifier of the Service Episode as assigned by the healthcare provider + + + Name of healthcare provider that issued the Service Episode ID + + + Description of the type of service episode. + + + Sequence containing attributes that are related to the scheduling of the Procedure Step. The Sequence may have one or more Items. + + + Unique identifier for the Study. + + + Uniquely identifies the Study SOP Instance associated with this Scheduled Procedure Step. This Sequence shall have only one Item. + + + + A departmental IS generated number that identifies the order for the Study. + + + The order number assigned to the Imaging Service Request by the party placing the order. + + + The order number assigned to the Imaging Service Request by the party filling the order. + + + Identifier of the related Requested Procedure. + + + Institution-generated administrative description or classification of Requested Procedure. + + + A sequence that conveys the Procedure Type of the requested procedure. The Requested Procedure Code Sequence shall contain only a single item. + + + + Identifier of the related Scheduled Procedure Step. + + + Institution-generated description or classification of the Scheduled Procedure Step to be performed. + + + Sequence describing the Scheduled Protocol following a specific coding scheme. This sequence contains one or more Items. + + + + Sequence that specifies the context for the Scheduled Protocol Code Sequence Item. One or more items may be included in this sequence. See Section C.4.10.1. +
The Protocol Context Sequence (0040,0440) allows the specification of parameters that further qualify the scheduled protocol, provided through a set of generic name/value pairs of context Content Items. +Note: This allows the specification of clinical, acquisition, or procedural qualifiers for the scheduled protocol, such as a specific body part, imaging technique, or parameters of a preparatory event (e.g., radionuclide injection). Specific uses of this Sequence may be documented in a Template defined in accordance with PS3.16. + +
+
+ + + Sequence that specifies modifiers for a Protocol Context Content Item. One or more items may be included in this sequence. See Section C.4.10.1. +
The Protocol Context Sequence (0040,0440) allows the specification of parameters that further qualify the scheduled protocol, provided through a set of generic name/value pairs of context Content Items. +Note: This allows the specification of clinical, acquisition, or procedural qualifiers for the scheduled protocol, such as a specific body part, imaging technique, or parameters of a preparatory event (e.g., radionuclide injection). Specific uses of this Sequence may be documented in a Template defined in accordance with PS3.16. + +
+
+ +
+ + + AE title of the modality on which the Performed Procedure Step was performed. + + + An institution defined name for the modality on which the Performed Procedure Step was performed. + + + Description of the location at which the Performed Procedure Step was performed. + + + Date on which the Performed Procedure Step started. +Note: This value may be used to determine the earliest date to use as the Study Date (0008,0020) in composite instances and in updated Modality Scheduled Procedure Steps in order to allow Study level attributes to have consistent values if additional Procedure Steps are performed. + + + Time at which the Performed Procedure Step started. +Note: This value may be used to determine the earliest time to use as the Study Time (0008,0030) in composite instances and in updated Modality Scheduled Procedure Steps in order to allow Study level attributes to have consistent values if additional Procedure Steps are performed. + + + User or equipment generated identifier of that part of a Procedure that has been carried out within this step. + + + Date on which the Performed Procedure Step ended. + + + Time at which the Performed Procedure Step ended. + + + Contains the state of the Performed Procedure Step. Enumerated Values: +IN PROGRESS = Started but not complete +DISCONTINUED = Canceled or unsuccessfully terminated +COMPLETED = Successfully completed + + + Institution-generated description or classification of the Procedure Step that was performed. + + + User-defined comments on the Performed Procedure Step. + + + A description of the type of procedure performed. + + + A sequence that conveys the (single) type of procedure performed. + + + + The reason the Performed Procedure Step Status (0040,0252) was set to DISCONTINUED. + + + + + + Type of equipment that originally acquired the data used to create the images associated with this Modality Performed Procedure Step. See C.7.3.1.1.1 for Defined Terms. +Note: A Modality value in the created SOP Instances may be different from the MPPS Modality value. For example, multiple series may have been created during the MPPS (images, waveforms, softcopy presentation states and/or structured reports) with SOP Instances in different series having different modality values. +
Defined Terms for the Modality (0008,0060) are: + +Retired Defined Terms for the Modality (0008,0060) are: + +Note: 1. The XA modality incorporates the retired modality DS. + 2. The RF modality incorporates the retired modalities CF, DF, VF. + 3. The modality listed in the Modality Data Element (0008,0060) may not match the name of the IOD in which it appears. For example, a SOP instance from XA IOD may list the RF modality when an RF implementation produces an XA object. + 4. The MR modality incorporates the retired modalities MA and MS. + +
+
+ + User or equipment generated Study Identifier. + + + Sequence describing the Protocol performed for this Procedure Step. This sequence may have zero or more Items. + + + + Sequence that specifies the context for the Performed Protocol Code Sequence Item. One or more items may be included in this sequence. See Section C.4.10.1. +
The Protocol Context Sequence (0040,0440) allows the specification of parameters that further qualify the scheduled protocol, provided through a set of generic name/value pairs of context Content Items. +Note: This allows the specification of clinical, acquisition, or procedural qualifiers for the scheduled protocol, such as a specific body part, imaging technique, or parameters of a preparatory event (e.g., radionuclide injection). Specific uses of this Sequence may be documented in a Template defined in accordance with PS3.16. + +
+
+ + + Sequence that specifies modifiers for a Protocol Context Content Item. One or more items may be included in this sequence. See Section C.4.10.1. +
The Protocol Context Sequence (0040,0440) allows the specification of parameters that further qualify the scheduled protocol, provided through a set of generic name/value pairs of context Content Items. +Note: This allows the specification of clinical, acquisition, or procedural qualifiers for the scheduled protocol, such as a specific body part, imaging technique, or parameters of a preparatory event (e.g., radionuclide injection). Specific uses of this Sequence may be documented in a Template defined in accordance with PS3.16. + +
+
+ + + Attributes of the Series that comprise this Modality Performed Procedure Step. The Sequence may have zero or more Items. + + + Name of the physician(s) administering this Series. + + + Identification of the physician(s) administering the Series. One or more items shall be included in this sequence. If more than one Item, the number and order shall correspond to the value of Performing Physician's Name (0008,1050), if present. + + + + Name(s) of the operator(s) who supporting this Series. + + + Identification of the operator(s) supporting the Series. One or more items shall be included in this sequence. If more than one Item, the number and order shall correspond to the value of Operators' Name (0008,1070), if present. + + + + User-defined description of the conditions under which the Series was performed. +Note: This attribute conveys series-specific protocol identification and may or may not be identical to the one presented in the Performed Protocol Code Sequence (0040,0260). + + + Unique Identifier of the Series. + + + User provided description of the Series + + + Title of the DICOM Application Entity where the Images and other Composite SOP Instances in this Series may be retrieved on the network. +Note: The duration for which this location remains valid is unspecified. + + + The instances in this series are expected to be archived in the long term archive. +Defined Terms: +NO, YES + + + A Sequence that provides reference to Composite SOP Instances created during the acquisition of the procedure step. The sequence may have zero or more Items. +Note: The use of Referenced Image Sequence is historical, and in this context it allows the reference of any Composite SOP Instance. + + + + Uniquely identifies instances, other than images, of any SOP Class that conforms to the DICOM Composite IOD Information Model, such as Waveforms, Presentation States or Structured Reports, created during the acquisition of the procedure step, and that are not referenced in Referenced Image Sequence (0008,1140). The sequence may have zero or more Items. + + +
+ + + Anatomic structure, space or region that has been exposed to ionizing radiation. The sequence may have zero or one Items. + + + + Total duration of X-Ray exposure during fluoroscopy in seconds (pedal time) during this Performed Procedure Step. + + + Total number of exposures made during this Performed Procedure Step. The number includes non-digital and digital exposures. + + + Distance in mm from the source to detector center. +Note: This value is traditionally referred to as Source Image Receptor Distance (SID). + + + Distance in mm from the source to the surface of the patient closest to the source during this Performed Procedure Step. +Note: This may be an estimated value based on assumptions about the patient's body size and habitus. + + + Average entrance dose value measured in dGy at the surface of the patient during this Performed Procedure Step. +Note: This may be an estimated value based on assumptions about the patient's body size and habitus. + + + Average entrance dose value measured in mGy at the surface of the patient during this Performed Procedure Step. +Note: This may be an estimated value based on assumptions about the patient's body size and habitus. + + + Typical dimension of the exposed area at the detector plane. If Rectangular: row dimension followed by column; if Round: diameter. Measured in mm. +Notes: 1. This may be an estimated value based on assumptions about the patient's body size and habitus. +2. This attribute is used in the X-Ray Acquisition Dose Module with units in cm (see Section C 8.7.8 Table C.8-33). + + + Total area-dose-product to which the patient was exposed, accumulated over the complete Performed Procedure Step and measured in dGy*cm*cm, including fluoroscopy. +Notes: 1. The sum of the area dose product of all images of a Series or a Study may not result in the total area dose product to which the patient was exposed. +2. This may be an estimated value based on assumptions about the patient's body size and habitus. + + + User-defined comments on any special conditions related to radiation dose encountered during this Performed Procedure Step. + + + Exposure Dose Sequence will contain Total Number of Exposures (0040,0301) items plus an item for each fluoroscopy episode not already counted as an exposure. + + + Specifies X-Ray radiation mode. Enumerated Values: +CONTINUOUS +PULSED + + + Peak kilo voltage output of the x-ray generator used. An average in the case of fluoroscopy (continuous radiation mode). + + + X-Ray Tube Current in µA. An average in the case of fluoroscopy (continuous radiation mode). + + + Time of x-ray exposure or fluoroscopy in msec. + + + Type of filter(s) inserted into the X-Ray beam (e.g. wedges). See C.8.7.10 and C.8.15.3.9 (for enhanced CT) for Defined Terms. +
This Module describes the attributes related to the filtration of X-Rays during the acquisition of an X-Ray image. +Table C.8-35 +X-RAY FILTRATION MODULE ATTRIBUTES + +
+
+ + The X-Ray absorbing material used in the filter. May be multi-valued. See C.8.7.10 and C.8.15.3.9 (for enhanced CT) for Defined Terms. +
This Module describes the attributes related to the filtration of X-Rays during the acquisition of an X-Ray image. +Table C.8-35 +X-RAY FILTRATION MODULE ATTRIBUTES + +
+
+ + User-defined comments on any special conditions related to radiation dose encountered during during the episode described by this Exposure Dose Sequence Item. + +
+ + + Contains billing codes for the Procedure Type performed within the Procedure Step. The sequence may have zero or more Items. + + + + Information about the film consumption for this Performed Procedure Step. The sequence may have zero or more Items. + + + Number of films actually printed. + + + Type(s) of medium on which images were printed. For Defined Terms see Table C.13-1. + + + Size(s) of film on which images were printed. For Defined Terms see Table C.13-3. + + + Chemicals, supplies and devices for billing used in the Performed Procedure Step. The sequence may have one or more Items. + + + Code values of chemicals, supplies or devices required for billing. The sequence may have zero or one Items. + + + + Sequence containing the quantity of used chemicals or devices. The sequence may have zero or one Items. + + + Numerical quantity value. + + + Unit of measurement. The sequence may have zero or one Items. + + + + + + Patient's full legal name. + + + Primary hospital identification number or code for the patient. + + + Identifier of the Assigning Authority that issued the Patient ID. + + + Date of birth of the named patient. + + + Sex of the named Patient. +Enumerated Values: +M = male +F = female +O = other + + + The list of Requested Procedures the Procedure Step shall contribute to. +One or more Items may be included in the sequence. + + + Unique identifier for the Study. + + + Uniquely identifies the Study SOP Instance that represents the Requested Procedure. +Zero or one Item may be included in this sequence. + + + Uniquely identifies the SOP Class. + + + Uniquely identifies the SOP Instance. + + + A departmental IS generated number that identifies the Imaging Service Request. + + + A sequence that conveys the Procedure Type of the Requested Procedure. +Zero or one Item may be included in this sequence. + + + + The order number assigned to the Imaging Service Request by the party placing the order. + + + The order number assigned to the Imaging Service Request by the party filling the order. + + + Identifier that identifies the Requested Procedure in the Imaging Service Request. + + + Institution-generated description or classification of the Requested Procedure. + + + Reason for requesting this procedure. + + + Coded reason for requesting this procedure. + + + + User-defined comments on the Requested Procedure. + + + Confidentiality Constraints on the Requested Procedure by the party filling the order. + + + Names of the physicians, who are intended recipients of results. + + + User-defined comments on the Imaging Service Request. + + + Physician who requested the Imaging Service Request. + + + Institutional department where the request initiated. + + + Date on which the Imaging Service Request was issued by the requester. + + + Time at which the Imaging Service Request was issued by the requester. + + + Patient's primary physician for this Imaging Service Request. + + + + + A status that informs the operator and the worklist management system about the progress of the scheduled General Purpose procedure step. +Enumerated Values are: +SCHEDULED, IN PROGRESS, SUSPENDED, COMPLETED, DISCONTINUED. +See PS 3.4 for a detailed description of the meaning and usage of these values. + + + Scheduled Procedure Step priority. +Enumerated Values are: +HIGH: used to indicate an urgent or emergent work item, equivalent to a STAT request. +MEDIUM: used to indicate a work item that has a priority less than HIGH and higher than LOW. It can be used to further stratify work items. +LOW: used to indicate a routine or non-urgent work item. + + + Identifier that identifies the Scheduled General Purpose Procedure Step. + + + Date and time when the General Purpose Scheduled Procedure Step was last modified or first created (whichever is most recent). +Note: This attribute should be implicitly updated by the worklist management system whenever any modification is made to attributes of a General Purpose Scheduled Procedure Step. In particular, note that creation of General Purpose Performed Procedure Steps by a performing device can modify attributes of a related General Purpose Scheduled Procedure Step (e.g. the contents of Resulting General Purpose Performed Procedure Steps Sequence (0040,4015)). + + + The list of processing application instances and/or application types on which the General Purpose Procedure Step is scheduled. +Zero or more Items may be included in this sequence. + + + + Identifying name within the enterprise of the equipment for which the General Purpose Scheduled Procedure Step is scheduled. The name conveyed in the Code Value (0008,0100) may be the same as the AE Title, but does not have to be. +Zero or more Items may be included in this sequence. + + + + Class of the equipment for which the General Purpose Scheduled Procedure Step is scheduled. +Zero or more Items may be included in this sequence. + + + + Geographic location of the equipment for which the General Purpose Scheduled Procedure Step is scheduled. +Zero or more Items may be included in this sequence. + + + + The list of human performers that are scheduled to be involved or responsible for performing the Workitem in the General Purpose Scheduled Procedure Step. +Zero or more Items may be included in this sequence. + + + Human performer that is involved or responsible for performing the Workitem. +Only a single Item shall be permitted in this sequence. + + + + Name of the human performer. + + + Organization to which the human performer is accountable for the activities in the Workitem. + + + Date and time on which the General Purpose Scheduled Procedure Step is scheduled to start. + + + Date on which the Procedure Step is expected to be completed. + + + A sequence that conveys the code for the Workitem. +Only a single Item shall be permitted in this sequence. + + + + User-defined comments on the Scheduled Procedure Step. + + + List of any Modality or General Purpose Performed Procedure Steps, that may be used to perform the procedure step. +This sequence may contain references to performed procedure steps resulting from previous contributions to the performance of the procedure step (e.g. an image processing procedure step interrupted, and completed later). +Zero or more Items may be included in this sequence. + + + + Flag that indicates the availability of Composite SOP Instances in the Attribute "Input Information Sequence" (0040,4021) of the General Purpose Scheduled Procedure Step. +Enumerated values are: +PARTIAL +COMPLETE +The value PARTIAL denotes that the list of Composite SOP Instances may not yet be complete, and additional ones may be added at a later time. +The value COMPLETE denotes that all Composite SOP Instances are available and listed. +Note: It may happen that the list of Composite SOP Instances is empty when the value of the Input Availability Flag is COMPLETE. In such a case a Workitem has been scheduled that does not require input information. + + + List of Composite SOP Instances that forms the input information needed to perform the scheduled procedure step. See also Input Availability Flag (0040,4020). The same Composite SOP Instance shall not be included in both the Input Information Sequence (0040,4021) and the Relevant Information Sequence (0040,4022). +Zero or more Items may be included in this sequence. + + + + List of Composite SOP Instances that refers to relevant information that is considered pertinent for the performance of the scheduled procedure step. The same Composite SOP Instance shall not be included in both the Input Information Sequence (0040,4021) and the Relevant Information Sequence (0040,4022). +Zero or more Items may be included in this sequence. + + + + Unique Study identification that shall be used for the created Composite SOP Instances resulting from this General Purpose Scheduled Procedure Step. +Note: In most cases this will be the same Study Instance UID as for the instances in the Input Information Sequence (0040,4021). + + + Date the Study started, if any previous procedure steps within the same study have already been performed. +Note: This value should be the same as that in the instances in the Input Information Sequence (0040,4021). + + + Time the Study started, if any previous procedure steps within the same study have already been performed. +Note: This value should be the same as that in the instances in the Input Information Sequence (0040,4021). + + + This flag indicates that multiple copies have to be made of a Composite SOP Instance that supports the notion of multiple copies. This includes the SR SOP Class. If set the Study Instance UIDs in the Referenced Request Sequence (0040,A370) shall be used for the created multiple copies. +Enumerated Values: +Y = Yes +N = No + + + List of all General Purpose Performed Procedure Steps that result from the performance of the procedure step. +Zero or more Items may be included in this sequence. +Note: Initially this list will be empty. New entries will be added when General Purpose Performed Procedure Steps are created by performing devices that are related to this Scheduled Procedure Step. E.g, this sequence may contain the partial results in case a General Purpose Scheduled Procedure Step is discontinued. + + + + The list of current human performers that are actually involved or responsible for performing the Workitem. +Zero or more Items may be included in this sequence. +Note: Initially this list will be empty. A list of entries may be created at the status transition of the General Purpose Scheduled Procedure Step Status (0040,4001) to "IN PROGRESS" + + + Human performer that is involved or responsible for performing the Workitem. +Only a single Item shall be permitted in this sequence. + + + + Name of the human performer. + + + Organization to which the human performer is accountable for the activities in the Workitem. + + + + + Patient's full legal name. + + + Primary hospital identification number or code for the patient. + + + Identifier of the Assigning Authority that issued the Patient ID. + + + Date of birth of the named patient. + + + Sex of the named Patient. +Enumerated Values: +M = male +F = female +O = other + + + The list of Requested Procedures the Procedure Step shall contribute to. +Zero or more Items may be included in the sequence. + + + Unique identifier for the Study. + + + Uniquely identifies the Study SOP Instance associated with this Scheduled Procedure Step. +Only a single Item shall be permitted in this sequence. + + + + A departmental IS generated number that identifies the order for the Study. + + + A sequence that conveys the Procedure Type of the Requested Procedure. +Zero or one Item may be included in this sequence. + + + + The order number assigned to the Imaging Service Request by the party placing the order. + + + The order number assigned to the Imaging Service Request by the party filling the order. + + + Identifier of the related Requested Procedure. + + + Institution-generated administrative description or classification of Requested Procedure. + + + Uniquely identifies the General Purpose Scheduled Procedure Step SOP Instance associated with this General Purpose Performed Procedure Step. +Zero or more Items may be included in this sequence. + + + + Transaction UID (0008,1195) used in the N-ACTION transaction that requested the transition to the IN PROGRESS state for the referenced General Purpose Scheduled Procedure Step. + + + Identification number of the visit as assigned by the healthcare provider + + + Name of healthcare provider that issued the Admission ID + + + Identifier of the Service Episode as assigned by the healthcare provider + + + Name of healthcare provider that issued the Service Episode ID + + + Description of the type of service episode. + + + + + The list of human performers that were actually involved in or responsible for performing this General Purpose Performed Procedure Step. +Zero or more Items may be included in this sequence. + + + Human performer that is actually involved or responsible for performing the General Purpose Performed Procedure Step. +Only a single Item shall be permitted in this sequence. + + + + Name of the human performer. + + + Organization to which the human performer is accountable for the activities in the General Purpose Performed Procedure Step. + + + Name within the enterprise of the equipment that created the General Purpose Performed Procedure Step. This name may be the same as the AE Title, but does not have to be. +Zero or one Item may be included in this sequence. + + + + Class of the equipment that created the General Purpose Performed Procedure Step. +Zero or one Item may be included in this sequence. + + + + Geographic location of the equipment that created General Purpose Performed Procedure Step. Zero or one Item may be included in this sequence. + + + + The list of processing application instances and/or application types on which the General Purpose Performed Procedure Step is executed. +Zero or more Items may be included in this sequence. + + + + Date on which the General Purpose Performed Procedure Step started. +Note: This value may be used to determine the earliest date to use as the Study Date (0008,0020) in composite instances and in updated General Purpose Scheduled Procedure Steps in order to allow Study level attributes to have consistent values if additional Procedure Steps are performed. + + + Time at which the General Purpose Performed Procedure Step started. +Note: This value may be used to determine the earliest time to use as the Study Time (0008,0030) in composite instances and in updated General Purpose Scheduled Procedure Steps in order to allow Study level attributes to have consistent values if additional Procedure Steps are performed. + + + User or equipment generated identifier of that part of a Procedure that has been carried out within this procedure step. + + + Date on which the General Purpose Performed Procedure Step ended. + + + Time at which the General Purpose Performed Procedure Step ended. + + + Contains the state of the Performed Procedure Step. Enumerated Values: +IN PROGRESS = Started but not complete +DISCONTINUED = Canceled or unsuccessfully terminated +COMPLETED = Successfully completed + + + Institution-generated description or classification of the Procedure Step that was performed. + + + User-defined comments on the Performed Procedure Step. This attribute shall not be used as a substitute for the code meaning in the Performed Workitem Code Sequence (0040,4019). + + + A sequence that conveys the (single) type of procedure performed. +Only a single Item shall be permitted in this sequence. + + + + + + A Sequence that provides reference to one or more Composite SOP instances, that identify the Structured Reports or other results created. +Zero or more Items may be included in this sequence. + + + Unique identifier for the Study + + + Sequence of Items where each Item includes the Attributes of a Series containing referenced Composite Object(s). One or more Items may be included in this sequence + + + The instances in this series are expected to be archived in the long term archive. +Defined Terms: +NO, YES + + + + A Sequence that provides suggested next Workitems, based on the produced results. +Note: This Attribute may also be used in case a step has been done incorrectly and should be redone. +Zero or more Items may be included in this sequence + + + + A Sequence that describes any non-DICOM output produced as results. +Zero or more Items may be included in this sequence. + + + + + + Uniquely identifies the Performed Procedure Step SOP Instance to which this availability notification instance is related, if any. The Sequence shall have zero or one Item. +Notes: 1. This may refer to a different PPS than that encoded in the composite instances themselves. +2. It is typically used for notification about instances created as a consequence of some scheduled activity. + + + + A sequence that conveys the (single) type of procedure performed. +Only a single Item shall be permitted in this sequence. + + + + Unique identifier for the Study of which all the Instances referenced in this notification are part. + + + Sequence of Items where each Item includes references to Instances within the same Series. One or more Items shall be included in this Sequence. + + + Unique identifier of the Series of which all the Instances referenced in this Item are part. + + + Sequence of Items where each Item includes a reference to a single Instance within this Series. One or more Items shall be included in this Sequence. + + + + The availability of the referenced Instance. +See Section C.4.23.1.1 +
The Enumerated Values for Instance Availability (0008,0056) are: +
+
+ + Title of the DICOM Application Entity from which the referenced Instance may or may not be retrievable, i.e. the scope for which Instance Availability (0008,0056) applies. See Section C.4.23.1.1. +
The Enumerated Values for Instance Availability (0008,0056) are: +
+
+ + The user or implementation specific human readable identifier that identifies the offline storage media on which the instance resides. + + + Uniquely identifies the offline storage media on which the instance resides. + +
+ + + Patient's full name. + + + Primary hospital identification number or code for the patient. + + + Identifier of the Assigning Authority that issued the Patient ID. + + + Birth date of the patient. + + + Sex of the named patient. +Enumerated Values: +M = male +F = female +O = other + + + A sequence that provides reference to a Patient SOP Class/Instance pair. Only a single Item shall be permitted in this Sequence. + + + + Birth time of the Patient. + + + Other identification numbers or codes used to identify the patient. + + + A sequence of identification numbers or codes used to identify the patient, which may or may not be human readable, and may or may not have been obtained from an implanted or attached device such as an RFID or barcode. +If present, shall contain one or more items. + + + An identification number or code used to identify the patient. + + + Identifier of the Assigning Authority that issued the Patient ID. + + + The type of identifier in this item. Defined Terms: +TEXT +RFID +BARCODE +Note: The identifier is coded as a string regardless of the type, not as a binary value. + + + Other names used to identify the patient. + + + Ethnic group or race of the patient. + + + User-defined additional information about the patient. + + + The species of the patient. +Required if the patient is an animal and if Patient Species Code Sequence (0010,2202) is not present. May be present otherwise. + + + The species of the patient. +One Item shall be present. +Required if the patient is an animal and if Patient Species Description (0010,2201) is not present. May be present otherwise. + + + + The breed of the patient. +Required if the patient is an animal and if Patient Breed Code Sequence (0010,2293) is empty. May be present otherwise. + + + The breed of the patient. +Zero or more Items shall be present. +Required if the patient is an animal. + + + + Information identifying an animal within a breed registry. +Zero or more Items shall be present. +Required if the patient is an animal. + + + Identification number of an animal within the registry. + + + Identification of the organization with which an animal is registered. +One Item shall be present. + + + + Name of person with medical decision making authority for the patient. +Required if the patient is an animal. May be present otherwise. + + + Relationship of Responsible Person to the patient. +Defined Terms: +OWNER +Required if Responsible Person is present and has a value. + + + Name of organization with medical decision making authority for the patient. +Required if patient is an animal. May be present otherwise. + + + The true identity of the patient has been removed from the Attributes and the Pixel Data +Enumerated Values: +YES +NO + + + A description or label of the mechanism or method use to remove the patient's identity. May be multi-valued if successive de-identification steps have been performed. +Note: This may be used to describe the extent or thoroughness of the de-identification, for example whether or not the de-identification is for a "Limited Data Set" (as per HIPAA Privacy Rule). +Required if Patient Identity Removed (0012,0062) is present and has a value of YES and De-identification Method Code Sequence (0012,0064) is not present. + + + A code describing the mechanism or method use to remove the patient's identity. One or more Items shall be present. Multiple items are used if successive de-identification steps have been performed +Required if Patient Identity Removed (0012,0062) is present and has a value of YES and De-identification Method (0012,0063) is not present. + + + + + + A departmental Information System identifier that identifies the Accession. See Section C.7.1.2.1.1 for further explanation. +
Specimen Accession Number (0040,050A) is the primary identifier of the Specimen. +Note: Specimen Accession Number (0040,050A) identifies tissue or fluid obtained from a Patient in a Specimen-harvest procedure. This Attribute was created to differentiate Accession Numbers, as used in Anatomic Pathology to identify specimens, from other uses of the term “Accession Number†in Information Systems. The Specimen Accession Number (0040,050A) is typically unique within the scope of the institution in which the Accession is performed. An Accession may contain multiple Specimens. Typically, an Accession contains the Specimens obtained in one Specimen-harvest procedure and submitted by one Requesting Physician. However, multiple Specimen-harvest procedures may be involved. + +
+
+ + Detailed description of one or more specimens. Zero or more Items may be included in this Sequence. + + + A departmental information system identifier for the Specimen. See Section C.7.1.2.1.2 for further explanation. +
Specimen Identifier (0040,0551) may be used to convey a slide number, a block number, or other secondary identifier of the Specimen. +Note: The Specimen Identifier (0040,0551) is typically unique within the scope of the institution in which the related Accession is performed. However, a value of Specimen Identifier (0040,0551) does not always exist. For example, it is common practice in some Anatomic Pathology departments to use a Specimen Identifier (0040,0551) to identify specimen-containers or blocks only if multiple containers or blocks are submitted for a single Accession. Therefore, Specimen Identifier (0040,0551) is modeled as a Type 2 Attribute. + +
+
+ + Specimen Type. Only a single Item shall be permitted in this Sequence. Required if Specimen Identifier (0040,0551) is sent with a value. + + + + Identifier of the Slide. +Required if the Specimen is a Slide. + +
+ + + The name of the clinical trial sponsor. See C.7.1.3.1.1. +
The Clinical Trial Sponsor Name (0012,0010) identifies the entity responsible for conducting the clinical trial and for defining the Clinical Trial Protocol ID (0012,0020). +
+
+ + Identifier for the noted protocol. See C.7.1.3.1.2. +
The Clinical Trial Protocol ID (0012,0020) is the number or character sequence used by the Clinical Trial Sponsor to uniquely identify the investigational protocol in which the subject has been enrolled. +
+
+ + The name of the clinical trial protocol. See C.7.1.3.1.3. +
The Clinical Trial Protocol Name (0012,0021) contains the title of the investigational protocol in which the subject has been enrolled. +Note: It is recommended that the phase of the clinical trial be noted in the Clinical Trial Protocol Name, if applicable. +
+
+ + The identifier of the site responsible for submitting clinical trial data. See C.7.1.3.1.4. +
The Clinical Trial Site ID (0012,0030) is the identification number or character string (issued by the entity identified by the Clinical Trial Sponsor Name (0012,0010)) used to identify the site responsible for submitting clinical trial data. +
+
+ + Name of the site responsible for submitting clinical trial data. See C.7.1.3.1.5 +
The Clinical Trial Site Name (0012,0031) is a character string used to identify the site responsible for submitting clinical trial data. +
+
+ + The assigned identifier for the clinical trial subject. See C.7.1.3.1.6. Shall be present if Clinical Trial Subject Reading ID (0012,0042) is absent. May be present otherwise. +
The Clinical Trial Subject ID (0012,0040) identifies the subject within the investigational protocol specified by Clinical Trial Protocol ID (0012,0020). +
+
+ + Identifies the subject for blinded evaluations. Shall be present if Clinical Trial Subject ID (0012,0040) is absent. May be present otherwise. See C.7.1.3.1.7. +
The Clinical Trial Subject Reading ID (0012,0042) identifies the subject in the context of blinded evaluations. + +
+
+
+ + + Unique identifier for the Study. + + + Date the Study started. + + + Time the Study started. + + + Name of the patient's referring physician + + + Identification of the patient's referring physician. Only a single item shall be permitted in this sequence. + + + + User or equipment generated Study identifier. + + + A RIS generated number that identifies the order for the Study. + + + Institution-generated description or classification of the Study (component) performed. + + + Names of the physician(s) who are responsible for overall patient care at time of Study (see Section C.7.3.1 for Performing Physician) + + + Identification of the physician(s) who are responsible for overall patient care at time of Study. One or more items shall be included in this sequence. If more than one Item, the number and order shall correspond to the value of Physician(s) of Record (0008,1048), if present. + + + + Names of the physician(s) reading the Study. + + + Identification of the physician(s) reading the Study. One or more items shall be included in this sequence. If more than one Item, the number and order shall correspond to the value of Name of Physician(s) Reading Study (0008,1060), if present. + + + + A sequence that provides reference to a Study SOP Class/Instance pair. The sequence may have zero or more Items. + + + + A Sequence that conveys the type of procedure performed. One or more Items may be included in this Sequence. + + + + + + Description of the admitting diagnosis (diagnoses) + + + A sequence that conveys the admitting diagnosis (diagnoses). One or more Items may be included in this Sequence. + + + + Age of the Patient. + + + Length or size of the Patient, in meters. + + + Weight of the Patient, in kilograms. + + + Occupation of the Patient. + + + Additional information about the Patient's medical history. + + + Identification number of the visit as assigned by the healthcare provider + + + Name of healthcare provider that issued the Admission ID + + + Identifier of the Service Episode as assigned by the healthcare provider + + + Name of healthcare provider that issued the Service Episode ID + + + Description of the type of service episode. + + + Whether or not a procedure has been performed in an effort to render the patient sterile. +Enumerated value: +ALTERED = Altered/Neutered +UNALTERED = Unaltered/intact +Note: If this Attribute is present but has no value then the status is unknown. +Required if patient is an animal. May be present otherwise. + + + + + An identifier specifying the one or more studies that are grouped together as a clinical time point or submission in a clinical trial. See C.7.2.3.1.1. +
The Clinical Trial Time Point ID (0012,0050) attribute identifies an imaging study within the context of an investigational protocol. This attribute is used to define a set of studies that are grouped together as a clinical time point or data submission in a clinical trial. The Clinical Trial Time Point Description (0012,0051) attribute can be used to give a description of the Clinical Trial Time Point to which the set of studies belongs. +
+
+ + A description of a set of one or more studies that are grouped together to represent a clinical time point or submission in a clinical trial. See C.7.2.3.1.1. +
The Clinical Trial Time Point ID (0012,0050) attribute identifies an imaging study within the context of an investigational protocol. This attribute is used to define a set of studies that are grouped together as a clinical time point or data submission in a clinical trial. The Clinical Trial Time Point Description (0012,0051) attribute can be used to give a description of the Clinical Trial Time Point to which the set of studies belongs. +
+
+
+ + + Type of equipment that originally acquired the data used to create the images in this Series. See C.7.3.1.1.1 for Defined Terms. +
Defined Terms for the Modality (0008,0060) are: + +Retired Defined Terms for the Modality (0008,0060) are: + +Note: 1. The XA modality incorporates the retired modality DS. + 2. The RF modality incorporates the retired modalities CF, DF, VF. + 3. The modality listed in the Modality Data Element (0008,0060) may not match the name of the IOD in which it appears. For example, a SOP instance from XA IOD may list the RF modality when an RF implementation produces an XA object. + 4. The MR modality incorporates the retired modalities MA and MS. + +
+
+ + Unique identifier of the Series. + + + A number that identifies this Series. + + + Laterality of (paired) body part examined. Required if the body part examined is a paired structure and Image Laterality (0020,0062) or Frame Laterality (0020,9072) are not sent. Enumerated Values: +R = right +L = left +Note: Some IODs support Image Laterality (0020,0062) at the Image level or Frame Laterality(0020,9072) at the Frame level in the Frame Anatomy functional group macro, which can provide a more comprehensive mechanism for specifying the laterality of the body part(s) being examined. + + + Date the Series started. + + + Time the Series started. + + + Name of the physician(s) administering the Series. + + + Identification of the physician(s) administering the Series. One or more items shall be included in this sequence. If more than one Item, the number and order shall correspond to the value of Performing Physicians' Name (0008,1050), if present. + + + + User-defined description of the conditions under which the Series was performed. +Note: This attribute conveys series-specific protocol identification and may or may not be identical to the one presented in the Performed Protocol Code Sequence (0040,0260). + + + User provided description of the Series + + + Name(s) of the operator(s) supporting the Series. + + + Identification of the operator(s) supporting the Series. One or more items shall be included in this sequence. If more than one Item, the number and order shall correspond to the value of Operators' Name (0008,1070), if present. + + + + Uniquely identifies the Performed Procedure Step SOP Instance to which the Series is related (e.g. a Modality or General-Purpose Performed Procedure Step SOP Instance). The Sequence shall have zero or one Item. + + + + Identification of Series significantly related to this Series. Zero or more Items may be present. +Notes: 1. For example, for a combined CT and PET acquisition, the CT images and PET images would be in separate series that could cross-reference each other with multiple purpose of reference codes meaning same anatomy, simultaneously acquired and same indication. +2. The related series may have different Frames of Reference and hence require some sort of registration before spatial coordinates can be directly compared. +3. This attribute is not intended for conveying localizer reference information, for which Referenced Image Sequence (0008,1140) should be used. + + + Instance UID of Study to which the related Series belongs + + + Instance UID of Related Series + + + Describes the purpose for which the reference is made. Zero or more Items may be present. +When absent, implies that the reason for the reference is unknown. + + + + Text description of the part of the body examined. See PS 3.16 Annex on Correspondence of Anatomic Region Codes and Body Part Examined for Defined Terms +Note: Some IODs support the Anatomic Region Sequence (0008,2218), which can provide a more comprehensive mechanism for specifying the body part being examined. + + + Patient position descriptor relative to the equipment. Required for CT and MR images; shall not be present if Patient Orientation Code Sequence (0054,0410) is present; may be present otherwise. See C.7.3.1.1.2 for Defined Terms and further explanation. +
Patient Position (0018,5100) specifies the position of the patient relative to the imaging equipment space. This attribute is intended for annotation purposes only. It does not provide an exact mathematical relationship of the patient to the imaging equipment. +When facing the front of the imaging equipment, Head First is defined as the patient’s head being positioned toward the front of the imaging equipment. Feet First is defined as the patient’s feet being positioned toward the front of the imaging equipment. Prone is defined as the patient’s face being positioned in a downward (gravity) direction. Supine is defined as the patient’s face being in an upward direction. Decubitus Right is defined as the patient’s right side being in a downward direction. Decubitus Left is defined as the patient’s left side being in a downward direction. +The Defined Terms are: + +
+
+ + The minimum value of all images in this Series. + + + The maximum value of all images in this Series. + + + Sequence that contains attributes from the Imaging Service Request. +The sequence may have one or more Items. + + + +
+ + + The name of the institution that is responsible for coordinating the medical imaging data for the clinical trial. See C.7.3.2.1.1. +
The Clinical Trial Coordinating Center Name (0012,0060) identifies the institution responsible for coordinating the collection of images and associated data for subjects enrolled in the clinical trial. +
+
+ + An identifier of the series in the context of a clinical trial. See C.7.3.2.1.2. +
The Clinical Trial Series ID (0012,0071) and Clinical Trial Series Description (0012,0072) attributes can be used to identify and describe a Series within the context of a clinical trial without requiring the replacement of the values in the Series Number (0020,0011) and Series Description (0008,103E) attributes in the General Series Module, whose manufacturer or user provided values may be relevant and important to retain. +
+
+ + A description of the series in the context of a clinical trial. See C.7.3.2.1.2. +
The Clinical Trial Series ID (0012,0071) and Clinical Trial Series Description (0012,0072) attributes can be used to identify and describe a Series within the context of a clinical trial without requiring the replacement of the values in the Series Number (0020,0011) and Series Description (0008,103E) attributes in the General Series Module, whose manufacturer or user provided values may be relevant and important to retain. +
+
+
+ + + A number that identifies this Series. +Notes: 1. The value of this attribute should be unique for all series in a study created on the same equipment. +2. Because series can be created on more than one equipment, it can not be guranteed that the value of Series Number (0020,0011) is unique in a study. + + + Uniquely identifies the Performed Procedure Step SOP Instance to which the Series is related (e.g. a Modality or General-Purpose Performed Procedure Step SOP Instance). Only a single Item is permitted in this sequence. +Required if the Modality Performed Procedure Step SOP Class or General Purpose Performed Procedure Step SOP Class is supported. + + + + + + Uniquely identifies the frame of reference for a Series. See C.7.4.1.1.1 for further explanation. +
The Frame of Reference UID (0020,0052) shall be used to uniquely identify a frame of reference for a series. Each series shall have a single Frame of Reference UID. However, multiple Series within a Study may share a Frame of Reference UID. All images in a Series that share the same Frame of Reference UID shall be spatially related to each other. +Notes: 1. Previous versions of this Standard defined a Data Element "Location", which has been retired. Frame of Reference UID provides a completely unambiguous identification of the image location reference used to indicate position. + 2. A common Frame of Reference UID may be used to spatially relate localizer images with a set of transverse images. However, in some cases (eg. multiple localizer images being related to a single set of transverse images) a common Frame of Reference UID may not be sufficient. The Referenced Image Sequence (0008,1140) provides an unambiguous method for relating localizer images. + +
+
+ + Part of the patient's anatomy used as a reference, such as the iliac crest, orbital-medial, sternal notch, symphysis pubis, xiphoid, lower coastal margin, external auditory meatus. See C.7.4.1.1.2 for further explanation. +
The Position Reference Indicator (0020,1040) specifies the part of the patient’s anatomy that was used as an anatomical reference point associated with a specific Frame of Reference UID. The Position Reference Indicator may or may not coincide with the origin of the fixed frame of reference related to the Frame of Reference UID. +The Position Reference Indicator shall be used only for annotation purposes and is not intended to be used as a mathematical spatial reference. +Note: The Position Reference Indicator may be sent zero length when it has no meaning, for example, when the Frame of Reference Module is required to relate mammographic images of the breast acquired without releasing breast compression, but where there is no meaningful anatomical reference point as such. + +
+
+
+ + + UID of common synchronization environment. See C.7.4.2.1.1. +
A set of equipment may share a common acquisition synchronization environment, which is identified by a Synchronization Frame of Reference UID. All SOP Instances that share the same Synchronization Frame of Reference UID shall be temporally related to each other. If a Synchronization Frame of Reference UID is present, all SOP Instances in the Series must share the same Frame of Reference. +The UTC Synchronization UID, 1.2.840.10008.15.1.1, may be used when the equipment is synchronized to the international standard UTC. In this case the quality of synchronization may be determined by means of the Time Distribution Protocol (0018,1802) and NTP Source Address (0018,1803). +Notes: 1. The Synchronization Frame of Reference UID defines an equipment synchronization environment, and does not need to be changed for each unrelated acquisition. SOP Instances may therefore share a Synchronization Frame of Reference UID, but be clinically unrelated (e.g., apply to different patients). + 2. When a synchronization environment is recalibrated, a new UID must be issued. + 3. The method of distributing the Synchronization Frame of Reference UID to multiple devices is not specified. + +
+
+ + Data acquisition synchronization with external equipment +Enumerated Values: +SOURCE - this equipment provides synchronization channel or trigger to other equipment +EXTERNAL - this equipment receives synchronization channel or trigger from other equipment +PASSTHRU - this equipment receives synchronization channel or trigger and forwards it +NO TRIGGER - data acquisition not synchronized by common channel or trigger + + + Specifies equipment ID of trigger source and/or type of trigger + + + Identifier of waveform channel that records the synchronization channel or trigger, see C.7.4.2.1.3. +Required if synchronization channel or trigger is encoded in a waveform in this SOP Instance + + + Acquisition DateTime (0008,002A) synchronized with external time reference. +Enumerated Values: Y, N +See C.7.4.2.1.4 +
The Acquisition Time Synchronized (0018,1800) attribute specifies whether the Acquisition DateTime (0008,002A) attribute of the Waveform Identification Module or the General Image Module represents an accurate synchronized timestamp for the acquisition of the waveform and/or image data. For triggered multi-frame images, the Acquisition DateTime applies to the trigger for the first image frame (see attribute Image Trigger Delay (0018.1067) in the Cine Module). +Note: The degree of precision of the Acquisition DateTime and its accuracy relative to the external clock are not specified, but need to be appropriate for the clinical application. + +For IODs that include the SR Document Content Module, the Acquisition Time Synchronized (0018,1800) attribute specifies whether the Observation DateTime (0040,A032) attribute of Items in the Content Sequence (0040,A730) of the SR Document Content Module represents an accurate synchronized timestamp for the Item. +
+
+ + ID of equipment or system providing time reference + + + Method of time distribution used to synchronize this equipment. +Defined Terms: +NTP - Network Time Protocol +IRIG - InterRange Instrumentation Group +GPS - Global Positioning System +SNTP - Simple Network Time Protocol + + + IP Address of NTP time source. IPv4 addresses shall be in dotted decimal (e.g. 192.168.1.1). The IPv6 addresses shall be in colon separated hexadecimal (e.g. 12:34:56:78:9a:bc:de:f0). +Note: Identity of this value in two instances acquired contemporaneously implies a common time base. The NTP Source Address may not persist over time. + +
+ + + Manufacturer of the equipment that produced the composite instances. + + + Institution where the equipment that produced the composite instances is located. + + + Mailing address of the institution where the equipment that produced the composite instances is located. + + + User defined name identifying the machine that produced the composite instances. + + + Department in the institution where the equipment that produced the composite instances is located. + + + Manufacturer's model name of the equipment that produced the composite instances. + + + Manufacturer's serial number of the equipment that produced the composite instances. +Note: This identifier corresponds to the device that actually created the images, such as a CR plate reader or a CT console, and may not be sufficient to identify all of the equipment in the imaging chain, such as the generator or gantry or plate. + + + Manufacturer's designation of software version of the equipment that produced the composite instances. + + + Identifier of the gantry or positioner. + + + The inherent limiting resolution in mm of the acquisition equipment for high contrast objects for the data gathering and reconstruction technique chosen. If variable across the images of the series, the value at the image center. + + + Date when the image acquisition device calibration was last changed in any way. Multiple entries may be used for additional calibrations at other times. See C.7.5.1.1.1 for further explanation. +
Date of Last Calibration (0018,1200) and Time of Last Calibration (0018,1201) are used to convey the date and time of calibration. The Attribute Date of Last Calibration (0018,1200) may be supported alone, however, Time of Last Calibration (0018,1201) Attribute has no meaning unless Attribute Date of Last Calibration (0018,1200) is also supported. The order for each Attribute shall be from the oldest date/time to the most recent date/time. When the Attributes are both supported they shall be provided as pairs. +
+
+ + Time when the image acquisition device calibration was last changed in any way. Multiple entries may be used. See C.7.5.1.1.1 for further explanation. +
Date of Last Calibration (0018,1200) and Time of Last Calibration (0018,1201) are used to convey the date and time of calibration. The Attribute Date of Last Calibration (0018,1200) may be supported alone, however, Time of Last Calibration (0018,1201) Attribute has no meaning unless Attribute Date of Last Calibration (0018,1200) is also supported. The order for each Attribute shall be from the oldest date/time to the most recent date/time. When the Attributes are both supported they shall be provided as pairs. +
+
+ + Single pixel value or one limit (inclusive) of a range of pixel values used in animage to pad to rectangular format or to signal background that may be suppressed. See C.7.5.1.1.2 for further explanation. +Required if Pixel Padding Range Limit (0028,0121) is present. May be present otherwise. +Note: The Value Representation of this Attribute is determined by the value of Pixel Representation (0028,0103). +
Pixel Padding Value (0028,0120) is used to pad grayscale images (those with a Photometric Interpretation of MONOCHROME1 or MONOCHROME2)to rectangular format. The native format of some images is not rectangular. It is common for devices with this format to pad the images to the rectangular format required by the DICOM Standard with a specific pixel value that is not contained in the native image. Further, when resampling, such as after spatial registration, padding may need to be used to fill previously non-existent pixels. +Pixel Padding Value (0028,0120) and Pixel Padding Range Limit (0028,0121) are also used to identify pixels to be excluded from the normal grayscale rendering pipeline for other reasons, such as suppression of background air. Pixel Padding Range Limit (0028,0121) is defined in the Image Pixel Module. +Notes: 1. The “native image†is that which is being padded to the required rectangular format, e.g., the area within the circular reconstruction perimeter of a CT image, or the subset of the rectangular area that contains useful image information. + 2. The pixel padding value is explicitly described in order to prevent display applications from taking it into account when determining the dynamic range of an image, since the Pixel Padding Value will be outside the range between the minimum and maximum values of the pixels in the native image + 3. No pixels in the native image will have a value equal to Pixel Padding Value. + +Pixel Padding Value (0028,0120) specifies either a single value of this padding value, or when combined with Pixel Padding Range Limit (0028,0121), a range of values (inclusive) that are padding. +The values of Pixel Padding Value (0028,0120) and Pixel Padding Range Limit (0028,0121) shall be valid values within the constraints defined by Bits Allocated (0028,0100), Bits Stored (0028,0101), and High Bit (0028,0102). +Pixel Padding Value (0028,0120) and Pixel Padding Range Limit (0028,0121) shall not be present when padding is performed but the pixel value used for padding does occur in the native image. +If Photometric Interpretation (0028,0004) is MONOCHROME2, Pixel Padding Value (0028,0120) shall be less than (closer to or equal to the minimum possible pixel value) or equal to Pixel Padding Range Limit (0028,0121). If Photometric Interpretation (0028,0004) is MONOCHROME1, Pixel Padding Value (0028,0120) shall be greater than (closer to or equal to the maximum possible pixel value) or equal to Pixel Padding Range Limit (0028,0121). +Notes: 1. When the relationship between pixel value and X-Ray Intensity is unknown, it is recommended that the following values be used to pad with black when the image is unsigned: + 0 if Photometric Interpretation (0028,0004) is MONOCHROME2. + 2BitsStored - 1 if Photometric Interpretation (0028,0004) is MONOCHROME1. + and when the image is signed: + -2BitsStored-1 if Photometric Interpretation (0028,0004) is MONOCHROME2. + 2BitsStored-1 - 1 if Photometric Interpretation (0028,0004) is MONOCHROME1. + 2. For projection radiography, when the relationship between pixel value and X-Ray Intensity is known (for example as defined by Pixel Intensity Relationship (0028,1040) and Pixel Intensity relationship Sign (0028,1041)), it is recommended that a pixel value equivalent to, or rendered similarly to, air (least X-Ray absorbance) be used for padding. However, if such a value may occur in the native image, the Pixel Padding Value (0028,0120) Attribute itself should not be sent. + E.g., for an XRF image obtained with an image intensifier, if air is black then a padded perimeter, if any, should also appear black. Typically though, if unpadded, this area would be collimated with a circular collimator, in which case the pixels would appear natively as white (greatest X-Ray absorbance) and a circular shutter would be necessary to neutralize them as black. Whether collimated areas are detected and treated as padded, or neutralized with shutters is at the discretion of the application. See also the Display Shutter Module C.7.6.11. + 3. The conditional requirement for the Pixel Padding Value Range Limit (0028,0121) in the Image Pixel Module means that it shall not be present unless Pixel Padding Value (0028,0120) is also present. + 4. The range of values to be suppressed between Pixel Padding Value (0028,0120) and Pixel Padding Value Range Limit (0028,0121) is specified as being inclusive, that is the values themselves as well as all values between are suppressed. + 5. When Pixel Padding Value Range Limit (0028,0121) is present, but not supported by a rendering application, the constraint that Pixel Padding Value (0028,0120) is closest to the “blackest†value, which is typically the most frequently occurring background pixel, will most often result in an acceptable display, permitting “backward compatibility†in the majority of cases. + +When modifying equipment changes the pixel padding value in the image, it shall change the values of Pixel Padding Value (0028,0120) and Pixel Padding Range Limit (0028,0121), if present. If modifying equipment changes the pixel padding values in the image to values present in the native image, the attribute Pixel Padding Value (0028,0120) and Pixel Padding Range Limit (0028,0121) shall be removed. +Notes: 1. For example, if a CT image containing signed values from -1024 to 3191 and a Pixel Padding Value of -2000 and a Rescale Intercept of 0 is converted to an unsigned image with a Rescale Intercept of -1024 by adding 1024 to all pixels and clipping all more negative pixels to 0, then the padding pixels will be indistinguishable from some of the modified native image pixels, and hence Pixel Padding Value (0028,0120) needs to be removed. + 2. If the modification involves lossy compression, which may result in changes to the pixel values, then the application of Pixel Padding Value and Pixel Padding Range Limit may result in a different appearance, and hence these attributes may need different values also. + +
+
+
+ + + Manufacturer of the equipment that produced the composite instances. + + + Manufacturer's model name of the equipment that produced the composite instances. + + + Manufacturer's serial number of the equipment that produced the composite instances. + + + Manufacturer's designation of software version of the equipment that produced the composite instances. + + + + + A number that identifies this image. +Note: This Attribute was named Image Number in earlier versions of this Standard. + + + Patient direction of the rows and columns of the image. Required if image does not require Image Orientation (Patient) (0020,0037) and Image Position (Patient) (0020,0032). See C.7.6.1.1.1 for further explanation. +Note: IOD's may have attributes other than Patient Orientation, Image Orientation, or Image Position (Patient) to describe orientation in which case this attribute will be zero length. +
The Patient Orientation (0020,0020) relative to the image plane shall be specified by two values that designate the anatomical direction of the positive row axis (left to right) and the positive column axis (top to bottom). The first entry is the direction of the rows, given by the direction of the last pixel in the first row from the first pixel in that row. The second entry is the direction of the columns, given by the direction of the last pixel in the first column from the first pixel in that column. +Anatomical direction shall be designated by the capital letters: A (anterior), P (posterior), R (right), L (left), H (head), F (foot). Each value of the orientation attribute shall contain at least one of these characters. If refinements in the orientation descriptions are to be specified, then they shall be designated by one or two additional letters in each value. Within each value, the letters shall be ordered with the principal orientation designated in the first character. +
+
+ + The date the image pixel data creation started. Required if image is part of a series in which the images are temporally related. +Note: This Attribute was formerly known as Image Date. + + + The time the image pixel data creation started. Required if image is part of a series in which the images are temporally related. + + + Image identification characteristics. See C.7.6.1.1.2 for Defined Terms and further explanation. +
The Image Type (0008,0008) Attribute identifies important image identification characteristics. These characteristics are: +a. Pixel Data Characteristics +1. is the image an ORIGINAL Image; an image whose pixel values are based on original or source data +2. is the image a DERIVED Image; an image whose pixel values have been derived in some manner from the pixel value of one or more other images +b. Patient Examination Characteristics +1. is the image a PRIMARY Image; an image created as a direct result of the Patient examination +2. is the image a SECONDARY Image; an image created after the initial Patient examination +c. Modality Specific Characteristics +d. Implementation specific identifiers; other implementation specific identifiers shall be documented in an implementation's conformance statement. +The Image Type attribute is multi-valued and shall be provided in the following manner: +a. Value 1 shall identify the Pixel Data Characteristics; Enumerated Values for the Pixel Data Characteristics are: +ORIGINAL identifies an Original Image +DERIVED identifies a Derived Image +b. Value 2 shall identify the Patient Examination Characteristics; Enumerated Values for the Patient Examination Characteristics are: +PRIMARY identifies a Primary Image +SECONDARY identifies a Secondary Image +c. Value 3 shall identify any Image IOD specific specialization (optional) +d. Other Values which are implementation specific (optional) +Any of the optional values (value 3 and beyond) may be sent either with a value or zero-length, independent of other optional values, unless otherwise specified by a specialization of this attribute in an IOD. +If the pixel data of the derived Image is different from the pixel data of the source images and this difference is expected to affect professional interpretation of the image, the Derived Image shall have a UID different than all the source images. +
+
+ + A number identifying the single continuous gathering of data over a period of time that resulted in this image. + + + The date the acquisition of data that resulted in this image started + + + The time the acquisition of data that resulted in this image started + + + The date and time that the acquisition of data that resulted in this image started. +Note: The synchronization of this time with an external clock is specified in the Synchronization Module in Acquisition Time Synchronized (0018,1800). + + + A sequence that references other images significantly related to this image (e.g. post-localizer CT image or Mammographic biopsy or partial view images). One or more Items may be included in this sequence. + + + + Describes the purpose for which the reference is made. Only a single Item shall be permitted in this sequence. + + + + A text description of how this image was derived. See C.7.6.1.1.3 for further explanation. +
If an Image is identified to be a derived image (see C.7.6.1.1.2 Image Type), Derivation Description (0008,2111) and Derivation Code Sequence (0008,9215) describe the way in which the image was derived. They may be used whether or not the Source Image Sequence (0008,2112) is provided. They may also be used in cases when the Derived Image pixel data is not significantly changed from one of the source images and the SOP Instance UID of the Derived Image is the same as the one used for the source image. +Notes: 1. Examples of Derived Images that would normally be expected to affect professional interpretation and would thus have a new UID include: + a. images resulting from image processing of another image (e.g. unsharp masking), + b. a multiplanar reformatted CT image, + c. a DSA image derived by subtracting pixel values of one image from another. +d. an image that has been decompressed after having been compressed with a lossy compression algorithm. To ensure that the user has the necessary information about the lossy compression, the approximate compression ratio may be included in Derivation Description (0008,2111). + An example of a Derived Image that would normally not be expected to affect professional interpretation and thus would not require a new UID is an image that has been padded with additional rows and columns for more display purposes. + 2. An image may be lossy compressed, e.g., for long term archive purposes, and its SOP Instance UID changed. PS3.4 provides a mechanism by which a query for the original image Instance may return a reference to the UID of the lossy compressed version of the image using the Alternate Representation Sequence (0008,3001). This allows an application processing a SOP Instance that references the original image UID, e.g., a Structured Report, to obtain a reference to an accessible version of the image even if the original SOP Instance is no longer available. + +
+
+ + A coded description of how this image was derived. See C.7.6.1.1.3 for further explanation. One or more Items may be included in this Sequence. More than one Item indicates that successive derivation steps have been applied. +
If an Image is identified to be a derived image (see C.7.6.1.1.2 Image Type), Derivation Description (0008,2111) and Derivation Code Sequence (0008,9215) describe the way in which the image was derived. They may be used whether or not the Source Image Sequence (0008,2112) is provided. They may also be used in cases when the Derived Image pixel data is not significantly changed from one of the source images and the SOP Instance UID of the Derived Image is the same as the one used for the source image. +Notes: 1. Examples of Derived Images that would normally be expected to affect professional interpretation and would thus have a new UID include: + a. images resulting from image processing of another image (e.g. unsharp masking), + b. a multiplanar reformatted CT image, + c. a DSA image derived by subtracting pixel values of one image from another. +d. an image that has been decompressed after having been compressed with a lossy compression algorithm. To ensure that the user has the necessary information about the lossy compression, the approximate compression ratio may be included in Derivation Description (0008,2111). + An example of a Derived Image that would normally not be expected to affect professional interpretation and thus would not require a new UID is an image that has been padded with additional rows and columns for more display purposes. + 2. An image may be lossy compressed, e.g., for long term archive purposes, and its SOP Instance UID changed. PS3.4 provides a mechanism by which a query for the original image Instance may return a reference to the UID of the lossy compressed version of the image using the Alternate Representation Sequence (0008,3001). This allows an application processing a SOP Instance that references the original image UID, e.g., a Structured Report, to obtain a reference to an accessible version of the image even if the original SOP Instance is no longer available. + +
+
+ + + A Sequence that identifies the set of Image SOP Class/Instance pairs of the Images that were used to derive this Image. Zero or more Items may be included in this Sequence. +See C.7.6.1.1.4 for further explanation. +
If an Image is identified to be a Derived image (see C.7.6.1.1.2 Image Type), Source Image Sequence (0008,2112) is an optional list of Referenced SOP Class UID (0008,1150)/ Referenced SOP Instance UID (0008,1150) pairs that identify the source images used to create the Derived image. It may be used whether or not there is a description of the way the image was derived in Derivation Description (0008,2111) or Derivation Code Sequence (0008,9215). +Note: Multiple Items may be present within Source Image Sequence (0008,2112), in which case either: + a) those images were combined to make the derived image (e.g. multiple source images to make an MPR or MIP), or + b) each of the items represents a step in the successive derivation of an image (e.g. when an image has had successive lossy compression steps applied to it), + c) some combination of the above. + The Purpose of Reference Code Sequence (0040,A170) and the Attributes within the referenced images themselves may be used to determine the history of the derivation, which is not otherwise explicitly specified. + +
+
+ + + Describes the purpose for which the reference is made, that is what role the source image or frame(s) played in the derivation of this image. Only a single Item shall be permitted in this sequence. + + + + The extent to which the spatial locations of all pixels are preserved during the processing of the source image that resulted in the current image +Enumerated Values: +YES +NO +REORIENTED_ONLY - A projection radiograph that has been flipped, and/or rotated by a multiple of 90 degrees + +Notes: 1. This applies not only to images with a known relationship to a 3D space, but also to projection images. For example, a projection radiograph such as a mammogram that is processed by a point image processing operation such as contrast enhancement, or a smoothing or edge enhancing convolution, would have a value of YES for this attribute. A projection radiograph that had been magnified or warped geometrically would have a value of NO for this attribute. A projection radiograph that has been flipped, and/or rotated by a multiple of 90 degrees, such that transformation of pixel locations is possible by comparison of the values of Patient Orientation (0020,0020) would have a value of REORIENTED_ONLY. This attribute is typically of importance in relating images with Presentation Intent Type (0008,0068) values of FOR PROCESSING and FOR PRESENTATION. +2. When the value of this attribute is NO, it is not possible to locate on the current image any pixel coordinates that are referenced relative to the source image, such as for example, might be required for rendering CAD findings derived from a referenced FOR PROCESSING image on the current FOR PRESENTATION image. + + + The Patient Orientation values of the source image. +Required if the value of Spatial Locations Preserved (0028,135A) is REORIENTED_ONLY. + + + A sequence which provides reference to a set of non-image SOP Class/Instance pairs significantly related to this Image, including waveforms that may or may not be temporally synchronized with this image . +One or more Items may be included in this sequence. + + + + Code describing the purpose of the reference to the Instance(s). Only a single Item shall be permitted in this sequence. + + + + Number of images that resulted from this acquisition of data + + + User-defined comments about the image + + + Indicates whether or not this image is a quality control or phantom image. +Enumerated Values: +YES +NO +If this Attribute is absent, then the image may or may not be a quality control or phantom image. The phantom device in the image can be described using the Device Module. See C.7.6.12 +
Table C.7-18 describes the Attributes of devices or calibration objects (e.g., catheters, markers, baskets) that are associated with a study and/or image. +Table C.7-18 +DEVICE MODULE ATTRIBUTES + +
+
+ + Indicates whether or not image contains sufficient burned in annotation to identify the patient and date the image was acquired. +Enumerated Values: +YES +NO +If this Attribute is absent, then the image may or may not contain burned in annotation. + + + Specifies whether an Image has undergone lossy compression. Enumerated Values: +00 = Image has NOT been subjected to lossy compression. +01 = Image has been subjected to lossy compression. +See C.7.6.1.1.5 +
The Attribute Lossy Image Compression (0028,2110) conveys that the Image has undergone lossy compression. It provides a means to record that the Image has been compressed (at a point in its lifetime) with a lossy algorithm and changes have been introduced into the pixel data. Once the value has been set to “01â€, it shall not be reset. +Note: If an image is compressed with a lossy algorithm, the attribute Lossy Image Compression (0028,2110) is set to “01â€. Subsequently, if the image is decompressed and transferred in uncompressed format, this attribute value remains “01â€. + +The value of the Lossy Image Compression (0028,2110) Attribute in SOP Instances containing multiple frames in which one or more of the frames have undergone lossy compression shall be “01â€. +Note: It is recommended that the applicable frames be noted in the Attribute Derivation Description (0008,2111). + +If an image is originally obtained as a lossy compressed image from the sensor, then Lossy Image Compression (0028,2110) is set to “01†and Value 1 of the Attribute Image Type (0008,0008) shall be set to ORIGINAL. +If an image is a compressed version of another image, Lossy Image Compression (0028,2110) is set to “01â€, Value 1 of the Attribute Image Type (0008,0008) shall be set to DERIVED, and if the predecessor was a DICOM image, then the Image shall receive a new SOP Instance UID. +Note: 1. It is recommended that the approximate compression ratio be provided in the Attribute Derivation Description (0008,2111). Furthermore, it is recommended that Derivation Description (0008,2111) be used to indicate when pixel data changes might affect professional interpretation. (see C.7.6.1.1.3). + 2. The attribute Lossy Image Compression (0028,2110) is defined as Type 3 for backward compatibility with existing IODs. It is expected to be required (i.e., defined as Type 1C) for new Image IODs and for existing IODs that undergo a major revision (e.g. a new IOD is specified). +The Defined Terms for Lossy Image Compression Method (0028,2114) are: +ISO_10918_1 = JPEG Lossy Compression +ISO_14495_1 = JPEG-LS Near-lossless Compression +ISO_15444_1 = JPEG 2000 Irreversible Compression +ISO_13818_2 = MPEG2 Compression + +
+
+ + Describes the approximate lossy compression ratio(s) that have been applied to this image. +See C.7.6.1.1.5 for further explanation. +May be multivalued if successive lossy compression steps have been applied. +Notes: 1. For example, a compression ratio of 30:1 would be described in this Attribute with a single value of 30. +2. For historical reasons, the lossy compression ratio may also be described in Derivation Description (0008,2111). +
The Attribute Lossy Image Compression (0028,2110) conveys that the Image has undergone lossy compression. It provides a means to record that the Image has been compressed (at a point in its lifetime) with a lossy algorithm and changes have been introduced into the pixel data. Once the value has been set to “01â€, it shall not be reset. +Note: If an image is compressed with a lossy algorithm, the attribute Lossy Image Compression (0028,2110) is set to “01â€. Subsequently, if the image is decompressed and transferred in uncompressed format, this attribute value remains “01â€. + +The value of the Lossy Image Compression (0028,2110) Attribute in SOP Instances containing multiple frames in which one or more of the frames have undergone lossy compression shall be “01â€. +Note: It is recommended that the applicable frames be noted in the Attribute Derivation Description (0008,2111). + +If an image is originally obtained as a lossy compressed image from the sensor, then Lossy Image Compression (0028,2110) is set to “01†and Value 1 of the Attribute Image Type (0008,0008) shall be set to ORIGINAL. +If an image is a compressed version of another image, Lossy Image Compression (0028,2110) is set to “01â€, Value 1 of the Attribute Image Type (0008,0008) shall be set to DERIVED, and if the predecessor was a DICOM image, then the Image shall receive a new SOP Instance UID. +Note: 1. It is recommended that the approximate compression ratio be provided in the Attribute Derivation Description (0008,2111). Furthermore, it is recommended that Derivation Description (0008,2111) be used to indicate when pixel data changes might affect professional interpretation. (see C.7.6.1.1.3). + 2. The attribute Lossy Image Compression (0028,2110) is defined as Type 3 for backward compatibility with existing IODs. It is expected to be required (i.e., defined as Type 1C) for new Image IODs and for existing IODs that undergo a major revision (e.g. a new IOD is specified). +The Defined Terms for Lossy Image Compression Method (0028,2114) are: +ISO_10918_1 = JPEG Lossy Compression +ISO_14495_1 = JPEG-LS Near-lossless Compression +ISO_15444_1 = JPEG 2000 Irreversible Compression +ISO_13818_2 = MPEG2 Compression + +
+
+ + A label for the lossy compression method(s) that have been applied to this image. +See C.7.6.1.1.5 for further explanation. +May be multivalued if successive lossy compression steps have been applied; the value order shall correspond to the values of Lossy Image Compression Ratio (0028,2112). +Note: For historical reasons, the lossy compression method may also be described in Derivation Description (0008,2111). +
The Attribute Lossy Image Compression (0028,2110) conveys that the Image has undergone lossy compression. It provides a means to record that the Image has been compressed (at a point in its lifetime) with a lossy algorithm and changes have been introduced into the pixel data. Once the value has been set to “01â€, it shall not be reset. +Note: If an image is compressed with a lossy algorithm, the attribute Lossy Image Compression (0028,2110) is set to “01â€. Subsequently, if the image is decompressed and transferred in uncompressed format, this attribute value remains “01â€. + +The value of the Lossy Image Compression (0028,2110) Attribute in SOP Instances containing multiple frames in which one or more of the frames have undergone lossy compression shall be “01â€. +Note: It is recommended that the applicable frames be noted in the Attribute Derivation Description (0008,2111). + +If an image is originally obtained as a lossy compressed image from the sensor, then Lossy Image Compression (0028,2110) is set to “01†and Value 1 of the Attribute Image Type (0008,0008) shall be set to ORIGINAL. +If an image is a compressed version of another image, Lossy Image Compression (0028,2110) is set to “01â€, Value 1 of the Attribute Image Type (0008,0008) shall be set to DERIVED, and if the predecessor was a DICOM image, then the Image shall receive a new SOP Instance UID. +Note: 1. It is recommended that the approximate compression ratio be provided in the Attribute Derivation Description (0008,2111). Furthermore, it is recommended that Derivation Description (0008,2111) be used to indicate when pixel data changes might affect professional interpretation. (see C.7.6.1.1.3). + 2. The attribute Lossy Image Compression (0028,2110) is defined as Type 3 for backward compatibility with existing IODs. It is expected to be required (i.e., defined as Type 1C) for new Image IODs and for existing IODs that undergo a major revision (e.g. a new IOD is specified). +The Defined Terms for Lossy Image Compression Method (0028,2114) are: +ISO_10918_1 = JPEG Lossy Compression +ISO_14495_1 = JPEG-LS Near-lossless Compression +ISO_15444_1 = JPEG 2000 Irreversible Compression +ISO_13818_2 = MPEG2 Compression + +
+
+ + This icon image is representative of the Image. Only a single Item shall be permitted in this Sequence. + + + + When present, specifies an identity transformation for the Presentation LUT such that the output of all grayscale transformations, if any, are defined to be in P-Values. +Enumerated Values are: +IDENTITY - output is in P-Values - shall be used if Photometric Interpretation (0028,0004) is MONOCHROME2 or any color photometric interpretation. +INVERSE - output after inversion is in P-Values - shall be used if Photometric Interpretation (0028,0004) is MONOCHROME1. +When this attribute is used with a color photometric interpretation then the luminance component is in P-Values. + + + Unique identification of the irradiation event(s) associated with the acquisition of this image. See C.7.6.1.1.7. +
An irradiation event is the occurrence of radiation being applied to a patient in single continuous time-frame between the start (release) and the stop (cease) of the irradiation. Any on-off switching of the irradiation source during the event shall not be treated as separate events, rather the event includes the time between start and stop of irradiation as triggered by the user. E.g., a pulsed fluoro X-Ray acquisition shall be treated as a single irradiation event. +
+
+
+ + + Physical distance in the patient between the center of each pixel, specified by a numeric pair - adjacent row spacing (delimiter) adjacent column spacing in mm. See 10.7.1.3 for further explanation. + + + The direction cosines of the first row and the first column with respect to the patient. See C.7.6.2.1.1 for further explanation. +
The Image Position (0020,0032) specifies the x, y, and z coordinates of the upper left hand corner of the image; it is the center of the first voxel transmitted. Image Orientation (0020,0037) specifies the direction cosines of the first row and the first column with respect to the patient. These Attributes shall be provide as a pair. Row value for the x, y, and z axes respectively followed by the Column value for the x, y, and z axes respectively. +The direction of the axes is defined fully by the patient’s orientation. The x-axis is increasing to the left hand side of the patient. The y-axis is increasing to the posterior side of the patient. The z-axis is increasing toward the head of the patient. +The patient based coordinate system is a right handed system, i.e. the vector cross product of a unit vector along the positive x-axis and a unit vector along the positive y-axis is equal to a unit vector along the positive z-axis. +Note If a patient lies parallel to the ground, face-up on the table, with his feet-to-head direction same as the front-to-back direction of the imaging equipment, the direction of the axes of this patient based coordinate system and the equipment based coordinate system in previous versions of this Standard will coincide. + +The Image Plane Attributes, in conjunction with the Pixel Spacing Attribute, describe the position and orientation of the image slices relative to the patient-based coordinate system. In each image frame the Image Position (Patient) (0020,0032) specifies the origin of the image with respect to the patient-based coordinate system. RCS and the Image Orientation (Patient) (0020,0037) attribute values specify the orientation of the image frame rows and columns. The mapping of pixel location to the RCS is calculated as follows: + + size 12{ left [ matrix { +P rSub { size 8{x} } {} ## +P rSub { size 8{y} } {} ## +P rSub { size 8{z} } {} ## +1 +} right ]= left [ matrix { +X rSub { size 8{x} } Δi {} # Y rSub { size 8{x} } Δj {} # 0 {} # S rSub { size 8{x} } {} ## +X rSub { size 8{y} } Δi {} # Y rSub { size 8{y} } Δj {} # 0 {} # S rSub { size 8{y} } {} ## +X rSub { size 8{z} } Δi {} # Y rSub { size 8{z} } Δj {} # 0 {} # S rSub { size 8{z} } {} ## +0 {} # 0 {} # 0 {} # 1{} +} right ] left [ matrix { +i {} ## +j {} ## +0 {} ## +1 +} right ]} {} + + = M +Where: +Pxyz The coordinates of the voxel (i,j) in the frame’s image plane in units of mm. +Sxyz The three values of the Image Position (Patient) (0020,0032) attributes. It is the location in mm from the origin of the RCS. +Xxyz The values from the row (X) direction cosine of the Image Orientation (Patient) (0020,0037) attribute. +Yxyz The values from the column (Y) direction cosine of the Image Orientation (Patient) (0020,0037) attribute. +i Column index to the image plane. The first column is index zero. +ï„i Column pixel resolution of the Pixel Spacing (0028,0030) attribute in units of mm. +j Row index to the image plane. The first row index is zero. +ï„j Row pixel resolution of the Pixel Spacing (0028,0030) attribute in units of mm. + +Additional constraints apply: +1) The row and column direction cosine vectors shall be orthogonal, i.e. their dot product shall be zero. +2) The row and column direction cosine vectors shall be normal, i.e. the dot product of each direction cosine vector with itself shall be unity. + +
+
+ + The x, y, and z coordinates of the upper left hand corner (center of the first voxel transmitted) of the image, in mm. See C.7.6.2.1.1 for further explanation. +
The Image Position (0020,0032) specifies the x, y, and z coordinates of the upper left hand corner of the image; it is the center of the first voxel transmitted. Image Orientation (0020,0037) specifies the direction cosines of the first row and the first column with respect to the patient. These Attributes shall be provide as a pair. Row value for the x, y, and z axes respectively followed by the Column value for the x, y, and z axes respectively. +The direction of the axes is defined fully by the patient’s orientation. The x-axis is increasing to the left hand side of the patient. The y-axis is increasing to the posterior side of the patient. The z-axis is increasing toward the head of the patient. +The patient based coordinate system is a right handed system, i.e. the vector cross product of a unit vector along the positive x-axis and a unit vector along the positive y-axis is equal to a unit vector along the positive z-axis. +Note If a patient lies parallel to the ground, face-up on the table, with his feet-to-head direction same as the front-to-back direction of the imaging equipment, the direction of the axes of this patient based coordinate system and the equipment based coordinate system in previous versions of this Standard will coincide. + +The Image Plane Attributes, in conjunction with the Pixel Spacing Attribute, describe the position and orientation of the image slices relative to the patient-based coordinate system. In each image frame the Image Position (Patient) (0020,0032) specifies the origin of the image with respect to the patient-based coordinate system. RCS and the Image Orientation (Patient) (0020,0037) attribute values specify the orientation of the image frame rows and columns. The mapping of pixel location to the RCS is calculated as follows: + + size 12{ left [ matrix { +P rSub { size 8{x} } {} ## +P rSub { size 8{y} } {} ## +P rSub { size 8{z} } {} ## +1 +} right ]= left [ matrix { +X rSub { size 8{x} } Δi {} # Y rSub { size 8{x} } Δj {} # 0 {} # S rSub { size 8{x} } {} ## +X rSub { size 8{y} } Δi {} # Y rSub { size 8{y} } Δj {} # 0 {} # S rSub { size 8{y} } {} ## +X rSub { size 8{z} } Δi {} # Y rSub { size 8{z} } Δj {} # 0 {} # S rSub { size 8{z} } {} ## +0 {} # 0 {} # 0 {} # 1{} +} right ] left [ matrix { +i {} ## +j {} ## +0 {} ## +1 +} right ]} {} + + = M +Where: +Pxyz The coordinates of the voxel (i,j) in the frame’s image plane in units of mm. +Sxyz The three values of the Image Position (Patient) (0020,0032) attributes. It is the location in mm from the origin of the RCS. +Xxyz The values from the row (X) direction cosine of the Image Orientation (Patient) (0020,0037) attribute. +Yxyz The values from the column (Y) direction cosine of the Image Orientation (Patient) (0020,0037) attribute. +i Column index to the image plane. The first column is index zero. +ï„i Column pixel resolution of the Pixel Spacing (0028,0030) attribute in units of mm. +j Row index to the image plane. The first row index is zero. +ï„j Row pixel resolution of the Pixel Spacing (0028,0030) attribute in units of mm. + +Additional constraints apply: +1) The row and column direction cosine vectors shall be orthogonal, i.e. their dot product shall be zero. +2) The row and column direction cosine vectors shall be normal, i.e. the dot product of each direction cosine vector with itself shall be unity. + +
+
+ + Nominal slice thickness, in mm. + + + Relative position of the image plane expressed in mm. C.7.6.2.1.2 for further explanation. + +
+ + + + A URL of a provider service that supplies the pixel data of the Image. +Required if the image is to be transferred in one of the following presentation contexts identified by Transfer Syntax UID: +1.2.840.10008.1.2.4.94 (DICOM JPIP Referenced Transfer Syntax) +1.2.840.10008.1.2.4.95 (DICOM JPIP Referenced Deflate Transfer Syntax) + + + Pixel value that represents one limit (inclusive) of a range of padding values used together with Pixel Padding Value (0028,0120) as defined in the General Equipment Module. See C.7.5.1.1.2 for further explanation. +Required if pixel padding is to be defined as a range rather than a single value. +Notes: 1. The Value Representation of this Attribute is determined by the value of Pixel Representation (0028,0103). +2. Pixel Padding Value (0028,0120) is also required when this Attribute is present. +
Pixel Padding Value (0028,0120) is used to pad grayscale images (those with a Photometric Interpretation of MONOCHROME1 or MONOCHROME2)to rectangular format. The native format of some images is not rectangular. It is common for devices with this format to pad the images to the rectangular format required by the DICOM Standard with a specific pixel value that is not contained in the native image. Further, when resampling, such as after spatial registration, padding may need to be used to fill previously non-existent pixels. +Pixel Padding Value (0028,0120) and Pixel Padding Range Limit (0028,0121) are also used to identify pixels to be excluded from the normal grayscale rendering pipeline for other reasons, such as suppression of background air. Pixel Padding Range Limit (0028,0121) is defined in the Image Pixel Module. +Notes: 1. The “native image†is that which is being padded to the required rectangular format, e.g., the area within the circular reconstruction perimeter of a CT image, or the subset of the rectangular area that contains useful image information. + 2. The pixel padding value is explicitly described in order to prevent display applications from taking it into account when determining the dynamic range of an image, since the Pixel Padding Value will be outside the range between the minimum and maximum values of the pixels in the native image + 3. No pixels in the native image will have a value equal to Pixel Padding Value. + +Pixel Padding Value (0028,0120) specifies either a single value of this padding value, or when combined with Pixel Padding Range Limit (0028,0121), a range of values (inclusive) that are padding. +The values of Pixel Padding Value (0028,0120) and Pixel Padding Range Limit (0028,0121) shall be valid values within the constraints defined by Bits Allocated (0028,0100), Bits Stored (0028,0101), and High Bit (0028,0102). +Pixel Padding Value (0028,0120) and Pixel Padding Range Limit (0028,0121) shall not be present when padding is performed but the pixel value used for padding does occur in the native image. +If Photometric Interpretation (0028,0004) is MONOCHROME2, Pixel Padding Value (0028,0120) shall be less than (closer to or equal to the minimum possible pixel value) or equal to Pixel Padding Range Limit (0028,0121). If Photometric Interpretation (0028,0004) is MONOCHROME1, Pixel Padding Value (0028,0120) shall be greater than (closer to or equal to the maximum possible pixel value) or equal to Pixel Padding Range Limit (0028,0121). +Notes: 1. When the relationship between pixel value and X-Ray Intensity is unknown, it is recommended that the following values be used to pad with black when the image is unsigned: + 0 if Photometric Interpretation (0028,0004) is MONOCHROME2. + 2BitsStored - 1 if Photometric Interpretation (0028,0004) is MONOCHROME1. + and when the image is signed: + -2BitsStored-1 if Photometric Interpretation (0028,0004) is MONOCHROME2. + 2BitsStored-1 - 1 if Photometric Interpretation (0028,0004) is MONOCHROME1. + 2. For projection radiography, when the relationship between pixel value and X-Ray Intensity is known (for example as defined by Pixel Intensity Relationship (0028,1040) and Pixel Intensity relationship Sign (0028,1041)), it is recommended that a pixel value equivalent to, or rendered similarly to, air (least X-Ray absorbance) be used for padding. However, if such a value may occur in the native image, the Pixel Padding Value (0028,0120) Attribute itself should not be sent. + E.g., for an XRF image obtained with an image intensifier, if air is black then a padded perimeter, if any, should also appear black. Typically though, if unpadded, this area would be collimated with a circular collimator, in which case the pixels would appear natively as white (greatest X-Ray absorbance) and a circular shutter would be necessary to neutralize them as black. Whether collimated areas are detected and treated as padded, or neutralized with shutters is at the discretion of the application. See also the Display Shutter Module C.7.6.11. + 3. The conditional requirement for the Pixel Padding Value Range Limit (0028,0121) in the Image Pixel Module means that it shall not be present unless Pixel Padding Value (0028,0120) is also present. + 4. The range of values to be suppressed between Pixel Padding Value (0028,0120) and Pixel Padding Value Range Limit (0028,0121) is specified as being inclusive, that is the values themselves as well as all values between are suppressed. + 5. When Pixel Padding Value Range Limit (0028,0121) is present, but not supported by a rendering application, the constraint that Pixel Padding Value (0028,0120) is closest to the “blackest†value, which is typically the most frequently occurring background pixel, will most often result in an acceptable display, permitting “backward compatibility†in the majority of cases. + +When modifying equipment changes the pixel padding value in the image, it shall change the values of Pixel Padding Value (0028,0120) and Pixel Padding Range Limit (0028,0121), if present. If modifying equipment changes the pixel padding values in the image to values present in the native image, the attribute Pixel Padding Value (0028,0120) and Pixel Padding Range Limit (0028,0121) shall be removed. +Notes: 1. For example, if a CT image containing signed values from -1024 to 3191 and a Pixel Padding Value of -2000 and a Rescale Intercept of 0 is converted to an unsigned image with a Rescale Intercept of -1024 by adding 1024 to all pixels and clipping all more negative pixels to 0, then the padding pixels will be indistinguishable from some of the modified native image pixels, and hence Pixel Padding Value (0028,0120) needs to be removed. + 2. If the modification involves lossy compression, which may result in changes to the pixel values, then the application of Pixel Padding Value and Pixel Padding Range Limit may result in a different appearance, and hence these attributes may need different values also. + +
+
+
+ + + Number of samples (planes) in this image. See C.7.6.3.1.1 for further explanation. +
Samples per Pixel (0028,0002) is the number of separate planes in this image. One, three, and four image planes are defined. Other numbers of image planes are allowed, but their meaning is not defined by this Standard. +For monochrome (gray scale) and palette color images, the number of planes is 1. For RGB and other three vector color models, the value of this attribute is 3. For four vector color models, the value of this attribute is 4. +All image planes shall have the same number of Rows (0028,0010), Columns (0028,0011), Bits Allocated (0028,0100), Bits Stored (0028,0101), High Bit (0028,0102), Pixel Representation (0028,0103), and Pixel Aspect Ratio (0028,0034). +The data in each pixel may be represented as a “Composite Pixel Codeâ€. If Samples Per Pixel is one, the Composite Pixel Code is just the “n†bit pixel sample, where “n†= Bits Allocated. If Samples Per Pixel is greater than one, Composite Pixel Code is a “k†bit concatenation of samples, where “k†= Bits Allocated multiplied by Samples Per Pixel, and with the sample representing the vector color designated first in the Photometric Interpretation name comprising the most significant bits of the Composite Pixel Code, followed in order by the samples representing the next vector colors, with the sample representing the vector color designated last in the Photometric Interpretation name comprising the least significant bits of the Composite Pixel Code. For example, for Photometric Interpretation = “RGBâ€, the most significant “Bits Allocated†bits contain the Red sample, the next “Bits Allocated†bits contain the Green sample, and the least significant “Bits Allocated†bits contain the Blue sample. +
+
+ + Specifies the intended interpretation of the pixel data. See C.7.6.3.1.2 for further explanation. +
The value of Photometric Interpretation (0028,0004) specifies the intended interpretation of the image pixel data. +See PS 3.5 for restrictions imposed by compressed Transfer Syntaxes. +The following values are defined. Other values are permitted but the meaning is not defined by this Standard. +MONOCHROME1 = Pixel data represent a single monochrome image plane. The minimum sample value is intended to be displayed as white after any VOI gray scale transformations have been performed. See PS 3.4. This value may be used only when Samples per Pixel (0028,0002) has a value of 1. +MONOCHROME2 = Pixel data represent a single monochrome image plane. The minimum sample value is intended to be displayed as black after any VOI gray scale transformations have been performed. See PS 3.4. This value may be used only when Samples per Pixel (0028,0002) has a value of 1. +PALETTE COLOR = Pixel data describe a color image with a single sample per pixel (single image plane). The pixel value is used as an index into each of the Red, Blue, and Green Palette Color Lookup Tables (0028,1101-1103&1201-1203). This value may be used only when Samples per Pixel (0028,0002) has a value of 1. When the Photometric Interpretation is Palette Color; Red, Blue, and Green Palette Color Lookup Tables shall be present. +RGB = Pixel data represent a color image described by red, green, and blue image planes. The minimum sample value for each color plane represents minimum intensity of the color. This value may be used only when Samples per Pixel (0028,0002) has a value of 3. +HSV = Retired. +ARGB = Retired. +CMYK = Retired. +YBR_FULL = Pixel data represent a color image described by one luminance (Y) and two chrominance planes (CB and CR). This photometric interpretation may be used only when Samples per Pixel (0028,0002) has a value of 3. Black is represented by Y equal to zero. The absence of color is represented by both CB and CR values equal to half full scale. +Note: In the case where the Bits Allocated (0028,0100) has value of 8 half full scale is 128. + +In the case where Bits Allocated (0028,0100) has a value of 8 then the following equations convert between RGB and YCBCR Photometric Interpretation. +Y = + .2990R + .5870G + .1140B +CB = - .1687R - .3313G + .5000B + 128 +CR = + .5000R - .4187G - .0813B + 128 +Note: The above is based on CCIR Recommendation 601-2 dated 1990. + +YBR_FULL_422 = The same as YBR_FULL except that the CB and CR values are sampled horizontally at half the Y rate and as a result there are half as many CB and CR values as Y values. +This Photometric Interpretation is only allowed with Planar Configuration (0028,0006) equal to 0. Two Y values shall be stored followed by one CB and one CR value. The CB and CR values shall be sampled at the location of the first of the two Y values. For each Row of Pixels, the first CB and CR samples shall be at the location of the first Y sample. The next CB and CR samples shall be at the location of the third Y sample etc. +Note: This subsampling is often referred to as cosited sampling. + +YBR_PARTIAL_422 = The same as YBR_FULL_422 except that: +1. black corresponds to Y = 16; +2. Y is restricted to 220 levels (i.e. the maximum value is 235); +3. CB and CR each has a minimum value of 16; +4. CB and CR are restricted to 225 levels (i.e. the maximum value is 240); +5. lack of color is represented by CB and CR equal to 128. +In the case where Bits Allocated (0028,0100) has value of 8 then the following equations convert between RGB and YBR_PARTIAL_422 Photometric Interpretation +Y = + .2568R + .5041G + .0979B + 16 +CB = - .1482R - .2910G + .4392B + 128 +CR = + .4392R - .3678G - .0714B + 128 +Note: The above is based on CCIR Recommendation 601-2 dated 1990. + +YBR_PARTIAL_420 = The same as YBR_PARTIAL_422 except that the CB and CR values are sampled horizontally and vertically at half the Y rate and as a result there are four times less CB and CR values than Y values, versus twice less for YBR_PARTIAL_422. +This Photometric Interpretation is only allowed with Planar Configuration (0028,0006) equal to 0. The CB and CR values shall be sampled at the location of the first of the two Y values. For the first Row of Pixels (etc.), the first CB and CR samples shall be at the location of the first Y sample. The next CB and CR samples shall be at the location of the third Y sample etc. The next Rows of Pixels containing CB and CR samples (at the same locations than for the first Row) will be the third etc. +YBR_ICT = Irreversible Color Transformation: +Pixel data represent a color image described by one luminance (Y) and two chrominance planes (CB and CR). This photometric interpretation may be used only when Samples per Pixel (0028,0002) has a value of 3. Black is represented by Y equal to zero. The absence of color is represented by both CB and CR values equal to zero. +Regardless of the value of Bits Allocated (0028,0100), the following equations convert between RGB and YCBCR Photometric Interpretation. +Y = + .29900R + .58700G + .11400B +CB = - .16875R - .33126G + .50000B +CR = + .50000R - .41869G - .08131B +Notes: 1. The above is based on ISO/IEC 15444-1 (JPEG 2000). + 2. In a JPEG 2000 bitstream, DC level shifting (used if the untransformed components are unsigned) is applied before forward color transformation, and the transformed components may be signed (unlike in JPEG ISO/IEC 10918-1). + 3. In JPEG 2000, spatial down-sampling of the chrominance components, if performed, is signaled in the JPEG 2000 bitstream. + +YBR_RCT = Reversible Color Transformation: +Pixel data represent a color image described by one luminance (Y) and two chrominance planes (CB and CR). This photometric interpretation may be used only when Samples per Pixel (0028,0002) has a value of 3. Black is represented by Y equal to zero. The absence of color is represented by both CB and CR values equal to zero. +Regardless of the value of Bits Allocated (0028,0100), the following equations convert between RGB and YBR_RCT Photometric Interpretation. +Y = R + 2G +B) / 4 (Note:  mean floor) +CB = B - G +CR = R - G +The following equations convert between YBR_RCT and RGB Photometric Interpretation. +G = Y –  (CR + CB) / 4 +R = CR + G +B = CB + G +Notes: 1. The above is based on ISO/IEC 15444-1 (JPEG 2000). + 2. In a JPEG 2000 bitstream, DC level shifting (used if the untransformed components are unsigned) is applied before forward color transformation, and the transformed components may be signed (unlike in JPEG ISO/IEC 10918-1). + 3. This photometric interpretation is a reversible approximation to the YUV transformation used in PAL and SECAM. + +
+
+ + Number of rows in the image. + + + Number of columns in the image + + + Number of bits allocated for each pixel sample. Each sample shall have the same number of bits allocated. See PS 3.5 for further explanation. + + + Number of bits stored for each pixel sample. Each sample shall have the same number of bits stored. See PS 3.5 for further explanation. + + + Most significant bit for pixel sample data. Each sample shall have the same high bit. See PS 3.5 for further explanation. + + + Data representation of the pixel samples. Each sample shall have the same pixel representation. Enumerated Values: +0000H = unsigned integer. +0001H = 2's complement + + + A data stream of the pixel samples that comprise the Image. See C.7.6.3.1.4 for further explanation. +Required if Pixel Data Provider URL (0028,7FE0) is not present. +
Pixel Data (7FE0,0010) for this image. The order of pixels sent for each image plane is left to right, top to bottom, i.e., the upper left pixel (labeled 1,1) is sent first followed by the remainder of row 1, followed by the first pixel of row 2 (labeled 2,1) then the remainder of row 2 and so on. +For multi-plane images see Planar Configuration (0028,0006) in this Section. +
+
+ + Indicates whether the pixel data are sent color-by-plane or color-by-pixel. Required if Samples per Pixel (0028,0002) has a value greater than 1. See C.7.6.3.1.3 for further explanation. +
Planar Configuration (0028,0006) indicates whether the color pixel data are sent color-by-plane or color-by-pixel. This Attribute shall be present if Samples per Pixel (0028,0002) has a value greater than 1. It shall not be present otherwise. +Enumerated Values: +0 = The sample values for the first pixel are followed by the sample values for the second pixel, etc. For RGB images, this means the order of the pixel values sent shall be R1, G1, B1, R2, G2, B2, ..., etc. +1 = Each color plane shall be sent contiguously. For RGB images, this means the order of the pixel values sent is R1, R2, R3, ..., G1, G2, G3, ..., B1, B2, B3, etc. +Note: Planar Configuration (0028,0006) is not meaningful when a compression transfer syntax is used that involves reorganization of sample components in the compressed bit stream. In such cases, since the Attribute is required to be sent, then an appropriate value to use may be specified in the description of the Transfer Syntax in PS 3.5, though in all likelihood the value of the Attribute will be ignored by the receiving implementation. + +
+
+ + Ratio of the vertical size and horizontal size of the pixels in the image specified by a pair of integer values where the first value is the vertical pixel size, and the second value is the horizontal pixel size. Required if the aspect ratio values do not have a ratio of 1:1 and the physical pixel spacing is not specified by Pixel Spacing (0028,0030), or Imager Pixel Spacing (0018,1164) or Nominal Scanned Pixel Spacing (0018,2010), either for the entire Image or per-frame in a Functional Group Macro. See C.7.6.3.1.7. +
The pixel aspect ratio is the ratio of the vertical size and horizontal size of the pixels in the image specified by a pair of integer values where the first value is the vertical pixel size, and the second value is the horizontal pixel size. To illustrate, consider the following example pixel size: + +Pixel Aspect Ratio = Vertical Size \ Horizontal Size = 0.30 mm \0.25 mm. Thus the Pixel Aspect Ratio could be represented as the multivalued integer string "6\5", "60\50", or any equivalent integer ratio. +
+
+ + The minimum actual pixel value encountered in this image. + + + The maximum actual pixel value encountered in this image. + + + Specifies the format of the Red Palette Color Lookup Table Data (0028,1201) Required if Photometric Interpretation (0028,0004) has a value of PALETTE COLOR or Pixel Presentation (0008,9205) at the image level equals COLOR or MIXED. See C.7.6.3.1.5 for further explanation. +
The three values of Palette Color Lookup Table Descriptor (0028,1101-1103) describe the format of the Lookup Table Data in the corresponding Data Element (0028,1201-1203) or (0028,1221-1223). +The first value is the number of entries in the lookup table. When the number of table entries is equal to 216 then this value shall be 0. The first value shall be identical for each of the Red, Green and Blue Palette Color Lookup Table Descriptors. +The second value is the first stored pixel value mapped. This pixel value is mapped to the first entry in the Lookup Table Data. All image pixel values less than the first value mapped are also mapped to the first entry in the Lookup Table Data if the Photometric Interpretation is PALETTE COLOR. +Note: In the case of the Supplemental Palette Color LUT, the stored pixel values less than the second descriptor value are grayscale values. + +An image pixel value one greater than the first value mapped is mapped to the second entry in the Lookup Table Data. Subsequent image pixel values are mapped to the subsequent entries in the Lookup Table Data up to an image pixel value equal to number of entries + first value mapped – 1, which is mapped to the last entry in the Lookup Table Data. Image pixel values greater than or equal to number of entries + first value mapped are also mapped to the last entry in the Lookup Table Data. The second value shall be identical for each of the Red, Green and Blue Palette Color Lookup Table Descriptors. +The third value specifies the number of bits for each entry in the Lookup Table Data. It shall take the value of 8 or 16. The LUT Data shall be stored in a format equivalent to 8 bits allocated when the number of bits for each entry is 8, and 16 bits allocated when the number of bits for each entry is 16, where in both cases the high bit is equal to bits allocated-1. The third value shall be identical for each of the Red, Green and Blue Palette Color Lookup Table Descriptors. +Note: Some implementations have encoded 8 bit entries with 16 bits allocated, padding the high bits; this can be detected by comparing the number of entries specified in the LUT Descriptor with the actual value length of the LUT Data entry. The value length in bytes should equal the number of entries if bits allocated is 8, and be twice as long if bits allocated is 16. + +When the Palette Color Lookup Table Descriptor (0028,1101-1103) are used as part of the Palette Color Lookup Table Module or the Supplemental Palette Color Lookup Table Module, the third value shall be equal to 16. +Notes: 1. A value of 16 indicates the Lookup Table Data will range from (0,0,0) minimum intensity to (65535,65535,65535) maximum intensity. + 2. Since the Palette Color Lookup Table Descriptor (0028,1101-1103) Attributes are multi-valued, in an Explicit VR Transfer Syntax, only one value representation (US or SS) may be specified, even though the first and third values are always by definition interpreted as unsigned. The explicit VR actually used is dictated by the VR needed to represent the second value, which will be consistent with Pixel Representation (0028,0103). + +
+
+ + Specifies the format of the Green Palette Color Lookup Table Data (0028,1202) Required if Photometric Interpretation (0028,0004) has a value of PALETTE COLOR or Pixel Presentation (0008,9205) at the image level equals COLOR or MIXED. See C.7.6.3.1.5 for further explanation. +
The three values of Palette Color Lookup Table Descriptor (0028,1101-1103) describe the format of the Lookup Table Data in the corresponding Data Element (0028,1201-1203) or (0028,1221-1223). +The first value is the number of entries in the lookup table. When the number of table entries is equal to 216 then this value shall be 0. The first value shall be identical for each of the Red, Green and Blue Palette Color Lookup Table Descriptors. +The second value is the first stored pixel value mapped. This pixel value is mapped to the first entry in the Lookup Table Data. All image pixel values less than the first value mapped are also mapped to the first entry in the Lookup Table Data if the Photometric Interpretation is PALETTE COLOR. +Note: In the case of the Supplemental Palette Color LUT, the stored pixel values less than the second descriptor value are grayscale values. + +An image pixel value one greater than the first value mapped is mapped to the second entry in the Lookup Table Data. Subsequent image pixel values are mapped to the subsequent entries in the Lookup Table Data up to an image pixel value equal to number of entries + first value mapped – 1, which is mapped to the last entry in the Lookup Table Data. Image pixel values greater than or equal to number of entries + first value mapped are also mapped to the last entry in the Lookup Table Data. The second value shall be identical for each of the Red, Green and Blue Palette Color Lookup Table Descriptors. +The third value specifies the number of bits for each entry in the Lookup Table Data. It shall take the value of 8 or 16. The LUT Data shall be stored in a format equivalent to 8 bits allocated when the number of bits for each entry is 8, and 16 bits allocated when the number of bits for each entry is 16, where in both cases the high bit is equal to bits allocated-1. The third value shall be identical for each of the Red, Green and Blue Palette Color Lookup Table Descriptors. +Note: Some implementations have encoded 8 bit entries with 16 bits allocated, padding the high bits; this can be detected by comparing the number of entries specified in the LUT Descriptor with the actual value length of the LUT Data entry. The value length in bytes should equal the number of entries if bits allocated is 8, and be twice as long if bits allocated is 16. + +When the Palette Color Lookup Table Descriptor (0028,1101-1103) are used as part of the Palette Color Lookup Table Module or the Supplemental Palette Color Lookup Table Module, the third value shall be equal to 16. +Notes: 1. A value of 16 indicates the Lookup Table Data will range from (0,0,0) minimum intensity to (65535,65535,65535) maximum intensity. + 2. Since the Palette Color Lookup Table Descriptor (0028,1101-1103) Attributes are multi-valued, in an Explicit VR Transfer Syntax, only one value representation (US or SS) may be specified, even though the first and third values are always by definition interpreted as unsigned. The explicit VR actually used is dictated by the VR needed to represent the second value, which will be consistent with Pixel Representation (0028,0103). + +
+
+ + Specifies the format of the Blue Palette Color Lookup Table Data (0028,1203) Required if Photometric Interpretation (0028,0004) has a value of PALETTE COLOR or Pixel Presentation (0008,9205) at the image level equals COLOR or MIXED. See C.7.6.3.1.5 for further explanation. +
The three values of Palette Color Lookup Table Descriptor (0028,1101-1103) describe the format of the Lookup Table Data in the corresponding Data Element (0028,1201-1203) or (0028,1221-1223). +The first value is the number of entries in the lookup table. When the number of table entries is equal to 216 then this value shall be 0. The first value shall be identical for each of the Red, Green and Blue Palette Color Lookup Table Descriptors. +The second value is the first stored pixel value mapped. This pixel value is mapped to the first entry in the Lookup Table Data. All image pixel values less than the first value mapped are also mapped to the first entry in the Lookup Table Data if the Photometric Interpretation is PALETTE COLOR. +Note: In the case of the Supplemental Palette Color LUT, the stored pixel values less than the second descriptor value are grayscale values. + +An image pixel value one greater than the first value mapped is mapped to the second entry in the Lookup Table Data. Subsequent image pixel values are mapped to the subsequent entries in the Lookup Table Data up to an image pixel value equal to number of entries + first value mapped – 1, which is mapped to the last entry in the Lookup Table Data. Image pixel values greater than or equal to number of entries + first value mapped are also mapped to the last entry in the Lookup Table Data. The second value shall be identical for each of the Red, Green and Blue Palette Color Lookup Table Descriptors. +The third value specifies the number of bits for each entry in the Lookup Table Data. It shall take the value of 8 or 16. The LUT Data shall be stored in a format equivalent to 8 bits allocated when the number of bits for each entry is 8, and 16 bits allocated when the number of bits for each entry is 16, where in both cases the high bit is equal to bits allocated-1. The third value shall be identical for each of the Red, Green and Blue Palette Color Lookup Table Descriptors. +Note: Some implementations have encoded 8 bit entries with 16 bits allocated, padding the high bits; this can be detected by comparing the number of entries specified in the LUT Descriptor with the actual value length of the LUT Data entry. The value length in bytes should equal the number of entries if bits allocated is 8, and be twice as long if bits allocated is 16. + +When the Palette Color Lookup Table Descriptor (0028,1101-1103) are used as part of the Palette Color Lookup Table Module or the Supplemental Palette Color Lookup Table Module, the third value shall be equal to 16. +Notes: 1. A value of 16 indicates the Lookup Table Data will range from (0,0,0) minimum intensity to (65535,65535,65535) maximum intensity. + 2. Since the Palette Color Lookup Table Descriptor (0028,1101-1103) Attributes are multi-valued, in an Explicit VR Transfer Syntax, only one value representation (US or SS) may be specified, even though the first and third values are always by definition interpreted as unsigned. The explicit VR actually used is dictated by the VR needed to represent the second value, which will be consistent with Pixel Representation (0028,0103). + +
+
+ + Red Palette Color Lookup Table Data. +Required if Photometric Interpretation (0028,0004) has a value of PALETTE COLOR or Pixel Presentation (0008,9205) at the image level equals COLOR or MIXED. See C.7.6.3.1.6 for further explanation. +
Palette Color Lookup Table Data (0028,1201-1203) contain the lookup table data corresponding to the Lookup Table Descriptor (0028,1101-1103). +Palette color values must always be scaled across the full range of available intensities. This is indicated by the fact that there are no bits stored and high bit values for palette color data. +Note: For example, if there are 16 bits per entry specified and only 8 bits of value are truly used then the 8 bit intensities from 0 to 255 must be scaled to the corresponding 16 bit intensities from 0 to 65535. To do this for 8 bit values, simply replicate the value in both the most and least significant bytes. + +These lookup tables shall be used only when there is a single sample per pixel (single image plane) in the image. +These lookup tables are required when the value of Photometric Interpretation (0028,0004) is Palette Color. The semantics of these lookup tables is not defined otherwise. +
+
+ + Green Palette Color Lookup Table Data. Required if Photometric Interpretation (0028,0004) has a value of PALETTE COLOR or Pixel Presentation (0008,9205) at the image level equals COLOR or MIXED. See C.7.6.3.1.6 for further explanation. +
Palette Color Lookup Table Data (0028,1201-1203) contain the lookup table data corresponding to the Lookup Table Descriptor (0028,1101-1103). +Palette color values must always be scaled across the full range of available intensities. This is indicated by the fact that there are no bits stored and high bit values for palette color data. +Note: For example, if there are 16 bits per entry specified and only 8 bits of value are truly used then the 8 bit intensities from 0 to 255 must be scaled to the corresponding 16 bit intensities from 0 to 65535. To do this for 8 bit values, simply replicate the value in both the most and least significant bytes. + +These lookup tables shall be used only when there is a single sample per pixel (single image plane) in the image. +These lookup tables are required when the value of Photometric Interpretation (0028,0004) is Palette Color. The semantics of these lookup tables is not defined otherwise. +
+
+ + Blue Palette Color Lookup Table Data. Required if Photometric Interpretation (0028,0004) has a value of PALETTE COLOR or Pixel Presentation (0008,9205) at the image level equals COLOR or MIXED. See C.7.6.3.1.6 for further explanation. +
Palette Color Lookup Table Data (0028,1201-1203) contain the lookup table data corresponding to the Lookup Table Descriptor (0028,1101-1103). +Palette color values must always be scaled across the full range of available intensities. This is indicated by the fact that there are no bits stored and high bit values for palette color data. +Note: For example, if there are 16 bits per entry specified and only 8 bits of value are truly used then the 8 bit intensities from 0 to 255 must be scaled to the corresponding 16 bit intensities from 0 to 65535. To do this for 8 bit values, simply replicate the value in both the most and least significant bytes. + +These lookup tables shall be used only when there is a single sample per pixel (single image plane) in the image. +These lookup tables are required when the value of Photometric Interpretation (0028,0004) is Palette Color. The semantics of these lookup tables is not defined otherwise. +
+
+ + An ICC Profile encoding the transformation of device-dependent color stored pixel values into PCS-Values. +See Section C.11.15.1.1.1. +When present, defines the color space of color Pixel Data (7FE0,0010) values, and the output of Palette Color Lookup Table Data (0028,1201-1203). +Note: The profile applies only to the Pixel Data (7FE0,0010) attribute at the same level of the dataset and not to any icons nested within sequences, which may or may not have their own ICC profile specified. + +
+ + + Contrast or bolus agent + + + Sequence that identifies the contrast agent. One or more Items may be present. + + + + Administration route of contrast agent + + + Sequence that identifies the route of administration of contrast agent. Only a single Item shall be permitted in this sequence. + + + + Sequence that identifies any additional drug that is administered with the contrast agent bolus. One or more Items may be present. + + + + Volume injected in milliliters of diluted contrast agent + + + Time of start of injection + + + Time of end of contrast injection + + + Total amount in milliliters of the undiluted contrast agent + + + Rate(s) of injection(s) in milliliters/sec + + + Duration(s) of injection(s) in seconds. Each Contrast Flow Duration value shall correspond to a value of Contrast Flow Rate (0018,1046). + + + Active ingredient of agent. Defined Terms: +IODINE +GADOLINIUM +CARBON DIOXIDE +BARIUM + + + Milligrams of active ingredient per milliliter of (diluted) agent + + + + + Sequence that identifies one or more contrast agents administered prior to or during the acquisition. Shall contain one or more Items. + + + + Identifying number, unique within this SOP Instance, of the agent administered. Used to reference this particular agent from the Contrast/Bolus Functional Group Macro. The number shall be 1 for the first Item and increase by 1 for each subsequent Item. + + + Sequence that identifies the route of administration of contrast agent. Shall contain exactly one Item. + + + + Active ingredient of agent. Zero or more Items may be included in the Sequence. + + + + Total volume administered in milliliters of diluted contrast agent. + + + Milligrams of active ingredient per milliliter of agent. + + + Absorption of the ingredient greater than the absorption of water (tissue). +Enumerated Values: +YES +NO +See Section C.7.6.4b.1. +
Table C.7-12 specifies the Attributes that describe the contrast /bolus used in the acquisition of the Image. +Table C.7-12 +CONTRAST/BOLUS MODULE ATTRIBUTES + +Note: 1. Flow duration is an alternate method of specifying stop time + 2. Flow rate allows for stepped injections by being capable of multiple values (1,N) instances. + 3. For a 100 ml injection of 76% Diatrizoate and meglumine/sodium, diluted 1:1, + the Contrast/Bolus Agent would be “76% Diatrizoate†as text + the Contrast/Bolus Volume would be 100 ml, + the Contrast/Bolus Total Dose would be 50 ml, + the Contrast/Bolus Ingredient would be “IODINEâ€, + the Contrast/Bolus Ingredient Concentration would be 370mg/ml. + +
+
+ + Sequence that describes one or more phases of contrast administered. If present, shall contain one or more Items. + + + Volume administered during this phase in milliliters of diluted contrast agent. + + + Time of start of administration. + + + Time of end of administration. + + + Rate of administration in milliliters/sec. Only a single value shall be present. + + + Duration of injection in seconds. Only a single value shall be present. + +
+ + + Describes the preferred playback sequencing for a multi-frame image. +Enumerated Values: +0 = Looping (1,2...n,1,2,...n,1,2,....n,...) +1 = Sweeping (1,2,...n,n-1,...2,1,2,...n,...) + + + Nominal time (in msec) per individual frame. See C.7.6.5.1.1 for further explanation. Required if Frame Increment Pointer (0028,0009) points to Frame Time. +
Frame Time (0018,1063) is the nominal time (in milliseconds) between individual frames of a Multi-frame image. If the Frame Increment Pointer points to this Attribute, Frame Time shall be used in the following manner to calculate 'the relative time' for each frame: +Frame 'Relative Time' (n) = Frame Delay + Frame Time * (n-1) + where: n = number of frame within the Multi-frame image and the first frame number is one +Note: When there is only one frame present, Frame Time (0018,1063) may have either a value of 0, or a nominal value that would apply if there were multiple frames. + +
+
+ + An array that contains the real time increments (in msec) between frames for a Multi-frame image. See C.7.6.5.1.2 for further explanation. Required if Frame Increment Pointer (0028,0009) points to Frame Time Vector. +Note: Frame Time Vector arrays may not be properly encoded if Explicit-VR transfer syntax is used and the VL of this attribute exceeds 65534 bytes. +
Frame Time Vector (0018,1065) is an array that contains the time increments (in milliseconds) between the nth frame and the previous frame for a Multi-frame image. The first frame always has a time increment of 0. If the Frame Increment Pointer points to this Attribute, the Frame Time Vector shall be used in the following manner to calculate 'relative time' T(n) for frame n: + +where ï„ti is the ith Frame Time Vector component. +
+
+ + The frame number of the first frame of the Multi-frame image to be displayed. + + + The Frame Number of the last frame of a Multi-frame image to be displayed. + + + Recommended rate at which the frames of a Multi-frame image should be displayed in frames/second. + + + Number of frames per second. + + + Time (in msec) from Content Time (0008,0033) to the start of the first frame in a Multi-frame image. + + + Delay time in milliseconds from trigger (e.g., X-Ray on pulse) to the first frame of a Multi-frame image. + + + Total time in seconds that data was actually taken for the entire Multi-frame image. + + + Elapsed time of data acquisition in msec per each frame. + + + Description of any multiplexed audio channels. See Section C.7.6.5.1.3. +Required if the Transfer Syntax used to encode the multi-frame image contains multiplexed (interleaved) audio channels, such as is possible with MPEG2. Zero or more items may be present in this sequence. +
During a video acquisition, audio may be used for voice commentary of what is being observed, as well as to record sound-based physiological information such as Doppler audio. +Some Transfer Syntaxes allow for the multiplexing of interleaved audio with video data, and the Attributes of the Cine Module support this encoding paradigm. They are not intended to describe audio acquired simultaneously when it is encoded in other SOP Instances or within Attributes other than Pixel Data (7FE0,0010) of the same SOP Instance. +Synchronization between audio and video is assumed to be encoded at the Transfer Syntax level (i.e. within the encoded bit stream). +Note: If no audio was recorded, the Multiplexed Audio Channels Description Code Sequence (003A,0300) will be present and contain no sequence items. +
+
+ + A reference to the audio channel as identified within Transfer Syntax encoded bit stream (1 for the main channel, 2 for the second channel and 3 to 9 to the complementary channels). + + + A coded descriptor qualifying the mode of the channel: +Enumerated Values: +MONO = 1 signal +STEREO = 2 simultaneously acquired (left and right) signals + + + A coded descriptor of the audio channel source. Only a single Item shall be permitted in this sequence. + + +
+ + + Number of frames in a Multi-frame Image. See C.7.6.6.1.1 for further explanation. +
A Multi-frame Image is defined as a Image whose pixel data consists of a sequential set of individual Image Pixel frames. A Multi-frame Image is transmitted as a single contiguous stream of pixels. Frame headers do not exist within the data stream. +Each individual frame shall be defined (and thus can be identified) by the Attributes in the Image Pixel Module (see C.7.6.3). All Image IE Attributes shall be related to the first frame in the Multi-frame image. +The total number of frames contained within a Multi-frame Image is conveyed in the Number of Frames (0028,0008). +The frames within a Multi-frame Image shall be conveyed as a logical sequence. The information that determines the sequential order of the frames shall be identified by the Data Element Tag or tags conveyed by the Frame Increment Pointer (0028,0009). Each specific Image IOD that supports the Multi-frame Module specializes the Frame Increment Pointer (0028,0009) to identify the Attributes that may be used as sequences. +Even if only a single frame is present, Frame Increment Pointer (0028,0009) is still required to be present and have at least one value, each of which shall point to an attribute that is also present in the dataset and has a value. +Note: For example, in single-frame instance of an IOD that is required to or may contain the Cine Module, it may be appropriate for Frame Time (0018,1063) to be present with a value of 0, and be the only target of Frame Increment Pointer (0028,0009). + +
+
+ + Contains the Data Element Tag of the attribute that is used as the frame increment in Multi-frame pixel data. See C.7.6.6.1.1 for further explanation. +
A Multi-frame Image is defined as a Image whose pixel data consists of a sequential set of individual Image Pixel frames. A Multi-frame Image is transmitted as a single contiguous stream of pixels. Frame headers do not exist within the data stream. +Each individual frame shall be defined (and thus can be identified) by the Attributes in the Image Pixel Module (see C.7.6.3). All Image IE Attributes shall be related to the first frame in the Multi-frame image. +The total number of frames contained within a Multi-frame Image is conveyed in the Number of Frames (0028,0008). +The frames within a Multi-frame Image shall be conveyed as a logical sequence. The information that determines the sequential order of the frames shall be identified by the Data Element Tag or tags conveyed by the Frame Increment Pointer (0028,0009). Each specific Image IOD that supports the Multi-frame Module specializes the Frame Increment Pointer (0028,0009) to identify the Attributes that may be used as sequences. +Even if only a single frame is present, Frame Increment Pointer (0028,0009) is still required to be present and have at least one value, each of which shall point to an attribute that is also present in the dataset and has a value. +Note: For example, in single-frame instance of an IOD that is required to or may contain the Cine Module, it may be appropriate for Frame Time (0018,1063) to be present with a value of 0, and be the only target of Frame Increment Pointer (0028,0009). + +
+
+
+ + + The frame number selected for use as a pictorial representation (e.g. icon) of the Multi-frame Image + + + Frame number(s) selected as frames of interest. A frame number may appear more than once. + + + Description of each one of the Frame(s) of Interest selected in (0028,6020). If multiple Frames of Interest are selected and this Attribute is used, it shall contain the same number of values as are in Frame Numbers of Interest (0028,6020). + + + A defined term for each one of the Frame(s) of Interest (0028,6020) that identifies the significance of the frame. If multiple Frames of Interest are selected and this Attribute is used, it shall contain the same number of values as are in Frame Numbers of Interest (0028,6020). +Defined Terms are: +HIGHMI = a frame acquired at the time of the high power pulse that destroys acoustic contrast +RWAVE = the frame closest to the R-Wave +TRIGGER = a trigger frame, for example a set delay from the R Wave +ENDSYSTOLE = the frame closest to end of systole, at the end of the T-wave + + + + + Defines a sequence that describes mask subtraction operations for a Multi-frame Image. One or more items may be included in this sequence. + + + Defined Term identifying the type of mask operation to be performed. See C.7.6.10.1 for further explanation. +
+ + + Identification of the Subtraction Item used to associate a certain Mask Sub-Pixel Shift (0028,6114) in the Frame Pixel Shift Functional Group. +See C.7.6.16.2.14.1. +Required if SOP Class UID (0008,0016) equals "1.2.840.10008.5.1.4.1.1.12.1.1" or "1.2.840.10008.5.1.4.1.1.12.2.1". May be present otherwise. +
Subtraction Item ID (0028,9416) specifies the ID of a subtraction operation to which the Mask Sub-pixel Shift (0028,6114) is associated. The Subtraction Item ID is also present in the Mask Subtraction Sequence (0028,6100) to allow this association. +When used as per-frame macro, the Subtraction Item ID (0028,9416) allows to specify different values of Mask Sub-pixel Shift (0028,6114) individually frame by frame, and relate them to a single item of the Mask Subtraction Sequence (0028,6100). +Note: There is no restriction in the number of Subtraction Item ID’s associated to each contrast frame. The same contrast frame may be present in several items of the Mask Subtraction Sequence, each item having a different value of Subtraction Item ID. + +When used as shared macro, the Subtraction Item ID (0028,9416) allows to specify one or more values of Mask Sub-pixel Shift that will be applied to all the frames of the Multi-frame image. +Note: Example of usage of Subtraction Item ID in a per-frame macro, see Figure C.7.6.16-8: + In this example of Multi-Frame Image with 3 frames, one Mask Frame (i.e., Frame 1) is applied to the next two frames of the Multi-Frame image (i.e., Frames 2 and 3). Therefore, there is only one item in the Mask Subtraction Sequence, containing its own Subtraction Item ID value (i.e., 100). The Frame Pixel Shift Macro allows to define a Mask Sub-Pixel Shift different for each contrast frame. + First Frame Subtracted: Subtraction of Frame 1 (Mask) to Frame 2, with Sub-Pixel Shift 1.3\2.4 + Second Frame Subtracted: Subtraction of Frame 1 (Mask) to Frame 3, with Sub-Pixel Shift 1.9\3.0 + +Figure C.7.6.16-8 +Example of usage of Subtraction Item ID in a per-frame Macro + +
+
+ + Each pair of numbers in this multi-valued attribute specify a beginning and ending frame number inclusive of a range where this particular mask operation is valid. Discontinuous ranges are represented by multiple pairs of numbers. Frames in a Multi-frame Image are specified by sequentially increasing number values beginning with 1. If this Attribute is missing in this particular sequence item, then the mask operation is applicable throughout the entire Multi-frame Image, subject to certain limits as described in C.7.6.10.1.1. +Required if Mask Operation (0028,6101) equals REV_TID. May be present otherwise. + + + Specifies the frame numbers of the pixel data used to generate this mask. Frames in a Multi-frame Image are specified by sequentially increasing number values beginning with 1. Required if the Mask Operation (0028,6101) is AVG_SUB. + + + Specifies the number of contrast frames to average together before performing the mask operation. If the Attribute is missing, no averaging is performed. + + + A pair of floating point numbers specifying the fractional vertical [adjacent row spacing] and horizontal [adjacent column spacing] pixel shift applied to the mask before subtracting it from the contrast frame. See Section C.7.6.10.1.2. +Note: When the Frame Pixel Shift Functional Group is present the values of the Mask Pixel Shift attribute of that Functional Group prevails over the values specified in this module. +
A pair of floating point numbers specifying the fractional vertical [adjacent row spacing] and horizontal [adjacent column spacing] pixel shift applied to the mask before subtracting it from the contrast frame. The row offset results in a shift of the pixels along the column axis. The column offset results in a shift of the pixels along the row axis. A positive row offset is a shift toward the pixels of the lower row of the pixel plane. A positive column offset is a shift toward the pixels of the left hand side column of the pixel plane. +
+
+ + If Mask Operation is TID, specifies the offset to be subtracted from the current frame number in order to locate the mask frame in TID mode. +If Mask Operation is REV_TID, specifies the initial offset to be subtracted from the first contrast frame number. See section C.7.6.10.1.1. +If zero length, TID Offset defaults to 1. Required if Mask Operation (0028,6101) is TID or REV_TID. + + + Free form explanation of this particular mask operation. + + + Specifies the method of selection of the mask operations of this item. +Defined Terms: +SYSTEM +USER + + + Specifies the recommended viewing protocol(s). +Defined terms: +SUB = for subtraction with mask images; +NAT = native viewing of image as sent. +Note: If an implementation does not recognize the defined term for Recommended Viewing Mode (0028,1090) , reverting to native display mode is recommended. + + + + + + + + Shape(s) of the shutter defined for display. Enumerated Values: +RECTANGULAR +CIRCULAR +POLYGONAL +This multi-valued Attribute shall contain at most one of each Enumerated Value. + + + Required if Shutter Shape (0018,1600) is RECTANGULAR. Location of the left edge of the rectangular shutter with respect to pixels in the image given as column. + + + Required if Shutter Shape (0018,1600) is RECTANGULAR. Location of the right edge of the rectangular shutter with respect to pixels in the image given as column. + + + Required if Shutter Shape (0018,1600) is RECTANGULAR. Location of the upper edge of the rectangular shutter with respect to pixels in the image given as row. + + + Required if Shutter Shape (0018,1600) is RECTANGULAR. Location of the lower edge of the rectangular shutter with respect to pixels in the image given as row. + + + Required if Shutter Shape (0018,1600) is CIRCULAR. Location of the center of the circular shutter with respect to pixels in the image given as row and column. + + + Required if Shutter Shape (0018,1600) is CIRCULAR. Radius of the circular shutter with respect to pixels in the image given as a number of pixels along the row direction. + + + Required if Shutter Shape (0018,1600) is POLYGONAL. +Multiple Values where the first set of two values are: +row of the origin vertex +column of the origin vertex +Two or more pairs of values follow and are the row and column coordinates of the other vertices of the polygon shutter. Polygon shutters are implicitly closed from the last vertex to the origin vertex and all edges shall be non-intersecting except at the vertices. + + + A single gray unsigned value used to replace those parts of the image occluded by the shutter, when rendered on a monochrome display. The units are specified in P-Values, from a minimum of 0000H (black) up to a maximum of FFFFH (white). +Note: The maximum P-Value for this Attribute may be different from the maximum P-Value from the output of the Presentation LUT, which may be less than 16 bits in depth. + + + A color triplet value used to replace those parts of the image occluded by the shutter, when rendered on a color display. The units are specified in PCS-Values, and the value is encoded as CIELab. See C.10.7.1.1. +
Attributes such as Graphic Layer Recommended Display CIELab Value (0070,0401) consist of three unsigned short values: +
+
+
+ + + Introduces sequence of items describing devices used that may be visible in the image. +One or more Items may be included in this Sequence. + + + + Manufacturer of the device + + + Manufacturer's model name of the device + + + Manufacturer's serial number of the device + + + User-supplied identifier for the device + + + Length in mm of device. See C.7.6.12.1.1. +
Depending on the type of device specified by the Code Value (0008,0100) in an item of the Device Sequence (0050,0010), various device size attributes (e.g., Device Length (0050,0014), Device Diameter (0050,0016), Device Volume (0050,0018), Inter Marker Distance (0050,0019)) may be required to fully characterize the device. +
+
+ + Unit diameter of device. See C.7.6.12.1.1. +
Depending on the type of device specified by the Code Value (0008,0100) in an item of the Device Sequence (0050,0010), various device size attributes (e.g., Device Length (0050,0014), Device Diameter (0050,0016), Device Volume (0050,0018), Inter Marker Distance (0050,0019)) may be required to fully characterize the device. +
+
+ + Required if Device Diameter (0050,0016) is present. Defined terms: +FR = French +GA = Gauge +IN = Inch +MM = Millimeter + + + Volume of device in ml. See C.7.6.12.1.1. +
Depending on the type of device specified by the Code Value (0008,0100) in an item of the Device Sequence (0050,0010), various device size attributes (e.g., Device Length (0050,0014), Device Diameter (0050,0016), Device Volume (0050,0018), Inter Marker Distance (0050,0019)) may be required to fully characterize the device. +
+
+ + Distance in mm between markers on calibrated device. See C.7.6.12.1.1. +
Depending on the type of device specified by the Code Value (0008,0100) in an item of the Device Sequence (0050,0010), various device size attributes (e.g., Device Length (0050,0014), Device Diameter (0050,0016), Device Volume (0050,0018), Inter Marker Distance (0050,0019)) may be required to fully characterize the device. +
+
+ + Further description in free form text describing the device. + +
+ + + Introduces sequence of items describing interventional therapies or procedures. +One or more Items may be included in this Sequence. + + + + Temporal relation of SOP Instance to intervention +Enumerated Values: +PRE +INTERMEDIATE +POST +NONE + + + + Sequence that identifies the interventional drug. +Only one item shall be included in this Sequence. + + + + Time of administration of the interventional drug. + + + Time of completion of administration of the intervention drug. + + + Sequence that identifies the Administration Route. This sequence shall contain exactly one item. + + + + Further description in free form text describing the therapy or other intervention. + + + + + A sequence of Items that describes the conditions present during the acquisition of the data of the SOP Instance. Zero or more items may be included in this sequence. + + + The type of the value encoded in this Item. +Defined Terms: +TEXT +NUMERIC +CODE +DATE +TIME +PNAME +See Section 10.2. + + + A concept that constrains the meaning of (i.e. defines the role of) the Observation Value. The "Name" component of a Name/Value pair. This sequence shall contain exactly one item. + + + + References one or more frames in a Multi-frame SOP Instance. The first frame shall be denoted as frame number one. +Required if this SOP Instance is a Multi-frame SOP Instance and the values in this sequence item do not apply to all frames. + + + This is the Value component of a Name/Value pair when the Concept implied by Concept Name Code Sequence (0040,A043) is a set of one or more numeric values. +Required if the value that Concept Name Code Sequence (0040,A043) requires (implies) is a set of one or more integers or real numbers. Shall not be present otherwise. + + + Units of measurement. Only a single Item shall be permitted in this Sequence. +Required if Numeric Value (0040,A30A) is sent. Shall not be present otherwise. + + + + This is the Value component of a Name/Value pair when the Concept implied by Concept Name Code Sequence (0040,A043) is a date. +Note: The purpose or role of the date value could be specified in Concept Name Code Sequence (0040,A043). + +Required if the value that Concept Name Code Sequence (0040,A043) requires (implies) is a date. Shall not be present otherwise. + + + This is the Value component of a Name/Value pair when the Concept implied by Concept Name Code Sequence (0040,A043) is a time. +Note: The purpose or role of the time value could be specified in Concept Name Code Sequence (0040,A043). + +Required if the value that Concept Name Code Sequence (0040,A043) requires (implies) is a time. Shall not be present otherwise. + + + This is the Value component of a Name/Value pair when the Concept implied by Concept Name Code Sequence (0040,A043) is a Person Name. +Note: The role of the person could be specified in Concept Name Code Sequence (0040,A043). + +Required if the value that Concept Name Code Sequence (0040,A043) irequires (implies) is a person name. Shall not be present otherwise. + + + This is the Value component of a Name/Value pair when the Concept implied by Concept Name Code Sequence (0040,A043) is a Text Observation Value. +Required if Date (0040,A121), Time (0040,A122), and Person Name (0040,A123) do not fully describe the concept specified by Concept Name Code Sequence (0040,A043). Shall not be present otherwise. + + + This is the Value component of a Name/Value pair when the Concept implied by Concept Name Code Sequence (0040,A043) is a Coded Value. This sequence shall contain exactly one item. +Required if Date (0040,A121), Time (0040,A122), Person Name (0040,A123), Text Value (0040,A160), and the pair of Numeric Value (0040,A30A) and Measurement Units Code Sequence (0040,08EA) are not present. + + + + Free-text description of the image-acquisition context. + + + + + Shape of the shutter defined for display. Enumerated Values are: +BITMAP +This Attribute shall contain one Value. + + + Specifies the Group (60xx) of an Overlay stored within the Presentation State IOD that contains the bitmap data, as defined in the Overlay Plane Module C.9.2. + + + A single gray unsigned value used to replace those parts of the image occluded by the shutter, when rendered on a monochrome display. The units are specified in P-Values, from a minimum of 0000H (black) up to a maximum of FFFFH (white). +Note: The maximum P-Value for this Attribute may be different from the maximum P-Value from the output of the Presentation LUT, which may be less than 16 bits in depth. + + + A color triplet value used to replace those parts of the image occluded by the shutter, when rendered on a color display. The units are specified in PCS-Values, and the value is encoded as CIELab. See C.10.7.1.1. +
Attributes such as Graphic Layer Recommended Display CIELab Value (0070,0401) consist of three unsigned short values: +
+
+
+ + + Sequence that contains the Functional Group Macros that are shared for all frames in this SOP Instance and Concatenation. +Note: The contents of this sequence are the same in all SOP Instances that comprise a Concatenation. +Zero or one Item may be included in this sequence. +See section C.7.6.16.1.1 for further explanation. + + + + Sequence that contains the Functional Group Macros corresponding to each frame of the Multi-frame Image. The first Item corresponds with the first frame, and so on. +Each Item shall contain the same set of Functional Group Macros. +This Sequence shall contain the same number of Items as the number of frames in the Multi-frame image. See Section C.7.6.16.1.2 for further explanation. +
The Per-frame Functional Groups Sequence Attribute (5200,9230) consists of a Sequence of Items. Each Item describes the frame of the same rank in the multi-frame pixel data. The first Item describes frame 1, the second Item describes frame 2, etc. Frames are implicitly numbered starting from 1. See Figure C.7.6.16-1. +
+
+ + + A number that identifies this instance. The value shall be the same for all SOP Instances of a Concatenation, and different for each separate Concatenation and for each SOP Instance not within a Concatenation in a series. + + + The date the data creation was started. +Note: For instance, this is the date the pixel data is created, not the date the data is acquired. + + + The time the data creation was started. +Note: For instance, this is the time the pixel data is created, not the time the data is acquired. + + + Number of frames in a multi-frame image. See C.7.6.6.1.1 for further explanation. +
A Multi-frame Image is defined as a Image whose pixel data consists of a sequential set of individual Image Pixel frames. A Multi-frame Image is transmitted as a single contiguous stream of pixels. Frame headers do not exist within the data stream. +Each individual frame shall be defined (and thus can be identified) by the Attributes in the Image Pixel Module (see C.7.6.3). All Image IE Attributes shall be related to the first frame in the Multi-frame image. +The total number of frames contained within a Multi-frame Image is conveyed in the Number of Frames (0028,0008). +The frames within a Multi-frame Image shall be conveyed as a logical sequence. The information that determines the sequential order of the frames shall be identified by the Data Element Tag or tags conveyed by the Frame Increment Pointer (0028,0009). Each specific Image IOD that supports the Multi-frame Module specializes the Frame Increment Pointer (0028,0009) to identify the Attributes that may be used as sequences. +Even if only a single frame is present, Frame Increment Pointer (0028,0009) is still required to be present and have at least one value, each of which shall point to an attribute that is also present in the dataset and has a value. +Note: For example, in single-frame instance of an IOD that is required to or may contain the Cine Module, it may be appropriate for Frame Time (0018,1063) to be present with a value of 0, and be the only target of Frame Increment Pointer (0028,0009). + +
+
+ + Offset of the first frame in a multi-frame image of a concatenation. Logical frame numbers in a concatenation can be used across all its SOP instances. This offset can be applied to the implicit frame number to find the logical frame number in a concatenation. The offset is numbered from zero; i.e., the instance of a concatenation that begins with the first frame of the concatenation has a Concatenation Frame Offset Number (0020,9228) of zero. +Required if Concatenation UID (0020,9161) is present. + + + The frame number selected for use as a pictorial representation (e.g. icon) of the multi-frame Image. + + + Identifier of all SOP Instances that belong to the same concatenation. +Required if a group of multi-frame image SOP Instances within a Series are part of a Concatenation. + + + Identifier for one SOP Instance belonging to a concatenation. See C.7.6.16.2.2.4 for further specification. The first instance in a concatentation (that with the lowest Concatenation Frame Offset Number (0020,9228) value) shall have an In-concatenation Number (0020,9162) value of 1, and subsequent instances shall have values monotonically increasing by 1. +Required if Concatenation UID (0020,9161) is present. +
Due to implementation specific reasons (such as maximum object size) the information of a multi-frame image may be split into more than one SOP Instance. These SOP Instances form together a Concatenation. This is a group of SOP Instances within a Series that is uniquely identified by the Concatenation UID (0020,9161). +The Dimension Index Sequence (0020,9222) for each SOP Instance with the same Concatenation UID (0020,9161) shall contain exactly the same tags and values. +In a Concatenation the Dimension Index Sequence (0020,9222) items of the Shared Functional Groups (5200,9229) shall be identical and have the same values for all individual SOP Instances. The items of the Per-frame Functional Groups (5200,9230) shall be identical for all individual SOP Instances but the values may change per frame. For all other Attributes of all the Modules of the IOD, the same Attributes shall be present and the values shall be identical, with the exception of the following Attributes: +
+
+ + The number of SOP Instances sharing the same Concatenation UID. + +
+ + + Identifies the physical characteristics of the pixels of this frame. Only a single Item shall be permitted in this sequence. + + + Physical distance in the patient between the centers of each pixel, specified by a numeric pair - adjacent row spacing (delimiter) adjacent column spacing in mm. See 10.7.1.3 for further explanation of the value order. +Note: In the case of CT images with an Acquisition Type (0018,9302) of CONSTANT_ANGLE, the pixel spacing is that in a plane normal to the central ray of the diverging X-Ray beam as it passes through the data collection center. +Required if Volumetric Properties (0008,9206) is other than DISTORTED or SAMPLED. May be present otherwise. + + + Nominal reconstructed slice thickness, in mm. +See C.7.6.2.1.1 and C.7.6.16.2.3.1 for further explanation. +Required if Volumetric Properties (0008,9206) is VOLUME or SAMPLED. May be present otherwise. +
The Image Position (0020,0032) specifies the x, y, and z coordinates of the upper left hand corner of the image; it is the center of the first voxel transmitted. Image Orientation (0020,0037) specifies the direction cosines of the first row and the first column with respect to the patient. These Attributes shall be provide as a pair. Row value for the x, y, and z axes respectively followed by the Column value for the x, y, and z axes respectively. +The direction of the axes is defined fully by the patient’s orientation. The x-axis is increasing to the left hand side of the patient. The y-axis is increasing to the posterior side of the patient. The z-axis is increasing toward the head of the patient. +The patient based coordinate system is a right handed system, i.e. the vector cross product of a unit vector along the positive x-axis and a unit vector along the positive y-axis is equal to a unit vector along the positive z-axis. +Note If a patient lies parallel to the ground, face-up on the table, with his feet-to-head direction same as the front-to-back direction of the imaging equipment, the direction of the axes of this patient based coordinate system and the equipment based coordinate system in previous versions of this Standard will coincide. + +The Image Plane Attributes, in conjunction with the Pixel Spacing Attribute, describe the position and orientation of the image slices relative to the patient-based coordinate system. In each image frame the Image Position (Patient) (0020,0032) specifies the origin of the image with respect to the patient-based coordinate system. RCS and the Image Orientation (Patient) (0020,0037) attribute values specify the orientation of the image frame rows and columns. The mapping of pixel location to the RCS is calculated as follows: + + size 12{ left [ matrix { +P rSub { size 8{x} } {} ## +P rSub { size 8{y} } {} ## +P rSub { size 8{z} } {} ## +1 +} right ]= left [ matrix { +X rSub { size 8{x} } Δi {} # Y rSub { size 8{x} } Δj {} # 0 {} # S rSub { size 8{x} } {} ## +X rSub { size 8{y} } Δi {} # Y rSub { size 8{y} } Δj {} # 0 {} # S rSub { size 8{y} } {} ## +X rSub { size 8{z} } Δi {} # Y rSub { size 8{z} } Δj {} # 0 {} # S rSub { size 8{z} } {} ## +0 {} # 0 {} # 0 {} # 1{} +} right ] left [ matrix { +i {} ## +j {} ## +0 {} ## +1 +} right ]} {} + + = M +Where: +Pxyz The coordinates of the voxel (i,j) in the frame’s image plane in units of mm. +Sxyz The three values of the Image Position (Patient) (0020,0032) attributes. It is the location in mm from the origin of the RCS. +Xxyz The values from the row (X) direction cosine of the Image Orientation (Patient) (0020,0037) attribute. +Yxyz The values from the column (Y) direction cosine of the Image Orientation (Patient) (0020,0037) attribute. +i Column index to the image plane. The first column is index zero. +ï„i Column pixel resolution of the Pixel Spacing (0028,0030) attribute in units of mm. +j Row index to the image plane. The first row index is zero. +ï„j Row pixel resolution of the Pixel Spacing (0028,0030) attribute in units of mm. + +Additional constraints apply: +1) The row and column direction cosine vectors shall be orthogonal, i.e. their dot product shall be zero. +2) The row and column direction cosine vectors shall be normal, i.e. the dot product of each direction cosine vector with itself shall be unity. + +
+
+
+ + + Identifies general characteristics of this frame. Only a single Item shall be permitted in this sequence. + + + A number identifying the single continuous gathering of data over a period of time that resulted in this frame. + + + The point in time that is most representative of when data was acquired for this frame. See C.7.6.16.2.2.1 and C.7.6.16.2.2.2 for further explanation. +Note: The synchronization of this time with an external clock is specified in the synchronization Module in Acquisition Time synchronized (0018,1800). +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. +
Figure C.7.6.16-2 shows the relationships among the various timing parameters used. +
+
+ + The date and time that the acquisition of data that resulted in this frame started. See C.7.6.16.2.2.1 for further explanation. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. +
Figure C.7.6.16-2 shows the relationships among the various timing parameters used. +
+
+ + The actual amount of time [in milliseconds] that was used to acquire data for this frame. See C.7.6.16.2.2.1 and C.7.6.16.2.2.3 for further explanation. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. +
Figure C.7.6.16-2 shows the relationships among the various timing parameters used. +
+
+ + Description of the position in the cardiac cycle that is most representative of this frame. +Defined Terms: +END_SYSTOLE +END_DIASTOLE +UNDETERMINED + + + Description of the position in the respiratory cycle that is most representative of this frame. +Defined Terms: +START _RESPIR +END_RESPIR +UNDETERMINED + + + Contains the values of the indices defined in the Dimension Index Sequence (0020,9222) for this multi-frame header frame. The number of values is equal to the number of Items of the Dimension Index Sequence and shall be applied in the same order. +See section C.7.6.17.1 for a description. +Required if the value of the Dimension Index Sequence (0020,9222) contains Items. + + + Ordinal number (starting from 1) of the frame in the set of frames with different temporal positions. + + + Identification of a group of frames, with different positions and/or orientations that belong together, within a dimension organization. +See C.7.6.16.2.2.4 for further explanation +
Due to implementation specific reasons (such as maximum object size) the information of a multi-frame image may be split into more than one SOP Instance. These SOP Instances form together a Concatenation. This is a group of SOP Instances within a Series that is uniquely identified by the Concatenation UID (0020,9161). +The Dimension Index Sequence (0020,9222) for each SOP Instance with the same Concatenation UID (0020,9161) shall contain exactly the same tags and values. +In a Concatenation the Dimension Index Sequence (0020,9222) items of the Shared Functional Groups (5200,9229) shall be identical and have the same values for all individual SOP Instances. The items of the Per-frame Functional Groups (5200,9230) shall be identical for all individual SOP Instances but the values may change per frame. For all other Attributes of all the Modules of the IOD, the same Attributes shall be present and the values shall be identical, with the exception of the following Attributes: +
+
+ + The ordinal number of a frame in a group of frames, with the same Stack ID +Required if Stack ID (0020,9056) is present. +See section C.7.6.16.2.2.4 for further explanation. + + + User-defined comments about the frame. + + + Label corresponding to a specific dimension index value. Selected from a set of dimension values defined by the application. +This attribute may be referenced by the Dimension Index Pointer (0020,9165) attribute in the Multi-frame Dimension Module. +See C.7.6.16.2.2.5 for further explanation. +
The Frame Label attribute (0020,9453) can be used to label frames that need to be handled as a group in application. The Dimension Index Pointer (0020,9165) from the Dimension Module may point to this attribute if it is the base of a dimension. +
+
+
+ + + Identifies the position of the plane of this frame. Only a single Item shall be permitted in this sequence. + + + The x, y, and z coordinates of the upper left hand corner (center of the first voxel transmitted) of the frame, in mm. See C.7.6.2.1.1 and C.7.6.16.2.3.1 for further explanation. +Note: In the case of CT images with an Acquisition Type (0018,9302) of CONSTANT_ANGLE the image plane is defined to pass through the data collection center and be normal to the central ray of the diverging X-Ray beam. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL and Volumetric Properties (0008,9206) of this frame is other than DISTORTED, may be present otherwise. +
The Image Position (0020,0032) specifies the x, y, and z coordinates of the upper left hand corner of the image; it is the center of the first voxel transmitted. Image Orientation (0020,0037) specifies the direction cosines of the first row and the first column with respect to the patient. These Attributes shall be provide as a pair. Row value for the x, y, and z axes respectively followed by the Column value for the x, y, and z axes respectively. +The direction of the axes is defined fully by the patient’s orientation. The x-axis is increasing to the left hand side of the patient. The y-axis is increasing to the posterior side of the patient. The z-axis is increasing toward the head of the patient. +The patient based coordinate system is a right handed system, i.e. the vector cross product of a unit vector along the positive x-axis and a unit vector along the positive y-axis is equal to a unit vector along the positive z-axis. +Note If a patient lies parallel to the ground, face-up on the table, with his feet-to-head direction same as the front-to-back direction of the imaging equipment, the direction of the axes of this patient based coordinate system and the equipment based coordinate system in previous versions of this Standard will coincide. + +The Image Plane Attributes, in conjunction with the Pixel Spacing Attribute, describe the position and orientation of the image slices relative to the patient-based coordinate system. In each image frame the Image Position (Patient) (0020,0032) specifies the origin of the image with respect to the patient-based coordinate system. RCS and the Image Orientation (Patient) (0020,0037) attribute values specify the orientation of the image frame rows and columns. The mapping of pixel location to the RCS is calculated as follows: + + size 12{ left [ matrix { +P rSub { size 8{x} } {} ## +P rSub { size 8{y} } {} ## +P rSub { size 8{z} } {} ## +1 +} right ]= left [ matrix { +X rSub { size 8{x} } Δi {} # Y rSub { size 8{x} } Δj {} # 0 {} # S rSub { size 8{x} } {} ## +X rSub { size 8{y} } Δi {} # Y rSub { size 8{y} } Δj {} # 0 {} # S rSub { size 8{y} } {} ## +X rSub { size 8{z} } Δi {} # Y rSub { size 8{z} } Δj {} # 0 {} # S rSub { size 8{z} } {} ## +0 {} # 0 {} # 0 {} # 1{} +} right ] left [ matrix { +i {} ## +j {} ## +0 {} ## +1 +} right ]} {} + + = M +Where: +Pxyz The coordinates of the voxel (i,j) in the frame’s image plane in units of mm. +Sxyz The three values of the Image Position (Patient) (0020,0032) attributes. It is the location in mm from the origin of the RCS. +Xxyz The values from the row (X) direction cosine of the Image Orientation (Patient) (0020,0037) attribute. +Yxyz The values from the column (Y) direction cosine of the Image Orientation (Patient) (0020,0037) attribute. +i Column index to the image plane. The first column is index zero. +ï„i Column pixel resolution of the Pixel Spacing (0028,0030) attribute in units of mm. +j Row index to the image plane. The first row index is zero. +ï„j Row pixel resolution of the Pixel Spacing (0028,0030) attribute in units of mm. + +Additional constraints apply: +1) The row and column direction cosine vectors shall be orthogonal, i.e. their dot product shall be zero. +2) The row and column direction cosine vectors shall be normal, i.e. the dot product of each direction cosine vector with itself shall be unity. + +
+
+
+ + + Identifies orientation of the plane of this frame. Only a single Item shall be permitted in this sequence. + + + The direction cosines of the first row and the first column with respect to the patient. See C.7.6.2.1.1 and C.7.6.16.2.3.1 for further explanation. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL and Volumetric Properties (0008,9206) of this frame is other than DISTORTED. May be present otherwise. +
The Image Position (0020,0032) specifies the x, y, and z coordinates of the upper left hand corner of the image; it is the center of the first voxel transmitted. Image Orientation (0020,0037) specifies the direction cosines of the first row and the first column with respect to the patient. These Attributes shall be provide as a pair. Row value for the x, y, and z axes respectively followed by the Column value for the x, y, and z axes respectively. +The direction of the axes is defined fully by the patient’s orientation. The x-axis is increasing to the left hand side of the patient. The y-axis is increasing to the posterior side of the patient. The z-axis is increasing toward the head of the patient. +The patient based coordinate system is a right handed system, i.e. the vector cross product of a unit vector along the positive x-axis and a unit vector along the positive y-axis is equal to a unit vector along the positive z-axis. +Note If a patient lies parallel to the ground, face-up on the table, with his feet-to-head direction same as the front-to-back direction of the imaging equipment, the direction of the axes of this patient based coordinate system and the equipment based coordinate system in previous versions of this Standard will coincide. + +The Image Plane Attributes, in conjunction with the Pixel Spacing Attribute, describe the position and orientation of the image slices relative to the patient-based coordinate system. In each image frame the Image Position (Patient) (0020,0032) specifies the origin of the image with respect to the patient-based coordinate system. RCS and the Image Orientation (Patient) (0020,0037) attribute values specify the orientation of the image frame rows and columns. The mapping of pixel location to the RCS is calculated as follows: + + size 12{ left [ matrix { +P rSub { size 8{x} } {} ## +P rSub { size 8{y} } {} ## +P rSub { size 8{z} } {} ## +1 +} right ]= left [ matrix { +X rSub { size 8{x} } Δi {} # Y rSub { size 8{x} } Δj {} # 0 {} # S rSub { size 8{x} } {} ## +X rSub { size 8{y} } Δi {} # Y rSub { size 8{y} } Δj {} # 0 {} # S rSub { size 8{y} } {} ## +X rSub { size 8{z} } Δi {} # Y rSub { size 8{z} } Δj {} # 0 {} # S rSub { size 8{z} } {} ## +0 {} # 0 {} # 0 {} # 1{} +} right ] left [ matrix { +i {} ## +j {} ## +0 {} ## +1 +} right ]} {} + + = M +Where: +Pxyz The coordinates of the voxel (i,j) in the frame’s image plane in units of mm. +Sxyz The three values of the Image Position (Patient) (0020,0032) attributes. It is the location in mm from the origin of the RCS. +Xxyz The values from the row (X) direction cosine of the Image Orientation (Patient) (0020,0037) attribute. +Yxyz The values from the column (Y) direction cosine of the Image Orientation (Patient) (0020,0037) attribute. +i Column index to the image plane. The first column is index zero. +ï„i Column pixel resolution of the Pixel Spacing (0028,0030) attribute in units of mm. +j Row index to the image plane. The first row index is zero. +ï„j Row pixel resolution of the Pixel Spacing (0028,0030) attribute in units of mm. + +Additional constraints apply: +1) The row and column direction cosine vectors shall be orthogonal, i.e. their dot product shall be zero. +2) The row and column direction cosine vectors shall be normal, i.e. the dot product of each direction cosine vector with itself shall be unity. + +
+
+
+ + + A sequence that provides reference to a set of SOP Class/Instance pairs identifying images or other composite SOP Instances used to plan the acquisition or significant related images. See Section C.7.6.16.2.5.1 for further explanation. Zero or more Items may be included in this Sequence. +
Referenced Image Sequence (0008,1140) shall be used to provide a reference to a set of SOP Class/Instance pairs identifying other data objects used to plan the acquisition of this image where the images shall share the same Frame of Reference UID (0020,0052). For each Item that contains such a reference, the value of the Purpose of Reference Code Sequence (0040,A170) shall be (â€121311â€, DCM, â€Localizer"). Applications can use the Referenced Image Sequence (0008,1140) in combination with data in Plane Position and Plane Orientation Macros to provide projections of the position of an image with respect to the referenced image. +The Referenced Image Sequence (0008,1140) may also be present when references to other images (or frames within other images) are required for other reasons, as specified by Purpose of Reference Code Sequence (0040,A170). +Note: An Image may contain references to itself (e.g. to other frames within itself). + +
+
+ + + Describes the purpose for which the reference is made. Only a single Item shall be permitted in this sequence. +See C.7.6.16.2.5.1 for further explanation. +
Referenced Image Sequence (0008,1140) shall be used to provide a reference to a set of SOP Class/Instance pairs identifying other data objects used to plan the acquisition of this image where the images shall share the same Frame of Reference UID (0020,0052). For each Item that contains such a reference, the value of the Purpose of Reference Code Sequence (0040,A170) shall be (â€121311â€, DCM, â€Localizer"). Applications can use the Referenced Image Sequence (0008,1140) in combination with data in Plane Position and Plane Orientation Macros to provide projections of the position of an image with respect to the referenced image. +The Referenced Image Sequence (0008,1140) may also be present when references to other images (or frames within other images) are required for other reasons, as specified by Purpose of Reference Code Sequence (0040,A170). +Note: An Image may contain references to itself (e.g. to other frames within itself). + +
+
+ +
+ + + A sequence that that provides reference to the set of SOP Class/Instance pairs of the Images or other composite SOP Instances which were used to derive this frame. Zero or more Items may be included in this Sequence. + + + A text description of how this frame data was derived. See C.7.6.1.1.3 for further explanation. +
If an Image is identified to be a derived image (see C.7.6.1.1.2 Image Type), Derivation Description (0008,2111) and Derivation Code Sequence (0008,9215) describe the way in which the image was derived. They may be used whether or not the Source Image Sequence (0008,2112) is provided. They may also be used in cases when the Derived Image pixel data is not significantly changed from one of the source images and the SOP Instance UID of the Derived Image is the same as the one used for the source image. +Notes: 1. Examples of Derived Images that would normally be expected to affect professional interpretation and would thus have a new UID include: + a. images resulting from image processing of another image (e.g. unsharp masking), + b. a multiplanar reformatted CT image, + c. a DSA image derived by subtracting pixel values of one image from another. +d. an image that has been decompressed after having been compressed with a lossy compression algorithm. To ensure that the user has the necessary information about the lossy compression, the approximate compression ratio may be included in Derivation Description (0008,2111). + An example of a Derived Image that would normally not be expected to affect professional interpretation and thus would not require a new UID is an image that has been padded with additional rows and columns for more display purposes. + 2. An image may be lossy compressed, e.g., for long term archive purposes, and its SOP Instance UID changed. PS3.4 provides a mechanism by which a query for the original image Instance may return a reference to the UID of the lossy compressed version of the image using the Alternate Representation Sequence (0008,3001). This allows an application processing a SOP Instance that references the original image UID, e.g., a Structured Report, to obtain a reference to an accessible version of the image even if the original SOP Instance is no longer available. + +
+
+ + A coded description of how this frame was derived. See C.7.6.1.1.3 for further explanation. One or more Items may be included in this Sequence. More than one Item indicates that successive derivation steps have been applied. +
If an Image is identified to be a derived image (see C.7.6.1.1.2 Image Type), Derivation Description (0008,2111) and Derivation Code Sequence (0008,9215) describe the way in which the image was derived. They may be used whether or not the Source Image Sequence (0008,2112) is provided. They may also be used in cases when the Derived Image pixel data is not significantly changed from one of the source images and the SOP Instance UID of the Derived Image is the same as the one used for the source image. +Notes: 1. Examples of Derived Images that would normally be expected to affect professional interpretation and would thus have a new UID include: + a. images resulting from image processing of another image (e.g. unsharp masking), + b. a multiplanar reformatted CT image, + c. a DSA image derived by subtracting pixel values of one image from another. +d. an image that has been decompressed after having been compressed with a lossy compression algorithm. To ensure that the user has the necessary information about the lossy compression, the approximate compression ratio may be included in Derivation Description (0008,2111). + An example of a Derived Image that would normally not be expected to affect professional interpretation and thus would not require a new UID is an image that has been padded with additional rows and columns for more display purposes. + 2. An image may be lossy compressed, e.g., for long term archive purposes, and its SOP Instance UID changed. PS3.4 provides a mechanism by which a query for the original image Instance may return a reference to the UID of the lossy compressed version of the image using the Alternate Representation Sequence (0008,3001). This allows an application processing a SOP Instance that references the original image UID, e.g., a Structured Report, to obtain a reference to an accessible version of the image even if the original SOP Instance is no longer available. + +
+
+ + + A Sequence which identifies the set of Image or other SOP Class/Instance pairs of the Instances which were used to derive this frame. Zero or more Items may be included in this Sequence. See C.7.6.1.1.4 for further explanation. +
If an Image is identified to be a Derived image (see C.7.6.1.1.2 Image Type), Source Image Sequence (0008,2112) is an optional list of Referenced SOP Class UID (0008,1150)/ Referenced SOP Instance UID (0008,1150) pairs that identify the source images used to create the Derived image. It may be used whether or not there is a description of the way the image was derived in Derivation Description (0008,2111) or Derivation Code Sequence (0008,9215). +Note: Multiple Items may be present within Source Image Sequence (0008,2112), in which case either: + a) those images were combined to make the derived image (e.g. multiple source images to make an MPR or MIP), or + b) each of the items represents a step in the successive derivation of an image (e.g. when an image has had successive lossy compression steps applied to it), + c) some combination of the above. + The Purpose of Reference Code Sequence (0040,A170) and the Attributes within the referenced images themselves may be used to determine the history of the derivation, which is not otherwise explicitly specified. + +
+
+ + + Describes the purpose for which the reference is made, that is what role the source image or frame played in the derivation of this image or frame. Only a single Item shall be permitted in this sequence. + + +
+ + + Sequence that describes the frame specific cardiac synchronization parameters. +Only a single Item shall be permitted in this sequence. + + + The nominal time relative to the preceding R peak divided by the nominal R-R interval multiplied by 100. +Required if used as a dimension index, may be present otherwise. + + + The nominal time in ms from the time of the previous R-peak to the value of the Frame Reference DateTime (0018,9151). See C.7.6.16.2.7.1 for further explanation. +
The Nominal Cardiac Trigger Delay Time (0020,9153) is the nominal trigger delay time in ms from the previous R-peak to the value of the Frame Reference DateTime (0018,9151). When frames are acquired with prospective gating, that is, the data acquisition actually begins in response to a timed delay from the R-peak, it may be that Actual Cardiac Trigger Delay Time (0020,9252) and the Nominal Cardiac Trigger Delay Time (0020,9153) have the same value. +However, when frames are the result of retrospective gating, that is, the data is continuously acquired and then later compared with a simultaneously acquired ECG waveform and fitted into time slots corresponding to nominal phases of the cardiac cycle, then Nominal Cardiac Trigger Delay Time (0020,9153) and the Actual Cardiac Trigger Delay Time (0020,9252) may have different values. +When multiple cardiac cycles are averaged together, then the Low R-R Value (0018,1081), and High R-R Value (0018,1082) are an average of the cardiac cycles that were accepted in the frame. +Note: For cardiac gated acquisitions the choice of the Frame Reference DateTime (0018,9151) is influenced by the Nominal Cardiac Trigger Delay Time (0020,9153). For respiratory gated acquisitions the choice of the Frame Reference DateTime (0018,9151) is influenced by the Nominal Respiratory Trigger Delay Time (0020,9255). +Figure C.7.6.16-5 depicts the usage. +
+
+ + The actual time in ms from the time of the previous R-peak to the value of the Frame Reference DateTime (0018,9151). See C.7.6.16.2.7.1 for further explanation. +Required if Intervals Acquired (0018,1083) is present and has a value of 1. May be present otherwise. +
The Nominal Cardiac Trigger Delay Time (0020,9153) is the nominal trigger delay time in ms from the previous R-peak to the value of the Frame Reference DateTime (0018,9151). When frames are acquired with prospective gating, that is, the data acquisition actually begins in response to a timed delay from the R-peak, it may be that Actual Cardiac Trigger Delay Time (0020,9252) and the Nominal Cardiac Trigger Delay Time (0020,9153) have the same value. +However, when frames are the result of retrospective gating, that is, the data is continuously acquired and then later compared with a simultaneously acquired ECG waveform and fitted into time slots corresponding to nominal phases of the cardiac cycle, then Nominal Cardiac Trigger Delay Time (0020,9153) and the Actual Cardiac Trigger Delay Time (0020,9252) may have different values. +When multiple cardiac cycles are averaged together, then the Low R-R Value (0018,1081), and High R-R Value (0018,1082) are an average of the cardiac cycles that were accepted in the frame. +Note: For cardiac gated acquisitions the choice of the Frame Reference DateTime (0018,9151) is influenced by the Nominal Cardiac Trigger Delay Time (0020,9153). For respiratory gated acquisitions the choice of the Frame Reference DateTime (0018,9151) is influenced by the Nominal Respiratory Trigger Delay Time (0020,9255). +Figure C.7.6.16-5 depicts the usage. +
+
+ + Number of R-R intervals acquired. + + + Number of R-R intervals rejected. + + + Average number of heart beats per minute for the collection period for this frame. This shall include all accepted beats as well as rejected beats. +Note: During prolonged acquisitions the average heart rate may differ from the reciprocal of the nominal R-R interval. + + + Nominal R-peak - R-peak interval time in ms for the cardiac cycle used for the acquisition of this frame. See C.7.6.16.2.7.1 for further explanation. +Required if Cardiac Synchronization Technique (0018,9037) equals other than NONE or REALTIME. May be present otherwise. +
The Nominal Cardiac Trigger Delay Time (0020,9153) is the nominal trigger delay time in ms from the previous R-peak to the value of the Frame Reference DateTime (0018,9151). When frames are acquired with prospective gating, that is, the data acquisition actually begins in response to a timed delay from the R-peak, it may be that Actual Cardiac Trigger Delay Time (0020,9252) and the Nominal Cardiac Trigger Delay Time (0020,9153) have the same value. +However, when frames are the result of retrospective gating, that is, the data is continuously acquired and then later compared with a simultaneously acquired ECG waveform and fitted into time slots corresponding to nominal phases of the cardiac cycle, then Nominal Cardiac Trigger Delay Time (0020,9153) and the Actual Cardiac Trigger Delay Time (0020,9252) may have different values. +When multiple cardiac cycles are averaged together, then the Low R-R Value (0018,1081), and High R-R Value (0018,1082) are an average of the cardiac cycles that were accepted in the frame. +Note: For cardiac gated acquisitions the choice of the Frame Reference DateTime (0018,9151) is influenced by the Nominal Cardiac Trigger Delay Time (0020,9153). For respiratory gated acquisitions the choice of the Frame Reference DateTime (0018,9151) is influenced by the Nominal Respiratory Trigger Delay Time (0020,9255). +Figure C.7.6.16-5 depicts the usage. +
+
+ + R-R interval low limit for beat rejection, in ms. + + + R-R interval high limit for beat rejection, in ms. + +
+ + + Identifies anatomic characteristics of this frame. Only a single Item shall be permitted in this sequence. + + + Laterality of (possibly paired) body parts (as described in Anatomic Region Sequence (0008,2218)) examined. +Enumerated Values: +R = right +L = left +U = unpaired +B = both left and right +Note: This Attribute is mandatory, in order to ensure that frames may be positioned correctly relative to one another for display. +Shall be consistent with any laterality information contained in Primary Anatomic Structure Modifier Sequence (0008,2230), if present. + + + + + + Contains the attributes involved in the transformation of stored pixel values. Only a single Item shall be permitted in this sequence. + + + The value b in relationship between stored values (SV) and the output units. +Output units = m*SV + b. + + + m in the equation specified by Rescale Intercept (0028,1052). + + + Specifies the output units of Rescale Slope (0028,1053) and Rescale Intercept (0028,1052). +See C.11.1.1.2 for further explanation. +Enumerated Value: +US = Unspecified if Modality (0008,0060) equals MR. +
Specifies the units of the output of the Modality LUT or rescale operation. +Defined Terms: + OD = The number in the LUT represents thousands of optical density. That is, a value of 2140 represents an optical density of 2.140. + HU = Hounsfield Units (CT) + US = Unspecified +Other values are permitted, but are not defined by the DICOM Standard. +
+
+
+ + + Window Center and Width values applied to the frame. Only one item is permitted in this sequence. + + + Window Center for display. See C.11.2.1.2 for further explanation. +
Window Center (0028,1050) and Window Width (0028,1051) specify a linear conversion from stored pixel values (after any Modality LUT or Rescale Slope and Intercept specified in the IOD have been applied) to values to be displayed. Window Center contains the input value that is the center of the window. Window Width contains the width of the window. +Note: The terms “window center†and “window width†are not consistently used in practice, nor were they defined in previous versions of the standard. The definitions here are presented for the purpose of defining consistent meanings for identity and threshold transformations while preserving the common practice of using integral values for center and width. + +Window Width (0028,1051) shall always be greater than or equal to 1. +When Window Width (0028,1051) is greater than 1, these Attributes select the range of input values that are to be mapped to the full range of the displayed output. +When Window Width (0028,1051) is equal to 1, they specify a threshold below which input values will be displayed as the minimum output value. +Note: Whether the minimum output value is rendered as black or white may depend on the value of Photometric Interpretation (0028,0004) or the presence of a Presentation LUT Module. + +These Attributes are applied according to the following pseudo-code, where x is the input value, y is an output value with a range from ymin to ymax, c is Window Center (0028,1050) and w is Window Width (0028,1051): + if (x <= c - 0.5 - (w-1)/2), then y = ymin + else if (x > c - 0.5 + (w-1)/2), then y = ymax, + else y = ((x - (c - 0.5)) / (w-1) + 0.5) * (ymax - ymin)+ ymin + +Notes: 1. For the purpose of this definition, a floating point calculation without integer truncation is assumed, though the manner of implementation may vary as long as the result is the same. + 2. The pseudo-code function computes a continuous value over the output range without any discontinuity at the boundaries. The value of 0 for w is expressly forbidden, and the value of 1 for w does not cause division by zero, since the continuous segment of the function will never be reached for that case. + 3. For example, for an output range 0 to 255: + c=2048, w=4096 becomes: + if (x <= 0) then y = 0 + else if (x > 4095) then y = 255 + else y = ((x - 2047.5) / 4095 + 0.5) * (255-0) + 0 + c=2048, w=1 becomes: + if (x <= 2047.5) then y = 0 + else if (x > 2047.5) then y = 255 + else /* not reached */ + + c=0, w=100 becomes: + if (x <= -50) then y = 0 + else if (x > 49) then y = 255 + else y = ((x + 0.5) / 99 + 0.5) * (255-0) + 0 + c=0, w=1 becomes: + if (x <= -0.5) then y = 0 + else if (x > -0.5) then y = 255 + else /* not reached */ + + 4. A Window Center of 2n-1 and a Window Width of 2n selects the range of input values from 0 to 2n-1. This represents an identity VOI LUT transformation in the case where no Modality LUT is specified and the stored pixel data are n bit unsigned integers. + 5. A Window Width of 1 is typically used to represent a "threshold" operation in which those integer input values less than the Window Center are represented as the minimum displayed value and those greater than or equal to the Window Center are represented as the maximum displayed value. A Window Width of 2 will have the same result for integral input values. + 6. The application of Window Center (0028,1050) and Window Width (0028,1051) may select a signed input range. There is no implication that this signed input range is clipped to zero. + 7. The selected input range may exceed the actual range of the input values, thus effectively “compressing†the contrast range of the displayed data into a narrower band of the available contrast range, and “flattening†the appearance. There are no limits to the maximum value of the window width, or to the minimum or maximum value of window level, both of which may exceed the actual or possible range of input values. + 8. Input values "below" the window are displayed as the minimum output value and input values "above" the window are displayed as the maximum output value. This is the common usage of the window operation in medical imaging. There is no provision for an alternative approach in which all values "outside" the window are displayed as the minimum output value. + 9. The output of the Window Center/Width or VOI LUT transformation is either implicitly scaled to the full range of the display device if there is no succeeding transformation defined, or implicitly scaled to the full input range of the succeeding transformation step (such as the Presentation LUT), if present. See C.11.6.1. + 10. Fractional values of Window Center and Window Width are permitted (since the VR of these Attributes is Decimal String), and though they are not often encountered, applications should be prepared to accept them. + +These Attributes shall be used only for Images with Photometric Interpretation (0028,0004) values of MONOCHROME1 and MONOCHROME2. They have no meaning for other Images. +If multiple values are present, both Attributes shall have the same number of values and shall be considered as pairs. Multiple values indicate that multiple alternative views may be presented. +If any VOI LUT Table is included by an Image, a Window Width and Window Center or the VOI LUT Table, but not both, may be applied to the Image for display. Inclusion of both indicates that multiple alternative views may be presented. +If multiple items are present in VOI LUT Sequence (0028,3010), only one may be applied to the Image for display. Multiple items indicate that multiple alternative views may be presented. +If the VOI LUT Module is defined in an IOD and if neither a VOI LUT Sequence nor a Window Width and Window Center are present, then the VOI LUT stage of the grayscale pipeline is defined to be an identity transformation. +Notes: 1. This requirement is specified so that IODs that define a particular output space for the grayscale pipeline, such as P-Values, are not in an undefined state when no VOI LUT Sequence or Window Width and Window Center are present. + 2. Despite the Type 3 requirement for VOI LUT Sequence and Window Center, implementations that render images are expected to implement and apply these transformations when they are present in the image, unless overridden by the user, a presentation state, or a hanging protocol, and to allow the user to select which transformation to apply when multiple transformations are present. + +
+
+ + Window Width for display. See C.11.2.1.2 for further explanation. +
Window Center (0028,1050) and Window Width (0028,1051) specify a linear conversion from stored pixel values (after any Modality LUT or Rescale Slope and Intercept specified in the IOD have been applied) to values to be displayed. Window Center contains the input value that is the center of the window. Window Width contains the width of the window. +Note: The terms “window center†and “window width†are not consistently used in practice, nor were they defined in previous versions of the standard. The definitions here are presented for the purpose of defining consistent meanings for identity and threshold transformations while preserving the common practice of using integral values for center and width. + +Window Width (0028,1051) shall always be greater than or equal to 1. +When Window Width (0028,1051) is greater than 1, these Attributes select the range of input values that are to be mapped to the full range of the displayed output. +When Window Width (0028,1051) is equal to 1, they specify a threshold below which input values will be displayed as the minimum output value. +Note: Whether the minimum output value is rendered as black or white may depend on the value of Photometric Interpretation (0028,0004) or the presence of a Presentation LUT Module. + +These Attributes are applied according to the following pseudo-code, where x is the input value, y is an output value with a range from ymin to ymax, c is Window Center (0028,1050) and w is Window Width (0028,1051): + if (x <= c - 0.5 - (w-1)/2), then y = ymin + else if (x > c - 0.5 + (w-1)/2), then y = ymax, + else y = ((x - (c - 0.5)) / (w-1) + 0.5) * (ymax - ymin)+ ymin + +Notes: 1. For the purpose of this definition, a floating point calculation without integer truncation is assumed, though the manner of implementation may vary as long as the result is the same. + 2. The pseudo-code function computes a continuous value over the output range without any discontinuity at the boundaries. The value of 0 for w is expressly forbidden, and the value of 1 for w does not cause division by zero, since the continuous segment of the function will never be reached for that case. + 3. For example, for an output range 0 to 255: + c=2048, w=4096 becomes: + if (x <= 0) then y = 0 + else if (x > 4095) then y = 255 + else y = ((x - 2047.5) / 4095 + 0.5) * (255-0) + 0 + c=2048, w=1 becomes: + if (x <= 2047.5) then y = 0 + else if (x > 2047.5) then y = 255 + else /* not reached */ + + c=0, w=100 becomes: + if (x <= -50) then y = 0 + else if (x > 49) then y = 255 + else y = ((x + 0.5) / 99 + 0.5) * (255-0) + 0 + c=0, w=1 becomes: + if (x <= -0.5) then y = 0 + else if (x > -0.5) then y = 255 + else /* not reached */ + + 4. A Window Center of 2n-1 and a Window Width of 2n selects the range of input values from 0 to 2n-1. This represents an identity VOI LUT transformation in the case where no Modality LUT is specified and the stored pixel data are n bit unsigned integers. + 5. A Window Width of 1 is typically used to represent a "threshold" operation in which those integer input values less than the Window Center are represented as the minimum displayed value and those greater than or equal to the Window Center are represented as the maximum displayed value. A Window Width of 2 will have the same result for integral input values. + 6. The application of Window Center (0028,1050) and Window Width (0028,1051) may select a signed input range. There is no implication that this signed input range is clipped to zero. + 7. The selected input range may exceed the actual range of the input values, thus effectively “compressing†the contrast range of the displayed data into a narrower band of the available contrast range, and “flattening†the appearance. There are no limits to the maximum value of the window width, or to the minimum or maximum value of window level, both of which may exceed the actual or possible range of input values. + 8. Input values "below" the window are displayed as the minimum output value and input values "above" the window are displayed as the maximum output value. This is the common usage of the window operation in medical imaging. There is no provision for an alternative approach in which all values "outside" the window are displayed as the minimum output value. + 9. The output of the Window Center/Width or VOI LUT transformation is either implicitly scaled to the full range of the display device if there is no succeeding transformation defined, or implicitly scaled to the full input range of the succeeding transformation step (such as the Presentation LUT), if present. See C.11.6.1. + 10. Fractional values of Window Center and Window Width are permitted (since the VR of these Attributes is Decimal String), and though they are not often encountered, applications should be prepared to accept them. + +These Attributes shall be used only for Images with Photometric Interpretation (0028,0004) values of MONOCHROME1 and MONOCHROME2. They have no meaning for other Images. +If multiple values are present, both Attributes shall have the same number of values and shall be considered as pairs. Multiple values indicate that multiple alternative views may be presented. +If any VOI LUT Table is included by an Image, a Window Width and Window Center or the VOI LUT Table, but not both, may be applied to the Image for display. Inclusion of both indicates that multiple alternative views may be presented. +If multiple items are present in VOI LUT Sequence (0028,3010), only one may be applied to the Image for display. Multiple items indicate that multiple alternative views may be presented. +If the VOI LUT Module is defined in an IOD and if neither a VOI LUT Sequence nor a Window Width and Window Center are present, then the VOI LUT stage of the grayscale pipeline is defined to be an identity transformation. +Notes: 1. This requirement is specified so that IODs that define a particular output space for the grayscale pipeline, such as P-Values, are not in an undefined state when no VOI LUT Sequence or Window Width and Window Center are present. + 2. Despite the Type 3 requirement for VOI LUT Sequence and Window Center, implementations that render images are expected to implement and apply these transformations when they are present in the image, unless overridden by the user, a presentation state, or a hanging protocol, and to allow the user to select which transformation to apply when multiple transformations are present. + +
+
+ + Explanation of the Window Center and Width. +Defined Terms for CT: +BRAIN +SOFT_TISSUE +LUNG +BONE + + + Describes a VOI LUT function to apply to the values of Window Center (0028,1050) and Window Width (0028,1051). +See C.11.2.1.3 for further explanation. +Defined terms: +LINEAR +SIGMOID +When this attribute is not present, the interpretation of the values of Window Center (0028,1050) and Window Width (0028,1051) is linear as in C.11.2.1.2. +
The VOI LUT Function (0028,1056) specifies a potentially non-linear conversion for the output of the (conceptual) Modality LUT values to the input of the (conceptual) Presentation LUT. +The behavior for the value LINEAR is defined in C.11.2.1.2. For all other values, the VOI LUT Function (0028,1056) shall include a unique descriptor of the LUT function to be used. Each descriptor is associated with a bivariate function of Window Center (0028,1050) and Window Width (0028,1051). +If the VOI LUT Function (0028,1056) is present with a value other than LINEAR, the values provided in Window Center (0028,1050) and Window Width (0028,1051) shall not be interpreted as a linear conversion of the (conceptual) Modality LUT values to the input to the (conceptual) Presentation LUT – but as parameters for the function defined by the VOI LUT Function descriptor in (0028,1056). +When defined, each descriptor must provide the functional relationship between the output of the (conceptual) Modality LUT values to the input of the (conceptual) Presentation LUT. +
+
+
+ + + The mapping of stored values to associated real world values. One or more Items may be included in this sequence. + + + Specifies the first stored value mapped for the Real Word Value Intercept (0040,9224) and Real World Value Slope (0040,9225) or Real World Value LUT (0040,9212) of this Item. +See C.7.6.16.2.11.1 for further explanation. +
+ + + Specifies the last stored value mapped for the Real Word Value Intercept (0040,9224) and Real World Value Slope (0040,9225) or Real World Value LUT (0040,9212) of this Item. +See C.7.6.16.2.11.1 for further explanation. +
+ + + The Intercept value in relationship between stored values (SV) and the real world values. +See section C.7.6.16.2.11.2 for further explanation. +Required if Real World Value LUT Data (0040,9212) is not present. + + + The Slope value in relationship between stored values (SV) and the real world values. +See section C.7.6.16.2.11.2 for further explanation. +Required if Real World Value LUT Data (0040,9212) is not present. + + + LUT Data in this Sequence. +Required if Real World Value Intercept (0040,9224) is not present. + + + Free form text explanation of the meaning of the LUT. + + + Label that is used to identify this transformation. + + + Units of measurement. Only a single value shall be present. See C.7.6.16.2.11.1 for further explanation. +
+ + + + + + Contains the attributes describing the use of contrast for this frame. One or more Items shall be present in this sequence. + + + Identifying number corresponding to the agent described in the Enhanced Contrast/Bolus Module. The number shall be 1 for the first Item and increase by 1 for each subsequent Item. + + + The administration of the selected agent had begun by the time this frame was acquired. +Enumerated Values: +YES +NO + + + The selected agent was detected in the frame. +Enumerated Values: +YES +NO +May only be zero length if the acquisition device is not capable of detecting the presence of this contrast agent in the frame. + + + Nominal phase of intravenous contrast administration. +Defined terms: +PRE_CONTRAST +POST_CONTRAST +IMMEDIATE +DYNAMIC +STEADY_STATE +DELAYED +ARTERIAL +CAPILLARY +VENOUS +PORTAL_VENOUS +Required if Contrast/Bolus Administration Route Sequence (0018,0014) for the Contrast/Bolus Agent Number (0018,9337) defined in the Contrast/Bolus Agent Sequence (0018,0012) is (G-D101, SRT, "Intravenous route") or (G-D101, SNM3, "Intravenous route"); may be present otherwise. +Note: SRT is the preferred designator for SNOMED, but SNM3 is allowed for backward compatibility. See PS3.16. + + + + + Defines a sequence of Pixel Intensity Relationship LUTs. +One or more items shall be present in this sequence. +At least one item with LUT Function (0028,9474) equals TO_LINEAR LUT shall be present if Pixel Intensity Relationship (0028,1040) equals LOG. +Only a single item with LUT Function (0028,9474) equals TO_LINEAR LUT shall be present. + + + Specifies the format of the LUT Data in this Sequence. +See C.11.1.1 and C.7.6.16.2.13.1 for further explanation. +
+ + + LUT Data in this Sequence. + + + The transformation function this LUT applies to the stored pixel values. +Defined Terms: +TO_LOG +TO_LINEAR + + + + + Sequence containing the pixel shift for a number of masks for this frame. +One or more items shall be present in this sequence. + + + Identifier of the Subtraction Item in the Mask Subtraction Sequence (0028,6100) to which this pixel shift is associated. +See C.7.6.16.2.14.1. +
Subtraction Item ID (0028,9416) specifies the ID of a subtraction operation to which the Mask Sub-pixel Shift (0028,6114) is associated. The Subtraction Item ID is also present in the Mask Subtraction Sequence (0028,6100) to allow this association. +When used as per-frame macro, the Subtraction Item ID (0028,9416) allows to specify different values of Mask Sub-pixel Shift (0028,6114) individually frame by frame, and relate them to a single item of the Mask Subtraction Sequence (0028,6100). +Note: There is no restriction in the number of Subtraction Item ID’s associated to each contrast frame. The same contrast frame may be present in several items of the Mask Subtraction Sequence, each item having a different value of Subtraction Item ID. + +When used as shared macro, the Subtraction Item ID (0028,9416) allows to specify one or more values of Mask Sub-pixel Shift that will be applied to all the frames of the Multi-frame image. +Note: Example of usage of Subtraction Item ID in a per-frame macro, see Figure C.7.6.16-8: + In this example of Multi-Frame Image with 3 frames, one Mask Frame (i.e., Frame 1) is applied to the next two frames of the Multi-Frame image (i.e., Frames 2 and 3). Therefore, there is only one item in the Mask Subtraction Sequence, containing its own Subtraction Item ID value (i.e., 100). The Frame Pixel Shift Macro allows to define a Mask Sub-Pixel Shift different for each contrast frame. + First Frame Subtracted: Subtraction of Frame 1 (Mask) to Frame 2, with Sub-Pixel Shift 1.3\2.4 + Second Frame Subtracted: Subtraction of Frame 1 (Mask) to Frame 3, with Sub-Pixel Shift 1.9\3.0 + +Figure C.7.6.16-8 +Example of usage of Subtraction Item ID in a per-frame Macro + +
+
+ + A pair of floating point numbers specifying the fractional vertical [adjacent row spacing] and horizontal [adjacent column spacing] pixel shift applied to the mask before subtracting it from this contrast frame. +Note: If no pixel shift has to be applied a pair of zero values should be specified. +See Section C.7.6.10.1.2. +
A pair of floating point numbers specifying the fractional vertical [adjacent row spacing] and horizontal [adjacent column spacing] pixel shift applied to the mask before subtracting it from the contrast frame. The row offset results in a shift of the pixels along the column axis. The column offset results in a shift of the pixels along the row axis. A positive row offset is a shift toward the pixels of the lower row of the pixel plane. A positive column offset is a shift toward the pixels of the left hand side column of the pixel plane. +
+
+
+ + + Sequence containing the row and column directions for this frame in the patient. +Only a single Item shall be permitted in this sequence. + + + Patient direction of the rows and columns of this frame. +See C.7.6.1.1.1 for further explanation. +
The Patient Orientation (0020,0020) relative to the image plane shall be specified by two values that designate the anatomical direction of the positive row axis (left to right) and the positive column axis (top to bottom). The first entry is the direction of the rows, given by the direction of the last pixel in the first row from the first pixel in that row. The second entry is the direction of the columns, given by the direction of the last pixel in the first column from the first pixel in that column. +Anatomical direction shall be designated by the capital letters: A (anterior), P (posterior), R (right), L (left), H (head), F (foot). Each value of the orientation attribute shall contain at least one of these characters. If refinements in the orientation descriptions are to be specified, then they shall be designated by one or two additional letters in each value. Within each value, the letters shall be ordered with the principal orientation designated in the first character. +
+
+
+ + + Sequence containing the display shutter parameters for this frame. +Only a single Item shall be permitted in this sequence. + + + + + + Sequence that describes the frame specific respiratory synchronization parameters. +Only a single Item shall be permitted in this sequence. + + + Measured interval time in ms from maximum respiration peak to the next peak for the respiratory cycle in which this frame occurs. See C.7.6.16.2.17.1 for further explanation. +Required if Respiratory Motion Compensation Technique (0018,9170) equals other than NONE or REALTIME and Respiratory Trigger Type (0020,9250) is absent or has a value of TIME or BOTH. +
For time based respiratory gating, the Nominal Respiratory Trigger Delay Time (0020,9255) is the prescribed trigger delay time in ms from the previous Respiratory-peak to the value of the Frame Reference DateTime (0018,9151). When frames are acquired with prospective gating, that is, the data acquisition actually begins in response to a timed delay from the Respiratory trigger, it may be that Actual Respiratory Trigger Delay Time (0020,9257) and the Nominal Respiratory Trigger Delay Time (0020,9255) have the same value. +However, when frames are the result of retrospective gating, that is, the data is continuously acquired and then later compared with a simultaneously acquired respiratory waveform and fitted into bins corresponding to nominal phases of the respiratory cycle, then Nominal Respiratory Trigger Delay Time (0020,9255) and the Actual Respiratory Trigger Delay Time (0020,9257) may have different values. +Figure C.7.6.16-9a and C.7.6.16-9b depict the usage. + + +Figure C.7.6.16-9a +Respiratory Timing Tags + + +Figure C.7.6.16-9b +Relationship of Respiratory Amplitude Attributes + +
+
+ + The nominal time relative to the preceding respiratory inspiration maximum divided by the nominal respiratory interval multiplied by 100. +Required if used as a dimension index, may be present otherwise. + + + The nominal time in ms from the beginning of the respiratory interval to the value of the Frame Reference DateTime (0018,9151). See C.7.6.16.2.17.1 for further explanation. +
For time based respiratory gating, the Nominal Respiratory Trigger Delay Time (0020,9255) is the prescribed trigger delay time in ms from the previous Respiratory-peak to the value of the Frame Reference DateTime (0018,9151). When frames are acquired with prospective gating, that is, the data acquisition actually begins in response to a timed delay from the Respiratory trigger, it may be that Actual Respiratory Trigger Delay Time (0020,9257) and the Nominal Respiratory Trigger Delay Time (0020,9255) have the same value. +However, when frames are the result of retrospective gating, that is, the data is continuously acquired and then later compared with a simultaneously acquired respiratory waveform and fitted into bins corresponding to nominal phases of the respiratory cycle, then Nominal Respiratory Trigger Delay Time (0020,9255) and the Actual Respiratory Trigger Delay Time (0020,9257) may have different values. +Figure C.7.6.16-9a and C.7.6.16-9b depict the usage. + + +Figure C.7.6.16-9a +Respiratory Timing Tags + + +Figure C.7.6.16-9b +Relationship of Respiratory Amplitude Attributes + +
+
+ + The actual time in ms from the beginning of the respiratory interval to the value of the Frame Reference DateTime (0018,9151). See C.7.6.16.2.17.1 for further explanation. +Required if Respiratory Trigger Type (0020,9250) is TIME or BOTH. +
For time based respiratory gating, the Nominal Respiratory Trigger Delay Time (0020,9255) is the prescribed trigger delay time in ms from the previous Respiratory-peak to the value of the Frame Reference DateTime (0018,9151). When frames are acquired with prospective gating, that is, the data acquisition actually begins in response to a timed delay from the Respiratory trigger, it may be that Actual Respiratory Trigger Delay Time (0020,9257) and the Nominal Respiratory Trigger Delay Time (0020,9255) have the same value. +However, when frames are the result of retrospective gating, that is, the data is continuously acquired and then later compared with a simultaneously acquired respiratory waveform and fitted into bins corresponding to nominal phases of the respiratory cycle, then Nominal Respiratory Trigger Delay Time (0020,9255) and the Actual Respiratory Trigger Delay Time (0020,9257) may have different values. +Figure C.7.6.16-9a and C.7.6.16-9b depict the usage. + + +Figure C.7.6.16-9a +Respiratory Timing Tags + + +Figure C.7.6.16-9b +Relationship of Respiratory Amplitude Attributes + +
+
+ + Nominal amplitude of the respiratory signal at which the acquisition of data for this frame begins, in percent of the nominal maximum value (which represents maximum inspiration). +Required if Respiratory Trigger Type (0020,9250) is AMPLITUDE or BOTH. + + + The phase of respiration at which the Starting Respiratory Amplitude (0020,9246) was measured. +Enumerated Value: +INSPIRATION +MAXIMUM +EXPIRATION +MINIMUM +Required if Starting Respiratory Amplitude (0020,9246) is present. + + + Nominal amplitude of the respiratory signal at which the acquisition of data for this frame ends, in percent of the nominal maximum value (which represents maximum inspiration). +Required if Respiratory Trigger Type (0020,9250) is AMPLITUDE or BOTH. + + + The phase of respiration at which the Ending Respiratory Amplitude (0020,9248) was measured. +Enumerated Value: +INSPIRATION +MAXIMUM +EXPIRATION +MINIMUM +Required if Ending Respiratory Amplitude (0020,9248) is present. + +
+ + + Sequence containing the Irradiation Event Identification for this frame. +Only a single Item shall be permitted in this sequence. + + + Unique identification of the irradiation event(s) associated with the acquisition of this image. + + + + + Sequence that lists the Dimension Organization UIDs referenced by the containing SOP Instance. See section C.7.6.17.2 for further explanation. Zero or more Items may be included in this Sequence. + + + Uniquely identifies a set of dimensions referenced within the containing SOP Instance. See section C.7.6.17.2 for further explanation. + + + Identifies the sequence containing the indices used to specify the dimension of the multi-frame object. +Zero or more Items may be included in this sequence. + + + Contains the Data Element Tag that is used to identify the Attribute connected with the index. See section C.7.6.17.1 for further explanation. + + + Identification of the creator of a group of private data elements. +Required if the Dimension Index Pointer (0020,9165) value is the Data Element Tag of a Private Attribute. + + + Contains the Data Element Tag of the Functional Group Sequence that contains the Attribute that is referenced by the Dimension Index Pointer (0020,9165). +See section C.7.6.17.1 for further explanation. +Required if the value of the Dimension Index Pointer (0020,9165) is the Data Element Tag of an Attribute that is contained within a Functional Group Sequence. + + + Identification of the creator of a group of private data elements. +Required if the Functional Group Pointer 0020,9167) value is the Data Element Tag of a Private Attribute. + + + Uniquely identifies a set of dimensions referenced within the containing SOP Instance. In particular the dimension described by this sequence item is associated with this Dimension Organization UID. See section C.7.6.17.2 for further explanation. +Required if the value of the Dimension Organization Sequence (0020,9221) contains Items + + + Free text description that explains the meaning of the dimension. + + + + + Defines if a cardiac synchronization technique was applied during or after the acquisition. +Enumerated Values: +NONE +REALTIME = total time for the acquisition is shorter than cardiac cycle, no gating is applied +PROSPECTIVE = +certain thresholds have been set for a gating window that defines the acceptance of measurement data during the acquisition +RETROSPECTIVE = +certain thresholds have been set for a gating window that defines the acceptance of measurement data after the acquisition +PACED = there is a constant RR interval (e.g., Pacemaker), which makes thresholding not required +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED. May be present otherwise. + + + Cardiac Signal Source. +Defined Terms: +ECG = electrocardiogram +VCG = vector cardiogram +PP = peripheral pulse +MR = magnetic resonance, i.e. M-mode or cardiac navigator +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED and Cardiac Synchronization Technique (0018,9037) equals other than NONE. +Otherwise may be present if Image Type (0008,0008) Value 1 is DERIVED and Cardiac Synchronization Technique (0018,9037) equals other than NONE. + + + R-R interval in ms measured prior to or during the scan. +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED and Cardiac Synchronization Technique (0018,9037) equals other than NONE. +Otherwise may be present if Image Type (0008,0008) Value 1 is DERIVED and Cardiac Synchronization Technique (0018,9037) equals other than NONE. +Note: The Heart Rate (0018,1088) attribute is not used in this Module, since its value can be derived as 1/ Cardiac RR Interval Specified (0018,9070). + + + Cardiac arrhythmia rejection technique. +Defined Terms: +NONE +RR_INTERVAL = +rejection based on deviation from average RR interval +QRS_LOOP = +rejection based on deviation from regular QRS loop +PVC = +rejection based on PVC criteria +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED and Cardiac Synchronization Technique (0018,9037) equals PROSPECTIVE or RETROSPECTIVE. +Otherwise may be present if Image Type (0008,0008) Value 1 is DERIVED and Cardiac Synchronization Technique (0018,9037) equals PROSPECTIVE or RETROSPECTIVE. + + + R-R interval low limit for beat rejection, in ms. +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED and Cardiac Synchronization Technique (0018,9037) equals PROSPECTIVE or RETROSPECTIVE. +Otherwise may be present if Image Type (0008,0008) Value 1 is DERIVED and Cardiac Synchronization Technique (0018,9037) equals PROSPECTIVE or RETROSPECTIVE. + + + R-R interval high limit for beat rejection, in ms. +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED and Cardiac Synchronization Technique (0018,9037) equals PROSPECTIVE or RETROSPECTIVE. +Otherwise may be present if Image Type (0008,0008) Value 1 is DERIVED and Cardiac Synchronization Technique (0018,9037) equals PROSPECTIVE or RETROSPECTIVE. + + + Number of R-R intervals acquired and used to create the image (not including the intervals rejected). +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED and Cardiac Synchronization Technique (0018,9037) equals other than NONE. +Otherwise may be present if Image Type (0008,0008) Value 1 is DERIVED and Cardiac Synchronization Technique (0018,9037) equals other than NONE. + + + Number of R-R intervals rejected. +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED and Cardiac Synchronization Technique (0018,9037) equals other than NONE. +Otherwise may be present if Image Type (0008,0008) Value 1 is DERIVED and Cardiac Synchronization Technique (0018,9037) equals other than NONE. + + + Number of beats prescribed to be skipped after each detected arrhythmia. + + + Description of type of framing performed. Defined Terms: +FORW = time forward from trigger +BACK = time back before trigger +PCNT = percentage of R-R forward from trigger +See C.7.6.18.1.1.1. +Required if type of framing is not time forward from trigger, may be present otherwise. +
Cardiac Framing Type (0018,1064) is the mechanism used to select the data acquired to construct the frames within a specified cardiac timing interval.C.7.6.18.2 Respiratory Synchronization Module +Table C7.6.18-2 specifies the attributes of the Respiratory Synchronization Module. +Table C.7.6.18-2 +RESPIRATORY SYNCHRONIZATION MODULE ATTRIBUTES + +
+
+
+ + + Applied technique to reduce respiratory motion artifacts. +Defined Terms: +NONE +BREATH_HOLD +REALTIME = +image acquisition shorter than respiratory cycle +GATING = Prospective gating +TRACKING = +prospective through-plane or in-plane motion tracking +PHASE_ORDERING = +prospective phase ordering +PHASE_RESCANNING = +prospective techniques, such as real-time averaging, diminishing variance and motion adaptive gating +RETROSPECTIVE = +retrospective gating +CORRECTION = +retrospective image correction +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED. May be present otherwise. + + + Signal source from which respiratory motion is derived. +Defined Terms: +NONE +BELT = includes various devices that detect or track expansion of the chest +NASAL_PROBE +CO2_SENSOR +NAVIGATOR = MR navigator and organ edge detection +MR_PHASE = phase (of center k-space line) +ECG = baseline demodulation of the ECG +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED and Respiratory Motion Compensation Technique (0018,9170) equals other than NONE. +Otherwise may be present if Image Type (0008,0008) Value 1 is DERIVED and Respiratory Motion Compensation Technique (0018,9170 equals other than NONE. + + + Respiratory trigger threshold in percent of the chest expansion for the frame relative to the last Respiratory-Peak. See C.7.6.16.2.17.1 for further explanation. +Required if Respiratory Motion Compensation Technique (0018,9170) equals other than NONE, REALTIME or BREATH_HOLD and if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED. May be present otherwise. +
For time based respiratory gating, the Nominal Respiratory Trigger Delay Time (0020,9255) is the prescribed trigger delay time in ms from the previous Respiratory-peak to the value of the Frame Reference DateTime (0018,9151). When frames are acquired with prospective gating, that is, the data acquisition actually begins in response to a timed delay from the Respiratory trigger, it may be that Actual Respiratory Trigger Delay Time (0020,9257) and the Nominal Respiratory Trigger Delay Time (0020,9255) have the same value. +However, when frames are the result of retrospective gating, that is, the data is continuously acquired and then later compared with a simultaneously acquired respiratory waveform and fitted into bins corresponding to nominal phases of the respiratory cycle, then Nominal Respiratory Trigger Delay Time (0020,9255) and the Actual Respiratory Trigger Delay Time (0020,9257) may have different values. +Figure C.7.6.16-9a and C.7.6.16-9b depict the usage. + + +Figure C.7.6.16-9a +Respiratory Timing Tags + + +Figure C.7.6.16-9b +Relationship of Respiratory Amplitude Attributes + +
+
+ + Characteristic of the respiratory signal used to the define the respiratory triggering. +Defined Terms: +TIME +AMPLITUDE +BOTH +Required if the value is not TIME, may be present otherwise. + +
+ + + Applied technique to reduce bulk or other physiology motion artifacts. +Defined Terms: +NONE +REALTIME = image acquisition shorter than motion cycle +GATING = prospective gating +TRACKING = prospective through and/or in‑plane motion tracking +RETROSPECTIVE = +retrospective gating +CORRECTION = retrospective image correction +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED. May be present otherwise. + + + Signal source to measure motion. +Defined Terms: +JOINT = joint motion detection +NAVIGATOR = MR navigator and organ edge detection +MR_PHASE = phase (of center k‑space line) +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED and Bulk Motion Compensation Technique (0018,9172) equals other than NONE. +Otherwise may be present if Image Type (0008,0008) Value 1 is DERIVED and Bulk Motion Compensation Technique (0018,9172) equals other than NONE. + + + + + Specifies the format of the Red Palette Color Lookup Table Data (0028,1201). See C.7.6.3.1.5 for further explanation. +
The three values of Palette Color Lookup Table Descriptor (0028,1101-1103) describe the format of the Lookup Table Data in the corresponding Data Element (0028,1201-1203) or (0028,1221-1223). +The first value is the number of entries in the lookup table. When the number of table entries is equal to 216 then this value shall be 0. The first value shall be identical for each of the Red, Green and Blue Palette Color Lookup Table Descriptors. +The second value is the first stored pixel value mapped. This pixel value is mapped to the first entry in the Lookup Table Data. All image pixel values less than the first value mapped are also mapped to the first entry in the Lookup Table Data if the Photometric Interpretation is PALETTE COLOR. +Note: In the case of the Supplemental Palette Color LUT, the stored pixel values less than the second descriptor value are grayscale values. + +An image pixel value one greater than the first value mapped is mapped to the second entry in the Lookup Table Data. Subsequent image pixel values are mapped to the subsequent entries in the Lookup Table Data up to an image pixel value equal to number of entries + first value mapped – 1, which is mapped to the last entry in the Lookup Table Data. Image pixel values greater than or equal to number of entries + first value mapped are also mapped to the last entry in the Lookup Table Data. The second value shall be identical for each of the Red, Green and Blue Palette Color Lookup Table Descriptors. +The third value specifies the number of bits for each entry in the Lookup Table Data. It shall take the value of 8 or 16. The LUT Data shall be stored in a format equivalent to 8 bits allocated when the number of bits for each entry is 8, and 16 bits allocated when the number of bits for each entry is 16, where in both cases the high bit is equal to bits allocated-1. The third value shall be identical for each of the Red, Green and Blue Palette Color Lookup Table Descriptors. +Note: Some implementations have encoded 8 bit entries with 16 bits allocated, padding the high bits; this can be detected by comparing the number of entries specified in the LUT Descriptor with the actual value length of the LUT Data entry. The value length in bytes should equal the number of entries if bits allocated is 8, and be twice as long if bits allocated is 16. + +When the Palette Color Lookup Table Descriptor (0028,1101-1103) are used as part of the Palette Color Lookup Table Module or the Supplemental Palette Color Lookup Table Module, the third value shall be equal to 16. +Notes: 1. A value of 16 indicates the Lookup Table Data will range from (0,0,0) minimum intensity to (65535,65535,65535) maximum intensity. + 2. Since the Palette Color Lookup Table Descriptor (0028,1101-1103) Attributes are multi-valued, in an Explicit VR Transfer Syntax, only one value representation (US or SS) may be specified, even though the first and third values are always by definition interpreted as unsigned. The explicit VR actually used is dictated by the VR needed to represent the second value, which will be consistent with Pixel Representation (0028,0103). + +
+
+ + Specifies the format of the Green Palette Color Lookup Table Data (0028,1202). See C.7.6.3.1.5 for further explanation. +
The three values of Palette Color Lookup Table Descriptor (0028,1101-1103) describe the format of the Lookup Table Data in the corresponding Data Element (0028,1201-1203) or (0028,1221-1223). +The first value is the number of entries in the lookup table. When the number of table entries is equal to 216 then this value shall be 0. The first value shall be identical for each of the Red, Green and Blue Palette Color Lookup Table Descriptors. +The second value is the first stored pixel value mapped. This pixel value is mapped to the first entry in the Lookup Table Data. All image pixel values less than the first value mapped are also mapped to the first entry in the Lookup Table Data if the Photometric Interpretation is PALETTE COLOR. +Note: In the case of the Supplemental Palette Color LUT, the stored pixel values less than the second descriptor value are grayscale values. + +An image pixel value one greater than the first value mapped is mapped to the second entry in the Lookup Table Data. Subsequent image pixel values are mapped to the subsequent entries in the Lookup Table Data up to an image pixel value equal to number of entries + first value mapped – 1, which is mapped to the last entry in the Lookup Table Data. Image pixel values greater than or equal to number of entries + first value mapped are also mapped to the last entry in the Lookup Table Data. The second value shall be identical for each of the Red, Green and Blue Palette Color Lookup Table Descriptors. +The third value specifies the number of bits for each entry in the Lookup Table Data. It shall take the value of 8 or 16. The LUT Data shall be stored in a format equivalent to 8 bits allocated when the number of bits for each entry is 8, and 16 bits allocated when the number of bits for each entry is 16, where in both cases the high bit is equal to bits allocated-1. The third value shall be identical for each of the Red, Green and Blue Palette Color Lookup Table Descriptors. +Note: Some implementations have encoded 8 bit entries with 16 bits allocated, padding the high bits; this can be detected by comparing the number of entries specified in the LUT Descriptor with the actual value length of the LUT Data entry. The value length in bytes should equal the number of entries if bits allocated is 8, and be twice as long if bits allocated is 16. + +When the Palette Color Lookup Table Descriptor (0028,1101-1103) are used as part of the Palette Color Lookup Table Module or the Supplemental Palette Color Lookup Table Module, the third value shall be equal to 16. +Notes: 1. A value of 16 indicates the Lookup Table Data will range from (0,0,0) minimum intensity to (65535,65535,65535) maximum intensity. + 2. Since the Palette Color Lookup Table Descriptor (0028,1101-1103) Attributes are multi-valued, in an Explicit VR Transfer Syntax, only one value representation (US or SS) may be specified, even though the first and third values are always by definition interpreted as unsigned. The explicit VR actually used is dictated by the VR needed to represent the second value, which will be consistent with Pixel Representation (0028,0103). + +
+
+ + Specifies the format of the Blue Palette Color Lookup table Data (0028,1203). See C.7.6.3.1.5 for further explanation. +
The three values of Palette Color Lookup Table Descriptor (0028,1101-1103) describe the format of the Lookup Table Data in the corresponding Data Element (0028,1201-1203) or (0028,1221-1223). +The first value is the number of entries in the lookup table. When the number of table entries is equal to 216 then this value shall be 0. The first value shall be identical for each of the Red, Green and Blue Palette Color Lookup Table Descriptors. +The second value is the first stored pixel value mapped. This pixel value is mapped to the first entry in the Lookup Table Data. All image pixel values less than the first value mapped are also mapped to the first entry in the Lookup Table Data if the Photometric Interpretation is PALETTE COLOR. +Note: In the case of the Supplemental Palette Color LUT, the stored pixel values less than the second descriptor value are grayscale values. + +An image pixel value one greater than the first value mapped is mapped to the second entry in the Lookup Table Data. Subsequent image pixel values are mapped to the subsequent entries in the Lookup Table Data up to an image pixel value equal to number of entries + first value mapped – 1, which is mapped to the last entry in the Lookup Table Data. Image pixel values greater than or equal to number of entries + first value mapped are also mapped to the last entry in the Lookup Table Data. The second value shall be identical for each of the Red, Green and Blue Palette Color Lookup Table Descriptors. +The third value specifies the number of bits for each entry in the Lookup Table Data. It shall take the value of 8 or 16. The LUT Data shall be stored in a format equivalent to 8 bits allocated when the number of bits for each entry is 8, and 16 bits allocated when the number of bits for each entry is 16, where in both cases the high bit is equal to bits allocated-1. The third value shall be identical for each of the Red, Green and Blue Palette Color Lookup Table Descriptors. +Note: Some implementations have encoded 8 bit entries with 16 bits allocated, padding the high bits; this can be detected by comparing the number of entries specified in the LUT Descriptor with the actual value length of the LUT Data entry. The value length in bytes should equal the number of entries if bits allocated is 8, and be twice as long if bits allocated is 16. + +When the Palette Color Lookup Table Descriptor (0028,1101-1103) are used as part of the Palette Color Lookup Table Module or the Supplemental Palette Color Lookup Table Module, the third value shall be equal to 16. +Notes: 1. A value of 16 indicates the Lookup Table Data will range from (0,0,0) minimum intensity to (65535,65535,65535) maximum intensity. + 2. Since the Palette Color Lookup Table Descriptor (0028,1101-1103) Attributes are multi-valued, in an Explicit VR Transfer Syntax, only one value representation (US or SS) may be specified, even though the first and third values are always by definition interpreted as unsigned. The explicit VR actually used is dictated by the VR needed to represent the second value, which will be consistent with Pixel Representation (0028,0103). + +
+
+ + Red Palette Color Lookup Table Data. See C.7.6.3.1.6 for further explanation. +
Palette Color Lookup Table Data (0028,1201-1203) contain the lookup table data corresponding to the Lookup Table Descriptor (0028,1101-1103). +Palette color values must always be scaled across the full range of available intensities. This is indicated by the fact that there are no bits stored and high bit values for palette color data. +Note: For example, if there are 16 bits per entry specified and only 8 bits of value are truly used then the 8 bit intensities from 0 to 255 must be scaled to the corresponding 16 bit intensities from 0 to 65535. To do this for 8 bit values, simply replicate the value in both the most and least significant bytes. + +These lookup tables shall be used only when there is a single sample per pixel (single image plane) in the image. +These lookup tables are required when the value of Photometric Interpretation (0028,0004) is Palette Color. The semantics of these lookup tables is not defined otherwise. +
+
+ + Green Palette Color Lookup Table Data. See C.7.6.3.1.6 for further explanation. +
Palette Color Lookup Table Data (0028,1201-1203) contain the lookup table data corresponding to the Lookup Table Descriptor (0028,1101-1103). +Palette color values must always be scaled across the full range of available intensities. This is indicated by the fact that there are no bits stored and high bit values for palette color data. +Note: For example, if there are 16 bits per entry specified and only 8 bits of value are truly used then the 8 bit intensities from 0 to 255 must be scaled to the corresponding 16 bit intensities from 0 to 65535. To do this for 8 bit values, simply replicate the value in both the most and least significant bytes. + +These lookup tables shall be used only when there is a single sample per pixel (single image plane) in the image. +These lookup tables are required when the value of Photometric Interpretation (0028,0004) is Palette Color. The semantics of these lookup tables is not defined otherwise. +
+
+ + Blue Palette Color Lookup Table Data. See C.7.6.3.1.6 for further explanation. +
Palette Color Lookup Table Data (0028,1201-1203) contain the lookup table data corresponding to the Lookup Table Descriptor (0028,1101-1103). +Palette color values must always be scaled across the full range of available intensities. This is indicated by the fact that there are no bits stored and high bit values for palette color data. +Note: For example, if there are 16 bits per entry specified and only 8 bits of value are truly used then the 8 bit intensities from 0 to 255 must be scaled to the corresponding 16 bit intensities from 0 to 65535. To do this for 8 bit values, simply replicate the value in both the most and least significant bytes. + +These lookup tables shall be used only when there is a single sample per pixel (single image plane) in the image. +These lookup tables are required when the value of Photometric Interpretation (0028,0004) is Palette Color. The semantics of these lookup tables is not defined otherwise. +
+
+
+ + + + + + A 4x4 homogeneous transformation matrix that maps patient coordinate space of the reconstructed image to the equipment defined original coordinate space. Matrix elements shall be listed in row-major order. See C.7.6.21.1. +
The Image to Equipment Mapping Matrix (0028,9520) is used to describe the relationship between the Patient oriented coordinate system and a modality specific equipment coordinate system. This mapping can only be used with systems that have a well-defined equipment coordinate system (such as XA, etc.). +The Image to Equipment Mapping Matrix AMB describes how to transform a point (Bx,By,Bz) with respect to the Patient coordinate system into (Ax,Ay,Az) with respect to the equipment coordinate system according to the equation below. + + size 12{ left [ matrix { +"" lSup { size 8{A} } x {} ## +"" lSup { size 8{A} } y {} ## +"" lSup { size 8{A} } z {} ## +1 +} right ]= left [ matrix { +M rSub { size 8{"11"} } {} # M rSub { size 8{"12"} } {} # M rSub { size 8{"13"} } {} # T rSub { size 8{x} } {} ## +M rSub { size 8{"21"} } {} # M rSub { size 8{"22"} } {} # M rSub { size 8{"23"} } {} # T rSub { size 8{y} } {} ## +M rSub { size 8{"31"} } {} # M rSub { size 8{"32"} } {} # M rSub { size 8{"33"} } {} # T rSub { size 8{z} } {} ## +0 {} # 0 {} # 0 {} # 1{} +} right ] left [ matrix { +"" lSup { size 8{B} } x {} ## +"" lSup { size 8{B} } y {} ## +"" lSup { size 8{B} } z {} ## +1 +} right ]} {} + + +The Image to Equipment Mapping Matrix is a rigid transformation that involves only translations and rotations. Mathematically, the matrix shall be orthonormal and can describe six degrees of freedom: three translations, and three rotations. +Note: Both the Patient Coordinate System and the Equipment Coordinate System are expressed in millimeters. + +
+
+ + Identification of the type of equipment coordinate system in which the projection images were acquired. See C.7.6.21.2. +Defined Terms: +ISOCENTER +
The Equipment Coordinate System Identification (0028,9537) identifies the Reference Coordinate System to which the Image to Equipment Mapping Matrix (0028,9520) is related. +The Defined Term ISOCENTER refers to a coordinate reference system where the origin corresponds with the center of rotation of the projections. +Note: For X-Ray 3D Angiographic Images created from SOP Instances of the Enhanced XA SOP Class (1.2.840.10008.5.1.4.1.1.12.1.1) the isocenter coordinate system is used to describe the positioning of the table and positioner (see C.8.19.6.13), and will use only the Defined Term ISOCENTER. + +
+
+
+ + + Specifies the format of the Red Palette Color Lookup Table Data (0028,1201). See C.7.6.3.1.5 for further explanation. +
The three values of Palette Color Lookup Table Descriptor (0028,1101-1103) describe the format of the Lookup Table Data in the corresponding Data Element (0028,1201-1203) or (0028,1221-1223). +The first value is the number of entries in the lookup table. When the number of table entries is equal to 216 then this value shall be 0. The first value shall be identical for each of the Red, Green and Blue Palette Color Lookup Table Descriptors. +The second value is the first stored pixel value mapped. This pixel value is mapped to the first entry in the Lookup Table Data. All image pixel values less than the first value mapped are also mapped to the first entry in the Lookup Table Data if the Photometric Interpretation is PALETTE COLOR. +Note: In the case of the Supplemental Palette Color LUT, the stored pixel values less than the second descriptor value are grayscale values. + +An image pixel value one greater than the first value mapped is mapped to the second entry in the Lookup Table Data. Subsequent image pixel values are mapped to the subsequent entries in the Lookup Table Data up to an image pixel value equal to number of entries + first value mapped – 1, which is mapped to the last entry in the Lookup Table Data. Image pixel values greater than or equal to number of entries + first value mapped are also mapped to the last entry in the Lookup Table Data. The second value shall be identical for each of the Red, Green and Blue Palette Color Lookup Table Descriptors. +The third value specifies the number of bits for each entry in the Lookup Table Data. It shall take the value of 8 or 16. The LUT Data shall be stored in a format equivalent to 8 bits allocated when the number of bits for each entry is 8, and 16 bits allocated when the number of bits for each entry is 16, where in both cases the high bit is equal to bits allocated-1. The third value shall be identical for each of the Red, Green and Blue Palette Color Lookup Table Descriptors. +Note: Some implementations have encoded 8 bit entries with 16 bits allocated, padding the high bits; this can be detected by comparing the number of entries specified in the LUT Descriptor with the actual value length of the LUT Data entry. The value length in bytes should equal the number of entries if bits allocated is 8, and be twice as long if bits allocated is 16. + +When the Palette Color Lookup Table Descriptor (0028,1101-1103) are used as part of the Palette Color Lookup Table Module or the Supplemental Palette Color Lookup Table Module, the third value shall be equal to 16. +Notes: 1. A value of 16 indicates the Lookup Table Data will range from (0,0,0) minimum intensity to (65535,65535,65535) maximum intensity. + 2. Since the Palette Color Lookup Table Descriptor (0028,1101-1103) Attributes are multi-valued, in an Explicit VR Transfer Syntax, only one value representation (US or SS) may be specified, even though the first and third values are always by definition interpreted as unsigned. The explicit VR actually used is dictated by the VR needed to represent the second value, which will be consistent with Pixel Representation (0028,0103). + +
+
+ + Specifies the format of the Green Palette Color Lookup Table Data (0028,1202). See C.7.6.3.1.5 for further explanation. +
The three values of Palette Color Lookup Table Descriptor (0028,1101-1103) describe the format of the Lookup Table Data in the corresponding Data Element (0028,1201-1203) or (0028,1221-1223). +The first value is the number of entries in the lookup table. When the number of table entries is equal to 216 then this value shall be 0. The first value shall be identical for each of the Red, Green and Blue Palette Color Lookup Table Descriptors. +The second value is the first stored pixel value mapped. This pixel value is mapped to the first entry in the Lookup Table Data. All image pixel values less than the first value mapped are also mapped to the first entry in the Lookup Table Data if the Photometric Interpretation is PALETTE COLOR. +Note: In the case of the Supplemental Palette Color LUT, the stored pixel values less than the second descriptor value are grayscale values. + +An image pixel value one greater than the first value mapped is mapped to the second entry in the Lookup Table Data. Subsequent image pixel values are mapped to the subsequent entries in the Lookup Table Data up to an image pixel value equal to number of entries + first value mapped – 1, which is mapped to the last entry in the Lookup Table Data. Image pixel values greater than or equal to number of entries + first value mapped are also mapped to the last entry in the Lookup Table Data. The second value shall be identical for each of the Red, Green and Blue Palette Color Lookup Table Descriptors. +The third value specifies the number of bits for each entry in the Lookup Table Data. It shall take the value of 8 or 16. The LUT Data shall be stored in a format equivalent to 8 bits allocated when the number of bits for each entry is 8, and 16 bits allocated when the number of bits for each entry is 16, where in both cases the high bit is equal to bits allocated-1. The third value shall be identical for each of the Red, Green and Blue Palette Color Lookup Table Descriptors. +Note: Some implementations have encoded 8 bit entries with 16 bits allocated, padding the high bits; this can be detected by comparing the number of entries specified in the LUT Descriptor with the actual value length of the LUT Data entry. The value length in bytes should equal the number of entries if bits allocated is 8, and be twice as long if bits allocated is 16. + +When the Palette Color Lookup Table Descriptor (0028,1101-1103) are used as part of the Palette Color Lookup Table Module or the Supplemental Palette Color Lookup Table Module, the third value shall be equal to 16. +Notes: 1. A value of 16 indicates the Lookup Table Data will range from (0,0,0) minimum intensity to (65535,65535,65535) maximum intensity. + 2. Since the Palette Color Lookup Table Descriptor (0028,1101-1103) Attributes are multi-valued, in an Explicit VR Transfer Syntax, only one value representation (US or SS) may be specified, even though the first and third values are always by definition interpreted as unsigned. The explicit VR actually used is dictated by the VR needed to represent the second value, which will be consistent with Pixel Representation (0028,0103). + +
+
+ + Specifies the format of the Blue Palette Color Lookup table Data (0028,1203). See C.7.6.3.1.5 for further explanation. +
The three values of Palette Color Lookup Table Descriptor (0028,1101-1103) describe the format of the Lookup Table Data in the corresponding Data Element (0028,1201-1203) or (0028,1221-1223). +The first value is the number of entries in the lookup table. When the number of table entries is equal to 216 then this value shall be 0. The first value shall be identical for each of the Red, Green and Blue Palette Color Lookup Table Descriptors. +The second value is the first stored pixel value mapped. This pixel value is mapped to the first entry in the Lookup Table Data. All image pixel values less than the first value mapped are also mapped to the first entry in the Lookup Table Data if the Photometric Interpretation is PALETTE COLOR. +Note: In the case of the Supplemental Palette Color LUT, the stored pixel values less than the second descriptor value are grayscale values. + +An image pixel value one greater than the first value mapped is mapped to the second entry in the Lookup Table Data. Subsequent image pixel values are mapped to the subsequent entries in the Lookup Table Data up to an image pixel value equal to number of entries + first value mapped – 1, which is mapped to the last entry in the Lookup Table Data. Image pixel values greater than or equal to number of entries + first value mapped are also mapped to the last entry in the Lookup Table Data. The second value shall be identical for each of the Red, Green and Blue Palette Color Lookup Table Descriptors. +The third value specifies the number of bits for each entry in the Lookup Table Data. It shall take the value of 8 or 16. The LUT Data shall be stored in a format equivalent to 8 bits allocated when the number of bits for each entry is 8, and 16 bits allocated when the number of bits for each entry is 16, where in both cases the high bit is equal to bits allocated-1. The third value shall be identical for each of the Red, Green and Blue Palette Color Lookup Table Descriptors. +Note: Some implementations have encoded 8 bit entries with 16 bits allocated, padding the high bits; this can be detected by comparing the number of entries specified in the LUT Descriptor with the actual value length of the LUT Data entry. The value length in bytes should equal the number of entries if bits allocated is 8, and be twice as long if bits allocated is 16. + +When the Palette Color Lookup Table Descriptor (0028,1101-1103) are used as part of the Palette Color Lookup Table Module or the Supplemental Palette Color Lookup Table Module, the third value shall be equal to 16. +Notes: 1. A value of 16 indicates the Lookup Table Data will range from (0,0,0) minimum intensity to (65535,65535,65535) maximum intensity. + 2. Since the Palette Color Lookup Table Descriptor (0028,1101-1103) Attributes are multi-valued, in an Explicit VR Transfer Syntax, only one value representation (US or SS) may be specified, even though the first and third values are always by definition interpreted as unsigned. The explicit VR actually used is dictated by the VR needed to represent the second value, which will be consistent with Pixel Representation (0028,0103). + +
+
+ + Palette Color Lookup Table UID. See C.7.9.1 for further explanation. +
This data element uniquely identifies a palette color lookup table set (red, green, blue). +Note: This can be used to avoid reloading a palette if a system already has that palette loaded without examining all the data entries in the palette. + +
+
+ + Red Palette Color Lookup Table Data. Required if segmented data is NOT used in an Image IOD, or if the IOD is a Presentation State IOD. See C.7.6.3.1.6 for further explanation. +
Palette Color Lookup Table Data (0028,1201-1203) contain the lookup table data corresponding to the Lookup Table Descriptor (0028,1101-1103). +Palette color values must always be scaled across the full range of available intensities. This is indicated by the fact that there are no bits stored and high bit values for palette color data. +Note: For example, if there are 16 bits per entry specified and only 8 bits of value are truly used then the 8 bit intensities from 0 to 255 must be scaled to the corresponding 16 bit intensities from 0 to 65535. To do this for 8 bit values, simply replicate the value in both the most and least significant bytes. + +These lookup tables shall be used only when there is a single sample per pixel (single image plane) in the image. +These lookup tables are required when the value of Photometric Interpretation (0028,0004) is Palette Color. The semantics of these lookup tables is not defined otherwise. +
+
+ + Green Palette Color Lookup Table Data. Required if segmented data is NOT used in an Image IOD, or if the IOD is a Presentation State IOD. See C.7.6.3.1.6 for further explanation. +
Palette Color Lookup Table Data (0028,1201-1203) contain the lookup table data corresponding to the Lookup Table Descriptor (0028,1101-1103). +Palette color values must always be scaled across the full range of available intensities. This is indicated by the fact that there are no bits stored and high bit values for palette color data. +Note: For example, if there are 16 bits per entry specified and only 8 bits of value are truly used then the 8 bit intensities from 0 to 255 must be scaled to the corresponding 16 bit intensities from 0 to 65535. To do this for 8 bit values, simply replicate the value in both the most and least significant bytes. + +These lookup tables shall be used only when there is a single sample per pixel (single image plane) in the image. +These lookup tables are required when the value of Photometric Interpretation (0028,0004) is Palette Color. The semantics of these lookup tables is not defined otherwise. +
+
+ + Blue Palette Color Lookup Table Data. Required if segmented data is NOT used in an Image IOD, or if the IOD is a Presentation State IOD. See C.7.6.3.1.6 for further explanation. +
Palette Color Lookup Table Data (0028,1201-1203) contain the lookup table data corresponding to the Lookup Table Descriptor (0028,1101-1103). +Palette color values must always be scaled across the full range of available intensities. This is indicated by the fact that there are no bits stored and high bit values for palette color data. +Note: For example, if there are 16 bits per entry specified and only 8 bits of value are truly used then the 8 bit intensities from 0 to 255 must be scaled to the corresponding 16 bit intensities from 0 to 65535. To do this for 8 bit values, simply replicate the value in both the most and least significant bytes. + +These lookup tables shall be used only when there is a single sample per pixel (single image plane) in the image. +These lookup tables are required when the value of Photometric Interpretation (0028,0004) is Palette Color. The semantics of these lookup tables is not defined otherwise. +
+
+ + Segmented Red Palette Color Lookup Table Data. Required segmented data is used in an Image IOD; shall not be present in a Presentation State IOD. See C.7.9.2 for further explanation. +
The Segmented Palette Color Lookup Table Data (0028,1221-1223) is stored as a series of segments, see Table C.7-23. When the segments are expanded into the actual lookup table data, it shall have the number of table entries specified by the first value of the Palette Color Lookup Table Descriptors (0028,1101-1103), Number of Table Entries. +These lookup tables shall be used only when segmented lookup table data use is desriable and there is a single sample per pixel (single image plane) in the image. +Table C.7-23 +COMPRESSED PALETTE COLOR LOOKUP TABLE DATA + +There are currently three types of segments: discrete, linear, and indirect. The segments type is identified by the opcodes in Table C.7-24: +Table C.7-24 +SEGMENT TYPES + +
+
+ + Segmented Green Palette Color Lookup Table Data. Required if segmented data is used in an Image IOD; shall not be present in a Presentation State IOD. See C.7.9.2 for further explanation. +
The Segmented Palette Color Lookup Table Data (0028,1221-1223) is stored as a series of segments, see Table C.7-23. When the segments are expanded into the actual lookup table data, it shall have the number of table entries specified by the first value of the Palette Color Lookup Table Descriptors (0028,1101-1103), Number of Table Entries. +These lookup tables shall be used only when segmented lookup table data use is desriable and there is a single sample per pixel (single image plane) in the image. +Table C.7-23 +COMPRESSED PALETTE COLOR LOOKUP TABLE DATA + +There are currently three types of segments: discrete, linear, and indirect. The segments type is identified by the opcodes in Table C.7-24: +Table C.7-24 +SEGMENT TYPES + +
+
+ + Segmented Blue Palette Color Lookup Table Data. Required if segmented data is used in an Image IOD; shall not be present in a Presentation State IOD. See C.7.9.2 for further explanation. +
The Segmented Palette Color Lookup Table Data (0028,1221-1223) is stored as a series of segments, see Table C.7-23. When the segments are expanded into the actual lookup table data, it shall have the number of table entries specified by the first value of the Palette Color Lookup Table Descriptors (0028,1101-1103), Number of Table Entries. +These lookup tables shall be used only when segmented lookup table data use is desriable and there is a single sample per pixel (single image plane) in the image. +Table C.7-23 +COMPRESSED PALETTE COLOR LOOKUP TABLE DATA + +There are currently three types of segments: discrete, linear, and indirect. The segments type is identified by the opcodes in Table C.7-24: +Table C.7-24 +SEGMENT TYPES + +
+
+
+ + + Text description of the part of the body examined. See PS 3.16 Annex on Correspondence of Anatomic Region Codes and Body Part Examined for Defined Terms + + + Radiographic view associated with Patient Position (0018,5100). Defined Terms: +AP = Anterior/Posterior +PA = Posterior/Anterior +LL = Left Lateral +RL = Right Lateral +RLD = Right Lateral Decubitus +LLD = Left Lateral Decubitus +RLO = Right Lateral Oblique +LLO = Left Lateral Oblique + + + Label for the type of filter inserted into the x-ray beam + + + Label describing any grid inserted. + + + Size of the focal spot in mm. For devices with variable focal spot or multiple focal spots, small dimension followed by large dimension. + + + Label of the type of storage phosphor plates used in this series + + + Label of type of phosphor on the plates + + + + + Specifies the intended interpretation of the pixel data. Shall have one of the following Enumerated Values: +MONOCHROME1 +MONOCHROME2 + + + Peak kilo voltage output of the x-ray generator used + + + The ID or serial number of the sensing plate upon which the image was acquired + + + Distance in mm from source to detector center. +Note: This value is traditionally referred to as Source Image Receptor Distance (SID). + + + Distance in mm from source to isocenter (center of field of view) . +Note: This value is traditionally referred to as Source Object Distance (SOD). + + + Time of x-ray exposure in msec + + + X-Ray Tube Current in mA. + + + The exposure expressed in mAs, for example calculated from Exposure Time and X-Ray Tube Current. + + + The exposure expressed in µAs, for example calculated from Exposure Time and X-Ray Tube Current. + + + Physical distance measured at the front plane of the Image Receptor housing between the center of each pixel. Specified by a numeric pair - row spacing value (delimiter) column spacing value - in mm. +In the case of CR, the front plane is defined to be the external surface of the CR plate closest to the patient and radiation source. + + + + Power in kW to the x-ray generator. + + + Describes device-specific processing associated with the image (e.g. Organ Description) + + + Code representing the device-specific processing associated with the image (e.g. CR Organ Filtering code) + + + Orientation of cassette, used to properly position the image for display. +Enumerated Values: +LANDSCAPE +PORTRAIT + + + Size of cassette. Defined Terms: +18CMX24CM +8INX10IN +24CMX30CM +10INX12IN +30CMX35CM +30CMX40CM +11INX14IN +35CMX35CM +14INX14IN +35CMX43CM +14INX17IN + + + Total number of x-ray exposures that have been made on the plate identified in Plate ID (0018,1004) + + + Relative x-ray exposure on the plate. Meaning of values is implementation specific. May be used to adjust the dynamic range of the plate digitizer (scanner). + + + Read out sensitivity. + + + + + + Image identification characteristics. See C.8.2.1.1.1 for specialization. +
For CT Images, Image Type (0008,0008) is specified to be Type 1 and uses one of the following Defined Terms for Value 3: +AXIAL identifies a CT Axial Image +LOCALIZER identifies a CT Localizer Image +Note: Axial in this context means any cross-sectional image, and includes transverse, coronal, sagittal and oblique images. +
+
+ + Number of samples (planes) in this image. See C.8.2.1.1.2 for specialization. +
For CT Images, Samples per Pixel (0028,0002) shall have an Enumerated Value of 1. +
+
+ + Specifies the intended interpretation of the pixel data. See C.8.2.1.1.3 for specialization. +
For CT Images, Photometric Interpretation (0028,0004) shall have one of the following Enumerated Values: + MONOCHROME1 + MONOCHROME2 +See C.7.6.3.1.1.2 for definition of these terms. +
+
+ + Number of bits allocated for each pixel sample. Each sample shall have the same number of bits allocated. See C.8.2.1.1.4 for specialization. +
For CT Images, Bits Allocated (0028,0100) shall have the Enumerated Value of 16. +
+
+ + Number of bits stored for each pixel sample. Each sample shall have the same number of bits stored. See C.8.2.1.1.5 for specialization. +
For CT Images, Bits Stored (0028,0101) shall have the Enumerated Values of 12 to 16. +
+
+ + Most significant bit for pixel sample data. Each sample shall have the same high bit. See C.8.2.1.1.6 for specialization. +
For CT Images, High Bit (0028,0102) shall have only the Enumerated Value of one less than the value sent in Bits Stored. +
+
+ + The value b in relationship between stored values (SV) and Hounsfield (HU). HU = m*SV+b + + + m in the equation specified in Rescale Intercept (0028,1052). + + + Peak kilo voltage output of the x-ray generator used + + + A number identifying the single continuous gathering of data over a period of time which resulted in this image + + + Parameters of scanning sequence. + + + The diameter in mm of the region over which data were collected + + + The x, y, and z coordinates (in the patient coordinate system) in mm of the center of the region in which data were collected. See C.8.15.3.6.1. +
In Figure C.8-19 the relationship of the Geometric Attributes within the CT Geometry and CT Reconstruction functional groups is shown. The figure, viewed from the front of the gantry (where the table enters the gantry), is informative only and is not meant to represent a standardization of an equipment-based frame of reference. + Figure C.8-19: Geometry of CT Acquisition System + +
+
+ + Diameter in mm of the region from within which data were used in creating the reconstruction of the image. Data may exist outside this region and portions of the patient may exist outside this region. + + + The x, y, and z coordinates (in the patient coordinate system) of the reconstruction center target point as used for reconstruction in mm. See C.8.15.3.6.1. +Note: If the reconstructed image is not magnified or panned the value corresponds with the Data Collection Center (Patient) (0018,9313) attribute. +
In Figure C.8-19 the relationship of the Geometric Attributes within the CT Geometry and CT Reconstruction functional groups is shown. The figure, viewed from the front of the gantry (where the table enters the gantry), is informative only and is not meant to represent a standardization of an equipment-based frame of reference. + Figure C.8-19: Geometry of CT Acquisition System + +
+
+ + Distance in mm from source to detector center. +Note: This value is traditionally referred to as Source Image Receptor Distance (SID). + + + Distance in mm from source to isocenter (center of field of view). +Note: This value is traditionally referred to as Source Object Distance (SOD). + + + Nominal angle of tilt in degrees of the scanning gantry. Not intended for mathematical computations. + + + The distance in mm of the top of the patient table to the center of rotation; below the center is positive. + + + Direction of rotation of the source when relevant, about nearest principal axis of equipment. +Enumerated Values: +CW = clockwise +CC = counter clockwise + + + Time of x-ray exposure in msec + + + X-Ray Tube Current in mA. + + + The exposure expressed in mAs, for example calculated from Exposure Time and X-Ray Tube Current. + + + The exposure expressed in µAs, for example calculated from Exposure Time and X-Ray Tube Current. + + + Label for the type of filter inserted into the x-ray beam. + + + Power in kW to the x-ray generator. + + + Size of the focal spot in mm. For devices with variable focal spot or multiple focal spots, small dimension followed by large dimension. + + + A label describing the convolution kernel or algorithm used to reconstruct the data + + + The time in seconds of a complete revolution of the source around the gantry orbit. + + + The width of a single row of acquired data (in mm). +Note: Adjacent physical detector rows may have been combined to form a single effective acquisition row. + + + The width of the total collimation (in mm) over the area of active x-ray detection. +Note: This will be equal the number of effective detector rows multiplied by single collimation width. + + + The distance in mm that the table moves in one second during the gathering of data that resulted in this image. + + + Motion of the table (in mm) during a complete revolution of the source around the gantry orbit. + + + Ratio of the Table Feed per Rotation (0018,9310) to the Total Collimation Width (0018,9307). + + + A label describing the type of exposure modulation used for the purpose of limiting the dose. +Defined Terms: +NONE + + + A percent value of dose saving due to the use of Exposure Modulation Type (0018,9323). A negative percent value of dose savings reflects an increase of exposure. + + + Computed Tomography Dose Index (CTDIvol), im mGy according to IEC 60601-2-44, Ed.2.1 (Clause 29.1.103.4), The Volume CTDIvol. It describes the average dose for this image for the selected CT conditions of operation. + + + The type of phantom used for CTDI measurement according to IEC 60601-2-44. Only a single Item shall be permitted in this Sequence. + + + + + The calibration factor for the calcium mass score. These factors incorporate the effects of +See C.8.2.1.1.7. +
The calibration factors for the Calcium Scoring Mass Factor Patient (0018,9351) and Calcium Scoring Mass Factor Device (0018,9352) attributes are defined by the International Consortium for Multi-Detector CT Evaluation of Coronary Calcium, see McCollough, C.H. “A multi-institutional, multi-manufacturer, international standard for the quantification of coronary artery calcium using cardiac CTâ€. +
+
+ + The calibration factors for the calcium mass score of the device. These factors incorporate the effects of +This a multi-value attribute, the first value specifies the mass factor for a small patient size, the second value for a medium patient size and the third value for a large patient size. +See C.8.2.1.1.7. +
The calibration factors for the Calcium Scoring Mass Factor Patient (0018,9351) and Calcium Scoring Mass Factor Device (0018,9352) attributes are defined by the International Consortium for Multi-Detector CT Evaluation of Coronary Calcium, see McCollough, C.H. “A multi-institutional, multi-manufacturer, international standard for the quantification of coronary artery calcium using cardiac CTâ€. +
+
+ + Contains the attributes defining the data acquisition in a multiple X-Ray source system beyond the primary source. The primary X-Ray source is specified in other attributes of this module. +One or more items may be present. + + + Peak kilo voltage output of the X-Ray generator used. + + + Nominal X-Ray tube current in milliamperes. + + + The diameter in mm of the region over which data were collected. + + + Used nominal size of the focal spot in mm. + + + Type of filter(s) inserted into the X-Ray beam. + + + The X-Ray absorbing material used in the filter. + +
+ + + Image identification characteristics. See C.8.3.1.1.1 for specialization. +
For MR Images, Image Type (0008,0008) is specified to be Type 1 and use one of the following Defined Terms for Value 3: + +
+
+ + Number of samples (planes) in this image. See C.8.3.1.1.2 for specialization. +
For MR Images, Samples per Pixel (0028,0002) shall have an Enumerated Value of 1. +
+
+ + Specifies the intended interpretation of the pixel data. See C.8.3.1.1.3 for specialization. +
For MR Images, Photometric Interpretation (0028,0004) shall have one of the following Enumerated Values: + MONOCHROME1 + MONOCHROME2 +See C.7.6.3.1.2 for definition of these terms. +
+
+ + Number of bits allocated for each pixel sample. Each sample shall have the same number of bits allocated. See C.8.3.1.1.4 for specialization. +
For MR Images, Bits Allocated (0028,0100) shall have the Enumerated Value of 16. +
+
+ + Description of the type of data taken. +Enumerated Values: +SE = Spin Echo +IR = Inversion Recovery +GR = Gradient Recalled +EP = Echo Planar +RM = Research Mode +Note: Multi-valued, but not all combinations are valid (e.g. SE/GR, etc.). + + + Variant of the Scanning Sequence. +Defined Terms: +SK = segmented k-space +MTC = magnetization transfer +contrast +SS = steady state +TRSS = time reversed steady +state +SP = spoiled +MP = MAG prepared +OSP = oversampling phase +NONE = no sequence variant + + + Parameters of scanning sequence. Defined Terms: +PER = Phase Encode +Reordering +RG = Respiratory Gating +CG = Cardiac Gating +PPG = Peripheral Pulse Gating +FC = Flow Compensation +PFF = Partial Fourier - +Frequency +PFP = Partial Fourier - Phase +SP = Spatial Presaturation +FS = Fat Saturation + + + Identification of data encoding scheme. Enumerated Values: +2D = frequency x phase +3D = frequency x phase x phase + + + The period of time in msec between the beginning of a pulse sequence and the beginning of the succeeding (essentially identical) pulse sequence. Required except when Scanning Sequence (0018,0020) is EP and Sequence Variant (0018,0021) is not SK. + + + Time in ms between the middle of the excitation pulse and the peak of the echo produced (kx=0). In the case of segmented k-space, the TE(eff) is the time between the middle of the excitation pulse to the peak of the echo that is used to cover the center of k-space (i.e.-kx=0, ky=0). + + + Number of lines in k-space acquired per excitation per image. + + + Time in msec after the middle of inverting RF pulse to middle of excitation pulse to detect the amount of longitudinal magnetization. Required if Scanning Sequence (0018,0020) has values of IR. + + + Time, in msec, between peak of the R wave and the peak of the echo produced. In the case of segmented k-space, the TE(eff) is the time between the peak of the echo that is used to cover the center of k-space. Required for Scan Options (0018,0022) which include heart gating (e.g. CG, PPG, etc.) + + + User defined name for the Scanning Sequence (0018,0020) and Sequence Variant (0018,0021) combination. + + + Angio Image Indicator. Primary image for Angio processing. Enumerated Values: +Y = Image is Angio +N = Image is not Angio + + + Number of times a given pulse sequence is repeated before any parameter is changed + + + Precession frequency in MHz of the nucleus being addressed + + + Nucleus that is resonant at the imaging frequency. Examples: 31P, 1H + + + The echo number used in generating this image. In the case of segmented k-space, it is the effective Echo Number. + + + Nominal field strength of MR magnet, in Tesla + + + Spacing between slices, in mm. The spacing is measured from the center-to-center of each slice. + + + Total number of lines in k-space in the 'y' direction collected during acquisition. + + + Fraction of acquisition matrix lines acquired, expressed as a percent. + + + Ratio of field of view dimension in phase direction to field of view dimension in frequency direction, expressed as a percent. + + + Reciprocal of the total sampling period, in hertz per pixel. + + + Average R-R interval used for the scans, in msec + + + Beat length sorting has been applied. +Enumerated Values: +Y = yes +N = No + + + R-R interval low limit for beat rejection, in msec + + + R-R interval high limit for beat rejection, in msec + + + Number of R-R intervals acquired. + + + Number of R-R intervals rejected. + + + Description of type of PVC rejection criteria used. + + + Number of beats skipped after a detected arrhythmia. + + + Beats per minute. + + + Number of images per cardiac cycle. + + + Percent of R-R interval, based on Heart Rate (0018,1088), prescribed as a window for a valid/usable trigger. + + + Diameter in mm. of the region from within which data were used in creating the reconstruction of the image. Data may exist outside this region and portions of the patient may exist outside this region. + + + Receive coil used. + + + Transmit coil used. + + + Dimensions of the acquired frequency /phase data before reconstruction. +Multi-valued: frequency rows\frequency columns\phase rows\phase columns. + + + The axis of phase encoding with respect to the image. Enumerated Values: +ROW = phase encoded in rows. +COL = phase encoded in columns. + + + Steady state angle in degrees to which the magnetic vector is flipped from the magnetic vector of the primary field. + + + Calculated whole body Specific Absorption Rate in watts/kilogram. + + + Flip angle variation applied during image acquisition. Enumerated Values: +Y = yes +N = no + + + The rate of change of the gradient coil magnetic flux density with time (T/s). + + + Temporal order of a dynamic or functional set of Images. + + + Total number of temporal positions prescribed. + + + Time delta between Images in a dynamic or functional set of Images. + + +
+ + + Sequence that describes the orientation of the patient with respect to gravity. See C.8.4.6.1.1 for further explanation. Zero or one item shall be present in the sequence. +
The Patient Orientation Code Sequence (0054,0410) is used to describe the orientation of the patient with respect to gravity, and is independent of the position in the gantry. +
+
+ + + Patient Orientation Modifier. Required if needed to fully specify the orientation of the patient with respect to gravity. See C.8.4.6.1.2 for further explanation. Zero or one item shall be present in the sequence. +
The Patient Orientation Modifier Code Sequence (0054,0412) is used to modify or enhance the orientation specified by Patient Orientation Code Sequence (0054,0410). +
+
+ + + Sequence which describes the orientation of the patient with respect to the gantry. See Section C.8.4.6.1.3 for further explanation. Zero or one item shall be present in the sequence. +
Patient Gantry Relationship Code Sequence (0054,0414) is used to describe the patient direction within the gantry, such as head-first or feet-first. When imaging the extremities, these directions are related to normal anatomic position. +Example: In normal anatomic position, the fingers point towards the feet. +
+
+ +
+ + + Number of samples (color planes) in this image. The value shall be 1. + + + Specifies the intended interpretation of the pixel data. See C.8.4.7.1.1 for further explanation. +
For NM Images, Photometric Interpretation (0028,0004) shall have one of the following Enumerated Values: +MONOCHROME2 +PALETTE COLOR +See C.7.6.3.1.2 for definition of these terms. +
+
+ + Number of bits allocated for each pixel sample. Each sample shall have the same number of bits allocated. +Enumerated Values: 8, 16. + + + Number of bits stored for each pixel sample. Each sample shall have the same number of bits stored. +The value shall be the same as the value in Bits Allocated (0028,0100). + + + Most significant bit for pixel sample data. Each sample shall have the same high bit. +Shall be one less than the value in Bits Stored (0028,0101). + + + Physical distance in the patient between the center of each pixel, specified by a numeric pair - adjacent row spacing (delimiter) adjacent column spacing, in mm. See 10.7.1.3 for further explanation of the value order. + +
+ + + Contains the Data Element Tags of one or more frame index vectors. See C.8.4.8.1.1 for further specialization. +
By definition, NM Images are multi-dimensional Multi-frame Images. The value of the Frame Increment Pointer (0028,0009) contains the Tag for one or more frame indexing vectors. This determines the number of dimensions of frame indices in the image, and the order in which these indices vary from one frame to the next, with the last Tag indicating the most rapidly changing index. The Enumerated Values for the Frame Increment Pointer (0028,0009) are determined by the Image Type (0008,0008), Value 3, as shown in Table C.8-8. +Table C.8-8 +ENUMERATED VALUES FOR FRAME INCREMENT POINTER + +
+
+ + An array which contains the energy window number for each frame. Required if the value of the Frame Increment Pointer (0028,0009) includes the Tag for Energy Window Vector (0054,0010). See C.8.4.8.1.2 for specialization. +
Number of Energy Windows (0054,0011) is the number of distinct energy window groupings acquired in this image. See C.8.4.10.1. When Image Type (0008,0008), Value 3, is RECON TOMO or RECON GATED TOMO, then the Number of Energy Windows (0054,0011) shall be 1. +Energy Window Vector (0054,0010) is an indexing vector. The value of the nth element of this vector is the energy window number for the nth frame in this image, and shall have a value from 1 to Number of Energy Windows (0054,0011). +
+
+ + Number of energy window groupings. See C.8.4.8.1.2 for specialization. +
Number of Energy Windows (0054,0011) is the number of distinct energy window groupings acquired in this image. See C.8.4.10.1. When Image Type (0008,0008), Value 3, is RECON TOMO or RECON GATED TOMO, then the Number of Energy Windows (0054,0011) shall be 1. +Energy Window Vector (0054,0010) is an indexing vector. The value of the nth element of this vector is the energy window number for the nth frame in this image, and shall have a value from 1 to Number of Energy Windows (0054,0011). +
+
+ + An array which contains the detector number for each frame. Required if the value of the Frame Increment Pointer (0028,0009) includes the Tag for Detector Vector (0054,0020). See C.8.4.8.1.3 for specialization. +
Number of Detectors (0054,0021) is the number of separate detectors which differentiate the frames in this image. When Image Type (0008,0008), Value 3, is RECON TOMO or RECON GATED TOMO, then the Number of Detectors (0054,0021) shall be 1. +Note: Number of Detectors (0054,0021) does not necessarily represent the actual number of detectors used during data acquisition. + Example 1: In a TOMO acquisition in which frames from 2 or more detectors are interleaved to form one continuous set of frames, then no distinction is made between frames on the basis of which detector created them. In this case, the Number of Detectors (0054,0021) would be 1. + Example 2: In a WHOLE BODY acquisition in which a single detector acquires anterior and posterior views in two separate passes, the Number of Detectors (0054,0021) would be 2. + +Detector Vector (0054,0020) is an indexing vector. The value of the nth element of this vector is the detector number of the nth frame in this image, and shall have a value from 1 to Number of Detectors (0054,0021). +
+
+ + Number of detectors. See C.8.4.8.1.3 for specialization. +
Number of Detectors (0054,0021) is the number of separate detectors which differentiate the frames in this image. When Image Type (0008,0008), Value 3, is RECON TOMO or RECON GATED TOMO, then the Number of Detectors (0054,0021) shall be 1. +Note: Number of Detectors (0054,0021) does not necessarily represent the actual number of detectors used during data acquisition. + Example 1: In a TOMO acquisition in which frames from 2 or more detectors are interleaved to form one continuous set of frames, then no distinction is made between frames on the basis of which detector created them. In this case, the Number of Detectors (0054,0021) would be 1. + Example 2: In a WHOLE BODY acquisition in which a single detector acquires anterior and posterior views in two separate passes, the Number of Detectors (0054,0021) would be 2. + +Detector Vector (0054,0020) is an indexing vector. The value of the nth element of this vector is the detector number of the nth frame in this image, and shall have a value from 1 to Number of Detectors (0054,0021). +
+
+ + An array which contains the phase number for each frame. Required if the value of the Frame Increment Pointer (0028,0009) includes the Tag for Phase Vector (0054,0030). See C.8.4.8.1.4 for specialization. +
Number of Phases (0054,0031) is the number of dynamic phases, independent of the number of Detectors and Isotopes. See Section C.8.4.14 for definition of a phase. +Phase Vector (0054,0030) is an indexing vector. The value of the nth element of this vector is the phase number of the nth frame in this image, and shall have a value from 1 to Number of Phases (0054,0031). +
+
+ + Number of phases. Required if the value of the Frame Increment Pointer (0028,0009) includes the Tag for Phase Vector (0054,0030). See C.8.4.8.1.4 for specialization. +
Number of Phases (0054,0031) is the number of dynamic phases, independent of the number of Detectors and Isotopes. See Section C.8.4.14 for definition of a phase. +Phase Vector (0054,0030) is an indexing vector. The value of the nth element of this vector is the phase number of the nth frame in this image, and shall have a value from 1 to Number of Phases (0054,0031). +
+
+ + An array which contains the rotation number for each frame. Required if the value of the Frame Increment Pointer (0028,0009) includes the Tag for Rotation Vector (0054,0050). See C.8.4.8.1.5 for specialization. +
Number of Rotations (0054,0051) is the number of separate rotations. See Section C.8.4.12 for definition of a rotation. When Image Type (0008,0008), Value 3, is RECON TOMO, GATED TOMO or RECON GATED TOMO, then the Number of Rotations (0054,0051) shall be 1. +Rotation Vector (0054,0050) is an indexing vector. The value of the nth element of this vector is the rotation number of the nth frame in this image, and shall have a value from 1 to Number of Rotations (0054,0051). +
+
+ + Number of rotations. Required if Image Type (0008,0008), Value 3 is +TOMO, +GATED TOMO, +RECON TOMO, or +RECON GATED TOMO. +See C.8.4.8.1.5 for specialization. +
Number of Rotations (0054,0051) is the number of separate rotations. See Section C.8.4.12 for definition of a rotation. When Image Type (0008,0008), Value 3, is RECON TOMO, GATED TOMO or RECON GATED TOMO, then the Number of Rotations (0054,0051) shall be 1. +Rotation Vector (0054,0050) is an indexing vector. The value of the nth element of this vector is the rotation number of the nth frame in this image, and shall have a value from 1 to Number of Rotations (0054,0051). +
+
+ + An array which contains the R-R interval number for each frame. Required if the value of the Frame Increment Pointer (0028,0009) includes the Tag for R-R Interval Vector (0054,0060). See C.8.4.8.1.6 for specialization. +
Number of R-R Intervals (0054,0061) is the number of ranges of heartbeat durations collected. A gated acquisition may employ one R-R Interval to collect data from normal beats, a second R-R Interval to collect data from ectopic beats, and possibly others. Each R-R Interval accepts beats whose duration is greater than its Low R-R Value (0018,1081) and shorter than its High R-R Value (0018,1082). Beats which do not fall within these ranges may be accepted by another R-R Interval, or may be rejected. +The Number of R-R Intervals (0054,0061) is the total number of such ranges. +R-R Interval Vector (0054,0060) is an indexing vector. The value of the nth element of this vector is the interval number of the nth frame in this image, and shall have a value from 1 to Number of R-R Intervals (0054,0061). +
+
+ + Number of R-R intervals. Required if the value of the Frame Increment Pointer (0028,0009) includes the Tag for R-R Interval Vector (0054,0060). See C.8.4.8.1.6 for specialization. +
Number of R-R Intervals (0054,0061) is the number of ranges of heartbeat durations collected. A gated acquisition may employ one R-R Interval to collect data from normal beats, a second R-R Interval to collect data from ectopic beats, and possibly others. Each R-R Interval accepts beats whose duration is greater than its Low R-R Value (0018,1081) and shorter than its High R-R Value (0018,1082). Beats which do not fall within these ranges may be accepted by another R-R Interval, or may be rejected. +The Number of R-R Intervals (0054,0061) is the total number of such ranges. +R-R Interval Vector (0054,0060) is an indexing vector. The value of the nth element of this vector is the interval number of the nth frame in this image, and shall have a value from 1 to Number of R-R Intervals (0054,0061). +
+
+ + An array which contains the time slot number for each frame. Required if the value of the Frame Increment Pointer (0028,0009) includes the Tag for Time Slot Vector (0054,0070). See C.8.4.8.1.7 for specialization. +
Number of Time Slots (0054,0071) is the number of frames into which each gating event is divided in a gated acquisition. For example, in a cardiac gated acquisition, data from a number of heartbeats are then combined by summing together the first frames from all beats into a summed first frame, all the second frames into a summed second frame, and so on. The result has the same number of frames as the Number of Time Slots in each beat. +Time Slot Vector (0054,0070) is an indexing vector. The value of the nth element of this vector is the time slot number of the nth frame in this image, and shall have a value from 1 to Number of Time Slots (0054,0071). +
+
+ + Number of time slots. Required if the value of the Frame Increment Pointer (0028,0009) includes the Tag for Time Slot Vector (0054,0070). See C.8.4.8.1.7 for specialization. +
Number of Time Slots (0054,0071) is the number of frames into which each gating event is divided in a gated acquisition. For example, in a cardiac gated acquisition, data from a number of heartbeats are then combined by summing together the first frames from all beats into a summed first frame, all the second frames into a summed second frame, and so on. The result has the same number of frames as the Number of Time Slots in each beat. +Time Slot Vector (0054,0070) is an indexing vector. The value of the nth element of this vector is the time slot number of the nth frame in this image, and shall have a value from 1 to Number of Time Slots (0054,0071). +
+
+ + An array which contains the spatial slice number for each frame. Required if the value of the Frame Increment Pointer (0028,0009) includes the Tag for Slice Vector (0054,0080). See C.8.4.8.1.8 for specialization. +
Number of Slices (0054,0081) is the number of slices in each separate volume. +Note: For images with Image Type (0008,0008), Value 3, equal to RECON GATED TOMO this implies that Number of Slices (0054,0081) is the same for all R-R Intervals and Time Slots. + +Slice Vector (0054,0080) is an indexing vector. The value of the nth element of this vector is the slice number of the nth frame in this image, and shall have a value from 1 to Number of Slices (0054,0081). +
+
+ + Number of slices. Required if the value of the Frame Increment Pointer (0028,0009) includes the Tag for Slice Vector (0054,0080). See C.8.4.8.1.8 for specialization. +
Number of Slices (0054,0081) is the number of slices in each separate volume. +Note: For images with Image Type (0008,0008), Value 3, equal to RECON GATED TOMO this implies that Number of Slices (0054,0081) is the same for all R-R Intervals and Time Slots. + +Slice Vector (0054,0080) is an indexing vector. The value of the nth element of this vector is the slice number of the nth frame in this image, and shall have a value from 1 to Number of Slices (0054,0081). +
+
+ + An array which contains the angular view number for each frame. Required if the value of the Frame Increment Pointer (0028,0009) includes the Tag for Angular View Vector (0054,0090). See C.8.4.8.1.9 for specialization. +
Angular View Vector (0054,0090) is an indexing vector. The value of the nth element of this vector is the angular view number of the nth frame in this image. If Image Type (0008,0008), Value 3, is TOMO or GATED TOMO, then the value shall be from 1 to Number of Frames in Rotation (0054,0053). +
+
+ + An array which contains the time slice number for each frame. Required if the value of the Frame Increment Pointer (0028,0009) includes the Tag for Time Slice Vector (0054,0100). See C.8.4.8.1.10 for specialization. +
Time Slice Vector (0054,0100) is an indexing vector. The value of the nth element of this vector is the time slice number of the nth frame in this image, and shall have a value from 1 to Number of Frames in Phase (0054,0033). +
+
+
+ + + Image identification characteristics. See C.8.4.9.1.1 for specialization. +
For NM images, Image Type (0008,0008) Value 3 is specified to be Type 1 and use one of the following Enumerated Values: +STATIC +DYNAMIC +GATED +WHOLE BODY +TOMO +GATED TOMO +RECON TOMO +RECON GATED TOMO + +For NM images, Image Type (0008,0008) Value 4 is specified to use one of the following Enumerated Values: +EMISSION +TRANSMISSION +Note: For NM images, Image Type (0008,0008) Value 1 will be ORIGINAL for all raw data and reconstructed images. DERIVED may be appropriate for some other results images. + For NM images, Image Type (0008,0008) Value 2 will be PRIMARY. + +
+
+ + User or equipment generated Image identifier. + + + Specifies whether an Image has undergone lossy compression. Enumerated Values: +00 = Image has NOT been subjected to lossy compression. +01 = Image has been subjected to lossy compression. +See C.7.6.1.1.5 +Required if Lossy Compression has been performed on the Image. +
The Attribute Lossy Image Compression (0028,2110) conveys that the Image has undergone lossy compression. It provides a means to record that the Image has been compressed (at a point in its lifetime) with a lossy algorithm and changes have been introduced into the pixel data. Once the value has been set to “01â€, it shall not be reset. +Note: If an image is compressed with a lossy algorithm, the attribute Lossy Image Compression (0028,2110) is set to “01â€. Subsequently, if the image is decompressed and transferred in uncompressed format, this attribute value remains “01â€. + +The value of the Lossy Image Compression (0028,2110) Attribute in SOP Instances containing multiple frames in which one or more of the frames have undergone lossy compression shall be “01â€. +Note: It is recommended that the applicable frames be noted in the Attribute Derivation Description (0008,2111). + +If an image is originally obtained as a lossy compressed image from the sensor, then Lossy Image Compression (0028,2110) is set to “01†and Value 1 of the Attribute Image Type (0008,0008) shall be set to ORIGINAL. +If an image is a compressed version of another image, Lossy Image Compression (0028,2110) is set to “01â€, Value 1 of the Attribute Image Type (0008,0008) shall be set to DERIVED, and if the predecessor was a DICOM image, then the Image shall receive a new SOP Instance UID. +Note: 1. It is recommended that the approximate compression ratio be provided in the Attribute Derivation Description (0008,2111). Furthermore, it is recommended that Derivation Description (0008,2111) be used to indicate when pixel data changes might affect professional interpretation. (see C.7.6.1.1.3). + 2. The attribute Lossy Image Compression (0028,2110) is defined as Type 3 for backward compatibility with existing IODs. It is expected to be required (i.e., defined as Type 1C) for new Image IODs and for existing IODs that undergo a major revision (e.g. a new IOD is specified). +The Defined Terms for Lossy Image Compression Method (0028,2114) are: +ISO_10918_1 = JPEG Lossy Compression +ISO_14495_1 = JPEG-LS Near-lossless Compression +ISO_15444_1 = JPEG 2000 Irreversible Compression +ISO_13818_2 = MPEG2 Compression + +
+
+ + Sum of all gamma events for all frames in the image. See C.8.4.9.1.2 for specialization. +
Counts Accumulated (0018,0070) is the total of all gamma events accumulated in all frames of this Image. This attribute applies to acquisition data, and often does not apply to processed images (DERIVED, SECONDARY). +
+
+ + Description of how the data collection was stopped. Defined Terms: +CNTS = counts +DENS = density +MANU = manual +OVFL = data overflow +TIME = time +TRIG = physiological trigger +See C.8.4.9.1.3 for specialization. +
Acquisition Termination Condition (0018,0071) is the method of acquisition termination which was actually applied to the data collection. The Defined Terms and definitions are: +CNTS = preset count limit was reached +DENS = preset count density was reached +MANU = acquisition was terminated manually +OVFL = acquisition was terminated automatically by pixel data overflow condition +TIME = preset time limit was reached +TRIG = preset number of physiological triggers was reached + +
+
+ + The height of the patient table in mm. The range and values of this element are determined by the manufacturer. Should not be included if Image Type (0008,0008), Value 3, is +TOMO, +GATED TOMO, +RECON TOMO or +RECON GATED TOMO. + + + Location of the patient table (or gantry relative to the table) in mm. The range and values of this element are determined by the manufacturer. Should not be included if Image Type (0008,0008), Value 3, is +TOMO, +GATED TOMO, +RECON TOMO or +RECON GATED TOMO. + + + Elapsed time for data acquisition in msec. Required if Image Type (0008,0008) Value 3 is: +WHOLE BODY or +STATIC. +See C.8.4.9.1.4 for specialization. +
Actual Frame Duration (0018,1242) is defined as the elapsed time in msec for a single frame of an acquisition. For some types of multi-frame images, Actual Frame Duration (0018,1242) may have a more specialized meaning as defined in the appropriate IOD Module. + +
+
+ + Maximum count rate achieved during the acquisition in counts/sec. + + + Code or description of processing functions applied to the data. + + + A value that indicates which, if any, corrections have been applied to the image. Corrections are applied to all frames in the image. Defined Terms: +UNIF = flood corrected +COR = center of rotation corrected +NCO = non-circular orbit corrected +DECY = decay corrected +ATTN = attenuation corrected +SCAT = scatter corrected +DTIM = dead time corrected +NRGY = energy corrected +LIN = linearity corrected +MOTN = motion corrected +CLN = count loss normalization; Any type of normalization applied to correct for count loss in Time Slots. + + + The type of scan performed. Used only if Image Type (0008,0008), Value 3, contains the value WHOLE BODY. Enumerated Values: +1PS = one pass +2PS = two pass +PCN = patient contour following +employed +MSP = multiple static frames +collected into a whole +body frame. + + + The speed of the camera motion over the body in mm/sec. +Required if Image Type (0008,0008) Value 3 contains the value WHOLE BODY. + + + Size of the imaged area in the direction of scanning motion, in mm. Required if Image Type (0008,0008) Value 3 contains the value WHOLE BODY. + + + Text indicating trigger source. Defined Term: +EKG + + +
+ + + Sequence of Items that describe the energy window groups used. Zero or more Items may be included in this sequence. +The number of items shall be equal to Number of Energy Windows (0054,0011). The first item corresponds to frames with value of 1 in the Energy Window Vector (0054,0010), the second item with value 2, etc. + + + A user defined name which describes this Energy Window. + + + Sequence of Items that describes this energy window group. One or more Items may be included in this Sequence. + + + The lower limit of the energy window in KeV. See C.8.4.10.1.1 for further explanation. +
Energy Window Lower Limit (0054,0014) is the acquisition energy window lower limit in KeV for acceptance of scintillation events into this Isotope. +
+
+ + The upper limit of the energy window in KeV. See C.8.4.10.1.2 for further explanation. +
Energy Window Upper Limit (0054,0015) is the acquisition energy window upper limit in KeV for acceptance of scintillation events into this Isotope. +
+
+ + Sequence of Items that describe isotope information. Zero or more Items may be included in this sequence. + + + Sequence that identifies the radionuclide. Zero or one item shall be present in the sequence. + + + + Route of injection. + + + Sequence that identifies the administration route for the radiopharmaceutical. This sequence shall contain exactly one item. + + + + Volume of injection in cubic cm. + + + Time of start of injection. See C.8.4.10.1.5 for further explanation. +
Radiopharmaceutical Start Time (0018,1072) is the actual time of radiopharmaceutical administration to the patient for imaging purposes, using the same time base as for the Acquisition Start Time (0008,0032). +
+
+ + Time of end of injection. See C.8.4.10.1.6 for further explanation. +
Radiopharmaceutical Stop Time (0018,1073) is the actual ending time of radiopharmaceutical administration to the patient for imaging purposes, using the same time base as for the Acquisition Start Time (0008,0032). +
+
+ + Total amount of radionuclide injected. See C.8.4.10.1.7 for further explanation. +
Radionuclide Total Dose (0018,1074) is the radiopharmaceutical dose administered to the patient measured in MegaBecquerels (Mbq) at the Radiopharmaceutical Start Time. +
+
+ + Sequence that contains calibration data. One or more Items may be included in this Sequence. + + + The Item number in the Energy Window Information Sequence to which the following calibration data relates. The Items are numbered starting from 1. + + + Pre-injection syringe count rate in counts/sec. See C.8.4.10.1.8 for further explanation. +
Syringe Counts (0018,1045) is the pre-injection syringe acquisition count rate measured in counts/sec, corrected to the Acquisition Start Time (0008,0032) if necessary. +
+
+ + Post-injection residue syringe count rate in counts/sec. See C.8.4.10.1.9 for further explanation. +
Residual Syringe Counts (0054,0017) is the syringe acquisition count rate following patient injection, measured in counts/sec, corrected to the Acquisition Start Time (0008,0032) if necessary. +
+
+ + Name of the radiopharmaceutical. + + + Sequence that identifies the radiopharmaceutical. This sequence shall contain exactly one item. + + + + Sequence of Items that describes the intervention drugs used. Zero or more Items may be included in this sequence. + + + Name of intervention drug. + + + Sequence that identifies the intervention drug name. Only a single Item shall be permitted in this Sequence. + + + + Sequence that identifies the administration route for the intervention drug. This sequence shall contain exactly one item. + + + + Time of administration of the intervention drug, using the same time base as for the Acquisition Start Time (0008,0032). + + + Time of completion of administration of the intervention drug, using the same time base as for the Acquisition Start Time (0008,0032). + + + Intervention drug dose, in mg. + +
+ + + Sequence of Items that describe the detectors used. Zero or more Items may be included in this sequence. +The number of items shall be equal to Number of Detectors (0054,0021). The first item corresponds to frames with value of 1 in the Detector Vector (0054,0020), the second item with value 2, etc. + + + Label describing the collimator used (LEAP, hires, etc.) + + + Collimator type. Defined Terms: +PARA = Parallel (default) +PINH = Pinhole +FANB = Fan-beam +CONE = Cone-beam +SLNT = Slant hole +ASTG = Astigmatic +DIVG = Diverging +NONE = No collimator +UNKN = Unknown + + + + Shape of the field of view of the Nuclear Medicine detector. Defined Terms: +RECTANGLE +ROUND +HEXAGONAL + + + Dimensions of the field of view, in mm. If Field of View Shape (0018,1147) is: +RECTANGLE: row dimension followed by column. +ROUND: diameter. +HEXAGONAL: diameter of a circumscribed circle. + + + Focal distance, in mm. A value of 0 means infinite distance for parallel collimation. See C.8.4.11.1.1 for further specialization. +
Focal Distance (0018,1182) for NM Image data is the focal distance, in mm for converging or diverging collimators, measured from the front face of the detector to the focus. Positive values indicate converging and negative values indicate diverging collimators. A value of 0 means infinite distance for parallel collimation. +
+
+ + Center of focus along a row. See C.8.4.11.1.2 for further explanation. +
X Focus Center (0018,1183) and Y Focus Center (0018,1184) for NM Image data is used to define the projection of the focus for a converging or diverging collimator within the un-zoomed Field of View. It is defined in mm for row and column relative to the center of the un-zoomed Field of View. +
+
+ + Center of focus along a column. See C.8.4.11.1.2 for further explanation. +
X Focus Center (0018,1183) and Y Focus Center (0018,1184) for NM Image data is used to define the projection of the focus for a converging or diverging collimator within the un-zoomed Field of View. It is defined in mm for row and column relative to the center of the un-zoomed Field of View. +
+
+ + The amount of offset from (0,0) applied to each pixel in the image before application of the zoom factor, specified by a numeric pair: row value (delimiter) column value (in mm). See C.8.4.11.1.3 for further explanation. +
Zoom Center (0028,0032) is the offset between the un-zoomed camera field of view and field of view, measured from the center of the un-zoomed camera field of view to the center the of the zoomed field of view. The offset is measured in mm in the un-zoomed camera FOV dimensions. Positive values are to the right and down from the un-zoomed center, as viewed from the image plane. When this attribute is not given, the Zoom Center is assumed to be 0\0. +
+
+ + The amount of magnification applied to each pixel in the image, specified by a numeric pair: row value (delimiter) column value. See C.8.4.11.1.4 for further explanation. +
Zoom Factor (0028,0031) is the magnification factor that was used during the acquisition. When this attribute is not given, it is assumed to be 1.0\1.0. +Note: Zoom Factor (0028,0031) is informational only. Pixel Spacing (0028,0030) already takes account of this and any other changes to pixel size. + +
+
+ + Average center of rotation offset of Nuclear Medicine detector in mm. See C.8.4.11.1.5 for further explanation. +
Center of Rotation Offset (0018,1145) is the average amount of offset in mm between the Detector Field of View center and the physical center of rotation of the gantry for circular orbital scans. Positive values indicate the physical center is to the right of the image plane center. +If: +1) Image Type (0008,0008) Value 3 is TOMO or GATED TOMO, and +2) Corrected Image (0028,0051) does not include the value "COR", and +3) Center of Rotation Offset (0018,1145) is non-zero, +then the receiver should assume that Center of Rotation correction has not already been done. +If the Center of Rotation Offset is zero, no correction shall be applied. +
+
+ + Angle of tilt in degrees of the detector. See C.8.4.11.1.6 for further explanation. +
Gantry/Detector Tilt (0018,1120) for NM Image data is the angle in degrees of the detector face relative to the patient's major (Head to Feet) axis (or the table supporting the patient). Positive tilt is towards the patient’s feet. +
+
+ + Distance in mm from transmission source to the detector face. Required if Image Type (0008,0008) Value 4 is TRANSMISSION, Value 3 is not TOMO,. + + + Position of the detector about the patient for the start of the acquisition, in degrees. Zero degrees is referenced to the origin at the patient's back. Viewing from the patient's feet, angle increases in a counter-clockwise direction (detector normal rotating from the patient's back towards the patient's left side). Should not be included if Image Type (0008,0008), Value 3, is +TOMO, +GATED TOMO, +RECON TOMO or +RECON GATED TOMO. + + + Radial distance of the detector from the center of rotation, in mm. Should not be included if Image Type (0008,0008), Value 3, is +TOMO, +GATED TOMO, +RECON TOMO or +RECON GATED TOMO. + + + The direction cosines of the first row and the first column with respect to the patient. See C.7.6.2.1.1 for further explanation. +
The Image Position (0020,0032) specifies the x, y, and z coordinates of the upper left hand corner of the image; it is the center of the first voxel transmitted. Image Orientation (0020,0037) specifies the direction cosines of the first row and the first column with respect to the patient. These Attributes shall be provide as a pair. Row value for the x, y, and z axes respectively followed by the Column value for the x, y, and z axes respectively. +The direction of the axes is defined fully by the patient’s orientation. The x-axis is increasing to the left hand side of the patient. The y-axis is increasing to the posterior side of the patient. The z-axis is increasing toward the head of the patient. +The patient based coordinate system is a right handed system, i.e. the vector cross product of a unit vector along the positive x-axis and a unit vector along the positive y-axis is equal to a unit vector along the positive z-axis. +Note If a patient lies parallel to the ground, face-up on the table, with his feet-to-head direction same as the front-to-back direction of the imaging equipment, the direction of the axes of this patient based coordinate system and the equipment based coordinate system in previous versions of this Standard will coincide. + +The Image Plane Attributes, in conjunction with the Pixel Spacing Attribute, describe the position and orientation of the image slices relative to the patient-based coordinate system. In each image frame the Image Position (Patient) (0020,0032) specifies the origin of the image with respect to the patient-based coordinate system. RCS and the Image Orientation (Patient) (0020,0037) attribute values specify the orientation of the image frame rows and columns. The mapping of pixel location to the RCS is calculated as follows: + + size 12{ left [ matrix { +P rSub { size 8{x} } {} ## +P rSub { size 8{y} } {} ## +P rSub { size 8{z} } {} ## +1 +} right ]= left [ matrix { +X rSub { size 8{x} } Δi {} # Y rSub { size 8{x} } Δj {} # 0 {} # S rSub { size 8{x} } {} ## +X rSub { size 8{y} } Δi {} # Y rSub { size 8{y} } Δj {} # 0 {} # S rSub { size 8{y} } {} ## +X rSub { size 8{z} } Δi {} # Y rSub { size 8{z} } Δj {} # 0 {} # S rSub { size 8{z} } {} ## +0 {} # 0 {} # 0 {} # 1{} +} right ] left [ matrix { +i {} ## +j {} ## +0 {} ## +1 +} right ]} {} + + = M +Where: +Pxyz The coordinates of the voxel (i,j) in the frame’s image plane in units of mm. +Sxyz The three values of the Image Position (Patient) (0020,0032) attributes. It is the location in mm from the origin of the RCS. +Xxyz The values from the row (X) direction cosine of the Image Orientation (Patient) (0020,0037) attribute. +Yxyz The values from the column (Y) direction cosine of the Image Orientation (Patient) (0020,0037) attribute. +i Column index to the image plane. The first column is index zero. +ï„i Column pixel resolution of the Pixel Spacing (0028,0030) attribute in units of mm. +j Row index to the image plane. The first row index is zero. +ï„j Row pixel resolution of the Pixel Spacing (0028,0030) attribute in units of mm. + +Additional constraints apply: +1) The row and column direction cosine vectors shall be orthogonal, i.e. their dot product shall be zero. +2) The row and column direction cosine vectors shall be normal, i.e. the dot product of each direction cosine vector with itself shall be unity. + +
+
+ + The x, y, and z coordinates of the upper left hand corner (center of the first voxel transmitted) of the image, in mm. See C.7.6.2.1.1 for further explanation. +
The Image Position (0020,0032) specifies the x, y, and z coordinates of the upper left hand corner of the image; it is the center of the first voxel transmitted. Image Orientation (0020,0037) specifies the direction cosines of the first row and the first column with respect to the patient. These Attributes shall be provide as a pair. Row value for the x, y, and z axes respectively followed by the Column value for the x, y, and z axes respectively. +The direction of the axes is defined fully by the patient’s orientation. The x-axis is increasing to the left hand side of the patient. The y-axis is increasing to the posterior side of the patient. The z-axis is increasing toward the head of the patient. +The patient based coordinate system is a right handed system, i.e. the vector cross product of a unit vector along the positive x-axis and a unit vector along the positive y-axis is equal to a unit vector along the positive z-axis. +Note If a patient lies parallel to the ground, face-up on the table, with his feet-to-head direction same as the front-to-back direction of the imaging equipment, the direction of the axes of this patient based coordinate system and the equipment based coordinate system in previous versions of this Standard will coincide. + +The Image Plane Attributes, in conjunction with the Pixel Spacing Attribute, describe the position and orientation of the image slices relative to the patient-based coordinate system. In each image frame the Image Position (Patient) (0020,0032) specifies the origin of the image with respect to the patient-based coordinate system. RCS and the Image Orientation (Patient) (0020,0037) attribute values specify the orientation of the image frame rows and columns. The mapping of pixel location to the RCS is calculated as follows: + +P rSub { size 8{x} } {} ## +P rSub { size 8{y} } {} ## +P rSub { size 8{z} } {} ## +1 +} right ]= left [ matrix { +X rSub { size 8{x} } Δi {} # Y rSub { size 8{x} } Δj {} # 0 {} # S rSub { size 8{x} } {} ## +X rSub { size 8{y} } Δi {} # Y rSub { size 8{y} } Δj {} # 0 {} # S rSub { size 8{y} } {} ## +X rSub { size 8{z} } Δi {} # Y rSub { size 8{z} } Δj {} # 0 {} # S rSub { size 8{z} } {} ## +0 {} # 0 {} # 0 {} # 1{} +} right ] left [ matrix { +i {} ## +j {} ## +0 {} ## +1 +} right ]} {} + + = M +Where: +Pxyz The coordinates of the voxel (i,j) in the frame’s image plane in units of mm. +Sxyz The three values of the Image Position (Patient) (0020,0032) attributes. It is the location in mm from the origin of the RCS. +Xxyz The values from the row (X) direction cosine of the Image Orientation (Patient) (0020,0037) attribute. +Yxyz The values from the column (Y) direction cosine of the Image Orientation (Patient) (0020,0037) attribute. +i Column index to the image plane. The first column is index zero. +ï„i Column pixel resolution of the Pixel Spacing (0028,0030) attribute in units of mm. +j Row index to the image plane. The first row index is zero. +ï„j Row pixel resolution of the Pixel Spacing (0028,0030) attribute in units of mm. + +Additional constraints apply: +1) The row and column direction cosine vectors shall be orthogonal, i.e. their dot product shall be zero. +2) The row and column direction cosine vectors shall be normal, i.e. the dot product of each direction cosine vector with itself shall be unity. + +
+
+ + Sequence that describes the projection of the anatomic region of interest on the image receptor. Only a single Item shall be permitted in this sequence. + + + + View Modifier. Required if needed to fully specify the View. Zero or one Items shall be permitted in this sequence. + + +
+ + + Sequence of Items that describe TOMO rotational groups. A new rotation is defined whenever the direction of the detector motion changes, or the Table Traverse (0018,1131) changes. Zero or more Items may be included in this sequence. +The number of items shall be equal to Number of Rotations (0054,0051). If Rotation Vector (0054,0050) is present, the first item corresponds to frames with value of 1 in the Rotation Vector (0054,0050), the second item with value 2, etc. + + + Position of the detector about the patient for the start of this rotation, in degrees. Zero degrees is referenced to the origin at the patient's back. Viewing from the patient's feet, angle increases in a counter-clockwise direction (detector normal rotating from the patient's back towards the patient's left side). + + + The angular scan arc step between views of the TOMO acquisition, in degrees. See C.8.4.12.1.1 for further explanation. +
Angular Step (0018,1144) is the nominal frame-to-frame incremental angle for TOMO and GATED TOMO acquisition images, defined in degrees. The Angular Step (0018,1144) shall be a positive number. Summation of Angular Step values is not defined to give accurate Angular Position or Scan Arc values. The Angular Step is the effective angular spacing between resultant frames of the Multi-framed planar image data. +
+
+ + Direction of rotation of the detector about the patient. See Start Angle (0054,0200) for further explanation of direction. +Enumerated Values: +CW = clockwise (decreasing angle) +CC = counter-clockwise (increasing angle). + + + + The effective angular range of the scan data in degrees. The value shall be positive. + + + Nominal acquisition time per angular position, in msec. + + + Radial distance of the detector +from the center of rotation, in mm. It shall have a single value which is an average value for this rotation, or it shall have one value per angular view. + + + Distance in mm from transmission source to the detector face. Required if Image Type (0008,0008) and Value 4, is TRANSMISSION. + + + Number of angular views in this rotation. + + + Location of the patient table (or gantry relative to the table) in mm.The range and values of this element are determined by the manufacturer. + + + The distance in mm of the top of the patient table to the center of rotation. Table height below the center of rotation has a positive value. + + + Describes the detector motion during acquisition. Enumerated Values: +STEP AND SHOOT = Interrupted motion, acquire only while stationary. +CONTINUOUS = Gantry motion and acquisition are simultaneous and continuous. +ACQ DURING STEP = Interrupted motion, acquisition is continuous. + +
+ + + Heart beat duration sorting has been applied. Enumerated Values: +Y = yes +N = no + + + Description of type of arrhythmic beat rejection criteria used. + + + Number of beats skipped after a detected arrhythmia + + + Average number of heart beats per minute for the collection period for these frames. This shall include all accepted beats as well as rejected beats. + + + Sequence of Items that describe R-R intervals. Each gated interval is defined by an upper and lower range of heart beat durations. Required if the Frame Increment Pointer (0028,0009) contains the Tag for R-R Interval Vector (0054,0060). Zero or more Items may be included in this sequence. +The number of items shall be equal to Number of R-R Intervals (0054,0061). The first item corresponds to frames with value of 1 in the R-R Interval Vector (0054,0060), the second item with value 2, etc. + + + Time interval measured in msec from the start of the R-wave to the beginning of the data taking. + + + Description of type of framing performed such as forward, backward, forward/backward by percentage. +See C.7.6.18.1.1.1. +
Cardiac Framing Type (0018,1064) is the mechanism used to select the data acquired to construct the frames within a specified cardiac timing interval.C.7.6.18.2 Respiratory Synchronization Module +Table C7.6.18-2 specifies the attributes of the Respiratory Synchronization Module. +Table C.7.6.18-2 +RESPIRATORY SYNCHRONIZATION MODULE ATTRIBUTES + +
+
+ + Sequence of Items that describe gating criteria. Zero or more Items may be included in this sequence. See C.8.4.13.1.1. +
Data Information Sequence (0054,0063) shall contain a single sequence item which applies to the sum of all angular views, except when Image Type (0008,0008) Value 3 is GATED TOMO. In this case it shall have either a single item which applies to the sum of all angular views, or it shall have one item for each angular view. +
+
+ + Nominal time per individual frame in msec. + + + Average duration of accepted beats, in msec. + + + R-R interval lower limit for beat rejection, in msec + + + R-R interval upper limit for beat rejection, in msec + + + Number of heartbeats that fall within Low R-R Value (0018,1081) and High R-R Value (0018,1082), and were therefore accepted and contribute gamma events to this R-R Interval. + + + Number of heartbeats that fall outside Low R-R (0018,1081) and High R-R Value (0018,1082), and do not contribute gamma events to this R-R Interval. However, they may contribute gamma events to other R-R Intervals. + + + Sequence of Items that describe Time Slot Information. Required if the Frame Increment Pointer (0028,0009) contains the Tag for Time Slot Vector (0054,0070). Zero or more Items may be included in this sequence. +The number of items shall be equal to Number of Time Slots (0054,0071). The first item corresponds to frames with value of 1 in the Time Slot Vector (0054,0070), the second item with value 2, etc. + + + The total amount of time, in msec, that the acquisition accumulates gamma events into this frame. See C.8.4.13.1.2. +
The Time Slot Time (0054,0073) records the effective imaging time of each Time Slot. For example, if some of the accepted beats are shorter than others then the last frames may not receive a contribution from the shorter beats. The Time Slot Time for a Time Slot is the total acquisition time for that Time Slot. It is approximately equal to the Frame Time (0018,1063) multiplied by the number of accepted beats contributing to the Time Slot. +
+
+
+ + + Sequence of Items that describes each dynamic phase. Required if the Frame Increment Pointer (0028,0009) contains the Tag for Phase Vector (0054,0030). Zero or more Items may be included in this sequence. +The number of items shall be equal to Number of Phases (0054,0031). The first item corresponds to frames with value of 1 in the Phase Vector (0054,0030), the second item with value 2, etc. + + + Time paused between the last frame of the previous phase and the first frame of this phase, in msec. + + + Nominal time of acquisition per individual frame, in msec. + + + Time paused between each frame of this phase (in msec). + + + Number of frames in this phase. + + + An array of trigger times when gating information is acquired simultaneously with the dynamic image data. See Section C.8.4.14.1.1 for further explanation. +
Trigger Vector (0054,0210) is an array containing a list of the inter-trigger interval times in milliseconds in the order in which they were acquired, with the first being measured from the start time of the first frame of the image data in the Phase. If this element is used, the start times are required to be the same so that a mathematical correlation can be made between trigger times and frame start times. +
+
+ + The number of entries in the Trigger Vector (0054,0210) for this phase. Required if Trigger Vector (0054,0210) is present. + + + Description of this phase of the Dynamic image. +Defined Terms: +FLOW +WASHOUT +UPTAKE +EMPTYING +EXCRETION + +
+ + + Spacing between slices, in mm, measured from center-to-center of each slice along the normal to the first image. The sign of the Spacing Between Slices (0018,0088) determines the direction of stacking. The normal is determined by the cross product of the direction cosines of the first row and first column of the first frame, such that a positive spacing indicates slices are stacked behind the first slice and a negative spacing indicates slices are stacked in front of the first slice. See Image Orientation (0020,0037) in the NM Detector module. + + + Diameter, in mm, of the region from within which the data was used in creating the reconstruction of the image. Data may exist outside this region and portions of the patient may exist outside this region. + + + A label describing the convolution kernel or algorithm used to reconstruct the data. + + + Nominal slice thickness, in mm. + + + Relative position of the image plane expressed in mm. +See C.7.6.2.1.2 for further explanation. +
The Slice Location (0020,1041) is defined as the relative position of the image plane expressed in mm. This information is relative to an unspecified implementation specific reference point. +
+
+ + Describes the anatomical direction that slices are progressing as the slices are considered in order (as defined by the Slice Vector (0054,0080)). Meaningful only for cardiac images. +When View Code Sequence (0054,0220) indicates a short axis view, then Enumerated Values are: +APEX_TO_BASE +BASE_TO_APEX + +
+ + + Defines a sequence of Ultrasound Regions. One or more Items may be included in this Sequence. + + + The bounds of a rectangle specifying the location of the region, x0,y0,x1,y1. +See C.8.5.5.1.14 for further explanation. +
These attributes specify the location of the region, Region Location Min x0 (0018,6018), Region Location Min y0 (0018,601A), Region Location Max x1 (0018,601C), Region Location Max y1 (0018,601E) expressed as offsets to the pixel coordinates. The upper left corner of the entire image is x=0,y=0 and the lower right corner is x=image width - 1, and y=image length - 1. Thus, a region will be specified as within these bounds. Where x0,y0 is the coordinate of the upper left corner of the region and x1,y1 is the coordinate of the lower right corner of the region. +
+
+ + The bounds of a rectangle specifying the location of the region, x0,y0,x1,y1. +See C.8.5.5.1.14 for further explanation. +
These attributes specify the location of the region, Region Location Min x0 (0018,6018), Region Location Min y0 (0018,601A), Region Location Max x1 (0018,601C), Region Location Max y1 (0018,601E) expressed as offsets to the pixel coordinates. The upper left corner of the entire image is x=0,y=0 and the lower right corner is x=image width - 1, and y=image length - 1. Thus, a region will be specified as within these bounds. Where x0,y0 is the coordinate of the upper left corner of the region and x1,y1 is the coordinate of the lower right corner of the region. +
+
+ + The bounds of a rectangle specifying the location of the region, x0,y0,x1,y1. +See C.8.5.5.1.14 for further explanation. +
These attributes specify the location of the region, Region Location Min x0 (0018,6018), Region Location Min y0 (0018,601A), Region Location Max x1 (0018,601C), Region Location Max y1 (0018,601E) expressed as offsets to the pixel coordinates. The upper left corner of the entire image is x=0,y=0 and the lower right corner is x=image width - 1, and y=image length - 1. Thus, a region will be specified as within these bounds. Where x0,y0 is the coordinate of the upper left corner of the region and x1,y1 is the coordinate of the lower right corner of the region. +
+
+ + The bounds of a rectangle specifying the location of the region, x0,y0,x1,y1. +See C.8.5.5.1.14 for further explanation. +
These attributes specify the location of the region, Region Location Min x0 (0018,6018), Region Location Min y0 (0018,601A), Region Location Max x1 (0018,601C), Region Location Max y1 (0018,601E) expressed as offsets to the pixel coordinates. The upper left corner of the entire image is x=0,y=0 and the lower right corner is x=image width - 1, and y=image length - 1. Thus, a region will be specified as within these bounds. Where x0,y0 is the coordinate of the upper left corner of the region and x1,y1 is the coordinate of the lower right corner of the region. +
+
+ + The physical units of the dimensions of the region. +See C.8.5.5.1.15 for Enumerated Values. +
Physical Units X Direction (0018,6024) and Physical Units Y Direction (0018,6026) provide Enumerated Values indicating the physical units of the dimensions of the region. + +
+
+ + The physical units of the dimensions of the region. +See C.8.5.5.1.15 for Enumerated Values. +
Physical Units X Direction (0018,6024) and Physical Units Y Direction (0018,6026) provide Enumerated Values indicating the physical units of the dimensions of the region. + +
+
+ + The physical value increments per positive X pixel increment. The units are as specified in the Physical Units X Direction (0018,6024). +See C.8.5.5.1.17 for further explanation. +
The Physical Delta X (0018,602C) is the physical value increment per positive X pixel increment, which is left to right. The Physical Delta Y (0018,602E) is the physical value increment per positive Y pixel increment which is top to bottom. +Note: When displaying Doppler data, ultrasound applications typically display the Doppler strip horizontally, with data sweeping (moving time origin) from left (oldest) to right (newest) or scrolling (static time origin) from right to left. The default display of positive velocity values normally indicates flow toward the transducer; negative velocity values indicate flow away from the transducer. In this case a negative Physical Delta Y is required to specify that the direction of positive velocities or frequencies is upward. + +
+
+ + The physical value increments per positive Y pixel increment. The units are as specified in the Physical Units Y Direction (0018,6026). +See C.8.5.5.1.17 for further explanation. +
The Physical Delta X (0018,602C) is the physical value increment per positive X pixel increment, which is left to right. The Physical Delta Y (0018,602E) is the physical value increment per positive Y pixel increment which is top to bottom. +Note: When displaying Doppler data, ultrasound applications typically display the Doppler strip horizontally, with data sweeping (moving time origin) from left (oldest) to right (newest) or scrolling (static time origin) from right to left. The default display of positive velocity values normally indicates flow toward the transducer; negative velocity values indicate flow away from the transducer. In this case a negative Physical Delta Y is required to specify that the direction of positive velocities or frequencies is upward. + +
+
+ + This coordinate pair, x0,y0 defines the location of a virtual "reference" pixel. +See C.8.5.5.1.16 for further explanation. +
This coordinate pair, Reference Pixel x0 (0018,6020), Reference Pixel y0 (0018,6022) defines the location of a virtual "reference" pixel. This reference pixel location is used to tie the image's pixel coordinate system to the physical coordinate system. For example, the reference pixel could be defined where a depth of zero centimeters occurs in the 2D image, or it could define where the baseline (i.e.: zero frequency) resides in a spectral display. The reference pixel location is the relative offset from the Region Location Min x0 (0018,6018) and Region Location Min y0 (0018,601A), not the image origin. The location is not required to be within the region or even within the image boundary. For this reason, the Reference Pixel x0 and Reference Pixel y0values can be positive or negative. +The reference pixel location varies depending on the type and spatial organization of the data within the region. +
+
+ + This coordinate pair, x0,y0 defines the location of a virtual "reference" pixel. +See C.8.5.5.1.16 for further explanation. +
This coordinate pair, Reference Pixel x0 (0018,6020), Reference Pixel y0 (0018,6022) defines the location of a virtual "reference" pixel. This reference pixel location is used to tie the image's pixel coordinate system to the physical coordinate system. For example, the reference pixel could be defined where a depth of zero centimeters occurs in the 2D image, or it could define where the baseline (i.e.: zero frequency) resides in a spectral display. The reference pixel location is the relative offset from the Region Location Min x0 (0018,6018) and Region Location Min y0 (0018,601A), not the image origin. The location is not required to be within the region or even within the image boundary. For this reason, the Reference Pixel x0 and Reference Pixel y0values can be positive or negative. +The reference pixel location varies depending on the type and spatial organization of the data within the region. +
+
+ + The Physical Value at the reference pixel x location. The units are specified in the Physical Units field. + + + The Physical Value at the reference pixel y location. The units are specified in the Physical Units field. + + + The spatial organization of the data within the region. +See C.8.5.5.1.1 for Enumerated Values. +
Enumerated Values for Region Spatial Format (0018,6012) indicate the spatial organization of the data within the region. + +
+
+ + The type of data within the region. +See C.8.5.5.1.2 for Enumerated Values. +
Enumerated Values for Region Data Type (0018,6014) indicate the type of data within the region. + +
+
+ + Flags used for special handling of the region. +See C.8.5.5.1.3 for Enumerated Values and further explanation. +
Region Flags (0018,6016) specify characteristics of US Regions. +Bit 0 of the Region Flags specifies the relative priority of the pixel component calibration specified by an US Region in the case where the US Region intersects with other US Regions. The calibration supplied by one or more of the regions may not be valid in the area that they intersect. Enumerated Values for Bit 0 (lsb): + 1 = Region pixels are low priority + 0 = Region pixels are high priority +A high priority region overwrites data of a low priority region when they overlap, thus invalidating any pixel component calibration specified for a low priority region. pixel component calibration of overlapping regions of the same priority is indeterminate where they overlap. Figure C.8-6 shows an example of intersecting regions. + + +Figure C.8-6 + Intersecting Spatial Format Regions and Overlapping Measurement +In this example, Region B is Color Flow while Region A is Tissue Echo. If Region B Color Flow values share the same bit planes as Region A Tissue Echo values, then it is indeterminate whether a pixel in this region is a Color Flow pixel or a Tissue Echo pixel. Since the pixels of the Color Flow region overwrite those of the Tissue Echo region, the Region Flag of the Tissue Echo region is assigned low priority and the Region Flag of the color region is assigned high priority. This means that if both the Tissue Echo and Color Flow regions define pixel component calibration that only the calibration specified by the Color Flow region can be applied to the pixel data value at Point X. +The measurement in Figure C.8-6 is a line between Point Y and Point Z. Both points are in Region A so the distance between them can be calculated using the Region A scaling (assuming that Region A defines both the Physical Units X Direction and Y Direction as being cm). If the points are in Region B, and hence also in Region A, it is still possible to calculate the distance because the region scaling is identical in both regions. The lower priority of Region B only applies to its pixel component calibration, not its X and Y direction scaling. +Enumerated Values for Bit 1 Scaling Protection: + 1 = Protected + 0 = Not Protected +Ultrasound systems should set this to 1 if the image is scaled automatically by the ultrasound system. If the image is frame-grabbed and scaling is not available then it should be set to 0. If the region is protected, the region can not be manually rescaled. That is the data defined by the region calibration Module can not be overridden by a reader of that image. +Enumerated Values for Bit 2 Doppler Scale Type: + 1 = Frequency + 0 = Velocity + +Valid for PW and CW regions only. Indicates which type of Doppler scale is used. +Enumerated Values for Bit 3-4 Scrolling Region: + 00 = Unspecified + 01 = Scrolling + 10 = Sweeping +11 = Sweeping then Scrolling + +Bit 5-31 Reserved for future use, shall be set to zero. +
+
+ + Describes how the components of a pixel can be described. Required if pixel component calibration exists for this region. +See C.8.5.5.1.4 for Enumerated Values and further explanation. +
Pixel Component Organization (0018,6044) provides an Enumerated Value describing how the components of a pixel can be described. The absence of this data element means that pixel component calibration does not exist for this region. Where: +0 = Bit aligned positions +1 = Ranges +2 = Table look up +3 = Code Sequence look up +Other values reserved for future use. +Pixel Component Organization defines the way in which the composite pixel values are mapped into real world values with physical units, as illustrated in Figure C.8-7. + +Figure C.8-7 +Pixel Component Calibration +An example of Component Calibration for an ultrasound image is shown in Figure C.8-8. + +Figure C.8-8 +Pixel Component Calibration Example +In this example, some pixels lie within two Regions. One Region specifies pixel component calibration for Doppler velocity values. The second Region specifies pixel component calibration for Doppler magnitude. A particular Pixel Data (7FE0,0010) value will thus map to a displayed value, a Doppler velocity and magnitude value. +The example has a Palette Color Photometric Interpretation with 16 Bits Allocated and Bits Stored per sample. The Palette Color Lookup Tables also have 16 bits for each entry. The fact that the example has just one sample per pixel means that each composite pixel value is identical to the single Pixel Data value. An example Pixel Data value is shown in brackets along with the output values resulting from each step where it is processed. +The Pixel Data value is mapped to red, green, and blue values from the supplied Palette Color Lookup Tables before being displayed. The display device supports 8 bits per sample and thus requires the scaling of the output values from the 16 bit per entry LUTs. +The Doppler Velocity Region maps each pixel value in the Region to the Doppler velocity. The Pixel Component Organization (0018,6044) has a value of zero, indicating bit aligned positions with a bit mask. The Pixel Component Mask (0018,6046) specifies that the least significant 4 bits of the most significant byte convey the Doppler velocity of each pixel. The Pixel Component Physical Units (0018,604C) are cm/sec, and the Pixel Component Data Type (0018,604E) indicates color flow velocity. The Table of X Break Points (0018,6052) and Table of Y Break Points (0018,6054) map each masked composite pixel value to a Doppler velocity value in cm/sec. +The Doppler Magnitude Region maps each pixel value in the Region to the Doppler magnitude. The Pixel Component Organization (0018,6044) has a value of zero, indicating bit aligned positions with a bit mask. The Pixel Component Mask (0018,6046) specifies that the most significant 4 bits of the most significant byte convey the Doppler magnitude of each pixel. The Pixel Component Physical Units (0018,604C) is set to dB, and the Pixel Component Data Type (0018,604E) indicates color flow magnitude. The Table of X Break Points (0018,6052) and Table of Y Break Points (0018,6054) map each masked composite pixel value to a Doppler magnitude value in dB. +
+
+ + This value is ANDed with the composite pixel code for each pixel within the region, then shifted right by the number of contiguous least significant zeros in the mask to obtain what will be referred to as the "Shifted Masked Composite Pixel Code" (SMCPC). Required if Pixel Component Organization = Bit aligned. +See C.8.5.5.1.5 for further explanation. +
Pixel Component Mask (0018,6046) is ANDed with the Composite Pixel Code (see Section C.7.6.3.1.1) for each pixel within the region, then shifted right by the number of contiguous least significant zeros in the mask to obtain what will be referred to as the "Shifted Masked Composite Pixel Code". +The mask will most likely (but not necessarily) contain a block of contiguous ones, surrounded by leading and trailing zeros. The purpose of this mask is to keep only those bits within the composite pixel code that pertain to the region. It is to be used only when Pixel Organization is bit aligned positions. +
+
+ + Defines the start of the numeric range of values within the composite pixel where calibration is to be defined by the "pixel physical calibration table". To be used only when ranges are used to describe the portion of the composite pixel. +Required if Pixel Component Organization = Ranges. + + + Defines the stop of the numeric range of values within the composite pixel where calibration is to be defined by the "pixel physical calibration table". To be used only when ranges are used to describe the portion of the composite pixel. +Required if Pixel Component Organization = Ranges. + + + The physical units to be applied to the pixel component. +Required if Pixel Component Organization exists. +See C.8.5.5.1.6 for further explanation. +
For Pixel Component Physical Units (0018,604C), the Enumerated Values describing the physical units to be applied to the pixel component are: + +
+
+ + The type of data for the pixel component. +Required if Pixel Component Organization exists. +See C.8.5.5.1.7 for further explanation. +
For Pixel Component Data Type (0018,604E), the Enumerated Values indicating the type of data for the pixel component are: +000AH Tissue Classification +
+
+ + The number of break point coordinate pairs used to describe a piece wise linear curve. +Required if Pixel Component Organization equals 0 or 1. Otherwise not used. +See C.8.5.5.1.8 for further explanation. +
The Number of Table Break Points (0018,6050) gives the number of entries in each of two tables: the Table of X Break Points (0018,6052) and Table of Y Break Points (0018,6054). These tables are used to designate a curve mapping the value of a pixel component to its actual physical value, as described in Section C.8.5.5.1.9. +
+
+ + An array of X values used to create the piece wise linear curve. +Required if Pixel Component Organization equals 0 or 1. Otherwise not used. +See C.8.5.5.1.9 for further explanation. +
Table of X Break Points (0018,6052) and Table of Y Break Points (0018,6054) are individual arrays of coordinates which interpreted together are used to create a piecewise linear curve. Each X value from the Table of X Break Points is matched with the corresponding Y value from the Table of Y Break Points yielding an (X,Y) coordinate. The set of (X,Y) coordinates describes a piecewise linear curve mapping the value of a pixel component to its actual physical value (in units defined in Pixel Component Physical Units data element (0018,604C) ). +The X direction on the curve has no units, and represents actual pixel component values. If the Pixel Component Organization (0018,6044) is "Bit aligned positions", and the width of the Pixel Component Mask is n bits then the X coordinates are in the range 0 through 2n -1. If the Pixel Component Organization is Ranges, then the X coordinates are in the range 0 through 2 number of bits in the composite pixel - 1. +Note: The X value is NOT relative to the Pixel Component Range Start (0018,6048). Not all possible X values in the range need be covered by the curve. +For any pixel component value in the range of the curve described by this table, the corresponding Y value is the actual physical value for that pixel, in units specified in the Pixel Component Physical Units data element (0018,604C). If the pixel component value is NOT within the range of specified X values for the curve, then no pixel calibration is defined by this region. It may be possible for pixel calibration to be defined by other spatial regions intersecting this one. +
+
+ + An array of Y values used to create the piece wise linear curve. +Required if Pixel Component Organization equals 0 or 1. Otherwise not used. +See C.8.5.5.1.9 for further explanation. +
Table of X Break Points (0018,6052) and Table of Y Break Points (0018,6054) are individual arrays of coordinates which interpreted together are used to create a piecewise linear curve. Each X value from the Table of X Break Points is matched with the corresponding Y value from the Table of Y Break Points yielding an (X,Y) coordinate. The set of (X,Y) coordinates describes a piecewise linear curve mapping the value of a pixel component to its actual physical value (in units defined in Pixel Component Physical Units data element (0018,604C) ). +The X direction on the curve has no units, and represents actual pixel component values. If the Pixel Component Organization (0018,6044) is "Bit aligned positions", and the width of the Pixel Component Mask is n bits then the X coordinates are in the range 0 through 2n -1. If the Pixel Component Organization is Ranges, then the X coordinates are in the range 0 through 2 number of bits in the composite pixel - 1. +Note: The X value is NOT relative to the Pixel Component Range Start (0018,6048). Not all possible X values in the range need be covered by the curve. +For any pixel component value in the range of the curve described by this table, the corresponding Y value is the actual physical value for that pixel, in units specified in the Pixel Component Physical Units data element (0018,604C). If the pixel component value is NOT within the range of specified X values for the curve, then no pixel calibration is defined by this region. It may be possible for pixel calibration to be defined by other spatial regions intersecting this one. +
+
+ + The number of entries in the Table of Pixel Values. +Required if the value of Pixel Component Organization (0018,6044) is 2 or 3. +Otherwise not used. See C.8.5.5.1.11 for further explanation. +
The Number of Table Entries (0018,6056) gives the number of entries in the Table of Pixel Values, the number of entries in the Table of Parameter Values (0018,605A), if present, and the number of items in the Pixel Value Mapping Code Sequence (0040,9098) , if present. +
+
+ + A table of Pixel Values used in conjunction with the Table of Parameter Values (0018,605A) or Pixel Value Mapping Code Sequence (0040,9098) to provide a mapping from Pixel Value to a real world value. +Required if the Pixel Component Organization equals 2. Otherwise not used. +See C.8.5.5.1.12 for further explanation. +
The Table of Pixel Values (0018,6058) specifies the pixel values that are mapped to real world parameter values or coded concepts (tissue characterizations). The number of entries in the table is given by Number of Table Entries (0018,6056). +A pixel is calibrated (mapped to a real-world value) by finding an entry in the Table of Pixel Values that matches its Composite Pixel Code (see Section C.7.6.3.1.1). The offset index of this entry is used as an index into the Parameter Value Table (0018,605A) or as a sequence item number in the Pixel Value Mapping Code Sequence (0040,9098) to select the real world value. The first Table of Pixel Values entry corresponds to sequence item 1. +Note: If a Composite Pixel Code has no matching value in the Pixel Value Table then there is no unambiguous way to determine the corresponding Parameter Value. A method may exist to determine a valid Parameter Value but the specification of such a method is outside the scope of the DICOM standard. No assumption should be made that linear interpolation will produce a valid result. + +
+
+ + A table of Parameter Values used in conjunction with the Table of Pixel Values (0018,6058) to provide a mapping from Pixel Value to Parameter Value. +Required if the value of Pixel Component Organization (0018,6044) is 2. +Otherwise not used. See C.8.5.5.1.13 for further explanation +
The Table of Parameter Values (0018,605A) provides the real world values for pixel values identified in the Table of Pixel Values (0018,6058). The number of table entries is given by Number of Table Entries (0018,6056) and the physical units are given by Pixel Component Physical Units (0018,604C). Values may repeat when a parameter value is associated with more than one Composite Pixel Code value. +
+
+ + Sequence that, in conjunction with the Table of Pixel Values (0018,6058), provides a mapping from a Pixel Value to an associated Coded Concept. One or more Items shall be present; the number of Items shall be equal to the value of Number of Table Entries (0018,6056). +Required if the value of Pixel Component Organization (0018,6044) is 3 (Code Sequence look up). +See Sections C.8.5.6.1.18 for further explanation. + + + + The manufacturer defined description of center frequency of the interrogating ultrasound energy. The units are kilohertz. + + + The ultrasound pulse repetition frequency, as defined by the manufacturer, used to collect data in the region. The units are in hertz. + + + The Doppler correction angle. The units are degrees. + + + The steering angle, as defined by the manufacturer, used for a steered 2D image. The units are degrees. + + + The x displacement, in pixels, from the Reference pixel to the center of the Doppler sample volume. + + + The y displacement, in pixels, from the Reference pixel to the center of the Doppler sample volume. + + + The starting and ending coordinates pairs of the m-line. Where the X0,Y0 are the starting point and X1,Y1 are the end point of the tm-line. +See C.8.5.5.1.10 for further explanation. +
TM-Line Position X1 ,TM-Line Position Y1 +The TM-Line Position X0 (0018,603D) and TM-Line Position Y0 (0018,603F) are the coordinates of the starting point and TM-Line Position X1 (0018,6041), TM-Line Position Y1 (0018,6043) are the coordinates of the end point of the TM-line. The coordinate is defined as the displacement, in pixels, from the Reference pixel. Typically used for M-mode line and CW Doppler. +
+
+ + The starting and ending coordinates pairs of the m-line. Where the X0,Y0 are the starting point and X1,Y1 are the end point of the tm-line. +See C.8.5.5.1.10 for further explanation. +
TM-Line Position X1 ,TM-Line Position Y1 +The TM-Line Position X0 (0018,603D) and TM-Line Position Y0 (0018,603F) are the coordinates of the starting point and TM-Line Position X1 (0018,6041), TM-Line Position Y1 (0018,6043) are the coordinates of the end point of the TM-line. The coordinate is defined as the displacement, in pixels, from the Reference pixel. Typically used for M-mode line and CW Doppler. +
+
+ + The starting and ending coordinates pairs of the m-line. Where the X0,Y0 are the starting point and X1,Y1 are the end point of the tm-line. +See C.8.5.5.1.10 for further explanation. +
TM-Line Position X1 ,TM-Line Position Y1 +The TM-Line Position X0 (0018,603D) and TM-Line Position Y0 (0018,603F) are the coordinates of the starting point and TM-Line Position X1 (0018,6041), TM-Line Position Y1 (0018,6043) are the coordinates of the end point of the TM-line. The coordinate is defined as the displacement, in pixels, from the Reference pixel. Typically used for M-mode line and CW Doppler. +
+
+ + The starting and ending coordinates pairs of the m-line. Where the X0,Y0 are the starting point and X1,Y1 are the end point of the tm-line. +See C.8.5.5.1.10 for further explanation. +
TM-Line Position X1 ,TM-Line Position Y1 +The TM-Line Position X0 (0018,603D) and TM-Line Position Y0 (0018,603F) are the coordinates of the starting point and TM-Line Position X1 (0018,6041), TM-Line Position Y1 (0018,6043) are the coordinates of the end point of the TM-line. The coordinate is defined as the displacement, in pixels, from the Reference pixel. Typically used for M-mode line and CW Doppler. +
+
+
+ + + Number of samples (planes) in this image. +See C.8.5.6.1.12 for specialization +
For US Images, Samples Per Pixel (0028,0002) is specified to use the following values for specific Photometric Interpretations: +Table C.8-19 +US SAMPLES PER PIXEL + +
+
+ + Specifies the intended interpretation of the pixel data. +See C.8.5.6.1.2 for specialization. +
For US Images, Photometric Interpretation (0028,0004) is specified to use the following Defined Terms: + +Note: It is recommended that future implementations should not use ARGB photometric interpretation. + +See PS 3.5 for restrictions imposed by compressed Transfer Syntaxes. +
+
+ + Number of bits allocated for each pixel sample. +See C.8.5.6.1.13 for specialization. +
For US Images, Bits Allocated (0028,0100) is specified to use the following values for specific Photometric Interpretations: +Table C.8-20 +US BITS ALLOCATED + +
+
+ + Number of bits stored for each pixel sample. +See C.8.5.6.1.14 for specialization. +
For US Images, Bits Stored (0028,0101) is specified to use the following values for specific Photometric Interpretations: +Table C.8-21 +US BITS STORED + +
+
+ + Most significant bit for pixel sample data. +See C.8.5.6.1.15 for specialization. +
For US Images, High Bit (0028,0102) is specified to use the following values for specific Photometric Interpretations: +Table C.8-22 +US HIGH BIT + +
+
+ + Indicates whether the pixel data are sent color-by-plane or color-by-pixel. +Required if Samples per Pixel (0028,0002) has a value greater than 1. +See C.8.5.6.1.16 for specialization. +
For US Images, Planar Configuration (0028,0006) is specified to use the following values for specific Photometric Interpretations: +Table C.8-23 +US PLANAR CONFIGURATION + +
+
+ + Data representation of pixel samples. +See C.8.5.6.1.3 for specialization. +
For US Images, Pixel Representation (0028,0103) is specified to use the following Enumerated Value: +0000H = unsigned integer +
+
+ + Contains the Data Element Tag of the attribute which is used as the frame increment in Multi-frame pixel data (see C.7.6.6). Required if Number of Frames is sent. +See C.8.5.6.1.4 for specialization. +
For US Multi-frame images, the Attribute Frame Increment Pointer (0028,0009) of the Multi-frame Module (see Section C.7.6.6) is specified by the following Defined Terms: +00181063 = sequencing by Frame Time (0018,1063) +00181065 = sequencing by Frame Time Vector (0018,1065) +
+
+ + Image identification characteristics. +See C.8.5.6.1.1 for specialization. +
For US Images, Image Type (0008,0008) is specified to be Type 2. The Defined Terms for Value 3 are: + +Value 4 is constructed as a modality bit map to allow for a description of multi-modality displays. In using this bit map, the sum of the values of the various modalities will unambiguously determine the constituent modalities. + +Notes: 1. All Values are hexadecimal encoded as a CS. See PS 3.5. + 2. For example, Color Flow with CW spectral Doppler would have a value 4 = 0015. Note that no assumption should be made in Color Doppler or Color M-Mode regarding underlying B or M-Mode, respectively. + +
+
+ + Specifies whether an Image has undergone lossy compression. Enumerated Values: +00 = Image has NOT been subjected to lossy compression. +01 = Image has been subjected to lossy compression. +See C.7.6.1.1.5 +Required if Lossy Compression has been performed on the Image. +
The Attribute Lossy Image Compression (0028,2110) conveys that the Image has undergone lossy compression. It provides a means to record that the Image has been compressed (at a point in its lifetime) with a lossy algorithm and changes have been introduced into the pixel data. Once the value has been set to “01â€, it shall not be reset. +Note: If an image is compressed with a lossy algorithm, the attribute Lossy Image Compression (0028,2110) is set to “01â€. Subsequently, if the image is decompressed and transferred in uncompressed format, this attribute value remains “01â€. + +The value of the Lossy Image Compression (0028,2110) Attribute in SOP Instances containing multiple frames in which one or more of the frames have undergone lossy compression shall be “01â€. +Note: It is recommended that the applicable frames be noted in the Attribute Derivation Description (0008,2111). + +If an image is originally obtained as a lossy compressed image from the sensor, then Lossy Image Compression (0028,2110) is set to “01†and Value 1 of the Attribute Image Type (0008,0008) shall be set to ORIGINAL. +If an image is a compressed version of another image, Lossy Image Compression (0028,2110) is set to “01â€, Value 1 of the Attribute Image Type (0008,0008) shall be set to DERIVED, and if the predecessor was a DICOM image, then the Image shall receive a new SOP Instance UID. +Note: 1. It is recommended that the approximate compression ratio be provided in the Attribute Derivation Description (0008,2111). Furthermore, it is recommended that Derivation Description (0008,2111) be used to indicate when pixel data changes might affect professional interpretation. (see C.7.6.1.1.3). + 2. The attribute Lossy Image Compression (0028,2110) is defined as Type 3 for backward compatibility with existing IODs. It is expected to be required (i.e., defined as Type 1C) for new Image IODs and for existing IODs that undergo a major revision (e.g. a new IOD is specified). +The Defined Terms for Lossy Image Compression Method (0028,2114) are: +ISO_10918_1 = JPEG Lossy Compression +ISO_14495_1 = JPEG-LS Near-lossless Compression +ISO_15444_1 = JPEG 2000 Irreversible Compression +ISO_13818_2 = MPEG2 Compression + +
+
+ + Number of Stages in this protocol. Required if image was acquired in a Staged protocol. + + + Number of views in this Stage. Required if image was acquired in a Staged protocol. + + + The time offset(s) of the reported R Wave peaks, each relative to the time of the start of the acquisition of the first frame in msec. Multi-valued, with one value per reported R Wave. + + + This element indicates if any ultrasound color data is present in an image. Enumerated Values: +00 = Ultrasound color data not present in image +01 = Ultrasound color data is present in image. +See C.8.5.6.10 + + + A Stage is a particular time slice of a protocol in which a set of images are collected. The names can be free form text. Recommended text for Stress Echo stage names are: +PRE-EXERCISE, +POST-EXERCISE, +PEAK-EXERCISE, +RECOVERY, +BASELINE, +LOW DOSE, +PEAK DOSE + + + Sequence of items describing the performed Ultrasound Protocol Stage(s). One or more Items may be included in this Sequence. + + + + A number that identifies the Stage. Stage Number starts at one. + + + A View is a particular combination of the position and orientation when a set of images are acquired. Images are acquired at the same View in different Stages for the purpose of comparison. + + + A number that identifies the View. View Number starts at one. + + + The number of event timers used at the time of acquisition of a Multi-frame image. + + + An array of values associated with each event timer. Units in milliseconds. + + + Name that identifies the event timer. + + + + Sequence that describes the view of the patient anatomy in this image. +Only a single Item shall be permitted in this Sequence. +See Section C.8.5.6.1.19. +
The view of the patient anatomy may be described using coded terminology in the View Code Sequence (0054,0220). The view is typically specified by transducer position relative to the patient anatomy and/or transducer orientation, +The view may be described by a single Code Sequence Item, or by combination of post-coordinated Code Sequence Items. The principal coded item is specified in View Code Sequence, and modifier terms in the View Modifier Code Sequence (0054,0222). The Baseline Context IDs for post-coordinated encoding of view are: +
+
+ + + Sequence that provides modifiers for the view of the patient anatomy. +Zero or more Items shall be permitted in this Sequence. +See Section C.8.5.6.1.19. +
The view of the patient anatomy may be described using coded terminology in the View Code Sequence (0054,0220). The view is typically specified by transducer position relative to the patient anatomy and/or transducer orientation, +The view may be described by a single Code Sequence Item, or by combination of post-coordinated Code Sequence Items. The principal coded item is specified in View Code Sequence, and modifier terms in the View Modifier Code Sequence (0054,0222). The Baseline Context IDs for post-coordinated encoding of view are: +
+
+ + + The date and time that the acquisition of data that resulted in this image started. +Required if Modality (0008,0060) = IVUS +May be present otherwise. +Note: The synchronization of this time with an external clock is specified in the Synchronization Module in Acquisition Time Synchronized (0018,1800). + + + Time interval measured in msec from the start of the R-wave to the beginning of data taking + + + Average R-R interval used for these data, in msec + + + Beat length sorting has been applied. Enumerated Values: +Y = yes +N = no + + + R-R interval low limit for beat rejection, in msec + + + R-R interval high limit for beat rejection, in msec + + + Beats per minute. + + + Defined Terms: +MOTOR_PULLBACK +MANUAL_PULLBACK +SELECTIVE +GATED_PULLBACK +See C.8.5.6.1.21 +Required if Modality (0008,0060) = IVUS +
This attribute denotes which of the following defined terms describes the method used to acquire the IVUS Images. +MOTOR_PULLBACK: The IVUS imaging catheter is positioned in the blood vessel under examination distal to the anatomical structures to be examined. Then the catheter is attached to a motorized mechanism capable of withdrawing the catheter through the vessel at a constant velocity specified by the attribute IVUS Pullback Rate (0018,3101) from the defined IVUS Pullback Start Frame Number (0018,3103) (see C.8.5.6.1.24) to the IVUS Pullback Stop Frame Number (0018,3104) (see C.8.5.6.1.25). +MANUAL_PULLBACK: The IVUS imaging catheter is positioned in the blood vessel under examination distal to the anatomical structures to be examined. Then the catheter is manually withdrawn through the vessel region of interest. +SELECTIVE: The IVUS imaging catheter is positioned in the blood vessel under examination near the anatomical structures to be examined. Then the catheter is manually withdrawn or advanced through the vessel region of interest. +GATED_PULLBACK: The IVUS imaging catheter is positioned in the blood vessel under examination distal to the anatomical structures to be examined. Then the catheter is attached to a motorized mechanism capable of withdrawing the catheter through the vessel at a rate specified by the attribute IVUS Gated Rate (0018,3102), once per heart cycle, from the defined IVUS Pullback Start Frame Number (0018,3103) (see C.8.5.6.1.24) to the IVUS Pullback Stop Frame Number (0018,3104) (see C.8.5.6.1.25). +
+
+ + Required if IVUS Acquisition (0018,3100) value is MOTOR_PULLBACK. Specified in units of mm/sec. +See C.8.5.6.1.22 +
The attribute IVUS Pullback Rate (0018,3101) is required when IVUS Acquisition (0018,3100) is MOTOR_PULLBACK and it specifies the velocity of withdrawal of the IVUS imaging catheter in millimeters per second. +
+
+ + Required if IVUS Acquisition (0018,3100) value is GATED_PULLBACK. Specified in units of mm/beat. +See C.8.5.6.1.23 +
The attribute IVUS Gated Rate (0018,3102) is required when IVUS Acquisition (0018,3100) is GATED_PULLBACK and it specifies the velocity of withdrawal of the IVUS imaging catheter in millimeters per beat. +
+
+ + Required if IVUS Acquisition (0018,3100) value is MOTOR_PULLBACK or GATED_PULLBACK. +See C.8.5.6.1.24 +
The IVUS Pullback Start Frame Number (0018,3103) specifies the frame number of a IVUS multi-frame acquisition upon which motorized or gated pullback begins. +
+
+ + Required if IVUS Acquisition (0018,3100) value is MOTOR_PULLBACK or GATED_PULLBACK. +See C.8.5.6.1.25 +
The IVUS Pullback Stop Frame Number (0018,3104) specifies the frame number of a IVUS multi-frame acquisition upon which motorized or gated pullback ends. +
+
+ + Identifier(s) of the lesion(s) of interest imaged within the current SOP Instance. Each lesion shall have a unique numeric integer identifier within the study. +See C.8.5.6.1.26. +
Attribute Lesion Number identifies the lesion(s) of interest imaged within the current SOP Instance. Each lesion shall have a unique numeric integer identifier within the study. If during a study the same lesion is imaged more than once, the same Lesion Number should be used for both SOP Instances. +Notes: 1.Lesion Number is not a DICOM UID. + 2.An IVUS pullback may contain multiple values in Lesion Number. + +
+
+ + Manufacturer defined character string description of ultrasound output level(s) used in generating a given image. Data may be expressed in dB, %, W/cm2, etc. + + + Manufacturer defined code or description of ultrasound transducer used. + + + Defined Terms: +SECTOR_PHASED +SECTOR_MECH +SECTOR_ANNULAR +LINEAR +CURVED LINEAR +SINGLE CRYSTAL +SPLIT XTAL CWD +IV_PHASED +IV_ROT XTAL +IV_ROT MIRROR +ENDOCAV_PA +ENDOCAV_MECH +ENDOCAV_CLA +ENDOCAV_AA +ENDOCAV_LINEAR +VECTOR_PHASED + + + The depth, from the transducer face, of the manufacturer defined beam focus used for the image, in cm. + + + Manufacturer defined description of processing of echo information. Data may include code or description of gain (initial, overall, TGC, dynamic range, etc.), preprocessing, postprocessing, Doppler processing parameters, e.g. cutoff filters, etc., as used in generating a given image. + + + See C.8.5.6.1.8 for Description. +
The thermal and/or mechanical indices, when made available by a manufacturer, are defined according to the Standard for Real-Time Display of Thermal and Mechanical Acoustic Output Indices on Diagnostic Ultrasound Equipment, a voluntary performance standard jointly published by AIUM and NEMA. +
+
+ + See C.8.5.6.1.8 for Description. +
The thermal and/or mechanical indices, when made available by a manufacturer, are defined according to the Standard for Real-Time Display of Thermal and Mechanical Acoustic Output Indices on Diagnostic Ultrasound Equipment, a voluntary performance standard jointly published by AIUM and NEMA. +
+
+ + See C.8.5.6.1.8 for Description. +
The thermal and/or mechanical indices, when made available by a manufacturer, are defined according to the Standard for Real-Time Display of Thermal and Mechanical Acoustic Output Indices on Diagnostic Ultrasound Equipment, a voluntary performance standard jointly published by AIUM and NEMA. +
+
+ + See C.8.5.6.1.8 for Description. +
The thermal and/or mechanical indices, when made available by a manufacturer, are defined according to the Standard for Real-Time Display of Thermal and Mechanical Acoustic Output Indices on Diagnostic Ultrasound Equipment, a voluntary performance standard jointly published by AIUM and NEMA. +
+
+ + See C.8.5.6.1.8 for Description. +
The thermal and/or mechanical indices, when made available by a manufacturer, are defined according to the Standard for Real-Time Display of Thermal and Mechanical Acoustic Output Indices on Diagnostic Ultrasound Equipment, a voluntary performance standard jointly published by AIUM and NEMA. +
+
+ + See C.8.5.6.1.8 for Description. +
The thermal and/or mechanical indices, when made available by a manufacturer, are defined according to the Standard for Real-Time Display of Thermal and Mechanical Acoustic Output Indices on Diagnostic Ultrasound Equipment, a voluntary performance standard jointly published by AIUM and NEMA. +
+
+ + The depth, in mm, from the transducer face to the deepest point included in the displayed image- the field of view. + + + Defined term which identifies the intended purpose of the ROI Overlay Type. +See C.8.5.6.1.11 for specialization. +
For US Images, Overlay Subtype (60xx,0045) shall use the following Defined Terms: +ACTIVE 2D/BMODE IMAGE AREA = identification of the active area of a 2D/B-mode image. +
+
+
+ + + Describes the kind of image conversion. Defined Terms : +DV = Digitized Video +DI = Digital Interface +DF = Digitized Film +WSD = Workstation +SD = Scanned Document +SI = Scanned Image +DRW = Drawing +SYN = Synthetic Image + + + Source equipment for the image. This type definition shall override the definition in the General Series Module. +See C.7.3.1.1.1 for Defined Terms. +
Defined Terms for the Modality (0008,0060) are: + +Retired Defined Terms for the Modality (0008,0060) are: + +Note: 1. The XA modality incorporates the retired modality DS. + 2. The RF modality incorporates the retired modalities CF, DF, VF. + 3. The modality listed in the Modality Data Element (0008,0060) may not match the name of the IOD in which it appears. For example, a SOP instance from XA IOD may list the RF modality when an RF implementation produces an XA object. + 4. The MR modality incorporates the retired modalities MA and MS. + +
+
+ + User defined identification of the device that converted the image + + + Manufacturer of the Secondary Capture Device + + + Manufacturer's model number of the Secondary Capture Device + + + Manufacturer's designation of software version of the Secondary Capture Device + + + Original format of the captured video image (e.g. NTSC, PAL, Videomed-H) + + + Additional information about digital interface used to acquire the image + +
+ + + The date the Secondary Capture Image was captured. + + + The time the Secondary Capture Image was captured. + + + Physical distance on the media being digitized or scanned between the center of each pixel, specified by a numeric pair - adjacent row spacing (delimiter) adjacent column spacing in mm. See 10.7.1.3 for further explanation of the value order. +Shall be consistent with Pixel Aspect Ratio (0028,0034), if present. + + + + + + Indicates whether or not image contains sufficient burned in annotation to identify the patient and date the image was acquired. +Enumerated Values: +YES +NO + + + Specifies an identity transformation for the Presentation LUT, such that the output of all grayscale transformations defined in the IOD containing this Module are defined to be P-Values. +Enumerated Values: +IDENTITY - output is in P-Values. +Required if Photometric Interpretation (0028,0004) is MONOCHROME2, and BitsStored (0028,0101) is greater than 1. +Note: If the VOI LUT Module is required by the IOD but no VOI LUT Sequence (0028,3010) or Window Center (0028,1050) is present, then the VOI LUT stage is an identity transformation. + + + Luminance of a hypothetical viewing device illuminating a piece of monochrome transmissive film, or for the case of reflective media, luminance obtainable from diffuse reflection of the illumination present. Expressed as L0, in candelas per square meter (cd/m2). +Note: May be used together with Reflected Ambient Light (2010,0160) to recover Optical Density information from P-Values. See C.8.6.3.1. +
Illumination (2010,015E) and Reflected Ambient Light (2010,0160) may be used to recover Optical Density information from P-Values. +Monochrome media that is being digitized is often measured in Optical Density values. These values need to be converted to P-Values for storage and display. The P-Values used in an image correspond to the perception of a human observer viewing the film on a hypothetical viewing device (such as a light box), using the specified values of Illumination (2010,015E) and Reflected Ambient Light (2010,0160). +The Grayscale Standard Display Function defined in PS 3.14 is used to convert Luminance to P-Values. In the case of scanned film, the Luminance is derived from Optical Density using the specified values of Illumination (2010,015E) and Reflected Ambient Light (2010,0160). An example of this derivation, as well as typical “default†values for these parameters, is specified in PS 3.14. +
+
+ + For scanned monochrome transmissive film viewed on a hypothetical viewing device, the luminance contribution due to reflected ambient light. Expressed as La, in candelas per square meter (cd/m2). +Note: May be used together with Illumination (2010,015E) to recover Optical Density information from P-Values. See C.8.6.3.1. +
Illumination (2010,015E) and Reflected Ambient Light (2010,0160) may be used to recover Optical Density information from P-Values. +Monochrome media that is being digitized is often measured in Optical Density values. These values need to be converted to P-Values for storage and display. The P-Values used in an image correspond to the perception of a human observer viewing the film on a hypothetical viewing device (such as a light box), using the specified values of Illumination (2010,015E) and Reflected Ambient Light (2010,0160). +The Grayscale Standard Display Function defined in PS 3.14 is used to convert Luminance to P-Values. In the case of scanned film, the Luminance is derived from Optical Density using the specified values of Illumination (2010,015E) and Reflected Ambient Light (2010,0160). An example of this derivation, as well as typical “default†values for these parameters, is specified in PS 3.14. +
+
+ + The value b in the relationship between stored values (SV) in Pixel Data (7FE0,0010) and the output units specified in Rescale Type (0028,1054). +Output units = m*SV + b. +Enumerated Value: 0 +Required if Photometric Interpretation (0028,0004) is MONOCHROME2, and BitsStored () is greater than 1. +Note: This specifies an identity Modality LUT transformation. + + + m in the equation specified by Rescale Intercept (0028,1052). +Enumerated Value: 1 +Required if Photometric Interpretation (0028,0004) is MONOCHROME2, and BitsStored (0028,0101) is greater than 1. +Note: This specifies an identity Modality LUT transformation. + + + Specifies the output units of Rescale Slope (0028,1053) and Rescale Intercept (0028,1052). +Enumerated Value: US = Unspecified +Required if Photometric Interpretation (0028,0004) is MONOCHROME2, and BitsStored (0028,0101) is greater than 1. +Note: This specifies an identity Modality LUT transformation. + + + Contains the Data Element Tag of the attribute which is used as the frame increment in Multi-frame pixel data. See C.7.6.6.1.1 for further explanation. +Shall be present if Number of Frames is greater than 1, overriding (specializing) the Type 1 requirement on this attribute in the Multi-frame Module. +
A Multi-frame Image is defined as a Image whose pixel data consists of a sequential set of individual Image Pixel frames. A Multi-frame Image is transmitted as a single contiguous stream of pixels. Frame headers do not exist within the data stream. +Each individual frame shall be defined (and thus can be identified) by the Attributes in the Image Pixel Module (see C.7.6.3). All Image IE Attributes shall be related to the first frame in the Multi-frame image. +The total number of frames contained within a Multi-frame Image is conveyed in the Number of Frames (0028,0008). +The frames within a Multi-frame Image shall be conveyed as a logical sequence. The information that determines the sequential order of the frames shall be identified by the Data Element Tag or tags conveyed by the Frame Increment Pointer (0028,0009). Each specific Image IOD that supports the Multi-frame Module specializes the Frame Increment Pointer (0028,0009) to identify the Attributes that may be used as sequences. +Even if only a single frame is present, Frame Increment Pointer (0028,0009) is still required to be present and have at least one value, each of which shall point to an attribute that is also present in the dataset and has a value. +Note: For example, in single-frame instance of an IOD that is required to or may contain the Cine Module, it may be appropriate for Frame Time (0018,1063) to be present with a value of 0, and be the only target of Frame Increment Pointer (0028,0009). + +
+
+ + Physical distance on the media being digitized or scanned between the center of each pixel, specified by a numeric pair - adjacent row spacing (delimiter) adjacent column spacing in mm. See 10.7.1.3 for further explanation of the value order. +Required if Conversion Type (0008,0064) is DF (Digitized Film). May also be present if Conversion Type (0008,0064) is SD (Scanned Document) or SI (Scanned Image). +Shall be consistent with Pixel Aspect Ratio (0028,0034), if present. + + + + Enumerated Values: +ROW +COLUMN + + + Angle of the edge of the film relative to the transport direction in degrees greater than or equal to -45 and less than or equal to +45. + +
+ + + An array which contains the real time increments (in msec) between frames for a Multi-frame image. +See C.7.6.5.1.2 for further explanation. +Required if Frame Increment Pointer (0028,0009) points to Frame Time Vector (0018,1065). +Note: Frame Time Vector arrays may not be properly encoded if Explicit-VR transfer syntax is used and the VL of this attribute exceeds 65534 bytes. +
Frame Time Vector (0018,1065) is an array that contains the time increments (in milliseconds) between the nth frame and the previous frame for a Multi-frame image. The first frame always has a time increment of 0. If the Frame Increment Pointer points to this Attribute, the Frame Time Vector shall be used in the following manner to calculate 'relative time' T(n) for frame n: + +where ï„ti is the ith Frame Time Vector component. +
+
+ + An array which contains, for each of the image frames, the corresponding page numbers of the original document. +Required if Frame Increment Pointer (0028,0009) points to Page Number Vector (0018,2001). + + + An array which contains, for each of the image frames, a descriptive label. +Required if Frame Increment Pointer (0028,0009) points to Frame Label Vector (0018,2002). + + + An array which contains, for each of the image frames, the primary angle of rotation about an undefined axis, in degrees. May be used for annotative purposes for "cine loops" of 3D reprojected images +Required if Frame Increment Pointer (0028,0009) points to Frame Primary Angle Vector (0018,2003). + + + An array which contains, for each of the image frames, the secondary angle of rotation about an undefined axis that is orthogonal to that used for Frame Primary Angle Vector (0018,2003), in degrees. May be used for annotative purposes for "cine loops" of 3D reprojected images +Required if Frame Increment Pointer (0028,0009) points to Frame Secondary Angle Vector (0018,2004). + + + An array that contains, for each of the image frames, the relative position of the image plane expressed in mm, as defined for Slice Location (0020,1041). See C.7.6.2.1.2 for further explanation. +Required if Frame Increment Pointer (0028,0009) points to Slice Location Vector (0018,2005). +
The Slice Location (0020,1041) is defined as the relative position of the image plane expressed in mm. This information is relative to an unspecified implementation specific reference point. +
+
+ + An array which contains, for each of the image frames, a label or number of the display window of a graphical user interface from which the frame was captured. +Required if Frame Increment Pointer (0028,0009) points to Display Window Label Vector (0018,2006). + +
+ + + Required if Multi-Frame Image. +Contains the Data Element Tag of the attribute that is used as the Frame increment in Multi-frame image pixel data (See C.7.6.6). Specialized for X-Ray as Enumerated Value: +00181063H = Frame Time (0018,1063); +00181065H = Frame Time Vector (0018,1065). +
Table C.7-14 specifies the Attributes of a Multi-frame pixel data Image. +Table C.7-14 +MULTI-FRAME MODULE ATTRIBUTES + +
+
+ + Specifies whether an Image has undergone lossy compression. Enumerated Values: +00 = Image has NOT been subjected to lossy compression. +01 = Image has been subjected to lossy compression. +See C.7.6.1.1.5 +Required if Lossy Compression has been performed on the Image. +
The Attribute Lossy Image Compression (0028,2110) conveys that the Image has undergone lossy compression. It provides a means to record that the Image has been compressed (at a point in its lifetime) with a lossy algorithm and changes have been introduced into the pixel data. Once the value has been set to “01â€, it shall not be reset. +Note: If an image is compressed with a lossy algorithm, the attribute Lossy Image Compression (0028,2110) is set to “01â€. Subsequently, if the image is decompressed and transferred in uncompressed format, this attribute value remains “01â€. + +The value of the Lossy Image Compression (0028,2110) Attribute in SOP Instances containing multiple frames in which one or more of the frames have undergone lossy compression shall be “01â€. +Note: It is recommended that the applicable frames be noted in the Attribute Derivation Description (0008,2111). + +If an image is originally obtained as a lossy compressed image from the sensor, then Lossy Image Compression (0028,2110) is set to “01†and Value 1 of the Attribute Image Type (0008,0008) shall be set to ORIGINAL. +If an image is a compressed version of another image, Lossy Image Compression (0028,2110) is set to “01â€, Value 1 of the Attribute Image Type (0008,0008) shall be set to DERIVED, and if the predecessor was a DICOM image, then the Image shall receive a new SOP Instance UID. +Note: 1. It is recommended that the approximate compression ratio be provided in the Attribute Derivation Description (0008,2111). Furthermore, it is recommended that Derivation Description (0008,2111) be used to indicate when pixel data changes might affect professional interpretation. (see C.7.6.1.1.3). + 2. The attribute Lossy Image Compression (0028,2110) is defined as Type 3 for backward compatibility with existing IODs. It is expected to be required (i.e., defined as Type 1C) for new Image IODs and for existing IODs that undergo a major revision (e.g. a new IOD is specified). +The Defined Terms for Lossy Image Compression Method (0028,2114) are: +ISO_10918_1 = JPEG Lossy Compression +ISO_14495_1 = JPEG-LS Near-lossless Compression +ISO_15444_1 = JPEG 2000 Irreversible Compression +ISO_13818_2 = MPEG2 Compression + +
+
+ + Image identification characteristics. +See C.8.7.1.1.1 for specialization. +
The Image Type attribute identifies important image characteristics in a multiple valued data element. For X-Ray, Image Type is specialized as follows: +a. Value 1 shall identify the Pixel Data Characteristics in accordance with Section C.7.6.1.1.2; Enumerated Values are: ORIGINAL and DERIVED; +b. Value 2 shall identify the Patient Examination Characteristics in accordance with Section C.7.6.1.1.2; Enumerated Values are: PRIMARY and SECONDARY. + +Note: X-Ray images generally use PRIMARY value for images captured from patient exposure. + +c. Value 3 shall identify the image set in terms of the imaging planes. Enumerated Values are: + + +d. Other Values are implementation specific (optional). + +
+
+ + The relationship between the Pixel sample values and the X-Ray beam intensity. +See Section C.8.7.1.1.2. +
Pixel Intensity Relationship (0028,1040) shall identify the relationship of the pixel values to the X-Ray beam intensity. Defined terms are: + +
+
+ + Number of samples (color planes) in this image shall have a value of 1. + + + Specifies the intended interpretation of the pixel data. Only MONOCHROME2 may be used. + + + Number of bits allocated for each pixel sample. +See Section C.8.7.1.1.6. +
For X-Ray Images, Bits Allocated (0028,0100) shall have the Enumerated Value of 8 or 16. +
+
+ + Number of bits stored for each pixel sample. +See Section C.8.7.1.1.7. +
For X-Ray Images, Bits Stored (0028,0101) shall have the Enumerated Values of 8, 10, 12, or 16. +
+
+ + Most significant bit for pixel sample data. +See Section C.8.7.1.1.8. +
For X-Ray Images, High Bit (0028,0102) shall have the Enumerated Value of one less than the value in Bit Stored. +
+
+ + Data representation of the pixel samples. +Shall have the value: +0000H = Unsigned Integer. + + + Parameters of scanning sequence. +See Section C. 8.7.1.1.4. + + + + Marks the location(s) of the R Wave in the cardiac cycles by referencing frame numbers; frame numbers begin with 1. + + + A sequence which provides reference to a set of Image SOP Class/Instance identifying other images significantly related to this image. Shall be present if Image Type (0008,0008) Value 3 is BIPLANE A or BIPLANE B. May be present otherwise. One or more items may be included in this sequence.. +See Section C.8.7.1.1.13. +
When Image Type (0008,0008) Value 3 is BIPLANE A or BIPLANE B, Referenced Image Sequence (0008,1140) shall be used to identify the corresponding SOP Instance of the Biplane acquisition. In this case, either: +
+
+ + + Describes the purpose for which the reference is made. Only a single Item shall be permitted in this Sequence. + + + + A text description of how this image was derived. +See C.8.7.1.1.5 for further explanation. +
If an Image is identified to be a Derived image (see C.8.9.1.1.1 Image Type), Derivation Description (0008,2111) is an optional and implementation specific text description of the way the image was derived from an original image. As applied to X-Ray images, it may be used to describe derivation operations such as edge enhancement, temporal filtering, digital subtraction, or other linear and non-linear transformations. +
+
+ + Indicates any visual processing performed on the images prior to exchange. +See Section C.8.7.1.1.3. +
Acquisition Device Processing Description (0018,1400) provides some indication in human readable text of the digital processing on the images before exchange. Examples of this processing are: edge enhanced, subtracted, time filtered, gamma corrected, convolved (spatially filtered). +
+
+ + A multi-valued attribute that contains a descriptive label for each of the image frames. The number of values shall equal the number of frames. + + + Contains the Data Element Tags of one or more attributes that vary or increment for the frames of a multi-frame image. See C.8.7.1.1.12. +Shall not be present if it would contain only one value and that value would be Frame Time (0018,1063) or Frame Time Vector (0018,1065). +
Frame Dimension Pointer (0028,000A) identifies attributes that vary or increment with each frame, and which are clinically significant for viewing or processing the image. This is intended for SOP Instances whose preferred clinical presentation is dependent on frame relationships other than simply time. +Defined Terms for multiframe cine from the Cine Module (see C.7.6.5) are: +00181063H = Frame Time (0018,1063) +00181065H = Frame Time Vector (0018,1065) +Defined Terms for rotational acquisition from the XA Positioner Module (see C.8.7.5) are: +00181520H = Positioner Primary Angle Increment (0018,1520) +00181521H = Positioner Secondary Angle Increment (0018,1521) +Defined Terms for stepped acquisition from the X-Ray Table Module (see C.8.7.4) are: +00181135H = Table Vertical Increment (0018,1135) +00181137H = Table Longitudinal Increment (0018,1137) +00181136H = Table Lateral Increment (0018,1136) +Defined Terms for an arbitrary labeled increment: +00182002H = Frame Label Vector (0018,2002) + +Notes: 1. Previous editions of the standard did not include the optional Frame Dimension Pointer (0028,000A), but instead depended entirely on the mandatory Frame Increment Pointer (0028,0009), and envisaged that only time and no other dimension would relate frames. Image creators that add the Frame Dimension Pointer (0028,000A) must anticipate that many implementations will ignore or discard this attribute when displaying or storing images and continue to assume that frames are temporally related. + 2. Frame Time (0018,1063) or Frame Time Vector (0018,1065) will also be present and will contain appropriate values consistent with the times of acquisition of the frames. + +
+
+ + Indicates whether a reference object (phantom) of known size is present in the image and was used for calibration. Enumerated Values: +YES +NO +Device is identified using the Device module. See C.7.6.12. +
Table C.7-18 describes the Attributes of devices or calibration objects (e.g., catheters, markers, baskets) that are associated with a study and/or image. +Table C.7-18 +DEVICE MODULE ATTRIBUTES + +
+
+
+ + + Peak kilo voltage output of the X-Ray generator used. + + + Identify the general level of X-Ray dose exposure. Enumerated values are: +SC = low dose exposure generally corresponding to fluoroscopic settings (e.g. preparation for diagnostic quality image acquisition); +GR = high dose for diagnostic quality image acquisition (also called digital spot or cine); + + + X-Ray Tube Current in mA. Required if Exposure (0018,1152) is not present. May be present otherwise. + + + X-Ray Tube Current in µA. + + + Duration of X-Ray exposure in msec. See 8.7.2.1.1. Required if Exposure (0018,1152) is not present. May be present otherwise. + + + Duration of X-Ray exposure in µsec. + + + The exposure expressed in mAs, for example calculated from Exposure Time and X-Ray Tube Current. Required if either Exposure Time (0018,1150) or X-Ray Tube Current (0018,1151) are not present. May be present otherwise. + + + The exposure expressed in µAs, for example calculated from Exposure Time and X-Ray Tube Current. + + + Identify the grid. Only a single value shall be present. Defined Terms are: +IN = A Grid is positioned; +NONE = No Grid is used. + + + Average width of X-Ray pulse in msec. + + + Specifies X-Ray radiation mode. Defined Terms: +CONTINUOUS +PULSED + + + Type of filter(s) inserted into the X-Ray beam (e.g. wedges). + + + Diameter of X-Ray intensifier in mm + + + Shape of the Image Intensifier Field of View. See C.8.7.2.1.2. Defined Terms are: +ROUND +RECTANGLE +
The Field of View Attribute describes the shape and dimensions of the Image Intensifier Field of View (zoom mode). This could be further restricted by the Collimator. See Section C.8.7.3. +
+
+ + Dimensions of the Image Intensifier Field of View in mm. If Rectangle, row dimension followed by column; if Round, diameter. + + + Physical distance measured at the front plane of the Image Receptor housing between the center of each pixel specified by a numeric pair - row spacing value(delimiter) column spacing value in mm. See 10.7.1.3 for further explanation of the value order. +The value of this attribute shall never be adjusted to account for correction for the effect of geometric magnification or calibration against an object of known size; Pixel Spacing (0028,0030) is specified for that purpose. + + + + Nominal focal spot size in mm used to acquire this image. + + + X-Ray dose, measured in dGy*cm*cm, to which the patient was exposed for the acquisition of this image plus any non-digitally recorded fluoroscopy which may have been performed to prepare for the acquisition of this image. +Note: The sum of the area dose product of all images of a Series or a Study may not result in the total area dose product to which the patient was exposed. + +
+ + + Shape(s) of the collimator. Enumerated Values: +RECTANGULAR +CIRCULAR +POLYGONAL +This multi-valued Attribute shall contain at most one of each Enumerated Value. + + + Required if Collimator Shape (0018,1700) is RECTANGULAR. Location of the left edge of the rectangular collimator with respect to pixels in the image given as column. See C.8.7.3.1.1. +
These attributes specify the pixel row or column where the X-Ray beam is fully obscured by a rectangular collimator: +- if the left edge of the collimator is not visible, Collimator Left Vertical Edge (0018,1702) shall have a value of 0; +- if the right edge of the collimator is not visible, Collimator Right Vertical Edge (0018,1704) value shall be 1 greater than the value of the Columns (0028,0011) attribute; +- if the top edge of the collimator is not visible, Collimator Upper Horizontal Edge (0018,1706) shall have a value of 0; +- if the bottom edge of the collimator is not visible, Collimator Lower Horizontal Edge (0018,1708) value shall be 1 greater than the value of the Rows (0028,0010) attribute. + +
+
+ + Required if Collimator Shape (0018,1700) is RECTANGULAR. Location of the right edge of the rectangular collimator with respect to pixels in the image given as column. See C.8.7.3.1.1. +
These attributes specify the pixel row or column where the X-Ray beam is fully obscured by a rectangular collimator: +- if the left edge of the collimator is not visible, Collimator Left Vertical Edge (0018,1702) shall have a value of 0; +- if the right edge of the collimator is not visible, Collimator Right Vertical Edge (0018,1704) value shall be 1 greater than the value of the Columns (0028,0011) attribute; +- if the top edge of the collimator is not visible, Collimator Upper Horizontal Edge (0018,1706) shall have a value of 0; +- if the bottom edge of the collimator is not visible, Collimator Lower Horizontal Edge (0018,1708) value shall be 1 greater than the value of the Rows (0028,0010) attribute. + +
+
+ + Required if Collimator Shape (0018,1700) is RECTANGULAR. Location of the upper edge of the rectangular collimator with respect to pixels in the image given as row. See C.8.7.3.1.1. +
These attributes specify the pixel row or column where the X-Ray beam is fully obscured by a rectangular collimator: +- if the left edge of the collimator is not visible, Collimator Left Vertical Edge (0018,1702) shall have a value of 0; +- if the right edge of the collimator is not visible, Collimator Right Vertical Edge (0018,1704) value shall be 1 greater than the value of the Columns (0028,0011) attribute; +- if the top edge of the collimator is not visible, Collimator Upper Horizontal Edge (0018,1706) shall have a value of 0; +- if the bottom edge of the collimator is not visible, Collimator Lower Horizontal Edge (0018,1708) value shall be 1 greater than the value of the Rows (0028,0010) attribute. + +
+
+ + Required if Collimator Shape (0018,1700) is RECTANGULAR. Location of the lower edge of the rectangular collimator with respect to pixels in the image given as row. See C.8.7.3.1.1. +
These attributes specify the pixel row or column where the X-Ray beam is fully obscured by a rectangular collimator: +- if the left edge of the collimator is not visible, Collimator Left Vertical Edge (0018,1702) shall have a value of 0; +- if the right edge of the collimator is not visible, Collimator Right Vertical Edge (0018,1704) value shall be 1 greater than the value of the Columns (0028,0011) attribute; +- if the top edge of the collimator is not visible, Collimator Upper Horizontal Edge (0018,1706) shall have a value of 0; +- if the bottom edge of the collimator is not visible, Collimator Lower Horizontal Edge (0018,1708) value shall be 1 greater than the value of the Rows (0028,0010) attribute. + +
+
+ + Required if Collimator Shape (0018,1700) is CIRCULAR. Location of the center of the circular collimator with respect to pixels in the image given as row and column. See C.8.7.3.1.1. +
These attributes specify the pixel row or column where the X-Ray beam is fully obscured by a rectangular collimator: +- if the left edge of the collimator is not visible, Collimator Left Vertical Edge (0018,1702) shall have a value of 0; +- if the right edge of the collimator is not visible, Collimator Right Vertical Edge (0018,1704) value shall be 1 greater than the value of the Columns (0028,0011) attribute; +- if the top edge of the collimator is not visible, Collimator Upper Horizontal Edge (0018,1706) shall have a value of 0; +- if the bottom edge of the collimator is not visible, Collimator Lower Horizontal Edge (0018,1708) value shall be 1 greater than the value of the Rows (0028,0010) attribute. + +
+
+ + Required if Collimator Shape (0018,1700) is CIRCULAR. Radius of the circular collimator with respect to pixels in the image given as a number of pixels along the row direction. See C.8.7.3.1.1. +
These attributes specify the pixel row or column where the X-Ray beam is fully obscured by a rectangular collimator: +- if the left edge of the collimator is not visible, Collimator Left Vertical Edge (0018,1702) shall have a value of 0; +- if the right edge of the collimator is not visible, Collimator Right Vertical Edge (0018,1704) value shall be 1 greater than the value of the Columns (0028,0011) attribute; +- if the top edge of the collimator is not visible, Collimator Upper Horizontal Edge (0018,1706) shall have a value of 0; +- if the bottom edge of the collimator is not visible, Collimator Lower Horizontal Edge (0018,1708) value shall be 1 greater than the value of the Rows (0028,0010) attribute. + +
+
+ + Required if Collimator Shape (0018,1700) is POLYGONAL. +Multiple Values where the first set of two values are: +row of the origin vertex; +column of the origin vertex. +Two or more pairs of values follow and are the row and column coordinates of the other vertices of the polygon collimator. Polygon collimators are implicitly closed from the last vertex to the origin vertex and all edges shall be non-intersecting except at the vertices. + +
+ + + Defined terms: +STATIC +DYNAMIC + + + Incremental change in Vertical position of the table relative to first frame of Multi-frame image given in mm. +Required if Table Motion is DYNAMIC. + + + Incremental change in Longitudinal position of the table relative to first frame of Multi-frame image in mm. Table motion towards +90°position of the primary angle of the positioner is positive. See C.8.7.4.1.2. +Required if Table Motion is DYNAMIC. +
The direction of the longitudinal movement is perpendicular to the primary axis of rotation of the positioner. A positive value of Table Longitudinal Increment (0018,1137) attributes indicates a movement towards the +90° position of the positioner, see figure C.8-9a. + +Figure C.8-9a +Table Longitudinal Movement +
+
+ + Incremental change in Lateral position of the table relative to first frame of Multi-frame image given in mm. Table motion towards +90°position of the secondary angle of the positioner is positive. See C.8.7.4.1.3. +Required if Table Motion is DYNAMIC. +
The direction of the lateral movement is perpendicular to the secondary axis of rotation of the positioner. A positive value of Table Lateral Increment (0018,1136) attributes indicates a movement towards the +90° position of the positioner, see figure C.8-9b. + +Figure C.8-9b +Table Lateral Movement +Note: The terms “longitudinal†and “lateral†are relative to an operator standing tableside, and facing the patient. Thus lateral movement is to the left and right of the operator, and longitudinal movement is towards or away from the operator. + +
+
+ + Angle of table plane in degrees relative to horizontal plane [Gravity plane]. Positive values indicate that the head of the table is upwards. + +
+ + + Distance in mm from source to isocenter (center of field of view). +Note: This value is traditionally referred to as Source Object Distance (SOD). + + + Distance in mm from source to detector center. +Note: This value is traditionally referred to as Source Image Receptor Distance (SID). + + + Ratio of Source Image Receptor Distance (SID) over Source Object Distance (SOD). + + + Used to describe the activity of the imaging devices. Defined terms: +DYNAMIC, +STATIC. +Required if Multi-frame data. See C.8.7.5.1.1. +
Positioner Motion attribute is STATIC if the imaging table moves during a multi-frame acquisition, but the X-Ray positioner do not move. +Note: If the positioner undergoes translation (non-rotational movement) during the acquisition, then that motion shall be described by an opposite table motion (See Section C.8.7.4). + +
+
+ + Position of the X-Ray Image Intensifier about the patient from the RAO to LAO direction where movement from RAO to vertical is positive. +See C.8.7.5.1.2. +
The definitions of Positioner Angles shall be with respect to the patient as illustrated in Figures C.8-11 and C.8-12 Zero degree is referenced to the origin perpendicular to the patient's chest. The Positioner Primary Angle definition is like longitude (in the equatorial plan); the Positioner Secondary Angle definition is like latitude (in the sagittal plane). The Positioner Angle attributes apply to the first frame of a multi-frame image. The valid range of Primary Positioner Angle is -180 to +180 degrees and the Secondary Positioner Angle range is -90 to + 90 degrees. +The Patient Plane is defined by the isocenter of the imaging device and slices through the patient such that it is perpendicular to the sagittal plane of the body. The Primary Axis of rotation is defined at the intersection of the Patient Plane and of the Sagittal Plane. The Positioner Primary Angle is defined in the transaxial plane at the isocenter with zero degrees in the direction perpendicular to the patient's chest and + 90 degrees at the Patient left hand side (LAO) and -90 at the Patient right hand side (RAO). The valid range of Primary Positioner Angle is -180 to +180 degrees. +The Secondary Axis is in the Patient Plane and is perpendicular to the Primary Axis at the isocenter. The Positioner Secondary Angle is defined in the Sagittal Plane at the isocenter with zero degrees in the direction perpendicular to the patient's chest. +90 degrees corresponds to the cranial direction. The Secondary Positioner Angle range is -90 to + 90 degrees. +At a 0 angle for both the Primary Angle (0018,1510) and Secondary Angle (0018,1511), the patient faces the Image Intensifier. +The Positioner Primary Angle (0018,1510) and Secondary Angle (0018,1511) apply to the first frame of a multi-frame image. + +Figure C.8-11 +Positioner Primary Angle + +Figure C.8-12 +Positioner Secondary Angle +
+
+ + Position of the X-Ray Image Intensifier about the patient from the CAU to CRA direction where movement from CAU to vertical is positive. +See C.8.7.5.1.2 +
The definitions of Positioner Angles shall be with respect to the patient as illustrated in Figures C.8-11 and C.8-12 Zero degree is referenced to the origin perpendicular to the patient's chest. The Positioner Primary Angle definition is like longitude (in the equatorial plan); the Positioner Secondary Angle definition is like latitude (in the sagittal plane). The Positioner Angle attributes apply to the first frame of a multi-frame image. The valid range of Primary Positioner Angle is -180 to +180 degrees and the Secondary Positioner Angle range is -90 to + 90 degrees. +The Patient Plane is defined by the isocenter of the imaging device and slices through the patient such that it is perpendicular to the sagittal plane of the body. The Primary Axis of rotation is defined at the intersection of the Patient Plane and of the Sagittal Plane. The Positioner Primary Angle is defined in the transaxial plane at the isocenter with zero degrees in the direction perpendicular to the patient's chest and + 90 degrees at the Patient left hand side (LAO) and -90 at the Patient right hand side (RAO). The valid range of Primary Positioner Angle is -180 to +180 degrees. +The Secondary Axis is in the Patient Plane and is perpendicular to the Primary Axis at the isocenter. The Positioner Secondary Angle is defined in the Sagittal Plane at the isocenter with zero degrees in the direction perpendicular to the patient's chest. +90 degrees corresponds to the cranial direction. The Secondary Positioner Angle range is -90 to + 90 degrees. +At a 0 angle for both the Primary Angle (0018,1510) and Secondary Angle (0018,1511), the patient faces the Image Intensifier. +The Positioner Primary Angle (0018,1510) and Secondary Angle (0018,1511) apply to the first frame of a multi-frame image. + +Figure C.8-11 +Positioner Primary Angle + +Figure C.8-12 +Positioner Secondary Angle +
+
+ + Incremental change in primary positioner angle for each frame. +See C.8.7.5.1.3. +Required if Positioner Motion is DYNAMIC. +
If the positioner angles change during acquisition of a multi-frame image, the Positioner Angle Increment attributes describe the angular change per frame. +If the change in positioner angle is nominally constant for each frame, these fields may contain a single value of the average angular change per frame. Alternatively, the fields may contain a vector of offsets from the (initial) Positioner Angle attributes, with one value for each frame in the multi-frame image. The number of values in the Positioner Angle Increment attributes must be one, or must be equal to the Number of Frames attribute (0028,0008) in the Multi-Frame Module (see Section C.7.6.6). +Note: It is permissible to generate a vector of the absolute positioner angles in the Positioner Angle Increment attributes, and set the Positioner Primary and Secondary Angle attributes to value 0. + +
+
+ + Incremental change in secondary positioner angle for each frame. +See C.8.7.5.1.3. +Required if Positioner Motion is DYNAMIC. +
If the positioner angles change during acquisition of a multi-frame image, the Positioner Angle Increment attributes describe the angular change per frame. +If the change in positioner angle is nominally constant for each frame, these fields may contain a single value of the average angular change per frame. Alternatively, the fields may contain a vector of offsets from the (initial) Positioner Angle attributes, with one value for each frame in the multi-frame image. The number of values in the Positioner Angle Increment attributes must be one, or must be equal to the Number of Frames attribute (0028,0008) in the Multi-Frame Module (see Section C.7.6.6). +Note: It is permissible to generate a vector of the absolute positioner angles in the Positioner Angle Increment attributes, and set the Positioner Primary and Secondary Angle attributes to value 0. + +
+
+ + Angle of the X-Ray beam in the row direction in degrees relative to the normal to the detector plane. Positive values indicate that the X-Ray beam is tilted towards higher numbered columns. Negative values indicate that the X-Ray beam is tilted towards lower numbered columns. +See C.8.7.5.1.4. +
Detector Angles are defined in a fashion similar to the positioner angles, except that the angle of the central x-ray beam vector is relative to the detector plane rather than the patient plane. The central x-ray beam vector is defined as the vector from the x-ray source through the isocenter to the detector plane. Zero degree is referenced to the normal to the detector plane pointing away from the x-ray source. The Detector Angle attributes apply to the first frame of a multi-frame image. The valid range of the Detector Angles is -90 to + 90 degrees. +The Primary Axis of rotation is defined along the line in the column direction of the detector plane which intersects the central x-ray beam vector. The Detector Primary Angle is defined in the plane perpendicular to the Primary Axis of rotation at the point where the central x-ray beam vector intersects the detector plane, with zero degrees in the direction normal to the detector plane and -90 degrees at the left hand side of the image (i.e., toward column 1) and +90 at the right hand side of the image (i.e., toward the highest numbered column). The valid range of Primary Detector Angle is -90 to +90 degrees. +The Secondary Axis is in the detector plane and is perpendicular to the Primary Axis at the intersection of the beam vector with the detector plane (i.e., it is along the row direction). The Detector Secondary Angle is defined in the plane perpendicular to the Secondary Axis at the point where the central x-ray beam vector intersects the detector plane, with zero degrees in the direction normal to the detector plane. +90 degrees corresponds to the direction toward the top of the image. The Secondary Detector Angle range is -90 to + 90 degrees. +
+
+ + Angle of the X-Ray beam in the column direction in degrees relative to the normal to the detector plane. Positive values indicate that the X-Ray beam is tilted towards lower numbered rows. Negative values indicate that the X-Ray beam is tilted towards higher numbered rows. +See C.8.7.5.1.4. +
Detector Angles are defined in a fashion similar to the positioner angles, except that the angle of the central x-ray beam vector is relative to the detector plane rather than the patient plane. The central x-ray beam vector is defined as the vector from the x-ray source through the isocenter to the detector plane. Zero degree is referenced to the normal to the detector plane pointing away from the x-ray source. The Detector Angle attributes apply to the first frame of a multi-frame image. The valid range of the Detector Angles is -90 to + 90 degrees. +The Primary Axis of rotation is defined along the line in the column direction of the detector plane which intersects the central x-ray beam vector. The Detector Primary Angle is defined in the plane perpendicular to the Primary Axis of rotation at the point where the central x-ray beam vector intersects the detector plane, with zero degrees in the direction normal to the detector plane and -90 degrees at the left hand side of the image (i.e., toward column 1) and +90 at the right hand side of the image (i.e., toward the highest numbered column). The valid range of Primary Detector Angle is -90 to +90 degrees. +The Secondary Axis is in the detector plane and is perpendicular to the Primary Axis at the intersection of the beam vector with the detector plane (i.e., it is along the row direction). The Detector Secondary Angle is defined in the plane perpendicular to the Secondary Axis at the point where the central x-ray beam vector intersects the detector plane, with zero degrees in the direction normal to the detector plane. +90 degrees corresponds to the direction toward the top of the image. The Secondary Detector Angle range is -90 to + 90 degrees. +
+
+
+ + + Distance in mm from source to detector center. +Note: This value is traditionally referred to as Source Image Receptor Distance (SID). + + + Distance in mm from source to isocenter (center of field of view). +Note: This value is traditionally referred to as Source Object Distance (SOD). + + + Ratio of SID (Source Image Receptor Distance) over SOD (Source Object Distance). + + + Angle of the X-Ray beam in degree relative to an orthogonal axis to the detector plane. Positive values indicate that the tilt is towards the head of the table. +Note: The detector plane is assumed to be parallel to the table plane. + + + + + Distance in mm between the table surface and the sharp image plane. + + + Angle span in degrees of rotation of X-Ray Source during X-Ray acquisition. + + + Time in seconds the source has taken to rotate the Tomo Angle during X-Ray acquisition. + + + Type of tomography. +Defined Terms: +LINEAR +SPIRAL +POLYCYCLOIDAL +CIRCULAR + + + Form of tomography: +Defined Terms: +MOTION +TOMOSYNTHESIS + + + The number of source images used to construct this tomosynthetic image. Only meaningful if Tomo Class (0018,1491) is TOMOSYNTHESIS. These may be listed in Source Image Sequence (0008,2112) of the General Image Module. + + + + + Peak kilo voltage output of the X-Ray generator used. + + + X-Ray Tube Current in mA. + + + X-Ray Tube Current in µA. + + + Duration of X-Ray exposure in msec. + + + Duration of X-Ray exposure in µsec. + + + The exposure expressed in mAs, for example calculated from Exposure Time and X-Ray Tube Current. + + + The exposure expressed in µAs, for example calculated from Exposure Time and X-Ray Tube Current. + + + Distance in mm from source to detector center. +Note: This value is traditionally referred to as Source Image Receptor Distance (SID). + + + Distance in mm from source to the table, support or bucky side that is closest to the Imaging Subject, as measured along the central ray of the X-Ray beam. +Note: 1. This definition is less useful in terms of estimating geometric magnification than a measurement to a defined point within the Imaging Subject, but accounts for what is realistically measurable in an automated fashion in a clinical setting. +2. This measurement does not take into account any air gap between the Imaging Subject and the "front" of the table or bucky. +3. If the detector is not mounted in a table or bucky, then the actual position relative to the patient is implementation or operator defined. +4. This value is traditionally referred to as Source Object Distance (SOD). + + + X-Ray dose, measured in dGy*cm*cm, to which the patient was exposed for the acquisition of this image plus any non-digitally recorded fluoroscopy which may have been performed to prepare for the acquisition of this image. +Notes: 1. The sum of the area dose product of all images of a Series or a Study may not result in the total area dose product to which the patient was exposed. +2. This may be an estimated value based on assumptions about the patient's body size and habitus. + + + The average thickness in mm of the body part examined when compressed, if compression has been applied during exposure. + + + Indication of the applied dose, in manufacturer specific units. +Notes: 1. This value is intended to provide a single location where manufacturer specific information can be found for annotation on a display or film, that has meaning to a knowledgeable observer. +2. This may be a calculated or measured value. Examples are the detector entrance dose (KB), the CR sensitivity value (S), or the logarithmic median (lgM). + + + Average entrance dose value measured in dGy at the surface of the patient during the acquisition of this image. +Note: This may be an estimated value based on assumptions about the patient's body size and habitus. + + + Average entrance dose value measured in mGy at the surface of the patient during the acquisition of this image. +Note: This may be an estimated value based on assumptions about the patient's body size and habitus. + + + Typical dimension of the exposed area at the detector plane. If Rectangular: row dimension followed by column; if Round: diameter. Measured in cm. +Notes: 1. The exposed area should be consistent with values specified in the X-Ray Collimator Module, if present. +2. This may be an estimated value based on assumptions about the patient's body size and habitus. +3. This attribute is used in the Radiation Dose Module with units in mm (see Section C.4.16 Table C.4-16). + + + Distance in mm from the source to the surface of the patient closest to the source during the acquisition of this image. +Note: This may be an estimated value based on assumptions about the patient's body size and habitus. + + + User-defined comments on any special conditions related to radiation dose encountered during the acquisition of this image. + + + The X-Ray output at the patient entrance surface and kVp used to acquire the image, measured in mGy/mAs. +Note: This value may be a calibrated value rather than measured during the exposure. + + + The thickness of Aluminum in mm required to reduce the X-Ray Output (0040,0312) by a factor of two. +Note: This value may be a calibrated value rather than measured during the exposure. + + + Average organ dose value measured in dGy during the acquisition of this image. +Note: This may be an estimated value. + + + Organ to which Organ Dose (0040,0316) applies. +Defined Terms: +BREAST +GONADS +BONE MARROW +FETUS +LENS +Note: The anatomic regions described by these terms are those that are particularly radiosensitive and for which it is conventional to obtain organ specific dose parameters. + + + The primary material in the anode of the X-Ray source. +Defined Terms: +TUNGSTEN +MOLYBDENUM +RHODIUM + + + The X-Ray absorbing material used in the filter. May be multi-valued. +Defined Terms: +MOLYBDENUM +ALUMINUM +COPPER +RHODIUM +NIOBIUM +EUROPIUM +LEAD + + + The minimum thickness in mm of the X-Ray absorbing material used in the filters. May be multi-valued, with values corresponding to the respective values in Filter Material (0018,7050). + + + The maximum thickness in mm of the X-Ray absorbing material used in the filters. May be multi-valued, with values corresponding to the respective values in Filter Material (0018,7050). + + + Type of rectification used in the X-Ray generator. +Defined Terms: +SINGLE PHASE +THREE PHASE +CONST POTENTIAL + + + + + Peak kilo voltage output of the X-Ray generator used. + + + X-Ray Tube Current in mA. + + + X-Ray Tube Current in µA. + + + Duration of X-Ray exposure in msec. + + + Duration of X-Ray exposure in µsec. + + + The exposure expressed in mAs, for example calculated from Exposure Time and X-Ray Tube Current. + + + The exposure expressed in µAs, for example calculated from Exposure Time and X-Ray Tube Current. + + + Type of exposure control. +Defined Terms: +MANUAL +AUTOMATIC + + + Text description of the mechanism of exposure control. +May describe the number and type of exposure sensors or position of the sensitive area of the imaging detector. + + + Whether the exposure was normally completed or not. +Defined Terms: +NORMAL +ABORTED + + + Nominal percentage phototimer setting, where a more positive value indicates greater exposure and a more negative value indicates less exposure. + + + Nominal focal spot size in mm used to acquire this image. + + + The primary material in the anode of the X-Ray source. +Defined Terms: +TUNGSTEN +MOLYBDENUM +RHODIUM + + + Type of rectification used in the X-Ray generator. +Defined Terms: +SINGLE PHASE +THREE PHASE +CONST POTENTIAL + + + Identifier of the generator + + + + + Type of filter(s) inserted into the X-Ray beam (e.g. wedges). +Defined Terms: +STRIP +WEDGE +BUTTERFLY +MULTIPLE +NONE + + + The X-Ray absorbing material used in the filter. May be multi-valued. +Defined Terms: +MOLYBDENUM +ALUMINUM +COPPER +RHODIUM +NIOBIUM +EUROPIUM +LEAD + + + The minimum thickness in mm of the X-Ray absorbing material used in the filters. May be multi-valued, with values corresponding to the respective values in Filter Material (0018,7050). + + + The maximum thickness in mm of the X-Ray absorbing material used in the filters. May be multi-valued, with values corresponding to the respective values in Filter Material (0018,7050). + + + + + Identifies the grid. May be multi-valued. +Defined Terms are: +FIXED +FOCUSED +RECIPROCATING +PARALLEL +CROSSED +NONE + + + The X-Ray absorbing material used in the grid. + + + The spacing material used in the grid. + + + The thickness in mm of the X-Ray absorbing material used in the grid. + + + The pitch in mm of the X-Ray absorbing material used in the grid. + + + Ratio of the vertical spacing and horizontal spacing of the X-Ray absorbing material used in the grid. Specified by a pair of integer values where the first value is the vertical size, and the second value is the horizontal size. + + + Period in mSec of reciprocation cycle. +Only meaningful if Grid (0018,1166) is RECIPROCATING. + + + Focal distance in mm of a FOCUSED grid. + + + Identifier of the grid + + + + + Type of equipment that originally acquired the data. Enumerated Values: +RTIMAGE = RT Image +RTDOSE = RT Dose +RTSTRUCT = RT Structure Set +RTPLAN = RT Plan +RTRECORD = RT Treatment Record +See C.8.8.1.1. +
The Enumerated Value for Modality (0008,0060) shall determined by the IOD: +RTIMAGE if RT Image IOD, +RTDOSE if RT Dose IOD, +RTSTRUCT if RT Structure Set IOD, +RTPLAN if RT Plan IOD or RT Ion Plan IOD, +RTRECORD if RT Beams Treatment Record IOD, RT Ion Beams Treatment Record IOD, RT Brachy Treatment Record IOD, or RT Treatment Summary Record IOD. +Note: DICOM specifies that a given series shall contain objects of only one Modality, and shall be created by a single device (described in the General Equipment Module). However, in general there may be many series defined for a given modality/device pair. Note that a radiotherapy series is generally created over an extended time interval (unlike in radiology, where all images in an image series are generally created together). + +
+
+ + Unique identifier of the series. + + + A number that identifies this series. + + + User provided description of the series. + + + Uniquely identifies the Performed Procedure Step SOP Instance to which the Series is related (e.g. a Modality or General-Purpose Performed Procedure Step SOP Instance). One or more items may be included in this sequence. + + + + Sequence that contains attributes from the Imaging Service Request. +The sequence may have one or more Items. + + + +
+ + + Number of samples (planes) in this image. See C.8.8.2.6.1 for specialization. +
For RT Images, Samples per Pixel (0028,0002) shall have the Enumerated Value of 0001H. +
+
+ + Specifies the intended interpretation of the pixel data. See C.8.8.2.6.2 for specialization. +
For RT Images, Photometric Interpretation (0028,0004) shall have the Enumerated Value of MONOCHROME2. +
+
+ + Number of bits allocated for each pixel sample. Each sample shall have the same number of bits allocated. See C.8.8.2.6.3 for specialization. +
For RT Images, Bits Allocated (0028,0100) shall have an Enumerated Value of 8 or 16. +
+
+ + Number of bits stored for each pixel sample. Each sample shall have the same number of bits stored. See C.8.8.2.6.4 for specialization. +
For RT Images, Bits Stored (0028,0101) shall have an Enumerated Value of: + 8 when Bits Allocated (0028,0100) is 8 + 12-16 when Bits Allocated (0028,0100) is 16 +
+
+ + Most significant bit for each pixel sample. Each sample shall have the same high bit. See C.8.8.2.6.5 for specialization. +
For RT Images, High Bit (0028,0102) shall have the Enumerated Value of one less than the value sent in Bits Stored (0028,0101). +
+
+ + Data representation of the pixel samples. Each sample shall have the same pixel representation. See C.8.8.2.6.6 for specialization. +
For RT Images, Pixel Representation (0028,0103) shall have the Enumerated Value of 0000H (unsigned integer). +
+
+ + The relationship between the Pixel sample values and the X-Ray beam intensity. +Enumerated Values: +LIN = Linearly proportional to X-Ray beam intensity +LOG = Logarithmically proportional to X-Ray beam intensity +See C.8.11.3.1.2 for further explanation. +
Pixel Intensity Relationship (0028,1040) and Pixel Intensity Relationship Sign (0028,1041) describe how the stored pixel values in Pixel Data (7FE0,0010) are related to the X-Ray beam intensity incident on the detector. +They do not define a transformation intended to be applied to the pixel data for presentation. +Note: For example, if Pixel Intensity Relationship (0028,1040) is LIN and Pixel Intensity Relationship Sign (0028,1041) is -1, then lower values of Pixel Data (7FE0,0010) indicate higher X-Ray beam intensities corresponding to less radiographically dense regions projected on the image such as through air, and higher values of Pixel Data (7FE0,0010) indicate lower X-Ray beam intensities corresponding to more radiographically dense regions projected on the image such as through bone and radio-opaque contrast agents. + +The transformation to be applied to the pixel data for presentation is defined by the successive application of the conceptual Modality LUT, the VOI Attributes and the conceptual Presentation LUT. This shall result in the output of P-Values. +Rescale Slope (0028,1053) and Rescale Intercept (0028,1052) define a linear subset of a conceptual Modality LUT transformation. For IODs that include this Module, these Attributes define an identity transformation. IODs that include the DX Image Module shall not include the Modality LUT Module. +The Presentation LUT Shape (2050,0020) defines a subset of a conceptual Presentation LUT. For IODs that include this Module, this Attribute defines an identity transformation or inverse identity transformation. IODs that include the DX Image Module shall not include the Presentation LUT Module. +Photometric Interpretation (0028,0004) indicates whether lower values that are the output of the VOI Attributes should be displayed as darker or lighter. Since the output of the equivalent of a conceptual Presentation LUT is in P-Values, which are defined in PS 3.14 such that lower values correspond to lower luminance levels, then the definition of the Presentation LUT Shape (2050,0020), otherwise intended to be an identity transformation, must take into account the effect of the value specified for Photometric Interpretation (0028,0004). +Note: Regardless of the values of Pixel Intensity Relationship (0028,1040) and Pixel Intensity Relationship Sign (0028,1041), the grayscale transformations to be applied to the Pixel Data (7FE0,0010) are defined by the equivalent of the Modality LUT (Rescale Slope (0028,1053) and Rescale Intercept (0028,1052)), Value of Interest Attributes, Photometric Interpretation (0028,0004) and the equivalent of the Presentation LUT (Presentation LUT Shape (2050,0020)). However, the combination of the grayscale transformations and the description of the pixel intensity relationship, together define whether, for example, air is expected to be displayed as black or white. + +
+
+ + The sign of the relationship between the Pixel sample values stored in Pixel Data (7FE0,0010) and the X-Ray beam intensity. +Required if Pixel Intensity Relationship (0028,1040) is present. +Enumerated Values; +1 = Lower pixel values correspond to less X-Ray beam intensity +-1 = Higher pixel values correspond to less X-Ray beam intensity +See C.8.11.3.1.2 for further explanation. +
Pixel Intensity Relationship (0028,1040) and Pixel Intensity Relationship Sign (0028,1041) describe how the stored pixel values in Pixel Data (7FE0,0010) are related to the X-Ray beam intensity incident on the detector. +They do not define a transformation intended to be applied to the pixel data for presentation. +Note: For example, if Pixel Intensity Relationship (0028,1040) is LIN and Pixel Intensity Relationship Sign (0028,1041) is -1, then lower values of Pixel Data (7FE0,0010) indicate higher X-Ray beam intensities corresponding to less radiographically dense regions projected on the image such as through air, and higher values of Pixel Data (7FE0,0010) indicate lower X-Ray beam intensities corresponding to more radiographically dense regions projected on the image such as through bone and radio-opaque contrast agents. + +The transformation to be applied to the pixel data for presentation is defined by the successive application of the conceptual Modality LUT, the VOI Attributes and the conceptual Presentation LUT. This shall result in the output of P-Values. +Rescale Slope (0028,1053) and Rescale Intercept (0028,1052) define a linear subset of a conceptual Modality LUT transformation. For IODs that include this Module, these Attributes define an identity transformation. IODs that include the DX Image Module shall not include the Modality LUT Module. +The Presentation LUT Shape (2050,0020) defines a subset of a conceptual Presentation LUT. For IODs that include this Module, this Attribute defines an identity transformation or inverse identity transformation. IODs that include the DX Image Module shall not include the Presentation LUT Module. +Photometric Interpretation (0028,0004) indicates whether lower values that are the output of the VOI Attributes should be displayed as darker or lighter. Since the output of the equivalent of a conceptual Presentation LUT is in P-Values, which are defined in PS 3.14 such that lower values correspond to lower luminance levels, then the definition of the Presentation LUT Shape (2050,0020), otherwise intended to be an identity transformation, must take into account the effect of the value specified for Photometric Interpretation (0028,0004). +Note: Regardless of the values of Pixel Intensity Relationship (0028,1040) and Pixel Intensity Relationship Sign (0028,1041), the grayscale transformations to be applied to the Pixel Data (7FE0,0010) are defined by the equivalent of the Modality LUT (Rescale Slope (0028,1053) and Rescale Intercept (0028,1052)), Value of Interest Attributes, Photometric Interpretation (0028,0004) and the equivalent of the Presentation LUT (Presentation LUT Shape (2050,0020)). However, the combination of the grayscale transformations and the description of the pixel intensity relationship, together define whether, for example, air is expected to be displayed as black or white. + +
+
+ + User-defined label for RT Image. + + + User-defined name for RT Image. + + + User-defined description of RT Image. + + + Name of operator(s) acquiring or creating RT Image. + + + Image identification characteristics (see Section C.7.6.1.1.2). RT Images shall use one of the following Defined Terms for Value 3: +DRR = digitally reconstructed radiograph +PORTAL = digital portal image or portal film image +SIMULATOR = conventional simulator image +RADIOGRAPH = radiographic image +BLANK = image pixels set to background value +FLUENCE = fluence map + + + Describes the kind of image conversion. Defined Terms: +DV = Digitized Video +DI = Digital Interface +DF = Digitized Film +WSD = Workstation + + + Describes the origin of the parameter values reported in the image. Required if Value 3 of Image Type (0008,0008) is SIMULATOR or PORTAL. +Enumerated Values: +OPERATOR = manually entered by operator +PLAN = planned parameter values +ACTUAL = electronically recorded + + + Describes whether or not image plane is normal to beam axis. +Enumerated Values: +NORMAL = image plane normal to beam axis +NON_NORMAL = image plane non-normal to beam axis + + + Position in (x,y,z) coordinates of origin of IEC X-RAY IMAGE RECEPTOR System in the IEC GANTRY coordinate system (mm). See Note 2. + + + X-Ray Image Receptor Angle i.e. orientation of IEC X-RAY IMAGE RECEPTOR coordinate system with respect to IEC GANTRY coordinate system (degrees). See C.8.8.2.2. +
The X-Ray Image Receptor Angle (3002,000E) specifies the rotation of the image receptor device in the IEC X-RAY IMAGE RECEPTOR PLANE. A positive angle corresponds to a counter-clockwise rotation of the X-Ray Image Receptor as viewed from the radiation source in the IEC GANTRY coordinate system. The normal (non-rotated) value for this parameter is zero degrees. +
+
+ + The direction cosines of the first row and the first column with respect to the IEC X-RAY IMAGE RECEPTOR coordinate system. Required if RT Image Plane (3002,000C) is NON_NORMAL. May be present otherwise. + + + Physical distance (in mm) between the center of each image pixel, specified by a numeric pair - adjacent row spacing (delimiter) adjacent column spacing. See C.8.8.2.3 and 10.7.1.3 for further explanation. +
The Image Plane Pixel Spacing (3002,0011) attribute shall always be defined on the image plane, i.e. at the radiation machine source to image plane distance specified by RT Image SID (3002,0026). For images where the source-image distance is undefined or unknown (e.g. DRR images), RT Image SID (3002,0026) shall equal Radiation Machine SAD (3002,0022) and Image Plane Pixel Spacing (3002,0011) shall be defined on this common plane. +
+
+ + The x and y coordinates (in mm) of the upper left hand corner of the image, in the IEC X-RAY IMAGE RECEPTOR coordinate system. This is the center of the first pixel transmitted. See C.8.8.2.7. +
When RT Image Plane (3002,000C) is NORMAL and RT Image Orientation (3002,0010) is not provided, the orientation is defined as follows: The image viewing direction goes from the radiation source to the image (i.e. in the sense of a beam’s eye view, or along the negative Zr direction of the IEC X-RAY IMAGE RECEPTOR coordinate system). The direction of rows goes along the positive Xr direction and the direction of the columns goes along the negative Yr direction of the IEC X-RAY IMAGE RECEPTOR coordinate system. Other interpretations shall be documented in an implementation's conformance statement. +
+
+ + User-defined name identifying radiation machine used in acquiring or computing image (i.e. name of conventional simulator, electron accelerator, X-Ray device, or machine modeled when calculating DRR). + + + Measurement unit of machine dosimeter. +Enumerated Values: +MU = Monitor Unit +MINUTE = minute + + + Radiation source to Gantry rotation axis distance of radiation machine used in acquiring or computing image (mm). + + + Source to patient surface distance (in mm) of radiation machine used in acquiring or computing image. + + + Distance from radiation machine source to image plane (in mm) along radiation beam axis. See C.8.8.2.3. +
The Image Plane Pixel Spacing (3002,0011) attribute shall always be defined on the image plane, i.e. at the radiation machine source to image plane distance specified by RT Image SID (3002,0026). For images where the source-image distance is undefined or unknown (e.g. DRR images), RT Image SID (3002,0026) shall equal Radiation Machine SAD (3002,0022) and Image Plane Pixel Spacing (3002,0011) shall be defined on this common plane. +
+
+ + Source to reference object distance (in mm), as used for magnification calculation of RADIOGRAPH and SIMULATOR images. + + + Introduces sequence of one Class/Instance pair describing RT Plan associated with image. Only a single item shall be permitted in this sequence. + + + + Uniquely identifies the corresponding N-segment treatment beam specified by Beam Number (300A,00C0) within Beam Sequence in RT Beams Module within the RT Plan referenced in Referenced RT Plan Sequence (300C,0002). + + + Identifier of Fraction Group within RT Plan referenced in Referenced RT Plan Sequence (300C,0002). + + + Fraction Number of fraction during which image was acquired, within Fraction Group referenced by Referenced Fraction Group Number (300C,0022) within RT Plan referenced in Referenced RT Plan Sequence (300C,0002). + + + Cumulative Meterset Weight within Beam referenced by Referenced Beam Number (300C,0006) at which image acquisition starts. + + + Cumulative Meterset Weight within Beam referenced by Referenced Beam Number (300C,0006) at which image acquisition ends. + + + Introduces sequence of Exposure parameter sets, corresponding to exposures used in generating the image. One or more items may be included in this sequence. See C.8.8.2.4. +
The Exposure Sequence (3002,0030) allows specification of imaging parameters and aperture definitions for single exposure images (single item sequence) or multiple exposures (multiple item sequence). A multiple exposure image can be expressed as a multi-frame image containing either a single frame, or more than one frame. Referenced Frame Number (0008,1160) shall be specified for each Exposure Sequence item for multiple exposure images expressed using more than one frame. +
+
+ + Identifies corresponding image frame in multi-frame image. Required if there is more than one item in Exposure Sequence (3002,0030), and image is a multi-frame image. + + + Peak kilo voltage output (kV) of X-Ray generator used to acquire image. Required if Value 3 of Image Type (0008,0008) is PORTAL, SIMULATOR or RADIOGRAPH. + + + Imaging device X-Ray Tube Current (mA). Required if Value 3 of Image Type (0008,0008) is SIMULATOR or RADIOGRAPH. + + + Time of X-Ray exposure (msec). Required if Value 3 of Image Type (0008,0008) is SIMULATOR or RADIOGRAPH. + + + Treatment machine Meterset duration over which image has been acquired, specified in Monitor units (MU) or minutes as defined by Primary Dosimeter Unit (300A,00B3). Required if Value 3 of Image Type (0008,0008) is PORTAL. + + + Positions of diaphragm jaw pairs (in mm) in IEC BEAM LIMITING DEVICE coordinate axis in the IEC order X1, X2, Y1, Y2. + + + Introduces sequence of beam limiting device (collimator) jaw or leaf (element) positions for given exposure. One or more items may be included in this sequence. + + + Type of beam limiting device (collimator). +Enumerated Values: +X = symmetric jaw pair in IEC X direction +Y = symmetric jaw pair in IEC Y direction +ASYMX = asymmetric jaw pair in IEC X direction +ASYMY = asymmetric pair in IEC Y direction +MLCX = multileaf (multi-element) jaw pair in IEC X direction +MLCY = multileaf (multi-element) jaw pair in IEC Y direction + + + Radiation source to beam limiting device (collimator) distance (mm). + + + Number of leaf (element) or jaw pairs (equal to 1 for standard beam limiting device jaws). + + + Boundaries (in mm) of beam limiting device (collimator) leaves (elements) in IEC BEAM LIMITING DEVICE coordinate axis appropriate to RT Beam Limiting Device Type (300A,00B8), i.e. X-axis for MLCY, Y-axis for MLCX. Contains N+1 values, where N is the Number of Leaf/Jaw Pairs (300A,00BC), starting from Leaf (Element) Pair 1. Required if RT Beam Limiting Device Type (300A,00B8) is MLCX or MLCY. + + + Positions of beam limiting device (collimator) leaf or jaw (element) pairs (in mm) in IEC BEAM LIMITING DEVICE coordinate axis appropriate to RT Beam Limiting Device Type (300A,00B8), e.g. X-axis for MLCX, Y-axis for MLCY). Contains 2N values, where N is the Number of Leaf/Jaw Pairs (300A,00BC), in IEC leaf (element) subscript order 101, 102, ... 1N, 201, 202, ... 2N. + + + Introduces sequence of Applicators associated with Beam. Only a single item shall be permitted in this sequence. + + + User or machine supplied identifier for Applicator. + + + Type of Applicator. +Defined Terms: +ELECTRON_SQUARE = square electron applicator +ELECTRON_RECT = rectangular electron applicator +ELECTRON_CIRC = circular electron applicator +ELECTRON_SHORT = short electron applicator +ELECTRON_OPEN = open (dummy) electron applicator +INTRAOPERATIVE = intraoperative (custom) applicator +STEREOTACTIC = stereotactic applicator + + + User-defined description for Applicator. + + + Number of shielding blocks associated with Beam. + + + Introduces sequence of blocks associated with Beam. Required if Number of Blocks (300A,00F0) is non-zero. Zero or more items may be included in this sequence. + + + User-supplied identifier for block tray. + + + Radiation Source to attachment edge of block tray assembly (mm). + + + Type of block. +Enumerated Values: +SHIELDING = blocking material is inside contour +APERTURE = blocking material is outside contour + + + Indicates presence or otherwise of geometrical divergence +Enumerated Values: +PRESENT = block edges are shaped for beam divergence +ABSENT = block edges are not shaped for beam divergence + + + Indicates on which side of the Block Tray the block is mounted. +Enumerated Values: +PATIENT_SIDE = the block is mounted on the side of the Block Tray which is towards the patient. +SOURCE_SIDE = the block is mounted on the side of the Block Tray which is towards the radiation source. + + + Identification Number of the Block. The value of Block Number (300A,00FC) shall be unique within the Beam in which it is created. + + + User-defined name for block. + + + User-supplied identifier for material used to manufacture Block. + + + Physical thickness of block (in mm) parallel to radiation beam axis. + + + Number of (x,y) pairs defining the block edge. + + + A data stream of (x,y) pairs which comprise the block edge. The number of pairs shall be equal to Block Number of Points (300A,0104), and the vertices shall be interpreted as a closed polygon. Coordinates are projected onto the machine isocentric plane in the IEC BEAM LIMITING DEVICE coordinate system (mm). + + + A Sequence of data describing the fluence map attributes for a radiotherapy beam. +Only one item may be included in this sequence. +Required if the third value of Image Type (0008,0008) is FLUENCE. + + + Source of fluence data. +Enumerated Values: +CALCULATED = Calculated by a workstation +MEASURED=Measured by exposure to a film or detector. + + + The meterset corresponding with a fluence map cell value of 1.0 expressed in units specified by Primary Dosimeter Units (300A,00B3). This is the meterset value used for treatment, not the meterset used to expose the film as defined by Meterset Exposure (3002,0032). + + + Treatment machine gantry angle, i.e. orientation of IEC GANTRY coordinate system with respect to IEC FIXED REFERENCE coordinate system (degrees). + + + Gantry Pitch Angle. i.e. the rotation of the IEC GANTRY coordinate system about the X-axis of the IEC GANTRY coordinate system (degrees). See C.8.8.25.6.5. +
The Gantry Pitch angle is not defined in IEC 61217. This angle is defined in the DICOM standard in a way compatible with the current notion of IEC by introducing it as rotation of the IEC GANTRY System as indicated below. +The Gantry Pitch Angle is defined as the rotation of the coordinate axes Yg, Zg about axis Xg by an angle ï¹g; see Figure C.8.8.25-7. An increase in the value of angle ï¹g corresponds to the clockwise rotation as viewed from the isocenter along the positive Xg axis + + +Figure C.8.8.25-7 Gantry Pitch Angle +
+
+ + Treatment machine beam limiting device (collimator) angle, i.e. orientation of IEC BEAM LIMITING DEVICE coordinate system with respect to IEC GANTRY coordinate system (degrees). + + + Patient Support angle, i.e. orientation of IEC PATIENT SUPPORT coordinate system with respect to IEC FIXED REFERENCE coordinate system (degrees). + + + Distance (positive) from the IEC PATIENT SUPPORT vertical axis to the IEC TABLE TOP ECCENTRIC vertical axis (mm). + + + Table Top (non-isocentric) angle, i.e. orientation of IEC TABLE TOP ECCENTRIC coordinate system with respect to IEC PATIENT SUPPORT system (degrees). + + + Table Top Pitch Angle, i.e. the rotation of the IEC TABLE TOP coordinate system about the X-axis of the IEC TABLE TOP coordinate system (degrees). See C.8.8.25.6.2. +
Pitch and Roll Coordinate Systems of the Table Top are not defined in IEC 61217. These angles are defined in the DICOM standard in a way compatible with the current notion of IEC by introducing them as rotations of the IEC Table Top System as indicated below. +The Table Top Pitch Angle is defined as the rotation of the coordinate axes Yt, Zt about axis Xt by an angle ï¹t; see Figure C.8.8.25-3. An increase in the value of angle ï¹t corresponds to the clockwise rotation of the Table Top as viewed from the Table Top coordinate system origin along the positive Xt axis. +The Table Top Roll Angle is defined as the rotation of the coordinate axes Xt, Zt about axis Yt by an angle ïªt; see Figure C.8.8.25-4. An increase in the value of angle ïªt corresponds to the clockwise rotation of the Table Top as viewed from the Table Top coordinate system origin along the positive Yt axis. + + +Figure C.8.8.25-3 Table Top Pitch Angle + +Figure C.8.8.25-4 Table Top Roll Angle + +
+
+ + Table Top Roll Angle, i.e. the rotation of the IEC TABLE TOP coordinate system about the Y-axis of the IEC TABLE TOP coordinate system (degrees). See C.8.8.25.6.2. +
Pitch and Roll Coordinate Systems of the Table Top are not defined in IEC 61217. These angles are defined in the DICOM standard in a way compatible with the current notion of IEC by introducing them as rotations of the IEC Table Top System as indicated below. +The Table Top Pitch Angle is defined as the rotation of the coordinate axes Yt, Zt about axis Xt by an angle ï¹t; see Figure C.8.8.25-3. An increase in the value of angle ï¹t corresponds to the clockwise rotation of the Table Top as viewed from the Table Top coordinate system origin along the positive Xt axis. +The Table Top Roll Angle is defined as the rotation of the coordinate axes Xt, Zt about axis Yt by an angle ïªt; see Figure C.8.8.25-4. An increase in the value of angle ïªt corresponds to the clockwise rotation of the Table Top as viewed from the Table Top coordinate system origin along the positive Yt axis. + + +Figure C.8.8.25-3 Table Top Pitch Angle + +Figure C.8.8.25-4 Table Top Roll Angle + +
+
+ + Table Top Vertical position in IEC TABLE TOP coordinate system (mm). + + + Table Top Longitudinal position in IEC TABLE TOP coordinate system (mm). + + + Table Top Lateral position in IEC TABLE TOP coordinate system (mm). + + + Isocenter coordinates (x,y,z), in mm. Specifies the location of the machine isocenter in the patient-based coordinate system associated with the Frame of Reference. It allows transformation from the equipment-based IEC coordinate system to the patient-based coordinate system. + + + Patient position descriptor relative to the patient support device. +Required if Isocenter Position (300A,012C) is present. May be present otherwise. +See Section C.8.8.12.1.2 for Defined Terms and further explanation. +Note: The orientation of the patient relative to the patient support device is denoted in the same manner as in the RT Patient Setup module. It defines the relation of the patient-based DICOM coordinate system identified by the frame of reference module of the RT Image to the IEC coordinate system and together with the Isocenter Position (300A,012C) allows the RT Image to be placed into the patient frame of reference. It also allows a system using an RT Image to verify that the patient is setup in a similar position relative to the patient support device. +
Defined Terms for Patient Position shall be those specified in Section C.7.3.1.1.2, plus the following: + SITTING +In the sitting position, the patient’s face is towards the front of the chair. +
+
+
+ + + Number of samples (planes) in this image. See C.8.8.3.4.1 for specialization. Required if Pixel Data (7FE0,0010) is present. +
For RT Doses, Samples per Pixel (0028,0002) shall have the Enumerated Value of 1. +
+
+ + Specifies the intended interpretation of the pixel data. See C.8.8.3.4.2 for specialization. Required if Pixel Data (7FE0,0010) is present. +
For RT Doses, Photometric Interpretation (0028,0004) shall have the Enumerated Value of MONOCHROME2. +
+
+ + Number of bits allocated for each pixel sample. Each sample shall have the same number of bits allocated. See C.8.8.3.4.3 for specialization. Required Pixel Data (7FE0,0010) is present. +
For RT Doses, Bits Allocated (0028,0100) shall have an Enumerated Value of 16 or 32. +
+
+ + Number of bits stored for each pixel sample. Each sample shall have the same number of bits stored. See C.8.8.3.4.4 for specialization. Required if Pixel Data (7FE0,0010) is present. +
For RT Doses, Bits Stored (0028,0101) shall have an Enumerated Value equal to Bits Allocated (0028,0100). +
+
+ + Most significant bit for each pixel sample. Each sample shall have the same high bit. See C.8.8.3.4.5 for specialization. Required if Pixel Data (7FE0,0010) is present. +
For RT Doses, High Bit (0028,0102) shall have the Enumerated Value of one less than the value sent in Bits Stored (0028,0101). +
+
+ + Data representation of the pixel samples. Each sample shall have the same pixel representation. See C.8.8.3.4.6 for specialization. Required Pixel Data (7FE0,0010) is present. +
For RT Doses, Pixel Representation (0028,0103) is specified to use the following Enumerated Values: +0001H = two’s complement integer, when Dose Type (3004,0004) = ERROR +0000H = unsigned integer, otherwise. +
+
+ + Units used to describe dose. +Enumerated Values: +GY = Gray +RELATIVE = dose relative to implicit reference value + + + Type of dose. +Defined Terms: +PHYSICAL = physical dose +EFFECTIVE = physical dose after correction for biological effect using user-defined modeling technique +ERROR = difference between desired and planned dose + + + A number that identifies this object instance. + + + User-defined comments for dose data. + + + Coordinates (x, y, z) of normalization point in the patient based coordinate system described in C.7.6.2.1.1 (mm). See C.8.8.3.1. +
The Normalization Point (3004,0008) aids in the interpretation and subsequent use of the transmitted data. If used, it shall be a point receiving dose contributions from all referenced components of the dose summation. +
+
+ + Type of dose summation. +Defined Terms: +PLAN = dose calculated for entire RT Plan +FRACTION = dose calculated for a single Fraction Group within RT Plan +BEAM = dose calculated for one or more Beams within RT Plan +BRACHY = dose calculated for one or more Brachy Application Setups within RT Plan +CONTROL_POINT = dose calculated for one or more Control Points within a Beam + + + Introduces sequence of one Class/Instance pair describing RT Plan associated with dose. Required if Dose Summation Type (3004,000A) is PLAN, FRACTION, BEAM, BRACHY or CONTROL_POINT. Only a single item shall be permitted in this sequence. See Note 1. + + + + Introduces sequence of one Fraction Group containing beams or brachy application setups contributing to dose. Required if Dose Summation Type (3004,000A) is FRACTION, BEAM, BRACHY or CONTROL_POINT. Only a single item shall be permitted in this sequence. See Note 1. + + + Uniquely identifies Fraction Group specified by Fraction Group Number (300A,0071) in Fraction Group Sequence of RT Fraction Scheme Module within RT Plan referenced in Referenced RT Plan Sequence (300C,0002). + + + Introduces sequence of Beams in current Fraction Group contributing to dose. Required if Dose Summation Type (3004,000A) is BEAM or CONTROL_POINT. One or more items may be included in this sequence. + + + Uniquely identifies Beam specified by Beam Number (300A,00C0) in Beam Sequence of RT Beams Module within RT Plan referenced in Referenced RT Plan Sequence (300C,0002). + + + Sequence defining the Control Points in current Beam contributing to dose. +Required if Dose Summation Type (3004,000A) is CONTROL_POINT. +Only a single item shall be present in this sequence. + + + Identifies Control Point specified by Control Point Index (300A,0112) within Beam referenced by Referenced Beam Number (300C,0006). This is the first of the two Control Points from which the Dose contribution to the Control Point can be calculated. + + + Identifies Control Point specified by Control Point Index (300A,0112) within Beam referenced by Referenced Beam Number (300C,0006). This is the second of the two Control Points from which the Dose contribution to the Control Point can be calculated. +The Control Point Index (300A,0112) referenced by Referenced +Stop Control Point Index (300C,00F6) shall be the Control Point Index (300A,0112) immediately following the Control Point Index (300A,0112) referenced by Referenced Start Control Point Index (300C,00F4) within the Referenced Beam Number (300C,0006). + + + Introduces sequence of Brachy Application Setups in current Fraction Group contributing to dose. Required if Dose Summation Type (3004,000A) is BRACHY. One or more items may be included in this sequence. + + + Uniquely identifies Brachy Application Setup specified by Brachy Application Setup Number (300A,0234) in Brachy Application Setup Sequence (300A,0230) of RT Brachy Application Setups Module within RT Plan referenced in Referenced RT Plan Sequence (300C,0002). + + + An array which contains the dose image plane offsets (in mm) of the dose image frames in a multi-frame dose. Required if multi-frame pixel data are present and Frame Increment Pointer (0028,0009) points to Grid Frame Offset Vector (3004,000C). See C.8.8.3.2. +
Grid Frame Offset Vector (3004,000C) shall be provided if a dose distribution is sent as a multi-frame image. Values of the Grid Frame Offset Vector (3004,000C) shall vary monotonically and are to be interpreted as follows: +a. If Grid Frame Offset Vector (3004,000C) is present and its first element is zero, this attribute contains an array of n elements indicating the plane location of the data in the right-handed image coordinate system, relative to the position of the first dose plane transmitted, i.e., the point at which the Image Position (Patient) (0020,0032) attribute is defined, with positive offsets in the direction of the cross product of the row and column directions. +b. If Grid Frame Offset Vector (3004,000C) is present, its first element is equal to the third element of Image Position (Patient) (0020,0032), and Image Orientation (Patient) (0020,0037) has the value (1,0,0,0,1,0), then Grid Frame Offset Vector contains an array of n elements indicating the plane location (patient z coordinate) of the data in the patient coordinate system. + +In future implementations, use of option a) is strongly recommended. +This attribute is conditional since the RT Dose module may be included even if pixel doses are not being transmitted, or the image may be a single-frame image. If the Multi-frame Module is present, Frame Increment Pointer (0028,0009) shall have the Enumerated Value of 3004000C (Grid Frame Offset Vector). +Note: Option (a) can represent a rectangular-parallelepiped dose grid with any orientation with respect to the patient, while option (b) can only represent a rectangular-parallelepiped dose grid whose planes are in the transverse patient dimension and whose x- and y-axes are parallel to the patient x- and y-axes. + Example: Figure C.8.8.3-1 shows an example of plane positions for a dose grid with transverse planes. + + + +Figure C.8.8.3-1 Dose Grid Frame Example + For this example, Table C.8.39b gives the values of elements in the Grid Frame Offset Vector (3004,000C) for both relative (option (a)) and absolute (option (b)) interpretations, under the following conditions: + 1. The value of Image Orientation (Patient) (0020,0037) is (1,0,0,0,1,0). I.e., the dose grid is transverse with x- and y-axes parallel to the patient x- and y-axes; + 2. The value of Image Position (Patient) (0020,0032), i.e. the position of the first element of the dose grid, is (4, 5, 6); and + 3. The spacing between adjacent dose grid planes is 2mm (uniform). + +Table C.8-39b. Values of Dose Grid Frame Offset Vector under +Relative (a) and Absolute (b) Interpretations + +
+
+ + Scaling factor that when multiplied by the dose grid data found in the Pixel Data (7FE0,0010) attribute of the Image Pixel Module, yields grid doses in the dose units as specified by Dose Units (3004,0002). + + + Specifies a list of patient heterogeneity characteristics used for calculating dose. This Atttibute shall be multi-valued if beams used to compute the dose have differing correction techniques. Enumerated Values: +IMAGE = image data +ROI_OVERRIDE = one or more ROI densities override image or water values where they exist +WATER = entire volume treated as water equivalent + +
+ + + Introduces sequence of one class/instance pair describing Structure Set containing structures which are used to calculate Dose-Volume Histograms (DVHs). Only a single item shall be permitted in this sequence. See C.8.8.4.1. +
The Referenced Structure Set Sequence (300C,0060) is required for direct cross-reference of the dose bin data with the corresponding ROI(s) from which they were derived. ROIs referenced by the DVH Referenced ROI Sequence (3004,0050) shall only contain contours with a Contour Geometric Type (3006,0042) of POINT or CLOSED_PLANAR. +
+
+ + + Coordinates (x, y, z) of common DVH normalization point in the patient based coordinate system described in C.7.6.2.1.1 (mm). + + + Dose Value at DVH Normalization Point (3004,0040) used as reference for individual DVHs when Dose Units (3004,0002) is RELATIVE. + + + Introduces sequence of DVHs. One or more items may be included in this sequence. + + + Introduces sequence of referenced ROIs used to calculate DVH. One or more items may be included in this sequence. + + + Uniquely identifies ROI used to calculate DVH specified by ROI Number (3006,0022) in Structure Set ROI Sequence (3006,0020) in Structure Set Module within RT Structure Set referenced by referenced RT Plan in Referenced RT Plan Sequence (300C,0002) in RT Dose Module. + + + Specifies whether volume within ROI is included or excluded in DVH. See C.8.8.4.2. Enumerated Values: INCLUDED, EXCLUDED. +
The volume used to calculate the DVH shall be the geometric union of ROIs where DVH ROI Contribution Type (3004,0062) is INCLUDED, minus the geometric union of ROIs where DVH ROI Contribution Type (3004,0062) is EXCLUDED. +
+
+ + Type of DVH. +Enumerated Values: +DIFFERENTIAL = differential dose-volume histogram +CUMULATIVE = cumulative dose-volume histogram +NATURAL = natural dose volume histogram + + + Dose axis units. +Enumerated Values: +GY = Gray +RELATIVE = dose relative to reference value specified in DVH Normalization Dose Value (3004,0042) + + + Type of dose. +Defined Terms: +PHYSICAL = physical dose +EFFECTIVE = physical dose after correction for biological effect using user-defined modeling technique +ERROR = difference between desired and planned dose + + + Scaling factor that when multiplied by the dose bin widths found in DVH Data (3004,0058), yields dose bin widths in the dose units as specified by Dose Units (3004,0002). + + + Volume axis units. +Defined Terms: +CM3 = cubic centimeters +PERCENT = percent +PER_U= volume per u with u(dose)=dose-3/2. See C.8.8.4.3. +
The unit PER_U is defined in: Anderson, LL: “A “natural†volume-dose histogram for brachytherapyâ€, Medical Physics 13(6) pp 898-903, 1986. +
+
+ + Number of bins n used to store DVH Data (3004,0058). + + + A data stream describing the dose bin widths Dn and associated volumes Vn in DVH Volume Units (3004,0054) in the order D1V1, D2V2, ... DnVn. +Note: DVH Data arrays may not be properly encoded if Explicit-VR transfer syntax is used and the VL of this attribute exceeds 65534 bytes. + + + Minimum calculated dose to ROI(s) described by DVH Referenced ROI Sequence (3004,0060). + + + Maximum calculated dose to ROI(s) described by DVH Referenced ROI Sequence (3004,0060). + + + Mean calculated dose to ROI(s) described by DVH Referenced ROI Sequence (3004,0060). + +
+ + + User-defined label for Structure Set. + + + User-defined name for Structure Set. + + + User-defined description for Structure Set. + + + A number that identifies this object instance. + + + Date at which Structure Set was last modified. + + + Time at which Structure Set was last modified. + + + Introduces sequence of items describing Frames of Reference in which the ROIs are defined. One or more items may be included in this sequence. See C.8.8.5.1. +
The Referenced Frame of Reference Sequence (3006,0010) describes a set of frames of reference in which some or all of the ROIs are expressed. Since the Referenced Frame of Reference UID (3006,0024) is required for each ROI, each frame of reference used to express the coordinates of an ROI shall be listed in the Referenced Frame of Reference Sequence (3006,0010) once and only once. +Notes: 1.As an example, a set of ROIs defined using a single image series would list the image series in a single Referenced Frame of Reference Sequence (3006,0010) item, providing the UID for this referenced frame of reference (obtained from the source images), and listing all pertinent images in the Contour Image Sequence (3006,0016). + 2. As an example, a set of ROIs containing ROIs referencing more than one frame of reference would list the referenced images in two or more different Referenced Frame of Reference Sequence (3006,0010) items, providing in each case the UID for this referenced frame of reference (obtained from the source images), and listing all pertinent images in the Contour Image Sequence (3006,0016). Each ROI would then reference the appropriate Frame of Reference UID (0020,0052). + +
+
+ + Uniquely identifies Frame of Reference within Structure Set. + + + Introduces sequence of transforms that relate other Frames of Reference to this Frame of Reference. One or more items may be included in this sequence. + + + Frame of Reference Coordinate System to be transformed to the current Frame of Reference. + + + Type of Transformation. Required if Frame of Reference Relationship Sequence (3006,00C0) is sent. +Defined Terms: +HOMOGENEOUS + + + Four-by-four transformation Matrix from Related Frame of Reference to current Frame of Reference. Matrix elements shall be listed in row-major order. See C.8.8.5.2. +
In a rigid body system, two coordinate systems can be related using a single 4 x 4 transformation matrix to describe any rotations and/or translations necessary to transform coordinates from the related coordinate system (frame of reference) to the primary system. The equation performing the transform from a point (X’,Y’,Z’) in the related coordinate system to a point (X,Y,Z) in the current coordinate system can be shown as follows, where for homogeneous transforms M41 = M42 = M43 = 0 and M44 = 1: +X M11 M12 M13 M14 X’ +Y = M21 M22 M23 M24 x Y’ +Z M31 M32 M33 M34 Z’ +1 M41 M42 M43 M44 1 +
+
+ + Comment regarding the transformation between the related and current Frames of Reference. + + + Introduces sequence of Studies containing series to be referenced. One or more items may be included in this sequence. + + + + Introduces sequence of items describing series of images within the referenced study which are used in defining the Structure Set. One or more items may be included in this sequence. + + + Unique identifier for the series containing the images. + + + Introduces sequence of items describing images in a given series used in defining the Structure Set (typically CT or MR images). One or more items may be included in this sequence. + + + + Introduces sequence of ROIs for current Structure Set. One or more items may be included in this sequence. + + + Identification number of the ROI. The value of ROI Number (3006,0022) shall be unique within the Structure Set in which it is created. + + + Uniquely identifies Frame of Reference in which ROI is defined, specified by Frame of Reference UID (0020,0052) in Referenced Frame of Reference Sequence (3006,0010). + + + User-defined name for ROI. + + + User-defined description for ROI. + + + Volume of ROI (cubic centimeters). + + + Type of algorithm used to generate ROI. +Defined Terms: +AUTOMATIC = calculated ROI +SEMIAUTOMATIC = ROI calculated with user assistance +MANUAL = user-entered ROI + + + User-defined description of technique used to generate ROI. + +
+ + + Introduces sequence of Contour Sequences defining ROIs. One or more items may be included in this sequence. + + + Uniquely identifies the referenced ROI described in the Structure Set ROI Sequence (3006,0020). + + + RGB triplet color representation for ROI, specified using the range 0-255. + + + Introduces sequence of Contours defining ROI. One or more items may be included in this sequence. + + + Identification number of the contour. The value of Contour Number (3006,0048) shall be unique within the Contour Sequence (3006,0040) in which it is defined. No semantics or ordering shall be inferred from this attribute. + + + List of Contour Number (3006,0048) defining lower-numbered contour(s) to which the current contour is connected. + + + Introduces sequence of images containing the contour. One or more items may be included in this sequence. + + + + Geometric type of contour. See C.8.8.6.1. +Enumerated Values: +POINT = single point +OPEN_PLANAR = open contour containing coplanar points +OPEN_NONPLANAR = open contour containing non-coplanar points +CLOSED_PLANAR = closed contour (polygon) containing coplanar points +
A contour can be one of the following geometric types: +- A Contour Geometric Type (3006,0042) of POINT indicates that the contour is a single point, defining a specific location of significance. +- A Contour Geometric Type (3006,0042) of OPEN_PLANAR indicates that the last vertex shall not be connected to the first point, and that all points in Contour Data (3006,0050) shall be coplanar. +- A Contour Geometric Type (3006,0042) of OPEN_NONPLANAR indicates that the last vertex shall not be connected to the first point, and that the points in Contour Data (3006,0050) may be non-coplanar. Contours having a Geometric Type (3006,0042) of OPEN_NONPLANAR can be used to represent objects best described by a single, possibly non-coplanar curve, such as a brachytherapy applicator. +- A Contour Geometric Type (3006,0042) of CLOSED_PLANAR indicates that the last point shall be connected to the first point, where the first point is not repeated in the Contour Data (3006,0050). All points in Contour Data (3006,0050) shall be coplanar. +
+
+ + Thickness of slab (in mm) represented by contour, where the Contour Data (3006,0050) defines a plane in the center of the slab, offset by the Contour Offset Vector (3006,0045) if it is present. See C.8.8.6.2. +
A set of Contour slabs may define a multi-slab Volume of Interest. Contour Slab Thickness (3006,0044) shall specify the thickness of a slab, the central plane of which shall be defined by the set of points offset from Contour Data (3006,0050) by the value of Contour Offset Vector (3006,0045). One contour slab may contain one to many sets of Contour Data (3006,0050) that may define regions of one complex Volume of Interest. If no valid value of Contour Slab Thickness (3006,0044) is sent, then the offset value shall be (0,0,0) and the original Contour Data (3006,0050) shall define the central plane of the Contour slab. +
+
+ + Vector (x,y,z) in the the patient based coordinate system described in C.7.6.2.1.1 which is normal to plane of Contour Data (3006,0050), describing direction and magnitude of the offset (in mm) of each point of the central plane of a contour slab from the corresponding original point of Contour Data (3006,0050). See C.8.8.6.2. +
A set of Contour slabs may define a multi-slab Volume of Interest. Contour Slab Thickness (3006,0044) shall specify the thickness of a slab, the central plane of which shall be defined by the set of points offset from Contour Data (3006,0050) by the value of Contour Offset Vector (3006,0045). One contour slab may contain one to many sets of Contour Data (3006,0050) that may define regions of one complex Volume of Interest. If no valid value of Contour Slab Thickness (3006,0044) is sent, then the offset value shall be (0,0,0) and the original Contour Data (3006,0050) shall define the central plane of the Contour slab. +
+
+ + Number of points (triplets) in Contour Data (3006,0050). + + + Sequence of (x,y,z) triplets defining a contour in the patient based coordinate system described in C.7.6.2.1.1 (mm). See C.8.8.6.1 and C.8.8.6.3. +Note: Contour Data may not be properly encoded if Explicit-VR transfer syntax is used and the VL of this attribute exceeds 65534 bytes. +
A contour can be one of the following geometric types: +- A Contour Geometric Type (3006,0042) of POINT indicates that the contour is a single point, defining a specific location of significance. +- A Contour Geometric Type (3006,0042) of OPEN_PLANAR indicates that the last vertex shall not be connected to the first point, and that all points in Contour Data (3006,0050) shall be coplanar. +- A Contour Geometric Type (3006,0042) of OPEN_NONPLANAR indicates that the last vertex shall not be connected to the first point, and that the points in Contour Data (3006,0050) may be non-coplanar. Contours having a Geometric Type (3006,0042) of OPEN_NONPLANAR can be used to represent objects best described by a single, possibly non-coplanar curve, such as a brachytherapy applicator. +- A Contour Geometric Type (3006,0042) of CLOSED_PLANAR indicates that the last point shall be connected to the first point, where the first point is not repeated in the Contour Data (3006,0050). All points in Contour Data (3006,0050) shall be coplanar. +
+
+
+ + + Introduces sequence of items specifying dose levels for isodose curves or dose points described in the ROI module. One or more items may be included in this sequence. See C.8.8.7.1. +
ROIs referenced in the RT Dose ROI Module shall have a Contour Geometric Type (3006,0042) of POINT, OPEN_PLANAR or CLOSED_PLANAR. +
+
+ + Uniquely identifies the referenced ROI within the current RT Dose. See Note 1 and C.8.8.7.2. + + + Units used for ROI Dose. +Enumerated Values: +GY = Gray +RELATIVE = dose relative to implicit reference value + + + Dose value for ROI, in units defined by Dose Units (3004,0002). See C.8.8.7.3. +
Dose Value (3004,0012) shall be the dose value corresponding to the referenced isodose curve, named dose point, or unnamed dose point. +
+
+
+ + + Introduces sequence of observations related to ROIs defined in the ROI Module. One or more items may be included in this sequence. + + + Identification number of the Observation. The value of Observation Number (3006,0082) shall be unique within the RT ROI Observations Sequence (3006,0080). + + + Uniquely identifies the referenced ROI described in the Structure Set ROI Sequence (3006,0020). + + + User-defined label for ROI Observation. + + + User-defined description for ROI Observation. + + + Introduces sequence of significantly related ROIs, e.g. CTVs contained within a PTV. One or more items may be included in this sequence. + + + Uniquely identifies the related ROI described in the Structure Set ROI Sequence (3006,0020). + + + Relationship of referenced ROI with respect to referencing ROI. +Defined Terms: +SAME = ROIs represent the same entity +ENCLOSED = referenced ROI completely encloses referencing ROI +ENCLOSING = referencing ROI completely encloses referenced ROI + + + Introduces sequence containing Code used to identify ROI. If this sequence is included, only one item shall be present. Baseline Context ID Number = 96. See Section 5.3 for further explanation. + + + + Introduces sequence of related ROI Observations. One or more items may be included in this sequence. + + + Uniquely identifies a related ROI Observation. + + + Type of ROI. See C.8.8.8.1. +Defined Terms: +EXTERNAL = external patient contour +PTV = Planning Target Volume (as defined in ICRU50) +CTV = Clinical Target Volume (as defined in ICRU50) +GTV = Gross Tumor Volume (as defined in ICRU50) +TREATED_VOLUME = Treated Volume (as defined in ICRU50) +IRRAD_VOLUME = Irradiated Volume (as defined in ICRU50) +BOLUS = patient bolus to be used for external beam therapy +AVOIDANCE = region in which dose is to be minimized +ORGAN = patient organ +MARKER = patient marker or marker on a localizer +REGISTRATION = registration ROI +ISOCENTER = treatment isocenter to be used for external beam therapy +CONTRAST_AGENT = volume into which a contrast agent has been injected +CAVITY = patient anatomical cavity +BRACHY_CHANNEL = brachytherapy channel +BRACHY_ACCESSORY = brachytherapy accessory device +BRACHY_SRC_APP = brachytherapy source applicator +BRACHY_CHNL_SHLD = brachytherapy channel shield +SUPPORT = external patient support device +FIXATION = external patient fixation or immobilisation device +DOSE_REGION = ROI to be used as a dose reference +CONTROL = ROI to be used in control of dose optimization and calculation +
RT ROI Interpreted Type (3006,00A4) shall describe the class of ROI (e.g. CTV, PTV). Individual instances of each class of structure (e.g. CTV1, CTV2) can be distinguished using ROI Observation Label (3006,0085). +
+
+ + Name of person performing the interpretation. + + + User-supplied identifier for ROI material. + + + Introduces sequence describing physical properties associated with current ROI interpretation. One or more items may be included in this sequence. + + + Physical property specified by ROI Physical Property Value (3006,00B4). +Defined Terms: +REL_MASS_DENSITY = mass density relative to water +REL_ELEC_DENSITY = electron density relative to water +EFFECTIVE_Z = effective atomic number +EFF_Z_PER_A = ratio of effective atomic number to mass (AMU-1) +REL_STOP_RATIO = linear stopping power ratio relative to water +ELEM_FRACTION = elemental composition of the material + + + The elemental composition of the ROI and the atomic mass fraction of the elements in the ROI. +Required if ROI Physical Property (3006,00B2) equals ELEM_FRACTION. +One or more items may be included in this sequence. + + + The atomic number of the element for which the ROI Elemental Composition Sequence (3006,00B6) is sent. + + + The fractional weight of the element for which the ROI Elemental Composition Sequence (3006,00B6) is sent. +The sum of all ROI Elemental Composition Atomic Mass Fractions (3006,00B8) sent in the ROI Elemental Composition Sequence (3006,00B6) shall equal 1.0 within acceptable limits of floating point precision. + + + User-assigned value for physical property. + +
+ + + User-defined label for treatment plan. + + + User-defined name for treatment plan. + + + User-defined description of treatment plan. + + + A number that identifies this object instance. + + + Name of operator(s) creating treatment plan. + + + Date treatment plan was last modified. + + + Time treatment plan was last modified. + + + Planned treatment protocols. + + + Intent of this plan. +Defined Terms: +CURATIVE = curative therapy on patient +PALLIATIVE = palliative therapy on patient +PROPHYLACTIC = preventative therapy on patient +VERIFICATION = verification of patient plan using phantom +MACHINE_QA= Quality assurance of the delivery machine (independently of a specific patient) +RESEARCH = Research project +SERVICE = Machine repair or maintenance operation + + + Planned treatment sites. + + + Describes whether RT Plan is based on patient or treatment device geometry. See C.8.8.9.1. +Defined Terms: +PATIENT = RT Structure Set exists +TREATMENT_DEVICE = RT Structure Set does not exist +
An RT Plan Geometry (300A,000C) of PATIENT shall signify that an RT Structure Set has been defined upon which the plan geometry is based, and this RT Structure Set shall be specified in the Referenced Structure Set Sequence (300C,0060). An RT Plan Geometry (300A,000C) of TREATMENT_DEVICE shall indicate that no patient geometry is available, and that the RT Plan is being defined with respect to the IEC FIXED Coordinate System. +
+
+ + Introduces sequence of one Class/Instance pair describing instance of RT Structure Set on which the RT Plan is based. Only a single item shall be permitted in this sequence. Required if RT Plan Geometry (300A,000C) is PATIENT. + + + + Introduces sequence of related SOP Class/Instance pairs describing related instances of RT Dose (for grids and named/unnamed point doses). One or more items may be included in this sequence. See Note 1. + + + + Introduces sequence of related SOP Class/Instance pairs describing related instances of RT Plan. One or more items may be included in this sequence. + + + + Relationship of referenced plan with respect to current plan. +Defined Terms: +PRIOR = plan delivered prior to current treatment +ALTERNATIVE = alternative plan prepared for current treatment +PREDECESSOR = plan used in derivation of current plan +VERIFIED_PLAN = plan which is verified using the current plan. This value shall only be used if Plan Intent (300A,000A) is present and has a value of VERIFICATION. + +
+ + + User-defined description of treatment prescription. + + + Introduces sequence of Dose References. One or more items may be included in this sequence. + + + Identification number of the Dose Reference. The value of Dose Reference Number (300A,0012) shall be unique within the RT Plan in which it is created. + + + A unique identifier for a Dose Reference that can be used to link the same entity across multiple RT Plan objects. + + + Structure type of Dose Reference. +Defined Terms: +POINT = dose reference point specified as ROI +VOLUME = dose reference volume specified as ROI +COORDINATES = point specified by Dose Reference Point Coordinates (300A,0018) +SITE = dose reference clinical site + + + User-defined description of Dose Reference. + + + Uniquely identifies ROI representing the dose reference specified by ROI Number (3006,0022) in Structure Set ROI Sequence (3006,0020) in Structure Set Module within RT Structure Set in Referenced Structure Set Sequence (300C,0060) in RT General Plan Module. Required if Dose Reference Structure Type (300A,0014) is POINT or VOLUME. + + + Coordinates (x,y,z) of Reference Point in the patient based coordinate system described in C.7.6.2.1.1 (mm). Required if Dose Reference Structure Type (300A,0014) is COORDINATES. + + + Dose (in Gy) from prior treatment to this Dose Reference (e.g. from a previous course of treatment). + + + Type of Dose Reference. +Defined Terms: +TARGET = treatment target (corresponding to GTV, PTV, or CTV in ICRU50) +ORGAN_AT_RISK = Organ at Risk (as defined in ICRU50) + + + Relative importance of satisfying constraint, where high values represent more important constraints. + + + The dose (in Gy) which when reached or exceeded should cause some action to be taken. + + + The maximum dose (in Gy) which can be delivered to the dose reference. + + + Minimum permitted dose (in Gy) to Dose Reference if Dose Reference Type (300A,0020) is TARGET. + + + Prescribed dose (in Gy) to Dose Reference if Dose Reference Type (300A,0020) is TARGET. + + + Maximum permitted dose (in Gy) to Dose Reference if Dose Reference Type (300A,0020) is TARGET. + + + Maximum permitted fraction (in percent) of Target to receive less than the Target Prescription Dose if Dose Reference Type (300A,0020) is TARGET and Dose Reference Structure Type (300A,0014) is VOLUME. See C.8.8.10.1. +
If the Target Underdose Volume Fraction (300A,0028) is not present, it shall be interpreted as zero. +
+
+ + Maximum dose (in Gy) to entire Dose Reference if Dose Reference Type (300A,0020) is ORGAN_AT_RISK and Dose Reference Structure Type (300A,0014) is VOLUME. + + + Maximum permitted dose (in Gy) to any part of Dose Reference if Dose Reference Type (300A,0020) is ORGAN_AT_RISK and Dose Reference Structure Type (300A,0014) is VOLUME. + + + Maximum dose (in Gy) to non-overdosed part of Dose Reference if Dose Reference Type (300A,0020) is ORGAN_AT_RISK and Dose Reference Structure Type (300A,0014) is VOLUME. + + + Maximum permitted fraction (in percent) of the Organ at Risk to receive more than the Organ at Risk Maximum Dose if Dose Reference Type (300A,0020) is ORGAN_AT_RISK and Dose Reference Structure Type (300A,0014) is VOLUME. + +
+ + + Introduces sequence of tolerance tables to be used for delivery of treatment plan. One or more items may be included in this sequence. See Note 1. + + + Identification number of the Tolerance Table. The value of Tolerance Table Number (300A,0042) shall be unique within the RT Plan in which it is created. Required if Tolerance Table Sequence (300A,0040) is sent. + + + User-defined label for Tolerance Table. + + + Maximum permitted difference (in degrees) between planned and delivered Gantry Angle. + + + Maximum permitted difference (in degrees) between planned and delivered Gantry Pitch Angle. + + + Maximum permitted difference (in degrees) between planned and delivered Beam Limiting Device Angle. + + + Introduces sequence of beam limiting device (collimator) tolerances. One or more items may be included in this sequence. + + + Type of beam limiting device (collimator). Required if Beam Limiting Device Tolerance Sequence (300A,0048) is sent. +Enumerated Values: +X = symmetric jaw pair in IEC X direction +Y = symmetric jaw pair in IEC Y direction +ASYMX = asymmetric jaw pair in IEC X direction +ASYMY = asymmetric pair in IEC Y direction +MLCX = multileaf (multi-element) jaw pair in IEC X direction +MLCY = multileaf (multi-element) jaw pair in IEC Y direction + + + Maximum permitted difference (in mm) between planned and delivered leaf (element) or jaw positions for current beam limiting device (collimator). Required if Beam Limiting Device Tolerance Sequence (300A,0048) is sent. + + + Maximum permitted difference (in degrees) between planned and delivered Patient Support Angle. + + + Maximum permitted difference (in degrees) between planned and delivered Table Top Eccentric Angle. + + + Maximum permitted difference (in degrees) between the planned and delivered Table Top Pitch Angle. + + + Maximum permitted difference (in degrees) between the planned and delivered Table Top Roll Angle. + + + Maximum permitted difference (in mm) between planned and delivered Table Top Vertical Position. + + + Maximum permitted difference (in mm) between planned and delivered Table Top Longitudinal Position. + + + Maximum permitted difference (in mm) between planned and delivered Table Top Lateral Position. + + + + + Introduces sequence of patient setup data for current plan. One or more items may be included in this sequence. + + + Identification number of the Patient Setup. The value of Patient Setup Number (300A,0182) shall be unique within the RT Plan in which it is created. + + + The user-defined label for the patient setup. + + + Patient position descriptor relative to the equipment. Required if Patient Additional Position (300A,0184) is not present. See Section C.8.8.12.1.2 for Defined Terms and further explanation. +
Defined Terms for Patient Position shall be those specified in Section C.7.3.1.1.2, plus the following: + SITTING +In the sitting position, the patient’s face is towards the front of the chair. +
+
+ + User-defined additional description of patient position. Required if Patient Position (0018,5100) is not present. + + + Introduces sequence of setup verification images for this patient setup. One or more items may be included in this sequence. See C.8.8.12.1.1 +
Images with modality SC or VL serve as visible light photos for visual setup control. Images with modality RTIMAGE serve as reference images on plan level. RT Images present in this sequence shall not be referenced in the Referenced Reference Image Sequence (300C,0042) of the RT Beams module. +
+
+ + Comment on the Setup Image. + + + + Introduces sequence of Fixation Devices used in Patient Setup. One or more items may be included in this sequence. + + + Type of Fixation Device used during in Patient Setup. Required if Fixation Device Sequence (300A,0190) is sent. +Defined Terms: +BITEBLOCK +HEADFRAME +MASK +MOLD +CAST +HEADREST +BREAST_BOARD +BODY_FRAME +VACUUM_MOLD +WHOLE_BODY_POD +RECTAL_BALLOON + + + User-defined label identifier for Fixation Device. Required if Fixation Device Sequence (300A,0190) is sent. + + + User-defined description of Fixation Device. + + + Position/Notch number of Fixation Device. + + + The Fixation Device Pitch Angle, i.e. orientation of PITCHED FIXATION DEVICE coordinate system with respect to IEC PATIENT SUPPORT coordinate system (degrees). Pitching is the rotation around IEC PATIENT SUPPORT X-axis. + + + The Fixation Device Roll Angle, i.e. orientation of ROLLED FIXATION DEVICE coordinate system with respect to IEC PITCHED FIXATION DEVICE coordinate system (degrees). Rolling is the rotation around IEC PATIENT SUPPORT Y-axis. + + + An identifier for the accessory intended to be read by a device such as a bar-code reader. + + + Introduces sequence of Shielding Devices used in Patient Setup. One or more items may be included in this sequence. + + + Type of Shielding Device used in Patient Setup. Required if Shielding Device Sequence (300A,01A0) is sent. +Defined Terms: +GUM +EYE +GONAD + + + User-defined label for Shielding Device. Required if Shielding Device Sequence (300A,01A0) is sent. + + + User-defined description of Shielding Device. + + + Position/Notch number of Shielding Device. + + + An identifier for the accessory intended to be read by a device such as a bar-code reader. + + + Setup Technique used in Patient Setup. +Defined Terms: +ISOCENTRIC +FIXED_SSD +TBI +BREAST_BRIDGE +SKIN_APPOSITION + + + User-defined description of Setup Technique. + + + Introduces sequence of devices used for patient alignment in Patient Setup. One or more items may be included in this sequence. + + + Type of Setup Device used for Patient alignment. Required if Setup Device Sequence (300A,01B4) is sent. +Defined Terms: +LASER_POINTER +DISTANCE_METER +TABLE_HEIGHT +MECHANICAL_PTR +ARC + + + User-defined label for Setup Device used for patient alignment. Required if Setup Device Sequence (300A,01B4) is sent. + + + User-defined description for Setup Device used for patient alignment. + + + Setup Parameter for Setup Device in appropriate IEC 61217 coordinate system. +Units shall be mm for distances and degrees for angles. Required if Setup Device Sequence (300A,011B4) is sent. + + + User-defined description of Setup Reference used for patient alignment. + + + Vertical Displacement in IEC TABLE TOP coordinate system (in mm) relative to initial Setup Position, i.e. vertical offset between patient positioning performed using setup and treatment position. + + + Longitudinal Displacement in IEC TABLE TOP coordinate system (in mm) relative to initial Setup Position, i.e. longitudinal offset between patient positioning performed using setup and treatment position. + + + Lateral Displacement in IEC TABLE TOP coordinate system (in mm) relative to initial Setup Position, i.e. lateral offset between patient positioning performed using setup and treatment position. + + + Introduces sequence of Motion Synchronization. One or more items may be included in this sequence. + + + Technique applied to reduce respiratory motion artifacts. +Defined Terms: +NONE +BREATH_HOLD +REALTIME = image acquisition shorter than respiratory cycle +GATING = Prospective gating +TRACKING = prospective through-plane or in-plane motion tracking +PHASE_ORDERING = prospective phase ordering +PHASE_RESCANNING = prospective techniques, such as real-time averaging, diminishing variance and motion adaptive gating +RETROSPECTIVE = retrospective gating +CORRECTION = retrospective image correction +UNKNOWN = technique not known + + + Signal source from which respiratory motion is derived. +Defined Terms: +NONE +BELT +NASAL_PROBE +CO2_SENSOR +NAVIGATOR = MR navigator and organ edge detection +MR_PHASE = phase (of center k-space line) +ECG = baseline demodulation of the ECG +SPIROMETER = Signal derived from flow sensor +EXTERNAL_MARKER = Signal determined from external motion surrogate +INTERNAL_MARKER = Signal determined from internal motion surrogate +IMAGE = Signal derived from an image +UNKNOWN = Signal source not known + + + Description of respiratory motion compensation technique. + + + Identifies the device providing the respiratory signal. + +
+ + + Introduces sequence of Fraction Groups in current Fraction Scheme. One or more items may be included in this sequence. + + + Identification number of the Fraction Group. The value of Fraction Group Number (300A,0071) shall be unique within the RT Plan in which it is created. + + + The user defined description for the fraction group. + + + Introduces sequence of related SOP Class/Instance pairs describing related instances of RT Dose (for grids, isodose curves and named/unnamed point doses). One or more items may be included in this sequence. See Note 1. + + + + Introduces sequence of Dose References for the current Fraction Group. One or more items may be included in this sequence. + + + Uniquely identifies Dose Reference specified by Dose Reference Number (300A,0012) within Dose Reference Sequence (300A,0010) in RT Prescription Module. Required if Referenced Dose Reference Sequence (300C,0050) is sent. + + + Relative importance of satisfying constraint, where high values represent more important constraints. + + + The dose (in Gy) which when reached or exceeded should cause some action to be taken. + + + The maximum dose (in Gy) which can be delivered to the dose reference. + + + Minimum permitted dose (in Gy) to Dose Reference if Dose Reference Type (300A,0020) of referenced Dose Reference is TARGET. + + + Prescribed dose (in Gy) to Dose Reference if Dose Reference Type (300A,0020) of referenced Dose Reference is TARGET. + + + Maximum permitted dose (in Gy) to Dose Reference if Dose Reference Type (300A,0020) of referenced Dose Reference is TARGET. + + + Maximum permitted fraction (in percent) of Target to receive less than the Target Prescription Dose (300A,0027) if Dose Reference Type (300A,0020) of referenced Dose Reference is TARGET and Dose Reference Structure Type (300A,0014) of referenced Dose Reference is VOLUME. + + + Maximum dose (in Gy) to entire Dose Reference if Dose Reference Type (300A,0020) of referenced Dose Reference is ORGAN_AT_RISK and Dose Reference Structure Type (300A,0014) of referenced Dose Reference is VOLUME. + + + Maximum permitted dose (in Gy) to any part of Dose Reference if Dose Reference Type (300A,0020) of referenced Dose Reference is ORGAN_AT_RISK and Dose Reference Structure Type (300A,0014) of referenced Dose Reference is VOLUME. + + + Maximum dose (in Gy) to non-overdosed part of Dose Reference if Dose Reference Type (300A,0020) of referenced Dose Reference is ORGAN_AT_RISK and Dose Reference Structure Type (300A,0014) of referenced Dose Reference is VOLUME. + + + Maximum permitted fraction (in percent) of Organ at Risk to receive more than the Organ at Risk Maximum Dose if Dose Reference Type (300A,0020) of referenced Dose Reference is ORGAN_AT_RISK and Dose Reference Structure Type (300A,0014) of referenced Dose Reference is VOLUME. + + + Total number of treatments (Fractions) prescribed for current Fraction Group. + + + Number of digits in Fraction Pattern (300A,007B) used to represent one day. See Note 2. + + + Number of weeks needed to describe treatment pattern. See Note 2. + + + String of 0's (no treatment) and 1's (treatment) describing treatment pattern. Length of string is 7 x Number of Fraction Pattern Digits Per Day x Repeat Fraction Cycle Length. Pattern shall start on a Monday. See Note 2. + + + Number of Beams in current Fraction Group. If Number of Beams is greater then zero, Number of Brachy Application Setups (300A,00A0) shall equal zero. + + + Introduces sequence of treatment beams in current Fraction Group. Required if Number of Beams (300A,0080) is greater than zero. One or more items may be included in this sequence. + + + Uniquely identifies Beam specified by Beam Number (300A,00C0) within Beam Sequence (300A,00B0) in RT Beams Module. Required if Referenced Beam Sequence (300C,0004) is sent. + + + Coordinates (x,y,z) of point at which Beam Dose is specified in the patient based coordinate system described in C.7.6.2.1.1 (mm). See Note 3. + + + Dose (in Gy) at Beam Dose Specification Point (300A,0082) due to current Beam. + + + The depth (in mm) in the patient along a ray from the source to the dose point specified by the Beam Dose Specification Point (300A,0082). + + + The radiological depth in mm (water-equivalent depth, taking tissue heterogeneity into account) in the patient along a ray from the source to the dose point specified by the Beam Dose Specification Point (300A,0082). + + + Source to patient surface distance along a ray from the source to the dose point specified by the Beam Dose Specification Point (300A,0082). + + + Machine setting to be delivered for current Beam, specified in Monitor Units (MU) or minutes as defined by Primary Dosimeter Unit (300A,00B3) (in RT Beams Module) for referenced Beam. See Note 4. + + + Number of Brachy Application Setups in current Fraction Group. If Number of Brachy Application Setups is greater then zero, Number of Beams (300A,0080) shall equal zero. + + + Introduces sequence of treatment Brachy Application Setups in current Fraction Group. Required if Number of Brachy Application Setups (300A,00A0) is greater than zero. One or more items may be included in this sequence. + + + Uniquely identifies Brachy Application Setup specified by Brachy Application Setup Number (300A,0234) within Brachy Application Setup Sequence (300A,0230) in RT Brachy Application Setups Module. Required if Referenced Brachy Application Setup Sequence (300C,000A) is sent. + + + Coordinates (x,y,z) of point in the patient based coordinate system described in C.7.6.2.1.1 at which Brachy Application Setup Dose (300A,00A4) is specified (mm). + + + Dose (in Gy) at Brachy Application Setup Dose Specification Point (300A,00A2) due to current Brachy Application Setup. + + + + + Introduces sequence of treatment beams for current RT Plan. One or more items may be included in this sequence. + + + Identification number of the Beam. The value of Beam Number (300A,00C0) shall be unique within the RT Plan in which it is created. See Note 1. + + + User-defined name for Beam. See Note 1. + + + User-defined description for Beam. See Note 1. + + + Motion characteristic of Beam. See Note 5. +Enumerated Values: +STATIC = All Control Point Sequence (300A,0111) attributes remain unchanged between consecutive pairs of control points with changing Cumulative Meterset Weight (300A,0134). +DYNAMIC = One or more Control Point Sequence (300A,0111) attributes change between one or more consecutive pairs of control points with changing Cumulative Meterset Weight (300A,0134). + + + Particle type of Beam. +Defined Terms: +PHOTON +ELECTRON +NEUTRON +PROTON + + + Type of high-dose treatment technique. +Defined Terms: +NORMAL = Standard treatment +TBI = Total Body Irradiation +HDR = High Dose Rate +Required if treatment technique requires a dose that would normally require overriding of treatment machine safety controls. + + + User-defined name identifying treatment machine to be used for beam delivery. See Note 2. + + + Manufacturer of the equipment to be used for beam delivery. + + + Institution where the equipment is located that is to be used for beam delivery. + + + Mailing address of the institution where the equipment is located that is to be used for beam delivery. + + + Department in the institution where the equipment is located that is to be used for beam delivery. + + + Manufacturer's model name of the equipment that is to be used for beam delivery. + + + Manufacturer's serial number of the equipment that is to be used for beam delivery. + + + Measurement unit of machine dosimeter. +See C.8.8.14.1. +Enumerated Values: +MU = Monitor Unit +MINUTE = minute +
The Meterset at a given Control Point is equal to the Beam Meterset (300A,0086) specified in the Referenced Beam Sequence (300C,0004) of the RT Fraction Scheme Module, multiplied by the Cumulative Meterset Weight (300A,0134) for the Control Point, divided by the Final Cumulative Meterset Weight (300A,010E). The Meterset is specified in units defined by Primary Dosimeter Unit (300A,00B3). If the calculation for Meterset results in a meterset value which is not an exact multiple of the primary meterset resolution, then the result shall be rounded to the nearest allowed meterset value (i.e. less than a half resolution unit shall be rounded down to the nearest resolution unit, and equal or greater than half a resolution unit shall be rounded up to the nearest resolution unit). +Note also that if Final Cumulative Meterset Weight (300A,010E) is equal to 100, then Cumulative Meterset Weight (300A,0134) becomes equivalent to the percentage of Beam Meterset (300A,0086) delivered at each control point. If Final Cumulative Meterset Weight (300A,010E) is equal to Beam Meterset (300A,0086), then the Cumulative Meterset Weight (300A,0134) at each control point becomes equal to the cumulative Meterset delivered at that control point. +
+
+ + Uniquely identifies Tolerance Table specified by Tolerance Table Number (300A,0042) within Tolerance Table Sequence in RT Tolerance Tables Module. These tolerances are to be used for verification of treatment machine settings. + + + Radiation source to Gantry rotation axis distance of the equipment that is to be used for beam delivery (mm). + + + Introduces sequence of beam limiting device (collimator) jaw or leaf (element) sets. One or more items may be included in this sequence. + + + Type of beam limiting device (collimator). +Enumerated Values: +X = symmetric jaw pair in IEC X direction +Y = symmetric jaw pair in IEC Y direction +ASYMX = asymmetric jaw pair in IEC X direction +ASYMY = asymmetric pair in IEC Y direction +MLCX = multileaf (multi-element) jaw pair in IEC X direction +MLCY = multileaf (multi-element) jaw pair in IEC Y direction + + + Radiation source to beam limiting device (collimator) distance of the equipment that is to be used for beam delivery (mm). + + + Number of leaf (element) or jaw pairs (equal to 1 for standard beam limiting device jaws). + + + Boundaries of beam limiting device (collimator) leaves (in mm) in IEC BEAM LIMITING DEVICE coordinate axis appropriate to RT Beam Limiting Device Type (300A,00B8), i.e. X-axis for MLCY, Y-axis for MLCX. Contains N+1 values, where N is the Number of Leaf/Jaw Pairs (300A,00BC), starting from Leaf (Element) Pair 1. Required if Beam Limiting Device Sequence (300A,00B6) is sent and RT Beam Limiting Device Type (300A,00B8) is MLCX or MLCY. See Note 3. + + + Uniquely identifies Patient Setup to be used for current beam, specified by Patient Setup Number (300A,0182) within Patient Setup Sequence of RT Patient Setup Module. + + + Introduces sequence of reference images used for validation of current beam. One or more items may be included in this sequence. + + + + Uniquely identifies Reference Image within Referenced Reference Image Sequence (300A,0042). Required if Referenced Reference Image Sequence (300A,0042) is sent. + + + Cumulative Meterset Weight within current Beam at which image acquisition starts. + + + Cumulative Meterset Weight within current Beam at which image acquisition ends. + + + Introduces sequence of planned verification images to be acquired during current beam. One or more items may be included in this sequence. See C.8.8.14.2. +
The Planned Verification Image Sequence (300A,00CA) contains attributes which describe the planned verification images to be acquired during current beam. The Start Cumulative Meterset Weight (300C,0008) specifies the Cumulative Meterset Weight at which image acquisition is to begin. If Meterset Exposure (3002,0032) is present in a sequence item and End Cumulative Meterset Weight (300C,0009) is not present then a single image shall be acquired using the meterset duration specified in Meterset Exposure (3002,0032). If End Cumulative Meterset Weight (300C,0009) is present in a sequence item and Meterset Exposure (3002,0032) is not present then a single image shall be acquired over the beam delivery from Start Cumulative Meterset Weight (300C,0008) to End Cumulative Meterset Weight (300C,0009). If both Meterset Exposure (3002,0032) and End Cumulative Meterset Weight (300C,0009) are present in a sequence item then images shall be acquired every Meterset Exposure (3002,0032) from Start Cumulative Meterset Weight (300C,0008) to End Cumulative Meterset Weight (300C,0009). No images shall extend past End Cumulative Meterset Weight (300C,0009). +
+
+ + Cumulative Meterset Weight within current Beam at which image acquisition will start. + + + Meterset duration over which image is to be acquired, specified in Monitor units (MU) or minutes as defined by Primary Dosimeter Unit (300A,00B3). + + + Cumulative Meterset Weight within current Beam at which image acquisition will end. + + + Describes whether or not image plane is normal to beam axis. +Enumerated Values: +NORMAL = image plane normal to beam axis +NON_NORMAL = image plane non-normal to beam axis + + + X-Ray Image Receptor Angle i.e. orientation of IEC X-RAY IMAGE RECEPTOR coordinate system with respect to IEC GANTRY coordinate system (degrees). See C.8.8.14.3. +
The X-Ray Image Receptor Angle (3002,000E) specifies the rotation of the image receptor device in the IEC X-RAY IMAGE RECEPTOR PLANE. A positive angle corresponds to a counter-clockwise rotation of the X-Ray Image Receptor as viewed from the radiation source in the IEC GANTRY coordinate system. The normal (non-rotated) value for this parameter is zero degrees. +
+
+ + The direction cosines of the first row and the first column with respect to the IEC X-RAY IMAGE RECEPTOR coordinate system. + + + The x and y coordinates (in mm) of the upper left hand corner of the image, in the IEC X-RAY IMAGE RECEPTOR coordinate system. This is the center of the first pixel transmitted. + + + Radiation machine source to image plane distance (mm). + + + User-specified device-specific parameters that describe how the imager will acquire the image. + + + Uniquely identifies Reference Image to which planned verification image is related, specified by Reference Image Number (300A,00C8) within Referenced Reference Image Sequence (300A,0042). + + + Delivery Type of treatment. +Defined Terms: +TREATMENT = normal patient treatment +OPEN_PORTFILM = portal image acquisition with open field +TRMT_PORTFILM = portal image acquisition with treatment port +CONTINUATION = continuation of interrupted treatment +SETUP = no treatment beam is applied for this RT Beam. To be used for specifying the gantry, couch, and other machine positions where X-Ray set-up images or measurements are to be taken + + + Introduces sequence of related SOP Class/Instance pairs describing related instances of RT Dose (for grids, isodose curves, and named/unnamed point doses). One or more items may be included in this sequence. + + + + Number of wedges associated with current Beam. + + + Introduces sequence of treatment wedges. Required if Number of Wedges (300A,00D0) is non-zero. One or more items may be included in this sequence. + + + Identification number of the Wedge. The value of Wedge Number (300A,00D2) shall be unique within the Beam in which it is created. Required if Wedge Sequence (300A,00D1) is sent. + + + Type of wedge (if any) defined for Beam. Required if Wedge Sequence (300A,00D1) is sent. +Defined Terms: +STANDARD = standard (static) wedge +DYNAMIC = moving beam limiting device (collimator) jaw simulating wedge +MOTORIZED = single wedge which can be removed from beam remotely + + + User-supplied identifier for Wedge. + + + An identifier for the accessory intended to be read by a device such as a bar-code reader. + + + Nominal wedge angle (degrees). Required if Wedge Sequence (300A,00D1) is sent. + + + Nominal wedge factor under machine calibration conditions at the beam energy specified by the Nominal Beam Energy (300A,0114) of the first Control Point of the Control Point Sequence (300A,0111). Required if Wedge Sequence (300A,00D1) is sent. + + + Orientation of wedge, i.e. orientation of IEC WEDGE FILTER coordinate system with respect to IEC BEAM LIMITING DEVICE coordinate system (degrees). Required if Wedge Sequence (300A,00D1) is sent. + + + Radiation source to wedge tray attachment edge distance (in mm) for current wedge. + + + Number of compensators associated with current Beam. + + + Compensator Tray transmission factor (between 0 and 1), at the beam energy specified by the Nominal Beam Energy (300A,0114) of the first Control Point of the Control Point Sequence (300A,0111). + + + Introduces sequence of treatment compensators. Required if Number of Compensators (300A,00E0) is non-zero. One or more items may be included in this sequence. + + + User defined description for the compensator. + + + Identification number of the Compensator. The value of Compensator Number (300A,00E4) shall be unique within the Beam in which it is created. Required if Number of Compensators (300A,00E0) is non-zero. + + + Type of compensator (if any). Defined Terms: +STANDARD = physical (static) compensator +DYNAMIC = moving Beam Limiting Device (collimator) simulating physical compensator + + + User-supplied identifier for material used to manufacture Compensator. Required if Number of Compensators (300A,00E0) is non-zero. + + + User-supplied identifier for compensator. + + + An identifier for the accessory intended to be read by a device such as a bar-code reader. + + + Radiation source to compensator tray attachment edge distance (in mm) for current compensator. Required if Compensator Sequence (300A,00E3) is sent. + + + Indicates presence or absence of geometrical divergence of the compensator. +Enumerated Values: +PRESENT = the compensator is shaped according to the beam geometrical divergence. +ABSENT = the compensator is not shaped according to the beam geometrical divergence. + + + Indicates on which side of the Compensator Tray the compensator is mounted. +Enumerated Values: +PATIENT_SIDE = the compensator is mounted on the side of the Compensator Tray which is towards the patient. +SOURCE_SIDE = the compensator is mounted on the side of the Compensator Tray which is towards the radiation source. +DOUBLE_SIDED = the compensator has a shaped (i.e. non-flat) surface on both sides of the Compensator Tray. + + + Number of rows in the compensator. A row is defined to be in the X direction of the IEC Beam Limiting Device Coordinate system. + + + Number of columns in the compensator. A column is defined to be in the Y direction of the IEC Beam Limiting Device Coordinate system. + + + Physical distance (in mm) between the center of each pixel projected onto machine isocentric plane. Specified by a numeric pair - adjacent row spacing (delimiter) adjacent column spacing. See 10.7.1.3 for further explanation of the value order. Required if Compensator Sequence (300A,00E3) is sent. + + + The x and y coordinates of the upper left hand corner (first pixel transmitted) of the compensator, projected onto the machine isocentric plane in the IEC BEAM LIMITING DEVICE coordinate system (mm). Required if Compensator Sequence (300A,00E3) is sent. + + + A data stream of the pixel samples which comprise the compensator, expressed as broad-beam transmission values (between 0 and 1) along a ray line passing through the pixel, at the beam energy specified by the Nominal Beam Energy (300A,0114) of the first Control Point of the Control Point Sequence (300A,0111). The order of pixels sent is left to right, top to bottom, i.e., the upper left pixel is sent first followed by the remainder of the first row , followed by the first pixel of the 2nd row, then the remainder of the 2nd row and so on) when viewed from the radiation source. Required if Material ID (300A,00E1) is zero-length. May be present if Material ID (300A,00E1) is non-zero length. See C.8.8.14.10 and C.8.8.14.11. +Note: Compensator Transmission Data may not be properly encoded if Explicit-VR transfer syntax is used and the VL of this attribute exceeds 65534 bytes. +
The direction of the rows and columns in Compensator Transmission Data (300A,00EB) and Compensator Thickness Data (300A,00EC) is defined as follows: The direction of rows goes along the positive Xb direction and the direction of the columns does along the negative Yb direction of the IEC X-BEAM LIMITING DEVICE coordinate system. Other interpretations shall be documented in an implementation's conformance statement. +
+
+ + A data stream of the pixel samples which comprise the compensator, expressed as thicknesses (in mm). The order of pixels sent is left to right, top to bottom, i.e., the upper left pixel is sent first followed by the remainder of the first row , followed by the first pixel of the 2nd row, then the remainder of the 2nd row and so on) when viewed from the radiation source. Required if Material ID (300A,00E1) is non-zero length. May be present if Material ID (300A,00E1) is zero length. See C.8.8.14.9 and C.8.8.14.10 and C.8.8.14.11. +Note: Compensator Thickness Data may not be properly encoded if Explicit-VR transfer syntax is used and the VL of this attribute exceeds 65534 bytes. +
The values stored in Compensator Thickness Data (300A,00EC) and Source to Compensator Distance (300A,02E2) shall be parallel to the radiation beam axis if Compensator Divergence (300A,02E0) equals ABSENT, or divergent according to the beam geometrical divergence if Compensator Divergence (300A,02E0) equals PRESENT. If Compensator Divergence (300A,02E0) is not sent, then the parallel or divergent nature of the thicknesses is as if ABSENT was specified for Compensator Divergence (300A,02E0). +
+
+ + A data stream of the pixel samples which comprise the distance from the radiation source to the compensator surface closest to the radiation source (in mm). The order of pixels sent is left to right, top to bottom (upper left pixel, followed by the remainder of row 1, followed by the remainder of the columns). Required if Material ID (300A,00E1) is non-zero length, and Compensator Mounting Position (300A,02E1) is DOUBLE_SIDED. May be present if Material ID (300A,00E1) is zero length and Compensator Mounting Position (300A,02E1) is DOUBLE_SIDED. See C.8.8.14.9 and C.8.8.14.11. +
The values stored in Compensator Thickness Data (300A,00EC) and Source to Compensator Distance (300A,02E2) shall be parallel to the radiation beam axis if Compensator Divergence (300A,02E0) equals ABSENT, or divergent according to the beam geometrical divergence if Compensator Divergence (300A,02E0) equals PRESENT. If Compensator Divergence (300A,02E0) is not sent, then the parallel or divergent nature of the thicknesses is as if ABSENT was specified for Compensator Divergence (300A,02E0). +
+
+ + Number of boli associated with current Beam. + + + Introduces sequence of boli associated with Beam. Required if Number of Boli (300A,00ED) is non-zero. One or more items may be included in this sequence. + + + Uniquely identifies ROI representing the Bolus specified by ROI Number (3006,0022) in Structure Set ROI Sequence (3006,0020) in Structure Set Module within RT Structure Set in Referenced Structure Set Sequence (300C,0060) in RT General Plan Module. Required if Referenced Bolus Sequence (300C,00B0) is sent. + + + User-supplied identifier for the Bolus. + + + User-defined description for the Bolus. + + + An identifier for the accessory intended to be read by a device such as a bar-code reader. + + + Number of shielding blocks associated with Beam. + + + Total block tray transmission for all block trays (between 0 and 1) at the beam energy specified by the Nominal Beam Energy (300A,0114) of the first Control Point of the Control Point Sequence (300A,0111). + + + Introduces sequence of blocks associated with Beam. Required if Number of Blocks (300A,00F0) is non-zero. One or more items may be included in this sequence. + + + User-supplied identifier for block tray. + + + An identifier for the accessory intended to be read by a device such as a bar-code reader. + + + Radiation Source to attachment edge of block tray assembly (mm). Required if Block Sequence (300A,00F4) is sent. + + + Type of block. Required if Block Sequence (300A,00F4) is sent. See C.8.8.14.4. +Enumerated Values: +SHIELDING = blocking material is inside contour +APERTURE = blocking material is outside contour +
All blocks with Block Type (300A,00F8) of APERTURE for a given beam shall have equal values of Block Transmission (300A,0102) and/or Block Thickness (300A,0100) if they are specified. The composite aperture shall be evaluated as the union of the individual apertures within a single Block. Shielding block transmission(s) shall be applied multiplicatively after the (composite) aperture has been evaluated. +
+
+ + Indicates presence or otherwise of geometrical divergence. Required if Block Sequence (300A,00F4) is sent. +Enumerated Values: +PRESENT = block edges are shaped for beam divergence +ABSENT = block edges are not shaped for beam divergence + + + Indicates on which side of the Block Tray the block is mounted. +Enumerated Values: +PATIENT_SIDE = the block is mounted on the side of the Block Tray which is towards the patient. +SOURCE_SIDE = the block is mounted on the side of the Block Tray which is towards the radiation source. + + + Identification number of the Block. The value of Block Number (300A,00FC) shall be unique within the Beam in which it is created. Required if Block Sequence (300A,00F4) is sent. + + + User-defined name for block. + + + User-supplied identifier for material used to manufacture Block. Required if Block Sequence (300A,00F4) is sent. + + + Physical thickness of block (in mm) parallel to radiation beam axis. Required if Material ID (300A,00E1) is non-zero length. May be present if Material ID (300A,00E1) is zero length. See C.8.8.14.4 and C.8.8.14.11. +
All blocks with Block Type (300A,00F8) of APERTURE for a given beam shall have equal values of Block Transmission (300A,0102) and/or Block Thickness (300A,0100) if they are specified. The composite aperture shall be evaluated as the union of the individual apertures within a single Block. Shielding block transmission(s) shall be applied multiplicatively after the (composite) aperture has been evaluated. +
+
+ + Transmission through the block (between 0 and 1) at the beam energy specified by the Nominal Beam Energy (300A,0114) of the first Control Point of the Control Point Sequence (300A,0111). Required if Material ID (300A,00E1) is zero length. May be present if Material ID (300A,00E1) is non-zero length. See C.8.8.14.4 and C.8.8.14.11. +
All blocks with Block Type (300A,00F8) of APERTURE for a given beam shall have equal values of Block Transmission (300A,0102) and/or Block Thickness (300A,0100) if they are specified. The composite aperture shall be evaluated as the union of the individual apertures within a single Block. Shielding block transmission(s) shall be applied multiplicatively after the (composite) aperture has been evaluated. +
+
+ + Number of (x,y) pairs defining the block edge. Required if Block Sequence (300A,00F4) is sent. + + + A data stream of (x,y) pairs which comprise the block edge. The number of pairs shall be equal to Block Number of Points (300A,0104), and the vertices shall be interpreted as a closed polygon. Coordinates are projected onto the machine isocentric plane in the IEC BEAM LIMITING DEVICE coordinate system (mm). Required if Block Sequence (300A,00F4) is sent. See Note 4. + + + Introduces sequence of Applicators associated with Beam. Only a single item shall be permitted in this sequence. + + + User or machine supplied identifier for Applicator. Required if Applicator Sequence (300A,0107) is sent. + + + An identifier for the accessory intended to be read by a device such as a bar-code reader. + + + Type of Applicator. Required if Applicator Sequence (300A,0107) is sent. +Defined Terms: +ELECTRON_SQUARE = square electron applicator +ELECTRON_RECT = rectangular electron applicator +ELECTRON_CIRC = circular electron applicator +ELECTRON_SHORT = short electron applicator +ELECTRON_OPEN = open (dummy) electron applicator +INTRAOPERATIVE = intraoperative (custom) applicator +STEREOTACTIC = stereotactic applicator + + + User-defined description for Applicator. + + + Introduces a Sequence of General Accessories associated with this Beam. One or more items may be included in this sequence. + + + Identification Number of the General Accessory. The value shall be unique within the sequence. + + + User or machine supplied identifier for General Accessory. + + + User supplied description of General Accessory. + + + Specifies the type of accessory. +Defined Terms: +GRATICULE = Accessory tray with a radio-opaque grid +IMAGE_DETECTOR = Image acquisition device positioned in the beam line +RETICLE = Accessory tray with radio-transparent markers or grid + + + Machine-readable identifier for this accessory + + + Value of Cumulative Meterset Weight (300A,0134) for final Control Point in Control Point Sequence (300A,0111). Required if Cumulative Meterset Weight is non-null in Control Points specified within Control Point Sequence (300A,0111). See C.8.8.14.1. +
The Meterset at a given Control Point is equal to the Beam Meterset (300A,0086) specified in the Referenced Beam Sequence (300C,0004) of the RT Fraction Scheme Module, multiplied by the Cumulative Meterset Weight (300A,0134) for the Control Point, divided by the Final Cumulative Meterset Weight (300A,010E). The Meterset is specified in units defined by Primary Dosimeter Unit (300A,00B3). If the calculation for Meterset results in a meterset value which is not an exact multiple of the primary meterset resolution, then the result shall be rounded to the nearest allowed meterset value (i.e. less than a half resolution unit shall be rounded down to the nearest resolution unit, and equal or greater than half a resolution unit shall be rounded up to the nearest resolution unit). +Note also that if Final Cumulative Meterset Weight (300A,010E) is equal to 100, then Cumulative Meterset Weight (300A,0134) becomes equivalent to the percentage of Beam Meterset (300A,0086) delivered at each control point. If Final Cumulative Meterset Weight (300A,010E) is equal to Beam Meterset (300A,0086), then the Cumulative Meterset Weight (300A,0134) at each control point becomes equal to the cumulative Meterset delivered at that control point. +
+
+ + Number of control points in Beam. + + + Introduces sequence of machine configurations describing treatment beam. Two or more items may be included in this sequence. See C.8.8.14.5 and C.8.8.14.6. +
The DICOM RT Beams Module uses a single beam model to handle static, arc, and dynamic delivery of external beam radiation by a medical accelerator or gamma beam therapy equipment (cobalt unit). All applicable parameters shall be specified at Control Point 0, with the exception of couch positions (see C.8.8.14.6). All parameters that change at any control point of a given beam shall be specified explicitly at all control points (including those preceding the change). No assumptions are made about the behavior of machine parameters between specified control points, and communicating devices shall agree on this behavior outside the current standard. +Gantry Rotation Direction (300A,011F), Beam Limiting Device Rotation Direction (300A,0121), Patient Support Rotation Direction (300A,0123), and Table Top Eccentric Rotation Direction (300A,0126) are defined as applying to the segment following the control point, and changes to these parameters during treatment may be specified without use of a “non-irradiation†segment. All other Control Point Sequence attributes are defined only at the control point. To unambiguously encode changes in discrete-valued attributes such as Wedge Position (300A,0118) and Nominal Beam Energy (300A,0114), a non-irradiation segment where Cumulative Meterset Weight (300A,0134) does not change, shall be used. +Some examples of beam specification using control points are as follows: + +a) Static delivery: + Control Point 0: All applicable treatment parameters defined, Cumulative Meterset Weight = 0 + Control Point 1: Cumulative Meterset Weight = 1, no other parameters defined + +b) Arc delivery: + Control Point 0: All applicable treatment parameters defined, Cumulative Meterset Weight = 0, Gantry Rotation Direction = rotation direction, Gantry Angle = initial angle + Control Point 1: Cumulative Meterset Weight = 1, Gantry Rotation Direction = NONE, Gantry Angle = final angle + +c) Dynamic delivery of two equally weighted segments: + Control Point 0: All applicable treatment parameters defined, Cumulative Meterset Weight = 0 + Control Point 1: All changing treatment parameters defined (including those which do not change at this control point), Cumulative Meterset Weight = 0.5 + Control Point 2: All changing treatment parameters defined (including those which do not change at this control point), Cumulative Meterset Weight = 1 + +d) Dynamic Delivery of two unequally weighted segments with a step change in table angle: + Control Point 0: All applicable treatment parameters defined, Patient Support Angle = initial angle, Patient Support Rotation Direction = NONE, Cumulative Meterset Weight = 0 + Control Point 1: All changing parameters defined (including those that do not change at this control point), Cumulative Meterset Weight = 0.3, Patient Support Angle = initial angle, Patient Support Rotation Direction = rotation direction + Control Point 2: All changing parameters defined (although none should change at this control point), Cumulative Meterset Weight = 0.3, Patient Support Angle = new angle, Patient Support Rotation Direction = NONE + Control Point 3: All changing parameters defined (including those that do not change at this control point), Cumulative Meterset Weight = 1, Patient Support Angle = new angle, Patient Support Rotation Direction = NONE + +
+
+ + Index of current Control Point, starting at 0 for first Control Point. Required if Control Point Sequence (300A,0111) is sent. + + + Cumulative weight to current control point. Cumulative Meterset Weight for the first item in Control Point Sequence shall always be zero. Cumulative Meterset Weight for the final item in Control Point Sequence shall always be equal to Final Cumulative Meterset Weight. Required if Control Point Sequence (300A,0111) is sent. See C.8.8.14.1. +
The Meterset at a given Control Point is equal to the Beam Meterset (300A,0086) specified in the Referenced Beam Sequence (300C,0004) of the RT Fraction Scheme Module, multiplied by the Cumulative Meterset Weight (300A,0134) for the Control Point, divided by the Final Cumulative Meterset Weight (300A,010E). The Meterset is specified in units defined by Primary Dosimeter Unit (300A,00B3). If the calculation for Meterset results in a meterset value which is not an exact multiple of the primary meterset resolution, then the result shall be rounded to the nearest allowed meterset value (i.e. less than a half resolution unit shall be rounded down to the nearest resolution unit, and equal or greater than half a resolution unit shall be rounded up to the nearest resolution unit). +Note also that if Final Cumulative Meterset Weight (300A,010E) is equal to 100, then Cumulative Meterset Weight (300A,0134) becomes equivalent to the percentage of Beam Meterset (300A,0086) delivered at each control point. If Final Cumulative Meterset Weight (300A,010E) is equal to Beam Meterset (300A,0086), then the Cumulative Meterset Weight (300A,0134) at each control point becomes equal to the cumulative Meterset delivered at that control point. +
+
+ + Introduces a sequence of Dose References for current Beam. One or more items may be included in this sequence. + + + Uniquely identifies Dose Reference specified by Dose Reference Number (300A,0012) in Dose Reference Sequence (300A,0010) in RT Prescription Module. Required if Referenced Dose Reference Sequence (300C,0050) is sent. + + + Coefficient used to calculate cumulative dose contribution from this Beam to the referenced Dose Reference at the current Control Point. Required if Referenced Dose Reference Sequence (300C,0050) is sent. See C.8.8.14.7. +
The Cumulative Dose Reference Coefficient (300A,010C) is the value by which Beam Dose (300A,0084) is multiplied to obtain the dose to the referenced dose reference site at the current control point (and after previous control points have been successfully administered). The Cumulative Dose Reference Coefficient (300A,010C) is by definition zero for the initial control point. The Cumulative Dose Reference Coefficient (300A,010C) of the final control point multiplied by Beam Dose (300A,0084) results in the final dose to the referenced dose reference site for the current beam. Dose calculation for dose reference sites other than points is not well defined. +
+
+ + Sequence describing related instances of RT Dose (for grids, isodose curves, and named/unnamed point doses). One or more items may be included in this sequence. +Required if RT Dose is being sent, and Dose Summation Type (3004,000A) equals CONTROL_POINT. + + + + Nominal Beam Energy at control point (MV/MeV). + + + Dose Rate to be set on treatment machine for segment beginning at current control point (e.g. MU/min). + + + A Sequence of Items describing Wedge Positions for the current control point. +Required for first item of Control Point Sequence if Number of Wedges (300A,00D0) is non-zero, and in subsequent control points if Wedge Position (300A,0118) changes during Beam. See C.8.8.14.5. +The number of items in this sequence shall equal the value of Number of Wedges (300A,00D0). +
The DICOM RT Beams Module uses a single beam model to handle static, arc, and dynamic delivery of external beam radiation by a medical accelerator or gamma beam therapy equipment (cobalt unit). All applicable parameters shall be specified at Control Point 0, with the exception of couch positions (see C.8.8.14.6). All parameters that change at any control point of a given beam shall be specified explicitly at all control points (including those preceding the change). No assumptions are made about the behavior of machine parameters between specified control points, and communicating devices shall agree on this behavior outside the current standard. +Gantry Rotation Direction (300A,011F), Beam Limiting Device Rotation Direction (300A,0121), Patient Support Rotation Direction (300A,0123), and Table Top Eccentric Rotation Direction (300A,0126) are defined as applying to the segment following the control point, and changes to these parameters during treatment may be specified without use of a “non-irradiation†segment. All other Control Point Sequence attributes are defined only at the control point. To unambiguously encode changes in discrete-valued attributes such as Wedge Position (300A,0118) and Nominal Beam Energy (300A,0114), a non-irradiation segment where Cumulative Meterset Weight (300A,0134) does not change, shall be used. +Some examples of beam specification using control points are as follows: + +a) Static delivery: + Control Point 0: All applicable treatment parameters defined, Cumulative Meterset Weight = 0 + Control Point 1: Cumulative Meterset Weight = 1, no other parameters defined + +b) Arc delivery: + Control Point 0: All applicable treatment parameters defined, Cumulative Meterset Weight = 0, Gantry Rotation Direction = rotation direction, Gantry Angle = initial angle + Control Point 1: Cumulative Meterset Weight = 1, Gantry Rotation Direction = NONE, Gantry Angle = final angle + +c) Dynamic delivery of two equally weighted segments: + Control Point 0: All applicable treatment parameters defined, Cumulative Meterset Weight = 0 + Control Point 1: All changing treatment parameters defined (including those which do not change at this control point), Cumulative Meterset Weight = 0.5 + Control Point 2: All changing treatment parameters defined (including those which do not change at this control point), Cumulative Meterset Weight = 1 + +d) Dynamic Delivery of two unequally weighted segments with a step change in table angle: + Control Point 0: All applicable treatment parameters defined, Patient Support Angle = initial angle, Patient Support Rotation Direction = NONE, Cumulative Meterset Weight = 0 + Control Point 1: All changing parameters defined (including those that do not change at this control point), Cumulative Meterset Weight = 0.3, Patient Support Angle = initial angle, Patient Support Rotation Direction = rotation direction + Control Point 2: All changing parameters defined (although none should change at this control point), Cumulative Meterset Weight = 0.3, Patient Support Angle = new angle, Patient Support Rotation Direction = NONE + Control Point 3: All changing parameters defined (including those that do not change at this control point), Cumulative Meterset Weight = 1, Patient Support Angle = new angle, Patient Support Rotation Direction = NONE + +
+
+ + Uniquely references Wedge described by Wedge Number (300A,00D2) in Wedge Sequence (300A,00D1). Required if Wedge Position Sequence (300A,0116) is sent. + + + Position of Wedge at current Control Point. Required if Wedge Position Sequence (300A,0116) is sent. +Enumerated Values: +IN +OUT + + + Introduces sequence of beam limiting device (collimator) jaw or leaf (element) positions. Required for first item of Control Point Sequence, or if Beam Limiting Device changes during Beam. One or more items may be included in this sequence. + + + Type of beam limiting device (collimator). The value of this attribute shall correspond to RT Beam Limiting Device Type (300A,00B8) defined in an item of Beam Limiting Device Sequence (300A,00B6). Required if Beam Limiting Device Position Sequence (300A,011A) is sent. +Enumerated Values: +X = symmetric jaw pair in IEC X direction +Y = symmetric jaw pair in IEC Y direction +ASYMX = asymmetric jaw pair in IEC X direction +ASYMY = asymmetric pair in IEC Y direction +MLCX = multileaf (multi-element) jaw pair in IEC X direction +MLCY = multileaf (multi-element) jaw pair in IEC Y direction + + + Positions of beam limiting device (collimator) leaf (element) or jaw pairs (in mm) in IEC BEAM LIMITING DEVICE coordinate axis appropriate to RT Beam Limiting Device Type (300A,00B8), e.g. X-axis for MLCX, Y-axis for MLCY. Contains 2N values, where N is the Number of Leaf/Jaw Pairs (300A,00BC) in Beam Limiting Device Sequence (300A,00B6). Values shall be listed in IEC leaf (element) subscript order 101, 102, ... 1N, 201, 202, ... 2N. Required if Beam Limiting Device Position Sequence (300A,011A) is sent. See Note 2. + + + Gantry angle of radiation source, i.e. orientation of IEC GANTRY coordinate system with respect to IEC FIXED REFERENCE coordinate system (degrees). Required for first item of Control Point Sequence, or if Gantry Angle changes during Beam. + + + Direction of Gantry Rotation when viewing gantry from isocenter, for segment following Control Point. Required for first item of Control Point Sequence, or if Gantry Rotation Direction changes during Beam. See C.8.8.14.8. +Enumerated Values: +CW = clockwise +CC = counter-clockwise +NONE = no rotation +
For the machine rotation angles Gantry Angle (300A,011E), Beam Limiting Device Angle (300A,0120), Patient Support Angle (300A,0122) , and Table Top Eccentric Angle (300A,0125), rotation direction is specified as clockwise (CW), counter-clockwise (CC), or NONE. The maximum permitted rotation between two Control Points is 360 degrees. Examples: +a) Gantry Angle moves from 5 degrees to 5 degrees, Gantry Rotation Direction = NONE: + No movement. + +b) Gantry Angle moves from 5 degrees to 5 degrees, Gantry Rotation Direction = CW: + Full clockwise rotation (360 degrees). + +c) Table Angle moves from 170 degrees to 160 degrees, Table Rotation Direction = CC: + Counter-clockwise rotation by 350 degrees (note direction of increasing table angle as defined by IEC 61217). + +
+
+ + Gantry Pitch Angle. i.e. the rotation of the IEC GANTRY coordinate system about the X-axis of the IEC GANTRY coordinate system (degrees). If used, must be present for first item of Control Point Sequence, or if used and Gantry Pitch Rotation Angle changes during Beam, must be present. See C.8.8.25.6.5. +
The Gantry Pitch angle is not defined in IEC 61217. This angle is defined in the DICOM standard in a way compatible with the current notion of IEC by introducing it as rotation of the IEC GANTRY System as indicated below. +The Gantry Pitch Angle is defined as the rotation of the coordinate axes Yg, Zg about axis Xg by an angle ï¹g; see Figure C.8.8.25-7. An increase in the value of angle ï¹g corresponds to the clockwise rotation as viewed from the isocenter along the positive Xg axis + + +Figure C.8.8.25-7 Gantry Pitch Angle +
+
+ + Direction of Gantry Pitch Angle when viewing along the positive X-axis of the IEC GANTRY coordinate system, for segment following Control Point. If used, must be present for first item of Control Point Sequence, or if used and Gantry Pitch Rotation Direction changes during Beam, must be present. See C.8.8.14.8 and C.8.8.25.6.5. +Enumerated Values: +CW = clockwise +CC = counter-clockwise +NONE = no rotation +
For the machine rotation angles Gantry Angle (300A,011E), Beam Limiting Device Angle (300A,0120), Patient Support Angle (300A,0122) , and Table Top Eccentric Angle (300A,0125), rotation direction is specified as clockwise (CW), counter-clockwise (CC), or NONE. The maximum permitted rotation between two Control Points is 360 degrees. Examples: +a) Gantry Angle moves from 5 degrees to 5 degrees, Gantry Rotation Direction = NONE: + No movement. + +b) Gantry Angle moves from 5 degrees to 5 degrees, Gantry Rotation Direction = CW: + Full clockwise rotation (360 degrees). + +c) Table Angle moves from 170 degrees to 160 degrees, Table Rotation Direction = CC: + Counter-clockwise rotation by 350 degrees (note direction of increasing table angle as defined by IEC 61217). + +
+
+ + Beam Limiting Device angle, i.e. orientation of IEC BEAM LIMITING DEVICE coordinate system with respect to IEC GANTRY coordinate system (degrees). Required for first item of Control Point Sequence, or if Beam Limiting Device Angle changes during Beam. + + + Direction of Beam Limiting Device Rotation when viewing beam limiting device (collimator) from radiation source, for segment following Control Point. Required for first item of Control Point Sequence, or if Beam Limiting Device Rotation Direction changes during Beam. See C.8.8.14.8. +Enumerated Values: +CW = clockwise +CC = counter-clockwise +NONE = no rotation +
For the machine rotation angles Gantry Angle (300A,011E), Beam Limiting Device Angle (300A,0120), Patient Support Angle (300A,0122) , and Table Top Eccentric Angle (300A,0125), rotation direction is specified as clockwise (CW), counter-clockwise (CC), or NONE. The maximum permitted rotation between two Control Points is 360 degrees. Examples: +a) Gantry Angle moves from 5 degrees to 5 degrees, Gantry Rotation Direction = NONE: + No movement. + +b) Gantry Angle moves from 5 degrees to 5 degrees, Gantry Rotation Direction = CW: + Full clockwise rotation (360 degrees). + +c) Table Angle moves from 170 degrees to 160 degrees, Table Rotation Direction = CC: + Counter-clockwise rotation by 350 degrees (note direction of increasing table angle as defined by IEC 61217). + +
+
+ + Patient Support angle, i.e. orientation of IEC PATIENT SUPPORT (turntable) coordinate system with respect to IEC FIXED REFERENCE coordinate system (degrees). Required for first item of Control Point Sequence, or if Patient Support Angle changes during Beam. + + + Direction of Patient Support Rotation when viewing table from above, for segment following Control Point. Required for first item of Control Point Sequence, or if Patient Support Rotation Direction changes during Beam. See C.8.8.14.8. +Enumerated Values: +CW = clockwise +CC = counter-clockwise +NONE = no rotation +
For the machine rotation angles Gantry Angle (300A,011E), Beam Limiting Device Angle (300A,0120), Patient Support Angle (300A,0122) , and Table Top Eccentric Angle (300A,0125), rotation direction is specified as clockwise (CW), counter-clockwise (CC), or NONE. The maximum permitted rotation between two Control Points is 360 degrees. Examples: +a) Gantry Angle moves from 5 degrees to 5 degrees, Gantry Rotation Direction = NONE: + No movement. + +b) Gantry Angle moves from 5 degrees to 5 degrees, Gantry Rotation Direction = CW: + Full clockwise rotation (360 degrees). + +c) Table Angle moves from 170 degrees to 160 degrees, Table Rotation Direction = CC: + Counter-clockwise rotation by 350 degrees (note direction of increasing table angle as defined by IEC 61217). + +
+
+ + Distance (positive) from the IEC PATIENT SUPPORT vertical axis to the IEC TABLE TOP ECCENTRIC vertical axis (mm). + + + Table Top (non-isocentric) angle, i.e. orientation of IEC TABLE TOP ECCENTRIC coordinate system with respect to IEC PATIENT SUPPORT coordinate system (degrees). Required for first item of Control Point Sequence, or if Table Top Eccentric Angle changes during Beam. + + + Direction of Table Top Eccentric Rotation when viewing table from above, for segment following Control Point. Required for first item of Control Point Sequence, or if Table Top Eccentric Rotation Direction changes during Beam. See C.8.8.14.8. +Enumerated Values: +CW = clockwise +CC = counter-clockwise +NONE = no rotation +
For the machine rotation angles Gantry Angle (300A,011E), Beam Limiting Device Angle (300A,0120), Patient Support Angle (300A,0122) , and Table Top Eccentric Angle (300A,0125), rotation direction is specified as clockwise (CW), counter-clockwise (CC), or NONE. The maximum permitted rotation between two Control Points is 360 degrees. Examples: +a) Gantry Angle moves from 5 degrees to 5 degrees, Gantry Rotation Direction = NONE: + No movement. + +b) Gantry Angle moves from 5 degrees to 5 degrees, Gantry Rotation Direction = CW: + Full clockwise rotation (360 degrees). + +c) Table Angle moves from 170 degrees to 160 degrees, Table Rotation Direction = CC: + Counter-clockwise rotation by 350 degrees (note direction of increasing table angle as defined by IEC 61217). + +
+
+ + Table Top Pitch Angle, i.e. the rotation of the IEC TABLE TOP coordinate system about the X-axis of the IEC TABLE TOP coordinate system (degrees). If required by treatment delivery device, shall be present for first item of Control Point Sequence. If required by treatment delivery device and if Table Top Pitch Angle changes during Beam, shall be present in all subsequent items of Control Point Sequence. See C.8.8.25.6.2. +
Pitch and Roll Coordinate Systems of the Table Top are not defined in IEC 61217. These angles are defined in the DICOM standard in a way compatible with the current notion of IEC by introducing them as rotations of the IEC Table Top System as indicated below. +The Table Top Pitch Angle is defined as the rotation of the coordinate axes Yt, Zt about axis Xt by an angle ï¹t; see Figure C.8.8.25-3. An increase in the value of angle ï¹t corresponds to the clockwise rotation of the Table Top as viewed from the Table Top coordinate system origin along the positive Xt axis. +The Table Top Roll Angle is defined as the rotation of the coordinate axes Xt, Zt about axis Yt by an angle ïªt; see Figure C.8.8.25-4. An increase in the value of angle ïªt corresponds to the clockwise rotation of the Table Top as viewed from the Table Top coordinate system origin along the positive Yt axis. + + +Figure C.8.8.25-3 Table Top Pitch Angle + +Figure C.8.8.25-4 Table Top Roll Angle + +
+
+ + Direction of Table Top Pitch Rotation when viewing the table along the positive X-axis of the IEC TABLE TOP coordinate system, for segment following Control Point. If required by treatment delivery device, shall be present for first item of Control Point Sequence. If required by treatment delivery device and if Table Top Pitch Rotation Direction changes during Beam, shall be present in all subsequent items of Control Point Sequence. See C.8.8.14.8 and C.8.8.25.6.2. +Enumerated Values: +CW = clockwise +CC = counter-clockwise +NONE = no rotation +
For the machine rotation angles Gantry Angle (300A,011E), Beam Limiting Device Angle (300A,0120), Patient Support Angle (300A,0122) , and Table Top Eccentric Angle (300A,0125), rotation direction is specified as clockwise (CW), counter-clockwise (CC), or NONE. The maximum permitted rotation between two Control Points is 360 degrees. Examples: +a) Gantry Angle moves from 5 degrees to 5 degrees, Gantry Rotation Direction = NONE: + No movement. + +b) Gantry Angle moves from 5 degrees to 5 degrees, Gantry Rotation Direction = CW: + Full clockwise rotation (360 degrees). + +c) Table Angle moves from 170 degrees to 160 degrees, Table Rotation Direction = CC: + Counter-clockwise rotation by 350 degrees (note direction of increasing table angle as defined by IEC 61217). + +
+
+ + Table Top Roll Angle, i.e. the rotation of the IEC TABLE TOP coordinate system about the IEC Y-axis of the IEC TABLE TOP coordinate system (degrees). If required by treatment delivery device, shall be present for first item of Control Point Sequence. If required by treatment delivery device and if Table Top Roll Angle changes during Beam, shall be present in all subsequent items of Control Point Sequence. See C.8.8.25.6.2. +
Pitch and Roll Coordinate Systems of the Table Top are not defined in IEC 61217. These angles are defined in the DICOM standard in a way compatible with the current notion of IEC by introducing them as rotations of the IEC Table Top System as indicated below. +The Table Top Pitch Angle is defined as the rotation of the coordinate axes Yt, Zt about axis Xt by an angle ï¹t; see Figure C.8.8.25-3. An increase in the value of angle ï¹t corresponds to the clockwise rotation of the Table Top as viewed from the Table Top coordinate system origin along the positive Xt axis. +The Table Top Roll Angle is defined as the rotation of the coordinate axes Xt, Zt about axis Yt by an angle ïªt; see Figure C.8.8.25-4. An increase in the value of angle ïªt corresponds to the clockwise rotation of the Table Top as viewed from the Table Top coordinate system origin along the positive Yt axis. + + +Figure C.8.8.25-3 Table Top Pitch Angle + +Figure C.8.8.25-4 Table Top Roll Angle + +
+
+ + Direction of Table Top Roll Rotation when viewing the table along the positive Y-axis of the IEC TABLE TOP coordinate system, for segment following Control Point. If required by treatment delivery device, shall be present for first item of Control Point Sequence. If required by treatment delivery device and if Table Top Roll Rotation Direction changes during Beam, shall be present in all subsequent items of Control Point Sequence. See C.8.8.14.8 and C.8.8.25.6.2. +Enumerated Values: +CW = clockwise +CC = counter-clockwise +NONE = no rotation +
For the machine rotation angles Gantry Angle (300A,011E), Beam Limiting Device Angle (300A,0120), Patient Support Angle (300A,0122) , and Table Top Eccentric Angle (300A,0125), rotation direction is specified as clockwise (CW), counter-clockwise (CC), or NONE. The maximum permitted rotation between two Control Points is 360 degrees. Examples: +a) Gantry Angle moves from 5 degrees to 5 degrees, Gantry Rotation Direction = NONE: + No movement. + +b) Gantry Angle moves from 5 degrees to 5 degrees, Gantry Rotation Direction = CW: + Full clockwise rotation (360 degrees). + +c) Table Angle moves from 170 degrees to 160 degrees, Table Rotation Direction = CC: + Counter-clockwise rotation by 350 degrees (note direction of increasing table angle as defined by IEC 61217). + +
+
+ + Table Top Vertical position in IEC TABLE TOP coordinate system (mm). Required for first item of Control Point Sequence, or if Table Top Vertical Position changes during Beam. See C.8.8.14.6. +
All treatment machine parameters except couch translations are specified in absolute machine coordinates as defined by IEC 61217. For the Table Top Vertical Position (300A,0128), Table Top Longitudinal Position (300A,0129), and Table Top Lateral Position (300A,012A), if the first Control Point contains a value of non-zero length, all subsequent Control Point position values are absolute values in their respective coordinate system. If the first Control Point contains a zero-length value, all subsequent Control Point position values are specified relative to the (unknown) initial value. +
+
+ + Table Top Longitudinal position in IEC TABLE TOP coordinate system (mm). Required for first item of Control Point Sequence, or if Table Top Longitudinal Position changes during Beam. See C.8.8.14.6. +
All treatment machine parameters except couch translations are specified in absolute machine coordinates as defined by IEC 61217. For the Table Top Vertical Position (300A,0128), Table Top Longitudinal Position (300A,0129), and Table Top Lateral Position (300A,012A), if the first Control Point contains a value of non-zero length, all subsequent Control Point position values are absolute values in their respective coordinate system. If the first Control Point contains a zero-length value, all subsequent Control Point position values are specified relative to the (unknown) initial value. +
+
+ + Table Top Lateral position in IEC TABLE TOP coordinate system (mm). Required for first item of Control Point Sequence, or if Table Top Lateral Position changes during Beam. See C.8.8.14.6. +
All treatment machine parameters except couch translations are specified in absolute machine coordinates as defined by IEC 61217. For the Table Top Vertical Position (300A,0128), Table Top Longitudinal Position (300A,0129), and Table Top Lateral Position (300A,012A), if the first Control Point contains a value of non-zero length, all subsequent Control Point position values are absolute values in their respective coordinate system. If the first Control Point contains a zero-length value, all subsequent Control Point position values are specified relative to the (unknown) initial value. +
+
+ + Isocenter coordinates (x,y,z) in the patient based coordinate system described in C.7.6.2.1.1 (mm). Required for first item of Segment Control Point Sequence, or if Segment Isocenter Position changes during Beam. + + + Patient surface entry point coordinates (x,y,z) in the patient based coordinate system described in C.7.6.2.1.1 (mm). + + + Source to Patient Surface distance (mm). + +
+ + + Type of brachytherapy treatment technique. Enumerated Values: +INTRALUMENARY +INTRACAVITARY +INTERSTITIAL +CONTACT +INTRAVASCULAR +PERMANENT +See C.8.8.15.1. +
In permanent implant techniques the value for Channel Total Time (300A,0286) shall be mean life time of the isotope. The Brachy Control Point Sequence (300A,02D0) shall consist of two items: the first having Cumulative Time Weight (300A,02D6) = 0 and the second having Cumulative Time Weight (300A,02D6) = Final Cumulative Time Weight (300A,02C8). +
+
+ + Type of brachytherapy treatment. +Defined Terms: +MANUAL = manually positioned +HDR = High dose rate +MDR = Medium dose rate +LDR = Low dose rate +PDR = Pulsed dose rate + + + Introduces single item sequence describing treatment machine to be used for treatment delivery. Only one item may be included in this sequence. + + + User-defined name identifying treatment machine to be used for treatment delivery. + + + Manufacturer of the equipment to be used for treatment delivery. + + + Institution where the equipment is located that is to be used for treatment delivery. + + + Mailing address of the institution where the equipment is located that is to be used for treatment delivery. + + + Department in the institution where the equipment is located that is to be used for treatment delivery. + + + Manufacturer's model name of the equipment that is to be used for treatment delivery. + + + Manufacturer's serial number of the equipment that is to be used for treatment delivery. + + + Introduces sequence of Sources to be used within Application Setups. One or more items may be included in this sequence. + + + Identification number of the Source. The value of Source Number (300A,0212) shall be unique within the RT Plan in which it is created. + + + Type of Source. Defined Terms: +POINT +LINE +CYLINDER +SPHERE + + + Manufacturer of Source. + + + Diameter of active Source (mm). + + + Length of active Source (mm). + + + User-supplied identifier for encapsulation material of active Source. + + + Nominal thickness of wall of encapsulation (mm). See C.8.8.15.12. +
If provided, Source Encapsulation Nominal Thickness (300A,0222), Brachy Accessory Device Nominal Thickness (300A,026A), Source Applicator Wall Nominal Thickness (300A,029C), and Channel Shield Nominal Thickness (300A,02B8) shall indicate that the related objects are of uniform thickness with the specified value. If this is not the case, these attributes shall not be provided. +If provided, Source Encapsulation Nominal Transmission (300A,0224), Brachy Accessory Device Nominal Transmission (300A,026C), Source Applicator Wall Nominal Transmission (300A,029E), and Channel Shield Nominal Transmission (300A,02BA) shall indicate that the related objects are of uniform transmission with the specified value. If this is not the case, these attributes shall not be provided. +No assumptions are made about the source characteristics beyond the parameters specified here. +
+
+ + Nominal transmission through wall of encapsulation (between 0 and 1). See C.8.8.15.12 +
If provided, Source Encapsulation Nominal Thickness (300A,0222), Brachy Accessory Device Nominal Thickness (300A,026A), Source Applicator Wall Nominal Thickness (300A,029C), and Channel Shield Nominal Thickness (300A,02B8) shall indicate that the related objects are of uniform thickness with the specified value. If this is not the case, these attributes shall not be provided. +If provided, Source Encapsulation Nominal Transmission (300A,0224), Brachy Accessory Device Nominal Transmission (300A,026C), Source Applicator Wall Nominal Transmission (300A,029E), and Channel Shield Nominal Transmission (300A,02BA) shall indicate that the related objects are of uniform transmission with the specified value. If this is not the case, these attributes shall not be provided. +No assumptions are made about the source characteristics beyond the parameters specified here. +
+
+ + Name of Isotope. + + + Half-life of Isotope (days). + + + Measurement unit of Source Strength. +Required if the source is not a gamma-emitting (photon) source. May be present otherwise. +Enumerated Values: +AIR_KERMA_RATE = Air Kerma Rate if Source is Gamma emitting Isotope. +DOSE_RATE_WATER = Dose Rate in Water if Source is Beta emitting Isotope. + + + Air Kerma Rate in air of Isotope specified at Air Kerma Rate Reference Date (300A,022C) and Air Kerma Rate Reference Time (300A,022E) (in µGy h-1 at 1 m). Value shall be zero for non-gamma sources. + + + Source Strength of Isotope at Source Strength Reference Date (300A,022C) and Source Strength Reference Time (300A,022E), in units specified in Source Strength Units (300A,0229). +Required if the source is not a gamma-emitting (photon) source. See C.8.8.15.13. +
For beta emitting isotopes, the Source Strength (300A,022B) shall be defined at reference point (r0,θ0), where r0 is the radial distance of 2 mm from the source longitudinal axis, and θ0 is the angle of 90 degrees between the source longitudinal axis and the line defined by the center of the source and the reference point. Refer to: +• IEC 60601-2-17 (Medical electrical equipment – Particular requirements for the safety of automatically-controlled brachytherapy afterloading equipment), where the beta source strength is defined as: ABSORBED DOSE RATE [Gy s-1] in water at 2 mm along the perpendicular bisector from a RADIOACTIVE SOURCE emitting beta RADIATION. +• Nath et. al.: Intravascular brachytherapy physics: Report of the AAPM Radiation Therapy Committee Task Group No. 60, Med. Phys 26 (2) Feb 1999, pp 119-152. +
+
+ + Reference date for Reference Air Kerma Rate (300A,022A) or Source Strength (300A,022B) of Isotope. + + + Reference time for Air Kerma Rate (300A,022A) or Source Strength (300A,022B) of Isotope. + + + Introduces sequence of Application Setups for current RT Plan. One or more items may be included in this sequence. + + + Type of Application Setup. Defined Terms: +FLETCHER_SUIT +DELCLOS +BLOEDORN +JOSLIN_FLYNN +CHANDIGARH +MANCHESTER +HENSCHKE +NASOPHARYNGEAL +OESOPHAGEAL +ENDOBRONCHIAL +SYED_NEBLETT +ENDORECTAL +PERINEAL + + + Identification number of the Application Setup. The value of Application Setup Number (300A,0234) shall be unique within the RT Plan in which it is created. + + + User-defined name for Application Setup. + + + Manufacturer of Application Setup. + + + Identification number of the Template. The value of Template Number (300A,0240) shall be unique within the Application Setup in which it is created. + + + User-defined type for Template Device. + + + User-defined name for Template Device. + + + Introduces sequence of reference images used for validation of current Application Setup. One or more items may be included in this sequence. + + + + Total Reference Air Kerma for current Application Setup, i.e. the product of Air Kerma Rate of all Sources in all Channels with their respective Channel Times (µGy at 1 m). Value shall be zero for non-gamma sources. + + + Introduces sequence of Brachy Accessory Devices associated with current Application Setup. One or more items may be included in this sequence. + + + Identification number of the Brachy Accessory Device. The value of Brachy Accessory Device Number (300A,0262) shall be unique within the Application Setup in which it is created. Required if Brachy Accessory Device Sequence (300A,0260) is sent. + + + User or machine supplied identifier for Brachy Accessory Device. Required if Brachy Accessory Device Sequence (300A,0260) is sent. + + + Type of Brachy Accessory Device. Required if Brachy Accessory Device Sequence (300A,0260) is sent. Defined Terms: +SHIELD +DILATATION +MOLD +PLAQUE +FLAB + + + User-defined name for Brachy Accessory Device. + + + User-supplied identifier for material of Brachy Accessory Device. See Note. + + + Nominal thickness of Brachy Accessory Device (mm). See C.8.8.15.12. +
If provided, Source Encapsulation Nominal Thickness (300A,0222), Brachy Accessory Device Nominal Thickness (300A,026A), Source Applicator Wall Nominal Thickness (300A,029C), and Channel Shield Nominal Thickness (300A,02B8) shall indicate that the related objects are of uniform thickness with the specified value. If this is not the case, these attributes shall not be provided. +If provided, Source Encapsulation Nominal Transmission (300A,0224), Brachy Accessory Device Nominal Transmission (300A,026C), Source Applicator Wall Nominal Transmission (300A,029E), and Channel Shield Nominal Transmission (300A,02BA) shall indicate that the related objects are of uniform transmission with the specified value. If this is not the case, these attributes shall not be provided. +No assumptions are made about the source characteristics beyond the parameters specified here. +
+
+ + Nominal Transmission through Brachy Accessory Device (between 0 and 1). See C.8.8.15.12. +
If provided, Source Encapsulation Nominal Thickness (300A,0222), Brachy Accessory Device Nominal Thickness (300A,026A), Source Applicator Wall Nominal Thickness (300A,029C), and Channel Shield Nominal Thickness (300A,02B8) shall indicate that the related objects are of uniform thickness with the specified value. If this is not the case, these attributes shall not be provided. +If provided, Source Encapsulation Nominal Transmission (300A,0224), Brachy Accessory Device Nominal Transmission (300A,026C), Source Applicator Wall Nominal Transmission (300A,029E), and Channel Shield Nominal Transmission (300A,02BA) shall indicate that the related objects are of uniform transmission with the specified value. If this is not the case, these attributes shall not be provided. +No assumptions are made about the source characteristics beyond the parameters specified here. +
+
+ + Uniquely identifies ROI representing the Brachy Accessory specified by ROI Number (3006,0022) in Structure Set ROI Sequence (3006,0020) in Structure Set Module within RT Structure Set referenced by Referenced RT Structure Set Sequence (300C,0060) in RT General Plan Module. Required if Brachy Accessory Device Sequence (300A,0260) is sent. See C.8.8.15.2. +
The Structure Set ROI shall be used in the Brachy Application Setups Module to describe the 3D coordinates of Accessory Devices, Applicators and Channel Shields, but not individual source positions (see C.8.8.15.9 and C.8.8.15.10). +
+
+ + Introduces sequence of Channels for current Application Setup. One or more items may be included in this sequence. + + + Identification number of the Channel. The value of Channel Number (300A,0282) shall be unique within the Application Setup in which it is created. + + + Length of Channel (mm). See C.8.8.15.3. +
If specified, the Channel Length (300A,0284) shall be the sum of the Source Applicator Length (300A,0296) and Transfer Tube Length (300A,02A4). +
+
+ + Total amount of time between first and final Control Points of the Brachy Control Point Sequence (300A,02D0) for current Channel (sec). Channel Total Time calculation is based upon the Reference Air Kerma Rate (300A,022A) of the Referenced Source Number (300C,000E). + + + Type of Source movement. See C.8.8.15.4. Defined Terms: +STEPWISE +FIXED +OSCILLATING +UNIDIRECTIONAL +
In brachytherapy treatment techniques involving oscillating source movement (i.e. when Source Movement Type (300A,0288) is OSCILLATING), the Brachy Control Point Sequence (300A,02D0) shall consist of two items. The first Control Point shall have Cumulative Time Weight (300A,02D6) = 0, and Control Point Relative Position (300A,02D2) equal to one end point of the oscillation. The second Control Point shall have Cumulative Time Weight (300A,02D6) = Final Cumulative Time Weight (300A,02C8), and Control Point Relative Position (300A,02D2) equal to the other end point of the oscillation. Transit time shall not be modeled explicitly for oscillating techniques. +
+
+ + Number of Pulses per fraction for current Channel. Required if Brachy Treatment Type (300A,0202) is PDR. + + + Pulse repetition interval (sec) for current Channel. Required if Brachy Treatment Type (300A,0202) is PDR. + + + Identification number of the Source Applicator. The value of Source Applicator Number (300A,0290) shall be unique within the Channel in which it is created. + + + User or machine supplied identifier for Source Applicator. Required if Source Applicator Number (300A,0290) is sent. + + + Type of Source Applicator. Required if Source Applicator Number (300A,0290) is sent. Defined Terms: +FLEXIBLE +RIGID + + + User-defined name for Source Applicator. + + + Length of Source Applicator (mm), defined as the distance between the connector of the applicator and the distal-most position of the source. Required if Source Applicator Number (300A,0290) is sent. + + + Manufacturer of Source Applicator. + + + User-supplied identifier for material of Source Applicator wall. See Note. + + + Nominal Thickness of Source Applicator wall (mm). See C.8.8.15.12. +
If provided, Source Encapsulation Nominal Thickness (300A,0222), Brachy Accessory Device Nominal Thickness (300A,026A), Source Applicator Wall Nominal Thickness (300A,029C), and Channel Shield Nominal Thickness (300A,02B8) shall indicate that the related objects are of uniform thickness with the specified value. If this is not the case, these attributes shall not be provided. +If provided, Source Encapsulation Nominal Transmission (300A,0224), Brachy Accessory Device Nominal Transmission (300A,026C), Source Applicator Wall Nominal Transmission (300A,029E), and Channel Shield Nominal Transmission (300A,02BA) shall indicate that the related objects are of uniform transmission with the specified value. If this is not the case, these attributes shall not be provided. +No assumptions are made about the source characteristics beyond the parameters specified here. +
+
+ + Nominal Transmission through Source Applicator wall (between 0 and 1). See C.8.8.15.12. +
If provided, Source Encapsulation Nominal Thickness (300A,0222), Brachy Accessory Device Nominal Thickness (300A,026A), Source Applicator Wall Nominal Thickness (300A,029C), and Channel Shield Nominal Thickness (300A,02B8) shall indicate that the related objects are of uniform thickness with the specified value. If this is not the case, these attributes shall not be provided. +If provided, Source Encapsulation Nominal Transmission (300A,0224), Brachy Accessory Device Nominal Transmission (300A,026C), Source Applicator Wall Nominal Transmission (300A,029E), and Channel Shield Nominal Transmission (300A,02BA) shall indicate that the related objects are of uniform transmission with the specified value. If this is not the case, these attributes shall not be provided. +No assumptions are made about the source characteristics beyond the parameters specified here. +
+
+ + Distance of path along channel (in mm) between adjacent (potential) dwell positions. Required if Source Movement Type (300A,0288) is STEPWISE. + + + Uniquely identifies ROI representing the Source Applicator specified by ROI Number (3006,0022) in Structure Set ROI Sequence (3006,0020) in Structure Set Module within RT Structure Set referenced by Referenced RT Structure Set Sequence (300C,0060) in RT General Plan Module. Required if Source Applicator Number (300A,0290) is sent. See C.8.8.15.2. +
The Structure Set ROI shall be used in the Brachy Application Setups Module to describe the 3D coordinates of Accessory Devices, Applicators and Channel Shields, but not individual source positions (see C.8.8.15.9 and C.8.8.15.10). +
+
+ + Identification number of the Transfer Tube. The value of Transfer Tube Number (300A,02A2) shall be unique within the Channel in which it is created. + + + Length of Transfer Tube of current afterloading Channel (mm). Required if value Transfer Tube Number (300A,02A2) is non-null. + + + Introduces sequence of Channel Shields associated with current Channel. One or more items may be included in this sequence. See C.8.8.15.5. +
The effect of Channel Shields on dose contributions shall be specific to the Channel for which they are specified. There shall be no effect of these shields on the dose contributions from any other Channels. +
+
+ + Identification number of the Channel Shield. The value of Channel Shield Number (300A,02B2) shall be unique within the Channel in which it is created. Required if Channel Shield Sequence (300A,02B0) is sent. + + + User or machine supplied identifier for Channel Shield. Required if Channel Shield Sequence (300A,02B0) is sent. + + + User-defined name for Channel Shield. + + + User-supplied identifier for material of Channel Shield. See Note. + + + Nominal Thickness of Channel Shield (mm). See C.8.8.15.12. +
If provided, Source Encapsulation Nominal Thickness (300A,0222), Brachy Accessory Device Nominal Thickness (300A,026A), Source Applicator Wall Nominal Thickness (300A,029C), and Channel Shield Nominal Thickness (300A,02B8) shall indicate that the related objects are of uniform thickness with the specified value. If this is not the case, these attributes shall not be provided. +If provided, Source Encapsulation Nominal Transmission (300A,0224), Brachy Accessory Device Nominal Transmission (300A,026C), Source Applicator Wall Nominal Transmission (300A,029E), and Channel Shield Nominal Transmission (300A,02BA) shall indicate that the related objects are of uniform transmission with the specified value. If this is not the case, these attributes shall not be provided. +No assumptions are made about the source characteristics beyond the parameters specified here. +
+
+ + Nominal Transmission of Channel Shield (between 0 and 1). See C.8.8.15.12. +
If provided, Source Encapsulation Nominal Thickness (300A,0222), Brachy Accessory Device Nominal Thickness (300A,026A), Source Applicator Wall Nominal Thickness (300A,029C), and Channel Shield Nominal Thickness (300A,02B8) shall indicate that the related objects are of uniform thickness with the specified value. If this is not the case, these attributes shall not be provided. +If provided, Source Encapsulation Nominal Transmission (300A,0224), Brachy Accessory Device Nominal Transmission (300A,026C), Source Applicator Wall Nominal Transmission (300A,029E), and Channel Shield Nominal Transmission (300A,02BA) shall indicate that the related objects are of uniform transmission with the specified value. If this is not the case, these attributes shall not be provided. +No assumptions are made about the source characteristics beyond the parameters specified here. +
+
+ + Uniquely identifies ROI representing the Channel Shield specified by ROI Number (3006,0022) in Structure Set ROI Sequence (3006,0020) in Structure Set Module within RT Structure Set referenced by Referenced RT Structure Set Sequence (300C,0060) in RT General Plan Module. Required if Channel Shield Sequence (300A,02B0) is sent. See C.8.8.15.2. +
The Structure Set ROI shall be used in the Brachy Application Setups Module to describe the 3D coordinates of Accessory Devices, Applicators and Channel Shields, but not individual source positions (see C.8.8.15.9 and C.8.8.15.10). +
+
+ + Uniquely identifies the referenced Source within the Source Sequence (300A,0210) for current Application Setup. + + + Number of control points in Channel. For an N-segment Channel there will be 2N (stepwise movement) or N+1 (continuous movement) control points. + + + Value of Cumulative Time Weight (300A,02D6) for final Control Point in Brachy Control Point Sequence (300A,02D0). Required if Cumulative Time Weight (300A,02D6) is non-null in Control Points specified within Brachy Control Point Sequence (300A,02D0). See C.8.8.15.6. +
The treatment time at a given Control Point is equal to the Channel Total Time (300A,0286), multiplied by the Cumulative Time Weight (300A,02D6) for the Control Point, divided by the Final Cumulative Time Weight (300A,02C8). If the calculation for treatment time results in a time value which is not an exact multiple of the timer resolution, then the result shall be rounded to the nearest allowed timer value (i.e. less than a half resolution unit shall be rounded down to the nearest resolution unit, and equal or greater than half a resolution unit shall be rounded up to the nearest resolution unit). +Note also that if Final Cumulative Time Weight (300A,02C8) is equal to 100, then Cumulative Time Weight (300A,02D6) becomes equivalent to the percentage of Channel Total Time (300A,0286) delivered at each control point. If Final Cumulative Time Weight (300A,02C8) is equal to Channel Total Time (300A,0286), then the Cumulative Time Weight (300A,02D6) at each control point becomes equal to the cumulative treatment time delivered at that control point. +If Treatment Type (300A,0202) is PDR, then the Channel Total Time (3008,0286) shall specify the duration of a single pulse. +
+
+ + Introduces sequence of machine configurations describing this Channel. Two or more items may be included in this sequence. See C.8.8.15.7. +
The Control Points shall be arranged such that the first Control Point for a particular Channel describes the first dwell position and the final Control Point for the Channel describes the final dwell position. If Brachy Treatment Type (300A,0202) is PDR, the Brachy Control Point Sequence (300A,02D0) shall specify the sequence of machine configurations for a single pulse. Similarly, if Source Movement Type (300A,0288) is OSCILLATING, the Brachy Control Point Sequence (300A,02D0) shall specify the sequence of machine configurations for a single period. +Some examples of Brachytherapy specification using control points are as follows: + + a) Stepwise motion; Four equally weighted dwell positions; Step size = 10; Final Cumulative Time Weight = 100: + + Control Point 0: Control Point Relative Position = 30, Cumulative Time Weight = 0 + Control Point 1: Control Point Relative Position = 30, Cumulative Time Weight = 25 + Control Point 2: Control Point Relative Position = 20, Cumulative Time Weight = 25 + Control Point 3: Control Point Relative Position = 20, Cumulative Time Weight = 50 + Control Point 4: Control Point Relative Position = 10, Cumulative Time Weight = 50 + Control Point 5: Control Point Relative Position = 10, Cumulative Time Weight = 75 + Control Point 6: Control Point Relative Position = 0, Cumulative Time Weight = 75 + Control Point 7: Control Point Relative Position = 0, Cumulative Time Weight = 100 + + b) Fixed (manually placed) sources; Final Cumulative Time Weight = 100: + + Control Point 0: Control Point Relative Position = 0, Control Point 3D Position = (x,y,z), +Cumulative Time Weight = 0 + Control Point 1: Control Point Relative Position = 0, Control Point 3D Position = (x,y,z), +Cumulative Time Weight = 100 + + c) Oscillating movement; Final Cumulative Time Weight = 100: + + Control Point 0: Control Point Relative Position = 100, Cumulative Time Weight = 0 + Control Point 1: Control Point Relative Position = 0, Cumulative Time Weight = 100 + + d) Unidirectional movement; Final Cumulative Time Weight = 100: + + Control Point 0: Control Point Relative Position = 0, Cumulative Time Weight = 0 + Control Point 1: Control Point Relative Position = 100, Cumulative Time Weight = 100 + + e) Stepwise motion with consideration of source transit times between dwell positions; Three equally weighted dwell positions; Step size = 10; Final Cumulative Time Weight = 79: + + Control Point 0: Control Point Relative Position = 30, Cumulative Time Weight = 0 + Control Point 1: Control Point Relative Position = 30, Cumulative Time Weight = 25 + Control Point 2: Control Point Relative Position = 20, Cumulative Time Weight = 27 + Control Point 3: Control Point Relative Position = 20, Cumulative Time Weight = 52 + Control Point 4: Control Point Relative Position = 10, Cumulative Time Weight = 54 + Control Point 5: Control Point Relative Position = 10, Cumulative Time Weight = 79 + + f) Stepwise motion with consideration of source transit times between dwell positions and to first and from last dwell position; Three equally weighted dwell positions; Step size = 10; Final Cumulative Time Weight = 383: + + Control Point 0: Control Point Relative Position = 1200, Cumulative Time Weight = 0 + Control Point 1: Control Point Relative Position = 30, Cumulative Time Weight = 150 + Control Point 2: Control Point Relative Position = 30, Cumulative Time Weight = 175 + Control Point 3: Control Point Relative Position = 20, Cumulative Time Weight = 177 + Control Point 4: Control Point Relative Position = 20, Cumulative Time Weight = 202 + Control Point 5: Control Point Relative Position = 10, Cumulative Time Weight = 204 + Control Point 6: Control Point Relative Position = 10, Cumulative Time Weight = 229 + Control Point 7: Control Point Relative Position = 1200, Cumulative Time Weight = 383 + +
+
+ + Index of current Control Point, starting at 0 for first Control Point. + + + Cumulative time weight to current Control Point (where the weighting is proportional to time values delivered). Cumulative Time Weight for first item in Brachy Control Point Sequence (300A,02D0) is always zero. See C.8.8.15.6 and C.8.8.15.8. +
The treatment time at a given Control Point is equal to the Channel Total Time (300A,0286), multiplied by the Cumulative Time Weight (300A,02D6) for the Control Point, divided by the Final Cumulative Time Weight (300A,02C8). If the calculation for treatment time results in a time value which is not an exact multiple of the timer resolution, then the result shall be rounded to the nearest allowed timer value (i.e. less than a half resolution unit shall be rounded down to the nearest resolution unit, and equal or greater than half a resolution unit shall be rounded up to the nearest resolution unit). +Note also that if Final Cumulative Time Weight (300A,02C8) is equal to 100, then Cumulative Time Weight (300A,02D6) becomes equivalent to the percentage of Channel Total Time (300A,0286) delivered at each control point. If Final Cumulative Time Weight (300A,02C8) is equal to Channel Total Time (300A,0286), then the Cumulative Time Weight (300A,02D6) at each control point becomes equal to the cumulative treatment time delivered at that control point. +If Treatment Type (300A,0202) is PDR, then the Channel Total Time (3008,0286) shall specify the duration of a single pulse. +
+
+ + Distance between current Control Point Position and the distal-most possible Source position in current Channel (mm). See C.8.8.15.9. +
Control Point Relative Position (300A,02D2) shall describe where a given source in a channel is located with respect to the end of the channel. This position shall correspond to the end of the afterloader applicator, not the “safe positionâ€. +
+
+ + Coordinates (x, y, z) of Control Point in the patient based coordinate system described in C.7.6.2.1.1 (mm). See C.8.8.15.10. +
Control Point 3D Position (300A,02D4) shall describe the absolute 3D coordinates of a source. This position shall correspond to the center of a source in an applicator during a remote or manually controlled afterloading treatment. +
+
+ + (x,y,z) component of the direction vector of the brachy source or seed at the Control Point 3D Position (300A,02D4). See C.8.8.15.14. +
The Control Point Orientation (300A,0412) shall be used to define the orientation of an anisotropic brachytherapy source or seed for the purpose of calculating the effect of the anisotropy on the dose calculation. The Control Point Orientation (300A,0412) shall be given by the direction vector of the long axis of the Brachy source or seed in the insertion direction, in the DICOM Patient Coordinate System. The direction vector shall be oriented from the source center as defined by the Control Point 3D Position (300A,02D4) along the long axis of the source and in the insertion direction. +
+
+ + Introduces a sequence of Dose References for current Channel. One or more items may be included in this sequence. + + + Uniquely identifies Dose Reference described in Dose Reference Sequence. (300A,0010) within RT Prescription Module of current RT Plan. Required if Brachy Referenced Dose Reference Sequence (300C,0055) is sent. + + + Coefficient used to calculate cumulative dose contribution from this Source to the referenced Dose Reference at the current Control Point. Required if Brachy Referenced Dose Reference Sequence (300C,0055) is sent. See C.8.8.15.11. +
The Cumulative Dose Reference Coefficient (300A,010C) is the value by which Brachy Application Setup Dose (300A,00A4) is multiplied to obtain the dose to the referenced dose reference site at the current control point (and after previous control points have been successfully administered). The Cumulative Dose Reference Coefficient (300A,010C) is by definition zero for the initial control point. The Cumulative Dose Reference Coefficient (300A,010C) of the final control point multiplied by Brachy Application Setup Dose (300A,00A4) results in the final dose to the referenced dose reference site for the current channel. Dose calculation for dose reference sites other than points is not well defined. +If Treatment Type (300A,0202) is PDR, then the Cumulative Dose Reference Coefficient (3008,010C) shall specify the dose delivered to the dose reference during a single pulse. The total dose delivered to the dose reference shall then be expressed by Cumulative Dose Reference Coefficient (3008,010C) multiplied by Number of Pulses (300A,028A) multiplied by Brachy Application Setup Dose (300A,00A4). +
+
+
+ + + Approval status at the time the SOP Instance was created. +Enumerated Values: +APPROVED = Reviewer recorded that object met an implied criterion +UNAPPROVED = No review of object has been recorded +REJECTED = Reviewer recorded that object failed to meet an implied criterion + + + Date on which object was reviewed. Required if Approval Status (300E,0002) is APPROVED or REJECTED. + + + Time at which object was reviewed. Required if Approval Status (300E,0002) is APPROVED or REJECTED. + + + Name of person who reviewed object. Required if Approval Status (300E,0002) is APPROVED or REJECTED. + + + + + Instance number identifying this particular instance of the object. + + + Date when current fraction was delivered, or Date last fraction was delivered in case of RT Treatment Summary Record IOD. See Note. + + + Time when current fraction was delivered (begun), or Time last fraction was delivered (begun) in case of RT Treatment Summary Record IOD. See Note. + + + A sequence which provides reference to a RT Plan SOP Class/Instance pair. Only a single Item shall be permitted in this Sequence. + + + + A sequence which provides reference to RT Treatment Record SOP Class/Instance pairs to which the current RT Treatment Record is significantly related. The sequence may contain one or more items. + + + + + + Introduces sequence describing treatment machine used for treatment delivery. Only a single Item shall be permitted in this Sequence. + + + User-defined name identifying treatment machine used for treatment delivery. + + + Manufacturer of the equipment used for treatment delivery. + + + Institution where the equipment is located that was used for treatment delivery. + + + Mailing address of the institution where the equipment is located that was used for treatment delivery. + + + Department in the institution where the equipment is located that was used for treatment delivery. + + + Manufacturer's model name of the equipment used for treatment delivery. + + + Manufacturer's serial number of the equipment used for treatment delivery. + + + + + Introduces sequence of doses measured during treatment delivery, summed over entire session. The sequence may contain one or more items. + + + Uniquely identifies Dose Reference specified by Dose Reference Number (300A,0012) in Dose Reference Sequence (300A,0010) in RT Prescription Module of referenced RT Plan. Required only if Measured Dose Reference Number (3008,0064) is not sent. It shall not be present otherwise. + + + Unique identifier of measured dose point. Required only if Referenced Dose Reference Number (300C,0051) is not sent. It shall not be present otherwise. + + + Units used to describe measured dose. +Enumerated Values: +GY = Gray +RELATIVE = Dose relative to implicit reference value + + + Measured Dose in units specified by Dose Units (3004,0002). + + + Type of dose measurement. +Defined Terms: +DIODE = semiconductor diode +TLD = thermoluminescent dosimeter +ION_CHAMBER = ion chamber +GEL = dose sensitive gel +EPID = electronic portal imaging device +FILM = dose sensitive film + + + User-defined description of Dose Reference (e.g. "Exit dose", "Point A"). + + + + + Introduces sequence of doses estimated for each treatment delivery. The sequence may contain one or more items. + + + Uniquely identifies Dose Reference specified by Dose Reference Number (300A,0012) in Dose Reference Sequence (300A,0010) in RT Prescription Module of referenced RT Plan. Required only if Calculated Dose Reference Number (3008,0072) is not sent. It shall not be present otherwise. + + + Unique identifier of dose reference point within RT Treatment Record IOD. Required only if Referenced Dose Reference Number (300C,0051) is not sent. It shall not be present otherwise. + + + Calculated Dose (Gy). + + + User-defined description of Calculated Dose Reference. + + + + + Name of operator administering treatment session. + + + Identifier of Fraction Group within referenced RT Plan. + + + Total number of treatments (Fractions) planned for current Fraction Group. + + + Measurement unit of machine dosimeter. +Enumerated Values: +MU = Monitor Unit +MINUTE = minute + + + Introduces sequence of Beams administered during treatment session. The sequence may contain one or more items. + + + References Beam specified by Beam Number (300A,00C0) in Beam Sequence (300A,00B0) in RT Beams Module within referenced RT Plan. + + + User-defined name for delivered Beam. + + + User-defined description for delivered Beam. + + + Motion characteristic of delivered Beam. Enumerated Values: +STATIC = all beam parameters remain unchanged during delivery +DYNAMIC = one or more beam parameters changes during delivery + + + Particle type of delivered Beam. +Defined Terms: +PHOTON, ELECTRON, NEUTRON, PROTON. + + + Type of high-dose treatment technique. +Defined Terms: +NORMAL = Standard treatment +TBI = Total Body Irradiation +HDR = High Dose Rate +Required if treatment technique requires a dose that would normally require overriding of treatment machine safety controls. + + + Introduces sequence of verification images obtained during delivery of current beam. The sequence may contain one or more items. + + + + Cumulative Meterset Weight within Beam referenced by Referenced Beam Number at which image acquisition starts. + + + Cumulative Meterset Weight within Beam referenced by Referenced Beam Number at which image acquisition ends. + + + Introduces sequence of doses measured during treatment delivery for current Beam. The sequence may contain one or more items. + + + Uniquely references Dose Reference specified by Dose Reference Number (300A,0012) in Dose Reference Sequence (300A,0010) in RT Prescription Module of referenced RT Plan. Required if Referenced Measured Dose Reference Sequence (3008,0080) is sent and Referenced Measured Dose Reference Number (3008,0082) is not sent. It shall not be present otherwise. + + + Uniquely references Measured Dose Reference specified by Measured Dose Reference Number (3008,0064) in Measured Dose Reference Sequence (3008,0010). Required if Referenced Measured Dose Reference Sequence (3008,0080) is sent and Referenced Dose Reference Number (300C,0051) is not sent. It shall not be present otherwise. + + + Measured Dose in units specified by Dose Units (3004,0002) in sequence referenced by Measured Dose Reference Sequence (3008,0010) or Dose Reference Sequence (300A,0010) in RT Prescription Module of referenced RT Plan as defined above. Required if Referenced Measured Dose Reference Sequence (3008,0080) is sent. + + + Introduces sequence of doses estimated for each treatment delivery. The sequence may contain one or more items. + + + Uniquely identifies Dose Reference specified by Dose Reference Number (300A,0012) in Dose Reference Sequence (300A,0010) in RT Prescription Module of referenced RT Plan. Required if Referenced Calculated Dose Reference Sequence (3008,0090) is sent and Referenced Calculated Dose Reference Number (3008,0092) is not sent. + + + Uniquely identifies Calculated Dose Reference specified by Calculated Dose Reference Number (3008,0072) within Calculated Dose Reference Sequence (3008,0070). Required if Referenced Calculated Dose Reference Sequence (3008,0090) is sent and Referenced Dose Reference Number (300C,0051) is not sent. + + + Calculated Dose (Gy). Required if Referenced Calculated Dose Reference Sequence (3008,0090) is sent. + + + Radiation source to gantry rotation axis distance of the equipment that was used for beam delivery (mm). + + + Introduces sequence of beam limiting device (collimator) jaw or leaf (element) leaf pair values. The sequence may contain one or more items. + + + Type of beam limiting device (collimator). +Enumerated Values: +X = symmetric jaw pair in IEC X direction +Y = symmetric jaw pair in IEC Y direction +ASYMX = asymmetric jaw pair in IEC X direction +ASYMY = asymmetric pair in IEC Y direction +MLCX = multileaf (multi-element) jaw pair in IEC X direction +MLCY = multileaf (multi-element) jaw pair in IEC Y direction + + + + Number of leaf (element) or jaw pairs (equal to 1 for standard beam limiting device jaws). + + + Uniquely identifies Patient Setup used within current beam, specified by Patient Setup Number (300A,0182) within Patient Setup Sequence (300A,0180) of RT Treatment Record. + + + Number of wedges associated with current delivered Beam. + + + Introduces sequence of treatment wedges present during delivered Beam. Required if Number of Wedges (300A,00D0) is non-zero. The sequence may contain one or more items. + + + Identification number of the Wedge. The value of Wedge Number (300A,00D2) shall be unique within the wedge sequence. + + + Type of wedge defined for delivered Beam. Required if Recorded Wedge Sequence (3008,00B0) is sent. +Defined Terms: +STANDARD = standard (static) wedge +DYNAMIC = moving Beam Limiting Device (collimator) jaw simulating wedge +MOTORIZED = single wedge which can be removed from beam remotely + + + User-supplied identifier for wedge. + + + An identifier for the accessory intended to be read by a device such as a bar-code reader. + + + Nominal wedge angle delivered (degrees). + + + Orientation of wedge, i.e. orientation of IEC WEDGE FILTER coordinate system with respect to IEC BEAM LIMITING DEVICE coordinate system (degrees). + + + Number of compensators associated with current delivered Beam. + + + Introduces sequence of treatment compensators associated with current Beam. The sequence may contain one or more items. + + + Uniquely identifies compensator specified by Compensator Number (300A,00E4) within Beam referenced by Referenced Beam Number (300C,0006). Required if Recorded Compensator Sequence (3008,00C0) is sent. + + + Type of compensator (if any). Required if Recorded Compensator Sequence (3008,00C0) is sent. +Defined Terms: +STANDARD = physical (static) compensator +DYNAMIC = moving Beam Limiting Device (collimator) simulating compensator + + + User-supplied identifier for compensator. + + + An identifier for the accessory intended to be read by a device such as a bar-code reader. + + + Number of boli used with current Beam. + + + Introduces sequence of boli associated with Beam. The sequence may contain one or more items. + + + Uniquely identifies ROI representing the bolus specified by ROI Number (3006,0022) in Structure Set ROI Sequence (3006,0020) in Structure Set Module within RT Structure Set IOD referenced by referenced RT Plan in Referenced RT Plan Sequence (300C,0002) in RT General Treatment Record Module. Required if Referenced Bolus Sequence (300C,00B0) is sent. + + + User-supplied identifier for the Bolus. + + + An identifier for the accessory intended to be read by a device such as a bar-code reader. + + + Number of shielding blocks or Electron Inserts associated with Beam. + + + Introduces sequence of blocks associated with current Beam. The sequence may contain one or more items. + + + User-supplied identifier for block tray or Electron Insert. + + + An identifier for the accessory intended to be read by a device such as a bar-code reader. + + + Uniquely identifies block specified by Block Number (300A,00FC) within Beam referenced by Referenced Beam Number (300C,0006). + + + User-defined name for block. Required if Recorded Block Sequence (3008,00D0) is sent. + + + Introduces sequence of Applicators associated with Beam. Only a single item shall be permitted in this sequence. + + + User or machine supplied identifier for Applicator. Required if Applicator Sequence (300A,0107) is sent. + + + An identifier for the accessory intended to be read by a device such as a bar-code reader. + + + Type of Applicator. Required if Applicator Sequence (300A,0107) is sent. +Defined Terms: +ELECTRON_SQUARE = square electron applicator +ELECTRON_RECT = rectangular electron applicator +ELECTRON_CIRC = circular electron applicator +ELECTRON_SHORT = short electron applicator +ELECTRON_OPEN = open (dummy) electron applicator +INTRAOPERATIVE = intraoperative (custom) applicator +STEREOTACTIC = stereotactic applicator + + + User-defined description for Applicator. + + + Introduces a Sequence of General Accessories associated with this Beam. One or more items may be included in this sequence. + + + Identification Number of the General Accessory. The value shall be unique within the sequence. + + + User or machine supplied identifier for General Accessory. + + + User supplied description of General Accessory. + + + Specifies the type of accessory. +Defined Terms: +GRATICULE = Accessory tray with a radio-opaque grid +IMAGE_DETECTOR = Image acquisition device positioned in the beam line +RETICLE = Accessory tray with radio-transparent markers or grid + + + Machine-readable identifier for this accessory + + + Fraction number for this beam administration. + + + Delivery Type of treatment. +Defined Terms: +TREATMENT = normal patient treatment +OPEN_PORTFILM = portal image acquisition with open field +TRMT_PORTFILM = portal image acquisition with treatment port +CONTINUATION = continuation of interrupted treatment +SETUP = no treatment beam is applied for this RT Beam. To be used for specifying the gantry, couch, and other machine positions where X-Ray set-up images or measurements are to be taken + + + Conditions under which treatment was terminated. +Enumerated Values: +NORMAL = treatment terminated normally +OPERATOR = operator terminated treatment +MACHINE = machine terminated treatment +UNKNOWN = status at termination unknown + + + Treatment machine termination code. This code is dependent upon the particular application and equipment. + + + Conditions under which treatment was verified by a verification system. +Enumerated Values: +VERIFIED = treatment verified +VERIFIED_OVR = treatment verified with at least one out-of-range value overridden +NOT_VERIFIED = treatment verified manually + + + Desired machine setting of primary meterset. + + + Desired machine setting of secondary meterset. + + + Machine setting actually delivered as recorded by primary meterset. + + + Machine setting actually delivered as recorded by secondary meterset. + + + Treatment Time set (sec). + + + Treatment Time actually delivered (sec). + + + Number of control points delivered. + + + Introduces sequence of beam control points for current treatment beam. The sequence may contain one or more items. See C.8.8.21.1. +
All treatment machine delivery parameters (including table angles and positions) in the RT Treatment Session Record Module shall be specified as absolute, not relative, values at the Control Point. +
+
+ + Uniquely identifies Control Point specified by Control Point Index (300A,0112) within Beam referenced by Referenced Beam Number (300C,0006). + + + Date administration of treatment beam began. + + + Time administration of treatment beam began. + + + Desired machine setting for current control point. See C.8.8.21.2. +
Specified Meterset (3008,0042) contains the MU as specified in the corresponding RT Plan at a given control point. +Delivered Meterset (3008,0044) shall contain one of the following three values: +
+
+ + Machine setting actually delivered at current control point. See C.8.8.21.2. +
Specified Meterset (3008,0042) contains the MU as specified in the corresponding RT Plan at a given control point. +Delivered Meterset (3008,0044) shall contain one of the following three values: +
+
+ + Dose Rate set on treatment machine for segment beginning at current control point (meterset/min). + + + Dose Rate actually delivered for segment beginning at current control point (meterset/min). + + + Nominal Beam Energy at control point. + + + Units used for Nominal Beam Energy (300A,0114). Required if Nominal Beam Energy (300A,0114) is sent. +Defined Terms: +MV = Megavolt +MEV = Mega electron-Volt +If Radiation Type (300A,00C6) is PHOTON, Nominal Beam Energy Unit (300A,0015) shall be MV. If Radiation Type (300A,00C6) is ELECTRON, Nominal Beam Energy Unit (300A,0015) shall be MEV. + + + Introduces sequence of Wedge positions for current control point. The sequence may contain one or more items. + + + Uniquely identifies wedge specified by Wedge Number (300A,00D2) within Beam referenced by Referenced Beam Number (300C,0006). Required if Wedge Position Sequence (300A,0116) is sent. + + + Position of Wedge at current control point. Required if Wedge Position Sequence (300A,0116) is sent. +Enumerated Values: IN, OUT. + + + Introduces sequence of beam limiting device (collimator) jaw or leaf (element) positions. Required for Control Point 0 of Control Point Delivery Sequence (3008,0040) or if beam limiting device (collimator) changes during beam administration. The sequence may contain one or more items. + + + Type of beam limiting device. The value of this attribute shall correspond to RT Beam Limiting Device Type (300A,00B8) defined in an element of Beam Limiting Device Leaf Pairs Sequence (3008,00A0). Required if Beam Limiting Device Position Sequence (300A,011A) is sent. +Enumerated Values: +X = symmetric jaw pair in IEC X direction +Y = symmetric jaw pair in IEC Y direction +ASYMX = asymmetric jaw pair in IEC X direction +ASYMY = asymmetric pair in IEC Y direction +MLCX = multileaf (multi-element) jaw pair in IEC X direction +MLCY = multileaf (multi-element) jaw pair in IEC Y direction + + + Positions of beam limiting device (collimator) leaf (element) or jaw pairs (mm) in IEC BEAM LIMITING DEVICE coordinate axis appropriate to RT Beam Limiting Device Type (300A,00B8), e.g. X-axis for MLCX, Y-axis for MLCY. Contains 2N values, where N is the Number of Leaf/Jaw Pairs (300A,00BC) defined in element of Beam Limiting Device Leaf Pairs Sequence (3008,00A0). Values shall be in IEC leaf subscript order 101, 102, … 1N, 201, 202 … 2N. Required if Beam Limiting Device Position Sequence (300A,011A) is sent. + + + Treatment machine gantry angle, i.e. orientation of IEC GANTRY coordinate system with respect to IEC FIXED REFERENCE coordinate system (degrees). Required for Control Point 0 of Control Point Delivery Sequence (3008,0040) or if Gantry Angle changes during beam administration. + + + Direction of Gantry Rotation when viewing gantry from isocenter, for segment beginning at current Control Point. Required for Control Point 0 of Control Point Delivery Sequence (3008,0040), or if Gantry Rotation Direction changes during beam administration. +Enumerated Values: +CW = clockwise +CC = counter-clockwise +NONE = no rotation + + + Gantry Pitch Angle. i.e. the rotation of the IEC GANTRY coordinate system about the X-axis of the IEC GANTRY coordinate system (degrees). If used, must be present for first item of Control Point Sequence, or if used and Gantry Pitch Rotation Angle changes during Beam, must be present. See C.8.8.25.6.5. +
The Gantry Pitch angle is not defined in IEC 61217. This angle is defined in the DICOM standard in a way compatible with the current notion of IEC by introducing it as rotation of the IEC GANTRY System as indicated below. +The Gantry Pitch Angle is defined as the rotation of the coordinate axes Yg, Zg about axis Xg by an angle ï¹g; see Figure C.8.8.25-7. An increase in the value of angle ï¹g corresponds to the clockwise rotation as viewed from the isocenter along the positive Xg axis + + +Figure C.8.8.25-7 Gantry Pitch Angle +
+
+ + Direction of Gantry Pitch Angle when viewing along the positive X-axis of the IEC GANTRY coordinate system, for segment following Control Point. If used, must be present for first item of Control Point Sequence, or if used and Gantry Pitch Rotation Direction changes during Beam, must be present. See C.8.8.14.8 and C.8.8.25.6.5. +Enumerated Values: +CW = clockwise +CC = counter-clockwise +NONE = no rotation +
For the machine rotation angles Gantry Angle (300A,011E), Beam Limiting Device Angle (300A,0120), Patient Support Angle (300A,0122) , and Table Top Eccentric Angle (300A,0125), rotation direction is specified as clockwise (CW), counter-clockwise (CC), or NONE. The maximum permitted rotation between two Control Points is 360 degrees. Examples: +a) Gantry Angle moves from 5 degrees to 5 degrees, Gantry Rotation Direction = NONE: + No movement. + +b) Gantry Angle moves from 5 degrees to 5 degrees, Gantry Rotation Direction = CW: + Full clockwise rotation (360 degrees). + +c) Table Angle moves from 170 degrees to 160 degrees, Table Rotation Direction = CC: + Counter-clockwise rotation by 350 degrees (note direction of increasing table angle as defined by IEC 61217). + +
+
+ + Position of Beam Stopper during beam administration. +Enumerated Values: +EXTENDED = Beam Stopper extended +RETRACTED = Beam Stopper retracted +UNKNOWN = Position unknown + + + Beam Limiting Device (collimator) angle, i.e. orientation of IEC BEAM LIMITING DEVICE coordinate system with respect to IEC GANTRY coordinate system (degrees). Required for Control Point 0 of Control Point Delivery Sequence (3008,0040) or if beam limiting device (collimator) angle changes during beam delivery. + + + Direction of Beam Limiting Device Rotation when viewing beam limiting device (collimator) from radiation source, for segment beginning at current Control Point. Required for Control Point 0 of Control Point Delivery Sequence (3008,0040) or if Beam Limiting Device Rotation Direction changes during beam administration. +Enumerated Values: +CW = clockwise +CC = counter-clockwise +NONE = no rotation + + + Patient Support angle, i.e. orientation of IEC PATIENT SUPPORT (turntable) coordinate system with respect to IEC FIXED REFERENCE coordinate system (degrees). Required for Control Point 0 of Control Point Delivery Sequence (3008,0040) or if Patient Support Angle changes during beam administration. + + + Direction of Patient Support Rotation when viewing table from above, for segment beginning at current Control Point. Required for Control Point 0 of Control Point Delivery Sequence (3008,0040), or if Patient Support Rotation Direction changes during beam administration. +Enumerated Values: +CW = clockwise +CC = counter-clockwise +NONE = no rotation + + + Distance (positive) from the IEC PATIENT SUPPORT vertical axis to the IEC TABLE TOP ECCENTRIC vertical axis (mm). + + + Table Top (non-isocentric) angle, i.e. orientation of IEC TABLE TOP ECCENTRIC coordinate system with respect to IEC PATIENT SUPPORT coordinate system (degrees). Required for Control Point 0 of Control Point Delivery Sequence (3008,0040) or if Table Top Eccentric Angle changes during beam administration. + + + Direction of Table Top Eccentric Rotation when viewing table from above, for segment beginning at current Control Point. Required for Control Point 0 of Control Point Delivery Sequence (3008,0040) or if Table Top Eccentric Rotation Direction changes during beam administration. +Enumerated Values: +CW = clockwise +CC = counter-clockwise +NONE = no rotation + + + Table Top Pitch Angle, i.e. the rotation of the IEC TABLE TOP coordinate system about the X-axis of the IEC TABLE TOP coordinate system (degrees). If required by treatment delivery device, shall be present for first item of Control Point Sequence. If required by treatment delivery device and if Table Top Pitch Angle changes during Beam, shall be present in all subsequent items of Control Point Sequence. See C.8.8.25.6.2. +
Pitch and Roll Coordinate Systems of the Table Top are not defined in IEC 61217. These angles are defined in the DICOM standard in a way compatible with the current notion of IEC by introducing them as rotations of the IEC Table Top System as indicated below. +The Table Top Pitch Angle is defined as the rotation of the coordinate axes Yt, Zt about axis Xt by an angle ï¹t; see Figure C.8.8.25-3. An increase in the value of angle ï¹t corresponds to the clockwise rotation of the Table Top as viewed from the Table Top coordinate system origin along the positive Xt axis. +The Table Top Roll Angle is defined as the rotation of the coordinate axes Xt, Zt about axis Yt by an angle ïªt; see Figure C.8.8.25-4. An increase in the value of angle ïªt corresponds to the clockwise rotation of the Table Top as viewed from the Table Top coordinate system origin along the positive Yt axis. + + +Figure C.8.8.25-3 Table Top Pitch Angle + +Figure C.8.8.25-4 Table Top Roll Angle + +
+
+ + Direction of Table Top Pitch Rotation when viewing the table along the positive X-axis of the IEC TABLE TOP coordinate system, for segment following Control Point. If required by treatment delivery device, shall be present for first item of Control Point Sequence. If required by treatment delivery device and if Table Top Pitch Rotation Direction changes during Beam, shall be present in all subsequent items of Control Point Sequence. See C.8.8.14.8 and C.8.8.25.6.2. +Enumerated Values: +CW = clockwise +CC = counter-clockwise +NONE = no rotation +
For the machine rotation angles Gantry Angle (300A,011E), Beam Limiting Device Angle (300A,0120), Patient Support Angle (300A,0122) , and Table Top Eccentric Angle (300A,0125), rotation direction is specified as clockwise (CW), counter-clockwise (CC), or NONE. The maximum permitted rotation between two Control Points is 360 degrees. Examples: +a) Gantry Angle moves from 5 degrees to 5 degrees, Gantry Rotation Direction = NONE: + No movement. + +b) Gantry Angle moves from 5 degrees to 5 degrees, Gantry Rotation Direction = CW: + Full clockwise rotation (360 degrees). + +c) Table Angle moves from 170 degrees to 160 degrees, Table Rotation Direction = CC: + Counter-clockwise rotation by 350 degrees (note direction of increasing table angle as defined by IEC 61217). + +
+
+ + Table Top Roll Angle, i.e. the rotation of the IEC TABLE TOP coordinate system about the IEC Y-axis of the IEC TABLE TOP coordinate system (degrees). If required by treatment delivery device, shall be present for first item of Control Point Sequence. If required by treatment delivery device and if Table Top Roll Angle changes during Beam, shall be present in all subsequent items of Control Point Sequence. See C.8.8.25.6.2. +
Pitch and Roll Coordinate Systems of the Table Top are not defined in IEC 61217. These angles are defined in the DICOM standard in a way compatible with the current notion of IEC by introducing them as rotations of the IEC Table Top System as indicated below. +The Table Top Pitch Angle is defined as the rotation of the coordinate axes Yt, Zt about axis Xt by an angle ï¹t; see Figure C.8.8.25-3. An increase in the value of angle ï¹t corresponds to the clockwise rotation of the Table Top as viewed from the Table Top coordinate system origin along the positive Xt axis. +The Table Top Roll Angle is defined as the rotation of the coordinate axes Xt, Zt about axis Yt by an angle ïªt; see Figure C.8.8.25-4. An increase in the value of angle ïªt corresponds to the clockwise rotation of the Table Top as viewed from the Table Top coordinate system origin along the positive Yt axis. + + +Figure C.8.8.25-3 Table Top Pitch Angle + +Figure C.8.8.25-4 Table Top Roll Angle + +
+
+ + Direction of Table Top Roll Rotation when viewing the table along the positive Y-axis of the IEC TABLE TOP coordinate system, for segment following Control Point. If required by treatment delivery device, shall be present for first item of Control Point Sequence. If required by treatment delivery device and if Table Top Roll Rotation Direction changes during Beam, shall be present in all subsequent items of Control Point Sequence. See C.8.8.14.8 and C.8.8.25.6.2. +Enumerated Values: +CW = clockwise +CC = counter-clockwise +NONE = no rotation +
For the machine rotation angles Gantry Angle (300A,011E), Beam Limiting Device Angle (300A,0120), Patient Support Angle (300A,0122) , and Table Top Eccentric Angle (300A,0125), rotation direction is specified as clockwise (CW), counter-clockwise (CC), or NONE. The maximum permitted rotation between two Control Points is 360 degrees. Examples: +a) Gantry Angle moves from 5 degrees to 5 degrees, Gantry Rotation Direction = NONE: + No movement. + +b) Gantry Angle moves from 5 degrees to 5 degrees, Gantry Rotation Direction = CW: + Full clockwise rotation (360 degrees). + +c) Table Angle moves from 170 degrees to 160 degrees, Table Rotation Direction = CC: + Counter-clockwise rotation by 350 degrees (note direction of increasing table angle as defined by IEC 61217). + +
+
+ + Table Top Vertical position in IEC TABLE TOP coordinate system (mm). This value is interpreted as an absolute, rather than relative, Table setting. Required for Control Point 0 of Control Point Delivery Sequence (3008,0040) or if Table Top Vertical Position changes during beam administration. + + + Table Top Longitudinal position in IEC TABLE TOP coordinate system (mm). This value is interpreted as an absolute, rather than relative, Table setting. Required for Control Point 0 of Control Point Delivery Sequence (3008,0040) or if Table Top Longitudinal Position changes during beam administration. + + + Table Top Lateral position in IEC TABLE TOP coordinate system (mm). This value is interpreted as an absolute, rather than relative, Table setting. Required for Control Point 0 of Control Point Delivery Sequence (3008,0040) or if Table Top Lateral Position changes during beam administration. + + + Introduces a sequence of items describing any corrections made to any attributes prior to delivery of the next control point. The sequence may contain one or more items. + + + Contains the Data Element Tag of the parent sequence containing the attribute that was corrected. +The value is limited in scope to the Treatment Session Beam Sequence (3008,0020) and all nested sequences therein. + + + Contains the sequence item index (starting at 1) of the corrected attribute within its parent sequence. + + + Contains the Data Element Tag of the attribute that was corrected. + + + The value applied to the attribute that was referenced by the Parameter Sequence Pointer (3008,0061), Parameter Item Index (3008,0063) and Parameter Pointer (3008,0065). + + + Introduces sequence of parameters that were overridden during the administration of the beam segment immediately prior to the current control point. The sequence may contain one or more items. + + + Contains the Data Element Tag of the attribute that was overridden. Required if Override Sequence (3008,0060) is sent. + + + Contains the Data Element Tag of the parent sequence containing the attribute that was overridden. The value is limited in scope to the Treatment Session Beam Sequence (3008,0020) and all nested sequences therein. + + + Contains the sequence item index (monotonically increasing from 1) of the overridden attributes within its parent sequence. The value is limited in scope to the Treatment Session Beam Sequence (3008,0020) and all nested sequences therein. + + + Name of operator who authorized override. Required if Override Sequence (3008,0060) is sent. + + + User-defined description of reason for override of parameter specified by Override Parameter Pointer (3008,0062). + +
+ + + Name of operator administering treatment session. + + + Identifier of Fraction Group within referenced RT Plan. + + + Total number of treatments (Fractions) planned for current Fraction Group. + + + Type of brachytherapy treatment technique. Enumerated Values: INTRALUMENARY, INTRACAVITARY, INTERSTITIAL, CONTACT, INTRAVASCULAR, PERMANENT. See RT Plan IOD. + + + Type of brachytherapy treatment. +Defined Terms: +MANUAL = manually positioned +HDR = High dose rate +MDR = Medium dose rate +LDR = Low dose rate +PDR = Pulsed dose rate + + + Introduces sequence of Sources to be used within Application Setups. The sequence may contain one or more items. + + + Identification number of the Source. The value of Source Number (300A,0212) shall be unique within the Recorded Source Sequence (3008,0100) in which it is created. + + + Type of Source. Defined Terms: POINT, LINE, CYLINDER, SPHERE. + + + Manufacturer of source. + + + Serial Number of source. + + + User-defined name of Isotope. + + + Half-life of Isotope (days). + + + Measurement unit of Source Strength. +Required if the source is not a gamma-emitting (photon) source. May be present otherwise. +Enumerated Values: +AIR_KERMA_RATE = Air Kerma Rate if Source is Gamma emitting Isotope. +DOSE_RATE_WATER = Dose Rate in Water if Source is Beta emitting Isotope. + + + Air Kerma Rate in air of Isotope specified at Air Kerma Rate Reference Date (300A,022C) and Air Kerma Rate Reference Time (300A,022E) (in µGy h-1 at 1 m). Value shall be zero for non-gamma sources. + + + Source Strength of Isotope at Source Strength Reference Date (300A,022C) and Source Strength Reference Time (300A,022E), in units specified in Source Strength Units (300A,0229). +Required if the source is not a gamma-emitting (photon) source. See C.8.8.15.13. +
For beta emitting isotopes, the Source Strength (300A,022B) shall be defined at reference point (r0,θ0), where r0 is the radial distance of 2 mm from the source longitudinal axis, and θ0 is the angle of 90 degrees between the source longitudinal axis and the line defined by the center of the source and the reference point. Refer to: +• IEC 60601-2-17 (Medical electrical equipment – Particular requirements for the safety of automatically-controlled brachytherapy afterloading equipment), where the beta source strength is defined as: ABSORBED DOSE RATE [Gy s-1] in water at 2 mm along the perpendicular bisector from a RADIOACTIVE SOURCE emitting beta RADIATION. +• Nath et. al.: Intravascular brachytherapy physics: Report of the AAPM Radiation Therapy Committee Task Group No. 60, Med. Phys 26 (2) Feb 1999, pp 119-152. +
+
+ + Reference date for Reference Air Kerma Rate (300A,022A) or Source Strength (300A,022B) of Isotope. + + + Reference time for Air Kerma Rate (300A,022A) or Source Strength (300A,022B) of Isotope. + + + Introduces sequence of Application Setups for RT Treatment Record for current RT Plan. The sequence may contain one or more items. + + + Type of Application Setup. Defined Terms: FLETCHER_SUIT, DELCLOS, BLOEDORN, JOSLIN_FLYNN, CHANDIGARH, MANCHESTER, HENSCHKE, NASOPHARYNGEAL, OESOPHAGEAL, ENDOBRONCHIAL, SYED_NEBLETT, ENDORECTAL, PERINEAL. + + + References application setup specified by Application Setup Number (300A,0234) in Application Setup Sequence (300A,0230) in RT Brachy Applications Module within referenced RT Plan. + + + User-defined name for Application Setup. + + + Manufacturer of Application Setup. + + + Identification number of the Template. + + + User-defined type for Template Device. + + + User-defined name for Template Device. + + + Results of check-wire travel through all channels of current Application Setup. +Enumerated Values: +PASSED = Passed check +FAILED = Failed check +UNKNOWN = Unknown status + + + Introduces sequence of verification images obtained during delivery of current beam. The sequence may contain one or more items. See Note. + + + + Total Reference Air Kerma for current Application Setup, i.e. the sum of the products of the Air Kerma Rates of each Source in each Channel with its respective Channel Time (µGy at 1 m). Value shall be zero for non-gamma sources. + + + Introduces sequence of doses measured during treatment delivery, summed over entire session. The sequence may contain one or more items. + + + Uniquely references Dose Reference specified by Dose Reference Number (300A,0012) in Dose Reference Sequence (300A,0010) in RT Prescription Module of referenced RT Plan. Required if Referenced Measured Dose Reference Sequence (3008,0080) is sent and Referenced Measured Dose Reference Number (3008,0082) is not sent. It shall not be present otherwise. + + + Uniquely references Measured Dose Reference specified by Measured Dose Reference Number (3008,0064) in Measured Dose Reference Sequence (3008,0010). Required if Referenced Measured Dose Reference Sequence (3008,0080) is sent and Referenced Dose Reference Number (300C,0051) is not sent. It shall not be present otherwise. + + + Measured Dose in units specified by Dose Units (3004,0002) in sequence referenced by Measured Dose Reference Sequence (3008,0010) or Dose Reference Sequence (300A,0010) in RT Prescription Module of referenced RT Plan as defined above. Required if Referenced Measured Dose Reference Sequence (3008,0080) is sent. + + + Introduces sequence of doses estimated for each treatment delivery. The sequence may contain one or more items. + + + Uniquely identifies Dose Reference specified by Dose Reference Number (300A,0012) in Dose Reference Sequence (300A,0010) in RT Prescription Module of referenced RT Plan. Required if Referenced Calculated Dose Reference Sequence (3008,0090) is sent and Referenced Calculated Dose Reference Number (3008,0092) is not sent. It shall not be present otherwise. + + + Uniquely identifies Calculated Dose Reference specified by Calculated Dose Reference Number (3008,0072) within Calculated Dose Reference Sequence (3008,0070). Required if Referenced Calculated Dose Reference Sequence (3008,0090) is sent and Referenced Dose Reference Number (300C,0051) is not sent. It shall not be present otherwise. + + + Calculated Dose (Gy). Required if Referenced Calculated Dose Reference Sequence (3008,0090) is sent. + + + Fraction number for this application setup. + + + Delivery Type of treatment. +Defined Terms: +TREATMENT = normal patient treatment +CONTINUATION = continuation of interrupted treatment + + + Conditions under which treatment was terminated. +Enumerated Values: +NORMAL = treatment terminated normally +OPERATOR = operator terminated treatment +MACHINE = machine terminated treatment for other than NORMAL condition +UNKNOWN = status at termination unknown + + + Treatment machine termination code. This code is dependent upon the particular application and equipment. + + + Conditions under which treatment was verified by a verification system. +Enumerated Values: +VERIFIED = treatment verified +VERIFIED_OVR = treatment verified with at least one out-of-range value overridden +NOT_VERIFIED = treatment verified manually + + + Introduces sequence of Brachy Accessory Devices associated with current Application Setup. The sequence may contain one or more items. + + + Identification number of the Brachy Accessory Device. The value of Brachy Accessory Device Number (300A,0262) shall be unique within the Application Setup in which it is created. Required if Recorded Brachy Accessory Device Sequence (3008,0120) is sent. + + + User or machine supplied identifier for Brachy Accessory Device. Required if Recorded Brachy Accessory Device Sequence (3008,0120) is sent. + + + Type of Brachy Accessory Device. Required if Recorded Brachy Accessory Device Sequence (3008,0120) is sent. Defined Terms: SHIELD, DILATATION, MOLD, PLAQUE, FLAB. + + + User-defined name for Brachy Accessory Device. + + + Introduces sequence of Channels for current Application Setup. The sequence may contain one or more items. + + + Identification number of the Channel. The value of Channel Number (300A,0282) shall be unique within the Application Setup in which it is created. + + + Length of Channel (mm). See RT Plan IOD. + + + Total amount of time specified between Control Point 0 and final Control Point of the Brachy Control Point Sequence (300A,02D0) for current Channel (sec). + + + Total amount of time actually delivered between Control Point 0 and final Control Point of the Brachy Control Point Sequence (300A,02D0) for current Channel (sec). + + + Type of Source movement. +Defined Terms: STEPWISE, FIXED, OSCILLATING, UNIDIRECTIONAL. + + + Number of Pulses specified per fraction for current Channel. Required if Brachy Treatment Type (300A,0202) is PDR. See C.8.8.22.1. +
In Brachytherapy treatment techniques where Brachy Treatment Type (300A,0202) is PDR, the Brachy Control Point Sequence (300A,02D0) shall consist of 2N items, where N = Delivered Number of Pulses (3008,0138). Each control point pair shall specify the start and end of a single pulse. +
+
+ + Number of Pulses actually delivered per fraction for current Channel. Required if Brachy Treatment Type (300A,0202) is PDR. See C.8.8.22.1. +
In Brachytherapy treatment techniques where Brachy Treatment Type (300A,0202) is PDR, the Brachy Control Point Sequence (300A,02D0) shall consist of 2N items, where N = Delivered Number of Pulses (3008,0138). Each control point pair shall specify the start and end of a single pulse. +
+
+ + Pulse repetition interval (sec) specified for current Channel. Required if Brachy Treatment Type (300A,0202) is PDR. See C.8.8.22.1 +
In Brachytherapy treatment techniques where Brachy Treatment Type (300A,0202) is PDR, the Brachy Control Point Sequence (300A,02D0) shall consist of 2N items, where N = Delivered Number of Pulses (3008,0138). Each control point pair shall specify the start and end of a single pulse. +
+
+ + Pulse repetition interval (sec) actually delivered for current Channel. Required if Brachy Treatment Type (300A,0202) is PDR. See C.8.8.22.1. +
In Brachytherapy treatment techniques where Brachy Treatment Type (300A,0202) is PDR, the Brachy Control Point Sequence (300A,02D0) shall consist of 2N items, where N = Delivered Number of Pulses (3008,0138). Each control point pair shall specify the start and end of a single pulse. +
+
+ + Introduces sequence of doses measured during treatment delivery, summed over entire session. The sequence may contain one or more items. + + + Uniquely references Dose Reference specified by Dose Reference Number (300A,0012) in Dose Reference Sequence (300A,0010) in RT Prescription Module of referenced RT Plan. Required if Referenced Measured Dose Reference Sequence (3008,0080) is sent and Referenced Measured Dose Reference Number (3008,0082) is not sent. It shall not be present otherwise. + + + References Measured Dose Reference specified by Measured Dose Reference Number (3008,0064) in Measured Dose Reference Sequence (3008,0010). Required if Referenced Measured Dose Reference Sequence (3008,0080) is sent and Referenced Dose Reference Number (300C,0051) is not sent. It shall not be present otherwise. + + + Measured Dose. Required if Referenced Measured Dose Reference Sequence (3008,0080) is sent. + + + Introduces sequence of doses estimated for each treatment delivery. The sequence may contain one or more items. + + + Uniquely identifies Dose Reference specified by Dose Reference Number (300A,0012) in Dose Reference Sequence (300A,0010) in RT Prescription Module of referenced RT Plan. Required if Referenced Calculated Dose Reference Sequence (3008,0090) is sent and Referenced Calculated Dose Reference Number (3008,0092) is not sent. It shall not be present otherwise. + + + Uniquely identifies Calculated Dose Reference specified by Calculated Dose Reference Number (3008,0072) within Calculated Dose Reference Sequence (3008,0070). Required if Referenced Calculated Dose Reference Sequence (3008,0090) is sent and Referenced Dose Reference Number (300C,0051) is not sent. It shall not be present otherwise. + + + Calculated Dose (Gy). Required if Referenced Calculated Dose Reference Sequence (3008,0090) is sent. + + + Introduces sequence of recorded Source Applicators. The sequence may contain one or more items. + + + Identification number of the Source Applicator. The value of Source Applicator Number (300A,0290) shall be unique within the Channel in which it is created. + + + User or machine supplied identifier for Source Applicator. Required if Recorded Source Applicator Sequence (3008,0140) is sent. + + + Type of Source Applicator. Required if Recorded Source Applicator Sequence (3008,0140) is sent. +Enumerated Values: FLEXIBLE, RIGID. + + + User-defined name for Source Applicator. + + + Length of Source Applicator (mm), defined as the distance between the connector of the applicator and the distal-most position of the source. Required if Recorded Source Applicator Sequence (3008,0140) is sent. + + + Manufacturer of Source Applicator. + + + Distance of path along channel (mm) between adjacent (potential) dwell positions. Required if Source Movement Type (300A,0288) is STEPWISE. + + + Identification number of the Transfer Tube. The value of Transfer Tube Number (300A,02A2) shall be unique within the Channel in which it is created. + + + Length of Transfer Tube of current afterloading Channel (mm). Required if value Transfer Tube Number (300A,02A2) is not zero length. + + + Introduces sequence of Channel Shields associated with current Channel. The sequence may contain one or more items. See RT Plan IOD for description of Channel Shields. + + + Identification number of the Channel Shield. The value of Channel Shield Number (300A,02B2) shall be unique within the Channel in which it is created. Required if Recorded Channel Shield Sequence (3008,0150) is sent. + + + User or machine supplied identifier for Channel Shield. Required if Recorded Channel Shield Sequence (3008,0150) is sent. + + + User-defined name for Channel Shield. + + + Uniquely identifies the referenced Source within the Recorded Source Sequence (3008,0100) for current Application Setup. + + + Date on which the source(s) exited the safe. Required if Recorded Channel Sequence (3008,0130) is sent and Brachy Treatment Type (300A,0202) is not MANUAL. + + + Time on which the source(s) exited the safe. Required if Recorded Channel Sequence (3008,0130) is sent and Brachy Treatment Type (300A,0202) is not MANUAL. + + + Date on which the source(s) returned to the safe. Required if Recorded Channel Sequence (3008,0130) is sent and Brachy Treatment Type (300A,0202) is not MANUAL. + + + Time on which the source(s) returned to the safe. Required if Recorded Channel Sequence (3008,0130) is sent and Brachy Treatment Type (300A,0202) is not MANUAL. + + + Number of control points in Channel. For an N-segment Channel there will be 2N (stepwise movement) or N+1 (continuous movement) control points. + + + Introduces sequence of machine configurations describing this Channel. The sequence may contain two or more items. See RT Plan IOD and C.8.8.22.1 for description of Brachy Control Point Delivered Sequence. + + + Index of current Control Point, starting at 0 for first Control Point. + + + Date when current Control Point occurred. + + + Time when current Control Point occurred. + + + Distance between current Control Point Position and the distal-most possible Source position in current Channel (mm). See RT Plan IOD. + + + Introduces sequence of parameters which were overridden during the administration of the treatment immediately prior to the current control point. The sequence may contain one or more items. + + + Contains the Data Element Tag of the attribute which was overridden. Required if Override Sequence (3008,0060) is sent. + + + Name of operator who authorized override. Required if Override Sequence (3008,0060) is sent. + + + User-defined description of reason for override of parameter specified by Override Parameter Pointer (3008,0062). + +
+ + + Status of the Treatment at the time the Treatment Summary was created. Enumerated Values: +NOT_STARTED, ON_TREATMENT, ON_BREAK, SUSPENDED, STOPPED, COMPLETED. See C.8.8.23.1. +
The definition of the enumerated values for Current Treatment Status (3008,0200) are defined as follows: +NOT_STARTED Patient has not yet begun treatment. +ON_TREATMENT Patient is currently undergoing treatment. +ON_BREAK Patient is currently not undergoing treatment, but a resumption date is known. +SUSPENDED Patient is currently not undergoing treatment, but resumption of treatment is planned at an unknown date. +STOPPED Patient has stopped treatment without completing the planned course. +COMPLETED Patient completed the planned course of treatment. +A change in the Current Treatment Status (or any other field) in a RT Treatment Summary Record Object shall define a new instance of the RT Treatment Summary Record IOD. +
+
+ + Comment on current treatment status. + + + Date of delivery of the first treatment. + + + Date of delivery of the most recent administration. + + + Introduces sequence describing current state of planned vs. delivered fraction groups. The sequence may contain one or more items. + + + References Fraction Group Number (300A,0071) in Fraction Group Sequence (300A,0070) in the referenced RT Plan. + + + Indicates type of fraction group. Required if Fraction Group Summary Sequence (3008,0220) is sent. Enumerated Values: EXTERNAL_BEAM, BRACHY. + + + Number of fractions planned for this fraction group. Required if Fraction Group Summary Sequence (3008,0220) is sent. + + + Number of fractions delivered as of Treatment Summary Report. Required if Fraction Group Summary Sequence (3008,0220) is sent. + + + Introduces sequence describing status of fractions in Fraction Group. The sequence may contain one or more items. + + + Identifies fraction. Required if Fraction Status Summary Sequence (3008,0240) is sent. + + + Date when fraction was delivered. Required if Fraction Status Summary Sequence (3008,0240) is sent. + + + Time when fraction was delivered. Required if Fraction Status Summary Sequence (3008,0240) is sent. + + + Conditions under which treatment was terminated. Required if Fraction Status Summary Sequence (3008,0240) is sent. +Enumerated Values: +NORMAL = treatment terminated normally +OPERATOR = operator terminated treatment +MACHINE = machine terminated treatment for other than NORMAL condition +UNKNOWN = status at termination unknown + + + Introduces sequence of references to Measured Dose References. The sequence may contain one or more items. + + + Uniquely identifies Dose Reference specified by Dose Reference Number (300A,0012) in Dose Reference Sequence (300A,0010) in RT Prescription Module of referenced RT Plan referenced in Referenced RT Plan Sequence (300C,0002) of RT General Treatment Record Module. + + + User-defined description of Dose Reference. + + + Cumulative Dose delivered to Dose Reference (Gy). Required if Treatment Summary Dose Reference Sequence (3008,00E0) is sent. + + + Introduces sequence of references to Calculated Dose References. The sequence may contain one or more items. + + + Uniquely identifies Dose Reference specified by Dose Reference Number (300A,0012) in Dose Reference Sequence (300A,0010) in RT Prescription Module of referenced RT Plan referenced in Referenced RT Plan Sequence (300C,0002) of RT General Treatment Record Module. + + + User-defined description of Dose Reference. + + + Cumulative Dose delivered to Dose Reference (Gy). Required if Treatment Summary Dose Reference Sequence (3008,0050) is sent. + +
+ + + Introduces sequence of ion tolerance tables to be used for delivery of treatment plan. One or more items shall be included in this sequence. See Note 1. + + + Identification number of the Tolerance Table. The value of Tolerance Table Number (300A,0042) shall be unique within the RT Ion Plan in which it is created. + + + User-defined label for Tolerance Table. + + + Maximum permitted difference (in degrees) between planned and delivered Gantry Angle. + + + Maximum permitted difference (in degrees) between planned and delivered Beam Limiting Device Angle. + + + Introduces sequence of beam limiting device (collimator) tolerances. One or more items may be included in this sequence. + + + Type of beam limiting device (collimator). +Enumerated Values: +X = symmetric jaw pair in IEC X direction +Y = symmetric jaw pair in IEC Y direction +ASYMX = asymmetric jaw pair in IEC X +direction +ASYMY = asymmetric pair in IEC Y +direction +MLCX = multileaf (multi-element) jaw pair +in IEC X direction +MLCY = multileaf (multi-element) jaw pair +in IEC Y direction + + + Maximum permitted difference (in mm) between planned and delivered leaf (element) or jaw positions for current beam limiting device (collimator). + + + Maximum permitted difference (in degrees) between planned and delivered Patient Support Angle. + + + Maximum permitted difference (in mm) between planned and delivered Table Top Vertical Position. + + + Maximum permitted difference (in mm) between planned and delivered Table Top Longitudinal Position. + + + Maximum permitted difference (in mm) between planned and delivered Table Top Lateral Position. + + + Maximum permitted difference (in degrees) between planned and delivered Table Top Pitch Angle. + + + Maximum permitted difference (in degrees) between planned and delivered Table Top Roll Angle. + + + Maximum permitted difference (in mm) between planned and delivered Snout Position. + + + + + Introduces sequence of setup and/or treatment beams for current RT Ion Plan. One or more items shall be included in this sequence. + + + Identification number of the Beam. The value of Beam Number (300A,00C0) shall be unique within the RT Ion Plan in which it is created. See section C.8.8.25.1. + + + User-defined name for Beam. See section C.8.8.25.1. + + + User-defined description for Beam. See section C.8.8.25.1. + + + Motion characteristic of Beam. +Enumerated Values: +STATIC = all beam parameters remain unchanged during delivery +DYNAMIC = one or more beam parameters changes during delivery + + + Particle type of Beam. +Defined Terms: +PHOTON +PROTON +ION + + + Mass number of radiation. Required if Radiation Type (300A,00C6) is ION + + + Atomic number of radiation. Required if Radiation Type (300A,00C6) is ION + + + Charge state of radiation. Required if Radiation Type (300A,00C6) is ION + + + The method of beam scanning to be used during treatment. +Defined Terms: +NONE = No beam scanning is performed. +UNIFORM = The beam is scanned between control points to create a uniform lateral fluence distribution across the field. +MODULATED = The beam is scanned between control points to create a modulated lateral fluence distribution across the field. + + + User-defined name identifying treatment machine to be used for beam delivery. See section C.8.8.25.2. + + + Manufacturer of the equipment to be used for beam delivery. + + + Institution where the equipment is located that is to be used for beam delivery. + + + Mailing address of the institution where the equipment is located that is to be used for beam delivery. + + + Department in the institution where the equipment is located that is to be used for beam delivery. + + + Manufacturer's model name of the equipment that is to be used for beam delivery. + + + Manufacturer's serial number of the equipment that is to be used for beam delivery. + + + Measurement unit of machine dosimeter. +Enumerated Values: +MU = Monitor Unit +NP = number of particles + + + Uniquely identifies Tolerance Table specified by Tolerance Table Number (300A,0042) within Tolerance Table Sequence in RT Ion Tolerance Tables Module. These tolerances are to be used for verification of treatment machine settings. + + + Distance (in mm) from virtual source position to gantry rotation axis or nominal isocenter position (fixed beam-lines) of the equipment to be used for beam delivery. Specified by a numeric pair - the VSAD in the IEC Gantry X direction followed by the VSAD in the IEC Gantry Y direction. +The VSAD is commonly used for designing apertures in contrast to the effective source-axis-distance (ESAD) that is commonly used with the inverse square law for calculating the dose decrease with distance. See section C.8.8.25.4. + + + Introduces sequence of beam limiting device (collimator) jaw or leaf (element) sets. One or more items may be included in this sequence. + + + Type of beam limiting device (collimator). +Enumerated Values: +X = symmetric jaw pair in IEC X direction +Y = symmetric jaw pair in IEC Y direction +ASYMX = asymmetric jaw pair in IEC X direction +ASYMY = asymmetric pair in IEC Y direction +MLCX = multileaf (multi-element) jaw pair in IEC X direction +MLCY = multileaf (multi-element) jaw pair in IEC Y direction + + + Isocenter to beam limiting device (collimator) distance (in mm) of the equipment that is to be used for beam delivery. +See section C.8.8.25.4. + + + Number of leaf (element) or jaw pairs (equal to 1 for standard beam limiting device jaws). + + + Boundaries of beam limiting device (collimator) leaves (in mm) in IEC BEAM LIMITING DEVICE coordinate axis appropriate to RT Beam Limiting Device Type (300A,00B8), i.e. X-axis for MLCY, Y-axis for MLCX. +Contains N+1 values, where N is the Number of Leaf/Jaw Pairs (300A,00BC), starting from Leaf (Element) Pair 1. Required if RT Beam Limiting Device Type (300A,00B8) is MLCX or MLCY. See section C.8.8.25.3. + + + Uniquely identifies Patient Setup to be used for current beam, specified by Patient Setup Number (300A,0182) within Patient Setup Sequence of RT Patient Setup Module. + + + Introduces sequence of reference images used for validation of current beam. One or more items may be included in this sequence. + + + + Uniquely identifies Reference Image within Referenced Reference Image Sequence (300C,0042). + + + Delivery Type of treatment. +Defined Terms: +TREATMENT = normal patient treatment +OPEN_PORTFILM = portal image acquisition with open field (the source of radiation is specified by Radiation Type (300A,00C6)) +TRMT_PORTFILM = portal image acquisition with treatment port (the source of radiation is specified by Radiation Type (300A,00C6)) +CONTINUATION = continuation of interrupted treatment +SETUP = no treatment beam is applied for this RT Beam. To be used for specifying the gantry, couch, and other machine positions where X-Ray set-up images or measurements shall be taken. + + + Introduces sequence of related SOP Class/Instance pairs describing related instances of RT Dose (for grids, isodose curves, and named/unnamed point doses). One or more items may be included in this sequence. + + + + Number of wedges associated with current beam. + + + Shift of the wedge tray induced on the range of the ion beam as measured in water (in mm). + + + Introduces sequence of treatment wedges. Required if Number of Wedges (300A,00D0) is non-zero. The number of items shall be identical to the value of Number of Wedges (300A,00D0). + + + Identification number of the Wedges. The value of Wedge Number (300A,00D2) shall be unique within the Beam in which it was created. + + + Typer of wedge (if any) defined for Beam. + +Defined Terms: +STANDARD = standard (static) wedge +MOTORIZED = single wedge that can be removed from beam remotely. +PARTIAL_STANDARD = wedge does not extend across the whole field and is operated manually. +PARTIAL_MOTORIZ = wedge does not extend across the whole field and can be removed from beam remotely. + + + User-supplied identifier for Wedge. + + + An accessory identifier to be read by a device such as a bar code reader. + + + Nominal wedge angle (degrees). + + + Orientation of wedge, i.e. orientation of IEC WEDGE FILTER coordinate system with respect to the IEC BEAM LIMITING DEVICE coordinate systems (degrees). + + + Isocenter to downstream edge of wedge tray (mm). +See section C.8.8.25.4 + + + Number of compensators associated with current Beam. + + + Water-Equivalent thickness of the compensator tray (in mm) parallel to radiation beam axis. + + + Introduces sequence of compensators. Required if Number of Compensators (300A,00E0) is non-zero. The number of items shall be identical to the value of Number of Compensators (300A,00E0). + + + User defined description for the compensator. + + + Identification number of the Compensator. The value of Compensator Number (300A,00E4) shall be unique within the Beam in which it is created. + + + User-supplied identifier for material used to manufacture Compensator. + + + User-supplied identifier for the compensator. + + + An accessory identifier to be read by a device such as a bar code reader. + + + Isocenter to compensator tray attachment edge distance (in mm) for current range compensator. Required if Compensator Mounting Position (300A,02E1) is not DOUBLE_SIDED. See section C.8.8.25.4 + + + Indicates presence or absence of geometrical divergence of the range compensator. +Enumerated Values: +PRESENT = the range compensator is shaped according to the beam geometrical divergence. +ABSENT = the range compensator is not shaped according to the beam geometrical divergence. + + + Indicates on which side of the Compensator Tray the compensator is mounted. +Enumerated Values: +PATIENT_SIDE = the Compensator is mounted on the side of the Compensator Tray that is towards the patient. +SOURCE_SIDE = the Compensator is mounted on the side of the Compensator Tray that is towards the radiation source. +DOUBLE_SIDED = the Compensator has a shaped (i.e. non-flat) surface on both sides of the Compensator Tray. + + + Number of rows in the range compensator. A row is defined to be in the X direction of the IEC Beam Limiting Device Coordinate system. + + + Number of columns in the range compensator. A column is defined to be in the Y direction of the IEC Beam Limiting Device Coordinate system. + + + Physical distance (in mm) between the center of each pixel projected onto machine isocentric plane. Specified by a numeric pair - adjacent row spacing followed by adjacent column spacing. See 10.7.1.3 for further explanation of the value order. + + + The x and y coordinates of the upper left hand corner (first pixel transmitted) of the range compensator, projected onto the machine isocentric plane in the IEC BEAM LIMITING DEVICE coordinate system (mm). + + + The offset distance (in mm) applied to the x coordinate of the Compensator Position (300A,00EA) for even numbered rows. Required if the compensator pattern is hexogonal. + + + A data stream of the pixel samples that comprise the range compensator, expressed as physical thickness (in mm), either parallel to radiation beam axis if Compensator Divergence (300A,02E0) equals ABSENT, or divergent according to the beam geometrical divergence if Compensator Divergence (300A,02E0) equals PRESENT. The order of pixels sent is left to right, top to bottom (upper left pixel, followed by the remainder of row 1, followed by the remainder of the rows). + + + A data stream of the pixel samples that comprise the distance from the isocenter to the compensator surface closest to the radiation source (in mm). The order of pixels sent is left to right, top to bottom (upper left pixel, followed by the remainder of row 1, followed by the remainder of the rows). Required if Material ID (300A,00E1) is non-zero length, and Compensator Mounting Position (300A,02E1) is DOUBLE_SIDED. See sections C.8.8.14.9 and C.8.8.25.4 + + + Compensator Linear Stopping Power Ratio, relative to water, at the beam energy specified by the Nominal Beam Energy (300A,0114) of the first Control Point of the Ion Control Point Sequence (300A,03A8). + + + The diameter (in mm) of the milling tool to be used to create the compensator. The diameter is expressed as the actual physcial size and not a projected size at isocenter. + + + Number of boli associated with current Beam. + + + Introduces sequence of boli associated with Beam. Required if Number of Boli (300A,00ED) is non-zero. The number of items shall be identical to the value of Number of Boli (300A,00ED). + + + Uniquely identifies ROI representing the Bolus specified by ROI Number (3006,0022) in Structure Set ROI Sequence (3006,0020) in Structure Set Module within RT Structure Set in Referenced Structure Set Sequence (300C,0060) in RT General Plan Module. + + + An accessory identifier to be read by a device such as a bar code reader. + + + Number of shielding blocks associated with Beam. + + + Water-Equivalent thickness of the block tray (in mm) parallel to radiation beam axis. + + + Introduces sequence of blocks associated with Beam. Required if Number of Blocks (300A,00F0) is non-zero. The number of items shall be identical to the value of Number of Blocks (300A,00F0). + + + User-supplied identifier for block tray. + + + An accessory identifier to be read by a device such as a bar code reader. + + + Isocenter to downstream edge of block tray (mm). See section C.8.8.25.4 + + + Type of block. See section C.8.8.14.4. +Enumerated Values: +SHIELDING = blocking material is inside contour +APERTURE = blocking material is outside contour + + + Indicates presence or otherwise of geometrical divergence. +Enumerated Values: +PRESENT = block edges are shaped for beam divergence +ABSENT = block edges are not shaped for beam divergence + + + Indicates on which side of the Block Tray the block is mounted. +Enumerated Values; +PATIENT_SIDE = the block is mounted on the side of the Block Tray that is towards the patient. +SOURCE_SIDE = the block is mounted on the side of the Block Tray that is towards the radiation source. + + + Identification number of the Block. The value of Block Number (300A,00FC) shall be unique within the Beam in which it is created. + + + User-defined name for block. + + + User-supplied identifier for material used to manufacture Block. + + + Physical thickness of block (in mm) parallel to radiation beam axis. See section C.8.8.14.4. + + + Number of (x,y) pairs defining the block edge. + + + A data stream of (x,y) pairs that comprise the block edge. The number of pairs shall be equal to Block Number of Points (300A,0104), and the vertices shall be interpreted as a closed polygon. Coordinates are projected onto the machine isocentric plane in the IEC BEAM LIMITING DEVICE coordinate system (mm). + + + Introduces sequence of Snouts associated with Beam. Only a single item shall be permitted in this sequence. + + + User or machine supplied identifier for Snout. + + + An accessory identifier to be read by a device such as a bar code reader. + + + Introduces sequence of Applicators associated with Beam. Only a single item shall be permitted in this sequence. + + + User or machine supplied identifier for Applicator. See section C.8.8.14.12 + + + An accessory identifier to be read by a device such as a bar code reader. + + + Type of applicator. + +Defined Terms: +ION_SQUARE = square ion applicator +ION_RECT = rectangluar ion applicator +ION_CIRC = circular ion applicator +ION_SHORT = short ion applicator +ION_OPEN = open (dummy) ion applicator +INTEROPERATIVE = interoperative (custom) applicator +STEREOTACTIC = stereotactic applicator + + + User-defined description for Applicator. + + + Introduces a Sequence of General Accessories associated with this Beam. One or more items may be included in this sequence. + + + Identification Number of the General Accessory. The value shall be unique within the sequence. + + + User or machine supplied identifier for General Accessory. + + + User supplied description of General Accessory. + + + Specifies the type of accessory. +Defined Terms: +GRATICULE = Accessory tray with a radio-opaque grid +IMAGE_DETECTOR = Image acquisition device positioned in the beam line +RETICLE = Accessory tray with radio-transparent markers or grid + + + Machine-readable identifier for this accessory + + + Number of range shifters associated with current beam. + + + Introduces sequence of range shifters associated with Beam. Required if Number of Range Shifters (300A,0312) is non-zero. The number of items shall be identical to the value of Number of Range Shifters (300A,0312). + + + Identification number of the Range Shifter. The value of Range Shifter Number (300A,0316) shall be unique within the Beam in which it is created. + + + User or machine supplied identifier for Range Shifter. + + + An accessory identifier to be read by a device such as a bar code reader. + + + Type of Range Shifter. +Defined Terms: +ANALOG = Device is variable thickness and is composed of opposing sliding wedges, water column or similar mechanism. +BINARY = Device is composed of different thickness materials that can be moved in or out of the beam in various stepped combinations. + + + User defined description of Range Shifter. + + + Number of lateral spreading devices associated with current beam. + + + Introduces sequence of lateral spreading devices associated with Beam. Required if Number of Lateral Spreading Devices (300A,0330) is non-zero. The number of items shall be identical to the value of Number of Lateral Spreading Devices (300A,0330). + + + Identification number of the Lateral Spreading Device. The value of Lateral Spreading Device Number (300A,0334) shall be unique within the Beam in which it is created. + + + User or machine supplied identifier for Lateral Spreading Device. + + + An accessory identifier to be read by a device such as a bar code reader. + + + Type of Lateral Spreading Device. +Defined Terms: +SCATTERER = metal placed into the beam path to scatter charged particles laterally. +MAGNET = nozzle configuration of magnet devices to expand beam laterally. + + + User-defined description for lateral spreading device. + + + Number of range modulators associated with current beam. + + + Introduces sequence of range modulators associated with Beam. Required if Number of Range Modulators (300A,0340) is non-zero. The number of items shall be identical to the value of Number of Range Modulators (300A,0340). + + + Identification number of the Range Modulator. The value of Range Modulator Number (300A,0344) shall be unique within the Beam in which it is created. + + + User or machine supplied identifier for Range Modulator. + + + An accessory identifier to be read by a device such as a bar code reader. + + + Type of Range Modulator. +Defined Terms: +FIXED = fixed modulation width and weights using ridge filter or constant speed wheel with constant beam current +WHL_FIXEDWEIGHTS = selected wheel/track (Range Modulator ID) is spinning at constant speed. Modulation width is adjusted by switching constant beam current on and off at wheel steps indicated by Range Modulator Gating Values. +WHL_MODWEIGHTS = selected wheel/track (Range Modulator ID) is spinning at constant speed. Weight per wheel step is adjusted by modulating beam current according to selected Beam Current Modulation ID (300A,034C). +Only one item in the Range Modulator Sequence (300A,0342) can have a Range Modulator Type (300A,0348) of WHL_MODWEIGHTS. + + + User-defined description of Range Modulator. + + + User-supplied identifier for the beam current modulation pattern. Required if Range Modulator Type (300A,0348) is WHL_MODWEIGHTS + + + + Azimuthal angle (degrees) of the fixation light coordinate around IEC BEAM LIMITING DEVICE Y-axis. Used for eye treatments. See section C.8.8.25.6.4. + + + Polar angle (degrees) of the fixation light coordinate. Used for eye treatments. See section C.8.8.25.6.4. + + + Value of Cumulative Meterset Weight (300A,0134) for final Control Point in Ion Control Point Sequence (300A,03A8). Required if Cumulative Meterset Weight is non-null in Control Points specified within Ion Control Point Sequence. See section C.8.8.14.1. + + + Number of control points in Beam. Value shall be greater than or equal to 2. + + + Introduces sequence of machine configurations describing Ion treatment beam. The number of items shall be identical to the value of Number of Control Points (300A,0110). See C.8.8.25.7. +
The control point sequence for RT Ion Beams is defined using the same rule set as in the RT Beams module (see Section C.8.8.14.5 Control Point Sequence). Specifically, the following rules apply: +
+
+ + Index of current Control Point, starting at 0 for first Control Point. + + + Cumulative weight to current control point. Cumulative Meterset Weight for the first item in Control Point Sequence shall always be zero. Cumulative Meterset Weight for the final item in Ion Control Point Sequence shall always be equal to Final Cumulative Meterset Weight. + + + Introduces a sequence of Dose References for current Beam. One or more items may be included in this sequence. + + + Uniquely identifies Dose Reference specified by Dose Reference Number (300A,0012) in Dose Reference Sequence (300A,0010) in RT Prescription Module. + + + Coefficient used to calculate cumulative dose contribution from this Beam to the referenced Dose Reference at the current Control Point. + + + Nominal Beam Energy at control point in MeV per nucleon. Defined at nozzle entrance before all Beam Modifiers. Required for first item of Control Point Sequence, or if Nominal Beam Energy changes during Beam, and KVp (0018,0060) is not present. + + + Peak kilo voltage output of the setup X-Ray generator to be used. Required for first item of Control Point Sequence, or if KVp changes during setup, and Nominal Beam Energy (300A,0114) is not present. + + + Specifies the speed of delivery of the specified dose in units specified by Primary Dosimeter Unit (300A,00B3) per minute. + + + Introduces sequence of Wedge positions for current control point. +Required for first item of Ion Control Point Sequence if Number of Wedges (300A,00D0) is non-zero, and in subsequent control points if Wedge Position (300A,0118) or Wedge Thin Edge Position (300A,00DB) changes during beam. +The number of items shall be identical to the value of Number of Wedges (300A,00D0). + + + Uniquely references Wedge described by Wedge Number (300A,00D2) in Wedge Sequence (300A,00D1). + + + Position of Wedge at current Control Point. +Enumerated Values: +IN +OUT + + + Closest distance from the central axis of the beam along a wedge axis to the thin edge as projected to the machine isocentric plane (mm). Value is positive is the wedge does not cover the central axis, negative if it does. Required if Wedge Type (300A,00D3) of the wedge referenced by Referenced Wedge Number (300C,00C0) is PARTIAL_STANDARD or PARTIAL_MOTORIZ. See section C.8.8.25.6.4. + + + Introduces sequence of Range Shifter settings for the current control point. One or more items shall be included in this sequence. Required for first item of Control Point Sequence if Number of Range Shifters (300A,0312) is non-zero, or if Range Shifter Setting (300A,0362) changes during Beam. + + + Uniquely references Range Shifter described by Range Shifter Number (300A,0316) in Range Shifter Sequence (300A,0314). + + + Machine specific setting attribute for the range shifter. The specific encoding of this value should be documented in a Conformance Statement. See section C.8.8.25.5. + + + Isocenter to downstream edge of range shifter (mm) at current control point. See section C.8.8.25.4 + + + Water equivalent thickness (in mm) of the range shifter at the central axis for the beam energy incident upon the device. + + + Introduces sequence of Lateral Spreading Device settings for the current control point. One or more items shall be included in this sequence. Required for first item of Control Point Sequence if Number of Lateral Spreading Devices (300A,0330) is non-zero, or if Lateral Spreading Device Setting (300A,0372) changes during Beam. + + + Uniquely references Lateral Spreading Device described by Lateral Spreading Device Number (300A,0334) in Lateral Spreading Device Sequence (300A,0332). + + + Machine specific setting attribute for the lateral spreading device. The specific encoding of this value should be documented in a Conformance Statement. See section C.8.8.25.5. + + + Isocenter to downstream edge of Lateral Spreading Device (mm) at current control point. See section C.8.8.25.4 + + + Water equivalent thickness (in mm) of the lateral spreading device at the central axis for the beam energy incident upon the device. + + + Introduces sequence of Range Modulator Settings for current control point. One or more items shall be included in this sequence. Required for first item of Control Point Sequence if Number of Range Modulators (300A,0340) is non-zero, or if Range Modulator Setting changes during Beam. + + + Uniquely references Range Modulator described by Range Modulator Number (300A,0344) in Range Modulator Sequence (300A,0342). + + + Start position defines the range modulator position at which the beam is switched on. Required if Range Modulator Type (300A,0348) of the range modulator referenced by Referenced Range Modulator Number (300C,0104) is WHL_MODWEIGHTS or WHL_FIXEDWEIGHTS + + + Stop position defines the range modulator position at which the beam is switched off. Required if Range Modulator Type (300A,0348) of the range modulator referenced by Referenced Range Modulator Number (300C,0104) is WHL_MODWEIGHTS or WHL_FIXEDWEIGHTS + + + If Range Modulator Type (300A,0348) is WHL_MODWEIGHTS or WHL_FIXEDWEIGHTS: +Water equivalent thickness (in mm) of the range modulator at the position specified by Range Modulator Gating Start Value (300A,0382). +If Range Modulator Type (300A,0348) is FIXED: +Minimum water equivalent thickness (in mm) of the range modulator. + + + If Range Modulator Type (300A,0348) is WHL_MODWEIGHTS or WHL_FIXEDWEIGHTS: +Water equivalent thickness (in mm) of the range modulator at the position specified by Range Modulator Gating Stop Value (300A,0384). +If Range Modulator Type (300A,0348) is FIXED: +Maximum water equivalent thickness (in mm) of the range modulator. + + + Isocenter to downstream edge of range modulator (mm) at current control point. See section C.8.8.25.4 + + + + Gantry angle of radiation source, i.e. orientation of IEC GANTRY coordinate system with respect to IEC FIXED REFERENCE coordinate system (degrees). Required for first item of Control Point Sequence, or if Gantry Angle changes during Beam. + + + Direction of Gantry Rotation when viewing gantry from isocenter, for segment following Control Point. Required for first item of Control Point Sequence, or if Gantry Rotation Direction changes during Beam. See section C.8.8.14.8. +Enumerated Values: +CW = clockwise +CC = counter-clockwise +NONE = no rotation + + + Gantry Pitch Angle of the radiation source, i.e. the rotation of the IEC GANTRY coordinate system about the X-axis of the IEC GANTRY coordinate system (degrees). Required for first item of Control Point Sequence, or if Gantry Pitch Rotation Angle changes during Beam. See C.8.8.25.6.5. +
The Gantry Pitch angle is not defined in IEC 61217. This angle is defined in the DICOM standard in a way compatible with the current notion of IEC by introducing it as rotation of the IEC GANTRY System as indicated below. +The Gantry Pitch Angle is defined as the rotation of the coordinate axes Yg, Zg about axis Xg by an angle ï¹g; see Figure C.8.8.25-7. An increase in the value of angle ï¹g corresponds to the clockwise rotation as viewed from the isocenter along the positive Xg axis + + +Figure C.8.8.25-7 Gantry Pitch Angle +
+
+ + Direction of Gantry Pitch Angle when viewing along the positive X-axis of the IEC GANTRY coordinate system, for segment following Control Point. Required for first item of Control Point Sequence, or if Gantry Pitch Rotation Direction changes during Beam. See C.8.8.14.8 and C.8.8.25.6.5. +Enumerated Values: +CW = clockwise +CC = counter-clockwise +NONE = no rotation +
For the machine rotation angles Gantry Angle (300A,011E), Beam Limiting Device Angle (300A,0120), Patient Support Angle (300A,0122) , and Table Top Eccentric Angle (300A,0125), rotation direction is specified as clockwise (CW), counter-clockwise (CC), or NONE. The maximum permitted rotation between two Control Points is 360 degrees. Examples: +a) Gantry Angle moves from 5 degrees to 5 degrees, Gantry Rotation Direction = NONE: + No movement. + +b) Gantry Angle moves from 5 degrees to 5 degrees, Gantry Rotation Direction = CW: + Full clockwise rotation (360 degrees). + +c) Table Angle moves from 170 degrees to 160 degrees, Table Rotation Direction = CC: + Counter-clockwise rotation by 350 degrees (note direction of increasing table angle as defined by IEC 61217). + +
+
+ + Beam Limiting Device angle, i.e. orientation of IEC BEAM LIMITING DEVICE coordinate system with respect to IEC GANTRY coordinate system (degrees). Required for first item of Control Point Sequence, or if Beam Limiting Device Angle changes during Beam. + + + Direction of Beam Limiting Device Rotation when viewing beam limiting device (collimator) from radiation source, for segment following Control Point. Required for first item of Control Point Sequence, or if Beam Limiting Device Rotation Direction changes during Beam. See section C.8.8.14.8. +Enumerated Values: +CW = clockwise +CC = counter-clockwise +NONE = no rotation + + + User-supplied or machine code identifier for machine configuration to produce beam spot. This may be the nominal spot size or some other machine specific value. Required if Scan Mode (300A,0308) is MODULATED. + + + Number of spot positions used to specify scanning pattern for current segment beginning at control point. Required if Scan Mode (300A,0308) is MODULATED. + + + The x and y coordinates of the scan spots are defined as projected onto the machine isocentric plane in the IEC GANTRY coordinate system (mm). Required if Scan Mode (300A,0308) is MODULATED. Contains 2N values where N is the Number of Scan Spot Positions (300A,0392). + + + A data set of meterset weights corresponding to scan spot positions. The order of weights matches the positions in Scan Spot Positions (300A,0394). The sum contained in all meterset weights shall match the difference of the cumulative meterset weight of the current control point to the following control point. Required if Scan Mode (300A,0308) is MODULATED. + + + The Scanning Spot Size as calculated using the Full Width Half Maximum (FWHM). Specified by a numeric pair - the size measured in air at isocenter in IEC GANTRY X direction followed by the size in the IEC GANTRY Y direction (mm). + + + The number of times the scan pattern given by Scan Spot Position Map (300A,0394) and Scan Spot Meterset Weights (300A,0396) shall be applied at the current control point. To obtain the meterset weight per painting, the values in the Scan Spot Meterset Weights (300A,0396) should be divided by the value of this attribute. Required if Scan Mode (300A,0308) is MODULATED. + + + Patient Support angle, i.e. orientation of IEC PATIENT SUPPORT (turntable) coordinate system with respect to IEC FIXED REFERENCE coordinate system (degrees). Required for first item of Control Point Sequence, or if Patient Support Angle changes during Beam. + + + Direction of Patient Support Rotation when viewing table from above, for segment following Control Point. Required for first item of Control Point Sequence, or if Patient Support Rotation Direction changes during Beam. See section C.8.8.14.8. +Enumerated Values: +CW = clockwise +CC = counter-clockwise +NONE = no rotation + + + Table Top Pitch Angle, i.e. the rotation of the IEC TABLE TOP coordinate system about the X-axis of the IEC TABLE TOP coordinate system (degrees). Required for first item of Control Point Sequence, or if Table Top Pitch Angle changes during Beam. See section C.8.8.25.6.2. + + + Direction of Table Top Pitch Rotation when viewing the table along the positive X-axis of the IEC TABLE TOP coordinate system, for segment following Control Point. Required for first item of Control Point Sequence, or if Table Top Pitch Rotation Direction changes during Beam. See C.8.8.14.8 and C.8.8.25.6.2. +Enumerated Values: +CW = clockwise +CC = counter-clockwise +NONE = no rotation +
For the machine rotation angles Gantry Angle (300A,011E), Beam Limiting Device Angle (300A,0120), Patient Support Angle (300A,0122) , and Table Top Eccentric Angle (300A,0125), rotation direction is specified as clockwise (CW), counter-clockwise (CC), or NONE. The maximum permitted rotation between two Control Points is 360 degrees. Examples: +a) Gantry Angle moves from 5 degrees to 5 degrees, Gantry Rotation Direction = NONE: + No movement. + +b) Gantry Angle moves from 5 degrees to 5 degrees, Gantry Rotation Direction = CW: + Full clockwise rotation (360 degrees). + +c) Table Angle moves from 170 degrees to 160 degrees, Table Rotation Direction = CC: + Counter-clockwise rotation by 350 degrees (note direction of increasing table angle as defined by IEC 61217). + +
+
+ + Table Top Roll Angle, i.e. the rotation of the IEC TABLE TOP coordinate system about the Y-axis of the IEC TABLE TOP coordinate system (degrees). Required for first item of Control Point Sequence, or if Table Top Roll Angle changes during Beam. See section C.8.8.25.6.2. + + + Direction of Table Top Roll Rotation when viewing the table along the positive Y-axis of the IEC TABLE TOP coordinate system, for segment following Control Point. Required for first item of Control Point Sequence, or if Table Top Roll Rotation Direction changes during Beam. See C.8.8.14.8 and C.8.8.25.6.2. +Enumerated Values: +CW = clockwise +CC = counter-clockwise +NONE = no rotation. +
For the machine rotation angles Gantry Angle (300A,011E), Beam Limiting Device Angle (300A,0120), Patient Support Angle (300A,0122) , and Table Top Eccentric Angle (300A,0125), rotation direction is specified as clockwise (CW), counter-clockwise (CC), or NONE. The maximum permitted rotation between two Control Points is 360 degrees. Examples: +a) Gantry Angle moves from 5 degrees to 5 degrees, Gantry Rotation Direction = NONE: + No movement. + +b) Gantry Angle moves from 5 degrees to 5 degrees, Gantry Rotation Direction = CW: + Full clockwise rotation (360 degrees). + +c) Table Angle moves from 170 degrees to 160 degrees, Table Rotation Direction = CC: + Counter-clockwise rotation by 350 degrees (note direction of increasing table angle as defined by IEC 61217). + +
+
+ + Angle (in degrees) of the head fixation for eye treatments with respect to the Table Top Pitch Angle (300A,0140) coordinate system. Positive head fixation angle is the same direction as positive Table Top pitch. See section C.8.8.25.6.4. + + + Table Top Vertical position in IEC TABLE TOP coordinate system (mm). Required for first item of Control Point Sequence, or if Table Top Vertical Position changes during Beam. See section C.8.8.14.6. + + + Table Top Longitudinal position in IEC TABLE TOP coordinate system (mm). Required for first item of Control Point Sequence, or if Table Top Longitudinal Position changes during Beam. See section C.8.8.14.6. + + + Table Top Lateral position in IEC TABLE TOP coordinate system (mm). Required for first item of Control Point Sequence, or if Table Top Lateral Position changes during Beam. See section C.8.8.14.6. + + + Axial position of the snout (in mm) measured from isocenter to the downstream side of the snout (without consideration of variable length elements such as blocks, MLC and/or compensators). Required for first item in Control Point Sequence, or if Snout Position changes during Beam. + + + Isocenter coordinates (x,y,z) in the patient based coordinate system described in C.7.6.2.1.1 (mm). Required for first item of Segment Control Point Sequence, or if Segment Isocenter Position changes during Beam. + + + Patient surface entry point coordinates (x,y,z), along the central axis of the beam, in the patient based coordinate system described in C.7.6.2.1.1 (mm). + +
+ + + Name of operator administering treatment session. + + + Identifier of fraction group within referenced RT Ion Plan. + + + Total number of treatments (fractions) planned for current fraction group. + + + Measurement unit of the machine dosimeter. +Enumerated Values: +MU = Monitor Units +NP = Number of Particles + + + Introduces sequence of setup and/or treatment beams administered during treatment session. One or more items shall be included in this sequence. + + + References Beam specified by Beam Number (300A,00C0) in Ion Beam Sequence (300A,03A2) in RT Ion Beams Module within the referenced RT Ion Plan. + + + User-defined name for Beam. See section C.8.8.25.1. + + + User-defined description for Beam. See section C.8.8.25.1. + + + Motion characteristic of Beam. +Enumerated Values: +STATIC = all beam parameters remain unchanged during delivery +DYNAMIC = one or more beam parameters changes during delivery + + + Particle type of Beam. +Defined Terms: +PHOTON +PROTON +ION + + + Mass number of radiation. Required if Radiation Type (300A,00C6) is ION + + + Atomic number of radiation. Required if Radiation Type (300A,00C6) is ION + + + Charge state of radiation. Required if Radiation Type (300A,00C6) is ION + + + The method of beam scanning used during treatment. +Defined Terms: +NONE = No beam scanning is performed. +UNIFORM = The beam is scanned between control points to create a uniform lateral fluence distribution across the field. +MODULATED = The beam is scanned between control points to create a modulated lateral fluence distribution across the field. + + + Uniquely identifies Ion Tolerance Table specified by Tolerance Table Number (300A,0042) within Ion Tolerance Table Sequence in RT Ion Tolerance Tables Module. These tolerances are to be used for verification of treatment machine settings. + + + Introduces sequence of beam limiting device (collimator) jaw or leaf (element) sets. One or more items may be included in this sequence. + + + Type of beam limiting device (collimator). +Enumerated Values: +X = symmetric jaw pair in IEC X direction +Y = symmetric jaw pair in IEC Y direction +ASYMX = asymmetric jaw pair in IEC X direction +ASYMY = asymmetric pair in IEC Y direction +MLCX = multileaf (multi-element) jaw pair in IEC X direction +MLCY = multileaf (multi-element) jaw pair in IEC Y direction + + + Number of leaf (element) or jaw pairs (equal to 1 for standard beam limiting device jaws). + + + Uniquely identifies Ion Patient Setup to be used for current beam, specified by Patient Setup Number (300A,0182) within Patient Setup Sequence of RT Patient Setup Module. + + + Introduces sequence of verification images obtained during delivery of current beam. One or more items may be included in this sequence. See C.8.8.14.2. +
The Planned Verification Image Sequence (300A,00CA) contains attributes which describe the planned verification images to be acquired during current beam. The Start Cumulative Meterset Weight (300C,0008) specifies the Cumulative Meterset Weight at which image acquisition is to begin. If Meterset Exposure (3002,0032) is present in a sequence item and End Cumulative Meterset Weight (300C,0009) is not present then a single image shall be acquired using the meterset duration specified in Meterset Exposure (3002,0032). If End Cumulative Meterset Weight (300C,0009) is present in a sequence item and Meterset Exposure (3002,0032) is not present then a single image shall be acquired over the beam delivery from Start Cumulative Meterset Weight (300C,0008) to End Cumulative Meterset Weight (300C,0009). If both Meterset Exposure (3002,0032) and End Cumulative Meterset Weight (300C,0009) are present in a sequence item then images shall be acquired every Meterset Exposure (3002,0032) from Start Cumulative Meterset Weight (300C,0008) to End Cumulative Meterset Weight (300C,0009). No images shall extend past End Cumulative Meterset Weight (300C,0009). +
+
+ + + Introduces sequence of doses measured during treatment delivery for current Beam. The sequence may contain one or more items. + + + Uniquely references Dose Reference specified by Dose Reference Number (300A,0012) in Dose Reference Sequence (300A,0010) in RT Prescription Module of referenced RT Ion Plan. Required if Referenced Measured Dose Reference Number (3008,0082) is not sent. + + + Uniquely references Measured Dose Reference specified by Measured Dose Reference Number (3008,0064) in Measured Dose Reference Sequence (3008,0010). Required if Referenced Dose Reference Number (300C,0051) is not sent. + + + Measured Dose in units specified by Dose Units (3004,0002) in sequence referenced by Measured Dose Reference Sequence (3008,0010) or Dose Reference Sequence (300A,0010) in RT Prescription Module of Referenced RT Ion Plan as defined above. + + + Introduces sequence of doses estimated for each treatment delivery. The sequence may contain one or more items. + + + Uniquely identifies Dose Reference specified by Dose Reference Number (300A,0012) in Dose Reference Sequence (300A,0010) in RT Prescription Module of referenced RT Ion Plan. Required if Referenced Calculated Dose Reference Number (3008,0092) is not sent. + + + Uniquely identifies Calculated Dose Reference specified by Calculated Dose Reference Number (3008,0072) within Calculated Dose Reference Sequence (3008,0070). Required if Referenced Dose Reference Number (300C,0051) is not sent. + + + Calculated Dose (Gy). + + + Number of wedges associated with current beam. + + + Introduces sequence of treatment wedges. Required if Number of Wedges (300A,00D0) is non-zero. One or more items may be included in this sequence. The number of items shall be identical to the value of Number of Wedges (300A,00D0). + + + Identification number of the Wedges. The value of Wedge Number (300A,00D2) shall be unique within the Beam in which it was created. + + + Type of wedge (if any) defined for Beam. +Defined Terms: +STANDARD = standard (static) wedge +MOTORIZED = single wedge that can be removed from beam remotely. +PARTIAL_STANDARD = wedge does not extend across the whole field and is operated manually. +PARTIAL_MOTORIZ = wedge does not extend across the whole field and can be removed from beam remotely. + + + User-supplied identifier for Wedge. + + + An accessory identifier to be read by a device such as a bar code reader. + + + Nominal wedge angle (degrees). + + + Orientation of wedge, i.e. orientation of IEC WEDGE FILTER coordinate system with respect to the IEC BEAM LIMITING DEVICE coordinate systems (degrees). + + + Number of range compensators associated with current Beam. + + + Introduces sequence of treatment compensators. Required if Number of Compensators (300A,00E0) is non-zero. One or more items may be included in this sequence. The number of items shall be identical to the value of Number of Compensators (300A,00E0). + + + Uniquely identifies compensator specified by Compensator Number (300A,00E4) within Beam referenced by Referenced Beam Number (300C,0006). + + + User-supplied identifier for compensator. + + + An accessory identifier to be read by a device such as a bar code reader. + + + Number of boli associated with current Beam. + + + Introduces sequence of boli associated with Beam. Required if Number of Boli (300A,00ED) is non-zero. One or more items may be included in this sequence. The number of items shall be identical to the value of Number of Boli (300A,00ED). + + + Uniquely identifies ROI representing the Bolus specified by ROI Number (3006,0022) in Structure Set ROI Sequence (3006,0020) in Structure Set Module within RT Structure Set in Referenced Structure Set Sequence (300C,0060) in RT General Plan Module. + + + An accessory identifier to be read by a device such as a bar code reader. + + + Number of shielding blocks associated with Beam. + + + Introduces sequence of blocks associated with Beam. Required if Number of Blocks (300A,00F0) is non-zero. One or more items may be included in this sequence. The number of items shall be identical to the value of Number of Blocks (300A,00F0). + + + User-supplied identifier for block tray. + + + An accessory identifier to be read by a device such as a bar code reader. + + + Uniquely identifies block specified by Block Number (300A,00FC) within Beam referenced by Referenced Beam Number (300C,0006). + + + User-defined name for block. + + + Introduces sequence of Snouts associated with Beam. +Required if Snout Sequence (300A,030C) is included in the RT Ion Plan referenced within the Referenced RT Plan Sequence (300C,0002). +Only a single item shall be permitted in this sequence. + + + User or machine supplied identifier for Snout. + + + An accessory identifier to be read by a device such as a bar code reader. + + + Introduces sequence of Applicators associated with Beam. +Required if Applicator Sequence (300A,0107) is included in the RT Ion Plan referenced within the Referenced RT Plan Sequence (300C,0002). +Only a single item shall be permitted in this sequence. + + + User or machine supplied identifier for Applicator. See C.8.8.14.12 + + + An accessory identifier to be read by a device such as a bar code reader. + + + Type of applicator. + +Defined Terms: +ION_SQUARE = square ion applicator +ION_RECT = rectangluar ion applicator +ION_CIRC = circular ion applicator +ION_SHORT = short ion applicator +ION_OPEN = open (dummy) ion applicator +INTEROPERATIVE = interoperative (custom) applicator +STEREOTACTIC = stereotactic applicator + + + User-defined description for Applicator. + + + Introduces a Sequence of General Accessories associated with this Beam. One or more items may be included in this sequence. + + + Identification Number of the General Accessory. The value shall be unique within the sequence. + + + User or machine supplied identifier for General Accessory. + + + User supplied description of General Accessory. + + + Specifies the type of accessory. +Defined Terms: +GRATICULE = Accessory tray with a radio-opaque grid +IMAGE_DETECTOR = Image acquisition device positioned in the beam line +RETICLE = Accessory tray with radio-transparent markers or grid + + + Machine-readable identifier for this accessory + + + Number of range shifters associated with current beam. + + + Introduces sequence of range shifters recorded with Beam. Required if Number of Range Shifters (300A,0312) is non-zero. One or more items may be included in this sequence. The number of items shall be identical to the value of Number of Range Shifters (300A,0312). + + + Uniquely identifies range shifter specified by Range Shifter Number (300A,0316) within Beam referenced by Referenced Beam Number (300C,0006). + + + User or machine supplied identifier for Range Modulator. + + + An accessory identifier to be read by a device such as a bar code reader. + + + Number of lateral spreading devices associated with current beam. + + + Introduces sequence of lateral spreading devices associated with Beam. Required if Number of Lateral Spreading Devices (300A,0330) is non-zero. One or more items may be included in this sequence. The number of items shall be identical to the value of Number of Lateral Spreading Devices (300A,0330). + + + Uniquely identifies lateral spreading device specified by Lateral Spreading Device Number (300A,0334) within Beam referenced by Referenced Beam Number (300C,0006). + + + User or machine supplied identifier for Lateral Spreading Device. + + + An accessory identifier to be read by a device such as a bar code reader. + + + Number of range modulators associated with current beam. + + + Introduces sequence of range modulators associated with Beam. Required if Number of Range Modulators (300A,0340) is non-zero. One or more items may be included in this sequence. The number of items shall be identical to the value of Number of Range Modulators (300A,0340). + + + Uniquely identifies range modulator specified by Range Modulator Number (300A,0344) within Beam referenced by Referenced Beam Number (300C,0006). + + + User or machine supplied identifier for Range Modulator. + + + An accessory identifier to be read by a device such as a bar code reader. + + + Type of Range Modulator. +Defined Terms: +FIXED = fixed modulation width and weights using ridge filter or constant speed wheel with constant beam current +WHL_FIXEDWEIGHTS = selected wheel/track (Range Modulator ID) is spinning at constant speed. Modulation width is adjusted by switching constant beam current on and off at wheel steps indicated by Range Modulator Interrupt Values +WHL_MODWEIGHTS = selected wheel/track (Range Modulator ID) is spinning at constant speed. Weight per wheel step is adjusted by modulating beam current according to selected Beam Current Modulation ID (300A,034C) + +Only one item in the Recorded Range Modulator Sequence (3008,00F6) can have a Range Modulator Type (300A,0348) of WHL_MODWEIGHTS. + + + User-supplied identifier for the beam current modulation pattern. Required if Range Modulator Type (300A,0348) is WHL_MODWEIGHTS + + + + Azimuthal angle (degrees) of the fixation light coordinate around IEC PATIENT SUPPORT Y-axis. Used for eye treatments. See section C.8.8.25.6.4. + + + Polar angle (degrees) of the fixation light coordinate. Used for eye treatments. See section C.8.8.25.6.4. + + + Fraction number for this beam administration. + + + Delivery Type of treatment. +Defined Terms: +TREATMENT = normal patient treatment +OPEN_PORTFILM = portal image acquisition with open field (the source of radiation is specified by Radiation Type (300A,00C6)) +TRMT_PORTFILM = portal image acquisition with treatment port (the source of radiation is specified by Radiation Type (300A,00C6)) +CONTINUATION = continuation of interrupted treatment +SETUP = no treatment beam was applied for this RT Beam. To be used for specifying the gantry, couch, and other machine positions where X-Ray set-up images or measurements were taken. + + + Conditions under which treatment was terminated. +Enumerated Values: +NORMAL = treatment terminated normally +OPERATOR = operator terminated treatment +MACHINE = machine terminated treatment +UNKNOWN = status at termination unknown + + + Treatment machine termination code. This code is dependent upon the particular application and equipment. + + + Conditions under which treatment was verified by a verification system. +Enumerated Values: +VERIFIED = treatment verified +VERIFIED_OVR = treatment verified with at least one out-of-range value overridden +NOT_VERIFIED = treatment verified manually + + + Desired machine setting of primary meterset in units specified by Primary Dosimeter Unit (300A,00B3). + + + Desired machine setting of secondary meterset. + + + Machine setting actually delivered as recorded by primary meterset in units specified by Primary Dosimeter Unit (300A,00B3). + + + Machine setting actually delivered as recorded by secondary meterset. + + + Treatment Time set (sec). + + + Treatment Time actually delivered (sec). + + + Number of control points in Beam. + + + Introduces sequence of beam control points for current ion treatment beam. One or more items may be included in this sequence. The number of items shall be identical to the value of Number of Control Points (300A,0110). See section C.8.8.21.1. + + + Uniquely identifies Control Point specified by Control Point Index (300A,0112) within the Beam referenced by Referenced Beam Number (300C,0006). + + + Date administration of treatment beam began. + + + Time administration of treatment beam began. + + + Desired machine setting for current control point in units specified by Primary Dosimeter Unit (300A,00B3). + + + Machine setting actually delivered at current control point in units specified by Primary Dosimeter Unit (300A,00B3). + + + The specified speed of delivery of the specified dose in units specified by Primary Dosimeter Unit (300A,00B3) per minute. + + + The delivered speed of delivery of the specified dose in units specified by Primary Dosimeter Unit (300A,00B3) per minute. + + + Nominal Beam Energy at control point in MeV per nucleon. Defined at nozzle entrance before all Beam Modifiers. Required for Control Point 0 of Ion Control Point Delivery Sequence (3008,0041) or if Nominal Beam Energy (300A,0114) changes during beam administration, and KVp (0018,0060) is not present. + + + Peak kilo voltage output of the setup X-Ray generator used. Required for Control Point 0 of Ion Control Point Delivery Sequence (3008,0041), or if KVp changes during setup, and Nominal Beam Energy (300A,0114) is not present. + + + Introduces sequence of Wedge positions for current control point. +Required for first item of Ion Control Point Sequence if Number of Wedges (300A,00D0) is non-zero, and in subsequent control points if Wedge Position (300A,0118) or Wedge Thin Edge Position (300A,00DB) changes during beam. One or more items may be included in this sequence. The number of items shall be identical to the value of Number of Wedges (300A,00D0). + + + Uniquely references Wedge described by Wedge Number (300A,00D2) in Wedge Sequence (300A,00D1). + + + Position of Wedge at current control point. +Enumerated Values: IN, OUT. + + + Closest distance from the central axis of the beam along a wedge axis to the thin edge as projected to the machine isocentric plane (mm). Value is positive is the wedge does not cover the central axis, negative if it does. Required if Wedge Type (300A,00D3) of the wedge referenced by Referenced Wedge Number (300C,00C0) is PARTIAL_STANDARD or PARTIAL_MOTORIZ. See section C.8.8.25.6.4. + + + + Introduces sequence of Range Shifter settings for the current control point. One or more items may be included in this sequence. Required for Control Point 0 of Ion Control Point Delivery Sequence (3008,0041) or if Range Shifter Setting (300A,0362) changes during beam administration, and Number of Range Shifters (300A,0312) is non-zero. + + + Uniquely references Range Shifter described by Range Shifter Number (300A,0316) in Range Shifter Sequence (300A,0314). + + + Machine specific setting attribute for the range shifter. The specific encoding of this value should be documented in a Conformance Statement. See section C.8.8.25.5. + + + Introduces sequence of Lateral Spreading Device settings for the current control point. One or more items may be included in this sequence. Required for Control Point 0 of Ion Control Point Delivery Sequence (3008,0041) or if Lateral Spreading Device Setting (300A,0372) changes during beam administration, and Number of Lateral Spreading Devices (300A,0330) is non-zero. + + + Uniquely references Lateral Spreading Device described by Lateral Spreading Device Number (300A,0334) in Lateral Spreading Device Sequence (300A,0332). + + + Machine specific setting attribute for the lateral spreading device. The specific encoding of this value should be documented in a Conformance Statement. See section C.8.8.25.5. + + + Introduces sequence of Range Modulator Settings for current control point. One or more items may be included in this sequence.Required for Control Point 0 of Ion Control Point Delivery Sequence (3008,0041), or if Range Modulator Settings change during beam administration, and Number of Range Modulators (300A,0340) is non-zero. + + + Uniquely references Range Modulator described by Range Modulator Number (300A,0344) in Range Modulator Sequence (300A,0342). + + + Start position defines the range modulator position at which the beam is switched on. Required if Range Modulator Type (300A,0348) of the range modulator referenced by Referenced Range Modulator Number (300C,0104) is WHL_MODWEIGHTS or WHL_FIXEDWEIGHTS + + + Stop position defines the range modulator position at which the beam is switched off. Required if Range Modulator Type (300A,0348) of the range modulator referenced by Referenced Range Modulator Number (300C,0104) is WHL_MODWEIGHTS or WHL_FIXEDWEIGHTS + + + Treatment machine gantry angle, i.e. orientation of IEC GANTRY coordinate system with respect to IEC FIXED REFERENCE coordinate system (degrees). Required for Control Point 0 of Ion Control Point Delivery Sequence (3008,0041) or if Gantry Angle changes during beam administration. + + + Direction of Gantry Rotation when viewing gantry from isocenter, for segment beginning at current Control Point. Required for Control Point 0 of Ion Control Point Delivery Sequence (3008,0041), or if Gantry Rotation Direction changes during beam administration. +Enumerated Values: +CW = clockwise +CC = counter-clockwise +NONE = no rotation + + + Gantry Pitch Angle. i.e. the rotation of the IEC GANTRY coordinate system about the X-axis of the IEC GANTRY coordinate system (degrees). Required for first item of Control Point Sequence, or if Gantry PitchRotation Angle changes during Beam. See C.8.8.25.6.5. +
The Gantry Pitch angle is not defined in IEC 61217. This angle is defined in the DICOM standard in a way compatible with the current notion of IEC by introducing it as rotation of the IEC GANTRY System as indicated below. +The Gantry Pitch Angle is defined as the rotation of the coordinate axes Yg, Zg about axis Xg by an angle ï¹g; see Figure C.8.8.25-7. An increase in the value of angle ï¹g corresponds to the clockwise rotation as viewed from the isocenter along the positive Xg axis + + +Figure C.8.8.25-7 Gantry Pitch Angle +
+
+ + Direction of Gantry PitchAngle when viewing along the positive X-axis of the IEC GANTRY coordinate system, for segment following Control Point. Required for first item of Control Point Sequence, or if Gantry PitchRotation Direction changes during Beam. See C.8.8.14.8 and C.8.8.25.6.5. +Enumerated Values: +CW = clockwise +CC = counter-clockwise +NONE = no rotation +
For the machine rotation angles Gantry Angle (300A,011E), Beam Limiting Device Angle (300A,0120), Patient Support Angle (300A,0122) , and Table Top Eccentric Angle (300A,0125), rotation direction is specified as clockwise (CW), counter-clockwise (CC), or NONE. The maximum permitted rotation between two Control Points is 360 degrees. Examples: +a) Gantry Angle moves from 5 degrees to 5 degrees, Gantry Rotation Direction = NONE: + No movement. + +b) Gantry Angle moves from 5 degrees to 5 degrees, Gantry Rotation Direction = CW: + Full clockwise rotation (360 degrees). + +c) Table Angle moves from 170 degrees to 160 degrees, Table Rotation Direction = CC: + Counter-clockwise rotation by 350 degrees (note direction of increasing table angle as defined by IEC 61217). + +
+
+ + Beam Limiting Device (collimator) angle, i.e. orientation of IEC BEAM LIMITING DEVICE coordinate system with respect to IEC GANTRY coordinate system (degrees). Required for Control Point 0 of Ion Control Point Delivery Sequence (3008,0041) or if beam limiting device (collimator) angle changes during beam administration. + + + Direction of Beam Limiting Device Rotation when viewing beam limiting device (collimator) from radiation source, for segment beginning at current Control Point. Required for Control Point 0 of Ion Control Point Delivery Sequence (3008,0041) or if Beam Limiting Device Rotation Direction changes during beam administration. +Enumerated Values: +CW = clockwise +CC = counter-clockwise +NONE = no rotation + + + User-supplied or machine code identifier for machine configuration to produce beam spot. This may be the nominal spot size or some other machine specific value. Required if Scan Mode (300A,0308) is MODULATED. + + + Number of spot positions used to specify scanning pattern for current segment beginning at control point. Required if Scan Mode (300A,0308) is MODULATED. + + + The x and y coordinates of the scan spots are defined as projected onto the machine isocentric plane in the IEC GANTRY coordinate system (mm). Required if Scan Mode (300A,0308) is MODULATED. Contains 2N values were N is the Number of Scan Spot Positions (300A,0392). + + + A data set of metersets delivered to the scan spot positions. The order of metersets matches the positions in Scan Spot Position Map (300A,0394). The sum contained in all metersets shall match the difference of the Delivered Meterset of the current control point to the following control point. Required if Scan Mode (300A,0308) is MODULATED. + + + The Scanning Spot Size as calculated using the Full Width Half Maximum (FWHM). Specified by a numeric pair - the size measured in air at isocenter in IEC GANTRY X direction followed by the size in the IEC GANTRY Y direction (mm). + + + The intended number of times the scan pattern given by Scan Spot Position Map (300A,0394) and Scan Spot Meterset Weights (300A,0396) in the Referenced RT Plan was to be applied at the current control point. +Note: The actual number of paintings is not known or recorded. The Scan Spot Metersets Delivered (3008,0047) contains the sum of all complete and partial repaints. +Required if Scan Mode (300A,0308) is MODULATED. + + + Patient Support angle, i.e. orientation of IEC PATIENT SUPPORT (turntable) coordinate system with respect to IEC FIXED REFERENCE coordinate system (degrees). Required for Control Point 0 of Ion Control Point Delivery Sequence (3008,0041) or if Patient Support Angle changes during beam administration. + + + Direction of Patient Support Rotation when viewing table from above, for segment beginning at current Control Point. +Required for Control Point 0 of Ion Control Point Delivery Sequence (3008,0041), or if Patient Support Rotation Direction changes during beam administration. +Enumerated Values: +CW = clockwise +CC = counter-clockwise +NONE = no rotation + + + Table Top Pitch Angle, i.e. the rotation of the IEC TABLE TOP coordinate system about the X-axis of the IEC TABLE TOP coordinate system (degrees). Required for first item of Control Point Sequence, or if Table Top Pitch Angle changes during Beam. See section C.8.8.25.6.2. + + + Direction of Table Top Pitch Rotation when viewing the table along the positive X-axis of the IEC TABLE TOP coordinate system, for segment following Control Point. Required for first item of Control Point Sequence, or if Table Top Pitch Rotation Direction changes during Beam. See C.8.8.14.8 and C.8.8.25.6.2. +Enumerated Values: +CW = clockwise +CC = counter-clockwise +NONE = no rotation +
For the machine rotation angles Gantry Angle (300A,011E), Beam Limiting Device Angle (300A,0120), Patient Support Angle (300A,0122) , and Table Top Eccentric Angle (300A,0125), rotation direction is specified as clockwise (CW), counter-clockwise (CC), or NONE. The maximum permitted rotation between two Control Points is 360 degrees. Examples: +a) Gantry Angle moves from 5 degrees to 5 degrees, Gantry Rotation Direction = NONE: + No movement. + +b) Gantry Angle moves from 5 degrees to 5 degrees, Gantry Rotation Direction = CW: + Full clockwise rotation (360 degrees). + +c) Table Angle moves from 170 degrees to 160 degrees, Table Rotation Direction = CC: + Counter-clockwise rotation by 350 degrees (note direction of increasing table angle as defined by IEC 61217). + +
+
+ + Table Top Roll Angle, i.e. the rotation of the IEC TABLE TOP coordinate system about the Y-axis of the IEC TABLE TOP coordinate system (degrees). Required for first item of Control Point Sequence, or if Table Top Roll Angle changes during Beam. See section C.8.8.25.6.2. + + + Direction of Table Top Roll Rotation when viewing the table along the positive Y-axis of the IEC TABLE TOP coordinate system, for segment following Control Point. Required for first item of Control Point Sequence, or if Table Top Roll Rotation Direction changes during Beam. See C.8.8.14.8 and C.8.8.25.6.2. +Enumerated Values: +CW = clockwise +CC = counter-clockwise +NONE = no rotation +
For the machine rotation angles Gantry Angle (300A,011E), Beam Limiting Device Angle (300A,0120), Patient Support Angle (300A,0122) , and Table Top Eccentric Angle (300A,0125), rotation direction is specified as clockwise (CW), counter-clockwise (CC), or NONE. The maximum permitted rotation between two Control Points is 360 degrees. Examples: +a) Gantry Angle moves from 5 degrees to 5 degrees, Gantry Rotation Direction = NONE: + No movement. + +b) Gantry Angle moves from 5 degrees to 5 degrees, Gantry Rotation Direction = CW: + Full clockwise rotation (360 degrees). + +c) Table Angle moves from 170 degrees to 160 degrees, Table Rotation Direction = CC: + Counter-clockwise rotation by 350 degrees (note direction of increasing table angle as defined by IEC 61217). + +
+
+ + Angle (in degrees) of the head fixation for eye treatments with respect to the Table Top Pitch Angle (300A,0140) coordinate system. Positive head fixation angle is the same direction as positive Table Top Pitch. See section C.8.8.25.6.4. + + + Table Top Vertical position in IEC TABLE TOP coordinate system (mm). This value is interpreted as an absolute, rather than relative, Table setting. Required for Control Point 0 of Ion Control Point Delivery Sequence (3008,0041) or if Table Top Vertical Position changes during beam administration. + + + Table Top Longitudinal position in IEC TABLE TOP coordinate system (mm). This value is interpreted as an absolute, rather than relative, Table setting. Required for Control Point 0 of Ion Control Point Delivery Sequence (3008,0041) or if Table Top Longitudinal Position changes during beam administration. + + + Table Top Lateral position in IEC TABLE TOP coordinate system (mm). This value is interpreted as an absolute, rather than relative, Table setting. Required for Control Point 0 of Ion Control Point Delivery Sequence (3008,0041) or if Table Top Lateral Position changes during beam administration. + + + Axial position of the snout (in mm) measured from isocenter to the downstream side of the snout (without consideration of variable length elements such as blocks, MLC and/or compensators). Required for Control Point 0 of Ion Control Point Delivery Sequence (3008,0041) or if Snout Position changes during beam administration. + + + Introduces a sequence of items describing corrections made to any attributes prior to delivery of the next control point. The sequence may contain one or more items. + + + Contains the Data Element Tag of the parent sequence containing the attribute that was corrected. The value is limited in scope to the Treatment Session Ion Beam Sequence (3008,0021) and all nested sequences therein. + + + Contains the ones-based sequence item index of the corrected attribute within its parent sequence as indicated by Parameter Sequence Pointer (3008,0061). + + + Contains the Data Element Tag of the attribute that was corrected. + + + The value that was added the value referenced by the Parameter Sequence Pointer (3008,0061), Parameter Item Index (3008,0063) and Parameter Pointer (3008,0065). + + + Introduces sequence of parameters that were overridden during the administration of the beam segment immediately prior to the current control point. The sequence may contain one or more items. + + + Contains the Data Element Tag of the parent sequence containing the attribute that was overriden. The value is limited in scope to the Treatment Session Ion Beam Sequence (3008,0021) and all nested sequences therein. + + + Contains the Data Element Tag of the attribute that was overridden. + + + Contains the ones-based sequence item index of the overriden attributes within it's parent sequence. The value is limited in scope to the Treatment Session Ion Beam Sequence (3008,0021) and all nested sequences therein. + + + Name of operator who authorized override. + + + User-defined description of reason for override of parameter specified by Override Parameter Pointer (3008,0062). + +
+ + + Introduces sequence of beam limiting device (collimator) jaw or leaf (element) positions. Required if Ion Beam Limiting Device Sequence (300A,03A4) is included and for first item of Control Point Sequence, or if Beam Limiting Device changes during Beam. One or more items shall be included in this sequence. + + + Type of beam limiting device (collimator). The value of this attribute shall correspond to RT Beam Limiting Device Type (300A,00B8) defined in an item of Ion Beam Limiting Device Sequence (300A,03A4). +Enumerated Values: +X = symmetric jaw pair in IEC X direction +Y = symmetric jaw pair in IEC Y direction +ASYMX = asymmetric jaw pair in IEC X direction +ASYMY = asymmetric pair in IEC Y direction +MLCX = multileaf (multi-element) jaw pair in IEC X direction +MLCY = multileaf (multi-element) jaw pair in IEC Y direction + + + Positions of beam limiting device (collimator) leaf (element) or jaw pairs (in mm) in IEC BEAM LIMITING DEVICE coordinate axis appropriate to RT Beam Limiting Device Type (300A,00B8), e.g. X-axis for MLCX, Y-axis for MLCY. Contains 2N values, where N is the Number of Leaf/Jaw Pairs (300A,00BC) in Ion Beam Limiting Device Sequence (300A,03A4). Values shall be listed in IEC leaf (element) subscript order 101, 102, ... 1N, 201, 202, ... 2N. See section C.8.8.25.3. + + + + + Defined terms: +TABLE = Treatment delivery system table +CHAIR = Treatment delivery system chair +See section C.8.8.25.6.3. + + + User-specified identifier for manufacturer specific patient support devices. + + + A Patient Support accessory identifier to be read by a device such as a bar code reader. + + + + + Date the Series started. See C.8.9.1.1.2 for specialization. +
For PET Series, Series Date (0008,0021) and Series Time (0008,0031) are specified to be Type 1. The Series Date (0008,0021) and Series Time (0008,0031) are used as the reference time for all PET Image attributes that are temporally related, including activity measurements. The Series Date (0008,0021) and Series Time (0008,0031) are not tied to any real-world event (e.g. acquisition start, radiopharmaceutical administration) and their real-world meaning are implementation dependent. +
+
+ + Time the Series started. See C.8.9.1.1.2 for specialization. +
For PET Series, Series Date (0008,0021) and Series Time (0008,0031) are specified to be Type 1. The Series Date (0008,0021) and Series Time (0008,0031) are used as the reference time for all PET Image attributes that are temporally related, including activity measurements. The Series Date (0008,0021) and Series Time (0008,0031) are not tied to any real-world event (e.g. acquisition start, radiopharmaceutical administration) and their real-world meaning are implementation dependent. +
+
+ + Pixel value units. See C.8.9.1.1.3 for explanation. Defined terms: +CNTS, NONE, CM2, PCNT, CPS, BQML, MGMINML, UMOLMINML, MLMING, MLG, 1CM, UMOLML, PROPCNTS, PROPCPS, MLMINML, MLML, GML, STDDEV +
The units of the pixel values obtained after conversion from the stored pixel values (SV) (Pixel Data (7FE0,0010)) to pixel value units (U), as defined by Rescale Intercept (0028,1052) and Rescale Slope (0028,1053). Defined Terms: + CNTS = counts + NONE = unitless + CM2 = centimeter**2 + PCNT = percent + CPS = counts/second + BQML = Becquerels/milliliter + MGMINML = milligram/minute/milliliter + UMOLMINML = micromole/minute/milliliter + MLMING = milliliter/minute/gram + MLG = milliliter/gram + 1CM = 1/centimeter + UMOLML = micromole/milliliter + PROPCNTS = proportional to counts + PROPCPS = proportional to counts/sec + MLMINML = milliliter/minute/milliliter + MLML = milliliter/milliliter + GML = grams/milliliter + STDDEV = standard deviations + +
+
+ + The primary source of counts. The primary source leads to the underlying image Units (0054,1001), as opposed to secondary sources which are used during reconstruction correction. Enumerated Values: +EMISSION +TRANSMISSION + + + A multi-valued indicator of the type of Series. See C.8.9.1.1.4 for explanation. +Value 1 Enumerated Values: +STATIC +DYNAMIC +GATED +WHOLE BODY +Value 2 Enumerated Values: +IMAGE +REPROJECTION +
The Series Type (0054,1000), Value 1 is used to identify the spatial location and temporal nature of the images within a PET Series. The Enumerated Values and their definitions are: + STATIC = a group of images at varying spatial locations at the same time + DYNAMIC = a group of images at a set of spatial locations (e.g. slices) at varying time slices, with all spatial locations acquired at all time slices + GATED = a group of images at the same spatial location, same starting and ending time, but acquired in different time slots of (possibly) different R-R intervals + WHOLE BODY = same as STATIC, except covering multiple transverse fields of view (and therefore acquired at a different time). +Notes: 1. Using this definition and the comments in C.8.9.1.1.1, here are some examples of PET series and the encoding of Series Type (0054,1000) Value 1. + Static acquisition: a group of n transverse images at varying superior<->inferior locations, all acquired between the same starting and ending time. Series Type = STATIC. + Dynamic acquisition: a group of n*m transverse images at n superior<->inferior locations, acquired with m different starting and ending times. Series Type = DYNAMIC. + Gated acquisition: a group of n*m*p transverse images at n superior<->inferior locations, all acquired between the same starting and ending time, acquired in m different R-R Intervals (as determined by Low R-R Value (0018,1081) and High R-R Value (0018,1082)), and acquired in p time slots of a given R-R Interval (as determined by Trigger Time (0054,1000) ). Series Type = GATED. + Whole body acquisition: a group of n transverse images at varying superior<->inferior locations covering a significant fraction of the entire body. Series Type = WHOLE BODY. + Multiple transverse fields of view: a group of n transverse images at varying superior<->inferior locations. Series Type = WHOLE BODY. + Interleaved: group of 2*n transverse images acquired at overlapped AFOVs to increase transverse sampling. Series Type = WHOLE BODY. + Sagittal (Coronal, Oblique): sagittal (coronal, oblique) re-sliced images derived by reformatting transverse images. The Series Type is STATIC, DYNAMIC, GATED, or WHOLE BODY depending on source Series Type. + Arithmetic: images derived by an arithmetic operation on operand images. The Series Type is STATIC, DYNAMIC, GATED, or WHOLE BODY depending on source Series Type. + Metabolic: images derived by a metabolic model. The Series Type is STATIC, DYNAMIC, GATED, or WHOLE BODY depending on source Series Type. + + 2. Using this definition, here are some images that are not stored in the same PET Series: + Two images from the same scan that were reconstructed differently. + Emission and transmission images for the same Patient and Study, even if acquired simultaneously (because emission and transmission images have different reconstruction processing). + Two images of same patient, one after NH3 injection and one after FDG injection. + Two images: an original image created from reconstructed scan data and its derived image based on a metabolic model. + +The Series Type (0054,1000), Value 2 is used to identify the volumetric meaning of the images within a PET Series. The Enumerated Values and their definitions are: + IMAGE = a tomographic image slice + REPROJECTION = a projection image derived from forward projection through slices of tomographic images, using the algorithm defined in Reprojection Method (0054,1004). +
+
+ + Method for projecting volumetric data onto planar projection. Required if Series Type (0054,1000), Value 2 is REPROJECTION. Defined terms: +SUM +MAX PIXEL + + + The maximum number of R-R Intervals that may exist in this Series. Required if Series Type (0054,1000), Value 1 is GATED. + + + The maximum number of Time Slots that may exist in this Series. Required if Series Type (0054,1000), Value 1 is GATED. + + + The maximum number of Time Slices that may exist in this Series. Required if Series Type (0054,1000), Value 1 is DYNAMIC. + + + The maximum number of Slices that may exist in this Series. + + + A value that indicates which, if any, corrections have been applied to the images in this series. Defined terms: +DECY=decay corrected +ATTN=attenuation corrected +SCAT=scatter corrected +DTIM=dead time corrected +MOTN=gantry motion corrected (e.g. wobble, clamshell) +PMOT=patient motion corrected +CLN=count loss normalization (correction for count loss in gated Time Slots). +RAN=randoms corrected +RADL=non-uniform radial sampling corrected +DCAL=sensitivity calibrated using dose calibrator +NORM=detector normalization + + + Type of randoms correction processing. Defined terms: +NONE = no randoms correction +DLYD = delayed event subtraction +SING = singles estimation + + + A textual description of the attenuation correction processing. e.g. measured vs. calculated, transmission source type (ring, line, point), assumed patient geometry (polygon, ellipse, segmented, attenuation coefficient, skull thickness), post-injection transmission, smoothing. + + + A textual description of the scatter correction processing. e.g. convolution-subtraction, dual energy window, model-based, use of attenuation data. + + + The real-world event to which images in this Series were decay corrected. See C.8.9.1.1.5 for explanation. Defined terms: +NONE = no decay correction +START= acquisition start time +ADMIN = radiopharmaceutical administration time +
The Decay Correction (0054,1102) is the real-world event to which images in this Series were decay corrected. If decay correction is applied, all images in the Series shall be decay corrected to the same time. The Defined Terms and definitions are: + NONE = no decay correction + START= acquisition start time, Acquisition Time (0008,0032) + ADMIN = radiopharmaceutical administration time, Radiopharmaceutical Start Time (0018,1072) +The time to which images have been decay corrected can be derived from Decay Factor (0054,1321), Frame Reference Time (0054,1300), Radionuclide Half Life (0018,1075), Series Date (0008,0021), and Series Time (0008,0031). +
+
+ + Diameter, in mm, of the region within which the data was used in creating the reconstruction of the image. Data may exist outside this region and portions of the patient may exist outside this region. + + + Textual description of the convolution kernel(s) used to reconstruct the data (e.g. name, cutoff, radial/axial/angular, mathematical form, DC handling) + + + Textual description of reconstruction processing, e.g. 2D filtered backprojection, 2D iterative, 3D PROMIS, 3D FAVOR, 3D iterative. + + + Textual description of which detector lines of response were used, mashed, or otherwise processed during tomographic reconstruction. + + + Description of how the data collection was started. Defined terms: +DENS = density (counts/sec) +RDD = relative density difference (change in counts/sec) +MANU = manual +TIME = time +AUTO = automatic, when ready +TRIG = physiological trigger +See C.8.9.1.1.6 for explanation. +
Acquisition Start Condition (0018,0073) is the method of starting acquisition data collection. The Defined Terms and definitions are: + DENS = preset count density (counts/sec) was reached + RDD = preset relative count density difference (change in counts/sec) was reached + MANU = acquisition was started manually + TIME = preset time limit was reached + AUTO = start automatically, when ready + TRIG = preset number of physiological triggers was reached +
+
+ + Count density, change in count density, or physiological triggers causing data collection to start. + + + Description of how the data collection for the series was stopped. Defined terms: +CNTS = counts +DENS = density (counts/sec) +RDD = relative density difference (change in counts/sec) +MANU = manual +OVFL = data overflow +TIME = time +TRIG = physiological trigger +See C.8.4.9.1.3 for explanation. +
Acquisition Termination Condition (0018,0071) is the method of acquisition termination which was actually applied to the data collection. The Defined Terms and definitions are: +CNTS = preset count limit was reached +DENS = preset count density was reached +MANU = acquisition was terminated manually +OVFL = acquisition was terminated automatically by pixel data overflow condition +TIME = preset time limit was reached +TRIG = preset number of physiological triggers was reached + +
+
+ + Number of counts, count density, change in count density, or physiological triggers causing the termination. + + + Shape of the field of view of the PET camera. Defined Terms: +CYLINDRICAL RING +HEXAGONAL +MULTIPLE PLANAR + + + Dimensions of the field of view, in mm. Transverse detector diameter followed by axial width. + + + Angle of tilt in degrees of the gantry. See C.8.9.1.1.7 for explanation. +
Gantry/Detector Tilt (0018,1120) for PET Image data is the angle in degrees of the gantry relative to the patient’s major (Head to Feet) axis (or the table supporting the patient). Positive tilt is moving the top of the gantry towards the patient’s feet. +
+
+ + Angle of slew in degrees of the gantry. Positive slew is moving the gantry on the patient's left toward the patient's superior, when the patient is supine. + + + Describes the detector motion during acquisition. Defined Terms: +NONE = stationary gantry +STEP AND SHOOT = Interrupted motion, acquire only while stationary +CONTINUOUS = Gantry motion and acquisition are simultaneous and continuous +WOBBLE = wobble motion +CLAMSHELL = clamshell motion + + + Collimator Type. Defined Terms: +NONE = no collimator +RING = transverse septa + + + Label describing the collimator used. + + + Maximum axial angle accepted, in degrees. + + + Number of adjacent axial lines of response mashed together. See C.8.9.1.1.8 for explanation. +
Axial Mash (0054,1201) is multi-valued and is defined as the number of unique axial Lines of Response (LOR) that were mashed together (center of the axial field of view only). Value 1 is the number of LORs mashed for an odd slice. Value 2 is the number of LORs mashed for an even slice. For discrete crystal scanners, each unique LOR corresponds to a pair of crystals. For continuous detectors whose bin size is variable, the number of LORs mashed is determined by the actual bin size divided by the Detector Element Size (0054,1203), Value 2. The value of Axial Mash (0054,1201) is the same regardless of whether the mashing was done during acquisition or reconstruction. +Note: As an example on a discrete crystal scanner, if a ring difference of -2,0,+2 are binned as an odd slice and a ring difference of -1,+1 are binned as an even slice, then the Axial Mash (0054,1201) is equal to 3\2 . + +
+
+ + Number of adjacent transverse lines of response mashed together. See C.8.9.1.1.9 for explanation. +
Transverse Mash (0054,1202) is defined as the number of unique transverse Lines of Response (LOR) that were mashed together. For discrete crystal scanners, each unique LOR corresponds to a pair of crystals. For continuous detectors whose bin size is variable, the number of LORs mashed is determined by the actual bin size divided by the Detector Element Size (0054,1203), Value 1. The value of Transverse Mash (0054,1202) is the same regardless of whether the mashing was done during acquisition or reconstruction. +
+
+ + Size of an individual detector element, in mm. Transverse dimension followed by axial dimension. For a discrete crystal, this is the crystal size. For a continuous detector, this is the pixel bin size. + + + The width of the coincidence timing window, in nsec. The maximum time difference accepted between two single events. + + + Sequence of Items that describes the energy windows used for this Series. This sequence may contain zero or more items. See C.8.9.1.1.10 for explanation. +
Multiple energy windows are allowed in order to allow coincidence events based on additional Energy Windows (e.g. Compton events scattered in the detector). All energy windows are assumed to contribute to all images in the PET Series. +
+
+ + The lower limit of the energy window, in KeV. + + + The upper limit of the energy window, in KeV. + + + Array defining the type of additional counts accumulated during acquisition. Defined terms: +DLYD=delayed events +SCAT=scattered events in secondary window +SING=singles +DTIM=events lost due to deadtime + +
+ + + Sequence of Items that describe isotope information. Zero or more Items may be included in this sequence. + + + Sequence that identifies the radionuclide. Zero or one item shall be present in the sequence. + + + + Route of administration. + + + Sequence that identifies the administration route of the radiopharmaceutical. This sequence shall contain exactly one item. + + + + Volume of administered radiopharmaceutical in cubic cm. + + + Time of start of administration. The actual time of radiopharmaceutical administration to the patient for imaging purposes, using the same time base as Series Time (0008,0031). +The use of this Attribute is deprecated in favor of Radiopharmaceutical Start DateTime (0018,1078). +Note: The use of a time alone can cause confusion when the procedure spans midnight. + + + Date and time of start of administration. The actual date and time of radiopharmaceutical administration to the patient for imaging purposes, using the same time base as Series Time (0008,0031). + + + Time of end of administration. The actual ending time of radiopharmaceutical administration to the patient for imaging purposes, using the same time base as Series Time (0008,0031). +The use of this Attribute is deprecated in favor of Radiopharmaceutical Stop DateTime (0018,1079). +Note: The use of a time alone can cause confusion when the procedure spans midnight. + + + Date and time of end of administration. The actual ending date and time of radiopharmaceutical administration to the patient for imaging purposes, using the same time base as Series Time (0008,0031). + + + The radiopharmaceutical dose administered to the patient measured in Becquerels (Bq) at the Radiopharmaceutical Start Time (0018,1072). +Note: In other IODs, such as the NM IOD, this same attribute is specified in MegaBecquerels (MBq). + + + The radionuclide half life, in seconds, that was used in the correction of this image. + + + The radionuclide positron fraction (fraction of decays that are by positron emission) that was used in the correction of this image. + + + The activity per unit mass of the radiopharmaceutical, in Bq/micromole, at the Radiopharmaceutical Start Time (0018,1072). + + + Name of the radiopharmaceutical. + + + Sequence that identifies the radiopharmaceutical. This sequence shall contain exactly one item. + + + + Sequence of Items that describes the intervention drugs used. One or more items may be included in this sequence. + + + Name of the intervention drug. + + + Sequence that identifies the intervention drug name. Only a single Item shall be permitted in this Sequence. + + + + Time of administration of the intervention drug, using the same time base as for the Series Time (0008,0031). + + + Time of completion of administration of the intervention drug, using the same time base as for the Series Time (0008,0031). + + + Intervention drug dose, in mg. + + + + + Heart beat duration sorting has been applied. Enumerated values: +Y = yes +N = no + + + Text indicating trigger source. Defined terms: +EKG + + + Description of the type of PVC rejection criteria used. + + + Number of beats skipped after a detected arrhythmia. + + + Average number of heart beats per minute for the collection period for this image. This shall include all accepted beats as well as rejected beats. + + + Description of type of framing performed. Defined Terms: +FORW = forward +BACK = backward +PCNT = forward/backward by percentage +See C.7.6.18.1.1.1. +
Cardiac Framing Type (0018,1064) is the mechanism used to select the data acquired to construct the frames within a specified cardiac timing interval.C.7.6.18.2 Respiratory Synchronization Module +Table C7.6.18-2 specifies the attributes of the Respiratory Synchronization Module. +Table C.7.6.18-2 +RESPIRATORY SYNCHRONIZATION MODULE ATTRIBUTES + +
+
+
+ + + Image identification characteristics. See C.8.9.4.1.1 for specialization. +
For PET Images, Image Type (0008,0008) is specified to be Type 1. +Note: For PET images, Image Type (0008,0008) Value 1 will be ORIGINAL for reconstructed images. DERIVED may be appropriate for some other results images. For PET images, Image Type (0008,0008) Value 2 will be PRIMARY. + +
+
+ + Number of samples (planes) in this image. This value shall be 1. + + + Specifies the intended interpretation of the pixel data. See C.8.9.4.1.2 for specialization. +
For PET images, Photometric Interpretation (0028,0004) shall have one of the following Enumerated Values: + MONOCHROME2 +See C.7.6.3.1.2 for definition of this term. +
+
+ + Number of bits allocated for each pixel sample. Each sample shall have the same number of bits allocated. Enumerated values: 16. + + + Number of bits stored for each pixel sample. Each sample shall have the same number of bits stored. The value shall be the same as the value in Bits Allocated (0028,0100). + + + Most significant bit for pixel sample data. Each sample shall have the same high bit. +Shall be one less than the value in Bits Stored (0028,0101). + + + The value b in relationship between stored values (SV) and pixel value units (U) defined in Units (0054,1001): U = m*SV+b. The Rescale Intercept is always zero for PET images. + + + m in the equation specified in Rescale Intercept (0028,1052). + + + The time that the pixel values in the image occurred. Frame Reference Time is the offset, in msec, from the Series reference time. See explanation in C.8.9.4.1.5. + + + Time interval, in msec, from the start of the trigger to the beginning of data acquisition for this image. Required if Series Type (0054,1000), Value 1 is GATED. + + + Nominal duration per individual frame, in msec. Required if Series Type (0054,1000), Value 1 is GATED. See C.8.9.4.1.3 for explanation. +
The Frame Time (0018,1063) is the explicit duration of the gated frame when Cardiac Framing Type (0018,1064) is equal to FORW or BACK. Frame Time (0018,1063) is the nominal duration of the gated frame when Cardiac Framing Type (0018,1064) is equal to PCNT. +
+
+ + R-R interval lower limit for beat rejection, in msec. Required if Series Type (0054,1000), Value 1 is GATED and Beat Rejection Flag (0018,1080) is Y. + + + R-R interval upper limit for beat rejection, in msec. Required if Series Type (0054,1000), Value 1 is GATED and Beat Rejection Flag (0018,1080) is Y. + + + Specifies whether an Image has undergone lossy compression. Enumerated values: +00 = Image has NOT been subjected to lossy compression. +01 = Image has been subjected to lossy compression. +See C.7.6.1.1.5. +Required if Lossy Compression has been performed on the image. +
The Attribute Lossy Image Compression (0028,2110) conveys that the Image has undergone lossy compression. It provides a means to record that the Image has been compressed (at a point in its lifetime) with a lossy algorithm and changes have been introduced into the pixel data. Once the value has been set to “01â€, it shall not be reset. +Note: If an image is compressed with a lossy algorithm, the attribute Lossy Image Compression (0028,2110) is set to “01â€. Subsequently, if the image is decompressed and transferred in uncompressed format, this attribute value remains “01â€. + +The value of the Lossy Image Compression (0028,2110) Attribute in SOP Instances containing multiple frames in which one or more of the frames have undergone lossy compression shall be “01â€. +Note: It is recommended that the applicable frames be noted in the Attribute Derivation Description (0008,2111). + +If an image is originally obtained as a lossy compressed image from the sensor, then Lossy Image Compression (0028,2110) is set to “01†and Value 1 of the Attribute Image Type (0008,0008) shall be set to ORIGINAL. +If an image is a compressed version of another image, Lossy Image Compression (0028,2110) is set to “01â€, Value 1 of the Attribute Image Type (0008,0008) shall be set to DERIVED, and if the predecessor was a DICOM image, then the Image shall receive a new SOP Instance UID. +Note: 1. It is recommended that the approximate compression ratio be provided in the Attribute Derivation Description (0008,2111). Furthermore, it is recommended that Derivation Description (0008,2111) be used to indicate when pixel data changes might affect professional interpretation. (see C.7.6.1.1.3). + 2. The attribute Lossy Image Compression (0028,2110) is defined as Type 3 for backward compatibility with existing IODs. It is expected to be required (i.e., defined as Type 1C) for new Image IODs and for existing IODs that undergo a major revision (e.g. a new IOD is specified). +The Defined Terms for Lossy Image Compression Method (0028,2114) are: +ISO_10918_1 = JPEG Lossy Compression +ISO_14495_1 = JPEG-LS Near-lossless Compression +ISO_15444_1 = JPEG 2000 Irreversible Compression +ISO_13818_2 = MPEG2 Compression + +
+
+ + An index identifying the position of this image within a PET Series. See C.8.9.4.1.9 for explanation. +
Image Index (0054,1330) is an index identifying the position of this image within a PET Series. +Note: The scheme for encoding Image Index (0054,1330) is as follows. Images within a PET Series can be viewed as a multi-dimensional array whose possible dimensions include R-R Intervals, Time Slots, Time Slices, and Slices. The dimensions of the array are defined by the Series Type (0054,1000) Value 1. Each dimension of the array has an index that identifies the position of this image in the array. The indices are: R-R Interval Index, Time Slot Index, Time Slice Index, Slice Index. The indices are calculated as follows: + + +Using these index values the position of this image within the multi-dimensional array (the Image Index (0054,1330)) is calculated as follows: + +
+
+ + The date the acquisition of data that resulted in this image started. See C.8.9.4.1.4 for specialization. +
For PET Images, Acquisition Date (0008,0022) and Acquisition Time (0008,0032) are specified to be Type 2. The Acquisition Date (0008,0022) and Acquisition Time (0008,0032) use the same time base as Series Time (0008,0031). +For Series Type (0054,1000) Value 1 equal to STATIC, WHOLE BODY, or DYNAMIC, the Acquisition Time (0008,0032) is the real-world beginning of the accumulation of events into this Image. For STATIC, WHOLE BODY, or DYNAMIC Series, the Acquisition Time (0008,0032) may vary from Image to Image within a PET Series. +For Series Type (0054,1000) Value 1 equal to GATED, the Acquisition Time (0008,0032) is the real-world beginning of the capability of accumulating events into this Image. (The actual accumulation of events has only occurred during an R-R Interval.) For GATED Series, the Acquisition Time (0008,0032) shall not vary from Image to Image within a PET Series. +
+
+ + The time the acquisition of data that resulted in this image started. See C.8.9.4.1.4 for specialization. +
For PET Images, Acquisition Date (0008,0022) and Acquisition Time (0008,0032) are specified to be Type 2. The Acquisition Date (0008,0022) and Acquisition Time (0008,0032) use the same time base as Series Time (0008,0031). +For Series Type (0054,1000) Value 1 equal to STATIC, WHOLE BODY, or DYNAMIC, the Acquisition Time (0008,0032) is the real-world beginning of the accumulation of events into this Image. For STATIC, WHOLE BODY, or DYNAMIC Series, the Acquisition Time (0008,0032) may vary from Image to Image within a PET Series. +For Series Type (0054,1000) Value 1 equal to GATED, the Acquisition Time (0008,0032) is the real-world beginning of the capability of accumulating events into this Image. (The actual accumulation of events has only occurred during an R-R Interval.) For GATED Series, the Acquisition Time (0008,0032) shall not vary from Image to Image within a PET Series. +
+
+ + Elapsed time of the data acquisition for this image, in msec. See C.8.9.4.1.6 for explanation. +
The accumulation of counts for a PET Image shall occur entirely between: +(1) the acquisition starting time (as specified by Acquisition Date (0008,0022) and Acquisition Time (0008,0032)), and +(2) the acquisition ending time, which is equal to the acquisition starting time in (1) plus the Actual Frame Duration (0018,1242). +If the Series Type (0054,1000), Value 1 is GATED, then the actual accumulation of counts has only occurred during an R-R Interval. +
+
+ + Average duration of accepted beats, in msec, of the R-R interval. + + + Number of heartbeats that fall within Low R-R Value (0018,1081) and High R-R Value (0018,1082), and were therefore accepted and contribute coincidence events to this R-R Interval. + + + Number of heartbeats that fall outside Low R-R Value (0018,1081) and High R-R Value (0018,1082), and do not contribute coincidence events to this R-R Interval. However, they may contribute coincidence events to other R-R Intervals. + + + The sum of events that occur in the primary event channel. The counts include Trues +Scatter+ Randoms if Randoms Correction Method (0054,1100) is NONE; otherwise the counts are Trues +Scatter. + + + Sum of counts accumulated in secondary channels. See C.8.9.4.1.7 for explanation. +
Secondary Counts Accumulated (0054,1311) is multi-valued and, if supplied, has Values corresponding to the Secondary Counts Type (0054,1220). The number and order of the Values in Secondary Counts Accumulated (0054,1311) shall be the same as Secondary Counts Type (0054,1220). +
+
+ + The slice-to-slice sensitivity correction factor that was used to correct this image. The value shall be one if no slice sensitivity correction was applied. + + + The decay factor that was used to scale this image. Required if Decay Correction (0054,1102) is other than NONE. If decay correction is applied, all images in the Series shall be decay corrected to the same time. + + + Factor that was used to scale this image from counts/sec to Bq/ml using a dose calibrator. The value shall be one if no dose calibration was applied. See C.8.9.4.1.8 for explanation. +
The Dose Calibration Factor (0054,1322) is the factor that was used to scale this image from counts/sec to Bq/ml using an external dose calibrator. The value shall be one if no dose calibration was applied. The application of a dose calibration correction is specified by Corrected Image (0028,0051) equal to DCAL. +Note: Dose Calibration Factor (0054,1322) is not equal to the inverse of the sensitivity (kcps/Bq/ml) of the scanner, which is usually measured for a given radiopharmaceutical distribution and excluding the effects of attenuation. + +
+
+ + An estimate of the fraction of acquired counts that were due to scatter and were corrected in this image. The value shall be zero if no scatter correction was applied. + + + The average dead time correction factor that was applied to this image. The value shall be one if no dead time correction was applied. + + + + Describes the anatomical direction that slices are progressing as the slices are considered in order (as defined by the Slice Index. See section C.8.9.4.1.9 for a definition of Slice Index). Meaningful only for cardiac images. +When View Code Sequence (0054,0220) indicates a short axis view, then Enumerated Values are: +APEX_TO_BASE +BASE_TO_APEX + + + Sequence that describes the projection of the anatomic region of interest. +Only a single Item shall be permitted in this sequence. + + + + View Modifier. +Required if needed to fully specify the View. +Only a single Item shall be permitted in this sequence. + + +
+ + + Type of equipment that originally acquired the data used to create the images in this Series. +Enumerated Values: +DX +PX +IO +MG +See section C.7.3.1.1.1 for further explanation. + + + Uniquely identifies the Performed Procedure Step SOP Instance to which the Series is related (e.g. a Modality or General-Purpose Performed Procedure Step SOP Instance). The Sequence shall have one Item. +Required if the Modality Performed Procedure Step SOP Class, General Purpose Performed Procedure Step SOP Class is supported. + + + + Identifies the intent of the images that are contained within this Series. +Enumerated Values: +FOR PRESENTATION +FOR PROCESSING +See C.8.11.1.1.1 for further explanation. +
Presentation Intent Type (0008,0068) shall identify the intent for the purposes of display or other presentation of all Images within this Series. +Notes: 1. Since this is a Series level attribute, all Images within a Series have the same value for this Attribute. + 2. The intent of this restriction is to ensure that FOR PRESENTATION and FOR PROCESSING images are placed in separate Series, so that no confusion can arise as to which images are suitable for diagnostic reading as determined by local policy. + +A Series of Images intended for viewing by an observer, after application of any grayscale transformations specified in the image object such as VOI LUT, shall have an Enumerated Value of FOR PRESENTATION. +Notes: 1. These images may still be of Image Type (0008,0008) ORIGINAL rather than DERIVED despite the possibility that they may have undergone some processing, such as unsharp masking. In this case a DERIVED image would have undergone yet further processing to make it substantially different from the original. See Figure C.8-13. + 2. These images may still be subjected to processing or further processing, if appropriate, depending on the application. + 3. These images are intended for display on a device, without (further) processing, since that device may not be capable of image processing. The quality of the displayed image or its suitability for any purpose is beyond the scope of the DICOM Standard. + +Images that have been corrected to account for characteristics of the detector but which are intended to be further processed before being displayed, shall have an Enumerated Value of FOR PROCESSING. +Note: This type is provided to allow the functions of image acquisition and image processing for presentation to be separated and yet have images conveyed between the two processes using a DICOM object. Individual sites or users may choose to substitute their own specialized processing in place of that supplied by the implementor. + Images available at this stage of processing may be useful for quality control and problem solving purposes, as well as academic research. + Images of this type may also be archived, retrieved and processed with different algorithms or parameters in order to alter the appearance of specific features for clinical purposes. + The nature of the detector correction that may have been applied before sending an image of type FOR PROCESSING is not specified. In particular, acquisitions that acquire several sets of matrices of pixel values (such as image data, gain offset and a defect map) must perform some processing (detector correction) before a DX Image object can be instantiated. + The nature of the processing that may have been applied before sending an image of type FOR PRESENTATION is also not specified. + It is expected that individual implementors will use Private Attributes to convey specifics of the processing applied that may be of use for further processing by those aware of the parameters and algorithms. The diversity of detector types and processing algorithms make it undesirable to standardize such parameters. + Whether or not the spatial locations of all pixels are preserved during the processing of the source image that resulted in the current image can be indicated by Spatial Locations Preserved (0028,135A) in a Source Image Sequence (0008,2112) reference from the FOR PRESENTATION image to a FOR PROCESSING predecessor. + +If images from the same exposure exist with different Values of Presentation Intent Type (0008,0068), then they shall have different SOP Instance UIDs. +Notes: 1. Source Image Sequence (0008,2112) may be used to relate these images. + 2. The SOP Class UIDs of the two images will also be different. + +
+
+
+ + + Laterality of (possibly paired) body part (as described in Anatomic Region Sequence (0008,2218)) examined. +Enumerated Values: +R = right +L = left +U = unpaired +B = both left and right + +Note: This Attribute is mandatory, in order to ensure that images may be positioned correctly relative to one another for display. +Shall be consistent with any laterality information contained in Primary Anatomic Structure Modifier Sequence (0008,2230), if present. +Note: Laterality (0020,0060) is a Series level Attribute and must be the same for all Images in the Series, hence it must be absent. + + + + + + Image identification characteristics. +See C.8.11.3.1.1 for specialization. +
Value 1 shall identify the Pixel Data Characteristics in accordance with Section C.7.6.1.1.2 where the Enumerated Values are defined to be ORIGINAL or DERIVED. +Note: DX images may still be of type ORIGINAL rather than DERIVED despite the possibility that they may have undergone some processing. In this case a DERIVED image would have undergone yet further processing to make it substantially different from the original. + +Value 2 shall identify the Patient Examination Characteristics in accordance with Section C.7.6.1.1.2 where the Enumerated Values are defined to be PRIMARY or SECONDARY. +Note: DX images generally use PRIMARY value for images captured from patient exposure. + +If images from the same exposure exist with different Values of Image Type, then they shall have different SOP Instance UIDs. +Note: Source Image Sequence (0008,2112) may be used to relate these images. + +Value 3 (which is specific to the IOD) shall be present and have zero length (null value). +Other Values (4 and beyond) are optional and implementation specific. +
+
+ + Number of samples in this image. Shall have an Enumerated Value of 1. + + + Specifies the intended interpretation of the pixel data. +Enumerated Values: +MONOCHROME1 +MONOCHROME2 + + + Number of bits allocated for each pixel sample. +Enumerated Values: 8, 16 + + + Number of bits stored for each pixel sample. +Enumerated Values: 6 to 16 + + + Most significant bit for pixel sample data. +Shall have an Enumerated Value of one less than the value in Bit Stored (0028,0101). + + + Data representation of the pixel samples. +Shall have the Enumerated Value: +0000H = Unsigned Integer. + + + The relationship between the Pixel sample values and the X-Ray beam intensity. +Enumerated Values: +LIN = Linearly proportional to X-Ray beam intensity +LOG = Logarithmically proportional to X-Ray beam intensity +See C.8.11.3.1.2 for further explanation. +
Pixel Intensity Relationship (0028,1040) and Pixel Intensity Relationship Sign (0028,1041) describe how the stored pixel values in Pixel Data (7FE0,0010) are related to the X-Ray beam intensity incident on the detector. +They do not define a transformation intended to be applied to the pixel data for presentation. +Note: For example, if Pixel Intensity Relationship (0028,1040) is LIN and Pixel Intensity Relationship Sign (0028,1041) is -1, then lower values of Pixel Data (7FE0,0010) indicate higher X-Ray beam intensities corresponding to less radiographically dense regions projected on the image such as through air, and higher values of Pixel Data (7FE0,0010) indicate lower X-Ray beam intensities corresponding to more radiographically dense regions projected on the image such as through bone and radio-opaque contrast agents. + +The transformation to be applied to the pixel data for presentation is defined by the successive application of the conceptual Modality LUT, the VOI Attributes and the conceptual Presentation LUT. This shall result in the output of P-Values. +Rescale Slope (0028,1053) and Rescale Intercept (0028,1052) define a linear subset of a conceptual Modality LUT transformation. For IODs that include this Module, these Attributes define an identity transformation. IODs that include the DX Image Module shall not include the Modality LUT Module. +The Presentation LUT Shape (2050,0020) defines a subset of a conceptual Presentation LUT. For IODs that include this Module, this Attribute defines an identity transformation or inverse identity transformation. IODs that include the DX Image Module shall not include the Presentation LUT Module. +Photometric Interpretation (0028,0004) indicates whether lower values that are the output of the VOI Attributes should be displayed as darker or lighter. Since the output of the equivalent of a conceptual Presentation LUT is in P-Values, which are defined in PS 3.14 such that lower values correspond to lower luminance levels, then the definition of the Presentation LUT Shape (2050,0020), otherwise intended to be an identity transformation, must take into account the effect of the value specified for Photometric Interpretation (0028,0004). +Note: Regardless of the values of Pixel Intensity Relationship (0028,1040) and Pixel Intensity Relationship Sign (0028,1041), the grayscale transformations to be applied to the Pixel Data (7FE0,0010) are defined by the equivalent of the Modality LUT (Rescale Slope (0028,1053) and Rescale Intercept (0028,1052)), Value of Interest Attributes, Photometric Interpretation (0028,0004) and the equivalent of the Presentation LUT (Presentation LUT Shape (2050,0020)). However, the combination of the grayscale transformations and the description of the pixel intensity relationship, together define whether, for example, air is expected to be displayed as black or white. + +
+
+ + The sign of the relationship between the Pixel sample values stored in Pixel Data (7FE0,0010) and the X-Ray beam intensity. +Enumerated Values; +1 = Lower pixel values correspond to less X-Ray beam intensity +-1 = Higher pixel values correspond to less X-Ray beam intensity +See C.8.11.3.1.2 for further explanation. +
Pixel Intensity Relationship (0028,1040) and Pixel Intensity Relationship Sign (0028,1041) describe how the stored pixel values in Pixel Data (7FE0,0010) are related to the X-Ray beam intensity incident on the detector. +They do not define a transformation intended to be applied to the pixel data for presentation. +Note: For example, if Pixel Intensity Relationship (0028,1040) is LIN and Pixel Intensity Relationship Sign (0028,1041) is -1, then lower values of Pixel Data (7FE0,0010) indicate higher X-Ray beam intensities corresponding to less radiographically dense regions projected on the image such as through air, and higher values of Pixel Data (7FE0,0010) indicate lower X-Ray beam intensities corresponding to more radiographically dense regions projected on the image such as through bone and radio-opaque contrast agents. + +The transformation to be applied to the pixel data for presentation is defined by the successive application of the conceptual Modality LUT, the VOI Attributes and the conceptual Presentation LUT. This shall result in the output of P-Values. +Rescale Slope (0028,1053) and Rescale Intercept (0028,1052) define a linear subset of a conceptual Modality LUT transformation. For IODs that include this Module, these Attributes define an identity transformation. IODs that include the DX Image Module shall not include the Modality LUT Module. +The Presentation LUT Shape (2050,0020) defines a subset of a conceptual Presentation LUT. For IODs that include this Module, this Attribute defines an identity transformation or inverse identity transformation. IODs that include the DX Image Module shall not include the Presentation LUT Module. +Photometric Interpretation (0028,0004) indicates whether lower values that are the output of the VOI Attributes should be displayed as darker or lighter. Since the output of the equivalent of a conceptual Presentation LUT is in P-Values, which are defined in PS 3.14 such that lower values correspond to lower luminance levels, then the definition of the Presentation LUT Shape (2050,0020), otherwise intended to be an identity transformation, must take into account the effect of the value specified for Photometric Interpretation (0028,0004). +Note: Regardless of the values of Pixel Intensity Relationship (0028,1040) and Pixel Intensity Relationship Sign (0028,1041), the grayscale transformations to be applied to the Pixel Data (7FE0,0010) are defined by the equivalent of the Modality LUT (Rescale Slope (0028,1053) and Rescale Intercept (0028,1052)), Value of Interest Attributes, Photometric Interpretation (0028,0004) and the equivalent of the Presentation LUT (Presentation LUT Shape (2050,0020)). However, the combination of the grayscale transformations and the description of the pixel intensity relationship, together define whether, for example, air is expected to be displayed as black or white. + +
+
+ + The value b in the relationship between stored values (SV) in Pixel Data (7FE0,0010) and the output units specified in Rescale Type (0028,1054). +Output units = m*SV + b. +Enumerated Value: 0 +See C.8.11.3.1.2 for further explanation. +
Pixel Intensity Relationship (0028,1040) and Pixel Intensity Relationship Sign (0028,1041) describe how the stored pixel values in Pixel Data (7FE0,0010) are related to the X-Ray beam intensity incident on the detector. +They do not define a transformation intended to be applied to the pixel data for presentation. +Note: For example, if Pixel Intensity Relationship (0028,1040) is LIN and Pixel Intensity Relationship Sign (0028,1041) is -1, then lower values of Pixel Data (7FE0,0010) indicate higher X-Ray beam intensities corresponding to less radiographically dense regions projected on the image such as through air, and higher values of Pixel Data (7FE0,0010) indicate lower X-Ray beam intensities corresponding to more radiographically dense regions projected on the image such as through bone and radio-opaque contrast agents. + +The transformation to be applied to the pixel data for presentation is defined by the successive application of the conceptual Modality LUT, the VOI Attributes and the conceptual Presentation LUT. This shall result in the output of P-Values. +Rescale Slope (0028,1053) and Rescale Intercept (0028,1052) define a linear subset of a conceptual Modality LUT transformation. For IODs that include this Module, these Attributes define an identity transformation. IODs that include the DX Image Module shall not include the Modality LUT Module. +The Presentation LUT Shape (2050,0020) defines a subset of a conceptual Presentation LUT. For IODs that include this Module, this Attribute defines an identity transformation or inverse identity transformation. IODs that include the DX Image Module shall not include the Presentation LUT Module. +Photometric Interpretation (0028,0004) indicates whether lower values that are the output of the VOI Attributes should be displayed as darker or lighter. Since the output of the equivalent of a conceptual Presentation LUT is in P-Values, which are defined in PS 3.14 such that lower values correspond to lower luminance levels, then the definition of the Presentation LUT Shape (2050,0020), otherwise intended to be an identity transformation, must take into account the effect of the value specified for Photometric Interpretation (0028,0004). +Note: Regardless of the values of Pixel Intensity Relationship (0028,1040) and Pixel Intensity Relationship Sign (0028,1041), the grayscale transformations to be applied to the Pixel Data (7FE0,0010) are defined by the equivalent of the Modality LUT (Rescale Slope (0028,1053) and Rescale Intercept (0028,1052)), Value of Interest Attributes, Photometric Interpretation (0028,0004) and the equivalent of the Presentation LUT (Presentation LUT Shape (2050,0020)). However, the combination of the grayscale transformations and the description of the pixel intensity relationship, together define whether, for example, air is expected to be displayed as black or white. + +
+
+ + m in the equation specified by Rescale Intercept (0028,1052). +Enumerated Value: 1 +See C.8.11.3.1.2 for further explanation. +
Pixel Intensity Relationship (0028,1040) and Pixel Intensity Relationship Sign (0028,1041) describe how the stored pixel values in Pixel Data (7FE0,0010) are related to the X-Ray beam intensity incident on the detector. +They do not define a transformation intended to be applied to the pixel data for presentation. +Note: For example, if Pixel Intensity Relationship (0028,1040) is LIN and Pixel Intensity Relationship Sign (0028,1041) is -1, then lower values of Pixel Data (7FE0,0010) indicate higher X-Ray beam intensities corresponding to less radiographically dense regions projected on the image such as through air, and higher values of Pixel Data (7FE0,0010) indicate lower X-Ray beam intensities corresponding to more radiographically dense regions projected on the image such as through bone and radio-opaque contrast agents. + +The transformation to be applied to the pixel data for presentation is defined by the successive application of the conceptual Modality LUT, the VOI Attributes and the conceptual Presentation LUT. This shall result in the output of P-Values. +Rescale Slope (0028,1053) and Rescale Intercept (0028,1052) define a linear subset of a conceptual Modality LUT transformation. For IODs that include this Module, these Attributes define an identity transformation. IODs that include the DX Image Module shall not include the Modality LUT Module. +The Presentation LUT Shape (2050,0020) defines a subset of a conceptual Presentation LUT. For IODs that include this Module, this Attribute defines an identity transformation or inverse identity transformation. IODs that include the DX Image Module shall not include the Presentation LUT Module. +Photometric Interpretation (0028,0004) indicates whether lower values that are the output of the VOI Attributes should be displayed as darker or lighter. Since the output of the equivalent of a conceptual Presentation LUT is in P-Values, which are defined in PS 3.14 such that lower values correspond to lower luminance levels, then the definition of the Presentation LUT Shape (2050,0020), otherwise intended to be an identity transformation, must take into account the effect of the value specified for Photometric Interpretation (0028,0004). +Note: Regardless of the values of Pixel Intensity Relationship (0028,1040) and Pixel Intensity Relationship Sign (0028,1041), the grayscale transformations to be applied to the Pixel Data (7FE0,0010) are defined by the equivalent of the Modality LUT (Rescale Slope (0028,1053) and Rescale Intercept (0028,1052)), Value of Interest Attributes, Photometric Interpretation (0028,0004) and the equivalent of the Presentation LUT (Presentation LUT Shape (2050,0020)). However, the combination of the grayscale transformations and the description of the pixel intensity relationship, together define whether, for example, air is expected to be displayed as black or white. + +
+
+ + Specifies the output units of Rescale Slope (0028,1053) and Rescale Intercept (0028,1052). +Enumerated Value: US = Unspecified +See C.8.11.3.1.2 for further explanation. +
Pixel Intensity Relationship (0028,1040) and Pixel Intensity Relationship Sign (0028,1041) describe how the stored pixel values in Pixel Data (7FE0,0010) are related to the X-Ray beam intensity incident on the detector. +They do not define a transformation intended to be applied to the pixel data for presentation. +Note: For example, if Pixel Intensity Relationship (0028,1040) is LIN and Pixel Intensity Relationship Sign (0028,1041) is -1, then lower values of Pixel Data (7FE0,0010) indicate higher X-Ray beam intensities corresponding to less radiographically dense regions projected on the image such as through air, and higher values of Pixel Data (7FE0,0010) indicate lower X-Ray beam intensities corresponding to more radiographically dense regions projected on the image such as through bone and radio-opaque contrast agents. + +The transformation to be applied to the pixel data for presentation is defined by the successive application of the conceptual Modality LUT, the VOI Attributes and the conceptual Presentation LUT. This shall result in the output of P-Values. +Rescale Slope (0028,1053) and Rescale Intercept (0028,1052) define a linear subset of a conceptual Modality LUT transformation. For IODs that include this Module, these Attributes define an identity transformation. IODs that include the DX Image Module shall not include the Modality LUT Module. +The Presentation LUT Shape (2050,0020) defines a subset of a conceptual Presentation LUT. For IODs that include this Module, this Attribute defines an identity transformation or inverse identity transformation. IODs that include the DX Image Module shall not include the Presentation LUT Module. +Photometric Interpretation (0028,0004) indicates whether lower values that are the output of the VOI Attributes should be displayed as darker or lighter. Since the output of the equivalent of a conceptual Presentation LUT is in P-Values, which are defined in PS 3.14 such that lower values correspond to lower luminance levels, then the definition of the Presentation LUT Shape (2050,0020), otherwise intended to be an identity transformation, must take into account the effect of the value specified for Photometric Interpretation (0028,0004). +Note: Regardless of the values of Pixel Intensity Relationship (0028,1040) and Pixel Intensity Relationship Sign (0028,1041), the grayscale transformations to be applied to the Pixel Data (7FE0,0010) are defined by the equivalent of the Modality LUT (Rescale Slope (0028,1053) and Rescale Intercept (0028,1052)), Value of Interest Attributes, Photometric Interpretation (0028,0004) and the equivalent of the Presentation LUT (Presentation LUT Shape (2050,0020)). However, the combination of the grayscale transformations and the description of the pixel intensity relationship, together define whether, for example, air is expected to be displayed as black or white. + +
+
+ + Specifies an identity transformation for the Presentation LUT, other than to account for the value of Photometric Interpretation (0028,0004), such that the output of all grayscale transformations defined in the IOD containing this Module are defined to be P-Values. +Enumerated Values: +IDENTITY - output is in P-Values - shall be used if Photometric Interpretation (0028,0004) is MONOCHROME2. +INVERSE - output after inversion is in P-Values - shall be used if Photometric Interpretation (0028,0004) is MONOCHROME1. +See C.8.11.3.1.2 for further explanation. +
Pixel Intensity Relationship (0028,1040) and Pixel Intensity Relationship Sign (0028,1041) describe how the stored pixel values in Pixel Data (7FE0,0010) are related to the X-Ray beam intensity incident on the detector. +They do not define a transformation intended to be applied to the pixel data for presentation. +Note: For example, if Pixel Intensity Relationship (0028,1040) is LIN and Pixel Intensity Relationship Sign (0028,1041) is -1, then lower values of Pixel Data (7FE0,0010) indicate higher X-Ray beam intensities corresponding to less radiographically dense regions projected on the image such as through air, and higher values of Pixel Data (7FE0,0010) indicate lower X-Ray beam intensities corresponding to more radiographically dense regions projected on the image such as through bone and radio-opaque contrast agents. + +The transformation to be applied to the pixel data for presentation is defined by the successive application of the conceptual Modality LUT, the VOI Attributes and the conceptual Presentation LUT. This shall result in the output of P-Values. +Rescale Slope (0028,1053) and Rescale Intercept (0028,1052) define a linear subset of a conceptual Modality LUT transformation. For IODs that include this Module, these Attributes define an identity transformation. IODs that include the DX Image Module shall not include the Modality LUT Module. +The Presentation LUT Shape (2050,0020) defines a subset of a conceptual Presentation LUT. For IODs that include this Module, this Attribute defines an identity transformation or inverse identity transformation. IODs that include the DX Image Module shall not include the Presentation LUT Module. +Photometric Interpretation (0028,0004) indicates whether lower values that are the output of the VOI Attributes should be displayed as darker or lighter. Since the output of the equivalent of a conceptual Presentation LUT is in P-Values, which are defined in PS 3.14 such that lower values correspond to lower luminance levels, then the definition of the Presentation LUT Shape (2050,0020), otherwise intended to be an identity transformation, must take into account the effect of the value specified for Photometric Interpretation (0028,0004). +Note: Regardless of the values of Pixel Intensity Relationship (0028,1040) and Pixel Intensity Relationship Sign (0028,1041), the grayscale transformations to be applied to the Pixel Data (7FE0,0010) are defined by the equivalent of the Modality LUT (Rescale Slope (0028,1053) and Rescale Intercept (0028,1052)), Value of Interest Attributes, Photometric Interpretation (0028,0004) and the equivalent of the Presentation LUT (Presentation LUT Shape (2050,0020)). However, the combination of the grayscale transformations and the description of the pixel intensity relationship, together define whether, for example, air is expected to be displayed as black or white. + +
+
+ + Specifies whether an Image has undergone lossy compression. Enumerated Values: +00 = Image has NOT been subjected to lossy compression. +01 = Image has been subjected to lossy compression. +See C.7.6.1.1.5 for further explanation. +
The Attribute Lossy Image Compression (0028,2110) conveys that the Image has undergone lossy compression. It provides a means to record that the Image has been compressed (at a point in its lifetime) with a lossy algorithm and changes have been introduced into the pixel data. Once the value has been set to “01â€, it shall not be reset. +Note: If an image is compressed with a lossy algorithm, the attribute Lossy Image Compression (0028,2110) is set to “01â€. Subsequently, if the image is decompressed and transferred in uncompressed format, this attribute value remains “01â€. + +The value of the Lossy Image Compression (0028,2110) Attribute in SOP Instances containing multiple frames in which one or more of the frames have undergone lossy compression shall be “01â€. +Note: It is recommended that the applicable frames be noted in the Attribute Derivation Description (0008,2111). + +If an image is originally obtained as a lossy compressed image from the sensor, then Lossy Image Compression (0028,2110) is set to “01†and Value 1 of the Attribute Image Type (0008,0008) shall be set to ORIGINAL. +If an image is a compressed version of another image, Lossy Image Compression (0028,2110) is set to “01â€, Value 1 of the Attribute Image Type (0008,0008) shall be set to DERIVED, and if the predecessor was a DICOM image, then the Image shall receive a new SOP Instance UID. +Note: 1. It is recommended that the approximate compression ratio be provided in the Attribute Derivation Description (0008,2111). Furthermore, it is recommended that Derivation Description (0008,2111) be used to indicate when pixel data changes might affect professional interpretation. (see C.7.6.1.1.3). + 2. The attribute Lossy Image Compression (0028,2110) is defined as Type 3 for backward compatibility with existing IODs. It is expected to be required (i.e., defined as Type 1C) for new Image IODs and for existing IODs that undergo a major revision (e.g. a new IOD is specified). +The Defined Terms for Lossy Image Compression Method (0028,2114) are: +ISO_10918_1 = JPEG Lossy Compression +ISO_14495_1 = JPEG-LS Near-lossless Compression +ISO_15444_1 = JPEG 2000 Irreversible Compression +ISO_13818_2 = MPEG2 Compression + +
+
+ + See C.7.6.1.1.5 for further explanation. +Required if Lossy Compression has been performed on the Image. +
The Attribute Lossy Image Compression (0028,2110) conveys that the Image has undergone lossy compression. It provides a means to record that the Image has been compressed (at a point in its lifetime) with a lossy algorithm and changes have been introduced into the pixel data. Once the value has been set to “01â€, it shall not be reset. +Note: If an image is compressed with a lossy algorithm, the attribute Lossy Image Compression (0028,2110) is set to “01â€. Subsequently, if the image is decompressed and transferred in uncompressed format, this attribute value remains “01â€. + +The value of the Lossy Image Compression (0028,2110) Attribute in SOP Instances containing multiple frames in which one or more of the frames have undergone lossy compression shall be “01â€. +Note: It is recommended that the applicable frames be noted in the Attribute Derivation Description (0008,2111). + +If an image is originally obtained as a lossy compressed image from the sensor, then Lossy Image Compression (0028,2110) is set to “01†and Value 1 of the Attribute Image Type (0008,0008) shall be set to ORIGINAL. +If an image is a compressed version of another image, Lossy Image Compression (0028,2110) is set to “01â€, Value 1 of the Attribute Image Type (0008,0008) shall be set to DERIVED, and if the predecessor was a DICOM image, then the Image shall receive a new SOP Instance UID. +Note: 1. It is recommended that the approximate compression ratio be provided in the Attribute Derivation Description (0008,2111). Furthermore, it is recommended that Derivation Description (0008,2111) be used to indicate when pixel data changes might affect professional interpretation. (see C.7.6.1.1.3). + 2. The attribute Lossy Image Compression (0028,2110) is defined as Type 3 for backward compatibility with existing IODs. It is expected to be required (i.e., defined as Type 1C) for new Image IODs and for existing IODs that undergo a major revision (e.g. a new IOD is specified). +The Defined Terms for Lossy Image Compression Method (0028,2114) are: +ISO_10918_1 = JPEG Lossy Compression +ISO_14495_1 = JPEG-LS Near-lossless Compression +ISO_15444_1 = JPEG 2000 Irreversible Compression +ISO_13818_2 = MPEG2 Compression + +
+
+ + A text description of how this image was derived. +See C.8.11.3.1.4 for further explanation. +
If an Image is identified to be a Derived image in Image Type (0008,0008), Derivation Description (0008,2111) is an optional and implementation specific text description of the way the image was derived from an original image. As applied to DX images, it may be used to describe derivation operations such as edge enhancement, temporal filtering, digital subtraction, or other linear and non-linear transformations. +
+
+ + Indicates any visual processing performed on the images prior to exchange. +See C.8.11.3.1.3 for further explanation. +
Acquisition Device Processing Description (0018,1400) provides some indication in human readable text of the digital processing on the images before exchange. Examples of this processing are: edge enhanced, subtracted, time filtered, gamma corrected, convolved (spatially filtered). +
+
+ + Code representing the device-specific processing associated with the image (e.g. Organ Filtering code) +Note: This Code is manufacturer specific but provides useful annotation information to the knowledgeable observer. + + + Patient direction of the rows and columns of the image. +See C.7.6.1.1.1 for further explanation. +
The Patient Orientation (0020,0020) relative to the image plane shall be specified by two values that designate the anatomical direction of the positive row axis (left to right) and the positive column axis (top to bottom). The first entry is the direction of the rows, given by the direction of the last pixel in the first row from the first pixel in that row. The second entry is the direction of the columns, given by the direction of the last pixel in the first column from the first pixel in that column. +Anatomical direction shall be designated by the capital letters: A (anterior), P (posterior), R (right), L (left), H (head), F (foot). Each value of the orientation attribute shall contain at least one of these characters. If refinements in the orientation descriptions are to be specified, then they shall be designated by one or two additional letters in each value. Within each value, the letters shall be ordered with the principal orientation designated in the first character. +
+
+ + Indicates whether a reference object (phantom) of known size is present in the image and was used for calibration. Enumerated Values: +YES +NO +Device is identified using the Device module. See C.7.6.12 for further explanation. +
Table C.7-18 describes the Attributes of devices or calibration objects (e.g., catheters, markers, baskets) that are associated with a study and/or image. +Table C.7-18 +DEVICE MODULE ATTRIBUTES + +
+
+ + Indicates whether or not image contains sufficient burned in annotation to identify the patient and date the image was acquired. +Enumerated Values: +YES +NO + + + Defines a sequence of VOI LUTs. +See C.8.11.3.1.5 for further explanation. +One or more Items may be included in this Sequence. +Required if Presentation Intent Type (0008,0068) is FOR PRESENTATION and Window Center (0028,1050) is not present. May also be present if Window Center (0028,1050) is present. +
The Attributes of the VOI LUT Module (C.11.2) are specialized in the DX Image Module. +Window Center (0028,1050) and Window Width (0028,1051) specify a linear conversion (unless otherwise specified by the value of VOI LUT Function (0028,1056); see C.11.2.1.3) from the output of the (conceptual) Modality LUT values to the input to the (conceptual) Presentation LUT. Window Center contains the value that is the center of the window. Window Width contains the width of the window. +The application of the Window Center (0028,1050) and Window Width (0028,1051) shall not produce a signed result. +Note: If the Presentation LUT Shape (2050,0020) is IDENTITY, then the result of applying the Window Center (0028,1050) and Window Width (0028,1051) is P-Values. + +If multiple values are present, both Attributes shall have the same number of values and shall be considered as pairs. Multiple values indicate that multiple alternative views should be presented. +The VOI LUT Sequence specifes a (potentially non-linear) conversion from the output of the (conceptual) Modality LUT values to the input to the (conceptual) Presentation LUT. +If multiple items are present in VOI LUT Sequence (0028,3010), only one shall be applied. Multiple items indicate that multiple alternative views should be presented. +If any VOI LUT Attributes are included by an Image, a Window Width and Window Center or the VOI LUT Table, but not both, shall be applied to the Image for display. Inclusion of both indicates that multiple alternative views should be presented. +The three values of the LUT Descriptor (0028,3002) describe the format of the LUT Data (0028,3006). +The first value is the number of entries in the lookup table. +The second value is the first stored pixel value mapped. This pixel value is mapped to the first entry in the LUT. All image pixel values less than the first value mapped are also mapped to the first entry in the LUT Data. An image pixel value one greater than the first value mapped is mapped to the second entry in the LUT Data. Subsequent image pixel values are mapped to the subsequent entries in the LUT Data up to an image pixel value equal to number of entries + first value mapped - 1 which is mapped to the last entry in the LUT Data. Image pixel values greater than number of entries + first value mapped are also mapped to the last entry in the LUT Data. +The third value specifies the number of bits for each entry in the LUT Data (analogous to “bits storedâ€). It shall be between 10-16. The LUT Data shall be stored in a format equivalent to 16 “bits allocated†and “high bit†equal to “bits stored†- 1. The third value conveys the range of LUT entry values. These unsigned LUT entry values shall range between 0 and 2 n -1, where n is the third value of the LUT Descriptor. +Notes: 1. The third value is restricted in the VOI LUT Module to 8 or 16 but is specialized here. + 2. The first and second values are not specialized and are the same as in the VOI LUT Module. + +The LUT Data (0028,3006) contains the LUT entry values. +
+
+ + Specifies the format of the LUT Data in this Sequence. +See C.8.11.3.1.5 for further explanation. +Required if the VOI LUT Sequence (0028,3010) is sent. +
The Attributes of the VOI LUT Module (C.11.2) are specialized in the DX Image Module. +Window Center (0028,1050) and Window Width (0028,1051) specify a linear conversion (unless otherwise specified by the value of VOI LUT Function (0028,1056); see C.11.2.1.3) from the output of the (conceptual) Modality LUT values to the input to the (conceptual) Presentation LUT. Window Center contains the value that is the center of the window. Window Width contains the width of the window. +The application of the Window Center (0028,1050) and Window Width (0028,1051) shall not produce a signed result. +Note: If the Presentation LUT Shape (2050,0020) is IDENTITY, then the result of applying the Window Center (0028,1050) and Window Width (0028,1051) is P-Values. + +If multiple values are present, both Attributes shall have the same number of values and shall be considered as pairs. Multiple values indicate that multiple alternative views should be presented. +The VOI LUT Sequence specifes a (potentially non-linear) conversion from the output of the (conceptual) Modality LUT values to the input to the (conceptual) Presentation LUT. +If multiple items are present in VOI LUT Sequence (0028,3010), only one shall be applied. Multiple items indicate that multiple alternative views should be presented. +If any VOI LUT Attributes are included by an Image, a Window Width and Window Center or the VOI LUT Table, but not both, shall be applied to the Image for display. Inclusion of both indicates that multiple alternative views should be presented. +The three values of the LUT Descriptor (0028,3002) describe the format of the LUT Data (0028,3006). +The first value is the number of entries in the lookup table. +The second value is the first stored pixel value mapped. This pixel value is mapped to the first entry in the LUT. All image pixel values less than the first value mapped are also mapped to the first entry in the LUT Data. An image pixel value one greater than the first value mapped is mapped to the second entry in the LUT Data. Subsequent image pixel values are mapped to the subsequent entries in the LUT Data up to an image pixel value equal to number of entries + first value mapped - 1 which is mapped to the last entry in the LUT Data. Image pixel values greater than number of entries + first value mapped are also mapped to the last entry in the LUT Data. +The third value specifies the number of bits for each entry in the LUT Data (analogous to “bits storedâ€). It shall be between 10-16. The LUT Data shall be stored in a format equivalent to 16 “bits allocated†and “high bit†equal to “bits stored†- 1. The third value conveys the range of LUT entry values. These unsigned LUT entry values shall range between 0 and 2 n -1, where n is the third value of the LUT Descriptor. +Notes: 1. The third value is restricted in the VOI LUT Module to 8 or 16 but is specialized here. + 2. The first and second values are not specialized and are the same as in the VOI LUT Module. + +The LUT Data (0028,3006) contains the LUT entry values. +
+
+ + Free form text explanation of the meaning of the LUT. + + + LUT Data in this Sequence. +Required if the VOI LUT Sequence (0028,3010) is sent. + + + Defines a Window Center for display. +See C.8.11.3.1.5 for further explanation. +Required if Presentation Intent Type (0008,0068) is FOR PRESENTATION and VOI LUT Sequence (0028,3010) is not present. May also be present if VOI LUT Sequence (0028,3010) is present. +
The Attributes of the VOI LUT Module (C.11.2) are specialized in the DX Image Module. +Window Center (0028,1050) and Window Width (0028,1051) specify a linear conversion (unless otherwise specified by the value of VOI LUT Function (0028,1056); see C.11.2.1.3) from the output of the (conceptual) Modality LUT values to the input to the (conceptual) Presentation LUT. Window Center contains the value that is the center of the window. Window Width contains the width of the window. +The application of the Window Center (0028,1050) and Window Width (0028,1051) shall not produce a signed result. +Note: If the Presentation LUT Shape (2050,0020) is IDENTITY, then the result of applying the Window Center (0028,1050) and Window Width (0028,1051) is P-Values. + +If multiple values are present, both Attributes shall have the same number of values and shall be considered as pairs. Multiple values indicate that multiple alternative views should be presented. +The VOI LUT Sequence specifes a (potentially non-linear) conversion from the output of the (conceptual) Modality LUT values to the input to the (conceptual) Presentation LUT. +If multiple items are present in VOI LUT Sequence (0028,3010), only one shall be applied. Multiple items indicate that multiple alternative views should be presented. +If any VOI LUT Attributes are included by an Image, a Window Width and Window Center or the VOI LUT Table, but not both, shall be applied to the Image for display. Inclusion of both indicates that multiple alternative views should be presented. +The three values of the LUT Descriptor (0028,3002) describe the format of the LUT Data (0028,3006). +The first value is the number of entries in the lookup table. +The second value is the first stored pixel value mapped. This pixel value is mapped to the first entry in the LUT. All image pixel values less than the first value mapped are also mapped to the first entry in the LUT Data. An image pixel value one greater than the first value mapped is mapped to the second entry in the LUT Data. Subsequent image pixel values are mapped to the subsequent entries in the LUT Data up to an image pixel value equal to number of entries + first value mapped - 1 which is mapped to the last entry in the LUT Data. Image pixel values greater than number of entries + first value mapped are also mapped to the last entry in the LUT Data. +The third value specifies the number of bits for each entry in the LUT Data (analogous to “bits storedâ€). It shall be between 10-16. The LUT Data shall be stored in a format equivalent to 16 “bits allocated†and “high bit†equal to “bits stored†- 1. The third value conveys the range of LUT entry values. These unsigned LUT entry values shall range between 0 and 2 n -1, where n is the third value of the LUT Descriptor. +Notes: 1. The third value is restricted in the VOI LUT Module to 8 or 16 but is specialized here. + 2. The first and second values are not specialized and are the same as in the VOI LUT Module. + +The LUT Data (0028,3006) contains the LUT entry values. +
+
+ + Window Width for display. See C.8.11.3.1.5 for further explanation. +Required if Window Center (0028,1050) is sent. +
The Attributes of the VOI LUT Module (C.11.2) are specialized in the DX Image Module. +Window Center (0028,1050) and Window Width (0028,1051) specify a linear conversion (unless otherwise specified by the value of VOI LUT Function (0028,1056); see C.11.2.1.3) from the output of the (conceptual) Modality LUT values to the input to the (conceptual) Presentation LUT. Window Center contains the value that is the center of the window. Window Width contains the width of the window. +The application of the Window Center (0028,1050) and Window Width (0028,1051) shall not produce a signed result. +Note: If the Presentation LUT Shape (2050,0020) is IDENTITY, then the result of applying the Window Center (0028,1050) and Window Width (0028,1051) is P-Values. + +If multiple values are present, both Attributes shall have the same number of values and shall be considered as pairs. Multiple values indicate that multiple alternative views should be presented. +The VOI LUT Sequence specifes a (potentially non-linear) conversion from the output of the (conceptual) Modality LUT values to the input to the (conceptual) Presentation LUT. +If multiple items are present in VOI LUT Sequence (0028,3010), only one shall be applied. Multiple items indicate that multiple alternative views should be presented. +If any VOI LUT Attributes are included by an Image, a Window Width and Window Center or the VOI LUT Table, but not both, shall be applied to the Image for display. Inclusion of both indicates that multiple alternative views should be presented. +The three values of the LUT Descriptor (0028,3002) describe the format of the LUT Data (0028,3006). +The first value is the number of entries in the lookup table. +The second value is the first stored pixel value mapped. This pixel value is mapped to the first entry in the LUT. All image pixel values less than the first value mapped are also mapped to the first entry in the LUT Data. An image pixel value one greater than the first value mapped is mapped to the second entry in the LUT Data. Subsequent image pixel values are mapped to the subsequent entries in the LUT Data up to an image pixel value equal to number of entries + first value mapped - 1 which is mapped to the last entry in the LUT Data. Image pixel values greater than number of entries + first value mapped are also mapped to the last entry in the LUT Data. +The third value specifies the number of bits for each entry in the LUT Data (analogous to “bits storedâ€). It shall be between 10-16. The LUT Data shall be stored in a format equivalent to 16 “bits allocated†and “high bit†equal to “bits stored†- 1. The third value conveys the range of LUT entry values. These unsigned LUT entry values shall range between 0 and 2 n -1, where n is the third value of the LUT Descriptor. +Notes: 1. The third value is restricted in the VOI LUT Module to 8 or 16 but is specialized here. + 2. The first and second values are not specialized and are the same as in the VOI LUT Module. + +The LUT Data (0028,3006) contains the LUT entry values. +
+
+ + Free form explanation of the meaning of the Window Center and Width. Multiple values correspond to multiple Window Center and Width values. + +
+ + + + Time in mSec that the detector is active during acquisition of this image. +Note: This activation window overlaps the time of the X-Ray exposure as defined by Exposure Time (0018,1150) and Detector Activation Offset From Exposure (0018,7016). + + + Offset time in mSec that the detector becomes active after the X-Ray beam is turned on during acquisition of this image. May be negative. + + + Shape of the Field of View, that is the image pixels stored in Pixel Data (7FE0,0010). +Enumerated Values: +RECTANGLE +ROUND +HEXAGONAL + + + Dimensions in mm of the Field of View, that is the image pixels stored in Pixel Data (7FE0,0010). If Field of View Shape (0018,1147) is: +RECTANGLE: row dimension followed by column. +ROUND: diameter. +HEXAGONAL: diameter of a circumscribed circle. + + + Offset of the TLHC of a rectangle circumscribing the Field of View, that is the image pixels stored in Pixel Data (7FE0,0010), before rotation or flipping, from the TLHC of the physical detector area measured in physical detector pixels as a row offset followed by a column offset. +Required if Field of View Rotation (0018,7032) or Field of View Horizontal Flip (0018,7034) is present. +See C.8.11.4.1.1 for further explanation. +
The relationship between the Physical Detector Area, the Active Detector Area, the Field of View (what is stored in the Pixel Data (7FE0,0010)), the Exposed Area (after X-Ray Collimation) and the Displayed Area is illustrated in the following diagrams. +Note: Some of these Attributes relate the image data to manufacturer specific characteristics of the detector that may be used for quality control purposes, e.g. correlation of image artifacts with a detector defect map, analysis of noise performance, etc. + +The Displayed Area is defined in pixel coordinates relative to the stored image pixel values by the Attributes of the Display Shutter Module (see section C.7.6.11). If this Module is not present or supported, then the Displayed Area is equal to the Field of View. +The Exposed Area is defined in pixel coordinates relative to the stored image pixel values by the Attributes of the X-Ray Collimator Module (see section C.8.7.3). +For the Digital X-Ray IODs, the Field of View is usually rectangular in shape and the same size as the stored Pixel Data (7FE0,0010). The shape and size of the Field of View and the spacing of the pixels are defined by the following Attributes: +- Field of View Shape (0018,1147), +- Field of View Dimensions (0018,1149), +- Imager Pixel Spacing (0018,1164), +- Rows (0028,0010), +- Columns (0028,0011) + +The following Attributes define the relationship of the Field of View to the Physical Detector Area: +- Field of View Origin (0018,7030), +- Field of View Rotation (0018,7032), +- Field of View Horizontal Flip (0018,7034). + +For the Digital X-Ray IODs, the Active Area, i.e. that part of the detector matrix that was activated for this exposure, is usually rectangular in shape. The shape and size of the Active Area and the size and spacing of the detectors are defined by the following Attributes: +- Detector Active Shape (0018,7024), +- Detector Active Dimensions (0018,7026), +- Detector Element Physical Size (0018,7020), +- Detector Element Spacing (0018,7022). + +Notes: 1. The Detector Element Physical Size (0018,7020) and Detector Element Spacing (0018,7022) may be different if there are insensitive regions between each detector. + 2. This model of description is not able to accurately describe multiple matrices of detectors that are “tiled†to produce a single image. + +The following optional Attribute defines the relationship of the Active Area to the Physical Detector Area: +- Detector Active Origin (0018,7028). + +The relationship between detectors and stored image pixels is defined by Detector Binning (0018,701A) which specifies how many detectors, in each of the row and column directions, contribute to (are pooled or averaged to form) a single stored image pixel. +Note: Detector Binning (0018,701A) may have values less than one if sub-sampling is used to derive an image with higher spatial resolution than the detector matrix. + + + +Figure C.8-14 +Explanation of DX Detector Attributes + + + + +Figure C.8-15 +Explanation of DX Detector Attributes +
+
+ + Clockwise rotation in degrees of Field of View, that is the image pixels stored in Pixel Data (7FE0,0010), relative to the physical detector. +Enumerated Values: +0, 90, 180, 270 +Required if Field of View Horizontal Flip (0018,7034) is present. +See C.8.11.4.1.1 for further explanation. +
The relationship between the Physical Detector Area, the Active Detector Area, the Field of View (what is stored in the Pixel Data (7FE0,0010)), the Exposed Area (after X-Ray Collimation) and the Displayed Area is illustrated in the following diagrams. +Note: Some of these Attributes relate the image data to manufacturer specific characteristics of the detector that may be used for quality control purposes, e.g. correlation of image artifacts with a detector defect map, analysis of noise performance, etc. + +The Displayed Area is defined in pixel coordinates relative to the stored image pixel values by the Attributes of the Display Shutter Module (see section C.7.6.11). If this Module is not present or supported, then the Displayed Area is equal to the Field of View. +The Exposed Area is defined in pixel coordinates relative to the stored image pixel values by the Attributes of the X-Ray Collimator Module (see section C.8.7.3). +For the Digital X-Ray IODs, the Field of View is usually rectangular in shape and the same size as the stored Pixel Data (7FE0,0010). The shape and size of the Field of View and the spacing of the pixels are defined by the following Attributes: +- Field of View Shape (0018,1147), +- Field of View Dimensions (0018,1149), +- Imager Pixel Spacing (0018,1164), +- Rows (0028,0010), +- Columns (0028,0011) + +The following Attributes define the relationship of the Field of View to the Physical Detector Area: +- Field of View Origin (0018,7030), +- Field of View Rotation (0018,7032), +- Field of View Horizontal Flip (0018,7034). + +For the Digital X-Ray IODs, the Active Area, i.e. that part of the detector matrix that was activated for this exposure, is usually rectangular in shape. The shape and size of the Active Area and the size and spacing of the detectors are defined by the following Attributes: +- Detector Active Shape (0018,7024), +- Detector Active Dimensions (0018,7026), +- Detector Element Physical Size (0018,7020), +- Detector Element Spacing (0018,7022). + +Notes: 1. The Detector Element Physical Size (0018,7020) and Detector Element Spacing (0018,7022) may be different if there are insensitive regions between each detector. + 2. This model of description is not able to accurately describe multiple matrices of detectors that are “tiled†to produce a single image. + +The following optional Attribute defines the relationship of the Active Area to the Physical Detector Area: +- Detector Active Origin (0018,7028). + +The relationship between detectors and stored image pixels is defined by Detector Binning (0018,701A) which specifies how many detectors, in each of the row and column directions, contribute to (are pooled or averaged to form) a single stored image pixel. +Note: Detector Binning (0018,701A) may have values less than one if sub-sampling is used to derive an image with higher spatial resolution than the detector matrix. + + + +Figure C.8-14 +Explanation of DX Detector Attributes + + + + +Figure C.8-15 +Explanation of DX Detector Attributes +
+
+ + Whether or not a horizontal flip has been applied to the Field of View, that is the image pixels stored in Pixel Data (7FE0,0010), after rotation relative to the physical detector as described in Field of View Rotation (0018,7032). +Enumerated Values: +NO +YES +Required if Field of View Rotation (0018,7032) is present. +See C.8.11.4.1.1 for further explanation. +
The relationship between the Physical Detector Area, the Active Detector Area, the Field of View (what is stored in the Pixel Data (7FE0,0010)), the Exposed Area (after X-Ray Collimation) and the Displayed Area is illustrated in the following diagrams. +Note: Some of these Attributes relate the image data to manufacturer specific characteristics of the detector that may be used for quality control purposes, e.g. correlation of image artifacts with a detector defect map, analysis of noise performance, etc. + +The Displayed Area is defined in pixel coordinates relative to the stored image pixel values by the Attributes of the Display Shutter Module (see section C.7.6.11). If this Module is not present or supported, then the Displayed Area is equal to the Field of View. +The Exposed Area is defined in pixel coordinates relative to the stored image pixel values by the Attributes of the X-Ray Collimator Module (see section C.8.7.3). +For the Digital X-Ray IODs, the Field of View is usually rectangular in shape and the same size as the stored Pixel Data (7FE0,0010). The shape and size of the Field of View and the spacing of the pixels are defined by the following Attributes: +- Field of View Shape (0018,1147), +- Field of View Dimensions (0018,1149), +- Imager Pixel Spacing (0018,1164), +- Rows (0028,0010), +- Columns (0028,0011) + +The following Attributes define the relationship of the Field of View to the Physical Detector Area: +- Field of View Origin (0018,7030), +- Field of View Rotation (0018,7032), +- Field of View Horizontal Flip (0018,7034). + +For the Digital X-Ray IODs, the Active Area, i.e. that part of the detector matrix that was activated for this exposure, is usually rectangular in shape. The shape and size of the Active Area and the size and spacing of the detectors are defined by the following Attributes: +- Detector Active Shape (0018,7024), +- Detector Active Dimensions (0018,7026), +- Detector Element Physical Size (0018,7020), +- Detector Element Spacing (0018,7022). + +Notes: 1. The Detector Element Physical Size (0018,7020) and Detector Element Spacing (0018,7022) may be different if there are insensitive regions between each detector. + 2. This model of description is not able to accurately describe multiple matrices of detectors that are “tiled†to produce a single image. + +The following optional Attribute defines the relationship of the Active Area to the Physical Detector Area: +- Detector Active Origin (0018,7028). + +The relationship between detectors and stored image pixels is defined by Detector Binning (0018,701A) which specifies how many detectors, in each of the row and column directions, contribute to (are pooled or averaged to form) a single stored image pixel. +Note: Detector Binning (0018,701A) may have values less than one if sub-sampling is used to derive an image with higher spatial resolution than the detector matrix. + + + +Figure C.8-14 +Explanation of DX Detector Attributes + + + + +Figure C.8-15 +Explanation of DX Detector Attributes +
+
+ + Physical distance measured at the front plane of the detector housing between the center of each image pixel specified by a numeric pair - row spacing value(delimiter) column spacing value in mm. See 10.7.1.3 for further explanation of the value order. +The value of this attribute shall never be adjusted to account for correction for the effect of geometric magnification or calibration against an object of known size; Pixel Spacing (0028,0030) is specified for that purpose. + + + + Identifier of the cassette that contains the photostimulable phosphor plate, for CR acquisitions. + + + Identifier of the photostimulable phosphor plate, for CR acquisitions. + +
+ + + The type of detector used to acquire this image. +Defined Terms: +DIRECT = X-Ray photoconductor +SCINTILLATOR = Phosphor used +STORAGE = Storage phosphor +FILM = Scanned film/screen + + + The physical configuration of the detector. +Defined Terms: +AREA = single or tiled detector +SLOT = scanned slot, slit or spot + + + Free text description of detector. + + + Text description of operating mode of detector (implementation specific). + + + The ID or serial number of the detector used to acquire this image. + + + The date on which the detector used to acquire this image as identified in Detector ID (0018,700A) was last calibrated. + + + The time at which the detector used to acquire this image as identified in Detector ID (0018,700A) was last calibrated. + + + Total number of X-Ray exposures that have been made on the detector used to acquire this image as identified in Detector ID (0018,700A) since it was calibrated. + + + Total number of X-Ray exposures that have been made on the detector used to acquire this image as identified in Detector ID (0018,700A) since it was manufactured. + + + Time in Seconds since an exposure was last made on this detector prior to the acquisition of this image. + + + Number of active detectors used to generate a single pixel. Specified as number of row detectors per pixel then column. + + + Name of the manufacturer of the detector component of the acquisition system + + + Model name of the detector component of the acquisition system + + + Whether or not the detector is operating within normal tolerances during this image acquisition. +Enumerated Values: +YES +NO +Note: This flag is intended to indicate whether or not there may have been some compromise of the diagnostic quality of the image due to some condition such as over-temperature, etc. + + + Detector temperature during exposure in degrees Celsius. + + + Detector sensitivity in manufacturer specific units. +Note: This value is intended to provide a single location where manufacturer specific information can be found for annotation on a display or film, that has meaning to a knowledgeable observer. + + + + Physical dimensions of each detector element that comprises the detector matrix, in mm. +Expressed as row dimension followed by column. +Note: This may not be the same as Detector Element Spacing (0018,7022) due to the presence of spacing material between detector elements. + + + Physical distance between the center of each detector element, specified by a numeric pair - row spacing value(delimiter) column spacing value in mm. See 10.7.1.3 for further explanation of the value order. +Note: This may not be the same as the Imager Pixel Spacing (0018,1164), and should not be assumed to describe the stored image. + + + Shape of the active area. +Enumerated Value: +RECTANGLE +ROUND +HEXAGONAL +Note: This may be different from the Field of View Shape (0018,1147), and should not be assumed to describe the stored image. + + + Dimensions in mm of the active area. +If Detector Active Shape(0018,7024) is: +RECTANGLE: row dimension followed by column. +ROUND: diameter. +HEXAGONAL: diameter of a circumscribed circle. +Note: This may be different from the Field of View Dimensions (0018,1149), and should not be assumed to describe the stored image. + + + Offset of the TLHC of a rectangle circumscribing the active detector area from the TLHC of a rectangle circumscribing the physical detector area, measured in physical detector pixels as a row offset followed by a column offset. +See C.8.11.4.1.1 for further explanation. +
The relationship between the Physical Detector Area, the Active Detector Area, the Field of View (what is stored in the Pixel Data (7FE0,0010)), the Exposed Area (after X-Ray Collimation) and the Displayed Area is illustrated in the following diagrams. +Note: Some of these Attributes relate the image data to manufacturer specific characteristics of the detector that may be used for quality control purposes, e.g. correlation of image artifacts with a detector defect map, analysis of noise performance, etc. + +The Displayed Area is defined in pixel coordinates relative to the stored image pixel values by the Attributes of the Display Shutter Module (see section C.7.6.11). If this Module is not present or supported, then the Displayed Area is equal to the Field of View. +The Exposed Area is defined in pixel coordinates relative to the stored image pixel values by the Attributes of the X-Ray Collimator Module (see section C.8.7.3). +For the Digital X-Ray IODs, the Field of View is usually rectangular in shape and the same size as the stored Pixel Data (7FE0,0010). The shape and size of the Field of View and the spacing of the pixels are defined by the following Attributes: +- Field of View Shape (0018,1147), +- Field of View Dimensions (0018,1149), +- Imager Pixel Spacing (0018,1164), +- Rows (0028,0010), +- Columns (0028,0011) + +The following Attributes define the relationship of the Field of View to the Physical Detector Area: +- Field of View Origin (0018,7030), +- Field of View Rotation (0018,7032), +- Field of View Horizontal Flip (0018,7034). + +For the Digital X-Ray IODs, the Active Area, i.e. that part of the detector matrix that was activated for this exposure, is usually rectangular in shape. The shape and size of the Active Area and the size and spacing of the detectors are defined by the following Attributes: +- Detector Active Shape (0018,7024), +- Detector Active Dimensions (0018,7026), +- Detector Element Physical Size (0018,7020), +- Detector Element Spacing (0018,7022). + +Notes: 1. The Detector Element Physical Size (0018,7020) and Detector Element Spacing (0018,7022) may be different if there are insensitive regions between each detector. + 2. This model of description is not able to accurately describe multiple matrices of detectors that are “tiled†to produce a single image. + +The following optional Attribute defines the relationship of the Active Area to the Physical Detector Area: +- Detector Active Origin (0018,7028). + +The relationship between detectors and stored image pixels is defined by Detector Binning (0018,701A) which specifies how many detectors, in each of the row and column directions, contribute to (are pooled or averaged to form) a single stored image pixel. +Note: Detector Binning (0018,701A) may have values less than one if sub-sampling is used to derive an image with higher spatial resolution than the detector matrix. + + + +Figure C.8-14 +Explanation of DX Detector Attributes + + + + +Figure C.8-15 +Explanation of DX Detector Attributes +
+
+
+ + + A Sequence that describes the radiographic method of patient, tube and detector positioning to achieve a well described projection or view. +Only a single Item shall be permitted in this Sequence. +Shall be consistent with the other Attributes in this Module, if present, but may more specifically describe the image acquisition. + + + + + Description of imaging subject's position relative to the equipment. +See C.7.3.1.1.2 for Defined Terms and further explanation. +If present, shall be consistent with Patient Gantry Relationship Code Sequence (0054,0414) and Patient Orientation Modifier Code Sequence (0054,0412). +
Patient Position (0018,5100) specifies the position of the patient relative to the imaging equipment space. This attribute is intended for annotation purposes only. It does not provide an exact mathematical relationship of the patient to the imaging equipment. +When facing the front of the imaging equipment, Head First is defined as the patient’s head being positioned toward the front of the imaging equipment. Feet First is defined as the patient’s feet being positioned toward the front of the imaging equipment. Prone is defined as the patient’s face being positioned in a downward (gravity) direction. Supine is defined as the patient’s face being in an upward direction. Decubitus Right is defined as the patient’s right side being in a downward direction. Decubitus Left is defined as the patient’s left side being in a downward direction. +The Defined Terms are: + +
+
+ + Radiographic view of the image relative to the imaging subject's orientation. +Shall be consistent with View Code Sequence (0054,0220). See C.8.11.5.1.1 for further explanation. +
View Code Sequence (0054,0220) replaces the function of View Position (0018,5101), and describes the radiographic view of the image relative to the real-world patient orientation as described in PS 3.17 annex on Explanation of Patient Orientation. + +
+
+ + Sequence that describes the projection of the anatomic region of interest on the image receptor. +Note: It is strongly recommended that this Attribute be present, in order to ensure that images may be positioned correctly relative to one another for display. +Shall be consistent with View Position (0018,5101). See C.8.11.5.1.1 for further explanation. +Only a single Item shall be permitted in this Sequence. +
View Code Sequence (0054,0220) replaces the function of View Position (0018,5101), and describes the radiographic view of the image relative to the real-world patient orientation as described in PS 3.17 annex on Explanation of Patient Orientation. + +
+
+ + + View modifier. + +Zero or more Items may be included in this Sequence. + + + + Sequence that describes the orientation of the patient with respect to gravity. +See C.8.11.5.1.2 for further explanation. +Only a single Item shall be permitted in this Sequence. +
This Attribute is not related to Patient Orientation (0020,0020) and conveys a different concept entirely. +
+
+ + + Patient Orientation Modifier. +Required if needed to fully specify the orientation of the patient with respect to gravity. +Only a single Item shall be permitted in this Sequence. + + + + Sequence which describes the orientation of the patient with respect to the gantry. + +Only a single Item shall be permitted in this Sequence. + + + + Distance in mm from source to the table, support or bucky side that is closest to the Imaging Subject, as measured along the central ray of the X-Ray beam. +Note: 1. This definition is less useful in terms of estimating geometric magnification than a measurement to a defined point within the Imaging Subject, but accounts for what is realistically measurable in an automated fashion in a clinical setting. +2. This measurement does not take into account any air gap between the Imaging Subject and the "front" of the table or bucky. +3. If the detector is not mounted in a table or bucky, then the actual position relative to the patient is implementation or operator defined. +4. This value is traditionally referred to as Source Object Distance (SOD). +See C.8.11.7 Mammography Image Module for explanation if Positioner Type (0018,1508) is MAMMOGRAPHIC. +
Table C.8-74 contains IOD Attributes that describe a Digital Mammography X-Ray Image including its acquisition and positioning. +Table C.8-74 +MAMMOGRAPHY IMAGE MODULE ATTRIBUTES + +
+
+ + Distance in mm from source to detector center. +Note: This value is traditionally referred to as Source Image Receptor Distance (SID). +See C.8.11.7 Mammography Image Module for explanation if Positioner Type (0018,1508) is MAMMOGRAPHIC. +
Table C.8-74 contains IOD Attributes that describe a Digital Mammography X-Ray Image including its acquisition and positioning. +Table C.8-74 +MAMMOGRAPHY IMAGE MODULE ATTRIBUTES + +
+
+ + Ratio of Source Image Receptor Distance (SID) over Source Object Distance (SOD). + + + Defined Terms: +CARM +COLUMN +MAMMOGRAPHIC +PANORAMIC +CEPHALOSTAT +RIGID +NONE +Notes: 1. The term CARM can apply to any positioner with 2 degrees of freedom of rotation of the X-Ray beam about the Imaging Subject. +2. The term COLUMN can apply to any positioner with 1 degree of freedom of rotation of the X-Ray beam about the Imaging Subject. + + + Position of the X-Ray beam about the patient from the RAO to LAO direction where movement from RAO to vertical is positive, if Positioner Type (0018,1508) is CARM. +See C.8.7.5 XA Positioner Module for further explanation if Positioner Type (0018,1508) is CARM. +See C.8.11.7 Mammography Image Module for explanation if Positioner Type (0018,1508) is MAMMOGRAPHIC. + + + Position of the X-Ray beam about the patient from the CAU to CRA direction where movement from CAU to vertical is positive, if Positioner Type (0018,1508) is CARM. +See C.8.7.5 XA Positioner Module for further explanation if Positioner Type (0018,1508) is CARM. +See C.8.11.7 Mammography Image Module for explanation if Positioner Type (0018,1508) is MAMMOGRAPHIC. + + + Angle of the X-Ray beam in the row direction in degrees relative to the normal to the detector plane. Positive values indicate that the X-Ray beam is tilted toward higher numbered columns. Negative values indicate that the X-Ray beam is tilted toward lower numbered columns. +See C.8.7.5 XA Positioner Module for further explanation. +See C.8.11.7 Mammography Image Module for explanation if Positioner Type (0018,1508) is MAMMOGRAPHIC. + + + Angle of the X-Ray beam in the column direction in degrees relative to the normal to the detector plane. Positive values indicate that the X-Ray beam is tilted toward lower numbered rows. Negative values indicate that the X-Ray beam is tilted toward higher numbered rows. +See C.8.7.5 XA Positioner Module for further explanation. +See C.8.11.7 Mammography Image Module for explanation if Positioner Type (0018,1508) is MAMMOGRAPHIC. + + + Angle of the X-Ray beam in degree relative to an orthogonal axis to the detector plane. Positive values indicate that the tilt is toward the head of the table. +Note: The detector plane is assumed to be parallel to the table plane. +Only meaningful if Positioner Type (0018,1508) is COLUMN. + + + Defined Terms: +FIXED +TILTING +NONE + + + Angle of table plane in degrees relative to horizontal plane [Gravity plane]. Positive values indicate that the head of the table is upward. +Only meaningful if Table Type (0018,113A) is TILTING. + + + The average thickness in mm of the body part examined when compressed, if compression has been applied during exposure. + + + The compression force applied to the body part during exposure, measured in Newtons. + +
+ + + Type of equipment that originally acquired the data used to create the images in this Series. +Enumerated Value: +MG +See section C.7.3.1.1.1 for further explanation. + + + Sequence that contains attributes from the Imaging Service Request. +The sequence may have one or more Items. + + + + + + Enumerated Values: +MAMMOGRAPHIC +NONE + + + Distance in mm from source to detector center on the chest wall line +Notes: 1. This value is traditionally referred to as Source Image Distance (SID). +2. See C.8.11.7.1.1. +
Figure C.8-8 shows the X-Ray beam for a digital mammography system. The X-Ray beam vector is defined from the Focal Spot to the center of the chest wall line of the Image Detection device. + +Figure C.8-8 +
+
+ + Distance in mm from source to the bucky side that is closest to the Imaging Subject, as measured along the X-Ray beam vector. +Notes: 1. This value is traditionally referred to as Source Object Distance (SOD). +2. See notes for this attribute in C.8.11.5 DX Positioning Module. +3. See C.8.11.7.1.1 for description of X-Ray beam vector. +
Figure C.8-8 shows the X-Ray beam for a digital mammography system. The X-Ray beam vector is defined from the Focal Spot to the center of the chest wall line of the Image Detection device. + +Figure C.8-8 +
+
+ + Position in degrees of the X-Ray beam vector in the coronal anatomical plane as if the patient were standing where movement of the X-Ray source from right to vertical is positive, and vertical is zero. + + + Position in degrees of the X-Ray beam vector in the sagittal anatomical plane as if the patient were standing where movement of the X-Ray source from anterior to posterior is positive, and vertical is zero. + + + Laterality of the region examined. +Enumerated Values: +R = right +L = left +B = both (e.g. cleavage) + + + Organ to which Organ Dose (0040,0316) applies. +Enumerated Value: +BREAST +Note: In the Mammography IOD, Organ Dose (0040,0316) refers to the mean glandular dose. + + + Whether or not an implant is present. Enumerated Values: +YES +NO + + + Indicates whether this image is a partial view, that is a subset of a single view of the breast. +Enumerated Values: YES, NO +If this Attribute is absent, then the image may or may not be a partial view. +Note: This may occur when a breast is larger than the active area of the detector. +If this Attribute is present, its value shall be NO if there is a View Modifier Code Sequence (0054,0222) Item of value (R-102D6, SNM3, "Magnification") or (R-102D7, SNM3, "Spot Compression"). + + + Free text description of the portion of the breast captured in a partial view image. +This Attribute shall not be present if there is a View Modifier Code Sequence (0054,0222) Item of value (R-102D6, SNM3, "Magnification") or (R-102D7, SNM3, "Spot Compression"). + + + Sequence that describes the portion or section of the breast captured in a partial view image. One or two Items may be present. See C.8.11.7.1.3. +If this Attribute is absent, then the image may or may not be a partial view. +This Attribute shall not be present if there is a View Modifier Code Sequence (0054,0222) Item of value (R-102D6, SNM3, "Magnification") or (R-102D7, SNM3, "Spot Compression"). +
The following combinations of coded terms may be used to express the breast sections, for example, for the left cranio-caudal (L CC) view. These terms would also apply to the R CC, and the right and left FB, XCC, XCCL and XCCM views: + +Note: If six images are required, then the “Central, Anterior†combination would be added. + +The following combinations of coded terms may be used to express the breast sections, for example, for the left medio-lateral oblique (L MLO) view. These terms would also apply to the R MLO, and to the right and left LM, ML, LMO, and SIO views: + +Note: If six images are required, then the “Central, Anterior†combination would be added. + +
+
+ + + + Sequence that describes the projection of the anatomic region of interest on the image receptor. +Only a single Item shall be permitted in this Sequence. + + + + View modifier. +Zero or more Items may be included in this Sequence. + + +
+ + + Type of equipment that originally acquired the data used to create the images in this Series. +Enumerated Values: +IO +See section C.7.3.1.1.1 for further explanation. + + + + + Enumerated Values: +NONE +CEPHALOSTAT +RIGID + + + Laterality of the region examined. +Enumerated Values: +R = right +L = left +B = both (i.e. midline) + + + Sequence that identifies the anatomic region of interest in this image. +Only a single Item shall be permitted in this Sequence. + + + + Sequence that refines the anatomic region of interest in this image. +Required if Primary Anatomic Structure Sequence (0008,2228) is not sent. +Only a single Item shall be permitted in this Sequence. + + + + Sequence that describes the primary anatomic structures of interest in this image. +See C.8.11.9.1.1 for further explanation. +Required if Anatomic Region Modifier Sequence (0008,2220) is not sent. +One or more Items may be included in this Sequence. +
The Code Value (0008,0100) shall be drawn from the DICOM Content Mapping Resource, Context ID 4018, for permanent dentition, or Context ID 4019 for deciduous dentition. +These Context Groups correspond to ISO 3950-1984 that describes a designation of permanent and deciduous dentition using a two digit code, the first digit of which designates a quadrant, and the second digit a tooth. +The teeth imaged shall be listed as multiple Items in the Primary Anatomic Structure Sequence (0008,2228). +
+
+ +
+ + + Image identification characteristics. +See C.8.12.1.1.6 for specialization. +
The Image Type attribute identifies important image characteristics in a multiple valued data element. For Visible Light, Image Type is specialized as follows: +a. Value 1 shall identify the Pixel Data Characteristics in accordance with Section C.7.6.1.1.2; Enumerated Values are: ORIGINAL and DERIVED; +b. Value 2 shall identify the Patient Examination Characteristics in accordance with Section C.7.6.1.1.2; Enumerated Values are: PRIMARY and SECONDARY. +c. Value 3 may be absent, but if present shall identify the members of a stereo pair, in which case Referenced Image Sequence (0008,1140) is used to identify the other member of the pair. If present, the Enumerated Values are: + + +d. Other Values are implementation specific (optional). + +
+
+ + Specifies the intended interpretation of the pixel data. +See C.8.12.1.1.1 for specialization of this Attribute. +
The Enumerated Values of Photometric Interpretation (0028,0004) shall be: +MONOCHROME2 +RGB +YBR_FULL_422 +YBR_PARTIAL_420 +YBR_RCT +YBR_ICT +Note: There is no formal color space defined, hence “false†color applications that encode near-visible light images may be encoded, for example, as RGB. + +
+
+ + Number of bits allocated for each pixel sample. Each sample shall have the same number of bits allocated. +See C.8.12.1.1.2 for specialization of this Attribute. See PS 3.5 for further explanation. +
The Enumerated Value of Bits Allocated (0028,0100) shall be 8; the Enumerated Value of Bits Stored (0028,0101) shall be 8; and the Enumerated Value of High Bit (0028,0102) shall be 7. +
+
+ + Number of bits stored for each pixel sample. Each sample shall have the same number of bits stored. +See C.8.12.1.1.2 for specialization of this Attribute. See PS 3.5 for further explanation. +
The Enumerated Value of Bits Allocated (0028,0100) shall be 8; the Enumerated Value of Bits Stored (0028,0101) shall be 8; and the Enumerated Value of High Bit (0028,0102) shall be 7. +
+
+ + Most significant bit for pixel sample data. Each sample shall have the same high bit. +See C.8.12.1.1.2 for specialization of this Attribute. See PS 3.5 for further explanation. +
The Enumerated Value of Bits Allocated (0028,0100) shall be 8; the Enumerated Value of Bits Stored (0028,0101) shall be 8; and the Enumerated Value of High Bit (0028,0102) shall be 7. +
+
+ + Data representation of the pixel samples. Each sample shall have the same pixel representation. +See Section C.8.12.1.1.3 for specialization of this Attribute. +
The Enumerated Value of Pixel Representation (0028,0103) shall be 0. +
+
+ + Number of samples (planes) per image. +See C.8.12.1.1.4 for specialization of this Attribute. +
The Enumerated Values of Samples per Pixel (0028,0002) shall be as follows: If the value of Photometric Interpretation (0028,0004) is MONOCHROME2, then the Enumerated Value of Samples per Pixel (0028,0002) shall be one (1). If the value of Photometric Interpretation (0028,0004) is RGB or YBR_FULL_422 or YBR_PARTIAL_420 or YBR_RCT or YBR_ICT, then the Enumerated Value of Samples per Pixel (0028,0002) shall be three (3). +
+
+ + Indicates whether the pixel data are sent color-by-plane or color-by-pixel. Required if Samples per Pixel (0028,0002) has a value greater than 1. +See C.8.12.1.1.5 for specialization of this Attribute. +
If present, the Enumerated Value of Planar Configuration (0028,0006) shall be 0. This value shall be present if Samples per Pixel (0028,0002) has a value greater than 1. +
+
+ + The time the image pixel data creation started. Required if the Image is part of a series in which the images are temporally related. +Note: This Attribute was formerly known as Image Time. + + + Specifies whether an Image has undergone lossy compression. Enumerated Values: +00 = Image has NOT been subjected to lossy compression. +01 = Image has been subjected to lossy compression. +See C.7.6.1.1.5 +
The Attribute Lossy Image Compression (0028,2110) conveys that the Image has undergone lossy compression. It provides a means to record that the Image has been compressed (at a point in its lifetime) with a lossy algorithm and changes have been introduced into the pixel data. Once the value has been set to “01â€, it shall not be reset. +Note: If an image is compressed with a lossy algorithm, the attribute Lossy Image Compression (0028,2110) is set to “01â€. Subsequently, if the image is decompressed and transferred in uncompressed format, this attribute value remains “01â€. + +The value of the Lossy Image Compression (0028,2110) Attribute in SOP Instances containing multiple frames in which one or more of the frames have undergone lossy compression shall be “01â€. +Note: It is recommended that the applicable frames be noted in the Attribute Derivation Description (0008,2111). + +If an image is originally obtained as a lossy compressed image from the sensor, then Lossy Image Compression (0028,2110) is set to “01†and Value 1 of the Attribute Image Type (0008,0008) shall be set to ORIGINAL. +If an image is a compressed version of another image, Lossy Image Compression (0028,2110) is set to “01â€, Value 1 of the Attribute Image Type (0008,0008) shall be set to DERIVED, and if the predecessor was a DICOM image, then the Image shall receive a new SOP Instance UID. +Note: 1. It is recommended that the approximate compression ratio be provided in the Attribute Derivation Description (0008,2111). Furthermore, it is recommended that Derivation Description (0008,2111) be used to indicate when pixel data changes might affect professional interpretation. (see C.7.6.1.1.3). + 2. The attribute Lossy Image Compression (0028,2110) is defined as Type 3 for backward compatibility with existing IODs. It is expected to be required (i.e., defined as Type 1C) for new Image IODs and for existing IODs that undergo a major revision (e.g. a new IOD is specified). +The Defined Terms for Lossy Image Compression Method (0028,2114) are: +ISO_10918_1 = JPEG Lossy Compression +ISO_14495_1 = JPEG-LS Near-lossless Compression +ISO_15444_1 = JPEG 2000 Irreversible Compression +ISO_13818_2 = MPEG2 Compression + +
+
+ + A Sequence that references other images significantly related to this image. One or more items may be included in this sequence. +Required if Image Type (0008,0008) Value 3 is present and has a value of "STEREO L" or "STEREO R". May also be present otherwise. See Section C.8.12.1.1.7. +
When Image Type (0008,0008) Value 3 is STEREO L or STEREO R, Referenced Image Sequence (0008,1140) shall be used to identify the corresponding SOP Instance of the Stereoscopic acquisition. In this case, either: +
+
+ + + Describes the purpose for which the reference is made. Zero or one item shall be present in the sequence. + + + + Window Center for display. See C.11.2.1.2 for further explanation. +Meaningful only if Photometric Interpretation (0028,0004) is MONOCHROME2. +
Window Center (0028,1050) and Window Width (0028,1051) specify a linear conversion from stored pixel values (after any Modality LUT or Rescale Slope and Intercept specified in the IOD have been applied) to values to be displayed. Window Center contains the input value that is the center of the window. Window Width contains the width of the window. +Note: The terms “window center†and “window width†are not consistently used in practice, nor were they defined in previous versions of the standard. The definitions here are presented for the purpose of defining consistent meanings for identity and threshold transformations while preserving the common practice of using integral values for center and width. + +Window Width (0028,1051) shall always be greater than or equal to 1. +When Window Width (0028,1051) is greater than 1, these Attributes select the range of input values that are to be mapped to the full range of the displayed output. +When Window Width (0028,1051) is equal to 1, they specify a threshold below which input values will be displayed as the minimum output value. +Note: Whether the minimum output value is rendered as black or white may depend on the value of Photometric Interpretation (0028,0004) or the presence of a Presentation LUT Module. + +These Attributes are applied according to the following pseudo-code, where x is the input value, y is an output value with a range from ymin to ymax, c is Window Center (0028,1050) and w is Window Width (0028,1051): + if (x <= c - 0.5 - (w-1)/2), then y = ymin + else if (x > c - 0.5 + (w-1)/2), then y = ymax, + else y = ((x - (c - 0.5)) / (w-1) + 0.5) * (ymax - ymin)+ ymin + +Notes: 1. For the purpose of this definition, a floating point calculation without integer truncation is assumed, though the manner of implementation may vary as long as the result is the same. + 2. The pseudo-code function computes a continuous value over the output range without any discontinuity at the boundaries. The value of 0 for w is expressly forbidden, and the value of 1 for w does not cause division by zero, since the continuous segment of the function will never be reached for that case. + 3. For example, for an output range 0 to 255: + c=2048, w=4096 becomes: + if (x <= 0) then y = 0 + else if (x > 4095) then y = 255 + else y = ((x - 2047.5) / 4095 + 0.5) * (255-0) + 0 + c=2048, w=1 becomes: + if (x <= 2047.5) then y = 0 + else if (x > 2047.5) then y = 255 + else /* not reached */ + + c=0, w=100 becomes: + if (x <= -50) then y = 0 + else if (x > 49) then y = 255 + else y = ((x + 0.5) / 99 + 0.5) * (255-0) + 0 + c=0, w=1 becomes: + if (x <= -0.5) then y = 0 + else if (x > -0.5) then y = 255 + else /* not reached */ + + 4. A Window Center of 2n-1 and a Window Width of 2n selects the range of input values from 0 to 2n-1. This represents an identity VOI LUT transformation in the case where no Modality LUT is specified and the stored pixel data are n bit unsigned integers. + 5. A Window Width of 1 is typically used to represent a "threshold" operation in which those integer input values less than the Window Center are represented as the minimum displayed value and those greater than or equal to the Window Center are represented as the maximum displayed value. A Window Width of 2 will have the same result for integral input values. + 6. The application of Window Center (0028,1050) and Window Width (0028,1051) may select a signed input range. There is no implication that this signed input range is clipped to zero. + 7. The selected input range may exceed the actual range of the input values, thus effectively “compressing†the contrast range of the displayed data into a narrower band of the available contrast range, and “flattening†the appearance. There are no limits to the maximum value of the window width, or to the minimum or maximum value of window level, both of which may exceed the actual or possible range of input values. + 8. Input values "below" the window are displayed as the minimum output value and input values "above" the window are displayed as the maximum output value. This is the common usage of the window operation in medical imaging. There is no provision for an alternative approach in which all values "outside" the window are displayed as the minimum output value. + 9. The output of the Window Center/Width or VOI LUT transformation is either implicitly scaled to the full range of the display device if there is no succeeding transformation defined, or implicitly scaled to the full input range of the succeeding transformation step (such as the Presentation LUT), if present. See C.11.6.1. + 10. Fractional values of Window Center and Window Width are permitted (since the VR of these Attributes is Decimal String), and though they are not often encountered, applications should be prepared to accept them. + +These Attributes shall be used only for Images with Photometric Interpretation (0028,0004) values of MONOCHROME1 and MONOCHROME2. They have no meaning for other Images. +If multiple values are present, both Attributes shall have the same number of values and shall be considered as pairs. Multiple values indicate that multiple alternative views may be presented. +If any VOI LUT Table is included by an Image, a Window Width and Window Center or the VOI LUT Table, but not both, may be applied to the Image for display. Inclusion of both indicates that multiple alternative views may be presented. +If multiple items are present in VOI LUT Sequence (0028,3010), only one may be applied to the Image for display. Multiple items indicate that multiple alternative views may be presented. +If the VOI LUT Module is defined in an IOD and if neither a VOI LUT Sequence nor a Window Width and Window Center are present, then the VOI LUT stage of the grayscale pipeline is defined to be an identity transformation. +Notes: 1. This requirement is specified so that IODs that define a particular output space for the grayscale pipeline, such as P-Values, are not in an undefined state when no VOI LUT Sequence or Window Width and Window Center are present. + 2. Despite the Type 3 requirement for VOI LUT Sequence and Window Center, implementations that render images are expected to implement and apply these transformations when they are present in the image, unless overridden by the user, a presentation state, or a hanging protocol, and to allow the user to select which transformation to apply when multiple transformations are present. + +
+
+ + Window Width for display. See C.11.2.1.2 for further explanation. +Required if Window Center (0028,1050) is present. +
Window Center (0028,1050) and Window Width (0028,1051) specify a linear conversion from stored pixel values (after any Modality LUT or Rescale Slope and Intercept specified in the IOD have been applied) to values to be displayed. Window Center contains the input value that is the center of the window. Window Width contains the width of the window. +Note: The terms “window center†and “window width†are not consistently used in practice, nor were they defined in previous versions of the standard. The definitions here are presented for the purpose of defining consistent meanings for identity and threshold transformations while preserving the common practice of using integral values for center and width. + +Window Width (0028,1051) shall always be greater than or equal to 1. +When Window Width (0028,1051) is greater than 1, these Attributes select the range of input values that are to be mapped to the full range of the displayed output. +When Window Width (0028,1051) is equal to 1, they specify a threshold below which input values will be displayed as the minimum output value. +Note: Whether the minimum output value is rendered as black or white may depend on the value of Photometric Interpretation (0028,0004) or the presence of a Presentation LUT Module. + +These Attributes are applied according to the following pseudo-code, where x is the input value, y is an output value with a range from ymin to ymax, c is Window Center (0028,1050) and w is Window Width (0028,1051): + if (x <= c - 0.5 - (w-1)/2), then y = ymin + else if (x > c - 0.5 + (w-1)/2), then y = ymax, + else y = ((x - (c - 0.5)) / (w-1) + 0.5) * (ymax - ymin)+ ymin + +Notes: 1. For the purpose of this definition, a floating point calculation without integer truncation is assumed, though the manner of implementation may vary as long as the result is the same. + 2. The pseudo-code function computes a continuous value over the output range without any discontinuity at the boundaries. The value of 0 for w is expressly forbidden, and the value of 1 for w does not cause division by zero, since the continuous segment of the function will never be reached for that case. + 3. For example, for an output range 0 to 255: + c=2048, w=4096 becomes: + if (x <= 0) then y = 0 + else if (x > 4095) then y = 255 + else y = ((x - 2047.5) / 4095 + 0.5) * (255-0) + 0 + c=2048, w=1 becomes: + if (x <= 2047.5) then y = 0 + else if (x > 2047.5) then y = 255 + else /* not reached */ + + c=0, w=100 becomes: + if (x <= -50) then y = 0 + else if (x > 49) then y = 255 + else y = ((x + 0.5) / 99 + 0.5) * (255-0) + 0 + c=0, w=1 becomes: + if (x <= -0.5) then y = 0 + else if (x > -0.5) then y = 255 + else /* not reached */ + + 4. A Window Center of 2n-1 and a Window Width of 2n selects the range of input values from 0 to 2n-1. This represents an identity VOI LUT transformation in the case where no Modality LUT is specified and the stored pixel data are n bit unsigned integers. + 5. A Window Width of 1 is typically used to represent a "threshold" operation in which those integer input values less than the Window Center are represented as the minimum displayed value and those greater than or equal to the Window Center are represented as the maximum displayed value. A Window Width of 2 will have the same result for integral input values. + 6. The application of Window Center (0028,1050) and Window Width (0028,1051) may select a signed input range. There is no implication that this signed input range is clipped to zero. + 7. The selected input range may exceed the actual range of the input values, thus effectively “compressing†the contrast range of the displayed data into a narrower band of the available contrast range, and “flattening†the appearance. There are no limits to the maximum value of the window width, or to the minimum or maximum value of window level, both of which may exceed the actual or possible range of input values. + 8. Input values "below" the window are displayed as the minimum output value and input values "above" the window are displayed as the maximum output value. This is the common usage of the window operation in medical imaging. There is no provision for an alternative approach in which all values "outside" the window are displayed as the minimum output value. + 9. The output of the Window Center/Width or VOI LUT transformation is either implicitly scaled to the full range of the display device if there is no succeeding transformation defined, or implicitly scaled to the full input range of the succeeding transformation step (such as the Presentation LUT), if present. See C.11.6.1. + 10. Fractional values of Window Center and Window Width are permitted (since the VR of these Attributes is Decimal String), and though they are not often encountered, applications should be prepared to accept them. + +These Attributes shall be used only for Images with Photometric Interpretation (0028,0004) values of MONOCHROME1 and MONOCHROME2. They have no meaning for other Images. +If multiple values are present, both Attributes shall have the same number of values and shall be considered as pairs. Multiple values indicate that multiple alternative views may be presented. +If any VOI LUT Table is included by an Image, a Window Width and Window Center or the VOI LUT Table, but not both, may be applied to the Image for display. Inclusion of both indicates that multiple alternative views may be presented. +If multiple items are present in VOI LUT Sequence (0028,3010), only one may be applied to the Image for display. Multiple items indicate that multiple alternative views may be presented. +If the VOI LUT Module is defined in an IOD and if neither a VOI LUT Sequence nor a Window Width and Window Center are present, then the VOI LUT stage of the grayscale pipeline is defined to be an identity transformation. +Notes: 1. This requirement is specified so that IODs that define a particular output space for the grayscale pipeline, such as P-Values, are not in an undefined state when no VOI LUT Sequence or Window Width and Window Center are present. + 2. Despite the Type 3 requirement for VOI LUT Sequence and Window Center, implementations that render images are expected to implement and apply these transformations when they are present in the image, unless overridden by the user, a presentation state, or a hanging protocol, and to allow the user to select which transformation to apply when multiple transformations are present. + +
+
+ + Sequence that identifies the anatomic region of interest in this image (i.e. external anatomy, surface anatomy, or general region of the body). +Only a single Item shall be permitted in this sequence. +Required if Number of Frames (0028,0008) is present and Specimen Accession Number (0040,050A) is absent. May be present otherwise. + + + + Sequence of Items that modifies the anatomic region of interest of this image +One or more Items may be included in this Sequence. + + + + + Describes the light color used for each channel to generate the image. +If Photometric Interpretation (0028,0004) has one of the YBR values, the meaning is for pixel data in an equivalent RGB encoding. +Note: Interpretation and representation of RGB images rely on the assumption that the red channel really contains the red wavelength range of illumination light, the blue channel the blue wavelength range, etc. Some modalities use the RGB Photometric Interpretation as a container representing 3 channels of any illumination wavelength. +Shall have the same number of items as the value of Samples per Pixel (0028,0002). The channels shall be described in the order in which the channels are encoded. + + +
+ + + The coordinates of the center point of the Image in the Slide Coordinate System Frame of Reference. Zero or one item shall be present in the sequence. See Section C.8.12.2.1.1 for further explanation. +
This Section defines the Slide Coordinate System and specifies the Attributes that shall be used to describe the location of the center point of the Image pixel plane (as captured through a microscope) in the Slide Coordinate System Frame of Reference. +Note: In Slide Microscopy (SM), the Microscope is equipped with a moveable Stage and position sensors that enable storage of the location of the center point of the displayed image with respect to the examined Specimen. + +The Stage is the part of the Microscope to which the Slide is attached for viewing. The Objective Lens is the lens that is closest to the Specimen. The Top Surface of the Slide is the surface of the Slide on which the Specimen in Mounted. The Bottom Surface of the Slide is the opposite surface. This Specification presumes that: 1) the Slide is rectangular; 2) the Top Surface of the Slide is oriented toward the Objective Lens of the Microscope; and 3) the Bottom Surface of the Slide is in perfect contact with the Microscope Stage when the Slide is attached to the Stage for viewing. +Notes: 1. The Label of the Slide is presumed to be mounted-on or written-on the Top Surface of the Slide. + 2. Specification of the mechanical form, function, or tolerances of the Microscope are outside the scope of this Standard. + +Figure C.8-16 depicts the Top Surface of the Slide on the Microscope Stage from the perspective of the Objective Lens. This is Reference Slide Orientation. The X, Y, and Z axes of the Slide Coordinate System in Reference Slide Orientation are defined as follows. The Y-axis is a line that includes the Left Edge of the Slide. The X-axis is a line that is orthogonal to the Y-axis and includes at least one point of the Specimen Edge of the Slide. The Z-axis is a line that passes through the intersection of the X-axis and Y-axis and is orthogonal to the Microscope Stage. The Origin (0,0,0) of the Slide Coordinate System is the point of intersection of the X, Y, and Z axes. + +Figure C.8-16 +REFERENCE SLIDE ORIENTATION + +Notes: 1. An improperly-placed coverslip or Specimen that overlaps an Edge of a Slide is not considered part of the Edge a Slide for purposes of defining the Slide Coordinate System. However, such objects may cause inaccurate positioning of the Slide on the Stage. + 2. If the Left Edge and Specimen Edge of the Slide are not orthogonal (e.g. the Slide is damaged or defective or the Specimen Edge is curvilinear), then the lower left-hand corner of the Slide may not be located at the Origin. + 3. The definitions of X, Y, and Z axes are the same for inverted microscopes, with the Top Surface of the slide (i.e. Specimen side of the Slide) still being closest to the Objective Lens. + +Figure C.8-17 depicts the Z-axis center point location. The X-axis value of Image Center Point Location (0040,073A) shall increase from the Origin toward the Right Edge in Reference Slide Orientation. The Y-axis value of Image Center Point Location (0040,073A) shall increase from the Origin toward the Label Edge in Reference Slide Orientation. The Z-axis value of Image Center Point Location (0040,073A) shall be referenced as zero at the image substrate reference plane (i.e. utilized surface of a glass slide) and shall increase in a positive fashion coincident with increased distance from the substrate surface. + +Figure C.8-17 +Z-AXIS CENTER POINT LOCATION, VIEW FROM RIGHT EDGE OF SLIDE +
+
+ + The X offset in millimeters from the Origin of the Slide Coordinate System. See Figure C.8-16. + + + The Y offset in millimeters from the Origin of the Slide Coordinate System. See Figure C.8-16. + + + The Z offset in microns from the image substrate reference plane (i.e. utilized surface of a glass slide). + + + Physical distance in the Imaging Subject, i.e. Patient or Specimen, between the center of each pixel along specified axes. One or more items may be present. + + + Axis of a coordinate system. This sequence shall contain exactly one item. + + + + The distance between the center-points of adjacent pixels along the axis specified by Coordinate System Axis Code Sequence (0040,08DA). + + + Units of the measurement. This sequence shall contain exactly one item. + + +
+ + + + Image characteristics. See C.8.16.1 and C.8.13.3.1.1. +
The Image Type (0008,0008) and associated Image Type related attributes provide a high level description of a multi-frame SOP Instance. These attributes describe properties that provide key summary information to users of the SOP Instance. Image Type (0008,0008) contains the highest level summary of what is in the SOP Instance. +The Frame Type (0008,9007) attribute mirrors the corresponding Image Type attribute and applies to the frame level rather than to the image level. +If more than one value is used by the set of frames for a given Frame Type (0008,9007) attribute value or associated attribute value then the corresponding value of the Image Type (0008,0008) or associated attribute shall contain a value of MIXED. This indicates that a mixed set of values exists within the multi-frame SOP Instance. +The value MIXED shall only be used in the Image Type (0008,0008) when the corresponding values for the individual frames are not equal. When a value of an attribute is equal for all frames, the same value shall be used for the corresponding value of the Image Type (0008,0008). Values 2 and 3 of Image Type (0008,0008) are an exception to the rule for MIXED: Values 2 and 3 may never have the value of MIXED as described in sections C.8.16.1.2 and C.8.16.1.3. +Image Type (0008,0008) and Frame Type (0008,9007) shall consist of four non-zero length values. +
+
+ + + + Number of samples (planes) in this image. This value shall be 1. + + + Specifies the intended interpretation of the pixel data. Enumerated Value: MONOCHROME2. See C.7.6.3.1.2 for definition of this term. +
The value of Photometric Interpretation (0028,0004) specifies the intended interpretation of the image pixel data. +See PS 3.5 for restrictions imposed by compressed Transfer Syntaxes. +The following values are defined. Other values are permitted but the meaning is not defined by this Standard. +MONOCHROME1 = Pixel data represent a single monochrome image plane. The minimum sample value is intended to be displayed as white after any VOI gray scale transformations have been performed. See PS 3.4. This value may be used only when Samples per Pixel (0028,0002) has a value of 1. +MONOCHROME2 = Pixel data represent a single monochrome image plane. The minimum sample value is intended to be displayed as black after any VOI gray scale transformations have been performed. See PS 3.4. This value may be used only when Samples per Pixel (0028,0002) has a value of 1. +PALETTE COLOR = Pixel data describe a color image with a single sample per pixel (single image plane). The pixel value is used as an index into each of the Red, Blue, and Green Palette Color Lookup Tables (0028,1101-1103&1201-1203). This value may be used only when Samples per Pixel (0028,0002) has a value of 1. When the Photometric Interpretation is Palette Color; Red, Blue, and Green Palette Color Lookup Tables shall be present. +RGB = Pixel data represent a color image described by red, green, and blue image planes. The minimum sample value for each color plane represents minimum intensity of the color. This value may be used only when Samples per Pixel (0028,0002) has a value of 3. +HSV = Retired. +ARGB = Retired. +CMYK = Retired. +YBR_FULL = Pixel data represent a color image described by one luminance (Y) and two chrominance planes (CB and CR). This photometric interpretation may be used only when Samples per Pixel (0028,0002) has a value of 3. Black is represented by Y equal to zero. The absence of color is represented by both CB and CR values equal to half full scale. +Note: In the case where the Bits Allocated (0028,0100) has value of 8 half full scale is 128. + +In the case where Bits Allocated (0028,0100) has a value of 8 then the following equations convert between RGB and YCBCR Photometric Interpretation. +Y = + .2990R + .5870G + .1140B +CB = - .1687R - .3313G + .5000B + 128 +CR = + .5000R - .4187G - .0813B + 128 +Note: The above is based on CCIR Recommendation 601-2 dated 1990. + +YBR_FULL_422 = The same as YBR_FULL except that the CB and CR values are sampled horizontally at half the Y rate and as a result there are half as many CB and CR values as Y values. +This Photometric Interpretation is only allowed with Planar Configuration (0028,0006) equal to 0. Two Y values shall be stored followed by one CB and one CR value. The CB and CR values shall be sampled at the location of the first of the two Y values. For each Row of Pixels, the first CB and CR samples shall be at the location of the first Y sample. The next CB and CR samples shall be at the location of the third Y sample etc. +Note: This subsampling is often referred to as cosited sampling. + +YBR_PARTIAL_422 = The same as YBR_FULL_422 except that: +1. black corresponds to Y = 16; +2. Y is restricted to 220 levels (i.e. the maximum value is 235); +3. CB and CR each has a minimum value of 16; +4. CB and CR are restricted to 225 levels (i.e. the maximum value is 240); +5. lack of color is represented by CB and CR equal to 128. +In the case where Bits Allocated (0028,0100) has value of 8 then the following equations convert between RGB and YBR_PARTIAL_422 Photometric Interpretation +Y = + .2568R + .5041G + .0979B + 16 +CB = - .1482R - .2910G + .4392B + 128 +CR = + .4392R - .3678G - .0714B + 128 +Note: The above is based on CCIR Recommendation 601-2 dated 1990. + +YBR_PARTIAL_420 = The same as YBR_PARTIAL_422 except that the CB and CR values are sampled horizontally and vertically at half the Y rate and as a result there are four times less CB and CR values than Y values, versus twice less for YBR_PARTIAL_422. +This Photometric Interpretation is only allowed with Planar Configuration (0028,0006) equal to 0. The CB and CR values shall be sampled at the location of the first of the two Y values. For the first Row of Pixels (etc.), the first CB and CR samples shall be at the location of the first Y sample. The next CB and CR samples shall be at the location of the third Y sample etc. The next Rows of Pixels containing CB and CR samples (at the same locations than for the first Row) will be the third etc. +YBR_ICT = Irreversible Color Transformation: +Pixel data represent a color image described by one luminance (Y) and two chrominance planes (CB and CR). This photometric interpretation may be used only when Samples per Pixel (0028,0002) has a value of 3. Black is represented by Y equal to zero. The absence of color is represented by both CB and CR values equal to zero. +Regardless of the value of Bits Allocated (0028,0100), the following equations convert between RGB and YCBCR Photometric Interpretation. +Y = + .29900R + .58700G + .11400B +CB = - .16875R - .33126G + .50000B +CR = + .50000R - .41869G - .08131B +Notes: 1. The above is based on ISO/IEC 15444-1 (JPEG 2000). + 2. In a JPEG 2000 bitstream, DC level shifting (used if the untransformed components are unsigned) is applied before forward color transformation, and the transformed components may be signed (unlike in JPEG ISO/IEC 10918-1). + 3. In JPEG 2000, spatial down-sampling of the chrominance components, if performed, is signaled in the JPEG 2000 bitstream. + +YBR_RCT = Reversible Color Transformation: +Pixel data represent a color image described by one luminance (Y) and two chrominance planes (CB and CR). This photometric interpretation may be used only when Samples per Pixel (0028,0002) has a value of 3. Black is represented by Y equal to zero. The absence of color is represented by both CB and CR values equal to zero. +Regardless of the value of Bits Allocated (0028,0100), the following equations convert between RGB and YBR_RCT Photometric Interpretation. +Y = R + 2G +B) / 4 (Note:  mean floor) +CB = B - G +CR = R - G +The following equations convert between YBR_RCT and RGB Photometric Interpretation. +G = Y –  (CR + CB) / 4 +R = CR + G +B = CB + G +Notes: 1. The above is based on ISO/IEC 15444-1 (JPEG 2000). + 2. In a JPEG 2000 bitstream, DC level shifting (used if the untransformed components are unsigned) is applied before forward color transformation, and the transformed components may be signed (unlike in JPEG ISO/IEC 10918-1). + 3. This photometric interpretation is a reversible approximation to the YUV transformation used in PAL and SECAM. + +
+
+ + Number of bits allocated for each pixel sample. Each sample shall have the same number of bits allocated. Enumerated Values: 8 and 16. + + + Number of bits stored for each pixel sample. Each sample shall have the same number of bits stored. Enumerated Values: 8, 12 and 16. See C.8.13.1.1.1 for specialization. +
Table C.8-80 specifies the allowed combinations of Bits Allocated (0028,0100) and Bits Stored (0028,0101). +Table C.8-80 +ALLOWED COMBINATIONS OF ATTRIBUTE VALUES + FOR BITS ALLOCATED AND BITS STORED + +
+
+ + Most significant bit for pixel sample data. Each sample shall have the same high bit. Shall be one less than the value in Bits Stored (0028,0101). + + + Value of the prescribed spacing to be applied between the slices in a volume that is to be acquired. The spacing in mm is defined as the center-to-center distance of adjacent slices. + + + Indicates whether or not the image contains sufficient burned in annotation to identify the patient and date the image was acquired. +Enumerated Values: +NO +This means that images that contain this Module shall not contain such burned in annotations. + + + Specifies whether an Image has undergone lossy compression. +Enumerated Values: +00 = Image has NOT been subjected to lossy compression. +01 = Image has been subjected to lossy compression. +See C.7.6.1.1.5 for further explanation. +
The Attribute Lossy Image Compression (0028,2110) conveys that the Image has undergone lossy compression. It provides a means to record that the Image has been compressed (at a point in its lifetime) with a lossy algorithm and changes have been introduced into the pixel data. Once the value has been set to “01â€, it shall not be reset. +Note: If an image is compressed with a lossy algorithm, the attribute Lossy Image Compression (0028,2110) is set to “01â€. Subsequently, if the image is decompressed and transferred in uncompressed format, this attribute value remains “01â€. + +The value of the Lossy Image Compression (0028,2110) Attribute in SOP Instances containing multiple frames in which one or more of the frames have undergone lossy compression shall be “01â€. +Note: It is recommended that the applicable frames be noted in the Attribute Derivation Description (0008,2111). + +If an image is originally obtained as a lossy compressed image from the sensor, then Lossy Image Compression (0028,2110) is set to “01†and Value 1 of the Attribute Image Type (0008,0008) shall be set to ORIGINAL. +If an image is a compressed version of another image, Lossy Image Compression (0028,2110) is set to “01â€, Value 1 of the Attribute Image Type (0008,0008) shall be set to DERIVED, and if the predecessor was a DICOM image, then the Image shall receive a new SOP Instance UID. +Note: 1. It is recommended that the approximate compression ratio be provided in the Attribute Derivation Description (0008,2111). Furthermore, it is recommended that Derivation Description (0008,2111) be used to indicate when pixel data changes might affect professional interpretation. (see C.7.6.1.1.3). + 2. The attribute Lossy Image Compression (0028,2110) is defined as Type 3 for backward compatibility with existing IODs. It is expected to be required (i.e., defined as Type 1C) for new Image IODs and for existing IODs that undergo a major revision (e.g. a new IOD is specified). +The Defined Terms for Lossy Image Compression Method (0028,2114) are: +ISO_10918_1 = JPEG Lossy Compression +ISO_14495_1 = JPEG-LS Near-lossless Compression +ISO_15444_1 = JPEG 2000 Irreversible Compression +ISO_13818_2 = MPEG2 Compression + +
+
+ + Describes the approximate lossy compression ratio(s) that have been applied to this image. +See C.7.6.1.1.5 for further explanation. +May be multivalued if successive lossy compression steps have been applied. +Note: For example, a compression ratio of 30:1 would be described in this Attribute with a single value of 30. +Required if Lossy Images Compression (0028,2110) is "01". +
The Attribute Lossy Image Compression (0028,2110) conveys that the Image has undergone lossy compression. It provides a means to record that the Image has been compressed (at a point in its lifetime) with a lossy algorithm and changes have been introduced into the pixel data. Once the value has been set to “01â€, it shall not be reset. +Note: If an image is compressed with a lossy algorithm, the attribute Lossy Image Compression (0028,2110) is set to “01â€. Subsequently, if the image is decompressed and transferred in uncompressed format, this attribute value remains “01â€. + +The value of the Lossy Image Compression (0028,2110) Attribute in SOP Instances containing multiple frames in which one or more of the frames have undergone lossy compression shall be “01â€. +Note: It is recommended that the applicable frames be noted in the Attribute Derivation Description (0008,2111). + +If an image is originally obtained as a lossy compressed image from the sensor, then Lossy Image Compression (0028,2110) is set to “01†and Value 1 of the Attribute Image Type (0008,0008) shall be set to ORIGINAL. +If an image is a compressed version of another image, Lossy Image Compression (0028,2110) is set to “01â€, Value 1 of the Attribute Image Type (0008,0008) shall be set to DERIVED, and if the predecessor was a DICOM image, then the Image shall receive a new SOP Instance UID. +Note: 1. It is recommended that the approximate compression ratio be provided in the Attribute Derivation Description (0008,2111). Furthermore, it is recommended that Derivation Description (0008,2111) be used to indicate when pixel data changes might affect professional interpretation. (see C.7.6.1.1.3). + 2. The attribute Lossy Image Compression (0028,2110) is defined as Type 3 for backward compatibility with existing IODs. It is expected to be required (i.e., defined as Type 1C) for new Image IODs and for existing IODs that undergo a major revision (e.g. a new IOD is specified). +The Defined Terms for Lossy Image Compression Method (0028,2114) are: +ISO_10918_1 = JPEG Lossy Compression +ISO_14495_1 = JPEG-LS Near-lossless Compression +ISO_15444_1 = JPEG 2000 Irreversible Compression +ISO_13818_2 = MPEG2 Compression + +
+
+ + A label for the lossy compression method(s) that have been applied to this image. +See C.7.6.1.1.5 for further explanation. +May be multivalued if successive lossy compression steps have been applied; the value order shall correspond to the values of Lossy Image Compression Ratio (0028,2112). +Required if Lossy Image Compression (0028,2110) is "01". +
The Attribute Lossy Image Compression (0028,2110) conveys that the Image has undergone lossy compression. It provides a means to record that the Image has been compressed (at a point in its lifetime) with a lossy algorithm and changes have been introduced into the pixel data. Once the value has been set to “01â€, it shall not be reset. +Note: If an image is compressed with a lossy algorithm, the attribute Lossy Image Compression (0028,2110) is set to “01â€. Subsequently, if the image is decompressed and transferred in uncompressed format, this attribute value remains “01â€. + +The value of the Lossy Image Compression (0028,2110) Attribute in SOP Instances containing multiple frames in which one or more of the frames have undergone lossy compression shall be “01â€. +Note: It is recommended that the applicable frames be noted in the Attribute Derivation Description (0008,2111). + +If an image is originally obtained as a lossy compressed image from the sensor, then Lossy Image Compression (0028,2110) is set to “01†and Value 1 of the Attribute Image Type (0008,0008) shall be set to ORIGINAL. +If an image is a compressed version of another image, Lossy Image Compression (0028,2110) is set to “01â€, Value 1 of the Attribute Image Type (0008,0008) shall be set to DERIVED, and if the predecessor was a DICOM image, then the Image shall receive a new SOP Instance UID. +Note: 1. It is recommended that the approximate compression ratio be provided in the Attribute Derivation Description (0008,2111). Furthermore, it is recommended that Derivation Description (0008,2111) be used to indicate when pixel data changes might affect professional interpretation. (see C.7.6.1.1.3). + 2. The attribute Lossy Image Compression (0028,2110) is defined as Type 3 for backward compatibility with existing IODs. It is expected to be required (i.e., defined as Type 1C) for new Image IODs and for existing IODs that undergo a major revision (e.g. a new IOD is specified). +The Defined Terms for Lossy Image Compression Method (0028,2114) are: +ISO_10918_1 = JPEG Lossy Compression +ISO_14495_1 = JPEG-LS Near-lossless Compression +ISO_15444_1 = JPEG 2000 Irreversible Compression +ISO_13818_2 = MPEG2 Compression + +
+
+ + Specifies an identity transformation for the Presentation LUT, such that the output of all grayscale transformations defined in the IOD containing this Module are defined to be P-Values. +Enumerated Values: +IDENTITY - output is in P-Values. + + + This icon image is representative of the Image. Only a single Item shall be permitted in this Sequence. + + +
+ + + A number identifying the single continuous gathering of data over a period of time that resulted in this image. +Note: This number is not required to be unique across SOP Instances in a series. See also the description of the Referenced Raw Data Sequence (0008,9121). + + + The date and time that the acquisition of data started. +Note: The synchronization of this time with an external clock is specified in the synchronization Module in Acquisition Time synchronized (0018,1800). +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED. May be present otherwise. + + + The time in seconds needed to run the prescribed pulse sequence. See C.7.6.16.2.2.1 for further explanation. +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED. May be present otherwise. +
Figure C.7.6.16-2 shows the relationships among the various timing parameters used. +
+
+ + A sequence that identifies the set of Raw Data SOP Class/Instance pairs of the Raw data which were used to derive this Image. +One or more Items may be included in this Sequence. +Note: The items of in this sequence may identify raw data that has not been stored or encoded as a DICOM object. This allows recognition that images and spectra in different instances have been reconstructed from the same raw data. + + + + References to waveforms acquired in conjunction with this image. These Waveforms may or may not be temporally synchronized with this image. +One or more Items may be included in this Sequence. + + + + Full set of Composite SOP Instances referred to inside the Referenced Image Sequences of this Enhanced MR Image SOP Instance. See C.8.13.2.1.2 for further explanation. +One or more Items may be included in this sequence. +Required if the Referenced Image Sequence (0008,1140) is present. +
The intent of the Referenced Image Evidence Sequence (0008,9092) and Source Image Evidence Sequence (0008,9154) is to provide a list of all unique SOP Instances listed in the Referenced Image Sequence (0008,1140) and Source Image Sequence (0008,2112) attributes respectively. +
+
+ + + Full set of Composite SOP Instances referred to inside the Source Image Sequences of this Enhanced MR Image SOP Instance. See C.8.13.2.1.2 for further explanation. +One or more Items may be included in this sequence. +Required if the Source Image Sequence (0008,2112) is present. +
The intent of the Referenced Image Evidence Sequence (0008,9092) and Source Image Evidence Sequence (0008,9154) is to provide a list of all unique SOP Instances listed in the Referenced Image Sequence (0008,1140) and Source Image Sequence (0008,2112) attributes respectively. +
+
+ + + References to Grayscale Presentation State instances acquired in conjunction with this instance. +Note: May only be used to reference Presentation States belonging to the acquired data and not to reference Presentation States generated subsequently such as during interpretation. +One or more Items may be included in this sequence. +Required if Presentation State is generated during acquisition, shall not be present otherwise. + + + + Content Qualification Indicator +Enumerated Values: +PRODUCT +RESEARCH +SERVICE +See C.8.13.2.1.1 for further explanation. +
Content Qualification (0018,9004) shall have the value PRODUCT if the content (image or Spectroscopy data) was produced with approved hardware and software. It shall have the value RESEARCH or SERVICE if there is any doubt as to whether the content was produced with approved hardware and software. +If data with Content Qualification (0018,9004) of RESEARCH or SERVICE is used to derive other content then it is expected that this derived content will also have Content Qualification (0018,9004) set to RESEARCH or SERVICE. +The intent of this element is to allow annotation of an advisory message that indicates that this content may not be suitable for clinical interpretation. +
+
+ + Nucleus that is resonant at the transmitter frequency. +Defined Terms: +1H +3HE +7LI +13C +19F +23NA +31P +129XE +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED. May be present otherwise. + + + Describes k-space filtering applied. Shall be NONE if no k-space filter. +Defined Terms: +COSINE +COSINE_SQUARED +FERMI +GAUSSIAN +HAMMING +HANNING +LORENTZIAN +LRNTZ_GSS_TRNSFM +RIESZ +TUKEY +NONE +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED. May be present otherwise. + + + Nominal field strength of the MR Magnet, in Tesla. +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED. May be present otherwise. + + + Agency that established MR safety standard applicable to the acquisition of this Instance. +Defined Terms: +IEC +FDA +MHW + + + Name and Version of the applicable standard. + + + User-defined comments about the image. + +
+ + + Representation of complex data of frames in the SOP Instance. See C.8.13.3.1.5 for a description and Defined Terms. +
The value of the Complex Image Component attribute (0008,9208) shall be used to indicate which component of the complex representation of the signal is represented in the pixel data. +Table C.8-85 specifies the Defined Terms for Complex Image Component attribute (0008,9208). +Table C.8-85 +COMPLEX IMAGE COMPONENT ATTRIBUTE VALUES + +
+
+ + Indication of acquisition contrast used with frames in the SOP Instance. See C.8.13.3.1.6 for a description and Defined Terms. +
Table C.8-86 specifies the Defined Terms for Acquisition Contrast attribute (0008,9209). +Table C.8-86 +ACQUISITION CONTRAST VALUES + +
+
+
+ + + Name of the pulse sequence for annotation purposes. Potentially vendor-specific name. +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED. May be present otherwise. + + + Identification of spatial data encoding scheme. +Defined Terms: +1D +2D +3D +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED. May be present otherwise. + + + Echo category of pulse sequences. +Enumerated Values: +SPIN +GRADIENT +BOTH +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED. May be present otherwise. + + + Multiple Spin Echo category of pulse sequence used to collect different lines in k-space for a single frame. +Enumerated Values: +YES +NO +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED and Echo Pulse sequence (0018,9008) equals SPIN or BOTH. +Otherwise may be present if Image Type (0008,0008) Value 1 is DERIVED and Echo Pulse sequence (0018,9008) equals SPIN or BOTH. + + + Technique that simultaneously excites several volumes. +Enumerated Values: +YES +NO +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED. May be present otherwise. + + + Phase Contrast Pulse sequence is a pulse sequence in which the flowing spins are velocity encoded in phase. +Enumerated Values: +YES +NO +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED. May be present otherwise. + + + Time of Flight contrast is created by the inflow of blood in the saturated plane. +Enumerated Values: +YES +NO +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED. May be present otherwise. + + + Steady State Sequence. +Defined Terms: +FREE_PRECESSION +TRANSVERSE +TIME_REVERSED +LONGITUDINAL +NONE +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED. May be present otherwise. + + + Echo Planar category of Pulse Sequences. +Enumerated Values: +YES +NO +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED. May be present otherwise. + + + Saturation recovery pulse sequence. +Enumerated Values: +YES +NO +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED. May be present otherwise. + + + Spectrally Selected Suppression. +Defined Terms: +FAT +WATER +FAT_AND_WATER +SILICON_GEL +NONE +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED. May be present otherwise. + + + Oversampling Phase. +Enumerated Values: +2D = phase direction +3D = out of plane direction +2D_3D = both +NONE +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED. May be present otherwise. + + + Geometry category of k-Space traversal. +Defined Terms: +RECTILINEAR +RADIAL +SPIRAL +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED. May be present otherwise. + + + Rectilinear phase encode reordering. +Defined Terms: +LINEAR +CENTRIC +SEGMENTED +REVERSE_LINEAR +REVERSE_CENTRIC +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED and Geometry of k-Space Traversal (0018,9032) equals RECTILINEAR. +Otherwise may be present if Image Type (0008,0008) Value 1 is DERIVED and Geometry of k-Space Traversal (0018,9032) equals RECTILINEAR. + + + Segmented k-Space traversal. If Geometry of k-Space Traversal is rectilinear, multiple lines can be acquired at one time. If Geometry of k-Space Traversal is spiral or radial, paths can be interleaved and acquired at one time. +Enumerated Values: +SINGLE = successive single echo coverage +PARTIAL = segmented coverage +FULL = single shot full coverage +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED. May be present otherwise. + + + Coverage of k-Space in the ky-kz plane. +Defined Terms: +FULL +CYLINDRICAL +ELLIPSOIDAL +WEIGHTED +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED and MR Acquisition Type (0018,0023) equals 3D. +Otherwise may be present if Image Type (0008,0008) Value 1 is DERIVED and MR Acquisition Type (0018,0023) equals 3D. + + + Number of interleaves or shots. +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED. May be present otherwise. + + + + + Identifies the characteristics of this frame. Only a single Item shall be permitted in this sequence. + + + Type of Frame. A multi-valued attribute analogous to the Image Type (0008,0008). +Enumerated Values and Defined Terms are the same as those for the four values of the Image Type (0008,0008) attribute, except that the value MIXED is not allowed. See C.8.16.1 and C.8.13.3.1.1. +
The Image Type (0008,0008) and associated Image Type related attributes provide a high level description of a multi-frame SOP Instance. These attributes describe properties that provide key summary information to users of the SOP Instance. Image Type (0008,0008) contains the highest level summary of what is in the SOP Instance. +The Frame Type (0008,9007) attribute mirrors the corresponding Image Type attribute and applies to the frame level rather than to the image level. +If more than one value is used by the set of frames for a given Frame Type (0008,9007) attribute value or associated attribute value then the corresponding value of the Image Type (0008,0008) or associated attribute shall contain a value of MIXED. This indicates that a mixed set of values exists within the multi-frame SOP Instance. +The value MIXED shall only be used in the Image Type (0008,0008) when the corresponding values for the individual frames are not equal. When a value of an attribute is equal for all frames, the same value shall be used for the corresponding value of the Image Type (0008,0008). Values 2 and 3 of Image Type (0008,0008) are an exception to the rule for MIXED: Values 2 and 3 may never have the value of MIXED as described in sections C.8.16.1.2 and C.8.16.1.3. +Image Type (0008,0008) and Frame Type (0008,9007) shall consist of four non-zero length values. +
+
+ + +
+ + + Identifies the timing and safety information of this frame. Only a single Item shall be permitted in this sequence. + + + The time in ms between two successive excitations of the same volume. Shall be 0 (zero) if there is a single excitation per volume. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. + + + Steady state angle in degrees to which the magnetic vector is flipped from the magnetic vector of the primary field. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. + + + Number of lines in k-space acquired per excitation of the same volume regardless of the type of echo or the number of frames derived from them. See section C.8.12.5.2.1. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. + + + Number of RF echoes collected per RF shot (or excitation) per frame. A value of zero shall correspond to a pure gradient echo frame. Note that this value corresponds to the current frame. Several frames may be derived from the same shot. See section C.8.13.5.2.1. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. + + + Number of gradient echoes collected per RF echo per shot (or excitation) per frame. A value of zero shall correspond to a pure RF echo frame. If RF Echo Train Length (0018,9240) is non zero and Gradient Echo Train Length is as well then only the central echo will be an RF Spin Echo, all others will be gradient echoes. See section C.8.13.5.2.1. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. + + + Sequence containing the methods of SAR calculation and the corresponding values. One or more items may be present. +Required if the system is capable of calculating Specific Absorption Rate (0018,9181). + + + Specification of the method of SAR calculation as defined in Applicable Safety Standard Description (0018,9174). +Defined Terms: +IEC_WHOLE_BODY +IEC_PARTIAL_BODY +IEC_HEAD +IEC_LOCAL + + + Specific Absorption Rate in W/kg. + + + Definition of gradient output unit, for which the value is stored in Gradient Output (0018,9182). +Defined Terms: +DB_DT = in T/s +ELECTRIC_FIELD = in V/m +PER_NERVE_STIM = percentage of peripheral nerve stimulation +Required if the system is capable of calculating Gradient Output (0018,9182). + + + Unit is defined by Gradient Output Type (0018,9180). +Required if the system is capable of calculating Gradient Output (0018,9182). + + + Sequence of operating mode information relating to the frame/SOP instance as required to adhere to the Applicable Safety Standard Agency (0018,9174) regulations. One or more Items may be included in this sequence. +Required if required by law or regulations. May be present otherwise. + + + Defined Terms: +STATIC FIELD +RF +GRADIENT + + + Operating mode applicable for the defined by the applicable standard. +Defined Terms: +IEC_NORMAL +IEC_FIRST_LEVEL +IEC_SECOND_LEVEL + + + + + Identifies the geometry parameters of this frame. Only a single Item shall be permitted in this sequence. + + + The axes of the in-plane phase encoding with respect to the frame. +Enumerated Values: +COLUMN +ROW +OTHER +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. + + + Number of Frequency Encoding steps (kx) acquired +Required if Frame Type (0008,9007) Value 1 is ORIGINAL. May be present otherwise. + + + Number of In-Plane Phase Encoding steps (ky) acquired +Required if Frame Type (0008,9007) Value 1 is ORIGINAL. May be present otherwise. + + + Number of Out-of-Plane Phase Encoding steps (kz) acquired +Required if MR Acquisition Type (0018,0023) equals 3D and Frame Type (0008,9007) Value 1 is ORIGINAL. May be present otherwise. + + + Fraction of acquisition matrix lines acquired, expressed as a percent. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. + + + Ratio of field of view dimension in phase direction to field of view dimension in frequency direction, expressed as a percent. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. + + + + + Identifies echo timing of this frame. Only a single Item shall be permitted in this sequence. + + + The time in ms between the middle of the excitation pulse and the peak of the echo produced for kx=0. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. + + + + + Identifies general acquisition parameters of this frame. Only a single Item shall be permitted in this sequence. + + + Inversion Recovery preparatory sequence. +Enumerated Values: +YES +NO +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. + + + Times in ms after the middle of inverting RF pulse to middle of excitation pulse to detect the amount of longitudinal magnetization. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL and Inversion Recovery (0018,9009) equals YES. +Otherwise may be present if Frame Type (0008,9007) Value 1 is DERIVED and Inversion Recovery (0018,9009) equals YES. + + + Flow Compensation. +Defined Terms: +ACCELERATION +VELOCITY +OTHER +NONE +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. + + + Flow Compensation Direction. +Enumerated Values: +PHASE +FREQUENCY +SLICE_SELECT +SLICE_AND_FREQ +SLICE_FREQ_PHASE +PHASE_AND_FREQ +SLICE_AND_PHASE +OTHER +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL and Flow Compensation (0018,9010) equals other than NONE. +Otherwise may be present if Frame Type (0008,9007) Value 1 is DERIVED and Flow Compensation (0018,9010) equals other than NONE. + + + Spoiling. +Enumerated Values: +RF = RF spoiled +GRADIENT = gradient spoiled +RF_AND_GRADIENT +NONE +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL and Echo Pulse Sequence (0018,9008) equals GRADIENT or BOTH. +Otherwise may be present if Frame Type (0008,9007) Value 1 is DERIVED and Echo Pulse Sequence (0018,9008) equals GRADIENT or BOTH. + + + T2 prepared Pulse Sequence. +Enumerated Values: +YES +NO +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. + + + Spectrally Selected Excitation. +Enumerated Values: +WATER = water excitation +FAT = fat excitation +NONE +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. + + + Spatial Pre-saturation. +Defined Terms: +SLAB +NONE +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. + + + Partial Fourier. +Enumerated Values: +YES +NO +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. + + + Direction of Partial Fourier. +Enumerated Values: +PHASE +FREQUENCY +SLICE_SELECT +COMBINATION +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL and Partial Fourier (0018,9081) equals YES. +Otherwise may be present if Frame Type (0008,9007) Value 1 is DERIVED and Partial Fourier (0018,9081) equals YES. + + + Parallel acquisition has been used to reduce measurement time. +Enumerated Values: +YES +NO +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. + + + Parallel acquisition characteristics. +Defined Terms: +PILS +SENSE +SMASH +OTHER +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL and Parallel Acquisition (0018,9077) equals YES. +Otherwise may be present if Frame Type (0008,9007) Value 1 is DERIVED and Parallel Acquisition (0018,9077) equals YES. + + + Measurement time reduction factor expressed as ratio of original and reduced measurement time for the in-plane direction. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL and Parallel Acquisition (0018,9077) equals YES. +Otherwise may be present if Frame Type (0008,9007) Value 1 is DERIVED and Parallel Acquisition (0018,9077) equals YES. + + + Measurement time reduction factor expressed as ratio of original and reduced measurement time for the out-of-plane direction +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL and Parallel Acquisition (0018,9077) equals YES. +Otherwise may be present if Frame Type (0008,9007) Value 1 is DERIVED and Parallel Acquisition (0018,9077) equals YES. + + + Measurement time reduction factor expressed as ratio of original and reduced measurement time for the second in-plane direction. +Only required for MR Spectroscopy SOP Instances. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL and Parallel Acquisition (0018,9077) equals YES. +Otherwise may be present if Frame Type (0008,9007) Value 1 is DERIVED and Parallel Acquisition (0018,9077) equals YES. + + + + + Identifies sequence containing MR modifier Sequence Attributes. Only one item may be included in this sequence. + + + Magnetization Transfer pulse sequence. +Enumerated Values: +ON_RESONANCE +OFF_RESONANCE +NONE +Required if Frame Type (0008,9007) Value 1 is ORIGINAL. May be present otherwise. + + + Blood Signal Nulling ("Black Blood") preparatory pulse sequence. +Enumerated Values: +YES +NO +Required if Frame Type (0008,9007) Value 1 is ORIGINAL. May be present otherwise. + + + Tagging. +Defined Terms: +GRID +LINE +NONE +Required if Frame Type (0008,9007) Value 1 is ORIGINAL. May be present otherwise. + + + Space between lines in mm. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL and Tagging (0018,9028) is GRID or LINE. +Otherwise may be present if Frame Type (0008,9007) Value 1 is DERIVED and Tagging (0018,9028) is GRID or LINE. + + + Space between the lines in mm in the other direction. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL and Tagging (0018,9028) is GRID. +Otherwise may be present if Frame Type (0008,9007) Value 1 is DERIVED and Tagging (0018,9028) is GRID. + + + Angle of the tag lines relative to the rows axis (left to right) of the image, with a range of 0-180 degrees. The angle is increasing in clockwise direction. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL and Tagging (0018,9028) is GRID or LINE. +Otherwise may be present if Frame Type (0008,9007) Value 1 is DERIVED and Tagging (0018,9028) is GRID or LINE. + + + Angle of the tag lines relative to the rows axis (left to right) of the image, with a range of 0-180 degrees. The angle is increasing in clockwise direction. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL and Tagging (0018,9028) is GRID. +Otherwise may be present if Frame Type (0008,9007) Value 1 is DERIVED and Tagging (0018,9028) is GRID. + + + Thickness of the line in mm. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL and Tagging (0018,9028) is GRID or LINE. +Otherwise may be present if Frame Type (0008,9007) Value 1 is DERIVED and Tagging (0018,9028) is GRID or LINE. + + + Delay time in ms of the beginning of the application of the tagging pattern relative to the last R-peak. + + + Center transmitter frequency in MHz. +Required if Frame Type (0008,9007) Value 1 is ORIGINAL. May be present otherwise. + + + Reciprocal of the effective sampling period, in hertz per pixel. +Required if Frame Type (0008,9007) Value 1 is ORIGINAL. May be present otherwise. + + + + + A sequence that provides information about each receive coil used. Only a single Item shall be permitted in this sequence. + + + Name of receive coil used. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. + + + Name of manufacturer of receive coil. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. + + + Type of receive coil used. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. +Defined Terms: +BODY +VOLUME = head, extremity, etc. +SURFACE +MULTICOIL + + + Indicates whether the receive coil is quadrature. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. +Enumerated Values: +YES = quadrature or circularly polarized +NO = linear + + + A sequence that provides information regarding each element of a multi-coil. It should include attributes for all elements, whether used in the current acquisition or not. One or more Items shall be present. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL and Receive Coil Type (0018,9043) equals MULTICOIL. May be present otherwise only if Receive Coil Type (0018,9043) equals MULTICOIL. + + + Name of element of multi-coil. + + + Indicates whether the multi-coil element was used in the current acquisition. +Enumerated Values: +YES +NO + + + A textual description of the configuration of multi-coil elements which was used in the current acquisition. + + + + + A sequence that provides information about the transmit coil used. Only a single Item shall be permitted in this sequence. + + + Name of transmit coil used. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. + + + Name of manufacturer of transmit coil. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. + + + Type of transmit coil used. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. +Defined Terms: +BODY +VOLUME = head, extremity, etc. +SURFACE + + + + + Identifies the diffusion parameters of this frame. One Item shall be included in this sequence. + + + Diffusion sensitization factor in sec/mm2. This is the actual b-value for original frames and those derived from frames with the same b-value, or the most representative b-value when derived from images with different b-values. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL and Diffusion b-matrix Sequence (0018,9601) is not present. May be present otherwise. + + + Specifies whether diffusion conditions for the frame are directional, or isotropic with respect to direction. +Defined Terms: +DIRECTIONAL +BMATRIX +ISOTROPIC +NONE = to be used when Frame Type (0008,9007) value 4 equals DIFFUSION_ANISO or Diffusion b-value (0018,9087) is 0 (zero). +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. + + + Sequence containing orientations of all diffusion sensitization gradients that were applied during the preparation phase for this frame. One or more Items may be present. +Required if Diffusion Directionality (0018,9075) equals DIRECTIONAL + + + The direction cosines of the diffusion gradient vector with respect to the patient +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. + + + The directional diffusion sensitization expressed as a 3x3 matrix with diagonal symmetry (with six unique elements from which the other elements can be derived). +The rows and columns of the matrix are the X (right to left), Y (anterior to posterior) and Z (foot to head) patient-relative orthogonal axes as defined in C.7.6.2.1.1. +The values are in units of ms/mm2. +Exactly one Item shall be present. +Required if Diffusion Directionality (0018,9075) equals BMATRIX. + + + The value of b[X,X]. + + + The value of b[X,Y]. + + + The value of b[X,Z]. + + + The value of b[Y,Y]. + + + The value of b[Y,Z]. + + + The value of b[Z,Z]. + + + Class of diffusion anisotropy calculation. Defined Terms: +FRACTIONAL +RELATIVE +VOLUME_RATIO +Required if Frame Type (0008,9007) value 4 equals DIFFUSION_ANISO. + + + + + Identifies the averaging parameters of this frame. Only a single Item shall be permitted in this sequence. + + + Maximum number of times any point in k-space is acquired. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. + + + + + A sequence that provides the position of spatial saturation bands deposited as part of the pulse sequence. Zero or more Items may be included in this sequence. + + + Thickness of slab in mm. + + + The direction cosines of a normal vector perpendicular to the saturation plane with respect to the patient. See C.7.6.2.1.1 for further explanation. +
The Image Position (0020,0032) specifies the x, y, and z coordinates of the upper left hand corner of the image; it is the center of the first voxel transmitted. Image Orientation (0020,0037) specifies the direction cosines of the first row and the first column with respect to the patient. These Attributes shall be provide as a pair. Row value for the x, y, and z axes respectively followed by the Column value for the x, y, and z axes respectively. +The direction of the axes is defined fully by the patient’s orientation. The x-axis is increasing to the left hand side of the patient. The y-axis is increasing to the posterior side of the patient. The z-axis is increasing toward the head of the patient. +The patient based coordinate system is a right handed system, i.e. the vector cross product of a unit vector along the positive x-axis and a unit vector along the positive y-axis is equal to a unit vector along the positive z-axis. +Note If a patient lies parallel to the ground, face-up on the table, with his feet-to-head direction same as the front-to-back direction of the imaging equipment, the direction of the axes of this patient based coordinate system and the equipment based coordinate system in previous versions of this Standard will coincide. + +The Image Plane Attributes, in conjunction with the Pixel Spacing Attribute, describe the position and orientation of the image slices relative to the patient-based coordinate system. In each image frame the Image Position (Patient) (0020,0032) specifies the origin of the image with respect to the patient-based coordinate system. RCS and the Image Orientation (Patient) (0020,0037) attribute values specify the orientation of the image frame rows and columns. The mapping of pixel location to the RCS is calculated as follows: + + size 12{ left [ matrix { +P rSub { size 8{x} } {} ## +P rSub { size 8{y} } {} ## +P rSub { size 8{z} } {} ## +1 +} right ]= left [ matrix { +X rSub { size 8{x} } Δi {} # Y rSub { size 8{x} } Δj {} # 0 {} # S rSub { size 8{x} } {} ## +X rSub { size 8{y} } Δi {} # Y rSub { size 8{y} } Δj {} # 0 {} # S rSub { size 8{y} } {} ## +X rSub { size 8{z} } Δi {} # Y rSub { size 8{z} } Δj {} # 0 {} # S rSub { size 8{z} } {} ## +0 {} # 0 {} # 0 {} # 1{} +} right ] left [ matrix { +i {} ## +j {} ## +0 {} ## +1 +} right ]} {} + + = M +Where: +Pxyz The coordinates of the voxel (i,j) in the frame’s image plane in units of mm. +Sxyz The three values of the Image Position (Patient) (0020,0032) attributes. It is the location in mm from the origin of the RCS. +Xxyz The values from the row (X) direction cosine of the Image Orientation (Patient) (0020,0037) attribute. +Yxyz The values from the column (Y) direction cosine of the Image Orientation (Patient) (0020,0037) attribute. +i Column index to the image plane. The first column is index zero. +ï„i Column pixel resolution of the Pixel Spacing (0028,0030) attribute in units of mm. +j Row index to the image plane. The first row index is zero. +ï„j Row pixel resolution of the Pixel Spacing (0028,0030) attribute in units of mm. + +Additional constraints apply: +1) The row and column direction cosine vectors shall be orthogonal, i.e. their dot product shall be zero. +2) The row and column direction cosine vectors shall be normal, i.e. the dot product of each direction cosine vector with itself shall be unity. + +
+
+ + The x, y, and z coordinates of the midpoint of the slab plane in mm with respect to the patient. See C.7.6.2.1.1 for further explanation. +
The Image Position (0020,0032) specifies the x, y, and z coordinates of the upper left hand corner of the image; it is the center of the first voxel transmitted. Image Orientation (0020,0037) specifies the direction cosines of the first row and the first column with respect to the patient. These Attributes shall be provide as a pair. Row value for the x, y, and z axes respectively followed by the Column value for the x, y, and z axes respectively. +The direction of the axes is defined fully by the patient’s orientation. The x-axis is increasing to the left hand side of the patient. The y-axis is increasing to the posterior side of the patient. The z-axis is increasing toward the head of the patient. +The patient based coordinate system is a right handed system, i.e. the vector cross product of a unit vector along the positive x-axis and a unit vector along the positive y-axis is equal to a unit vector along the positive z-axis. +Note If a patient lies parallel to the ground, face-up on the table, with his feet-to-head direction same as the front-to-back direction of the imaging equipment, the direction of the axes of this patient based coordinate system and the equipment based coordinate system in previous versions of this Standard will coincide. + +The Image Plane Attributes, in conjunction with the Pixel Spacing Attribute, describe the position and orientation of the image slices relative to the patient-based coordinate system. In each image frame the Image Position (Patient) (0020,0032) specifies the origin of the image with respect to the patient-based coordinate system. RCS and the Image Orientation (Patient) (0020,0037) attribute values specify the orientation of the image frame rows and columns. The mapping of pixel location to the RCS is calculated as follows: + + size 12{ left [ matrix { +P rSub { size 8{x} } {} ## +P rSub { size 8{y} } {} ## +P rSub { size 8{z} } {} ## +1 +} right ]= left [ matrix { +X rSub { size 8{x} } Δi {} # Y rSub { size 8{x} } Δj {} # 0 {} # S rSub { size 8{x} } {} ## +X rSub { size 8{y} } Δi {} # Y rSub { size 8{y} } Δj {} # 0 {} # S rSub { size 8{y} } {} ## +X rSub { size 8{z} } Δi {} # Y rSub { size 8{z} } Δj {} # 0 {} # S rSub { size 8{z} } {} ## +0 {} # 0 {} # 0 {} # 1{} +} right ] left [ matrix { +i {} ## +j {} ## +0 {} ## +1 +} right ]} {} + + = M +Where: +Pxyz The coordinates of the voxel (i,j) in the frame’s image plane in units of mm. +Sxyz The three values of the Image Position (Patient) (0020,0032) attributes. It is the location in mm from the origin of the RCS. +Xxyz The values from the row (X) direction cosine of the Image Orientation (Patient) (0020,0037) attribute. +Yxyz The values from the column (Y) direction cosine of the Image Orientation (Patient) (0020,0037) attribute. +i Column index to the image plane. The first column is index zero. +ï„i Column pixel resolution of the Pixel Spacing (0028,0030) attribute in units of mm. +j Row index to the image plane. The first row index is zero. +ï„j Row pixel resolution of the Pixel Spacing (0028,0030) attribute in units of mm. + +Additional constraints apply: +1) The row and column direction cosine vectors shall be orthogonal, i.e. their dot product shall be zero. +2) The row and column direction cosine vectors shall be normal, i.e. the dot product of each direction cosine vector with itself shall be unity. + +
+
+
+ + + Describes the chemical shift parameters used to measure the resonant peaks from which the MR metabolite map represented by this frame was derived. Only a single Item shall be permitted in this sequence. + + + Text describing the Metabolite Map. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. + + + When the measured peaks or their ratios can be related to metabolite substances, this sequence may be used to describe the metabolite substance whose resonant peaks are mapped in the Metabolite Map, or the ratio of substance resonant peaks that is mapped. +Only one item shall be present in this Sequence. + + + + The list of frequencies that were used to create the Metabolite Map. One or more Items may be included in this sequence. + + + Minimal value of Chemical Shift Frequency in ppm. + + + Maximum value of Chemical Shift Frequency in ppm. + + + + + Identifies the velocity encoding of this frame. Only a single Item shall be permitted in this sequence. + + + The direction cosines of the velocity encoding vector with respect to the patient. See C.7.6.2.1.1 for further explanation. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. +
The Image Position (0020,0032) specifies the x, y, and z coordinates of the upper left hand corner of the image; it is the center of the first voxel transmitted. Image Orientation (0020,0037) specifies the direction cosines of the first row and the first column with respect to the patient. These Attributes shall be provide as a pair. Row value for the x, y, and z axes respectively followed by the Column value for the x, y, and z axes respectively. +The direction of the axes is defined fully by the patient’s orientation. The x-axis is increasing to the left hand side of the patient. The y-axis is increasing to the posterior side of the patient. The z-axis is increasing toward the head of the patient. +The patient based coordinate system is a right handed system, i.e. the vector cross product of a unit vector along the positive x-axis and a unit vector along the positive y-axis is equal to a unit vector along the positive z-axis. +Note If a patient lies parallel to the ground, face-up on the table, with his feet-to-head direction same as the front-to-back direction of the imaging equipment, the direction of the axes of this patient based coordinate system and the equipment based coordinate system in previous versions of this Standard will coincide. + +The Image Plane Attributes, in conjunction with the Pixel Spacing Attribute, describe the position and orientation of the image slices relative to the patient-based coordinate system. In each image frame the Image Position (Patient) (0020,0032) specifies the origin of the image with respect to the patient-based coordinate system. RCS and the Image Orientation (Patient) (0020,0037) attribute values specify the orientation of the image frame rows and columns. The mapping of pixel location to the RCS is calculated as follows: + + size 12{ left [ matrix { +P rSub { size 8{x} } {} ## +P rSub { size 8{y} } {} ## +P rSub { size 8{z} } {} ## +1 +} right ]= left [ matrix { +X rSub { size 8{x} } Δi {} # Y rSub { size 8{x} } Δj {} # 0 {} # S rSub { size 8{x} } {} ## +X rSub { size 8{y} } Δi {} # Y rSub { size 8{y} } Δj {} # 0 {} # S rSub { size 8{y} } {} ## +X rSub { size 8{z} } Δi {} # Y rSub { size 8{z} } Δj {} # 0 {} # S rSub { size 8{z} } {} ## +0 {} # 0 {} # 0 {} # 1{} +} right ] left [ matrix { +i {} ## +j {} ## +0 {} ## +1 +} right ]} {} + + = M +Where: +Pxyz The coordinates of the voxel (i,j) in the frame’s image plane in units of mm. +Sxyz The three values of the Image Position (Patient) (0020,0032) attributes. It is the location in mm from the origin of the RCS. +Xxyz The values from the row (X) direction cosine of the Image Orientation (Patient) (0020,0037) attribute. +Yxyz The values from the column (Y) direction cosine of the Image Orientation (Patient) (0020,0037) attribute. +i Column index to the image plane. The first column is index zero. +ï„i Column pixel resolution of the Pixel Spacing (0028,0030) attribute in units of mm. +j Row index to the image plane. The first row index is zero. +ï„j Row pixel resolution of the Pixel Spacing (0028,0030) attribute in units of mm. + +Additional constraints apply: +1) The row and column direction cosine vectors shall be orthogonal, i.e. their dot product shall be zero. +2) The row and column direction cosine vectors shall be normal, i.e. the dot product of each direction cosine vector with itself shall be unity. + +
+
+ + Minimum velocity in cm/s. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. + + + Maximum velocity in cm/s. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. + +
+ + + Type of equipment that originally acquired the data used to create the images in this Series. +Enumerated Values: +MR +See section C.7.3.1.1.1 for further explanation. + + + Uniquely identifies the Performed Procedure Step SOP Instance to which the Series is related (e.g. a Modality or General-Purpose Performed Procedure Step SOP Instance). The Sequence shall have one Item. +Required if the Modality Performed Procedure Step SOP Class , General Purpose Performed Procedure Step SOP Class is supported. + + + + + + + Spectroscopy data characteristics. See C.8.14.5.1.1. +
The Image Type (0008,0008) and Frame Type (0008,9007) are not included in this Macro but one or the other is always included in the Module or Macro that invokes this Macro, and they are therefore described here. +In addition to the requirements specified in C.8.16.1 Image Type and Frame Type, the following additional requirements and Defined Terms are specified. +
+
+ + + Precession frequency in MHz of the nucleus being addressed for each spectral axis. +See section C.8.14.1.1 for further explanation of the ordering. +Required if Image Type (0008,0008) Value 1 is ORIGINAL. May be present otherwise. + + + Spectral width in Hz. +See section C.8.14.1.1 for further explanation of the ordering. +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED. May be present otherwise. + + + The chemical shift at the transmitter frequency in ppm. +See section C.8.14.1.1 for further explanation of the ordering. +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED. May be present otherwise. + + + Name of volume localization technique used. Shall be "NONE" if no spatial localization was performed. +Defined Terms: +ILOPS +ISIS +PRIME +PRESS +SLIM +SLOOP +STEAM +NONE +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED. May be present otherwise. + + + A sequence of one or more Items that provide the position of RF excitations used to select a volume of tissue. The selected volume is described by the intersection of the sequence Items. +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED and Volume Localization Technique (0018,9054) is other than NONE. May be present if Volume Localization Technique (0018,9054) is other than NONE. + + + Thickness of slab in mm. + + + The direction cosines of a normal vector perpendicular to the selection plane with respect to the patient. See C.7.6.2.1.1 for further explanation. +
The Image Position (0020,0032) specifies the x, y, and z coordinates of the upper left hand corner of the image; it is the center of the first voxel transmitted. Image Orientation (0020,0037) specifies the direction cosines of the first row and the first column with respect to the patient. These Attributes shall be provide as a pair. Row value for the x, y, and z axes respectively followed by the Column value for the x, y, and z axes respectively. +The direction of the axes is defined fully by the patient’s orientation. The x-axis is increasing to the left hand side of the patient. The y-axis is increasing to the posterior side of the patient. The z-axis is increasing toward the head of the patient. +The patient based coordinate system is a right handed system, i.e. the vector cross product of a unit vector along the positive x-axis and a unit vector along the positive y-axis is equal to a unit vector along the positive z-axis. +Note If a patient lies parallel to the ground, face-up on the table, with his feet-to-head direction same as the front-to-back direction of the imaging equipment, the direction of the axes of this patient based coordinate system and the equipment based coordinate system in previous versions of this Standard will coincide. + +The Image Plane Attributes, in conjunction with the Pixel Spacing Attribute, describe the position and orientation of the image slices relative to the patient-based coordinate system. In each image frame the Image Position (Patient) (0020,0032) specifies the origin of the image with respect to the patient-based coordinate system. RCS and the Image Orientation (Patient) (0020,0037) attribute values specify the orientation of the image frame rows and columns. The mapping of pixel location to the RCS is calculated as follows: + + size 12{ left [ matrix { +P rSub { size 8{x} } {} ## +P rSub { size 8{y} } {} ## +P rSub { size 8{z} } {} ## +1 +} right ]= left [ matrix { +X rSub { size 8{x} } Δi {} # Y rSub { size 8{x} } Δj {} # 0 {} # S rSub { size 8{x} } {} ## +X rSub { size 8{y} } Δi {} # Y rSub { size 8{y} } Δj {} # 0 {} # S rSub { size 8{y} } {} ## +X rSub { size 8{z} } Δi {} # Y rSub { size 8{z} } Δj {} # 0 {} # S rSub { size 8{z} } {} ## +0 {} # 0 {} # 0 {} # 1{} +} right ] left [ matrix { +i {} ## +j {} ## +0 {} ## +1 +} right ]} {} + + = M +Where: +Pxyz The coordinates of the voxel (i,j) in the frame’s image plane in units of mm. +Sxyz The three values of the Image Position (Patient) (0020,0032) attributes. It is the location in mm from the origin of the RCS. +Xxyz The values from the row (X) direction cosine of the Image Orientation (Patient) (0020,0037) attribute. +Yxyz The values from the column (Y) direction cosine of the Image Orientation (Patient) (0020,0037) attribute. +i Column index to the image plane. The first column is index zero. +ï„i Column pixel resolution of the Pixel Spacing (0028,0030) attribute in units of mm. +j Row index to the image plane. The first row index is zero. +ï„j Row pixel resolution of the Pixel Spacing (0028,0030) attribute in units of mm. + +Additional constraints apply: +1) The row and column direction cosine vectors shall be orthogonal, i.e. their dot product shall be zero. +2) The row and column direction cosine vectors shall be normal, i.e. the dot product of each direction cosine vector with itself shall be unity. + +
+
+ + The x, y, and z coordinates of the mid-point of the slab in mm. See C.7.6.2.1.1 for further explanation. +
The Image Position (0020,0032) specifies the x, y, and z coordinates of the upper left hand corner of the image; it is the center of the first voxel transmitted. Image Orientation (0020,0037) specifies the direction cosines of the first row and the first column with respect to the patient. These Attributes shall be provide as a pair. Row value for the x, y, and z axes respectively followed by the Column value for the x, y, and z axes respectively. +The direction of the axes is defined fully by the patient’s orientation. The x-axis is increasing to the left hand side of the patient. The y-axis is increasing to the posterior side of the patient. The z-axis is increasing toward the head of the patient. +The patient based coordinate system is a right handed system, i.e. the vector cross product of a unit vector along the positive x-axis and a unit vector along the positive y-axis is equal to a unit vector along the positive z-axis. +Note If a patient lies parallel to the ground, face-up on the table, with his feet-to-head direction same as the front-to-back direction of the imaging equipment, the direction of the axes of this patient based coordinate system and the equipment based coordinate system in previous versions of this Standard will coincide. + +The Image Plane Attributes, in conjunction with the Pixel Spacing Attribute, describe the position and orientation of the image slices relative to the patient-based coordinate system. In each image frame the Image Position (Patient) (0020,0032) specifies the origin of the image with respect to the patient-based coordinate system. RCS and the Image Orientation (Patient) (0020,0037) attribute values specify the orientation of the image frame rows and columns. The mapping of pixel location to the RCS is calculated as follows: + + size 12{ left [ matrix { +P rSub { size 8{x} } {} ## +P rSub { size 8{y} } {} ## +P rSub { size 8{z} } {} ## +1 +} right ]= left [ matrix { +X rSub { size 8{x} } Δi {} # Y rSub { size 8{x} } Δj {} # 0 {} # S rSub { size 8{x} } {} ## +X rSub { size 8{y} } Δi {} # Y rSub { size 8{y} } Δj {} # 0 {} # S rSub { size 8{y} } {} ## +X rSub { size 8{z} } Δi {} # Y rSub { size 8{z} } Δj {} # 0 {} # S rSub { size 8{z} } {} ## +0 {} # 0 {} # 0 {} # 1{} +} right ] left [ matrix { +i {} ## +j {} ## +0 {} ## +1 +} right ]} {} + + = M +Where: +Pxyz The coordinates of the voxel (i,j) in the frame’s image plane in units of mm. +Sxyz The three values of the Image Position (Patient) (0020,0032) attributes. It is the location in mm from the origin of the RCS. +Xxyz The values from the row (X) direction cosine of the Image Orientation (Patient) (0020,0037) attribute. +Yxyz The values from the column (Y) direction cosine of the Image Orientation (Patient) (0020,0037) attribute. +i Column index to the image plane. The first column is index zero. +ï„i Column pixel resolution of the Pixel Spacing (0028,0030) attribute in units of mm. +j Row index to the image plane. The first row index is zero. +ï„j Row pixel resolution of the Pixel Spacing (0028,0030) attribute in units of mm. + +Additional constraints apply: +1) The row and column direction cosine vectors shall be orthogonal, i.e. their dot product shall be zero. +2) The row and column direction cosine vectors shall be normal, i.e. the dot product of each direction cosine vector with itself shall be unity. + +
+
+ + Indicates whether de-coupling was active. +Enumerated Values: +YES +NO +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED. May be present otherwise. + + + Nucleus being de-coupled. +Defined Terms: +1H +3HE +7LI +13C +19F +23NA +31P +129XE +See section C.8.14.1.1 for further explanation of the ordering. +Required if De-coupling (0018,9059) equals YES. + + + The center frequency (Hz) for the de-coupling. +See section C.8.14.1.1 for further explanation of the ordering. +Required if De-coupling (0018,9059) equals YES. + + + The de-coupling modulation scheme used. +Defined Terms: +MLEV +WALTZ +NARROWBAND +Required if De-coupling (0018,9059) equals YES. + + + The chemical shift in ppm at the de-coupling frequency. +See section C.8.14.1.1 for further explanation of the ordering. +Required if De-coupling (0018,9059) equals YES. + + + Describes time domain filtering or apodization applied. Shall be NONE if no filtering operations were applied to the time domain data. +Defined Terms: +COSINE +COSINE_SQUARED +EXPONENTIAL +GAUSSIAN +HAMMING +HANNING +LORENTZIAN +LRNTZ_GSS_TRNSFM +NONE +See section C.8.14.1.1 for further explanation of the ordering. +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED. May be present otherwise. + + + Number of zero fills added to the time domain data before FT. Shall be 0 (zero) if no zero filling performed. +See section C.8.14.1.1 for further explanation of the ordering. +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED. May be present otherwise. + + + Describes baseline correction techniques. Shall be NONE if no baseline correction was performed. +Defined Terms: +LINEAR_TILT +LOCAL_LINEAR_FIT +POLYNOMIAL_FIT +SINC_DECONVOLUTN +TIME_DOMAIN_FIT +SPLINE +NONE +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED. May be present otherwise. + + + Specifies whether operations were performed to correct resonant frequency of metabolite peaks due to B0 field inhomogeneities. +Enumerated Values: +YES +NO +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED. May be present otherwise. + + + Describes whether a first order (frequency dependent) phase correction was applied to the spectral data. +Enumerated Values: +YES +NO +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED. May be present otherwise. + + + Enumerated Values: +YES +NO +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED. May be present otherwise. + +
+ + + Name of the pulse sequence for annotation purposes. Potentially vendor-specific name. +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED. May be present otherwise. + + + Identification of data encoding scheme. +Defined Terms: +SINGLE_VOXEL +ROW +PLANE +VOLUME +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED. May be present otherwise. + + + Echo category of pulse sequences. +Enumerated Values: +SPIN +GRADIENT +BOTH +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED. May be present otherwise. + + + Multiple Spin Echo category of pulse sequence used to collect different lines in k-space for a single frame. +Enumerated Values: +YES +NO +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED and Echo Pulse Sequence (0018,9008) equals SPIN or BOTH. +Otherwise may be present if Image Type (0008,0008) Value 1 is DERIVED and Echo Pulse Sequence (0018,9008) equals SPIN or BOTH. + + + Technique that simultaneously excites several volumes. +Enumerated Values: +YES +NO +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED. May be present otherwise. + + + Steady State Sequence. +Defined Terms: +FREE_PRECESSION +TRANSVERSE +TIME_REVERSED +LONGITUDINAL +NONE +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED. May be present otherwise. + + + Echo Planar category of pulse-sequences. +Enumerated Values: +YES +NO +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED. May be present otherwise. + + + Spectrally Selected Suppression. +Defined Terms: +WATER +FAT +FAT_AND_WATER +SILICON_GEL +NONE +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED. May be present otherwise. + + + Geometry category of k-Space traversal. +Defined Terms: +RECTILINEAR +RADIAL +SPIRAL +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED. May be present otherwise. + + + Rectilinear phase encode reordering. +Defined Terms: +LINEAR +CENTRIC +SEGMENTED +REVERSE_LINEAR +REVERSE_CENTRIC +Required if Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED and Geometry of k-Space Traversal (0018,9032) equals RECTILINEAR. +Otherwise may be present if Image Type (0008,0008) Value 1 is DERIVED and Geometry of k-Space Traversal (0018,9032) equals RECTILINEAR. + + + Segmented k-Space traversal. If Geometry of k-Space Traversal is rectilinear, multiple lines can be acquired at one time. If Geometry of k-Space Traversal is spiral or radial, paths can be interleaved and acquired at one time. +Enumerated Values: +SINGLE = successive single echo coverage +PARTIAL = segmented coverage +FULL = single shot full coverage +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED. May be present otherwise. + + + Coverage of k-Space. +Defined Terms: +FULL +CYLINDRICAL +ELLIPSOIDAL +WEIGHTED +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED and MR Spectroscopy Acquisition Type (0018,9200) equals VOLUME. +Otherwise may be present if Image Type (0008,0008) Value 1 is DERIVED and MR Spectroscopy Acquisition Type (0018,9200) equals VOLUME. + + + Number of interleaves or shots. +Required if Image Type (0008,0008) Value 1 is ORIGINAL or MIXED. May be present otherwise. + + + + + Identifies sequence containing Frame Type Attributes. Only a single Item shall be permitted in this sequence. + + + Spectroscopy data characteristics. See C.8.14.5.1.1. +
The Image Type (0008,0008) and Frame Type (0008,9007) are not included in this Macro but one or the other is always included in the Module or Macro that invokes this Macro, and they are therefore described here. +In addition to the requirements specified in C.8.16.1 Image Type and Frame Type, the following additional requirements and Defined Terms are specified. +
+
+ +
+ + + Identifies the geometry parameters of this frame. Only a single Item shall be permitted in this sequence. + + + Number of data points in the columns direction. +Required if Frame Type (0008,9007) Value 1 is ORIGINAL. May be present otherwise. + + + Number of Phase Encoding Rows. +Required if Frame Type (0008,9007) Value 1 is ORIGINAL. May be present otherwise. + + + Number of Phase Encoding Columns. +Required if Frame Type (0008,9007) Value 1 is ORIGINAL. May be present otherwise. + + + Number of out-of-plane Phase Encoding steps. +Required if MR Spectroscopy Acquisition Type (0018,9200) equals PLANE and Frame Type (0008,9007) Value 1 is ORIGINAL. May be present otherwise. + + + Fraction of acquisition matrix lines acquired, expressed as a percent. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. + + + Ratio of field of view dimension in phase direction to field of view dimension in frequency direction, expressed as a percent. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. + + + + + Number of voxels in the vertical direction in the frame. + + + Number of voxels in the horizontal direction in the frame. + + + Number of rows of data points in spectroscopic data. + + + Number of columns of data points in spectroscopic data. + + + Data representation of the data points. Each data point shall have the same representation. +Enumerated Values: +COMPLEX = Data is complex pair +REAL = Data contains only real component +IMAGINARY = Data contains only imaginary component +MAGNITUDE = Magnitude data + + + Domain of represented signal in column direction. +Enumerated Values: +FREQUENCY +TIME + + + Domain of represented signal in row direction. +Enumerated Values: +FREQUENCY +TIME +Required if Data Point Rows (0028,9001) has a value of more than 1. + + + First Order Phase Correction Angle. Number of values is determined by Row  Column  Number of Frames. +Required if First Order Phase Correction (0018,9198) equals YES + + + A data stream of the signal intensities that comprise the spectroscopic data. See C.8.14.4.1 for further explanation. +
The Spectroscopy Data attribute (5600,0020) contains the Signal intensities for the spectra. The order of voxels sent for each spectral plane is left to right, top to bottom, i.e., the upper left voxel (labeled 1,1) is sent first followed by the remainder of row 1, followed by the first voxel of row 2 (labeled 2,1) then the remainder of row 2 and so on. Each "voxel" represents an entire spectrum. The complete spectral data from each voxel is sent, followed by the spectral data from the next voxel position. +The number of voxels on each frame are described by Rows (0028,0010) and Columns (0028,0011). The number of frames is described by Number of Frames (0028,0008). The frames may represent different locations in a 3D acquisition, or the same position at a different point of time, or a difference of some other combination of attributes. +Note: Either Rows or Columns or both may have a value of 1 (e.g., for single voxel spectroscopy). A value of zero for the corresponding value of Pixel Spacing in the Pixel Measures Macro is permitted under these circumstances. See 10.7.1.3. + +The spectral data points are ordered from lower effective magnetic field strength (down-field) to higher effective magnetic field strength (up-field) when the Signal Domain Columns (0028,9003) or Signal Domain Rows (0028,9235) attributes contain the value FREQUENCY and from first sample acquired to last sample acquired when the Signal Domain Columns (0028,9003) or Signal Domain Rows (0028,9235) attributes contain the value TIME. +For two-dimensional spectral acquisitions, the ordering is such that all data points from a row (corresponding to all data points acquired in an individual sampling period), are followed by all data points from the successive sampling period. Following all data of the rows from a given voxel position, the data from the subsequent voxel position are sent. The axis parallel to the row direction corresponds to the sampling time axis. The axis parallel to the column direction corresponds to the evolution time axis. +The dimensions of each spectrum that make up a voxel are described by Data Point Rows (0028,9001) and Data Point Columns (0028,9002). In the case of 1D spectra, the number of Data Point Rows shall be 1. +For a Data Representation (0028,9108) value of COMPLEX, the order of data points is real channel followed by imaginary channel for each spectral data point. For the other Data Representation values (REAL, IMAGINARY and MAGNITUDE), each spectral data point contains only a single value. +The Figure C.8-18 depicts 6 frames each made up of 4 rows and 4 columns of voxels. Specific values for Data Point Rows (0028,9001) and Data Point Columns (0028,9002) of these voxels are not depicted. +
+
+
+ + + Indication if geometric manipulations are possible with frames in the SOP Instance. See C.8.14.5.1.2 for a description and Enumerated Values. +
See C.8.16.2.1.2. No additional requirements or Defined Terms. +
+
+ + Method used for volume calculations with frames in the SOP Instance. See C.8.14.5.1.3 for a description and Defined Terms. +
See C.8.16.2.1.3 for requirements, but not Defined Terms. +Table C.8-110 specifies the Defined Terms for the Volume Based Calculation Technique (0008,9207) attribute. +Table C.8-110 +VOLUME BASED CALCULATION TECHNIQUE ATTRIBUTE VALUES + +
+
+ + Representation of complex data of frames in the SOP Instance. See C.8.14.5.1.4 for a description and Defined Terms. +
The value of the Complex Image Component attribute (0008,9208) shall be used to indicate which component of the complex representation of the signal is represented in the spectroscopy data. +Table C.8-111 specifies the Defined Terms for Complex Image Component attribute (0008,9208). +Table C.8-111 +COMPLEX IMAGE COMPONENT ATTRIBUTE VALUES + +
+
+ + Indication of acquisition contrast used with frames in the SOP Instance. See C.8.14.5.1.5 for a description and Defined Terms. +
Table C.8-112 specifies the Defined Terms for Acquisition Contrast attribute (0008,9209). +Table C.8-112 +ACQUISITION CONTRAST VALUES + +
+
+
+ + + Type of equipment that originally acquired the data used to create the images in this Series. +Enumerated Values: +CT +See section C.7.3.1.1.1 for further explanation. + + + Uniquely identifies the Performed Procedure Step SOP Instance to which the Series is related (e.g. a Modality or General-Purpose Performed Procedure Step SOP Instance). The Sequence shall have one Item. +Required if the Modality Performed Procedure Step SOP Class , General Purpose Performed Procedure Step SOP Class is supported. + + + + + + Image characteristics. See sections C.8.16.1 and C.8.15.2.1.1. + + + + A number identifying the single continuous gathering of data over a period of time that resulted in this image. +Note: This number is not required to be unique across SOP Instances in a series. See also the description of the Referenced Raw Data Sequence (0008,9121). + + + The date and time that the acquisition of data started. +Notes: 1. The synchronization of this time with an external clock is specified in the synchronization Module in Acquisition Time synchronized (0018,1800) . +2. See C.7.6.16.2.2.1 for an overview of all acquisition related timing attributes. +Required if Image Type (0008,0008) Value 1 of this frame is ORIGINAL or MIXED, may be present otherwise. +
Figure C.7.6.16-2 shows the relationships among the various timing parameters used. +
+
+ + The time in seconds needed to complete the acquisition of data. See C.7.6.16.2.2.1 for further explanation. +Required if Image Type (0008,0008) Value 1 of this frame is ORIGINAL or MIXED, may be present otherwise. +
Figure C.7.6.16-2 shows the relationships among the various timing parameters used. +
+
+ + A sequence that identifies the set of Raw Data SOP Class/Instance pairs of the Raw data that were used to derive this Image. +One or more Items may be included in this Sequence. +Note: The items of in this sequence may identify raw data that has not been stored or encoded as a DICOM object. This allows recognition that images in different instances have been reconstructed from the same raw data. + + + + References to waveforms acquired in conjunction with this image. These Waveforms may or may not be temporally synchronized with this image. +One or more Items may be included in this sequence. + + + + Full set of Composite SOP Instances referring to image SOP Instances inside the frames of this Enhanced CT Image SOP Instance. See C.8.13.2.1.2 for further explanation. +One or more Items may be included in this sequence. +Required if the Referenced Image Sequence (0008,1140) is present. +
The intent of the Referenced Image Evidence Sequence (0008,9092) and Source Image Evidence Sequence (0008,9154) is to provide a list of all unique SOP Instances listed in the Referenced Image Sequence (0008,1140) and Source Image Sequence (0008,2112) attributes respectively. +
+
+ + + Full set of Composite SOP Instances used as source image SOP Instances inside the frames of this Enhanced CT Image SOP Instance. See C.8.13.2.1.2 for further explanation. +One or more Items may be included in this sequence. +Required if the Source Image Sequence (0008,2112) is present. +
The intent of the Referenced Image Evidence Sequence (0008,9092) and Source Image Evidence Sequence (0008,9154) is to provide a list of all unique SOP Instances listed in the Referenced Image Sequence (0008,1140) and Source Image Sequence (0008,2112) attributes respectively. +
+
+ + + References to Grayscale Presentation State instances acquired in conjunction with this instance. +Note: May only be used to reference Presentation States belonging to the acquired data and not to reference Presentation States generated subsequently such as during interpretation. +One or more Items may be included in this sequence. +Required if Presentation State is generated during acquisition, shall not be present otherwise. + + + + Number of samples (planes) in this image. This value shall be 1. + + + Specifies the intended interpretation of the pixel data. Enumerated Value: MONOCHROME2. +See C.7.6.3.1.2 for definition of this term. +
The value of Photometric Interpretation (0028,0004) specifies the intended interpretation of the image pixel data. +See PS 3.5 for restrictions imposed by compressed Transfer Syntaxes. +The following values are defined. Other values are permitted but the meaning is not defined by this Standard. +MONOCHROME1 = Pixel data represent a single monochrome image plane. The minimum sample value is intended to be displayed as white after any VOI gray scale transformations have been performed. See PS 3.4. This value may be used only when Samples per Pixel (0028,0002) has a value of 1. +MONOCHROME2 = Pixel data represent a single monochrome image plane. The minimum sample value is intended to be displayed as black after any VOI gray scale transformations have been performed. See PS 3.4. This value may be used only when Samples per Pixel (0028,0002) has a value of 1. +PALETTE COLOR = Pixel data describe a color image with a single sample per pixel (single image plane). The pixel value is used as an index into each of the Red, Blue, and Green Palette Color Lookup Tables (0028,1101-1103&1201-1203). This value may be used only when Samples per Pixel (0028,0002) has a value of 1. When the Photometric Interpretation is Palette Color; Red, Blue, and Green Palette Color Lookup Tables shall be present. +RGB = Pixel data represent a color image described by red, green, and blue image planes. The minimum sample value for each color plane represents minimum intensity of the color. This value may be used only when Samples per Pixel (0028,0002) has a value of 3. +HSV = Retired. +ARGB = Retired. +CMYK = Retired. +YBR_FULL = Pixel data represent a color image described by one luminance (Y) and two chrominance planes (CB and CR). This photometric interpretation may be used only when Samples per Pixel (0028,0002) has a value of 3. Black is represented by Y equal to zero. The absence of color is represented by both CB and CR values equal to half full scale. +Note: In the case where the Bits Allocated (0028,0100) has value of 8 half full scale is 128. + +In the case where Bits Allocated (0028,0100) has a value of 8 then the following equations convert between RGB and YCBCR Photometric Interpretation. +Y = + .2990R + .5870G + .1140B +CB = - .1687R - .3313G + .5000B + 128 +CR = + .5000R - .4187G - .0813B + 128 +Note: The above is based on CCIR Recommendation 601-2 dated 1990. + +YBR_FULL_422 = The same as YBR_FULL except that the CB and CR values are sampled horizontally at half the Y rate and as a result there are half as many CB and CR values as Y values. +This Photometric Interpretation is only allowed with Planar Configuration (0028,0006) equal to 0. Two Y values shall be stored followed by one CB and one CR value. The CB and CR values shall be sampled at the location of the first of the two Y values. For each Row of Pixels, the first CB and CR samples shall be at the location of the first Y sample. The next CB and CR samples shall be at the location of the third Y sample etc. +Note: This subsampling is often referred to as cosited sampling. + +YBR_PARTIAL_422 = The same as YBR_FULL_422 except that: +1. black corresponds to Y = 16; +2. Y is restricted to 220 levels (i.e. the maximum value is 235); +3. CB and CR each has a minimum value of 16; +4. CB and CR are restricted to 225 levels (i.e. the maximum value is 240); +5. lack of color is represented by CB and CR equal to 128. +In the case where Bits Allocated (0028,0100) has value of 8 then the following equations convert between RGB and YBR_PARTIAL_422 Photometric Interpretation +Y = + .2568R + .5041G + .0979B + 16 +CB = - .1482R - .2910G + .4392B + 128 +CR = + .4392R - .3678G - .0714B + 128 +Note: The above is based on CCIR Recommendation 601-2 dated 1990. + +YBR_PARTIAL_420 = The same as YBR_PARTIAL_422 except that the CB and CR values are sampled horizontally and vertically at half the Y rate and as a result there are four times less CB and CR values than Y values, versus twice less for YBR_PARTIAL_422. +This Photometric Interpretation is only allowed with Planar Configuration (0028,0006) equal to 0. The CB and CR values shall be sampled at the location of the first of the two Y values. For the first Row of Pixels (etc.), the first CB and CR samples shall be at the location of the first Y sample. The next CB and CR samples shall be at the location of the third Y sample etc. The next Rows of Pixels containing CB and CR samples (at the same locations than for the first Row) will be the third etc. +YBR_ICT = Irreversible Color Transformation: +Pixel data represent a color image described by one luminance (Y) and two chrominance planes (CB and CR). This photometric interpretation may be used only when Samples per Pixel (0028,0002) has a value of 3. Black is represented by Y equal to zero. The absence of color is represented by both CB and CR values equal to zero. +Regardless of the value of Bits Allocated (0028,0100), the following equations convert between RGB and YCBCR Photometric Interpretation. +Y = + .29900R + .58700G + .11400B +CB = - .16875R - .33126G + .50000B +CR = + .50000R - .41869G - .08131B +Notes: 1. The above is based on ISO/IEC 15444-1 (JPEG 2000). + 2. In a JPEG 2000 bitstream, DC level shifting (used if the untransformed components are unsigned) is applied before forward color transformation, and the transformed components may be signed (unlike in JPEG ISO/IEC 10918-1). + 3. In JPEG 2000, spatial down-sampling of the chrominance components, if performed, is signaled in the JPEG 2000 bitstream. + +YBR_RCT = Reversible Color Transformation: +Pixel data represent a color image described by one luminance (Y) and two chrominance planes (CB and CR). This photometric interpretation may be used only when Samples per Pixel (0028,0002) has a value of 3. Black is represented by Y equal to zero. The absence of color is represented by both CB and CR values equal to zero. +Regardless of the value of Bits Allocated (0028,0100), the following equations convert between RGB and YBR_RCT Photometric Interpretation. +Y = R + 2G +B) / 4 (Note:  mean floor) +CB = B - G +CR = R - G +The following equations convert between YBR_RCT and RGB Photometric Interpretation. +G = Y –  (CR + CB) / 4 +R = CR + G +B = CB + G +Notes: 1. The above is based on ISO/IEC 15444-1 (JPEG 2000). + 2. In a JPEG 2000 bitstream, DC level shifting (used if the untransformed components are unsigned) is applied before forward color transformation, and the transformed components may be signed (unlike in JPEG ISO/IEC 10918-1). + 3. This photometric interpretation is a reversible approximation to the YUV transformation used in PAL and SECAM. + +
+
+ + Number of bits allocated for each pixel sample. Each sample shall have the same number of bits allocated. This value shall be 16. + + + Number of bits stored for each pixel sample. Each sample shall have the same number of bits stored. This value shall be 12 or16. + + + Most significant bit for pixel sample data. Each sample shall have the same high bit. Shall be one less than the value in Bits Stored (0028,0101). + + + Content Qualification Indicator +Enumerated Values: +PRODUCT +RESEARCH +SERVICE +See C.8.13.2.1.1 for further explanation. +
Content Qualification (0018,9004) shall have the value PRODUCT if the content (image or Spectroscopy data) was produced with approved hardware and software. It shall have the value RESEARCH or SERVICE if there is any doubt as to whether the content was produced with approved hardware and software. +If data with Content Qualification (0018,9004) of RESEARCH or SERVICE is used to derive other content then it is expected that this derived content will also have Content Qualification (0018,9004) set to RESEARCH or SERVICE. +The intent of this element is to allow annotation of an advisory message that indicates that this content may not be suitable for clinical interpretation. +
+
+ + User-defined comments about the image + + + Indicates whether or not the image contains sufficient burned in annotation to identify the patient and date the image was acquired. +Enumerated Values: +NO +This means that images that contain this Module shall not contain such burned in annotations. + + + Specifies whether an Image has undergone lossy compression. Enumerated Values: +00 = Image has NOT been subjected to lossy compression. +01 = Image has been subjected to lossy compression. +See C.7.6.1.1.5 for further explanation. +
The Attribute Lossy Image Compression (0028,2110) conveys that the Image has undergone lossy compression. It provides a means to record that the Image has been compressed (at a point in its lifetime) with a lossy algorithm and changes have been introduced into the pixel data. Once the value has been set to “01â€, it shall not be reset. +Note: If an image is compressed with a lossy algorithm, the attribute Lossy Image Compression (0028,2110) is set to “01â€. Subsequently, if the image is decompressed and transferred in uncompressed format, this attribute value remains “01â€. + +The value of the Lossy Image Compression (0028,2110) Attribute in SOP Instances containing multiple frames in which one or more of the frames have undergone lossy compression shall be “01â€. +Note: It is recommended that the applicable frames be noted in the Attribute Derivation Description (0008,2111). + +If an image is originally obtained as a lossy compressed image from the sensor, then Lossy Image Compression (0028,2110) is set to “01†and Value 1 of the Attribute Image Type (0008,0008) shall be set to ORIGINAL. +If an image is a compressed version of another image, Lossy Image Compression (0028,2110) is set to “01â€, Value 1 of the Attribute Image Type (0008,0008) shall be set to DERIVED, and if the predecessor was a DICOM image, then the Image shall receive a new SOP Instance UID. +Note: 1. It is recommended that the approximate compression ratio be provided in the Attribute Derivation Description (0008,2111). Furthermore, it is recommended that Derivation Description (0008,2111) be used to indicate when pixel data changes might affect professional interpretation. (see C.7.6.1.1.3). + 2. The attribute Lossy Image Compression (0028,2110) is defined as Type 3 for backward compatibility with existing IODs. It is expected to be required (i.e., defined as Type 1C) for new Image IODs and for existing IODs that undergo a major revision (e.g. a new IOD is specified). +The Defined Terms for Lossy Image Compression Method (0028,2114) are: +ISO_10918_1 = JPEG Lossy Compression +ISO_14495_1 = JPEG-LS Near-lossless Compression +ISO_15444_1 = JPEG 2000 Irreversible Compression +ISO_13818_2 = MPEG2 Compression + +
+
+ + Describes the approximate lossy compression ratio(s) that have been applied to this image. +See C.7.6.1.1.5 for further explanation. +May be multivalued if successive lossy compression steps have been applied. +Note: For example, a compression ratio of 30:1 would be described in this Attribute with a single value of 30. +Required if Lossy Images Compression (0028,2110) is "01". +
The Attribute Lossy Image Compression (0028,2110) conveys that the Image has undergone lossy compression. It provides a means to record that the Image has been compressed (at a point in its lifetime) with a lossy algorithm and changes have been introduced into the pixel data. Once the value has been set to “01â€, it shall not be reset. +Note: If an image is compressed with a lossy algorithm, the attribute Lossy Image Compression (0028,2110) is set to “01â€. Subsequently, if the image is decompressed and transferred in uncompressed format, this attribute value remains “01â€. + +The value of the Lossy Image Compression (0028,2110) Attribute in SOP Instances containing multiple frames in which one or more of the frames have undergone lossy compression shall be “01â€. +Note: It is recommended that the applicable frames be noted in the Attribute Derivation Description (0008,2111). + +If an image is originally obtained as a lossy compressed image from the sensor, then Lossy Image Compression (0028,2110) is set to “01†and Value 1 of the Attribute Image Type (0008,0008) shall be set to ORIGINAL. +If an image is a compressed version of another image, Lossy Image Compression (0028,2110) is set to “01â€, Value 1 of the Attribute Image Type (0008,0008) shall be set to DERIVED, and if the predecessor was a DICOM image, then the Image shall receive a new SOP Instance UID. +Note: 1. It is recommended that the approximate compression ratio be provided in the Attribute Derivation Description (0008,2111). Furthermore, it is recommended that Derivation Description (0008,2111) be used to indicate when pixel data changes might affect professional interpretation. (see C.7.6.1.1.3). + 2. The attribute Lossy Image Compression (0028,2110) is defined as Type 3 for backward compatibility with existing IODs. It is expected to be required (i.e., defined as Type 1C) for new Image IODs and for existing IODs that undergo a major revision (e.g. a new IOD is specified). +The Defined Terms for Lossy Image Compression Method (0028,2114) are: +ISO_10918_1 = JPEG Lossy Compression +ISO_14495_1 = JPEG-LS Near-lossless Compression +ISO_15444_1 = JPEG 2000 Irreversible Compression +ISO_13818_2 = MPEG2 Compression + +
+
+ + A label for the lossy compression method(s) that have been applied to this image. +See C.7.6.1.1.5 for further explanation. +May be multivalued if successive lossy compression steps have been applied; the value order shall correspond to the values of Lossy Image Compression Ratio (0028,2112). +Required if Lossy Image Compression (0028,2110) is "01". +
The Attribute Lossy Image Compression (0028,2110) conveys that the Image has undergone lossy compression. It provides a means to record that the Image has been compressed (at a point in its lifetime) with a lossy algorithm and changes have been introduced into the pixel data. Once the value has been set to “01â€, it shall not be reset. +Note: If an image is compressed with a lossy algorithm, the attribute Lossy Image Compression (0028,2110) is set to “01â€. Subsequently, if the image is decompressed and transferred in uncompressed format, this attribute value remains “01â€. + +The value of the Lossy Image Compression (0028,2110) Attribute in SOP Instances containing multiple frames in which one or more of the frames have undergone lossy compression shall be “01â€. +Note: It is recommended that the applicable frames be noted in the Attribute Derivation Description (0008,2111). + +If an image is originally obtained as a lossy compressed image from the sensor, then Lossy Image Compression (0028,2110) is set to “01†and Value 1 of the Attribute Image Type (0008,0008) shall be set to ORIGINAL. +If an image is a compressed version of another image, Lossy Image Compression (0028,2110) is set to “01â€, Value 1 of the Attribute Image Type (0008,0008) shall be set to DERIVED, and if the predecessor was a DICOM image, then the Image shall receive a new SOP Instance UID. +Note: 1. It is recommended that the approximate compression ratio be provided in the Attribute Derivation Description (0008,2111). Furthermore, it is recommended that Derivation Description (0008,2111) be used to indicate when pixel data changes might affect professional interpretation. (see C.7.6.1.1.3). + 2. The attribute Lossy Image Compression (0028,2110) is defined as Type 3 for backward compatibility with existing IODs. It is expected to be required (i.e., defined as Type 1C) for new Image IODs and for existing IODs that undergo a major revision (e.g. a new IOD is specified). +The Defined Terms for Lossy Image Compression Method (0028,2114) are: +ISO_10918_1 = JPEG Lossy Compression +ISO_14495_1 = JPEG-LS Near-lossless Compression +ISO_15444_1 = JPEG 2000 Irreversible Compression +ISO_13818_2 = MPEG2 Compression + +
+
+ + Specifies an identity transformation for the Presentation LUT, such that the output of all grayscale transformations defined in the IOD containing this Module are defined to be P-Values. +Enumerated Values: +IDENTITY - output is in P-Values. + + + This icon image is representative of the Image. Only a single Item shall be permitted in this Sequence. + + +
+ + + Identifies the characteristics of this frame. Only a single Item shall be permitted in this sequence. + + + Type of Frame. A multi-valued attribute analogous to the Image Type (0008,0008). +Enumerated Values and Defined Terms are the same as those for the four values of the Image Type (0008,0008) attribute, except that the value MIXED is not allowed. See sections C.8.16.1 and C.8.15.2.1.1.1. + + + + + + Contains the attributes defining the CT acquisition mode. Only a single Item shall be permitted in this sequence. + + + Description of the method used during acquisition of this frame. See C.8.15.3.2.1 for Defined Terms. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. +
Acquisition Type (0018,9302) has the following Defined Terms: +SEQUENCED identifies that the acquisition was performed by acquiring single or multi detector data while rotating the source about the gantry while the table is not moving. Additional slices are acquired by incrementing the table position and again rotating the source about the gantry while the table is not moving. +SPIRAL identifies that the acquisition was performed by acquiring data while rotating the source about the gantry while continuously moving the table. +CONSTANT_ANGLE identifies that the acquisition was performed by holding the source at a constant angle and moving the table to obtain a projection image (e.g., a localizer image). +STATIONARY identifies that the acquisition was performed by holding the table at a constant position and acquiring multiple slices over time at the same location. +FREE identifies that the acquisition was performed while rotating the source about the gantry while the table movement is under direct control of a human operator or under the control of an analysis application (e.g., fluoroscopic image). +
+
+ + The constant angle at which the x-ray source is located during acquisition. 0 degrees means that the source is located at the highest point of the gantry orbit. Degrees increase from 0 to positive 360 in a clockwise direction as viewed when facing the gantry where the table enters the gantry. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL and Acquisition Type (0018,9302) is CONSTANT_ANGLE. +May be present otherwise if Frame Type (0008,9007) Value 1 of this frame is DERIVED and Acquisition Type (0018,9302) is CONSTANT_ANGLE. + + + Identifies that the acquisition was performed by repetitively acquiring the same volume set over a period of time. +Note: The Acquisition Type (0018,9302) value may be SEQUENCED, SPIRAL or STATIONARY depending on whether table movement is necessary to cover the volume. +Enumerated Values +YES +NO +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. + + + Identifies that near real-time display of a block of continuously acquired data was performed, which may result in a lower than usual image quality. +Enumerated Values +YES +NO +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. + +
+ + + Contains the attributes defining the details of the acquisition. Only a single Item shall be permitted in this sequence. + + + Direction of rotation of the source about the gantry, as viewed while facing the gantry where the table enters the gantry. +Enumerated Values: +CW = clockwise +CC = counter clockwise +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL and Acquisition Type (0018,9302) is other than CONSTANT_ANGLE. +Otherwise may be present if Frame Type (0008,9007) Value 1 of this frame is DERIVED and Acquisition Type (0018,9302) is other than CONSTANT_ANGLE. + + + The time in seconds of a complete revolution of the source around the gantry orbit. This value is independent of the Reconstruction Angle (0018,9319) of the frame. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL and Acquisition Type (0018,9302) is other than CONSTANT_ANGLE. +Otherwise may be present if Frame Type (0008,9007) Value 1 of this frame is DERIVED and Acquisition Type (0018,9302) is other than CONSTANT_ANGLE. + + + The width of a single row of acquired data (in mm). +Note: Adjacent physical detector rows may have been combined to form a single effective acquisition row. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. + + + The width of the total collimation (in mm) over the area of active x-ray detection. +Note: This will be equal to the number of effective detector rows multiplied by single collimation width. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. + + + The distance in mm from the top of the patient table to the center of rotation of the source (i.e. the data collection center or isocenter). The distance is positive when the table is below the data collection center. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. + + + Nominal angle of tilt in degrees of the scanning gantry. Not intended for mathematical computations. Zero degrees means the gantry is not tilted, negative degrees are when the top of the gantry is tilted away from where the table enters the gantry. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. + + + The diameter in mm of the region over which data were collected. See C.8.15.3.6.1. +Note: In the case of an Acquisition Type (0018,9302) of CONSTANT_ANGLE, the diameter is that in a plane normal to the central ray of the diverging X-Ray beam as it passes through the data collection center. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. +
In Figure C.8-19 the relationship of the Geometric Attributes within the CT Geometry and CT Reconstruction functional groups is shown. The figure, viewed from the front of the gantry (where the table enters the gantry), is informative only and is not meant to represent a standardization of an equipment-based frame of reference. + Figure C.8-19: Geometry of CT Acquisition System + +
+
+
+ + + Contains the attributes defining the movement of the CT table. Only a single Item shall be permitted in this sequence. + + + The distance in mm that the table moves in one second during the gathering of data that resulted in this frame. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL and Acquisition Type (0018,9302) is SPIRAL or CONSTANT_ANGLE. +May be present otherwise if Frame Type (0008,9007) Value 1 of this frame is DERIVED and Acquisition Type (0018,9302) is SPIRAL or CONSTANT_ANGLE. + + + Motion of the table (in mm) during a complete revolution of the source around the gantry orbit. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL and Acquisition Type (0018,9302) is SPIRAL. +May be present otherwise if Frame Type (0008,9007) Value 1 of this frame is DERIVED and Acquisition Type (0018,9302) is SPIRAL. + + + Ratio of the Table Feed per Rotation (0018,9310) to the Total Collimation Width (0018,9307). +See C.8.15.3.4.1 for further explanation and some examples. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL and Acquisition Type (0018,9302) is SPIRAL. +May be present otherwise if Frame Type (0008,9007) Value 1 of this frame is DERIVED and Acquisition Type (0018,9302) is SPIRAL. +
The formula for Spiral Pitch Factor (0018,9311) in terms of Table Feed per Rotation (0018,9310) and Total Collimation Width (0018,9307) is: + Spiral Pitch Factor = (Table Feed per Rotation (mm))/(Total Collimation Width (mm)) +An example calculation of Spiral Pitch Factor (0018,9311) for a single slice spiral acquisition of an image with a Total Collimation Width of 2.5mm and a Table Feed per Rotation of 10mm is: + Spiral Pitch Factor = (10 mm)/(2.5 mm) = 4.0 +An example calculation of Spiral Pitch Factor (0018,9311) for a multiple slice spiral acquisition having a Total Collimation Width of 20mm and a Table Feed per Rotation of 10mm is: + Spiral Pitch Factor = (10 mm)/(20 mm) = 0.5 +
+
+
+ + + Contains the attributes defining the CT geometry. Only a single Item shall be permitted in this sequence. + + + Relative longitudinal position of acquisition location of this frame in mm from an implementation specific reference point. Shall be relative to the same reference point for all frames in this SOP Instance, but may be different from the reference point in other SOP Instances. Positions as the table moves into the gantry viewed from the front are more negative. +Notes: 1. For contiguous slices reconstructed from multiple detectors one would expect different values for adjacent slices. +2. Lateral positioning or tilting or swiveling are not described. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. + + + The x, y, and z coordinates (in the patient coordinate system) in mm of the center of the region in which data were collected. See C.8.15.3.6.1. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. +
In Figure C.8-19 the relationship of the Geometric Attributes within the CT Geometry and CT Reconstruction functional groups is shown. The figure, viewed from the front of the gantry (where the table enters the gantry), is informative only and is not meant to represent a standardization of an equipment-based frame of reference. + Figure C.8-19: Geometry of CT Acquisition System + +
+
+ + The x, y, and z coordinates (in the patient coordinate system) of the reconstruction center target point as used for reconstruction in mm. See C.8.15.3.6.1. +Note: If the reconstructed image is not magnified or panned the value corresponds with the Data Collection Center (0018,9313) attribute. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. +
In Figure C.8-19 the relationship of the Geometric Attributes within the CT Geometry and CT Reconstruction functional groups is shown. The figure, viewed from the front of the gantry (where the table enters the gantry), is informative only and is not meant to represent a standardization of an equipment-based frame of reference. + Figure C.8-19: Geometry of CT Acquisition System + +
+
+
+ + + Contains the attributes defining the CT geometry. Only a single Item shall be permitted in this sequence. + + + Distance in mm from source to detector center. See C.8.15.3.6.1. +Note: This value is traditionally referred to as Source Image Receptor Distance (SID). +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. +
In Figure C.8-19 the relationship of the Geometric Attributes within the CT Geometry and CT Reconstruction functional groups is shown. The figure, viewed from the front of the gantry (where the table enters the gantry), is informative only and is not meant to represent a standardization of an equipment-based frame of reference. + Figure C.8-19: Geometry of CT Acquisition System + +
+
+ + Distance in mm from source to data collection center. See C.8.15.3.6.1. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. +
In Figure C.8-19 the relationship of the Geometric Attributes within the CT Geometry and CT Reconstruction functional groups is shown. The figure, viewed from the front of the gantry (where the table enters the gantry), is informative only and is not meant to represent a standardization of an equipment-based frame of reference. + Figure C.8-19: Geometry of CT Acquisition System + +
+
+
+ + + Contains the attributes holding information about the reconstruction techniques used. Only a single Item shall be permitted in this sequence. + + + Description of the algorithm used when reconstructing the image from the data acquired during the acquisition process. +Defined Terms: +FILTER_BACK_PROJ +ITERATIVE +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. + + + A label describing the convolution kernel or algorithm used to reconstruct the data. A single value shall be present. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. + + + A label describing the group that the Convolution Kernel (0018,1210) belongs. +Defined Terms: +BRAIN +SOFT_TISSUE +LUNG +BONE +CONSTANT_ANGLE +Required if Convolution Kernel (0018,1210) is present. May be present otherwise. + + + The diameter in mm of the region from which data were used in creating the reconstruction of the image. Data may exist outside this region and portions of the patient may exist outside this region. See C.8.15.3.6.1. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL and Reconstruction Field of View (0018,9317) is not present. +Otherwise may be present if Frame Type (0008,9007) Value 1 of this frame is DERIVED and Reconstruction Field of View (0018,9317) is not present. +
In Figure C.8-19 the relationship of the Geometric Attributes within the CT Geometry and CT Reconstruction functional groups is shown. The figure, viewed from the front of the gantry (where the table enters the gantry), is informative only and is not meant to represent a standardization of an equipment-based frame of reference. + Figure C.8-19: Geometry of CT Acquisition System + +
+
+ + The field of view width (x-dimension) followed by height (y-dimension) as used for reconstruction in mm. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL and Reconstruction Diameter (0018,1100) is not present. +Otherwise may be present if Frame Type (0008,9007) Value 1 of this frame is DERIVED and Reconstruction Diameter (0018,1100) is not present. + + + Physical distance in the patient between the center of each reconstructed pixel, specified by a numeric pair - adjacent row spacing (delimiter) adjacent column spacing in mm. See 10.7.1.3 for further explanation of the value order. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. + + + Angle (in degrees) over which the data from which the frame was reconstructed was collected, where 360 degrees signifies a complete revolution of the source around the gantry orbit. It is possible, in the case of over-scanning that the Reconstruction Angle is greater than 360 degrees. +Shall be 0 if Acquisition Type (0018,9302) is CONSTANT_ANGLE. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. + + + A label describing the filter applied to the reconstructed image after the original reconstruction has been completed. +Note: When Frame Type (0008,9007) Value 1 of this frame is DERIVED and Frame Type (0008,9007) Value 4 is FILTERED the type of filtration is described in Derivation Image Macro. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. + +
+ + + Contains the attributes defining exposure information. Only a single Item shall be permitted in this sequence. + + + Duration of exposure for this frame in milliseconds. If Acquisition Type (0018,9302) equals SPIRAL the duration of exposure shall be weighted by the Spiral Pitch Factor (0018,9311). +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. + + + Nominal X-Ray tube current in milliamperes. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. + + + The exposure expressed in milliampere seconds, for example calculated from exposure time and X-Ray tube current. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. + + + A label describing the type of exposure modulation used for the purpose of limiting the dose. +Defined Terms: +NONE +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. + + + A percent value of dose saving due to the use of Exposure Modulation Type (0018,9323). A negative percent value of dose savings reflects an increase of exposure. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL and Exposure Modulation Type (0018,9323) is not equal to NONE. +Otherwise may be present if Frame Type (0008,9007) Value 1 of this frame is DERIVED and Exposure Modulation Type (0018,9323) is not equal to NONE. + + + Computed Tomography Dose Index (CTDIvol), in mGy according to IEC 60601-2-44, Ed.2.1 (Clause 29.1.103.4), The Volume CTDIvol. It describes the average dose for this frame for the selected CT conditions of operation. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. + + + The type of phantom used for CTDI measurement according to IEC 60601-2-44. Only a single Item shall be permitted in this Sequence. + + + + + + Contains the attributes defining the x-ray information. Only a single Item shall be permitted in this sequence. + + + Peak kilo voltage output of the x-ray generator used. +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. + + + Used nominal size of the focal spot in mm. The attribute may only have one or two values, for devices with variable focal spot, small dimension followed by large dimension +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. + + + Type of filter(s) inserted into the X-Ray beam. +Defined Terms: +WEDGE +BUTTERFLY +MULTIPLE +FLAT +SHAPED +NONE +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL. May be present otherwise. + + + The X-Ray absorbing material used in the filter. May be multi-valued. +Defined Terms: +MOLYBDENUM +ALUMINUM +COPPER +RHODIUM +NIOBIUM +EUROPIUM +LEAD +MIXED +Note: MIXED may be used to indicate a filter type of complex composition for which listing the individual materials would be excessive or undesirable; it is not intended to mean "unknown". +Required if Frame Type (0008,9007) Value 1 of this frame is ORIGINAL and the value of Filter Type (0018,1160) is other than NONE. May be present otherwise. + + + The calibration factor for the calcium mass score. These factors incorporate the effects of +See C.8.2.1.1.7. +
The calibration factors for the Calcium Scoring Mass Factor Patient (0018,9351) and Calcium Scoring Mass Factor Device (0018,9352) attributes are defined by the International Consortium for Multi-Detector CT Evaluation of Coronary Calcium, see McCollough, C.H. “A multi-institutional, multi-manufacturer, international standard for the quantification of coronary artery calcium using cardiac CTâ€. +
+
+ + The calibration factors for the calcium mass score of the device. These factors incorporate the effects of +This a multi-value attribute, the first value specifies the mass factor for a small patient size, the second value for a medium patient size and the third value for a large patient size. +See C.8.2.1.1.7. +
The calibration factors for the Calcium Scoring Mass Factor Patient (0018,9351) and Calcium Scoring Mass Factor Device (0018,9352) attributes are defined by the International Consortium for Multi-Detector CT Evaluation of Coronary Calcium, see McCollough, C.H. “A multi-institutional, multi-manufacturer, international standard for the quantification of coronary artery calcium using cardiac CTâ€. +
+
+
+ + + Contains the attributes involved in the transformation of stored pixel values. Only a single Item shall be permitted in this sequence. + + + The value b in relationship between stored values (SV) and the output units. +Output units = m*SV + b. + + + m in the equation specified by Rescale Intercept (0028,1052). + + + Specifies the output units of Rescale Slope (0028,1053) and Rescale Intercept (0028,1052). +See C.11.1.1.2 for further explanation. +If Frame Type (0008,9007) Value 1 of this frame is ORIGINAL and Frame Type (0008,9007) Value 3 is not LOCALIZER, the value shall be HU (Hounsfield Units). +
Specifies the units of the output of the Modality LUT or rescale operation. +Defined Terms: + OD = The number in the LUT represents thousands of optical density. That is, a value of 2140 represents an optical density of 2.140. + HU = Hounsfield Units (CT) + US = Unspecified +Other values are permitted, but are not defined by the DICOM Standard. +
+
+
+ + + Contains the attributes defining the data acquisition in a multiple X-Ray source system beyond the primary source. The primary X-Ray source is specified in the CT X-Ray Details Sequence. +One or more items may be present. + + + Peak kilo voltage output of the X-Ray generator used. + + + Nominal X-Ray tube current in milliamperes. + + + The diameter in mm of the region over which data were collected. + + + Used nominal size of the focal spot in mm. + + + Type of filter(s) inserted into the X-Ray beam. + + + The X-Ray absorbing material used in the filter. + + + + + Indication of the presence or absence of color information that may be used during rendering. See C.8.16.2.1.1 for a description and Enumerated Values. +
Table C.8-132 +PIXEL PRESENTATION ATTRIBUTE VALUES + +
+
+ + Indication if geometric manipulations are possible with frames in the SOP Instance. See C.8.16.2.1.2 for a description and Enumerated Values. +
The value of the Volumetric Properties attribute (0008,9206) allows applications doing geometric manipulations (e.g., MAX_IP or MPR or planning) to determine if the image is an appropriate candidate for an operation without having to know all the details of the generating application. +Table C.8-133 specifies the Enumerated Values for the Volumetric Properties (0008,9206) attribute. +Table C.8-133 +VOLUMETRIC PROPERTIES ATTRIBUTE VALUES + +
+
+ + Method used for volume calculations with frames in the SOP Instance. See C.8.16.2.1.3 for a description and Defined Terms. +
The value of the Volume Based Calculation Technique attribute (0008,9207) shall be used to indicate the method used for calculating pixels based on geometry. +Shall have a value of NONE when Value 1 of Image Type (0008,0008) or Value 1 of Frame Type (0008,9007) is ORIGINAL. +Table C.8-134 specifies the Defined Terms for the Volume Based Calculation Technique (0008,9207) attribute. +Table C.8-134 +VOLUME BASED CALCULATION TECHNIQUE ATTRIBUTE VALUES + +
+
+
+ + + Source equipment that produced the Ophthalmic Photography Series. Enumerated Value: OP + + + + + Image identification characteristics. +See C.8.17.2.1.4 for specialization. +
The Image Type attribute (0008,0008) (General Image Module, C.7.6.1) identifies important image characteristics in a multiple valued data element. For the Ophthalmic Photography Image IOD, Image Type is specified as a Type 1 attribute and further specialized as follows: +a. Value 1 shall identify the Pixel Data Characteristics in accordance with Section C.7.6.1.1.2; Enumerated Values are: ORIGINAL and DERIVED; +
+
+ + A number that identifies this image. + + + + Number of samples (planes) in this image. Enumerated values: 1 or 3. +See C.8.17.2.1.2 for further explanation. +
Samples per Pixel (0028,0002) shall be 1 or 3. +Cameras producing 2-color images are required to use a value of 3 for Samples per Pixel (0028,0002) and a value of 2 for Samples per Pixel Used (0028,0003). For 2-color images with a RGB Photometric Interpretation, the R and G channel shall be used and the B channel shall have all values set to zero. +Note: In the case of Photometric Interpretations typically used for compression such as YBR_FULL_422, the encoding will be as if the RGB values were transformed to YCbCr. + +
+
+ + The number of samples (planes) containing information. Enumerated value: 2. +Required if different from Samples per Pixel (0028,0002). +See section C.8.17.2.1.2 + + + Specifies the intended interpretation of the pixel data. +See section C.8.17.2.1.3 + + + Data representation of the pixel samples. Enumerated value: 0 + + + Indicates whether the pixel data are sent color-by-plane or color-by-pixel. Required if Samples per Pixel (0028,0002) has a value greater than 1. +Enumerated value shall be 0 (color-by-pixel). + + + Nominal physical distance at the focal plane (in the retina) between the center of each pixel, specified by a numeric pair - adjacent row spacing (delimiter) adjacent column spacing in mm. See 10.7.1.3 for further explanation of the value order. +Note: These values are specified as nominal because the physical distance may vary across the field of the images and the lens correction is likely to be imperfect. +Required when Acquisition Device Type Code Sequence (0022,0015) contains an item with the value (SRT, R-1021A,"Fundus Camera"). May be present otherwise. + + + The time the image pixel data creation started. + + + The date the image pixel data creation started. + + + The date and time that the acquisition of data started. +Note: The synchronization of this time with an external clock is specified in the synchronization Module in Acquisition Time Synchronized (0018,1800). +Required if Image Type (0008,0008) Value 1 is ORIGINAL. May be present otherwise. + + + A Sequence that identifies the Images that were used to derive this Image. Required if Image Type Value 1 is DERIVED. Zero or more items may be present in the sequence. +See C.7.6.1.1.4 for further explanation. +
If an Image is identified to be a Derived image (see C.7.6.1.1.2 Image Type), Source Image Sequence (0008,2112) is an optional list of Referenced SOP Class UID (0008,1150)/ Referenced SOP Instance UID (0008,1150) pairs that identify the source images used to create the Derived image. It may be used whether or not there is a description of the way the image was derived in Derivation Description (0008,2111) or Derivation Code Sequence (0008,9215). +Note: Multiple Items may be present within Source Image Sequence (0008,2112), in which case either: + a) those images were combined to make the derived image (e.g. multiple source images to make an MPR or MIP), or + b) each of the items represents a step in the successive derivation of an image (e.g. when an image has had successive lossy compression steps applied to it), + c) some combination of the above. + The Purpose of Reference Code Sequence (0040,A170) and the Attributes within the referenced images themselves may be used to determine the history of the derivation, which is not otherwise explicitly specified. + +
+
+ + + Describes the purpose for which the reference is made, that is what role the source image or frame(s) played in the derivation of this image. Only a single Item shall be permitted in this sequence. + + + + Specifies whether an Image has undergone lossy compression. Enumerated Values: +00 = Image has NOT been subjected to lossy compression. +01 = Image has been subjected to lossy compression. +See C.7.6.1.1.5 +
The Attribute Lossy Image Compression (0028,2110) conveys that the Image has undergone lossy compression. It provides a means to record that the Image has been compressed (at a point in its lifetime) with a lossy algorithm and changes have been introduced into the pixel data. Once the value has been set to “01â€, it shall not be reset. +Note: If an image is compressed with a lossy algorithm, the attribute Lossy Image Compression (0028,2110) is set to “01â€. Subsequently, if the image is decompressed and transferred in uncompressed format, this attribute value remains “01â€. + +The value of the Lossy Image Compression (0028,2110) Attribute in SOP Instances containing multiple frames in which one or more of the frames have undergone lossy compression shall be “01â€. +Note: It is recommended that the applicable frames be noted in the Attribute Derivation Description (0008,2111). + +If an image is originally obtained as a lossy compressed image from the sensor, then Lossy Image Compression (0028,2110) is set to “01†and Value 1 of the Attribute Image Type (0008,0008) shall be set to ORIGINAL. +If an image is a compressed version of another image, Lossy Image Compression (0028,2110) is set to “01â€, Value 1 of the Attribute Image Type (0008,0008) shall be set to DERIVED, and if the predecessor was a DICOM image, then the Image shall receive a new SOP Instance UID. +Note: 1. It is recommended that the approximate compression ratio be provided in the Attribute Derivation Description (0008,2111). Furthermore, it is recommended that Derivation Description (0008,2111) be used to indicate when pixel data changes might affect professional interpretation. (see C.7.6.1.1.3). + 2. The attribute Lossy Image Compression (0028,2110) is defined as Type 3 for backward compatibility with existing IODs. It is expected to be required (i.e., defined as Type 1C) for new Image IODs and for existing IODs that undergo a major revision (e.g. a new IOD is specified). +The Defined Terms for Lossy Image Compression Method (0028,2114) are: +ISO_10918_1 = JPEG Lossy Compression +ISO_14495_1 = JPEG-LS Near-lossless Compression +ISO_15444_1 = JPEG 2000 Irreversible Compression +ISO_13818_2 = MPEG2 Compression + +
+
+ + Describes the approximate lossy compression ratio(s) that have been applied to this image. See C.7.6.1.1.5 for further explanation. +May be multivalued if successive lossy compression steps have been applied. +Notes: 1. For example, a compression ratio of 30:1 would be described in this Attribute with a single value of 30. +2. For historical reasons, the lossy compression ratio should also be described in Derivation Description (0008,2111) +Required if Lossy Image Compression (0028,2110) has a value of "01". +
The Attribute Lossy Image Compression (0028,2110) conveys that the Image has undergone lossy compression. It provides a means to record that the Image has been compressed (at a point in its lifetime) with a lossy algorithm and changes have been introduced into the pixel data. Once the value has been set to “01â€, it shall not be reset. +Note: If an image is compressed with a lossy algorithm, the attribute Lossy Image Compression (0028,2110) is set to “01â€. Subsequently, if the image is decompressed and transferred in uncompressed format, this attribute value remains “01â€. + +The value of the Lossy Image Compression (0028,2110) Attribute in SOP Instances containing multiple frames in which one or more of the frames have undergone lossy compression shall be “01â€. +Note: It is recommended that the applicable frames be noted in the Attribute Derivation Description (0008,2111). + +If an image is originally obtained as a lossy compressed image from the sensor, then Lossy Image Compression (0028,2110) is set to “01†and Value 1 of the Attribute Image Type (0008,0008) shall be set to ORIGINAL. +If an image is a compressed version of another image, Lossy Image Compression (0028,2110) is set to “01â€, Value 1 of the Attribute Image Type (0008,0008) shall be set to DERIVED, and if the predecessor was a DICOM image, then the Image shall receive a new SOP Instance UID. +Note: 1. It is recommended that the approximate compression ratio be provided in the Attribute Derivation Description (0008,2111). Furthermore, it is recommended that Derivation Description (0008,2111) be used to indicate when pixel data changes might affect professional interpretation. (see C.7.6.1.1.3). + 2. The attribute Lossy Image Compression (0028,2110) is defined as Type 3 for backward compatibility with existing IODs. It is expected to be required (i.e., defined as Type 1C) for new Image IODs and for existing IODs that undergo a major revision (e.g. a new IOD is specified). +The Defined Terms for Lossy Image Compression Method (0028,2114) are: +ISO_10918_1 = JPEG Lossy Compression +ISO_14495_1 = JPEG-LS Near-lossless Compression +ISO_15444_1 = JPEG 2000 Irreversible Compression +ISO_13818_2 = MPEG2 Compression + +
+
+ + A label for the lossy compression method(s) that have been applied to this image. +See C.7.6.1.1.5 for further explanation. +May be multivalued if successive lossy compression steps have been applied; the value order shall correspond to the values of Lossy Image Compression Ratio (0028,2112). +Required if Lossy Image Compression (0028,2110) has a value of "01". +Note: For historical reasons, the lossy compression method should also be described in Derivation Description (0008,2111). +
The Attribute Lossy Image Compression (0028,2110) conveys that the Image has undergone lossy compression. It provides a means to record that the Image has been compressed (at a point in its lifetime) with a lossy algorithm and changes have been introduced into the pixel data. Once the value has been set to “01â€, it shall not be reset. +Note: If an image is compressed with a lossy algorithm, the attribute Lossy Image Compression (0028,2110) is set to “01â€. Subsequently, if the image is decompressed and transferred in uncompressed format, this attribute value remains “01â€. + +The value of the Lossy Image Compression (0028,2110) Attribute in SOP Instances containing multiple frames in which one or more of the frames have undergone lossy compression shall be “01â€. +Note: It is recommended that the applicable frames be noted in the Attribute Derivation Description (0008,2111). + +If an image is originally obtained as a lossy compressed image from the sensor, then Lossy Image Compression (0028,2110) is set to “01†and Value 1 of the Attribute Image Type (0008,0008) shall be set to ORIGINAL. +If an image is a compressed version of another image, Lossy Image Compression (0028,2110) is set to “01â€, Value 1 of the Attribute Image Type (0008,0008) shall be set to DERIVED, and if the predecessor was a DICOM image, then the Image shall receive a new SOP Instance UID. +Note: 1. It is recommended that the approximate compression ratio be provided in the Attribute Derivation Description (0008,2111). Furthermore, it is recommended that Derivation Description (0008,2111) be used to indicate when pixel data changes might affect professional interpretation. (see C.7.6.1.1.3). + 2. The attribute Lossy Image Compression (0028,2110) is defined as Type 3 for backward compatibility with existing IODs. It is expected to be required (i.e., defined as Type 1C) for new Image IODs and for existing IODs that undergo a major revision (e.g. a new IOD is specified). +The Defined Terms for Lossy Image Compression Method (0028,2114) are: +ISO_10918_1 = JPEG Lossy Compression +ISO_14495_1 = JPEG-LS Near-lossless Compression +ISO_15444_1 = JPEG 2000 Irreversible Compression +ISO_13818_2 = MPEG2 Compression + +
+
+ + Specifies an identity transformation for the Presentation LUT, such that the output of all grayscale transformations defined in the IOD containing this Module are defined to be P-Values. +Enumerated Values: +IDENTITY - output is in P-Values. +Required if Photometric Interpretation (0028,0004) is MONOCHROME2 + + + Indicates whether a reference object (phantom) of known size is present in the image and was used for calibration. Enumerated Values: +YES +NO + + + Indicates whether or not image contains sufficient burned in annotation to identify the patient and date the image was acquired. +Enumerated Value: +YES +NO + +
+ + + + + + Enumerated Values: +YES +NO + + + Coded value for patient movement or orientation, which is the intent, and not necessarily the result, based on what the patient is capable of. +Required if the value of Patient Eye Movement Commanded (0022,0005) is YES. +A single item shall be present in this sequence. + + + + + + + Laterality of object imaged (as described in Anatomic Region Sequence (0008,2218)) examined. +Enumerated Values: +R = right eye +L = left eye +B = both left and right eye +Shall be consistent with any laterality information contained in Primary Anatomic Structure Modifier Sequence (0008,2230), if present. +Note: Laterality (0020,0060) is a Series level Attribute and must be the same for all Images in the Series. Since most Ophthalmic Photographic Image studies contain images of both eyes, the series level attribute will rarely be present. + + + The position of this image on the retina (as defined by a specified nomenclature; the nomenclature is implicit in the code used). Only a single Item shall be permitted in this sequence. + + + + + + + Type of equipment that originally acquired the data used to create the images in this Series. +Enumerated Values: +OPT +See section C.7.3.1.1.1 for further explanation. + + + A number that identifies this Series. + + + Uniquely identifies the Performed Procedure Step SOP Instance to which the Series is related (e.g. a Modality or General-Purpose Performed Procedure Step SOP Instance). The Sequence shall have one Item. +Required if the Modality Performed Procedure Step SOP Class or General Purpose Performed Procedure Step SOP Class is supported. + + + + + + Image identification characteristics. + + + Number of samples (planes) in this image. See C.7.6.3.1.1 for further explanation. Value shall be 1. +
Samples per Pixel (0028,0002) is the number of separate planes in this image. One, three, and four image planes are defined. Other numbers of image planes are allowed, but their meaning is not defined by this Standard. +For monochrome (gray scale) and palette color images, the number of planes is 1. For RGB and other three vector color models, the value of this attribute is 3. For four vector color models, the value of this attribute is 4. +All image planes shall have the same number of Rows (0028,0010), Columns (0028,0011), Bits Allocated (0028,0100), Bits Stored (0028,0101), High Bit (0028,0102), Pixel Representation (0028,0103), and Pixel Aspect Ratio (0028,0034). +The data in each pixel may be represented as a “Composite Pixel Codeâ€. If Samples Per Pixel is one, the Composite Pixel Code is just the “n†bit pixel sample, where “n†= Bits Allocated. If Samples Per Pixel is greater than one, Composite Pixel Code is a “k†bit concatenation of samples, where “k†= Bits Allocated multiplied by Samples Per Pixel, and with the sample representing the vector color designated first in the Photometric Interpretation name comprising the most significant bits of the Composite Pixel Code, followed in order by the samples representing the next vector colors, with the sample representing the vector color designated last in the Photometric Interpretation name comprising the least significant bits of the Composite Pixel Code. For example, for Photometric Interpretation = “RGBâ€, the most significant “Bits Allocated†bits contain the Red sample, the next “Bits Allocated†bits contain the Green sample, and the least significant “Bits Allocated†bits contain the Blue sample. +
+
+ + The date and time that the acquisition of data started. +Note: The synchronization of this time with an external clock is specified in the synchronization Module in Acquisition Time synchronized (0018,1800) . + + + The scan time in seconds used to create all frames of an Ophthalmic Tomography image. +Required if Image Type (0008,0008) Value 1 is ORIGINAL. May be present otherwise. + + + A number identifying the single continuous gathering of data over a period of time which resulted in this image. + + + Specifies the intended interpretation of the pixel data. +Enumerated Value shall be: MONOCHROME2 + + + Data representation of pixel samples. Enumerated Value shall be 0. + + + Number of bits allocated for each pixel sample. Each sample shall have the same number of bits allocated. +Bits Allocated (0028,0100) shall be 8 or 16 + + + Number of bits stored for each pixel sample. Each sample shall have the same number of bits stored. +Bits Stored (0028,0101) shall be 8, 12 or 16 + + + Most significant bit for pixel sample data. Each sample shall have the same high bit. +High Bit (0028,0102) shall be one less than Bits Stored + + + Specifies an identity transformation for the Presentation LUT, such that the output of all grayscale transformations defined in the IOD containing this Module are defined to be P-Values. +Enumerated Values: +IDENTITY - output is in P-Values. + + + Specifies whether an Image has undergone lossy compression (at a point in its lifetime). +Enumerated Values: +00 = Image has NOT been subjected to lossy compression. +01 = Image has been subjected to lossy compression. +Once this tag has been set to 01 it shall not be reset. +If this tag is empty, no information is explicitly available. +See C.7.6.1.1.5 +
The Attribute Lossy Image Compression (0028,2110) conveys that the Image has undergone lossy compression. It provides a means to record that the Image has been compressed (at a point in its lifetime) with a lossy algorithm and changes have been introduced into the pixel data. Once the value has been set to “01â€, it shall not be reset. +Note: If an image is compressed with a lossy algorithm, the attribute Lossy Image Compression (0028,2110) is set to “01â€. Subsequently, if the image is decompressed and transferred in uncompressed format, this attribute value remains “01â€. + +The value of the Lossy Image Compression (0028,2110) Attribute in SOP Instances containing multiple frames in which one or more of the frames have undergone lossy compression shall be “01â€. +Note: It is recommended that the applicable frames be noted in the Attribute Derivation Description (0008,2111). + +If an image is originally obtained as a lossy compressed image from the sensor, then Lossy Image Compression (0028,2110) is set to “01†and Value 1 of the Attribute Image Type (0008,0008) shall be set to ORIGINAL. +If an image is a compressed version of another image, Lossy Image Compression (0028,2110) is set to “01â€, Value 1 of the Attribute Image Type (0008,0008) shall be set to DERIVED, and if the predecessor was a DICOM image, then the Image shall receive a new SOP Instance UID. +Note: 1. It is recommended that the approximate compression ratio be provided in the Attribute Derivation Description (0008,2111). Furthermore, it is recommended that Derivation Description (0008,2111) be used to indicate when pixel data changes might affect professional interpretation. (see C.7.6.1.1.3). + 2. The attribute Lossy Image Compression (0028,2110) is defined as Type 3 for backward compatibility with existing IODs. It is expected to be required (i.e., defined as Type 1C) for new Image IODs and for existing IODs that undergo a major revision (e.g. a new IOD is specified). +The Defined Terms for Lossy Image Compression Method (0028,2114) are: +ISO_10918_1 = JPEG Lossy Compression +ISO_14495_1 = JPEG-LS Near-lossless Compression +ISO_15444_1 = JPEG 2000 Irreversible Compression +ISO_13818_2 = MPEG2 Compression + +
+
+ + Describes the approximate lossy compression ratio(s) that have been applied to this image. Required when compression has been applied. +See C.7.6.1.1.5 for further explanation. +May be multivalued if successive lossy compression steps have been applied. +Notes: 1. For example, a compression ratio of 30:1 would be described in this Attribute with a single value of 30. +2. For historical reasons, the lossy compression ratio should also be described in Derivation Description (0008,2111). +
The Attribute Lossy Image Compression (0028,2110) conveys that the Image has undergone lossy compression. It provides a means to record that the Image has been compressed (at a point in its lifetime) with a lossy algorithm and changes have been introduced into the pixel data. Once the value has been set to “01â€, it shall not be reset. +Note: If an image is compressed with a lossy algorithm, the attribute Lossy Image Compression (0028,2110) is set to “01â€. Subsequently, if the image is decompressed and transferred in uncompressed format, this attribute value remains “01â€. + +The value of the Lossy Image Compression (0028,2110) Attribute in SOP Instances containing multiple frames in which one or more of the frames have undergone lossy compression shall be “01â€. +Note: It is recommended that the applicable frames be noted in the Attribute Derivation Description (0008,2111). + +If an image is originally obtained as a lossy compressed image from the sensor, then Lossy Image Compression (0028,2110) is set to “01†and Value 1 of the Attribute Image Type (0008,0008) shall be set to ORIGINAL. +If an image is a compressed version of another image, Lossy Image Compression (0028,2110) is set to “01â€, Value 1 of the Attribute Image Type (0008,0008) shall be set to DERIVED, and if the predecessor was a DICOM image, then the Image shall receive a new SOP Instance UID. +Note: 1. It is recommended that the approximate compression ratio be provided in the Attribute Derivation Description (0008,2111). Furthermore, it is recommended that Derivation Description (0008,2111) be used to indicate when pixel data changes might affect professional interpretation. (see C.7.6.1.1.3). + 2. The attribute Lossy Image Compression (0028,2110) is defined as Type 3 for backward compatibility with existing IODs. It is expected to be required (i.e., defined as Type 1C) for new Image IODs and for existing IODs that undergo a major revision (e.g. a new IOD is specified). +The Defined Terms for Lossy Image Compression Method (0028,2114) are: +ISO_10918_1 = JPEG Lossy Compression +ISO_14495_1 = JPEG-LS Near-lossless Compression +ISO_15444_1 = JPEG 2000 Irreversible Compression +ISO_13818_2 = MPEG2 Compression + +
+
+ + A label for the lossy compression method(s) that have been applied to this image. +See C.7.6.1.1.5 for further explanation. +May be multi-valued if successive lossy compression steps have been applied; the value order shall correspond to the values of Lossy Image Compression Ratio (0028,2112). +Required if Lossy Image Compression (0028,2110) has a value of "01". +Note: For historical reasons, the lossy compression method should also be described in Derivation Description (0008,2111). +
The Attribute Lossy Image Compression (0028,2110) conveys that the Image has undergone lossy compression. It provides a means to record that the Image has been compressed (at a point in its lifetime) with a lossy algorithm and changes have been introduced into the pixel data. Once the value has been set to “01â€, it shall not be reset. +Note: If an image is compressed with a lossy algorithm, the attribute Lossy Image Compression (0028,2110) is set to “01â€. Subsequently, if the image is decompressed and transferred in uncompressed format, this attribute value remains “01â€. + +The value of the Lossy Image Compression (0028,2110) Attribute in SOP Instances containing multiple frames in which one or more of the frames have undergone lossy compression shall be “01â€. +Note: It is recommended that the applicable frames be noted in the Attribute Derivation Description (0008,2111). + +If an image is originally obtained as a lossy compressed image from the sensor, then Lossy Image Compression (0028,2110) is set to “01†and Value 1 of the Attribute Image Type (0008,0008) shall be set to ORIGINAL. +If an image is a compressed version of another image, Lossy Image Compression (0028,2110) is set to “01â€, Value 1 of the Attribute Image Type (0008,0008) shall be set to DERIVED, and if the predecessor was a DICOM image, then the Image shall receive a new SOP Instance UID. +Note: 1. It is recommended that the approximate compression ratio be provided in the Attribute Derivation Description (0008,2111). Furthermore, it is recommended that Derivation Description (0008,2111) be used to indicate when pixel data changes might affect professional interpretation. (see C.7.6.1.1.3). + 2. The attribute Lossy Image Compression (0028,2110) is defined as Type 3 for backward compatibility with existing IODs. It is expected to be required (i.e., defined as Type 1C) for new Image IODs and for existing IODs that undergo a major revision (e.g. a new IOD is specified). +The Defined Terms for Lossy Image Compression Method (0028,2114) are: +ISO_10918_1 = JPEG Lossy Compression +ISO_14495_1 = JPEG-LS Near-lossless Compression +ISO_15444_1 = JPEG 2000 Irreversible Compression +ISO_13818_2 = MPEG2 Compression + +
+
+ + Indicates whether or not image contains sufficient burned in annotation to identify the patient and date the image was acquired. +Enumerated Value: +NO + + + Offset of the first frame in a multi-frame image of a concatenation. Value shall be 0. + + + Identifier for one SOP Instance belonging to a concatenation. Value shall be 1. + + + The number of SOP Instances sharing the same Concatenation UID (0020,9161). Value Shall be 1. + +
+ + + Axial length of the eye in mm. + + + The horizontal field of view in degrees + + + + + + The refractive state of the imaged eye at +the time of acquisition. Zero or one Item +shall be present. Zero length means the refractive state was not measured. + + + Sphere value in diopters + + + Cylinder value in diopters + + + Axis value in degrees + + + Emmetropic magnification value (dimensionless). Zero length means the emmetropic magnification was not measured. + + + Value of intraocular pressure in mmHg. +Zero length means the pressure was not measured + + + Enumerated Values: +YES +NO +If this tag is empty, no information is available. + + + Information about the agent administered. Required if the value of Pupil Dilated (0022,000D) is YES. Zero or more items may be present. +Note: An empty sequence indicates that an agent was used for dilation, but the name was not entered. + + + The actual agent administered to dilate the pupil. One item shall be present. + + + + The concentration of the agent. + + + Units of measure for the Mydriatic Agent Concentration. Required if Mydriatic Agent Concentration (0022,004E) is present. One item shall be present. + + + + The degree of the dilation in mm. +Required if the value of Pupil Dilated (0022,000D) is YES. + + + + + Describes the type of acquisition device. A single item shall be present in the sequence. + + + + Filters used in the light source path. Zero or more items may be present in the sequence. + + + + Nominal pass-through wavelength of light path filter in nm + + + Pass band of light path filter in nm. This Attribute has two Values. The first is the shorter and the second the longer wavelength relative to the peak. The values are for the - 3dB nominal (1/2 of peak) pass through intensity. +One of the two Values may be zero length, in which case it is a cutoff filter. + + + Type of detector used for creating this image. Defined terms: +CCD = Charge Coupled Device +CMOS = Complementary Metal Oxide Semiconductor +PHOTO = Photodetector +INT = Interferometer + + + Wavelength of the illuminator in nm. Required if Acquisition Device Type Code Sequence (0022,0015) contains an item with the value (A-00FBE, SRT, "Optical Coherence Tomography Scanner"). May be present otherwise. + + + Power of the illuminator in microwatts at corneal plane. Required if Acquisition Device Type Code Sequence (0022,0015) contains an item with the value (SRT, A-00FBE,"Optical Coherence Tomography Scanner"). May be present otherwise. + + + Bandwidth of the illuminator in nm. Required if Acquisition Device Type Code Sequence (0022,0015) contains an item with the value (A-00FBE, SRT, "Optical Coherence Tomography Scanner"). May be present otherwise. + + + The inherent limiting resolution in microns for depth of the acquisition equipment for high contrast objects for the data gathering and reconstruction technique chosen. If variable, the value at the center of the scanning volume. Required if Acquisition Device Type Code Sequence (0022,0015) contains an item with the value (A-00FBE, SRT, "Optical Coherence Tomography Scanner"). May be present otherwise. + + + Maximum distortion in depth direction in % of Depth Spatial Resolution. Required if Acquisition Device Type Code Sequence (0022,0015) contains an item with the value (SRT, A-00FBE,"Optical Coherence Tomography Scanner"). May be present otherwise. + + + The inherent limiting resolution in microns of the acquisition equipment in the direction of a row. Required if Acquisition Device Type Code Sequence (0022,0015) contains an item with the value (A-00FBE, SRT, "Optical Coherence Tomography Scanner"). May be present otherwise. + + + Maximum distortion in along-scan direction in % of Along-scan Spatial Resolution. Required if Acquisition Device Type Code Sequence (0022,0015) contains an item with the value (A-00FBE, SRT, "Optical Coherence Tomography Scanner"). May be present otherwise. + + + The inherent limiting resolution in microns of the acquisition equipment perpendicular to the slice. Required if Acquisition Device Type Code Sequence (0022,0015) contains an item with the value (A-00FBE, SRT, "Optical Coherence Tomography Scanner"). May be present otherwise. + + + Maximum distortion in across-scan direction in % of cross-scan Spatial Resolution. Required if Acquisition Device Type Code Sequence (0022,0015) contains an item with the value (A-00FBE, SRT, "Optical Coherence Tomography Scanner"). May be present otherwise. + + + + + Specifies the column locations for this frame in terms of locations on a referenced image. One or more items shall be present. + + + + Image coordinates for the points on the referenced image that correspond to the points on this frame. See section C.8.17.10.1.1. + + + Relative position in microns signifying the location of a Transverse image in the z-axis. Required if Ophthalmic Image Orientation (0022,0039) is TRANSVERSE. + + + Enumerated Values: +LINEAR +NONLINEAR +TRANSVERSE + + + + + Source equipment that produced the Stereometric Series. Enumerated Value: SMR + + + + + Sequence of items identifying pairs of images. There shall be one or more items in this sequence. + + + Stereo separation angle in degrees + + + Horizontal displacement of instrument between left and right image in mm + + + Horizontal displacement of right image relative to left image in pixels for optimal display. Offset of right image to right means positive value. + + + Vertical displacement of right image relative to left image in pixels for optimal display. Offset of right image downwards means positive value. + + + Rotation of right image relative to left image in degrees for optimal display. The rotation of the right image against the left image counterclockwise is positive, rotation around the center is assumed. + + + Left Image of the Pair. Only one Item shall be present in this Sequence. + + + + Right Image of the Pair. Only one Item shall be present in this Sequence. + + + + + + Type of equipment that originally acquired the data used to create the images in this Series. +Enumerated Values: +XA +RF +See section C.7.3.1.1.1 for further explanation. + + + A number that identifies this Series. + + + Uniquely identifies the Performed Procedure Step SOP Instance to which the Series is related (e.g. a Modality or General-Purpose Performed Procedure Step SOP Instance). Only a single Item is permitted in this sequence. +Required if the Modality Performed Procedure Step SOP Class, General Purpose Performed Procedure Step SOP Class is supported. + + + + + + Image identification characteristics. +See C.8.19.2.1.1 for specialization. +
The Image Type attribute identifies important image characteristics in a multiple valued data element. For X-Ray, Image Type is specialized as follows: +a. Value 1 shall identify the Pixel Data Characteristics in accordance with Section C.7.6.1.1.2; Enumerated Values are: ORIGINAL and DERIVED; +b. Value 2 shall identify the Patient Examination Characteristics in accordance with Section C.7.6.1.1.2; Enumerated Values are: PRIMARY and SECONDARY. + +Note: X-Ray images generally use PRIMARY value for images captured from patient exposure. + +c. Value 3 shall identify the image set in terms of the imaging planes. Enumerated Values are: + + +d. Other Values are implementation specific (optional). + +
+
+ + Identification of the plane used to acquire this image. +Defined Terms: +MONOPLANE +PLANE A +PLANE B +Notes: 1. MONOPLANE may only be used for a single plane system +2. PLANE A and PLANE B must be used for two plane systems, independent if the acquisition is single plane or biplane. +3. The value has to be in accordance with Image Type (0008,0008) value 3. If this value is SINGLE PLANE all three Defined Term are applicable. +Required if Image Type (0008,0008) Value 3 is not equal to UNDEFINED. + + + A number identifying the single continuous gathering of data over a period of time that resulted in this image. + + + The date and time that the acquisition of data that resulted in this image started. +Note: The synchronization of this time with an external clock is specified in the Synchronization Module in Acquisition Time Synchronized (0018,1800). + + + Number of bits allocated for each pixel sample. Each sample shall have the same number of bits allocated. Enumerated Values: 8 and 16. + + + Number of bits stored for each pixel sample. Each sample shall have the same number of bits stored. Enumerated Values: 8 to 16. See C.8.19.2.1.2 for specialization. +
Table C.8.X2-2 specifies the allowed combinations of Bits Allocated (0028,0100) and Bits Stored (0028,0101). +Table C.8.19.2-2 +ALLOWED COMBINATIONS OF ATTRIBUTE VALUES + FOR BITS ALLOCATED AND BITS STORED + +
+
+ + Most significant bit for pixel sample data. Each sample shall have the same high bit. Shall be one less than the value in Bits Stored (0028,0101). + + + Number of samples (color planes) in this image shall have a value of 1. + + + Data representation of the pixel samples. +Shall have the value: +0000H = Unsigned Integer. + + + Specifies the intended interpretation of the pixel data. +Enumerated Values: +MONOCHROME1 +MONOCHROME2 + + + User defined name of the protocol used to acquire this image. + + + User defined description of the protocol used to acquire this image. + + + Identifies any acquisition technique that was used during the acquisition of the image. +Defined Terms: +TOMO = Tomography +CHASE = Bolus Chasing +STEP = Stepping +ROTA = Rotation + + + Content Qualification Indicator +Enumerated Values: +PRODUCT +RESEARCH +SERVICE +See C.8.13.2.1.1 for further explanation. +
Content Qualification (0018,9004) shall have the value PRODUCT if the content (image or Spectroscopy data) was produced with approved hardware and software. It shall have the value RESEARCH or SERVICE if there is any doubt as to whether the content was produced with approved hardware and software. +If data with Content Qualification (0018,9004) of RESEARCH or SERVICE is used to derive other content then it is expected that this derived content will also have Content Qualification (0018,9004) set to RESEARCH or SERVICE. +The intent of this element is to allow annotation of an advisory message that indicates that this content may not be suitable for clinical interpretation. +
+
+ + Sequence that describes the orientation of the patient with respect to gravity. +See C.8.11.5.1.2 for further explanation. +Only a single Item shall be permitted in this Sequence. +Required if Positioner Type (0018,1508) equals CARM and C-arm Positioner Tabletop Relationship (0018,9474) equals YES. May be present otherwise. +
This Attribute is not related to Patient Orientation (0020,0020) and conveys a different concept entirely. +
+
+ + + Patient Orientation Modifier. +Required if needed to fully specify the orientation of the patient with respect to gravity. +Only a single Item shall be permitted in this Sequence. + + + + Sequence that describes the orientation of the patient with respect to the head of the table. See Section C.8.4.6.1.3 for further explanation. +Zero or one item shall be present in the sequence. +Required if Positioner Type (0018,1508) equals CARM and C-arm Positioner Tabletop Relationship (0018,9474) equals YES. May be present otherwise. +
Patient Gantry Relationship Code Sequence (0054,0414) is used to describe the patient direction within the gantry, such as head-first or feet-first. When imaging the extremities, these directions are related to normal anatomic position. +Example: In normal anatomic position, the fingers point towards the feet. +
+
+ + + Body thickness in mm at examination location perpendicular to the table top for this series. +Notes: 1. This is intended for estimation of the thickness of the patient at the tabletop, not for precise calculation of the size of the object in the X-Ray beam (see Calculated Anatomy Thickness (0018,9452) attribute). +2. For example, used to estimate the value range of the Distance Object to Table Top (0018,9403) attribute. + + + Indicates whether or not the image contains sufficient burned in annotation to identify the patient and date the image was acquired. +Enumerated Values: +NO + + + Specifies whether an Image has undergone lossy compression. Enumerated Values: +00 = Image has NOT been subjected to lossy compression. +01 = Image has been subjected to lossy compression. +See C.7.6.1.1.5 for further explanation. +
The Attribute Lossy Image Compression (0028,2110) conveys that the Image has undergone lossy compression. It provides a means to record that the Image has been compressed (at a point in its lifetime) with a lossy algorithm and changes have been introduced into the pixel data. Once the value has been set to “01â€, it shall not be reset. +Note: If an image is compressed with a lossy algorithm, the attribute Lossy Image Compression (0028,2110) is set to “01â€. Subsequently, if the image is decompressed and transferred in uncompressed format, this attribute value remains “01â€. + +The value of the Lossy Image Compression (0028,2110) Attribute in SOP Instances containing multiple frames in which one or more of the frames have undergone lossy compression shall be “01â€. +Note: It is recommended that the applicable frames be noted in the Attribute Derivation Description (0008,2111). + +If an image is originally obtained as a lossy compressed image from the sensor, then Lossy Image Compression (0028,2110) is set to “01†and Value 1 of the Attribute Image Type (0008,0008) shall be set to ORIGINAL. +If an image is a compressed version of another image, Lossy Image Compression (0028,2110) is set to “01â€, Value 1 of the Attribute Image Type (0008,0008) shall be set to DERIVED, and if the predecessor was a DICOM image, then the Image shall receive a new SOP Instance UID. +Note: 1. It is recommended that the approximate compression ratio be provided in the Attribute Derivation Description (0008,2111). Furthermore, it is recommended that Derivation Description (0008,2111) be used to indicate when pixel data changes might affect professional interpretation. (see C.7.6.1.1.3). + 2. The attribute Lossy Image Compression (0028,2110) is defined as Type 3 for backward compatibility with existing IODs. It is expected to be required (i.e., defined as Type 1C) for new Image IODs and for existing IODs that undergo a major revision (e.g. a new IOD is specified). +The Defined Terms for Lossy Image Compression Method (0028,2114) are: +ISO_10918_1 = JPEG Lossy Compression +ISO_14495_1 = JPEG-LS Near-lossless Compression +ISO_15444_1 = JPEG 2000 Irreversible Compression +ISO_13818_2 = MPEG2 Compression + +
+
+ + See C.7.6.1.1.5 for further explanation. +Required if Lossy Image Compression (0028,2110) equals 01. +
The Attribute Lossy Image Compression (0028,2110) conveys that the Image has undergone lossy compression. It provides a means to record that the Image has been compressed (at a point in its lifetime) with a lossy algorithm and changes have been introduced into the pixel data. Once the value has been set to “01â€, it shall not be reset. +Note: If an image is compressed with a lossy algorithm, the attribute Lossy Image Compression (0028,2110) is set to “01â€. Subsequently, if the image is decompressed and transferred in uncompressed format, this attribute value remains “01â€. + +The value of the Lossy Image Compression (0028,2110) Attribute in SOP Instances containing multiple frames in which one or more of the frames have undergone lossy compression shall be “01â€. +Note: It is recommended that the applicable frames be noted in the Attribute Derivation Description (0008,2111). + +If an image is originally obtained as a lossy compressed image from the sensor, then Lossy Image Compression (0028,2110) is set to “01†and Value 1 of the Attribute Image Type (0008,0008) shall be set to ORIGINAL. +If an image is a compressed version of another image, Lossy Image Compression (0028,2110) is set to “01â€, Value 1 of the Attribute Image Type (0008,0008) shall be set to DERIVED, and if the predecessor was a DICOM image, then the Image shall receive a new SOP Instance UID. +Note: 1. It is recommended that the approximate compression ratio be provided in the Attribute Derivation Description (0008,2111). Furthermore, it is recommended that Derivation Description (0008,2111) be used to indicate when pixel data changes might affect professional interpretation. (see C.7.6.1.1.3). + 2. The attribute Lossy Image Compression (0028,2110) is defined as Type 3 for backward compatibility with existing IODs. It is expected to be required (i.e., defined as Type 1C) for new Image IODs and for existing IODs that undergo a major revision (e.g. a new IOD is specified). +The Defined Terms for Lossy Image Compression Method (0028,2114) are: +ISO_10918_1 = JPEG Lossy Compression +ISO_14495_1 = JPEG-LS Near-lossless Compression +ISO_15444_1 = JPEG 2000 Irreversible Compression +ISO_13818_2 = MPEG2 Compression + +
+
+ + A label for the lossy compression method(s) that have been applied to this image. +See C.7.6.1.1.5 for further explanation. +May be multi valued if successive lossy compression steps have been applied; the value order shall correspond to the values of Lossy Image Compression Ratio (0028,2112). +Note: For historical reasons, the lossy compression method may also be described in Derivation Description (0008,2111). +Required if Lossy Image Compression (0028,2110) equals 01. +
The Attribute Lossy Image Compression (0028,2110) conveys that the Image has undergone lossy compression. It provides a means to record that the Image has been compressed (at a point in its lifetime) with a lossy algorithm and changes have been introduced into the pixel data. Once the value has been set to “01â€, it shall not be reset. +Note: If an image is compressed with a lossy algorithm, the attribute Lossy Image Compression (0028,2110) is set to “01â€. Subsequently, if the image is decompressed and transferred in uncompressed format, this attribute value remains “01â€. + +The value of the Lossy Image Compression (0028,2110) Attribute in SOP Instances containing multiple frames in which one or more of the frames have undergone lossy compression shall be “01â€. +Note: It is recommended that the applicable frames be noted in the Attribute Derivation Description (0008,2111). + +If an image is originally obtained as a lossy compressed image from the sensor, then Lossy Image Compression (0028,2110) is set to “01†and Value 1 of the Attribute Image Type (0008,0008) shall be set to ORIGINAL. +If an image is a compressed version of another image, Lossy Image Compression (0028,2110) is set to “01â€, Value 1 of the Attribute Image Type (0008,0008) shall be set to DERIVED, and if the predecessor was a DICOM image, then the Image shall receive a new SOP Instance UID. +Note: 1. It is recommended that the approximate compression ratio be provided in the Attribute Derivation Description (0008,2111). Furthermore, it is recommended that Derivation Description (0008,2111) be used to indicate when pixel data changes might affect professional interpretation. (see C.7.6.1.1.3). + 2. The attribute Lossy Image Compression (0028,2110) is defined as Type 3 for backward compatibility with existing IODs. It is expected to be required (i.e., defined as Type 1C) for new Image IODs and for existing IODs that undergo a major revision (e.g. a new IOD is specified). +The Defined Terms for Lossy Image Compression Method (0028,2114) are: +ISO_10918_1 = JPEG Lossy Compression +ISO_14495_1 = JPEG-LS Near-lossless Compression +ISO_15444_1 = JPEG 2000 Irreversible Compression +ISO_13818_2 = MPEG2 Compression + +
+
+ + A sequence that identifies the SOP Class/Instance pairs of the corresponding plane for a Biplane acquisition device. +Only a single Item shall be permitted in this Sequence. +Required if Image Type (0008,0008) Value 3 is BIPLANE A or BIPLANE B. + + + + Full set of Composite SOP Instances referred to inside the Referenced Image Sequences of this SOP Instance. See C.8.13.2.1.2 for further explanation. +One or more Items may be permitted in this sequence. +Required if the Referenced Image Sequence (0008,1140) is present. +
The intent of the Referenced Image Evidence Sequence (0008,9092) and Source Image Evidence Sequence (0008,9154) is to provide a list of all unique SOP Instances listed in the Referenced Image Sequence (0008,1140) and Source Image Sequence (0008,2112) attributes respectively. +
+
+ + + Full set of Composite SOP Instances referred to inside the Source Image Sequences of this SOP Instance. See C.8.13.2.1.2 for further explanation. +One or more Items may be permitted in this sequence. +Required if the Source Image Sequence (0008,2112) is present. +
The intent of the Referenced Image Evidence Sequence (0008,9092) and Source Image Evidence Sequence (0008,9154) is to provide a list of all unique SOP Instances listed in the Referenced Image Sequence (0008,1140) and Source Image Sequence (0008,2112) attributes respectively. +
+
+ + + A sequence which provides reference to a set of non-image SOP Class/Instance pairs significantly related to this Image, including waveforms that may or may not be temporally synchronized with this image. +One or more Items may be included in this sequence. + + + + Code describing the purpose of the reference to the SOP Instances. +Only a single Item shall be permitted in this sequence. + + + + User-defined comments about the image. + + + Indicates whether or not this image is a quality control or phantom image. +Enumerated Values: +YES +NO +If this Attribute is absent, then the image may or may not be a quality control or phantom image. + + + This icon image is representative of the Image. Only a single Item shall be permitted in this Sequence. + + + + Specifies a predefined identity transformation for the Presentation LUT such that the output of all grayscale transformations, if any, are defined to be in P-Values. +Enumerated Values: +IDENTITY - output is in P-Values - shall be used if Photometric Interpretation (0028,0004) is MONOCHROME2 +INVERSE - output after inversion is in P-Values - shall be used if Photometric Interpretation (0028,0004) is MONOCHROME1. + +
+ + + Average of the peak kilo voltage outputs of the X-Ray generator used for all frames. + + + Identify the general level of X-Ray dose exposure. Enumerated values are: +SC = low dose exposure generally corresponding to fluoroscopic settings (e.g. preparation for diagnostic quality image acquisition); +GR = high dose for diagnostic quality image acquisition (also called digital spot or cine); + + + Average of the nominal X-Ray tube currents in milliamperes for all frames. +Required if Exposure in mAs (0018,9332) is not present. May be present otherwise. + + + Duration of X-Ray exposure in milliseconds. See C.8.7.2.1.1. +Required if Exposure in mAs (0018,9332) is not present. May be present otherwise. +
Exposure time is the cumulative time the patient received X-Ray exposure during this image (Multi-frame image acquisition). Calculation is pulse width * number of frames. +
+
+ + The exposure expressed in milliampereseconds, for example calculated from Exposure Time and X-Ray Tube Current. +Required if either Exposure Time in ms (0018,9328) or X-Ray Tube Current in mA (0018,9330) are not present. May be present otherwise. + + + Average width of X-Ray pulse in msec. + + + The time in seconds needed for the complete acquisition. +See C.7.6.16.2.2.1 for further explanation +
Figure C.7.6.16-2 shows the relationships among the various timing parameters used. +
+
+ + Specifies X-Ray radiation mode. Defined Terms: +CONTINUOUS +PULSED + + + Nominal focal spot size in mm used to acquire this image. + + + The primary material in the anode of the X-Ray source. +Defined Terms: +TUNGSTEN +MOLYBDENUM +RHODIUM + + + Type of rectification used in the X-Ray generator. +Defined Terms: +SINGLE PHASE +THREE PHASE +CONST POTENTIAL + + + Identifies with type of X-Ray receptor is used. +Enumerated Values: +IMG_INTENSIFIER +DIGITAL_DETECTOR + + + Physical distance measured at the receptor plane of the detector between the centers of each pixel specified by a numeric pair - row spacing value (delimiter) column spacing value in mm. See 10.7.1.3 for further explanation of the value order. +Note: These values are the actual pixel spacing distances of the stored pixel values of an image. + + + Distance in mm between the receptor plane and the detector housing. The direction of the distance is positive from receptor plane to X-Ray source. +Note: 1. A negative value is allowed in the case of an image intensifier the receptor plane can be a virtual plane located outside the detector housing depending the magnification factor of the intensifier. A negative value is not applicable for the digital detector. +2. Used to calculate the pixel size of the plane in the patient when markers are used, and they are placed on the detector housing. + + + Defined Terms: +CARM +COLUMN +Notes: 1. The term CARM can apply to any positioner with 2 degrees of freedom of rotation of the X-Ray beam about the Imaging Subject. +2. The term COLUMN can apply to any positioner with 1 degree of freedom of rotation of the X-Ray beam about the Imaging Subject. + + + Describes for C-arm positioner type systems if positioner and tabletop has the same geometrical reference system. +Enumerated Values: +YES +NO +Note: The value NO is intended for mobile systems where there is no table fixed to the system +Required if Positioner Type (0018,1508) equals CARM. + + + X-Ray dose, measured in dGy*cm*cm, to which the patient was exposed for the acquisition of this image only. +Notes: 1. The sum of the Image Area Dose Product of all images of a Series or a Study may not result in the actual area dose product to which the patient was exposed. +2. This may be an estimated value based on assumptions about the patient's body size and habitus. + +
+ + + Physical diameter of the maximum active area X-Ray intensifier in mm. +Note: This attribute does not specify the field of view. The attribute Field of View Dimension(s) in Float (0018,9461) is intended for this value. + + + Shape of the active area used for acquiring this image. +Enumerated Value: +RECTANGLE +ROUND +HEXAGONAL +Note: This may be different from the Field of View Shape (0018,1147), and should not be assumed to describe the stored image. + + + Dimensions in mm of the active area used for acquiring this image. +If Intensifier Active Shape (0018,9427) is: +RECTANGLE: row dimension followed by column. +ROUND: diameter. +HEXAGONAL: diameter of the circle circumscribing the hexagon. +Note: This may be different from the Field of View Dimension(s) in Float (0018,9461), and should not be assumed to describe the stored image. + + + + + + Dimensions of the physical detector measured in mm as a row size followed by a column size. + + + Position of the Isocenter measured in physical detector elements as a row offset followed by a column offset from the TLHC of a rectangle circumscribing the physical detector area. +Required if Isocenter Reference System Sequence (0018,9462) is present. + + + + + A sequence that describes general characteristics of this frame. +Only a single Item shall be permitted in this sequence. + + + A text description of how this frame was derived. +See C.8.7.1.1.5 for further explanation. +
If an Image is identified to be a Derived image (see C.8.9.1.1.1 Image Type), Derivation Description (0008,2111) is an optional and implementation specific text description of the way the image was derived from an original image. As applied to X-Ray images, it may be used to describe derivation operations such as edge enhancement, temporal filtering, digital subtraction, or other linear and non-linear transformations. +
+
+ + A coded description of how this frame was derived. See C.7.6.1.1.3 for further explanation. One or more Items may be included in this Sequence. More than one Item indicates that successive derivation steps have been applied. +
If an Image is identified to be a derived image (see C.7.6.1.1.2 Image Type), Derivation Description (0008,2111) and Derivation Code Sequence (0008,9215) describe the way in which the image was derived. They may be used whether or not the Source Image Sequence (0008,2112) is provided. They may also be used in cases when the Derived Image pixel data is not significantly changed from one of the source images and the SOP Instance UID of the Derived Image is the same as the one used for the source image. +Notes: 1. Examples of Derived Images that would normally be expected to affect professional interpretation and would thus have a new UID include: + a. images resulting from image processing of another image (e.g. unsharp masking), + b. a multiplanar reformatted CT image, + c. a DSA image derived by subtracting pixel values of one image from another. +d. an image that has been decompressed after having been compressed with a lossy compression algorithm. To ensure that the user has the necessary information about the lossy compression, the approximate compression ratio may be included in Derivation Description (0008,2111). + An example of a Derived Image that would normally not be expected to affect professional interpretation and thus would not require a new UID is an image that has been padded with additional rows and columns for more display purposes. + 2. An image may be lossy compressed, e.g., for long term archive purposes, and its SOP Instance UID changed. PS3.4 provides a mechanism by which a query for the original image Instance may return a reference to the UID of the lossy compressed version of the image using the Alternate Representation Sequence (0008,3001). This allows an application processing a SOP Instance that references the original image UID, e.g., a Structured Report, to obtain a reference to an accessible version of the image even if the original SOP Instance is no longer available. + +
+
+ + + Indicates any visual processing performed on the frame prior to exchange. +See Section C.8.7.1.1.3. +
Acquisition Device Processing Description (0018,1400) provides some indication in human readable text of the digital processing on the images before exchange. Examples of this processing are: edge enhanced, subtracted, time filtered, gamma corrected, convolved (spatially filtered). +
+
+ + Code representing the device-specific processing associated with the frame (e.g. Organ Filtering code) +Note: This Code is manufacturer specific but provides useful annotation information to the knowledgeable observer. + +
+ + + Sequence containing the field of view for this frame. +One or more items may be included in this sequence. + + + Shape of the Field of View, that is the image pixels stored in Pixel Data (7FE0,0010). +Enumerated Values: +RECTANGLE +ROUND +HEXAGONAL + + + Dimensions in mm of the Field of View, that is the image pixels stored in Pixel Data (7FE0,0010). If Field of View Shape (0018,1147) is: +RECTANGLE: row dimension followed by column. +ROUND: diameter. +HEXAGONAL: diameter of the circle circumscribing the hexagon. + + + Offset of the TLHC of a rectangle circumscribing the Field of View, i.e., the image pixels stored in Pixel Data (7FE0,0010) before rotation or flipping, from the TLHC of the physical detector area measured in physical detector pixels as a row offset followed by a column offset. +See C.8.11.4.1.1 for further explanation. +Required if X-Ray Receptor Type (0018,9420) is present and equals DIGITAL_DETECTOR. +
The relationship between the Physical Detector Area, the Active Detector Area, the Field of View (what is stored in the Pixel Data (7FE0,0010)), the Exposed Area (after X-Ray Collimation) and the Displayed Area is illustrated in the following diagrams. +Note: Some of these Attributes relate the image data to manufacturer specific characteristics of the detector that may be used for quality control purposes, e.g. correlation of image artifacts with a detector defect map, analysis of noise performance, etc. + +The Displayed Area is defined in pixel coordinates relative to the stored image pixel values by the Attributes of the Display Shutter Module (see section C.7.6.11). If this Module is not present or supported, then the Displayed Area is equal to the Field of View. +The Exposed Area is defined in pixel coordinates relative to the stored image pixel values by the Attributes of the X-Ray Collimator Module (see section C.8.7.3). +For the Digital X-Ray IODs, the Field of View is usually rectangular in shape and the same size as the stored Pixel Data (7FE0,0010). The shape and size of the Field of View and the spacing of the pixels are defined by the following Attributes: +- Field of View Shape (0018,1147), +- Field of View Dimensions (0018,1149), +- Imager Pixel Spacing (0018,1164), +- Rows (0028,0010), +- Columns (0028,0011) + +The following Attributes define the relationship of the Field of View to the Physical Detector Area: +- Field of View Origin (0018,7030), +- Field of View Rotation (0018,7032), +- Field of View Horizontal Flip (0018,7034). + +For the Digital X-Ray IODs, the Active Area, i.e. that part of the detector matrix that was activated for this exposure, is usually rectangular in shape. The shape and size of the Active Area and the size and spacing of the detectors are defined by the following Attributes: +- Detector Active Shape (0018,7024), +- Detector Active Dimensions (0018,7026), +- Detector Element Physical Size (0018,7020), +- Detector Element Spacing (0018,7022). + +Notes: 1. The Detector Element Physical Size (0018,7020) and Detector Element Spacing (0018,7022) may be different if there are insensitive regions between each detector. + 2. This model of description is not able to accurately describe multiple matrices of detectors that are “tiled†to produce a single image. + +The following optional Attribute defines the relationship of the Active Area to the Physical Detector Area: +- Detector Active Origin (0018,7028). + +The relationship between detectors and stored image pixels is defined by Detector Binning (0018,701A) which specifies how many detectors, in each of the row and column directions, contribute to (are pooled or averaged to form) a single stored image pixel. +Note: Detector Binning (0018,701A) may have values less than one if sub-sampling is used to derive an image with higher spatial resolution than the detector matrix. + + + +Figure C.8-14 +Explanation of DX Detector Attributes + + + + +Figure C.8-15 +Explanation of DX Detector Attributes +
+
+ + Clockwise rotation in degrees of Field of View, i.e., the image pixels stored in Pixel Data (7FE0,0010), relative to the physical detector. +Enumerated Values: +0, 90, 180, 270 +See C.8.11.4.1.1 for further explanation. +
The relationship between the Physical Detector Area, the Active Detector Area, the Field of View (what is stored in the Pixel Data (7FE0,0010)), the Exposed Area (after X-Ray Collimation) and the Displayed Area is illustrated in the following diagrams. +Note: Some of these Attributes relate the image data to manufacturer specific characteristics of the detector that may be used for quality control purposes, e.g. correlation of image artifacts with a detector defect map, analysis of noise performance, etc. + +The Displayed Area is defined in pixel coordinates relative to the stored image pixel values by the Attributes of the Display Shutter Module (see section C.7.6.11). If this Module is not present or supported, then the Displayed Area is equal to the Field of View. +The Exposed Area is defined in pixel coordinates relative to the stored image pixel values by the Attributes of the X-Ray Collimator Module (see section C.8.7.3). +For the Digital X-Ray IODs, the Field of View is usually rectangular in shape and the same size as the stored Pixel Data (7FE0,0010). The shape and size of the Field of View and the spacing of the pixels are defined by the following Attributes: +- Field of View Shape (0018,1147), +- Field of View Dimensions (0018,1149), +- Imager Pixel Spacing (0018,1164), +- Rows (0028,0010), +- Columns (0028,0011) + +The following Attributes define the relationship of the Field of View to the Physical Detector Area: +- Field of View Origin (0018,7030), +- Field of View Rotation (0018,7032), +- Field of View Horizontal Flip (0018,7034). + +For the Digital X-Ray IODs, the Active Area, i.e. that part of the detector matrix that was activated for this exposure, is usually rectangular in shape. The shape and size of the Active Area and the size and spacing of the detectors are defined by the following Attributes: +- Detector Active Shape (0018,7024), +- Detector Active Dimensions (0018,7026), +- Detector Element Physical Size (0018,7020), +- Detector Element Spacing (0018,7022). + +Notes: 1. The Detector Element Physical Size (0018,7020) and Detector Element Spacing (0018,7022) may be different if there are insensitive regions between each detector. + 2. This model of description is not able to accurately describe multiple matrices of detectors that are “tiled†to produce a single image. + +The following optional Attribute defines the relationship of the Active Area to the Physical Detector Area: +- Detector Active Origin (0018,7028). + +The relationship between detectors and stored image pixels is defined by Detector Binning (0018,701A) which specifies how many detectors, in each of the row and column directions, contribute to (are pooled or averaged to form) a single stored image pixel. +Note: Detector Binning (0018,701A) may have values less than one if sub-sampling is used to derive an image with higher spatial resolution than the detector matrix. + + + +Figure C.8-14 +Explanation of DX Detector Attributes + + + + +Figure C.8-15 +Explanation of DX Detector Attributes +
+
+ + Whether or not a horizontal flip has been applied to the Field of View, i.e., the image pixels stored in Pixel Data (7FE0,0010), after rotation relative to the physical detector as described in Field of View Rotation (0018,7032). +Enumerated Values: +NO +YES +See C.8.11.4.1.1 for further explanation. +
The relationship between the Physical Detector Area, the Active Detector Area, the Field of View (what is stored in the Pixel Data (7FE0,0010)), the Exposed Area (after X-Ray Collimation) and the Displayed Area is illustrated in the following diagrams. +Note: Some of these Attributes relate the image data to manufacturer specific characteristics of the detector that may be used for quality control purposes, e.g. correlation of image artifacts with a detector defect map, analysis of noise performance, etc. + +The Displayed Area is defined in pixel coordinates relative to the stored image pixel values by the Attributes of the Display Shutter Module (see section C.7.6.11). If this Module is not present or supported, then the Displayed Area is equal to the Field of View. +The Exposed Area is defined in pixel coordinates relative to the stored image pixel values by the Attributes of the X-Ray Collimator Module (see section C.8.7.3). +For the Digital X-Ray IODs, the Field of View is usually rectangular in shape and the same size as the stored Pixel Data (7FE0,0010). The shape and size of the Field of View and the spacing of the pixels are defined by the following Attributes: +- Field of View Shape (0018,1147), +- Field of View Dimensions (0018,1149), +- Imager Pixel Spacing (0018,1164), +- Rows (0028,0010), +- Columns (0028,0011) + +The following Attributes define the relationship of the Field of View to the Physical Detector Area: +- Field of View Origin (0018,7030), +- Field of View Rotation (0018,7032), +- Field of View Horizontal Flip (0018,7034). + +For the Digital X-Ray IODs, the Active Area, i.e. that part of the detector matrix that was activated for this exposure, is usually rectangular in shape. The shape and size of the Active Area and the size and spacing of the detectors are defined by the following Attributes: +- Detector Active Shape (0018,7024), +- Detector Active Dimensions (0018,7026), +- Detector Element Physical Size (0018,7020), +- Detector Element Spacing (0018,7022). + +Notes: 1. The Detector Element Physical Size (0018,7020) and Detector Element Spacing (0018,7022) may be different if there are insensitive regions between each detector. + 2. This model of description is not able to accurately describe multiple matrices of detectors that are “tiled†to produce a single image. + +The following optional Attribute defines the relationship of the Active Area to the Physical Detector Area: +- Detector Active Origin (0018,7028). + +The relationship between detectors and stored image pixels is defined by Detector Binning (0018,701A) which specifies how many detectors, in each of the row and column directions, contribute to (are pooled or averaged to form) a single stored image pixel. +Note: Detector Binning (0018,701A) may have values less than one if sub-sampling is used to derive an image with higher spatial resolution than the detector matrix. + + + +Figure C.8-14 +Explanation of DX Detector Attributes + + + + +Figure C.8-15 +Explanation of DX Detector Attributes +
+
+ + Manufacturer defined description of the field of view selected during acquisition. + +
+ + + Sequence containing the Exposure Control Sensing Region for this frame. +One or more items may be included in this sequence. + + + Shape of the Exposure Control Sensing Region. Enumerated Values: +RECTANGULAR +CIRCULAR +POLYGONAL + + + Required if Exposure Control Sensing Region Shape (0018,9435) is RECTANGULAR. Location of the left edge of the rectangular Exposure Control Sensing Region expressed as effective pixel column. See C.8.19.6.3.1. +
The Exposure Control Sensing Region Left Vertical Edge (0018,9436), Exposure Control Sensing Region Right Vertical Edge (0018,9437), Exposure Control Sensing Region Upper Horizontal Edge (0018,9438), Exposure Control Sensing Region Lower Horizontal Edge (0018,9439) and Center of Circular Exposure Control Sensing Region (0018,9440) may have a negative value when the point defined by the attribute lies outside the left or upper border of the pixel data matrix. The top left pixel of the image has a pixel row and column value of 1. +
+
+ + Required if Exposure Control Sensing Region Shape (0018,9435) is RECTANGULAR. Location of the right edge of the rectangular Exposure Control Sensing Region expressed as effective pixel column. See C.8.19.6.3.1. +
The Exposure Control Sensing Region Left Vertical Edge (0018,9436), Exposure Control Sensing Region Right Vertical Edge (0018,9437), Exposure Control Sensing Region Upper Horizontal Edge (0018,9438), Exposure Control Sensing Region Lower Horizontal Edge (0018,9439) and Center of Circular Exposure Control Sensing Region (0018,9440) may have a negative value when the point defined by the attribute lies outside the left or upper border of the pixel data matrix. The top left pixel of the image has a pixel row and column value of 1. +
+
+ + Required if Exposure Control Sensing Region Shape (0018,9435) is RECTANGULAR. Location of the upper edge of the rectangular Exposure Control Sensing Region expressed as effective pixel row. See C.8.19.6.3.1. +
The Exposure Control Sensing Region Left Vertical Edge (0018,9436), Exposure Control Sensing Region Right Vertical Edge (0018,9437), Exposure Control Sensing Region Upper Horizontal Edge (0018,9438), Exposure Control Sensing Region Lower Horizontal Edge (0018,9439) and Center of Circular Exposure Control Sensing Region (0018,9440) may have a negative value when the point defined by the attribute lies outside the left or upper border of the pixel data matrix. The top left pixel of the image has a pixel row and column value of 1. +
+
+ + Required if Exposure Control Sensing Region Shape (0018,9435) is RECTANGULAR. Location of the lower edge of the rectangular Exposure Control Sensing Region expressed as effective pixel row. See C.8.19.6.3.1. +
The Exposure Control Sensing Region Left Vertical Edge (0018,9436), Exposure Control Sensing Region Right Vertical Edge (0018,9437), Exposure Control Sensing Region Upper Horizontal Edge (0018,9438), Exposure Control Sensing Region Lower Horizontal Edge (0018,9439) and Center of Circular Exposure Control Sensing Region (0018,9440) may have a negative value when the point defined by the attribute lies outside the left or upper border of the pixel data matrix. The top left pixel of the image has a pixel row and column value of 1. +
+
+ + Required if Exposure Control Sensing Region Shape (0018,9435) is CIRCULAR. Location of the center of the circular Exposure Control Sensing Region expressed as effective pixel row and column. See C.8.19.6.3.1. +
The Exposure Control Sensing Region Left Vertical Edge (0018,9436), Exposure Control Sensing Region Right Vertical Edge (0018,9437), Exposure Control Sensing Region Upper Horizontal Edge (0018,9438), Exposure Control Sensing Region Lower Horizontal Edge (0018,9439) and Center of Circular Exposure Control Sensing Region (0018,9440) may have a negative value when the point defined by the attribute lies outside the left or upper border of the pixel data matrix. The top left pixel of the image has a pixel row and column value of 1. +
+
+ + Required if Exposure Control Sensing Region Shape (0018,9435) is CIRCULAR. Radius of the circular Exposure Control Sensing Region expressed as effective number of pixels along the row direction. See C.8.19.6.3.1. +
The Exposure Control Sensing Region Left Vertical Edge (0018,9436), Exposure Control Sensing Region Right Vertical Edge (0018,9437), Exposure Control Sensing Region Upper Horizontal Edge (0018,9438), Exposure Control Sensing Region Lower Horizontal Edge (0018,9439) and Center of Circular Exposure Control Sensing Region (0018,9440) may have a negative value when the point defined by the attribute lies outside the left or upper border of the pixel data matrix. The top left pixel of the image has a pixel row and column value of 1. +
+
+ + Required if Exposure Control Sensing Region Shape (0018,9435) is POLYGONAL. +Multiple Values where the first set of two values are: +row of the origin vertex; +column of the origin vertex. +Two or more pairs of values follow and are the effective pixel row and column coordinates of the other vertices of the polygon Exposure Control Sensing Region. Polygon Exposure Control Sensing Regions are implicitly closed from the last vertex to the origin vertex and all edges shall be non-intersecting except at the vertices. See C.8.19.6.3.1. +
The Exposure Control Sensing Region Left Vertical Edge (0018,9436), Exposure Control Sensing Region Right Vertical Edge (0018,9437), Exposure Control Sensing Region Upper Horizontal Edge (0018,9438), Exposure Control Sensing Region Lower Horizontal Edge (0018,9439) and Center of Circular Exposure Control Sensing Region (0018,9440) may have a negative value when the point defined by the attribute lies outside the left or upper border of the pixel data matrix. The top left pixel of the image has a pixel row and column value of 1. +
+
+
+ + + Sequence containing the pixel data properties for this frame. +Only a single Item shall be permitted in this sequence. + + + The relationship between the Pixel and the X-Ray beam intensity. See C.8.19.6.4.1. +
Pixel Intensity Relationship (0028,1040) shall identify the relationship of the pixel values to the X-Ray beam intensity. Defined terms are: + +
+
+ + The sign of the relationship between the Pixel sample values stored in Pixel Data (7FE0,0010) and the X-Ray beam intensity. +Enumerated Values: +1 = Lower pixel values correspond to less X-Ray beam intensity +-1 = Higher pixel values correspond to less X-Ray beam intensity +See C.8.11.3.1.2 for further explanation. +
Pixel Intensity Relationship (0028,1040) and Pixel Intensity Relationship Sign (0028,1041) describe how the stored pixel values in Pixel Data (7FE0,0010) are related to the X-Ray beam intensity incident on the detector. +They do not define a transformation intended to be applied to the pixel data for presentation. +Note: For example, if Pixel Intensity Relationship (0028,1040) is LIN and Pixel Intensity Relationship Sign (0028,1041) is -1, then lower values of Pixel Data (7FE0,0010) indicate higher X-Ray beam intensities corresponding to less radiographically dense regions projected on the image such as through air, and higher values of Pixel Data (7FE0,0010) indicate lower X-Ray beam intensities corresponding to more radiographically dense regions projected on the image such as through bone and radio-opaque contrast agents. + +The transformation to be applied to the pixel data for presentation is defined by the successive application of the conceptual Modality LUT, the VOI Attributes and the conceptual Presentation LUT. This shall result in the output of P-Values. +Rescale Slope (0028,1053) and Rescale Intercept (0028,1052) define a linear subset of a conceptual Modality LUT transformation. For IODs that include this Module, these Attributes define an identity transformation. IODs that include the DX Image Module shall not include the Modality LUT Module. +The Presentation LUT Shape (2050,0020) defines a subset of a conceptual Presentation LUT. For IODs that include this Module, this Attribute defines an identity transformation or inverse identity transformation. IODs that include the DX Image Module shall not include the Presentation LUT Module. +Photometric Interpretation (0028,0004) indicates whether lower values that are the output of the VOI Attributes should be displayed as darker or lighter. Since the output of the equivalent of a conceptual Presentation LUT is in P-Values, which are defined in PS 3.14 such that lower values correspond to lower luminance levels, then the definition of the Presentation LUT Shape (2050,0020), otherwise intended to be an identity transformation, must take into account the effect of the value specified for Photometric Interpretation (0028,0004). +Note: Regardless of the values of Pixel Intensity Relationship (0028,1040) and Pixel Intensity Relationship Sign (0028,1041), the grayscale transformations to be applied to the Pixel Data (7FE0,0010) are defined by the equivalent of the Modality LUT (Rescale Slope (0028,1053) and Rescale Intercept (0028,1052)), Value of Interest Attributes, Photometric Interpretation (0028,0004) and the equivalent of the Presentation LUT (Presentation LUT Shape (2050,0020)). However, the combination of the grayscale transformations and the description of the pixel intensity relationship, together define whether, for example, air is expected to be displayed as black or white. + +
+
+ + Geometrical characteristics of the pixel data to indicate whether pixel spacing is uniform for all pixels or not. +Enumerated Values: +UNIFORM +NON_UNIFORM + + + The percentage of the maximum deviation of the pixel spacing values of images for which the geometric properties are non-uniform. +Note: This attribute may be used to judge the result of measurements, 3D reconstructions, etc. +Required if Geometrical Properties (0028,9444) equals NON_UNIFORM. + + + The type or a combination of types of image processing applied to the pixel data before being stored. +Defined Terms: +DIGITAL_SUBTR +HIGH_PASS_FILTER +LOW_PASS_FILTER +MULTI_BAND_FLTR +FRAME_AVERAGING +NONE + +
+ + + Sequence containing the detector properties for this frame. +Only a single Item shall be permitted in this sequence. + + + Time in mSec that the detector is active during acquisition of this image. +Note: This activation window overlaps the time of the X-Ray exposure as defined by Exposure Time in ms (0018,9328) and Detector Activation Offset From Exposure (0018,7016). + + + Offset time in mSec that the detector becomes active after the X-Ray beam is turned on during acquisition of this image. May be negative. + + + + + Sequence containing the calibration flag for this frame. +Only a single Item shall be permitted in this sequence. + + + Indicates whether a reference object (phantom) of known size is present in the frame and was used for calibration. Enumerated Values: +YES +NO +Note: Device is identified using the Device module. See C.7.6.12. +
Table C.7-18 describes the Attributes of devices or calibration objects (e.g., catheters, markers, baskets) that are associated with a study and/or image. +Table C.7-18 +DEVICE MODULE ATTRIBUTES + +
+
+
+ + + Sequence containing object thickness for this frame. +Only a single Item shall be permitted in this sequence. + + + The physical thickness in mm of the anatomic region of interest as specified in the Anatomic Region Sequence (0008,2218) in the direction of the center of the beam. +Note: The value takes in account the position relative to object and the X-Ray source - detector axis. + + + + + Sequence containing the acquisition parameters for this frame. +Only a single Item shall be permitted in this sequence. + + + Exact peak kilo voltage output of the X-Ray generator used for this frame. + + + Exact Nominal X-Ray tube current in milliamperes applied during the Acquisition Duration (0018,9220) for this frame. + + + + + A sequence that describes the geometrical position of the patient relative to the equipment. +Only a single Item shall be permitted in this sequence. + + + Distance between the anatomic region of interest of observation and table top in mm. +Notes: 1.This value is always positive, the object is assumed to be above the table. +2.The value of this attribute is depending on the patient position on the tabletop (supine, left or right decubitus, etc.) + + + Physical distance within the anatomic region of interest in the center of the beam and perpendicular to the beam between the center of each pixel, specified by a numeric pair adjacent row spacing (delimiter) adjacent column spacing in mm. See C.8.19.6.9.2. See 10.7.1.3 for further explanation of the value order. +Required if Distance Object to Table Top (0018,9403) is not empty. +Note: This value is provided besides the values that are the input parameters of the calibration algorithm. +
The value provided for the Beam Angle (0018,9449) attribute shall correspond to the other attribute values within this module and according to the mathematic terms listed in section C.8.19.6.9.1. +The terms listed will result in infinite result when used with 90-degree beam angles. +It is outside the scope of this Standard to define reasonable limits for single input values in the above-mentioned terms, or to define the mathematical accuracy of applications using those terms. +Note: It may be reasonable to limit automatic calculations to a narrow range of +/- 60 degrees for Beam Angle and inform users about possible deviations in the calibration result when exceeding such range limits. + +
+
+ + The distance of the top of the patient table to the center of rotation of the source (i.e. the isocenter) in mm. A positive value indicates that the tabletop is below the isocenter. +Note: All the distances are measured perpendicular to the Table Top plane. +Required if Image Type (0008,0008) Value 1 is ORIGINAL, may be present otherwise. + + + The equipment related angle in degrees of the X-Ray beam relative to the perpendicular to the tabletop plane. An angle from 0 to +90 degrees indicates that the X-Ray source is below the table. +The valid range is 0 to +180 degrees. +Required if Image Type (0008,0008) Value 1 is ORIGINAL, may be present otherwise. + +
+ + + A sequence that describes the geometrical position of the positioner. +Only a single Item shall be permitted in this sequence. + + + Position of the X-Ray Image Intensifier about the patient from the RAO to LAO direction where movement from RAO to vertical is positive. +See C.8.7.5.1.2. +Required if Positioner Type (0018,1508) equals CARM. +
The definitions of Positioner Angles shall be with respect to the patient as illustrated in Figures C.8-11 and C.8-12 Zero degree is referenced to the origin perpendicular to the patient's chest. The Positioner Primary Angle definition is like longitude (in the equatorial plan); the Positioner Secondary Angle definition is like latitude (in the sagittal plane). The Positioner Angle attributes apply to the first frame of a multi-frame image. The valid range of Primary Positioner Angle is -180 to +180 degrees and the Secondary Positioner Angle range is -90 to + 90 degrees. +The Patient Plane is defined by the isocenter of the imaging device and slices through the patient such that it is perpendicular to the sagittal plane of the body. The Primary Axis of rotation is defined at the intersection of the Patient Plane and of the Sagittal Plane. The Positioner Primary Angle is defined in the transaxial plane at the isocenter with zero degrees in the direction perpendicular to the patient's chest and + 90 degrees at the Patient left hand side (LAO) and -90 at the Patient right hand side (RAO). The valid range of Primary Positioner Angle is -180 to +180 degrees. +The Secondary Axis is in the Patient Plane and is perpendicular to the Primary Axis at the isocenter. The Positioner Secondary Angle is defined in the Sagittal Plane at the isocenter with zero degrees in the direction perpendicular to the patient's chest. +90 degrees corresponds to the cranial direction. The Secondary Positioner Angle range is -90 to + 90 degrees. +At a 0 angle for both the Primary Angle (0018,1510) and Secondary Angle (0018,1511), the patient faces the Image Intensifier. +The Positioner Primary Angle (0018,1510) and Secondary Angle (0018,1511) apply to the first frame of a multi-frame image. + +Figure C.8-11 +Positioner Primary Angle + +Figure C.8-12 +Positioner Secondary Angle +
+
+ + Position of the X-Ray Image Intensifier about the patient from the CAU to CRA direction where movement from CAU to vertical is positive. +See C.8.7.5.1.2 +Required if Positioner Type (0018,1508) equals CARM. +
The definitions of Positioner Angles shall be with respect to the patient as illustrated in Figures C.8-11 and C.8-12 Zero degree is referenced to the origin perpendicular to the patient's chest. The Positioner Primary Angle definition is like longitude (in the equatorial plan); the Positioner Secondary Angle definition is like latitude (in the sagittal plane). The Positioner Angle attributes apply to the first frame of a multi-frame image. The valid range of Primary Positioner Angle is -180 to +180 degrees and the Secondary Positioner Angle range is -90 to + 90 degrees. +The Patient Plane is defined by the isocenter of the imaging device and slices through the patient such that it is perpendicular to the sagittal plane of the body. The Primary Axis of rotation is defined at the intersection of the Patient Plane and of the Sagittal Plane. The Positioner Primary Angle is defined in the transaxial plane at the isocenter with zero degrees in the direction perpendicular to the patient's chest and + 90 degrees at the Patient left hand side (LAO) and -90 at the Patient right hand side (RAO). The valid range of Primary Positioner Angle is -180 to +180 degrees. +The Secondary Axis is in the Patient Plane and is perpendicular to the Primary Axis at the isocenter. The Positioner Secondary Angle is defined in the Sagittal Plane at the isocenter with zero degrees in the direction perpendicular to the patient's chest. +90 degrees corresponds to the cranial direction. The Secondary Positioner Angle range is -90 to + 90 degrees. +At a 0 angle for both the Primary Angle (0018,1510) and Secondary Angle (0018,1511), the patient faces the Image Intensifier. +The Positioner Primary Angle (0018,1510) and Secondary Angle (0018,1511) apply to the first frame of a multi-frame image. + +Figure C.8-11 +Positioner Primary Angle + +Figure C.8-12 +Positioner Secondary Angle +
+
+ + Angle of the X-Ray beam in degree relative to an orthogonal axis to the detector plane. Positive values indicate that the tilt is towards the head of the patient. +Notes: 1. The detector plane is assumed to be parallel to the table plane +2. This attribute differentiates form the attribute Column Angulation (0018,1450) by using the patient based coordinate system instead of the equipment based coordinate system. +Required if Positioner Type (0018,1508) equals COLUMN. + +
+ + + A sequence that describes the geometrical position of the table top. +Only a single Item shall be permitted in this sequence. + + + Table Top Vertical position with respect to an arbitrary chosen reference by the equipment in (mm). Table motion downwards is positive + + + Table Top Longitudinal position with respect to an arbitrary chosen reference by the equipment in (mm). Table motion towards LAO is positive assuming that the patient is positioned supine and its head is in normal position. + + + Table Top Lateral position with respect to an arbitrary chosen reference by the equipment in (mm). Table motion towards CRA is positive assuming that the patient is positioned supine and its head is in normal position. + + + Rotation of the table in the horizontal plane (clockwise when looking from above the table). + + + Angle of the head-feet axis of the table in degrees relative to the horizontal plane. Positive values indicate that the head of the table is upwards. + + + Angle of the left-right axis of the table in degrees relative to the horizontal plane. Positive values indicate that the left of the table is upwards. + + + + + A sequence that describes the collimator shape. +Only a single Item shall be permitted in this sequence. + + + Shape(s) of the collimator. Enumerated Values: +RECTANGULAR +CIRCULAR +POLYGONAL +This multi-valued Attribute shall contain at most one of each Enumerated Value. + + + Required if Collimator Shape (0018,1700) is RECTANGULAR. Location of the left edge of the rectangular collimator expressed as effective pixel column. See C.8.7.3.1.1 and C.8.19.6.12.1. +
These attributes specify the pixel row or column where the X-Ray beam is fully obscured by a rectangular collimator: +- if the left edge of the collimator is not visible, Collimator Left Vertical Edge (0018,1702) shall have a value of 0; +- if the right edge of the collimator is not visible, Collimator Right Vertical Edge (0018,1704) value shall be 1 greater than the value of the Columns (0028,0011) attribute; +- if the top edge of the collimator is not visible, Collimator Upper Horizontal Edge (0018,1706) shall have a value of 0; +- if the bottom edge of the collimator is not visible, Collimator Lower Horizontal Edge (0018,1708) value shall be 1 greater than the value of the Rows (0028,0010) attribute. + +
+
+ + Required if Collimator Shape (0018,1700) is RECTANGULAR. Location of the right edge of the rectangular collimator expressed as effective pixel column. See C.8.7.3.1.1 and C.8.19.6.12.1. +
These attributes specify the pixel row or column where the X-Ray beam is fully obscured by a rectangular collimator: +- if the left edge of the collimator is not visible, Collimator Left Vertical Edge (0018,1702) shall have a value of 0; +- if the right edge of the collimator is not visible, Collimator Right Vertical Edge (0018,1704) value shall be 1 greater than the value of the Columns (0028,0011) attribute; +- if the top edge of the collimator is not visible, Collimator Upper Horizontal Edge (0018,1706) shall have a value of 0; +- if the bottom edge of the collimator is not visible, Collimator Lower Horizontal Edge (0018,1708) value shall be 1 greater than the value of the Rows (0028,0010) attribute. + +
+
+ + Required if Collimator Shape (0018,1700) is RECTANGULAR. Location of the upper edge of the rectangular collimator expressed as effective pixel row. See C.8.7.3.1.1 and C.8.19.6.12.1. +
These attributes specify the pixel row or column where the X-Ray beam is fully obscured by a rectangular collimator: +- if the left edge of the collimator is not visible, Collimator Left Vertical Edge (0018,1702) shall have a value of 0; +- if the right edge of the collimator is not visible, Collimator Right Vertical Edge (0018,1704) value shall be 1 greater than the value of the Columns (0028,0011) attribute; +- if the top edge of the collimator is not visible, Collimator Upper Horizontal Edge (0018,1706) shall have a value of 0; +- if the bottom edge of the collimator is not visible, Collimator Lower Horizontal Edge (0018,1708) value shall be 1 greater than the value of the Rows (0028,0010) attribute. + +
+
+ + Required if Collimator Shape (0018,1700) is RECTANGULAR. Location of the lower edge of the rectangular collimator expressed as effective pixel row. See C.8.7.3.1.1 and C.8.19.6.12.1. +
These attributes specify the pixel row or column where the X-Ray beam is fully obscured by a rectangular collimator: +- if the left edge of the collimator is not visible, Collimator Left Vertical Edge (0018,1702) shall have a value of 0; +- if the right edge of the collimator is not visible, Collimator Right Vertical Edge (0018,1704) value shall be 1 greater than the value of the Columns (0028,0011) attribute; +- if the top edge of the collimator is not visible, Collimator Upper Horizontal Edge (0018,1706) shall have a value of 0; +- if the bottom edge of the collimator is not visible, Collimator Lower Horizontal Edge (0018,1708) value shall be 1 greater than the value of the Rows (0028,0010) attribute. + +
+
+ + Required if Collimator Shape (0018,1700) is CIRCULAR. Location of the center of the circular collimator expressed as effective pixel row and column. See C.8.7.3.1.1 and C.8.19.6.12.1. +
These attributes specify the pixel row or column where the X-Ray beam is fully obscured by a rectangular collimator: +- if the left edge of the collimator is not visible, Collimator Left Vertical Edge (0018,1702) shall have a value of 0; +- if the right edge of the collimator is not visible, Collimator Right Vertical Edge (0018,1704) value shall be 1 greater than the value of the Columns (0028,0011) attribute; +- if the top edge of the collimator is not visible, Collimator Upper Horizontal Edge (0018,1706) shall have a value of 0; +- if the bottom edge of the collimator is not visible, Collimator Lower Horizontal Edge (0018,1708) value shall be 1 greater than the value of the Rows (0028,0010) attribute. + +
+
+ + Required if Collimator Shape (0018,1700) is CIRCULAR. Radius of the circular collimator expressed as effective number of pixels along the row direction. See C.8.7.3.1.1 and C.8.19.6.12.1. +
These attributes specify the pixel row or column where the X-Ray beam is fully obscured by a rectangular collimator: +- if the left edge of the collimator is not visible, Collimator Left Vertical Edge (0018,1702) shall have a value of 0; +- if the right edge of the collimator is not visible, Collimator Right Vertical Edge (0018,1704) value shall be 1 greater than the value of the Columns (0028,0011) attribute; +- if the top edge of the collimator is not visible, Collimator Upper Horizontal Edge (0018,1706) shall have a value of 0; +- if the bottom edge of the collimator is not visible, Collimator Lower Horizontal Edge (0018,1708) value shall be 1 greater than the value of the Rows (0028,0010) attribute. + +
+
+ + Required if Collimator Shape (0018,1700) is POLYGONAL. +Multiple Values where the first set of two values are: +row of the origin vertex; +column of the origin vertex. +Two or more pairs of values follow and are the effective pixel row and column coordinates of the other vertices of the polygon collimator. Polygon collimators are implicitly closed from the last vertex to the origin vertex and all edges shall be non-intersecting except at the vertices. See C.8.19.6.12.1. +
The top left pixel of the image has a pixel row and column value of 1. +
+
+
+ + + A sequence that describes the Isocenter Reference Coordinate System (O, X, Y, Z). +Only a single Item shall be permitted in this sequence. + + + Position of the X-Ray center beam in the isocenter reference system in the X direction (deg). +See C.8.19.6.13.1.2 for further explanation. +
The positioner coordinate system (Op, Xp, Yp, Zp) is defined as follows: +
+
+ + Position of the X-Ray center beam in the isocenter reference system in the Z direction (deg). +See C.8.19.6.13.1.2 for further explanation. +
The positioner coordinate system (Op, Xp, Yp, Zp) is defined as follows: +
+
+ + Rotation of the X-Ray detector plane (deg). +See C.8.19.6.13.1.2 for further explanation. +
The positioner coordinate system (Op, Xp, Yp, Zp) is defined as follows: +
+
+ + X position of the Table Reference Point with respect to the Isocenter (mm). +See C.8.19.6.13.1.3 for further explanation. +
The table coordinate system (Ot, Xt, Yt, Zt) is defined as follows: +
+
+ + Y position of the Table Reference Point with respect to the Isocenter (mm). +See C.8.19.6.13.1.3 for further explanation. +
The table coordinate system (Ot, Xt, Yt, Zt) is defined as follows: +
+
+ + Z position of the Table Reference Point with respect to the Isocenter (mm). +See C.8.19.6.13.1.3 for further explanation. +
The table coordinate system (Ot, Xt, Yt, Zt) is defined as follows: +
+
+ + Rotation of the table in the horizontal plane. +See C.8.19.6.13.1.3 for further explanation. +
The table coordinate system (Ot, Xt, Yt, Zt) is defined as follows: +
+
+ + Angle of the head-feet axis of the table in degrees relative to the horizontal plane. +See C.8.19.6.13.1.3 for further explanation. +
The table coordinate system (Ot, Xt, Yt, Zt) is defined as follows: +
+
+ + Angle of the left-right axis of the table in degrees relative to the horizontal plane. +See C.8.19.6.13.1.3 for further explanation. +
The table coordinate system (Ot, Xt, Yt, Zt) is defined as follows: +
+
+
+ + + Sequence containing the geometric properties for this frame. +Only a single Item shall be permitted in this sequence. + + + Distance from source to isocenter in mm. + + + Distance from source to receptor plane perpendicular to the receptor plane in mm. +Note: This value is traditionally referred to as Source Image Receptor Distance (SID). + + + + + Describes the preferred playback sequencing for a multi-frame image. +Enumerated Values: +0 = Looping (1,2...n,1,2,...n,1,2,....n,...) +1 = Sweeping (1,2,...n,n -1,...2,1,2,...n,...) + + + Sequence that specifies the display frame rate of a selected set of frames. The Items are ordered in increasing frame number. The range of the frames may not overlap and the ranges shall be adjacent. +One or more items may be included. + + + The Frame Number of the first frame of the set of frames to be displayed in this Item. + + + The Frame Number of the last frame of the set of frames to be displayed in this Item. + + + A flag indicating that the range of frames in this item may be skipped. +Defined Terms: +DISPLAY +SKIP + + + Recommended rate at which the frames of this Item should be displayed in frames/second. + + + Specifies the recommended viewing protocol(s). +Defined terms: +SUB = subtraction with mask images +NAT = native viewing of image as stored +Note: If an implementation does not recognize the defined term for Recommended Viewing Mode (0028,1090), reverting to native display mode is recommended. + + + Edge enhancement filter percentage that is recommended by the pixel data creator as filter presetting for display purposes. The value of 100% corresponds to the maximum filter strength that can be applied by a specific application displaying the image. + + + + + Modality Type +Enumerated Value: +SEG + + + A number that identifies this Series + + + Uniquely identifies the Performed Procedure Step SOP Instance to which the Series is related (e.g. a Modality or General-Purpose Performed Procedure Step SOP). Only a single Item is permitted in this sequence. +Required if the SOP Instance was created in a workflow managed with the Modality Performed Procedure Step SOP Class or General Purpose Performed Procedure Step SOP Class. + + + + + + Value 1 shall be DERIVED. Value 2 shall be PRIMARY. No other values shall be present. + + + + Enumerated Values: +1 + + + Enumerated Values: +MONOCHROME2 + + + Enumerated Values: +0 + + + If Segmentation Type (0062,0001) is BINARY, shall be 1. Otherwise it shall be 8. See Section C.8.20.2.1. +
As a consequence of the enumerated Bits Allocated and Bits Stored attribute values, single bit pixels shall be packed 8 to a byte as defined by the encoding rules in PS 3.5. +
+
+ + If Segmentation Type (0062,0001) is BINARY, shall be 1. Otherwise it shall be 8. See Section C.8.20.2.1. +
As a consequence of the enumerated Bits Allocated and Bits Stored attribute values, single bit pixels shall be packed 8 to a byte as defined by the encoding rules in PS 3.5. +
+
+ + If Segmentation Type (0062,0001) is BINARY, shall be 0. Otherwise it shall be 7. See Section C.8.20.2.1. +
As a consequence of the enumerated Bits Allocated and Bits Stored attribute values, single bit pixels shall be packed 8 to a byte as defined by the encoding rules in PS 3.5. +
+
+ + Specifies whether an Image has undergone lossy compression. +Enumerated Values: +00 = Image has NOT been subjected to lossy compression. +01 = Image has been subjected to lossy compression. +See Section C.8.20.2.2 +
If Lossy Image Compression (0028,2110) in any of the source images is “01â€, the value shall be “01†for the Segmentation instance. +The process of segmentation itself is defined not to be lossy compression, even though it involves loss. If the Segmentation instance is encoded using a lossy compression transfer syntax, then the value shall be set to “01â€. +Notes: It is not advisable to lossy compress a Segmentation SOP Instance. In particular, a binary segmentation should not be lossy compressed. + +
+
+ + Describes the approximate lossy compression ratio(s) that have been applied to this image. +See C.7.6.1.1.5 for further explanation. May be multivalued if successive lossy compression steps have been applied. +Notes: 1. For example, a compression ratio of 30:1 would be described in this Attribute with a single value of 30. +2. For historical reasons, the lossy compression ratio may also be described in Derivation Description (0008,2111). +Required if present in the source images or this IOD instance has been compressed. +
The Attribute Lossy Image Compression (0028,2110) conveys that the Image has undergone lossy compression. It provides a means to record that the Image has been compressed (at a point in its lifetime) with a lossy algorithm and changes have been introduced into the pixel data. Once the value has been set to “01â€, it shall not be reset. +Note: If an image is compressed with a lossy algorithm, the attribute Lossy Image Compression (0028,2110) is set to “01â€. Subsequently, if the image is decompressed and transferred in uncompressed format, this attribute value remains “01â€. + +The value of the Lossy Image Compression (0028,2110) Attribute in SOP Instances containing multiple frames in which one or more of the frames have undergone lossy compression shall be “01â€. +Note: It is recommended that the applicable frames be noted in the Attribute Derivation Description (0008,2111). + +If an image is originally obtained as a lossy compressed image from the sensor, then Lossy Image Compression (0028,2110) is set to “01†and Value 1 of the Attribute Image Type (0008,0008) shall be set to ORIGINAL. +If an image is a compressed version of another image, Lossy Image Compression (0028,2110) is set to “01â€, Value 1 of the Attribute Image Type (0008,0008) shall be set to DERIVED, and if the predecessor was a DICOM image, then the Image shall receive a new SOP Instance UID. +Note: 1. It is recommended that the approximate compression ratio be provided in the Attribute Derivation Description (0008,2111). Furthermore, it is recommended that Derivation Description (0008,2111) be used to indicate when pixel data changes might affect professional interpretation. (see C.7.6.1.1.3). + 2. The attribute Lossy Image Compression (0028,2110) is defined as Type 3 for backward compatibility with existing IODs. It is expected to be required (i.e., defined as Type 1C) for new Image IODs and for existing IODs that undergo a major revision (e.g. a new IOD is specified). +The Defined Terms for Lossy Image Compression Method (0028,2114) are: +ISO_10918_1 = JPEG Lossy Compression +ISO_14495_1 = JPEG-LS Near-lossless Compression +ISO_15444_1 = JPEG 2000 Irreversible Compression +ISO_13818_2 = MPEG2 Compression + +
+
+ + A label for the lossy compression method(s) that have been applied to this image. +See C.7.6.1.1.5 for further explanation. May be multivalued if successive lossy compression steps have been applied; the value order shall correspond to the values of Lossy Image Compression Ratio (0028,2112). +Note: For historical reasons, the lossy compression method may also be described in Derivation Description (0008,2111). +Required if present in the source images or this IOD instance has been compressed. See section C.8.20.2.2. +
The Attribute Lossy Image Compression (0028,2110) conveys that the Image has undergone lossy compression. It provides a means to record that the Image has been compressed (at a point in its lifetime) with a lossy algorithm and changes have been introduced into the pixel data. Once the value has been set to “01â€, it shall not be reset. +Note: If an image is compressed with a lossy algorithm, the attribute Lossy Image Compression (0028,2110) is set to “01â€. Subsequently, if the image is decompressed and transferred in uncompressed format, this attribute value remains “01â€. + +The value of the Lossy Image Compression (0028,2110) Attribute in SOP Instances containing multiple frames in which one or more of the frames have undergone lossy compression shall be “01â€. +Note: It is recommended that the applicable frames be noted in the Attribute Derivation Description (0008,2111). + +If an image is originally obtained as a lossy compressed image from the sensor, then Lossy Image Compression (0028,2110) is set to “01†and Value 1 of the Attribute Image Type (0008,0008) shall be set to ORIGINAL. +If an image is a compressed version of another image, Lossy Image Compression (0028,2110) is set to “01â€, Value 1 of the Attribute Image Type (0008,0008) shall be set to DERIVED, and if the predecessor was a DICOM image, then the Image shall receive a new SOP Instance UID. +Note: 1. It is recommended that the approximate compression ratio be provided in the Attribute Derivation Description (0008,2111). Furthermore, it is recommended that Derivation Description (0008,2111) be used to indicate when pixel data changes might affect professional interpretation. (see C.7.6.1.1.3). + 2. The attribute Lossy Image Compression (0028,2110) is defined as Type 3 for backward compatibility with existing IODs. It is expected to be required (i.e., defined as Type 1C) for new Image IODs and for existing IODs that undergo a major revision (e.g. a new IOD is specified). +The Defined Terms for Lossy Image Compression Method (0028,2114) are: +ISO_10918_1 = JPEG Lossy Compression +ISO_14495_1 = JPEG-LS Near-lossless Compression +ISO_15444_1 = JPEG 2000 Irreversible Compression +ISO_13818_2 = MPEG2 Compression + +
+
+ + The type of encoding used to indicate the presence of the segmented property at a pixel/voxel location. +Enumerated Values are: +BINARY +FRACTIONAL +See section C.8.20.2.3. + + + For fractional segmentation encoding, the meaning of the fractional value. +Enumerated Values are: +PROBABILITY +OCCUPANCY +Required if Segmentation Type (0062,0001) is FRACTIONAL. See section C.8.20.2.3. + + + Specifies the value that represents 100%. There shall be no values in Pixel Data (7FE0,0010) greater than this value. Required if Segmentation Type (0062,0001) is FRACTIONAL. + + + Describes the segments that are contained within the data. One or more items shall be present. + + + Identification number of the segment. The value of Segment Number (0062,0004) shall be unique within the Segmentation instance in which it is created. See C.8.20.2.4. +
Segment Number (0062,0004) shall be unique within each instance, start at a value of 1, and increase monotonically by 1. +
+
+ + User-defined label identifying this segment. This may be the same as the Code Meaning (0008,0104) of the Segmented Property Type Code Sequence (0062,000F). + + + User-defined description for this segment. + + + Type of algorithm used to generate the segment. Enumerated Values are: +AUTOMATIC: calculated segment +SEMIAUTOMATIC: calculated segment with user assistance +MANUAL: user-entered segment + + + Name of algorithm used to generate the segment. Required if Segment Algorithm Type (0062,0008) is not MANUAL. + + + + Sequence defining the general category of this segment. This sequence shall contain a single item. + + + + Sequence defining the specific property type of this segment. This sequence shall contain a single item. + + + + A default single gray unsigned value in which it is recommended that the maximum pixel value in this segment be rendered on a monochrome display. The units are specified in P-Values from a minimum of 0000H (black) up to a maximum of FFFFH (white). +Note: The maximum P-Value for this Attribute may be different from the maximum P-Value from the output of the Presentation LUT, which may be less than 16 bits in depth. + + + A default triplet value in which it is recommended that segment be rendered on a color display. The units are specified in PCS-Values, and the value is encoded as CIELab. See C.10.7.1.1. +
Attributes such as Graphic Layer Recommended Display CIELab Value (0070,0401) consist of three unsigned short values: +
+
+
+ + + Identifies the characteristics of this frame. Only a single Item shall be permitted in this sequence. + + + Uniquely identifies the segment described in the Segment Sequence (0062,0002) by reference to the Segment Number (0062,0004). Referenced Segment Number (0062,000B) shall not be multi-valued. + + + + + Image identification characteristics. +See C.8.21.1.1.1 for specialization. +
In addition to the requirements specified in C.8.16.1 Image Type, the following additional requirements and Defined Terms are specified. +
+
+ + + Number of bits allocated for each voxel sample. Each sample shall have the same number of bits allocated. Enumerated Values: 8 and 16. + + + Number of bits stored for each voxel sample. Each sample shall have the same number of bits stored. Enumerated Values: 8 to16. + + + Most significant bit for pixel sample data. Each sample shall have the same high bit. Shall be one less than the value in Bits Stored (0028,0101). + + + Number of samples (color planes) in this image shall have a value of 1. + + + Specifies the intended interpretation of the voxel data. +Enumerated Values: +MONOCHROME2 + + + Content Qualification Indicator +Enumerated Values: +PRODUCT +RESEARCH +SERVICE +See C.8.13.2.1.1 for further explanation. +
Content Qualification (0018,9004) shall have the value PRODUCT if the content (image or Spectroscopy data) was produced with approved hardware and software. It shall have the value RESEARCH or SERVICE if there is any doubt as to whether the content was produced with approved hardware and software. +If data with Content Qualification (0018,9004) of RESEARCH or SERVICE is used to derive other content then it is expected that this derived content will also have Content Qualification (0018,9004) set to RESEARCH or SERVICE. +The intent of this element is to allow annotation of an advisory message that indicates that this content may not be suitable for clinical interpretation. +
+
+ + Indicates whether or not the image contains sufficient burned in annotation to identify the patient and date the image was acquired. +Enumerated Values: +NO + + + Specifies whether an Image has undergone lossy compression. Enumerated Values: +00 = Image has NOT been subjected to lossy compression. +01 = Image has been subjected to lossy compression. +See C.7.6.1.1.5 for further explanation. +
The Attribute Lossy Image Compression (0028,2110) conveys that the Image has undergone lossy compression. It provides a means to record that the Image has been compressed (at a point in its lifetime) with a lossy algorithm and changes have been introduced into the pixel data. Once the value has been set to “01â€, it shall not be reset. +Note: If an image is compressed with a lossy algorithm, the attribute Lossy Image Compression (0028,2110) is set to “01â€. Subsequently, if the image is decompressed and transferred in uncompressed format, this attribute value remains “01â€. + +The value of the Lossy Image Compression (0028,2110) Attribute in SOP Instances containing multiple frames in which one or more of the frames have undergone lossy compression shall be “01â€. +Note: It is recommended that the applicable frames be noted in the Attribute Derivation Description (0008,2111). + +If an image is originally obtained as a lossy compressed image from the sensor, then Lossy Image Compression (0028,2110) is set to “01†and Value 1 of the Attribute Image Type (0008,0008) shall be set to ORIGINAL. +If an image is a compressed version of another image, Lossy Image Compression (0028,2110) is set to “01â€, Value 1 of the Attribute Image Type (0008,0008) shall be set to DERIVED, and if the predecessor was a DICOM image, then the Image shall receive a new SOP Instance UID. +Note: 1. It is recommended that the approximate compression ratio be provided in the Attribute Derivation Description (0008,2111). Furthermore, it is recommended that Derivation Description (0008,2111) be used to indicate when pixel data changes might affect professional interpretation. (see C.7.6.1.1.3). + 2. The attribute Lossy Image Compression (0028,2110) is defined as Type 3 for backward compatibility with existing IODs. It is expected to be required (i.e., defined as Type 1C) for new Image IODs and for existing IODs that undergo a major revision (e.g. a new IOD is specified). +The Defined Terms for Lossy Image Compression Method (0028,2114) are: +ISO_10918_1 = JPEG Lossy Compression +ISO_14495_1 = JPEG-LS Near-lossless Compression +ISO_15444_1 = JPEG 2000 Irreversible Compression +ISO_13818_2 = MPEG2 Compression + +
+
+ + See C.7.6.1.1.5 for further explanation. +Required if Lossy Image Compression (0028,2110) equals 01. +
The Attribute Lossy Image Compression (0028,2110) conveys that the Image has undergone lossy compression. It provides a means to record that the Image has been compressed (at a point in its lifetime) with a lossy algorithm and changes have been introduced into the pixel data. Once the value has been set to “01â€, it shall not be reset. +Note: If an image is compressed with a lossy algorithm, the attribute Lossy Image Compression (0028,2110) is set to “01â€. Subsequently, if the image is decompressed and transferred in uncompressed format, this attribute value remains “01â€. + +The value of the Lossy Image Compression (0028,2110) Attribute in SOP Instances containing multiple frames in which one or more of the frames have undergone lossy compression shall be “01â€. +Note: It is recommended that the applicable frames be noted in the Attribute Derivation Description (0008,2111). + +If an image is originally obtained as a lossy compressed image from the sensor, then Lossy Image Compression (0028,2110) is set to “01†and Value 1 of the Attribute Image Type (0008,0008) shall be set to ORIGINAL. +If an image is a compressed version of another image, Lossy Image Compression (0028,2110) is set to “01â€, Value 1 of the Attribute Image Type (0008,0008) shall be set to DERIVED, and if the predecessor was a DICOM image, then the Image shall receive a new SOP Instance UID. +Note: 1. It is recommended that the approximate compression ratio be provided in the Attribute Derivation Description (0008,2111). Furthermore, it is recommended that Derivation Description (0008,2111) be used to indicate when pixel data changes might affect professional interpretation. (see C.7.6.1.1.3). + 2. The attribute Lossy Image Compression (0028,2110) is defined as Type 3 for backward compatibility with existing IODs. It is expected to be required (i.e., defined as Type 1C) for new Image IODs and for existing IODs that undergo a major revision (e.g. a new IOD is specified). +The Defined Terms for Lossy Image Compression Method (0028,2114) are: +ISO_10918_1 = JPEG Lossy Compression +ISO_14495_1 = JPEG-LS Near-lossless Compression +ISO_15444_1 = JPEG 2000 Irreversible Compression +ISO_13818_2 = MPEG2 Compression + +
+
+ + A label for the lossy compression method(s) that have been applied to this image. +See C.7.6.1.1.5 for further explanation. +May be multi-valued if successive lossy compression steps have been applied; the value order shall correspond to the values of Lossy Image Compression Ratio (0028,2112). +Note: For historical reasons, the lossy compression method may also be described in Derivation Description (0008,2111). +Required if Lossy Image Compression (0028,2110) equals 01. +
The Attribute Lossy Image Compression (0028,2110) conveys that the Image has undergone lossy compression. It provides a means to record that the Image has been compressed (at a point in its lifetime) with a lossy algorithm and changes have been introduced into the pixel data. Once the value has been set to “01â€, it shall not be reset. +Note: If an image is compressed with a lossy algorithm, the attribute Lossy Image Compression (0028,2110) is set to “01â€. Subsequently, if the image is decompressed and transferred in uncompressed format, this attribute value remains “01â€. + +The value of the Lossy Image Compression (0028,2110) Attribute in SOP Instances containing multiple frames in which one or more of the frames have undergone lossy compression shall be “01â€. +Note: It is recommended that the applicable frames be noted in the Attribute Derivation Description (0008,2111). + +If an image is originally obtained as a lossy compressed image from the sensor, then Lossy Image Compression (0028,2110) is set to “01†and Value 1 of the Attribute Image Type (0008,0008) shall be set to ORIGINAL. +If an image is a compressed version of another image, Lossy Image Compression (0028,2110) is set to “01â€, Value 1 of the Attribute Image Type (0008,0008) shall be set to DERIVED, and if the predecessor was a DICOM image, then the Image shall receive a new SOP Instance UID. +Note: 1. It is recommended that the approximate compression ratio be provided in the Attribute Derivation Description (0008,2111). Furthermore, it is recommended that Derivation Description (0008,2111) be used to indicate when pixel data changes might affect professional interpretation. (see C.7.6.1.1.3). + 2. The attribute Lossy Image Compression (0028,2110) is defined as Type 3 for backward compatibility with existing IODs. It is expected to be required (i.e., defined as Type 1C) for new Image IODs and for existing IODs that undergo a major revision (e.g. a new IOD is specified). +The Defined Terms for Lossy Image Compression Method (0028,2114) are: +ISO_10918_1 = JPEG Lossy Compression +ISO_14495_1 = JPEG-LS Near-lossless Compression +ISO_15444_1 = JPEG 2000 Irreversible Compression +ISO_13818_2 = MPEG2 Compression + +
+
+ + Full set of Composite SOP Instances referred to inside the Referenced Image Sequences of this SOP Instance. See C.8.13.2.1.2 for further explanation. +One or more Items may be permitted in this sequence. +Required if the Referenced Image Sequence (0008,1140) is present. +
The intent of the Referenced Image Evidence Sequence (0008,9092) and Source Image Evidence Sequence (0008,9154) is to provide a list of all unique SOP Instances listed in the Referenced Image Sequence (0008,1140) and Source Image Sequence (0008,2112) attributes respectively. +
+
+ + + User-defined comments about the image. + + + Indicates whether or not this image is a quality control or phantom image. +Enumerated Values: +YES +NO +If this Attribute is absent, then the image may or may not be a quality control or phantom image. + + + This icon image is representative of the Image. + + + + Specifies a predefined identity transformation for the Presentation LUT such that the output of all grayscale transformations, if any, are defined to be in P-Values. +Enumerated Values: +IDENTITY = output is in P-Values + +
+ + + A sequence that describes characteristics of the sources that are used to create a derived SOP Instance. +One or more Items may be present. + + + + + Indicates any visual processing performed on the frame prior to exchange. +See Section C.8.7.1.1.3. +Required if present and consistent in the contributing SOP Instances. +
Acquisition Device Processing Description (0018,1400) provides some indication in human readable text of the digital processing on the images before exchange. Examples of this processing are: edge enhanced, subtracted, time filtered, gamma corrected, convolved (spatially filtered). +
+
+ + Code representing the device-specific processing associated with the frame (e.g. Organ Filtering code) +Required if present and have an equal value in the contributing SOP Instances. + + + Identification of the plane used to acquire this image. +Defined Terms: +MONOPLANE +PLANE A +PLANE B +Required if present and consistent in the contributing SOP Instances. + + + Physical distance measured at the receptor plane of the detector between the centers of each pixel specified by a numeric pair - row spacing value (delimiter) column spacing value in mm. +Required if present and consistent in the contributing SOP Instances. + +
+ + + A sequence that describes characteristics of the sources that are used to create a derived SOP Instance. +One or more Items may be present. + + + + + Indicates any visual processing performed on the frame prior to exchange. +See Section C.8.7.1.1.3. +Required if present and consistent in the contributing SOP Instances. +
Acquisition Device Processing Description (0018,1400) provides some indication in human readable text of the digital processing on the images before exchange. Examples of this processing are: edge enhanced, subtracted, time filtered, gamma corrected, convolved (spatially filtered). +
+
+ + Code representing the device-specific processing associated with the frame (e.g. Organ Filtering code). +Required if present and have an equal value in the contributing SOP Instances. + + + Physical distance measured at the receptor plane of the detector between the centers of each pixel specified by a numeric pair - row spacing value (delimiter) column spacing value in mm. +Required if present and consistent in the contributing SOP Instances. + +
+ + + A Sequence that identifies the set of Images that constitute this acquisition context. +Required if the reconstruction is created from DICOM SOP Instances. +Note: The attribute is absent in the case where the images used to create the volume are not available as SOP Instances, e.g., the volume was directly generated by acquisition system. +One or more Items may be included in this Sequence. + + + + Shape of the Field of View in the referenced images. +Enumerated Values: +RECTANGLE +ROUND +HEXAGONAL +Required if present and consistent in the contributing SOP Instances. + + + Dimensions in mm of the Field of View in the referenced images. If Field of View Shape (0018,1147) is: +RECTANGLE: row dimension followed by column. +ROUND: diameter. +HEXAGONAL: diameter of the circle circumscribing the hexagon. +Required if present and consistent in the contributing SOP Instances. + + + Offset of the TLHC of a rectangle circumscribing the Field of View in the referenced images, before rotation or flipping, from the TLHC of the physical detector area measured in physical detector pixels as a row offset followed by a column offset. +See C.8.11.4.1.1 for further explanation. +Required if X-Ray Receptor Type (0018,9420) is present and equals DIGITAL_DETECTOR. +
The relationship between the Physical Detector Area, the Active Detector Area, the Field of View (what is stored in the Pixel Data (7FE0,0010)), the Exposed Area (after X-Ray Collimation) and the Displayed Area is illustrated in the following diagrams. +Note: Some of these Attributes relate the image data to manufacturer specific characteristics of the detector that may be used for quality control purposes, e.g. correlation of image artifacts with a detector defect map, analysis of noise performance, etc. + +The Displayed Area is defined in pixel coordinates relative to the stored image pixel values by the Attributes of the Display Shutter Module (see section C.7.6.11). If this Module is not present or supported, then the Displayed Area is equal to the Field of View. +The Exposed Area is defined in pixel coordinates relative to the stored image pixel values by the Attributes of the X-Ray Collimator Module (see section C.8.7.3). +For the Digital X-Ray IODs, the Field of View is usually rectangular in shape and the same size as the stored Pixel Data (7FE0,0010). The shape and size of the Field of View and the spacing of the pixels are defined by the following Attributes: +- Field of View Shape (0018,1147), +- Field of View Dimensions (0018,1149), +- Imager Pixel Spacing (0018,1164), +- Rows (0028,0010), +- Columns (0028,0011) + +The following Attributes define the relationship of the Field of View to the Physical Detector Area: +- Field of View Origin (0018,7030), +- Field of View Rotation (0018,7032), +- Field of View Horizontal Flip (0018,7034). + +For the Digital X-Ray IODs, the Active Area, i.e. that part of the detector matrix that was activated for this exposure, is usually rectangular in shape. The shape and size of the Active Area and the size and spacing of the detectors are defined by the following Attributes: +- Detector Active Shape (0018,7024), +- Detector Active Dimensions (0018,7026), +- Detector Element Physical Size (0018,7020), +- Detector Element Spacing (0018,7022). + +Notes: 1. The Detector Element Physical Size (0018,7020) and Detector Element Spacing (0018,7022) may be different if there are insensitive regions between each detector. + 2. This model of description is not able to accurately describe multiple matrices of detectors that are “tiled†to produce a single image. + +The following optional Attribute defines the relationship of the Active Area to the Physical Detector Area: +- Detector Active Origin (0018,7028). + +The relationship between detectors and stored image pixels is defined by Detector Binning (0018,701A) which specifies how many detectors, in each of the row and column directions, contribute to (are pooled or averaged to form) a single stored image pixel. +Note: Detector Binning (0018,701A) may have values less than one if sub-sampling is used to derive an image with higher spatial resolution than the detector matrix. + + + +Figure C.8-14 +Explanation of DX Detector Attributes + + + + +Figure C.8-15 +Explanation of DX Detector Attributes +
+
+ + Clockwise rotation in degrees of Field of View in the referenced images, relative to the physical detector. +Enumerated Values: +0, 90, 180, 270 +See C.8.11.4.1.1 for further explanation. +Required if present and consistent in the contributing SOP Instances. +
The relationship between the Physical Detector Area, the Active Detector Area, the Field of View (what is stored in the Pixel Data (7FE0,0010)), the Exposed Area (after X-Ray Collimation) and the Displayed Area is illustrated in the following diagrams. +Note: Some of these Attributes relate the image data to manufacturer specific characteristics of the detector that may be used for quality control purposes, e.g. correlation of image artifacts with a detector defect map, analysis of noise performance, etc. + +The Displayed Area is defined in pixel coordinates relative to the stored image pixel values by the Attributes of the Display Shutter Module (see section C.7.6.11). If this Module is not present or supported, then the Displayed Area is equal to the Field of View. +The Exposed Area is defined in pixel coordinates relative to the stored image pixel values by the Attributes of the X-Ray Collimator Module (see section C.8.7.3). +For the Digital X-Ray IODs, the Field of View is usually rectangular in shape and the same size as the stored Pixel Data (7FE0,0010). The shape and size of the Field of View and the spacing of the pixels are defined by the following Attributes: +- Field of View Shape (0018,1147), +- Field of View Dimensions (0018,1149), +- Imager Pixel Spacing (0018,1164), +- Rows (0028,0010), +- Columns (0028,0011) + +The following Attributes define the relationship of the Field of View to the Physical Detector Area: +- Field of View Origin (0018,7030), +- Field of View Rotation (0018,7032), +- Field of View Horizontal Flip (0018,7034). + +For the Digital X-Ray IODs, the Active Area, i.e. that part of the detector matrix that was activated for this exposure, is usually rectangular in shape. The shape and size of the Active Area and the size and spacing of the detectors are defined by the following Attributes: +- Detector Active Shape (0018,7024), +- Detector Active Dimensions (0018,7026), +- Detector Element Physical Size (0018,7020), +- Detector Element Spacing (0018,7022). + +Notes: 1. The Detector Element Physical Size (0018,7020) and Detector Element Spacing (0018,7022) may be different if there are insensitive regions between each detector. + 2. This model of description is not able to accurately describe multiple matrices of detectors that are “tiled†to produce a single image. + +The following optional Attribute defines the relationship of the Active Area to the Physical Detector Area: +- Detector Active Origin (0018,7028). + +The relationship between detectors and stored image pixels is defined by Detector Binning (0018,701A) which specifies how many detectors, in each of the row and column directions, contribute to (are pooled or averaged to form) a single stored image pixel. +Note: Detector Binning (0018,701A) may have values less than one if sub-sampling is used to derive an image with higher spatial resolution than the detector matrix. + + + +Figure C.8-14 +Explanation of DX Detector Attributes + + + + +Figure C.8-15 +Explanation of DX Detector Attributes +
+
+ + Whether or not a horizontal flip has been applied to the Field of View in the referenced images, after rotation relative to the physical detector as described in Field of View Rotation (0018,7032). +Enumerated Values: +NO +YES +See C.8.11.4.1.1 for further explanation. +Required if present and consistent in the contributing SOP Instances. +
The relationship between the Physical Detector Area, the Active Detector Area, the Field of View (what is stored in the Pixel Data (7FE0,0010)), the Exposed Area (after X-Ray Collimation) and the Displayed Area is illustrated in the following diagrams. +Note: Some of these Attributes relate the image data to manufacturer specific characteristics of the detector that may be used for quality control purposes, e.g. correlation of image artifacts with a detector defect map, analysis of noise performance, etc. + +The Displayed Area is defined in pixel coordinates relative to the stored image pixel values by the Attributes of the Display Shutter Module (see section C.7.6.11). If this Module is not present or supported, then the Displayed Area is equal to the Field of View. +The Exposed Area is defined in pixel coordinates relative to the stored image pixel values by the Attributes of the X-Ray Collimator Module (see section C.8.7.3). +For the Digital X-Ray IODs, the Field of View is usually rectangular in shape and the same size as the stored Pixel Data (7FE0,0010). The shape and size of the Field of View and the spacing of the pixels are defined by the following Attributes: +- Field of View Shape (0018,1147), +- Field of View Dimensions (0018,1149), +- Imager Pixel Spacing (0018,1164), +- Rows (0028,0010), +- Columns (0028,0011) + +The following Attributes define the relationship of the Field of View to the Physical Detector Area: +- Field of View Origin (0018,7030), +- Field of View Rotation (0018,7032), +- Field of View Horizontal Flip (0018,7034). + +For the Digital X-Ray IODs, the Active Area, i.e. that part of the detector matrix that was activated for this exposure, is usually rectangular in shape. The shape and size of the Active Area and the size and spacing of the detectors are defined by the following Attributes: +- Detector Active Shape (0018,7024), +- Detector Active Dimensions (0018,7026), +- Detector Element Physical Size (0018,7020), +- Detector Element Spacing (0018,7022). + +Notes: 1. The Detector Element Physical Size (0018,7020) and Detector Element Spacing (0018,7022) may be different if there are insensitive regions between each detector. + 2. This model of description is not able to accurately describe multiple matrices of detectors that are “tiled†to produce a single image. + +The following optional Attribute defines the relationship of the Active Area to the Physical Detector Area: +- Detector Active Origin (0018,7028). + +The relationship between detectors and stored image pixels is defined by Detector Binning (0018,701A) which specifies how many detectors, in each of the row and column directions, contribute to (are pooled or averaged to form) a single stored image pixel. +Note: Detector Binning (0018,701A) may have values less than one if sub-sampling is used to derive an image with higher spatial resolution than the detector matrix. + + + +Figure C.8-14 +Explanation of DX Detector Attributes + + + + +Figure C.8-15 +Explanation of DX Detector Attributes +
+
+ + Identifies the grid. May be multi-valued. +Defined Terms are: +FIXED +FOCUSED +RECIPROCATING +PARALLEL +CROSSED +NONE +Required if present and consistent in the contributing SOP Instances. + + + Identifies the type of X-Ray receptor used. +Enumerated Values: +IMG_INTENSIFIER +DIGITAL_DETECTOR +Required if present and consistent in the contributing SOP Instances. + + + Average of the peak kilo voltage outputs of the X-Ray generator used for all frames. +Required if present and consistent in the contributing SOP Instances. + + + Average of the nominal X-Ray tube currents in milliamperes for all frames. +Required if present and consistent in the contributing SOP Instances. + + + Duration of X-Ray exposure in milliseconds. See C.8.7.2.1.1. +Required if present and consistent in the contributing SOP Instances. +
Exposure time is the cumulative time the patient received X-Ray exposure during this image (Multi-frame image acquisition). Calculation is pulse width * number of frames. +
+
+ + The exposure expressed in milliampereseconds, for example calculated from Exposure Time and X-Ray Tube Current. +Required if present and consistent in the contributing SOP Instances. + + + Contrast or bolus agent. +Required if present and consistent in the contributing SOP Instances. + + + Sequence that identifies the contrast agent. One or more Items may be present. +Required if present and consistent in the contributing SOP Instances. + + + + Start date and time of that part of an acquisition used for this acquisition context. +Required if present and consistent in the contributing SOP Instances. + + + End date and time of that part of an acquisition used for this acquisition context. +Required if present and consistent in the contributing SOP Instances. + +
+ + + Exact peak kilo voltage output of the X-Ray generator used for this projection. +Required if present and consistent in the contributing SOP Instances. + + + Exact Nominal X-Ray tube current in milliamperes applied during the Frame Acquisition Duration (0018,9220) for this projection. +Required if present and consistent in the contributing SOP Instances. + + + The actual amount of time [in milliseconds] that was used to acquire data for this projection. See C.7.6.16.2.2.1 and C.7.6.16.2.2.3 for further explanation. +Required if present and consistent in the contributing SOP Instances. +
Figure C.7.6.16-2 shows the relationships among the various timing parameters used. +
+
+ + Shape(s) of the collimator. Enumerated Values: +RECTANGULAR +CIRCULAR +POLYGONAL +This multi-valued Attribute shall contain at most one of each Enumerated Value. +Required if present and consistent in the contributing SOP Instances. + + + Required if Collimator Shape (0018,1700) is RECTANGULAR. Location of the left edge of the rectangular collimator with respect to pixels in the image given as column. See C.8.7.3.1.1. +
These attributes specify the pixel row or column where the X-Ray beam is fully obscured by a rectangular collimator: +- if the left edge of the collimator is not visible, Collimator Left Vertical Edge (0018,1702) shall have a value of 0; +- if the right edge of the collimator is not visible, Collimator Right Vertical Edge (0018,1704) value shall be 1 greater than the value of the Columns (0028,0011) attribute; +- if the top edge of the collimator is not visible, Collimator Upper Horizontal Edge (0018,1706) shall have a value of 0; +- if the bottom edge of the collimator is not visible, Collimator Lower Horizontal Edge (0018,1708) value shall be 1 greater than the value of the Rows (0028,0010) attribute. + +
+
+ + Required if Collimator Shape (0018,1700) is RECTANGULAR. Location of the right edge of the rectangular collimator with respect to pixels in the image given as column. See C.8.7.3.1.1. +
These attributes specify the pixel row or column where the X-Ray beam is fully obscured by a rectangular collimator: +- if the left edge of the collimator is not visible, Collimator Left Vertical Edge (0018,1702) shall have a value of 0; +- if the right edge of the collimator is not visible, Collimator Right Vertical Edge (0018,1704) value shall be 1 greater than the value of the Columns (0028,0011) attribute; +- if the top edge of the collimator is not visible, Collimator Upper Horizontal Edge (0018,1706) shall have a value of 0; +- if the bottom edge of the collimator is not visible, Collimator Lower Horizontal Edge (0018,1708) value shall be 1 greater than the value of the Rows (0028,0010) attribute. + +
+
+ + Required if Collimator Shape (0018,1700) is RECTANGULAR. Location of the upper edge of the rectangular collimator with respect to pixels in the image given as row. See C.8.7.3.1.1. +
These attributes specify the pixel row or column where the X-Ray beam is fully obscured by a rectangular collimator: +- if the left edge of the collimator is not visible, Collimator Left Vertical Edge (0018,1702) shall have a value of 0; +- if the right edge of the collimator is not visible, Collimator Right Vertical Edge (0018,1704) value shall be 1 greater than the value of the Columns (0028,0011) attribute; +- if the top edge of the collimator is not visible, Collimator Upper Horizontal Edge (0018,1706) shall have a value of 0; +- if the bottom edge of the collimator is not visible, Collimator Lower Horizontal Edge (0018,1708) value shall be 1 greater than the value of the Rows (0028,0010) attribute. + +
+
+ + Required if Collimator Shape (0018,1700) is RECTANGULAR. Location of the lower edge of the rectangular collimator with respect to pixels in the image given as row. See C.8.7.3.1.1. +
These attributes specify the pixel row or column where the X-Ray beam is fully obscured by a rectangular collimator: +- if the left edge of the collimator is not visible, Collimator Left Vertical Edge (0018,1702) shall have a value of 0; +- if the right edge of the collimator is not visible, Collimator Right Vertical Edge (0018,1704) value shall be 1 greater than the value of the Columns (0028,0011) attribute; +- if the top edge of the collimator is not visible, Collimator Upper Horizontal Edge (0018,1706) shall have a value of 0; +- if the bottom edge of the collimator is not visible, Collimator Lower Horizontal Edge (0018,1708) value shall be 1 greater than the value of the Rows (0028,0010) attribute. + +
+
+ + Required if Collimator Shape (0018,1700) is CIRCULAR. Location of the center of the circular collimator with respect to pixels in the image given as row and column. See C.8.7.3.1.1. +
These attributes specify the pixel row or column where the X-Ray beam is fully obscured by a rectangular collimator: +- if the left edge of the collimator is not visible, Collimator Left Vertical Edge (0018,1702) shall have a value of 0; +- if the right edge of the collimator is not visible, Collimator Right Vertical Edge (0018,1704) value shall be 1 greater than the value of the Columns (0028,0011) attribute; +- if the top edge of the collimator is not visible, Collimator Upper Horizontal Edge (0018,1706) shall have a value of 0; +- if the bottom edge of the collimator is not visible, Collimator Lower Horizontal Edge (0018,1708) value shall be 1 greater than the value of the Rows (0028,0010) attribute. + +
+
+ + Required if Collimator Shape (0018,1700) is CIRCULAR. Radius of the circular collimator with respect to pixels in the image given as a number of pixels along the row direction. See C.8.7.3.1.1. +
These attributes specify the pixel row or column where the X-Ray beam is fully obscured by a rectangular collimator: +- if the left edge of the collimator is not visible, Collimator Left Vertical Edge (0018,1702) shall have a value of 0; +- if the right edge of the collimator is not visible, Collimator Right Vertical Edge (0018,1704) value shall be 1 greater than the value of the Columns (0028,0011) attribute; +- if the top edge of the collimator is not visible, Collimator Upper Horizontal Edge (0018,1706) shall have a value of 0; +- if the bottom edge of the collimator is not visible, Collimator Lower Horizontal Edge (0018,1708) value shall be 1 greater than the value of the Rows (0028,0010) attribute. + +
+
+ + Required if Collimator Shape (0018,1700) is POLYGONAL. +Multiple Values where the first set of two values are: +row of the origin vertex; +column of the origin vertex. +Two or more pairs of values follow and are the row and column coordinates of the other vertices of the polygon collimator. Polygon collimators are implicitly closed from the last vertex to the origin vertex and all edges shall be non-intersecting except at the vertices. + +
+ + + Each item represents an acquisition context related to one or more reconstructions. +The values of the Acquisition Index (0020,9518) attribute may be used as index to Items in this sequence. +One or more Items may be present. + + + + + Dimensions of the physical detector measured in mm as a row size followed by a column size. +Required if present and consistent in the contributing SOP Instances. + + + Position of the Isocenter measured in physical detector elements as a row offset followed by a column offset from the TLHC of a rectangle circumscribing the physical detector area. +Required if Isocenter Reference System Sequence (0018,9462) is present. +Required if present and consistent in the contributing SOP Instances. + + + Distance from source to receptor plane perpendicular to the receptor plane in mm +or distance in mm from source to detector +center on the chest wall line See C.8.11.7.1.1. +Required if present and consistent in the contributing SOP Instances. +Note: This value is traditionally referred to as Source Image Receptor Distance (SID). +
Figure C.8-8 shows the X-Ray beam for a digital mammography system. The X-Ray beam vector is defined from the Focal Spot to the center of the chest wall line of the Image Detection device. + +Figure C.8-8 +
+
+ + Distance from source to isocenter in mm. +Required if present and consistent in the contributing SOP Instances. + + + Nominal focal spot size in mm used to acquire this image. +Required if present and consistent in the contributing SOP Instances. + + + Type of filter(s) inserted into the X-Ray beam (e.g. wedges). +Defined Terms: +STRIP +WEDGE +BUTTERFLY +MULTIPLE +NONE +Required if present and consistent in the contributing SOP Instances. + + + The X-Ray absorbing material used in the filter. May be multi-valued. +Defined Terms: +MOLYBDENUM +ALUMINUM +COPPER +RHODIUM +NIOBIUM +EUROPIUM +LEAD +Required if present and consistent in the contributing SOP Instances. + + + The minimum thickness in mm of the X-Ray absorbing material used in the filters. May be multi-valued, with values corresponding to the respective values in Filter Material (0018,7050). +Required if present and consistent in the contributing SOP Instances. + + + The maximum thickness in mm of the X-Ray absorbing material used in the filters. May be multi-valued, with values corresponding to the respective values in Filter Material (0018,7050). +Required if present and consistent in the contributing SOP Instances. + + + Total amount of rotation of the primary positioner in degrees. +Required if present and consistent in the contributing SOP Instances. + + + Start position of the primary positioner in degrees. See C.8.7.5.1.2. +Required if present and consistent in the contributing SOP Instances. +
The definitions of Positioner Angles shall be with respect to the patient as illustrated in Figures C.8-11 and C.8-12 Zero degree is referenced to the origin perpendicular to the patient's chest. The Positioner Primary Angle definition is like longitude (in the equatorial plan); the Positioner Secondary Angle definition is like latitude (in the sagittal plane). The Positioner Angle attributes apply to the first frame of a multi-frame image. The valid range of Primary Positioner Angle is -180 to +180 degrees and the Secondary Positioner Angle range is -90 to + 90 degrees. +The Patient Plane is defined by the isocenter of the imaging device and slices through the patient such that it is perpendicular to the sagittal plane of the body. The Primary Axis of rotation is defined at the intersection of the Patient Plane and of the Sagittal Plane. The Positioner Primary Angle is defined in the transaxial plane at the isocenter with zero degrees in the direction perpendicular to the patient's chest and + 90 degrees at the Patient left hand side (LAO) and -90 at the Patient right hand side (RAO). The valid range of Primary Positioner Angle is -180 to +180 degrees. +The Secondary Axis is in the Patient Plane and is perpendicular to the Primary Axis at the isocenter. The Positioner Secondary Angle is defined in the Sagittal Plane at the isocenter with zero degrees in the direction perpendicular to the patient's chest. +90 degrees corresponds to the cranial direction. The Secondary Positioner Angle range is -90 to + 90 degrees. +At a 0 angle for both the Primary Angle (0018,1510) and Secondary Angle (0018,1511), the patient faces the Image Intensifier. +The Positioner Primary Angle (0018,1510) and Secondary Angle (0018,1511) apply to the first frame of a multi-frame image. + +Figure C.8-11 +Positioner Primary Angle + +Figure C.8-12 +Positioner Secondary Angle +
+
+ + Nominal increment of the primary positioner angle in degrees. Positive values indicate moving from RAO to LAO position through the anterior. See C.8.7.5.1.2. +Required if present and consistent in the contributing SOP Instances. +
The definitions of Positioner Angles shall be with respect to the patient as illustrated in Figures C.8-11 and C.8-12 Zero degree is referenced to the origin perpendicular to the patient's chest. The Positioner Primary Angle definition is like longitude (in the equatorial plan); the Positioner Secondary Angle definition is like latitude (in the sagittal plane). The Positioner Angle attributes apply to the first frame of a multi-frame image. The valid range of Primary Positioner Angle is -180 to +180 degrees and the Secondary Positioner Angle range is -90 to + 90 degrees. +The Patient Plane is defined by the isocenter of the imaging device and slices through the patient such that it is perpendicular to the sagittal plane of the body. The Primary Axis of rotation is defined at the intersection of the Patient Plane and of the Sagittal Plane. The Positioner Primary Angle is defined in the transaxial plane at the isocenter with zero degrees in the direction perpendicular to the patient's chest and + 90 degrees at the Patient left hand side (LAO) and -90 at the Patient right hand side (RAO). The valid range of Primary Positioner Angle is -180 to +180 degrees. +The Secondary Axis is in the Patient Plane and is perpendicular to the Primary Axis at the isocenter. The Positioner Secondary Angle is defined in the Sagittal Plane at the isocenter with zero degrees in the direction perpendicular to the patient's chest. +90 degrees corresponds to the cranial direction. The Secondary Positioner Angle range is -90 to + 90 degrees. +At a 0 angle for both the Primary Angle (0018,1510) and Secondary Angle (0018,1511), the patient faces the Image Intensifier. +The Positioner Primary Angle (0018,1510) and Secondary Angle (0018,1511) apply to the first frame of a multi-frame image. + +Figure C.8-11 +Positioner Primary Angle + +Figure C.8-12 +Positioner Secondary Angle +
+
+ + Total amount of rotation of the secondary positioner in degrees. +Required if present and consistent in the contributing SOP Instances. + + + Start position of the secondary positioner in degrees. See C.8.7.5.1.2. +Required if present and consistent in the contributing SOP Instances. +
The definitions of Positioner Angles shall be with respect to the patient as illustrated in Figures C.8-11 and C.8-12 Zero degree is referenced to the origin perpendicular to the patient's chest. The Positioner Primary Angle definition is like longitude (in the equatorial plan); the Positioner Secondary Angle definition is like latitude (in the sagittal plane). The Positioner Angle attributes apply to the first frame of a multi-frame image. The valid range of Primary Positioner Angle is -180 to +180 degrees and the Secondary Positioner Angle range is -90 to + 90 degrees. +The Patient Plane is defined by the isocenter of the imaging device and slices through the patient such that it is perpendicular to the sagittal plane of the body. The Primary Axis of rotation is defined at the intersection of the Patient Plane and of the Sagittal Plane. The Positioner Primary Angle is defined in the transaxial plane at the isocenter with zero degrees in the direction perpendicular to the patient's chest and + 90 degrees at the Patient left hand side (LAO) and -90 at the Patient right hand side (RAO). The valid range of Primary Positioner Angle is -180 to +180 degrees. +The Secondary Axis is in the Patient Plane and is perpendicular to the Primary Axis at the isocenter. The Positioner Secondary Angle is defined in the Sagittal Plane at the isocenter with zero degrees in the direction perpendicular to the patient's chest. +90 degrees corresponds to the cranial direction. The Secondary Positioner Angle range is -90 to + 90 degrees. +At a 0 angle for both the Primary Angle (0018,1510) and Secondary Angle (0018,1511), the patient faces the Image Intensifier. +The Positioner Primary Angle (0018,1510) and Secondary Angle (0018,1511) apply to the first frame of a multi-frame image. + +Figure C.8-11 +Positioner Primary Angle + +Figure C.8-12 +Positioner Secondary Angle +
+
+ + Nominal increment of the secondary positioner angle in degrees. Positive values indicate moving from CAU to CRA through the anterior. See C.8.7.5.1.2. +Required if present and consistent in the contributing SOP Instances. +
The definitions of Positioner Angles shall be with respect to the patient as illustrated in Figures C.8-11 and C.8-12 Zero degree is referenced to the origin perpendicular to the patient's chest. The Positioner Primary Angle definition is like longitude (in the equatorial plan); the Positioner Secondary Angle definition is like latitude (in the sagittal plane). The Positioner Angle attributes apply to the first frame of a multi-frame image. The valid range of Primary Positioner Angle is -180 to +180 degrees and the Secondary Positioner Angle range is -90 to + 90 degrees. +The Patient Plane is defined by the isocenter of the imaging device and slices through the patient such that it is perpendicular to the sagittal plane of the body. The Primary Axis of rotation is defined at the intersection of the Patient Plane and of the Sagittal Plane. The Positioner Primary Angle is defined in the transaxial plane at the isocenter with zero degrees in the direction perpendicular to the patient's chest and + 90 degrees at the Patient left hand side (LAO) and -90 at the Patient right hand side (RAO). The valid range of Primary Positioner Angle is -180 to +180 degrees. +The Secondary Axis is in the Patient Plane and is perpendicular to the Primary Axis at the isocenter. The Positioner Secondary Angle is defined in the Sagittal Plane at the isocenter with zero degrees in the direction perpendicular to the patient's chest. +90 degrees corresponds to the cranial direction. The Secondary Positioner Angle range is -90 to + 90 degrees. +At a 0 angle for both the Primary Angle (0018,1510) and Secondary Angle (0018,1511), the patient faces the Image Intensifier. +The Positioner Primary Angle (0018,1510) and Secondary Angle (0018,1511) apply to the first frame of a multi-frame image. + +Figure C.8-11 +Positioner Primary Angle + +Figure C.8-12 +Positioner Secondary Angle +
+
+ + Sequence containing detailed acquisition context of each individual projection used in this acquisition context. +Zero or more items may be present. +Required if present and consistent in the contributing SOP Instances. + + + + Position of the X-Ray center beam for this projection in the isocenter reference system in the X direction (deg). +See C.8.19.6.13.1.2 for further explanation. +Required if present and consistent in the contributing SOP Instances. +
The positioner coordinate system (Op, Xp, Yp, Zp) is defined as follows: +
+
+ + Position of the X-Ray center beam for this projection in the isocenter reference system in the Z direction (deg). +See C.8.19.6.13.1.2 for further explanation. +Required if present and consistent in the contributing SOP Instances. +
The positioner coordinate system (Op, Xp, Yp, Zp) is defined as follows: +
+
+ + Rotation of the X-Ray detector plane for this projection (deg). +See C.8.19.6.13.1.2 for further explanation. +Required if present and consistent in the contributing SOP Instances. +
The positioner coordinate system (Op, Xp, Yp, Zp) is defined as follows: +
+
+
+ + + Each item represents a acquisition context related to a set of frames of SOP Instance defined by this IOD, +The values of the Acquisition Index (0020,9518) attribute may be used as index to Items in this sequence. +One or more Items may be present. + + + + + Sequence containing detailed acquisition context of each individual projection used in this acquisition context. +Zero or more items may be present. +Required if present and consistent in the contributing SOP Instances. + + + + + + A sequence of Items each describing the characteristics of one 3D reconstruction included in this SOP instance. +One or more items may be present. + + + Free text description of the purpose of the reconstruction, e.g., mask volume. + + + Name of the application that created the reconstruction. + + + Version of the application that created the reconstruction. + + + Name of the manufacturer of the application that created the reconstruction. + + + Type of algorithm used to create the reconstruction. +Defined Terms: +FILTER_BACK_PROJ +ITERATIVE + + + Description of the algorithm used to create the reconstruction. + + + The Item number(s) of the X-Ray 3D Acquisition Sequence (0018,9507) that describes the acquisition context(s) contributing to this reconstruction. + + + + + A sequence that describes general characteristics of this frame. +Only a single Item shall be permitted in this sequence. + + + Type of Frame. A multi-valued attribute analogous to the Image Type (0008,0008). +Enumerated Values and Defined Terms are the same as those for the four values of the Image Type (0008,0008) attribute, except that the value MIXED is not allowed. See C.8.16.1 and C.8.13.3.1.1. +
The Image Type (0008,0008) and associated Image Type related attributes provide a high level description of a multi-frame SOP Instance. These attributes describe properties that provide key summary information to users of the SOP Instance. Image Type (0008,0008) contains the highest level summary of what is in the SOP Instance. +The Frame Type (0008,9007) attribute mirrors the corresponding Image Type attribute and applies to the frame level rather than to the image level. +If more than one value is used by the set of frames for a given Frame Type (0008,9007) attribute value or associated attribute value then the corresponding value of the Image Type (0008,0008) or associated attribute shall contain a value of MIXED. This indicates that a mixed set of values exists within the multi-frame SOP Instance. +The value MIXED shall only be used in the Image Type (0008,0008) when the corresponding values for the individual frames are not equal. When a value of an attribute is equal for all frames, the same value shall be used for the corresponding value of the Image Type (0008,0008). Values 2 and 3 of Image Type (0008,0008) are an exception to the rule for MIXED: Values 2 and 3 may never have the value of MIXED as described in sections C.8.16.1.2 and C.8.16.1.3. +Image Type (0008,0008) and Frame Type (0008,9007) shall consist of four non-zero length values. +
+
+ + + The Item number of the X-Ray 3D Reconstruction Sequence (0018,9530) that describes the characteristics of the 3D Reconstruction to which this frame is part of. + +
+ + + Number of Rows in Overlay. + + + Number of Columns in Overlay. + + + Indicates whether this overlay represents a region of interest or other graphics. Enumerated Values: +G = Graphics +R = ROI. + + + Location of first overlay point with respect to pixels in the image, given as row\column. +The upper left pixel of the image has the coordinate 1\1. +Column values greater than 1 indicate the overlay plane origin is to the right of the image origin. Row values greater than 1 indicate the overlay plane origin is below the image origin. Values less than 1 indicate the overlay plane origin is above or to the left of the image origin. +Note: Values of 0\0 indicate that the overlay pixels start 1 row above and one column to the left of the image pixels. + + + Number of Bits Allocated in the Overlay. +Tthe value of this Attribute shall be 1. +Note: Formerly the standard described embedding the overlay data in the Image Pixel Data (7FE0,0010), in which case the value of this Attribute was required to be the same as Bits Allocated (0028,0100). This usage has been retired. See PS 3.3 2004. + + + The value of this Attribute shall be 0. +Note: Formerly the standard described embedding the overlay data in the Image Pixel Data (7FE0,0010), in which case the value of this Attribute specified the bit in which the overlay was stored. This usage has been retired. See PS 3.3 2004. + + + Overlay pixel data. +The order of pixels sent for each overlay is left to right, top to bottom, i.e., the upper left pixel is sent first followed by the remainder of the first row , followed by the first pixel of the 2nd row, then the remainder of the 2nd row and so on. +Overlay data shall be contained in this Attribute . +See C.9.2.1.1 for further explanation. +
There are two specific types of overlays. The type is specified in this Attribute. +A Region of Interest (ROI) is a specific use of an Overlay. The overlay bits corresponding to all the pixels included in the ROI shall be set to 1. All other bits are set to 0. This is used to specify an area of the image of particular interest. +A Graphics overlay may express reference marks, graphic annotation, or bit mapped text, etc. A Graphics overlay may be used to mark the boundary of a ROI. If this is the case and the ROI statistical parameters are used, they will only refer to the pixels under the boundaries, not those in the included regions. +The overlay bits corresponding to all the pixels included in the Graphics shall be set to 1. All other bits are set to 0. +
+
+ + User-defined comments about the overlay. + + + Defined term which identifies the intended purpose of the Overlay Type. See C.9.2.1.3 for further explanation. +
Two Defined Terms are specified: +USER - User created graphic annotation (e.g. operator) +AUTOMATED - Machine or algorithm generated graphic annotation, such as output of a Computer Assisted Diagnosis algorithm. + +Note: Additional or alternative Defined Terms may be specified in modality specific Modules, such as in the Ultrasound Image Module, C.8.5.6.1.11. + +
+
+ + A user defined text string which may be used to label or name this overlay. + + + Number of pixels in ROI area. +See C.9.2.1.2 for further explanation. +
These Attributes contain the statistical parameters of the ROI. The values of these parameters are for the overlay pixel values set to 1. +
+
+ + ROI Mean. +See C.9.2.1.2 for further explanation. +
These Attributes contain the statistical parameters of the ROI. The values of these parameters are for the overlay pixel values set to 1. +
+
+ + ROI standard deviation. +See C.9.2.1.2 for further explanation. +
These Attributes contain the statistical parameters of the ROI. The values of these parameters are for the overlay pixel values set to 1. +
+
+
+ + + Number of Frames in Overlay. Required if Overlay data contains multiple frames. + + + Frame number of Multi-frame Image to which this overlay applies; frames are numbered from 1. + + + + + A sequence of Items each of which describes the displayed area selection for a group of images or frames. Sufficient Items shall be present to describe every image and frame listed in the Presentation State Relationship Module. +One or more Items shall be present. + + + Sequence of Items where each Item provides reference to a selected set of Image SOP Class/SOP Instance pairs that are defined in the Presentation State Relationship Module. One or more Items shall be present. +Requiredif the displayed area selection in this Item does not apply to all the images and frames listed in the Presentation State Relationship Module. + + + + The top left (after spatial transformation) pixel in the referenced image to be displayed, given as column\row. Column is the horizontal (before spatial transformation) offset (X) and row is the vertical (before spatial transformation) offset (Y) relative to the origin of the pixel data before spatial transformation, which is 1\1. See Figure C.10.4-1. + + + The bottom right (after spatial transformation) pixel in the referenced image to be displayed, given as column\row. Column is the horizontal (before spatial transformation) offset (X) and row is the vertical (before spatial transformation) offset (Y) relative to the origin of the pixel data before spatial transformation, which is 1\1. See Figure C.10.4-1. + + + Manner of selection of display size. +Enumerated Values: +SCALE TO FIT +TRUE SIZE +MAGNIFY +See C.10.4 for further explanation. + + + Physical distance between the center of each pixel in the referenced image (before spatial transformation), specified by a numeric pair - adjacent row spacing (delimiter) adjacent column spacing in mm. See 10.7.1.3 for further explanation of the value order. +Notes: 1. This value may be different from Pixel Spacing (0028,0030) or Imager Pixel Spacing (0018,1164) specified in the referenced image, which are ignored, since some form of calibration may have been performed (for example by reference to an object of known size in the image). +2. If the row and column spacing are different, then the pixel aspect ratio of the image is not 1:1. +Required if Presentation Size Mode (0070,0100) is TRUE SIZE, in which case the values will correspond to the physical distance between the center of each pixel on the display device. +May be present if Presentation Size Mode (0070,0100) is SCALE TO FIT or MAGNIFY, in which case the values are used to compute the aspect ratio of the image pixels. + + + Ratio of the vertical size and the horizontal size of the pixels in the referenced image, to be used to display the referenced image, specified by a pair of integer values where the first value is the vertical pixel size and the second value is the horizontal pixel size. See C.7.6.3.1.7. +Required if Presentation Pixel Spacing (0070,0101) is not present. +Notes: 1. This value may be different from the aspect ratio specified by Pixel Aspect Ratio (0028,0034) in the referenced image, or implied by the values of Pixel Spacing (0028,0030) or Imager Pixel Spacing (0018,1164) specified in the referenced image, which are ignored. +2. This value must be specified even if the aspect ratio is 1:1. +
The pixel aspect ratio is the ratio of the vertical size and horizontal size of the pixels in the image specified by a pair of integer values where the first value is the vertical pixel size, and the second value is the horizontal pixel size. To illustrate, consider the following example pixel size: + +Pixel Aspect Ratio = Vertical Size \ Horizontal Size = 0.30 mm \0.25 mm. Thus the Pixel Aspect Ratio could be represented as the multivalued integer string "6\5", "60\50", or any equivalent integer ratio. +
+
+ + Ratio of displayed pixels to source pixels, specified in one dimension. +Required if Presentation Size Mode (0070,0100) is MAGNIFY. +Notes: 1. A value of 1.0 would imply that one pixel in the referenced image would be displayed as one pixel on the display (i.e. it would not be interpolated if the aspect ratio of the image pixels is 1:1). +2. A value of 2.0 would imply that one pixel in the referenced image would be displayed as 4 pixels on the display (i.e. up-sampled by a factor of 2 in each of the row and column directions). +3. A value of 0.5 would imply that 4 pixels in the referenced image would be displayed as 1 pixel on the display (i.e. down-sampled by a factor of 2 in each of the row and column directions). +4. If the source pixels have an aspect ratio of other than 1:1, then they are assumed to have been interpolated to a display pixel aspect ratio of 1:1 prior to magnification. + +
+ + + A sequence of Items each of which represents a group of annotations composed of graphics or text or both. +One or more Items shall be present. + + + Sequence of Items where each Item provides reference to a selected set of Image SOP Class/SOP Instance pairs that are defined in the Presentation State Relationship Module. One or more Items shall be present. +Required if graphic annotations in this Item do not apply to all the images and frames listed in the Presentation State Relationship Module. + + + + The layer defined in the Graphic Layer Module C.10.7 in which the graphics or text is to be rendered. + + + Sequence that describes a text annotation. One or more Items may be present. +Either one or both of Text Object Sequence (0070,0008) or Graphic Object Sequence (0070,0009) are required . + + + Units of measure for the axes of the text bounding box. +Defines whether or not the annotation is Image or Displayed Area relative. Both dimensions shall have the same units. +Enumerated Values: +PIXEL = Image relative position specified with sub-pixel resolution such that the origin at the Top Left Hand Corner (TLHC) of the TLHC pixel is 0.0\0.0, the Bottom Right Hand Corner (BRHC) of the TLHC pixel is 1.0\1.0, and the BRHC of the BRHC pixel is Columns\Rows (see figure C.10.5-1). The values must be within the range 0\0 to Columns\Rows. +DISPLAY = Fraction of Specified Displayed Area where 0.0\0.0 is the TLHC and 1.0\1.0 is the BRHC. The values must be within the range 0.0 to 1.0. +Required if Bounding Box Top Left Hand Corner (0070,0010) or Bounding Box Bottom Right Hand Corner (0070,0011) is present. + + + Units of measure for the axes of the text anchor point annotation. +Enumerated Values for Anchor Point Annotation Units (0070,0004) are the same as for Bounding Box Annotation Units (0070,0003). +Required if Anchor Point (0070,0014) is present. + + + Text data which is unformatted and whose manner of display within the defined bounding box or relative to the specified anchor point is implementation dependent. See C.10.5.1.1. +The text value may contain spaces, as well as multiple lines separated by either LF, CR, CR LF or LF CR, but otherwise no format control characters (such as horizontal or vertical tab and form feed) shall be present, even if permitted by the Value Representation of ST. +The text shall be interpreted as specified by Specific Character Set (0008,0005) if present in the SOP Common Module. +Note: The text may contain single or multi-byte characters and use code extension techniques as described in PS 3.5 if permitted by the values of Specific Character Set (0008,0005). +
The text shall be displayed if any part of the bounding box or anchor point is within the Specified Display Area. +The text need not be confined to within the bounding box, but shall be rendered in a direction from the Top Left Hand Corner (TLHC) of the bounding box to the Bottom Right Hand Corner (BRHC) of the bounding box, even if these coordinates have been specified in an image relative space and then transformed (rotated, flipped or scaled). +Notes: 1. An implementation may render text outside the confines of the bounding box if necessary to display all the specified text. + 2. Alternatively, an implementation may choose to render the text in a scrolling box, or a link to another fixed or popup window as appropriate. + +Whether the contents of the bounding box completely opacify the underlying image or whether the box is “transparent†is undefined. +Notes: 1. For example, an implementation may choose an “exclusive or†style opacification to be sure that the text is discernible over light and dark portions of the image. + 2. Commonly, the region of the bounding box around the text will be rendered “transparentlyâ€, i.e. the image will be visible, though some implementations may choose to opacify the bounding box behind the text to improve its readability. + +An alternative to specifying a bounding box, is to specify an Anchor Point (0070,0014), i.e. some point in an image or Specified Displayed Area that is related to the text. The semantics of this relationship, and the manner of positioning or linking the text to this point, are unspecified. +Notes: 1. For example, a description of a feature may be linked to a point in the image, and when that image is displayed, if it is magnified and panned, the rendered text (and any arrow or line drawn in response to Anchor Point Visibility (0070,0015)) might be repositioned as appropriate so as not to be cropped out of the Specified Displayed Area. + 2. As another example, the text could be rendered in a pop-up window when a hypertext link flagged on the displayed image at the location of the Anchor Point (0070,0014) is selected. + 3. The bounding box and anchor point need not be defined with the same axis units, i.e. one can be image pixel relative, and the other displayed area relative. + +The size, font and rotation of the individual rendered text characters are unspecified. +
+
+ + Location of the Top Left Hand Corner (TLHC) of the bounding box in which Unformatted Text Value (0070,0006) is to be displayed, in Bounding Box Annotation Units (0070,0003), given as column\row. Column is the horizontal offset and row is the vertical offset. +Required if Anchor Point (0070,0014) is not present. + + + Location of the Bottom Right Hand Corner (BRHC) of the bounding box in which Unformatted Text Value (0070,0006) is to be displayed, in Bounding Box Annotation Units (0070,0003), given as column\row. Column is the horizontal offset and row is the vertical offset. +Required if Anchor Point (0070,0014) is not present. + + + Location of the text relative to the vertical edges of the bounding box. Enumerated Values: +LEFT = closest to left edge +RIGHT = closest to right edge +CENTER = centered +Required if Bounding Box Top Left Hand Corner (0070,0010) is present. + + + Location of a point in the image or Specified Displayed Area to which the Unformatted Text Value (0070,0006) is related, in Anchor Point Annotation Units (0070,0004), given as column\row. Column is the horizontal offset and row is the vertical offset. +Required if Bounding Box Top Left Hand Corner (0070,0010) and Bounding Box Bottom Right Hand Corner (0070,0011) are not present. +May be present even if a bounding box is specified (i.e. Bounding Box Top Left Hand Corner (0070,0010) and Bounding Box Bottom Right Hand Corner (0070,0011) are present). + + + Flag to indicate whether or not a visible indication (such as a line or arrow) of the relationship between the text and the anchor point is to be displayed. +Enumerated Values: +Y = yes +N = no +Required if Anchor Point (0070,0014) is present. + + + Sequence that describes a graphic annotation. One or more Items may be present. +Either one or both of Text Object Sequence (0070,0008) or Graphic Object Sequence (0070,0009) are required. + + + Units of measure for the axes of the graphic annotation. +Enumerated Values for Graphic Annotation Units (0070,0005) are the same as for Bounding Box Annotation Units (0070,0003). + + + Enumerated Value: 2 + + + Number of data points in this graphic. + + + Coordinates that specify this graphic annotation. +See C.10.5.1.2 for further explanation. +
Graphic Data (0070,0022) contains the points in the graphic annotation, each dimension for the first point, followed by dimensions for second point, etc. For a two dimensional curve: X1, Y1, X2, Y2, etc. The first (X) dimension corresponds to the image or Specified Displayed Area column (horizontal offset), and the second (Y) dimension corresponds to the image or Specified Displayed Area row (vertical offset). The Value Representation of all components of the N-tuple shall be the same. The image or Specified Displayed Area relative drawing space is defined in Graphic Annotation Units (0070,0005). +If Graphic Type (0070,0023) is POINT, then two values (one point) shall be specified and the single point specified is to be drawn. +If Graphic Type (0070,0023) is POLYLINE, then the points are to be interpreted as an n-tuple list of end points between which straight lines are to be drawn. +If Graphic Type (0070,0023) is INTERPOLATED, then the points are to be interpreted as an n-tuple list of end points between which some form of implementation dependent curved lines are to be drawn. The rendered line shall pass through all the specified points. +If Graphic Type (0070,0023) is CIRCLE, then exactly two points shall be present; the first point is to be interpreted as the center and the second point as a point on the circumference of a circle, some form of implementation dependent representation of which is to be drawn. +If Graphic Type (0070,0023) is ELLIPSE, then exactly four points shall be present; the first two points are to be interpreted as the endpoints of the major axis and the second two points as the endpoints of the minor axis of an ellipse, some form of implementation dependent representation of which is to be drawn. +The notion of “open†or “closed†has no inherent meaning in the context of an arbitrary graphic, other than in the condition for the presence of Graphic Filled (0070,0024). The graphic has no semantic notion of an associated observation such as a region of interest, except that which the unformatted text in the same Item may describe. +The choice of pixel value used to represent the graphic on a display is defined in the Graphic Layer Module C.10.7. + +Figure C.10.5-1 +Sub-pixel Addressing Units in PIXEL Space +
+
+ + The shape of graphic that is to be drawn. See C.10.5.1.2. +Enumerated Values: +POINT +POLYLINE +INTERPOLATED +CIRCLE +ELLIPSE +
Graphic Data (0070,0022) contains the points in the graphic annotation, each dimension for the first point, followed by dimensions for second point, etc. For a two dimensional curve: X1, Y1, X2, Y2, etc. The first (X) dimension corresponds to the image or Specified Displayed Area column (horizontal offset), and the second (Y) dimension corresponds to the image or Specified Displayed Area row (vertical offset). The Value Representation of all components of the N-tuple shall be the same. The image or Specified Displayed Area relative drawing space is defined in Graphic Annotation Units (0070,0005). +If Graphic Type (0070,0023) is POINT, then two values (one point) shall be specified and the single point specified is to be drawn. +If Graphic Type (0070,0023) is POLYLINE, then the points are to be interpreted as an n-tuple list of end points between which straight lines are to be drawn. +If Graphic Type (0070,0023) is INTERPOLATED, then the points are to be interpreted as an n-tuple list of end points between which some form of implementation dependent curved lines are to be drawn. The rendered line shall pass through all the specified points. +If Graphic Type (0070,0023) is CIRCLE, then exactly two points shall be present; the first point is to be interpreted as the center and the second point as a point on the circumference of a circle, some form of implementation dependent representation of which is to be drawn. +If Graphic Type (0070,0023) is ELLIPSE, then exactly four points shall be present; the first two points are to be interpreted as the endpoints of the major axis and the second two points as the endpoints of the minor axis of an ellipse, some form of implementation dependent representation of which is to be drawn. +The notion of “open†or “closed†has no inherent meaning in the context of an arbitrary graphic, other than in the condition for the presence of Graphic Filled (0070,0024). The graphic has no semantic notion of an associated observation such as a region of interest, except that which the unformatted text in the same Item may describe. +The choice of pixel value used to represent the graphic on a display is defined in the Graphic Layer Module C.10.7. + +Figure C.10.5-1 +Sub-pixel Addressing Units in PIXEL Space +
+
+ + Whether or not the closed graphics element is displayed as filled (in some unspecified manner that shall be distinguishable from an outline) or as an outline. See C.10.5.1.2. +Enumerated Values: +Y = yes +N = no +Required if Graphic Data (0070,0022) is "closed", that is Graphic Type (0070,0023) is CIRCLE or ELLIPSE, or Graphic Type (0070,0023) is POLYLINE or INTERPOLATED and the first data point is the same as the last data point. +
Graphic Data (0070,0022) contains the points in the graphic annotation, each dimension for the first point, followed by dimensions for second point, etc. For a two dimensional curve: X1, Y1, X2, Y2, etc. The first (X) dimension corresponds to the image or Specified Displayed Area column (horizontal offset), and the second (Y) dimension corresponds to the image or Specified Displayed Area row (vertical offset). The Value Representation of all components of the N-tuple shall be the same. The image or Specified Displayed Area relative drawing space is defined in Graphic Annotation Units (0070,0005). +If Graphic Type (0070,0023) is POINT, then two values (one point) shall be specified and the single point specified is to be drawn. +If Graphic Type (0070,0023) is POLYLINE, then the points are to be interpreted as an n-tuple list of end points between which straight lines are to be drawn. +If Graphic Type (0070,0023) is INTERPOLATED, then the points are to be interpreted as an n-tuple list of end points between which some form of implementation dependent curved lines are to be drawn. The rendered line shall pass through all the specified points. +If Graphic Type (0070,0023) is CIRCLE, then exactly two points shall be present; the first point is to be interpreted as the center and the second point as a point on the circumference of a circle, some form of implementation dependent representation of which is to be drawn. +If Graphic Type (0070,0023) is ELLIPSE, then exactly four points shall be present; the first two points are to be interpreted as the endpoints of the major axis and the second two points as the endpoints of the minor axis of an ellipse, some form of implementation dependent representation of which is to be drawn. +The notion of “open†or “closed†has no inherent meaning in the context of an arbitrary graphic, other than in the condition for the presence of Graphic Filled (0070,0024). The graphic has no semantic notion of an associated observation such as a region of interest, except that which the unformatted text in the same Item may describe. +The choice of pixel value used to represent the graphic on a display is defined in the Graphic Layer Module C.10.7. + +Figure C.10.5-1 +Sub-pixel Addressing Units in PIXEL Space +
+
+
+ + + How far to rotate the image clockwise in degrees, before any Image Horizontal Flip (0070,0041) is applied. +Enumerated Values: +0, 90,180,270 +Notes: Negative values are not permitted since the Value Representation is unsigned. + + + Whether or not to flip the image horizontally after any Image Rotation has been applied such that the left side of the image becomes the right side. +Enumerated Values: +Y = yes, +N = no +Note: No vertical flip is specified since the same result can be achieved by a combination of a 180 degree rotation and a horizontal flip. + + + + + A sequence of Items each of which represents a single layer in which overlays, curves, graphics or text may be rendered. +One or more Items shall be present. An Item is required for each layer referenced from the Graphic Annotation Module or the Overlay Activation Module. + + + A string which identifies the layer. +Note: This identifier may be used by other Attributes within the same presentation state instance to reference this layer. There is no requirement for the same identifiers to be used in different presentation states, and there is no mechanism for referencing layers in other presentation states. That is, a UID is not required. + + + An integer indicating the order in which it is recommended that the layer be rendered, if the display is capable of distinguishing. Lower numbered layers are to be rendered first. + + + A default single gray unsigned value in which it is recommended that the layer be rendered on a monochrome display. The units are specified in P-Values from a minimum of 0000H (black) up to a maximum of FFFFH (white). +Note: The maximum P-Value for this Attribute may be different from the maximum P-Value from the output of the Presentation LUT, which may be less than 16 bits in depth. + + + A default color triplet value in which it is recommended that the layer be rendered on a color display. The units are specified in PCS-Values, and the value is encoded as CIELab. See C.10.7.1.1. +
Attributes such as Graphic Layer Recommended Display CIELab Value (0070,0401) consist of three unsigned short values: +
+
+ + A free text description of the contents of this layer. + +
+ + + A number that identifies this Waveform. + + + The date the Waveform data was created. + + + The time the Waveform data was created. + + + The date and time that the acquisition of data that resulted in this waveform started; the reference timestamp for the Multiplex Group Time Offset (0018,1068) for a waveform multiplex group +Note: The synchronization of this time with an external clock is specified in the Synchronization Module in Acquisition Time Synchronized (0018,1800). + + + A sequence which provides reference to a set of SOP Class/Instance pairs significantly related to this Waveform. One or more Items may be included in this sequence. + + + + Code describing the purpose of the reference to the Instance(s). Only a single Item shall be permitted in this sequence. + + + + + + Sequence of one or more Items, each representing one waveform multiplex group. Ordering of Items in this Sequence is significant for external reference to specific multiplex groups. + + + Offset time in milliseconds from a reference time (see C.10.9.1.1). +Required if Acquisition Time Synchronized (0018,1800) value is Y; may be present otherwise. + + + Offset time in milliseconds from a synchronization trigger to the first sample of a waveform multiplex group. May be positive or negative. Required if waveform acquisition is synchronized to a trigger. + + + Sample number whose time corresponds to a synchronization trigger (see C.10.9.1.2). + + + See C.10.9.1.3. Enumerated values: +ORIGINAL +DERIVED +
Waveform Originality (003A,0004) shall have the value ORIGINAL if the Waveform Data samples are the original or source data, and shall have the value DERIVED if the Waveform Data samples have been derived in some manner from the sample data of other waveforms. +Notes : 1. The Waveform Originality (003A,0004) attribute is comparable to the Image Type (0008,0008) attribute value 1 (see C.7.6.1.1.2). Within a single Multiplex Group, all channels shall have the same Originality value. + 2. Waveform data which has been transcoded from a non-DICOM format may have Waveform Originality value ORIGINAL if the samples are unchanged from the originally acquired waveform samples. + +
+
+ + Number of channels for this multiplex group. + + + Number of samples per channel in this multiplex group. + + + Frequency in Hz + + + Label for multiplex group + + + Sequence of one or more Items, with one Item per channel (see C.10.9.1.4). Ordering of Items in this Sequence is significant for reference to specific channels. + + + Equipment physical channel number used for acquisition. + + + Text label for channel which may be used for display purposes + + + One or more values for the status of this channel within this SOP Instance. Defined terms: +OK +TEST DATA +DISCONNECTED +QUESTIONABLE +INVALID +UNCALIBRATED +UNZEROED +Precise location of a change in status may be noted in an Annotation. + + + A coded descriptor of the waveform channel source (metric, anatomical position, function, and technique). Only a single Item shall be permitted in this sequence. (See C.10.9.1.4.1) +
Channel Source Sequence (003A,0208) identifies the metric (quality being measured, e.g., voltage or pressure), the anatomical position of the sensor or probe, the function of the channel (e.g., measurement or stimulus), and any particulars of technique which affect those parameters (e.g., pull-back across multiple anatomic sites, or differential input from two distinct sites). If the full semantics of the source is not carried in a single coded entry (e.g., if it specifies the location but not the metric), additional qualifiers are identified in Channel Source Modifiers Sequence (003A,0209) coded entries. +When a single sensor channel is used to collect a waveform from two (or more) anatomic sites, e.g., in hemodynamic pull-back procedures, multiple Channel Source Modifier items will identify the sequence of sites, if not encoded in the semantics of the Channel Source Coded Entry. Transition times from one site to another may be indicated with an Annotation, or pull-back rate may be indicated with an Acquisition Context Sequence Item (see Section C.7.6.14). +The Baseline (default) Context IDs are defined by IOD in accordance with Section A.34. Restrictions in the IOD may also determine the pattern of specification of the waveform source, i.e., which item is to be encoded in the Channel Source sequence, and the order in which Channel Source Modifier items are to be encoded. Unless otherwise specified, pattern of specification of the waveform source shall be: +
+
+ + + Sequence of one or more Items which further qualify the Waveform Source. Required if Channel Source Sequence (003A,0208) does not fully specify the semantics of the source. Ordering of Items in this Sequence may be semantically significant. + + + + A sequence which provides reference to a DICOM waveform from which this channel was derived. One or more Items may be included in this Sequence. + + + + Identifies the waveform multiplex group and channel within the referenced SOP Instance. Pair of values (M,C). + + + Additional description of waveform channel derivation + + + Nominal numeric value of unit quantity of sample. Required if samples represent defined (not arbitrary) units. + + + A coded descriptor of the Units of measure for the Channel Sensitivity. Only a single Item shall be permitted in this sequence. (see C.10.9.1.4.2) Required if Channel Sensitivity (003A,0210) is present. + + + + Multiplier to be applied to encoded sample values to match units specified in Channel Sensitivity (003A,0210) (e.g., based on calibration data) (see C.10.9.1.4.2) Required if Channel Sensitivity (003A,0210) is present. + + + Offset of encoded sample value 0 from actual 0 using the units defined in the Channel Sensitivity Units Sequence (003A,0211). Required if Channel Sensitivity (003A,0210) is present. + + + Offset of first sample of channel from waveform multiplex group start time, in seconds (see C.10.9.1.4.3) +Required if Channel Sample Skew is not present. + + + Offset of first sample of channel from waveform multiplex group start time, in samples (see C.10.9.1.4.3) +Required if Channel Time Skew is not present. + + + Additional offset of first sample of channel to be used in aligning multiple channels for presentation or analysis, in seconds (see C.10.9.1.4.3) + + + Number of significant bits within the waveform samples (see C.10.9.1.4.4) + + + Nominal 3dB point of lower frequency of pass band; in Hz + + + Nominal 3dB point of upper frequency of pass band; in Hz + + + Center frequency of notch filter(s); in Hz + + + Nominal 3dB bandwidth of notch filter(s); in Hz + + + Minimum valid sample value as limited by the acquisition equipment (see C.10.9.1.4.5) + + + Maximum valid sample value as limited by the acquisition equipment (see C.10.9.1.4.5) + + + Size of each waveform data sample within the Waveform Data; see section C.10.9.1.5 + + + Data representation of the waveform data points. See C.10.9.1.5. +
Waveform Bits Allocated (5400,1004) specifies the number of bits allocated for each sample, and Waveform Sample Interpretation (5400,1006) specifies the data representation of each waveform sample. Waveform Bits Allocated shall be a multiple of 8. These data elements are related, and their defined terms are specified in Table C.10-10. +Table C.10-10 +Waveform Bits Allocated and Waveform Sample Interpretation + +Notes: 1. The set of valid values from within this table may be constrained by definition of the IOD (see Section A.34). +2. mu-law and A-law encoding is without the alternate bit inversion used for PCM transmission through the telephone network. +This representation also applies to the Channel Minimum and Maximum Data Values, and Waveform Padding Value. +
+
+ + Value of waveform samples inserted in channels when input is absent or invalid. Required if acquisition equipment inserts padding. See C.10.9.1.6. +
Equipment which produces digitized waveform curves may encode a specific value when the source is disconnected or otherwise invalid. This value is encoded like the Waveform Data attribute with one sample only. +The Waveform Padding Value need not be within the range specified by the Channel Minimum and Maximum Data Values. +
+
+ + Encoded data samples - channel multiplexed +See section C.10.9.1.7 + + + The recommended time-based waveform data display scale in units of mm/s (see C.10.9.1.8). + + + A color triplet value recommended for rendering the waveform display background on a color display. The units are specified in PCS-Values, and the value is encoded as CIELab. See C.10.7.1.1. +
Attributes such as Graphic Layer Recommended Display CIELab Value (0070,0401) consist of three unsigned short values: +
+
+ + Sequence of Items, each Item describing a Presentation Group of one or more waveform channels to be displayed together. +Note: A Presentation Group is conventionally denoted a "display page", and a waveform object may be rendered using several Presentation Groups under user display control. +One or more Items may be present. + + + A number that identifies the Presentation Group. + + + Sequence of Items, each Item describing a channel to be displayed in the Presentation Group. +One or more Items shall be present. + + + Identifier of the displayed channel, specified as a pair of values (M,C) where the first value is the ordinal of the sequence item of the Waveform Sequence (5400,0100) attribute (i.e., the Multiplex Group Number), and the second value is the ordinal of the sequence item of the Channel Definition Sequence (003A,0200) attribute (i.e., the Waveform Channel Number) within the multiplex group. +Note: In the context of a Channel Display Sequence (003A,0242) Item, only a single channel shall be referenced. + + + The offset in seconds from the beginning of the channel waveform data to the first sample to be used for presentation. Value may be negative. + + + A color triplet value recommended for rendering the channel on a color display. The units are specified in PCS-Values, and the value is encoded as CIELab. See C.10.7.1.1. +
Attributes such as Graphic Layer Recommended Display CIELab Value (0070,0401) consist of three unsigned short values: +
+
+ + Position of the Channel within the Presentation Group display area (see C.10.9.1.9). + + + Specifies display area shading between the displayed waveform channel and another line. The nature of the shading (e.g., solid, or cross-hatching) is implementation dependent. +Enumerated Values: +NONE - no shading +BASELINE- shading between the waveform and the channel display baseline (sample value 0 equivalent location) +ABSOLUTE - shading between the waveform and the channel real world actual value 0 (i.e., taking into account the Channel Baseline (003A,0213) value) +DIFFERENCE - shading between the waveform and a second waveform in the Presentation Group at the same Channel Position that also has Display Shading Flag (003A,0246) value DIFFERENCE. + + + Fraction of the Presentation Group vertical display dimension assigned to the unit quantity (least significant bit) of the Channel samples (see C.10.9.1.10). Required if Absolute Channel Display Scale (003A,0248) is not present, may be present otherwise. + + + Nominal vertical display height in mm assigned to the unit quantity (least significant bit) of the Channel samples (see C.10.9.1.10). Required if Fractional Channel Display Scale (003A,0247) is not present, may be present otherwise. + +
+ + + Sequence of Annotation Items; one or more items shall be present + + + Text Observation Value (annotation). +Mutually exclusive with Concept Name Code Sequence (0040,A043) + + + Code representing the fully specified name of the NUMERIC measurement or CODED concept. This sequence shall contain exactly one item. +Mutually exclusive with Text Value (0070,0006). + + + + A sequence of items modifying or specializing the Concept Name. One or more Items may be included in this Sequence. +Required if Concept Name Code Sequence (0040,A043) is sent and the value does not fully describe the semantics of the measurement or concept. + + + + A sequence that conveys the categorical coded nominal value. This sequence shall contain exactly one item. + + + + A sequence of items modifying or specializing the Concept. One or more Items may be included in this Sequence. +Required if Concept Code Sequence (0040,A168) is sent and the value does not fully describe the semantics of the concept value. + + + + Numeric measurement value or values. + + + Units of measurement. Coded entry sequence with one item only. + + + + List of channels in waveform to which annotation applies. See C.10.10.1.1 +
Referenced Waveform Channels (0040,A0B0) is a multi-value attribute which lists the channels to which an annotation of a waveform applies. Each channel is specified as a pair of values (M,C), where the first value is the ordinal of the sequence item of the Waveform Sequence (5400,0100) attribute (i.e., the Multiplex Group Number), and the second value is the ordinal of the sequence item of the Channel Definition Sequence (003A,0200) attribute (i.e., the Waveform Channel Number) within the multiplex group. +If the specified channel number is 0, the annotation applies to all channels in the multiplex group. +Note: As an example, an annotation which applies to the entire first multiplex group and channels 2 and 3 of the third multiplex group would have Referenced Channels value 0001 0000 0003 0002 0003 0003. +
+
+ + See C.10.10.1.2 for Enumerated Values. +Required if Annotation does not apply to entire Referenced Waveform Channels; shall not be present if Annotation applies to entire temporal extent of referenced channels. +
The Temporal Range Type attribute (0040,A130) defines the type of temporal extent of the annotated region of interest. A temporal point (or instant of time) may be defined by a waveform sample offset (for a single waveform multiplex group only), time offset, or absolute time. +The following terms are Enumerated Values for Temporal Range Type: +POINT = a single temporal point +MULTIPOINT = multiple temporal points +SEGMENT = a range between two temporal points +MULTISEGMENT = multiple segments, each denoted by two temporal points +BEGIN = a range beginning at one temporal point, and extending beyond the end of the acquired data +END = a range beginning before the start of the acquired data, and extending to (and including) the identified temporal point +
+
+ + List of samples within a multiplex group specifying temporal points for annotation. Position of first sample is 1. Required if Temporal Range Type (0040,A130) is present, and if Referenced Time Offsets (0040,A138) and Referenced DateTime (0040,A13A) are not present. See C.10.10.1.3 +
Referenced Sample Positions (0040,A132) may be used only if Referenced Waveform Channels (0040,A0B0) refers to channels within a single multiplex group. The sample position is by channel, and applies to all channels specified in Referenced Channels (0040,A0B0). +
+
+ + Specifies temporal points for annotation by number of seconds after start of data. Required if Temporal Range Type (0040,A130) is present, and if Referenced Sample Positions (0040,A132) and Referenced DateTime (0040,A13A) are not present. + + + Specifies temporal points for annotation by absolute time. Required if Temporal Range Type (0040,A130) is present, and if Referenced Sample Positions (0040,A132) and Referenced Time Offsets (0040,A138) are not present. + + + Number identifying associated annotations (see C.10.10.1.4). + +
+ + + + + + Defines a sequence of Modality LUTs. +Only one Item may be present. Shall not be present if Rescale Intercept (0028,1052) is present. + + + Specifies the format of the LUT Data in this Sequence. +See C.11.1.1 for further explanation. +Required if the Modality LUT Sequence (0028,3000) is sent. +
+ + + Free form text explanation of the meaning of the LUT. + + + Specifies the output values of this Modality LUT. +See C.11.1.1.2 for further explanation. +Required if the Modality LUT Sequence (0028,3000) is sent. +
Specifies the units of the output of the Modality LUT or rescale operation. +Defined Terms: + OD = The number in the LUT represents thousands of optical density. That is, a value of 2140 represents an optical density of 2.140. + HU = Hounsfield Units (CT) + US = Unspecified +Other values are permitted, but are not defined by the DICOM Standard. +
+
+ + LUT Data in this Sequence. +Required if the Modality LUT Sequence (0028,3000) is sent. + + + The value b in relationship between stored values (SV) and the output units specified in Rescale Type (0028,1054). +Output units = m*SV + b. +Required if Modality LUT Sequence (0028,3000) is not present. Shall not be present otherwise. + + + m in the equation specified by Rescale Intercept (0028,1052). +Required if Rescale Intercept is present. + + + Specifies the output units of Rescale Slope (0028,1053) and Rescale Intercept (0028,1052). +See C.11.1.1.2 for further explanation. +Required if Rescale Intercept is present. +
Specifies the units of the output of the Modality LUT or rescale operation. +Defined Terms: + OD = The number in the LUT represents thousands of optical density. That is, a value of 2140 represents an optical density of 2.140. + HU = Hounsfield Units (CT) + US = Unspecified +Other values are permitted, but are not defined by the DICOM Standard. +
+
+ + + + + + + Defines a sequence of VOI LUTs. One or more Items shall be present. +Required if Window Center (0028,1050) is not present. May be present otherwise. + + + Specifies the format of the LUT Data in this Sequence. +See C.11.2.1.1 for further explanation. +
The three values of the LUT Descriptor (0028,3002) describe the format of the LUT Data in the corresponding Data Element (0028,3006). +The first value is the number of entries in the lookup table. When the number of table entries is equal to 216 then this value shall be 0. +The second value is the first input value mapped. The Value Representation of the second value (US or SS) depends on the source of the input to the VOI LUT, and shall be: +- the same as specified by Pixel Representation (0028,0103), if there is no Modality LUT or Rescale Slope and Intercept specified; +- SS if the possible output range after application of the Rescale Slope and Intercept may be signed; +Note: This is always the case for the CT Image IOD in which the Rescale Type is specified to be Hounsfield Units, which are always signed. +- US otherwise. + +This input value is mapped to the first entry in the LUT. All input values less than the first value mapped are also mapped to the first entry in the LUT Data. An input value one greater than the first value mapped is mapped to the second entry in the LUT Data. Subsequent input values are mapped to the subsequent entries in the LUT Data up to an input value equal to number of entries + first value mapped - 1 which is mapped to the last entry in the LUT Data. Input values greater than or equal to number of entries + first value mapped are also mapped to the last entry in the LUT Data. +The third value specifies the number of bits for each entry in the LUT Data. If the VOI LUT is included in an Image IOD, the third value of LUT Descriptor (0028,3002) shall be 8 or 16 bits, unless otherwise specialized. If the VOI LUT is included in a Presentation State IOD, the third value of LUT Descriptor (0028,3002) shall be between 8 and 16 inclusive. The LUT Data shall be stored in a format equivalent to 8 bits allocated when the number of bits for each entry is 8, and 16 bits allocated when the number of bits for each entry is 16, where in both cases the high bit is equal to bits stored - 1, and where bits stored is the third value. +Notes: 1. Since the LUT Descriptor (0028,3002) Attribute is multi-valued, in an Explicit VR Transfer Syntax, only one value representation (US or SS) may be specified, even though the first and third values are always by definition interpreted as unsigned. The explicit VR actually used is dictated by the VR needed to represent the second value. + 2. Some implementations have encoded 8 bit entries with 16 bits allocated, padding the high bits; this can be detected by comparing the number of entries specified in the LUT Descriptor with the actual value length of the LUT Data entry. The value length in bytes should equal the number of entries if bits allocated is 8, and be twice as long if bits allocated is 16. + +The LUT Data contains the LUT entry values. +The output range is from 0 to 2n-1 where n is the third value of LUT Descriptor. This range is always unsigned. +
+
+ + Free form text explanation of the meaning of the LUT. + + + LUT Data in this Sequence. + + + Window Center for display. +See C.11.2.1.2 for further explanation. +Required if VOI LUT Sequence (0028,3010) is not present. May be present otherwise. +
Window Center (0028,1050) and Window Width (0028,1051) specify a linear conversion from stored pixel values (after any Modality LUT or Rescale Slope and Intercept specified in the IOD have been applied) to values to be displayed. Window Center contains the input value that is the center of the window. Window Width contains the width of the window. +Note: The terms “window center†and “window width†are not consistently used in practice, nor were they defined in previous versions of the standard. The definitions here are presented for the purpose of defining consistent meanings for identity and threshold transformations while preserving the common practice of using integral values for center and width. + +Window Width (0028,1051) shall always be greater than or equal to 1. +When Window Width (0028,1051) is greater than 1, these Attributes select the range of input values that are to be mapped to the full range of the displayed output. +When Window Width (0028,1051) is equal to 1, they specify a threshold below which input values will be displayed as the minimum output value. +Note: Whether the minimum output value is rendered as black or white may depend on the value of Photometric Interpretation (0028,0004) or the presence of a Presentation LUT Module. + +These Attributes are applied according to the following pseudo-code, where x is the input value, y is an output value with a range from ymin to ymax, c is Window Center (0028,1050) and w is Window Width (0028,1051): + if (x <= c - 0.5 - (w-1)/2), then y = ymin + else if (x > c - 0.5 + (w-1)/2), then y = ymax, + else y = ((x - (c - 0.5)) / (w-1) + 0.5) * (ymax - ymin)+ ymin + +Notes: 1. For the purpose of this definition, a floating point calculation without integer truncation is assumed, though the manner of implementation may vary as long as the result is the same. + 2. The pseudo-code function computes a continuous value over the output range without any discontinuity at the boundaries. The value of 0 for w is expressly forbidden, and the value of 1 for w does not cause division by zero, since the continuous segment of the function will never be reached for that case. + 3. For example, for an output range 0 to 255: + c=2048, w=4096 becomes: + if (x <= 0) then y = 0 + else if (x > 4095) then y = 255 + else y = ((x - 2047.5) / 4095 + 0.5) * (255-0) + 0 + c=2048, w=1 becomes: + if (x <= 2047.5) then y = 0 + else if (x > 2047.5) then y = 255 + else /* not reached */ + + c=0, w=100 becomes: + if (x <= -50) then y = 0 + else if (x > 49) then y = 255 + else y = ((x + 0.5) / 99 + 0.5) * (255-0) + 0 + c=0, w=1 becomes: + if (x <= -0.5) then y = 0 + else if (x > -0.5) then y = 255 + else /* not reached */ + + 4. A Window Center of 2n-1 and a Window Width of 2n selects the range of input values from 0 to 2n-1. This represents an identity VOI LUT transformation in the case where no Modality LUT is specified and the stored pixel data are n bit unsigned integers. + 5. A Window Width of 1 is typically used to represent a "threshold" operation in which those integer input values less than the Window Center are represented as the minimum displayed value and those greater than or equal to the Window Center are represented as the maximum displayed value. A Window Width of 2 will have the same result for integral input values. + 6. The application of Window Center (0028,1050) and Window Width (0028,1051) may select a signed input range. There is no implication that this signed input range is clipped to zero. + 7. The selected input range may exceed the actual range of the input values, thus effectively “compressing†the contrast range of the displayed data into a narrower band of the available contrast range, and “flattening†the appearance. There are no limits to the maximum value of the window width, or to the minimum or maximum value of window level, both of which may exceed the actual or possible range of input values. + 8. Input values "below" the window are displayed as the minimum output value and input values "above" the window are displayed as the maximum output value. This is the common usage of the window operation in medical imaging. There is no provision for an alternative approach in which all values "outside" the window are displayed as the minimum output value. + 9. The output of the Window Center/Width or VOI LUT transformation is either implicitly scaled to the full range of the display device if there is no succeeding transformation defined, or implicitly scaled to the full input range of the succeeding transformation step (such as the Presentation LUT), if present. See C.11.6.1. + 10. Fractional values of Window Center and Window Width are permitted (since the VR of these Attributes is Decimal String), and though they are not often encountered, applications should be prepared to accept them. + +These Attributes shall be used only for Images with Photometric Interpretation (0028,0004) values of MONOCHROME1 and MONOCHROME2. They have no meaning for other Images. +If multiple values are present, both Attributes shall have the same number of values and shall be considered as pairs. Multiple values indicate that multiple alternative views may be presented. +If any VOI LUT Table is included by an Image, a Window Width and Window Center or the VOI LUT Table, but not both, may be applied to the Image for display. Inclusion of both indicates that multiple alternative views may be presented. +If multiple items are present in VOI LUT Sequence (0028,3010), only one may be applied to the Image for display. Multiple items indicate that multiple alternative views may be presented. +If the VOI LUT Module is defined in an IOD and if neither a VOI LUT Sequence nor a Window Width and Window Center are present, then the VOI LUT stage of the grayscale pipeline is defined to be an identity transformation. +Notes: 1. This requirement is specified so that IODs that define a particular output space for the grayscale pipeline, such as P-Values, are not in an undefined state when no VOI LUT Sequence or Window Width and Window Center are present. + 2. Despite the Type 3 requirement for VOI LUT Sequence and Window Center, implementations that render images are expected to implement and apply these transformations when they are present in the image, unless overridden by the user, a presentation state, or a hanging protocol, and to allow the user to select which transformation to apply when multiple transformations are present. + +
+
+ + Window Width for display. See C.11.2.1.2 for further explanation. +Required if Window Center (0028,1050) is sent. +
Window Center (0028,1050) and Window Width (0028,1051) specify a linear conversion from stored pixel values (after any Modality LUT or Rescale Slope and Intercept specified in the IOD have been applied) to values to be displayed. Window Center contains the input value that is the center of the window. Window Width contains the width of the window. +Note: The terms “window center†and “window width†are not consistently used in practice, nor were they defined in previous versions of the standard. The definitions here are presented for the purpose of defining consistent meanings for identity and threshold transformations while preserving the common practice of using integral values for center and width. + +Window Width (0028,1051) shall always be greater than or equal to 1. +When Window Width (0028,1051) is greater than 1, these Attributes select the range of input values that are to be mapped to the full range of the displayed output. +When Window Width (0028,1051) is equal to 1, they specify a threshold below which input values will be displayed as the minimum output value. +Note: Whether the minimum output value is rendered as black or white may depend on the value of Photometric Interpretation (0028,0004) or the presence of a Presentation LUT Module. + +These Attributes are applied according to the following pseudo-code, where x is the input value, y is an output value with a range from ymin to ymax, c is Window Center (0028,1050) and w is Window Width (0028,1051): + if (x <= c - 0.5 - (w-1)/2), then y = ymin + else if (x > c - 0.5 + (w-1)/2), then y = ymax, + else y = ((x - (c - 0.5)) / (w-1) + 0.5) * (ymax - ymin)+ ymin + +Notes: 1. For the purpose of this definition, a floating point calculation without integer truncation is assumed, though the manner of implementation may vary as long as the result is the same. + 2. The pseudo-code function computes a continuous value over the output range without any discontinuity at the boundaries. The value of 0 for w is expressly forbidden, and the value of 1 for w does not cause division by zero, since the continuous segment of the function will never be reached for that case. + 3. For example, for an output range 0 to 255: + c=2048, w=4096 becomes: + if (x <= 0) then y = 0 + else if (x > 4095) then y = 255 + else y = ((x - 2047.5) / 4095 + 0.5) * (255-0) + 0 + c=2048, w=1 becomes: + if (x <= 2047.5) then y = 0 + else if (x > 2047.5) then y = 255 + else /* not reached */ + + c=0, w=100 becomes: + if (x <= -50) then y = 0 + else if (x > 49) then y = 255 + else y = ((x + 0.5) / 99 + 0.5) * (255-0) + 0 + c=0, w=1 becomes: + if (x <= -0.5) then y = 0 + else if (x > -0.5) then y = 255 + else /* not reached */ + + 4. A Window Center of 2n-1 and a Window Width of 2n selects the range of input values from 0 to 2n-1. This represents an identity VOI LUT transformation in the case where no Modality LUT is specified and the stored pixel data are n bit unsigned integers. + 5. A Window Width of 1 is typically used to represent a "threshold" operation in which those integer input values less than the Window Center are represented as the minimum displayed value and those greater than or equal to the Window Center are represented as the maximum displayed value. A Window Width of 2 will have the same result for integral input values. + 6. The application of Window Center (0028,1050) and Window Width (0028,1051) may select a signed input range. There is no implication that this signed input range is clipped to zero. + 7. The selected input range may exceed the actual range of the input values, thus effectively “compressing†the contrast range of the displayed data into a narrower band of the available contrast range, and “flattening†the appearance. There are no limits to the maximum value of the window width, or to the minimum or maximum value of window level, both of which may exceed the actual or possible range of input values. + 8. Input values "below" the window are displayed as the minimum output value and input values "above" the window are displayed as the maximum output value. This is the common usage of the window operation in medical imaging. There is no provision for an alternative approach in which all values "outside" the window are displayed as the minimum output value. + 9. The output of the Window Center/Width or VOI LUT transformation is either implicitly scaled to the full range of the display device if there is no succeeding transformation defined, or implicitly scaled to the full input range of the succeeding transformation step (such as the Presentation LUT), if present. See C.11.6.1. + 10. Fractional values of Window Center and Window Width are permitted (since the VR of these Attributes is Decimal String), and though they are not often encountered, applications should be prepared to accept them. + +These Attributes shall be used only for Images with Photometric Interpretation (0028,0004) values of MONOCHROME1 and MONOCHROME2. They have no meaning for other Images. +If multiple values are present, both Attributes shall have the same number of values and shall be considered as pairs. Multiple values indicate that multiple alternative views may be presented. +If any VOI LUT Table is included by an Image, a Window Width and Window Center or the VOI LUT Table, but not both, may be applied to the Image for display. Inclusion of both indicates that multiple alternative views may be presented. +If multiple items are present in VOI LUT Sequence (0028,3010), only one may be applied to the Image for display. Multiple items indicate that multiple alternative views may be presented. +If the VOI LUT Module is defined in an IOD and if neither a VOI LUT Sequence nor a Window Width and Window Center are present, then the VOI LUT stage of the grayscale pipeline is defined to be an identity transformation. +Notes: 1. This requirement is specified so that IODs that define a particular output space for the grayscale pipeline, such as P-Values, are not in an undefined state when no VOI LUT Sequence or Window Width and Window Center are present. + 2. Despite the Type 3 requirement for VOI LUT Sequence and Window Center, implementations that render images are expected to implement and apply these transformations when they are present in the image, unless overridden by the user, a presentation state, or a hanging protocol, and to allow the user to select which transformation to apply when multiple transformations are present. + +
+
+ + Free form explanation of the meaning of the Window Center and Width. Multiple values correspond to multiple Window Center and Width values. + + + Describes a VOI LUT function to apply to the values of Window Center (0028,1050) and Window Width (0028,1051). +See C.11.2.1.3 for further explanation. +Defined terms: +LINEAR +SIGMOID +When this attribute is not present, the interpretation of the values of Window Center (0028,1050) and Window Width (0028,1051) is linear as in C.11.2.1.2. +
The VOI LUT Function (0028,1056) specifies a potentially non-linear conversion for the output of the (conceptual) Modality LUT values to the input of the (conceptual) Presentation LUT. +The behavior for the value LINEAR is defined in C.11.2.1.2. For all other values, the VOI LUT Function (0028,1056) shall include a unique descriptor of the LUT function to be used. Each descriptor is associated with a bivariate function of Window Center (0028,1050) and Window Width (0028,1051). +If the VOI LUT Function (0028,1056) is present with a value other than LINEAR, the values provided in Window Center (0028,1050) and Window Width (0028,1051) shall not be interpreted as a linear conversion of the (conceptual) Modality LUT values to the input to the (conceptual) Presentation LUT – but as parameters for the function defined by the VOI LUT Function descriptor in (0028,1056). +When defined, each descriptor must provide the functional relationship between the output of the (conceptual) Modality LUT values to the input of the (conceptual) Presentation LUT. +
+
+
+ + + Defines a sequence of Presentation LUTs. Only a single item shall be included in this sequence. + + + Specifies the format of the LUT Data in this Sequence. +Required if Presentation LUT Sequence (2050,0010) +is sent. +See C.11.4.1 for further explanation. +
The three values of the LUT Descriptor (0028,3002) describe the format of the data in LUT Data (0028,3006). +The first value is the number of entries in the lookup table. When the number of table entries is equal to 216 then this value shall be 0. The number of entries shall be equal to the number of possible values in the input. (For 8 bit input will be 256 entries, for 12 bit input it will be 4096 entries) +The second value is the first input value mapped, and shall always be 0. The Value Representation of the second value is always US. This input value is mapped to the first entry in the LUT. Subsequent input values are mapped to the subsequent entries in the LUT Data up to an input value equal to number of entries + first value mapped - 1 which is mapped to the last entry in the LUT Data. There are no input values greater than number of entries – 1. +The third value specifies the number of bits for each entry in the LUT Data. It shall be between 10 and 16 inclusive. The LUT Data shall be stored in a format equivalent to 16 bits allocated where the high bit is equal to bits stored - 1, where bits stored is the third value. +Note: Since the LUT Descriptor (0028,3002) Attribute is multi-valued, in an Explicit VR Transfer Syntax, only one value representation (US or SS) may be specified. Since all three values are always by definition interpreted as unsigned, the explicit VR actually used will always be US. + +LUT Data (0028,3006) contains the LUT entry values, which are P-Values. +The output range is from 0 to 2n-1 where n is the third value of LUT Descriptor. This range is always unsigned. +This range specifies the output range of the P-Values. +
+
+ + Free form text explanation of the meaning of the LUT. + + + LUT Data in this Sequence. + + + Specifies pre-defined Presentation LUT shapes. +Enumerated Values : +IDENTITY = input to the Presentation LUT is in P-Values, no further translation is necessary. +LIN OD = input to Presentation LUT is in linear optical density over the range of Min Density (2010,0120) and Max Density (2010,1030). +Note: LIN OD is only defined for hardcopy devices and is not applicable to softcopy devices. + +
+ + + Defines a sequence of Histograms. +One or more Items may be included in this Sequence. + + + The number of "bins" (entries) in the histogram. + + + The stored pixel value corresponding to the lowest pixel value counted in the first bin. All image pixel values less than this value are not included in the histogram. +Note: The Value Representation of this Attribute is determined by the value of Pixel Representation (0028,0103). + + + The stored pixel value corresponding to the highest pixel value counted in the last bin. All image pixel values greater than this value are not included in the histogram. +Note: The Value Representation of this Attribute is determined by the value of Pixel Representation (0028,0103). + + + The number of consecutive stored pixel values included in a bin. All bins shall be of equal width. + + + Free form text explanation of the meaning of the LUT. + + + Histogram Data encoded as 32 bit unsigned counts of the number of pixel values in each bin. + + + + + Defines a sequence of Presentation LUTs. Only a single item shall be included in this sequence. Required if Presentation LUT Shape (2050,0020) is absent. + + + Specifies the format of the LUT Data in this Sequence. +See C.11.6.1.1 for further explanation. +
The three values of the LUT Descriptor (0028,3002) describe the format of the LUT Data in the corresponding Data Element (0028,3006). +The first value is the number of entries in the lookup table. When the number of table entries is equal to 216 then this value shall be 0. +The second value is the first implicitly scaled input value mapped, and shall always be 0. The Value Representation of the second value is always US. This implicitly scaled input value is mapped to the first entry in the LUT. There are no implicitly scaled input values less than the first value mapped. An implicitly scaled input value one greater than the first value mapped is mapped to the second entry in the LUT Data. Subsequent implicitly scaled input values are mapped to the subsequent entries in the LUT Data up to an implicitly scaled input value equal to number of entries + first value mapped - 1 which is mapped to the last entry in the LUT Data. There are no implicitly scaled input values greater than number of entries + first value mapped. +The third value specifies the number of bits for each entry in the LUT Data. The third value of the LUT Descriptor (0028,3002) shall be between 8 and 16 inclusive. The LUT Data shall be stored in a format equivalent to 8 bits allocated when the number of bits for each entry is 8, and 16 bits allocated when the number of bits for each entry is 16, where the high bit is equal to bits stored - 1, and where bits stored is the third value. +Notes: 1. Since the LUT Descriptor (0028,3002) Attribute is multi-valued, in an Explicit VR Transfer Syntax, only one value representation (US or SS) may be specified. Since all three values are always by definition interpreted as unsigned, the explicit VR actually used will always be US. + 2. Some implementations have encoded 8 bit entries with 16 bits allocated, padding the high bits; this can be detected by comparing the number of entries specified in the LUT Descriptor with the actual value length of the LUT Data entry. The value length in bytes should equal the number of entries if bits allocated is 8, and be twice as long if bits allocated is 16. + +The LUT Data contains the LUT entry values, which are P-Values. +The output range is from 0 to 2n-1 where n is the third value of LUT Descriptor. This range is always unsigned. +This range specifies the output range of the P-Values. +
+
+ + Free form text explanation of the meaning of the LUT. + + + LUT Data in this Sequence. + + + Specifies predefined Presentation LUT transformation. Required if Presentation LUT Sequence (2050,0010) is absent. +Enumerated Values: +IDENTITY - no further translation necessary, input values are P-Values +INVERSE - output values after inversion are P-Values +See C.11.6.1.2. +
A value of INVERSE shall mean the same as a value of IDENTITY, except that the minimum output value shall convey the meaning of the maximum available luminance, and the maximum value shall convey the minimum available luminance. In other words: + P-Value = maximum value - output value + +
+
+
+ + + The layer (defined in Graphic Layer (0070,0002) of the Graphic Layer Module C.10.7) in which the Overlay described in group 60xx shall be displayed. If no layer is specified (zero length) then the overlay shall not be displayed. +Required if Group 60xx is present in the referenced image(s) or the Presentation State instance containing this Module. + + + + + Defines a sequence of VOI LUTs or Window Centers and Widths and to which images and frames they apply. +No more than one VOI LUT Sequence containing a single Item or one pair of Window Center/Width values shall be specified for each image or frame. +One or more Items shall be present. + + + Sequence of Items where each Item provides reference to a selected set of Image SOP Class/SOP Instance pairs that are defined in the Presentation State Relationship Module, to which this VOI LUT or Window Center and Width applies. One or more Items shall be present. +Required if the VOI LUT transformation in this Item does not apply to all the images and frames listed in the Presentation State Relationship Module. + + + + + + + Type of equipment that originally acquired the data. Enumerated Value: +PR = Presentation State +See C.7.3.1.1.1. +
Defined Terms for the Modality (0008,0060) are: + +Retired Defined Terms for the Modality (0008,0060) are: + +Note: 1. The XA modality incorporates the retired modality DS. + 2. The RF modality incorporates the retired modalities CF, DF, VF. + 3. The modality listed in the Modality Data Element (0008,0060) may not match the name of the IOD in which it appears. For example, a SOP instance from XA IOD may list the RF modality when an RF implementation produces an XA object. + 4. The MR modality incorporates the retired modalities MA and MS. + +
+
+
+ + + Date on which this presentation was created. +Note: This date may be different from the date that the DICOM SOP Instance was created, since the presentation state information contained may have been recorded earlier. + + + Time at which this presentation was created. +Note: This time may be different from the time that the DICOM SOP Instance was created, since the presentation state information contained may have been recorded earlier. + + + + + + + + + Sequence of Items where each Item includes the Attributes of one Series to which the Presentation applies. +One or more Items shall be present. + + + Unique identifier of a Series that is part of the Study defined by the Study Instance UID (0020,000D) in the enclosing dataset. +Note: The Study Instance UID (0020,000D) will be that of the presentation state itself, unless the macro is invoked from the Blending Sequence (0070,0402) in the Presentation State Blending Module, in which case it will be explicitly specified. + + + Sequence of Items where each Item provides reference to a selected set of Image SOP Class/SOP Instance pairs to which the Presentation applies that are part of the Study defined by Study Instance UID (0020,000D) and the Series defined by Series Instance UID (0020,000E). One or more Items shall be present. The referenced SOP Class shall be the same for all Images in any Item of this Referenced Series Sequence (0008,1115). + + + + + + A single grayscale unsigned value used to replace those parts of the image occluded by the shutter, when rendered on a monochrome display. The units are specified in P-Values. +Required if the Display Shutter Module or Bitmap Display Shutter Module is present. +Note: The requirement in this module is type 1C which overrides the type 3 in the Display Shutter Module. + + + A color triplet value used to replace those parts of the image occluded by the shutter, when rendered on a color display. The units are specified in PCS-Values, and the value is encoded as CIELab. See C.10.7.1.1. +Required if the Display Shutter Module or Bitmap Display Shutter Module is present and the SOP Class is other than Grayscale Softcopy Presentation State Storage. +Note: The requirement in this module is type 1C, which overrides the type 3 in the Display Shutter and Bitmap Display Shutter Modules. +
Attributes such as Graphic Layer Recommended Display CIELab Value (0070,0401) consist of three unsigned short values: +
+
+
+ + + Required if Mask Module is present. +Only one Item shall be present. +Applicable Frame Range (0028,6102) shall not be included in the Sequence Item. +See C.7.6.10 for a complete definition of the Attributes in the Items of this Sequence other than Mask Operation(0028,6101) and Applicable Frame Range (0028,6102). +Notes: 1. This Sequence is replicated here in order to specify one Item, additional conditions on Mask Operation (0028,6101) and to forbid Applicable Frame Range (0028,6102). +2. The role of Applicable Frame Range (0028,6102) is replaced by Referenced Frame Number (0008,1160). +
Table C.7-16 specifies the Attributes that describe mask operations for a Multi-frame image. +Table C.7-16 +MASK MODULE ATTRIBUTES + +Note: Frame numbers begin at 1. + +
+
+ + Type of mask operation to be performed +Enumerated Values: +AVG_SUB +TID +See C.7.6.10.1 for further explanation. +Note: The requirement in this module is for Enumerated Values which override the requirements of the Mask Module. +
+ + + Specified the number of contrast frames to average together before performing the mask operation. +Required if Mask Frame Numbers (0028,6110) specifies more than one frame (i.e. is multi-valued). +Note: The requirement in this module is conditional and overrides the optional requirements of the Mask Module. + + + Specifies the recommended viewing protocol(s). +Enumerated Value: +SUB = for subtraction with mask images +Required if Mask Subtraction Sequence (0028,6100) is present. +Note: The requirement in this module is type 1C and an Enumerated Value is specified which override the requirements of the Mask Module. + + + + + A Sequence of exactly two Items, one identifying and describing transformations upon a set of underlying grayscale images, and the other identifying and describing transformations upon a set of superimposed grayscale images. See C.11.14.1.1. +
The Blending Sequence (0070,0402) Attribute is used to identify two sets of images, one to be superimposed upon the other. +The sets of images and any subset of the frames therein in the case of multi-frame images are identified by Study, Series, SOP Instance and Frame Number. +This module specifies no explicit relationship (such as pairing or ordering) between the sets of images and frames defined in the first item for the underlying images, and the second item for the superimposed images. This module does not define how the images are spatially related, and what re-sampling, if any, needs to be performed before the images are blended for rendering. +Note: The images in the two sets may share the same Frame of Reference, in which case the rendering application can spatially relate the two sets of images based on their Image Position (Patient) (0020,0032) and Image Orientation (Patient) (0020,0037) Attributes. + Alternatively, a Spatial Registration SOP Instance may exist that relates either two different Frames of Reference, or two sets of images identified by UID and frame. + Whilst the two sets of images may already be spatially co-registered and oriented in the same plane, or even be sampled at the same in-plane and between-plane resolution, this will frequently not be the case. + See PS 3.4 for behavioral requirements that apply to Storage SOP Classes using this Module. + +
+
+ + Whether or not the contents of the Item represent the superimposed or underlying image set. +Enumerated Values: +SUPERIMPOSED +UNDERLYING + + + Unique identifier for the Study that contains the images, which may differ from the Study in which the presentation state is contained. + + + + + Defines a sequence of VOI LUTs or Window Centers and Widths and to which images and frames they apply. +No more than one VOI LUT Sequence containing a single Item or one pair of Window Center/Width values shall be specified for each image or frame. +One or more Items shall be present. +Required if a VOI LUT is to be applied to referenced image(s). + + + Sequence of Items identifying images that are defined in the enclosing Item of the Blending Sequence (0070,0402), to which this VOI LUT or Window Center and Width applies. One or more Items shall be present. +Required if the VOI LUT transformation in this Item does not apply to all the images and frames in the enclosing Item of the Blending Sequence (0070,0402). + + + + + A value from 0.0 to 1.0 indicating the relative opacity of the pixels of the superimposed image, where 1.0 means that pixels of the superimposed image completely replace the pixels of the underlying image, and 0.0 means that the pixels of the underlying image completely replace the pixels of the superimposed image. +See PS 3.4 for a detailed description of the blending operation. + + + A reference to Spatial Registration Instances that may be used to register the underlying and superimposed images. +Zero or more Items may be present. +Note: A Spatial Registration Instance may identify registration between frames of reference, or between explicitly identified images. In the latter case, the list of images referenced by the Presentation State, not the list of images referenced by the Spatial Registration Instance, are to be blended. + + +
+ + + An ICC Profile encoding the transformation of device-dependent color stored pixel values into PCS-Values. + + + + + Uniquely identifies the SOP Class. See C.12.1.1.1 for further explanation. See also PS 3.4. +
The SOP Class UID and SOP Instance UID Attributes are defined for all DICOM IODs. However, they are only encoded in Composite IODs with the Type equal to 1. See C.1.2.3. When encoded they shall be equal to their respective Attributes in the DIMSE Services and the File Meta Information header (see PS 3.10 Media Storage). +
+
+ + Uniquely identifies the SOP Instance. See C.12.1.1.1 for further explanation. See also PS 3.4. +
The SOP Class UID and SOP Instance UID Attributes are defined for all DICOM IODs. However, they are only encoded in Composite IODs with the Type equal to 1. See C.1.2.3. When encoded they shall be equal to their respective Attributes in the DIMSE Services and the File Meta Information header (see PS 3.10 Media Storage). +
+
+ + Character Set that expands or replaces the Basic Graphic Set. +Required if an expanded or replacement character set is used. +See C.12.1.1.2 for Defined Terms. +
Specific Character Set (0008,0005) identifies the Character Set that expands or replaces the Basic Graphic Set (ISO 646) for values of Data Elements that have Value Representation of SH, LO, ST, PN, LT or UT. See PS 3.5. +If the Attribute Specific Character Set (0008,0005) is not present or has only a single value, Code Extension techniques are not used. Defined terms for the Attribute Specific Character Set (0008,0005), when single valued, are derived from the International Registration Number as per ISO 2375 (e.g., ISO_IR 100 for Latin alphabet No. 1). See Table C.12-2. +Table C.12-2 + DEFINED TERMS FOR SINGLE-BYTE CHARACTER SETS WITHOUT CODE EXTENSIONS + +Note: To use the single-byte code table of JIS X0201, the value of attribute Specific Character Set (0008,0005), value 1 should be ISO_IR 13. This means that ISO-IR 13 is designated as the G1 code element which is invoked in the GR area. It should be understood that, in addition, ISO-IR 14 is designated as the G0 code element and this is invoked in the GL area. + +If the attribute Specific Character Set (0008,0005) has more than one value, Code Extension techniques are used and Escape Sequences may be encountered in all character sets. Requirements for the use of Code Extension techniques are specified in PS 3.5. In order to indicate the presence of Code Extension, the Defined Terms for the repertoires have the prefix “ISO 2022â€, e.g., ISO 2022 IR 100 for the Latin Alphabet No. 1. See Table 12-3 and Table 12-4. Table 12-3 describes single-byte character sets for value 1 to value n of the attribute Specific Character Set (0008,0005), and Table 12-4 describes multi-byte character sets for value 2 to value n of the attribute Specific Character Set (0008,0005). +Note: A prefix other than “ISO 2022†may be needed in the future if other Code Extension techniques are adopted. +Table C.12-3 +DEFINED TERMS FOR SINGLE-BYTE CHARACTER SETS WITH CODE EXTENSIONS + +Note: If the attribute Specific Character Set (0008,0005) has more than one value and value 1 is empty, it is assumed that value 1 is ISO 2022 IR 6. + +Table C.12-4 +DEFINED TERMS FOR MULTI-BYTE CHARACTER SETS WITH CODE EXTENSIONS + +There are multi-byte character sets that prohibit the use of Code Extension Techniques. The Unicode character set used in ISO 10646, when encoded in UTF-8, and the GB18030 character set, encoded per the rules of GB18030, both prohibit the use of Code Extension Techniques. These character sets may only be specified as value 1 in the Specific Character Set (0008,0005) attribute and there shall only be one value. The minimal length UTF-8 encoding shall always be used for ISO 10646. +Notes: 1. The ISO standards for 10646 now prohibit the use of anything but the minimum length encoding for UTF-8. UTF-8 permits multiple different encodings, but when used to encode Unicode characters in accordance with ISO 10646-1 and 10646-2 (with extensions) only the minimal encodings are legal. + 2. The representation for the characters in the DICOM Default Character Repertoire is the same single byte value for the Default Character Repertoire, ISO 10646 in UTF-8, and GB18030. It is also the 7-bit US-ASCII encoding. +Table C.12-5 +DEFINED TERMS FOR MULTI-BYTE CHARACTER SETS WITHOUT CODE EXTENSIONS + +
+
+ + Date the SOP Instance was created. + + + Time the SOP Instance was created. + + + Uniquely identifies device which created the SOP Instance. + + + Uniquely identifies a Related General SOP Class for the SOP Class of this Instance. See PS 3.4. + + + The SOP Class in which the Instance was originally encoded, but which has been replaced during a fall-back conversion to the current Related General SOP Class. See PS 3.4. + + + Sequence of items that map values of Coding Scheme Designator (0008,0102) to an external coding system registration, or to a private or local coding scheme. One or more items may be present in the sequence. + + + The value of a Coding Scheme Designator, used in this SOP Instance, which is being mapped. + + + The name of the external registry where further definition of the identified coding scheme may be obtained. Required if coding scheme is registered. +Defined term: HL7 + + + The coding scheme UID identifier. Required if coding scheme is identified by an ISO 8824 object identifier compatible with the UI VR. + + + The coding scheme identifier as defined in an external registry. Required if coding scheme is registered and Coding Scheme UID (0008,010C) is not present. + + + The coding scheme full common name + + + The coding scheme version associated with the Coding Scheme Designator (0008,0102). + + + Name of the organization responsible for the Coding Scheme. May include organizational contact information. + + + Contains the offset from UTC to the timezone for all DA and TM Attributes present in this SOP Instance, and for all DT Attributes present in this SOP Instance that do not contain an explicitly encoded timezone offset. +Encoded as an ASCII string in the format "&ZZXX". The components of this string, from left to right, are & = "+" or "-", and ZZ = Hours and XX = Minutes of offset. Leading space characters shall not be present. +The offset for UTC shall be +0000; -0000 shall not be used. +Notes: 1. This encoding is the same as described in PS 3.5 for the offset component of the DT Value Representation. +2. This Attribute does not apply to values with a DT Value Representation, that contains an explicitly encoded timezone offset. +3. The corrected time may cross a 24 hour boundary. For example, if Local Time = 1.00 a.m. and Offset = +0200, then UTC = 11.00 p.m. (23.00) the day before. +4. The "+" sign may not be omitted. +Time earlier than UTC is expressed as a negative offset. +Note: For example: +UTC = 5.00 a.m. +Local Time = 3.00 a.m. +Offset = -0200 + +The local timezone offset is undefined if this Attribute is absent. + + + Sequence of Items containing descriptive attributes of related equipment which has contributed to the acquisition, creation or modification of the composite instance. +One or more Items may be included in this Sequence. +See C.12.1.1.5 for further explanation. +
Contributing Equipment Sequence (0018,A001) allows equipment to be described which has contributed towards the creation of the composite instance. The general class of contribution is denoted via a coded entry within the Purpose of Reference Code Sequence (0040,A170). +Notes: 1. For example, a post-processing application creating DERIVED images from ORIGINAL images would place its own identification within the Equipment Module and identify the original acquisition equipment as an Item within the Contributing Equipment Sequence (0018,A001). Here, the value of the Purpose of Reference Code Sequence (0040,A170) within the Item would be (109101, DCM, â€Acquisition Equipment"). Image display applications wishing to annotate images with information related to the acquisition environment would prefer to extract such details from the Contributing Equipment Sequence rather than the Equipment Module. + 2. For example, an image fusion application would place its own identification within the Equipment Module and identify each of the original acquisition equipment as separate Items within the Contributing Equipment Sequence (0018,A001). Here, the value of the Purpose of Reference Code Sequence (0040,A170) within each Item would be (109101, DCM, â€Acquisition Equipment"). + 3. For example, a post-processing application creating DERIVED images from other DERIVED images would place its own identification within the Equipment Module and add the source equipment as an additional Item within the Contributing Equipment Sequence (0018,A001). Here, the value of the Purpose of Reference Code Sequence (0040,A170) within the Item would be (109102, DCM, â€Processing Equipment"). + 4. For example, a gateway device that coerces attributes of existing composite instances (without creating new composite instances) would retain information about the creating equipment within the Equipment Module and provide its own identification as an Item within the Contributing Equipment Sequence (0018,A001). Here, the value of the Purpose of Reference Code Sequence (0040,A170) within the Item would be (109103, DCM, â€Modifying Equipment"). + +
+
+ + Describes the purpose for which the related equipment is being reference. Only a single Item shall be permitted in this sequence. +See C.12.1.1.5 for further explanation. +
Contributing Equipment Sequence (0018,A001) allows equipment to be described which has contributed towards the creation of the composite instance. The general class of contribution is denoted via a coded entry within the Purpose of Reference Code Sequence (0040,A170). +Notes: 1. For example, a post-processing application creating DERIVED images from ORIGINAL images would place its own identification within the Equipment Module and identify the original acquisition equipment as an Item within the Contributing Equipment Sequence (0018,A001). Here, the value of the Purpose of Reference Code Sequence (0040,A170) within the Item would be (109101, DCM, â€Acquisition Equipment"). Image display applications wishing to annotate images with information related to the acquisition environment would prefer to extract such details from the Contributing Equipment Sequence rather than the Equipment Module. + 2. For example, an image fusion application would place its own identification within the Equipment Module and identify each of the original acquisition equipment as separate Items within the Contributing Equipment Sequence (0018,A001). Here, the value of the Purpose of Reference Code Sequence (0040,A170) within each Item would be (109101, DCM, â€Acquisition Equipment"). + 3. For example, a post-processing application creating DERIVED images from other DERIVED images would place its own identification within the Equipment Module and add the source equipment as an additional Item within the Contributing Equipment Sequence (0018,A001). Here, the value of the Purpose of Reference Code Sequence (0040,A170) within the Item would be (109102, DCM, â€Processing Equipment"). + 4. For example, a gateway device that coerces attributes of existing composite instances (without creating new composite instances) would retain information about the creating equipment within the Equipment Module and provide its own identification as an Item within the Contributing Equipment Sequence (0018,A001). Here, the value of the Purpose of Reference Code Sequence (0040,A170) within the Item would be (109103, DCM, â€Modifying Equipment"). + +
+
+ + + Manufacturer of the equipment that contributed to the composite instance. + + + Institution where the equipment that contributed to the composite instance is located. + + + Address of the institution where the equipment that contributed to the composite instance is located. + + + User defined name identifying the machine that contributed to the composite instance. + + + Department in the institution where the equipment that contributed to the composite instance is located. + + + Manufacturer's model name of the equipment that contributed to the composite instance. + + + Manufacturer's serial number of the equipment that contributed to the composite instance. + + + Manufacturer's designation of the software version of the equipment that contributed to the composite instance. + + + The inherent limiting resolution in mm of the acquisition equipment for high contrast objects for the data gathering and reconstruction technique chosen. If variable across the images of the series, the value at the image center. + + + Date when the image acquisition device calibration was last changed in any way. Multiple entries may be used for additional calibrations at other times. See C.7.5.1.1.1 for further explanation. +
Date of Last Calibration (0018,1200) and Time of Last Calibration (0018,1201) are used to convey the date and time of calibration. The Attribute Date of Last Calibration (0018,1200) may be supported alone, however, Time of Last Calibration (0018,1201) Attribute has no meaning unless Attribute Date of Last Calibration (0018,1200) is also supported. The order for each Attribute shall be from the oldest date/time to the most recent date/time. When the Attributes are both supported they shall be provided as pairs. +
+
+ + Time when the image acquisition device calibration was last changed in any way. Multiple entries may be used. See C.7.5.1.1.1 for further explanation. +
Date of Last Calibration (0018,1200) and Time of Last Calibration (0018,1201) are used to convey the date and time of calibration. The Attribute Date of Last Calibration (0018,1200) may be supported alone, however, Time of Last Calibration (0018,1201) Attribute has no meaning unless Attribute Date of Last Calibration (0018,1200) is also supported. The order for each Attribute shall be from the oldest date/time to the most recent date/time. When the Attributes are both supported they shall be provided as pairs. +
+
+ + The Date & Time when the equipment contributed to the composite instance. + + + Description of the contribution the equipment made to the composite instance. + + + A number that identifies this Composite object instance. + + + A flag that indicates the storage status of the SOP Instance. Not Specified (NS) implies that this SOP Instance has no special storage status, and hence no special actions need be taken. Original (OR) implies that this is the primary SOP instance for the purpose of storage, but that it has not yet been authorized for diagnostic use. Authorized Original (AO) implies that this is the primary SOP instance for the purpose of storage, which has been authorized for diagnostic use. Any copies of an Authorized Original should be given the status of Authorized Copy. Authorized Copy (AC) implies that this is a copy of an Authorized Original SOP Instance. +Enumerated Values: +NS, OR, AO, AC +Note: Proper use of these flags is specified in Security Profiles. Implementations that do not conform to such Security Profiles may not necessarily handle these flags properly. + + + The date and time when the SOP Instance Status (0100,0410) was set to AO. + + + Any comments associated with the setting of the SOP Instance Status (0100,0410) to AO. + + + The certification number issued to the Application Entity that set the SOP Instance Status (0100,0410) to AO. + + + + Sequence of Items containing encrypted DICOM data. One or more Items shall be present. Required if application level confidentiality is needed and certain recipients are allowed to decrypt all or portions of the Encrypted Attributes Data Set. See C.12.1.1.4.1. +
Each Item of the Encrypted Attributes Sequence (0400,0500) contains an encrypted DICOM dataset containing a single instance of the Encrypted Attributes Data Set (Table C.12-7). It also contains encrypted content-encryption keys for one or more recipients. The encoding is based on the Enveloped-data Content Type of the Cryptographic Message Syntax defined in RFC 2630. It allows to encrypt the embedded Data Set for an arbitrary number of recipients using any of the three key management techniques supported by RFC 2630: +
+
+ + Transfer Syntax used to encode the encrypted content. Only Transfer Syntaxes that explicitly include the VR and use Little Endian encoding shall be used. + + + Encrypted data. See C.12.1.1.4.2. +
The Encrypted Content (0400,0520) Attribute contains an Enveloped-data content type of the cryptographic message syntax defined in RFC 2630. The encrypted content of the Enveloped-data content type is an instance of the Encrypted Attributes Data Set as shown in Table C.12-7 (i.e., it is a Sequence with a single Item), encoded with the Transfer Syntax specified by the Encrypted Content Transfer Syntax UID (0400,0510) Attribute. Figure C.12-2 shows an example of how the Encrypted Content is encoded. The exact use of this Data Set is defined in the Attribute Confidentiality Profiles in PS 3.15. +Since the de-identified SOP Instance is a significantly altered version of the original Data Set, it is a new SOP Instance, with a SOP Instance UID that differs from the original Data Set. +Note: 1. Content encryption may require that the content (the DICOM Data Set) be padded to a multiple of some block size. This shall be performed according to the Content-encryption Process defined in RFC-2630. + 2. Any standard or private Transfer Syntax may be specified in Encrypted Content Transfer Syntax UID (0400,0510) unless encoding is performed in accordance with an Attribute Confidentiality Profile that specifies additional restrictions. In general, an application entity decoding the Encrypted Attributes Sequence may not assume any particular Transfer Syntax or set of Transfer Syntaxes to be used with Encrypted Content Transfer Syntax UID (0400,0510). + 3. For certain applications it might be necessary to “blacken†(remove) identifying information that is burned in to the image pixel data. The Encrypted Attributes Data Set does not specify a means of restoring the original image information without the complete image pixel data being encoded inside the Modified Attributes Sequence (0400,0550). If access to the original, unmodified pixel data is required and the image pixel data cannot be replicated inside the Modified Attributes Sequence (0400,0550) due to resource considerations, the SOP Instance UID may be used to locate the original SOP Instance from which the de-identified version was derived. + 4. There is no guarantee that the original SOP Instance can be reconstructed from the data in Encrypted Content. If access to the original data is required, the (de-encrypted) UIDs may be used to locate the original SOP Instance from which the de-identified version was derived. + +Table C.12-7 +ENCRYPTED ATTRIBUTES DATA SET ATTRIBUTES + +
+
+ + Sequence of Items containing all attributes that were removed or replaced by other values in the main dataset. +One or more Items may be permitted in this sequence. + + + The source that provided the SOP Instance prior to the removal or replacement of the values. For example, this might be the Institution from which imported SOP Instances were received. + + + Date and time the attributes were removed and/or replaced. + + + Identification of the system which removed and/or replaced the attributes. + + + Reason for the attribute modification. Defined terms are: +COERCE = Replace values of attributes such as Patient Name, ID, Accession Number, for example, during import of media from an external institution, or reconciliation against a master patient index. +CORRECT = Replace incorrect values, such as Patient Name or ID, for example, when incorrect worklist item was chosen or operator input error. + + + Sequence containing a single item that contains all the Attributes, with their previous values, that were modified or removed from the main data set. + + + + Sequence of items defining mapping and/or access mechanism for HL7 Structured Documents referenced from the current SOP Instance. One or more Items may be included in this sequence. +See C.12.1.1.6. +Required if HL7 Structured Documents are referenced within the Instance. +
The HL7 Structured Document Reference Sequence (0040,A390) identifies instances of Structured Documents defined under an HL7 standard. The HL7 standards that define such documents include the Clinical Document Architecture (CDA) and Structured Product Labeling (SPL) standards. +References to HL7 Structured Documents from within DICOM SOP Instances shall be encoded with a SOP Class UID and SOP Instance UID pair. The Abstract Syntax of an HL7 Structured Document is defined by its Hierarchical Message Description; the Object Identifier of the Hierarchical Message Description shall be used as the SOP Class UID for the Structured Document reference. +Notes: 1. The Hierarchical Message Description Object Identifiers are specified in the HL7 OID Registry (http://hl7.org/oid). The HL7 OIDs for these types of documents are: + CDA Release 1 2.16.840.1.113883.1.7.1 + CDA Release 2 2.16.840.1.113883.1.7.2 + SPL Release 1 2.16.840.1.113883.1.7.3 + 2. The Hierarchical Message Description Object Identifiers do not imply a network or media storage service, as do SOP Class UIDs. However, they do identify the Abstract Syntax, similar to SOP Class UIDs. + +The HL7 Structured Document instances are natively identified by an attribute using the Instance Identifier (II) Data Type, as defined in HL7 v3 Data Types - Abstract Specification. A UID as defined by the DICOM UI Value Representation is a valid identifier under the II Data Type; however, an II attribute is not always encodable as a UID. Therefore a UID shall be constructed for use within the DICOM Data Set that can be mapped to the native instance identifier encoded as an HL7 II Data Type. This mapping is performed through the combination of the local Referenced SOP Instance UID (0008,1155) and the HL7 Instance Identifier (0040,E001) attributes in the HL7 Structured Document Reference Sequence (0040,A390). +Notes: 1. An HL7 II is not encodable as a UID if it exceeds 64 characters, or if it includes an extension. See HL7 v3 DT R1. + 2. Even though an II may contain just a UID, applications should take care to use the II specified in HL7 Instance Identifier (0040,E001) to access the Structured Document. If the instance identifier used natively within the referenced document is encodable using the UI VR, i.e., it is an ISO 8824 OID up to 64 characters without an extension, it is recommended to be used as the Referenced SOP Instance UID within the current Instance. + 3. The Referenced SOP Instance UID used to reference a particular HL7 Structured Document is not necessarily the same in all DICOM Instances. For example, two SR Documents may internally use different SOP Instance UIDs to reference the same HL7 Structured Document, but they will each contain a mapping to the same HL7 Instance Identifier as the external identifier. + 4. The HL7 Instance Identifier is encoded in attribute (0040,E001) as a serialization of the UID and Extension (if any) separated by a caret character. This is the same format adopted in the IHE Cross-Enterprise Document Sharing (XDS) profile (see http://www.ihe.net). + 5. See Figure C.12-3. + + +Figure C.12-3 HL7 Structured Document References + +
+
+ + Unique identifier for the class of HL7 Structured Document. + + + Unique identifier for the HL7 Structured Document as used in DICOM instance references. + + + Instance Identifier of the referenced HL7 Structured Document, encoded as a UID (OID or UUID), concatenated with a caret ("^") and Extension value (if Extension is present in Instance Identifier). + + + Retrieval access path to HL7 Structured Document. Includes fully specified scheme, authority, path, and query in accordance with RFC 2396 + +
+ + + A sequence of one or more items that describe the parameters used to calculate a MAC for use in Digital Signatures. + + + A number, unique within this SOP Instance, used to identify this MAC Parameters Sequence (4FFE,0001) item from an Item of the Digital Signatures Sequence (FFFA,FFFA). + + + The Transfer Syntax UID used to encode the values of the Data Elements included in the MAC calculation. Only Transfer Syntaxes that explicitly include the VR and use Little Endian encoding shall be used. +Notes: Certain Transfer Syntaxes, particularly those that are used with compressed data, allow the fragmentation of the pixel data to change. If such fragmentation changes, Digital Signatures generated with such Transfer Syntaxes could become invalid. + + + The algorithm used in generating the MAC to be encrypted to form the Digital Signature. +Defined Terms: RIPEMD160 +MD5 +SHA1 +. +Note: Digital Signature Security Profiles (see PS 3.15) may require the use of a restricted subset of these terms. + + + A list of Data Element Tags in the order they appear in the Data Set which identify the Data Elements used in creating the MAC for the Digital Signature. See Section C.12.1.1.3.1.1. +
The Data Elements Signed Attribute shall list the Tags of the Data Elements that are included in the MAC calculation. The Tags listed shall reference Data Elements at the same level as the Mac Parameters Sequence (4FFE,0001) Data Element in which the Data Elements Signed Attribute appears. Tags included in Data Elements Signed shall be listed in the order in which they appear within the Data Set. +The following Data Elements shall not be included either implicitly or explicitly in the list of Tags in Data Elements Signed, nor included as part of the MAC calculation: +
+
+ + Sequence holding Digital Signatures. One or more items may be included in this sequence. + + + A number used to identify which MAC Parameters Sequence item was used in the calculation of this Digital Signature. + + + A UID that can be used to uniquely reference this signature. + + + The date and time the Digital Signature was created. The time shall include an offset (i.e., time zone indication) from Coordinated Universal Time. +Note: This is not a certified timestamp, and hence is not completely verifiable. An application can compare this date and time with those of other signatures and the validity date of the certificate to gain confidence in the veracity of this date and time. + + + The type of certificate used in (0400,0115). +Defined Term: X509_1993_SIG +Note: Digital Signature Security Profiles (see PS 3.15) may require the use of a restricted subset of these terms. + + + A certificate that holds the identity of the entity producing this Digital Signature, that entity's public key or key identifier, and the algorithm and associated parameters with which that public key is to be used. Algorithms allowed are specified in Digital Signature Security Profiles (see PS 3.15). +Notes: 1. As technology advances, additional encryption algorithms may be allowed in future versions. Implementations should take this possibility into account. +2. When symmetric encryption is used, the certificate merely identifies which key was used by which entity, but not the actual key itself. Some other means (e.g., a trusted third party) must be used to obtain the key. + + + The MAC generated as described in Section C.12.1.1.3.1.1 and encrypted using the algorithm, parameters, and private key associated with the Certificate of the Signer (0400,0115). See Section C.12.1.1.3.1.2. +
To generate the MAC, Data Elements referenced either explicitly or implicitly by the Tags in the Data Elements Signed list shall be encoded using the Transfer Syntax identified by the MAC Calculation Transfer Syntax UID (0400,0010) of the MAC Parameters Sequence item where the Data Elements Signed Attribute appears. Data shall be formed into a byte stream and presented to the MAC Algorithm for computation of the MAC according to the following rules: +For all Data Elements except those with a VR of SQ or with a VR of OB with an undefined length, all Data Element fields, including the Tag, the VR, the reserved field (if any), the Value Length, and the Value, shall be placed into the byte stream in the order encountered. +For Data Elements with a VR of SQ or with a VR of OB with an undefined length, the Tag, the VR, and the reserved field are placed into the byte stream. The Value Length shall not be included. This is followed by each Item Tag in the order encountered, without including the Value Length, followed by the contents of the Value for that item. In the case of an Item within a Data Element whose VR is SQ, these rules are applied recursively to all of the Data Elements within the Value of that Item. After all the Items have been incorporate into the byte stream, a Sequence Delimitation Item Tag (FFFE,E0DD) shall be added to the byte stream presented to the MAC Algorithm, regardless of whether or not it was originally present. +Note: Since the Value Length of Data Elements with a VR of SQ can be either explicit or undefined, the Value Lengths of such Data Elements are left out of the MAC calculation. Similarly, the Value Length of Data Elements with a VR of OB with an undefined length are also left out so that they are handled consistently. If such Data Elements do come with undefined lengths, including the Item Tags that separate the Items or fragments insures that Data Elements cannot be moved between Items or Fragments without compromising the Digital Signature. For those Data Elements with explicit lengths, if the length of an item changes, the added or removed portions would also impact the MAC calculation, so it is not necessary to include explicit lengths in the MAC calculation. It is possible that including the Value Lengths could make cryptoanalysis easier. + +After the fields of all the Data Elements in the Data Elements Signed list have been placed into the byte stream presented to the MAC Algorithm according to the above rules, all of the Data Elements within the Digital Signatures Sequence item except the Certificate of Signer (0400,0115), Signature (0400,0120), Certified Timestamp Type (0400,0305), and Certified Timestamp (0400,0310) shall also be encoded according to the above rules, and presented to the MAC algorithm (i.e., the Attributes of the Digital Signature Sequence Item for this particular Digital Signature are also implicitly included in the list of Data Elements Signed, except as noted above). +The resulting MAC code after processing this byte stream by the MAC Algorithm is then encrypted as specified in the Certificate of Signer and placed in the Value of the Signature Data Element. +Notes: 1. The Transfer Syntax used in the MAC calculation may differ from the Transfer Syntax used to exchange the Data Set. + 2. Digital Signatures require explicit VR in order to calculate the MAC. An Application Entity which receives a Data Set with an implicit VR Transfer Syntax may not be able to verify Digital Signatures that include Private Data Elements or Data Elements unknown to that Application Entity.This also true of any Data Elements whose VR is UN. Without knowledge of the Value Representation, the receiving Application Entity would be unable to perform proper byte swapping or be able to properly parse sequences in order to generate a MAC. + 3. If more than one entity signs, each Digital Signature would appear in its own Digital Signatures Sequence item. The Digital Signatures may or may not share the same MAC Parameters Sequence item. +4. The notion of a notary public (i.e., someone who verifies the identity of the signer) for Digital Signatures is partially filled by the authority that issued the Certificate of Signer. + +
+
+ + The type of certified timestamp used in the Certified Timestamp (0400,0310) Attribute. Required if Certified Timestamp (0400,0310) is present. +Defined Terms: CMS_TSP - Internet X.509 Public Key Infrastructure Time Stamp Protocol +Note: Digital Signature Security Profiles (see PS 3.15) may require the use of a restricted subset of these terms. + + + A certified timestamp of the Digital Signature (0400,0120) Attribute Value, which shall be obtained when the Digital Signature is created. See Section C.12.1.1.3.1.3. +
To generate a certified timestamp, the Value of the Signature (0400,0120) Attribute is sent to a third party, as specified by the protocol referred to by the Certified Timestamp Type (0400,0305) Attribute. The third party then generates and returns a certified timestamp in the form specified by that protocol. The certified timestamp returned by the third party is encoded as a stream of bytes in the Certified Timestamp Attribute. +Note: The timestamp protocol may be specified by a Profile in PS 3.15. + +
+
+ + The purpose of this Digital Signature. Only a single Item shall be permitted in this sequence. + + +
+ + + Sequence of Items containing all Attributes that were removed or replaced by "dummy values" in the main dataset during de-identification of the SOP instance. Upon reversal of the de-identification process, the Attributes are copied back into the main dataset, replacing any dummy values that might have been created. Only a single Item shall be present. + + + + + + + Sequence of items each identifying a Study other than the Study of which this Instance is a part, which Studies contain Instances that are referenced elsewhere in this Instance. One or more Items shall be present. Required if this Instance references Instances in other Studies. + + + Unique identifier of the Study containing the referenced Instances. + + + + + + Number of copies to be printed for each film of the film session. + + + Specifies the priority of the print job. +Enumerated Values: +HIGH +MED +LOW + + + Type of medium on which the print job will be printed. Defined Terms: +PAPER +CLEAR FILM +BLUE FILM +MAMMO CLEAR FILM +MAMMO BLUE FILM + + + Film destination. Defined Terms: +MAGAZINE = the exposed film is stored in film magazine +PROCESSOR = the exposed film is developed in film processor +BIN_i = the exposed film is deposited in a sorter bin where "I" represents the bin number. Film sorter BINs shall be numbered sequentially starting from one and no maxiumu is placed on the number of BINs. The encoding of the BIN number shall not contain leading zeros. + + + Human readable label that identifies the film session + + + Amount of memory allocated for the film session. Value is expressed in KB + + + Identification of the owner of the film session + + + + + A Sequence which provides references to a set of Film Box SOP Class/Instance pairs. Zero or more Items may be included in this Sequence. + + + + + + Type of image display format. Enumerated Values: +STANDARD\C,R : film contains equal size rectangular image boxes with R rows of image boxes and C columns of image boxes; C and R are integers. +ROW\R1,R2,R3, etc. : film contains rows with equal size rectangular image boxes with R1 image boxes in the first row, R2 image boxes in second row, R3 image boxes in third row, etc.; R1, R2, R3, etc. are integers. +COL\C1,C2,C3, etc.: film contains columns with equal size rectangular image boxes with C1 image boxes in the first column, C2 image boxes in second column, C3 image boxes in third column, etc.; C1, C2, C3, etc. are integers. +SLIDE : film contains 35mm slides; the number of slides for a particular film size is configuration dependent. +SUPERSLIDE : film contains 40mm slides; the number of slides for a particular film size is configuration dependent. +CUSTOM\i : film contains a customized ordering of rectangular image boxes; i identifies the image display format; the definition of the image display formats is defined in the Conformance Statement; i is an integer + + + Identification of annotation display format. The definition of the annotation display formats and the annotation box position sequence are defined in the Conformance Statement + + + Film orientation. Enumerated Values: +PORTRAIT = vertical film position +LANDSCAPE = horizontal film position + + + Film size identification. Defined Terms: +8INX10IN +8_5INX11IN +10INX12IN +10INX14IN +11INX14IN +11INX17IN +14INX14IN +14INX17IN +24CMX24CM +24CMX30CM +A4 +A3 +Note: 10INX14IN corresponds with 25.7CMX36.4CM +A4 corresponds with 210 x 297 millimeters +A3 corresponds with 297 x 420 millimeters + + + Interpolation type by which the printer magnifies or decimates the image in order to fit the image in the image box on film. Defined Terms: +REPLICATE +BILINEAR +CUBIC +NONE + + + Further specifies the type of the interpolation function. Values are defined in Conformance Statement. Only valid for Magnification Type (2010,0060) = CUBIC + + + Density of the film areas surrounding and between images on the film. Defined Terms: +BLACK +WHITE +i where i represents the desired density in hundredths of OD (e.g. 150 corresponds with 1.5 OD) + + + Density of the image box area on the film that contains no image. Defined Terms: +BLACK +WHITE +i where i represents the desired density in hundredths of OD (e.g. 150 corresponds with 1.5 OD) + + + Minimum density of the images on the film, expressed in hundredths of OD. If Min Density is lower than minimum printer density than Min Density is set to minimum printer density. + + + Maximum density of the images on the film, expressed in hundredths of OD. If Max Density is higher than maximum printer density than Max Density is set to maximum printer density. + + + Specifies whether a trim box shall be printed surrounding each image on the film. Enumerated Values: +YES +NO + + + Character string that contains either the ID of the printer configuration table that contains a set of values for implementation specific print parameters (e.g. perception LUT related parameters) or one or more configuration data values, encoded as characters. If there are multiple configuration data values encoded in the string, they shall be separated by backslashes. The definition of values shall be contained in the SCP's Conformance Statement. +Defined Terms: +CS000-CS999: Implementation specific curve type. +Note: It is recommended that for SCPs, CS000 represent the lowest contrast and CS999 the highest contrast levels available. + + + Luminance of lightbox illuminating a piece of transmissive film, or for the case of reflective media, luminance obtainable from diffuse reflection of the illumination present. Expressed as L0, in candelas per square meter (cd/m2). + + + For transmissive film, luminance contribution due to reflected ambient light. Expressed as La, in candelas per square meter (cd/m2). + + + Specifies the resolution at which images in this Film Box are to be printed. +Defined Terms: +STANDARD = approximately 4k x 5k printable pixels on a 14 x 17 inch film +HIGH = Approximately twice the resolution of STANDARD. + + + An ICC Profile encoding the transformation of device-dependent color stored pixel values into PCS-Values. See C.11.15. +Note. This is an Input Device Profile that describes the characteristics of the pixel data in the film box, not an Output Device Profile that might describe the characteristics of the Print SCP. +
Table C.11.15-1 contains Attributes that identify and describe an ICC Profile. +Table C.11.15-1 +ICC PROFILE MODULE ATTRIBUTES + +
+
+
+ + + A sequence which provides references to a Film Session SOP Class/Instance pairs. Only a single Item shall be permitted in this Sequence. + + + + A sequence which provides references to a set of Image Box SOP Class/Instance pairs. One or more Items may be included in this Sequence. + + + + A Sequence which provides references to a set of Basic Annotation Box SOP Class/Instance pairs. Zero or more Items may be included in this Sequence. + + + + A sequence which provides references to a Presentation LUT related SOP Class/Instance pairs. Only a single Item shall be included in this sequence. + + + + + + The position of the image on the film, based on Image Display Format (2010,0010). See C.13.5.1 for specification. +
The position of the image on the film; the encoding of the image position sequence is based on the selected Image Display Format (2010,0010). The image position sequence shall be increasing order beginning with the value 1. Image Box Position (2020,0010) is defined as follows: +- STANDARD display format: image box sequence shall be major row order (from left-to-right and from top-to-bottom); top left image position shall be equal to 1. +- ROW display format: image box sequence shall be major row order (from left-to-right and from top-to-bottom); top left image position shall be set to 1. +- COL display format: image box sequence shall be major column order (from top-to-bottom and from left-to-right); top left image position shall be equal to 1. +- SLIDE display format: image box sequence shall be major row order (from left-to-right and from top-to-bottom); top left image position shall be set to 1. +- SUPERSLIDE display format: image box sequence shall be major row order (from left-to-right and from top-to-bottom); top left image position shall be set to 1. +- CUSTOM STANDARD display format: image box sequence shall be defined in the Conformance Statement; top left image position shall be set to 1. + +
+
+ + Specifies whether minimum pixel values (after VOI LUT transformation) are to printed black or white. Enumerated Values: +NORMAL = pixels shall be printed as specified by the Photometric Interpretation (0028,0004) +REVERSE = pixels shall be printed with the opposite polarity as specified by the Photometric Interpretation (0028,0004) +If Polarity (2020,0020) is not specified by the SCU, the SCP shall print with NORMAL polarity. + + + Description is the same as in Table C.13-3. Overrides the Magnification Type specified for the Film Box + + + Description is the same as in Table C.13-3. Overrides the Smoothing Type specified for the Film Box + + + See Table C.13-3 for description of Configuration Information. + + + Width (x-dimension) in mm of the image to be printed. This value overrides the size that corresponds with optimal filling of the Image Box. + + + Specifies whether image pixels are to be decimated or cropped if the image rows or columns is greater than the available printable pixels in an Image Box. +Decimation means that a magnification factor <1 is applied to the image. The method of decimation shall be that specified by Magnification Type (2010,0060) or the SCP default if not specified +Cropping means that some image rows and/or columns are deleted before printing +Enumerated Values: +DECIMATE = a magnification factor <1 to be applied to the image. +CROP = some image rows and/or columns are to be deleted before printing. The specific algorithm for cropping shall be described in the SCP Conformance Statement. +FAIL = the SCP shall not crop or decimate + + + A sequence which provides the content of the grayscale image pixel data to be printed. This is a specialization of the Image Pixel Module defined in C.7.6.3 of this part. It is encoded as a sequence of Attributes of the Image Pixel Module. Zero or one Item may be included in this Sequence. +See PS 3.4 for further description. + + + See C.7.6.3 for description of Image Pixel Module. Enumerated Value: 1 +
Table C.7-11a describes the Image Pixel Module. +Table C.7-11a +IMAGE PIXEL MODULE ATTRIBUTES + +Table C.7-11b specifies the common attributes that describe the pixel data of the image. + +Table C.7-11b +IMAGE PIXEL MACRO ATTRIBUTES + +
+
+ + See C.7.6.3 for description of Image Pixel Module. Enumerated Values: +MONOCHROME1 +MONOCHROME2 +
Table C.7-11a describes the Image Pixel Module. +Table C.7-11a +IMAGE PIXEL MODULE ATTRIBUTES + +Table C.7-11b specifies the common attributes that describe the pixel data of the image. + +Table C.7-11b +IMAGE PIXEL MACRO ATTRIBUTES + +
+
+ + See C.7.6.3 for description of Image Pixel Module +
Table C.7-11a describes the Image Pixel Module. +Table C.7-11a +IMAGE PIXEL MODULE ATTRIBUTES + +Table C.7-11b specifies the common attributes that describe the pixel data of the image. + +Table C.7-11b +IMAGE PIXEL MACRO ATTRIBUTES + +
+
+ + See C.7.6.3 for description of Image Pixel Module +
Table C.7-11a describes the Image Pixel Module. +Table C.7-11a +IMAGE PIXEL MODULE ATTRIBUTES + +Table C.7-11b specifies the common attributes that describe the pixel data of the image. + +Table C.7-11b +IMAGE PIXEL MACRO ATTRIBUTES + +
+
+ + See C.7.6.3 for description of Image Pixel Module +
Table C.7-11a describes the Image Pixel Module. +Table C.7-11a +IMAGE PIXEL MODULE ATTRIBUTES + +Table C.7-11b specifies the common attributes that describe the pixel data of the image. + +Table C.7-11b +IMAGE PIXEL MACRO ATTRIBUTES + +
+
+ + See C.7.6.3 for description of Image Pixel Module. Enumerated Values: +8 (if Bits Stored = 8) +16 (if Bits Stored = 12) +
Table C.7-11a describes the Image Pixel Module. +Table C.7-11a +IMAGE PIXEL MODULE ATTRIBUTES + +Table C.7-11b specifies the common attributes that describe the pixel data of the image. + +Table C.7-11b +IMAGE PIXEL MACRO ATTRIBUTES + +
+
+ + See C.7.6.3 for description of Image Pixel Module. Enumerated Values: +8 +12 +
Table C.7-11a describes the Image Pixel Module. +Table C.7-11a +IMAGE PIXEL MODULE ATTRIBUTES + +Table C.7-11b specifies the common attributes that describe the pixel data of the image. + +Table C.7-11b +IMAGE PIXEL MACRO ATTRIBUTES + +
+
+ + See C.7.6.3 for description of Image Pixel Module. Enumerated Values: +7 (if BITS STORED = 8) +11 (if BITS STORED = 12) +
Table C.7-11a describes the Image Pixel Module. +Table C.7-11a +IMAGE PIXEL MODULE ATTRIBUTES + +Table C.7-11b specifies the common attributes that describe the pixel data of the image. + +Table C.7-11b +IMAGE PIXEL MACRO ATTRIBUTES + +
+
+ + See C.7.6.3 for description of Image Pixel Module. Enumerated Value: +0 (unsigned integer) +
Table C.7-11a describes the Image Pixel Module. +Table C.7-11a +IMAGE PIXEL MODULE ATTRIBUTES + +Table C.7-11b specifies the common attributes that describe the pixel data of the image. + +Table C.7-11b +IMAGE PIXEL MACRO ATTRIBUTES + +
+
+ + See C.7.6.3 for description of Image Pixel Module +
Table C.7-11a describes the Image Pixel Module. +Table C.7-11a +IMAGE PIXEL MODULE ATTRIBUTES + +Table C.7-11b specifies the common attributes that describe the pixel data of the image. + +Table C.7-11b +IMAGE PIXEL MACRO ATTRIBUTES + +
+
+ + A sequence which provides the content of the color image pixel data to be printed. It is a specialization of the Image Pixel Module defined in C.7.6.3 of this part. It is encoded as a sequence of Attributes of the Image Pixel Module. Zero or one Item may be included in this Sequence. +See PS 3.4 for further description. + + + See C.7.6.3 for description of Image Pixel Module. Enumerated Value: +3 +
Table C.7-11a describes the Image Pixel Module. +Table C.7-11a +IMAGE PIXEL MODULE ATTRIBUTES + +Table C.7-11b specifies the common attributes that describe the pixel data of the image. + +Table C.7-11b +IMAGE PIXEL MACRO ATTRIBUTES + +
+
+ + See C.7.6.3 for description of Image Pixel Module. Enumerated Value: +RGB +
Table C.7-11a describes the Image Pixel Module. +Table C.7-11a +IMAGE PIXEL MODULE ATTRIBUTES + +Table C.7-11b specifies the common attributes that describe the pixel data of the image. + +Table C.7-11b +IMAGE PIXEL MACRO ATTRIBUTES + +
+
+ + See C.7.6.3 for description of Image Pixel Module. Enumerated Value: +1 (frame interleave) +
Table C.7-11a describes the Image Pixel Module. +Table C.7-11a +IMAGE PIXEL MODULE ATTRIBUTES + +Table C.7-11b specifies the common attributes that describe the pixel data of the image. + +Table C.7-11b +IMAGE PIXEL MACRO ATTRIBUTES + +
+
+ + See C.7.6.3 for description of Image Pixel Module. +
Table C.7-11a describes the Image Pixel Module. +Table C.7-11a +IMAGE PIXEL MODULE ATTRIBUTES + +Table C.7-11b specifies the common attributes that describe the pixel data of the image. + +Table C.7-11b +IMAGE PIXEL MACRO ATTRIBUTES + +
+
+ + See C.7.6.3 for description of Image Pixel Module. +
Table C.7-11a describes the Image Pixel Module. +Table C.7-11a +IMAGE PIXEL MODULE ATTRIBUTES + +Table C.7-11b specifies the common attributes that describe the pixel data of the image. + +Table C.7-11b +IMAGE PIXEL MACRO ATTRIBUTES + +
+
+ + See C.7.6.3 for description of Image Pixel Module. +
Table C.7-11a describes the Image Pixel Module. +Table C.7-11a +IMAGE PIXEL MODULE ATTRIBUTES + +Table C.7-11b specifies the common attributes that describe the pixel data of the image. + +Table C.7-11b +IMAGE PIXEL MACRO ATTRIBUTES + +
+
+ + See C.7.6.3 for description of Image Pixel Module. Enumerated Value: 8 +
Table C.7-11a describes the Image Pixel Module. +Table C.7-11a +IMAGE PIXEL MODULE ATTRIBUTES + +Table C.7-11b specifies the common attributes that describe the pixel data of the image. + +Table C.7-11b +IMAGE PIXEL MACRO ATTRIBUTES + +
+
+ + See C.7.6.3 for description of Image Pixel Module. Enumerated Value: +8 +
Table C.7-11a describes the Image Pixel Module. +Table C.7-11a +IMAGE PIXEL MODULE ATTRIBUTES + +Table C.7-11b specifies the common attributes that describe the pixel data of the image. + +Table C.7-11b +IMAGE PIXEL MACRO ATTRIBUTES + +
+
+ + See C.7.6.3 for description of Image Pixel Module. Enumerated Value: +7 +
Table C.7-11a describes the Image Pixel Module. +Table C.7-11a +IMAGE PIXEL MODULE ATTRIBUTES + +Table C.7-11b specifies the common attributes that describe the pixel data of the image. + +Table C.7-11b +IMAGE PIXEL MACRO ATTRIBUTES + +
+
+ + See C.7.6.3 for description of Image Pixel Module. Enumerated Value: +0000H (unsigned integer) +
Table C.7-11a describes the Image Pixel Module. +Table C.7-11a +IMAGE PIXEL MODULE ATTRIBUTES + +Table C.7-11b specifies the common attributes that describe the pixel data of the image. + +Table C.7-11b +IMAGE PIXEL MACRO ATTRIBUTES + +
+
+ + See C.7.6.3 for description of Image Pixel Module +
Table C.7-11a describes the Image Pixel Module. +Table C.7-11a +IMAGE PIXEL MODULE ATTRIBUTES + +Table C.7-11b specifies the common attributes that describe the pixel data of the image. + +Table C.7-11b +IMAGE PIXEL MACRO ATTRIBUTES + +
+
+
+ + + The position of the annotation box in the parent film box. Annotation position sequence depends on the selected Annotation Display Format ID (2010,0030) + + + Text string + + + + + Execution status of print job. Enumerated Values: +PENDING +PRINTING +DONE +FAILURE + + + Additional information about Execution Status (2100,0020). +Defined Terms when the Execution Status is DONE or PRINTING: +NORMAL +Defined Terms when the Execution Status is FAILURE: +INVALID PAGE DES = The specified page layout cannot be printed or other page description errors have been detected. +INSUFFIC MEMORY = There is not enough memory available to complete this job. +See Section C.13.9.1 for additional Defined Terms when the Execution Status is PENDING or FAILURE. +
Additional Defined Terms for Printer Status Info (2110,0020) and Execution Status Info (2100,0030) are: + +
+
+ + Date of print job creation. + + + Time of print job creation. + + + Priority of print job (see C.13.1 for further explanation). + + + User defined name identifying the printer. + + + DICOM Application Entity Title that issued the print operation. + +
+ + + Printer device status. Enumerated Values: +NORMAL +WARNING +FAILURE + + + Additional information about Printer Status (2110,0010). +Defined Terms when the Printer Status is equal to NORMAL: +NORMAL +See Section C.13.9.1 for Defined Terms when the Printer Status is equal to WARNING or FAILURE. +
Additional Defined Terms for Printer Status Info (2110,0020) and Execution Status Info (2100,0030) are: + +
+
+ + User defined name identifying the printer. + + + Manufacturer of the printer. + + + Manufacturer's model number of the printer. + + + Manufacturer's serial number of the printer. + + + Manufacturer's designation of software version of the printer. + + + Date when the printer was last calibrated. + + + Time when the printer was last calibrated. + +
+ + + Contains printer configuration information for a single Application Entity title. See Print Management Service Class Structure in PS 3.4. The sequence shall contain one item for each physical printer/Meta SOP Class combination supported by the Application Entity title. + + + The Meta-SOP Class and a list of optional SOP Classes supported. It shall contain one Meta SOP Class UID and 0-n optional SOP Class UIDs. + + + Maximum number of kilobytes of memory that can be allocated for a Film Session. The value shall be 0 if Memory Allocation (2000,0060) is not supported. + + + The maximum number of bits for each pixel that can be stored in printer memory. + + + The number of bits used by the print engine for internal LUT calculation and printing of each pixel. + + + A sequence which specifies the combinations of Medium Type and Film Size IDs available in the printer at this time and the Min and Max Densities supported by these media. +The Item Number with the value of 1 is the printer default. There is no significance to other item numbers. +One item for each Medium Type and Film Size ID installed shall be included. + + + A number that labels this item. Each item in the sequence shall have a unique number. + + + See C.13.1 +
Table C.13-1 +BASIC FILM SESSION PRESENTATION MODULE ATTRIBUTES + +
+
+ + See C.13.3 +
Table C.13-3 +BASIC FILM BOX PRESENTATION MODULE ATTRIBUTES + +
+
+ + Minimum density that can be printed, expressed in hundredths of OD. + + + Maximum density that can be printed, expressed in hundredths of OD. + + + A sequence which specifies combinations of Medium Type and Film Size ID for which the printer will accept an N-CREATE of a Film Box, but are not physically installed in the printer at this time. It also specifies the Min and Max Densities supported by these media. User intervention may be required to instal these media in the printer. +One item for each Medium Type and Film Size ID available, but not installed shall be included. + + + See C.13.1 +
Table C.13-1 +BASIC FILM SESSION PRESENTATION MODULE ATTRIBUTES + +
+
+ + See C.13.3 +
Table C.13-3 +BASIC FILM BOX PRESENTATION MODULE ATTRIBUTES + +
+
+ + Minimum density that can be printed, expressed in hundredths of OD. + + + Maximum density that can be printed, expressed in hundredths of OD. + + + A sequence which specifies the Image Display Formats supported, rows and columns in Image Boxes for each format, pixel spacing, and whether Requested Image Size is supported as a function of Film Orientation, Film Size ID, and Printer Resolution ID. +One item for each display format, film orientation, film size, and printer resolution combination shall be included. + + + Number of printable rows in an Image Box. + + + Number of printable columns in an Image Box + + + See C.13.3 +
Table C.13-3 +BASIC FILM BOX PRESENTATION MODULE ATTRIBUTES + +
+
+ + See C.13.3 +
Table C.13-3 +BASIC FILM BOX PRESENTATION MODULE ATTRIBUTES + +
+
+ + See C.13.3 +
Table C.13-3 +BASIC FILM BOX PRESENTATION MODULE ATTRIBUTES + +
+
+ + Printer Resolution identification. Defined Terms are the same as Requested Resolution ID (2020,0050). See C.13.3. +
Table C.13-3 +BASIC FILM BOX PRESENTATION MODULE ATTRIBUTES + +
+
+ + Physical distance on the printed film between the center of each pixel, specified by a numeric pair - adjacent row spacing (delimiter) adjacent column spacing in mm. See 10.7.1.3 for further explanation of the value order. + + + Indicates whether the printer supports Requested Image Size (2020,0030) for this display format and film orientation and size combination. +Enumerated Values: +NO = not supported +YES = supported + + + The printer's default resolution identification. Defined Terms are the same as Requested Resolution ID (2020,0050). See C.13.3. +
Table C.13-3 +BASIC FILM BOX PRESENTATION MODULE ATTRIBUTES + +
+
+ + Printer's default magnification type. See C.13.3 for Defined Terms. +
Table C.13-3 +BASIC FILM BOX PRESENTATION MODULE ATTRIBUTES + +
+
+ + Other magnification types available in the printer. See C.13.3 for Defined Terms. +
Table C.13-3 +BASIC FILM BOX PRESENTATION MODULE ATTRIBUTES + +
+
+ + Printer's default smoothing type. See C.13.3. +
Table C.13-3 +BASIC FILM BOX PRESENTATION MODULE ATTRIBUTES + +
+
+ + Other smoothing types available in the printer. See C.13.3. +
Table C.13-3 +BASIC FILM BOX PRESENTATION MODULE ATTRIBUTES + +
+
+ + A free form text description of Configuration Information (2010,0150) supported by the printer. + + + The maximum number of films that can be collated for an N-ACTION of the Film Session. The value shall be 0 if N-ACTION of the Film Session is not supported. + + + Indicates whether the printer will decimate or crop image pixels if the image rows or columns is greater than the available printable pixels in an Image Box. +See C.13.5. +Enumerated Values when the printer does not support Requested Decimate/Crop Behavior (2020,0040): +DECIMATE = image will be decimated to fit. +CROP = image will be cropped to fit. +FAIL = N-SET of the Image Box will fail +Enumerated Values when the printer supports Requested Decimate/Crop Behavior (2020,0040): + +DEF DECIMATE = image will be decimated to fit. +DEF CROP = image will be cropped to fit +DEF FAIL = N-SET of the Image Box will fail +This value indicates the printer default if the SCU does not create or set Requested Decimate/Crop Behavior for the Image Box. +
Table C.13-5 +IMAGE BOX PIXEL PRESENTATION MODULE ATTRIBUTES + +Note: Referenced Image Overlay Box Sequence (2020,0130) and Original Image Sequence (2130,00C0) were previously included in this Module but have been retired. See PS 3.3 2004. + +
+
+
+ + + Uniquely identifies this Storage Commitment transaction. + + + Application Entity Title where the SOP Instance(s) may be retrieved via a network based retrieve service. + + + User or implementation specific human readable identification of a Storage Media on which the SOP Instances reside. + + + Uniquely identifies a Storage Media on which the SOP Instances reside. + + + A sequence of Items where each Item references a single SOP Instance for which storage commitment is requested / or has been provided. + + + + Application Entity Title from which the SOP Instance may be retrieved via a network based retrieve service. + + + The user or implementation specific human readable identifier that identifies a Storage Media on which this SOP Instance resides. + + + Uniquely identifies a Storage Media on which this SOP Instance resides. + + + A sequence of Items where each Item references a single SOP Instance for which storage commitment could not be provided. + + + + The reason that storage commitment could not be provided for this SOP Instance. +See Section C.14.1.1. +
The following values and semantics shall be used for the Failure Reason Attribute : +0110H - Processing failure +A general failure in processing the operation was encountered. +0112H - No such object instance +One or more of the elements in the Referenced SOP Instance Sequence was not available. +0213H - Resource limitation +The SCP does not currently have enough resources to store the requested SOP Instance(s). +0122H - Referenced SOP Class not supported +Storage Commitment has been requested for a SOP Instance with a SOP Class that is not supported by the SCP. +0119H - Class / Instance conflict +The SOP Class of an element in the Referenced SOP Instance Sequence did not correspond to the SOP class registered for this SOP Instance at the SCP. +0131H - Duplicate transaction UID +The Transaction UID of the Storage Commitment Request is already in use. + +
+
+
+ + + Modality type. +Enumerated Value: +SR = SR Document + + + Unique identifier of the Series. +Note: No SR-specific semantics are specified. + + + A number that identifies the Series. +Note: No SR-specific semantics are specified. + + + Date the Series started. + + + Time the Series started. + + + User provided description of the Series + + + Uniquely identifies the Performed Procedure Step SOP Instance for which the Series is created. Zero or one item shall be present in the sequence. +Notes: 1. The Performed Procedure Step referred to by this Attribute is the Step during which this Document is generated. +2. If this Document is generated during the same Modality or General Purpose Performed Procedure Step as the evidence in the current interpretation procedure, this attribute may contain reference to that Modality or General Purpose Performed Procedure Step. +3. This Attribute is not used to convey reference to the evidence in the current interpretation procedure. See Current Requested Procedure Evidence Sequence (0040,A375). +4. This Sequence may be sent zero length if the Performed Procedure Step is unknown. + + + + + + A number that identifies the SR Document. + + + The estimated degree of completeness of this SR Document with respect to externally defined criteria in a manner specified in the Conformance Statement. +Note: It may be desirable to make these criteria adaptable to local policies or user decisions. +Enumerated Values: +PARTIAL = Partial content. +COMPLETE = Complete content. + + + Explanation of the value sent in Completion Flag (0040,A491). + + + Indicates whether this SR Document is Verified. Enumerated Values: +UNVERIFIED = Not attested to. +VERIFIED = Attested to by a Verifying Observer Name (0040,A075) who is accountable for its content. +Note: The intent of this specification is that the "prevailing final version" of an SR Document is the version having the most recent Verification DateTime (0040,A030), Completion Flag (0040,A491) of COMPLETE and Verification Flag (0040,A493) of VERIFIED. + + + The date the document content creation started. + + + The time the document content creation started. + + + The person or persons authorized to verify documents of this type and accept responsibility for the content of this document. One or more Items may be included in this sequence. +Required if Verification Flag (0040,A493) is VERIFIED. +Note: In HL7 Structured Documents, the comparable attribute is the "legalAuthenticator". + + + The person authorized by the Verifying Organization (0040,A027) to verify documents of this type and who accepts responsibility for the content of this document. + + + Coded identifier of Verifying Observer. Zero or one Items shall be permitted in this sequence. + + + + Organization to which the Verifying Observer Name (0040,A075) is accountable in the current interpretation procedure. + + + Date and Time of verification by the Verifying Observer Name (0040,A075). + + + The person or device that created the clinical content of this document. This attribute sets the default Observer Context for the root of the content tree. +One or more Items may be included in this sequence. + + + + Persons or devices related to the clinical content of this document. +One or more Items may be included in this sequence. + + + Participant's role with respect to the clinical content of this document. See C.17.2.5. +Defined Terms: +SOURCE - Equipment that contributed to the content +ENT - Data enterer (e.g., transcriptionist) +ATTEST - Attestor +Note: In HL7 Structured Documents, the participation comparable to Attestor is the "Authenticator". +
The Verifying Observer Sequence (0040,A073), Author Observer Sequence (0040,A078), and Participant Sequence (0040,A07A) identify significant contributors to the SR document. The Author creates the clinical content of the document. The Verifying Observer verifies and accepts legal responsibility for the content. Other participants may include an Attestor, a person identified as a Participant who “signs†an SR document, but who does not have legal authority to verify the clinical content. E.g., an SR document may be authored and attested by a resident, and then verified by a staff physician; or a document may be authored by a CAD device and attested by a technologist, and then verified by a physician; or a technologist working with a measurement software package may be the author, the package is a Source participant, and the final content is verified by a physician. +An individual shall not be identified in both the Verifying Observer Sequence (as the legal authenticator) and in the Participant Sequence as an Attestor. An individual may be identified in both the Author Observer Sequence and either the Verifying Observer Sequence or the Participant Sequence. +The participation DateTime for the Verifying Observer is conveyed in Verification DateTime (0040,A030) within the Verifying Observer Sequence, for the Author Observer in the Observation DateTime (0040,A032) in the main Data Set (see C.17.3), and for other participants in Participation DateTime (0040,A082) within the Participant Sequence. +
+
+ + DateTime of participation with respect to the clinical content of this document. + + + + Custodial organization for this SR Document instance. Represents the organization from which the document originates and that is in charge of maintaining the document, i.e., the steward of the original source document. +Note: This may or may not be identical to the Institution identified in the Equipment Module. +Only a single item shall be present in this sequence. + + + Name of Custodial Institution or Organization. + + + Coded identifier of Custodial Institution or Organization. +Zero or one Items may be included in this sequence. + + + + Shall refer to SR SOP Instances (e.g. prior or provisional reports) whose content has been wholly or partially included in this document with or without modification. One or more Items may be included in this sequence. +Required if this document includes content from other documents. +Note: The amendment process of an existing SR Document is not explicitly described, but several approaches may be considered. One may choose, for example, to create a new SR Document that includes the original content with any amendments applied or included. The structure of this amended SR Document may or may not reflect what was amended. However, the use of the Predecessor Document Sequence allows tracing back to the input SR Document, which in this case is the previous version. + + + + Duplicates of this document, stored with different SOP Instance UIDs. One or more Items may be included in this sequence. +Required if this document is stored with different SOP Instance UIDs in one or more other Studies. +See C.17.2.2 for further explanation. +
If identical copies of an SR Document are to be included in multiple Studies then the entire SR Document shall be duplicated with appropriate changes for inclusion into the different Studies (i.e. Study Instance UID, Series Instance UID, SOP Instance UID, Identical Documents Sequence etc.). The Identical Documents Sequence Attribute in each SOP Instance shall contain references to all other duplicate SOP Instances. +Note: If an SR Document contains an Identical Documents Sequence then it will not be further duplicated without producing a new complete set of duplicate SOP Instances with re-generated Identical Documents Sequences. This is a consequence of the rules for modification of SR Document content in PS3.4. For example, if there are two identical reports and an application is creating a third identical report, then the first two reports must be re-generated in order that their Identical Documents Sequence will reference the new duplicate document and all other identical documents. + +If a new SR Document is created using content from an SR Document that contains an Identical Documents Sequence and is part of the same Requested Procedure, then the new SR Document shall only contain a new Identical Documents Sequence if the new SR Document is duplicated. The Predecessor Documents Sequence in all the new SR Documents shall contain references to the original SR Document and all its duplicates as well as any other documents from which content is included. +Note: It is up to an implementation to decide whether a new SR Document is duplicated across multiple Studies. This may require user input to make the decision. + +
+
+ + + Identifies Requested Procedures which are being fulfilled (completely or partially) by creation of this Document. One or more Items may be included in this sequence. +Required if this Document fulfills at least one Requested Procedure. + + + Unique identifier for the Study. + + + Uniquely identifies the Study SOP Instance. +Only a single Item shall be permitted in this sequence. + + + + A departmental IS generated number which identifies the order for the Study. + + + The order number assigned to the Imaging Service Request by the party placing the order. + + + The order number assigned to the Imaging Service Request by the party filling the order. + + + Identifier of the related Requested Procedure + + + Institution-generated administrative description or classification of Requested Procedure. + + + A sequence that conveys the requested procedure. Zero or one Item may be included in this sequence. + + + + Reason for requesting this procedure. + + + Coded Reason for requesting this procedure. +One or more sequence items may be present. + + + + A Sequence that conveys the codes of the performed procedures pertaining to this SOP Instance. Zero or more Items may be included in this sequence. + + + + Full set of Composite SOP Instances, of which the creator is aware, which were created to satisfy the current Requested Procedure(s) for which this SR Document is generated or that are referenced in the content tree. One or more Items may be included in this sequence. +Required if the creator is aware of Composite Objects acquired in order to satisfy the Requested Procedure(s) for which the SR Document is or if instances are referenced in the content tree. May be present otherwise. +See C.17.2.3 for further explanation. +
The intent of the Current Requested Procedure Evidence Sequence (0040,A375) is to reference all evidence created in order to satisfy the current Requested Procedure(s) for this SR Document. This shall include, but is not limited to, all current evidence referenced in the content tree. +For a completed SR Document satisfying (i.e., being the final report for) the current Requested Procedure(s), this sequence shall list the full set of Composite SOP Instances created for the current Requested Procedure(s). For other SOP Instances that include the SR Document General Module, this sequence shall contain at minimum the set of Composite SOP Instances from the current Requested Procedure(s) that are referenced in the content tree. +The Pertinent Other Evidence Sequence (0040,A385) attribute is used to reference all other evidence considered pertinent for this SR Document that is not listed in the Current Requested Procedure Evidence Sequence (0040,A375). +This requires that the same SOP Instance shall not be referenced in both of these Sequences. +For the purposes of inclusion in the Current Requested Procedure Evidence Sequence (0040,A375) and the Pertinent Other Evidence Sequence (0040,A385), the set of Composite SOP Instances is defined to include not only the images and waveforms referenced in the content tree, but also all presentation states, real world value maps and other accompanying composite instances that are referenced from the content items. +
+
+ + + Other Composite SOP Instances that are considered to be pertinent evidence by the creator of this SR Document. This evidence must have been acquired in order to satisfy Requested Procedures other than the one(s) for which this SR Document is generated. One or more Items may be included in this sequence. +Required if pertinent evidence from other Requested Procedures needs to be recorded. +See C.17.2.3 for further explanation. +
The intent of the Current Requested Procedure Evidence Sequence (0040,A375) is to reference all evidence created in order to satisfy the current Requested Procedure(s) for this SR Document. This shall include, but is not limited to, all current evidence referenced in the content tree. +For a completed SR Document satisfying (i.e., being the final report for) the current Requested Procedure(s), this sequence shall list the full set of Composite SOP Instances created for the current Requested Procedure(s). For other SOP Instances that include the SR Document General Module, this sequence shall contain at minimum the set of Composite SOP Instances from the current Requested Procedure(s) that are referenced in the content tree. +The Pertinent Other Evidence Sequence (0040,A385) attribute is used to reference all other evidence considered pertinent for this SR Document that is not listed in the Current Requested Procedure Evidence Sequence (0040,A375). +This requires that the same SOP Instance shall not be referenced in both of these Sequences. +For the purposes of inclusion in the Current Requested Procedure Evidence Sequence (0040,A375) and the Pertinent Other Evidence Sequence (0040,A385), the set of Composite SOP Instances is defined to include not only the images and waveforms referenced in the content tree, but also all presentation states, real world value maps and other accompanying composite instances that are referenced from the content items. +
+
+ + + Sequence specifying SOP Instances significantly related to the current SOP Instance. Such referenced Instances may include equivalent documents or renderings of this document. +One or more Items may be included in this sequence. +Required if the identity of a CDA Document equivalent to the current SOP Instance is known at the time of creation of this SOP Instance (see C.17.2.6). May be present otherwise. + + + + Code describing the purpose of the reference to the Instance(s). Only a single Item shall be permitted in this sequence. + + +
+ + + Unique identifier for the Study + + + Sequence of Items where each Item includes the Attributes of a Series containing referenced Composite Object(s). One or more Items may be included in this sequence + + + + + + Enumerated Values: +PSN - Person +DEV - Device + + + Name of the person observer for this document Instance. +Required if Observer Type value is PSN. + + + Coded identifier of person observer. Zero or one Items shall be permitted in this sequence. +Required if Observer Type value is PSN. + + + + Name of the device observer for this document instance. +Required if Observer Type value is DEV. + + + Unique identifier of device observer. +Required if Observer Type value is DEV. + + + Manufacturer of the device observer. +Required if Observer Type value is DEV. + + + Model Name of the device observer. +Required if Observer Type value is DEV. + + + Institution or organization to which the identified person is responsible or accountable, or which manages the identified device. + + + Institution or organization to which the identified person is responsible or accountable, or which manages the identified device. +Zero or one Items shall be permitted in this Sequence. + + + + + + + + + + The type of the value encoded in this Content Item. +Defined Terms: +TEXT +NUM +CODE +DATETIME +DATE +TIME +UIDREF +PNAME +COMPOSITE +IMAGE +WAVEFORM +SCOORD +TCOORD +CONTAINER +See C.17.3.2.1 for further explanation. +
The value of the name/value pair is encoded with one of the Value Types defined in Table C.17.3-7 (the choice of which may be constrained by the IOD in which this Module is contained). The Value Type (0040,A040) attribute explicitly conveys the type of Content Item value encoding. + +Table C.17.3-7 +VALUE TYPE DEFINITIONS + +Note: It is recommended that drawings and sketches, sometimes used in reports, be represented byIMAGE Content Items that reference separate SOP Instances (e.g., 8-bit, MONOCHROME2, Secondary Capture, or Multi-frame Single Bit Secondary Capture). + +
+
+ + Code describing the concept represented by this Content Item. Also conveys the value of Document Title and section headings in documents. Only a single Item shall be permitted in this sequence. +Required if Value Type (0040,A040) is TEXT or NUM or CODE or DATETIME or DATE or TIME or UIDREF or PNAME. +Required if Value Type (0040,A040) is CONTAINER and a heading is present, or this is the Root Content Item. +Note: That is, containers without headings do not require Concept Name Code Sequence +Required if Value Type (0040,A040) is COMPOSITE, IMAGE, WAVEFORM, SCOORD or TCOORD, and the Purpose of Reference is conveyed in the Concept Name. +See C.17.3.2.2 for further explanation. +
The Concept Name Code Sequence (0040,A043) conveys the name of the concept whose value is expressed by the value attribute or set of attributes. Depending on the Value Type (0040,A040), the meaning of the Concept Name Code Sequence may reflect specifics of the use of the particular data type (see Table C.17.3-7). +
+
+ + + This is the value of the Content Item. +Required if Value Type (0040,A040) is TEXT. +Text data which is unformatted and whose manner of display is implementation dependent. +The text value may contain spaces, as well as multiple lines separated by either LF, CR, CR LF or LF CR, but otherwise no format control characters (such as horizontal or vertical tab and form feed) shall be present, even if permitted by the Value Representation of UT. +The text shall be interpreted as specified by Specific Character Set (0008,0005) if present in the SOP Common Module. +Note: The text may contain single or multi-byte characters and use code extension techniques as described in PS 3.5 if permitted by the values of Specific Character Set (0008,0005). + + + This is the value of the Content Item. +Required if Value Type (0040,A040) is DATETIME. + + + This is the value of the Content Item. +Required if Value Type (0040,A040) is DATE. + + + This is the value of the Content Item. +Required if Value Type (0040,A040) is TIME. + + + This is the value of the Content Item. +Required if Value Type (0040,A040) is PNAME. + + + This is the value of the Content Item. +Required if Value Type (0040,A040) is UIDREF. + + + + + + + + + +
+ + + The date and time on which this Content Item was completed. For the purpose of recording measurements or logging events, completion time is defined as the time of data acquisition of the measurement, or the time of occurrence of the event. +Required if the date and time are different from the Content Date (0008,0023) and Content Time (0008,0033) or the Observation DateTime (0040,A032) defined in higher items. May be present otherwise. +Note: When Content Items are copied into successor reports, the Content Date (0008,0023) and Content Time (0008,0033) of the new report are likely to be different than the date and time of the original observation. Therefore this attribute may need to be included in any copied Content Items to satisfy the condition. + + + A potentially recursively nested Sequence of Items that conveys content that is the Target of Relationships with the enclosing Source Content Item. +One or more Items may be included in this sequence. +Required if the enclosing Content Item has relationships. +Notes: 1. If this Attribute is not present then the enclosing Item is a leaf. +2. The order of Items within this Sequence is semantically significant for presentation. +See C.17.3.2.4 for further explanation. +
The Content Sequence (0040,A730) provides the hierarchical structuring of the Content Tree (see C.17.3.1) by recursively nesting Content Items. A parent (or source) Content Item has an explicit relationship to each child (or target) Content Item, conveyed by the Relationship Type (0040,A010) attribute. +Table C.17.3-8 describes the Relationship Types between Source Content Items and the Target Content Items. +Table C.17.3-8 +RELATIONSHIP TYPE DEFINITIONS + +
+
+ + The type of relationship between the (enclosing) Source Content Item and the Target Content Item. +IODs specify additional constraints on Relationships (including lists of Enumerated Values). +Defined Terms: +CONTAINS +HAS PROPERTIES +HAS OBS CONTEXT +HAS ACQ CONTEXT +INFERRED FROM +SELECTED FROM +HAS CONCEPT MOD +See C.17.3.2.4 for further explanation. +
The Content Sequence (0040,A730) provides the hierarchical structuring of the Content Tree (see C.17.3.1) by recursively nesting Content Items. A parent (or source) Content Item has an explicit relationship to each child (or target) Content Item, conveyed by the Relationship Type (0040,A010) attribute. +Table C.17.3-8 describes the Relationship Types between Source Content Items and the Target Content Items. +Table C.17.3-8 +RELATIONSHIP TYPE DEFINITIONS + +
+
+ + + + An ordered set of one or more integers that uniquely identifies the Target Content Item of the relationship. +The root Content Item is referenced by a single value of 1. +Each subsequent integer represents an ordinal position of a Content Item in the Content Sequence (0040,A730) in which it belongs. The Referenced Content Item Identifier is the set of these ordinal positions along the by-value relationship path. The number of values in this Multi-Value Attribute is exactly the number of relationships traversed in the SR content tree plus one. +Note: 1. See C.17.3.2.5. +2. Content Items are ordered in a Content Sequence starting from 1 as defined in VR of SQ (See PS 3.5). +Required if the Target Content Item is denoted by-reference, i.e. the Document Relationship Macro and Document Content Macro are not included. +
Content Items are identified by their position in the Content Item tree. They have an implicit order as defined by the order of the Sequence Items. When a Content Item is the target of a by-reference relationship, its position is specified in the Referenced Content Item Identifier (0040,DB73) in a Content Sequence Item subsidiary to the source Content Item. +Note: Figure C.17.3-3 illustrates an SR content tree and identifiers associated with each Content Item: + +
+
+
+ + + Modality type. +Enumerated Value: +KO = Key Object Selection + + + Unique identifier of the Series. +Note: No specific semantics are specified. + + + A number that identifies the Series. +Note: No specific semantics are specified. + + + Date the Series started. + + + Time the Series started. + + + User provided description of the Series + + + Uniquely identifies the Performed Procedure Step SOP Instance for which the Series is created. Zero or one item shall be present in the sequence. +Notes: See notes on this attribute in Section C.17.1 SR Document Series Module + + + + + + A number that identifies the Document. + + + The date the document content creation started. + + + The time the document content creation started. + + + Identifies Requested Procedures to which this Document pertains. One or more Items may be included in this sequence. +Required if this Document pertains to at least one Requested Procedure. + + + Unique identifier for the Study. + + + Uniquely identifies the Study SOP Instance. +Only a single Item shall be permitted in this sequence. + + + + A departmental IS generated number which identifies the order for the Study. + + + The order number assigned to the Imaging Service Request by the party placing the order. + + + The order number assigned to the Imaging Service Request by the party filling the order. + + + Identifier of the related Requested Procedure + + + Institution-generated administrative description or classification of Requested Procedure. + + + A sequence that conveys the requested procedure. Zero or one Item may be included in this sequence. + + + + List of all Composite SOP Instances referenced in the Content Sequence (0040,A730) , including all presentation states, real world value maps and other accompanying composite instances that are referenced from the content items. One or more Items shall be included in this sequence. +Note: In the context of the Key Object Selection, the current evidence is considered to be only the set of instances referenced within the Key Object Selection. + + + + Duplicates of this document, stored with different SOP Instance UIDs. One or more Items may be included in this sequence. +Required if this Key Object Selection document references instances in more than one Study. +See C.17.2.2 and C.17.6.2.1 for further explanation and conditions. +
If identical copies of an SR Document are to be included in multiple Studies then the entire SR Document shall be duplicated with appropriate changes for inclusion into the different Studies (i.e. Study Instance UID, Series Instance UID, SOP Instance UID, Identical Documents Sequence etc.). The Identical Documents Sequence Attribute in each SOP Instance shall contain references to all other duplicate SOP Instances. +Note: If an SR Document contains an Identical Documents Sequence then it will not be further duplicated without producing a new complete set of duplicate SOP Instances with re-generated Identical Documents Sequences. This is a consequence of the rules for modification of SR Document content in PS3.4. For example, if there are two identical reports and an application is creating a third identical report, then the first two reports must be re-generated in order that their Identical Documents Sequence will reference the new duplicate document and all other identical documents. + +If a new SR Document is created using content from an SR Document that contains an Identical Documents Sequence and is part of the same Requested Procedure, then the new SR Document shall only contain a new Identical Documents Sequence if the new SR Document is duplicated. The Predecessor Documents Sequence in all the new SR Documents shall contain references to the original SR Document and all its duplicates as well as any other documents from which content is included. +Note: It is up to an implementation to decide whether a new SR Document is duplicated across multiple Studies. This may require user input to make the decision. + +
+
+ +
+ + + This is the value of the Content Item. +Shall consist of a Sequence of Items conveying the measured value(s), which represent integers or real numbers and units of measurement. Zero or one Items shall be permitted in this sequence. + + + Numeric measurement value. Only a single value shall be present. + + + Units of measurement. Only a single Item shall be permitted in this sequence. + + + + Qualification of Numeric Value in Measured Value Sequence, or reason for absence of Measured Value Sequence Item. Only a single Item shall be permitted in this sequence. + + + + + + This is the value of the Content Item. Only a single Item shall be permitted in this sequence. + + + + + + References to Composite Object SOP Class/SOP Instance pairs. +Only a single Item shall be permitted in this Sequence. + + + + + + + Identifies the frame numbers within the Referenced SOP Instance to which the reference applies. The first frame shall be denoted as frame number 1. +Note: This Attribute may be multi-valued. +Required if the Referenced SOP Instance is a multi-frame image and the reference does not apply to all frames, and Referenced Segment Number (0062,000B) is not present. + + + Identifies the segments to which the reference applies identified by Segment Number (0062,0004). Required if the Referenced SOP Instance is a Segmentation and the reference does not apply to all segments and Referenced Frame Number (0008,1160) is not present. + + + Reference to a Softcopy Presentation State SOP Class/SOP Instance pair. Only a single Item shall be permitted in this sequence. + + + + Reference to a Real World Value Mapping SOP Class/SOP Instance pair. Only a single Item shall be permitted in this sequence. + + + + This Icon Image is representative of the Image. Only a single Item shall be permitted in this Sequence. +The Icon Image may be no greater than 128 rows by 128 columns. + + + + + + + List of channels in Waveform to which the reference applies. See C.18.5.1.1 +Required if the Referenced SOP Instance is a Waveform that contains multiple Channels and not all Channels in the Waveform are referenced. +
Referenced Waveform Channels (0040,A0B0) is a multi-value attribute which lists the channels referenced. Each channel is specified as a pair of values (M,C), where the first value is the sequence item number of the Waveform Sequence (5400,0100) attribute in the referenced object (i.e. the Multiplex Group Number), and the second value is the sequence item number of the Channel Definition Sequence (003A,0200) attribute (i.e., the Channel Number) within the multiplex group. +If the specified channel number is 0, the annotation applies to all channels in the multiplex group. +Note: As an example, an annotation which applies to the entire first multiplex group and channels 2 and 3 of the third multiplex group would have Referenced Waveform Channels (0040,A0B0) value 0001 0000 0003 0002 0003 0003. + +
+
+
+ + + An ordered set of (column,row) pairs that denote positions in an image specified with sub-pixel resolution such that the origin at the TLHC of the TLHC pixel is 0.0\0.0, the BRHC of the TLHC pixel is 1.0\1.0, and the BRHC of the BRHC pixel is Columns\Rows. The values must be within the range 0\0 to Columns\Rows. The values Columns (0028,0011) and Rows (0028,0010) are those contained in the referenced image. +See C.18.6.1.1 for further explanation. +
Graphic Data may be used to associate an anatomic or spatial Concept with a defined subset of one or more images. Graphic Data may be explicitly defined as a single point (i.e. to denote the epicenter of an anatomic site or lesion) or more than one point (i.e. representing a set of points or an open or closed polygon). +Note: Spatial coordinates may be used to associate observational data with a set of Image features. Spatial coordinates also may be used to convey coordinates that are input data for a measurement. + +
+
+ + See C.18.6.1.2 for Enumerated Values. +
When annotation applies to an image, this attribute defines the type of geometry of the annotated region of interest. The following Enumerated Values are specified for image spatial coordinate geometries: +POINT = a single pixel denoted by a single (column,row) pair +MULTIPOINT = multiple pixels each denoted by an (column,row) pair +POLYLINE = a series of connected line segments with ordered vertices denoted by (column,row) pairs; if the first and last vertices are the same it is a closed polygon +CIRCLE = a circle defined by two (column,row) pairs. The first point is the central pixel. The second point is a pixel on the perimeter of the circle. +ELLIPSE = an ellipse defined by four pixel (column,row) pairs, the first two points specifying the endpoints of the major axis and the second two points specifying the endpoints of the minor axis of an ellipse + +
+
+
+ + + See C.18.7.1.1 for Enumerated Values. +
This Attribute defines the type of temporal extent of the region of interest. A temporal point (or instant of time) may be defined by a waveform sample offset (for a single waveform multiplex group only), time offset, or absolute time. +The following Enumerated Values are specified for Temporal Range Type: +POINT = a single temporal point +MULTIPOINT = multiple temporal points +SEGMENT = a range between two temporal points +MULTISEGMENT = multiple segments, each denoted by two temporal points +BEGIN = a range beginning at one temporal point, and extending beyond the end of the acquired data +END = a range beginning before the start of the acquired data, and extending to (and including) the identified temporal point + +
+
+ + List of samples within a multiplex group specifying temporal points of the referenced data. Position of first sample is 1. +Required if the Referenced SOP Instance is a Waveform and Referenced Time Offsets (0040,A138) and Referenced DateTime (0040,A13A) are not present. +May be used only if Referenced Channels (0040,A0B0) refers to channels within a single multiplex group. + + + Specifies temporal points for reference by number of seconds after start of data. +Required if Referenced Sample Positions (0040,A132) and Referenced DateTime (0040,A13A) are not present. + + + Specifies temporal points for reference by absolute time. +Required if Referenced Sample Positions (0040,A132) and Referenced Time Offsets (0040,A138) are not present. + +
+ + + This flag specifies for a CONTAINER whether or not its contained Content Items are logically linked in a continuous textual flow, or are separate items. +Enumerated Values: +SEPARATE +CONTINUOUS +See C.18.8.1.1 for further explanation. +
Continuity of Content (0040,A050) specifies whether or not all the Content Items contained in a CONTAINER are logically linked in a continuous textual flow, or are separate entities. It only applies to the children contained in the container, and not their children (which if containers themselves, will have the attribute specified explicitly). +Notes: 1. This allows the interspersing of measurements, codes, and image references, amongst text. For example, the following: “A mass of diameter = 3 cm was detected.†can be represented by the following Content Items in a CONTAINER with a Continuity of Content (0040,A050) of CONTINUOUS: + TEXT “A mass of†+ NUM “Diameter†3 “cm†+ TEXT “was detected.†+ 2. The Continuity of Content applies only to subsidiary Content Items with Relationship Type CONTAINS. Other subsidiary items, e.g., with Relationship Type HAS CONCEPT MOD or HAS OBS CONTEXT, are not part of the Continuity of Content, but apply to the Container as a whole. + +
+
+ + Template that describes the content of this Content Item and its subsidiary Content Items. +Only a single Item shall be permitted in this sequence. +Required if a template was used to define the content of this Item, and the template consists of a single CONTAINER with nested content, and it is the outermost invocation of a set of nested templates that start with the same CONTAINER (see C.18.8.1.2). + + + Mapping Resource that defines the template. See Section 8.4. Defined Terms: +DCMR = DICOM Content Mapping Resource + + + Template identifier. + +
+ + + A number that identifies this image. The value shall be unique within a series. + + + The date the raw data creation was started. + + + The time the raw data creation was started. + + + The date and time that the acquisition of data started. +Note: The synchronization of this time with an external clock is specified in the synchronization Module in Acquisition Time synchronized (0018,1800). + + + Unique identification of the equipment and version of the software that has created the Raw Data information. The UID allows one to avoid attempting to interpret raw data with an unknown format. + + + A sequence that provides reference to a set of SOP Class/Instance pairs identifying other Instances significantly related to this Instance. One or more Items may be included in this Sequence. + + + + Describes the purpose for which the reference is made. Only a single Item shall be permitted in this sequence. +See C.7.6.16.2.5.1. +
Referenced Image Sequence (0008,1140) shall be used to provide a reference to a set of SOP Class/Instance pairs identifying other data objects used to plan the acquisition of this image where the images shall share the same Frame of Reference UID (0020,0052). For each Item that contains such a reference, the value of the Purpose of Reference Code Sequence (0040,A170) shall be (â€121311â€, DCM, â€Localizer"). Applications can use the Referenced Image Sequence (0008,1140) in combination with data in Plane Position and Plane Orientation Macros to provide projections of the position of an image with respect to the referenced image. +The Referenced Image Sequence (0008,1140) may also be present when references to other images (or frames within other images) are required for other reasons, as specified by Purpose of Reference Code Sequence (0040,A170). +Note: An Image may contain references to itself (e.g. to other frames within itself). + +
+
+ + +
+ + + Modality type. +Enumerated Value: +REG + + + + + The date the content creation started. + + + The time the content creation started. + + + + A sequence of one or more registration items. Each item defines a spatial registration to the referenced images in that item. All referenced images are in the same spatial frame of reference or atlas. + + + Identifies a Frame of Reference that may or may not be an image set (e.g. atlas or physical space). See C.7.4.1.1.1 for further explanation. Required if Referenced Image Sequence (0008,1140) is absent. May be present otherwise. +
The Frame of Reference UID (0020,0052) shall be used to uniquely identify a frame of reference for a series. Each series shall have a single Frame of Reference UID. However, multiple Series within a Study may share a Frame of Reference UID. All images in a Series that share the same Frame of Reference UID shall be spatially related to each other. +Notes: 1. Previous versions of this Standard defined a Data Element "Location", which has been retired. Frame of Reference UID provides a completely unambiguous identification of the image location reference used to indicate position. + 2. A common Frame of Reference UID may be used to spatially relate localizer images with a set of transverse images. However, in some cases (eg. multiple localizer images being related to a single set of transverse images) a common Frame of Reference UID may not be sufficient. The Referenced Image Sequence (0008,1140) provides an unambiguous method for relating localizer images. + +
+
+ + Identifies the set of images registered in this sequence item. One or more items shall be present. Required if Frame of Reference UID (0020,0052) is absent. May be present otherwise. + + + + A sequence that specifies one spatial registration. Exactly one item shall be present + + + User description or comments about the registration. + + + Describes the information input into the registration process. Zero or one Items may be present in this Sequence. + + + + One or more items shall be present. Each item specifies a transformation. The item order is significant and corresponds to matrix multiplication order. See C.20.2.1.1. +
The Frame of Reference Transformation Matrix (3006,00C6) AMB describes how to transform a point (Bx,By,Bz) with respect to RCSB into (Ax,Ay,Az) with respect to RCSA according to the equation below. + + + + + + + + + + + + + + + + + + + + A + + + + x + + + + + + + + + + + + + + A + + + + y + + + + + + + + + + + + + + A + + + + z + + + + + + + 1 + + + + + = + + + + + + + M + + + 11 + + + + + + + + + + M + + + 12 + + + + + + + + + + M + + + 13 + + + + + + + + + + T + + + x + + + + + + + + + + + + M + + + 21 + + + + + + + + + + M + + + 22 + + + + + + + + + + M + + + 23 + + + + + + + + + + T + + + y + + + + + + + + + + + + M + + + 31 + + + + + + + + + + M + + + 32 + + + + + + + + + + M + + + 33 + + + + + + + + + + T + + + z + + + + + + + + + + + 0 + + + + + + 0 + + + + + + 0 + + + + + + 1 + + + + + + + + + + + + + + + + + + + B + + + + x + + + + + + + + + + + + + + B + + + + y + + + + + + + + + + + + + + B + + + + z + + + + + + + 1 + + + + + + + + + + size 12{ left [ matrix { +"" lSup { size 8{A} } x {} ## +"" lSup { size 8{A} } y {} ## +"" lSup { size 8{A} } z {} ## +1 +} right ]= left [ matrix { +M rSub { size 8{"11"} } {} # M rSub { size 8{"12"} } {} # M rSub { size 8{"13"} } {} # T rSub { size 8{x} } {} ## +M rSub { size 8{"21"} } {} # M rSub { size 8{"22"} } {} # M rSub { size 8{"23"} } {} # T rSub { size 8{y} } {} ## +M rSub { size 8{"31"} } {} # M rSub { size 8{"32"} } {} # M rSub { size 8{"33"} } {} # T rSub { size 8{z} } {} ## +0 {} # 0 {} # 0 {} # 1{} +} right ] left [ matrix { +"" lSup { size 8{B} } x {} ## +"" lSup { size 8{B} } y {} ## +"" lSup { size 8{B} } z {} ## +1 +} right ]} {} + + +The Frame of Reference Transformation Matrix is expressible as multiple matrices, each in a separate item of the Matrix Sequence (0070,030A). The equation below specifies the order of the matrix multiplication where M1, M2 and M3 are the first, second and third items in the sequence. + + + + + + + + + + + + + + + x + ' + + + + + + y + ' + + + + + + z + ' + + + + + + 1 + + + + + + + + + T + + + + = + + M + + + 3 + + + + + + + + M + + + 2 + + + + + + + M + + + 1 + + + + + + + + + + x + + + + + + y + + + + + + z + + + + + + 1 + + + + + + + + + T + + + + + + + + + + + + + size 12{ left [ matrix { +x' {} # y' {} # z' {} # 1{} +} right ] rSup { size 8{T} } =M rSub { size 8{3} } left (M rSub { size 8{2} } left (M rSub { size 8{1} } left [ matrix { +x {} # y {} # z {} # 1{} +} right ] rSup { size 8{T} } right ) right )} {} + + +where = +Registration often involves two or more RCS, each with a corresponding Frame of Reference Transformation Matrix. For example, another Frame of Reference Transformation Matrix AMC can describe how to transform a point (Cx,Cy,Cz) with respect to RCSC into (Ax,Ay,Az) with respect to RCSA. It is straightforward to find the Frame of Reference Transformation Matrix BMC that describes how to transform the point (Cx,Cy,Cz) with respect to RCSC into the point (Bx,By,Bz) with respect to RCSB. The solution is to invert AMB and multiply by AMC, as shown below: + + + + + + + + + + + + + + + + + + + + B + + + + x + + + + + + + + + + + + + + B + + + + y + + + + + + + + + + + + + + B + + + + z + + + + + + + 1 + + + + + = +  + + + + + + + + A + + + + + Μ + + + B + + + + + +  + + + + − + 1 + + + + + ∗ + + + + + + + A + + + + + + M + + + C + + + + + + + + + + + + + + + C + + + + x + + + + + + + + + + + + + + C + + + + y + + + + + + + + + + + + + + C + + + + z + + + + + + + 1 + + + + + + + + + + size 12{ left [ matrix { +"" lSup { size 8{B} } x {} ## +"" lSup { size 8{B} } y {} ## +"" lSup { size 8{B} } z {} ## +1 +} right ]= \( "" lSup { size 8{A} } Μ rSub { size 8{B} } \) rSup { size 8{ - 1} } * "" lSup { size 8{A} } M rSub { size 8{C} } left [ matrix { +"" lSup { size 8{C} } x {} ## +"" lSup { size 8{C} } y {} ## +"" lSup { size 8{C} } z {} ## +1 +} right ]} {} + + + +
+
+ + A 4x4 homogeneous transformation matrix that registers the referenced images to the local RCS. Matrix elements shall be listed in row-major order. See C.20.2.1.1. +
The Frame of Reference Transformation Matrix (3006,00C6) AMB describes how to transform a point (Bx,By,Bz) with respect to RCSB into (Ax,Ay,Az) with respect to RCSA according to the equation below. + + + + + + + + + + + + + + + + + + + + A + + + + x + + + + + + + + + + + + + + A + + + + y + + + + + + + + + + + + + + A + + + + z + + + + + + + 1 + + + + + = + + + + + + + M + + + 11 + + + + + + + + + + M + + + 12 + + + + + + + + + + M + + + 13 + + + + + + + + + + T + + + x + + + + + + + + + + + + M + + + 21 + + + + + + + + + + M + + + 22 + + + + + + + + + + M + + + 23 + + + + + + + + + + T + + + y + + + + + + + + + + + + M + + + 31 + + + + + + + + + + M + + + 32 + + + + + + + + + + M + + + 33 + + + + + + + + + + T + + + z + + + + + + + + + + + 0 + + + + + + 0 + + + + + + 0 + + + + + + 1 + + + + + + + + + + + + + + + + + + + B + + + + x + + + + + + + + + + + + + + B + + + + y + + + + + + + + + + + + + + B + + + + z + + + + + + + 1 + + + + + + + + + + size 12{ left [ matrix { +"" lSup { size 8{A} } x {} ## +"" lSup { size 8{A} } y {} ## +"" lSup { size 8{A} } z {} ## +1 +} right ]= left [ matrix { +M rSub { size 8{"11"} } {} # M rSub { size 8{"12"} } {} # M rSub { size 8{"13"} } {} # T rSub { size 8{x} } {} ## +M rSub { size 8{"21"} } {} # M rSub { size 8{"22"} } {} # M rSub { size 8{"23"} } {} # T rSub { size 8{y} } {} ## +M rSub { size 8{"31"} } {} # M rSub { size 8{"32"} } {} # M rSub { size 8{"33"} } {} # T rSub { size 8{z} } {} ## +0 {} # 0 {} # 0 {} # 1{} +} right ] left [ matrix { +"" lSup { size 8{B} } x {} ## +"" lSup { size 8{B} } y {} ## +"" lSup { size 8{B} } z {} ## +1 +} right ]} {} + + +The Frame of Reference Transformation Matrix is expressible as multiple matrices, each in a separate item of the Matrix Sequence (0070,030A). The equation below specifies the order of the matrix multiplication where M1, M2 and M3 are the first, second and third items in the sequence. + + + + + + + + + + + + + + + x + ' + + + + + + y + ' + + + + + + z + ' + + + + + + 1 + + + + + + + + + T + + + + = + + M + + + 3 + + + + + + + + M + + + 2 + + + + + + + M + + + 1 + + + + + + + + + + x + + + + + + y + + + + + + z + + + + + + 1 + + + + + + + + + T + + + + + + + + + + + + + size 12{ left [ matrix { +x' {} # y' {} # z' {} # 1{} +} right ] rSup { size 8{T} } =M rSub { size 8{3} } left (M rSub { size 8{2} } left (M rSub { size 8{1} } left [ matrix { +x {} # y {} # z {} # 1{} +} right ] rSup { size 8{T} } right ) right )} {} + + +where = +Registration often involves two or more RCS, each with a corresponding Frame of Reference Transformation Matrix. For example, another Frame of Reference Transformation Matrix AMC can describe how to transform a point (Cx,Cy,Cz) with respect to RCSC into (Ax,Ay,Az) with respect to RCSA. It is straightforward to find the Frame of Reference Transformation Matrix BMC that describes how to transform the point (Cx,Cy,Cz) with respect to RCSC into the point (Bx,By,Bz) with respect to RCSB. The solution is to invert AMB and multiply by AMC, as shown below: + + + + + + + + + + + + + + + + + + + + B + + + + x + + + + + + + + + + + + + + B + + + + y + + + + + + + + + + + + + + B + + + + z + + + + + + + 1 + + + + + = +  + + + + + + + + A + + + + + Μ + + + B + + + + + +  + + + + − + 1 + + + + + ∗ + + + + + + + A + + + + + + M + + + C + + + + + + + + + + + + + + + C + + + + x + + + + + + + + + + + + + + C + + + + y + + + + + + + + + + + + + + C + + + + z + + + + + + + 1 + + + + + + + + + + size 12{ left [ matrix { +"" lSup { size 8{B} } x {} ## +"" lSup { size 8{B} } y {} ## +"" lSup { size 8{B} } z {} ## +1 +} right ]= \( "" lSup { size 8{A} } Μ rSub { size 8{B} } \) rSup { size 8{ - 1} } * "" lSup { size 8{A} } M rSub { size 8{C} } left [ matrix { +"" lSup { size 8{C} } x {} ## +"" lSup { size 8{C} } y {} ## +"" lSup { size 8{C} } z {} ## +1 +} right ]} {} + + + +
+
+ + Type of Frame of Reference Transformation Matrix (3006,00C6). Defined terms: +RIGID +RIGID_SCALE +AFFINE +See C.20.2.1.2 +
There are three types of Registration Matrices: +RIGID: This is a registration involving only translations and rotations. Mathematically, the matrix is constrained to be orthonormal and describes six degrees of freedom: three translations, and three rotations. +RIGID_SCALE: This is a registration involving only translations, rotations and scaling. Mathematically, the matrix is constrained to be orthogonal and describes nine degrees of freedom: three translations, three rotations and three scales. This type of transformation is sometimes used in atlas mapping. +AFFINE: This is a registration involving translations, rotations, scaling and shearing. Mathematically, there are no constraints on the elements of the Frame of Reference Transformation Matrix, so it conveys twelve degrees of freedom. This type of transformation is sometimes used in atlas mapping. +See the PS 3.17 Annex on Transforms and Mappings for more detail. +
+
+ + The fiducials used to determine the Frame of Reference Transformation Matrix. One or more Items may be present. + + + + The UID that identifies the fiducial used as registration input. + +
+ + + The date the vector grid data creation started. + + + The time the vector grid data creation started. + + + + A sequence of one or more registration items. Each item defines a spatial registration to the referenced images in that item. At least one item shall have a Deformable Registration Grid Sequence (0064,0005) with one item. See C.20.3.1.1. +
The registrations in this module are applied to the Registered RCS coordinates in the following order. First, transform the coordinates using the matrix described in the Pre Deformation Matrix Registration Sequence (0064,000F). Next apply the deformation offsets to the resulting coordinates. Finally, transform those coordinates using the matrix described in the Post Deformation Matrix Registration Sequence (0064,0010). The resulting coordinate addresses the sample point within the Source RCS. +Thus a source coordinate may be calculated using the following equation: +(This assumes that the center position of each deformation voxel will be transformed) + + + + + + + + + + + + + + + X + + + + + Source + + + + + + + + + + + + + + Y + + + + + Source + + + + + + + + + + + + + + Z + + + + + Source + + + + + + + + + + + + 1 + + + + + = + + M + + + + + Post + + + + + + + + + + M + + + + Pr + e + + + + + + + + + + + + + X + + + + + Start + + + + + +  + + i + ∗ + + X + + + R + + + + + + + + + + + + + + + Y + + + + + Start + + + + + +  + + j + ∗ + + Y + + + R + + + + + + + + + + + + + + + Z + + + + + Start + + + + + +  + + k + ∗ + + Z + + + R + + + + + + + + + + + + 1 + + + + +  + + + + + + + ΔX + + + + + ijk + + + + + + + + + + + + + + ΔY + + + + + ijk + + + + + + + + + + + + + + ΔZ + + + + + ijk + + + + + + + + + + + + 0 + + + + + + + + + + + + + size 12{ left [ matrix { +X rSub { size 8{ ital "Source"} } {} ## +Y rSub { size 8{ ital "Source"} } {} ## +Z rSub { size 8{ ital "Source"} } {} ## +1 +} right ]=M rSub { size 8{ ital "Post"} } left (M rSub { size 8{"Pr"e} } left [ matrix { +X rSub { size 8{ ital "Start"} } +i*X rSub { size 8{R} } {} ## +Y rSub { size 8{ ital "Start"} } +j*Y rSub { size 8{R} } {} ## +Z rSub { size 8{ ital "Start"} } +k*Z rSub { size 8{R} } {} ## +1 +} right ]+ left [ matrix { +ΔX rSub { size 8{ ital "ijk"} } {} ## +ΔY rSub { size 8{ ital "ijk"} } {} ## +ΔZ rSub { size 8{ ital "ijk"} } {} ## +0 +} right ] right )} {} + + +Where: + The spatial coordinate in the Source RCS. + The start coordinate, in the Registered RCS, of the deformation grid as specified in the Image Position (Patient) attribute (0020,0032). + The index into the deformation grid in the X, Y, and Z dimension. + The resolution of the deformation grid in the X, Y, and Z dimension as specified in the Grid Resolution attribute (0064,0008). + The deformation specified at index (i,j,k) in the deformation grid. If the Deformation Registration Grid Sequence (0064,0005) has no items, the ï„ values are zero. +MPre The transformation matrix specified in the Pre Deformation Matrix Registration Sequence (0064,000F). +MPost The transformation matrix specified in the Post Deformation Matrix Registration Sequence (0064,0010). +
+
+ + Identifies the Frame of Reference of a Source RCS. The Source RCS may or may not include an image set (e.g. atlas). See C.7.4.1.1.1 for further explanation. +
The Frame of Reference UID (0020,0052) shall be used to uniquely identify a frame of reference for a series. Each series shall have a single Frame of Reference UID. However, multiple Series within a Study may share a Frame of Reference UID. All images in a Series that share the same Frame of Reference UID shall be spatially related to each other. +Notes: 1. Previous versions of this Standard defined a Data Element "Location", which has been retired. Frame of Reference UID provides a completely unambiguous identification of the image location reference used to indicate position. + 2. A common Frame of Reference UID may be used to spatially relate localizer images with a set of transverse images. However, in some cases (eg. multiple localizer images being related to a single set of transverse images) a common Frame of Reference UID may not be sufficient. The Referenced Image Sequence (0008,1140) provides an unambiguous method for relating localizer images. + +
+
+ + Identifies the set of images registered in this sequence item. One or more items shall be present. Required if the registration applies to a subset of images within the specified Source Frame of Reference UID (0064,0003). All referenced images shall be in the same spatial frame of reference. + + + + User description or comments about the registration. + + + Describes the method used for the registration process. Zero or one item shall be present. + + + + A sequence that specifies one spatial registration to be applied prior to the deformation. Exactly one item shall be present. Required if a matrix transformation is to be applied prior to deformation. + + + A 4x4 homogeneous transformation matrix. Matrix elements shall be listed in row-major order. See C.20.2.1.1. +
The Frame of Reference Transformation Matrix (3006,00C6) AMB describes how to transform a point (Bx,By,Bz) with respect to RCSB into (Ax,Ay,Az) with respect to RCSA according to the equation below. + + + + + + + + + + + + + + + + + + + + A + + + + x + + + + + + + + + + + + + + A + + + + y + + + + + + + + + + + + + + A + + + + z + + + + + + + 1 + + + + + = + + + + + + + M + + + 11 + + + + + + + + + + M + + + 12 + + + + + + + + + + M + + + 13 + + + + + + + + + + T + + + x + + + + + + + + + + + + M + + + 21 + + + + + + + + + + M + + + 22 + + + + + + + + + + M + + + 23 + + + + + + + + + + T + + + y + + + + + + + + + + + + M + + + 31 + + + + + + + + + + M + + + 32 + + + + + + + + + + M + + + 33 + + + + + + + + + + T + + + z + + + + + + + + + + + 0 + + + + + + 0 + + + + + + 0 + + + + + + 1 + + + + + + + + + + + + + + + + + + + B + + + + x + + + + + + + + + + + + + + B + + + + y + + + + + + + + + + + + + + B + + + + z + + + + + + + 1 + + + + + + + + + + size 12{ left [ matrix { +"" lSup { size 8{A} } x {} ## +"" lSup { size 8{A} } y {} ## +"" lSup { size 8{A} } z {} ## +1 +} right ]= left [ matrix { +M rSub { size 8{"11"} } {} # M rSub { size 8{"12"} } {} # M rSub { size 8{"13"} } {} # T rSub { size 8{x} } {} ## +M rSub { size 8{"21"} } {} # M rSub { size 8{"22"} } {} # M rSub { size 8{"23"} } {} # T rSub { size 8{y} } {} ## +M rSub { size 8{"31"} } {} # M rSub { size 8{"32"} } {} # M rSub { size 8{"33"} } {} # T rSub { size 8{z} } {} ## +0 {} # 0 {} # 0 {} # 1{} +} right ] left [ matrix { +"" lSup { size 8{B} } x {} ## +"" lSup { size 8{B} } y {} ## +"" lSup { size 8{B} } z {} ## +1 +} right ]} {} + + +The Frame of Reference Transformation Matrix is expressible as multiple matrices, each in a separate item of the Matrix Sequence (0070,030A). The equation below specifies the order of the matrix multiplication where M1, M2 and M3 are the first, second and third items in the sequence. + + + + + + + + + + + + + + + x + ' + + + + + + y + ' + + + + + + z + ' + + + + + + 1 + + + + + + + + + T + + + + = + + M + + + 3 + + + + + + + + M + + + 2 + + + + + + + M + + + 1 + + + + + + + + + + x + + + + + + y + + + + + + z + + + + + + 1 + + + + + + + + + T + + + + + + + + + + + + + size 12{ left [ matrix { +x' {} # y' {} # z' {} # 1{} +} right ] rSup { size 8{T} } =M rSub { size 8{3} } left (M rSub { size 8{2} } left (M rSub { size 8{1} } left [ matrix { +x {} # y {} # z {} # 1{} +} right ] rSup { size 8{T} } right ) right )} {} + + +where = +Registration often involves two or more RCS, each with a corresponding Frame of Reference Transformation Matrix. For example, another Frame of Reference Transformation Matrix AMC can describe how to transform a point (Cx,Cy,Cz) with respect to RCSC into (Ax,Ay,Az) with respect to RCSA. It is straightforward to find the Frame of Reference Transformation Matrix BMC that describes how to transform the point (Cx,Cy,Cz) with respect to RCSC into the point (Bx,By,Bz) with respect to RCSB. The solution is to invert AMB and multiply by AMC, as shown below: + + + + + + + + + + + + + + + + + + + + B + + + + x + + + + + + + + + + + + + + B + + + + y + + + + + + + + + + + + + + B + + + + z + + + + + + + 1 + + + + + = +  + + + + + + + + A + + + + + Μ + + + B + + + + + +  + + + + − + 1 + + + + + ∗ + + + + + + + A + + + + + + M + + + C + + + + + + + + + + + + + + + C + + + + x + + + + + + + + + + + + + + C + + + + y + + + + + + + + + + + + + + C + + + + z + + + + + + + 1 + + + + + + + + + + size 12{ left [ matrix { +"" lSup { size 8{B} } x {} ## +"" lSup { size 8{B} } y {} ## +"" lSup { size 8{B} } z {} ## +1 +} right ]= \( "" lSup { size 8{A} } Μ rSub { size 8{B} } \) rSup { size 8{ - 1} } * "" lSup { size 8{A} } M rSub { size 8{C} } left [ matrix { +"" lSup { size 8{C} } x {} ## +"" lSup { size 8{C} } y {} ## +"" lSup { size 8{C} } z {} ## +1 +} right ]} {} + + + +
+
+ + Type of Frame of Reference Transformation Matrix (3006,00C6). Defined terms: +RIGID +RIGID_SCALE +AFFINE +See C.20.2.1.2 +
There are three types of Registration Matrices: +RIGID: This is a registration involving only translations and rotations. Mathematically, the matrix is constrained to be orthonormal and describes six degrees of freedom: three translations, and three rotations. +RIGID_SCALE: This is a registration involving only translations, rotations and scaling. Mathematically, the matrix is constrained to be orthogonal and describes nine degrees of freedom: three translations, three rotations and three scales. This type of transformation is sometimes used in atlas mapping. +AFFINE: This is a registration involving translations, rotations, scaling and shearing. Mathematically, there are no constraints on the elements of the Frame of Reference Transformation Matrix, so it conveys twelve degrees of freedom. This type of transformation is sometimes used in atlas mapping. +See the PS 3.17 Annex on Transforms and Mappings for more detail. +
+
+ + A sequence that specifies one spatial registration to be applied after the application of the deformation. Exactly one item shall be present. Required if matrix transformation is to be performed after application of the deformation. + + + A 4x4 homogeneous transformation matrix. Matrix elements shall be listed in row-major order. See C.20.2.1.1. +
The Frame of Reference Transformation Matrix (3006,00C6) AMB describes how to transform a point (Bx,By,Bz) with respect to RCSB into (Ax,Ay,Az) with respect to RCSA according to the equation below. + + + + + + + + + + + + + + + + + + + + A + + + + x + + + + + + + + + + + + + + A + + + + y + + + + + + + + + + + + + + A + + + + z + + + + + + + 1 + + + + + = + + + + + + + M + + + 11 + + + + + + + + + + M + + + 12 + + + + + + + + + + M + + + 13 + + + + + + + + + + T + + + x + + + + + + + + + + + + M + + + 21 + + + + + + + + + + M + + + 22 + + + + + + + + + + M + + + 23 + + + + + + + + + + T + + + y + + + + + + + + + + + + M + + + 31 + + + + + + + + + + M + + + 32 + + + + + + + + + + M + + + 33 + + + + + + + + + + T + + + z + + + + + + + + + + + 0 + + + + + + 0 + + + + + + 0 + + + + + + 1 + + + + + + + + + + + + + + + + + + + B + + + + x + + + + + + + + + + + + + + B + + + + y + + + + + + + + + + + + + + B + + + + z + + + + + + + 1 + + + + + + + + + + size 12{ left [ matrix { +"" lSup { size 8{A} } x {} ## +"" lSup { size 8{A} } y {} ## +"" lSup { size 8{A} } z {} ## +1 +} right ]= left [ matrix { +M rSub { size 8{"11"} } {} # M rSub { size 8{"12"} } {} # M rSub { size 8{"13"} } {} # T rSub { size 8{x} } {} ## +M rSub { size 8{"21"} } {} # M rSub { size 8{"22"} } {} # M rSub { size 8{"23"} } {} # T rSub { size 8{y} } {} ## +M rSub { size 8{"31"} } {} # M rSub { size 8{"32"} } {} # M rSub { size 8{"33"} } {} # T rSub { size 8{z} } {} ## +0 {} # 0 {} # 0 {} # 1{} +} right ] left [ matrix { +"" lSup { size 8{B} } x {} ## +"" lSup { size 8{B} } y {} ## +"" lSup { size 8{B} } z {} ## +1 +} right ]} {} + + +The Frame of Reference Transformation Matrix is expressible as multiple matrices, each in a separate item of the Matrix Sequence (0070,030A). The equation below specifies the order of the matrix multiplication where M1, M2 and M3 are the first, second and third items in the sequence. + + + + + + + + + + + + + + + x + ' + + + + + + y + ' + + + + + + z + ' + + + + + + 1 + + + + + + + + + T + + + + = + + M + + + 3 + + + + + + + + M + + + 2 + + + + + + + M + + + 1 + + + + + + + + + + x + + + + + + y + + + + + + z + + + + + + 1 + + + + + + + + + T + + + + + + + + + + + + + size 12{ left [ matrix { +x' {} # y' {} # z' {} # 1{} +} right ] rSup { size 8{T} } =M rSub { size 8{3} } left (M rSub { size 8{2} } left (M rSub { size 8{1} } left [ matrix { +x {} # y {} # z {} # 1{} +} right ] rSup { size 8{T} } right ) right )} {} + + +where = +Registration often involves two or more RCS, each with a corresponding Frame of Reference Transformation Matrix. For example, another Frame of Reference Transformation Matrix AMC can describe how to transform a point (Cx,Cy,Cz) with respect to RCSC into (Ax,Ay,Az) with respect to RCSA. It is straightforward to find the Frame of Reference Transformation Matrix BMC that describes how to transform the point (Cx,Cy,Cz) with respect to RCSC into the point (Bx,By,Bz) with respect to RCSB. The solution is to invert AMB and multiply by AMC, as shown below: + + + + + + + + + + + + + + + + + + + + B + + + + x + + + + + + + + + + + + + + B + + + + y + + + + + + + + + + + + + + B + + + + z + + + + + + + 1 + + + + + = +  + + + + + + + + A + + + + + Μ + + + B + + + + + +  + + + + − + 1 + + + + + ∗ + + + + + + + A + + + + + + M + + + C + + + + + + + + + + + + + + + C + + + + x + + + + + + + + + + + + + + C + + + + y + + + + + + + + + + + + + + C + + + + z + + + + + + + 1 + + + + + + + + + + size 12{ left [ matrix { +"" lSup { size 8{B} } x {} ## +"" lSup { size 8{B} } y {} ## +"" lSup { size 8{B} } z {} ## +1 +} right ]= \( "" lSup { size 8{A} } Μ rSub { size 8{B} } \) rSup { size 8{ - 1} } * "" lSup { size 8{A} } M rSub { size 8{C} } left [ matrix { +"" lSup { size 8{C} } x {} ## +"" lSup { size 8{C} } y {} ## +"" lSup { size 8{C} } z {} ## +1 +} right ]} {} + + + +
+
+ + Type of Frame of Reference Transformation Matrix (3006,00C6). Defined terms: +RIGID +RIGID_SCALE +AFFINE +See C.20.2.1.2 +
There are three types of Registration Matrices: +RIGID: This is a registration involving only translations and rotations. Mathematically, the matrix is constrained to be orthonormal and describes six degrees of freedom: three translations, and three rotations. +RIGID_SCALE: This is a registration involving only translations, rotations and scaling. Mathematically, the matrix is constrained to be orthogonal and describes nine degrees of freedom: three translations, three rotations and three scales. This type of transformation is sometimes used in atlas mapping. +AFFINE: This is a registration involving translations, rotations, scaling and shearing. Mathematically, there are no constraints on the elements of the Frame of Reference Transformation Matrix, so it conveys twelve degrees of freedom. This type of transformation is sometimes used in atlas mapping. +See the PS 3.17 Annex on Transforms and Mappings for more detail. +
+
+ + Describes the deformation grid used to sample into the Source RCS. Exactly one item shall be present. Required if deformation is performed. See C.20.3.1.2. +
The vector represents the deformation at the center of the voxel. Deformations between voxel centers shall be determined through interpolation of the surrounding vectors in an implementation dependent manner. +
+
+ + The direction of cosines of the first row and first column of the Vector Grid Data (0064,0009) with respect to the patient. See C.7.6.2.1.1 for further explanation. +
The Image Position (0020,0032) specifies the x, y, and z coordinates of the upper left hand corner of the image; it is the center of the first voxel transmitted. Image Orientation (0020,0037) specifies the direction cosines of the first row and the first column with respect to the patient. These Attributes shall be provide as a pair. Row value for the x, y, and z axes respectively followed by the Column value for the x, y, and z axes respectively. +The direction of the axes is defined fully by the patient’s orientation. The x-axis is increasing to the left hand side of the patient. The y-axis is increasing to the posterior side of the patient. The z-axis is increasing toward the head of the patient. +The patient based coordinate system is a right handed system, i.e. the vector cross product of a unit vector along the positive x-axis and a unit vector along the positive y-axis is equal to a unit vector along the positive z-axis. +Note If a patient lies parallel to the ground, face-up on the table, with his feet-to-head direction same as the front-to-back direction of the imaging equipment, the direction of the axes of this patient based coordinate system and the equipment based coordinate system in previous versions of this Standard will coincide. + +The Image Plane Attributes, in conjunction with the Pixel Spacing Attribute, describe the position and orientation of the image slices relative to the patient-based coordinate system. In each image frame the Image Position (Patient) (0020,0032) specifies the origin of the image with respect to the patient-based coordinate system. RCS and the Image Orientation (Patient) (0020,0037) attribute values specify the orientation of the image frame rows and columns. The mapping of pixel location to the RCS is calculated as follows: + + size 12{ left [ matrix { +P rSub { size 8{x} } {} ## +P rSub { size 8{y} } {} ## +P rSub { size 8{z} } {} ## +1 +} right ]= left [ matrix { +X rSub { size 8{x} } Δi {} # Y rSub { size 8{x} } Δj {} # 0 {} # S rSub { size 8{x} } {} ## +X rSub { size 8{y} } Δi {} # Y rSub { size 8{y} } Δj {} # 0 {} # S rSub { size 8{y} } {} ## +X rSub { size 8{z} } Δi {} # Y rSub { size 8{z} } Δj {} # 0 {} # S rSub { size 8{z} } {} ## +0 {} # 0 {} # 0 {} # 1{} +} right ] left [ matrix { +i {} ## +j {} ## +0 {} ## +1 +} right ]} {} + + = M +Where: +Pxyz The coordinates of the voxel (i,j) in the frame’s image plane in units of mm. +Sxyz The three values of the Image Position (Patient) (0020,0032) attributes. It is the location in mm from the origin of the RCS. +Xxyz The values from the row (X) direction cosine of the Image Orientation (Patient) (0020,0037) attribute. +Yxyz The values from the column (Y) direction cosine of the Image Orientation (Patient) (0020,0037) attribute. +i Column index to the image plane. The first column is index zero. +ï„i Column pixel resolution of the Pixel Spacing (0028,0030) attribute in units of mm. +j Row index to the image plane. The first row index is zero. +ï„j Row pixel resolution of the Pixel Spacing (0028,0030) attribute in units of mm. + +Additional constraints apply: +1) The row and column direction cosine vectors shall be orthogonal, i.e. their dot product shall be zero. +2) The row and column direction cosine vectors shall be normal, i.e. the dot product of each direction cosine vector with itself shall be unity. + +
+
+ + The x, y, and z coordinates of the upper left hand voxel (center of the first voxel transmitted) of the grid, in mm in the Registered Frame of Reference. See C.7.6.2.1.1 for further explanation. +
The Image Position (0020,0032) specifies the x, y, and z coordinates of the upper left hand corner of the image; it is the center of the first voxel transmitted. Image Orientation (0020,0037) specifies the direction cosines of the first row and the first column with respect to the patient. These Attributes shall be provide as a pair. Row value for the x, y, and z axes respectively followed by the Column value for the x, y, and z axes respectively. +The direction of the axes is defined fully by the patient’s orientation. The x-axis is increasing to the left hand side of the patient. The y-axis is increasing to the posterior side of the patient. The z-axis is increasing toward the head of the patient. +The patient based coordinate system is a right handed system, i.e. the vector cross product of a unit vector along the positive x-axis and a unit vector along the positive y-axis is equal to a unit vector along the positive z-axis. +Note If a patient lies parallel to the ground, face-up on the table, with his feet-to-head direction same as the front-to-back direction of the imaging equipment, the direction of the axes of this patient based coordinate system and the equipment based coordinate system in previous versions of this Standard will coincide. + +The Image Plane Attributes, in conjunction with the Pixel Spacing Attribute, describe the position and orientation of the image slices relative to the patient-based coordinate system. In each image frame the Image Position (Patient) (0020,0032) specifies the origin of the image with respect to the patient-based coordinate system. RCS and the Image Orientation (Patient) (0020,0037) attribute values specify the orientation of the image frame rows and columns. The mapping of pixel location to the RCS is calculated as follows: + + size 12{ left [ matrix { +P rSub { size 8{x} } {} ## +P rSub { size 8{y} } {} ## +P rSub { size 8{z} } {} ## +1 +} right ]= left [ matrix { +X rSub { size 8{x} } Δi {} # Y rSub { size 8{x} } Δj {} # 0 {} # S rSub { size 8{x} } {} ## +X rSub { size 8{y} } Δi {} # Y rSub { size 8{y} } Δj {} # 0 {} # S rSub { size 8{y} } {} ## +X rSub { size 8{z} } Δi {} # Y rSub { size 8{z} } Δj {} # 0 {} # S rSub { size 8{z} } {} ## +0 {} # 0 {} # 0 {} # 1{} +} right ] left [ matrix { +i {} ## +j {} ## +0 {} ## +1 +} right ]} {} + + = M +Where: +Pxyz The coordinates of the voxel (i,j) in the frame’s image plane in units of mm. +Sxyz The three values of the Image Position (Patient) (0020,0032) attributes. It is the location in mm from the origin of the RCS. +Xxyz The values from the row (X) direction cosine of the Image Orientation (Patient) (0020,0037) attribute. +Yxyz The values from the column (Y) direction cosine of the Image Orientation (Patient) (0020,0037) attribute. +i Column index to the image plane. The first column is index zero. +ï„i Column pixel resolution of the Pixel Spacing (0028,0030) attribute in units of mm. +j Row index to the image plane. The first row index is zero. +ï„j Row pixel resolution of the Pixel Spacing (0028,0030) attribute in units of mm. + +Additional constraints apply: +1) The row and column direction cosine vectors shall be orthogonal, i.e. their dot product shall be zero. +2) The row and column direction cosine vectors shall be normal, i.e. the dot product of each direction cosine vector with itself shall be unity. + +
+
+ + The dimensions of the grid, in voxels. A triple representing the number of voxels along the X, Y, and Z axes. + + + The resolution of the grid voxels. A triple representing the size of a deformation voxel in along the X, Y, and Z dimension, in mm. + + + A data stream of vectors. See C.20.3.1.3 for further explanation. +
The Vector Grid Data attribute (0064,0009) contains the vector data. Each voxel in the Vector Grid Data attribute (0064,0009) is represented by an vector. The vector describes the direction and magnitude of the deformation at the center of the deformation voxel. +The order of vectors sent for each vector plane shall be left to right, top to bottom, i.e., the upper left vector (labeled 1,1) is sent first followed by the remainder of row 1, followed by the first vector of row 2 (labeled 2,1) then the remainder of row 2 and so on. +A vector triple with values of (NaN,NaN,NaN) shall indicate that the transformation at that point of the deformation grid is undefined. +The size of this attribute value is determined by the dimensions specified in the Grid Dimensions attribute (0064,0007). For dimensions of XD\YD\ZD, the size of the attribute value can be calculated with the equation: +Number of Bytes = XD * YD * ZD * 3 * 4 + +
+
+ + The fiducials used to determine the registration. One or more Items may be present. + + + + The UID that identifies the fiducial used as registration input. + +
+ + + Modality type. +Enumerated Value: +FID + + + + + The date the content creation started. + + + The time the content creation started. + + + + A sequence of one or more items, each of which is a fiducial set. + + + Identifies a Frame of Reference that may or may not be an image set (e.g. an atlas or physical space). See C.7.4.1.1.1 for further explanation. Required if Referenced Image Sequence (0008,1140) is absent. May be present otherwise. +
The Frame of Reference UID (0020,0052) shall be used to uniquely identify a frame of reference for a series. Each series shall have a single Frame of Reference UID. However, multiple Series within a Study may share a Frame of Reference UID. All images in a Series that share the same Frame of Reference UID shall be spatially related to each other. +Notes: 1. Previous versions of this Standard defined a Data Element "Location", which has been retired. Frame of Reference UID provides a completely unambiguous identification of the image location reference used to indicate position. + 2. A common Frame of Reference UID may be used to spatially relate localizer images with a set of transverse images. However, in some cases (eg. multiple localizer images being related to a single set of transverse images) a common Frame of Reference UID may not be sufficient. The Referenced Image Sequence (0008,1140) provides an unambiguous method for relating localizer images. + +
+
+ + Identifies the set of images in which the fiducials are located. Required if Frame of Reference UID (0020,0052) is absent. May be present otherwise. One or more Items shall be present. +All referenced images shall have the same Frame of Reference UID if present in the images. + + + + A sequence that specifies one or more fiducials, one item per fiducial. + + + A fiducial assignment identifier that is unique within this Fiducial Sequence item but may match the fiducial identifier of an equivalent feature in another item. + + + A code sequence for a term that identifies a well-known fiducial type (potentially including methodology, anatomy, tools, etc.). Only one item shall be present. Required if Identifier (0070,0310) is absent. May be present otherwise. + + + + Globally unique identifier for the fiducial instance of this fiducial assignment. + + + User description or comments about the fiducial. + + + See C.21.2.1.1 for defined terms. +
For convenient registration, correlated Fiducials exist in each image set of the Registration Sequence. Correlated Fiducials are identified with either Fiducial Identifier (0070,0310) or Fiducial Identifier Code Sequence (0070,0311). + +Shape Type (0070,0306) defines the geometric interpretation of the Contour Data (3006,0050) and Graphic Data (0070,0022). A point is defined as a triplet (x,y,z) in the case of spatial data or a pair (x,y) in the case of graphic data. +Defined Terms are: +POINT = a single point designating a single fiducial point. +Note: A point may be the epicenter of a more complex shape such as sphere. +LINE = two points that specify a line or axis such as the inter-orbital line. The point locations have no significance other than identifying the line, i.e. they are not line segment end points. +PLANE = three points that identify a plane such as the laterality plane +SURFACE = three or more points (usually many) that reside on, or near, a region of a curved surface. The surface may be flat or curved, closed or open. The point order has no significance. +RULER = two or more evenly spaced collinear points ordered sequentially along the line, such as a physical ruler placed in the imaging field. +L_SHAPE = three points of two perpendicular line segments, AB and BC, having a common end point B. The order of the points is: ABC. May represent an L-shaped marker placed in the imaging field. +T_SHAPE = three points of two perpendicular line segments AB and CD, such that C bisects AB. The order is ABD. +SHAPE = three or more points that specify the shape of a well-known fiducial type. The term in the Fiducial Identifier Code Sequence (0070,0311) defines the shape and the order of the points that represent it. +
+
+ + Number of points (triplets) in Contour Data (3006,0050). Required if Contour Data is present. + + + Specifies the coordinates of this item's fiducial. One triplet (x,y,z) shall be present for each point in the fiducial. See C.21.2.1.2 for further explanation. Required if Frame of Reference UID (0020,0052) is present in this item of the Fiducial Set Sequence (0070,031C). Shall not be present otherwise. +Note: Contour Data may not be properly encoded if Explicit-VR transfer syntax is used and the VL of this attribute exceeds 65534 bytes. +
Contour Data (3006,0050) is an ordered set of triplets that defines a shape. The triplets (x,y,z) denote points in the Reference Coordinate System of the Registration Instance. +Note: Contours may associate observational data with a set of Image features or specify coordinates that are input data for a measurement. +
+
+ + The estimated uncertainty radius for the Contour Data in mm. See C.21.2.1.3 +
The uncertainty is an estimate of the standard deviation of the fiducial location process. +
+
+ + The image pixel locations of the fiducial's points. Shall contain one or more items. More than one item shall be present only if a fiducial spans more than one image. Required if Contour Data is not present. May be present otherwise. + + + Graphic point coordinates of the fiducial points in the image of the Referenced Image Sequence. If Fiducial's Contour Data (3006,0050) is present, these points correlate to the points in the Contour Data, one row-column pair for each point and in the same order. +See C.10.5.1.2 for further explanation. +
Graphic Data (0070,0022) contains the points in the graphic annotation, each dimension for the first point, followed by dimensions for second point, etc. For a two dimensional curve: X1, Y1, X2, Y2, etc. The first (X) dimension corresponds to the image or Specified Displayed Area column (horizontal offset), and the second (Y) dimension corresponds to the image or Specified Displayed Area row (vertical offset). The Value Representation of all components of the N-tuple shall be the same. The image or Specified Displayed Area relative drawing space is defined in Graphic Annotation Units (0070,0005). +If Graphic Type (0070,0023) is POINT, then two values (one point) shall be specified and the single point specified is to be drawn. +If Graphic Type (0070,0023) is POLYLINE, then the points are to be interpreted as an n-tuple list of end points between which straight lines are to be drawn. +If Graphic Type (0070,0023) is INTERPOLATED, then the points are to be interpreted as an n-tuple list of end points between which some form of implementation dependent curved lines are to be drawn. The rendered line shall pass through all the specified points. +If Graphic Type (0070,0023) is CIRCLE, then exactly two points shall be present; the first point is to be interpreted as the center and the second point as a point on the circumference of a circle, some form of implementation dependent representation of which is to be drawn. +If Graphic Type (0070,0023) is ELLIPSE, then exactly four points shall be present; the first two points are to be interpreted as the endpoints of the major axis and the second two points as the endpoints of the minor axis of an ellipse, some form of implementation dependent representation of which is to be drawn. +The notion of “open†or “closed†has no inherent meaning in the context of an arbitrary graphic, other than in the condition for the presence of Graphic Filled (0070,0024). The graphic has no semantic notion of an associated observation such as a region of interest, except that which the unformatted text in the same Item may describe. +The choice of pixel value used to represent the graphic on a display is defined in the Graphic Layer Module C.10.7. + +Figure C.10.5-1 +Sub-pixel Addressing Units in PIXEL Space +
+
+ + A sequence that specifies the image containing the fiducial's graphic coordinates. Only one item shall be present. Shall be an image within the set of the images in the Referenced Image Sequence (0008,1140) of the encapsulating Fiducial Set Sequence (0070,031C) item. + + +
+ + + User or implementation specific human readable identification of the Storage Media to be created. + + + Uniquely identifies a Storage Media to be created. + + + Number of copies of set of media to be created for storing this file-set. +Note: If the entire request fits on a single piece of media per copy, then this value corresponds to the actual number of pieces of media to be created. + + + Specifies the priority of the request. +Enumerated Values: +HIGH +MED +LOW + + + Specifies whether or not to extract label information from the instances. +Enumerated Values: +YES +NO + + + Unformatted free text to include in the label instead of or in addition to information extracted from the instances. + + + An implementation-dependent code string that may be used as a hint to select a particular layout or format of label. + + + Unstructured text that describes where and to whom the media is to be sent. + + + String that describes the bar code value to be printed on the media label. +Note It is SCU responsibility to convey a value for this attribute coherent in length and content with the requested Barcode Symbology (2200,0006). + + + Code string that describes the bar code symbology that shall be used for printing the Barcode Value (2200,0005). +See Section C.22.1.1 for Defined Terms. +
Defined Terms for Barcode Symbology (2200,0006) are: + +Note This table doesn’t suppose to list all the bar code symbologies in use (there are currently more than 400). Implementations supporting other symbologies can extend this list. Implementation specific code values shall be defined in the Conformance Statement. + +
+
+ + A flag indicating if the SCP is allowed to split this request over more than one piece of media. +Enumerated Values: +YES +NO + +Note: 1. The SCP is not required to support the split of a media creation request across more than one piece of media. +2. If the size of the set of SOP instances is greater than the media storage capacity, and this flag has been set to NO, the SCP shall refuse to process the request. + + + A flag indicating if the SCP is allowed to perform lossy compression. +Enumerated Values: +YES +NO + + + A flag indicating if the SCP should include in the media additional Non-DICOM information/objects +Defined Terms: +NO +FOR_PHYSICIAN +FOR_PATIENT +FOR_TEACHING +FOR_RESEARCH + + + A flag indicating if the SCP should include on the media a DICOM Instance Display Application. +Enumerated Values: +NO +YES + + + A flag to indicate whether or not the SCU intends to issue a subsequent media creation request referencing some or all of the instances contained in Referenced SOP Sequence (0008,1199). +Enumerated Values: +YES +NO + + + A sequence of Items where each Item references a single SOP Instance, the Media Application Profile to be used, and, where applicable, the icon representing the referenced image + + + + The Media Application Profile to be used for this SOP Instance. +Note: This is the label of the profile as defined in PS 3.11, e.g. "STD-XABC-CD". + + + This Icon Image is representative of the Image. + + + + Execution status of a request. +See Section C.22.1.2 for Enumerated Values +
Enumerated Values for Execution Status (2100,0020) are: + +
+
+ + Additional information about Execution Status (2100,0020). +When Execution Status is DONE, CREATING or IDLE, Defined Terms are: +NORMAL +See Section C.22.1.3 for Defined Terms when the Execution Status is PENDING or FAILURE. +
Defined Terms for Execution Status Info (2100,0030) are: + +Note: For most of the above statuses, the SCU can obtain more details about the processing errors (e.g., what are the SOP instances not available) by using the Failure Reason Attribute (0008,1197) within the Failed SOP Sequence (0008,1198). + +
+
+ + Number of pieces of media that have been successfully created, in order to store all copies of the requested file-set. +Note: If the entire request fits on a single piece of media per copy, then this value corresponds to the number of copies of media created. + + + A sequence of Items describing SOP Instances for which media creation failed. + + + + The Media Application Profile used for this SOP Instance. +Note: This is the label of the profile as defined in PS 3.11, e.g. "STD-XABC-CD". + + + The reason that media creation failed for this SOP Instance. +See Section C.22.1.4. +
Defined Terms for Failure Reason (0008,1197) are: + +
+
+ + Attributes associated with the Failure Reason (0008,1197). +See Section C.22.1.4. +
Defined Terms for Failure Reason (0008,1197) are: + +
+
+ + A Sequence describing the identifiers of all pieces of media created to satisfy the request. One or more items are allowed. +Note: If the SCP splits a media creation request across more than one piece of media (e.g. if it doesn't fit on one), then all the created pieces of media will be included in this Sequence. + + + User or implementation specific human readable identification of the Storage Media that has been created. + + + Uniquely identifies the Storage Media that has been created. + +
+ + + Short descriptor that identifies the Hanging Protocol. + + + Explanation of the objective or intent of the Hanging Protocol. + + + Identifies the level at which this Hanging Protocol is defined, and the intended use. +Enumerated values: +MANUFACTURER +SITE +USER_GROUP +SINGLE_USER + + + Identifies the creator of the Hanging Protocol. + + + Date and time on which the Hanging Protocol was created. + + + Sequence that defines the type of imaging studies to which this Hanging Protocol applies. One or more sequence items shall be present. See C.23.1.1.1. +
The Hanging Protocol Definition Sequence (0072,000C) provides a collection of one or more sequence items that defines the intent for the Hanging Protocol with respect to modality, anatomy, laterality, procedure and/or reason. +This allows for some degree of flexibility in defining the intent for the Hanging Protocol, while providing a precise structure for query matching using the existing rules for Sequence Matching, as defined in PS 3.4. +Notes:1. The Hanging Protocol Definition Sequence (0072,000C) does not imply anything about the related image sets. These are defined in the Image Sets Sequence (0072,0020). +2. When creating a Hanging Protocol Instance, the values that are used for Procedure Code Sequence (0008,1032) or Reason for Requested Procedure Code Sequence (0040,100A) may come from a variety of sources, but are expected to be consistent throughout the domain in which a Hanging Protocol Instance will be exchanged. The following are recommended as potential sources of values. +Procedure Code Sequence (0008,1032): +
+
+ + Type of equipment that originally acquired the data used to create images or related objects to which this Hanging Protocol applies. See C.7.3.1.1.1 for Defined Terms. +Required if Anatomic Region Sequence (0008,2218) is not present. May be present otherwise. +
Defined Terms for the Modality (0008,0060) are: + +Retired Defined Terms for the Modality (0008,0060) are: + +Note: 1. The XA modality incorporates the retired modality DS. + 2. The RF modality incorporates the retired modalities CF, DF, VF. + 3. The modality listed in the Modality Data Element (0008,0060) may not match the name of the IOD in which it appears. For example, a SOP instance from XA IOD may list the RF modality when an RF implementation produces an XA object. + 4. The MR modality incorporates the retired modalities MA and MS. + +
+
+ + Sequence that identifies the anatomic region of interest to which this Hanging Protocol applies. One or more sequence items may be present. +Required if Modality (0008,0060) is not present. May be present otherwise. + + + + Laterality of the body part to which this Hanging Protocol applies. +Enumerated Values: +R - Right +L - Left +B - Both +U - Unpaired +Zero length means not applicable. +Required if Anatomic Region Sequence (0008,2218) is present. + + + Sequence that identifies a procedure to which this Hanging Protocol applies. Zero or more sequence items may be present. + + + + Sequence that identifies a reason for procedure to which this Hanging Protocol applies. Zero or more sequence items may be present. + + + + Identifies the number of prior image sets used in this Hanging Protocol. + + + Sequence describing one or more types of Image Sets to which the Hanging Protocol applies. One or more sequence items shall be present. See C.23.1.1.2. +
The Image Sets Sequence (0072,0020) within a Hanging Protocol Instance serves to identify the type of image or other object sets to which the Hanging Protocol is intended to apply. Multiple types of image sets may be identified for a Hanging Protocol, to combine, for example, multiple imaging studies for a specific anatomy, or multiple imaging studies performed over a period of time, to monitor the progress of a condition. All image sets shall be for the same patient. +The images to be included in an Image Set may be specified directly by matching attribute values within the images, or indirectly through Key Object Selection Documents or Presentation States by matching their attribute values. +Key Object Selection Documents shall be matched by their SOP Class UID. The available Key Object Selection Documents may be further matched on the values of their other attributes (e.g., Concept Name Code Sequence, Coding Scheme Designator = “DCM†and Code Value = “113003â€, which has a code meaning of “For Surgeryâ€). When the Hanging Protocol Instance is applied, the image object instances referenced by the matching Key Object Selection Document instances comprise the image set. +Presentation States shall be matched by their SOP Class UID. The available Presentation States may be further matched on the values of their other attributes (e.g., Content Label). When the Hanging Protocol Instance is applied, the image object instances referenced by the matching Presentation State instances comprise the image set. +Note: Image Sets Sequence (0072,0020) allows other objects such as waveforms and SR documents to be identified. However, Hanging Protocol Display module operations such as filtering, reformatting, and sorting are defined only for image objects. The only expectation for non-image objects is to associate the objects with a position on a screen. +Each sequence item in the Image Sets Sequence (0072,0020) shall follow these rules: +
+
+ + Sequence containing Image Set selection attributes and values that are used to identify one type of image or object set for the Hanging Protocol. One or more sequence items shall be present. See C.23.1.1.3. +
The Image Set Selector Sequence (0072,0022) contains sequence items that specify the DICOM attribute tags and values that shall be used to identify the image or other object set. +The Image Set Selector Usage Flag (0072,0024) indicates whether the attribute identified by the Selector Attribute (0072,0026) causes matching to succeed or fail if the attribute is not available in an image object. +Within a sequence item, the Selector Attribute (0072,0026) identifies a DICOM attribute tag that is likely to be present in image or other object instances that are desired for the Image Set. If it is a multi-valued attribute, the Selector Value Number (0072,0028) indicates which value is intended to be used for matching. The Selector Attribute VR (0072,0050) identifies the Value Representation of the Selector Attribute (0072,0026). The value of Selector Attribute VR (0072,0050) determines which attribute of the Hanging Protocol Selector Attribute Value Macro is required to specify one or more desired values for the DICOM attribute tag. If more than one value is specified for the attribute, or more than one sequence item is specified in the Selector Code Sequence Value (0072,0080), then image object instances with a corresponding attribute that matches any one of the values shall be included in the Image Set. +Note: The values used for the Selector Attribute (0072,0026) are intended to identify a type of image set via the general categories of modality, anatomy, procedure intent and/or reason. Therefore the values of the tags represented by Selector Attribute (0072,0026) are likely to be coded terms, enumerated values, defined terms or free text. The use of free text attributes is less desirable, because their values are less predictable for matching. +In an image object, some attributes occur at the top level, or nested within a Sequence or Functional Group Sequence, or both. In addition, a Private Attribute may be identified as a Selector Attribute (0072,0026). The attributes of the Hanging Protocol Selector Attribute Context Macro identify a Sequence, Functional Group Sequence, or Private Group context for the Selector Attribute (0072,0026). +The creator of a Hanging Protocol Instance uses this collection of attributes to identify one type of image set to which the Hanging Protocol is intended to apply. The user of a Hanging Protocol Instance (e.g., softcopy review workstation or pre-fetching application) uses this collection of attributes to match a specific image set to a Hanging Protocol, and/or to determine which image sets need to be retrieved in order to use a Hanging Protocol Instance. The Key Attributes to match against to obtain image sets are specified in the Selector Attribute (0072,0026) and its context in each sequence item. +If the value of the tag represented by Selector Attribute (0072,0026) contains a free text description (i.e., Selector Attribute VR = LO, SH, ST, LT, UT), whether exact or partial matching is used to identify a specific image instance when applying a Hanging Protocol Instance is implementation dependent. +
+
+ + Indicates the behavior of matching against an image object when the Selector Attribute (0072,0026) is not available in the image object. +Enumerated Values: +MATCH - if the attribute is not in the image object, consider the image to be a match anyway. +NO_MATCH - if the attribute is not in the image object, then do not consider the image to be a match. + + + Data Element Tag of an Attribute from an Image or other IOD to use for Image Set selection. + + + The Value Representation of the Selector Attribute (0072,0026). See PS 3.5 for Enumerated Values of Value Representation. + + + + + Positive integer identifying which value of a multi-valued attribute identified by Selector Attribute (0072,0026) is to be used for Image Set selection. The value 1 identifies the first value. The value zero identifies any value. + + + Sequence containing time based Image Set selection categories and values that are used to identify one type of image set for the Hanging Protocol per sequence item. One or more sequence items shall be present. The Image Set Selector Sequence (0072,0022) shall be applied to each sequence item to define an image set. See C.23.1.1.2. +
The Image Sets Sequence (0072,0020) within a Hanging Protocol Instance serves to identify the type of image or other object sets to which the Hanging Protocol is intended to apply. Multiple types of image sets may be identified for a Hanging Protocol, to combine, for example, multiple imaging studies for a specific anatomy, or multiple imaging studies performed over a period of time, to monitor the progress of a condition. All image sets shall be for the same patient. +The images to be included in an Image Set may be specified directly by matching attribute values within the images, or indirectly through Key Object Selection Documents or Presentation States by matching their attribute values. +Key Object Selection Documents shall be matched by their SOP Class UID. The available Key Object Selection Documents may be further matched on the values of their other attributes (e.g., Concept Name Code Sequence, Coding Scheme Designator = “DCM†and Code Value = “113003â€, which has a code meaning of “For Surgeryâ€). When the Hanging Protocol Instance is applied, the image object instances referenced by the matching Key Object Selection Document instances comprise the image set. +Presentation States shall be matched by their SOP Class UID. The available Presentation States may be further matched on the values of their other attributes (e.g., Content Label). When the Hanging Protocol Instance is applied, the image object instances referenced by the matching Presentation State instances comprise the image set. +Note: Image Sets Sequence (0072,0020) allows other objects such as waveforms and SR documents to be identified. However, Hanging Protocol Display module operations such as filtering, reformatting, and sorting are defined only for image objects. The only expectation for non-image objects is to associate the objects with a position on a screen. +Each sequence item in the Image Sets Sequence (0072,0020) shall follow these rules: +
+
+ + A monotonically increasing integer, starting from 1, incrementing by one, unique within the Hanging Protocol Instance. +Note: Each item of the Display Sets Sequence (0072,0200) references one Image Set Number (0072,0032). + + + Category of the Time Based Image Set selector. +Enumerated Values: +RELATIVE_TIME +ABSTRACT_PRIOR + + + Exactly two numeric values, indicating the start and end values of a prior range of instance acquisition times relative to the date and time of a current image set. The units shall be specified in Relative Time Units (0072,003A). +The value pair 0\0 shall indicate a current image set. The value pair n\n shall indicate "prior from the instance acquisition time of a current image set by n units". +Required if the value of Image Set Selector Category (0072,0034) is RELATIVE_TIME. +Note: 1. A value pair "1\7" with Relative Time Units (0072,003A) of DAYS would indicate the range "prior by 1 to 7 days before a current image set". +2. The VR of this attribute is unsigned, hence future time cannot be represented. + + + Units of time for Relative Time (0072,0038). +Enumerated Values: +SECONDS, MINUTES, HOURS, DAYS, WEEKS, MONTHS, YEARS. +Required if Relative Time (0072,0038) is present. + + + Identifies a prior image set in abstract terms. +Exactly two integer values, indicating the range of prior studies to include. Each value shall be greater than zero, where 1 indicates the most recent prior and higher values indicate successively older priors. The special value -1 shall indicate the oldest prior. +Notes: 1. The value pair n\n indicates the nth prior. +2. The value pair -1\-1 indicates the oldest prior. +3. The value pair m\n indicates the mth through nth priors, where m is the more recent prior. +4. The value pair 1\-1 indicates all priors. +5. The value pair m\-1 indicates the mth prior and all priors older than m. +Required if Image Set Selector Category (0072,0034) is ABSTRACT_PRIOR and Abstract Prior Code Sequence (0072,003E) is not present. + + + Identifies a prior image set using coded terminology. Only one sequence item shall be present. +Required if Image Set Selector Category (0072,0034) is ABSTRACT_PRIOR and Abstract Prior Value (0072,003C) is not present. + + + + Description of the objective of the image set defined by this sequence item. + + + Sequence that provides a coded identifier for the person, group, or site for which this Hanging Protocol was defined. Zero or one item shall be present in the sequence. +Note: If a standardized naming schema becomes available, it should be used. Meanwhile, local coding schemes such as employee numbers and department numbers are likely to be used. + + + + Group or site for which this Hanging Protocol was defined. + + + Sequence that identifies the Hanging Protocol from which this Hanging Protocol was derived, or on which it is based. One sequence item may be present. + + +
+ + + Positive integer indicating the number of screens for which this Hanging Protocol is intended. + + + Sequence of zero or more items that describes the set of screens for which this Hanging Protocol is intended. + + + Positive integer indicating the intended number of rows of the addressable area of the screen in pixels. +Note: The goal is not absolute size matching. + + + Positive integer indicating the intended number of columns of the addressable area of the screen in pixels. +Note: The goal is not absolute size matching. + + + Exactly four unitless floating point values indicating the rectangular coordinate position of the screen within the overall bounding box that encompasses all the screens. See C.23.2.1.1. +
For the Display Environment Spatial Position (0072,0108) attribute, the lower left corner of the overall bounding box has Cartesian coordinates of (0.0,0.0). The upper right corner has coordinates of (1.0,1.0). The scale of the box is based on the Number of Vertical Pixels (0072,0104) and Number of Horizontal Pixels (0072,0106), not the physical size of the screens that are part of the workstation. The coordinates of each individual screen’s box are defined in absolute coordinates relative to the (0,0) and (1,1) range of the overall box. Position of a box is given by a (x1,y1), (x2,y2) pair that identifies the upper left corner and lower right corner if the box is rectangular. + +Note: The goal is not absolute position matching of the image boxes rendered on the screens using Hanging Protocol layout information, but that the relative positioning of the image boxes should be consistent between different workstations. +The following figure depicts a 1K x 1K screen positioned to the left of a 2K x 2.5K screen. The Display Environment Spatial Position (0072,0108) of the 1K x 1K screen is (0.0,0.4) (0.33,0.0), and the Display Environment Spatial Position (0072,0108) of the 2K x 2.5K screen is (0.33,1.0) (1.0,0.0). + +
+
+ + Positive integer indicating the desired minimum number of grayscale bits per pixel of the screen. +Required if Screen Minimum Color Bit Depth (0072,010C) is not present. + + + Positive integer indicating the desired minimum total number of bits per color channel used to present a pixel. +Required if Screen Minimum Grayscale Bit Depth (0072,010A) is not present. +Note: A 24-bit color system with 8 bits per color channel (red, green, blue) would have a value of 8. + + + Positive integer indicating the desired maximum time in milliseconds required by the application to repaint the full screen once (i.e., recalculate all pixels and paint them to the screen). +Note: This is not the screen refresh time. + +
+ + + Sequence that describes one or more display sets used to present the Image Sets defined in the Image Sets Sequence (0072,0020). One or more sequence items shall be present. See C.23.3.1. +
The attributes of a Display Set Sequence Item shall be applied to the image set represented by the value of Image Set Number (0072,0032) in the following order: +
+
+ + A monotonically increasing integer, starting from 1, incrementing by one, unique within the Hanging Protocol Instance. It shall be used to identify linked display sets in the Display Set Scrolling Group (0072,0212). + + + Description of the objective of the display set defined by this sequence item. + + + Positive integer value that designates this Display Set as part of a specific presentation group. All Display Sets with the same Display Set Presentation Group (0072,0204) value shall be displayed at the same time. The value 1 shall indicate that this Display Set is part of the initial presentation group.Subsequent values incrementing by 1 shall imply successive temporal ordering of display. + + + Image Set Number (0072,0032) value from a Time Based Image Sets Sequence (0072,0030) Item within the Image Sets Sequence (0072,0020) Item that is selected for display by this Display Set. +Note: Multiple Image Boxes Sequence (0072,0300) Items within a Display Sets Sequence (0072,0200) Item may be used to spread one image set over multiple image boxes with the same Display Set characteristics. + + + Sequence that defines the image boxes for this Display Set. Exactly one sequence item shall be present unless Image Box Layout Type (0072,0304) is TILED, in which case one or more items shall be present. + + + A monotonically increasing integer that identifies the order of image boxes for scrolling, starting from 1, incrementing by one, unique within a Display Set Sequence Item. + + + Exactly four unitless floating point values indicating the rectangular coordinate position of the image box within the overall bounding box that encompasses all the display space (across all screens). See C.23.2.1.1. +
For the Display Environment Spatial Position (0072,0108) attribute, the lower left corner of the overall bounding box has Cartesian coordinates of (0.0,0.0). The upper right corner has coordinates of (1.0,1.0). The scale of the box is based on the Number of Vertical Pixels (0072,0104) and Number of Horizontal Pixels (0072,0106), not the physical size of the screens that are part of the workstation. The coordinates of each individual screen’s box are defined in absolute coordinates relative to the (0,0) and (1,1) range of the overall box. Position of a box is given by a (x1,y1), (x2,y2) pair that identifies the upper left corner and lower right corner if the box is rectangular. + +Note: The goal is not absolute position matching of the image boxes rendered on the screens using Hanging Protocol layout information, but that the relative positioning of the image boxes should be consistent between different workstations. +The following figure depicts a 1K x 1K screen positioned to the left of a 2K x 2.5K screen. The Display Environment Spatial Position (0072,0108) of the 1K x 1K screen is (0.0,0.4) (0.33,0.0), and the Display Environment Spatial Position (0072,0108) of the 2K x 2.5K screen is (0.33,1.0) (1.0,0.0). + +
+
+ + Type of layout of the image box. +All types except for TILED are single rectangles containing a single frame of image pixel data. The types are primarily distinguished by their interaction technique. +Defined Terms: +TILED: a scrollable array of rectangles, each containing a single frame of image pixel data. +STACK: a single rectangle containing a steppable single frame, intended for user-controlled stepping through the image set, usually via continuous device interaction (e.g., mouse scrolling) or by single stepping (mouse or button click). +CINE: a single rectangle, intended for video type play back where the user controls are play sequence, rate of play, and direction. +PROCESSED: intended for interactive 3D visualizations that have custom interfaces. +SINGLE: a single rectangle, intended for images and objects with no defined methods of interaction. +Note: This value may also be used for non-image objects, such as waveforms and SR documents. + + + Positive integer defining the horizontal Image Box tile dimension; the number of columns. +Required if the value of Image Box Layout Type (0072,0304) is TILED. + + + Positive integer defining the vertical Image Box tile dimension; the number of rows. +Required if the value of Image Box Layout Type (0072,0304) is TILED. + + + Enumerated Values: +VERTICAL: scroll images by row +HORIZONTAL: scroll images by column. +Required if the value of Image Box Layout Type (0072,0304) is TILED, and the value of Image Box Tile Horizontal Dimension (0072,0306) or Image Box Tile Vertical Dimension (0072,0308) is greater than 1. + + + Defines the type of small increment scrolling to be applied to this Image Box. +Required if the value of Image Box Layout Type (0072,0304) is TILED, and the value of Image Box Tile Horizontal Dimension (0072,0306) or Image Box Tile Vertical Dimension (0072,0308) is greater than 1. Scrolling is not specified if zero length. +Enumerated Values: +PAGE: In a TILED image box, replace all image slots with the next N x M images in the set, +ROW_COLUMN: in a TILED image box, move each row or column of images to the next row or column, depending on Image Box Scroll Direction (0072,0310) +IMAGE: In a TILED image box, move each image to the next slot, either horizontally or vertically, depending on Image Box Scroll Direction (0072,0310) +Note: If there are multiple image boxes of different Tile Dimensions in a Display Set, then only IMAGE scrolling applies, and the value of this attribute is ignored. + + + Defines the positive integer number of pages, rows, columns, or images per small increment scroll, based on the values of Image Box Small Scroll Type (0072,0312) and Image Box Scroll Direction (0072,0310). The value applies to both forward and backward scrolling. +Required if Image Box Small Scroll Type (0072,0312) is present with a value. + + + Defines the type of large increment scrolling to be applied to this Image Box. +Required if the value of Image Box Layout Type (0072,0304) is TILED, and the value of Image Box Tile Horizontal Dimension (0072,0306) or Image Box Tile Vertical Dimension (0072,0308) is greater than 1. +Enumerated Values: +PAGE: In a TILED image box, replace all image slots with the next N x M images in the set, +ROW_COLUMN: in a TILED image box, move each row or column of images to the next row or column, depending on Image Box Scroll Direction (0072,0310) +IMAGE: In a TILED image box, move each image to the next slot, either horizontally or vertically, depending on Image Box Scroll Direction (0072,0310) +Note: If there are multiple image boxes of different Tile Dimensions in a Display Set, then only IMAGE scrolling applies, and the value of the attribute is ignored. + + + Defines the positive integer number of pages, rows, columns, or images per large increment scroll, based on the values of Image Box Large Scroll Type (0072,0316) and Image Box Scroll Direction (0072,cc50). The value applies to both forward and backward scrolling. +Required if Image Box Large Scroll Type (0072,0316) is present with a value. + + + If this Image Box overlaps in spatial position with others, this attribute indicates the layer of this Image Box in relation to the others. The value shall be a positive integer in the range 1 to 100, where 1 = top and 100 = bottom. +If this attribute is not present, then the expected behavior is not defined. + + + Describes the preferred playback sequencing for the Image Box. Overrides any Preferred Playback Sequencing (0018,1244) value in the image objects being displayed. +Required if the value of Image Box Layout Type (0072,0304) is CINE. +Enumerated Values: +0 = Looping (1,2...n,1,2,...n,1,2,....n,...) +1 = Sweeping (1,2,...n,n-1,...2,1,2,...n,...) +2 = Stop (1,2…n) + + + Recommended rate at which the frames of a multi-frame image shall be displayed, in frames/second. Shall have a value greater than zero. Overrides any Recommended Display Frame Rate (0008,2144) value in the image objects being displayed. +Required if the value of Image Box Layout Type (0072,0304) is CINE and if Cine Relative to Real-Time (0072,0330) is not present. + + + A positive unitless floating point numeric factor equal to playback rate divided by acquisition rate. +Required if the value of Image Box Layout Type (0072,0304) is CINE and if Recommended Display Frame Rate (0008,2144) is not present. +Note: The capture rate may change within the image object, as specified in Frame Time (0018,1063) or Frame Time Vector (0018,1065). + + + Sequence that defines filter criteria to be applied to the image set identified by Image Set Number (0072,0032). Zero or more items shall be included in this sequence. See C.23.3.1.1. +
The items in the Filter Operations Sequence (0072,0400) determine which subset of the images in the identified Image Set are to be displayed in the associated Display Set image boxes. If there are multiple Items in the Filter Operations Sequence (0072,0400), the filter operations shall be applied in Item order, and the output of the preceding filter shall serve as the input to the succeeding filter (i.e., an AND operation). +When Filter-by Category (0072,0402) has a value of IMAGE_PLANE, Selector Attribute VR (0072,0050) shall have a value of “CSâ€, and abstract enumerated values shall be used for the value of the associated Selector CS Value (0072,0062) attribute, which may be computed from the values of Image Orientation (Patient) (0020,0037) or Patient Orientation (0020,0020). Enumerated Values: TRANSVERSE, CORONAL, SAGITTAL, OBLIQUE. +Note: Cross-sectional images do not normally contain a categorical description of the image plane, but rather only a patient-relative row and column direction cosines that are unit vectors. The category of image plane can be determined first by categorizing the row and column major directions (or detecting if the orientation is oblique according to a pre-specified threshold), and then using those categories to select a plan category. + The following pseudo-code can be used to determine the major axis (R or L, A or P, H or F) from a single direction cosine that is an (x,y,z) tuple (as defined in C.7.6.2.1.1): + + if (abs(x) > threshold) + axis = “RL†+ else if (abs(y) > threshold) + axis = “AP†+ else if (abs(z) > threshold) + axis = “HF†+ else + is OBLIQUE + + Having determined the major axis of the row and column, the category of plane can be obtained from a table lookup: + + + Alternatively, one can obtain a single vector that is the normal to the orientation (cross product of the row and column unit vectors), then find which of the x, y and z components has the maximum absolute value that is above threshold; if x then SAGITTAL, if y then CORONAL, if z then TRANSVERSE; if all of the components are below threshold then the orientation is OBLIQUE. + + Since it is also necessary to determine whether or not to flip or rotate the image into the preferred orientation (as specified by Display Set Patient orientation (0072,0700)) for the category of plane (e.g., sagittals are normally viewed with row direction posteriorly and column direction towards the feet), the categorical row and column direction to use can be obtained as above, additional accounting for the sign of the direction cosine, e.g.: + + if x < 0 then orientationX = “R†else orientationX = “L†+ if y < 0 then orientationY = “A†else orientationY = “P†+ if z < 0 then orientationZ = “F†else orientationZ = “H†+ if (abs(x) > threshold) + orientation = orientationX + … + +An application that is applying a Hanging Protocol Instance shall support any value for Selector Attribute (0072,0026). If the attribute identified by Selector Attribute is not present in an image of the referenced Image Set, then the image is included in the filter output. The attributes of the Hanging Protocol Selector Attribute Context Macro specify whether the Selector Attribute (0072,0026) is contained in a Sequence, Functional Group Sequence, or Private Group. +Notes: 1. The following attributes from image IODs are examples of some possible values for the Selector Attribute (0072,0026) of the Filter Operations Sequence (0072,0400). This is not a complete list: +
+
+ + Category of the filter operation. See C.23.3.1.1. +Defined terms: +IMAGE_PLANE +Required if Selector Attribute (0072,0026) is not present. +
The items in the Filter Operations Sequence (0072,0400) determine which subset of the images in the identified Image Set are to be displayed in the associated Display Set image boxes. If there are multiple Items in the Filter Operations Sequence (0072,0400), the filter operations shall be applied in Item order, and the output of the preceding filter shall serve as the input to the succeeding filter (i.e., an AND operation). +When Filter-by Category (0072,0402) has a value of IMAGE_PLANE, Selector Attribute VR (0072,0050) shall have a value of “CSâ€, and abstract enumerated values shall be used for the value of the associated Selector CS Value (0072,0062) attribute, which may be computed from the values of Image Orientation (Patient) (0020,0037) or Patient Orientation (0020,0020). Enumerated Values: TRANSVERSE, CORONAL, SAGITTAL, OBLIQUE. +Note: Cross-sectional images do not normally contain a categorical description of the image plane, but rather only a patient-relative row and column direction cosines that are unit vectors. The category of image plane can be determined first by categorizing the row and column major directions (or detecting if the orientation is oblique according to a pre-specified threshold), and then using those categories to select a plan category. + The following pseudo-code can be used to determine the major axis (R or L, A or P, H or F) from a single direction cosine that is an (x,y,z) tuple (as defined in C.7.6.2.1.1): + + if (abs(x) > threshold) + axis = “RL†+ else if (abs(y) > threshold) + axis = “AP†+ else if (abs(z) > threshold) + axis = “HF†+ else + is OBLIQUE + + Having determined the major axis of the row and column, the category of plane can be obtained from a table lookup: + + + Alternatively, one can obtain a single vector that is the normal to the orientation (cross product of the row and column unit vectors), then find which of the x, y and z components has the maximum absolute value that is above threshold; if x then SAGITTAL, if y then CORONAL, if z then TRANSVERSE; if all of the components are below threshold then the orientation is OBLIQUE. + + Since it is also necessary to determine whether or not to flip or rotate the image into the preferred orientation (as specified by Display Set Patient orientation (0072,0700)) for the category of plane (e.g., sagittals are normally viewed with row direction posteriorly and column direction towards the feet), the categorical row and column direction to use can be obtained as above, additional accounting for the sign of the direction cosine, e.g.: + + if x < 0 then orientationX = “R†else orientationX = “L†+ if y < 0 then orientationY = “A†else orientationY = “P†+ if z < 0 then orientationZ = “F†else orientationZ = “H†+ if (abs(x) > threshold) + orientation = orientationX + … + +An application that is applying a Hanging Protocol Instance shall support any value for Selector Attribute (0072,0026). If the attribute identified by Selector Attribute is not present in an image of the referenced Image Set, then the image is included in the filter output. The attributes of the Hanging Protocol Selector Attribute Context Macro specify whether the Selector Attribute (0072,0026) is contained in a Sequence, Functional Group Sequence, or Private Group. +Notes: 1. The following attributes from image IODs are examples of some possible values for the Selector Attribute (0072,0026) of the Filter Operations Sequence (0072,0400). This is not a complete list: +
+
+ + Operation to be applied based on the presence or absence of the attribute represented by Selector Attribute (0072,0026) in each image of the Image Set. +Required if Selector Attribute (0072,0026) is present and Filter-by Operator (0072,0406) is not present. +Enumerated Values: +PRESENT: Include the image if the attribute is present +NOT_PRESENT: Include the image if the attribute is not present + + + Data Element Tag of an Attribute from an Image IOD to use as a filter. See C.23.3.1.1 for potential attributes. +Required if Filter-by Category (0072,0402) is not present. +
The items in the Filter Operations Sequence (0072,0400) determine which subset of the images in the identified Image Set are to be displayed in the associated Display Set image boxes. If there are multiple Items in the Filter Operations Sequence (0072,0400), the filter operations shall be applied in Item order, and the output of the preceding filter shall serve as the input to the succeeding filter (i.e., an AND operation). +When Filter-by Category (0072,0402) has a value of IMAGE_PLANE, Selector Attribute VR (0072,0050) shall have a value of “CSâ€, and abstract enumerated values shall be used for the value of the associated Selector CS Value (0072,0062) attribute, which may be computed from the values of Image Orientation (Patient) (0020,0037) or Patient Orientation (0020,0020). Enumerated Values: TRANSVERSE, CORONAL, SAGITTAL, OBLIQUE. +Note: Cross-sectional images do not normally contain a categorical description of the image plane, but rather only a patient-relative row and column direction cosines that are unit vectors. The category of image plane can be determined first by categorizing the row and column major directions (or detecting if the orientation is oblique according to a pre-specified threshold), and then using those categories to select a plan category. + The following pseudo-code can be used to determine the major axis (R or L, A or P, H or F) from a single direction cosine that is an (x,y,z) tuple (as defined in C.7.6.2.1.1): + + if (abs(x) > threshold) + axis = “RL†+ else if (abs(y) > threshold) + axis = “AP†+ else if (abs(z) > threshold) + axis = “HF†+ else + is OBLIQUE + + Having determined the major axis of the row and column, the category of plane can be obtained from a table lookup: + + + Alternatively, one can obtain a single vector that is the normal to the orientation (cross product of the row and column unit vectors), then find which of the x, y and z components has the maximum absolute value that is above threshold; if x then SAGITTAL, if y then CORONAL, if z then TRANSVERSE; if all of the components are below threshold then the orientation is OBLIQUE. + + Since it is also necessary to determine whether or not to flip or rotate the image into the preferred orientation (as specified by Display Set Patient orientation (0072,0700)) for the category of plane (e.g., sagittals are normally viewed with row direction posteriorly and column direction towards the feet), the categorical row and column direction to use can be obtained as above, additional accounting for the sign of the direction cosine, e.g.: + + if x < 0 then orientationX = “R†else orientationX = “L†+ if y < 0 then orientationY = “A†else orientationY = “P†+ if z < 0 then orientationZ = “F†else orientationZ = “H†+ if (abs(x) > threshold) + orientation = orientationX + … + +An application that is applying a Hanging Protocol Instance shall support any value for Selector Attribute (0072,0026). If the attribute identified by Selector Attribute is not present in an image of the referenced Image Set, then the image is included in the filter output. The attributes of the Hanging Protocol Selector Attribute Context Macro specify whether the Selector Attribute (0072,0026) is contained in a Sequence, Functional Group Sequence, or Private Group. +Notes: 1. The following attributes from image IODs are examples of some possible values for the Selector Attribute (0072,0026) of the Filter Operations Sequence (0072,0400). This is not a complete list: +
+
+ + The Value Representation of the Selector Attribute (0072,0026). +Required if Selector Attribute (0072,0026) or Filter-by Category (0072,0402), and Filter-by Operator (0072,0406) are present. + + + + + Positive integer identifying which value of the attribute identified by Selector Attribute (0072,0026) is to be used for filtering. The value 1 identifies the first value. The value zero identifies any value. +Required if Selector Attribute (0072,0026) and Filter-by Operator (0072,0406) are present. + + + Operation to be applied between the value(s) in the Hanging Protocol Selector Attribute Value Macro ("selector"), and the value(s) of the attribute identified by Selector Attribute (0072,0026) in each image of the Image Set. See C.23.3.1.1. +Required if Filter-by Category (0072,0402) is present, or if Selector Attribute (0072,0026) is present and Filter-by Attribute Presence (0072,0404) is not present. +Enumerated Values: +RANGE_INCL: the values lie within the specified range, or are equal to the endpoints; applies only to numeric, date or time Selector Attribute (0072,0026); two values shall be present in the selector, the first of which is less than or equal to the second +RANGE_EXCL: the values lie outside the specified range, and are not equal to the endpoints; applies only to numeric Selector Attribute (0072,0026); two values shall be present in the selector, the first of which is less than or equal to the second +GREATER_OR_EQUAL: applies only to numeric Selector Attribute (0072,0026) +LESS_OR_EQUAL: applies only to numeric Selector Attribute (0072,0026) +GREATER_THAN: applies only to numeric Selector Attribute (0072,0026) +LESS_THAN: applies only to numeric Selector Attribute (0072,0026) +MEMBER_OF: one of the values in the image is present in the values of the selector; if one value is present in each, this is an "equal to" operator +NOT_MEMBER_OF: none of the values in the image is present in the values of the selector; if one value is present in each, this is a "not equal to" operator +
The items in the Filter Operations Sequence (0072,0400) determine which subset of the images in the identified Image Set are to be displayed in the associated Display Set image boxes. If there are multiple Items in the Filter Operations Sequence (0072,0400), the filter operations shall be applied in Item order, and the output of the preceding filter shall serve as the input to the succeeding filter (i.e., an AND operation). +When Filter-by Category (0072,0402) has a value of IMAGE_PLANE, Selector Attribute VR (0072,0050) shall have a value of “CSâ€, and abstract enumerated values shall be used for the value of the associated Selector CS Value (0072,0062) attribute, which may be computed from the values of Image Orientation (Patient) (0020,0037) or Patient Orientation (0020,0020). Enumerated Values: TRANSVERSE, CORONAL, SAGITTAL, OBLIQUE. +Note: Cross-sectional images do not normally contain a categorical description of the image plane, but rather only a patient-relative row and column direction cosines that are unit vectors. The category of image plane can be determined first by categorizing the row and column major directions (or detecting if the orientation is oblique according to a pre-specified threshold), and then using those categories to select a plan category. + The following pseudo-code can be used to determine the major axis (R or L, A or P, H or F) from a single direction cosine that is an (x,y,z) tuple (as defined in C.7.6.2.1.1): + + if (abs(x) > threshold) + axis = “RL†+ else if (abs(y) > threshold) + axis = “AP†+ else if (abs(z) > threshold) + axis = “HF†+ else + is OBLIQUE + + Having determined the major axis of the row and column, the category of plane can be obtained from a table lookup: + + + Alternatively, one can obtain a single vector that is the normal to the orientation (cross product of the row and column unit vectors), then find which of the x, y and z components has the maximum absolute value that is above threshold; if x then SAGITTAL, if y then CORONAL, if z then TRANSVERSE; if all of the components are below threshold then the orientation is OBLIQUE. + + Since it is also necessary to determine whether or not to flip or rotate the image into the preferred orientation (as specified by Display Set Patient orientation (0072,0700)) for the category of plane (e.g., sagittals are normally viewed with row direction posteriorly and column direction towards the feet), the categorical row and column direction to use can be obtained as above, additional accounting for the sign of the direction cosine, e.g.: + + if x < 0 then orientationX = “R†else orientationX = “L†+ if y < 0 then orientationY = “A†else orientationY = “P†+ if z < 0 then orientationZ = “F†else orientationZ = “H†+ if (abs(x) > threshold) + orientation = orientationX + … + +An application that is applying a Hanging Protocol Instance shall support any value for Selector Attribute (0072,0026). If the attribute identified by Selector Attribute is not present in an image of the referenced Image Set, then the image is included in the filter output. The attributes of the Hanging Protocol Selector Attribute Context Macro specify whether the Selector Attribute (0072,0026) is contained in a Sequence, Functional Group Sequence, or Private Group. +Notes: 1. The following attributes from image IODs are examples of some possible values for the Selector Attribute (0072,0026) of the Filter Operations Sequence (0072,0400). This is not a complete list: +
+
+ + Sequence that defines sorting criteria to be applied to the result of filter and reformat operations, to define the order in which to present the images in the Image Boxes. Zero or more items shall be included in this sequence. See C.23.3.1.2. +
The Items in the Sorting Operations Sequence (0072,0600) define the order in which the images resulting from the filter and reformat operations on the Image Set are to be displayed in the associated Image Boxes of the Display Set. The sorting criteria may include the value of a numeric, date, or time Attribute that is expected to be present in each of the image objects in the filtered Image Set, and/or an abstract sorting category. A sorting direction shall be associated with each sorting criterion. If a textual Attribute is used for sorting, then the INCREASING sorting direction indicates alpabetical order, and DECREASING indicates reverse alphabetical order. +If a code sequence Attribute is used for sorting, then the Code Meaning (0008,0104) shall be sorted alphabetically. If a string numeric Attribute is used for sorting (VR of IS or DS), then sorting shall be on the numeric value, and padding shall be ignored. When sorting by date or time Attribute, then sorting shall be on the temporal value, not the alphabetic string. +If there are multiple Items in the Sorting Operations Sequence (0072,0600), then the sorting operations shall be applied in Item order. The least rapidly varying attribute for the sorting operation shall be the first Item in the sequence. +Note: For example, a Sorting Operations Sequence (0072,0600) with two Items: + Item #1: (0018,5101) View Position, INCREASING + Item #2: (0008,0020) Study Date, INCREASING + results in the following order, based on these attribute values in the image objects: + +When the Sort-by Category (0072,0602) is used with a value of ALONG_AXIS, such as for CT, MR or other cross-sectional image sets, the sorting operation is computed from the values Image Position (Patient) (0020,0032) and Image Orientation (Patient) (0020,0037) in the image objects. +For the image set to be displayed, a “dominant axis†of the set shall be determined. The dominant axis is the normal to the Image Orientation (Patient) (0020,0037) attribute (assuming all selected images are parallel), computed as the dot product in a right-handed coordinate system (see C.7.6.2.1.1). The INCREASING direction for ALONG_AXIS of the image set shall be in the positive direction along the dominant axis. The DECREASING direction shall be in the negative direction along that axis. +When the Sort-by Category (0072,0602) is used with a value of BY_ACQ_TIME, the sorting operation is computed from appropriate values in the image objects (e.g., Frame Acquisition DateTime, Acquisition Time, Content Time, Acquisition DateTime), since the specific attribute used may vary from one Image Instance or SOP Class to another, yet the Hanging Protocol Instance may be generally applicable. +An application that is applying a Hanging Protocol Instance shall support any value for Selector Attribute (0072,0026), provided that it is present in the referenced Image Set. The attributes of the Hanging Protocol Selector Attribute Context Macro specify whether the Selector Attribute (0072,0026) is contained in a Sequence, Functional Group Sequence or Private Group. +Notes: 1. The following attributes from image IODs are examples of some possible values for the Selector Attribute (0072,0026) of the Sorting Operations Sequence (0072,0600). This is not a complete list: +
+
+ + Data Element Tag of an Attribute from an Image IOD to be used for sorting. See C.23.3.1.2 for potential attributes. +Required if Sort-by Category (0072,0602) is not present. +
The Items in the Sorting Operations Sequence (0072,0600) define the order in which the images resulting from the filter and reformat operations on the Image Set are to be displayed in the associated Image Boxes of the Display Set. The sorting criteria may include the value of a numeric, date, or time Attribute that is expected to be present in each of the image objects in the filtered Image Set, and/or an abstract sorting category. A sorting direction shall be associated with each sorting criterion. If a textual Attribute is used for sorting, then the INCREASING sorting direction indicates alpabetical order, and DECREASING indicates reverse alphabetical order. +If a code sequence Attribute is used for sorting, then the Code Meaning (0008,0104) shall be sorted alphabetically. If a string numeric Attribute is used for sorting (VR of IS or DS), then sorting shall be on the numeric value, and padding shall be ignored. When sorting by date or time Attribute, then sorting shall be on the temporal value, not the alphabetic string. +If there are multiple Items in the Sorting Operations Sequence (0072,0600), then the sorting operations shall be applied in Item order. The least rapidly varying attribute for the sorting operation shall be the first Item in the sequence. +Note: For example, a Sorting Operations Sequence (0072,0600) with two Items: + Item #1: (0018,5101) View Position, INCREASING + Item #2: (0008,0020) Study Date, INCREASING + results in the following order, based on these attribute values in the image objects: + +When the Sort-by Category (0072,0602) is used with a value of ALONG_AXIS, such as for CT, MR or other cross-sectional image sets, the sorting operation is computed from the values Image Position (Patient) (0020,0032) and Image Orientation (Patient) (0020,0037) in the image objects. +For the image set to be displayed, a “dominant axis†of the set shall be determined. The dominant axis is the normal to the Image Orientation (Patient) (0020,0037) attribute (assuming all selected images are parallel), computed as the dot product in a right-handed coordinate system (see C.7.6.2.1.1). The INCREASING direction for ALONG_AXIS of the image set shall be in the positive direction along the dominant axis. The DECREASING direction shall be in the negative direction along that axis. +When the Sort-by Category (0072,0602) is used with a value of BY_ACQ_TIME, the sorting operation is computed from appropriate values in the image objects (e.g., Frame Acquisition DateTime, Acquisition Time, Content Time, Acquisition DateTime), since the specific attribute used may vary from one Image Instance or SOP Class to another, yet the Hanging Protocol Instance may be generally applicable. +An application that is applying a Hanging Protocol Instance shall support any value for Selector Attribute (0072,0026), provided that it is present in the referenced Image Set. The attributes of the Hanging Protocol Selector Attribute Context Macro specify whether the Selector Attribute (0072,0026) is contained in a Sequence, Functional Group Sequence or Private Group. +Notes: 1. The following attributes from image IODs are examples of some possible values for the Selector Attribute (0072,0026) of the Sorting Operations Sequence (0072,0600). This is not a complete list: +
+
+ + + Positive integer identifying which value of the attribute identified by Selector Attribute (0072,0026) is to be used for sorting. The value of 1 identifies the first value. Shall not be zero. +Required if Selector Attribute (0072,0026) is present. + + + Category of the sorting operation. See C.23.3.1.2. +Defined terms: +ALONG_AXIS: for CT, MR, other cross-sectional image sets +BY_ACQ_TIME +Required if Selector Attribute (0072,0026) is not present. +
The Items in the Sorting Operations Sequence (0072,0600) define the order in which the images resulting from the filter and reformat operations on the Image Set are to be displayed in the associated Image Boxes of the Display Set. The sorting criteria may include the value of a numeric, date, or time Attribute that is expected to be present in each of the image objects in the filtered Image Set, and/or an abstract sorting category. A sorting direction shall be associated with each sorting criterion. If a textual Attribute is used for sorting, then the INCREASING sorting direction indicates alpabetical order, and DECREASING indicates reverse alphabetical order. +If a code sequence Attribute is used for sorting, then the Code Meaning (0008,0104) shall be sorted alphabetically. If a string numeric Attribute is used for sorting (VR of IS or DS), then sorting shall be on the numeric value, and padding shall be ignored. When sorting by date or time Attribute, then sorting shall be on the temporal value, not the alphabetic string. +If there are multiple Items in the Sorting Operations Sequence (0072,0600), then the sorting operations shall be applied in Item order. The least rapidly varying attribute for the sorting operation shall be the first Item in the sequence. +Note: For example, a Sorting Operations Sequence (0072,0600) with two Items: + Item #1: (0018,5101) View Position, INCREASING + Item #2: (0008,0020) Study Date, INCREASING + results in the following order, based on these attribute values in the image objects: + +When the Sort-by Category (0072,0602) is used with a value of ALONG_AXIS, such as for CT, MR or other cross-sectional image sets, the sorting operation is computed from the values Image Position (Patient) (0020,0032) and Image Orientation (Patient) (0020,0037) in the image objects. +For the image set to be displayed, a “dominant axis†of the set shall be determined. The dominant axis is the normal to the Image Orientation (Patient) (0020,0037) attribute (assuming all selected images are parallel), computed as the dot product in a right-handed coordinate system (see C.7.6.2.1.1). The INCREASING direction for ALONG_AXIS of the image set shall be in the positive direction along the dominant axis. The DECREASING direction shall be in the negative direction along that axis. +When the Sort-by Category (0072,0602) is used with a value of BY_ACQ_TIME, the sorting operation is computed from appropriate values in the image objects (e.g., Frame Acquisition DateTime, Acquisition Time, Content Time, Acquisition DateTime), since the specific attribute used may vary from one Image Instance or SOP Class to another, yet the Hanging Protocol Instance may be generally applicable. +An application that is applying a Hanging Protocol Instance shall support any value for Selector Attribute (0072,0026), provided that it is present in the referenced Image Set. The attributes of the Hanging Protocol Selector Attribute Context Macro specify whether the Selector Attribute (0072,0026) is contained in a Sequence, Functional Group Sequence or Private Group. +Notes: 1. The following attributes from image IODs are examples of some possible values for the Selector Attribute (0072,0026) of the Sorting Operations Sequence (0072,0600). This is not a complete list: +
+
+ + Sorting direction to be applied to the value(s) in the image set of the attribute identified by Selector Attribute (0072,0026) or Sort-by Category (0072,0602). +Enumerated Values: INCREASING, DECREASING + + + Type of blending of superimposed and underlying images from the image set, performed before reformatting. See C.23.3.1.3. +Defined Terms: +COLOR - apply a pseudo-color to the superimposed image while blending +
A Blending Operation Type (0072,0500) of COLOR implies that the filtered selected image set contains two sets of images appropriate for blending, such as CT and PET images defined in the same frame of reference or associated by a spatial registration object. The decision as to which subset are the underlying images and which subset are the superimposed images is left to the discretion of the display application. There is no mechanism to explicitly specify the two subsets. +The relative opacity and color-related aspects of blending are not specified by the Hanging Protocol, and are left to the discretion of the application. +
+
+ + Reformatting operation to be applied to the Image Set. +Defined terms: MPR, 3D_RENDERING, SLAB + + + The desired thickness of the reformatted images in millimeters. +Required if value of Reformatting Operation Type (0072,0510) is SLAB or MPR. May be present otherwise. + + + The desired spacing of the reformatted images in millimeters. The spacing is measured from the center-to-center of each reconstructed image. +Required if value of Reformatting Operation Type (0072,0510) is SLAB or MPR. May be present otherwise. + + + Initial view of the reformatted images. +Required if the value of Reformatting Operation Type (0072,0510) is MPR or 3D_RENDERING. May be present otherwise. +Defined Terms: +SAGITTAL, TRANSVERSE, CORONAL, OBLIQUE + + + Describes the intended 3D rendering type. One or more values shall be present. The first value shall not be zero length. Required if the value of Reformatting Operation Type (0072,0510) is 3D_RENDERING: +Defined Terms for value 1: +MIP, SURFACE, VOLUME +Additional values may be used to identify implementation specific sub-types. + + + Patient direction of the rows and columns of the images, as intended for display. See C.23.3.1.4. +
The attributes that indicate the presentation intent for each Display Set of a Hanging Protocol Instance are: Display Set Patient Orientation (0072,0700), VOI Type (0072,0702), Pseudo-color Type (0072,0704), Show Grayscale Inverted (0072,0706), Show Image True Size Flag (0072,0710), Show Graphic Annotation Flag (0072,0712), Show Patient Demographics Flag (0072,0714), and Show Acquisition Techniques Flag (0072,0716). +
+
+ + Indicates direction in which to horizontally justify the image within a viewport that is not the same shape (aspect ratio) as the image. +Enumerated Values: +LEFT +CENTER +RIGHT +Note: Typically used in mammography display applications in which images from the patient's left and right are displayed "back to back", rather than centered. + + + Indicates direction in which to vertically justify the image within a viewport that is not the same shape (aspect ratio) as the image. +Enumerated Values: +TOP +CENTER +BOTTOM + + + Expected value of interest transformation for display (e.g., Window Center and Window Width or VOI LUT). +Defined Terms: +LUNG +MEDIASTINUM +ABDO_PELVIS +LIVER +SOFT_TISSUE +BONE +BRAIN +POST_FOSSA + + + A category of pseudo-color palette choice to be applied after application of the VOI LUT. If this attribute is not present, a pseudo-color palette shall not be applied. +Defined Terms: +BLACK_BODY +HOT_IRON +DEFAULT + + + Whether or not to invert the rendered luminance of the displayed values. See C.23.3.1.4. +Enumerated values: +YES = The maximum output value after the display pipeline has been applied shall be displayed with the minimum available luminance. +NO = The maximum output value after the display pipeline has been applied shall be displayed with the maximum available luminance. +Notes: 1. The YES and NO values of this Attribute correspond to the Presentation LUT Shape (2050,0020) values of INVERSE and IDENTITY, as described in C.11.6.1.2. +2. Only applicable to display of grayscale images. +
The attributes that indicate the presentation intent for each Display Set of a Hanging Protocol Instance are: Display Set Patient Orientation (0072,0700), VOI Type (0072,0702), Pseudo-color Type (0072,0704), Show Grayscale Inverted (0072,0706), Show Image True Size Flag (0072,0710), Show Graphic Annotation Flag (0072,0712), Show Patient Demographics Flag (0072,0714), and Show Acquisition Techniques Flag (0072,0716). +
+
+ + Indicates whether or not to display images with the physical size of the rendered image pixel the same on the screen as specified in the image attributes, unless overridden by a Presentation State instance. +Enumerated values: +YES = Display images at True Size. +NO = The rendered size is not specified. + + + Indicates whether or not to display items from the Graphic Annotation Sequence (0070,0001) in an applied Presentation State, and the attributes of the Overlay Plane module in the image objects or applied Presentation State. +Enumerated Values: +YES +NO + + + Indicates whether or not to display patient and study identification information. +Enumerated Values: +YES +NO + + + Indicates whether or not to display image acquisition technique information. +Enumerated Values: +YES +NO + + + Description of the intent of the Display Set Presentation Group (0072,0204). If present, shall have the same value in all sequence Items assigned the same value for Display Set Presentation Group (0072,0204). + + + If one or more Image Sets identified by Image Set Number (0072,0032) in the Display Sets Sequence (0072,0200) Items is not available, indicate whether or not to maintain the expected layout in the absence of complete Image Sets. Enumerated Values: +MAINTAIN_LAYOUT: If one or more Image Sets is not available, maintain the layout with empty Image Boxes. +ADAPT_LAYOUT: If one or more Image Sets is not available, rearrange the layout at the discretion of the application. +If this attribute is zero length, then the expected behavior is not defined. + + + Each sequence item of this attribute identifies a group of Display Sets to which synchronized scrolling is to be applied. Zero or more sequence items may be present. +The dimensions along which the synchronization occurs shall be those specified in the Sorting Operations Sequence (0072,0600). + + + Multi-valued list of two or more Display Set Number (0072,0202) values. Indicates that the images within the specified Display Sets are scrolled in parallel, to maintain the established synchronization. + + + Describes a geometric relationship between Display Sets for the purpose of static or interactive localization or navigation. One or more sequence items may be present. + + + Display Set Number (0072,0202) of the Display Set where the geometric relationship to the Reference Display Sets (0072,0218) is graphically depicted. +Required if there is a one-way interaction such that the location of the Reference Display Sets is indicated on or controlled by the Navigation Display Set. +Note: For example, the graphical representation may indicate either the number of slices displayed or contained in the Reference Display Set(s). + + + One or more Display Set Number (0072,0202) values. +If Navigation Display Set is present, shall list those Display Sets that are controlled by or indicated on the Navigation Display Set. +If Navigation Display Set is absent, shall indicate that all of the Reference Display Sets cross-reference each other. + +
+ + + The modality appropriate for the encapsulated document. +This Type definition shall override the definition in the SC Equipment Module. +See section C.7.3.1.1.1 for Defined Terms. +Note: SR may be an appropriate value for an Encapsulated CDA document with a structured XML Body. + + + Unique identifier of the Series. + + + + A number that identifies the Series. + + + Uniquely identifies the Performed Procedure Step SOP Instance for which the Series is created. Only a single Item shall be permitted in this sequence. +Note: The Performed Procedure Step referred to by this Attribute is the Step during which this Document is generated. + + + + User provided description of the Series + + + Sequence that contains attributes from the Imaging Service Request. +The sequence may have one or more Items. + + + + + + + A number that identifies this SOP Instance. The value shall be unique within a series. + + + The date the document content creation was started. + + + The time the document content creation was started. + + + The date and time that the original generation of the data in the document started. + + + Indicates whether or not the encapsulated document contains sufficient burned in annotation to identify the patient and date the data was acquired. +Enumerated Values: +YES +NO +Identification of patient and date as text in an encapsulated document (e.g., in an XML attribute or element) is equivalent to "burned in annotation". A de-identified document may use the value NO. + + + A sequence that identifies the set of Instances that were used to derive the encapsulated document. One or more Items may be included in this Sequence. +Required if derived from one or more DICOM Instances. May be present otherwise. + + + + The title of the document. +Note: In the case of a PDF encapsulated document, this may be the value of the "Title" entry in the "Document Information Directory" as encoded in the PDF data. + + + A coded representation of the document title. Zero or one item may be present. + + + + Indicates whether the Encapsulated Document is Verified. Enumerated Values: +UNVERIFIED = Not attested by a legally accountable person. +VERIFIED = Attested to (signed) by a Verifying Observer or Legal Authenticator named in the document, who is accountable for its content. + + + Instance Identifier of the encapsulated HL7 Structured Document, encoded as a UID (OID or UUID), concatenated with a caret ("^") and Extension value (if Extension is present in Instance Identifier). +Required if encapsulated document is a CDA document. + + + The type of the encapsulated document stream described using the MIME Media Type (see RFC 2046). + + + MIME Types of subcomponents of the encapsulated document. +Required if the encapsulated document incorporates subcomponents with MIME types different than the primary MIME Type of the encapsulated document. +Note: An Encapsulated CDA that includes an embedded JPEG image and an embedded PDF would list "image/jpeg\application/pdf". + + + Encapsulated Document stream, containing a document encoded according to the MIME Type. + + + + + Modality type. +Enumerated Value: +RWV + + + + + The date the content creation started. + + + The time the content creation started. + + + + A sequence of one or more real world value mapping items. Each item defines a single mapping and a list of images to which the mapping applies. + + + + A sequence listing the images to which the mapping applies. One or more items shall be present. + + + + + + Identifier of the contrast agent, drug, or device being characterized, typically from a package bar code, RFID, or other materials management ID. This ID might not be globally unique and might conflict with other IDs used within the scope of the institution. + + + Manufacturer of product. + + + Coded type of product. One Item shall be included in the Sequence. + + + + Trade or generic name of product. +Note: May be multi-valued. + + + Further description in free form text describing the drug or device. +Note: This attribute is limited by the LT Value Representation to 10240 characters. Larger text descriptions, or graphical descriptions, may be referenced in the Pertinent Documents Sequence (0038,0100). + + + Identifier of the manufacturing batch of which this product is part. + + + The date and time after which the manufacturer no longer ensures the safety, quality, and/or proper functioning of the material. + + + Parameters of the product. Zero or more Items may be included in the Sequence. + + + + Reference to a Product Label document for the product. Zero or more Items may be included in this sequence. + + + Unique identifier for the class of an HL7 Structured Product Label document. + + + Unique identifier for the HL7 Structured Product Label Document as used in DICOM instance references (see C.12.1.1.6) + + + Instance Identifier of the referenced HL7 Structured Document, encoded as a UID (OID or UUID), concatenated with a caret ("^") and Extension value (if Extension is present in Instance Identifier). + + + Retrieval access path to Product Label Document. Includes fully specified scheme, authority, path, and query in accordance with RFC 2396 + + + + + Status of request for substance administration. Enumerated Values: +APPROVED - Use of the substance for the patient is approved, with related notes (e.g., appropriate dose for age/weight) in Approval Status Further Description (0044,0003) +WARNING - The substance may be used for the patient subject to warnings described in Approval Status Further Description (0044,0003) +CONTRA_INDICATED - The substance should not be used for the patient for the reasons described in Approval Status Further Description (0044,0003) + + + Description of warning or contra-indication, or notes on approval. + + + Timestamp for the Substance Administration Approval response + + + + + Route of administration for drug or contrast. One Item may be present in this Sequence. + + + + + + Patient's full name + + + Primary identification number or code for the patient. + + + Identifier of the Assigning Authority (system, organization, agency, or department) that issued the Patient ID. + + + Identification number of the visit as assigned by the healthcare provider + + + Name of healthcare provider that issued the Admission ID + + + Identifier of the contrast agent, drug, or device administered, typically from a package bar code, RFID, or other materials management ID. This ID might not be globally unique and might conflict with other IDs used within the scope of the institution. + + + Trade or generic name of product. +Note: May be multi-valued. + + + Text description of the contrast agent, drug, or device administered. + + + Date and Time of Substance Administration + + + Comments provided by the operator responsible for the substance administration. + + + Identifier for a device that controls substance administration, e.g., injector, infusion pump, etc. + + + Route of administration for drug or contrast. One Item may be present in this Sequence. + + + + Parameters of the substance as administered to the patient, e.g., volume, quantity. Zero or more Items may be included in the Sequence. + + + + Person administering the substance to the patient, or legally responsible for the administration, and authorized to add an entry to the Medication Administration Record. One or more Items may be present in this Sequence. + + + Coded identifier of the person administering the contrast agent, drug, or device. +One Item may be present in this Sequence. + + + + + + + + + + User or implementation specific Identifier (up to 16 characters). For definition, see PS 3.10. The File-set ID is intended to be a short human readable label to easily (but not necessarily uniquely) identify a specific File-set to facilitate operator manipulation of the physical media on which the File-set is stored. Assignment of Value and semantics are environment specific. + + + ID of a File (in the same File-set) used for user comments related to the File-set (e.g. a readme file). The Specific Character set used may be specified in the Specific Character Set of the File-set Descriptor File (0004,1142). +Note: This File is not DICOM formatted (no Preamble, nor DICM Prefix and Meta Information). + + + Character set used in the File-set Descriptor File with a File ID as specified in File-set Descriptor File ID (0004,1141). Required to specify the expanded or replacement character set. If absent, only the Basic Graphic set is used. See C.12.1.1.2 for Defined Terms. +
Specific Character Set (0008,0005) identifies the Character Set that expands or replaces the Basic Graphic Set (ISO 646) for values of Data Elements that have Value Representation of SH, LO, ST, PN, LT or UT. See PS 3.5. +If the Attribute Specific Character Set (0008,0005) is not present or has only a single value, Code Extension techniques are not used. Defined terms for the Attribute Specific Character Set (0008,0005), when single valued, are derived from the International Registration Number as per ISO 2375 (e.g., ISO_IR 100 for Latin alphabet No. 1). See Table C.12-2. +Table C.12-2 + DEFINED TERMS FOR SINGLE-BYTE CHARACTER SETS WITHOUT CODE EXTENSIONS + +Note: To use the single-byte code table of JIS X0201, the value of attribute Specific Character Set (0008,0005), value 1 should be ISO_IR 13. This means that ISO-IR 13 is designated as the G1 code element which is invoked in the GR area. It should be understood that, in addition, ISO-IR 14 is designated as the G0 code element and this is invoked in the GL area. + +If the attribute Specific Character Set (0008,0005) has more than one value, Code Extension techniques are used and Escape Sequences may be encountered in all character sets. Requirements for the use of Code Extension techniques are specified in PS 3.5. In order to indicate the presence of Code Extension, the Defined Terms for the repertoires have the prefix “ISO 2022â€, e.g., ISO 2022 IR 100 for the Latin Alphabet No. 1. See Table 12-3 and Table 12-4. Table 12-3 describes single-byte character sets for value 1 to value n of the attribute Specific Character Set (0008,0005), and Table 12-4 describes multi-byte character sets for value 2 to value n of the attribute Specific Character Set (0008,0005). +Note: A prefix other than “ISO 2022†may be needed in the future if other Code Extension techniques are adopted. +Table C.12-3 +DEFINED TERMS FOR SINGLE-BYTE CHARACTER SETS WITH CODE EXTENSIONS + +Note: If the attribute Specific Character Set (0008,0005) has more than one value and value 1 is empty, it is assumed that value 1 is ISO 2022 IR 6. + +Table C.12-4 +DEFINED TERMS FOR MULTI-BYTE CHARACTER SETS WITH CODE EXTENSIONS + +There are multi-byte character sets that prohibit the use of Code Extension Techniques. The Unicode character set used in ISO 10646, when encoded in UTF-8, and the GB18030 character set, encoded per the rules of GB18030, both prohibit the use of Code Extension Techniques. These character sets may only be specified as value 1 in the Specific Character Set (0008,0005) attribute and there shall only be one value. The minimal length UTF-8 encoding shall always be used for ISO 10646. +Notes: 1. The ISO standards for 10646 now prohibit the use of anything but the minimum length encoding for UTF-8. UTF-8 permits multiple different encodings, but when used to encode Unicode characters in accordance with ISO 10646-1 and 10646-2 (with extensions) only the minimal encodings are legal. + 2. The representation for the characters in the DICOM Default Character Repertoire is the same single byte value for the Default Character Repertoire, ISO 10646 in UTF-8, and GB18030. It is also the 7-bit US-ASCII encoding. +Table C.12-5 +DEFINED TERMS FOR MULTI-BYTE CHARACTER SETS WITHOUT CODE EXTENSIONS + +
+
+
+ + + Offset of the first byte (of the Item Data Element) of the first Directory Record of the Root Directory Entity. This Offset is a number of bytes starting with the first byte of the File Meta Information. When the Root Directory Entity contains no Directory Record, this offset shall be set to 00000000H. +Note: This offset includes the File Preamble and the DICM Prefix. + + + Offset of the first byte (of the Item Data Element) of the last Directory Record of the Root Directory Entity. This Offset is a number of bytes starting with the first byte of the File Meta Information. When the Root Directory Entity contains no Directory Record, this offset shall be set to 00000000H. +Note: This offset includes the File Preamble and the DICM Prefix. + + + When set, this Flag indicates that an inconsistency within the Directory or between the Directory and the Files of the File-set may exist. Potential recovery actions are implementation specific and are beyond the scope of this Standard. Enumerated Values: +0000H: no known inconsistencies +FFFFH: the FSR or FSU shall assume that inconsistencies are present. +This flag shall be set by implementations before a File-set update which, if interrupted, may result in an inconsistent File-set. +Note: There may be error conditions where an inconsistency is present but this flag is not set. There may also be conditions where no inconsistencies are present but the flag is set. + + + Sequence of zero or more Items where each Item contains a Directory Record by including the Directory Elements from (0004,1400) to (0004,1511) and Record selection Keys as defined below (marked with a >). +A zero length Value indicates that no Directory Records are contained in the Root Directory Entity. + + + Offset of the first byte (of the Item Data Element) of the next Directory Record of the same Directory Entity. This Offset is an unsigned integer representing a number of bytes starting with the first byte of the File Meta-information. A zero offset shall be used to mean that there is no other Directory Record in this Directory Entity. +This Offset may be used to keep an inactive Record (0004,1410) chained with the next Directory Record of the same Directory Entity. +Note: This offset includes the File Preamble and the DICM Prefix. + + + This flag facilitates the deletion of referenced files. +Enumerated Values: +FFFFH = record is in use. +0000H = record is inactive. All attributes of an inactive Directory Record except (0004,1400) and (0004,1410) shall be ignored. +Other Values are reserved and shall not be set by File-set Creators, but if present shall be interpreted as FFFFH by File-set Readers or Updaters. +If a Directory Record is changed from in use to inactive, the FSU shall ensure that all Directory Records of referenced lower-level Directory Entities are changed to inactive. + + + Offset of the first byte (of the Item Data Element) of the first Directory Record of the Referenced Lower Level Directory Entity. This Offset is a number of bytes starting with the first byte of the File Meta Information. +When no lower-level Directory Entity (containing at least one Directory Record) is referenced, this Attribute shall have a Value of 00000000H. +Note: This offset includes the File Preamble and the DICM Prefix. + + + Defines a specialized type of Directory Record by reference to its position in the Media Storage Directory Information Model (see Section F.4). +Enumerated Values (see Section F.5): +PATIENT STUDY SERIES +IMAGE +RT DOSE RT STRUCTURE SET +RT PLAN RT TREAT RECORD +PRESENTATION WAVEFORM +SR DOCUMENT KEY OBJECT DOC +SPECTROSCOPY RAW DATA +REGISTRATION FIDUCIAL +HANGING PROTOCOL ENCAP DOC +HL7 STRUC DOC VALUE MAP +STEREOMETRIC + +PRIVATE = Privately defined record hierarchy position. Type shall be defined by Private Record UID (0004,1432). +Notes: 1. Enumerated Values PRINT QUEUE, FILM SESSION, FILM BOX, and IMAGE BOX were previously defined in DICOM for this Attribute. They are now retired. See PS3.3-1998. +2. Enumerated Values OVERLAY, MODALITY LUT, VOI LUT, CURVE, TOPIC, VISIT, RESULTS, INTERPRETATION, STUDY COMPONENT and STORED PRINT were previously defined in DICOM for this Attribute. They are now retired. See PS3.3-2004. +3. Enumerated Value MRDR was previously defined in DICOM for this Attribute, to allow indirect reference to a File by multiple Directory Records. It is now retired. FSUs and FSRs are unlikely to be capable of supporting this mechanism. See PS3.3-2004. + + + Required if the Directory Record Type (0004,1430) is of Value PRIVATE. This UID is used to define a non-standard type of Directory Record by reference to its position in a private extension to the Basic Directory IOD Information Model (see Section F.5). This UID shall be registered according to the procedures defined in PS 3.5. Its meaning may or may not be specified in a Conformance Statement. + + + A Multiple Value (See PS 3.5) which represents the ordered components of the File ID containing a "referenced object" or Referenced SOP Instance. A maximum of 8 components, each from 1 to 8 characters shall be used (see Section 8.2). +Note: The Referenced File ID provides the means to "locate" the File through the DICOM File Service provided by the Media Format Layer. +All referenced Files shall be with the File-set to which the Directory belongs. Any File within the File-set (to which the Directory belongs) shall be referenced by at most one Directory Record. When the Directory Record does not reference any SOP Instance this attribute shall not be present. + + + Unique ID for the SOP Class of the Instance stored in the referenced File. +Required if the Directory Record references a SOP Instance. + + + Unique Identifier for the SOP Instance stored in the referenced file. +Required if the Directory Record references a SOP Instance. + + + Unique Identifier for the Transfer Syntax used to encode the Instance stored in the referenced file. +Required if the Directory Record references a SOP Instance. + + + Unique ID for the Related General SOP Class(es) related to the SOP Class of the Instance stored in the referenced file. +Required if the Directory Record references a SOP Instance that encodes the Related General SOP Class UID (0008,001A). +Note: This may be useful to an FSR that does not support the SOP Class of the referenced Instance, but which does support one of the Related General SOP Classes. + + + + + + + + + Required if an extended or replacement character set is used in one of the keys + + + + + + + + + + + + Required if an extended or replacement character set is used in one of the keys + + + + + + + + + + + + Required only if (0004,1511) is absent. +(See Note) + + + + + + + + + + + + Required if an extended or replacement character set is used in one of the keys + + + + + + + + + + + + This Icon Image is representative of the Series. It may or may not correspond to one of the images of the Series. Only a single Item shall be permitted in this Sequence. + + + + + + + Required if an extended or replacement character set is used in one of the keys. + + + + + + This Icon Image is representative of the Image. Only a single Item shall be permitted in this Sequence. + + + + + + + Required if an extended or replacement character set is used in one of the keys. + + + + + + + + + + + + This Icon Image is representative of the RT Dose. Only a single Item shall be permitted in this Sequence. + + + + + + + Required if an extended or replacement character set is used in one of the keys. + + + + + + + + + + + + + + + + + + Required if an extended or replacement character set is used in one of the keys + + + + + + + + + + + + + + + + + + Required if an extended or replacement character set is used in one of the keys + + + + + + + + + + + + + + + Required if an extended or replacement character set is used in one of the keys. + + + Date on which this presentation was created. +Note: This date may be different from the date that the DICOM SOP Instance was created, since the presentation state information contained may have been recorded earlier. + + + Time at which this presentation was created. +Note: This time may be different from the time that the DICOM SOP Instance was created, since the presentation state information contained may have been recorded earlier. + + + + Sequence of Items where each Item includes the Attributes of one Series to which the Presentation applies. +Required if the IOD of the Presentation SOP Instance referenced by this directory record includes the Presentation State Relationship Module. One or more Items may be included in this Sequence. + + + Unique identifier of a Series that is part of this Study. + + + Sequence of Items where each Item provides reference to an Image SOP Instance . + + + + Sequence of exactly two Items where each Item includes the Attributes of a Study to which the Presentation applies. +Required if the SOP Instance referenced by this directory record includes the Blending Sequence (0070,0402) attribute. + + + Unique identifier for a Study that contains the images to which the Presentation applies. + + + Sequence of Items where each Item includes the Attributes of one Series to which the Presentation applies. +Only a single item shall be permitted in this Sequence. + + + Unique identifier of the Series + + + Sequence of Items where each Item provides reference to an Image SOP Instance to which the Presentation applies + + + + + + + Required if an extended or replacement character set is used in one of the keys. + + + + + + + + + + + + + + + Required if an extended or replacement character set is used in one of the keys. + + + + + + + + + + + + + + + + + + Most recent Date and Time of verification among those defined in the Verifying Observer Sequence (0040,A073). +Required if Verification Flag (0040,A493) is VERIFIED. + + + Code describing the concept represented by the root Content Item (Document Title). This sequence shall contain exactly one Item. + + + + Contains the Target Content Items that modify the Concept Name Code Sequence of the root Content Item (Document Title). +Required if the root Content Item is the Source Content Item of HAS CONCEPT MOD relationships. +One or more Items shall be included in this Sequence. All, and only, Content Items with the HAS CONCEPT MOD relationship from the root Content Item shall be included in this Sequence. + + + Enumerated Value: +HAS CONCEPT MOD + + + + + + + Required if an extended or replacement character set is used in one of the keys. + + + + + + + + + + + + Code describing the concept represented by the root Content Item (Document Title). This sequence shall contain exactly one Item. + + + + Contains the Target Content Items that modify the Concept Name Code Sequence of the root Content Item (Document Title). +Required if the root Content Item is the Source Content Item of HAS CONCEPT MOD relationships. +One or more Items shall be included in this Sequence. All, and only, Content Items with the HAS CONCEPT MOD relationship from the root Content Item shall be included in this Sequence. + + + Enumerated Value: +HAS CONCEPT MOD + + + + + + + Required if an extended or replacement character set is used in one of the keys. + + + + + + + + + + + + + + + Required if present in the spectroscopy instance. + + + + + + + + + + + + + + + + + + + This Icon Image is representative of the Spectroscopy instance. Only a single Item shall be permitted in this Sequence. + + + + + + + Required if an extended or replacement character set is used in one of the keys. + + + + + + + + + + + + This Icon Image is representative of the Raw Data instance. Only a single Item shall be permitted in this Sequence. + + + + + + + Required if an extended or replacement character set is used in one of the keys. + + + The date the content creation started. + + + The time the content creation started. + + + + + + + Required if an extended or replacement character set is used in one of the keys. + + + The date the content creation started. + + + The time the content creation started. + + + + + + + Required if an extended or replacement character set is used in one of the keys + + + + + + + + + + + + + + + + + + Sequence that defines the type of imaging studies to which this Hanging Protocol applies. One or more sequence items shall be present. + + + Required if Anatomic Region Sequence (0008,2218) is not present. May be present otherwise. + + + Required if Modality (0008,0060) is not present. May be present otherwise. + + + + Required if Anatomic Region Sequence (0008,2218) is present. + + + One or more Items may be included in this Sequence. + + + + One or more Items may be included in this sequence. + + + + + + + Sequence that provides a coded identifier for the person, group, or site for which this Hanging Protocol was defined. Zero or one Items may be included in this Sequence. + + + + + + + Required if an extended or replacement character set is used in one of the keys. + + + The date the content creation started. + + + The time the content creation started. + + + A number that identifies this instance + + + The title of the document. + + + Instance Identifier from the referenced HL7 Structured Document, encoded as a UID (OID or UUID), concatenated with a caret ("^") and Extension value (if Extension is present in Instance Identifier). +Required if encapsulated document is an HL7 Structured Document. + + + A coded representation of the document title. Zero or one item may be present. + + + + The type of the encapsulated document stream described using the MIME Media Type (see RFC 2046). + + + + + + Required if an extended or replacement character set is used in one of the keys. + + + Instance Identifier from the referenced HL7 Structured Document, encoded as a UID (OID or UUID), concatenated with a caret ("^") and Extension value (if Extension is present in Instance Identifier). + + + Effective Time from the referenced HL7 Structured Document + + + Document Type Code from the referenced HL7 Structured Document. Required if the HL7 Structured Document contains a Document Type Code. Only a single Item shall be permitted in this Sequence. + + + + Document Title from the referenced HL7 Structured Document. Required if the HL7 Structured Document contains a Document Title. + + + + + Required if an extended or replacement character set is used in one of the keys. + + + The date the content creation started. + + + The time the content creation started. + + + + + + + Required if an extended or replacement character set is used in one of the keys. + + + + diff --git a/gdcm/Source/InformationObjectDefinition/Part3.xsl b/gdcm/Source/InformationObjectDefinition/Part3.xsl new file mode 100644 index 0000000..bf7101f --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/Part3.xsl @@ -0,0 +1,901 @@ + + + + + + + + + ' + " + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ’“â€â€“ ï­Â­ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SHOULD NOT HAPPEN + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Error: could not MATCH + + + + + + + + + + UNHANDLED + + + + + + + + + + + + + + + + + + + + + + NO TABLE REF + + + + + + + + + ERROR: + + + + + + + ^([CF]\.[0-9a-z\.]+)\s*(.*)$ + + + + + See Section ([C]\.[0-9\.]+) + See ([C]\.[0-9a-f\.]+) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + — + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +NOT IOD/Macro or Module ref= + + +name= + + +att name= + + + + + + + + + + + + + + + + + + Info: section found + + + + + + + + Info: all paragraphs extracted + + + Error: section found multiple times! + + + Error: section not found! + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + (.*Enumerated [Vv]alue[s]?\s*(are)*\s*:)(.*) + (.*Defined [Tt]erm[s]?\s*(are)*\s*:)(.*) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +type="text/xsl" href="ma2html.xsl" + + to produce output use: +$ xsltproc ma2html.xsl ModuleAttributes.xml + + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + + + + + + diff --git a/gdcm/Source/InformationObjectDefinition/Part4.xml b/gdcm/Source/InformationObjectDefinition/Part4.xml new file mode 100644 index 0000000..1605753 --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/Part4.xml @@ -0,0 +1,219 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdcm/Source/InformationObjectDefinition/Part4.xsl b/gdcm/Source/InformationObjectDefinition/Part4.xsl new file mode 100644 index 0000000..5c72494 --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/Part4.xsl @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + + + + diff --git a/gdcm/Source/InformationObjectDefinition/Part4ToC++.xsl b/gdcm/Source/InformationObjectDefinition/Part4ToC++.xsl new file mode 100644 index 0000000..2ba81c2 --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/Part4ToC++.xsl @@ -0,0 +1,58 @@ + + + + + + + +// GENERATED FILE DO NOT EDIT +// $ xsltproc Part4ToC++.xsl Part4.xml > gdcmSOPClassUIDToIOD.cxx + +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + + +#include "gdcmSOPClassUIDToIOD.h" + +namespace gdcm +{ + static const char * const SOPClassToIOD[][2] = { + + + {" + + " , " + + "}, + + + + +{ 0, 0 } +}; + +} // end namespace gdcm + + + diff --git a/gdcm/Source/InformationObjectDefinition/README.txt b/gdcm/Source/InformationObjectDefinition/README.txt new file mode 100644 index 0000000..a26f2f4 --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/README.txt @@ -0,0 +1,11 @@ +Part 3.3 + + +Footnote: +http://www.devarticles.com/c/a/XML/An-Introduction-to-XML-Schemas/ +http://www.xml.com/pub/a/2000/11/29/schemas/part1.html +http://xmlfr.org/w3c/TR/xmlschema-0/ +http://xmlfr.org/documentations/tutoriels/001218-0001 +http://xml.ascc.net/schematron/ +http://xml.ascc.net/resource/schematron/schematron.html +http://209.85.129.104/search?q=cache:sTA73AQ9KKMJ:lists.xml.org/archives/xml-dev/200005/msg00741.html+xml+schema+condition&hl=fr&gl=fr&ct=clnk&cd=2&client=firefox-a diff --git a/gdcm/Source/InformationObjectDefinition/Template.xml.in b/gdcm/Source/InformationObjectDefinition/Template.xml.in new file mode 100644 index 0000000..3197f73 --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/Template.xml.in @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/gdcm/Source/InformationObjectDefinition/ValueRepresentation.xsd b/gdcm/Source/InformationObjectDefinition/ValueRepresentation.xsd new file mode 100644 index 0000000..d5389a9 --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/ValueRepresentation.xsd @@ -0,0 +1,693 @@ + + + + + + + + + + + + + + + + + + + + + + + +--> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ` + + diff --git a/gdcm/Source/InformationObjectDefinition/extract.xsl b/gdcm/Source/InformationObjectDefinition/extract.xsl new file mode 100644 index 0000000..22f4677 --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/extract.xsl @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdcm/Source/InformationObjectDefinition/gdcmDefinedTerms.cxx b/gdcm/Source/InformationObjectDefinition/gdcmDefinedTerms.cxx new file mode 100644 index 0000000..afe7ef0 --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/gdcmDefinedTerms.cxx @@ -0,0 +1,17 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmDefinedTerms.h" + +namespace gdcm +{} diff --git a/gdcm/Source/InformationObjectDefinition/gdcmDefinedTerms.h b/gdcm/Source/InformationObjectDefinition/gdcmDefinedTerms.h new file mode 100644 index 0000000..3a71129 --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/gdcmDefinedTerms.h @@ -0,0 +1,37 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMDEFINEDTERMS_H +#define GDCMDEFINEDTERMS_H + +#include "gdcmTypes.h" + +namespace gdcm +{ +/** + * \brief +Defined Terms are used when the specified explicit Values may be extended by implementors to include additional new Values. These new Values shall be specified in the Conformance Statement (see PS 3.2) and shall not have the same meaning as currently defined Values in this standard. A Data Element with Defined Terms that does not contain a Value equivalent to one of the Values currently specified in this standard shall not be considered to have an invalid value. +Note: Interpretation Type ID (4008,0210) is an example of a Data Element having Defined Terms. It is defined to have a Value that may be one of the set of standard Values; REPORT or AMENDMENT (see PS 3.3). Because this Data Element has Defined Terms other Interpretation Type IDs may be defined by the implementor. + * + */ +class GDCM_EXPORT DefinedTerms +{ +public: + DefinedTerms() { + } +private: +}; + +} // end namespace gdcm + +#endif //GDCMDEFINEDTERMS_H diff --git a/gdcm/Source/InformationObjectDefinition/gdcmDefs.cxx b/gdcm/Source/InformationObjectDefinition/gdcmDefs.cxx new file mode 100644 index 0000000..a2bc56b --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/gdcmDefs.cxx @@ -0,0 +1,369 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmDefs.h" +#include "gdcmTableReader.h" +#include "gdcmMediaStorage.h" +//#include "gdcmGlobal.h" +#include "gdcmTrace.h" +#include "gdcmFile.h" + +#include + +namespace gdcm +{ + +Defs::Defs() +{ +} + +Defs::~Defs() +{ +} + +void Defs::LoadDefaults() +{ +// TableReader tr(*this); +// const Global &g = Global::GetInstance(); +// const char *filename = g.Locate( "Part3.xml" ); +// +// if( filename ) +// { +// tr.SetFilename(filename); +// tr.Read(); +// } +// else +// { +// gdcmErrorMacro( "Could not find Part3.xml file. Please report" ); +// throw Exception( "Impossible" ); +// } +} + +void Defs::LoadFromFile(const char *filename) +{ + assert( filename ); + TableReader tr(*this); + tr.SetFilename(filename); + tr.Read(); +} + +const char *Defs::GetIODNameFromMediaStorage(MediaStorage const &ms) +{ + const char *iodname; + switch(ms) + { + case MediaStorage::MediaStorageDirectoryStorage: + iodname = "Basic Directory IOD Modules"; + break; + case MediaStorage::MRImageStorage: + iodname = "MR Image IOD Modules"; + break; + case MediaStorage::EnhancedMRImageStorage: + iodname = "Enhanced MR Image IOD Modules"; + break; + case MediaStorage::CTImageStorage: + iodname = "CT Image IOD Modules"; + break; + case MediaStorage::EnhancedCTImageStorage: + iodname = "Enhanced CT Image IOD Modules"; + break; + case MediaStorage::ComputedRadiographyImageStorage: + iodname = "CR Image IOD Modules"; + break; + case MediaStorage::XRayAngiographicImageStorage: + //case MediaStorage::XRayAngiographicBiPlaneImageStorageRetired: // FIXME ??? + iodname = "X Ray Angiographic Image IOD Modules"; + break; + case MediaStorage::UltrasoundImageStorageRetired: + case MediaStorage::UltrasoundImageStorage: + iodname = "US Image IOD Modules"; + break; + case MediaStorage::UltrasoundMultiFrameImageStorageRetired: + case MediaStorage::UltrasoundMultiFrameImageStorage: + iodname ="US Multi Frame Image IOD Modules"; + break; + case MediaStorage::SecondaryCaptureImageStorage: + iodname = "SC Image IOD Modules"; + break; + case MediaStorage::XRayRadiofluoroscopingImageStorage: + iodname = "XRF Image IOD Modules"; + break; + case MediaStorage::MRSpectroscopyStorage: + iodname = "MR Spectroscopy IOD Modules"; + break; + case MediaStorage::NuclearMedicineImageStorageRetired: + case MediaStorage::NuclearMedicineImageStorage: + iodname = "NM Image IOD Modules"; + break; + case MediaStorage::MultiframeSingleBitSecondaryCaptureImageStorage: + iodname = "Multi Frame Single Bit SC Image IOD Modules"; + break; + case MediaStorage::MultiframeGrayscaleByteSecondaryCaptureImageStorage: + iodname = "Multi Frame Grayscale Byte SC Image IOD Modules"; + break; + case MediaStorage::MultiframeGrayscaleWordSecondaryCaptureImageStorage: + iodname = "Multi Frame Grayscale Word SC Image IOD Modules"; + break; + case MediaStorage::MultiframeTrueColorSecondaryCaptureImageStorage: + iodname = "Multi Frame True Color SC Image IOD Modules"; + break; + case MediaStorage::EncapsulatedPDFStorage: + iodname = "Encapsulated PDF IOD Modules"; + break; + case MediaStorage::EncapsulatedCDAStorage: + iodname = "Encapsulated CDA IOD Modules"; + break; + case MediaStorage::VLPhotographicImageStorage: + iodname = "VL Photographic Image IOD Modules"; + break; + case MediaStorage::SegmentationStorage: + iodname = "Segmentation IOD Modules"; + break; + case MediaStorage::RawDataStorage: + iodname = "Raw Data IOD Modules"; + break; + case MediaStorage::MammographyCADSR: + iodname = "Mammography CAD SR IOD Modules"; + break; + case MediaStorage::VideoEndoscopicImageStorage: + iodname = "Video Endoscopic Image IOD Modules"; + break; + case MediaStorage::RTImageStorage: + iodname = "RT Image IOD Modules"; + break; + case MediaStorage::RTDoseStorage: + iodname = "RT Dose IOD Modules"; + break; + case MediaStorage::RTStructureSetStorage: + iodname = "RT Structure Set IOD Modules"; + break; + case MediaStorage::RTPlanStorage: + iodname = "RT Plan IOD Modules"; + break; + case MediaStorage::ModalityPerformedProcedureStepSOPClass: + iodname = "Modality Performed Procedure Step IOD Modules"; + break; + case MediaStorage::HangingProtocolStorage: + iodname = "Hanging Protocol IOD Modules"; + break; + case MediaStorage::KeyObjectSelectionDocument: + iodname = "Key Object Selection Document IOD Modules"; + break; + case MediaStorage::ComprehensiveSR: + iodname = "Comprehensive SR IOD Modules"; + break; + case MediaStorage::HemodynamicWaveformStorage: + iodname = "Hemodynamic IOD Modules"; + break; + case MediaStorage::DigitalIntraoralXrayImageStorageForPresentation: + case MediaStorage::DigitalIntraoralXRayImageStorageForProcessing: + iodname = "Digital Intra Oral X Ray Image IOD Modules"; + break; + case MediaStorage::DigitalXRayImageStorageForPresentation: + case MediaStorage::DigitalXRayImageStorageForProcessing: + iodname = "Digital X Ray Image IOD Modules"; + break; + case MediaStorage::DigitalMammographyImageStorageForPresentation: + case MediaStorage::DigitalMammographyImageStorageForProcessing: + iodname = "Digital Mammography X Ray Image IOD Modules"; + break; + case MediaStorage::GrayscaleSoftcopyPresentationStateStorageSOPClass: + iodname = "Grayscale Softcopy Presentation State IOD Modules"; + break; + case MediaStorage::LeadECGWaveformStorage: + iodname = "12 Lead ECG IOD Modules"; + break; + case MediaStorage::GeneralECGWaveformStorage: + iodname = "General ECG IOD Modules"; + break; + case MediaStorage::AmbulatoryECGWaveformStorage: + iodname = "Ambulatory ECG IOD Modules"; + break; + case MediaStorage::BasicVoiceAudioWaveformStorage: + iodname = "Basic Voice Audio IOD Modules"; + break; + case MediaStorage::SpacialFiducialsStorage: + iodname = "Spatial Fiducials IOD Modules"; + break; + case MediaStorage::BasicTextSR: + iodname = "Basic Text SR IOD Modules"; + break; + case MediaStorage::CardiacElectrophysiologyWaveformStorage: + iodname = "Basic Cardiac EP IOD Modules"; + break; + case MediaStorage::PETImageStorage: + iodname = "PET Image IOD Modules"; + break; + case MediaStorage::EnhancedSR: + iodname = "Enhanced SR IOD Modules"; + break; + case MediaStorage::SpacialRegistrationStorage: + iodname = "Spatial Registration IOD Modules"; + break; + case MediaStorage::RTIonPlanStorage: + iodname = "RT Ion Plan IOD Modules"; + break; + case MediaStorage::XRay3DAngiographicImageStorage: + iodname = "X Ray 3D Angiographic Image IOD Modules"; + break; + case MediaStorage::EnhancedXAImageStorage: + iodname = "Enhanced X Ray Angiographic Image IOD Modules"; + break; + case MediaStorage::RTIonBeamsTreatmentRecordStorage: + iodname = "RT Ion Beams Treatment Record IOD Modules"; + break; + case MediaStorage::RTTreatmentSummaryRecordStorage: + iodname = "RT Treatment Summary Record IOD Modules"; + break; + case MediaStorage::VLEndoscopicImageStorage: + iodname = "VL Endoscopic Image IOD Modules"; + break; + case MediaStorage::XRayRadiationDoseSR: + iodname = "X Ray Radiation Dose SR IOD Modules"; + break; + case MediaStorage::CSANonImageStorage: + iodname = "Siemens Non-image IOD Modules"; + break; + case MediaStorage::VLMicroscopicImageStorage: + iodname = "VL Microscopic Image IOD Modules"; + break; + default: + iodname = 0; + } + return iodname; +} + +const IOD& Defs::GetIODFromFile(const File& file) const +{ + MediaStorage ms; + ms.SetFromFile(file); // SetFromDataSet does not handle DICOMDIR + + const IODs &iods = GetIODs(); + const char *iodname = GetIODNameFromMediaStorage( ms ); + if( !iodname ) + { + gdcmErrorMacro( "Not implemented: " << ms ); + throw "Not Implemented"; + } + const IOD &iod = iods.GetIOD( iodname ); + return iod; +} + +Type Defs::GetTypeFromTag(const File& file, const Tag& tag) const +{ + Type ret; + MediaStorage ms; + ms.SetFromFile(file); // SetFromDataSet does not handle DICOMDIR + + const IODs &iods = GetIODs(); + const Modules &modules = GetModules(); + const char *iodname = GetIODNameFromMediaStorage( ms ); + if( !iodname ) + { + gdcmErrorMacro( "Not implemented: " << ms ); + return ret; + } + const IOD &iod = iods.GetIOD( iodname ); + const Macros ¯os = GetMacros(); + + IOD::SizeType niods = iod.GetNumberOfIODs(); + // Iterate over each iod entry in order: + for(unsigned int idx = 0; idx < niods; ++idx) + { + const IODEntry &iodentry = iod.GetIODEntry(idx); + const char *ref = iodentry.GetRef(); + //Usage::UsageType ut = iodentry.GetUsageType(); + + const Module &module = modules.GetModule( ref ); + if( module.FindModuleEntryInMacros(macros, tag ) ) + { + const ModuleEntry &module_entry = module.GetModuleEntryInMacros(macros,tag); + ret = module_entry.GetType(); + } + } + + return ret; +} + +bool Defs::Verify(const File& file) const +{ + MediaStorage ms; + ms.SetFromFile(file); + + const IODs &iods = GetIODs(); + const Modules &modules = GetModules(); + const char *iodname = GetIODNameFromMediaStorage( ms ); + if( !iodname ) + { + gdcmErrorMacro( "Not implemented" ); + return false; + } + const IOD &iod = iods.GetIOD( iodname ); + + //std::cout << iod << std::endl; + //std::cout << iod.GetIODEntry(14) << std::endl; + IOD::SizeType niods = iod.GetNumberOfIODs(); + bool v = true; + // Iterate over each iod entry in order: + for(unsigned int idx = 0; idx < niods; ++idx) + { + const IODEntry &iodentry = iod.GetIODEntry(idx); + const char *ref = iodentry.GetRef(); + Usage::UsageType ut = iodentry.GetUsageType(); + + const Module &module = modules.GetModule( ref ); + //std::cout << module << std::endl; + v = v && module.Verify( file.GetDataSet(), ut ); + } + + return v; + +} + +bool Defs::Verify(const DataSet& ds) const +{ + MediaStorage ms; + ms.SetFromDataSet(ds); + + const IODs &iods = GetIODs(); + const Modules &modules = GetModules(); + const char *iodname = GetIODNameFromMediaStorage( ms ); + if( !iodname ) + { + gdcmErrorMacro( "Not implemented" ); + return false; + } + const IOD &iod = iods.GetIOD( iodname ); + + //std::cout << iod << std::endl; + //std::cout << iod.GetIODEntry(14) << std::endl; + IOD::SizeType niods = iod.GetNumberOfIODs(); + bool v = true; + // Iterate over each iod entry in order: + for(unsigned int idx = 0; idx < niods; ++idx) + { + const IODEntry &iodentry = iod.GetIODEntry(idx); + const char *ref = iodentry.GetRef(); + Usage::UsageType ut = iodentry.GetUsageType(); + + const Module &module = modules.GetModule( ref ); + //std::cout << module << std::endl; + v = v && module.Verify( ds, ut ); + } + + return v; + +} + + +} // end namespace gdcm diff --git a/gdcm/Source/InformationObjectDefinition/gdcmDefs.h b/gdcm/Source/InformationObjectDefinition/gdcmDefs.h new file mode 100644 index 0000000..1afe432 --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/gdcmDefs.h @@ -0,0 +1,80 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMDEFS_H +#define GDCMDEFS_H + +#include "gdcmModules.h" +#include "gdcmMacros.h" +#include "gdcmIODs.h" + +#include + +namespace gdcm +{ +class DataSet; +class File; +class MediaStorage; +/** + * \brief FIXME I do not like the name 'Defs' + * \note bla + */ +class GDCM_EXPORT Defs +{ +public: + Defs(); + ~Defs(); + + const Modules &GetModules() const { return Part3Modules; } + Modules &GetModules() { return Part3Modules; } + + /// Users should not directly use Macro. Macro are simply a way for DICOM WG to re-use Tables. + /// Macros are conviently wraped within Modules. See gdcm::Module API directly + const Macros &GetMacros() const { return Part3Macros; } + Macros &GetMacros() { return Part3Macros; } + + const IODs & GetIODs() const { return Part3IODs; } + IODs & GetIODs() { return Part3IODs; } + + bool IsEmpty() const { return GetModules().IsEmpty(); } + + bool Verify(const File& file) const; + + // \deprecated DO NOT USE + bool Verify(const DataSet& ds) const; + + Type GetTypeFromTag(const File& file, const Tag& tag) const; + + static const char *GetIODNameFromMediaStorage(MediaStorage const &ms); + + const IOD& GetIODFromFile(const File& file) const; + +protected: + friend class Global; + void LoadDefaults(); + void LoadFromFile(const char *filename); + +private: + // Part 3 stuff: + Macros Part3Macros; + Modules Part3Modules; + IODs Part3IODs; + + Defs &operator=(const Defs &val); // purposely not implemented + Defs(const Defs &val); // purposely not implemented +}; + + +} // end namespace gdcm + +#endif //GDCMDEFS_H diff --git a/gdcm/Source/InformationObjectDefinition/gdcmEnumeratedValues.cxx b/gdcm/Source/InformationObjectDefinition/gdcmEnumeratedValues.cxx new file mode 100644 index 0000000..53ad2de --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/gdcmEnumeratedValues.cxx @@ -0,0 +1,17 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmEnumeratedValues.h" + +namespace gdcm +{} diff --git a/gdcm/Source/InformationObjectDefinition/gdcmEnumeratedValues.h b/gdcm/Source/InformationObjectDefinition/gdcmEnumeratedValues.h new file mode 100644 index 0000000..430edf0 --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/gdcmEnumeratedValues.h @@ -0,0 +1,44 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMENUMERATEDVALUES_H +#define GDCMENUMERATEDVALUES_H + +#include "gdcmTypes.h" + +namespace gdcm +{ +/** + * \brief + * Element. A Data Element with Enumerated Values that does not have a Value equivalent to one of the + * Values specified in this standard has an invalid value within the scope of a specific Information + * Object/SOP Class definition. + * Note: + * 1. Patient Sex (0010, 0040) is an example of a Data Element having Enumerated Values. It is defined to + * have a Value that is either "M", "F", or "O" (see PS 3.3). No other Value shall be given to this Data + * Element. + * 2. Future modifications of this standard may add to the set of allowed values for Data Elements with + * Enumerated Values. Such additions by themselves may or may not require a change in SOP Class + * UIDs, depending on the semantics of the Data Element. + */ +class GDCM_EXPORT EnumeratedValues +{ +public: + EnumeratedValues() { + } +private: +}; + +} // end namespace gdcm + +#endif //GDCMENUMERATEDVALUES_H diff --git a/gdcm/Source/InformationObjectDefinition/gdcmIOD.cxx b/gdcm/Source/InformationObjectDefinition/gdcmIOD.cxx new file mode 100644 index 0000000..266d066 --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/gdcmIOD.cxx @@ -0,0 +1,52 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmIOD.h" + +#include "gdcmDataSet.h" +#include "gdcmModule.h" +#include "gdcmModules.h" +#include "gdcmDefs.h" + +namespace gdcm +{ + +Type IOD::GetTypeFromTag(const Defs &defs, const Tag& tag) const +{ + Type ret; + const IOD &iod = *this; + static const Modules &modules = defs.GetModules(); + static const Macros ¯os = defs.GetMacros(); + + const size_t niods = iod.GetNumberOfIODs(); + // Iterate over each iod entry in order: + bool found = false; + for(unsigned int idx = 0; !found && idx < niods; ++idx) + { + const IODEntry &iodentry = iod.GetIODEntry(idx); + const char *ref = iodentry.GetRef(); + //Usage::UsageType ut = iodentry.GetUsageType(); + + const Module &module = modules.GetModule( ref ); + if( module.FindModuleEntryInMacros(macros, tag ) ) + { + const ModuleEntry &module_entry = module.GetModuleEntryInMacros(macros,tag); + ret = module_entry.GetType(); + found = true; + } + } + + return ret; +} + +} diff --git a/gdcm/Source/InformationObjectDefinition/gdcmIOD.h b/gdcm/Source/InformationObjectDefinition/gdcmIOD.h new file mode 100644 index 0000000..c4c0afa --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/gdcmIOD.h @@ -0,0 +1,81 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMIOD_H +#define GDCMIOD_H + +#include "gdcmTypes.h" +#include "gdcmTag.h" +#include "gdcmIODEntry.h" + +#include + +namespace gdcm +{ +class DataSet; +class Defs; + +/** + * \brief Class for representing a IOD + * \note bla + * + * \sa Dict + */ +class GDCM_EXPORT IOD +{ +public: + typedef std::vector MapIODEntry; + typedef MapIODEntry::size_type SizeType; + + IOD() {} + friend std::ostream& operator<<(std::ostream& _os, const IOD &_val); + + void Clear() { IODInternal.clear(); } + + void AddIODEntry(const IODEntry & iode) + { + IODInternal.push_back(iode); + } + + SizeType GetNumberOfIODs() const { + return IODInternal.size(); + } + + const IODEntry& GetIODEntry(SizeType idx) const + { + return IODInternal[idx]; + } + + Type GetTypeFromTag(const Defs &defs, const Tag& tag) const; + +private: + //IOD &operator=(const IOD &_val); // purposely not implemented + //IOD(const IOD &_val); // purposely not implemented + + MapIODEntry IODInternal; +}; +//----------------------------------------------------------------------------- +inline std::ostream& operator<<(std::ostream& _os, const IOD &_val) +{ + IOD::MapIODEntry::const_iterator it = _val.IODInternal.begin(); + for(;it != _val.IODInternal.end(); ++it) + { + _os << *it << '\n'; + } + + return _os; +} + +} // end namespace gdcm + +#endif //GDCMIOD_H diff --git a/gdcm/Source/InformationObjectDefinition/gdcmIODEntry.cxx b/gdcm/Source/InformationObjectDefinition/gdcmIODEntry.cxx new file mode 100644 index 0000000..a5acb70 --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/gdcmIODEntry.cxx @@ -0,0 +1,49 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmIODEntry.h" + +#include // abort + +namespace gdcm +{ + +Usage::UsageType IODEntry::GetUsageType() const +{ + assert( !usage.empty() ); + if( usage == "M" ) + { + return Usage::Mandatory; + } + else if( usage == "U" ) + { + return Usage::UserOption; + } + else if( usage.find( "U - " ) < usage.size() ) + { + return Usage::UserOption; + } + else if( usage.find( "C- " ) < usage.size() ) + { + return Usage::Conditional; + } + else if( usage.find( "C - " ) < usage.size() ) + { + return Usage::Conditional; + } + //else + assert(0); // Keep me so that I can debug Part3.xml + return Usage::Invalid; +} + +} diff --git a/gdcm/Source/InformationObjectDefinition/gdcmIODEntry.h b/gdcm/Source/InformationObjectDefinition/gdcmIODEntry.h new file mode 100644 index 0000000..af208f1 --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/gdcmIODEntry.h @@ -0,0 +1,89 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMIODENTRY_H +#define GDCMIODENTRY_H + +#include "gdcmUsage.h" +#include "gdcmType.h" + +#include + +namespace gdcm +{ +/** + * \brief Class for representing a IODEntry + * \note +A.1.3 IOD Module Table and Functional Group Macro Table +This Section of each IOD defines in a tabular form the Modules comprising the IOD. The following +information must be specified for each Module in the table: +- The name of the Module or Functional Group +- A reference to the Section in Annex C which defines the Module or Functional Group +- The usage of the Module or Functional Group; whether it is: +- Mandatory (see A.1.3.1) , abbreviated M +- Conditional (see A.1.3.2) , abbreviated C +- User Option (see A.1.3.3) , abbreviated U +The Modules referenced are defined in Annex C. +A.1.3.1 MANDATORY MODULES +For each IOD, Mandatory Modules shall be supported per the definitions, semantics and requirements +defined in Annex C. +PS 3.3 - 2008 +Page 96 +- Standard - +A.1.3.2 CONDITIONAL MODULES +Conditional Modules are Mandatory Modules if specific conditions are met. If the specified conditions are +not met, this Module shall not be supported; that is, no information defined in that Module shall be sent. +A.1.3.3 USER OPTION MODULES +User Option Modules may or may not be supported. If an optional Module is supported, the Attribute +Types specified in the Modules in Annex C shall be supported. + * \sa DictEntry + */ +class GDCM_EXPORT IODEntry +{ +public: + IODEntry(const char *name = "", const char *ref = "", const char *usag = ""):Name(name),Ref(ref),usage(usag) { + } + friend std::ostream& operator<<(std::ostream& _os, const IODEntry &_val); + + void SetIE(const char *ie) { IE = ie; } + const char *GetIE() const { return IE.c_str(); } + + void SetName(const char *name) { Name = name; } + const char *GetName() const { return Name.c_str(); } + + void SetRef(const char *ref) { Ref = ref; } + const char *GetRef() const { return Ref.c_str(); } + + void SetUsage(const char *usag) { usage = usag; } + const char *GetUsage() const { return usage.c_str(); } + Usage::UsageType GetUsageType() const; + +private: + std::string IE; + + std::string Name; + + std::string Ref; + + std::string usage; +}; +//----------------------------------------------------------------------------- +inline std::ostream& operator<<(std::ostream& _os, const IODEntry &_val) +{ + _os << _val.IE << "\t" << _val.Name << "\t" << _val.Ref << "\t" << _val.usage; + return _os; +} + +} // end namespace gdcm + +#endif //GDCMIODENTRY_H diff --git a/gdcm/Source/InformationObjectDefinition/gdcmIODs.h b/gdcm/Source/InformationObjectDefinition/gdcmIODs.h new file mode 100644 index 0000000..a69cc32 --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/gdcmIODs.h @@ -0,0 +1,78 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMIODS_H +#define GDCMIODS_H + +#include "gdcmTypes.h" +#include "gdcmIOD.h" + +#include + +namespace gdcm +{ +/** + * \brief Class for representing a IODs + * \note bla + * \sa IOD + */ +class GDCM_EXPORT IODs +{ +public: + typedef std::string IODName; + typedef std::map IODMapType; + + IODs() {} + friend std::ostream& operator<<(std::ostream& _os, const IODs &_val); + + void Clear() { IODsInternal.clear(); } + + void AddIOD(const char *name , const IOD & module ) + { + IODsInternal.insert( + IODMapType::value_type(name, module)); + } + const IOD &GetIOD(const char *name) const + { + //return IODsInternal[name]; + IODMapType::const_iterator it = IODsInternal.find( name ); + assert( it != IODsInternal.end() ); + assert( it->first == name ); + return it->second; + } + + typedef IODMapType::const_iterator IODMapTypeConstIterator; + IODMapTypeConstIterator Begin() const { return IODsInternal.begin(); } + IODMapTypeConstIterator End() const { return IODsInternal.end(); } + +private: + IODMapType IODsInternal; +}; +//----------------------------------------------------------------------------- +inline std::ostream& operator<<(std::ostream& _os, const IODs &_val) +{ + IODs::IODMapType::const_iterator it = _val.IODsInternal.begin(); + for(;it != _val.IODsInternal.end(); ++it) + { + const std::string &name = it->first; + const IOD &m = it->second; + _os << name << " " << m << '\n'; + } + + return _os; +} + + +} // end namespace gdcm + +#endif //GDCMIODS_H diff --git a/gdcm/Source/InformationObjectDefinition/gdcmMacro.cxx b/gdcm/Source/InformationObjectDefinition/gdcmMacro.cxx new file mode 100644 index 0000000..0e4d14f --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/gdcmMacro.cxx @@ -0,0 +1,82 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmMacro.h" +#include "gdcmDataSet.h" +#include "gdcmUsage.h" +//#include "gdcmDefs.h" +#include "gdcmModuleEntry.h" // MacroEntry +//#include "gdcmGlobal.h" + +namespace gdcm +{ + +bool Macro::FindMacroEntry(const Tag &tag) const +{ + MapModuleEntry::const_iterator it = ModuleInternal.find(tag); + if( it != ModuleInternal.end() ) + { + return true; + } + // Not found anywhere :( + return false; +} + +const MacroEntry& Macro::GetMacroEntry(const Tag &tag) const +{ + MapModuleEntry::const_iterator it = ModuleInternal.find(tag); + if( it != ModuleInternal.end() ) + { + assert( it->first == tag ); + return it->second; + } + // Not found anywhere :( + throw "Could not find Module for Tag requested"; +} + +bool Macro::Verify(const DataSet& ds, Usage const & usage) const +{ + bool success = true; + if( usage == Usage::UserOption ) return success; + Macro::MapModuleEntry::const_iterator it = ModuleInternal.begin(); + for(;it != ModuleInternal.end(); ++it) + { + const Tag &tag = it->first; + const ModuleEntry &me = it->second; + const gdcm::Type &type = me.GetType(); + if( ds.FindDataElement( tag ) ) + { + // element found + const DataElement &de = ds.GetDataElement( tag ); + if ( de.IsEmpty() && (type == Type::T1 || type == Type::T1C ) ) + { + gdcmWarningMacro( "T1 element cannot be empty: " << de ); + success = false; + } + } + else + { + if( type == Type::T1 || type == Type::T1C ) + { + gdcmWarningMacro( "DataSet is missing tag: " << tag ); + gdcmWarningMacro( "ModuleEntry specify: " << me ); + gdcmWarningMacro( "Usage is: " << usage ); + success = false; + } + } + } + + return success; +} + +} diff --git a/gdcm/Source/InformationObjectDefinition/gdcmMacro.h b/gdcm/Source/InformationObjectDefinition/gdcmMacro.h new file mode 100644 index 0000000..40907cd --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/gdcmMacro.h @@ -0,0 +1,97 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMMACRO_H +#define GDCMMACRO_H + +#include "gdcmTypes.h" +#include "gdcmTag.h" +#include "gdcmMacroEntry.h" + +#include +#include + +namespace gdcm +{ + +class DataSet; +class Usage; +/** + * \brief Class for representing a Macro + * \note Attribute Macro: + * a set of Attributes that are described in a single table that is referenced + * by multiple Module or other tables. + * \sa Module + */ +class GDCM_EXPORT Macro +{ +public: + typedef std::map MapModuleEntry; + typedef std::vector ArrayIncludeMacrosType; + + //typedef MapModuleEntry::const_iterator ConstIterator; + //typedef MapModuleEntry::iterator Iterator; + //ConstIterator Begin() const { return ModuleInternal.begin(); } + //Iterator Begin() { return ModuleInternal.begin(); } + //ConstIterator End() const { return ModuleInternal.end(); } + //Iterator End() { return ModuleInternal.end(); } + + Macro() {} + friend std::ostream& operator<<(std::ostream& _os, const Macro&_val); + + void Clear() { ModuleInternal.clear(); } + + /// Will add a ModuleEntry direcly at root-level. See Macro for nested-included level. + void AddMacroEntry(const Tag& tag, const MacroEntry & module) + { + ModuleInternal.insert( + MapModuleEntry::value_type(tag, module)); + } + + /// Find or Get a ModuleEntry. ModuleEntry are either search are root-level + /// or within nested-macro included in module. + bool FindMacroEntry(const Tag &tag) const; + const MacroEntry& GetMacroEntry(const Tag &tag) const; + + void SetName( const char *name) { Name = name; } + const char *GetName() const { return Name.c_str(); } + + // Verify will print on std::cerr for error + // Upon success will return true, false otherwise + bool Verify(const DataSet& ds, Usage const & usage) const; + +private: + //Module &operator=(const Module &_val); // purposely not implemented + //Module(const Module &_val); // purposely not implemented + + MapModuleEntry ModuleInternal; + std::string Name; +}; +//----------------------------------------------------------------------------- +inline std::ostream& operator<<(std::ostream& _os, const Macro &_val) +{ + _os << _val.Name << '\n'; + Macro::MapModuleEntry::const_iterator it = _val.ModuleInternal.begin(); + for(;it != _val.ModuleInternal.end(); ++it) + { + const Tag &t = it->first; + const MacroEntry &de = it->second; + _os << t << " " << de << '\n'; + } + + return _os; +} + +} // end namespace gdcm + +#endif //GDCMMACRO_H diff --git a/gdcm/Source/InformationObjectDefinition/gdcmMacroEntry.h b/gdcm/Source/InformationObjectDefinition/gdcmMacroEntry.h new file mode 100644 index 0000000..0f48caa --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/gdcmMacroEntry.h @@ -0,0 +1,82 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#if 0 +#ifndef GDCMMACROENTRY_H +#define GDCMMACROENTRY_H + +#include "gdcmTypes.h" +#include "gdcmType.h" + +#include + +namespace gdcm +{ +/** + * \brief Class for representing a ModuleEntry + * \note bla + * \sa DictEntry + */ +class GDCM_EXPORT MacroEntry +{ +public: + MacroEntry(const char *name = "", const char *type = "3", const char *description = ""):Name(name)/*,Type(type)*/,DescriptionField(description) { + DataElementType = Type::GetTypeType(type); + } + virtual ~MacroEntry() {} // important + friend std::ostream& operator<<(std::ostream& _os, const MacroEntry &_val); + + void SetName(const char *name) { Name = name; } + const char *GetName() const { return Name.c_str(); } + + void SetType(const Type &type) { DataElementType = type; } + const Type &GetType() const { return DataElementType; } + + /* + * WARNING: 'Description' is currently a std::string, but it might change in the future + * do not expect it to remain the same, and always use the ModuleEntry::Description typedef + * instead. + */ + typedef std::string Description; + void SetDescription(const char *d) { DescriptionField = d; } + const Description & GetDescription() const { return DescriptionField; } + +protected: + // PS 3.3 repeats the name of an attribute, but often contains typos + // for now we will not use this info, but instead access the DataDict instead + std::string Name; + + // An attribute, encoded as a Data Element, may or may not be required in a + // Data Set, depending on that Attribute's Data Element Type. + Type DataElementType; + + // TODO: for now contains the raw description (with enumerated values, defined terms...) + Description DescriptionField; +}; +//----------------------------------------------------------------------------- +inline std::ostream& operator<<(std::ostream& _os, const MacroEntry &_val) +{ + _os << _val.Name << "\t" << _val.DataElementType << "\t" << _val.DescriptionField; + return _os; +} + + +} // end namespace gdcm + +#endif //GDCMMODULEENTRY_H +#endif + +#ifndef GDCMMACROENTRY_H +#define GDCMMACROENTRY_H +#include "gdcmModuleEntry.h" +#endif diff --git a/gdcm/Source/InformationObjectDefinition/gdcmMacros.cxx b/gdcm/Source/InformationObjectDefinition/gdcmMacros.cxx new file mode 100644 index 0000000..bb68099 --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/gdcmMacros.cxx @@ -0,0 +1,18 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmMacros.h" + +namespace gdcm +{ +} diff --git a/gdcm/Source/InformationObjectDefinition/gdcmMacros.h b/gdcm/Source/InformationObjectDefinition/gdcmMacros.h new file mode 100644 index 0000000..44a8170 --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/gdcmMacros.h @@ -0,0 +1,78 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMMACROS_H +#define GDCMMACROS_H + +#include "gdcmTypes.h" +#include "gdcmMacro.h" + +#include + +namespace gdcm +{ +/** + * \brief Class for representing a Modules + * \note bla + * \sa Module + */ +class GDCM_EXPORT Macros +{ +public: + typedef std::map ModuleMapType; + + Macros() {} + friend std::ostream& operator<<(std::ostream& _os, const Macros&_val); + + void Clear() { ModulesInternal.clear(); } + + // A Module is inserted based on it's ref + void AddMacro(const char *ref, const Macro & module ) + { + assert( ref && *ref ); + assert( ModulesInternal.find( ref ) == ModulesInternal.end() ); + ModulesInternal.insert( + ModuleMapType::value_type(ref, module)); + } + const Macro &GetMacro(const char *name) const + { + assert( name && *name ); + ModuleMapType::const_iterator it = ModulesInternal.find( name ); + assert( it != ModulesInternal.end() ); + assert( it->first == name ); + return it->second; + } + + bool IsEmpty() const { return ModulesInternal.empty(); } + +private: + ModuleMapType ModulesInternal; +}; +//----------------------------------------------------------------------------- +inline std::ostream& operator<<(std::ostream& _os, const Macros &_val) +{ + Macros::ModuleMapType::const_iterator it = _val.ModulesInternal.begin(); + for(;it != _val.ModulesInternal.end(); ++it) + { + const std::string &name = it->first; + const Macro &m = it->second; + _os << name << " " << m << '\n'; + } + + return _os; +} + + +} // end namespace gdcm + +#endif //GDCMMODULES_H diff --git a/gdcm/Source/InformationObjectDefinition/gdcmModule.cxx b/gdcm/Source/InformationObjectDefinition/gdcmModule.cxx new file mode 100644 index 0000000..dba0926 --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/gdcmModule.cxx @@ -0,0 +1,126 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmModule.h" +#include "gdcmDataSet.h" +#include "gdcmUsage.h" +//#include "gdcmDefs.h" +#include "gdcmMacros.h" // Macros +//#include "gdcmGlobal.h" + +namespace gdcm +{ + +bool Module::FindModuleEntryInMacros(Macros const ¯os, const Tag &tag) const +{ + (void)macros; + MapModuleEntry::const_iterator it = ModuleInternal.find(tag); + if( it != ModuleInternal.end() ) + { + return true; + } + // Need to search within Nested-Included Macro: + // start with easy case: + if( ArrayIncludeMacros.empty() ) return false; + + // we need to loop over all Included-Macro: + //static const Global &g = Global::GetInstance(); + //static const Defs &defs = g.GetDefs(); + //static const Macros ¯os = defs.GetMacros(); + +#if 0 + for( ArrayIncludeMacrosType::const_iterator it = ArrayIncludeMacros.begin(); + it != ArrayIncludeMacros.end(); ++it) + { + const std::string &name = *it; + const Macro ¯o = macros.GetMacro( name.c_str() ); + if( macro.FindMacroEntry( tag ) ) + { + return true; + } + } +#endif + // Not found anywhere :( + return false; +} + +const ModuleEntry& Module::GetModuleEntryInMacros(Macros const ¯os, const Tag &tag) const +{ + MapModuleEntry::const_iterator it = ModuleInternal.find(tag); + if( it != ModuleInternal.end() ) + { + assert( it->first == tag ); + return it->second; + } + // Need to search within Nested-Included Macro: + // start with easy case: + if( ArrayIncludeMacros.empty() ) + { + throw "Could not find Module for Tag requested"; + } + + // we need to loop over all Included-Macro: + //static const Global &g = Global::GetInstance(); + //static const Defs &defs = g.GetDefs(); + //static const Macros ¯os = defs.GetMacros(); + + for( ArrayIncludeMacrosType::const_iterator it2 = ArrayIncludeMacros.begin(); + it2 != ArrayIncludeMacros.end(); ++it2) + { + const std::string &name = *it2; + const Macro ¯o= macros.GetMacro( name.c_str() ); + if( macro.FindMacroEntry( tag ) ) + { + return macro.GetMacroEntry(tag); + } + } + // Not found anywhere :( + throw "Could not find Module for Tag requested"; +} + +bool Module::Verify(const DataSet& ds, Usage const & usage) const +{ + bool success = true; + if( usage == Usage::UserOption ) return success; + Module::MapModuleEntry::const_iterator it = ModuleInternal.begin(); + for(;it != ModuleInternal.end(); ++it) + { + const Tag &tag = it->first; + const ModuleEntry &me = it->second; + const gdcm::Type &type = me.GetType(); + if( ds.FindDataElement( tag ) ) + { + // element found + const DataElement &de = ds.GetDataElement( tag ); + if ( de.IsEmpty() && (type == Type::T1 || type == Type::T1C ) ) + { + gdcmWarningMacro( "T1 element cannot be empty: " << de ); + success = false; + } + } + else + { + if( type == Type::T1 || type == Type::T1C ) + { + gdcmWarningMacro( "DataSet is missing tag: " << tag ); + gdcmWarningMacro( "ModuleEntry specify: " << me ); + gdcmWarningMacro( "Usage is: " << usage ); + success = false; + } + } + } + + return success; +} + +} diff --git a/gdcm/Source/InformationObjectDefinition/gdcmModule.h b/gdcm/Source/InformationObjectDefinition/gdcmModule.h new file mode 100644 index 0000000..37093d1 --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/gdcmModule.h @@ -0,0 +1,104 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMMODULE_H +#define GDCMMODULE_H + +#include "gdcmTypes.h" +#include "gdcmTag.h" +#include "gdcmModuleEntry.h" + +#include +#include + +namespace gdcm +{ + +class DataSet; +class Usage; +class Macros; +/** + * \brief Class for representing a Module + * \note + * Module: A set of Attributes within an Information Entity or Normalized IOD which + * are logically related to each other. + * \sa Macro + */ +class GDCM_EXPORT Module +{ +public: + typedef std::map MapModuleEntry; + typedef std::vector ArrayIncludeMacrosType; + + //typedef MapModuleEntry::const_iterator ConstIterator; + //typedef MapModuleEntry::iterator Iterator; + //ConstIterator Begin() const { return ModuleInternal.begin(); } + //Iterator Begin() { return ModuleInternal.begin(); } + //ConstIterator End() const { return ModuleInternal.end(); } + //Iterator End() { return ModuleInternal.end(); } + + Module() {} + friend std::ostream& operator<<(std::ostream& _os, const Module &_val); + + void Clear() { ModuleInternal.clear(); } + + /// Will add a ModuleEntry direcly at root-level. See Macro for nested-included level. + void AddModuleEntry(const Tag& tag, const ModuleEntry & module) + { + ModuleInternal.insert( + MapModuleEntry::value_type(tag, module)); + } + + void AddMacro(const char *include) + { + ArrayIncludeMacros.push_back( include ); + } + + /// Find or Get a ModuleEntry. ModuleEntry are either search are root-level + /// or within nested-macro included in module. + bool FindModuleEntryInMacros(Macros const ¯os, const Tag &tag) const; + const ModuleEntry& GetModuleEntryInMacros(Macros const ¯os, const Tag &tag) const; + + void SetName( const char *name) { Name = name; } + const char *GetName() const { return Name.c_str(); } + + // Verify will print on std::cerr for error + // Upon success will return true, false otherwise + bool Verify(const DataSet& ds, Usage const & usage) const; + +private: + //Module &operator=(const Module &_val); // purposely not implemented + //Module(const Module &_val); // purposely not implemented + + MapModuleEntry ModuleInternal; + std::string Name; + ArrayIncludeMacrosType ArrayIncludeMacros; +}; +//----------------------------------------------------------------------------- +inline std::ostream& operator<<(std::ostream& _os, const Module &_val) +{ + _os << _val.Name << '\n'; + Module::MapModuleEntry::const_iterator it = _val.ModuleInternal.begin(); + for(;it != _val.ModuleInternal.end(); ++it) + { + const Tag &t = it->first; + const ModuleEntry &de = it->second; + _os << t << " " << de << '\n'; + } + + return _os; +} + +} // end namespace gdcm + +#endif //GDCMMODULE_H diff --git a/gdcm/Source/InformationObjectDefinition/gdcmModuleEntry.h b/gdcm/Source/InformationObjectDefinition/gdcmModuleEntry.h new file mode 100644 index 0000000..f0e9e63 --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/gdcmModuleEntry.h @@ -0,0 +1,77 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMMODULEENTRY_H +#define GDCMMODULEENTRY_H + +#include "gdcmTypes.h" +#include "gdcmType.h" + +#include + +namespace gdcm +{ +/** + * \brief Class for representing a ModuleEntry + * \note bla + * \sa DictEntry + */ +class GDCM_EXPORT ModuleEntry +{ +public: + ModuleEntry(const char *name = "", const char *type = "3", const char *description = ""):Name(name)/*,Type(type)*/,DescriptionField(description) { + DataElementType = Type::GetTypeType(type); + } + virtual ~ModuleEntry() {} // important + friend std::ostream& operator<<(std::ostream& _os, const ModuleEntry &_val); + + void SetName(const char *name) { Name = name; } + const char *GetName() const { return Name.c_str(); } + + void SetType(const Type &type) { DataElementType = type; } + const Type &GetType() const { return DataElementType; } + + /* + * WARNING: 'Description' is currently a std::string, but it might change in the future + * do not expect it to remain the same, and always use the ModuleEntry::Description typedef + * instead. + */ + typedef std::string Description; + void SetDescription(const char *d) { DescriptionField = d; } + const Description & GetDescription() const { return DescriptionField; } + +protected: + // PS 3.3 repeats the name of an attribute, but often contains typos + // for now we will not use this info, but instead access the DataDict instead + std::string Name; + + // An attribute, encoded as a Data Element, may or may not be required in a + // Data Set, depending on that Attribute's Data Element Type. + Type DataElementType; + + // TODO: for now contains the raw description (with enumerated values, defined terms...) + Description DescriptionField; +}; +//----------------------------------------------------------------------------- +inline std::ostream& operator<<(std::ostream& _os, const ModuleEntry &_val) +{ + _os << _val.Name << "\t" << _val.DataElementType << "\t" << _val.DescriptionField; + return _os; +} + +typedef ModuleEntry MacroEntry; + + +} // end namespace gdcm + +#endif //GDCMMODULEENTRY_H diff --git a/gdcm/Source/InformationObjectDefinition/gdcmModules.cxx b/gdcm/Source/InformationObjectDefinition/gdcmModules.cxx new file mode 100644 index 0000000..c31f049 --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/gdcmModules.cxx @@ -0,0 +1,18 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmModules.h" + +namespace gdcm +{ +} diff --git a/gdcm/Source/InformationObjectDefinition/gdcmModules.h b/gdcm/Source/InformationObjectDefinition/gdcmModules.h new file mode 100644 index 0000000..3730f96 --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/gdcmModules.h @@ -0,0 +1,79 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMMODULES_H +#define GDCMMODULES_H + +#include "gdcmTypes.h" +#include "gdcmModule.h" + +#include + +namespace gdcm +{ +/** + * \brief Class for representing a Modules + * \note bla + * \sa Module + */ +class GDCM_EXPORT Modules +{ +public: + typedef std::map ModuleMapType; + + Modules() {} + friend std::ostream& operator<<(std::ostream& _os, const Modules &_val); + + void Clear() { ModulesInternal.clear(); } + + // A Module is inserted based on it's ref + void AddModule(const char *ref, const Module & module ) + { + assert( ref && *ref ); + assert( ModulesInternal.find( ref ) == ModulesInternal.end() ); + ModulesInternal.insert( + ModuleMapType::value_type(ref, module)); + } + const Module &GetModule(const char *name) const + { + assert( name && *name ); + ModuleMapType::const_iterator it = ModulesInternal.find( name ); + assert( it != ModulesInternal.end() ); + assert( it->first == name ); + return it->second; + } + + bool IsEmpty() const { return ModulesInternal.empty(); } + +private: + ModuleMapType ModulesInternal; +}; +//----------------------------------------------------------------------------- +inline std::ostream& operator<<(std::ostream& _os, const Modules &_val) +{ + Modules::ModuleMapType::const_iterator it = _val.ModulesInternal.begin(); + for(;it != _val.ModulesInternal.end(); ++it) + { + const std::string &name = it->first; + const Module &m = it->second; + _os << name << " " << m << '\n'; + } + + return _os; +} + + + +} // end namespace gdcm + +#endif //GDCMMODULES_H diff --git a/gdcm/Source/InformationObjectDefinition/gdcmNestedModuleEntries.cxx b/gdcm/Source/InformationObjectDefinition/gdcmNestedModuleEntries.cxx new file mode 100644 index 0000000..7998501 --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/gdcmNestedModuleEntries.cxx @@ -0,0 +1,15 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#include "gdcmNestedModuleEntries.h" diff --git a/gdcm/Source/InformationObjectDefinition/gdcmNestedModuleEntries.h b/gdcm/Source/InformationObjectDefinition/gdcmNestedModuleEntries.h new file mode 100644 index 0000000..b905671 --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/gdcmNestedModuleEntries.h @@ -0,0 +1,56 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMNESTEDMODULEENTRIES_H +#define GDCMNESTEDMODULEENTRIES_H + +#include "gdcmModuleEntry.h" +#include + +namespace gdcm +{ +/** + * \brief Class for representing a NestedModuleEntries + * \note bla + * \sa ModuleEntry + */ +class GDCM_EXPORT NestedModuleEntries : public ModuleEntry +{ +public: + NestedModuleEntries(const char *name = "", const char *type = "3", const char *description = ""):ModuleEntry(name,type,description) { } + friend std::ostream& operator<<(std::ostream& _os, const NestedModuleEntries &_val); + + typedef std::vector::size_type SizeType; + SizeType GetNumberOfModuleEntries() { return ModuleEntriesList.size(); } + + const ModuleEntry &GetModuleEntry(SizeType idx) const { return ModuleEntriesList[idx]; } + ModuleEntry &GetModuleEntry(SizeType idx) { return ModuleEntriesList[idx]; } + + void AddModuleEntry(const ModuleEntry &me) { ModuleEntriesList.push_back( me ); } + +private: + std::vector ModuleEntriesList; +}; +//----------------------------------------------------------------------------- +inline std::ostream& operator<<(std::ostream& _os, const NestedModuleEntries &_val) +{ + _os << "Nested:" << _val.Name << "\t" << _val.DataElementType << "\t" << _val.DescriptionField; + return _os; +} + +typedef NestedModuleEntries NestedMacroEntries; + + +} // end namespace gdcm + +#endif //GDCMNESTEDMODULEENTRIES_H diff --git a/gdcm/Source/InformationObjectDefinition/gdcmPatient.cxx b/gdcm/Source/InformationObjectDefinition/gdcmPatient.cxx new file mode 100644 index 0000000..0581c22 --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/gdcmPatient.cxx @@ -0,0 +1,17 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmPatient.h" + +namespace gdm +{} diff --git a/gdcm/Source/InformationObjectDefinition/gdcmPatient.h b/gdcm/Source/InformationObjectDefinition/gdcmPatient.h new file mode 100644 index 0000000..a01122a --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/gdcmPatient.h @@ -0,0 +1,39 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMPATIENT_H +#define GDCMPATIENT_H + +#include "gdcmTypes.h" +#include "gdcmStudy.h" + +namespace gdcm +{ +/** + * \brief + * See PS 3.3 - 2007 + * DICOM MODEL OF THE REAL-WORLD, p 54 + */ +class GDCM_EXPORT Patient +{ +public: + Patient() { + } + +private: + std::vector StudyList; +}; + +} // end namespace gdcm + +#endif //GDCMPATIENT_H diff --git a/gdcm/Source/InformationObjectDefinition/gdcmSeries.cxx b/gdcm/Source/InformationObjectDefinition/gdcmSeries.cxx new file mode 100644 index 0000000..0ed93c6 --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/gdcmSeries.cxx @@ -0,0 +1,17 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmSeries.h" + +namespace gdcm +{} diff --git a/gdcm/Source/InformationObjectDefinition/gdcmSeries.h b/gdcm/Source/InformationObjectDefinition/gdcmSeries.h new file mode 100644 index 0000000..1fdd8e1 --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/gdcmSeries.h @@ -0,0 +1,35 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMSERIES_H +#define GDCMSERIES_H + +#include "gdcmTypes.h" + +namespace gdcm +{ +/** + * \brief Series + */ +class GDCM_EXPORT Series +{ +public: + Series() { + } +private: + // Image, Waveform... +}; + +} // end namespace gdcm + +#endif //GDCMSERIES_H diff --git a/gdcm/Source/InformationObjectDefinition/gdcmStudy.cxx b/gdcm/Source/InformationObjectDefinition/gdcmStudy.cxx new file mode 100644 index 0000000..74d1f40 --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/gdcmStudy.cxx @@ -0,0 +1,17 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmStudy.h" + +namespace gdcm +{} diff --git a/gdcm/Source/InformationObjectDefinition/gdcmStudy.h b/gdcm/Source/InformationObjectDefinition/gdcmStudy.h new file mode 100644 index 0000000..d4516c2 --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/gdcmStudy.h @@ -0,0 +1,38 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMSTUDY_H +#define GDCMSTUDY_H + +#include "gdcmTypes.h" +#include "gdcmSeries.h" + +#include + +namespace gdcm +{ +/** + * \brief Study + */ +class GDCM_EXPORT Study +{ +public: + Study() { + } +private: + std::vector SeriesList; +}; + +} // end namespace gdcm + +#endif //GDCMSTUDY_H diff --git a/gdcm/Source/InformationObjectDefinition/gdcmTable.cxx b/gdcm/Source/InformationObjectDefinition/gdcmTable.cxx new file mode 100644 index 0000000..7ed52d4 --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/gdcmTable.cxx @@ -0,0 +1,19 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmTable.h" + +namespace gdcm +{ + +} // end namespace gdcm diff --git a/gdcm/Source/InformationObjectDefinition/gdcmTable.h b/gdcm/Source/InformationObjectDefinition/gdcmTable.h new file mode 100644 index 0000000..d6839af --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/gdcmTable.h @@ -0,0 +1,68 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMTABLE_H +#define GDCMTABLE_H + +#include "gdcmTableEntry.h" +#include "gdcmTag.h" + +#include + +namespace gdcm +{ + +/** + * \brief Table + */ +class Table +{ +public: + typedef std::map MapTableEntry; + Table() {} + ~Table() {} + + friend std::ostream& operator<<(std::ostream& _os, const Table &_val); + + void InsertEntry(Tag const &tag, TableEntry const &te) + { +#ifndef NDEBUG + MapTableEntry::size_type s = TableInternal.size(); +#endif + TableInternal.insert( + MapTableEntry::value_type(tag, te)); + assert( s < TableInternal.size() ); + } + + const TableEntry &GetTableEntry(const Tag &tag) const + { + MapTableEntry::const_iterator it = + TableInternal.find(tag); + if (it == TableInternal.end()) + { + assert( 0 && "Impossible" ); + return GetTableEntry(Tag(0,0)); + } + return it->second; + } + +private: + Table &operator=(const Table &_val); // purposely not implemented + Table(const Table&_val); // purposely not implemented + + MapTableEntry TableInternal; +}; + +} // end namespace gdcm + +#endif //GDCMTABLE_H diff --git a/gdcm/Source/InformationObjectDefinition/gdcmTableEntry.h b/gdcm/Source/InformationObjectDefinition/gdcmTableEntry.h new file mode 100644 index 0000000..7347da9 --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/gdcmTableEntry.h @@ -0,0 +1,43 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMTABLEENTRY_H +#define GDCMTABLEENTRY_H + +#include "gdcmType.h" + +#include + +namespace gdcm +{ + +/** + * \brief TableEntry + */ +class TableEntry +{ +public: + TableEntry(const char *attribute = 0, + Type const &type = Type(), const char * des = 0 ) : + Attribute(attribute ? attribute : ""),TypeField(type),Description(des ? des : "") {} + ~TableEntry() {} + +private: + std::string Attribute; + Type TypeField; + std::string Description; +}; + +} // end namespace gdcm + +#endif //GDCMTABLEENTRY_H diff --git a/gdcm/Source/InformationObjectDefinition/gdcmTableReader.cxx b/gdcm/Source/InformationObjectDefinition/gdcmTableReader.cxx new file mode 100644 index 0000000..fdf64a1 --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/gdcmTableReader.cxx @@ -0,0 +1,574 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmTableReader.h" +#include "gdcmTable.h" + +#include +#include +#include "gdcm_expat.h" + +#include // for stderr +#include + +namespace gdcm +{ +#if 1 +#ifdef XML_LARGE_SIZE +#if defined(XML_USE_MSC_EXTENSIONS) && _MSC_VER < 1400 +#define XML_FMT_INT_MOD "I64" +#else +#define XML_FMT_INT_MOD "ll" +#endif +#else +#define XML_FMT_INT_MOD "l" +#endif +#else +#define XML_FMT_INT_MOD "" +#endif + +#ifndef BUFSIZ +#define BUFSIZ 4096 +#endif + +static void XMLCALL startElement(void *userData, const char *name, const char **atts) +{ + TableReader *tr = reinterpret_cast(userData); + tr->StartElement(name, atts); +} + +static void XMLCALL endElement(void *userData, const char *name) +{ + TableReader *tr = reinterpret_cast(userData); + tr->EndElement(name); +} + +static void XMLCALL characterDataHandler(void* userData, const char* data, + int length) +{ + TableReader *tr = reinterpret_cast(userData); + tr->CharacterDataHandler(data,length); +} + +void TableReader::HandleMacroEntryDescription(const char **atts) +{ + (void)atts; + assert( ParsingMacroEntryDescription == false ); + ParsingMacroEntryDescription = true; + assert( *atts == NULL ); + assert( Description == "" ); +} + +void TableReader::HandleModuleInclude(const char **atts) +{ + const char *ref = *atts; + assert( strcmp(ref, "ref") == 0 ); + (void)ref; //removing warning + const char *include = *(atts+1); + CurrentModule.AddMacro( include ); + //assert( *(atts+2) == 0 ); // description ? +} + +void TableReader::HandleModuleEntryDescription(const char **atts) +{ + (void)atts; + assert( ParsingModuleEntryDescription == false ); + ParsingModuleEntryDescription = true; + assert( *atts == NULL ); + assert( Description == "" ); +} + +void TableReader::HandleMacroEntry(const char **atts) +{ + std::string strgrp = "group"; + std::string strelt = "element"; + std::string strname = "name"; + std::string strtype = "type"; + Tag &tag = CurrentTag; + MacroEntry &moduleentry = CurrentMacroEntry; + const char **current = atts; + while(*current /*&& current+1*/) + { + if( strgrp == *current ) + { + unsigned int v; + const char *raw = *(current+1); + int r = sscanf(raw, "%04x", &v); + assert( r == 1 ); + assert( v <= 0xFFFF ); + (void)r; //removing warning + tag.SetGroup( (uint16_t)v ); + } + else if( strelt == *current ) + { + unsigned int v; + const char *raw = *(current+1); + int r = sscanf(raw, "%04x", &v); + assert( r == 1 ); + assert( v <= 0xFFFF ); + (void)r; //removing warning + tag.SetElement( (uint16_t)v ); + } + else if( strname == *current ) + { + const char *raw = *(current+1); + moduleentry.SetName( raw ); + } + else if( strtype == *current ) + { + const char *raw = *(current+1); + moduleentry.SetType( Type::GetTypeType(raw) ); + } + else + { + assert(0); + } + ++current; + ++current; + } +} + +void TableReader::HandleModuleEntry(const char **atts) +{ + std::string strgrp = "group"; + std::string strelt = "element"; + std::string strname = "name"; + std::string strtype = "type"; + Tag &tag = CurrentTag; + ModuleEntry &moduleentry = CurrentModuleEntry; + const char **current = atts; + while(*current /*&& current+1*/) + { + if( strgrp == *current ) + { + unsigned int v; + const char *raw = *(current+1); + int r = sscanf(raw, "%04x", &v); + assert( r == 1 ); + assert( v <= 0xFFFF ); + (void)r; //removing warning + tag.SetGroup( (uint16_t)v ); + } + else if( strelt == *current ) + { + unsigned int v; + const char *raw = *(current+1); + int r = sscanf(raw, "%04x", &v); + assert( r == 1 ); + assert( v <= 0xFFFF ); + (void)r; //removing warning + tag.SetElement( (uint16_t)v ); + } + else if( strname == *current ) + { + const char *raw = *(current+1); + moduleentry.SetName( raw ); + } + else if( strtype == *current ) + { + const char *raw = *(current+1); + moduleentry.SetType( Type::GetTypeType(raw) ); + } + else + { + assert(0); + } + ++current; + ++current; + } +} + +void TableReader::HandleIODEntry(const char **atts) +{ + std::string strie = "ie"; + std::string strname = "name"; + std::string strref = "ref"; + std::string strusage = "usage"; + // + std::string strdesc = "description"; + IODEntry &iodentry = CurrentIODEntry; + const char **current = atts; + while(*current /*&& current+1*/) + { + const char *raw = *(current+1); + if( strie == *current ) + { + iodentry.SetIE( raw ); + } + else if( strname == *current ) + { + iodentry.SetName( raw ); + } + else if( strref == *current ) + { + iodentry.SetRef( raw ); + } + else if( strusage == *current ) + { + iodentry.SetUsage( raw ); + } + else if( strdesc == *current ) + { + //iodentry.SetDescription( raw ); + } + else + { + assert(0); + } + ++current; + ++current; + } +} + +void TableReader::HandleIOD(const char **atts) +{ + HandleModule(atts); +} + +void TableReader::HandleMacro(const char **atts) +{ + HandleModule(atts); +} + +void TableReader::HandleModule(const char **atts) +{ + std::string strref = "ref"; + std::string strname = "name"; + std::string strtable = "table"; + const char **current = atts; + while(*current /*&& current+1*/) + { + if( strref == *current ) + { + CurrentModuleRef = *(current+1); + } + else if( strtable == *current ) + { + // ref to table is needed for referencing Macro + CurrentMacroRef = *(current+1); + } + else if( strname == *current ) + { + CurrentModuleName = *(current+1); + } + else + { + assert(0); + } + ++current; + ++current; + } +} + +void TableReader::StartElement(const char *name, const char **atts) +{ + //int i; + //int *depthPtr = (int *)userData; +// for (i = 0; i < *depthPtr; i++) +// putchar('\t'); + //std::cout << name << /*" : " << atts[0] << "=" << atts[1] <<*/ std::endl; + if( strcmp(name, "tables" ) == 0 ) + { + //*depthPtr += 1; + } + else if( strcmp(name, "macro" ) == 0 ) + { + ParsingMacro = true; + HandleMacro(atts); + } + else if( strcmp(name, "module" ) == 0 ) + { + //std::cout << "Start Module" << std::endl; + ParsingModule = true; + HandleModule(atts); + } + else if( strcmp(name, "iod" ) == 0 ) + { + ParsingIOD = true; + HandleIOD(atts); + } + else if( strcmp(name, "entry" ) == 0 ) + { + if( ParsingModule ) + { + ParsingModuleEntry = true; + HandleModuleEntry(atts); + } + else if( ParsingMacro ) + { + ParsingMacroEntry = true; + HandleMacroEntry(atts); + } + else if( ParsingIOD ) + { + ParsingIODEntry = true; + HandleIODEntry(atts); + } + } + else if( strcmp(name, "description" ) == 0 ) + { + if( ParsingModuleEntry ) + { + HandleModuleEntryDescription(atts); + } + else if( ParsingMacroEntry ) + { + HandleMacroEntryDescription(atts); + } + else /*if( ParsingIODoEntry )*/ + { + assert(0); + } + } + else if( strcmp(name, "section" ) == 0 ) + { + // TODO ! + } + else if( strcmp(name, "include" ) == 0 ) + { + // TODO ! + HandleModuleInclude(atts); + } + else if ( strcmp(name,"standard-sop-classes") == 0 ) + { + // TODO ! + } + else if ( strcmp(name,"mapping") == 0 ) + { + // TODO ! + } + else if ( strcmp(name,"unrecognized-rows") == 0 ) + { + // TODO ! + } + else if ( strcmp(name,"retired-defined-terms") == 0 ) + { + // TODO ! + } + else if ( strcmp(name,"enumerated-values") == 0 ) + { + // TODO ! + } + else if ( strcmp(name,"defined-terms") == 0 ) + { + // TODO ! + } + else if ( strcmp(name,"term") == 0 ) + { + // TODO ! + } + else if ( strcmp(name,"sop-classes") == 0 ) + { + // TODO ! + } + else if ( strcmp(name,"standard-and-related-general-sop-classes") == 0 ) + { + // TODO ! + } + else if ( strcmp(name,"media-storage-standard-sop-classes") == 0 ) + { + // TODO ! + } + else + { + assert(0); + } +} + +void TableReader::EndElement(const char *name) +{ +// int *depthPtr = (int *)userData; +// *depthPtr -= 1; + if( strcmp(name, "tables" ) == 0 ) + { + } + else if( strcmp(name, "macro" ) == 0 ) + { + //std::cout << "Start Macro" << std::endl; + CurrentMacro.SetName( CurrentModuleName.c_str() ); + CurrentDefs.GetMacros().AddMacro( CurrentMacroRef.c_str(), CurrentMacro); + CurrentMacroRef.clear(); + CurrentModuleName.clear(); + CurrentMacro.Clear(); + ParsingMacro = false; + } + else if( strcmp( "module", name) == 0 ) + { + CurrentModule.SetName( CurrentModuleName.c_str() ); + CurrentDefs.GetModules().AddModule( CurrentModuleRef.c_str(), CurrentModule); + //std::cout << "End Module: " << CurrentModuleRef << "," << CurrentModuleName << std::endl; + CurrentModuleRef.clear(); + CurrentModuleName.clear(); + CurrentModule.Clear(); + ParsingModule = false; + } + else if( strcmp(name, "iod" ) == 0 ) + { + CurrentDefs.GetIODs().AddIOD( CurrentModuleName.c_str(), CurrentIOD); + CurrentModuleName.clear(); + CurrentIOD.Clear(); + ParsingIOD = false; + } + else if( strcmp(name, "entry" ) == 0 ) + { + if( ParsingModule ) + { + ParsingModuleEntry = false; + CurrentModule.AddModuleEntry( CurrentTag, CurrentModuleEntry); + } + else if( ParsingMacro ) + { + ParsingMacroEntry = false; + CurrentMacro.AddMacroEntry( CurrentTag, CurrentMacroEntry); + } + else if( ParsingIOD ) + { + ParsingIODEntry = false; + CurrentIOD.AddIODEntry( CurrentIODEntry); + } + } + else if( strcmp(name, "description" ) == 0 ) + { + if( ParsingModuleEntry ) + { + ParsingModuleEntryDescription = false; + CurrentModuleEntry.SetDescription( Description.c_str() ); + Description = ""; + } + else if( ParsingMacroEntry ) + { + ParsingMacroEntryDescription = false; + //assert( !Description.empty() ); + CurrentMacroEntry.SetDescription( Description.c_str() ); + Description = ""; + } + else + { + assert(0); + } + } + else if( strcmp(name, "mapping" ) == 0 ) + { + // TODO ! + } + else if( strcmp(name, "standard-sop-classes" ) == 0 ) + { + // TODO ! + } + else if ( strcmp(name,"standard-and-related-general-sop-classes") == 0 ) + { + // TODO ! + } + else if ( strcmp(name,"media-storage-standard-sop-classes") == 0 ) + { + // TODO ! + } + else if( strcmp(name, "section" ) == 0 ) + { + // TODO ! + } + else if( strcmp(name, "unrecognized-rows" ) == 0 ) + { + // TODO ! + } + else if( strcmp(name, "retired-defined-terms" ) == 0 ) + { + // TODO ! + } + else if( strcmp(name, "enumerated-values" ) == 0 ) + { + // TODO ! + } + else if( strcmp(name, "defined-terms" ) == 0 ) + { + // TODO ! + } + else if( strcmp(name, "term" ) == 0 ) + { + // TODO ! + } + else if( strcmp(name, "sop-classes" ) == 0 ) + { + // TODO ! + } + else if( strcmp(name, "include" ) == 0 ) + { + if( ParsingModule ) + { + } + else if( ParsingMacro ) + { + //abort(); + } + else + { + assert(0); + } + } + else + { + assert(0); + } +} + +void TableReader::CharacterDataHandler(const char *data, int length) +{ + if( ParsingModuleEntryDescription ) + { + std::string name( data, length); + assert( (unsigned int)length == strlen( name.c_str() ) ); + Description.append( name ); + } + else if( ParsingMacroEntryDescription ) + { + std::string name( data, length); + assert( (unsigned int)length == strlen( name.c_str() ) ); + Description.append( name ); + } + else + { + //assert(0); + } +} + +int TableReader::Read() +{ + std::ifstream is( Filename.c_str(), std::ios::binary ); + + char buf[BUFSIZ]; + XML_Parser parser = XML_ParserCreate(NULL); + int done; + //int depth = 0; + XML_SetUserData(parser, this); + XML_SetElementHandler(parser, startElement, endElement); + XML_SetCharacterDataHandler(parser, characterDataHandler); + int ret = 0; + do { + is.read(buf, sizeof(buf)); + std::streamsize len = is.gcount(); + done = (unsigned int)len < sizeof(buf); + if (XML_Parse(parser, buf, (int)len, done) == XML_STATUS_ERROR) { + fprintf(stderr, + "%s at line %" XML_FMT_INT_MOD "u\n", + XML_ErrorString(XML_GetErrorCode(parser)), + XML_GetCurrentLineNumber(parser)); + ret = 1; // Mark as error + done = 1; // exit while + } + } while (!done); + XML_ParserFree(parser); + is.close(); + return ret; +} + +} // end namespace gdcm diff --git a/gdcm/Source/InformationObjectDefinition/gdcmTableReader.h b/gdcm/Source/InformationObjectDefinition/gdcmTableReader.h new file mode 100644 index 0000000..4af6add --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/gdcmTableReader.h @@ -0,0 +1,103 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMTABLEREADER_H +#define GDCMTABLEREADER_H + +#include "gdcmTypes.h" +#include "gdcmDefs.h" +//#include "gdcmModule.h" +//#include "gdcmIOD.h" +//#include "gdcmIODs.h" +//#include "gdcmModules.h" + +#include +#include +#include + +namespace gdcm +{ +/** + * \brief Class for representing a TableReader + * \note This class is an empty shell meant to be derived + */ +class GDCM_EXPORT TableReader +{ +public: + TableReader(Defs &defs):CurrentDefs(defs),ParsingModule(false),ParsingModuleEntry(false), + ParsingModuleEntryDescription(false), + ParsingMacro(false), + ParsingMacroEntry(false), + ParsingMacroEntryDescription(false), + ParsingIOD(false), + ParsingIODEntry(false), + Description() {} + virtual ~TableReader() {} + + // Set/Get filename + void SetFilename(const char *filename) { Filename = filename; } + const char *GetFilename() { return Filename.c_str(); } + + int Read(); + +//protected: + // You need to override those function in your subclasses: + virtual void StartElement(const char *name, const char **atts); + virtual void EndElement(const char *name); + virtual void CharacterDataHandler(const char *data, int length); + +void HandleModuleEntry(const char **atts); +void HandleModule(const char **atts); +void HandleModuleEntryDescription(const char **atts); +void HandleMacroEntry(const char **atts); +void HandleMacro(const char **atts); +void HandleMacroEntryDescription(const char **atts); +void HandleModuleInclude(const char **atts); +void HandleIODEntry(const char **atts); +void HandleIOD(const char **atts); + + //const Modules & GetModules() const { return CurrentModules; } + //const Macros & GetMacros() const { return CurrentMacros; } + //const IODs & GetIODs() const { return CurrentIODs; } + const Defs & GetDefs() const { return CurrentDefs; } + +private: + std::string Filename; + Defs &CurrentDefs; + //Macros CurrentMacros; + //Modules CurrentModules; + //IODs CurrentIODs; + Macro CurrentMacro; + Module CurrentModule; + IOD CurrentIOD; + MacroEntry CurrentMacroEntry; + ModuleEntry CurrentModuleEntry; + IODEntry CurrentIODEntry; + std::string CurrentModuleName; + std::string CurrentModuleRef; + std::string CurrentMacroRef; + bool ParsingModule; + bool ParsingModuleEntry; + bool ParsingModuleEntryDescription; + bool ParsingMacro; + bool ParsingMacroEntry; + bool ParsingMacroEntryDescription; + bool ParsingIOD; + bool ParsingIODEntry; + Tag CurrentTag; + std::string Description; +}; + +} // end namespace gdcm + +#endif //GDCMTABLEREADER_H diff --git a/gdcm/Source/InformationObjectDefinition/gdcmTables.h.in b/gdcm/Source/InformationObjectDefinition/gdcmTables.h.in new file mode 100644 index 0000000..75daff0 --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/gdcmTables.h.in @@ -0,0 +1,19 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMTABLES_H +#define GDCMTABLES_H +const char * const gdcmTables[] = { + @GDCM_XML_TABLES@ + 0 }; +#endif // GDCMTABLES_H diff --git a/gdcm/Source/InformationObjectDefinition/gdcmType.cxx b/gdcm/Source/InformationObjectDefinition/gdcmType.cxx new file mode 100644 index 0000000..e7bc47d --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/gdcmType.cxx @@ -0,0 +1,47 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmType.h" +#include + +namespace gdcm +{ + +static const char *TypeStrings[] = { + "1", + "1C", + "2", + "2C", + "3", + "UNKNOWN", + 0 +}; + +const char *Type::GetTypeString(TypeType type) +{ + return TypeStrings[type]; +} + +Type::TypeType Type::GetTypeType(const char *type) +{ + int i = 0; + while(TypeStrings[i] != 0) + { + if( strcmp(type, TypeStrings[i]) == 0 ) + return (TypeType)i; + ++i; + } + return UNKNOWN; +} + +} // end namespace gdcm diff --git a/gdcm/Source/InformationObjectDefinition/gdcmType.h b/gdcm/Source/InformationObjectDefinition/gdcmType.h new file mode 100644 index 0000000..9affd64 --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/gdcmType.h @@ -0,0 +1,73 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#ifndef GDCMTYPE_H +#define GDCMTYPE_H + +#include "gdcmTypes.h" + +#include + +namespace gdcm +{ + +/** + * \brief Type + * \note + * PS 3.5 + * 7.4 DATA ELEMENT TYPE + * 7.4.1 TYPE 1 REQUIRED DATA ELEMENTS + * 7.4.2 TYPE 1C CONDITIONAL DATA ELEMENTS + * 7.4.3 TYPE 2 REQUIRED DATA ELEMENTS + * 7.4.4 TYPE 2C CONDITIONAL DATA ELEMENTS + * 7.4.5 TYPE 3 OPTIONAL DATA ELEMENTS + * + * The intent of Type 2 Data Elements is to allow a zero length to be conveyed + * when the operator or application does not know its value or has a specific + * reason for not specifying its value. It is the intent that the device should + * support these Data Elements. + */ +class GDCM_EXPORT Type +{ +public: + typedef enum { + T1 = 0, + T1C, + T2, + T2C, + T3, + UNKNOWN + } TypeType; + + Type(TypeType type = UNKNOWN) : TypeField(type) { } + + operator TypeType () const { return TypeField; } + friend std::ostream &operator<<(std::ostream &os, const Type &vr); + + static const char *GetTypeString(TypeType type); + static TypeType GetTypeType(const char *type); + +private: + TypeType TypeField; +}; +//----------------------------------------------------------------------------- +inline std::ostream &operator<<(std::ostream &_os, const Type &val) +{ + _os << Type::GetTypeString(val.TypeField); + return _os; +} + +} // end namespace gdcm + +#endif //GDCMTYPE_H diff --git a/gdcm/Source/InformationObjectDefinition/gdcmUsage.cxx b/gdcm/Source/InformationObjectDefinition/gdcmUsage.cxx new file mode 100644 index 0000000..8fb7f61 --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/gdcmUsage.cxx @@ -0,0 +1,44 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmUsage.h" +#include + +namespace gdcm +{ + +static const char *UsageStrings[] = { + "Mandatory", // (see A.1.3.1) , abbreviated M + "Conditional", // (see A.1.3.2) , abbreviated C + "UserOption", // (see A.1.3.3) , abbreviated U + NULL +}; + +const char *Usage::GetUsageString(UsageType type) +{ + return UsageStrings[type]; +} + +Usage::UsageType Usage::GetUsageType(const char *type) +{ + int i = 0; + while(UsageStrings[i] != 0) + { + if( strcmp(type, UsageStrings[i]) == 0 ) + return (UsageType)i; + ++i; + } + return Invalid; +} + +} // end namespace gdcm diff --git a/gdcm/Source/InformationObjectDefinition/gdcmUsage.h b/gdcm/Source/InformationObjectDefinition/gdcmUsage.h new file mode 100644 index 0000000..1c972a1 --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/gdcmUsage.h @@ -0,0 +1,78 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMUSAGE_H +#define GDCMUSAGE_H + +#include "gdcmTypes.h" + +#include + +namespace gdcm +{ + +/** + * \brief Usage + * \note +A.1.3 IOD Module Table and Functional Group Macro Table +This Section of each IOD defines in a tabular form the Modules comprising the IOD. The following +information must be specified for each Module in the table: +- The name of the Module or Functional Group +- A reference to the Section in Annex C which defines the Module or Functional Group +- The usage of the Module or Functional Group; whether it is: +- Mandatory (see A.1.3.1) , abbreviated M +- Conditional (see A.1.3.2) , abbreviated C +- User Option (see A.1.3.3) , abbreviated U +The Modules referenced are defined in Annex C. +A.1.3.1 MANDATORY MODULES +For each IOD, Mandatory Modules shall be supported per the definitions, semantics and requirements +defined in Annex C. + +A.1.3.2 CONDITIONAL MODULES +Conditional Modules are Mandatory Modules if specific conditions are met. If the specified conditions are +not met, this Module shall not be supported; that is, no information defined in that Module shall be sent. +A.1.3.3 USER OPTION MODULES +User Option Modules may or may not be supported. If an optional Module is supported, the Attribute +Types specified in the Modules in Annex C shall be supported. + */ +class GDCM_EXPORT Usage +{ +public: + typedef enum { + Mandatory, // (see A.1.3.1) , abbreviated M + Conditional, // (see A.1.3.2) , abbreviated C + UserOption, // (see A.1.3.3) , abbreviated U + Invalid + } UsageType; + + Usage(UsageType type = Invalid) : UsageField(type) { } + + operator UsageType () const { return UsageField; } + friend std::ostream &operator<<(std::ostream &os, const Usage &vr); + + static const char *GetUsageString(UsageType type); + static UsageType GetUsageType(const char *type); + +private: + UsageType UsageField; +}; +//----------------------------------------------------------------------------- +inline std::ostream &operator<<(std::ostream &_os, const Usage &val) +{ + _os << Usage::GetUsageString(val.UsageField); + return _os; +} + +} // end namespace gdcm + +#endif //GDCMUSAGE_H diff --git a/gdcm/Source/InformationObjectDefinition/gdcmXMLDictReader.cxx b/gdcm/Source/InformationObjectDefinition/gdcmXMLDictReader.cxx new file mode 100644 index 0000000..4cd18db --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/gdcmXMLDictReader.cxx @@ -0,0 +1,232 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmXMLDictReader.h" +#include "gdcmDict.h" + +#include +#include // abort + +namespace gdcm +{ + +XMLDictReader::XMLDictReader():ParsingDescription(false),Description() +{ +} + +void XMLDictReader::HandleEntry(const char **atts) +{ + assert( !ParsingDescription ); + VR vr; + VM vm; + assert( vm == VM::VM0 ); + std::string name; + bool ret; + + Tag &tag = CurrentTag; + DictEntry &de = CurrentDE; + + int i = 0; + const char **current = atts; + // Supported attributes: + std::string group = "group"; + std::string element = "element"; + std::string strvr = "vr"; + std::string strvm = "vm"; + std::string retired = "retired"; + std::string retiredtrue = "true"; + std::string retiredfalse = "false"; + std::string version = "version"; + std::string strname = "name"; + + while(*current /*&& current+1*/) + { + assert( *(current + 1) ); + if( group == *current ) + { + unsigned int v; + const char *raw = *(current+1); + int r = sscanf(raw, "%04x", &v); + assert( r == 1 ); + assert( v <= 0xFFFF ); + + char sv[4+1]; + r = sprintf(sv, "%04x", v); + assert( r == 4 ); + if( strncmp(raw, sv, 4) == 0 ) // GroupXX + { + tag.SetGroup( v ); + } + else + { + assert( (raw[0] == '5' && raw[1] == '0') || (raw[0] == '6' && raw[1] == '0') ); + if( raw[0] == '5' ) tag.SetGroup( 0x5000 ); + if( raw[0] == '6' ) tag.SetGroup( 0x6000 ); + CurrentDE.SetGroupXX( true ); + } + } + else if( element == *current ) + { + unsigned int v; + const char *raw = *(current+1); + int r = sscanf(raw, "%04x", &v); + assert( r == 1 ); + assert( v <= 0xFFFF ); + + char sv[4+1]; + r = sprintf(sv, "%04x", v); + assert( r == 4 ); + if( strncmp(raw, sv, 4) == 0 ) + { + tag.SetElement( v ); + } + else + { + assert( raw[0] == '3' && raw[1] == '1' ); + tag.SetElement( 0x3100 ); + CurrentDE.SetElementXX( true ); + } + } + else if( strvr == *current ) + { + vr = VR::GetVRTypeFromFile( *(current + 1) ); + //assert( vr != VR::INVALID ); + } + else if( strvm == *current ) + { + vm = VM::GetVMType( *(current + 1) ); + //assert( *(current+1) != '\0' ); + //assert( vm != VM::VM0 ); + //assert( vm != VM::VM_END ); + } + else if( retired == *current ) + { + if( retiredtrue == *(current+1) ) + { + ret = true; + } + else if( retiredfalse == *(current+1) ) + { + ret = false; + } + else + { + assert(0); + } + } + else if( version == *current ) + { + // ?? + } + else if( strname == *current ) + { + name = *(current+1); + } + else + { + assert(0); + } + // goes on to the next attribute (need to skip value) + ++current; + ++current; + } + // Done ! + de = DictEntry(name.c_str(), vr, vm, ret ); +} + +void XMLDictReader::HandleDescription(const char **atts) +{ + assert( ParsingDescription ); + assert( *atts == NULL ); + assert( Description == "" ); +#if 0 + DictEntry &de = CurrentDE; + + const char **current = atts; + std::string description; + while(*current /*&& current+1*/) + { + assert( *(current + 1) ); + ++current; + } + // Done ! + //de.SetName( description.c_str() ); +#endif +} + +void XMLDictReader::StartElement(const char *name, const char **atts) +{ + std::string dict = "dict"; + std::string entry = "entry"; + std::string description = "description"; // aka name + Tag currenttag; + //DictEntry currentde("",VR::INVALID,VM::VM0,true); + if( dict == name ) + { + // dict ?? + } + else if( entry == name ) + { + HandleEntry(atts); + } + else if( description == name ) + { + ParsingDescription = true; // mark that we are processing description element + // We need a second pass to fill in the currentde struct: + HandleDescription(atts); + } + else + { + std::cerr << name << std::endl; + assert(0); + } +} + +void XMLDictReader::EndElement(const char *name) +{ + std::string entry = "entry"; + std::string dict = "dict"; + std::string description = "description"; // free form text usually the raw description of tag + if( entry == name ) + { + // Ok currentde is now valid let's insert it into the Dict: + DICOMDict.AddDictEntry( CurrentTag, CurrentDE); + } + else if( description == name ) + { + assert( ParsingDescription ); + ParsingDescription = false; + + // TODO: do something with description ?? + Description = ""; + } + else if ( dict == name ) + { + } + else + { + assert(0); + } +} + +void XMLDictReader::CharacterDataHandler(const char *data, int length) +{ + if( ParsingDescription ) + { + std::string name( data, length); + assert( length == strlen( name.c_str() ) ); + Description.append( name ); + } +} + +} diff --git a/gdcm/Source/InformationObjectDefinition/gdcmXMLDictReader.h b/gdcm/Source/InformationObjectDefinition/gdcmXMLDictReader.h new file mode 100644 index 0000000..b41e0de --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/gdcmXMLDictReader.h @@ -0,0 +1,55 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMXMLDICTREADER_H +#define GDCMXMLDICTREADER_H + +#include "gdcmTableReader.h" +#include "gdcmDict.h" +#include "gdcmDictEntry.h" +#include "gdcmTag.h" + +namespace gdcm +{ +/** + * \brief Class for representing a XMLDictReader + * \note bla + * Will read the DICOMV3.xml file + */ +class GDCM_EXPORT XMLDictReader : public TableReader +{ +public: + XMLDictReader(); + ~XMLDictReader() {} + + void StartElement(const char *name, const char **atts); + void EndElement(const char *name); + void CharacterDataHandler(const char *data, int length); + + const Dict & GetDict() { return DICOMDict; } + +protected: + void HandleEntry(const char **atts); + void HandleDescription(const char **atts); + +private: + Dict DICOMDict; + Tag CurrentTag; + DictEntry CurrentDE; + bool ParsingDescription; + std::string Description; +}; + +} // end namespace gdcm + +#endif //GDCMXMLDICTREADER_H diff --git a/gdcm/Source/InformationObjectDefinition/gdcmXMLPrivateDictReader.cxx b/gdcm/Source/InformationObjectDefinition/gdcmXMLPrivateDictReader.cxx new file mode 100644 index 0000000..2f249ff --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/gdcmXMLPrivateDictReader.cxx @@ -0,0 +1,263 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmXMLPrivateDictReader.h" +#include "gdcmDict.h" + +#include +#include // abort + +namespace gdcm +{ + +XMLPrivateDictReader::XMLPrivateDictReader():ParsingDescription(false),Description() +{ +} + +void XMLPrivateDictReader::HandleEntry(const char **atts) +{ + assert( !ParsingDescription ); + std::string name; + std::string owner; + VR vr; + VM::VMType vm = VM::VM0; + bool ret = false; + + PrivateTag &tag = CurrentTag; + DictEntry &de = CurrentDE; + + int i = 0; + const char **current = atts; + // Supported attributes: + std::string group = "group"; + std::string element = "element"; + std::string strvr = "vr"; + std::string strvm = "vm"; + std::string retired = "retired"; + std::string retiredtrue = "true"; + std::string retiredfalse = "false"; + std::string version = "version"; + std::string strowner = "owner"; + std::string strname = "name"; + + while(*current /*&& current+1*/) + { + assert( *(current + 1) ); + if( group == *current ) + { + unsigned int v; + const char *raw = *(current+1); + int r = sscanf(raw, "%04x", &v); + assert( r == 1 ); + assert( v <= 0xFFFF ); + + char sv[4+1]; + r = sprintf(sv, "%04x", v); + assert( r == 4 ); + if( strncmp(raw, sv, 4) == 0 ) // GroupXX + { + tag.SetGroup( v ); + } + else + { + assert( (raw[0] == '5' && raw[1] == '0') || (raw[0] == '6' && raw[1] == '0') || + (raw[0] == '7' && raw[1] == '0') ); + if( raw[0] == '5' ) tag.SetGroup( 0x5000 ); + else if( raw[0] == '6' ) tag.SetGroup( 0x6000 ); + else if( raw[0] == '7' ) tag.SetGroup( 0x7000 ); + else assert(0); + CurrentDE.SetGroupXX( true ); + } + } + else if( element == *current ) + { + const char *raw = *(current+1); + assert( (raw[0] == 'x' && raw[1] == 'x' ) + || (raw[2] == 'x' && raw[3] == 'x') ); + if (raw[2] == 'x' && raw[3] == 'x') + { + if( raw[0] == '0' && raw[1] == '0' ) + { + tag.SetElement( 0x0000 ); + CurrentDE.SetElementXX( true ); + } + else if( raw[0] == '1' && raw[1] == '0' ) + { + tag.SetElement( 0x1000 ); + CurrentDE.SetElementXX( true ); + } + else + { + assert(0); // FIXME + } + } + else + { + unsigned int v; + int r = sscanf(raw+2, "%02x", &v); + assert( r == 1 ); + assert( v <= 0xFF ); + + char sv[4+1]; + r = sprintf(sv, "xx%02x", v); + assert( r == 4 ); + if( strncmp(raw, sv, 4) == 0 ) + { + tag.SetElement( v ); + } + else + { + assert(0); + } + } + } + else if( strvr == *current ) + { + vr = VR::GetVRTypeFromFile( *(current + 1) ); + //assert( vr != VR::INVALID ); + } + else if( strvm == *current ) + { + vm = VM::GetVMType( *(current + 1) ); + //assert( *(current+1) != '\0' ); + //assert( vm != VM::VM0 ); + //assert( vm != VM::VM_END ); + } + else if( retired == *current ) + { + if( retiredtrue == *(current+1) ) + { + ret = true; + } + else if( retiredfalse == *(current+1) ) + { + ret = false; + } + else + { + assert(0); + } + } + else if( version == *current ) + { + // ?? + } + else if( strowner == *current ) + { + owner = *(current+1); + } + else if( strname == *current ) + { + name = *(current+1); + } + else + { + assert(0); + } + // goes on to the next attribute (need to skip value) + ++current; + ++current; + } + // Done ! + de = DictEntry(name.c_str(), vr, vm, ret ); + tag.SetOwner( owner.c_str() ); +} + +void XMLPrivateDictReader::HandleDescription(const char **atts) +{ + assert( ParsingDescription ); + assert( *atts == NULL ); + assert( Description == "" ); +#if 0 + DictEntry &de = CurrentDE; + + const char **current = atts; + std::string description; + while(*current /*&& current+1*/) + { + assert( *(current + 1) ); + ++current; + } + // Done ! + //de.SetName( description.c_str() ); +#endif +} + +void XMLPrivateDictReader::StartElement(const char *name, const char **atts) +{ + std::string dict = "dict"; + std::string entry = "entry"; + std::string description = "description"; // aka name + Tag currenttag; + //DictEntry currentde("",VR::INVALID,VM::VM0,true); + if( dict == name ) + { + // dict ?? + } + else if( entry == name ) + { + HandleEntry(atts); + } + else if( description == name ) + { + ParsingDescription = true; // mark that we are processing description element + // We need a second pass to fill in the currentde struct: + HandleDescription(atts); + } + else + { + std::cerr << name << std::endl; + assert(0); + } +} + +void XMLPrivateDictReader::EndElement(const char *name) +{ + std::string entry = "entry"; + std::string dict = "dict"; + std::string description = "description"; // free form text usually the raw description of tag + if( entry == name ) + { + // Ok currentde is now valid let's insert it into the Dict: + PDict.AddDictEntry( CurrentTag, CurrentDE); + } + else if( description == name ) + { + assert( ParsingDescription ); + ParsingDescription = false; + + // TODO: do something with description ?? + // + // Invalidate Description ? + Description = ""; + } + else if ( dict == name ) + { + } + else + { + assert(0); + } +} + +void XMLPrivateDictReader::CharacterDataHandler(const char *data, int length) +{ + if( ParsingDescription ) + { + std::string name( data, length); + assert( length == strlen( name.c_str() ) ); + Description.append( name ); + } +} + +} diff --git a/gdcm/Source/InformationObjectDefinition/gdcmXMLPrivateDictReader.h b/gdcm/Source/InformationObjectDefinition/gdcmXMLPrivateDictReader.h new file mode 100644 index 0000000..3fd1c4b --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/gdcmXMLPrivateDictReader.h @@ -0,0 +1,55 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMXMLPRIVATEDICTREADER_H +#define GDCMXMLPRIVATEDICTREADER_H + +#include "gdcmTableReader.h" +#include "gdcmDict.h" +#include "gdcmDictEntry.h" +#include "gdcmTag.h" + +namespace gdcm +{ +/** + * \brief Class for representing a XMLPrivateDictReader + * \note bla + * Will read the Private.xml file + */ +class GDCM_EXPORT XMLPrivateDictReader : public TableReader +{ +public: + XMLPrivateDictReader(); + ~XMLPrivateDictReader() {} + + void StartElement(const char *name, const char **atts); + void EndElement(const char *name); + void CharacterDataHandler(const char *data, int length); + + const PrivateDict & GetPrivateDict() { return PDict; } + +protected: + void HandleEntry(const char **atts); + void HandleDescription(const char **atts); + +private: + PrivateDict PDict; + PrivateTag CurrentTag; + DictEntry CurrentDE; + bool ParsingDescription; + std::string Description; +}; + +} // end namespace gdcm + +#endif //GDCMXMLPRIVATEDICTREADER_H diff --git a/gdcm/Source/InformationObjectDefinition/getelements.xsl b/gdcm/Source/InformationObjectDefinition/getelements.xsl new file mode 100644 index 0000000..e538107 --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/getelements.xsl @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + (,) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
TagNameTypeDescription
+
+ + +
+
diff --git a/gdcm/Source/InformationObjectDefinition/ma2html.xsl b/gdcm/Source/InformationObjectDefinition/ma2html.xsl new file mode 100644 index 0000000..df313c3 --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/ma2html.xsl @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + (,) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
TagNameTypeDescription
+
+ + +
+
diff --git a/gdcm/Source/InformationObjectDefinition/ma2pdf.xsl b/gdcm/Source/InformationObjectDefinition/ma2pdf.xsl new file mode 100644 index 0000000..c68c3e7 --- /dev/null +++ b/gdcm/Source/InformationObjectDefinition/ma2pdf.xsl @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + PS 3.3-2007 +Page + + + + + - Standard - + + + + + + + + + + + + + + + + + + + + + + + + Name + + + Tag + + + Type + + + Description + + + + + + + + + + + + + + ( + + , + + ) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdcm/Source/MediaStorageAndFileFormat/CMakeLists.txt b/gdcm/Source/MediaStorageAndFileFormat/CMakeLists.txt new file mode 100644 index 0000000..0302c91 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/CMakeLists.txt @@ -0,0 +1,224 @@ +# Define the srcs for Media Storage And FileFormat +# MSFF +set(MSFF_SRCS + gdcmFileStreamer.cxx + gdcmJSON.cxx + gdcmFileChangeTransferSyntax.cxx + gdcmAnonymizer.cxx + gdcmFileAnonymizer.cxx + gdcmIconImageFilter.cxx + gdcmIconImageGenerator.cxx + gdcmDICOMDIRGenerator.cxx + gdcmSpacing.cxx + gdcmFileExplicitFilter.cxx + gdcmFileDerivation.cxx + gdcmImageFragmentSplitter.cxx + gdcmTagPath.cxx + gdcmSimpleSubjectWatcher.cxx + gdcmAnonymizeEvent.cxx + gdcmPixmap.cxx + gdcmBitmap.cxx + gdcmRescaler.cxx + gdcmImageToImageFilter.cxx + gdcmBitmapToBitmapFilter.cxx + gdcmPixmapToPixmapFilter.cxx + gdcmImageChangeTransferSyntax.cxx + gdcmImageApplyLookupTable.cxx + gdcmOrientation.cxx + gdcmDataSetHelper.cxx + gdcmImageChangePlanarConfiguration.cxx + gdcmImageChangePhotometricInterpretation.cxx + gdcmDirectionCosines.cxx + gdcmSorter.cxx + gdcmSerieHelper.cxx + gdcmIPPSorter.cxx + gdcmApplicationEntity.cxx + gdcmDICOMDIR.cxx + gdcmSpectroscopy.cxx + gdcmEncapsulatedDocument.cxx + gdcmSplitMosaicFilter.cxx + gdcmFiducials.cxx + gdcmWaveform.cxx + gdcmPersonName.cxx + gdcmIconImage.cxx + gdcmUIDGenerator.cxx + gdcmUUIDGenerator.cxx + gdcmPrinter.cxx + gdcmDictPrinter.cxx + gdcmXMLPrinter.cxx + gdcmScanner.cxx + gdcmPixmapReader.cxx + gdcmImageReader.cxx + gdcmPixmapWriter.cxx + gdcmImageWriter.cxx + gdcmStringFilter.cxx + gdcmImageHelper.cxx + gdcmValidate.cxx + gdcmDumper.cxx + gdcmImage.cxx + gdcmImageConverter.cxx + gdcmImageCodec.cxx + gdcmJPEG12Codec.cxx + gdcmRLECodec.cxx + gdcmPDFCodec.cxx + gdcmAudioCodec.cxx + gdcmJPEG16Codec.cxx + gdcmJPEGLSCodec.cxx + gdcmJPEG8Codec.cxx + gdcmJPEGCodec.cxx + gdcmPVRGCodec.cxx + gdcmKAKADUCodec.cxx + gdcmPNMCodec.cxx + gdcmPGXCodec.cxx + gdcmRAWCodec.cxx + gdcmLookupTable.cxx + gdcmOverlay.cxx + gdcmCurve.cxx + gdcmPhotometricInterpretation.cxx + gdcmPixelFormat.cxx + gdcmSegmentedPaletteColorLookupTable.cxx + gdcmStreamImageReader.cxx + gdcmImageRegionReader.cxx + #gdcmStreamImageWriter.cxx + gdcmDirectoryHelper.cxx + gdcmSegment.cxx + gdcmSurface.cxx + gdcmMeshPrimitive.cxx + gdcmSegmentWriter.cxx + gdcmSurfaceWriter.cxx + gdcmSegmentReader.cxx + gdcmSurfaceReader.cxx + gdcmSurfaceHelper.cxx + gdcmSegmentHelper.cxx + ) +if(OPENJPEG_VERSION VERSION_LESS 2.0) + list(APPEND MSFF_SRCS + gdcmJPEG2000Codec.cxx + ) +else () + list(APPEND MSFF_SRCS + gdcmOpenJPEG2Codec.cxx + ) +endif() + +# Do the proper thing when building static...if only there was configured +# headers or def files instead +if(NOT BUILD_SHARED_LIBS) + set_source_files_properties(gdcmJPEG2000Codec.cxx + PROPERTIES + COMPILE_FLAGS -DOPJ_STATIC + ) +else() + set_source_files_properties(gdcmJPEGLSCodec.cxx + PROPERTIES + COMPILE_FLAGS -DCHARLS_SHARED + ) +endif() + + +# Add the include paths +include_directories( + "${GDCM_SOURCE_DIR}/Source/Common" + "${GDCM_BINARY_DIR}/Source/Common" + "${GDCM_SOURCE_DIR}/Source/DataStructureAndEncodingDefinition" + "${GDCM_SOURCE_DIR}/Source/DataDictionary" + "${GDCM_SOURCE_DIR}/Source/InformationObjectDefinition" + ${CMAKE_CURRENT_SOURCE_DIR} + + # FIXME: + "${GDCM_SOURCE_DIR}/Utilities" + "${GDCM_BINARY_DIR}/Utilities" + ) + +# CharLS +if(GDCM_USE_JPEGLS) + #include_directories("${GDCM_BINARY_DIR}/Utilities/gdcmcharls") +endif() + +if(GDCM_USE_SYSTEM_CHARLS) + include_directories(${CHARLS_INCLUDE_DIRS} ) +else() + include_directories( + "${GDCM_BINARY_DIR}/Utilities/gdcmcharls" + ) +endif() +if(GDCM_USE_SYSTEM_OPENJPEG) + include_directories(${OPENJPEG_INCLUDE_DIRS} ) +else() + include_directories( + "${GDCM_BINARY_DIR}/Utilities/gdcmopenjpeg" + ) +if(GDCM_USE_OPENJPEG_V2) + INCLUDE_DIRECTORIES( + "${GDCM_BINARY_DIR}/Utilities/gdcmopenjpeg-v2" + ) +endif() +endif() +if(GDCM_USE_SYSTEM_LJPEG) + #message(${LJPEG_INCLUDE_DIRS} ) + include_directories(${LJPEG_INCLUDE_DIRS} ) +endif() +if(NOT GDCM_USE_SYSTEM_ZLIB) + include_directories( + "${GDCM_BINARY_DIR}/Utilities/gdcmzlib" + ) +endif() +if(GDCM_USE_SYSTEM_UUID) + include_directories( + ${UUID_INCLUDE_DIR} + ) + set(GDCMUUID ${UUID_LIBRARIES}) +else() + include_directories( + "${GDCM_BINARY_DIR}/Utilities/gdcmuuid" # uuid_mangle.h + ) + set(GDCMUUID gdcmuuid) +endif() +if(GDCM_USE_SYSTEM_JSON) + include_directories( + ${JSON_INCLUDE_DIRS} + ) +endif() + +add_library(gdcmMSFF ${MSFF_SRCS}) +# gdcmPVRGCodec calls gdcmjpeg +if(GDCM_USE_PVRG) + if(NOT GDCM_USE_SYSTEM_PVRG) + add_dependencies(gdcmMSFF gdcmjpeg) + endif() +endif() + +# main libs: +target_link_libraries(gdcmMSFF gdcmIOD gdcmDSED gdcmDICT ${GDCM_LJPEG_LIBRARIES} ${GDCM_OPENJPEG_LIBRARIES}) +set_target_properties(gdcmMSFF PROPERTIES ${GDCM_LIBRARY_PROPERTIES} LINK_INTERFACE_LIBRARIES "gdcmDSED;gdcmDICT;gdcmIOD") +if(GDCM_USE_JPEGLS) + target_link_libraries(gdcmMSFF ${GDCM_CHARLS_LIBRARIES}) +endif() + +if(CMAKE_COMPILER_IS_GNUCXX AND MINGW) + # I am getting: +# CMakeFiles/gdcmMSFF.dir/gdcmScanner.obj(.text$_ZN4gdcm6ReaderC1Ev[gdcm::Reader::Reader()]+0x3a):gdcmScanner.cxx: variable 'vtable for gdcm::Reader' can't be auto-imported. Please read the documentation for ld's --enable-auto-import for details. +# CMakeFiles/gdcmMSFF.dir/gdcmImageReader.obj(.text$_ZN4gdcm6ReaderC2Ev[gdcm::Reader::Reader()]+0x3a):gdcmImageReader.cxx: variable 'vtable for gdcm::Reader' can't be auto-imported. Please read the documentation for ld's --enable-auto-import for details. +# CMakeFiles/gdcmMSFF.dir/gdcmImageWriter.obj(.text$_ZN4gdcm6WriterC2Ev[gdcm::Writer::Writer()]+0x3a):gdcmImageWriter.cxx: variable 'vtable for gdcm::Writer' can't be auto-imported. Please read the documentation for ld's --enable-auto-import for details. + + set_target_properties(gdcmMSFF PROPERTIES LINK_FLAGS "-Wl,--enable-runtime-pseudo-reloc") +endif() +#if(HAVE_UUIDCREATE) +if(WIN32) + # For UuidCreate + # http://msdn.microsoft.com/en-us/library/aa379205(VS.85).aspx + target_link_libraries(gdcmMSFF rpcrt4) +#endif() +else() +target_link_libraries(gdcmMSFF ${GDCMUUID}) +endif() +if(GDCM_USE_SYSTEM_JSON) +target_link_libraries(gdcmMSFF ${JSON_LIBRARIES}) +endif() + +# libs +install_library(gdcmMSFF) +# PDB +install_pdb(gdcmMSFF) +# include files +install_includes("*.h" "*.txx") diff --git a/gdcm/Source/MediaStorageAndFileFormat/FileMetaInformation.txt b/gdcm/Source/MediaStorageAndFileFormat/FileMetaInformation.txt new file mode 100644 index 0000000..77c031c --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/FileMetaInformation.txt @@ -0,0 +1,92 @@ +PS 3.10-2006 +Page 21 +Attribute Name Tag Type Attribute Description +File Preamble No Tag +or Length +Fields +1 A fixed 128 byte field available for Application Profile or +implementation specified use. If not used by an Application +Profile or a specific implementation all bytes shall be set to +00H. +File-set Readers or Updaters shall not rely on the content of +this Preamble to determine that this File is or is not a +DICOM File. +DICOM Prefix No Tag +or Length +Fields +1 Four bytes containing the character string "DICM". This +Prefix is intended to be used to recognize that this File is or +not a DICOM File. +Group Length (0002,0000) 1 Number of bytes following this File Meta Element (end of +the Value field) up to and including the last File Meta +Element of the Group 2 File Meta Information +File Meta +Information +Version +(0002,0001) 1 This is a two byte field where each bit identifies a version of +this File Meta Information header. In version 1 the first byte +value is 00H and the second value byte value is 01H. +Implementations reading Files with Meta Information where +this attribute has bit 0 (lsb) of the second byte set to 1 may +interpret the File Meta Information as specified in this +version of PS 3.10. All other bits shall not be checked. +Note: A bit field where each bit identifies a version, allows +explicit indication of the support of multiple previous +versions. Future versions of the File Meta Information +that can be read by verson 1 readers will have bit 0 of +the second byte set to 1 +Media Storage +SOP Class UID +(0002,0002) 1 Uniquely identifies the SOP Class associated with the Data +Set. SOP Class UIDs allowed for media storage are +specified in PS 3.4 of the DICOM Standard - Media Storage +Application Profiles. +Media Storage +SOP Instance UID +(0002,0003) 1 Uniquely identifies the SOP Instance associated with the +Data Set placed in the file and following the File Meta +Information. +Transfer Syntax +UID +(0002,0010) 1 Uniquely identifies the Transfer Syntax used to encode the +following Data Set. This Transfer Syntax does not apply to +the File Meta Information. +Note: It is recommended to use one of the DICOM Transfer +Syntaxes supporting explicit Value Representation +encoding to facilitate interpretation of File Meta +Element Values. JPIP Referenced Pixel Data Transfer +Syntaxes are not used. (See PS 3.5 of the DICOM +Standard). +Implementation +Class UID +(0002,0012) 1 Uniquely identifies the implementation which wrote this file +and its content. It provides an unambiguous identification +of the type of implementation which last wrote the file in the +event of interchange problems. It follows the same policies +as defined by PS 3.7 of the DICOM Standard (association +negotiation). +Implementation +Version Name +(0002,0013) 3 Identifies a version for an Implementation Class UID +(0002,0012) using up to 16 characters of the repertoire +identified in Section 8.5. It follows the same policies as +defined by PS 3.7 of the DICOM Standard (association + PS 3.10-2006 +Page 22 +negotiation). +Source Application +Entity Title +(0002,0016) 3 The DICOM Application Entity (AE) Title of the AE which +wrote this file's content (or last updated it). If used, it allows +the tracing of the source of errors in the event of media +interchange problems. The policies associated with AE +Titles are the same as those defined in PS 3.8 of the +DICOM Standard. +Private Information +Creator UID +(0002,0100) 3 The UID of the creator of the private information +(0002,0102). +Private Information (0002,0102) 1C Contains Private Information placed in the File Meta +Information. The creator shall be identified in (0002,0100). +Required if Private Information Creator UID (0002,0100) is +present. diff --git a/gdcm/Source/MediaStorageAndFileFormat/README.txt b/gdcm/Source/MediaStorageAndFileFormat/README.txt new file mode 100644 index 0000000..e098ff8 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/README.txt @@ -0,0 +1,113 @@ +Part 3.8 +PS 3.10-2006 +Page 10 +3.3 PRESENTATION SERVICE DEFINITIONS +This Part of the Standard makes use of the following terms defined in ISO 8822: +a. Abstract Syntax; +b. Abstract Syntax Name. +3.4 DICOM INTRODUCTION AND OVERVIEW DEFINITIONS +This Part of the Standard makes use of the following terms defined in PS 3.1 of the DICOM Standard: +- Attribute. +3.5 DICOM INFORMATION OBJECT DEFINITIONS +This Part of the Standard makes use of the following terms defined in PS 3.3 of the DICOM Standard: +a. Information Object Definition. +3.6 DICOM DATA STRUCTURE AND ENCODING DEFINITIONS +This Part of the Standard makes use of the following terms defined in PS 3.5 of the DICOM Standard: +a. Data Element; +b. Data Set; +c. Data Element Type; +d. Value; +e. Value Multiplicity; +f. Value Representation; +3.7 DICOM MESSAGE EXCHANGE DEFINITIONS +This Part of the Standard makes use of the following terms defined in PS 3.7 of the DICOM Standard: +a. Service Object Pair (SOP) Class; +b. Service Object Pair (SOP) Instance; +c. Implementation Class UID. +3.8 DICOM MEDIA STORAGE AND FILE FORMAT DEFINITIONS +The following definitions are commonly used in this Part of the Standard: +Application Profile: A Media Storage Application Profile defines a selection of choices at the various +layers of the DICOM Media Storage Model which are applicable to a specific need or context in which the +media interchange is intended to be performed. +DICOM File Service: The DICOM File Service specifies a minimum abstract view of files to be provided +by the Media Format Layer. Constraining access to the content of files by the Application Entities +through such a DICOM File Service boundary ensures Media Format and Physical Media independence. +DICOM File: A DICOM File is a File with a content formatted according to the requirements of this Part of +the DICOM Standard. In particular such files shall contain, the File Meta Information and a properly +formatted Data Set. + PS 3.10-2006 +Page 11 +DICOMDIR File: A unique and mandatory DICOM File within a File-set which contains the Media Storage +Directory SOP Class. This File is given a single component File ID, DICOMDIR. +File: A File is an ordered string of zero or more bytes, where the first byte is at the beginning of the file +and the last byte at the end of the File. Files are identified by a unique File ID and may by written, read +and/or deleted. +File ID: Files are identified by a File ID which is unique within the context of the File-set they belong to. A +set of ordered File ID Components (up to a maximum of eight) forms a File ID. +File ID Component: A string of one to eight characters of a defined character set. +File Meta Information: The File Meta Information includes identifying information on the encapsulated +Data Set. It is a mandatory header at the beginning of every DICOM File. +File-set: A File-set is a collection of DICOM Files (and possibly non-DICOM Files) that share a common +naming space within which File IDs are unique. +File-set Creator: An Application Entity that creates the DICOMDIR File (see section 8.6) and zero or +more DICOM Files. +File-set Reader: An Application Entity that accesses one or more files in a File-set. +File-set Updater: An Application Entity that accesses Files, creates additional Files, or deletes existing +Files in a File-set. A File-set Updater makes the appropriate alterations to the DICOMDIR file reflecting +the additions or deletions. +DICOM File Format: The DICOM File Format provides a means to encapsulate in a File the Data Set +representing a SOP Instance related to a DICOM Information Object. +Media Format: Data structures and associated policies which organizes the bit streams defined by the +Physical Media format into data file structures and associated file directories. +Media Storage Model: The DICOM Media Storage Model pertains to the data structures used at different +layers to achieve interoperability through media interchange. +Media Storage Services: DICOM Media Storage Services define a set of operations with media that +facilitate storage to and retrieval from the media of DICOM SOP Instances. +Physical Media: A piece of material with recording capabilities for streams of bits. Characteristics of a +Physical Media include form factor, mechanical characteristics, recording properties and rules for +recording and organizing bit streams in accessible structures +Secure DICOM File: A DICOM File that is encapsulated with the Cryptographic Message Syntax +specified in RFC 2630. +Secure File-set: A File-set in which all DICOM Files are Secure DICOM Files. +Secure Media Storage Application Profile: A DICOM Media Storage Application Profile that requires a +Secure File-set. + PS 3.10-2006 +Page 12 +4 Symbols and Abbreviations +The following symbols and abbreviations are used in this Part of the Standard. +ACC American College of Cardiology +ACR American College of Radiology +ASCII American Standard Code for Information Interchange +AE Application Entity +ANSI American National Standards Institute +CEN/TC/251 Comite Europeen de Normalisation - Technical Committee 251 - Medical +Informatics +DICOM Digital Imaging and Communications in Medicine +FSC File-set Creator +FSR File-set Reader +FSU File-set Updater +HL7 Health Level 7 +HTML Hypertext Transfer Markup Language +IEEE Institute of Electrical and Electronics Engineers +ISO International Standards Organization +ID Identifier +IOD Information Object Definition +JIRA Japan Industries Association of Radiation Apparatus +MIME Multipurpose Internet Mail Extensions +NEMA National Electrical Manufacturers Association +OSI Open Systems Interconnection +SOP Service-Object Pair +TCP/IP Transmission Control Protocol/Internet Protocol +UID Unique Identifier +VR Value Representation +XML Extensible Markup Language +5 Conventions +Words are capitalized in this document to help the reader understand that these words have been +previously defined in Section 3 of this document and are to be interpreted with that meaning. +A Tag is represented as (gggg,eeee), where gggg equates to the Group Number and eeee equates to the +Element Number within that Group. Tags are represented in hexadecimal notation as specified in PS 3.5 +of the DICOM Standard.. +Attributes of File Meta Information are assigned a Type which indicates if a specific Attribute is required +depending on the Media Storage Services. The following Type designations are derived from the PS 3.5 +designations but take into account the Media Storage environment: + diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmAnonymizeEvent.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmAnonymizeEvent.cxx new file mode 100644 index 0000000..3b1d8be --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmAnonymizeEvent.cxx @@ -0,0 +1,18 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmAnonymizeEvent.h" + +namespace gdcm +{ +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmAnonymizeEvent.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmAnonymizeEvent.h new file mode 100644 index 0000000..e31e4b6 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmAnonymizeEvent.h @@ -0,0 +1,53 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMANONYMIZEEVENT_H +#define GDCMANONYMIZEEVENT_H + +#include "gdcmEvent.h" +#include "gdcmTag.h" + +namespace gdcm +{ + +/** + * \brief AnonymizeEvent + * Special type of event triggered during the Anonymization process + * + * \see Anonymizer + */ +class AnonymizeEvent : public AnyEvent +{ +public: + typedef AnonymizeEvent Self; + typedef AnyEvent Superclass; + AnonymizeEvent(Tag const &tag = 0):m_Tag(tag) {} + virtual ~AnonymizeEvent() {} + virtual const char * GetEventName() const { return "AnonymizeEvent"; } + virtual bool CheckEvent(const ::gdcm::Event* e) const + { return (dynamic_cast(e) == NULL ? false : true) ; } + virtual ::gdcm::Event* MakeObject() const + { return new Self; } + AnonymizeEvent(const Self&s) : AnyEvent(s){}; + + void SetTag(const Tag& t ) { m_Tag = t; } + Tag const & GetTag() const { return m_Tag; } +private: + void operator=(const Self&); + Tag m_Tag; +}; + + +} // end namespace gdcm + +#endif //GDCMANONYMIZEEVENT_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmAnonymizer.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmAnonymizer.cxx new file mode 100644 index 0000000..02ebf6b --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmAnonymizer.cxx @@ -0,0 +1,1140 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmAnonymizer.h" +#include "gdcmGlobal.h" +#include "gdcmStringFilter.h" +#include "gdcmSequenceOfItems.h" +#include "gdcmExplicitDataElement.h" +#include "gdcmSwapper.h" +#include "gdcmDataSetHelper.h" +#include "gdcmUIDGenerator.h" +#include "gdcmAttribute.h" +#include "gdcmDummyValueGenerator.h" +#include "gdcmDicts.h" +#include "gdcmType.h" +#include "gdcmDefs.h" +#include "gdcmCryptographicMessageSyntax.h" +#include "gdcmEvent.h" +#include "gdcmAnonymizeEvent.h" + +namespace gdcm +{ +// PS 3.15 - 2008 +// Table E.1-1 +// BALCPA +static Tag BasicApplicationLevelConfidentialityProfileAttributes[] = { +// Attribute Name Tag +/* Instance Creator UID */ Tag(0x0008,0x0014), +/* SOP Instance UID */ Tag(0x0008,0x0018), +/* Accession Number */ Tag(0x0008,0x0050), +/* Institution Name */ Tag(0x0008,0x0080), +/* Institution Address */ Tag(0x0008,0x0081), +/* Referring Physician's Name */ Tag(0x0008,0x0090), +/* Referring Physician's Address */ Tag(0x0008,0x0092), +/* Referring Physician's Telephone Numbers */ Tag(0x0008,0x0094), +/* Station Name */ Tag(0x0008,0x1010), +/* Study Description */ Tag(0x0008,0x1030), +/* Series Description */ Tag(0x0008,0x103E), +/* Institutional Department Name */ Tag(0x0008,0x1040), +/* Physician(s) of Record */ Tag(0x0008,0x1048), +/* Performing Physicians' Name */ Tag(0x0008,0x1050), +/* Name of Physician(s) Reading Study */ Tag(0x0008,0x1060), +/* Operators' Name */ Tag(0x0008,0x1070), +/* Admitting Diagnoses Description */ Tag(0x0008,0x1080), +/* Referenced SOP Instance UID */ Tag(0x0008,0x1155), +/* Derivation Description */ Tag(0x0008,0x2111), +/* Patient's Name */ Tag(0x0010,0x0010), +/* Patient ID */ Tag(0x0010,0x0020), +/* Patient's Birth Date */ Tag(0x0010,0x0030), +/* Patient's Birth Time */ Tag(0x0010,0x0032), +/* Patient's Sex */ Tag(0x0010,0x0040), +/* Other Patient Ids */ Tag(0x0010,0x1000), +/* Other Patient Names */ Tag(0x0010,0x1001), +/* Patient's Age */ Tag(0x0010,0x1010), +/* Patient's Size */ Tag(0x0010,0x1020), +/* Patient's Weight */ Tag(0x0010,0x1030), +/* Medical Record Locator */ Tag(0x0010,0x1090), +/* Ethnic Group */ Tag(0x0010,0x2160), +/* Occupation */ Tag(0x0010,0x2180), +/* Additional Patient's History */ Tag(0x0010,0x21B0), +/* Patient Comments */ Tag(0x0010,0x4000), +/* Device Serial Number */ Tag(0x0018,0x1000), +/* Protocol Name */ Tag(0x0018,0x1030), +/* Study Instance UID */ Tag(0x0020,0x000D), +/* Series Instance UID */ Tag(0x0020,0x000E), +/* Study ID */ Tag(0x0020,0x0010), +/* Frame of Reference UID */ Tag(0x0020,0x0052), +/* Synchronization Frame of Reference UID */ Tag(0x0020,0x0200), +/* Image Comments */ Tag(0x0020,0x4000), +/* Request Attributes Sequence */ Tag(0x0040,0x0275), +/* UID */ Tag(0x0040,0xA124), +/* Content Sequence */ Tag(0x0040,0xA730), +/* Storage Media File-set UID */ Tag(0x0088,0x0140), +/* Referenced Frame of Reference UID */ Tag(0x3006,0x0024), +/* Related Frame of Reference UID */ Tag(0x3006,0x00C2) +}; + + +Anonymizer::~Anonymizer() +{ +} + +bool Anonymizer::Empty( Tag const &t) +{ + // There is a secret code path to make it work for VR::SQ since operation is just 'make empty' + return Replace(t, "", 0); +} + +bool Anonymizer::Remove( Tag const &t ) +{ + DataSet &ds = F->GetDataSet(); + if(ds.FindDataElement(t)) + return ds.Remove( t ) == 1; + else + return true; +} + +bool Anonymizer::Replace( Tag const &t, const char *value ) +{ + VL::Type len = 0; //to avoid the size_t warning on 64 bit windows + if( value ) + { + len = (VL::Type)strlen( value );//strlen returns size_t, but it should be VL::Type + //strlen shouldn't be more than 4gb anyway + } + return Replace( t, value, len ); +} + +bool Anonymizer::Replace( Tag const &t, const char *value, VL const & vl ) +{ + if( t.GetGroup() < 0x0008 ) return false; + static const Global &g = GlobalInstance; + static const Dicts &dicts = g.GetDicts(); + DataSet &ds = F->GetDataSet(); + // Let's do the private tag: + bool ret = false; + if ( t.IsPrivate() ) + { + // Only one operation is allowed: making a private tag empty ... + if ( vl == 0 ) + { + if( ds.FindDataElement( t ) ) + { + DataElement de ( ds.GetDataElement(t) ); + if ( de.GetVR() != VR::INVALID ) + { + if( de.GetVR() == VR::SQ ) + { + if( vl == 0 && value && *value == 0 ) + { + DataElement de2( t ); + de2.SetVR( VR::SQ ); + ds.Replace( de2 ); + return true; + } + gdcmDebugMacro( "Cannot replace a VR:SQ" ); + return false; + } + } + de.SetByteValue( "", vl ); + ds.Insert( de ); + ret = true; + } + else + { + // TODO + assert( 0 && "TODO" ); + ret = false; + } + } + } + else + { + // Ok this is a public element + assert( t.IsPublic() ); + const DictEntry &dictentry = dicts.GetDictEntry(t); + if ( dictentry.GetVR() == VR::INVALID + || dictentry.GetVR() == VR::UN + || dictentry.GetVR() == VR::SQ + ) + { + // Make the VR::SQ empty + if( dictentry.GetVR() == VR::SQ && vl == 0 && value && *value == 0 ) + { + DataElement de( t ); + de.SetVR( VR::SQ ); + //de.SetByteValue( "", 0 ); + ds.Replace( de ); + } + else + { + // Let's give up ! + gdcmWarningMacro( "Cannot process tag: " << t << " with vr: " << dictentry.GetVR() ); + } + //ret = false; + } + else if ( dictentry.GetVR() & VR::VRBINARY ) + { + if( vl == 0 ) + { + DataElement de( t ); + if( ds.FindDataElement( t ) ) + { + de.SetVR( ds.GetDataElement(t).GetVR() ); + } + else + { + de.SetVR( dictentry.GetVR() ); + } + de.SetByteValue( "", 0 ); + ds.Replace( de ); + ret = true; + } + else + { + gdcmWarningMacro( "You need to explicitely specify the length for this type of vr: " << dictentry.GetVR() ); + ret = false; + } +#if 0 + StringFilter sf; + sf.SetFile( *F ); + std::string s = sf.FromString(t, value, vl); + DataElement de( t ); + if( ds.FindDataElement( t ) ) + { + de.SetVR( ds.GetDataElement(t).GetVR() ); + } + else + { + de.SetVR( dictentry.GetVR() ); + } + de.SetByteValue( s.c_str(), s.size() ); + ds.Replace( de ); + ret = true; +#endif + } + else + { + // vr from dict seems to be ascii, so it seems resonable to write a ByteValue here: + assert( dictentry.GetVR() & VR::VRASCII ); + if( value ) + { + std::string padded( value, vl ); + // All ASCII VR needs to be padded with a space + if( vl.IsOdd() ) + { + if( dictentry.GetVR() == VR::UI ) + { + // \0 is automatically added when using a ByteValue + } + else + { + padded += " "; + } + } + // Hum, we could have cases where a public element would not be known, in which case + // it is a good idea to first check for the VR as found in the file: + DataElement de( t ); + if( ds.FindDataElement( t ) ) + { + de.SetVR( ds.GetDataElement(t).GetVR() ); + } + else + { + de.SetVR( dictentry.GetVR() ); + } + const VL::Type paddedSize = (VL::Type) padded.size();//casting to avoid size_t warning on 64 + de.SetByteValue( padded.c_str(), paddedSize ); + ds.Replace( de ); + ret = true; + } + } + } + return ret; +} + +static bool Anonymizer_RemoveRetired(File const &file, DataSet &ds) +{ + static const Global &g = GlobalInstance; + static const Dicts &dicts = g.GetDicts(); + static const Dict &pubdict = dicts.GetPublicDict(); + DataSet::Iterator it = ds.Begin(); + for( ; it != ds.End(); ) + { + const DataElement &de1 = *it; + // std::set::erase invalidate iterator, so we need to make a copy first: + DataSet::Iterator dup = it; + ++it; + if( de1.GetTag().IsPublic() ) + { + const DictEntry &entry = pubdict.GetDictEntry( de1.GetTag() ); + if( entry.GetRetired() ) + { + ds.GetDES().erase(dup); + } + } + else + { + const DataElement &de = *dup; + VR vr = DataSetHelper::ComputeVR(file, ds, de.GetTag() ); + if( vr.Compatible(VR::SQ) ) + { + SmartPointer sq = de.GetValueAsSQ(); + if( sq ) + { + gdcm::SequenceOfItems::SizeType n = sq->GetNumberOfItems(); + for( gdcm::SequenceOfItems::SizeType i = 1; i <= n; i++) // item starts at 1, not 0 + { + Item &item = sq->GetItem( i ); + DataSet &nested = item.GetNestedDataSet(); + Anonymizer_RemoveRetired( file, nested ); + } + DataElement de_dup = *dup; + de_dup.SetValue( *sq ); + de_dup.SetVLToUndefined(); // FIXME + ds.Replace( de_dup ); + } + } + } + } + return true; +} + +bool Anonymizer::RemoveRetired() +{ + DataSet &ds = F->GetDataSet(); + return Anonymizer_RemoveRetired(*F, ds); +} + +static bool Anonymizer_RemoveGroupLength(File const &file, DataSet &ds) +{ + DataSet::Iterator it = ds.Begin(); + for( ; it != ds.End(); ) + { + const DataElement &de1 = *it; + // std::set::erase invalidate iterator, so we need to make a copy first: + DataSet::Iterator dup = it; + ++it; + if( de1.GetTag().IsGroupLength() ) + { + ds.GetDES().erase(dup); + } + else + { + const DataElement &de = *dup; + VR vr = DataSetHelper::ComputeVR(file, ds, de.GetTag() ); + if( vr.Compatible(VR::SQ) ) + { + SmartPointer sq = de.GetValueAsSQ(); + if( sq ) + { + gdcm::SequenceOfItems::SizeType n = sq->GetNumberOfItems(); + for( gdcm::SequenceOfItems::SizeType i = 1; i <= n; i++) // item starts at 1, not 0 + { + Item &item = sq->GetItem( i ); + DataSet &nested = item.GetNestedDataSet(); + Anonymizer_RemoveGroupLength( file, nested ); + } + DataElement de_dup = *dup; + de_dup.SetValue( *sq ); + de_dup.SetVLToUndefined(); // FIXME + ds.Replace( de_dup ); + } + } + } + } + return true; +} + +bool Anonymizer::RemoveGroupLength() +{ + DataSet &ds = F->GetDataSet(); + return Anonymizer_RemoveGroupLength(*F, ds); +} + +static bool Anonymizer_RemovePrivateTags(File const &file, DataSet &ds) +{ + DataSet::Iterator it = ds.Begin(); + for( ; it != ds.End(); ) + { + const DataElement &de1 = *it; + // std::set::erase invalidate iterator, so we need to make a copy first: + DataSet::Iterator dup = it; + ++it; + if( de1.GetTag().IsPrivate() ) + { + ds.GetDES().erase(dup); + } + else + { + const DataElement &de = *dup; + VR vr = DataSetHelper::ComputeVR(file, ds, de.GetTag() ); + if( vr.Compatible(VR::SQ) ) + { + SmartPointer sq = de.GetValueAsSQ(); + if( sq ) + { + gdcm::SequenceOfItems::SizeType n = sq->GetNumberOfItems(); + for( gdcm::SequenceOfItems::SizeType i = 1; i <= n; i++) // item starts at 1, not 0 + { + Item &item = sq->GetItem( i ); + DataSet &nested = item.GetNestedDataSet(); + Anonymizer_RemovePrivateTags( file, nested ); + } + DataElement de_dup = *dup; + de_dup.SetValue( *sq ); + de_dup.SetVLToUndefined(); // FIXME + ds.Replace( de_dup ); + } + } + } + } + return true; +} + +bool Anonymizer::RemovePrivateTags() +{ + DataSet &ds = F->GetDataSet(); + return Anonymizer_RemovePrivateTags(*F, ds); +} + +/* + * Implementation note: + * In order to implement the dummy 'memory' we use a static std::map + * this works great but we cannot be thread safe. + * In order to be thread safe, we would need to externalize this map generation + * maybe using a gdcm::Scanner do the operation once (Scanner is doing) the merging + * automatically... + * this is left as an exercise for the reader :) + */ +bool Anonymizer::BasicApplicationLevelConfidentialityProfile(bool deidentify) +{ + this->InvokeEvent( StartEvent() ); + bool ret; + if( deidentify ) + ret = BasicApplicationLevelConfidentialityProfile1(); + else + ret = BasicApplicationLevelConfidentialityProfile2(); + this->InvokeEvent( EndEvent() ); + return ret; +} + +std::vector Anonymizer::GetBasicApplicationLevelConfidentialityProfileAttributes() +{ + static const unsigned int deidSize = sizeof(Tag); + static const unsigned int numDeIds = sizeof(BasicApplicationLevelConfidentialityProfileAttributes) / deidSize; + static const Tag *start = BasicApplicationLevelConfidentialityProfileAttributes; + static const Tag *end = start + numDeIds; + return std::vector(start, end); +} + +bool Anonymizer::CheckIfSequenceContainsAttributeToAnonymize(File const &file, SequenceOfItems* sqi) const +{ + static const unsigned int deidSize = sizeof(Tag); + static const unsigned int numDeIds = sizeof(BasicApplicationLevelConfidentialityProfileAttributes) / deidSize; + static const Tag *start = BasicApplicationLevelConfidentialityProfileAttributes; + static const Tag *end = start + numDeIds; + + bool found = false; + for(const Tag *ptr = start ; ptr != end && !found ; ++ptr) + { + const Tag& tag = *ptr; + found = sqi->FindDataElement( tag ); + } + // ok we can exit. + if( found ) return true; + + // now look into sub-sequence: + gdcm::SequenceOfItems::SizeType n = sqi->GetNumberOfItems(); + for( gdcm::SequenceOfItems::SizeType i = 1; i <= n; i++) // item starts at 1, not 0 + { + Item &item = sqi->GetItem( i ); + DataSet &nested = item.GetNestedDataSet(); + DataSet::Iterator it = nested.Begin(); + for( ; it != nested.End() && !found; ++it) + { + const DataElement &de = *it; + VR vr = DataSetHelper::ComputeVR(file, nested, de.GetTag() ); + SmartPointer sqi2 = 0; + if( vr == VR::SQ ) + { + sqi2 = de.GetValueAsSQ(); + } + if( sqi2 ) + { + found = CheckIfSequenceContainsAttributeToAnonymize(file, sqi2); + } + } + } + + return found; +} + +// Implementation note: +// This function trigger: +// 1 StartEvent +// 1 EndEvent +// 6 IterationEvent +// N AnonymizeEvent (depend on number of tag found) +bool Anonymizer::BasicApplicationLevelConfidentialityProfile1() +{ + static const unsigned int deidSize = sizeof(Tag); + static const unsigned int numDeIds = sizeof(BasicApplicationLevelConfidentialityProfileAttributes) / deidSize; + static const Tag *start = BasicApplicationLevelConfidentialityProfileAttributes; + static const Tag *end = start + numDeIds; + if( !CMS ) + { + gdcmErrorMacro( "Need a certificate" ); + return false; + } + + CryptographicMessageSyntax &p7 = *CMS; + //p7.SetCertificate( this->x509 ); + + DataSet &ds = F->GetDataSet(); + if( ds.FindDataElement( Tag(0x0400,0x0500) ) + || ds.FindDataElement( Tag(0x0012,0x0062) ) + || ds.FindDataElement( Tag(0x0012,0x0063) ) ) + { + gdcmDebugMacro( "EncryptedContentTransferSyntax Attribute is present !" ); + return false; + } +#if 0 + if( !ds.FindDataElement( Tag(0x0008,0x0018) ) + || ds.GetDataElement( Tag(0x0008,0x0018) ).IsEmpty() ) + { + return false; + } +#endif + + // PS 3.15 + // E.1 BASIC APPLICATION LEVEL CONFIDENTIALITY PROFILE + // An Application may claim conformance to the Basic Application Level Confidentiality Profile as a deidentifier + // if it protects all Attributes that might be used by unauthorized entities to identify the patient. + // Protection in this context is defined as the following process: + + // 1. The application may create one or more instances of the Encrypted Attributes Data Set and copy + // Attributes to be protected into the (single) item of the Modified Attributes Sequence (0400,0550) of + // one or more of the Encrypted Attributes Data Set instances. + + // Create an instance of the Encrypted Attributes DataSet + // Modified Attributes Sequence (0400,0550) 1 Sequence of Items containing all Attributes + // that were removed or replaced by "dummy values" in the main dataset during deidentification + // of the SOP instance. Upon reversal of the de-identification process, the + // Attributes are copied back into the main dataset, replacing any dummy values that + // might have been created. Only a single Item shall be present. + + // Create a Sequence + SmartPointer sq1 = new SequenceOfItems(); + sq1->SetLengthToUndefined(); + + // Create a *single* item + Item item1; + item1.SetVLToUndefined(); + DataSet &encryptedds = item1.GetNestedDataSet(); + // Loop over root level attributes: + for(const Tag *ptr = start ; ptr != end ; ++ptr) + { + const Tag& tag = *ptr; + if( ds.FindDataElement( tag ) ) + encryptedds.Insert( ds.GetDataElement( tag ) ); + } + this->InvokeEvent( IterationEvent() ); + // Check that root level sequence do not contains any of those attributes +{ + DataSet::ConstIterator it = ds.Begin(); + for( ; it != ds.End(); ++it ) + { + const DataElement &de = *it; + //const SequenceOfItems *sqi = de.GetSequenceOfItems(); + SmartPointer sqi = 0; + VR vr = DataSetHelper::ComputeVR(*F, ds, de.GetTag() ); + if( vr == VR::SQ ) + { + sqi = de.GetValueAsSQ(); + } + if( sqi ) + { + bool found + = CheckIfSequenceContainsAttributeToAnonymize(*F, sqi); + if( found ) + { + // A special Tag was found within the SQ,let's store the entire Sequence of Item: + if( !encryptedds.FindDataElement( de.GetTag() ) ) + { + // What if we found a Patient Name within a Content Sequence + // we do not need to insert twice this DICOM Attribute + encryptedds.Insert( de ); + } + else + { + assert( de == encryptedds.GetDataElement( de.GetTag() ) ); + } + } + } + } +} + + this->InvokeEvent( IterationEvent() ); + sq1->AddItem(item1); + + DataElement des( Tag(0x0400,0x0550) ); + des.SetVR(VR::SQ); + des.SetValue(*sq1); + des.SetVLToUndefined(); + + std::ostringstream os; + des.Write(os); + + std::string encrypted_str = os.str(); + + // Note: 1. Content encryption may require that the content (the DICOM Data Set) be padded to a + // multiple of some block size. This shall be performed according to the Content-encryption + // Process defined in RFC-2630. + size_t encrypted_len = encrypted_str.size() * 20; // this is really overestimated + + char *orig = new char[ encrypted_len ]; + char *buf = new char[ encrypted_len ]; + memset( buf, 0, encrypted_len ); + memset( orig, 0, encrypted_len ); + memcpy( orig, encrypted_str.c_str(), encrypted_str.size() ); + + size_t encrypted_len2 = encrypted_len; + bool b = p7.Encrypt( buf, encrypted_len, orig, encrypted_str.size() ); + if( !b ) + { + delete[] orig; + delete[] buf; + gdcmErrorMacro( "Problem with Encrypt" ); + return false; + } + assert( encrypted_len <= encrypted_len2 ); + (void)encrypted_len2;//warning removal + + { + // Create a Sequence + SmartPointer sq = new SequenceOfItems(); + sq->SetLengthToUndefined(); + + // FIXME: should be user configurable: + //TransferSyntax encrypted_ts = TransferSyntax::ImplicitVRLittleEndian; + TransferSyntax encrypted_ts = TransferSyntax::ExplicitVRLittleEndian; + // + DataElement encrypted_ts_de( Tag(0x400,0x510) ); + encrypted_ts_de.SetVR( Attribute<0x0400, 0x0510>::GetVR() ); + const VL::Type encryptedStrLen = (VL::Type)strlen(encrypted_ts.GetString()); + encrypted_ts_de.SetByteValue( encrypted_ts.GetString(), encryptedStrLen ); + // + DataElement encrypted_de( Tag(0x400,0x520) ); + encrypted_de.SetVR( Attribute<0x0400, 0x0520>::GetVR() ); + const VL::Type encryptedLenSize = (VL::Type)encrypted_len; + encrypted_de.SetByteValue( (char*)buf, encryptedLenSize ); + delete[] buf; + delete[] orig; + + // Create an item + Item item2; + item2.SetVLToUndefined(); + DataSet &nds = item2.GetNestedDataSet(); + nds.Insert(encrypted_ts_de); + nds.Insert(encrypted_de); + + sq->AddItem(item2); + + // 4. All instances of the Encrypted Attributes Data Set shall be encoded + // with a DICOM Transfer Syntax, encrypted, and stored in the dataset to be + // protected as an Item of the Encrypted Attributes Sequence (0400,0500). + // The encryption shall be done using RSA [RFC 2313] for the key transport + // of the content-encryption keys. A de-identifier conforming to this + // security profile may use either AES or Triple-DES for + // content-encryption. The AES key length may be any length allowed by the + // RFCs. The Triple-DES key length is 168 bits as defined by ANSI X9.52. + // Encoding shall be performed according to the specifications for RSA Key + // Transport and Triple DES Content Encryption in RFC-3370 and for AES + // Content Encryption in RFC-3565. + + // 5. No requirements on the size of the asymmetric key pairs used for RSA + // key transport are defined in this confidentiality scheme. + // Implementations claiming conformance to the Basic Application Level + // Confidentiality Profile as a de-identifier shall always protect (e.g. + // encrypt and replace) the SOP Instance UID (0008,0018) Attribute as well + // as all references to other SOP Instances, whether contained in the main + // dataset or embedded in an Item of a Sequence of Items, that could + // potentially be used by unauthorized entities to identify the patient. + + // Insert sequence into data set + DataElement subdes( Tag(0x0400,0x0500) ); + subdes.SetVR(VR::SQ); + subdes.SetValue(*sq); + subdes.SetVLToUndefined(); + + ds.Insert(subdes); + } + this->InvokeEvent( IterationEvent() ); + + // 2. Each Attribute to be protected shall then either be removed from the + // dataset, or have its value replaced by a different "replacement value" + // which does not allow identification of the patient. + + //for(const Tag *ptr = start ; ptr != end ; ++ptr) + // { + // const Tag& tag = *ptr; + // // FIXME Type 1 ! + // if( ds.FindDataElement( tag ) ) BALCPProtect(F->GetDataSet(), tag); + // } + // Check that root level sequence do not contains any of those attributes + try + { + RecurseDataSet( F->GetDataSet() ); + } + catch(std::exception &ex) + { + gdcmDebugMacro( "Problem during RecurseDataSet"); + (void)ex; //to get rid of the warning. TODO: spit out the exception + return false; + } +catch(...) +{ + gdcmDebugMacro( "Unknown Problem during RecurseDataSet" ); + return false; +} + + this->InvokeEvent( IterationEvent() ); + + // Group Length are removed since PS 3.3-2008 + RemoveGroupLength(); + + // 3. At the discretion of the de-identifier, Attributes may be added to the + // dataset to be protected. ... + + // 6. The attribute Patient Identity Removed (0012,0062) shall be replaced or + // added to the dataset with a value of YES, and a value inserted in + // De-identification Method (0012,0063) or De-identification Method Code + // Sequence (0012,0064). + Replace( Tag(0x0012,0x0062), "YES"); + Replace( Tag(0x0012,0x0063), "BASIC APPLICATION LEVEL CONFIDENTIALITY PROFILE"); + + this->InvokeEvent( IterationEvent() ); + +#if 0 + // Since the de-identified SOP Instance is a significantly altered version of + // the original Data Set, it is a new SOP Instance, with a SOP Instance UID + // that differs from the original Data Set. + UIDGenerator uid; + if( ds.FindDataElement( Tag(0x0008,0x0018) ) ) + { + Replace( Tag(0x008,0x0018), uid.Generate() ); + } + + this->InvokeEvent( IterationEvent() ); +#endif + + return true; +} + + +bool IsVRUI(Tag const &tag) +{ + static const Global &g = Global::GetInstance(); + static const Dicts &dicts = g.GetDicts(); + const DictEntry &dictentry = dicts.GetDictEntry(tag); + if( dictentry.GetVR() == VR::UI ) return true; + //if( tag == Tag(0x0020,0x000d) // Study Instance UID : UI + // || tag == Tag(0x0020,0x0052) // + // || tag == Tag(0x0020,0x000e) ) // Series Instance UID : UI + // { + // return true; + // } + return false; +} + +static const Tag SpecialTypeTags[] = { +/* Patient's Name */ Tag(0x0010,0x0010), +/* Patient ID */ Tag(0x0010,0x0020), +/* Study ID */ Tag(0x0020,0x0010), +/* Series Number */ Tag(0x0020,0x0011) +}; + +bool Anonymizer::CanEmptyTag(Tag const &tag, const IOD &iod) const +{ + static const Global &g = Global::GetInstance(); + //static const Dicts &dicts = g.GetDicts(); + static const Defs &defs = g.GetDefs(); + const DataSet &ds = F->GetDataSet(); (void)ds; + //Type told = defs.GetTypeFromTag(*F, tag); + Type t = iod.GetTypeFromTag(defs, tag); + //assert( t == told ); + + gdcmDebugMacro( "Type for tag=" << tag << " is " << t ); + + //assert( t != Type::UNKNOWN ); + + if( t == Type::T1 || t == Type::T1C ) + { + return false; + } + // What if we are dealing with a Standard Extended SOP class + // eg. gdcmData/05115014-mr-siemens-avanto-syngo-with-palette-icone.dcm + // where Attribute is not present in standard DICOM IOD - (0x0088,0x0140) UI Storage Media FileSet UID + if( t == Type::UNKNOWN ) + { + return true; + } + + // http://groups.google.com/group/comp.protocols.dicom/browse_thread/thread/b1b23101bb655b81 +/* +... +3. It is the responsibility of the de-identifier to ensure the +consistency of dummy values for Attributes +such as Study Instance UID (0020,000D) or Frame of Reference UID +(0020,0052) if multiple related +SOP Instances are protected. +... + +I think it would also make sense to quote the following attributes: +* Patient ID, +* Study ID, +* Series Number. +It is required they have consistent values when one is about to +generate a DICOMDIR + +=> Sup 142 +*/ + static const unsigned int deidSize = sizeof(Tag); + static const unsigned int numDeIds = sizeof(SpecialTypeTags) / deidSize; + + bool b = std::binary_search(SpecialTypeTags, SpecialTypeTags + numDeIds, tag); + + // This is a Type 3 attribute but with VR=UI + // + //assert( dicts.GetDictEntry(tag).GetVR() != VR::UI ); + return !b; +} + +Anonymizer::DummyMapNonUIDTags Anonymizer::dummyMapNonUIDTags; +Anonymizer::DummyMapUIDTags Anonymizer::dummyMapUIDTags; + +void Anonymizer::ClearInternalUIDs() +{ + dummyMapNonUIDTags.clear(); + dummyMapUIDTags.clear(); +} + +bool Anonymizer::BALCPProtect(DataSet &ds, Tag const & tag, IOD const & iod) +{ + // \precondition + assert( ds.FindDataElement(tag) ); + + AnonymizeEvent ae; + ae.SetTag( tag ); + this->InvokeEvent( ae ); + + + bool canempty = CanEmptyTag( tag, iod ); + if( !canempty ) + { + DataElement copy; + copy = ds.GetDataElement( tag ); + + if ( IsVRUI( tag ) ) + { + std::string UIDToAnonymize = ""; + gdcm::UIDGenerator uid; + + if( !copy.IsEmpty() ) + { + if( const ByteValue *bv = copy.GetByteValue() ) + { + UIDToAnonymize = std::string( bv->GetPointer(), bv->GetLength() ); + } + } + + std::string anonymizedUID = ""; + if( !UIDToAnonymize.empty() ) + { + if ( dummyMapUIDTags.count( UIDToAnonymize ) == 0 ) + { + anonymizedUID = uid.Generate(); + dummyMapUIDTags[ UIDToAnonymize ] = anonymizedUID; + } + else + { + anonymizedUID = dummyMapUIDTags[ UIDToAnonymize ]; + } + } + else + { + // gdcmData/LEADTOOLS_FLOWERS-16-MONO2-JpegLossless.dcm + // has an empty 0008,0018 attribute, let's try to handle creating new UID + anonymizedUID = uid.Generate(); + } + + copy.SetByteValue( anonymizedUID.c_str(), (uint32_t)anonymizedUID.size() ); + ds.Replace( copy ); + } + else + { + TagValueKey tvk; + tvk.first = tag; + + assert( dummyMapNonUIDTags.count( tvk ) == 0 || dummyMapNonUIDTags.count( tvk ) == 1 ); + if( dummyMapNonUIDTags.count( tvk ) == 0 ) + { + const char *ret = DummyValueGenerator::Generate( tvk.second.c_str() ); + if( ret ) + { + dummyMapNonUIDTags[ tvk ] = ret; + } + else + dummyMapNonUIDTags[ tvk ] = ""; + } + + std::string &v = dummyMapNonUIDTags[ tvk ]; + copy.SetByteValue( v.c_str(), (uint32_t)v.size() ); + } + ds.Replace( copy ); + } + else + { + //Empty( tag ); + DataElement copy = ds.GetDataElement( tag ); + copy.Empty(); + ds.Replace( copy ); + } + return true; +} + +void Anonymizer::RecurseDataSet( DataSet & ds ) +{ + if( ds.IsEmpty() ) return; + + static const unsigned int deidSize = sizeof(Tag); + static const unsigned int numDeIds = sizeof(BasicApplicationLevelConfidentialityProfileAttributes) / deidSize; + static const Tag *start = BasicApplicationLevelConfidentialityProfileAttributes; + static const Tag *end = start + numDeIds; + + static const Global &g = Global::GetInstance(); + static const Defs &defs = g.GetDefs(); + const IOD& iod = defs.GetIODFromFile(*F); + + for(const Tag *ptr = start ; ptr != end ; ++ptr) + { + const Tag& tag = *ptr; + // FIXME Type 1 ! + if( ds.FindDataElement( tag ) ) + { + BALCPProtect(ds, tag, iod); + } + } + + DataSet::ConstIterator it = ds.Begin(); + for( ; it != ds.End(); /*++it*/ ) + { + assert( it != ds.End() ); + DataElement de = *it; ++it; + //const SequenceOfItems *sqi = de.GetSequenceOfItems(); + VR vr = DataSetHelper::ComputeVR(*F, ds, de.GetTag() ); + SmartPointer sqi = 0; + if( vr == VR::SQ ) + { + sqi = de.GetValueAsSQ(); + } + if( sqi ) + { + de.SetValue( *sqi ); // EXTREMELY IMPORTANT #2912092 + de.SetVLToUndefined(); + assert( sqi->IsUndefinedLength() ); + //de.GetVL().SetToUndefined(); + //sqi->SetLengthToUndefined(); + gdcm::SequenceOfItems::SizeType n = sqi->GetNumberOfItems(); + for( gdcm::SequenceOfItems::SizeType i = 1; i <= n; ++i ) + { + Item &item = sqi->GetItem( i ); + DataSet &nested = item.GetNestedDataSet(); + RecurseDataSet( nested ); + } + } + ds.Replace( de ); + } + +} + +//void Anonymizer::SetAESKey(AES const &aes) +//{ +// AESKey = aes; +//} +// +//const AES &Anonymizer::GetAESKey() const +//{ +// return AESKey; +//} + +bool Anonymizer::BasicApplicationLevelConfidentialityProfile2() +{ + if( !CMS ) + { + gdcmErrorMacro( "Need a certificate" ); + return false; + } + // 1. The application shall decrypt, using its recipient key, one instance of + // the Encrypted Content (0400,0520) Attribute within the Encrypted + // Attributes Sequence (0400,0500) and decode the resulting block of bytes + // into a DICOM dataset using the Transfer Syntax specified in the Encrypted + // Content Transfer Syntax UID (0400,0510). Re-identifiers claiming + // conformance to this profile shall be capable of decrypting the Encrypted + // Content using either AES or Triple-DES in all possible key lengths + // specified in this profile + CryptographicMessageSyntax &p7 = *CMS; + //p7.SetCertificate( this->x509 ); + + DataSet &ds = F->GetDataSet(); + if( !ds.FindDataElement( Tag(0x0400,0x0500) ) ) + { + gdcmDebugMacro( "Could not find EncryptedAttributesSQ" ); + return false; + } + const DataElement &EncryptedAttributesSequence = ds.GetDataElement( Tag(0x0400,0x0500) ); + //const SequenceOfItems *sq = EncryptedAttributesSequence.GetSequenceOfItems(); + SmartPointer sq = EncryptedAttributesSequence.GetValueAsSQ(); + const Item &item1 = sq->GetItem(1); + const DataSet &nds1 = item1.GetNestedDataSet(); + if( !nds1.FindDataElement( Tag(0x0400,0x0510) ) + || nds1.GetDataElement( Tag(0x0400,0x0510) ).IsEmpty() ) + { + gdcmDebugMacro( "Missing EncryptedContentTransferSyntax Attribute" ); + return false; + } + + const DataElement &EncryptedContentTransferSyntax = nds1.GetDataElement( Tag(0x0400,0x0510) ); + + std::string ts( EncryptedContentTransferSyntax.GetByteValue()->GetPointer(), + EncryptedContentTransferSyntax.GetByteValue()->GetLength() ); + + if( TransferSyntax::GetTSType( ts.c_str() ) != TransferSyntax::ExplicitVRLittleEndian ) + { + gdcmDebugMacro( "Only ExplicitVRLittleEndian is supported" ); + return false; + } + + if( !nds1.FindDataElement( Tag(0x0400,0x0520) ) + || nds1.GetDataElement( Tag(0x0400,0x0520) ).IsEmpty() ) + { + gdcmDebugMacro( "Missing EncryptedContent Attribute" ); + return false; + } + + const DataElement &EncryptedContent = nds1.GetDataElement( Tag(0x0400,0x0520) ); + const ByteValue *bv = EncryptedContent.GetByteValue(); + + size_t encrypted_len = bv->GetLength(); + char *orig = new char[ encrypted_len ]; + char *buf = new char[ encrypted_len ]; + memcpy(orig, bv->GetPointer(), encrypted_len ); + + size_t encrypted_len2 = encrypted_len; + bool b = p7.Decrypt( buf, encrypted_len, orig, encrypted_len); + if( !b ) + { + // ooops + gdcmDebugMacro( "Could not decrypt" ); + return false; + } + assert( encrypted_len <= encrypted_len2 ); + (void)encrypted_len2;//warning removal + + std::stringstream ss; + ss.str( std::string((char*)buf, encrypted_len) ); + DataSet des; + DataElement dummy; + try + { + dummy.Read(ss); + } + //catch( std::Exception & e) + catch( ... ) + { + delete[] buf; + delete[] orig; + + return false; + } + des.Insert( dummy ); + //des.Read(ss); + //des.ReadNested(ss); + + //std::cout << des << std::endl; + //std::cout << dummy << std::endl; + //std::cout << ss.tellg() << std::endl; + assert( (size_t)ss.tellg() <= encrypted_len ); + // TODO: check that for i = ss.tellg() to encrypted_len, ss[i] == 0 + delete[] buf; + delete[] orig; + + // 2. The application shall move all Attributes contained in the single item + // of the Modified Attributes Sequence (0400,0550) of the decoded dataset + // into the main dataset, replacing dummy value Attributes that may be + // present in the main dataset. + //assert( dummy.GetVR() == VR::SQ ); +{ + //const SequenceOfItems *sqi = dummy.GetSequenceOfItems(); + SmartPointer sqi = dummy.GetValueAsSQ(); + assert( sqi && sqi->GetNumberOfItems() == 1 ); + Item const & item2 = sqi->GetItem( 1 ); + const DataSet &nds2 = item2.GetNestedDataSet(); + DataSet::ConstIterator it = nds2.Begin(); + for( ; it != nds2.End(); ++it ) + { + ds.Replace( *it ); + } + + // FIXME the above Replace assume that the encrypted content will replace + // any dummy values. What if the anonymizer was dumb and forgot + // to encrypt say UID 8,18 ? We would be left with the Instance UID + // of the encrypted one ? + if( !nds2.FindDataElement( Tag(0x8,0x18) ) ) + { + gdcm::MediaStorage ms; + ms.SetFromFile( *F ); + if( ms != MediaStorage::MediaStorageDirectoryStorage ) + { + gdcmErrorMacro( "Could not find Instance UID" ); + return false; + } + } +} + + // 3. The attribute Patient Identity Removed (0012,0062) shall be replaced or + // added to the dataset with a value of NO and De-identification Method + // (0012,0063) and De-identification Method Code Sequence (0012,0064) shall + // be removed. + //Replace( Tag(0x0012,0x0062), "NO"); + Remove( Tag(0x0012,0x0062) ); + Remove( Tag(0x0012,0x0063) ); + + Remove( Tag(0x0400,0x0500) ); // ?? + + return true; +} + +void Anonymizer::SetCryptographicMessageSyntax(CryptographicMessageSyntax *cms) +{ + CMS = cms; +} + +const CryptographicMessageSyntax *Anonymizer::GetCryptographicMessageSyntax() const +{ + return CMS; +} + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmAnonymizer.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmAnonymizer.h new file mode 100644 index 0000000..4b8653d --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmAnonymizer.h @@ -0,0 +1,173 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMANONYMIZER_H +#define GDCMANONYMIZER_H + +#include "gdcmFile.h" +#include "gdcmSubject.h" +#include "gdcmEvent.h" +#include "gdcmSmartPointer.h" + +#include + +namespace gdcm +{ +class TagPath; +class IOD; +class CryptographicMessageSyntax; + +/** + * \brief Anonymizer + * This class is a multi purpose anonymizer. It can work in 2 mode: + * - Full (irreversible) anonymizer (aka dumb mode) + * - reversible de-identifier/re-identifier (aka smart mode). This implements the Basic Application Level Confidentiality Profile, DICOM PS 3.15-2009 + * + * 1. dumb mode + * This is a dumb anonymizer implementation. All it allows user is simple operation such as: + * + * Tag based functions: + * - complete removal of DICOM attribute (Remove) + * - make a tag empty, ie make it's length 0 (Empty) + * - replace with another string-based value (Replace) + * + * DataSet based functions: + * - Remove all group length attribute from a DICOM dataset (Group Length element are deprecated, DICOM 2008) + * - Remove all private attributes + * - Remove all retired attributes + * + * All function calls actually execute the user specified request. Previous + * implementation were calling a general Anonymize function but traversing a + * std::set is O(n) operation, while a simple user specified request is + * O(log(n)) operation. So 'm' user interaction is O(m*log(n)) which is < O(n) + * complexity. + * + * 2. smart mode + * this mode implements the Basic Application Level Confidentiality Profile + * (DICOM PS 3.15-2008) In this case, it is extremely important to use the same + * gdcm::Anonymizer class when anonymizing a FileSet. Once the gdcm::Anonymizer + * is destroyed its memory of known (already processed) UIDs will be lost. + * which will make the anonymizer behaves incorrectly for attributes such as + * Series UID Study UID where user want some consistency. When attribute is + * Type 1 / Type 1C, a dummy generator will take in the existing value and + * produce a dummy value (a sha1 representation). sha1 algorithm is considered + * to be cryptographically strong (compared to md5sum) so that we meet the + * following two conditions: + * - Produce the same dummy value for the same input value + * - do not provide an easy way to retrieve the original value from the sha1 generated value + * + * This class implement the Subject/Observer pattern trigger the following event: + * \li AnonymizeEvent + * \li IterationEvent + * \li StartEvent + * \li EndEvent + * + * \see CryptographicMessageSyntax + */ +class GDCM_EXPORT Anonymizer : public Subject +{ +public: + Anonymizer():F(new File),CMS(NULL) {} + ~Anonymizer(); + + /// Make Tag t empty (if not found tag will be created) + /// Warning: does not handle SQ element + bool Empty( Tag const &t ); + //bool Empty( PrivateTag const &t ); + //bool Empty( TagPath const &t ); + + /// remove a tag (even a SQ can be removed) + /// Return code is false when tag t cannot be found + bool Remove( Tag const &t ); + //bool Remove( PrivateTag const &t ); + //bool Remove( TagPath const &t ); + + /// Replace tag with another value, if tag is not found it will be created: + /// WARNING: this function can only execute if tag is a VRASCII + bool Replace( Tag const &t, const char *value ); + + /// when the value contains \0, it is a good idea to specify the length. This function + /// is required when dealing with VRBINARY tag + bool Replace( Tag const &t, const char *value, VL const & vl ); + //bool Replace( PrivateTag const &t, const char *value, VL const & vl ); + //bool Replace( TagPath const &t, const char *value, VL const & vl ); + + /// Main function that loop over all elements and remove private tags + bool RemovePrivateTags(); + + /// Main function that loop over all elements and remove group length + bool RemoveGroupLength(); + + /// Main function that loop over all elements and remove retired element + bool RemoveRetired(); + + // TODO: + // bool Remove( PRIVATE_TAGS | GROUP_LENGTH | RETIRED ); + + /// Set/Get File + void SetFile(const File& f) { F = f; } + //const File &GetFile() const { return *F; } + File &GetFile() { return *F; } + + /// PS 3.15 / E.1.1 De-Identifier + /// An Application may claim conformance to the Basic Application Level Confidentiality Profile as a deidentifier + /// if it protects all Attributes that might be used by unauthorized entities to identify the patient. + /// NOT THREAD SAFE + bool BasicApplicationLevelConfidentialityProfile(bool deidentify = true); + + /// Set/Get CMS key that will be used to encrypt the dataset within BasicApplicationLevelConfidentialityProfile + void SetCryptographicMessageSyntax( CryptographicMessageSyntax *cms ); + const CryptographicMessageSyntax *GetCryptographicMessageSyntax() const; + + /// for wrapped language: instantiate a reference counted object + static SmartPointer New() { return new Anonymizer; } + + /// Return the list of Tag that will be considered when anonymizing a DICOM file. + static std::vector GetBasicApplicationLevelConfidentialityProfileAttributes(); + + /// Clear the internal mapping of real UIDs to generated UIDs + /// \warning the mapping is definitely lost + static void ClearInternalUIDs(); + +protected: + // Internal function used to either empty a tag or set it's value to a dummy value (Type 1 vs Type 2) + bool BALCPProtect(DataSet &ds, Tag const & tag, const IOD &iod); + bool CanEmptyTag(Tag const &tag, const IOD &iod) const; + void RecurseDataSet( DataSet & ds ); + +private: + bool BasicApplicationLevelConfidentialityProfile1(); + bool BasicApplicationLevelConfidentialityProfile2(); + bool CheckIfSequenceContainsAttributeToAnonymize(File const &file, SequenceOfItems* sqi) const; + +private: + // I would prefer to have a smart pointer to DataSet but DataSet does not derive from Object... + SmartPointer F; + CryptographicMessageSyntax *CMS; + + typedef std::pair< Tag, std::string > TagValueKey; + typedef std::map< TagValueKey, std::string > DummyMapNonUIDTags; + typedef std::map< std::string, std::string > DummyMapUIDTags; + static DummyMapNonUIDTags dummyMapNonUIDTags; + static DummyMapUIDTags dummyMapUIDTags; +}; + +/** + * \example ManipulateFile.cs + * \example ClinicalTrialIdentificationWorkflow.cs + * This is a C# example on how to use gdcm::Anonymizer + */ + +} // end namespace gdcm + +#endif //GDCMANONYMIZER_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmApplicationEntity.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmApplicationEntity.cxx new file mode 100644 index 0000000..1233716 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmApplicationEntity.cxx @@ -0,0 +1,17 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmApplicationEntity.h" + +namespace gdcm +{} diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmApplicationEntity.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmApplicationEntity.h new file mode 100644 index 0000000..e7fd8c2 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmApplicationEntity.h @@ -0,0 +1,62 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMAPPLICATIONENTITY_H +#define GDCMAPPLICATIONENTITY_H + +#include "gdcmTypes.h" +#include +#include // abort + +namespace gdcm +{ + +/** + * \brief ApplicationEntity + * - AE Application Entity + * - A string of characters that identifies an Application Entity with leading + * and trailing spaces (20H) being non-significant. A value consisting solely + * of spaces shall not be used. + * - Default Character Repertoire excluding character code 5CH (the BACKSLASH \ in + * ISO-IR 6), and control characters LF, FF, CR and ESC. + * - 16 bytes maximum + */ +class GDCM_EXPORT ApplicationEntity +{ +public: + static const unsigned int MaxNumberOfComponents = 1; + static const unsigned int MaxLength = 16; + std::string Internal; + static const char Separator = ' '; + static const char Padding = ' '; + //static const char Excluded[5] = { '\\' /* 5CH */, '\n' /* LF */, '\f', /* FF */, '\r' /* CR */, 0x1b /* ESC */}; + + bool IsValid() const { + return true; + } + void Squeeze() { + // trim leading and trailing white spaces + } + void SetBlob(const std::vector& v) { + (void)v; + assert(0); //TODO + } + void Print(std::ostream &os) const { + (void)os; + assert(0); //TODO + } +}; + +} // end namespace gdcm + +#endif //GDCMAPPLICATIONENTITY_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmAudioCodec.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmAudioCodec.cxx new file mode 100644 index 0000000..bc33baa --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmAudioCodec.cxx @@ -0,0 +1,34 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmAudioCodec.h" +#include "gdcmDataElement.h" + +namespace gdcm +{ + +AudioCodec::AudioCodec() +{ +} + +AudioCodec::~AudioCodec() +{ +} + +bool AudioCodec::Decode(DataElement const &is, DataElement &os) +{ + os = is; + return true; +} + +} diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmAudioCodec.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmAudioCodec.h new file mode 100644 index 0000000..bfa303c --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmAudioCodec.h @@ -0,0 +1,37 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMAUDIOCODEC_H +#define GDCMAUDIOCODEC_H + +#include "gdcmCodec.h" + +namespace gdcm +{ + +/** + * \brief AudioCodec + */ +class GDCM_EXPORT AudioCodec : public Codec +{ +public: + AudioCodec(); + ~AudioCodec(); + bool CanCode(TransferSyntax const &) const { return false; } + bool CanDecode(TransferSyntax const &) const { return false; } + bool Decode(DataElement const &is, DataElement &os); +}; + +} // end namespace gdcm + +#endif //GDCMAUDIOCODEC_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmBitmap.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmBitmap.cxx new file mode 100644 index 0000000..d39a854 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmBitmap.cxx @@ -0,0 +1,951 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmBitmap.h" +#include "gdcmSequenceOfFragments.h" +#include "gdcmRAWCodec.h" +#include "gdcmJPEGCodec.h" +#include "gdcmPVRGCodec.h" +#include "gdcmKAKADUCodec.h" +#include "gdcmJPEGLSCodec.h" +#include "gdcmJPEG2000Codec.h" +#include "gdcmRLECodec.h" + +#include + +namespace gdcm +{ +/* + * PICKER-16-MONO2-Nested_icon.dcm: +(0088,0200) SQ (Sequence with undefined length #=1) # u/l, 1 BitmapSequence + (fffe,e000) na (Item with undefined length #=10) # u/l, 1 Item + (0028,0002) US 1 # 2, 1 SamplesPerPixel + (0028,0004) CS [MONOCHROME2] # 12, 1 PhotometricInterpretation + (0028,0010) US 64 # 2, 1 Rows + (0028,0011) US 64 # 2, 1 Columns + (0028,0034) IS [1\1] # 4, 2 PixelAspectRatio + (0028,0100) US 8 # 2, 1 BitsAllocated + (0028,0101) US 8 # 2, 1 BitsStored + (0028,0102) US 7 # 2, 1 HighBit + (0028,0103) US 0 # 2, 1 PixelRepresentation + (7fe0,0010) OW 0000\0000\0000\0000\0000\0000\0000\0000\0000\0000\0000\0000\0000... # 4096, 1 PixelData + (fffe,e00d) na (ItemDelimitationItem) # 0, 0 ItemDelimitationItem +(fffe,e0dd) na (SequenceDelimitationItem) # 0, 0 SequenceDelimitationItem +*/ + +Bitmap::Bitmap(): + PlanarConfiguration(0), + NumberOfDimensions(2), + TS(), + PF(), + PI(), + Dimensions(), + PixelData(), + LUT(new LookupTable), + NeedByteSwap(false), + LossyFlag(false) +{} + +Bitmap::~Bitmap() {} + +/* + * Internal implementation everything assume that NumberOfDimensions was set + */ +unsigned int Bitmap::GetNumberOfDimensions() const +{ + assert( NumberOfDimensions ); + return NumberOfDimensions; +} + +void Bitmap::SetNumberOfDimensions(unsigned int dim) +{ + NumberOfDimensions = dim; + assert( NumberOfDimensions ); + Dimensions.resize( 3 /*NumberOfDimensions*/ ); // fill with 0 + assert( NumberOfDimensions == 2 || NumberOfDimensions == 3 ); + if( NumberOfDimensions == 2 ) + { + Dimensions[2] = 1; + //Spacing[2] = 1; + } +} + +const unsigned int *Bitmap::GetDimensions() const +{ + assert( NumberOfDimensions ); + return &Dimensions[0]; +} + +unsigned int Bitmap::GetDimension(unsigned int idx) const +{ + assert( NumberOfDimensions ); + return Dimensions[idx]; +} + +void Bitmap::SetDimensions(const unsigned int *dims) +{ + assert( NumberOfDimensions ); + //assert( Dimensions.empty() ); + Dimensions = std::vector(dims, + dims+NumberOfDimensions); +} + +void Bitmap::SetDimension(unsigned int idx, unsigned int dim) +{ + //assert( dim ); + assert( NumberOfDimensions ); + assert( idx < NumberOfDimensions ); + Dimensions.resize( 3 /*NumberOfDimensions*/ ); + // Can dim be 0 ?? + // -> no ! + //assert( dim ); // PhilipsLosslessRice.dcm + Dimensions[idx] = dim; + if( NumberOfDimensions == 2 ) + { + Dimensions[2] = 1; + } +} + +// TODO does it make sense to PlanarConfiguration in Bitmap +// and SamplesPerPixel in PixelFormat when those two are linked... +unsigned int Bitmap::GetPlanarConfiguration() const +{ + if( PlanarConfiguration && PF.GetSamplesPerPixel() != 3 ) + { + assert(0); + // LEADTOOLS_FLOWERS-8-PAL-RLE.dcm + // User specify PlanarConfiguration whereas SamplesPerPixel != 3 + gdcmWarningMacro( + "Can't set PlanarConfiguration if SamplesPerPixel is not 3" ); + // Let's assume it's this way... + return 0; + } + return PlanarConfiguration; +} + +void Bitmap::SetPlanarConfiguration(unsigned int pc) +{ + // precondition + assert( pc == 0 || pc == 1 ); + PlanarConfiguration = pc; + if( pc ) + { + // LEADTOOLS_FLOWERS-8-MONO2-Uncompressed.dcm + if( PF.GetSamplesPerPixel() != 3 ) // Please set PixelFormat first + { + gdcmWarningMacro( "Cant have Planar Configuration in non RGB input. Discarding" ); + PlanarConfiguration = 0; + } + const TransferSyntax &ts = GetTransferSyntax(); + if( ts == TransferSyntax::JPEGBaselineProcess1 + || ts == TransferSyntax::JPEGExtendedProcess2_4 + || ts == TransferSyntax::JPEGExtendedProcess3_5 + || ts == TransferSyntax::JPEGSpectralSelectionProcess6_8 + || ts == TransferSyntax::JPEGFullProgressionProcess10_12 + || ts == TransferSyntax::JPEGLosslessProcess14 + || ts == TransferSyntax::JPEGLosslessProcess14_1 + || ts == TransferSyntax::JPEGLSLossless + || ts == TransferSyntax::JPEGLSNearLossless + || ts == TransferSyntax::JPEG2000Lossless + || ts == TransferSyntax::JPEG2000 + || ts == TransferSyntax::JPIPReferenced + ) + { + // PS 3.6 - 2011 8.2.4 JPEG 2000 IMAGE COMPRESSION + // The value of Planar Configuration (0028,0006) is irrelevant since the + // manner of encoding components is specified in the JPEG 2000 standard, + // hence it shall be set to 0. + // By extension, this behavior has been applied also to JPEG and JPEG-LS + gdcmWarningMacro( "Cant have Planar Configuration in JPEG/JPEG-LS/JPEG 2000. Discarding" ); + PlanarConfiguration = 0; + } + } + // \postcondition + assert( PlanarConfiguration == 0 || PlanarConfiguration == 1 ); +} + + + +void Bitmap::Clear() +{ + Dimensions.clear(); +} + +const PhotometricInterpretation &Bitmap::GetPhotometricInterpretation() const +{ + return PI; +} + +void Bitmap::SetPhotometricInterpretation( + PhotometricInterpretation const &pi) +{ + PI = pi; +} + +#if 0 +bool Bitmap::GetBuffer(char *buffer) const +{ + if( IsEmpty() ) + { + buffer = 0; + return false; + } + + const ByteValue *bv = PixelData.GetByteValue(); + if( !bv ) + { + // KODAK_CompressedIcon.dcm + // contains a compressed Icon Sequence, one has to guess this is lossless jpeg... +#ifdef MDEBUG + const SequenceOfFragments *sqf = PixelData.GetSequenceOfFragments(); + std::ofstream os( "/tmp/kodak.ljpeg", std::ios::binary); + sqf->WriteBuffer( os ); +#endif + gdcmWarningMacro( "Compressed Icon are not support for now" ); + buffer = 0; + return false; + } + assert( bv ); + RAWCodec codec; + //assert( GetPhotometricInterpretation() == PhotometricInterpretation::MONOCHROME2 ); + //codec.SetPhotometricInterpretation( GetPhotometricInterpretation() ); + if( GetPhotometricInterpretation() != PhotometricInterpretation::MONOCHROME2 ) + { + gdcmWarningMacro( "PhotometricInterpretation: " << GetPhotometricInterpretation() << " not handled for now" ); + } + codec.SetPhotometricInterpretation( PhotometricInterpretation::MONOCHROME2 ); + codec.SetPixelFormat( GetPixelFormat() ); + codec.SetPlanarConfiguration( 0 ); + DataElement out; + bool r = codec.Decode(PixelData, out); + assert( r ); + const ByteValue *outbv = out.GetByteValue(); + assert( outbv ); + //unsigned long check = outbv->GetLength(); // FIXME + memcpy(buffer, outbv->GetPointer(), outbv->GetLength() ); // FIXME + return r; +} +#endif + +unsigned long Bitmap::GetBufferLength() const +{ + //assert( !IsEncapsulated() ); + if( PF == PixelFormat::UNKNOWN ) return 0; + + assert( NumberOfDimensions ); + //assert( NumberOfDimensions == Dimensions.size() ); + if( NumberOfDimensions != Dimensions.size() ) + { + assert( Dimensions[2] == 1 ); + } + unsigned long len = 0; + unsigned int mul = 1; + // First multiply the dimensions: + std::vector::const_iterator it = Dimensions.begin(); + for(; it != Dimensions.end(); ++it) + { + assert( *it ); + mul *= *it; + } + // Multiply by the pixel size: + // Special handling of packed format: + if( PF == PixelFormat::UINT12 || PF == PixelFormat::INT12 ) + { +#if 1 + mul *= PF.GetPixelSize(); +#else + assert( PF.GetSamplesPerPixel() == 1 ); + unsigned int save = mul; + save *= 12; + save /= 8; + assert( save * 8 / 12 == mul ); + mul = save; +#endif + } + else if( PF == PixelFormat::SINGLEBIT ) + { + assert( PF.GetSamplesPerPixel() == 1 ); + unsigned int save = mul; + save /= 8; + assert( save * 8 == mul ); + mul = save; + } + else if( PF.GetBitsAllocated() % 8 != 0 ) + { + // gdcmDataExtra/gdcmSampleData/images_of_interest/USBitsAllocated14.dcm + // BitsAllocated :14 + // BitsStored :14 + // HighBit :13 + assert( PF.GetSamplesPerPixel() == 1 ); + const ByteValue *bv = PixelData.GetByteValue(); + assert( bv ); + unsigned int ref = bv->GetLength() / mul; + if( !GetTransferSyntax().IsEncapsulated() ) + assert( bv->GetLength() % mul == 0 ); + mul *= ref; + } + else + { + mul *= PF.GetPixelSize(); + } + len = mul; + + assert( len != 0 ); + return len; +} + +bool Bitmap::TryRAWCodec(char *buffer, bool &lossyflag) const +{ + RAWCodec codec; + const TransferSyntax &ts = GetTransferSyntax(); + if(!buffer) + { + if( codec.CanDecode( ts ) ) // short path + { + lossyflag = false; + return true; + } + return false; + } + + const ByteValue *bv = PixelData.GetByteValue(); + if( bv ) + { + unsigned long len = GetBufferLength(); + if( !codec.CanDecode( ts ) ) return false; + codec.SetPlanarConfiguration( GetPlanarConfiguration() ); + codec.SetPhotometricInterpretation( GetPhotometricInterpretation() ); + codec.SetLUT( GetLUT() ); + codec.SetPixelFormat( GetPixelFormat() ); + codec.SetNeedByteSwap( GetNeedByteSwap() ); + codec.SetNeedOverlayCleanup( AreOverlaysInPixelData() ); + DataElement out; + //bool r = codec.Decode(PixelData, out); + bool r = codec.DecodeBytes(bv->GetPointer(), bv->GetLength(), + buffer, len); + if( !r ) return false; + //const ByteValue *outbv = out.GetByteValue(); + //assert( outbv ); + if( len != bv->GetLength() ) + { + // SIEMENS_GBS_III-16-ACR_NEMA_1.acr + // This is also handling the famous DermaColorLossLess.dcm issue + // where RGB image is odd length (GetBufferLength()) but + // ByteValue::GetLength is rounded up to the next even byte length + // gdcmDebugMacro( "Pixel Length " << bv->GetLength() << + // " is different from computed value " << len ); + // ((ByteValue*)outbv)->SetLength( len ); + } +#if 0 + if ( GetPixelFormat() != codec.GetPixelFormat() ) + { + gdcm::Bitmap *i = (gdcm::Bitmap*)this; + i->SetPixelFormat( codec.GetPixelFormat() ); + } +#endif + + unsigned long check; // = outbv->GetLength(); // FIXME + check = len; + // DermaColorLossLess.dcm + assert( check == len || check == len + 1 ); + (void)check;// removing warning + //if(buffer) memcpy(buffer, outbv->GetPointer(), outbv->GetLength() ); // FIXME + return r; + } + return false; +} + +bool Bitmap::TryJPEGCodec(char *buffer, bool &lossyflag) const +{ + JPEGCodec codec; + const TransferSyntax &ts = GetTransferSyntax(); + if(!buffer) + { + if( codec.CanDecode( ts ) ) // short path + { + TransferSyntax ts2; + const SequenceOfFragments *sf = PixelData.GetSequenceOfFragments(); + if( !sf ) return false; + const Fragment &frag = sf->GetFragment(0); + const ByteValue &bv2 = dynamic_cast(frag.GetValue()); + gdcm::PixelFormat pf = GetPixelFormat(); // gdcm::PixelFormat::UINT8; + codec.SetPixelFormat( pf ); + + std::stringstream ss; + ss.write( bv2.GetPointer(), bv2.GetLength() ); + bool b = codec.GetHeaderInfo( ss, ts2 ); + //bool b = codec.GetHeaderInfo( bv2.GetPointer(), bv2.GetLength() , ts2 ); + if(!b) return false; + assert( b ); + lossyflag = codec.IsLossy(); + // we need to know the actual pixeltype after ::Read +#if 0 + if( codec.GetPixelFormat() != GetPixelFormat() ) + { + gdcm::Bitmap *i = (gdcm::Bitmap*)this; + i->SetPixelFormat( codec.GetPixelFormat() ); + } +#endif + + return true; + } + return false; + } + + if( codec.CanDecode( ts ) ) + { + unsigned long len = GetBufferLength(); + codec.SetNumberOfDimensions( GetNumberOfDimensions() ); + codec.SetDimensions( GetDimensions() ); + codec.SetPlanarConfiguration( GetPlanarConfiguration() ); + codec.SetPhotometricInterpretation( GetPhotometricInterpretation() ); + codec.SetPixelFormat( GetPixelFormat() ); + codec.SetNeedOverlayCleanup( AreOverlaysInPixelData() ); + DataElement out; + bool r = codec.Decode(PixelData, out); + // PHILIPS_Gyroscan-12-MONO2-Jpeg_Lossless.dcm + if( !r ) + { + return false; + } + // FIXME ! This should be done all the time for all codec: + // Did PI change or not ? + if ( GetPlanarConfiguration() != codec.GetPlanarConfiguration() ) + { + gdcm::Bitmap *i = (gdcm::Bitmap*)this; (void)i; + //i->SetPlanarConfiguration( codec.GetPlanarConfiguration() ); + } + // I cannot re-activate the following since I would loose the palette color information + // (this is not stored in the JPEG header). + //if ( GetPhotometricInterpretation() != codec.GetPhotometricInterpretation() ) + // { + // // HACK + // // YBRisGray.dcm + // gdcm::Bitmap *i = (gdcm::Bitmap*)this; + // i->SetPhotometricInterpretation( codec.GetPhotometricInterpretation() ); + // } +#if 1 + if ( GetPixelFormat() != codec.GetPixelFormat() ) + { + // gdcmData/DCMTK_JPEGExt_12Bits.dcm + assert( GetPixelFormat().GetPixelRepresentation() == + codec.GetPixelFormat().GetPixelRepresentation() ); +// assert( GetPixelFormat().GetBitsStored() == +// codec.GetPixelFormat().GetBitsStored() ); + assert( GetPixelFormat().GetBitsAllocated() == 12 ); + gdcm::Bitmap *i = (gdcm::Bitmap*)this; + i->SetPixelFormat( codec.GetPixelFormat() ); + } +#endif + //if ( GetPhotometricInterpretation() == PhotometricInterpretation::YBR_FULL_422 + //|| GetPhotometricInterpretation() == PhotometricInterpretation::YBR_FULL ) + // { + // gdcm::Bitmap *i = (gdcm::Bitmap*)this; + // i->SetPhotometricInterpretation( PhotometricInterpretation::RGB ); + // } + const ByteValue *outbv = out.GetByteValue(); + assert( outbv ); + unsigned long check = outbv->GetLength(); // FIXME + (void)check; + // DermaColorLossLess.dcm has a len of 63531, but DICOM will give us: 63532 ... + if( len > outbv->GetLength() ) + { + gdcmErrorMacro( "Impossible length: " << len << " should be (max): " << outbv->GetLength() ); + return false; + } + assert( len <= outbv->GetLength() ); + if(buffer) memcpy(buffer, outbv->GetPointer(), len /*outbv->GetLength()*/ ); // FIXME + + lossyflag = codec.IsLossy(); + //assert( codec.IsLossy() == ts.IsLossy() ); + + return true; + } + return false; +} + +bool Bitmap::TryJPEGCodec2(std::ostream &os) const +{ + unsigned long len = GetBufferLength(); + const TransferSyntax &ts = GetTransferSyntax(); + + JPEGCodec codec; + if( codec.CanCode( ts ) ) + { + codec.SetDimensions( GetDimensions() ); + codec.SetPlanarConfiguration( GetPlanarConfiguration() ); + codec.SetPhotometricInterpretation( GetPhotometricInterpretation() ); + codec.SetPixelFormat( GetPixelFormat() ); + codec.SetNeedOverlayCleanup( AreOverlaysInPixelData() ); + DataElement out; + bool r = codec.Code(PixelData, out); + // PHILIPS_Gyroscan-12-MONO2-Jpeg_Lossless.dcm + if( !r ) + { + return false; + } + // FIXME ! This should be done all the time for all codec: + // Did PI change or not ? + if ( GetPhotometricInterpretation() != codec.GetPhotometricInterpretation() ) + { + // HACK + //gdcm::Bitmap *i = (gdcm::Bitmap*)this; + //i->SetPhotometricInterpretation( codec.GetPhotometricInterpretation() ); + } + const ByteValue *outbv = out.GetByteValue(); + assert( outbv ); + unsigned long check = outbv->GetLength(); // FIXME + (void)check; + // DermaColorLossLess.dcm has a len of 63531, but DICOM will give us: 63532 ... + assert( outbv->GetLength() < len ); (void)len; + //memcpy(buffer, outbv->GetPointer(), outbv->GetLength() ); + os.write( outbv->GetPointer(), outbv->GetLength() ); + + return true; + } + return false; +} + +bool Bitmap::TryPVRGCodec(char *buffer, bool &lossyflag) const +{ + unsigned long len = GetBufferLength(); + const TransferSyntax &ts = GetTransferSyntax(); + + PVRGCodec codec; + if( codec.CanDecode( ts ) ) + { + codec.SetPixelFormat( GetPixelFormat() ); + //codec.SetBufferLength( len ); + //codec.SetNumberOfDimensions( GetNumberOfDimensions() ); + codec.SetPlanarConfiguration( GetPlanarConfiguration() ); + codec.SetPhotometricInterpretation( GetPhotometricInterpretation() ); + codec.SetNeedOverlayCleanup( AreOverlaysInPixelData() ); + codec.SetDimensions( GetDimensions() ); + DataElement out; + bool r = codec.Decode(PixelData, out); + if(!r) return false; + codec.SetLossyFlag( ts.IsLossy() ); + assert( r ); + if ( GetPlanarConfiguration() != codec.GetPlanarConfiguration() ) + { + gdcm::Bitmap *i = (gdcm::Bitmap*)this; + i->PlanarConfiguration = codec.GetPlanarConfiguration(); + } + const ByteValue *outbv = out.GetByteValue(); + assert( outbv ); + unsigned long check = outbv->GetLength(); // FIXME + (void)check; + assert( len <= outbv->GetLength() ); + if(buffer) memcpy(buffer, outbv->GetPointer(), len /*outbv->GetLength()*/ ); // FIXME + + lossyflag = codec.IsLossy(); + //assert( codec.IsLossy() == ts.IsLossy() ); + + return r; + } + return false; +} + +bool Bitmap::TryKAKADUCodec(char *buffer, bool &lossyflag) const +{ + unsigned long len = GetBufferLength(); + const TransferSyntax &ts = GetTransferSyntax(); + + KAKADUCodec codec; + if( codec.CanDecode( ts ) ) + { + codec.SetPixelFormat( GetPixelFormat() ); + //codec.SetBufferLength( len ); + codec.SetNumberOfDimensions( GetNumberOfDimensions() ); + codec.SetPlanarConfiguration( GetPlanarConfiguration() ); + codec.SetPhotometricInterpretation( GetPhotometricInterpretation() ); + codec.SetNeedOverlayCleanup( AreOverlaysInPixelData() ); + codec.SetDimensions( GetDimensions() ); + DataElement out; + bool r = codec.Decode(PixelData, out); + if( !r ) return false; + const ByteValue *outbv = out.GetByteValue(); + assert( outbv ); + unsigned long check = outbv->GetLength(); // FIXME + (void)check; + assert( len <= outbv->GetLength() ); + // DermaColorLossLess.dcm has a len of 63531, but DICOM will give us: 63532 ... + assert( len <= outbv->GetLength() ); + if(buffer) memcpy(buffer, outbv->GetPointer(), len /*outbv->GetLength()*/ ); // FIXME + + //assert( codec.IsLossy() == ts.IsLossy() ); + lossyflag = codec.IsLossy(); + if( codec.IsLossy() != ts.IsLossy() ) + { + gdcmErrorMacro( "EVIL file, it is declared as lossless but is in fact lossy." ); + } + + return r; + } + return false; +} + +bool Bitmap::TryJPEGLSCodec(char *buffer, bool &lossyflag) const +{ + JPEGLSCodec codec; + const TransferSyntax &ts = GetTransferSyntax(); + if(!buffer) + { + if( codec.CanDecode( ts ) ) // short path + { + TransferSyntax ts2; + const SequenceOfFragments *sf = PixelData.GetSequenceOfFragments(); + if( !sf ) return false; + const Fragment &frag = sf->GetFragment(0); + const ByteValue &bv2 = dynamic_cast(frag.GetValue()); + + std::stringstream ss; + ss.write( bv2.GetPointer(), bv2.GetLength() ); + bool b = codec.GetHeaderInfo( ss, ts2 ); + //bool b = codec.GetHeaderInfo( bv2.GetPointer(), bv2.GetLength() , ts2 ); + if( !b ) return false; + lossyflag = codec.IsLossy(); + // we need to know the actual pixeltype after ::Read +#if 0 +// This is actually very dangerous to change the pixel format right here. What if +// user stored a 16/10/9 signed image using JPEG-LS, JPEG-LS would be required to use +// the full spectrum of the unsigned short 16 bits range to store that image and would +// therefore -rightfully- declared as 16 bits... + if( codec.GetPixelFormat() != GetPixelFormat() ) + { + gdcm::Bitmap *i = (gdcm::Bitmap*)this; + i->SetPixelFormat( codec.GetPixelFormat() ); + } +#endif + + return true; + } + return false; + } + + + if( codec.CanDecode( ts ) ) + { + unsigned long len = GetBufferLength(); + codec.SetPixelFormat( GetPixelFormat() ); + codec.SetBufferLength( len ); + codec.SetNumberOfDimensions( GetNumberOfDimensions() ); + codec.SetPlanarConfiguration( GetPlanarConfiguration() ); + codec.SetPhotometricInterpretation( GetPhotometricInterpretation() ); + codec.SetNeedOverlayCleanup( AreOverlaysInPixelData() ); + codec.SetDimensions( GetDimensions() ); + DataElement out; + bool r = codec.Decode(PixelData, out); + if( !r ) return false; + const ByteValue *outbv = out.GetByteValue(); + assert( outbv ); + unsigned long check = outbv->GetLength(); // FIXME + (void)check; + assert( len <= outbv->GetLength() ); + // DermaColorLossLess.dcm has a len of 63531, but DICOM will give us: 63532 ... + assert( len <= outbv->GetLength() ); + if(buffer) memcpy(buffer, outbv->GetPointer(), len /*outbv->GetLength()*/ ); // FIXME + + //assert( codec.IsLossy() == ts.IsLossy() ); + lossyflag = codec.IsLossy(); + if( codec.IsLossy() != ts.IsLossy() ) + { + gdcmErrorMacro( "EVIL file, it is declared as lossless but is in fact lossy." ); + } + + return r; + } + return false; +} + +bool Bitmap::IsLossy() const +{ + // FIXME each call is expensive... + //bool lossyflag; + //if( this->GetBufferInternal(0, lossyflag) ) + // { + // return lossyflag; + // } + //return false; + return LossyFlag; +} + +bool Bitmap::ComputeLossyFlag() +{ + bool lossyflag; + if( this->GetBufferInternal(0, lossyflag) ) + { + LossyFlag = lossyflag; + return true; + } + LossyFlag = false; + return false; +} + +bool Bitmap::TryJPEG2000Codec(char *buffer, bool &lossyflag) const +{ + JPEG2000Codec codec; + const TransferSyntax &ts = GetTransferSyntax(); + if(!buffer) + { + if( codec.CanDecode( ts ) ) // short path + { + TransferSyntax ts2; + const SequenceOfFragments *sf = PixelData.GetSequenceOfFragments(); + if( !sf ) return false; + const Fragment &frag = sf->GetFragment(0); + const ByteValue &bv2 = dynamic_cast(frag.GetValue()); + + bool b = codec.GetHeaderInfo( bv2.GetPointer(), bv2.GetLength() , ts2 ); + if( !b ) return false; + lossyflag = codec.IsLossy(); + // we need to know the actual pixeltype after ::Read +#if 0 + if( codec.GetPixelFormat() != GetPixelFormat() ) + { + // Because J2K support the full spectrum I do not see any issue + // with the following: + gdcm::Bitmap *i = (gdcm::Bitmap*)this; + i->SetPixelFormat( codec.GetPixelFormat() ); + } +#else + // lets only check the only issue we have: + // OsirixFake16BitsStoredFakeSpacing.dcm + const PixelFormat & cpf = codec.GetPixelFormat(); + const PixelFormat & pf = GetPixelFormat(); + if( cpf.GetBitsAllocated() == pf.GetBitsAllocated() ) + { + if( cpf.GetPixelRepresentation() == pf.GetPixelRepresentation() ) + { + if( cpf.GetSamplesPerPixel() == pf.GetSamplesPerPixel() ) + { + if( cpf.GetBitsStored() < pf.GetBitsStored() ) + { + gdcm::Bitmap *i = (gdcm::Bitmap*)this; + gdcmWarningMacro( "Encapsulated stream has fewer bits actually stored on disk. correcting." ); + i->GetPixelFormat().SetBitsStored( cpf.GetBitsStored() ); + } + } + } + } +#endif + + return true; + } + return false; + } + + if( codec.CanDecode( ts ) ) + { + unsigned long len = GetBufferLength(); + codec.SetPixelFormat( GetPixelFormat() ); + codec.SetNumberOfDimensions( GetNumberOfDimensions() ); + codec.SetPlanarConfiguration( GetPlanarConfiguration() ); + codec.SetPhotometricInterpretation( GetPhotometricInterpretation() ); + codec.SetNeedOverlayCleanup( AreOverlaysInPixelData() ); + codec.SetDimensions( GetDimensions() ); + DataElement out; + bool r = codec.Decode(PixelData, out); + if(!r) return false; + assert( r ); + const ByteValue *outbv = out.GetByteValue(); + assert( outbv ); + unsigned long check = outbv->GetLength(); // FIXME + (void)check; + assert( len <= outbv->GetLength() ); + if(buffer) memcpy(buffer, outbv->GetPointer(), len /*outbv->GetLength()*/ ); // FIXME + + lossyflag = codec.IsLossy(); + if( codec.IsLossy() && !ts.IsLossy() ) + { + assert( codec.IsLossy() ); + assert( !ts.IsLossy() ); + gdcmErrorMacro( "EVIL file, it is declared as lossless but is in fact lossy." ); + } +#if 0 + if( codec.GetPixelFormat() != GetPixelFormat() ) + { + gdcm::Bitmap *i = (gdcm::Bitmap*)this; + i->SetPixelFormat( codec.GetPixelFormat() ); + } +#else + // lets only check the only issue we have: + // OsirixFake16BitsStoredFakeSpacing.dcm + const PixelFormat & cpf = codec.GetPixelFormat(); + const PixelFormat & pf = GetPixelFormat(); + if( cpf.GetBitsAllocated() == pf.GetBitsAllocated() ) + { + if( cpf.GetPixelRepresentation() == pf.GetPixelRepresentation() ) + { + if( cpf.GetSamplesPerPixel() == pf.GetSamplesPerPixel() ) + { + if( cpf.GetBitsStored() < pf.GetBitsStored() ) + { + gdcm::Bitmap *i = (gdcm::Bitmap*)this; + gdcmWarningMacro( "Encapsulated stream has fewer bits actually stored on disk. correcting." ); + i->GetPixelFormat().SetBitsStored( cpf.GetBitsStored() ); + } + } + } + } + +#endif + return r; + } + return false; +} + +bool Bitmap::TryJPEG2000Codec2(std::ostream &os) const +{ + unsigned long len = GetBufferLength(); + (void)len; + const TransferSyntax &ts = GetTransferSyntax(); + + JPEG2000Codec codec; + if( codec.CanCode( ts ) ) + { + codec.SetDimensions( GetDimensions() ); + codec.SetPixelFormat( GetPixelFormat() ); + codec.SetNumberOfDimensions( GetNumberOfDimensions() ); + codec.SetPlanarConfiguration( GetPlanarConfiguration() ); + codec.SetPhotometricInterpretation( GetPhotometricInterpretation() ); + codec.SetNeedOverlayCleanup( AreOverlaysInPixelData() ); + DataElement out; + bool r = codec.Code(PixelData, out); + assert( r ); + const ByteValue *outbv = out.GetByteValue(); + assert( outbv ); + unsigned long check = outbv->GetLength(); // FIXME + (void)check; + //memcpy(buffer, outbv->GetPointer(), outbv->GetLength() ); // FIXME + os.write(outbv->GetPointer(), outbv->GetLength() ); + return r; + } + return false; +} + +bool Bitmap::TryRLECodec(char *buffer, bool &lossyflag ) const +{ + unsigned long len = GetBufferLength(); + const TransferSyntax &ts = GetTransferSyntax(); + + RLECodec codec; + if( codec.CanDecode( ts ) ) + { + //assert( sf->GetNumberOfFragments() == 1 ); + //assert( sf->GetNumberOfFragments() == GetDimensions(2) ); + codec.SetDimensions( GetDimensions() ); + codec.SetNumberOfDimensions( GetNumberOfDimensions() ); + codec.SetPlanarConfiguration( GetPlanarConfiguration() ); + codec.SetPhotometricInterpretation( GetPhotometricInterpretation() ); + codec.SetPixelFormat( GetPixelFormat() ); + codec.SetLUT( GetLUT() ); + codec.SetNeedOverlayCleanup( AreOverlaysInPixelData() ); + codec.SetBufferLength( len ); + DataElement out; + bool r = codec.Decode(PixelData, out); + if( !r ) return false; + const ByteValue *outbv = out.GetByteValue(); + //unsigned long check = outbv->GetLength(); // FIXME + // DermaColorLossLess.dcm has a len of 63531, but DICOM will give us: 63532 ... + assert( len <= outbv->GetLength() ); + if(buffer) memcpy(buffer, outbv->GetPointer(), len /*outbv->GetLength()*/ ); // FIXME + lossyflag = false; + return true; + } + return false; +} + +// Acces the raw data +bool Bitmap::GetBuffer(char *buffer) const +{ + bool dummy; + return GetBufferInternal(buffer, dummy); +} + +bool Bitmap::GetBufferInternal(char *buffer, bool &lossyflag) const +{ + bool success = false; + if( !success ) success = TryRAWCodec(buffer, lossyflag); + if( !success ) success = TryJPEGCodec(buffer, lossyflag); + if( !success ) success = TryPVRGCodec(buffer, lossyflag); // AFTER IJG trial ! + //if( !success ) success = TryKAKADUCodec(buffer, lossyflag); + if( !success ) success = TryJPEG2000Codec(buffer, lossyflag); + if( !success ) success = TryJPEGLSCodec(buffer, lossyflag); + if( !success ) success = TryRLECodec(buffer, lossyflag); + //if( !success ) success = TryDeltaEncodingCodec(buffer); + if( !success ) + { + buffer = 0; + //throw Exception( "No codec found for this image"); + } + + return success; +} + +// Compress the raw data +bool Bitmap::GetBuffer2(std::ostream &os) const +{ + bool success = false; + //if( !success ) success = TryRAWCodec2(buffer); + if( !success ) success = TryJPEGCodec2(os); + //if( !success ) success = TryJPEG2000Codec2(os); + //if( !success ) success = TryRLECodec2(buffer); + if( !success ) + { + //buffer = 0; + throw Exception( "No codec found for this image"); + } + + return success; +} + +bool Bitmap::IsTransferSyntaxCompatible( TransferSyntax const & ts ) const +{ + if( GetTransferSyntax() == ts ) return true; + // Special cases: + if( GetTransferSyntax() == TransferSyntax::JPEGExtendedProcess2_4 ) + { + if( GetPixelFormat().GetBitsAllocated() == 8 ) + { + if( ts == TransferSyntax::JPEGBaselineProcess1 ) return true; + } + } + // default: + return false; +} + +void Bitmap::Print(std::ostream &os) const +{ + Object::Print(os); + //assert( NumberOfDimensions ); + if( !IsEmpty() ) + { + os << "NumberOfDimensions: " << NumberOfDimensions << "\n"; + assert( Dimensions.size() ); + os << "Dimensions: ("; + std::vector::const_iterator it = Dimensions.begin(); + os << *it; + for(++it; it != Dimensions.end(); ++it) + { + os << "," << *it; + } + os << ")\n"; + PF.Print(os); + os << "PhotometricInterpretation: " << PI << "\n"; + os << "PlanarConfiguration: " << PlanarConfiguration << "\n"; + os << "TransferSyntax: " << TS << "\n"; + } +} + +} diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmBitmap.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmBitmap.h new file mode 100644 index 0000000..6fc6c82 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmBitmap.h @@ -0,0 +1,184 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMBITMAP_H +#define GDCMBITMAP_H + +#include "gdcmObject.h" +#include "gdcmCurve.h" +#include "gdcmDataElement.h" +//#include "gdcmIconImage.h" +#include "gdcmLookupTable.h" +#include "gdcmOverlay.h" +#include "gdcmPhotometricInterpretation.h" +#include "gdcmPixelFormat.h" +#include "gdcmSmartPointer.h" +#include "gdcmTransferSyntax.h" + +#include + +namespace gdcm +{ + +/** + * \brief Bitmap class + * A bitmap based image. Used as parent for both IconImage and the main Pixel Data Image + * It does not contains any World Space information (IPP, IOP) + */ +class GDCM_EXPORT Bitmap : public Object +{ +public: + Bitmap(); + ~Bitmap(); + void Print(std::ostream &) const; + + virtual bool AreOverlaysInPixelData() const { return false; } + + /// Return the number of dimension of the pixel data bytes; for example 2 for a 2D matrices of values + unsigned int GetNumberOfDimensions() const; + void SetNumberOfDimensions(unsigned int dim); + + /// return the planar configuration + unsigned int GetPlanarConfiguration() const; + /// \warning you need to call SetPixelFormat first (before SetPlanarConfiguration) for consistency checking + void SetPlanarConfiguration(unsigned int pc); + + bool GetNeedByteSwap() const + { + return NeedByteSwap; + } + void SetNeedByteSwap(bool b) + { + NeedByteSwap = b; + } + + + /// Transfer syntax + void SetTransferSyntax(TransferSyntax const &ts) { + TS = ts; + } + const TransferSyntax &GetTransferSyntax() const { + return TS; + } + bool IsTransferSyntaxCompatible( TransferSyntax const & ts ) const; + void SetDataElement(DataElement const &de) { + PixelData = de; + } + const DataElement& GetDataElement() const { return PixelData; } + DataElement& GetDataElement() { return PixelData; } + + /// Set/Get LUT + void SetLUT(LookupTable const &lut) + { + LUT = SmartPointer( const_cast(&lut) ); + } + const LookupTable &GetLUT() const + { + return *LUT; + } + LookupTable &GetLUT() + { + return *LUT; + } + + /// Return the dimension of the pixel data, first dimension (x), then 2nd (y), then 3rd (z)... + const unsigned int *GetDimensions() const; + unsigned int GetDimension(unsigned int idx) const; + + void SetColumns(unsigned int col) { SetDimension(0,col); } + unsigned int GetColumns() const { return GetDimension(0); } + void SetRows(unsigned int rows) { SetDimension(1,rows); } + unsigned int GetRows() const { return GetDimension(1); } + void SetDimensions(const unsigned int dims[3]); + void SetDimension(unsigned int idx, unsigned int dim); + /// Get/Set PixelFormat + const PixelFormat &GetPixelFormat() const + { + return PF; + } + PixelFormat &GetPixelFormat() + { + return PF; + } + void SetPixelFormat(PixelFormat const &pf) + { + PF = pf; + PF.Validate(); + } + + /// return the photometric interpretation + const PhotometricInterpretation &GetPhotometricInterpretation() const; + void SetPhotometricInterpretation(PhotometricInterpretation const &pi); + + bool IsEmpty() const { return Dimensions.size() == 0; } + void Clear(); + + /// Return the length of the image after decompression + /// WARNING for palette color: It will NOT take into account the Palette Color + /// thus you need to multiply this length by 3 if computing the size of equivalent RGB image + unsigned long GetBufferLength() const; + + /// Acces the raw data + bool GetBuffer(char *buffer) const; + + /// Return whether or not the image was compressed using a lossy compressor or not + bool IsLossy() const; + + /// Specifically set that the image was compressed using a lossy compression mechanism + void SetLossyFlag(bool f) { LossyFlag = f; } + +protected: + bool TryRAWCodec(char *buffer, bool &lossyflag) const; + bool TryJPEGCodec(char *buffer, bool &lossyflag) const; + bool TryPVRGCodec(char *buffer, bool &lossyflag) const; + bool TryKAKADUCodec(char *buffer, bool &lossyflag) const; + bool TryJPEGLSCodec(char *buffer, bool &lossyflag) const; + bool TryJPEG2000Codec(char *buffer, bool &lossyflag) const; + bool TryRLECodec(char *buffer, bool &lossyflag) const; + + bool TryJPEGCodec2(std::ostream &os) const; + bool TryJPEG2000Codec2(std::ostream &os) const; + + bool GetBuffer2(std::ostream &os) const; + + friend class PixmapReader; + friend class ImageChangeTransferSyntax; + // Function to compute the lossy flag based only on the image buffer. + // Watch out that image can be lossy but in implicit little endian format... + bool ComputeLossyFlag(); + +//private: +protected: + unsigned int PlanarConfiguration; + unsigned int NumberOfDimensions; + TransferSyntax TS; + PixelFormat PF; // SamplesPerPixel, BitsAllocated, BitsStored, HighBit, PixelRepresentation + PhotometricInterpretation PI; + // Mind dump: unsigned int is required here, since we are reading (0028,0008) Number Of Frames + // which is VR::IS, so I cannot simply assumed that unsigned short is enough... :( + std::vector Dimensions; // Col/Row + DataElement PixelData; // copied from 7fe0,0010 + + typedef SmartPointer LUTPtr; + LUTPtr LUT; + // I believe the following 3 ivars can be derived from TS ... + bool NeedByteSwap; + bool LossyFlag; + +private: + bool GetBufferInternal(char *buffer, bool &lossyflag) const; +}; + +} // end namespace gdcm + +#endif //GDCMBITMAP_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmBitmapToBitmapFilter.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmBitmapToBitmapFilter.cxx new file mode 100644 index 0000000..5176bd8 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmBitmapToBitmapFilter.cxx @@ -0,0 +1,58 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmBitmapToBitmapFilter.h" + +#include "gdcmImage.h" + +#include +#include // abort +#include // memcpy + +namespace gdcm +{ + +BitmapToBitmapFilter::BitmapToBitmapFilter() +{ +} + +void BitmapToBitmapFilter::SetInput(const Bitmap& image) +{ + Input = image; + const Bitmap *p = ℑ + if( dynamic_cast(p) ) + { + Output = new Image; + } + else if( dynamic_cast(p) ) + { + Output = new Pixmap; + } + else if( dynamic_cast(p) ) + { + Output = new Bitmap; + } + else + { + Output = NULL; + assert( 0 ); + } +} + +const Bitmap &BitmapToBitmapFilter::GetOutputAsBitmap() const +{ + return *Output; +} + + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmBitmapToBitmapFilter.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmBitmapToBitmapFilter.h new file mode 100644 index 0000000..57134e8 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmBitmapToBitmapFilter.h @@ -0,0 +1,48 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMBITMAPTOBITMAPFILTER_H +#define GDCMBITMAPTOBITMAPFILTER_H + +#include "gdcmBitmap.h" + +namespace gdcm +{ + +/** + * \brief BitmapToBitmapFilter class + * Super class for all filter taking an image and producing an output image + */ +class GDCM_EXPORT BitmapToBitmapFilter +{ +public: + BitmapToBitmapFilter(); + ~BitmapToBitmapFilter() {} + + /// Set input image + void SetInput(const Bitmap& image); + + /// Get Output image + const Bitmap &GetOutput() const { return *Output; } + + // SWIG/Java hack: + const Bitmap &GetOutputAsBitmap() const; + +protected: + SmartPointer Input; + SmartPointer Output; +}; + +} // end namespace gdcm + +#endif //GDCMBITMAPTOBITMAPFILTER_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmCodec.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmCodec.h new file mode 100644 index 0000000..6ab31e6 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmCodec.h @@ -0,0 +1,32 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMCODEC_H +#define GDCMCODEC_H + +#include "gdcmCoder.h" +#include "gdcmDecoder.h" + +namespace gdcm +{ + +/** + * \brief Codec class + */ +class GDCM_EXPORT Codec : public Coder, public Decoder +{ +}; + +} // end namespace gdcm + +#endif //GDCMCODEC_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmCoder.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmCoder.h new file mode 100644 index 0000000..e94d9c4 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmCoder.h @@ -0,0 +1,46 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMCODER_H +#define GDCMCODER_H + +#include "gdcmTypes.h" +#include "gdcmDataElement.h" // FIXME + +namespace gdcm +{ + +class TransferSyntax; +class DataElement; +/** + * \brief Coder + */ +class GDCM_EXPORT Coder +{ +public: + virtual ~Coder() {} + + /// Return whether this coder support this transfer syntax (can code it) + virtual bool CanCode(TransferSyntax const &) const = 0; + + // Note: in / out are reserved keyword in C#. Change to in_ / out_ + + /// Code + virtual bool Code(DataElement const &in_, DataElement &out_) { (void)in_; (void)out_; return false; } +protected: + virtual bool InternalCode(const char *bv, unsigned long len, std::ostream &os) { (void)bv;(void)os;(void)len;return false; } +}; + +} // end namespace gdcm + +#endif //GDCMCODER_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmConstCharWrapper.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmConstCharWrapper.h new file mode 100644 index 0000000..bf8601e --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmConstCharWrapper.h @@ -0,0 +1,53 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMCONSTCHARWRAPPER_H +#define GDCMCONSTCHARWRAPPER_H + +namespace gdcm +{ + +#error + +/* + * This class is a pure hack. Its only goal is to work around a bad bug in : + * $ swig -version + * SWIG Version 1.3.31 + * + * See + * - http://sourceforge.net/mailarchive/forum.php?thread_name=bf0c3b3f0802290552y5163989t76572b80a044ce28%40mail.gmail.com&forum_name=swig-user + * + * As a side note there is also a problem with const reference to enum type: + * - http://sourceforge.net/mailarchive/forum.php?thread_name=bf0c3b3f0802290552y5163989t76572b80a044ce28%40mail.gmail.com&forum_name=swig-user + * + * And to keep a track of isse with swig here is the last one: + * + * - http://sourceforge.net/mailarchive/forum.php?thread_name=bf0c3b3f0802290552y5163989t76572b80a044ce28%40mail.gmail.com&forum_name=swig-user + */ + + +/** + * \brief Do not use me + */ +class ConstCharWrapper +{ +public: + ConstCharWrapper(const char *i=0):Internal(i) {} + operator const char * () const { return Internal; } +private: + const char *Internal; +}; + +} // end namespace gdcm + +#endif //GDCMCONSTCHARWRAPPER_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmCurve.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmCurve.cxx new file mode 100644 index 0000000..f063d98 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmCurve.cxx @@ -0,0 +1,557 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmCurve.h" +#include "gdcmDataElement.h" +#include "gdcmDataSet.h" +#include "gdcmAttribute.h" + +#include + +namespace gdcm +{ +/* + +C.10.2.1 Curve Attribute Descriptions +C.10.2.1.1 Type of data +A description of the Type of Data (50xx,0020) in this curve. +Defined Terms: +TAC = time activity curve PROF = image profile +HIST = histogram ROI = polygraphic region of interest +TABL = table of values FILT = filter kernel +POLY = poly line ECG = ecg data +PRESSURE = pressure data FLOW = flow data +PHYSIO = physio data RESP = Respiration trace +*/ + +class CurveInternal +{ +public: + CurveInternal(): + Group(0), + Dimensions(0), + NumberOfPoints(0), + TypeOfData(), + CurveDescription(), + DataValueRepresentation(0), + Data() {} + +/* +(5004,0000) UL 2316 # 4, 1 CurveGroupLength +(5004,0005) US 1 # 2, 1 CurveDimensions +(5004,0010) US 1126 # 2, 1 NumberOfPoints +(5004,0020) CS [PHYSIO] # 6, 1 TypeOfData +(5004,0022) LO (no value available) # 0, 0 CurveDescription +(5000,0030) SH [DPPS\NONE] # 10, 2 AxisUnits +(5004,0103) US 0 # 2, 1 DataValueRepresentation +(5000,0110) US 0\1 # 4, 2 CurveDataDescriptor +(5000,0112) US 0 # 2, 1 CoordinateStartValue +(5000,0114) US 300 # 2, 1 CoordinateStepValue +(5000,2500) LO [Physio_1] # 8, 1 CurveLabel +(5004,3000) OW 0020\0020\0020\0020\0020\0020\0020\0020\0020\0020\0020\0020\0020... # 2252, 1 CurveData +*/ +// Identifier need to be in the [5000,50FF] range (no odd number): + unsigned short Group; + unsigned short Dimensions; + unsigned short NumberOfPoints; + std::string TypeOfData; + std::string CurveDescription; + unsigned short DataValueRepresentation; + std::vector Data; + std::vector CurveDataDescriptor; + unsigned short CoordinateStartValue; + unsigned short CoordinateStepValue; + void Print(std::ostream &os) const { + os << "Group 0x" << std::hex << Group << std::dec << std::endl; + os << "Dimensions :" << Dimensions << std::endl; + os << "NumberOfPoints :" << NumberOfPoints << std::endl; + os << "TypeOfData :" << TypeOfData << std::endl; + os << "CurveDescription :" << CurveDescription << std::endl; + os << "DataValueRepresentation :" << DataValueRepresentation << std::endl; + unsigned short * p = (unsigned short*)&Data[0]; + for(int i = 0; i < NumberOfPoints; i+=2) + { + os << p[i] << "," << p[i+1] << std::endl; + } + } +}; + +Curve::Curve() +{ + Internal = new CurveInternal; +} + +Curve::~Curve() +{ + delete Internal; +} + +Curve::Curve(Curve const &ov):Object(ov) +{ + //delete Internal; + Internal = new CurveInternal; + // TODO: copy CurveInternal into other... + *Internal = *ov.Internal; +} + +void Curve::Print(std::ostream &os) const +{ + Internal->Print( os ); +} + +unsigned int Curve::GetNumberOfCurves(DataSet const & ds) +{ + Tag overlay(0x5000,0x0000); // First possible overlay + bool finished = false; + unsigned int numoverlays = 0; + while( !finished ) + { + const DataElement &de = ds.FindNextDataElement( overlay ); + if( de.GetTag().GetGroup() > 0x50FF ) // last possible curve + { + finished = true; + } + else if( de.GetTag().IsPrivate() ) + { + // Move on to the next public one: + overlay.SetGroup( (uint16_t)(de.GetTag().GetGroup() + 1) ); + overlay.SetElement( 0 ); // reset just in case... + } + else + { + // Yeah this is an overlay element + //if( ds.FindDataElement( Tag(overlay.GetGroup(),0x3000 ) ) ) + if( ds.FindDataElement( Tag(de.GetTag().GetGroup(),0x3000 ) ) ) + { + // ok so far so good... + //const DataElement& overlaydata = ds.GetDataElement(Tag(overlay.GetGroup(),0x3000)); + const DataElement& overlaydata = ds.GetDataElement(Tag(de.GetTag().GetGroup(),0x3000)); + if( !overlaydata.IsEmpty() ) + { + ++numoverlays; + } + } + // Store found tag in overlay: + overlay = de.GetTag(); + // Move on to the next possible one: + overlay.SetGroup( (uint16_t)(overlay.GetGroup() + 2) ); + // reset to element 0x0 just in case... + overlay.SetElement( 0 ); + } + } + + return numoverlays; +} + +void Curve::Update(const DataElement & de) +{ + assert( de.GetTag().IsPublic() ); + const ByteValue* bv = de.GetByteValue(); + if( !bv ) return; // Discard any empty element (will default to another value) + assert( bv->GetPointer() && bv->GetLength() ); + std::string s( bv->GetPointer(), bv->GetLength() ); + // What if a \0 can be found before the end of string... + //assert( strlen( s.c_str() ) == s.size() ); + + // First thing check consistency: + if( !GetGroup() ) + { + SetGroup( de.GetTag().GetGroup() ); + } + else // check consistency + { + assert( GetGroup() == de.GetTag().GetGroup() ); // programmer error + } + + //std::cerr << "Tag: " << de.GetTag() << std::endl; + if( de.GetTag().GetElement() == 0x0000 ) // CurveGroupLength + { + // ?? + } + else if( de.GetTag().GetElement() == 0x0005 ) // CurveDimensions + { + Attribute<0x5000,0x0005> at; + at.SetFromDataElement( de ); + SetDimensions( at.GetValue() ); + } + else if( de.GetTag().GetElement() == 0x0010 ) // NumberOfPoints + { + Attribute<0x5000,0x0010> at; + at.SetFromDataElement( de ); + SetNumberOfPoints( at.GetValue() ); + } + else if( de.GetTag().GetElement() == 0x0020 ) // TypeOfData + { + SetTypeOfData( s.c_str() ); + } + else if( de.GetTag().GetElement() == 0x0022 ) // CurveDescription + { + SetCurveDescription( s.c_str() ); + } + else if( de.GetTag().GetElement() == 0x0030 ) // AxisUnits + { + gdcmWarningMacro( "TODO" ); + } + else if( de.GetTag().GetElement() == 0x0040 ) // Axis Labels + { + gdcmWarningMacro( "TODO" ); + } + else if( de.GetTag().GetElement() == 0x0103 ) // DataValueRepresentation + { + Attribute<0x5000,0x0103> at; + at.SetFromDataElement( de ); + SetDataValueRepresentation( at.GetValue() ); + } + else if( de.GetTag().GetElement() == 0x0104 ) // Minimum Coordinate Value + { + gdcmWarningMacro( "TODO" ); + } + else if( de.GetTag().GetElement() == 0x0105 ) // Maximum Coordinate Value + { + gdcmWarningMacro( "TODO" ); + } + else if( de.GetTag().GetElement() == 0x0106 ) // Curve Range + { + gdcmWarningMacro( "TODO" ); + } + else if( de.GetTag().GetElement() == 0x0110 ) // CurveDataDescriptor + { + Attribute<0x5000,0x0110> at; + at.SetFromDataElement( de ); + SetCurveDataDescriptor( at.GetValues(), at.GetNumberOfValues() ); + } + else if( de.GetTag().GetElement() == 0x0112 ) // CoordinateStartValue + { + Attribute<0x5000,0x0112> at; + at.SetFromDataElement( de ); + SetCoordinateStartValue( at.GetValue() ); + } + else if( de.GetTag().GetElement() == 0x0114 ) // CoordinateStepValue + { + Attribute<0x5000,0x0114> at; + at.SetFromDataElement( de ); + SetCoordinateStepValue( at.GetValue() ); + } + else if( de.GetTag().GetElement() == 0x2500 ) // CurveLabel + { + gdcmWarningMacro( "TODO" ); + } + else if( de.GetTag().GetElement() == 0x2600 ) // Referenced Overlay Sequence + { + gdcmWarningMacro( "TODO" ); + } + else if( de.GetTag().GetElement() == 0x2610 ) // Referenced Overlay Group + { + gdcmWarningMacro( "TODO" ); + } + else if( de.GetTag().GetElement() == 0x3000 ) // CurveData + { + SetCurve(bv->GetPointer(), bv->GetLength()); + } + else + { + assert( 0 && "should not happen: Unknown curve tag" ); + } + +} + +void Curve::SetGroup(unsigned short group) { Internal->Group = group; } +unsigned short Curve::GetGroup() const { return Internal->Group; } +void Curve::SetDimensions(unsigned short dimensions) { Internal->Dimensions = dimensions; } +unsigned short Curve::GetDimensions() const { return Internal->Dimensions; } +void Curve::SetNumberOfPoints(unsigned short numberofpoints) { Internal->NumberOfPoints = numberofpoints; } +unsigned short Curve::GetNumberOfPoints() const { return Internal->NumberOfPoints; } +void Curve::SetTypeOfData(const char *typeofdata) +{ + if( typeofdata ) + Internal->TypeOfData = typeofdata; +} +const char *Curve::GetTypeOfData() const { return Internal->TypeOfData.c_str(); } + +static const char * const TypeOfDataDescription[][2] = { +{ "TAC" , "time activity curve" }, +{ "PROF" , "image profile" }, +{ "HIST" , "histogram" }, +{ "ROI" , "polygraphic region of interest" }, +{ "TABL" , "table of values" }, +{ "FILT" , "filter kernel" }, +{ "POLY" , "poly line" }, +{ "ECG" , "ecg data" }, +{ "PRESSURE" , "pressure data" }, +{ "FLOW" , "flow data" }, +{ "PHYSIO" , "physio data" }, +{ "RESP" , "Respiration trace" }, +{ 0 , 0 } +}; +const char *Curve::GetTypeOfDataDescription() const +{ + typedef const char* const (*TypeOfDataDescriptionType)[2]; + TypeOfDataDescriptionType t = TypeOfDataDescription; + int i = 0; + const char *p = t[i][0]; + while( p ) + { + if( Internal->TypeOfData == p ) + { + break; + } + ++i; + p = t[i][0]; + } + return t[i][1]; +} + +void Curve::SetCurveDescription(const char *curvedescription) +{ + if( curvedescription ) + Internal->CurveDescription = curvedescription; +} +void Curve::SetDataValueRepresentation(unsigned short datavaluerepresentation) { Internal->DataValueRepresentation = datavaluerepresentation; } +unsigned short Curve::GetDataValueRepresentation() const { return Internal->DataValueRepresentation; } + +void Curve::SetCurveDataDescriptor(const uint16_t * values, size_t num) +{ + Internal->CurveDataDescriptor = std::vector(values, values+num); +} +std::vector const &Curve::GetCurveDataDescriptor() const +{ + return Internal->CurveDataDescriptor; +} + +void Curve::SetCoordinateStartValue( unsigned short v ) +{ + Internal->CoordinateStartValue = v; +} +void Curve::SetCoordinateStepValue( unsigned short v ) +{ + Internal->CoordinateStepValue = v; +} + +bool Curve::IsEmpty() const +{ + return Internal->Data.empty(); +} + +void Curve::SetCurve(const char *array, unsigned int length) +{ + if( !array || length == 0 ) return; + Internal->Data.resize( length ); + std::copy(array, array+length, Internal->Data.begin()); + //assert( 8 * length == (unsigned int)Internal->Rows * Internal->Columns ); + //assert( Internal->Data.size() == length ); +} + +void Curve::Decode(std::istream &is, std::ostream &os) +{ + (void)is; + (void)os; + assert(0); +} + +/* +PS 3.3 - 2004 +C.10.2.1.2 Data value representation +0000H = unsigned short (US) +0001H = signed short (SS) +0002H = floating point single (FL) +0003H = floating point double (FD) +0004H = signed long (SL) +*/ +inline size_t getsizeofrep( unsigned short dr ) +{ + size_t val = 0; + switch( dr ) + { + case 0: + val = sizeof( uint16_t ); + break; + case 1: + val = sizeof( int16_t ); + break; + case 2: + val = sizeof( float ); + break; + case 3: + val = sizeof( double ); + break; + case 4: + val = sizeof( int32_t ); + break; + } + return val; +} + +/* +C.10.2.1.5 Curve data descriptor, coordinate start value, coordinate step value +The Curve Data for dimension(s) containing evenly distributed data can be eliminated by using a +method that defines the Coordinate Start Value and Coordinate Step Value (interval). The one +dimensional data list is then calculated rather than being enumerated. +For the Curve Data Descriptor (50xx,0110) an Enumerated Value describing how each +component of the N-tuple curve is described, either by points or interval spacing. One value for +each dimension. Where: +0000H = Dimension component described using interval spacing +0001H = Dimension component described using values +Using interval spacing: +Dimension component(s) described by interval spacing use Attributes of Coordinate Start Value +(50xx,0112), Coordinate Step Value (50xx,0114) and Number of Points (50xx,0010). The 1- +dimensional data list is calculated by using a start point of Coordinate Start Value and adding the +interval (Coordinate Step Value) to obtain each data point until the Number of Points is satisfied. +The data points of this dimension will be absent from Curve Data (50xx,3000). +*/ +double Curve::ComputeValueFromStartAndStep(unsigned int idx) const +{ + assert( !Internal->CurveDataDescriptor.empty() ); + const double res = Internal->CoordinateStartValue + + Internal->CoordinateStepValue * idx; + return res; +} + +void Curve::GetAsPoints(float *array) const +{ + assert( getsizeofrep(Internal->DataValueRepresentation) ); + if( Internal->CurveDataDescriptor.empty() ) + { + assert( Internal->Data.size() == (uint32_t)Internal->NumberOfPoints * + Internal->Dimensions * getsizeofrep( Internal->DataValueRepresentation) ); + } + else + { + assert( Internal->Data.size() == (uint32_t)Internal->NumberOfPoints * + 1 * getsizeofrep( Internal->DataValueRepresentation) ); + } + assert( Internal->Dimensions == 1 || Internal->Dimensions == 2 ); + + const int mult = Internal->Dimensions; + int genidx = -1; + if( !Internal->CurveDataDescriptor.empty() ) + { + assert( Internal->CurveDataDescriptor.size() == Internal->Dimensions ); + assert( Internal->CurveDataDescriptor.size() == 2 ); // FIXME + if( Internal->CurveDataDescriptor[0] == 0 ) + { + assert( Internal->CurveDataDescriptor[1] == 1 ); + genidx = 0; + } + else if( Internal->CurveDataDescriptor[1] == 0 ) + { + assert( Internal->CurveDataDescriptor[0] == 1 ); + genidx = 1; + } + else + { + assert( 0 && "TODO" ); + } + } + const char * beg = &Internal->Data[0]; + const char * end = beg + Internal->Data.size(); + if( genidx == -1 ) + { + assert( end == beg + 2 * Internal->NumberOfPoints ); (void)beg;(void)end; + } + else + { + assert( end == beg + mult * Internal->NumberOfPoints ); (void)beg;(void)end; + } + + + if( Internal->DataValueRepresentation == 0 ) + { + // PS 3.3 - 2004 + // C.10.2.1.5 Curve data descriptor, coordinate start value, coordinate step value + uint16_t * p = (uint16_t*)&Internal->Data[0]; + // X + if( genidx == 0 ) + for(int i = 0; i < Internal->NumberOfPoints; i++ ) + array[3*i+0] = ComputeValueFromStartAndStep( i ); + else + for(int i = 0; i < Internal->NumberOfPoints; i++ ) + array[3*i+0] = p[i + 0]; + // Y + if( genidx == 1 ) + for(int i = 0; i < Internal->NumberOfPoints; i++ ) + array[3*i+1] = ComputeValueFromStartAndStep( i ); + else + { + if( mult == 2 && genidx == -1 ) + for(int i = 0; i < Internal->NumberOfPoints; i++ ) + array[3*i+1] = p[i + 1]; + else if( mult == 2 && genidx == 0 ) + for(int i = 0; i < Internal->NumberOfPoints; i++ ) + array[3*i+1] = p[i + 0]; + else + for(int i = 0; i < Internal->NumberOfPoints; i++ ) + array[3*i+1] = 0; + } + // Z + for(int i = 0; i < Internal->NumberOfPoints; i++ ) + array[3*i+2] = 0; + } + else if( Internal->DataValueRepresentation == 1 ) + { + int16_t * p = (int16_t*)&Internal->Data[0]; + for(int i = 0; i < Internal->NumberOfPoints; i++ ) + { + array[3*i+0] = p[mult*i + 0]; + if( mult > 1 ) + array[3*i+1] = p[mult*i + 1]; + else + array[3*i+1] = 0; + array[3*i+2] = 0; + } + } + else if( Internal->DataValueRepresentation == 2 ) + { + float * p = (float*)&Internal->Data[0]; + for(int i = 0; i < Internal->NumberOfPoints; i++ ) + { + array[3*i+0] = p[mult*i + 0]; + if( mult > 1 ) + array[3*i+1] = p[mult*i + 1]; + else + array[3*i+1] = 0; + array[3*i+2] = 0; + } + } + else if( Internal->DataValueRepresentation == 3 ) + { + double * p = (double*)&Internal->Data[0]; + for(int i = 0; i < Internal->NumberOfPoints; i++ ) + { + array[3*i+0] = (float)p[mult*i + 0]; + if( mult > 1 ) + array[3*i+1] = (float)p[mult*i + 1]; + else + array[3*i+1] = 0; + array[3*i+2] = 0; + } + } + else if( Internal->DataValueRepresentation == 4 ) + { + int32_t * p = (int32_t*)&Internal->Data[0]; + for(int i = 0; i < Internal->NumberOfPoints; i++ ) + { + array[3*i+0] = (float)p[mult*i + 0]; + if( mult > 1 ) + array[3*i+1] = (float)p[mult*i + 1]; + else + array[3*i+1] = 0; + array[3*i+2] = 0; + } + } + else + { + assert( 0 ); + } +} + +} diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmCurve.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmCurve.h new file mode 100644 index 0000000..908782d --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmCurve.h @@ -0,0 +1,85 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMCURVE_H +#define GDCMCURVE_H + +#include "gdcmTypes.h" +#include "gdcmObject.h" + +#include + +namespace gdcm +{ + +class CurveInternal; +class ByteValue; +class DataSet; +class DataElement; +/** + * \brief Curve class to handle element 50xx,3000 Curve Data + * WARNING: This is deprecated and lastly defined in PS 3.3 - 2004 + * + * Examples: + * - GE_DLX-8-MONO2-Multiframe-Jpeg_Lossless.dcm + * - GE_DLX-8-MONO2-Multiframe.dcm + * - gdcmSampleData/Philips_Medical_Images/integris_HV_5000/xa_integris.dcm + * - TOSHIBA-CurveData[1-3].dcm + */ +class GDCM_EXPORT Curve : public Object +{ +public: + Curve(); + ~Curve(); + void Print(std::ostream &) const; + + void GetAsPoints(float *array) const; + + static unsigned int GetNumberOfCurves(DataSet const & ds); + + // Update curve data from dataelmenet de: + void Update(const DataElement & de); + + void SetGroup(unsigned short group); + unsigned short GetGroup() const; + void SetDimensions(unsigned short dimensions); + unsigned short GetDimensions() const; + void SetNumberOfPoints(unsigned short numberofpoints); + unsigned short GetNumberOfPoints() const; + void SetTypeOfData(const char *typeofdata); + const char *GetTypeOfData() const; + // See PS 3.3 - 2004 - C.10.2.1.1 Type of data + const char *GetTypeOfDataDescription() const; + void SetCurveDescription(const char *curvedescription); + void SetDataValueRepresentation(unsigned short datavaluerepresentation); + unsigned short GetDataValueRepresentation() const; + void SetCurveDataDescriptor(const uint16_t * values, size_t num); + std::vector const &GetCurveDataDescriptor() const; + void SetCoordinateStartValue( unsigned short v ); + void SetCoordinateStepValue( unsigned short v ); + + void SetCurve(const char *array, unsigned int length); + + bool IsEmpty() const; + + void Decode(std::istream &is, std::ostream &os); + + Curve(Curve const &ov); +private: + double ComputeValueFromStartAndStep(unsigned int idx) const; + CurveInternal *Internal; +}; + +} // end namespace gdcm + +#endif //GDCMCURVE_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmDICOMDIR.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmDICOMDIR.cxx new file mode 100644 index 0000000..cc2496d --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmDICOMDIR.cxx @@ -0,0 +1,17 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmDICOMDIR.h" + +namespace gdcm +{} diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmDICOMDIR.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmDICOMDIR.h new file mode 100644 index 0000000..21437d0 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmDICOMDIR.h @@ -0,0 +1,39 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMDICOMDIR_H +#define GDCMDICOMDIR_H + +#include "gdcmFileSet.h" + +namespace gdcm +{ +/** + * \brief DICOMDIR class + * + * Structured for handling DICOMDIR + */ +class GDCM_EXPORT DICOMDIR +{ +public: + DICOMDIR() {} + DICOMDIR(const FileSet& fs):_FS(fs) {} + +private: + FileSet _FS; + //13 sept 2010 mmr-- added the underscore to FS to compile under Sunos gcc +}; + +} // end namespace gdcm + +#endif //GDCMDICOMDIR_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmDICOMDIRGenerator.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmDICOMDIRGenerator.cxx new file mode 100644 index 0000000..a1b38ce --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmDICOMDIRGenerator.cxx @@ -0,0 +1,1058 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmDICOMDIRGenerator.h" +#include "gdcmFile.h" +#include "gdcmSmartPointer.h" + +#include "gdcmUIDGenerator.h" +#include "gdcmFilename.h" +#include "gdcmScanner.h" +#include "gdcmAttribute.h" +#include "gdcmSequenceOfItems.h" +#include "gdcmFileMetaInformation.h" +#include "gdcmExplicitDataElement.h" +#include "gdcmTag.h" +#include "gdcmVR.h" +#include "gdcmCodeString.h" + + +namespace gdcm +{ + +class DICOMDIRGeneratorInternal +{ +public: + DICOMDIRGeneratorInternal():F(new File) {} + SmartPointer F; + typedef Directory::FilenamesType FilenamesType; + FilenamesType fns; + typedef Directory::FilenameType FilenameType; + FilenameType rootdir; + Scanner scanner; + std::vector OffsetTable; + std::string FileSetID; +}; + +bool DICOMDIRGenerator::ComputeDirectoryRecordsOffset(const SequenceOfItems *sqi, VL start) +{ + gdcm::SequenceOfItems::SizeType nitems = sqi->GetNumberOfItems(); + std::vector &offsets = Internals->OffsetTable; + Internals->OffsetTable.resize( nitems + 1 ); + offsets[0] = start; + for(gdcm::SequenceOfItems::SizeType i = 1; i <= nitems; ++i) + { + const Item &item = sqi->GetItem(i); + offsets[i] = offsets[i-1] + item.GetLength(); + } + +//#define MDEBUG +#ifdef MDEBUG + for(unsigned int i = 0; i <= nitems; ++i) + { + std::cout << "offset #" << i << " -> "<< offsets[i] << std::endl; + } +#endif + + return true; +} + +static const char *GetLowerLevelDirectoryRecord(const char *input) +{ + if( !input ) return NULL; + + if( strcmp( input, "PATIENT " ) == 0 ) + { + return "STUDY "; + } + else if( strcmp( input, "STUDY ") == 0 ) + { + return "SERIES"; + } + else if( strcmp( input, "SERIES" ) == 0 ) + { + return "IMAGE "; + } + else if( strcmp( input, "IMAGE " ) == 0 ) + { + return NULL; + } + assert( 0 ); + //std::cerr << "COULD NOT FIND:" << input << std::endl; + return NULL; +} + + +DICOMDIRGenerator::MyPair DICOMDIRGenerator::GetReferenceValueForDirectoryType(size_t itemidx) +{ + /* + * PS 3.11 - 2008 / D.3.3 Directory Information in DICOMDIR + * The Patient ID at the patient level shall be unique for each patient directory record in one File Set. + */ + /* + * This function will return the Patient ID when directorytype == "PATIENT" + * This function will return the Study Instance UID when directorytype == "STUDY" + * This function will return the Series Instance UID when directorytype == "SERIES" + * This function will return the SOP Instance UID when directorytype == "IMAGE" + */ + MyPair ret; + const SequenceOfItems *sqi = GetDirectoryRecordSequence(); + const Item &item = sqi->GetItem(itemidx); + const DataSet &ds = item.GetNestedDataSet(); + Attribute<0x4,0x1430> directoryrecordtype; + directoryrecordtype.Set( ds ); + + const char *input = directoryrecordtype.GetValue(); + assert( input ); + + if( strcmp( input, "PATIENT " ) == 0 ) + { + Attribute<0x10,0x20> patientid; + patientid.Set( ds ); + assert( patientid.GetValue() ); + ret.first = patientid.GetValue(); + ret.second = patientid.GetTag(); + } + else if( strcmp( input, "STUDY ") == 0 ) + { + Attribute <0x20,0xd> studyuid; + studyuid.Set( ds ); + assert( studyuid.GetValue() ); + ret.first = studyuid.GetValue(); + ret.second = studyuid.GetTag(); + } + else if( strcmp( input, "SERIES" ) == 0 ) + { + Attribute <0x20,0xe> seriesuid; + seriesuid.Set( ds ); + assert( seriesuid.GetValue() ); + ret.first = seriesuid.GetValue(); + ret.second = seriesuid.GetTag(); + } + else if( strcmp( input, "IMAGE " ) == 0 ) + { + Attribute <0x04,0x1511> sopuid; + sopuid.Set( ds ); + assert( sopuid.GetValue() ); + ret.first = sopuid.GetValue(); + ret.second = Tag(0x8,0x18); // watch out ! + } + else + { + assert( 0 ); + } + return ret; +} + +static Tag GetParentTag(Tag const &t) +{ + Tag ret; + if( t == Tag(0x8,0x18) ) + { + ret = Tag(0x20,0xe); + } + else if( t == Tag(0x20,0xe) ) + { + ret = Tag(0x20,0xd); + } + else if( t == Tag(0x20,0xd) ) + { + ret = Tag(0x10,0x20); + } + else if( t == Tag(0x10,0x20) ) + { + ret = Tag(0x0,0x0); + } + else + { + assert( 0 ); + } + return ret; +} + +bool DICOMDIRGenerator::SeriesBelongToStudy(const char *seriesuid, const char *studyuid) +{ + assert( seriesuid ); + assert( studyuid ); + const Scanner &scanner = GetScanner(); + + Scanner::TagToValue const &ttv = scanner.GetMappingFromTagToValue(Tag(0x20,0xe), seriesuid); + Tag tstudyuid(0x20,0xd); + bool b = false; + if( ttv.find( tstudyuid ) != ttv.end() ) + { + const char *v = ttv.find(tstudyuid)->second; + if( v && strcmp(v, studyuid ) == 0 ) + { + b = true; + } + } + + return b; +} + +bool DICOMDIRGenerator::ImageBelongToSeries(const char *sopuid, const char *seriesuid, Tag const &t1, Tag const &t2) +{ + assert( seriesuid ); + assert( sopuid ); + const Scanner &scanner = GetScanner(); + + Scanner::TagToValue const &ttv = scanner.GetMappingFromTagToValue(t1, sopuid); + bool b = false; + if( ttv.find( t2 ) != ttv.end() ) + { + const char *v = ttv.find(t2)->second; + if( v && strcmp(v, seriesuid) == 0 ) + { + b = true; + } + } + + return b; +} + +bool DICOMDIRGenerator::ImageBelongToSameSeries(const char *sopuid1, const char *sopuid2, Tag const &t) +{ + assert( sopuid1 ); + assert( sopuid2 ); + const Scanner &scanner = GetScanner(); + + Scanner::TagToValue const &ttv1 = scanner.GetMappingFromTagToValue(t, sopuid1); + Scanner::TagToValue const &ttv2 = scanner.GetMappingFromTagToValue(t, sopuid2); + Tag tseriesuid = GetParentTag( t ); + if( tseriesuid == Tag(0x0,0x0) ) + { + // Let's pretend that Patient belong to the same 'root' element: + return true; + } + bool b = false; + const char *seriesuid1 = NULL; + if( ttv1.find( tseriesuid ) != ttv1.end() ) + { + seriesuid1 = ttv1.find(tseriesuid)->second; + } + const char *seriesuid2 = NULL; + if( ttv2.find( tseriesuid ) != ttv2.end() ) + { + seriesuid2 = ttv2.find(tseriesuid)->second; + } + assert( seriesuid1 ); + assert( seriesuid2 ); + + b = strcmp( seriesuid1, seriesuid2) == 0; + return b; +} + +size_t DICOMDIRGenerator::FindLowerLevelDirectoryRecord( size_t item1, const char *directorytype ) +{ +// return FindNextDirectoryRecord( item1, GetLowerLevelDirectoryRecord( directorytype ) ); + const char *lowerdirectorytype = GetLowerLevelDirectoryRecord( directorytype ); + if( !lowerdirectorytype ) return 0; + + const SequenceOfItems *sqi = GetDirectoryRecordSequence(); + gdcm::SequenceOfItems::SizeType nitems = sqi->GetNumberOfItems(); + for(gdcm::SequenceOfItems::SizeType i = item1 + 1; i <= nitems; ++i) + { + const Item &item = sqi->GetItem(i); + const DataSet &ds = item.GetNestedDataSet(); + Attribute<0x4,0x1430> directoryrecordtype; + directoryrecordtype.Set( ds ); + + // found a match ? + if( strcmp( lowerdirectorytype, directoryrecordtype.GetValue() ) == 0 ) + { + // Need to make sure belong to same parent record: + MyPair refval1 = GetReferenceValueForDirectoryType(item1); + MyPair refval2 = GetReferenceValueForDirectoryType(i); + bool b = ImageBelongToSeries(refval2.first.c_str(), + refval1.first.c_str(), refval2.second, refval1.second); + if( b ) return i; + } + //assert( strncmp( lowerdirectorytype, directoryrecordtype.GetValue(), strlen( lowerdirectorytype ) ) != 0 ); + } + + // Not found + return 0; + +} + +/* + * Finding the next Directory Record type is easy, simply starting from the start and iterating + * to the end guarantee travering everything without omitting anyone. + * + * TODO: Need to make sure that Series belong to the same Study... + */ +size_t DICOMDIRGenerator::FindNextDirectoryRecord( size_t item1, const char *directorytype ) +{ + if( !directorytype ) return 0; + const SequenceOfItems *sqi = GetDirectoryRecordSequence(); + gdcm::SequenceOfItems::SizeType nitems = sqi->GetNumberOfItems(); + for(gdcm::SequenceOfItems::SizeType i = item1 + 1; i <= nitems; ++i) + { + const Item &item = sqi->GetItem(i); + const DataSet &ds = item.GetNestedDataSet(); + Attribute<0x4,0x1430> directoryrecordtype; + directoryrecordtype.Set( ds ); + + // found a match ? + if( strcmp( directorytype, directoryrecordtype.GetValue() ) == 0 ) + { + // Need to make sure belong to same parent record: + MyPair refval1 = GetReferenceValueForDirectoryType(item1); + MyPair refval2 = GetReferenceValueForDirectoryType(i); + bool b = ImageBelongToSameSeries(refval1.first.c_str(), refval2.first.c_str(), refval1.second); + if( b ) return i; + } + //assert( strncmp( directorytype, directoryrecordtype.GetValue(), strlen( directorytype ) ) != 0 ); + } + + // Not found + return 0; +} + +bool DICOMDIRGenerator::TraverseDirectoryRecords(VL start ) +{ + SequenceOfItems *sqi = GetDirectoryRecordSequence(); + + ComputeDirectoryRecordsOffset(sqi, start); + + gdcm::SequenceOfItems::SizeType nitems = sqi->GetNumberOfItems(); + for(gdcm::SequenceOfItems::SizeType i = 1; i <= nitems; ++i) + { + Item &item = sqi->GetItem(i); + DataSet &ds = item.GetNestedDataSet(); + Attribute<0x4,0x1430> directoryrecordtype; + directoryrecordtype.Set( ds ); + //std::cout << "FOUND DIRECTORY TYPE:" << directoryrecordtype.GetValue() << std::endl; + size_t next = FindNextDirectoryRecord( i, directoryrecordtype.GetValue() ); + if( next ) + { + Attribute<0x4,0x1400> offsetofthenextdirectoryrecord = {0}; + offsetofthenextdirectoryrecord.SetValue( Internals->OffsetTable[ next - 1 ] ); + ds.Replace( offsetofthenextdirectoryrecord.GetAsDataElement() ); + } + size_t lower = FindLowerLevelDirectoryRecord( i, directoryrecordtype.GetValue() ); + if( lower ) + { + Attribute<0x4,0x1420> offsetofreferencedlowerleveldirectoryentity = {0}; + offsetofreferencedlowerleveldirectoryentity.SetValue( Internals->OffsetTable[ lower - 1 ] ); + ds.Replace( offsetofreferencedlowerleveldirectoryentity.GetAsDataElement() ); + } + } + return true; +} + +template +void SingleDataElementInserter(gdcm::DataSet &ds, gdcm::Scanner const & scanner) +{ + Attribute patientsname; + gdcm::Scanner::ValuesType patientsnames = scanner.GetValues( patientsname.GetTag() ); +#ifndef NDEBUG + const unsigned int npatient = patientsnames.size(); + assert( npatient == 1 ); +#endif + + gdcm::Scanner::ValuesType::const_iterator it = patientsnames.begin(); + patientsname.SetValue( it->c_str() ); + ds.Insert( patientsname.GetAsDataElement() ); +} + + +/* + (fffe,e000) na "Directory Record" PATIENT #=8 # u/l, 1 Item + # offset=$374 + (0004,1400) up 0 # 4, 1 OffsetOfTheNextDirectoryRecord + (0004,1410) US 65535 # 2, 1 RecordInUseFlag + (0004,1420) up 502 # 4, 1 OffsetOfReferencedLowerLevelDirectoryEntity + (0004,1430) CS [PATIENT] # 8, 1 DirectoryRecordType + (0010,0010) PN [Test^PixelSpacing] # 18, 1 PatientsName + (0010,0020) LO [62354PQGRRST] # 12, 1 PatientID + (0010,0030) DA (no value available) # 0, 0 PatientsBirthDate + (0010,0040) CS (no value available) # 0, 0 PatientsSex + (fffe,e00d) na "ItemDelimitationItem" # 0, 0 ItemDelimitationItem +*/ +bool DICOMDIRGenerator::AddPatientDirectoryRecord() +{ + gdcm::DataSet &rootds = GetFile().GetDataSet(); + gdcm::Scanner const & scanner = GetScanner(); + + Attribute<0x10,0x20> patientid; + gdcm::Scanner::ValuesType patientids = scanner.GetValues( patientid.GetTag() ); + //unsigned int npatients = patientids.size(); + + const gdcm::DataElement &de = rootds.GetDataElement( Tag(0x4,0x1220) ); + //SequenceOfItems * sqi = (SequenceOfItems*)de.GetSequenceOfItems(); + SmartPointer sqi = de.GetValueAsSQ(); + + gdcm::Scanner::ValuesType::const_iterator it = patientids.begin(); + for( ; it != patientids.end(); ++it) + { + Item item; + item.SetVLToUndefined(); + DataSet &ds = item.GetNestedDataSet(); + + // (0004,1400) up 0 # 4, 1 OffsetOfTheNextDirectoryRecord + // (0004,1410) US 65535 # 2, 1 RecordInUseFlag + // (0004,1420) up 502 # 4, 1 OffsetOfReferencedLowerLevelDirectoryEntity + // (0004,1430) CS [PATIENT] # 8, 1 DirectoryRecordType + Attribute<0x4,0x1400> offsetofthenextdirectoryrecord = {0}; + ds.Insert( offsetofthenextdirectoryrecord.GetAsDataElement() ); + Attribute<0x4,0x1410> recordinuseflag = {0xFFFF}; + ds.Insert( recordinuseflag.GetAsDataElement() ); + Attribute<0x4,0x1420> offsetofreferencedlowerleveldirectoryentity = {0}; + ds.Insert( offsetofreferencedlowerleveldirectoryentity.GetAsDataElement() ); + Attribute<0x4,0x1430> directoryrecordtype; + directoryrecordtype.SetValue( "PATIENT" ); + ds.Insert( directoryrecordtype.GetAsDataElement() ); + const char *pid = it->c_str(); + if( ! (pid && *pid) ) + { + const char *fn = scanner.GetFilenameFromTagToValue(patientid.GetTag(), pid); + gdcmErrorMacro( "Missing Patient ID from file: " << fn ); + (void)fn; //warning removal + return false; + } + gdcmAssertAlwaysMacro( pid && *pid ); + patientid.SetValue( pid ); + ds.Insert( patientid.GetAsDataElement() ); + + gdcm::Scanner::TagToValue const &ttv = scanner.GetMappingFromTagToValue(patientid.GetTag(), pid); + Attribute<0x10,0x10> patientsname; + if( ttv.find( patientsname.GetTag() ) != ttv.end() ) + { + patientsname.SetValue( ttv.find(patientsname.GetTag())->second ); + ds.Insert( patientsname.GetAsDataElement() ); + } + + //SingleDataElementInserter<0x10,0x10>(ds, scanner); + //SingleDataElementInserter<0x10,0x20>(ds, scanner); + //SingleDataElementInserter<0x10,0x30>(ds, scanner); + //SingleDataElementInserter<0x10,0x40>(ds, scanner); + + sqi->AddItem( item ); + } + + return true; +} + +/* + (fffe,e000) na "Directory Record" STUDY #=10 # u/l, 1 Item + # offset=$502 + (0004,1400) up 0 # 4, 1 OffsetOfTheNextDirectoryRecord + (0004,1410) US 65535 # 2, 1 RecordInUseFlag + (0004,1420) up 748 # 4, 1 OffsetOfReferencedLowerLevelDirectoryEntity + (0004,1430) CS [STUDY] # 6, 1 DirectoryRecordType + (0008,0020) DA [20050624] # 8, 1 StudyDate + (0008,0030) TM [104221] # 6, 1 StudyTime + (0008,0050) SH [8-13547713751] # 14, 1 AccessionNumber + (0008,1030) LO [Test support of different pixel spacing attributes] # 50, 1 StudyDescription + (0020,000d) UI [1.3.6.1.4.1.5962.1.2.65535.1119624141.7160.0] # 44, 1 StudyInstanceUID + (0020,0010) SH [734591762345] # 12, 1 StudyID + (fffe,e00d) na "ItemDelimitationItem" # 0, 0 ItemDelimitationItem +*/ +bool DICOMDIRGenerator::AddStudyDirectoryRecord() +{ + gdcm::DataSet &rootds = GetFile().GetDataSet(); + gdcm::Scanner const & scanner = GetScanner(); + + Attribute<0x20,0xd> studyinstanceuid; + gdcm::Scanner::ValuesType studyinstanceuids = scanner.GetValues( studyinstanceuid.GetTag() ); + + const gdcm::DataElement &de = rootds.GetDataElement( Tag(0x4,0x1220) ); + //SequenceOfItems * sqi = (SequenceOfItems*)de.GetSequenceOfItems(); + SmartPointer sqi = de.GetValueAsSQ(); + + gdcm::Scanner::ValuesType::const_iterator it = studyinstanceuids.begin(); + for( ; it != studyinstanceuids.end(); ++it) + { + Item item; + item.SetVLToUndefined(); + DataSet &ds = item.GetNestedDataSet(); + + Attribute<0x4,0x1400> offsetofthenextdirectoryrecord = {0}; + ds.Insert( offsetofthenextdirectoryrecord.GetAsDataElement() ); + Attribute<0x4,0x1410> recordinuseflag = {0xFFFF}; + ds.Insert( recordinuseflag.GetAsDataElement() ); + Attribute<0x4,0x1420> offsetofreferencedlowerleveldirectoryentity = {0}; + ds.Insert( offsetofreferencedlowerleveldirectoryentity.GetAsDataElement() ); + Attribute<0x4,0x1430> directoryrecordtype; + directoryrecordtype.SetValue( "STUDY" ); + ds.Insert( directoryrecordtype.GetAsDataElement() ); + const char *studyuid = it->c_str(); + if( ! (studyuid && *studyuid) ) + { + const char *fn = scanner.GetFilenameFromTagToValue(studyinstanceuid.GetTag(), studyuid); + gdcmErrorMacro( "Missing Study Instance UID from file: " << fn ); + (void)fn;//warning removal + return false; + } + gdcmAssertAlwaysMacro( studyuid && *studyuid ); + studyinstanceuid.SetValue( studyuid ); + ds.Insert( studyinstanceuid.GetAsDataElement() ); + + //SingleDataElementInserter<0x20,0xd>(ds, scanner); + //SingleDataElementInserter<0x8,0x20>(ds, scanner); + //SingleDataElementInserter<0x8,0x30>(ds, scanner); + //SingleDataElementInserter<0x8,0x1030>(ds, scanner); + //SingleDataElementInserter<0x8,0x50>(ds, scanner); + //SingleDataElementInserter<0x20,0x10>(ds, scanner); + gdcm::Scanner::TagToValue const &ttv = scanner.GetMappingFromTagToValue(studyinstanceuid.GetTag(), studyuid); + + Attribute<0x8,0x20> studydate; + if( ttv.find( studydate.GetTag() ) != ttv.end() ) + { + studydate.SetValue( ttv.find(studydate.GetTag())->second ); + ds.Insert( studydate.GetAsDataElement() ); + } + Attribute<0x8,0x30> studytime; + if( ttv.find( studytime.GetTag() ) != ttv.end() ) + { + studytime.SetValue( ttv.find(studytime.GetTag())->second ); + ds.Insert( studytime.GetAsDataElement() ); + } + Attribute<0x8,0x1030> studydesc; + if( ttv.find( studydesc.GetTag() ) != ttv.end() ) + { + studydesc.SetValue( ttv.find(studydesc.GetTag())->second ); + ds.Insert( studydesc.GetAsDataElement() ); + } + Attribute<0x8,0x50> accessionnumber; + if( ttv.find( accessionnumber.GetTag() ) != ttv.end() ) + { + accessionnumber.SetValue( ttv.find(accessionnumber.GetTag())->second ); + ds.Insert( accessionnumber.GetAsDataElement() ); + } + Attribute<0x20,0x10> studyid; + if( ttv.find( studyid.GetTag() ) != ttv.end() ) + { + studyid.SetValue( ttv.find(studyid.GetTag())->second ); + ds.Insert( studyid.GetAsDataElement() ); + } + + sqi->AddItem( item ); + } + + return true; +} + +/* + (fffe,e000) na "Directory Record" SERIES #=11 # u/l, 1 Item + # offset=$748 + (0004,1400) up 1214 # 4, 1 OffsetOfTheNextDirectoryRecord + (0004,1410) US 65535 # 2, 1 RecordInUseFlag + (0004,1420) up 938 # 4, 1 OffsetOfReferencedLowerLevelDirectoryEntity + (0004,1430) CS [SERIES] # 6, 1 DirectoryRecordType + (0008,0060) CS [CR] # 2, 1 Modality + (0008,0080) LO (no value available) # 0, 0 InstitutionName + (0008,0081) ST (no value available) # 0, 0 InstitutionAddress + (0008,103e) LO [Computed Radiography] # 20, 1 SeriesDescription + (0008,1050) PN (no value available) # 0, 0 PerformingPhysiciansName + (0020,000e) UI [1.3.6.1.4.1.5962.1.3.65535.4.1119624143.7187.0] # 46, 1 SeriesInstanceUID + (0020,0011) IS [4] # 2, 1 SeriesNumber + (fffe,e00d) na "ItemDelimitationItem" # 0, 0 ItemDelimitationItem +*/ +bool DICOMDIRGenerator::AddSeriesDirectoryRecord() +{ + gdcm::DataSet &rootds = GetFile().GetDataSet(); + gdcm::Scanner const & scanner = GetScanner(); + + Attribute<0x20,0xe> seriesinstanceuid; + gdcm::Scanner::ValuesType seriesinstanceuids = scanner.GetValues( seriesinstanceuid.GetTag() ); + + const gdcm::DataElement &de = rootds.GetDataElement( Tag(0x4,0x1220) ); + //SequenceOfItems * sqi = (SequenceOfItems*)de.GetSequenceOfItems(); + SmartPointer sqi = de.GetValueAsSQ(); + + gdcm::Scanner::ValuesType::const_iterator it = seriesinstanceuids.begin(); + for( ; it != seriesinstanceuids.end(); ++it) + { + Item item; + item.SetVLToUndefined(); + DataSet &ds = item.GetNestedDataSet(); + + Attribute<0x4,0x1400> offsetofthenextdirectoryrecord = {0}; + ds.Insert( offsetofthenextdirectoryrecord.GetAsDataElement() ); + Attribute<0x4,0x1410> recordinuseflag = {0xFFFF}; + ds.Insert( recordinuseflag.GetAsDataElement() ); + Attribute<0x4,0x1420> offsetofreferencedlowerleveldirectoryentity = {0}; + ds.Insert( offsetofreferencedlowerleveldirectoryentity.GetAsDataElement() ); + Attribute<0x4,0x1430> directoryrecordtype; + directoryrecordtype.SetValue( "SERIES" ); + ds.Insert( directoryrecordtype.GetAsDataElement() ); + const char *seriesuid = it->c_str(); + if( ! (seriesuid && *seriesuid) ) + { + const char *fn = scanner.GetFilenameFromTagToValue(seriesinstanceuid.GetTag(), seriesuid); + gdcmErrorMacro( "Missing Study Instance UID from file: " << fn ); + (void)fn;//warning removal + return false; + } + gdcmAssertAlwaysMacro( seriesuid && *seriesuid ); + seriesinstanceuid.SetValue( seriesuid ); + ds.Insert( seriesinstanceuid.GetAsDataElement() ); + + gdcm::Scanner::TagToValue const &ttv = scanner.GetMappingFromTagToValue(seriesinstanceuid.GetTag(), seriesuid); + Attribute<0x8,0x60> modality; + if( ttv.find( modality.GetTag() ) != ttv.end() ) + { + modality.SetValue( ttv.find(modality.GetTag())->second ); + ds.Insert( modality.GetAsDataElement() ); + } + Attribute<0x20,0x11> seriesnumber; + if( ttv.find( seriesnumber.GetTag() ) != ttv.end() ) + { + seriesnumber.SetValue( atoi(ttv.find(seriesnumber.GetTag())->second) ); + ds.Insert( seriesnumber.GetAsDataElement() ); + } + + sqi->AddItem( item ); + } + + return true; +} + +/* + (fffe,e000) na "Directory Record" IMAGE #=13 # u/l, 1 Item + # offset=$1398 refFileID="IMAGES\DXIMAGE" + (0004,1400) up 0 # 4, 1 OffsetOfTheNextDirectoryRecord + (0004,1410) US 65535 # 2, 1 RecordInUseFlag + (0004,1420) up 0 # 4, 1 OffsetOfReferencedLowerLevelDirectoryEntity + (0004,1430) CS [IMAGE] # 6, 1 DirectoryRecordType + (0004,1500) CS [IMAGES\DXIMAGE] # 14, 2 ReferencedFileID + (0004,1510) UI =DigitalXRayImageStorageForPresentation # 28, 1 ReferencedSOPClassUIDInFile + (0004,1511) UI [1.3.6.1.4.1.5962.1.1.65535.3.1.1119624143.7180.0] # 48, 1 ReferencedSOPInstanceUIDInFile + (0004,1512) UI =LittleEndianExplicit # 20, 1 ReferencedTransferSyntaxUIDInFile + (0008,0008) CS [ORIGINAL\PRIMARY] # 16, 2 ImageType + (0020,0013) IS [1] # 2, 1 InstanceNumber + (0028,0004) CS [MONOCHROME2] # 12, 1 PhotometricInterpretation + (0028,0008) IS [1] # 2, 1 NumberOfFrames + (0050,0004) CS (no value available) # 0, 0 CalibrationImage + (fffe,e00d) na "ItemDelimitationItem" # 0, 0 ItemDelimitationItem +*/ +bool DICOMDIRGenerator::AddImageDirectoryRecord() +{ + gdcm::DataSet &rootds = GetFile().GetDataSet(); + gdcm::Scanner const & scanner = GetScanner(); + + const Attribute<0x8,0x18> sopinstanceuid = { "" }; + gdcm::Scanner::ValuesType sopinstanceuids = scanner.GetValues( sopinstanceuid.GetTag() ); + //unsigned int ninstance = sopinstanceuids.size(); + + const gdcm::DataElement &de = rootds.GetDataElement( Tag(0x4,0x1220) ); + //SequenceOfItems * sqi = (SequenceOfItems*)de.GetSequenceOfItems(); + SmartPointer sqi = de.GetValueAsSQ(); + + gdcm::Scanner::ValuesType::const_iterator it = sopinstanceuids.begin(); + gdcm::Filename rootdir = Internals->rootdir.c_str(); + const char *rd = rootdir.ToWindowsSlashes(); + size_t strlen_rd = strlen( rd ); + for( ; it != sopinstanceuids.end(); ++it) + { + Item item; + item.SetVLToUndefined(); + DataSet &ds = item.GetNestedDataSet(); + + Attribute<0x4,0x1400> offsetofthenextdirectoryrecord = {0}; + ds.Insert( offsetofthenextdirectoryrecord.GetAsDataElement() ); + Attribute<0x4,0x1410> recordinuseflag = {0xFFFF}; + ds.Insert( recordinuseflag.GetAsDataElement() ); + Attribute<0x4,0x1420> offsetofreferencedlowerleveldirectoryentity = {0}; + ds.Insert( offsetofreferencedlowerleveldirectoryentity.GetAsDataElement() ); + Attribute<0x4,0x1430> directoryrecordtype; + directoryrecordtype.SetValue( "IMAGE" ); + ds.Insert( directoryrecordtype.GetAsDataElement() ); + + const char *sopuid = it->c_str(); + gdcm::Scanner::TagToValue const &ttv = scanner.GetMappingFromTagToValue(sopinstanceuid.GetTag(), sopuid); + Attribute<0x0004,0x1500> referencedfileid; + const char *fn_str = scanner.GetFilenameFromTagToValue(sopinstanceuid.GetTag(), sopuid); + referencedfileid.SetNumberOfValues( 1 ); + gdcm::Filename fn = fn_str; + std::string relative = fn.ToWindowsSlashes(); + std::string::size_type l = relative.find( rd ); + if( l != std::string::npos ) + { + assert( l == 0 ); // FIXME + relative.replace( l, strlen_rd, "" ); + fn = relative.c_str() + 1; + } + referencedfileid.SetValue( fn.ToWindowsSlashes() ); + ds.Insert( referencedfileid.GetAsDataElement() ); + Attribute<0x0004,0x1510> referencedsopclassuidinfile; + Attribute<0x8,0x16> sopclassuid; + if( ttv.find( sopclassuid.GetTag() ) != ttv.end() ) + { + referencedsopclassuidinfile.SetValue( ttv.find(sopclassuid.GetTag())->second ); + } + ds.Insert( referencedsopclassuidinfile.GetAsDataElement() ); + Attribute<0x0004,0x1511> referencedsopinstanceuidinfile; + if( ttv.find( sopinstanceuid.GetTag() ) != ttv.end() ) + { + referencedsopinstanceuidinfile.SetValue( ttv.find(sopinstanceuid.GetTag())->second ); + } + ds.Insert( referencedsopinstanceuidinfile.GetAsDataElement() ); + Attribute<0x0004,0x1512> referencedtransfersyntaxuidinfile; + Attribute<0x2,0x10> transfersyntaxuid; + if( ttv.find( transfersyntaxuid.GetTag() ) != ttv.end() ) + { + referencedtransfersyntaxuidinfile.SetValue( ttv.find(transfersyntaxuid.GetTag())->second ); + } + ds.Insert( referencedtransfersyntaxuidinfile.GetAsDataElement() ); + + Attribute<0x20,0x13> instancenumber = { 0 }; + if( ttv.find( instancenumber.GetTag() ) != ttv.end() ) + { + instancenumber.SetValue( atoi(ttv.find(instancenumber.GetTag())->second) ); + } + ds.Insert( instancenumber.GetAsDataElement() ); + + Attribute<0x8,0x8> imagetype; + //gdcm::Scanner::ValuesType imagetypes = scanner.GetValues( imagetype.GetTag() ); + //gdcm::Scanner::ValuesType::const_iterator it = imagetypes.begin(); + //assert( imagetypes.size() == 1 ); + //imagetype.SetNumberOfValues( 1 ); + //imagetype.SetValue( it->c_str() ); + //ds.Replace( imagetype.GetAsDataElement() ); + DataElement de2( imagetype.GetTag() ); + de2.SetVR( imagetype.GetVR() ); + if( ttv.find( imagetype.GetTag() ) != ttv.end() ) + { + const char *v = ttv.find(imagetype.GetTag())->second; + VL::Type strlenV = (VL::Type)strlen(v); + de2.SetByteValue( v, strlenV ); + } + ds.Insert( de2 ); + + sqi->AddItem( item ); + } + + return true; +} + +DICOMDIRGenerator::DICOMDIRGenerator( ) +{ + Internals = new DICOMDIRGeneratorInternal; +} + +DICOMDIRGenerator::~DICOMDIRGenerator( ) +{ + delete Internals; +} + +static bool IsCompatibleWithISOIEC9660MediaFormat(const char *filename) +{ + if(!filename) return false; + // (0004,1500) CS [IMG001] # 6, 1 ReferencedFileID + // + Attribute< 0x4, 0x1500 > at; + DataElement de( at.GetTag() ); + std::string copy = filename; + if( copy.size() % 2 ) + { + copy.push_back( ' ' ); + } + VL::Type copySize = (VL::Type)copy.size(); + de.SetByteValue( copy.c_str(), copySize ) ; + at.SetFromDataElement( de ); + unsigned int n = at.GetNumberOfValues(); + // A volume may have at most 8 levels of directories, where the root + // directory is defined as level 1. + if( n > 8 ) + { + gdcmDebugMacro( "8 Levels of directories" ); + return false; + } + + for( unsigned int i = 0; i < n; ++i) + { + gdcm::CodeString cs = at.GetValue( i ); + if( !cs.IsValid() || cs.Size() > 8 ) + { + gdcmDebugMacro( "Problem with CS: " << cs ); + return false; + } + } + return true; +} + +void DICOMDIRGenerator::SetFilenames( FilenamesType const & fns ) +{ + Internals->fns = fns; +} + +void DICOMDIRGenerator::SetRootDirectory( FilenameType const & root ) +{ + Internals->rootdir = root; +} + +bool DICOMDIRGenerator::Generate() +{ + gdcm::Scanner &scanner = GetScanner(); + // + scanner.AddTag( Tag(0x02,0x10) ); + // + scanner.AddTag( Tag(0x10,0x10) ); + // + scanner.AddTag( Tag(0x10,0x20) ); + // + scanner.AddTag( Tag(0x8,0x60) ); + // + scanner.AddTag( Tag(0x20,0x11) ); + // + scanner.AddTag( Tag(0x8,0x18) ); + // + scanner.AddTag( Tag(0x8,0x20) ); + // + scanner.AddTag( Tag(0x8,0x30) ); + // + scanner.AddTag( Tag(0x8,0x1030) ); + // + scanner.AddTag( Tag(0x8,0x50) ); + // + scanner.AddTag( Tag(0x20,0x13) ); + // + scanner.AddTag( Tag(0x20,0xd) ); + // + scanner.AddTag( Tag(0x20,0x10) ); + // + scanner.AddTag( Tag(0x20,0xe) ); + // + scanner.AddTag( Tag(0x28,0x4) ); + // + scanner.AddTag( Tag(0x28,0x8) ); + // + scanner.AddTag( Tag(0x50,0x4) ); + // + scanner.AddTag( Tag(0x10,0x30) ); + // + scanner.AddTag( Tag(0x10,0x40) ); + // + scanner.AddTag( Tag(0x8,0x80) ); + // + scanner.AddTag( Tag(0x8,0x16) ); + // + scanner.AddTag( Tag(0x2,0x10) ); + // + scanner.AddTag( Tag(0x8,0x8) ); + + FilenamesType const &filenames = Internals->fns; + gdcm::Filename rootdir = Internals->rootdir.c_str(); + const char *rd = rootdir.ToWindowsSlashes(); + size_t strlen_rd = strlen( rd ); + + // Let's check that filenames are ok for iso9660 + compatible with VR:CS +{ + FilenamesType::const_iterator it = filenames.begin(); + for( ; it != filenames.end(); ++it ) + { + gdcm::Filename fn = it->c_str(); + const char *f = fn.ToWindowsSlashes(); + std::string relative = f; + std::string::size_type l = relative.find( rd ); + if( l != std::string::npos ) + { + assert( l == 0 ); // FIXME + relative.replace( l, strlen_rd, "" ); + f = relative.c_str() + 1; + } + if( !IsCompatibleWithISOIEC9660MediaFormat( f ) ) + { + gdcmErrorMacro( "Invalid file name: " << f ); + return false; + } + } +} + + if( !scanner.Scan( filenames ) ) + { + return false; + } + + //scanner.Print( std::cout ); + + Scanner::ValuesType vt = scanner.GetValues( Tag(0x2,0x10) ); + Scanner::ValuesType vtref; + vtref.insert( TransferSyntax::GetTSString( TransferSyntax::ExplicitVRLittleEndian ) ); + if( vt == vtref ) + { + // All files are ExplicitVRLittleEndian which is required for DICOMDIR + } + else + { + gdcmErrorMacro( "Found Transfer Syntax not ExplicitVRLittleEndian." ); + return false; + } + + // (0004,1220) SQ (Sequence with undefined length #=8) # u/l, 1 DirectoryRecordSequence + + gdcm::DataSet &ds = GetFile().GetDataSet(); + + Attribute<0x4,0x1130> filesetid; + filesetid.SetValue( Internals->FileSetID.c_str() ); + ds.Insert( filesetid.GetAsDataElement() ); + + CodeString cs = filesetid.GetValue(); + if( !cs.IsValid() ) + { + gdcmErrorMacro( "Invalid File Set ID: " << filesetid.GetValue() ); + return false; + } + + Attribute<0x4,0x1200> offsetofthefirstdirectoryrecordoftherootdirectoryentity = {0}; + ds.Insert( offsetofthefirstdirectoryrecordoftherootdirectoryentity.GetAsDataElement() ); + Attribute<0x4,0x1202> offsetofthelastdirectoryrecordoftherootdirectoryentity = { 0 }; + ds.Insert( offsetofthelastdirectoryrecordoftherootdirectoryentity.GetAsDataElement() ); + Attribute<0x4,0x1212> filesetconsistencyflag = {0}; + ds.Insert( filesetconsistencyflag.GetAsDataElement() ); + + + gdcm::DataElement de_drs( Tag(0x4,0x1220) ); // DirectoryRecordSequence + + SequenceOfItems * sqi0 = new SequenceOfItems; + de_drs.SetVR( VR::SQ ); + de_drs.SetValue( *sqi0 ); + de_drs.SetVLToUndefined(); + + ds.Insert( de_drs ); + + bool b; + b = AddPatientDirectoryRecord(); + if( !b ) return false; + b = AddStudyDirectoryRecord(); + if( !b ) return false; + b = AddSeriesDirectoryRecord(); + if( !b ) return false; + b = AddImageDirectoryRecord(); + if( !b ) return false; + +/* +The DICOMDIR File shall use the Explicit VR Little Endian Transfer Syntax (UID=1.2.840.10008.1.2.1) to +encode the Media Storage Directory SOP Class. The DICOMDIR File shall comply with the DICOM File +Format specified in Section 7 of this Standard. In particular the: +a. SOP Class UID in the File Meta Information (header of the DICOMDIR File) shall have the +Value specified in PS 3.4 of this Standard for the Media Storage Directory SOP Class; +b. SOP Instance UID in the File Meta Information (header of the DICOMDIR File) shall contain +the File-set UID Value. The File-set UID is assigned by the Application Entity which created +the File-set (FSC role, see Section 8.3) with zero or more DICOM Files. This File-set UID +Value shall not be changed by any other Application Entities reading or updating the content of +the File-set. +*/ + FileMetaInformation &h = GetFile().GetHeader(); + gdcm::Attribute<0x2,0x2> at1; + gdcm::MediaStorage ms = gdcm::MediaStorage::MediaStorageDirectoryStorage; + const char* msstr = gdcm::MediaStorage::GetMSString(ms); + at1.SetValue( msstr ); + h.Insert( at1.GetAsDataElement() ); + + gdcm::Attribute<0x2,0x3> at2; + gdcm::UIDGenerator uid; + const char *mediastoragesopinstanceuid = uid.Generate(); + if( !gdcm::UIDGenerator::IsValid( mediastoragesopinstanceuid ) ) + { + return 1; + } + at2.SetValue( mediastoragesopinstanceuid ); + h.Insert( at2.GetAsDataElement() ); + + gdcm::TransferSyntax ts = gdcm::TransferSyntax::ExplicitVRLittleEndian; + h.SetDataSetTransferSyntax( ts ); + + //std::cout << ds << std::endl; + //std::cout << h << std::endl; + + + /* Very important step it should be the *VERY* last one */ + // We need to compute all offset, which can be only done when all attributes have been inserted. + // Let's start with offsetofthefirstdirectoryrecordoftherootdirectoryentity : + h.FillFromDataSet( ds ); + VL fmi_len = h.GetFullLength(); + VL fmi_len_offset = 0; +{ + gdcm::DataSet::ConstIterator it = ds.Begin(); + for(; it != ds.End() && it->GetTag() != Tag(0x0004,0x1220); ++it) + { + const DataElement &detmp = *it; + fmi_len_offset += detmp.GetLength(); + } + // Now add the partial length for attribute 0004,1220: + fmi_len_offset += it->GetTag().GetLength(); + fmi_len_offset += it->GetVR().GetLength(); + fmi_len_offset += it->GetVR().GetLength(); +} + //std::cerr << fmi_len << " and " << fmi_len_offset << std::endl; + offsetofthefirstdirectoryrecordoftherootdirectoryentity.SetValue( fmi_len + fmi_len_offset ); + ds.Replace( offsetofthefirstdirectoryrecordoftherootdirectoryentity.GetAsDataElement() ); + + VL fmi_len_offset2 = 0; +{ + gdcm::DataSet::ConstIterator it = ds.Begin(); + for( ; it != ds.End() && it->GetTag() <= Tag(0x0004,0x1220); ++it) + { + const DataElement &detmp = *it; + fmi_len_offset2 += detmp.GetLength(); + } +} + +{ + //const gdcm::DataElement &de_drs = ds.GetDataElement( Tag(0x4,0x1220) ); // DirectoryRecordSequence + SmartPointer sqi = de_drs.GetValueAsSQ(); + gdcm::SequenceOfItems::SizeType n = sqi->GetNumberOfItems(); + const Item &item = sqi->GetItem( n ); // last item + VL sub = item.GetLength(); + // Let's substract item length as well as the item sequence delimiter end (tag + vl => 8) + offsetofthelastdirectoryrecordoftherootdirectoryentity.SetValue( fmi_len + fmi_len_offset2 - sub - 8 ); + + ds.Replace( offsetofthelastdirectoryrecordoftherootdirectoryentity.GetAsDataElement() ); + + TraverseDirectoryRecords(offsetofthefirstdirectoryrecordoftherootdirectoryentity.GetValue() ); +} + + return true; +} + +void DICOMDIRGenerator::SetFile(const File& f) +{ + Internals->F = f; +} + +File &DICOMDIRGenerator::GetFile() +{ + return *Internals->F; +} + +Scanner &DICOMDIRGenerator::GetScanner() +{ + return Internals->scanner; +} + +SequenceOfItems *DICOMDIRGenerator::GetDirectoryRecordSequence() +{ + gdcm::DataSet &ds = GetFile().GetDataSet(); + const gdcm::DataElement &de = ds.GetDataElement( Tag(0x4,0x1220) ); + //SequenceOfItems * sqi = (SequenceOfItems*)de.GetSequenceOfItems(); + SmartPointer sqi = de.GetValueAsSQ(); + return sqi; +} + +const char *DICOMDIRGenerator::ComputeFileID(const char *input) +{ + assert( 0 ); (void)input; + return NULL; +} + +void DICOMDIRGenerator::SetDescriptor( const char *d ) +{ + Internals->FileSetID = d; +} + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmDICOMDIRGenerator.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmDICOMDIRGenerator.h new file mode 100644 index 0000000..3d45a45 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmDICOMDIRGenerator.h @@ -0,0 +1,111 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMDICOMDIRGENERATOR_H +#define GDCMDICOMDIRGENERATOR_H + +#include "gdcmDirectory.h" +#include "gdcmTag.h" +#include // std::pair + +namespace gdcm +{ +class File; +class Scanner; +class SequenceOfItems; +class VL; +class DICOMDIRGeneratorInternal; + +/** + * \brief DICOMDIRGenerator class + * This is a STD-GEN-CD DICOMDIR generator. + * ref: PS 3.11-2008 Annex D (Normative) - General Purpose CD-R and DVD Interchange Profiles + * + * \note + * PS 3.11 - 2008 / D.3.2 Physical Medium And Medium Format + * The STD-GEN-CD and STD-GEN-SEC-CD application profiles require the 120 mm CD-R physical + * medium with the ISO/IEC 9660 Media Format, as defined in PS3.12. + * See also PS 3.12 - 2008 / Annex F 120mm CD-R Medium (Normative) and + * PS 3.10 - 2008 / 8 DICOM File Service / 8.1 FILE-SET + * + * \warning: + * PS 3.11 - 2008 / D.3.1 SOP Classes and Transfer Syntaxes + * Composite Image & Stand-alone Storage are required to be stored as Explicit VR Little + * Endian Uncompressed (1.2.840.10008.1.2.1). When a DICOM file is found using another + * Transfer Syntax the generator will simply stops. + * + * \warning + * - Input files should be Explicit VR Little Endian + * - filenames should be valid VR::CS value (16 bytes, upper case ...) + * + * \bug: + * There is a current limitation of not handling Referenced SOP Class UID / + * Referenced SOP Instance UID simply because the gdcm::Scanner does not allow us + * See PS 3.11 / Table D.3-2 STD-GEN Additional DICOMDIR Keys + */ +class GDCM_EXPORT DICOMDIRGenerator +{ +public: + typedef Directory::FilenamesType FilenamesType; + typedef Directory::FilenameType FilenameType; + DICOMDIRGenerator(); + ~DICOMDIRGenerator(); + + /// Set the list of filenames from which the DICOMDIR should be generated from + void SetFilenames( FilenamesType const & fns ); + + /// Set the root directory from which the filenames should be considered. + void SetRootDirectory( FilenameType const & root ); + + /// Set the File Set ID. + /// \warning this need to be a valid VR::CS value + void SetDescriptor( const char *d ); + + /// Main function to generate the DICOMDIR + bool Generate(); + + /// Set/Get file. The DICOMDIR file will be valid once a call to Generate has been done + void SetFile(const File& f); + File &GetFile(); + +protected: + Scanner &GetScanner(); + bool AddPatientDirectoryRecord(); + bool AddStudyDirectoryRecord(); + bool AddSeriesDirectoryRecord(); + bool AddImageDirectoryRecord(); + +private: + const char *ComputeFileID(const char *); + bool TraverseDirectoryRecords(VL start ); + bool ComputeDirectoryRecordsOffset(const SequenceOfItems *sqi, VL start); + size_t FindNextDirectoryRecord( size_t item1, const char *directorytype ); + SequenceOfItems *GetDirectoryRecordSequence(); + size_t FindLowerLevelDirectoryRecord( size_t item1, const char *directorytype ); + typedef std::pair< std::string, Tag> MyPair; + MyPair GetReferenceValueForDirectoryType(size_t item); + bool SeriesBelongToStudy(const char *seriesuid, const char *studyuid); + bool ImageBelongToSeries(const char *sopuid, const char *seriesuid, Tag const &t1, Tag const &t2); + bool ImageBelongToSameSeries(const char *sopuid, const char *seriesuid, Tag const &t); + + DICOMDIRGeneratorInternal * Internals; +}; + +/** + * \example GenerateDICOMDIR.cs + * This is a C# example on how to use gdcm::DICOMDIRGenerator + */ + +} // end namespace gdcm + +#endif //GDCMDICOMDIRGENERATOR_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmDataSetHelper.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmDataSetHelper.cxx new file mode 100644 index 0000000..81293bc --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmDataSetHelper.cxx @@ -0,0 +1,311 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmDataSetHelper.h" +#include "gdcmFile.h" +#include "gdcmDataSet.h" +#include "gdcmSequenceOfItems.h" +#include "gdcmImplicitDataElement.h" +#include "gdcmGlobal.h" +#include "gdcmDicts.h" +#include "gdcmDict.h" +#include "gdcmAttribute.h" + +namespace gdcm +{ +/* + See PS 3.5 - 2008 + Annex A (Normative) Transfer Syntax Specifications +*/ + +VR ComputeVRImplicitLittleEndian(DataSet const &ds, const Tag& tag) +{ + (void)ds; + (void)tag; + /* + A.1 DICOM IMPLICIT VR LITTLE ENDIAN TRANSFER SYNTAX + a) The Data Elements contained in the Data Set structure shall be encoded with Implicit VR + (without a VR Field) as specified in Section 7.1.3. + b) The encoding of the overall Data Set structure (Data Element Tags, Value Length, and Value) + shall be in Little Endian as specified in Section 7.3. + c) The encoding of the Data Elements of the Data Set shall be as follows according to their Value + Representations: + - For all Value Representations defined in this part, except for the Value Representations + OB and OW, the encoding shall be in Little Endian as specified in Section 7.3 + - For the Value Representations OB and OW, the encoding shall meet the following + specification depending on the Data Element Tag: + - Data Element (7FE0,0010) Pixel Data has the Value Representation OW and shall + be encoded in Little Endian. + - Data Element (60xx,3000) Overlay Data has the Value Representation OW and shall + be encoded in Little Endian. + - Data Element (5400,1010) Waveform Data shall have Value Representation OW + and shall be encoded in Little Endian. + - Data Elements (0028,1201), (0028,1202),(0028,1203) Red, Green, Blue Palette + Lookup Table Data have the Value Representation OW and shall be encoded in + Little Endian. + Note: Previous versions of the Standard either did not specify the encoding of these Data + Elements in this Part, but specified a VR of US or SS in PS 3.6 (1993), or specified + OW in this Part but a VR of US, SS or OW in PS 3.6 (1996). The actual encoding + of the values and their byte order would be identical in each case. + - Data Elements (0028,1101), (0028,1102),(0028,1103) Red, Green, Blue Palette + Lookup Table Descriptor have the Value Representation SS or US (depending on + rules specified in the IOD in PS 3.3), and shall be encoded in Little Endian. The first + and third values are always interpreted as unsigned, regardless of the Value + Representation. + - Data Elements (0028,1221),(0028,1222),(0028,1223) Segmented Red, Green, Blue + Palette Color Lookup table Data have the Value Representation OW and shall be + encoded in Little Endian. + - Data Element (0028,3006) Lookup Table Data has the Value Representation US, SS + or OW and shall be encoded in Little Endian. + - Data Element (0028,3002) Lookup Table Descriptor has the Value Representation + SS or US (depending on rules specified in the IOD in PS 3.3), and shall be encoded + in Little Endian. The first and third values are always interpreted as unsigned, + regardless of the Value Representation. + */ + VR vr = VR::INVALID; + return vr; +} + +VR DataSetHelper::ComputeVR(File const &file, DataSet const &ds, const Tag& tag) +{ + const Global& g = GlobalInstance; + const Dicts &dicts = g.GetDicts(); + //const Dict &d = dicts.GetPublicDict(); + + std::string strowner; + const char *owner = 0; + const Tag& t = tag; + if( t.IsPrivate() && !t.IsPrivateCreator() ) + { + strowner = ds.GetPrivateCreator(t); + owner = strowner.c_str(); + } + const DictEntry &entry = dicts.GetDictEntry(t,owner); + const VR &refvr = entry.GetVR(); + //const VM &vm = entry.GetVM(); + + // not much we can do... + if( refvr == VR::INVALID || refvr == VR::UN ) + { + // postcondition says it cannot be VR::INVALID, so return VR::UN + return VR::UN; + } + + VR vr = refvr; + + // Special handling of US or SS vr: + if( vr == VR::US_SS ) + { + // I believe all US_SS VR derived from the value from 0028,0103 ... except 0028,0071 + if( t != Tag(0x0028,0x0071) ) + { + // In case of SAX parser, we would have had to process Pixel Representation already: + Attribute<0x0028,0x0103> at; + const Tag &pixelrep = at.GetTag(); + assert( pixelrep < t ); + const DataSet &rootds = file.GetDataSet(); + // FIXME + // PhilipsWith15Overlays.dcm has a Private SQ with public elements such as + // 0028,3002, so we cannot look up element in current dataset, but have to get the root dataset + // to loop up... + + // FIXME: + // gdcmDataExtra/gdcmSampleData/ImagesPapyrus/TestImages/wristb.pap + // It's the contrary: root dataset does not have a Pixel Representation, but each SQ do... + assert( rootds.FindDataElement( pixelrep ) || ds.FindDataElement( pixelrep ) ); + if( ds.FindDataElement( pixelrep ) ) + { + at.SetFromDataElement( ds.GetDataElement( pixelrep ) ); + } + else if( rootds.FindDataElement( pixelrep ) ) + { + at.SetFromDataElement( rootds.GetDataElement( pixelrep ) ); + } + else + { + //throw Exception( "Unhandled" ); + gdcmWarningMacro( "Unhandled" ); + vr = VR::INVALID; + } + //assert( at.GetValue() == 0 || at.GetValue() == 1 ); + if( at.GetValue() ) + { + vr = VR::SS; + } + else + { + vr = VR::US; + } + } + else + { + // FIXME ??? + vr = VR::US; + } + } + else if( vr == VR::OB_OW ) + { + Tag pixeldata(0x7fe0,0x0010); + Tag waveformpaddingvalue(0x5400,0x100a); + Tag waveformdata(0x5400,0x1010); + Tag overlaydata(0x6000,0x3000); + Tag curvedata(0x5000,0x3000); + Tag audiodata(0x5000,0x200c); + Tag variablepixeldata(0x7f00,0x0010); + Tag bitsallocated(0x0028,0x0100); + Tag channelminval(0x5400,0x0110); + Tag channelmaxval(0x5400,0x0112); + //assert( ds.FindDataElement( pixeldata ) ); + int v = -1; + if( waveformdata == t || waveformpaddingvalue == t ) + { + Tag waveformbitsallocated(0x5400,0x1004); + // For Waveform Data: + // (5400,1004) US 16 # 2,1 Waveform Bits Allocated + assert( ds.FindDataElement( waveformbitsallocated ) ); + Attribute<0x5400,0x1004> at; + at.SetFromDataElement( ds.GetDataElement( waveformbitsallocated ) ); + v = at.GetValue(); + } + else // ( pixeldata == t ) + { + // For Pixel Data: + assert( ds.FindDataElement( bitsallocated ) ); + Attribute<0x0028,0x0100> at; + at.SetFromDataElement( ds.GetDataElement( bitsallocated ) ); + } + (void)v; + + if( pixeldata == t || t.IsGroupXX(overlaydata) ) + { + vr = VR::OW; + } + else if( waveformdata == t || waveformpaddingvalue == t ) + { + //assert( v == 8 || v == 16 ); + vr = VR::OW; + } + else if ( t.IsGroupXX(audiodata) ) + { + vr = VR::OB; + } + else if ( t.IsGroupXX(curvedata) ) + { + vr = VR::OB; + } + else if ( t.IsGroupXX(variablepixeldata) ) + { + vr = VR::OB; + } + else if ( t == channelminval || t == channelmaxval ) + { + vr = VR::OB; + } + else + { + assert( 0 && "Should not happen" ); + vr = VR::INVALID; + } + } + else if( vr == VR::US_SS_OW ) + { + vr = VR::OW; + } + // TODO need to treat US_SS_OW too + + // \postcondition: + assert( vr.IsVRFile() ); + assert( vr != VR::INVALID ); + + if( tag.IsGroupLength() ) + { + assert( vr == VR::UL ); + } + if( tag.IsPrivateCreator() ) + { + assert( vr == VR::LO ); + } + return vr; +} + + +/* +SequenceOfItems* DataSetHelper::ComputeSQFromByteValue(File const & file, DataSet const &ds, const Tag &tag) +{ + const TransferSyntax &ts = file.GetHeader().GetDataSetTransferSyntax(); + assert( ts != TransferSyntax::DeflatedExplicitVRLittleEndian ); + const DataElement &de = ds.GetDataElement( tag ); + if( de.IsEmpty() ) + { + return 0; + } + Value &v = const_cast(de.GetValue()); + SequenceOfItems *sq = dynamic_cast(&v); + if( sq ) // all set ! + { + SmartPointer sqi = sq; + return sqi; + } + + try + { + if( ts.GetSwapCode() == SwapCode::BigEndian ) + { + assert(0); + } + else + { + if( ts.GetNegociatedType() == TransferSyntax::Implicit ) + { + assert( de.GetVR() == VR::INVALID ); + const ByteValue *bv = de.GetByteValue(); + assert( bv ); + SequenceOfItems *sqi = new SequenceOfItems; + sqi->SetLength( bv->GetLength() ); + std::stringstream ss; + ss.str( std::string( bv->GetPointer(), bv->GetLength() ) ); + sqi->Read( ss ); + return sqi; + } + else + { + assert( de.GetVR() == VR::UN ); // cp 246, IVRLE SQ + const ByteValue *bv = de.GetByteValue(); + assert( bv ); + SequenceOfItems *sqi = new SequenceOfItems; + sqi->SetLength( bv->GetLength() ); + std::stringstream ss; + ss.str( std::string( bv->GetPointer(), bv->GetLength() ) ); + sqi->Read( ss ); + return sqi; + } + } + } + catch( ParseException &pex ) + { + gdcmDebugMacro( pex.what() ); + } + catch( Exception &ex ) + { + gdcmDebugMacro( ex.what() ); + } + catch( ... ) + { + gdcmWarningMacro( "Unknown exception" ); + } + + return 0; +} +*/ + +} diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmDataSetHelper.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmDataSetHelper.h new file mode 100644 index 0000000..08b0246 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmDataSetHelper.h @@ -0,0 +1,46 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMDATASETHELPER_H +#define GDCMDATASETHELPER_H + +#include "gdcmTypes.h" +#include "gdcmVR.h" + +namespace gdcm +{ +class DataSet; +class File; +class Tag; +class SequenceOfItems; + +/** + * \brief DataSetHelper (internal class, not intended for user level) + * + * \details + */ +class GDCM_EXPORT DataSetHelper +{ +public: + /// ds -> current dataset, which is not the same as the root dataset + /// return VR::INVALID in case of error + static VR ComputeVR(File const & file, DataSet const &ds, const Tag& tag); + + //static SequenceOfItems* ComputeSQFromByteValue(File const & file, DataSet const &ds, const Tag &tag); + +protected: +}; + +} // end namespace gdcm + +#endif // GDCMDATASETHELPER_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmDecoder.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmDecoder.h new file mode 100644 index 0000000..9ff9e28 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmDecoder.h @@ -0,0 +1,45 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#ifndef GDCMDECODER_H +#define GDCMDECODER_H + +#include "gdcmTypes.h" +#include "gdcmDataElement.h" // FIXME + +namespace gdcm +{ + +class TransferSyntax; +class DataElement; +/** + * \brief Decoder + */ +class GDCM_EXPORT Decoder +{ +public: + virtual ~Decoder() {} + + /// Return whether this decoder support this transfer syntax (can decode it) + virtual bool CanDecode(TransferSyntax const &) const = 0; + + /// Decode + virtual bool Decode(DataElement const &, DataElement &) { return false; } +protected: + virtual bool DecodeByStreams(std::istream &, std::ostream &) { return false; } +}; + +} // end namespace gdcm + +#endif //GDCMDECODER_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmDeltaEncodingCodec.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmDeltaEncodingCodec.cxx new file mode 100644 index 0000000..a555316 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmDeltaEncodingCodec.cxx @@ -0,0 +1,50 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmDeltaEncodingCodec.h" +#include "gdcmTransferSyntax.h" +#include "gdcmByteSwap.txx" +#include "gdcmDataElement.h" +#include "gdcmSequenceOfFragments.h" + +#include + +namespace gdcm +{ + +DeltaEncodingCodec::DeltaEncodingCodec() +{ +} + +DeltaEncodingCodec::~DeltaEncodingCodec() +{ +} + +bool DeltaEncodingCodec::CanDecode(TransferSyntax const &ts) +{ + return true; // FIXME +} + +bool DeltaEncodingCodec::Decode(DataElement const &in, DataElement &out) +{ + out = in; + return true; +} + +bool DeltaEncodingCodec::Decode(std::istream &is, std::ostream &os) +{ + abort(); + return true; +} + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmDeltaEncodingCodec.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmDeltaEncodingCodec.h new file mode 100644 index 0000000..321856e --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmDeltaEncodingCodec.h @@ -0,0 +1,40 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMDELTAENCODINGCODEC_H +#define GDCMDELTAENCODINGCODEC_H + +#include "gdcmImageCodec.h" +#error do not use + +namespace gdcm +{ + +/** + * \brief DeltaEncodingCodec compression used by some private + * vendor + */ +class DeltaEncodingCodec : public ImageCodec +{ +public: + DeltaEncodingCodec(); + ~DeltaEncodingCodec(); + bool CanDecode(TransferSyntax const &ts); + bool Decode(DataElement const &is, DataElement &os); +protected: + bool Decode(std::istream &is, std::ostream &os); +}; + +} // end namespace gdcm + +#endif //GDCMDELTAENCODINGCODEC_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmDictPrinter.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmDictPrinter.cxx new file mode 100644 index 0000000..270ce84 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmDictPrinter.cxx @@ -0,0 +1,527 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmDictPrinter.h" +#include "gdcmDict.h" +#include "gdcmGlobal.h" +#include "gdcmDicts.h" +#include "gdcmSequenceOfItems.h" + +namespace gdcm +{ + +//----------------------------------------------------------------------------- +DictPrinter::DictPrinter() +{ +} + +//----------------------------------------------------------------------------- +DictPrinter::~DictPrinter() +{ +} + +VM GuessVMType(DataElement const &de) +{ + if( de.IsEmpty() ) return VM::VM1; + const VR &vr = de.GetVR(); + const VL &vl = de.GetVL(); + const Value& value = de.GetValue(); + VM vm; + if( VR::IsBinary( vr ) ) + { + if( vr == VR::SQ ) + { + vm = VM::VM1; // ?? + } + else if( vr & VR::OB_OW ) + { + vm = VM::VM1; + } + else + { + vm = VM::GetVMTypeFromLength( value.GetLength(), vr.GetSize() ); + } + } + else + { + assert( VR::IsASCII( vr ) || vr == VR::INVALID ); + switch(vr) + { + case VR::INVALID: + vm = VM::VM1; + break; + case VR::UN: // TODO need to do some magic guessing + vm = VM::VM1; + break; + case VR::DA: case VR::TM: case VR::LT: + case VR::SH: case VR::UI: case VR::LO: case VR::ST: + case VR::UT: case VR::AE: case VR::AS: + vm = VM::VM1; + break; + case VR::PN: + vm = VM::VM1; // I think it is ok + break; + case VR::IS: case VR::DS: case VR::DT: case VR::CS: + { + // Need to count \\ character + const ByteValue *bv = dynamic_cast(&value); + vm = VM::VM1; // why not ? + if(!de.IsEmpty()) + { + assert( bv && "not bv" ); + const char *array = bv->GetPointer(); + unsigned int c = VM::GetNumberOfElementsFromArray(array, vl); + vm = VM::GetVMTypeFromLength( c, 1 ); + } + } + break; + default: + vm = VM::VM0; + assert( 0 ); // Impossible happen ! (someone added new VR and forgot this switch) + } + } + + return vm; +} + +struct OWNER_VERSION +{ + const char* owner; + const char* version; +}; + +// See getowner.xsl +static const OWNER_VERSION OwnerVersionTable[] ={ +{"","EMPTY!"}, +{"","2"}, +{"","3"}, +{"1.2.840.113663.1","ATL"}, +{"1.2.840.113681","DUP"}, +{"1.2.840.113708.794.1.1.2.0","ARM"}, +{"2.16.840.1.114059.1.1.6.1.50.1","DEX"}, +{"ACUSON","ACU"}, +{"ADAC_IMG","ADAC"}, +{"AEGIS_DICOM_2.00","AEG"}, +{"AGFA PACS Archive Mirroring 1.0 ","MIT"}, +{"AGFA","AGFA"}, +{"AGFA_ADC_Compact","AGFA"}, +{"Applicare/RadWorks/Version 5.0","APL"}, +{"Applicare/RadWorks/Version 6.0","APL"}, +{"Applicare/RadWorks/Version 6.0/Summary","APL"}, +{"BioPri","BIO"}, +{"CAMTRONICS IP ","CMT"}, +{"CAMTRONICS","CMT"}, +{"CARDIO-D.R. 1.0 ","PDIC"}, +{"Canon Inc.","CAN"}, +{"DIDI TO PCR 1.1 ","PSPI"}, +{"DIGISCAN IMAGE","SSPI"}, +{"DLX_ANNOT_01","DLX"}, +{"DLX_EXAMS_01","DLX"}, +{"DLX_LKUP_01 ","GEM"}, +{"DLX_PATNT_01","DLX"}, +{"DLX_SERIE_01","DLX"}, +{"DLX_SERIE_01","GEM"}, +{"ELSCINT1","EL1"}, +{"FDMS 1.0","FUJ"}, +{"FFP DATA","SSPI"}, +{"GE ??? From Adantage Review CS","GEM"}, +{"GEIIS PACS","GEM"}, +{"GEIIS ","GEM"}, +{"GEMS_3DSTATE_001","GEM"}, +{"GEMS_ACQU_01","GEM"}, +{"GEMS_ACRQA_1.0 BLOCK1 ","GEM"}, +{"GEMS_ACRQA_1.0 BLOCK2 ","GEM"}, +{"GEMS_ACRQA_1.0 BLOCK3 ","GEM"}, +{"GEMS_ACRQA_2.0 BLOCK1 ","GEM"}, +{"GEMS_ACRQA_2.0 BLOCK2 ","GEM"}, +{"GEMS_ACRQA_2.0 BLOCK3 ","GEM"}, +{"GEMS_ADWSoft_3D1","GEM"}, +{"GEMS_ADWSoft_DPO","GEM"}, +{"GEMS_AWSOFT_CD1 ","GEM"}, +{"GEMS_AWSoft_SB1 ","GEM"}, +{"GEMS_CTHD_01","GEM"}, +{"GEMS_CT_CARDIAC_001 ","GEM"}, +{"GEMS_CT_HINO_01 ","GEM"}, +{"GEMS_CT_VES_01","GEM"}, +{"GEMS_DL_FRAME_01","GEM"}, +{"GEMS_DL_IMG_01","GEM"}, +{"GEMS_DL_PATNT_01","GEM"}, +{"GEMS_DL_SERIES_01 ","GEM"}, +{"GEMS_DL_STUDY_01","GEM"}, +{"GEMS_DRS_1","GEM"}, +{"GEMS_FALCON_03","GEM"}, +{"GEMS_GDXE_ATHENAV2_INTERNAL_USE ","GEM"}, +{"GEMS_GDXE_FALCON_04 ","GEM"}, +{"GEMS_GENIE_1","GEM"}, +{"GEMS_GNHD_01","GEM"}, +{"GEMS_HELIOS_01","GEM"}, +{"GEMS_IDEN_01","GEM"}, +{"GEMS_IMAG_01","GEM"}, +{"GEMS_IMPS_01","GEM"}, +{"GEMS_IQTB_IDEN_47 ","GEM"}, +{"GEMS_PARM_01","GEM"}, +{"GEMS_PATI_01","GEM"}, +{"GEMS_PETD_01","GEM"}, +{"GEMS_RELA_01","GEM"}, +{"GEMS_SENO_02","GEM"}, +{"GEMS_SERS_01","GEM"}, +{"GEMS_STDY_01","GEM"}, +{"GEMS_YMHD_01","GEM"}, +{"GE_GENESIS_REV3.0 ","GEM"}, +{"HOLOGIC ","HOL"}, +{"Hologic ","HOL"}, +{"ISG shadow","ISG"}, +{"ISI ","SSPI"}, +{"KINETDX ","KDX"}, +{"KINETDX_GRAPHICS","KDX"}, +{"LODOX_STATSCAN","LDX"}, +{"LORAD Selenia ","LOR"}, +{"MERGE TECHNOLOGIES, INC.","MRG"}, +{"MITRA LINKED ATTRIBUTES 1.0 ","MIT"}, +{"MITRA MARKUP 1.0","MIT"}, +{"MITRA OBJECT ATTRIBUTES 1.0 ","MIT"}, +{"MITRA OBJECT DOCUMENT 1.0 ","MIT"}, +{"MITRA OBJECT UTF8 ATTRIBUTES 1.0","MIT"}, +{"MITRA PRESENTATION 1.0","MIT"}, +{"MMCPrivate","HIT"}, +{"Mayo/IBM Archive Project","MIBM"}, +{"MeVis BreastCare","MEV"}, +{"Mortara_Inc ","MOR"}, +{"PAPYRUS 3.0 ","PA3"}, +{"PAPYRUS ","PAP"}, +{"PHILIPS MR R5.5/PART","PSPI"}, +{"PHILIPS MR R5.6/PART","PSPI"}, +{"PHILIPS MR SPECTRO;1","PSPI"}, +{"PHILIPS MR","PSPI"}, +{"PHILIPS MR/LAST ","PSPI"}, +{"PHILIPS MR/PART ","PSPI"}, +{"PHILIPS NM -Private ","PMNM"}, +{"PHILIPS-MR-1","PDIC"}, +{"PMS-THORA-5.1 ","PDIC"}, +{"PMTF INFORMATION DATA ","TSH"}, +{"Philips Imaging DD 001","PMFE"}, +{"Philips Imaging DD 129","PMFE"}, +{"Philips MR Imaging DD 001 ","PMFE"}, +{"Philips MR Imaging DD 002 ","PMFE"}, +{"Philips MR Imaging DD 003 ","PMFE"}, +{"Philips MR Imaging DD 004 ","PMFE"}, +{"Philips MR Imaging DD 005 ","PMFE"}, +{"Philips PET Private Group ","PPET"}, +{"Philips X-ray Imaging DD 001","PMFE"}, +{"Picker MR Private Group ","PCK"}, +{"Picker NM Private Group ","PCK"}, +{"SCHICK TECHNOLOGIES - Change Item Creator ID","SCH"}, +{"SCHICK TECHNOLOGIES - Change List Creator ID","SCH"}, +{"SCHICK TECHNOLOGIES - Image Security Creator ID ","SCH"}, +{"SCHICK TECHNOLOGIES - Note List Creator ID","SCH"}, +{"SECTRA_Ident_01 ","SEC"}, +{"SECTRA_ImageInfo_01 ","SEC"}, +{"SECTRA_OverlayInfo_01 ","SEC"}, +{"SEGAMI MIML ","MOR"}, +{"SHS MagicView 300 ","SSPI"}, +{"SIEMENS CM VA0 ACQU","SSPI"}, +{"SIEMENS CM VA0 CMS ","SSPI"}, +{"SIEMENS CM VA0 LAB ","SSPI"}, +{"SIEMENS CSA HEADER","SSPI"}, +{"SIEMENS CSA NON-IMAGE ","SSPI"}, +{"SIEMENS CSA REPORT","SSPI"}, +{"SIEMENS CT VA0 COAD","SSPI"}, +{"SIEMENS CT VA0 GEN ","SSPI"}, +{"SIEMENS CT VA0 IDE ","SSPI"}, +{"SIEMENS CT VA0 ORI ","SSPI"}, +{"SIEMENS CT VA0 OST ","SSPI"}, +{"SIEMENS CT VA0 RAW ","SSPI"}, +{"SIEMENS DFR.01 MANIPULATED","SSPI"}, +{"SIEMENS DFR.01 ORIGINAL ","SSPI"}, +{"SIEMENS DICOM ","SSPI"}, +{"SIEMENS DLR.01","SPI"}, +{"SIEMENS DLR.01","SSPI"}, +{"SIEMENS ISI ","SSPI"}, +{"SIEMENS MED DISPLAY 0000","SSPI"}, +{"SIEMENS MED DISPLAY ","SSPI"}, +{"SIEMENS MED ECAT FILE INFO","SSPI"}, +{"SIEMENS MED HG","SSPI"}, +{"SIEMENS MED MAMMO " ,"SSPI"}, +{"SIEMENS MED MG","SSPI"}, +{"SIEMENS MED NM","SSPI"}, +{"SIEMENS MED SP DXMG WH AWS 1","SSPI"}, +{"SIEMENS MED ","SSPI"}, +{"SIEMENS MEDCOM HEADER ","SSPI"}, +{"SIEMENS MEDCOM HEADER2","SSPI"}, +{"SIEMENS MEDCOM OOG","SSPI"}, +{"SIEMENS MR VA0 COAD","SSPI"}, +{"SIEMENS MR VA0 GEN ","SSPI"}, +{"SIEMENS MR VA0 RAW ","SSPI"}, +{"SIEMENS NUMARIS II","SSPI"}, +{"SIEMENS RA GEN","SSPI"}, +{"SIEMENS RA PLANE A","SSPI"}, +{"SIEMENS RA PLANE B","SSPI"}, +{"SIEMENS RIS ","SSPI"}, +{"SIEMENS SIENET","SSPI"}, +{"SIEMENS SMS-AX ACQ 1.0 ","SSPI"}, +{"SIEMENS SMS-AX ORIGINAL IMAGE INFO 1.0 ","SSPI"}, +{"SIEMENS SMS-AX QUANT 1.0 ","SSPI"}, +{"SIEMENS SMS-AX VIEW 1.0","SSPI"}, +{"SIEMENS Selma ","SSPI"}, +{"SIEMENS WH SR 1.0 ","SSPI"}, +{"SIEMENS_FLCOMPACT_VA01A_PROC","SSPI"}, +{"SIENET","SSPI"}, +{"SPI RELEASE 1 ","SPI"}, +{"SPI Release 1 ","SPI"}, +//{"SPI ","SPI"}, // FIXME ?? +{"SPI ","SSPI"}, +{"SPI-P Release 1 ","PSPI"}, +{"SPI-P Release 1;1 ","PSPI"}, +{"SPI-P Release 1;2 ","PSPI"}, +{"SPI-P Release 1;3 ","PSPI"}, +{"SPI-P Release 2;1 ","PSPI"}, +{"SPI-P-CTBE Release 1","PSPI"}, +{"SPI-P-CTBE-Private Release 1","PSPI"}, +{"SPI-P-GV-CT Release 1 ","PSPI"}, +{"SPI-P-PCR Release 2 ","PSPI"}, +{"SPI-P-Private-CWS Release 1 ","PSPI"}, +{"SPI-P-Private-DCI Release 1 ","PSPI"}, +{"SPI-P-Private-DiDi Release 1","PSPI"}, +{"SPI-P-Private_CDS Release 1 ","PSPI"}, +{"SPI-P-Private_ICS Release 1 ","PSPI"}, +{"SPI-P-Private_ICS Release 1;1 ","PSPI"}, +{"SPI-P-Private_ICS Release 1;2 ","PSPI"}, +{"SPI-P-Private_ICS Release 1;4 ","PSPI"}, +{"SPI-P-Private_ICS Release 1;5 ","PSPI"}, +{"SPI-P-XSB-DCI Release 1 ","PSPI"}, +{"SPI-P-XSB-VISUB Release 1 ","PSPI"}, +{"STENTOR ","STE"}, +{"Siemens: Thorax/Multix FD Image Stamp ","SSPI"}, +{"Siemens: Thorax/Multix FD Lab Settings","SSPI"}, +{"Siemens: Thorax/Multix FD Post Processing ","SSPI"}, +{"Siemens: Thorax/Multix FD Raw Image Settings","SSPI"}, +{"Siemens: Thorax/Multix FD Version ","SSPI"}, +{"Silhouette Annot V1.0 ","ISG"}, +{"Silhouette Graphics Export V1.0 ","ISG"}, +{"Silhouette Line V1.0","ISG"}, +{"Silhouette ROI V1.0 ","ISG"}, +{"Silhouette Sequence Ids V1.0","ISG"}, +{"Silhouette V1.0 ","ISG"}, +{"Silhouette VRS 3.0","ISG"}, +{"TOSHIBA COMAPL HEADER ","TSH"}, +{"TOSHIBA COMAPL OOG","TSH"}, +{"TOSHIBA ENCRYPTED SR DATA ","TSH"}, +{"TOSHIBA MDW HEADER","TSH"}, +{"TOSHIBA MDW NON-IMAGE ","TSH"}, +{"TOSHIBA_MEC_1.0 ","TSH"}, +{"TOSHIBA_MEC_CT3 ","TSH"}, +{"TOSHIBA_MEC_CT_1.0","TSH"}, +{"TOSHIBA_MEC_MR3 ","TSH"}, +{"TOSHIBA_MEC_OT3 ","TSH"}, +{"TOSHIBA_MEC_XA3 ","TSH"}, +{"Viewing Protocol",""}, +{"http://www.gemedicalsystems.com/it_solutions/rad_pacs/","GEM"}, + +// Manualy added: +{ "GEMS_Ultrasound_ImageGroup_001", "GEM" }, +{ "GEMS_Ultrasound_MovieGroup_001", "GEM" }, +{ "SIEMENS MED OCS SITE NAME ", "SSPI" }, +{ "PHILIPS IMAGING DD 001", "PMFE" }, +{ "PHILIPS MR IMAGING DD 001 ", "PMFE" }, +{ "INTELERAD MEDICAL SYSTEMS ", "IMS" }, +{ "SIEMENS CT VA1 DUMMY", "SSPI" }, +{ "PATRIOT_PRIVATE_IMAGE_DATA", "PPID" }, +{ "VEPRO VIF 3.0 DATA", "VV3D" }, +{ "VEPRO DICOM TRANSFER 1.0", "VDT1" }, +{ "HMC ", "HMC" }, +{ "Philips3D ", "PM3D" }, +{ "SIEMENS MED SMS USG ANTARES ", "SSPI" }, +{ "ACUSON:1.2.840.113680.1.0:7f10", "ACU" }, +{ "ACUSON:1.2.840.113680.1.0 ", "ACU" }, +{ "SIEMENS MR HEADER", "SSPI" }, // !! +{ "INTEGRIS 1.0", "INT1" }, +{ "SYNARC_1.0", "SYN" }, +{ "MeVis eatDicom", "MVD" }, +{ "PHILIPS MR/PART 6 ", "PMFE" }, +{ "PHILIPS MR/PART 7 ", "PMFE" }, +{ "PHILIPS MR/PART 12", "PMFE" }, +{ "HMC - CT - ID ", "HMC" }, +{ "SPI-P-Private_ICS Release 1;8 ", "SPI" }, +{ "ACUSON:1.2.840.113680.1.0:7ffe", "ACU" }, +{ "SIEMENS MED OCS FIELD NAME", "SSPI" }, +{ "SIEMENS MED OCS FIELD ID", "SSPI" }, +{ "SIEMENS MED OCS CALIBRATION DATE", "SSPI" }, +{ "SIEMENS MED OCS NUMBER OF SUB FRAMES", "SSPI" }, +{ "SIEMENS MED OCS AE TITLE", "SSPI" }, +{ "GEMS_ADWSoft_DPO1 ", "GEM" }, +{ "SPI-P-Private_ICS Release 1;6 ", "SSPI" }, +{ "SIEMENS MR HEADER ", "SSPI" }, +{ "NO PRIVATE CREATOR", "BLA" }, +{ "SFS1.00 ", "SFS" }, +{ "ATL PRIVATE TAGS", "ATL" }, +{ "Philips EV Imaging DD 022 ", "PMFE" }, +{ "Harmony R1.0 C2 ", "HRMY" }, +{ "Harmony R1.0", "HRMY" }, +{ "Harmony R2.0", "HRMY" }, +{ "Harmony R1.0 C3 ", "HRMY" }, +{ "Philips US Imaging DD 017 ", "PMFE" }, +{ "Philips US Imaging DD 023 ", "PMFE" }, +{ "Philips US Imaging DD 033 ", "PMFE" }, +{ "Philips US Imaging DD 034 ", "PMFE" }, +{ "Philips US Imaging DD 035 ", "PMFE" }, +{ "Philips US Imaging DD 036 ", "PMFE" }, +{ "Philips US Imaging DD 038 ", "PMFE" }, +{ "Philips US Imaging DD 039 ", "PMFE" }, +{ "Philips US Imaging DD 040 ", "PMFE" }, +{ "Philips US Imaging DD 042 ", "PMFE" }, +{ "Philips US Imaging DD 043 ", "PMFE" }, +{ "Philips US Imaging DD 081 ", "PMFE" }, + +{ "Array DICOM private elements version1.0 ", "ARRAY" }, +{ "PI Private Block (0781:3000 - 0781:30FF)", "PIP" }, + + + + + + +{ "XXXXXXXXXXXXXXXX", "ANO" }, // FIXME ! +{ "XXXXXXXXXXXXXX", "ANO"}, +{ "XXXXXXXXX_xx", "ANO" }, // FIXME +{ " MED NM", "ANO" }, // Clearly should be SIEMENS + + { NULL, NULL }, +}; + +std::string GetVersion(std::string const &owner) +{ + + const OWNER_VERSION *p = OwnerVersionTable; + while( p->owner ) + { +//#ifndef NDEBUG +// if( strlen(p->owner) % 2 ) +// { +// // HEY ! +// std::cerr << "OWNER= \"" << p->owner << "\"" << std::endl; +// assert(0); +// } +//#endif + //if( owner == p->owner ) + if( strcmp(owner.c_str(), p->owner) == 0 ) + { + return p->version; + } + ++p; + } + std::cerr << "OWNER= \"" << owner << "\"" << std::endl; + return "GDCM:UNKNOWN"; +} + +// TODO: make it protected: +std::string GetOwner(DataSet const &ds, DataElement const &de) +{ + return ds.GetPrivateCreator(de.GetTag()); +} + +void DictPrinter::PrintDataElement2(std::ostream& os, const DataSet &ds, const DataElement &de) +{ + const Global& g = GlobalInstance; + const Dicts &dicts = g.GetDicts(); + + //const SequenceOfItems *sqi = de.GetSequenceOfItems(); + //const SequenceOfFragments *sqf = de.GetSequenceOfFragments(); + + std::string strowner; + const char *owner = 0; + const Tag& t = de.GetTag(); + if( t.IsPrivate() && !t.IsPrivateCreator() ) + { + strowner = ds.GetPrivateCreator(t); + owner = strowner.c_str(); + } + const DictEntry &entry = dicts.GetDictEntry(t,owner); + + if( de.GetTag().IsPrivate() && de.GetTag().GetElement() >= 0x0100 ) + { + //owner = GetOwner(ds,de); + //version = GetVersion(owner); + + const VR &vr = de.GetVR(); + VR pvr = vr; + if( vr == VR::INVALID ) pvr = VR::UN; + if( de.GetTag().GetElement() == 0x0 ) + { + pvr = VR::UL; + } + else if( de.GetTag().GetElement() <= 0xFF ) + { + pvr = VR::LO; + owner = "Private Creator"; + } + VM vm = GuessVMType(de); + + os << + "> 8) << "\" "; + + os << "vr=\"" << pvr << "\" vm=\"" << vm << "\" "; + //os << "\" retired=\"false\"; + if( de.GetTag().IsPrivate() ) + { + os << "name=\"?\" owner=\"" << owner + << /*"\" version=\"" << version << */ "\"/>\n"; + } + //os << "\n ?\n"; + //os << "\n"; + //os << "/>\n"; + //os << " Unknown "; + //os << (t.IsPrivate() ? "Private" : "Public"); + //os << " Tag & Data\n"; + //os << " \n"; + //os << " \n"; + //os << " \n"; + //os << "\n"; + } + + if( entry.GetVR() == VR::SQ || true ) + { + SmartPointer sqi = de.GetValueAsSQ(); + if( sqi ) + { + SequenceOfItems::ItemVector::const_iterator it = sqi->Items.begin(); + for(; it != sqi->Items.end(); ++it) + { + const Item &item = *it; + const DataSet &nestedds = item.GetNestedDataSet(); + PrintDataSet2(os, nestedds); + } + } + } +} + +//----------------------------------------------------------------------------- +void DictPrinter::PrintDataSet2(std::ostream& os, const DataSet &ds) +{ + DataSet::ConstIterator it = ds.Begin(); + for( ; it != ds.End(); ++it ) + { + const DataElement &de = *it; + PrintDataElement2(os, ds, de); + } +} + +void DictPrinter::Print(std::ostream& os) +{ + const DataSet &ds = F->GetDataSet(); + PrintDataSet2(os, ds); + //os << "\n"; +} + +} diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmDictPrinter.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmDictPrinter.h new file mode 100644 index 0000000..5287f30 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmDictPrinter.h @@ -0,0 +1,41 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMDICTPRINTER_H +#define GDCMDICTPRINTER_H + +#include "gdcmPrinter.h" + +namespace gdcm +{ + +/** + * \brief DictPrinter class + */ +// It's a sink there is no output +class GDCM_EXPORT DictPrinter : public Printer +{ +public: + DictPrinter(); + ~DictPrinter(); + + void Print(std::ostream& os); + +protected: + void PrintDataElement2(std::ostream& os, const DataSet &ds, const DataElement &ide); + void PrintDataSet2(std::ostream& os, const DataSet &ds); +}; + +} // end namespace gdcm + +#endif //GDCMDICTPRINTER_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmDirectionCosines.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmDirectionCosines.cxx new file mode 100644 index 0000000..5da29d9 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmDirectionCosines.cxx @@ -0,0 +1,161 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmDirectionCosines.h" + +#include +#include // fabs +#include // sscanf + +namespace gdcm +{ + +DirectionCosines::DirectionCosines() +{ + Values[0] = 1; + Values[1] = 0; + Values[2] = 0; + Values[3] = 0; + Values[4] = 1; + Values[5] = 0; +} + +DirectionCosines::DirectionCosines(const double dircos[6]) +{ + Values[0] = dircos[0]; + Values[1] = dircos[1]; + Values[2] = dircos[2]; + Values[3] = dircos[3]; + Values[4] = dircos[4]; + Values[5] = dircos[5]; +} + +DirectionCosines::~DirectionCosines() {} + +void DirectionCosines::Print(std::ostream &os) const +{ + os << Values[0] << ","; + os << Values[1] << ","; + os << Values[2] << ","; + os << Values[3] << ","; + os << Values[4] << ","; + os << Values[5]; +} + +bool DirectionCosines::IsValid() const +{ + // gdcmData/gdcm-MR-SIEMENS-16-2.acr + // => {-1, -0, 0, -0, 0.05233599990606308, 0.99862951040267944} + const double epsilon = 1e-3; //std::numeric_limits::epsilon(); + + double norm_v1 = Values[0] * Values[0] + Values[1]*Values[1] + Values[2]*Values[2]; + double norm_v2 = Values[3] * Values[3] + Values[4]*Values[4] + Values[5]*Values[5]; + double dot = Dot(); + + bool ret = false; + if( fabs(norm_v1 - 1) < epsilon && fabs(norm_v2 - 1) < epsilon ) + { + if( fabs(dot) < epsilon ) + { + ret = true; + } + } + return ret; +} + +void DirectionCosines::Cross(double z[3]) const +{ + //assert( Dot() == 0 ); + const double *x = Values; + const double *y = x+3; + double Zx = x[1]*y[2] - x[2]*y[1]; + double Zy = x[2]*y[0] - x[0]*y[2]; + double Zz = x[0]*y[1] - x[1]*y[0]; + z[0] = Zx; z[1] = Zy; z[2] = Zz; +} + +double DirectionCosines::Dot() const +{ + const double *x = Values; + const double *y = x+3; + return x[0]*y[0] + x[1]*y[1] + x[2]*y[2]; +} + +// static function is within gdcm:: namespace, so should not pollute too much on UNIX +static double Norm(const double x[3]) +{ + return sqrt(x[0]*x[0] + x[1]*x[1] + x[2]*x[2]); +} + +void DirectionCosines::Normalize() +{ + double *x = Values; + double den; + if ( (den = Norm(x)) != 0.0 ) + { + for (int i=0; i < 3; i++) + { + x[i] /= den; + } + } + x = Values+3; + if ( (den = Norm(x)) != 0.0 ) + { + for (int i=0; i < 3; i++) + { + x[i] /= den; + } + } +} + +bool DirectionCosines::SetFromString(const char *str) +{ + if( !str ) return false; + int n = sscanf( str, "%lf\\%lf\\%lf\\%lf\\%lf\\%lf", Values, Values+1, Values+2, Values+3, Values+4, Values+5 ); + if( n == 6 ) + { + return true; + } + // else + Values[0] = 1; + Values[1] = 0; + Values[2] = 0; + Values[3] = 0; + Values[4] = 1; + Values[5] = 0; + return false; +} + +double DirectionCosines::CrossDot(DirectionCosines const &dc) const +{ + double z1[3]; + Cross(z1); + double z2[3]; + dc.Cross(z2); + + const double *x = z1; + const double *y = z2; + return x[0]*y[0] + x[1]*y[1] + x[2]*y[2]; +} + +double DirectionCosines::ComputeDistAlongNormal(const double ipp[3]) const +{ + double normal[3]; + Cross(normal); + double dist = 0.; + for (int i = 0; i < 3; ++i) dist += normal[i]*ipp[i]; + return dist; +} + + +} diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmDirectionCosines.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmDirectionCosines.h new file mode 100644 index 0000000..ce0842b --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmDirectionCosines.h @@ -0,0 +1,68 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMDIRECTIONCOSINES_H +#define GDCMDIRECTIONCOSINES_H + +#include "gdcmTypes.h" + +namespace gdcm +{ + +/** + * \brief class to handle DirectionCosines + */ +class GDCM_EXPORT DirectionCosines +{ +public: + DirectionCosines(); + DirectionCosines(const double dircos[6]); + // Cannot get the following signature to be wrapped with swig... + //DirectionCosines(const double *dircos = 0 ); + ~DirectionCosines(); + + /// Print + void Print(std::ostream &) const; + + /// Compute Cross product + void Cross(double z[3]) const; + + /// Compute Dot + double Dot() const; + + /// Normalize in-place + void Normalize(); + + /// Make the class behave like a const double * + operator const double* () const { return Values; } + + /// Return whether or not this is a valid direction cosines + bool IsValid() const; + + /// Initialize from string str. It requires 6 floating point separated by a + /// backslash character. + bool SetFromString(const char *str); + + /// Compute the Dot product of the two cross vector of both DirectionCosines object + double CrossDot(DirectionCosines const &dc) const; + + /// Compute the distance along the normal + double ComputeDistAlongNormal(const double ipp[3]) const; + +private: + double Values[6]; +}; + +} // end namespace gdcm + +#endif //GDCMDIRECTIONCOSINES_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmDirectoryHelper.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmDirectoryHelper.cxx new file mode 100644 index 0000000..92c9bac --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmDirectoryHelper.cxx @@ -0,0 +1,267 @@ + +#include "gdcmDirectoryHelper.h" +#include "gdcmScanner.h" +#include "gdcmIPPSorter.h" +#include "gdcmAttribute.h" +#include "gdcmDataElement.h" +#include "gdcmReader.h" + + +namespace gdcm{ +//given an SOPClassUID, get the number of series that are that SOP Class +//that is, the MR images, the CT Images, whatever. Just have to be sure to give the proper +//SOP Class UID. +//returns an empty vector if nothing's there or if something goes wrong. +gdcm::Directory::FilenamesType DirectoryHelper::GetSeriesUIDsBySOPClassUID(const std::string& inDirectory, + const std::string& inSOPClassUID) +{ + gdcm::Scanner theScanner; + gdcm::Directory theDir; + theScanner.AddTag(Tag(0x0008, 0x0016));//SOP Class UID + theScanner.AddTag(Tag(0x0020, 0x000e));//Series UID + Directory::FilenamesType theReturn; + + try { + theDir.Load(inDirectory); + theScanner.Scan(theDir.GetFilenames()); + + //now find all series UIDs + Directory::FilenamesType theSeriesValues = theScanner.GetOrderedValues(Tag(0x0020,0x000e)); + + //now count the number of series that are of that given SOPClassUID + size_t theNumSeries = theSeriesValues.size(); + for (size_t i = 0; i < theNumSeries; i++){ + std::string theFirstFilename = + theScanner.GetFilenameFromTagToValue(Tag(0x0020,0x000e), theSeriesValues[i].c_str()); + std::string theSOPClassUID = theScanner.GetValue(theFirstFilename.c_str(), Tag(0x0008,0x0016)); + //dicom strings sometimes have trailing spaces; make sure to avoid those + size_t endpos = theSOPClassUID.find_last_not_of(" "); // Find the first character position from reverse af + if( std::string::npos != endpos ) + theSOPClassUID = theSOPClassUID.substr( 0, endpos+1 ); + if (theSOPClassUID == inSOPClassUID.c_str()){ + theReturn.push_back(theSeriesValues[i]); + } + } + return theReturn; + } catch (...){ + Directory::FilenamesType theBlank; + return theBlank;//something broke during scanning + } +} + + +//given the name of a directory, return the list of CT Image UIDs +gdcm::Directory::FilenamesType DirectoryHelper::GetCTImageSeriesUIDs(const std::string& inDirectory) +{ + return GetSeriesUIDsBySOPClassUID(inDirectory, "1.2.840.10008.5.1.4.1.1.2"); +} + +//given the name of a directory, return the list of CT Image UIDs +gdcm::Directory::FilenamesType DirectoryHelper::GetMRImageSeriesUIDs(const std::string& inDirectory) +{ + return GetSeriesUIDsBySOPClassUID(inDirectory, "1.2.840.10008.5.1.4.1.1.4"); +} + +//given the name of a directory, return the list of CT Image UIDs +gdcm::Directory::FilenamesType DirectoryHelper::GetRTStructSeriesUIDs(const std::string& inDirectory) +{ + return GetSeriesUIDsBySOPClassUID(inDirectory, "1.2.840.10008.5.1.4.1.1.481.3"); +} + +//given a directory and a series UID, provide all filenames with that series UID. +Directory::FilenamesType DirectoryHelper::GetFilenamesFromSeriesUIDs(const std::string& inDirectory, + const std::string& inSeriesUID) +{ + gdcm::Scanner theScanner; + gdcm::Directory theDir; + theScanner.AddTag(Tag(0x0020, 0x000e));//Series UID + Directory::FilenamesType theReturn; + + try { + theDir.Load(inDirectory); + theScanner.Scan(theDir.GetFilenames()); + //now find all series UIDs + Directory::FilenamesType theSeriesValues = theScanner.GetOrderedValues(Tag(0x0020,0x000e)); + //now count the number of series that are of that given SOPClassUID + size_t theNumSeries = theSeriesValues.size(); + for (size_t i = 0; i < theNumSeries; i++) + { + std::string theSeriesUID = theSeriesValues[i]; + //dicom strings sometimes have trailing spaces; make sure to avoid those + size_t endpos = theSeriesUID.find_last_not_of(" "); // Find the first character position from reverse af + if( std::string::npos != endpos ) + theSeriesUID = theSeriesUID.substr( 0, endpos+1 ); + if (inSeriesUID == theSeriesUID) + { + gdcm::Directory::FilenamesType theFilenames = + theScanner.GetAllFilenamesFromTagToValue(Tag(0x0020, 0x000e), theSeriesValues[i].c_str()); + gdcm::Directory::FilenamesType::const_iterator citor; + for (citor = theFilenames.begin(); citor < theFilenames.end(); citor++) + { + theReturn.push_back(*citor); + } + // theReturn.push_back(theScanner.GetFilenameFromTagToValue(Tag(0x0020,0x000e), + // theSeriesValues[i].c_str())); + } + } + return theReturn; + } catch (...){ + Directory::FilenamesType theBlank; + return theBlank;//something broke during scanning + } + +} +//the code in GetSeriesUIDsBySOPClassUID will enumerate the CT images in a directory +//This code will retrieve an image by its Series UID. +//this code doesn't return pointers or smart pointers because it's intended to +//be easily wrapped by calling languages that don't know pointers (ie, Java) +//this function is a proof of concept +//for it to really work, it needs to also +std::vector DirectoryHelper::LoadImageFromFiles(const std::string& inDirectory, + const std::string& inSeriesUID) +{ + gdcm::Scanner theScanner; + gdcm::Directory theDir; + theScanner.AddTag(Tag(0x0020, 0x000e));//Series UID + std::vector theReturn; + std::vector blank;//returned in case of an error + + try { + theDir.Load(inDirectory); + theScanner.Scan(theDir.GetFilenames()); + + //now find all series UIDs + Directory::FilenamesType theSeriesValues = theScanner.GetOrderedValues(Tag(0x0020,0x000e)); + + //now count the number of series that are of that given SOPClassUID + size_t theNumSeries = theSeriesValues.size(); + for (size_t i = 0; i < theNumSeries; i++){ + if (inSeriesUID == theSeriesValues[i]){ + //find all files that have that series UID, and then load them via + //the vtkImageReader + Directory::FilenamesType theFiles = + theScanner.GetAllFilenamesFromTagToValue(Tag(0x0020, 0x000e), theSeriesValues[i].c_str()); + IPPSorter sorter; + sorter.SetComputeZSpacing(true); + sorter.SetZSpacingTolerance(0.000001); + if (!sorter.Sort(theFiles)){ + gdcmWarningMacro("Unable to sort Image Files."); + return blank; + } + Directory::FilenamesType theSortedFiles = sorter.GetFilenames(); + for (unsigned long j = 0; j < theSortedFiles.size(); ++j){ + Reader theReader; + theReader.SetFileName(theSortedFiles[j].c_str()); + theReader.Read(); + theReturn.push_back(theReader.GetFile().GetDataSet()); + } + return theReturn; + } + } + return blank; + } catch (...){ + gdcmWarningMacro("Something went wrong reading CT images."); + return blank; + } +} + + +//When writing RTStructs, each contour will have z position defined. +//use that z position to determine the SOPInstanceUID for that plane. +std::string DirectoryHelper::RetrieveSOPInstanceUIDFromZPosition(double inZPos, + const std::vector& inDS) +{ + std::vector::const_iterator itor; + gdcm::Tag thePosition(0x0020, 0x0032); + gdcm::Tag theSOPInstanceUID(0x0008, 0x0018); + std::string blank;//return only if there's a problem + for (itor = inDS.begin(); itor != inDS.end(); itor++) + { + if (itor->FindDataElement(thePosition)) + { + DataElement de = itor->GetDataElement(thePosition); + gdcm::Attribute<0x0020,0x0032> at; + at.SetFromDataElement( de ); + if (fabs(at.GetValue(2) - inZPos)<0.01) + { + DataElement de2 = itor->GetDataElement(theSOPInstanceUID); + const ByteValue* theVal = de2.GetByteValue(); + size_t theValLen = theVal->GetLength(); + std::string theReturn(de2.GetByteValue()->GetPointer(), theValLen); + return theReturn; + } + } + } + return blank; +} + +//When writing RTStructs, the frame of reference is done by planes to start with +std::string DirectoryHelper::RetrieveSOPInstanceUIDFromIndex(int inIndex, + const std::vector& inDS) +{ + + gdcm::Tag theSOPInstanceUID(0x0008, 0x0018); + std::string blank;//return only if there's a problem + if (inDS[inIndex].FindDataElement(theSOPInstanceUID)){ + DataElement de = inDS[inIndex].GetDataElement(theSOPInstanceUID); + const ByteValue* theVal = de.GetByteValue(); + size_t theValLen = theVal->GetLength(); + std::string theReturn(de.GetByteValue()->GetPointer(), theValLen); + return theReturn; + } + return blank; +} + +//each plane needs to know the SOPClassUID, and that won't change from image to image +//so, retrieve this once at the start of writing. +std::string DirectoryHelper::GetSOPClassUID(const std::vector& inDS) +{ + gdcm::Tag theSOPClassUID(0x0008, 0x0016); + std::string blank;//return only if there's a problem + if (inDS[0].FindDataElement(theSOPClassUID)){ + DataElement de = inDS[0].GetDataElement(theSOPClassUID); + const ByteValue* theVal = de.GetByteValue(); + size_t theValLen = theVal->GetLength(); + std::string theReturn(de.GetByteValue()->GetPointer(), theValLen); + return theReturn; + } + return blank; +} + +//retrieve the frame of reference from the set of datasets +std::string DirectoryHelper::GetFrameOfReference(const std::vector& inDS){ + + gdcm::Tag theSOPClassUID(0x0020, 0x0052); + std::string blank;//return only if there's a problem + if (inDS[0].FindDataElement(theSOPClassUID)){ + DataElement de = inDS[0].GetDataElement(theSOPClassUID); + const ByteValue* theVal = de.GetByteValue(); + size_t theValLen = theVal->GetLength(); + std::string theReturn(de.GetByteValue()->GetPointer(), theValLen); + return theReturn; + } + return blank; +} + + +//---------------------------------------------------------------------------- +//used by the vtkGDCMImageReader and vtkGDCMPolyDataReader. Could be used elsewhere, I suppose. +std::string DirectoryHelper::GetStringValueFromTag(const gdcm::Tag& t, const gdcm::DataSet& ds) +{ + std::string buffer; + + if( ds.FindDataElement( t ) ) + { + const gdcm::DataElement& de = ds.GetDataElement( t ); + const gdcm::ByteValue *bv = de.GetByteValue(); + if( bv ) // Can be Type 2 + { + buffer = std::string( bv->GetPointer(), bv->GetLength() ); + // Will be padded with at least one \0 + } + } + + // Since return is a const char* the very first \0 will be considered + return buffer.c_str(); // Yes, I mean .c_str() +} +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmDirectoryHelper.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmDirectoryHelper.h new file mode 100644 index 0000000..6bcd115 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmDirectoryHelper.h @@ -0,0 +1,80 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#include "gdcmDirectory.h" +#include "gdcmDataSet.h" + +namespace gdcm +{ + +/** + * \brief DirectoryHelper + * this class is designed to help mitigate some of the commonly performed + * operations on directories. namely: + * 1) the ability to determine the number of series in a directory by what type + * of series is present + * 2) the ability to find all ct series in a directory + * 3) the ability to find all mr series in a directory + * 4) to load a set of DataSets from a series that's already been sorted by the + * IPP sorter + * 5) For rtstruct stuff, you need to know the sopinstanceuid of each z plane, + * so there's a retrieval function for that + * 6) then a few other functions for rtstruct writeouts + */ +class GDCM_EXPORT DirectoryHelper +{ +public: + //returns all series UIDs in a given directory that match a particular SOP Instance UID + static Directory::FilenamesType GetSeriesUIDsBySOPClassUID(const std::string& inDirectory, + const std::string& inSOPClassUID); + + //specific implementations of the SOPClassUID grabber, so you don't have to + //remember the SOP Class UIDs of CT or MR images. + static Directory::FilenamesType GetCTImageSeriesUIDs(const std::string& inDirectory); + static Directory::FilenamesType GetMRImageSeriesUIDs(const std::string& inDirectory); + static Directory::FilenamesType GetRTStructSeriesUIDs(const std::string& inDirectory); + + //given a directory and a series UID, provide all filenames with that series UID. + static Directory::FilenamesType GetFilenamesFromSeriesUIDs(const std::string& inDirectory, + const std::string& inSeriesUID); + + //given a series UID, load all the images associated with that series UID + //these images will be IPP sorted, so that they can be used for gathering all + //the necessary information for generating an RTStruct + //this function should be called by the writer once, if the writer's dataset + //vector is empty. Make sure to have a new writer for new rtstructs. + static std::vector LoadImageFromFiles(const std::string& inDirectory, + const std::string& inSeriesUID); + + //When writing RTStructs, each contour will have z position defined. + //use that z position to determine the SOPInstanceUID for that plane. + static std::string RetrieveSOPInstanceUIDFromZPosition(double inZPos, + const std::vector& inDS); + + //When writing RTStructs, the frame of reference is done by planes to start with + static std::string RetrieveSOPInstanceUIDFromIndex(int inIndex, + const std::vector& inDS); + + //each plane needs to know the SOPClassUID, and that won't change from image to image + //so, retrieve this once at the start of writing. + static std::string GetSOPClassUID(const std::vector& inDS); + + //retrieve the frame of reference from the set of datasets + static std::string GetFrameOfReference(const std::vector& inDS); + + //both the image and polydata readers use these functions to get std::strings + static std::string GetStringValueFromTag(const gdcm::Tag& t, const gdcm::DataSet& ds); +}; + +} diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmDumper.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmDumper.cxx new file mode 100644 index 0000000..3e5c030 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmDumper.cxx @@ -0,0 +1,18 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmDumper.h" + +namespace gdcm +{ +} diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmDumper.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmDumper.h new file mode 100644 index 0000000..1222845 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmDumper.h @@ -0,0 +1,38 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMDUMPER_H +#define GDCMDUMPER_H + +#include "gdcmPrinter.h" + +namespace gdcm +{ + +// It's a sink there is no output +/** + * \brief Codec class + * \note + * Use it to simply dump value read from the file. No interpretation is done. + * But it is real fast ! Almost no overhead + */ +class GDCM_EXPORT Dumper : public Printer +{ +public: + Dumper() { PrintStyle = CONDENSED_STYLE; } + ~Dumper() {}; +}; + +} // end namespace gdcm + +#endif //GDCMDUMPER_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmEncapsulatedDocument.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmEncapsulatedDocument.cxx new file mode 100644 index 0000000..bc4caf5 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmEncapsulatedDocument.cxx @@ -0,0 +1,17 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmEncapsulatedDocument.h" + +namespace gdcm +{} diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmEncapsulatedDocument.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmEncapsulatedDocument.h new file mode 100644 index 0000000..0c51475 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmEncapsulatedDocument.h @@ -0,0 +1,34 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMENCAPSULATEDDOCUMENT_H +#define GDCMENCAPSULATEDDOCUMENT_H + +#include "gdcmFile.h" + +namespace gdcm +{ +/** + * \brief EncapsulatedDocument + */ +class GDCM_EXPORT EncapsulatedDocument +{ +public: + EncapsulatedDocument() {} + +private: +}; + +} // end namespace gdcm + +#endif //GDCMENCAPSULATEDDOCUMENT_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmFiducials.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmFiducials.cxx new file mode 100644 index 0000000..f20e6ed --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmFiducials.cxx @@ -0,0 +1,17 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmFiducials.h" + +namespace gdcm +{} diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmFiducials.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmFiducials.h new file mode 100644 index 0000000..93e4179 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmFiducials.h @@ -0,0 +1,34 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMFIDUCIALS_H +#define GDCMFIDUCIALS_H + +#include "gdcmFile.h" + +namespace gdcm +{ +/** + * \brief Fiducials + */ +class GDCM_EXPORT Fiducials +{ +public: + Fiducials() {} + +private: +}; + +} // end namespace gdcm + +#endif //GDCMFIDUCIALS_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmFileAnonymizer.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmFileAnonymizer.cxx new file mode 100644 index 0000000..8ae0e53 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmFileAnonymizer.cxx @@ -0,0 +1,524 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmFileAnonymizer.h" + +#include "gdcmReader.h" + +#include +#include +#include +#include +#include // sort + +namespace gdcm +{ + +enum Action +{ + EMPTY, + REMOVE, + REPLACE +}; + +struct PositionEmpty +{ + std::streampos BeginPos; + std::streampos EndPos; + Action action; + bool IsTagFound; // Required for EMPTY + DataElement DE; + bool operator() (const PositionEmpty & i, const PositionEmpty & j) + { + return (int)i.BeginPos < (int)j.BeginPos; + } +}; + +class FileAnonymizerInternals +{ +public: + std::string InputFilename; + std::string OutputFilename; + std::set EmptyTags; + std::set RemoveTags; + std::map ReplaceTags; + TransferSyntax TS; + std::vector PositionEmptyArray; +}; + +FileAnonymizer::FileAnonymizer() +{ + Internals = new FileAnonymizerInternals; +} + +FileAnonymizer::~FileAnonymizer() +{ + delete Internals; +} + +void FileAnonymizer::Empty( Tag const &t ) +{ + if( t.GetGroup() >= 0x0008 ) + { + Internals->EmptyTags.insert( t ); + } +} + +void FileAnonymizer::Remove( Tag const &t ) +{ + if( t.GetGroup() >= 0x0008 ) + { + Internals->RemoveTags.insert( t ); + } +} + +void FileAnonymizer::Replace( Tag const &t, const char *value ) +{ + if( value && t.GetGroup() >= 0x0008 ) + { + Internals->ReplaceTags.insert( + std::make_pair( t, value) ); + } +} + +void FileAnonymizer::Replace( Tag const &t, const char *value, VL const & vl ) +{ + if( value && t.GetGroup() >= 0x0008 ) + { + Internals->ReplaceTags.insert( + std::make_pair( t, std::string(value, vl) ) ); + } +} + +void FileAnonymizer::SetInputFileName(const char *filename_native) +{ + if( filename_native ) + Internals->InputFilename = filename_native; +} + +void FileAnonymizer::SetOutputFileName(const char *filename_native) +{ + if( filename_native ) + Internals->OutputFilename = filename_native; +} + +bool FileAnonymizer::ComputeReplaceTagPosition() +{ +/* + Implementation details: + We should make sure that the user know what she is doing in case of SQ. + Let's assume a User call Replace( Tag(0x0008,0x2112), "FOOBAR" ) + For quite a lot of DICOM implementation this Tag is required to be a SQ. + Therefore even if the Attribute is declared with VR:UN, some implementation + will try very hard to decode it as SQ...which obviously will fail + Instead do not support SQ at all here and document it should not be used for SQ + */ + assert( !Internals->InputFilename.empty() ); + const char *filename = Internals->InputFilename.c_str(); + assert( filename ); + + std::map::reverse_iterator rit = Internals->ReplaceTags.rbegin(); + for ( ; rit != Internals->ReplaceTags.rend(); rit++ ) + { + PositionEmpty pe; + + std::set removeme; + const Tag & t = rit->first; + const std::string & valuereplace = rit->second; + removeme.insert( t ); + + std::ifstream is( filename, std::ios::binary ); + Reader reader; + reader.SetStream( is ); + if( !reader.ReadSelectedTags( removeme ) ) + { + return false; + } + + pe.EndPos = pe.BeginPos = is.tellg(); + pe.action = REPLACE; + pe.IsTagFound = false; + const File & f = reader.GetFile(); + const DataSet &ds = f.GetDataSet(); + const TransferSyntax &ts = f.GetHeader().GetDataSetTransferSyntax(); + Internals->TS = ts; + + pe.DE.SetTag( t ); + if( ds.FindDataElement( t ) ) + { + const DataElement &de = ds.GetDataElement( t ); + pe.IsTagFound = true; + pe.DE.SetVL( de.GetVL() ); // Length is not used, unless to check undefined flag + pe.DE.SetVR( de.GetVR() ); + assert( pe.DE.GetVL().IsUndefined() == de.GetVL().IsUndefined() ); + assert( pe.DE.GetVR() == de.GetVR() ); + assert( pe.DE.GetTag() == de.GetTag() ); + if( de.GetVL().IsUndefined() ) + { + // This is a SQ + gdcmErrorMacro( "Replacing a SQ is not supported. Use Remove() or Empty()" ); + return false; + } + else + { + assert( !de.GetVL().IsUndefined() ); + pe.BeginPos -= de.GetVL(); + pe.BeginPos -= 2 * de.GetVR().GetLength(); // (VR+) VL + pe.BeginPos -= 4; // Tag + assert( (int)pe.EndPos == + (int)pe.BeginPos + (int)de.GetVL() + 2 * de.GetVR().GetLength() + 4 ); + } + pe.DE.SetByteValue( valuereplace.c_str(), (uint32_t)valuereplace.size() ); + assert( pe.DE.GetVL() == valuereplace.size() ); + } + else + { + // We need to insert an Empty Data Element ! + //FIXME, for some public element we could do something nicer than VR:UN + pe.DE.SetVR( VR::UN ); + pe.DE.SetByteValue( valuereplace.c_str(), (uint32_t)valuereplace.size() ); + assert( pe.DE.GetVL() == valuereplace.size() ); + } + + // We need to push_back outside of if() since Action:Empty + // on a missing tag, means insert it ! + Internals->PositionEmptyArray.push_back( pe ); + + is.close(); + } + return true; +} + +bool FileAnonymizer::ComputeRemoveTagPosition() +{ + assert( !Internals->InputFilename.empty() ); + const char *filename = Internals->InputFilename.c_str(); + assert( filename ); + + std::set::reverse_iterator rit = Internals->RemoveTags.rbegin(); + for ( ; rit != Internals->RemoveTags.rend(); rit++ ) + { + PositionEmpty pe; + + std::set removeme; + const Tag & t = *rit; + removeme.insert( t ); + + std::ifstream is( filename, std::ios::binary ); + Reader reader; + reader.SetStream( is ); + if( !reader.ReadSelectedTags( removeme ) ) + { + return false; + } + + pe.EndPos = pe.BeginPos = is.tellg(); + pe.action = REMOVE; + pe.IsTagFound = false; + const File & f = reader.GetFile(); + const DataSet &ds = f.GetDataSet(); + const TransferSyntax &ts = f.GetHeader().GetDataSetTransferSyntax(); + Internals->TS = ts; + + pe.DE.SetTag( t ); + if( ds.FindDataElement( t ) ) + { + const DataElement &de = ds.GetDataElement( t ); + pe.IsTagFound = true; + pe.DE.SetVL( de.GetVL() ); // Length is not used, unless to check undefined flag + pe.DE.SetVR( de.GetVR() ); + assert( pe.DE.GetVL().IsUndefined() == de.GetVL().IsUndefined() ); + assert( pe.DE.GetVR() == de.GetVR() ); + assert( pe.DE.GetTag() == de.GetTag() ); + if( de.GetVL().IsUndefined() ) + { + // This is a SQ + VL vl; + if( ts.GetNegociatedType() == TransferSyntax::Implicit ) + { + vl = de.GetLength(); + } + else + { + vl = de.GetLength(); + } + assert( pe.BeginPos > vl ); + pe.BeginPos -= vl; + } + else + { + assert( !de.GetVL().IsUndefined() ); + pe.BeginPos -= de.GetVL(); + pe.BeginPos -= 2 * de.GetVR().GetLength(); // (VR+) VL + pe.BeginPos -= 4; // Tag + assert( (int)pe.EndPos == + (int)pe.BeginPos + (int)de.GetVL() + 2 * de.GetVR().GetLength() + 4 ); + } + Internals->PositionEmptyArray.push_back( pe ); + } + else + { + // Yay no need to do anything ! + } + + is.close(); + } + + return true; +} + +bool FileAnonymizer::ComputeEmptyTagPosition() +{ + // FIXME we sometime empty, attributes that are already empty... + assert( !Internals->InputFilename.empty() ); + const char *filename = Internals->InputFilename.c_str(); + assert( filename ); + + std::set::reverse_iterator rit = Internals->EmptyTags.rbegin(); + for ( ; rit != Internals->EmptyTags.rend(); rit++ ) + { + PositionEmpty pe; + + std::set removeme; + const Tag & t = *rit; + removeme.insert( t ); + + std::ifstream is( filename, std::ios::binary ); + Reader reader; + reader.SetStream( is ); + if( !reader.ReadSelectedTags( removeme ) ) + { + return false; + } + + pe.EndPos = pe.BeginPos = is.tellg(); + pe.action = EMPTY; + pe.IsTagFound = false; + const File & f = reader.GetFile(); + const DataSet &ds = f.GetDataSet(); + const TransferSyntax &ts = f.GetHeader().GetDataSetTransferSyntax(); + Internals->TS = ts; + + pe.DE.SetTag( t ); + if( ds.FindDataElement( t ) ) + { + const DataElement &de = ds.GetDataElement( t ); + pe.IsTagFound = true; + pe.DE.SetVL( de.GetVL() ); // Length is not used, unless to check undefined flag + pe.DE.SetVR( de.GetVR() ); + assert( pe.DE.GetVL().IsUndefined() == de.GetVL().IsUndefined() ); + assert( pe.DE.GetVR() == de.GetVR() ); + assert( pe.DE.GetTag() == de.GetTag() ); + if( de.GetVL().IsUndefined() ) + { + // This is a SQ + VL vl; + if( ts.GetNegociatedType() == TransferSyntax::Implicit ) + { + vl = de.GetLength(); + } + else + { + vl = de.GetLength(); + } + assert( pe.BeginPos > vl ); + pe.BeginPos -= vl; + pe.BeginPos += 4; // Tag + if( ts.GetNegociatedType() == TransferSyntax::Implicit ) + { + pe.BeginPos += 0; + } + else + { + pe.BeginPos += de.GetVR().GetLength(); + } + } + else + { + assert( !de.GetVL().IsUndefined() ); + pe.BeginPos -= de.GetVL(); + if( ts.GetNegociatedType() == TransferSyntax::Implicit ) + { + pe.BeginPos -= 4; + } + else + { + pe.BeginPos -= de.GetVR().GetLength(); + assert( (int)pe.EndPos == + (int)pe.BeginPos + (int)de.GetVL() + de.GetVR().GetLength() ); + } + } + } + else + { + // We need to insert an Empty Data Element ! + //FIXME, for some public element we could do something nicer than VR:UN + pe.DE.SetVR( VR::UN ); + pe.DE.SetVL( 0 ); + } + + // We need to push_back outside of if() since Action:Empty + // on a missing tag, means insert it ! + Internals->PositionEmptyArray.push_back( pe ); + + is.close(); + } + + return true; +} + +bool FileAnonymizer::Write() +{ + if( Internals->OutputFilename.empty() ) return false; + const char *outfilename = Internals->OutputFilename.c_str(); + if( Internals->InputFilename.empty() ) return false; + const char *filename = Internals->InputFilename.c_str(); + + Internals->PositionEmptyArray.clear(); + + // Compute offsets + if( !ComputeRemoveTagPosition() + || !ComputeEmptyTagPosition() + || !ComputeReplaceTagPosition() ) + { + return false; + } + + // Make sure we will copy from lower offset to highest: + PositionEmpty pe_sort = {}; + std::sort (Internals->PositionEmptyArray.begin(), + Internals->PositionEmptyArray.end(), pe_sort); + + // Step 2. Copy & skip proper portion + std::ofstream of( outfilename, std::ios::binary ); + std::ifstream is( filename, std::ios::binary ); + std::vector::const_iterator it = + Internals->PositionEmptyArray.begin(); + std::streampos prev = 0; + const TransferSyntax &ts = Internals->TS; + for( ; it != Internals->PositionEmptyArray.end(); ++it ) + { + const PositionEmpty & pe = *it; + Action action = pe.action; + + if( pe.IsTagFound ) + { + const DataElement & de = pe.DE; + int vrlen = de.GetVR().GetLength(); + if( ts.GetNegociatedType() == TransferSyntax::Implicit ) + { + vrlen = 4; + } + + std::streampos end = pe.BeginPos; + + // FIXME: most efficient way to copy chunk of file in c++ ? + for( int i = (int)prev; i < end; ++i) + { + of.put( (char)is.get() ); + } + if( action == EMPTY ) + { + // Create a 0 Value Length (VR+Tag was copied in previous loop) + for( int i = 0; i < vrlen; ++i) + { + of.put( 0 ); + } + } + else if( action == REPLACE ) + { + if( ts.GetSwapCode() == SwapCode::BigEndian ) + { + if( ts.GetNegociatedType() == TransferSyntax::Implicit ) + { + gdcmErrorMacro( "Cant write Virtual Big Endian" ); + return 1; + } + else + { + pe.DE.Write( of ); + } + } + else + { + if( ts.GetNegociatedType() == TransferSyntax::Implicit ) + { + pe.DE.Write( of ); + } + else + { + pe.DE.Write( of ); + } + } + } + // Skip the Value + assert( is.good() ); + is.seekg( pe.EndPos ); + assert( is.good() ); + prev = is.tellg(); + assert( prev == pe.EndPos ); + } + else + { + std::streampos end = pe.BeginPos; + + // FIXME: most efficient way to copy chunk of file in c++ ? + for( int i = (int)prev; i < end; ++i) + { + of.put( (char)is.get() ); + } + if( ts.GetSwapCode() == SwapCode::BigEndian ) + { + if( ts.GetNegociatedType() == TransferSyntax::Implicit ) + { + gdcmErrorMacro( "Cant write Virtual Big Endian" ); + return 1; + } + else + { + pe.DE.Write( of ); + } + } + else + { + if( ts.GetNegociatedType() == TransferSyntax::Implicit ) + { + pe.DE.Write( of ); + } + else + { + pe.DE.Write( of ); + } + } + prev = is.tellg(); + } + } + + of << is.rdbuf(); + of.close(); + is.close(); + +#if 0 + Reader r; + r.SetFileName( outfilename ); + if( !r.Read() ) + { + gdcmErrorMacro( "Output file got corrupted, please report" ); + return false; + } +#endif + + return true; +} + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmFileAnonymizer.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmFileAnonymizer.h new file mode 100644 index 0000000..1615974 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmFileAnonymizer.h @@ -0,0 +1,86 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMFILEANONYMIZER_H +#define GDCMFILEANONYMIZER_H + +#include "gdcmSubject.h" +#include "gdcmEvent.h" +#include "gdcmTag.h" +#include "gdcmVL.h" + +namespace gdcm +{ +class FileAnonymizerInternals; + +/** + * \brief FileAnonymizer + * + * This Anonymizer is a file-based Anonymizer. It requires a valid DICOM + * file and will use the Value Length to skip over any information. + * + * It will not load the DICOM dataset taken from SetInputFileName() into memory + * and should consume much less memory than gdcm::Anonymizer. + * + * \warning: Each time you call Replace() with a value. This value will copied, + * and stored in memory. The behavior is not ideal for extremely large data + * (larger than memory size). This class is really meant to take a large DICOM + * input file and then only changed some small attribute. + * + * caveats: + * \li This class will NOT work with unordered attributes in a DICOM File, + * \li This class does neither recompute nor update the Group Length element, + * \li This class currently does not update the File Meta Information header. + */ +class GDCM_EXPORT FileAnonymizer : public Subject +{ +public: + FileAnonymizer(); + ~FileAnonymizer(); + + /// Make Tag t empty + /// Warning: does not handle SQ element + void Empty( Tag const &t ); + + /// remove a tag (even a SQ can be removed) + void Remove( Tag const &t ); + + /// Replace tag with another value, if tag is not found it will be created: + /// WARNING: this function can only execute if tag is a VRASCII + /// WARNING: Do not ever try to write a value in a SQ Data Element ! + void Replace( Tag const &t, const char *value_str ); + + /// when the value contains \0, it is a good idea to specify the length. This function + /// is required when dealing with VRBINARY tag + void Replace( Tag const &t, const char *value_data, VL const & vl ); + + /// Set input filename + void SetInputFileName(const char *filename_native); + + /// Set output filename + void SetOutputFileName(const char *filename_native); + + /// Write the output file + bool Write(); + +private: + bool ComputeEmptyTagPosition(); + bool ComputeRemoveTagPosition(); + bool ComputeReplaceTagPosition(); + FileAnonymizerInternals *Internals; + +}; + +} // end namespace gdcm + +#endif //GDCMFILEANONYMIZER_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmFileChangeTransferSyntax.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmFileChangeTransferSyntax.cxx new file mode 100644 index 0000000..38d435e --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmFileChangeTransferSyntax.cxx @@ -0,0 +1,259 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmFileChangeTransferSyntax.h" + +#include "gdcmImageCodec.h" +#include "gdcmReader.h" +#include "gdcmWriter.h" +#include "gdcmImageRegionReader.h" +#include "gdcmJPEGCodec.h" +#include "gdcmImageHelper.h" +#include "gdcmEvent.h" +#include "gdcmProgressEvent.h" + +namespace gdcm +{ + +class FileChangeTransferSyntaxInternals +{ +public: + FileChangeTransferSyntaxInternals(): + IC(NULL), + InitializeCopy(false) + {} + ~FileChangeTransferSyntaxInternals() + { + } + ImageCodec *IC; + bool InitializeCopy; + std::streampos PixelDataPos; + std::string InFilename; + std::string OutFilename; + TransferSyntax TS; + JPEGCodec jpeg; + std::vector Dims; + PixelFormat PF; + PhotometricInterpretation PI; + unsigned int PC; + bool Needbyteswap; + double Progress; +}; + +FileChangeTransferSyntax::FileChangeTransferSyntax() +{ + Internals = new FileChangeTransferSyntaxInternals; +} + +FileChangeTransferSyntax::~FileChangeTransferSyntax() +{ + delete Internals; +} + +bool FileChangeTransferSyntax::Change() +{ + this->InvokeEvent( StartEvent() ); + if( !InitializeCopy() ) + { + gdcmDebugMacro( "Could not InitializeCopy" ); + return false; + } + + const char *filename = this->Internals->InFilename.c_str(); + std::ifstream is( filename, std::ios::binary ); + is.seekg( Internals->PixelDataPos, std::ios::beg ); + const char *outfilename = this->Internals->OutFilename.c_str(); + std::fstream os( outfilename, std::ofstream::in | std::ofstream::out | std::ios::binary ); + os.seekp( 0, std::ios::end ); + + const std::vector & dims = Internals->Dims; + const PixelFormat &pf = Internals->PF; + const PhotometricInterpretation &pi = Internals->PI; + unsigned int pc = Internals->PC; + const int pixsize = pf.GetPixelSize(); + + const bool needbyteswap = Internals->Needbyteswap; + ImageCodec *codec = Internals->IC; + codec->SetDimensions( dims ); + codec->SetNumberOfDimensions( 2 ); + codec->SetPlanarConfiguration( pc ); + codec->SetPhotometricInterpretation( pi ); + codec->SetNeedByteSwap( needbyteswap ); + codec->SetPixelFormat( pf ); // need to be last ! + + std::vector vbuffer; + vbuffer.resize( dims[0] * pixsize ); + + char *data = &vbuffer[0]; + const size_t datalen = vbuffer.size(); + + VL vl; + vl.SetToUndefined(); + DataElement de( Tag(0x7fe0,0x0010), vl, VR::OB ); + switch ( pf.GetBitsAllocated() ) + { + case 8: + de.SetVR( VR::OB ); + break; + //case 12: + case 16: + case 32: + de.SetVR( VR::OW ); + break; + default: + return false; + } + de.GetTag().Write( os ); + de.GetVR().Write( os ); + de.GetVL().Write( os ); + + Fragment frag; + // Basic Offset Table + frag.Write( os ); + + const size_t nscanlines = dims[2] * dims[1]; + const double progresstick = 1. / (double)nscanlines; + Internals->Progress = 0; + for( unsigned int z = 0; z < dims[2]; ++z ) + { + // frag header: + frag.Write( os ); + std::streampos start = os.tellp(); + for( unsigned int y = 0; y < dims[1]; ++y ) + { + is.read( data, datalen ); + assert( is.good() ); + bool b = ((JPEGCodec*)Internals->IC)->EncodeBuffer(os, data, datalen); + if( !b ) return false; + Internals->Progress += progresstick; + ProgressEvent pe; + pe.SetProgress( Internals->Progress ); + this->InvokeEvent( pe ); + } + const std::streampos end = os.tellp(); + + // Compute JPEG length: + const VL jpegvl = (uint32_t)(end - start); + start -= 4; + if( jpegvl.IsOdd() ) + { + // 0 - padding: + os.put( 0 ); + } + os.seekp( start, std::ios::beg ); + jpegvl.Write( os ); + os.seekp( 0, std::ios::end ); + } + + const Tag seqDelItem(0xfffe,0xe0dd); + seqDelItem.Write(os); + VL zero = 0; + zero.Write(os); + + is.close(); + os.close(); + + this->InvokeEvent( EndEvent() ); + return true; +} + +void FileChangeTransferSyntax::SetTransferSyntax( TransferSyntax const & ts ) +{ + Internals->TS = ts; + Internals->IC = &Internals->jpeg; +} + +ImageCodec * FileChangeTransferSyntax::GetCodec() +{ + return Internals->IC; +} + +void FileChangeTransferSyntax::SetInputFileName(const char *filename_native) +{ + if( filename_native ) + Internals->InFilename = filename_native; +} + +void FileChangeTransferSyntax::SetOutputFileName(const char *filename_native) +{ + if( filename_native ) + Internals->OutFilename = filename_native; +} + +bool FileChangeTransferSyntax::InitializeCopy() +{ + if( !Internals->IC ) + { + return false; + } + if( !this->Internals->InitializeCopy ) + { + const char *filename = this->Internals->InFilename.c_str(); + const char *outfilename = this->Internals->OutFilename.c_str(); + { + // Make sure to update image meta data: + std::ifstream is( filename, std::ios::binary ); + ImageRegionReader reader; + reader.SetStream( is ); + if( !reader.ReadInformation() ) + { + gdcmDebugMacro("ImageRegionReader::ReadInformation failed" ); + return false; + } + is.clear(); // important + Internals->PixelDataPos = is.tellg(); + gdcm::File & file = reader.GetFile(); + const DataSet & ds = file.GetDataSet(); + if( ds.FindDataElement( Tag(0x7fe0,0x0010) ) ) + { + const DataElement & de = ds.GetDataElement( Tag(0x7fe0,0x0010) ); + gdcmAssertAlwaysMacro( "Impossible happen"); (void)de; + return false; + } + gdcm::FileMetaInformation & fmi = file.GetHeader(); + const TransferSyntax &ts = fmi.GetDataSetTransferSyntax(); + if( ts.IsEncapsulated() ) + { + gdcmDebugMacro( "Dont know how to handle encapsulated TS: " << ts ); + return false; + } + if(ts == TransferSyntax::ImplicitVRBigEndianPrivateGE || ts == TransferSyntax::ExplicitVRBigEndian ) + { + gdcmDebugMacro( "Dont know how to handle TS: " << ts ); + return false; + } + Internals->Needbyteswap = (ts == TransferSyntax::ImplicitVRBigEndianPrivateGE || ts == TransferSyntax::ExplicitVRBigEndian ); + Internals->Dims = ImageHelper::GetDimensionsValue(file); + Internals->PF = ImageHelper::GetPixelFormatValue(file); + Internals->PI = ImageHelper::GetPhotometricInterpretationValue(file); + Internals->PC = ImageHelper::GetPlanarConfigurationValue(file); + if( Internals->PC ) + { + gdcmDebugMacro( "Dont know how to handle Planar Configuration" ); + return false; + } + is.close(); + + Writer writer; + fmi.Clear(); + fmi.SetDataSetTransferSyntax( Internals->TS ); + writer.SetFileName( outfilename ); + writer.SetFile( file ); + if( !writer.Write() ) return false; + } + this->Internals->InitializeCopy = true; + } + return true; +} + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmFileChangeTransferSyntax.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmFileChangeTransferSyntax.h new file mode 100644 index 0000000..005158e --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmFileChangeTransferSyntax.h @@ -0,0 +1,71 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMFILECHANGETRANSFERSYNTAX_H +#define GDCMFILECHANGETRANSFERSYNTAX_H + +#include "gdcmSubject.h" +#include "gdcmSmartPointer.h" + +namespace gdcm +{ +class FileChangeTransferSyntaxInternals; +class ImageCodec; +class TransferSyntax; + +/** + * \brief FileChangeTransferSyntax + * + * This class is a file-based replacement of the in-memory + * ImageChangeTransferSyntax + * + * This class provide a file-based compression mecanism. It will take in an + * uncompressed DICOM image file (Pixel Data element). Then then produced as + * output a compressed DICOM file (Transfer Syntax will be updated). + * + * Currently it supports the following transfer syntax: + * - JPEGLosslessProcess14_1 + */ +class GDCM_EXPORT FileChangeTransferSyntax : public Subject +{ +public: + FileChangeTransferSyntax(); + ~FileChangeTransferSyntax(); + + /// Set input filename (raw DICOM) + void SetInputFileName(const char *filename_native); + + /// Set output filename (target compressed DICOM) + void SetOutputFileName(const char *filename_native); + + /// Change the transfer syntax + bool Change(); + + /// Specify the Target Transfer Syntax + void SetTransferSyntax( TransferSyntax const & ts ); + + /// Retrieve the actual codec (valid after calling SetTransferSyntax) + /// Only advanced users should call this function. + ImageCodec * GetCodec(); + + /// for wrapped language: instantiate a reference counted object + static SmartPointer New() { return new FileChangeTransferSyntax; } + +private: + bool InitializeCopy(); + FileChangeTransferSyntaxInternals *Internals; +}; + +} // end namespace gdcm + +#endif //GDCMFILEANONYMIZER_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmFileDerivation.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmFileDerivation.cxx new file mode 100644 index 0000000..59e8d41 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmFileDerivation.cxx @@ -0,0 +1,496 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmFileDerivation.h" +#include "gdcmFile.h" +#include "gdcmAttribute.h" +#include "gdcmUIDGenerator.h" + +#include +#include + +/* +PS 3.16 - 2008 +CID 7202 Source Image Purposes of Reference +Context ID 7202 +Source Image Purposes of Reference +Type: Extensible Version: 20051101 +Coding Scheme +Designator +(0008,0102) +Code Value +(0008,0100) +Code Meaning +(0008,0104) +DCM 121320 Uncompressed predecessor +DCM 121321 Mask image for image processing operation +DCM 121322 Source image for image processing operation +DCM 121329 Source image for montage +DCM 121330 Lossy compressed predecessor +*/ + +/* +CID 7203 Image Derivation +Context ID 7203 +Image Derivation +Type: Extensible Version: 20050822 +Coding Scheme +Designator +(0008,0102) +Code Value +(0008,0100) +Code Meaning +(0008,0104) +DCM 113040 Lossy Compression +DCM 113041 Apparent Diffusion Coefficient +DCM 113042 Pixel by pixel addition +DCM 113043 Diffusion weighted +DCM 113044 Diffusion Anisotropy +DCM 113045 Diffusion Attenuated +DCM 113046 Pixel by pixel division +DCM 113047 Pixel by pixel mask +DCM 113048 Pixel by pixel Maximum +DCM 113049 Pixel by pixel mean +DCM 113050 Metabolite Maps from spectroscopy data +DCM 113051 Pixel by pixel Minimum +DCM 113052 Mean Transit Time +DCM 113053 Pixel by pixel multiplication +DCM 113054 Negative Enhancement Integral +DCM 113055 Regional Cerebral Blood Flow +DCM 113056 Regional Cerebral Blood Volume +DCM 113057 R-Coefficient Map +DCM 113058 Proton Density map +DCM 113059 Signal Change Map +DCM 113060 Signal to Noise Map +DCM 113061 Standard Deviation +DCM 113062 Pixel by pixel subtraction +DCM 113063 T1 Map +DCM 113064 T2* Map +DCM 113065 T2 Map +DCM 113066 Time Course of Signal +DCM 113067 Temperature encoded +DCM 113068 Student¿s T-Test +DCM 113069 Time To Peak map +DCM 113070 Velocity encoded +DCM 113071 Z-Score Map +DCM 113072 Multiplanar reformatting +DCM 113073 Curved multiplanar reformatting +DCM 113074 Volume rendering +DCM 113075 Surface rendering +DCM 113076 Segmentation +DCM 113077 Volume editing +DCM 113078 Maximum intensity projection +DCM 113079 Minimum intensity projection +DCM 113085 Spatial resampling +DCM 113086 Edge enhancement +DCM 113087 Smoothing +DCM 113088 Gaussian blur +DCM 113089 Unsharp mask +DCM 113090 Image stitching +*/ +namespace gdcm +{ +/* +Annex D DICOM Controlled Terminology Definitions (Normative) +This Annex specifies the meanings of codes defined in DICOM, either explicitly or by reference to another +part of DICOM or an external reference document or standard. +DICOM Code Definitions (Coding Scheme Designator ¿DCM¿ Coding Scheme Version ¿01¿) +*/ + +struct CodeDefinition +{ +const char *CodingSchemeDesignator; +unsigned int CodeValue; +const char *CodeMeaning; +}; + +// CID 7202 Source Image Purposes of Reference +static const CodeDefinition SourceImagePurposesofReference[] = { +{"DCM",121320,"Uncompressed predecessor"}, +{"DCM",121321,"Mask image for image processing operation"}, +{"DCM",121322,"Source image for image processing operation"}, +{"DCM",121329,"Source image for montage"}, +{"DCM",121330,"Lossy compressed predecessor"}, +{NULL,0,NULL} // sentinel +}; + +// CID 7203 Image Derivation +static const CodeDefinition ImageDerivation[] = { +{ "DCM",113040,"Lossy Compression" }, +{ "DCM",113041,"Apparent Diffusion Coefficient" }, +{ "DCM",113042,"Pixel by pixel addition" }, +{ "DCM",113043,"Diffusion weighted" }, +{ "DCM",113044,"Diffusion Anisotropy" }, +{ "DCM",113045,"Diffusion Attenuated" }, +{ "DCM",113046,"Pixel by pixel division" }, +{ "DCM",113047,"Pixel by pixel mask" }, +{ "DCM",113048,"Pixel by pixel Maximum" }, +{ "DCM",113049,"Pixel by pixel mean" }, +{ "DCM",113050,"Metabolite Maps from spectroscopy data" }, +{ "DCM",113051,"Pixel by pixel Minimum" }, +{ "DCM",113052,"Mean Transit Time" }, +{ "DCM",113053,"Pixel by pixel multiplication" }, +{ "DCM",113054,"Negative Enhancement Integral" }, +{ "DCM",113055,"Regional Cerebral Blood Flow" }, +{ "DCM",113056,"Regional Cerebral Blood Volume" }, +{ "DCM",113057,"R-Coefficient Map" }, +{ "DCM",113058,"Proton Density map" }, +{ "DCM",113059,"Signal Change Map" }, +{ "DCM",113060,"Signal to Noise Map" }, +{ "DCM",113061,"Standard Deviation" }, +{ "DCM",113062,"Pixel by pixel subtraction" }, +{ "DCM",113063,"T1 Map" }, +{ "DCM",113064,"T2* Map" }, +{ "DCM",113065,"T2 Map" }, +{ "DCM",113066,"Time Course of Signal" }, +{ "DCM",113067,"Temperature encoded" }, +{ "DCM",113068,"Student's T-Test" }, +{ "DCM",113069,"Time To Peak map" }, +{ "DCM",113070,"Velocity encoded" }, +{ "DCM",113071,"Z-Score Map" }, +{ "DCM",113072,"Multiplanar reformatting" }, +{ "DCM",113073,"Curved multiplanar reformatting" }, +{ "DCM",113074,"Volume rendering" }, +{ "DCM",113075,"Surface rendering" }, +{ "DCM",113076,"Segmentation" }, +{ "DCM",113077,"Volume editing" }, +{ "DCM",113078,"Maximum intensity projection" }, +{ "DCM",113079,"Minimum intensity projection" }, +{ "DCM",113085,"Spatial resampling" }, +{ "DCM",113086,"Edge enhancement" }, +{ "DCM",113087,"Smoothing" }, +{ "DCM",113088,"Gaussian blur" }, +{ "DCM",113089,"Unsharp mask" }, +{ "DCM",113090,"Image stitching" }, +{NULL,0,NULL} // sentinel +}; + +// CID 7205 Purpose Of Reference to Alternate Representation +static const CodeDefinition PurposeOfReferencetoAlternateRepresentation[] = { +{ "DCM",121324,"Source image" }, +{ "DCM",121325,"Lossy compressed image" }, +{ "DCM",121326,"Alternate SOP Class instance" }, +{ "DCM",121327,"Full fidelity image" }, +{ "DCM",121328,"Alternate Photometric Interpretation image" }, +{NULL,0,NULL} // sentinel +}; + +class FileDerivationInternals +{ +public: + FileDerivationInternals():References(),DerivationCodeSequenceCodeValue(0),PurposeOfReferenceCodeSequenceCodeValue(0),DerivationDescription() {} + std::vector< std::pair< std::string, std::string > > References; + unsigned int DerivationCodeSequenceCodeValue; + unsigned int PurposeOfReferenceCodeSequenceCodeValue; + std::string DerivationDescription; +}; + +FileDerivation::FileDerivation():F(new File),Internals(new FileDerivationInternals) +{ +} + +FileDerivation::~FileDerivation() +{ + delete Internals; +} + +const CodeDefinition * GetCodeDefinition( unsigned int codevalue, const CodeDefinition list[] ) +{ + const CodeDefinition * cds = list; + while( cds->CodeMeaning && cds->CodeValue != codevalue ) + { + ++cds; + } + if( cds->CodeValue ) + return cds; + // else + return NULL; +} + +void FileDerivation::SetDerivationDescription( const char *dd ) +{ + this->Internals->DerivationDescription = dd; +} + +void FileDerivation::SetDerivationCodeSequenceCodeValue(unsigned int codevalue) +{ + this->Internals->DerivationCodeSequenceCodeValue = codevalue; +} + +void FileDerivation::SetPurposeOfReferenceCodeSequenceCodeValue(unsigned int codevalue) +{ + this->Internals->PurposeOfReferenceCodeSequenceCodeValue = codevalue; +} + +bool FileDerivation::AddReference(const char *referencedsopclassuid, const char *referencedsopinstanceuid) +{ + if( !gdcm::UIDGenerator::IsValid(referencedsopclassuid) ) + { + return false; + } + if( !gdcm::UIDGenerator::IsValid(referencedsopinstanceuid) ) + { + return false; + } + // + Internals->References.push_back( std::make_pair( referencedsopclassuid, referencedsopinstanceuid) ); + return true; +} + +/* +PS 3.3 - 2008 C.7.6.1.1.3 Derivation Description +If an Image is identified to be a derived image (see C.7.6.1.1.2 Image Type), Derivation +Description (0008,2111) and Derivation Code Sequence (0008,9215) describe the way in which +the image was derived. They may be used whether or not the Source Image Sequence +(0008,2112) is provided. They may also be used in cases when the Derived Image pixel data is +not significantly changed from one of the source images and the SOP Instance UID of the Derived +Image is the same as the one used for the source image. +*/ +bool FileDerivation::AddDerivationDescription() +{ + File &file = GetFile(); + DataSet &ds = file.GetDataSet(); + + if( !this->Internals->DerivationDescription.empty() ) + { + Attribute<0x0008,0x2111> at1; + at1.SetValue( this->Internals->DerivationDescription.c_str() ); + ds.Replace( at1.GetAsDataElement() ); + } + +// ADD_DERIV: should we append the derivation after any existing one ? +// For compat reason: always override the existing one +//#define ADD_DERIV + const Tag sisq(0x8,0x9215); + SmartPointer sqi; + sqi = new SequenceOfItems; +#ifdef ADD_DERIV + if( ds.FindDataElement( sisq ) ) + sqi = ds.GetDataElement( sisq ).GetValueAsSQ(); +#endif + sqi->SetLengthToUndefined(); + + Item item; + item.SetVLToUndefined(); + + //Item &item1 = sqi->GetItem(1); + DataSet &subds3 = item.GetNestedDataSet(); + + unsigned int codevalue = this->Internals->DerivationCodeSequenceCodeValue; + const CodeDefinition *cd = GetCodeDefinition( codevalue, ImageDerivation ); + if ( !cd ) + { + return false; + } + + std::ostringstream os; + os << cd->CodeValue; + + Attribute<0x0008,0x0100> at1; + at1.SetValue( os.str() ); + subds3.Replace( at1.GetAsDataElement() ); + Attribute<0x0008,0x0102> at2; + at2.SetValue( cd->CodingSchemeDesignator ); + subds3.Replace( at2.GetAsDataElement() ); + Attribute<0x0008,0x0104> at3; + at3.SetValue( cd->CodeMeaning ); + subds3.Replace( at3.GetAsDataElement() ); + + sqi->AddItem( item ); + + DataElement de( sisq ); + de.SetVR( VR::SQ ); + de.SetValue( *sqi ); + de.SetVLToUndefined(); + ds.Replace( de ); + + return true; +} + +/* +PS 3.3 - 2008 C.7.6.1.1.4 Source image sequence +If an Image is identified to be a Derived image (see C.7.6.1.1.2 Image Type), Source Image +Sequence (0008,2112) is an optional list of Referenced SOP Class UID (0008,1150)/ Referenced +SOP Instance UID (0008,1150) pairs that identify the source images used to create the Derived +image. It may be used whether or not there is a description of the way the image was derived in +Derivation Description (0008,2111) or Derivation Code Sequence (0008,9215). +*/ +bool FileDerivation::AddSourceImageSequence() +{ + File &file = GetFile(); + + const Tag sisq(0x8,0x2112); + SmartPointer sqi; + sqi = new SequenceOfItems; + DataElement de( sisq); + de.SetVR( VR::SQ ); + de.SetValue( *sqi ); + de.SetVLToUndefined(); + + DataSet &ds = file.GetDataSet(); + ds.Insert( de ); + + //sqi = (SequenceOfItems*)ds.GetDataElement( sisq ).GetSequenceOfItems(); + sqi = ds.GetDataElement( sisq ).GetValueAsSQ(); + sqi->SetLengthToUndefined(); + + if( sqi->GetNumberOfItems() ) + { + gdcmWarningMacro( "Do not support appending Referenced Image" ); + return false; + } + std::vector< std::pair< std::string, std::string > >::const_iterator it = + Internals->References.begin(); + for( ; it != Internals->References.end(); ++it ) + { + Item item1; + item1.SetVLToUndefined(); + + DataSet &subds = item1.GetNestedDataSet(); + /* + (0008,1150) UI =UltrasoundImageStorage # 28, 1 ReferencedSOPClassUID + (0008,1155) UI [1.2.840.1136190195280574824680000700.3.0.1.19970424140438] # 58, 1 ReferencedSOPInstanceUID + */ + { + gdcm::Attribute<0x8,0x1150> sopinstanceuid; + sopinstanceuid.SetValue( it->first ); + subds.Replace( sopinstanceuid.GetAsDataElement() ); + gdcm::Attribute<0x8,0x1155> sopclassuid; + sopclassuid.SetValue( it->second ); + subds.Replace( sopclassuid.GetAsDataElement() ); + } + if( !AddPurposeOfReferenceCodeSequence(subds) ) + { + return false; + } + sqi->AddItem( item1 ); + } + + + return true; +} + +bool FileDerivation::AddPurposeOfReferenceCodeSequence(DataSet &subds) +{ +/* + (0040,a170) SQ (Sequence with undefined length #=1) # u/l, 1 PurposeOfReferenceCodeSequence + (fffe,e000) na (Item with undefined length #=3) # u/l, 1 Item + (0008,0100) SH [121320] # 6, 1 CodeValue + (0008,0102) SH [DCM] # 4, 1 CodingSchemeDesignator + (0008,0104) LO [Uncompressed predecessor] # 24, 1 CodeMeaning + (fffe,e00d) na (ItemDelimitationItem) # 0, 0 ItemDelimitationItem + (fffe,e0dd) na (SequenceDelimitationItem) # 0, 0 SequenceDelimitationItem +*/ + const Tag prcs(0x0040,0xa170); + if( !subds.FindDataElement( prcs) ) + { + SequenceOfItems *sqi2 = new SequenceOfItems; + DataElement de( prcs ); + de.SetVR( VR::SQ ); + de.SetValue( *sqi2 ); + de.SetVLToUndefined(); + subds.Insert( de ); + } + + //SequenceOfItems *sqi = (SequenceOfItems*)subds.GetDataElement( prcs ).GetSequenceOfItems(); + SmartPointer sqi = subds.GetDataElement( prcs ).GetValueAsSQ(); + sqi->SetLengthToUndefined(); + + if( !sqi->GetNumberOfItems() ) + { + Item item; //( Tag(0xfffe,0xe000) ); + item.SetVLToUndefined(); + sqi->AddItem( item ); + } + Item &item2 = sqi->GetItem(1); + DataSet &subds2 = item2.GetNestedDataSet(); + + /* + (0008,0100) SH [121320] # 6, 1 CodeValue + (0008,0102) SH [DCM] # 4, 1 CodingSchemeDesignator + (0008,0104) LO [Uncompressed predecessor] # 24, 1 CodeMeaning + */ + + unsigned int codevalue = this->Internals->PurposeOfReferenceCodeSequenceCodeValue; + const CodeDefinition *cd = GetCodeDefinition( codevalue, SourceImagePurposesofReference ); + if( !cd ) + { + cd = GetCodeDefinition( codevalue, PurposeOfReferencetoAlternateRepresentation ); + } + if (!cd) + { + return false; + } + + std::ostringstream os; + os << cd->CodeValue; + + Attribute<0x0008,0x0100> at1; + at1.SetValue( os.str() ); + subds2.Replace( at1.GetAsDataElement() ); + Attribute<0x0008,0x0102> at2; + at2.SetValue( cd->CodingSchemeDesignator ); + subds2.Replace( at2.GetAsDataElement() ); + Attribute<0x0008,0x0104> at3; + at3.SetValue( cd->CodeMeaning ); + subds2.Replace( at3.GetAsDataElement() ); + + return true; +} + + +bool FileDerivation::Derive() +{ + File &file = GetFile(); + + DataSet &ds = file.GetDataSet(); + { + // (0008,0008) CS [ORIGINAL\SECONDARY] # 18, 2 ImageType + gdcm::Attribute<0x0008,0x0008> at3; + static const gdcm::CSComp values[] = {"DERIVED","SECONDARY"}; + at3.SetValues( values, 2, true ); // true => copy data ! + if( ds.FindDataElement( at3.GetTag() ) ) + { + const gdcm::DataElement &de = ds.GetDataElement( at3.GetTag() ); + if( !de.IsEmpty() ) + at3.SetFromDataElement( de ); + // Make sure that value #1 is at least 'DERIVED', so override in all cases: + at3.SetValue( 0, values[0] ); + } + ds.Replace( at3.GetAsDataElement() ); + } +// { +// Attribute<0x0008,0x2111> at1; +// at1.SetValue( "lossy conversion" ); +// ds.Replace( at1.GetAsDataElement() ); +// } + + bool b = AddSourceImageSequence(); + if( !b ) + { + gdcmDebugMacro( "Could not AddSourceImageSequence" ); + return false; + } + + b = AddDerivationDescription(); + if( !b ) + { + gdcmDebugMacro( "Could not AddDerivationDescription" ); + return false; + } + + return true; +} + + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmFileDerivation.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmFileDerivation.h new file mode 100644 index 0000000..1592d7b --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmFileDerivation.h @@ -0,0 +1,93 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMFILEDERIVATION_H +#define GDCMFILEDERIVATION_H + +#include "gdcmFile.h" + +namespace gdcm +{ + +class FileDerivationInternals; +class DataSet; +/** + * \brief FileDerivation class + * See PS 3.16 - 2008 For the list of Code Value that can be used for in + * Derivation Code Sequence + * + * URL: http://medical.nema.org/medical/dicom/2008/08_16pu.pdf + * + * DICOM Part 16 has two Context Groups CID 7202 and CID 7203 which contain a + * set of codes defining reason for a source image reference (ie. reason code + * for referenced image sequence) and a coded description of the deriation + * applied to the new image data from the original. Both these context groups + * are extensible. + * + * File Derivation is compulsary when creating a lossy derived image. + */ +class GDCM_EXPORT FileDerivation +{ +public: + FileDerivation(); + ~FileDerivation(); + + /// Create the proper reference. Need to pass the original SOP Class UID and the original + /// SOP Instance UID, so that those value can be used as Reference. + /// \warning referencedsopclassuid and referencedsopinstanceuid needs to be \0 padded. This + /// is not compatible with how ByteValue->GetPointer works. + bool AddReference(const char *referencedsopclassuid, const char *referencedsopinstanceuid); + + // CID 7202 Source Image Purposes of Reference + // {"DCM",121320,"Uncompressed predecessor"}, + + /// Specify the Purpose Of Reference Code Value. Eg. 121320 + void SetPurposeOfReferenceCodeSequenceCodeValue(unsigned int codevalue); + + // CID 7203 Image Derivation + // { "DCM",113040,"Lossy Compression" }, + + /// Specify the Derivation Code Sequence Code Value. Eg 113040 + void SetDerivationCodeSequenceCodeValue(unsigned int codevalue); + + /// Specify the Derivation Description. Eg "lossy conversion" + void SetDerivationDescription( const char *dd ); + + /// Change + bool Derive(); + + /// Set/Get File + void SetFile(const File& f) { F = f; } + File &GetFile() { return *F; } + const File &GetFile() const { return *F; } + +protected: + bool AddDerivationDescription(); + bool AddSourceImageSequence(); + bool AddPurposeOfReferenceCodeSequence(DataSet &ds); + +private: + SmartPointer F; + FileDerivationInternals *Internals; +}; + +/** + * \example GenFakeImage.cxx + * \example ReformatFile.cs + * This is a C++ example on how to use gdcm::FileDerivation + */ + + +} // end namespace gdcm + +#endif //GDCMFILEDERIVATION_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmFileExplicitFilter.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmFileExplicitFilter.cxx new file mode 100644 index 0000000..bc63e95 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmFileExplicitFilter.cxx @@ -0,0 +1,210 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmFileExplicitFilter.h" +#include "gdcmExplicitDataElement.h" +#include "gdcmSequenceOfFragments.h" +#include "gdcmSequenceOfItems.h" +#include "gdcmFragment.h" +#include "gdcmGlobal.h" +#include "gdcmDict.h" +#include "gdcmDicts.h" +#include "gdcmGroupDict.h" +#include "gdcmVR.h" +#include "gdcmVM.h" +#include "gdcmDataSetHelper.h" + +namespace gdcm +{ + +void FileExplicitFilter::SetRecomputeItemLength(bool b) +{ + RecomputeItemLength = b; +} + +void FileExplicitFilter::SetRecomputeSequenceLength(bool b) +{ + RecomputeSequenceLength = b; +} + +bool FileExplicitFilter::ChangeFMI() +{ +/* + gdcm::FileMetaInformation &fmi = F->GetHeader(); + gdcm::TransferSyntax ts = gdcm::TransferSyntax::ImplicitVRLittleEndian; + { + ts = gdcm::TransferSyntax::ExplicitVRLittleEndian; + } + const char *tsuid = gdcm::TransferSyntax::GetTSString( ts ); + gdcm::DataElement de( gdcm::Tag(0x0002,0x0010) ); + de.SetByteValue( tsuid, strlen(tsuid) ); + de.SetVR( gdcm::Attribute<0x0002, 0x0010>::GetVR() ); + fmi.Replace( de ); + //fmi.Remove( gdcm::Tag(0x0002,0x0012) ); // will be regenerated + //fmi.Remove( gdcm::Tag(0x0002,0x0013) ); // ' ' ' + fmi.SetDataSetTransferSyntax(ts); +*/ + + return true; +} + +bool FileExplicitFilter::ProcessDataSet(DataSet &ds, Dicts const & dicts) +{ + if( RecomputeSequenceLength || RecomputeItemLength ) + { + gdcmWarningMacro( "Not implemented sorry" ); + return false; + } + DataSet::Iterator it = ds.Begin(); + for( ; it != ds.End(); ) + { + DataElement de = *it; + std::string strowner; + const char *owner = 0; + const Tag& t = de.GetTag(); + if( t.IsPrivate() && !ChangePrivateTags + // As a special exception we convert to proper VR : + // - Private Group Length + // - Private Creator + // This makes the output more readable (and this should be relative safe) + && !t.IsGroupLength() && !t.IsPrivateCreator() + ) + { + // nothing to do ! just skip + ++it; + continue; + } + if( t.IsPrivate() && !t.IsPrivateCreator() ) + { + strowner = ds.GetPrivateCreator(t); + owner = strowner.c_str(); + } + const DictEntry &entry = dicts.GetDictEntry(t,owner); + const VR &vr = entry.GetVR(); + + //assert( de.GetVR() == VR::INVALID ); + VR cvr = DataSetHelper::ComputeVR(*F,ds, t); + VR oldvr = de.GetVR(); + //SequenceOfItems *sqi = de.GetSequenceOfItems(); + //SequenceOfItems *sqi = dynamic_cast(&de.GetValue()); + SmartPointer sqi = 0; + if( vr == VR::SQ ) + { + sqi = de.GetValueAsSQ(); + if(!sqi) + { + assert( de.IsEmpty() ); + } + } + if( de.GetByteValue() && !sqi ) + { + // all set + //assert( cvr != VR::SQ /*&& cvr != VR::UN*/ ); + assert( cvr != VR::INVALID ); + if( cvr != VR::UN ) + { + // about to change , make some paranoid test: + //assert( cvr.Compatible( oldvr ) ); // LT != LO but there are somewhat compatible + if( cvr & VR::VRASCII ) + { + //assert( oldvr & VR::VRASCII || oldvr == VR::INVALID || oldvr == VR::UN ); + // gdcm-JPEG-Extended.dcm has a couple of VR::OB private field + // is this a good idea to change them to an ASCII when we know this might not work ? + if( !(oldvr & VR::VRASCII || oldvr == VR::INVALID || oldvr == VR::UN) ) + { + gdcmErrorMacro( "Cannot convert VR for tag: " << t << " " << oldvr << " is incompatible with " << cvr << " as given by ref. dict." ); + return false; + } + } + else if( cvr & VR::VRBINARY ) + { + // PHILIPS_Gyroscan-12-MONO2-Jpeg_Lossless.dcm + if( !( oldvr & VR::VRBINARY || oldvr == VR::INVALID || oldvr == VR::UN ) ) + { + gdcmErrorMacro( "Cannot convert VR for tag: " << t << " " << oldvr << " is incompatible with " << cvr << " as given by ref. dict." ); + return false; + } + } + else + { + assert( 0 ); // programmer error + } + + // let's do one more check we are going to make this attribute explicit VR, there is + // still a special case, when VL is > uint16_max then we must give up: + if( !(cvr & VR::VL32) && de.GetVL() > UINT16_MAX ) + { + cvr = VR::UN; + } + de.SetVR( cvr ); + } + } + else if( sqi ) + { + assert( cvr == VR::SQ || cvr == VR::UN ); + de.SetVR( VR::SQ ); + if( de.GetByteValue() ) + { + de.SetValue( *sqi ); + //de.SetVL( sqi->ComputeLength() ); + } + de.SetVLToUndefined(); + assert( sqi->GetLength().IsUndefined() ); + // recursive + SequenceOfItems::ItemVector::iterator sit = sqi->Items.begin(); + for(; sit != sqi->Items.end(); ++sit) + { + //Item &item = const_cast(*sit); + Item &item = *sit; + item.SetVLToUndefined(); + DataSet &nds = item.GetNestedDataSet(); + //const DataElement &deitem = item; + ProcessDataSet(nds, dicts); + item.SetVL( item.GetLength() ); + } + } + else if( de.GetSequenceOfFragments() ) + { + assert( cvr & VR::OB_OW ); + } + else + { + // Ok length is 0, it can be a 0 length explicit SQ (implicit) or a ByteValue... + // we cannot make any error here, simply change the VR + de.SetVR( cvr ); + } + ++it; + ds.Replace( de ); + } + return true; +} + +bool FileExplicitFilter::Change() +{ + //if( !UseVRUN) + // { + // gdcmErrorMacro( "Not implemented" ); + // return false; + // } + const Global& g = GlobalInstance; + const Dicts &dicts = g.GetDicts(); + + DataSet &ds = F->GetDataSet(); + + bool b = ProcessDataSet(ds, dicts); + + return b; +} + + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmFileExplicitFilter.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmFileExplicitFilter.h new file mode 100644 index 0000000..5ea755b --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmFileExplicitFilter.h @@ -0,0 +1,78 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMFILEEXPLICITFILTER_H +#define GDCMFILEEXPLICITFILTER_H + +#include "gdcmFile.h" + +namespace gdcm +{ +class Dicts; + +/** + * \brief FileExplicitFilter class + * After changing a file from Implicit to Explicit representation (see + * ImageChangeTransferSyntax) one operation is to make sure the VR of each + * DICOM attribute are accurate and do match the one from PS 3.6. Indeed when a + * file is written in Implicit reprensentation, the VR is not stored directly + * in the file. + * + * \warning changing an implicit dataset to an explicit dataset is NOT a + * trivial task of simply changing the VR to the dict one: + * \li One has to make sure SQ is properly set + * \li One has to recompute the explicit length SQ + * \li One has to make sure that VR is valid for the encoding + * \li One has to make sure that VR 16bits can store the original value length + */ +class GDCM_EXPORT FileExplicitFilter +{ +public: + FileExplicitFilter():F(new File),ChangePrivateTags(false),UseVRUN(true),RecomputeItemLength(false),RecomputeSequenceLength(false) {} + ~FileExplicitFilter() {} + + /// Decide whether or not to VR'ify private tags + void SetChangePrivateTags(bool b) { ChangePrivateTags = b;} + + /// When VR=16bits in explicit but Implicit has a 32bits length, use VR=UN + void SetUseVRUN(bool b) { UseVRUN = b; } + + /// By default set Sequence & Item length to Undefined to avoid recomputing length: + void SetRecomputeItemLength(bool b); + void SetRecomputeSequenceLength(bool b); + + /// Set FMI Transfer Syntax + + /// Change + bool Change(); + + /// Set/Get File + void SetFile(const File& f) { F = f; } + File &GetFile() { return *F; } + +protected: + bool ProcessDataSet(DataSet &ds, Dicts const & dicts); + bool ChangeFMI(); + +private: + SmartPointer F; + bool ChangePrivateTags; + bool UseVRUN; + bool RecomputeItemLength; + bool RecomputeSequenceLength; +}; + + +} // end namespace gdcm + +#endif //GDCMFILEEXPLICITFILTER_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmFileStreamer.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmFileStreamer.cxx new file mode 100644 index 0000000..fb212d1 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmFileStreamer.cxx @@ -0,0 +1,919 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmFileStreamer.h" + +#include "gdcmTag.h" +#include "gdcmPrivateTag.h" +#include "gdcmDataElement.h" +#include "gdcmReader.h" +#include "gdcmWriter.h" +#include "gdcmAttribute.h" +#include "gdcmEvent.h" +#include "gdcmProgressEvent.h" + +#define _FILE_OFFSET_BITS 64 + +#include +#include // fstat +#include + +#if defined(_WIN32) && (defined(_MSC_VER) || defined(__MINGW32__)) +#include +typedef int64_t off64_t; +#else +#if defined(__APPLE__) || defined(__FreeBSD__) +# define off64_t off_t +#endif +#include // ftruncate +#endif + +namespace gdcm +{ + +// Implementation detail: +// FILE* have been chosen over std::fstream since it has been reported to lead +// to vastly superior speed. The only issue in doing so, is the manual +// handling of 64bits offset. Create thin wrapper: +// See here for discussion: +// http://stackoverflow.com/questions/17863594/size-of-off-t-at-compilation-time +// Basically enforce use of off64_t over off_t since on windows off_t is pretty +// much guarantee to be 32bits only. +static inline int FSeeko(FILE *stream, off64_t offset, int whence) +{ +#if _WIN32 +#if defined(__MINGW32__) + return fseek(stream, offset, whence); // 32bits +#else + return _fseeki64(stream, offset, whence); +#endif +#else + return fseeko(stream, offset, whence); +#endif +} + +static inline off64_t FTello(FILE *stream) +{ +#if _WIN32 +#if defined(__MINGW32__) + return ftell( stream ); // 32bits +#else + return _ftelli64( stream ); +#endif +#else + return ftello( stream ); +#endif +} + +static inline bool FTruncate( const int fd, const off64_t len ) +{ +#if _WIN32 +#if defined(__MINGW32__) + const long size = len; + const int ret = _chsize( fd, size ); // 32bits + return ret == 0 ? true : false; +#else + const __int64 size = len; + const errno_t err = _chsize_s( fd, size ); + return err == 0 ? true : false; +#endif +#else + const int ret = ftruncate(fd, len); + return ret == 0 ? true : false; +#endif +} + +static bool prepare_file( FILE * pFile, const off64_t offset, const off64_t inslen ) +{ + // fast path + if( inslen == 0 ) return true; + + const size_t BUFFERSIZE = 4096; + char buffer[BUFFERSIZE]; + struct stat sb; + + int fd = fileno( pFile ); + if (fstat(fd, &sb) == 0) + { + if( inslen < 0 ) + { + off64_t bytes_to_move = sb.st_size - offset; + off64_t read_start_offset = offset; + while (bytes_to_move != 0) + { + const size_t bytes_this_time = std::min((off64_t)BUFFERSIZE, bytes_to_move); + const off64_t rd_off = read_start_offset; + const off64_t wr_off = rd_off + inslen; + if( FSeeko(pFile, rd_off, SEEK_SET) ) + { + return false; + } + if (fread(buffer, 1, bytes_this_time, pFile) != bytes_this_time) + { + return false; + } + assert( wr_off < rd_off ); + if( FSeeko(pFile, wr_off, SEEK_SET) ) + { + return false; + } + if (fwrite(buffer, 1, bytes_this_time, pFile) != bytes_this_time) + { + return false; + } + bytes_to_move -= bytes_this_time; + read_start_offset += bytes_this_time; + } + assert( read_start_offset == sb.st_size ); + if( !FTruncate( fd, sb.st_size + inslen ) ) + { + return false; + } + } + else + { +#if 0 + assert(sb.st_size >= offset); +#endif + if (sb.st_size > offset) + { + size_t bytes_to_move = sb.st_size - offset; + off64_t read_end_offset = sb.st_size; + while (bytes_to_move != 0) + { + const size_t bytes_this_time = std::min(BUFFERSIZE, bytes_to_move); + const off64_t rd_off = read_end_offset - bytes_this_time; + assert( (off64_t)rd_off >= offset ); + const off64_t wr_off = rd_off + inslen; + if( FSeeko(pFile, rd_off, SEEK_SET) ) + { + return false; + } + if (fread(buffer, 1, bytes_this_time, pFile) != bytes_this_time) + { + return false; + } + if( FSeeko(pFile, wr_off, SEEK_SET) ) + { + return false; + } + if (fwrite(buffer, 1, bytes_this_time, pFile) != bytes_this_time) + { + return false; + } + bytes_to_move -= bytes_this_time; + read_end_offset = rd_off; + } + assert( read_end_offset == offset ); + } + } + // easy case when sb.st_size == offset ... + } // fstat + return true; +} + +enum Operation +{ + NOOPERATION, + DATAELEMENT, + GROUPDATAELEMENT +}; + +class FileStreamerInternals +{ +public: + FileStreamerInternals():operation(NOOPERATION), + CurrentTag(0x0,0x0), + MaxSizeDE(0), + StartOffset(0), + CheckTemplateFileName(false), + InitializeCopy(false), + CheckPixelDataElement(false), + pFile(NULL), + ReservedDataLength(0), + ReservedGroupDataElement(0), + Self(NULL) + { + PrivateCreator.SetByteValue("",0); + } + bool SetTag( const Tag & t ) { + if( !IsValid() ) return false; + // else + CurrentTag = t; + operation = DATAELEMENT; + return true; + } + bool SetPrivateCreator( const DataElement & de, const size_t maxsizde, const uint8_t startoffset ) { + if( !IsValid() ) return false; + // else + PrivateCreator = de; + operation = GROUPDATAELEMENT; + StartOffset = startoffset; + static const size_t limitmax = std::numeric_limits::max(); + if( maxsizde % 2 == 0 + && maxsizde < limitmax ) + { + MaxSizeDE = maxsizde; + return true; + } + return false; + } + bool Match( Operation op, Tag const & t ) + { + if( operation != op ) return false; + if( CurrentTag != t ) return false; + return true; + } + bool Match( Operation op, DataElement const & de ) + { + if( operation != op ) return false; + if( PrivateCreator != de ) return false; + return true; + } + bool Reset( const Tag & ) + { + CurrentTag = Tag(0x0,0x0); + operation = NOOPERATION; + return true; + } + bool Reset( const DataElement & ) + { + PrivateCreator.SetTag( Tag(0x0,0x0) ); + operation = NOOPERATION; + return true; + } + bool IsValid() + { + if( TemplateFilename.empty() ) return false; + if( OutFilename.empty() ) return false; + if( operation != NOOPERATION ) return false; + if( CurrentTag != Tag(0x0,0x0) ) return false; + if( PrivateCreator.GetTag() != Tag(0x0,0x0) ) return false; + if( PrivateCreator.GetVL() != 0 ) return false; + return true; + } + bool CheckDataElement( const Tag & t ) + { + static const Tag pixeldata(0x7fe0,0x0010); + if( t != pixeldata ) return false; + CheckPixelDataElement = true; + return true; + } + bool StartDataElement( const Tag & t ) + { + Self->InvokeEvent( StartEvent() ); + const char *outfilename = OutFilename.c_str(); + assert( outfilename ); + actualde = 0; + { + std::ifstream is( outfilename, std::ios::binary ); + if( !is.good() ) return false; + + std::set tagset; + tagset.insert( t ); + + Reader reader; + reader.SetStream( is ); + if( !reader.ReadSelectedTags( tagset, false ) ) + { + return false; + } + + const File & f = reader.GetFile(); + const DataSet &ds = f.GetDataSet(); + const TransferSyntax &ts = f.GetHeader().GetDataSetTransferSyntax(); + TS = ts; + + // At least on Visual Studio compiler, I need to call clear(), to get + // proper tellg() value: + if( is.eof() ) is.clear(); + + thepos = is.tellg(); + is.close(); + + if( ds.FindDataElement( t ) ) + { + const gdcm::DataElement & de = ds.GetDataElement( t ); + // Here is the actual trick: + if( !de.IsEmpty() ) + { + // if you trigger this assertion, this means we have been allocating + // memory for an element when not needed. + assert( (de.GetByteValue() && de.GetByteValue()->GetPointer() == 0) || de.GetSequenceOfFragments() ); + } + actualde = de.GetVL() + 2 * de.GetVR().GetLength() + 4; + thepos -= actualde; + } + else + { + // no attribute found, easy case ! + } + } + pFile = fopen(outfilename, "r+b"); + assert( pFile ); + CurrentDataLenth = 0; + return true; + } + bool AppendToDataElement( const Tag & t, const char *data, size_t len ) + { + // copy trailing stuff + if( CurrentDataLenth == 0 ) + { + size_t dicomlen = 4 + 4; // Tag + VL for Implicit + if( TS.GetNegociatedType() == TransferSyntax::Explicit ) + dicomlen += 4; + off64_t newlen = len; + assert( (size_t)newlen == len ); + newlen += dicomlen; + newlen -= actualde; + off64_t plength = newlen; + assert( ReservedDataLength >= 0 ); + if( ReservedDataLength ) + { + if( (newlen + ReservedDataLength) >= (off64_t)len ) + { + plength = newlen + ReservedDataLength - len; + } + else + { + plength = newlen + ReservedDataLength - len; + } + ReservedDataLength -= len; + assert( ReservedDataLength >= 0 ); + } + //if( !prepare_file( pFile, (off64_t)thepos + actualde, newlen ) ) + if( !prepare_file( pFile, (off64_t)thepos + actualde, plength ) ) + { + return false; + } + // insert new data in between + FSeeko(pFile, thepos, SEEK_SET); + std::stringstream ss; + const Tag tag = t; + if( TS.GetSwapCode() == SwapCode::BigEndian ) + tag.Write(ss); + else + tag.Write(ss); + if( TS.GetNegociatedType() == TransferSyntax::Explicit ) + { + VR un = VR::UN; + un.Write(ss); + } + const VL vl = 0; // will be updated later (UpdateDataElement) + if( TS.GetSwapCode() == SwapCode::BigEndian ) + vl.Write(ss); + else + vl.Write(ss); + const std::string dicomdata = ss.str(); + fwrite(dicomdata.c_str(), 1, dicomdata.size(), pFile); + assert( dicomdata.size() == dicomlen ); + thepos += dicomlen; + } + else + { + const off64_t curpos = FTello(pFile); + assert( curpos == thepos ); + if( ReservedDataLength >= (off64_t)len ) + { + // simply update remaining reserved buffer: + ReservedDataLength -= len; + } + else + { + const off64_t plength = len - ReservedDataLength; + assert( plength >= 0 ); + if( !prepare_file( pFile, (off64_t)curpos, plength) ) + { + return false; + } + ReservedDataLength = 0; // no more reserved buffer + } + FSeeko(pFile, curpos, SEEK_SET); + } + + assert( ReservedDataLength >= 0 ); + fwrite(data, 1, len, pFile); + thepos += len; + CurrentDataLenth += len; + assert( CurrentDataLenth < std::numeric_limits::max() ); + return true; + } + bool StopDataElement( const Tag & t ) + { + // Update DataElement: + const size_t currentdatalenth = CurrentDataLenth; + assert( ReservedDataLength >= 0); + //const off64_t refpos = FTello(pFile); + if( !UpdateDataElement( t ) ) + { + return false; + } + if( ReservedDataLength > 0) + { + const off64_t curpos = thepos; + if( !prepare_file( pFile, curpos + ReservedDataLength, - ReservedDataLength) ) + { + return false; + } + ReservedDataLength = 0; + } + assert( ReservedDataLength == 0); + fclose(pFile); + pFile = NULL; + // Do some extra work: + if( CheckPixelDataElement ) + { + const char *outfilename = OutFilename.c_str(); + Reader reader; + reader.SetFileName( outfilename ); + std::set tagset; + // (0028,0002) US 3 # 2,1 Samples per Pixel + // (0028,0010) US 256 # 2,1 Rows + // (0028,0011) US 256 # 2,1 Columns + // (0028,0100) US 16 # 2,1 Bits Allocated + // (0028,0008) IS [56] # 2,1 Number of Frames + Attribute<0x28,0x02> spp = { 1 }; + Attribute<0x28,0x10> rows; + Attribute<0x28,0x11> cols; + Attribute<0x28,0x100> ba = { 0 }; + Attribute<0x28,0x08> nframes = { 1 }; + tagset.insert( spp.GetTag() ); + tagset.insert( rows.GetTag() ); + tagset.insert( cols.GetTag() ); + tagset.insert( ba.GetTag() ); + tagset.insert( nframes.GetTag() ); + if( !reader.ReadSelectedTags( tagset, true) ) + { + return false; + } + const File & f = reader.GetFile(); + const DataSet &ds = f.GetDataSet(); + const FileMetaInformation &fmi = f.GetHeader(); + const TransferSyntax &ts = fmi.GetDataSetTransferSyntax(); + if( ts.IsEncapsulated() ) + { + gdcmDebugMacro( "Only RAW (uncompressed) Pixel Data is supported for now" ); + return false; + } + spp.SetFromDataSet( ds ); + rows.SetFromDataSet( ds ); + cols.SetFromDataSet( ds ); + ba.SetFromDataSet( ds ); + nframes.SetFromDataSet( ds ); + assert( ba.GetValue() % 8 == 0 ); + const size_t computedlength = spp.GetValue() * nframes.GetValue() * rows.GetValue() * cols.GetValue() * ( ba.GetValue() / 8 ); + if( computedlength != currentdatalenth ) + { + gdcmDebugMacro( "Invalid size for Pixel Data Element: " << computedlength << " vs " << currentdatalenth ); + return false; + } + } + Self->InvokeEvent( EndEvent() ); + return true; + } + bool ReserveDataElement( size_t len ) + { + ReservedDataLength = len; + return true; + } + bool ReserveGroupDataElement( unsigned short ndataelement ) + { + if( ndataelement <= 256 ) + { + this->ReservedGroupDataElement = ndataelement; + return true; + } + return false; + } + bool StartGroupDataElement( const PrivateTag & ori_pt ) + { + Self->InvokeEvent( StartEvent() ); + // Need to cleanup the whole group, well not really, since as per DICOM + // mechanism we can simply append + const char *outfilename = OutFilename.c_str(); + DataElement private_creator = ori_pt.GetAsDataElement(); + assert( outfilename ); + Tag curtag = ori_pt; + { + bool cont = false; + do + { + Self->InvokeEvent( IterationEvent() ); + std::set tagset; + PrivateTag pt = curtag; + tagset.insert( pt ); + + std::ifstream is( outfilename, std::ios::binary ); + if( !is.good() ) return false; + + Reader reader; + reader.SetStream( is ); + if( !reader.ReadSelectedPrivateTags( tagset, false ) ) + { + return false; + } + + const File & f = reader.GetFile(); + const DataSet &ds = f.GetDataSet(); + cont = ds.FindDataElement( curtag ); + if( cont ) + { + curtag.SetElement( (uint16_t)(curtag.GetElement() + 0x1) ); + } + else + { + const TransferSyntax &ts = f.GetHeader().GetDataSetTransferSyntax(); + TS = ts; + thepos = is.tellg(); + } + is.close(); + } + while( cont ); + // found a free spot: + private_creator.GetTag().SetElement( curtag.GetElement() ); + actualde = 0; + } + + // copy trailing stuff + std::string dicomdata; + { + std::stringstream ss; + assert( private_creator.GetTag().IsPrivateCreator() ); + if( TS.GetSwapCode() == SwapCode::BigEndian ) + { + if( TS.GetNegociatedType() == TransferSyntax::Explicit ) + { + private_creator.Write( ss ); + } + else + { + return 1; + } + } + else + { + if( TS.GetNegociatedType() == TransferSyntax::Explicit ) + { + private_creator.Write( ss ); + } + else + { + private_creator.Write( ss ); + } + } + dicomdata = ss.str(); + } + + // find thepcpos: + std::streampos thepcpos = 0; + { + std::set tagset; + Tag prev = private_creator.GetTag(); + //assert( prev.GetElement() ); + prev.SetElement( (uint16_t)(prev.GetElement() - 0x1) ); + tagset.insert( prev ); + + std::ifstream is( outfilename, std::ios::binary ); + if( !is.good() ) return false; + + Reader reader; + reader.SetStream( is ); + if( !reader.ReadSelectedTags( tagset, false ) ) + { + return false; + } + thepcpos = is.tellg(); + is.close(); + } + + const size_t pclen = dicomdata.size(); + pFile = fopen(outfilename, "r+b"); + + if( !prepare_file( pFile, (off64_t)thepcpos, pclen ) ) + { + return false; + } + + FSeeko(pFile, thepcpos, SEEK_SET); + { + fwrite(dicomdata.c_str(), 1, dicomdata.size(), pFile); +#if 0 + fflush(pFile); // need to flush so that prepareFile works as expected. +#endif + thepos += pclen; + } + + CurrentGroupTag.SetElement( this->StartOffset ); // First possible + CurrentGroupTag.SetPrivateCreator( private_creator.GetTag() ); + CurrentDataLenth = 0; + + if( this->ReservedGroupDataElement ) + { + if( !this->ReserveDataElement( MaxSizeDE ) ) + { + return false; + } + } + return true; + } + bool AppendToGroupDataElement( const DataElement & , const char *data, size_t len ) + { + size_t len_to_move = len; + while( len_to_move != 0 ) + { + Self->InvokeEvent( IterationEvent() ); + const size_t len_this_time = std::min(MaxSizeDE - CurrentDataLenth, len_to_move); + assert( len_this_time % 2 == 0 ); + if( !AppendToDataElement( CurrentGroupTag, data, len_this_time ) ) + { + return false; + } + assert( CurrentDataLenth <= MaxSizeDE ); + len_to_move -= len_this_time; + if( CurrentDataLenth == MaxSizeDE ) + { + // flush + assert( CurrentDataLenth % 2 == 0 ); + if( !UpdateDataElement( CurrentGroupTag ) ) + { + return false; + } + assert( CurrentDataLenth == 0 ); + CurrentGroupTag.SetElement( (uint16_t)(CurrentGroupTag.GetElement() + 1) ); + const int lowbits = CurrentGroupTag.GetElement() & 0x00ff; + if( lowbits == 0 ) + { + // we are wrapping, this is not handled: + gdcmDebugMacro( "Too many data elements. Giving up" ); + return false; + } + } + } + return true; + } + bool StopGroupDataElement( const DataElement & ) + { + return StopDataElement( CurrentGroupTag ); + } + TransferSyntax TS; + std::string TemplateFilename; + std::string OutFilename; +private: + Operation operation; + Tag CurrentTag; + DataElement PrivateCreator; + size_t MaxSizeDE; + uint8_t StartOffset; +public: + bool CheckTemplateFileName; + bool InitializeCopy; + bool CheckPixelDataElement; +private: + // really private ! + FILE* pFile; + std::streampos thepos; + size_t actualde; + size_t CurrentDataLenth; + Tag CurrentGroupTag; + off64_t ReservedDataLength; + unsigned short ReservedGroupDataElement; +public: + FileStreamer *Self; +private: + bool UpdateDataElement( const Tag & t ) + { + // This function will set the VL for current DataElement: + if( CurrentDataLenth ) + { + if( CurrentDataLenth % 2 == 1 ) + { + const off64_t curpos = FTello(pFile); + if( ReservedDataLength >= 1 ) + { + // simply update remaining reserved buffer: + ReservedDataLength -= 1; + } + else + { + if( !prepare_file( pFile, (off64_t)curpos, 1) ) + { + return false; + } + } + FSeeko(pFile, curpos, SEEK_SET); + int ret = fputc(0, pFile); // Set to NULL padding ? + thepos += 1; + assert( ret != EOF ); (void)ret; + CurrentDataLenth += 1; + } + assert( CurrentDataLenth % 2 == 0 ); + off64_t vlpos = thepos; + vlpos -= CurrentDataLenth; + vlpos -= 4; // VL + if( TS.GetNegociatedType() == TransferSyntax::Explicit ) + { + vlpos -= 4; // VR + } + vlpos -= 4; // Tag + gdcmAssertAlwaysMacro( vlpos >= 0 ); + FSeeko(pFile, vlpos, SEEK_SET); + std::stringstream ss; + const Tag tag = t; + if( TS.GetSwapCode() == SwapCode::BigEndian ) + tag.Write(ss); + else + tag.Write(ss); + if( TS.GetNegociatedType() == TransferSyntax::Explicit ) + { + VR un = VR::UN; + un.Write(ss); + } + gdcmAssertAlwaysMacro( CurrentDataLenth < std::numeric_limits::max() ); + const VL vl = (uint32_t)CurrentDataLenth; + if( TS.GetSwapCode() == SwapCode::BigEndian ) + vl.Write(ss); + else + vl.Write(ss); + const std::string dicomdata = ss.str(); + fwrite(dicomdata.c_str(), 1, dicomdata.size(), pFile); + CurrentDataLenth = 0; + } + return true; + } +}; + +FileStreamer::FileStreamer() +{ + Internals = new FileStreamerInternals; +} + +FileStreamer::~FileStreamer() +{ + delete Internals; +} + +void FileStreamer::SetTemplateFileName(const char *filename_native) +{ + if( filename_native ) + Internals->TemplateFilename = filename_native; +} + +bool FileStreamer::InitializeCopy() +{ +#if 0 + static int checksize = 0; + if( !checksize ) + { + const int soff = sizeof( off64_t ); + const int si64 = sizeof( int64_t ); + if( soff != si64 ) return false; + if( !(sizeof(sb.st_size) > 4) ) // LFS ? + { + return false; + } + ++checksize; + } +#endif + + if( !this->Internals->InitializeCopy ) + { + const char *filename = this->Internals->TemplateFilename.c_str(); + const char *outfilename = this->Internals->OutFilename.c_str(); + if( this->Internals->CheckTemplateFileName ) + { + // Prefer a GDCM copy, even if this is slower in most cases, this + // guarantee that the output file will be correct as per-DICOM spec, + // which will greatly simplify the rest of the process. + Reader reader; + reader.SetFileName( filename ); + if( !reader.Read() ) return false; + Writer writer; + writer.SetFileName( outfilename ); + writer.SetFile( reader.GetFile() ); + if( !writer.Write() ) return false; + } + else + { + assert( filename ); + assert( outfilename ); + std::ifstream is( filename, std::ios::binary ); + if( !is.good() ) return false; + std::ofstream of( outfilename, std::ios::binary ); + if( !of.good() ) return false; + of << is.rdbuf(); + of.close(); + is.close(); + } + this->Internals->InitializeCopy = true; + this->Internals->Self = this; + } + return true; +} + +bool FileStreamer::StartDataElement( const Tag & t ) +{ + if( !this->Internals->SetTag( t ) ) + { + gdcmDebugMacro( "Could not StartDataElement" ); + return false; + } + if( !InitializeCopy() ) + { + gdcmDebugMacro( "Could not InitializeCopy" ); + return false; + } + return Internals->StartDataElement( t ); +} + +bool FileStreamer::AppendToDataElement( const Tag & t, const char *data, size_t len ) +{ + if( !this->Internals->Match( DATAELEMENT, t) ) + { + gdcmDebugMacro( "Could not AppendToDataElement" ); + return false; + } + return this->Internals->AppendToDataElement( t, data, len ); +} + +bool FileStreamer::StopDataElement( const Tag & t ) +{ + if( !this->Internals->Reset(t) ) + { + return false; + } + return this->Internals->StopDataElement( t ); +} + +bool FileStreamer::StartGroupDataElement( const PrivateTag & pt, size_t maxsizede, uint8_t startoffset ) +{ + const DataElement private_creator = pt.GetAsDataElement(); + if( !this->Internals->SetPrivateCreator( private_creator, maxsizede, startoffset ) ) + { + gdcmDebugMacro( "Could not StartGroupDataElement" ); + return false; + } + if( !InitializeCopy() ) + { + gdcmDebugMacro( "Could not InitializeCopy" ); + return false; + } + return Internals->StartGroupDataElement( pt ); +} + +bool FileStreamer::AppendToGroupDataElement( const PrivateTag & pt, const char *data, size_t len ) +{ + const DataElement private_creator = pt.GetAsDataElement(); + if( !this->Internals->Match( GROUPDATAELEMENT, private_creator) ) + { + gdcmDebugMacro( "Could not AppendToGroupDataElement" ); + return false; + } + return this->Internals->AppendToGroupDataElement( private_creator, data, len ); +} + +bool FileStreamer::StopGroupDataElement( const PrivateTag & pt ) +{ + const DataElement private_creator = pt.GetAsDataElement(); + if( !this->Internals->Reset( private_creator ) ) + { + return false; + } + return this->Internals->StopGroupDataElement( private_creator ); +} + +bool FileStreamer::ReserveGroupDataElement( unsigned short ndataelement ) +{ + return Internals->ReserveGroupDataElement( ndataelement ); +} +bool FileStreamer::ReserveDataElement( size_t len ) +{ + return Internals->ReserveDataElement( len ); +} + +void FileStreamer::SetOutputFileName(const char *filename_native) +{ + if( filename_native ) + Internals->OutFilename = filename_native; +} + +void FileStreamer::CheckTemplateFileName(bool check) +{ + this->Internals->CheckTemplateFileName = check; +} + +bool FileStreamer::CheckDataElement( const Tag & t ) +{ + return this->Internals->CheckDataElement( t ); +} + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmFileStreamer.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmFileStreamer.h new file mode 100644 index 0000000..0690f28 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmFileStreamer.h @@ -0,0 +1,103 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMFILESTREAMER_H +#define GDCMFILESTREAMER_H + +#include "gdcmSubject.h" +#include "gdcmSmartPointer.h" + +namespace gdcm +{ +class FileStreamerInternals; + +class Tag; +class PrivateTag; +/** + * \brief FileStreamer + * This class let a user create a massive DICOM DataSet from a template DICOM + * file, by appending chunks of data. + * + * This class support two mode of operation: + * 1. Creating a single DataElement by appending chunk after chunk of data. + * + * 2. Creating a set of DataElement within the same group, using a private + * creator for start. New DataElement are added any time the user defined + * maximum size for data element is reached. + * + * \warning any existing DataElement is removed, pick carefully which + * DataElement to add. + */ +class GDCM_EXPORT FileStreamer : public Subject +{ +public: + FileStreamer(); + ~FileStreamer(); + + /// Set input DICOM template filename + void SetTemplateFileName(const char *filename_native); + + // Decide to check template or not (default: false) + /// Instead of simply blindly copying the input DICOM Template file, GDCM will + /// be used to check the input file, and correct any issues recognized within + /// the file. Only use if you do not have control over the input template + /// file. + void CheckTemplateFileName(bool check); + + /// Set output filename (target file) + void SetOutputFileName(const char *filename_native); + + /// Decide to check the Data Element to be written (default: off) + /// The implementation has default strategy for checking validity of DataElement. + /// Currently it only support checking for the following tags: + /// - (7fe0,0010) Pixel Data + bool CheckDataElement( const Tag & t ); + + /// Start Single Data Element Operation + /// This will delete any existing Tag t. Need to call it only once. + bool StartDataElement( const Tag & t ); + /// Append to previously started Tag t + bool AppendToDataElement( const Tag & t, const char *array, size_t len ); + /// Stop appending to tag t. This will compute the proper attribute length. + bool StopDataElement( const Tag & t ); + /// Add a hint on the final size of the dataelement. When optimally chosen, + /// this reduce the number of file in-place copying. Should be called before + /// StartDataElement + bool ReserveDataElement( size_t len ); + + /// Start Private Group (multiple DataElement) Operation. Each newly added + /// DataElement will have a length lower than \param maxsizede . + /// When not specified, maxsizede is set to maximum size allowed by DICOM (= 2^32). + /// startoffset can be used to specify the very first element you want to + /// start with (instead of the first possible). Value should be in [0x0, 0xff] + /// This will find the first available private creator. + bool StartGroupDataElement( const PrivateTag & pt, size_t maxsizede = 0, uint8_t startoffset = 0 ); + /// Append to previously started private creator + bool AppendToGroupDataElement( const PrivateTag & pt, const char *array, size_t len ); + /// Stop appending to private creator + bool StopGroupDataElement( const PrivateTag & pt ); + /// Optimisation: pre-allocate the number of dataelement within the private + /// group (ndataelement <= 256). Should be called before StartGroupDataElement + bool ReserveGroupDataElement( unsigned short ndataelement ); + + /// for wrapped language: instantiate a reference counted object + static SmartPointer New() { return new FileStreamer; } + +private: + bool InitializeCopy(); + FileStreamerInternals *Internals; +}; + +} // end namespace gdcm + +#endif //GDCMFILESTREAMER_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmIPPSorter.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmIPPSorter.cxx new file mode 100644 index 0000000..a4f7393 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmIPPSorter.cxx @@ -0,0 +1,265 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmIPPSorter.h" +#include "gdcmScanner.h" +#include "gdcmElement.h" +#include "gdcmDirectionCosines.h" + +#include +#include + +namespace gdcm +{ + +IPPSorter::IPPSorter() +{ + ComputeZSpacing = true; + DropDuplicatePositions = false; + ZSpacing = 0; + ZTolerance = 1e-6; + DirCosTolerance = 0.; +} + + +inline double spacing_round(double n, int d) /* pow is defined as pow( double, double) or pow(double int) on M$ comp */ +{ + return floor(n * pow(10., d) + .5) / pow(10., d); +} + +bool IPPSorter::Sort(std::vector const & filenames) +{ + // BUG: I cannot clear Filenames since input filenames could also be the output of ourself... + // Filenames.clear(); + ZSpacing = 0; + if( filenames.empty() ) + { + Filenames.clear(); + return true; + } + + Scanner scanner; + const Tag tipp(0x0020,0x0032); // Image Position (Patient) + const Tag tiop(0x0020,0x0037); // Image Orientation (Patient) + const Tag tframe(0x0020,0x0052); // Frame of Reference UID + // Temporal Position Identifier (0020,0100) 3 Temporal order of a dynamic or functional set of Images. + //const Tag tpi(0x0020,0x0100); + scanner.AddTag( tipp ); + scanner.AddTag( tiop ); + scanner.AddTag( tframe ); + bool b = scanner.Scan( filenames ); + if( !b ) + { + gdcmDebugMacro( "Scanner failed" ); + return false; + } + Scanner::ValuesType iops = scanner.GetValues(tiop); + Scanner::ValuesType frames = scanner.GetValues(tframe); + if( DirCosTolerance == 0. ) + { + if( iops.size() != 1 ) + { + gdcmDebugMacro( "More than one IOP (or no IOP): " << iops.size() ); + //std::copy(iops.begin(), iops.end(), std::ostream_iterator(std::cout, "\n")); + return false; + } + } + if( frames.size() > 1 ) // Should I really tolerate no Frame of Reference UID ? + { + gdcmDebugMacro( "More than one Frame Of Reference UID" ); + return false; + } + + const char *reference = filenames[0].c_str(); + // we cannot simply consider the first file, what if this is not DICOM ? + for(std::vector::const_iterator it1 = filenames.begin(); + it1 != filenames.end(); ++it1) + { + const char *filename = it1->c_str(); + bool iskey = scanner.IsKey(filename); + if( iskey ) + { + reference = filename; + } + } + Scanner::TagToValue const &t2v = scanner.GetMapping(reference); + Scanner::TagToValue::const_iterator it = t2v.find( tiop ); + // Take the first file in the list of filenames, if not IOP is found, simply gives up: + if( it == t2v.end() ) + { + // DEAD CODE + gdcmDebugMacro( "No iop in: " << reference ); + return false; + } + if( it->first != tiop ) + { + // first file does not contains Image Orientation (Patient), let's give up + gdcmDebugMacro( "No iop in first file "); + return false; + } + const char *dircos = it->second; + if( !dircos ) + { + // first file does contains Image Orientation (Patient), but it is empty + gdcmDebugMacro( "Empty iop in first file "); + return false; + } + + // http://www.itk.org/pipermail/insight-users/2003-September/004762.html + // Compute normal: + // The steps I take when reconstructing a volume are these: First, + // calculate the slice normal from IOP: + double normal[3]; + + gdcm::DirectionCosines dc; + dc.SetFromString( dircos ); + if( !dc.IsValid() ) return false; + dc.Cross( normal ); + // You only have to do this once for all slices in the volume. Next, for + // each slice, calculate the distance along the slice normal using the IPP + // tag ("dist" is initialized to zero before reading the first slice) : + //typedef std::multimap SortedFilenames; + typedef std::map SortedFilenames; + SortedFilenames sorted; +{ + std::vector::const_iterator it1 = filenames.begin(); + DirectionCosines dc2; + for(; it1 != filenames.end(); ++it1) + { + const char *filename = it1->c_str(); + bool iskey = scanner.IsKey(filename); + if( iskey ) + { + const char *value = scanner.GetValue(filename, tipp); + if( value ) + { + if( DirCosTolerance != 0. ) + { + const char *value2 = scanner.GetValue(filename, tiop); + if( !dc2.SetFromString( value2 ) ) + { + if( value2 ) + gdcmWarningMacro( filename << " cant read IOP: " << value2 ); + return false; + } + double cd = dc2.CrossDot( dc ); + // result should be as close to 1 as possible: + if( fabs(1 - cd) > DirCosTolerance ) + { + gdcmWarningMacro( filename << " Problem with DirCosTolerance: " ); + // Cant print cd since 0.9999 is printed as 1... may confuse user + return false; + } + //dc2.Normalize(); + //dc2.Print( std::cout << std::endl ); + } + //gdcmDebugMacro( filename << " has " << ipp << " = " << value ); + Element ipp; + std::stringstream ss; + ss.str( value ); + ipp.Read( ss ); + double dist = 0; + for (int i = 0; i < 3; ++i) dist += normal[i]*ipp[i]; + // FIXME: This test is weak, since implicitely we are doing a != on floating point value + if( sorted.find(dist) != sorted.end() ) + { + if( this->DropDuplicatePositions ) + { + gdcmWarningMacro( "dropping file " << filename << " since Z position: " << dist << " already found" ); + continue; + } + gdcmWarningMacro( "dist: " << dist << " for " << filename << + " already found in " << sorted.find(dist)->second ); + return false; + } + sorted.insert( + SortedFilenames::value_type(dist,filename) ); + } + else + { + gdcmDebugMacro( "File: " << filename << " has no Tag" << tipp << ". Skipping." ); + } + } + else + { + gdcmDebugMacro( "File: " << filename << " could not be read. Skipping." ); + } + } +} + assert( !sorted.empty() ); +{ + SortedFilenames::const_iterator it2 = sorted.begin(); + double prev = it2->first; + Filenames.push_back( it2->second ); + if( sorted.size() > 1 ) + { + bool spacingisgood = true; + ++it2; + double current = it2->first; + double zspacing = current - prev; + for( ; it2 != sorted.end(); ++it2) + { + //std::cout << it2->first << " " << it2->second << std::endl; + current = it2->first; + Filenames.push_back( it2->second ); + if( fabs((current - prev) - zspacing) > ZTolerance ) + { + gdcmDebugMacro( "ZTolerance test failed. You need to decrease ZTolerance." ); + spacingisgood = false; + } + // update prev for the next for-loop + prev = current; + } + // is spacing good ? + if( spacingisgood && ComputeZSpacing ) + { + // If user ask for a ZTolerance of 1e-4, there is no need for us to + // store the extra digits... this will make sure to return 2.2 from a 2.1999938551239993 value + const int l = (int)( -log10(ZTolerance) ); + ZSpacing = spacing_round(zspacing, l); + } + if( !spacingisgood ) + { + std::ostringstream os; + os << "Filenames and 'z' positions" << std::endl; + double prev1 = 0.; + for(SortedFilenames::const_iterator it1 = sorted.begin(); it1 != sorted.end(); ++it1) + { + std::string f = it1->second; + if( f.length() > 32 ) + { + f = f.substr(0,10) + " ... " + f.substr(f.length()-17); + } + double d = it1->first - prev1; + if( it1 != sorted.begin() && fabs(d - zspacing) > ZTolerance) os << "* "; + else os << " "; + os << it1->first << "\t" << f << std::endl; + prev1 = it1->first; + } + gdcmDebugMacro( os.str() ); + } + assert( spacingisgood == false || (ComputeZSpacing ? (ZSpacing > ZTolerance && ZTolerance > 0) : ZTolerance > 0) ); + } +} + + // return true: means sorting succeed, it does not mean spacing computation succeded ! + return true; +} + +bool IPPSorter::ComputeSpacing(std::vector const & filenames) +{ + (void)filenames; + return false; +} + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmIPPSorter.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmIPPSorter.h new file mode 100644 index 0000000..756a213 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmIPPSorter.h @@ -0,0 +1,109 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMIPPSORTER_H +#define GDCMIPPSORTER_H + +#include "gdcmSorter.h" + +#include +#include + +namespace gdcm +{ +/** + * \brief IPPSorter + * Implement a simple Image Position (Patient) sorter, along the Image + * Orientation (Patient) direction. + * This algorithm does NOT support duplicate and will FAIL in case of duplicate + * IPP. + * \warning See special note for SetZSpacingTolerance when computing the + * ZSpacing from the IPP of each DICOM files (default tolerance for consistent + * spacing is: 1e-6mm) + * + * For more information on Spacing, and how it is defined in DICOM, advanced + * users may refers to: + * + * http://gdcm.sourceforge.net/wiki/index.php/Imager_Pixel_Spacing + * + * \bug There are currently a couple of bugs in this implementation: + * \li Gantry Tilt is not considered + */ +class GDCM_EXPORT IPPSorter : public Sorter +{ +public: + IPPSorter(); + + // FIXME: I do not like public virtual function... + /// Main entry point to the sorter. + /// It will execute the filter, option should be set before + /// running this function (SetZSpacingTolerance, ...) + /// Return value indicate if sorting could be achived. Warning this does *NOT* imply + /// that spacing is consistent, it only means the file are sorted according to IPP + /// You should check if ZSpacing is 0 or not to deduce if file are actually a 3D volume + virtual bool Sort(std::vector const & filenames); + + /// Functions related to Z-Spacing computation + /// Set to true when sort algorithm should also perform a regular + /// Z-Spacing computation using the Image Position (Patient) + /// Potential reason for failure: + /// 1. ALL slices are taken into account, if one slice if + /// missing then ZSpacing will be set to 0 since the spacing + /// will not be found to be regular along the Series + void SetComputeZSpacing(bool b) { ComputeZSpacing = b; } + /// 2. Another reason for failure is that that Z-Spacing is only + /// slightly changing (eg 1e-3) along the serie, a human can determine + /// that this is ok and change the tolerance from its default value: 1e-6 + void SetZSpacingTolerance(double tol) { ZTolerance = tol; } + double GetZSpacingTolerance() const { return ZTolerance; } + + /// Sometimes IOP along a series is slightly changing for example: + /// "0.999081\\0.0426953\\0.00369272\\-0.0419025\\0.955059\\0.293439", + /// "0.999081\\0.0426953\\0.00369275\\-0.0419025\\0.955059\\0.293439", + /// "0.999081\\0.0426952\\0.00369272\\-0.0419025\\0.955059\\0.293439", + /// We need an API to define the tolerance which is allowed. Internally + /// the cross vector of each direction cosines is computed. The tolerance + /// then define the the distance in between 1. to the dot product of those + /// cross vectors. In a perfect world this dot product is of course 1.0 which + /// imply a DirectionCosines tolerance of exactly 0.0 (default). + void SetDirectionCosinesTolerance(double tol) { DirCosTolerance = tol; } + double GetDirectionCosinesTolerance() const { return DirCosTolerance; } + + /// Makes the IPPSorter ignore multiple images located at the same position. + /// Only the first occurence will be kept. + /// DropDuplicatePositions defaults to false. + void SetDropDuplicatePositions(bool b) { DropDuplicatePositions = b; } + + /// Read-only function to provide access to the computed value for the Z-Spacing + /// The ComputeZSpacing must have been set to true before execution of + /// sort algorithm. Call this function *after* calling Sort(); + /// Z-Spacing will be 0 on 2 occasions: + /// \li Sorting simply failed, potentially duplicate IPP => ZSpacing = 0 + /// \li ZSpacing could not be computed (Z-Spacing is not constant, or ZTolerance is too low) + double GetZSpacing() const { return ZSpacing; } + +protected: + bool ComputeZSpacing; + bool DropDuplicatePositions; + double ZSpacing; + double ZTolerance; + double DirCosTolerance; + +private: + bool ComputeSpacing(std::vector const & filenames); +}; + + +} // end namespace gdcm + +#endif //GDCMIPPSORTER_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmIconImage.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmIconImage.cxx new file mode 100644 index 0000000..7623a92 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmIconImage.cxx @@ -0,0 +1,123 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmIconImage.h" + +namespace gdcm +{ +} // end namespace gdcm + +#if 0 +#include "gdcmRAWCodec.h" +#include "gdcmSequenceOfFragments.h" + +namespace gdcm +{ +/* + * PICKER-16-MONO2-Nested_icon.dcm: +(0088,0200) SQ (Sequence with undefined length #=1) # u/l, 1 IconImageSequence + (fffe,e000) na (Item with undefined length #=10) # u/l, 1 Item + (0028,0002) US 1 # 2, 1 SamplesPerPixel + (0028,0004) CS [MONOCHROME2] # 12, 1 PhotometricInterpretation + (0028,0010) US 64 # 2, 1 Rows + (0028,0011) US 64 # 2, 1 Columns + (0028,0034) IS [1\1] # 4, 2 PixelAspectRatio + (0028,0100) US 8 # 2, 1 BitsAllocated + (0028,0101) US 8 # 2, 1 BitsStored + (0028,0102) US 7 # 2, 1 HighBit + (0028,0103) US 0 # 2, 1 PixelRepresentation + (7fe0,0010) OW 0000\0000\0000\0000\0000\0000\0000\0000\0000\0000\0000\0000\0000... # 4096, 1 PixelData + (fffe,e00d) na (ItemDelimitationItem) # 0, 0 ItemDelimitationItem +(fffe,e0dd) na (SequenceDelimitationItem) # 0, 0 SequenceDelimitationItem +*/ + +IconImage::IconImage(): + TS(), + PF(), + PI(), + Dimensions(), + Spacing(), + PixelData() {} + +IconImage::~IconImage() {} + +void IconImage::SetDimension(unsigned int idx, unsigned int dim) +{ + assert( idx < NumberOfDimensions ); + Dimensions.resize( NumberOfDimensions ); + // Can dim be 0 ?? + Dimensions[idx] = dim; +} + +void IconImage::Clear() +{ + Dimensions.clear(); +} + +const PhotometricInterpretation &IconImage::GetPhotometricInterpretation() const +{ + return PI; +} + +void IconImage::SetPhotometricInterpretation( + PhotometricInterpretation const &pi) +{ + PI = pi; +} + +bool IconImage::GetBuffer(char *buffer) const +{ + if( IsEmpty() ) + { + buffer = 0; + return false; + } + + const ByteValue *bv = PixelData.GetByteValue(); + if( !bv ) + { + // KODAK_CompressedIcon.dcm + // contains a compressed Icon Sequence, one has to guess this is lossless jpeg... +#ifdef MDEBUG + const SequenceOfFragments *sqf = PixelData.GetSequenceOfFragments(); + std::ofstream os( "/tmp/kodak.ljpeg", std::ios::binary ); + sqf->WriteBuffer( os ); +#endif + gdcmWarningMacro( "Compressed Icon are not support for now" ); + buffer = 0; + return false; + } + assert( bv ); + RAWCodec codec; + //assert( GetPhotometricInterpretation() == PhotometricInterpretation::MONOCHROME2 ); + //codec.SetPhotometricInterpretation( GetPhotometricInterpretation() ); + if( GetPhotometricInterpretation() != PhotometricInterpretation::MONOCHROME2 ) + { + gdcmWarningMacro( "PhotometricInterpretation: " << GetPhotometricInterpretation() << " not handled for now" ); + } + codec.SetPhotometricInterpretation( PhotometricInterpretation::MONOCHROME2 ); + codec.SetPixelFormat( GetPixelFormat() ); + codec.SetPlanarConfiguration( 0 ); + DataElement out; + bool r = codec.Decode(PixelData, out); + assert( r ); + const ByteValue *outbv = out.GetByteValue(); + assert( outbv ); + //unsigned long check = outbv->GetLength(); // FIXME + memcpy(buffer, outbv->GetPointer(), outbv->GetLength() ); // FIXME + return r; +} + + +} +#endif diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmIconImage.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmIconImage.h new file mode 100644 index 0000000..9cded9f --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmIconImage.h @@ -0,0 +1,94 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMICONIMAGE_H +#define GDCMICONIMAGE_H + +#if 0 +#include "gdcmObject.h" +#include "gdcmDataElement.h" +#include "gdcmPhotometricInterpretation.h" +#include "gdcmPixelFormat.h" +#include "gdcmTransferSyntax.h" + +#include + +namespace gdcm +{ + +/** + * \brief IconImage class + */ +class GDCM_EXPORT IconImage : public Object +{ +public: + IconImage(); + ~IconImage(); + void Print(std::ostream &) const {} + + /// Transfer syntax + void SetTransferSyntax(TransferSyntax const &ts) { + TS = ts; + } + const TransferSyntax &GetTransferSyntax() const { + return TS; + } + void SetDataElement(DataElement const &de) { + PixelData = de; + } + const DataElement& GetDataElement() const { return PixelData; } + + void SetColumns(unsigned int col) { SetDimension(0,col); } + void SetRows(unsigned int rows) { SetDimension(1,rows); } + void SetDimension(unsigned int idx, unsigned int dim); + int GetColumns() const { return Dimensions[0]; } + int GetRows() const { return Dimensions[1]; } + // Get/Set PixelFormat + const PixelFormat &GetPixelFormat() const + { + return PF; + } + void SetPixelFormat(PixelFormat const &pf) + { + PF = pf; + } + + const PhotometricInterpretation &GetPhotometricInterpretation() const; + void SetPhotometricInterpretation(PhotometricInterpretation const &pi); + + bool IsEmpty() const { return Dimensions.size() == 0; } + void Clear(); + + bool GetBuffer(char *buffer) const; + +private: + TransferSyntax TS; + PixelFormat PF; // SamplesPerPixel, BitsAllocated, BitsStored, HighBit, PixelRepresentation + PhotometricInterpretation PI; + std::vector Dimensions; // Col/Row + std::vector Spacing; // PixelAspectRatio ? + DataElement PixelData; // copied from 7fe0,0010 + static const unsigned int NumberOfDimensions = 2; +}; + +} // end namespace gdcm +#endif +#include "gdcmBitmap.h" + +namespace gdcm +{ + //class GDCM_EXPORT IconImage : public Pixmap {}; + typedef Bitmap IconImage; +} + +#endif //GDCMICONIMAGE_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmIconImageFilter.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmIconImageFilter.cxx new file mode 100644 index 0000000..5b3ffc2 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmIconImageFilter.cxx @@ -0,0 +1,562 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmIconImageFilter.h" +#include "gdcmIconImage.h" +#include "gdcmAttribute.h" +#include "gdcmPrivateTag.h" +#include "gdcmJPEGCodec.h" + +namespace gdcm +{ + +class IconImageFilterInternals +{ +public: + std::vector < SmartPointer< IconImage > > icons; +}; + +IconImageFilter::IconImageFilter():F(new File),Internals(new IconImageFilterInternals) +{ +} + +IconImageFilter::~IconImageFilter() +{ + delete Internals; +} + +void IconImageFilter::ExtractIconImages() +{ + const DataSet &rootds = F->GetDataSet(); + const FileMetaInformation &header = F->GetHeader(); + const TransferSyntax &ts = header.GetDataSetTransferSyntax(); + + // PICKER-16-MONO2-Nested_icon.dcm + const Tag ticonimage(0x0088,0x0200); + + // Public Icon + if( rootds.FindDataElement( ticonimage ) ) + { + const DataElement &iconimagesq = rootds.GetDataElement( ticonimage ); + SmartPointer sq = iconimagesq.GetValueAsSQ(); + // Is SQ empty ? + if( sq ) + { + gdcmAssertAlwaysMacro( sq->GetNumberOfItems() == 1 ); + + SmartPointer< IconImage > si1 = new IconImage; + IconImage &pixeldata = *si1; + SequenceOfItems::ConstIterator it = sq->Begin(); + const DataSet &ds = it->GetNestedDataSet(); + + { + Attribute<0x0028,0x0011> at = { 0 }; + at.SetFromDataSet( ds ); + pixeldata.SetDimension(0, at.GetValue() ); + } + + { + Attribute<0x0028,0x0010> at = { 0 }; + at.SetFromDataSet( ds ); + pixeldata.SetDimension(1, at.GetValue() ); + } + + PixelFormat pf; + { + Attribute<0x0028,0x0100> at = { 0 }; + at.SetFromDataSet( ds ); + pf.SetBitsAllocated( at.GetValue() ); + } + { + Attribute<0x0028,0x0101> at = { 0 }; + at.SetFromDataSet( ds ); + pf.SetBitsStored( at.GetValue() ); + } + { + Attribute<0x0028,0x0102> at = { 0 }; + at.SetFromDataSet( ds ); + pf.SetHighBit( at.GetValue() ); + } + { + Attribute<0x0028,0x0103> at = { 0 }; + at.SetFromDataSet( ds ); + pf.SetPixelRepresentation( at.GetValue() ); + } + { + Attribute<0x0028,0x0002> at = { 1 }; + at.SetFromDataSet( ds ); + pf.SetSamplesPerPixel( at.GetValue() ); + } + pixeldata.SetPixelFormat( pf ); + // D 0028|0004 [CS] [Photometric Interpretation] [MONOCHROME2 ] + const Tag tphotometricinterpretation(0x0028, 0x0004); + assert( ds.FindDataElement( tphotometricinterpretation ) ); + const ByteValue *photometricinterpretation = + ds.GetDataElement( tphotometricinterpretation ).GetByteValue(); + std::string photometricinterpretation_str( + photometricinterpretation->GetPointer(), + photometricinterpretation->GetLength() ); + PhotometricInterpretation pi( + PhotometricInterpretation::GetPIType( + photometricinterpretation_str.c_str())); + assert( pi != PhotometricInterpretation::UNKNOW); + pixeldata.SetPhotometricInterpretation( pi ); + + // + if ( pi == PhotometricInterpretation::PALETTE_COLOR ) + { + SmartPointer lut = new LookupTable; + const Tag testseglut(0x0028, (0x1221 + 0)); + if( ds.FindDataElement( testseglut ) ) + { + gdcmAssertAlwaysMacro(0 && "Please report this image"); + } + lut->Allocate( pf.GetBitsAllocated() ); + + // for each red, green, blue: + for(int i=0; i<3; ++i) + { + // (0028,1101) US 0\0\16 + // (0028,1102) US 0\0\16 + // (0028,1103) US 0\0\16 + const Tag tdescriptor(0x0028, (uint16_t)(0x1101 + i)); + //const Tag tdescriptor(0x0028, 0x3002); + Element el_us3; + // Now pass the byte array to a DICOMizer: + el_us3.SetFromDataElement( ds[tdescriptor] ); //.GetValue() ); + lut->InitializeLUT( LookupTable::LookupTableType(i), + el_us3[0], el_us3[1], el_us3[2] ); + + // (0028,1201) OW + // (0028,1202) OW + // (0028,1203) OW + const Tag tlut(0x0028, (uint16_t)(0x1201 + i)); + //const Tag tlut(0x0028, 0x3006); + + // Segmented LUT + // (0028,1221) OW + // (0028,1222) OW + // (0028,1223) OW + const Tag seglut(0x0028, (uint16_t)(0x1221 + i)); + if( ds.FindDataElement( tlut ) ) + { + const ByteValue *lut_raw = ds.GetDataElement( tlut ).GetByteValue(); + assert( lut_raw ); + // LookupTableType::RED == 0 + lut->SetLUT( LookupTable::LookupTableType(i), + (unsigned char*)lut_raw->GetPointer(), lut_raw->GetLength() ); + //assert( pf.GetBitsAllocated() == el_us3.GetValue(2) ); + + unsigned long check = + (el_us3.GetValue(0) ? el_us3.GetValue(0) : 65536) + * el_us3.GetValue(2) / 8; + assert( check == lut_raw->GetLength() ); (void)check; + } + else if( ds.FindDataElement( seglut ) ) + { + const ByteValue *lut_raw = ds.GetDataElement( seglut ).GetByteValue(); + assert( lut_raw ); + lut->SetLUT( LookupTable::LookupTableType(i), + (unsigned char*)lut_raw->GetPointer(), lut_raw->GetLength() ); + //assert( pf.GetBitsAllocated() == el_us3.GetValue(2) ); + + //unsigned long check = + // (el_us3.GetValue(0) ? el_us3.GetValue(0) : 65536) + // * el_us3.GetValue(2) / 8; + //assert( check == lut_raw->GetLength() ); (void)check; + } + else + { + gdcmWarningMacro( "Icon Sequence is incomplete. Giving up" ); + pixeldata.Clear(); + return; + } + } + pixeldata.SetLUT(*lut); + } + + const Tag tpixeldata = Tag(0x7fe0, 0x0010); + if( !ds.FindDataElement( tpixeldata ) ) + { + gdcmWarningMacro( "Icon Sequence is incomplete. Giving up" ); + pixeldata.Clear(); + return; + } + const DataElement& de = ds.GetDataElement( tpixeldata ); + pixeldata.SetDataElement( de ); + + // Pass TransferSyntax: + pixeldata.SetTransferSyntax( ts ); + Internals->icons.push_back( pixeldata ); + } + } + + // AMIInvalidPrivateDefinedLengthSQasUN.dcm + // GE_CT_With_Private_compressed-icon.dcm + // MR_GE_with_Private_Compressed_Icon_0009_1110.dcm + // FIXME: + // Not all tags from the private sequence can be handled + // For instance an icon has a window center/width ... + const PrivateTag tgeiconimage(0x0009,0x0010,"GEIIS"); + + // Private Icon + if( rootds.FindDataElement( tgeiconimage ) ) + { + const DataElement &iconimagesq = rootds.GetDataElement( tgeiconimage ); + //const SequenceOfItems* sq = iconimagesq.GetSequenceOfItems(); + SmartPointer sq = iconimagesq.GetValueAsSQ(); + // Is SQ empty ? + assert( sq ); + if( !sq ) return; + SmartPointer< IconImage > si1 = new IconImage; + IconImage &pixeldata = *si1; + + SequenceOfItems::ConstIterator it = sq->Begin(); + const DataSet &ds = it->GetNestedDataSet(); + + // D 0028|0011 [US] [Columns] [512] + { + //const DataElement& de = ds.GetDataElement( Tag(0x0028, 0x0011) ); + Attribute<0x0028,0x0011> at = { 0 }; + at.SetFromDataSet( ds ); + pixeldata.SetDimension(0, at.GetValue() ); + } + + // D 0028|0010 [US] [Rows] [512] + { + //const DataElement& de = ds.GetDataElement( Tag(0x0028, 0x0010) ); + Attribute<0x0028,0x0010> at = { 0 }; + at.SetFromDataSet( ds ); + pixeldata.SetDimension(1, at.GetValue() ); + } + + PixelFormat pf1; + // D 0028|0100 [US] [Bits Allocated] [16] + { + //const DataElement& de = ds.GetDataElement( Tag(0x0028, 0x0100) ); + Attribute<0x0028,0x0100> at = { 0 }; + at.SetFromDataSet( ds ); + pf1.SetBitsAllocated( at.GetValue() ); + } + // D 0028|0101 [US] [Bits Stored] [12] + { + //const DataElement& de = ds.GetDataElement( Tag(0x0028, 0x0101) ); + Attribute<0x0028,0x0101> at = { 0 }; + at.SetFromDataSet( ds ); + pf1.SetBitsStored( at.GetValue() ); + } + // D 0028|0102 [US] [High Bit] [11] + { + //const DataElement& de = ds.GetDataElement( Tag(0x0028, 0x0102) ); + Attribute<0x0028,0x0102> at = { 0 }; + at.SetFromDataSet( ds ); + pf1.SetHighBit( at.GetValue() ); + } + // D 0028|0103 [US] [Pixel Representation] [0] + { + //const DataElement& de = ds.GetDataElement( Tag(0x0028, 0x0103) ); + Attribute<0x0028,0x0103> at = { 0 }; + at.SetFromDataSet( ds ); + pf1.SetPixelRepresentation( at.GetValue() ); + } + // (0028,0002) US 1 # 2, 1 SamplesPerPixel + { + //const DataElement& de = ds.GetDataElement( Tag(0x0028, 0x0002) ); + Attribute<0x0028,0x0002> at = { 1 }; + at.SetFromDataSet( ds ); + pf1.SetSamplesPerPixel( at.GetValue() ); + } + pixeldata.SetPixelFormat( pf1 ); + // D 0028|0004 [CS] [Photometric Interpretation] [MONOCHROME2 ] + const Tag tphotometricinterpretation(0x0028, 0x0004); + assert( ds.FindDataElement( tphotometricinterpretation ) ); + const ByteValue *photometricinterpretation = ds.GetDataElement( tphotometricinterpretation ).GetByteValue(); + std::string photometricinterpretation_str( + photometricinterpretation->GetPointer(), + photometricinterpretation->GetLength() ); + PhotometricInterpretation pi( + PhotometricInterpretation::GetPIType( + photometricinterpretation_str.c_str())); + assert( pi != PhotometricInterpretation::UNKNOW); + pixeldata.SetPhotometricInterpretation( pi ); + const Tag tpixeldata = Tag(0x7fe0, 0x0010); + assert( ds.FindDataElement( tpixeldata ) ); + { + const DataElement& de = ds.GetDataElement( tpixeldata ); +#if 0 + JPEGCodec jpeg; + jpeg.SetPhotometricInterpretation( pixeldata.GetPhotometricInterpretation() ); + jpeg.SetPlanarConfiguration( 0 ); + PixelFormat pf = pixeldata.GetPixelFormat(); + // Apparently bits stored can only be 8 or 12: + if( pf.GetBitsStored() == 16 ) + { + pf.SetBitsStored( 12 ); + } + jpeg.SetPixelFormat( pf ); + DataElement de2; + jpeg.Decode( de, de2); + pixeldata.SetDataElement( de2 ); +#endif +#if 0 + JPEGCodec jpeg; + jpeg.SetPhotometricInterpretation( pixeldata.GetPhotometricInterpretation() ); + jpeg.SetPixelFormat( pixeldata.GetPixelFormat() ); + DataElement de2; + jpeg.Decode( de, de2); + PixelFormat &pf2 = jpeg.GetPixelFormat(); +#endif +#if 1 + std::istringstream is; + const ByteValue *bv = de.GetByteValue(); + assert( bv ); + is.str( std::string( bv->GetPointer(), bv->GetLength() ) ); + gdcm::TransferSyntax jpegts; + JPEGCodec jpeg; + jpeg.SetPixelFormat( pf1 ); // important to initialize + bool b = jpeg.GetHeaderInfo( is, jpegts ); + if( !b ) + { + assert( 0 ); + } + //jpeg.GetPixelFormat().Print (std::cout); + pixeldata.SetPixelFormat( jpeg.GetPixelFormat() ); + // Set appropriate transfer Syntax + pixeldata.SetTransferSyntax( jpegts ); +#endif + pixeldata.SetDataElement( de ); + } + Internals->icons.push_back( pixeldata ); + } + + // AFAIK this icon SQ is undocumented , but I found it in: + // gdcmDataExtra/gdcmBreakers/2929J888_8b_YBR_RLE_PlanConf0_breaker.dcm + // aka 'SmallPreview' + // The SQ contains a DataElement: + // (0002,0010) UI [1.2.840.10008.1.2.1] # 20,1 Transfer Syntax UID + // sigh... + const PrivateTag tgeiconimage2(0x6003,0x0010,"GEMS_Ultrasound_ImageGroup_001"); + + if( rootds.FindDataElement( tgeiconimage2 ) ) + { + const DataElement &iconimagesq = rootds.GetDataElement( tgeiconimage2 ); + //const SequenceOfItems* sq = iconimagesq.GetSequenceOfItems(); + SmartPointer sq = iconimagesq.GetValueAsSQ(); + // Is SQ empty ? + assert( sq ); + if( !sq ) return; + + SmartPointer< IconImage > si1 = new IconImage; + IconImage &pixeldata = *si1; + + SequenceOfItems::ConstIterator it = sq->Begin(); + const DataSet &ds = it->GetNestedDataSet(); + + // D 0028|0011 [US] [Columns] [512] + { + const DataElement& de = ds.GetDataElement( Tag(0x0028, 0x0011) ); + Attribute<0x0028,0x0011> at; + at.SetFromDataElement( de ); + pixeldata.SetDimension(0, at.GetValue() ); + } + + // D 0028|0010 [US] [Rows] [512] + { + const DataElement& de = ds.GetDataElement( Tag(0x0028, 0x0010) ); + Attribute<0x0028,0x0010> at; + at.SetFromDataElement( de ); + pixeldata.SetDimension(1, at.GetValue() ); + } + + PixelFormat pf; + // D 0028|0100 [US] [Bits Allocated] [16] + { + const DataElement& de = ds.GetDataElement( Tag(0x0028, 0x0100) ); + Attribute<0x0028,0x0100> at; + at.SetFromDataElement( de ); + pf.SetBitsAllocated( at.GetValue() ); + } + // D 0028|0101 [US] [Bits Stored] [12] + { + const DataElement& de = ds.GetDataElement( Tag(0x0028, 0x0101) ); + Attribute<0x0028,0x0101> at; + at.SetFromDataElement( de ); + pf.SetBitsStored( at.GetValue() ); + } + // D 0028|0102 [US] [High Bit] [11] + { + const DataElement& de = ds.GetDataElement( Tag(0x0028, 0x0102) ); + Attribute<0x0028,0x0102> at; + at.SetFromDataElement( de ); + pf.SetHighBit( at.GetValue() ); + } + // D 0028|0103 [US] [Pixel Representation] [0] + { + const DataElement& de = ds.GetDataElement( Tag(0x0028, 0x0103) ); + Attribute<0x0028,0x0103> at; + at.SetFromDataElement( de ); + pf.SetPixelRepresentation( at.GetValue() ); + } + // (0028,0002) US 1 # 2, 1 SamplesPerPixel + { + const DataElement& de = ds.GetDataElement( Tag(0x0028, 0x0002) ); + Attribute<0x0028,0x0002> at; + at.SetFromDataElement( de ); + pf.SetSamplesPerPixel( at.GetValue() ); + } + pixeldata.SetPixelFormat( pf ); + // D 0028|0004 [CS] [Photometric Interpretation] [MONOCHROME2 ] + const Tag tphotometricinterpretation(0x0028, 0x0004); + assert( ds.FindDataElement( tphotometricinterpretation ) ); + const ByteValue *photometricinterpretation = ds.GetDataElement( tphotometricinterpretation ).GetByteValue(); + std::string photometricinterpretation_str( + photometricinterpretation->GetPointer(), + photometricinterpretation->GetLength() ); + PhotometricInterpretation pi( + PhotometricInterpretation::GetPIType( + photometricinterpretation_str.c_str())); + assert( pi != PhotometricInterpretation::UNKNOW); + pixeldata.SetPhotometricInterpretation( pi ); + //const Tag tpixeldata = Tag(0x7fe0, 0x0010); + const PrivateTag tpixeldata(0x6003,0x0011,"GEMS_Ultrasound_ImageGroup_001"); + assert( ds.FindDataElement( tpixeldata ) ); + { + const DataElement& de = ds.GetDataElement( tpixeldata ); + pixeldata.SetDataElement( de ); + /* + JPEGCodec jpeg; + jpeg.SetPhotometricInterpretation( pixeldata.GetPhotometricInterpretation() ); + jpeg.SetPlanarConfiguration( 0 ); + PixelFormat pf = pixeldata.GetPixelFormat(); + // Apparently bits stored can only be 8 or 12: + if( pf.GetBitsStored() == 16 ) + { + pf.SetBitsStored( 12 ); + } + jpeg.SetPixelFormat( pf ); + DataElement de2; + jpeg.Decode( de, de2); + pixeldata.SetDataElement( de2 ); + */ + } + { + Attribute<0x002,0x0010> at; + at.SetFromDataSet( ds ); + TransferSyntax tstype = TransferSyntax::GetTSType( at.GetValue() ); + pixeldata.SetTransferSyntax( tstype ); + } + Internals->icons.push_back( pixeldata ); + } +} + +/* +[ICONDATA2] +PrivateCreator = VEPRO VIM 5.0 DATA +Group = 0x0055 +Element = 0x0030 +Data.ID = C|0|3 +Data.Type = C|3|1 +Data.Width = I|4|2 +Data.Height = I|6|2 +*/ +namespace { +struct VeproData +{ + char ID[3]; + char Type; + uint16_t Width; + uint16_t Height; +}; +} + +// documentation was found in : VIM/VIMSYS/dcmviewpriv.dat +void IconImageFilter::ExtractVeproIconImages() +{ + const DataSet &rootds = F->GetDataSet(); + + const gdcm::PrivateTag ticon1(0x55,0x0030,"VEPRO VIF 3.0 DATA"); + const gdcm::PrivateTag ticon2(0x55,0x0030,"VEPRO VIM 5.0 DATA"); + + const gdcm::ByteValue * bv = NULL; + // Prefer VIF over VIM ? + if( rootds.FindDataElement( ticon1 ) ) + { + const DataElement &de = rootds.GetDataElement( ticon1 ); + bv = de.GetByteValue(); + } + else if( rootds.FindDataElement( ticon2 ) ) + { + const DataElement &de = rootds.GetDataElement( ticon2 ); + bv = de.GetByteValue(); + } + + if( bv ) + { + const char *buf = bv->GetPointer(); + size_t len = bv->GetLength(); + VeproData data; + memcpy(&data, buf, sizeof(data)); + + const char *raw = buf + sizeof(data); + + size_t offset = 4; + // All header starts with the letter 'RAW\0', it looks like we need + // to skip them (all 4 of them) + int magic = memcmp( raw, "RAW\0", 4 ); + gdcmAssertAlwaysMacro( magic == 0 ); + + unsigned int dims[3] = {}; + dims[0] = data.Width; + dims[1] = data.Height; + + assert( dims[0] * dims[1] == len - sizeof(data) - offset ); + + DataElement pd; + pd.SetByteValue( raw + offset, (uint32_t)(len - sizeof(data) - offset) ); + + SmartPointer< IconImage > si1 = new IconImage; + IconImage &pixeldata = *si1; + pixeldata.SetDataElement( pd ); + + pixeldata.SetDimension(0, dims[0] ); + pixeldata.SetDimension(1, dims[1] ); + + PixelFormat pf = PixelFormat::UINT8; + pixeldata.SetPixelFormat( pf ); + pixeldata.SetPhotometricInterpretation( PhotometricInterpretation::MONOCHROME2 ); + + Internals->icons.push_back( pixeldata ); + } +} + +bool IconImageFilter::Extract() +{ + Internals->icons.clear(); + ExtractIconImages(); + ExtractVeproIconImages(); + return GetNumberOfIconImages() != 0; +} + +unsigned int IconImageFilter::GetNumberOfIconImages() const +{ + // what is icons are in undefined length sequence ? + return (unsigned int)Internals->icons.size(); +} + +IconImage& IconImageFilter::GetIconImage( unsigned int i ) const +{ + assert( i < Internals->icons.size() ); + return *Internals->icons[i]; +} + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmIconImageFilter.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmIconImageFilter.h new file mode 100644 index 0000000..b0a01f3 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmIconImageFilter.h @@ -0,0 +1,78 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMICONIMAGEFILTER_H +#define GDCMICONIMAGEFILTER_H + +#include "gdcmFile.h" +#include "gdcmIconImage.h" + +namespace gdcm +{ +class IconImageFilterInternals; + +/** + * \brief IconImageFilter + * This filter will extract icons from a gdcm::File + * This filter will loop over all known sequence (public and private) that may + * contains an IconImage and retrieve them. The filter will fails with a value + * of false if no icon can be found + * Since it handle both public and private icon type, one should not assume the + * icon is in uncompress form, some private vendor store private icon in + * JPEG8/JPEG12 + * + * Implementation details: + * This filter supports the following Icons: + * - (0088,0200) Icon Image Sequence + * - (0009,10,GEIIS) GE IIS Thumbnail Sequence + * - (6003,10,GEMS_Ultrasound_ImageGroup_001) GEMS Image Thumbnail Sequence + * - (0055,30,VEPRO VIF 3.0 DATA) Icon Data + * - (0055,30,VEPRO VIM 5.0 DATA) ICONDATA2 + * + * \warning the icon stored in those private attribute do not conform to + * definition of Icon Image Sequence (do not simply copy/paste). For example + * some private icon can be expressed as 12bits pixel, while the DICOM standard + * only allow 8bits icons. + * + * \see ImageReader + */ +class GDCM_EXPORT IconImageFilter +{ +public: + IconImageFilter(); + ~IconImageFilter(); + + /// Set/Get File + void SetFile(const File& f) { F = f; } + File &GetFile() { return *F; } + const File &GetFile() const { return *F; } + + /// Extract all Icon found in File + bool Extract(); + + /// Retrieve extract IconImage (need to call Extract first) + unsigned int GetNumberOfIconImages() const; + IconImage& GetIconImage( unsigned int i ) const; + +protected: + void ExtractIconImages(); + void ExtractVeproIconImages(); + +private: + SmartPointer F; + IconImageFilterInternals *Internals; +}; + +} // end namespace gdcm + +#endif //GDCMICONIMAGEFILTER_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmIconImageGenerator.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmIconImageGenerator.cxx new file mode 100644 index 0000000..fa3754a --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmIconImageGenerator.cxx @@ -0,0 +1,985 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmIconImageGenerator.h" +#include "gdcmIconImage.h" +#include "gdcmAttribute.h" +#include "gdcmPrivateTag.h" +#include "gdcmImage.h" +#include "gdcmJPEGCodec.h" +#include "gdcmRescaler.h" + +#include +#include +#include +#include + +namespace gdcm +{ +class IconImageGeneratorInternals +{ +public: + IconImageGeneratorInternals() + { + dims[0] = dims[1] = 0; + Min = 0; + Max = 0; + UseMinMax = false; + AutoMinMax = false; + ConvertRGBToPaletteColor = true; + UseOutsideValuePixel = false; + OutsideValuePixel = 0; + } + unsigned int dims[2]; + double Min; + double Max; + bool UseMinMax; + bool AutoMinMax; + bool ConvertRGBToPaletteColor; + bool UseOutsideValuePixel; + double OutsideValuePixel; +}; + +IconImageGenerator::IconImageGenerator():P(new Pixmap),I(new IconImage),Internals(new IconImageGeneratorInternals) +{ +} + +IconImageGenerator::~IconImageGenerator() +{ + delete Internals; +} + +// Implementation detail: +// This function was required at some point in time since the implementation +// RGB -> PALETTE is extremely slow +void IconImageGenerator::ConvertRGBToPaletteColor(bool b) +{ + Internals->ConvertRGBToPaletteColor = b; +} + +void IconImageGenerator::SetOutputDimensions(const unsigned int dims[2]) +{ + Internals->dims[0] = dims[0]; + Internals->dims[1] = dims[1]; +} + +namespace quantization +{ +// retrieved from: +// http://en.literateprograms.org/Special:Downloadcode/Median_cut_algorithm_(C_Plus_Plus) + +/* Copyright (c) 2011 the authors listed at the following URL, and/or +the authors of referenced articles or incorporated external code: +http://en.literateprograms.org/Median_cut_algorithm_(C_Plus_Plus)?action=history&offset=20080309133934 + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Retrieved from: http://en.literateprograms.org/Median_cut_algorithm_(C_Plus_Plus)?oldid=12754 +*/ + + const unsigned int NUM_DIMENSIONS = 3; + + struct Point + { + unsigned char x[NUM_DIMENSIONS]; + }; + + class Block + { + Point minCorner, maxCorner; + Point* points; + size_t pointsLength; + public: + Block(Point* points, size_t pointsLength); + Point * getPoints(); + size_t numPoints() const; + size_t longestSideIndex() const; + int longestSideLength() const; + bool operator<(const Block& rhs) const; + void shrink(); + }; + + template + class CoordinatePointComparator + { + public: + bool operator()(Point left, Point right) + { + return left.x[index] < right.x[index]; + } + }; + + //std::list medianCut(Point* image, int numPoints, unsigned int desiredSize); + + Block::Block(Point* pts, size_t ptslen) + { + this->points = pts; + this->pointsLength = ptslen; + for(size_t i=0; i < NUM_DIMENSIONS; i++) + { + minCorner.x[i] = std::numeric_limits::min(); + maxCorner.x[i] = std::numeric_limits::max(); + } + } + + Point * Block::getPoints() + { + return points; + } + + size_t Block::numPoints() const + { + return pointsLength; + } + + size_t Block::longestSideIndex() const + { + int m = maxCorner.x[0] - minCorner.x[0]; + size_t maxIndex = 0; + for(size_t i=1; i < NUM_DIMENSIONS; i++) + { + int diff = maxCorner.x[i] - minCorner.x[i]; + if (diff > m) + { + m = diff; + maxIndex = i; + } + } + return maxIndex; + } + + int Block::longestSideLength() const + { + int i = longestSideIndex(); + return maxCorner.x[i] - minCorner.x[i]; + } + + bool Block::operator<(const Block& rhs) const + { + return this->longestSideLength() < rhs.longestSideLength(); + } + + void Block::shrink() + { + size_t i,j; + for(j=0; j medianCut(DataElement const &PixelData, int numPoints, unsigned int desiredSize, + std::vector & outputimage ) + { + //Point* points = (Point*)malloc(sizeof(Point) * numPoints); + Point* Points = new Point[numPoints]; + const ByteValue *bv = PixelData.GetByteValue(); + const char *inbuffer = bv->GetPointer(); + size_t bvlen = bv->GetLength(); (void)bvlen; + assert( bvlen == (size_t) numPoints * 3 ); // only 8bits RGB please + for(int i = 0; i < numPoints; i++) + { + memcpy(&Points[i], inbuffer + 3 * i, 3); + } + Point* image = Points; + + std::priority_queue blockQueue; + + Block initialBlock(image, numPoints); + initialBlock.shrink(); + + blockQueue.push(initialBlock); + while (blockQueue.size() < desiredSize && blockQueue.top().numPoints() > 1) + { + Block longestBlock = blockQueue.top(); + + blockQueue.pop(); + Point * begin = longestBlock.getPoints(); + Point * median = longestBlock.getPoints() + (longestBlock.numPoints()+1)/2; + Point * end = longestBlock.getPoints() + longestBlock.numPoints(); + switch(longestBlock.longestSideIndex()) + { + case 0: std::nth_element(begin, median, end, CoordinatePointComparator<0>()); break; + case 1: std::nth_element(begin, median, end, CoordinatePointComparator<1>()); break; + case 2: std::nth_element(begin, median, end, CoordinatePointComparator<2>()); break; + } + + Block block1(begin, median-begin), block2(median, end-median); + block1.shrink(); + block2.shrink(); + + blockQueue.push(block1); + blockQueue.push(block2); + } + + std::list result; + //int s = blockQueue.size(); + outputimage.resize( numPoints ); + //const ByteValue *bv = PixelData.GetByteValue(); + //const char *inbuffer = bv->GetPointer(); + + while(!blockQueue.empty()) + { + Block block = blockQueue.top(); + blockQueue.pop(); + Point * points = block.getPoints(); + + int sum[NUM_DIMENSIONS] = {0}; + for(size_t i=0; i < block.numPoints(); i++) + { + for(size_t j=0; j < NUM_DIMENSIONS; j++) + { + sum[j] += points[i].x[j]; + } + } + + Point averagePoint; + for(size_t j=0; j < NUM_DIMENSIONS; j++) + { + averagePoint.x[j] = (unsigned char)(sum[j] / block.numPoints()); + } + + result.push_back(averagePoint); + + //int index = std::distance(s.begin(), it.first); + size_t index = result.size(); + assert( index <= 256 ); + + for(int i = 0; i < numPoints; i++) + { + const char *currentcolor = inbuffer + 3 * i; + for(size_t j = 0; j < block.numPoints(); j++) + { + assert( currentcolor < inbuffer + bvlen ); + assert( currentcolor + 3 <= inbuffer + bvlen ); + if( std::equal( currentcolor, currentcolor + 3, points[j].x ) ) + { + //assert( outputimage[i] == 0 ); + assert( index > 0 ); + outputimage[i] = (unsigned char)(index - 1); + } + } + } + } + + delete[] Points; + return result; + } + +} // end namespace quantization + +// Create LUT with a maximum number of color equal to \param maxcolor +void IconImageGenerator::BuildLUT( Bitmap & bitmap, unsigned int maxcolor ) +{ + assert( Internals->ConvertRGBToPaletteColor ); + using namespace quantization; + const unsigned int *dims = bitmap.GetDimensions(); + unsigned int numPoints = dims[0]*dims[1]; + + std::vector indeximage; + std::list palette = + medianCut(bitmap.GetDataElement(), numPoints, maxcolor, indeximage); + + size_t ncolors = palette.size(); + LookupTable & lut = bitmap.GetLUT(); + lut.Clear(); + lut.Allocate( 8 ); + std::vector< unsigned char > buffer[3]; + for( int i = 0; i < 3; ++i ) + buffer[i].reserve( ncolors ); + + std::list::const_iterator it = palette.begin(); + for( ; it != palette.end(); ++it ) + { + Point const & p = *it; + for( int i = 0; i < 3; ++i ) + buffer[i].push_back( p.x[i] ); + } + + for( int i = 0; i < 3; ++i ) + { + lut.InitializeLUT( LookupTable::LookupTableType(i), (unsigned short)ncolors, 0, 8 ); + lut.SetLUT( LookupTable::LookupTableType(i), &buffer[i][0], (unsigned short)ncolors ); + } + + bitmap.GetDataElement().SetByteValue( (char*)&indeximage[0], (uint32_t)indeximage.size() ); + assert( lut.Initialized() ); +} + +void IconImageGenerator::SetOutsideValuePixel(double v) +{ + if( Internals->AutoMinMax ) + { + Internals->UseOutsideValuePixel = true; + Internals->OutsideValuePixel = v; + } +} + +void IconImageGenerator::AutoPixelMinMax(bool b) +{ + if( b ) + { + Internals->UseMinMax = false; + Internals->AutoMinMax = true; + } +} + +void IconImageGenerator::SetPixelMinMax(double min, double max) +{ + Internals->Min = min; + Internals->Max = max; + Internals->UseMinMax = true; + Internals->AutoMinMax = false; +} + +template +void ComputeMinMax( const TPixelType *p, size_t npixels , double & min, double &max, double discardvalue) +{ + assert( npixels ); + const TPixelType discard = (TPixelType)discardvalue; + assert( (double)discard == discardvalue ); + TPixelType lmin = std::numeric_limits< TPixelType>::max(); + TPixelType lmax = std::numeric_limits< TPixelType>::min(); + for( size_t i = 0; i < npixels; ++i ) + { + if( p[i] < lmin && p[i] != discard ) + { + lmin = p[i]; + } + else if( p[i] > lmax /* && p[i] != discard */ ) + { + lmax = p[i]; + } + } + //assert( lmin != std::numeric_limits< TPixelType>::max() ); + //assert( lmax != std::numeric_limits< TPixelType>::min() ); + + // what if lmin == lmax == 0 for example: + // let's fake a slightly different min/max found: + if( lmin == lmax ) + { + if( lmax == std::numeric_limits::max() ) + { + lmin--; + assert( lmin + 1 > lmin ); + } + else + { + lmax++; + } + } + min = lmin; + max = lmax; +// std::cout << min << " " << max << std::endl; +} + +template +void ComputeMinMax( const TPixelType *p, size_t npixels , double & min, double &max) +{ + assert( npixels ); + TPixelType lmin = std::numeric_limits< TPixelType>::max(); + TPixelType lmax = std::numeric_limits< TPixelType>::min(); + for( size_t i = 0; i < npixels; ++i ) + { + if( p[i] < lmin ) + { + lmin = p[i]; + } + else if( p[i] > lmax ) + { + lmax = p[i]; + } + } + //assert( lmin != std::numeric_limits< TPixelType>::max() ); + //assert( lmax != std::numeric_limits< TPixelType>::min() ); + + // what if lmin == lmax == 0 for example: + // let's fake a slightly different min/max found: + if( lmin == lmax ) + { + if( lmax == std::numeric_limits::max() ) + { + lmin--; + assert( lmin + 1 > lmin ); + } + else + { + lmax++; + } + } + min = lmin; + max = lmax; +// std::cout << min << " " << max << std::endl; +} + +bool IconImageGenerator::Generate() +{ +/* +PS 3.3-2009 +F.7 ICON IMAGE KEY DEFINITION +a. Only monochrome and palette color images shall be used. Samples per Pixel +(0028,0002) shall have a Value of 1, Photometric Interpretation (0028,0004) shall +have a Value of either MONOCHROME 1, MONOCHROME 2 or PALETTE COLOR, +Planar Configuration (0028,0006) shall not be present +Note: True color icon images are not supported. This is due to the fact that the reduced size of the +Icon Image makes the quality of a palette color image (with 256 colors) sufficient in most cases. +This simplifies the handling of Icon Images by File-set Readers and File-set Updaters. +b. If an FSR/FSU supports Icons (i.e. does not ignore them) then it shall support at least +a maximum size of 64 by 64 Icons. An FSC may write Icons of any size. Icons larger +than 64 by 64 may be ignored by FSRs and FSUs unless specialized by Application +Profiles +c. Pixel samples have a Value of either 1 or 8 for Bits Allocated (0028,0100) and Bits +Stored (0028,0101). High Bit (0028,0102) shall have a Value of one less than the +Value used in Bit Stored +d. Pixel Representation (0028,0103) shall used an unsigned integer representation +(Value 0000H) +e. Pixel Aspect Ratio (0028,0034) shall have a Value of 1:1 +f. If a Palette Color lookup Table is used, an 8 Bit Allocated (0028,0100) shall be used +*/ + I->Clear(); + I->SetNumberOfDimensions(2); + I->SetDimension(0, Internals->dims[0] ); + I->SetDimension(1, Internals->dims[1] ); + + PixelFormat oripf = P->GetPixelFormat(); + + if( P->GetPhotometricInterpretation() != PhotometricInterpretation::MONOCHROME1 + && P->GetPhotometricInterpretation() != PhotometricInterpretation::MONOCHROME2 + && P->GetPhotometricInterpretation() != PhotometricInterpretation::PALETTE_COLOR + && P->GetPhotometricInterpretation() != PhotometricInterpretation::RGB + && P->GetPhotometricInterpretation() != PhotometricInterpretation::YBR_FULL + && P->GetPhotometricInterpretation() != PhotometricInterpretation::YBR_FULL_422 + && P->GetPhotometricInterpretation() != PhotometricInterpretation::YBR_RCT + && P->GetPhotometricInterpretation() != PhotometricInterpretation::YBR_ICT ) + { + gdcmErrorMacro( "PhotometricInterpretation is not supported: " + << P->GetPhotometricInterpretation() ); + return false; + } + + if( P->GetPhotometricInterpretation() == PhotometricInterpretation::RGB + || P->GetPhotometricInterpretation() == PhotometricInterpretation::YBR_FULL + || P->GetPhotometricInterpretation() == PhotometricInterpretation::YBR_FULL_422 + || P->GetPhotometricInterpretation() == PhotometricInterpretation::YBR_RCT + || P->GetPhotometricInterpretation() == PhotometricInterpretation::YBR_ICT ) + { + if( Internals->ConvertRGBToPaletteColor ) + { + I->SetPhotometricInterpretation( PhotometricInterpretation::PALETTE_COLOR ); + } + else + { + I->SetPhotometricInterpretation( PhotometricInterpretation::RGB ); + } + } + else + { + I->SetPhotometricInterpretation( P->GetPhotometricInterpretation() ); + assert( I->GetPhotometricInterpretation() == PhotometricInterpretation::MONOCHROME1 + || I->GetPhotometricInterpretation() == PhotometricInterpretation::MONOCHROME2 + || I->GetPhotometricInterpretation() == PhotometricInterpretation::PALETTE_COLOR ); + if( !Internals->ConvertRGBToPaletteColor + && P->GetPhotometricInterpretation() == PhotometricInterpretation::PALETTE_COLOR ) + { + I->SetPhotometricInterpretation( PhotometricInterpretation::RGB ); + } + } + + assert( I->GetPlanarConfiguration() == 0 ); + + // FIXME we should not retrieve the whole image, ideally we only need a + // single 2D frame + std::vector< char > vbuffer; + size_t framelen = P->GetBufferLength(); + if( P->GetNumberOfDimensions() == 3 ) + { + const unsigned int *dims = P->GetDimensions(); + assert( framelen % dims[2] == 0 ); + framelen /= dims[2]; + } + vbuffer.resize( P->GetBufferLength() ); + char *buffer = &vbuffer[0]; + bool boolean = P->GetBuffer(buffer); + if( !boolean ) return false; + + // truncate to the size of a single frame: + vbuffer.resize( framelen ); + + // Important: After call to GetBuffer() in case we have a 12bits stored image + I->SetPixelFormat( P->GetPixelFormat() ); + + DataElement& pixeldata = I->GetDataElement(); + std::vector< char > vbuffer2; + vbuffer2.resize( I->GetBufferLength() ); + + uint8_t ps = I->GetPixelFormat().GetPixelSize(); + + char *iconb = &vbuffer2[0]; + char *imgb = &vbuffer[0]; + + const unsigned int *imgdims = P->GetDimensions(); + const unsigned int stepi = imgdims[0] / Internals->dims[0]; + const unsigned int stepj = imgdims[1] / Internals->dims[1]; + // Let's cherry-pick pixel from the input image. The nice thing about this approach + // is that this also works for palletized image. + // In the future it would be nice to also support averaging a group of pixel, instead + // of always picking the top-left pixel from the block. + for(unsigned int i = 0; i < Internals->dims[1]; ++i ) + for(unsigned int j = 0; j < Internals->dims[0]; ++j ) + { + assert( (i * Internals->dims[0] + j) * ps < I->GetBufferLength() ); + assert( (i * imgdims[0] * stepj + j * stepi) * ps < framelen /*P->GetBufferLength()*/ ); + memcpy(iconb + (i * Internals->dims[0] + j) * ps, + imgb + (i * imgdims[0] * stepj + j * stepi) * ps, ps ); + } + // Apply LUT + if( P->GetPhotometricInterpretation() == PhotometricInterpretation::PALETTE_COLOR ) + { + std::string tempvbuf(&vbuffer2[0], vbuffer2.size()); + std::istringstream is( tempvbuf ); + std::stringstream ss; + P->GetLUT().Decode( is, ss ); + + if( I->GetPixelFormat().GetBitsAllocated() == 16 ) + { + //assert( I->GetPixelFormat().GetPixelRepresentation() == 0 ); + std::string s = ss.str(); + gdcm::Rescaler r; + r.SetPixelFormat( I->GetPixelFormat() ); + //r.SetPixelFormat( PixelFormat::UINT16 ); + + // FIXME: This is not accurate. We should either: + // - Read the value from window/level to get better min,max value + // - iterate over all possible value to find the min,max as we are looping + // over all values anyway + const double min = 0; // oripf.GetMin(); + const double max = 65536 - 1; //oripf.GetMax(); + r.SetSlope( 255. / (max - min + 0) ); // UINT8_MAX + const double step = min * r.GetSlope(); + r.SetIntercept( 0 - step ); + + // paranoid self check: + assert( r.GetIntercept() + r.GetSlope() * min == 0. ); + assert( r.GetIntercept() + r.GetSlope() * max == 255. ); + + r.SetTargetPixelType( PixelFormat::UINT8 ); + r.SetUseTargetPixelType(true); + + std::vector v8; + v8.resize( Internals->dims[0] * Internals->dims[1] * 3 ); + if( !r.Rescale(&v8[0],&s[0],s.size()) ) + { + assert( 0 ); // should not happen in real life + gdcmErrorMacro( "Problem in the rescaler" ); + return false; + } + if( Internals->ConvertRGBToPaletteColor ) + { + LookupTable &lut = I->GetLUT(); + lut.Allocate(); + + // re-encode: + std::stringstream ss2; + ss2.str( std::string( &v8[0], v8.size() ) ); + + std::string s2 = ss2.str(); + // As per standard, we only support 8bits icon + I->SetPixelFormat( PixelFormat::UINT8 ); + pixeldata.SetByteValue( &s2[0], (uint32_t)s2.size() ); + + BuildLUT( *I, 256 ); + } + else + { + I->SetPixelFormat( PixelFormat::UINT8 ); + I->GetPixelFormat().SetSamplesPerPixel( 3 ); + pixeldata.SetByteValue( &v8[0], (uint32_t)v8.size() ); + } + } + else + { + assert( I->GetPixelFormat() == PixelFormat::UINT8 ); + std::string s = ss.str(); + if( Internals->ConvertRGBToPaletteColor ) + { + LookupTable &lut = I->GetLUT(); + lut.Allocate(); + + // As per standard, we only support 8bits icon + I->SetPixelFormat( PixelFormat::UINT8 ); + pixeldata.SetByteValue( &s[0], (uint32_t)s.size() ); + + BuildLUT(*I, 256 ); + } + else + { + I->SetPixelFormat( PixelFormat::UINT8 ); + I->GetPixelFormat().SetSamplesPerPixel( 3 ); + pixeldata.SetByteValue( &s[0], (uint32_t)s.size() ); + } + } + } + else if( P->GetPhotometricInterpretation() == PhotometricInterpretation::RGB + || P->GetPhotometricInterpretation() == PhotometricInterpretation::YBR_FULL + || P->GetPhotometricInterpretation() == PhotometricInterpretation::YBR_FULL_422 + || P->GetPhotometricInterpretation() == PhotometricInterpretation::YBR_ICT + || P->GetPhotometricInterpretation() == PhotometricInterpretation::YBR_RCT ) + { + std::string tempvbuf( &vbuffer2[0], vbuffer2.size() ); + if( P->GetPhotometricInterpretation() == PhotometricInterpretation::YBR_FULL + || P->GetPhotometricInterpretation() == PhotometricInterpretation::YBR_FULL_422 ) + { + assert( I->GetPixelFormat() == PixelFormat::UINT8 ); + if( P->GetPlanarConfiguration() == 0 ) + { + unsigned char *ybr = (unsigned char*)&tempvbuf[0]; + unsigned char *ybr_out = ybr; + unsigned char *ybr_end = ybr + vbuffer2.size(); + int R, G, B; + for( ; ybr != ybr_end; ) + { + unsigned char a = (unsigned char)(*ybr); ++ybr; + unsigned char b = (unsigned char)(*ybr); ++ybr; + unsigned char c = (unsigned char)(*ybr); ++ybr; + + R = 38142 *(a-16) + 52298 *(c -128); + G = 38142 *(a-16) - 26640 *(c -128) - 12845 *(b -128); + B = 38142 *(a-16) + 66093 *(b -128); + + R = (R+16384)>>15; + G = (G+16384)>>15; + B = (B+16384)>>15; + + if (R < 0) R = 0; + if (G < 0) G = 0; + if (B < 0) B = 0; + if (R > 255) R = 255; + if (G > 255) G = 255; + if (B > 255) B = 255; + + *ybr_out = (unsigned char)R; ++ybr_out; + *ybr_out = (unsigned char)G; ++ybr_out; + *ybr_out = (unsigned char)B; ++ybr_out; + } +#if 0 + std::ofstream d( "/tmp/d.rgb", std::ios::binary ); + d.write( &tempvbuf[0], tempvbuf.size() ); + d.close(); +#endif + assert( ybr_out == ybr_end ); + } + else // ( P->GetPlanarConfiguration() == 1 ) + { + std::string tempvbufybr = tempvbuf; + + unsigned char *ybr = (unsigned char*)&tempvbufybr[0]; + unsigned char *ybr_end = ybr + vbuffer2.size(); + assert( vbuffer2.size() % 3 == 0 ); + size_t ybrl = vbuffer2.size() / 3; + unsigned char *ybra = ybr + 0 * ybrl; + unsigned char *ybrb = ybr + 1 * ybrl; + unsigned char *ybrc = ybr + 2 * ybrl; + + unsigned char *ybr_out = (unsigned char*)&tempvbuf[0]; + unsigned char *ybr_out_end = ybr_out + vbuffer2.size(); + int R, G, B; + for( ; ybr_out != ybr_out_end; ) + { + unsigned char a = (unsigned char)(*ybra); ++ybra; + unsigned char b = (unsigned char)(*ybrb); ++ybrb; + unsigned char c = (unsigned char)(*ybrc); ++ybrc; + + R = 38142 *(a-16) + 52298 *(c -128); + G = 38142 *(a-16) - 26640 *(c -128) - 12845 *(b -128); + B = 38142 *(a-16) + 66093 *(b -128); + + R = (R+16384)>>15; + G = (G+16384)>>15; + B = (B+16384)>>15; + + if (R < 0) R = 0; + if (G < 0) G = 0; + if (B < 0) B = 0; + if (R > 255) R = 255; + if (G > 255) G = 255; + if (B > 255) B = 255; + + *ybr_out = (unsigned char)R; ++ybr_out; + *ybr_out = (unsigned char)G; ++ybr_out; + *ybr_out = (unsigned char)B; ++ybr_out; + } + assert( ybra + 2 * ybrl == ybr_end ); (void)ybr_end; + assert( ybrb + 1 * ybrl == ybr_end ); + assert( ybrc + 0 * ybrl == ybr_end ); + } + } + else + { + if( P->GetPlanarConfiguration() == 1 ) + { + assert( I->GetPixelFormat() == PixelFormat::UINT8 ); + std::string tempvbufrgb = tempvbuf; + + unsigned char *rgb = (unsigned char*)&tempvbufrgb[0]; + unsigned char *rgb_end = rgb + vbuffer2.size(); + assert( vbuffer2.size() % 3 == 0 ); + size_t rgbl = vbuffer2.size() / 3; + unsigned char *rgba = rgb + 0 * rgbl; + unsigned char *rgbb = rgb + 1 * rgbl; + unsigned char *rgbc = rgb + 2 * rgbl; + + unsigned char *rgb_out = (unsigned char*)&tempvbuf[0]; + unsigned char *rgb_out_end = rgb_out + vbuffer2.size(); + for( ; rgb_out != rgb_out_end; ) + { + unsigned char a = (unsigned char)(*rgba); ++rgba; + unsigned char b = (unsigned char)(*rgbb); ++rgbb; + unsigned char c = (unsigned char)(*rgbc); ++rgbc; + + *rgb_out = a; ++rgb_out; + *rgb_out = b; ++rgb_out; + *rgb_out = c; ++rgb_out; + } + assert( rgba + 2 * rgbl == rgb_end ); (void)rgb_end; + assert( rgbb + 1 * rgbl == rgb_end ); + assert( rgbc + 0 * rgbl == rgb_end ); + } + } + + std::istringstream is( tempvbuf ); + if( I->GetPixelFormat() == PixelFormat::UINT8 ) + { + std::string s = is.str(); + if( Internals->ConvertRGBToPaletteColor ) + { + // As per standard, we only support 8bits icon + I->SetPixelFormat( PixelFormat::UINT8 ); + pixeldata.SetByteValue( &s[0], (uint32_t)s.size() ); + + BuildLUT(*I, 256 ); + } + else + { + I->SetPixelFormat( PixelFormat::UINT8 ); + I->GetPixelFormat().SetSamplesPerPixel( 3 ); + pixeldata.SetByteValue( &s[0], (uint32_t)s.size() ); + } + } + else + { + assert( I->GetPixelFormat() == PixelFormat::UINT16 ); + assert( I->GetPixelFormat().GetPixelRepresentation() == 0 ); + std::string s = is.str(); + gdcm::Rescaler r; + r.SetPixelFormat( I->GetPixelFormat() ); + //r.SetPixelFormat( PixelFormat::UINT16 ); + + // FIXME: This is not accurate. We should either: + // - Read the value from window/level to get better min,max value + // - iterate over all possible value to find the min,max as we are looping + // over all values anyway + const double min = 0; // oripf.GetMin(); + const double max = 65536 - 1; //oripf.GetMax(); + r.SetSlope( 255. / (max - min + 0) ); // UINT8_MAX + const double step = min * r.GetSlope(); + r.SetIntercept( 0 - step ); + + // paranoid self check: + assert( r.GetIntercept() + r.GetSlope() * min == 0. ); + assert( r.GetIntercept() + r.GetSlope() * max == 255. ); + + r.SetTargetPixelType( PixelFormat::UINT8 ); + r.SetUseTargetPixelType(true); + + std::vector v8; + v8.resize( Internals->dims[0] * Internals->dims[1] * 3 ); + if( !r.Rescale(&v8[0],&s[0],s.size()) ) + { + assert( 0 ); // should not happen in real life + gdcmErrorMacro( "Problem in the rescaler" ); + return false; + } + + if( Internals->ConvertRGBToPaletteColor ) + { + LookupTable &lut = I->GetLUT(); + lut.Allocate(); + + I->SetPixelFormat( PixelFormat::UINT8 ); + pixeldata.SetByteValue( &v8[0], (uint32_t)v8.size() ); + + BuildLUT(*I, 256 ); + } + else + { + I->SetPixelFormat( PixelFormat::UINT8 ); + I->GetPixelFormat().SetSamplesPerPixel( 3 ); + pixeldata.SetByteValue( &v8[0], (uint32_t)v8.size() ); + } + } + } + else + { + // MONOCHROME1 / MONOCHROME2 ... + char *buffer2 = &vbuffer2[0]; + pixeldata.SetByteValue( buffer2, (uint32_t)vbuffer2.size() ); + + gdcm::Rescaler r; + r.SetPixelFormat( I->GetPixelFormat() ); + + // FIXME: This is not accurate. We should either: + // - Read the value from window/level to get better min,max value + // - iterate over all possible value to find the min,max as we are looping + // over all values anyway + double min = (double)oripf.GetMin(); + double max = (double)oripf.GetMax(); + if( Internals->UseMinMax ) + { + min = Internals->Min; + max = Internals->Max; + } + if( Internals->AutoMinMax ) + { + const char *p = &vbuffer2[0]; + size_t len = vbuffer2.size(); + const PixelFormat &pf = I->GetPixelFormat(); + assert( pf.GetSamplesPerPixel() == 1 ); + if( Internals->UseOutsideValuePixel ) + { + const double d = Internals->OutsideValuePixel; + switch ( pf.GetScalarType() ) + { + case PixelFormat::UINT8: + ComputeMinMax( (uint8_t*)p, len / sizeof( uint8_t ), min, max, d); + break; + case PixelFormat::INT8: + ComputeMinMax( (int8_t*)p, len / sizeof( int8_t ), min, max, d); + break; + case PixelFormat::UINT16: + ComputeMinMax( (uint16_t*)p, len / sizeof( uint16_t ), min, max, d); + break; + case PixelFormat::INT16: + ComputeMinMax( (int16_t*)p, len / sizeof( int16_t ), min, max, d); + break; + default: + assert( 0 ); // should not happen + break; + } + // ok we have found the min value, we should now be able to replace all value 'd' with this min now: + switch ( pf.GetScalarType() ) + { + case PixelFormat::UINT8: + std::replace( (uint8_t*)p, (uint8_t*)p + len / sizeof( uint8_t ), (uint8_t)d, (uint8_t)min); + break; + case PixelFormat::INT8: + std::replace( (int8_t*)p, (int8_t*)p + len / sizeof( int8_t ), (int8_t)d, (int8_t)min); + break; + case PixelFormat::UINT16: + std::replace( (uint16_t*)p, (uint16_t*)p + len / sizeof( uint16_t ), (uint16_t)d, (uint16_t)min); + break; + case PixelFormat::INT16: + std::replace( (int16_t*)p, (int16_t*)p + len / sizeof( int16_t ), (int16_t)d, (int16_t)min); + break; + default: + assert( 0 ); // should not happen + break; + } + } + switch ( pf.GetScalarType() ) + { + case PixelFormat::UINT8: + ComputeMinMax( (uint8_t*)p, len / sizeof( uint8_t ), min, max); + break; + case PixelFormat::INT8: + ComputeMinMax( (int8_t*)p, len / sizeof( int8_t ), min, max); + break; + case PixelFormat::UINT16: + ComputeMinMax( (uint16_t*)p, len / sizeof( uint16_t ), min, max); + break; + case PixelFormat::INT16: + ComputeMinMax( (int16_t*)p, len / sizeof( int16_t ), min, max); + break; + default: + assert( 0 ); // should not happen + break; + } + } + r.SetSlope( 255. / (max - min + 0) ); // UINT8_MAX + const double step = min * r.GetSlope(); + r.SetIntercept( 0 - step ); + + // paranoid self check: + assert( (int)(0.5 + r.GetIntercept() + r.GetSlope() * min) == 0 ); + assert( (int)(0.5 + r.GetIntercept() + r.GetSlope() * max) == 255 ); + + r.SetTargetPixelType( PixelFormat::UINT8 ); + r.SetUseTargetPixelType(true); + + std::vector v8; + v8.resize( Internals->dims[0] * Internals->dims[1] ); + if( !r.Rescale(&v8[0],&vbuffer2[0],vbuffer2.size()) ) + { + assert( 0 ); // should not happen in real life + gdcmErrorMacro( "Problem in the rescaler" ); + return false; + } + + // As per standard, we only support 8bits icon + I->SetPixelFormat( PixelFormat::UINT8 ); + pixeldata.SetByteValue( &v8[0], (uint32_t)v8.size() ); + } + + // \postcondition + if( !Internals->ConvertRGBToPaletteColor + && I->GetPhotometricInterpretation() == PhotometricInterpretation::RGB ) + { + assert( I->GetPixelFormat().GetSamplesPerPixel() == 3 ); + } + else + { + assert( I->GetPixelFormat().GetSamplesPerPixel() == 1 ); + } + assert( I->GetPixelFormat().GetBitsAllocated() == 8 ); + assert( I->GetPixelFormat().GetBitsStored() == 8 ); + assert( I->GetPixelFormat().GetHighBit() == 7 ); + assert( I->GetPixelFormat().GetPixelRepresentation() == 0 ); + + return true; +} + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmIconImageGenerator.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmIconImageGenerator.h new file mode 100644 index 0000000..ef13ca2 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmIconImageGenerator.h @@ -0,0 +1,94 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMICONIMAGEGENERATOR_H +#define GDCMICONIMAGEGENERATOR_H + +#include "gdcmPixmap.h" +#include "gdcmIconImage.h" + +namespace gdcm +{ +class IconImageGeneratorInternals; +/** + * \brief IconImageGenerator + * This filter will generate a valid Icon from the Pixel Data element (an + * instance of gdcm::Pixmap). + * To generate a valid Icon, one is only allowed the following Photometric + * Interpretation: + * - MONOCHROME1 + * - MONOCHROME2 + * - PALETTE_COLOR + * + * The Pixel Bits Allocated is restricted to 8bits, therefore 16 bits image + * needs to be rescaled. By default the filter will use the full scalar range + * of 16bits image to rescale to unsigned 8bits. + * This may not be ideal for some situation, in which case the API + * SetPixelMinMax can be used to overwrite the default min,max interval used. + * + * \see ImageReader + */ +class GDCM_EXPORT IconImageGenerator +{ +public: + IconImageGenerator(); + ~IconImageGenerator(); + + /// Set/Get File + void SetPixmap(const Pixmap& p) { P = p; } + Pixmap &GetPixmap() { return *P; } + const Pixmap &GetPixmap() const { return *P; } + + /// Set Target dimension of output Icon + void SetOutputDimensions(const unsigned int dims[2]); + + /// Override default min/max to compute best rescale for 16bits -> 8bits + /// downscale. Typically those value can be read from the SmallestImagePixelValue + /// LargestImagePixelValue DICOM attribute. + void SetPixelMinMax(double min, double max); + + /// Instead of explicitely specifying the min/max value for the rescale + /// operation, let the internal mechanism compute the min/max of icon and + /// rescale to best appropriate. + void AutoPixelMinMax(bool b); + + /// Converting from RGB to PALETTE_COLOR can be a slow operation. However DICOM + /// standard requires that color icon be described as palette. Set this boolean + /// to false only if you understand the consequences. + /// default value is true, false generates invalid Icon Image Sequence + void ConvertRGBToPaletteColor(bool b); + + /// Set a pixel value that should be discarded. This happen typically for CT image, where + /// a pixel has been used to pad outside the image (see Pixel Padding Value). + /// Requires AutoPixelMinMax(true) + void SetOutsideValuePixel(double v); + + /// Generate Icon + bool Generate(); + + /// Retrieve generated Icon + const IconImage& GetIconImage() const { return *I; } + +protected: + +private: + void BuildLUT( Bitmap & bitmap, unsigned int maxcolor ); + + SmartPointer P; + SmartPointer I; + IconImageGeneratorInternals *Internals; +}; + +} // end namespace gdcm + +#endif //GDCMICONIMAGEGENERATOR_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmImage.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmImage.cxx new file mode 100644 index 0000000..17530a8 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmImage.cxx @@ -0,0 +1,189 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmImage.h" +#include "gdcmTrace.h" +#include "gdcmExplicitDataElement.h" +#include "gdcmByteValue.h" +#include "gdcmDataSet.h" +#include "gdcmSequenceOfFragments.h" +#include "gdcmFragment.h" + +#include + +namespace gdcm +{ + +const double *Image::GetSpacing() const +{ + assert( NumberOfDimensions ); + return &Spacing[0]; +} + +double Image::GetSpacing(unsigned int idx) const +{ + assert( NumberOfDimensions ); + //if( idx < Spacing.size() ) + { + return Spacing[idx]; + } + //assert( 0 && "Should not happen" ); + //return 1; // FIXME ??? +} + +void Image::SetSpacing(const double *spacing) +{ + assert( NumberOfDimensions ); + Spacing = std::vector(spacing, + spacing+NumberOfDimensions); +} + +void Image::SetSpacing(unsigned int idx, double spacing) +{ + //assert( spacing > 1.e3 ); + Spacing.resize( 3 /*idx + 1*/ ); + Spacing[idx] = spacing; +} + +const double *Image::GetOrigin() const +{ + assert( NumberOfDimensions ); + if( !Origin.empty() ) + return &Origin[0]; + return 0; +} + +double Image::GetOrigin(unsigned int idx) const +{ + assert( NumberOfDimensions ); + if( idx < Origin.size() ) + { + return Origin[idx]; + } + return 0; // FIXME ??? +} + +void Image::SetOrigin(const float *ori) +{ + assert( NumberOfDimensions ); + Origin.resize( NumberOfDimensions ); + for(unsigned int i = 0; i < NumberOfDimensions; ++i) + { + Origin[i] = ori[i]; + } +} + +void Image::SetOrigin(const double *ori) +{ + assert( NumberOfDimensions ); + Origin = std::vector(ori, + ori+NumberOfDimensions); +} + +void Image::SetOrigin(unsigned int idx, double ori) +{ + Origin.resize( idx + 1 ); + Origin[idx] = ori; +} + +const double *Image::GetDirectionCosines() const +{ + assert( NumberOfDimensions ); + if( !DirectionCosines.empty() ) + return &DirectionCosines[0]; + return 0; +} +double Image::GetDirectionCosines(unsigned int idx) const +{ + assert( NumberOfDimensions ); + if( idx < DirectionCosines.size() ) + { + return DirectionCosines[idx]; + } + return 0; // FIXME !! +} + +void Image::SetDirectionCosines(const float *dircos) +{ + assert( NumberOfDimensions ); + DirectionCosines.resize( 6 ); + for(int i = 0; i < 6; ++i) + { + DirectionCosines[i] = dircos[i]; + } +} + +void Image::SetDirectionCosines(const double *dircos) +{ + assert( NumberOfDimensions ); + DirectionCosines = std::vector(dircos, + dircos+6); +} + +void Image::SetDirectionCosines(unsigned int idx, double dircos) +{ + DirectionCosines.resize( idx + 1 ); + DirectionCosines[idx] = dircos; +} + +void Image::Print(std::ostream &os) const +{ + Pixmap::Print(os); + if( NumberOfDimensions ) + { + { + os << "Origin: ("; + if( !Origin.empty() ) + { + std::vector::const_iterator it = Origin.begin(); + os << *it; + for(++it; it != Origin.end(); ++it) + { + os << "," << *it; + } + } + os << ")\n"; + } + { + os << "Spacing: ("; + std::vector::const_iterator it = Spacing.begin(); + os << *it; + for(++it; it != Spacing.end(); ++it) + { + os << "," << *it; + } + os << ")\n"; + } + { + os << "DirectionCosines: ("; + if( !DirectionCosines.empty() ) + { + std::vector::const_iterator it = DirectionCosines.begin(); + os << *it; + for(++it; it != DirectionCosines.end(); ++it) + { + os << "," << *it; + } + } + os << ")\n"; + } + { + os << "Rescale Intercept/Slope: (" << Intercept << "," << Slope << ")\n"; + } + //std::vector Spacing; + //std::vector Origin; + + } +} + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmImage.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmImage.h new file mode 100644 index 0000000..e01008b --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmImage.h @@ -0,0 +1,113 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMIMAGE_H +#define GDCMIMAGE_H + +#include "gdcmPixmap.h" + +#include + +namespace gdcm +{ + +/** + * \brief Image + * This is the container for an Image in the general sense. + * From this container you should be able to request information like: + * - Origin + * - Dimension + * - PixelFormat + * ... + * But also to retrieve the image as a raw buffer (char *) + * Since we have to deal with both RAW data and JPEG stream (which + * internally encode all the above information) this API might seems + * redundant. One way to solve that would be to subclass gdcm::Image + * with gdcm::JPEGImage which would from the stream extract the header info + * and fill it to please gdcm::Image...well except origin for instance + * + * Basically you can see it as a storage for the Pixel Data element (7fe0,0010). + * + * \warning This class does some heuristics to guess the Spacing but is not + * compatible with DICOM CP-586. In case of doubt use PixmapReader instead + * + * \see ImageReader PixmapReader + */ +class GDCM_EXPORT Image : public Pixmap +{ +public: + Image ():Spacing(),SC(),Intercept(0),Slope(1) { + //DirectionCosines.resize(6); + Origin.resize( 3 /*NumberOfDimensions*/ ); // fill with 0 + DirectionCosines.resize( 6 ); // fill with 0 + DirectionCosines[0] = 1; + DirectionCosines[4] = 1; + Spacing.resize( 3 /*NumberOfDimensions*/, 1 ); // fill with 1 + + } + ~Image() {} + + /// Return a 3-tuples specifying the spacing + /// NOTE: 3rd value can be an aribtrary 1 value when the spacing was not specified (ex. 2D image). + /// WARNING: when the spacing is not specifier, a default value of 1 will be returned + const double *GetSpacing() const; + double GetSpacing(unsigned int idx) const; + void SetSpacing(const double *spacing); + void SetSpacing(unsigned int idx, double spacing); + + /// Return a 3-tuples specifying the origin + /// Will return (0,0,0) if the origin was not specified. + const double *GetOrigin() const; + double GetOrigin(unsigned int idx) const; + void SetOrigin(const float *ori); + void SetOrigin(const double *ori); + void SetOrigin(unsigned int idx, double ori); + + /// Return a 6-tuples specifying the direction cosines + /// A default value of (1,0,0,0,1,0) will be return when the direction cosines was not specified. + const double *GetDirectionCosines() const; + double GetDirectionCosines(unsigned int idx) const; + void SetDirectionCosines(const float *dircos); + void SetDirectionCosines(const double *dircos); + void SetDirectionCosines(unsigned int idx, double dircos); + + /// print + void Print(std::ostream &os) const; + + /// intercept + void SetIntercept(double intercept) { Intercept = intercept; } + double GetIntercept() const { return Intercept; } + + /// slope + void SetSlope(double slope) { Slope = slope; } + double GetSlope() const { return Slope; } + +private: + std::vector Spacing; + std::vector Origin; + std::vector DirectionCosines; + + // I believe the following 3 ivars can be derived from TS ... + SwapCode SC; + double Intercept; + double Slope; +}; + +/** + * \example DecompressImage.cs + * This is a C# example on how to use gdcm::Image + */ + +} // end namespace gdcm + +#endif //GDCMIMAGE_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmImageApplyLookupTable.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmImageApplyLookupTable.cxx new file mode 100644 index 0000000..e9713dc --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmImageApplyLookupTable.cxx @@ -0,0 +1,84 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmImageApplyLookupTable.h" + +#include + +namespace gdcm +{ + +bool ImageApplyLookupTable::Apply() +{ + Output = Input; + const Bitmap &image = *Input; + + PhotometricInterpretation pi = image.GetPhotometricInterpretation(); + if( pi != PhotometricInterpretation::PALETTE_COLOR ) + { + gdcmDebugMacro( "Image is not palettized" ); + return false; + } + const gdcm::LookupTable &lut = image.GetLUT(); + int bitsample = lut.GetBitSample(); + if( !bitsample ) return false; + + const unsigned long len = image.GetBufferLength(); + std::vector v; + v.resize( len ); + char *p = &v[0]; + image.GetBuffer( p ); + std::stringstream is; + if( !is.write( p, len ) ) + { + gdcmErrorMacro( "Could not write to stringstream" ); + return false; + } + + DataElement &de = Output->GetDataElement(); +#if 0 + std::ostringstream os; + lut.Decode(is, os); + const std::string str = os.str(); + VL::Type strSize = (VL::Type)str.size(); + de.SetByteValue( str.c_str(), strSize); +#else + std::vector v2; + v2.resize( len * 3 ); + lut.Decode(&v2[0], v2.size(), &v[0], v.size()); + assert( v2.size() < (size_t)std::numeric_limits::max ); + de.SetByteValue( &v2[0], (uint32_t)v2.size()); +#endif + Output->GetLUT().Clear(); + Output->SetPhotometricInterpretation( PhotometricInterpretation::RGB ); + Output->GetPixelFormat().SetSamplesPerPixel( 3 ); + Output->SetPlanarConfiguration( 0 ); // FIXME OT-PAL-8-face.dcm has a PlanarConfiguration while being PALETTE COLOR... + const gdcm::TransferSyntax &ts = image.GetTransferSyntax(); + //assert( ts == TransferSyntax::RLELossless ); + if( ts.IsExplicit() ) + { + Output->SetTransferSyntax( TransferSyntax::ExplicitVRLittleEndian ); + } + else + { + assert( ts.IsImplicit() ); + Output->SetTransferSyntax( TransferSyntax::ImplicitVRLittleEndian ); + } + + + bool success = true; + return success; +} + + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmImageApplyLookupTable.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmImageApplyLookupTable.h new file mode 100644 index 0000000..f07875d --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmImageApplyLookupTable.h @@ -0,0 +1,44 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMIMAGEAPPLYLOOKUPTABLE_H +#define GDCMIMAGEAPPLYLOOKUPTABLE_H + +#include "gdcmImageToImageFilter.h" + +namespace gdcm +{ + +class DataElement; +/** + * \brief ImageApplyLookupTable class + * It applies the LUT the PixelData (only PALETTE_COLOR images) + * Output will be a PhotometricInterpretation=RGB image + */ +class GDCM_EXPORT ImageApplyLookupTable : public ImageToImageFilter +{ +public: + ImageApplyLookupTable() {} + ~ImageApplyLookupTable() {} + + /// Apply + bool Apply(); + +protected: + +private: +}; + +} // end namespace gdcm + +#endif //GDCMIMAGEAPPLYLOOKUPTABLE_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmImageChangePhotometricInterpretation.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmImageChangePhotometricInterpretation.cxx new file mode 100644 index 0000000..2684c9e --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmImageChangePhotometricInterpretation.cxx @@ -0,0 +1,135 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmImageChangePhotometricInterpretation.h" +#include "gdcmSequenceOfFragments.h" +#include "gdcmSequenceOfItems.h" +#include "gdcmFragment.h" +#include "gdcmRAWCodec.h" + +namespace gdcm +{ + +/* + * http://groups.google.com/group/comp.protocols.dicom/browse_thread/thread/10f91b14e3013a11 + * http://groups.google.com/group/comp.protocols.dicom/browse_thread/thread/1190189387c1702c + * http://groups.google.com/group/comp.protocols.dicom/browse_thread/thread/a9e118fbbf6dcc9f + * http://forum.dcmtk.org/viewtopic.php?p=5441&sid=61ad1304edb31203c4136890ab651405 + +YBR_FULL as Photometric Interpretation is really the right thing to do. The +problem is that the JPEG bitstream as such does not contain any indication of +the color model - it just specifies that there are three samples per pixel. In +theory it is well possible to apply baseline JPEG compression to RGB pixel +data, although this is an unusual approach since YCbCr provides for better +compression ratio at given image quality. A JFIF header would contain that +information, but the JFIF header is neither required nor recommended in the +DICOM JPEG bitstream. In the absence of that information, and with a JPEG +compressed DICOM file where Photometric Interpretation is "RGB", the parser +needs to decide whether the encoder did something unsual but legal and +decompress the JPEG bitstream as RGB, or whether the encoder just failed to +correctly encode the color model of the JPEG bitstream (which in my experience +is in most cases the correct assumption) and ignore Photometric Interpretation +(and thus incorrectly decode unusual but legal images). +*/ +bool ImageChangePhotometricInterpretation::ChangeMonochrome() +{ + // Ok let's give up on this one for now. + // We would need to take care of Pixel Padding Value to actually be able to + // invert the image without this information we potentially will be making + // mistake. just like Largest Image Pixel Value and other would be wrong + const Bitmap &image = *Input; + PhotometricInterpretation pi = image.GetPhotometricInterpretation(); + assert( pi == PhotometricInterpretation::MONOCHROME1 || pi == PhotometricInterpretation::MONOCHROME2 ); + if( pi == PI ) + { + return true; + } + + unsigned long len = image.GetBufferLength(); + char *p = new char[len]; + image.GetBuffer( p ); + std::stringstream is; + is.write( p, len ); + delete[] p; + + //ImageCodec ic; + RAWCodec ic; + std::ostringstream os; + ic.DoInvertMonochrome( is, os ); + + DataElement &de = Output->GetDataElement(); + std::string str = os.str(); + VL::Type strSize = (VL::Type)str.size(); + de.SetByteValue( str.c_str(), strSize); + //Output->GetLUT().Clear(); + Output->SetPhotometricInterpretation( PI ); + //Output->GetPixelFormat().SetSamplesPerPixel( 3 ); + //Output->SetPlanarConfiguration( 0 ); // FIXME OT-PAL-8-face.dcm has a PlanarConfiguration while being PALETTE COLOR... + //const gdcm::TransferSyntax &ts = image.GetTransferSyntax(); + ////assert( ts == TransferSyntax::RLELossless ); + //if( ts.IsExplicit() ) + // { + // Output->SetTransferSyntax( TransferSyntax::ExplicitVRLittleEndian ); + // } + //else + // { + // assert( ts.IsImplicit() ); + // Output->SetTransferSyntax( TransferSyntax::ImplicitVRLittleEndian ); + // } + + + bool success = true; + return success; +} + +bool ImageChangePhotometricInterpretation::Change() +{ + // PS 3.3 - 2008 C.7.6.3.1.2 Photometric Interpretation + Output = Input; + if( PI == PhotometricInterpretation::YBR_FULL ) + { + assert( Input->GetPhotometricInterpretation() == PhotometricInterpretation::RGB ); + /* + In the case where Bits Allocated (0028,0100) has a value of 8 then the following equations convert + between RGB and YCBCR Photometric Interpretation. + Y = + .2990R + .5870G + .1140B + CB = - .1687R - .3313G + .5000B + 128 + CR = + .5000R - .4187G - .0813B + 128 + Note: The above is based on CCIR Recommendation 601-2 dated 1990. + */ + } + else if( PI == PhotometricInterpretation::RGB ) + { + /* octave: + * B = [.2990,.5870,.1140;- .16874, - .33126, .5000; .5000, - .41869, - .08131] + * inv(B) + * 1.0000e+00 -3.6820e-05 1.4020e+00 + * 1.0000e+00 -3.4411e-01 -7.1410e-01 + * 1.0000e+00 1.7720e+00 -1.3458e-04 + */ + + } + else if( PI == PhotometricInterpretation::MONOCHROME1 || PI == PhotometricInterpretation::MONOCHROME2 ) + { + return ChangeMonochrome(); + } + else + { + return false; + } + + return true; +} + + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmImageChangePhotometricInterpretation.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmImageChangePhotometricInterpretation.h new file mode 100644 index 0000000..7aad807 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmImageChangePhotometricInterpretation.h @@ -0,0 +1,117 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMIMAGECHANGEPHOTOMETRICINTERPRETATION_H +#define GDCMIMAGECHANGEPHOTOMETRICINTERPRETATION_H + +#include "gdcmImageToImageFilter.h" +#include "gdcmPhotometricInterpretation.h" + +namespace gdcm +{ + +class DataElement; +/** + * \brief ImageChangePhotometricInterpretation class + * Class to change the Photometric Interpetation of an input DICOM + */ +class GDCM_EXPORT ImageChangePhotometricInterpretation : public ImageToImageFilter +{ +public: + ImageChangePhotometricInterpretation():PI() {} + ~ImageChangePhotometricInterpretation() {} + + /// Set/Get requested PhotometricInterpretation + void SetPhotometricInterpretation(PhotometricInterpretation const &pi) { PI = pi; } + const PhotometricInterpretation &GetPhotometricInterpretation() const { return PI; } + + /// Change + bool Change(); + + /// colorspace converstion (based on CCIR Recommendation 601-2) + template + static void RGB2YBR(T ybr[3], const T rgb[3]); + template + static void YBR2RGB(T rgb[3], const T ybr[3]); + +protected: + bool ChangeMonochrome(); + +private: + PhotometricInterpretation PI; +}; + + +// http://en.wikipedia.org/wiki/YCbCr +template +void ImageChangePhotometricInterpretation::RGB2YBR(T ybr[3], const T rgb[3]) +{ +#if 1 + ybr[0] = 65.738 * rgb[0] + 129.057 * rgb[1] + 25.064 * rgb[2] + 16; + ybr[1] = -37.945 * rgb[0] + -74.494 * rgb[1] + 112.439 * rgb[2] + 128; + ybr[2] = 112.439 * rgb[0] + -94.154 * rgb[1] + -18.285 * rgb[2] + 128; +#else + + const double R = rgb[0]; + const double G = rgb[1]; + const double B = rgb[2]; + const double Y = .2990 * R + .5870 * G + .1140 * B; + const double CB = -.168736 * R - .331264 * G + .5000 * B + 128; + const double CR = .5000 * R - .418688 * G - .081312 * B + 128; + //assert( Y >= 0 && Y <= 255 ); + //assert( CB >= 0 && CB <= 255 ); + //assert( CR >= 0 && CR <= 255 ); + ybr[0] = Y /*+ 0.5*/; + ybr[1] = CB /*+ 0.5*/; + ybr[2] = CR /*+ 0.5*/; +#endif +} + +template +void ImageChangePhotometricInterpretation::YBR2RGB(T rgb[3], const T ybr[3]) +{ + +#if 1 + rgb[0] = 298.082 * ((int)ybr[0]-16) + 0. * ((int)ybr[1]-128) + 408.583 * ((int)ybr[2]-128) - 1. / 256; + rgb[1] = 298.082 * ((int)ybr[0]-16) + -100.291 * ((int)ybr[1]-128) + -208.12 * ((int)ybr[2]-128) - 1. / 256; + rgb[2] = 298.082 * ((int)ybr[0]-16) + 516.411 * ((int)ybr[1]-128) + 0. * ((int)ybr[2]-128) - 1. / 256; + +#else + const double Y = ybr[0]; + const double Cb = ybr[1]; + const double Cr = ybr[2]; + //const double R = 1.0000e+00 * Y - 3.6820e-05 * CB + 1.4020e+00 * CR; + //const double G = 1.0000e+00 * Y - 3.4411e-01 * CB - 7.1410e-01 * CR; + //const double B = 1.0000e+00 * Y + 1.7720e+00 * CB - 1.3458e-04 * CR; + const double r = Y + 1.402 * (Cr-128); + const double g = Y - 0.344136 * (Cb-128) - 0.714136 * (Cr-128); + const double b = Y + 1.772 * (Cb-128); + double R = r < 0 ? 0 : r; + R = R > 255 ? 255 : R; + double G = g < 0 ? 0 : g; + G = G > 255 ? 255 : G; + double B = b < 0 ? 0 : b; + B = B > 255 ? 255 : B; + assert( R >= 0 && R <= 255 ); + assert( G >= 0 && G <= 255 ); + assert( B >= 0 && B <= 255 ); + rgb[0] = ((R < 0 ? 0 : R) > 255 ? 255 : R); + rgb[1] = G; + rgb[2] = B; +#endif + +} + +} // end namespace gdcm + +#endif //GDCMIMAGECHANGEPHOTOMETRICINTERPRETATION_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmImageChangePlanarConfiguration.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmImageChangePlanarConfiguration.cxx new file mode 100644 index 0000000..270200c --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmImageChangePlanarConfiguration.cxx @@ -0,0 +1,114 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmImageChangePlanarConfiguration.h" +#include "gdcmSequenceOfFragments.h" +#include "gdcmSequenceOfItems.h" +#include "gdcmFragment.h" + +namespace gdcm +{ +/* + * C.7.6.3.1.3 Planar Configuration + * Note: Planar Configuration (0028,0006) is not meaningful when a compression transfer syntax is + * used that involves reorganization of sample components in the compressed bit stream. In such + * cases, since the Attribute is required to be sent, then an appropriate value to use may be + * specified in the description of the Transfer Syntax in PS 3.5, though in all likelihood the value of + * the Attribute will be ignored by the receiving implementation. + */ + +bool ImageChangePlanarConfiguration::Change() +{ + if( PlanarConfiguration != 0 && PlanarConfiguration != 1 ) return false; // seriously + Output = Input; + if( Input->GetPixelFormat().GetSamplesPerPixel() != 3 ) + { + return true; + } + assert( Input->GetPhotometricInterpretation() == PhotometricInterpretation::YBR_FULL + || Input->GetPhotometricInterpretation() == PhotometricInterpretation::YBR_FULL_422 + || Input->GetPhotometricInterpretation() == PhotometricInterpretation::YBR_RCT + || Input->GetPhotometricInterpretation() == PhotometricInterpretation::RGB ); + if( Input->GetPlanarConfiguration() == PlanarConfiguration ) + { + return true; + } + + const Bitmap &image = *Input; + + const unsigned int *dims = image.GetDimensions(); + unsigned long len = image.GetBufferLength(); + char *p = new char[len]; + image.GetBuffer( p ); + + assert( len % 3 == 0 ); + const size_t ps = Input->GetPixelFormat().GetPixelSize(); + const size_t framesize = dims[0] * dims[1] * ps; + assert( framesize * dims[2] == len ); + + char *copy = new char[len]; + size_t size = framesize / 3; + if( PlanarConfiguration == 0 ) + { + for(unsigned int z = 0; z < dims[2]; ++z) + { + const char *frame = p + z * framesize; + const char *r = frame + 0; + const char *g = frame + size; + const char *b = frame + size + size; + + char *framecopy = copy + z * framesize; + ImageChangePlanarConfiguration::RGBPlanesToRGBPixels(framecopy, r, g, b, size); + } + } + else // User requested to do PlanarConfiguration == 1 + { + assert( PlanarConfiguration == 1 ); + for(unsigned int z = 0; z < dims[2]; ++z) + { + const char *frame = p + z * framesize; + char *framecopy = copy + z * framesize; + char *r = framecopy + 0; + char *g = framecopy + size; + char *b = framecopy + size + size; + + ImageChangePlanarConfiguration::RGBPixelsToRGBPlanes(r, g, b, frame, size); + } + } + delete[] p; + + DataElement &de = Output->GetDataElement(); + de.SetByteValue( copy, (uint32_t)len ); + delete[] copy; + + Output->SetPlanarConfiguration( PlanarConfiguration ); + if( Input->GetTransferSyntax().IsImplicit() ) + { + assert( Output->GetTransferSyntax().IsImplicit() ); + } + else if( Input->GetTransferSyntax() == TransferSyntax::ExplicitVRBigEndian ) + { + Output->SetTransferSyntax( TransferSyntax::ExplicitVRBigEndian ); + } + else + { + Output->SetTransferSyntax( TransferSyntax::ExplicitVRLittleEndian ); + } + //assert( Output->GetTransferSyntax().IsRaw() ); + assert( Output->GetPhotometricInterpretation() == Input->GetPhotometricInterpretation() ); + + return true; +} + + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmImageChangePlanarConfiguration.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmImageChangePlanarConfiguration.h new file mode 100644 index 0000000..daa3a38 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmImageChangePlanarConfiguration.h @@ -0,0 +1,90 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMIMAGECHANGEPLANARCONFIGURATION_H +#define GDCMIMAGECHANGEPLANARCONFIGURATION_H + +#include "gdcmImageToImageFilter.h" + +namespace gdcm +{ + +class DataElement; +/** + * \brief ImageChangePlanarConfiguration class + * Class to change the Planar configuration of an input DICOM + * By default it will change into the more usual reprensentation: PlanarConfiguration = 0 + */ +class GDCM_EXPORT ImageChangePlanarConfiguration : public ImageToImageFilter +{ +public: + ImageChangePlanarConfiguration():PlanarConfiguration(0) {} + ~ImageChangePlanarConfiguration() {} + + /// Set/Get requested PlanarConfigation + void SetPlanarConfiguration(unsigned int pc) { PlanarConfiguration = pc; } + unsigned int GetPlanarConfiguration() const { return PlanarConfiguration; } + + /// s is the size of one plane (r,g or b). Thus the output buffer needs to be at least 3*s bytes long + /// s can be seen as the number of RGB pixels in the output + template + static size_t RGBPlanesToRGBPixels(T *out, const T *r, const T *g, const T *b, size_t s); + + /// Convert a regular RGB pixel image (R,G,B,R,G,B...) into a planar R,G,B image (R,R..,G,G...B,B) + /// \warning this works on a frame basis, you need to loop over all frames in multiple frames + /// image to apply this function + template + static size_t RGBPixelsToRGBPlanes(T *r, T *g, T *b, const T* rgb, size_t s); + + /// Change + bool Change(); + +protected: + +private: + unsigned int PlanarConfiguration; +}; + +template +size_t ImageChangePlanarConfiguration::RGBPlanesToRGBPixels(T *out, const T *r, const T *g, const T *b, size_t s) +{ + T *pout = out; + for(size_t i = 0; i < s; ++i ) + { + *pout++ = *r++; + *pout++ = *g++; + *pout++ = *b++; + } + + assert( (size_t)(pout - out) == 3 * s * sizeof(T) ); + return pout - out; +} + +template +size_t ImageChangePlanarConfiguration::RGBPixelsToRGBPlanes(T *r, T *g, T *b, const T *rgb, size_t s) +{ + const T *prgb = rgb; + for(size_t i = 0; i < s; ++i ) + { + *r++ = *prgb++; + *g++ = *prgb++; + *b++ = *prgb++; + } + assert( (size_t)(prgb - rgb) == 3 * s * sizeof(T) ); + return prgb - rgb; +} + + +} // end namespace gdcm + +#endif //GDCMIMAGECHANGEPLANARCONFIGURATION_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmImageChangeTransferSyntax.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmImageChangeTransferSyntax.cxx new file mode 100644 index 0000000..588cf06 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmImageChangeTransferSyntax.cxx @@ -0,0 +1,476 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmImageChangeTransferSyntax.h" +#include "gdcmSequenceOfFragments.h" +#include "gdcmSequenceOfItems.h" +#include "gdcmFragment.h" +#include "gdcmPixmap.h" +#include "gdcmBitmap.h" +#include "gdcmRAWCodec.h" +#include "gdcmJPEGCodec.h" +#include "gdcmJPEGLSCodec.h" +#include "gdcmJPEG2000Codec.h" +#include "gdcmRLECodec.h" + +namespace gdcm +{ + +/* +bool ImageChangeTransferSyntax::TryRAWCodecIcon(const DataElement &pixelde) +{ + unsigned long len = Input->GetIconImage().GetBufferLength(); + //assert( len == pixelde.GetByteValue()->GetLength() ); + const TransferSyntax &ts = GetTransferSyntax(); + + RAWCodec codec; + if( codec.CanCode( ts ) ) + { + codec.SetDimensions( Input->GetIconImage().GetDimensions() ); + codec.SetPlanarConfiguration( Input->GetIconImage().GetPlanarConfiguration() ); + codec.SetPhotometricInterpretation( Input->GetIconImage().GetPhotometricInterpretation() ); + codec.SetPixelFormat( Input->GetIconImage().GetPixelFormat() ); + codec.SetNeedOverlayCleanup( Input->GetIconImage().AreOverlaysInPixelData() ); + DataElement out; + //bool r = codec.Code(Input->GetDataElement(), out); + bool r = codec.Code(pixelde, out); + + DataElement &de = Output->GetIconImage().GetDataElement(); + de.SetValue( out.GetValue() ); + if( !r ) + { + return false; + } + return true; + } + return false; +} +*/ + +void UpdatePhotometricInterpretation( Bitmap const &input, Bitmap &output ) +{ + // when decompressing J2K, need to revert to proper photo inter in uncompressed TS: + if( input.GetPhotometricInterpretation() == PhotometricInterpretation::YBR_RCT + || input.GetPhotometricInterpretation() == PhotometricInterpretation::YBR_ICT ) + { + output.SetPhotometricInterpretation( PhotometricInterpretation::RGB ); + } + // when decompressing loss jpeg, need to revert to proper photo inter in uncompressed TS: + if( input.GetPhotometricInterpretation() == PhotometricInterpretation::YBR_FULL_422 ) + { + output.SetPhotometricInterpretation( PhotometricInterpretation::YBR_FULL ); + } + assert( output.GetPhotometricInterpretation() == PhotometricInterpretation::RGB + || output.GetPhotometricInterpretation() == PhotometricInterpretation::YBR_FULL + || output.GetPhotometricInterpretation() == PhotometricInterpretation::MONOCHROME1 + || output.GetPhotometricInterpretation() == PhotometricInterpretation::MONOCHROME2 + || output.GetPhotometricInterpretation() == PhotometricInterpretation::ARGB + || output.GetPhotometricInterpretation() == PhotometricInterpretation::PALETTE_COLOR ); // programmer error +} + +bool ImageChangeTransferSyntax::TryRAWCodec(const DataElement &pixelde, Bitmap const &input, Bitmap &output) +{ + unsigned long len = input.GetBufferLength(); (void)len; + //assert( len == pixelde.GetByteValue()->GetLength() ); + const TransferSyntax &ts = GetTransferSyntax(); + + RAWCodec codec; + if( codec.CanCode( ts ) ) + { + codec.SetDimensions( input.GetDimensions() ); + codec.SetPlanarConfiguration( input.GetPlanarConfiguration() ); + codec.SetPhotometricInterpretation( input.GetPhotometricInterpretation() ); + codec.SetPixelFormat( input.GetPixelFormat() ); + codec.SetNeedOverlayCleanup( input.AreOverlaysInPixelData() ); + DataElement out; + //bool r = codec.Code(input.GetDataElement(), out); + bool r = codec.Code(pixelde, out); + + if( !r ) + { + return false; + } + DataElement &de = output.GetDataElement(); + de.SetValue( out.GetValue() ); + UpdatePhotometricInterpretation( input, output ); + return true; + } + return false; +} + +bool ImageChangeTransferSyntax::TryRLECodec(const DataElement &pixelde, Bitmap const &input, Bitmap &output) +{ + unsigned long len = input.GetBufferLength(); (void)len; + //assert( len == pixelde.GetByteValue()->GetLength() ); + const TransferSyntax &ts = GetTransferSyntax(); + + RLECodec codec; + if( codec.CanCode( ts ) ) + { + codec.SetDimensions( input.GetDimensions() ); + codec.SetPlanarConfiguration( input.GetPlanarConfiguration() ); + codec.SetPhotometricInterpretation( input.GetPhotometricInterpretation() ); + codec.SetPixelFormat( input.GetPixelFormat() ); + codec.SetNeedOverlayCleanup( input.AreOverlaysInPixelData() ); + DataElement out; + //bool r = codec.Code(input.GetDataElement(), out); + bool r = codec.Code(pixelde, out); + + if( !r ) + { + return false; + } + DataElement &de = output.GetDataElement(); + de.SetValue( out.GetValue() ); + UpdatePhotometricInterpretation( input, output ); + return true; + } + return false; +} + +bool ImageChangeTransferSyntax::TryJPEGCodec(const DataElement &pixelde, Bitmap const &input, Bitmap &output) +{ + unsigned long len = input.GetBufferLength(); (void)len; + //assert( len == pixelde.GetByteValue()->GetLength() ); + const TransferSyntax &ts = GetTransferSyntax(); + + JPEGCodec jpgcodec; + // pass lossy/lossless flag: + // JPEGCodec are easier to deal with since there is no dual transfer syntax + // that can be both lossy and lossless: + if( ts.IsLossy() ) + { + assert( !ts.IsLossless() ); + jpgcodec.SetLossless( false ); + } + + ImageCodec *codec = &jpgcodec; + if( UserCodec && UserCodec->CanCode( ts ) ) + { + codec = UserCodec; + } + + if( codec->CanCode( ts ) ) + { + codec->SetDimensions( input.GetDimensions() ); + // FIXME: GDCM always apply the planar configuration to 0... + //if( input.GetPlanarConfiguration() ) + // { + // output.SetPlanarConfiguration( 0 ); + // } + codec->SetPlanarConfiguration( input.GetPlanarConfiguration() ); + codec->SetPhotometricInterpretation( input.GetPhotometricInterpretation() ); + codec->SetPixelFormat( input.GetPixelFormat() ); + codec->SetNeedOverlayCleanup( input.AreOverlaysInPixelData() ); + DataElement out; + //bool r = codec.Code(input.GetDataElement(), out); + bool r = codec->Code(pixelde, out); + // FIXME: this is not the best place to change the Output image internal type, + // but since I know IJG is always applying the Planar Configuration, it does make + // any sense to EVER produce a JPEG image where the Planar Configuration would be one + // so let's be nice and actually sync JPEG configuration with DICOM Planar Conf. + output.SetPlanarConfiguration( 0 ); + //output.SetPhotometricInterpretation( PhotometricInterpretation::RGB ); + + // Indeed one cannot produce a true lossless RGB image according to DICOM standard + // when doing lossless jpeg: + if( output.GetPhotometricInterpretation() == PhotometricInterpretation::RGB ) + { + gdcmWarningMacro( "Technically this is not defined in the standard. \n" + "Some validator may complains this image is invalid, but would be wrong."); + } + + // PHILIPS_Gyroscan-12-MONO2-Jpeg_Lossless.dcm + if( !r ) + { + return false; + } + DataElement &de = output.GetDataElement(); + de.SetValue( out.GetValue() ); + UpdatePhotometricInterpretation( input, output ); + // When compressing with JPEG I think planar should always be: + //output.SetPlanarConfiguration(0); + // FIXME ! This should be done all the time for all codec: + // Did PI change or not ? + if ( !output.GetPhotometricInterpretation().IsSameColorSpace( codec->GetPhotometricInterpretation() ) ) + { + // HACK + //gdcm::Image *i = (gdcm::Image*)this; + //i->SetPhotometricInterpretation( codec.GetPhotometricInterpretation() ); + assert(0); + } + return true; + } + return false; +} + +bool ImageChangeTransferSyntax::TryJPEGLSCodec(const DataElement &pixelde, Bitmap const &input, Bitmap &output) +{ + unsigned long len = input.GetBufferLength(); (void)len; + //assert( len == pixelde.GetByteValue()->GetLength() ); + const TransferSyntax &ts = GetTransferSyntax(); + + JPEGLSCodec codec; + if( codec.CanCode( ts ) ) + { + codec.SetDimensions( input.GetDimensions() ); + codec.SetPixelFormat( input.GetPixelFormat() ); + //codec.SetNumberOfDimensions( input.GetNumberOfDimensions() ); + codec.SetPlanarConfiguration( input.GetPlanarConfiguration() ); + codec.SetPhotometricInterpretation( input.GetPhotometricInterpretation() ); + codec.SetNeedOverlayCleanup( input.AreOverlaysInPixelData() ); + DataElement out; + //bool r = codec.Code(input.GetDataElement(), out); + bool r = codec.Code(pixelde, out); + if(!r) return false; + output.SetPlanarConfiguration( 0 ); + + DataElement &de = output.GetDataElement(); + de.SetValue( out.GetValue() ); + UpdatePhotometricInterpretation( input, output ); + return r; + } + return false; +} + +bool ImageChangeTransferSyntax::TryJPEG2000Codec(const DataElement &pixelde, Bitmap const &input, Bitmap &output) +{ + unsigned long len = input.GetBufferLength(); (void)len; + //assert( len == pixelde.GetByteValue()->GetLength() ); + const TransferSyntax &ts = GetTransferSyntax(); + + JPEG2000Codec j2kcodec; + ImageCodec *codec = &j2kcodec; + if( UserCodec && UserCodec->CanCode( ts ) ) + { + codec = UserCodec; + } + + if( codec->CanCode( ts ) ) + { + codec->SetDimensions( input.GetDimensions() ); + codec->SetPixelFormat( input.GetPixelFormat() ); + codec->SetNumberOfDimensions( input.GetNumberOfDimensions() ); + codec->SetPlanarConfiguration( input.GetPlanarConfiguration() ); + codec->SetPhotometricInterpretation( input.GetPhotometricInterpretation() ); + codec->SetNeedOverlayCleanup( input.AreOverlaysInPixelData() ); + DataElement out; + //bool r = codec.Code(input.GetDataElement(), out); + bool r = codec->Code(pixelde, out); + + // The value of Planar Configuration (0028,0006) is irrelevant since the + // manner of encoding components is specified in the JPEG 2000 standard, + // hence it shall be set to 0. + output.SetPlanarConfiguration( 0 ); + + if( input.GetPixelFormat().GetSamplesPerPixel() == 3 ) + { + if( input.GetPhotometricInterpretation().IsSameColorSpace( PhotometricInterpretation::RGB ) ) + { + if( ts == TransferSyntax::JPEG2000Lossless ) + { + output.SetPhotometricInterpretation( PhotometricInterpretation::YBR_RCT ); + } + else + { + assert( ts == TransferSyntax::JPEG2000 ); + output.SetPhotometricInterpretation( PhotometricInterpretation::YBR_ICT ); + } + } + else + { + assert( input.GetPhotometricInterpretation().IsSameColorSpace( PhotometricInterpretation::YBR_FULL ) ); + if( ts == TransferSyntax::JPEG2000Lossless ) + { + output.SetPhotometricInterpretation( PhotometricInterpretation::YBR_FULL ); + // Indeed one cannot produce a true lossless RGB image according to DICOM standard + gdcmWarningMacro( "Technically this is not defined in the standard. \n" + "Some validator may complains this image is invalid, but would be wrong."); + } + else + { + assert( ts == TransferSyntax::JPEG2000 ); + //output.SetPhotometricInterpretation( PhotometricInterpretation::YBR_ICT ); + // FIXME: technically when doing lossy we could be standard compliant and first convert to + // RGB THEN compress to YBR_ICT. For now produce improper j2k image + output.SetPhotometricInterpretation( PhotometricInterpretation::YBR_FULL ); + } + } + } + else + { + assert( input.GetPixelFormat().GetSamplesPerPixel() == 1 ); + } + + if( !r ) return false; + DataElement &de = output.GetDataElement(); + de.SetValue( out.GetValue() ); + UpdatePhotometricInterpretation( input, output ); + return r; + } + return false; +} + +bool ImageChangeTransferSyntax::Change() +{ + if( TS == TransferSyntax::TS_END ) + { + if( !Force ) return false; + // When force option is set but no specific TransferSyntax has been set, only inspect the + // encapsulated stream... + // See gdcm::ImageReader::Read + if( Input->GetTransferSyntax().IsEncapsulated() && Input->GetTransferSyntax() != TransferSyntax::RLELossless ) + { + Output = Input; + return true; + } + return false; + } + // let's get rid of some easy case: + if( Input->GetPhotometricInterpretation() == PhotometricInterpretation::PALETTE_COLOR && + TS.IsLossy() ) + { + gdcmErrorMacro( "PALETTE_COLOR and Lossy compression are impossible. Convert to RGB first." ); + return false; + } + + Output = Input; +// if( TS.IsLossy() && !TS.IsLossless() ) +// Output->SetLossyFlag( true ); + + // Fast path + if( Input->GetTransferSyntax() == TS && !Force ) return true; + + // FIXME + // For now only support raw input, otherwise we would need to first decompress them + if( (Input->GetTransferSyntax() != TransferSyntax::ImplicitVRLittleEndian + && Input->GetTransferSyntax() != TransferSyntax::ExplicitVRLittleEndian + && Input->GetTransferSyntax() != TransferSyntax::ExplicitVRBigEndian) + || Force ) + { + // In memory decompression: + gdcm::DataElement pixeldata( gdcm::Tag(0x7fe0,0x0010) ); + gdcm::ByteValue *bv0 = new gdcm::ByteValue(); + uint32_t len0 = (uint32_t)Input->GetBufferLength(); + bv0->SetLength( len0 ); + bool b = Input->GetBuffer( (char*)bv0->GetPointer() ); + if( !b ) + { + gdcmErrorMacro( "Error in getting buffer from input image." ); + return false; + } + pixeldata.SetValue( *bv0 ); + + bool success = false; + if( !success ) success = TryRAWCodec(pixeldata, *Input, *Output); + if( !success ) success = TryJPEGCodec(pixeldata, *Input, *Output); + if( !success ) success = TryJPEGLSCodec(pixeldata, *Input, *Output); + if( !success ) success = TryJPEG2000Codec(pixeldata, *Input, *Output); + if( !success ) success = TryRLECodec(pixeldata, *Input, *Output); + Output->SetTransferSyntax( TS ); + if( !success ) + { + //assert(0); + return false; + } + + // same goes for icon + gdcm::DataElement iconpixeldata( gdcm::Tag(0x7fe0,0x0010) ); + Bitmap &bitmap = *Input; + if( Pixmap *pixmap = dynamic_cast( &bitmap ) ) + { + Bitmap &outbitmap = *Output; + Pixmap *outpixmap = dynamic_cast( &outbitmap ); + assert( outpixmap != NULL ); + if( !pixmap->GetIconImage().IsEmpty() ) + { + // same goes for icon + gdcm::ByteValue *bv = new gdcm::ByteValue(); + uint32_t len = (uint32_t)pixmap->GetIconImage().GetBufferLength(); + bv->SetLength( len ); + bool bb = pixmap->GetIconImage().GetBuffer( (char*)bv->GetPointer() ); + if( !bb ) + { + return false; + } + iconpixeldata.SetValue( *bv ); + + success = false; + if( !success ) success = TryRAWCodec(iconpixeldata, pixmap->GetIconImage(), outpixmap->GetIconImage()); + if( !success ) success = TryJPEGCodec(iconpixeldata, pixmap->GetIconImage(), outpixmap->GetIconImage()); + if( !success ) success = TryJPEGLSCodec(iconpixeldata, pixmap->GetIconImage(), outpixmap->GetIconImage()); + if( !success ) success = TryJPEG2000Codec(iconpixeldata, pixmap->GetIconImage(), outpixmap->GetIconImage()); + if( !success ) success = TryRLECodec(iconpixeldata, pixmap->GetIconImage(), outpixmap->GetIconImage()); + outpixmap->GetIconImage().SetTransferSyntax( TS ); + if( !success ) + { + //assert(0); + return false; + } + assert( outpixmap->GetIconImage().GetTransferSyntax() == TS ); + } + } + + //Output->ComputeLossyFlag(); + assert( Output->GetTransferSyntax() == TS ); + //if( TS.IsLossy() ) assert( Output->IsLossy() ); + return success; + } + + // too bad we actually have to do some work... + bool success = false; + if( !success ) success = TryRAWCodec(Input->GetDataElement(), *Input, *Output); + if( !success ) success = TryJPEGCodec(Input->GetDataElement(), *Input, *Output); + if( !success ) success = TryJPEG2000Codec(Input->GetDataElement(), *Input, *Output); + if( !success ) success = TryJPEGLSCodec(Input->GetDataElement(), *Input, *Output); + if( !success ) success = TryRLECodec(Input->GetDataElement(), *Input, *Output); + Output->SetTransferSyntax( TS ); + if( !success ) + { + //assert(0); + return false; + } + + Bitmap &bitmap = *Input; + if( Pixmap *pixmap = dynamic_cast( &bitmap ) ) + { + if( !pixmap->GetIconImage().IsEmpty() && CompressIconImage ) + { + Bitmap &outbitmap = *Output; + Pixmap *outpixmap = dynamic_cast( &outbitmap ); + + // same goes for icon + success = false; + if( !success ) success = TryRAWCodec(pixmap->GetIconImage().GetDataElement(), pixmap->GetIconImage(), outpixmap->GetIconImage()); + if( !success ) success = TryJPEGCodec(pixmap->GetIconImage().GetDataElement(), pixmap->GetIconImage(), outpixmap->GetIconImage()); + if( !success ) success = TryJPEGLSCodec(pixmap->GetIconImage().GetDataElement(), pixmap->GetIconImage(), outpixmap->GetIconImage()); + if( !success ) success = TryJPEG2000Codec(pixmap->GetIconImage().GetDataElement(), pixmap->GetIconImage(), outpixmap->GetIconImage()); + if( !success ) success = TryRLECodec(pixmap->GetIconImage().GetDataElement(), pixmap->GetIconImage(), outpixmap->GetIconImage()); + outpixmap->GetIconImage().SetTransferSyntax( TS ); + if( !success ) + { + //assert(0); + return false; + } + assert( outpixmap->GetIconImage().GetTransferSyntax() == TS ); + } + } + + //Output->ComputeLossyFlag(); + + assert( Output->GetTransferSyntax() == TS ); + return success; +} + + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmImageChangeTransferSyntax.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmImageChangeTransferSyntax.h new file mode 100644 index 0000000..4a13626 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmImageChangeTransferSyntax.h @@ -0,0 +1,92 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMIMAGECHANGETRANSFERSYNTAX_H +#define GDCMIMAGECHANGETRANSFERSYNTAX_H + +#include "gdcmImageToImageFilter.h" +#include "gdcmTransferSyntax.h" + +namespace gdcm +{ + +class DataElement; +class ImageCodec; +/** + * \brief ImageChangeTransferSyntax class + * Class to change the transfer syntax of an input DICOM + * + * If only Force param is set but no input TransferSyntax is set, it is assumed + * that user only wants to inspect encapsulated stream (advanced dev. option). + * + * When using UserCodec it is very important that the TransferSyntax (as set in + * SetTransferSyntax) is actually understood by UserCodec (ie. + * UserCodec->CanCode( TransferSyntax ) ). Otherwise the behavior is to use a + * default codec. + * + * \sa JPEGCodec JPEGLSCodec JPEG2000Codec + */ +class GDCM_EXPORT ImageChangeTransferSyntax : public ImageToImageFilter +{ +public: + ImageChangeTransferSyntax():TS(TransferSyntax::TS_END),Force(false),CompressIconImage(false),UserCodec(0) {} + ~ImageChangeTransferSyntax() {} + + /// Set target Transfer Syntax + void SetTransferSyntax(const TransferSyntax &ts) { TS = ts; } + /// Get Transfer Syntax + const TransferSyntax &GetTransferSyntax() const { return TS; } + + /// Change + bool Change(); + + /// Decide whether or not to also compress the Icon Image using the same + /// Transfer Syntax. Default is to simply decompress icon image + void SetCompressIconImage(bool b) { CompressIconImage = b; } + + /// When target Transfer Syntax is identical to input target syntax, no + /// operation is actually done. + /// This is an issue when someone wants to re-compress using GDCM internal + /// implementation a JPEG (for example) image + void SetForce( bool f ) { Force = f; } + + /// Allow user to specify exactly which codec to use. this is needed to + /// specify special qualities or compression option. + /// \warning if the codec 'ic' is not compatible with the TransferSyntax + /// requested, it will not be used. It is the user responsibility to check + /// that UserCodec->CanCode( TransferSyntax ) + void SetUserCodec(ImageCodec *ic) { UserCodec = ic; } + +protected: + bool TryJPEGCodec(const DataElement &pixelde, Bitmap const &input, Bitmap &output); + bool TryJPEG2000Codec(const DataElement &pixelde, Bitmap const &input, Bitmap &output); + bool TryJPEGLSCodec(const DataElement &pixelde, Bitmap const &input, Bitmap &output); + bool TryRAWCodec(const DataElement &pixelde, Bitmap const &input, Bitmap &output); + bool TryRLECodec(const DataElement &pixelde, Bitmap const &input, Bitmap &output); + +private: + TransferSyntax TS; + bool Force; + bool CompressIconImage; + + ImageCodec *UserCodec; +}; + +/** + * \example StandardizeFiles.cs + * This is a C++ example on how to use gdcm::ImageChangeTransferSyntax + */ + +} // end namespace gdcm + +#endif //GDCMIMAGECHANGETRANSFERSYNTAX_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmImageCodec.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmImageCodec.cxx new file mode 100644 index 0000000..c23b95a --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmImageCodec.cxx @@ -0,0 +1,605 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmImageCodec.h" +#include "gdcmJPEGCodec.h" +#include "gdcmByteSwap.txx" +#include "gdcmTrace.h" + +#include +#include +#include + +#include +#include + +namespace gdcm +{ + +class ImageInternals +{ +public: +}; + +ImageCodec::ImageCodec() +{ + PlanarConfiguration = 0; + RequestPlanarConfiguration = false; + RequestPaddedCompositePixelCode = false; + PI = PhotometricInterpretation::UNKNOW; + //LUT = LookupTable(LookupTable::UNKNOWN); + LUT = new LookupTable; + NeedByteSwap = false; + NeedOverlayCleanup = false; + Dimensions[0] = Dimensions[1] = Dimensions[2] = 0; + NumberOfDimensions = 0; + LossyFlag = false; +} + +ImageCodec::~ImageCodec() +{ +} + +bool ImageCodec::GetHeaderInfo(std::istream &, TransferSyntax &) +{ + // This function should really be virtual pure. + assert( 0 ); + return false; +} + +void ImageCodec::SetLossyFlag(bool l) +{ + LossyFlag = l; +} + +bool ImageCodec::GetLossyFlag() const +{ + return LossyFlag; +} + +bool ImageCodec::IsLossy() const +{ + return LossyFlag; +} + +void ImageCodec::SetNumberOfDimensions(unsigned int dim) +{ + NumberOfDimensions = dim; +} + +unsigned int ImageCodec::GetNumberOfDimensions() const +{ + return NumberOfDimensions; +} + + +const PhotometricInterpretation &ImageCodec::GetPhotometricInterpretation() const +{ + return PI; +} + +void ImageCodec::SetPhotometricInterpretation( + PhotometricInterpretation const &pi) +{ + PI = pi; +} + +bool ImageCodec::DoByteSwap(std::istream &is, std::ostream &os) +{ + // FIXME: Do some stupid work: + std::streampos start = is.tellg(); + assert( 0 - start == 0 ); + is.seekg( 0, std::ios::end); + size_t buf_size = (size_t)is.tellg(); + //assert(buf_size < INT_MAX); + char *dummy_buffer = new char[(unsigned int)buf_size]; + is.seekg(start, std::ios::beg); + is.read( dummy_buffer, buf_size); + is.seekg(start, std::ios::beg); // reset + //SwapCode sc = is.GetSwapCode(); + + assert( !(buf_size % 2) ); +#ifdef GDCM_WORDS_BIGENDIAN + if( PF.GetBitsAllocated() == 16 ) + { + ByteSwap::SwapRangeFromSwapCodeIntoSystem((uint16_t*) + dummy_buffer, SwapCode::LittleEndian, buf_size/2); + } +#else + // GE_DLX-8-MONO2-PrivateSyntax.dcm is 8bits + // assert( PF.GetBitsAllocated() == 16 ); + if ( PF.GetBitsAllocated() == 16 ) + { + ByteSwap::SwapRangeFromSwapCodeIntoSystem((uint16_t*) + dummy_buffer, SwapCode::BigEndian, buf_size/2); + } +#endif + os.write(dummy_buffer, buf_size); + delete[] dummy_buffer; + return true; +} + +bool ImageCodec::DoYBR(std::istream &is, std::ostream &os) +{ + // FIXME: Do some stupid work: + std::streampos start = is.tellg(); + assert( 0 - start == 0 ); + is.seekg( 0, std::ios::end); + size_t buf_size = (size_t)is.tellg(); + //assert(buf_size < INT_MAX); + char *dummy_buffer = new char[(unsigned int)buf_size]; + is.seekg(start, std::ios::beg); + is.read( dummy_buffer, buf_size); + is.seekg(start, std::ios::beg); // reset + //SwapCode sc = is.GetSwapCode(); + + // Code is coming from: + // http://lestourtereaux.free.fr/papers/data/yuvrgb.pdf + assert( !(buf_size % 3) ); + unsigned long size = (unsigned long)buf_size/3; + //assert(buf_size < INT_MAX); + unsigned char *copy = new unsigned char[ (unsigned int)buf_size ]; + memmove( copy, dummy_buffer, (size_t)buf_size); +assert(0); // Do not use this code ! + // FIXME FIXME FIXME + // The following is bogus: we are doing two operation at once: + // Planar configuration AND YBR... doh ! + const unsigned char *a = copy + 0; + const unsigned char *b = copy + size; + const unsigned char *c = copy + size + size; + int R, G, B; + + unsigned char *p = (unsigned char*)dummy_buffer; + for (unsigned long j = 0; j < size; ++j) + { + R = 38142 *(*a-16) + 52298 *(*c -128); + G = 38142 *(*a-16) - 26640 *(*c -128) - 12845 *(*b -128); + B = 38142 *(*a-16) + 66093 *(*b -128); + + R = (R+16384)>>15; + G = (G+16384)>>15; + B = (B+16384)>>15; + + if (R < 0) R = 0; + if (G < 0) G = 0; + if (B < 0) B = 0; + if (R > 255) R = 255; + if (G > 255) G = 255; + if (B > 255) B = 255; + + *(p++) = (unsigned char)R; + *(p++) = (unsigned char)G; + *(p++) = (unsigned char)B; + a++; + b++; + c++; + } + delete[] copy; + + os.write(dummy_buffer, buf_size); + delete[] dummy_buffer; + return true; +} + +bool ImageCodec::DoPlanarConfiguration(std::istream &is, std::ostream &os) +{ + // FIXME: Do some stupid work: + std::streampos start = is.tellg(); + assert( 0 - start == 0 ); + is.seekg( 0, std::ios::end); + size_t buf_size = (size_t)is.tellg(); + //assert(buf_size < INT_MAX); + char *dummy_buffer = new char[(unsigned int)buf_size]; + is.seekg(start, std::ios::beg); + is.read( dummy_buffer, buf_size); + is.seekg(start, std::ios::beg); // reset + //SwapCode sc = is.GetSwapCode(); + + // US-RGB-8-epicard.dcm + //assert( image.GetNumberOfDimensions() == 3 ); + assert( buf_size % 3 == 0 ); + unsigned long size = (unsigned long)buf_size/3; + char *copy = new char[ (unsigned int)buf_size ]; + //memmove( copy, dummy_buffer, buf_size); + + const char *r = dummy_buffer /*copy*/; + const char *g = dummy_buffer /*copy*/ + size; + const char *b = dummy_buffer /*copy*/ + size + size; + + char *p = copy /*dummy_buffer*/; + for (unsigned long j = 0; j < size; ++j) + { + *(p++) = *(r++); + *(p++) = *(g++); + *(p++) = *(b++); + } + delete[] dummy_buffer /*copy*/; + + os.write(copy /*dummy_buffer*/, buf_size); + delete[] copy; + return true; +} + +bool ImageCodec::DoSimpleCopy(std::istream &is, std::ostream &os) +{ +#if 1 + std::streampos start = is.tellg(); + assert( 0 - start == 0 ); + is.seekg( 0, std::ios::end); + size_t buf_size = (size_t)is.tellg(); + //assert(buf_size < INT_MAX); + char *dummy_buffer = new char[(unsigned int)buf_size]; + is.seekg(start, std::ios::beg); + is.read( dummy_buffer, buf_size); + is.seekg(start, std::ios::beg); // reset + os.write( dummy_buffer, buf_size); + delete[] dummy_buffer ; +#else + // This code is ideal but is failing on an RLE image...need to figure out + // what is wrong to reactivate this code. + os.rdbuf( is.rdbuf() ); +#endif + + return true; +} + +bool ImageCodec::DoPaddedCompositePixelCode(std::istream &is, std::ostream &os) +{ + // FIXME: Do some stupid work: + std::streampos start = is.tellg(); + assert( 0 - start == 0 ); + is.seekg( 0, std::ios::end); + size_t buf_size = (size_t)is.tellg(); + //assert(buf_size < INT_MAX); + char *dummy_buffer = new char[(unsigned int)buf_size]; + is.seekg(start, std::ios::beg); + is.read( dummy_buffer, buf_size); + is.seekg(start, std::ios::beg); // reset + //SwapCode sc = is.GetSwapCode(); + + assert( !(buf_size % 2) ); + if( GetPixelFormat().GetBitsAllocated() == 16 ) + { + for(size_t i = 0; i < buf_size/2; ++i) + { +#ifdef GDCM_WORDS_BIGENDIAN + os.write( dummy_buffer+i, 1 ); + os.write( dummy_buffer+i+buf_size/2, 1 ); +#else + os.write( dummy_buffer+i+buf_size/2, 1 ); + os.write( dummy_buffer+i, 1 ); +#endif + } + } + else if( GetPixelFormat().GetBitsAllocated() == 32 ) + { + assert( !(buf_size % 4) ); + for(size_t i = 0; i < buf_size/4; ++i) + { +#ifdef GDCM_WORDS_BIGENDIAN + os.write( dummy_buffer+i, 1 ); + os.write( dummy_buffer+i+1*buf_size/4, 1 ); + os.write( dummy_buffer+i+2*buf_size/4, 1 ); + os.write( dummy_buffer+i+3*buf_size/4, 1 ); +#else + os.write( dummy_buffer+i+3*buf_size/4, 1 ); + os.write( dummy_buffer+i+2*buf_size/4, 1 ); + os.write( dummy_buffer+i+1*buf_size/4, 1 ); + os.write( dummy_buffer+i, 1 ); +#endif + } + } + else + { + return false; + } + delete[] dummy_buffer; + return true; +} + +bool ImageCodec::DoInvertMonochrome(std::istream &is, std::ostream &os) +{ + if ( PF.GetPixelRepresentation() ) + { + if ( PF.GetBitsAllocated() == 8 ) + { + uint8_t c; + while( is.read((char*)&c,1) ) + { + c = (uint8_t)(255 - c); + os.write((char*)&c, 1 ); + } + } + else if ( PF.GetBitsAllocated() == 16 ) + { + assert( PF.GetBitsStored() != 12 ); + uint16_t smask16 = 65535; + uint16_t c; + while( is.read((char*)&c,2) ) + { + c = (uint16_t)(smask16 - c); + os.write((char*)&c, 2); + } + } + } + else + { + if ( PF.GetBitsAllocated() == 8 ) + { + uint8_t c; + while( is.read((char*)&c,1) ) + { + c = (uint8_t)(255 - c); + os.write((char*)&c, 1); + } + } + else if ( PF.GetBitsAllocated() == 16 ) + { + uint16_t mask = 1; + for (int j=0; j mask ) + { + // IMAGES/JPLY/RG3_JPLY aka CompressedSamples^RG3/1.3.6.1.4.1.5962.1.1.11.1.5.20040826185059.5457 + // gdcmData/D_CLUNIE_RG3_JPLY.dcm + // stores a 12bits JPEG stream with scalar value [0,1024], however + // the DICOM header says the data are stored on 10bits [0,1023], thus this HACK: + gdcmWarningMacro( "Bogus max value: "<< c << " max should be at most: " << mask + << " results will be truncated. Use at own risk"); + c = mask; + } + assert( c <= mask ); + c = (uint16_t)(mask - c); + assert( c <= mask ); + os.write((char*)&c, 2); + } + } + + } + return true; +} + +struct ApplyMask +{ + uint16_t operator()(uint16_t c) const { + return (uint16_t)((c >> (BitsStored - HighBit - 1)) & pmask); + } + unsigned short BitsStored; + unsigned short HighBit; + uint16_t pmask; +}; + +// Cleanup the unused bits +bool ImageCodec::DoOverlayCleanup(std::istream &is, std::ostream &os) +{ + assert( PF.GetBitsAllocated() > 8 ); + if( PF.GetBitsAllocated() == 16 ) + { + // pmask : to mask the 'unused bits' (may contain overlays) + uint16_t pmask = 0xffff; + pmask = (uint16_t)(pmask >> ( PF.GetBitsAllocated() - PF.GetBitsStored() )); + + if( PF.GetPixelRepresentation() ) + { + // smask : to check the 'sign' when BitsStored != BitsAllocated + uint16_t smask = 0x0001; + smask = (uint16_t)( + smask << ( 16 - (PF.GetBitsAllocated() - PF.GetBitsStored() + 1) )); + // nmask : to propagate sign bit on negative values + int16_t nmask = (int16_t)0x8000; + nmask = (int16_t)(nmask >> ( PF.GetBitsAllocated() - PF.GetBitsStored() - 1 )); + + uint16_t c; + while( is.read((char*)&c,2) ) + { + c = (uint16_t)(c >> (PF.GetBitsStored() - PF.GetHighBit() - 1)); + if ( c & smask ) + { + c = (uint16_t)(c | nmask); + } + else + { + c = c & pmask; + } + os.write((char*)&c, 2 ); + } + } + else // Pixel are unsigned + { +#if 1 + uint16_t c; + while( is.read((char*)&c,2) ) + { + c = (uint16_t)( + (c >> (PF.GetBitsStored() - PF.GetHighBit() - 1)) & pmask); + os.write((char*)&c, 2 ); + } + //os.rdbuf( is.rdbuf() ); +#else + //std::ostreambuf_iterator end_of_stream_iterator; + //std::ostreambuf_iterator out_iter(os.rdbuf()); + //while( out_iter != end_of_stream_iterator ) + // { + // *out_iter = + // (*out_iter >> (PF.GetBitsStored() - PF.GetHighBit() - 1)) & pmask; + // } + std::istreambuf_iterator it_in(is); + std::istreambuf_iterator eos; + std::ostreambuf_iterator it_out(os); + ApplyMask am; + am.BitsStored = PF.GetBitsStored(); + am.HighBit = PF.GetHighBit(); + am.pmask = pmask; + + std::transform(it_in, eos, it_out, am); +#endif + } + } + else + { + assert(0); // TODO + } + return true; +} + +bool ImageCodec::Decode(DataElement const &, DataElement &) +{ + return true; +} + +bool ImageCodec::DecodeByStreams(std::istream &is, std::ostream &os) +{ + assert( PlanarConfiguration == 0 || PlanarConfiguration == 1); + assert( PI != PhotometricInterpretation::UNKNOW ); + std::stringstream bs_os; // ByteSwap + std::stringstream pcpc_os; // Padded Composite Pixel Code + std::stringstream pi_os; // PhotometricInterpretation + std::stringstream pl_os; // PlanarConf + std::istream *cur_is = &is; + + // First thing do the byte swap: + if( NeedByteSwap ) + { + // MR_GE_with_Private_Compressed_Icon_0009_1110.dcm + DoByteSwap(*cur_is,bs_os); + cur_is = &bs_os; + } + if ( RequestPaddedCompositePixelCode ) + { + // D_CLUNIE_CT2_RLE.dcm + DoPaddedCompositePixelCode(*cur_is,pcpc_os); + cur_is = &pcpc_os; + } + + // Second thing do palette color. + // This way PALETTE COLOR will be applied before we do + // Planar Configuration + switch(PI) + { + case PhotometricInterpretation::MONOCHROME2: + case PhotometricInterpretation::RGB: + case PhotometricInterpretation::ARGB: + break; + case PhotometricInterpretation::MONOCHROME1: + // CR-MONO1-10-chest.dcm + //DoInvertMonochrome(*cur_is, pi_os); + //cur_is = &pi_os; + break; + case PhotometricInterpretation::YBR_FULL: + //DoYBR(*cur_is,pi_os); + //cur_is = &pi_os; + { + const JPEGCodec *c = dynamic_cast(this); + if( c ) + { + // The following is required for very special case of color space conversion + // dcmdrle ACUSON-24-YBR_FULL-RLE.dcm bla.dcm + // dcmcjpeg bla.dcm foo.dcm + // foo.dcm would be not displayed correctly + //this->SetPhotometricInterpretation( PhotometricInterpretation::RGB ); + } + } + break; + case PhotometricInterpretation::PALETTE_COLOR: + //assert( LUT ); + // Nothing needs to be done + break; + case PhotometricInterpretation::YBR_FULL_422: + { + // US-GE-4AICL142.dcm + // Hopefully it has been done by the JPEG decoder itself... + const JPEGCodec *c = dynamic_cast(this); + if( !c ) + { + gdcmErrorMacro( "YBR_FULL_422 is not implemented in GDCM. Image will be displayed incorrectly" ); + //this->SetPhotometricInterpretation( PhotometricInterpretation::RGB ); + } + } + break; + case PhotometricInterpretation::YBR_ICT: + break; + case PhotometricInterpretation::YBR_RCT: + break; + default: + gdcmErrorMacro( "Unhandled PhotometricInterpretation: " << PI ); + return false; + assert(0); + } + + if( /*PlanarConfiguration ||*/ RequestPlanarConfiguration ) + { + DoPlanarConfiguration(*cur_is,pl_os); + cur_is = &pl_os; + } + + // Do the overlay cleanup (cleanup the unused bits) + // must be the last operation (duh!) + if ( PF.GetBitsAllocated() != PF.GetBitsStored() + && PF.GetBitsAllocated() != 8 ) + { + // Technically we should only run this operation if the image declares it has overlay AND + // there is no (0x60xx,0x3000) element, for example: + // - XA_GE_JPEG_02_with_Overlays.dcm + // - SIEMENS_GBS_III-16-ACR_NEMA_1.acr + // Sigh, I finally found someone not declaring that unused bits where not zero: + // gdcmConformanceTests/dcm4chee_unusedbits_not_zero.dcm + if( NeedOverlayCleanup ) + DoOverlayCleanup(*cur_is,os); + else + { + // Once the issue with IMAGES/JPLY/RG3_JPLY aka gdcmData/D_CLUNIE_RG3_JPLY.dcm is solved the previous + // code will be replace with a simple call to: + DoSimpleCopy(*cur_is,os); + } + } + else + { + assert( PF.GetBitsAllocated() == PF.GetBitsStored() ); + DoSimpleCopy(*cur_is,os); + } + + return true; +} + +bool ImageCodec::IsValid(PhotometricInterpretation const &) +{ + return false; +} + +void ImageCodec::SetDimensions(const unsigned int d[3]) +{ + Dimensions[0] = d[0]; + Dimensions[1] = d[1]; + Dimensions[2] = d[2]; +} + +void ImageCodec::SetDimensions(const std::vector & d) +{ + size_t theSize = d.size(); + assert(theSize<= 3); + for (size_t i = 0; i < 3; i++) + { + if (i < theSize) + Dimensions[i] = d[i]; + else + Dimensions[i] = 1; + } +} + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmImageCodec.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmImageCodec.h new file mode 100644 index 0000000..b839728 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmImageCodec.h @@ -0,0 +1,134 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMIMAGECODEC_H +#define GDCMIMAGECODEC_H + +#include "gdcmCodec.h" +#include "gdcmPhotometricInterpretation.h" +#include "gdcmLookupTable.h" +#include "gdcmSmartPointer.h" +#include "gdcmPixelFormat.h" + +namespace gdcm +{ + +/** + * \brief ImageCodec + * \note Main codec, this is a central place for all implementation + */ +class GDCM_EXPORT ImageCodec : public Codec +{ + friend class ImageChangePhotometricInterpretation; +public: + ImageCodec(); + ~ImageCodec(); + bool CanCode(TransferSyntax const &) const { return false; } + bool CanDecode(TransferSyntax const &) const { return false; } + bool Decode(DataElement const &is_, DataElement &os); + bool IsLossy() const; + void SetLossyFlag(bool l); + bool GetLossyFlag() const; + + virtual bool GetHeaderInfo(std::istream &is_, TransferSyntax &ts); + + virtual ImageCodec * Clone() const = 0; + +protected: + bool DecodeByStreams(std::istream &is_, std::ostream &os); + virtual bool IsValid(PhotometricInterpretation const &pi); +public: + + unsigned int GetPlanarConfiguration() const + { + return PlanarConfiguration; + } + void SetPlanarConfiguration(unsigned int pc) + { + assert( pc == 0 || pc == 1 ); + PlanarConfiguration = pc; + } + + PixelFormat &GetPixelFormat() + { + return PF; + } + const PixelFormat &GetPixelFormat() const + { + return PF; + } + virtual void SetPixelFormat(PixelFormat const &pf) + { + PF = pf; + } + const PhotometricInterpretation &GetPhotometricInterpretation() const; + void SetPhotometricInterpretation(PhotometricInterpretation const &pi); + + bool GetNeedByteSwap() const + { + return NeedByteSwap; + } + void SetNeedByteSwap(bool b) + { + NeedByteSwap = b; + } + void SetNeedOverlayCleanup(bool b) + { + NeedOverlayCleanup = b; + } + void SetLUT(LookupTable const &lut) + { + LUT = SmartPointer( const_cast(&lut) ); + } + const LookupTable &GetLUT() const + { + return *LUT; + } + + void SetDimensions(const unsigned int d[3]); + void SetDimensions(const std::vector & d); + const unsigned int *GetDimensions() const { return Dimensions; } + void SetNumberOfDimensions(unsigned int dim); + unsigned int GetNumberOfDimensions() const; + +protected: + bool RequestPlanarConfiguration; + bool RequestPaddedCompositePixelCode; +//private: + unsigned int PlanarConfiguration; + PhotometricInterpretation PI; + PixelFormat PF; + bool NeedByteSwap; + bool NeedOverlayCleanup; + + typedef SmartPointer LUTPtr; + LUTPtr LUT; + unsigned int Dimensions[3]; // FIXME + unsigned int NumberOfDimensions; + bool LossyFlag; + + bool DoOverlayCleanup(std::istream &is_, std::ostream &os); + bool DoByteSwap(std::istream &is_, std::ostream &os); + bool DoYBR(std::istream &is_, std::ostream &os); + bool DoPlanarConfiguration(std::istream &is_, std::ostream &os); + bool DoSimpleCopy(std::istream &is_, std::ostream &os); + bool DoPaddedCompositePixelCode(std::istream &is_, std::ostream &os); + bool DoInvertMonochrome(std::istream &is_, std::ostream &os); + + //template + //bool DoInvertPlanarConfiguration(T *output, const T *input, uint32_t length); +}; + +} // end namespace gdcm + +#endif //GDCMIMAGECODEC_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmImageConverter.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmImageConverter.cxx new file mode 100644 index 0000000..d00fbc6 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmImageConverter.cxx @@ -0,0 +1,44 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmImageConverter.h" +#include "gdcmImage.h" + +namespace gdcm +{ + +ImageConverter::ImageConverter() +{ + Output = new Image; +} + +ImageConverter::~ImageConverter() +{ + delete Output; +} + +void ImageConverter::SetInput(Image const &input) +{ + Input = const_cast(&input); +} + +const Image& ImageConverter::GetOuput() const +{ + return *Output; +} + +void ImageConverter::Convert() +{ +} + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmImageConverter.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmImageConverter.h new file mode 100644 index 0000000..bdbf968 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmImageConverter.h @@ -0,0 +1,51 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#ifndef GDCMIMAGECONVERTER_H +#define GDCMIMAGECONVERTER_H + +#include "gdcmTypes.h" + +namespace gdcm +{ + +class Image; +/** + * \brief Image Converter + * \note + * This is the class used to convert from on gdcm::Image to another + * This is typically used to convert let say YBR JPEG compressed + * gdcm::Image to a RAW RGB gdcm::Image. So that the buffer can be directly + * pass to third party application. + * This filter is application level and not integrated directly in GDCM + */ +class GDCM_EXPORT ImageConverter +{ +public: + ImageConverter(); + ~ImageConverter(); + + void SetInput(Image const &input); + const Image& GetOuput() const; + + void Convert(); + +private: + Image *Input; + Image *Output; +}; + +} // end namespace gdcm + +#endif //GDCMIMAGECONVERTER_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmImageFragmentSplitter.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmImageFragmentSplitter.cxx new file mode 100644 index 0000000..79f5032 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmImageFragmentSplitter.cxx @@ -0,0 +1,113 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmImageFragmentSplitter.h" +#include "gdcmSequenceOfFragments.h" + +namespace gdcm +{ + +bool ImageFragmentSplitter::Split() +{ + Output = Input; + const Bitmap &image = *Input; + + const unsigned int *dims = image.GetDimensions(); + if( dims[2] != 1 ) + { + gdcmDebugMacro( "Cannot split a 3D image" ); + return false; + } + const DataElement& pixeldata = image.GetDataElement(); + + const SequenceOfFragments *sqf = pixeldata.GetSequenceOfFragments(); + if( !sqf ) + { + gdcmDebugMacro( "Cannot split a non-encapsulated syntax" ); + return false; + } + + if ( sqf->GetNumberOfFragments() != 1 ) + { + gdcmDebugMacro( "Case not handled (for now)" ); + return false; + } + + //assert( sqf->GetNumberOfFragments() == 1 ); + + // WARNING do not keep the same Basic Offset Table... + const Fragment& frag = sqf->GetFragment(0); + const ByteValue *bv = frag.GetByteValue(); + const char *p = bv->GetPointer(); + unsigned long len = bv->GetLength(); + if( FragmentSizeMax > len && !Force ) + { + // I think it is ok + return true; + } + // prevent zero division + if( FragmentSizeMax == 0 ) + { + gdcmDebugMacro( "Need to set a real value for fragment size" ); + return false; // seriously... + } + unsigned long nfrags = len / FragmentSizeMax; + unsigned long lastfrag = len % FragmentSizeMax; + + SmartPointer sq = new SequenceOfFragments; + // Let's do all complete frag: + for(unsigned long i = 0; i < nfrags; ++i) + { + Fragment splitfrag; + splitfrag.SetByteValue( p + i * FragmentSizeMax, FragmentSizeMax); + sq->AddFragment( splitfrag ); + } + // Last (incomplete one): + if( lastfrag ) + { + Fragment splitfrag; + splitfrag.SetByteValue( p + nfrags * FragmentSizeMax, (uint32_t)lastfrag ); + assert( nfrags * FragmentSizeMax + lastfrag == len ); + sq->AddFragment( splitfrag ); + } + Output->GetDataElement().SetValue( *sq ); + + bool success = true; + return success; +} + +void ImageFragmentSplitter::SetFragmentSizeMax(unsigned int fragsize) +{ +/* + * A.4 TRANSFER SYNTAXES FOR ENCAPSULATION OF ENCODED PIXEL DATA + * + * All items containing an encoded fragment shall be made of an even number of bytes + * greater or equal to two. The last fragment of a frame may be padded, if necessary, + * to meet the sequence item format requirements of the DICOM Standard. + */ + FragmentSizeMax = fragsize; + if( fragsize % 2 ) + { + // what if FragmentSizeMax == 0 ... + FragmentSizeMax--; + } + // How do I handle this one... + if( fragsize < 2 ) + { + FragmentSizeMax = 2; + } + // \postcondition: + assert( FragmentSizeMax >= 2 && (FragmentSizeMax % 2) == 0 ); +} + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmImageFragmentSplitter.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmImageFragmentSplitter.h new file mode 100644 index 0000000..a771cdb --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmImageFragmentSplitter.h @@ -0,0 +1,53 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMIMAGEFRAGMENTSPLITTER_H +#define GDCMIMAGEFRAGMENTSPLITTER_H + +#include "gdcmImageToImageFilter.h" + +namespace gdcm +{ + +class DataElement; +/** + * \brief ImageFragmentSplitter class + * For single frame image, DICOM standard allow splitting the frame into multiple fragments + */ +class GDCM_EXPORT ImageFragmentSplitter : public ImageToImageFilter +{ +public: + ImageFragmentSplitter():FragmentSizeMax(0),Force(false) {} + ~ImageFragmentSplitter() {} + + /// Split + bool Split(); + + /// FragmentSizeMax needs to be an even number + void SetFragmentSizeMax(unsigned int fragsize); + unsigned int GetFragmentSizeMax() const { return FragmentSizeMax; } + + /// When file already has all it's segment < FragmentSizeMax there is not need to run the filter. + /// Unless the user explicitly say 'force' recomputation ! + void SetForce( bool f ) { Force = f; } + +protected: + +private: + unsigned int FragmentSizeMax; + bool Force; +}; + +} // end namespace gdcm + +#endif //GDCMIMAGEFRAGMENTSPLITTER_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmImageHelper.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmImageHelper.cxx new file mode 100644 index 0000000..29e4ae3 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmImageHelper.cxx @@ -0,0 +1,2200 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmImageHelper.h" +#include "gdcmMediaStorage.h" +#include "gdcmFile.h" +#include "gdcmDataSet.h" +#include "gdcmDataElement.h" +#include "gdcmItem.h" +#include "gdcmSequenceOfItems.h" +#include "gdcmGlobal.h" +#include "gdcmDictEntry.h" +#include "gdcmDicts.h" +#include "gdcmAttribute.h" +#include "gdcmImage.h" +#include "gdcmDirectionCosines.h" +#include "gdcmSegmentedPaletteColorLookupTable.h" +#include "gdcmByteValue.h" + +#include // fabs + + /* TODO: + * + * (0028,9145) SQ (Sequence with undefined length #=1) # u/l, 1 PixelValueTransformationSequence + * (fffe,e000) na (Item with undefined length #=3) # u/l, 1 Item + * (0028,1052) DS [0.00000] # 8, 1 RescaleIntercept + * (0028,1053) DS [1.00000] # 8, 1 RescaleSlope + * (0028,1054) LO [US] # 2, 1 RescaleType + * (fffe,e00d) na (ItemDelimitationItem) # 0, 0 ItemDelimitationItem + * (fffe,e0dd) na (SequenceDelimitationItem) # 0, 0 SequenceDelimitationItem + * + * Same goes for window level... + */ + +namespace gdcm +{ + +bool ImageHelper::ForceRescaleInterceptSlope = false; +bool ImageHelper::ForcePixelSpacing = false; + +bool GetOriginValueFromSequence(const DataSet& ds, const Tag& tfgs, std::vector &ori) +{ + if( !ds.FindDataElement( tfgs ) ) return false; + //const SequenceOfItems * sqi = ds.GetDataElement( tfgs ).GetSequenceOfItems(); + SmartPointer sqi = ds.GetDataElement( tfgs ).GetValueAsSQ(); + assert( sqi ); + // Get first item: + const Item &item = sqi->GetItem(1); + const DataSet & subds = item.GetNestedDataSet(); + // Plane position Sequence + const Tag tpms(0x0020,0x9113); + if( !subds.FindDataElement(tpms) ) return false; + //const SequenceOfItems * sqi2 = subds.GetDataElement( tpms ).GetSequenceOfItems(); + SmartPointer sqi2 = subds.GetDataElement( tpms ).GetValueAsSQ(); + assert( sqi2 ); + const Item &item2 = sqi2->GetItem(1); + const DataSet & subds2 = item2.GetNestedDataSet(); + // + const Tag tps(0x0020,0x0032); + if( !subds2.FindDataElement(tps) ) return false; + const DataElement &de = subds2.GetDataElement( tps ); + //assert( bv ); + gdcm::Attribute<0x0020,0x0032> at; + at.SetFromDataElement( de ); + //at.Print( std::cout ); + ori.push_back( at.GetValue(0) ); + ori.push_back( at.GetValue(1) ); + ori.push_back( at.GetValue(2) ); + + return true; +} + +bool GetDirectionCosinesValueFromSequence(const DataSet& ds, const Tag& tfgs, std::vector &dircos) +{ + if( !ds.FindDataElement( tfgs ) ) return false; + //const SequenceOfItems * sqi = ds.GetDataElement( tfgs ).GetSequenceOfItems(); + SmartPointer sqi = ds.GetDataElement( tfgs ).GetValueAsSQ(); + assert( sqi ); + // Get first item: + const Item &item = sqi->GetItem(1); + const DataSet & subds = item.GetNestedDataSet(); + // Plane position Sequence + const Tag tpms(0x0020,0x9116); + if( !subds.FindDataElement(tpms) ) return false; + //const SequenceOfItems * sqi2 = subds.GetDataElement( tpms ).GetSequenceOfItems(); + SmartPointer sqi2 = subds.GetDataElement( tpms ).GetValueAsSQ(); + assert( sqi2 && sqi2->GetNumberOfItems() ); + // Take it from the first item + const Item &item2 = sqi2->GetItem(1); + const DataSet & subds2 = item2.GetNestedDataSet(); + // + const Tag tps(0x0020,0x0037); + if( !subds2.FindDataElement(tps) ) return false; + const DataElement &de = subds2.GetDataElement( tps ); + //assert( bv ); + gdcm::Attribute<0x0020,0x0037> at; + at.SetFromDataElement( de ); + dircos.push_back( at.GetValue(0) ); + dircos.push_back( at.GetValue(1) ); + dircos.push_back( at.GetValue(2) ); + dircos.push_back( at.GetValue(3) ); + dircos.push_back( at.GetValue(4) ); + dircos.push_back( at.GetValue(5) ); + + return true; +} + +bool GetInterceptSlopeValueFromSequence(const DataSet& ds, const Tag& tfgs, std::vector &intslope) +{ + if( !ds.FindDataElement( tfgs ) ) return false; + //const SequenceOfItems * sqi = ds.GetDataElement( tfgs ).GetSequenceOfItems(); + SmartPointer sqi = ds.GetDataElement( tfgs ).GetValueAsSQ(); + assert( sqi ); + // Get first item: + const Item &item = sqi->GetItem(1); + const DataSet & subds = item.GetNestedDataSet(); + // (0028,9145) SQ (Sequence with undefined length) # u/l,1 Pixel Value Transformation Sequence + const Tag tpms(0x0028,0x9145); + if( !subds.FindDataElement(tpms) ) return false; + //const SequenceOfItems * sqi2 = subds.GetDataElement( tpms ).GetSequenceOfItems(); + SmartPointer sqi2 = subds.GetDataElement( tpms ).GetValueAsSQ(); + assert( sqi2 ); + const Item &item2 = sqi2->GetItem(1); + const DataSet & subds2 = item2.GetNestedDataSet(); + { + // (0028,1052) DS [0] # 2,1 Rescale Intercept + const Tag tps(0x0028,0x1052); + if( !subds2.FindDataElement(tps) ) return false; + const DataElement &de = subds2.GetDataElement( tps ); + //assert( bv ); + gdcm::Attribute<0x0028,0x1052> at; + at.SetFromDataElement( de ); + //at.Print( std::cout ); + intslope.push_back( at.GetValue() ); + } + { + // (0028,1053) DS [5.65470085470085] # 16,1 Rescale Slope + const Tag tps(0x0028,0x1053); + if( !subds2.FindDataElement(tps) ) return false; + const DataElement &de = subds2.GetDataElement( tps ); + //assert( bv ); + gdcm::Attribute<0x0028,0x1053> at; + at.SetFromDataElement( de ); + //at.Print( std::cout ); + intslope.push_back( at.GetValue() ); + } + + assert( intslope.size() == 2 ); + return true; +} + +bool ComputeZSpacingFromIPP(const DataSet &ds, double &zspacing) +{ + // first we need to get the direction cosines: + const Tag t1(0x5200,0x9229); + const Tag t2(0x5200,0x9230); + std::vector cosines; + // For some reason TOSHIBA-EnhancedCT.dcm is storing the direction cosines in the per-frame section + // and not the shared one... oh well + bool b1 = GetDirectionCosinesValueFromSequence(ds, t1, cosines) + || GetDirectionCosinesValueFromSequence(ds,t2,cosines); + if(!b1) + { + cosines.resize( 6 ); + bool b2 = ImageHelper::GetDirectionCosinesFromDataSet(ds, cosines); + if( b2 ) + { + gdcmWarningMacro( "Image Orientation (Patient) cannot be stored here!. Continuing" ); + b1 = b2; + } + else + { + gdcmErrorMacro( "Image Orientation (Patient) was not found" ); + cosines[0] = 1; + cosines[1] = 0; + cosines[2] = 0; + cosines[3] = 0; + cosines[4] = 1; + cosines[5] = 0; + } + } + assert( b1 && cosines.size() == 6 ); // yeah we really need that + + const Tag tfgs(0x5200,0x9230); + if( !ds.FindDataElement( tfgs ) ) return false; + //const SequenceOfItems * sqi = ds.GetDataElement( tfgs ).GetSequenceOfItems(); + SmartPointer sqi = ds.GetDataElement( tfgs ).GetValueAsSQ(); + assert( sqi ); + double normal[3]; + DirectionCosines dc( &cosines[0] ); + dc.Cross( normal ); + + // For each item + std::vector distances; + gdcm::SequenceOfItems::SizeType nitems = sqi->GetNumberOfItems(); + std::vector dircos_subds2; dircos_subds2.resize(6); + for(gdcm::SequenceOfItems::SizeType i0 = 1; i0 <= nitems; ++i0) + { + const Item &item = sqi->GetItem(i0); + const DataSet & subds = item.GetNestedDataSet(); + // (0020,9113) SQ (Sequence with undefined length #=1) # u/l, 1 PlanePositionSequence + const Tag tpms(0x0020,0x9113); + if( !subds.FindDataElement(tpms) ) return false; + //const SequenceOfItems * sqi2 = subds.GetDataElement( tpms ).GetSequenceOfItems(); + SmartPointer sqi2 = subds.GetDataElement( tpms ).GetValueAsSQ(); + assert( sqi2 ); + const Item &item2 = sqi2->GetItem(1); + const DataSet & subds2 = item2.GetNestedDataSet(); + // Check Image Orientation (Patient) + if( ImageHelper::GetDirectionCosinesFromDataSet(subds2, dircos_subds2) ) + { + assert( dircos_subds2 == cosines ); + } + // (0020,0032) DS [-82.5\-82.5\1153.75] # 20, 3 ImagePositionPatient + const Tag tps(0x0020,0x0032); + if( !subds2.FindDataElement(tps) ) return false; + const DataElement &de = subds2.GetDataElement( tps ); + Attribute<0x0020,0x0032> ipp; + ipp.SetFromDataElement(de); + double dist = 0; + for (int i = 0; i < 3; ++i) dist += normal[i]*ipp[i]; + distances.push_back( dist ); + } + assert( distances.size() == nitems ); + double meanspacing = 0; + double prev = distances[0]; + for(unsigned int i = 1; i < nitems; ++i) + { + const double current = distances[i] - prev; + meanspacing += current; + prev = distances[i]; + } + bool timeseries = false; + if( nitems > 1 ) + { + meanspacing /= (double)(nitems - 1); + if( meanspacing == 0.0 ) + { + // Could be a time series. Assume time spacing of 1. for now: + gdcmDebugMacro( "Assuming time series for Z-spacing" ); + meanspacing = 1.0; + timeseries = true; + } + } + + zspacing = meanspacing; + assert( zspacing != 0.0 ); // technically this should not happen + + if( !timeseries ) + { + // Check spacing is consistent: + const double ZTolerance = 1e-3; // ??? FIXME + prev = distances[0]; + for(unsigned int i = 1; i < nitems; ++i) + { + const double current = distances[i] - prev; + if( fabs(current - zspacing) > ZTolerance ) + { + // For now simply gives up + gdcmErrorMacro( "This Enhanced Multiframe is not supported for now. Sorry" ); + return false; + } + prev = distances[i]; + } + } + return true; +} + +// EnhancedMRImageStorage & EnhancedCTImageStorage +bool GetSpacingValueFromSequence(const DataSet& ds, const Tag& tfgs, std::vector &sp) +{ + // (0028,9110) SQ (Sequence with undefined length #=1) # u/l, 1 PixelMeasuresSequence + // (fffe,e000) na (Item with undefined length #=2) # u/l, 1 Item + // (0018,0050) DS [0.5] # 4, 1 SliceThickness + // (0028,0030) DS [0.322\0.322] # 12, 2 PixelSpacing + // + //const Tag tfgs(0x5200,0x9229); + //const Tag tfgs(0x5200,0x9230); + //assert( ds.FindDataElement( tfgs ) ); + if( !ds.FindDataElement( tfgs ) ) return false; + //const SequenceOfItems * sqi = ds.GetDataElement( tfgs ).GetSequenceOfItems(); + SmartPointer sqi = ds.GetDataElement( tfgs ).GetValueAsSQ(); + assert( sqi ); + // Get first item: + const Item &item = sqi->GetItem(1); + const DataSet & subds = item.GetNestedDataSet(); + // + const Tag tpms(0x0028,0x9110); + if( !subds.FindDataElement(tpms) ) return false; + //const SequenceOfItems * sqi2 = subds.GetDataElement( tpms ).GetSequenceOfItems(); + SmartPointer sqi2 = subds.GetDataElement( tpms ).GetValueAsSQ(); + assert( sqi2 ); + const Item &item2 = sqi2->GetItem(1); + const DataSet & subds2 = item2.GetNestedDataSet(); + // + const Tag tps(0x0028,0x0030); + if( !subds2.FindDataElement(tps) ) return false; + const DataElement &de = subds2.GetDataElement( tps ); + //assert( bv ); + gdcm::Attribute<0x0028,0x0030> at; + at.SetFromDataElement( de ); + //at.Print( std::cout ); + sp.push_back( at.GetValue(1) ); + sp.push_back( at.GetValue(0) ); + + // BUG ! Check for instace: + // gdcmData/BRTUM001.dcm + // Slice Thickness is 5.0 while the Zspacing should be 6.0 ! +#if 0 + // Do the 3rd dimension zspacing: + // + const Tag tst(0x0018,0x0050); + if( !subds2.FindDataElement(tst) ) return false; + const DataElement &de2 = subds2.GetDataElement( tst ); + gdcm::Attribute<0x0018,0x0050> at2; + at2.SetFromDataElement( de2 ); + //at2.Print( std::cout ); + sp.push_back( at2.GetValue(0) ); +#endif + double zspacing; + bool b = ComputeZSpacingFromIPP(ds, zspacing); + if( !b ) return false; + + sp.push_back( zspacing ); + + return true; +} + +// UltrasoundMultiframeImageStorage +bool GetUltraSoundSpacingValueFromSequence(const DataSet& ds, std::vector &sp) +{ +/* +(0018,6011) SQ (Sequence with explicit length #=1) # 196, 1 SequenceOfUltrasoundRegions + (fffe,e000) na (Item with explicit length #=15) # 188, 1 Item + (0018,6012) US 1 # 2, 1 RegionSpatialFormat + (0018,6014) US 1 # 2, 1 RegionDataType + (0018,6016) UL 0 # 4, 1 RegionFlags + (0018,6018) UL 0 # 4, 1 RegionLocationMinX0 + (0018,601a) UL 0 # 4, 1 RegionLocationMinY0 + (0018,601c) UL 479 # 4, 1 RegionLocationMaxX1 + (0018,601e) UL 479 # 4, 1 RegionLocationMaxY1 + (0018,6020) SL 0 # 4, 1 ReferencePixelX0 + (0018,6022) SL 0 # 4, 1 ReferencePixelY0 + (0018,6024) US 3 # 2, 1 PhysicalUnitsXDirection + (0018,6026) US 3 # 2, 1 PhysicalUnitsYDirection + (0018,6028) FD 0 # 8, 1 ReferencePixelPhysicalValueX + (0018,602a) FD 0 # 8, 1 ReferencePixelPhysicalValueY + (0018,602c) FD 0.002 # 8, 1 PhysicalDeltaX + (0018,602e) FD 0.002 # 8, 1 PhysicalDeltaY + (fffe,e00d) na (ItemDelimitationItem for re-encoding) # 0, 0 ItemDelimitationItem +(fffe,e0dd) na (SequenceDelimitationItem for re-encod.) # 0, 0 SequenceDelimitationItem +*/ + const Tag tsqusreg(0x0018,0x6011); + if( !ds.FindDataElement( tsqusreg ) ) return false; + //const SequenceOfItems * sqi = ds.GetDataElement( tsqusreg ).GetSequenceOfItems(); + SmartPointer sqi = ds.GetDataElement( tsqusreg ).GetValueAsSQ(); + assert( sqi ); + // Get first item: + const Item &item = sqi->GetItem(1); + const DataSet & subds = item.GetNestedDataSet(); + // (0018,602c) FD 0.002 # 8, 1 PhysicalDeltaX + // (0018,602e) FD 0.002 # 8, 1 PhysicalDeltaY + gdcm::Attribute<0x0018,0x602c> at1; + gdcm::Attribute<0x0018,0x602e> at2; + const DataElement &de1 = subds.GetDataElement( at1.GetTag() ); + at1.SetFromDataElement( de1 ); + assert( at1.GetNumberOfValues() == 1 ); + const DataElement &de2 = subds.GetDataElement( at2.GetTag() ); + at2.SetFromDataElement( de2 ); + assert( at2.GetNumberOfValues() == 1 ); + sp.push_back( at1.GetValue() ); + sp.push_back( at2.GetValue() ); + + return true; +} + + + +/* Enhanced stuff looks like: + + (0020,9113) SQ (Sequence with undefined length #=1) # u/l, 1 PlanePositionSequence + (fffe,e000) na (Item with undefined length #=1) # u/l, 1 Item + (0020,0032) DS [73.5100815890831\-129.65028828174\189.777023529388] # 50, 3 ImagePositionPatient + (fffe,e00d) na (ItemDelimitationItem) # 0, 0 ItemDelimitationItem + (fffe,e0dd) na (SequenceDelimitationItem) # 0, 0 SequenceDelimitationItem + (0020,9116) SQ (Sequence with undefined length #=1) # u/l, 1 PlaneOrientationSequence + (fffe,e000) na (Item with undefined length #=1) # u/l, 1 Item + (0020,0037) DS [0.01604138687252\0.99942564964294\-0.0298495516180\0.0060454937629... # 102, 6 ImageOrientationPatient + (fffe,e00d) na (ItemDelimitationItem) # 0, 0 ItemDelimitationItem + (fffe,e0dd) na (SequenceDelimitationItem) # 0, 0 SequenceDelimitationItem + (0028,9110) SQ (Sequence with undefined length #=1) # u/l, 1 PixelMeasuresSequence + (fffe,e000) na (Item with undefined length #=2) # u/l, 1 Item + (0018,0050) DS [1] # 2, 1 SliceThickness + (0028,0030) DS [0.83333331346511\0.83333331346511] # 34, 2 PixelSpacing + (fffe,e00d) na (ItemDelimitationItem) # 0, 0 ItemDelimitationItem + (fffe,e0dd) na (SequenceDelimitationItem) # 0, 0 SequenceDelimitationItem +*/ + +std::vector ImageHelper::GetOriginValue(File const & f) +{ + std::vector ori; + MediaStorage ms; + ms.SetFromFile(f); + const DataSet& ds = f.GetDataSet(); + + if( ms == MediaStorage::EnhancedCTImageStorage + || ms == MediaStorage::EnhancedMRImageStorage + || ms == MediaStorage::OphthalmicTomographyImageStorage + || ms == MediaStorage::SegmentationStorage ) + { + const Tag t1(0x5200,0x9229); + const Tag t2(0x5200,0x9230); + if( GetOriginValueFromSequence(ds,t1, ori) + || GetOriginValueFromSequence(ds, t2, ori) ) + { + assert( ori.size() == 3 ); + return ori; + } + ori.resize( 3 ); + gdcmWarningMacro( "Could not find Origin" ); + return ori; + } + if( ms == MediaStorage::NuclearMedicineImageStorage ) + { + const Tag t1(0x0054,0x0022); + if( ds.FindDataElement( t1 ) ) + { + SmartPointer sqi = ds.GetDataElement( t1 ).GetValueAsSQ(); + if( sqi && sqi->GetNumberOfItems() >= 1) + { + // Get first item: + const Item &item = sqi->GetItem(1); + const DataSet & subds = item.GetNestedDataSet(); + const Tag timagepositionpatient(0x0020, 0x0032); + assert( subds.FindDataElement( timagepositionpatient ) ); + Attribute<0x0020,0x0032> at = {{0,0,0}}; // default value if empty + at.SetFromDataSet( subds ); + ori.resize( at.GetNumberOfValues() ); + for( unsigned int i = 0; i < at.GetNumberOfValues(); ++i ) + { + ori[i] = at.GetValue(i); + } + return ori; + } + } + ori.resize( 3 ); + gdcmWarningMacro( "Could not find Origin" ); + return ori; + } + ori.resize( 3 ); + + // else + const Tag timagepositionpatient(0x0020, 0x0032); + if( ms != MediaStorage::SecondaryCaptureImageStorage && ds.FindDataElement( timagepositionpatient ) ) + { + const DataElement& de = ds.GetDataElement( timagepositionpatient ); + Attribute<0x0020,0x0032> at = {{0,0,0}}; // default value if empty + at.SetFromDataElement( de ); + for( unsigned int i = 0; i < at.GetNumberOfValues(); ++i ) + { + ori[i] = at.GetValue(i); + } + } + else + { + ori[0] = 0; + ori[1] = 0; + ori[2] = 0; + } + assert( ori.size() == 3 ); + return ori; +} + +bool ImageHelper::GetDirectionCosinesFromDataSet(DataSet const & ds, std::vector & dircos) +{ + // \precondition: this dataset is not a secondary capture ! + // else + const Tag timageorientationpatient(0x0020, 0x0037); + if( ds.FindDataElement( timageorientationpatient ) /*&& !ds.GetDataElement( timageorientationpatient ).IsEmpty()*/ ) + { + const DataElement& de = ds.GetDataElement( timageorientationpatient ); + Attribute<0x0020,0x0037> at = {{1,0,0,0,1,0}}; // default value if empty + at.SetFromDataElement( de ); + for( unsigned int i = 0; i < at.GetNumberOfValues(); ++i ) + { + dircos[i] = at.GetValue(i); + } + DirectionCosines dc( &dircos[0] ); + if( !dc.IsValid() ) + { + dc.Normalize(); + if( dc.IsValid() ) + { + gdcmWarningMacro( "DirectionCosines was not normalized. Fixed" ); + const double * p = dc; + dircos = std::vector(p, p + 6); + //return dircos; + } + else + { + // PAPYRUS_CR_InvalidIOP.dcm + gdcmWarningMacro( "Could not get DirectionCosines. Will be set to unit vector." ); + //dircos[0] = 1; + //dircos[1] = 0; + //dircos[2] = 0; + //dircos[3] = 0; + //dircos[4] = 1; + //dircos[5] = 0; + return false; + } + } + return true; + } + return false; +} + +std::vector ImageHelper::GetDirectionCosinesValue(File const & f) +{ + std::vector dircos; + MediaStorage ms; + ms.SetFromFile(f); + const DataSet& ds = f.GetDataSet(); + + if( ms == MediaStorage::EnhancedCTImageStorage + || ms == MediaStorage::EnhancedMRImageStorage + || ms == MediaStorage::SegmentationStorage ) + { + const Tag t1(0x5200,0x9229); + const Tag t2(0x5200,0x9230); + if( GetDirectionCosinesValueFromSequence(ds,t1, dircos) + || GetDirectionCosinesValueFromSequence(ds, t2, dircos) ) + { + assert( dircos.size() == 6 ); + return dircos; + } + else + { + dircos.resize( 6 ); + bool b2 = ImageHelper::GetDirectionCosinesFromDataSet(ds, dircos); + if( b2 ) + { + gdcmWarningMacro( "Image Orientation (Patient) cannot be stored here!. Continuing" ); + } + else + { + gdcmErrorMacro( "Image Orientation (Patient) was not found" ); + dircos[0] = 1; + dircos[1] = 0; + dircos[2] = 0; + dircos[3] = 0; + dircos[4] = 1; + dircos[5] = 0; + } + return dircos; + } + } + if( ms == MediaStorage::NuclearMedicineImageStorage ) + { + const Tag t1(0x0054,0x0022); + if( ds.FindDataElement( t1 ) ) + { + SmartPointer sqi = ds.GetDataElement( t1 ).GetValueAsSQ(); + if( sqi && sqi->GetNumberOfItems() >= 1 ) + { + // Get first item: + const Item &item = sqi->GetItem(1); + const DataSet & subds = item.GetNestedDataSet(); + + dircos.resize( 6 ); + bool b2 = ImageHelper::GetDirectionCosinesFromDataSet(subds, dircos); + if( b2 ) + { + } + else + { + gdcmErrorMacro( "Image Orientation (Patient) was not found" ); + dircos[0] = 1; + dircos[1] = 0; + dircos[2] = 0; + dircos[3] = 0; + dircos[4] = 1; + dircos[5] = 0; + } + return dircos; + } + } + } + + dircos.resize( 6 ); + if( ms == MediaStorage::SecondaryCaptureImageStorage || !GetDirectionCosinesFromDataSet(ds, dircos) ) + { + dircos[0] = 1; + dircos[1] = 0; + dircos[2] = 0; + dircos[3] = 0; + dircos[4] = 1; + dircos[5] = 0; + } + + assert( dircos.size() == 6 ); + return dircos; +} + +void ImageHelper::SetForceRescaleInterceptSlope(bool b) +{ + ForceRescaleInterceptSlope = b; +} + +bool ImageHelper::GetForceRescaleInterceptSlope() +{ + return ForceRescaleInterceptSlope; +} + +void ImageHelper::SetForcePixelSpacing(bool b) +{ + ForcePixelSpacing = b; +} + +bool ImageHelper::GetForcePixelSpacing() +{ + return ForcePixelSpacing; +} + +bool GetRescaleInterceptSlopeValueFromDataSet(const DataSet& ds, std::vector & interceptslope) +{ + Attribute<0x0028,0x1052> at1; + bool intercept = ds.FindDataElement(at1.GetTag()); + if( intercept ) + { + if( !ds.GetDataElement(at1.GetTag()).IsEmpty() ) + { + at1.SetFromDataElement( ds.GetDataElement(at1.GetTag()) ); + interceptslope[0] = at1.GetValue(); + } + } + Attribute<0x0028,0x1053> at2; + bool slope = ds.FindDataElement(at2.GetTag()); + if ( slope ) + { + if( !ds.GetDataElement(at2.GetTag()).IsEmpty() ) + { + at2.SetFromDataElement( ds.GetDataElement(at2.GetTag()) ); + interceptslope[1] = at2.GetValue(); + if( interceptslope[1] == 0 ) + { + // come' on ! WTF + gdcmDebugMacro( "Cannot have slope == 0. Defaulting to 1.0 instead" ); + interceptslope[1] = 1; + } + } + } + return true; +} + + +/// This function returns pixel information about an image from its dataset +/// That includes samples per pixel and bit depth (in that order) +/// Returns a PixelFormat +PixelFormat ImageHelper::GetPixelFormatValue(const File& f) +{ + // D 0028|0011 [US] [Columns] [512] + //[10/20/10 9:05:07 AM] Mathieu Malaterre: + PixelFormat pf; + const DataSet& ds = f.GetDataSet(); + // D 0028|0100 [US] [Bits Allocated] [16] + { + //const DataElement& de = ds.GetDataElement( Tag(0x0028, 0x0100) ); + Attribute<0x0028,0x0100> at = { 0 }; + at.SetFromDataSet( ds ); + pf.SetBitsAllocated( at.GetValue() ); + } + // D 0028|0101 [US] [Bits Stored] [12] + { + //const DataElement& de = ds.GetDataElement( Tag(0x0028, 0x0101) ); + Attribute<0x0028,0x0101> at = { 0 }; + at.SetFromDataSet( ds ); + pf.SetBitsStored( at.GetValue() ); + } + // D 0028|0102 [US] [High Bit] [11] + { + //const DataElement& de = ds.GetDataElement( Tag(0x0028, 0x0102) ); + Attribute<0x0028,0x0102> at = { 0 }; + at.SetFromDataSet( ds ); + pf.SetHighBit( at.GetValue() ); + } + // D 0028|0103 [US] [Pixel Representation] [0] + { + //const DataElement& de = ds.GetDataElement( Tag(0x0028, 0x0103) ); + Attribute<0x0028,0x0103> at = { 0 }; + at.SetFromDataSet( ds ); + pf.SetPixelRepresentation( at.GetValue() ); + } + // (0028,0002) US 1 # 2, 1 SamplesPerPixel + { + //if( ds.FindDataElement( Tag(0x0028, 0x0002) ) ) + { + //const DataElement& de = ds.GetDataElement( Tag(0x0028, 0x0002) ); + Attribute<0x0028,0x0002> at = { 1 }; + at.SetFromDataSet( ds ); + pf.SetSamplesPerPixel( at.GetValue() ); + } + // else pf will default to 1... + } + return pf; + +} +/// This function checks tags (0x0028, 0x0010) and (0x0028, 0x0011) for the +/// rows and columns of the image in pixels (as opposed to actual distances). +/// Also checks 0054, 0081 for the number of z slices for a 3D image +/// If that tag is not present, default the z dimension to 1 +std::vector ImageHelper::GetDimensionsValue(const File& f) +{ + DataSet const & ds = f.GetDataSet(); + + MediaStorage ms; + ms.SetFromFile(f); + std::vector theReturn(3); +#if 0 + if( ms == MediaStorage::VLWholeSlideMicroscopyImageStorage ) + { + { + Attribute<0x0048,0x0006> at = { 0 }; + at.SetFromDataSet( ds ); + theReturn[0] = at.GetValue(); + } + { + Attribute<0x0048,0x0007> at = { 0 }; + at.SetFromDataSet( ds ); + theReturn[1] = at.GetValue(); + } + theReturn[2] = 1; + } + else +#endif + { + { + Attribute<0x0028,0x0011> at = { 0 }; + at.SetFromDataSet( ds ); + theReturn[0] = at.GetValue(); + } + { + Attribute<0x0028,0x0010> at = { 0 }; + at.SetFromDataSet( ds ); + theReturn[1] = at.GetValue(); + } + { + Attribute<0x0028,0x0008> at = { 0 }; + at.SetFromDataSet( ds ); + int numberofframes = at.GetValue(); + theReturn[2] = 1; + if( numberofframes > 1 ) + { + theReturn[2] = at.GetValue(); + } + } + // ACR-NEMA legacy + { + Attribute<0x0028,0x0005> at = { 0 }; + if( ds.FindDataElement( at.GetTag() ) ) + { + const DataElement &de = ds.GetDataElement( at.GetTag() ); + // SIEMENS_MAGNETOM-12-MONO2-Uncompressed.dcm picks VR::SS instead... + if( at.GetVR().Compatible( de.GetVR() ) ) + { + at.SetFromDataSet( ds ); + int imagedimensions = at.GetValue(); + if( imagedimensions == 3 ) + { + Attribute<0x0028,0x0012> at2 = { 0 }; + at2.SetFromDataSet( ds ); + theReturn[2] = at2.GetValue(); + } + } + else + { + gdcmWarningMacro( "Sorry cant read attribute (wrong VR): " << at.GetTag() ); + } + } + } + } + + return theReturn; +} + +void ImageHelper::SetDimensionsValue(File& f, const Image & img) +{ + const unsigned int *dims = img.GetDimensions(); + MediaStorage ms; + ms.SetFromFile(f); + DataSet& ds = f.GetDataSet(); + assert( MediaStorage::IsImage( ms ) ); +#if 0 + if( ms == MediaStorage::VLWholeSlideMicroscopyImageStorage ) + { + Attribute<0x0048,0x0006> columns; + columns.SetValue( dims[0] ); + ds.Replace( columns.GetAsDataElement() ); + Attribute<0x0048,0x0007> rows; + rows.SetValue( dims[1] ); + ds.Replace( rows.GetAsDataElement() ); + if( dims[2] > 1 ) + { + assert( 0 ); + } + } + else +#endif + { + Attribute<0x0028,0x0010> rows; + rows.SetValue( (uint16_t)dims[1] ); + ds.Replace( rows.GetAsDataElement() ); + Attribute<0x0028,0x0011> columns; + columns.SetValue( (uint16_t)dims[0] ); + ds.Replace( columns.GetAsDataElement() ); + if( dims[2] > 1 ) + { + Attribute<0x0028,0x0008> numframes = { 0 }; + ds.Replace( numframes.GetAsDataElement() ); + } + } +} + +std::vector ImageHelper::GetRescaleInterceptSlopeValue(File const & f) +{ + std::vector interceptslope; + MediaStorage ms; + ms.SetFromFile(f); + const DataSet& ds = f.GetDataSet(); + + if( ms == MediaStorage::EnhancedCTImageStorage + || ms == MediaStorage::EnhancedMRImageStorage + || ms == MediaStorage::SegmentationStorage ) + { + const Tag t1(0x5200,0x9229); + const Tag t2(0x5200,0x9230); + if( GetInterceptSlopeValueFromSequence(ds,t1, interceptslope) + || GetInterceptSlopeValueFromSequence(ds,t2, interceptslope) ) + { + assert( interceptslope.size() == 2 ); + return interceptslope; + } + else + { + interceptslope.resize( 2 ); + interceptslope[0] = 0; + interceptslope[1] = 1; + bool b = GetRescaleInterceptSlopeValueFromDataSet(ds, interceptslope); + gdcmAssertMacro( b ); (void)b; + return interceptslope; + } + } + + // else + interceptslope.resize( 2 ); + interceptslope[0] = 0; + interceptslope[1] = 1; + if( ms == MediaStorage::CTImageStorage + || ms == MediaStorage::ComputedRadiographyImageStorage + /*|| ms == MediaStorage::MRImageStorage // FIXME ! */ + || ms == MediaStorage::PETImageStorage + || ms == MediaStorage::SecondaryCaptureImageStorage + || ms == MediaStorage::MultiframeGrayscaleWordSecondaryCaptureImageStorage + || ms == MediaStorage::MultiframeGrayscaleByteSecondaryCaptureImageStorage + || ForceRescaleInterceptSlope + ) + { + bool b = GetRescaleInterceptSlopeValueFromDataSet(ds, interceptslope); + gdcmAssertMacro( b ); (void)b; + } + else if ( + ms == MediaStorage::RTDoseStorage + ) + { + Attribute<0x3004,0x000e> gridscaling = { 0 }; + gridscaling.SetFromDataSet( ds ); + interceptslope[0] = 0; + interceptslope[1] = gridscaling.GetValue(); + if( interceptslope[1] == 0 ) + { + // come' on ! WTF + gdcmWarningMacro( "Cannot have slope == 0. Defaulting to 1.0 instead" ); + interceptslope[1] = 1; + } + } + + // \post condition slope can never be 0: + assert( interceptslope[1] != 0. ); + return interceptslope; +} + +Tag ImageHelper::GetSpacingTagFromMediaStorage(MediaStorage const &ms) +{ + Tag t; + + // gdcmData/MR00010001.dcm => GeneralElectricMagneticResonanceImageStorage + // (0018,0088) DS [] # 4, 1 SpacingBetweenSlices + // (0028,0030) DS [ 0.8593750000\0.8593750000] # 26, 2 PixelSpacing + switch(ms) + { + case MediaStorage::EnhancedUSVolumeStorage: + // Enhanced stuff are handled elsewere... look carefully :) + //case MediaStorage::EnhancedMRImageStorage: + //case MediaStorage::EnhancedCTImageStorage: + // gdcmWarningMacro( "Enhanced image are not currently supported. Spacing will be wrong" ); + case MediaStorage::CTImageStorage: + case MediaStorage::MRImageStorage: + case MediaStorage::RTDoseStorage: + case MediaStorage::NuclearMedicineImageStorage: + case MediaStorage::PETImageStorage: + case MediaStorage::GeneralElectricMagneticResonanceImageStorage: + case MediaStorage::PhilipsPrivateMRSyntheticImageStorage: + case MediaStorage::VLPhotographicImageStorage: // VL Image IOD + case MediaStorage::VLMicroscopicImageStorage: + // (0028,0030) DS [2.0\2.0] # 8, 2 PixelSpacing + t = Tag(0x0028,0x0030); + break; + case MediaStorage::ComputedRadiographyImageStorage: // See pixelspacingtestimages/DISCIMG/IMAGES/CRIMAGE + case MediaStorage::DigitalXRayImageStorageForPresentation: + case MediaStorage::DigitalXRayImageStorageForProcessing: + case MediaStorage::DigitalMammographyImageStorageForPresentation: + case MediaStorage::DigitalMammographyImageStorageForProcessing: + case MediaStorage::DigitalIntraoralXrayImageStorageForPresentation: + case MediaStorage::DigitalIntraoralXRayImageStorageForProcessing: + case MediaStorage::XRayAngiographicImageStorage: + case MediaStorage::XRayRadiofluoroscopingImageStorage: + case MediaStorage::XRayAngiographicBiPlaneImageStorageRetired: + // (0018,1164) DS [0.5\0.5] # 8, 2 ImagerPixelSpacing + t = Tag(0x0018,0x1164); + break; + case MediaStorage::RTImageStorage: // gdcmData/SYNGORTImage.dcm + t = Tag(0x3002,0x0011); // ImagePlanePixelSpacing + break; + case MediaStorage::SecondaryCaptureImageStorage: + case MediaStorage::MultiframeSingleBitSecondaryCaptureImageStorage: + case MediaStorage::MultiframeGrayscaleByteSecondaryCaptureImageStorage: + case MediaStorage::MultiframeGrayscaleWordSecondaryCaptureImageStorage: + case MediaStorage::MultiframeTrueColorSecondaryCaptureImageStorage: + // See PS 3.3-2008. Table C.8-25 SC IMAGE MODULE ATTRIBUTES + // and Table C.8-25b SC MULTI-FRAME IMAGE MODULE ATTRIBUTES + t = Tag(0x0018,0x2010); + break; + case MediaStorage::HardcopyGrayscaleImageStorage: + t = Tag(0xffff,0xffff); + break; + case MediaStorage::GEPrivate3DModelStorage: // FIXME FIXME !!! + case MediaStorage::Philips3D: + case MediaStorage::VideoEndoscopicImageStorage: + gdcmWarningMacro( "FIXME" ); + t = Tag(0xffff,0xffff); + break; + case MediaStorage::UltrasoundMultiFrameImageStorage: + // gdcmData/US-MONO2-8-8x-execho.dcm + // this should be handled somewhere else + //assert(0); + gdcmWarningMacro( "FIXME" ); + t = Tag(0xffff,0xffff); + break; + case MediaStorage::UltrasoundImageStorage: // ?? + case MediaStorage::UltrasoundImageStorageRetired: + case MediaStorage::UltrasoundMultiFrameImageStorageRetired: + // (0028,0034) IS [4\3] # 4, 2 PixelAspectRatio + t = Tag(0xffff,0xffff); // FIXME + t = Tag(0x0028,0x0034); // FIXME + break; + default: + gdcmDebugMacro( "Do not handle: " << ms ); + t = Tag(0xffff,0xffff); + break; + } + + // should only override unless Modality set it already + // basically only Secondary Capture should reach that point + if( ForcePixelSpacing && t == Tag(0xffff,0xffff) ) + { + t = Tag(0x0028,0x0030); + } + + return t; +} + +Tag ImageHelper::GetZSpacingTagFromMediaStorage(MediaStorage const &ms) +{ + Tag t; + + switch(ms) + { + case MediaStorage::EnhancedUSVolumeStorage: + case MediaStorage::MRImageStorage: + case MediaStorage::NuclearMedicineImageStorage: // gdcmData/Nm.dcm + case MediaStorage::GeneralElectricMagneticResonanceImageStorage: + // (0018,0088) DS [3] # 2, 1 SpacingBetweenSlices + t = Tag(0x0018,0x0088); + break; + // No spacing AFAIK for those: +/* +$ dciodvfy gdcmData/D_CLUNIE_CT1_JPLL.dcm +CTImage +Warning - Attribute is not present in standard DICOM IOD - (0x0018,0x0088) DS Spacing Between Slices +Warning - Dicom dataset contains attributes not present in standard DICOM IOD - this is a Standard Extended SOP Class +*/ + case MediaStorage::PETImageStorage: // ?? + case MediaStorage::CTImageStorage: + case MediaStorage::RTImageStorage: + // ImagerPixelSpacing section: + case MediaStorage::ComputedRadiographyImageStorage: // ?? + case MediaStorage::DigitalXRayImageStorageForPresentation: + case MediaStorage::DigitalXRayImageStorageForProcessing: + case MediaStorage::DigitalMammographyImageStorageForPresentation: + case MediaStorage::DigitalMammographyImageStorageForProcessing: + case MediaStorage::DigitalIntraoralXrayImageStorageForPresentation: + case MediaStorage::DigitalIntraoralXRayImageStorageForProcessing: + case MediaStorage::XRayAngiographicImageStorage: + case MediaStorage::XRayRadiofluoroscopingImageStorage: + case MediaStorage::XRayAngiographicBiPlaneImageStorageRetired: + // US: + case MediaStorage::UltrasoundImageStorage: + case MediaStorage::UltrasoundMultiFrameImageStorage: + case MediaStorage::UltrasoundImageStorageRetired: + case MediaStorage::UltrasoundMultiFrameImageStorageRetired: + // SC: + case MediaStorage::SecondaryCaptureImageStorage: + case MediaStorage::MultiframeGrayscaleByteSecondaryCaptureImageStorage: + case MediaStorage::MultiframeGrayscaleWordSecondaryCaptureImageStorage: + case MediaStorage::HardcopyGrayscaleImageStorage: + t = Tag(0xffff,0xffff); + break; + case MediaStorage::RTDoseStorage: // gdcmData/BogugsItemAndSequenceLengthCorrected.dcm + t = Tag(0x3004,0x000c); + break; + case MediaStorage::GEPrivate3DModelStorage: + case MediaStorage::Philips3D: + case MediaStorage::VideoEndoscopicImageStorage: + gdcmWarningMacro( "FIXME" ); + t = Tag(0xffff,0xffff); + break; + default: + gdcmDebugMacro( "Do not handle Z spacing for: " << ms ); + t = Tag(0xffff,0xffff); + break; + } + + if( ForcePixelSpacing && t == Tag(0xffff,0xffff) ) + { + t = Tag(0x0018,0x0088); + } + return t; +} + +std::vector ImageHelper::GetSpacingValue(File const & f) +{ + std::vector sp; + sp.reserve(3); + MediaStorage ms; + ms.SetFromFile(f); + const DataSet& ds = f.GetDataSet(); + + if( ms == MediaStorage::EnhancedCTImageStorage + || ms == MediaStorage::EnhancedMRImageStorage + || ms == MediaStorage::OphthalmicTomographyImageStorage + || ms == MediaStorage::SegmentationStorage ) + { + // + const Tag t1(0x5200,0x9229); + const Tag t2(0x5200,0x9230); + if( GetSpacingValueFromSequence(ds,t1, sp) + || GetSpacingValueFromSequence(ds, t2, sp) ) + { + assert( sp.size() == 3 ); + return sp; + } + // Else. + // How do I send an error ? + sp.resize( 3 ); // FIXME !! + sp[2] = 1.; + gdcmWarningMacro( "Could not find Spacing" ); + return sp; + } + else if( ms == MediaStorage::UltrasoundMultiFrameImageStorage ) + { + if( GetUltraSoundSpacingValueFromSequence(ds, sp) ) + { + // 3rd dimension is too difficult to handle for now... + // (0018,1065) DS [0\ 957\ 990\ 990\1023\1023\ 990\ 990\1023\ 957\1023\1023\1023\ 990... # 562,113 FrameTimeVector + sp.push_back( 1.0 ); + return sp; + } + else + { + // TODO this one is easy: + // (0028,0009) AT (0018,1063) # 4, 1 FrameIncrementPointer + // -> (0018,1063) DS [76.000000] # 10, 1 FrameTime + + gdcmWarningMacro( "No spacing value found" ); + sp.push_back( 1.0 ); + sp.push_back( 1.0 ); + sp.push_back( 1.0 ); + return sp; + } + } + + Tag spacingtag = GetSpacingTagFromMediaStorage(ms); + if( spacingtag != Tag(0xffff,0xffff) && ds.FindDataElement( spacingtag ) && !ds.GetDataElement( spacingtag ).IsEmpty() ) + { + const DataElement& de = ds.GetDataElement( spacingtag ); + const Global &g = GlobalInstance; + const Dicts &dicts = g.GetDicts(); + const DictEntry &entry = dicts.GetDictEntry(de.GetTag()); + const VR & vr = entry.GetVR(); + assert( vr.Compatible( de.GetVR() ) ); + switch(vr) + { + case VR::DS: + { + Element el; + std::stringstream ss; + const ByteValue *bv = de.GetByteValue(); + assert( bv ); + std::string s = std::string( bv->GetPointer(), bv->GetLength() ); + ss.str( s ); + // Stupid file: CT-MONO2-8-abdo.dcm + // The spacing is something like that: [0.2\0\0.200000] + // I would need to throw an expection that VM is not compatible + el.SetLength( entry.GetVM().GetLength() * entry.GetVR().GetSizeof() ); + std::string::size_type found = s.find('\\'); + if( found != std::string::npos ) + { + el.Read( ss ); + assert( el.GetLength() == 2 ); + for(unsigned int i = 0; i < el.GetLength(); ++i) + { + if( el.GetValue(i) ) + { + sp.push_back( el.GetValue(i) ); + } + else + { + gdcmWarningMacro( "Cant have a spacing of 0" ); + sp.push_back( 1.0 ); + } + } + std::swap( sp[0], sp[1]); + } + else + { + double singleval; + ss >> singleval; + if( singleval == 0.0 ) + { + singleval = 1.0; + } + sp.push_back( singleval ); + sp.push_back( singleval ); + } + assert( sp.size() == (unsigned int)entry.GetVM() ); + } + break; + case VR::IS: + { + Element el; + std::stringstream ss; + const ByteValue *bv = de.GetByteValue(); + assert( bv ); + std::string s = std::string( bv->GetPointer(), bv->GetLength() ); + ss.str( s ); + el.SetLength( entry.GetVM().GetLength() * entry.GetVR().GetSizeof() ); + el.Read( ss ); + for(unsigned int i = 0; i < el.GetLength(); ++i) + sp.push_back( el.GetValue(i) ); + assert( sp.size() == (unsigned int)entry.GetVM() ); + } + break; + default: + assert(0); + break; + } + } + else + { + sp.push_back( 1.0 ); + sp.push_back( 1.0 ); + } + assert( sp.size() == 2 ); + // Make sure multiframe: + std::vector dims = ImageHelper::GetDimensionsValue( f ); + + // Do Z: + Tag zspacingtag = ImageHelper::GetZSpacingTagFromMediaStorage(ms); + if( zspacingtag != Tag(0xffff,0xffff) && ds.FindDataElement( zspacingtag ) ) + { + const DataElement& de = ds.GetDataElement( zspacingtag ); + if( de.IsEmpty() ) + { + sp.push_back( 1.0 ); + } + else + { + const Global &g = GlobalInstance; + const Dicts &dicts = g.GetDicts(); + const DictEntry &entry = dicts.GetDictEntry(de.GetTag()); + const VR & vr = entry.GetVR(); + assert( de.GetVR() == vr || de.GetVR() == VR::INVALID || de.GetVR() == VR::UN ); + if( entry.GetVM() == VM::VM1 ) + { + switch(vr) + { + case VR::DS: + { + Element el; + std::stringstream ss; + const ByteValue *bv = de.GetByteValue(); + assert( bv ); + std::string s = std::string( bv->GetPointer(), bv->GetLength() ); + ss.str( s ); + el.SetLength( entry.GetVM().GetLength() * entry.GetVR().GetSizeof() ); + el.Read( ss ); + for(unsigned int i = 0; i < el.GetLength(); ++i) + { + const double value = el.GetValue(i); + sp.push_back( value ); + } + //assert( sp.size() == entry.GetVM() ); + } + break; + default: + assert(0); + break; + } + } + else + { + assert( entry.GetVM() == VM::VM2_n ); + assert( vr == VR::DS ); + Attribute<0x28,0x8> numberoframes; + const DataElement& de1 = ds.GetDataElement( numberoframes.GetTag() ); + numberoframes.SetFromDataElement( de1 ); + Attribute<0x3004,0x000c> gridframeoffsetvector; + const DataElement& de2 = ds.GetDataElement( gridframeoffsetvector.GetTag() ); + gridframeoffsetvector.SetFromDataElement( de2 ); + double v1 = gridframeoffsetvector[0]; + double v2 = gridframeoffsetvector[1]; + // FIXME. I should check consistency + sp.push_back( v2 - v1 ); + } + } + } + else if( ds.FindDataElement( Tag(0x0028,0x0009) ) ) // Frame Increment Pointer + { + const DataElement& de = ds.GetDataElement( Tag(0x0028,0x0009) ); + gdcm::Attribute<0x0028,0x0009,VR::AT,VM::VM1> at; + at.SetFromDataElement( de ); + assert( ds.FindDataElement( at.GetTag() ) ); + if( ds.FindDataElement( at.GetValue() ) ) + { +/* +$ dcmdump D_CLUNIE_NM1_JPLL.dcm" | grep 0028,0009 +(0028,0009) AT (0054,0010)\(0054,0020) # 8, 2 FrameIncrementPointer +*/ + const DataElement& de2 = ds.GetDataElement( at.GetValue() ); + if( at.GetValue() == Tag(0x0018,0x1063) && at.GetNumberOfValues() == 1 ) + { + Attribute<0x0018,0x1063> at2; + at2.SetFromDataElement( de2 ); + if( dims[2] > 1 ) + { + sp.push_back( at2.GetValue() ); + } + else + { + if( at2.GetValue() != 0. ) + { + gdcmErrorMacro( "Number of Frame should be equal to 0" ); + sp.push_back( 0.0 ); + } + else + { + sp.push_back( 1.0 ); + } + } + } + else + { + gdcmWarningMacro( "Dont know how to handle spacing for: " << de ); + sp.push_back( 1.0 ); + } + } + else + { + gdcmErrorMacro( "Tag: " << at.GetTag() << " was found to point to missing" + "Tag: " << at.GetValue() << " default to 1.0." ); + sp.push_back( 1.0 ); + } + } + else + { + sp.push_back( 1.0 ); + } + + assert( sp.size() == 3 ); + assert( sp[0] != 0. ); + assert( sp[1] != 0. ); + //if( ms != MediaStorage::MRImageStorage ) + // assert( sp[2] != 0. ); + return sp; +} + +void ImageHelper::SetSpacingValue(DataSet & ds, const std::vector & spacing) +{ + MediaStorage ms; + ms.SetFromDataSet(ds); + assert( MediaStorage::IsImage( ms ) ); + if( ms == MediaStorage::SecondaryCaptureImageStorage ) + { + Tag pixelspacing(0x0028,0x0030); + Tag imagerpixelspacing(0x0018,0x1164); + Tag spacingbetweenslice(0x0018,0x0088); + //ds.Remove( pixelspacing ); + //ds.Remove( imagerpixelspacing ); + //ds.Remove( spacingbetweenslice ); + //return; + } + assert( spacing.size() == 3 ); + + if( ms == MediaStorage::EnhancedCTImageStorage + || ms == MediaStorage::EnhancedMRImageStorage + || ms == MediaStorage::SegmentationStorage ) + { +/* + (0028,9110) SQ (Sequence with undefined length #=1) # u/l, 1 PixelMeasuresSequence + (fffe,e000) na (Item with undefined length #=2) # u/l, 1 Item + (0018,0050) DS [5.00000] # 8, 1 SliceThickness + (0028,0030) DS [0.820312\0.820312] # 18, 2 PixelSpacing + (fffe,e00d) na (ItemDelimitationItem) # 0, 0 ItemDelimitationItem + (fffe,e0dd) na (SequenceDelimitationItem) # 0, 0 SequenceDelimitationItem +*/ + const Tag tfgs(0x5200,0x9229); + SmartPointer sqi; + if( !ds.FindDataElement( tfgs ) ) + { + sqi = new SequenceOfItems; + DataElement de( tfgs ); + de.SetVR( VR::SQ ); + de.SetValue( *sqi ); + de.SetVLToUndefined(); + ds.Insert( de ); + } + //sqi = (SequenceOfItems*)ds.GetDataElement( tfgs ).GetSequenceOfItems(); + sqi = ds.GetDataElement( tfgs ).GetValueAsSQ(); + sqi->SetLengthToUndefined(); + + if( !sqi->GetNumberOfItems() ) + { + Item item; //( Tag(0xfffe,0xe000) ); + item.SetVLToUndefined(); + sqi->AddItem( item ); + } + Item &item1 = sqi->GetItem(1); + DataSet &subds = item1.GetNestedDataSet(); + const Tag tpms(0x0028,0x9110); + if( !subds.FindDataElement( tpms ) ) + { + SequenceOfItems *sqi2 = new SequenceOfItems; + DataElement de( tpms ); + de.SetVR( VR::SQ ); + de.SetValue( *sqi2 ); + de.SetVLToUndefined(); + subds.Insert( de ); + } + + //sqi = (SequenceOfItems*)subds.GetDataElement( tpms ).GetSequenceOfItems(); + sqi = subds.GetDataElement( tpms ).GetValueAsSQ(); + sqi->SetLengthToUndefined(); + + if( !sqi->GetNumberOfItems() ) + { + Item item; //( Tag(0xfffe,0xe000) ); + item.SetVLToUndefined(); + sqi->AddItem( item ); + } + Item &item2 = sqi->GetItem(1); + DataSet &subds2 = item2.GetNestedDataSet(); + + // + //Attribute<0x0018,0x0050> at2; + //at2.SetValue( spacing[2] ); + Attribute<0x0028,0x0030> at1; + at1.SetValue( spacing[1], 0 ); + at1.SetValue( spacing[0], 1 ); + subds2.Replace( at1.GetAsDataElement() ); + //subds2.Replace( at2.GetAsDataElement() ); + + return; + } + + + Tag spacingtag = GetSpacingTagFromMediaStorage(ms); + Tag zspacingtag = GetZSpacingTagFromMediaStorage(ms); + //std::vector spacingtags; + //spacingtags.push_back( spacingtag ); + //spacingtags.push_back( zspacingtag ); + { + const Tag ¤tspacing = spacingtag; + if( currentspacing != Tag(0xffff,0xffff) ) + { + DataElement de( currentspacing ); + const Global &g = GlobalInstance; + const Dicts &dicts = g.GetDicts(); + const DictEntry &entry = dicts.GetDictEntry(de.GetTag()); + const VR & vr = entry.GetVR(); + const VM & vm = entry.GetVM(); (void)vm; + assert( de.GetVR() == vr || de.GetVR() == VR::INVALID ); + switch(vr) + { + case VR::DS: + { + Element el; + el.SetLength( entry.GetVM().GetLength() * vr.GetSizeof() ); + assert( entry.GetVM() == VM::VM2 ); + for( unsigned int i = 0; i < entry.GetVM().GetLength(); ++i) + { + el.SetValue( spacing[i], i ); + } + el.SetValue( spacing[1], 0 ); + el.SetValue( spacing[0], 1 ); + //assert( el.GetValue(0) == spacing[0] && el.GetValue(1) == spacing[1] ); + std::stringstream os; + el.Write( os ); + de.SetVR( VR::DS ); + if( os.str().size() % 2 ) os << " "; + VL::Type osStrSize = (VL::Type)os.str().size(); + de.SetByteValue( os.str().c_str(),osStrSize ); + ds.Replace( de ); + } + break; + case VR::IS: + { + Element el; + el.SetLength( entry.GetVM().GetLength() * vr.GetSizeof() ); + assert( entry.GetVM() == VM::VM2 ); + for( unsigned int i = 0; i < entry.GetVM().GetLength(); ++i) + { + el.SetValue( (int)spacing[i], i ); + } + //assert( el.GetValue(0) == spacing[0] && el.GetValue(1) == spacing[1] ); + std::stringstream os; + el.Write( os ); + de.SetVR( VR::IS ); + if( os.str().size() % 2 ) os << " "; + VL::Type osStrSize = (VL::Type)os.str().size(); + de.SetByteValue( os.str().c_str(), osStrSize ); + ds.Replace( de ); + } + break; + default: + assert(0); + } + } + } + { + const Tag ¤tspacing = zspacingtag; + if( currentspacing != Tag(0xffff,0xffff) ) + { + DataElement de( currentspacing ); + const Global &g = GlobalInstance; + const Dicts &dicts = g.GetDicts(); + const DictEntry &entry = dicts.GetDictEntry(de.GetTag()); + const VR & vr = entry.GetVR(); + const VM & vm = entry.GetVM(); (void)vm; + assert( de.GetVR() == vr || de.GetVR() == VR::INVALID ); + if( entry.GetVM() == VM::VM2_n ) + { + assert( vr == VR::DS ); + assert( de.GetTag() == Tag(0x3004,0x000c) ); + Attribute<0x28,0x8> numberoframes; + // Make we are multiframes: + if( ds.FindDataElement( numberoframes.GetTag() ) ) + { + const DataElement& de1 = ds.GetDataElement( numberoframes.GetTag() ); + numberoframes.SetFromDataElement( de1 ); + + Element el; + el.SetLength( numberoframes.GetValue() * vr.GetSizeof() ); + assert( entry.GetVM() == VM::VM2_n ); + double spacing_start = 0; + assert( 0 < numberoframes.GetValue() ); + for( int i = 0; i < numberoframes.GetValue(); ++i) + { + el.SetValue( spacing_start, i ); + spacing_start += spacing[2]; + } + //assert( el.GetValue(0) == spacing[0] && el.GetValue(1) == spacing[1] ); + std::stringstream os; + el.Write( os ); + de.SetVR( VR::DS ); + if( os.str().size() % 2 ) os << " "; + VL::Type osStrSize = (VL::Type)os.str().size(); + de.SetByteValue( os.str().c_str(), osStrSize ); + ds.Replace( de ); + } + } + else + { + switch(vr) + { + case VR::DS: + { + Element el; + el.SetLength( entry.GetVM().GetLength() * vr.GetSizeof() ); + assert( entry.GetVM() == VM::VM1 ); + for( unsigned int i = 0; i < entry.GetVM().GetLength(); ++i) + { + el.SetValue( spacing[i+2], i ); + } + //assert( el.GetValue(0) == spacing[0] && el.GetValue(1) == spacing[1] ); + std::stringstream os; + el.Write( os ); + de.SetVR( VR::DS ); + if( os.str().size() % 2 ) os << " "; + VL::Type osStrSize = (VL::Type)os.str().size(); + de.SetByteValue( os.str().c_str(), osStrSize ); + ds.Replace( de ); + } + break; + default: + assert(0); + } + } + } + } + +} + +void SetDataElementInSQAsItemNumber(DataSet & ds, DataElement const & de, Tag const & sqtag, unsigned int itemidx) +{ + const Tag tfgs = sqtag; //(0x5200,0x9230); + SmartPointer sqi; + if( !ds.FindDataElement( tfgs ) ) + { + sqi = new SequenceOfItems; + DataElement detmp( tfgs ); + detmp.SetVR( VR::SQ ); + detmp.SetValue( *sqi ); + detmp.SetVLToUndefined(); + ds.Insert( detmp ); + } + //sqi = (SequenceOfItems*)ds.GetDataElement( tfgs ).GetSequenceOfItems(); + sqi = ds.GetDataElement( tfgs ).GetValueAsSQ(); + sqi->SetLengthToUndefined(); + + if( sqi->GetNumberOfItems() < itemidx ) + { + Item item; //( Tag(0xfffe,0xe000) ); + item.SetVLToUndefined(); + sqi->AddItem( item ); + } + Item &item1 = sqi->GetItem(itemidx); + DataSet &subds = item1.GetNestedDataSet(); + const Tag tpms(0x0020,0x9113); + if( !subds.FindDataElement( tpms ) ) + { + SequenceOfItems *sqi2 = new SequenceOfItems; + DataElement detmp( tpms ); + detmp.SetVR( VR::SQ ); + detmp.SetValue( *sqi2 ); + detmp.SetVLToUndefined(); + subds.Insert( detmp ); + } + + //sqi = (SequenceOfItems*)subds.GetDataElement( tpms ).GetSequenceOfItems(); + sqi = subds.GetDataElement( tpms ).GetValueAsSQ(); + sqi->SetLengthToUndefined(); + + if( !sqi->GetNumberOfItems() ) + { + Item item; //( Tag(0xfffe,0xe000) ); + item.SetVLToUndefined(); + sqi->AddItem( item ); + } + Item &item2 = sqi->GetItem(1); + DataSet &subds2 = item2.GetNestedDataSet(); + + //gdcm::Attribute<0x0020,0x0032> ipp = {{0,0,0}}; // default value + //ipp.SetValue( origin[0], 0); + //ipp.SetValue( origin[1], 1); + //ipp.SetValue( origin[2], 2); + + subds2.Replace( de ); +} + +void ImageHelper::SetOriginValue(DataSet & ds, const Image & image) +{ + const double *origin = image.GetOrigin(); + //assert( origin.size() == 3 ); + MediaStorage ms; + ms.SetFromDataSet(ds); + assert( MediaStorage::IsImage( ms ) ); + + if( ms == MediaStorage::SecondaryCaptureImageStorage ) + { + Tag ipp(0x0020,0x0032); + ds.Remove( ipp ); + } + + // FIXME Hardcoded + if( ms != MediaStorage::CTImageStorage + && ms != MediaStorage::MRImageStorage + && ms != MediaStorage::RTDoseStorage + //&& ms != MediaStorage::ComputedRadiographyImageStorage + && ms != MediaStorage::SegmentationStorage + && ms != MediaStorage::EnhancedMRImageStorage + && ms != MediaStorage::EnhancedCTImageStorage ) + { + // FIXME: should I remove the ipp tag ??? + return; + } + + if( ms == MediaStorage::EnhancedCTImageStorage + || ms == MediaStorage::EnhancedMRImageStorage + || ms == MediaStorage::SegmentationStorage ) + { +/* + (0020,9113) SQ (Sequence with undefined length #=1) # u/l, 1 PlanePositionSequence + (fffe,e000) na (Item with undefined length #=1) # u/l, 1 Item + (0020,0032) DS [40.0000\-105.000\105.000] # 24, 3 ImagePositionPatient + (fffe,e00d) na (ItemDelimitationItem) # 0, 0 ItemDelimitationItem + (fffe,e0dd) na (SequenceDelimitationItem) # 0, 0 SequenceDelimitationItem +*/ + + const Tag tfgs(0x5200,0x9230); + + gdcm::Attribute<0x0020,0x0032> ipp = {{0,0,0}}; // default value + double zspacing = image.GetSpacing(2); + unsigned int dimz = image.GetDimension(2); + const double *cosines = image.GetDirectionCosines(); + DirectionCosines dc( cosines ); + + double normal[3]; + dc.Cross( normal ); + + for(unsigned int i = 0; i < dimz; ++i ) + { + double new_origin[3]; + for (int j = 0; j < 3; j++) + { + // the n'th slice is n * z-spacing aloung the IOP-derived + // z-axis + new_origin[j] = origin[j] + normal[j] * i * zspacing; + } + + ipp.SetValue( new_origin[0], 0); + ipp.SetValue( new_origin[1], 1); + ipp.SetValue( new_origin[2], 2); + SetDataElementInSQAsItemNumber(ds, ipp.GetAsDataElement(), tfgs, i+1); + } + + return; + } + + // Image Position (Patient) + gdcm::Attribute<0x0020,0x0032> ipp = {{0,0,0}}; // default value + ipp.SetValue( origin[0], 0); + ipp.SetValue( origin[1], 1); + ipp.SetValue( origin[2], 2); + + ds.Replace( ipp.GetAsDataElement() ); +} + +void ImageHelper::SetDirectionCosinesValue(DataSet & ds, const std::vector & dircos) +{ + MediaStorage ms; + ms.SetFromDataSet(ds); + assert( MediaStorage::IsImage( ms ) ); + + if( ms == MediaStorage::SecondaryCaptureImageStorage ) + { + Tag iop(0x0020,0x0037); + ds.Remove( iop ); + return; + } + + // FIXME Hardcoded + if( ms != MediaStorage::CTImageStorage + && ms != MediaStorage::MRImageStorage + && ms != MediaStorage::RTDoseStorage + //&& ms != MediaStorage::ComputedRadiographyImageStorage + && ms != MediaStorage::SegmentationStorage + && ms != MediaStorage::EnhancedMRImageStorage + && ms != MediaStorage::EnhancedCTImageStorage ) + { + // FIXME: should I remove the iop tag ??? + return; + } + + // Image Orientation (Patient) + gdcm::Attribute<0x0020,0x0037> iop = {{1,0,0,0,1,0}}; // default value + + assert( dircos.size() == 6 ); + DirectionCosines dc( &dircos[0] ); + if( !dc.IsValid() ) + { + gdcmWarningMacro( "Direction Cosines are not valid. Using default value (1\\0\\0\\0\\1\\0)" ); + } + else + { + iop.SetValue( dircos[0], 0); + iop.SetValue( dircos[1], 1); + iop.SetValue( dircos[2], 2); + iop.SetValue( dircos[3], 3); + iop.SetValue( dircos[4], 4); + iop.SetValue( dircos[5], 5); + } + + if( ms == MediaStorage::EnhancedCTImageStorage + || ms == MediaStorage::EnhancedMRImageStorage + || ms == MediaStorage::SegmentationStorage ) + { +/* + (0020,9116) SQ (Sequence with undefined length #=1) # u/l, 1 PlaneOrientationSequence + (fffe,e000) na (Item with undefined length #=1) # u/l, 1 Item + (0020,0037) DS [0.00000\1.00000\0.00000\0.00000\0.00000\-1.00000] # 48, 6 ImageOrientationPatient + (fffe,e00d) na (ItemDelimitationItem) # 0, 0 ItemDelimitationItem + (fffe,e0dd) na (SequenceDelimitationItem) # 0, 0 SequenceDelimitationItem +*/ + const Tag tfgs(0x5200,0x9229); + SmartPointer sqi; + if( !ds.FindDataElement( tfgs ) ) + { + sqi = new SequenceOfItems; + DataElement de( tfgs ); + de.SetVR( VR::SQ ); + de.SetValue( *sqi ); + de.SetVLToUndefined(); + ds.Insert( de ); + } + //sqi = (SequenceOfItems*)ds.GetDataElement( tfgs ).GetSequenceOfItems(); + sqi = ds.GetDataElement( tfgs ).GetValueAsSQ(); + sqi->SetLengthToUndefined(); + + if( !sqi->GetNumberOfItems() ) + { + Item item; //( Tag(0xfffe,0xe000) ); + item.SetVLToUndefined(); + sqi->AddItem( item ); + } + Item &item1 = sqi->GetItem(1); + DataSet &subds = item1.GetNestedDataSet(); + const Tag tpms(0x0020,0x9116); + if( !subds.FindDataElement( tpms ) ) + { + SequenceOfItems *sqi2 = new SequenceOfItems; + DataElement de( tpms ); + de.SetVR( VR::SQ ); + de.SetValue( *sqi2 ); + de.SetVLToUndefined(); + subds.Insert( de ); + } + + //sqi = (SequenceOfItems*)subds.GetDataElement( tpms ).GetSequenceOfItems(); + sqi = subds.GetDataElement( tpms ).GetValueAsSQ(); + sqi->SetLengthToUndefined(); + + if( !sqi->GetNumberOfItems() ) + { + Item item; //( Tag(0xfffe,0xe000) ); + item.SetVLToUndefined(); + sqi->AddItem( item ); + } + Item &item2 = sqi->GetItem(1); + DataSet &subds2 = item2.GetNestedDataSet(); + + subds2.Replace( iop.GetAsDataElement() ); + return; + } + + ds.Replace( iop.GetAsDataElement() ); +} + +void ImageHelper::SetRescaleInterceptSlopeValue(File & f, const Image & img) +{ + MediaStorage ms; + // SetFromFile is required here, SetFromDataSet is not enough for all cases + ms.SetFromFile(f); + assert( MediaStorage::IsImage( ms ) ); + DataSet &ds = f.GetDataSet(); + + // FIXME Hardcoded + if( ms != MediaStorage::CTImageStorage + && ms != MediaStorage::ComputedRadiographyImageStorage + && ms != MediaStorage::MRImageStorage // FIXME ! + && ms != MediaStorage::PETImageStorage + && ms != MediaStorage::RTDoseStorage + && ms != MediaStorage::SecondaryCaptureImageStorage + && ms != MediaStorage::MultiframeGrayscaleWordSecondaryCaptureImageStorage + && ms != MediaStorage::MultiframeGrayscaleByteSecondaryCaptureImageStorage + && ms != MediaStorage::EnhancedMRImageStorage + && ms != MediaStorage::EnhancedCTImageStorage + && ms != MediaStorage::SegmentationStorage ) + { + if( img.GetIntercept() != 0. || img.GetSlope() != 1. ) + { + throw "Impossible"; // Please report + } + return; + } + + if( ms == MediaStorage::SegmentationStorage ) return; // seg storage cannot have rescale slope + if( ms == MediaStorage::EnhancedCTImageStorage + || ms == MediaStorage::EnhancedMRImageStorage + ) + { +/* + (0020,9116) SQ (Sequence with undefined length #=1) # u/l, 1 PlaneOrientationSequence + (fffe,e000) na (Item with undefined length #=1) # u/l, 1 Item + (0020,0037) DS [0.00000\1.00000\0.00000\0.00000\0.00000\-1.00000] # 48, 6 ImageOrientationPatient + (fffe,e00d) na (ItemDelimitationItem) # 0, 0 ItemDelimitationItem + (fffe,e0dd) na (SequenceDelimitationItem) # 0, 0 SequenceDelimitationItem +*/ + const Tag tfgs(0x5200,0x9229); + SmartPointer sqi; + if( !ds.FindDataElement( tfgs ) ) + { + sqi = new SequenceOfItems; + DataElement de( tfgs ); + de.SetVR( VR::SQ ); + de.SetValue( *sqi ); + de.SetVLToUndefined(); + ds.Insert( de ); + } + //sqi = (SequenceOfItems*)ds.GetDataElement( tfgs ).GetSequenceOfItems(); + sqi = ds.GetDataElement( tfgs ).GetValueAsSQ(); + sqi->SetLengthToUndefined(); + + if( !sqi->GetNumberOfItems() ) + { + Item item; //( Tag(0xfffe,0xe000) ); + item.SetVLToUndefined(); + sqi->AddItem( item ); + } + Item &item1 = sqi->GetItem(1); + DataSet &subds = item1.GetNestedDataSet(); + const Tag tpms(0x0028,0x9145); + if( !subds.FindDataElement( tpms ) ) + { + SequenceOfItems *sqi2 = new SequenceOfItems; + DataElement de( tpms ); + de.SetVR( VR::SQ ); + de.SetValue( *sqi2 ); + de.SetVLToUndefined(); + subds.Insert( de ); + } + + //sqi = (SequenceOfItems*)subds.GetDataElement( tpms ).GetSequenceOfItems(); + sqi = subds.GetDataElement( tpms ).GetValueAsSQ(); + sqi->SetLengthToUndefined(); + + if( !sqi->GetNumberOfItems() ) + { + Item item; //( Tag(0xfffe,0xe000) ); + item.SetVLToUndefined(); + sqi->AddItem( item ); + } + Item &item2 = sqi->GetItem(1); + DataSet &subds2 = item2.GetNestedDataSet(); + + Attribute<0x0028,0x1052> at1; + at1.SetValue( img.GetIntercept() ); + subds2.Insert( at1.GetAsDataElement() ); + Attribute<0x0028,0x1053> at2; + at2.SetValue( img.GetSlope() ); + subds2.Insert( at2.GetAsDataElement() ); + + return; + } + + if( ms == MediaStorage::RTDoseStorage ) + { + Attribute<0x3004,0x00e> at2; + at2.SetValue( img.GetSlope() ); + ds.Replace( at2.GetAsDataElement() ); + + return; + } + + // Question: should I always insert them ? + // Answer: not always, let's discard MR if (1,0): + if( ms == MediaStorage::MRImageStorage && img.GetIntercept() == 0. && img.GetSlope() == 1. ) + { + } + else + { + Attribute<0x0028,0x1052> at1; + at1.SetValue( img.GetIntercept() ); + ds.Replace( at1.GetAsDataElement() ); + Attribute<0x0028,0x1053> at2; + at2.SetValue( img.GetSlope() ); + ds.Replace( at2.GetAsDataElement() ); + + Attribute<0x0028,0x1054> at3; // Rescale Type + at3.SetValue( "US" ); // FIXME + if( ms == MediaStorage::SecondaryCaptureImageStorage ) + { + // As per 3-2009, US is the only valid enumerated value: + ds.Replace( at3.GetAsDataElement() ); + } + else + { + // In case user decide to override the default: + ds.Insert( at3.GetAsDataElement() ); + } + } +} + +bool ImageHelper::ComputeSpacingFromImagePositionPatient(const std::vector & imageposition, std::vector & spacing) +{ + if( imageposition.size() % 3 != 0 ) + { + return false; + } + std::vector::const_iterator it = imageposition.begin(); + //const double x0 = *it++; + //const double y0 = *it++; + //const double z0 = *it++; + spacing[0] = spacing[1] = spacing[2] = 0.; + for( ; it != imageposition.end(); ++it) + { + const double x = *it++; + const double y = *it++; + const double z = *it; + spacing[0] += x; + spacing[1] += y; + spacing[2] += z; + } + size_t n = imageposition.size() / 3; + spacing[0] /= (double)n; + spacing[1] /= (double)n; + spacing[2] /= (double)n; + + return true; +} + + +//functions to get more information from a file +//useful for the stream image reader, which fills in necessary image information +//distinctly from the reader-style data input +//code is borrowed from gdcmPixmapReader::ReadImage(MediaStorage const &ms) +PhotometricInterpretation ImageHelper::GetPhotometricInterpretationValue(File const& f){ + // 5. Photometric Interpretation + // D 0028|0004 [CS] [Photometric Interpretation] [MONOCHROME2 ] + PixelFormat pf = GetPixelFormatValue(f); + const Tag tphotometricinterpretation(0x0028, 0x0004); + const ByteValue *photometricinterpretation = + ImageHelper::GetPointerFromElement(tphotometricinterpretation, f); + PhotometricInterpretation pi = PhotometricInterpretation::UNKNOW; + if( photometricinterpretation ) + { + std::string photometricinterpretation_str( + photometricinterpretation->GetPointer(), + photometricinterpretation->GetLength() ); + pi = PhotometricInterpretation::GetPIType( photometricinterpretation_str.c_str() ); + } + else + { + if( pf.GetSamplesPerPixel() == 1 ) + { + gdcmWarningMacro( "No PhotometricInterpretation found, default to MONOCHROME2" ); + pi = PhotometricInterpretation::MONOCHROME2; + } + else if( pf.GetSamplesPerPixel() == 3 ) + { + gdcmWarningMacro( "No PhotometricInterpretation found, default to RGB" ); + pi = PhotometricInterpretation::RGB; + } + else if( pf.GetSamplesPerPixel() == 4 ) + { + gdcmWarningMacro( "No PhotometricInterpretation found, default to RGB" ); + pi = PhotometricInterpretation::ARGB; + } + } + + bool isacrnema = false; + DataSet ds = f.GetDataSet(); + const Tag trecognitioncode(0x0008,0x0010); + if( ds.FindDataElement( trecognitioncode ) && !ds.GetDataElement( trecognitioncode ).IsEmpty() ) + { + // PHILIPS_Gyroscan-12-MONO2-Jpeg_Lossless.dcm + // PHILIPS_Gyroscan-12-Jpeg_Extended_Process_2_4.dcm + gdcmDebugMacro( "Mixture of ACR NEMA and DICOM file" ); + isacrnema = true; + } + if( !pf.GetSamplesPerPixel() || (pi.GetSamplesPerPixel() != pf.GetSamplesPerPixel()) ) + { + if( pi != PhotometricInterpretation::UNKNOW ) + { + pf.SetSamplesPerPixel( pi.GetSamplesPerPixel() ); + } + else if ( isacrnema ) + { + assert ( pf.GetSamplesPerPixel() == 0 ); + assert ( pi == PhotometricInterpretation::UNKNOW ); + pf.SetSamplesPerPixel( 1 ); + pi = PhotometricInterpretation::MONOCHROME2; + } + else + { + gdcmWarningMacro( "Cannot recognize image type. Does not looks like ACR-NEMA and is missing both Sample Per Pixel AND PhotometricInterpretation. Please report" ); + } + } + return pi; +} +//returns the configuration of colors in a plane, either RGB RGB RGB or RRR GGG BBB +//code is borrowed from gdcmPixmapReader::ReadImage(MediaStorage const &ms) +unsigned int ImageHelper::GetPlanarConfigurationValue(const File& f){ + // 4. Planar Configuration + // D 0028|0006 [US] [Planar Configuration] [1] + const Tag planarconfiguration = Tag(0x0028, 0x0006); + PixelFormat pf = GetPixelFormatValue(f); + unsigned int pc = 0; + // FIXME: Whatif planaconfiguration is send in a grayscale image... it would be empty... + // well hopefully :( + DataSet const & ds = f.GetDataSet(); + if( ds.FindDataElement( planarconfiguration ) && !ds.GetDataElement( planarconfiguration ).IsEmpty() ) + { + const DataElement& de = ds.GetDataElement( planarconfiguration ); + Attribute<0x0028,0x0006> at = { 0 }; + at.SetFromDataElement( de ); + + //unsigned int pc = ReadUSFromTag( planarconfiguration, ss, conversion ); + pc = at.GetValue(); + if( pc && pf.GetSamplesPerPixel() != 3 ) + { + gdcmDebugMacro( "Cannot have PlanarConfiguration=1, when Sample Per Pixel != 3" ); + pc = 0; + } + } + return pc; +} + + //returns the lookup table of an image file +SmartPointer ImageHelper::GetLUT(File const& f){ + + DataSet const & ds = f.GetDataSet(); + PixelFormat pf = GetPixelFormatValue(f); + PhotometricInterpretation pi = GetPhotometricInterpretationValue(f); + // Do the Palette Color: + // 1. Modality LUT Sequence + bool modlut = ds.FindDataElement(Tag(0x0028,0x3000) ); + if( modlut ) + { + gdcmWarningMacro( "Modality LUT (0028,3000) are not handled. Image will not be displayed properly" ); + } + // 2. LUTData (0028,3006) + // technically I do not need to warn about LUTData since either modality lut XOR VOI LUT need to + // be sent to require a LUT Data... + bool lutdata = ds.FindDataElement(Tag(0x0028,0x3006) ); + if( lutdata ) + { + gdcmWarningMacro( "LUT Data (0028,3006) are not handled. Image will not be displayed properly" ); + } + // 3. VOILUTSequence (0028,3010) + bool voilut = ds.FindDataElement(Tag(0x0028,0x3010) ); + if( voilut ) + { + gdcmWarningMacro( "VOI LUT (0028,3010) are not handled. Image will not be displayed properly" ); + } + // (0028,0120) US 32767 # 2, 1 PixelPaddingValue + bool pixelpaddingvalue = ds.FindDataElement(Tag(0x0028,0x0120)); + + // PS 3.3 - 2008 / C.7.5.1.1.2 Pixel Padding Value and Pixel Padding Range Limit + if(pixelpaddingvalue) + { + // Technically if Pixel Padding Value is 0 on MONOCHROME2 image, then appearance should be fine... + bool vizissue = true; + if( pf.GetPixelRepresentation() == 0 ) + { + Element ppv; + if( !ds.GetDataElement(Tag(0x0028,0x0120) ).IsEmpty() ) + { + ppv.SetFromDataElement( ds.GetDataElement(Tag(0x0028,0x0120)) ); //.GetValue() ); + if( pi == PhotometricInterpretation::MONOCHROME2 && ppv.GetValue() == 0 ) + { + vizissue = false; + } + } + } + else if( pf.GetPixelRepresentation() == 1 ) + { + gdcmDebugMacro( "TODO" ); + } + // test if there is any viz issue: + if( vizissue ) + { + gdcmDebugMacro( "Pixel Padding Value (0028,0120) is not handled. Image will not be displayed properly" ); + } + } + SmartPointer lut = new LookupTable; + const Tag testseglut(0x0028, (0x1221 + 0)); + if( ds.FindDataElement( testseglut ) ) + { + lut = new SegmentedPaletteColorLookupTable; + } + //SmartPointer lut = new SegmentedPaletteColorLookupTable; + lut->Allocate( pf.GetBitsAllocated() ); + + // for each red, green, blue: + for(int i=0; i<3; ++i) + { + // (0028,1101) US 0\0\16 + // (0028,1102) US 0\0\16 + // (0028,1103) US 0\0\16 + const Tag tdescriptor(0x0028, (uint16_t)(0x1101 + i)); + //const Tag tdescriptor(0x0028, 0x3002); + Element el_us3 = {{ 0, 0, 0}}; + // Now pass the byte array to a DICOMizer: + el_us3.SetFromDataElement( ds[tdescriptor] ); //.GetValue() ); + lut->InitializeLUT( LookupTable::LookupTableType(i), + el_us3[0], el_us3[1], el_us3[2] ); + + // (0028,1201) OW + // (0028,1202) OW + // (0028,1203) OW + const Tag tlut(0x0028, (uint16_t)(0x1201 + i)); + //const Tag tlut(0x0028, 0x3006); + + // Segmented LUT + // (0028,1221) OW + // (0028,1222) OW + // (0028,1223) OW + const Tag seglut(0x0028, (uint16_t)(0x1221 + i)); + if( ds.FindDataElement( tlut ) ) + { + const ByteValue *lut_raw = ds.GetDataElement( tlut ).GetByteValue(); + if( lut_raw ) + { + // LookupTableType::RED == 0 + lut->SetLUT( LookupTable::LookupTableType(i), + (unsigned char*)lut_raw->GetPointer(), lut_raw->GetLength() ); + //assert( pf.GetBitsAllocated() == el_us3.GetValue(2) ); + } + else + { + lut->Clear(); + } + + unsigned long check = + (el_us3.GetValue(0) ? el_us3.GetValue(0) : 65536) + * el_us3.GetValue(2) / 8; + assert( !lut->Initialized() || check == lut_raw->GetLength() ); (void)check; + } + else if( ds.FindDataElement( seglut ) ) + { + const ByteValue *lut_raw = ds.GetDataElement( seglut ).GetByteValue(); + if( lut_raw ) + { + lut->SetLUT( LookupTable::LookupTableType(i), + (unsigned char*)lut_raw->GetPointer(), lut_raw->GetLength() ); + //assert( pf.GetBitsAllocated() == el_us3.GetValue(2) ); + } + else + { + lut->Clear(); + } + + //unsigned long check = + // (el_us3.GetValue(0) ? el_us3.GetValue(0) : 65536) + // * el_us3.GetValue(2) / 8; + //assert( check == lut_raw->GetLength() ); (void)check; + } + else + { + assert(0); + } + } + if( ! lut->Initialized() ) { + gdcmDebugMacro("LUT was uninitialized!"); + } + return lut; +} + + +const ByteValue* ImageHelper::GetPointerFromElement(Tag const &tag, const File& inF) { + + const DataSet &ds = inF.GetDataSet(); + if( ds.FindDataElement( tag ) ) + { + const DataElement &de = ds.GetDataElement( tag ); + return de.GetByteValue(); + } + return 0; +} + +} diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmImageHelper.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmImageHelper.h new file mode 100644 index 0000000..467aad8 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmImageHelper.h @@ -0,0 +1,133 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMIMAGEHELPER_H +#define GDCMIMAGEHELPER_H + +#include "gdcmTypes.h" +#include "gdcmTag.h" +#include +#include "gdcmPixelFormat.h" +#include "gdcmPhotometricInterpretation.h" +#include "gdcmSmartPointer.h" +#include "gdcmLookupTable.h" + +namespace gdcm +{ + +class MediaStorage; +class DataSet; +class File; +class Image; +class ByteValue; +/** + * \brief ImageHelper (internal class, not intended for user level) + * + * \details + * Helper for writing World images in DICOM. DICOM has a 'template' approach to image where + * MR Image Storage are distinct object from Enhanced MR Image Storage. For example the + * Pixel Spacing in one object is not at the same position (ie Tag) as in the other + * this class is the central (read: fragile) place where all the dispatching is done from + * a unified view of a world image (typically VTK or ITK point of view) down to the low + * level DICOM point of view. + * + * \warning: do not expect the API of this class to be maintained at any point, since as + * Modalities are added the API might have to be augmented or behavior changed to cope + * with new modalities. + */ +class GDCM_EXPORT ImageHelper +{ +public: + /// GDCM 1.x compatibility issue: + /// when using ReWrite an MR Image Storage would be rewritten with a Rescale Slope/Intercept + /// while the standard would prohibit this (Philips Medical System is still doing that) + /// Unless explicitely set elsewhere by the standard, it will use value from 0028,1052 / 0028,1053 + /// for the Rescale Slope & Rescale Intercept values + static void SetForceRescaleInterceptSlope(bool); + static bool GetForceRescaleInterceptSlope(); + + /// GDCM 1.x compatibility issue: + /// When using ReWrite an MR Image Storage would be rewritten as Secondary Capture Object while + /// still having a Pixel Spacing tag (0028,0030). If you have deal with those files, use this + /// very special flag to handle them + /// Unless explicitely set elsewhere by the standard, it will use value from 0028,0030 / 0018,0088 + /// for the Pixel Spacing of the Image + static void SetForcePixelSpacing(bool); + static bool GetForcePixelSpacing(); + + /// This function checks tags (0x0028, 0x0010) and (0x0028, 0x0011) for the + /// rows and columns of the image in pixels (as opposed to actual distances). + /// The output is {col , row} + static std::vector GetDimensionsValue(const File& f); + static void SetDimensionsValue(File& f, const Image & img); + + /// This function returns pixel information about an image from its dataset + /// That includes samples per pixel and bit depth (in that order) + static PixelFormat GetPixelFormatValue(const File& f); + + /// Set/Get shift/scale from/to a file + /// \warning this function reads/sets the Slope/Intercept in appropriate + /// class storage, but also Grid Scaling in RT Dose Storage + /// Can't take a dataset because the mediastorage of the file must be known + static std::vector GetRescaleInterceptSlopeValue(File const & f); + static void SetRescaleInterceptSlopeValue(File & f, const Image & img); + + /// Set/Get Origin (IPP) from/to a file + static std::vector GetOriginValue(File const & f); + static void SetOriginValue(DataSet & ds, const Image & img); + + /// Get Direction Cosines (IOP) from/to a file + /// Requires a file because mediastorage must be known + static std::vector GetDirectionCosinesValue(File const & f); + /// Set Direction Cosines (IOP) from/to a file + /// When IOD does not defines what is IOP (eg. typically Secondary Capture Image Storage) + /// this call will simply remove the IOP attribute. + /// Else in case of MR/CT image storage, this call will properly lookup the correct attribute + /// to store the IOP. + // FIXME: There is a major issue for image with multiple IOP (eg. Enhanced * Image Storage). + static void SetDirectionCosinesValue(DataSet & ds, const std::vector & dircos); + + /// Set/Get Spacing from/to a File + static std::vector GetSpacingValue(File const & f); + static void SetSpacingValue(DataSet & ds, const std::vector & spacing); + + /// DO NOT USE + static bool ComputeSpacingFromImagePositionPatient(const std::vector &imageposition, std::vector & spacing); + + static bool GetDirectionCosinesFromDataSet(DataSet const & ds, std::vector & dircos); + + //functions to get more information from a file + //useful for the stream image reader, which fills in necessary image information + //distinctly from the reader-style data input + static PhotometricInterpretation GetPhotometricInterpretationValue(File const& f); + //returns the configuration of colors in a plane, either RGB RGB RGB or RRR GGG BBB + static unsigned int GetPlanarConfigurationValue(const File& f); + + //returns the lookup table of an image file + static SmartPointer GetLUT(File const& f); + + ///Moved from PixampReader to here. Generally used for photometric interpretation. + static const ByteValue* GetPointerFromElement(Tag const &tag, File const& f); + +protected: + static Tag GetSpacingTagFromMediaStorage(MediaStorage const &ms); + static Tag GetZSpacingTagFromMediaStorage(MediaStorage const &ms); + +private: + static bool ForceRescaleInterceptSlope; + static bool ForcePixelSpacing; +}; + +} // end namespace gdcm + +#endif // GDCMIMAGEHELPER_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmImageReader.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmImageReader.cxx new file mode 100644 index 0000000..7969a4f --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmImageReader.cxx @@ -0,0 +1,153 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmImageReader.h" +#include "gdcmExplicitDataElement.h" +#include "gdcmImplicitDataElement.h" +#include "gdcmValue.h" +#include "gdcmFileMetaInformation.h" +#include "gdcmElement.h" +#include "gdcmPhotometricInterpretation.h" +#include "gdcmTransferSyntax.h" +#include "gdcmAttribute.h" +#include "gdcmImageHelper.h" +#include "gdcmPrivateTag.h" +#include "gdcmJPEGCodec.h" + +namespace gdcm +{ +ImageReader::ImageReader() +{ + PixelData = new Image; +} + +ImageReader::~ImageReader() +{ +} + +const Image& ImageReader::GetImage() const +{ + return dynamic_cast(*PixelData); +} +Image& ImageReader::GetImage() +{ + return dynamic_cast(*PixelData); +} + +//void ImageReader::SetImage(Image const &img) +//{ +// PixelData = img; +//} + +bool ImageReader::Read() +{ + return PixmapReader::Read(); +} + +bool ImageReader::ReadImage(MediaStorage const &ms) +{ + if( !PixmapReader::ReadImage(ms) ) + { + return false; + } + //const DataSet &ds = F->GetDataSet(); + Image& pixeldata = GetImage(); + + // 4 1/2 Let's do Pixel Spacing + std::vector spacing = ImageHelper::GetSpacingValue(*F); + // FIXME: Only SC is allowed not to have spacing: + if( !spacing.empty() ) + { + assert( spacing.size() >= pixeldata.GetNumberOfDimensions() ); // In MR, you can have a Z spacing, but store a 2D image + pixeldata.SetSpacing( &spacing[0] ); + if( spacing.size() > pixeldata.GetNumberOfDimensions() ) // FIXME HACK + { + pixeldata.SetSpacing(pixeldata.GetNumberOfDimensions(), spacing[pixeldata.GetNumberOfDimensions()] ); + } + } + // 4 2/3 Let's do Origin + std::vector origin = ImageHelper::GetOriginValue(*F); + if( !origin.empty() ) + { + pixeldata.SetOrigin( &origin[0] ); + if( origin.size() > pixeldata.GetNumberOfDimensions() ) // FIXME HACK + { + pixeldata.SetOrigin(pixeldata.GetNumberOfDimensions(), origin[pixeldata.GetNumberOfDimensions()] ); + } + } + + std::vector dircos = ImageHelper::GetDirectionCosinesValue(*F); + if( !dircos.empty() ) + { + pixeldata.SetDirectionCosines( &dircos[0] ); + } + + // Do the Rescale Intercept & Slope + std::vector is = ImageHelper::GetRescaleInterceptSlopeValue(*F); + pixeldata.SetIntercept( is[0] ); + pixeldata.SetSlope( is[1] ); + + return true; +} + +bool ImageReader::ReadACRNEMAImage() +{ + if( !PixmapReader::ReadACRNEMAImage() ) + { + return false; + } + const DataSet &ds = F->GetDataSet(); + Image& pixeldata = GetImage(); + + // 4 1/2 Let's do Pixel Spacing + const Tag tpixelspacing(0x0028, 0x0030); + if( ds.FindDataElement( tpixelspacing ) ) + { + const DataElement& de = ds.GetDataElement( tpixelspacing ); + Attribute<0x0028,0x0030> at; + at.SetFromDataElement( de ); + pixeldata.SetSpacing( 0, at.GetValue(0)); + pixeldata.SetSpacing( 1, at.GetValue(1)); + } + // 4 2/3 Let's do Origin + const Tag timageposition(0x0020, 0x0030); + if( ds.FindDataElement( timageposition) ) + { + const DataElement& de = ds.GetDataElement( timageposition); + Attribute<0x0020,0x0030> at = {{}}; + at.SetFromDataElement( de ); + pixeldata.SetOrigin( at.GetValues() ); + if( at.GetNumberOfValues() > pixeldata.GetNumberOfDimensions() ) // FIXME HACK + { + pixeldata.SetOrigin(pixeldata.GetNumberOfDimensions(), at.GetValue(pixeldata.GetNumberOfDimensions()) ); + } + } + const Tag timageorientation(0x0020, 0x0035); + if( ds.FindDataElement( timageorientation) ) + { + const DataElement& de = ds.GetDataElement( timageorientation); + Attribute<0x0020,0x0035> at = {{1,0,0,0,1,0}};//to get rid of brackets warnings in linux, lots of {} + at.SetFromDataElement( de ); + pixeldata.SetDirectionCosines( at.GetValues() ); + } + + // Do the Rescale Intercept & Slope + std::vector is = ImageHelper::GetRescaleInterceptSlopeValue(*F); + pixeldata.SetIntercept( is[0] ); + pixeldata.SetSlope( is[1] ); + + return true; +} + + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmImageReader.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmImageReader.h new file mode 100644 index 0000000..2bcf41f --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmImageReader.h @@ -0,0 +1,59 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMIMAGEREADER_H +#define GDCMIMAGEREADER_H + +#include "gdcmPixmapReader.h" +#include "gdcmImage.h" + +namespace gdcm +{ + +class MediaStorage; +/** + * \brief ImageReader + * \note its role is to convert the DICOM DataSet into a gdcm::Image + * representation + * Image is different from Pixmap has it has a position and a direction in + * Space. + * + * \see Image + */ +class GDCM_EXPORT ImageReader : public PixmapReader +{ +public: + ImageReader(); + virtual ~ImageReader();//needs to be virtual to ensure lack of memory leaks + + /// Read the DICOM image. There are two reason for failure: + /// 1. The input filename is not DICOM + /// 2. The input DICOM file does not contains an Image. + + virtual bool Read(); + + // Following methods are valid only after a call to 'Read' + + /// Return the read image + const Image& GetImage() const; + Image& GetImage(); + //void SetImage(Image const &img); + +protected: + bool ReadImage(MediaStorage const &ms); + bool ReadACRNEMAImage(); +}; + +} // end namespace gdcm + +#endif //GDCMIMAGEREADER_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmImageRegionReader.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmImageRegionReader.cxx new file mode 100644 index 0000000..3f6e43b --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmImageRegionReader.cxx @@ -0,0 +1,468 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmImageRegionReader.h" +#include "gdcmImageHelper.h" +#include "gdcmBoxRegion.h" + +#include "gdcmRAWCodec.h" +#include "gdcmRLECodec.h" +#include "gdcmJPEG2000Codec.h" +#include "gdcmJPEGCodec.h" +#include "gdcmJPEGLSCodec.h" + +namespace gdcm +{ + +class ImageRegionReaderInternals +{ +public: + ImageRegionReaderInternals() + { + TheRegion = NULL; + Modified = false; + FileOffset = -1; + } + ~ImageRegionReaderInternals() + { + delete TheRegion; + } + void SetRegion(Region const & r) + { + delete TheRegion; + TheRegion = r.Clone(); + assert( TheRegion ); + Modified = true; + } + Region *GetRegion() const + { + return TheRegion; + } + std::streampos GetFileOffset() const + { + return FileOffset; + } + void SetFileOffset( std::streampos f ) + { + FileOffset = f; + } +private: + Region *TheRegion; + bool Modified; + std::streamoff FileOffset; +}; + +ImageRegionReader::ImageRegionReader() +{ + Internals = new ImageRegionReaderInternals; +} + +ImageRegionReader::~ImageRegionReader() +{ + delete Internals; +} + +void ImageRegionReader::SetRegion(Region const & region) +{ + Internals->SetRegion( region ); +} + +Region const &ImageRegionReader::GetRegion() const +{ + return *Internals->GetRegion(); +} + +size_t ImageRegionReader::ComputeBufferLength() const +{ + // Is this a legal extent: + if( Internals->GetRegion() ) + { + if( !Internals->GetRegion()->IsValid() ) + { + gdcmDebugMacro( "Sorry not a valid extent. Giving up" ); + return 0; + } + } + PixelFormat pixelInfo = ImageHelper::GetPixelFormatValue(GetFile()); + size_t bytesPerPixel = pixelInfo.GetPixelSize(); + return this->Internals->GetRegion()->Area()*bytesPerPixel; +} + +bool ImageRegionReader::ReadInformation() +{ + std::set st; + Tag tpixeldata(0x7fe0, 0x0010); // never read this one + st.insert(tpixeldata); + if (!ReadUpToTag(tpixeldata, st)) + { + gdcmWarningMacro("Failed ReadUpToTag."); + return false; + } + const bool iseof = GetStreamPtr()->eof(); + if( iseof ) + { + gdcmDebugMacro( "No Pixel Data, sorry" ); + return false; + } + std::streampos fileoffset = GetStreamPtr()->tellg(); + assert( fileoffset != std::streampos(-1) ); + Internals->SetFileOffset( fileoffset ); + + const File &file = GetFile(); + const DataSet &ds = file.GetDataSet(); (void)ds; + //std::cout << ds << std::endl; + + MediaStorage ms; + ms.SetFromFile(file); + assert( ms != MediaStorage::VLWholeSlideMicroscopyImageStorage ); + if( !MediaStorage::IsImage( ms ) ) + { + gdcmDebugMacro( "Not an image recognized. Giving up"); + return false; + } + + // populate Image meta data + if( !ReadImageInternal(ms, false) ) + { + return false; + } + // FIXME Copy/paste from ImageReader::ReadImage + Image& pixeldata = GetImage(); + + // 4 1/2 Let's do Pixel Spacing + std::vector spacing = ImageHelper::GetSpacingValue(*F); + // FIXME: Only SC is allowed not to have spacing: + if( !spacing.empty() ) + { + assert( spacing.size() >= pixeldata.GetNumberOfDimensions() ); // In MR, you can have a Z spacing, but store a 2D image + pixeldata.SetSpacing( &spacing[0] ); + if( spacing.size() > pixeldata.GetNumberOfDimensions() ) // FIXME HACK + { + pixeldata.SetSpacing(pixeldata.GetNumberOfDimensions(), spacing[pixeldata.GetNumberOfDimensions()] ); + } + } + // 4 2/3 Let's do Origin + std::vector origin = ImageHelper::GetOriginValue(*F); + if( !origin.empty() ) + { + pixeldata.SetOrigin( &origin[0] ); + if( origin.size() > pixeldata.GetNumberOfDimensions() ) // FIXME HACK + { + pixeldata.SetOrigin(pixeldata.GetNumberOfDimensions(), origin[pixeldata.GetNumberOfDimensions()] ); + } + } + + std::vector dircos = ImageHelper::GetDirectionCosinesValue(*F); + if( !dircos.empty() ) + { + pixeldata.SetDirectionCosines( &dircos[0] ); + } + + // Do the Rescale Intercept & Slope + std::vector is = ImageHelper::GetRescaleInterceptSlopeValue(*F); + pixeldata.SetIntercept( is[0] ); + pixeldata.SetSlope( is[1] ); + + return true; +} + +bool ImageRegionReader::ReadRAWIntoBuffer(char *buffer, size_t buflen) +{ + (void)buflen; + std::vector dimensions = ImageHelper::GetDimensionsValue(GetFile()); + PixelFormat pixelInfo = ImageHelper::GetPixelFormatValue(GetFile()); + + const FileMetaInformation &header = GetFile().GetHeader(); + const TransferSyntax &ts = header.GetDataSetTransferSyntax(); + + bool needbyteswap = (ts == TransferSyntax::ImplicitVRBigEndianPrivateGE || ts == TransferSyntax::ExplicitVRBigEndian ); + RAWCodec theCodec; + if( !theCodec.CanDecode( ts ) ) return false; + theCodec.SetPlanarConfiguration( + ImageHelper::GetPlanarConfigurationValue(GetFile())); + theCodec.SetPhotometricInterpretation( + ImageHelper::GetPhotometricInterpretationValue(GetFile())); + //theCodec.SetLUT( GetLUT() ); + theCodec.SetPixelFormat( ImageHelper::GetPixelFormatValue(GetFile()) ); + theCodec.SetNeedByteSwap( needbyteswap ); + //theCodec.SetNeedOverlayCleanup( AreOverlaysInPixelData() ); + theCodec.SetDimensions(ImageHelper::GetDimensionsValue(GetFile())); + std::istream* theStream = GetStreamPtr(); + + const BoxRegion &boundingbox = this->Internals->GetRegion()->ComputeBoundingBox(); + unsigned int xmin = boundingbox.GetXMin(); + unsigned int xmax = boundingbox.GetXMax(); + unsigned int ymin = boundingbox.GetYMin(); + unsigned int ymax = boundingbox.GetYMax(); + unsigned int zmin = boundingbox.GetZMin(); + unsigned int zmax = boundingbox.GetZMax(); + assert( xmax >= xmin ); + assert( ymax >= ymin ); + unsigned int rowsize = xmax - xmin + 1; + unsigned int colsize = ymax - ymin + 1; + unsigned int bytesPerPixel = pixelInfo.GetPixelSize(); + + std::vector buffer1; + buffer1.resize( rowsize*bytesPerPixel ); + char *tmpBuffer1 = &buffer1[0]; + std::vector buffer2; + buffer2.resize( rowsize*bytesPerPixel ); + char *tmpBuffer2 = &buffer2[0]; + unsigned int y, z; + std::streamoff theOffset; + for (z = zmin; z <= zmax; ++z) + { + for (y = ymin; y <= ymax; ++y) + { + theStream->seekg(std::ios::beg); + theOffset = (size_t)Internals->GetFileOffset() + (z*dimensions[1]*dimensions[0] + y*dimensions[0] + xmin)*bytesPerPixel; + theStream->seekg(theOffset); + theStream->read(tmpBuffer1, rowsize*bytesPerPixel); + if (!theCodec.DecodeBytes(tmpBuffer1, rowsize*bytesPerPixel, + tmpBuffer2, rowsize*bytesPerPixel)) + { + return false; + } + memcpy(&(buffer[((z-zmin)*rowsize*colsize + + (y-ymin)*rowsize)*bytesPerPixel]), + tmpBuffer2, rowsize*bytesPerPixel); + } + } + return true; +} + +bool ImageRegionReader::ReadRLEIntoBuffer(char *buffer, size_t buflen) +{ + (void)buflen; + std::vector dimensions = ImageHelper::GetDimensionsValue(GetFile()); + //const PixelFormat pixelInfo = ImageHelper::GetPixelFormatValue(GetFile()); + + const FileMetaInformation &header = GetFile().GetHeader(); + const TransferSyntax &ts = header.GetDataSetTransferSyntax(); + + bool needbyteswap = (ts == TransferSyntax::ImplicitVRBigEndianPrivateGE || ts == TransferSyntax::ExplicitVRBigEndian ); + RLECodec theCodec; + if( !theCodec.CanDecode( ts ) ) return false; + theCodec.SetPlanarConfiguration( + ImageHelper::GetPlanarConfigurationValue(GetFile())); + theCodec.SetPhotometricInterpretation( + ImageHelper::GetPhotometricInterpretationValue(GetFile())); + //theCodec.SetLUT( GetLUT() ); + theCodec.SetPixelFormat( ImageHelper::GetPixelFormatValue(GetFile()) ); + theCodec.SetNeedByteSwap( needbyteswap ); + //theCodec.SetNeedOverlayCleanup( AreOverlaysInPixelData() ); + std::vector d = ImageHelper::GetDimensionsValue(GetFile()); + theCodec.SetDimensions(d ); + theCodec.SetNumberOfDimensions( 2 ); + if( d[2] > 1 ) + theCodec.SetNumberOfDimensions( 3 ); + + std::istream* theStream = GetStreamPtr(); + const BoxRegion &boundingbox = this->Internals->GetRegion()->ComputeBoundingBox(); + unsigned int xmin = boundingbox.GetXMin(); + unsigned int xmax = boundingbox.GetXMax(); + unsigned int ymin = boundingbox.GetYMin(); + unsigned int ymax = boundingbox.GetYMax(); + unsigned int zmin = boundingbox.GetZMin(); + unsigned int zmax = boundingbox.GetZMax(); + + assert( xmax >= xmin ); + assert( ymax >= ymin ); + + theCodec.DecodeExtent( + buffer, + xmin, xmax, + ymin, ymax, + zmin, zmax, + *theStream + ); + + return true; +} + +bool ImageRegionReader::ReadJPEG2000IntoBuffer(char *buffer, size_t buflen) +{ + (void)buflen; + std::vector dimensions = ImageHelper::GetDimensionsValue(GetFile()); + //const PixelFormat pixelInfo = ImageHelper::GetPixelFormatValue(GetFile()); + + const FileMetaInformation &header = GetFile().GetHeader(); + const TransferSyntax &ts = header.GetDataSetTransferSyntax(); + + bool needbyteswap = (ts == TransferSyntax::ImplicitVRBigEndianPrivateGE || ts == TransferSyntax::ExplicitVRBigEndian ); + JPEG2000Codec theCodec; + if( !theCodec.CanDecode( ts ) ) return false; + theCodec.SetPlanarConfiguration( + ImageHelper::GetPlanarConfigurationValue(GetFile())); + theCodec.SetPhotometricInterpretation( + ImageHelper::GetPhotometricInterpretationValue(GetFile())); + //theCodec.SetLUT( GetLUT() ); + theCodec.SetPixelFormat( ImageHelper::GetPixelFormatValue(GetFile()) ); + theCodec.SetNeedByteSwap( needbyteswap ); + //theCodec.SetNeedOverlayCleanup( AreOverlaysInPixelData() ); + std::vector d = ImageHelper::GetDimensionsValue(GetFile()); + theCodec.SetDimensions(d ); + theCodec.SetNumberOfDimensions( 2 ); + if( d[2] > 1 ) + theCodec.SetNumberOfDimensions( 3 ); + + std::istream* theStream = GetStreamPtr(); + const BoxRegion &boundingbox = this->Internals->GetRegion()->ComputeBoundingBox(); + unsigned int xmin = boundingbox.GetXMin(); + unsigned int xmax = boundingbox.GetXMax(); + unsigned int ymin = boundingbox.GetYMin(); + unsigned int ymax = boundingbox.GetYMax(); + unsigned int zmin = boundingbox.GetZMin(); + unsigned int zmax = boundingbox.GetZMax(); + + assert( xmax >= xmin ); + assert( ymax >= ymin ); + + theCodec.DecodeExtent( + buffer, + xmin, xmax, + ymin, ymax, + zmin, zmax, + *theStream + ); + + return true; +} + +bool ImageRegionReader::ReadJPEGIntoBuffer(char *buffer, size_t buflen) +{ + (void)buflen; + std::vector dimensions = ImageHelper::GetDimensionsValue(GetFile()); + //const PixelFormat pixelInfo = ImageHelper::GetPixelFormatValue(GetFile()); + + const FileMetaInformation &header = GetFile().GetHeader(); + const TransferSyntax &ts = header.GetDataSetTransferSyntax(); + + bool needbyteswap = (ts == TransferSyntax::ImplicitVRBigEndianPrivateGE || ts == TransferSyntax::ExplicitVRBigEndian ); + JPEGCodec theCodec; + if( !theCodec.CanDecode( ts ) ) return false; + theCodec.SetPlanarConfiguration( + ImageHelper::GetPlanarConfigurationValue(GetFile())); + theCodec.SetPhotometricInterpretation( + ImageHelper::GetPhotometricInterpretationValue(GetFile())); + //theCodec.SetLUT( GetLUT() ); + theCodec.SetNeedByteSwap( needbyteswap ); + //theCodec.SetNeedOverlayCleanup( AreOverlaysInPixelData() ); + std::vector d = ImageHelper::GetDimensionsValue(GetFile()); + theCodec.SetDimensions(d ); + theCodec.SetNumberOfDimensions( 2 ); + if( d[2] > 1 ) + theCodec.SetNumberOfDimensions( 3 ); + // last call: + theCodec.SetPixelFormat( ImageHelper::GetPixelFormatValue(GetFile()) ); + + std::istream* theStream = GetStreamPtr(); + const BoxRegion &boundingbox = this->Internals->GetRegion()->ComputeBoundingBox(); + unsigned int xmin = boundingbox.GetXMin(); + unsigned int xmax = boundingbox.GetXMax(); + unsigned int ymin = boundingbox.GetYMin(); + unsigned int ymax = boundingbox.GetYMax(); + unsigned int zmin = boundingbox.GetZMin(); + unsigned int zmax = boundingbox.GetZMax(); + + assert( xmax >= xmin ); + assert( ymax >= ymin ); + + theCodec.DecodeExtent( + buffer, + xmin, xmax, + ymin, ymax, + zmin, zmax, + *theStream + ); + + return true; +} + +bool ImageRegionReader::ReadJPEGLSIntoBuffer(char *buffer, size_t buflen) +{ + (void)buflen; + std::vector dimensions = ImageHelper::GetDimensionsValue(GetFile()); + //const PixelFormat pixelInfo = ImageHelper::GetPixelFormatValue(GetFile()); + + const FileMetaInformation &header = GetFile().GetHeader(); + const TransferSyntax &ts = header.GetDataSetTransferSyntax(); + + bool needbyteswap = (ts == TransferSyntax::ImplicitVRBigEndianPrivateGE || ts == TransferSyntax::ExplicitVRBigEndian ); + JPEGLSCodec theCodec; + if( !theCodec.CanDecode( ts ) ) return false; + theCodec.SetPlanarConfiguration( + ImageHelper::GetPlanarConfigurationValue(GetFile())); + theCodec.SetPhotometricInterpretation( + ImageHelper::GetPhotometricInterpretationValue(GetFile())); + //theCodec.SetLUT( GetLUT() ); + theCodec.SetPixelFormat( ImageHelper::GetPixelFormatValue(GetFile()) ); + theCodec.SetNeedByteSwap( needbyteswap ); + //theCodec.SetNeedOverlayCleanup( AreOverlaysInPixelData() ); + std::vector d = ImageHelper::GetDimensionsValue(GetFile()); + theCodec.SetDimensions(d ); + theCodec.SetNumberOfDimensions( 2 ); + if( d[2] > 1 ) + theCodec.SetNumberOfDimensions( 3 ); + + std::istream* theStream = GetStreamPtr(); + const BoxRegion &boundingbox = this->Internals->GetRegion()->ComputeBoundingBox(); + unsigned int xmin = boundingbox.GetXMin(); + unsigned int xmax = boundingbox.GetXMax(); + unsigned int ymin = boundingbox.GetYMin(); + unsigned int ymax = boundingbox.GetYMax(); + unsigned int zmin = boundingbox.GetZMin(); + unsigned int zmax = boundingbox.GetZMax(); + + assert( xmax >= xmin ); + assert( ymax >= ymin ); + + theCodec.DecodeExtent( + buffer, + xmin, xmax, + ymin, ymax, + zmin, zmax, + *theStream + ); + + return true; +} +bool ImageRegionReader::ReadIntoBuffer(char *buffer, size_t buflen) +{ + size_t thelen = ComputeBufferLength(); + if( buflen < thelen ) + { + gdcmDebugMacro( "buffer cannot be smaller than computed buffer length" ); + return false; + } + assert( Internals->GetFileOffset() != std::streampos(-1) ); + gdcmDebugMacro( "Using FileOffset: " << Internals->GetFileOffset() ); + std::istream* theStream = GetStreamPtr(); + theStream->seekg( Internals->GetFileOffset() ); + + bool success = false; + if( !success ) success = ReadRAWIntoBuffer(buffer, buflen); + if( !success ) success = ReadRLEIntoBuffer(buffer, buflen); + if( !success ) success = ReadJPEGIntoBuffer(buffer, buflen); + if( !success ) success = ReadJPEGLSIntoBuffer(buffer, buflen); + if( !success ) success = ReadJPEG2000IntoBuffer(buffer, buflen); + + return success; +} + +bool ImageRegionReader::Read() +{ + return false; +} + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmImageRegionReader.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmImageRegionReader.h new file mode 100644 index 0000000..2779c78 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmImageRegionReader.h @@ -0,0 +1,67 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMIMAGEEXTENTREADER_H +#define GDCMIMAGEEXTENTREADER_H + +#include "gdcmImageReader.h" +#include "gdcmImage.h" +#include "gdcmRegion.h" + +namespace gdcm +{ + +class ImageRegionReaderInternals; +/** + * \brief ImageRegionReader + * \see ImageReader + */ +class GDCM_EXPORT ImageRegionReader : public ImageReader +{ +public: + ImageRegionReader(); + ~ImageRegionReader(); + + /// Set/Get Region to be read + void SetRegion(Region const & region); + Region const &GetRegion() const; + + /// Explicit call which will compute the minimal buffer length that can hold the whole + /// uncompressed image as defined by Region `region`. + /// \return 0 upon error + size_t ComputeBufferLength() const; + + /// Read meta information (not Pixel Data) from the DICOM file. + /// \return false upon error + bool ReadInformation(); + + /// Read into buffer: + /// \return false upon error + bool ReadIntoBuffer(char *inreadbuffer, size_t buflen); + +protected: + /// To prevent user from calling super class Read() function + bool Read(); + +private: + bool ReadRAWIntoBuffer(char *buffer, size_t buflen); + bool ReadRLEIntoBuffer(char *buffer, size_t buflen); + bool ReadJPEG2000IntoBuffer(char *buffer, size_t buflen); + bool ReadJPEGIntoBuffer(char *buffer, size_t buflen); + bool ReadJPEGLSIntoBuffer(char *buffer, size_t buflen); + ImageRegionReaderInternals *Internals; +}; + +} // end namespace gdcm + +#endif //GDCMIMAGEEXTENTREADER_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmImageToImageFilter.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmImageToImageFilter.cxx new file mode 100644 index 0000000..0b5dfce --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmImageToImageFilter.cxx @@ -0,0 +1,37 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmImageToImageFilter.h" +#include "gdcmImage.h" + +namespace gdcm +{ + +ImageToImageFilter::ImageToImageFilter() +{ + Input = new Image; + Output = new Image; +} + +Image &ImageToImageFilter::GetInput() +{ + return dynamic_cast(*Input); +} + +const Image &ImageToImageFilter::GetOutput() const +{ + return dynamic_cast(*Output); +} + + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmImageToImageFilter.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmImageToImageFilter.h new file mode 100644 index 0000000..d21d994 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmImageToImageFilter.h @@ -0,0 +1,44 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMIMAGETOIMAGEFILTER_H +#define GDCMIMAGETOIMAGEFILTER_H + +#include "gdcmPixmapToPixmapFilter.h" + +namespace gdcm +{ + +class Image; +/** + * \brief ImageToImageFilter class + * Super class for all filter taking an image and producing an output image + */ +class GDCM_EXPORT ImageToImageFilter : public PixmapToPixmapFilter +{ +public: + ImageToImageFilter(); + ~ImageToImageFilter() {} + + Image &GetInput(); + + // NOTE: covariant return-type to preserve backward compatible API + /// Get Output image + const Image &GetOutput() const; + +protected: +}; + +} // end namespace gdcm + +#endif //GDCMIMAGETOIMAGEFILTER_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmImageWriter.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmImageWriter.cxx new file mode 100644 index 0000000..ae4c373 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmImageWriter.cxx @@ -0,0 +1,386 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmImageWriter.h" +#include "gdcmTrace.h" +#include "gdcmDataSet.h" +#include "gdcmDataElement.h" +#include "gdcmAttribute.h" +#include "gdcmUIDGenerator.h" +#include "gdcmSystem.h" +#include "gdcmImageHelper.h" +#include "gdcmLookupTable.h" +#include "gdcmItem.h" +#include "gdcmSequenceOfItems.h" + +namespace gdcm +{ + +ImageWriter::ImageWriter() +{ + PixelData = new Image; +} + +ImageWriter::~ImageWriter() +{ +} + +//void ImageWriter::SetImage(Image const &img) +//{ +// PixelData = img; +//} + +bool ImageWriter::Write() +{ + if( !PrepareWrite() ) return false; + + //assert( Stream.is_open() ); + File& file = GetFile(); + DataSet& ds = file.GetDataSet(); + + // Some Type 2 Element: + // PatientName + if( !ds.FindDataElement( Tag(0x0010,0x0010) ) ) + { + DataElement de( Tag(0x0010,0x0010) ); + de.SetVR( Attribute<0x0010,0x0010>::GetVR() ); + ds.Insert( de ); + } + // PatientID + if( !ds.FindDataElement( Tag(0x0010,0x0020) ) ) + { + DataElement de( Tag(0x0010,0x0020) ); + de.SetVR( Attribute<0x0010,0x0020>::GetVR() ); + ds.Insert( de ); + } + // PatientBirthDate + if( !ds.FindDataElement( Tag(0x0010,0x0030) ) ) + { + DataElement de( Tag(0x0010,0x0030) ); + de.SetVR( Attribute<0x0010,0x0030>::GetVR() ); + ds.Insert( de ); + } + // PatientSex + if( !ds.FindDataElement( Tag(0x0010,0x0040) ) ) + { + DataElement de( Tag(0x0010,0x0040) ); + de.SetVR( Attribute<0x0010,0x0040>::GetVR() ); + ds.Insert( de ); + } + // Laterality + if( false && !ds.FindDataElement( Tag(0x0020,0x0060) ) ) + { + DataElement de( Tag(0x0020,0x0060) ); + de.SetVR( Attribute<0x0020,0x0060>::GetVR() ); + ds.Insert( de ); + } + // StudyDate + char date[22]; + const size_t datelen = 8; + int res = System::GetCurrentDateTime(date); + assert( res ); + (void)res;//warning removal + if( !ds.FindDataElement( Tag(0x0008,0x0020) ) ) + { + DataElement de( Tag(0x0008,0x0020) ); + // Do not copy the whole cstring: + de.SetByteValue( date, datelen ); + de.SetVR( Attribute<0x0008,0x0020>::GetVR() ); + ds.Insert( de ); + } + // StudyTime + const size_t timelen = 6 + 1 + 6; // time + milliseconds + Attribute<0x0008, 0x0030> studytime; + if( !ds.FindDataElement( studytime.GetTag() ) ) + { + // Do not copy the whole cstring: + studytime.SetValue( CSComp(date+datelen, timelen) ); + ds.Insert( studytime.GetAsDataElement() ); + } + // ReferringPhysicianName + if( !ds.FindDataElement( Tag(0x0008,0x0090) ) ) + { + DataElement de( Tag(0x0008,0x0090) ); + de.SetVR( Attribute<0x0008,0x0090>::GetVR() ); + ds.Insert( de ); + } + // StudyID + if( !ds.FindDataElement( Tag(0x0020,0x0010) ) ) + { + // FIXME: this one is actually bad since the value is needed for DICOMDIR construction + DataElement de( Tag(0x0020,0x0010) ); + de.SetVR( Attribute<0x0020,0x0010>::GetVR() ); + ds.Insert( de ); + } + // AccessionNumber + if( !ds.FindDataElement( Tag(0x0008,0x0050) ) ) + { + DataElement de( Tag(0x0008,0x0050) ); + de.SetVR( Attribute<0x0008,0x0050>::GetVR() ); + ds.Insert( de ); + } + // SeriesNumber + if( !ds.FindDataElement( Tag(0x0020,0x0011) ) ) + { + DataElement de( Tag(0x0020,0x0011) ); + de.SetVR( Attribute<0x0020,0x0011>::GetVR() ); + ds.Insert( de ); + } + // InstanceNumber + if( !ds.FindDataElement( Tag(0x0020,0x0013) ) ) + { + DataElement de( Tag(0x0020,0x0013) ); + de.SetVR( Attribute<0x0020,0x0013>::GetVR() ); + ds.Insert( de ); + } + + MediaStorage ms; + ms.SetFromFile( GetFile() ); + assert( ms != MediaStorage::MS_END ); + + // Patient Orientation + if( ms == MediaStorage::SecondaryCaptureImageStorage && !ds.FindDataElement( Tag(0x0020,0x0020) ) ) + { + DataElement de( Tag(0x0020,0x0020) ); + de.SetVR( Attribute<0x0020,0x0020>::GetVR() ); + ds.Insert( de ); + } + + // (re)Compute MediaStorage: + if( !ds.FindDataElement( Tag(0x0008, 0x0060) ) ) + { + const char *modality = ms.GetModality(); + DataElement de( Tag(0x0008, 0x0060 ) ); + VL::Type strlenModality = (VL::Type)strlen(modality); + de.SetByteValue( modality, strlenModality ); + de.SetVR( Attribute<0x0008, 0x0060>::GetVR() ); + ds.Insert( de ); + } + else + { + const ByteValue *bv = ds.GetDataElement( Tag(0x0008, 0x0060 ) ).GetByteValue(); + std::string modality2; + if( bv ) + { + modality2 = std::string( bv->GetPointer(), bv->GetLength() ); + //assert( modality2.find( ' ' ) == std::string::npos ); // no space ... + } + else + { + // remove empty Modality, and set a new one... + ds.Remove( Tag(0x0008, 0x0060 ) ); // Modality is Type 1 ! + assert( ms != MediaStorage::MS_END ); + } +/* + if( modality2 != ms.GetModality() ) + { + assert( std::string(ms.GetModality()).find( ' ' ) == std::string::npos ); // no space ... + DataElement de( Tag(0x0008, 0x0060 ) ); + de.SetByteValue( ms.GetModality(), strlen(ms.GetModality()) ); + de.SetVR( Attribute<0x0008, 0x0060>::GetVR() ); + ds.Insert( de ); // FIXME: should we always replace ? + // Well technically you could have a SecondaryCaptureImageStorage with a modality of NM... + } +*/ + } + if( !ds.FindDataElement( Tag(0x0008, 0x0064) ) ) + { + if( ms == MediaStorage::SecondaryCaptureImageStorage ) + { + // (0008,0064) CS [SI] # 2, 1 ConversionType + const char conversion[] = "WSD "; // FIXME + DataElement de( Tag(0x0008, 0x0064 ) ); + VL::Type strlenConversion = (VL::Type)strlen(conversion); + de.SetByteValue( conversion, strlenConversion ); + de.SetVR( Attribute<0x0008, 0x0064>::GetVR() ); + ds.Insert( de ); + } + } + + + Image & pixeldata = GetImage(); + PixelFormat pf = pixeldata.GetPixelFormat(); + PhotometricInterpretation pi = pixeldata.GetPhotometricInterpretation(); + + // Do the Rescale Intercept & Slope + if( pi == PhotometricInterpretation::MONOCHROME1 || pi == PhotometricInterpretation::MONOCHROME2 ) + { + assert( pf.GetSamplesPerPixel() == 1 ); + ImageHelper::SetRescaleInterceptSlopeValue(GetFile(), pixeldata); + } + else + { + assert( pixeldata.GetIntercept() == 0 && pixeldata.GetSlope() == 1 ); + } + +// Attribute<0x0028, 0x0006> planarconfiguration; +// planarconfiguration.SetValue( PixelData->GetPlanarConfiguration() ); +// ds.Replace( planarconfiguration.GetAsDataElement() ); + + // PhotometricInterpretation + // const Tag tphotometricinterpretation(0x0028, 0x0004); + //if( !ds.FindDataElement( Tag(0x0028, 0x0004) ) ) + { + //if( pi == PhotometricInterpretation::RGB + // || pi == PhotometricInterpretation::YBR_FULL ) // FIXME + // { + // Attribute<0x0028, 0x0006> planarconfiguration; + // planarconfiguration.SetValue( PixelData->GetPlanarConfiguration() ); + // ds.Replace( planarconfiguration.GetAsDataElement() ); + // } + //else + if ( pi == PhotometricInterpretation::PALETTE_COLOR ) + { + const LookupTable &lut = PixelData->GetLUT(); + assert( lut.Initialized() ); +// assert( (pf.GetBitsAllocated() == 8 && pf.GetPixelRepresentation() == 0) +// || (pf.GetBitsAllocated() == 16 && pf.GetPixelRepresentation() == 0) ); + // lut descriptor: + // (0028,1101) US 256\0\16 # 6, 3 RedPaletteColorLookupTableDescriptor + // (0028,1102) US 256\0\16 # 6, 3 GreenPaletteColorLookupTableDescriptor + // (0028,1103) US 256\0\16 # 6, 3 BluePaletteColorLookupTableDescriptor + // lut data: + unsigned short length, subscript, bitsize; + unsigned short rawlut8[256]; + unsigned short rawlut16[65536]; + unsigned short *rawlut = rawlut8; + unsigned int lutlen = 256; + if( pf.GetBitsAllocated() == 16 ) + { + rawlut = rawlut16; + lutlen = 65536; + } + unsigned int l; + + // FIXME: should I really clear rawlut each time ? + // RED + memset(rawlut,0,lutlen*2); + lut.GetLUT(LookupTable::RED, (unsigned char*)rawlut, l); + DataElement redde( Tag(0x0028, 0x1201) ); + redde.SetVR( VR::OW ); + redde.SetByteValue( (char*)rawlut, l); + ds.Replace( redde ); + // descriptor: + Attribute<0x0028, 0x1101, VR::US, VM::VM3> reddesc; + lut.GetLUTDescriptor(LookupTable::RED, length, subscript, bitsize); + reddesc.SetValue(length,0); reddesc.SetValue(subscript,1); reddesc.SetValue(bitsize,2); + ds.Replace( reddesc.GetAsDataElement() ); + + // GREEN + memset(rawlut,0,lutlen*2); + lut.GetLUT(LookupTable::GREEN, (unsigned char*)rawlut, l); + DataElement greende( Tag(0x0028, 0x1202) ); + greende.SetVR( VR::OW ); + greende.SetByteValue( (char*)rawlut, l); + ds.Replace( greende ); + // descriptor: + Attribute<0x0028, 0x1102, VR::US, VM::VM3> greendesc; + lut.GetLUTDescriptor(LookupTable::GREEN, length, subscript, bitsize); + greendesc.SetValue(length,0); greendesc.SetValue(subscript,1); greendesc.SetValue(bitsize,2); + ds.Replace( greendesc.GetAsDataElement() ); + + // BLUE + memset(rawlut,0,lutlen*2); + lut.GetLUT(LookupTable::BLUE, (unsigned char*)rawlut, l); + DataElement bluede( Tag(0x0028, 0x1203) ); + bluede.SetVR( VR::OW ); + bluede.SetByteValue( (char*)rawlut, l); + ds.Replace( bluede ); + // descriptor: + Attribute<0x0028, 0x1103, VR::US, VM::VM3> bluedesc; + lut.GetLUTDescriptor(LookupTable::BLUE, length, subscript, bitsize); + bluedesc.SetValue(length,0); bluedesc.SetValue(subscript,1); bluedesc.SetValue(bitsize,2); + ds.Replace( bluedesc.GetAsDataElement() ); + } + + ds.Remove( Tag(0x0028, 0x1221) ); + ds.Remove( Tag(0x0028, 0x1222) ); + ds.Remove( Tag(0x0028, 0x1223) ); + + } + + // FIXME shouldn't this be done by the ImageApplyLookupTable filter ? + if( pi == PhotometricInterpretation::RGB ) + { + // usual tags: + ds.Remove( Tag(0x0028, 0x1101) ); + ds.Remove( Tag(0x0028, 0x1102) ); + ds.Remove( Tag(0x0028, 0x1103) ); + + ds.Remove( Tag(0x0028, 0x1201) ); + ds.Remove( Tag(0x0028, 0x1202) ); + ds.Remove( Tag(0x0028, 0x1203) ); + + // Dont' forget the segmented one: + ds.Remove( Tag(0x0028, 0x1221) ); + ds.Remove( Tag(0x0028, 0x1222) ); + ds.Remove( Tag(0x0028, 0x1223) ); + + // PaletteColorLookupTableUID ?? + ds.Remove( Tag(0x0028, 0x1199) ); + } +// Attribute<0x0028, 0x0004> photometricinterpretation; +// photometricinterpretation.SetValue( pi ); +// ds.Replace( photometricinterpretation.GetAsDataElement() ); +Attribute<0x0028,0x0004> piat; +//const DataElement &pide = ds.GetDataElement( piat.GetTag() ); +//const char *str1 = pide.GetByteValue()->GetPointer(); +{ + const char *pistr = PhotometricInterpretation::GetPIString(pi); + DataElement de( Tag(0x0028, 0x0004 ) ); + VL::Type strlenPistr = (VL::Type)strlen(pistr); + de.SetByteValue( pistr, strlenPistr ); + de.SetVR( piat.GetVR() ); + ds.Replace( de ); +} + + + // Spacing: + std::vector sp; + sp.resize(3); // important ! + sp[0] = pixeldata.GetSpacing(0); + sp[1] = pixeldata.GetSpacing(1); + sp[2] = pixeldata.GetSpacing(2); // might be a dummy value... + ImageHelper::SetSpacingValue(ds, sp); + + // Direction Cosines: + const double *dircos = pixeldata.GetDirectionCosines(); + if( dircos ) + { + std::vector iop; + iop.resize(6); + iop[0] = dircos[0]; + iop[1] = dircos[1]; + iop[2] = dircos[2]; + iop[3] = dircos[3]; + iop[4] = dircos[4]; + iop[5] = dircos[5]; + ImageHelper::SetDirectionCosinesValue(ds, iop); + } + + // Origin: + const double *origin = pixeldata.GetOrigin(); + if( origin ) + { + ImageHelper::SetOriginValue(ds, pixeldata); + } + + assert( Stream ); + if( !Writer::Write() ) + { + return false; + } + return true; +} + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmImageWriter.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmImageWriter.h new file mode 100644 index 0000000..666e391 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmImageWriter.h @@ -0,0 +1,50 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMIMAGEWRITER_H +#define GDCMIMAGEWRITER_H + +#include "gdcmPixmapWriter.h" +#include "gdcmImage.h" + +namespace gdcm +{ + +class Image; +/** + * \brief ImageWriter + */ +class GDCM_EXPORT ImageWriter : public PixmapWriter +{ +public: + ImageWriter(); + ~ImageWriter(); + + /// Set/Get Image to be written + /// It will overwrite anything Image infos found in DataSet + /// (see parent class to see how to pass dataset) + const Image& GetImage() const { return dynamic_cast(*PixelData); } + Image& GetImage() { return dynamic_cast(*PixelData); } // FIXME + //void SetImage(Image const &img); + + /// Write + bool Write(); // Execute() + +protected: + +private: +}; + +} // end namespace gdcm + +#endif //GDCMIMAGEWRITER_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmJPEG12Codec.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmJPEG12Codec.cxx new file mode 100644 index 0000000..dc1bc14 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmJPEG12Codec.cxx @@ -0,0 +1,21 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmJPEG12Codec.h" + +#include "gdcm_ljpeg12.h" + +#include + +#define JPEGBITSCodec JPEG12Codec +#include "gdcmJPEGBITSCodec.cxx" diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmJPEG12Codec.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmJPEG12Codec.h new file mode 100644 index 0000000..a794986 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmJPEG12Codec.h @@ -0,0 +1,49 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMJPEG12CODEC_H +#define GDCMJPEG12CODEC_H + +#include "gdcmJPEGCodec.h" + +namespace gdcm +{ + +class JPEGInternals; +class ByteValue; +/** + * \brief Class to do JPEG 12bits (lossy & lossless) + * \note internal class + */ +class JPEG12Codec : public JPEGCodec +{ +public: + JPEG12Codec(); + ~JPEG12Codec(); + + bool DecodeByStreams(std::istream &is, std::ostream &os); + bool InternalCode(const char *input, unsigned long len, std::ostream &os); + + bool GetHeaderInfo(std::istream &is, TransferSyntax &ts); + +protected: + bool IsStateSuspension() const; + virtual bool EncodeBuffer(std::ostream &os, const char *data, size_t datalen); + +private: + JPEGInternals *Internals; +}; + +} // end namespace gdcm + +#endif //GDCMJPEG12CODEC_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmJPEG16Codec.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmJPEG16Codec.cxx new file mode 100644 index 0000000..795676e --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmJPEG16Codec.cxx @@ -0,0 +1,21 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmJPEG16Codec.h" + +#include "gdcm_ljpeg16.h" + +#include + +#define JPEGBITSCodec JPEG16Codec +#include "gdcmJPEGBITSCodec.cxx" diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmJPEG16Codec.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmJPEG16Codec.h new file mode 100644 index 0000000..ce109a1 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmJPEG16Codec.h @@ -0,0 +1,49 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMJPEG16CODEC_H +#define GDCMJPEG16CODEC_H + +#include "gdcmJPEGCodec.h" + +namespace gdcm +{ + +class JPEGInternals; +class ByteValue; +/** + * \brief Class to do JPEG 16bits (lossless) + * \note internal class + */ +class JPEG16Codec : public JPEGCodec +{ +public: + JPEG16Codec(); + ~JPEG16Codec(); + + bool DecodeByStreams(std::istream &is, std::ostream &os); + bool InternalCode(const char *input, unsigned long len, std::ostream &os); + + bool GetHeaderInfo(std::istream &is, TransferSyntax &ts); + +protected: + bool IsStateSuspension() const; + virtual bool EncodeBuffer(std::ostream &os, const char *data, size_t datalen); + +private: + JPEGInternals *Internals; +}; + +} // end namespace gdcm + +#endif //GDCMJPEG16CODEC_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmJPEG2000Codec.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmJPEG2000Codec.cxx new file mode 100644 index 0000000..40a9f8a --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmJPEG2000Codec.cxx @@ -0,0 +1,1606 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmJPEG2000Codec.h" +#include "gdcmTransferSyntax.h" +#include "gdcmTrace.h" +#include "gdcmDataElement.h" +#include "gdcmSequenceOfFragments.h" +#include "gdcmSwapper.h" + +#include +#include + +#ifdef OPENJPEG_MAJOR_VERSION +#if OPENJPEG_MAJOR_VERSION == 1 +#include "gdcm_openjpeg.h" +#elif OPENJPEG_MAJOR_VERSION == 2 +#define USE_OPJ_DEPRECATED // opj_setup_decoder +#include "gdcm_openjpeg2.h" +#else +#error should not happen +#endif +#else +#error should not happen +#endif + +namespace gdcm +{ + +/** +sample error callback expecting a FILE* client object +*/ +void error_callback(const char *msg, void *) { + (void)msg; + gdcmErrorMacro( "Error in gdcmopenjpeg" << msg ); +} +/** +sample warning callback expecting a FILE* client object +*/ +void warning_callback(const char *msg, void *) { + (void)msg; + gdcmWarningMacro( "Warning in gdcmopenjpeg" << msg ); +} +/** +sample debug callback expecting no client object +*/ +void info_callback(const char *msg, void *) { + (void)msg; + gdcmDebugMacro( "Info in gdcmopenjpeg" << msg ); +} + +#define J2K_CFMT 0 +#define JP2_CFMT 1 +#define JPT_CFMT 2 + +#if OPENJPEG_MAJOR_VERSION == 1 +#define MJ2_CFMT 3 +#define PXM_DFMT 0 +#define PGX_DFMT 1 +#define BMP_DFMT 2 +#define YUV_DFMT 3 +#elif OPENJPEG_MAJOR_VERSION == 2 +#define PXM_DFMT 10 +#define PGX_DFMT 11 +#define BMP_DFMT 12 +#define YUV_DFMT 13 +#define TIF_DFMT 14 +#define RAW_DFMT 15 +#define TGA_DFMT 16 +#define PNG_DFMT 17 +#endif // OPENJPEG_MAJOR_VERSION == 1 + +#if OPENJPEG_MAJOR_VERSION == 2 +struct myfile +{ + char *mem; + char *cur; + size_t len; +}; + +void gdcm_error_callback(const char* msg, void* f) +{ + if( strcmp( msg, "Cannot read data with no size known, giving up\n" ) == 0 ) + { + OPJ_UINT32 **s = (OPJ_UINT32**)f; + *s[1] = *s[0]; + gdcmWarningMacro( "Recovering from odd J2K file" ); + } +// else +// { +// fprintf( stderr, msg ); +// } +} + + +OPJ_UINT32 opj_read_from_memory(void * p_buffer, OPJ_UINT32 p_nb_bytes, myfile* p_file) +{ + //OPJ_UINT32 l_nb_read = fread(p_buffer,1,p_nb_bytes,p_file); + OPJ_UINT32 l_nb_read; + if( p_file->cur + p_nb_bytes < p_file->mem + p_file->len ) + { + l_nb_read = 1*p_nb_bytes; + } + else + { + l_nb_read = (OPJ_UINT32)(p_file->mem + p_file->len - p_file->cur); + assert( l_nb_read < p_nb_bytes ); + } + memcpy(p_buffer,p_file->cur,l_nb_read); + p_file->cur += l_nb_read; + assert( p_file->cur <= p_file->mem + p_file->len ); + //std::cout << "l_nb_read: " << l_nb_read << std::endl; + return l_nb_read ? l_nb_read : ((OPJ_UINT32)-1); +} + +OPJ_UINT32 opj_write_from_memory (void * p_buffer, OPJ_UINT32 p_nb_bytes, myfile* p_file) +{ + //return fwrite(p_buffer,1,p_nb_bytes,p_file); + OPJ_UINT32 l_nb_write; + //if( p_file->cur + p_nb_bytes < p_file->mem + p_file->len ) + // { + l_nb_write = 1*p_nb_bytes; + // } + //else + // { + // l_nb_write = p_file->mem + p_file->len - p_file->cur; + // assert( l_nb_write < p_nb_bytes ); + // } + memcpy(p_file->cur,p_buffer,l_nb_write); + p_file->cur += l_nb_write; + p_file->len += l_nb_write; + //assert( p_file->cur < p_file->mem + p_file->len ); + return l_nb_write; + //return p_nb_bytes; +} + +OPJ_SIZE_T opj_skip_from_memory (OPJ_SIZE_T p_nb_bytes, myfile * p_file) +{ + //if (fseek(p_user_data,p_nb_bytes,SEEK_CUR)) + // { + // return -1; + // } + if( p_file->cur + p_nb_bytes < p_file->mem + p_file->len ) + { + p_file->cur += p_nb_bytes; + return p_nb_bytes; + } + + p_file->cur = p_file->mem + p_file->len; + return (OPJ_SIZE_T)-1; +} + +bool opj_seek_from_memory (OPJ_SIZE_T p_nb_bytes, myfile * p_file) +{ + //if (fseek(p_user_data,p_nb_bytes,SEEK_SET)) + // { + // return false; + // } + //return true; + if( p_file->cur + p_nb_bytes < p_file->mem + p_file->len ) + { + p_file->cur += p_nb_bytes; + return true; + } + p_file->cur = p_file->mem + p_file->len; + return false; +} + +opj_stream_t* OPJ_CALLCONV opj_stream_create_memory_stream (myfile* p_mem,OPJ_UINT32 p_size,bool p_is_read_stream) +{ + opj_stream_t* l_stream = 00; + if + (! p_mem) + { + return 00; + } + l_stream = opj_stream_create(p_size,p_is_read_stream); + if + (! l_stream) + { + return 00; + } + opj_stream_set_user_data(l_stream,p_mem); + opj_stream_set_read_function(l_stream,(opj_stream_read_fn) opj_read_from_memory); + opj_stream_set_write_function(l_stream, (opj_stream_write_fn) opj_write_from_memory); + opj_stream_set_skip_function(l_stream, (opj_stream_skip_fn) opj_skip_from_memory); + opj_stream_set_seek_function(l_stream, (opj_stream_seek_fn) opj_seek_from_memory); + return l_stream; +} + +#endif // OPENJPEG_MAJOR_VERSION == 2 + +/* + * Divide an integer by a power of 2 and round upwards. + * + * a divided by 2^b + */ +inline int int_ceildivpow2(int a, int b) { + return (a + (1 << b) - 1) >> b; +} + +class JPEG2000Internals +{ +public: + JPEG2000Internals() + { + memset(&coder_param, 0, sizeof(coder_param)); + opj_set_default_encoder_parameters(&coder_param); + } + + opj_cparameters coder_param; +}; + +void JPEG2000Codec::SetRate(unsigned int idx, double rate) +{ + Internals->coder_param.tcp_rates[idx] = (float)rate; + if( Internals->coder_param.tcp_numlayers <= (int)idx ) + { + Internals->coder_param.tcp_numlayers = idx + 1; + } + Internals->coder_param.cp_disto_alloc = 1; +} + +double JPEG2000Codec::GetRate(unsigned int idx ) const +{ + return Internals->coder_param.tcp_rates[idx]; +} + +void JPEG2000Codec::SetQuality(unsigned int idx, double q) +{ + Internals->coder_param.tcp_distoratio[idx] = (float)q; + if( Internals->coder_param.tcp_numlayers <= (int)idx ) + { + Internals->coder_param.tcp_numlayers = idx + 1; + } + Internals->coder_param.cp_fixed_quality = 1; +} + +double JPEG2000Codec::GetQuality(unsigned int idx) const +{ + return Internals->coder_param.tcp_distoratio[idx]; +} + +void JPEG2000Codec::SetTileSize(unsigned int tx, unsigned int ty) +{ + Internals->coder_param.cp_tdx = tx; + Internals->coder_param.cp_tdy = ty; + Internals->coder_param.tile_size_on = true; +} + +void JPEG2000Codec::SetNumberOfResolutions(unsigned int nres) +{ + Internals->coder_param.numresolution = nres; +} + +void JPEG2000Codec::SetReversible(bool res) +{ + Internals->coder_param.irreversible = !res; +} + +JPEG2000Codec::JPEG2000Codec() +{ + Internals = new JPEG2000Internals; +} + +JPEG2000Codec::~JPEG2000Codec() +{ + delete Internals; +} + +bool JPEG2000Codec::CanDecode(TransferSyntax const &ts) const +{ + return ts == TransferSyntax::JPEG2000Lossless + || ts == TransferSyntax::JPEG2000 + || ts == TransferSyntax::JPEG2000Part2Lossless + || ts == TransferSyntax::JPEG2000Part2; +} + +bool JPEG2000Codec::CanCode(TransferSyntax const &ts) const +{ + return ts == TransferSyntax::JPEG2000Lossless + || ts == TransferSyntax::JPEG2000 + || ts == TransferSyntax::JPEG2000Part2Lossless + || ts == TransferSyntax::JPEG2000Part2; +} + +/* +A.4.4 JPEG 2000 image compression + + If the object allows multi-frame images in the pixel data field, then for these JPEG 2000 Part 1 Transfer + Syntaxes, each frame shall be encoded separately. Each fragment shall contain encoded data from a + single frame. + Note: That is, the processes defined in ISO/IEC 15444-1 shall be applied on a per-frame basis. The proposal + for encapsulation of multiple frames in a non-DICOM manner in so-called ¿Motion-JPEG¿ or ¿M-JPEG¿ + defined in 15444-3 is not used. +*/ +bool JPEG2000Codec::Decode(DataElement const &in, DataElement &out) +{ + if( NumberOfDimensions == 2 ) + { + const SequenceOfFragments *sf = in.GetSequenceOfFragments(); + const ByteValue *j2kbv = in.GetByteValue(); + if( !sf && !j2kbv ) return false; + SmartPointer sf_bug = new SequenceOfFragments; + if ( j2kbv ) + { + gdcmWarningMacro( "Pixel Data is not encapsulated correctly. Continuing anyway" ); + assert( !sf ); + std::stringstream is; + size_t j2kbv_len = j2kbv->GetLength(); + char *mybuffer = new char[j2kbv_len]; + bool b = j2kbv->GetBuffer(mybuffer, j2kbv_len); + assert( b ); + if( b ) is.write(mybuffer, j2kbv_len); + delete[] mybuffer; + + try { + sf_bug->Read(is,true); + } catch ( ... ) { + return false; + } + sf = &*sf_bug; + } + if( !sf ) return false; + std::stringstream is; + unsigned long totalLen = sf->ComputeByteLength(); + char *buffer = new char[totalLen]; + sf->GetBuffer(buffer, totalLen); + is.write(buffer, totalLen); + delete[] buffer; + std::stringstream os; + bool r = DecodeByStreams(is, os); + if(!r) return false; + out = in; + std::string str = os.str(); + out.SetByteValue( &str[0], (uint32_t)str.size() ); + //memcpy(buffer, os.str().c_str(), len); + return r; + } + else if ( NumberOfDimensions == 3 ) + { + /* I cannot figure out how to use openjpeg to support multiframes + * as encoded in DICOM + * MM: Hack. If we are lucky enough the number of encapsulated fragments actually match + * the number of Z frames. + * MM: hopefully this is the standard so people are following it ... + */ + //#ifdef SUPPORT_MULTIFRAMESJ2K_ONLY + const SequenceOfFragments *sf = in.GetSequenceOfFragments(); + if( !sf ) return false; + std::stringstream os; + if( sf->GetNumberOfFragments() != Dimensions[2] ) + { + gdcmErrorMacro( "Not handled" ); + return false; + } + for(unsigned int i = 0; i < sf->GetNumberOfFragments(); ++i) + { + std::stringstream is; + const Fragment &frag = sf->GetFragment(i); + if( frag.IsEmpty() ) return false; + const ByteValue *bv = frag.GetByteValue(); + assert( bv ); + size_t bv_len = bv->GetLength(); + char *mybuffer = new char[bv_len]; + bv->GetBuffer(mybuffer, bv->GetLength()); + is.write(mybuffer, bv->GetLength()); + delete[] mybuffer; + bool r = DecodeByStreams(is, os); + if(!r) return false; + assert( r == true ); + } + std::string str = os.str(); + assert( str.size() ); + out.SetByteValue( &str[0], (uint32_t)str.size() ); + + return true; + } + // else + return false; +} + +std::pair JPEG2000Codec::DecodeByStreamsCommon(char *dummy_buffer, size_t buf_size) +{ + opj_dparameters_t parameters; /* decompression parameters */ +#if OPENJPEG_MAJOR_VERSION == 1 + opj_event_mgr_t event_mgr; /* event manager */ + opj_dinfo_t* dinfo; /* handle to a decompressor */ + opj_cio_t *cio; +#elif OPENJPEG_MAJOR_VERSION == 2 + opj_codec_t* dinfo = NULL; /* handle to a decompressor */ + opj_stream_t *cio = NULL; +#endif // OPENJPEG_MAJOR_VERSION == 1 + opj_image_t *image = NULL; + + unsigned char *src = (unsigned char*)dummy_buffer; + uint32_t file_length = (uint32_t)buf_size; // 32bits truncation should be ok since DICOM cannot have larger than 2Gb image + + // WARNING: OpenJPEG is very picky when there is a trailing 00 at the end of the JPC + // so we need to make sure to remove it: + // See for example: DX_J2K_0Padding.dcm + // and D_CLUNIE_CT1_J2KR.dcm + // Marker 0xffd9 EOI End of Image (JPEG 2000 EOC End of codestream) + // gdcmData/D_CLUNIE_CT1_J2KR.dcm contains a trailing 0xFF which apparently is ok... + while( file_length > 0 && src[file_length-1] != 0xd9 ) + { + file_length--; + } + // what if 0xd9 is never found ? + assert( file_length > 0 && src[file_length-1] == 0xd9 ); + +#if OPENJPEG_MAJOR_VERSION == 1 + /* configure the event callbacks (not required) */ + memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); + event_mgr.error_handler = error_callback; + event_mgr.warning_handler = warning_callback; + event_mgr.info_handler = info_callback; +#endif // OPENJPEG_MAJOR_VERSION == 1 + + /* set decoding parameters to default values */ + opj_set_default_decoder_parameters(¶meters); + +#if OPENJPEG_MAJOR_VERSION == 1 + // default blindly copied + parameters.cp_layer=0; + parameters.cp_reduce=0; + // parameters.decod_format=-1; + // parameters.cod_format=-1; +#endif + + const char jp2magic[] = "\x00\x00\x00\x0C\x6A\x50\x20\x20\x0D\x0A\x87\x0A"; + if( memcmp( src, jp2magic, sizeof(jp2magic) ) == 0 ) + { + /* JPEG-2000 compressed image data ... sigh */ + // gdcmData/ELSCINT1_JP2vsJ2K.dcm + // gdcmData/MAROTECH_CT_JP2Lossy.dcm + gdcmWarningMacro( "J2K start like JPEG-2000 compressed image data instead of codestream" ); + parameters.decod_format = JP2_CFMT; + assert(parameters.decod_format == JP2_CFMT); + } + else + { + /* JPEG-2000 codestream */ + parameters.decod_format = J2K_CFMT; + assert(parameters.decod_format == J2K_CFMT); + } + parameters.cod_format = PGX_DFMT; + assert(parameters.cod_format == PGX_DFMT); + + /* get a decoder handle */ + switch(parameters.decod_format) + { + case J2K_CFMT: + dinfo = opj_create_decompress(CODEC_J2K); + break; + case JP2_CFMT: + dinfo = opj_create_decompress(CODEC_JP2); + break; + default: + gdcmErrorMacro( "Impossible happen" ); + return std::make_pair(0,0); + } + + int reversible; +#if OPENJPEG_MAJOR_VERSION == 1 + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, NULL); + + /* setup the decoder decoding parameters using user parameters */ + opj_setup_decoder(dinfo, ¶meters); + + /* open a byte stream */ + cio = opj_cio_open((opj_common_ptr)dinfo, src, file_length); + + /* decode the stream and fill the image structure */ + image = opj_decode(dinfo, cio); + if(!image) { + opj_destroy_decompress(dinfo); + opj_cio_close(cio); + gdcmErrorMacro( "opj_decode failed" ); + return std::make_pair(0,0); + } +#elif OPENJPEG_MAJOR_VERSION == 2 + myfile mysrc; + myfile *fsrc = &mysrc; + fsrc->mem = fsrc->cur = (char*)src; + fsrc->len = file_length; + + OPJ_UINT32 *s[2]; + // the following hack is used for the file: DX_J2K_0Padding.dcm + // see the function j2k_read_sot in openjpeg (line: 5946) + // to deal with zero length Psot + OPJ_UINT32 fl = file_length - 100; + s[0] = &fl; + s[1] = 0; + opj_set_error_handler(dinfo, gdcm_error_callback, s); + + cio = opj_stream_create_memory_stream(fsrc,J2K_STREAM_CHUNK_SIZE, true); + + /* setup the decoder decoding parameters using user parameters */ + opj_setup_decoder(dinfo, ¶meters); + bool bResult; + OPJ_INT32 l_tile_x0,l_tile_y0; + OPJ_UINT32 l_tile_width,l_tile_height,l_nb_tiles_x,l_nb_tiles_y; + bResult = opj_read_header( + dinfo, + &image, + &l_tile_x0, + &l_tile_y0, + &l_tile_width, + &l_tile_height, + &l_nb_tiles_x, + &l_nb_tiles_y, + cio); + assert( bResult ); + +#if OPENJPEG_MAJOR_VERSION == 1 +#else + // needs to be before call to opj_decode... + reversible = opj_get_reversible(dinfo, ¶meters ); + assert( reversible == 0 || reversible == 1 ); +#endif + + image = opj_decode(dinfo, cio); + //assert( image ); + bResult = bResult && (image != 00); + bResult = bResult && opj_end_decompress(dinfo,cio); + if (!image) + { + opj_destroy_codec(dinfo); + opj_stream_destroy(cio); + gdcmErrorMacro( "opj_decode failed" ); + return std::make_pair(0,0); + } +#endif // OPENJPEG_MAJOR_VERSION == 1 + +#if 0 + if( image->color_space ) + { + if( image->color_space == CLRSPC_GRAY ) + { + assert( this->GetPhotometricInterpretation() == PhotometricInterpretation::MONOCHROME2 + || this->GetPhotometricInterpretation() == PhotometricInterpretation::MONOCHROME1 + || this->GetPhotometricInterpretation() == PhotometricInterpretation::PALETTE_COLOR ); + } + else if( image->color_space == CLRSPC_SRGB ) + { + assert( this->GetPhotometricInterpretation() == PhotometricInterpretation::RGB ); + } + else + { + assert(0); + } + } +#endif + +#if OPENJPEG_MAJOR_VERSION == 1 + opj_j2k_t* j2k = NULL; + opj_jp2_t* jp2 = NULL; + + switch(parameters.decod_format) + { + case J2K_CFMT: + j2k = (opj_j2k_t*)dinfo->j2k_handle; + assert( j2k ); + reversible = j2k->cp->tcps->tccps->qmfbid; + break; + case JP2_CFMT: + jp2 = (opj_jp2_t*)dinfo->jp2_handle; + assert( jp2 ); + reversible = jp2->j2k->cp->tcps->tccps->qmfbid; + break; + default: + gdcmErrorMacro( "Impossible happen" ); + return std::make_pair(0,0); + } +#endif // OPENJPEG_MAJOR_VERSION == 1 + LossyFlag = !reversible; + +#if 0 +#ifndef GDCM_USE_SYSTEM_OPENJPEG + if( j2k ) + j2k_dump_cp(stdout, image, j2k->cp); + if( jp2 ) + j2k_dump_cp(stdout, image, jp2->j2k->cp); +#endif +#endif + + assert( image->numcomps == this->GetPixelFormat().GetSamplesPerPixel() ); + assert( image->numcomps == this->GetPhotometricInterpretation().GetSamplesPerPixel() ); + +#if OPENJPEG_MAJOR_VERSION == 1 + /* close the byte stream */ + opj_cio_close(cio); +#elif OPENJPEG_MAJOR_VERSION == 2 + /* close the byte stream */ + opj_stream_destroy(cio); +#endif // OPENJPEG_MAJOR_VERSION == 1 + + // Copy buffer + unsigned long len = Dimensions[0]*Dimensions[1] * (PF.GetBitsAllocated() / 8) * image->numcomps; + char *raw = new char[len]; + //assert( len == fsrc->len ); + for (unsigned int compno = 0; compno < (unsigned int)image->numcomps; compno++) + { + opj_image_comp_t *comp = &image->comps[compno]; + + int w = image->comps[compno].w; + int wr = int_ceildivpow2(image->comps[compno].w, image->comps[compno].factor); + + //int h = image.comps[compno].h; + int hr = int_ceildivpow2(image->comps[compno].h, image->comps[compno].factor); + //assert( wr * hr * 1 * image->numcomps * (comp->prec/8) == len ); + + // ELSCINT1_JP2vsJ2K.dcm + // -> prec = 12, bpp = 0, sgnd = 0 + //assert( wr == Dimensions[0] ); + //assert( hr == Dimensions[1] ); +#if OPENJPEG_MAJOR_VERSION == 1 + if( comp->bpp == PF.GetBitsAllocated() ) + { + gdcmWarningMacro( "BPP = " << comp->bpp << " vs BitsAllocated = " << PF.GetBitsAllocated() ); + } +#endif // OPENJPEG_MAJOR_VERSION == 1 + + if( comp->sgnd != PF.GetPixelRepresentation() ) + { + PF.SetPixelRepresentation( (uint16_t)comp->sgnd ); + } +#ifndef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + assert( comp->prec == PF.GetBitsStored()); // D_CLUNIE_RG3_JPLY.dcm + assert( comp->prec - 1 == PF.GetHighBit()); +#endif + //assert( comp->prec >= PF.GetBitsStored()); + if( comp->prec != PF.GetBitsStored() ) + { + PF.SetBitsStored( (unsigned short)comp->prec ); + PF.SetHighBit( (unsigned short)(comp->prec - 1) ); // ?? + } + assert( PF.IsValid() ); + assert( comp->prec <= 32 ); + + if (comp->prec <= 8) + { + uint8_t *data8 = (uint8_t*)raw + compno; + for (int i = 0; i < wr * hr; i++) + { + int v = image->comps[compno].data[i / wr * w + i % wr]; + *data8 = (uint8_t)v; + data8 += image->numcomps; + } + } + else if (comp->prec <= 16) + { + // ELSCINT1_JP2vsJ2K.dcm is a 12bits image + uint16_t *data16 = (uint16_t*)raw + compno; + for (int i = 0; i < wr * hr; i++) + { + int v = image->comps[compno].data[i / wr * w + i % wr]; + *data16 = (uint16_t)v; + data16 += image->numcomps; + } + } + else + { + uint32_t *data32 = (uint32_t*)raw + compno; + for (int i = 0; i < wr * hr; i++) + { + int v = image->comps[compno].data[i / wr * w + i % wr]; + *data32 = (uint32_t)v; + data32 += image->numcomps; + } + } + } + +#if OPENJPEG_MAJOR_VERSION == 1 + /* free remaining structures */ + if(dinfo) { + opj_destroy_decompress(dinfo); + } +#elif OPENJPEG_MAJOR_VERSION == 2 + /* free remaining structures */ + if (dinfo) + { + opj_destroy_codec(dinfo); + } +#endif // OPENJPEG_MAJOR_VERSION == 1 + + /* free image data structure */ + opj_image_destroy(image); + + return std::make_pair(raw,len); +} + +bool JPEG2000Codec::DecodeByStreams(std::istream &is, std::ostream &os) +{ + // FIXME: Do some stupid work: + is.seekg( 0, std::ios::end); + size_t buf_size = (size_t)is.tellg(); + char *dummy_buffer = new char[buf_size]; + is.seekg(0, std::ios::beg); + is.read( dummy_buffer, buf_size); + + std::pair raw_len = this->DecodeByStreamsCommon(dummy_buffer, buf_size); + /* free the memory containing the code-stream */ + delete[] dummy_buffer; + + if( !raw_len.first || !raw_len.second ) return false; + os.write( raw_len.first, raw_len.second); + delete[] raw_len.first; + return true; +} + +template +void rawtoimage_fill(T *inputbuffer, int w, int h, int numcomps, opj_image_t *image, int pc) +{ + T *p = inputbuffer; + if( pc ) + { + for(int compno = 0; compno < numcomps; compno++) + { + for (int i = 0; i < w * h; i++) + { + /* compno : 0 = GREY, (0, 1, 2) = (R, G, B) */ + image->comps[compno].data[i] = *p; + ++p; + } + } + } + else + { + for (int i = 0; i < w * h; i++) + { + for(int compno = 0; compno < numcomps; compno++) + { + /* compno : 0 = GREY, (0, 1, 2) = (R, G, B) */ + image->comps[compno].data[i] = *p; + ++p; + } + } + } +} + +opj_image_t* rawtoimage(char *inputbuffer, opj_cparameters_t *parameters, + int fragment_size, int image_width, int image_height, int sample_pixel, + int bitsallocated, int bitsstored, int sign, int quality, int pc) +{ + (void)quality; + (void)fragment_size; + int w, h; + int numcomps; + OPJ_COLOR_SPACE color_space; + opj_image_cmptparm_t cmptparm[3]; /* maximum of 3 components */ + opj_image_t * image = NULL; + + assert( sample_pixel == 1 || sample_pixel == 3 ); + if( sample_pixel == 1 ) + { + numcomps = 1; + color_space = CLRSPC_GRAY; + } + else // sample_pixel == 3 + { + numcomps = 3; + color_space = CLRSPC_SRGB; + /* Does OpenJPEg support: CLRSPC_SYCC ?? */ + } + if( bitsallocated % 8 != 0 ) + { + gdcmDebugMacro( "BitsAllocated is not % 8" ); + return 0; + } + assert( bitsallocated % 8 == 0 ); + // eg. fragment_size == 63532 and 181 * 117 * 3 * 8 == 63531 ... + assert( ((fragment_size + 1)/2 ) * 2 == ((image_height * image_width * numcomps * (bitsallocated/8) + 1)/ 2 )* 2 ); + int subsampling_dx = parameters->subsampling_dx; + int subsampling_dy = parameters->subsampling_dy; + + // FIXME + w = image_width; + h = image_height; + + /* initialize image components */ + memset(&cmptparm[0], 0, 3 * sizeof(opj_image_cmptparm_t)); + //assert( bitsallocated == 8 ); + for(int i = 0; i < numcomps; i++) { + cmptparm[i].prec = bitsstored; + cmptparm[i].bpp = bitsallocated; + cmptparm[i].sgnd = sign; + cmptparm[i].dx = subsampling_dx; + cmptparm[i].dy = subsampling_dy; + cmptparm[i].w = w; + cmptparm[i].h = h; + } + + /* create the image */ + image = opj_image_create(numcomps, &cmptparm[0], color_space); + if(!image) { + return NULL; + } + /* set image offset and reference grid */ + image->x0 = parameters->image_offset_x0; + image->y0 = parameters->image_offset_y0; + image->x1 = parameters->image_offset_x0 + (w - 1) * subsampling_dx + 1; + image->y1 = parameters->image_offset_y0 + (h - 1) * subsampling_dy + 1; + + /* set image data */ + + //assert( fragment_size == numcomps*w*h*(bitsallocated/8) ); + if (bitsallocated <= 8) + { + if( sign ) + { + rawtoimage_fill((int8_t*)inputbuffer,w,h,numcomps,image,pc); + } + else + { + rawtoimage_fill((uint8_t*)inputbuffer,w,h,numcomps,image,pc); + } + } + else if (bitsallocated <= 16) + { + if( sign ) + { + rawtoimage_fill((int16_t*)inputbuffer,w,h,numcomps,image,pc); + } + else + { + rawtoimage_fill((uint16_t*)inputbuffer,w,h,numcomps,image,pc); + } + } + else if (bitsallocated <= 32) + { + if( sign ) + { + rawtoimage_fill((int32_t*)inputbuffer,w,h,numcomps,image,pc); + } + else + { + rawtoimage_fill((uint32_t*)inputbuffer,w,h,numcomps,image,pc); + } + } + else + { + return NULL; + } + + return image; +} + + // Compress into JPEG +bool JPEG2000Codec::Code(DataElement const &in, DataElement &out) +{ + out = in; + if( NeedOverlayCleanup ) + { + gdcmErrorMacro( "TODO" ); + return false; + } + + // + // Create a Sequence Of Fragments: + SmartPointer sq = new SequenceOfFragments; + + const unsigned int *dims = this->GetDimensions(); + + const ByteValue *bv = in.GetByteValue(); + const char *input = bv->GetPointer(); + unsigned long len = bv->GetLength(); + unsigned long image_len = len / dims[2]; + size_t inputlength = image_len; + + for(unsigned int dim = 0; dim < dims[2]; ++dim) + { + std::ostringstream os; + std::ostream *fp = &os; + const char *inputdata = input + dim * image_len; //bv->GetPointer(); + //size_t inputlength = bv->GetLength(); + int image_width = dims[0]; + int image_height = dims[1]; + int numZ = 0; //dims[2]; + const PixelFormat &pf = this->GetPixelFormat(); + int sample_pixel = pf.GetSamplesPerPixel(); + int bitsallocated = pf.GetBitsAllocated(); +#ifndef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + int bitsstored = pf.GetBitsStored(); +#else + // Usual D_CLUNIE_RG3_JPLY.dcm kludge: + int bitsstored = pf.GetBitsAllocated(); +#endif + int sign = pf.GetPixelRepresentation(); + int quality = 100; + + //// input_buffer is ONE image + //// fragment_size is the size of this image (fragment) + (void)numZ; + bool bSuccess; + //bool delete_comment = true; + opj_cparameters_t parameters; /* compression parameters */ +#if OPENJPEG_MAJOR_VERSION == 1 + opj_event_mgr_t event_mgr; /* event manager */ +#endif // OPENJPEG_MAJOR_VERSION == 1 + opj_image_t *image = NULL; + //quality = 100; + +#if OPENJPEG_MAJOR_VERSION == 1 + /* + configure the event callbacks (not required) + setting of each callback is optionnal + */ + memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); + event_mgr.error_handler = error_callback; + event_mgr.warning_handler = warning_callback; + event_mgr.info_handler = info_callback; +#endif // OPENJPEG_MAJOR_VERSION == 1 + + /* set encoding parameters to default values */ + //memset(¶meters, 0, sizeof(parameters)); + //opj_set_default_encoder_parameters(¶meters); + + memcpy(¶meters, &(Internals->coder_param), sizeof(parameters)); + + if ((parameters.cp_disto_alloc || parameters.cp_fixed_alloc || parameters.cp_fixed_quality) + && (!(parameters.cp_disto_alloc ^ parameters.cp_fixed_alloc ^ parameters.cp_fixed_quality))) + { + gdcmErrorMacro( "Error: options -r -q and -f cannot be used together." ); + return false; + } /* mod fixed_quality */ + + /* if no rate entered, lossless by default */ + if (parameters.tcp_numlayers == 0) + { + parameters.tcp_rates[0] = 0; + parameters.tcp_numlayers = 1; + parameters.cp_disto_alloc = 1; + } + + if(parameters.cp_comment == NULL) { + const char comment[] = "Created by GDCM/OpenJPEG version 2.0"; + parameters.cp_comment = (char*)malloc(strlen(comment) + 1); + strcpy(parameters.cp_comment, comment); + /* no need to delete parameters.cp_comment on exit */ + //delete_comment = false; + } + + // Compute the proper number of resolutions to use. + // This is mostly done for images smaller than 64 pixels + // along any dimension. + unsigned int numberOfResolutions = 0; + + unsigned int tw = image_width >> 1; + unsigned int th = image_height >> 1; + + while( tw && th ) + { + numberOfResolutions++; + tw >>= 1; + th >>= 1; + } + + // Clamp the number of resolutions to 6. + if( numberOfResolutions > 6 ) + { + numberOfResolutions = 6; + } + + parameters.numresolution = numberOfResolutions; + + + /* decode the source image */ + /* ----------------------- */ + + image = rawtoimage((char*)inputdata, ¶meters, + static_cast( inputlength ), + image_width, image_height, + sample_pixel, bitsallocated, bitsstored, sign, quality, this->GetPlanarConfiguration() ); + if (!image) { + return false; + } + + /* encode the destination image */ + /* ---------------------------- */ + parameters.cod_format = J2K_CFMT; /* J2K format output */ + size_t codestream_length; +#if OPENJPEG_MAJOR_VERSION == 1 + opj_cio_t *cio = NULL; + + /* get a J2K compressor handle */ + opj_cinfo_t* cinfo = opj_create_compress(CODEC_J2K); + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)cinfo, &event_mgr, stderr); + + /* setup the encoder parameters using the current image and using user parameters */ + opj_setup_encoder(cinfo, ¶meters, image); + + /* open a byte stream for writing */ + /* allocate memory for all tiles */ + cio = opj_cio_open((opj_common_ptr)cinfo, NULL, 0); + + /* encode the image */ + bSuccess = opj_encode(cinfo, cio, image, parameters.index); + if (!bSuccess) { + opj_cio_close(cio); + fprintf(stderr, "failed to encode image\n"); + return false; + } + codestream_length = cio_tell(cio); +#elif OPENJPEG_MAJOR_VERSION == 2 + opj_codec_t* cinfo = 00; + opj_stream_t *cio = 00; + + /* get a J2K compressor handle */ + cinfo = opj_create_compress(CODEC_J2K); + + /* setup the encoder parameters using the current image and using user parameters */ + opj_setup_encoder(cinfo, ¶meters, image); + + myfile mysrc; + myfile *fsrc = &mysrc; + char *buffer_j2k = new char[image_len]; // overallocated + fsrc->mem = fsrc->cur = buffer_j2k; + fsrc->len = 0; + + /* open a byte stream for writing */ + /* allocate memory for all tiles */ + cio = opj_stream_create_memory_stream(fsrc,J2K_STREAM_CHUNK_SIZE,false); + if (! cio) + { + return false; + } + /* encode the image */ + /*if (*indexfilename) // If need to extract codestream information + bSuccess = opj_encode_with_info(cinfo, cio, image, &cstr_info); + else*/ + bSuccess = opj_start_compress(cinfo,image,cio); + bSuccess = bSuccess && opj_encode(cinfo, cio); + bSuccess = bSuccess && opj_end_compress(cinfo, cio); + + if (!bSuccess) + { + opj_stream_destroy(cio); + return false; + } + codestream_length = mysrc.len; +#endif // OPENJPEG_MAJOR_VERSION == 1 + + /* write the buffer to disk */ + //f = fopen(parameters.outfile, "wb"); + //if (!f) { + // fprintf(stderr, "failed to open %s for writing\n", parameters.outfile); + // return 1; + //} + //fwrite(cio->buffer, 1, codestream_length, f); + //#define MDEBUG +#ifdef MDEBUG + static int c = 0; + std::ostringstream os; + os << "/tmp/debug"; + os << c; + c++; + os << ".j2k"; + std::ofstream debug(os.str().c_str(), std::ios::binary); + debug.write((char*)(cio->buffer), codestream_length); + debug.close(); +#endif + +#if OPENJPEG_MAJOR_VERSION == 1 + fp->write((char*)(cio->buffer), codestream_length); + + /* close and free the byte stream */ + opj_cio_close(cio); + + /* free remaining compression structures */ + opj_destroy_compress(cinfo); +#elif OPENJPEG_MAJOR_VERSION == 2 + fp->write((char*)(mysrc.mem), codestream_length); + delete [] buffer_j2k; + + /* close and free the byte stream */ + opj_stream_destroy(cio); + + /* free remaining compression structures */ + opj_destroy_codec(cinfo); +#endif // OPENJPEG_MAJOR_VERSION == 1 + + /* free user parameters structure */ + //if(delete_comment) { + if(parameters.cp_comment) free(parameters.cp_comment); + //} + if(parameters.cp_matrice) free(parameters.cp_matrice); + + /* free image data */ + opj_image_destroy(image); + + std::string str = os.str(); + assert( str.size() ); + Fragment frag; + frag.SetByteValue( &str[0], (uint32_t)str.size() ); + sq->AddFragment( frag ); + } + + //unsigned int nfrags = sq->GetNumberOfFragments(); + assert( sq->GetNumberOfFragments() == dims[2] ); + out.SetValue( *sq ); + + return true; +} + +bool JPEG2000Codec::GetHeaderInfo(std::istream &is, TransferSyntax &ts) +{ + // FIXME: Do some stupid work: + is.seekg( 0, std::ios::end); + size_t buf_size = (size_t)is.tellg(); + char *dummy_buffer = new char[buf_size]; + is.seekg(0, std::ios::beg); + is.read( dummy_buffer, buf_size); + bool b = GetHeaderInfo( dummy_buffer, (size_t)buf_size, ts ); + delete[] dummy_buffer; + return b; +} + +bool JPEG2000Codec::GetHeaderInfo(const char * dummy_buffer, size_t buf_size, TransferSyntax &ts) +{ + opj_dparameters_t parameters; /* decompression parameters */ +#if OPENJPEG_MAJOR_VERSION == 1 + opj_event_mgr_t event_mgr; /* event manager */ + opj_dinfo_t* dinfo; /* handle to a decompressor */ + opj_cio_t *cio; +#elif OPENJPEG_MAJOR_VERSION == 2 + opj_codec_t* dinfo = NULL; /* handle to a decompressor */ + opj_stream_t *cio = NULL; +#endif // OPENJPEG_MAJOR_VERSION == 1 + opj_image_t *image = NULL; + unsigned char *src = (unsigned char*)dummy_buffer; + size_t file_length = buf_size; + +#if OPENJPEG_MAJOR_VERSION == 1 + /* configure the event callbacks (not required) */ + memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); + event_mgr.error_handler = error_callback; + event_mgr.warning_handler = warning_callback; + event_mgr.info_handler = info_callback; +#endif // OPENJPEG_MAJOR_VERSION == 1 + + /* set decoding parameters to default values */ + opj_set_default_decoder_parameters(¶meters); + +#if OPENJPEG_MAJOR_VERSION == 1 + // default blindly copied + parameters.cp_layer=0; + parameters.cp_reduce=0; + // parameters.decod_format=-1; + // parameters.cod_format=-1; +#endif + + const char jp2magic[] = "\x00\x00\x00\x0C\x6A\x50\x20\x20\x0D\x0A\x87\x0A"; + if( memcmp( src, jp2magic, sizeof(jp2magic) ) == 0 ) + { + /* JPEG-2000 compressed image data */ + // gdcmData/ELSCINT1_JP2vsJ2K.dcm + gdcmWarningMacro( "J2K start like JPEG-2000 compressed image data instead of codestream" ); + parameters.decod_format = JP2_CFMT; + assert(parameters.decod_format == JP2_CFMT); + } + else + { + /* JPEG-2000 codestream */ + parameters.decod_format = J2K_CFMT; + assert(parameters.decod_format == J2K_CFMT); + } + parameters.cod_format = PGX_DFMT; + assert(parameters.cod_format == PGX_DFMT); + + /* get a decoder handle */ + switch(parameters.decod_format ) + { + case J2K_CFMT: + dinfo = opj_create_decompress(CODEC_J2K); + break; + case JP2_CFMT: + dinfo = opj_create_decompress(CODEC_JP2); + break; + default: + gdcmErrorMacro( "Impossible happen" ); + return false; + } + +#if OPENJPEG_MAJOR_VERSION == 1 + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, NULL); + + /* setup the decoder decoding parameters using user parameters */ + opj_setup_decoder(dinfo, ¶meters); + + /* open a byte stream */ + cio = opj_cio_open((opj_common_ptr)dinfo, src, (int)file_length); + + /* decode the stream and fill the image structure */ + image = opj_decode(dinfo, cio); + if(!image) { + opj_destroy_decompress(dinfo); + opj_cio_close(cio); + gdcmErrorMacro( "opj_decode failed" ); + return false; + } +#elif OPENJPEG_MAJOR_VERSION == 2 + myfile mysrc; + myfile *fsrc = &mysrc; + fsrc->mem = fsrc->cur = (char*)src; + fsrc->len = file_length; + + // the hack is not used when reading meta-info of a j2k stream: + opj_set_error_handler(dinfo, gdcm_error_callback, NULL); + + cio = opj_stream_create_memory_stream(fsrc,J2K_STREAM_CHUNK_SIZE, true); + + /* setup the decoder decoding parameters using user parameters */ + opj_setup_decoder(dinfo, ¶meters); + bool bResult; + OPJ_INT32 l_tile_x0,l_tile_y0; + OPJ_UINT32 l_tile_width,l_tile_height,l_nb_tiles_x,l_nb_tiles_y; + bResult = opj_read_header( + dinfo, + &image, + &l_tile_x0, + &l_tile_y0, + &l_tile_width, + &l_tile_height, + &l_nb_tiles_x, + &l_nb_tiles_y, + cio); + //image = opj_decode(dinfo, cio); + //bResult = bResult && (image != 00); + //bResult = bResult && opj_end_decompress(dinfo,cio); + //if (!image) + // { + // opj_destroy_codec(dinfo); + // opj_stream_destroy(cio); + // gdcmErrorMacro( "opj_decode failed" ); + // return false; + // } +#endif // OPENJPEG_MAJOR_VERSION == 1 + + int reversible; +#if OPENJPEG_MAJOR_VERSION == 1 + opj_j2k_t* j2k = NULL; + opj_jp2_t* jp2 = NULL; + + switch(parameters.decod_format) + { + case J2K_CFMT: + j2k = (opj_j2k_t*)dinfo->j2k_handle; + assert( j2k ); + reversible = j2k->cp->tcps->tccps->qmfbid; + break; + case JP2_CFMT: + jp2 = (opj_jp2_t*)dinfo->jp2_handle; + assert( jp2 ); + reversible = jp2->j2k->cp->tcps->tccps->qmfbid; + break; + default: + gdcmErrorMacro( "Impossible happen" ); + return false; + } +#else + reversible = opj_get_reversible(dinfo, ¶meters ); + assert( reversible == 0 || reversible == 1 ); +#endif // OPENJPEG_MAJOR_VERSION == 1 + LossyFlag = !reversible; + +#if 0 +#ifndef GDCM_USE_SYSTEM_OPENJPEG + if( j2k ) + j2k_dump_cp(stdout, image, j2k->cp); + if( jp2 ) + j2k_dump_cp(stdout, image, jp2->j2k->cp); +#endif +#endif + + int compno = 0; + opj_image_comp_t *comp = &image->comps[compno]; + + if( image->numcomps == 3 ) + { + opj_image_comp_t *comp1 = &image->comps[1]; + opj_image_comp_t *comp2 = &image->comps[2]; + bool invalid = false; +#if OPENJPEG_MAJOR_VERSION == 1 + if( comp->bpp != comp1->bpp ) invalid = true; + if( comp->bpp != comp2->bpp ) invalid = true; +#endif // OPENJPEG_MAJOR_VERSION == 1 + if( comp->prec != comp1->prec ) invalid = true; + if( comp->prec != comp2->prec ) invalid = true; + if( comp->sgnd != comp1->sgnd ) invalid = true; + if( comp->sgnd != comp2->sgnd ) invalid = true; + if( comp->h != comp1->h ) invalid = true; + if( comp->h != comp2->h ) invalid = true; + if( comp->w != comp1->w ) invalid = true; + if( comp->w != comp2->w ) invalid = true; + if( invalid ) + { + gdcmErrorMacro( "Invalid test failed" ); + return false; + } + } + + this->Dimensions[0] = comp->w; + this->Dimensions[1] = comp->h; + + if( comp->prec <= 8 ) + { +#if OPENJPEG_MAJOR_VERSION == 1 + if( comp->bpp ) assert( comp->bpp == 8 ); +#endif // OPENJPEG_MAJOR_VERSION == 1 + this->PF = PixelFormat( PixelFormat::UINT8 ); + } + else if( comp->prec <= 16 ) + { +#if OPENJPEG_MAJOR_VERSION == 1 + if( comp->bpp ) assert( comp->bpp == 16 ); +#endif // OPENJPEG_MAJOR_VERSION == 1 + this->PF = PixelFormat( PixelFormat::UINT16 ); + } + else if( comp->prec <= 32 ) + { +#if OPENJPEG_MAJOR_VERSION == 1 + if( comp->bpp ) assert( comp->bpp == 32 ); +#endif // OPENJPEG_MAJOR_VERSION == 1 + this->PF = PixelFormat( PixelFormat::UINT32 ); + } + else + { + gdcmErrorMacro( "do not handle precision: " << comp->prec ); + return false; + } + this->PF.SetBitsStored( (unsigned short)comp->prec ); + this->PF.SetHighBit( (unsigned short)(comp->prec - 1) ); + this->PF.SetPixelRepresentation( (unsigned short)comp->sgnd ); + + if( image->numcomps == 1 ) + { + // normally we have codec only, but in some case we have a JP2 with + // color space info: + // - gdcmData/MAROTECH_CT_JP2Lossy.dcm + // - gdcmData/D_CLUNIE_CT1_J2KI.dcm -> color_space = 32767 + //assert( image->color_space == 0 || image->color_space == CLRSPC_GRAY ); + PI = PhotometricInterpretation::MONOCHROME2; + this->PF.SetSamplesPerPixel( 1 ); + } + else if( image->numcomps == 3 ) + { + //assert( image->color_space == 0 ); + //PI = PhotometricInterpretation::RGB; + /* + 8.2.4 JPEG 2000 IMAGE COMPRESSION + The JPEG 2000 bit stream specifies whether or not a reversible or irreversible + multi-component (color) transformation, if any, has been applied. If no + multi-component transformation has been applied, then the components shall + correspond to those specified by the DICOM Attribute Photometric Interpretation + (0028,0004). If the JPEG 2000 Part 1 reversible multi-component transformation + has been applied then the DICOM Attribute Photometric Interpretation + (0028,0004) shall be YBR_RCT. If the JPEG 2000 Part 1 irreversible + multi-component transformation has been applied then the DICOM Attribute + Photometric Interpretation (0028,0004) shall be YBR_ICT. Notes: 1. For + example, single component may be present, and the Photometric Interpretation + (0028,0004) may be MONOCHROME2. 2. Though it would be unusual, would not take + advantage of correlation between the red, green and blue components, and would + not achieve effective compression, a Photometric Interpretation of RGB could be + specified as long as no multi-component transformation was specified by the + JPEG 2000 bit stream. 3. Despite the application of a multi-component color + transformation and its reflection in the Photometric Interpretation attribute, + the color space remains undefined. There is currently no means of conveying + standard color spaces either by fixed values (such as sRGB) or by ICC + profiles. Note in particular that the JP2 file header is not sent in the JPEG + 2000 bitstream that is encapsulated in DICOM. + */ + PI = PhotometricInterpretation::YBR_RCT; + this->PF.SetSamplesPerPixel( 3 ); + } + else if( image->numcomps == 4 ) + { + /* Yes this is legal */ + // http://www.crc.ricoh.com/~gormish/jpeg2000conformance/ + // jpeg2000testimages/Part4TestStreams/codestreams_profile0/p0_06.j2k + gdcmErrorMacro( "Image is 4 components which is not supported anymore in DICOM (ARGB is retired)" ); + // TODO: How about I get the 3 comps and set the alpha plane in the overlay ? + return false; + } + else + { + // jpeg2000testimages/Part4TestStreams/codestreams_profile0/p0_13.j2k + gdcmErrorMacro( "Image is " << image->numcomps << " components which is not supported in DICOM" ); + return false; + } + + assert( PI != PhotometricInterpretation::UNKNOW ); + + bool mct = false; + if( mct ) + { + if( reversible ) + { + ts = TransferSyntax::JPEG2000Part2Lossless; + } + else + { + ts = TransferSyntax::JPEG2000Part2; + if( PI == PhotometricInterpretation::YBR_RCT ) + { + // FIXME ??? + PI = PhotometricInterpretation::YBR_ICT; + } + } + } + else + { + if( reversible ) + { + ts = TransferSyntax::JPEG2000Lossless; + } + else + { + ts = TransferSyntax::JPEG2000; + if( PI == PhotometricInterpretation::YBR_RCT ) + { + // FIXME ??? + PI = PhotometricInterpretation::YBR_ICT; + } + } + } + + //assert( ts.IsLossy() == this->GetPhotometricInterpretation().IsLossy() ); + //assert( ts.IsLossless() == this->GetPhotometricInterpretation().IsLossless() ); + if( this->GetPhotometricInterpretation().IsLossy() ) + { + assert( ts.IsLossy() ); + } + if( ts.IsLossless() && !ts.IsLossy() ) + { + assert( this->GetPhotometricInterpretation().IsLossless() ); + } + +#if OPENJPEG_MAJOR_VERSION == 1 + /* close the byte stream */ + opj_cio_close(cio); + + /* free the memory containing the code-stream */ + //delete[] src; //FIXME + + /* free remaining structures */ + if(dinfo) { + opj_destroy_decompress(dinfo); + } +#elif OPENJPEG_MAJOR_VERSION == 2 + /* close the byte stream */ + opj_stream_destroy(cio); + /* free remaining structures */ + if (dinfo) + { + opj_destroy_codec(dinfo); + } +#endif // OPENJPEG_MAJOR_VERSION == 1 + + /* free image data structure */ + opj_image_destroy(image); + + + return true; +} + +bool JPEG2000Codec::DecodeExtent( + char *buffer, + unsigned int xmin, unsigned int xmax, + unsigned int ymin, unsigned int ymax, + unsigned int zmin, unsigned int zmax, + std::istream & is +) +{ + BasicOffsetTable bot; + bot.Read( is ); + + const unsigned int * dimensions = this->GetDimensions(); + const PixelFormat & pf = this->GetPixelFormat(); + assert( pf.GetBitsAllocated() % 8 == 0 ); + assert( pf != PixelFormat::SINGLEBIT ); + assert( pf != PixelFormat::UINT12 && pf != PixelFormat::INT12 ); + + if( NumberOfDimensions == 2 ) + { + char *dummy_buffer = NULL; + std::vector vdummybuffer; + size_t buf_size = 0; + + const Tag seqDelItem(0xfffe,0xe0dd); + gdcm::Fragment frag; + while( frag.ReadPreValue(is) && frag.GetTag() != seqDelItem ) + { + size_t fraglen = frag.GetVL(); + size_t oldlen = vdummybuffer.size(); + // update + buf_size = fraglen + oldlen; + vdummybuffer.resize( buf_size ); + dummy_buffer = &vdummybuffer[0]; + // read J2K + is.read( &vdummybuffer[oldlen], fraglen ); + } + assert( frag.GetTag() == seqDelItem && frag.GetVL() == 0 ); + assert( zmin == zmax ); + assert( zmin == 0 ); + + std::pair raw_len = this->DecodeByStreamsCommon(dummy_buffer, buf_size); + if( !raw_len.first || !raw_len.second ) return false; + + char *raw = raw_len.first; + const unsigned int rowsize = xmax - xmin + 1; + const unsigned int colsize = ymax - ymin + 1; + const unsigned int bytesPerPixel = pf.GetPixelSize(); + + const char *tmpBuffer1 = raw; + unsigned int z = 0; + for (unsigned int y = ymin; y <= ymax; ++y) + { + size_t theOffset = 0 + (z*dimensions[1]*dimensions[0] + y*dimensions[0] + xmin)*bytesPerPixel; + tmpBuffer1 = raw + theOffset; + memcpy(&(buffer[((z-zmin)*rowsize*colsize + + (y-ymin)*rowsize)*bytesPerPixel]), + tmpBuffer1, rowsize*bytesPerPixel); + } + delete[] raw_len.first; + + } + else if ( NumberOfDimensions == 3 ) + { + const Tag seqDelItem(0xfffe,0xe0dd); + gdcm::Fragment frag; + std::streamoff thestart = is.tellg(); + unsigned int numfrags = 0; + std::vector< size_t > offsets; + while( frag.ReadPreValue(is) && frag.GetTag() != seqDelItem ) + { + //std::streamoff relstart = is.tellg(); + //assert( relstart - thestart == 8 ); + std::streamoff off = frag.GetVL(); + offsets.push_back( off ); + is.seekg( off, std::ios::cur ); + ++numfrags; + } + assert( frag.GetTag() == seqDelItem && frag.GetVL() == 0 ); + assert( numfrags == offsets.size() ); + if( numfrags != Dimensions[2] ) + { + gdcmErrorMacro( "Not handled" ); + return false; + } + + for( unsigned int z = zmin; z <= zmax; ++z ) + { + size_t curoffset = std::accumulate( offsets.begin(), offsets.begin() + z, 0 ); + is.seekg( thestart + curoffset + 8 * z, std::ios::beg ); + is.seekg( 8, std::ios::cur ); + + const size_t buf_size = offsets[z]; + char *dummy_buffer = new char[ buf_size ]; + is.read( dummy_buffer, buf_size ); + std::pair raw_len = this->DecodeByStreamsCommon(dummy_buffer, buf_size); + /* free the memory containing the code-stream */ + delete[] dummy_buffer; + if( !raw_len.first || !raw_len.second ) return false; + + char *raw = raw_len.first; + const unsigned int rowsize = xmax - xmin + 1; + const unsigned int colsize = ymax - ymin + 1; + const unsigned int bytesPerPixel = pf.GetPixelSize(); + + const char *tmpBuffer1 = raw; + for (unsigned int y = ymin; y <= ymax; ++y) + { + size_t theOffset = 0 + (0*dimensions[1]*dimensions[0] + y*dimensions[0] + xmin)*bytesPerPixel; + tmpBuffer1 = raw + theOffset; + memcpy(&(buffer[((z-zmin)*rowsize*colsize + + (y-ymin)*rowsize)*bytesPerPixel]), + tmpBuffer1, rowsize*bytesPerPixel); + } + delete[] raw_len.first; + } + } + return true; +} + +ImageCodec * JPEG2000Codec::Clone() const +{ + return NULL; +} + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmJPEG2000Codec.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmJPEG2000Codec.h new file mode 100644 index 0000000..ddef63b --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmJPEG2000Codec.h @@ -0,0 +1,79 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMJPEG2000CODEC_H +#define GDCMJPEG2000CODEC_H + +#include "gdcmImageCodec.h" + +namespace gdcm +{ + +class JPEG2000Internals; +/** + * \brief Class to do JPEG 2000 + * \note + * the class will produce JPC (JPEG 2000 codestream), since some private implementor + * are using full jp2 file the decoder tolerate jp2 input + * this is an implementation of an ImageCodec + */ +class GDCM_EXPORT JPEG2000Codec : public ImageCodec +{ +friend class ImageRegionReader; + friend class Bitmap; +public: + JPEG2000Codec(); + ~JPEG2000Codec(); + + bool CanDecode(TransferSyntax const &ts) const; + bool CanCode(TransferSyntax const &ts) const; + + bool Decode(DataElement const &is, DataElement &os); + bool Code(DataElement const &in, DataElement &out); + + virtual bool GetHeaderInfo(std::istream &is, TransferSyntax &ts); + virtual ImageCodec * Clone() const; + + // JPEG-2000 / OpenJPEG specific way of encoding lossy-ness + // ref: http://www.openjpeg.org/index.php?menu=doc#encoder + void SetRate(unsigned int idx, double rate); + double GetRate(unsigned int idx = 0) const; + + void SetQuality(unsigned int idx, double q); + double GetQuality(unsigned int idx = 0) const; + + void SetTileSize(unsigned int tx, unsigned int ty); + + void SetNumberOfResolutions(unsigned int nres); + + void SetReversible(bool res); + +protected: + bool DecodeExtent( + char *buffer, + unsigned int xmin, unsigned int xmax, + unsigned int ymin, unsigned int ymax, + unsigned int zmin, unsigned int zmax, + std::istream & is + ); + + bool DecodeByStreams(std::istream &is, std::ostream &os); +private: + std::pair DecodeByStreamsCommon(char *dummy_buffer, size_t buf_size); + bool GetHeaderInfo(const char * dummy_buffer, size_t len, TransferSyntax &ts); + JPEG2000Internals *Internals; +}; + +} // end namespace gdcm + +#endif //GDCMJPEG2000CODEC_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmJPEG8Codec.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmJPEG8Codec.cxx new file mode 100644 index 0000000..5395e1a --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmJPEG8Codec.cxx @@ -0,0 +1,21 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmJPEG8Codec.h" + +#include "gdcm_ljpeg8.h" + +#include + +#define JPEGBITSCodec JPEG8Codec +#include "gdcmJPEGBITSCodec.cxx" diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmJPEG8Codec.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmJPEG8Codec.h new file mode 100644 index 0000000..ab4be89 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmJPEG8Codec.h @@ -0,0 +1,49 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMJPEG8CODEC_H +#define GDCMJPEG8CODEC_H + +#include "gdcmJPEGCodec.h" + +namespace gdcm +{ + +class JPEGInternals; +class ByteValue; +/** + * \brief Class to do JPEG 8bits (lossy & lossless) + * \note internal class + */ +class JPEG8Codec : public JPEGCodec +{ +public: + JPEG8Codec(); + ~JPEG8Codec(); + + bool DecodeByStreams(std::istream &is, std::ostream &os); + bool InternalCode(const char *input, unsigned long len, std::ostream &os); + + bool GetHeaderInfo(std::istream &is, TransferSyntax &ts); + +protected: + bool IsStateSuspension() const; + virtual bool EncodeBuffer(std::ostream &os, const char *data, size_t datalen); + +private: + JPEGInternals *Internals; +}; + +} // end namespace gdcm + +#endif //GDCMJPEG8CODEC_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmJPEGBITSCodec.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmJPEGBITSCodec.cxx new file mode 100644 index 0000000..990d3fa --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmJPEGBITSCodec.cxx @@ -0,0 +1,1584 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmTrace.h" +#include "gdcmTransferSyntax.h" + +#include + +/* + * jdatasrc.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains decompression data source routines for the case of + * reading JPEG data from a file (or any stdio stream). While these routines + * are sufficient for most applications, some will want to use a different + * source manager. + * IMPORTANT: we assume that fread() will correctly transcribe an array of + * JOCTETs from 8-bit-wide elements on external storage. If char is wider + * than 8 bits on your machine, you may need to do some tweaking. + */ + +/* this is not a core library module, so it doesn't define JPEG_INTERNALS */ + +namespace gdcm +{ + +/* Expanded data source object for stdio input */ + +typedef struct { + struct jpeg_source_mgr pub; /* public fields */ + + std::istream * infile; /* source stream */ + JOCTET * buffer; /* start of buffer */ + boolean start_of_file; /* have we gotten any data yet? */ +} my_source_mgr; + +typedef my_source_mgr * my_src_ptr; + +#define INPUT_BUF_SIZE 4096 /* choose an efficiently fread'able size */ + + +/* + * Initialize source --- called by jpeg_read_header + * before any data is actually read. + */ + +METHODDEF(void) +init_source (j_decompress_ptr cinfo) +{ + my_src_ptr src = (my_src_ptr) cinfo->src; + + /* We reset the empty-input-file flag for each image, + * but we don't clear the input buffer. + * This is correct behavior for reading a series of images from one source. + */ + src->start_of_file = TRUE; +} + + +/* + * Fill the input buffer --- called whenever buffer is emptied. + * + * In typical applications, this should read fresh data into the buffer + * (ignoring the current state of next_input_byte & bytes_in_buffer), + * reset the pointer & count to the start of the buffer, and return TRUE + * indicating that the buffer has been reloaded. It is not necessary to + * fill the buffer entirely, only to obtain at least one more byte. + * + * There is no such thing as an EOF return. If the end of the file has been + * reached, the routine has a choice of ERREXIT() or inserting fake data into + * the buffer. In most cases, generating a warning message and inserting a + * fake EOI marker is the best course of action --- this will allow the + * decompressor to output however much of the image is there. However, + * the resulting error message is misleading if the real problem is an empty + * input file, so we handle that case specially. + * + * In applications that need to be able to suspend compression due to input + * not being available yet, a FALSE return indicates that no more data can be + * obtained right now, but more may be forthcoming later. In this situation, + * the decompressor will return to its caller (with an indication of the + * number of scanlines it has read, if any). The application should resume + * decompression after it has loaded more data into the input buffer. Note + * that there are substantial restrictions on the use of suspension --- see + * the documentation. + * + * When suspending, the decompressor will back up to a convenient restart point + * (typically the start of the current MCU). next_input_byte & bytes_in_buffer + * indicate where the restart point will be if the current call returns FALSE. + * Data beyond this point must be rescanned after resumption, so move it to + * the front of the buffer rather than discarding it. + */ + +METHODDEF(boolean) +fill_input_buffer (j_decompress_ptr cinfo) +{ + my_src_ptr src = (my_src_ptr) cinfo->src; + size_t nbytes; + + //FIXME FIXME FIXME FIXME FIXME + //nbytes = JFREAD(src->infile, src->buffer, INPUT_BUF_SIZE); + std::streampos pos = src->infile->tellg(); + std::streampos end = src->infile->seekg(0, std::ios::end).tellg(); + src->infile->seekg(pos, std::ios::beg); + //FIXME FIXME FIXME FIXME FIXME + if( end == pos ) + { + /* Start the I/O suspension simply by returning false here: */ + return FALSE; + } + if( (end - pos) < INPUT_BUF_SIZE ) + { + src->infile->read( (char*)src->buffer, (size_t)(end - pos) ); + } + else + { + src->infile->read( (char*)src->buffer, INPUT_BUF_SIZE); + } + + std::streamsize gcount = src->infile->gcount(); + assert(gcount < INT_MAX); + nbytes = (size_t)gcount; + + if (nbytes <= 0) { + if (src->start_of_file) /* Treat empty input file as fatal error */ + ERREXIT(cinfo, JERR_INPUT_EMPTY); + WARNMS(cinfo, JWRN_JPEG_EOF); + /* Insert a fake EOI marker */ + src->buffer[0] = (JOCTET) 0xFF; + src->buffer[1] = (JOCTET) JPEG_EOI; + nbytes = 2; + } + + src->pub.next_input_byte = src->buffer; + src->pub.bytes_in_buffer = nbytes; + src->start_of_file = FALSE; + + return TRUE; +} + + +/* + * Skip data --- used to skip over a potentially large amount of + * uninteresting data (such as an APPn marker). + * + * Writers of suspendable-input applications must note that skip_input_data + * is not granted the right to give a suspension return. If the skip extends + * beyond the data currently in the buffer, the buffer can be marked empty so + * that the next read will cause a fill_input_buffer call that can suspend. + * Arranging for additional bytes to be discarded before reloading the input + * buffer is the application writer's problem. + */ + +METHODDEF(void) +skip_input_data (j_decompress_ptr cinfo, long num_bytes) +{ + my_src_ptr src = (my_src_ptr) cinfo->src; + + /* Just a dumb implementation for now. Could use fseek() except + * it doesn't work on pipes. Not clear that being smart is worth + * any trouble anyway --- large skips are infrequent. + */ + if (num_bytes > 0) { + while (num_bytes > (long) src->pub.bytes_in_buffer) { + num_bytes -= (long) src->pub.bytes_in_buffer; + (void) fill_input_buffer(cinfo); + /* note we assume that fill_input_buffer will never return FALSE, + * so suspension need not be handled. + */ + } + src->pub.next_input_byte += (size_t) num_bytes; + src->pub.bytes_in_buffer -= (size_t) num_bytes; + } +} + + +/* + * An additional method that can be provided by data source modules is the + * resync_to_restart method for error recovery in the presence of RST markers. + * For the moment, this source module just uses the default resync method + * provided by the JPEG library. That method assumes that no backtracking + * is possible. + */ + + +/* + * Terminate source --- called by jpeg_finish_decompress + * after all data has been read. Often a no-op. + * + * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding + * application must deal with any cleanup that should happen even + * for error exit. + */ + +METHODDEF(void) +term_source (j_decompress_ptr cinfo) +{ + (void)cinfo; + /* no work necessary here */ +} + + +/* + * Prepare for input from a stdio stream. + * The caller must have already opened the stream, and is responsible + * for closing it after finishing decompression. + */ + +GLOBAL(void) +jpeg_stdio_src (j_decompress_ptr cinfo, std::istream & infile, bool flag) +{ + my_src_ptr src; + + /* The source object and input buffer are made permanent so that a series + * of JPEG images can be read from the same file by calling jpeg_stdio_src + * only before the first one. (If we discarded the buffer at the end of + * one image, we'd likely lose the start of the next one.) + * This makes it unsafe to use this manager and a different source + * manager serially with the same JPEG object. Caveat programmer. + */ + if (cinfo->src == NULL) { /* first time for this JPEG object? */ + cinfo->src = (struct jpeg_source_mgr *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + SIZEOF(my_source_mgr)); + src = (my_src_ptr) cinfo->src; + src->buffer = (JOCTET *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + INPUT_BUF_SIZE * SIZEOF(JOCTET)); + } + + src = (my_src_ptr) cinfo->src; + src->pub.init_source = init_source; + src->pub.fill_input_buffer = fill_input_buffer; + src->pub.skip_input_data = skip_input_data; + src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ + src->pub.term_source = term_source; + src->infile = &infile; + if( flag ) + { + src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ + src->pub.next_input_byte = NULL; /* until buffer loaded */ + } +} + +} // end namespace gdcm + + +namespace gdcm +{ +/* + * The following was copy/paste from example.c + */ + +struct my_error_mgr { + struct jpeg_error_mgr pub; /* "public" fields */ + jmp_buf setjmp_buffer; /* for return to caller */ +}; +typedef struct my_error_mgr* my_error_ptr; + +class JPEGInternals +{ +public: + JPEGInternals():cinfo(),jerr(),StateSuspension(0),SampBuffer(0) {} + jpeg_decompress_struct cinfo; + jpeg_compress_struct cinfo_comp; + my_error_mgr jerr; + int StateSuspension; + void *SampBuffer; +}; + +JPEGBITSCodec::JPEGBITSCodec() +{ + Internals = new JPEGInternals; + BitSample = BITS_IN_JSAMPLE; +} + +JPEGBITSCodec::~JPEGBITSCodec() +{ + delete Internals; +} + +/* + * Here's the routine that will replace the standard error_exit method: + */ +extern "C" { +METHODDEF(void) my_error_exit (j_common_ptr cinfo) { + /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */ + my_error_ptr myerr = (my_error_ptr) cinfo->err; + + /* Always display the message. */ + /* We could postpone this until after returning, if we chose. */ + (*cinfo->err->output_message) (cinfo); + + /* Return control to the setjmp point */ + longjmp(myerr->setjmp_buffer, 1); +} +} + +bool JPEGBITSCodec::GetHeaderInfo(std::istream &is, TransferSyntax &ts) +{ + /* This struct contains the JPEG decompression parameters and pointers to + * working space (which is allocated as needed by the JPEG library). + */ + jpeg_decompress_struct &cinfo = Internals->cinfo; + + /* We use our private extension JPEG error handler. + * Note that this struct must live as long as the main JPEG parameter + * struct, to avoid dangling-pointer problems. + */ + my_error_mgr &jerr = Internals->jerr; + /* More stuff */ + //FILE * infile; /* source file */ + //JSAMPARRAY buffer; /* Output row buffer */ + //int row_stride; /* physical row width in output buffer */ + + if( Internals->StateSuspension == 0 ) + { + // Step 1: allocate and initialize JPEG decompression object + // + // We set up the normal JPEG error routines, then override error_exit. + cinfo.err = jpeg_std_error(&jerr.pub); + jerr.pub.error_exit = my_error_exit; + // Establish the setjmp return context for my_error_exit to use. + if (setjmp(jerr.setjmp_buffer)) + { + // If we get here, the JPEG code has signaled an error. + // We need to clean up the JPEG object, close the input file, and return. + // But first handle the case IJG does not like: + if ( jerr.pub.msg_code == JERR_BAD_PRECISION /* 18 */ ) + { + this->BitSample = jerr.pub.msg_parm.i[0]; + assert( this->BitSample == 1 || this->BitSample == 8 || this->BitSample == 12 || this->BitSample == 16 ); + assert( this->BitSample == cinfo.data_precision ); + } + jpeg_destroy_decompress(&cinfo); + // TODO: www.dcm4che.org/jira/secure/attachment/10185/ct-implicit-little.dcm + // weird Icon Image from GE... + return false; + } + } + + if( Internals->StateSuspension == 0 ) + { + // Now we can initialize the JPEG decompression object. + jpeg_create_decompress(&cinfo); + + // Step 2: specify data source (eg, a file) + jpeg_stdio_src(&cinfo, is, true); + } + else + { + jpeg_stdio_src(&cinfo, is, false); + } + + /* Step 3: read file parameters with jpeg_read_header() */ + + if ( Internals->StateSuspension < 2 ) + { + if( jpeg_read_header(&cinfo, TRUE) == JPEG_SUSPENDED ) + { + Internals->StateSuspension = 2; + } + // First of all are we using the proper JPEG decoder (correct bit sample): + if( jerr.pub.num_warnings ) + { + if ( jerr.pub.msg_code == 128 ) + { + this->BitSample = jerr.pub.msg_parm.i[0]; + jpeg_destroy_decompress(&cinfo); + return false; + } + else + { + assert( 0 ); + } + } + this->Dimensions[1] = cinfo.image_height; /* Number of rows in image */ + this->Dimensions[0] = cinfo.image_width; /* Number of columns in image */ + + int prep = this->PF.GetPixelRepresentation(); + //this->BitSample = cinfo.data_precision; + int precision = cinfo.data_precision; + // if lossy it should only be 8 or 12, but for lossless it can be [2-16] + if( precision == 1 ) + { + // lossless ! + this->PF = PixelFormat( PixelFormat::SINGLEBIT ); + } + else if( precision <= 8 ) + { + this->PF = PixelFormat( PixelFormat::UINT8 ); + } + else if( precision <= 12 ) + { + this->PF = PixelFormat( PixelFormat::UINT12 ); + } + else if( precision <= 16 ) + { + // lossless ! + this->PF = PixelFormat( PixelFormat::UINT16 ); + } + else + { + assert( 0 ); + } + this->PF.SetPixelRepresentation( (uint16_t)prep ); + this->PF.SetBitsStored( (uint16_t)precision ); + assert( (precision - 1) >= 0 ); + this->PF.SetHighBit( (uint16_t)(precision - 1) ); + + this->PlanarConfiguration = 0; + // Let's check the color space: + // JCS_UNKNOWN -> 0 + // JCS_GRAYSCALE, /* monochrome */ + // JCS_RGB, /* red/green/blue */ + // JCS_YCbCr, /* Y/Cb/Cr (also known as YUV) */ + // JCS_CMYK, /* C/M/Y/K */ + // JCS_YCCK /* Y/Cb/Cr/K */ + + if( cinfo.jpeg_color_space == JCS_UNKNOWN ) + { + // I do not know if this possible, it looks like IJG always computes a default + if( cinfo.num_components == 1 ) + { + PI = PhotometricInterpretation::MONOCHROME2; + this->PF.SetSamplesPerPixel( 1 ); + } + else if( cinfo.num_components == 3 ) + { + PI = PhotometricInterpretation::RGB; + this->PF.SetSamplesPerPixel( 3 ); + } + else + { + assert( 0 ); + } + } + else if( cinfo.jpeg_color_space == JCS_GRAYSCALE ) + { + assert( cinfo.num_components == 1 ); + PI = PhotometricInterpretation::MONOCHROME2; + this->PF.SetSamplesPerPixel( 1 ); + } + else if( cinfo.jpeg_color_space == JCS_RGB ) + { + assert( cinfo.num_components == 3 ); + PI = PhotometricInterpretation::RGB; + this->PF.SetSamplesPerPixel( 3 ); + } + else if( cinfo.jpeg_color_space == JCS_YCbCr ) + { + assert( cinfo.num_components == 3 ); + PI = PhotometricInterpretation::YBR_FULL_422; + this->PF.SetSamplesPerPixel( 3 ); + this->PlanarConfiguration = 1; + } + else if( cinfo.jpeg_color_space == JCS_CMYK ) + { + assert( cinfo.num_components == 4 ); + PI = PhotometricInterpretation::CMYK; + this->PF.SetSamplesPerPixel( 4 ); + } + else if( cinfo.jpeg_color_space == JCS_YCCK ) + { + assert( cinfo.num_components == 4 ); + PI = PhotometricInterpretation::YBR_FULL_422; // 4th plane ?? + this->PF.SetSamplesPerPixel( 4 ); + assert( 0 ); //TODO + } + else + { + assert( 0 ); //TODO + } + } + if( cinfo.process == JPROC_LOSSLESS ) + { + int predictor = cinfo.Ss; + /* not very user friendly... */ + switch(predictor) + { + case 1: + ts = TransferSyntax::JPEGLosslessProcess14_1; + break; + default: + ts = TransferSyntax::JPEGLosslessProcess14; + break; + } + } + else if( cinfo.process == JPROC_SEQUENTIAL ) + { + if( this->BitSample == 8 ) + ts = TransferSyntax::JPEGBaselineProcess1; + else if( this->BitSample == 12 ) + ts = TransferSyntax::JPEGExtendedProcess2_4; + } + else if( cinfo.process == JPROC_PROGRESSIVE ) + { + if( this->BitSample == 8 ) + { + ts = TransferSyntax::JPEGFullProgressionProcess10_12; + } + else if( this->BitSample == 12 ) + { + ts = TransferSyntax::JPEGFullProgressionProcess10_12; + } + else + { + assert(0); // TODO + return false; + } + } + else + { + assert(0); // TODO + return false; + } + if( cinfo.process == JPROC_LOSSLESS ) + { + LossyFlag = false; + } + else + { + LossyFlag = true; + } + + // Pixel density stuff: +/* +UINT8 density_unit +UINT16 X_density +UINT16 Y_density + The resolution information to be written into the JFIF marker; + not used otherwise. density_unit may be 0 for unknown, + 1 for dots/inch, or 2 for dots/cm. The default values are 0,1,1 + indicating square pixels of unknown size. +*/ + + if( cinfo.density_unit != 0 + || cinfo.X_density != 1 + || cinfo.Y_density != 1 + ) + { + gdcmErrorMacro( "Pixel Density from JFIF Marker is not supported (for now)" ); + //return false; + } + + +#if 0 + switch ( cinfo.jpeg_color_space ) + { + case JCS_GRAYSCALE: + if( GetPhotometricInterpretation() != PhotometricInterpretation::MONOCHROME1 + && GetPhotometricInterpretation() != PhotometricInterpretation::MONOCHROME2 ) + { + gdcmWarningMacro( "Wrong PhotometricInterpretation. DICOM says: " << + GetPhotometricInterpretation() << " but JPEG says: " + << cinfo.jpeg_color_space ); + //Internals->SetPhotometricInterpretation( PhotometricInterpretation::MONOCHROME2 ); + this->PI = PhotometricInterpretation::MONOCHROME2; + } + break; + case JCS_RGB: + assert( GetPhotometricInterpretation() == PhotometricInterpretation::RGB ); + break; + case JCS_YCbCr: + if( GetPhotometricInterpretation() != PhotometricInterpretation::YBR_FULL && + GetPhotometricInterpretation() != PhotometricInterpretation::YBR_FULL_422 ) + { + // DermaColorLossLess.dcm (lossless) + // LEADTOOLS_FLOWERS-24-RGB-JpegLossy.dcm (lossy) + gdcmWarningMacro( "Wrong PhotometricInterpretation. DICOM says: " << + GetPhotometricInterpretation() << " but JPEG says: " + << cinfo.jpeg_color_space ); + // Here it gets nasty since apparently when this occurs lossless means + // we should not do any color conversion, but we *might* be breaking + // correct DICOM file. + // FIXME FIXME + /* prevent the library from performing any color space conversion */ + if ( cinfo.process == JPROC_LOSSLESS ) + { + cinfo.jpeg_color_space = JCS_UNKNOWN; + cinfo.out_color_space = JCS_UNKNOWN; + } + } + break; + default: + assert(0); + return false; + } + //assert( cinfo.data_precision == BITS_IN_JSAMPLE ); + //assert( cinfo.data_precision == this->BitSample ); + + /* Step 4: set parameters for decompression */ + /* no op */ + } + + /* Step 5: Start decompressor */ + + if (Internals->StateSuspension < 3 ) + { + if ( jpeg_start_decompress(&cinfo) == FALSE ) + { + /* Suspension: jpeg_start_decompress */ + Internals->StateSuspension = 3; + } + + /* We may need to do some setup of our own at this point before reading + * the data. After jpeg_start_decompress() we have the correct scaled + * output image dimensions available, as well as the output colormap + * if we asked for color quantization. + * In this example, we need to make an output work buffer of the right size. + */ + /* JSAMPLEs per row in output buffer */ + row_stride = cinfo.output_width * cinfo.output_components; + row_stride *= sizeof(JSAMPLE); + /* Make a one-row-high sample array that will go away when done with image */ + buffer = (*cinfo.mem->alloc_sarray) + ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); + + /* Save the buffer in case of suspension to be able to reuse it later: */ + Internals->SampBuffer = buffer; + } + else + { + /* JSAMPLEs per row in output buffer */ + row_stride = cinfo.output_width * cinfo.output_components; + row_stride *= sizeof(JSAMPLE); + + /* Suspension: re-use the buffer: */ + buffer = (JSAMPARRAY)Internals->SampBuffer; + } + + /* Step 6: while (scan lines remain to be read) */ + /* jpeg_read_scanlines(...); */ + + /* Here we use the library's state variable cinfo.output_scanline as the + * loop counter, so that we don't have to keep track ourselves. + */ + while (cinfo.output_scanline < cinfo.output_height) { + /* jpeg_read_scanlines expects an array of pointers to scanlines. + * Here the array is only one element long, but you could ask for + * more than one scanline at a time if that's more convenient. + */ + if( jpeg_read_scanlines(&cinfo, buffer, 1) == 0 ) + { + /* Suspension in jpeg_read_scanlines */ + Internals->StateSuspension = 3; + return true; + } + os.write((char*)buffer[0], row_stride); + } + + /* Step 7: Finish decompression */ + + if( jpeg_finish_decompress(&cinfo) == FALSE ) + { + /* Suspension: jpeg_finish_decompress */ + Internals->StateSuspension = 4; + } +#endif + + /* Step 8: Release JPEG decompression object */ + + /* This is an important step since it will release a good deal of memory. */ + jpeg_destroy_decompress(&cinfo); + + /* After finish_decompress, we can close the input file. + * Here we postpone it until after no more JPEG errors are possible, + * so as to simplify the setjmp error logic above. (Actually, I don't + * think that jpeg_destroy can do an error exit, but why assume anything...) + */ + //fclose(infile); + + /* At this point you may want to check to see whether any corrupt-data + * warnings occurred (test whether jerr.pub.num_warnings is nonzero). + */ + /* In any case make sure the we reset the internal state suspension */ + Internals->StateSuspension = 0; + + /* And we're done! */ + return true; + +} + +/* + * Note: see dcmdjpeg +cn option to avoid the YBR => RGB loss + */ +bool JPEGBITSCodec::DecodeByStreams(std::istream &is, std::ostream &os) +{ + /* This struct contains the JPEG decompression parameters and pointers to + * working space (which is allocated as needed by the JPEG library). + */ + jpeg_decompress_struct &cinfo = Internals->cinfo; + + /* We use our private extension JPEG error handler. + * Note that this struct must live as long as the main JPEG parameter + * struct, to avoid dangling-pointer problems. + */ + my_error_mgr &jerr = Internals->jerr; + /* More stuff */ + //FILE * infile; /* source file */ + JSAMPARRAY buffer; /* Output row buffer */ + size_t row_stride; /* physical row width in output buffer */ + + if( Internals->StateSuspension == 0 ) + { + // Step 1: allocate and initialize JPEG decompression object + // + // We set up the normal JPEG error routines, then override error_exit. + cinfo.err = jpeg_std_error(&jerr.pub); + jerr.pub.error_exit = my_error_exit; + // Establish the setjmp return context for my_error_exit to use. + if (setjmp(jerr.setjmp_buffer)) + { + // If we get here, the JPEG code has signaled an error. + // We need to clean up the JPEG object, close the input file, and return. + // But first handle the case IJG does not like: + if ( jerr.pub.msg_code == JERR_BAD_PRECISION /* 18 */ ) + { + this->BitSample = jerr.pub.msg_parm.i[0]; + //assert( this->BitSample == 8 || this->BitSample == 12 || this->BitSample == 16 ); + } + jpeg_destroy_decompress(&cinfo); + // TODO: www.dcm4che.org/jira/secure/attachment/10185/ct-implicit-little.dcm + // weird Icon Image from GE... + return false; + } + } + + if( Internals->StateSuspension == 0 ) + { + // Now we can initialize the JPEG decompression object. + jpeg_create_decompress(&cinfo); + + // Step 2: specify data source (eg, a file) + jpeg_stdio_src(&cinfo, is, true); + } + else + { + jpeg_stdio_src(&cinfo, is, false); + } + + /* Step 3: read file parameters with jpeg_read_header() */ + + if ( Internals->StateSuspension < 2 ) + { + if( jpeg_read_header(&cinfo, TRUE) == JPEG_SUSPENDED ) + { + Internals->StateSuspension = 2; + } + // First of all are we using the proper JPEG decoder (correct bit sample): + if( jerr.pub.num_warnings ) + { + // PHILIPS_Gyroscan-12-MONO2-Jpeg_Lossless.dcm + if ( jerr.pub.msg_code == JWRN_MUST_DOWNSCALE ) + { + // PHILIPS_Gyroscan-12-Jpeg_Extended_Process_2_4.dcm + // PHILIPS_Gyroscan-12-MONO2-Jpeg_Lossless.dcm + // MARCONI_MxTWin-12-MONO2-JpegLossless-ZeroLengthSQ.dcm + // LJPEG_BuginGDCM12.dcm + gdcmDebugMacro( "JWRN_MUST_DOWNSCALE" ); + this->BitSample = jerr.pub.msg_parm.i[0]; + assert( cinfo.data_precision == this->BitSample ); + jpeg_destroy_decompress(&cinfo); + return false; + } + else + { + assert( 0 ); + } + } + // Let's check the color space: + // JCS_UNKNOWN -> 0 + // JCS_GRAYSCALE + // JCS_RGB + // JCS_YCbCr + // JCS_CMYK + // JCS_YCCK + + // Sanity checks: + const unsigned int * dims = this->GetDimensions(); + if( cinfo.image_width != dims[0] + || cinfo.image_height != dims[1] ) + { + gdcmErrorMacro( "Unhandled: dimension mismatch. JPEG is " << + cinfo.image_width << "," << cinfo.image_height << " while DICOM " << dims[0] << + "," << dims[1] ); // FIXME is this ok by standard ? + return false; + } + assert( cinfo.image_width == dims[0] ); + assert( cinfo.image_height == dims[1] ); + + switch ( cinfo.jpeg_color_space ) + { + case JCS_GRAYSCALE: + if( GetPhotometricInterpretation() != PhotometricInterpretation::MONOCHROME1 + && GetPhotometricInterpretation() != PhotometricInterpretation::MONOCHROME2 ) + { + gdcmWarningMacro( "Wrong PhotometricInterpretation. DICOM says: " << + GetPhotometricInterpretation() << " but JPEG says: " + << (int)cinfo.jpeg_color_space ); + //Internals->SetPhotometricInterpretation( PhotometricInterpretation::MONOCHROME2 ); + this->PI = PhotometricInterpretation::MONOCHROME2; + } + break; + case JCS_RGB: + //assert( GetPhotometricInterpretation() == PhotometricInterpretation::RGB ); + if ( cinfo.process == JPROC_LOSSLESS ) + { + cinfo.jpeg_color_space = JCS_UNKNOWN; + cinfo.out_color_space = JCS_UNKNOWN; + } + if( GetPhotometricInterpretation() == PhotometricInterpretation::YBR_RCT + || GetPhotometricInterpretation() == PhotometricInterpretation::YBR_ICT ) + this->PI = PhotometricInterpretation::RGB; + break; + case JCS_YCbCr: + if( GetPhotometricInterpretation() != PhotometricInterpretation::YBR_FULL && + GetPhotometricInterpretation() != PhotometricInterpretation::YBR_FULL_422 ) + { + // DermaColorLossLess.dcm (lossless) + // LEADTOOLS_FLOWERS-24-RGB-JpegLossy.dcm (lossy) + gdcmWarningMacro( "Wrong PhotometricInterpretation. DICOM says: " << + GetPhotometricInterpretation() << " but JPEG says: " + << (int)cinfo.jpeg_color_space ); + // Here it gets nasty since apparently when this occurs lossless means + // we should not do any color conversion, but we *might* be breaking + // correct DICOM file. + // FIXME FIXME + /* prevent the library from performing any color space conversion */ + cinfo.jpeg_color_space = JCS_UNKNOWN; + cinfo.out_color_space = JCS_UNKNOWN; + } + if ( cinfo.process == JPROC_LOSSLESS ) + { + //cinfo.jpeg_color_space = JCS_UNKNOWN; + //cinfo.out_color_space = JCS_UNKNOWN; + } + if( GetPhotometricInterpretation() == PhotometricInterpretation::YBR_FULL + || GetPhotometricInterpretation() == PhotometricInterpretation::YBR_FULL_422 ) + { + cinfo.jpeg_color_space = JCS_UNKNOWN; + cinfo.out_color_space = JCS_UNKNOWN; + //this->PlanarConfiguration = 1; + } + break; + case JCS_CMYK: + assert( GetPhotometricInterpretation() == PhotometricInterpretation::CMYK ); + if ( cinfo.process == JPROC_LOSSLESS ) + { + cinfo.jpeg_color_space = JCS_UNKNOWN; + cinfo.out_color_space = JCS_UNKNOWN; + } + break; + case JCS_UNKNOWN: + if ( cinfo.process == JPROC_LOSSLESS ) + { + cinfo.jpeg_color_space = JCS_UNKNOWN; + cinfo.out_color_space = JCS_UNKNOWN; + } + break; + default: + assert(0); + return false; + } + //assert( cinfo.data_precision == BITS_IN_JSAMPLE ); + //assert( cinfo.data_precision == this->BitSample ); + + /* Step 4: set parameters for decompression */ + /* no op */ + } + + /* Step 5: Start decompressor */ + + if (Internals->StateSuspension < 3 ) + { + if ( jpeg_start_decompress(&cinfo) == FALSE ) + { + /* Suspension: jpeg_start_decompress */ + Internals->StateSuspension = 3; + } + + /* We may need to do some setup of our own at this point before reading + * the data. After jpeg_start_decompress() we have the correct scaled + * output image dimensions available, as well as the output colormap + * if we asked for color quantization. + * In this example, we need to make an output work buffer of the right size. + */ + /* JSAMPLEs per row in output buffer */ + row_stride = cinfo.output_width * cinfo.output_components; + row_stride *= sizeof(JSAMPLE); + /* Make a one-row-high sample array that will go away when done with image */ + buffer = (*cinfo.mem->alloc_sarray) + ((j_common_ptr) &cinfo, JPOOL_IMAGE, (JDIMENSION)row_stride, 1); + + /* Save the buffer in case of suspension to be able to reuse it later: */ + Internals->SampBuffer = buffer; + } + else + { + /* JSAMPLEs per row in output buffer */ + row_stride = cinfo.output_width * cinfo.output_components; + row_stride *= sizeof(JSAMPLE); + + /* Suspension: re-use the buffer: */ + buffer = (JSAMPARRAY)Internals->SampBuffer; + } + + /* Step 6: while (scan lines remain to be read) */ + /* jpeg_read_scanlines(...); */ + + /* Here we use the library's state variable cinfo.output_scanline as the + * loop counter, so that we don't have to keep track ourselves. + */ + while (cinfo.output_scanline < cinfo.output_height) { + /* jpeg_read_scanlines expects an array of pointers to scanlines. + * Here the array is only one element long, but you could ask for + * more than one scanline at a time if that's more convenient. + */ + if( jpeg_read_scanlines(&cinfo, buffer, 1) == 0 ) + { + /* Suspension in jpeg_read_scanlines */ + Internals->StateSuspension = 3; + return true; + } + os.write((char*)buffer[0], row_stride); + } + + /* Step 7: Finish decompression */ + + if( jpeg_finish_decompress(&cinfo) == FALSE ) + { + /* Suspension: jpeg_finish_decompress */ + Internals->StateSuspension = 4; + return true; + } + + /* we are done decompressing the file, now is a good time to store the type + of compression used: lossless or not */ + if( cinfo.process == JPROC_LOSSLESS ) + { + LossyFlag = false; + } + else + { + LossyFlag = true; + } + + /* Step 8: Release JPEG decompression object */ + + /* This is an important step since it will release a good deal of memory. */ + jpeg_destroy_decompress(&cinfo); + + /* After finish_decompress, we can close the input file. + * Here we postpone it until after no more JPEG errors are possible, + * so as to simplify the setjmp error logic above. (Actually, I don't + * think that jpeg_destroy can do an error exit, but why assume anything...) + */ + //fclose(infile); + + /* At this point you may want to check to see whether any corrupt-data + * warnings occurred (test whether jerr.pub.num_warnings is nonzero). + */ + /* gdcmData/D_CLUNIE_MR4_JPLY.dcm produces a single warning: + * Invalid SOS parameters for sequential JPEG + * Be nice with this one: + */ + if( jerr.pub.num_warnings > 1 ) + { + gdcmErrorMacro( "Too many warning during decompression of JPEG stream: " << jerr.pub.num_warnings ); + return false; + } + /* In any case make sure the we reset the internal state suspension */ + Internals->StateSuspension = 0; + + /* And we're done! */ + return true; +} + +/* + * jdatadst.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains compression data destination routines for the case of + * emitting JPEG data to a file (or any stdio stream). While these routines + * are sufficient for most applications, some will want to use a different + * destination manager. + * IMPORTANT: we assume that fwrite() will correctly transcribe an array of + * JOCTETs into 8-bit-wide elements on external storage. If char is wider + * than 8 bits on your machine, you may need to do some tweaking. + */ + +/** + * \brief very low level C 'structure', used to decode jpeg file + * Should not appear in the Doxygen supplied documentation + */ +typedef struct { + struct jpeg_destination_mgr pub; /* public fields */ + + std::ostream * outfile; /* target stream */ + JOCTET * buffer; /* start of buffer */ +} my_destination_mgr; + +typedef my_destination_mgr * my_dest_ptr; + +#define OUTPUT_BUF_SIZE 4096 /* choose an efficiently fwrite'able size */ + +/* + * Initialize destination --- called by jpeg_start_compress + * before any data is actually written. + */ + +METHODDEF(void) +init_destination (j_compress_ptr cinfo) +{ + my_dest_ptr dest = (my_dest_ptr) cinfo->dest; + + /* Allocate the output buffer --- it will be released when done with image */ + dest->buffer = (JOCTET *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + OUTPUT_BUF_SIZE * SIZEOF(JOCTET)); + + dest->pub.next_output_byte = dest->buffer; + dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; +} + + +/* + * Empty the output buffer --- called whenever buffer fills up. + * + * In typical applications, this should write the entire output buffer + * (ignoring the current state of next_output_byte & free_in_buffer), + * reset the pointer & count to the start of the buffer, and return TRUE + * indicating that the buffer has been dumped. + * + * In applications that need to be able to suspend compression due to output + * overrun, a FALSE return indicates that the buffer cannot be emptied now. + * In this situation, the compressor will return to its caller (possibly with + * an indication that it has not accepted all the supplied scanlines). The + * application should resume compression after it has made more room in the + * output buffer. Note that there are substantial restrictions on the use of + * suspension --- see the documentation. + * + * When suspending, the compressor will back up to a convenient restart point + * (typically the start of the current MCU). next_output_byte & free_in_buffer + * indicate where the restart point will be if the current call returns FALSE. + * Data beyond this point will be regenerated after resumption, so do not + * write it out when emptying the buffer externally. + */ + +METHODDEF(boolean) +empty_output_buffer (j_compress_ptr cinfo) +{ + my_dest_ptr dest = (my_dest_ptr) cinfo->dest; + + //if (JFWRITE(dest->outfile, dest->buffer, OUTPUT_BUF_SIZE) != + // (size_t) OUTPUT_BUF_SIZE) + // ERREXIT(cinfo, JERR_FILE_WRITE); + size_t output_buf_size = OUTPUT_BUF_SIZE; + if( !dest->outfile->write((char*)dest->buffer, output_buf_size) ) + { + ERREXIT(cinfo, JERR_FILE_WRITE); + } + + dest->pub.next_output_byte = dest->buffer; + dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; + + return TRUE; +} + + +/* + * Terminate destination --- called by jpeg_finish_compress + * after all data has been written. Usually needs to flush buffer. + * + * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding + * application must deal with any cleanup that should happen even + * for error exit. + */ + +METHODDEF(void) +term_destination (j_compress_ptr cinfo) +{ + my_dest_ptr dest = (my_dest_ptr) cinfo->dest; + size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer; + + /* Write any data remaining in the buffer */ + if (datacount > 0) { + //if (JFWRITE(dest->outfile, dest->buffer, datacount) != datacount) + // ERREXIT(cinfo, JERR_FILE_WRITE); + if( !dest->outfile->write((char*)dest->buffer, datacount) ) + ERREXIT(cinfo, JERR_FILE_WRITE); + } + //fflush(dest->outfile); + dest->outfile->flush(); + /* Make sure we wrote the output file OK */ + //if (ferror(dest->outfile)) + if (dest->outfile->fail()) + ERREXIT(cinfo, JERR_FILE_WRITE); +} + + +/* + * Prepare for output to a stdio stream. + * The caller must have already opened the stream, and is responsible + * for closing it after finishing compression. + */ + +GLOBAL(void) +jpeg_stdio_dest (j_compress_ptr cinfo, /*FILE * */ std::ostream * outfile) +{ + my_dest_ptr dest; + + /* The destination object is made permanent so that multiple JPEG images + * can be written to the same file without re-executing jpeg_stdio_dest. + * This makes it dangerous to use this manager and a different destination + * manager serially with the same JPEG object, because their private object + * sizes may be different. Caveat programmer. + */ + if (cinfo->dest == NULL) { /* first time for this JPEG object? */ + cinfo->dest = (struct jpeg_destination_mgr *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + SIZEOF(my_destination_mgr)); + } + + dest = (my_dest_ptr) cinfo->dest; + dest->pub.init_destination = init_destination; + dest->pub.empty_output_buffer = empty_output_buffer; + dest->pub.term_destination = term_destination; + dest->outfile = outfile; +} + +/* + * Sample routine for JPEG compression. We assume that the target file name + * and a compression quality factor are passed in. + */ + +bool JPEGBITSCodec::InternalCode(const char* input, unsigned long len, std::ostream &os) +{ + int quality = 100; (void)len; + (void)quality; + JSAMPLE * image_buffer = (JSAMPLE*)input; /* Points to large array of R,G,B-order data */ + const unsigned int *dims = this->GetDimensions(); + int image_height = dims[1]; /* Number of rows in image */ + int image_width = dims[0]; /* Number of columns in image */ + + /* This struct contains the JPEG compression parameters and pointers to + * working space (which is allocated as needed by the JPEG library). + * It is possible to have several such structures, representing multiple + * compression/decompression processes, in existence at once. We refer + * to any one struct (and its associated working data) as a "JPEG object". + */ + struct jpeg_compress_struct cinfo; + /* This struct represents a JPEG error handler. It is declared separately + * because applications often want to supply a specialized error handler + * (see the second half of this file for an example). But here we just + * take the easy way out and use the standard error handler, which will + * print a message on stderr and call exit() if compression fails. + * Note that this struct must live as long as the main JPEG parameter + * struct, to avoid dangling-pointer problems. + */ + struct jpeg_error_mgr jerr; + /* More stuff */ + //FILE * outfile; /* target file */ + std::ostream * outfile = &os; + JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ + size_t row_stride; /* physical row width in image buffer */ + + /* Step 1: allocate and initialize JPEG compression object */ + + /* We have to set up the error handler first, in case the initialization + * step fails. (Unlikely, but it could happen if you are out of memory.) + * This routine fills in the contents of struct jerr, and returns jerr's + * address which we place into the link field in cinfo. + */ + cinfo.err = jpeg_std_error(&jerr); + /* Now we can initialize the JPEG compression object. */ + jpeg_create_compress(&cinfo); + + /* Step 2: specify data destination (eg, a file) */ + /* Note: steps 2 and 3 can be done in either order. */ + + /* Here we use the library-supplied code to send compressed data to a + * stdio stream. You can also write your own code to do something else. + * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that + * requires it in order to write binary files. + */ + //if ((outfile = fopen(filename, "wb")) == NULL) { + // fprintf(stderr, "can't open %s\n", filename); + // exit(1); + //} + jpeg_stdio_dest(&cinfo, outfile); + + /* Step 3: set parameters for compression */ + + /* First we supply a description of the input image. + * Four fields of the cinfo struct must be filled in: + */ + cinfo.image_width = image_width; /* image width and height, in pixels */ + cinfo.image_height = image_height; + + switch( this->GetPhotometricInterpretation() ) + { + case PhotometricInterpretation::MONOCHROME1: + case PhotometricInterpretation::MONOCHROME2: + case PhotometricInterpretation::PALETTE_COLOR: + cinfo.input_components = 1; /* # of color components per pixel */ + cinfo.in_color_space = JCS_GRAYSCALE; /* colorspace of input image */ + break; + case PhotometricInterpretation::RGB: + case PhotometricInterpretation::YBR_RCT: + case PhotometricInterpretation::YBR_ICT: + cinfo.input_components = 3; /* # of color components per pixel */ + cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ + break; + case PhotometricInterpretation::YBR_FULL: + case PhotometricInterpretation::YBR_FULL_422: + case PhotometricInterpretation::YBR_PARTIAL_420: + case PhotometricInterpretation::YBR_PARTIAL_422: + cinfo.input_components = 3; /* # of color components per pixel */ + cinfo.in_color_space = JCS_YCbCr; /* colorspace of input image */ + break; + case PhotometricInterpretation::HSV: + case PhotometricInterpretation::ARGB: + case PhotometricInterpretation::CMYK: + // TODO ! + case PhotometricInterpretation::UNKNOW: + case PhotometricInterpretation::PI_END: // To please compiler + return false; + } + //if ( cinfo.process == JPROC_LOSSLESS ) + // { + // cinfo.in_color_space = JCS_UNKNOWN; + // } + //assert( cinfo.image_height * cinfo.image_width * cinfo.input_components * sizeof(JSAMPLE) == len ); + + /* Now use the library's routine to set default compression parameters. + * (You must set at least cinfo.in_color_space before calling this, + * since the defaults depend on the source color space.) + */ + jpeg_set_defaults(&cinfo); + + /* + * predictor = 1 + * point_transform = 0 + * => lossless transformation. + * Basicaly you need to have point_transform = 0, but you can pick whichever predictor [1...7] you want + * TODO: is there a way to pick the right predictor (best compression/fastest ?) + */ + if( Lossless ) + { + jpeg_simple_lossless (&cinfo, 1, 0); + //jpeg_simple_lossless (&cinfo, 7, 0); + } + + /* Now you can set any non-default parameters you wish to. + * Here we just illustrate the use of quality (quantization table) scaling: + */ + if( Lossless ) + { + assert( Quality == 100 ); + } + jpeg_set_quality(&cinfo, Quality, TRUE /* limit to baseline-JPEG values */); + + /* + * See write_file_header + */ + cinfo.write_JFIF_header = 0; + //cinfo.density_unit = 2; + //cinfo.X_density = 2; + //cinfo.Y_density = 5; + + /* Step 4: Start compressor */ + + /* TRUE ensures that we will write a complete interchange-JPEG file. + * Pass TRUE unless you are very sure of what you're doing. + */ + jpeg_start_compress(&cinfo, TRUE); + + /* Step 5: while (scan lines remain to be written) */ + /* jpeg_write_scanlines(...); */ + + /* Here we use the library's state variable cinfo.next_scanline as the + * loop counter, so that we don't have to keep track ourselves. + * To keep things simple, we pass one scanline per call; you can pass + * more if you wish, though. + */ + row_stride = image_width * cinfo.input_components; /* JSAMPLEs per row in image_buffer */ + + if( this->GetPlanarConfiguration() == 0 ) + { + while (cinfo.next_scanline < cinfo.image_height) { + /* jpeg_write_scanlines expects an array of pointers to scanlines. + * Here the array is only one element long, but you could pass + * more than one scanline at a time if that's more convenient. + */ + row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride]; + (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); + } + } + else + { + /* + * warning: Need to read C.7.6.3.1.3 Planar Configuration (see note about Planar Configuration dummy value) + */ + JSAMPLE *tempbuffer = (JSAMPLE*)malloc( row_stride * sizeof(JSAMPLE) ); + row_pointer[0] = tempbuffer; + int offset = image_height * image_width; + while (cinfo.next_scanline < cinfo.image_height) { + assert( row_stride % 3 == 0 ); + JSAMPLE* ptempbuffer = tempbuffer; + JSAMPLE* red = image_buffer + cinfo.next_scanline * row_stride / 3; + JSAMPLE* green = image_buffer + cinfo.next_scanline * row_stride / 3 + offset; + JSAMPLE* blue = image_buffer + cinfo.next_scanline * row_stride / 3 + offset * 2; + for(size_t i = 0; i < row_stride / 3; ++i ) + { + *ptempbuffer++ = *red++; + *ptempbuffer++ = *green++; + *ptempbuffer++ = *blue++; + } + (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); + } + free(tempbuffer); + } + + /* Step 6: Finish compression */ + + jpeg_finish_compress(&cinfo); + /* After finish_compress, we can close the output file. */ + //fclose(outfile); + + /* Step 7: release JPEG compression object */ + + /* This is an important step since it will release a good deal of memory. */ + jpeg_destroy_compress(&cinfo); + + /* And we're done! */ + return true; +} + +bool JPEGBITSCodec::EncodeBuffer(std::ostream &os, const char *data, size_t datalen) +{ + (void)datalen; + JSAMPLE * image_buffer = (JSAMPLE*)data; /* Points to large array of R,G,B-order data */ + const unsigned int *dims = this->GetDimensions(); + int image_height = dims[1]; /* Number of rows in image */ + int image_width = dims[0]; /* Number of columns in image */ + + /* This struct contains the JPEG compression parameters and pointers to + * working space (which is allocated as needed by the JPEG library). + * It is possible to have several such structures, representing multiple + * compression/decompression processes, in existence at once. We refer + * to any one struct (and its associated working data) as a "JPEG object". + */ + jpeg_compress_struct &cinfo = Internals->cinfo_comp; + /* This struct represents a JPEG error handler. It is declared separately + * because applications often want to supply a specialized error handler + * (see the second half of this file for an example). But here we just + * take the easy way out and use the standard error handler, which will + * print a message on stderr and call exit() if compression fails. + * Note that this struct must live as long as the main JPEG parameter + * struct, to avoid dangling-pointer problems. + */ + my_error_mgr &jerr = Internals->jerr; + /* More stuff */ + //FILE * outfile; /* target file */ + std::ostream *outfile = &os; + JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ + size_t row_stride; /* physical row width in image buffer */ + + if( Internals->StateSuspension == 0 ) + { + /* Step 1: allocate and initialize JPEG compression object */ + + /* We have to set up the error handler first, in case the initialization + * step fails. (Unlikely, but it could happen if you are out of memory.) + * This routine fills in the contents of struct jerr, and returns jerr's + * address which we place into the link field in cinfo. + */ + cinfo.err = jpeg_std_error(&jerr.pub); + /* Now we can initialize the JPEG compression object. */ + jpeg_create_compress(&cinfo); + + /* Step 2: specify data destination (eg, a file) */ + /* Note: steps 2 and 3 can be done in either order. */ + + /* Here we use the library-supplied code to send compressed data to a + * stdio stream. You can also write your own code to do something else. + * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that + * requires it in order to write binary files. + */ + //if ((outfile = fopen(filename, "wb")) == NULL) { + // fprintf(stderr, "can't open %s\n", filename); + // exit(1); + //} + } + if( Internals->StateSuspension == 0 ) + { + jpeg_stdio_dest(&cinfo, outfile); + } + + /* Step 3: set parameters for compression */ + + /* First we supply a description of the input image. + * Four fields of the cinfo struct must be filled in: + */ + if( Internals->StateSuspension == 0 ) + { + cinfo.image_width = image_width; /* image width and height, in pixels */ + cinfo.image_height = image_height; + } + + if( Internals->StateSuspension == 0 ) +{ + switch( this->GetPhotometricInterpretation() ) + { + case PhotometricInterpretation::MONOCHROME1: + case PhotometricInterpretation::MONOCHROME2: + case PhotometricInterpretation::PALETTE_COLOR: + cinfo.input_components = 1; /* # of color components per pixel */ + cinfo.in_color_space = JCS_GRAYSCALE; /* colorspace of input image */ + break; + case PhotometricInterpretation::RGB: + case PhotometricInterpretation::YBR_RCT: + case PhotometricInterpretation::YBR_ICT: + cinfo.input_components = 3; /* # of color components per pixel */ + cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ + break; + case PhotometricInterpretation::YBR_FULL: + case PhotometricInterpretation::YBR_FULL_422: + case PhotometricInterpretation::YBR_PARTIAL_420: + case PhotometricInterpretation::YBR_PARTIAL_422: + cinfo.input_components = 3; /* # of color components per pixel */ + cinfo.in_color_space = JCS_YCbCr; /* colorspace of input image */ + break; + case PhotometricInterpretation::HSV: + case PhotometricInterpretation::ARGB: + case PhotometricInterpretation::CMYK: + // TODO ! + case PhotometricInterpretation::UNKNOW: + case PhotometricInterpretation::PI_END: // To please compiler + return false; + } +} + //if ( cinfo.process == JPROC_LOSSLESS ) + // { + // cinfo.in_color_space = JCS_UNKNOWN; + // } + //assert( cinfo.image_height * cinfo.image_width * cinfo.input_components * sizeof(JSAMPLE) == len ); + + /* Now use the library's routine to set default compression parameters. + * (You must set at least cinfo.in_color_space before calling this, + * since the defaults depend on the source color space.) + */ +if( Internals->StateSuspension == 0 ) +{ + jpeg_set_defaults(&cinfo); +} + + /* + * predictor = 1 + * point_transform = 0 + * => lossless transformation. + * Basicaly you need to have point_transform = 0, but you can pick whichever predictor [1...7] you want + * TODO: is there a way to pick the right predictor (best compression/fastest ?) + */ +if( Internals->StateSuspension == 0 ) +{ + if( Lossless ) + { + jpeg_simple_lossless (&cinfo, 1, 0); + //jpeg_simple_lossless (&cinfo, 7, 0); + } +} + + /* Now you can set any non-default parameters you wish to. + * Here we just illustrate the use of quality (quantization table) scaling: + */ + if( Lossless ) + { + assert( Quality == 100 ); + } +if( Internals->StateSuspension == 0 ) +{ + jpeg_set_quality(&cinfo, Quality, TRUE /* limit to baseline-JPEG values */); +} + +if( Internals->StateSuspension == 0 ) +{ + /* + * See write_file_header + */ + cinfo.write_JFIF_header = 0; +} + //cinfo.density_unit = 2; + //cinfo.X_density = 2; + //cinfo.Y_density = 5; + + /* Step 4: Start compressor */ + +if( Internals->StateSuspension == 0 ) +{ + /* TRUE ensures that we will write a complete interchange-JPEG file. + * Pass TRUE unless you are very sure of what you're doing. + */ + jpeg_start_compress(&cinfo, TRUE); + Internals->StateSuspension = 1; +} + + /* Step 5: while (scan lines remain to be written) */ + /* jpeg_write_scanlines(...); */ + + /* Here we use the library's state variable cinfo.next_scanline as the + * loop counter, so that we don't have to keep track ourselves. + * To keep things simple, we pass one scanline per call; you can pass + * more if you wish, though. + */ + row_stride = image_width * cinfo.input_components; /* JSAMPLEs per row in image_buffer */ + +if ( Internals->StateSuspension == 1 ) +{ + assert( this->GetPlanarConfiguration() == 0 ); + assert( row_stride * sizeof(JSAMPLE) == datalen ); + { + //while (cinfo.next_scanline < cinfo.image_height) { + /* jpeg_write_scanlines expects an array of pointers to scanlines. + * Here the array is only one element long, but you could pass + * more than one scanline at a time if that's more convenient. + */ + row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride * 0]; + const JDIMENSION nscanline = jpeg_write_scanlines(&cinfo, row_pointer, 1); + assert( nscanline == 1 ); (void)nscanline; + assert(cinfo.next_scanline <= cinfo.image_height); + //} + } + if(cinfo.next_scanline == cinfo.image_height) + { +Internals->StateSuspension = 2; + } +} + + /* Step 6: Finish compression */ + +if (Internals->StateSuspension == 2 ) +{ + jpeg_finish_compress(&cinfo); + /* After finish_compress, we can close the output file. */ + //fclose(outfile); +} + + /* Step 7: release JPEG compression object */ + +if (Internals->StateSuspension == 2 ) +{ + /* This is an important step since it will release a good deal of memory. */ + jpeg_destroy_compress(&cinfo); + + Internals->StateSuspension = 0; +} + + /* And we're done! */ + return true; +} + +bool JPEGBITSCodec::IsStateSuspension() const +{ + return Internals->StateSuspension != 0; +} + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmJPEGCodec.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmJPEGCodec.cxx new file mode 100644 index 0000000..85a5f24 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmJPEGCodec.cxx @@ -0,0 +1,659 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmJPEGCodec.h" +#include "gdcmTransferSyntax.h" +#include "gdcmTrace.h" +#include "gdcmDataElement.h" +#include "gdcmSequenceOfFragments.h" +#include "gdcmSwapper.h" +#include "gdcmJPEG8Codec.h" +#include "gdcmJPEG12Codec.h" +#include "gdcmJPEG16Codec.h" + +#include +#include + +namespace gdcm +{ + +JPEGCodec::JPEGCodec():BitSample(0),Lossless(true),Quality(100) +{ + Internal = NULL; +} + +JPEGCodec::~JPEGCodec() +{ + delete Internal; +} + +void JPEGCodec::SetQuality(double q) +{ + Quality = (int)q;//not sure why a double is passed and stored in an int. + //the casting will happen here anyway, so making it explicit removes a warning. +} + +double JPEGCodec::GetQuality() const +{ + return Quality; +} + +void JPEGCodec::SetLossless(bool l) +{ + Lossless = l; +} + +bool JPEGCodec::GetLossless() const +{ + return Lossless; +} + +bool JPEGCodec::CanDecode(TransferSyntax const &ts) const +{ + return ts == TransferSyntax::JPEGBaselineProcess1 + || ts == TransferSyntax::JPEGExtendedProcess2_4 + || ts == TransferSyntax::JPEGExtendedProcess3_5 + || ts == TransferSyntax::JPEGSpectralSelectionProcess6_8 + || ts == TransferSyntax::JPEGFullProgressionProcess10_12 + || ts == TransferSyntax::JPEGLosslessProcess14 + || ts == TransferSyntax::JPEGLosslessProcess14_1; +} + +bool JPEGCodec::CanCode(TransferSyntax const &ts) const +{ + return ts == TransferSyntax::JPEGBaselineProcess1 + || ts == TransferSyntax::JPEGExtendedProcess2_4 + || ts == TransferSyntax::JPEGExtendedProcess3_5 + || ts == TransferSyntax::JPEGSpectralSelectionProcess6_8 + || ts == TransferSyntax::JPEGFullProgressionProcess10_12 + || ts == TransferSyntax::JPEGLosslessProcess14 + || ts == TransferSyntax::JPEGLosslessProcess14_1; +} + +void JPEGCodec::SetPixelFormat(PixelFormat const &pt) +{ + ImageCodec::SetPixelFormat(pt); + // Here is the deal: D_CLUNIE_RG3_JPLY.dcm is a 12Bits Stored / 16 Bits Allocated image + // the jpeg encapsulated is: a 12 Sample Precision + // so far so good. + // So what if we are dealing with image such as: SIEMENS_MOSAIC_12BitsStored-16BitsJPEG.dcm + // which is also a 12Bits Stored / 16 Bits Allocated image + // however the jpeg encapsulated is now a 16 Sample Precision + + // We have the choice to decide to use Bits Stored or Bits Allocated, however in the case of + // such an image as: gdcmData/MR16BitsAllocated_8BitsStored.dcm we are required to use + // bits allocated to deal with the logic to decide withe the encoder + SetBitSample( pt.GetBitsAllocated() ); + //SetBitSample( pt.GetBitsStored() ); +} + +void JPEGCodec::SetupJPEGBitCodec(int bit) +{ + BitSample = bit; + delete Internal; Internal = NULL; + assert( Internal == NULL ); + // what should I do with those single bit images ? + if ( BitSample <= 8 ) + { + gdcmDebugMacro( "Using JPEG8" ); + Internal = new JPEG8Codec; + } + else if ( /*BitSample > 8 &&*/ BitSample <= 12 ) + { + gdcmDebugMacro( "Using JPEG12" ); + Internal = new JPEG12Codec; + } + else if ( /*BitSample > 12 &&*/ BitSample <= 16 ) + { + gdcmDebugMacro( "Using JPEG16" ); + Internal = new JPEG16Codec; + } + else + { + // gdcmNonImageData/RT/RTDOSE.dcm + gdcmWarningMacro( "Cannot instantiate JPEG codec for bit sample: " << bit ); + // Clearly make sure Internal will not be used + delete Internal; + Internal = NULL; + } +} + +void JPEGCodec::SetBitSample(int bit) +{ + SetupJPEGBitCodec(bit); + if( Internal ) + { + Internal->SetDimensions( this->GetDimensions() ); + Internal->SetPlanarConfiguration( this->GetPlanarConfiguration() ); + Internal->SetPhotometricInterpretation( this->GetPhotometricInterpretation() ); + Internal->ImageCodec::SetPixelFormat( this->ImageCodec::GetPixelFormat() ); + //Internal->SetNeedOverlayCleanup( this->AreOverlaysInPixelData() ); + } +} + +/* +A.4.1 JPEG image compression +For all images, including all frames of a multi-frame image, the JPEG +Interchange Format shall be used (the table specification shall be included). +*/ +bool JPEGCodec::Decode(DataElement const &in, DataElement &out) +{ + assert( Internal ); + out = in; + // Fragments... + const SequenceOfFragments *sf0 = in.GetSequenceOfFragments(); + const ByteValue *jpegbv = in.GetByteValue(); + if( !sf0 && !jpegbv ) return false; + std::stringstream os; + if( sf0 ) + { + for(unsigned int i = 0; i < sf0->GetNumberOfFragments(); ++i) + { + std::stringstream is; + const Fragment &frag = sf0->GetFragment(i); + if( frag.IsEmpty() ) return false; + const ByteValue &bv = dynamic_cast(frag.GetValue()); + size_t bv_len = bv.GetLength(); + char *mybuffer = new char[bv_len]; + bool b = bv.GetBuffer(mybuffer, bv.GetLength()); + assert( b ); (void)b; + is.write(mybuffer, bv.GetLength()); + delete[] mybuffer; + bool r = DecodeByStreams(is, os); + // PHILIPS_Gyroscan-12-MONO2-Jpeg_Lossless.dcm + if( !r ) + { + gdcmDebugMacro( "Failed to decompress Frag #" << i ); + const bool suspended = Internal->IsStateSuspension(); + const size_t nfrags = sf0->GetNumberOfFragments(); + // In case of chunked-jpeg, this is always an error + if( suspended ) + return false; + // Ok so we are decoding a multiple frame jpeg DICOM file: + // if we are lucky, we might be trying to decode some sort of broken multi-frame + // DICOM file. In this case check that we have read all Fragment properly: + if( i >= this->GetDimensions()[2] ) + { + // JPEGInvalidSecondFrag.dcm + assert( nfrags == this->GetNumberOfDimensions() ); (void)nfrags; // sentinel + gdcmWarningMacro( "Invalid JPEG Fragment found at pos #" << i + 1 << ". Skipping it" ); + } + else + return false; + } + } + } + else if ( jpegbv ) + { + // GEIIS Icon: + std::stringstream is0; + size_t jpegbv_len = jpegbv->GetLength(); + char *mybuffer0 = new char[jpegbv_len]; + bool b0 = jpegbv->GetBuffer(mybuffer0, jpegbv->GetLength()); + assert( b0 ); (void)b0; + is0.write(mybuffer0, jpegbv->GetLength()); + delete[] mybuffer0; + bool r = DecodeByStreams(is0, os); + if( !r ) + { + // let's try another time: + // JPEGDefinedLengthSequenceOfFragments.dcm + is0.seekg(0); + SequenceOfFragments sf_bug; + try { + sf_bug.Read(is0,true); + } catch ( ... ) { + return false; + } + + const SequenceOfFragments *sf = &sf_bug; + for(unsigned int i = 0; i < sf->GetNumberOfFragments(); ++i) + { + std::stringstream is; + const Fragment &frag = sf->GetFragment(i); + if( frag.IsEmpty() ) return false; + const ByteValue &bv = dynamic_cast(frag.GetValue()); + size_t bv_len = bv.GetLength(); + char *mybuffer = new char[bv_len]; + bool b = bv.GetBuffer(mybuffer, bv.GetLength()); + assert( b ); (void)b; + is.write(mybuffer, bv.GetLength()); + delete[] mybuffer; + bool r2 = DecodeByStreams(is, os); + if( !r2 ) + { + return false; + } + } + + } + } + //assert( pos == len ); + const size_t sizeOfOs = os.tellp(); + os.seekp( 0, std::ios::beg ); + ByteValue * bv = new ByteValue; + bv->SetLength( (uint32_t)sizeOfOs ); + bv->Read( os ); + out.SetValue( *bv ); + + return true; +} + +void JPEGCodec::ComputeOffsetTable(bool b) +{ + (void)b; + // Not implemented + assert(0); +} + +bool JPEGCodec::GetHeaderInfo( std::istream & is, TransferSyntax &ts ) +{ + assert( Internal ); + if ( !Internal->GetHeaderInfo(is, ts) ) + { + // let's check if this is one of those buggy lossless JPEG + if( this->BitSample != Internal->BitSample ) + { + // MARCONI_MxTWin-12-MONO2-JpegLossless-ZeroLengthSQ.dcm + // PHILIPS_Gyroscan-12-MONO2-Jpeg_Lossless.dcm + gdcmWarningMacro( "DICOM header said it was " << this->BitSample << + " but JPEG header says it's: " << Internal->BitSample ); + if( this->BitSample < Internal->BitSample ) + { + //assert(0); // Outside buffer will be too small + } + is.seekg(0, std::ios::beg); + SetupJPEGBitCodec( Internal->BitSample ); + if( Internal && Internal->GetHeaderInfo(is, ts) ) + { + // Foward everything back to meta jpeg codec: + this->SetLossyFlag( Internal->GetLossyFlag() ); + this->SetDimensions( Internal->GetDimensions() ); + this->SetPhotometricInterpretation( Internal->GetPhotometricInterpretation() ); + int prep = this->GetPixelFormat().GetPixelRepresentation(); + this->PF = Internal->GetPixelFormat(); // DO NOT CALL SetPixelFormat + this->PF.SetPixelRepresentation( (uint16_t)prep ); + return true; + } + else + { + //assert(0); // FATAL ERROR + gdcmErrorMacro( "Do not support this JPEG Type" ); + return false; + } + } + return false; + } + // else + // Foward everything back to meta jpeg codec: + this->SetLossyFlag( Internal->GetLossyFlag() ); + this->SetDimensions( Internal->GetDimensions() ); + this->SetPhotometricInterpretation( Internal->GetPhotometricInterpretation() ); + this->PF = Internal->GetPixelFormat(); // DO NOT CALL SetPixelFormat + + if( this->PI != Internal->PI ) + { + gdcmWarningMacro( "PhotometricInterpretation issue" ); + this->PI = Internal->PI; + } + + return true; +} + +bool JPEGCodec::Code(DataElement const &in, DataElement &out) +{ + out = in; + + // Create a Sequence Of Fragments: + SmartPointer sq = new SequenceOfFragments; + const Tag itemStart(0xfffe, 0xe000); + //sq->GetTable().SetTag( itemStart ); + //const char dummy[4] = {}; + //sq->GetTable().SetByteValue( dummy, sizeof(dummy) ); + + const ByteValue *bv = in.GetByteValue(); + const unsigned int *dims = this->GetDimensions(); + const char *input = bv->GetPointer(); + unsigned long len = bv->GetLength(); + unsigned long image_len = len / dims[2]; + if(!Internal) return false; + + // forward parameter to low level bits implementation (8/12/16) + Internal->SetLossless( this->GetLossless() ); + Internal->SetQuality( this->GetQuality() ); + + for(unsigned int dim = 0; dim < dims[2]; ++dim) + { + std::stringstream os; + const char *p = input + dim * image_len; + bool r = Internal->InternalCode(p, image_len, os); + if( !r ) + { + return false; + } + + std::string str = os.str(); + assert( str.size() ); + Fragment frag; + //frag.SetTag( itemStart ); + VL::Type strSize = (VL::Type)str.size(); + frag.SetByteValue( &str[0], strSize ); + sq->AddFragment( frag ); + + } + //unsigned int n = sq->GetNumberOfFragments(); + assert( sq->GetNumberOfFragments() == dims[2] ); + out.SetValue( *sq ); + + return true; +} + + +bool JPEGCodec::DecodeByStreams(std::istream &is, std::ostream &os) +{ + std::stringstream tmpos; + if ( !Internal->DecodeByStreams(is,tmpos) ) + { +#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + // let's check if this is one of those buggy lossless JPEG + if( this->BitSample != Internal->BitSample ) + { + // MARCONI_MxTWin-12-MONO2-JpegLossless-ZeroLengthSQ.dcm + // PHILIPS_Gyroscan-12-MONO2-Jpeg_Lossless.dcm + gdcmWarningMacro( "DICOM header said it was " << this->BitSample << + " but JPEG header says it's: " << Internal->BitSample ); + if( this->BitSample < Internal->BitSample ) + { + //assert(0); // Outside buffer will be too small + } + is.seekg(0, std::ios::beg); + SetupJPEGBitCodec( Internal->BitSample ); + if( Internal ) + { + //Internal->SetPixelFormat( this->GetPixelFormat() ); // FIXME + Internal->SetDimensions( this->GetDimensions() ); + Internal->SetPlanarConfiguration( this->GetPlanarConfiguration() ); // meaningless ? + Internal->SetPhotometricInterpretation( this->GetPhotometricInterpretation() ); + if( Internal->DecodeByStreams(is,tmpos) ) + { + return ImageCodec::DecodeByStreams(tmpos,os); + } + else + { + gdcmErrorMacro( "Could not succeed after 2 tries" ); + } + } + } +#endif + return false; + } + if( this->PlanarConfiguration != Internal->PlanarConfiguration ) + { + gdcmWarningMacro( "PlanarConfiguration issue" ); + this->PlanarConfiguration = Internal->PlanarConfiguration; + //this->RequestPlanarConfiguration = true; + } + if( this->PI != Internal->PI ) + { + gdcmWarningMacro( "PhotometricInterpretation issue" ); + this->PI = Internal->PI; + } + if( this->PF == PixelFormat::UINT12 + || this->PF == PixelFormat::INT12 ) + { + this->PF.SetBitsAllocated( 16 ); + } + + return ImageCodec::DecodeByStreams(tmpos,os); +} + +bool JPEGCodec::IsValid(PhotometricInterpretation const &pi) +{ + bool ret = false; + switch( pi ) + { + // JPEGCodec can produce the following PhotometricInterpretation as output: + case PhotometricInterpretation::MONOCHROME1: + case PhotometricInterpretation::MONOCHROME2: + case PhotometricInterpretation::PALETTE_COLOR: + case PhotometricInterpretation::RGB: + case PhotometricInterpretation::YBR_FULL: + case PhotometricInterpretation::YBR_FULL_422: + case PhotometricInterpretation::YBR_PARTIAL_422: + case PhotometricInterpretation::YBR_PARTIAL_420: + ret = true; + break; + default: + ; +// case HSV: +// case ARGB: // retired +// case CMYK: +// case YBR_RCT: +// case YBR_ICT: +// ret = false; + } + return ret; +} + +bool JPEGCodec::DecodeExtent( + char *buffer, + unsigned int xmin, unsigned int xmax, + unsigned int ymin, unsigned int ymax, + unsigned int zmin, unsigned int zmax, + std::istream & is + ) +{ + BasicOffsetTable bot; + bot.Read( is ); + + const unsigned int * dimensions = this->GetDimensions(); + const PixelFormat & pf = this->GetPixelFormat(); + //assert( pf.GetBitsAllocated() % 8 == 0 ); + assert( pf != PixelFormat::SINGLEBIT ); + //assert( pf != PixelFormat::UINT12 && pf != PixelFormat::INT12 ); + + if( NumberOfDimensions == 2 ) + { + //char *dummy_buffer = NULL; + std::vector vdummybuffer; + size_t buf_size = 0; + + const Tag seqDelItem(0xfffe,0xe0dd); + gdcm::Fragment frag; + unsigned int nfrags = 0; + try + { + while( frag.ReadPreValue(is) && frag.GetTag() != seqDelItem ) + { + ++nfrags; + size_t fraglen = frag.GetVL(); + size_t oldlen = vdummybuffer.size(); + // update + buf_size = fraglen + oldlen; + vdummybuffer.resize( buf_size ); + //dummy_buffer = &vdummybuffer[0]; + // read J2K + is.read( &vdummybuffer[oldlen], fraglen ); + } + assert( frag.GetTag() == seqDelItem && frag.GetVL() == 0 ); + } + catch(Exception &ex) + { + (void)ex; +#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION + // that's ok ! In all cases the whole file was read, because + // Fragment::Read only fail on eof() reached 1. + // SIEMENS-JPEG-CorruptFrag.dcm is more difficult to deal with, we have a + // partial fragment, read we decide to add it anyway to the stack of + // fragments (eof was reached so we need to clear error bit) + if( frag.GetTag() == Tag(0xfffe,0xe000) ) + { + gdcmWarningMacro( "Pixel Data Fragment could be corrupted. Use file at own risk" ); + //Fragments.push_back( frag ); + is.clear(); // clear the error bit + } + // 2. GENESIS_SIGNA-JPEG-CorruptFrag.dcm + else if ( frag.GetTag() == Tag(0xddff,0x00e0) ) + { + assert( nfrags == 1 ); + const ByteValue *bv = frag.GetByteValue(); + assert( (unsigned char)bv->GetPointer()[ bv->GetLength() - 1 ] == 0xfe ); + // Yes this is an extra copy, this is a bug anyway, go fix YOUR code + frag.SetByteValue( bv->GetPointer(), bv->GetLength() - 1 ); + assert( 0 ); + gdcmWarningMacro( "JPEG Fragment length was declared with an extra byte" + " at the end: stripped !" ); + is.clear(); // clear the error bit + } + else + { + // 3. gdcm-JPEG-LossLess3a.dcm: easy case, an extra tag was found + // instead of terminator (eof is the next char) + gdcmWarningMacro( "Reading failed at Tag:" << frag.GetTag() << + ". Use file at own risk." << ex.what() ); + } +#endif /* GDCM_SUPPORT_BROKEN_IMPLEMENTATION */ + } + + assert( zmin == zmax ); + assert( zmin == 0 ); + + std::stringstream iis; + iis.write( &vdummybuffer[0], vdummybuffer.size() ); + std::stringstream os; + bool b = DecodeByStreams(iis,os); + if(!b) return false; + assert( b ); + + const unsigned int rowsize = xmax - xmin + 1; + const unsigned int colsize = ymax - ymin + 1; + const unsigned int bytesPerPixel = pf.GetPixelSize(); + os.seekg(0, std::ios::beg ); + assert( os.good() ); + std::istream *theStream = &os; + std::vector buffer1; + buffer1.resize( rowsize*bytesPerPixel ); + char *tmpBuffer1 = &buffer1[0]; + unsigned int y, z; + std::streamoff theOffset; + for (z = zmin; z <= zmax; ++z) + { + for (y = ymin; y <= ymax; ++y) + { + theStream->seekg(std::ios::beg); + theOffset = 0 + (z*dimensions[1]*dimensions[0] + y*dimensions[0] + xmin)*bytesPerPixel; + theStream->seekg(theOffset); + theStream->read(tmpBuffer1, rowsize*bytesPerPixel); + memcpy(&(buffer[((z-zmin)*rowsize*colsize + + (y-ymin)*rowsize)*bytesPerPixel]), + tmpBuffer1, rowsize*bytesPerPixel); + } + } + } + else if ( NumberOfDimensions == 3 ) + { + const Tag seqDelItem(0xfffe,0xe0dd); + gdcm::Fragment frag; + std::streamoff thestart = is.tellg(); + unsigned int numfrags = 0; + std::vector< size_t > offsets; + while( frag.ReadPreValue(is) && frag.GetTag() != seqDelItem ) + { + //std::streamoff relstart = is.tellg(); + //assert( relstart - thestart == 8 ); + std::streamoff off = frag.GetVL(); + offsets.push_back( off ); + is.seekg( off, std::ios::cur ); + ++numfrags; + } + assert( frag.GetTag() == seqDelItem && frag.GetVL() == 0 ); + assert( numfrags == offsets.size() ); + if( numfrags != Dimensions[2] ) + { + gdcmErrorMacro( "Not handled" ); + return false; + } + + for( unsigned int z = zmin; z <= zmax; ++z ) + { + size_t curoffset = std::accumulate( offsets.begin(), offsets.begin() + z, 0 ); + is.seekg( thestart + curoffset + 8 * z, std::ios::beg ); + is.seekg( 8, std::ios::cur ); + + //const size_t buf_size = offsets[z]; + //char *dummy_buffer = new char[ buf_size ]; + //is.read( dummy_buffer, buf_size ); + + std::stringstream os; + const bool b = DecodeByStreams(is, os); (void)b; + assert( b ); + /* free the memory containing the code-stream */ + //delete[] dummy_buffer; + + os.seekg(0, std::ios::beg ); + assert( os.good() ); + std::istream *theStream = &os; + + unsigned int rowsize = xmax - xmin + 1; + unsigned int colsize = ymax - ymin + 1; + unsigned int bytesPerPixel = pf.GetPixelSize(); + + std::vector buffer1; + buffer1.resize( rowsize*bytesPerPixel ); + char *tmpBuffer1 = &buffer1[0]; + unsigned int y; + std::streamoff theOffset; + for (y = ymin; y <= ymax; ++y) + { + theStream->seekg(std::ios::beg); + theOffset = 0 + (0*dimensions[1]*dimensions[0] + y*dimensions[0] + xmin)*bytesPerPixel; + theStream->seekg(theOffset); + theStream->read(tmpBuffer1, rowsize*bytesPerPixel); + memcpy(&(buffer[((z-zmin)*rowsize*colsize + + (y-ymin)*rowsize)*bytesPerPixel]), + tmpBuffer1, rowsize*bytesPerPixel); + } + } + } + return true; +} + +bool JPEGCodec::IsStateSuspension() const +{ + assert( 0 ); + return false; +} + +ImageCodec * JPEGCodec::Clone() const +{ + JPEGCodec *copy = new JPEGCodec; + ImageCodec &ic = *copy; + ic = *this; + assert( copy->PF == PF ); + //copy->SetupJPEGBitCodec( BitSample ); + copy->SetPixelFormat( GetPixelFormat() ); + assert( copy->BitSample == BitSample ); + copy->Lossless = Lossless; + copy->Quality = Quality; + + return copy; +} + +bool JPEGCodec::EncodeBuffer( std::ostream & out, + const char *inbuffer, size_t inlen) +{ + assert( Internal ); + return Internal->EncodeBuffer(out, inbuffer, inlen); +} + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmJPEGCodec.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmJPEGCodec.h new file mode 100644 index 0000000..dca0d82 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmJPEGCodec.h @@ -0,0 +1,102 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMJPEGCODEC_H +#define GDCMJPEGCODEC_H + +#include "gdcmImageCodec.h" + +namespace gdcm +{ + +class PixelFormat; +class TransferSyntax; +/** + * \brief JPEG codec + * Class to do JPEG (8bits, 12bits, 16bits lossy & lossless). + * It redispatch in between the different codec implementation: gdcm::JPEG8Codec, + * gdcm::JPEG12Codec & gdcm::JPEG16Codec + * It also support inconsistency in between DICOM header and JPEG compressed stream + * ImageCodec implementation for the JPEG case + * + * \note + * Things you should know if you ever want to dive into DICOM/JPEG world (among other): + * + * - http://groups.google.com/group/comp.protocols.dicom/browse_thread/thread/625e46919f2080e1 + * - http://groups.google.com/group/comp.protocols.dicom/browse_thread/thread/75fdfccc65a6243 + * - http://groups.google.com/group/comp.protocols.dicom/browse_thread/thread/2d525ef6a2f093ed + * - http://groups.google.com/group/comp.protocols.dicom/browse_thread/thread/6b93af410f8c921f + */ +class GDCM_EXPORT JPEGCodec : public ImageCodec +{ +friend class ImageRegionReader; +public: + JPEGCodec(); + ~JPEGCodec(); + bool CanDecode(TransferSyntax const &ts) const; + bool CanCode(TransferSyntax const &ts) const; + bool Decode(DataElement const &is, DataElement &os); + void SetPixelFormat(PixelFormat const &pf); + + /// Compute the offset table: + void ComputeOffsetTable(bool b); + + /// Compress into JPEG + bool Code(DataElement const &in, DataElement &out); + + virtual bool GetHeaderInfo(std::istream &is, TransferSyntax &ts); + virtual ImageCodec * Clone() const; + + //void SetReversible(bool res); + + void SetQuality(double q); + double GetQuality() const; + + void SetLossless(bool l); + bool GetLossless() const; + + virtual bool EncodeBuffer( std::ostream & out, + const char *inbuffer, size_t inlen); + +protected: + bool DecodeExtent( + char *buffer, + unsigned int xmin, unsigned int xmax, + unsigned int ymin, unsigned int ymax, + unsigned int zmin, unsigned int zmax, + std::istream & is + ); + + bool DecodeByStreams(std::istream &is, std::ostream &os); + bool IsValid(PhotometricInterpretation const &pi); + +protected: + // Internal method called by SetPixelFormat + // Instantiate the right jpeg codec (8, 12 or 16) + void SetBitSample(int bit); + + virtual bool IsStateSuspension() const; + +protected: + int BitSample; + bool Lossless; + int Quality; + +private: + void SetupJPEGBitCodec(int bit); + JPEGCodec *Internal; +}; + +} // end namespace gdcm + +#endif //GDCMJPEGCODEC_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmJPEGLSCodec.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmJPEGLSCodec.cxx new file mode 100644 index 0000000..7ac2205 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmJPEGLSCodec.cxx @@ -0,0 +1,513 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmJPEGLSCodec.h" +#include "gdcmTransferSyntax.h" +#include "gdcmSequenceOfFragments.h" +#include "gdcmDataElement.h" +#include "gdcmSwapper.h" + +#include + +// CharLS includes +#include "gdcm_charls.h" + +namespace gdcm +{ + +JPEGLSCodec::JPEGLSCodec():BufferLength(0),Lossless(true),LossyError(0) +{ +} + +JPEGLSCodec::~JPEGLSCodec() +{ +} + +void JPEGLSCodec::SetLossless(bool l) +{ + Lossless = l; +} + +bool JPEGLSCodec::GetLossless() const +{ + return Lossless; +} + +bool JPEGLSCodec::GetHeaderInfo(std::istream &is, TransferSyntax &ts) +{ +#ifndef GDCM_USE_JPEGLS + return false; +#else + is.seekg( 0, std::ios::end); + size_t buf_size = (size_t)is.tellg(); + //assert(buf_size < INT_MAX); + char *dummy_buffer = new char[(unsigned int)buf_size]; + is.seekg(0, std::ios::beg); + is.read( dummy_buffer, buf_size); + + JlsParameters metadata = {}; + //assert(buf_size < INT_MAX); + if (JpegLsReadHeader(dummy_buffer, (unsigned int)buf_size, &metadata) != OK) + { + return false; + } + delete[] dummy_buffer; + + // $1 = {width = 512, height = 512, bitspersample = 8, components = 1, allowedlossyerror = 0, ilv = ILV_NONE, colorTransform = 0, custom = {MAXVAL = 0, T1 = 0, T2 = 0, T3 = 0, RESET = 0}} + + this->Dimensions[0] = metadata.width; + this->Dimensions[1] = metadata.height; + if( metadata.bitspersample <= 8 ) + { + this->PF = PixelFormat( PixelFormat::UINT8 ); + } + else if( metadata.bitspersample <= 16 ) + { + assert( metadata.bitspersample > 8 ); + this->PF = PixelFormat( PixelFormat::UINT16 ); + } + else + { + assert(0); + } + this->PF.SetBitsStored( (uint16_t)metadata.bitspersample ); + assert( this->PF.IsValid() ); +// switch( metadata.bitspersample ) +// { +// case 8: +// this->PF = PixelFormat( PixelFormat::UINT8 ); +// break; +// case 12: +// this->PF = PixelFormat( PixelFormat::UINT16 ); +// this->PF.SetBitsStored( 12 ); +// break; +// case 16: +// this->PF = PixelFormat( PixelFormat::UINT16 ); +// break; +// default: +// assert(0); +// } + if( metadata.components == 1 ) + { + PI = PhotometricInterpretation::MONOCHROME2; + this->PF.SetSamplesPerPixel( 1 ); + } + else if( metadata.components == 3 ) + { + PI = PhotometricInterpretation::RGB; + this->PF.SetSamplesPerPixel( 3 ); + } + else assert(0); + + // allowedlossyerror == 0 => Lossless + LossyFlag = metadata.allowedlossyerror != 0; + + if( metadata.allowedlossyerror == 0 ) + { + ts = TransferSyntax::JPEGLSLossless; + } + else + { + ts = TransferSyntax::JPEGLSNearLossless; + } + + + return true; +#endif +} + +bool JPEGLSCodec::CanDecode(TransferSyntax const &ts) const +{ +#ifndef GDCM_USE_JPEGLS + return false; +#else + return ts == TransferSyntax::JPEGLSLossless + || ts == TransferSyntax::JPEGLSNearLossless; +#endif +} + +bool JPEGLSCodec::CanCode(TransferSyntax const &ts) const +{ +#ifndef GDCM_USE_JPEGLS + return false; +#else + return ts == TransferSyntax::JPEGLSLossless + || ts == TransferSyntax::JPEGLSNearLossless; +#endif +} + +bool JPEGLSCodec::DecodeByStreamsCommon(char *buffer, size_t totalLen, std::vector &rgbyteOut) +{ + const BYTE* pbyteCompressed = (const BYTE*)buffer; + size_t cbyteCompressed = totalLen; + + JlsParameters params = {}; + if(JpegLsReadHeader(pbyteCompressed, cbyteCompressed, ¶ms) != OK ) + { + gdcmDebugMacro( "Could not parse JPEG-LS header" ); + return false; + } + + // allowedlossyerror == 0 => Lossless + LossyFlag = params.allowedlossyerror!= 0; + + rgbyteOut.resize(params.height *params.width * ((params.bitspersample + 7) / 8) * params.components); + + JLS_ERROR result = JpegLsDecode(&rgbyteOut[0], rgbyteOut.size(), pbyteCompressed, cbyteCompressed, ¶ms); + + if (result != OK) + { + return false; + } + + return true; +} + +bool JPEGLSCodec::Decode(DataElement const &in, DataElement &out) +{ +#ifndef GDCM_USE_JPEGLS + return false; +#else + if( NumberOfDimensions == 2 ) + { + const SequenceOfFragments *sf = in.GetSequenceOfFragments(); + assert( sf ); + unsigned long totalLen = sf->ComputeByteLength(); + char *buffer = new char[totalLen]; + sf->GetBuffer(buffer, totalLen); + + std::vector rgbyteOut; + bool b = DecodeByStreamsCommon(buffer, totalLen, rgbyteOut); + if( !b ) return false; + delete[] buffer; + + out = in; + + out.SetByteValue( (char*)&rgbyteOut[0], (uint32_t)rgbyteOut.size() ); + return true; + } + else if( NumberOfDimensions == 3 ) + { + const SequenceOfFragments *sf = in.GetSequenceOfFragments(); + assert( sf ); + gdcmAssertAlwaysMacro( sf->GetNumberOfFragments() == Dimensions[2] ); + std::stringstream os; + for(unsigned int i = 0; i < sf->GetNumberOfFragments(); ++i) + { + const Fragment &frag = sf->GetFragment(i); + if( frag.IsEmpty() ) return false; + const ByteValue *bv = frag.GetByteValue(); + assert( bv ); + size_t totalLen = bv->GetLength(); + char *mybuffer = new char[totalLen]; + + bv->GetBuffer(mybuffer, bv->GetLength()); + + const BYTE* pbyteCompressed = (const BYTE*)mybuffer; + while( totalLen > 0 && pbyteCompressed[totalLen-1] != 0xd9 ) + { + totalLen--; + } + // what if 0xd9 is never found ? + assert( totalLen > 0 && pbyteCompressed[totalLen-1] == 0xd9 ); + + size_t cbyteCompressed = totalLen; + + JlsParameters params = {}; + if( JpegLsReadHeader(pbyteCompressed, cbyteCompressed, ¶ms) != OK ) + { + gdcmDebugMacro( "Could not parse JPEG-LS header" ); + return false; + } + + // allowedlossyerror == 0 => Lossless + LossyFlag = params.allowedlossyerror!= 0; + + std::vector rgbyteOut; + rgbyteOut.resize(params.height *params.width * ((params.bitspersample + 7) / 8) * params.components); + + JLS_ERROR result = JpegLsDecode(&rgbyteOut[0], rgbyteOut.size(), pbyteCompressed, cbyteCompressed, ¶ms); + bool r = true; + + delete[] mybuffer; + if (result != OK) + { + return false; + } + os.write( (char*)&rgbyteOut[0], rgbyteOut.size() ); + + if(!r) return false; + assert( r == true ); + } + std::string str = os.str(); + assert( str.size() ); + out.SetByteValue( &str[0], (uint32_t)str.size() ); + + return true; + } + return false; + +#endif +} + +// Compress into JPEG +bool JPEGLSCodec::Code(DataElement const &in, DataElement &out) +{ +#ifndef GDCM_USE_JPEGLS + return false; +#else + out = in; + // + // Create a Sequence Of Fragments: + SmartPointer sq = new SequenceOfFragments; + const Tag itemStart(0xfffe, 0xe000); + //sq->GetTable().SetTag( itemStart ); + + const unsigned int *dims = this->GetDimensions(); + int image_width = dims[0]; + int image_height = dims[1]; + const PixelFormat &pf = this->GetPixelFormat(); + int sample_pixel = pf.GetSamplesPerPixel(); + int bitsallocated = pf.GetBitsAllocated(); + int bitsstored = pf.GetBitsStored(); + + const ByteValue *bv = in.GetByteValue(); + const char *input = bv->GetPointer(); + unsigned long len = bv->GetLength(); + unsigned long image_len = len / dims[2]; + size_t inputlength = image_len; + + for(unsigned int dim = 0; dim < dims[2]; ++dim) + { + const char *inputdata = input + dim * image_len; //bv->GetPointer(); + + JlsParameters params = {}; +/* +The fields in JlsCustomParameters do not control lossy/lossless. They +provide the possiblity to tune the JPEG-LS internals for better compression +ratios. Expect a lot of work and testing to achieve small improvements. + +Lossy/lossless is controlled by the field allowedlossyerror. If you put in +0, encoding is lossless. If it is non-zero, then encoding is lossy. The +value of 3 is often suggested as a default. + +The nice part about JPEG-LS encoding is that in lossy encoding, there is a +guarenteed maximum error for each pixel. So a pixel that has value 12, +encoded with a maximum lossy error of 3, may be decoded as a value between 9 +and 15, but never anything else. In medical imaging this could be a useful +guarantee. + +The not so nice part is that you may see striping artifacts when decoding +"non-natural" images. I haven't seen the effects myself on medical images, +but I suspect screenshots may suffer the most. Also, the bandwidth saving is +not as big as with other lossy schemes. + +As for 12 bit, I am about to commit a unit test (with the sample you gave +me) that does a successful round trip encoding of 12 bit color. I did notice +that for 12 bit, the encoder fails if the unused bits are non-zero, but the +sample dit not suffer from that. +*/ + params.allowedlossyerror = Lossless ? 0 : LossyError; + params.components = sample_pixel; + // D_CLUNIE_RG3_JPLY.dcm. The famous 16bits allocated / 10 bits stored with the pixel value = 1024 + // CharLS properly encode 1024 considering it as 10bits data, so the output + // Using bitsstored for the encoder gives a slightly better compression ratio, and is indeed the + // right way of doing it. + + // gdcmData/PHILIPS_Gyroscan-8-MONO2-Odd_Sequence.dcm + if( true || pf.GetPixelRepresentation() ) + { + // gdcmData/CT_16b_signed-UsedBits13.dcm + params.bitspersample = bitsallocated; + } + else + { + params.bitspersample = bitsstored; + } + params.height = image_height; + params.width = image_width; + + if (sample_pixel == 4) + { + params.ilv = ILV_LINE; + } + else if (sample_pixel == 3) + { + params.ilv = ILV_LINE; + params.colorTransform = COLORXFORM_HP1; + } + + std::vector rgbyteCompressed; + rgbyteCompressed.resize(image_width * image_height * 4); + //rgbyteCompressed.resize(size.cx *size.cy * ccomp * cbit / 4); + + size_t cbyteCompressed; + JLS_ERROR error = JpegLsEncode(&rgbyteCompressed[0], rgbyteCompressed.size(), &cbyteCompressed, inputdata, inputlength, ¶ms); + if( error != OK ) + { + gdcmErrorMacro( "Error compressing: " << (int)error ); + return false; + } + + assert( cbyteCompressed < rgbyteCompressed.size() ); + + Fragment frag; + frag.SetByteValue( (char*)&rgbyteCompressed[0], (uint32_t)cbyteCompressed ); + sq->AddFragment( frag ); + } + + assert( sq->GetNumberOfFragments() == dims[2] ); + out.SetValue( *sq ); + + return true; + +#endif +} + +void JPEGLSCodec::SetLossyError(int error) +{ + LossyError = error; +} + +bool JPEGLSCodec::Decode(DataElement const &, char* , size_t, + uint32_t , uint32_t , uint32_t , + uint32_t , uint32_t , uint32_t ) +{ + return false; +} + +bool JPEGLSCodec::DecodeExtent( + char *buffer, + unsigned int xmin, unsigned int xmax, + unsigned int ymin, unsigned int ymax, + unsigned int zmin, unsigned int zmax, + std::istream & is + ) +{ + BasicOffsetTable bot; + bot.Read( is ); + + const unsigned int * dimensions = this->GetDimensions(); + const PixelFormat & pf = this->GetPixelFormat(); + assert( pf.GetBitsAllocated() % 8 == 0 ); + assert( pf != PixelFormat::SINGLEBIT ); + assert( pf != PixelFormat::UINT12 && pf != PixelFormat::INT12 ); + + if( NumberOfDimensions == 2 ) + { + char *dummy_buffer = NULL; + std::vector vdummybuffer; + size_t buf_size = 0; + + const Tag seqDelItem(0xfffe,0xe0dd); + gdcm::Fragment frag; + while( frag.ReadPreValue(is) && frag.GetTag() != seqDelItem ) + { + size_t fraglen = frag.GetVL(); + size_t oldlen = vdummybuffer.size(); + // update + buf_size = fraglen + oldlen; + vdummybuffer.resize( buf_size ); + dummy_buffer = &vdummybuffer[0]; + // read J2K + is.read( &vdummybuffer[oldlen], fraglen ); + } + assert( frag.GetTag() == seqDelItem && frag.GetVL() == 0 ); + assert( zmin == zmax ); + assert( zmin == 0 ); + + std::vector outv; + bool b = DecodeByStreamsCommon(dummy_buffer, buf_size, outv); + if( !b ) return false; + + unsigned char *raw = &outv[0]; + const unsigned int rowsize = xmax - xmin + 1; + const unsigned int colsize = ymax - ymin + 1; + const unsigned int bytesPerPixel = pf.GetPixelSize(); + + const unsigned char *tmpBuffer1 = raw; + unsigned int z = 0; + for (unsigned int y = ymin; y <= ymax; ++y) + { + size_t theOffset = 0 + (z*dimensions[1]*dimensions[0] + y*dimensions[0] + xmin)*bytesPerPixel; + tmpBuffer1 = raw + theOffset; + memcpy(&(buffer[((z-zmin)*rowsize*colsize + + (y-ymin)*rowsize)*bytesPerPixel]), + tmpBuffer1, rowsize*bytesPerPixel); + } + } + else if ( NumberOfDimensions == 3 ) + { + const Tag seqDelItem(0xfffe,0xe0dd); + gdcm::Fragment frag; + std::streamoff thestart = is.tellg(); + unsigned int numfrags = 0; + std::vector< size_t > offsets; + while( frag.ReadPreValue(is) && frag.GetTag() != seqDelItem ) + { + //std::streamoff relstart = is.tellg(); + //assert( relstart - thestart == 8 ); + std::streamoff off = frag.GetVL(); + offsets.push_back( off ); + is.seekg( off, std::ios::cur ); + ++numfrags; + } + assert( frag.GetTag() == seqDelItem && frag.GetVL() == 0 ); + assert( numfrags == offsets.size() ); + if( numfrags != Dimensions[2] ) + { + gdcmErrorMacro( "Not handled" ); + return false; + } + + for( unsigned int z = zmin; z <= zmax; ++z ) + { + size_t curoffset = std::accumulate( offsets.begin(), offsets.begin() + z, 0 ); + is.seekg( thestart + curoffset + 8 * z, std::ios::beg ); + is.seekg( 8, std::ios::cur ); + + const size_t buf_size = offsets[z]; + char *dummy_buffer = new char[ buf_size ]; + is.read( dummy_buffer, buf_size ); + + std::vector outv; + bool b = DecodeByStreamsCommon(dummy_buffer, buf_size, outv); + delete[] dummy_buffer; + + if( !b ) return false; + + unsigned char *raw = &outv[0]; + const unsigned int rowsize = xmax - xmin + 1; + const unsigned int colsize = ymax - ymin + 1; + const unsigned int bytesPerPixel = pf.GetPixelSize(); + + const unsigned char *tmpBuffer1 = raw; + for (unsigned int y = ymin; y <= ymax; ++y) + { + size_t theOffset = 0 + (0*dimensions[1]*dimensions[0] + y*dimensions[0] + xmin)*bytesPerPixel; + tmpBuffer1 = raw + theOffset; + memcpy(&(buffer[((z-zmin)*rowsize*colsize + + (y-ymin)*rowsize)*bytesPerPixel]), + tmpBuffer1, rowsize*bytesPerPixel); + } + } + } + return true; +} + +ImageCodec * JPEGLSCodec::Clone() const +{ + return NULL; +} + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmJPEGLSCodec.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmJPEGLSCodec.h new file mode 100644 index 0000000..14050d3 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmJPEGLSCodec.h @@ -0,0 +1,85 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMJPEGLSCODEC_H +#define GDCMJPEGLSCODEC_H + +#include "gdcmImageCodec.h" + +namespace gdcm +{ + +class JPEGLSInternals; +/** + * \brief JPEG-LS + * \note codec that implement the JPEG-LS compression + * this is an implementation of ImageCodec for JPEG-LS + * + * It uses the CharLS JPEG-LS implementation http://charls.codeplex.com + */ +class GDCM_EXPORT JPEGLSCodec : public ImageCodec +{ +friend class ImageRegionReader; +public: + JPEGLSCodec(); + ~JPEGLSCodec(); + bool CanDecode(TransferSyntax const &ts) const; + bool CanCode(TransferSyntax const &ts) const; + + unsigned long GetBufferLength() const { return BufferLength; } + void SetBufferLength(unsigned long l) { BufferLength = l; } + + bool Decode(DataElement const &is, DataElement &os); + bool Decode(DataElement const &in, char* outBuffer, size_t inBufferLength, + uint32_t inXMin, uint32_t inXMax, uint32_t inYMin, + uint32_t inYMax, uint32_t inZMin, uint32_t inZMax); + bool Code(DataElement const &in, DataElement &out); + + bool GetHeaderInfo(std::istream &is, TransferSyntax &ts); + virtual ImageCodec * Clone() const; + + void SetLossless(bool l); + bool GetLossless() const; + +/* + * test.acr can look pretty bad, even with a lossy error of 2. Explanation follows: + * I agree that the test image looks ugly. In this particular case I can + * explain though. + * + * The image is 8 bit, but it does not use the full 8 bit dynamic range. The + * black pixels have value 234 and the white 255. If you set allowed lossy + * error to 2, you allow an error of about 10% of the actual dynamic range. + * That is of course very visible. + */ + /// [0-3] generally + void SetLossyError(int error); + +protected: + bool DecodeExtent( + char *buffer, + unsigned int xmin, unsigned int xmax, + unsigned int ymin, unsigned int ymax, + unsigned int zmin, unsigned int zmax, + std::istream & is + ); + +private: + bool DecodeByStreamsCommon(char *buffer, size_t totalLen, std::vector &rgbyteOut); + unsigned long BufferLength; + bool Lossless; + int LossyError; +}; + +} // end namespace gdcm + +#endif //GDCMJPEGLSCODEC_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmJSON.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmJSON.cxx new file mode 100644 index 0000000..93aa21c --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmJSON.cxx @@ -0,0 +1,991 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmJSON.h" +#include "gdcmGlobal.h" +#include "gdcmDicts.h" +#include "gdcmBase64.h" +#include "gdcmSystem.h" + +#ifdef GDCM_USE_SYSTEM_JSON +#include +#endif + +/* + * Implementation is done based on Sup166, which may change in the future. + */ + +// TODO: CP 246 / VR=SQ + Sequence: ! + +// Clarification needed: +// "00081070":{ +// "Tag":"00081070", +// "VR":"PN", +// "Value":[ +// null +// ] +// }, + + +// Need to pay attention that: +// \ISO 2022 IR 13\ISO 2022 IR 87 +// encodes to: +// [ null, "ISO 2022 IR 13", "ISO 2022 IR 87" ] +// or ? +// [ "", "ISO 2022 IR 13", "ISO 2022 IR 87" ] + +// TODO: +// DS/IS should be encoded as number + +// Question, does F.2.5 DICOM JSON Model Null Values +// imply: +// "Sequence": [ null ] ? + +// does not make any sense to send Group Length... + +// Clarification needed, specs says IS should be a Number but example uses +// String + +namespace gdcm +{ + +#ifdef GDCM_USE_SYSTEM_JSON +static inline void wstrim(std::string& str) +{ + str.erase(0, str.find_first_not_of(' ')); + str.erase(str.find_last_not_of(' ')+1); +} + +static inline bool CanContainBackslash( const VR::VRType vrtype ) +{ + assert( VR::IsASCII( vrtype ) ); + // PS 3.5-2011 / Table 6.2-1 DICOM VALUE REPRESENTATIONS + switch( vrtype ) + { + case VR::AE: // ScheduledStationAETitle + //case VR::AS: // no + //case VR::AT: // binary + case VR::CS: // SpecificCharacterSet + case VR::DA: // CalibrationDate + case VR::DS: // FrameTimeVector + case VR::DT: // ReferencedDateTime + //case VR::FD: // binary + //case VR::FL: + case VR::IS: // ReferencedFrameNumber + case VR::LO: // OtherPatientIDs + //case VR::LT: // VM1 + //case VR::OB: // binary + //case VR::OD: // binary + //case VR::OF: // binary + //case VR::OW: // binary + case VR::PN: // PerformingPhysicianName + case VR::SH: // PatientTelephoneNumbers + //case VR::SL: // binary + //case VR::SQ: // binary + //case VR::SS: // binary + //case VR::ST: // VM1 + case VR::TM: // CalibrationTime + case VR::UI: // SOPClassesInStudy + //case VR::UL: // binary + //case VR::UN: // binary + //case VR::US: // binary + //case VR::UT: // VM1 + assert( !(vrtype & VR::VR_VM1) ); + return true; + default: + ; + } + return false; +} +#endif + +class JSONInternal +{ +public: + JSONInternal():PrettyPrint(false),PreferKeyword(false){} + bool PrettyPrint; + bool PreferKeyword; +}; + +JSON::JSON() +{ + Internals = new JSONInternal; +} + +JSON::~JSON() +{ + delete Internals; +} + +void JSON::SetPrettyPrint(bool onoff) +{ + Internals->PrettyPrint = onoff; +} +bool JSON::GetPrettyPrint() const +{ + return Internals->PrettyPrint; +} +void JSON::PrettyPrintOn() +{ + Internals->PrettyPrint = true; +} +void JSON::PrettyPrintOff() +{ + Internals->PrettyPrint = false; +} + +#ifdef GDCM_USE_SYSTEM_JSON + +/* + "StudyInstanceUID": { + "Tag": "0020000D", + "VR": "UI", + "Value": [ "1.2.392.200036.9116.2.2.2.1762893313.1029997326.945873" ] + }, +*/ + +static void DataElementToJSONArray( const VR::VRType vr, const DataElement & de, json_object *my_array ) +{ + if( de.IsEmpty() ) + { + // F.2.5 DICOM JSON Model Null Values + if( vr == VR::PN ) + { + json_object *my_object_comp = json_object_new_object(); + json_object_array_add(my_array, my_object_comp ); + } + //else + // json_object_array_add(my_array, NULL ); + return; + } + // else + assert( !de.IsEmpty() ); + const bool checkbackslash = CanContainBackslash( vr ); + const ByteValue * bv = de.GetByteValue(); + const char * value = bv->GetPointer(); + size_t len = bv->GetLength(); + + if( vr == VR::UI ) + { + const std::string strui( value, len ); + const size_t lenuid = strlen( strui.c_str() ); // trick to remove trailing \0 + json_object_array_add(my_array, json_object_new_string_len(strui.c_str(), lenuid)); + } + else if( vr == VR::PN ) + { + const char *str1 = value; + // remove whitespace: + while( str1[len-1] == ' ' ) + { + len--; + } + assert( str1 ); + std::stringstream ss; + static const char *Keys[] = { + "Alphabetic", + "Ideographic", + "Phonetic", + }; + while (1) + { + assert( str1 && (size_t)(str1 - value) <= len ); + const char * sep = strchr(str1, '\\'); + const size_t llen = (sep != NULL) ? (sep - str1) : (value + len - str1); + const std::string component(str1, llen); + + const char *str2 = component.c_str(); + assert( str2 ); + const size_t len2 = component.size(); + assert( len2 == llen ); + + int idx = 0; + json_object *my_object_comp = json_object_new_object(); + while (1) + { + assert( str2 && (size_t)(str2 - component.c_str() ) <= len2 ); + const char * sep2 = strchr(str2, '='); + const size_t llen2 = (sep2 != NULL) ? (sep2 - str2) : (component.c_str() + len2 - str2); + const std::string group(str2, llen2); + const char *thekey = Keys[idx++]; + + json_object_object_add(my_object_comp, thekey, + json_object_new_string_len( group.c_str(), group.size() ) ); + if (sep2 == NULL) break; + str2 = sep2 + 1; + } + json_object_array_add(my_array, my_object_comp); + if (sep == NULL) break; + str1 = sep + 1; + assert( checkbackslash ); + } + } + else if( vr == VR::DS || vr == VR::IS ) + { + const char *str1 = value; + assert( str1 ); + VRToType::Type vris; + VRToType::Type vrds; + while (1) + { + std::stringstream ss; + assert( str1 && (size_t)(str1 - value) <= len ); + const char * sep = strchr(str1, '\\'); + const size_t llen = (sep != NULL) ? (sep - str1) : (value + len - str1); + // This is complex, IS/DS should not be stored as string anymore + switch( vr ) + { + case VR::IS: + ss.str( std::string(str1, llen) ); + ss >> vris; + json_object_array_add(my_array, json_object_new_int(vris)); // json_object_new_int takes an int32_t + break; + case VR::DS: + ss.str( std::string(str1, llen) ); + ss >> vrds; + json_object_array_add(my_array, json_object_new_double(vrds)); + break; + default: + assert( 0 ); // programmer error + } + if (sep == NULL) break; + str1 = sep + 1; + assert( checkbackslash ); + } + } + else if( checkbackslash ) + { + const char *str1 = value; + assert( str1 ); + while (1) + { + assert( str1 && (size_t)(str1 - value) <= len ); + const char * sep = strchr(str1, '\\'); + const size_t llen = (sep != NULL) ? (sep - str1) : (value + len - str1); + json_object_array_add(my_array, json_object_new_string_len(str1, llen)); + if (sep == NULL) break; + str1 = sep + 1; + } + } + else // default + { + json_object_array_add(my_array, json_object_new_string_len(value, len)); + } +} + +// Encode from DICOM to JSON +// TODO: do I really need libjson for this task ? +// FIXME: once again everything is loaded into memory +static void ProcessNestedDataSet( const DataSet & ds, json_object *my_object, const bool preferkeyword ) +{ + const Global& g = GlobalInstance; + const Dicts &dicts = g.GetDicts(); + const Dict &d = dicts.GetPublicDict(); (void)d; + + std::vector buffer; + for( DataSet::ConstIterator it = ds.Begin(); + it != ds.End(); ++it ) + { + const DataElement &de = *it; + VR::VRType vr = de.GetVR(); + const Tag& t = de.GetTag(); + if( t.IsGroupLength() ) continue; // I do not see why we should send those ? + std::string strowner; + const char *owner = 0; + if( t.IsPrivate() && !t.IsPrivateCreator() ) + { + strowner = ds.GetPrivateCreator(t); + owner = strowner.c_str(); + } + const DictEntry &entry = dicts.GetDictEntry(t,owner); + const std::string & str_tag = t.PrintAsContinuousUpperCaseString(); + const bool issequence = vr == VR::SQ || de.IsUndefinedLength(); + const bool isprivatecreator = t.IsPrivateCreator(); + if( issequence ) vr = VR::SQ; + else if( isprivatecreator ) vr = VR::LO; // always prefer VR::LO (over invalid/UN) + else if( vr == VR::INVALID ) vr = VR::UN; + const char * vr_str = VR::GetVRString(vr); + assert( VR::GetVRTypeFromFile(vr_str) != VR::INVALID ); + + json_object *my_object_cur; + my_object_cur = json_object_new_object(); + json_object *my_array; + my_array = json_object_new_array(); + + //json_object_object_add(my_object_cur, "Tag", + // json_object_new_string( str_tag.c_str()) ); + json_object_object_add(my_object_cur, "VR", + json_object_new_string_len( vr_str, 2 ) ); + if( owner ) + { + json_object_object_add(my_object_cur, "PrivateCreator", + json_object_new_string( owner ) ); + } + + if( vr == VR::SQ ) + { + SmartPointer sqi; + sqi = de.GetValueAsSQ(); + if( sqi ) + { + int nitems = sqi->GetNumberOfItems(); + for(int i = 1; i <= nitems; ++i) + { + const Item &item = sqi->GetItem( i ); + const DataSet &nested = item.GetNestedDataSet(); + + json_object *my_object_sq; + my_object_sq = json_object_new_object(); + + ProcessNestedDataSet( nested, my_object_sq, preferkeyword ); + json_object_array_add(my_array, my_object_sq ); + } + } + else if( const SequenceOfFragments *sqf = de.GetSequenceOfFragments() ) + { + json_object_array_add(my_array, NULL ); // FIXME + assert( 0 ); + } + else + { + assert( de.IsEmpty() ); + //json_object_array_add(my_array, NULL ); // F.2.5 req ? + } + //json_object_object_add(my_object_cur, "Sequence", my_array ); + int numel = json_object_array_length ( my_array ); + if( numel ) + json_object_object_add(my_object_cur, "Value", my_array ); + } + else if( VR::IsASCII( vr ) ) + { + DataElementToJSONArray( vr, de, my_array ); + int numel = json_object_array_length ( my_array ); + if( numel ) + { + if( vr == VR::PN ) + { + //json_object_object_add(my_object_cur, "PersonName", my_array ); + json_object_object_add(my_object_cur, "Value", my_array ); + } + else + json_object_object_add(my_object_cur, "Value", my_array ); + } + } + else + { + const char *wheretostore = "Value"; + switch( vr ) + { + case VR::FD: + { + // Does not work, see https://github.com/json-c/json-c/pull/59 + Element el; + el.Set( de.GetValue() ); + int ellen = el.GetLength(); + for( int i = 0; i < ellen; ++i ) + { + json_object_array_add(my_array, json_object_new_double( el.GetValue( i ) )); + } + } + break; + case VR::FL: + { + Element el; + el.Set( de.GetValue() ); + int ellen = el.GetLength(); + for( int i = 0; i < ellen; ++i ) + { + json_object_array_add(my_array, json_object_new_double( el.GetValue( i ) )); + } + } + break; + case VR::SS: + { + Element el; + el.Set( de.GetValue() ); + int ellen = el.GetLength(); + for( int i = 0; i < ellen; ++i ) + { + json_object_array_add(my_array, json_object_new_int( el.GetValue( i ) )); + } + } + break; + case VR::US: + { + Element el; + el.Set( de.GetValue() ); + int ellen = el.GetLength(); + for( int i = 0; i < ellen; ++i ) + { + json_object_array_add(my_array, json_object_new_int( el.GetValue( i ) )); + } + } + break; + case VR::SL: + { + Element el; + el.Set( de.GetValue() ); + int ellen = el.GetLength(); + for( int i = 0; i < ellen; ++i ) + { + json_object_array_add(my_array, json_object_new_int( el.GetValue( i ) )); + } + } + break; + case VR::UL: + { + Element el; + el.Set( de.GetValue() ); + int ellen = el.GetLength(); + for( int i = 0; i < ellen; ++i ) + { + json_object_array_add(my_array, json_object_new_int( el.GetValue( i ) )); + } + } + break; + case VR::AT: + { + Element el; + el.Set( de.GetValue() ); + int ellen = el.GetLength(); + for( int i = 0; i < ellen; ++i ) + { + const std::string atstr = el.GetValue( i ).PrintAsContinuousUpperCaseString(); + json_object_array_add(my_array, json_object_new_string( atstr.c_str() )); + } + } + break; + case VR::UN: + case VR::INVALID: + case VR::OD: + case VR::OF: + case VR::OB: + case VR::OW: + { + assert( !de.IsUndefinedLength() ); // handled before + const ByteValue * bv = de.GetByteValue(); + wheretostore = "InlineBinary"; + if( bv ) + { + const char *src = bv->GetPointer(); + const size_t len = bv->GetLength(); + assert( len % 2 == 0 ); + const size_t len64 = Base64::GetEncodeLength(src, len); + buffer.resize( len64 ); + const size_t ret = Base64::Encode( &buffer[0], len64, src, len ); + assert( ret != 0 ); + json_object_array_add(my_array, json_object_new_string_len(&buffer[0], len64)); + } + } + break; + default: + assert( 0 ); // programmer error + } + json_object_object_add(my_object_cur, wheretostore, my_array ); + } + //const char *keyword = entry.GetKeyword(); + //assert( keyword && *keyword ); + //if( preferkeyword && keyword && *keyword && !t.IsPrivateCreator() ) + // { + // json_object_object_add(my_object, keyword, my_object_cur ); + // } + //else + { + json_object_object_add(my_object, str_tag.c_str(), my_object_cur ); + } + } +} +#endif + +bool JSON::Code(DataSet const & ds, std::ostream & os) +{ +#ifdef GDCM_USE_SYSTEM_JSON + json_object *my_object; + my_object = json_object_new_object(); + + ProcessNestedDataSet( ds, my_object, Internals->PreferKeyword ); + + const char* str = NULL; + if( Internals->PrettyPrint ) + { +#ifdef JSON_C_VERSION + str = json_object_to_json_string_ext(my_object, JSON_C_TO_STRING_SPACED | JSON_C_TO_STRING_PRETTY ); +#else + str = json_object_to_json_string( my_object ); +#endif + } + else + { + str = json_object_to_json_string( my_object ); + } + os << str; + json_object_put(my_object); // free memory + return true; +#else + (void)ds; + (void)os; + return false; +#endif +} + +#ifdef GDCM_USE_SYSTEM_JSON +// Paranoid +static inline bool CheckTagKeywordConsistency( const char *name, const Tag & thetag ) +{ + // Can be keyword or tag + assert( name ); + + // start with easy one: + // only test first string character: + bool istag = *name >= '0' && *name <= '9'; // should be relatively efficient + if( istag ) + { + assert( strlen(name) == 8 ); + Tag t; + t.ReadFromContinuousString( name ); + return t == thetag; + } + // else keyword: + const Global& g = GlobalInstance; + const Dicts &dicts = g.GetDicts(); + const Dict &d = dicts.GetPublicDict(); + const char * keyword = d.GetKeywordFromTag(thetag); + if( !keyword ) + { + gdcmDebugMacro( "Unknown Keyword: " << name ); + return true; + } + // else + assert( strcmp( name, keyword ) == 0 ); + return strcmp( name, keyword ) == 0; +} +#endif + +#ifdef GDCM_USE_SYSTEM_JSON +#ifdef JSON_C_VERSION +static void ProcessJSONElement( const char *tag_str, json_object * obj, DataElement & de ) +{ + json_type jtype = json_object_get_type( obj ); + assert( jtype == json_type_object ); + json_object * jvr = json_object_object_get(obj, "VR"); + + const char * vr_str = json_object_get_string ( jvr ); + de.GetTag().ReadFromContinuousString( tag_str ); + const char * pc_str = 0; + if( de.GetTag().IsPrivate() && !de.GetTag().IsPrivateCreator() ) + { + json_object * jprivatecreator = json_object_object_get(obj, "PrivateCreator"); + pc_str = json_object_get_string ( jprivatecreator ); + assert( pc_str ); + } + + VR::VRType vrtype = VR::GetVRTypeFromFile( vr_str ); + assert( vrtype != VR::INVALID ); + assert( vrtype != VR::VR_END ); + de.SetVR( vrtype ); + + if( vrtype == VR::SQ ) + { + json_object * jvalue = json_object_object_get(obj, "Value"); + json_type jvaluetype = json_object_get_type( jvalue ); + assert( jvaluetype != json_type_null && jvaluetype == json_type_array ); +#ifndef NDEBUG + json_object * jseq = json_object_object_get(obj, "Sequence"); + json_type jsqtype = json_object_get_type( jseq ); + assert( jsqtype == json_type_null ); +#endif + if( jvaluetype == json_type_array ) + { + // Create a Sequence + gdcm::SmartPointer sq = new gdcm::SequenceOfItems; + sq->SetLengthToUndefined(); + + int sqlen = json_object_array_length ( jvalue ); + for( int itemidx = 0; itemidx < sqlen; ++itemidx ) + { + json_object * jitem = json_object_array_get_idx ( jvalue, itemidx ); + json_type jitemtype = json_object_get_type( jitem ); + assert( jitemtype == json_type_object ); + //const char * dummy = json_object_to_json_string ( jitem ); + + // Create an item + gdcm::Item item; + item.SetVLToUndefined(); + gdcm::DataSet &nds = item.GetNestedDataSet(); + +#ifdef JSON_C_VERSION + json_object_iterator it; + json_object_iterator itEnd; + it = json_object_iter_begin(jitem); + itEnd = json_object_iter_end(jitem); + + while (!json_object_iter_equal(&it, &itEnd)) + { + const char *name = json_object_iter_peek_name(&it); + assert( name ); + json_object * value = json_object_iter_peek_value (&it); + DataElement lde; + ProcessJSONElement( name, value, lde ); + nds.Insert( lde ); + json_object_iter_next(&it); + } +#endif + sq->AddItem(item); + } + + // Insert sequence into data set + de.SetValue(*sq); + de.SetVLToUndefined(); + } + } + else if( VR::IsASCII( vrtype ) ) + { +/* + F.2.5 DICOM JSON Model Null Values + If an attribute is present in DICOM but empty, it shall be preserved in the DICOM JSON object and passed + with the value of "null". For example: + "Value": [ null ] +*/ + json_object * jvalue = json_object_object_get(obj, "Value"); +#ifndef NDEBUG + json_object * jpn = json_object_object_get(obj, "PersonName"); + json_type jpntype = json_object_get_type( jpn ); + assert( jpntype == json_type_null ); +#endif + json_type jvaluetype = json_object_get_type( jvalue ); + //const char * dummy = json_object_to_json_string ( jvalue ); + assert( jvaluetype == json_type_null || jvaluetype == json_type_array ); + if( jvaluetype == json_type_array ) + { + //assert( vrtype != VR::PN ); + const int valuelen = json_object_array_length ( jvalue ); + std::string str; + for( int validx = 0; validx < valuelen; ++validx ) + { + if( validx ) str += '\\'; + json_object * value = json_object_array_get_idx ( jvalue, validx ); + json_type valuetype = json_object_get_type( value ); + if( value ) + { + assert( valuetype != json_type_null ); + std::string value_str; + std::stringstream ss; + VRToType::Type vris; + VRToType::Type vrds; + switch( vrtype ) + { + case VR::PN: + { + json_object * jopn[3]; + jopn[0] = json_object_object_get(value, "Alphabetic"); + jopn[1]= json_object_object_get(value, "Ideographic"); + jopn[2]= json_object_object_get(value, "Phonetic"); + for( int i = 0; i < 3; ++i ) + { + const char *tmp = json_object_get_string ( jopn[i] ); + if( tmp ) + { + if( i ) value_str += '='; + value_str += tmp; + } + } + } + break; + case VR::IS: + vris = json_object_get_int( value ); + ss << vris; + value_str = ss.str(); + break; + case VR::DS: + vrds = json_object_get_double( value ); + ss << vrds; + value_str = ss.str(); + break; + default: + value_str = json_object_get_string ( value ); + } + str += value_str; + } + else + { + // We have a [ null ] array, so at most there is a single item: + assert( valuelen == 1 ); + assert( valuetype == json_type_null ); + } + } + if( str.size() % 2 ) + { + if( vrtype == VR::UI ) + str.push_back( 0 ); + else + str.push_back( ' ' ); + } + de.SetByteValue( &str[0], str.size() ); + } +#ifndef NDEBUG + else if( jpntype == json_type_array ) + { + assert( 0 ); + } +#endif + } + else + { + json_object * jvaluebin = json_object_object_get(obj, "InlineBinary"); + json_type jvaluebintype = json_object_get_type( jvaluebin ); + json_object * jvalue = json_object_object_get(obj, "Value"); + json_type jvaluetype = json_object_get_type( jvalue ); + //const char * dummy = json_object_to_json_string ( jvalue ); + assert( jvaluetype == json_type_array || jvaluetype == json_type_null ); + if( jvaluetype == json_type_array ) + { + DataElement locde; + const int valuelen = json_object_array_length ( jvalue ); + const int vrsizeof = vrtype == VR::INVALID ? 0 : de.GetVR().GetSizeof(); + switch( vrtype ) + { + case VR::FD: + { + Element el; + el.SetLength( valuelen * vrsizeof ); + for( int validx = 0; validx < valuelen; ++validx ) + { + json_object * value = json_object_array_get_idx ( jvalue, validx ); + assert( json_object_get_type( value ) == json_type_double ); + const double v = json_object_get_double ( value ); + el.SetValue(v, validx); + } + locde = el.GetAsDataElement(); + } + break; + case VR::FL: + { + Element el; + el.SetLength( valuelen * vrsizeof ); + for( int validx = 0; validx < valuelen; ++validx ) + { + json_object * value = json_object_array_get_idx ( jvalue, validx ); + assert( json_object_get_type( value ) == json_type_double ); + const double v = json_object_get_double ( value ); + el.SetValue(v, validx); + } + locde = el.GetAsDataElement(); + } + break; + case VR::SS: + { + Element el; + el.SetLength( valuelen * vrsizeof ); + for( int validx = 0; validx < valuelen; ++validx ) + { + json_object * value = json_object_array_get_idx ( jvalue, validx ); + assert( json_object_get_type( value ) == json_type_int ); + const int v = json_object_get_int( value ); + el.SetValue(v, validx); + } + locde = el.GetAsDataElement(); + } + break; + case VR::US: + { + Element el; + el.SetLength( valuelen * vrsizeof ); + for( int validx = 0; validx < valuelen; ++validx ) + { + json_object * value = json_object_array_get_idx ( jvalue, validx ); + assert( json_object_get_type( value ) == json_type_int ); + const int v = json_object_get_int( value ); + el.SetValue(v, validx); + } + locde = el.GetAsDataElement(); + } + break; + case VR::SL: + { + Element el; + el.SetLength( valuelen * vrsizeof ); + for( int validx = 0; validx < valuelen; ++validx ) + { + json_object * value = json_object_array_get_idx ( jvalue, validx ); + assert( json_object_get_type( value ) == json_type_int ); + const int v = json_object_get_int( value ); + el.SetValue(v, validx); + } + locde = el.GetAsDataElement(); + } + break; + case VR::UL: + { + Element el; + el.SetLength( valuelen * vrsizeof ); + for( int validx = 0; validx < valuelen; ++validx ) + { + json_object * value = json_object_array_get_idx ( jvalue, validx ); + assert( json_object_get_type( value ) == json_type_int ); + const int v = json_object_get_int( value ); + el.SetValue(v, validx); + } + locde = el.GetAsDataElement(); + } + break; + case VR::AT: + { + Element el; + el.SetLength( valuelen * vrsizeof ); + for( int validx = 0; validx < valuelen; ++validx ) + { + json_object * value = json_object_array_get_idx ( jvalue, validx ); + assert( json_object_get_type( value ) == json_type_string ); + const char *atstr = json_object_get_string( value ); + Tag t; + t.ReadFromContinuousString( atstr ); + el.SetValue(t, validx); + } + locde = el.GetAsDataElement(); + } + break; + default: + assert( 0 ); + } + if( !locde.IsEmpty() ) + de.SetValue( locde.GetValue() ); + } + else if( jvaluebintype == json_type_array ) + { + DataElement locde; + const int valuelen = json_object_array_length ( jvaluebin ); + switch( vrtype ) + { + case VR::UN: + case VR::INVALID: + case VR::OB: + case VR::OD: + case VR::OF: + case VR::OW: + { + assert( valuelen == 1 || valuelen == 0 ); + if( valuelen ) + { + json_object * value = json_object_array_get_idx ( jvaluebin, 0 ); + json_type valuetype = json_object_get_type( value ); + if( value ) + { + assert( valuetype != json_type_null ); + const char * value_str = json_object_get_string ( value ); + assert( value_str ); + const size_t len64 = strlen( value_str ); + const size_t len = Base64::GetDecodeLength( value_str, len64 ); + std::vector buffer; + buffer.resize( len ); + const size_t ret = Base64::Decode( &buffer[0], len, + value_str, len64 ); + assert( ret != 0 ); + locde.SetByteValue( &buffer[0], len ); + } + else + { + // We have a [ null ] array, so at most there is a single item: + assert( valuelen == 1 ); + assert( valuetype == json_type_null ); + } + } + } + break; + default: + assert( 0 ); + } + if( !locde.IsEmpty() ) + de.SetValue( locde.GetValue() ); + } + else + { + assert( jvaluebintype == json_type_null && jvaluetype == json_type_null ); + } + } +} +#endif +#endif + +bool JSON::Decode(std::istream & is, DataSet & ds) +{ +#ifdef GDCM_USE_SYSTEM_JSON + +#ifdef JSON_C_VERSION + json_object *jobj = NULL; + const char *mystring = NULL; + int stringlen = 0; + enum json_tokener_error jerr; + std::string str; + json_tokener * tok = json_tokener_new (); + do + { + std::getline( is, str ); + mystring = str.c_str(); + stringlen = str.size(); + jobj = json_tokener_parse_ex(tok, mystring, stringlen); + //if( is.eof() ) break; + } while ((jerr = json_tokener_get_error(tok)) == json_tokener_continue ); + + if (jerr != json_tokener_success) + { + fprintf(stderr, "Error: %s\n", json_tokener_error_desc(jerr)); + // Handle errors, as appropriate for your application. + assert( 0 ); + } + if (tok->char_offset < stringlen) // XXX shouldn't access internal fields + { + // Handle extra characters after parsed object as desired. + // e.g. issue an error, parse another object from that point, etc... + } + // Success, use jobj here. + json_tokener_free( tok ); +#else + std::stringstream ss; + std::string str; + while( std::getline( is, str ) ) + { + ss << str; + } + const std::string & wholestr = ss.str(); + json_object *obj; + obj = json_tokener_parse( wholestr.c_str() ); +#endif + +#ifdef JSON_C_VERSION + json_object_iterator it; + json_object_iterator itEnd; + it = json_object_iter_begin(jobj); + itEnd = json_object_iter_end(jobj); + + while (!json_object_iter_equal(&it, &itEnd)) + { + const char *name = json_object_iter_peek_name(&it); + assert( name ); + json_object * value = json_object_iter_peek_value (&it); + DataElement de; + ProcessJSONElement( name, value, de ); + ds.Insert( de ); + json_object_iter_next(&it); + } + return true; +#else + gdcmErrorMacro( "Version too old" ); + return false; +#endif +#else + (void)is; + (void)ds; + return false; +#endif +} + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmJSON.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmJSON.h new file mode 100644 index 0000000..24451d7 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmJSON.h @@ -0,0 +1,49 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMJSON_H +#define GDCMJSON_H + +/* +See Sup 166 (QIDO-RS) +http://www.dclunie.com/dicom-status/status.html#Supplement166 +*/ + +#include "gdcmFile.h" +#include "gdcmDataElement.h" + +namespace gdcm +{ + +class JSONInternal; +class GDCM_EXPORT JSON +{ +public: + JSON(); + ~JSON(); + + bool GetPrettyPrint() const; + void SetPrettyPrint(bool onoff); + void PrettyPrintOn(); + void PrettyPrintOff(); + + bool Code(DataSet const & in, std::ostream & os); + bool Decode(std::istream & is, DataSet & out); + +private: + JSONInternal *Internals; +}; + +} // end namespace gdcm + +#endif //GDCMXMLPRINTER_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmKAKADUCodec.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmKAKADUCodec.cxx new file mode 100644 index 0000000..db87afe --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmKAKADUCodec.cxx @@ -0,0 +1,243 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmKAKADUCodec.h" +#include "gdcmTransferSyntax.h" +#include "gdcmDataElement.h" +#include "gdcmFilename.h" +#include "gdcmSystem.h" +#include "gdcmSequenceOfFragments.h" +#include "gdcmPNMCodec.h" +#include "gdcmByteSwap.txx" + +namespace gdcm +{ +/* +*/ + +KAKADUCodec::KAKADUCodec() +{ + //NeedByteSwap = true; +} + +KAKADUCodec::~KAKADUCodec() +{ +} + +bool KAKADUCodec::CanDecode(TransferSyntax const &ts) const +{ +#ifndef GDCM_USE_KAKADU + (void)ts; + return false; +#else + return ts == TransferSyntax::JPEG2000Lossless + || ts == TransferSyntax::JPEG2000; +#endif +} + +bool KAKADUCodec::CanCode(TransferSyntax const &) const +{ + return false; +} + +/* KAKADU command line is a bit tricky to use: + * + * kdu_expand + */ +bool KAKADUCodec::Decode(DataElement const &in, DataElement &out) +{ +#ifndef GDCM_USE_KAKADU + (void)in; + (void)out; + return false; +#else + // First thing creates a j2k file from the fragment: + const gdcm::SequenceOfFragments *sf = in.GetSequenceOfFragments(); + if(!sf) return false; + + if( NumberOfDimensions == 2 ) + { + // http://msdn.microsoft.com/en-us/library/hs3e7355.aspx + // -> check if tempnam needs the 'free' + char *tempinput = tempnam(0, "gdcminkduexp"); + char *tempoutput = tempnam(0, "gdcmoutkduexp"); + if( !tempinput || !tempoutput ) + { + //free(input); + //free(output); + return false; + } + std::string input = tempinput; + input += ".j2k"; + std::string output = tempoutput; + output += ".rawl"; + + std::ofstream outfile(input.c_str(), std::ios::binary); + sf->WriteBuffer(outfile); + outfile.close(); // flush ! + + //gdcm::Filename fn( System::GetCurrentProcessFileName() ); + //std::string executable_path = fn.GetPath(); +#ifdef GDCM_USE_SYSTEM_KAKADU + std::string kakadu_command = GDCM_KAKADU_EXPAND_EXECUTABLE; + kakadu_command += " -quiet"; +#else +#error not implemented +#endif + // ./bin/kakadujpeg -d -s jpeg.jpg -ci 0 out.raw + kakadu_command += " -i "; + kakadu_command += input; + kakadu_command += " -o "; + kakadu_command += output; + + //std::cerr << kakadu_command << std::endl; + gdcmDebugMacro( kakadu_command ); + int ret = system(kakadu_command.c_str()); + //std::cerr << "system: " << ret << std::endl; + + size_t len = gdcm::System::FileSize(output.c_str()); + if(!len) return false; + + std::ifstream is(output.c_str(), std::ios::binary); + char * buf = new char[len]; + is.read(buf, len); + out.SetTag( gdcm::Tag(0x7fe0,0x0010) ); + out.SetByteValue( buf, len ); + delete[] buf; + + if( !System::RemoveFile(input.c_str()) ) + { + gdcmErrorMacro( "Could not delete input: " << input ); + } + + if( !System::RemoveFile(output.c_str()) ) + { + gdcmErrorMacro( "Could not delete output: " << output ); + } + + free(tempinput); + free(tempoutput); + } + else if ( NumberOfDimensions == 3 ) + { + std::stringstream os; + if( sf->GetNumberOfFragments() != Dimensions[2] ) + { + gdcmErrorMacro( "Not handled" ); + return false; + } + + for(unsigned int i = 0; i < sf->GetNumberOfFragments(); ++i) + { + // http://msdn.microsoft.com/en-us/library/hs3e7355.aspx + // -> check if tempnam needs the 'free' + char *tempinput = tempnam(0, "gdcminkduexp"); + char *tempoutput = tempnam(0, "gdcmoutkduexp"); + if( !tempinput || !tempoutput ) + { + //free(input); + //free(output); + return false; + } + std::string input = tempinput; + input += ".j2k"; + std::string output = tempoutput; + output += ".rawl"; + + std::ofstream outfile(input.c_str(), std::ios::binary); + const Fragment &frag = sf->GetFragment(i); + assert( !frag.IsEmpty() ); + const ByteValue *bv = frag.GetByteValue(); + assert( bv ); + //sf->WriteBuffer(outfile); + bv->WriteBuffer( outfile ); + outfile.close(); // flush ! + + //gdcm::Filename fn( System::GetCurrentProcessFileName() ); + //std::string executable_path = fn.GetPath(); +#ifdef GDCM_USE_SYSTEM_KAKADU + std::string kakadu_command = GDCM_KAKADU_EXPAND_EXECUTABLE; + kakadu_command += " -quiet"; +#else +#error not implemented +#endif + // ./bin/kakadujpeg -d -s jpeg.jpg -ci 0 out.raw + kakadu_command += " -i "; + kakadu_command += input; + kakadu_command += " -o "; + kakadu_command += output; + + //std::cerr << kakadu_command << std::endl; + gdcmDebugMacro( kakadu_command ); + int ret = system(kakadu_command.c_str()); + //std::cerr << "system: " << ret << std::endl; + + size_t len = gdcm::System::FileSize(output.c_str()); + if(!len) return false; + + std::ifstream is(output.c_str(), std::ios::binary); + char * buf = new char[len]; + is.read(buf, len); + os.write(buf, len); + //out.SetByteValue( buf, len ); + delete[] buf; + + if( !System::RemoveFile(input.c_str()) ) + { + gdcmErrorMacro( "Could not delete input: " << input ); + } + if( !System::RemoveFile(output.c_str()) ) + { + gdcmErrorMacro( "Could not delete output: " << output ); + } + free(tempinput); + free(tempoutput); + } + std::string str = os.str(); + assert( str.size() ); + out.SetTag( gdcm::Tag(0x7fe0,0x0010) ); + out.SetByteValue( &str[0], str.size() ); + } + else + { + gdcmErrorMacro( "Not handled" ); + return false; + } + + // FIXME: + //LossyFlag = true; + + //return ImageCodec::Decode(in,out); + return true; +#endif +} + +// Compress into JPEG +bool KAKADUCodec::Code(DataElement const &in, DataElement &out) +{ +#ifndef GDCM_USE_KAKADU + (void)in; + (void)out; + return false; +#else + // That would be neat, please contribute :) + return false; +#endif +} + +ImageCodec * KAKADUCodec::Clone() const +{ + return NULL; +} + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmKAKADUCodec.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmKAKADUCodec.h new file mode 100644 index 0000000..962a5b7 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmKAKADUCodec.h @@ -0,0 +1,42 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMKAKADUCODEC_H +#define GDCMKAKADUCODEC_H + +#include "gdcmImageCodec.h" + +namespace gdcm +{ + +/** + * \brief KAKADUCodec + */ +class KAKADUCodec : public ImageCodec +{ +public: + KAKADUCodec(); + ~KAKADUCodec(); + bool CanDecode(TransferSyntax const &ts) const; + bool CanCode(TransferSyntax const &ts) const; + + bool Decode(DataElement const &is, DataElement &os); + bool Code(DataElement const &in, DataElement &out); + + virtual ImageCodec * Clone() const; +private: +}; + +} // end namespace gdcm + +#endif //GDCMKAKADUCODEC_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmLookupTable.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmLookupTable.cxx new file mode 100644 index 0000000..70c4fda --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmLookupTable.cxx @@ -0,0 +1,656 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmLookupTable.h" +#include +#include + +#include + +namespace gdcm +{ + +class LookupTableInternal +{ +public: + LookupTableInternal():RGB() + { + Length[0] = Length[1] = Length[2] = 0; + Subscript[0] = Subscript[1] = Subscript[2] = 0; + BitSize[0] = BitSize[1] = BitSize[2] = 0; + } + unsigned int Length[3]; // In DICOM the length is specified on a short + // but 65536 is expressed as 0 ... + unsigned short Subscript[3]; + unsigned short BitSize[3]; + std::vector RGB; +}; + +LookupTable::LookupTable() +{ + Internal = new LookupTableInternal; + BitSample = 0; + IncompleteLUT = false; +} + +LookupTable::~LookupTable() +{ + delete Internal; +} + +bool LookupTable::Initialized() const +{ + bool b1 = BitSample != 0; + bool b2 = + Internal->BitSize[0] != 0 && + Internal->BitSize[1] != 0 && + Internal->BitSize[2] != 0; + return b1 && b2; +} + +void LookupTable::Clear() +{ + BitSample = 0; + IncompleteLUT = false; + delete Internal; + Internal = new LookupTableInternal; +} + +void LookupTable::Allocate( unsigned short bitsample ) +{ + if( bitsample == 8 ) + { + Internal->RGB.resize( 256 * 3 ); + } + else if ( bitsample == 16 ) + { + Internal->RGB.resize( 65536 * 2 * 3 ); + } + else + { + gdcmAssertAlwaysMacro(0); + } + BitSample = bitsample; +} + +void LookupTable::InitializeLUT(LookupTableType type, unsigned short length, + unsigned short subscript, unsigned short bitsize) +{ + if( bitsize != 8 && bitsize != 16 ) + { + return; + } + assert( type >= RED && type <= BLUE ); + assert( subscript == 0 ); + assert( bitsize == 8 || bitsize == 16 ); + if( length == 0 ) + { + Internal->Length[type] = 65536; + } + else + { + if( length != 256 ) + { + IncompleteLUT = true; + } + Internal->Length[type] = length; + } + Internal->Subscript[type] = subscript; + Internal->BitSize[type] = bitsize; +} + +unsigned int LookupTable::GetLUTLength(LookupTableType type) const +{ + return Internal->Length[type]; +} + +void LookupTable::SetLUT(LookupTableType type, const unsigned char *array, + unsigned int length) +{ + (void)length; + //if( !Initialized() ) return; + if( !Internal->Length[type] ) + { + gdcmDebugMacro( "Need to set length first" ); + return; + } + + if( !IncompleteLUT ) + { + assert( Internal->RGB.size() == 3*Internal->Length[type]*(BitSample/8) ); + } + // Too funny: 05115014-mr-siemens-avanto-syngo-with-palette-icone.dcm + // There is pseudo PALETTE_COLOR LUT in the Icon, if one look carefully the LUT values + // goes like this: 0, 1, 2, 3, 4, 5, 6, 7 ... + if( BitSample == 8 ) + { + const unsigned int mult = Internal->BitSize[type]/8; + assert( Internal->Length[type]*mult == length + || Internal->Length[type]*mult + 1 == length ); + unsigned int offset = 0; + if( mult == 2 ) + { + offset = 1; + } + for( unsigned int i = 0; i < Internal->Length[type]; ++i) + { + assert( i*mult+offset < length ); + assert( 3*i+type < Internal->RGB.size() ); + Internal->RGB[3*i+type] = array[i*mult+offset]; + } + } + else if( BitSample == 16 ) + { + assert( Internal->Length[type]*(BitSample/8) == length ); + uint16_t *uchar16 = (uint16_t*)&Internal->RGB[0]; + const uint16_t *array16 = (uint16_t*)array; + for( unsigned int i = 0; i < Internal->Length[type]; ++i) + { + assert( 2*i < length ); + assert( 2*(3*i+type) < Internal->RGB.size() ); + uchar16[3*i+type] = array16[i]; + } + } +} + +void LookupTable::GetLUT(LookupTableType type, unsigned char *array, unsigned int &length) const +{ + if( BitSample == 8 ) + { + const unsigned int mult = Internal->BitSize[type]/8; + length = Internal->Length[type]*mult; + unsigned int offset = 0; + if( mult == 2 ) + { + offset = 1; + } + for( unsigned int i = 0; i < Internal->Length[type]; ++i) + { + assert( i*mult+offset < length ); + assert( 3*i+type < Internal->RGB.size() ); + array[i*mult+offset] = Internal->RGB[3*i+type]; + } + } + else if( BitSample == 16 ) + { + length = Internal->Length[type]*(BitSample/8); + uint16_t *uchar16 = (uint16_t*)&Internal->RGB[0]; + uint16_t *array16 = (uint16_t*)array; + for( unsigned int i = 0; i < Internal->Length[type]; ++i) + { + assert( 2*i < length ); + assert( 2*(3*i+type) < Internal->RGB.size() ); + array16[i] = uchar16[3*i+type]; + } + } +} + +void LookupTable::GetLUTDescriptor(LookupTableType type, unsigned short &length, + unsigned short &subscript, unsigned short &bitsize) const +{ + assert( type >= RED && type <= BLUE ); + if( Internal->Length[type] == 65536 ) + { + length = 0; + } + else + { + length = (unsigned short)Internal->Length[type]; + } + subscript = Internal->Subscript[type]; + bitsize = Internal->BitSize[type]; + + // postcondition + assert( subscript == 0 ); + assert( bitsize == 8 || bitsize == 16 ); +} + +void LookupTable::InitializeRedLUT(unsigned short length, +unsigned short subscript, +unsigned short bitsize) + { + InitializeLUT(RED, length, subscript, bitsize); + } +void LookupTable::InitializeGreenLUT(unsigned short length, + unsigned short subscript, + unsigned short bitsize) +{ + InitializeLUT(GREEN, length, subscript, bitsize); +} +void LookupTable::InitializeBlueLUT(unsigned short length, + unsigned short subscript, + unsigned short bitsize) +{ + InitializeLUT(BLUE, length, subscript, bitsize); +} + +void LookupTable::SetRedLUT(const unsigned char *red, unsigned int length) +{ + SetLUT(RED, red, length); +} + +void LookupTable::SetGreenLUT(const unsigned char *green, unsigned int length) +{ + SetLUT(GREEN, green, length); +} + +void LookupTable::SetBlueLUT(const unsigned char *blue, unsigned int length) +{ + SetLUT(BLUE, blue, length); +} + +namespace { + typedef union { + uint8_t rgb[4]; // 3rd value = 0 + uint32_t I; + } U8; + + typedef union { + uint16_t rgb[4]; // 3rd value = 0 + uint64_t I; + } U16; + + struct ltstr8 + { + bool operator()(U8 u1, U8 u2) const + { + return u1.I < u2.I; + } + }; + struct ltstr16 + { + bool operator()(U16 u1, U16 u2) const + { + return u1.I < u2.I; + } + }; +} // end namespace + +inline void printrgb( const unsigned char *rgb ) +{ + std::cout << int(rgb[0]) << "," << int(rgb[1]) << "," << int(rgb[2]); +} + +void LookupTable::Encode(std::istream &is, std::ostream &os) +{ + if ( BitSample == 8 ) + { +#if 0 + // FIXME: + // There is a very subbtle issue here. We are trying to compress a 8bits RGB image + // into an 8bits allocated indexed Pixel Data with 8bits LUT... this is just not + // possible in the general case + typedef std::set< U8, ltstr8 > RGBColorIndexer; + RGBColorIndexer s; + + int count = 0; + while( !is.eof() ) + { + U8 u; + u.rgb[3] = 0; + is.read( (char*)u.rgb, 3); + assert( u.rgb[3] == 0 ); + //assert( u.rgb[0] == u.rgb[1] && u.rgb[1] == u.rgb[2] ); + std::pair it = s.insert( u ); + if( it.second ) ++count; + int d = std::distance(s.begin(), it.first); + //std::cout << count << " Index: " << d << " -> "; printrgb( u.rgb ); std::cout << "\n"; + //assert( s.size() < 256 ); + assert( d < s.size() ); + //assert( d < 256 && d >= 0 ); + } + + // now generate output image + // this has two been done in two passes as std::set always re-balance + is.clear(); + is.seekg( 0 ); + while( !is.eof() ) + { + U8 u; + u.rgb[3] = 0; + is.read( (char*)u.rgb, 3); + assert( u.rgb[3] == 0 ); + //assert( u.rgb[0] == u.rgb[1] && u.rgb[1] == u.rgb[2] ); + std::pair it = s.insert( u ); + int d = std::distance(s.begin(), it.first); + //std::cout << "Index: " << d << " -> "; printrgb( u.rgb ); std::cout << "\n"; + assert( d < s.size() ); + //assert( d < 256 && d >= 0 ); + os.put( d ); + } + + // now setup the LUT itself: + unsigned short ncolor = s.size(); + // FIXME: shop'off any RGB that is not at the beginning. + if( ncolor > 256 ) ncolor = 256; + InitializeRedLUT(ncolor, 0, 8); + InitializeGreenLUT(ncolor, 0, 8); + InitializeBlueLUT(ncolor, 0, 8); + //int i = Internal->RGB.size(); + //assert( Internal->RGB.size() == 5 ); + int idx = 0; + for( RGBColorIndexer::const_iterator it = s.begin(); it != s.end() && idx < 256; ++it, ++idx ) + { + assert( idx == std::distance( s.begin(), it ) ); + //std::cout << "Index: " << idx << " -> "; printrgb( it->rgb ); std::cout << "\n"; + Internal->RGB[3*idx+RED] = it->rgb[RED]; + Internal->RGB[3*idx+GREEN] = it->rgb[GREEN]; + Internal->RGB[3*idx+BLUE] = it->rgb[BLUE]; + } +#else + while( !is.eof() ) + { + U8 u; + u.rgb[3] = 0; + is.read( (char*)u.rgb, 3); + assert( u.rgb[3] == 0 ); + int d = 0; + assert( d < 256 && d >= 0 ); + os.put( (char)d ); + } +#endif + } + else if ( BitSample == 16 ) + { +#if 0 + typedef std::set< U16, ltstr16 > RGBColorIndexer; + RGBColorIndexer s; + + while( !is.eof() ) + { + U16 u; + u.rgb[3] = 0; + is.read( (char*)u.rgb, 3*2); + assert( u.rgb[3] == 0 ); + //assert( u.rgb[0] == u.rgb[1] && u.rgb[1] == u.rgb[2] ); + std::pair it = s.insert( u ); + int d = std::distance(s.begin(), it.first); + //std::cout << "Index: " << d << " -> "; printrgb( u.rgb ); std::cout << "\n"; + assert( d < s.size() ); + assert( d < 65536 && d >= 0 ); + } + + // now generate output image + // this has two been done in two passes as std::set always re-balance + is.clear(); + is.seekg( 0 ); + while( !is.eof() ) + { + U16 u; + u.rgb[3] = 0; + is.read( (char*)u.rgb, 3*2); + assert( u.rgb[3] == 0 ); + //assert( u.rgb[0] == u.rgb[1] && u.rgb[1] == u.rgb[2] ); + std::pair it = s.insert( u ); + unsigned short d = std::distance(s.begin(), it.first); + //std::cout << "Index: " << d << " -> "; printrgb( u.rgb ); std::cout << "\n"; + assert( d < s.size() ); + assert( d < 65536 && d >= 0 ); + os.write( (char*)&d , 2 ); + } + + // now setup the LUT itself: + unsigned short ncolor = s.size(); + InitializeRedLUT(ncolor, 0, 16); + InitializeGreenLUT(ncolor, 0, 16); + InitializeBlueLUT(ncolor, 0, 16); + //int i = Internal->RGB.size(); + //assert( Internal->RGB.size() == 5 ); + int idx = 0; + uint16_t *rgb16 = (uint16_t*)&Internal->RGB[0]; + for( RGBColorIndexer::const_iterator it = s.begin(); it != s.end(); ++it, ++idx ) + { + assert( idx == std::distance( s.begin(), it ) ); + //std::cout << "Index: " << idx << " -> "; printrgb( it->rgb ); std::cout << "\n"; + rgb16[3*idx+RED] = it->rgb[RED]; + rgb16[3*idx+GREEN] = it->rgb[GREEN]; + rgb16[3*idx+BLUE] = it->rgb[BLUE]; + } +#else + while( !is.eof() ) + { + U16 u; + u.rgb[3] = 0; + is.read( (char*)u.rgb, 3*2); + assert( u.rgb[3] == 0 ); + int d = 0; + assert( d < 65536 && d >= 0 ); + os.write( (char*)&d , 2 ); + } +#endif + } +} + +void LookupTable::Decode(std::istream &is, std::ostream &os) const +{ + assert( Initialized() ); + if ( BitSample == 8 ) + { + unsigned char idx; + unsigned char rgb[3]; + while( !is.eof() ) + { + is.read( (char*)(&idx), 1); + if( is.eof() ) break; + if( IncompleteLUT ) + { + assert( idx < Internal->Length[RED] ); + assert( idx < Internal->Length[GREEN] ); + assert( idx < Internal->Length[BLUE] ); + } + rgb[RED] = Internal->RGB[3*idx+RED]; + rgb[GREEN] = Internal->RGB[3*idx+GREEN]; + rgb[BLUE] = Internal->RGB[3*idx+BLUE]; + os.write((char*)rgb, 3 ); + } + } + else if ( BitSample == 16 ) + { + // gdcmData/NM-PAL-16-PixRep1.dcm + const uint16_t *rgb16 = (uint16_t*)&Internal->RGB[0]; + while( !is.eof() ) + { + unsigned short idx; + unsigned short rgb[3]; + is.read( (char*)(&idx), 2); + if( is.eof() ) break; + if( IncompleteLUT ) + { + assert( idx < Internal->Length[RED] ); + assert( idx < Internal->Length[GREEN] ); + assert( idx < Internal->Length[BLUE] ); + } + rgb[RED] = rgb16[3*idx+RED]; + rgb[GREEN] = rgb16[3*idx+GREEN]; + rgb[BLUE] = rgb16[3*idx+BLUE]; + os.write((char*)rgb, 3*2); + } + } +} + +bool LookupTable::Decode(char *output, size_t outlen, const char *input, size_t inlen ) const +{ + bool success = false; + if( outlen < 3 * inlen ) + { + gdcmDebugMacro( "Out buffer too small" ); + return false; + } + if( !Initialized() ) + { + gdcmDebugMacro( "Not Initialized" ); + return false; + } + if ( BitSample == 8 ) + { + const unsigned char * end = (unsigned char*)input + inlen; + unsigned char * rgb = (unsigned char*)output; + for( unsigned char * idx = (unsigned char*)input; idx != end; ++idx ) + { + if( IncompleteLUT ) + { + assert( *idx < Internal->Length[RED] ); + assert( *idx < Internal->Length[GREEN] ); + assert( *idx < Internal->Length[BLUE] ); + } + rgb[RED] = Internal->RGB[3 * *idx+RED]; + rgb[GREEN] = Internal->RGB[3 * *idx+GREEN]; + rgb[BLUE] = Internal->RGB[3 * *idx+BLUE]; + rgb += 3; + } + success = true; + } + else if ( BitSample == 16 ) + { + const uint16_t *rgb16 = (uint16_t*)&Internal->RGB[0]; + assert( inlen % 2 == 0 ); + const uint16_t * end = (uint16_t*)(input + inlen); + uint16_t * rgb = (uint16_t*)output; + for( uint16_t * idx = (uint16_t*)input; idx != end; ++idx ) + { + if( IncompleteLUT ) + { + assert( *idx < Internal->Length[RED] ); + assert( *idx < Internal->Length[GREEN] ); + assert( *idx < Internal->Length[BLUE] ); + } + rgb[RED] = rgb16[3 * *idx+RED]; + rgb[GREEN] = rgb16[3 * *idx+GREEN]; + rgb[BLUE] = rgb16[3 * *idx+BLUE]; + rgb += 3; + } + success = true; + } + return success; +} + +const unsigned char *LookupTable::GetPointer() const +{ + if ( BitSample == 8 ) + { + return &Internal->RGB[0]; + } + return 0; +} + +bool LookupTable::GetBufferAsRGBA(unsigned char *rgba) const +{ + bool ret = false; + if ( BitSample == 8 ) + { + std::vector::const_iterator it = Internal->RGB.begin(); + for(; it != Internal->RGB.end() ;) + { + // RED + *rgba++ = *it++; + // GREEN + *rgba++ = *it++; + // BLUE + *rgba++ = *it++; + // ALPHA + *rgba++ = 255; + } + ret = true; + } + else if ( BitSample == 16 ) + { +/* + assert( Internal->Length[type]*(BitSample/8) == length ); + uint16_t *uchar16 = (uint16_t*)&Internal->RGB[0]; + const uint16_t *array16 = (uint16_t*)array; + for( unsigned int i = 0; i < Internal->Length[type]; ++i) + { + assert( 2*i < length ); + assert( 2*(3*i+type) < Internal->RGB.size() ); + uchar16[3*i+type] = array16[i]; + std::cout << i << " -> " << array16[i] << "\n"; + } + + ret = true; +*/ + //std::vector::const_iterator it = Internal->RGB.begin(); + uint16_t *uchar16 = (uint16_t*)&Internal->RGB[0]; + uint16_t *rgba16 = (uint16_t*)rgba; + size_t s = Internal->RGB.size(); + s /= 2; + s /= 3; + memset(rgba,0,Internal->RGB.size() * 4 / 3); // FIXME + for(size_t i = 0; i < s; ++i) + { + // RED + *rgba16++ = *uchar16++; + // GREEN + *rgba16++ = *uchar16++; + // BLUE + *rgba16++ = *uchar16++; + // ALPHA + *rgba16++ = 255*255; + } + + ret = true; + } + return ret; +} + +bool LookupTable::WriteBufferAsRGBA(const unsigned char *rgba) +{ + bool ret = false; + if ( BitSample == 8 ) + { + std::vector::iterator it = Internal->RGB.begin(); + for(; it != Internal->RGB.end() ;) + { + // RED + *it++ = *rgba++; + // GREEN + *it++ = *rgba++; + // BLUE + *it++ = *rgba++; + // ALPHA + rgba++; // = 255; + } + ret = true; + } + else if ( BitSample == 16 ) + { + //assert( Internal->Length[type]*(BitSample/8) == length ); + uint16_t *uchar16 = (uint16_t*)&Internal->RGB[0]; + const uint16_t *rgba16 = (uint16_t*)rgba; + size_t s = Internal->RGB.size(); + s /= 2; + s /= 3; + assert( s == 65536 ); + + for( unsigned int i = 0; i < s /*i < Internal->Length[type]*/; ++i) + { + //assert( 2*i < length ); + //assert( 2*(3*i+type) < Internal->RGB.size() ); + //uchar16[3*i+type] = array16[i]; + //std::cout << i << " -> " << array16[i] << "\n"; + // RED + *uchar16++ = *rgba16++; + // GREEN + *uchar16++ = *rgba16++; + // BLUE + *uchar16++ = *rgba16++; + // + rgba16++; // = *rgba16++; + } + + ret = true; + //ret = false; + } + return ret; +} + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmLookupTable.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmLookupTable.h new file mode 100644 index 0000000..abd38d7 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmLookupTable.h @@ -0,0 +1,111 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#ifndef GDCMLOOKUPTABLE_H +#define GDCMLOOKUPTABLE_H + +#include "gdcmTypes.h" +#include "gdcmObject.h" +#include + +namespace gdcm +{ + +class LookupTableInternal; +/** + * \brief LookupTable class + */ +class GDCM_EXPORT LookupTable : public Object +{ +public: + typedef enum { + RED = 0, // Keep RED == 0 + GREEN, + BLUE, + GRAY, + UNKNOWN + } LookupTableType; + + LookupTable(); + ~LookupTable(); + void Print(std::ostream &) const {} + + /// Allocate the LUT + void Allocate( unsigned short bitsample = 8 ); + /// Generic interface: + //TODO: check to see if length should be unsigned short, unsigned int, or whatever + void InitializeLUT(LookupTableType type, unsigned short length, + unsigned short subscript, unsigned short bitsize); + unsigned int GetLUTLength(LookupTableType type) const; + virtual void SetLUT(LookupTableType type, const unsigned char *array, + unsigned int length); + void GetLUT(LookupTableType type, unsigned char *array, unsigned int &length) const; + void GetLUTDescriptor(LookupTableType type, unsigned short &length, + unsigned short &subscript, unsigned short &bitsize) const; + + /// RED / GREEN / BLUE specific: + void InitializeRedLUT(unsigned short length, unsigned short subscript, + unsigned short bitsize); + void SetRedLUT(const unsigned char *red, unsigned int length); + void InitializeGreenLUT(unsigned short length, unsigned short subscript, + unsigned short bitsize); + void SetGreenLUT(const unsigned char *green, unsigned int length); + void InitializeBlueLUT(unsigned short length, unsigned short subscript, + unsigned short bitsize); + void SetBlueLUT(const unsigned char *blue, unsigned int length); + + /// Clear the LUT + void Clear(); + + /// Decode the LUT + void Decode(std::istream &is, std::ostream &os) const; + + /// Decode the LUT + /// outputbuffer will contains the RGB decoded PALETTE COLOR input image of size inlen + /// the outputbuffer should be at least 3 times the size of inlen + bool Decode(char *outputbuffer, size_t outlen, const char *inputbuffer, size_t inlen) const; + + LookupTable(LookupTable const &lut):Object(lut) + { + assert(0); + } + + /// return the LUT as RGBA buffer + bool GetBufferAsRGBA(unsigned char *rgba) const; + + /// return a raw pointer to the LUT + const unsigned char *GetPointer() const; + + /// Write the LUT as RGBA + bool WriteBufferAsRGBA(const unsigned char *rgba); + + /// return the bit sample + unsigned short GetBitSample() const { return BitSample; } + + /// return whether the LUT has been initialized + bool Initialized() const; + +private: + /// Unfinished work + void Encode(std::istream &is, std::ostream &os); + +protected: + LookupTableInternal *Internal; + unsigned short BitSample; // refer to the pixel type (not the bit size of LUT) + bool IncompleteLUT:1; +}; + +} // end namespace gdcm + +#endif //GDCMLOOKUPTABLE_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmMeshPrimitive.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmMeshPrimitive.cxx new file mode 100644 index 0000000..cc92fff --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmMeshPrimitive.cxx @@ -0,0 +1,149 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#include "gdcmMeshPrimitive.h" +#include "gdcmCodeString.h" + +#include + +namespace gdcm +{ + +static const char * MPStrings[] = { + "VERTEX", + "EDGE", + "TRIANGLE", + "TRIANGLESTRIP", + "TRIANGLEFAN", + "LINE", + "FACET", + 0 +}; + +const char * MeshPrimitive::GetMPTypeString(const MPType type) +{ + assert( type <= MPType_END ); + return MPStrings[(int)type]; +} + +MeshPrimitive::MPType MeshPrimitive::GetMPType(const char * type) +{ + if(!type) return MPType_END; + + // Delete possible space as last character + String<> str( type ); + str.Trim(); + const char * typeClear = str.Trim().c_str(); + + for(unsigned int i = 0; MPStrings[i] != 0; ++i) + { + if( strcmp(typeClear, MPStrings[i]) == 0 ) + { + return (MPType)i; + } + } + // Ouch ! We did not find anything, that's pretty bad, let's hope that + // the toolkit which wrote the image is buggy and tolerate space padded binary + // string + CodeString codestring = typeClear; + std::string cs = codestring.GetAsString(); + for(unsigned int i = 0; MPStrings[i] != 0; ++i) + { + if( strcmp(cs.c_str(), MPStrings[i]) == 0 ) + { + return (MPType)i; + } + } + + return MPType_END; +} + +MeshPrimitive::MeshPrimitive(): + PrimitiveType(MPType_END), + PrimitiveData(1, DataElement()) +{ +} + +MeshPrimitive::~MeshPrimitive() +{ +} + +MeshPrimitive::MPType MeshPrimitive::GetPrimitiveType() const +{ + return PrimitiveType; +} + +void MeshPrimitive::SetPrimitiveType(const MPType type) +{ + assert( type <= MPType_END ); + PrimitiveType = type; +} + +const DataElement & MeshPrimitive::GetPrimitiveData() const +{ + return PrimitiveData.front(); +} + +DataElement & MeshPrimitive::GetPrimitiveData() +{ + return PrimitiveData.front(); +} + +void MeshPrimitive::SetPrimitiveData(DataElement const & de) +{ + PrimitiveData.insert(PrimitiveData.begin(), de); +} + +const MeshPrimitive::PrimitivesData & MeshPrimitive::GetPrimitivesData() const +{ + return PrimitiveData; +} + +MeshPrimitive::PrimitivesData & MeshPrimitive::GetPrimitivesData() +{ + return PrimitiveData; +} + +void MeshPrimitive::SetPrimitivesData(PrimitivesData const & DEs) +{ + PrimitiveData = DEs; +} + +void MeshPrimitive::SetPrimitiveData(const unsigned int idx, DataElement const & de) +{ + PrimitiveData.insert(PrimitiveData.begin() + idx, de); +} + +void MeshPrimitive::AddPrimitiveData(DataElement const & de) +{ + PrimitiveData.push_back(de); +} + +const DataElement & MeshPrimitive::GetPrimitiveData(const unsigned int idx) const +{ + assert( idx < this->GetNumberOfPrimitivesData() ); + return PrimitiveData[idx]; +} +DataElement & MeshPrimitive::GetPrimitiveData(const unsigned int idx) +{ + assert( idx < this->GetNumberOfPrimitivesData() ); + return PrimitiveData[idx]; +} + +unsigned int MeshPrimitive::GetNumberOfPrimitivesData() const +{ + return (unsigned int)PrimitiveData.size(); +} + +} diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmMeshPrimitive.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmMeshPrimitive.h new file mode 100644 index 0000000..55ba503 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmMeshPrimitive.h @@ -0,0 +1,90 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#ifndef GDCMMESHPRIMITIVE_H +#define GDCMMESHPRIMITIVE_H + +#include +#include + +namespace gdcm +{ + +/** + * \brief This class defines surface mesh primitives. + * It is designed from surface mesh primitives macro. + * + * \see PS 3.3 C.27.4 + */ +class GDCM_EXPORT MeshPrimitive : public Object +{ +public: + + typedef std::vector< DataElement > PrimitivesData; + + /** + * \brief This enumeration defines primitive types. + * + * \see PS 3.3 C.27.4.1 + */ + typedef enum { + VERTEX = 0, + EDGE, + TRIANGLE, + TRIANGLE_STRIP, + TRIANGLE_FAN, + LINE, + FACET, + MPType_END + } MPType; + + static const char * GetMPTypeString(const MPType type); + + static MPType GetMPType(const char * type); + + MeshPrimitive(); + + virtual ~MeshPrimitive(); + + MPType GetPrimitiveType() const; + void SetPrimitiveType(const MPType type); + + const DataElement & GetPrimitiveData() const; + DataElement & GetPrimitiveData(); + void SetPrimitiveData(DataElement const & de); + + const PrimitivesData & GetPrimitivesData() const; + PrimitivesData & GetPrimitivesData(); + void SetPrimitivesData(PrimitivesData const & DEs); + + const DataElement & GetPrimitiveData(const unsigned int idx) const; + DataElement & GetPrimitiveData(const unsigned int idx); + void SetPrimitiveData(const unsigned int idx, DataElement const & de); + void AddPrimitiveData(DataElement const & de); + + unsigned int GetNumberOfPrimitivesData() const; + +protected: + + // Use to define tag where PrimitiveData will be put. + MPType PrimitiveType; + + // PrimitiveData contains point index list. + // It shall have 1 or 1-n DataElement following PrimitiveType. + PrimitivesData PrimitiveData; +}; + +} + +#endif // GDCMMESHPRIMITIVE_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmOrientation.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmOrientation.cxx new file mode 100644 index 0000000..28d4500 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmOrientation.cxx @@ -0,0 +1,120 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmOrientation.h" + +#include + +namespace gdcm +{ + +Orientation::Orientation() {} +Orientation::~Orientation() {} + +void Orientation::Print(std::ostream &os) const +{ + os << "ObliquityThresholdCosineValue:" << ObliquityThresholdCosineValue; +} + +static const char *OrientationStrings[] = { + "UNKNOWN", + "AXIAL", + "CORONAL", + "SAGITTAL", + "OBLIQUE", + NULL +}; + +// http://public.kitware.com/pipermail/insight-users/2005-March/012246.html +// 0.5477 would be the square root of 1 (unit vector sum of squares) divided by 3 (oblique axes - a "double" oblique) +// 0.7071 would be the square root of 1 (unit vector sum of squares) divided by 2 (oblique axes) +double Orientation::ObliquityThresholdCosineValue = 0.8; +//const double Orientation::obliquityThresholdCosineValue = 0.7071; +char Orientation::GetMajorAxisFromPatientRelativeDirectionCosine(double x, double y, double z) +{ + char axis = 0; + + char orientationX = x < 0 ? 'R' : 'L'; + char orientationY = y < 0 ? 'A' : 'P'; + char orientationZ = z < 0 ? 'F' : 'H'; + + double absX = fabs(x); + double absY = fabs(y); + double absZ = fabs(z); + + // The tests here really don't need to check the other dimensions, + // just the threshold, since the sum of the squares should be == 1.0 + // but just in case ... + + if (absX>ObliquityThresholdCosineValue && absX>absY && absX>absZ) + { + axis = orientationX; + } + else if (absY>ObliquityThresholdCosineValue && absY>absX && absY>absZ) + { + axis = orientationY; + } + else if (absZ>ObliquityThresholdCosineValue && absZ>absX && absZ>absY) + { + axis = orientationZ; + } + else + { + // nothing + } + return axis; +} + +void Orientation::SetObliquityThresholdCosineValue(double val) +{ + Orientation::ObliquityThresholdCosineValue = val; +} + +double Orientation::GetObliquityThresholdCosineValue() +{ + return Orientation::ObliquityThresholdCosineValue; +} + +Orientation::OrientationType Orientation::GetType(const double dircos[6]) +{ + OrientationType type = Orientation::UNKNOWN; + if( dircos ) + { + char rowAxis = GetMajorAxisFromPatientRelativeDirectionCosine(dircos[0],dircos[1],dircos[2]); + char colAxis = GetMajorAxisFromPatientRelativeDirectionCosine(dircos[3],dircos[4],dircos[5]); + if (rowAxis != 0 && colAxis != 0 ) + { + if ((rowAxis == 'R' || rowAxis == 'L') && (colAxis == 'A' || colAxis == 'P')) type = Orientation::AXIAL; + else if ((colAxis == 'R' || colAxis == 'L') && (rowAxis == 'A' || rowAxis == 'P')) type = Orientation::AXIAL; + + else if ((rowAxis == 'R' || rowAxis == 'L') && (colAxis == 'H' || colAxis == 'F')) type = Orientation::CORONAL; + else if ((colAxis == 'R' || colAxis == 'L') && (rowAxis == 'H' || rowAxis == 'F')) type = Orientation::CORONAL; + + else if ((rowAxis == 'A' || rowAxis == 'P') && (colAxis == 'H' || colAxis == 'F')) type = Orientation::SAGITTAL; + else if ((colAxis == 'A' || colAxis == 'P') && (rowAxis == 'H' || rowAxis == 'F')) type = Orientation::SAGITTAL; + } + else + { + type = Orientation::OBLIQUE; + } + } + return type; +} + +const char *Orientation::GetLabel(OrientationType type) +{ + return OrientationStrings[type]; +} + + +} diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmOrientation.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmOrientation.h new file mode 100644 index 0000000..c4d21f6 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmOrientation.h @@ -0,0 +1,69 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMORIENTATION_H +#define GDCMORIENTATION_H + +#include "gdcmTypes.h" + +namespace gdcm +{ + +/** + * \brief class to handle Orientation + */ +class GDCM_EXPORT Orientation +{ + friend std::ostream& operator<<(std::ostream &_os, const Orientation &o); +public: + Orientation(); + ~Orientation(); + + /// Print + void Print(std::ostream &) const; + + typedef enum { + UNKNOWN, + AXIAL, + CORONAL, + SAGITTAL, + OBLIQUE + } OrientationType; + + /// Return the type of orientation from a direction cosines + /// Input is an array of 6 double + static OrientationType GetType(const double dircos[6]); + + /// ObliquityThresholdCosineValue stuff + static void SetObliquityThresholdCosineValue(double val); + static double GetObliquityThresholdCosineValue(); + + /// Return the label of an Orientation + static const char *GetLabel(OrientationType type); + +protected: + static char GetMajorAxisFromPatientRelativeDirectionCosine(double x, double y, double z); + +private: + static double ObliquityThresholdCosineValue; +}; +//----------------------------------------------------------------------------- +inline std::ostream& operator<<(std::ostream &os, const Orientation &o) +{ + o.Print( os ); + return os; +} + +} // end namespace gdcm + +#endif //GDCMORIENTATION_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmOverlay.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmOverlay.cxx new file mode 100644 index 0000000..afa0e88 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmOverlay.cxx @@ -0,0 +1,501 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmOverlay.h" +#include "gdcmTag.h" +#include "gdcmDataElement.h" +#include "gdcmDataSet.h" +#include "gdcmAttribute.h" + +#include + +namespace gdcm +{ + +class OverlayInternal +{ +public: + OverlayInternal(): + InPixelData(false), + Group(0), // invalid default + Rows(0), + Columns(0), + NumberOfFrames(0), + Description(), + Type(), + //Origin[2], + FrameOrigin(0), + BitsAllocated(0), + BitPosition(0), + Data() { Origin[0] = Origin[1] = 0; } + /* + (6000,0010) US 484 # 2, 1 OverlayRows + (6000,0011) US 484 # 2, 1 OverlayColumns + (6000,0015) IS [1] # 2, 1 NumberOfFramesInOverlay + (6000,0022) LO [Siemens MedCom Object Graphics] # 30, 1 OverlayDescription + (6000,0040) CS [G] # 2, 1 OverlayType + (6000,0050) SS 1\1 # 4, 2 OverlayOrigin + (6000,0051) US 1 # 2, 1 ImageFrameOrigin + (6000,0100) US 1 # 2, 1 OverlayBitsAllocated + (6000,0102) US 0 # 2, 1 OverlayBitPosition + (6000,3000) OW 0000\0000\0000\0000\0000\0000\0000\0000\0000\0000\0000\0000\0000... # 29282, 1 OverlayData + */ + + bool InPixelData; +// Identifier need to be in the [6000,60FF] range (no odd number): + unsigned short Group; +// Descriptor: + unsigned short Rows; // (6000,0010) US 484 # 2, 1 OverlayRows + unsigned short Columns; // (6000,0011) US 484 # 2, 1 OverlayColumns + unsigned int NumberOfFrames; // (6000,0015) IS [1] # 2, 1 NumberOfFramesInOverlay + std::string Description; // (6000,0022) LO [Siemens MedCom Object Graphics] # 30, 1 OverlayDescription + std::string Type; // (6000,0040) CS [G] # 2, 1 OverlayType + signed short Origin[2]; // (6000,0050) SS 1\1 # 4, 2 OverlayOrigin + unsigned short FrameOrigin; // (6000,0051) US 1 # 2, 1 ImageFrameOrigin + unsigned short BitsAllocated; // (6000,0100) US 1 # 2, 1 OverlayBitsAllocated + unsigned short BitPosition; // (6000,0102) US 0 # 2, 1 OverlayBitPosition + //std::vector Data; + std::vector Data; // hold the Overlay data, but not the trailing DICOM padding (\0) + void Print(std::ostream &os) const { + os << "Group 0x" << std::hex << Group << std::dec << std::endl; + os << "Rows " << Rows << std::endl; + os << "Columns " << Columns << std::endl; + os << "NumberOfFrames " << NumberOfFrames << std::endl; + os << "Description " << Description << std::endl; + os << "Type " << Type << std::endl; + os << "Origin[2] " << Origin[0] << "," << Origin[1] << std::endl; + os << "FrameOrigin " << FrameOrigin << std::endl; + os << "BitsAllocated " << BitsAllocated << std::endl; + os << "BitPosition " << BitPosition << std::endl; + //std::vector Data; + } +}; + +Overlay::Overlay() +{ + Internal = new OverlayInternal; +} + +Overlay::~Overlay() +{ + delete Internal; +} + +Overlay::Overlay(Overlay const &ov):Object(ov) +{ + //delete Internal; + Internal = new OverlayInternal; + // TODO: copy OverlayInternal into other... + *Internal = *ov.Internal; +} + +void Overlay::Update(const DataElement & de) +{ +/* + 8.1.2 Overlay data encoding of related data elements + Encoded Overlay Planes always have a bit depth of 1, and are encoded separately from the Pixel Data in Overlay Data (60xx,3000). The following two Data Elements shall define the Overlay Plane structure: + ¿ Overlay Bits Allocated (60xx,0100) + ¿ Overlay Bit Position (60xx,0102) + Notes: 1. There is no Data Element analogous to Bits Stored (0028,0101) since Overlay Planes always have a bit depth of 1. + 2. Restrictions on the allowed values for these Data Elements are defined in PS 3.3. Formerly overlay data stored in unused bits of Pixel Data (7FE0,0010) was described, and these attributes had meaningful values but this usage has been retired. See PS 3.5 2004. For overlays encoded in Overlay Data Element (60xx,3000), Overlay Bits Allocated (60xx,0100) is always 1 and Overlay Bit Position (60xx,0102) is always 0. +*/ + + assert( de.GetTag().IsPublic() ); + const ByteValue* bv = de.GetByteValue(); + if( !bv ) return; // Discard any empty element (will default to another value) + assert( bv->GetPointer() && bv->GetLength() ); + std::string s( bv->GetPointer(), bv->GetLength() ); + // What if a \0 can be found before the end of string... + //assert( strlen( s.c_str() ) == s.size() ); + + // First thing check consistency: + if( !GetGroup() ) + { + SetGroup( de.GetTag().GetGroup() ); + } + else // check consistency + { + assert( GetGroup() == de.GetTag().GetGroup() ); // programmer error + } + + //std::cerr << "Tag: " << de.GetTag() << std::endl; + if( de.GetTag().GetElement() == 0x0000 ) // OverlayGroupLength + { + // ?? + } + else if( de.GetTag().GetElement() == 0x0010 ) // OverlayRows + { + Attribute<0x6000,0x0010> at; + at.SetFromDataElement( de ); + SetRows( at.GetValue() ); + } + else if( de.GetTag().GetElement() == 0x0011 ) // OverlayColumns + { + Attribute<0x6000,0x0011> at; + at.SetFromDataElement( de ); + SetColumns( at.GetValue() ); + } + else if( de.GetTag().GetElement() == 0x0015 ) // NumberOfFramesInOverlay + { + Attribute<0x6000,0x0015> at; + at.SetFromDataElement( de ); + SetNumberOfFrames( at.GetValue() ); + } + else if( de.GetTag().GetElement() == 0x0022 ) // OverlayDescription + { + SetDescription( s.c_str() ); + } + else if( de.GetTag().GetElement() == 0x0040 ) // OverlayType + { + SetType( s.c_str() ); + } + else if( de.GetTag().GetElement() == 0x0045 ) // OverlaySubtype + { + gdcmWarningMacro( "FIXME" ); + } + else if( de.GetTag().GetElement() == 0x0050 ) // OverlayOrigin + { + Attribute<0x6000,0x0050> at; + at.SetFromDataElement( de ); + SetOrigin( at.GetValues() ); + } + else if( de.GetTag().GetElement() == 0x0051 ) // ImageFrameOrigin + { + Attribute<0x6000,0x0051> at; + at.SetFromDataElement( de ); + SetFrameOrigin( at.GetValue() ); + } + else if( de.GetTag().GetElement() == 0x0060 ) // OverlayCompressionCode (RET) + { + assert( s == "NONE" ); // FIXME ?? + } + else if( de.GetTag().GetElement() == 0x0100 ) // OverlayBitsAllocated + { + Attribute<0x6000,0x0100> at; + at.SetFromDataElement( de ); + // if OverlayBitsAllocated is 1 it imply OverlayData element + // if OverlayBitsAllocated is 16 it imply Overlay in unused pixel bits + if( at.GetValue() != 1 ) + { + gdcmWarningMacro( "Unsuported OverlayBitsAllocated: " << at.GetValue() ); + } + SetBitsAllocated( at.GetValue() ); + } + else if( de.GetTag().GetElement() == 0x0102 ) // OverlayBitPosition + { + Attribute<0x6000,0x0102> at; + at.SetFromDataElement( de ); + if( at.GetValue() != 0 ) // For old ACR when using unused bits... + { + gdcmDebugMacro( "Unsuported OverlayBitPosition: " << at.GetValue() ); + } + SetBitPosition( at.GetValue() ); + } + else if( de.GetTag().GetElement() == 0x0110 ) // OverlayFormat (RET) + { + assert( s == "RECT" ); + } + else if( de.GetTag().GetElement() == 0x0200 ) // OverlayLocation (RET) + { + Attribute<0x6000,0x0200> at; + at.SetFromDataElement( de ); + gdcmWarningMacro( "FIXME: " << at.GetValue() ); + } + else if( de.GetTag().GetElement() == 0x1301 ) // ROIArea + { + gdcmWarningMacro( "FIXME" ); + } + else if( de.GetTag().GetElement() == 0x1302 ) // ROIMean + { + gdcmWarningMacro( "FIXME" ); + } + else if( de.GetTag().GetElement() == 0x1303 ) // ROIStandardDeviation + { + gdcmWarningMacro( "FIXME" ); + } + else if( de.GetTag().GetElement() == 0x1500 ) // OverlayLabel + { + gdcmWarningMacro( "FIXME" ); + } + else if( de.GetTag().GetElement() == 0x3000 ) // OverlayData + { + SetOverlay(bv->GetPointer(), bv->GetLength()); + } + else + { + gdcmErrorMacro( "Tag is not supported: " << de.GetTag() << std::endl ); + assert(0); + } +} + +bool Overlay::GrabOverlayFromPixelData(DataSet const &ds) +{ + const unsigned int ovlength = Internal->Rows * Internal->Columns / 8; + Internal->Data.resize( ovlength ); // set to 0 + if( Internal->BitsAllocated == 16 ) + { + //assert( Internal->BitPosition >= 12 ); + if( ds.FindDataElement( Tag(0x7fe0,0x0010) ) ) + { + gdcmErrorMacro("Could not find Pixel Data. Cannot extract Overlay." ); + return false; + } + const DataElement &pixeldata = ds.GetDataElement( Tag(0x7fe0,0x0010) ); + const ByteValue *bv = pixeldata.GetByteValue(); + if( !bv ) + { + // XA_GE_JPEG_02_with_Overlays.dcm + return false; + } + assert( bv ); + const char *array = bv->GetPointer(); + // SIEMENS_GBS_III-16-ACR_NEMA_1.acr is pain to support, + // I cannot simply use the bv->GetLength I have to use the image dim: + const unsigned int length = ovlength * 8 * 2; //bv->GetLength(); + const uint16_t *p = (uint16_t*)array; + const uint16_t *end = (uint16_t*)(array + length); + //const unsigned int ovlength = length / (8*2); + assert( 8 * ovlength == (unsigned int)Internal->Rows * Internal->Columns ); + if( Internal->Data.empty() ) + { + return false; + } + unsigned char * overlay = (unsigned char*)&Internal->Data[0]; + int c = 0; + uint16_t pmask = (uint16_t)(1 << Internal->BitPosition); + assert( length / 2 == ovlength * 8 ); + while( p != end ) + { + const uint16_t val = *p & pmask; + assert( val == 0x0 || val == pmask ); + // 128 -> 0x80 + if( val ) + { + overlay[ c / 8 ] |= (unsigned char)(0x1 << c%8); + } + else + { + // else overlay[ c / 8 ] is already 0 + } + ++p; + ++c; + } + assert( (unsigned)c / 8 == ovlength ); + } + else + { + gdcmErrorMacro( "Could not grab Overlay from image. Please report." ); + return false; + } + return true; +} + +void Overlay::SetGroup(unsigned short group) { Internal->Group = group; } +unsigned short Overlay::GetGroup() const { return Internal->Group; } + +void Overlay::SetRows(unsigned short rows) { Internal->Rows = rows; } +unsigned short Overlay::GetRows() const { return Internal->Rows; } +void Overlay::SetColumns(unsigned short columns) { Internal->Columns = columns; } +unsigned short Overlay::GetColumns() const { return Internal->Columns; } +void Overlay::SetNumberOfFrames(unsigned int numberofframes) { Internal->NumberOfFrames = numberofframes; } +void Overlay::SetDescription(const char* description) { if( description ) Internal->Description = description; } +const char *Overlay::GetDescription() const { return Internal->Description.c_str(); } +void Overlay::SetType(const char* type) { if( type ) Internal->Type = type; } +const char *Overlay::GetType() const { return Internal->Type.c_str(); } +static const char *OverlayTypeStrings[] = { + "INVALID", + "G ", + "R ", +}; +const char *Overlay::GetOverlayTypeAsString(OverlayType ot) +{ + return OverlayTypeStrings[ (int) ot ]; +} +Overlay::OverlayType Overlay::GetOverlayTypeFromString(const char *s) +{ + static const int n = sizeof( OverlayTypeStrings ) / sizeof ( *OverlayTypeStrings ); + if( s ) + { + for( int i = 0; i < n; ++i ) + { + if( strcmp(s, OverlayTypeStrings[i] ) == 0 ) + { + return (OverlayType)i; + } + } + } + // could not find the proper type, maybe padded with \0 ? + if( strlen(s) == 1 ) + { + for( int i = 0; i < n; ++i ) + { + if( strncmp(s, OverlayTypeStrings[i], 1 ) == 0 ) + { + gdcmDebugMacro( "Invalid Padding for OVerlay Type" ); + return (OverlayType)i; + } + } + } + return Overlay::Invalid; +} +Overlay::OverlayType Overlay::GetTypeAsEnum() const +{ + return GetOverlayTypeFromString( GetType() ); +} + +void Overlay::SetOrigin(const signed short origin[2]) +{ + if( origin ) + { + Internal->Origin[0] = origin[0]; + Internal->Origin[1] = origin[1]; + } +} +const signed short * Overlay::GetOrigin() const +{ + return &Internal->Origin[0]; +} +void Overlay::SetFrameOrigin(unsigned short frameorigin) { Internal->FrameOrigin = frameorigin; } +void Overlay::SetBitsAllocated(unsigned short bitsallocated) { Internal->BitsAllocated = bitsallocated; } +unsigned short Overlay::GetBitsAllocated() const { return Internal->BitsAllocated; } +void Overlay::SetBitPosition(unsigned short bitposition) { Internal->BitPosition = bitposition; } +unsigned short Overlay::GetBitPosition() const { return Internal->BitPosition; } + +bool Overlay::IsEmpty() const +{ + return Internal->Data.empty(); +} +bool Overlay::IsZero() const +{ + if( IsEmpty() ) return false; + + std::vector::const_iterator it = Internal->Data.begin(); + for(; it != Internal->Data.end(); ++it ) + { + if( *it ) return true; + } + return false; +} +bool Overlay::IsInPixelData() const { return Internal->InPixelData; } +void Overlay::IsInPixelData(bool b) { Internal->InPixelData = b; } + +/* + * row,col = 400,400 => 20000 + * row,col = 1665,1453 => 302406 + * row,col = 20,198 => 495 words + 1 dicom \0 padding + */ +inline unsigned int compute_bit_and_dicom_padding(unsigned short rows, unsigned short columns) +{ + unsigned int word_padding = ( rows * columns + 7 ) / 8; // need to send full word (8bits at a time) + return word_padding + word_padding%2; // Cannot have odd length +} + +void Overlay::SetOverlay(const char *array, size_t length) +{ + if( !array || !length ) return; + const size_t computed_length = (Internal->Rows * Internal->Columns + 7) / 8; + Internal->Data.resize( computed_length ); // filled with 0 if length < computed_length + if( length < computed_length ) + { + gdcmWarningMacro( "Not enough data found in Overlay. Proceed with caution" ); + std::copy(array, array+length, Internal->Data.begin()); + } + else + { + // do not try to copy more than allocated: + // technically we may be missing the trailing DICOM padding (\0), but we have all the data needed anyway: + std::copy(array, array+computed_length, Internal->Data.begin()); + } + /* warning need to take into account padding to the next word (8bits) */ + //assert( length == compute_bit_and_dicom_padding(Internal->Rows, Internal->Columns) ); + assert( Internal->Data.size() == computed_length ); +} + +const ByteValue &Overlay::GetOverlayData() const +{ + static ByteValue bv; + bv = ByteValue( Internal->Data ); + return bv; +} + +size_t Overlay::GetUnpackBufferLength() const +{ + const size_t unpacklen = Internal->Rows * Internal->Columns; + return unpacklen; +} + +bool Overlay::GetUnpackBuffer(char *buffer, size_t len) const +{ + const size_t unpacklen = GetUnpackBufferLength(); + if( len < unpacklen ) return false; + unsigned char *unpackedbytes = (unsigned char*)buffer; + const unsigned char *begin = unpackedbytes; + for( std::vector::const_iterator it = Internal->Data.begin(); it != Internal->Data.end(); ++it ) + { + assert( unpackedbytes <= begin + len ); // We never store more than actually required + // const unsigned char &packedbytes = *it; + // weird bug with gcc 3.3 (prerelease on SuSE) apparently: + unsigned char packedbytes = static_cast(*it); + unsigned char mask = 1; + for (unsigned int i = 0; i < 8 && unpackedbytes < begin + len; ++i) + { + if ( (packedbytes & mask) == 0) + { + *unpackedbytes = 0; + } + else + { + *unpackedbytes = 255; + } + ++unpackedbytes; + mask <<= 1; + } + } + assert(unpackedbytes <= begin + len); + return true; +} + +void Overlay::Decompress(std::ostream &os) const +{ + const size_t unpacklen = GetUnpackBufferLength(); + unsigned char unpackedbytes[8]; + //std::vector::const_iterator beg = Internal->Data.begin(); + size_t curlen = 0; + for( std::vector::const_iterator it = Internal->Data.begin(); it != Internal->Data.end(); ++it ) + { + unsigned char packedbytes = *it; + unsigned char mask = 1; + unsigned int i = 0; + for (; i < 8 && curlen < unpacklen; ++i) + { + if ( (packedbytes & mask) == 0) + { + unpackedbytes[i] = 0; + } + else + { + unpackedbytes[i] = 255; + } + mask <<= 1; + ++curlen; + } + os.write(reinterpret_cast(unpackedbytes), i); + } +} + +void Overlay::Print(std::ostream &os) const +{ + Internal->Print( os ); +} + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmOverlay.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmOverlay.h new file mode 100644 index 0000000..19623c4 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmOverlay.h @@ -0,0 +1,134 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMOVERLAY_H +#define GDCMOVERLAY_H + +#include "gdcmTypes.h" +#include "gdcmObject.h" + +namespace gdcm +{ + +class OverlayInternal; +class ByteValue; +class DataSet; +class DataElement; +/** + * \brief Overlay class + * \note + * see AreOverlaysInPixelData + * + * \todo + * Is there actually any way to recognize an overlay ? On images with multiple overlay I do not see + * any way to differenciate them (other than the group tag). + * + * Example: + */ +class GDCM_EXPORT Overlay : public Object +{ +public: + Overlay(); + ~Overlay(); + /// Print + void Print(std::ostream &) const; + + /// Update overlay from data element de: + void Update(const DataElement & de); + + /// Set Group number + void SetGroup(unsigned short group); + /// Get Group number + unsigned short GetGroup() const; + /// set rows + void SetRows(unsigned short rows); + /// get rows + unsigned short GetRows() const; + /// set columns + void SetColumns(unsigned short columns); + /// get columns + unsigned short GetColumns() const; + /// set number of frames + void SetNumberOfFrames(unsigned int numberofframes); + /// set description + void SetDescription(const char* description); + /// get description + const char *GetDescription() const; + typedef enum { + Invalid = 0, + Graphics = 1, + ROI = 2 + } OverlayType; + /// set type + void SetType(const char* type); + /// get type + const char *GetType() const; + OverlayType GetTypeAsEnum() const; + static const char *GetOverlayTypeAsString(OverlayType ot); + static OverlayType GetOverlayTypeFromString(const char *); + /// set origin + void SetOrigin(const signed short origin[2]); + /// get origin + const signed short * GetOrigin() const; + /// set frame origin + void SetFrameOrigin(unsigned short frameorigin); + /// set bits allocated + void SetBitsAllocated(unsigned short bitsallocated); + /// return bits allocated + unsigned short GetBitsAllocated() const; + /// set bit position + void SetBitPosition(unsigned short bitposition); + /// return bit position + unsigned short GetBitPosition() const; + + /// set overlay from byte array + length + void SetOverlay(const char *array, size_t length); + /// + bool GrabOverlayFromPixelData(DataSet const &ds); + + /// Return the Overlay Data as ByteValue: + /// Not thread safe + const ByteValue &GetOverlayData() const; + + /// Return whether or not the Overlay is empty: + bool IsEmpty() const; + + /// return true if all bits are set to 0 + bool IsZero() const; + + /// return if the Overlay is stored in the pixel data or not + bool IsInPixelData() const; + + /// Set wether or no the OverlayData is in the Pixel Data: + void IsInPixelData(bool b); + + /// Decode the internal OverlayData (packed bits) into unpacked representation + void Decompress(std::ostream &os) const; + + /// Retrieve the size of the buffer needed to hold the Overlay + /// as specified by Col & Row parameters + size_t GetUnpackBufferLength() const; + + /// Retrieve the unpack buffer for Overlay. This is an error if + /// the size if below GetUnpackBufferLength() + bool GetUnpackBuffer(char *buffer, size_t len) const; + + Overlay(Overlay const &ov); + +private: + OverlayInternal *Internal; +}; + +} // end namespace gdcm + +#endif //GDCMOVERLAY_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmPDFCodec.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmPDFCodec.cxx new file mode 100644 index 0000000..f14175e --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmPDFCodec.cxx @@ -0,0 +1,34 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmPDFCodec.h" +#include "gdcmDataElement.h" + +namespace gdcm +{ + +PDFCodec::PDFCodec() +{ +} + +PDFCodec::~PDFCodec() +{ +} + +bool PDFCodec::Decode(DataElement const &is, DataElement &os) +{ + os = is; + return true; +} + +} diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmPDFCodec.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmPDFCodec.h new file mode 100644 index 0000000..56b9217 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmPDFCodec.h @@ -0,0 +1,37 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMPDFCODEC_H +#define GDCMPDFCODEC_H + +#include "gdcmCodec.h" + +namespace gdcm +{ + +/** + * \brief PDFCodec class + */ +class GDCM_EXPORT PDFCodec : public Codec +{ +public: + PDFCodec(); + ~PDFCodec(); + bool CanCode(TransferSyntax const &) const { return false; } + bool CanDecode(TransferSyntax const &) const { return false; } + bool Decode(DataElement const &is, DataElement &os); +}; + +} // end namespace gdcm + +#endif //GDCMPDFCODEC_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmPGXCodec.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmPGXCodec.cxx new file mode 100644 index 0000000..e294764 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmPGXCodec.cxx @@ -0,0 +1,108 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmPGXCodec.h" +#include "gdcmTransferSyntax.h" +#include "gdcmSystem.h" +#include "gdcmDataElement.h" +#include "gdcmSequenceOfFragments.h" +#include "gdcmSwapper.h" +#include "gdcmFilenameGenerator.h" + +namespace gdcm +{ + +PGXCodec::PGXCodec() +{ +} + +PGXCodec::~PGXCodec() +{ +} + +bool PGXCodec::CanDecode(TransferSyntax const &) const +{ + return false; +} + +bool PGXCodec::CanCode(TransferSyntax const &) const +{ + return false; +} + +bool PGXCodec::Write(const char *filename, const DataElement &out) const +{ + if( !filename ) return false; + //const PhotometricInterpretation &pi = this->GetPhotometricInterpretation(); + std::vector filenames; + const PixelFormat& pf = GetPixelFormat(); + unsigned short nsamples = pf.GetSamplesPerPixel(); + FilenameGenerator fg; + std::string base = filename; + std::string::size_type dot_pos = base.size() - 4; + std::string prefix = base.substr(0, dot_pos ); + fg.SetPrefix( prefix.c_str() ); + fg.SetPattern( "_%d.pgx" ); + size_t zdim = Dimensions[2]; + size_t num_images = zdim * nsamples; + fg.SetNumberOfFilenames(num_images); + if( !fg.Generate() ) return false; + const gdcm::ByteValue *bv = out.GetByteValue(); + if(!bv) + { + gdcmErrorMacro( "PGX Codec does not handle compress syntax." + "You need to decompress first." ); + return false; + } + const unsigned int *dims = this->GetDimensions(); + size_t image_size = dims[0] * dims[1]; + const char *img_buffer = bv->GetPointer(); + + for( unsigned int i = 0; i < num_images; ++i, img_buffer += image_size ) + { + const char *targetname = fg.GetFilename( i ); + + std::ofstream os( targetname, std::ios::binary ); + os << "PG ML "; + os << (pf.GetPixelRepresentation() ? "-" : "+"); + os << " "; + os << pf.GetBitsStored(); + os << " "; + os << dims[0] << " " << dims[1] << "\n"; + os.write( img_buffer, image_size ); + os.close(); + } + + return true; +} + +bool PGXCodec::Read(const char *filename, DataElement &out) const +{ + (void)filename; + (void)out; + return false; +} + +bool PGXCodec::GetHeaderInfo(std::istream &is, TransferSyntax &ts) +{ + (void)is; + (void)ts; + return false; +} + +ImageCodec * PGXCodec::Clone() const +{ + return NULL; +} + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmPGXCodec.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmPGXCodec.h new file mode 100644 index 0000000..f337b4e --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmPGXCodec.h @@ -0,0 +1,44 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMPGXCODEC_H +#define GDCMPGXCODEC_H + +#include "gdcmImageCodec.h" + +namespace gdcm +{ + +/** + * \brief Class to do PGX + * See PGX as used in JPEG 2000 implementation and reference images + */ +class GDCM_EXPORT PGXCodec : public ImageCodec +{ +public: + PGXCodec(); + ~PGXCodec(); + bool CanDecode(TransferSyntax const &ts) const; + bool CanCode(TransferSyntax const &ts) const; + + bool GetHeaderInfo(std::istream &is, TransferSyntax &ts); + virtual ImageCodec * Clone() const; + + bool Read(const char *filename, DataElement &out) const; + bool Write(const char *filename, const DataElement &out) const; +private: +}; + +} // end namespace gdcm + +#endif //GDCMPGXCODEC_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmPNMCodec.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmPNMCodec.cxx new file mode 100644 index 0000000..5e11e10 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmPNMCodec.cxx @@ -0,0 +1,309 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmPNMCodec.h" +#include "gdcmTransferSyntax.h" +#include "gdcmSystem.h" +#include "gdcmDataElement.h" +#include "gdcmSequenceOfFragments.h" +#include "gdcmSwapper.h" + +namespace gdcm +{ + +PNMCodec::PNMCodec():BufferLength(0) +{ +} + +PNMCodec::~PNMCodec() +{ +} + +bool PNMCodec::CanDecode(TransferSyntax const &) const +{ + return false; +} + +bool PNMCodec::CanCode(TransferSyntax const &) const +{ + return false; +} + + + +bool PNMCodec::Write(const char *filename, const DataElement &out) const +{ + std::ofstream os(filename, std::ios::binary); + const unsigned int *dims = this->GetDimensions(); + const PhotometricInterpretation &pi = this->GetPhotometricInterpretation(); + if( pi == PhotometricInterpretation::MONOCHROME2 + || pi == PhotometricInterpretation::MONOCHROME1 ) // warning viz will be surprising + { + os << "P5\n"; + } + else if( pi == PhotometricInterpretation::RGB + || pi == PhotometricInterpretation::PALETTE_COLOR ) + { + os << "P6\n"; + } + else + { + gdcmErrorMacro( "PhotometricInterpretation unhandled: " << pi ); + return false; + } + os << dims[0] << " " << dims[1] << "\n"; + + const unsigned int pc = this->GetPlanarConfiguration(); + if( pc ) + { + gdcmErrorMacro( "PlanarConfiguration unhandled: " << pc ); + return false; + } + + const PixelFormat& pf = GetPixelFormat(); + switch(pf) + { + case PixelFormat::UINT8: + //case PixelFormat::INT8: + os << "255"; + break; + case PixelFormat::UINT16: + //case PixelFormat::INT16: + os << "65535"; + break; + default: + gdcmErrorMacro( "Unhandled PF: " << pf ); + return false; + } + os << "\n"; + + const gdcm::ByteValue *bv = out.GetByteValue(); + // FIXME: PNM Codec cannot handle encapsulated syntax... sigh + if(!bv) + { + gdcmErrorMacro( "PNM Codec does not handle compress syntax. You need to decompress first." ); + return false; + } + assert(bv); + + if( pi == PhotometricInterpretation::PALETTE_COLOR ) + { + std::stringstream is; + is.write( bv->GetPointer(), bv->GetLength() ); + + const gdcm::LookupTable &lut = this->GetLUT(); + lut.Decode(is, os); + } + else + { + if( pf.GetBitsAllocated() == 16 ) + { + bv->Write( os ); + } + else + { + //bv->Write( os ); + bv->WriteBuffer( os ); + } + } + + os.close(); + + + return true; +} + +bool PNMCodec::Read(const char *filename, DataElement &out) const +{ + size_t len = gdcm::System::FileSize(filename); + std::ifstream is(filename, std::ios::binary); + std::string type, str; + std::getline(is,type); + gdcm::PhotometricInterpretation pi; + if( type == "P5" ) + pi = gdcm::PhotometricInterpretation::MONOCHROME2; + else if( type == "P6" ) + pi = gdcm::PhotometricInterpretation::RGB; + else + { + std::cerr << "Unhandled PGM type: " << type << std::endl; + return false; + } + + // skip comments: + while( is.peek() == '#' ) + { + std::getline(is, str); + //std::cout << str << std::endl; + } + unsigned int dims[3] = {}; + is >> dims[0]; is >> dims[1]; + unsigned int maxval; + is >> maxval; + // some kind of empty line... + if( is.peek() == '\n' ) + { + is.get(); + } + std::streampos pos = is.tellg(); + //assert(pos < INT_MAX); + size_t m = (len - (size_t)pos ) / ( dims[0]*dims[1] ); + if( m * dims[0] * dims[1] != len - pos ) + { + std::cerr << "Problem computing length" << std::endl; + return false; + } + gdcm::PixelFormat pf; + switch(maxval) + { + case 255: + pf = gdcm::PixelFormat::UINT8; + break; + case 1023: + pf = gdcm::PixelFormat::UINT16; + pf.SetBitsStored( 10 ); + break; + case 4095: + pf = gdcm::PixelFormat::UINT16; + pf.SetBitsStored( 12 ); + break; + case 32767: + pf = gdcm::PixelFormat::UINT16; + pf.SetBitsStored( 15 ); + break; + case 65535: + pf = gdcm::PixelFormat::UINT16; + break; + default: + std::cerr << "Unhandled max val: " << maxval << std::endl; + return false; + } + if( pi == gdcm::PhotometricInterpretation::RGB ) + { + pf.SetSamplesPerPixel( 3 ); + } + //if ( maxval * 8 != bpp ) return 1; + + size_t pdlen = GetBufferLength(); + assert( pdlen ); + char * buf = new char[pdlen]; + // is should be at right offset, just read! + is.read(buf, len); + if( !is.eof() ) return false; + + out.SetTag( gdcm::Tag(0x7fe0,0x0010) ); + VL::Type pdLenSize = (VL::Type)pdlen; + out.SetByteValue( buf, pdLenSize ); + delete[] buf; + + is.close(); + + return true; +} + +bool PNMCodec::GetHeaderInfo(std::istream &is, TransferSyntax &ts) +{ + is.seekg( 0, std::ios::end ); + std::streampos len = is.tellg(); + //assert(len < INT_MAX); + is.seekg( 0, std::ios::beg ); + + std::string type, str; + std::getline(is,type); + gdcm::PhotometricInterpretation pi; + if( type == "P5" ) + pi = gdcm::PhotometricInterpretation::MONOCHROME2; + else if( type == "P6" ) // P3 => ASCII + pi = gdcm::PhotometricInterpretation::RGB; + else + { + std::cerr << "Unhandled PGM type: " << type << std::endl; + return false; + } + + // skip comments: + while( is.peek() == '#' ) + { + std::getline(is, str); + //std::cout << str << std::endl; + } + unsigned int dims[3] = {}; + is >> dims[0]; is >> dims[1]; + unsigned int maxval; + is >> maxval; + // http://netpbm.sourceforge.net/doc/pgm.html + // some kind of empty line... + if( is.peek() == '\n' ) + { + is.get(); + } + std::streamoff pos = is.tellg(); + //assert(len < INT_MAX); + //assert(pos < INT_MAX); + size_t m = ((size_t)len - (size_t)pos ) / ( dims[0]*dims[1] ); + if( m * dims[0] * dims[1] != (size_t)len - pos ) + { + std::cerr << "Problem computing length" << std::endl; + std::cerr << "Pos: " << len - pos << std::endl; + std::cerr << "expected: " << m * dims[0] * dims[1] << std::endl; + return false; + } + gdcm::PixelFormat pf; + switch(maxval) + { + case 255: + pf = gdcm::PixelFormat::UINT8; + break; + case 1023: + pf = gdcm::PixelFormat::UINT16; + pf.SetBitsStored( 10 ); + break; + case 4095: + pf = gdcm::PixelFormat::UINT16; + pf.SetBitsStored( 12 ); + break; + case 32767: + pf = gdcm::PixelFormat::UINT16; + pf.SetBitsStored( 15 ); + break; + case 65535: + pf = gdcm::PixelFormat::UINT16; + break; + default: + std::cerr << "Unhandled max val: " << maxval << std::endl; + return false; + } + if( pi == gdcm::PhotometricInterpretation::RGB ) + { + pf.SetSamplesPerPixel( 3 ); + } + //if ( maxval * 8 != bpp ) return 1; + + //image.SetTransferSyntax( gdcm::TransferSyntax::ExplicitVRBigEndian ); // PGM are big endian + //image.SetTransferSyntax( gdcm::TransferSyntax::ExplicitVRLittleEndian ); // PGM are big endian + //image.SetTransferSyntax( gdcm::TransferSyntax::ImplicitVRBigEndianPrivateGE ); // PGM are big endian + ts = gdcm::TransferSyntax::ImplicitVRBigEndianPrivateGE; + + SetPhotometricInterpretation( pi ); + SetPixelFormat( pf ); + SetDimensions( dims ); + + return true; +} + +ImageCodec * PNMCodec::Clone() const +{ + return NULL; +} + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmPNMCodec.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmPNMCodec.h new file mode 100644 index 0000000..fb8f445 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmPNMCodec.h @@ -0,0 +1,52 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMPNMCODEC_H +#define GDCMPNMCODEC_H + +#include "gdcmImageCodec.h" + +namespace gdcm +{ + +/** + * \brief Class to do PNM + * PNM is the Portable anymap file format. The main web page can be found at: + * http://netpbm.sourceforge.net/ + * \note + * Only support P5 & P6 PNM file (binary grayscale and binary rgb) + */ +class GDCM_EXPORT PNMCodec : public ImageCodec +{ +public: + PNMCodec(); + ~PNMCodec(); + bool CanDecode(TransferSyntax const &ts) const; + bool CanCode(TransferSyntax const &ts) const; + + unsigned long GetBufferLength() const { return BufferLength; } + void SetBufferLength(unsigned long l) { BufferLength = l; } + + bool GetHeaderInfo(std::istream &is, TransferSyntax &ts); + virtual ImageCodec * Clone() const; + + bool Read(const char *filename, DataElement &out) const; + bool Write(const char *filename, const DataElement &out) const; + //bool Write(const char *filename); +private: + unsigned long BufferLength; +}; + +} // end namespace gdcm + +#endif //GDCMPNMCODEC_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmPVRGCodec.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmPVRGCodec.cxx new file mode 100644 index 0000000..e5e463b --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmPVRGCodec.cxx @@ -0,0 +1,219 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmPVRGCodec.h" +#include "gdcmTransferSyntax.h" +#include "gdcmDataElement.h" +#include "gdcmFilename.h" +#include "gdcmSystem.h" +#include "gdcmSequenceOfFragments.h" +#include "gdcmPNMCodec.h" +#include "gdcmByteSwap.txx" + +namespace gdcm +{ +/* +http://groups.google.com/group/comp.compression/browse_thread/thread/e2e20d85a436cfa5 +*/ + +PVRGCodec::PVRGCodec() +{ + NeedByteSwap = true; +} + +PVRGCodec::~PVRGCodec() +{ +} + +bool PVRGCodec::CanDecode(TransferSyntax const &ts) const +{ +#ifndef GDCM_USE_PVRG + (void)ts; + return false; +#else + return ts == TransferSyntax::JPEGBaselineProcess1 + || ts == TransferSyntax::JPEGExtendedProcess2_4 + || ts == TransferSyntax::JPEGExtendedProcess3_5 + || ts == TransferSyntax::JPEGSpectralSelectionProcess6_8 + || ts == TransferSyntax::JPEGFullProgressionProcess10_12 + || ts == TransferSyntax::JPEGLosslessProcess14 + || ts == TransferSyntax::JPEGLosslessProcess14_1; +#endif +} + +bool PVRGCodec::CanCode(TransferSyntax const &) const +{ + return false; +} + +/* PVRG command line is a bit tricky to use: + * + * ./bin/pvrg-jpeg -d -s jpeg.jpg -ci 0 out.raw + * + * means decompress input file: jpeg.jpg into out.raw + * warning the -ci is important otherwise JFIF is assumed + * and comp # is assumed to be 1... + * -u reduce verbosity + */ +bool PVRGCodec::Decode(DataElement const &in, DataElement &out) +{ +#ifndef GDCM_USE_PVRG + (void)in; + (void)out; + return false; +#else + // First thing create a jpegls file from the fragment: + const gdcm::SequenceOfFragments *sf = in.GetSequenceOfFragments(); + if(!sf) + { + gdcmDebugMacro( "Could not find SequenceOfFragments" ); + return false; + } + +#ifdef GDCM_USE_SYSTEM_PVRG + std::string pvrg_command = GDCM_PVRG_JPEG_EXECUTABLE; +#else + gdcm::Filename fn( System::GetCurrentProcessFileName() ); + std::string executable_path = fn.GetPath(); + + std::string pvrg_command = executable_path + "/gdcmjpeg"; +#endif + if( !System::FileExists( pvrg_command.c_str() ) ) + { + gdcmErrorMacro( "Could not find: " << pvrg_command ); + return false; + } + + // http://msdn.microsoft.com/en-us/library/hs3e7355.aspx + // -> check if tempnam needs the 'free' + char *input = tempnam(0, "gdcminpvrg"); + char *output = tempnam(0, "gdcmoutpvrg"); + if( !input || !output ) + { + //free(input); + //free(output); + return false; + } + + std::ofstream outfile(input, std::ios::binary); + sf->WriteBuffer(outfile); + outfile.close(); // flush ! + + // -u -> set Notify to 0 (less verbose) + //pvrg_command += " -ci 0 -d -u "; + pvrg_command += " -d -u "; + // ./bin/pvrgjpeg -d -s jpeg.jpg -ci 0 out.raw + pvrg_command += "-s "; + pvrg_command += input; + //pvrg_command += " -ci 0 "; + //pvrg_command += output; + + //std::cerr << pvrg_command << std::endl; + gdcmDebugMacro( pvrg_command ); + int ret = system(pvrg_command.c_str()); + //std::cerr << "system: " << ret << std::endl; + if( ret ) + { + gdcmErrorMacro( "Looks like pvrg gave up in input, with ret value: " << ret ); + return false; + } + + int numoutfile = GetPixelFormat().GetSamplesPerPixel(); + std::string wholebuf; + for( int file = 0; file < numoutfile; ++file ) + { + std::ostringstream os; + os << input; + os << "."; + os << file; // dont ask + const std::string altfile = os.str(); + const size_t len = gdcm::System::FileSize(altfile.c_str()); + if( !len ) + { + gdcmDebugMacro( "Output file was really empty: " << altfile ); + return false; + } + const char *rawfile = altfile.c_str(); + + gdcmDebugMacro( "Processing: " << rawfile ); + std::ifstream is(rawfile, std::ios::binary); + std::string buf; + buf.resize( len ); + is.read(&buf[0], len); + out.SetTag( gdcm::Tag(0x7fe0,0x0010) ); + + if ( PF.GetBitsAllocated() == 16 ) + { + ByteSwap::SwapRangeFromSwapCodeIntoSystem((uint16_t*) + &buf[0], +#ifdef GDCM_WORDS_BIGENDIAN + SwapCode::LittleEndian, +#else + SwapCode::BigEndian, +#endif + len/2); + } + wholebuf.insert( wholebuf.end(), buf.begin(), buf.end() ); + if( !System::RemoveFile(rawfile) ) + { + gdcmErrorMacro( "Could not delete output: " << rawfile); + } + } + out.SetByteValue( &wholebuf[0], (uint32_t)wholebuf.size() ); + if( numoutfile == 3 ) + { + this->PlanarConfiguration = 1; + } + + if( !System::RemoveFile(input) ) + { + gdcmErrorMacro( "Could not delete input: " << input ); + } + + free(input); + free(output); + + // FIXME: + LossyFlag = true; + + //return ImageCodec::Decode(in,out); + return true; +#endif +} + +void PVRGCodec::SetLossyFlag( bool l ) +{ + LossyFlag = l; +} + +// Compress into JPEG +bool PVRGCodec::Code(DataElement const &in, DataElement &out) +{ +#ifndef GDCM_USE_PVRG + (void)in; + (void)out; + return false; +#else + (void)in; + (void)out; + /* Do I really want to produce JPEG by PVRG ? Shouldn't IJG handle all cases nicely ? */ + return false; +#endif +} + +ImageCodec * PVRGCodec::Clone() const +{ + return NULL; +} + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmPVRGCodec.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmPVRGCodec.h new file mode 100644 index 0000000..bb4b991 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmPVRGCodec.h @@ -0,0 +1,52 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMPVRGCODEC_H +#define GDCMPVRGCODEC_H + +#include "gdcmImageCodec.h" + +namespace gdcm +{ + +/** + * \brief PVRGCodec + * \note pvrg is a broken implementation of the JPEG standard. It is known to + * have a bug in the 16bits lossless implementation of the standard. + * + * In an ideal world, you should not need this codec at all. But to support + * some broken file such as: + * + * PHILIPS_Gyroscan-12-Jpeg_Extended_Process_2_4.dcm + * + * we have to... + */ +class PVRGCodec : public ImageCodec +{ +public: + PVRGCodec(); + ~PVRGCodec(); + bool CanDecode(TransferSyntax const &ts) const; + bool CanCode(TransferSyntax const &ts) const; + + bool Decode(DataElement const &is, DataElement &os); + bool Code(DataElement const &in, DataElement &out); + void SetLossyFlag( bool l ); + + virtual ImageCodec * Clone() const; +private: +}; + +} // end namespace gdcm + +#endif //GDCMPVRGCODEC_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmPersonName.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmPersonName.cxx new file mode 100644 index 0000000..2363700 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmPersonName.cxx @@ -0,0 +1,18 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#include "gdcmPersonName.h" + +namespace gdcm +{} diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmPersonName.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmPersonName.h new file mode 100644 index 0000000..6a18a65 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmPersonName.h @@ -0,0 +1,83 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#ifndef GDCMPERSONNAME_H +#define GDCMPERSONNAME_H + +#include "gdcmTypes.h" +#include +#include // std::min +#include // strlen + +namespace gdcm +{ + +/** + * \brief PersonName class + */ +class GDCM_EXPORT PersonName +{ +public: + static const unsigned int MaxNumberOfComponents = 5; + static const unsigned int MaxLength = 64; + char Component[MaxNumberOfComponents][MaxLength+1]; + static const char Separator = '^'; + static const char Padding = ' '; + + unsigned int GetNumberOfComponents() const { + unsigned int r = 0; + for(unsigned int i = 0; i < 5; ++i) { + if( *Component[i] != '\0' ) r = i; + } + return r+1; + } + unsigned int GetMaxLength() const { return MaxLength; }; + void SetBlob(const std::vector& v) { + (void)v; + //assert(0); //TODO + } + void SetComponents(const char *comp1 = "", + const char *comp2 = "", + const char *comp3 = "", + const char *comp4 = "", + const char *comp5 = "") { + const char *components[5] = { comp1, comp2, comp3, comp4, comp5 }; + SetComponents( components ); + } + void SetComponents(const char *components[]) { + for(unsigned int i = 0; i < 5; ++i) { + //strncpy(Component[i], components[i], std::min( (unsigned int)strlen(components[i]), GetMaxLength() ) ); + assert( strlen(components[i]) < GetMaxLength() ); + strcpy(Component[i], components[i]); + assert( strlen(Component[i]) < GetMaxLength() ); + } + } + void Print(std::ostream &os) const + { + //os << "Family Name Complex: " << Component[0] << std::endl; + //os << "Given Name Complex: " << Component[1] << std::endl; + //os << "Middle Name : " << Component[2] << std::endl; + //os << "Name Suffix : " << Component[3] << std::endl; + //os << "Name Prefix : " << Component[4] << std::endl; + os << Component[0] << '^'; + os << Component[1] << '^'; + os << Component[2] << '^'; + os << Component[3] << '^'; + os << Component[4]; + } +}; + +} // end namespace gdcm + +#endif //GDCMPERSONNAME_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmPhotometricInterpretation.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmPhotometricInterpretation.cxx new file mode 100644 index 0000000..e47bb66 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmPhotometricInterpretation.cxx @@ -0,0 +1,215 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmPhotometricInterpretation.h" +#include "gdcmTransferSyntax.h" +#include "gdcmTrace.h" +#include "gdcmCodeString.h" +#include "gdcmVR.h" + +#include +#include +#include + +namespace gdcm +{ +/* + * HSV/ARGB/CMYK can still be found in PS 3.3 - 2000: + * + * HSV = Pixel data represent a color image described by hue, saturation, and value image planes. + * The minimum sample value for each HSV plane represents a minimum value of each vector. This + * value may be used only when Samples per Pixel (0028,0002) has a value of 3. + * + * ARGB = Pixel data represent a color image described by red, green, blue, and alpha image planes. + * The minimum sample value for each RGB plane represents minimum intensity of the color. The + * alpha plane is passed through Palette Color Lookup Tables. If the alpha pixel value is greater than + * 0, the red, green, and blue lookup table values override the red, green, and blue, pixel plane colors. + * This value may be used only when Samples per Pixel (0028,0002) has a value of 4. + * + * CMYK = Pixel data represent a color image described by cyan, magenta, yellow, and black image + * planes. The minimum sample value for each CMYK plane represents a minimum intensity of the + * color. This value may be used only when Samples per Pixel (0028,0002) has a value of 4. + * + */ + +static const char *PIStrings[] = { + "UNKNOW", + "MONOCHROME1 ", + "MONOCHROME2 ", + "PALETTE COLOR ", + "RGB ", + "HSV ", + "ARGB", + "CMYK", + "YBR_FULL", + "YBR_FULL_422", + "YBR_PARTIAL_422 ", + "YBR_PARTIAL_420 ", + "YBR_ICT ", + "YBR_RCT ", + 0 +}; + +const char *PhotometricInterpretation::GetPIString(PIType pi) +{ + //assert( pi < PhotometricInterpretation::PI_END ); + return PIStrings[pi]; +} + +PhotometricInterpretation::PIType PhotometricInterpretation::GetPIType(const char *inputpi) +{ + if( !inputpi ) return PI_END; + + // The following code allows use to handle whitespace and invalid padding: + CodeString codestring = inputpi; + CSComp cs = codestring.GetAsString(); + const char *pi = cs.c_str(); + for( unsigned int i = 1; PIStrings[i] != 0; ++i ) + { + if( strcmp(pi, PIStrings[i]) == 0 ) + { + return PIType(i); + } + } + + // Ouch ! We did not find anything, that's pretty bad, let's hope that + // the toolkit which wrote the image is buggy and tolerate \0 padded ASCII + // string + // warning this piece of code will do MONOCHROME -> MONOCHROME1 + static const unsigned int n = sizeof(PIStrings) / sizeof(*PIStrings) - 1; + + size_t len = strlen(pi); + if( pi[len-1] == ' ' ) len--; + + for( unsigned int i = 1; i < n; ++i ) + { + if( strncmp(pi, PIStrings[i], len ) == 0 ) + { + gdcmDebugMacro( "PhotometricInterpretation was found: [" << pi + << "], but is invalid. It should be padded with a space" ); + return PIType(i); + } + } + //assert(0); + return PI_END; +} + +bool PhotometricInterpretation::IsRetired(PIType pi) +{ + return pi == HSV || pi == ARGB || pi == CMYK; +} + +unsigned short PhotometricInterpretation::GetSamplesPerPixel() const +{ + if ( PIField == UNKNOW ) return 0; + else if( PIField == MONOCHROME1 + || PIField == MONOCHROME2 + || PIField == PALETTE_COLOR ) + { + return 1; + } + else if( PIField == ARGB || PIField == CMYK ) + { + return 4; + } + else + { + assert( PIField != PI_END ); + assert( //PIField == PALETTE_COLOR + PIField == RGB + || PIField == HSV + //|| PIField == ARGB + //|| PIField == CMYK + || PIField == YBR_FULL + || PIField == YBR_FULL_422 + || PIField == YBR_PARTIAL_422 + || PIField == YBR_PARTIAL_420 + || PIField == YBR_ICT + || PIField == YBR_RCT + ); + return 3; + } +} + +bool PhotometricInterpretation::IsLossy() const +{ + return !IsLossless(); +} + +bool PhotometricInterpretation::IsLossless() const +{ + switch ( PIField ) + { + case MONOCHROME1: + case MONOCHROME2: + case PALETTE_COLOR: + case RGB: + case HSV: + case ARGB: + case CMYK: + case YBR_FULL: + case YBR_RCT: + return true; + break; + case YBR_FULL_422: + case YBR_PARTIAL_422: + case YBR_PARTIAL_420: + case YBR_ICT: + return false; + break; + default: + assert(0); + return false; + } + + assert( 0 ); // technically one should not reach here, unless UNKNOW ... + return false; +} + +const char *PhotometricInterpretation::GetString() const +{ + return PhotometricInterpretation::GetPIString( PIField ); +} + +bool PhotometricInterpretation::IsSameColorSpace( PhotometricInterpretation const &pi ) const +{ + if( PIField == pi ) return true; + + // else + if( PIField == RGB + || PIField == YBR_RCT + || PIField == YBR_ICT ) + { + if( pi == RGB || pi == YBR_RCT || pi == YBR_ICT ) return true; + } + + if( PIField == YBR_FULL + || PIField == YBR_FULL_422 ) + { + if( pi == YBR_FULL || pi == YBR_FULL_422 ) return true; + } + + return false; +} + +//PhotometricInterpretation::PIType PhotometricInterpretation::GetEquivalent(TransferSyntax const &ts) +//{ +// // A.8.5.4 Multi-frame True Color SC Image IOD Content Constraints +// if( PIField == RGB ) +// { +// if( ts == gdcm::TransferSyntax:: +// } +// return PIField; +//} +// +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmPhotometricInterpretation.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmPhotometricInterpretation.h new file mode 100644 index 0000000..3e0526e --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmPhotometricInterpretation.h @@ -0,0 +1,100 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#ifndef GDCMPHOTOMETRICINTERPRETATION_H +#define GDCMPHOTOMETRICINTERPRETATION_H + +#include "gdcmTypes.h" +#include + +namespace gdcm +{ + +class TransferSyntax; +/** + * \brief Class to represent an PhotometricInterpretation + */ +class GDCM_EXPORT PhotometricInterpretation +{ +public: + typedef enum { + UNKNOW = 0, + MONOCHROME1, + MONOCHROME2, + PALETTE_COLOR, + RGB, + HSV, + ARGB, // retired + CMYK, + YBR_FULL, + YBR_FULL_422, + YBR_PARTIAL_422, + YBR_PARTIAL_420, + YBR_ICT, + YBR_RCT, + // PALETTE_COLOR ? + //MONOCHROME = MONOCHROME1 | MONOCHROME2, + //COLOR = RGB | HSV | ARGB | CMYK | YBR_FULL | YBR_FULL_422 | YBR_PARTIAL_422 | YBR_PARTIAL_420 | YBR_ICT | YBR_RCT, + PI_END // Helpfull for internal implementation + } PIType; // PhotometricInterpretationType + + PhotometricInterpretation(PIType pi = UNKNOW):PIField(pi) {} + + static const char *GetPIString(PIType pi); + + const char *GetString() const; + + // You need to make sure end of string is \0 + static PIType GetPIType(const char *pi); + + static bool IsRetired(PIType pi); + + bool IsLossy() const; + bool IsLossless() const; + + /// return the value for Sample Per Pixel associated with a particular Photometric Interpretation + unsigned short GetSamplesPerPixel() const; + + // TODO + // not all PhotometricInterpretation are allowed for compressed Transfer + // syntax + // static bool IsAllowedForCompressedTS(PIType pi); + + friend std::ostream& operator<<(std::ostream& os, const PhotometricInterpretation& pi); + + operator PIType () const { return PIField; } + + PIType GetType () const { return PIField; } + + // Will return whether current PhotometricInterpretation is the same Color Space as input: + // eg. RGB and YBR_RCT are + bool IsSameColorSpace( PhotometricInterpretation const &pi ) const; + + //static PIType GetEquivalent(TransferSyntax const &ts); + +private: + PIType PIField; +}; +//----------------------------------------------------------------------------- +inline std::ostream& operator<<(std::ostream& os, const PhotometricInterpretation &val) +{ + const char *s = PhotometricInterpretation::GetPIString(val.PIField); + os << (s ? s : ""); + return os; +} + + +} // end namespace gdcm + +#endif //GDCMPHOTOMETRICINTERPRETATION_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmPixelFormat.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmPixelFormat.cxx new file mode 100644 index 0000000..dc395c5 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmPixelFormat.cxx @@ -0,0 +1,313 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmPixelFormat.h" +#include "gdcmTrace.h" +#include + +namespace gdcm +{ +static const char *ScalarTypeStrings[] = { + "UINT8", + "INT8", + "UINT12", + "INT12", + "UINT16", + "INT16", + "UINT32", + "INT32", + "FLOAT16", + "FLOAT32", + "FLOAT64", + "SINGLEBIT", + NULL, +}; + +PixelFormat::PixelFormat(ScalarType st) +{ + SamplesPerPixel = 1; + SetScalarType( st ); +} + +unsigned short PixelFormat::GetSamplesPerPixel() const +{ + // \postcondition + assert( SamplesPerPixel == 1 || SamplesPerPixel == 3 || SamplesPerPixel == 4 ); + return SamplesPerPixel; +} + +void PixelFormat::SetScalarType(ScalarType st) +{ + SamplesPerPixel = 1; + switch(st) + { + case PixelFormat::UINT8: + BitsAllocated = 8; + PixelRepresentation = 0; + break; + case PixelFormat::INT8: + BitsAllocated = 8; + PixelRepresentation = 1; + break; + case PixelFormat::UINT12: + BitsAllocated = 12; + PixelRepresentation = 0; + break; + case PixelFormat::INT12: + BitsAllocated = 12; + PixelRepresentation = 1; + break; + case PixelFormat::UINT16: + BitsAllocated = 16; + PixelRepresentation = 0; + break; + case PixelFormat::INT16: + BitsAllocated = 16; + PixelRepresentation = 1; + break; + case PixelFormat::UINT32: + BitsAllocated = 32; + PixelRepresentation = 0; + break; + case PixelFormat::INT32: + BitsAllocated = 32; + PixelRepresentation = 1; + break; + case PixelFormat::FLOAT16: + BitsAllocated = 16; + // secret code: + PixelRepresentation = 2; + break; + case PixelFormat::FLOAT32: + BitsAllocated = 32; + // secret code: + PixelRepresentation = 3; + break; + case PixelFormat::FLOAT64: + BitsAllocated = 64; + // secret code: + PixelRepresentation = 4; + break; + case PixelFormat::SINGLEBIT: + BitsAllocated = 1; + PixelRepresentation = 0; + break; + case PixelFormat::UNKNOWN: + BitsAllocated = 0; + PixelRepresentation = 0; + break; + default: + assert(0); + break; + } + BitsStored = BitsAllocated; + HighBit = (uint16_t)(BitsStored - 1); +} + +PixelFormat::ScalarType PixelFormat::GetScalarType() const +{ + ScalarType type = PixelFormat::UNKNOWN; + switch( BitsAllocated ) + { + case 0: + type = PixelFormat::UNKNOWN; + break; + case 1: + type = PixelFormat::SINGLEBIT; + break; + case 8: + type = PixelFormat::UINT8; + break; + case 12: + type = PixelFormat::UINT12; + break; + case 16: + type = PixelFormat::UINT16; + break; + case 32: + type = PixelFormat::UINT32; + break; + case 64: + type = PixelFormat::UINT32; // why not ? + break; + case 24: + gdcmDebugMacro( "This is illegal in DICOM, assuming a RGB image" ); + type = PixelFormat::UINT8; + //assert(0); + break; + default: + gdcmErrorMacro( "I have never seen this before BitsAllocated " + << BitsAllocated ); + type = PixelFormat::UNKNOWN; + //assert(0); + } + if( type != PixelFormat::UNKNOWN ) + { + if( PixelRepresentation == 0 ) + { + // all set ! + } + else if( PixelRepresentation == 1 ) + { + assert( type <= INT32 ); + // That's why you need to order properly type in ScalarType + type = ScalarType(int(type)+1); + } + else if( PixelRepresentation == 2 ) + { + assert( BitsAllocated == 16 ); + return FLOAT16; + } + else if( PixelRepresentation == 3 ) + { + assert( BitsAllocated == 32 ); + return FLOAT32; + } + else if( PixelRepresentation == 4 ) + { + assert( BitsAllocated == 64 ); + return FLOAT64; + } + else + { + assert(0); + } + } + return type; +} + +const char *PixelFormat::GetScalarTypeAsString() const +{ + return ScalarTypeStrings[GetScalarType()]; +} + +uint8_t PixelFormat::GetPixelSize() const +{ + uint8_t pixelsize = (uint8_t)(BitsAllocated / 8); + if( BitsAllocated == 12 ) + { + pixelsize = 2; // fake a short value + } + else + { + assert( !(BitsAllocated % 8) ); + } + pixelsize *= SamplesPerPixel; + + return pixelsize; +} + +int64_t PixelFormat::GetMin() const +{ + assert( BitsAllocated ); // cannot be unknown + assert( BitsStored <= 32 ); + if( PixelRepresentation == 1 ) + { + return (int64_t)(~(((1ull << BitsStored) - 1) >> 1)); + } + else if( PixelRepresentation == 0 ) + { + return 0; + } + //else if( PixelRepresentation == 3 ) // 32bits float + // { + // return (float) -1.0e+38f; + // } + //else if( PixelRepresentation == 4 ) // 64bits float + // { + // return (double) -1.0e+299; + // } + else + { + assert(0); + } + return 0; +} + +int64_t PixelFormat::GetMax() const +{ + assert( BitsAllocated ); // cannot be unknown + assert( BitsStored <= 32 ); + if( PixelRepresentation == 1 ) + { + return (int64_t)(((1ull << BitsStored) - 1) >> 1); + } + else if( PixelRepresentation == 0 ) + { + return (int64_t)((1ull << BitsStored) - 1); + } + //else if( PixelRepresentation == 3 ) // 32bits float + // { + // return (float) 1.0e+38f; + // } + //else if( PixelRepresentation == 4 ) // 64bits float + // { + // return (double) 1.0e+299; + // } + else + { + assert(0); + } + return 0; +} + +bool PixelFormat::IsValid() const +{ + if( PixelRepresentation != 0 && PixelRepresentation != 1 ) + { + return false; + } + if( BitsAllocated < BitsStored ) return false; + if( BitsAllocated < HighBit ) return false; + return true; +} + +bool PixelFormat::Validate() +{ + if( !IsValid() ) return false; + //assert( BitsStored >= HighBit ); // DigitexAlpha_no_7FE0.dcm + assert( PixelRepresentation == 0 || PixelRepresentation == 1 ); + assert( SamplesPerPixel == 1 || SamplesPerPixel == 3 || SamplesPerPixel == 4 ); + if ( BitsStored == 0 ) + { + gdcmDebugMacro( "Bits Stored is 0. Setting is to max value" ); + BitsStored = BitsAllocated; + } + if ( BitsAllocated == 24 ) + { + gdcmDebugMacro( "ACR-NEMA way of storing RGB data. Updating" ); + if( BitsStored == 24 && HighBit == 23 && SamplesPerPixel == 1 ) + { + BitsAllocated = 8; + BitsStored = 8; + HighBit = 7; + SamplesPerPixel = 3; + return true; + } + // all other case, simply give up + return false; + } + return true; +} + +void PixelFormat::Print(std::ostream &os) const +{ + os << "SamplesPerPixel :" << SamplesPerPixel << "\n"; + os << "BitsAllocated :" << BitsAllocated << "\n"; + os << "BitsStored :" << BitsStored << "\n"; + os << "HighBit :" << HighBit << "\n"; + os << "PixelRepresentation:" << PixelRepresentation << "\n"; + os << "ScalarType found :" << GetScalarTypeAsString() << "\n"; +} + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmPixelFormat.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmPixelFormat.h new file mode 100644 index 0000000..e054917 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmPixelFormat.h @@ -0,0 +1,222 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#ifndef GDCMPIXELFORMAT_H +#define GDCMPIXELFORMAT_H + +#include "gdcmTypes.h" +#include +#include + +namespace gdcm +{ + +/** + * \brief PixelFormat + * \note + * By default the Pixel Type will be instanciated with the following + * parameters: + * - SamplesPerPixel : 1 + * - BitsAllocated : 8 + * - BitsStored : 8 + * - HighBit : 7 + * - PixelRepresentation : 0 + */ +class GDCM_EXPORT PixelFormat +{ + friend class Bitmap; + friend std::ostream& operator<<(std::ostream &_os, const PixelFormat &pf); +public: + // When adding a type please add its dual type (its unsigned conterpart) + typedef enum { + UINT8, + INT8, + UINT12, + INT12, + UINT16, + INT16, + UINT32, // For some DICOM files (RT or SC) + INT32, // " " + FLOAT16, // sure why not... + FLOAT32, // good ol' 'float' + FLOAT64, // aka 'double' + SINGLEBIT, // bool / monochrome + UNKNOWN // aka BitsAllocated == 0 && PixelRepresentation == 0 + } ScalarType; + + // default cstor: + explicit PixelFormat ( + unsigned short samplesperpixel = 1, + unsigned short bitsallocated = 8, + unsigned short bitsstored = 8, + unsigned short highbit = 7, + unsigned short pixelrepresentation = 0 ) : + SamplesPerPixel(samplesperpixel), + BitsAllocated(bitsallocated), + BitsStored(bitsstored), + HighBit(highbit), + PixelRepresentation(pixelrepresentation) {} + // helper, for the common case + PixelFormat(ScalarType st); + + // For transparency of use + operator ScalarType() const { return GetScalarType(); } + + /// Samples Per Pixel see (0028,0002) US Samples Per Pixel + /// DICOM - only allows 1, 3 and 4 as valid value. Other value are undefined behavior. + unsigned short GetSamplesPerPixel() const; + void SetSamplesPerPixel(unsigned short spp) + { + gdcmAssertMacro( spp <= 4 ); + SamplesPerPixel = spp; + assert( SamplesPerPixel == 1 || SamplesPerPixel == 3 || SamplesPerPixel == 4 ); + } + + /// BitsAllocated see Tag (0028,0100) US Bits Allocated + unsigned short GetBitsAllocated() const + { + return BitsAllocated; + } + void SetBitsAllocated(unsigned short ba) + { + if( ba ) + { + BitsAllocated = ba; + BitsStored = ba; + HighBit = (unsigned short)(ba - 1); + } + else // Make the PixelFormat as UNKNOWN + { + BitsAllocated = 0; + PixelRepresentation = 0; + } + } + + /// BitsStored see Tag (0028,0101) US Bits Stored + unsigned short GetBitsStored() const + { + assert( BitsStored <= BitsAllocated ); + return BitsStored; + } + void SetBitsStored(unsigned short bs) + { + if( bs <= BitsAllocated && bs ) + { + BitsStored = bs; + SetHighBit( (unsigned short) (bs - 1) ); + } + } + + /// HighBit see Tag (0028,0102) US High Bit + unsigned short GetHighBit() const + { + assert( HighBit < BitsStored ); + return HighBit; + } + void SetHighBit(unsigned short hb) + { + if( hb < BitsStored ) + HighBit = hb; + } + + /// PixelRepresentation: 0 or 1, see Tag (0028,0103) US Pixel Representation + unsigned short GetPixelRepresentation() const + { + return (unsigned short)(PixelRepresentation ? 1 : 0); + } + void SetPixelRepresentation(unsigned short pr) + { + PixelRepresentation = (unsigned short)(pr ? 1 : 0); + } + + /// ScalarType does not take into account the sample per pixel + ScalarType GetScalarType() const; + + /// Set PixelFormat based only on the ScalarType + /// \warning: You need to call SetScalarType *before* SetSamplesPerPixel + void SetScalarType(ScalarType st); + const char *GetScalarTypeAsString() const; + + /// return the size of the pixel + /// This is the number of words it would take to store one pixel + /// \warning the return value takes into account the SamplesPerPixel + /// \warning in the rare case when BitsAllocated == 12, the function + /// assume word padding and value returned will be identical as if BitsAllocated == 16 + uint8_t GetPixelSize() const; + + /// Print + void Print(std::ostream &os) const; + + /// return the min possible of the pixel + int64_t GetMin() const; + + /// return the max possible of the pixel + int64_t GetMax() const; + + /// return IsValid + bool IsValid() const; + + bool operator==(ScalarType st) const + { + return GetScalarType() == st; + } + bool operator!=(ScalarType st) const + { + return GetScalarType() != st; + } + bool operator==(const PixelFormat &pf) const + { + return + SamplesPerPixel == pf.SamplesPerPixel && + BitsAllocated == pf.BitsAllocated && + BitsStored == pf.BitsStored && + HighBit == pf.HighBit && + PixelRepresentation == pf.PixelRepresentation; + } + bool operator!=(const PixelFormat &pf) const + { + return + SamplesPerPixel != pf.SamplesPerPixel || + BitsAllocated != pf.BitsAllocated || + BitsStored != pf.BitsStored || + HighBit != pf.HighBit || + PixelRepresentation != pf.PixelRepresentation; + } + +protected: + /// When image with 24/24/23 was read, need to validate + bool Validate(); + +private: + // D 0028|0002 [US] [Samples per Pixel] [1] + unsigned short SamplesPerPixel; + // D 0028|0100 [US] [Bits Allocated] [8] + unsigned short BitsAllocated; + // D 0028|0101 [US] [Bits Stored] [8] + unsigned short BitsStored; + // D 0028|0102 [US] [High Bit] [7] + unsigned short HighBit; + // D 0028|0103 [US] [Pixel Representation] [0] + unsigned short PixelRepresentation; +}; +//----------------------------------------------------------------------------- +inline std::ostream& operator<<(std::ostream &os, const PixelFormat &pf) +{ + pf.Print( os ); + return os; +} + +} // end namespace gdcm + +#endif //GDCMPIXELFORMAT_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmPixmap.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmPixmap.cxx new file mode 100644 index 0000000..ffad6a5 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmPixmap.cxx @@ -0,0 +1,67 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmPixmap.h" + +namespace gdcm +{ +/* + * PICKER-16-MONO2-Nested_icon.dcm: +(0088,0200) SQ (Sequence with undefined length #=1) # u/l, 1 PixmapSequence + (fffe,e000) na (Item with undefined length #=10) # u/l, 1 Item + (0028,0002) US 1 # 2, 1 SamplesPerPixel + (0028,0004) CS [MONOCHROME2] # 12, 1 PhotometricInterpretation + (0028,0010) US 64 # 2, 1 Rows + (0028,0011) US 64 # 2, 1 Columns + (0028,0034) IS [1\1] # 4, 2 PixelAspectRatio + (0028,0100) US 8 # 2, 1 BitsAllocated + (0028,0101) US 8 # 2, 1 BitsStored + (0028,0102) US 7 # 2, 1 HighBit + (0028,0103) US 0 # 2, 1 PixelRepresentation + (7fe0,0010) OW 0000\0000\0000\0000\0000\0000\0000\0000\0000\0000\0000\0000\0000... # 4096, 1 PixelData + (fffe,e00d) na (ItemDelimitationItem) # 0, 0 ItemDelimitationItem +(fffe,e0dd) na (SequenceDelimitationItem) # 0, 0 SequenceDelimitationItem +*/ + +Pixmap::Pixmap():Overlays(),Curves(),Icon(new IconImage) {} + +Pixmap::~Pixmap() {} + +bool Pixmap::AreOverlaysInPixelData() const +{ + int total = 0; + std::vector::const_iterator it = Overlays.begin(); + for(; it != Overlays.end(); ++it) + { + total += (int)it->IsInPixelData(); + } + assert( total == (int)GetNumberOfOverlays() || !total ); + return total != 0; +} + +void Pixmap::Print(std::ostream &os) const +{ + Bitmap::Print(os); + for( std::vector::const_iterator it = Overlays.begin(); + it != Overlays.end(); ++it) + { + it->Print( os ); + } + for( std::vector::const_iterator it = Curves.begin(); + it != Curves.end(); ++it) + { + it->Print( os ); + } +} + +} diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmPixmap.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmPixmap.h new file mode 100644 index 0000000..96fb317 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmPixmap.h @@ -0,0 +1,84 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMPIXMAP_H +#define GDCMPIXMAP_H + +#include "gdcmBitmap.h" +#include "gdcmCurve.h" +#include "gdcmIconImage.h" +#include "gdcmOverlay.h" + +namespace gdcm +{ + +/** + * \brief Pixmap class + * A bitmap based image. Used as parent for both IconImage and the main Pixel Data Image + * It does not contains any World Space information (IPP, IOP) + * + * \see PixmapReader + */ +class GDCM_EXPORT Pixmap : public Bitmap +{ +public: + Pixmap(); + ~Pixmap(); + void Print(std::ostream &) const; + + /// returns if Overlays are stored in the unused bit of the pixel data: + bool AreOverlaysInPixelData() const; + + /// Curve: group 50xx + Curve& GetCurve(size_t i = 0) { + assert( i < Curves.size() ); + return Curves[i]; + } + const Curve& GetCurve(size_t i = 0) const { + assert( i < Curves.size() ); + return Curves[i]; + } + size_t GetNumberOfCurves() const { return Curves.size(); } + void SetNumberOfCurves(size_t n) { Curves.resize(n); } + + /// Overlay: group 60xx + Overlay& GetOverlay(size_t i = 0) { + assert( i < Overlays.size() ); + return Overlays[i]; + } + const Overlay& GetOverlay(size_t i = 0) const { + assert( i < Overlays.size() ); + return Overlays[i]; + } + size_t GetNumberOfOverlays() const { return Overlays.size(); } + void SetNumberOfOverlays(size_t n) { Overlays.resize(n); } + void RemoveOverlay(size_t i) { + assert( i < Overlays.size() ); + Overlays.erase( Overlays.begin() + i ); + } + + /// Set/Get Icon Image + const IconImage &GetIconImage() const { return *Icon; } + IconImage &GetIconImage() { return *Icon; } + void SetIconImage(IconImage const &ii) { Icon = ii; } + +//private: +protected: + std::vector Overlays; + std::vector Curves; + SmartPointer Icon; +}; + +} // end namespace gdcm + +#endif //GDCMPIXMAP_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmPixmapReader.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmPixmapReader.cxx new file mode 100644 index 0000000..3bcc797 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmPixmapReader.cxx @@ -0,0 +1,1307 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmPixmapReader.h" +#include "gdcmExplicitDataElement.h" +#include "gdcmImplicitDataElement.h" +#include "gdcmValue.h" +#include "gdcmFileMetaInformation.h" +#include "gdcmElement.h" +#include "gdcmPhotometricInterpretation.h" +#include "gdcmSegmentedPaletteColorLookupTable.h" +#include "gdcmTransferSyntax.h" +#include "gdcmLookupTable.h" +#include "gdcmAttribute.h" +#include "gdcmIconImage.h" +#include "gdcmPrivateTag.h" +#include "gdcmJPEGCodec.h" +#include "gdcmImageHelper.h" + +namespace gdcm +{ +PixmapReader::PixmapReader():PixelData(new Pixmap) +{ +} + +PixmapReader::~PixmapReader() +{ +} + +const Pixmap& PixmapReader::GetPixmap() const +{ + return *PixelData; +} +Pixmap& PixmapReader::GetPixmap() +{ + return *PixelData; +} + +//void PixmapReader::SetPixmap(Pixmap const &img) +//{ +// PixelData = img; +//} + + +bool PixmapReader::Read() +{ + if( !Reader::Read() ) + { + // cemra_bug/IM-0001-0066.dcm + // will return from the parser with an error + // but a partial Pixel Data can be seen + return false; + } + + const FileMetaInformation &header = F->GetHeader(); + const DataSet &ds = F->GetDataSet(); + const TransferSyntax &ts = header.GetDataSetTransferSyntax(); + + // Need to set the type of image we are dealing with: + PixelData->SetTransferSyntax( ts ); + + bool res = false; + /* Does it really make sense to check for Media Storage SOP Class UID? + * I need then to check consistency with 0008 0016 Instance SOP Class UID + * ... I don't think there is an end. + * I'd rather go the old way check a bunch of tags (From Image Plane + * Module). + */ + MediaStorage ms = header.GetMediaStorage(); + bool isImage = MediaStorage::IsImage( ms ); + if( isImage ) + { + // I cannot leave this here, since ELSCINT1 / LOSSLESS RICE declares CT Image Storage, + // when in fact this is a private Media Storage (no Pixel Data element) + //assert( ds.FindDataElement( Tag(0x7fe0,0x0010 ) ) ); + assert( ts != TransferSyntax::TS_END && ms != MediaStorage::MS_END ); + // Good it's the easy case. It's declared as an Image: + //PixelData->SetCompressionFromTransferSyntax( ts ); + res = ReadImage(ms); + } + //else if( ms == MediaStorage::MRSpectroscopyStorage ) + // { + // res = ReadImage(ms); + // } + else + { + MediaStorage ms2 = ds.GetMediaStorage(); + //assert( !ds.FindDataElement( Tag(0x7fe0,0x0010 ) ) ); + if( ms == MediaStorage::MediaStorageDirectoryStorage && ms2 == MediaStorage::MS_END ) + { + gdcmDebugMacro( "DICOM file is not an Image file but a : " << + MediaStorage::GetMSString(ms) << " SOP Class UID" ); + res = false; + } + else if( ms == ms2 && ms != MediaStorage::MS_END ) + { + gdcmDebugMacro( "DICOM file is not an Image file but a : " << + MediaStorage::GetMSString(ms) << " SOP Class UID" ); + res = false; + } + else + { + if( ms2 != MediaStorage::MS_END ) + { + bool isImage2 = MediaStorage::IsImage( ms2 ); + if( isImage2 ) + { + gdcmDebugMacro( "After all it might be a DICOM file " + "(Mallinckrodt-like)" ); + + //PixelData->SetCompressionFromTransferSyntax( ts ); + //PixelData->SetCompressionType( Compression::RAW ); + res = ReadImage(ms2); + } + else + { + ms2.SetFromFile( *F ); + if( MediaStorage::IsImage( ms2 ) ) + { + res = ReadImage(ms2); + } + else + { + gdcmDebugMacro( "DICOM file is not an Image file but a : " << + MediaStorage::GetMSString(ms2) << " SOP Class UID" ); + res = false; + } + } + } + else if( ts == TransferSyntax::ImplicitVRBigEndianACRNEMA || header.IsEmpty() ) + { + // Those transfer syntax have a high probability of being ACR NEMA + gdcmDebugMacro( "Looks like an ACR-NEMA file" ); + // Hopefully all ACR-NEMA are RAW: + //PixelData->SetCompressionType( Compression::RAW ); + res = ReadACRNEMAImage(); + } + else // there is a Unknown Media Storage Syntax + { + assert( ts != TransferSyntax::TS_END && ms == MediaStorage::MS_END ); + // god damit I don't know what to do... + gdcmWarningMacro( "Attempting to read this file as a DICOM file" + "\nDesperate attempt" ); + MediaStorage ms3; + ms3.SetFromFile( GetFile() ); + if( ms3 != MediaStorage::MS_END ) + { + res = ReadImage(ms3); + } + else + { + // Giving up + res = false; + } + } + } + } + + //if(res) PixelData->Print( std::cout ); + return res; +} + +// PICKER-16-MONO2-Nested_icon.dcm +void DoIconImage(const DataSet& rootds, Pixmap& image) +{ + const Tag ticonimage(0x0088,0x0200); + IconImage &pixeldata = image.GetIconImage(); + if( rootds.FindDataElement( ticonimage ) ) + { + const DataElement &iconimagesq = rootds.GetDataElement( ticonimage ); + //const SequenceOfItems* sq = iconimagesq.GetSequenceOfItems(); + SmartPointer sq = iconimagesq.GetValueAsSQ(); + // Is SQ empty ? + if( !sq ) return; + SequenceOfItems::ConstIterator it = sq->Begin(); + const DataSet &ds = it->GetNestedDataSet(); + + // D 0028|0011 [US] [Columns] [512] + { + //const DataElement& de = ds.GetDataElement( Tag(0x0028, 0x0011) ); + Attribute<0x0028,0x0011> at = { 0 }; + at.SetFromDataSet( ds ); + pixeldata.SetDimension(0, at.GetValue() ); + } + + // D 0028|0010 [US] [Rows] [512] + { + //const DataElement& de = ds.GetDataElement( Tag(0x0028, 0x0010) ); + Attribute<0x0028,0x0010> at = { 0 }; + at.SetFromDataSet( ds ); + pixeldata.SetDimension(1, at.GetValue() ); + } + + PixelFormat pf; + // D 0028|0100 [US] [Bits Allocated] [16] + { + //const DataElement& de = ds.GetDataElement( Tag(0x0028, 0x0100) ); + Attribute<0x0028,0x0100> at = { 0 }; + at.SetFromDataSet( ds ); + pf.SetBitsAllocated( at.GetValue() ); + } + // D 0028|0101 [US] [Bits Stored] [12] + { + //const DataElement& de = ds.GetDataElement( Tag(0x0028, 0x0101) ); + Attribute<0x0028,0x0101> at = { 0 }; + at.SetFromDataSet( ds ); + pf.SetBitsStored( at.GetValue() ); + } + // D 0028|0102 [US] [High Bit] [11] + { + //const DataElement& de = ds.GetDataElement( Tag(0x0028, 0x0102) ); + Attribute<0x0028,0x0102> at = { 0 }; + at.SetFromDataSet( ds ); + pf.SetHighBit( at.GetValue() ); + } + // D 0028|0103 [US] [Pixel Representation] [0] + { + //const DataElement& de = ds.GetDataElement( Tag(0x0028, 0x0103) ); + Attribute<0x0028,0x0103> at = { 0 }; + at.SetFromDataSet( ds ); + pf.SetPixelRepresentation( at.GetValue() ); + } + // (0028,0002) US 1 # 2, 1 SamplesPerPixel + { + //if( ds.FindDataElement( Tag(0x0028, 0x0002) ) ) + { + //const DataElement& de = ds.GetDataElement( Tag(0x0028, 0x0002) ); + Attribute<0x0028,0x0002> at = { 1 }; + at.SetFromDataSet( ds ); + pf.SetSamplesPerPixel( at.GetValue() ); + } + // else pf will default to 1... + } + pixeldata.SetPixelFormat( pf ); + // D 0028|0004 [CS] [Photometric Interpretation] [MONOCHROME2 ] + const Tag tphotometricinterpretation(0x0028, 0x0004); + PhotometricInterpretation pi = PhotometricInterpretation::MONOCHROME2; + if( ds.FindDataElement( tphotometricinterpretation ) ) + { + const ByteValue *photometricinterpretation = ds.GetDataElement( tphotometricinterpretation ).GetByteValue(); + std::string photometricinterpretation_str( + photometricinterpretation->GetPointer(), + photometricinterpretation->GetLength() ); + pi = PhotometricInterpretation::GetPIType( + photometricinterpretation_str.c_str()); + } + assert( pi != PhotometricInterpretation::UNKNOW); + pixeldata.SetPhotometricInterpretation( pi ); + + // + if ( pi == PhotometricInterpretation::PALETTE_COLOR ) + { + SmartPointer lut = new LookupTable; + const Tag testseglut(0x0028, (0x1221 + 0)); + if( ds.FindDataElement( testseglut ) ) + { + assert(0 && "Please report this image"); + lut = new SegmentedPaletteColorLookupTable; + } + //SmartPointer lut = new SegmentedPaletteColorLookupTable; + lut->Allocate( pf.GetBitsAllocated() ); + + // for each red, green, blue: + for(int i=0; i<3; ++i) + { + // (0028,1101) US 0\0\16 + // (0028,1102) US 0\0\16 + // (0028,1103) US 0\0\16 + const Tag tdescriptor(0x0028, (uint16_t)(0x1101 + i)); + //const Tag tdescriptor(0x0028, 0x3002); + Element el_us3; + // Now pass the byte array to a DICOMizer: + el_us3.SetFromDataElement( ds[tdescriptor] ); //.GetValue() ); + lut->InitializeLUT( LookupTable::LookupTableType(i), + el_us3[0], el_us3[1], el_us3[2] ); + + // (0028,1201) OW + // (0028,1202) OW + // (0028,1203) OW + const Tag tlut(0x0028, (uint16_t)(0x1201 + i)); + //const Tag tlut(0x0028, 0x3006); + + // Segmented LUT + // (0028,1221) OW + // (0028,1222) OW + // (0028,1223) OW + const Tag seglut(0x0028, (uint16_t)(0x1221 + i)); + if( ds.FindDataElement( tlut ) ) + { + const ByteValue *lut_raw = ds.GetDataElement( tlut ).GetByteValue(); + assert( lut_raw ); + // LookupTableType::RED == 0 + lut->SetLUT( LookupTable::LookupTableType(i), + (unsigned char*)lut_raw->GetPointer(), lut_raw->GetLength() ); + //assert( pf.GetBitsAllocated() == el_us3.GetValue(2) ); + + unsigned long check = + (el_us3.GetValue(0) ? el_us3.GetValue(0) : 65536) + * el_us3.GetValue(2) / 8; + assert( check == lut_raw->GetLength() + || check + 1 == lut_raw->GetLength() ); (void)check; + } + else if( ds.FindDataElement( seglut ) ) + { + const ByteValue *lut_raw = ds.GetDataElement( seglut ).GetByteValue(); + assert( lut_raw ); + lut->SetLUT( LookupTable::LookupTableType(i), + (unsigned char*)lut_raw->GetPointer(), lut_raw->GetLength() ); + //assert( pf.GetBitsAllocated() == el_us3.GetValue(2) ); + + //unsigned long check = + // (el_us3.GetValue(0) ? el_us3.GetValue(0) : 65536) + // * el_us3.GetValue(2) / 8; + //assert( check == lut_raw->GetLength() ); (void)check; + } + else + { + gdcmWarningMacro( "Icon Sequence is incomplete. Giving up" ); + pixeldata.Clear(); + return; + } + } + pixeldata.SetLUT(*lut); + } + + const Tag tpixeldata = Tag(0x7fe0, 0x0010); + if( !ds.FindDataElement( tpixeldata ) ) + { + gdcmWarningMacro( "Icon Sequence is incomplete. Giving up" ); + pixeldata.Clear(); + return; + } + const DataElement& de = ds.GetDataElement( tpixeldata ); + pixeldata.SetDataElement( de ); + + // Pass TransferSyntax: + // Warning This is legal for the Icon to be uncompress in a compressed image + // We need to set the appropriate TS here: + const ByteValue *bv = de.GetByteValue(); + if( bv ) + pixeldata.SetTransferSyntax( TransferSyntax::ImplicitVRLittleEndian ); + else + pixeldata.SetTransferSyntax( image.GetTransferSyntax() ); + } +} + +// GE_DLX-8-MONO2-Multiframe.dcm +void DoCurves(const DataSet& ds, Pixmap& pixeldata) +{ + unsigned int numcurves; + if( (numcurves = Curve::GetNumberOfCurves( ds )) ) + { + pixeldata.SetNumberOfCurves( numcurves ); + + Tag curve(0x5000,0x0000); + bool finished = false; + unsigned int idxcurves = 0; + while( !finished ) + { + const DataElement &de = ds.FindNextDataElement( curve ); + // Are we done: + if( de.GetTag().GetGroup() > 0x50FF ) // last possible curve curve + { + finished = true; + } + else if( de.GetTag().IsPrivate() ) // GEMS owns some 0x5003 + { + // Move on to the next public one: + curve.SetGroup( (uint16_t)(de.GetTag().GetGroup() + 1) ); + curve.SetElement( 0 ); + } + else + { + // Yay! this is an curve element + Curve &ov = pixeldata.GetCurve(idxcurves); + ++idxcurves; // move on to the next one + curve = de.GetTag(); + uint16_t currentcurve = curve.GetGroup(); + assert( !(currentcurve % 2) ); // 0x6001 is not an curve... + // Now loop on all element from this current group: + DataElement de2 = de; + while( de2.GetTag().GetGroup() == currentcurve ) + { + ov.Update(de2); + curve.SetElement( (uint16_t)(de2.GetTag().GetElement() + 1) ); + de2 = ds.FindNextDataElement( curve ); + // Next element: + //curve.SetElement( curve.GetElement() + 1 ); + } + // If we exit the loop we have pass the current curve and potentially point to the next one: + //curve.SetElement( curve.GetElement() + 1 ); + //ov.Print( std::cout ); + } + } + //std::cout << "Num of curves: " << numcurves << std::endl; + assert( idxcurves == numcurves ); + } +} + +unsigned int GetNumberOfOverlaysInternal(DataSet const & ds, std::vector & overlaylist) +{ + Tag overlay(0x6000,0x0000); // First possible overlay + bool finished = false; + unsigned int numoverlays = 0; + while( !finished ) + { + const DataElement &de = ds.FindNextDataElement( overlay ); + if( de.GetTag().GetGroup() > 0x60FF ) // last possible curve + { + finished = true; + } + else if( de.GetTag().IsPrivate() ) + { + // Move on to the next public one: + overlay.SetGroup( (uint16_t)(de.GetTag().GetGroup() + 1) ); + overlay.SetElement( 0 ); // reset just in case... + } + else + { + // Yeah this is a potential overlay element, let's check this is not a broken LEADTOOL image, + // or prova0001.dcm: + // (5000,0000) UL 0 # 4, 1 GenericGroupLength + // (6000,0000) UL 0 # 4, 1 GenericGroupLength + // (6001,0000) UL 28 # 4, 1 PrivateGroupLength + // (6001,0010) LT [PAPYRUS 3.0] # 12, 1 PrivateCreator + // (6001,1001) LT (no value available) # 0, 0 Unknown Tag & Data +/* + * FIXME: + * In order to support : gdcmData/SIEMENS_GBS_III-16-ACR_NEMA_1.acr + * gdcmDataExtra/gdcmSampleData/images_of_interest/XA_GE_JPEG_02_with_Overlays.dcm + * I cannot simply check for overlay_group,3000 this would not work + * I would need a strong euristick + */ + // Store found tag in overlay: + overlay = de.GetTag(); + // heuristic based on either the Overlay Data or the Col/Row info + Tag toverlaydata(overlay.GetGroup(),0x3000 ); + Tag toverlayrows(overlay.GetGroup(),0x0010 ); + Tag toverlaycols(overlay.GetGroup(),0x0011 ); + Tag toverlaybitpos(overlay.GetGroup(),0x0102 ); + if( ds.FindDataElement( toverlaydata ) ) + { + // ok so far so good... + const DataElement& overlaydata = ds.GetDataElement( toverlaydata ); + //const DataElement& overlaydata = ds.GetDataElement(Tag(overlay.GetGroup(),0x0010)); + if( !overlaydata.IsEmpty() ) + { + ++numoverlays; + overlaylist.push_back( overlay.GetGroup() ); + } + } + else if( ds.FindDataElement( toverlayrows ) && ds.FindDataElement( toverlaycols ) + && ds.FindDataElement( toverlaybitpos ) ) + { + // Overlay Pixel are in Unused Pixel + assert( !ds.FindDataElement( toverlaydata ) ); + const DataElement& overlayrows = ds.GetDataElement( toverlayrows ); + const DataElement& overlaycols = ds.GetDataElement( toverlaycols ); + assert( ds.FindDataElement( toverlaybitpos ) ); + const DataElement& overlaybitpos = ds.GetDataElement( toverlaybitpos ); + if( !overlayrows.IsEmpty() && !overlaycols.IsEmpty() && !overlaybitpos.IsEmpty() ) + { + ++numoverlays; + overlaylist.push_back( overlay.GetGroup() ); + } + } + // Move on to the next possible one: + overlay.SetGroup( (uint16_t)(overlay.GetGroup() + 2) ); + // reset to element 0x0 just in case... + overlay.SetElement( 0 ); + } + } + + // at most one out of two : + assert( numoverlays < 0x00ff / 2 ); + // PS 3.3 - 2004: + // C.9.2 Overlay plane module + // Each Overlay Plane is one bit deep. Sixteen separate Overlay Planes may be associated with an + // Image or exist as Standalone Overlays in a Series + assert( numoverlays <= 16 ); + assert( numoverlays == overlaylist.size() ); + return numoverlays; +} + +bool DoOverlays(const DataSet& ds, Pixmap& pixeldata) +{ + bool updateoverlayinfo = false; + unsigned int numoverlays; + std::vector overlaylist; + if( (numoverlays = GetNumberOfOverlaysInternal( ds, overlaylist )) ) + { + pixeldata.SetNumberOfOverlays( numoverlays ); + + for( unsigned int idxoverlays = 0; idxoverlays < numoverlays; ++idxoverlays ) + { + Overlay &ov = pixeldata.GetOverlay(idxoverlays); + uint16_t currentoverlay = overlaylist[idxoverlays]; + Tag overlay(0x6000,0x0000); + overlay.SetGroup( currentoverlay ); + const DataElement &de = ds.FindNextDataElement( overlay ); + assert( !(currentoverlay % 2) ); // 0x6001 is not an overlay... + // Now loop on all element from this current group: + DataElement de2 = de; + while( de2.GetTag().GetGroup() == currentoverlay ) + { + ov.Update(de2); + overlay.SetElement( (uint16_t)(de2.GetTag().GetElement() + 1) ); + de2 = ds.FindNextDataElement( overlay ); + } + + // Let's decode it: + std::ostringstream unpack; + ov.Decompress( unpack ); + std::string s = unpack.str(); + //size_t l = s.size(); + // The following line will fail with images like XA_GE_JPEG_02_with_Overlays.dcm + // since the overlays are stored in the unused bit of the PixelData + if( !ov.IsEmpty() ) + { + //assert( unpack.str().size() / 8 == ((ov.GetRows() * ov.GetColumns()) + 7 ) / 8 ); + assert( ov.IsInPixelData( ) == false ); + } + else + { + gdcmDebugMacro( "This image does not contains Overlay in the 0x60xx tags. " + << "Instead the overlay is stored in the unused bit of the Pixel Data. " + << "This is not supported right now" + << std::endl ); + ov.IsInPixelData( true ); + // make sure Overlay is valid + if( ov.GetBitsAllocated() != pixeldata.GetPixelFormat().GetBitsAllocated() ) + { + gdcmWarningMacro( "Bits Allocated are wrong. Correcting." ); + ov.SetBitsAllocated( pixeldata.GetPixelFormat().GetBitsAllocated() ); + } + + if( !ov.GrabOverlayFromPixelData(ds) ) + { + gdcmErrorMacro( "Could not extract Overlay from Pixel Data" ); + //throw Exception("TODO: Could not extract Overlay Data"); + } + updateoverlayinfo = true; + } + } + //std::cout << "Num of Overlays: " << numoverlays << std::endl; + } + + // Now is good time to do some cleanup (eg. DX_GE_FALCON_SNOWY-VOI.dcm). + const PixelFormat &pf = pixeldata.GetPixelFormat(); + // Yes I am using a call in the for() loop, because I internally modify the + // number of overlays: + for( size_t ov_idx = pixeldata.GetNumberOfOverlays(); ov_idx != 0; --ov_idx ) + { + size_t ov = ov_idx - 1; + const Overlay& o = pixeldata.GetOverlay(ov); + if( o.IsInPixelData() ) + { + unsigned short obp = o.GetBitPosition(); + if( obp < pf.GetBitsStored() ) + { + pixeldata.RemoveOverlay( ov ); + gdcmWarningMacro( "Invalid BitPosition: " << obp << " for overlay #" << ov << " removing it." ); + } + } + } + + if( updateoverlayinfo ) + { + for( size_t ov = 0; ov < pixeldata.GetNumberOfOverlays(); ++ov ) + { + Overlay& o = pixeldata.GetOverlay(ov); + // We need to update information + if( o.GetBitsAllocated() == 16 ) + { + o.SetBitsAllocated( 1 ); + o.SetBitPosition( 0 ); + } + else + { + gdcmErrorMacro( "Overlay is not supported" ); + return false; + } + } + } + + return true; +} + +bool PixmapReader::ReadImage(MediaStorage const &ms) +{ + return ReadImageInternal(ms); +} + +bool PixmapReader::ReadImageInternal(MediaStorage const &ms, bool handlepixeldata ) +{ + const DataSet &ds = F->GetDataSet(); + std::string conversion; + + bool isacrnema = false; + const Tag trecognitioncode(0x0008,0x0010); + if( ds.FindDataElement( trecognitioncode ) && !ds.GetDataElement( trecognitioncode ).IsEmpty() ) + { + // PHILIPS_Gyroscan-12-MONO2-Jpeg_Lossless.dcm + // PHILIPS_Gyroscan-12-Jpeg_Extended_Process_2_4.dcm + gdcmDebugMacro( "Mixture of ACR NEMA and DICOM file" ); + isacrnema = true; + const char *str = ds.GetDataElement( trecognitioncode ).GetByteValue()->GetPointer(); + assert( strncmp( str, "ACR-NEMA", strlen( "ACR-NEMA" ) ) == 0 || + strncmp( str, "ACRNEMA", strlen( "ACRNEMA" ) ) == 0 ); + (void)str;//warning removal + } + + std::vector vdims = ImageHelper::GetDimensionsValue(*F); + unsigned int numberofframes = vdims[2]; + // What should I do when numberofframes == 0 ? + if( numberofframes > 1 ) + { + PixelData->SetNumberOfDimensions(3); + PixelData->SetDimension(2, numberofframes ); + } + else + { + gdcmDebugMacro( "NumberOfFrames was specified with a value of: " + << numberofframes ); + PixelData->SetNumberOfDimensions(2); + } + + // 2. What are the col & rows: + PixelData->SetDimension(0, vdims[0] ); + PixelData->SetDimension(1, vdims[1] ); + + // 3. Pixel Format ? + PixelFormat pf; + // D 0028|0002 [US] [Samples per Pixel] [1] + { + Attribute<0x0028,0x0002> at = { 1 }; // By default assume 1 Samples Per Pixel + at.SetFromDataSet( ds ); + pf.SetSamplesPerPixel( at.GetValue() ); + } + + if( ms == MediaStorage::MRSpectroscopyStorage ) + { + pf.SetScalarType( PixelFormat::FLOAT32 ); + } + else + { + assert( MediaStorage::IsImage( ms ) ); + // D 0028|0100 [US] [Bits Allocated] [16] + //pf.SetBitsAllocated( + // ReadUSFromTag( Tag(0x0028, 0x0100), ss, conversion ) ); + { + //const DataElement& de = ds.GetDataElement( Tag(0x0028, 0x0100) ); + Attribute<0x0028,0x0100> at = { 0 }; + at.SetFromDataSet( ds ); + pf.SetBitsAllocated( at.GetValue() ); + //assert( at.GetValue() == ReadUSFromTag( Tag(0x0028, 0x0100), ss, conversion ) ); + } + + // D 0028|0101 [US] [Bits Stored] [12] + //pf.SetBitsStored( + // ReadUSFromTag( Tag(0x0028, 0x0101), ss, conversion ) ); + { + //const DataElement& de = ds.GetDataElement( Tag(0x0028, 0x0101) ); + Attribute<0x0028,0x0101> at = { 0 }; + at.SetFromDataSet( ds ); + pf.SetBitsStored( at.GetValue() ); + //assert( at.GetValue() == ReadUSFromTag( Tag(0x0028, 0x0101), ss, conversion ) ); + } + + // D 0028|0102 [US] [High Bit] [11] + //pf.SetHighBit( + // ReadUSFromTag( Tag(0x0028, 0x0102), ss, conversion ) ); + { + //const DataElement& de = ds.GetDataElement( Tag(0x0028, 0x0102) ); + Attribute<0x0028,0x0102> at = { 0 }; + at.SetFromDataSet( ds ); + pf.SetHighBit( at.GetValue() ); + //assert( at.GetValue() == ReadUSFromTag( Tag(0x0028, 0x0102), ss, conversion ) ); + } + + // D 0028|0103 [US] [Pixel Representation] [0] + //Tag tpixelrep(0x0028, 0x0103); + //if( ds.FindDataElement( tpixelrep ) && !ds.GetDataElement( tpixelrep ).IsEmpty() ) + { + //pf.SetPixelRepresentation( + // ReadUSFromTag( Tag(0x0028, 0x0103), ss, conversion ) ); + //const DataElement& de = ds.GetDataElement( Tag(0x0028, 0x0103) ); + Attribute<0x0028,0x0103> at = { 0 }; + at.SetFromDataSet( ds ); + pf.SetPixelRepresentation( at.GetValue() ); + //assert( at.GetValue() == ReadUSFromTag( Tag(0x0028, 0x0103), ss, conversion ) ); + + } +// else +// { +// gdcmWarningMacro( "Pixel Representation was not found. Default to Unsigned Pixel Representation" ); +// pf.SetPixelRepresentation( 0 ); +// } + } + + // 5. Photometric Interpretation + // D 0028|0004 [CS] [Photometric Interpretation] [MONOCHROME2 ] + const Tag tphotometricinterpretation(0x0028, 0x0004); + const ByteValue *photometricinterpretation + = ImageHelper::GetPointerFromElement( tphotometricinterpretation, *F ); + PhotometricInterpretation pi = PhotometricInterpretation::UNKNOW; + if( photometricinterpretation ) + { + std::string photometricinterpretation_str( + photometricinterpretation->GetPointer(), + photometricinterpretation->GetLength() ); + pi = PhotometricInterpretation::GetPIType( photometricinterpretation_str.c_str() ); + // http://www.dominator.com/assets/003/5278.pdf + // JPEG 2000 lossless YUV_RCT + if( pi == PhotometricInterpretation::PI_END ) + { + gdcmWarningMacro( "Discarding suspicious PhotometricInterpretation found: " + << photometricinterpretation_str ); + } + } + // try again harder: + if( !photometricinterpretation || pi == PhotometricInterpretation::PI_END ) + { + if( pf.GetSamplesPerPixel() == 1 ) + { + gdcmWarningMacro( "No PhotometricInterpretation found, default to MONOCHROME2" ); + pi = PhotometricInterpretation::MONOCHROME2; + } + else if( pf.GetSamplesPerPixel() == 3 ) + { + gdcmWarningMacro( "No PhotometricInterpretation found, default to RGB" ); + pi = PhotometricInterpretation::RGB; + } + else if( pf.GetSamplesPerPixel() == 4 ) + { + gdcmWarningMacro( "No PhotometricInterpretation found, default to ARGB" ); + pi = PhotometricInterpretation::ARGB; + } + else + { + gdcmWarningMacro( "Impossible value for Samples Per Pixel: " << pf.GetSamplesPerPixel() ); + return false; + } + } + assert( pi != PhotometricInterpretation::PI_END ); + if( !pf.GetSamplesPerPixel() || (pi.GetSamplesPerPixel() != pf.GetSamplesPerPixel()) ) + { + if( pi != PhotometricInterpretation::UNKNOW ) + { + pf.SetSamplesPerPixel( pi.GetSamplesPerPixel() ); + } + else if ( isacrnema ) + { + assert ( pf.GetSamplesPerPixel() == 0 ); + assert ( pi == PhotometricInterpretation::UNKNOW ); + pf.SetSamplesPerPixel( 1 ); + pi = PhotometricInterpretation::MONOCHROME2; + } + else + { + gdcmWarningMacro( "Cannot recognize image type. Does not looks like" + "ACR-NEMA and is missing both Sample Per Pixel AND PhotometricInterpretation." + "Please report" ); + return false; + } + } + assert ( pf.GetSamplesPerPixel() != 0 ); + // Very important to set the PixelFormat here before PlanarConfiguration + PixelData->SetPixelFormat( pf ); + pf = PixelData->GetPixelFormat(); + if( !pf.IsValid() ) + { + return false; + } + if( pi == PhotometricInterpretation::UNKNOW ) return false; + PixelData->SetPhotometricInterpretation( pi ); + + // 4. Planar Configuration + // D 0028|0006 [US] [Planar Configuration] [1] + const Tag planarconfiguration = Tag(0x0028, 0x0006); + // FIXME: Whatif planaconfiguration is send in a grayscale image... it would be empty... + // well hopefully :( + if( ds.FindDataElement( planarconfiguration ) && !ds.GetDataElement( planarconfiguration ).IsEmpty() ) + { + const DataElement& de = ds.GetDataElement( planarconfiguration ); + Attribute<0x0028,0x0006> at = { 0 }; + at.SetFromDataElement( de ); + + //unsigned int pc = ReadUSFromTag( planarconfiguration, ss, conversion ); + unsigned int pc = at.GetValue(); + if( pc && PixelData->GetPixelFormat().GetSamplesPerPixel() != 3 ) + { + gdcmDebugMacro( "Cannot have PlanarConfiguration=1, when Sample Per Pixel != 3" ); + pc = 0; + } + PixelData->SetPlanarConfiguration( pc ); + } + + + // Do the Palette Color: + // 1. Modality LUT Sequence + bool modlut = ds.FindDataElement(Tag(0x0028,0x3000) ); + if( modlut ) + { + gdcmWarningMacro( "Modality LUT (0028,3000) are not handled. Image will not be displayed properly" ); + } + // 2. LUTData (0028,3006) + // technically I do not need to warn about LUTData since either modality lut XOR VOI LUT need to + // be sent to require a LUT Data... + bool lutdata = ds.FindDataElement(Tag(0x0028,0x3006) ); + if( lutdata ) + { + gdcmWarningMacro( "LUT Data (0028,3006) are not handled. Image will not be displayed properly" ); + } + // 3. VOILUTSequence (0028,3010) + bool voilut = ds.FindDataElement(Tag(0x0028,0x3010) ); + if( voilut ) + { + gdcmWarningMacro( "VOI LUT (0028,3010) are not handled. Image will not be displayed properly" ); + } + // (0028,0120) US 32767 # 2, 1 PixelPaddingValue + bool pixelpaddingvalue = ds.FindDataElement(Tag(0x0028,0x0120)); + + // PS 3.3 - 2008 / C.7.5.1.1.2 Pixel Padding Value and Pixel Padding Range Limit + if(pixelpaddingvalue) + { + // Technically if Pixel Padding Value is 0 on MONOCHROME2 image, then appearance should be fine... + bool vizissue = true; + if( pf.GetPixelRepresentation() == 0 ) + { + Element ppv; + if( !ds.GetDataElement(Tag(0x0028,0x0120) ).IsEmpty() ) + { + ppv.SetFromDataElement( ds.GetDataElement(Tag(0x0028,0x0120)) ); //.GetValue() ); + if( pi == PhotometricInterpretation::MONOCHROME2 && ppv.GetValue() == 0 ) + { + vizissue = false; + } + } + } + else if( pf.GetPixelRepresentation() == 1 ) + { + gdcmDebugMacro( "TODO" ); + } + // test if there is any viz issue: + if( vizissue ) + { + gdcmDebugMacro( "Pixel Padding Value (0028,0120) is not handled. Image will not be displayed properly" ); + } + } + // 4. Palette Color Lookup Table Descriptor + if ( pi == PhotometricInterpretation::PALETTE_COLOR ) + { + //const DataElement& modlutsq = ds.GetDataElement( Tag(0x0028,0x3000) ); + //const SequenceOfItems* sq = modlutsq.GetSequenceOfItems(); + //SequenceOfItems::ConstIterator it = sq->Begin(); + //const DataSet &ds = it->GetNestedDataSet(); + + SmartPointer lut = new LookupTable; + const Tag testseglut(0x0028, (0x1221 + 0)); + if( ds.FindDataElement( testseglut ) ) + { + lut = new SegmentedPaletteColorLookupTable; + } + //SmartPointer lut = new SegmentedPaletteColorLookupTable; + lut->Allocate( pf.GetBitsAllocated() ); + + // for each red, green, blue: + for(int i=0; i<3; ++i) + { + // (0028,1101) US 0\0\16 + // (0028,1102) US 0\0\16 + // (0028,1103) US 0\0\16 + const Tag tdescriptor(0x0028, (uint16_t)(0x1101 + i)); + //const Tag tdescriptor(0x0028, 0x3002); + Element el_us3 = {{ 0, 0, 0}}; + // Now pass the byte array to a DICOMizer: + el_us3.SetFromDataElement( ds[tdescriptor] ); //.GetValue() ); + lut->InitializeLUT( LookupTable::LookupTableType(i), + el_us3[0], el_us3[1], el_us3[2] ); + + // (0028,1201) OW + // (0028,1202) OW + // (0028,1203) OW + const Tag tlut(0x0028, (uint16_t)(0x1201 + i)); + //const Tag tlut(0x0028, 0x3006); + + // Segmented LUT + // (0028,1221) OW + // (0028,1222) OW + // (0028,1223) OW + const Tag seglut(0x0028, (uint16_t)(0x1221 + i)); + if( ds.FindDataElement( tlut ) ) + { + const ByteValue *lut_raw = ds.GetDataElement( tlut ).GetByteValue(); + if( lut_raw ) + { + // LookupTableType::RED == 0 + lut->SetLUT( LookupTable::LookupTableType(i), + (unsigned char*)lut_raw->GetPointer(), lut_raw->GetLength() ); + //assert( pf.GetBitsAllocated() == el_us3.GetValue(2) ); + } + else + { + lut->Clear(); + } + + unsigned long check = + (el_us3.GetValue(0) ? el_us3.GetValue(0) : 65536) + * el_us3.GetValue(2) / 8; + assert( !lut->Initialized() || check == lut_raw->GetLength() ); (void)check; + } + else if( ds.FindDataElement( seglut ) ) + { + const ByteValue *lut_raw = ds.GetDataElement( seglut ).GetByteValue(); + if( lut_raw ) + { + lut->SetLUT( LookupTable::LookupTableType(i), + (unsigned char*)lut_raw->GetPointer(), lut_raw->GetLength() ); + //assert( pf.GetBitsAllocated() == el_us3.GetValue(2) ); + } + else + { + lut->Clear(); + } + + //unsigned long check = + // (el_us3.GetValue(0) ? el_us3.GetValue(0) : 65536) + // * el_us3.GetValue(2) / 8; + //assert( check == lut_raw->GetLength() ); (void)check; + } + else + { + assert(0); + } + } + if( ! lut->Initialized() ) return false; + PixelData->SetLUT(*lut); + } + // TODO + //assert( pi.GetSamplesPerPixel() == pf.GetSamplesPerPixel() ); + + // 5.5 Do IconImage if any + assert( PixelData->GetIconImage().IsEmpty() ); + DoIconImage(ds, *PixelData); + + // 6. Do the Curves if any + DoCurves(ds, *PixelData); + + // 7. Do the Overlays if any + if( !DoOverlays(ds, *PixelData) ) + { + return false; + } + + // 8. Do the PixelData + if( handlepixeldata ) + { + if( ms == MediaStorage::MRSpectroscopyStorage ) + { + const Tag spectdata = Tag(0x5600, 0x0020); + if( !ds.FindDataElement( spectdata ) ) + { + gdcmWarningMacro( "No Spectroscopy Data Found" ); + return false; + } + const DataElement& xde = ds.GetDataElement( spectdata ); + //bool need = PixelData->GetTransferSyntax() == TransferSyntax::ImplicitVRBigEndianPrivateGE; + //PixelData->SetNeedByteSwap( need ); + PixelData->SetDataElement( xde ); + } + else + { + const Tag pixeldata = Tag(0x7fe0, 0x0010); + if( !ds.FindDataElement( pixeldata ) ) + { + gdcmWarningMacro( "No Pixel Data Found" ); + return false; + } + const DataElement& xde = ds.GetDataElement( pixeldata ); + bool need = PixelData->GetTransferSyntax() == TransferSyntax::ImplicitVRBigEndianPrivateGE; + PixelData->SetNeedByteSwap( need ); + PixelData->SetDataElement( xde ); + + // FIXME: + // We should check that when PixelData is RAW that Col * Dim == PixelData->GetLength() + //PixelFormat guesspf = PixelFormat->GuessPixelFormat(); + + } + + const unsigned int *dims = PixelData->GetDimensions(); + if( dims[0] == 0 || dims[1] == 0 ) + { + // Pseudo-declared JPEG SC image storage. Let's fix col/row/pf/pi + gdcm::JPEGCodec jpeg; + if( jpeg.CanDecode( PixelData->GetTransferSyntax() ) ) + { + std::stringstream ss; + const DataElement &de = PixelData->GetDataElement(); + //const ByteValue *bv = de.GetByteValue(); + const SequenceOfFragments *sqf = de.GetSequenceOfFragments(); + if( !sqf ) + { + // TODO: It would be nice to recognize file such as JPEGDefinedLengthSequenceOfFragments.dcm + gdcmDebugMacro( "File is declared as JPEG compressed but does not contains Fragmens explicitely." ); + return false; + } + sqf->WriteBuffer( ss ); + //std::string s( bv->GetPointer(), bv->GetLength() ); + //is.str( s ); + gdcm::PixelFormat jpegpf ( gdcm::PixelFormat::UINT8 ); // usual guess... + jpeg.SetPixelFormat( jpegpf ); + gdcm::TransferSyntax ts; + bool b = jpeg.GetHeaderInfo( ss, ts ); + if( b ) + { + std::vector v(3); + v[0] = PixelData->GetDimensions()[0]; + v[1] = PixelData->GetDimensions()[1]; + v[2] = PixelData->GetDimensions()[2]; + assert( jpeg.GetDimensions()[0] ); + assert( jpeg.GetDimensions()[1] ); + v[0] = jpeg.GetDimensions()[0]; + v[1] = jpeg.GetDimensions()[1]; + PixelData->SetDimensions( &v[0] ); + //PixelData->SetPixelFormat( jpeg.GetPixelFormat() ); + //PixelData->SetPhotometricInterpretation( jpeg.GetPhotometricInterpretation() ); + assert( PixelData->IsTransferSyntaxCompatible( ts ) ); + } + else + { + gdcmDebugMacro( "Columns or Row was found to be 0. Cannot compute dimension." ); + return false; + } + } + else + { + gdcmDebugMacro( "Columns or Row was found to be 0. Cannot compute dimension." ); + return false; + } + } + } + + // Let's be smart when computing the lossyflag (0028,2110) + // LossyImageCompression + Attribute<0x0028,0x2110> licat; + bool lossyflag = false; + bool haslossyflag = false; + if( ds.FindDataElement( licat.GetTag() ) ) + { + haslossyflag = true; + licat.SetFromDataSet( ds ); // could be empty + const CSComp & v = licat.GetValue(); + lossyflag = atoi( v.c_str() ) == 1; + PixelData->SetLossyFlag(lossyflag); + } + + // Two cases: + // - DataSet did not specify the lossyflag + // - DataSet specify it to be 0, but there is still a change it could be wrong: + if( !haslossyflag || !lossyflag ) + { + PixelData->ComputeLossyFlag(); + if( PixelData->IsLossy() && (!lossyflag && haslossyflag ) ) + { + // We always prefer the setting from the stream... + gdcmWarningMacro( "DataSet set LossyFlag to 0, while Codec made the stream lossy" ); + } + } + + return true; +} + +bool PixmapReader::ReadACRNEMAImage() +{ + const DataSet &ds = F->GetDataSet(); + std::stringstream ss; + std::string conversion; + + // Ok we have the dataset let's feed the Image (PixelData) + // 1. First find how many dimensions there is: + // D 0028|0005 [SS] [Image Dimensions (RET)] [2] + const Tag timagedimensions = Tag(0x0028, 0x0005); + if( ds.FindDataElement( timagedimensions ) ) + { + const DataElement& de0 = ds.GetDataElement( timagedimensions ); + Attribute<0x0028,0x0005> at0 = { 0 }; + at0.SetFromDataElement( de0 ); + assert( at0.GetNumberOfValues() == 1 ); + unsigned short imagedimensions = at0.GetValue(); + //assert( imagedimensions == ReadSSFromTag( timagedimensions, ss, conversion ) ); + if ( imagedimensions == 3 ) + { + PixelData->SetNumberOfDimensions(3); + // D 0028|0012 [US] [Planes] [262] + const DataElement& de1 = ds.GetDataElement( Tag(0x0028, 0x0012) ); + Attribute<0x0028,0x0012> at1 = { 0 }; + at1.SetFromDataElement( de1 ); + assert( at1.GetNumberOfValues() == 1 ); + PixelData->SetDimension(2, at1.GetValue() ); + //assert( at.GetValue() == ReadUSFromTag( Tag(0x0028, 0x0012), ss, conversion ) ); + } + else if ( imagedimensions == 2 ) + { + PixelData->SetNumberOfDimensions(2); + } + else + { + gdcmErrorMacro( "Unhandled Image Dimensions: " << imagedimensions ); + return false; + } + } + else + { + gdcmWarningMacro( "Attempting a guess for the number of dimensions" ); + PixelData->SetNumberOfDimensions( 2 ); + } + + // 2. What are the col & rows: + // D 0028|0011 [US] [Columns] [512] + { + //const DataElement& de = ds.GetDataElement( Tag(0x0028, 0x0011) ); + Attribute<0x0028,0x0011> at = { 0 }; + at.SetFromDataSet( ds ); + PixelData->SetDimension(0, at.GetValue() ); + //assert( at.GetValue() == ReadUSFromTag( Tag(0x0028, 0x0011), ss, conversion ) ); + } + + // D 0028|0010 [US] [Rows] [512] + { + //const DataElement& de = ds.GetDataElement( Tag(0x0028, 0x0010) ); + Attribute<0x0028,0x0010> at = { 0 }; + at.SetFromDataSet( ds ); + PixelData->SetDimension(1, at.GetValue() ); + //assert( at.GetValue() == ReadUSFromTag( Tag(0x0028, 0x0010), ss, conversion ) ); + } + + // This is the definition of an ACR NEMA image: + // D 0008|0010 [LO] [Recognition Code (RET)] [ACR-NEMA 2.0] + // LIBIDO compatible code: + // D 0008|0010 [LO] [Recognition Code (RET)] [ACRNEMA_LIBIDO_1.1] + const Tag trecognitioncode(0x0008,0x0010); + if( ds.FindDataElement( trecognitioncode ) && !ds.GetDataElement( trecognitioncode ).IsEmpty() ) + { + const ByteValue *libido = ds.GetDataElement(trecognitioncode).GetByteValue(); + assert( libido ); + std::string libido_str( libido->GetPointer(), libido->GetLength() ); + assert( libido_str != "CANRME_AILIBOD1_1." ); + if( strcmp(libido_str.c_str() , "ACRNEMA_LIBIDO_1.1") == 0 || strcmp(libido_str.c_str() , "ACRNEMA_LIBIDO_1.0") == 0 ) + { + // Swap Columns & Rows + // assert( PixelData->GetNumberOfDimensions() == 2 ); + const unsigned int *dims = PixelData->GetDimensions(); + unsigned int tmp = dims[0]; + PixelData->SetDimension(0, dims[1] ); + PixelData->SetDimension(1, tmp ); + } + else + { + assert( libido_str == "ACR-NEMA 2.0" + || libido_str == "ACR-NEMA 1.0" ); + } + } + else + { + gdcmWarningMacro( + "Reading as ACR NEMA an image which does not look likes ACR NEMA" ); + // File: acc-max.dcm is it ACR or DICOM ? + // assert(0); + } + + // 3. Pixel Format ? + PixelFormat pf; + // D 0028|0100 [US] [Bits Allocated] [16] + { + //const DataElement& de = ds.GetDataElement( Tag(0x0028, 0x0100) ); + Attribute<0x0028,0x0100> at = { 0 }; + at.SetFromDataSet( ds ); + pf.SetBitsAllocated( at.GetValue() ); + //assert( at.GetValue() == ReadUSFromTag( Tag(0x0028, 0x0100), ss, conversion ) ); + } + + // D 0028|0101 [US] [Bits Stored] [12] + { + //const DataElement& de = ds.GetDataElement( Tag(0x0028, 0x0101) ); + Attribute<0x0028,0x0101> at = { 0 }; + at.SetFromDataSet( ds ); + pf.SetBitsStored( at.GetValue() ); + //assert( at.GetValue() == ReadUSFromTag( Tag(0x0028, 0x0101), ss, conversion ) ); + } + + // D 0028|0102 [US] [High Bit] [11] + { + //const DataElement& de = ds.GetDataElement( Tag(0x0028, 0x0102) ); + Attribute<0x0028,0x0102> at = { 0 }; + at.SetFromDataSet( ds ); + pf.SetHighBit( at.GetValue() ); + //assert( at.GetValue() == ReadUSFromTag( Tag(0x0028, 0x0102), ss, conversion ) ); + } + + // D 0028|0103 [US] [Pixel Representation] [0] + { + //const DataElement& de = ds.GetDataElement( Tag(0x0028, 0x0103) ); + Attribute<0x0028,0x0103> at = { 0 }; + at.SetFromDataSet( ds ); + pf.SetPixelRepresentation( at.GetValue() ); + //assert( at.GetValue() == ReadUSFromTag( Tag(0x0028, 0x0103), ss, conversion ) ); + } + + PixelData->SetPixelFormat( pf ); + + // 4. Do the Curves/Overlays if any + DoCurves(ds, *PixelData); + DoOverlays(ds, *PixelData); + + // 5. Do the PixelData + const Tag pixeldata = Tag(0x7fe0, 0x0010); + if( !ds.FindDataElement( pixeldata ) ) + { + gdcmWarningMacro( "No Pixel Data Found" ); + return false; + } + const DataElement& de = ds.GetDataElement( pixeldata ); + if ( de.GetVR() == VR::OW ) + { + //assert(0); + //PixelData->SetNeedByteSwap(true); + } + PixelData->SetDataElement( de ); + + // There is no such thing as Photometric Interpretation and + // Planar Configuration in ACR NEMA so let's default to something ... + PixelData->SetPhotometricInterpretation( + PhotometricInterpretation::MONOCHROME2 ); + PixelData->SetPlanarConfiguration(0); + const Tag planarconfiguration(0x0028, 0x0006); + if( ds.FindDataElement( planarconfiguration ) && !ds.GetDataElement( planarconfiguration ).IsEmpty() ) + { + //const DataElement& de = ds.GetDataElement( planarconfiguration ); + Attribute<0x0028,0x0006> at = { 0 }; + at.SetFromDataSet( ds ); + + //unsigned int pc = ReadUSFromTag( planarconfiguration, ss, conversion ); + unsigned int pc = at.GetValue(); + if( pc && PixelData->GetPixelFormat().GetSamplesPerPixel() != 3 ) + { + gdcmDebugMacro( "Cannot have PlanarConfiguration=1, when Sample Per Pixel != 3" ); + pc = 0; + } + PixelData->SetPlanarConfiguration( pc ); + } + + const Tag tphotometricinterpretation(0x0028, 0x0004); + // Some funny ACR NEMA file have PhotometricInterpretation ... + if( ds.FindDataElement( tphotometricinterpretation ) && !ds.GetDataElement( tphotometricinterpretation ).IsEmpty() ) + { + const ByteValue *photometricinterpretation + = ds.GetDataElement( tphotometricinterpretation ).GetByteValue(); + assert( photometricinterpretation ); + std::string photometricinterpretation_str( + photometricinterpretation->GetPointer(), + photometricinterpretation->GetLength() ); + PhotometricInterpretation pi( + PhotometricInterpretation::GetPIType( + photometricinterpretation_str.c_str())); + PixelData->SetPhotometricInterpretation( pi ); + } + else + { + // Wild guess: + if( PixelData->GetPixelFormat().GetSamplesPerPixel() == 1 ) + { + assert( PixelData->GetPhotometricInterpretation() == PhotometricInterpretation::MONOCHROME2 ); + // No need... + //PixelData->SetPhotometricInterpretation( PhotometricInterpretation::MONOCHROME2 ); + } + else if( PixelData->GetPixelFormat().GetSamplesPerPixel() == 3 ) + { + // LIBIDO-24-ACR_NEMA-Rectangle.dcm + PixelData->SetPhotometricInterpretation( PhotometricInterpretation::RGB ); + } + else if( PixelData->GetPixelFormat().GetSamplesPerPixel() == 4 ) + { + PixelData->SetPhotometricInterpretation( PhotometricInterpretation::ARGB ); + } + else + { + gdcmErrorMacro( "Cannot handle Samples Per Pixel=" << PixelData->GetPixelFormat().GetSamplesPerPixel() ); + return false; + } + } + + return true; +} + + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmPixmapReader.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmPixmapReader.h new file mode 100644 index 0000000..f7f37a5 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmPixmapReader.h @@ -0,0 +1,73 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMPIXMAPREADER_H +#define GDCMPIXMAPREADER_H + +#include "gdcmReader.h" +#include "gdcmPixmap.h" + +namespace gdcm +{ + +class ByteValue; +class MediaStorage; +/** + * \brief PixmapReader + * \note its role is to convert the DICOM DataSet into a gdcm::Pixmap + * representation + * By default it is also loading the lookup table and overlay when found as + * they impact the rendering or the image + * + * See PS 3.3-2008, Table C.7-11b IMAGE PIXEL MACRO ATTRIBUTES for the list of + * attribute that belong to what gdcm calls a 'Pixmap' + * + * \warning the API ReadUpToTag and ReadSelectedTag + * + * \see Pixmap + */ +class GDCM_EXPORT PixmapReader : public Reader +{ +public: + PixmapReader(); + virtual ~PixmapReader(); //needs to be virtual to ensure lack of memory leaks + + /// Read the DICOM image. There are two reason for failure: + /// 1. The input filename is not DICOM + /// 2. The input DICOM file does not contains an Pixmap. + + virtual bool Read(); + + // Following methods are valid only after a call to 'Read' + + /// Return the read image (need to call Read() first) + const Pixmap& GetPixmap() const; + Pixmap& GetPixmap(); + //void SetPixamp(Pixmap const &pix); + +protected: + bool ReadImageInternal(MediaStorage const &ms, bool handlepixeldata = true); + virtual bool ReadImage(MediaStorage const &ms); + virtual bool ReadACRNEMAImage(); + + SmartPointer PixelData; +}; + +/** + * \example StandardizeFiles.cs + * This is a C++ example on how to use gdcm::PixmapReader + */ + +} // end namespace gdcm + +#endif //GDCMPIXMAPREADER_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmPixmapToPixmapFilter.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmPixmapToPixmapFilter.cxx new file mode 100644 index 0000000..fc0b2b3 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmPixmapToPixmapFilter.cxx @@ -0,0 +1,39 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmPixmapToPixmapFilter.h" +#include "gdcmPixmap.h" + +namespace gdcm +{ + +PixmapToPixmapFilter::PixmapToPixmapFilter() +{ +} + +Pixmap &PixmapToPixmapFilter::GetInput() +{ + return dynamic_cast(*Input); +} + +const Pixmap &PixmapToPixmapFilter::GetOutput() const +{ + return dynamic_cast(*Output); +} + +const Pixmap &PixmapToPixmapFilter::GetOutputAsPixmap() const +{ + return dynamic_cast(*Output); +} + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmPixmapToPixmapFilter.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmPixmapToPixmapFilter.h new file mode 100644 index 0000000..9ffe06c --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmPixmapToPixmapFilter.h @@ -0,0 +1,44 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMPIXMAPTOPIXMAPFILTER_H +#define GDCMPIXMAPTOPIXMAPFILTER_H + +#include "gdcmBitmapToBitmapFilter.h" + +namespace gdcm +{ + +class Pixmap; +/** + * \brief PixmapToPixmapFilter class + * Super class for all filter taking an image and producing an output image + */ +class GDCM_EXPORT PixmapToPixmapFilter : public BitmapToBitmapFilter +{ +public: + PixmapToPixmapFilter(); + ~PixmapToPixmapFilter() {} + + Pixmap &GetInput(); + + /// Get Output image + const Pixmap &GetOutput() const; + + // SWIG/Java hack: + const Pixmap &GetOutputAsPixmap() const; +}; + +} // end namespace gdcm + +#endif //GDCMPIXMAPTOPIXMAPFILTER_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmPixmapWriter.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmPixmapWriter.cxx new file mode 100644 index 0000000..d943944 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmPixmapWriter.cxx @@ -0,0 +1,680 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmPixmapWriter.h" +#include "gdcmTrace.h" +#include "gdcmDataSet.h" +#include "gdcmDataElement.h" +#include "gdcmAttribute.h" +#include "gdcmUIDGenerator.h" +#include "gdcmSystem.h" +#include "gdcmPixmap.h" +#include "gdcmLookupTable.h" +#include "gdcmItem.h" +#include "gdcmSequenceOfItems.h" + +namespace gdcm +{ + +PixmapWriter::PixmapWriter():PixelData(new Pixmap) +{ +} + +PixmapWriter::~PixmapWriter() +{ +} + +void PixmapWriter::SetPixmap(Pixmap const &img) +{ + PixelData = img; +} + +void PixmapWriter::DoIconImage(DataSet & rootds, Pixmap const & image) +{ + //const Tag ticonimage(0x0088,0x0200); + const IconImage &icon = image.GetIconImage(); + if( !icon.IsEmpty() ) + { + //DataElement iconimagesq = rootds.GetDataElement( ticonimage ); + //iconimagesq.SetTag( ticonimage ); + DataElement iconimagesq; + iconimagesq.SetTag( Attribute<0x0088,0x0200>::GetTag() ); + iconimagesq.SetVR( VR::SQ ); + SmartPointer sq = new SequenceOfItems; + sq->SetLengthToUndefined(); + + DataSet ds; + //SequenceOfItems* sq = iconimagesq.GetSequenceOfItems(); + //// Is SQ empty ? + //if( !sq ) return; + //SequenceOfItems::Iterator it = sq->Begin(); + //DataSet &ds = it->GetNestedDataSet(); + + // col & rows: + Attribute<0x0028, 0x0011> columns; + columns.SetValue( (uint16_t)icon.GetDimension(0) ); + ds.Insert( columns.GetAsDataElement() ); + + Attribute<0x0028, 0x0010> rows; + rows.SetValue( (uint16_t)icon.GetDimension(1) ); + ds.Insert( rows.GetAsDataElement() ); + + PixelFormat pf = icon.GetPixelFormat(); + Attribute<0x0028, 0x0100> bitsallocated; + bitsallocated.SetValue( pf.GetBitsAllocated() ); + ds.Replace( bitsallocated.GetAsDataElement() ); + + Attribute<0x0028, 0x0101> bitsstored; + bitsstored.SetValue( pf.GetBitsStored() ); + ds.Replace( bitsstored.GetAsDataElement() ); + + Attribute<0x0028, 0x0102> highbit; + highbit.SetValue( pf.GetHighBit() ); + ds.Replace( highbit.GetAsDataElement() ); + + Attribute<0x0028, 0x0103> pixelrepresentation; + pixelrepresentation.SetValue( pf.GetPixelRepresentation() ); + ds.Replace( pixelrepresentation.GetAsDataElement() ); + + Attribute<0x0028, 0x0002> samplesperpixel; + samplesperpixel.SetValue( pf.GetSamplesPerPixel() ); + ds.Replace( samplesperpixel.GetAsDataElement() ); + + if( pf.GetSamplesPerPixel() != 1 ) + { + Attribute<0x0028, 0x0006> planarconf; + planarconf.SetValue( (uint16_t)icon.GetPlanarConfiguration() ); + ds.Replace( planarconf.GetAsDataElement() ); + } + PhotometricInterpretation pi = icon.GetPhotometricInterpretation(); +Attribute<0x0028,0x0004> piat; + const char *pistr = PhotometricInterpretation::GetPIString(pi); +{ + DataElement de( Tag(0x0028, 0x0004 ) ); + VL::Type strlenPistr = (VL::Type)strlen(pistr); + de.SetByteValue( pistr, strlenPistr ); + de.SetVR( piat.GetVR() ); + ds.Replace( de ); +} + + if ( pi == PhotometricInterpretation::PALETTE_COLOR ) + { + const LookupTable &lut = icon.GetLUT(); + assert( (pf.GetBitsAllocated() == 8 && pf.GetPixelRepresentation() == 0) + || (pf.GetBitsAllocated() == 16 && pf.GetPixelRepresentation() == 0) ); + // lut descriptor: + // (0028,1101) US 256\0\16 # 6, 3 RedPaletteColorLookupTableDescriptor + // (0028,1102) US 256\0\16 # 6, 3 GreenPaletteColorLookupTableDescriptor + // (0028,1103) US 256\0\16 # 6, 3 BluePaletteColorLookupTableDescriptor + // lut data: + unsigned short length, subscript, bitsize; + //unsigned short rawlut8[256]; + std::vector rawlut8; + rawlut8.resize(256); + //unsigned short rawlut16[65536]; + std::vector rawlut16; + unsigned short *rawlut = &rawlut8[0]; + unsigned int lutlen = 256; + if( pf.GetBitsAllocated() == 16 ) + { + rawlut16.resize(65536); + rawlut = &rawlut16[0]; + lutlen = 65536; + } + unsigned int l; + + // FIXME: should I really clear rawlut each time ? + // RED + memset(rawlut,0,lutlen*2); + lut.GetLUT(LookupTable::RED, (unsigned char*)rawlut, l); + DataElement redde( Tag(0x0028, 0x1201) ); + redde.SetVR( VR::OW ); + redde.SetByteValue( (char*)rawlut, l); + ds.Replace( redde ); + // descriptor: + Attribute<0x0028, 0x1101, VR::US, VM::VM3> reddesc; + lut.GetLUTDescriptor(LookupTable::RED, length, subscript, bitsize); + reddesc.SetValue(length,0); reddesc.SetValue(subscript,1); reddesc.SetValue(bitsize,2); + ds.Replace( reddesc.GetAsDataElement() ); + + // GREEN + memset(rawlut,0,lutlen*2); + lut.GetLUT(LookupTable::GREEN, (unsigned char*)rawlut, l); + DataElement greende( Tag(0x0028, 0x1202) ); + greende.SetVR( VR::OW ); + greende.SetByteValue( (char*)rawlut, l); + ds.Replace( greende ); + // descriptor: + Attribute<0x0028, 0x1102, VR::US, VM::VM3> greendesc; + lut.GetLUTDescriptor(LookupTable::GREEN, length, subscript, bitsize); + greendesc.SetValue(length,0); greendesc.SetValue(subscript,1); greendesc.SetValue(bitsize,2); + ds.Replace( greendesc.GetAsDataElement() ); + + // BLUE + memset(rawlut,0,lutlen*2); + lut.GetLUT(LookupTable::BLUE, (unsigned char*)rawlut, l); + DataElement bluede( Tag(0x0028, 0x1203) ); + bluede.SetVR( VR::OW ); + bluede.SetByteValue( (char*)rawlut, l); + ds.Replace( bluede ); + // descriptor: + Attribute<0x0028, 0x1103, VR::US, VM::VM3> bluedesc; + lut.GetLUTDescriptor(LookupTable::BLUE, length, subscript, bitsize); + bluedesc.SetValue(length,0); bluedesc.SetValue(subscript,1); bluedesc.SetValue(bitsize,2); + ds.Replace( bluedesc.GetAsDataElement() ); + } + + //ds.Remove( Tag(0x0028, 0x1221) ); + //ds.Remove( Tag(0x0028, 0x1222) ); + //ds.Remove( Tag(0x0028, 0x1223) ); + + + { + // Pixel Data + DataElement de( Tag(0x7fe0,0x0010) ); + const Value &v = icon.GetDataElement().GetValue(); + de.SetValue( v ); + const ByteValue *bv = de.GetByteValue(); + const TransferSyntax &ts = icon.GetTransferSyntax(); + assert( ts.IsExplicit() || ts.IsImplicit() ); + VL vl; + if( bv ) + { + // if ts is explicit -> set VR + vl = bv->GetLength(); + } + else + { + // if ts is explicit -> set VR + vl.SetToUndefined(); + } + if( ts.IsExplicit() ) + { + switch ( pf.GetBitsAllocated() ) + { + case 8: + de.SetVR( VR::OB ); + break; + //case 12: + case 16: + case 32: + de.SetVR( VR::OW ); + break; + default: + assert( 0 && "should not happen" ); + break; + } + } + else + { + de.SetVR( VR::OB ); + } + de.SetVL( vl ); + ds.Replace( de ); +} + + Item item; + item.SetNestedDataSet( ds ); + sq->AddItem( item ); + iconimagesq.SetValue( *sq ); + + rootds.Replace( iconimagesq ); + + } +} + +bool PixmapWriter::PrepareWrite() +{ + File& file = GetFile(); + DataSet& ds = file.GetDataSet(); + + FileMetaInformation &fmi_orig = file.GetHeader(); + const TransferSyntax &ts_orig = fmi_orig.GetDataSetTransferSyntax(); + + // col & rows: + Attribute<0x0028, 0x0011> columns; + columns.SetValue( (uint16_t)PixelData->GetDimension(0) ); + ds.Replace( columns.GetAsDataElement() ); + + Attribute<0x0028, 0x0010> rows; + rows.SetValue( (uint16_t)PixelData->GetDimension(1) ); + ds.Replace( rows.GetAsDataElement() ); + + // (0028,0008) IS [12] # 2, 1 NumberOfFrames + const Tag tnumberofframes = Tag(0x0028, 0x0008); + if( PixelData->GetNumberOfDimensions() == 3 ) + { + Attribute<0x0028, 0x0008> numberofframes; + assert( PixelData->GetDimension(2) >= 1 ); + numberofframes.SetValue( PixelData->GetDimension(2) ); + ds.Replace( numberofframes.GetAsDataElement() ); + } + else if( ds.FindDataElement(tnumberofframes) ) // Remove Number Of Frames + { + assert( PixelData->GetNumberOfDimensions() == 2 ); + assert( PixelData->GetDimension(2) == 1 ); + ds.Remove( tnumberofframes ); + } + + PixelFormat pf = PixelData->GetPixelFormat(); + if ( !pf.IsValid() ) + { + gdcmWarningMacro( "Pixel format is not valid: " << pf ); + return false; + } + PhotometricInterpretation pi = PixelData->GetPhotometricInterpretation(); + if( pi.GetSamplesPerPixel() != pf.GetSamplesPerPixel() ) + { + gdcmWarningMacro( "Photometric Interpretation and Pixel format are not compatible: " + << pi.GetSamplesPerPixel() << " vs " << pf.GetSamplesPerPixel() ); + return false; + } + + { + assert( pi != PhotometricInterpretation::UNKNOW ); + const char *pistr = PhotometricInterpretation::GetPIString(pi); + DataElement de( Tag(0x0028, 0x0004 ) ); + VL::Type strlenPistr = (VL::Type)strlen(pistr); + de.SetByteValue( pistr, strlenPistr ); + de.SetVR( Attribute<0x0028,0x0004>::GetVR() ); + ds.Replace( de ); + } + + // Pixel Format : + // (0028,0100) US 8 # 2, 1 BitsAllocated + // (0028,0101) US 8 # 2, 1 BitsStored + // (0028,0102) US 7 # 2, 1 HighBit + // (0028,0103) US 0 # 2, 1 PixelRepresentation + Attribute<0x0028, 0x0100> bitsallocated; + bitsallocated.SetValue( pf.GetBitsAllocated() ); + ds.Replace( bitsallocated.GetAsDataElement() ); + + Attribute<0x0028, 0x0101> bitsstored; + bitsstored.SetValue( pf.GetBitsStored() ); + ds.Replace( bitsstored.GetAsDataElement() ); + + Attribute<0x0028, 0x0102> highbit; + highbit.SetValue( pf.GetHighBit() ); + ds.Replace( highbit.GetAsDataElement() ); + + Attribute<0x0028, 0x0103> pixelrepresentation; + pixelrepresentation.SetValue( pf.GetPixelRepresentation() ); + ds.Replace( pixelrepresentation.GetAsDataElement() ); + + Attribute<0x0028, 0x0002> samplesperpixel; + samplesperpixel.SetValue( pf.GetSamplesPerPixel() ); + ds.Replace( samplesperpixel.GetAsDataElement() ); + + if( pf.GetSamplesPerPixel() != 1 ) + { + Attribute<0x0028, 0x0006> planarconf; + planarconf.SetValue( (uint16_t)PixelData->GetPlanarConfiguration() ); + ds.Replace( planarconf.GetAsDataElement() ); + } + + // Overlay Data 60xx + gdcm::SequenceOfItems::SizeType nOv = PixelData->GetNumberOfOverlays(); + for(gdcm::SequenceOfItems::SizeType ovidx = 0; ovidx < nOv; ++ovidx ) + { + // (6000,0010) US 484 # 2, 1 OverlayRows + // (6000,0011) US 484 # 2, 1 OverlayColumns + // (6000,0015) IS [1] # 2, 1 NumberOfFramesInOverlay + // (6000,0022) LO [Siemens MedCom Object Graphics] # 30, 1 OverlayDescription + // (6000,0040) CS [G] # 2, 1 OverlayType + // (6000,0050) SS 1\1 # 4, 2 OverlayOrigin + // (6000,0051) US 1 # 2, 1 ImageFrameOrigin + // (6000,0100) US 1 # 2, 1 OverlayBitsAllocated + // (6000,0102) US 0 # 2, 1 OverlayBitPosition + // (6000,3000) OW 0000\0000\0000\0000\0000\0000\0000\0000\0000\0000\0000\0000\0000... # 29282, 1 OverlayData + DataElement de; + const Overlay &ov = PixelData->GetOverlay(ovidx); + Attribute<0x6000,0x0010> overlayrows; + overlayrows.SetValue( ov.GetRows() ); + de = overlayrows.GetAsDataElement(); + de.GetTag().SetGroup( ov.GetGroup() ); + ds.Replace( de ); + Attribute<0x6000,0x0011> overlaycolumns; + overlaycolumns.SetValue( ov.GetColumns() ); + de = overlaycolumns.GetAsDataElement(); + de.GetTag().SetGroup( ov.GetGroup() ); + ds.Replace( de ); + if( ov.GetDescription() ) // Type 3 + { + Attribute<0x6000,0x0022> overlaydescription; + overlaydescription.SetValue( ov.GetDescription() ); + de = overlaydescription.GetAsDataElement(); + de.GetTag().SetGroup( ov.GetGroup() ); + ds.Replace( de ); + } + Attribute<0x6000,0x0040> overlaytype; // 'G' or 'R' + overlaytype.SetValue( ov.GetType() ); + de = overlaytype.GetAsDataElement(); + de.GetTag().SetGroup( ov.GetGroup() ); + ds.Replace( de ); + Attribute<0x6000,0x0050> overlayorigin; + overlayorigin.SetValues( ov.GetOrigin() ); + de = overlayorigin.GetAsDataElement(); + de.GetTag().SetGroup( ov.GetGroup() ); + ds.Replace( de ); + Attribute<0x6000,0x0100> overlaybitsallocated; + overlaybitsallocated.SetValue( ov.GetBitsAllocated() ); + de = overlaybitsallocated.GetAsDataElement(); + de.GetTag().SetGroup( ov.GetGroup() ); + ds.Replace( de ); + Attribute<0x6000,0x0102> overlaybitposition; + overlaybitposition.SetValue( ov.GetBitPosition() ); + de = overlaybitposition.GetAsDataElement(); + de.GetTag().SetGroup( ov.GetGroup() ); + ds.Replace( de ); + + // FIXME: for now rewrite 'Overlay in pixel data' still in the pixel data element... + //if( !ov.IsInPixelData() ) + { + const ByteValue & overlaydatabv = ov.GetOverlayData(); + DataElement overlaydata( Tag(0x6000,0x3000) ); + overlaydata.SetByteValue( overlaydatabv.GetPointer(), overlaydatabv.GetLength() ); + overlaydata.SetVR( VR::OW ); // FIXME + overlaydata.GetTag().SetGroup( ov.GetGroup() ); + ds.Replace( overlaydata ); + } + } + + // Pixel Data + DataElement depixdata( Tag(0x7fe0,0x0010) ); + const Value &v = PixelData->GetDataElement().GetValue(); + depixdata.SetValue( v ); + const ByteValue *bvpixdata = depixdata.GetByteValue(); + const TransferSyntax &ts = PixelData->GetTransferSyntax(); + assert( ts.IsExplicit() || ts.IsImplicit() ); + + // It is perfectly ok to store a lossy image using a J2K (this is odd, but valid). + // as long as your mark LossyImageCompression with value 1 +#if 0 + // if ts_orig is undefined we need to check ts of Pixel Data comply with itself + if( ts_orig == TransferSyntax::TS_END ) + { + if( !ts.CanStoreLossy() && PixelData->IsLossy() ) + { + gdcmWarningMacro( "Sorry Pixel Data in encapsulated stream was found to be " + "lossy while Transfer Syntax does not authorized that" ); + return false; + } + // Obviously we could also be checking the contrary: trying to store a + // lossless compressed JPEG file using a lossy JPEG (compatible) one. But I + // do not believe this is an error in this case. + } +#endif + + if( /*ts.IsLossy() &&*/ PixelData->IsLossy() ) + { + Attribute<0x0028,0x2110> at1; + Attribute<0x0028,0x2114> at3; + if( ts_orig == TransferSyntax::TS_END ) + { + // Add the Lossy stuff: + at1.SetValue( "01" ); + ds.Replace( at1.GetAsDataElement() ); + } + else if( ts_orig.IsLossy() ) + { + // Add the Lossy stuff: + at1.SetValue( "01" ); + ds.Replace( at1.GetAsDataElement() ); + /* + The Defined Terms for Lossy Image Compression Method (0028,2114) are : + ISO_10918_1 = JPEG Lossy Compression + ISO_14495_1 = JPEG-LS Near-lossless Compression + ISO_15444_1 = JPEG 2000 Irreversible Compression + ISO_13818_2 = MPEG2 Compression + */ + + if( ts_orig == TransferSyntax::JPEG2000 ) + { + static const CSComp newvalues2[] = {"ISO_15444_1"}; + at3.SetValues( newvalues2, 1 ); + } + else if( ts_orig == TransferSyntax::JPEGLSNearLossless ) + { + static const CSComp newvalues2[] = {"ISO_14495_1"}; + at3.SetValues( newvalues2, 1 ); + } + else if ( + ts_orig == TransferSyntax::JPEGBaselineProcess1 || + ts_orig == TransferSyntax::JPEGExtendedProcess2_4 || + ts_orig == TransferSyntax::JPEGExtendedProcess3_5 || + ts_orig == TransferSyntax::JPEGSpectralSelectionProcess6_8 || + ts_orig == TransferSyntax::JPEGFullProgressionProcess10_12 ) + { + static const CSComp newvalues2[] = {"ISO_10918_1"}; + at3.SetValues( newvalues2, 1 ); + } + else + { + gdcmErrorMacro( + "Pixel Data is lossy but I cannot find the original transfer syntax" ); + return false; + } + ds.Replace( at3.GetAsDataElement() ); + } + else + { + assert( ds.FindDataElement( at1.GetTag() ) ); + assert( ds.FindDataElement( at3.GetTag() ) ); + at1.Set( ds ); + assert( atoi(at1.GetValue().c_str()) == 1 ); + } + } + + VL vl; + if( bvpixdata ) + { + // if ts is explicit -> set VR + vl = bvpixdata->GetLength(); + } + else + { + // if ts is explicit -> set VR + vl.SetToUndefined(); + } + if( ts.IsExplicit() ) + { + switch ( pf.GetBitsAllocated() ) + { + case 1: + case 8: + depixdata.SetVR( VR::OB ); + break; + case 12: + case 16: + case 32: + depixdata.SetVR( VR::OW ); + break; + default: + assert( 0 && "should not happen" ); + break; + } + } + else + { + depixdata.SetVR( VR::OB ); + } + depixdata.SetVL( vl ); + ds.Replace( depixdata ); + + // Do Icon Image + DoIconImage(ds, GetPixmap()); + + MediaStorage ms; + ms.SetFromFile( GetFile() ); + assert( ms != MediaStorage::MS_END ); + + // Most SOP Class support 2D, but let's make sure that 3D is ok: + if( PixelData->GetNumberOfDimensions() > 2 ) + { + if( ms.GetModalityDimension() < PixelData->GetNumberOfDimensions() ) + { + gdcmErrorMacro( "Problem with NumberOfDimensions and MediaStorage" ); +#if 0 + return false; +#endif + } + } + + const char* msstr = MediaStorage::GetMSString(ms); + if( !ds.FindDataElement( Tag(0x0008, 0x0016) ) ) + { + DataElement de( Tag(0x0008, 0x0016 ) ); + VL::Type strlenMsstr = (VL::Type)strlen(msstr); + de.SetByteValue( msstr, strlenMsstr); + de.SetVR( Attribute<0x0008, 0x0016>::GetVR() ); + ds.Insert( de ); + } + else + { + const ByteValue *bv = ds.GetDataElement( Tag(0x0008,0x0016) ).GetByteValue(); + if( !bv ) + { + gdcmErrorMacro( "Cant be empty" ); + return false; + } + if( strncmp( bv->GetPointer(), msstr, bv->GetLength() ) != 0 ) + { + DataElement de = ds.GetDataElement( Tag(0x0008,0x0016) ); + VL::Type strlenMsstr = (VL::Type) strlen(msstr); + de.SetByteValue( msstr, strlenMsstr ); + ds.Replace( de ); + } + else + { + assert( bv->GetLength() == strlen( msstr ) || bv->GetLength() == strlen(msstr) + 1 ); + } + } + + // UIDs: + // (0008,0018) UI [1.3.6.1.4.1.5962.1.1.1.1.3.20040826185059.5457] # 46, 1 SOPInstanceUID + // (0020,000d) UI [1.3.6.1.4.1.5962.1.2.1.20040826185059.5457] # 42, 1 StudyInstanceUID + // (0020,000e) UI [1.3.6.1.4.1.5962.1.3.1.1.20040826185059.5457] # 44, 1 SeriesInstanceUID + UIDGenerator uid; + + // Be careful with the SOP Instance UID: + if( ds.FindDataElement( Tag(0x0008, 0x0018) ) && false ) + { + // We are coming from a real DICOM image, we need to reference it... + const Tag tsourceImageSequence(0x0008,0x2112); + SmartPointer sq; + if( ds.FindDataElement( tsourceImageSequence ) ) + { + DataElement &de = (DataElement&)ds.GetDataElement( tsourceImageSequence ); + de.SetVLToUndefined(); // For now + if( de.IsEmpty() ) + { + sq = new SequenceOfItems; + de.SetValue( *sq ); + } + sq = de.GetValueAsSQ(); + } + else + { + sq = new SequenceOfItems; + } + sq->SetLengthToUndefined(); + Item item; //( /*Tag(0xfffe,0xe000)*/ ); + //DataSet sourceimageds; + // (0008,1150) UI =MRImageStorage # 26, 1 ReferencedSOPClassUID + // (0008,1155) UI [1.3.6.1.4.17434.1.1.5.2.1160650698.1160650698.0] # 48, 1 ReferencedSOPInstanceUID + DataElement referencedSOPClassUID = ds.GetDataElement( Tag(0x0008,0x0016) ); + referencedSOPClassUID.SetTag( Tag(0x0008,0x1150 ) ); + DataElement referencedSOPInstanceUID = ds.GetDataElement( Tag(0x0008,0x0018) ); + referencedSOPInstanceUID.SetTag( Tag(0x0008,0x1155) ); + //item.SetNestedDataSet( sourceimageds ); + item.SetVLToUndefined(); + item.InsertDataElement( referencedSOPClassUID ); + item.InsertDataElement( referencedSOPInstanceUID ); + sq->AddItem( item ); + if( !ds.FindDataElement( tsourceImageSequence ) ) + { + DataElement de( tsourceImageSequence ); + de.SetVR( VR::SQ ); + de.SetValue( *sq ); + de.SetVLToUndefined(); + //std::cout << de << std::endl; + ds.Insert( de ); + } + } + { + const char *sop = uid.Generate(); + DataElement de( Tag(0x0008,0x0018) ); + VL::Type strlenSOP = (VL::Type) strlen(sop); + de.SetByteValue( sop, strlenSOP ); + de.SetVR( Attribute<0x0008, 0x0018>::GetVR() ); + ds.ReplaceEmpty( de ); + } + + // Are we on a particular Study ? If not create a new UID + if( !ds.FindDataElement( Tag(0x0020, 0x000d) ) ) + { + const char *study = uid.Generate(); + DataElement de( Tag(0x0020,0x000d) ); + VL::Type strlenStudy= (VL::Type)strlen(study); + de.SetByteValue( study, strlenStudy ); + de.SetVR( Attribute<0x0020, 0x000d>::GetVR() ); + ds.ReplaceEmpty( de ); + } + + // Are we on a particular Series ? If not create a new UID + if( !ds.FindDataElement( Tag(0x0020, 0x000e) ) ) + { + const char *series = uid.Generate(); + DataElement de( Tag(0x0020,0x000e) ); + VL::Type strlenSeries= (VL::Type)strlen(series); + de.SetByteValue( series, strlenSeries ); + de.SetVR( Attribute<0x0020, 0x000e>::GetVR() ); + ds.ReplaceEmpty( de ); + } + + FileMetaInformation &fmi = file.GetHeader(); + fmi.Clear(); + //assert( ts == TransferSyntax::ImplicitVRLittleEndian ); + { + const char *tsuid = TransferSyntax::GetTSString( ts ); + DataElement de( Tag(0x0002,0x0010) ); + VL::Type strlenTSUID = (VL::Type)strlen(tsuid); + de.SetByteValue( tsuid, strlenTSUID ); + de.SetVR( Attribute<0x0002, 0x0010>::GetVR() ); + fmi.Replace( de ); + fmi.SetDataSetTransferSyntax(ts); + } + fmi.FillFromDataSet( ds ); + + + return true; +} + +bool PixmapWriter::Write() +{ + if( !PrepareWrite() ) return false; + + assert( Stream ); + if( !Writer::Write() ) + { + return false; + } + return true; +} + +void PixmapWriter::SetImage(Pixmap const &img) +{ + PixelData = img; +} + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmPixmapWriter.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmPixmapWriter.h new file mode 100644 index 0000000..d1ed486 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmPixmapWriter.h @@ -0,0 +1,70 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMPIXMAPWRITER_H +#define GDCMPIXMAPWRITER_H + +#include "gdcmWriter.h" +#include "gdcmPixmap.h" + +namespace gdcm +{ + +class StreamImageWriter; +class Pixmap; +/** + * \brief PixmapWriter + * This class will takes two inputs: + * 1. The DICOM DataSet + * 2. The Image input + * It will override any info from the Image over the DataSet. + * + * For instance when one read in a lossy compressed image and write out as unencapsulated + * (ie implicitely lossless) then some attribute are definitely needed to mark this + * dataset as Lossy (typically 0028,2114) + */ +class GDCM_EXPORT PixmapWriter : public Writer +{ +public: + PixmapWriter(); + ~PixmapWriter(); + + const Pixmap& GetPixmap() const { return *PixelData; } + Pixmap& GetPixmap() { return *PixelData; } // FIXME + void SetPixmap(Pixmap const &img); + + /// Set/Get Pixmap to be written + /// It will overwrite anything Pixmap infos found in DataSet + /// (see parent class to see how to pass dataset) + virtual const Pixmap& GetImage() const { return *PixelData; } + virtual Pixmap& GetImage() { return *PixelData; } // FIXME + virtual void SetImage(Pixmap const &img); + + /// Write + bool Write(); // Execute() + +protected: + void DoIconImage(DataSet & ds, Pixmap const & image); + bool PrepareWrite(); + + SmartPointer PixelData; +}; + +/** + * \example StandardizeFiles.cs + * This is a C++ example on how to use gdcm::PixmapWriter + */ + +} // end namespace gdcm + +#endif //GDCMPIXMAPWRITER_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmPrinter.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmPrinter.cxx new file mode 100644 index 0000000..6dfacf8 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmPrinter.cxx @@ -0,0 +1,991 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmPrinter.h" +#include "gdcmSequenceOfItems.h" +#include "gdcmSequenceOfFragments.h" +#include "gdcmDict.h" +#include "gdcmDicts.h" +#include "gdcmGroupDict.h" +#include "gdcmVR.h" +#include "gdcmVM.h" +#include "gdcmElement.h" +#include "gdcmGlobal.h" +#include "gdcmAttribute.h" +#include "gdcmDataSetHelper.h" + +#include "gdcmDataSet.h" + +#include // for typeid + +#define gdcm_terminal_vt100_normal "\33[0m" +#define gdcm_terminal_vt100_bold "\33[1m" +#define gdcm_terminal_vt100_underline "\33[4m" +#define gdcm_terminal_vt100_blink "\33[5m" +#define gdcm_terminal_vt100_inverse "\33[7m" +#define gdcm_terminal_vt100_foreground_black "\33[30m" +#define gdcm_terminal_vt100_foreground_red "\33[31m" +#define gdcm_terminal_vt100_foreground_green "\33[32m" +#define gdcm_terminal_vt100_foreground_yellow "\33[33m" +#define gdcm_terminal_vt100_foreground_blue "\33[34m" +#define gdcm_terminal_vt100_foreground_magenta "\33[35m" +#define gdcm_terminal_vt100_foreground_cyan "\33[36m" +#define gdcm_terminal_vt100_foreground_white "\33[37m" +#define gdcm_terminal_vt100_background_black "\33[40m" +#define gdcm_terminal_vt100_background_red "\33[41m" +#define gdcm_terminal_vt100_background_green "\33[42m" +#define gdcm_terminal_vt100_background_yellow "\33[43m" +#define gdcm_terminal_vt100_background_blue "\33[44m" +#define gdcm_terminal_vt100_background_magenta "\33[45m" +#define gdcm_terminal_vt100_background_cyan "\33[46m" +#define gdcm_terminal_vt100_background_white "\33[47m" + +static const char * GDCM_TERMINAL_VT100_NORMAL = ""; +static const char * GDCM_TERMINAL_VT100_BOLD = ""; +static const char * GDCM_TERMINAL_VT100_UNDERLINE = ""; +static const char * GDCM_TERMINAL_VT100_BLINK = ""; +static const char * GDCM_TERMINAL_VT100_INVERSE = ""; +static const char * GDCM_TERMINAL_VT100_FOREGROUND_BLACK = ""; +static const char * GDCM_TERMINAL_VT100_FOREGROUND_RED = ""; +static const char * GDCM_TERMINAL_VT100_FOREGROUND_GREEN = ""; +static const char * GDCM_TERMINAL_VT100_FOREGROUND_YELLOW = ""; +static const char * GDCM_TERMINAL_VT100_FOREGROUND_BLUE = ""; +static const char * GDCM_TERMINAL_VT100_FOREGROUND_MAGENTA = ""; +static const char * GDCM_TERMINAL_VT100_FOREGROUND_CYAN = ""; +static const char * GDCM_TERMINAL_VT100_FOREGROUND_WHITE = ""; +static const char * GDCM_TERMINAL_VT100_BACKGROUND_BLACK = ""; +static const char * GDCM_TERMINAL_VT100_BACKGROUND_RED = ""; +static const char * GDCM_TERMINAL_VT100_BACKGROUND_GREEN = ""; +static const char * GDCM_TERMINAL_VT100_BACKGROUND_YELLOW = ""; +static const char * GDCM_TERMINAL_VT100_BACKGROUND_BLUE = ""; +static const char * GDCM_TERMINAL_VT100_BACKGROUND_MAGENTA = ""; +static const char * GDCM_TERMINAL_VT100_BACKGROUND_CYAN = ""; +static const char * GDCM_TERMINAL_VT100_BACKGROUND_WHITE = ""; + +namespace gdcm +{ +//----------------------------------------------------------------------------- +Printer::Printer():PrintStyle(Printer::VERBOSE_STYLE),F(0) +{ + MaxPrintLength = 0x100; // Need to be %2 + +} + +//----------------------------------------------------------------------------- +Printer::~Printer() +{ +} + +void Printer::SetColor(bool c) +{ + if( c ) + { + GDCM_TERMINAL_VT100_NORMAL = gdcm_terminal_vt100_normal ; + GDCM_TERMINAL_VT100_BOLD = gdcm_terminal_vt100_bold ; + GDCM_TERMINAL_VT100_UNDERLINE = gdcm_terminal_vt100_underline ; + GDCM_TERMINAL_VT100_BLINK = gdcm_terminal_vt100_blink ; + GDCM_TERMINAL_VT100_INVERSE = gdcm_terminal_vt100_inverse ; + GDCM_TERMINAL_VT100_FOREGROUND_BLACK = gdcm_terminal_vt100_foreground_black ; + GDCM_TERMINAL_VT100_FOREGROUND_RED = gdcm_terminal_vt100_foreground_red ; + GDCM_TERMINAL_VT100_FOREGROUND_GREEN = gdcm_terminal_vt100_foreground_green ; + GDCM_TERMINAL_VT100_FOREGROUND_YELLOW = gdcm_terminal_vt100_foreground_yellow ; + GDCM_TERMINAL_VT100_FOREGROUND_BLUE = gdcm_terminal_vt100_foreground_blue ; + GDCM_TERMINAL_VT100_FOREGROUND_MAGENTA = gdcm_terminal_vt100_foreground_magenta ; + GDCM_TERMINAL_VT100_FOREGROUND_CYAN = gdcm_terminal_vt100_foreground_cyan ; + GDCM_TERMINAL_VT100_FOREGROUND_WHITE = gdcm_terminal_vt100_foreground_white ; + GDCM_TERMINAL_VT100_BACKGROUND_BLACK = gdcm_terminal_vt100_background_black ; + GDCM_TERMINAL_VT100_BACKGROUND_RED = gdcm_terminal_vt100_background_red ; + GDCM_TERMINAL_VT100_BACKGROUND_GREEN = gdcm_terminal_vt100_background_green ; + GDCM_TERMINAL_VT100_BACKGROUND_YELLOW = gdcm_terminal_vt100_background_yellow ; + GDCM_TERMINAL_VT100_BACKGROUND_BLUE = gdcm_terminal_vt100_background_blue ; + GDCM_TERMINAL_VT100_BACKGROUND_MAGENTA = gdcm_terminal_vt100_background_magenta ; + GDCM_TERMINAL_VT100_BACKGROUND_CYAN = gdcm_terminal_vt100_background_cyan ; + GDCM_TERMINAL_VT100_BACKGROUND_WHITE = gdcm_terminal_vt100_background_white ; + } + else + { + GDCM_TERMINAL_VT100_NORMAL = ""; + GDCM_TERMINAL_VT100_BOLD = ""; + GDCM_TERMINAL_VT100_UNDERLINE = ""; + GDCM_TERMINAL_VT100_BLINK = ""; + GDCM_TERMINAL_VT100_INVERSE = ""; + GDCM_TERMINAL_VT100_FOREGROUND_BLACK = ""; + GDCM_TERMINAL_VT100_FOREGROUND_RED = ""; + GDCM_TERMINAL_VT100_FOREGROUND_GREEN = ""; + GDCM_TERMINAL_VT100_FOREGROUND_YELLOW = ""; + GDCM_TERMINAL_VT100_FOREGROUND_BLUE = ""; + GDCM_TERMINAL_VT100_FOREGROUND_MAGENTA = ""; + GDCM_TERMINAL_VT100_FOREGROUND_CYAN = ""; + GDCM_TERMINAL_VT100_FOREGROUND_WHITE = ""; + GDCM_TERMINAL_VT100_BACKGROUND_BLACK = ""; + GDCM_TERMINAL_VT100_BACKGROUND_RED = ""; + GDCM_TERMINAL_VT100_BACKGROUND_GREEN = ""; + GDCM_TERMINAL_VT100_BACKGROUND_YELLOW = ""; + GDCM_TERMINAL_VT100_BACKGROUND_BLUE = ""; + GDCM_TERMINAL_VT100_BACKGROUND_MAGENTA = ""; + GDCM_TERMINAL_VT100_BACKGROUND_CYAN = ""; + GDCM_TERMINAL_VT100_BACKGROUND_WHITE = ""; + + } +} + +void PrintValue(VR::VRType const &vr, VM const &vm, const Value &v); + +template +inline char *bswap(char *out, const char *in, size_t length) +{ + assert( !(length % sizeof(T)) ); + assert( out != in ); + for(size_t i = 0; i < length; i+=2) + { + //const char copy = in[i]; + out[i] = in[i+1]; + out[i+1] = in[i]; + } + return out; +} + +//----------------------------------------------------------------------------- + /* +void Printer::PrintElement(std::ostream& os, const ImplicitDataElement &ide, DictEntry const &entry) +{ + const Tag &t = _val.GetTag(); + const uint32_t vl = _val.GetVL(); + _os << t; + + if ( printVR ) + { + //_os << " (VR=" << VR::GetVRString(dictVR) << ")"; + _os << " " << VR::GetVRString(dictVR) << " "; + } + //_os << "\tVL=" << std::dec << vl << "\tValueField=["; + if( _val.GetVL() ) + { + // FIXME FIXME: + // value could dereference a NULL pointer in case of 0 length... + const Value& value = _val.GetValue(); + if( dictVR != VR::INVALID && VR::IsBinary(dictVR) ) + { + PrintValue(dictVR, vm, value); + } + else + { + _os << "[" << value << "]"; + } + } + //_os << "]"; + _os << "\t\t"; + _os << "#" << std::setw(4) << std::setfill(' ') << std::dec << vl << ", 1 "; +} + */ + +// = reinterpret_cast< const Element& > ( array ); +// os.flush(); + // memcpy( (void*)(&e), array, e.GetLength() * sizeof( VRToType::Type) ); + // bswap::Type>( (char*)(&e), array, e.GetLength() * sizeof( VRToType::Type) ); +#define PrinterTemplateSubCase1n(type,rep) \ + case VM::rep: \ + {Element e; \ + /*assert( VM::rep == VM::VM1_n );*/ \ + e.SetArray( (VRToType::Type *)array, length, true ); \ + e.Print( os ); }\ + break; +#define PrinterTemplateSubCase(type,rep) \ + case VM::rep: \ + {Element e; \ + /*assert( bv.GetLength() == VMToLength::Length * sizeof( VRToType::Type) ); */ \ + assert( bv.GetLength() == e.GetLength() * sizeof( VRToType::Type) ); \ + memcpy( (void*)(&e), array, e.GetLength() * sizeof( VRToType::Type) ); \ + e.Print( os ); }\ + break; +#define PrinterTemplateSub(type) \ +switch(vm) { \ +PrinterTemplateSubCase(type, VM1) \ +PrinterTemplateSubCase(type, VM2) \ +PrinterTemplateSubCase(type, VM3) \ +PrinterTemplateSubCase(type, VM4) \ +PrinterTemplateSubCase(type, VM5) \ +PrinterTemplateSubCase(type, VM6) \ +PrinterTemplateSubCase(type, VM24) \ +PrinterTemplateSubCase1n(type, VM1_n) \ +default: assert(0); } + +#define PrinterTemplateSub2(type) \ +switch(vm) { \ + PrinterTemplateSubCase1n(type, VM1) \ +default: assert(0); } + +#define PrinterTemplateCase(type) \ + case VR::type: \ + PrinterTemplateSub(type) \ + break; +#define PrinterTemplateCase2(type) \ + case VR::type: \ + PrinterTemplateSub2(type) \ + break; +#define PrinterTemplate() \ +switch(vr) { \ +PrinterTemplateCase(AE) \ +PrinterTemplateCase(AS) \ +PrinterTemplateCase(AT) \ +PrinterTemplateCase(CS) \ +PrinterTemplateCase(DA) \ +PrinterTemplateCase(DS) \ +PrinterTemplateCase(DT) \ +PrinterTemplateCase(FL) \ +PrinterTemplateCase(FD) \ +PrinterTemplateCase(IS) \ +PrinterTemplateCase(LO) \ +PrinterTemplateCase(LT) \ +PrinterTemplateCase2(OB) \ +PrinterTemplateCase(OF) \ +PrinterTemplateCase2(OW) \ +PrinterTemplateCase(PN) \ +PrinterTemplateCase(SH) \ +PrinterTemplateCase(SL) \ +PrinterTemplateCase(SQ) \ +PrinterTemplateCase(SS) \ +PrinterTemplateCase(ST) \ +PrinterTemplateCase(TM) \ +PrinterTemplateCase(UI) \ +PrinterTemplateCase(UL) \ +PrinterTemplateCase(UN) \ +PrinterTemplateCase(US) \ +PrinterTemplateCase(UT) \ +default: assert(0); } + +void PrintValue(VR::VRType const &vr, VM const &vm, const Value &v) +{ + try + { + const ByteValue &bv = dynamic_cast(v); + const char *array = bv.GetPointer(); + const VL &length = bv.GetLength(); + //unsigned short val = *(unsigned short*)(array); + std::ostream &os = std::cout; + + // Big phat MACRO: + PrinterTemplate() + } + catch(...) + { + // Indeed a SequenceOfFragments is not handle ... + std::cerr << "Problem in PrintValue" << std::endl; + } +} + +//----------------------------------------------------------------------------- +#if 0 +void Printer::PrintDataSet(std::ostream& os, const DataSet &ds) +{ + //ImplicitDataElement de; + Printer::PrintStyles pstyle = is.GetPrintStyle(); + (void)pstyle; + bool printVR = true; //is.GetPrintVR(); + + std::ostream &_os = std::cout; + //static const Dicts dicts; + //const Dict &d = dicts.GetPublicDict(); + static const Dict d; + static const GroupDict gd; + try + { + //while( is.Read(de) ) + DataSet::ConstIterator it = ds.Begin(); + for( ; it != ds.End(); ++it ) + { + const ImplicitDataElement &de = *it; + const Tag &t = de.GetTag(); + const DictEntry &entry = d.GetDictEntry(de.GetTag()); + // Use VR from dictionary + VR::VRType vr = entry.GetVR(); + VM::VMType vm = entry.GetVM(); + if( /*de.GetTag().GetGroup()%2 &&*/ de.GetTag().GetElement() == 0 ) + { + assert( vr == VR::INVALID || vr == VR::UL ); + assert( vm == VM::VM0 || vm == VM::VM1 ); + vr = VR::UL; + vm = VM::VM1; + } + if( vr == VR::INVALID || VR::IsBinary(vr) || VR::IsASCII( vr ) ) + { + // TODO: FIXME FIXME FIXME + if ( de.GetTag().GetElement() == 0x0 ) + { + if( vr == VR::INVALID ) // not found + { + vr = VR::UL; // this is a group length (VR=UL,VM=1) + } + } + if( vr == VR::INVALID && entry.GetVR() != VR::INVALID ) + { + vr = entry.GetVR(); + } + // TODO FIXME FIXME FIXME + // Data Element (7FE0,0010) Pixel Data has the Value Representation + // OW and shall be encoded in Little Endian. + //VM::VMType vm = VM::VM1; + if( t == Tag(0x7fe0,0x0010) ) + { + assert( vr == VR::OB_OW ); + vr = VR::OW; + //vm = VM::VM1_n; + } + // RETIRED: + // See PS 3.5 - 2004 + // Data Element (50xx,3000) Curve Data has the Value Representation OB + // with its component points (n-tuples) having the Value Representation + // specified in Data Value Representation (50xx,0103). + // The component points shall be encoded in Little Endian. + else if( t == Tag(0x5004,0x3000) ) // FIXME + { + assert( vr == VR::OB_OW ); + vr = VR::OB; + } + // Value of pixels not present in the native image added to an image + // to pad to rectangular format. See C.7.5.1.1.2 for further explanation. + // Note: The Value Representation of this Attribute is determined + // by the value of Pixel Representation (0028,0103). + if( vr == VR::US_SS ) + { + if( t == Tag(0x0028,0x0120) // Pixel Padding Value + || t == Tag(0x0028,0x0106) // Smallest Image Pixel Value + || t == Tag(0x0028,0x0107) // Largest Image Pixel Value + || t == Tag(0x0028,0x0108) // Smallest Pixel Value in Series + || t == Tag(0x0028,0x0109) // Largest Pixel Value in Series + || t == Tag(0x0028,0x1101) // Red Palette Color Lookup Table Descriptor + || t == Tag(0x0028,0x1102) // Green Palette Color Lookup Table Descriptor + || t == Tag(0x0028,0x1103) // Blue Palette Color Lookup Table Descriptor + ) + { + // TODO It would be nice to have a TagToVR<0x0028,0x0103>::VRType + // and TagToVM<0x0028,0x0103>::VMType ... + // to be able to have an independant Standard from implementation :) + const ImplicitDataElement &pixel_rep = + ds.GetDataElement( Tag(0x0028, 0x0103) ); + const Value &value = pixel_rep.GetValue(); + const ByteValue &bv = static_cast(value); + // FIXME: + unsigned short pixel_rep_value = *(unsigned short*)(bv.GetPointer()); + assert( pixel_rep_value == 0x0 || pixel_rep_value == 0x1 ); + vr = pixel_rep_value ? VR::SS : VR::US; + } + else + { + assert(0); + } + } + + PrintImplicitDataElement(_os, de, printVR, vr /*entry.GetVR()*/, vm); + } + else + { + assert(0); + const Value& val = de.GetValue(); + _os << de.GetTag(); + if ( printVR ) + { + //_os << " ?VR=" << vr; + _os << " " << vr; + } + //_os << "\tVL=" << std::dec << de.GetVL() << "\tValueField=["; + _os << "\t" << std::dec << de.GetVL() << "\tValueField=["; + + // Use super class of the template stuff + //Attribute af; + //// Last minute check, is it a Group Length: + //af.SetVR(vr); + //af.SetVM(vm); + //af.SetLength( val.GetLength() ); + //std::istringstream iss; + //iss.str( std::string( val.GetPointer(), val.GetLength() ) ); + //af.Read( iss ); + //af.Print( _os ); + _os << "]"; + } + if( de.GetTag().GetElement() == 0x0 ) + { + _os << "\t\t" << gd.GetName(de.GetTag().GetGroup() ) + << " " << entry.GetName() << std::endl; + } + else + { +// _os.flush(); +// std::streampos pos = _os.tellp(); +// streambuf *s = _os.rdbuf(); + //int pos = _os.str().size(); + _os << " " << entry.GetName() << std::endl; + } + } + } + catch(std::exception &e) + { + std::cerr << "Exception:" << typeid(e).name() << std::endl; + } +} +#endif + +// TODO / FIXME +// SIEMENS_GBS_III-16-ACR_NEMA_1.acr is a tough kid: 0009,1131 is supposed to be VR::UL, but +// there are only two bytes... +#define StringFilterCase(type) \ + case VR::type: \ + { \ + Element el; \ + if( !de.IsEmpty() ) { \ + el.Set( de.GetValue() ); \ + if( el.GetLength() ) { \ + os << "" << el.GetValue(); \ + long l = std::min( (long) el.GetLength(), (long) (MaxPrintLength / VR::GetLength(VR::type)) ); \ + for(long i = 1; i < l; ++i) os << "\\" << el.GetValue((unsigned int)i); \ + os << ""; } \ + else { if( de.IsEmpty() ) os << GDCM_TERMINAL_VT100_INVERSE << "(no value)" << GDCM_TERMINAL_VT100_NORMAL; \ + else os << GDCM_TERMINAL_VT100_INVERSE << GDCM_TERMINAL_VT100_FOREGROUND_RED << "(VR=" << refvr << " is incompatible with length)" << GDCM_TERMINAL_VT100_NORMAL; } } \ + else { assert( de.IsEmpty()); os << GDCM_TERMINAL_VT100_INVERSE << "(no value)" << GDCM_TERMINAL_VT100_NORMAL; } \ + } break + +VR Printer::PrintDataElement(std::ostringstream &os, const Dicts &dicts, const DataSet & ds, + const DataElement &de, std::ostream &out, std::string const & indent ) +{ + const ByteValue *bv = de.GetByteValue(); + const SequenceOfItems *sqi = 0; //de.GetSequenceOfItems(); + const Value &value = de.GetValue(); + const SequenceOfFragments *sqf = de.GetSequenceOfFragments(); + + std::string strowner; + const char *owner = 0; + const Tag& t = de.GetTag(); + if( t.IsPrivate() && !t.IsPrivateCreator() ) + { + strowner = ds.GetPrivateCreator(t); + owner = strowner.c_str(); + } + const DictEntry &entry = dicts.GetDictEntry(t,owner); + const VR &vr = entry.GetVR(); + const VM &vm = entry.GetVM(); + const char *name = entry.GetName(); + bool retired = entry.GetRetired(); + //if( t.IsPrivate() ) assert( retired == false ); + + const VR &vr_read = de.GetVR(); + const VL &vl_read = de.GetVL(); + os << indent; // first thing do the shift ! + os << t << " "; + os << vr_read << " "; + + //VR refvr = GetRefVR(dicts, de); + VR refvr; + // always prefer the vr from the file: + if( vr_read == VR::INVALID ) + { + refvr = vr; + } + else if ( vr_read == VR::UN && vr != VR::INVALID ) // File is explicit, but still prefer vr from dict when UN + { + refvr = vr; + } + else // cool the file is Explicit ! + { + refvr = vr_read; + } + if( refvr.IsDual() ) // This mean vr was read from a dict entry: + { + refvr = DataSetHelper::ComputeVR(*F,ds, t); + } + + assert( refvr != VR::US_SS ); + assert( refvr != VR::OB_OW ); + + if( dynamic_cast( &value ) ) + { + sqi = de.GetValueAsSQ(); + refvr = VR::SQ; + assert( refvr == VR::SQ ); + } +#if 0 + else if( vr == VR::SQ && vr_read != VR::SQ ) + { + sqi = de.GetValueAsSQ(); + refvr = VR::SQ; + assert( refvr == VR::SQ ); + } +#endif + + if( (vr_read == VR::INVALID || vr_read == VR::UN ) && vl_read.IsUndefined() ) + { + assert( refvr == VR::SQ ); + } + +// if( vr_read == VR::SQ || vr_read == VR::UN ) +// { +// sqi = de.GetValueAsSQ(); +// } + if( vr != VR::INVALID && (!vr.Compatible( vr_read ) || vr_read == VR::INVALID || vr_read == VR::UN ) ) + { + assert( vr != VR::INVALID ); + // FIXME : if terminal supports it: print in red/green ! + os << GDCM_TERMINAL_VT100_FOREGROUND_GREEN; + if( vr == VR::US_SS || vr == VR::OB_OW ) + { + os << "(" << vr << " => " << refvr << ") "; + } + else + { + os << "(" << vr << ") "; + } + os << GDCM_TERMINAL_VT100_NORMAL; + } + else if( sqi /*de.GetSequenceOfItems()*/ && refvr == VR::INVALID ) + { + // when vr == VR::INVALID and vr_read is also VR::INVALID, we have a seldom case where we can guess + // the vr + // eg. CD1/647662/647663/6471066 has a SQ at (2001,9000) + os << GDCM_TERMINAL_VT100_FOREGROUND_GREEN; + os << "(SQ) "; + os << GDCM_TERMINAL_VT100_NORMAL; + assert( refvr == VR::INVALID ); + refvr = VR::SQ; + } + + // Print Value now: + if( refvr & VR::VRASCII ) + { + assert( !sqi && !sqf ); + if( bv ) + { + VL l = std::min( bv->GetLength(), MaxPrintLength ); + os << "["; + if( bv->IsPrintable(l) ) + { + bv->PrintASCII(os,l); + } + else + { + os << GDCM_TERMINAL_VT100_INVERSE; + os << GDCM_TERMINAL_VT100_FOREGROUND_RED; + bv->PrintASCII(os,l); + os << GDCM_TERMINAL_VT100_NORMAL; + } + os << "]"; + } + else + { + assert( de.IsEmpty() ); + os << GDCM_TERMINAL_VT100_INVERSE; + os << "(no value)"; + os << GDCM_TERMINAL_VT100_NORMAL; + } + } + else + { + assert( refvr & VR::VRBINARY || (vr == VR::INVALID && refvr == VR::INVALID) ); + //std::ostringstream os; + std::string s; + switch(refvr) + { + StringFilterCase(AT); + StringFilterCase(FL); + StringFilterCase(FD); + //StringFilterCase(OB); + StringFilterCase(OF); + //StringFilterCase(OW); + StringFilterCase(SL); + //StringFilterCase(SQ); + StringFilterCase(SS); + StringFilterCase(UL); + //StringFilterCase(UN); + StringFilterCase(US); + //StringFilterCase(UT); + case VR::OB: + case VR::OW: + case VR::OB_OW: + case VR::UN: + case VR::US_SS_OW: // TODO: check with ModalityLUT.dcm + /* + VR::US_SS_OW: + undefined_length_un_vr.dcm + GDCMFakeJPEG.dcm + PhilipsWith15Overlays.dcm + */ + { + if ( bv ) + { + //VL l = std::min( bv->GetLength(), MaxPrintLength ); + //VL l = std::min( (int)bv->GetLength(), 0xF ); + //int width = (vr == VR::OW ? 4 : 2); + //os << std::hex << std::setw( width ) << std::setfill('0'); + bv->PrintHex(os, MaxPrintLength / 4); + //os << std::dec; + } + else if ( sqf ) + { + assert( t == Tag(0x7fe0,0x0010) ); + //os << *sqf; + } + else if ( sqi ) + { + // gdcmDataExtra/gdcmSampleData/images_of_interest/illegal_UN_stands_for_SQ.dcm + gdcmErrorMacro( "Should not happen: VR=UN but contains a SQ" ); + //os << *sqi; + } + else + { + assert( !sqi && !sqf ); + assert( de.IsEmpty() ); + os << GDCM_TERMINAL_VT100_INVERSE << "(no value)" << GDCM_TERMINAL_VT100_NORMAL; + } + } + break; + case VR::US_SS: + // impossible... + assert( refvr != VR::US_SS ); + break; + case VR::SQ: + if( !sqi /*!de.GetSequenceOfItems()*/ && !de.IsEmpty() && de.GetValue().GetLength() ) + { + // This case is insane, this is an implicit file, with a defined length SQ. + // Since this is a private element there is no way to guess that, and to + // make it even worse the binary blob does not start with item start... + // Bug_Philips_ItemTag_3F3F.dcm + //os << GDCM_TERMINAL_VT100_BACKGROUND_RED; + //bv->PrintHex(os, MaxPrintLength / 4); + //os << GDCM_TERMINAL_VT100_NORMAL; + } + else + { + if( vl_read.IsUndefined() ) + { + os << "(Sequence with undefined length)"; + } + else + { + os << "(Sequence with defined length)"; + } + } + break; + // Let's be a little more helpful and try to print anyway when possible: + case VR::INVALID: + { + if( bv ) + { + VL l = std::min( bv->GetLength(), MaxPrintLength ); + if( bv->IsPrintable(l) ) + { + os << "["; + bv->PrintASCII(os,l); + os << "]"; + } + else if( t == Tag(0xfffe,0xe000) ) bv->PrintHex(os, MaxPrintLength / 8); + else + { + os << GDCM_TERMINAL_VT100_INVERSE; + // << "(non-printable character found)" + bv->PrintHex(os, MaxPrintLength / 8); + os << GDCM_TERMINAL_VT100_NORMAL; + } + } + else + { + assert( !sqi && !sqf ); + assert( de.IsEmpty() ); + os << GDCM_TERMINAL_VT100_INVERSE << "(no value)" << GDCM_TERMINAL_VT100_NORMAL; + } + } + break; + default: + assert(0); + break; + } + os << s; + } + out.width(57); + out << std::left << os.str(); + // There is something wrong going on when doing terminal color stuff + // Let's add a couple of space to be nicer... + if( os.str().find( GDCM_TERMINAL_VT100_NORMAL ) != std::string::npos ) + { + out << " "; + } + os.str( "" ); + // Extra info (not in the file) + os << " # "; + // Append the VL + if( vl_read.IsUndefined() ) + { + os << "u/l"; + } + else + { + os << std::dec << vl_read; + } + if( vl_read.IsOdd() ) + { + os << GDCM_TERMINAL_VT100_FOREGROUND_GREEN; + os << " (" << (vl_read + 1) << ")"; + os << GDCM_TERMINAL_VT100_NORMAL; + } + os << ","; + // Append the VM + if( vm != VM::VM0 ) + { + os << vm; + } + else + { + os << GDCM_TERMINAL_VT100_FOREGROUND_RED; + os << "?"; + os << GDCM_TERMINAL_VT100_NORMAL; + } + VM guessvm = VM::VM0; + if( refvr & VR::VRASCII ) + { + assert( refvr != VR::INVALID ); + assert( refvr & VR::VRASCII ); + if( bv ) + { + unsigned int count = VM::GetNumberOfElementsFromArray(bv->GetPointer(), bv->GetLength()); + guessvm = VM::GetVMTypeFromLength(count, 1); // hackish... + } + } + else if( refvr & VR::VRBINARY ) + { + assert( refvr != VR::INVALID ); + assert( refvr & VR::VRBINARY ); + if( refvr & VR::OB_OW || refvr == VR::SQ ) + { + guessvm = VM::VM1; + } + else if ( refvr == VR::UN && sqi ) + { + // This is a SQ / UN + guessvm = VM::VM1; + } + else if( bv ) + { + guessvm = VM::GetVMTypeFromLength(bv->GetLength(), refvr.GetSize() ); + } + else + { + if( de.IsEmpty() ) guessvm = VM::VM0; + else assert( 0 && "Impossible" ); + } + } + else if( refvr == VR::INVALID ) + { + refvr = VR::UN; + guessvm = VM::VM1; + } + else + { + // Burst into flames ! + assert( 0 && "Impossible happen" ); + } + if( !vm.Compatible( guessvm ) ) + { + os << GDCM_TERMINAL_VT100_FOREGROUND_RED; + os << " (" << guessvm << ") "; + os << GDCM_TERMINAL_VT100_NORMAL; + } + // Append the name now: + if( name && *name ) + { + // No owner case ! + if( t.IsPrivate() && (owner == 0 || *owner == 0 ) && !t.IsPrivateCreator() ) + { + os << GDCM_TERMINAL_VT100_FOREGROUND_RED; + os << " " << name; + os << GDCM_TERMINAL_VT100_NORMAL; + } + // retired element + else if( retired ) + { + assert( t.IsPublic() || t.GetElement() == 0x0 ); // Is there such thing as private and retired element ? + os << " " << GDCM_TERMINAL_VT100_FOREGROUND_RED << GDCM_TERMINAL_VT100_UNDERLINE; + os << name; + os << GDCM_TERMINAL_VT100_NORMAL; + os << GDCM_TERMINAL_VT100_NORMAL; + } + else + { + os << GDCM_TERMINAL_VT100_BOLD; + os << " " << name; + os << GDCM_TERMINAL_VT100_NORMAL; + } + } + else + { + os << GDCM_TERMINAL_VT100_FOREGROUND_RED; + if( t.IsPublic() ) + { + // What ? A public element that we do not know about !!! + os << GDCM_TERMINAL_VT100_BLINK; + } + os << " GDCM:UNKNOWN"; // Special keyword + os << GDCM_TERMINAL_VT100_NORMAL; + } + os << "\n"; + return refvr; +} + +void Printer::PrintSQ(const SequenceOfItems *sqi, std::ostream & os, std::string const & indent) +{ + if( !sqi ) return; + SequenceOfItems::ItemVector::const_iterator it = sqi->Items.begin(); + for(; it != sqi->Items.end(); ++it) + { + const Item &item = *it; + const DataSet &ds = item.GetNestedDataSet(); + const DataElement &deitem = item; + std::string nextindent = indent + " "; + os << nextindent << deitem.GetTag(); + os << " "; + os << "na"; //deitem.GetVR(); + os << " "; + if( deitem.GetVL().IsUndefined() ) + { + os << "(Item with undefined length)"; + } + else + { + os << "(Item with defined length)"; + } + os << "\n"; + PrintDataSet(ds, os, nextindent + " "); + if( deitem.GetVL().IsUndefined() ) + { + const Tag itemDelItem(0xfffe,0xe00d); + os << nextindent << itemDelItem << "\n"; + } + } + if( sqi->GetLength().IsUndefined() ) + { + const Tag seqDelItem(0xfffe,0xe0dd); + os << indent << seqDelItem << "\n"; + } +} + +void Printer::PrintDataSet(const DataSet &ds, std::ostream &out, std::string const & indent ) +{ + const Global& g = GlobalInstance; + const Dicts &dicts = g.GetDicts(); + const Dict &d = dicts.GetPublicDict(); (void)d; + + DataSet::ConstIterator it = ds.Begin(); + for( ; it != ds.End(); ++it ) + { + const DataElement &de = *it; + + //const ByteValue *bv = de.GetByteValue(); + const SequenceOfFragments *sqf = de.GetSequenceOfFragments(); + + std::ostringstream os; + + VR refvr = PrintDataElement(os, dicts, ds, de, out, indent); + + if( refvr == VR::SQ /*|| sqi*/ ) + { + //SmartPointer sqi2 = DataSetHelper::ComputeSQFromByteValue( *F, ds, de.GetTag() ); + SmartPointer sqi2 = de.GetValueAsSQ(); + PrintSQ(sqi2, os, indent); + /* + const SequenceOfItems *sqi = de.GetSequenceOfItems(); + if( sqi ) // empty SQ ? + { + assert( sqi ); + PrintSQ(sqi, os, indent); + } + else + { + if( !de.IsEmpty() ) + { + // Ok so far we know: + // 1. VR is SQ sqi == NULL + // 2. DataElement is not empty ... + // => This is a VR:UN or Implicit SQ with defined length. + // let's try to interpret this sequence + SequenceOfItems *sqi2 = DataSetHelper::ComputeSQFromByteValue( *F, ds, de.GetTag() ); + if(sqi2) PrintSQ(sqi2, os, indent); + delete sqi2; + } + } + */ + } + else if ( sqf ) + { + std::string nextindent = indent + " "; + const BasicOffsetTable & table = sqf->GetTable(); + //os << nextindent << table.GetTag() << "\n"; + PrintDataElement(os,dicts,ds,table,out,nextindent); + size_t numfrag = sqf->GetNumberOfFragments(); + for(size_t i = 0; i < numfrag; ++i) + { + const Fragment& frag = sqf->GetFragment(i); + //os << nextindent<< frag << "\n"; + PrintDataElement(os,dicts,ds,frag,out,nextindent); + } + const Tag seqDelItem(0xfffe,0xe0dd); + VL zero = 0; + os << /*nextindent <<*/ seqDelItem; + os << " " << zero << "\n"; + } + else + { + // This is a byte value, so it should have been already treated + } + out << os.str(); + } +} + +//----------------------------------------------------------------------------- +void DumpDataSet(const DataSet &ds, std::ostream &os ) +{ + DataSet::ConstIterator it = ds.Begin(); + for( ; it != ds.End(); ++it ) + { + const DataElement &de = *it; + const Tag& t = de.GetTag(); (void)t; + const VR& vr = de.GetVR(); (void)vr; + os << de << std::endl; + //if( VR::IsASCII( vr ) ) + // { + // } + } +} + +//----------------------------------------------------------------------------- +void Printer::Print(std::ostream& os) +{ + os << "# Dicom-File-Format\n"; + os << "\n"; + os << "# Dicom-Meta-Information-Header\n"; + os << "# Used TransferSyntax: \n"; + + const FileMetaInformation &meta = F->GetHeader(); + if( PrintStyle == VERBOSE_STYLE ) + PrintDataSet(meta, os); + else if (PrintStyle == CONDENSED_STYLE ) + DumpDataSet(meta, os); + + os << "\n# Dicom-Data-Set\n"; + os << "# Used TransferSyntax: "; + const TransferSyntax &metats = meta.GetDataSetTransferSyntax(); + os << metats; + os << std::endl; + const DataSet &ds = F->GetDataSet(); + if( PrintStyle == VERBOSE_STYLE ) + PrintDataSet(ds, os); + else if (PrintStyle == CONDENSED_STYLE ) + DumpDataSet(ds, os); +} + +} diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmPrinter.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmPrinter.h new file mode 100644 index 0000000..205407a --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmPrinter.h @@ -0,0 +1,104 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMPRINTER_H +#define GDCMPRINTER_H + +// TODO Class to implement printing +// Since DICOM does printing ? +// Also I would like to encapsulate the IsCharacterPrintable thing +// (to avoid printing \0 and other weird characters) +// \todo I still need to implement skiping of group (shadow) +// need to implement longer field to read + +/* + * Output: + * For ASCII: + * Typically will look like: + * [ORIGINAL\PRIMARY\OTHER] + * If a non printable character is found: RED and INVERSE is used: + * [ .] + * + * when the VR is not found (file or dict), we check if we can print the output: + * on success ASCII mode is used, on failure the output is printed a series of bytes + * + * Special case when the data element is empty: + * INVERSE << (no value) + * + * retired public element are printed in red and underline + * unknown private element are printed in RED followed by 'UNKNOWN' + * + * Correct VR is printed in green just after the found VR + * + * length of data element is printed in bytes, followed by the VM, a green VM is appended + * if this is not compatible + */ +#include "gdcmFile.h" +#include "gdcmDataElement.h" + +namespace gdcm +{ + +class DataSet; +class DictEntry; +class Dicts; +/** + * \brief Printer class + */ +// It's a sink there is no output +class GDCM_EXPORT Printer +{ +public: + Printer(); + ~Printer(); + + /// Set file + void SetFile(File const &f) { F = &f; } + + /// Set color mode or not + void SetColor(bool c); + + typedef enum { + VERBOSE_STYLE = 0, // GDCM Legacy VERBOSE one + CONDENSED_STYLE, // + // Ok I am missing voc here ...better naming would be nice + XML // sure why not + } PrintStyles; + + /// Set PrintStyle value + void SetStyle(PrintStyles ps) { + PrintStyle = ps; + } + /// Get PrintStyle value + PrintStyles GetPrintStyle() const { + return PrintStyle; + } + + /// Print + void Print(std::ostream& os); + + /// Print an individual dataset + void PrintDataSet(const DataSet &ds, std::ostream& os, const std::string &s = ""); + +protected: + VR PrintDataElement(std::ostringstream & os, const Dicts &dicts, const DataSet & ds, const DataElement &de, std::ostream &out, std::string const & indent ); +void PrintSQ(const SequenceOfItems *sqi, std::ostream & os, std::string const & indent); + + PrintStyles PrintStyle; + const File *F; + VL MaxPrintLength; +}; + +} // end namespace gdcm + +#endif //GDCMPRINTER_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmRAWCodec.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmRAWCodec.cxx new file mode 100644 index 0000000..bd744d3 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmRAWCodec.cxx @@ -0,0 +1,218 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmRAWCodec.h" +#include "gdcmTransferSyntax.h" +#include "gdcmByteSwap.txx" +#include "gdcmDataElement.h" +#include "gdcmSequenceOfFragments.h" +#include "gdcmUnpacker12Bits.h" + +#include +#include + +#include + +namespace gdcm +{ + +class RAWInternals +{ +public: +}; + +RAWCodec::RAWCodec() +{ + Internals = new RAWInternals; +} + +RAWCodec::~RAWCodec() +{ + delete Internals; +} + +bool RAWCodec::CanCode(TransferSyntax const &ts) const +{ + return ts == TransferSyntax::ImplicitVRLittleEndian + || ts == TransferSyntax::ExplicitVRLittleEndian + || ts == TransferSyntax::ExplicitVRBigEndian + || ts == TransferSyntax::ImplicitVRBigEndianPrivateGE + || ts == TransferSyntax::DeflatedExplicitVRLittleEndian; +} + +bool RAWCodec::CanDecode(TransferSyntax const &ts) const +{ + return ts == TransferSyntax::ImplicitVRLittleEndian + || ts == TransferSyntax::ExplicitVRLittleEndian + || ts == TransferSyntax::ExplicitVRBigEndian + || ts == TransferSyntax::ImplicitVRBigEndianPrivateGE + || ts == TransferSyntax::DeflatedExplicitVRLittleEndian; +} + +bool RAWCodec::Code(DataElement const &in, DataElement &out) +{ + out = in; + //assert(0); + return true; +} + +bool RAWCodec::DecodeBytes(const char* inBytes, size_t inBufferLength, + char* outBytes, size_t inOutBufferLength) +{ + // First let's see if we can do a fast-path: + if( !NeedByteSwap && + !RequestPaddedCompositePixelCode && + // PI == PhotometricInterpretation::MONOCHROME2 && + /*!PlanarConfiguration &&*/ !RequestPlanarConfiguration && + GetPixelFormat().GetBitsAllocated() != 12 && + !NeedOverlayCleanup ) + { + assert( !NeedOverlayCleanup ); + assert( PI != PhotometricInterpretation::YBR_PARTIAL_422 ); + assert( PI != PhotometricInterpretation::YBR_PARTIAL_420 ); + assert( PI != PhotometricInterpretation::YBR_ICT ); + assert( this->GetPixelFormat() != PixelFormat::UINT12 ); + assert( this->GetPixelFormat() != PixelFormat::INT12 ); + // DermaColorLossLess.dcm + //assert(inBufferLength == inOutBufferLength || inBufferLength == inOutBufferLength + 1); + // What if the user request a subportion of the image: + // this happen in the case of MOSAIC image, where we are only interested in the non-zero + // pixel of the tiled image. + // removal of this assert also solve an issue with: SIEMENS_GBS_III-16-ACR_NEMA_1.acr + // where we need to discard trailing pixel data bytes. + if( inOutBufferLength <= inBufferLength ) + { + memcpy(outBytes, inBytes, inOutBufferLength); + } + else + { + gdcmWarningMacro( "Requesting too much data. Truncating result" ); + memcpy(outBytes, inBytes, inBufferLength); + } + return true; + } + // else + assert( inBytes ); + assert( outBytes ); + std::stringstream is; + is.write(inBytes, inBufferLength); + std::stringstream os; + bool r = DecodeByStreams(is, os); + assert( r ); + if(!r) return false; + + std::string str = os.str(); + //std::string::size_type check = str.size();//unused + + + if( this->GetPixelFormat() == PixelFormat::UINT12 || + this->GetPixelFormat() == PixelFormat::INT12 ) + { + size_t len = str.size() * 16 / 12; + char * copy = new char[len]; + bool b = Unpacker12Bits::Unpack(copy, &str[0], str.size() ); (void)b; + assert( b ); + assert (len == inOutBufferLength); + assert(inOutBufferLength == len); + memcpy(outBytes, copy, len); + + delete[] copy; + + this->GetPixelFormat().SetBitsAllocated( 16 ); + } + else + { + // DermaColorLossLess.dcm + //assert (check == inOutBufferLength || check == inOutBufferLength + 1); + // problem with: SIEMENS_GBS_III-16-ACR_NEMA_1.acr + memcpy(outBytes, str.c_str(), inOutBufferLength); + } + + return r; +} + +bool RAWCodec::Decode(DataElement const &in, DataElement &out) +{ + // First let's see if we can do a fast-path: + if( !NeedByteSwap && + !RequestPaddedCompositePixelCode && + PI == PhotometricInterpretation::MONOCHROME2 && + !PlanarConfiguration && !RequestPlanarConfiguration && + GetPixelFormat().GetBitsAllocated() != 12 && + !NeedOverlayCleanup ) + { + assert( this->GetPixelFormat() != PixelFormat::UINT12 ); + assert( this->GetPixelFormat() != PixelFormat::INT12 ); + out = in; + return true; + } + // else + const ByteValue *bv = in.GetByteValue(); + assert( bv ); + std::stringstream is; + is.write(bv->GetPointer(), bv->GetLength()); + std::stringstream os; + bool r = DecodeByStreams(is, os); + if(!r) return false; + assert( r ); + + std::string str = os.str(); + //std::string::size_type check = str.size(); + + out = in; + + if( this->GetPixelFormat() == PixelFormat::UINT12 || + this->GetPixelFormat() == PixelFormat::INT12 ) + { + size_t len = str.size() * 16 / 12; + char * copy = new char[len];//why use an array, and not a vector? + bool b = Unpacker12Bits::Unpack(copy, &str[0], str.size() ); + assert( b ); + (void)b; + VL::Type lenSize = (VL::Type)len; + out.SetByteValue( copy, lenSize ); + delete[] copy; + + this->GetPixelFormat().SetBitsAllocated( 16 ); + } + else + { + VL::Type strSize = (VL::Type) str.size(); + out.SetByteValue( &str[0], strSize); + } + + return r; +} + +bool RAWCodec::DecodeByStreams(std::istream &is, std::ostream &os) +{ + bool r = ImageCodec::DecodeByStreams(is, os); + return r; +} + +bool RAWCodec::GetHeaderInfo(std::istream &, TransferSyntax &ts) +{ + ts = gdcm::TransferSyntax::ExplicitVRLittleEndian; + if( NeedByteSwap ) + { + ts = gdcm::TransferSyntax::ImplicitVRBigEndianPrivateGE; + } + return true; +} + +ImageCodec * RAWCodec::Clone() const +{ + return NULL; +} + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmRAWCodec.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmRAWCodec.h new file mode 100644 index 0000000..fcff2cf --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmRAWCodec.h @@ -0,0 +1,53 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMRAWCODEC_H +#define GDCMRAWCODEC_H + +#include "gdcmImageCodec.h" + +namespace gdcm +{ + +class RAWInternals; +/** + * \brief RAWCodec class + */ +class GDCM_EXPORT RAWCodec : public ImageCodec +{ +public: + RAWCodec(); + ~RAWCodec(); + bool CanCode(TransferSyntax const &ts) const; + bool CanDecode(TransferSyntax const &ts) const; + bool Decode(DataElement const &is, DataElement &os); + bool Code(DataElement const &in, DataElement &out); + + bool GetHeaderInfo(std::istream &is, TransferSyntax &ts); + virtual ImageCodec * Clone() const; + + /// Used by the ImageStreamReader-- converts a read in + /// buffer into one with the proper encodings. + bool DecodeBytes(const char* inBytes, size_t inBufferLength, + char* outBytes, size_t inOutBufferLength); + +protected: + bool DecodeByStreams(std::istream &is, std::ostream &os); + +private: + RAWInternals *Internals; +}; + +} // end namespace gdcm + +#endif // GDCMRAWCODEC_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmRLECodec.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmRLECodec.cxx new file mode 100644 index 0000000..cc612ac --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmRLECodec.cxx @@ -0,0 +1,848 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmRLECodec.h" +#include "gdcmTransferSyntax.h" +#include "gdcmTrace.h" +#include "gdcmByteSwap.txx" +#include "gdcmDataElement.h" +#include "gdcmSequenceOfFragments.h" +#include "gdcmSmartPointer.h" +#include "gdcmSwapper.h" + +#include +#include // req C++11 +#include // ptrdiff_t fix +#include + +namespace gdcm +{ + +// TODO ideally this code should be in utilities for ease of reuse +class RLEHeader +{ +public: + uint32_t NumSegments; + uint32_t Offset[15]; + + void Print(std::ostream &os) + { + os << "NumSegments:" << NumSegments << "\n"; + for(int i=0; i<15; ++i) + { + os << i << ":" << Offset[i] << "\n"; + } + } +}; + +class RLEFrame +{ +public: + void Read(std::istream &is) + { + // read Header (64 bytes) + is.read((char*)(&Header), sizeof(uint32_t)*16); + assert( sizeof(uint32_t)*16 == 64 ); + assert( sizeof(RLEHeader) == 64 ); + SwapperNoOp::SwapArray((uint32_t*)&Header,16); + uint32_t numSegments = Header.NumSegments; + if( numSegments >= 1 ) + { + assert( Header.Offset[0] == 64 ); + } + // We just check that we are indeed at the proper position start+64 + } + void Print(std::ostream &os) + { + Header.Print(os); + } +//private: + RLEHeader Header; + std::vector Bytes; +}; + +class RLEInternals +{ +public: + RLEFrame Frame; + std::vector SegmentLength; +}; + +RLECodec::RLECodec() +{ + Internals = new RLEInternals; + Length = 0; + BufferLength = 0; +} + +RLECodec::~RLECodec() +{ + delete Internals; +} + +bool RLECodec::CanDecode(TransferSyntax const &ts) const +{ + return ts == TransferSyntax::RLELossless; +} + +bool RLECodec::CanCode(TransferSyntax const &ts) const +{ + return ts == TransferSyntax::RLELossless; +} + +/* +G.3 THE RLE ALGORITHM +The RLE algorithm described in this section is used to compress Byte Segments into RLE Segments. +There is a one-to-one correspondence between Byte Segments and RLE Segments. Each RLE segment +must be an even number of bytes or padded at its end with zero to make it even. +G.3.1 The RLE encoder +A sequence of identical bytes (Replicate Run) is encoded as a two-byte code: +< -count + 1 > , where +count = the number of bytes in the run, and +2 <= count <= 128 +and a non-repetitive sequence of bytes (Literal Run) is encoded as: +< count - 1 > , where +count = number of bytes in the sequence, and +1 <= count <= 128. +The value of -128 may not be used to prefix a byte value. +Note: It is common to encode a 2-byte repeat run as a Replicate Run except when preceded and followed by +a Literal Run, in which case it's best to merge the three runs into a Literal Run. +Three-byte repeats shall be encoded as Replicate Runs. Each row of the image shall be encoded +separately and not cross a row boundary. +*/ +inline int count_identical_bytes(const char *start, size_t len) +{ + assert( len ); +#if 0 + const char *p = start + 1; + const unsigned int cmin = std::min(128u,len); + const char *end = start + cmin; + while( p < end && *p == *start ) + { + ++p; + } + return p - start; +#else + const char ref = start[0]; + unsigned int count = 1; // start at one; make unsigned for comparison + const size_t cmin = std::min((size_t)128,len); + while( count < cmin && start[count] == ref ) + { + //std::cerr << "count/len:" << count << "," << len << std::endl; + ++count; + } + assert( /*2 <= count && */ count <= 128 ); // remove post condition as it will be our return error code + assert( count >= 1 ); + return count; +#endif +} + +inline int count_nonrepetitive_bytes(const char *start, size_t len) +{ +/* + * TODO: + * I need a special handling when there is only a one repetition that break the Literal run... +Note: It is common to encode a 2-byte repeat run as a Replicate Run except when preceded and followed by +a Literal Run, in which case it's best to merge the three runs into a Literal Run. +*/ + assert( len ); +#if 0 + const char *prev = start; + const char *p = start + 1; + const unsigned int cmin = std::min(128u,len); + const char *end = start + cmin; + while( p < end && *p != *prev ) + { + ++prev; + ++p; + } + return p - start; +#else + unsigned int count = 1; + const size_t cmin = std::min((size_t)128,len); +#if 0 + // TODO: this version that handles the note still does not work... + while( count < cmin ) + { + if ( start[count] != start[count-1] ) + { + // Special case: + if( count + 1 < cmin && start[count] != start[count+1] ) + { + continue; + } + break; + } + ++count; + } +#else +#if 1 + // This version properly encode: 0 1 1 0 as: 3 0 1 1 0 ... + for( count = 1; count < cmin; ++count ) + { + if( start[count] == start[count-1] ) + { + if( count + 1 < cmin && start[count] != start[count+1] ) + { + continue; + } + --count;//Note that count can go negative, or wrapped if unsigned! + break; + } + } +#else + // This version does not handle 0 1 1 0 as specified in the note in the DICOM standard + while( count < cmin && start[count] != start[count-1] ) + { + ++count; + } +#endif +#endif + assert( 1 <= count && count <= 128 ); + return count; +#endif +} + +/* return output length */ +ptrdiff_t rle_encode(char *output, size_t outputlength, const char *input, size_t inputlength) +{ + char *pout = output; + const char *pin = input; + size_t length = inputlength; + while( pin != input + inputlength ) + { + assert( length <= inputlength ); + assert( pin <= input + inputlength ); + int count = count_identical_bytes(pin, length); + if( count > 1 ) /* or 2 ? */ + { + // repeat case: + // + // Test first we are allowed to write two bytes: + if( pout + 1 + 1 > output + outputlength ) return -1; + *pout = (char)(-count + 1); + assert( /**pout != -128 &&*/ 1 - *pout == count ); + assert( *pout <= -1 && *pout >= -127 ); + ++pout; + *pout = *pin; + ++pout; + } + else + { + // non repeat case: + // ok need to compute non-repeat: + count = count_nonrepetitive_bytes(pin, length); + // first test we are allowed to write 1 + count bytes in the output buffer: + if( pout + count + 1 > output + outputlength ) return -1; + *pout = (char)(count - 1); + assert( *pout != -128 && *pout+1 == count ); + assert( *pout >= 0 ); + ++pout; + memcpy(pout, pin, count); + pout += count; + } + // count byte where read, move pin to new position: + pin += count; + // compute remaining length: + assert( count <= (int)length ); + length -= count; + } + return pout - output; +} + +template +bool DoInvertPlanarConfiguration(T *output, const T *input, uint32_t inputlength) +{ + const T *r = input+0; + const T *g = input+1; + const T *b = input+2; + uint32_t length = (inputlength / 3) * 3; // remove the 0 padding + assert( length == inputlength || length == inputlength - 1 ); + assert( length % 3 == 0 ); + uint32_t plane_length = length / 3; + T *pout = output; + // copy red plane: + while( pout != output + plane_length * 1 ) + { + *pout++ = *r; + r += 3; + } + assert( r == input + length ); + // copy green plane: + assert( pout == output + plane_length ); + while( pout != output + plane_length * 2 ) + { + *pout++ = *g; + g += 3; + } + assert( g == input + length + 1); + // copy blue plane: + assert( pout == output + 2*plane_length ); + while( pout != output + plane_length * 3 ) + { + *pout++ = *b; + b += 3; + } + assert( b == input + length + 2); + assert ( pout = output + length ); + return true; +} + + +bool RLECodec::Code(DataElement const &in, DataElement &out) +{ + const unsigned int *dims = this->GetDimensions(); + const unsigned int n = 256*256; + char *outbuf; + // At most we are encoding a single row at a time, so we would be very unlucky + // if the row *after* compression would not fit in 256*256 bytes... + char small_buffer[n]; + outbuf = small_buffer; + + // Create a Sequence Of Fragments: + SmartPointer sq = new SequenceOfFragments; + const Tag itemStart(0xfffe, 0xe000); + //sq->GetTable().SetTag( itemStart ); + // FIXME ? Is this compulsary ? + //const char dummy[4] = {}; + //sq->GetTable().SetByteValue( dummy, sizeof(dummy) ); + + const ByteValue *bv = in.GetByteValue(); + assert( bv ); + const char *input = bv->GetPointer(); + unsigned long bvl = bv->GetLength(); + unsigned long image_len = bvl / dims[2]; + + // If 16bits, need to do the padded composite... + char *buffer = 0; + // if rgb (3 comp) need to the planar configuration + char *bufferrgb = 0; + if( GetPixelFormat().GetBitsAllocated() > 8 ) + { + //RequestPaddedCompositePixelCode = true; + buffer = new char [ image_len ]; + } + + if ( GetPhotometricInterpretation() == PhotometricInterpretation::RGB + || GetPhotometricInterpretation() == PhotometricInterpretation::YBR_FULL + || GetPhotometricInterpretation() == PhotometricInterpretation::YBR_RCT + || GetPhotometricInterpretation() == PhotometricInterpretation::YBR_FULL_422 ) + { + bufferrgb = new char [ image_len ]; + } + + unsigned int MaxNumSegments = 1; + if( GetPixelFormat().GetBitsAllocated() == 8 ) + { + MaxNumSegments *= 1; + } + else if( GetPixelFormat().GetBitsAllocated() == 16 ) + { + MaxNumSegments *= 2; + } + else if( GetPixelFormat().GetBitsAllocated() == 32 ) + { + MaxNumSegments *= 4; + } + else + { + delete[] buffer; + delete[] bufferrgb; + return false; + } + + if( GetPhotometricInterpretation() == PhotometricInterpretation::RGB + || GetPhotometricInterpretation() == PhotometricInterpretation::YBR_FULL + || GetPhotometricInterpretation() == PhotometricInterpretation::YBR_RCT + || GetPhotometricInterpretation() == PhotometricInterpretation::YBR_FULL_422 ) + { + MaxNumSegments *= 3; + } + + assert( GetPixelFormat().GetBitsAllocated() == 8 || GetPixelFormat().GetBitsAllocated() == 16 + || GetPixelFormat().GetBitsAllocated() == 32 ); + if( GetPixelFormat().GetSamplesPerPixel() == 3 ) + { + assert( MaxNumSegments % 3 == 0 ); + } + + RLEHeader header = { static_cast ( MaxNumSegments ), { 64 } }; + // there cannot be any space in between the end of the RLE header and the start + // of the first RLE segment + // + // Create a RLE Frame for each frame: + for(unsigned int dim = 0; dim < dims[2]; ++dim) + { + // Within each frame, create the RLE Segments: + // lets' try a simple scheme where each Segments is given an equal portion + // of the input image. + const char *ptr_img = input + dim * image_len; + if( GetPlanarConfiguration() == 0 && GetPixelFormat().GetSamplesPerPixel() == 3 ) + { + if( GetPixelFormat().GetBitsAllocated() == 8 ) + { + DoInvertPlanarConfiguration(bufferrgb, ptr_img, (uint32_t)(image_len / sizeof(char))); + } + else /* ( GetPixelFormat().GetBitsAllocated() == 16 ) */ + { + assert( GetPixelFormat().GetBitsAllocated() == 16 ); + // should not happen right ? + DoInvertPlanarConfiguration((short*)bufferrgb, (short*)ptr_img, (uint32_t)(image_len / sizeof(short))); + } + ptr_img = bufferrgb; + } + if( GetPixelFormat().GetBitsAllocated() == 32 ) + { + assert( !(image_len % 4) ); + //assert( image_len % 3 == 0 ); + unsigned int div = GetPixelFormat().GetSamplesPerPixel(); + for(unsigned int j = 0; j < div; ++j) + { + unsigned long iimage_len = image_len / div; + char *ibuffer = buffer + j * iimage_len; + const char *iptr_img = ptr_img + j * iimage_len; + assert( iimage_len % 4 == 0 ); + for(unsigned long i = 0; i < iimage_len/4; ++i) + { +#ifdef GDCM_WORDS_BIGENDIAN + ibuffer[i] = iptr_img[4*i+0]; +#else + ibuffer[i] = iptr_img[4*i+3]; +#endif + } + for(unsigned long i = 0; i < iimage_len/4; ++i) + { +#ifdef GDCM_WORDS_BIGENDIAN + ibuffer[i+iimage_len/4] = iptr_img[4*i+1]; +#else + ibuffer[i+iimage_len/4] = iptr_img[4*i+2]; +#endif + } + for(unsigned long i = 0; i < iimage_len/4; ++i) + { +#ifdef GDCM_WORDS_BIGENDIAN + ibuffer[i+2*iimage_len/4] = iptr_img[4*i+2]; +#else + ibuffer[i+2*iimage_len/4] = iptr_img[4*i+1]; +#endif + } + for(unsigned long i = 0; i < iimage_len/4; ++i) + { +#ifdef GDCM_WORDS_BIGENDIAN + ibuffer[i+3*iimage_len/4] = iptr_img[4*i+3]; +#else + ibuffer[i+3*iimage_len/4] = iptr_img[4*i+0]; +#endif + } + } + ptr_img = buffer; + } + else if( GetPixelFormat().GetBitsAllocated() == 16 ) + { + assert( !(image_len % 2) ); + //assert( image_len % 3 == 0 ); + unsigned int div = GetPixelFormat().GetSamplesPerPixel(); + for(unsigned int j = 0; j < div; ++j) + { + unsigned long iimage_len = image_len / div; + char *ibuffer = buffer + j * iimage_len; + const char *iptr_img = ptr_img + j * iimage_len; + assert( iimage_len % 2 == 0 ); + for(unsigned long i = 0; i < iimage_len/2; ++i) + { +#ifdef GDCM_WORDS_BIGENDIAN + ibuffer[i] = iptr_img[2*i]; +#else + ibuffer[i] = iptr_img[2*i+1]; +#endif + } + for(unsigned long i = 0; i < iimage_len/2; ++i) + { +#ifdef GDCM_WORDS_BIGENDIAN + ibuffer[i+iimage_len/2] = iptr_img[2*i+1]; +#else + ibuffer[i+iimage_len/2] = iptr_img[2*i]; +#endif + } + } + ptr_img = buffer; + } + assert( image_len % MaxNumSegments == 0 ); + const size_t input_seg_length = image_len / MaxNumSegments; + std::string datastr; + for(unsigned int seg = 0; seg < MaxNumSegments; ++seg ) + { + size_t partition = input_seg_length; + const char *ptr = ptr_img + seg * input_seg_length; + assert( ptr < ptr_img + image_len ); + if( seg == MaxNumSegments - 1 ) + { + partition += image_len % MaxNumSegments; + assert( (MaxNumSegments-1) * input_seg_length + partition == (size_t)image_len ); + } + assert( partition == input_seg_length ); + + std::stringstream data; + assert( partition % dims[1] == 0 ); + size_t length = 0; + // Do not cross row boundary: + for(unsigned int y = 0; y < dims[1]; ++y) + { + ptrdiff_t llength = rle_encode(outbuf, n, ptr + y*dims[0], partition / dims[1] /*image_len*/); + if( llength < 0 ) + { + std::cerr << "RLE compressor error" << std::endl; + return false; + } + assert( llength ); + data.write((char*)outbuf, llength); + length += llength; + } + // update header + header.Offset[1+seg] = (uint32_t)(header.Offset[seg] + length); + + assert( data.str().size() == length ); + datastr += data.str(); + } + header.Offset[MaxNumSegments] = 0; + std::stringstream os; + //header.Print( std::cout ); + os.write((char*)&header,sizeof(header)); + std::string str = os.str() + datastr; + assert( str.size() ); + Fragment frag; + //frag.SetTag( itemStart ); + VL::Type strSize = (VL::Type)str.size(); + frag.SetByteValue( &str[0], strSize ); + sq->AddFragment( frag ); + } + + out.SetValue( *sq ); + + if( buffer /*GetPixelFormat().GetBitsAllocated() > 8*/ ) + { + //RequestPaddedCompositePixelCode = true; + delete[] buffer; + } + if ( bufferrgb /*GetPhotometricInterpretation() == PhotometricInterpretation::RGB*/ ) + { + delete[] bufferrgb; + } + + return true; +} + +// G.3.2 The RLE decoder +// Pseudo code for the RLE decoder is shown below: +// Loop until the number of output bytes equals the uncompressed segment size +// Read the next source byte into n +// If n> =0 and n <= 127 then +// output the next n+1 bytes literally +// Elseif n <= - 1 and n >= -127 then +// output the next byte -n+1 times +// Elseif n = - 128 then +// output nothing +// Endif +// Endloop + +size_t RLECodec::DecodeFragment(Fragment const & frag, char *buffer, unsigned long llen) +{ + + std::stringstream is; + const ByteValue &bv = dynamic_cast(frag.GetValue()); + size_t bv_len = bv.GetLength(); + char *mybuffer = new char[bv_len]; + bv.GetBuffer(mybuffer, bv.GetLength()); + is.write(mybuffer, bv.GetLength()); + delete[] mybuffer; + std::stringstream os; + SetLength( llen ); +#if !defined(NDEBUG) + const unsigned int * const dimensions = this->GetDimensions(); + const PixelFormat & pf = this->GetPixelFormat(); + assert( llen == dimensions[0] * dimensions[1] * pf.GetPixelSize() ); +#endif + bool r = DecodeByStreams(is, os); + assert( r == true ); + (void)r; //warning removal + std::streampos p = is.tellg(); + // http://groups.google.com/group/microsoft.public.vc.stl/browse_thread/thread/96740930d0e4e6b8 + if( !!is ) + { + // Indeed the length of the RLE stream has been padded with a \0 + // which is discarded + std::streamoff check = bv.GetLength() - p; + // check == 2 for gdcmDataExtra/gdcmSampleData/US_DataSet/GE_US/2929J686-breaker + assert( check == 0 || check == 1 || check == 2 ); + if( check ) gdcmWarningMacro( "tiny offset detected in between RLE segments" ); + } + else + { + // ALOKA_SSD-8-MONO2-RLE-SQ.dcm + gdcmWarningMacro( "Bad RLE stream" ); + } + std::string::size_type check = os.str().size(); + // If the following assert fail expect big troubles: + memcpy(buffer, os.str().c_str(), check); +// pos += check; + return check; +} + +bool RLECodec::Decode(DataElement const &in, DataElement &out) +{ + if( NumberOfDimensions == 2 ) + { + out = in; + const SequenceOfFragments *sf = in.GetSequenceOfFragments(); + if( !sf ) return false; + unsigned long len = GetBufferLength(); + std::stringstream is; + sf->WriteBuffer( is ); + SetLength( len ); + std::stringstream os; + bool r = DecodeByStreams(is, os); + assert( r ); (void)r; //warning removal + std::string str = os.str(); + std::string::size_type check = str.size(); + assert( check == len ); + VL::Type checkCast = (VL::Type)check; + out.SetByteValue( &str[0], checkCast ); + return true; + } + else if ( NumberOfDimensions == 3 ) + { + out = in; + const SequenceOfFragments *sf = in.GetSequenceOfFragments(); + if( !sf ) return false; + unsigned long len = GetBufferLength(); + char *buffer = new char[len]; + unsigned long pos = 0; + // Each RLE Frame store a 2D frame. len is the 3d length + unsigned long llen = len / sf->GetNumberOfFragments(); + // assert( GetNumberOfDimensions() == 2 + // || GetDimension(2) == sf->GetNumberOfFragments() ); + for(unsigned int i = 0; i < sf->GetNumberOfFragments(); ++i) + { + const Fragment &frag = sf->GetFragment(i); + const size_t check = DecodeFragment(frag, buffer + pos, llen); (void)check; + assert( check == llen ); + pos += llen; + } + assert( pos == len ); + out.SetByteValue( buffer, (uint32_t)len ); + delete[] buffer; + return true; + } + return false; +} + +bool RLECodec::DecodeExtent( + char *buffer, + unsigned int xmin, unsigned int xmax, + unsigned int ymin, unsigned int ymax, + unsigned int zmin, unsigned int zmax, + std::istream & is +) +{ + std::stringstream tmpos; + BasicOffsetTable bot; + bot.Read( is ); + //std::cout << bot << std::endl; + + const unsigned int * dimensions = this->GetDimensions(); + const PixelFormat & pf = this->GetPixelFormat(); + assert( pf.GetBitsAllocated() % 8 == 0 ); + assert( pf != PixelFormat::SINGLEBIT ); + assert( pf != PixelFormat::UINT12 && pf != PixelFormat::INT12 ); + + // skip + std::stringstream os; + gdcm::Fragment frag; + for( unsigned int z = 0; z < zmin; ++z ) + { + frag.ReadPreValue(is); + std::streamoff off = frag.GetVL(); + is.seekg( off, std::ios::cur ); + } + for( unsigned int z = zmin; z <= zmax; ++z ) + { + frag.ReadPreValue(is); + std::streampos start = is.tellg(); + + SetLength( dimensions[0] * dimensions[1] * pf.GetPixelSize() ); + const bool r = DecodeByStreams(is, os); (void)r; + assert( r ); + + // handle DICOM padding + std::streampos end = is.tellg(); + size_t numberOfReadBytes = end - start; + if( numberOfReadBytes > frag.GetVL() ) + { + // Special handling for ALOKA_SSD-8-MONO2-RLE-SQ.dcm + size_t diff = numberOfReadBytes - frag.GetVL(); + assert( diff == 1 ); + os.seekp( -diff, std::ios::cur ); + os.put( 0 ); + end = (size_t)end - 1; + } + assert( end - start == frag.GetVL() || (size_t)(end - start) + 1 == frag.GetVL() ); + // sync is (rle16loo.dcm) + if( (end - start) % 2 == 1 ) + { + is.get(); + } + } // for each z + + os.seekg(0, std::ios::beg ); + assert( os.good() ); + std::istream *theStream = &os; + + unsigned int rowsize = xmax - xmin + 1; + unsigned int colsize = ymax - ymin + 1; + unsigned int bytesPerPixel = pf.GetPixelSize(); + + std::vector buffer1; + buffer1.resize( rowsize*bytesPerPixel ); + char *tmpBuffer1 = &buffer1[0]; + unsigned int y, z; + std::streamoff theOffset; + for (z = zmin; z <= zmax; ++z) + { + for (y = ymin; y <= ymax; ++y) + { + theStream->seekg(std::ios::beg); + theOffset = 0 + ((z-zmin)*dimensions[1]*dimensions[0] + y*dimensions[0] + xmin)*bytesPerPixel; + theStream->seekg(theOffset); + theStream->read(tmpBuffer1, rowsize*bytesPerPixel); + memcpy(&(buffer[((z-zmin)*rowsize*colsize + + (y-ymin)*rowsize)*bytesPerPixel]), + tmpBuffer1, rowsize*bytesPerPixel); + } + } + return true; +} + +bool RLECodec::DecodeByStreamsCommon(std::istream &, std::ostream &) +{ + return false; +} + +bool RLECodec::DecodeByStreams(std::istream &is, std::ostream &os) +{ + std::streampos start = is.tellg(); + // FIXME: Do some stupid work: + char dummy_buffer[256]; + std::stringstream tmpos; + + RLEFrame &frame = Internals->Frame; + frame.Read(is); + unsigned long numSegments = frame.Header.NumSegments; + + unsigned long numberOfReadBytes = 0; + + unsigned long length = Length; + assert( length ); + // Special case: + assert( GetPixelFormat().GetBitsAllocated() == 32 || + GetPixelFormat().GetBitsAllocated() == 16 || + GetPixelFormat().GetBitsAllocated() == 8 ); + if( GetPixelFormat().GetBitsAllocated() > 8 ) + { + RequestPaddedCompositePixelCode = true; + } + + assert( GetPixelFormat().GetSamplesPerPixel() == 3 || GetPixelFormat().GetSamplesPerPixel() == 1 ); + // A footnote: + // RLE *by definition* with more than one component will have applied the + // Planar Configuration because it simply does not make sense to do it + // otherwise. So implicitely RLE is indeed PlanarConfiguration == 1. However + // when the image says: "hey I am PlanarConfiguration = 0 AND RLE", then + // apply the PlanarConfiguration internally so that people don't get lost + // Because GDCM internally set PlanarConfiguration == 0 by default, even if + // the Attribute is not sent, it will still default to 0 and we will be + // consistent with ourselves... + if( GetPixelFormat().GetSamplesPerPixel() == 3 && GetPlanarConfiguration() == 0 ) + { + RequestPlanarConfiguration = true; + } + length /= numSegments; + for(unsigned long i = 0; i= 0 /*&& byte <= 127*/ ) /* 2nd is always true */ + { + is.read( dummy_buffer, byte+1 ); + //assert( is.good() ); // impossible because ALOKA_SSD-8-MONO2-RLE-SQ.dc + numberOfReadBytes += byte+1; + numOutBytes += byte+ 1; + tmpos.write( dummy_buffer, byte+1 ); + } + else if( byte <= -1 && byte >= -127 ) + { + char nextByte; + is.read( &nextByte, 1); + numberOfReadBytes += 1; + memset(dummy_buffer, nextByte, -byte + 1); + numOutBytes += -byte + 1; + tmpos.write( dummy_buffer, -byte+1 ); + } + else /* byte == -128 */ + { + assert( byte == -128 ); + } + //assert( numberOfReadBytes + frame.Header.Offset[i] - is.tellg() + start == 0); + } + assert( numOutBytes == length ); + } + + return ImageCodec::DecodeByStreams(tmpos,os); +} + +bool RLECodec::GetHeaderInfo(std::istream &is, TransferSyntax &ts) +{ + (void)is; + ts = TransferSyntax::RLELossless; + return true; +} + +ImageCodec * RLECodec::Clone() const +{ + return NULL; +} + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmRLECodec.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmRLECodec.h new file mode 100644 index 0000000..825127f --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmRLECodec.h @@ -0,0 +1,78 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMRLECODEC_H +#define GDCMRLECODEC_H + +#include "gdcmImageCodec.h" + +namespace gdcm +{ + +class Fragment; +class RLEInternals; +/** + * \brief Class to do RLE + * \note + * ANSI X3.9 + * A.4.2 RLE Compression + * Annex G defines a RLE Compression Transfer Syntax. This transfer Syntax is + * identified by the UID value "1.2.840.10008.1.2.5". If the object allows + * multi-frame images in the pixel data field, then each frame shall be encoded + * separately. Each frame shall be encoded in one and only one Fragment (see PS + * 3.5.8.2). + * + */ +class GDCM_EXPORT RLECodec : public ImageCodec +{ +friend class ImageRegionReader; +public: + RLECodec(); + ~RLECodec(); + bool CanCode(TransferSyntax const &ts) const; + bool CanDecode(TransferSyntax const &ts) const; + bool Decode(DataElement const &is, DataElement &os); + unsigned long GetBufferLength() const { return BufferLength; } + void SetBufferLength(unsigned long l) { BufferLength = l; } + + bool Code(DataElement const &in, DataElement &out); + bool GetHeaderInfo(std::istream &is, TransferSyntax &ts); + virtual ImageCodec * Clone() const; + +protected: + bool DecodeExtent( + char *buffer, + unsigned int XMin, unsigned int XMax, + unsigned int YMin, unsigned int YMax, + unsigned int ZMin, unsigned int ZMax, + std::istream & is + ); + + bool DecodeByStreams(std::istream &is, std::ostream &os); +public: + + void SetLength(unsigned long l) + { + Length = l; + } +private: + bool DecodeByStreamsCommon(std::istream &is, std::ostream &os); + RLEInternals *Internals; + unsigned long Length; + unsigned long BufferLength; + size_t DecodeFragment(Fragment const & frag, char *buffer, unsigned long llen); +}; + +} // end namespace gdcm + +#endif //GDCMRLECODEC_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmRescaler.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmRescaler.cxx new file mode 100644 index 0000000..ec63b9e --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmRescaler.cxx @@ -0,0 +1,506 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmRescaler.h" +#include +#include // abort +#include // memcpy + +namespace gdcm +{ + +// parameter 'size' is in bytes +template +void RescaleFunction(TOut *out, const TIn *in, double intercept, double slope, size_t size) +{ + size /= sizeof(TIn); + for(size_t i = 0; i != size; ++i) + { + // Implementation detail: + // The rescale function does not add the usual +0.5 to do the proper integer type + // cast, since TOut is expected to be floating point type whenever it would occur + out[i] = (TOut)(slope * in[i] + intercept); + //assert( out[i] == (TOut)(slope * in[i] + intercept) ); // will really slow down stuff... + //assert( in[i] == (TIn)(((double)out[i] - intercept) / slope + 0.5) ); + + // For image such as: gdcmData/MR16BitsAllocated_8BitsStored.dcm, the following line will not work: + // Indeed the pixel declares itself as 16/8/7 with pixel representation of 1. In this case + // anything outside the range [-127,128] is required to be discarded ! + //assert( (TIn)out[i] == in[i] ); + } +} + +// no such thing as partial specialization of function in c++ +// so instead use this trick: +template +struct FImpl; + +template +void InverseRescaleFunction(TOut *out, const TIn *in, double intercept, double slope, size_t size) +{ FImpl::InverseRescaleFunction(out,in,intercept,slope,size); } // users, don't touch this! + +template +struct FImpl +{ + // parameter 'size' is in bytes + // TODO: add template parameter for intercept/slope so that we can have specialized instantiation + // when 1. both are int, 2. slope is 1, 3. intercept is 0 + // Detail: casting from float to int is soooo slow + static void InverseRescaleFunction( TOut *out, const TIn *in, + double intercept, double slope, size_t size) // users, go ahead and specialize this + { + // If you read the code down below you'll see a specialized function for float, thus + // if we reach here it pretty much means slope/intercept were integer type + assert( intercept == (int)intercept ); + assert( slope == (int)slope ); + size /= sizeof(TIn); + for(size_t i = 0; i != size; ++i) + { + // '+ 0.5' trick is NOT needed for image such as: gdcmData/D_CLUNIE_CT1_J2KI.dcm + out[i] = (TOut)(((double)in[i] - intercept) / slope ); + } + } +}; + +template +struct FImpl +{ + static void InverseRescaleFunction(TOut *out, const float *in, + double intercept, double slope, size_t size) + { + size /= sizeof(float); + for(size_t i = 0; i != size; ++i) + { + // '+ 0.5' trick is needed for instance for : gdcmData/MR-MONO2-12-shoulder.dcm + // well known trick of adding 0.5 after a floating point type operation to properly find the + // closest integer that will represent the transformation + // TOut in this case is integer type, while input is floating point type + out[i] = (TOut)(((double)in[i] - intercept) / slope + 0.5); + //assert( out[i] == (TOut)(((double)in[i] - intercept) / slope ) ); + } + } +}; +template +struct FImpl +{ + static void InverseRescaleFunction(TOut *out, const double *in, + double intercept, double slope, size_t size) + { + size /= sizeof(double); + for(size_t i = 0; i != size; ++i) + { + // '+ 0.5' trick is needed for instance for : gdcmData/MR-MONO2-12-shoulder.dcm + // well known trick of adding 0.5 after a floating point type operation to properly find the + // closest integer that will represent the transformation + // TOut in this case is integer type, while input is floating point type + out[i] = (TOut)(((double)in[i] - intercept) / slope + 0.5); + //assert( out[i] == (TOut)(((double)in[i] - intercept) / slope ) ); + } + } +}; + +PixelFormat::ScalarType ComputeBestFit(const PixelFormat &pf, double intercept, double slope) +{ + PixelFormat::ScalarType st = PixelFormat::UNKNOWN; + assert( slope == (int)slope && intercept == (int)intercept); + + const double min = slope * (double)pf.GetMin() + intercept; + const double max = slope * (double)pf.GetMax() + intercept; + assert( min <= max ); + assert( min == (int64_t)min && max == (int64_t)max ); + if( min >= 0 ) // unsigned + { + if( max <= std::numeric_limits::max() ) + { + st = PixelFormat::UINT8; + } + else if( max <= std::numeric_limits::max() ) + { + st = PixelFormat::UINT16; + } + else if( max <= std::numeric_limits::max() ) + { + st = PixelFormat::UINT32; + } + //else if( max <= std::numeric_limits::max() ) + // { + // st = PixelFormat::FLOAT32; + // } + //else if( max <= std::numeric_limits::max() ) + // { + // st = PixelFormat::FLOAT64; + // } + else + { + assert(0); + } + } + else + { + if( max <= std::numeric_limits::max() + && min >= std::numeric_limits::min() ) + { + st = PixelFormat::INT8; + } + else if( max <= std::numeric_limits::max() + && min >= std::numeric_limits::min() ) + { + st = PixelFormat::INT16; + } + else if( max <= std::numeric_limits::max() + && min >= std::numeric_limits::min() ) + { + st = PixelFormat::INT32; + } + //else if( max <= std::numeric_limits::max() ) + // { + // st = PixelFormat::FLOAT32; + // } + //else if( max <= std::numeric_limits::max() ) + // { + // st = PixelFormat::FLOAT64; + // } + else + { + assert(0); + } + } + // postcondition: + assert( min >= PixelFormat(st).GetMin() ); + assert( max <= PixelFormat(st).GetMax() ); + assert( st != PixelFormat::UNKNOWN ); + return st; +} + +PixelFormat::ScalarType Rescaler::ComputeInterceptSlopePixelType() +{ + assert( PF != PixelFormat::UNKNOWN ); + PixelFormat::ScalarType output = PixelFormat::UNKNOWN; + if( PF == PixelFormat::SINGLEBIT ) return PixelFormat::SINGLEBIT; + if( Slope != (int)Slope || Intercept != (int)Intercept) + { + //assert( PF != PixelFormat::INT8 && PF != PixelFormat::UINT8 ); // Is there any Object that have Rescale on char ? + assert( PF != PixelFormat::SINGLEBIT ); + return PixelFormat::FLOAT64; + } + double intercept = Intercept; + double slope = Slope; + output = ComputeBestFit (PF,intercept,slope); + assert( output != PixelFormat::UNKNOWN ); + return output; +} + +template +void Rescaler::RescaleFunctionIntoBestFit(char *out, const TIn *in, size_t n) +{ + double intercept = Intercept; + double slope = Slope; + PixelFormat::ScalarType output = ComputeInterceptSlopePixelType(); + if( UseTargetPixelType ) + { + output = TargetScalarType; + } + switch(output) + { + case PixelFormat::SINGLEBIT: + assert(0); + break; + case PixelFormat::UINT8: + RescaleFunction((uint8_t*)out,in,intercept,slope,n); + break; + case PixelFormat::INT8: + RescaleFunction((int8_t*)out,in,intercept,slope,n); + break; + case PixelFormat::UINT16: + RescaleFunction((uint16_t*)out,in,intercept,slope,n); + break; + case PixelFormat::INT16: + RescaleFunction((int16_t*)out,in,intercept,slope,n); + break; + case PixelFormat::UINT32: + RescaleFunction((uint32_t*)out,in,intercept,slope,n); + break; + case PixelFormat::INT32: + RescaleFunction((int32_t*)out,in,intercept,slope,n); + break; + case PixelFormat::FLOAT32: + RescaleFunction((float*)out,in,intercept,slope,n); + break; + case PixelFormat::FLOAT64: + RescaleFunction((double*)out,in,intercept,slope,n); + break; + default: + assert(0); + break; + } + } + +template +void Rescaler::InverseRescaleFunctionIntoBestFit(char *out, const TIn *in, size_t n) +{ + double intercept = Intercept; + double slope = Slope; + //PixelFormat::ScalarType output = ComputeInterceptSlopePixelType(); + PixelFormat output = ComputePixelTypeFromMinMax(); + switch(output) + { + case PixelFormat::SINGLEBIT: + assert(0); + break; + case PixelFormat::UINT8: + InverseRescaleFunction((uint8_t*)out,in,intercept,slope,n); + break; + case PixelFormat::INT8: + InverseRescaleFunction((int8_t*)out,in,intercept,slope,n); + break; + case PixelFormat::UINT16: + InverseRescaleFunction((uint16_t*)out,in,intercept,slope,n); + break; + case PixelFormat::INT16: + InverseRescaleFunction((int16_t*)out,in,intercept,slope,n); + break; + case PixelFormat::UINT32: + InverseRescaleFunction((uint32_t*)out,in,intercept,slope,n); + break; + case PixelFormat::INT32: + InverseRescaleFunction((int32_t*)out,in,intercept,slope,n); + break; + //case PixelFormat::FLOAT32: + // InverseRescaleFunction((float*)out,in,intercept,slope,n); + // break; + default: + assert(0); + break; + } + } + + +bool Rescaler::InverseRescale(char *out, const char *in, size_t n) +{ + // fast path: + if( Slope == 1 && Intercept == 0 ) + { + memcpy(out,in,n); + return true; + } + // check if we are dealing with floating point type + if( Slope != (int)Slope || Intercept != (int)Intercept) + { + // need to rescale as double (64bits) as slope/intercept are 64bits + //assert(0); + } + // else integral type + switch(PF) + { + //case PixelFormat::UINT8: + // InverseRescaleFunctionIntoBestFit(out,(uint8_t*)in,n); + // break; + //case PixelFormat::INT8: + // InverseRescaleFunctionIntoBestFit(out,(int8_t*)in,n); + // break; + case PixelFormat::UINT16: + InverseRescaleFunctionIntoBestFit(out,(uint16_t*)in,n); + break; + case PixelFormat::INT16: + InverseRescaleFunctionIntoBestFit(out,(int16_t*)in,n); + break; + case PixelFormat::UINT32: + InverseRescaleFunctionIntoBestFit(out,(uint32_t*)in,n); + break; + case PixelFormat::INT32: + InverseRescaleFunctionIntoBestFit(out,(int32_t*)in,n); + break; + case PixelFormat::FLOAT32: + assert( sizeof(float) == 32 / 8 ); + InverseRescaleFunctionIntoBestFit(out,(float*)in,n); + break; + case PixelFormat::FLOAT64: + assert( sizeof(double) == 64 / 8 ); + InverseRescaleFunctionIntoBestFit(out,(double*)in,n); + break; + default: + //InverseRescaleFunction((unsigned short*)out,(float*)in,Intercept,Slope,n); + assert(0); + break; + } + + return true;} + +bool Rescaler::Rescale(char *out, const char *in, size_t n) +{ + if( UseTargetPixelType == false ) + { + // fast path: + if( Slope == 1 && Intercept == 0 ) + { + memcpy(out,in,n); + return true; + } + // check if we are dealing with floating point type + if( Slope != (int)Slope || Intercept != (int)Intercept) + { + // need to rescale as float (32bits) as slope/intercept are 32bits + //assert(0); + } + } + // else integral type + switch(PF) + { + case PixelFormat::SINGLEBIT: + memcpy(out,in,n); + break; + case PixelFormat::UINT8: + RescaleFunctionIntoBestFit(out,(uint8_t*)in,n); + break; + case PixelFormat::INT8: + RescaleFunctionIntoBestFit(out,(int8_t*)in,n); + break; + case PixelFormat::UINT12: + case PixelFormat::UINT16: + RescaleFunctionIntoBestFit(out,(uint16_t*)in,n); + break; + case PixelFormat::INT12: + case PixelFormat::INT16: + RescaleFunctionIntoBestFit(out,(int16_t*)in,n); + break; + case PixelFormat::UINT32: + RescaleFunctionIntoBestFit(out,(uint32_t*)in,n); + break; + case PixelFormat::INT32: + RescaleFunctionIntoBestFit(out,(int32_t*)in,n); + break; + default: + gdcmErrorMacro( "Unhandled: " << PF ); + assert(0); + break; + } + + return true; +} + +PixelFormat ComputeInverseBestFitFromMinMax(/*const PixelFormat &pf,*/ double intercept, double slope, double _min, double _max) +{ + PixelFormat st = PixelFormat::UNKNOWN; + //assert( slope == (int)slope && intercept == (int)intercept); + + double dmin = (_min - intercept ) / slope; + double dmax = (_max - intercept ) / slope; + assert( dmin <= dmax ); + assert( dmax <= std::numeric_limits::max() ); + assert( dmin >= std::numeric_limits::min() ); + /* + * Tricky: what happen in the case where floating point approximate dmax as: 65535.000244081035 + * Take for instance: _max = 64527, intercept = -1024, slope = 1.000244140625 + * => dmax = 65535.000244081035 + * thus we must always make sure to cast to an integer first. + */ + int64_t min = (int64_t)dmin; + int64_t max = (int64_t)dmax; + if( min >= 0 ) // unsigned + { + if( max <= std::numeric_limits::max() ) + { + st = PixelFormat::UINT8; + } + else if( max <= std::numeric_limits::max() ) + { + st = PixelFormat::UINT16; + assert( st.GetBitsAllocated() == 16 ); + // FIXME + if( max <= 4096 ) + { + st.SetBitsStored( 12 ); + st.SetHighBit( 11 ); + } + } + else if( max <= std::numeric_limits::max() ) + { + st = PixelFormat::UINT32; + } + else + { + assert(0); + } + } + else + { + if( max <= std::numeric_limits::max() + && min >= std::numeric_limits::min() ) + { + st = PixelFormat::INT8; + } + else if( max <= std::numeric_limits::max() + && min >= std::numeric_limits::min() ) + { + st = PixelFormat::INT16; + } + else if( max <= std::numeric_limits::max() + && min >= std::numeric_limits::min() ) + { + st = PixelFormat::INT32; + } + else + { + assert(0); + } + } + // postcondition: + assert( min >= PixelFormat(st).GetMin() ); + assert( max <= PixelFormat(st).GetMax() ); + assert( st != PixelFormat::UNKNOWN ); + assert( st != PixelFormat::FLOAT32 && st != PixelFormat::FLOAT16 && st != PixelFormat::FLOAT64 ); + return st; +} + +PixelFormat Rescaler::ComputePixelTypeFromMinMax() +{ + assert( PF != PixelFormat::UNKNOWN ); + PixelFormat output = PixelFormat::UNKNOWN; + double intercept = Intercept; + double slope = Slope; +#if 0 + if( Slope != (int)Slope || Intercept != (int)Intercept) + { + //assert( PF != PixelFormat::INT8 && PF != PixelFormat::UINT8 ); // Is there any Object that have Rescale on char ? + assert( PF == PixelFormat::FLOAT32 || PF == PixelFormat::FLOAT16 ); + PixelFormat::ScalarType dummy = PF.GetScalarType(); + switch(PF) + { + case PixelFormat::FLOAT16: + output = ComputeInverseBestFitFromMinMax (/*PF,*/intercept,slope,ScalarRangeMin,ScalarRangeMax); + break; + case PixelFormat::FLOAT32: + output = ComputeInverseBestFitFromMinMax (/*PF,*/intercept,slope,ScalarRangeMin,ScalarRangeMax); + //assert(0); + break; + default: + assert(0); + } + } +#endif + output = ComputeInverseBestFitFromMinMax (/*PF,*/intercept,slope,ScalarRangeMin,ScalarRangeMax); + assert( output != PixelFormat::UNKNOWN && output >= PixelFormat::UINT8 && output <= PixelFormat::INT32 ); + return output; +} + +void Rescaler::SetTargetPixelType( PixelFormat const & targetpf ) +{ + TargetScalarType = targetpf.GetScalarType(); +} + +void Rescaler::SetUseTargetPixelType(bool b) +{ + UseTargetPixelType = b; +} + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmRescaler.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmRescaler.h new file mode 100644 index 0000000..fd3dbfc --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmRescaler.h @@ -0,0 +1,134 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMRESCALER_H +#define GDCMRESCALER_H + +#include "gdcmTypes.h" +#include "gdcmPixelFormat.h" + +namespace gdcm +{ + +/** + * \brief Rescale class + * This class is meant to apply the linear transform of Stored Pixel Value to + * Real World Value. + * This is mostly found in CT or PET dataset, where the value are stored using + * one type, but need to be converted to another scale using a linear + * transform. + * There are basically two cases: + * In CT: the linear transform is generally integer based. E.g. the Stored + * Pixel Type is unsigned short 12bits, but to get Hounsfield unit, one need to + * apply the linear transform: + * \f[ + * RWV = 1. * SV - 1024 + * \f] + * So the best scalar to store the Real World Value will be 16 bits signed + * type. + * + * In PET: the linear transform is generally floating point based. + * Since the dynamic range can be quite high, the Rescale Slope / Rescale + * Intercept can be changing throughout the Series. So it is important to read + * all linear transform and deduce the best Pixel Type only at the end (when + * all the images to be read have been parsed). + * + * \warning Internally any time a floating point value is found either in the + * Rescale Slope or the Rescale Intercept it is assumed that the best matching + * output pixel type is FLOAT64 (in previous implementation it was FLOAT32). + * Because VR:DS is closer to a 64bits floating point type FLOAT64 is thus a + * best matching pixel type for the floating point transformation. + * + * Example: Let say input is FLOAT64, and we want UINT16 as ouput, we would do: + * + *\code + * Rescaler ir; + * ir.SetIntercept( 0 ); + * ir.SetSlope( 5.6789 ); + * ir.SetPixelFormat( FLOAT64 ); + * ir.SetMinMaxForPixelType( ((PixelFormat)UINT16).GetMin(), ((PixelFormat)UINT16).GetMax() ); + * ir.InverseRescale(output,input,numberofbytes ); + *\endcode + * + * \note handle floating point transformation back and forth to integer + * properly (no loss) + * + * \see Unpacker12Bits + */ +class GDCM_EXPORT Rescaler +{ +public: + Rescaler():Intercept(0),Slope(1),PF(PixelFormat::UNKNOWN),TargetScalarType(PixelFormat::UNKNOWN), ScalarRangeMin(0), ScalarRangeMax(0), UseTargetPixelType(false) {} + ~Rescaler() {} + + /// Direct transform + bool Rescale(char *out, const char *in, size_t n); + + /// Inverse transform + bool InverseRescale(char *out, const char *in, size_t n); + + /// Set Intercept: used for both direct&inverse transformation + void SetIntercept(double i) { Intercept = i; } + double GetIntercept() const { return Intercept; } + + /// Set Slope: user for both direct&inverse transformation + void SetSlope(double s) { Slope = s; } + double GetSlope() const { return Slope; } + + /// By default (when UseTargetPixelType is false), a best + /// matching Target Pixel Type is computed. However user can override + /// this auto selection by switching UseTargetPixelType:true and + /// also specifying the specifix Target Pixel Type + void SetTargetPixelType( PixelFormat const & targetst ); + + /// Override default behavior of Rescale + void SetUseTargetPixelType(bool b); + + /// Set Pixel Format of input data + void SetPixelFormat(PixelFormat const & pf) { PF = pf; } + + /// Compute the Pixel Format of the output data + /// Used for direct transformation + PixelFormat::ScalarType ComputeInterceptSlopePixelType(); + + /// Set target interval for output data. A best match will be computed (if possible) + /// Used for inverse transformation + void SetMinMaxForPixelType(double min, double max) + { + ScalarRangeMin = min; + ScalarRangeMax = max; + } + + /// Compute the Pixel Format of the output data + /// Used for inverse transformation + PixelFormat ComputePixelTypeFromMinMax(); + +protected: + template + void RescaleFunctionIntoBestFit(char *out, const TIn *in, size_t n); + template + void InverseRescaleFunctionIntoBestFit(char *out, const TIn *in, size_t n); + +private: + double Intercept; // 0028,1052 + double Slope; // 0028,1053 + PixelFormat PF; + PixelFormat::ScalarType TargetScalarType; + double ScalarRangeMin; + double ScalarRangeMax; + bool UseTargetPixelType; +}; + +} // end namespace gdcm + +#endif //GDCMRESCALER_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmScanner.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmScanner.cxx new file mode 100644 index 0000000..f72fb24 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmScanner.cxx @@ -0,0 +1,418 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmScanner.h" +#include "gdcmReader.h" +#include "gdcmGlobal.h" +#include "gdcmDicts.h" +#include "gdcmDict.h" +#include "gdcmDictEntry.h" +#include "gdcmStringFilter.h" +#include "gdcmProgressEvent.h" +#include "gdcmFileNameEvent.h" + +#include // std::find + +namespace gdcm +{ + + +Scanner::~Scanner() +{ +} + +void Scanner::ClearTags() +{ + Tags.clear(); +} + +void Scanner::ClearSkipTags() +{ + SkipTags.clear(); +} + +void Scanner::AddSkipTag( Tag const & t ) +{ + SkipTags.insert( t ); + assert(0); // This is NOT implemented for now +} + +// Warning: API is passing a public tag (no way to specify private tag) +void Scanner::AddPrivateTag( PrivateTag const & t ) +{ + static const Global &g = GlobalInstance; + static const Dicts &dicts = g.GetDicts(); + const DictEntry &entry = dicts.GetDictEntry( t ); + //std::cout << "Debug: " << entry << std::endl; + // Is this tag an ASCII on ? + if( entry.GetVR() & VR::VRASCII ) + { + PrivateTags.insert( t ); + } + else if( entry.GetVR() == VR::INVALID ) + { + gdcmWarningMacro( "Only tag with known VR are allowed. Tag " << t << " will be discarded" ); + } + else + { + assert( entry.GetVR() & VR::VRBINARY ); + //gdcmWarningMacro( "Only ASCII VR are supported for now. Tag " << t << " will be discarded" ); + PrivateTags.insert( t ); + } +} + +void Scanner::AddTag( Tag const & t ) +{ + static const Global &g = GlobalInstance; + static const Dicts &dicts = g.GetDicts(); + const DictEntry &entry = dicts.GetDictEntry( t ); + // Is this tag an ASCII on ? + if( entry.GetVR() & VR::VRASCII ) + { + Tags.insert( t ); + } + else if( entry.GetVR() == VR::INVALID ) + { + gdcmWarningMacro( "Only tag with known VR are allowed. Tag " << t << " will be discarded" ); + } + else + { + assert( entry.GetVR() & VR::VRBINARY ); + //gdcmWarningMacro( "Only ASCII VR are supported for now. Tag " << t << " will be discarded" ); + Tags.insert( t ); + } +} + +bool Scanner::Scan( Directory::FilenamesType const & filenames ) +{ + this->InvokeEvent( StartEvent() ); + + // Is there at least one tag ? + if( !Tags.empty() || !PrivateTags.empty() ) + { + //if( filenames.empty() ) return true; + + // Prepare hash table: + Mappings.clear(); + Mappings[""]; // Create a fake table for dummy file + + // Make our own copy: + Filenames = filenames; + + // Find the tag with the highest value (get the one from the end of the std::set) + Tag last; + if( !Tags.empty() ) + { + TagsType::const_reverse_iterator it1 = Tags.rbegin(); + const Tag & publiclast = *it1; + last = publiclast; + } + if( !PrivateTags.empty() ) + { + PrivateTagsType::const_reverse_iterator pit1 = PrivateTags.rbegin(); + Tag privatelast = *pit1; + if( last < privatelast ) last = privatelast; + } + + StringFilter sf; + Directory::FilenamesType::const_iterator it = Filenames.begin(); + const double progresstick = 1. / (double)Filenames.size(); + Progress = 0; + for(; it != Filenames.end(); ++it) + { + Reader reader; + const char *filename = it->c_str(); + assert( filename ); + reader.SetFileName( filename ); + bool read = false; + try + { + // Start reading all tags, including the 'last' one: + read = reader.ReadUpToTag(last, SkipTags); + } + catch(std::exception & ex) + { + (void)ex; + gdcmWarningMacro( "Failed to read:" << filename << " with ex:" << ex.what() ); + } + catch(...) + { + gdcmWarningMacro( "Failed to read:" << filename << " with unknown error" ); + } + if( read ) + { + // Keep the mapping: + sf.SetFile( reader.GetFile() ); + Scanner::ProcessPublicTag(sf, filename); + //Scanner::ProcessPrivateTag(sf, filename); + } + Progress += progresstick; + ProgressEvent pe; + pe.SetProgress( Progress ); + this->InvokeEvent( pe ); + // For outside application tell which file is being processed: + FileNameEvent fe( filename ); + this->InvokeEvent( fe ); + } + } + + this->InvokeEvent( EndEvent() ); + return true; +} + +void Scanner::Print( std::ostream & os ) const +{ + os << "Values:\n"; + for(ValuesType::const_iterator it = Values.begin() ; it != Values.end(); + ++it) + { + os << *it << "\n"; + } + os << "Mapping:\n"; + Directory::FilenamesType::const_iterator file = Filenames.begin(); + for(; file != Filenames.end(); ++file) + { + const char *filename = file->c_str(); + assert( filename && *filename ); + bool b = IsKey(filename); + const char *comment = !b ? "could not be read" : "could be read"; + os << "Filename: " << filename << " (" << comment << ")\n"; + //const FilenameToValue &mapping = Mappings[*tag]; + if( Mappings.find(filename) != Mappings.end() ) + { + const TagToValue &mapping = GetMapping(filename); + TagToValue::const_iterator it = mapping.begin(); + for( ; it != mapping.end(); ++it) + { + const Tag & tag = it->first; + const char *value = it->second; + os << tag << " -> [" << value << "]\n"; + } + } + } +} + +Scanner::TagToValue const & Scanner::GetMapping(const char *filename) const +{ +// assert( Mappings.find(filename) != Mappings.end() ); + assert( filename && *filename ); + if( Mappings.find(filename) != Mappings.end() ) + return Mappings.find(filename)->second; + return Mappings.find("")->second; // dummy file could not be found +} + +bool Scanner::IsKey( const char * filename ) const +{ +/* + // std::find on contiguous array will operate in 0(n) which is way too slow, assume user is not too dumb... + Directory::FilenamesType::const_iterator it = std::find(Filenames.begin(), Filenames.end(), filename); + if( it == Filenames.end() ) + { + gdcmErrorMacro( "The file: " << filename << " was not scanned" ); + return false; + } +*/ + // Look for the file in Mappings table: + assert( filename && *filename ); + MappingType::const_iterator it2 = Mappings.find(filename); + return it2 != Mappings.end(); +} + + +Directory::FilenamesType Scanner::GetKeys() const +{ + Directory::FilenamesType keys; + + Directory::FilenamesType::const_iterator file = Filenames.begin(); + for(; file != Filenames.end(); ++file) + { + const char *filename = file->c_str(); + if( IsKey( filename ) ) + { + keys.push_back( filename ); + } + } + assert( keys.size() <= Filenames.size() ); + return keys; +} + + +const char* Scanner::GetValue(const char *filename, Tag const &t) const +{ + // \precondition + assert( Tags.find( t ) != Tags.end() ); + TagToValue const &ftv = GetMapping(filename); + if( ftv.find(t) != ftv.end() ) + { + return ftv.find(t)->second; + } + return NULL; +} + +const char *Scanner::GetFilenameFromTagToValue(Tag const &t, const char *valueref) const +{ + const char *filenameref = 0; + if( valueref ) + { + Directory::FilenamesType::const_iterator file = Filenames.begin(); + size_t len = strlen( valueref ); + if( len && valueref[ len - 1 ] == ' ' ) + { + --len; + } + for(; file != Filenames.end() && !filenameref; ++file) + { + const char *filename = file->c_str(); + const char * value = GetValue(filename, t); + if( value && strncmp(value, valueref, len ) == 0 ) + { + filenameref = filename; + } + } + } + return filenameref; +} + + +/// Will loop over all files and return a vector of std::strings of filenames +/// where value match the reference value 'valueref' +Directory::FilenamesType +Scanner::GetAllFilenamesFromTagToValue(Tag const &t, const char *valueref) const +{ + Directory::FilenamesType theReturn; + if( valueref ) + { + size_t len = strlen( valueref ); + if( len && valueref[ len - 1 ] == ' ' ) + { + --len; + } + Directory::FilenamesType::const_iterator file = Filenames.begin(); + for(; file != Filenames.end(); ++file) + { + const char *filename = file->c_str(); + const char * value = GetValue(filename, t); + if( value && strncmp(value, valueref, len ) == 0 ) + { + theReturn.push_back( filename ); + } + } + } + return theReturn; + +} + +Scanner::TagToValue const & Scanner::GetMappingFromTagToValue(Tag const &t, const char *valueref) const +{ + return GetMapping( GetFilenameFromTagToValue(t, valueref) ); +} + +Scanner::ValuesType Scanner::GetValues(Tag const &t) const +{ + ValuesType vt; + Directory::FilenamesType::const_iterator file = Filenames.begin(); + for(; file != Filenames.end(); ++file) + { + const char *filename = file->c_str(); + TagToValue const &ttv = GetMapping(filename); + if( ttv.find(t) != ttv.end() ) + { + vt.insert( ttv.find(t)->second ); + } + } + return vt; +} + + +Directory::FilenamesType Scanner::GetOrderedValues(Tag const &t) const +{ + Directory::FilenamesType theReturn; + Directory::FilenamesType::const_iterator file = Filenames.begin(); + for(; file != Filenames.end(); ++file) + { + const char *filename = file->c_str(); + TagToValue const &ttv = GetMapping(filename); + if( ttv.find(t) != ttv.end() ) + { + std::string theVal = std::string(ttv.find(t)->second); + if (std::find(theReturn.begin(), theReturn.end(), theVal) == theReturn.end()){ + theReturn.push_back( theVal );//only add new tags to the list + } + } + } + return theReturn; +} + +void Scanner::ProcessPublicTag(StringFilter &sf, const char *filename) +{ + assert( filename ); + TagToValue &mapping = Mappings[filename]; + const File& file = sf.GetFile(); + + const FileMetaInformation & header = file.GetHeader(); + const DataSet & ds = file.GetDataSet(); + TagsType::const_iterator tag = Tags.begin(); + for( ; tag != Tags.end(); ++tag ) + { + if( tag->GetGroup() == 0x2 ) + { + if( header.FindDataElement( *tag ) ) + { + //std::string s; + DataElement const & de = header.GetDataElement( *tag ); + //const ByteValue *bv = de.GetByteValue(); + ////assert( VR::IsASCII( vr ) ); + //if( bv ) // Hum, should I store an empty string or what ? + // { + // s = std::string( bv->GetPointer(), bv->GetLength() ); + // s.resize( std::min( s.size(), strlen( s.c_str() ) ) ); + // } + std::string s = sf.ToString(de.GetTag()); + + // Store the potentially new value: + Values.insert( s ); + assert( Values.find( s ) != Values.end() ); + const char *value = Values.find( s )->c_str(); + assert( value ); + mapping.insert( + TagToValue::value_type(*tag, value)); + } + } + else + { + if( ds.FindDataElement( *tag ) ) + { + //std::string s; + DataElement const & de = ds.GetDataElement( *tag ); + //const ByteValue *bv = de.GetByteValue(); + ////assert( VR::IsASCII( vr ) ); + //if( bv ) // Hum, should I store an empty string or what ? + // { + // s = std::string( bv->GetPointer(), bv->GetLength() ); + // s.resize( std::min( s.size(), strlen( s.c_str() ) ) ); + // } + std::string s = sf.ToString(de.GetTag()); + + // Store the potentially new value: + Values.insert( s ); + assert( Values.find( s ) != Values.end() ); + const char *value = Values.find( s )->c_str(); + assert( value ); + mapping.insert( + TagToValue::value_type(*tag, value)); + } + } + } // end for +} + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmScanner.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmScanner.h new file mode 100644 index 0000000..c4fb763 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmScanner.h @@ -0,0 +1,209 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMSCANNER_H +#define GDCMSCANNER_H + +#include "gdcmDirectory.h" +#include "gdcmSubject.h" +#include "gdcmTag.h" +#include "gdcmPrivateTag.h" +#include "gdcmSmartPointer.h" + +#include +#include +#include + +#include // strcmp + +namespace gdcm +{ +class StringFilter; + +/** + * \brief Scanner + * This filter is meant for quickly browsing a FileSet (a set of files on + * disk). Special consideration are taken so as to read the mimimum amount of + * information in each file in order to retrieve the user specified set of + * DICOM Attribute. + * + * This filter is dealing with both VRASCII and VRBINARY element, thanks to the + * help of gdcm::StringFilter + * + * \warning IMPORTANT In case of file where tags are not ordered (illegal as + * per DICOM specification), the output will be missing information + * + * \note implementation details. All values are stored in a std::set of + * std::string. Then the address of the cstring underlying the std::string is + * used in the std::map. + * + * This class implement the Subject/Observer pattern trigger the following events: + * \li ProgressEvent + * \li StartEvent + * \li EndEvent + */ +class GDCM_EXPORT Scanner : public Subject +{ + friend std::ostream& operator<<(std::ostream &_os, const Scanner &s); +public: + Scanner():Values(),Filenames(),Mappings() {} + ~Scanner(); + + /// struct to map a filename to a value + /// Implementation note: + /// all std::map in this class will be using const char * and not std::string + /// since we are pointing to existing std::string (hold in a std::vector) + /// this avoid an extra copy of the byte array. + /// Tag are used as Tag class since sizeof(tag) <= sizeof(pointer) + typedef std::map TagToValue; + //typedef std::map TagToValue; //StringMap; + //typedef TagToStringMap TagToValue; + typedef TagToValue::value_type TagToValueValueType; + + /// Add a tag that will need to be read. Those are root level skip tags + void AddTag( Tag const & t ); + void ClearTags(); + + // Work in progress do not use: + void AddPrivateTag( PrivateTag const & t ); + + /// Add a tag that will need to be skipped. Those are root level skip tags + void AddSkipTag( Tag const & t ); + void ClearSkipTags(); + + /// Start the scan ! + bool Scan( Directory::FilenamesType const & filenames ); + + Directory::FilenamesType const &GetFilenames() const { return Filenames; } + + /// Print result + void Print( std::ostream & os ) const; + + /// Check if filename is a key in the Mapping table. + /// returns true only of file can be found, which means + /// the file was indeed a DICOM file that could be processed + bool IsKey( const char * filename ) const; + + /// Return the list of filename that are key in the internal map, + /// which means those filename were properly parsed + Directory::FilenamesType GetKeys() const; + + // struct to store all the values found: + typedef std::set< std::string > ValuesType; + + /// Get all the values found (in lexicographic order) + ValuesType const & GetValues() const { return Values; } + + /// Get all the values found (in lexicographic order) associated with Tag 't' + ValuesType GetValues(Tag const &t) const; + + /// Get all the values found (in a vector) associated with Tag 't' + /// This function is identical to GetValues, but is accessible from the wrapped + /// layer (python, C#, java) + Directory::FilenamesType GetOrderedValues(Tag const &t) const; + + /* ltstr is CRITICAL, otherwise pointers value are used to do the key comparison */ + struct ltstr + { + bool operator()(const char* s1, const char* s2) const + { + assert( s1 && s2 ); + return strcmp(s1, s2) < 0; + } + }; + typedef std::map MappingType; + typedef MappingType::const_iterator ConstIterator; + ConstIterator Begin() const { return Mappings.begin(); } + ConstIterator End() const { return Mappings.end(); } + + /// Mappings are the mapping from a particular tag to the map, mapping filename to value: + MappingType const & GetMappings() const { return Mappings; } + + /// Get the std::map mapping filenames to value for file 'filename' + TagToValue const & GetMapping(const char *filename) const; + + /// Will loop over all files and return the first file where value match the reference value + /// 'valueref' + const char *GetFilenameFromTagToValue(Tag const &t, const char *valueref) const; + + /// Will loop over all files and return a vector of std::strings of filenames + /// where value match the reference value 'valueref' + Directory::FilenamesType GetAllFilenamesFromTagToValue(Tag const &t, const char *valueref) const; + + /// See GetFilenameFromTagToValue(). This is simply GetFilenameFromTagToValue followed + // by a call to GetMapping() + TagToValue const & GetMappingFromTagToValue(Tag const &t, const char *value) const; + + /// Retrieve the value found for tag: t associated with file: filename + /// This is meant for a single short call. If multiple calls (multiple tags) + /// should be done, prefer the GetMapping function, and then reuse the TagToValue + /// hash table. + /// \warning Tag 't' should have been added via AddTag() prior to the Scan() call ! + const char* GetValue(const char *filename, Tag const &t) const; + + /// for wrapped language: instanciate a reference counted object + static SmartPointer New() { return new Scanner; } + +protected: + void ProcessPublicTag(StringFilter &sf, const char *filename); +private: + // struct to store all uniq tags in ascending order: + typedef std::set< Tag > TagsType; + typedef std::set< PrivateTag > PrivateTagsType; + std::set< Tag > Tags; + std::set< PrivateTag > PrivateTags; + std::set< Tag > SkipTags; + ValuesType Values; + Directory::FilenamesType Filenames; + + // Main struct that will hold all mapping: + MappingType Mappings; + + double Progress; +}; +//----------------------------------------------------------------------------- +inline std::ostream& operator<<(std::ostream &os, const Scanner &s) +{ + s.Print( os ); + return os; +} + +#if defined(SWIGPYTHON) || defined(SWIGCSHARP) || defined(SWIGJAVA) +/* + * HACK: I need this temp class to be able to manipulate a std::map from python, + * swig does not support wrapping of simple class like std::map... + */ +class SWIGTagToValue +{ +public: + SWIGTagToValue(Scanner::TagToValue const &t2v):Internal(t2v),it(t2v.begin()) {} + const Scanner::TagToValueValueType& GetCurrent() const { return *it; } + const Tag& GetCurrentTag() const { return it->first; } + const char *GetCurrentValue() const { return it->second; } + void Start() { it = Internal.begin(); } + bool IsAtEnd() const { return it == Internal.end(); } + void Next() { ++it; } +private: + const Scanner::TagToValue& Internal; + Scanner::TagToValue::const_iterator it; +}; +#endif /* SWIG */ + +/** + * \example ScanDirectory.cs + * This is a C# example on how to use gdcm::Scanner + */ + +} // end namespace gdcm + +#endif //GDCMSCANNER_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmSegment.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmSegment.cxx new file mode 100644 index 0000000..eb75c68 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmSegment.cxx @@ -0,0 +1,234 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmSegment.h" +#include "gdcmCodeString.h" + +#include + +namespace gdcm +{ + +static const char * ALGOTypeStrings[] = { + "MANUAL", + "AUTOMATIC", + + 0 +}; + +const char * Segment::GetALGOTypeString(ALGOType type) +{ + assert( type <= ALGOType_END ); + return ALGOTypeStrings[(int)type]; +} + +Segment::ALGOType Segment::GetALGOType(const char * type) +{ + if(!type) return ALGOType_END; + + // Delete possible space as last character + String<> str( type ); + str.Trim(); + + const char * strClear = str.Trim().c_str(); + + for(unsigned int i = 0; ALGOTypeStrings[i] != 0; ++i) + { + if( strcmp(strClear, ALGOTypeStrings[i]) == 0 ) + { + return (ALGOType)i; + } + } + // Ouch ! We did not find anything, that's pretty bad, let's hope that + // the toolkit which wrote the image is buggy and tolerate space padded binary + // string + CodeString codestring = strClear; + std::string cs = codestring.GetAsString(); + for(unsigned int i = 0; ALGOTypeStrings[i] != 0; ++i) + { + if( strcmp(cs.c_str(), ALGOTypeStrings[i]) == 0 ) + { + return (ALGOType)i; + } + } + + return ALGOType_END; +} + +Segment::Segment(): + SegmentNumber(0), + SegmentLabel(""), + SegmentDescription(""), + AnatomicRegion(), + PropertyCategory(), + PropertyType(), + SegmentAlgorithmType(ALGOType_END), + SegmentAlgorithmName(""), + SurfaceCount(0), + Surfaces() +{ +} + +Segment::~Segment() +{ +} + +unsigned short Segment::GetSegmentNumber() const +{ + return SegmentNumber; +} + +void Segment::SetSegmentNumber(const unsigned short num) +{ + SegmentNumber = num; +} + +const char * Segment::GetSegmentLabel() const +{ + return SegmentLabel.c_str(); +} + +void Segment::SetSegmentLabel(const char * label) +{ + SegmentLabel = label; +} + +const char * Segment::GetSegmentDescription() const +{ + return SegmentDescription.c_str(); +} + +void Segment::SetSegmentDescription(const char * description) +{ + SegmentDescription = description; +} + +SegmentHelper::BasicCodedEntry const & Segment::GetAnatomicRegion() const +{ + return AnatomicRegion; +} + +SegmentHelper::BasicCodedEntry & Segment::GetAnatomicRegion() +{ + return AnatomicRegion; +} + +void Segment::SetAnatomicRegion(SegmentHelper::BasicCodedEntry const & BSE) +{ + AnatomicRegion.CV = BSE.CV; + AnatomicRegion.CSD = BSE.CSD; + AnatomicRegion.CM = BSE.CM; +} + +SegmentHelper::BasicCodedEntry const & Segment::GetPropertyCategory() const +{ + return PropertyCategory; +} + +SegmentHelper::BasicCodedEntry & Segment::GetPropertyCategory() +{ + return PropertyCategory; +} + +void Segment::SetPropertyCategory(SegmentHelper::BasicCodedEntry const & BSE) +{ + PropertyCategory.CV = BSE.CV; + PropertyCategory.CSD = BSE.CSD; + PropertyCategory.CM = BSE.CM; +} + +SegmentHelper::BasicCodedEntry const & Segment::GetPropertyType() const +{ + return PropertyType; +} + +SegmentHelper::BasicCodedEntry & Segment::GetPropertyType() +{ + return PropertyType; +} + +void Segment::SetPropertyType(SegmentHelper::BasicCodedEntry const & BSE) +{ + PropertyType.CV = BSE.CV; + PropertyType.CSD = BSE.CSD; + PropertyType.CM = BSE.CM; +} + +Segment::ALGOType Segment::GetSegmentAlgorithmType() const +{ + return SegmentAlgorithmType; +} + +void Segment::SetSegmentAlgorithmType(Segment::ALGOType type) +{ + assert(type <= ALGOType_END); + SegmentAlgorithmType = type; +} + +void Segment::SetSegmentAlgorithmType(const char * typeStr) +{ + SetSegmentAlgorithmType( GetALGOType(typeStr) ); +} + +const char * Segment::GetSegmentAlgorithmName() const +{ + return SegmentAlgorithmName.c_str(); +} + +void Segment::SetSegmentAlgorithmName(const char * name) +{ + SegmentAlgorithmName = name; +} + +void Segment::ComputeSurfaceCount() +{ + SurfaceCount = Surfaces.size(); +} + +unsigned long Segment::GetSurfaceCount() +{ + if (SurfaceCount == 0) + { + ComputeSurfaceCount(); + } + + return SurfaceCount; +} + +void Segment::SetSurfaceCount(const unsigned long nb) +{ + SurfaceCount = nb; +} + +Segment::SurfaceVector const & Segment::GetSurfaces() const +{ + return Surfaces; +} + +Segment::SurfaceVector & Segment::GetSurfaces() +{ + return Surfaces; +} + +SmartPointer< Surface > Segment::GetSurface(const unsigned int idx /*= 0*/) const +{ + assert( idx < SurfaceCount ); + return Surfaces[idx]; +} + +void Segment::AddSurface(SmartPointer< Surface > surface) +{ + Surfaces.push_back(surface); +} + +} diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmSegment.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmSegment.h new file mode 100644 index 0000000..4d72fa3 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmSegment.h @@ -0,0 +1,126 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMSEGMENT_H +#define GDCMSEGMENT_H + +#include + +#include +#include +#include "gdcmSegmentHelper.h" + +namespace gdcm +{ + +/** + * \brief This class defines a segment. + * It mainly contains attributes of group 0x0062. + * In addition, it can be associated with surface. + * + * \see PS 3.3 C.8.20.2 and C.8.23 + */ +class GDCM_EXPORT Segment : public Object +{ +public: + + typedef std::vector< SmartPointer< Surface > > SurfaceVector; + + typedef enum { + MANUAL = 0, + AUTOMATIC, + ALGOType_END + } ALGOType; + + static const char * GetALGOTypeString(ALGOType type); + static ALGOType GetALGOType(const char * type); + + + Segment(); + + virtual ~Segment(); + + //** Segment getters/setters **// + unsigned short GetSegmentNumber() const; + void SetSegmentNumber(const unsigned short num); + + const char * GetSegmentLabel() const; + void SetSegmentLabel(const char * label); + + const char * GetSegmentDescription() const; + void SetSegmentDescription(const char * description); + + SegmentHelper::BasicCodedEntry const & GetAnatomicRegion() const; + SegmentHelper::BasicCodedEntry & GetAnatomicRegion(); + void SetAnatomicRegion(SegmentHelper::BasicCodedEntry const & BSE); + + SegmentHelper::BasicCodedEntry const & GetPropertyCategory() const; + SegmentHelper::BasicCodedEntry & GetPropertyCategory(); + void SetPropertyCategory(SegmentHelper::BasicCodedEntry const & BSE); + + SegmentHelper::BasicCodedEntry const & GetPropertyType() const; + SegmentHelper::BasicCodedEntry & GetPropertyType(); + void SetPropertyType(SegmentHelper::BasicCodedEntry const & BSE); + + ALGOType GetSegmentAlgorithmType() const; + void SetSegmentAlgorithmType(ALGOType type); + void SetSegmentAlgorithmType(const char * typeStr); + + const char * GetSegmentAlgorithmName() const; + void SetSegmentAlgorithmName(const char * name); + + //** Surface getters/setters **// + unsigned long GetSurfaceCount(); + void SetSurfaceCount(const unsigned long nb); + + SurfaceVector const & GetSurfaces() const; + SurfaceVector & GetSurfaces(); + + SmartPointer< Surface > GetSurface(const unsigned int idx = 0) const; + + void AddSurface(SmartPointer< Surface > surface); + +protected : + //** Segment members **// + //0062 0004 US 1 Segment Number + unsigned short SegmentNumber; + //0062 0005 LO 1 Segment Label + std::string SegmentLabel; + //0062 0006 ST 1 Segment Description + std::string SegmentDescription; + + // General Anatomic Region + SegmentHelper::BasicCodedEntry AnatomicRegion; + // Property Category Code + SegmentHelper::BasicCodedEntry PropertyCategory; + // Property Type Code + SegmentHelper::BasicCodedEntry PropertyType; + + //0062 0008 CS 1 Segment Algorithm Type + ALGOType SegmentAlgorithmType; + //0062 0009 LO 1 Segment Algorithm Name + std::string SegmentAlgorithmName; + + //** Surface members **// + //0066 002a UL 1 Surface Count + unsigned long SurfaceCount; + + SurfaceVector Surfaces; + +private : + void ComputeSurfaceCount(); +}; + +} + +#endif // GDCMSEGMENT_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmSegmentHelper.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmSegmentHelper.cxx new file mode 100644 index 0000000..789f828 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmSegmentHelper.cxx @@ -0,0 +1,46 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmSegmentHelper.h" + +namespace gdcm +{ + +namespace SegmentHelper +{ + +bool BasicCodedEntry::IsEmpty(const bool checkOptionalAttributes/* = false*/) const +{ + bool res = true; + + if (!CV.empty() && !CSD.empty() && !CM.empty()) + { + if (checkOptionalAttributes) + { + if (!CSV.empty()) + { + res = false; + } + } + else + { + res = false; + } + } + + return res; +} + +} // end of SegmentHelper namespace + +} // end of gdcm namespace diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmSegmentHelper.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmSegmentHelper.h new file mode 100644 index 0000000..01ee18e --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmSegmentHelper.h @@ -0,0 +1,90 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMSEGMENTHELPER_H +#define GDCMSEGMENTHELPER_H + +#include + +namespace gdcm +{ + +namespace SegmentHelper +{ + +/** + * \brief This structure defines a basic coded entry with all of its attributes. + * + * \see PS 3.3 section 8.8. + */ +struct BasicCodedEntry +{ + /** + * \brief Constructor. + */ + BasicCodedEntry(): + CV(""), + CSD(""), + CSV(""), + CM("") + {} + + /** + * \brief constructor which defines type 1 attributes. + */ + BasicCodedEntry(const char * a_CV, + const char * a_CSD, + const char * a_CM): + CV(a_CV), + CSD(a_CSD), + CSV(""), + CM(a_CM) + {} + + /** + * \brief constructor which defines attributes. + */ + BasicCodedEntry(const char * a_CV, + const char * a_CSD, + const char * a_CSV, + const char * a_CM): + CV(a_CV), + CSD(a_CSD), + CSV(a_CSV), + CM(a_CM) + {} + + /** + * \brief Check if each attibutes of the basic coded entry is defined. + * + * \param checkOptionalAttributes Check also type 1C attributes. + */ + bool IsEmpty(const bool checkOptionalAttributes = false) const; + + + //** Members **// + // 0008 0100 1 Code Value + std::string CV; /// Code Value attribute + // 0008 0102 1 Coding Scheme Designator + std::string CSD; /// Coding Scheme Designator attribute + // 0008 0103 1C Coding Scheme Version + std::string CSV; /// Coding Scheme Version attribute + // 0008 0104 1 Code Meaning + std::string CM; /// Code Meaning attribute +}; + +} // end of SegmentHelper namespace + +} // end of gdcm namespace + +#endif // GDCMSEGMENTHELPER_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmSegmentReader.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmSegmentReader.cxx new file mode 100644 index 0000000..c985dd3 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmSegmentReader.cxx @@ -0,0 +1,350 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmSegmentReader.h" +#include "gdcmMediaStorage.h" +#include "gdcmAttribute.h" +#include "gdcmString.h" + +namespace gdcm +{ + +SegmentReader::SegmentReader() +{ +} + +SegmentReader::~SegmentReader() +{ +} + +const SegmentReader::SegmentVector SegmentReader::GetSegments() const +{ + return const_cast(this)->GetSegments(); +} + +SegmentReader::SegmentVector SegmentReader::GetSegments() +{ + SegmentVector res; + + // Make a segment vector from map with no duplicate. + SegmentMap::const_iterator itMap = Segments.begin(); + SegmentMap::const_iterator itMapEnd = Segments.end(); + if (itMap != itMapEnd) + { + // Add first segment + res.push_back(itMap->second); + itMap++; + + // Search and add only different segments + SegmentVector::const_iterator itVec; + SegmentVector::const_iterator itVecEnd; + for (; itMap != itMapEnd; itMap++) + { + itVec = res.begin(); + itVecEnd = res.end(); // if res is a list, remove this line + while (itVec != itVecEnd && itMap->second != *itVec) + itVec++; + if (itVec == itVecEnd) + res.push_back(itMap->second); + } + } + + return res; +} + +//unsigned int SegmentReader::GetNumberOfSegments() +//{ +// return GetSegments().size(); +//} + +bool SegmentReader::Read() +{ + bool res = false; + + // Read a file + if( !Reader::Read() ) + { + return res; + } + + // Read Segments from file + const FileMetaInformation & header = F->GetHeader(); + MediaStorage ms = header.GetMediaStorage(); + + if( ms == MediaStorage::SegmentationStorage + || ms == MediaStorage::SurfaceSegmentationStorage ) + { + res = ReadSegments(); + } + else + { + const char * modality = ms.GetModality(); + const DataSet & dsRoot = F->GetDataSet(); + if (modality != 0) + { // Check modality + String<> modalityStr( modality ); + if ( modalityStr.Trim() == "SEG" ) + { + res = ReadSegments(); + } + else if (dsRoot.FindDataElement( Tag(0x0062, 0x0002) )) + { // Try to find Segment Sequence + res = ReadSegments(); + } + } + else if (dsRoot.FindDataElement( Tag(0x0062, 0x0002) )) + { // Try to find Segment Sequence + res = ReadSegments(); + } + } + + return res; +} + +bool SegmentReader::ReadSegments() +{ + bool res = false; + + const DataSet & ds = F->GetDataSet(); + + // Segment Sequence + const Tag segmentSQTag(0x0062, 0x0002); + if (ds.FindDataElement(segmentSQTag)) + { + SmartPointer< SequenceOfItems > segmentSQ = ds.GetDataElement(segmentSQTag).GetValueAsSQ(); + + const size_t numberOfSegments = segmentSQ->GetNumberOfItems(); + if ( numberOfSegments == 0) + { + gdcmErrorMacro( "No segment found" ); + return false; + } + + for (unsigned int i = 1; i <= numberOfSegments; ++i) + { + if ( !ReadSegment( segmentSQ->GetItem(i), i ) ) + { + gdcmWarningMacro( "Segment "< segment = new Segment; + + const DataSet & rootDs = GetFile().GetDataSet(); + const DataSet & segmentDS = segmentItem.GetNestedDataSet(); + + // Segment Number + const Tag segmentNumberTag(0x0062, 0x0004); + if (segmentDS.FindDataElement( segmentNumberTag ) + && !segmentDS.GetDataElement( segmentNumberTag ).IsEmpty() ) + { + Attribute<0x0062, 0x0004> segmentNumberAt; + segmentNumberAt.SetFromDataSet( segmentDS ); + segment->SetSegmentNumber( segmentNumberAt.GetValue() ); + } + else + { + segment->SetSegmentNumber( (unsigned short)idx ); + } + + // Segment Label + Attribute<0x0062, 0x0005> segmentLabelAt; + segmentLabelAt.SetFromDataSet( segmentDS ); + segment->SetSegmentLabel( segmentLabelAt.GetValue() ); + + // Segment Description + Attribute<0x0062, 0x0006> segmentDescriptionAt; + segmentDescriptionAt.SetFromDataSet( segmentDS ); + segment->SetSegmentDescription( segmentDescriptionAt.GetValue() ); + + // Segment Algorithm Type + Attribute<0x0062, 0x0008> segmentAlgoType; + segmentAlgoType.SetFromDataSet( segmentDS ); + segment->SetSegmentAlgorithmType( segmentAlgoType.GetValue() ); + + // Surface Count + Attribute<0x0066, 0x002A> surfaceCountAt; + surfaceCountAt.SetFromDataSet( segmentDS ); + const unsigned long surfaceCount = surfaceCountAt.GetValue(); + segment->SetSurfaceCount( surfaceCount ); + + // Check if there is a Surface Segmentation Module + if (surfaceCount > 0 + || rootDs.FindDataElement( Tag(0x0066, 0x0002) )) + { + //***** GENERAL ANATOMY MANDATORY MACRO ATTRIBUTES *****// + // Anatomic Region Sequence (0008,2218) Type 1 + if( segmentDS.FindDataElement( Tag(0x0008, 0x2218) ) ) + { + SmartPointer anatRegSQ = segmentDS.GetDataElement( Tag(0x0008, 0x2218) ).GetValueAsSQ(); + + if (anatRegSQ->GetNumberOfItems() > 0) // Only one item is a type 1 + { + const Item & anatRegItem = anatRegSQ->GetItem(1); + const DataSet & anatRegDS = anatRegItem.GetNestedDataSet(); + + //***** CODE SEQUENCE MACRO ATTRIBUTES *****// + SegmentHelper::BasicCodedEntry & anatReg = segment->GetAnatomicRegion(); + + // Code Value (Type 1) + Attribute<0x0008, 0x0100> codeValueAt; + codeValueAt.SetFromDataSet( anatRegDS ); + anatReg.CV = codeValueAt.GetValue(); + + // Coding Scheme (Type 1) + Attribute<0x0008, 0x0102> codingSchemeAt; + codingSchemeAt.SetFromDataSet( anatRegDS ); + anatReg.CSD = codingSchemeAt.GetValue(); + + // Code Meaning (Type 1) + Attribute<0x0008, 0x0104> codeMeaningAt; + codeMeaningAt.SetFromDataSet( anatRegDS ); + anatReg.CM = codeMeaningAt.GetValue(); + } + } + // else assert? return false? gdcmWarning? + + //***** Segmented Property Category Code Sequence *****// + // Segmented Property Category Code Sequence (0062,0003) Type 1 + if( segmentDS.FindDataElement( Tag(0x0062, 0x0003) ) ) + { + SmartPointer propCatSQ = segmentDS.GetDataElement( Tag(0x0062, 0x0003) ).GetValueAsSQ(); + + if (propCatSQ->GetNumberOfItems() > 0) // Only one item is a type 1 + { + const Item & propCatItem = propCatSQ->GetItem(1); + const DataSet & propCatDS = propCatItem.GetNestedDataSet(); + + //***** CODE SEQUENCE MACRO ATTRIBUTES *****// + SegmentHelper::BasicCodedEntry & propCat = segment->GetPropertyCategory(); + + // Code Value (Type 1) + Attribute<0x0008, 0x0100> codeValueAt; + codeValueAt.SetFromDataSet( propCatDS ); + propCat.CV = codeValueAt.GetValue(); + + // Coding Scheme (Type 1) + Attribute<0x0008, 0x0102> codingSchemeAt; + codingSchemeAt.SetFromDataSet( propCatDS ); + propCat.CSD = codingSchemeAt.GetValue(); + + // Code Meaning (Type 1) + Attribute<0x0008, 0x0104> codeMeaningAt; + codeMeaningAt.SetFromDataSet( propCatDS ); + propCat.CM = codeMeaningAt.GetValue(); + } + } + // else assert? return false? gdcmWarning? + + //***** Segmented Property Type Code Sequence *****// + // Segmented Property Type Code Sequence (0062,000F) Type 1 + if( segmentDS.FindDataElement( Tag(0x0062, 0x000F) ) ) + { + SmartPointer propTypSQ = segmentDS.GetDataElement( Tag(0x0062, 0x000F) ).GetValueAsSQ(); + + if (propTypSQ->GetNumberOfItems() > 0) // Only one item is a type 1 + { + const Item & propTypItem = propTypSQ->GetItem(1); + const DataSet & propTypDS = propTypItem.GetNestedDataSet(); + + //***** CODE SEQUENCE MACRO ATTRIBUTES *****// + SegmentHelper::BasicCodedEntry & propTyp = segment->GetPropertyType(); + + // Code Value (Type 1) + Attribute<0x0008, 0x0100> codeValueAt; + codeValueAt.SetFromDataSet( propTypDS ); + propTyp.CV = codeValueAt.GetValue(); + + // Coding Scheme (Type 1) + Attribute<0x0008, 0x0102> codingSchemeAt; + codingSchemeAt.SetFromDataSet( propTypDS ); + propTyp.CSD = codingSchemeAt.GetValue(); + + // Code Meaning (Type 1) + Attribute<0x0008, 0x0104> codeMeaningAt; + codeMeaningAt.SetFromDataSet( propTypDS ); + propTyp.CM = codeMeaningAt.GetValue(); + } + } + // else assert? return false? gdcmWarning? + + // Referenced Surface Sequence + const Tag refSurfaceSQTag(0x0066, 0x002B); + if (segmentDS.FindDataElement(refSurfaceSQTag)) + { + SmartPointer< SequenceOfItems > refSurfaceSQ = segmentDS.GetDataElement(refSurfaceSQTag).GetValueAsSQ(); + + // Index each surface of a segment + SequenceOfItems::ConstIterator itRefSurface = refSurfaceSQ->Begin(); + SequenceOfItems::ConstIterator itEndRefSurface = refSurfaceSQ->End(); + unsigned long numberOfSurfaces = 0; + for (; itRefSurface != itEndRefSurface; itRefSurface++) + { + const DataSet & refSurfaceDS = itRefSurface->GetNestedDataSet(); + + // Referenced Surface Number + Attribute<0x0066, 0x002C> refSurfaceNumberAt; + refSurfaceNumberAt.SetFromDataSet( refSurfaceDS ); + unsigned long refSurfaceNumber; + if ( !refSurfaceNumberAt.GetAsDataElement().IsEmpty() ) + { + refSurfaceNumber = refSurfaceNumberAt.GetValue(); + } + else + { + refSurfaceNumber = idx; + } + // Index the segment with its referenced surface number + Segments[refSurfaceNumber] = segment; + + // Compute number of items + // (can not use GetNumberOfItems because of it returns a unsigned int) + ++numberOfSurfaces; + } + + // Set surface count corresponding to number of items + if ( numberOfSurfaces != surfaceCount) + { + segment->SetSurfaceCount( numberOfSurfaces ); // Is it the right thing to do? + } + } + else + {// Index the segment with item number + Segments[idx] = segment; + } + } + else + { // If is not a surface segmentation storage + + // Segment Algorithm Name + Attribute<0x0062, 0x0009> segmentAlgoName; + segmentAlgoName.SetFromDataSet( segmentDS ); + segment->SetSegmentAlgorithmName( segmentAlgoName.GetValue() ); + + // Index the segment with item number + Segments[idx] = segment; + } + + return true; +} + +} diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmSegmentReader.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmSegmentReader.h new file mode 100644 index 0000000..0b36f7b --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmSegmentReader.h @@ -0,0 +1,65 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMSEGMENTREADER_H +#define GDCMSEGMENTREADER_H + +#include + +#include +#include + +namespace gdcm +{ + +/** + * \brief This class defines a segment reader. + * It reads attributes of group 0x0062. + * + * \see PS 3.3 C.8.20.2 and C.8.23 + */ +class GDCM_EXPORT SegmentReader : public Reader +{ +public: + typedef std::vector< SmartPointer< Segment > > SegmentVector; + + SegmentReader(); + + virtual ~SegmentReader(); + + /// Read + virtual bool Read(); // Set to protected ? + + //** Segment getters/setters **// + const SegmentVector GetSegments() const; + SegmentVector GetSegments(); + +// unsigned int GetNumberOfSegments(); + +protected: + + typedef std::map< unsigned long, SmartPointer< Segment > > SegmentMap; + + bool ReadSegments(); + + bool ReadSegment(const Item & segmentItem, const unsigned int idx); + + + SegmentMap Segments; // The key value is item number (in segment sequence) + // or the surface number (for a surface segmentation). + +}; + +} + +#endif // GDCMSEGMENTREADER_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmSegmentWriter.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmSegmentWriter.cxx new file mode 100644 index 0000000..ea64228 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmSegmentWriter.cxx @@ -0,0 +1,434 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmSegmentWriter.h" +#include "gdcmAttribute.h" + +namespace gdcm +{ + +SegmentWriter::SegmentWriter() +{ +} + +SegmentWriter::~SegmentWriter() +{ +} + +unsigned int SegmentWriter::GetNumberOfSegments() const +{ + return (unsigned int)Segments.size(); +} + +void SegmentWriter::SetNumberOfSegments(const unsigned int size) +{ + Segments.resize(size); +} + +const SegmentWriter::SegmentVector & SegmentWriter::GetSegments() const +{ + return Segments; +} + +SegmentWriter::SegmentVector & SegmentWriter::GetSegments() +{ + return Segments; +} + +SmartPointer< Segment > SegmentWriter::GetSegment(const unsigned int idx /*= 0*/) const +{ + assert( idx < Segments.size() ); + return Segments[idx]; +} + +void SegmentWriter::AddSegment(SmartPointer< Segment > segment) +{ + Segments.push_back(segment); +} + +void SegmentWriter::SetSegments(SegmentVector & segments) +{ + Segments = segments; +} + +bool SegmentWriter::PrepareWrite() +{ + File & file = GetFile(); + DataSet & ds = file.GetDataSet(); + + // Segment Sequence + SmartPointer segmentsSQ; + if( !ds.FindDataElement( Tag(0x0062, 0x0002) ) ) + { + segmentsSQ = new SequenceOfItems; + DataElement detmp( Tag(0x0062, 0x0002) ); + detmp.SetVR( VR::SQ ); + detmp.SetValue( *segmentsSQ ); + detmp.SetVLToUndefined(); + ds.Insert( detmp ); + } + segmentsSQ = ds.GetDataElement( Tag(0x0062, 0x0002) ).GetValueAsSQ(); + segmentsSQ->SetLengthToUndefined(); + +{ + // Fill the Segment Sequence + const unsigned int numberOfSegments = this->GetNumberOfSegments(); + assert( numberOfSegments ); + const size_t nbItems = segmentsSQ->GetNumberOfItems(); + if (nbItems < numberOfSegments) + { + const size_t diff = numberOfSegments - nbItems; + const size_t nbOfItemToMake = (diff > 0?diff:0); + for(unsigned int i = 1; i <= nbOfItemToMake; ++i) + { + Item item; + item.SetVLToUndefined(); + segmentsSQ->AddItem(item); + } + } +} + // else Should I remove items? + + std::vector< SmartPointer< Segment > >::const_iterator it0 = Segments.begin(); + std::vector< SmartPointer< Segment > >::const_iterator it0End = Segments.end(); + unsigned int itemNumber = 1; + unsigned long surfaceNumber = 1; + for (; it0 != it0End; it0++) + { + SmartPointer< Segment > segment = *it0; + assert( segment ); + + Item & segmentItem = segmentsSQ->GetItem(itemNumber); + DataSet & segmentDS = segmentItem.GetNestedDataSet(); + + // Segment Number (Type 1) + Attribute<0x0062, 0x0004> segmentNumberAt; + unsigned short segmentNumber = segment->GetSegmentNumber(); + if (segmentNumber == 0) + segmentNumber = (unsigned short)itemNumber; + segmentNumberAt.SetValue( segmentNumber ); + segmentDS.Replace( segmentNumberAt.GetAsDataElement() ); + + // Segment Label (Type 1) + const char * segmentLabel = segment->GetSegmentLabel(); + if ( strcmp(segmentLabel, "") != 0 ) + { + gdcmWarningMacro("No segment label specified"); + } + Attribute<0x0062, 0x0005> segmentLabelAt; + segmentLabelAt.SetValue( segmentLabel ); + segmentDS.Replace( segmentLabelAt.GetAsDataElement() ); + + // Segment Description (Type 3) + const char * segmentDescription = segment->GetSegmentDescription(); + if ( strcmp(segmentDescription, "") != 0 ) + { + Attribute<0x0062, 0x0006> segmentDescriptionAt; + segmentDescriptionAt.SetValue( segmentDescription ); + segmentDS.Replace( segmentDescriptionAt.GetAsDataElement() ); + } + + // Segment Algorithm Type (Type 1) + const char * segmentAlgorithmType = Segment::GetALGOTypeString( segment->GetSegmentAlgorithmType() ); + if ( segmentAlgorithmType == 0 ) + { + gdcmWarningMacro("No segment algorithm type specified"); + Attribute<0x0062, 0x0008> segmentAlgorithmTypeAt; + segmentAlgorithmTypeAt.SetValue( "" ); + segmentDS.Replace( segmentAlgorithmTypeAt.GetAsDataElement() ); + } + else + { + Attribute<0x0062, 0x0008> segmentAlgorithmTypeAt; + segmentAlgorithmTypeAt.SetValue( segmentAlgorithmType ); + segmentDS.Replace( segmentAlgorithmTypeAt.GetAsDataElement() ); + } + + //***** GENERAL ANATOMY MANDATORY MACRO ATTRIBUTES *****// + { + const SegmentHelper::BasicCodedEntry & anatReg = segment->GetAnatomicRegion(); + if (anatReg.IsEmpty()) + { + gdcmWarningMacro("Anatomic region not specified or incomplete"); + } + + // Anatomic Region Sequence (0008,2218) Type 1 + SmartPointer anatRegSQ; + const Tag anatRegSQTag(0x0008, 0x2218); + if( !segmentDS.FindDataElement( anatRegSQTag ) ) + { + anatRegSQ = new SequenceOfItems; + DataElement detmp( anatRegSQTag ); + detmp.SetVR( VR::SQ ); + detmp.SetValue( *anatRegSQ ); + detmp.SetVLToUndefined(); + segmentDS.Insert( detmp ); + } + anatRegSQ = segmentDS.GetDataElement( anatRegSQTag ).GetValueAsSQ(); + anatRegSQ->SetLengthToUndefined(); + + // Fill the Anatomic Region Sequence + const size_t nbItems = anatRegSQ->GetNumberOfItems(); + if (nbItems < 1) // Only one item is a type 1 + { + Item item; + item.SetVLToUndefined(); + anatRegSQ->AddItem(item); + } + + Item & anatRegItem = anatRegSQ->GetItem(1); + DataSet & anatRegDS = anatRegItem.GetNestedDataSet(); + + //***** CODE SEQUENCE MACRO ATTRIBUTES *****// + { + // Code Value (Type 1) + Attribute<0x0008, 0x0100> codeValueAt; + codeValueAt.SetValue( anatReg.CV ); + anatRegDS.Replace( codeValueAt.GetAsDataElement() ); + + // Coding Scheme (Type 1) + Attribute<0x0008, 0x0102> codingSchemeAt; + codingSchemeAt.SetValue( anatReg.CSD ); + anatRegDS.Replace( codingSchemeAt.GetAsDataElement() ); + + // Code Meaning (Type 1) + Attribute<0x0008, 0x0104> codeMeaningAt; + codeMeaningAt.SetValue( anatReg.CM ); + anatRegDS.Replace( codeMeaningAt.GetAsDataElement() ); + } + } + + //***** Segmented Property Category Code Sequence *****// + { + const SegmentHelper::BasicCodedEntry & propCat = segment->GetPropertyCategory(); + if (propCat.IsEmpty()) + { + gdcmWarningMacro("Segmented property category not specified or incomplete"); + } + + // Segmented Property Category Code Sequence (0062,0003) Type 1 + SmartPointer propCatSQ; + const Tag propCatSQTag(0x0062, 0x0003); + if( !segmentDS.FindDataElement( propCatSQTag ) ) + { + propCatSQ = new SequenceOfItems; + DataElement detmp( propCatSQTag ); + detmp.SetVR( VR::SQ ); + detmp.SetValue( *propCatSQ ); + detmp.SetVLToUndefined(); + segmentDS.Insert( detmp ); + } + propCatSQ = segmentDS.GetDataElement( propCatSQTag ).GetValueAsSQ(); + propCatSQ->SetLengthToUndefined(); + + // Fill the Segmented Property Category Code Sequence + const size_t nbItems = propCatSQ->GetNumberOfItems(); + if (nbItems < 1) // Only one item is a type 1 + { + Item item; + item.SetVLToUndefined(); + propCatSQ->AddItem(item); + } + + Item & propCatItem = propCatSQ->GetItem(1); + DataSet & propCatDS = propCatItem.GetNestedDataSet(); + + //***** CODE SEQUENCE MACRO ATTRIBUTES *****// + { + // Code Value (Type 1) + Attribute<0x0008, 0x0100> codeValueAt; + codeValueAt.SetValue( propCat.CV ); + propCatDS.Replace( codeValueAt.GetAsDataElement() ); + + // Coding Scheme (Type 1) + Attribute<0x0008, 0x0102> codingSchemeAt; + codingSchemeAt.SetValue( propCat.CSD ); + propCatDS.Replace( codingSchemeAt.GetAsDataElement() ); + + // Code Meaning (Type 1) + Attribute<0x0008, 0x0104> codeMeaningAt; + codeMeaningAt.SetValue( propCat.CM ); + propCatDS.Replace( codeMeaningAt.GetAsDataElement() ); + } + } + + //***** Segmented Property Type Code Sequence *****// + { + const SegmentHelper::BasicCodedEntry & propType = segment->GetPropertyType(); + if (propType.IsEmpty()) + { + gdcmWarningMacro("Segmented property type not specified or incomplete"); + } + + // Segmented Property Type Code Sequence (0062,000F) Type 1 + SmartPointer propTypeSQ; + const Tag propTypeSQTag(0x0062, 0x000F); + if( !segmentDS.FindDataElement( propTypeSQTag ) ) + { + propTypeSQ = new SequenceOfItems; + DataElement detmp( propTypeSQTag ); + detmp.SetVR( VR::SQ ); + detmp.SetValue( *propTypeSQ ); + detmp.SetVLToUndefined(); + segmentDS.Insert( detmp ); + } + propTypeSQ = segmentDS.GetDataElement( propTypeSQTag ).GetValueAsSQ(); + propTypeSQ->SetLengthToUndefined(); + + // Fill the Segmented Property Type Code Sequence + const size_t nbItems = propTypeSQ->GetNumberOfItems(); + if (nbItems < 1) // Only one item is a type 1 + { + Item item; + item.SetVLToUndefined(); + propTypeSQ->AddItem(item); + } + + Item & propTypeItem = propTypeSQ->GetItem(1); + DataSet & propTypeDS = propTypeItem.GetNestedDataSet(); + + //***** CODE SEQUENCE MACRO ATTRIBUTES *****// + { + // Code Value (Type 1) + Attribute<0x0008, 0x0100> codeValueAt; + codeValueAt.SetValue( propType.CV ); + propTypeDS.Replace( codeValueAt.GetAsDataElement() ); + + // Coding Scheme (Type 1) + Attribute<0x0008, 0x0102> codingSchemeAt; + codingSchemeAt.SetValue( propType.CSD ); + propTypeDS.Replace( codingSchemeAt.GetAsDataElement() ); + + // Code Meaning (Type 1) + Attribute<0x0008, 0x0104> codeMeaningAt; + codeMeaningAt.SetValue( propType.CM ); + propTypeDS.Replace( codeMeaningAt.GetAsDataElement() ); + } + } + + //***** Surface segmentation *****// + const unsigned long surfaceCount = segment->GetSurfaceCount(); + if (surfaceCount > 0) + { + // Surface Count + Attribute<0x0066, 0x002A> surfaceCountAt; + surfaceCountAt.SetValue( (unsigned int)surfaceCount ); + segmentDS.Replace( surfaceCountAt.GetAsDataElement() ); + + //***** Referenced Surface Sequence *****// + SmartPointer segmentsRefSQ; + if( !segmentDS.FindDataElement( Tag(0x0066, 0x002B) ) ) + { + segmentsRefSQ = new SequenceOfItems; + DataElement detmp( Tag(0x0066, 0x002B) ); + detmp.SetVR( VR::SQ ); + detmp.SetValue( *segmentsRefSQ ); + detmp.SetVLToUndefined(); + segmentDS.Insert( detmp ); + } + segmentsRefSQ = segmentDS.GetDataElement( Tag(0x0066, 0x002B) ).GetValueAsSQ(); + segmentsRefSQ->SetLengthToUndefined(); + + // Fill the Segment Surface Generation Algorithm Identification Sequence + const size_t nbItems = segmentsRefSQ->GetNumberOfItems(); + if (nbItems < surfaceCount) + { + const size_t diff = surfaceCount - nbItems; + const size_t nbOfItemToMake = (diff > 0?diff:0); + for(unsigned int i = 1; i <= nbOfItemToMake; ++i) + { + Item item; + item.SetVLToUndefined(); + segmentsRefSQ->AddItem(item); + } + } + // else Should I remove items? + + std::vector< SmartPointer< Surface > > surfaces = segment->GetSurfaces(); + std::vector< SmartPointer< Surface > >::const_iterator it = surfaces.begin(); + std::vector< SmartPointer< Surface > >::const_iterator itEnd = surfaces.end(); + unsigned int itemSurfaceNumber = 1; + for (; it != itEnd; it++) + { + SmartPointer< Surface > surface = *it; + + Item & segmentsRefItem = segmentsRefSQ->GetItem( itemSurfaceNumber++ ); + DataSet & segmentsRefDS = segmentsRefItem.GetNestedDataSet(); + + // Referenced Surface Number + Attribute<0x0066, 0x002C> refSurfaceNumberAt; + unsigned long refSurfaceNumber = surface->GetSurfaceNumber(); + if (refSurfaceNumber == 0) + { + refSurfaceNumber = surfaceNumber++; + surface->SetSurfaceNumber( refSurfaceNumber ); + } + refSurfaceNumberAt.SetValue( (unsigned int)refSurfaceNumber ); + segmentsRefDS.Replace( refSurfaceNumberAt.GetAsDataElement() ); + + //***** Segment Surface Source Instance Sequence *****// + { +// SmartPointer surfaceSourceSQ; +// if( !segmentsRefDS.FindDataElement( Tag(0x0066, 0x002E) ) ) +// { +// surfaceSourceSQ = new SequenceOfItems; +// DataElement detmp( Tag(0x0066, 0x002E) ); +// detmp.SetVR( VR::SQ ); +// detmp.SetValue( *surfaceSourceSQ ); +// detmp.SetVLToUndefined(); +// segmentsRefDS.Insert( detmp ); +// } +// surfaceSourceSQ = segmentsRefDS.GetDataElement( Tag(0x0066, 0x002E) ).GetValueAsSQ(); +// surfaceSourceSQ->SetLengthToUndefined(); + + //NOTE: If surfaces are derived from image, include ‘Image SOP Instance Reference Macro’ PS 3.3 Table C.10-3. + // How to know it? + } + } + } + else + { + // Segment Algorithm Name (Type 1) + const char * segmentAlgorithmName = segment->GetSegmentAlgorithmName(); + if ( strcmp(segmentAlgorithmName, "") != 0 ) + { + gdcmWarningMacro("No segment algorithm name specified"); + } + Attribute<0x0062, 0x0009> segmentAlgorithmNameAt; + segmentAlgorithmNameAt.SetValue( segmentAlgorithmName ); + segmentDS.Replace( segmentAlgorithmNameAt.GetAsDataElement() ); + } + + ++itemNumber; + } + + return true; +} + +bool SegmentWriter::Write() +{ + if( !PrepareWrite() ) + { + return false; + } + + assert( Stream ); + if( !Writer::Write() ) + { + return false; + } + + return true; +} + +} diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmSegmentWriter.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmSegmentWriter.h new file mode 100644 index 0000000..bab1d5c --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmSegmentWriter.h @@ -0,0 +1,63 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMSEGMENTWRITER_H +#define GDCMSEGMENTWRITER_H + +#include +#include + +namespace gdcm +{ + +/** + * \brief This class defines a segment writer. + * It writes attributes of group 0x0062. + * + * \see PS 3.3 C.8.20.2 and C.8.23 + */ +class GDCM_EXPORT SegmentWriter : public Writer +{ +public: + typedef std::vector< SmartPointer< Segment > > SegmentVector; + + SegmentWriter(); + + virtual ~SegmentWriter(); + + /// Write + bool Write(); // Set to protected ? + + //** Segment getters/setters **// + unsigned int GetNumberOfSegments() const; + void SetNumberOfSegments(const unsigned int size); + + const SegmentVector & GetSegments() const; + SegmentVector & GetSegments(); + SmartPointer< Segment > GetSegment(const unsigned int idx = 0) const; + + void AddSegment(SmartPointer< Segment > segment); + + void SetSegments(SegmentVector & segments); + +protected: + + bool PrepareWrite(); + + + SegmentVector Segments; +}; + +} + +#endif // GDCMSEGMENTWRITER_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmSegmentedPaletteColorLookupTable.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmSegmentedPaletteColorLookupTable.cxx new file mode 100644 index 0000000..c1440b2 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmSegmentedPaletteColorLookupTable.cxx @@ -0,0 +1,202 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmSegmentedPaletteColorLookupTable.h" +#include "gdcmDataSet.h" + +// http://blog.goo.ne.jp/satomi_takeo/e/3643e5249b2a9650f9e10ef1c830e8b8 +// +#include +#include +#include +#include +#include + +namespace gdcm +{ + // abstract class for segment. + template + class Segment { + public: + virtual ~Segment() {} + typedef std::map SegmentMap; + virtual bool Expand(const SegmentMap& instances, + std::vector& expanded) const = 0; + const EntryType* First() const { return _first; } + const EntryType* Last() const { return _last; } + struct ToMap { + std::pair< + typename SegmentMap::key_type, + typename SegmentMap::mapped_type + > + operator()(const Segment* segment) const + { return std::make_pair(segment->First(), segment); } + }; + protected: + Segment(const EntryType* first, const EntryType* last) { + _first = first; _last = last; + } + const EntryType* _first; + const EntryType* _last; + }; + + // discrete segment (opcode = 0) + template + class DiscreteSegment : public Segment { + public: + typedef typename Segment::SegmentMap SegmentMap; + DiscreteSegment(const EntryType* first) + : Segment(first, first+2+*(first+1)) {} + virtual bool Expand(const SegmentMap&, + std::vector& expanded) const + { + std::copy(this->_first + 2, this->_last, std::back_inserter(expanded)); + return true; + } + }; + + // linear segment (opcode = 1) + template + class LinearSegment : public Segment { + public: + typedef typename Segment::SegmentMap SegmentMap; + LinearSegment(const EntryType* first) + : Segment(first, first+3) {} + virtual bool Expand(const SegmentMap&, + std::vector& expanded) const + { + if ( expanded.empty() ) { + // linear segment can't be the first segment. + return false; + } + EntryType length = *(this->_first + 1); + EntryType y0 = expanded.back(); + EntryType y1 = *(this->_first + 2); + double y01 = y1 - y0; + for ( EntryType i = 0; i (y0) + + (static_cast(i)/static_cast(length)) * y01; + EntryType value_int = static_cast(value_float + 0.5); + expanded.push_back(value_int); + } + return true; + } + }; + + // indirect segment (opcode = 2) + template + class IndirectSegment : public Segment { + public: + typedef typename Segment::SegmentMap SegmentMap; + IndirectSegment(const EntryType* first) + : Segment(first, first+2+4/sizeof(EntryType)) {} + virtual bool Expand(const SegmentMap& instances, + std::vector& expanded) const + { + if ( instances.empty() ) { + // some other segments are required as references. + return false; + } + const EntryType* first_segment = instances.begin()->first; + const unsigned short* pOffset + = reinterpret_cast(this->_first + 2); + unsigned long offsetBytes + = (*pOffset) | (static_cast(*(pOffset + 1)) << 16); + const EntryType* copied_part_head + = first_segment + offsetBytes / sizeof(EntryType); + typename SegmentMap::const_iterator ppHeadSeg = instances.find(copied_part_head); + if ( ppHeadSeg == instances.end() ) { + // referred segment not found + return false; + } + EntryType nNumCopies = *(this->_first + 1); + typename SegmentMap::const_iterator ppSeg = ppHeadSeg; + while ( std::distance(ppHeadSeg, ppSeg) second->Expand(instances, expanded); + ++ppSeg; + } + return true; + } + }; + + template + void ExpandPalette(const EntryType* raw_values, uint32_t length, + std::vector& palette) + { + typedef std::deque*> SegmentList; + SegmentList segments; + const EntryType* raw_seg = raw_values; + while ( (std::distance(raw_values, raw_seg) * sizeof(EntryType)) * segment = NULL; + if ( *raw_seg == 0 ) { + segment = new DiscreteSegment(raw_seg); + } else if ( *raw_seg == 1 ) { + segment = new LinearSegment(raw_seg); + } else if ( *raw_seg == 2 ) { + segment = new IndirectSegment(raw_seg); + } + if ( segment ) { + segments.push_back(segment); + raw_seg = segment->Last(); + } else { + // invalid opcode + break; + } + } + typename Segment::SegmentMap instances; + std::transform(segments.begin(), segments.end(), + std::inserter(instances, instances.end()), typename Segment::ToMap()); + typename SegmentList::iterator ppSeg = segments.begin(); + typename SegmentList::iterator endOfSegments = segments.end(); + for ( ; ppSeg != endOfSegments; ++ppSeg ) { + (*ppSeg)->Expand(instances, palette); + } + ppSeg = segments.begin(); + for ( ; ppSeg != endOfSegments; ++ppSeg ) { + delete *ppSeg; + } + } + +SegmentedPaletteColorLookupTable::SegmentedPaletteColorLookupTable() +{ +} + +SegmentedPaletteColorLookupTable::~SegmentedPaletteColorLookupTable() +{ +} + +void SegmentedPaletteColorLookupTable::SetLUT(LookupTableType type, const unsigned char *array, + unsigned int length) +{ + if( BitSample == 8 ) + { + assert(0); // TODO + } + else if( BitSample == 16 ) + { + const uint16_t *array16 = (uint16_t*)array; + const uint16_t *segment_values = array16; + std::vector palette; + unsigned int num_entries = GetLUTLength(type); + palette.reserve(num_entries); + assert( length % 2 == 0 ); + // FIXME: inplace byteswapping (BAD!) + SwapperNoOp::SwapArray((uint16_t*)segment_values,length/2); + ExpandPalette(segment_values, length, palette); + LookupTable::SetLUT(type, (unsigned char*)&palette[0], (unsigned int)(palette.size() * 2)); + } +} + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmSegmentedPaletteColorLookupTable.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmSegmentedPaletteColorLookupTable.h new file mode 100644 index 0000000..b950494 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmSegmentedPaletteColorLookupTable.h @@ -0,0 +1,41 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#ifndef GDCMSEGMENTEDPALETTECOLORLOOKUPTABLE_H +#define GDCMSEGMENTEDPALETTECOLORLOOKUPTABLE_H + +#include "gdcmLookupTable.h" + +namespace gdcm +{ + +/** + * \brief SegmentedPaletteColorLookupTable class + */ +class GDCM_EXPORT SegmentedPaletteColorLookupTable : public LookupTable +{ +public: + SegmentedPaletteColorLookupTable(); + ~SegmentedPaletteColorLookupTable(); + void Print(std::ostream &) const {} + + /// Initialize a SegmentedPaletteColorLookupTable + void SetLUT(LookupTableType type, const unsigned char *array, + unsigned int length); + +}; + +} // end namespace gdcm + +#endif //GDCMSEGMENTEDPALETTECOLORLOOKUPTABLE_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmSerieHelper.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmSerieHelper.cxx new file mode 100644 index 0000000..eec3620 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmSerieHelper.cxx @@ -0,0 +1,473 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmSerieHelper.h" + +#include "gdcmStringFilter.h" +#include "gdcmDirectory.h" +#include "gdcmIPPSorter.h" +#include "gdcmImageReader.h" +#include "gdcmImageHelper.h" +#include "gdcmTrace.h" + +namespace gdcm +{ + +SerieHelper::SerieHelper() +{ + gdcm::Trace::WarningOff(); + UseSeriesDetails = false; + Clear(); + UserLessThanFunction = 0; + DirectOrder = true; + //LoadMode = 0; +} + +SerieHelper::~SerieHelper() +{ + Clear(); +} + +void SerieHelper::AddRestriction(uint16_t group, uint16_t elem, std::string const &value, int op) +{ + Rule r; + r.group = group; + r.elem = elem; + r.value = value; + r.op = op; + Restrictions.push_back( r ); +} + +void SerieHelper::AddRestriction(const std::string & tag) +{ + Tag t; + t.ReadFromPipeSeparatedString(tag.c_str()); + AddRestriction( Tag(t.GetGroup(), t.GetElement()) ); +} + +void SerieHelper::AddRestriction(const Tag& tag) +{ + Rule r; + r.group = tag.GetGroup(); + r.elem = tag.GetElement(); + Refine.push_back( r ); +} + +void SerieHelper::SetUseSeriesDetails( bool useSeriesDetails ) +{ + UseSeriesDetails = useSeriesDetails; +} + +void SerieHelper::CreateDefaultUniqueSeriesIdentifier() +{ + // If the user requests, additional information can be appended + // to the SeriesUID to further differentiate volumes in the DICOM + // objects being processed. + + // 0020 0011 Series Number + // A scout scan prior to a CT volume scan can share the same + // SeriesUID, but they will sometimes have a different Series Number + AddRestriction( Tag(0x0020, 0x0011) ); + // 0018 0024 Sequence Name + // For T1-map and phase-contrast MRA, the different flip angles and + // directions are only distinguished by the Sequence Name + AddRestriction( Tag(0x0018, 0x0024) ); + // 0018 0050 Slice Thickness + // On some CT systems, scout scans and subsequence volume scans will + // have the same SeriesUID and Series Number - YET the slice + // thickness will differ from the scout slice and the volume slices. + AddRestriction( Tag(0x0018, 0x0050) ); + // 0028 0010 Rows + // If the 2D images in a sequence don't have the same number of rows, + // then it is difficult to reconstruct them into a 3D volume. + AddRestriction( Tag(0x0028, 0x0010)); + // 0028 0011 Columns + // If the 2D images in a sequence don't have the same number of columns, + // then it is difficult to reconstruct them into a 3D volume. + AddRestriction( Tag(0x0028, 0x0011)); +} + +void SerieHelper::Clear() +{ + // For all the 'Single SerieUID' Filesets that may already exist + FileList *l = GetFirstSingleSerieUIDFileSet(); + while (l) + { + // For all the gdcm::File of a File set + for (gdcm::FileList::iterator it = l->begin(); + it != l->end(); + ++it) + { + //delete *it; // remove each entry + } + l->clear(); + delete l; // remove the container + l = GetNextSingleSerieUIDFileSet(); + } + // Need to clear that too: + SingleSerieUIDFileSetHT.clear(); +} + +void SerieHelper::SetDirectory(std::string const &dir, bool recursive) +{ + Directory dirList; + unsigned int nfiles = dirList.Load(dir, recursive); (void)nfiles; + + Directory::FilenamesType const &filenames = dirList.GetFilenames(); + for( Directory::FilenamesType::const_iterator it = filenames.begin(); + it != filenames.end(); ++it) + { + AddFileName( *it ); + } +} + +void SerieHelper::AddFileName(std::string const &filename) +{ + // Only accept DICOM file containing Image (Pixel Data element): + gdcm::ImageReader reader; + reader.SetFileName( filename.c_str() ); + if( !reader.Read() ) + { + gdcmWarningMacro("Could not read file: " << filename ); + } + else + { + SmartPointer f = new FileWithName( reader.GetFile() ); + f->filename = filename; + (void)AddFile( *f /*reader.GetFile()*/ ); // discard return value + } +} + +bool CompareDicomString(const std::string &s1, const char *s2, int op) +{ + // s2 is the string from the DICOM reference e.g. : 'MONOCHROME1' + std::string s1_even = s1; //Never change input parameter + std::string s2_even = /*DicomString(*/ s2 ; + assert( s2_even.size() % 2 == 0 ); + if ( s1_even[s1_even.size()-1] == ' ' ) + { + s1_even[s1_even.size()-1] = '\0'; //replace space character by null + } + switch (op) + { + case GDCM_EQUAL : + return s1_even == s2_even; + case GDCM_DIFFERENT : + return s1_even != s2_even; + case GDCM_GREATER : + return s1_even > s2_even; + case GDCM_GREATEROREQUAL : + return s1_even >= s2_even; + case GDCM_LESS : + return s1_even < s2_even; + case GDCM_LESSOREQUAL : + return s1_even <= s2_even; + default : + gdcmDebugMacro(" Wrong operator : " << op); + return false; + } +} +bool SerieHelper::AddFile(FileWithName &header) +{ + StringFilter sf; + sf.SetFile( header ); + int allrules = 1; + // First step the user has defined a set of rules for the DICOM + // he is looking for. + // make sure the file correspond to his set of rules: + + std::string s; + for(SerieRestrictions::iterator it2 = Restrictions.begin(); + it2 != Restrictions.end(); + ++it2) + { + const Rule &r = *it2; + //s = header->GetEntryValue( r.group, r.elem ); + s = sf.ToString( Tag(r.group,r.elem) ); + if ( !CompareDicomString(s, r.value.c_str(), r.op) ) + { + // Argh ! This rule is unmatched; let's just quit + allrules = 0; + break; + } + } + + if ( allrules ) // all rules are respected: + { + // Allright! we have a found a DICOM that matches the user expectation. + // Let's add it to the specific 'id' which by default is uid (Serie UID) + // but can be `refined` by user with more paramater (see AddRestriction(g,e)) + + std::string id = CreateUniqueSeriesIdentifier( &header ); + // if id == GDCM_UNFOUND then consistently we should find GDCM_UNFOUND + // no need here to do anything special + + if ( SingleSerieUIDFileSetHT.count(id) == 0 ) + { + gdcmDebugMacro(" New Serie UID :[" << id << "]"); + // create a std::list in 'id' position + SingleSerieUIDFileSetHT[id] = new FileList; + } + // Current Serie UID and DICOM header seems to match add the file: + SingleSerieUIDFileSetHT[id]->push_back( header ); + } + else + { + // one rule not matched, tell user: + return false; + } + return true; +} + +FileList *SerieHelper::GetFirstSingleSerieUIDFileSet() +{ + ItFileSetHt = SingleSerieUIDFileSetHT.begin(); + if ( ItFileSetHt != SingleSerieUIDFileSetHT.end() ) + return ItFileSetHt->second; + return NULL; +} + +FileList *SerieHelper::GetNextSingleSerieUIDFileSet() +{ + //gdcmAssertMacro (ItFileSetHt != SingleSerieUIDFileSetHT.end()); + + ++ItFileSetHt; + if ( ItFileSetHt != SingleSerieUIDFileSetHT.end() ) + return ItFileSetHt->second; + return NULL; +} + +bool SerieHelper::UserOrdering(FileList *fileList) +{ + std::sort(fileList->begin(), fileList->end(), SerieHelper::UserLessThanFunction); + if (!DirectOrder) + { + std::reverse(fileList->begin(), fileList->end()); + } + return true; +} + +namespace details { +bool MyFileNameSortPredicate(const SmartPointer& d1, const SmartPointer& d2) +{ + return d1->filename < d2->filename; +} +} + +bool SerieHelper::FileNameOrdering( FileList *fileList ) +{ + std::sort(fileList->begin(), fileList->end(), details::MyFileNameSortPredicate); + + return true; +} + +bool SerieHelper::ImagePositionPatientOrdering( FileList *fileList ) +{ + //iop is calculated based on the file file + std::vector cosines; + double normal[3] = {}; + std::vector ipp; + double dist; + double min = 0, max = 0; + bool first = true; + + std::multimap > distmultimap; + // Use a multimap to sort the distances from 0,0,0 + for ( FileList::const_iterator + it = fileList->begin(); + it != fileList->end(); ++it ) + { + if ( first ) + { + //(*it)->GetImageOrientationPatient( cosines ); + cosines = ImageHelper::GetDirectionCosinesValue( **it ); + + // You only have to do this once for all slices in the volume. Next, + // for each slice, calculate the distance along the slice normal + // using the IPP ("Image Position Patient") tag. + // ("dist" is initialized to zero before reading the first slice) : + normal[0] = cosines[1]*cosines[5] - cosines[2]*cosines[4]; + normal[1] = cosines[2]*cosines[3] - cosines[0]*cosines[5]; + normal[2] = cosines[0]*cosines[4] - cosines[1]*cosines[3]; + + ipp = ImageHelper::GetOriginValue( **it ); + //ipp[0] = (*it)->GetXOrigin(); + //ipp[1] = (*it)->GetYOrigin(); + //ipp[2] = (*it)->GetZOrigin(); + + dist = 0; + for ( int i = 0; i < 3; ++i ) + { + dist += normal[i]*ipp[i]; + } + + distmultimap.insert(std::pair >(dist, *it)); + + max = min = dist; + first = false; + } + else + { + ipp = ImageHelper::GetOriginValue( **it ); + //ipp[0] = (*it)->GetXOrigin(); + //ipp[1] = (*it)->GetYOrigin(); + //ipp[2] = (*it)->GetZOrigin(); + + dist = 0; + for ( int i = 0; i < 3; ++i ) + { + dist += normal[i]*ipp[i]; + } + + distmultimap.insert(std::pair >(dist, *it)); + + min = (min < dist) ? min : dist; + max = (max > dist) ? max : dist; + } + } + + // Find out if min/max are coherent + if ( min == max ) + { + gdcmWarningMacro("Looks like all images have the exact same image position" + << ". No PositionPatientOrdering sort performed" ); + return false; + } + + // Check to see if image shares a common position + bool ok = true; + for (std::multimap >::iterator it2 = distmultimap.begin(); + it2 != distmultimap.end(); + ++it2) + { + if (distmultimap.count((*it2).first) != 1) + { + gdcmErrorMacro("File: " + //<< ((*it2).second->GetFileName()) + << " Distance: " + << (*it2).first + << " position is not unique"); + + ok = false; + } + } + if (!ok) + { + return false; + } + + fileList->clear(); // doesn't delete list elements, only nodes + + if (DirectOrder) + { + for (std::multimap >::iterator it3 = distmultimap.begin(); + it3 != distmultimap.end(); + ++it3) + { + fileList->push_back( (*it3).second ); + } + } + else // user asked for reverse order + { + std::multimap >::const_iterator it4; + it4 = distmultimap.end(); + do + { + it4--; + fileList->push_back( (*it4).second ); + } while (it4 != distmultimap.begin() ); + } + + distmultimap.clear(); + + return true; +} + +void SerieHelper::OrderFileList(FileList *fileSet) +{ + IPPSorter ipps; + if ( SerieHelper::UserLessThanFunction ) + { + UserOrdering( fileSet ); + return; + } + else if ( ImagePositionPatientOrdering( fileSet ) ) + { + return ; + } + /* + else if ( ImageNumberOrdering(fileSet ) ) + { + return ; + }*/ + else + { + FileNameOrdering(fileSet ); + } +} + + +std::string SerieHelper::CreateUniqueSeriesIdentifier( File * inFile ) +{ + StringFilter sf; + sf.SetFile( *inFile ); + if( true /*inFile->IsReadable()*/ ) + { + // 0020 000e UI REL Series Instance UID + //std::string uid = inFile->GetEntryValue (0x0020, 0x000e); + std::string uid = sf.ToString( Tag(0x0020, 0x000e) ); + std::string id = uid.c_str(); + if(UseSeriesDetails) + { + for(SerieRestrictions::iterator it2 = Refine.begin(); + it2 != Refine.end(); + ++it2) + { + const Rule &r = *it2; + //std::string s = inFile->GetEntryValue( r.group, r.elem ); + std::string s = sf.ToString( Tag(r.group, r.elem) ); + //if( s == gdcm::GDCM_UNFOUND ) + // { + // s = ""; + // } + if( id == uid && !s.empty() ) + { + id += "."; // add separator + } + id += s; + } + } + // Eliminate non-alnum characters, including whitespace... + // that may have been introduced by concats. + for(size_t i=0; i= 'a' && id[i] <= 'z') + || (id[i] >= '0' && id[i] <= '9') + || (id[i] >= 'A' && id[i] <= 'Z'))) + { + id.erase(i, 1); + } + } + return id; + } + else // Could not open inFile + { + gdcmWarningMacro("Could not parse series info."); + std::string id = "GDCM_UNFOUND"; //gdcm::GDCM_UNFOUND; + return id; + } +} + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmSerieHelper.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmSerieHelper.h new file mode 100644 index 0000000..a75fc45 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmSerieHelper.h @@ -0,0 +1,121 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMSERIEHELPER_H +#define GDCMSERIEHELPER_H + +#include "gdcmTag.h" +#include "gdcmSmartPointer.h" +#include "gdcmFile.h" +#include +#include +#include + +namespace gdcm +{ + +enum CompOperators { + GDCM_EQUAL = 0, + GDCM_DIFFERENT, + GDCM_GREATER, + GDCM_GREATEROREQUAL, + GDCM_LESS, + GDCM_LESSOREQUAL +}; +enum LodModeType +{ + LD_ALL = 0x00000000, + LD_NOSEQ = 0x00000001, + LD_NOSHADOW = 0x00000002, + LD_NOSHADOWSEQ = 0x00000004 +}; + + +/** + * \brief FileWithName + * + * \details + * Backward only class do not use in newer code + */ +class GDCM_EXPORT FileWithName : public File +{ +public: + FileWithName(File &f):File(f),filename(){} + std::string filename; +}; + +typedef std::vector< SmartPointer > FileList; +typedef bool (*BOOL_FUNCTION_PFILE_PFILE_POINTER)(File *, File *); +class Scanner; + +/** + * \brief SerieHelper + * DO NOT USE this class, it is only a temporary solution for ITK migration from GDCM 1.x to GDCM 2.x + * It will disapear soon, you've been warned. + * + * Instead see gdcm::ImageHelper or gdcm::IPPSorter + */ +class GDCM_EXPORT SerieHelper +{ +public: + SerieHelper(); + ~SerieHelper(); + + void Clear(); + void SetLoadMode (int ) {} + void SetDirectory(std::string const &dir, bool recursive=false); + + void AddRestriction(const std::string & tag); + void SetUseSeriesDetails( bool useSeriesDetails ); + void CreateDefaultUniqueSeriesIdentifier(); + FileList *GetFirstSingleSerieUIDFileSet(); + FileList *GetNextSingleSerieUIDFileSet(); + std::string CreateUniqueSeriesIdentifier( File * inFile ); + void OrderFileList(FileList *fileSet); + void AddRestriction(uint16_t group, uint16_t elem, std::string const &value, int op); + +protected: + bool UserOrdering(FileList *fileSet); + void AddFileName(std::string const &filename); + bool AddFile(FileWithName &header); + void AddRestriction(const Tag& tag); + bool ImagePositionPatientOrdering(FileList *fileSet); + bool FileNameOrdering( FileList *fileList ); + + typedef struct { + uint16_t group; + uint16_t elem; + std::string value; + int op; + } Rule; + typedef std::vector SerieRestrictions; + + typedef std::map SingleSerieUIDFileSetmap; + SingleSerieUIDFileSetmap SingleSerieUIDFileSetHT; + SingleSerieUIDFileSetmap::iterator ItFileSetHt; + +private: + SerieRestrictions Restrictions; + SerieRestrictions Refine; + + bool UseSeriesDetails; + bool DirectOrder; + + BOOL_FUNCTION_PFILE_PFILE_POINTER UserLessThanFunction; +}; + +// backward compat +} // end namespace gdcm + + +#endif //GDCMSERIEHELPER_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmSimpleSubjectWatcher.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmSimpleSubjectWatcher.cxx new file mode 100644 index 0000000..5525e51 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmSimpleSubjectWatcher.cxx @@ -0,0 +1,185 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmSimpleSubjectWatcher.h" +#include "gdcmEvent.h" +#include "gdcmAnonymizeEvent.h" +#include "gdcmDataSetEvent.h" +#include "gdcmProgressEvent.h" +#include "gdcmFileNameEvent.h" + +namespace gdcm +{ + +SimpleSubjectWatcher::SimpleSubjectWatcher(Subject *s, const char *comment):m_Subject(s),m_Comment(comment) +{ + // Create a series of commands + m_StartFilterCommand = SimpleCommandType::New(); + m_EndFilterCommand = SimpleCommandType::New(); + m_ProgressFilterCommand = CommandType::New(); + m_FileNameFilterCommand = CommandType::New(); + m_IterationFilterCommand = SimpleCommandType::New(); + m_AbortFilterCommand = SimpleCommandType::New(); + + m_AnonymizeFilterCommand = CommandType::New(); + m_DataSetFilterCommand = CommandType::New(); + m_DataFilterCommand = CommandType::New(); + + // Assign the callbacks + m_StartFilterCommand->SetCallbackFunction(this, + &SimpleSubjectWatcher::StartFilter); + m_EndFilterCommand->SetCallbackFunction(this, + &SimpleSubjectWatcher::EndFilter); + m_ProgressFilterCommand->SetCallbackFunction(this, + &SimpleSubjectWatcher::ShowProgress); + m_FileNameFilterCommand->SetCallbackFunction(this, + &SimpleSubjectWatcher::ShowFileName); + m_IterationFilterCommand->SetCallbackFunction(this, + &SimpleSubjectWatcher::ShowIteration); + m_AbortFilterCommand->SetCallbackFunction(this, + &SimpleSubjectWatcher::ShowAbort); + m_AnonymizeFilterCommand->SetCallbackFunction(this, + &SimpleSubjectWatcher::ShowAnonymization); + m_DataSetFilterCommand->SetCallbackFunction(this, + &SimpleSubjectWatcher::ShowDataSet); + m_DataFilterCommand->SetCallbackFunction(this, + &SimpleSubjectWatcher::ShowData); + + // Add the commands as observers + m_StartTag = m_Subject->AddObserver(StartEvent(), m_StartFilterCommand); + m_EndTag = m_Subject->AddObserver(EndEvent(), m_EndFilterCommand); + m_ProgressTag + = m_Subject->AddObserver(ProgressEvent(), m_ProgressFilterCommand); + m_FileNameTag + = m_Subject->AddObserver(FileNameEvent(), m_FileNameFilterCommand); + m_IterationTag + = m_Subject->AddObserver(IterationEvent(), m_IterationFilterCommand); + m_AbortTag + = m_Subject->AddObserver(AbortEvent(), m_AbortFilterCommand); + m_AnonymizeTag + = m_Subject->AddObserver(AnonymizeEvent(), m_AnonymizeFilterCommand); + m_DataSetTag + = m_Subject->AddObserver(DataSetEvent(), m_DataSetFilterCommand); + m_DataTag + = m_Subject->AddObserver(DataEvent(), m_DataFilterCommand); + + m_TestAbort = false; +} + +SimpleSubjectWatcher::~SimpleSubjectWatcher() +{ + // Remove any observers we have on the old process object + if (m_Subject) + { + if (m_StartFilterCommand) + { + m_Subject->RemoveObserver(m_StartTag); + } + if (m_EndFilterCommand) + { + m_Subject->RemoveObserver(m_EndTag); + } + if (m_ProgressFilterCommand) + { + m_Subject->RemoveObserver(m_ProgressTag); + } + if (m_FileNameFilterCommand) + { + m_Subject->RemoveObserver(m_FileNameTag); + } + if (m_IterationFilterCommand) + { + m_Subject->RemoveObserver(m_IterationTag); + } + if (m_AbortFilterCommand) + { + m_Subject->RemoveObserver(m_AbortTag); + } + if (m_AnonymizeFilterCommand) + { + m_Subject->RemoveObserver(m_AnonymizeTag); + } + if (m_DataFilterCommand) + { + m_Subject->RemoveObserver(m_DataTag); + } + if (m_DataSetFilterCommand) + { + m_Subject->RemoveObserver(m_DataSetTag); + } + } +} + +void SimpleSubjectWatcher::StartFilter() +{ + std::cout << "Start" << std::endl; +} +void SimpleSubjectWatcher::EndFilter() +{ + std::cout << "End" << std::endl; +} +void SimpleSubjectWatcher::ShowProgress(Subject *caller, const Event &evt) +{ + const ProgressEvent &pe = dynamic_cast(evt); + (void)caller; + if( !m_Comment.empty() ) + std::cout << "(" << m_Comment << ") "; + std::cout << "Progress: " << pe.GetProgress() << std::endl; +} +void SimpleSubjectWatcher::ShowFileName(Subject *caller, const Event &evt) +{ + const FileNameEvent &pe = dynamic_cast(evt); + (void)caller; + if( !m_Comment.empty() ) + std::cout << "(" << m_Comment << ") "; + std::cout << "FileName: " << pe.GetFileName() << std::endl; +} +void SimpleSubjectWatcher::ShowIteration() +{ + std::cout << "Iteration" << std::endl; +} +void SimpleSubjectWatcher::ShowAbort() +{ + std::cout << "Abort" << std::endl; +} +void SimpleSubjectWatcher::ShowAnonymization(Subject *caller, const Event &evt) +{ + const AnonymizeEvent &ae = dynamic_cast(evt); + (void)caller; + std::cout << "AnonymizeEvent: " << ae.GetTag() << std::endl; +} +void SimpleSubjectWatcher::ShowData(Subject *caller, const Event &evt) +{ + const DataEvent &ae = dynamic_cast(evt); + (void)caller; + std::cout << "DataEvent: " << ae.GetDataLength() << std::endl; +} +void SimpleSubjectWatcher::ShowDataSet(Subject *caller, const Event &evt) +{ + const DataSetEvent &ae = dynamic_cast(evt); + (void)caller; + std::cout << "DataSetEvent: \n"; + std::cout << ae.GetDataSet() << std::endl; +} + +void SimpleSubjectWatcher::TestAbortOn() +{ + m_TestAbort = true; +} +void SimpleSubjectWatcher::TestAbortOff() +{ + m_TestAbort = false; +} + + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmSimpleSubjectWatcher.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmSimpleSubjectWatcher.h new file mode 100644 index 0000000..6a38cb7 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmSimpleSubjectWatcher.h @@ -0,0 +1,87 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMSIMPLESUBJECTWATCHER_H +#define GDCMSIMPLESUBJECTWATCHER_H + +#include "gdcmSubject.h" +#include "gdcmCommand.h" +#include "gdcmSmartPointer.h" +#include "gdcmAnonymizeEvent.h" +#include "gdcmDataEvent.h" + +namespace gdcm +{ +//----------------------------------------------------------------------------- +class Event; +/** + * \brief SimpleSubjectWatcher + * This is a typical Subject Watcher class. It will observe all events. + */ +class GDCM_EXPORT SimpleSubjectWatcher +{ +public: + SimpleSubjectWatcher(Subject * s, const char *comment = ""); + virtual ~SimpleSubjectWatcher(); + +protected: + virtual void StartFilter(); + virtual void EndFilter(); + virtual void ShowProgress(Subject *caller, const Event &evt); + virtual void ShowFileName(Subject *caller, const Event &evt); + virtual void ShowIteration(); + virtual void ShowAnonymization(Subject *caller, const Event &evt); + virtual void ShowDataSet(Subject *caller, const Event &evt); + virtual void ShowData(Subject *caller, const Event &evt); + virtual void ShowAbort(); + +protected: + // Custom API used for internal Testing do not use ! + void TestAbortOn(); + void TestAbortOff(); + +private: + SmartPointer m_Subject; + std::string m_Comment; + + typedef SimpleMemberCommand SimpleCommandType; + typedef MemberCommand CommandType; + + SmartPointer m_StartFilterCommand; + SmartPointer m_EndFilterCommand; + SmartPointer m_ProgressFilterCommand; + SmartPointer m_FileNameFilterCommand; + SmartPointer m_IterationFilterCommand; + SmartPointer m_AbortFilterCommand; + SmartPointer m_AnonymizeFilterCommand; + SmartPointer m_DataFilterCommand; + SmartPointer m_DataSetFilterCommand; + + unsigned long m_StartTag; + unsigned long m_EndTag; + unsigned long m_ProgressTag; + unsigned long m_FileNameTag; + unsigned long m_IterationTag; + unsigned long m_AbortTag; + unsigned long m_AnonymizeTag; + unsigned long m_DataTag; + unsigned long m_DataSetTag; + + bool m_TestAbort; + + SimpleSubjectWatcher(const SimpleSubjectWatcher&); // Not implemented. + void operator=(const SimpleSubjectWatcher&); // Not implemented. +}; +} // end namespace gdcm +//----------------------------------------------------------------------------- +#endif //GDCMSIMPLESUBJECTWATCHER_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmSorter.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmSorter.cxx new file mode 100644 index 0000000..0272ae3 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmSorter.cxx @@ -0,0 +1,169 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmSorter.h" +#include "gdcmElement.h" +#include "gdcmSerieHelper.h" +#include "gdcmFile.h" +#include "gdcmReader.h" + +#include +#include + +namespace gdcm +{ + +Sorter::Sorter() +{ + SortFunc = NULL; +} + + +Sorter::~Sorter() +{ +} + +void Sorter::SetSortFunction( SortFunction f ) +{ + SortFunc = f; +} + + +namespace { +class SortFunctor +{ +public: + bool operator() (File const *file1, File const *file2) + { + return (SortFunc)(file1->GetDataSet(), file2->GetDataSet()); + } + Sorter::SortFunction SortFunc; + SortFunctor() + { + SortFunc = 0; + } + SortFunctor(SortFunctor const &sf) + { + SortFunc = sf.SortFunc; + } + void operator=(Sorter::SortFunction sf) + { + SortFunc = sf; + } +}; +} + +bool Sorter::StableSort(std::vector const & filenames) +{ + // BUG: I cannot clear Filenames since input filenames could also be the output of ourself... + // Filenames.clear(); + if( filenames.empty() || !SortFunc ) + { + Filenames.clear(); + return true; + } + + std::vector< SmartPointer > filelist; + filelist.resize( filenames.size() ); + + std::vector< SmartPointer >::iterator it2 = filelist.begin(); + for( Directory::FilenamesType::const_iterator it = filenames.begin(); + it != filenames.end() && it2 != filelist.end(); ++it, ++it2) + { + gdcm::Reader reader; + reader.SetFileName( it->c_str() ); + SmartPointer &f = *it2; + if( reader.Read() ) + { + f = new FileWithName( reader.GetFile() ); + f->filename = *it; + } + else + { + gdcmErrorMacro( "File could not be read: " << it->c_str() ); + return false; + } + } + SortFunctor sf; + sf = Sorter::SortFunc; + std::stable_sort( filelist.begin(), filelist.end(), sf); + + Filenames.clear(); // cleanup any previous call + for(it2 = filelist.begin(); it2 != filelist.end(); ++it2 ) + { + SmartPointer const & f = *it2; + Filenames.push_back( f->filename ); + } + + return true; +} + +bool Sorter::Sort(std::vector const & filenames) +{ + (void)filenames; + Filenames.clear(); + + if( filenames.empty() || !SortFunc ) return true; + + std::vector< SmartPointer > filelist; + filelist.resize( filenames.size() ); + + std::vector< SmartPointer >::iterator it2 = filelist.begin(); + for( Directory::FilenamesType::const_iterator it = filenames.begin(); + it != filenames.end() && it2 != filelist.end(); ++it, ++it2) + { + gdcm::Reader reader; + reader.SetFileName( it->c_str() ); + SmartPointer &f = *it2; + if( reader.Read() ) + { + f = new FileWithName( reader.GetFile() ); + f->filename = *it; + } + else + { + gdcmErrorMacro( "File could not be read: " << it->c_str() ); + return false; + } + } + //std::sort( filelist.begin(), filelist.end(), Sorter::SortFunc); + SortFunctor sf; + sf = Sorter::SortFunc; + std::sort( filelist.begin(), filelist.end(), sf); + + for(it2 = filelist.begin(); it2 != filelist.end(); ++it2 ) + { + SmartPointer const & f = *it2; + Filenames.push_back( f->filename ); + } + + return true; +} + +bool Sorter::AddSelect( Tag const &tag, const char *value ) +{ + Selection.insert( SelectionMap::value_type(tag,value) ); + return true; +} + + +void Sorter::Print( std::ostream &os) const +{ + std::vector::const_iterator it = Filenames.begin(); + for( ; it != Filenames.end(); ++it) + { + os << *it < +#include +#include + +namespace gdcm +{ +class DataSet; + +/** + * \brief Sorter + * General class to do sorting using a custom function + * You simply need to provide a function of type: Sorter::SortFunction + * + * \warning implementation details. For now there is no cache mechanism. Which means + * that everytime you call Sort, all files specified as input paramater are *read* + * + * \see Scanner + */ +class GDCM_EXPORT Sorter +{ + friend std::ostream& operator<<(std::ostream &_os, const Sorter &s); +public: + Sorter(); + virtual ~Sorter(); + + /// Typically the output of gdcm::Directory::GetFilenames() + virtual bool Sort(std::vector const & filenames); + + /// Return the list of filenames as sorted by the specific algorithm used. + /// Empty by default (before Sort() is called) + const std::vector &GetFilenames() const { return Filenames; } + + /// Print + void Print(std::ostream &os) const; + + /// UNSUPPORTED FOR NOW + bool AddSelect( Tag const &tag, const char *value ); + + /// Set the sort function which compares one dataset to the other + typedef bool (*SortFunction)(DataSet const &, DataSet const &); + void SetSortFunction( SortFunction f ); + + virtual bool StableSort(std::vector const & filenames); + +protected: + std::vector Filenames; + typedef std::map SelectionMap; + std::map Selection; + SortFunction SortFunc; +}; +//----------------------------------------------------------------------------- +inline std::ostream& operator<<(std::ostream &os, const Sorter &s) +{ + s.Print( os ); + return os; +} + + +} // end namespace gdcm + +#endif //GDCMSORTER_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmSpacing.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmSpacing.cxx new file mode 100644 index 0000000..50f5241 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmSpacing.cxx @@ -0,0 +1,117 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmSpacing.h" + +namespace gdcm +{ + +Spacing::Spacing() {} + +Spacing::~Spacing() {} + +/* + * http://www.ics.uci.edu/~eppstein/numth/frap.c + * http://stackoverflow.com/questions/95727/how-to-convert-floats-to-human-readable-fractions + * http://www.cs.umd.edu/class/sum2003/cmsc311/Notes/Data/fracToBaseK.html + * http://docs.sun.com/source/806-3568/ncg_goldberg.html + */ +/* +** find rational approximation to given real number +** David Eppstein / UC Irvine / 8 Aug 1993 +** +** With corrections from Arno Formella, May 2008 +** +** usage: a.out r d +** r is real number to approx +** d is the maximum denominator allowed +** +** based on the theory of continued fractions +** if x = a1 + 1/(a2 + 1/(a3 + 1/(a4 + ...))) +** then best approximation is found by truncating this series +** (with some adjustments in the last term). +** +** Note the fraction can be recovered as the first column of the matrix +** ( a1 1 ) ( a2 1 ) ( a3 1 ) ... +** ( 1 0 ) ( 1 0 ) ( 1 0 ) +** Instead of keeping the sequence of continued fraction terms, +** we just keep the last partial product of these matrices. +*/ + +// return error +double frap(double frac[2], double startx, double maxden = 10 ) +{ + long m[2][2]; + double x; + long ai; + + x = startx; + + /* initialize matrix */ + m[0][0] = m[1][1] = 1; + m[0][1] = m[1][0] = 0; + + /* loop finding terms until denom gets too big */ + while (m[1][0] * ( ai = (long)x ) + m[1][1] <= maxden) + { + long t; + t = m[0][0] * ai + m[0][1]; + m[0][1] = m[0][0]; + m[0][0] = t; + t = m[1][0] * ai + m[1][1]; + m[1][1] = m[1][0]; + m[1][0] = t; + if(x==(double)ai) break; // AF: division by zero + x = 1/(x - (double) ai); + if(x>(double)0x7FFFFFFF) break; // AF: representation failure + } + + /* now remaining x is between 0 and 1/ai */ + /* approx as either 0 or 1/m where m is max that will fit in maxden */ + /* first try zero */ + //printf("%ld/%ld, error = %e\n", m[0][0], m[1][0], + // startx - ((double) m[0][0] / (double) m[1][0])); + frac[0] = (double)m[0][0]; + frac[1] = (double)m[1][0]; + const double error = startx - ((double) m[0][0] / (double) m[1][0]); + + /* now try other possibility */ + ai = ((long)maxden - m[1][1]) / m[1][0]; + m[0][0] = m[0][0] * ai + m[0][1]; + m[1][0] = m[1][0] * ai + m[1][1]; + //printf("%ld/%ld, error = %e\n", m[0][0], m[1][0], + // startx - ((double) m[0][0] / (double) m[1][0])); + const double error2 = startx - ((double) m[0][0] / (double) m[1][0]); + assert( fabs(error) < fabs(error2) ); (void)error2; + + return error; +} + +Attribute<0x28,0x34> Spacing::ComputePixelAspectRatioFromPixelSpacing(const Attribute<0x28,0x30>& pixelspacing) +{ + Attribute<0x28,0x34> pixelaspectratio; + const double ratio = pixelspacing[0] / pixelspacing[1]; +// double value = 2.5; +// double integral_part; +// double frac_part = modf(value, &integral_part); + double frac[2]; + double error = frap(frac, ratio); + (void)error; + pixelaspectratio[0] = static_cast(frac[0]); + pixelaspectratio[1] = static_cast(frac[1]); + + return pixelaspectratio; +} + + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmSpacing.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmSpacing.h new file mode 100644 index 0000000..2ce74d7 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmSpacing.h @@ -0,0 +1,124 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMSPACING_H +#define GDCMSPACING_H + +#include "gdcmTypes.h" +#include "gdcmAttribute.h" + +namespace gdcm +{ +/** + It all began with a mail to WG6: + +Subject: Imager Pixel Spacing vs Pixel Spacing +Body: [Apologies for the duplicate post, namely to David Clunie & OFFIS team] + +I have been trying to understand CP-586 in the following two cases: + +On the one hand: +- DISCIMG/IMAGES/CRIMAGE taken from +http://dclunie.com/images/pixelspacingtestimages.zip + +And on the other hand: +- http://gdcm.sourceforge.net/thingies/cr_pixelspacing.dcm + +If I understand correctly the CP, one is required to use Pixel Spacing +for measurement ('true size' print) instead of Imager Pixel Spacing, +since the two attributes are present and Pixel Spacing is different from +Imager Pixel Spacing. + +If this is correct, then the test data DISCIMG/IMAGES/CRIMAGE is +incorrect. If this is incorrect (ie. I need to use Imager Pixel +Spacing), then the display of cr_pixelspacing.dcm for measurement will +be incorrect. + +Could someone please let me know what am I missing here? I could not +find any information in any header that would allow me to differentiate +those. + +Thank you for your time, + +Ref: + http://lists.nema.org/scripts/lyris.pl?sub=488573&id=400720477 +*/ + +/** + * \brief Class for Spacing + * + * See PS 3.3-2008, Table C.7-11b IMAGE PIXEL MACRO ATTRIBUTES + +Ratio of the vertical size and horizontal size +of the pixels in the image specified by a +pair of integer values where the first value +is the vertical pixel size, and the second +value is the horizontal pixel size. Required +if the aspect ratio values do not have a +ratio of 1:1 and the physical pixel spacing is +not specified by Pixel Spacing (0028,0030), +or Imager Pixel Spacing (0018,1164) or +Nominal Scanned Pixel Spacing +(0018,2010), either for the entire Image or +per-frame in a Functional Group Macro. +See C.7.6.3.1.7. + + +PS 3.3-2008 +10.7.1.3 Pixel Spacing Value Order and Valid Values +All pixel spacing related attributes shall have non-zero values, except when there is only a single row or +column or pixel of data present, in which case the corresponding value may be zero. + +Ref: +http://gdcm.sourceforge.net/wiki/index.php/Imager_Pixel_Spacing + */ +class GDCM_EXPORT Spacing +{ +public : + Spacing(); + ~Spacing(); + + // Here are the list of spacing we support: + // (0018,0088) DS [1.500000] # 8,1 Spacing Between Slices + // (0018,1164) DS [0.5\0.5 ] # 8,2 Imager Pixel Spacing + // (0018,2010) DS [0.664062\0.664062 ] # 18,2 Nominal Scanned Pixel Spacing + // (0018,7022) DS [0.125\0.125 ] # 12,2 Detector Element Spacing + // (0028,0030) DS [0.25\0.25 ] # 10,2 Pixel Spacing + // > (0028,0a02) CS [FIDUCIAL] # 8,1 Pixel Spacing Calibration Type + // > (0028,0a04) LO [Used fiducial ] # 14,1 Pixel Spacing Calibration Description + // (0028,0034) IS [4\3 ] # 4,2 Pixel Aspect Ratio + // (3002,0011) DS [0.8\0.8 ] # 8,2 Image Plane Pixel Spacing + + // Here is the list of Spacing we do not support: + // + // + // + // + // + // + // + // + // + + typedef enum { + DETECTOR = 0, // (0018,1164) Imager Pixel Spacing + MAGNIFIED, // (0018,1114) (IHE Mammo) + CALIBRATED, // (0028,0030) Pixel Spacing -> (0028,0a04) Pixel Spacing Calibration Description + UNKNOWN + } SpacingType; + + static Attribute<0x28,0x34> ComputePixelAspectRatioFromPixelSpacing(const Attribute<0x28,0x30>& pixelspacing); +}; +} // end namespace gdcm +//----------------------------------------------------------------------------- +#endif //GDCMSPACING_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmSpectroscopy.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmSpectroscopy.cxx new file mode 100644 index 0000000..d13310c --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmSpectroscopy.cxx @@ -0,0 +1,17 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmSpectroscopy.h" + +namespace gdcm +{} diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmSpectroscopy.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmSpectroscopy.h new file mode 100644 index 0000000..f5a3ac1 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmSpectroscopy.h @@ -0,0 +1,34 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMSPECTROSCOPY_H +#define GDCMSPECTROSCOPY_H + +#include "gdcmFile.h" + +namespace gdcm +{ +/** + * \brief Spectroscopy class + */ +class GDCM_EXPORT Spectroscopy +{ +public: + Spectroscopy() {} + +private: +}; + +} // end namespace gdcm + +#endif //GDCMSPECTROSCOPY_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmSplitMosaicFilter.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmSplitMosaicFilter.cxx new file mode 100644 index 0000000..4c05457 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmSplitMosaicFilter.cxx @@ -0,0 +1,172 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmSplitMosaicFilter.h" +#include "gdcmCSAHeader.h" +#include "gdcmAttribute.h" +#include "gdcmImageHelper.h" + +#include + +namespace gdcm +{ +SplitMosaicFilter::SplitMosaicFilter():F(new File),I(new Image) {} +SplitMosaicFilter::~SplitMosaicFilter() {} + +namespace details { +/* + * gdcmDataExtra/gdcmSampleData/images_of_interest/MR-sonata-3D-as-Tile.dcm + */ +static bool reorganize_mosaic(const unsigned short *input, const unsigned int *inputdims, + unsigned int square, const unsigned int *outputdims, unsigned short *output ) +{ + for(unsigned int x = 0; x < outputdims[0]; ++x) + { + for(unsigned int y = 0; y < outputdims[1]; ++y) + { + for(unsigned int z = 0; z < outputdims[2]; ++z) + { + const size_t outputidx = x + y*outputdims[0] + z*outputdims[0]*outputdims[1]; + const size_t inputidx = (x + (z%square)*outputdims[0]) + + (y + (z/square)*outputdims[1])*inputdims[0]; + output[ outputidx ] = input[ inputidx ]; + } + } + } + return true; +} +} + +void SplitMosaicFilter::SetImage(const Image& image) +{ + I = image; +} + +bool SplitMosaicFilter::ComputeMOSAICDimensions( unsigned int dims[3] ) +{ + gdcm::CSAHeader csa; + gdcm::DataSet& ds = GetFile().GetDataSet(); + + const gdcm::PrivateTag &t1 = csa.GetCSAImageHeaderInfoTag(); + if( !csa.LoadFromDataElement( ds.GetDataElement( t1 ) ) ) + { + return false; + } + + std::vector colrow = + gdcm::ImageHelper::GetDimensionsValue( GetFile() ); + dims[0] = colrow[0]; + dims[1] = colrow[1]; + + // SliceThickness ?? + int numberOfImagesInMosaic = 0; + if( csa.FindCSAElementByName( "NumberOfImagesInMosaic" ) ) + { + const gdcm::CSAElement &csael4 = csa.GetCSAElementByName( "NumberOfImagesInMosaic" ); + if( !csael4.IsEmpty() ) + { + gdcm::Element el4 = {{ 0 }}; + el4.Set( csael4.GetValue() ); + numberOfImagesInMosaic = el4.GetValue(); + } + } + + if( !numberOfImagesInMosaic ) return false; + + unsigned int div = (unsigned int )ceil(sqrt( (double)numberOfImagesInMosaic ) ); + dims[0] /= div; + dims[1] /= div; + dims[2] = numberOfImagesInMosaic; + return true; +} + +bool SplitMosaicFilter::Split() +{ + bool success = true; + gdcm::DataSet& ds = GetFile().GetDataSet(); + + unsigned int dims[3] = {0,0,0}; + if( ! ComputeMOSAICDimensions( dims ) ) + { + return false; + } + unsigned int div = (unsigned int )ceil(sqrt( (double)dims[2]) ); + + const gdcm::Image &inputimage = GetImage(); + if( inputimage.GetPixelFormat() != PixelFormat::UINT16 ) + { + gdcmDebugMacro( "Expecting UINT16 PixelFormat" ); + return false; + } + unsigned long l = inputimage.GetBufferLength(); + std::vector buf; + buf.resize(l); + inputimage.GetBuffer( &buf[0] ); + gdcm::DataElement pixeldata( gdcm::Tag(0x7fe0,0x0010) ); + + std::vector outbuf; + outbuf.resize(l); + + bool b = details::reorganize_mosaic( + (unsigned short*)&buf[0], inputimage.GetDimensions(), div, dims, + (unsigned short*)&outbuf[0] ); + if( !b ) return false; + + VL::Type outbufSize = (VL::Type)outbuf.size(); + pixeldata.SetByteValue( &outbuf[0], outbufSize ); + + gdcm::Image &image = GetImage(); + + image.SetNumberOfDimensions( 3 ); + image.SetDimension(0, dims[0] ); + image.SetDimension(1, dims[1] ); + image.SetDimension(2, dims[2] ); + + gdcm::PhotometricInterpretation pi; + pi = gdcm::PhotometricInterpretation::MONOCHROME2; + + image.SetDataElement( pixeldata ); + + // Second part need to fix the Media Storage, now that this is not a single slice anymore + gdcm::MediaStorage ms = gdcm::MediaStorage::SecondaryCaptureImageStorage; + ms.SetFromFile( GetFile() ); + + if( ms == gdcm::MediaStorage::MRImageStorage ) + { + // Ok make it a MediaStorage::EnhancedMRImageStorage +// ms = gdcm::MediaStorage::EnhancedMRImageStorage; +// +// // Remove old MRImageStorage attribute then: +// ds.Remove( gdcm::Tag(0x0020,0x0032) ); // Image Position (Patient) +// ds.Remove( gdcm::Tag(0x0020,0x0037) ); // Image Orientation (Patient) +// ds.Remove( gdcm::Tag(0x0028,0x1052) ); // Rescale Intercept +// ds.Remove( gdcm::Tag(0x0028,0x1053) ); // Rescale Slope +// ds.Remove( gdcm::Tag(0x0028,0x1054) ); // Rescale Type + } + else + { + gdcmDebugMacro( "Expecting MRImageStorage" ); + return false; + } + gdcm::DataElement de( gdcm::Tag(0x0008, 0x0016) ); + const char* msstr = gdcm::MediaStorage::GetMSString(ms); + VL::Type strlenMsstr = (VL::Type)strlen(msstr); + de.SetByteValue( msstr, strlenMsstr ); + de.SetVR( gdcm::Attribute<0x0008, 0x0016>::GetVR() ); + ds.Replace( de ); + + return success; +} + + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmSplitMosaicFilter.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmSplitMosaicFilter.h new file mode 100644 index 0000000..029fce5 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmSplitMosaicFilter.h @@ -0,0 +1,67 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMSPLITMOSAICFILTER_H +#define GDCMSPLITMOSAICFILTER_H + +#include "gdcmFile.h" +#include "gdcmImage.h" + +namespace gdcm +{ + +/* + * Everything done in this code is for the sole purpose of writing interoperable + * software under Sect. 1201 (f) Reverse Engineering exception of the DMCA. + * If you believe anything in this code violates any law or any of your rights, + * please contact us (gdcm-developers@lists.sourceforge.net) so that we can + * find a solution. + */ +/** + * \brief SplitMosaicFilter class + * Class to reshuffle bytes for a SIEMENS Mosaic image + * Siemens CSA Image Header + * CSA:= Common Siemens Architecture, sometimes also known as Common syngo Architecture + * + */ +class GDCM_EXPORT SplitMosaicFilter +{ +public: + SplitMosaicFilter(); + ~SplitMosaicFilter(); + + /// Split the SIEMENS MOSAIC image + bool Split(); + + /// Compute the new dimensions according to private information + /// stored in the MOSAIC header. + bool ComputeMOSAICDimensions(unsigned int dims[3]); + + void SetImage(const Image& image); + const Image &GetImage() const { return *I; } + Image &GetImage() { return *I; } + + void SetFile(const File& f) { F = f; } + File &GetFile() { return *F; } + const File &GetFile() const { return *F; } + +protected: + +private: + SmartPointer F; + SmartPointer I; +}; + +} // end namespace gdcm + +#endif //GDCMSPLITMOSAICFILTER_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmStreamImageReader.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmStreamImageReader.cxx new file mode 100644 index 0000000..2c25412 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmStreamImageReader.cxx @@ -0,0 +1,494 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#include "gdcmStreamImageReader.h" + +#include "gdcmImage.h" +#include "gdcmMediaStorage.h" +#include "gdcmImageHelper.h" +#include "gdcmRAWCodec.h" +#include "gdcmJPEGLSCodec.h" + +#include + +namespace gdcm +{ + +//see http://stackoverflow.com/questions/1448467/initializing-a-c-stdistringstream-from-an-in-memory-buffer/1449527#1449527 +struct OneShotReadBuf : public std::streambuf +{ + OneShotReadBuf(void* s, std::size_t n){ + char* cast = (char*)s; + setg(cast, cast, cast+n); + } +}; + +StreamImageReader::StreamImageReader() +{ + //set these values to be the opposite ends of possible, + //so that if the extent is not defined, read can fail properly. + mXMin = mYMin = mZMin = std::numeric_limits::max(); + mXMax = mYMax = mZMax = std::numeric_limits::min(); +} + +StreamImageReader::~StreamImageReader() +{ +} + +/// One of either SetFileName or SetStream must be called prior +/// to any other functions. +void StreamImageReader::SetFileName(const char* inFileName) +{ + mReader.SetFileName(inFileName); +} + +void StreamImageReader::SetStream(std::istream& inStream) +{ + mReader.SetStream(inStream); +} + +std::vector StreamImageReader::GetDimensionsValueForResolution( unsigned int res ) +{ + std::vector extent(3); + File &file_t = mReader.GetFile(); + DataSet &ds_t = file_t.GetDataSet(); + + const DataElement &seq = ds_t.GetDataElement( Tag(0x0048,0x0200) ); + SmartPointer sqi = seq.GetValueAsSQ(); + + Item &itemL = sqi->GetItem(res); + DataSet &subds_L = itemL.GetNestedDataSet(); + + const DataElement &brrL = subds_L.GetDataElement( Tag(0x0048,0x0202) ); + Element elL1; + elL1.SetFromDataElement( brrL ); + extent[0] = elL1.GetValue(0); + extent[1] = elL1.GetValue(1); + extent[2] = res; + return extent; +} + +/// Defines an image extent for the Read function. +/// DICOM states that an image can have no more than 2^16 pixels per edge (as of 2009) +/// In this case, the pixel extents ignore the direction cosines entirely, and +/// assumes that the origin of the image is at location 0,0 (regardless of the definition +/// in space per the tags). So, if the first 100 pixels of the first row are to be read in, +/// this function should be called with DefinePixelExtent(0, 100, 0, 1), regardless +/// of pixel size or orientation. +void StreamImageReader::DefinePixelExtent(uint16_t inXMin, uint16_t inXMax, + uint16_t inYMin, uint16_t inYMax, + uint16_t inZMin, uint16_t inZMax){ + mXMin = inXMin; + mYMin = inYMin; + mXMax = inXMax; + mYMax = inYMax; + mZMin = inZMin; + mZMax = inZMax; +} +/// Paying attention to the pixel format and so forth, define the proper buffer length for the user. +/// The return amount is in bytes. +/// If the return is 0, then that means that the pixel extent was not defined prior +uint32_t StreamImageReader::DefineProperBufferLength() const +{ + if (mXMax < mXMin || mYMax < mYMin || mZMax < mZMin) return 0; + PixelFormat pixelInfo = ImageHelper::GetPixelFormatValue(mReader.GetFile()); + //unsigned short samplesPerPixel = pixelInfo.GetSamplesPerPixel(); + int bytesPerPixel = pixelInfo.GetPixelSize(); + return (mYMax - mYMin)*(mXMax - mXMin)*(mZMax - mZMin)*bytesPerPixel; +} + +/// Read the DICOM image. There are two reason for failure: +/// 1. The extent is not set +/// 2. The output buffer is not set +/// This method has been implemented to look similar to the metaimageio in itk +bool StreamImageReader::Read(char* inReadBuffer, const std::size_t& inBufferLength) +{ + //need to have some kind of extent defined. + if (mXMin > mXMax || mYMin > mYMax || mZMin > mZMax) + { + return false; //for now + } + +// OneShotReadBuf osrb(inReadBuffer, inBufferLength); +// std::ostream ostr(&osrb); + + //put the codec interpretation here + +// return ReadImageSubregionRAW(ostr); + //just do memcpys instead of doing this stream shenanigans + return ReadImageSubregionRAW(inReadBuffer, inBufferLength); +} + +/** Read a particular subregion, using the stored mFileOffset as the beginning of the stream. + This class reads uncompressed data; other subclasses will reimplement this function for compression. + Assumes that the given buffer is the size in bytes returned from DefineProperBufferLength. + */ +bool StreamImageReader::ReadImageSubregionRAW(char* inReadBuffer, const std::size_t& inBufferLength) +{ + //assumes that the file is organized in row-major format, with each row rastering across + assert( mFileOffset != -1 ); + (void)inBufferLength; + int y, z; + std::streamoff theOffset; + + //need to get the pixel size information + //should that come from the header? + //most likely that's a tag in the header + std::vector extent = ImageHelper::GetDimensionsValue(mReader.GetFile()); + PixelFormat pixelInfo = ImageHelper::GetPixelFormatValue(mReader.GetFile()); + //unsigned short samplesPerPixel = pixelInfo.GetSamplesPerPixel(); + int bytesPerPixel = pixelInfo.GetPixelSize(); + int SubRowSize = mXMax - mXMin; + int SubColSize = mYMax - mYMin; + + //set up the codec prior to resetting the file, just in case that affects the way that + //files are handled by the ImageHelper + + const FileMetaInformation &header = mReader.GetFile().GetHeader(); + const TransferSyntax &ts = header.GetDataSetTransferSyntax(); + bool needbyteswap = (ts == TransferSyntax::ImplicitVRBigEndianPrivateGE); + + RAWCodec theCodec; + if( !theCodec.CanDecode(ts) ) + { + JPEGLSCodec theJpegLSCodec; + if (!theJpegLSCodec.CanDecode(ts)) + { + gdcmDebugMacro( "Raw Codec cannot decode this file by streaming." ); + return false; + } + else + { + //read in the entire file for jpegls + //right now, it needs to be read entirely off of disk first + //kind of a shame, but it's the way it is now + mReader.Read(); + } + } + + theCodec.SetNeedByteSwap( needbyteswap ); + theCodec.SetDimensions(ImageHelper::GetDimensionsValue(mReader.GetFile())); + theCodec.SetPlanarConfiguration( + ImageHelper::GetPlanarConfigurationValue(mReader.GetFile())); + theCodec.SetPhotometricInterpretation( + ImageHelper::GetPhotometricInterpretationValue(mReader.GetFile())); + //how do I handle byte swapping here? where is it set? + + //have to reset the stream to the proper position + //first, reopen the stream,then the loop should set the right position + //mReader.SetFileName(mReader.GetFileName().c_str()); + std::istream* theStream = mReader.GetStreamPtr();//probably going to need a copy of this + + //to ensure thread safety; if the stream ptr handler gets used simultaneously by different threads, + //that would be BAD + //tmpBuffer is for a single raster + + char* tmpBuffer = new char[SubRowSize*bytesPerPixel]; + char* tmpBuffer2 = new char[SubRowSize*bytesPerPixel]; + try + { + for (z = mZMin; z < mZMax; ++z) + { +#if 0 + theStream->seekg(std::ios::beg); + + if(mFileOffset1 == 0) + { + mFileOffset1 = mFileOffset; + for(int j = 1; j<=z; j++) + { + std::vector extent = GetDimensionsValueForResolution(j); + mFileOffset1 = mFileOffset1 + (int)((extent[1])*(extent[0])*bytesPerPixel); + mFileOffset1 = mFileOffset1 + 4*sizeof(uint16_t); + } + } + else + { + mFileOffset1 = mFileOffset; + } + + std::vector extent = GetDimensionsValueForResolution(z+1); +#endif + + for (y = mYMin; y < mYMax; ++y) + { +#if 0 + theOffset = mFileOffset1 + (y*(int)(extent[0]) + mXMin)*bytesPerPixel; +#else + theStream->seekg(std::ios::beg); + theOffset = mFileOffset + (z * (int)(extent[1]*extent[0]) + y*(int)extent[0] + mXMin)*bytesPerPixel; +#endif + theStream->seekg(theOffset); + theStream->read(tmpBuffer, SubRowSize*bytesPerPixel); + //now, convert that buffer. + if (!theCodec.DecodeBytes(tmpBuffer, SubRowSize*bytesPerPixel, + tmpBuffer2, SubRowSize*bytesPerPixel)) + { + delete [] tmpBuffer; + delete [] tmpBuffer2; + return false; + } + //this next line may require a bit of finagling... + //std::copy(tmpBuffer2, &(tmpBuffer2[SubRowSize*bytesPerPixel]), std::ostream_iterator(os)); + //make sure to have a test that will test different x, y, and z mins and maxes + memcpy(&(inReadBuffer[((z-mZMin)*SubRowSize*SubColSize + + (y-mYMin)*SubRowSize)// + mXMin)//shouldn't need mXMin + *bytesPerPixel]), tmpBuffer2, SubRowSize*bytesPerPixel); + } +#if 0 + if((mYMax == extent[1]) && (mXMax == extent[0])) + { + mFileOffset1 = mFileOffset1 + (int)((extent[1])*(extent[0])*bytesPerPixel) + 4*sizeof(uint16_t); + } +#endif + } +#if 0 + mFileOffset = mFileOffset1; +#endif + } + + catch (std::exception & ex) + { + (void)ex; + gdcmWarningMacro( "Failed to read with ex:" << ex.what() ); + delete [] tmpBuffer; + delete [] tmpBuffer2; + return false; + } + catch (...) + { + gdcmWarningMacro( "Failed to read with unknown error." ); + delete [] tmpBuffer; + delete [] tmpBuffer2; + return false; + } + + delete [] tmpBuffer; + delete [] tmpBuffer2; + return true; +} + +/** This class reads via the jpegls codec. +Due to limitations in that codec, the entire file must be read into memory before a subregion +can be decoded. + */ +bool StreamImageReader::ReadImageSubregionJpegLS(char* inReadBuffer, const std::size_t& inBufferLength) { + //assumes that the file is organized in row-major format, with each row rastering across + //don't need to get all the other stuff (ie, the file offset) since we have to read it all in anyway + + //set up the codec prior to resetting the file, just in case that affects the way that + //files are handled by the ImageHelper + + const FileMetaInformation &header = mReader.GetFile().GetHeader(); + const TransferSyntax &ts = header.GetDataSetTransferSyntax(); + bool needbyteswap = (ts == TransferSyntax::ImplicitVRBigEndianPrivateGE); + + JPEGLSCodec theCodec; + if (!theCodec.CanDecode(ts)) + { + gdcmDebugMacro( "JpegLS cannot read this." ); + return false; + } + //read in the entire file for jpegls + //right now, it needs to be read entirely off of disk first + //kind of a shame, but it's the way it is now + mReader.Read(); + + theCodec.SetNeedByteSwap( needbyteswap ); + theCodec.SetDimensions(ImageHelper::GetDimensionsValue(mReader.GetFile())); + theCodec.SetPlanarConfiguration(ImageHelper::GetPlanarConfigurationValue(mReader.GetFile())); + theCodec.SetPhotometricInterpretation(ImageHelper::GetPhotometricInterpretationValue(mReader.GetFile())); + + try { + DataSet ds = mReader.GetFile().GetDataSet(); + Tag thePixelDataTag(0x7fe0, 0x0010); + DataElement de = ds.GetDataElement(thePixelDataTag); + theCodec.Decode(de, inReadBuffer, inBufferLength, mXMin, mXMax, mYMin, mYMax, mZMin, mZMax); + } + catch (std::exception & ex){ + (void)ex; + gdcmWarningMacro( "Failed to read with ex:" << ex.what() ); + return false; + } + catch (...){ + gdcmWarningMacro( "Failed to read with unknown error." ); + return false; + } + return true; +} + +/// Set the spacing and dimension information for the set filename. +/// returns false if the file is not initialized or not an image, +/// with the pixel 0x7fe0, 0x0010 tag. +bool StreamImageReader::ReadImageInformation() +{ + //read up to the point in the stream where the pixel information tag is + //store that location and keep the rest of the data as the header information dataset + std::set theSkipTags; + Tag thePixelDataTag(0x7fe0, 0x0010);//must be LESS than the pixel information tag, 0x7fe0,0x0010 + //otherwise, it'll read that tag as well. + //make a reader object in readimageinformation + //call read up to tag + //then create data structures from that dataset that's been read-up-to + theSkipTags.insert(thePixelDataTag); + + try + { + //ok, need to read up until I know what kind of endianness i'm dealing with? + if (!mReader.ReadUpToTag(thePixelDataTag, theSkipTags)) + { + gdcmWarningMacro("Failed to read tags in the gdcm stream image reader."); + return false; + } +#if 0 + std::streampos shift = 4*sizeof(uint16_t)+2*sizeof(uint32_t); + mFileOffset = mReader.GetStreamPtr()->tellg()+ shift; + mFileOffset1 = 0; +#else + mFileOffset = mReader.GetStreamPtr()->tellg(); +#endif + } + catch(std::exception & ex) + { + (void)ex; + gdcmWarningMacro( "Failed to read with ex:" << ex.what() ); + return false; + } + catch(...) + { + gdcmWarningMacro( "Failed to read with unknown error" ); + return false; + } + + // eg. ELSCINT1_PMSCT_RLE1.dcm + if( mFileOffset == -1 ) return false; + + // postcondition + assert( mFileOffset != -1 ); + + const File &file_t = mReader.GetFile(); + const DataSet &ds_t = file_t.GetDataSet(); + + MediaStorage ms; + ms.SetFromFile(file_t); + + if( ms == MediaStorage::VLWholeSlideMicroscopyImageStorage ) + { + if( !ds_t.FindDataElement( Tag(0x0048,0x0200) ) ) + { + gdcmWarningMacro( "error occured in WSI File read" ); + return false; + } + + DataElement seq = ds_t.GetDataElement( Tag(0x0048,0x0200) ); + SmartPointer sqi = seq.GetValueAsSQ(); + gdcm::SequenceOfItems::SizeType s = sqi->GetNumberOfItems(); + + Item itemL = sqi->GetItem(1); + DataSet &subds_L = itemL.GetNestedDataSet(); + + if( !subds_L.FindDataElement( Tag(0x0008,0x1160) ) ) + { + gdcmWarningMacro( "Error occured during WSI File Read" ); + return false; + } + + DataElement rfnL = subds_L.GetDataElement( Tag(0x0008,0x1160) ); + Element elL; + elL.SetFromDataElement( rfnL ); + + if( !subds_L.FindDataElement( Tag(0x0048,0x0202) ) ) + { + gdcmWarningMacro( "Error During WSI File Read" ); + return false; + } + + DataElement brrL = subds_L.GetDataElement( Tag(0x0048,0x0202) ); + Element elL1; + elL1.SetFromDataElement( brrL ); + + Item itemH = sqi->GetItem(s); + DataSet &subds_H = itemH.GetNestedDataSet(); + + if( !subds_H.FindDataElement( Tag(0x0008,0x1160) ) ) + { + gdcmWarningMacro( "Error occured during WSI File Read" ); + return false; + } + + DataElement rfnH = subds_H.GetDataElement( Tag(0x0008,0x1160) ); + Element elH; + elH.SetFromDataElement( rfnH ); + + if( !subds_H.FindDataElement( Tag(0x0048,0x0202) ) ) + { + gdcmWarningMacro( "Error During WSI File Read" ); + return false; + } + + DataElement brrH = subds_H.GetDataElement( Tag(0x0048,0x0202) ); + Element elH1; + elH1.SetFromDataElement( brrH ); + } + + return true; +} + +bool StreamImageReader::CanReadImage() const +{ + //this is the check to ensure that ReadImageInformation was read in properly + if (mFileOffset == -1) + { + return false; + } + + const FileMetaInformation &header = mReader.GetFile().GetHeader(); + const TransferSyntax &ts = header.GetDataSetTransferSyntax(); + //bool needbyteswap = (ts == TransferSyntax::ImplicitVRBigEndianPrivateGE); + + RAWCodec theCodec; + bool canDecodeRaw = theCodec.CanDecode(ts); + if (!canDecodeRaw) return false; + + std::vector extent = ImageHelper::GetDimensionsValue(mReader.GetFile()); + if (extent.empty()) return false; //should not happen with current GetDimensionsValue implementation + //but just in case... + + if (extent[0] == 0 || extent[1] == 0) + return false; + + return true; +} + + /// Returns the dataset read by ReadImageInformation + /// Couple this with the ImageHelper to get statistics about the image, + /// like pixel extent, to be able to initialize buffers for reading +File const &StreamImageReader::GetFile() const +{ + if (mFileOffset > 0) + { + /// mFileOffset1 = 0; + return mReader.GetFile(); + } + else + { + assert(0); + return mReader.GetFile(); + } +} + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmStreamImageReader.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmStreamImageReader.h new file mode 100644 index 0000000..8af443f --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmStreamImageReader.h @@ -0,0 +1,126 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#ifndef GDCMSTREAMIMAGEREADER_H +#define GDCMSTREAMIMAGEREADER_H + +#include "gdcmReader.h" + +namespace gdcm +{ + +class MediaStorage; +/** + * \brief StreamImageReader + * \note its role is to convert the DICOM DataSet into a gdcm::Image + * representation via an ITK streaming (ie, multithreaded) interface + * Image is different from Pixmap has it has a position and a direction in + * Space. + * Currently, this class is thread safe in that it can read a single extent + * in a single thread. Multiple versions can be used for multiple extents/threads. + * + * \see Image + */ +class GDCM_EXPORT StreamImageReader +{ + +public: + StreamImageReader(); + virtual ~StreamImageReader(); + + /// One of either SetFileName or SetStream must be called prior + /// to any other functions. These initialize an internal Reader class + /// to be able to get non-pixel image information. + void SetFileName(const char* inFileName); + void SetStream(std::istream& inStream); + + std::vector GetDimensionsValueForResolution( unsigned int ); + + /// Defines an image extent for the Read function. + /// DICOM states that an image can have no more than 2^16 pixels per edge (as of 2009) + /// In this case, the pixel extents ignore the direction cosines entirely, and + /// assumes that the origin of the image is at location 0,0 (regardless of the definition + /// in space per the tags). So, if the first 100 pixels of the first row are to be read in, + /// this function should be called with DefinePixelExtent(0, 100, 0, 1), regardless + /// of pixel size or orientation. + void DefinePixelExtent(uint16_t inXMin, uint16_t inXMax, + uint16_t inYMin, uint16_t inYMax, uint16_t inZMin = 0, uint16_t inZMax = 1); + + /// Paying attention to the pixel format and so forth, define the proper buffer length for the user. + /// The return amount is in bytes. Call this function to determine the size of the char* buffer + /// that will need to be passed in to ReadImageSubregion(). + /// If the return is 0, then that means that the pixel extent was not defined prior + uint32_t DefineProperBufferLength() const; + + /// Read the DICOM image. There are three reasons for failure: + /// 1. The extent is not set + /// 2. the conversion from char* to std::ostream (internally) fails + /// 3. the given buffer isn't large enough to accommodate the desired pixel extent. + /// This method has been implemented to look similar to the metaimageio in itk + /// MUST have an extent defined, or else Read will return false. + /// If no particular extent is required, use ImageReader instead. + bool Read(char* inReadBuffer, const std::size_t& inBufferLength); + + /// Only RAW images are currently readable by the stream reader. As more + /// streaming codecs are added, then this function will be updated to reflect + /// those changes. Calling this function prior to reading will ensure that + /// only streamable files are streamed. Make sure to call ReadImageInformation + /// prior to calling this function. + bool CanReadImage() const; + + /// Set the spacing and dimension information for the set filename. + /// returns false if the file is not initialized or not an image, + /// with the pixel (7fe0,0010) tag. + virtual bool ReadImageInformation(); + + /// Returns the dataset read by ReadImageInformation + /// Couple this with the ImageHelper to get statistics about the image, + /// like pixel extent, to be able to initialize buffers for reading + File const & GetFile() const; + +protected: +private: + //contains a reader for being able to ReadUpToTag + //however, we don't want the user to be able to call Read + //either directly or via a parent class call, so we hide the reader in here. + Reader mReader; + + std::streamoff mFileOffset; //the file offset for getting header information +#if 0 + std::streamoff mFileOffset1; +#endif + DataSet mHeaderInformation; //all the non-pixel information + + //for thread safety, these should not be stored here, but should be used + //for every read subregion operation. + uint16_t mXMin, mYMin, mXMax, mYMax, mZMin, mZMax; + + /// Using the min, max, etc set by DefinePixelExtent, this will fill the given buffer + /// Make sure to call DefinePixelExtent and to initialize the buffer with the + /// amount given by DefineProperBufferLength prior to calling this. + /// reads by the RAW codec; other codecs are added once implemented + bool ReadImageSubregionRAW(char* inReadBuffer, const std::size_t& inBufferLength); + + /// Reads the file via JpegLS. The JpegLS codec, as of this writing, requires that the + /// entire file be read in in order to decode a subregion, so that's what's done here. + bool ReadImageSubregionJpegLS(char* inReadBuffer, const std::size_t& inBufferLength); +}; + +} // end namespace gdcm + +#endif //GDCMSTREAMIMAGEREADER_H + diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmStreamImageWriter.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmStreamImageWriter.cxx new file mode 100644 index 0000000..9af8ebb --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmStreamImageWriter.cxx @@ -0,0 +1,433 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ + + + +#include "gdcmStreamImageWriter.h" +#include "gdcmTag.h" +#include "gdcmMediaStorage.h" +#include +#include "gdcmImageHelper.h" +#include "gdcmRAWCodec.h" + +namespace gdcm +{ + +StreamImageWriter::StreamImageWriter():mspFile(new File) +{ + //set these values to be the opposite ends of possible, + //so that if the extent is not defined, read can fail properly. + mXMin = mYMin = mZMin = std::numeric_limits::max(); + mXMax = mYMax = mZMax = std::numeric_limits::min(); + mElementOffsets = 0; + mElementOffsets1 = 0; +} +StreamImageWriter::~StreamImageWriter() +{ +} + + +/// One of either SetFileName or SetStream must be called prior +/// to any other functions. +void StreamImageWriter::SetFileName(const char* inFileName){ + mWriter.SetFileName(inFileName); + mElementOffsets = 0;//changing to a new file, should make sure that we're starting again +} +void StreamImageWriter::SetStream(std::ostream& inStream){ + mWriter.SetStream(inStream); +} + + +/// Defines an image extent for the Read function. +/// DICOM states that an image can have no more than 2^16 pixels per edge (as of 2009) +/// In this case, the pixel extents ignore the direction cosines entirely, and +/// assumes that the origin of the image is at location 0,0 (regardless of the definition +/// in space per the tags). So, if the first 100 pixels of the first row are to be read in, +/// this function should be called with DefinePixelExtent(0, 100, 0, 1), regardless +/// of pixel size or orientation. +void StreamImageWriter::DefinePixelExtent(uint16_t inXMin, uint16_t inXMax, + uint16_t inYMin, uint16_t inYMax, + uint16_t inZMin, uint16_t inZMax){ + mXMin = inXMin; + mYMin = inYMin; + mXMax = inXMax; + mYMax = inYMax; + mZMin = inZMin; + mZMax = inZMax; +} + +/// Read the DICOM image. There are two reason for failure: +/// 1. The extent is not set +/// 2. The output buffer is not set +/// This method has been implemented to look similar to the metaimageio in itk +bool StreamImageWriter::Write(void* inReadBuffer, const std::size_t& inBufferLength){ + + //need to have some kind of extent defined. + if (mXMin > mXMax || mYMin > mYMax || mZMin > mZMax) + return false; //for now + + +// OneShotReadBuf osrb(inReadBuffer, inBufferLength); +// std::ostream ostr(&osrb); + + //put the codec interpretation here + +// return ReadImageSubregionRAW(ostr); + //just do memcpys instead of doing this stream shenanigans + return WriteImageSubregionRAW((char*)inReadBuffer, inBufferLength); + +} +/// Paying attention to the pixel format and so forth, define the proper buffer length for the user. +/// The return amount is in bytes. +/// If the return is 0, then that means that the pixel extent was not defined prior +/// this return is for RAW inputs which are then encoded by the writer, but are used +/// to ensure that the writer gets the proper buffer size +uint32_t StreamImageWriter::DefineProperBufferLength() { + if (mXMax < mXMin || mYMax < mYMin || mZMax < mZMin) return 0; + PixelFormat pixelInfo = ImageHelper::GetPixelFormatValue(mWriter.GetFile()); + //unsigned short samplesPerPixel = pixelInfo.GetSamplesPerPixel(); + int bytesPerPixel = pixelInfo.GetPixelSize(); + return (mYMax - mYMin)*(mXMax - mXMin)*(mZMax - mZMin)*bytesPerPixel; +} + +/// when writing a raw file, we know the full extent, and can just write the first +/// 12 bytes out (the tag, the VR, and the size) +/// when we do compressed files, we'll do it in chunks, as described in +/// 2009-3, part 5, Annex A, section 4. +/// Pass the raw codec so that in the rare case of a bigendian explicit raw, +/// the first 12 bytes written out should still be kosher. +/// returns -1 if there's any failure, or the complete offset (12 bytes) +/// if it works. Those 12 bytes are then added to the position in order to determine +/// where to write. +int StreamImageWriter::WriteRawHeader(RAWCodec* inCodec, std::ostream* inStream) +{ + //if this is the first time writing the file out, then + //the first few header bytes need to be written out; the tags, the length, etc + //that information is found at 2009, section 5, annex A, table 4-1 and 4-2 + //for now, just writing out straight raw, which means that the first 12 bytes are + //07fe, 0010, OB, 00, 32 bit length + //and must be written in little endian (for now-- could do big endian raw, but not atm) + //so, we set those 12 bytes up, send them through the codec, and then write them directly to disk + //because this is raw, we know exactly the size that will be written. So, let's do that. + if(mElementOffsets == 0) + { + uint16_t firstTag = 0x7fe0; + uint16_t secondTag = 0x0010; + //uint16_t thirdTag = 0x4f42; + uint16_t thirdTag = 0x424f; // OB + uint16_t fourthTag = 0x0000; + //uint16_t fourthTag = 0x0000; + + uint32_t fifthTag = 0xffffffff; + + uint16_t sixthTag = 0xfffe; + uint16_t seventhTag = 0xe000; + uint32_t eightthTag = 0x00000000; + + const int theBufferSize = 4*sizeof(uint16_t)+sizeof(uint32_t)+2*sizeof(uint16_t)+sizeof(uint32_t); + char* tmpBuffer1 = new char[theBufferSize]; + + memcpy(&(tmpBuffer1[0]), &firstTag, sizeof(uint16_t)); + memcpy(&(tmpBuffer1[sizeof(uint16_t)]), &secondTag, sizeof(uint16_t)); + memcpy(&(tmpBuffer1[2*sizeof(uint16_t)]), &thirdTag, sizeof(uint16_t)); + memcpy(&(tmpBuffer1[3*sizeof(uint16_t)]), &fourthTag, sizeof(uint16_t)); + + //Addition by Manoj + memcpy(&(tmpBuffer1[4*sizeof(uint16_t)]), &fifthTag, sizeof(uint32_t));// Data Element Length 4 bytes + + // Basic OffSet Tabl with No Item Value + memcpy(&(tmpBuffer1[4*sizeof(uint16_t)+sizeof(uint32_t)]), &sixthTag, sizeof(uint16_t)); //fffe + memcpy(&(tmpBuffer1[5*sizeof(uint16_t)+sizeof(uint32_t)]), &seventhTag, sizeof(uint16_t));//e000 + memcpy(&(tmpBuffer1[6*sizeof(uint16_t)+sizeof(uint32_t)]), &eightthTag, sizeof(uint32_t));//00000000H + + assert( inStream && *inStream && !inStream->eof() && inStream->good() ); + inStream->write(tmpBuffer1, theBufferSize); + inStream->flush(); + assert( inStream && *inStream ); + } + + uint16_t NinthTag = 0xfffe; + uint16_t TenthTag = 0xe000; + + std::vector extent = ImageHelper::GetDimensionsValue(mWriter.GetFile()); + PixelFormat pixelInfo = ImageHelper::GetPixelFormatValue(mWriter.GetFile()); + int bytesPerPixel = pixelInfo.GetPixelSize(); + uint32_t sizeTag = extent[0]*extent[1]*extent[2]*bytesPerPixel; + + const int theBufferSize1 = 2*sizeof(uint16_t)+sizeof(uint32_t); + + char* tmpBuffer3 = new char[theBufferSize1]; + char* tmpBuffer4 = new char[theBufferSize1]; + // std::streamoff theOffset; + + try { + + //First Fragment (Single Frame) of Pixel Data + memcpy(&(tmpBuffer3[0]), &NinthTag, sizeof(uint16_t)); //fffe + memcpy(&(tmpBuffer3[sizeof(uint16_t)]), &TenthTag, sizeof(uint16_t)); //e000 + + memcpy(&(tmpBuffer3[2*sizeof(uint16_t)]), &sizeTag, sizeof(uint32_t));//Item Length + //run that through the codec + + if (!inCodec->DecodeBytes(tmpBuffer3, theBufferSize1, + tmpBuffer4, theBufferSize1)){ + delete [] tmpBuffer3; + gdcmErrorMacro( "Problems in Header" ); + delete [] tmpBuffer4; + return -1; + } + + //write that chunk to the end of the file, ie, this function + //requires that it be called with a stream in append mode + // inStream->seekp(std::ios::beg); + // theOffset = mFileOffset; + // inStream->seekp(theOffset); + assert( inStream && *inStream && !inStream->eof() && inStream->good() ); + inStream->write(tmpBuffer4, theBufferSize1); + inStream->flush(); + assert( inStream && *inStream ); + + } catch(...){ + delete [] tmpBuffer3; + delete [] tmpBuffer4; + return -1; + } + delete [] tmpBuffer3; + delete [] tmpBuffer4; + return sizeTag; +} + +/** Read a particular subregion, using the stored mFileOffset as the beginning of the stream. + This class reads uncompressed data; other subclasses will reimplement this function for compression. + Assumes that the given buffer is the size in bytes returned from DefineProperBufferLength. + */ +bool StreamImageWriter::WriteImageSubregionRAW(char* inWriteBuffer, const std::size_t& inBufferLength) +{ + (void)inBufferLength; + //assumes that the file is organized in row-major format, with each row rastering across +// assert( mFileOffset != -1 ); + int y, z; +// std::streamoff theOffset; + + //need to get the pixel size information + //should that come from the header? + //most likely that's a tag in the header + std::vector extent = ImageHelper::GetDimensionsValue(mWriter.GetFile()); + PixelFormat pixelInfo = ImageHelper::GetPixelFormatValue(mWriter.GetFile()); + //unsigned short samplesPerPixel = pixelInfo.GetSamplesPerPixel(); + int bytesPerPixel = pixelInfo.GetPixelSize(); + int SubRowSize = mXMax - mXMin; + int SubColSize = mYMax - mYMin; + + //set up the codec prior to resetting the file, just in case that affects the way that + //files are handled by the ImageHelper + + const FileMetaInformation &header = mWriter.GetFile().GetHeader(); + const TransferSyntax &ts = header.GetDataSetTransferSyntax(); + bool needbyteswap = (ts == TransferSyntax::ImplicitVRBigEndianPrivateGE); + + RAWCodec theCodec; + if( !theCodec.CanDecode(ts) || ts == gdcm::TransferSyntax::ExplicitVRBigEndian) + { + gdcmErrorMacro( "Only RAW for now" ); + return false; + } + + theCodec.SetNeedByteSwap( needbyteswap ); + theCodec.SetDimensions(ImageHelper::GetDimensionsValue(mWriter.GetFile())); + theCodec.SetPlanarConfiguration( + ImageHelper::GetPlanarConfigurationValue(mWriter.GetFile())); + theCodec.SetPhotometricInterpretation( + ImageHelper::GetPhotometricInterpretationValue(mWriter.GetFile())); + //how do I handle byte swapping here? where is it set? + + //have to reset the stream to the proper position + //first, reopen the stream,then the loop should set the right position + //MM: you have to reopen the stream, by default, the writer closes it each time it writes. +// mWriter.SetFileName(mWriter.GetFileName().c_str(), true);//open in file append mode + std::ostream* theStream = mWriter.GetStreamPtr();//probably going to need a copy of this + //to ensure thread safety; if the stream ptr handler gets used simultaneously by different threads, + //that would be BAD + //tmpBuffer is for a single raster + assert( theStream && *theStream ); + char* tmpBuffer = new char[SubRowSize*bytesPerPixel]; + char* tmpBuffer2 = new char[SubRowSize*bytesPerPixel]; + try { + if (mElementOffsets == 0 || mElementOffsets1 ==0 ){ + mElementOffsets = WriteRawHeader(&theCodec, theStream); + mElementOffsets1 = mElementOffsets; + } + if (mElementOffsets < 0){//something broke during writing + gdcmErrorMacro( "Broke" ); + delete [] tmpBuffer; + delete [] tmpBuffer2; + return false; + } + //only need to seek to the location once, and then write sequentially + //may be trickier with compressed images, but should work for RAW + // theStream->seekp(std::ios::end); + //seeking to the end should be sufficient, if we're guaranteed to get chunks in order +// theOffset = mFileOffset + (mZMin * (int)(extent[1]*extent[0]) + mYMin*(int)extent[0] + mXMin)*bytesPerPixel + mElementOffsets; + // theStream->seekp(mElementOffsets); + for (z = mZMin; z < mZMax; ++z){ + for (y = mYMin; y < mYMax; ++y){ + //this next line may require a bit of finagling... + //std::copy(tmpBuffer2, &(tmpBuffer2[SubRowSize*bytesPerPixel]), std::ostream_iterator(os)); + //make sure to have a test that will test different x, y, and z mins and maxes + memcpy(tmpBuffer, &(inWriteBuffer[((z-mZMin)*SubRowSize*SubColSize + + (y-mYMin)*SubRowSize)// + mXMin)//shouldn't need mXMin + *bytesPerPixel]), SubRowSize*bytesPerPixel); + + + if (!theCodec.DecodeBytes(tmpBuffer, SubRowSize*bytesPerPixel, + tmpBuffer2, SubRowSize*bytesPerPixel)){ + delete [] tmpBuffer; + delete [] tmpBuffer2; + return false; + } + //should be appending + //assert( theStream && *theStream && !theStream->eof() && theStream->good() ); + theStream->write(tmpBuffer2, SubRowSize*bytesPerPixel); + theStream->flush(); + //assert( theStream && *theStream ); + } + } + } + catch (std::exception & ex){ + (void)ex; + gdcmWarningMacro( "Failed to write with ex:" << ex.what() ); + delete [] tmpBuffer; + delete [] tmpBuffer2; + return false; + } + catch (...){ + gdcmWarningMacro( "Failed to write with unknown error." ); + delete [] tmpBuffer; + delete [] tmpBuffer2; + return false; + } + delete [] tmpBuffer; + delete [] tmpBuffer2; + return true; +} + +/// Set the spacing and dimension information for the set filename. +/// returns false if the file is not initialized or not an image, +/// with the pixel 0x7fe0, 0x0010 tag. +bool StreamImageWriter::WriteImageInformation(){ + + //ok, the writer has a file in it, and so we place the dataset that we're given into + //the file + File &mFile = *mspFile; + mWriter.SetFile(mFile); + mElementOffsets = 0;//changing to a new file, should make sure that we're starting again + //filename needs to be set prior to this function + try + { + //question! is this file a copy of the file that was given in, or a reference? + mFile.GetDataSet().Remove( Tag(0x7fe0,0x0010) ); // FIXME + assert( !mFile.GetDataSet().FindDataElement( Tag(0x7fe0,0x0010) ) ); + if( !mWriter.Write() )//should write everything BUT the image tag. right? + { + //assert( 0 );//this assert fires when the image is not writeable, ie, doesn't have + //tags 2,3 and 8,18 + //if the writer can't write, then this should return false. + return false; + } + //this is where to start writing zeros for the image. + //BUT! do we know here if it's compressed for writing out? If so, shouldn't that require forcing + //the datasets to be presented sequentially? + //at this point, we should be at the end of the dataset, and the pointer should be set to eof + //which is good, because otherwise, we have a problem (write is inherited, and I can't easily + //do the trick where I return the stream location + //no longer really using the mFileLocation anyway, because always appending. + /* mWriter.SetFileName(mWriter.GetFileName().c_str());//MM: we must call setfilename in order to open + //the stream. Otherwise, the position information will be wrong. + std::ostream* theStreamPtr = mWriter.GetStreamPtr(); + theStreamPtr->seekp(std::ios::end); + mFileOffset = theStreamPtr->tellp(); + std::ofstream* theFileStreamPtr = dynamic_cast(theStreamPtr); + if (theFileStreamPtr!= NULL){ + theFileStreamPtr->close(); + } + */ + } + catch(std::exception & ex) + { + (void)ex; + gdcmWarningMacro( "Failed to write with ex:" << ex.what() ); + } + catch(...) + { + gdcmWarningMacro( "Failed to write with unknown error" ); + } + + // eg. ELSCINT1_PMSCT_RLE1.dcm +// if( mFileOffset == -1 ) return false; + + // postcondition +// assert( mFileOffset != -1 ); + return true; +} + +//this function determines if a file can even be written using the streaming writer +//unlike the reader, can be called before WriteImageInformation, but must be called +//after SetFile. +bool StreamImageWriter::CanWriteFile() const +{ + File &mFile = *mspFile; + if (mspFile == NULL) + { + return false; + } + + bool hasTag23 = mFile.GetDataSet().FindDataElement(Tag(0x02,0x03)); + bool hasTag818 = mFile.GetDataSet().FindDataElement(Tag(0x08,0x18)); + if (!hasTag23 && !hasTag818){ + // std::cout << "It is good"; + return false; //need both tags to be able to write out to disk + } + + + const FileMetaInformation &header = mFile.GetHeader(); + const TransferSyntax &ts = header.GetDataSetTransferSyntax(); + //std::cout<< ts; + RAWCodec theCodec; +// bool canDecodeWithRaw = !theCodec.CanDecode(ts); + bool canDecodeWithRaw = theCodec.CanDecode(ts); + if (!canDecodeWithRaw) + { + //std::cout << "It is not good"; + return false; + } + + return true; +} + + /// Set the image information to be written to disk that is everything but + /// the pixel information. Copies the data into a new dataset, except for the pixel element +///This way, writing the image information will just write everything else. +void StreamImageWriter::SetFile(const File& inFile) +{ + mspFile = inFile; + File &mFile = *mspFile; + mWriter.SetFile(mFile); + mElementOffsets1 = 0; +} + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmStreamImageWriter.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmStreamImageWriter.h new file mode 100644 index 0000000..8e31c48 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmStreamImageWriter.h @@ -0,0 +1,145 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ + +#ifndef GDCMSTREAMIMAGEWRITER_H +#define GDCMSTREAMIMAGEWRITER_H + +#include "gdcmWriter.h" +#include +#include "gdcmDataSet.h" + +namespace gdcm +{ + +class MediaStorage; +class RAWCodec; +/** + * \brief StreamImageReader + * \note its role is to convert the DICOM DataSet into a gdcm::Image + * representation via an ITK streaming (ie, multithreaded) interface + * Image is different from Pixmap has it has a position and a direction in + * Space. + * Currently, this class is threadsafe in that it can read a single extent + * in a single thread. Multiple versions can be used for multiple extents/threads. + * + * \see Image + */ +class GDCM_EXPORT StreamImageWriter +{ + +public: + StreamImageWriter(); + virtual ~StreamImageWriter(); + + + /// One of either SetFileName or SetStream must be called prior + /// to any other functions. These initialize an internal Reader class + /// to be able to get non-pixel image information. + void SetFileName(const char* inFileName); + void SetStream(std::ostream& inStream); + + /// Defines an image extent for the Read function. + /// DICOM states that an image can have no more than 2^16 pixels per edge (as of 2009) + /// In this case, the pixel extents ignore the direction cosines entirely, and + /// assumes that the origin of the image is at location 0,0 (regardless of the definition + /// in space per the tags). So, if the first 100 pixels of the first row are to be read in, + /// this function should be called with DefinePixelExtent(0, 100, 0, 1), regardless + /// of pixel size or orientation. + /// 15 nov 2010: added z dimension, defaults to being 1 plane large + void DefinePixelExtent(uint16_t inXMin, uint16_t inXMax, + uint16_t inYMin, uint16_t inYMax, uint16_t inZMin = 0, uint16_t inZMax = 1); + + + /// Paying attention to the pixel format and so forth, define the proper buffer length for the user. + /// The return amount is in bytes. + /// If the return is 0, then that means that the pixel extent was not defined prior + /// this return is for RAW inputs which are then encoded by the writer, but are used + /// to ensure that the writer gets the proper buffer size + uint32_t DefineProperBufferLength(); + + /// Read the DICOM image. There are three reasons for failure: + /// 1. The extent is not set + /// 2. the conversion from void* to std::ostream (internally) fails + /// 3. the given buffer isn't large enough to accomodate the desired pixel extent. + /// This method has been implemented to look similar to the metaimageio in itk + /// MUST have an extent defined, or else Read will return false. + /// If no particular extent is required, use ImageReader instead. + bool Write(void* inWriteBuffer, const std::size_t& inBufferLength); + + /// Write the header information to disk, and a bunch of zeros for the actual pixel information + /// Of course, if we're doing a non-compressed format, that works + /// but if it's compressed, we have to force the ordering of chunks that are written. + virtual bool WriteImageInformation(); + + /// This function determines if a file can even be written using the streaming writer + /// unlike the reader, can be called before WriteImageInformation, but must be called + /// after SetFile. + bool CanWriteFile() const; + + + /// Set the image information to be written to disk that is everything but + /// the pixel information: (7fe0,0010) PixelData + void SetFile(const File& inFile); + +protected: + + //contains the PrepareWrite function, which will get the given dataset ready + //for writing to disk by manufacturing the header information. + //note that if there is a pixel element in the given dataset, that will be removed + //during the copy, so that the imagewriter can write everything else out + Writer mWriter; + + //is the offset necessary if we always append? + //std::streamoff mFileOffset; //the fileoffset for getting header information + SmartPointer mspFile; //all the non-pixel information + + //for thread safety, these should not be stored here, but should be used + //for every read subregion operation. + uint16_t mXMin, mYMin, mXMax, mYMax, mZMin, mZMax; + + /// Using the min, max, etc set by DefinePixelExtent, this will fill the given buffer + /// Make sure to call DefinePixelExtent and to initialize the buffer with the + /// amount given by DefineProperBufferLength prior to calling this. + /// reads by the RAW codec; other codecs are added once implemented + //virtual bool ReadImageSubregionRAW(std::ostream& os); + virtual bool WriteImageSubregionRAW(char* inWriteBuffer, const std::size_t& inBufferLength); + + /// when writing a raw file, we know the full extent, and can just write the first + /// 12 bytes out (the tag, the VR, and the size) + /// when we do compressed files, we'll do it in chunks, as described in + /// 2009-3, part 5, Annex A, section 4. + /// Pass the raw codec so that in the rare case of a bigendian explicit raw, + /// the first 12 bytes written out should still be kosher. + /// returns -1 if there's any failure, or the complete offset (12 bytes) + /// if it works. Those 12 bytes are then added to the position in order to determine + /// where to write. + int WriteRawHeader(RAWCodec* inCodec, std::ostream* inStream); + + /// The result of WriteRawHeader (or another header, when that's implemented) + /// This result is saved so that the first N bytes aren't constantly being + /// rewritten for each chunk that's passed in. + /// For compressed data, the offset table will require rewrites of data. + int mElementOffsets; + int mElementOffsets1; + +}; + + +} // end namespace gdcm + +#endif //GDCMSTREAMIMAGEWRITER_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmStringFilter.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmStringFilter.cxx new file mode 100644 index 0000000..3fafc2b --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmStringFilter.cxx @@ -0,0 +1,567 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmStringFilter.h" +#include "gdcmGlobal.h" +#include "gdcmElement.h" +#include "gdcmByteValue.h" +#include "gdcmAttribute.h" +#include "gdcmDataSetHelper.h" + +#include // strtok + +namespace gdcm +{ + +//----------------------------------------------------------------------------- +StringFilter::StringFilter():F(new File) +{ +} +//----------------------------------------------------------------------------- +StringFilter::~StringFilter() +{ +} + +void StringFilter::SetDicts(const Dicts &dicts) +{ + (void)dicts; + assert(0); // FIXME +} + +std::string StringFilter::ToString(const Tag& t) const +{ + return ToStringPair(t).second; +} + +/* +std::string StringFilter::ToMIME64(const Tag& t) const +{ + return ToStringPair(t).second; + // base64 streams have to be a multiple of 4 bytes long + int encodedLengthEstimate = 2 * bv->GetLength(); + encodedLengthEstimate = ((encodedLengthEstimate / 4) + 1) * 4; + + char *bin = new char[encodedLengthEstimate]; + unsigned int encodedLengthActual = static_cast( + itksysBase64_Encode( + (const unsigned char *) bv->GetPointer(), + static_cast< unsigned long>( bv->GetLength() ), + (unsigned char *) bin, + static_cast< int >( 0 ) )); + std::string encodedValue(bin, encodedLengthActual); + +} +*/ + +#define StringFilterCase(type) \ + case VR::type: \ + { \ + Element el; \ + if( !de.IsEmpty() ) { \ + el.Set( de.GetValue() ); \ + if( el.GetLength() ) { \ + os << el.GetValue(); \ + for(unsigned int i = 1; i < el.GetLength(); ++i) os << "\\" << el.GetValue(i); \ + retvalue = os.str(); } } \ + } break + +std::pair StringFilter::ToStringPair(const Tag& t) const +{ + if( t.GetGroup() == 0x2 ) + { + const FileMetaInformation &header = GetFile().GetHeader(); + return ToStringPair(t, header); + } + else + { + const DataSet &ds = GetFile().GetDataSet(); + return ToStringPair(t, ds); + } +} + +bool StringFilter::ExecuteQuery(std::string const & query_const, std::string &value ) const +{ +// if( t.GetGroup() == 0x2 ) +// { +// const FileMetaInformation &header = GetFile().GetHeader(); +// return ToStringPair(query_const, header); +// } +// else + { + const DataSet &ds = GetFile().GetDataSet(); + return ExecuteQuery(query_const, ds, value); + } +} + +bool StringFilter::ExecuteQuery(std::string const & query_const, + DataSet const &ds, std::string &retvalue ) const +{ + //std::pair ret; + static gdcm::Global &g = gdcm::Global::GetInstance(); + static const gdcm::Dicts &dicts = g.GetDicts(); + static const gdcm::Dict &pubdict = dicts.GetPublicDict(); + + char *query = strdup( query_const.c_str() ); + const char delim[] = "/"; + const char subdelim[] = "[]@='"; + + char *str1, *str2, *token, *subtoken; + char *saveptr1, *saveptr2; + int j; + + //bool dicomnativemodel = false;//unused + const gdcm::DataSet *curds = NULL; + const gdcm::DataElement *curde = NULL; + gdcm::Tag t; + int state = 0; + SmartPointer sqi; + for (j = 1, str1 = query; state >= 0 ; j++, str1 = NULL) + { + token = System::StrTokR(str1, delim, &saveptr1); + + if (token == NULL) + break; + //printf("%d: %s\n", j, token); + + std::vector< std::string > subtokens; + for (str2 = token; ; str2 = NULL) + { + subtoken = System::StrTokR(str2, subdelim, &saveptr2); + if (subtoken == NULL) + break; + //printf(" --> %s\n", subtoken); + subtokens.push_back( subtoken ); + } + if( subtokens[0] == "DicomNativeModel" ) + { + // move to next state + assert( state == 0 ); + state = 1; + curds = &ds; + } + else if( subtokens[0] == "DicomAttribute" ) + { + if( state != 1 ) + { + state = -1; + break; + } + assert( subtokens[1] == "keyword" ); + const char *k = subtokens[2].c_str(); + /*const gdcm::DictEntry &dictentry = */pubdict.GetDictEntryByKeyword(k, t); + if( !curds->FindDataElement( t ) ) + { + state = -1; + break; + } + curde = &curds->GetDataElement( t ); + } + else if( subtokens[0] == "Item" ) + { + assert( state == 1 ); + assert( curde ); + assert( subtokens[1] == "number" ); + sqi = curde->GetValueAsSQ(); + if( !sqi ) + { + state = -1; + break; + } + gdcm::Item const &item = sqi->GetItem( atoi( subtokens[2].c_str() ) ); + curds = &item.GetNestedDataSet(); + } + else if( subtokens[0] == "Value" ) + { + assert( state == 1 ); + // move to next state + state = 2; + assert( subtokens[1] == "number" ); +#if !defined(NDEBUG) + const gdcm::ByteValue * const bv = curde->GetByteValue(); (void)bv; + assert( bv ); + //bv->Print( std::cout << std::endl ); +#endif + } + else + { + assert( subtokens.size() ); + gdcmDebugMacro( "Unhandled token: " << subtokens[0] ); + state = -1; + } + } + if( state != 2 ) + { + return false; + } + free( query ); + + const DataElement &de = *curde; + + const DictEntry &entry = pubdict.GetDictEntry(de.GetTag()); + + const VR &vr_read = de.GetVR(); + const VR &vr_dict = entry.GetVR(); + + if( vr_dict == VR::INVALID ) + { + // FIXME This is a public element we do not support... + return false; + } + + VR vr; + // always prefer the vr from the file: + if( vr_read == VR::INVALID ) + { + vr = vr_dict; + } + else if ( vr_read == VR::UN && vr_dict != VR::INVALID ) // File is explicit, but still prefer vr from dict when UN + { + vr = vr_dict; + } + else // cool the file is Explicit ! + { + vr = vr_read; + } + if( vr.IsDual() ) // This mean vr was read from a dict entry: + { + vr = DataSetHelper::ComputeVR(*F,ds, t); + } + + if( vr == VR::UN ) + { + // this element is not known... + return false; + } + + assert( vr != VR::UN && vr != VR::INVALID ); + //ret.first = entry.GetName(); + if( VR::IsASCII( vr ) ) + { + assert( vr & VR::VRASCII ); + const ByteValue *bv = de.GetByteValue(); + if( de.GetVL() ) + { + assert( bv /*|| bv->IsEmpty()*/ ); + retvalue = std::string( bv->GetPointer(), bv->GetLength() ); + // Let's remove any trailing \0 : + retvalue.resize( std::min( retvalue.size(), strlen( retvalue.c_str() ) ) ); // strlen is garantee to be lower or equal to ::size() + } + else + { + //assert( bv == NULL ); + retvalue = ""; // ?? + } + } + else + { + assert( vr & VR::VRBINARY ); + const ByteValue *bv = de.GetByteValue(); + if( bv ) + { + //VM::VMType vm = entry.GetVM();//!!mmr-- can I remove this, or will it mess with the stream? + //assert( vm == VM::VM1 ); + if( vr.IsDual() ) // This mean vr was read from a dict entry: + { + vr = DataSetHelper::ComputeVR(GetFile(),ds, t); + } + std::ostringstream os; + switch(vr) + { + StringFilterCase(AT); + StringFilterCase(FL); + StringFilterCase(FD); + //StringFilterCase(OB); + StringFilterCase(OF); + //StringFilterCase(OW); + StringFilterCase(SL); + //StringFilterCase(SQ); + StringFilterCase(SS); + StringFilterCase(UL); + //StringFilterCase(UN); + StringFilterCase(US); + StringFilterCase(UT); + case VR::UN: + case VR::US_SS: + assert(0); + break; + case VR::OB: + case VR::OW: + case VR::OB_OW: + case VR::SQ: + gdcmWarningMacro( "Unhandled: " << vr << " for tag " << de.GetTag() ); + retvalue = ""; + break; + default: + assert(0); + break; + } + } + } + return true; +} + +std::pair StringFilter::ToStringPair(const Tag& t, DataSet const &ds) const +{ + std::pair ret; + const Global &g = GlobalInstance; + const Dicts &dicts = g.GetDicts(); + if( ds.IsEmpty() || !ds.FindDataElement(t) ) + { + gdcmDebugMacro( "DataSet is empty or does not contains tag:" ); + return ret; + } + const DataElement &de = ds.GetDataElement( t ); + //assert( de.GetTag().IsPublic() ); + std::string strowner; + const char *owner = 0; + if( t.IsPrivate() && !t.IsPrivateCreator() ) + { + strowner = ds.GetPrivateCreator(t); + owner = strowner.c_str(); + } + + const DictEntry &entry = dicts.GetDictEntry(de.GetTag(), owner); + + const VR &vr_read = de.GetVR(); + const VR &vr_dict = entry.GetVR(); + + if( vr_dict == VR::INVALID ) + { + // FIXME This is a public element we do not support... + return ret; + } + + VR vr; + // always prefer the vr from the file: + if( vr_read == VR::INVALID ) + { + vr = vr_dict; + } + else if ( vr_read == VR::UN && vr_dict != VR::INVALID ) // File is explicit, but still prefer vr from dict when UN + { + vr = vr_dict; + } + else // cool the file is Explicit ! + { + vr = vr_read; + } + if( vr.IsDual() ) // This mean vr was read from a dict entry: + { + vr = DataSetHelper::ComputeVR(*F,ds, t); + } + + if( vr == VR::UN ) + { + // this element is not known... + return ret; + } + + assert( vr != VR::UN && vr != VR::INVALID ); + //std::cerr << "Found " << vr << " for " << de.GetTag() << std::endl; + ret.first = entry.GetName(); + if( VR::IsASCII( vr ) ) + { + assert( vr & VR::VRASCII ); + const ByteValue *bv = de.GetByteValue(); + if( de.GetVL() ) + { + assert( bv /*|| bv->IsEmpty()*/ ); + ret.second = std::string( bv->GetPointer(), bv->GetLength() ); + // Let's remove any trailing \0 : + ret.second.resize( std::min( ret.second.size(), strlen( ret.second.c_str() ) ) ); // strlen is garantee to be lower or equal to ::size() + } + else + { + //assert( bv == NULL ); + ret.second = ""; // ?? + } + } + else + { + assert( vr & VR::VRBINARY ); + const ByteValue *bv = de.GetByteValue(); + if( bv ) + { + //VM::VMType vm = entry.GetVM();//!!mmr-- can I remove this, or will it mess with the stream? + //assert( vm == VM::VM1 ); + if( vr.IsDual() ) // This mean vr was read from a dict entry: + { + vr = DataSetHelper::ComputeVR(GetFile(),ds, t); + } + std::ostringstream os; + std::string retvalue; + switch(vr) + { + StringFilterCase(AT); + StringFilterCase(FL); + StringFilterCase(FD); + //StringFilterCase(OB); + StringFilterCase(OF); + //StringFilterCase(OW); + StringFilterCase(SL); + //StringFilterCase(SQ); + StringFilterCase(SS); + StringFilterCase(UL); + //StringFilterCase(UN); + StringFilterCase(US); + StringFilterCase(UT); + case VR::UN: + case VR::US_SS: + assert(0); + break; + case VR::OB: + case VR::OW: + case VR::OB_OW: + case VR::SQ: + gdcmWarningMacro( "Unhandled: " << vr << " for tag " << de.GetTag() ); + ret.second = ""; + break; + default: + assert(0); + break; + } + ret.second = retvalue; + } + } + return ret; +} + +std::string StringFilter::FromString(const Tag&t, const char * value, VL const & vl) +{ + (void)t; + (void)value; + (void)vl; + assert(0 && "TODO"); + return ""; +} + +#define FromStringFilterCase(type) \ + case VR::type: \ + { \ + Element el; \ + /* el.ReadComputeLength( is ); */ \ + el.SetLength( vl ); \ + for(unsigned int i = 0; i < vm.GetLength(); ++i) \ + is >> el.GetValue(i); \ + el.Write(os); \ + } \ + break + +size_t count_backslash(const char *s, size_t len) +{ + size_t c = 0; + for(size_t i = 0; i < len; ++i, ++s) + { + if( *s == '\\' ) + { + ++c; + } + } + return c; +} + +std::string StringFilter::FromString(const Tag&t, const char * value, size_t len) +{ + if( !value || !len ) return ""; + const Global &g = GlobalInstance; + const Dicts &dicts = g.GetDicts(); + std::string strowner; + const char *owner = 0; + const DataSet &ds = GetFile().GetDataSet(); + if( t.IsPrivate() && !t.IsPrivateCreator() ) + { + strowner = ds.GetPrivateCreator(t); + owner = strowner.c_str(); + } + + const DictEntry &entry = dicts.GetDictEntry(t, owner); + const VM &vm = entry.GetVM(); + //const VR &vr = entry.GetVR(); + const DataElement &de = ds.GetDataElement( t ); + const VR &vr_read = de.GetVR(); + const VR &vr_dict = entry.GetVR(); + + VR vr; + // always prefer the vr from the file: + if( vr_read == VR::INVALID ) + { + vr = vr_dict; + } + else if ( vr_read == VR::UN && vr_dict != VR::INVALID ) // File is explicit, but still prefer vr from dict when UN + { + vr = vr_dict; + } + else // cool the file is Explicit ! + { + vr = vr_read; + } + if( vr.IsDual() ) // This mean vr was read from a dict entry: + { + vr = DataSetHelper::ComputeVR(*F,ds, t); + } + + if( vr == VR::UN ) + { + // this element is not known... + //return ret; + } + + std::string s(value,value+len); + if( VR::IsASCII( vr ) ) + { + return s; + } + VL::Type castLen = (VL::Type)len; + VL::Type count = VM::GetNumberOfElementsFromArray(value, castLen); + VL vl = vm.GetLength() * vr.GetSizeof(); + if( vm.GetLength() == 0 ) + { + // VM1_n + vl = count * vr.GetSizeof(); +#if !defined(NDEBUG) + VM check = VM::GetVMTypeFromLength(count, 1); + assert( vm.Compatible( check ) ); +#endif + } + + //if( vl != vm.GetLength() * vr.GetSizeof() ) + // { + // assert(0); + // } + + std::istringstream is; + is.str( s ); + std::ostringstream os; + switch(vr) + { + FromStringFilterCase(AT); + FromStringFilterCase(FL); + FromStringFilterCase(FD); + //FromStringFilterCase(OB); + FromStringFilterCase(OF); + //FromStringFilterCase(OW); + FromStringFilterCase(SL); + //FromStringFilterCase(SQ); + FromStringFilterCase(SS); + FromStringFilterCase(UL); + //FromStringFilterCase(UN); + FromStringFilterCase(US); + FromStringFilterCase(UT); + default: + gdcmErrorMacro( "Not implemented" ); + assert(0); + } + return os.str(); +} + +} diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmStringFilter.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmStringFilter.h new file mode 100644 index 0000000..8275f2e --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmStringFilter.h @@ -0,0 +1,80 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMSTRINGFILTER_H +#define GDCMSTRINGFILTER_H + +#include "gdcmDataElement.h" +#include "gdcmDicts.h" +#include "gdcmFile.h" + +namespace gdcm +{ + +/** + * \brief StringFilter + * StringFilter is the class that make gdcm2.x looks more like gdcm1 and transform the binary blob + * contained in a DataElement into a string, typically this is a nice feature to have for wrapped language + */ +class GDCM_EXPORT StringFilter +{ +public: + StringFilter(); + ~StringFilter(); + + /// + void UseDictAlways(bool ) {} + + /// Allow user to pass in there own dicts + void SetDicts(const Dicts &dicts); + + /// Convert to string the ByteValue contained in a DataElement + std::string ToString(const Tag& t) const; + + //std::string ToMime64(const Tag& t) const; + + /// Convert to string the ByteValue contained in a DataElement + /// the returned elements are: + /// pair.first : the name as found in the dictionary of DataElement + /// pari.second : the value encoded into a string (US,UL...) are properly converted + std::pair ToStringPair(const Tag& t) const; + + /// DEPRECATED: NEVER USE IT + std::string FromString(const Tag&t, const char * value, VL const & vl); + + // Use this one + std::string FromString(const Tag&t, const char * value, size_t len); + + //typedef std::map StringSet; + + /// Set/Get File + void SetFile(const File& f) { F = f; } + File &GetFile() { return *F; } + const File &GetFile() const { return *F; } + + /// Execute the XPATH query to find a value (as string) + /// return false when attribute is not found (or an error in the XPATH query) + /// You need to make sure that your XPATH query is syntatically correct + bool ExecuteQuery(std::string const &query, std::string & value) const; + +protected: + std::pair ToStringPair(const Tag& t, DataSet const &ds) const; + bool ExecuteQuery(std::string const &query, DataSet const &ds, std::string & value) const; + +private: + SmartPointer F; +}; + +} // end namespace gdcm + +#endif //GDCMSTRINGFILTER_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmSurface.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmSurface.cxx new file mode 100644 index 0000000..a248e8d --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmSurface.cxx @@ -0,0 +1,533 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmSurface.h" +#include "gdcmCodeString.h" +#include "gdcmString.h" + +#include + + +namespace gdcm +{ +static const char * STATESStrings[] = { + "NO", + "YES", + "UNKNOWN", + + 0 +}; + +const char * Surface::GetSTATESString(STATES state) +{ + assert( state <= STATES_END ); + return STATESStrings[(int)state]; +} + +Surface::STATES Surface::GetSTATES(const char * state) +{ + if(!state) return STATES_END; + + // Delete possible space as last character + String<> str( state ); + str.Trim(); + const char * stateClear = str.Trim().c_str(); + + for(unsigned int i = 0; STATESStrings[i] != 0; ++i) + { + if( strcmp(stateClear, STATESStrings[i]) == 0 ) + { + return (STATES)i; + } + } + // Ouch ! We did not find anything, that's pretty bad, let's hope that + // the toolkit which wrote the image is buggy and tolerate space padded binary + // string + CodeString codestring = stateClear; + std::string cs = codestring.GetAsString(); + for(unsigned int i = 0; STATESStrings[i] != 0; ++i) + { + if( strcmp(cs.c_str(), STATESStrings[i]) == 0 ) + { + return (STATES)i; + } + } + + return STATES_END; +} + +static const char * VIEWStrings[] = { + "SURFACE", + "WIREFRAME", + "POINTS", + + 0 +}; + +const char * Surface::GetVIEWTypeString(VIEWType type) +{ + assert( type <= VIEWType_END ); + return VIEWStrings[(int)type]; +} + +Surface::VIEWType Surface::GetVIEWType(const char * type) +{ + if(!type) return VIEWType_END; + + // Delete possible space as last character + String<> str( type ); + str.Trim(); + const char * typeClear = str.Trim().c_str(); + + for(unsigned int i = 0; VIEWStrings[i] != 0; ++i) + { + if( strcmp(typeClear, VIEWStrings[i]) == 0 ) + { + return (VIEWType)i; + } + } + // Ouch ! We did not find anything, that's pretty bad, let's hope that + // the toolkit which wrote the image is buggy and tolerate space padded binary + // string + CodeString codestring = typeClear; + std::string cs = codestring.GetAsString(); + for(unsigned int i = 0; VIEWStrings[i] != 0; ++i) + { + if( strcmp(cs.c_str(), VIEWStrings[i]) == 0 ) + { + return (VIEWType)i; + } + } + + return VIEWType_END; +} + +Surface::Surface(): + SurfaceNumber(0), + SurfaceComments(""), + SurfaceProcessing(false), + SurfaceProcessingRatio(1.), + SurfaceProcessingDescription(""), + ProcessingAlgorithm(), + RecommendedDisplayGrayscaleValue(0), + RecommendedPresentationOpacity(1), + RecommendedPresentationType(SURFACE), + FiniteVolume(UNKNOWN), + Manifold(UNKNOWN), + AlgorithmFamily(), + AlgorithmVersion(""), + AlgorithmName(""), + NumberOfSurfacePoints(0), + PointCoordinatesData(), + PointPositionAccuracy(0), + MeanPointDistance(0), + MaximumPointDistance(0), + PointsBoundingBoxCoordinates(0), + AxisOfRotation(0), + CenterOfRotation(0), + NumberOfVectors(0), + VectorDimensionality(0), + VectorAccuracy(0), + VectorCoordinateData(), + Primitive(new MeshPrimitive) +{ + RecommendedDisplayCIELabValue[0] = 0; + RecommendedDisplayCIELabValue[1] = 0; + RecommendedDisplayCIELabValue[2] = 0; +} + +Surface::~Surface() +{ + if (PointPositionAccuracy != 0) delete PointPositionAccuracy; + if (PointsBoundingBoxCoordinates != 0) delete PointsBoundingBoxCoordinates; + if (AxisOfRotation != 0) delete AxisOfRotation; + if (CenterOfRotation != 0) delete CenterOfRotation; + + if (VectorAccuracy != 0) delete VectorAccuracy; +} + +unsigned short Surface::GetRecommendedDisplayGrayscaleValue() const +{ + return RecommendedDisplayGrayscaleValue; +} + +void Surface::SetRecommendedDisplayGrayscaleValue(const unsigned short vl) +{ + RecommendedDisplayGrayscaleValue = vl; +} + +const unsigned short * Surface::GetRecommendedDisplayCIELabValue() const +{ + return &RecommendedDisplayCIELabValue[0]; +} + +unsigned short Surface::GetRecommendedDisplayCIELabValue(const unsigned int idx) const +{ + assert( idx < 3 ); + return RecommendedDisplayCIELabValue[idx]; +} + +void Surface::SetRecommendedDisplayCIELabValue(const unsigned short vl[3]) +{ + RecommendedDisplayCIELabValue[0] = vl[0]; + RecommendedDisplayCIELabValue[1] = vl[1]; + RecommendedDisplayCIELabValue[2] = vl[2]; +} + +void Surface::SetRecommendedDisplayCIELabValue(const unsigned short vl, const unsigned int idx/* = 0*/) +{ + assert( idx < 3 ); + RecommendedDisplayCIELabValue[idx] = vl; +} + +void Surface::SetRecommendedDisplayCIELabValue(const std::vector< unsigned short > & vl) +{ + assert( vl.size() > 2 ); + + RecommendedDisplayCIELabValue[0] = vl[0]; + RecommendedDisplayCIELabValue[1] = vl[1]; + RecommendedDisplayCIELabValue[2] = vl[2]; +} + +float Surface::GetRecommendedPresentationOpacity() const +{ + return RecommendedPresentationOpacity; +} + +void Surface::SetRecommendedPresentationOpacity(float opacity) +{ + if( (0 <= opacity) && (opacity <= 1) ) + { + RecommendedPresentationOpacity = opacity; + } + //else keep default value : 1 +} + +Surface::VIEWType Surface::GetRecommendedPresentationType() const +{ + return RecommendedPresentationType; +} + +void Surface::SetRecommendedPresentationType(VIEWType type) +{ + if( type < VIEWType_END) + { + RecommendedPresentationType = type; + } +} + +unsigned long Surface::GetSurfaceNumber() const +{ + return SurfaceNumber; +} + +void Surface::SetSurfaceNumber(const unsigned long nb) +{ + SurfaceNumber = nb; +} + +const char * Surface::GetSurfaceComments() const +{ + return SurfaceComments.c_str(); +} + +void Surface::SetSurfaceComments(const char * comment) +{ + SurfaceComments = comment; +} + +bool Surface::GetSurfaceProcessing() const +{ + return SurfaceProcessing; +} + +void Surface::SetSurfaceProcessing(bool b) +{ + SurfaceProcessing = b; +} + +float Surface::GetSurfaceProcessingRatio() const +{ + return SurfaceProcessingRatio; +} + +void Surface::SetSurfaceProcessingRatio(const float ratio) +{ + SurfaceProcessingRatio = ratio; +} + +const char * Surface::GetSurfaceProcessingDescription() const +{ + return SurfaceProcessingDescription.c_str(); +} + +void Surface::SetSurfaceProcessingDescription(const char * description) +{ + SurfaceProcessingDescription = description; +} + +SegmentHelper::BasicCodedEntry const & Surface::GetProcessingAlgorithm() const +{ + return ProcessingAlgorithm; +} + +SegmentHelper::BasicCodedEntry & Surface::GetProcessingAlgorithm() +{ + return ProcessingAlgorithm; +} + +void Surface::SetProcessingAlgorithm(SegmentHelper::BasicCodedEntry const & BSE) +{ + ProcessingAlgorithm.CV = BSE.CV; + ProcessingAlgorithm.CSD = BSE.CSD; + ProcessingAlgorithm.CM = BSE.CM; +} + +Surface::STATES Surface::GetFiniteVolume() const +{ + return FiniteVolume; +} + +void Surface::SetFiniteVolume(STATES state) +{ + assert( state < STATES_END ); + FiniteVolume = state; +} + +Surface::STATES Surface::GetManifold() const +{ + return Manifold; +} + +void Surface::SetManifold(STATES state) +{ + assert( state < STATES_END ); + Manifold = state; +} + +SegmentHelper::BasicCodedEntry const & Surface::GetAlgorithmFamily() const +{ + return AlgorithmFamily; +} + +SegmentHelper::BasicCodedEntry & Surface::GetAlgorithmFamily() +{ + return AlgorithmFamily; +} + +void Surface::SetAlgorithmFamily(SegmentHelper::BasicCodedEntry const & BSE) +{ + AlgorithmFamily.CV = BSE.CV; + AlgorithmFamily.CSD = BSE.CSD; + AlgorithmFamily.CM = BSE.CM; +} + +const char * Surface::GetAlgorithmVersion() const +{ + return AlgorithmVersion.c_str(); +} + +void Surface::SetAlgorithmVersion(const char * str) +{ + AlgorithmVersion = str; +} + +const char * Surface::GetAlgorithmName() const +{ + return AlgorithmName.c_str(); +} + +void Surface::SetAlgorithmName(const char * str) +{ + AlgorithmName = str; +} + +unsigned long Surface::GetNumberOfSurfacePoints() const +{ + return NumberOfSurfacePoints; +} + +void Surface::SetNumberOfSurfacePoints(const unsigned long nb) +{ + NumberOfSurfacePoints = nb; +} + +const DataElement & Surface::GetPointCoordinatesData() const +{ + return PointCoordinatesData; +} + +DataElement & Surface::GetPointCoordinatesData() +{ + return PointCoordinatesData; +} + +void Surface::SetPointCoordinatesData(DataElement const & de) +{ + PointCoordinatesData = de; +} + + +const float * Surface::GetPointPositionAccuracy() const +{ + return PointPositionAccuracy; +} + +void Surface::SetPointPositionAccuracy(const float * accuracies) +{ + assert(accuracies); + + if (PointPositionAccuracy == 0) PointPositionAccuracy = new float[3]; + + PointPositionAccuracy[0] = accuracies[0]; + PointPositionAccuracy[1] = accuracies[1]; + PointPositionAccuracy[2] = accuracies[2]; +} + +float Surface::GetMeanPointDistance() const +{ + return MeanPointDistance; +} + +void Surface::SetMeanPointDistance(float average) +{ + MeanPointDistance = average; +} + +float Surface::GetMaximumPointDistance() const +{ + return MaximumPointDistance; +} + +void Surface::SetMaximumPointDistance(float maximum) +{ + MaximumPointDistance = maximum; +} + +const float * Surface::GetPointsBoundingBoxCoordinates() const +{ + return PointsBoundingBoxCoordinates; +} + +void Surface::SetPointsBoundingBoxCoordinates(const float * coordinates) +{ + assert(coordinates); + + if (PointsBoundingBoxCoordinates == 0) PointsBoundingBoxCoordinates = new float[6]; + + PointsBoundingBoxCoordinates[0] = coordinates[0]; + PointsBoundingBoxCoordinates[1] = coordinates[1]; + PointsBoundingBoxCoordinates[2] = coordinates[2]; + PointsBoundingBoxCoordinates[3] = coordinates[3]; + PointsBoundingBoxCoordinates[4] = coordinates[4]; + PointsBoundingBoxCoordinates[5] = coordinates[5]; +} + +const float * Surface::GetAxisOfRotation() const +{ + return AxisOfRotation; +} + +void Surface::SetAxisOfRotation(const float * axis) +{ + assert(axis); + + if (AxisOfRotation == 0) AxisOfRotation = new float[3]; + + AxisOfRotation[0] = axis[0]; + AxisOfRotation[1] = axis[1]; + AxisOfRotation[2] = axis[2]; +} + +const float * Surface::GetCenterOfRotation() const +{ + return CenterOfRotation; +} + +void Surface::SetCenterOfRotation(const float * center) +{ + assert(center); + + if (CenterOfRotation == 0) CenterOfRotation = new float[3]; + + CenterOfRotation[0] = center[0]; + CenterOfRotation[1] = center[1]; + CenterOfRotation[2] = center[2]; +} + +unsigned long Surface::GetNumberOfVectors() const +{ + return NumberOfVectors; +} + +void Surface::SetNumberOfVectors(const unsigned long nb) +{ + NumberOfVectors = nb; +} + +unsigned short Surface::GetVectorDimensionality() const +{ + return VectorDimensionality; +} + +void Surface::SetVectorDimensionality(const unsigned short dim) +{ + VectorDimensionality = dim; +} + +const float * Surface::GetVectorAccuracy() const +{ + return VectorAccuracy; +} + +void Surface::SetVectorAccuracy(const float * accuracy) +{ + assert(accuracy); + + if (VectorAccuracy == 0) VectorAccuracy = new float[ VectorDimensionality ]; + + for (unsigned int i = 0; i < VectorDimensionality; ++i) + VectorAccuracy[i] = accuracy[i]; +} + +const DataElement & Surface::GetVectorCoordinateData() const +{ + return VectorCoordinateData; +} + +DataElement & Surface::GetVectorCoordinateData() +{ + return VectorCoordinateData; +} + +void Surface::SetVectorCoordinateData(DataElement const & de) +{ + VectorCoordinateData = de; +} + +MeshPrimitive const & Surface::GetMeshPrimitive() const +{ + return *Primitive; +} + +MeshPrimitive & Surface::GetMeshPrimitive() +{ + return *Primitive; +} + +void Surface::SetMeshPrimitive(MeshPrimitive & mp) +{ + Primitive = mp; +} + +} diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmSurface.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmSurface.h new file mode 100644 index 0000000..786d113 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmSurface.h @@ -0,0 +1,256 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMSURFACE_H +#define GDCMSURFACE_H + +#include +#include +#include +#include "gdcmSegmentHelper.h" // for BasicCodedEntry + +namespace gdcm +{ + +/** + * \brief This class defines a SURFACE IE. + * This members are taken from required surface mesh module attributes. + * + * \see PS 3.3 A.1.2.18 , A.57 and C.27 + */ +class GDCM_EXPORT Surface : public Object +{ +public: + + typedef enum { + NO = 0, + YES, + UNKNOWN, + STATES_END + } STATES; + + static const char * GetSTATESString(STATES state); + static STATES GetSTATES(const char * state); + + /** + * \brief Enumeration for Recommended Presentation Type + * + * \see Tag(0x0066, 0x000D) and PS 3.3 C.27.1.1.3 + */ + typedef enum { + SURFACE = 0, + WIREFRAME, + POINTS, + VIEWType_END + } VIEWType; + + static const char * GetVIEWTypeString(VIEWType type); + static VIEWType GetVIEWType(const char * type); + + Surface(); + + virtual ~Surface(); + + //** Common getters/setters **// + unsigned long GetSurfaceNumber() const; + void SetSurfaceNumber(const unsigned long nb); + + const char * GetSurfaceComments() const; + void SetSurfaceComments(const char * comment); + + bool GetSurfaceProcessing() const; + void SetSurfaceProcessing(bool b); + + float GetSurfaceProcessingRatio() const; + void SetSurfaceProcessingRatio(const float ratio); + + const char * GetSurfaceProcessingDescription() const; + void SetSurfaceProcessingDescription(const char * description); + + SegmentHelper::BasicCodedEntry const & GetProcessingAlgorithm() const; + SegmentHelper::BasicCodedEntry & GetProcessingAlgorithm(); + void SetProcessingAlgorithm(SegmentHelper::BasicCodedEntry const & BSE); + + unsigned short GetRecommendedDisplayGrayscaleValue() const; + void SetRecommendedDisplayGrayscaleValue(const unsigned short vl); + + const unsigned short * GetRecommendedDisplayCIELabValue() const; + unsigned short GetRecommendedDisplayCIELabValue(const unsigned int idx) const; + void SetRecommendedDisplayCIELabValue(const unsigned short vl[3]); + void SetRecommendedDisplayCIELabValue(const unsigned short vl, const unsigned int idx = 0); + void SetRecommendedDisplayCIELabValue(const std::vector< unsigned short > & vl); + + float GetRecommendedPresentationOpacity() const; + void SetRecommendedPresentationOpacity(const float opacity); + + VIEWType GetRecommendedPresentationType() const; + void SetRecommendedPresentationType(VIEWType type); + + STATES GetFiniteVolume() const; + void SetFiniteVolume(STATES state); + + STATES GetManifold() const; + void SetManifold(STATES state); + + SegmentHelper::BasicCodedEntry const & GetAlgorithmFamily() const; + SegmentHelper::BasicCodedEntry & GetAlgorithmFamily(); + void SetAlgorithmFamily(SegmentHelper::BasicCodedEntry const & BSE); + + const char * GetAlgorithmVersion() const; + void SetAlgorithmVersion(const char * str); + + const char * GetAlgorithmName() const; + void SetAlgorithmName(const char * str); + + //** Points getters/setters **// + unsigned long GetNumberOfSurfacePoints() const; + void SetNumberOfSurfacePoints(const unsigned long nb); + + const DataElement & GetPointCoordinatesData() const; + DataElement & GetPointCoordinatesData(); + + void SetPointCoordinatesData(DataElement const & de); + + /** + * \note Pointer is null if undefined + */ + const float * GetPointPositionAccuracy() const; + void SetPointPositionAccuracy(const float * accuracies); + + float GetMeanPointDistance() const; + void SetMeanPointDistance(float average); + + float GetMaximumPointDistance() const; + void SetMaximumPointDistance(float maximum); + + /** + * \note Pointer is null if undefined + */ + const float * GetPointsBoundingBoxCoordinates() const; + void SetPointsBoundingBoxCoordinates(const float * coordinates); + + /** + * \note Pointer is null if undefined + */ + const float * GetAxisOfRotation() const; + void SetAxisOfRotation(const float * axis); + + /** + * \note Pointer is null if undefined + */ + const float * GetCenterOfRotation() const; + void SetCenterOfRotation(const float * center); + + //** Vectors getters/setters **// + unsigned long GetNumberOfVectors() const; + void SetNumberOfVectors(const unsigned long nb); + + unsigned short GetVectorDimensionality() const; + void SetVectorDimensionality(const unsigned short dim); + + const float * GetVectorAccuracy() const; + void SetVectorAccuracy(const float * accuracy); + + const DataElement & GetVectorCoordinateData() const; + DataElement & GetVectorCoordinateData(); + + void SetVectorCoordinateData(DataElement const & de); + + //** Primitive getters/setters **// + MeshPrimitive const & GetMeshPrimitive() const; + MeshPrimitive & GetMeshPrimitive(); + + void SetMeshPrimitive(MeshPrimitive & mp); + +private: + + //** Common members **// + + //0066 0003 UL 1 Surface Number + unsigned long SurfaceNumber; + //0066 0004 LT 1 Surface Comments + std::string SurfaceComments; + + //0066 0009 CS 1 Surface Processing + bool SurfaceProcessing; + //0066 000a FL 1 Surface Processing Ratio + float SurfaceProcessingRatio; + //0066 000b LO 1 Surface Processing Description + std::string SurfaceProcessingDescription; + // Processing Algorithm Code + SegmentHelper::BasicCodedEntry ProcessingAlgorithm; + + //0062 000c US 1 Recommended Display Grayscale Value + unsigned short RecommendedDisplayGrayscaleValue; + //0062 000d US 3 Recommended Display CIELab Value + unsigned short RecommendedDisplayCIELabValue[3]; + + // 0066 000c FL 1 Recommended Presentation Opacity + float RecommendedPresentationOpacity; + // 0066 000d CS 1 Recommended Presentation Type + VIEWType RecommendedPresentationType; + + //0066 000e CS 1 Finite Volume + STATES FiniteVolume; + //0066 0010 CS 1 Manifold + STATES Manifold; + + // Algorithm Family Code + SegmentHelper::BasicCodedEntry AlgorithmFamily; + + //0066 0031 LO 1 Algorithm Version + std::string AlgorithmVersion; + //0066 0032 LT 1 Algorithm Parameters + //0066 0036 LO 1 Algorithm Name + std::string AlgorithmName; + + + //** Point members **// + + //0066 0015 UL 1 Number of Surface Points + unsigned long NumberOfSurfacePoints; + //0066 0016 OF 1 Point Coordinates Data + DataElement PointCoordinatesData; + //0066 0017 FL 3 Point Position Accuracy + float * PointPositionAccuracy; + //0066 0018 FL 1 Mean Point Distance + float MeanPointDistance; + //0066 0019 FL 1 Maximum Point Distance + float MaximumPointDistance; + //0066 001a FL 6 Points Bounding Box Coordinates + float * PointsBoundingBoxCoordinates; + //0066 001b FL 3 Axis of Rotation + float * AxisOfRotation; + //0066 001c FL 3 Center of Rotation + float * CenterOfRotation; + + + //** Normal members **// + + //0066 001e UL 1 Number of Vectors + unsigned long NumberOfVectors; + //0066 001f US 1 Vector Dimensionality + unsigned short VectorDimensionality; + //0066 0020 FL 1-n Vector Accuracy + float * VectorAccuracy; + //0066 0021 OF 1 Vector Coordinate Data + DataElement VectorCoordinateData; + + + //** Primitive members **// + SmartPointer< MeshPrimitive > Primitive; +}; + +} + +#endif // GDCMSURFACE_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmSurfaceHelper.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmSurfaceHelper.cxx new file mode 100644 index 0000000..1844f2f --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmSurfaceHelper.cxx @@ -0,0 +1,139 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmSurfaceHelper.h" + +#include + +namespace gdcm +{ + +std::vector< float > SurfaceHelper::RGBToXYZ(const std::vector & RGB) +{ + std::vector< float > XYZ(3); + float tmp[3]; + + tmp[0] = RGB[0]; + tmp[1] = RGB[1]; + tmp[2] = RGB[2]; + + const float A = (float)(1. / 12.92); + const float B = (float)(1. / 1.055); + + if ( tmp[0] > 0.04045 ) tmp[0] = powf( (float)( ( tmp[0] + 0.055 ) * B ), 2.4f); + else tmp[0] *= A; + if ( tmp[1] > 0.04045 ) tmp[1] = powf( (float)( ( tmp[1] + 0.055 ) * B ), 2.4f); + else tmp[1] *= A; + if ( tmp[2] > 0.04045 ) tmp[2] = powf( (float)( ( tmp[2] + 0.055 ) * B ), 2.4f); + else tmp[2] *= A; + + tmp[0] *= 100; + tmp[1] *= 100; + tmp[2] *= 100; + + //Observer. = 2°, Illuminant = D65 + XYZ[0] = (float)(tmp[0] * 0.4124 + tmp[1] * 0.3576 + tmp[2] * 0.1805); + XYZ[1] = (float)(tmp[0] * 0.2126 + tmp[1] * 0.7152 + tmp[2] * 0.0722); + XYZ[2] = (float)(tmp[0] * 0.0193 + tmp[1] * 0.1192 + tmp[2] * 0.9505); + + return XYZ; +} + +std::vector< float > SurfaceHelper::XYZToRGB(const std::vector & XYZ) +{ + std::vector< float > RGB(3); + float tmp[3]; + + tmp[0] = XYZ[0]; + tmp[1] = XYZ[1]; + tmp[2] = XYZ[2]; + + // Divide by 100 + tmp[0] *= 0.01f; //X from 0 to 95.047 (Observer = 2°, Illuminant = D65) + tmp[1] *= 0.01f; //Y from 0 to 100.000 + tmp[2] *= 0.01f; //Z from 0 to 108.883 + + RGB[0] = (float)(tmp[0] * 3.2406 + tmp[1] * -1.5372 + tmp[2] * -0.4986); + RGB[1] = (float)(tmp[0] * -0.9689 + tmp[1] * 1.8758 + tmp[2] * 0.0415); + RGB[2] = (float)(tmp[0] * 0.0557 + tmp[1] * -0.2040 + tmp[2] * 1.0570); + + const float A = (float)(1. / 2.4); + + if ( RGB[0] > 0.0031308 ) RGB[0] = 1.055f * powf( RGB[0], A) - 0.055f; + else RGB[0] *= 12.92f; + if ( RGB[1] > 0.0031308 ) RGB[1] = 1.055f * powf( RGB[1], A) - 0.055f; + else RGB[1] *= 12.92f; + if ( RGB[2] > 0.0031308 ) RGB[2] = 1.055f * powf( RGB[2], A) - 0.055f; + else RGB[2] *= 12.92f; + + return RGB; +} + +std::vector< float > SurfaceHelper::XYZToCIELab(const std::vector & XYZ) +{ + std::vector< float > CIELab(3); + float tmp[3]; + + tmp[0] = (float)(XYZ[0] / 95.047); //ref_X = 95.047 Observer= 2°, Illuminant= D65 + tmp[1] = (float)(XYZ[1] * 0.01); //ref_Y = 100.000 + tmp[2] = (float)(XYZ[2] / 108.883); //ref_Z = 108.883 + + const float A = (float)(1. / 3.); + const float B = (float)(16. / 116.); + + if ( tmp[0] > 0.008856 ) tmp[0] = powf(tmp[0], A); + else tmp[0] = (float)(7.787 * tmp[0] + B); + if ( tmp[1] > 0.008856 ) tmp[1] = powf(tmp[1], A); + else tmp[1] = (float)(7.787 * tmp[1] + B); + if ( tmp[2] > 0.008856 ) tmp[2] = powf(tmp[2], A); + else tmp[2] = (float)(7.787 * tmp[2] + B); + + CIELab[0] = ( 116 * tmp[1] ) - 16; + CIELab[1] = 500 * ( tmp[0] - tmp[1] ); + CIELab[2] = 200 * ( tmp[1] - tmp[2] ); + + return CIELab; +} + +std::vector< float > SurfaceHelper::CIELabToXYZ(const std::vector & CIELab) +{ + std::vector< float > XYZ(3); + float tmp[3]; + + tmp[1] = (float)(( CIELab[0] + 16 ) / 116.); + tmp[0] = (float)(CIELab[1] * 0.002 + tmp[1]); + tmp[2] = (float)(tmp[1] - CIELab[2] * 0.005); + + // Compute t + const float A = tmp[0]*tmp[0]*tmp[0]; + const float B = tmp[1]*tmp[1]*tmp[1]; + const float C = tmp[2]*tmp[2]*tmp[2]; + + const float D = (float)(16. / 116.); + + // Compute f(t) + if ( B > 0.008856f) tmp[1] = B; + else tmp[1] = (float)(( tmp[1] - D ) / 7.787); + if ( A > 0.008856f) tmp[0] = A; + else tmp[0] = (float)(( tmp[0] - D ) / 7.787); + if ( C > 0.008856f) tmp[2] = C; + else tmp[2] = (float)(( tmp[2] - D ) / 7.787); + + XYZ[0] = (float)(tmp[0] * 95.047); //ref_X = 95.047 Observer= 2°, Illuminant= D65 + XYZ[1] = (float)(tmp[1] * 100.); //ref_Y = 100.000 + XYZ[2] = (float)(tmp[2] * 108.883); //ref_Z = 108.883 + + return XYZ; +} + +} diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmSurfaceHelper.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmSurfaceHelper.h new file mode 100644 index 0000000..ca375f8 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmSurfaceHelper.h @@ -0,0 +1,208 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMSURFACEHELPER_H +#define GDCMSURFACEHELPER_H + +#include "gdcmTypes.h" // for GDCM_EXPORT + +#include +#include + +namespace gdcm +{ + +/** + * \brief SurfaceHelper + * Helper class for Surface object + */ +class GDCM_EXPORT SurfaceHelper +{ +public: + + typedef std::vector< unsigned short > ColorArray; + + /** + * \brief Convert a RGB color into DICOM grayscale (ready to write). + * + * \see PS 3.3 C.27.1 tag(0062,000C) + * + * \param RGB RGB array. + * \param rangeMax Max value of the RGB range. + * + * \tparam T Type of RGB components. + * \tparam U Type of rangeMax value. + */ + template + static unsigned short RGBToRecommendedDisplayGrayscale(const std::vector & RGB, + const U rangeMax = 255); + /** + * \brief Convert a RGB color into DICOM CIE-Lab (ready to write). + * + * \see PS 3.3 C.10.7.1.1 + * + * \param RGB RGB array. + * \param rangeMax Max value of the RGB range. + * + * \tparam T Type of RGB components. + * \tparam U Type of rangeMax value. + */ + template + static ColorArray RGBToRecommendedDisplayCIELab(const std::vector & RGB, + const U rangeMax = 255); + /** + * \brief Convert a DICOM CIE-Lab (after reading) color into RGB. + * + * \see PS 3.3 C.10.7.1.1 + * + * \param CIELab DICOM CIE-Lab array. + * \param rangeMax Max value of the RGB range. + * + * \tparam T Type of CIELab components. + * \tparam U Type of rangeMax value. + */ + template + static std::vector RecommendedDisplayCIELabToRGB(const ColorArray & CIELab, + const U rangeMax = 255); + /** + * \brief Convert a DICOM CIE-Lab (after reading) color into RGB. + * + * \see PS 3.3 C.10.7.1.1 + * + * \param CIELab DICOM CIE-Lab array. + * \param rangeMax Max value of the RGB range. + * + * \tparam U Type of rangeMax value. + */ + template + static std::vector RecommendedDisplayCIELabToRGB(const ColorArray & CIELab, + const U rangeMax = 255); + +private: + + static std::vector< float > RGBToXYZ(const std::vector & RGB); + + static std::vector< float > XYZToRGB(const std::vector & XYZ); + + static std::vector< float > XYZToCIELab(const std::vector & XYZ); + + static std::vector< float > CIELabToXYZ(const std::vector & CIELab); +}; + +template +unsigned short SurfaceHelper::RGBToRecommendedDisplayGrayscale(const std::vector & RGB, + const U rangeMax/* = 255*/) +{ + assert(RGB.size() > 2); + + unsigned short Grayscale = 0; + + const float inverseRangeMax = 1. / (float) rangeMax; + + // 0xFFFF "=" 255 "=" white + Grayscale = (unsigned short) ((0.2989 * RGB[0] + 0.5870 * RGB[1] + 0.1140 * RGB[2]) + * inverseRangeMax // Convert to range 0-1 + * 0xFFFF); // Convert to range 0x0000-0xFFFF + + return Grayscale; +} + +template +SurfaceHelper::ColorArray SurfaceHelper::RGBToRecommendedDisplayCIELab(const std::vector & RGB, + const U rangeMax/* = 255*/) +{ + assert(RGB.size() > 2); + + ColorArray CIELab(3); + std::vector tmp(3); + + // Convert to range 0-1 + const float inverseRangeMax = 1. / (float) rangeMax; + tmp[0] = (float) (RGB[0] * inverseRangeMax); + tmp[1] = (float) (RGB[1] * inverseRangeMax); + tmp[2] = (float) (RGB[2] * inverseRangeMax); + + tmp = SurfaceHelper::XYZToCIELab( SurfaceHelper::RGBToXYZ( tmp ) ); + + // Convert to range 0x0000-0xFFFF + // 0xFFFF "=" 127, 0x8080 "=" 0, 0x0000 "=" -128 + CIELab[0] = (unsigned short) ( 0xFFFF * (tmp[0]*0.01)); + if(tmp[1] >= -128 && tmp[1] <= 0) + { + CIELab[1] = (unsigned short)(((float)(0x8080)/128.0)*tmp[1] + ((float)0x8080)); + } + else if(tmp[1] <= 127 && tmp[1] > 0) + { + CIELab[1] = (unsigned short)(((float)(0xFFFF - 0x8080)/127.0)*tmp[1] + (float)(0x8080)); + } + if(tmp[2] >= -128 && tmp[2] <= 0) + { + CIELab[2] = (unsigned short)(((float)0x8080/128.0)*tmp[2] + ((float)0x8080)); + } + else if(tmp[2] <= 127 && tmp[2] > 0) + { + CIELab[2] = (unsigned short)(((float)(0xFFFF - 0x8080)/127.0)*tmp[2] + (float)(0x8080)); + } + + return CIELab; +} + +template +std::vector SurfaceHelper::RecommendedDisplayCIELabToRGB(const ColorArray & CIELab, + const U rangeMax/* = 255*/) +{ + assert(CIELab.size() > 2); + + std::vector RGB(3); + std::vector tmp(3); + + // Convert to range 0-1 + + tmp[0] = 100.0*CIELab[0] /(float)(0xFFFF); + if(CIELab[1] >= 0x0000 && CIELab[1] <= 0x8080) + { + tmp[1] = (float)(((CIELab[1] - 0x8080) * 128.0)/(float)0x8080); + } + else if(CIELab[1] <= 0xFFFF && CIELab[1] > 0x8080) + { + tmp[1] = (float)((CIELab[1]-0x8080)*127.0 / (float)(0xFFFF - 0x8080)); + } + if(CIELab[2] >= 0x0000 && CIELab[2] <= 0x8080) + { + tmp[2] = (float)(((CIELab[2] - 0x8080) * 128.0)/(float)0x8080); + } + else if(CIELab[2] <= 0xFFFF && CIELab[2] > 0x8080) + { + tmp[2] = (float)((CIELab[2]-0x8080)*127.0 / (float)(0XFFFF - 0x8080)); + } + + tmp = SurfaceHelper::XYZToRGB( SurfaceHelper::CIELabToXYZ( tmp ) ); + + // Convert to range 0-rangeMax + RGB[0] = (T) (tmp[0] * rangeMax); + RGB[1] = (T) (tmp[1] * rangeMax); + RGB[2] = (T) (tmp[2] * rangeMax); + + return RGB; +} + +template +std::vector SurfaceHelper::RecommendedDisplayCIELabToRGB(const ColorArray & CIELab, + const U rangeMax/* = 255*/) +{ + return RecommendedDisplayCIELabToRGB(CIELab, rangeMax); +} + +} // end namespace gdcm + +#endif // GDCMSURFACEHELPER_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmSurfaceReader.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmSurfaceReader.cxx new file mode 100644 index 0000000..b7621f0 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmSurfaceReader.cxx @@ -0,0 +1,597 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmSurfaceReader.h" +#include "gdcmMediaStorage.h" +#include "gdcmAttribute.h" +#include "gdcmString.h" + +namespace gdcm +{ + +SurfaceReader::SurfaceReader() +{ +} + +SurfaceReader::~SurfaceReader() +{ +} + +unsigned long SurfaceReader::GetNumberOfSurfaces() const +{ + return Segments.size(); +} + +bool SurfaceReader::Read() +{ + bool res = false; + + if (!SegmentReader::Read()) + { + return res; + } + + const FileMetaInformation & header = F->GetHeader(); + MediaStorage ms = header.GetMediaStorage(); + if( ms == MediaStorage::SurfaceSegmentationStorage ) + { + res = ReadSurfaces(); + } + else + { + // Try to find Surface Sequence + const DataSet & dsRoot = F->GetDataSet(); + if (dsRoot.FindDataElement( Tag(0x0066, 0x0002) )) + { + res = ReadSurfaces(); + } + } + + return res; +} + +bool SurfaceReader::ReadSurfaces() +{ + bool res = false; + + const DataSet & ds = F->GetDataSet(); + + // Surface Sequence + const Tag surfaceSQTag(0x0066, 0x0002); + if (ds.FindDataElement(surfaceSQTag)) + { + SmartPointer< SequenceOfItems > surfaceSQ = ds.GetDataElement(surfaceSQTag).GetValueAsSQ(); + + if ( surfaceSQ->GetNumberOfItems() == 0) + { + gdcmErrorMacro( "No surface found" ); + return false; + } + + SequenceOfItems::ConstIterator itSurface = surfaceSQ->Begin(); + SequenceOfItems::ConstIterator itEndSurface = surfaceSQ->End(); + unsigned long idxItem = 1; + for (; itSurface != itEndSurface; itSurface++) + { + if ( !ReadSurface( *itSurface, idxItem ) ) + { + gdcmWarningMacro( "Surface "< surface = new Surface; + + const DataSet & surfacesDS = surfaceItem.GetNestedDataSet(); + + // Recommended Display Grayscale Value + Attribute<0x0062, 0x000C> recommendedDisplayGrayscaleValue; + recommendedDisplayGrayscaleValue.SetFromDataSet( surfacesDS ); + surface->SetRecommendedDisplayGrayscaleValue( recommendedDisplayGrayscaleValue.GetValue() ); + + // Recommended Display CIELab Value + Attribute<0x0062, 0x000D> recommendedDisplayCIELabValue; + recommendedDisplayCIELabValue.SetFromDataSet( surfacesDS ); + const unsigned short * array = recommendedDisplayCIELabValue.GetValues(); + unsigned short CIELavValue[3] = {0, 0, 0}; + unsigned int i = 0; + while (array != 0 && i < 3) + CIELavValue[i++] = *(array++); + surface->SetRecommendedDisplayCIELabValue( CIELavValue ); + + // Surface Number + Attribute<0x0066, 0x0003> surfaceNumberAt; + surfaceNumberAt.SetFromDataSet( surfacesDS ); + unsigned long surfaceNumber = idx; + if ( !surfaceNumberAt.GetAsDataElement().IsEmpty() ) + { + surfaceNumber = surfaceNumberAt.GetValue(); + } + surface->SetSurfaceNumber( surfaceNumber ); + + // Surface Comments + Attribute<0x0066, 0x0004> surfaceComments; + surfaceComments.SetFromDataSet( surfacesDS ); + surface->SetSurfaceComments( surfaceComments.GetValue() ); + + // Surface Processing + Attribute<0x0066, 0x0009> surfaceProcessingAt; + surfaceProcessingAt.SetFromDataSet( surfacesDS ); + String<> surfaceProcessingStr( surfaceProcessingAt.GetValue() ); + bool surfaceProcessing; + if (surfaceProcessingStr.Trim() == "YES") + surfaceProcessing = true; + else + surfaceProcessing = false; + surface->SetSurfaceProcessing( surfaceProcessing ); + + if (surfaceProcessing) + { + // Surface Processing Ratio + Attribute<0x0066, 0x000A> surfaceProcessingRatioAt; + surfaceProcessingRatioAt.SetFromDataSet( surfacesDS ); + surface->SetSurfaceProcessingRatio( surfaceProcessingRatioAt.GetValue() ); + + // Surface Processing Description + Attribute<0x0066, 0x000B> surfaceProcessingDescriptionAt; + surfaceProcessingDescriptionAt.SetFromDataSet( surfacesDS ); + surface->SetSurfaceProcessingDescription( surfaceProcessingDescriptionAt.GetValue() ); + + //***** Surface Processing Algorithm Identification Sequence *****// + if( surfacesDS.FindDataElement( Tag(0x0066, 0x0035) ) ) + { + SmartPointer processingAlgoSQ = surfacesDS.GetDataElement( Tag(0x0066, 0x0035) ).GetValueAsSQ(); + + if (processingAlgoSQ->GetNumberOfItems() > 0) // Only one item (type 1) + { + const Item & processingAlgoItem = processingAlgoSQ->GetItem(1); + const DataSet & processingAlgoDS = processingAlgoItem.GetNestedDataSet(); + + //***** Algorithm Family Code Sequence *****// + if( processingAlgoDS.FindDataElement( Tag(0x0066, 0x002F) ) ) + { + SmartPointer algoFamilySQ = processingAlgoDS.GetDataElement( Tag(0x0066, 0x002F) ).GetValueAsSQ(); + + if (algoFamilySQ->GetNumberOfItems() > 0) // Only one item (type 1) + { + const Item & algoFamilyItem = algoFamilySQ->GetItem(1); + const DataSet & algoFamilyDS = algoFamilyItem.GetNestedDataSet(); + + //***** CODE SEQUENCE MACRO ATTRIBUTES *****// + SegmentHelper::BasicCodedEntry & processingAlgo = surface->GetProcessingAlgorithm(); + + // Code Value (Type 1) + Attribute<0x0008, 0x0100> codeValueAt; + codeValueAt.SetFromDataSet( algoFamilyDS ); + processingAlgo.CV = codeValueAt.GetValue(); + + // Coding Scheme (Type 1) + Attribute<0x0008, 0x0102> codingSchemeAt; + codingSchemeAt.SetFromDataSet( algoFamilyDS ); + processingAlgo.CSD = codingSchemeAt.GetValue(); + + // Code Meaning (Type 1) + Attribute<0x0008, 0x0104> codeMeaningAt; + codeMeaningAt.SetFromDataSet( algoFamilyDS ); + processingAlgo.CM = codeMeaningAt.GetValue(); + } + } + } + } + } + + // Recommended Presentation Opacity + Attribute<0x0066, 0x000C> recommendedPresentationOpacity; + recommendedPresentationOpacity.SetFromDataSet( surfacesDS ); + surface->SetRecommendedPresentationOpacity( recommendedPresentationOpacity.GetValue() ); + + // Recommended Presentation Type + Attribute<0x0066, 0x000D> recommendedPresentationType; + recommendedPresentationType.SetFromDataSet( surfacesDS ); + surface->SetRecommendedPresentationType( Surface::GetVIEWType( recommendedPresentationType.GetValue() ) ); + + // Finite Volume + Attribute<0x0066, 0x000E> finiteVolumeAt; + finiteVolumeAt.SetFromDataSet( surfacesDS ); + Surface::STATES finiteVolume = Surface::GetSTATES( finiteVolumeAt.GetValue() ); + if ( finiteVolume == Surface::STATES_END) + finiteVolume = Surface::UNKNOWN; + surface->SetFiniteVolume( finiteVolume ); + + + // Manifold + Attribute<0x0066, 0x0010> manifoldAt; + manifoldAt.SetFromDataSet( surfacesDS ); + Surface::STATES manifold = Surface::GetSTATES( manifoldAt.GetValue() ); + if ( manifold == Surface::STATES_END ) + manifold = Surface::UNKNOWN; + surface->SetManifold( manifold ); + + //***** Surface Points Sequence ******// + if ( !ReadPointMacro(surface, surfacesDS) ) + return false; + + //***** Surface Points Normals Sequence ******// + const Tag surfaceNormalsSQTag(0x0066, 0x0012); + if ( surfacesDS.FindDataElement(surfaceNormalsSQTag)) + { + SmartPointer< SequenceOfItems > surfaceNormalsSQ = surfacesDS.GetDataElement(surfaceNormalsSQTag).GetValueAsSQ(); + + if ( surfaceNormalsSQ->GetNumberOfItems() > 0) // One Item shall be permitted + { + const DataSet & surfaceNormalsDS = surfaceNormalsSQ->GetItem(1).GetNestedDataSet(); + + // Number of Vectors + Attribute<0x0066, 0x001E> numberOfVectors; + numberOfVectors.SetFromDataSet( surfaceNormalsDS ); + surface->SetNumberOfVectors( numberOfVectors.GetValue() ); + + // Vector Dimensionality + Attribute<0x0066, 0x001F> vectorDimensionality; + vectorDimensionality.SetFromDataSet( surfaceNormalsDS ); + surface->SetVectorDimensionality( vectorDimensionality.GetValue() ); + + // Vector Accuracy (Type 3) + const Tag vectorAccuracyTag = Tag(0x0066, 0x0020); + if ( surfaceNormalsDS.FindDataElement( vectorAccuracyTag ) ) + { + const DataElement & vectorAccuracyDE = surfaceNormalsDS.GetDataElement( vectorAccuracyTag ); + if ( !vectorAccuracyDE.IsEmpty() ) + { + Attribute<0x0066, 0x0020> vectorAccuracyAt; + vectorAccuracyAt.SetFromDataElement( vectorAccuracyDE ); + surface->SetVectorAccuracy( vectorAccuracyAt.GetValues() ); + } + } + + const Tag vectorCoordDataTag = Tag(0x0066, 0x0021); + if( surfaceNormalsDS.FindDataElement( vectorCoordDataTag ) ) + { + const DataElement & de = surfaceNormalsDS.GetDataElement( vectorCoordDataTag ); + surface->SetVectorCoordinateData( de ); + } + else + { + gdcmWarningMacro( "No Vector Coordinate Data Found" ); + return false; + } + } + else + { + gdcmWarningMacro( "Surface Point Normals Sequence empty" ); +// return false; + } + } + + //***** Surface Mesh Primitives Sequence ******// + const Tag surfacePrimitivesSQTag(0x0066, 0x0013); + if ( !surfacesDS.FindDataElement(surfacePrimitivesSQTag)) + { + gdcmWarningMacro( "No Surface Mesh Primitives Sequence Found" ); + return false; + } + SmartPointer< SequenceOfItems > surfacePrimitivesSQ = surfacesDS.GetDataElement(surfacePrimitivesSQTag).GetValueAsSQ(); + + if ( surfacePrimitivesSQ->GetNumberOfItems() < 1) // One Item shall be permitted + { + gdcmWarningMacro( "Surface Mesh Primitives Sequence empty" ); + return false; + } + + SmartPointer< MeshPrimitive > meshPrimitive = new MeshPrimitive; + DataSet & surfacePrimitivesDS = surfacePrimitivesSQ->GetItem(1).GetNestedDataSet(); + Tag typedTag; + + if (surfacePrimitivesDS.FindDataElement( Tag(0x0066, 0x0023) )) + { + typedTag = Tag(0x0066, 0x0023); + meshPrimitive->SetPrimitiveType( MeshPrimitive::TRIANGLE ); + } + else if (surfacePrimitivesDS.FindDataElement( Tag(0x0066, 0x0024)) ) + { + typedTag = Tag(0x0066, 0x0024); + meshPrimitive->SetPrimitiveType( MeshPrimitive::EDGE ); + } + else if (surfacePrimitivesDS.FindDataElement( Tag(0x0066, 0x0025)) ) + { + typedTag = Tag(0x0066, 0x0025); + meshPrimitive->SetPrimitiveType( MeshPrimitive::VERTEX ); + } + else + { + SmartPointer< SequenceOfItems > typedSQ; + if (surfacePrimitivesDS.FindDataElement( Tag(0x0066, 0x0026) )) + { + typedSQ = surfacePrimitivesDS.GetDataElement( Tag(0x0066, 0x0026) ).GetValueAsSQ(); + meshPrimitive->SetPrimitiveType( MeshPrimitive::TRIANGLE_STRIP ); + } + else if (surfacePrimitivesDS.FindDataElement( Tag(0x0066, 0x0027)) ) + { + typedSQ = surfacePrimitivesDS.GetDataElement( Tag(0x0066, 0x0027) ).GetValueAsSQ(); + meshPrimitive->SetPrimitiveType( MeshPrimitive::TRIANGLE_FAN ); + } + else if (surfacePrimitivesDS.FindDataElement( Tag(0x0066, 0x0028)) ) + { + typedSQ = surfacePrimitivesDS.GetDataElement( Tag(0x0066, 0x0028) ).GetValueAsSQ(); + meshPrimitive->SetPrimitiveType( MeshPrimitive::LINE ); + } + else if (surfacePrimitivesDS.FindDataElement( Tag(0x0066, 0x0034)) ) + { + typedSQ = surfacePrimitivesDS.GetDataElement( Tag(0x0066, 0x0034) ).GetValueAsSQ(); + meshPrimitive->SetPrimitiveType( MeshPrimitive::FACET ); + } + else + { + gdcmErrorMacro( "Unknown surface mesh primitives type" ); + return false; + } + + if (typedSQ->GetNumberOfItems() > 0) + { + const size_t nbItems = typedSQ->GetNumberOfItems(); + MeshPrimitive::PrimitivesData & primitivesData= meshPrimitive->GetPrimitivesData(); + primitivesData.reserve( nbItems ); + + SequenceOfItems::ConstIterator it = typedSQ->Begin(); + SequenceOfItems::ConstIterator itEnd= typedSQ->End(); + for (; it != itEnd; it++) + { + const DataSet & typedPrimitivesDS = it->GetNestedDataSet(); + if ( typedPrimitivesDS.FindDataElement( Tag(0x0066, 0x0029)) ) + { + meshPrimitive->AddPrimitiveData( typedPrimitivesDS.GetDataElement( Tag(0x0066, 0x0029)) ); + } + else + { + gdcmWarningMacro( "Missing Primitive Point Index List" ); + return false; + } + } + } + else + { + gdcmWarningMacro( "Mesh Primitive typed Sequence empty" ); + return false; + } + } + + if (typedTag.GetElementTag() != 0) + { + const DataElement & meshPrimitiveData = surfacePrimitivesDS.GetDataElement( typedTag ); + meshPrimitive->SetPrimitiveData( meshPrimitiveData ); + } + else + { + gdcmWarningMacro( "No typed Point Index List found" ); + return false; + } + + // Get the appropriated segment + SmartPointer< Segment > segment = Segments[surfaceNumber]; + + //***** Segment Sequence *****// + SmartPointer segmentsSQ = F->GetDataSet().GetDataElement( Tag(0x0062, 0x0002) ).GetValueAsSQ(); + SequenceOfItems::ConstIterator itSegment = segmentsSQ->Begin(); + SequenceOfItems::ConstIterator itEndSegment = segmentsSQ->End(); + bool findItem = false; + while( !findItem && itSegment != itEndSegment ) + { + const DataSet & segmentDS = itSegment->GetNestedDataSet(); + + //***** Referenced Surface Sequence *****// + SmartPointer refSurfaceSQ = segmentDS.GetDataElement( Tag(0x0066, 0x002B) ).GetValueAsSQ(); + SequenceOfItems::ConstIterator itRefSurface = refSurfaceSQ->Begin(); + SequenceOfItems::ConstIterator itEndRefSurface = refSurfaceSQ->End(); + while( !findItem && itRefSurface != itEndRefSurface ) + { + const DataSet & refSurfaceDS = itRefSurface->GetNestedDataSet(); + + // Referenced Surface Number + Attribute<0x0066, 0x002C> refSurfaceNumberAt; + refSurfaceNumberAt.SetFromDataSet( refSurfaceDS ); + unsigned long refSurfaceNumber; + if ( !refSurfaceNumberAt.GetAsDataElement().IsEmpty() ) + { + refSurfaceNumber = refSurfaceNumberAt.GetValue(); + } + else + { + refSurfaceNumber = idx; + } + + if (refSurfaceNumber == surfaceNumber) + { + findItem = true; + + //***** Segment Surface Generation Algorithm Identification Sequence *****// + if( refSurfaceDS.FindDataElement( Tag(0x0066, 0x002D) ) ) + { + SmartPointer algoSQ = refSurfaceDS.GetDataElement( Tag(0x0066, 0x002D) ).GetValueAsSQ(); + + if (algoSQ->GetNumberOfItems() > 0) // Only one item is a type 1 + { + const Item & algoItem = algoSQ->GetItem(1); + const DataSet & algoDS = algoItem.GetNestedDataSet(); + + //***** Algorithm Family Code Sequence *****// + if( algoDS.FindDataElement( Tag(0x0066, 0x002F) ) ) + { + SmartPointer algoFamilySQ = algoDS.GetDataElement( Tag(0x0066, 0x002F) ).GetValueAsSQ(); + + if (algoFamilySQ->GetNumberOfItems() > 0) // Only one item is a type 1 + { + const Item & algoFamilyItem = algoFamilySQ->GetItem(1); + const DataSet & algoFamilyDS = algoFamilyItem.GetNestedDataSet(); + + //***** CODE SEQUENCE MACRO ATTRIBUTES *****// + SegmentHelper::BasicCodedEntry & algoFamily = surface->GetAlgorithmFamily(); + + // Code Value (Type 1) + Attribute<0x0008, 0x0100> codeValueAt; + codeValueAt.SetFromDataSet( algoFamilyDS ); + algoFamily.CV = codeValueAt.GetValue(); + + // Coding Scheme (Type 1) + Attribute<0x0008, 0x0102> codingSchemeAt; + codingSchemeAt.SetFromDataSet( algoFamilyDS ); + algoFamily.CSD = codingSchemeAt.GetValue(); + + // Code Meaning (Type 1) + Attribute<0x0008, 0x0104> codeMeaningAt; + codeMeaningAt.SetFromDataSet( algoFamilyDS ); + algoFamily.CM = codeMeaningAt.GetValue(); + } + } + + // Algorithm Version + Attribute<0x0066, 0x0031> algoVersionAt; + algoVersionAt.SetFromDataSet( algoDS ); + surface->SetAlgorithmVersion( algoVersionAt.GetValue() ); + + // Algorithm Name + Attribute<0x0066, 0x0036> algoNameAt; + algoNameAt.SetFromDataSet( algoDS ); + surface->SetAlgorithmName( algoNameAt.GetValue() ); + } + } + // else assert? return false? gdcmWarning? + } + itRefSurface++; + } + itSegment++; + } + + // Add a MeshPrimitive to the surface + surface->SetMeshPrimitive( *meshPrimitive ); + + // Add surface to the appropriated segment + segment->AddSurface(surface); + + return true; +} + +bool SurfaceReader::ReadPointMacro(SmartPointer< Surface > surface, const DataSet & surfaceDS) +{ + //***** Surface Points Sequence ******// + const Tag surfacePointsSQTag(0x0066, 0x0011); + if ( !surfaceDS.FindDataElement(surfacePointsSQTag)) + { + gdcmWarningMacro( "No Surface Point Sequence Found" ); + return false; + } + SmartPointer< SequenceOfItems > surfacePointsSQ = surfaceDS.GetDataElement(surfacePointsSQTag).GetValueAsSQ(); + + if ( surfacePointsSQ->GetNumberOfItems() == 0) // One Item shall be permitted + { + gdcmWarningMacro( "Surface Point Sequence empty" ); + return false; + } + + const DataSet & surfacePointsDS = surfacePointsSQ->GetItem(1).GetNestedDataSet(); + + const Tag pointCoordDataTag = Tag(0x0066, 0x0016); + if( !surfacePointsDS.FindDataElement( pointCoordDataTag ) ) + { + gdcmWarningMacro( "No Point Coordinates Data Found" ); + return false; + } + const DataElement & pointCoordDataDe = surfacePointsDS.GetDataElement( pointCoordDataTag ); + surface->SetPointCoordinatesData( pointCoordDataDe ); + + // Number of Surface Points + const Tag numberOfSurfacePointsTag = Tag(0x0066, 0x0015); + if (surfacePointsDS.FindDataElement( numberOfSurfacePointsTag ) + && !surfacePointsDS.GetDataElement( numberOfSurfacePointsTag ).IsEmpty() ) + { + Attribute<0x0066, 0x0015> numberOfSurfacePointsAt; + numberOfSurfacePointsAt.SetFromDataSet( surfacePointsDS ); + surface->SetNumberOfSurfacePoints( numberOfSurfacePointsAt.GetValue() ); + } + else + { + const unsigned long numberOfSurfacePoints = (unsigned long) ( pointCoordDataDe.GetVL().GetLength() / (VR::GetLength(VR::OF) * 3) ); + surface->SetNumberOfSurfacePoints( numberOfSurfacePoints ); + } + + // Point Position Accuracy (Type 3) + const Tag pointPositionAccuracyTag = Tag(0x0066, 0x0017); + if (surfacePointsDS.FindDataElement( pointPositionAccuracyTag ) + && !surfacePointsDS.GetDataElement( pointPositionAccuracyTag ).IsEmpty() ) + { + Attribute<0x0066, 0x0017> pointPositionAccuracyAt; + pointPositionAccuracyAt.SetFromDataSet( surfacePointsDS ); + surface->SetPointPositionAccuracy( pointPositionAccuracyAt.GetValues() ); + } + + // Mean Point Distance (Type 3) + const Tag meanPointDistanceTag = Tag(0x0066, 0x0018); + if (surfacePointsDS.FindDataElement( meanPointDistanceTag ) + && !surfacePointsDS.GetDataElement( meanPointDistanceTag ).IsEmpty() ) + { + Attribute<0x0066, 0x0018> meanPointDistanceAt; + meanPointDistanceAt.SetFromDataSet( surfacePointsDS ); + surface->SetMeanPointDistance( meanPointDistanceAt.GetValue() ); + } + + // Maximum Point Distance (Type 3) + const Tag maximumPointDistanceTag = Tag(0x0066, 0x0019); + if (surfacePointsDS.FindDataElement( maximumPointDistanceTag ) + && !surfacePointsDS.GetDataElement( maximumPointDistanceTag ).IsEmpty() ) + { + Attribute<0x0066, 0x0019> maximumPointDistanceAt; + maximumPointDistanceAt.SetFromDataSet( surfacePointsDS ); + surface->SetMaximumPointDistance( maximumPointDistanceAt.GetValue() ); + } + + // Point Bounding Box Coordinates (Type 3) + const Tag pointsBoundingBoxCoordinatesTag = Tag(0x0066, 0x001a); + if (surfacePointsDS.FindDataElement( pointsBoundingBoxCoordinatesTag ) + && !surfacePointsDS.GetDataElement( pointsBoundingBoxCoordinatesTag ).IsEmpty() ) + { + Attribute<0x0066, 0x001a> pointsBoundingBoxCoordinatesAt; + pointsBoundingBoxCoordinatesAt.SetFromDataSet( surfacePointsDS ); + surface->SetPointsBoundingBoxCoordinates( pointsBoundingBoxCoordinatesAt.GetValues() ); + } + + // Axis of Rotation (Type 3) + const Tag axisOfRotationTag = Tag(0x0066, 0x001b); + if (surfacePointsDS.FindDataElement( axisOfRotationTag ) + && !surfacePointsDS.GetDataElement( axisOfRotationTag ).IsEmpty() ) + { + Attribute<0x0066, 0x001b> axisOfRotationAt; + axisOfRotationAt.SetFromDataSet( surfacePointsDS ); + surface->SetAxisOfRotation( axisOfRotationAt.GetValues() ); + } + + // Center of Rotation (Type 3) + const Tag centerOfRotationTag = Tag(0x0066, 0x001c); + if (surfacePointsDS.FindDataElement( centerOfRotationTag ) + && !surfacePointsDS.GetDataElement( centerOfRotationTag ).IsEmpty() ) + { + Attribute<0x0066, 0x001c> centerOfRotationAt; + centerOfRotationAt.SetFromDataSet( surfacePointsDS ); + surface->SetAxisOfRotation( centerOfRotationAt.GetValues() ); + } + + return true; +} + +} diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmSurfaceReader.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmSurfaceReader.h new file mode 100644 index 0000000..61793ae --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmSurfaceReader.h @@ -0,0 +1,52 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMSURFACEREADER_H +#define GDCMSURFACEREADER_H + +#include +#include + +namespace gdcm +{ + +/** + * \brief This class defines a SURFACE IE reader. + * It reads surface mesh module attributes. + * + * \see PS 3.3 A.1.2.18 , A.57 and C.27 + */ +class GDCM_EXPORT SurfaceReader : public SegmentReader +{ +public: + SurfaceReader(); + + virtual ~SurfaceReader(); + + /// Read + virtual bool Read(); + + unsigned long GetNumberOfSurfaces() const; + + protected: + + bool ReadSurfaces(); + + bool ReadSurface(const Item & surfaceItem, const unsigned long idx); + + bool ReadPointMacro(SmartPointer< Surface > surface, const DataSet & surfaceDS); +}; + +} + +#endif // GDCMSURFACEREADER_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmSurfaceWriter.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmSurfaceWriter.cxx new file mode 100644 index 0000000..d379fcc --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmSurfaceWriter.cxx @@ -0,0 +1,889 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmSurfaceWriter.h" +#include "gdcmAttribute.h" +#include "gdcmUIDGenerator.h" + +namespace gdcm +{ + +SurfaceWriter::SurfaceWriter(): + NumberOfSurfaces(0) +{ +} + +SurfaceWriter::~SurfaceWriter() +{ +} + +void SurfaceWriter::ComputeNumberOfSurfaces() +{ + std::vector< SmartPointer< Segment > >::const_iterator it = Segments.begin(); + std::vector< SmartPointer< Segment > >::const_iterator itEnd = Segments.end(); + for (; it != itEnd; it++) + { + NumberOfSurfaces += (*it)->GetSurfaceCount(); + } +} + +unsigned long SurfaceWriter::GetNumberOfSurfaces() +{ + if (NumberOfSurfaces == 0) + { + ComputeNumberOfSurfaces(); + } + + return NumberOfSurfaces; +} + +void SurfaceWriter::SetNumberOfSurfaces(const unsigned long nb) +{ + NumberOfSurfaces = nb; +} + +bool SurfaceWriter::PrepareWrite() +{ + if( !SegmentWriter::PrepareWrite() ) + { + return false; + } + + File & file = GetFile(); + DataSet & ds = file.GetDataSet(); + + FileMetaInformation & fmi = file.GetHeader(); + const TransferSyntax & ts = fmi.GetDataSetTransferSyntax(); + assert( ts.IsExplicit() || ts.IsImplicit() ); + + // Number Of Surface + const unsigned long nbSurfaces = this->GetNumberOfSurfaces(); + if (nbSurfaces == 0) + { + gdcmErrorMacro( "No surface to write" ); + return false; + } + Attribute<0x0066, 0x0001> numberOfSurfaces; + numberOfSurfaces.SetValue( (unsigned int)nbSurfaces ); + ds.Replace( numberOfSurfaces.GetAsDataElement() ); + + // Surface Sequence + SmartPointer surfacesSQ; + if( !ds.FindDataElement( Tag(0x0066, 0x0002) ) ) + { + surfacesSQ = new SequenceOfItems; + DataElement detmp( Tag(0x0066, 0x0002) ); + detmp.SetVR( VR::SQ ); + detmp.SetValue( *surfacesSQ ); + detmp.SetVLToUndefined(); + ds.Insert( detmp ); + } + surfacesSQ = ds.GetDataElement( Tag(0x0066, 0x0002) ).GetValueAsSQ(); + surfacesSQ->SetLengthToUndefined(); + + // Fill the Surface Sequence +{ + const size_t nbItems = surfacesSQ->GetNumberOfItems(); + if (nbItems < nbSurfaces) + { + const size_t diff = nbSurfaces - nbItems; + const size_t nbOfItemToMake = (diff > 0?diff:0); + for(unsigned int i = 1; i <= nbOfItemToMake; ++i) + { + Item item; + item.SetVLToUndefined(); + surfacesSQ->AddItem(item); + } + } +} + // else Should I remove items? + + std::vector< SmartPointer< Segment > > segments = this->GetSegments(); + std::vector< SmartPointer< Segment > >::const_iterator it0 = segments.begin(); + std::vector< SmartPointer< Segment > >::const_iterator it0End = segments.end(); + unsigned int numSegment= 1; + unsigned int numSurface= 1; + for (; it0 != it0End; it0++) + { + SmartPointer< Segment > segment = *it0; + assert( segment ); + + std::vector< SmartPointer< Surface > > surfaces = segment->GetSurfaces(); + std::vector< SmartPointer< Surface > >::const_iterator it1 = surfaces.begin(); + std::vector< SmartPointer< Surface > >::const_iterator it1End = surfaces.end(); + for (; it1 != it1End; it1++) + { + SmartPointer< Surface > surface = *it1; + assert( surface ); + + Item & surfaceItem = surfacesSQ->GetItem( numSurface ); + DataSet & surfaceDS = surfaceItem.GetNestedDataSet(); + + // Recommended Display Grayscale Value + Attribute<0x0062, 0x000C> recommendedDisplayGrayscaleValue; + recommendedDisplayGrayscaleValue.SetValue( surface->GetRecommendedDisplayGrayscaleValue() ); + surfaceDS.Replace( recommendedDisplayGrayscaleValue.GetAsDataElement() ); + + // Recommended Display CIELab Value + Attribute<0x0062, 0x000D> recommendedDisplayCIELabValue; + recommendedDisplayCIELabValue.SetValues( surface->GetRecommendedDisplayCIELabValue(), 3 ); + surfaceDS.Replace( recommendedDisplayCIELabValue.GetAsDataElement() ); + + // Surface Number (Type 1) + Attribute<0x0066, 0x0003> surfaceNumberAt; + unsigned long surfaceNumber = surface->GetSurfaceNumber(); + if (surfaceNumber == 0) + surfaceNumber = numSurface; + surfaceNumberAt.SetValue( (unsigned int)surfaceNumber ); + surfaceDS.Replace( surfaceNumberAt.GetAsDataElement() ); + + // Surface Comments (Type 3) + const char * surfaceComments = surface->GetSurfaceComments(); + if (strcmp(surfaceComments, "") != 0) + { + Attribute<0x0066, 0x0004> surfaceCommentsAt; + surfaceCommentsAt.SetValue( surfaceComments ); + surfaceDS.Replace( surfaceCommentsAt.GetAsDataElement() ); + } + + // Surface Processing + const bool surfaceProcessing = surface->GetSurfaceProcessing(); + Attribute<0x0066, 0x0009> surfaceProcessingAt; + surfaceProcessingAt.SetValue( (surfaceProcessing ? "YES" : "NO") ); + surfaceDS.Replace( surfaceProcessingAt.GetAsDataElement() ); + + if (surfaceProcessing) + { + Attribute<0x0066, 0x000A> surfaceProcessingRatioAt; + surfaceProcessingRatioAt.SetValue( surface->GetSurfaceProcessingRatio() ); + surfaceDS.Replace( surfaceProcessingRatioAt.GetAsDataElement() ); + + const char * surfaceProcessingDescription = surface->GetSurfaceProcessingDescription(); + if (strcmp(surfaceProcessingDescription, "") != 0) + { + Attribute<0x0066, 0x000B> surfaceProcessingDescriptionAt; + surfaceProcessingDescriptionAt.SetValue( surfaceProcessingDescription ); + surfaceDS.Replace( surfaceProcessingDescriptionAt.GetAsDataElement() ); + } + + //***** Surface Processing Algorithm Identification Sequence *****// + { + SmartPointer processingAlgoIdSQ; + const Tag processingAlgoIdTag(0x0066, 0x0035); + if( !surfaceDS.FindDataElement( processingAlgoIdTag ) ) + { + processingAlgoIdSQ = new SequenceOfItems; + DataElement detmp( processingAlgoIdTag ); + detmp.SetVR( VR::SQ ); + detmp.SetValue( *processingAlgoIdSQ ); + detmp.SetVLToUndefined(); + surfaceDS.Insert( detmp ); + } + processingAlgoIdSQ = surfaceDS.GetDataElement( processingAlgoIdTag ).GetValueAsSQ(); + processingAlgoIdSQ->SetLengthToUndefined(); + + if (processingAlgoIdSQ->GetNumberOfItems() < 1) // One item shall be permitted + { + Item item; + item.SetVLToUndefined(); + processingAlgoIdSQ->AddItem(item); + } + + ::gdcm::Item & processingAlgoIdItem = processingAlgoIdSQ->GetItem(1); + ::gdcm::DataSet & processingAlgoIdDS = processingAlgoIdItem.GetNestedDataSet(); + + //***** Algorithm Family Code Sequence *****// + //See: PS.3.3 Table 8.8-1 and PS 3.16 Context ID 7162 + { + const SegmentHelper::BasicCodedEntry & processingAlgo = surface->GetProcessingAlgorithm(); + if (processingAlgo.IsEmpty()) + { + gdcmWarningMacro("Surface provessing algorithm family not specified or incomplete"); + } + + SmartPointer algoFamilyCodeSQ; + const Tag algoFamilyCodeTag(0x0066, 0x002F); + if( !processingAlgoIdDS.FindDataElement( algoFamilyCodeTag ) ) + { + algoFamilyCodeSQ = new SequenceOfItems; + DataElement detmp( algoFamilyCodeTag ); + detmp.SetVR( VR::SQ ); + detmp.SetValue( *algoFamilyCodeSQ ); + detmp.SetVLToUndefined(); + processingAlgoIdDS.Insert( detmp ); + } + algoFamilyCodeSQ = processingAlgoIdDS.GetDataElement( algoFamilyCodeTag ).GetValueAsSQ(); + algoFamilyCodeSQ->SetLengthToUndefined(); + + // Fill the Algorithm Family Code Sequence + if (algoFamilyCodeSQ->GetNumberOfItems() < 1) + { + Item item; + item.SetVLToUndefined(); + algoFamilyCodeSQ->AddItem(item); + } + + ::gdcm::Item & algoFamilyCodeItem = algoFamilyCodeSQ->GetItem(1); + ::gdcm::DataSet & algoFamilyCodeDS = algoFamilyCodeItem.GetNestedDataSet(); + + //***** CODE SEQUENCE MACRO ATTRIBUTES *****// + { + // Code Value (Type 1) + Attribute<0x0008, 0x0100> codeValueAt; + codeValueAt.SetValue( processingAlgo.CV ); + algoFamilyCodeDS.Replace( codeValueAt.GetAsDataElement() ); + + // Coding Scheme (Type 1) + Attribute<0x0008, 0x0102> codingSchemeAt; + codingSchemeAt.SetValue( processingAlgo.CSD ); + algoFamilyCodeDS.Replace( codingSchemeAt.GetAsDataElement() ); + + // Code Meaning (Type 1) + Attribute<0x0008, 0x0104> codeMeaningAt; + codeMeaningAt.SetValue( processingAlgo.CM ); + algoFamilyCodeDS.Replace( codeMeaningAt.GetAsDataElement() ); + } + } + } + } + + // Presentation Opacity + Attribute<0x0066, 0x000C> presentationOpacity; + presentationOpacity.SetValue( surface->GetRecommendedPresentationOpacity() ); + surfaceDS.Replace( presentationOpacity.GetAsDataElement() ); + + // Presentation Type + Attribute<0x0066, 0x000D> presentationType; + const char * reconmmendedPresentationType = Surface::GetVIEWTypeString( surface->GetRecommendedPresentationType() ); + if (reconmmendedPresentationType != 0) + presentationType.SetValue( reconmmendedPresentationType ); + else + presentationType.SetValue( Surface::GetVIEWTypeString(Surface::SURFACE) ); // Is it the right thing to do? + surfaceDS.Replace( presentationType.GetAsDataElement() ); + + // Finite Volume + Attribute<0x0066, 0x000E> finiteVolumeAt; + Surface::STATES finiteVolume = surface->GetFiniteVolume(); + if (finiteVolume == Surface::STATES_END) + finiteVolume = Surface::UNKNOWN; + finiteVolumeAt.SetValue( Surface::GetSTATESString( finiteVolume ) ); + surfaceDS.Replace( finiteVolumeAt.GetAsDataElement() ); + + // Manifold + Attribute<0x0066, 0x0010> manifoldAt; + Surface::STATES manifold = surface->GetManifold(); + if (manifold == Surface::STATES_END) + manifold = Surface::UNKNOWN; + manifoldAt.SetValue( Surface::GetSTATESString( manifold ) ); + surfaceDS.Replace( manifoldAt.GetAsDataElement() ); + + //****** Surface Points *****// + // (0066,0011) SQ (Sequence with undefined length #=1) # u/l, 1 Surface Points Sequence + // (fffe,e000) na (Item with undefined length #=1) # u/l, 1 Item + // (0066,0015) UL # 0, 1 Number Of Surface Points + // (0066,0016) OW # 0, 1 Point Coordinates Data + // (fffe,e00d) na (ItemDelimitationItem) # 0, 0 ItemDelimitationItem + // (fffe,e0dd) na (SequenceDelimitationItem) # 0, 0 SequenceDelimitationItem + if ( !PrepareWritePointMacro(surface, surfaceDS, ts) ) + return false; + + //****** Surface Points Normals *****// + // (0066,0012) SQ (Sequence with undefined length #=1) # u/l, 1 Surface Points Sequence + // (fffe,e000) na (Item with undefined length #=1) # u/l, 1 Item + // (0066,001e) UL # 0, 1 Number of Vectors + // (0066,001f) US # 0, 1 Vector Dimensionality + // (0066,0021) OF # 0, 1_n Vector Coordinate Data + // (fffe,e00d) na (ItemDelimitationItem) # 0, 0 ItemDelimitationItem + // (fffe,e0dd) na (SequenceDelimitationItem) # 0, 0 SequenceDelimitationItem + const unsigned long numberofvectors = surface->GetNumberOfVectors(); + SmartPointer< MeshPrimitive > meshPrimitive = surface->GetMeshPrimitive(); + const MeshPrimitive::MPType primitiveType = meshPrimitive->GetPrimitiveType(); + if (numberofvectors > 0 + && primitiveType != MeshPrimitive::TRIANGLE_STRIP + && primitiveType != MeshPrimitive::TRIANGLE_FAN) + { + SmartPointer surfacePointsNormalsSQ; + if( !surfaceDS.FindDataElement( Tag(0x0066, 0x0012) ) ) + { + surfacePointsNormalsSQ = new SequenceOfItems; + DataElement detmp( Tag(0x0066, 0x0012) ); + detmp.SetVR( VR::SQ ); + detmp.SetValue( *surfacePointsNormalsSQ ); + detmp.SetVLToUndefined(); + surfaceDS.Insert( detmp ); + } + surfacePointsNormalsSQ = surfaceDS.GetDataElement( Tag(0x0066, 0x0012) ).GetValueAsSQ(); + surfacePointsNormalsSQ->SetLengthToUndefined(); + + if (surfacePointsNormalsSQ->GetNumberOfItems() < 1) // One item shall be permitted + { + Item item; + item.SetVLToUndefined(); + surfacePointsNormalsSQ->AddItem(item); + } + + Item & surfacePointsNormalsItem = surfacePointsNormalsSQ->GetItem(1); + DataSet & surfacePointsNormalsDS = surfacePointsNormalsItem.GetNestedDataSet(); + + // Number of Vectors + Attribute<0x0066, 0x001E> numberOfVectors; + numberOfVectors.SetValue( (unsigned int)surface->GetNumberOfVectors() ); + surfacePointsNormalsDS.Replace( numberOfVectors.GetAsDataElement() ); + + // Vector Dimensionality + Attribute<0x0066, 0x001F> vectorDimensionalityAt; + unsigned short vectorDimensionality = surface->GetVectorDimensionality(); + assert( vectorDimensionality ); + vectorDimensionalityAt.SetValue( vectorDimensionality ); + surfacePointsNormalsDS.Replace( vectorDimensionalityAt.GetAsDataElement() ); + + // Vector Accuracy (Type 3) + Attribute<0x0066, 0x0020> vectorAccuracyAt; + const float * vectorAccuracy = surface->GetVectorAccuracy(); + if (vectorAccuracy != 0) + { + vectorAccuracyAt.SetValues( vectorAccuracy, vectorDimensionality ); + surfacePointsNormalsDS.Replace( vectorAccuracyAt.GetAsDataElement() ); + } + + // Vector Coordinate Data + DataElement vectorCoordDataDE( Tag(0x0066, 0x0021) ); + vectorCoordDataDE.SetVR( VR::OF ); + const Value & vectorCoordinateDataValue = surface->GetVectorCoordinateData().GetValue(); + assert( &vectorCoordinateDataValue ); + vectorCoordDataDE.SetValue( vectorCoordinateDataValue ); + + const ByteValue *bv = vectorCoordDataDE.GetByteValue(); + VL vl; + if ( bv ) + vl = bv->GetLength(); + else + vl.SetToUndefined(); + vectorCoordDataDE.SetVL( vl ); + + if ( ts.IsExplicit() ) + vectorCoordDataDE.SetVR( VR::OF ); + + surfacePointsNormalsDS.Replace( vectorCoordDataDE ); + } + else if (numberofvectors > 0) + { + gdcmWarningMacro("Triangle strip or fan have no surface points normals"); + } + + //****** Surface Mesh Primitives *****// + // Two exemples : + // (0066,0013) SQ (Sequence with undefined length #=1) # u/l, 1 Surface Mesh Primitives Sequence + // (fffe,e000) na (Item with undefined length #=1) # u/l, 1 Item + // (0066,0016) OW # 0, 1 Edge Point Index List + // (fffe,e00d) na (ItemDelimitationItem) # 0, 0 ItemDelimitationItem + // (fffe,e0dd) na (SequenceDelimitationItem) # 0, 0 SequenceDelimitationItem + // + // OR + // + // (0066,0013) SQ (Sequence with undefined length #=1) # u/l, 1 Surface Mesh Primitives Sequence + // (fffe,e000) na (Item with undefined length #=1) # u/l, 1 Item + // (0066,0026) SQ (Sequence with undefined length #=1) # u/l, 1 // Triangle Strip Sequence + // (fffe,e000) na (Item with undefined length #=1) # u/l, 1 Item + // (0066,0029) OW # 0, 1 // Primitive Point Index List + // (fffe,e00d) na (ItemDelimitationItem) # 0, 0 ItemDelimitationItem + // ... + // (fffe,e000) na (Item with undefined length #=1) # u/l, 1 Item + // (0066,0029) OW # 0, 1 // Primitive Point Index List + // (fffe,e00d) na (ItemDelimitationItem) # 0, 0 ItemDelimitationItem + // (fffe,e0dd) na (SequenceDelimitationItem) # 0, 0 SequenceDelimitationItem + // (fffe,e00d) na (ItemDelimitationItem) # 0, 0 ItemDelimitationItem + // (fffe,e0dd) na (SequenceDelimitationItem) # 0, 0 SequenceDelimitationItem + + // Surface Mesh Primitives Sequence + { + SmartPointer surfaceMeshPrimitivesSQ; + if( !surfaceDS.FindDataElement( Tag(0x0066, 0x0013) ) ) + { + surfaceMeshPrimitivesSQ = new SequenceOfItems; + DataElement detmp( Tag(0x0066, 0x0013) ); + detmp.SetVR( VR::SQ ); + detmp.SetValue( *surfaceMeshPrimitivesSQ ); + detmp.SetVLToUndefined(); + surfaceDS.Insert( detmp ); + } + surfaceMeshPrimitivesSQ = surfaceDS.GetDataElement( Tag(0x0066, 0x0013) ).GetValueAsSQ(); + surfaceMeshPrimitivesSQ->SetLengthToUndefined(); + + if (surfaceMeshPrimitivesSQ->GetNumberOfItems() < 1) // One itme shall be permitted + { + Item item; + item.SetVLToUndefined(); + surfaceMeshPrimitivesSQ->AddItem(item); + } + + Item & surfaceMeshPrimitivesItem = surfaceMeshPrimitivesSQ->GetItem(1); + DataSet & surfaceMeshPrimitivesDS = surfaceMeshPrimitivesItem.GetNestedDataSet(); + + //***** Handle "Typed" Point Index List *****// + bool insertInSQ = false; + + // Primitive Point Index List + Tag typedPrimitiveTag; + typedPrimitiveTag.SetGroup(0x0066); + DataSet & pointIndexListDS0 = surfaceMeshPrimitivesDS; + + switch (primitiveType) + { + case MeshPrimitive::VERTEX: + // Vertex Point Index List + typedPrimitiveTag.SetElement(0x0025); + break; + case MeshPrimitive::EDGE: + // Edge Point Index List + typedPrimitiveTag.SetElement(0x0024); + break; + case MeshPrimitive::TRIANGLE: + // Triangle Point Index List + typedPrimitiveTag.SetElement(0x0023); + break; + case MeshPrimitive::TRIANGLE_STRIP: + case MeshPrimitive::TRIANGLE_FAN: + case MeshPrimitive::LINE: + case MeshPrimitive::FACET: + // Primitive Point Index List + typedPrimitiveTag.SetElement(0x0029); + insertInSQ = true; + break; + default: + gdcmErrorMacro( "Unknown surface mesh primitives type" ); + return false; + } + + if (insertInSQ) + { + // Handled "complex" mesh primitives + + Tag typedSequenceTag; + typedSequenceTag.SetGroup(0x0066); + switch (primitiveType) + { + case MeshPrimitive::TRIANGLE_STRIP: + // Triangle Strip Sequence + typedSequenceTag.SetElement(0x0026); + break; + case MeshPrimitive::TRIANGLE_FAN: + // Triangle Fan Sequence + typedSequenceTag.SetElement(0x0027); + break; + case MeshPrimitive::LINE: + // Line Sequence + typedSequenceTag.SetElement(0x0028); + break; + case MeshPrimitive::FACET: + // Facet Sequence + typedSequenceTag.SetElement(0x0034); + break; + default: + gdcmErrorMacro( "Unknown surface mesh primitives type" ); + return false; + } + + // "Typed" Sequence + SmartPointer typedSequenceSQ; + if( !surfaceMeshPrimitivesDS.FindDataElement( typedSequenceTag ) ) + { + typedSequenceSQ = new SequenceOfItems; + DataElement detmp( typedSequenceTag ); + detmp.SetVR( VR::SQ ); + detmp.SetValue( *typedSequenceSQ ); + detmp.SetVLToUndefined(); + surfaceMeshPrimitivesDS.Insert( detmp ); + } + typedSequenceSQ = surfaceMeshPrimitivesDS.GetDataElement( typedSequenceTag ).GetValueAsSQ(); + typedSequenceSQ->SetLengthToUndefined(); + + // Fill the Segment Sequence + const unsigned int numberOfPrimitives = meshPrimitive->GetNumberOfPrimitivesData(); + assert( numberOfPrimitives ); + const size_t nbItems = typedSequenceSQ->GetNumberOfItems(); + if (nbItems < numberOfPrimitives) + { + const size_t diff = numberOfPrimitives - nbItems; + const size_t nbOfItemToMake = (diff > 0?diff:0); + for(unsigned int i = 1; i <= nbOfItemToMake; ++i) + { + Item item; + item.SetVLToUndefined(); + typedSequenceSQ->AddItem(item); + } + } + // else Should I remove items? + + const MeshPrimitive::PrimitivesData & primitivesData= meshPrimitive->GetPrimitivesData(); + MeshPrimitive::PrimitivesData::const_iterator it = primitivesData.begin(); + MeshPrimitive::PrimitivesData::const_iterator itEnd = primitivesData.end(); + unsigned int i = 1; + for (; it != itEnd; it++) + { + Item & typedSequenceItem = typedSequenceSQ->GetItem(i++); + DataSet & pointIndexListDS = typedSequenceItem.GetNestedDataSet(); + + // "Typed" Point Index List + DataElement typedPointIndexListDE( typedPrimitiveTag ); + + const Value & pointIndexListValue = it->GetValue(); + assert( &pointIndexListValue ); + typedPointIndexListDE.SetValue( pointIndexListValue ); + + const ByteValue * pointIndexListBV = typedPointIndexListDE.GetByteValue(); + VL pointIndexListVL; + if( pointIndexListBV ) + { + pointIndexListVL = pointIndexListBV->GetLength(); + } + else + { + pointIndexListVL.SetToUndefined(); + } + typedPointIndexListDE.SetVL( pointIndexListVL ); + + if ( ts.IsExplicit() ) + typedPointIndexListDE.SetVR( VR::OW ); + + pointIndexListDS.Replace( typedPointIndexListDE ); + } + } + else + { + // Handled "simple" mesh primitives + + // "Typed" Point Index List + DataElement typedPointIndexListDE( typedPrimitiveTag ); + + const Value & pointIndexListValue = meshPrimitive->GetPrimitiveData().GetValue(); + assert( &pointIndexListValue ); + typedPointIndexListDE.SetValue( pointIndexListValue ); + + const ByteValue * pointIndexListBV = typedPointIndexListDE.GetByteValue(); + VL pointIndexListVL; + if ( pointIndexListBV ) + pointIndexListVL = pointIndexListBV->GetLength(); + else + pointIndexListVL.SetToUndefined(); + typedPointIndexListDE.SetVL( pointIndexListVL ); + + if ( ts.IsExplicit() ) + typedPointIndexListDE.SetVR( VR::OW ); + + pointIndexListDS0.Replace( typedPointIndexListDE ); + } + } + ++numSurface; + } + + + //***** Segment Sequence *****// + SmartPointer segmentsSQ = ds.GetDataElement( Tag(0x0062, 0x0002) ).GetValueAsSQ(); + Item & segmentIt = segmentsSQ->GetItem( numSegment++ ); + DataSet & segmentDS = segmentIt.GetNestedDataSet(); + + //***** Referenced Surface Sequence *****// + SmartPointer refSurfaceSQ = segmentDS.GetDataElement( Tag(0x0066, 0x002B) ).GetValueAsSQ(); + SequenceOfItems::Iterator itRefSurface = refSurfaceSQ->Begin(); + SequenceOfItems::Iterator itEndRefSurface = refSurfaceSQ->End(); + unsigned int idxSurface = 0; + for (; itRefSurface != itEndRefSurface; itRefSurface++) + { + DataSet & refSurfaceDS = itRefSurface->GetNestedDataSet(); + SmartPointer< Surface > surface = segment->GetSurface( idxSurface++ ); + + //***** Segment Surface Generation Algorithm Identification Sequence *****// + { + SmartPointer segmentsAlgoIdSQ; + const Tag segmentsAlgoIdTag(0x0066, 0x002D); + if( !refSurfaceDS.FindDataElement( segmentsAlgoIdTag ) ) + { + segmentsAlgoIdSQ = new SequenceOfItems; + DataElement detmp( segmentsAlgoIdTag ); + detmp.SetVR( VR::SQ ); + detmp.SetValue( *segmentsAlgoIdSQ ); + detmp.SetVLToUndefined(); + refSurfaceDS.Insert( detmp ); + } + segmentsAlgoIdSQ = refSurfaceDS.GetDataElement( segmentsAlgoIdTag ).GetValueAsSQ(); + segmentsAlgoIdSQ->SetLengthToUndefined(); + + if (segmentsAlgoIdSQ->GetNumberOfItems() < 1) + { + Item item; + item.SetVLToUndefined(); + segmentsAlgoIdSQ->AddItem(item); + } + + ::gdcm::Item & segmentsAlgoIdItem = segmentsAlgoIdSQ->GetItem(1); + ::gdcm::DataSet & segmentsAlgoIdDS = segmentsAlgoIdItem.GetNestedDataSet(); + + //***** Algorithm Family Code Sequence *****// + //See: PS.3.3 Table 8.8-1 and PS 3.16 Context ID 7162 + const SegmentHelper::BasicCodedEntry & algoFamily = surface->GetAlgorithmFamily(); + if (algoFamily.IsEmpty()) + { + gdcmWarningMacro("Segment surface generation algorithm family not specified or incomplete"); + } + + SmartPointer algoFamilyCodeSQ; + const Tag algoFamilyCodeTag(0x0066, 0x002F); + + if( !segmentsAlgoIdDS.FindDataElement( algoFamilyCodeTag ) ) + { + algoFamilyCodeSQ = new SequenceOfItems; + DataElement detmp( algoFamilyCodeTag ); + detmp.SetVR( VR::SQ ); + detmp.SetValue( *algoFamilyCodeSQ ); + detmp.SetVLToUndefined(); + segmentsAlgoIdDS.Insert( detmp ); + } + + algoFamilyCodeSQ = segmentsAlgoIdDS.GetDataElement( algoFamilyCodeTag ).GetValueAsSQ(); + algoFamilyCodeSQ->SetLengthToUndefined(); + + // Fill the Algorithm Family Code Sequence + if (algoFamilyCodeSQ->GetNumberOfItems() < 1) + { + Item item; + item.SetVLToUndefined(); + algoFamilyCodeSQ->AddItem(item); + } + + ::gdcm::Item & algoFamilyCodeItem = algoFamilyCodeSQ->GetItem(1); + ::gdcm::DataSet & algoFamilyCodeDS = algoFamilyCodeItem.GetNestedDataSet(); + + //***** CODE SEQUENCE MACRO ATTRIBUTES *****// + { + // Code Value (Type 1) + Attribute<0x0008, 0x0100> codeValueAt; + codeValueAt.SetValue( algoFamily.CV ); + algoFamilyCodeDS.Replace( codeValueAt.GetAsDataElement() ); + + // Coding Scheme (Type 1) + Attribute<0x0008, 0x0102> codingSchemeAt; + codingSchemeAt.SetValue( algoFamily.CSD ); + algoFamilyCodeDS.Replace( codingSchemeAt.GetAsDataElement() ); + + // Code Meaning (Type 1) + Attribute<0x0008, 0x0104> codeMeaningAt; + codeMeaningAt.SetValue( algoFamily.CM ); + algoFamilyCodeDS.Replace( codeMeaningAt.GetAsDataElement() ); + } + + // Algorithm Version + const char * algorithmVersion = surface->GetAlgorithmVersion(); + if (strcmp(algorithmVersion, "") != 0) + { + gdcmWarningMacro("No algorithm version specified"); + } + Attribute<0x0066, 0x0031> algorithmVersionAt; + algorithmVersionAt.SetValue( algorithmVersion ); + segmentsAlgoIdDS.Replace( algorithmVersionAt.GetAsDataElement() ); + + // Algorithm Name + const char * algorithmName = surface->GetAlgorithmName(); + if (strcmp(algorithmName, "") != 0) + { + gdcmWarningMacro("No algorithm name specified"); + } + Attribute<0x0066, 0x0036> algorithmNameAt; + algorithmNameAt.SetValue( algorithmName ); + segmentsAlgoIdDS.Replace( algorithmNameAt.GetAsDataElement() ); + } + } + + } + + //** Complete the file **// + // Is SOP Class UID defined? + if( !ds.FindDataElement( Tag(0x0008, 0x0016) ) ) + { + const char * SOPClassUID = MediaStorage::GetMSString(MediaStorage::SurfaceSegmentationStorage); + + DataElement de( Tag(0x0008, 0x0016) ); + VL::Type strlenSOPClassUID= (VL::Type)strlen(SOPClassUID); + de.SetByteValue( SOPClassUID, strlenSOPClassUID ); + de.SetVR( Attribute<0x0008, 0x0016>::GetVR() ); + ds.ReplaceEmpty( de ); + } + + // Is SOP Instance UID defined? + if( !ds.FindDataElement( Tag(0x0008, 0x0018) ) ) + { + UIDGenerator UIDgen; + UIDgen.SetRoot( MediaStorage::GetMSString(MediaStorage::SurfaceSegmentationStorage) ); + const char * SOPInstanceUID = UIDgen.Generate(); + + DataElement de( Tag(0x0008, 0x0018) ); + VL::Type strlenSOPInstanceUID= (VL::Type)strlen(SOPInstanceUID); + de.SetByteValue( SOPInstanceUID, strlenSOPInstanceUID ); + de.SetVR( Attribute<0x0008, 0x0018>::GetVR() ); + ds.ReplaceEmpty( de ); + } + + fmi.Clear(); + { + const char *tsuid = TransferSyntax::GetTSString( ts ); + DataElement de( Tag(0x0002,0x0010) ); + VL::Type strlenTSUID = (VL::Type)strlen(tsuid); + de.SetByteValue( tsuid, strlenTSUID ); + de.SetVR( Attribute<0x0002, 0x0010>::GetVR() ); + fmi.Replace( de ); + fmi.SetDataSetTransferSyntax(ts); + } + fmi.FillFromDataSet( ds ); + + return true; +} + +bool SurfaceWriter::Write() +{ + if( !PrepareWrite() ) + { + return false; + } + + assert( Stream ); + if( !Writer::Write() ) + { + return false; + } + + return true; +} + +bool SurfaceWriter::PrepareWritePointMacro(SmartPointer< Surface > surface, + DataSet & surfaceDS, + const TransferSyntax & ts) +{ + //****** Surface Points *****// + // (0066,0011) SQ (Sequence with undefined length #=1) # u/l, 1 Surface Points Sequence + // (fffe,e000) na (Item with undefined length #=1) # u/l, 1 Item + // (0066,0015) UL # 0, 1 Number Of Surface Points + // (0066,0016) OW # 0, 1 Point Coordinates Data + // (fffe,e00d) na (ItemDelimitationItem) # 0, 0 ItemDelimitationItem + // (fffe,e0dd) na (SequenceDelimitationItem) # 0, 0 SequenceDelimitationItem + + //***** Surface Points Sequence *****// + { + SmartPointer surfacePointsSq; + if( !surfaceDS.FindDataElement( Tag(0x0066, 0x0011) ) ) + { + surfacePointsSq = new SequenceOfItems; + DataElement detmp( Tag(0x0066, 0x0011) ); + detmp.SetVR( VR::SQ ); + detmp.SetValue( *surfacePointsSq ); + detmp.SetVLToUndefined(); + surfaceDS.Insert( detmp ); + } + surfacePointsSq = surfaceDS.GetDataElement( Tag(0x0066, 0x0011) ).GetValueAsSQ(); + surfacePointsSq->SetLengthToUndefined(); + + if (surfacePointsSq->GetNumberOfItems() < 1) // One item shall be permitted + { + Item item; + item.SetVLToUndefined(); + surfacePointsSq->AddItem(item); + } + + Item & surfacePointsItem = surfacePointsSq->GetItem(1); + DataSet & surfacePointsDs = surfacePointsItem.GetNestedDataSet(); + + // Point Coordinates Data + DataElement pointCoordDataDE( Tag(0x0066, 0x0016) ); + const Value & pointCoordinateDataValue = surface->GetPointCoordinatesData().GetValue(); + assert( &pointCoordinateDataValue ); + pointCoordDataDE.SetValue( pointCoordinateDataValue ); + + const ByteValue *bv = pointCoordDataDE.GetByteValue(); + VL vl; + if ( bv ) + vl = bv->GetLength(); + else + vl.SetToUndefined(); + pointCoordDataDE.SetVL( vl ); + + if ( ts.IsExplicit() ) + pointCoordDataDE.SetVR( VR::OF ); + + surfacePointsDs.Replace( pointCoordDataDE ); + + // Number Of Surface Points + Attribute<0x0066, 0x0015> numberOfSurfacePointsAt; + unsigned long numberOfSurfacePoints = surface->GetNumberOfSurfacePoints(); + if (numberOfSurfacePoints == 0) + numberOfSurfacePoints = bv->GetLength() / (VR::GetLength(VR::OF) * 3); + numberOfSurfacePointsAt.SetValue( (unsigned int)numberOfSurfacePoints ); + surfacePointsDs.Replace( numberOfSurfacePointsAt.GetAsDataElement() ); + + // Point Position Accuracy (Type 3) + Attribute<0x0066, 0x0017> pointPositionAccuracyAt; + const float * pointPositionAccuracy = surface->GetPointPositionAccuracy(); + if (pointPositionAccuracy != 0) + { + pointPositionAccuracyAt.SetValues( pointPositionAccuracy ); + surfacePointsDs.Replace( pointPositionAccuracyAt.GetAsDataElement() ); + } + + // Mean Point Distance (Type 3) + Attribute<0x0066, 0x0018> meanPointDistanceAt; + float meanPointDistance = surface->GetMeanPointDistance(); + if (meanPointDistance != 0) // FIXME: user can specified 0 value + { + meanPointDistanceAt.SetValue( meanPointDistance ); + surfacePointsDs.Replace( meanPointDistanceAt.GetAsDataElement() ); + } + + // Maximum Point Distance (Type 3) + Attribute<0x0066, 0x0019> maximumPointDistanceAt; + float maximumPointDistance = surface->GetMaximumPointDistance(); + if (maximumPointDistance != 0) // FIXME: user can specified 0 value + { + maximumPointDistanceAt.SetValue( maximumPointDistance ); + surfacePointsDs.Replace( maximumPointDistanceAt.GetAsDataElement() ); + } + + // Point Bounding Box Coordinates (Type 3) + Attribute<0x0066, 0x001a> pointsBoundingBoxCoordinatesAt; + const float * pointsBoundingBoxCoordinates = surface->GetPointsBoundingBoxCoordinates(); + if (pointsBoundingBoxCoordinates != 0) + { + pointsBoundingBoxCoordinatesAt.SetValues( pointsBoundingBoxCoordinates ); + surfacePointsDs.Replace( pointsBoundingBoxCoordinatesAt.GetAsDataElement() ); + } + + // Axis of Rotation (Type 3) + Attribute<0x0066, 0x001b> axisOfRotationAt; + const float * axisOfRotation = surface->GetAxisOfRotation(); + if (axisOfRotation != 0) + { + axisOfRotationAt.SetValues( axisOfRotation ); + surfacePointsDs.Replace( axisOfRotationAt.GetAsDataElement() ); + } + + // Center of Rotation (Type 3) + Attribute<0x0066, 0x001c> centerOfRotationAt; + const float * centerOfRotation = surface->GetCenterOfRotation(); + if (centerOfRotation != 0) + { + centerOfRotationAt.SetValues( centerOfRotation ); + surfacePointsDs.Replace( centerOfRotationAt.GetAsDataElement() ); + } + + return true; + } +} + +} diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmSurfaceWriter.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmSurfaceWriter.h new file mode 100644 index 0000000..20f6918 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmSurfaceWriter.h @@ -0,0 +1,62 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMSURFACEWRITER_H +#define GDCMSURFACEWRITER_H + +#include +#include + +namespace gdcm +{ + +/** + * \brief This class defines a SURFACE IE writer. + * It writes surface mesh module attributes. + * + * \see PS 3.3 A.1.2.18 , A.57 and C.27 + */ +class GDCM_EXPORT SurfaceWriter : public SegmentWriter +{ +public: + SurfaceWriter(); + + virtual ~SurfaceWriter(); + +// const Surface & GetSurface() const { return *SurfaceData; } +// Surface & GetSurface() { return *SurfaceData; } +// void SetSurface(Surface const & segment); + + /// Write + bool Write(); // Execute() + + unsigned long GetNumberOfSurfaces(); + void SetNumberOfSurfaces(const unsigned long nb); + +protected: + + bool PrepareWrite(); + + void ComputeNumberOfSurfaces(); + + bool PrepareWritePointMacro(SmartPointer< Surface > surface, + DataSet & surfaceDS, + const TransferSyntax & ts); + + //0066 0001 UL 1 Number of Surfaces + unsigned long NumberOfSurfaces; +}; + +} + +#endif // GDCMSURFACEWRITER_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmTagPath.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmTagPath.cxx new file mode 100644 index 0000000..ef934e2 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmTagPath.cxx @@ -0,0 +1,155 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmTagPath.h" +#include "gdcmTag.h" + +#include +#include // strlen +#include // abort +#include // sscanf + +namespace gdcm +{ + +/* + * Implementation detail: a tag path is simply a vector. + * with the following convention: + * First tag is a valid tag, + * Second tag is an item number (or 0) + * Third tag is a valid tag + * ... + * and so on an so forth + */ + +TagPath::TagPath():Path() +{ +} + +TagPath::~TagPath() +{ +} + +void TagPath::Print(std::ostream &os) const +{ + unsigned int flip = 0; + std::vector::const_iterator it = Path.begin(); + for(; it != Path.end(); ++it) + { + if( flip % 2 == 0 ) + { + os << *it << "/"; + } + else // item number + { + // assert( it->GetElementTag() < 255 ); // how many item max can we have ? + os << it->GetElementTag() << "/"; + } + ++flip; + } +} + +bool TagPath::IsValid(const char *path) +{ + TagPath tp; + return tp.ConstructFromString(path); +} + +bool TagPath::ConstructFromTagList(Tag const *l, unsigned int n) +{ + //Path = std::vector(l,l+n); + Path.clear(); + for(unsigned int i = 0; i < n; ++i) + { + Path.push_back( l[i] ); + if( i+1 < n ) + { + Path.push_back( 0 ); + } + } + return true; +} + +bool TagPath::ConstructFromString(const char *path) +{ + Path.clear(); + if(!path) return false; + unsigned int flip = 0; + size_t pos = 0; + const size_t len = strlen(path); + if(!len) return false; + // Need to start with a / + if( path[pos] == '/' ) + { + ++pos; + } + else + { + return false; + } + while( pos != len ) + { + Tag t; + if( flip % 2 == 0 ) + { + if( t.ReadFromCommaSeparatedString( path+pos ) ) + { + pos += 4 + 4 + 1; + Path.push_back( t ); + } + else + { + return false; + } + } + else + { + unsigned int value = 0; + if( path[pos] == '*' ) + { + t.SetElementTag( 0 ); + pos++; + Path.push_back( t ); + } + else if( sscanf(path+pos, "%d/", &value) == 1 ) + { + } + } + ++flip; + if( pos != len && path[pos] == '/' ) ++pos; + //else assert(0); + } + return true; +} + +bool TagPath::Push(Tag const & t) +{ + if( Path.size() % 2 == 0 ) + { + Path.push_back( t ); + return true; + } + return false; +} + +bool TagPath::Push(unsigned int itemnum) +{ + if( Path.size() % 2 == 1 ) + { + Path.push_back( itemnum ); + return true; + } + return false; +} + +} diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmTagPath.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmTagPath.h new file mode 100644 index 0000000..f98fa72 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmTagPath.h @@ -0,0 +1,58 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMTAGPATH_H +#define GDCMTAGPATH_H + +#include "gdcmTag.h" + +#include + +namespace gdcm +{ + +/** + * \brief class to handle a path of tag. + * + * Any Resemblance to Existing XPath is Purely Coincidental + * ftp://medical.nema.org/medical/dicom/supps/sup118_pc.pdf + */ +class GDCM_EXPORT TagPath +{ +public: + TagPath(); + ~TagPath(); + void Print(std::ostream &) const; + + /// "/0018,0018/"... + /// No space allowed, comma is use to separate tag group + /// from tag element and slash is used to separate tag + /// return false if invalid + bool ConstructFromString(const char *path); + + /// Return if path is valid or not + static bool IsValid(const char *path); + + /// Construct from a list of tags + bool ConstructFromTagList(Tag const *l, unsigned int n); + + bool Push(Tag const & t); + bool Push(unsigned int itemnum); + +private: + std::vector Path; +}; + +} // end namespace gdcm + +#endif //GDCMTAGPATH_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmUIDGenerator.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmUIDGenerator.cxx new file mode 100644 index 0000000..e0d90c9 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmUIDGenerator.cxx @@ -0,0 +1,253 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmUIDGenerator.h" +#include "gdcmTrace.h" +#include "gdcmSystem.h" + +#include +#include + +// FIXME... +#if defined(_WIN32) || defined(__CYGWIN__) +#define HAVE_UUIDCREATE +#else +#define HAVE_UUID_GENERATE +#endif + +#ifdef HAVE_UUID_GENERATE +#include "gdcm_uuid.h" +#endif + +#ifdef GDCM_HAVE_RPC_H +#include +#endif + +namespace gdcm +{ + +/* + * This is just plain bad luck. GDCM UID root is 26 byte long + * And all implementation of the DCE UUID (Theodore Y. Ts'o) + * are based on a uint128_t (unsigned char [16]). Which + * means that converted to a base 10 number they require at + * least 39 bytes to fit in memory, since the highest possible + * number is 256**16 - 1 = 340282366920938463463374607431768211455 + * Unfortunately root + '.' + suffix should be at most 64 bytes + * + * So to get a full UUID implementation as per RFC 4122 + * http://www.ietf.org/rfc/rfc4122.txt we need a shorter + * root... + * + */ +const char UIDGenerator::GDCM_UID[] = "1.2.826.0.1.3680043.2.1143"; +std::string UIDGenerator::Root = GetGDCMUID(); +// The following contains the *encoded* hardware address (not the raw as in ipconfig/ifconfig) +std::string UIDGenerator::EncodedHardwareAddress; // = System::GetHardwareAddress(); + +const char *UIDGenerator::GetRoot() { return Root.c_str(); } +void UIDGenerator::SetRoot(const char * root) { + assert( IsValid( root ) ); + Root = root; +} + +const char *UIDGenerator::GetGDCMUID() +{ + return GDCM_UID; +} + +/* + * http://www.isthe.com/chongo/tech/comp/fnv/ + */ +#define FNV1_64_INIT ((uint64_t)0xcbf29ce484222325ULL) +struct fnv_hash +{ + static uint64_t + hash(const char* pBuffer, size_t nByteLen) + { + uint64_t nHashVal = FNV1_64_INIT, + nMagicPrime = 0x00000100000001b3ULL; + + unsigned char* pFirst = ( unsigned char* )( pBuffer ), + * pLast = pFirst + nByteLen; + + while( pFirst < pLast ) + { + nHashVal ^= *pFirst++, + nHashVal *= nMagicPrime; + } + + return nHashVal; + } +}; + +/* +Implementation note: You cannot set a root of more than 26 bytes (which should already +enough for most people). +Since implementation is only playing with the first 8bits of the upper +*/ +const char* UIDGenerator::Generate() +{ + Unique = GetRoot(); + // We choose here a value of 26 so that we can still have 37 bytes free to + // set the suffix part which is sufficient to store a 2^(128-8+1)-1 number + if( Unique.empty() || Unique.size() > 62 ) // 62 is simply the highest possible limit + { + // I cannot go any further... + return NULL; + } + unsigned char uuid[16]; + bool r = UIDGenerator::GenerateUUID(uuid); + // This should only happen in some obscure cases. Since the creation of UUID failed + // I should try to go any further and make sure the user's computer crash and burn + // right away + if( !r ) return 0; + char randbytesbuf[64]; + size_t len = System::EncodeBytes(randbytesbuf, uuid, sizeof(uuid)); + assert( len < 64 ); // programmer error + Unique += "."; // This dot is compulsary to separate root from suffix + if( Unique.size() + len > 64 ) + { + int idx = 0; + bool found = false; + std::bitset<8> x; + while( !found && idx < 16 ) /* 16 is insane ... oh well */ + { + // too bad ! randbytesbuf is too long, let's try to truncate the high bits a little + x = uuid[idx]; + unsigned int i = 0; + while( ( Unique.size() + len > 64 ) && i < 8 ) + { + x[7-i] = 0; + uuid[idx] = (unsigned char)x.to_ulong(); + len = System::EncodeBytes(randbytesbuf, uuid, sizeof(uuid)); + ++i; + } + if( ( Unique.size() + len > 64 ) && i == 8 ) + { + // too bad only reducing the 8 bits from uuid[idx] was not enought, + // let's set to zero the following bits... + idx++; + } + else + { + // cool we found enough to stop + found = true; + } + } + if( !found ) + { + // Technically this could only happen when root has a length >= 64 ... is it + // even remotely possible ? + gdcmWarningMacro( "Root is too long for current implementation" ); + return NULL; + } + } + // can now safely use randbytesbuf as is, no need to truncate any more: + Unique += randbytesbuf; + + assert( IsValid( Unique.c_str() ) ); + + return Unique.c_str(); +} + + +/* return true on success */ +bool UIDGenerator::GenerateUUID(unsigned char *uuid_data) +{ +#if defined(HAVE_UUID_GENERATE) + uuid_t g; + uuid_generate(g); + memcpy(uuid_data, g, sizeof(uuid_t)); +#elif defined(HAVE_UUID_CREATE) + uint32_t rv; + uuid_t g; + uuid_create(&g, &rv); + if (rv != uuid_s_ok) + return false; + memcpy(uuid_data, &g, sizeof(uuid_t)); +#elif defined(HAVE_UUIDCREATE) + if (FAILED(UuidCreate((UUID *)uuid_data))) + { + return false; + } +#else +#error should not happen +#endif + return true; +} + +bool UIDGenerator::IsValid(const char *uid_) +{ + /* + 9.1 UID ENCODING RULES + The DICOM UID encoding rules are defined as follows: + - Each component of a UID is a number and shall consist of one or more digits. The first digit of + each component shall not be zero unless the component is a single digit. + Note: Registration authorities may distribute components with non-significant leading zeroes. The leading + zeroes should be ignored when being encoded (ie. 00029 would be encoded 29). + - Each component numeric value shall be encoded using the characters 0-9 of the Basic G0 Set + of the International Reference Version of ISO 646:1990 (the DICOM default character + repertoire). + - Components shall be separated by the character "." (2EH). + - If ending on an odd byte boundary, except when used for network negotiation (See PS 3.8), + one trailing NULL (00H), as a padding character, shall follow the last component in order to + align the UID on an even byte boundary. + - UID's, shall not exceed 64 total characters, including the digits of each component, separators + between components, and the NULL (00H) padding character if needed. + */ + + /* + * FIXME: This is not clear in the standard, but I believe a trailing '.' is not allowed since + * this is considered as a separator for components + */ + + std::string uid = uid_; + if( uid.size() > 64 || uid.empty() ) + { + return false; + } + if( uid[0] == '.' || uid[uid.size()-1] == '.' ) // important to do that first + { + return false; + } + std::string::size_type i = 0; + for(; i < uid.size(); ++i) + { + if( uid[i] == '.' ) // if test is true we are garantee that next char is valid (see previous check) + { + // check that next character is neither '0' (except single number) not '.' + if( uid[i+1] == '.' ) + { + return false; + } + else if( uid[i+1] == '0' ) // character is garantee to exist since '.' is not last char + { + // Need to check first if we are not at the end of string + if( i+2 != uid.size() && uid[i+2] != '.' ) + { + return false; + } + } + } + else if ( !isdigit( (unsigned char)uid[i] ) ) + { + return false; + } + } + // no error found ! + return true; +} + + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmUIDGenerator.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmUIDGenerator.h new file mode 100644 index 0000000..8318d1d --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmUIDGenerator.h @@ -0,0 +1,87 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMUIDGENERATOR_H +#define GDCMUIDGENERATOR_H + +#include "gdcmTypes.h" + +namespace gdcm +{ + +/** + * \brief Class for generating unique UID + * \note bla + * Usage: + * When constructing a Series or Study UID, user *has* to keep around the UID, + * otherwise the UID Generator will simply forget the value and create a new UID. + */ +class GDCM_EXPORT UIDGenerator +{ +public: + /// By default the root of a UID is a GDCM Root... + UIDGenerator():Unique() {} + + // Function to override the GDCM root with a user one: + // WARNING: This need to be a valid root, otherwise call will fail + // Implementation note. According to DICOM standard PS 3.5, Section 9 : + // Unique Identifiers (UIDs), we have: + /* + ... + The portion of the UID uniquely identifies an organization, (i.e., manufacturer, research + organization, NEMA, etc.), and is composed of a number of numeric components as defined by ISO 8824. + The portion of the UID is also composed of a number of numeric components, and shall be + unique within the scope of the . This implies that the organization identified in the is + responsible for guaranteeing uniqueness by providing registration policies. These policies shall + guarantee uniqueness for all UID's created by that organization. Unlike the , which may + be common for UID's in an organization, the shall take different unique values between different + UID's that identify different objects. + ... + */ + /// The current implementation in GDCM make use of the UUID implementation (RFC 4122) and has been + /// successfully been tested for a root of size 26 bytes. Any longer root should work (the Generate() + /// function will return a string), but will truncate the high bits of the 128bits UUID until the + /// generated string fits on 64 bits. The authors disclaims any + /// responsabitlity for garanteeing uniqueness of UIDs when the root is longer than 26 bytes. + static void SetRoot(const char * root); + static const char *GetRoot(); + + /// Internally uses a std::string, so two calls have the same pointer ! + /// save into a std::string + /// In summary do not write code like that: + /// const char *uid1 = uid.Generate(); + /// const char *uid2 = uid.Generate(); + /// since uid1 == uid2 + const char* Generate(); + + /// Find out if the string is a valid UID or not + /// \todo: Move that in DataStructureAndEncoding (see FileMetaInformation::CheckFileMetaInformation) + static bool IsValid(const char *uid); + + /// Return the default (GDCM) root UID: + static const char *GetGDCMUID(); // who would want that in the public API ?? + +protected: + static bool GenerateUUID(unsigned char *uuid_data); + +private: + static const char GDCM_UID[]; + static std::string Root; + static std::string EncodedHardwareAddress; + std::string Unique; // Buffer +}; + + +} // end namespace gdcm + +#endif //GDCMUIDGENERATOR_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmUUIDGenerator.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmUUIDGenerator.cxx new file mode 100644 index 0000000..f9b24c8 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmUUIDGenerator.cxx @@ -0,0 +1,99 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmUUIDGenerator.h" +#include "gdcmTrace.h" +#include "gdcmSystem.h" + +#include // memcpy + +// FIXME... +#if defined(_WIN32) || defined(__CYGWIN__) +#define HAVE_UUIDCREATE +#else +#define HAVE_UUID_GENERATE +#endif + +#ifdef HAVE_UUID_GENERATE +#include "gdcm_uuid.h" +#endif + +#ifdef GDCM_HAVE_RPC_H +#include +#endif + +namespace gdcm +{ + +const char* UUIDGenerator::Generate() +{ + Unique.resize( 36 ); + char *uuid_data = &Unique[0]; +#if defined(HAVE_UUID_GENERATE) + assert( sizeof(uuid_t) == 16 ); + uuid_t g; + uuid_generate(g); + uuid_unparse(g, uuid_data); +#elif defined(HAVE_UUID_CREATE) + uint32_t rv; + uuid_t g; + uuid_create(&g, &rv); + if (rv != uuid_s_ok) return NULL; + uuid_to_string(&g, &uuid_data, &rv); + if (rv != uuid_s_ok) return NULL; +#elif defined(HAVE_UUIDCREATE) + UUID uuid; + UuidCreate(&uuid); + BYTE * str = 0; + UuidToString(&uuid, &str); + Unique = (char*)str; + RpcStringFree(&str); +#else +#error should not happen +#endif + assert( IsValid( Unique.c_str() ) ); + + return Unique.c_str(); +} + +bool UUIDGenerator::IsValid(const char *suid) +{ + if( !suid ) return false; +#if defined(HAVE_UUID_GENERATE) + uuid_t uu; + // technically the specification wants char* input not const char*: + // this makes compilation fails otherwise on OpenIndiana: + int res = uuid_parse((char*)suid, uu); + if( res ) return false; +#elif defined(HAVE_UUID_CREATE) + // http://www.freebsd.org/cgi/man.cgi?query=uuid_create + uint32_t status; + uuid_t uuid; + uuid_from_string(suid, &uuid, &status); + if( status != uuid_s_ok ) return false; +#elif defined(HAVE_UUIDCREATE) + // http://msdn.microsoft.com/en-us/library/windows/desktop/aa379336(v=vs.85).aspx + UUID uuid; + if (FAILED(UuidFromString((unsigned char*)suid, &uuid))) + { + return false; + } +#else +#error should not happen +#endif + // no error found ! + return true; +} + + +} // end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmUUIDGenerator.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmUUIDGenerator.h new file mode 100644 index 0000000..222b51b --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmUUIDGenerator.h @@ -0,0 +1,42 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMUUIDGENERATOR_H +#define GDCMUUIDGENERATOR_H + +#include "gdcmTypes.h" + +namespace gdcm +{ + +/** + * \brief Class for generating unique UUID + * generate DCE 1.1 uid + */ +class GDCM_EXPORT UUIDGenerator +{ +public: + /// Return the generated uuid + /// NOT THREAD SAFE + const char* Generate(); + + /// Find out if the string is a valid UUID or not + static bool IsValid(const char *uid); + +private: + std::string Unique; // Buffer +}; + +} // end namespace gdcm + +#endif //GDCMUUIDGENERATOR_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmValidate.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmValidate.cxx new file mode 100644 index 0000000..b3ec47a --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmValidate.cxx @@ -0,0 +1,43 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmValidate.h" + +namespace gdcm +{ +//----------------------------------------------------------------------------- +Validate::Validate():F(0) +{ +} +//----------------------------------------------------------------------------- +Validate::~Validate() +{ +} + +//----------------------------------------------------------------------------- +void Validate::Validation() +{ + if(!F) return; + V.GetHeader().SetPreamble( F->GetHeader().GetPreamble() ); + //FileMetaInformation &fmi = F.GetHeader(); + FileMetaInformation fmi( F->GetHeader() ); + fmi.FillFromDataSet( F->GetDataSet() ); + std::cout << "Validation" << std::endl; + //std::cout << fmi << std::endl; + //std::cout << fmi.GetDataElement( Tag(0x0002, 0x0002) ) << std::endl; + V.SetHeader( fmi ); + V.SetDataSet( F->GetDataSet() ); + //std::cout << V.GetHeader() << std::endl; +} + +} diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmValidate.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmValidate.h new file mode 100644 index 0000000..d5596ad --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmValidate.h @@ -0,0 +1,43 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMVALIDATE_H +#define GDCMVALIDATE_H + +#include "gdcmFile.h" + +namespace gdcm +{ + +/** + * \brief Validate class + */ +class GDCM_EXPORT Validate +{ +public: + Validate(); + ~Validate(); + + void SetFile(File const &f) { F = &f; } + const File& GetValidatedFile() { return V; } + + void Validation(); + +protected: + const File *F; + File V; // Validated file +}; + +} // end namespace gdcm + +#endif //GDCMVALIDATE_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmWaveform.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmWaveform.cxx new file mode 100644 index 0000000..47e4793 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmWaveform.cxx @@ -0,0 +1,17 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmWaveform.h" + +namespace gdcm +{} diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmWaveform.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmWaveform.h new file mode 100644 index 0000000..b9588a4 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmWaveform.h @@ -0,0 +1,34 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMWAVEFORM_H +#define GDCMWAVEFORM_H + +#include "gdcmFile.h" + +namespace gdcm +{ +/** + * \brief Waveform class + */ +class GDCM_EXPORT Waveform +{ +public: + Waveform() {} + +private: +}; + +} // end namespace gdcm + +#endif //GDCMWAVEFORM_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmXMLPrinter.cxx b/gdcm/Source/MediaStorageAndFileFormat/gdcmXMLPrinter.cxx new file mode 100644 index 0000000..7a5131c --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmXMLPrinter.cxx @@ -0,0 +1,583 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#include "gdcmXMLPrinter.h" +#include "gdcmSequenceOfItems.h" +#include "gdcmSequenceOfFragments.h" +#include "gdcmDict.h" +#include "gdcmDicts.h" +#include "gdcmGroupDict.h" +#include "gdcmVR.h" +#include "gdcmVM.h" +#include "gdcmElement.h" +#include "gdcmGlobal.h" +#include "gdcmAttribute.h" +#include "gdcmDataSetHelper.h" +#include "gdcmUUIDGenerator.h" + +#include "gdcmDataSet.h" + +#include + + +namespace gdcm +{ +//----------------------------------------------------------------------------- +XMLPrinter::XMLPrinter():PrintStyle(XMLPrinter::OnlyUUID),F(0) +{ +} + +//----------------------------------------------------------------------------- +XMLPrinter::~XMLPrinter() +{ +} + +// Carried forward from Printer Class +// SIEMENS_GBS_III-16-ACR_NEMA_1.acr is a tough kid: 0009,1131 is supposed to be VR::UL, but +// there are only two bytes... + +VR XMLPrinter::PrintDataElement(std::ostream &os, const Dicts &dicts, const DataSet & ds, + const DataElement &de, const TransferSyntax & ts) +{ + + const ByteValue *bv = de.GetByteValue(); + const SequenceOfItems *sqi = 0; + const Value &value = de.GetValue(); + const SequenceOfFragments *sqf = de.GetSequenceOfFragments(); + + std::string strowner; + const char *owner = 0; + const Tag& t = de.GetTag(); + UUIDGenerator UIDgen; + + if( t.IsPrivate() && !t.IsPrivateCreator() ) + { + strowner = ds.GetPrivateCreator(t); + owner = strowner.c_str(); + } + const DictEntry &entry = dicts.GetDictEntry(t,owner); + const VR &vr = entry.GetVR(); + const VM &vm = entry.GetVM(); + (void)vm; + const char *name = entry.GetKeyword(); + bool retired = entry.GetRetired(); + + const VR &vr_read = de.GetVR(); + const VL &vl_read = de.GetVL(); + + //Printing Tag + + + os << " tag = \"" << std::uppercase << std::hex << std::setw(4) << std::setfill('0') << + t.GetGroup() << std::setw(4) << t.GetElement() << std::nouppercase <<"\"" << std::dec; + + //Printing Private Creator + if( owner && *owner ) + { + os << " privateCreator = \"" << owner << "\" "; + } + + VR refvr; + + // Prefer the vr from the file: + + if( vr_read == VR::INVALID ) + { + refvr = vr; + } + else if ( vr_read == VR::UN && vr != VR::INVALID ) // File is explicit, but still prefer vr from dict when UN + { + refvr = vr; + } + else // The file is Explicit ! + { + refvr = vr_read; + } + + if( refvr.IsDual() ) // This means vr was read from a dict entry: + { + refvr = DataSetHelper::ComputeVR(*F,ds, t); + } + + //as DataSetHelper would have been called + assert( refvr != VR::US_SS ); + assert( refvr != VR::OB_OW ); + + if( dynamic_cast( &value ) ) + { + sqi = de.GetValueAsSQ(); + refvr = VR::SQ; + assert( refvr == VR::SQ ); + } +#if 0 + else if( vr == VR::SQ && vr_read != VR::SQ ) + { + sqi = de.GetValueAsSQ(); + refvr = VR::SQ; + assert( refvr == VR::SQ ); + } +#endif + + if( (vr_read == VR::INVALID || vr_read == VR::UN ) && vl_read.IsUndefined() ) + { + assert( refvr == VR::SQ ); + } + +// if( vr_read == VR::SQ || vr_read == VR::UN ) +// { +// sqi = de.GetValueAsSQ(); +// } + if( vr != VR::INVALID && (!vr.Compatible( vr_read ) || vr_read == VR::INVALID || vr_read == VR::UN ) ) + { + assert( vr != VR::INVALID ); + + /* + No need as we will save only the VR to which it is stored by GDCM in the XML file + + if( vr == VR::US_SS || vr == VR::OB_OW ) + { + os << "(" << vr << " => " << refvr << ") "; + } + else + { + os << "(" << vr << ") "; + } + */ + + } + else if( sqi /*de.GetSequenceOfItems()*/ && refvr == VR::INVALID ) + { + // when vr == VR::INVALID and vr_read is also VR::INVALID, we have a seldom case where we can guess + // the vr + // eg. CD1/647662/647663/6471066 has a SQ at (2001,9000) + + assert( refvr == VR::INVALID ); + refvr = VR::SQ; + } + + if(refvr == VR::INVALID) + refvr = VR::UN; + + // Printing the VR -- Value Representation + os << " vr = \"" << refvr << "\" "; + + // Add the keyword attribute : + + if( t.IsPublic()) + { + if( name && *name ) + { + os <<"keyword = \""; + + /* No owner */ + if( t.IsPrivate() && (owner == 0 || *owner == 0 ) && !t.IsPrivateCreator() ) + { + //os << name; + //os = PrintXML_char(os,name); + } + /* retired element */ + else if( retired ) + { + assert( t.IsPublic() || t.GetElement() == 0x0 ); // Is there such thing as private and retired element ? + //os << name; + //os = PrintXML_char(os,name); + } + /* Public element */ + else + { + //os << name; + //os = PrintXML_char(os,name); + } + + char c; + for (; (*name)!='\0'; name++) + { + c = *name; + if(c == '&') + os << "&"; + else if(c == '<') + os << "<"; + else if(c == '>') + os << ">"; + else if(c == '\'') + os << "'"; + else if(c == '\"') + os << """; + else + os << c; + } + os << "\""; + } + else + { + if( t.IsPublic() ) + { + gdcmWarningMacro( "An unknown public element."); + } + // os << ""; // Special keyword + } + } + os << ">\n"; + +#define StringFilterCase(type) \ + case VR::type: \ + { \ + Element el; \ + if( !de.IsEmpty() ) { \ + el.Set( de.GetValue() ); \ + if( el.GetLength() ) { \ + os << "" ;os << "" << el.GetValue();os << "\n"; \ + const uint32_t l = (uint32_t)el.GetLength(); \ + for(uint32_t i = 1; i < l; ++i) \ + { \ + os << "" ;\ + os << el.GetValue(i);os << "\n";} \ + } \ + else { if( de.IsEmpty() ) \ + {} } } \ + else { assert( de.IsEmpty()); } \ + } break + + + // Print Value now: + + //Handle PN first, acc. to Standard + if(refvr == VR::PN) + { + if( bv ) + { + bv->PrintPNXML(os); //new function to print each value in new child tag + } + else + { + assert( de.IsEmpty() ); + } + } + else if( refvr & VR::VRASCII ) + { + //assert( !sqi && !sqf); + assert(!sqi); + if( bv ) + { + bv->PrintASCIIXML(os); //new function to print each value in new child tag + } + else + { + assert( de.IsEmpty() ); + } + } + else + { + assert( refvr & VR::VRBINARY || (vr == VR::INVALID && refvr == VR::INVALID) ); + std::string s; + switch(refvr) + { + StringFilterCase(AT); + StringFilterCase(FL); + StringFilterCase(FD); + StringFilterCase(OF); + StringFilterCase(SL); + StringFilterCase(SS); + StringFilterCase(UL); + StringFilterCase(US); + case VR::OB: + case VR::OW: + case VR::OB_OW: + case VR::UN: + case VR::US_SS_OW: + { + if ( bv ) + { + if(PrintStyle) + { + bv->PrintHexXML(os); + } + else + { + if(bv->GetLength()) + { + const char *suid = UIDgen.Generate(); + os << "\n"; + HandleBulkData( suid, ts, bv->GetPointer(), bv->GetLength() ); + } + } + } + else if ( sqf ) + { + assert( t == Tag(0x7fe0,0x0010) ); + } + else if ( sqi ) + { + gdcmErrorMacro( "Should not happen: VR=UN but contains a SQ" ); + } + else + { + assert( !sqi && !sqf ); + assert( de.IsEmpty() ); + } + } + break; + case VR::US_SS: + assert( refvr != VR::US_SS ); + break; + case VR::SQ://The below info need not be printed into the XML infoset acc. to the standard + if( !sqi && !de.IsEmpty() && de.GetValue().GetLength() ) + { + } + else + { + if( vl_read.IsUndefined() ) + { + //os << "(Sequence with undefined length)"; + } + else + { + //os << "(Sequence with defined length)"; + } + } + break; + case VR::INVALID: + if( bv ) + { + if(PrintStyle) + bv->PrintHexXML(os); + else + { + if(bv->GetLength()) + { + const char *suid = UIDgen.Generate(); + os << "\n"; + HandleBulkData( suid, ts, bv->GetPointer(), bv->GetLength() ); + } + } + } + else + { + assert( !sqi && !sqf ); + assert( de.IsEmpty() ); + } + break; + default: + assert(0 && "No Match! Impossible!!"); + break; + } + } + + //os << "\n"; + return refvr; +} + +void XMLPrinter::PrintSQ(const SequenceOfItems *sqi, const TransferSyntax & ts, std::ostream & os) +{ + if( !sqi ) return; + + int noItems = 1; + + SequenceOfItems::ItemVector::const_iterator it = sqi->Items.begin(); + for(; it != sqi->Items.end(); ++it) + { + const Item &item = *it; + const DataSet &ds = item.GetNestedDataSet(); + //const DataElement &deitem = item; + /* + os << "> 8) << "\" "; + os << " VR = \"UN\" keyword = "; + + if( deitem.GetVL().IsUndefined() ) + { + os << "\"ItemWithUndefinedLength\""; + } + else + { + os << "\"ItemWithDefinedLength\""; + } + os << ">\n"; + */ + os << "\n"; + PrintDataSet(ds, ts, os); + /* + if( deitem.GetVL().IsUndefined() ) + { + os << "\n"; + } + os << "\n\n"; + */ + os << "\n"; + } + /* + if( sqi->GetLength().IsUndefined() ) + { + os << "\n"; + } + */ +} + +void XMLPrinter::PrintDataSet(const DataSet &ds, const TransferSyntax & ts, std::ostream &os) +{ + const Global& g = GlobalInstance; + const Dicts &dicts = g.GetDicts(); + const Dict &d = dicts.GetPublicDict(); (void)d; + + DataSet::ConstIterator it = ds.Begin(); + UUIDGenerator UIDgen; + + for( ; it != ds.End(); ++it ) + { + const DataElement &de = *it; + + const SequenceOfFragments *sqf = de.GetSequenceOfFragments(); + + os << " sqi2 = de.GetValueAsSQ(); + PrintSQ(sqi2, ts, os); + } + else if ( sqf ) + { + /*I have appended all fragments into one by calling the GetBuffer method in + gdcmSequenceOfFragments which does not write the Table to the buffer. + It is slightly buggy as the size returnes includes that of the table. + Should I get the Table size and subtract it? + Or should I append the table as well in the BulkData?? + */ + unsigned long size = sqf->ComputeByteLength(); + char *bulkData = new char [size]; + if(sqf->GetBuffer(bulkData, size)) + { + if(size) + { + const char *suid = UIDgen.Generate(); + os << "\n"; + HandleBulkData( suid, ts, bulkData, size); + } + } + /* + const BasicOffsetTable & table = sqf->GetTable(); + const ByteValue *bv = table.GetByteValue(); + + if(bv->GetLength()) + { + const char *suid = UIDgen.Generate(); + os << "\n"; + HandleBulkData( suid, ts, bv->GetPointer(), bv->GetLength() ); + } + + unsigned int numfrag = sqf->GetNumberOfFragments(); + for(unsigned int i = 0; i < numfrag; i++) + { + const Fragment& frag = sqf->GetFragment(i); + const ByteValue *bv = frag.GetByteValue(); + if(bv->GetLength()) + { + const char *suid = UIDgen.Generate(); + os << "\n"; + HandleBulkData( suid, ts, bv->GetPointer(), bv->GetLength() ); + } + } + */ + } + else + { + // This is a byte value, so it should have been already treated. + } + os << "\n"; + } +} + + + +/*------------------------------------------------------------------------------------------------------------------------------------------------*/ + +void XMLPrinter::Print(std::ostream& os) +{ + /* XML Meta Info */ + const Tag CharacterEncoding(0x0008,0x0005); + + const DataSet &ds = F->GetDataSet(); + const FileMetaInformation &header = F->GetHeader(); + const TransferSyntax &ts = header.GetDataSetTransferSyntax(); + + os << " at; + at.SetFromDataElement( de ); + const char* EncodingFromFile = at.GetValue(0); + if (!strcmp(EncodingFromFile,"ISO_IR 6")) + os << "UTF-8"; + else if (!strcmp(EncodingFromFile,"ISO_IR 192")) + os << "UTF-8"; + else if (!strcmp(EncodingFromFile,"ISO_IR 100")) + os << "ISO-8859-1"; + else if (!strcmp(EncodingFromFile,"ISO_IR 101")) + os << "ISO-8859-2"; + else if (!strcmp(EncodingFromFile,"ISO_IR 109")) + os << "ISO-8859-3"; + else if (!strcmp(EncodingFromFile,"ISO_IR 110")) + os << "ISO-8859-4"; + else if (!strcmp(EncodingFromFile,"ISO_IR 148")) + os << "ISO-8859-9"; + else if (!strcmp(EncodingFromFile,"ISO_IR 144")) + os << "ISO-8859-5"; + else if (!strcmp(EncodingFromFile,"ISO_IR 127")) + os << "ISO-8859-6"; + else if (!strcmp(EncodingFromFile,"ISO_IR 126")) + os << "ISO-8859-7"; + else if (!strcmp(EncodingFromFile,"ISO_IR 138")) + os << "ISO-8859-8"; + else + os << "UTF-8"; + os << "\"?>\n"; + } + else + { + os << "UTF-8\"?>\n\n"; + } + } + else + { + os << "UTF-8\"?>\n\n"; + } + os << "\n"; + + PrintDataSet(ds, ts, os); + + os << ""; +} + +// Drop BulkData by default. +// Application programmer can override this mechanism. +void XMLPrinter::HandleBulkData(const char *uuid, const TransferSyntax & ts, + const char *bulkdata, size_t bulklen) +{ + (void)ts; + (void)uuid; + (void)bulkdata; + (void)bulklen; +} + +}//end namespace gdcm diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcmXMLPrinter.h b/gdcm/Source/MediaStorageAndFileFormat/gdcmXMLPrinter.h new file mode 100644 index 0000000..089b6e0 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcmXMLPrinter.h @@ -0,0 +1,136 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMXMLPRINTER_H +#define GDCMXMLPRINTER_H + +/* + +The Normative version of the XML Schema for the Native DICOM Model follows: + + + +start = element NativeDicomModel { DicomDataSet } + +# A DICOM Data Set is as defined in PS3.5. It does not appear +# as an XML Element, since it does not appear in the binary encoded +# DICOM objects. It exists here merely as a documentation aid. + +DicomDataSet = DicomAttribute* +DicomAttribute = element DicomAttribute { +Tag, VR, Keyword?, PrivateCreator?, +( BulkData | Value+ | Item+ | PersonName+ )? +} + +BulkData = element BulkData{ UUID } +Value = element Value { Number, xsd:string } +Item = element Item { Number, DicomDataSet } +PersonName = element PersonName { +Number, +element SingleByte { NameComponents }?, +element Ideographic { NameComponents }?, +element Phonetic +{ NameComponents }? +} + +NameComponents = +element FamilyName {xsd:string}?, +element GivenName {xsd:string}?, +element MiddleName {xsd:string}?, +element NamePrefix {xsd:string}?, +element NameSuffix {xsd:string}? + +# keyword is the attribute tag from PS3.6 +# (derived from the DICOM Attribute's name) +Keyword = attribute keyword { xsd:token } +# canonical XML definition of Hex, with lowercase letters disallowed +Tag = attribute tag { xsd:string{ minLength="8" maxLength="8" pattern="[0-9A-F]{8}" } } +VR = attribute vr { "AE" | "AS" | "AT"| "CS" | "DA" | "DS" | "DT" | "FL" | "FD" +| "IS" | "LO" | "LT" | "OB" | "OF" | "OW" | "PN" | "SH" | "SL" +| "SQ" | "SS" | "ST" | "TM" | "UI" | "UL" | "UN" | "US" | "UT" } +PrivateCreator = attribute privateCreator{ xsd:string } +UUID = attribute uuid { xsd:string } +Number = attribute number { xsd:positiveInteger } + + +*/ + +#include "gdcmFile.h" +#include "gdcmDataElement.h" + +namespace gdcm +{ + +class DataSet; +class DictEntry; +class Dicts; + +class GDCM_EXPORT XMLPrinter +{ +public: + XMLPrinter(); + virtual ~XMLPrinter(); + + // Set file + void SetFile(File const &f) { F = &f; } + + + + typedef enum { + + OnlyUUID = 0 , + LOADBULKDATA = 1 + + } PrintStyles; + + // Set PrintStyle value + void SetStyle(PrintStyles ps) + { + PrintStyle = ps; + } + + // Get PrintStyle value + PrintStyles GetPrintStyle() const + { + return PrintStyle; + } + + // Print + void Print(std::ostream& os); + + // Print an individual dataset + void PrintDataSet(const DataSet &ds, const TransferSyntax & ts, std::ostream& os); + + //void PrintUID(std::ostream &os); + + /// Virtual function mecanism to allow application programmer to + /// override the default mecanism for BulkData handling. By default + /// GDCM will simply discard the BulkData and only write the UUID + virtual void HandleBulkData(const char *uuid, const TransferSyntax &ts, + const char *bulkdata, size_t bulklen); + +protected: + + VR PrintDataElement(std::ostream &os, const Dicts &dicts, const DataSet & ds, const DataElement &de, const TransferSyntax & ts); + + void PrintSQ(const SequenceOfItems *sqi, const TransferSyntax & ts, std::ostream &os); + + PrintStyles PrintStyle; + + const File *F; + +}; + +} // end namespace gdcm + +#endif //GDCMXMLPRINTER_H diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcm_j2k.h b/gdcm/Source/MediaStorageAndFileFormat/gdcm_j2k.h new file mode 100644 index 0000000..afcad63 --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcm_j2k.h @@ -0,0 +1,446 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2006-2007, Parvatha Elangovan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef GDCM_J2K_H +#define GDCM_J2K_H +/** +@file j2k.h +@brief The JPEG-2000 Codestream Reader/Writer (J2K) + +The functions in J2K.C have for goal to read/write the several parts of the codestream: markers and data. +*/ + +/** @defgroup J2K J2K - JPEG-2000 codestream reader/writer */ +/*@{*/ + +#define J2K_CP_CSTY_PRT 0x01 +#define J2K_CP_CSTY_SOP 0x02 +#define J2K_CP_CSTY_EPH 0x04 +#define J2K_CCP_CSTY_PRT 0x01 +#define J2K_CCP_CBLKSTY_LAZY 0x01 +#define J2K_CCP_CBLKSTY_RESET 0x02 +#define J2K_CCP_CBLKSTY_TERMALL 0x04 +#define J2K_CCP_CBLKSTY_VSC 0x08 +#define J2K_CCP_CBLKSTY_PTERM 0x10 +#define J2K_CCP_CBLKSTY_SEGSYM 0x20 +#define J2K_CCP_QNTSTY_NOQNT 0 +#define J2K_CCP_QNTSTY_SIQNT 1 +#define J2K_CCP_QNTSTY_SEQNT 2 + +/* ----------------------------------------------------------------------- */ + +#define J2K_MS_SOC 0xff4f /**< SOC marker value */ +#define J2K_MS_SOT 0xff90 /**< SOT marker value */ +#define J2K_MS_SOD 0xff93 /**< SOD marker value */ +#define J2K_MS_EOC 0xffd9 /**< EOC marker value */ +#define J2K_MS_SIZ 0xff51 /**< SIZ marker value */ +#define J2K_MS_COD 0xff52 /**< COD marker value */ +#define J2K_MS_COC 0xff53 /**< COC marker value */ +#define J2K_MS_RGN 0xff5e /**< RGN marker value */ +#define J2K_MS_QCD 0xff5c /**< QCD marker value */ +#define J2K_MS_QCC 0xff5d /**< QCC marker value */ +#define J2K_MS_POC 0xff5f /**< POC marker value */ +#define J2K_MS_TLM 0xff55 /**< TLM marker value */ +#define J2K_MS_PLM 0xff57 /**< PLM marker value */ +#define J2K_MS_PLT 0xff58 /**< PLT marker value */ +#define J2K_MS_PPM 0xff60 /**< PPM marker value */ +#define J2K_MS_PPT 0xff61 /**< PPT marker value */ +#define J2K_MS_SOP 0xff91 /**< SOP marker value */ +#define J2K_MS_EPH 0xff92 /**< EPH marker value */ +#define J2K_MS_CRG 0xff63 /**< CRG marker value */ +#define J2K_MS_COM 0xff64 /**< COM marker value */ +/* UniPG>> */ +#ifdef USE_JPWL +#define J2K_MS_EPC 0xff68 /**< EPC marker value (Part 11: JPEG 2000 for Wireless) */ +#define J2K_MS_EPB 0xff66 /**< EPB marker value (Part 11: JPEG 2000 for Wireless) */ +#define J2K_MS_ESD 0xff67 /**< ESD marker value (Part 11: JPEG 2000 for Wireless) */ +#define J2K_MS_RED 0xff69 /**< RED marker value (Part 11: JPEG 2000 for Wireless) */ +#endif /* USE_JPWL */ +#ifdef USE_JPSEC +#define J2K_MS_SEC 0xff65 /**< SEC marker value (Part 8: Secure JPEG 2000) */ +#define J2K_MS_INSEC 0xff94 /**< INSEC marker value (Part 8: Secure JPEG 2000) */ +#endif /* USE_JPSEC */ +/* < there was a PPT marker for the present tile */ + int ppt; + /** used in case of multiple marker PPT (number of info already stored) */ + int ppt_store; + /** ppmbug1 */ + int ppt_len; + /** add fixed_quality */ + float distoratio[100]; + /** tile-component coding parameters */ + opj_tccp_t *tccps; +} opj_tcp_t; + +/** +Coding parameters +*/ +typedef struct opj_cp { + /** Digital cinema profile*/ + OPJ_CINEMA_MODE cinema; + /** Maximum rate for each component. If == 0, component size limitation is not considered */ + int max_comp_size; + /** Size of the image in bits*/ + int img_size; + /** Rsiz*/ + OPJ_RSIZ_CAPABILITIES rsiz; + /** Enabling Tile part generation*/ + char tp_on; + /** Flag determining tile part generation*/ + char tp_flag; + /** Position of tile part flag in progression order*/ + int tp_pos; + /** allocation by rate/distortion */ + int disto_alloc; + /** allocation by fixed layer */ + int fixed_alloc; + /** add fixed_quality */ + int fixed_quality; + /** if != 0, then original dimension divided by 2^(reduce); if == 0 or not used, image is decoded to the full resolution */ + int reduce; + /** if != 0, then only the first "layer" layers are decoded; if == 0 or not used, all the quality layers are decoded */ + int layer; + /** if == NO_LIMITATION, decode entire codestream; if == LIMIT_TO_MAIN_HEADER then only decode the main header */ + OPJ_LIMIT_DECODING limit_decoding; + /** XTOsiz */ + int tx0; + /** YTOsiz */ + int ty0; + /** XTsiz */ + int tdx; + /** YTsiz */ + int tdy; + /** comment for coding */ + char *comment; + /** number of tiles in width */ + int tw; + /** number of tiles in heigth */ + int th; + /** ID number of the tiles present in the codestream */ + int *tileno; + /** size of the vector tileno */ + int tileno_size; + /** packet header store there for futur use in t2_decode_packet */ + unsigned char *ppm_data; + /** pointer remaining on the first byte of the first header if ppm is used */ + unsigned char *ppm_data_first; + /** if ppm == 1 --> there was a PPM marker for the present tile */ + int ppm; + /** use in case of multiple marker PPM (number of info already store) */ + int ppm_store; + /** use in case of multiple marker PPM (case on non-finished previous info) */ + int ppm_previous; + /** ppmbug1 */ + int ppm_len; + /** tile coding parameters */ + opj_tcp_t *tcps; + /** fixed layer */ + int *matrice; +/* UniPG>> */ +#ifdef USE_JPWL + /** enables writing of EPC in MH, thus activating JPWL */ + bool epc_on; + /** enables writing of EPB, in case of activated JPWL */ + bool epb_on; + /** enables writing of ESD, in case of activated JPWL */ + bool esd_on; + /** enables writing of informative techniques of ESD, in case of activated JPWL */ + bool info_on; + /** enables writing of RED, in case of activated JPWL */ + bool red_on; + /** error protection method for MH (0,1,16,32,37-128) */ + int hprot_MH; + /** tile number of header protection specification (>=0) */ + int hprot_TPH_tileno[JPWL_MAX_NO_TILESPECS]; + /** error protection methods for TPHs (0,1,16,32,37-128) */ + int hprot_TPH[JPWL_MAX_NO_TILESPECS]; + /** tile number of packet protection specification (>=0) */ + int pprot_tileno[JPWL_MAX_NO_PACKSPECS]; + /** packet number of packet protection specification (>=0) */ + int pprot_packno[JPWL_MAX_NO_PACKSPECS]; + /** error protection methods for packets (0,1,16,32,37-128) */ + int pprot[JPWL_MAX_NO_PACKSPECS]; + /** enables writing of ESD, (0/2/4 bytes) */ + int sens_size; + /** sensitivity addressing size (0=auto/2/4 bytes) */ + int sens_addr; + /** sensitivity range (0-3) */ + int sens_range; + /** sensitivity method for MH (-1,0-7) */ + int sens_MH; + /** tile number of sensitivity specification (>=0) */ + int sens_TPH_tileno[JPWL_MAX_NO_TILESPECS]; + /** sensitivity methods for TPHs (-1,0-7) */ + int sens_TPH[JPWL_MAX_NO_TILESPECS]; + /** enables JPWL correction at the decoder */ + bool correct; + /** expected number of components at the decoder */ + int exp_comps; + /** maximum number of tiles at the decoder */ + int max_tiles; +#endif /* USE_JPWL */ +/* <cp. +@param j2k J2K decompressor handle +@param parameters decompression parameters +*/ +void j2k_setup_decoder(opj_j2k_t *j2k, opj_dparameters_t *parameters); +/** +Decode an image from a JPEG-2000 codestream +@param j2k J2K decompressor handle +@param cio Input buffer stream +@param cstr_info Codestream information structure if required, NULL otherwise +@return Returns a decoded image if successful, returns NULL otherwise +*/ +opj_image_t* j2k_decode(opj_j2k_t *j2k, opj_cio_t *cio, opj_codestream_info_t *cstr_info); +/** +Decode an image form a JPT-stream (JPEG 2000, JPIP) +@param j2k J2K decompressor handle +@param cio Input buffer stream +@param cstr_info Codestream information structure if required, NULL otherwise +@return Returns a decoded image if successful, returns NULL otherwise +*/ +opj_image_t* j2k_decode_jpt_stream(opj_j2k_t *j2k, opj_cio_t *cio, opj_codestream_info_t *cstr_info); +/** +Creates a J2K compression structure +@param cinfo Codec context info +@return Returns a handle to a J2K compressor if successful, returns NULL otherwise +*/ +opj_j2k_t* j2k_create_compress(opj_common_ptr cinfo); +/** +Destroy a J2K compressor handle +@param j2k J2K compressor handle to destroy +*/ +void j2k_destroy_compress(opj_j2k_t *j2k); +/** +Setup the encoder parameters using the current image and using user parameters. +Coding parameters are returned in j2k->cp. +@param j2k J2K compressor handle +@param parameters compression parameters +@param image input filled image +*/ +void j2k_setup_encoder(opj_j2k_t *j2k, opj_cparameters_t *parameters, opj_image_t *image); +/** +Converts an enum type progression order to string type +*/ +char *j2k_convert_progression_order(OPJ_PROG_ORDER prg_order); +/** +Encode an image into a JPEG-2000 codestream +@param j2k J2K compressor handle +@param cio Output buffer stream +@param image Image to encode +@param cstr_info Codestream information structure if required, NULL otherwise +@return Returns true if successful, returns false otherwise +*/ +bool j2k_encode(opj_j2k_t *j2k, opj_cio_t *cio, opj_image_t *image, opj_codestream_info_t *cstr_info); + +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* GDCM_J2K_H */ diff --git a/gdcm/Source/MediaStorageAndFileFormat/gdcm_jp2.h b/gdcm/Source/MediaStorageAndFileFormat/gdcm_jp2.h new file mode 100644 index 0000000..ffced5a --- /dev/null +++ b/gdcm/Source/MediaStorageAndFileFormat/gdcm_jp2.h @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef GDCM_JP2_H +#define GDCM_JP2_H +/** +@file jp2.h +@brief The JPEG-2000 file format Reader/Writer (JP2) + +*/ + +/** @defgroup JP2 JP2 - JPEG-2000 file format reader/writer */ +/*@{*/ + +#define JPIP_JPIP 0x6a706970 + +#define JP2_JP 0x6a502020 /**< JPEG 2000 signature box */ +#define JP2_FTYP 0x66747970 /**< File type box */ +#define JP2_JP2H 0x6a703268 /**< JP2 header box */ +#define JP2_IHDR 0x69686472 /**< Image header box */ +#define JP2_COLR 0x636f6c72 /**< Colour specification box */ +#define JP2_JP2C 0x6a703263 /**< Contiguous codestream box */ +#define JP2_URL 0x75726c20 /**< URL box */ +#define JP2_DBTL 0x6474626c /**< ??? */ +#define JP2_BPCC 0x62706363 /**< Bits per component box */ +#define JP2_JP2 0x6a703220 /**< File type fields */ + +/* ----------------------------------------------------------------------- */ + +/** +JP2 component +*/ +typedef struct opj_jp2_comps { + int depth; + int sgnd; + int bpcc; +} opj_jp2_comps_t; + +/** +JPEG-2000 file format reader/writer +*/ +typedef struct opj_jp2 { + /** codec context */ + opj_common_ptr cinfo; + /** handle to the J2K codec */ + opj_j2k_t *j2k; + unsigned int w; + unsigned int h; + unsigned int numcomps; + unsigned int bpc; + unsigned int C; + unsigned int UnkC; + unsigned int IPR; + unsigned int meth; + unsigned int approx; + unsigned int enumcs; + unsigned int precedence; + unsigned int brand; + unsigned int minversion; + unsigned int numcl; + unsigned int *cl; + opj_jp2_comps_t *comps; + unsigned int j2k_codestream_offset; + unsigned int j2k_codestream_length; +} opj_jp2_t; + +/** +JP2 Box +*/ +typedef struct opj_jp2_box { + int length; + int type; + int init_pos; +} opj_jp2_box_t; + +/** @name Exported functions */ +/*@{*/ +/* ----------------------------------------------------------------------- */ +/** +Write the JP2H box - JP2 Header box (used in MJ2) +@param jp2 JP2 handle +@param cio Output buffer stream +*/ +void jp2_write_jp2h(opj_jp2_t *jp2, opj_cio_t *cio); +/** +Read the JP2H box - JP2 Header box (used in MJ2) +@param jp2 JP2 handle +@param cio Input buffer stream +@return Returns true if successful, returns false otherwise +*/ +bool jp2_read_jp2h(opj_jp2_t *jp2, opj_cio_t *cio); +/** +Creates a JP2 decompression structure +@param cinfo Codec context info +@return Returns a handle to a JP2 decompressor if successful, returns NULL otherwise +*/ +opj_jp2_t* jp2_create_decompress(opj_common_ptr cinfo); +/** +Destroy a JP2 decompressor handle +@param jp2 JP2 decompressor handle to destroy +*/ +void jp2_destroy_decompress(opj_jp2_t *jp2); +/** +Setup the decoder decoding parameters using user parameters. +Decoding parameters are returned in jp2->j2k->cp. +@param jp2 JP2 decompressor handle +@param parameters decompression parameters +*/ +void jp2_setup_decoder(opj_jp2_t *jp2, opj_dparameters_t *parameters); +/** +Decode an image from a JPEG-2000 file stream +@param jp2 JP2 decompressor handle +@param cio Input buffer stream +@param cstr_info Codestream information structure if required, NULL otherwise +@return Returns a decoded image if successful, returns NULL otherwise +*/ +opj_image_t* jp2_decode(opj_jp2_t *jp2, opj_cio_t *cio, opj_codestream_info_t *cstr_info); +/** +Creates a JP2 compression structure +@param cinfo Codec context info +@return Returns a handle to a JP2 compressor if successful, returns NULL otherwise +*/ +opj_jp2_t* jp2_create_compress(opj_common_ptr cinfo); +/** +Destroy a JP2 compressor handle +@param jp2 JP2 compressor handle to destroy +*/ +void jp2_destroy_compress(opj_jp2_t *jp2); +/** +Setup the encoder parameters using the current image and using user parameters. +Coding parameters are returned in jp2->j2k->cp. +@param jp2 JP2 compressor handle +@param parameters compression parameters +@param image input filled image +*/ +void jp2_setup_encoder(opj_jp2_t *jp2, opj_cparameters_t *parameters, opj_image_t *image); +/** +Encode an image into a JPEG-2000 file stream +@param jp2 JP2 compressor handle +@param cio Output buffer stream +@param image Image to encode +@param cstr_info Codestream information structure if required, NULL otherwise +@return Returns true if successful, returns false otherwise +*/ +bool jp2_encode(opj_jp2_t *jp2, opj_cio_t *cio, opj_image_t *image, opj_codestream_info_t *cstr_info); +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* GDCM_JP2_H */ diff --git a/gdcm/Source/MessageExchangeDefinition/CMakeLists.txt b/gdcm/Source/MessageExchangeDefinition/CMakeLists.txt new file mode 100644 index 0000000..779f24f --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/CMakeLists.txt @@ -0,0 +1,99 @@ +# Add the include paths +include_directories( + "${GDCM_BINARY_DIR}/Source/Common" + "${GDCM_SOURCE_DIR}/Source/Common" + "${GDCM_SOURCE_DIR}/Source/DataStructureAndEncodingDefinition" + "${GDCM_SOURCE_DIR}/Source/DataDictionary" + "${GDCM_SOURCE_DIR}/Source/InformationObjectDefinition" + "${GDCM_SOURCE_DIR}/Source/MediaStorageAndFileFormat" + + "${GDCM_BINARY_DIR}/Testing/Source/Data" + "${GDCM_SOURCE_DIR}/Testing/Source/Data" + + "${GDCM_SOURCE_DIR}/Utilities" + ) + +if(NOT GDCM_USE_SYSTEM_SOCKETXX) + include_directories( + "${GDCM_SOURCE_DIR}/Utilities/socketxx" + "${GDCM_SOURCE_DIR}/Utilities/socketxx/socket++" # local.h + "${GDCM_BINARY_DIR}/Utilities/socketxx/socket++" # config.h + ) +endif() + +set(MessageExchangeDefinition_SRCS + gdcmAAbortPDU.cxx + gdcmRoleSelectionSub.cxx + gdcmSOPClassExtendedNegociationSub.cxx + gdcmPresentationContextGenerator.cxx + gdcmAAssociateACPDU.cxx + gdcmAAssociateRJPDU.cxx + gdcmAAssociateRQPDU.cxx + gdcmARTIMTimer.cxx + gdcmAReleaseRPPDU.cxx + gdcmAReleaseRQPDU.cxx + gdcmAbstractSyntax.cxx + gdcmApplicationContext.cxx + gdcmAsynchronousOperationsWindowSub.cxx + gdcmQueryBase.cxx + gdcmBaseRootQuery.cxx + gdcmCEchoMessages.cxx + gdcmCFindMessages.cxx + gdcmCMoveMessages.cxx + gdcmCStoreMessages.cxx + gdcmCommandDataSet.cxx + gdcmCompositeMessageFactory.cxx + gdcmCompositeNetworkFunctions.cxx + gdcmImplementationClassUIDSub.cxx + gdcmImplementationUIDSub.cxx + gdcmImplementationVersionNameSub.cxx + gdcmMaximumLengthSub.cxx + gdcmPDUFactory.cxx + gdcmPDataTFPDU.cxx + gdcmFindPatientRootQuery.cxx + gdcmMovePatientRootQuery.cxx + gdcmPresentationContext.cxx + gdcmPresentationContextRQ.cxx + gdcmPresentationContextAC.cxx + gdcmPresentationDataValue.cxx + gdcmQueryFactory.cxx + gdcmQueryImage.cxx + gdcmQueryPatient.cxx + gdcmQuerySeries.cxx + gdcmQueryStudy.cxx + gdcmServiceClassUser.cxx + gdcmServiceClassApplicationInformation.cxx + gdcmFindStudyRootQuery.cxx + gdcmMoveStudyRootQuery.cxx + gdcmTransferSyntaxSub.cxx + gdcmULActionAA.cxx + gdcmULActionAE.cxx + gdcmULActionAR.cxx + gdcmULActionDT.cxx + gdcmULBasicCallback.cxx + gdcmULConnection.cxx + gdcmULConnectionInfo.cxx + gdcmULConnectionManager.cxx + gdcmULTransitionTable.cxx + gdcmULWritingCallback.cxx + gdcmUserInformation.cxx + ) + +add_library(gdcmMEXD ${MessageExchangeDefinition_SRCS}) +target_link_libraries(gdcmMEXD gdcmMSFF gdcmDICT gdcmDSED gdcmIOD) +if(GDCM_USE_SYSTEM_SOCKETXX) + target_link_libraries(gdcmMEXD socket++) +else() + target_link_libraries(gdcmMEXD socketxx) +endif() +set_target_properties(gdcmMEXD PROPERTIES ${GDCM_LIBRARY_PROPERTIES} LINK_INTERFACE_LIBRARIES "") +if(WIN32) + target_link_libraries(gdcmMEXD ws2_32) +endif() + +# libs +install_library(gdcmMEXD) +# PDB +install_pdb(gdcmMEXD) +# include files +install_includes("*.h") diff --git a/gdcm/Source/MessageExchangeDefinition/README.txt b/gdcm/Source/MessageExchangeDefinition/README.txt new file mode 100644 index 0000000..a9c4940 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/README.txt @@ -0,0 +1,26 @@ +Part 3.7 / Part 3.8 + +The DICOM UL protocol consists of seven Protocol Data Units: +a) A-ASSOCIATE-RQ PDU +b) A-ASSOCIATE-AC PDU +c) A-ASSOCIATE-RJ PDU +d) P-DATA-TF PDU +e) A-RELEASE-RQ PDU +f) A-RELEASE-RP PDU +g) A-ABORT PDU + +The encoding of the DICOM UL PDUs is defined as follows (Big Endian byte ordering): +Note: The Big Endian byte ordering has been chosen for consistency with the OSI and TCP/IP environment. +This pertains to the DICOM UL PDU headers only. The encoding of the PDV message fragments is +defined by the Transfer Syntax negotiated at association establishment. +a) Each PDU type shall consist of one or more bytes that when represented, are numbered +sequentially, with byte 1 being the lowest byte number. +b) Each byte within the PDU shall consist of eight bits that, when represented, are numbered 7 to +0, where bit 0 is the low order bit. +c) When consecutive bytes are used to represent a string of characters, the lowest byte numbers +represent the first character. +d) When consecutive bytes are used to represent a binary number, the lower byte number has +the most significant value. +e) The lowest byte number is placed first in the transport service data flow. +f) An overview of the PDUs is shown in Figures 9-1 and 9-2. The detailed structure of each PDU +is specified in the following sections. diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmAAbortPDU.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmAAbortPDU.cxx new file mode 100644 index 0000000..2402710 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmAAbortPDU.cxx @@ -0,0 +1,164 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmAAbortPDU.h" +#include "gdcmSwapper.h" + +namespace gdcm +{ +namespace network +{ +const uint8_t AAbortPDU::ItemType = 0x7; // PDUType ? +const uint8_t AAbortPDU::Reserved2 = 0x0; +const uint8_t AAbortPDU::Reserved7 = 0x0; +const uint8_t AAbortPDU::Reserved8 = 0x0; + +/* +This Source field shall contain an integer value encoded as an +unsigned binary number. One of the following values shall be used: +0 - DICOM UL service-user (initiated abort) +1 - reserved +2 - DICOM UL service-provider (initiated abort) +*/ +/* +This field shall contain an integer value encoded as an unsigned +binary number. If the Source field has the value (2) “DICOM UL +service-provider,†it shall take one of the following: +0 - reason-not-specified +1 - unrecognized-PDU +2 - unexpected-PDU +3 - reserved +4 - unrecognized-PDU parameter +5 - unexpected-PDU parameter +6 - invalid-PDU-parameter value +If the Source field has the value (0) “DICOM UL service-user,†this +reason field shall not be significant. It shall be sent with a value 00H +but not tested to this value when received. +Note: The reserved fields are used to preserve symmetry with OSI +ACSE/Presentation Services and Protocol. +*/ +AAbortPDU::AAbortPDU() +{ + ItemLength = 0; + Source = 0; + Reason = 0; + + ItemLength = (uint32_t)Size() - 6; + assert( (ItemLength + 4 + 1 + 1) == Size() ); +} + +std::istream &AAbortPDU::Read(std::istream &is) +{ + //uint8_t itemtype = 0; + //is.read( (char*)&itemtype, sizeof(ItemType) ); + //assert( itemtype == ItemType ); + uint8_t reserved2 = 0; + is.read( (char*)&reserved2, sizeof(Reserved2) ); + uint32_t itemlength = ItemLength; + is.read( (char*)&itemlength, sizeof(ItemLength) ); + SwapperDoOp::SwapArray(&itemlength,1); + ItemLength = itemlength; + uint8_t reserved7 = 0; + is.read( (char*)&reserved7, sizeof(Reserved7) ); + uint8_t reserved8 = 0; + is.read( (char*)&reserved8, sizeof(Reserved8) ); + uint8_t source = 0; + is.read( (char*)&source, sizeof(Source) ); + Source = source; + uint8_t reason = 0; + is.read( (char*)&reason, sizeof(Reason) ); + Reason = reason; + + assert( (ItemLength + 4 + 1 + 1) == Size() ); + return is; +} + +const std::ostream &AAbortPDU::Write(std::ostream &os) const +{ + return os; +} + +size_t AAbortPDU::Size() const +{ + size_t ret = 0; + ret += sizeof(ItemType); + ret += sizeof(Reserved2); + ret += sizeof(ItemLength); + ret += sizeof(Reserved7); + ret += sizeof(Reserved8); + ret += sizeof(Source); + ret += sizeof(Reason); + + return ret; +} + +namespace { +static const char *PrintSourceAsString( uint8_t source ) +{ + // See PS 3.8-2011 Table 9-26 A-ABORT PDU FIELDS + switch( source ) + { + case 0x0: + return "DICOM UL service-user (initiated abort)"; + case 0x1: + return "reserved"; + case 0x2: + return "DICOM UL service-provider (initiated abort)"; + } + // Conquest DICOM 1.14.17c, return '3' as source value: + return "BOGUS SCP IMPLEMENTATION, REPORT UPSTREAM"; +} + +static const char *PrintReasonAsString( uint8_t reason ) +{ + switch( reason ) + { + case 0x0: + return "reason-not-specified"; + case 0x1: + return "unrecognized-PDU"; + case 0x2: + return "unexpected-PDU"; + case 0x3: + return "reserved"; + case 0x4: + return "unrecognized-PDU parameter"; + case 0x5: + return "unexpected-PDU parameter"; + case 0x6: + return "invalid-PDU-parameter value"; + } + assert( 0 ); + return NULL; +} +} + +void AAbortPDU::Print(std::ostream &os) const +{ + os << "PDULength: " << ItemLength << std::endl; + os << "Source: " << PrintSourceAsString( Source ) << std::endl; + os << "Reason: " << PrintReasonAsString( Reason ) << std::endl; +} + +void AAbortPDU::SetSource(const uint8_t s) +{ + Source = s; +} + +void AAbortPDU::SetReason(const uint8_t r) +{ + Reason = r; +} + +} // end namespace network +} // end namespace gdcm diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmAAbortPDU.h b/gdcm/Source/MessageExchangeDefinition/gdcmAAbortPDU.h new file mode 100644 index 0000000..40adf54 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmAAbortPDU.h @@ -0,0 +1,60 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMAABORTPDU_H +#define GDCMAABORTPDU_H + +#include "gdcmTypes.h" +#include "gdcmBasePDU.h" + +namespace gdcm +{ + +namespace network +{ + +/** + * \brief AAbortPDU + * Table 9-26 A-ABORT PDU FIELDS + */ +class GDCM_EXPORT AAbortPDU : public BasePDU +{ +public: + AAbortPDU(); + std::istream &Read(std::istream &is); + const std::ostream &Write(std::ostream &os) const; + + /// \internal Compute Size + size_t Size() const; + void Print(std::ostream &os) const; + + bool IsLastFragment() const { return true; } + + void SetSource(const uint8_t s); + void SetReason(const uint8_t r); + +private: + static const uint8_t ItemType; // PDUType ? + static const uint8_t Reserved2; + uint32_t ItemLength; // PDU Length + static const uint8_t Reserved7; + static const uint8_t Reserved8; + uint8_t Source; + uint8_t Reason; // diag +}; + +} // end namespace network + +} // end namespace gdcm + +#endif //GDCMAABORTPDU_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmAAssociateACPDU.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmAAssociateACPDU.cxx new file mode 100644 index 0000000..939fe4a --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmAAssociateACPDU.cxx @@ -0,0 +1,253 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmAAssociateACPDU.h" +#include "gdcmSwapper.h" +#include "gdcmAAssociateRQPDU.h" + +namespace gdcm +{ +namespace network +{ +const uint8_t AAssociateACPDU::ItemType = 0x02; // PDUType ? +const uint8_t AAssociateACPDU::Reserved2 = 0x00; +const uint16_t AAssociateACPDU::ProtocolVersion = 0x01; // big endian +const uint16_t AAssociateACPDU::Reserved9_10 = 0x0000; +//const uint8_t AAssociateACPDU::Reserved11_26[16] = { }; +//const uint8_t AAssociateACPDU::Reserved27_42[16] = { }; +//const uint8_t AAssociateACPDU::Reserved43_74[32] = { }; + +AAssociateACPDU::AAssociateACPDU() +{ + PDULength = 0; // len of + memset(Reserved11_26, ' ', sizeof(Reserved11_26)); + memset(Reserved27_42, ' ', sizeof(Reserved27_42)); + memset(Reserved43_74, ' ', sizeof(Reserved43_74)); + + PDULength = (uint32_t)(Size() - 6); +} + +void AAssociateACPDU::SetCalledAETitle(const char calledaetitle[16]) +{ + //size_t len = strlen( calledaetitle ); + //assert( len <= 16 ); // since forwared from AA-RQ no reason to be invalid + strncpy(Reserved11_26, calledaetitle, 16 ); +} + +void AAssociateACPDU::SetCallingAETitle(const char callingaetitle[16]) +{ + //size_t len = strlen( callingaetitle ); + //assert( len <= 16 ); // since forwared from AA-RQ no reason to be invalid + strncpy(Reserved27_42, callingaetitle, 16 ); +} + +std::istream &AAssociateACPDU::Read(std::istream &is) +{ + //uint8_t itemtype = 0; + //is.read( (char*)&itemtype, sizeof(ItemType) ); + //assert( itemtype == ItemType ); + assert( is.good() ); + uint8_t reserved2; + is.read( (char*)&reserved2, sizeof(Reserved2) ); + uint32_t pdulength = 0; + is.read( (char*)&pdulength, sizeof(PDULength) ); + SwapperDoOp::SwapArray(&pdulength,1); + PDULength = pdulength; + uint16_t protocolversion; + is.read( (char*)&protocolversion, sizeof(ProtocolVersion) ); + SwapperDoOp::SwapArray(&protocolversion,1); + if( protocolversion != ProtocolVersion ) + { + gdcmErrorMacro( "Improper Protocol Version: " << protocolversion ); + } + uint16_t reserved9_10; + is.read( (char*)&reserved9_10, sizeof(Reserved9_10) ); + SwapperDoOp::SwapArray(&reserved9_10,1); + char reserved11_26[16]; + memset( reserved11_26, 0, sizeof(reserved11_26)); + is.read( (char*)&reserved11_26, sizeof(Reserved11_26) ); // called + memcpy( Reserved11_26, reserved11_26, sizeof(Reserved11_26) ); + char reserved27_42[16]; + memset( reserved27_42, 0, sizeof(reserved27_42)); + is.read( (char*)&reserved27_42, sizeof(Reserved27_42) ); // calling + memcpy( Reserved27_42, reserved27_42, sizeof(Reserved27_42) ); + uint8_t reserved43_74[32]; + memset( reserved43_74, 0, sizeof(reserved43_74)); + is.read( (char*)&reserved43_74, sizeof(Reserved43_74) ); // 0 (32 times) + memcpy( Reserved43_74, reserved43_74, sizeof(Reserved43_74) ); + + uint8_t itemtype2 = 0x0; + size_t curlen = 0; + while( curlen + 68 < PDULength ) + { + is.read( (char*)&itemtype2, sizeof(ItemType) ); + switch ( itemtype2 ) + { + case 0x10: // ApplicationContext ItemType + AppContext.Read( is ); + curlen += AppContext.Size(); + break; + case 0x21: // PresentationContextAC ItemType + { + PresentationContextAC pcac; + pcac.Read( is ); + PresContextAC.push_back( pcac ); + curlen += pcac.Size(); + } + break; + case 0x50: // UserInformation ItemType + UserInfo.Read( is ); + curlen += UserInfo.Size(); + break; + default: + gdcmErrorMacro( "Unknown ItemType: " << std::hex << (int) itemtype2 ); + curlen = PDULength; // make sure to exit + break; + } + // WARNING: I cannot simply call Size() since UserInfo is initialized with GDCM + // own parameter, this will bias the computation. Instead compute relative + // length of remaining bytes to read. + //curlen = Size(); + } + assert( curlen + 68 == PDULength ); + assert( PDULength + 4 + 1 + 1 == Size() ); + + return is; +} + +const std::ostream &AAssociateACPDU::Write(std::ostream &os) const +{ + os.write( (char*)&ItemType, sizeof(ItemType) ); + os.write( (char*)&Reserved2, sizeof(Reserved2) ); + //os.write( (char*)&PDULength, sizeof(PDULength) ); + uint32_t copy = PDULength; + SwapperDoOp::SwapArray(©,1); + os.write( (char*)©, sizeof(PDULength) ); + uint16_t protocolversion = ProtocolVersion; + SwapperDoOp::SwapArray(&protocolversion,1); + os.write( (char*)&protocolversion, sizeof(ProtocolVersion) ); + os.write( (char*)&Reserved9_10, sizeof(Reserved9_10) ); + os.write( (char*)&Reserved11_26, sizeof(Reserved11_26) ); + //const char calling[] = "ANY-SCP "; + //os.write( calling, 16 ); + + os.write( (char*)&Reserved27_42, sizeof(Reserved27_42) ); + //const char called[] = "STORESCU "; + //const char called[] = "ECHOSCU "; + //os.write( called, 16 ); + os.write( (char*)&Reserved43_74, sizeof(Reserved43_74) ); + AppContext.Write( os ); + gdcmAssertAlwaysMacro( PresContextAC.size() ); + std::vector::const_iterator it = PresContextAC.begin(); + for( ; it != PresContextAC.end(); ++it ) + { + it->Write( os ); + } + UserInfo.Write( os ); + + assert( PDULength + 4 + 1 + 1 == Size() ); + + return os; +} + +size_t AAssociateACPDU::Size() const +{ + size_t ret = 0; + ret += sizeof(ItemType); + ret += sizeof(Reserved2); + ret += sizeof(PDULength); + ret += sizeof(ProtocolVersion); + ret += sizeof(Reserved9_10); + ret += sizeof(Reserved11_26); + ret += sizeof(Reserved27_42); + ret += sizeof(Reserved43_74); + ret += AppContext.Size(); + std::vector::const_iterator it = PresContextAC.begin(); + for( ; it != PresContextAC.end(); ++it ) + { + ret += it->Size(); + } + ret += UserInfo.Size(); + return ret; +} + +void AAssociateACPDU::AddPresentationContextAC( PresentationContextAC const &pcac ) +{ + PresContextAC.push_back( pcac ); + PDULength = (uint32_t)(Size() - 6); + assert( PDULength + 4 + 1 + 1 == Size() ); +} + +void AAssociateACPDU::Print(std::ostream &os) const +{ + os << "ProtocolVersion: " << std::hex << ProtocolVersion << std::dec << std::endl; + os << "Reserved9_10: " << std::hex << Reserved9_10 << std::dec << std::endl; + os << "Reserved11_26: [" << std::string(Reserved11_26,sizeof(Reserved11_26)) << "]" << std::endl; + os << "Reserved27_42: [" << std::string(Reserved27_42,sizeof(Reserved27_42)) << "]" << std::endl; + /*os << "Reserved43_74: [" << std::string(Reserved43_74,sizeof(Reserved43_74)) << "]" << std::endl;*/ + os << "Application Context Name: "; + AppContext.Print( os ); + os << "List of PresentationContextAC: " << std::endl; + std::vector::const_iterator it = PresContextAC.begin(); + for( ; it != PresContextAC.end(); ++it ) + { + it->Print(os); + } + os << "User Information: "; + UserInfo.Print( os ); +} + +void AAssociateACPDU::InitFromRQ( AAssociateRQPDU const & rqpdu ) +{ + // Table 9-17 ASSOCIATE-AC PDU fields + // This reserved field shall be sent with a value identical to the value + // received in the same field of the A-ASSOCIATE-RQ PDU + const std::string called = rqpdu.GetCalledAETitle(); + SetCalledAETitle( rqpdu.GetCalledAETitle().c_str() ); + const std::string calling = rqpdu.GetCallingAETitle(); + SetCallingAETitle( rqpdu.GetCallingAETitle().c_str() ); + const std::string reserved = rqpdu.GetReserved43_74(); + memcpy( Reserved43_74, reserved.c_str(), sizeof(Reserved43_74) ); + + assert( ProtocolVersion == 0x01 ); + assert( Reserved9_10 == 0x0 ); + assert( memcmp( Reserved11_26, called.c_str(), sizeof( Reserved11_26) ) == 0 ); + assert( memcmp( Reserved27_42, calling.c_str(), sizeof(Reserved27_42) ) == 0 ); + assert( memcmp( Reserved43_74, reserved.c_str(), sizeof(Reserved43_74) ) == 0 ); +} + + +void AAssociateACPDU::InitSimple( AAssociateRQPDU const & rqpdu ) +{ + TransferSyntaxSub ts1; + ts1.SetNameFromUID( UIDs::ImplicitVRLittleEndianDefaultTransferSyntaxforDICOM ); + + assert( rqpdu.GetNumberOfPresentationContext() ); + for( unsigned int index = 0; index < rqpdu.GetNumberOfPresentationContext(); index++ ) + { + // FIXME / HARDCODED We only ever accept Little Endian + // FIXME we should check : + // rqpdu.GetAbstractSyntax() contains LittleEndian + PresentationContextAC pcac1; + PresentationContextRQ const &pc = rqpdu.GetPresentationContext(index); + uint8_t id = pc.GetPresentationContextID(); + + pcac1.SetPresentationContextID( id ); // DCMTK MR + pcac1.SetTransferSyntax( ts1 ); + AddPresentationContextAC( pcac1 ); + } + +} + +} // end namespace network +} // end namespace gdcm diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmAAssociateACPDU.h b/gdcm/Source/MessageExchangeDefinition/gdcmAAssociateACPDU.h new file mode 100644 index 0000000..4e7134e --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmAAssociateACPDU.h @@ -0,0 +1,104 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMAASSOCIATEACPDU_H +#define GDCMAASSOCIATEACPDU_H + +#include "gdcmTypes.h" +#include "gdcmApplicationContext.h" +#include "gdcmPresentationContextAC.h" +#include "gdcmUserInformation.h" +#include "gdcmBasePDU.h" + +#include + +namespace gdcm +{ + +namespace network +{ +class AAssociateRQPDU; + +/** + * \brief AAssociateACPDU + * Table 9-17 + * ASSOCIATE-AC PDU fields + */ +class AAssociateACPDU : public BasePDU +{ +public: + AAssociateACPDU(); + std::istream &Read(std::istream &is); + const std::ostream &Write(std::ostream &os) const; + + void AddPresentationContextAC( PresentationContextAC const &pcac ); + + typedef std::vector::size_type SizeType; + const PresentationContextAC &GetPresentationContextAC( SizeType i ) { + assert( !PresContextAC.empty() && i < PresContextAC.size() ); + return PresContextAC[i]; + } + SizeType GetNumberOfPresentationContextAC() const { + return PresContextAC.size(); + } + const UserInformation &GetUserInformation() const { return UserInfo; } + + SizeType Size() const; + + void Print(std::ostream &os) const; + bool IsLastFragment() const { return true; } + + void InitFromRQ( AAssociateRQPDU const & rqpdu ); +protected: + friend class AAssociateRQPDU; + void SetCalledAETitle(const char calledaetitle[16]); + void SetCallingAETitle(const char callingaetitle[16]); + +private: + void InitSimple( AAssociateRQPDU const & rqpdu ); + +private: + static const uint8_t ItemType; // PDUType ? + static const uint8_t Reserved2; + uint32_t PDULength; // len of + static const uint16_t ProtocolVersion; + static const uint16_t Reserved9_10; + + // This reserved field shall be sent with a value identical to the value + // received in the same field of the A-ASSOCIATE-RQ PDU, but its value + // shall not be tested when received. + char Reserved11_26[16]; + // This reserved field shall be sent with a value identical to the value + // received in the same field of the A-ASSOCIATE-RQ PDU, but its value + // shall not be tested when received. + char Reserved27_42[16]; + // This reserved field shall be sent with a value identical to the value + // received in the same field of the A-ASSOCIATE-RQ PDU, but its value + // shall not be tested when received. + char Reserved43_74[32]; + /* + 75-xxx Variable items This variable field shall contain the following items: one Application + Context Item, one or more Presentation Context Item(s) and one User + Information Item. For a complete description of these items see Sections + 7.1.1.2, 7.1.1.14, and 7.1.1.6. + */ + ApplicationContext AppContext; + std::vector PresContextAC; + UserInformation UserInfo; +}; + +} // end namespace network + +} // end namespace gdcm + +#endif //GDCMAASSOCIATEACPDU_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmAAssociateRJPDU.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmAAssociateRJPDU.cxx new file mode 100644 index 0000000..c6e10d4 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmAAssociateRJPDU.cxx @@ -0,0 +1,166 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmAAssociateRJPDU.h" +#include "gdcmSwapper.h" + +namespace gdcm +{ +namespace network +{ +const uint8_t AAssociateRJPDU::ItemType = 0x03; // PDUType ? +const uint8_t AAssociateRJPDU::Reserved2 = 0x00; +const uint8_t AAssociateRJPDU::Reserved8 = 0x00; + +AAssociateRJPDU::AAssociateRJPDU() +{ + ItemLength = 0; + Result = 0; + Source = 0; + Reason = 0; // diag ? +} + +std::istream &AAssociateRJPDU::Read(std::istream &is) +{ + //uint8_t itemtype = 0; + //is.read( (char*)&itemtype, sizeof(ItemType) ); + //assert( itemtype == ItemType ); + uint8_t reserved2; + is >> reserved2; + uint32_t itemlength; + is.read( (char*)&itemlength, sizeof(ItemLength) ); + SwapperDoOp::SwapArray(&itemlength,1); + ItemLength = itemlength; + uint8_t reserved8; + is >> reserved8; + uint8_t result; + is >> result; + Result = result; + uint8_t source; + is >> source; + Source = source; + uint8_t reason; + is >> reason; + Reason = reason; + + //assert( ItemLength + 4 + 1 + 1 == Size() ); + + return is; +} + +const std::ostream &AAssociateRJPDU::Write(std::ostream &os) const +{ + return os; +} + +namespace { +static const char *PrintResultAsString( uint8_t result ) +{ + switch( result ) + { + case 0x1: + return "rejected-permanent"; + case 0x2: + return "rejected-transient"; + } + assert( 0 ); + return NULL; +} + +static const char *PrintSourceAsString( uint8_t source ) +{ + switch( source ) + { + case 0x0: + return "DICOM UL service-user"; + case 0x1: + return "DICOM UL service-provider (ACSE related function)"; + case 0x2: + return "DICOM UL service-provider (Presentation related function)"; + } + assert( 0 ); + return NULL; +} + +static const char *PrintReasonAsString( uint8_t source, uint8_t reason ) +{ + switch( source ) + { + case 0x1: + switch( reason ) + { + case 0x1: + return "1 - no-reason-given"; + case 0x2: + return "2 - application-context-name-not-supported"; + case 0x3: + return "3 - calling-AE-title-not-recognized"; + case 0x4: + case 0x5: + case 0x6: + return "4-6 - reserved"; + case 0x7: + return "7 - called-AE-title-not-recognized"; + case 0x8: + case 0x9: + case 0xa: + return "8-10 - reserved"; + } + case 0x2: + switch( reason ) + { + case 0x1: + return "no-reason-given"; + case 0x2: + return "protocol-version-not-supported"; + } + case 0x3: + switch( reason ) + { + case 0x0: + return "0 - reserved"; + case 0x1: + return "1 - temporary-congestion"; + case 0x2: + return "2 - local-limit-exceeded"; + case 0x3: + case 0x4: + case 0x5: + case 0x6: + case 0x7: + return "3-7 - reserved"; + } + } + assert( 0 ); + return NULL; +} + +} + + +void AAssociateRJPDU::Print(std::ostream &os) const +{ + os << "PDULength: " << ItemLength << std::endl; + os << "Result: " << PrintResultAsString( Result ) << std::endl; + os << "Source: " << PrintSourceAsString( Source ) << std::endl; + os << "Reason: " << PrintReasonAsString( Source, Reason ) << std::endl; +} + + +size_t AAssociateRJPDU::Size() const{ + return sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint32_t)+ + sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint8_t); +} + +} // end namespace network +} // end namespace gdcm diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmAAssociateRJPDU.h b/gdcm/Source/MessageExchangeDefinition/gdcmAAssociateRJPDU.h new file mode 100644 index 0000000..8282716 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmAAssociateRJPDU.h @@ -0,0 +1,54 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMAASSOCIATERJPDU_H +#define GDCMAASSOCIATERJPDU_H + +#include "gdcmTypes.h" +#include "gdcmBasePDU.h" + +namespace gdcm +{ + +namespace network +{ + +/** + * \brief AAssociateRJPDU + * Table 9-21 + * ASSOCIATE-RJ PDU FIELDS + */ +class AAssociateRJPDU : public BasePDU +{ +public: + AAssociateRJPDU(); + std::istream &Read(std::istream &is); + const std::ostream &Write(std::ostream &os) const; + void Print(std::ostream &os) const; + size_t Size() const; + bool IsLastFragment() const { return true; } +private: + static const uint8_t ItemType; // PDUType ? + static const uint8_t Reserved2; + uint32_t ItemLength; // PDU Length ? + static const uint8_t Reserved8; + uint8_t Result; + uint8_t Source; + uint8_t Reason; // diag ? +}; + +} // end namespace network + +} // end namespace gdcm + +#endif //GDCMAASSOCIATERJPDU_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmAAssociateRQPDU.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmAAssociateRQPDU.cxx new file mode 100644 index 0000000..74484ab --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmAAssociateRQPDU.cxx @@ -0,0 +1,314 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmAAssociateRQPDU.h" +#include "gdcmSwapper.h" + +#include "gdcmAAssociateACPDU.h" +#include +#include + +namespace gdcm +{ +/* +9.3.2 A-ASSOCIATE-RQ PDU STRUCTURE +An A-ASSOCIATE-RQ PDU shall be made of a sequence of mandatory fields followed by a variable +length field. Table 9-11 shows the sequence of the mandatory fields. +The variable field shall consist of one Application Context Item, one or more Presentation Context Items, +and one User Information Item. Sub-Items shall exist for the Presentation Context and User Information +Items. +*/ +namespace network +{ +const uint8_t AAssociateRQPDU::ItemType = 0x1; // PDUType ? +const uint8_t AAssociateRQPDU::Reserved2 = 0x0; +const uint16_t AAssociateRQPDU::ProtocolVersion = 0x1; // big - endian ? +const uint16_t AAssociateRQPDU::Reserved9_10 = 0x0; +//const uint8_t AAssociateRQPDU::Reserved43_74[32] = {}; + +AAssociateRQPDU::AAssociateRQPDU() +{ + memset(CalledAETitle, ' ', sizeof(CalledAETitle)); + //const char called[] = "ANY-SCP"; + //strncpy(CalledAETitle, called, strlen(called) ); + memset(CallingAETitle, ' ', sizeof(CallingAETitle)); + //const char calling[] = "ECHOSCU"; + //strncpy(CallingAETitle, calling, strlen(calling) ); + memset(Reserved43_74, 0x0, sizeof(Reserved43_74)); + + //SetCallingAETitle( "MOVESCU" ); + + ItemLength = (uint32_t)Size() - 6; + assert( (ItemLength + 4 + 1 + 1) == Size() ); +} + +std::istream &AAssociateRQPDU::Read(std::istream &is) +{ + //uint8_t itemtype = 0; + //is.read( (char*)&itemtype, sizeof(ItemType) ); + //assert( itemtype == ItemType ); + uint8_t reserved2; + is >> reserved2; + uint32_t itemlength; + is.read( (char*)&itemlength, sizeof(ItemLength) ); + SwapperDoOp::SwapArray(&itemlength,1); + ItemLength = itemlength; + uint16_t protocolversion; + is.read( (char*)&protocolversion, sizeof(ProtocolVersion) ); + SwapperDoOp::SwapArray(&protocolversion,1); + if( protocolversion != ProtocolVersion ) + { + gdcmWarningMacro( "ProtocolVersion is: " << protocolversion ); + } + uint16_t reserved9_10; + is.read( (char*)&reserved9_10, sizeof(Reserved9_10) ); + SwapperDoOp::SwapArray(&reserved9_10,1); + //char calledaetitle[16]; + is.read( (char*)&CalledAETitle, sizeof(CalledAETitle) ); // called + //char callingaetitle[16]; + is.read( (char*)&CallingAETitle, sizeof(CallingAETitle) ); // calling + uint8_t reserved43_74[32] = { }; + is.read( (char*)&reserved43_74, sizeof(Reserved43_74) ); // 0 (32 times) + memcpy( Reserved43_74, reserved43_74, sizeof(Reserved43_74) ); + + uint8_t itemtype2 = 0x0; + size_t curlen = 0; + while( curlen + 68 < ItemLength ) + { + is.read( (char*)&itemtype2, sizeof(ItemType) ); + switch ( itemtype2 ) + { + case 0x10: // ApplicationContext ItemType + AppContext.Read( is ); + curlen += AppContext.Size(); + break; + case 0x20: // PresentationContextRQ ItemType + { + PresentationContextRQ pc; + pc.Read( is ); + PresContext.push_back( pc ); + curlen += pc.Size(); + } + break; + case 0x50: // UserInformation ItemType + UserInfo.Read( is ); + curlen += UserInfo.Size(); + break; + default: + gdcmErrorMacro( "Unknown ItemType: " << std::hex << (int) itemtype2 ); + curlen = ItemLength; // make sure to exit + break; + } + // WARNING: I cannot simply call Size() since UserInfo is initialized with GDCM + // own parameter, this will bias the computation. Instead compute relative + // length of remaining bytes to read. + //curlen = Size(); + } + assert( curlen + 68 == ItemLength ); + + assert( ItemLength + 4 + 1 + 1 == Size() ); + + return is; +} + +const std::ostream &AAssociateRQPDU::Write(std::ostream &os) const +{ + assert( ItemLength + 4 + 1 + 1 == Size() ); +#if 0 + // Need to check all context Id are ordered ? and odd number ? + std::vector::const_iterator it = PresContext.begin(); + for( ; it != PresContext.end(); ++it) + { + it->Write(os); + } +#endif + os.write( (char*)&ItemType, sizeof(ItemType) ); + os.write( (char*)&Reserved2, sizeof(Reserved2) ); + uint32_t copy = ItemLength; + SwapperDoOp::SwapArray(©,1); + os.write( (char*)©, sizeof(ItemLength) ); + uint16_t protocolversion = ProtocolVersion; + SwapperDoOp::SwapArray(&protocolversion,1); + os.write( (char*)&protocolversion, sizeof(ProtocolVersion) ); + os.write( (char*)&Reserved9_10, sizeof(Reserved9_10) ); + assert( AAssociateRQPDU::IsAETitleValid(CalledAETitle) ); + os.write( CalledAETitle, 16 ); + assert( AAssociateRQPDU::IsAETitleValid(CallingAETitle) ); + os.write( CallingAETitle, 16 ); + os.write( (char*)&Reserved43_74, sizeof(Reserved43_74) ); + AppContext.Write(os); + std::vector::const_iterator it = PresContext.begin(); + for( ; it != PresContext.end(); ++it) + { + it->Write(os); + } + UserInfo.Write(os); + + return os; +} + +size_t AAssociateRQPDU::Size() const +{ + size_t ret = 0; + ret += sizeof(ItemType); + ret += sizeof(Reserved2); + ret += sizeof(ItemLength); + ret += sizeof(ProtocolVersion); + ret += sizeof(Reserved9_10); + ret += sizeof(CalledAETitle); + ret += sizeof(CallingAETitle); + ret += sizeof(Reserved43_74); + ret += AppContext.Size(); + std::vector::const_iterator it = PresContext.begin(); + for( ; it != PresContext.end(); ++it) + { + ret += it->Size(); + } + ret += UserInfo.Size(); + + return ret; +} + +bool AAssociateRQPDU::IsAETitleValid(const char title[16]) +{ + if(!title) return false; +#if 0 + std::string s ( title, 16 ); + // check no \0 : + //size_t len = strlen( s.c_str() ); + + // FIXME: +// if( len != 16 ) return false; + std::locale loc; + std::string str = s; + for (size_t i=0; i < str.size(); ++i) + { + str[i] = std::toupper(str[i],loc); + } + if( str != s ) return false; +#else + const size_t reallen = strlen( title ); + std::string s ( title, std::min(reallen, (size_t)16) ); + // check no \0 : + size_t len = strlen( s.c_str() ); + + char OnlySpaces[16]; + memset(OnlySpaces, ' ', sizeof(OnlySpaces)); + if( strncmp( title, OnlySpaces, len ) == 0 ) + { + return false; + } +#endif + return true; +} + +void AAssociateRQPDU::AddPresentationContext( PresentationContextRQ const &pc ) +{ + PresContext.push_back( pc ); + ItemLength = (uint32_t)Size() - 6; + assert( (ItemLength + 4 + 1 + 1) == Size() ); +} + +void AAssociateRQPDU::SetCalledAETitle(const char calledaetitle[16]) +{ + assert( AAssociateRQPDU::IsAETitleValid(calledaetitle) ); + size_t len = strlen( calledaetitle ); + if( len <= 16 ) + { + memset(CalledAETitle, ' ', sizeof(CalledAETitle)); + strncpy(CalledAETitle, calledaetitle, len ); + } + // FIXME Need to check upper case + // FIXME cannot set to only whitespaces +} + +void AAssociateRQPDU::SetCallingAETitle(const char callingaetitle[16]) +{ + assert( AAssociateRQPDU::IsAETitleValid(callingaetitle) ); + size_t len = strlen( callingaetitle ); + if( len <= 16 ) + { + memset(CallingAETitle, ' ', sizeof(CallingAETitle)); + strncpy(CallingAETitle, callingaetitle, len ); + } + // FIXME Need to check upper case + // FIXME cannot set to only whitespaces +} + +std::string AAssociateRQPDU::GetReserved43_74() const +{ + return std::string(Reserved43_74,32); +} + +void AAssociateRQPDU::Print(std::ostream &os) const +{ + //static const uint8_t ItemType; // PDUType ? + //static const uint8_t Reserved2; + //uint32_t ItemLength; // PDU Length + //static const uint16_t ProtocolVersion; + //static const uint16_t Reserved9_10; + os << "CalledAETitle: "; + os << GetCalledAETitle() << std::endl; + os << "CallingAETitle: "; + os << GetCallingAETitle() << std::endl; + //static const uint8_t Reserved43_74[32]; // { 0 } + os << "ApplicationContext: "; + AppContext.Print( os ); + os << std::endl; + //std::vector PresContext; + os << "PresentationContext(s): "; + std::vector::const_iterator it = PresContext.begin(); + for( ; it != PresContext.end(); ++it) + { + it->Print( os << std::endl ); + } + os << "UserInformation: "; + UserInfo.Print( os ); + os << std::endl; +} + +const PresentationContextRQ *AAssociateRQPDU::GetPresentationContextByID(uint8_t id) const +{ + std::vector::const_iterator it = PresContext.begin(); + for( ; it != PresContext.end(); ++it) + { + if( it->GetPresentationContextID() == id ) + { + return &*it; + } + } + return NULL; +} + +const PresentationContextRQ *AAssociateRQPDU::GetPresentationContextByAbstractSyntax(AbstractSyntax const & as ) const +{ + std::vector::const_iterator it = PresContext.begin(); + for( ; it != PresContext.end(); ++it) + { + if( it->GetAbstractSyntax() == as ) + { + return &*it; + } + } + return NULL; +} + +void AAssociateRQPDU::SetUserInformation( UserInformation const & ui ) +{ + UserInfo = ui; + ItemLength = (uint32_t)Size() - 6; + assert( (ItemLength + 4 + 1 + 1) == Size() ); +} + +} // end namespace network +} // end namespace gdcm diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmAAssociateRQPDU.h b/gdcm/Source/MessageExchangeDefinition/gdcmAAssociateRQPDU.h new file mode 100644 index 0000000..852a684 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmAAssociateRQPDU.h @@ -0,0 +1,153 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMAASSOCIATERQPDU_H +#define GDCMAASSOCIATERQPDU_H + +#include "gdcmTypes.h" +#include "gdcmVR.h" // AEComp +#include "gdcmApplicationContext.h" +#include "gdcmPresentationContextRQ.h" +#include "gdcmUserInformation.h" +#include "gdcmBasePDU.h" + +namespace gdcm +{ + +namespace network +{ + +class AAssociateACPDU; +/** + * \brief AAssociateRQPDU + * Table 9-11 ASSOCIATE-RQ PDU fields + */ +class AAssociateRQPDU : public BasePDU +{ +public: + AAssociateRQPDU(); + std::istream &Read(std::istream &is); + const std::ostream &Write(std::ostream &os) const; + size_t Size() const; + void AddPresentationContext( PresentationContextRQ const &pc ); + + /// Set the Called AE Title + void SetCalledAETitle(const char calledaetitle[16]); + std::string GetCalledAETitle() const { return std::string(CalledAETitle,16); } + + /// Set the Calling AE Title + void SetCallingAETitle(const char callingaetitle[16]); + std::string GetCallingAETitle() const { return std::string(CallingAETitle,16); } + + /// Check whether or not the \param title is a valid AE title + static bool IsAETitleValid(const char title[16]); + + /// This function will initialize an AAssociateACPDU from + /// the fields in the AAssociateRQPDU structure + //void InitFromRQ( AAssociateACPDU & acpdu ); + + void Print(std::ostream &os) const; + + AAssociateRQPDU(const AAssociateRQPDU &pdu):BasePDU(pdu) + { + assert( 0 ); + } + //this function fails to compile on windows. +// AAssociateRQPDU &operator=(const AAssociateRQPDU &_val) +// { +// assert( 0 ); +// } + + typedef std::vector::size_type SizeType; + SizeType GetNumberOfPresentationContext() const { + return PresContext.size(); + } + PresentationContextRQ const &GetPresentationContext(SizeType i) const { + assert( !PresContext.empty() && i < PresContext.size() ); + return PresContext[i]; + } + typedef std::vector PresentationContextArrayType; + PresentationContextArrayType const &GetPresentationContexts() { return PresContext; } + + const PresentationContextRQ *GetPresentationContextByID(uint8_t i) const; + const PresentationContextRQ *GetPresentationContextByAbstractSyntax(AbstractSyntax const & as ) const; + bool IsLastFragment() const { return true; } + + const UserInformation & GetUserInformation() const { return UserInfo; } + void SetUserInformation( UserInformation const & ui ); + +protected: + friend class AAssociateACPDU; + std::string GetReserved43_74() const; + +private: + // 1 PDU-type 01H + static const uint8_t ItemType; // PDUType ? + // 2 Reserved This reserved field shall be sent with a value 00H but not tested to this value when received. + static const uint8_t Reserved2; + /* 3-6 PDU-length This PDU-length shall be the number of bytes from the first byte of the + following field to the last byte of the variable field. It shall be encoded as + an unsigned binary number + */ + uint32_t ItemLength; // PDU Length + /* + 7-8 Protocol-version This two byte field shall use one bit to identify each version of the + DICOM UL protocol supported by the calling end-system. This is + Version 1 and shall be identified with bit 0 set. A receiver of this PDU + implementing only this version of the DICOM UL protocol shall only test + that bit 0 is set. + */ + static const uint16_t ProtocolVersion; + /* + 9-10 Reserved This reserved field shall be sent with a value 0000H but not tested to + this value when received. + */ + static const uint16_t Reserved9_10; + /* + 11-26 Called-AE-title Destination DICOM Application Name. It shall be encoded as 16 + characters as defined by the ISO 646:1990-Basic G0 Set with leading + and trailing spaces (20H) being non-significant. The value made of 16 + spaces (20H) meaning "no Application Name specified" shall not be + used. For a complete description of the use of this field, see Section + 7.1.1.4. + */ + char CalledAETitle[16]; + /* + 27-42 Calling-AE-title Source DICOM Application Name. It shall be encoded as 16 + characters as defined by the ISO 646:1990-Basic G0 Set with leading + and trailing spaces (20H) being non-significant. The value made of 16 + spaces (20H) meaning "no Application Name specified" shall not be + used. For a complete description of the use of this field, see Section + 7.1.1.3. + */ + char CallingAETitle[16]; + /* + 43-74 Reserved This reserved field shall be sent with a value 00H for all bytes but not + tested to this value when received + */ + char Reserved43_74[32]; // { 0 } + /* + 75-xxx Variable items This variable field shall contain the following items: one Application + Context Item, one or more Presentation Context Items and one User + Information Item. For a complete description of the use of these items + see Sections 7.1.1.2, 7.1.1.13, and 7.1.1.6. + */ + ApplicationContext AppContext; + std::vector PresContext; + UserInformation UserInfo; +}; + +} // end namespace network +} // end namespace gdcm + +#endif //GDCMAASSOCIATERQPDU_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmARTIMTimer.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmARTIMTimer.cxx new file mode 100644 index 0000000..e07d585 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmARTIMTimer.cxx @@ -0,0 +1,83 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +/* + +This file contains the code for the ARTIM timer. + +Basically, the ARTIM timer will just get the wall time when it's started, +and then can be queried for the current time, and then can be stopped (ie, +the start time reset). + +Because we're trying to do this without threading, we should be able to 'start' the +ARTIM timer by this mechanism, and then when waiting for a particular response, tight +loop that with sleep calls and determinations of when the ARTIM timer has reached its +peak. As such, this isn't a strict 'timer' in the traditional sense of the word, +but more of a time keeper. + +*/ + +#include "gdcmARTIMTimer.h" +#include "gdcmSystem.h" + +namespace gdcm +{ +namespace network +{ + +//initiates the start and timeout at -1; +ARTIMTimer::ARTIMTimer(){ + mStartTime = 0; + mTimeOut = 0; +} +double ARTIMTimer::GetCurrentTime() const{ + return 0; //platform-specific timing functions go here... +} + +void ARTIMTimer::Start(){ + mStartTime = GetCurrentTime(); +} +void ARTIMTimer::SetTimeout(double inTimeOut){ + mTimeOut = inTimeOut; +} + +double ARTIMTimer::GetTimeout() const{ + return mTimeOut; +} +double ARTIMTimer::GetElapsedTime() const{ + if (mStartTime > 0){ + return GetCurrentTime() - mStartTime; + } else { + return -1; //not started yet + } +} + +bool ARTIMTimer::GetHasExpired() const{ + double theElapsed = GetElapsedTime(); + if (theElapsed > 0){ + return theElapsed > mTimeOut; + } else { + return false; //not started yet + } +} + +void ARTIMTimer::Stop() { + mStartTime = -1;//stop the timer by resetting it. +} + +} // end namespace network +} // end namespace gdcm diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmARTIMTimer.h b/gdcm/Source/MessageExchangeDefinition/gdcmARTIMTimer.h new file mode 100644 index 0000000..8b2bb2a --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmARTIMTimer.h @@ -0,0 +1,67 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#ifndef GDCMARTIMTIMER_H +#define GDCMARTIMTIMER_H + +namespace gdcm { + namespace network{ +/** \brief ARTIMTimer + * This file contains the code for the ARTIM timer. + * + * Basically, the ARTIM timer will just get the wall time when it's started, + * and then can be queried for the current time, and then can be stopped (ie, + * the start time reset). + * + * Because we're trying to do this without threading, we should be able to 'start' the + * ARTIM timer by this mechanism, and then when waiting for a particular response, tight + * loop that with sleep calls and determinations of when the ARTIM timer has reached its + * peak. As such, this isn't a strict 'timer' in the traditional sense of the word, + * but more of a time keeper. + * + * There can be only one ARTIM timer per connection. + */ +class ARTIMTimer +{ + private: + double mStartTime; //ms timing should be good enough, but there are also + //high-resolution timing options. Those return doubles. For now, + //go with integer timing solutions based on milliseconds (DWORD on windows), + //but leave as doubles to ease transitions to other timing methods. + + double mTimeOut; + //once GetCurrentTime() -mStartTime > mTimeout, GetHasExpired returns true. + + double GetCurrentTime() const;//a platform-specific implementation of getting the + //current time. + + public: + ARTIMTimer(); //initiates the start and timeout at -1; + void Start(); //'start' the timer by getting the current wall time + void Stop();//'stop' the timer by resetting the 'start' to -1; + void SetTimeout(double inTimeout); + double GetTimeout() const; + + double GetElapsedTime() const; + + bool GetHasExpired() const; + + }; + } +} + +#endif //GDCMARTIMTIMER_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmAReleaseRPPDU.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmAReleaseRPPDU.cxx new file mode 100644 index 0000000..175e017 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmAReleaseRPPDU.cxx @@ -0,0 +1,80 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmAReleaseRPPDU.h" +#include "gdcmSwapper.h" + +namespace gdcm +{ +namespace network +{ +const uint8_t AReleaseRPPDU::ItemType = 0x6; // PDUType ? +const uint8_t AReleaseRPPDU::Reserved2 = 0x0; +const uint32_t AReleaseRPPDU::Reserved7_10 = 0x0; + +AReleaseRPPDU::AReleaseRPPDU() +{ + ItemLength = (uint32_t)(Size() - 6); // PDU Length + assert( ItemLength + 6 == Size() ); +} + +std::istream &AReleaseRPPDU::Read(std::istream &is) +{ + //uint8_t itemtype = 0; + //is.read( (char*)&itemtype, sizeof(ItemType) ); + //assert( itemtype == ItemType ); + uint8_t reserved2 = 0; + is.read( (char*)&reserved2, sizeof(Reserved2) ); + uint32_t itemlength = ItemLength; + is.read( (char*)&itemlength, sizeof(ItemLength) ); + SwapperDoOp::SwapArray(&itemlength,1); + ItemLength = itemlength; + uint32_t reserved7_10; + is.read( (char*)&reserved7_10, sizeof(Reserved7_10) ); + + assert( ItemLength + 6 == Size() ); + return is; +} + +const std::ostream &AReleaseRPPDU::Write(std::ostream &os) const +{ + os.write( (char*)&ItemType, sizeof(ItemType) ); + os.write( (char*)&Reserved2, sizeof(Reserved2) ); + uint32_t copy = ItemLength; + SwapperDoOp::SwapArray(©,1); + os.write( (char*)©, sizeof(ItemLength) ); + os.write( (char*)&Reserved7_10, sizeof(Reserved7_10) ); + + assert( ItemLength + 6 == Size() ); + + return os; +} + +size_t AReleaseRPPDU::Size() const +{ + size_t ret = 0; + ret += sizeof(ItemType); + ret += sizeof(Reserved2); + ret += sizeof(ItemLength); // len of + ret += sizeof(Reserved7_10); + + return ret; +} + +void AReleaseRPPDU::Print(std::ostream &os) const +{ + os << "PDULength: " << ItemLength << std::endl; +} + +} // end namespace network +} // end namespace gdcm diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmAReleaseRPPDU.h b/gdcm/Source/MessageExchangeDefinition/gdcmAReleaseRPPDU.h new file mode 100644 index 0000000..04aaabc --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmAReleaseRPPDU.h @@ -0,0 +1,51 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMARELEASERPPDU_H +#define GDCMARELEASERPPDU_H + +#include "gdcmTypes.h" +#include "gdcmBasePDU.h" + +namespace gdcm +{ + +namespace network +{ + +/** + * \brief AReleaseRPPDU + * Table 9-25 + * A-RELEASE-RP PDU fields + */ +class AReleaseRPPDU : public BasePDU +{ +public: + AReleaseRPPDU(); + std::istream &Read(std::istream &is); + const std::ostream &Write(std::ostream &os) const; + size_t Size() const; + void Print(std::ostream &os) const; + bool IsLastFragment() const { return true; } +private: + static const uint8_t ItemType; // PDUType ? + static const uint8_t Reserved2; + uint32_t ItemLength; // PDU Length + static const uint32_t Reserved7_10; +}; + +} // end namespace network + +} // end namespace gdcm + +#endif //GDCMARELEASERPPDU_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmAReleaseRQPDU.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmAReleaseRQPDU.cxx new file mode 100644 index 0000000..f7b89aa --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmAReleaseRQPDU.cxx @@ -0,0 +1,79 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmAReleaseRQPDU.h" +#include "gdcmSwapper.h" + +namespace gdcm +{ +namespace network +{ +const uint8_t AReleaseRQPDU::ItemType = 0x5; // PDUType ? +const uint8_t AReleaseRQPDU::Reserved2 = 0x0; +const uint32_t AReleaseRQPDU::Reserved7_10 = 0x0; + +AReleaseRQPDU::AReleaseRQPDU() +{ + ItemLength = (uint32_t)(Size() - 6); // PDU Length + assert( ItemLength + 6 == Size() ); +} + +std::istream &AReleaseRQPDU::Read(std::istream &is) +{ + //uint8_t itemtype = 0; + //is.read( (char*)&itemtype, sizeof(ItemType) ); + //assert( itemtype == ItemType ); + uint8_t reserved2 = 0; + is.read( (char*)&reserved2, sizeof(Reserved2) ); + uint32_t itemlength = ItemLength; + is.read( (char*)&itemlength, sizeof(ItemLength) ); + SwapperDoOp::SwapArray(&itemlength,1); + ItemLength = itemlength; + uint32_t reserved7_10; + is.read( (char*)&reserved7_10, sizeof(Reserved7_10) ); + + assert( ItemLength + 6 == Size() ); + return is; +} + +const std::ostream &AReleaseRQPDU::Write(std::ostream &os) const +{ + os.write( (char*)&ItemType, sizeof(ItemType) ); + os.write( (char*)&Reserved2, sizeof(Reserved2) ); + uint32_t copy = ItemLength; + SwapperDoOp::SwapArray(©,1); + os.write( (char*)©, sizeof(ItemLength) ); + os.write( (char*)&Reserved7_10, sizeof(Reserved7_10) ); + + assert( ItemLength + 6 == Size() ); + + return os; +} + +size_t AReleaseRQPDU::Size() const +{ + size_t ret = 0; + ret += sizeof(ItemType); + ret += sizeof(Reserved2); + ret += sizeof(ItemLength); // len of + ret += sizeof(Reserved7_10); + + return ret; +} + +void AReleaseRQPDU::Print(std::ostream &os) const +{ + os << "AReleaseRQ PDU printing not implemented yet" << std::endl; +} +} // end namespace network +} // end namespace gdcm diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmAReleaseRQPDU.h b/gdcm/Source/MessageExchangeDefinition/gdcmAReleaseRQPDU.h new file mode 100644 index 0000000..fdb25ac --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmAReleaseRQPDU.h @@ -0,0 +1,51 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMARELEASERQPDU_H +#define GDCMARELEASERQPDU_H + +#include "gdcmTypes.h" +#include "gdcmBasePDU.h" + +namespace gdcm +{ + +namespace network +{ + +/** + * \brief AReleaseRQPDU + * Table 9-24 + * A-RELEASE-RQ PDU FIELDS + */ +class AReleaseRQPDU : public BasePDU +{ +public: + AReleaseRQPDU(); + std::istream &Read(std::istream &is); + const std::ostream &Write(std::ostream &os) const; + size_t Size() const; + void Print(std::ostream &os) const; + bool IsLastFragment() const { return true; } +private: + static const uint8_t ItemType; // PDUType ? + static const uint8_t Reserved2; + uint32_t ItemLength; // PDU Length + static const uint32_t Reserved7_10; +}; + +} // end namespace network + +} // end namespace gdcm + +#endif //GDCMARELEASERQPDU_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmAbstractSyntax.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmAbstractSyntax.cxx new file mode 100644 index 0000000..50accb5 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmAbstractSyntax.cxx @@ -0,0 +1,128 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmAbstractSyntax.h" +#include "gdcmSwapper.h" +#include + +namespace gdcm +{ +namespace network +{ +const uint8_t AbstractSyntax::ItemType = 0x30; +const uint8_t AbstractSyntax::Reserved2 = 0x00; + +AbstractSyntax::AbstractSyntax() +{ + //UpdateName ( "1.2.840.10008.1.1" ); // Verification SOP Class + ItemLength = 0; +} + +std::istream &AbstractSyntax::Read(std::istream &is) +{ + uint8_t itemtype = 0x0; + is.read( (char*)&itemtype, sizeof(ItemType) ); + assert( itemtype == ItemType ); + uint8_t reserved2; + is.read( (char*)&reserved2, sizeof(Reserved2) ); + uint16_t itemlength; + is.read( (char*)&itemlength, sizeof(ItemLength) ); + SwapperDoOp::SwapArray(&itemlength,1); + ItemLength = itemlength; + + char name[256]; + assert( itemlength < 256 ); + is.read( name, itemlength ); + Name = std::string(name,itemlength); + + return is; +} + +const std::ostream &AbstractSyntax::Write(std::ostream &os) const +{ + os.write( (char*)&ItemType, sizeof(ItemType) ); + os.write( (char*)&Reserved2, sizeof(Reserved2) ); + //os.write( (char*)&ItemLength, sizeof(ItemLength) ); + uint16_t copy = ItemLength; + SwapperDoOp::SwapArray(©,1); + os.write( (char*)©, sizeof(ItemLength) ); + + os.write( Name.c_str(), Name.size() ); + return os; +} + +size_t AbstractSyntax::Size() const +{ + size_t ret = 0; + assert( Name.size() == ItemLength ); + ret += sizeof(ItemType); + ret += sizeof(Reserved2); + ret += sizeof(ItemLength); + ret += ItemLength; + assert(ret <= (size_t)std::numeric_limits::max); + assert(ret >= 4); + return ret; +} + +void AbstractSyntax::UpdateName( const char *name ) +{ + if( name ) + { + UIDs uids; + bool b = uids.SetFromUID( name ); + if( b ) + { + Name = name; + size_t lenTemp = Name.size(); + assert(lenTemp < (size_t)std::numeric_limits::max); + ItemLength = (uint16_t)lenTemp; + assert( (size_t)ItemLength + 4 == Size() ); + return; + } + } + + gdcmErrorMacro( "Invalid Name: " << name ); + throw "Invalid Name"; +} + +void AbstractSyntax::SetNameFromUID( UIDs::TSName tsname ) +{ + const char *name = UIDs::GetUIDString( tsname ); + UpdateName( name ); +} +//void AbstractSyntax::SetNameFromUIDString( const std::string& inUIDName ) +//{ +// const char *name = inUIDName.c_str(); +// UpdateName( name ); +//} + +void AbstractSyntax::Print(std::ostream &os) const +{ + os << Name << std::endl; +} + +DataElement AbstractSyntax::GetAsDataElement() const +{ + DataElement de( Tag(0x0,0x2) ); + de.SetVR( VR::UI ); + std::string suid; + suid = Name; + if( suid.size() % 2 ) + suid.push_back( 0 ); + de.SetByteValue( suid.c_str(), (uint32_t)suid.size() ); + + return de; +} + +} // end namespace network +} // end namespace gdcm diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmAbstractSyntax.h b/gdcm/Source/MessageExchangeDefinition/gdcmAbstractSyntax.h new file mode 100644 index 0000000..fa73b26 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmAbstractSyntax.h @@ -0,0 +1,70 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMABSTRACTSYNTAX_H +#define GDCMABSTRACTSYNTAX_H + +#include "gdcmTypes.h" +#include "gdcmUIDs.h" +#include "gdcmDataElement.h" + +namespace gdcm +{ + +namespace network +{ + +/** + * \brief AbstractSyntax + * Table 9-14 + * ABSTRACT SYNTAX SUB-ITEM FIELDS + */ +class AbstractSyntax +{ +public: + AbstractSyntax(); + std::istream &Read(std::istream &is); + const std::ostream &Write(std::ostream &os) const; + + void SetName( const char *name ) { UpdateName( name ); } + const char *GetName() const { return Name.c_str(); } + + // accept a UIDs::TSType also... + void SetNameFromUID( UIDs::TSName tsname ); + //now that the PresentationContext messes around with UIDs and returns a string + //use that string as well. + //void SetNameFromUIDString( const std::string& inUIDName ); + + size_t Size() const; + + void Print(std::ostream &os) const; + + bool operator==(const AbstractSyntax & as) const + { + return Name == as.Name; + } + + DataElement GetAsDataElement() const; + +private: + void UpdateName( const char *name ); + static const uint8_t ItemType; + static const uint8_t Reserved2; + uint16_t ItemLength; // len of + std::string /*AbstractSyntax*/ Name; // UID +}; + +} // end namespace network +} // end namespace gdcm + +#endif //GDCMABSTRACTSYNTAX_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmApplicationContext.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmApplicationContext.cxx new file mode 100644 index 0000000..9d58334 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmApplicationContext.cxx @@ -0,0 +1,97 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmApplicationContext.h" +#include "gdcmSwapper.h" + +#include + +namespace gdcm +{ +namespace network +{ +const uint8_t ApplicationContext::ItemType = 0x10; +const uint8_t ApplicationContext::Reserved2 = 0x00; + +// PS 3.7 - 2011 +// A.2.1 DICOM Registered Application Context Names +static const char DICOMApplicationContextName[] = "1.2.840.10008.3.1.1.1"; + +ApplicationContext::ApplicationContext() +{ + UpdateName( DICOMApplicationContextName ); +} + +std::istream &ApplicationContext::Read(std::istream &is) +{ + //uint8_t itemtype = 0x0; + //is.read( (char*)&itemtype, sizeof(ItemType) ); + //assert( itemtype == ItemType ); + uint8_t reserved2 = 0x0; + is.read( (char*)&reserved2, sizeof(Reserved2) ); + uint16_t itemlength; + is.read( (char*)&itemlength, sizeof(ItemLength) ); + SwapperDoOp::SwapArray(&itemlength,1); + ItemLength = itemlength; + + char name[256]; + assert( itemlength < 256 ); + is.read( name, ItemLength ); + Name = std::string(name,itemlength); + assert( Name == DICOMApplicationContextName ); + + return is; +} + +const std::ostream &ApplicationContext::Write(std::ostream &os) const +{ + os.write( (char*)&ItemType, sizeof(ItemType) ); + os.write( (char*)&Reserved2, sizeof(Reserved2) ); + uint16_t copy = ItemLength; + SwapperDoOp::SwapArray(©,1); + os.write( (char*)©, sizeof(ItemLength) ); + + assert( Name == DICOMApplicationContextName ); + os.write( Name.c_str(), Name.size() ); + return os; +} + +size_t ApplicationContext::Size() const +{ + size_t ret = 0; + assert( Name.size() == ItemLength ); + ret += sizeof(ItemType); + ret += sizeof(Reserved2); + ret += sizeof(ItemLength); + ret += ItemLength; + return ret; +} + +void ApplicationContext::UpdateName( const char *name ) +{ + if( name ) + { + Name = name; + assert( Name.size() < std::numeric_limits::max() ); + ItemLength = (uint16_t)Name.size(); + assert( (size_t)ItemLength + 4 == Size() ); + } +} + +void ApplicationContext::Print(std::ostream &os) const +{ + os << Name << std::endl; +} + +} // end namespace network +} // end namespace gdcm diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmApplicationContext.h b/gdcm/Source/MessageExchangeDefinition/gdcmApplicationContext.h new file mode 100644 index 0000000..450afd8 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmApplicationContext.h @@ -0,0 +1,58 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMAPPLICATIONCONTEXT_H +#define GDCMAPPLICATIONCONTEXT_H + +#include "gdcmTypes.h" + +namespace gdcm +{ + +namespace network +{ + +/** + * \brief ApplicationContext + * Table 9-12 + * APPLICATION CONTEXT ITEM FIELDS + * \todo + * Looks like Application Context can only be 64 bytes at max (see Figure 9-1 / PS 3.8 - 2009 ) + */ +class ApplicationContext +{ +public: + ApplicationContext(); + std::istream &Read(std::istream &is); + const std::ostream &Write(std::ostream &os) const; + + void SetName( const char *name ) { UpdateName( name ); } + const char *GetName() const { return Name.c_str(); } + size_t Size() const; + + //static const uint8_t GetItemType() { return ItemType; } + void Print(std::ostream &os) const; + +private: + void UpdateName( const char *name ); + static const uint8_t ItemType; + static const uint8_t Reserved2; + uint16_t ItemLength; // len of application context name + std::string /*ApplicationContext*/ Name; // UID +}; + +} // end namespace network + +} // end namespace gdcm + +#endif //GDCMAPPLICATIONCONTEXT_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmAsynchronousOperationsWindowSub.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmAsynchronousOperationsWindowSub.cxx new file mode 100644 index 0000000..6940598 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmAsynchronousOperationsWindowSub.cxx @@ -0,0 +1,99 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmAsynchronousOperationsWindowSub.h" +#include "gdcmFileMetaInformation.h" +#include "gdcmSwapper.h" + +namespace gdcm +{ +namespace network +{ +const uint8_t AsynchronousOperationsWindowSub::ItemType = 0x53; +const uint8_t AsynchronousOperationsWindowSub::Reserved2 = 0x00; + +AsynchronousOperationsWindowSub::AsynchronousOperationsWindowSub() +{ + ItemLength = 0; + MaximumNumberOperationsInvoked = 0; + MaximumNumberOperationsPerformed = 0; + + ItemLength = (uint16_t)(Size() - 4); + assert( (size_t)ItemLength + 4 == Size() ); +} + +std::istream &AsynchronousOperationsWindowSub::Read(std::istream &is) +{ + //uint8_t itemtype = 0x0; + //is.read( (char*)&itemtype, sizeof(ItemType) ); + //assert( itemtype == ItemType ); + uint8_t reserved2; + is.read( (char*)&reserved2, sizeof(Reserved2) ); + uint16_t itemlength; + is.read( (char*)&itemlength, sizeof(ItemLength) ); + SwapperDoOp::SwapArray(&itemlength,1); + ItemLength = itemlength; + + uint16_t maximumnumberoperationsinvoked; + is.read( (char*)&maximumnumberoperationsinvoked, sizeof(MaximumNumberOperationsInvoked) ); + SwapperDoOp::SwapArray(&maximumnumberoperationsinvoked,1); + MaximumNumberOperationsInvoked = maximumnumberoperationsinvoked; + + uint16_t maximumnumberoperationsperformed; + is.read( (char*)&maximumnumberoperationsperformed, sizeof(MaximumNumberOperationsPerformed) ); + SwapperDoOp::SwapArray(&maximumnumberoperationsperformed,1); + MaximumNumberOperationsPerformed = maximumnumberoperationsperformed; + + return is; +} + +const std::ostream &AsynchronousOperationsWindowSub::Write(std::ostream &os) const +{ + os.write( (char*)&ItemType, sizeof(ItemType) ); + os.write( (char*)&Reserved2, sizeof(Reserved2) ); + //os.write( (char*)&ItemLength, sizeof(ItemLength) ); + uint16_t copy = ItemLength; + SwapperDoOp::SwapArray(©,1); + os.write( (char*)©, sizeof(ItemLength) ); + + uint16_t maximumnumberoperationsinvoked = MaximumNumberOperationsInvoked; + SwapperDoOp::SwapArray(&maximumnumberoperationsinvoked,1); + os.write( (char*)&maximumnumberoperationsinvoked, sizeof(MaximumNumberOperationsInvoked) ); + + uint16_t maximumnumberoperationsperformed = MaximumNumberOperationsPerformed; + SwapperDoOp::SwapArray(&maximumnumberoperationsperformed,1); + os.write( (char*)&maximumnumberoperationsperformed, sizeof(MaximumNumberOperationsPerformed) ); + + return os; +} + +size_t AsynchronousOperationsWindowSub::Size() const +{ + size_t ret = 0; + ret += sizeof(ItemType); + ret += sizeof(Reserved2); + ret += sizeof(ItemLength); + ret += sizeof(MaximumNumberOperationsInvoked); + ret += sizeof(MaximumNumberOperationsPerformed); + + return ret; +} + +void AsynchronousOperationsWindowSub::Print(std::ostream &os) const +{ + os << "MaximumNumberOperationsInvoked: " << MaximumNumberOperationsInvoked << std::endl; + os << "MaximumNumberOperationsPerformed: " << MaximumNumberOperationsPerformed << std::endl; +} + +} // end namespace network +} // end namespace gdcm diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmAsynchronousOperationsWindowSub.h b/gdcm/Source/MessageExchangeDefinition/gdcmAsynchronousOperationsWindowSub.h new file mode 100644 index 0000000..2f92683 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmAsynchronousOperationsWindowSub.h @@ -0,0 +1,54 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMASYNCHRONOUSOPERATIONSWINDOWSUB_H +#define GDCMASYNCHRONOUSOPERATIONSWINDOWSUB_H + +#include "gdcmTypes.h" + +namespace gdcm +{ + +namespace network +{ + +/** + * \brief AsynchronousOperationsWindowSub + * PS 3.7 + * Table D.3-7 + * ASYNCHRONOUS OPERATIONS WINDOW SUB-ITEM FIELDS + * (A-ASSOCIATE-RQ) + */ +class AsynchronousOperationsWindowSub +{ +public: + AsynchronousOperationsWindowSub(); + std::istream &Read(std::istream &is); + const std::ostream &Write(std::ostream &os) const; + + size_t Size() const; + void Print(std::ostream &os) const; + +private: + static const uint8_t ItemType; + static const uint8_t Reserved2; + uint16_t ItemLength; + uint16_t MaximumNumberOperationsInvoked; + uint16_t MaximumNumberOperationsPerformed; +}; + +} // end namespace network + +} // end namespace gdcm + +#endif // GDCMASYNCHRONOUSOPERATIONSWINDOWSUB_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmBaseCompositeMessage.h b/gdcm/Source/MessageExchangeDefinition/gdcmBaseCompositeMessage.h new file mode 100644 index 0000000..7ca0316 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmBaseCompositeMessage.h @@ -0,0 +1,66 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#ifndef GDCMBASECOMPOSITEMESSSAGE_H +#define GDCMBASECOMPOSITEMESSSAGE_H + +#include "gdcmPresentationDataValue.h" +#include "gdcmBaseRootQuery.h" + +#include + +namespace gdcm +{ + namespace network + { +class ULConnection; +/** + * \brief BaseCompositeMessage + * The Composite events described in section 3.7-2009 of the DICOM standard all + * use their own messages. These messages are constructed using Presentation + * Data Values, from section 3.8-2009 of the standard, and then fill in + * appropriate values in their datasets. + * + * So, for the five composites: + * \li C-ECHO + * \li C-FIND + * \li C-MOVE + * \li C-GET + * \li C-STORE + * there are a series of messages. However, all of these messages are obtained + * as part of a PDataPDU, and all have to be placed there. Therefore, since + * they all have shared functionality and construction tropes, that will be put + * into a base class. Further, the base class will be then returned by the + * factory class, gdcmCompositePDUFactory. + * + * This is an abstract class. It cannot be instantiated on its own. + */ +class BaseCompositeMessage +{ + public: + virtual ~BaseCompositeMessage() {} + //construct the appropriate pdv and dataset for this message + //for instance, setting tag 0x0,0x100 to the appropriate value + //the pdv, as described in Annex E of 3.8-2009, is the first byte + //of the message (the MessageHeader), and then the subsequent dataset + //that describes the operation. + virtual std::vector ConstructPDV(const ULConnection &inConnection, + const BaseRootQuery * inRootQuery) = 0; + }; + } +} +#endif //BASECOMPOSITEMESSSAGE_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmBasePDU.h b/gdcm/Source/MessageExchangeDefinition/gdcmBasePDU.h new file mode 100644 index 0000000..a0c174d --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmBasePDU.h @@ -0,0 +1,67 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#ifndef GDCMBASEPDU_H +#define GDCMBASEPDU_H + +#include "gdcmTypes.h" + +namespace gdcm +{ +namespace network +{ + +/** + * \brief BasePDU + * base class for PDUs + * + * all PDUs start with the first ten bytes as specified: + * 01 PDU type + * 02 reserved + * 3-6 PDU Length (unsigned) + * 7-10 variable + * + * on some, 7-10 are split (7-8 as protocol version in Associate-RQ, for instance, + * while associate-rj splits those four bytes differently). + * + * Also common to all the PDUs is their ability to read and write to a stream. + * + * So, let's just get them all bunched together into one (abstract) class, shall we? + * + * Why? + * 1) so that the ULEvent can have the PDU stored in it, since the event takes PDUs and not + * other class structures (other class structures get converted into PDUs) + * 2) to make reading PDUs in the event loop cleaner + */ +class BasePDU +{ +public: + virtual ~BasePDU() {} + + virtual std::istream &Read(std::istream &is) = 0; + virtual const std::ostream &Write(std::ostream &os) const = 0; + + virtual size_t Size() const = 0; + virtual void Print(std::ostream &os) const = 0; + + virtual bool IsLastFragment() const = 0; +}; + +} // end namespace network +} // end namespace gdcm + +#endif // GDCMBASEPDU_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmBaseRootQuery.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmBaseRootQuery.cxx new file mode 100644 index 0000000..e5350f8 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmBaseRootQuery.cxx @@ -0,0 +1,310 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +/* +contains: a baseclass which will produce a dataset for c-find and c-move with +patient root + +This class contains the functionality used in patient c-find and c-move +queries. StudyRootQuery derives from this class. + +Namely: +1) list all tags associated with a particular query type +2) produce a query dataset via tag association + +Eventually, it can be used to validate a particular dataset type. + +The dataset held by this object (or, really, one of its derivates) should be +passed to a c-find or c-move query. + +*/ + +#include "gdcmBaseRootQuery.h" +#include "gdcmDataElement.h" +#include "gdcmTag.h" +#include "gdcmDict.h" +#include "gdcmDictEntry.h" +#include "gdcmDicts.h" +#include "gdcmGlobal.h" +#include "gdcmAttribute.h" +#include "gdcmWriter.h" +#include "gdcmPrinter.h" +#include + +namespace gdcm +{ + +BaseRootQuery::BaseRootQuery() +{ + //nothing to do, really +} +BaseRootQuery::~BaseRootQuery() +{ + //nothing to do, really +} + +void BaseRootQuery::SetSearchParameter(const Tag& inTag, const DictEntry& inDictEntry, const std::string& inValue) +{ + //borrowed this code from anonymization; not sure if it's correct, though. + DataElement de; + de.SetTag( inTag ); + const VR &vr = inDictEntry.GetVR(); + if( vr.IsDual() ) + { + if( vr == VR::US_SS ) + { + de.SetVR( VR::US ); + } + else if( vr == VR::US_SS_OW ) + { + de.SetVR( VR::OW ); + } + else if( vr == VR::OB_OW ) + { + de.SetVR( VR::OB ); + } + } + else + { + de.SetVR( vr ); + } + + std::string thePaddedValue = inValue; + if (thePaddedValue.length() % 2 ){ + thePaddedValue.push_back(' '); + } + + assert(thePaddedValue.length() < std::numeric_limits::max()); + de.SetByteValue(thePaddedValue.c_str(), (uint32_t)thePaddedValue.length()); + + //Replace any existing values + mDataSet.Replace(de); +} + +void BaseRootQuery::SetSearchParameter(const Tag& inTag, const std::string& inValue){ + //IF WE WANTED, we could validate the incoming tag as belonging to our set of tags. + //but we will not. + + static const Global &g = Global::GetInstance(); + static const Dicts &dicts = g.GetDicts(); + static const Dict &pubdict = dicts.GetPublicDict(); + + const DictEntry &dictentry = pubdict.GetDictEntry(inTag); + + SetSearchParameter(inTag, dictentry, inValue); + +} +void BaseRootQuery::SetSearchParameter(const std::string& inKeyword, const std::string& inValue){ + + static const Global &g = Global::GetInstance(); + static const Dicts &dicts = g.GetDicts(); + static const Dict &pubdict = dicts.GetPublicDict(); + + Tag theTag; + const DictEntry &dictentry = pubdict.GetDictEntryByName(inKeyword.c_str(), theTag); + SetSearchParameter(theTag, dictentry, inValue); +} + +const std::ostream &BaseRootQuery::WriteHelpFile(std::ostream &os) +{ + //mash all the query types into a vector for ease-of-use + std::vector theQueries; + std::vector::const_iterator qtor; + theQueries.push_back(&mPatient); + theQueries.push_back(&mStudy); + theQueries.push_back(&mSeries); + theQueries.push_back(&mImage); + + + std::vector theTags; + std::vector::iterator ttor; + + + static const Global &g = Global::GetInstance(); + static const Dicts &dicts = g.GetDicts(); + static const Dict &pubdict = dicts.GetPublicDict(); + + os << "The following tags must be supported by a C-FIND/C-MOVE " << mHelpDescription << ": " << std::endl; + for (qtor = theQueries.begin(); qtor < theQueries.end(); qtor++){ + os << "Level: " << (*qtor)->GetName() << std::endl; + theTags = (*qtor)->GetRequiredTags(mRootType); + for (ttor = theTags.begin(); ttor < theTags.end(); ttor++){ + const DictEntry &dictentry = pubdict.GetDictEntry(*ttor); + os << "Keyword: " << dictentry.GetKeyword() << " Tag: " << *ttor << std::endl; + } + os << std::endl; + } + + + os << std::endl; + os << "The following tags are unique at each level of a " << mHelpDescription << ": " << std::endl; + for (qtor = theQueries.begin(); qtor < theQueries.end(); qtor++){ + os << "Level: " << (*qtor)->GetName() << std::endl; + theTags = (*qtor)->GetUniqueTags(mRootType); + for (ttor = theTags.begin(); ttor < theTags.end(); ttor++){ + const DictEntry &dictentry = pubdict.GetDictEntry(*ttor); + os << "Keyword: " << dictentry.GetKeyword() << " Tag: " << *ttor << std::endl; + } + os << std::endl; + } + + + os << std::endl; + os << "The following tags are optional at each level of a " << mHelpDescription << ": " << std::endl; + for (qtor = theQueries.begin(); qtor < theQueries.end(); qtor++){ + os << "Level: " << (*qtor)->GetName() << std::endl; + theTags = (*qtor)->GetOptionalTags(mRootType); + for (ttor = theTags.begin(); ttor < theTags.end(); ttor++){ + const DictEntry &dictentry = pubdict.GetDictEntry(*ttor); + os << "Keyword: " << dictentry.GetKeyword() << " Tag: " << *ttor << std::endl; + } + os << std::endl; + } + + os << std::endl; + + return os; +} + + +bool BaseRootQuery::WriteQuery(const std::string& inFileName) +{ + Writer writer; + writer.SetCheckFileMetaInformation( false ); + writer.GetFile().GetHeader().SetDataSetTransferSyntax( + TransferSyntax::ImplicitVRLittleEndian ); + writer.GetFile().SetDataSet( GetQueryDataSet() ); + writer.SetFileName( inFileName.c_str() ); + if( !writer.Write() ) + { + gdcmWarningMacro( "Could not write: " << inFileName ); + return false; + } + return true; +} + +DataSet const & BaseRootQuery::GetQueryDataSet() const +{ + return mDataSet; +} + +DataSet & BaseRootQuery::GetQueryDataSet() +{ + return mDataSet; +} + +void BaseRootQuery::AddQueryDataSet(const DataSet & ds) +{ + // Cannot use std::set::insert in case a unique key was added (eg. 10,20 with an empty + // value). The user defined value for 10,20 in ds would not be taken into account + DataSet::ConstIterator it = ds.Begin(); + for( ; it != ds.End(); ++it ) + { + mDataSet.Replace( *it ); + } +} + +void BaseRootQuery::Print(std::ostream &os) const +{ + UIDs::TSName asuid = GetAbstractSyntaxUID(); + const char *asname = UIDs::GetUIDName( asuid ); + os << "===================== OUTGOING DIMSE MESSAGE ====================" << std::endl; + os << "Affected SOP Class UID :" << asname << std::endl; + os << "======================= END DIMSE MESSAGE =======================" << std::endl; + + os << "Find SCU Request Identifiers:" << std::endl; + os << "# Dicom-Data-Set" << std::endl; + os << "# Used TransferSyntax: Unknown Transfer Syntax" << std::endl; + Printer p; + p.PrintDataSet( mDataSet, os ); +} + +static const char *QueryLevelStrings[] = { + "PATIENT ", + "STUDY ", + "SERIES", + "IMAGE ", +}; + +const char *BaseRootQuery::GetQueryLevelString( EQueryLevel ql ) +{ + return QueryLevelStrings[ ql ]; +} + +int BaseRootQuery::GetQueryLevelFromString( const char * str ) +{ + if( str ) + { + const std::string s = str; + static const int n = + sizeof( QueryLevelStrings ) / sizeof( *QueryLevelStrings ); + for( int i = 0; i < n; ++i ) + { + if( s == QueryLevelStrings[ i ] ) + { + return i; + } + } + } + return -1; // FIXME never use it as valid enum +} + +QueryBase * BaseRootQuery::Construct( ERootType inRootType, EQueryLevel qlevel ) +{ + QueryBase* qb = NULL; + // Check no new extension: + assert( inRootType == ePatientRootType || inRootType == eStudyRootType ); + + if( qlevel == ePatient ) + { + if( inRootType == ePatientRootType ) + { + qb = new QueryPatient; + } + } + else if( qlevel == eStudy ) + { + qb = new QueryStudy; + } + else if( qlevel == eSeries ) + { + qb = new QuerySeries; + } + else if( qlevel == eImage ) + { + qb = new QueryImage; + } + return qb; +} + +EQueryLevel BaseRootQuery::GetQueryLevelFromQueryRoot( ERootType roottype ) +{ + EQueryLevel level = ePatient; + switch( roottype ) + { + case ePatientRootType: + level = ePatient; + break; + case eStudyRootType: + level = eStudy; + break; + } + assert( level == eStudy || level == ePatient ); + return level; +} + +} // end namespace gdcm diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmBaseRootQuery.h b/gdcm/Source/MessageExchangeDefinition/gdcmBaseRootQuery.h new file mode 100644 index 0000000..490f717 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmBaseRootQuery.h @@ -0,0 +1,139 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#ifndef GDCMBASEROOTQUERY_H +#define GDCMBASEROOTQUERY_H + +#include "gdcmDataSet.h" +#include "gdcmUIDs.h" +#include "gdcmObject.h" +#include "gdcmQueryPatient.h" +#include "gdcmQueryStudy.h" +#include "gdcmQuerySeries.h" +#include "gdcmQueryImage.h" + +namespace gdcm +{ + class QueryFactory; + class DictEntry; + + enum EQueryLevel + { + // -1 is reserved do not use + ePatient = 0, + eStudy = 1, + eSeries = 2, + eImage = 3 + }; + enum EQueryType + { + eFind = 0, + eMove + }; + +/** + * \brief BaseRootQuery + * contains: a baseclass which will produce a dataset for c-find and c-move + * with patient/study root + * + * This class contains the functionality used in patient c-find and c-move + * queries. PatientRootQuery and StudyRootQuery derive from this class. + * + * Namely: + * 1) list all tags associated with a particular query type + * 2) produce a query dataset via tag association + * + * Eventually, it can be used to validate a particular dataset type. + * + * The dataset held by this object (or, really, one of its derivates) should be + * passed to a c-find or c-move query. + */ +class GDCM_EXPORT BaseRootQuery : public Object +{ + //these four classes contain the required, unique, and optional tags from the standard. + //used both to list the tags as well as to validate a dataset, if ever we were to do so. +protected: + QueryPatient mPatient; + QueryStudy mStudy; + QuerySeries mSeries; + QueryImage mImage; + + DataSet mDataSet; + friend class QueryFactory; + BaseRootQuery(); + + ERootType mRootType; //set in construction, and it's something else in the study root type + std::string mHelpDescription; //used when generating the help output + + void SetSearchParameter(const Tag& inTag, const DictEntry& inDictEntry, const std::string& inValue); +public: + virtual ~BaseRootQuery(); + + void SetSearchParameter(const Tag& inTag, const std::string& inValue); + void SetSearchParameter(const std::string& inKeyword, const std::string& inValue); + + const std::ostream &WriteHelpFile(std::ostream &os); + + //this function allows writing of the query to disk for storing for future use + //virtual in case it needs to be overiden + //returns false if the operation failed + bool WriteQuery(const std::string& inFileName); + + /// Set/Get the internal representation of the query as a DataSet + DataSet const & GetQueryDataSet() const; + DataSet & GetQueryDataSet(); + void AddQueryDataSet(const DataSet & ds); + + ///this function will return all tags at a given query level, so that + ///they maybe selected for searching. The boolean forFind is true + ///if the query is a find query, or false for a move query. + virtual std::vector GetTagListByLevel(const EQueryLevel& inQueryLevel) = 0; + + /// this function sets tag 8,52 to the appropriate value based on query level + /// also fills in the right unique tags, as per the standard's requirements + /// should allow for connection with dcmtk + virtual void InitializeDataSet(const EQueryLevel& inQueryLevel) = 0; + + ///have to be able to ensure that + ///0x8,0x52 is set (which will be true if InitializeDataSet is called...) + ///that the level is appropriate (ie, not setting PATIENT for a study query + ///that the tags in the query match the right level (either required, unique, optional) + ///by default, this function checks to see if the query is for finding, which is more + ///permissive than for moving. For moving, only the unique tags are allowed. + ///10 Jan 2011: adding in the 'strict' mode. + ///according to the standard (at least, how I've read it), only tags for a particular + ///level should be allowed in a particular query (ie, just series level tags in a series + ///level query). However, it seems that dcm4chee doesn't share that interpretation. + ///So, if 'inStrict' is false, then tags from the current level and all higher levels + ///are now considered valid. So, if you're doing a non-strict series-level query, + ///tags from the patient and study level can be passed along as well. + virtual bool ValidateQuery(bool inStrict = true) const = 0; + + virtual UIDs::TSName GetAbstractSyntaxUID() const = 0; + + void Print(std::ostream &os) const; + + static const char *GetQueryLevelString( EQueryLevel ql ); + static int GetQueryLevelFromString( const char * str ); + + static QueryBase * Construct(ERootType inRootType, EQueryLevel qlevel); + EQueryLevel GetQueryLevelFromQueryRoot( ERootType roottype ); +}; + +} // end namespace gdcm + +#endif //GDCMBASEROOTQUERY_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmCEchoMessages.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmCEchoMessages.cxx new file mode 100644 index 0000000..91378e4 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmCEchoMessages.cxx @@ -0,0 +1,85 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +/* +this file defines the messages for the cecho action +5 oct 2010 mmr +*/ + +#include "gdcmCEchoMessages.h" +#include "gdcmUIDs.h" +#include "gdcmAttribute.h" +#include "gdcmImplicitDataElement.h" +#include "gdcmPresentationContextRQ.h" +#include "gdcmCommandDataSet.h" +#include "gdcmULConnection.h" + +namespace gdcm{ +namespace network{ + +std::vector CEchoRQ::ConstructPDV( + const ULConnection &inConnection, const BaseRootQuery* inRootQuery) +{ + (void)inRootQuery; + PresentationDataValue thePDV; + PresentationContextRQ pc( UIDs::VerificationSOPClass ); + thePDV.SetPresentationContextID( + inConnection.GetPresentationContextIDFromPresentationContext(pc) ); + + thePDV.SetCommand(true); + thePDV.SetLastFragment(true); + //ignore incoming data set, make your own + + CommandDataSet ds; + ds.Insert( pc.GetAbstractSyntax().GetAsDataElement() ); + { + Attribute<0x0,0x100> at = { 48 }; + ds.Insert( at.GetAsDataElement() ); + } + { + Attribute<0x0,0x110> at = { 1 }; + ds.Insert( at.GetAsDataElement() ); + } + { + Attribute<0x0,0x800> at = { 257 }; + ds.Insert( at.GetAsDataElement() ); + } + { + Attribute<0x0,0x0> at = { 0 }; + unsigned int glen = ds.GetLength(); + assert( (glen % 2) == 0 ); + at.SetValue( glen ); + ds.Insert( at.GetAsDataElement() ); + } + + thePDV.SetDataSet(ds); + //!!!Mathieu, I assume you'll want to fix this + std::vector thePDVs; + thePDVs.push_back(thePDV); + return thePDVs; + +} + +std::vector CEchoRSP::ConstructPDVByDataSet(const DataSet* inDataSet){ + std::vector thePDV; + (void)inDataSet; + assert( 0 && "TODO" ); + return thePDV; +} + +}//namespace network +}//namespace gdcm diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmCEchoMessages.h b/gdcm/Source/MessageExchangeDefinition/gdcmCEchoMessages.h new file mode 100644 index 0000000..2c52c56 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmCEchoMessages.h @@ -0,0 +1,48 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#ifndef GDCMCECHOMESSAGES_H +#define GDCMCECHOMESSAGES_H + +#include "gdcmBaseCompositeMessage.h" + +namespace gdcm{ + namespace network{ + +class ULConnection; + +/** + * \brief CEchoRQ + * this file defines the messages for the cecho action + */ +class CEchoRQ : public BaseCompositeMessage { + public: + std::vector ConstructPDV(const ULConnection &inConnection, + const BaseRootQuery* inRootQuery); + }; + +/** + * \brief CEchoRSP + * this file defines the messages for the cecho action + */ + class CEchoRSP : public BaseCompositeMessage { + public: + std::vector ConstructPDVByDataSet(const DataSet* inDataSet); + }; + } +} +#endif // GDCMCECHOMESSAGES_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmCFindMessages.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmCFindMessages.cxx new file mode 100644 index 0000000..51d2abf --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmCFindMessages.cxx @@ -0,0 +1,122 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +/* +this file defines the messages for the cfind action +5 oct 2010 mmr +*/ + +#include "gdcmCFindMessages.h" +#include "gdcmUIDs.h" +#include "gdcmAttribute.h" +#include "gdcmImplicitDataElement.h" +#include "gdcmPresentationContextRQ.h" +#include "gdcmCommandDataSet.h" +#include "gdcmULConnection.h" + +namespace gdcm{ +namespace network{ + +std::vector CFindRQ::ConstructPDV( + const ULConnection &inConnection, const BaseRootQuery* inRootQuery) +{ + std::vector thePDVs; + PresentationDataValue thePDV; +#if 0 + int contextID = ePatientRootQueryRetrieveInformationModelFIND; + const char *uid = UIDs::GetUIDString( + UIDs::PatientRootQueryRetrieveInformationModelFIND ); + std::string suid = uid; + if (dynamic_cast(inRootQuery)!=NULL) + { + contextID = eStudyRootQueryRetrieveInformationModelFIND; + const char *uid2 = UIDs::GetUIDString( + UIDs::StudyRootQueryRetrieveInformationModelFIND ); + suid = uid2; + } + thePDV.SetPresentationContextID(contextID);//could it be 5, if the server does study? +#else + PresentationContextRQ pc( inRootQuery->GetAbstractSyntaxUID() ); + uint8_t presidx = inConnection.GetPresentationContextIDFromPresentationContext(pc); + if( !presidx ) + { + // try harder: + PresentationContextRQ pc2( inRootQuery->GetAbstractSyntaxUID(), UIDs::ExplicitVRLittleEndian); + presidx = inConnection.GetPresentationContextIDFromPresentationContext(pc2); + if( !presidx ) + { + gdcmErrorMacro( "Could not find Pres Cont ID" ); + return thePDVs; + } + } + thePDV.SetPresentationContextID( presidx ); +#endif + + thePDV.SetCommand(true); + thePDV.SetLastFragment(true); + //ignore incoming data set, make your own + + CommandDataSet ds; + ds.Insert( pc.GetAbstractSyntax().GetAsDataElement() ); + { + Attribute<0x0,0x100> at = { 32 }; + ds.Insert( at.GetAsDataElement() ); + } + { + Attribute<0x0,0x110> at = { 1 }; + ds.Insert( at.GetAsDataElement() ); + } + { + Attribute<0x0,0x700> at = { 2 }; + ds.Insert( at.GetAsDataElement() ); + } + { + Attribute<0x0,0x800> at = { 1 }; + ds.Insert( at.GetAsDataElement() ); + } + { + Attribute<0x0,0x0> at = { 0 }; + unsigned int glen = ds.GetLength(); + assert( (glen % 2) == 0 ); + at.SetValue( glen ); + ds.Insert( at.GetAsDataElement() ); + } + + thePDV.SetDataSet(ds); + thePDVs.push_back(thePDV); + thePDV.SetDataSet(inRootQuery->GetQueryDataSet()); + thePDV.SetMessageHeader( 2 ); + thePDVs.push_back(thePDV); + return thePDVs; +} + +std::vector CFindRSP::ConstructPDVByDataSet(const DataSet* inDataSet){ + std::vector thePDV; + (void)inDataSet; + assert( 0 && "TODO" ); + return thePDV; +} +std::vector CFindCancelRQ::ConstructPDVByDataSet(const DataSet* inDataSet){ + std::vector thePDV; + (void)inDataSet; + assert( 0 && "TODO" ); + return thePDV; +} + + +}//namespace network +}//namespace gdcm diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmCFindMessages.h b/gdcm/Source/MessageExchangeDefinition/gdcmCFindMessages.h new file mode 100644 index 0000000..18b3a14 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmCFindMessages.h @@ -0,0 +1,59 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#ifndef GDCMCFINDMESSAGES_H +#define GDCMCFINDMESSAGES_H + +#include "gdcmBaseCompositeMessage.h" +#include "gdcmBaseRootQuery.h" + +namespace gdcm +{ +namespace network +{ + +/** + * \brief CFindRQ + * this file defines the messages for the cfind action + */ +class CFindRQ : public BaseCompositeMessage +{ +public: + std::vector ConstructPDV(const ULConnection &inConnection, + const BaseRootQuery* inRootQuery); +}; + +/** + * \brief CFindRSP + * this file defines the messages for the cfind action + */ +class CFindRSP : public BaseCompositeMessage { +public: + std::vector ConstructPDVByDataSet(const DataSet* inDataSet); +}; + +/** + * \brief CFindCancelRQ + * this file defines the messages for the cfind action + */ + class CFindCancelRQ : public BaseCompositeMessage { + public: + std::vector ConstructPDVByDataSet(const DataSet* inDataSet); + }; +} +} +#endif diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmCMoveMessages.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmCMoveMessages.cxx new file mode 100644 index 0000000..0eba681 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmCMoveMessages.cxx @@ -0,0 +1,133 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#include "gdcmCMoveMessages.h" +#include "gdcmUIDs.h" +#include "gdcmAttribute.h" +#include "gdcmImplicitDataElement.h" +#include "gdcmCommandDataSet.h" +#include "gdcmPresentationContextRQ.h" +#include "gdcmULConnection.h" +#include "gdcmAAssociateRQPDU.h" + +namespace gdcm{ +namespace network{ + +std::vector CMoveRQ::ConstructPDV( + const ULConnection &inConnection, + const BaseRootQuery* inRootQuery) +{ + std::vector thePDVs; + PresentationContextRQ pc( inRootQuery->GetAbstractSyntaxUID() ); +{ + PresentationDataValue thePDV; +#if 0 + int contextID = ePatientRootQueryRetrieveInformationModelMOVE; + const char *uid = UIDs::GetUIDString( + UIDs::PatientRootQueryRetrieveInformationModelMOVE ); + std::string suid = uid; + if (dynamic_cast(inRootQuery)!=NULL) + { + contextID = eStudyRootQueryRetrieveInformationModelMOVE; + const char *uid2 = UIDs::GetUIDString( + UIDs::StudyRootQueryRetrieveInformationModelMOVE ); + suid = uid2; + } + thePDV.SetPresentationContextID(contextID);//could it be 5, if the server does study? +#else + thePDV.SetPresentationContextID( + inConnection.GetPresentationContextIDFromPresentationContext(pc) ); +#endif + thePDV.SetCommand(true); + thePDV.SetLastFragment(true); + //ignore incoming data set, make your own + + CommandDataSet ds; + ds.Insert( pc.GetAbstractSyntax().GetAsDataElement() ); + { + Attribute<0x0,0x100> at = { 33 };//0021H, as per the spec + ds.Insert( at.GetAsDataElement() ); + } + { + Attribute<0x0,0x110> at = { 1 }; + ds.Insert( at.GetAsDataElement() ); + } + { + Attribute<0x0,0x600> at = { "" }; + const char *calling = inConnection.GetConnectionInfo().GetCallingAETitle(); + assert( AAssociateRQPDU::IsAETitleValid( calling ) ); + at.SetValue( calling ); + ds.Insert( at.GetAsDataElement() ); + } + { + Attribute<0x0,0x700> at = { 0 }; + ds.Insert( at.GetAsDataElement() ); + } + { + Attribute<0x0,0x800> at = { 1 }; + ds.Insert( at.GetAsDataElement() ); + } + { + Attribute<0x0,0x0> at = { 0 }; + unsigned int glen = ds.GetLength(); + assert( (glen % 2) == 0 ); + at.SetValue( glen ); + ds.Insert( at.GetAsDataElement() ); + } + + thePDV.SetDataSet(ds); + thePDVs.push_back(thePDV); +} + { + PresentationDataValue thePDV; + thePDV.SetPresentationContextID( + inConnection.GetPresentationContextIDFromPresentationContext(pc) ); + //thePDV.SetBlob( sub ); + thePDV.SetDataSet(inRootQuery->GetQueryDataSet()); + thePDV.SetMessageHeader( 2 ); + thePDVs.push_back(thePDV); + } + return thePDVs; + +} + +//this is a private function, should not be callable +//but if you manage to do call it, return a blank dataset. +std::vector CMoveRQ::ConstructPDVByDataSet(const DataSet* inDataSet){ + std::vector thePDVs; + (void)inDataSet; + assert( 0 && "TODO" ); + return thePDVs; + +} + +std::vector CMoveRSP::ConstructPDVByDataSet(const DataSet* inDataSet){ + std::vector thePDV; + (void)inDataSet; + assert( 0 && "TODO" ); + return thePDV; +} +std::vector CMoveCancelRq::ConstructPDVByDataSet(const DataSet* inDataSet){ + std::vector thePDV; + (void)inDataSet; + assert( 0 && "TODO" ); + return thePDV; +} + + +}//namespace network +}//namespace gdcm diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmCMoveMessages.h b/gdcm/Source/MessageExchangeDefinition/gdcmCMoveMessages.h new file mode 100644 index 0000000..8452956 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmCMoveMessages.h @@ -0,0 +1,57 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#ifndef GDCMCMOVEMESSAGES_H +#define GDCMCMOVEMESSAGES_H + +#include "gdcmBaseCompositeMessage.h" +#include "gdcmBaseRootQuery.h" + +namespace gdcm{ + namespace network{ + class ULConnection; +/** + * \brief CMoveRQ + * this file defines the messages for the cmove action + */ +class CMoveRQ : public BaseCompositeMessage { + //this class will fulfill the inheritance, + //but additional information is needed by cmovd + //namely, the root type or the calling AE-TITLE + std::vector ConstructPDVByDataSet(const DataSet* inDataSet); + public: + std::vector ConstructPDV( + const ULConnection &inConnection, + const BaseRootQuery* inRootQuery); + }; + +/** + * \brief CMoveRSP + * this file defines the messages for the cmove action + */ +class CMoveRSP : public BaseCompositeMessage { + public: + std::vector ConstructPDVByDataSet(const DataSet* inDataSet); + }; + + class CMoveCancelRq : public BaseCompositeMessage { + public: + std::vector ConstructPDVByDataSet(const DataSet* inDataSet); + }; + } +} +#endif diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmCStoreMessages.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmCStoreMessages.cxx new file mode 100644 index 0000000..a43b6d0 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmCStoreMessages.cxx @@ -0,0 +1,351 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#include "gdcmCStoreMessages.h" + +#include "gdcmUIDs.h" +#include "gdcmAttribute.h" +#include "gdcmFile.h" +#include "gdcmImplicitDataElement.h" +#include "gdcmPresentationContextRQ.h" +#include "gdcmCommandDataSet.h" +#include "gdcmBasePDU.h" +#include "gdcmPDataTFPDU.h" +#include "gdcmMediaStorage.h" +#include "gdcmULConnection.h" +#include "gdcmWriter.h" + +#include + +namespace gdcm{ + +class DataSetWriter : public Writer +{ +public: + DataSetWriter() + { + SetWriteDataSetOnly( true ); + } +}; + +namespace network{ + +std::vector CStoreRQ::ConstructPDV( +const ULConnection &inConnection, File const & file ) +{ +const DataSet* inDataSet = &file.GetDataSet(); + + std::vector thePDVs; + PresentationContextRQ pc( UIDs::VerificationSOPClass ); + uint8_t prescontid; +{ + assert( inDataSet ); + PresentationDataValue thePDV; +#if 0 + std::string UIDString; + thePDV.SetPresentationContextID( + PresentationContextRQ::AssignPresentationContextID(*inDataSet, UIDString)); +#else +{ + MediaStorage mst; + if (!mst.SetFromDataSet(*inDataSet)) + { + throw Exception("Missing MediaStorage"); + } + UIDs uid; + uid.SetFromUID( MediaStorage::GetMSString(mst) ); + //as.SetNameFromUID( uid ); + pc.GetAbstractSyntax().SetName( uid.GetString() ); +} + +// prescontid = inConnection.GetPresentationContextIDFromAbstractSyntax(as); +// thePDV.SetPresentationContextID( prescontid ); +#endif + + thePDV.SetCommand(true); + thePDV.SetLastFragment(true); + //ignore incoming data set, make your own + + CommandDataSet ds; + { + DataElement de( Tag(0x0,0x2) ); + de.SetVR( VR::UI ); + if( !inDataSet->FindDataElement( Tag(0x0008, 0x0016) ) || + inDataSet->GetDataElement( Tag(0x0008, 0x0016) ).IsEmpty() ) + { + throw Exception("Missing SOP Class UID"); + } + const DataElement& msclass = inDataSet->GetDataElement( Tag(0x0008, 0x0016) ); + const char *uid = msclass.GetByteValue()->GetPointer(); + assert( uid ); + std::string suid = std::string(uid, msclass.GetByteValue()->GetLength()); + + // self check +// const PresentationContextAC * pc = inConnection.GetPresentationContextACByID(prescontid); +// assert( pc ); +// TransferSyntaxSub const &tssub = pc->GetTransferSyntax(); + const TransferSyntax & fmits = file.GetHeader().GetDataSetTransferSyntax(); + const char *tsuidvalue = fmits.GetString(); +// TransferSyntaxSub tssub; +// tssub.SetName( tsuidvalue ); + pc.GetTransferSyntax(0).SetName( tsuidvalue ); + + std::string tsuid = fmits.GetString(); + + prescontid = inConnection.GetPresentationContextIDFromPresentationContext(pc); + // prescontid cannot possibly be unknown since we are only looking in our own + // AAssociateRQPDU + assert( prescontid != 0 ); + const PresentationContextRQ * rqpc = inConnection.GetPresentationContextRQByID(prescontid); + assert( rqpc ); + + // Now let's see if this best matching PresentationContextRQ can be found in the AC + // section of the AAssociateACPDU + const PresentationContextAC * acpc = inConnection.GetPresentationContextACByID(prescontid); + + // the following make sure that the accepted Presentation Context match the actual encoding + // of the current File + // ADV: technically we could use an explicit VR encoded dataset and send it over + // an implicit TS accecpted Transfer syntax. However thing do not interchange well + // so we really need a filter to check whether conversion is ok or not. + if( acpc == 0 ) + { + // Technically we should fallback to something else. Anyway lets' give up + // and hope the user will convert the encapsulated stream to something else... + throw Exception("Server side refuse our proposed PC."); + } + + TransferSyntaxSub const & actssub = acpc->GetTransferSyntax(); + assert( rqpc->GetNumberOfTransferSyntaxes() == 1 ); // TODO FIXME + TransferSyntaxSub const & rqtssub = rqpc->GetTransferSyntax(0); + if( !(actssub == rqtssub) ) + { + gdcmDebugMacro( "Faulty Presentation Context : " + << (int)acpc->GetPresentationContextID() ); + throw Exception("Server side refuse our proposed PC for context id" ); + } + +#if 0 + // For some reason using a dcmtk 3.5.4 server. The PresCont even if refused returned + // filled with the default Implicit Little Endian. So make sure TS matches + TransferSyntaxSub const & actssub = acpc->GetTransferSyntax(); + TransferSyntaxSub const & dummy0 = pc.GetTransferSyntax(0); + if( !(actssub == pc.GetTransferSyntax(0)) ) + { + gdcmDebugMacro( "Faulty Presentation Context : " + << (int)acpc->GetPresentationContextID() ); + throw Exception("Server side refuse our proposed PC for context id" ); + } +#endif + + thePDV.SetPresentationContextID( prescontid ); + + assert(suid.size() < std::numeric_limits::max()); + de.SetByteValue( suid.c_str(), (uint32_t)suid.size() ); + ds.Insert( de ); + } + + { + assert( inDataSet->FindDataElement( Tag(0x0008, 0x0018) ) ); + const DataElement& msinst = inDataSet->GetDataElement( Tag(0x0008, 0x0018) ); + std::string suid; + DataElement de( Tag(0x0,0x1000) ); + de.SetVR( VR::UI ); + if( !msinst.IsEmpty() ) + { + const ByteValue* bv = msinst.GetByteValue(); + if( bv ) + { + const char *uid = bv->GetPointer(); + assert( uid ); + suid = std::string(uid, bv->GetLength() ); + assert(suid.size() < std::numeric_limits::max()); + } + } + de.SetByteValue( suid.c_str(), (uint32_t)suid.size() ); + ds.Insert( de ); + } + + { + Attribute<0x0,0x100> at = { 1 }; + ds.Insert( at.GetAsDataElement() ); + } +static uint32_t messageid = 1; + { + Attribute<0x0,0x110> at = { 0 }; + at.SetValue( (unsigned short)messageid++ ); + assert( messageid < std::numeric_limits::max()); + ds.Insert( at.GetAsDataElement() ); + } + { + Attribute<0x0,0x700> at = { 2 }; + ds.Insert( at.GetAsDataElement() ); + } + { + Attribute<0x0,0x800> at = { 1 }; + ds.Insert( at.GetAsDataElement() ); + } + { + Attribute<0x0,0x0> at = { 0 }; + unsigned int glen = ds.GetLength(); + assert( (glen % 2) == 0 ); + at.SetValue( glen ); + ds.Insert( at.GetAsDataElement() ); + } + + thePDV.SetDataSet(ds); + + //!!!Mathieu, I assume you'll want to fix this + thePDVs.push_back(thePDV); +} + + // now let's chunk'ate the dataset: +{ + std::stringstream ss; +#if 0 + inDataSet->Write( ss ); +#else + DataSetWriter writer; + writer.SetStream( ss ); + writer.SetFile( file ); + writer.Write(); +#endif + + std::string ds_copy = ss.str(); + // E: 0006:0308 DUL Illegal PDU Length 16390. Max expected 16384 + //const size_t maxpdu = 16384 - 6; + size_t maxpdu = 16378; + maxpdu = inConnection.GetMaxPDUSize() - 6; + size_t len = ds_copy.size(); + const char *begin = ds_copy.c_str(); + const char *end = begin + len; + const char *cur = begin; + while( cur < end ) + { + size_t remaining = std::min( maxpdu , (size_t)(end - cur) ); + std::string sub( cur, remaining ); + + PresentationDataValue thePDV; + std::string UIDString; + thePDV.SetPresentationContextID( prescontid ); + + thePDV.SetBlob( sub ); + cur += remaining; + + if( cur < end ) + thePDV.SetMessageHeader( 0 ); + else + { + assert( cur == end ); + thePDV.SetMessageHeader( 2 ); + } + thePDVs.push_back(thePDV); + } +} + + return thePDVs; + +} + +//private hack +std::vector CStoreRQ::ConstructPDV( +const ULConnection &inConnection, const BaseRootQuery* inRootQuery) +{ + std::vector thePDVs; + (void)inRootQuery; + (void)inConnection; + assert( 0 && "TODO" ); + return thePDVs; +} + +//private hack +std::vector CStoreRSP::ConstructPDV(const ULConnection &, const BaseRootQuery* inRootQuery) +{ + std::vector thePDVs; + (void)inRootQuery; + assert( 0 && "TODO" ); + return thePDVs; +} + +std::vector CStoreRSP::ConstructPDV(const DataSet* inDataSet, const BasePDU* inPDU){ + std::vector thePDVs; + +///should be passed the received dataset, ie, the cstorerq, so that +///the cstorersp contains the appropriate SOP instance UIDs. + CommandDataSet ds; + + uint32_t theMessageID = 0; + Attribute<0x0,0x0110> at3 = { 0 }; + at3.SetFromDataSet( *inDataSet ); + theMessageID = at3.GetValue(); + + const DataElement &de1 = inDataSet->GetDataElement( Tag( 0x0000,0x0002 ) ); + const DataElement &de2 = inDataSet->GetDataElement( Tag( 0x0000,0x1000 ) ); + //pass back the instance UIDs in the response + ds.Insert(de1); + ds.Insert(de2); + + //code is from the presentationdatavalue::myinit2 + { + // Command Field + Attribute<0x0,0x100> at = { 32769 }; + ds.Insert( at.GetAsDataElement() ); + } + { + // Message ID Being Responded To + Attribute<0x0,0x120> at = { 1 }; + at.SetValue( (unsigned short)theMessageID ); + ds.Insert( at.GetAsDataElement() ); + } + { + Attribute<0x0,0x800> at = { 257 }; + ds.Insert( at.GetAsDataElement() ); + } + { + Attribute<0x0,0x900> at = { 0 }; + ds.Insert( at.GetAsDataElement() ); + } + { + Attribute<0x0,0x0> at = { 0 }; + unsigned int glen = ds.GetLength(); + assert( (glen % 2) == 0 ); + at.SetValue( glen ); + ds.Insert( at.GetAsDataElement() ); + } + + PresentationDataValue pdv; + + // FIXME + // how do we retrieve the actual PresID from the AAssociate? + const PDataTFPDU* theDataPDU = dynamic_cast(inPDU); + assert (theDataPDU); + uint8_t thePDVValue; + PresentationDataValue const &input_pdv = theDataPDU->GetPresentationDataValue(0); + thePDVValue = input_pdv.GetPresentationContextID(); + + pdv.SetPresentationContextID( thePDVValue ); + + pdv.SetDataSet(ds); + + pdv.SetMessageHeader(3); + thePDVs.push_back(pdv); + + return thePDVs; +} + +}//namespace network +}//namespace gdcm diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmCStoreMessages.h b/gdcm/Source/MessageExchangeDefinition/gdcmCStoreMessages.h new file mode 100644 index 0000000..92b93e8 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmCStoreMessages.h @@ -0,0 +1,49 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#ifndef GDCMCSTOREMESSAGES_H +#define GDCMCSTOREMESSAGES_H + +#include "gdcmBaseCompositeMessage.h" + +namespace gdcm{ +class File; + namespace network{ + class BasePDU; +/** + * \brief CStoreRQ + * this file defines the messages for the cecho action + */ +class CStoreRQ : public BaseCompositeMessage { + std::vector ConstructPDV(const ULConnection &inConnection, const BaseRootQuery* inRootQuery);//to fulfill the virtual contract + public: + std::vector ConstructPDV(const ULConnection &inConnection, + const File& file); + }; + +/** + * \brief CStoreRSP + * this file defines the messages for the cecho action + */ + class CStoreRSP : public BaseCompositeMessage { + std::vector ConstructPDV(const ULConnection &inConnection, const BaseRootQuery* inRootQuery);//to fulfill the virtual contract + public: + std::vector ConstructPDV(const DataSet* inDataSet, const BasePDU* inPC); + }; + } +} +#endif // GDCMCSTOREMESSAGES_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmCommandDataSet.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmCommandDataSet.cxx new file mode 100644 index 0000000..d8b97d7 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmCommandDataSet.cxx @@ -0,0 +1,35 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmCommandDataSet.h" + +#include "gdcmVR.h" +#include "gdcmImplicitDataElement.h" +#include "gdcmTag.h" + +namespace gdcm +{ + +std::istream &CommandDataSet::Read(std::istream &is) +{ + this->DataSet::Read(is); + return is; +} + +std::ostream &CommandDataSet::Write(std::ostream &os) const +{ + this->DataSet::Write(os); + return os; +} + +} // end namespace gdcm diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmCommandDataSet.h b/gdcm/Source/MessageExchangeDefinition/gdcmCommandDataSet.h new file mode 100644 index 0000000..e3179cb --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmCommandDataSet.h @@ -0,0 +1,68 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMCOMMANDDATASET_H +#define GDCMCOMMANDDATASET_H + +#include "gdcmDataSet.h" +#include "gdcmDataElement.h" + +namespace gdcm +{ +/** + * \brief Class to represent a Command DataSet + * + * \see DataSet + */ +class GDCM_EXPORT CommandDataSet : public DataSet +{ +public: + CommandDataSet() {} + ~CommandDataSet() {} + + friend std::ostream &operator<<(std::ostream &_os, const CommandDataSet &_val); + + // FIXME: no virtual function means: duplicate code... + void Insert(const DataElement& de) { + if( de.GetTag().GetGroup() == 0x0000 ) + { + InsertDataElement( de ); + } + else + { + gdcmErrorMacro( "Cannot add element with group != 0x0000 in the command dataset : " << de ); + } + } + void Replace(const DataElement& de) { + Remove(de.GetTag()); + Insert(de); + } + + /// Read + std::istream &Read(std::istream &is); + + /// Write + std::ostream &Write(std::ostream &os) const; + +protected: +}; +//----------------------------------------------------------------------------- +inline std::ostream& operator<<(std::ostream &os, const CommandDataSet &val) +{ + val.Print( os ); + return os; +} + +} // end namespace gdcm + +#endif //GDCMFILEMETAINFORMATION_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmCompositeMessageFactory.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmCompositeMessageFactory.cxx new file mode 100644 index 0000000..240259e --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmCompositeMessageFactory.cxx @@ -0,0 +1,61 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +/* +This class constructs PDataPDUs, but that have been specifically constructed for the +composite DICOM services (C-Echo, C-Find, C-Get, C-Move, and C-Store). It will also handle +parsing the incoming data to determine which of the CompositePDUs the incoming data is, and +so therefore allowing the scu to determine what to do with incoming data (if acting as +a storescp server, for instance). + +name and date: 4 oct 2010 mmr +*/ + +#include "gdcmCompositeMessageFactory.h" +#include "gdcmCEchoMessages.h" +#include "gdcmCStoreMessages.h" +#include "gdcmCFindMessages.h" +#include "gdcmCMoveMessages.h" +#include "gdcmBaseRootQuery.h" + +namespace gdcm { +namespace network { + std::vector CompositeMessageFactory::ConstructCEchoRQ(const ULConnection& inConnection) + { + CEchoRQ theEchoRQ; + return theEchoRQ.ConstructPDV(inConnection,NULL); + } + + std::vector CompositeMessageFactory::ConstructCStoreRQ(const ULConnection& inConnection, const File &file) + { + CStoreRQ theStoreRQ; + return theStoreRQ.ConstructPDV(inConnection,file); + } + std::vector CompositeMessageFactory::ConstructCStoreRSP(const DataSet *inDataSet, const BasePDU* inPDU) { + CStoreRSP theStoreRSP; + return theStoreRSP.ConstructPDV(inDataSet, inPDU); + } + std::vector CompositeMessageFactory::ConstructCFindRQ(const ULConnection& inConnection, const BaseRootQuery* inRootQuery) { + CFindRQ theFindRQ; + return theFindRQ.ConstructPDV(inConnection, inRootQuery); + } + std::vector CompositeMessageFactory::ConstructCMoveRQ(const ULConnection& inConnection, const BaseRootQuery* inRootQuery) { + CMoveRQ theMoveRQ; + return theMoveRQ.ConstructPDV(inConnection, inRootQuery); + } +} +} diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmCompositeMessageFactory.h b/gdcm/Source/MessageExchangeDefinition/gdcmCompositeMessageFactory.h new file mode 100644 index 0000000..77deadd --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmCompositeMessageFactory.h @@ -0,0 +1,58 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#ifndef GDCMCOMPOSITEMESSAGEFACTORY_H +#define GDCMCOMPOSITEMESSAGEFACTORY_H + +#include "gdcmPresentationDataValue.h" +#include "gdcmULConnection.h" + +namespace gdcm { + class BaseRootQuery; + class File; + namespace network { + class BasePDU; +/** + * \brief CompositeMessageFactory + * This class constructs PDataPDUs, but that have been specifically constructed for the + * composite DICOM services (C-Echo, C-Find, C-Get, C-Move, and C-Store). It will also handle + * parsing the incoming data to determine which of the CompositePDUs the incoming data is, and + * so therefore allowing the scu to determine what to do with incoming data (if acting as + * a storescp server, for instance). + */ +class CompositeMessageFactory +{ + public: + //the echo request only needs a properly constructed PDV. + //find, move, etc, may need something more robust, but since those are + //easily placed into the appropriate pdatapdu in the pdufactory, + //this approach without a base class (but done internally) is useful. + static std::vector ConstructCEchoRQ(const ULConnection& inConnection); + + static std::vector ConstructCStoreRQ(const ULConnection& inConnection,const File &file); + static std::vector ConstructCStoreRSP(const DataSet *inDataSet, const BasePDU* inPC); + + static std::vector ConstructCFindRQ(const ULConnection& inConnection, const BaseRootQuery* inRootQuery); + + static std::vector ConstructCMoveRQ(const ULConnection& inConnection, const BaseRootQuery* inRootQuery); + + + }; + } +} + +#endif // GDCMCOMPOSITEMESSAGEFACTORY_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmCompositeNetworkFunctions.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmCompositeNetworkFunctions.cxx new file mode 100644 index 0000000..1c9b5f4 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmCompositeNetworkFunctions.cxx @@ -0,0 +1,456 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ + +#include "gdcmCompositeNetworkFunctions.h" + +#include + +#include "gdcmReader.h" +#include "gdcmPrinter.h" +#include "gdcmAttribute.h" +#include "gdcmULConnectionManager.h" +#include "gdcmULConnection.h" +#include "gdcmDataSet.h" +#include "gdcmVersion.h" +#include "gdcmGlobal.h" +#include "gdcmSystem.h" +#include "gdcmUIDGenerator.h" +#include "gdcmWriter.h" +#include "gdcmSimpleSubjectWatcher.h" +#include "gdcmProgressEvent.h" +#include "gdcmQueryFactory.h" +#include "gdcmULWritingCallback.h" +#include "gdcmULBasicCallback.h" +#include "gdcmPresentationContextGenerator.h" + +namespace gdcm +{ + +// Execute like this: +// gdcmscu --echo www.dicomserver.co.uk 11112 +bool CompositeNetworkFunctions::CEcho(const char *remote, uint16_t portno, + const char *aetitle, const char *call) +{ + if( !remote ) return false; + if( !aetitle ) + { + aetitle = "GDCMSCU"; + } + if( !call ) + { + call = "ANY-SCP"; + } + + // Generate the PresentationContext array from the echo UID: + PresentationContextGenerator generator; + if( !generator.GenerateFromUID( UIDs::VerificationSOPClass ) ) + { + gdcmErrorMacro( "Failed to generate pres context." ); + return false; + } + + network::ULConnectionManager theManager; + if (!theManager.EstablishConnection(aetitle, call, remote, 0, portno, 1000, + generator.GetPresentationContexts() )) + { + gdcmErrorMacro( "Failed to establish connection." ); + return false; + } + std::vector theValues1 = theManager.SendEcho(); + + //should print _something_ to let the user know of success, if they ask for something + //other than a return code. + if (Trace::GetDebugFlag()) + { + DataSet ds = network::PresentationDataValue::ConcatenatePDVBlobs(theValues1); + Printer thePrinter; + thePrinter.PrintDataSet(ds, Trace::GetStream()); + } + theManager.BreakConnection(-1);//wait for a while for the connection to break, ie, infinite + + // Check the Success Status + DataSet ds = network::PresentationDataValue::ConcatenatePDVBlobs( theValues1 ); + Attribute<0x0,0x0900> at; + if( ds.FindDataElement( at.GetTag() ) ) + { + at.SetFromDataSet( ds ); + if( at.GetValue() != 0 ) + { + gdcmErrorMacro( "Wrong value for Status (C-ECHO)" ); + return false; + } + return true; + } + + gdcmDebugMacro( "Empty return on C-ECHO (no Status)" ); + return false; +} + +// this function will take command line options and construct a cmove query from them +// returns NULL if the query could not be constructed. +// note that the caller is responsible for deleting the constructed query. +// used to build both a move and a find query (true for inMove if it's move, false if it's find) +BaseRootQuery* CompositeNetworkFunctions::ConstructQuery( ERootType inRootType, + EQueryLevel inQueryLevel, const KeyValuePairArrayType& keys, bool inMove) +{ + KeyValuePairArrayType::const_iterator it = keys.begin(); + DataSet ds; + for(; it != keys.end(); ++it) + { + DataElement de( it->first ); + const std::string &s = it->second; + de.SetByteValue ( s.c_str(), (uint32_t)s.size() ); + ds.Insert( de ); + } + return CompositeNetworkFunctions::ConstructQuery( inRootType, + inQueryLevel, ds, inMove); +} + +BaseRootQuery* CompositeNetworkFunctions::ConstructQuery( ERootType inRootType, + EQueryLevel inQueryLevel, const DataSet& ds, bool inMove) +{ + BaseRootQuery* outQuery = NULL; + if( inMove ) + outQuery = QueryFactory::ProduceQuery(inRootType, eMove, inQueryLevel); + else + outQuery = QueryFactory::ProduceQuery(inRootType, eFind, inQueryLevel); + if (!outQuery) + { + gdcmErrorMacro( "Specify the query" ); + return NULL; + } + outQuery->AddQueryDataSet(ds); + + // setup the special character set + std::vector inCharSetType; + inCharSetType.push_back( QueryFactory::GetCharacterFromCurrentLocale() ); + DataElement de = QueryFactory::ProduceCharacterSetDataElement(inCharSetType); + std::string param ( de.GetByteValue()->GetPointer(), + de.GetByteValue()->GetLength() ); + outQuery->SetSearchParameter(de.GetTag(), param ); + + // Print info: + if (Trace::GetDebugFlag()) + { + outQuery->Print( Trace::GetStream() ); + } + + return outQuery; +} + + +//note that pointer to the base root query-- the caller must instantiated and delete +bool CompositeNetworkFunctions::CMove( const char *remote, uint16_t portno, + const BaseRootQuery* query, uint16_t portscp, + const char *aetitle, const char *call, const char* outputdir) +{ + if( !remote ) return false; + if( !aetitle ) + { + aetitle = "GDCMSCU"; + } + if( !call ) + { + call = "ANY-SCP"; + } + + /* movescu -v -d --aetitle GDCMDASH3 --call GDCM_STORE --patient --key + * 8,52=IMAGE --key 8,18=1.3.12.2.1107.5.8.1.123456789.199507271758050707765 + * dicom.example.com 11112 --key 10,20 +P 5677 + * --key 20,d=1.3.12.2.1107.5.8.1.123456789.199507271758050705910 + * --key 20,e=1.3.12.2.1107.5.8.1.123456789.199507271758050706635 + */ + + if (!outputdir || !*outputdir) + { + outputdir = "."; + } + + // Generate the PresentationContext array from the query UID: + PresentationContextGenerator generator; + if( !generator.GenerateFromUID( query->GetAbstractSyntaxUID() ) ) + { + gdcmErrorMacro( "Failed to generate pres context." ); + return false; + } + + network::ULConnectionManager theManager; + if (!theManager.EstablishConnectionMove(aetitle, call, remote, 0, portno, 1000, + portscp, generator.GetPresentationContexts())) + { + gdcmErrorMacro( "Failed to establish connection." ); + return false; + } + + network::ULWritingCallback theCallback; + theCallback.SetDirectory(outputdir); + bool ret = theManager.SendMove( query, &theCallback ); + if( !ret ) return false; + + ret = theManager.BreakConnection(-1);//wait for a while for the connection to break, ie, infinite + return ret; +} + +//note that pointer to the base root query-- the caller must instantiated and delete +bool CompositeNetworkFunctions::CFind( const char *remote, uint16_t portno, + const BaseRootQuery* query, std::vector &retDataSets, + const char *aetitle, const char *call ) +{ + if( !remote ) return false; + if( !aetitle ) + { + aetitle = "GDCMSCU"; + } + if( !call ) + { + call = "ANY-SCP"; + } + + // $ findscu -v -d --aetitle ACME1 --call ACME_STORE -P -k 0010,0010="X*" + // dhcp-67-183 5678 patqry.dcm + // Add a query: + + // Generate the PresentationContext array from the query UID: + PresentationContextGenerator generator; + if( !generator.GenerateFromUID( query->GetAbstractSyntaxUID() ) ) + { + gdcmErrorMacro( "Failed to generate pres context." ); + return false; + } + + network::ULConnectionManager theManager; + if (!theManager.EstablishConnection(aetitle, call, remote, 0, portno, 1000, + generator.GetPresentationContexts())) + { + gdcmErrorMacro( "Failed to establish connection." ); + return false; + } + std::vector theDataSets; + std::vector theResponses; + //theDataSets = theManager.SendFind( query ); + network::ULBasicCallback theCallback; + theManager.SendFind(query, &theCallback); + theDataSets = theCallback.GetDataSets(); + theResponses = theCallback.GetResponses(); + + bool ret = false; // by default an error + if( theResponses.empty() ) + { + gdcmErrorMacro( "Failed to GetResponses." ); + return false; + } + assert( theResponses.size() >= 1 ); + // take the last one: + const DataSet &ds = theResponses[ theResponses.size() - 1 ]; // FIXME + assert ( ds.FindDataElement(Tag(0x0, 0x0900)) ); + Attribute<0x0,0x0900> at; + at.SetFromDataSet( ds ); + + // Table CC.2.8-2 + //C-FIND RESPONSE STATUS VALUES + const uint16_t theVal = at.GetValue(); + switch( theVal ) + { + case 0x0: // Matching is complete - No final Identifier is supplied. + gdcmDebugMacro( "C-Find was successful." ); + // Append the new DataSet to the ret one: + retDataSets.insert( retDataSets.end(), theDataSets.begin(), theDataSets.end() ); + ret = true; + break; + case 0xA900: // Identifier Does Not Match SOP Class + { + Attribute<0x0,0x0901> errormsg; + errormsg.SetFromDataSet( ds ); + gdcm::Tag const & t = errormsg.GetValue(); + gdcmErrorMacro( "Offending Element: " << t ); (void)t; + } + break; + case 0xA700: // Refused: Out of Resources + { + Attribute<0x0,0x0902> errormsg; + errormsg.SetFromDataSet( ds ); + const char *themsg = errormsg.GetValue(); + assert( themsg ); (void)themsg; + gdcmErrorMacro( "Response Status: [" << themsg << "]" ); + } + break; + case 0x0122: // SOP Class not Supported + gdcmErrorMacro( "SOP Class not Supported" ); + break; + case 0xfe00: // Matching terminated due to Cancel request + gdcmErrorMacro( "Matching terminated due to Cancel request" ); + break; + default: + { + if( theVal >= 0xC000 && theVal <= 0xCFFF ) // Unable to process + { + Attribute<0x0,0x0902> errormsg; + errormsg.SetFromDataSet( ds ); + const char *themsg = errormsg.GetValue(); + assert( themsg ); (void)themsg; + gdcmErrorMacro( "Response Status: " << themsg ); + } + } + } + theManager.BreakConnection(-1);//wait for a while for the connection to break, ie, infinite + + return ret; +} + +class MyWatcher : public SimpleSubjectWatcher +{ + size_t nfiles; + double progress; + size_t index; + double refprogress; +public: + MyWatcher(Subject * s, const char *comment = "", size_t n = 1):SimpleSubjectWatcher(s,comment),nfiles(n),progress(0),index(0),refprogress(0){} + void ShowIteration() + { + index++; + assert( index <= nfiles ); + refprogress = progress; + } + void ShowProgress(Subject *caller, const Event &evt) + { + const ProgressEvent &pe = dynamic_cast(evt); + (void)caller; + progress = refprogress + (1. / (double)nfiles ) * pe.GetProgress(); +// std::cout << "Progress: " << progress << " " << pe.GetProgress() << std::endl; + } + virtual void ShowDataSet(Subject *, const Event &) {} +}; + +bool CompositeNetworkFunctions::CStore( const char *remote, uint16_t portno, + const Directory::FilenamesType& filenames, + const char *aetitle, const char *call) +{ + if( !remote ) return false; + // TODO AE-TITLE are more restrictive than that ! + if( !aetitle ) + { + aetitle = "GDCMSCU"; + } + if( !call ) + { + call = "ANY-SCP"; + } + + SmartPointer ps = new network::ULConnectionManager; + network::ULConnectionManager &theManager = *ps; + Directory::FilenamesType const &files = filenames; + + //SimpleSubjectWatcher watcher(ps, "cstore"); + MyWatcher watcher(ps, "cstore", files.size() ); + + // Generate the PresentationContext array from the File-Set: + PresentationContextGenerator generator; + if( !generator.GenerateFromFilenames(filenames) ) + { + gdcmErrorMacro( "Failed to generate pres context." ); + return false; + } + + if (!theManager.EstablishConnection(aetitle, call, remote, 0, + portno, 1000, generator.GetPresentationContexts() )) + { + gdcmErrorMacro( "Failed to establish connection." ); + return false; + } + + const char *fn = ""; // FIXME + bool ret = true; // by default no error + try + { + for( size_t i = 0; i < files.size(); ++i ) + { + const std::string & filename = files[i]; + fn = filename.c_str(); + assert( fn && *fn ); (void)fn; + Reader reader; + reader.SetFileName( filename.c_str() ); + gdcmDebugMacro( "Processing: " << filename ); + if( !reader.Read() ) + { + gdcmErrorMacro( "Could not read: " << filename ); + return false; + } + const File &file = reader.GetFile(); + std::vector theDataSets; + theDataSets = theManager.SendStore( file ); + if( theDataSets.empty() ) + { + gdcmErrorMacro( "Could not C-STORE: " << filename ); + return false; + } + assert( theDataSets.size() == 1 ); + const DataSet &ds = theDataSets[0]; + assert ( ds.FindDataElement(Tag(0x0, 0x0900)) ); + DataElement const & de = ds.GetDataElement(Tag(0x0,0x0900)); + Attribute<0x0,0x0900> at; + at.SetFromDataElement( de ); + // PS 3.4 - 2011 + // Table W.4-1 C-STORE RESPONSE STATUS VALUES + const uint16_t theVal = at.GetValue(); + switch( theVal ) + { + case 0x0: + gdcmDebugMacro( "C-Store of file " << filename << " was successful." ); + break; + case 0xA700: + case 0xA900: + case 0xC000: + { + // TODO: value from 0901 ? + gdcmErrorMacro( "C-Store of file " << filename << " was a failure." ); + Attribute<0x0,0x0902> errormsg; + errormsg.SetFromDataSet( ds ); + const char *themsg = errormsg.GetValue(); + assert( themsg ); (void)themsg; + gdcmErrorMacro( "Response Status: " << themsg ); + ret = false; // at least one file was not sent correctly + } + break; + default: + gdcmErrorMacro( "Unhandle error code: " << theVal ); + gdcmAssertAlwaysMacro( 0 ); + } + theManager.InvokeEvent( IterationEvent() ); + } + } + catch ( Exception &e ) + { + (void)e; //to avoid unreferenced variable warning on release + // If you reach here this is basically because GDCM does not support encoding other + // than raw transfer syntx (Little Endian Explicit/Implicit...) + theManager.BreakConnection(-1);//wait for a while for the connection to break, ie, infinite + gdcmErrorMacro( "C-Store of file " << fn << " was unsuccessful, aborting. " ); (void)fn; + gdcmErrorMacro( "Error was " << e.what() ); + return false; + } + catch (...) + { + theManager.BreakConnection(-1);//wait for a while for the connection to break, ie, infinite + gdcmErrorMacro( "C-Store of file " << fn << " was unsuccessful, aborting. " ); + return false; + } + theManager.BreakConnection(-1);//wait for a while for the connection to break, ie, infinite + return ret; +} + +} // end namespace gdcm diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmCompositeNetworkFunctions.h b/gdcm/Source/MessageExchangeDefinition/gdcmCompositeNetworkFunctions.h new file mode 100644 index 0000000..784c63f --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmCompositeNetworkFunctions.h @@ -0,0 +1,124 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#ifndef GDCMCOMPOSITENETWORKFUNCTIONS_H +#define GDCMCOMPOSITENETWORKFUNCTIONS_H + +#include "gdcmDirectory.h" +#include "gdcmBaseRootQuery.h" // EQueryLevel / EQueryType + +#include +#include + +namespace gdcm +{ +/** + * \brief Composite Network Functions + * These functions provide a generic API to the DICOM functions implemented in + * GDCM. + * Advanced users can use this code as a template for building their own + * versions of these functions (for instance, to provide progress bars or some + * other way of handling returned query information), but for most users, these + * functions should be sufficient to interface with a PACS to a local machine. + * Note that these functions are not contained within a static class or some + * other class-style interface, because multiple connections can be + * instantiated in the same program. The DICOM standard is much more function + * oriented rather than class oriented in this instance, so the design of this + * API reflects that functional approach. + * These functions implements the following SCU operations: + * \li C-ECHO SCU + * \li C-FIND SCU + * \li C-STORE SCU + * \li C-MOVE SCU (+internal C-STORE SCP) + */ +class GDCM_EXPORT CompositeNetworkFunctions +{ +public: + /// The most basic network function. Use this function to ensure that the + /// remote server is responding on the given IP and port number as expected. + /// \param aetitle when not set will default to 'GDCMSCU' + /// \param call when not set will default to 'ANY-SCP' + /// \warning This is an error to set remote to NULL or portno to 0 + /// \return true if it worked. + static bool CEcho( const char *remote, uint16_t portno, const char *aetitle = NULL, + const char *call = NULL ); + + typedef std::pair KeyValuePairType; + typedef std::vector< KeyValuePairType > KeyValuePairArrayType; + + /// This function will take a list of strings and tags and fill in a query that + /// can be used for either CFind or CMove (depending on the input boolean + /// \param inMove). + /// Note that the caller is responsible for deleting the constructed query. + /// This function is used to build both a move and a find query + /// (true for inMove if it's move, false if it's find) + static BaseRootQuery* ConstructQuery(ERootType inRootType, EQueryLevel inQueryLevel, + const DataSet& queryds, bool inMove = false ); + + /// \deprecated + static BaseRootQuery* ConstructQuery(ERootType inRootType, EQueryLevel inQueryLevel, + const KeyValuePairArrayType& keys, bool inMove = false ); + + /// This function will use the provided query to get files from a remote server. + /// NOTE that this functionality is essentially equivalent to C-GET in the + /// DICOM standard; however, C-GET has been deprecated, so this function + /// allows for the user to ask a remote server for files matching a query and + /// return them to the local machine. + /// Files will be written to the given output directory. + /// If the operation succeeds, the function returns true. + /// This function is a prime candidate for being overwritten by expert users; + /// if the datasets should remain in memory, for instance, that behavior can + /// be changed by creating a user-level version of this function. + /// \param aetitle when not set will default to 'GDCMSCU' + /// \param call when not set will default to 'ANY-SCP' + /// This is an error to set remote to NULL or portno to 0 + /// when \param outputdir is not set default to current dir ('.') + /// \return true if it worked. + static bool CMove( const char *remote, uint16_t portno, const BaseRootQuery* query, + uint16_t portscp, const char *aetitle = NULL, + const char *call = NULL, const char *outputdir = NULL); + + /// This function will use the provided query to determine what files a remote + /// server contains that match the query strings. The return is a vector of + /// datasets that contain tags as reported by the server. If the dataset is + /// empty, then it is possible that an error condition was encountered; in + /// which case, the user should monitor the error and warning streams. + /// \param aetitle when not set will default to 'GDCMSCU' + /// \param call when not set will default to 'ANY-SCP' + /// \warning This is an error to set remote to NULL or portno to 0 + /// \return true if it worked. + static bool CFind( const char *remote, uint16_t portno, + const BaseRootQuery* query, + std::vector &retDataSets, + const char *aetitle = NULL, + const char *call = NULL ); + + /// This function will place the provided files into the remote server. + /// The function returns true if it worked for all files. + /// \warning the server side can refuse an association on a given file + /// \param aetitle when not set will default to 'GDCMSCU' + /// \param call when not set will default to 'ANY-SCP' + /// \warning This is an error to set remote to NULL or portno to 0 + /// \return true if it worked for all files + static bool CStore( const char *remote, uint16_t portno, + const Directory::FilenamesType & filenames, + const char *aetitle = NULL, const char *call = NULL); +}; + +} // end namespace gdcm + +#endif // GDCMCOMPOSITENETWORKFUNCTIONS_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmDIMSE.h b/gdcm/Source/MessageExchangeDefinition/gdcmDIMSE.h new file mode 100644 index 0000000..57f8aaa --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmDIMSE.h @@ -0,0 +1,121 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMDIMSE_H +#define GDCMDIMSE_H + +#include "gdcmTypes.h" + +namespace gdcm +{ + +namespace network +{ + +/** + * \brief DIMSE + * PS 3.7 - 2009 + * Annex E Command Dictionary (Normative) + * E.1 REGISTRY OF DICOM COMMAND ELEMENTS + * Table E.1-1 + * COMMAND FIELDS (PART 1) + */ +class DIMSE { +public: + typedef enum { +C_STORE_RQ = 0x0001, +C_STORE_RSP = 0x8001, +C_GET_RQ = 0x0010, +C_GET_RSP = 0x8010, +C_FIND_RQ = 0x0020, +C_FIND_RSP = 0x8020, +C_MOVE_RQ = 0x0021, +C_MOVE_RSP = 0x8021, +C_ECHO_RQ = 0x0030, +C_ECHO_RSP = 0x8030, +N_EVENT_REPORT_RQ = 0x0100, +N_EVENT_REPORT_RSP = 0x8100, +N_GET_RQ = 0x0110, +N_GET_RSP = 0x8110, +N_SET_RQ = 0x0120, +N_SET_RSP = 0x8120, +N_ACTION_RQ = 0x0130, +N_ACTION_RSP = 0x8130, +N_CREATE_RQ = 0x0140, +N_CREATE_RSP = 0x8140, +N_DELETE_RQ = 0x0150, +N_DELETE_RSP = 0x8150, +C_CANCEL_RQ = 0x0FFF + } CommandTypes; +}; + +/* +9.1.5.1 C-ECHO parameters +Table 9.1-5 +C-ECHO PARAMETERS +*/ +class CEchoRQ +{ +public: + uint16_t MessageID; /* M */ + UIComp AffectedSOPClassUID; /* M */ +}; + +class CEchoRSP +{ +public: +/* +Message ID M U +Message ID Being Responded To  M +Affected SOP Class UID M U(=) +Status  M +*/ +}; + +/** +PS 3.4 - 2009 +Table B.2-1 C-STORE STATUS + */ +class CFind +{ +/* +Failure Refused: Out of Resources A700 (0000,0902) +Identifier does not match SOP Class A900 (0000,0901) +(0000,0902) +Unable to process Cxxx (0000,0901) +(0000,0902) +Cancel Matching terminated due to Cancel +request +FE00 None +Success Matching is complete – No final Identifier +is supplied. +0000 None +Pending Matches are continuing – Current Match +is supplied and any Optional Keys were +supported in the same manner as +Required Keys. +FF00 Identifier +Matches are continuing – Warning that +one or more Optional Keys were not +supported for existence and/or matching +for this Identifier. +FF01 Identifier +*/ +}; + + +} // end namespace network + +} // end namespace gdcm + +#endif //GDCMDIMSE_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmFindPatientRootQuery.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmFindPatientRootQuery.cxx new file mode 100644 index 0000000..8493240 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmFindPatientRootQuery.cxx @@ -0,0 +1,265 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmFindPatientRootQuery.h" +#include "gdcmAttribute.h" +#include + +namespace gdcm +{ + +FindPatientRootQuery::FindPatientRootQuery() +{ + mRootType = ePatientRootType; + mHelpDescription = "Patient-level root query"; +} + +void FindPatientRootQuery::InitializeDataSet(const EQueryLevel& inQueryLevel) +{ + switch (inQueryLevel) + { + case ePatient: + { + Attribute<0x8,0x52> at1 = { "PATIENT " }; + mDataSet.Insert( at1.GetAsDataElement() ); + } + break; + case eStudy: + { + Attribute<0x8,0x52> at1 = { "STUDY " }; + mDataSet.Insert( at1.GetAsDataElement() ); + Attribute<0x10,0x20> PatientLevel = { "" }; + mDataSet.Insert( PatientLevel.GetAsDataElement() ); + } + break; + case eSeries: + { + Attribute<0x8,0x52> at1 = { "SERIES" }; + mDataSet.Insert( at1.GetAsDataElement() ); + Attribute<0x10,0x20> PatientLevel = { "" }; + mDataSet.Insert( PatientLevel.GetAsDataElement() ); + Attribute<0x20, 0xd> Studylevel = { "" }; + mDataSet.Insert( Studylevel.GetAsDataElement() ); + } + break; + case eImage: + { + Attribute<0x8,0x52> at1 = { "IMAGE " }; + mDataSet.Insert( at1.GetAsDataElement() ); + + Attribute<0x10,0x20> PatientLevel = { "" }; + mDataSet.Insert( PatientLevel.GetAsDataElement() ); + + Attribute<0x20, 0xd> Studylevel = { "" }; + mDataSet.Insert( Studylevel.GetAsDataElement() ); + + Attribute<0x20, 0xe> SeriesLevel = { "" }; + mDataSet.Insert( SeriesLevel.GetAsDataElement() ); + } + break; + } +} + +std::vector FindPatientRootQuery::GetTagListByLevel(const EQueryLevel& inQueryLevel) +{ + switch (inQueryLevel) + { + case ePatient: + return mPatient.GetAllTags(ePatientRootType); + case eStudy: + return mStudy.GetAllTags(ePatientRootType); + case eSeries: +// default: + return mSeries.GetAllTags(ePatientRootType); + case eImage: + return mImage.GetAllTags(ePatientRootType); + default: //have to return _something_ if a query level isn't given + assert(0); + { + std::vector empty; + return empty; + } + } +} + +bool FindPatientRootQuery::ValidateQuery(bool inStrict) const +{ + //if it's empty, it's not useful + const DataSet &ds = GetQueryDataSet(); + if (ds.Size() == 0) + { + if (inStrict) + gdcmWarningMacro( "Empty DataSet in ValidateQuery" ); + return false; + } + + //search for 0x8,0x52 + Attribute<0x0008, 0x0052> level; + level.SetFromDataSet( ds ); + const std::string & theVal = level.GetValue(); + const int ilevel = BaseRootQuery::GetQueryLevelFromString( theVal.c_str() ); + if( ilevel == -1 ) + { + gdcmWarningMacro( "Invalid Level" ); + return false; + } + + bool theReturn = true; + + // requirement is that tag should belong to { opttags U requiredtags } && at + // least one tag from { requiredtags } + std::vector tags; // Optional+Required (at same level) + std::vector hiertags; // Unique + Unique level above (Hierarchical Search) + + if (inStrict) + { + QueryBase* qb = BaseRootQuery::Construct( ePatientRootType, (EQueryLevel)ilevel ); + if (qb == NULL) + { + gdcmWarningMacro( "Invalid Query" ); + return false; + } + + std::vector opttags = qb->GetOptionalTags(ePatientRootType); + tags.insert( tags.begin(), opttags.begin(), opttags.end() ); + std::vector reqtags = qb->GetRequiredTags(ePatientRootType); + tags.insert( tags.begin(), reqtags.begin(), reqtags.end() ); + hiertags = qb->GetHierachicalSearchTags(ePatientRootType); + tags.insert( tags.begin(), hiertags.begin(), hiertags.end() ); + delete qb; + } + else + { + QueryBase* qb = NULL; + if (strcmp(theVal.c_str(), "PATIENT ") == 0) + { + //make sure remaining tags are somewhere in the list of required, unique, or optional tags + std::vector tagGroup; + qb = new QueryPatient(); + tagGroup = qb->GetAllTags(ePatientRootType); + tags.insert(tags.end(), tagGroup.begin(), tagGroup.end()); + delete qb; + } + else if (strcmp(theVal.c_str(), "STUDY ") == 0) + { + //make sure remaining tags are somewhere in the list of required, unique, or optional tags + std::vector tagGroup; + qb = new QueryPatient(); + tagGroup = qb->GetAllTags(ePatientRootType); + tags.insert(tags.end(), tagGroup.begin(), tagGroup.end()); + delete qb; + qb = new QueryStudy(); + tagGroup = qb->GetAllTags(ePatientRootType); + tags.insert(tags.end(), tagGroup.begin(), tagGroup.end()); + delete qb; + } + else if (strcmp(theVal.c_str(), "SERIES") == 0) + { + //make sure remaining tags are somewhere in the list of required, unique, or optional tags + std::vector tagGroup; + qb = new QueryPatient(); + tagGroup = qb->GetAllTags(ePatientRootType); + tags.insert(tags.end(), tagGroup.begin(), tagGroup.end()); + delete qb; + qb = new QueryStudy(); + tagGroup = qb->GetAllTags(eStudyRootType); + tags.insert(tags.end(), tagGroup.begin(), tagGroup.end()); + delete qb; + qb = new QuerySeries(); + tagGroup = qb->GetAllTags(ePatientRootType); + tags.insert(tags.end(), tagGroup.begin(), tagGroup.end()); + delete qb; + } + else if (strcmp(theVal.c_str(), "IMAGE ") == 0 ) + { + //make sure remaining tags are somewhere in the list of required, unique, or optional tags + std::vector tagGroup; + qb = new QueryPatient(); + tagGroup = qb->GetAllTags(ePatientRootType); + tags.insert(tags.end(), tagGroup.begin(), tagGroup.end()); + delete qb; + qb = new QueryStudy(); + tagGroup = qb->GetAllTags(ePatientRootType); + tags.insert(tags.end(), tagGroup.begin(), tagGroup.end()); + delete qb; + qb = new QuerySeries(); + tagGroup = qb->GetAllTags(ePatientRootType); + tags.insert(tags.end(), tagGroup.begin(), tagGroup.end()); + delete qb; + qb = new QueryImage(); + tagGroup = qb->GetAllTags(ePatientRootType); + tags.insert(tags.end(), tagGroup.begin(), tagGroup.end()); + delete qb; + } + if (tags.empty()) + { + gdcmWarningMacro( "Invalid Level" ); + return false; + } + } + //all the tags in the dataset should be in that tag list + //otherwise, it's not valid + //also, while the level tag must be present, and the language tag can be + //present (but does not have to be), some other tag must show up as well + //so, have two counts: 1 for tags that are found, 1 for tags that are not + //if there are no found tags, then the query is invalid + //if there is one improper tag found, then the query is invalid + DataSet::ConstIterator itor; + Attribute<0x0008, 0x0005> language; + if( inStrict ) + { + unsigned int thePresentTagCount = 0; + for (itor = ds.Begin(); itor != ds.End(); itor++) + { + Tag t = itor->GetTag(); + if (t == level.GetTag()) continue; + if (t == language.GetTag()) continue; + assert( !tags.empty() ); + if (std::find(tags.begin(), tags.end(), t) == tags.end()) + { + //check to see if it's a language tag, 8,5, and if it is, ignore if it's one + //of the possible language tag values + //well, for now, just allow it if it's present. + gdcmWarningMacro( "You have an extra tag: " << t ); + theReturn = false; + break; + } + else + { + // Ok this tags is in Unique/Required or Optional, need to check + // if it is in Required/Unique now: + //std::copy( hiertags.begin(), hiertags.end(), + // std::ostream_iterator( std::cout, "," ) ); + if (std::find(hiertags.begin(), hiertags.end(), t) != + hiertags.end()) + { + gdcmDebugMacro( "Found at least one key: " << t ); + thePresentTagCount++; + } + } + } + if( thePresentTagCount != hiertags.size() ) + { + gdcmWarningMacro( "Missing Key found (within the hierachical search ones)" ); + theReturn = false; + } + } + return theReturn; +} + +UIDs::TSName FindPatientRootQuery::GetAbstractSyntaxUID() const +{ + return UIDs::PatientRootQueryRetrieveInformationModelFIND; +} + +} diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmFindPatientRootQuery.h b/gdcm/Source/MessageExchangeDefinition/gdcmFindPatientRootQuery.h new file mode 100644 index 0000000..0011544 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmFindPatientRootQuery.h @@ -0,0 +1,41 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMFINDPATIENTROOTQUERY_H +#define GDCMFINDPATIENTROOTQUERY_H + +#include "gdcmBaseRootQuery.h" + +namespace gdcm +{ +/** + * \brief PatientRootQuery + * contains: the class which will produce a dataset for c-find with patient root + */ +class GDCM_EXPORT FindPatientRootQuery : public BaseRootQuery +{ + friend class QueryFactory; +public: + FindPatientRootQuery(); + + void InitializeDataSet(const EQueryLevel& inQueryLevel); + + std::vector GetTagListByLevel(const EQueryLevel& inQueryLevel); + bool ValidateQuery(bool inStrict = true) const; + + UIDs::TSName GetAbstractSyntaxUID() const; +}; + +} // end namespace gdcm + +#endif // GDCMFINDPATIENTROOTQUERY_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmFindStudyRootQuery.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmFindStudyRootQuery.cxx new file mode 100644 index 0000000..e49878d --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmFindStudyRootQuery.cxx @@ -0,0 +1,248 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmFindStudyRootQuery.h" + +#include "gdcmAttribute.h" +#include "gdcmDataSet.h" + +#include +#include + +namespace gdcm +{ + +FindStudyRootQuery::FindStudyRootQuery() +{ + mRootType = eStudyRootType; + mHelpDescription = "Study-level root query"; +} + +void FindStudyRootQuery::InitializeDataSet(const EQueryLevel& inQueryLevel) +{ + switch (inQueryLevel) + { + case eStudy: + { + Attribute<0x8,0x52> at1 = { "STUDY " }; + mDataSet.Insert( at1.GetAsDataElement() ); + } + break; + case eSeries: + { + Attribute<0x8,0x52> at1 = { "SERIES" }; + mDataSet.Insert( at1.GetAsDataElement() ); + Attribute<0x20, 0xd> Studylevel = { "" }; + mDataSet.Insert( Studylevel.GetAsDataElement() ); + } + default: // ePatient + break; + case eImage: + { + Attribute<0x8,0x52> at1 = { "IMAGE " }; + mDataSet.Insert( at1.GetAsDataElement() ); + + Attribute<0x20, 0xd> Studylevel = { "" }; + mDataSet.Insert( Studylevel.GetAsDataElement() ); + + Attribute<0x20, 0xe> SeriesLevel = { "" }; + mDataSet.Insert( SeriesLevel.GetAsDataElement() ); + } + break; + } +} + +std::vector FindStudyRootQuery::GetTagListByLevel(const EQueryLevel& inQueryLevel) +{ + switch (inQueryLevel) + { + case ePatient: + return mPatient.GetAllTags(eStudyRootType); + case eStudy: + return mStudy.GetAllTags(eStudyRootType); + case eSeries: + // default: + return mSeries.GetAllTags(eStudyRootType); + case eImage: + return mImage.GetAllTags(eStudyRootType); + default: //have to return _something_ if a query level isn't given + assert(0); + { + std::vector empty; + return empty; + } + } +} + +/* +PS 3.4- 2011 + +C.4.1.2.1 Baseline Behavior of SCU +The Identifier contained in a C-FIND request shall contain a single value in +the Unique Key Attribute for each level above the Query/Retrieve level. No +Required or Optional Keys shall be specified which are associated with +levels above the Query/Retrieve level. + */ +bool FindStudyRootQuery::ValidateQuery(bool inStrict) const +{ + //if it's empty, it's not useful + const DataSet & ds = GetQueryDataSet(); + if (ds.Size() == 0) + { + if (inStrict) + gdcmWarningMacro( "Empty DataSet in ValidateQuery" ); + return false; + } + + //search for 0x8,0x52 + Attribute<0x0008, 0x0052> level; + level.SetFromDataSet( ds ); + const std::string & theVal = level.GetValue(); + const int ilevel = BaseRootQuery::GetQueryLevelFromString( theVal.c_str() ); + if( ilevel == -1 ) + { + gdcmWarningMacro( "Invalid Level" ); + return false; + } + + bool theReturn = true; + + // requirement is that tag should belong to { opttags U requiredtags } && at + // least one tag from { requiredtags } + std::vector tags; // Optional+Required (at same level) + std::vector hiertags; // Unique + Unique level above (Hierarchical Search) + + if (inStrict) + { + QueryBase* qb = BaseRootQuery::Construct( eStudyRootType, (EQueryLevel)ilevel ); + if (qb == NULL) + { + gdcmWarningMacro( "Invalid Query" ); + return false; + } + + std::vector opttags = qb->GetOptionalTags(eStudyRootType); + tags.insert( tags.begin(), opttags.begin(), opttags.end() ); + std::vector reqtags = qb->GetRequiredTags(eStudyRootType); + tags.insert( tags.begin(), reqtags.begin(), reqtags.end() ); + hiertags = qb->GetHierachicalSearchTags(eStudyRootType); + tags.insert( tags.begin(), hiertags.begin(), hiertags.end() ); + delete qb; + } + else //include all previous levels (ie, series gets study, image gets series and study) + { + QueryBase* qb = NULL; + + if (strcmp(theVal.c_str(), "STUDY ") == 0) + { + //make sure remaining tags are somewhere in the list of required, unique, or optional tags + std::vector tagGroup; + qb = new QueryStudy(); + tagGroup = qb->GetAllTags(eStudyRootType); + tags.insert(tags.end(), tagGroup.begin(), tagGroup.end()); + delete qb; + } + if (strcmp(theVal.c_str(), "SERIES") == 0) + { + //make sure remaining tags are somewhere in the list of required, unique, or optional tags + std::vector tagGroup; + qb = new QueryStudy(); + tagGroup = qb->GetAllTags(eStudyRootType); + tags.insert(tags.end(), tagGroup.begin(), tagGroup.end()); + delete qb; + qb = new QuerySeries(); + tagGroup = qb->GetAllTags(eStudyRootType); + tags.insert(tags.end(), tagGroup.begin(), tagGroup.end()); + delete qb; + } + if (strcmp(theVal.c_str(), "IMAGE ") == 0 ) + { + //make sure remaining tags are somewhere in the list of required, unique, or optional tags + std::vector tagGroup; + qb = new QueryStudy(); + tagGroup = qb->GetAllTags(eStudyRootType); + tags.insert(tags.end(), tagGroup.begin(), tagGroup.end()); + delete qb; + qb = new QuerySeries(); + tagGroup = qb->GetAllTags(eStudyRootType); + tags.insert(tags.end(), tagGroup.begin(), tagGroup.end()); + delete qb; + qb = new QueryImage(); + tagGroup = qb->GetAllTags(eStudyRootType); + tags.insert(tags.end(), tagGroup.begin(), tagGroup.end()); + delete qb; + } + if (tags.empty()) + { + gdcmWarningMacro( "Invalid Level" ); + return false; + } + } + + //all the tags in the dataset should be in that tag list + //otherwise, it's not valid + //also, while the level tag must be present, and the language tag can be + //present (but does not have to be), some other tag must show up as well + //so, have two counts: 1 for tags that are found, 1 for tags that are not + //if there are no found tags, then the query is invalid + //if there is one improper tag found, then the query is invalid + DataSet::ConstIterator itor; + Attribute<0x0008, 0x0005> language; + if( inStrict ) + { + unsigned int thePresentTagCount = 0; + for (itor = ds.Begin(); itor != ds.End(); itor++) + { + const Tag & t = itor->GetTag(); + if (t == level.GetTag()) continue; + if (t == language.GetTag()) continue; + if (std::find(tags.begin(), tags.end(), t) == tags.end()) + { + //check to see if it's a language tag, 8,5, and if it is, ignore if it's one + //of the possible language tag values + //well, for now, just allow it if it's present. + gdcmWarningMacro( "You have an extra tag: " << t ); + theReturn = false; + break; + } + else + { + // Ok this tags is in Unique/Required or Optional, need to check + // if it is in Required/Unique now: + //std::copy( hiertags.begin(), hiertags.end(), + // std::ostream_iterator( std::cout, "," ) ); + if (std::find(hiertags.begin(), hiertags.end(), t) != + hiertags.end()) + { + gdcmDebugMacro( "Found at least one key: " << t ); + thePresentTagCount++; + } + } + } + if( thePresentTagCount != hiertags.size() ) + { + assert( !hiertags.empty() ); + gdcmWarningMacro( "Missing Key found (within the hierachical search ones): " << hiertags[0] ); + gdcmDebugMacro( "Current DataSet is: " << ds ); + theReturn = false; + } + } + return theReturn; +} + +UIDs::TSName FindStudyRootQuery::GetAbstractSyntaxUID() const +{ + return UIDs::StudyRootQueryRetrieveInformationModelFIND; +} + +} // end namespace gdcm diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmFindStudyRootQuery.h b/gdcm/Source/MessageExchangeDefinition/gdcmFindStudyRootQuery.h new file mode 100644 index 0000000..4dfd8d3 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmFindStudyRootQuery.h @@ -0,0 +1,45 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMFINDSTUDYROOTQUERY_H +#define GDCMFINDSTUDYROOTQUERY_H + +#include "gdcmBaseRootQuery.h" + +namespace gdcm +{ +/** + * \brief FindStudyRootQuery + * contains: the class which will produce a dataset for C-FIND with study root + */ +class GDCM_EXPORT FindStudyRootQuery : public BaseRootQuery +{ + friend class QueryFactory; +public: + FindStudyRootQuery(); + + void InitializeDataSet(const EQueryLevel& inQueryLevel); + + std::vector GetTagListByLevel(const EQueryLevel& inQueryLevel); + + /// have to be able to ensure that (0008,0052) is set + /// that the level is appropriate (ie, not setting PATIENT for a study query + /// that the tags in the query match the right level (either required, unique, optional) + bool ValidateQuery(bool inStrict = true) const; + + UIDs::TSName GetAbstractSyntaxUID() const; +}; + +} // end namespace gdcm + +#endif // GDCMFINDSTUDYROOTQUERY_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmImplementationClassUIDSub.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmImplementationClassUIDSub.cxx new file mode 100644 index 0000000..360e202 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmImplementationClassUIDSub.cxx @@ -0,0 +1,85 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmImplementationClassUIDSub.h" +#include "gdcmFileMetaInformation.h" +#include "gdcmSwapper.h" + +namespace gdcm +{ +namespace network +{ +const uint8_t ImplementationClassUIDSub::ItemType = 0x52; +const uint8_t ImplementationClassUIDSub::Reserved2 = 0x00; + +ImplementationClassUIDSub::ImplementationClassUIDSub() +{ + ImplementationClassUID = FileMetaInformation::GetImplementationClassUID(); + + ItemLength = (uint16_t)ImplementationClassUID.size(); + assert( (size_t)ItemLength + 4 == Size() ); +} + +std::istream &ImplementationClassUIDSub::Read(std::istream &is) +{ + //uint8_t itemtype = 0x0; + //is.read( (char*)&itemtype, sizeof(ItemType) ); + //assert( itemtype == ItemType ); + uint8_t reserved2; + is.read( (char*)&reserved2, sizeof(Reserved2) ); + uint16_t itemlength; + is.read( (char*)&itemlength, sizeof(ItemLength) ); + SwapperDoOp::SwapArray(&itemlength,1); + ItemLength = itemlength; + + char name[256]; + assert( itemlength < 256 ); + is.read( name, itemlength ); + ImplementationClassUID = std::string(name, itemlength); + + assert( (size_t)ItemLength + 4 == Size() ); + return is; +} + +const std::ostream &ImplementationClassUIDSub::Write(std::ostream &os) const +{ + os.write( (char*)&ItemType, sizeof(ItemType) ); + os.write( (char*)&Reserved2, sizeof(Reserved2) ); + //os.write( (char*)&ItemLength, sizeof(ItemLength) ); + uint16_t copy = ItemLength; + SwapperDoOp::SwapArray(©,1); + os.write( (char*)©, sizeof(ItemLength) ); + + os.write( ImplementationClassUID.c_str(), ImplementationClassUID.size() ); + + return os; +} + +size_t ImplementationClassUIDSub::Size() const +{ + size_t ret = 0; + assert( ImplementationClassUID.size() == ItemLength ); + ret += sizeof(ItemType); + ret += sizeof(Reserved2); + ret += sizeof(ItemLength); + ret += ItemLength; + return ret; +} + +void ImplementationClassUIDSub::Print(std::ostream &os) const +{ + os << "ImplementationClassUID: " << ImplementationClassUID << std::endl; +} + +} // end namespace network +} // end namespace gdcm diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmImplementationClassUIDSub.h b/gdcm/Source/MessageExchangeDefinition/gdcmImplementationClassUIDSub.h new file mode 100644 index 0000000..3c5c442 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmImplementationClassUIDSub.h @@ -0,0 +1,53 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMIMPLEMENTATIONCLASSUIDSUB_H +#define GDCMIMPLEMENTATIONCLASSUIDSUB_H + +#include "gdcmTypes.h" + +namespace gdcm +{ + +namespace network +{ + +/** + * \brief ImplementationClassUIDSub + * PS 3.7 + * Table D.3-1 + * IMPLEMENTATION CLASS UID SUB-ITEM FIELDS (A-ASSOCIATE-RQ) + */ +class ImplementationClassUIDSub +{ +public: + ImplementationClassUIDSub(); + std::istream &Read(std::istream &is); + const std::ostream &Write(std::ostream &os) const; + + size_t Size() const; + + void Print(std::ostream &os) const; + +private: + static const uint8_t ItemType; + static const uint8_t Reserved2; + uint16_t ItemLength; + std::string ImplementationClassUID; +}; + +} // end namespace network + +} // end namespace gdcm + +#endif //GDCMMAXIMUMLENGTHSUB_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmImplementationUIDSub.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmImplementationUIDSub.cxx new file mode 100644 index 0000000..373b4c1 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmImplementationUIDSub.cxx @@ -0,0 +1,40 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmImplementationUIDSub.h" + +namespace gdcm +{ +namespace network +{ +const uint8_t ImplementationUIDSub::ItemType = 0x52; +const uint8_t ImplementationUIDSub::Reserved2 = 0x00; + +ImplementationUIDSub::ImplementationUIDSub() +{ + ImplementationClassUID = "FOO"; + ItemLength = (uint16_t)ImplementationClassUID.size(); +} + +const std::ostream &ImplementationUIDSub::Write(std::ostream &os) const +{ + os.write( (char*)&ItemType, sizeof(ItemType) ); + os.write( (char*)&Reserved2, sizeof(Reserved2) ); + os.write( (char*)&ItemLength, sizeof(ItemLength) ); + os.write( ImplementationClassUID.c_str(), ImplementationClassUID.size() ); + + return os; +} + +} // end namespace network +} // end namespace gdcm diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmImplementationUIDSub.h b/gdcm/Source/MessageExchangeDefinition/gdcmImplementationUIDSub.h new file mode 100644 index 0000000..74ea5c9 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmImplementationUIDSub.h @@ -0,0 +1,46 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMIMPLEMENTATIONUIDSUB_H +#define GDCMIMPLEMENTATIONUIDSUB_H + +#include "gdcmTypes.h" + +namespace gdcm +{ + +namespace network +{ + +/** + * \brief ImplementationUIDSub + * Table D.3-2 + * IMPLEMENTATION UID SUB-ITEM FIELDS (A-ASSOCIATE-AC) + */ +class GDCM_EXPORT ImplementationUIDSub +{ +public: + ImplementationUIDSub(); + const std::ostream &Write(std::ostream &os) const; +private: + static const uint8_t ItemType; + static const uint8_t Reserved2; + uint16_t ItemLength; + std::string ImplementationClassUID; +}; + +} // end namespace network + +} // end namespace gdcm + +#endif //GDCMMAXIMUMLENGTHSUB_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmImplementationVersionNameSub.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmImplementationVersionNameSub.cxx new file mode 100644 index 0000000..fe12e8e --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmImplementationVersionNameSub.cxx @@ -0,0 +1,84 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmImplementationVersionNameSub.h" +#include "gdcmFileMetaInformation.h" +#include "gdcmSwapper.h" + +namespace gdcm +{ +namespace network +{ +const uint8_t ImplementationVersionNameSub::ItemType = 0x55; +const uint8_t ImplementationVersionNameSub::Reserved2 = 0x00; + +ImplementationVersionNameSub::ImplementationVersionNameSub() +{ + ImplementationVersionName = FileMetaInformation::GetImplementationVersionName(); + ItemLength = (uint16_t)ImplementationVersionName.size(); + assert( (size_t)ItemLength + 4 == Size() ); +} + +std::istream &ImplementationVersionNameSub::Read(std::istream &is) +{ + //uint8_t itemtype = 0x0; + //is.read( (char*)&itemtype, sizeof(ItemType) ); + //assert( itemtype == ItemType ); + uint8_t reserved2; + is.read( (char*)&reserved2, sizeof(Reserved2) ); + uint16_t itemlength; + is.read( (char*)&itemlength, sizeof(ItemLength) ); + SwapperDoOp::SwapArray(&itemlength,1); + ItemLength = itemlength; + + char name[256]; + assert( itemlength < 256 ); + is.read( name, itemlength ); + ImplementationVersionName = std::string(name,itemlength); + + return is; +} + +const std::ostream &ImplementationVersionNameSub::Write(std::ostream &os) const +{ + os.write( (char*)&ItemType, sizeof(ItemType) ); + os.write( (char*)&Reserved2, sizeof(Reserved2) ); + //os.write( (char*)&ItemLength, sizeof(ItemLength) ); + uint16_t copy = ItemLength; + SwapperDoOp::SwapArray(©,1); + os.write( (char*)©, sizeof(ItemLength) ); + + os.write( ImplementationVersionName.c_str(), ImplementationVersionName.size() ); + + return os; +} + +size_t ImplementationVersionNameSub::Size() const +{ + size_t ret = 0; + assert( ImplementationVersionName.size() == ItemLength ); + ret += sizeof(ItemType); + ret += sizeof(Reserved2); + ret += sizeof(ItemLength); + ret += ItemLength; + + return ret; +} + +void ImplementationVersionNameSub::Print(std::ostream &os) const +{ + os << "ImplementationVersionName: " << ImplementationVersionName << std::endl; +} + +} // end namespace network +} // end namespace gdcm diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmImplementationVersionNameSub.h b/gdcm/Source/MessageExchangeDefinition/gdcmImplementationVersionNameSub.h new file mode 100644 index 0000000..451ed4b --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmImplementationVersionNameSub.h @@ -0,0 +1,51 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMIMPLEMENTATIONVERSIONNAMESUB_H +#define GDCMIMPLEMENTATIONVERSIONNAMESUB_H + +#include "gdcmTypes.h" + +namespace gdcm +{ + +namespace network +{ + +/** + * \brief ImplementationVersionNameSub + * Table D.3-3 + * IMPLEMENTATION VERSION NAME SUB-ITEM FIELDS (A-ASSOCIATE-RQ) + */ +class ImplementationVersionNameSub +{ +public: + ImplementationVersionNameSub(); + std::istream &Read(std::istream &is); + const std::ostream &Write(std::ostream &os) const; + + size_t Size() const; + void Print(std::ostream &os) const; + +private: + static const uint8_t ItemType; + static const uint8_t Reserved2; + uint16_t ItemLength; + std::string ImplementationVersionName; +}; + +} // end namespace network + +} // end namespace gdcm + +#endif //GDCMMAXIMUMLENGTHSUB_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmMaximumLengthSub.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmMaximumLengthSub.cxx new file mode 100644 index 0000000..02bceea --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmMaximumLengthSub.cxx @@ -0,0 +1,95 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmMaximumLengthSub.h" +#include "gdcmSwapper.h" + +namespace gdcm +{ +namespace network +{ +const uint8_t MaximumLengthSub::ItemType = 0x51; +const uint8_t MaximumLengthSub::Reserved2 = 0x00; + +MaximumLengthSub::MaximumLengthSub() +{ + ItemLength = 0x4; + MaximumLength = 0x4000; + assert( (size_t)ItemLength + 4 == Size() ); +} + +std::istream &MaximumLengthSub::Read(std::istream &is) +{ + //uint8_t itemtype = 0x0; + //is.read( (char*)&itemtype, sizeof(ItemType) ); + //assert( itemtype == ItemType ); + uint8_t reserved2; + is.read( (char*)&reserved2, sizeof(Reserved2) ); + uint16_t itemlength; + is.read( (char*)&itemlength, sizeof(ItemLength) ); + SwapperDoOp::SwapArray(&itemlength,1); + ItemLength = itemlength; + + uint32_t maximumlength; + is.read( (char*)&maximumlength, sizeof(MaximumLength) ); + SwapperDoOp::SwapArray(&maximumlength,1); + MaximumLength = maximumlength; // 16384 == max possible (0x4000) + + return is; +} + +const std::ostream &MaximumLengthSub::Write(std::ostream &os) const +{ + os.write( (char*)&ItemType, sizeof(ItemType) ); + os.write( (char*)&Reserved2, sizeof(Reserved2) ); + //os.write( (char*)&ItemLength, sizeof(ItemLength) ); + { + uint16_t copy = ItemLength; + SwapperDoOp::SwapArray(©,1); + os.write( (char*)©, sizeof(ItemLength) ); + } + + //os.write( (char*)&MaximumLength, sizeof(MaximumLength) ); + { + uint32_t copy = MaximumLength; + SwapperDoOp::SwapArray(©,1); + os.write( (char*)©, sizeof(MaximumLength) ); + } + + return os; +} + +size_t MaximumLengthSub::Size() const +{ + size_t ret = 0; + ret += sizeof(ItemType); + ret += sizeof(Reserved2); + ret += sizeof(ItemLength); + ret += sizeof(MaximumLength); + + return ret; +} + +void MaximumLengthSub::Print(std::ostream &os) const +{ + os << "MaximumLength: " << MaximumLength << std::endl; +} + +void MaximumLengthSub::SetMaximumLength(uint32_t maximumlength) +{ + MaximumLength = maximumlength; + MaximumLength -= (maximumlength % 2); +} + +} // end namespace network +} // end namespace gdcm diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmMaximumLengthSub.h b/gdcm/Source/MessageExchangeDefinition/gdcmMaximumLengthSub.h new file mode 100644 index 0000000..d858912 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmMaximumLengthSub.h @@ -0,0 +1,61 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMMAXIMUMLENGTHSUB_H +#define GDCMMAXIMUMLENGTHSUB_H + +#include "gdcmTypes.h" + +namespace gdcm +{ + +namespace network +{ + +/** + * \brief MaximumLengthSub + * Annex D + * Table D.1-1 + * MAXIMUM LENGTH SUB-ITEM FIELDS (A-ASSOCIATE-RQ) + * + * or + * + * Table D.1-2 + * Maximum length sub-item fields (A-ASSOCIATE-AC) + */ +class MaximumLengthSub +{ +public: + MaximumLengthSub(); + std::istream &Read(std::istream &is); + const std::ostream &Write(std::ostream &os) const; + + size_t Size() const; + + uint32_t GetMaximumLength() const { return MaximumLength; } + void SetMaximumLength(uint32_t maximumlength); + + void Print(std::ostream &os) const; + +private: + static const uint8_t ItemType; + static const uint8_t Reserved2; + uint16_t ItemLength; + uint32_t MaximumLength; +}; + +} // end namespace network + +} // end namespace gdcm + +#endif //GDCMMAXIMUMLENGTHSUB_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmMovePatientRootQuery.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmMovePatientRootQuery.cxx new file mode 100644 index 0000000..29db031 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmMovePatientRootQuery.cxx @@ -0,0 +1,264 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmMovePatientRootQuery.h" +#include "gdcmAttribute.h" +#include + +namespace gdcm +{ + +MovePatientRootQuery::MovePatientRootQuery() +{ + mRootType = ePatientRootType; + mHelpDescription = "Patient-level root query"; +} + +void MovePatientRootQuery::InitializeDataSet(const EQueryLevel& inQueryLevel) +{ + switch (inQueryLevel) + { + case ePatient: + { + Attribute<0x8,0x52> at1 = { "PATIENT " }; + mDataSet.Insert( at1.GetAsDataElement() ); + } + break; + case eStudy: + { + Attribute<0x8,0x52> at1 = { "STUDY " }; + mDataSet.Insert( at1.GetAsDataElement() ); + Attribute<0x10,0x20> PatientLevel = { "" }; + mDataSet.Insert( PatientLevel.GetAsDataElement() ); + } + break; + case eSeries: + { + Attribute<0x8,0x52> at1 = { "SERIES" }; + mDataSet.Insert( at1.GetAsDataElement() ); + Attribute<0x10,0x20> PatientLevel = { "" }; + mDataSet.Insert( PatientLevel.GetAsDataElement() ); + Attribute<0x20, 0xd> Studylevel = { "" }; + mDataSet.Insert( Studylevel.GetAsDataElement() ); + } + case eImage: + { + Attribute<0x8,0x52> at1 = { "IMAGE " }; + mDataSet.Insert( at1.GetAsDataElement() ); + + Attribute<0x10,0x20> PatientLevel = { "" }; + mDataSet.Insert( PatientLevel.GetAsDataElement() ); + + Attribute<0x20, 0xd> Studylevel = { "" }; + mDataSet.Insert( Studylevel.GetAsDataElement() ); + + Attribute<0x20, 0xe> SeriesLevel = { "" }; + mDataSet.Insert( SeriesLevel.GetAsDataElement() ); + } + break; + } +} + +std::vector MovePatientRootQuery::GetTagListByLevel(const EQueryLevel& inQueryLevel) +{ + switch (inQueryLevel) + { + case ePatient: + return mPatient.GetUniqueTags(ePatientRootType); + case eStudy: + return mStudy.GetUniqueTags(ePatientRootType); + case eSeries: +// default: + return mSeries.GetUniqueTags(ePatientRootType); + case eImage: + return mImage.GetUniqueTags(ePatientRootType); + default: //have to return _something_ if a query level isn't given + assert(0); + { + std::vector empty; + return empty; + } + } +} + +bool MovePatientRootQuery::ValidateQuery(bool inStrict) const +{ + //if it's empty, it's not useful + const DataSet &ds = GetQueryDataSet(); + if (ds.Size() == 0) + { + if (inStrict) + gdcmWarningMacro( "Empty DataSet in ValidateQuery" ); + return false; + } + + // search for 0x8,0x52 + Attribute<0x0008, 0x0052> level; + level.SetFromDataSet( ds ); + const std::string theVal = level.GetValue(); + const int ilevel = BaseRootQuery::GetQueryLevelFromString( theVal.c_str() ); + if( ilevel == -1 ) + { + gdcmWarningMacro( "Invalid Level" ); + return false; + } + + bool theReturn = true; + + // requirement is that tag should belong to { opttags U requiredtags } && at + // least one tag from { requiredtags } + std::vector tags; // Optional+Required (at same level) + std::vector hiertags; // Unique + Unique level above (Hierarchical Search) + + if (inStrict) + { + QueryBase* qb = BaseRootQuery::Construct( ePatientRootType, (EQueryLevel)ilevel ); + if (qb == NULL) + { + gdcmWarningMacro( "Invalid Query" ); + return false; + } + + std::vector opttags = qb->GetOptionalTags(ePatientRootType); + tags.insert( tags.begin(), opttags.begin(), opttags.end() ); + std::vector reqtags = qb->GetRequiredTags(ePatientRootType); + tags.insert( tags.begin(), reqtags.begin(), reqtags.end() ); + hiertags = qb->GetHierachicalSearchTags(ePatientRootType); + tags.insert( tags.begin(), hiertags.begin(), hiertags.end() ); + delete qb; + } + else //include all previous levels (ie, series gets study and patient, image gets series, study, and patient) + { + QueryBase* qb = NULL; + if (strcmp(theVal.c_str(), "PATIENT ") == 0) + { + //make sure remaining tags are somewhere in the list of required, unique, or optional tags + std::vector tagGroup; + qb = new QueryPatient(); + tagGroup = qb->GetUniqueTags(ePatientRootType); + tags.insert(tags.end(), tagGroup.begin(), tagGroup.end()); + delete qb; + } + else if (strcmp(theVal.c_str(), "STUDY ") == 0) + { + //make sure remaining tags are somewhere in the list of required, unique, or optional tags + std::vector tagGroup; + qb = new QueryPatient(); + tagGroup = qb->GetUniqueTags(ePatientRootType); + tags.insert(tags.end(), tagGroup.begin(), tagGroup.end()); + delete qb; + qb = new QueryStudy(); + tagGroup = qb->GetUniqueTags(ePatientRootType); + tags.insert(tags.end(), tagGroup.begin(), tagGroup.end()); + delete qb; + } + else if (strcmp(theVal.c_str(), "SERIES") == 0) + { + //make sure remaining tags are somewhere in the list of required, unique, or optional tags + std::vector tagGroup; + qb = new QueryPatient(); + tagGroup = qb->GetUniqueTags(ePatientRootType); + tags.insert(tags.end(), tagGroup.begin(), tagGroup.end()); + delete qb; + qb = new QueryStudy(); + tagGroup = qb->GetUniqueTags(eStudyRootType); + tags.insert(tags.end(), tagGroup.begin(), tagGroup.end()); + delete qb; + qb = new QuerySeries(); + tagGroup = qb->GetUniqueTags(ePatientRootType); + tags.insert(tags.end(), tagGroup.begin(), tagGroup.end()); + delete qb; + } + else if (strcmp(theVal.c_str(), "IMAGE ") == 0) + { + //make sure remaining tags are somewhere in the list of required, unique, or optional tags + std::vector tagGroup; + qb = new QueryPatient(); + tagGroup = qb->GetUniqueTags(ePatientRootType); + tags.insert(tags.end(), tagGroup.begin(), tagGroup.end()); + delete qb; + qb = new QueryStudy(); + tagGroup = qb->GetUniqueTags(ePatientRootType); + tags.insert(tags.end(), tagGroup.begin(), tagGroup.end()); + delete qb; + qb = new QuerySeries(); + tagGroup = qb->GetUniqueTags(ePatientRootType); + tags.insert(tags.end(), tagGroup.begin(), tagGroup.end()); + delete qb; + qb = new QueryImage(); + tagGroup = qb->GetUniqueTags(ePatientRootType); + tags.insert(tags.end(), tagGroup.begin(), tagGroup.end()); + delete qb; + } + if (tags.empty()) + { + gdcmWarningMacro( "Invalid Level" ); + return false; + } + } + //all the tags in the dataset should be in that tag list + //otherwise, it's not valid + //also, while the level tag must be present, and the language tag can be + //present (but does not have to be), some other tag must show up as well + //so, have two counts: 1 for tags that are found, 1 for tags that are not + //if there are no found tags, then the query is invalid + //if there is one improper tag found, then the query is invalid + DataSet::ConstIterator itor; + Attribute<0x0008, 0x0005> language; + if( inStrict ) + { + unsigned int thePresentTagCount = 0; + for (itor = ds.Begin(); itor != ds.End(); itor++) + { + const Tag &t = itor->GetTag(); + if (t == level.GetTag()) continue; + if (t == language.GetTag()) continue; + assert( !tags.empty() ); + if (std::find(tags.begin(), tags.end(), t) == tags.end()) + { + //check to see if it's a language tag, 8,5, and if it is, ignore if it's one + //of the possible language tag values + //well, for now, just allow it if it's present. + gdcmWarningMacro( "You have an extra tag: " << t ); + theReturn = false; + break; + } + else + { + // Ok this tags is in Unique/Required or Optional, need to check + // if it is in Required/Unique now: + //std::copy( hiertags.begin(), hiertags.end(), + // std::ostream_iterator( std::cout, "," ) ); + if (std::find(hiertags.begin(), hiertags.end(), t) != + hiertags.end()) + { + gdcmDebugMacro( "Found at least one key: " << t ); + thePresentTagCount++; + } + } + } + if( thePresentTagCount != hiertags.size() ) + { + gdcmWarningMacro( "Missing Key found (within the hierachical search ones)" ); + theReturn = false; + } + } + return theReturn; +} + +UIDs::TSName MovePatientRootQuery::GetAbstractSyntaxUID() const +{ + return UIDs::PatientRootQueryRetrieveInformationModelMOVE; +} + +} diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmMovePatientRootQuery.h b/gdcm/Source/MessageExchangeDefinition/gdcmMovePatientRootQuery.h new file mode 100644 index 0000000..186b48d --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmMovePatientRootQuery.h @@ -0,0 +1,42 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMMOVEPATIENTROOTQUERY_H +#define GDCMMOVEPATIENTROOTQUERY_H + +#include "gdcmFindPatientRootQuery.h" + +namespace gdcm +{ +/** + * \brief MovePatientRootQuery + * contains: the class which will produce a dataset for c-move with patient root + */ +class GDCM_EXPORT MovePatientRootQuery : public BaseRootQuery +{ + friend class QueryFactory; +public: + MovePatientRootQuery(); + + void InitializeDataSet(const EQueryLevel& inQueryLevel); + + std::vector GetTagListByLevel(const EQueryLevel& inQueryLevel); + + bool ValidateQuery(bool inStrict = true) const; + + UIDs::TSName GetAbstractSyntaxUID() const; +}; + +} // end namespace gdcm + +#endif // GDCMMOVEPATIENTROOTQUERY_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmMoveStudyRootQuery.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmMoveStudyRootQuery.cxx new file mode 100644 index 0000000..d6dac5a --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmMoveStudyRootQuery.cxx @@ -0,0 +1,235 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmMoveStudyRootQuery.h" + +#include "gdcmAttribute.h" +#include "gdcmDataSet.h" +#include + +namespace gdcm +{ + +MoveStudyRootQuery::MoveStudyRootQuery() +{ + mRootType = eStudyRootType; + mHelpDescription = "Study-level root query"; +} + +void MoveStudyRootQuery::InitializeDataSet(const EQueryLevel& inQueryLevel) +{ + switch (inQueryLevel) + { + case eStudy: + { + Attribute<0x8,0x52> at1 = { "STUDY " }; + mDataSet.Insert( at1.GetAsDataElement() ); + } + break; + case eSeries: + { + Attribute<0x8,0x52> at1 = { "SERIES" }; + mDataSet.Insert( at1.GetAsDataElement() ); + Attribute<0x20, 0xd> Studylevel = { "" };// make it blank + mDataSet.Insert( Studylevel.GetAsDataElement() ); + } + default: + break; + case eImage: + { + Attribute<0x8,0x52> at1 = { "IMAGE " }; + mDataSet.Insert( at1.GetAsDataElement() ); + + Attribute<0x20, 0xd> Studylevel = { "" };// make it blank + mDataSet.Insert( Studylevel.GetAsDataElement() ); + + Attribute<0x20, 0xe> SeriesLevel = { "" };// make it blank + mDataSet.Insert( SeriesLevel.GetAsDataElement() ); + } + break; + } +} + +std::vector MoveStudyRootQuery::GetTagListByLevel(const EQueryLevel& inQueryLevel) +{ + switch (inQueryLevel) + { + case ePatient: + return mPatient.GetUniqueTags(eStudyRootType); + case eStudy: + return mStudy.GetUniqueTags(eStudyRootType); + case eSeries: +// default: + return mSeries.GetUniqueTags(eStudyRootType); + case eImage: + return mImage.GetUniqueTags(eStudyRootType); + default: //have to return _something_ if a query level isn't given + assert(0); + { + std::vector empty; + return empty; + } + } +} + +bool MoveStudyRootQuery::ValidateQuery(bool inStrict) const +{ + //if it's empty, it's not useful + const DataSet &ds = GetQueryDataSet(); + if (ds.Size() == 0) + { + if (inStrict) + gdcmWarningMacro( "Empty DataSet in ValidateQuery" ); + return false; + } + + //search for 0x8,0x52 + Attribute<0x0008, 0x0052> level; + level.SetFromDataElement( ds.GetDataElement( level.GetTag() ) ); + const std::string theVal = level.GetValue(); + const int ilevel = BaseRootQuery::GetQueryLevelFromString( theVal.c_str() ); + if( ilevel == -1 ) + { + gdcmWarningMacro( "Invalid Level" ); + return false; + } + + bool theReturn = true; + + // requirement is that tag should belong to { opttags U requiredtags } && at + // least one tag from { requiredtags } + std::vector tags; // Optional+Required (at same level) + std::vector hiertags; // Unique + Unique level above (Hierarchical Search) + + if (inStrict) + { + QueryBase* qb = BaseRootQuery::Construct( eStudyRootType, (EQueryLevel)ilevel ); + if (qb == NULL) + { + gdcmWarningMacro( "Invalid Query" ); + return false; + } + + std::vector opttags = qb->GetOptionalTags(eStudyRootType); + tags.insert( tags.begin(), opttags.begin(), opttags.end() ); + std::vector reqtags = qb->GetRequiredTags(eStudyRootType); + tags.insert( tags.begin(), reqtags.begin(), reqtags.end() ); + hiertags = qb->GetHierachicalSearchTags(eStudyRootType); + tags.insert( tags.begin(), hiertags.begin(), hiertags.end() ); + delete qb; + } + else //include all previous levels (ie, series gets study, image gets series and study) + { + QueryBase* qb = NULL; + + if (strcmp(theVal.c_str(), "STUDY ") == 0) + { + //make sure remaining tags are somewhere in the list of required, unique, or optional tags + std::vector tagGroup; + qb = new QueryStudy(); + tagGroup = qb->GetUniqueTags(eStudyRootType); + tags.insert(tags.end(), tagGroup.begin(), tagGroup.end()); + delete qb; + } + if (strcmp(theVal.c_str(), "SERIES") == 0) + { + //make sure remaining tags are somewhere in the list of required, unique, or optional tags + std::vector tagGroup; + qb = new QueryStudy(); + tagGroup = qb->GetUniqueTags(eStudyRootType); + tags.insert(tags.end(), tagGroup.begin(), tagGroup.end()); + delete qb; + qb = new QuerySeries(); + tagGroup = qb->GetUniqueTags(eStudyRootType); + tags.insert(tags.end(), tagGroup.begin(), tagGroup.end()); + delete qb; + } + if (strcmp(theVal.c_str(), "IMAGE ") == 0) + { + //make sure remaining tags are somewhere in the list of required, unique, or optional tags + std::vector tagGroup; + qb = new QueryStudy(); + tagGroup = qb->GetUniqueTags(eStudyRootType); + tags.insert(tags.end(), tagGroup.begin(), tagGroup.end()); + delete qb; + qb = new QuerySeries(); + tagGroup = qb->GetUniqueTags(eStudyRootType); + tags.insert(tags.end(), tagGroup.begin(), tagGroup.end()); + delete qb; + qb = new QueryImage(); + tagGroup = qb->GetUniqueTags(eStudyRootType); + tags.insert(tags.end(), tagGroup.begin(), tagGroup.end()); + delete qb; + } + if (tags.empty()) + { + gdcmWarningMacro( "Invalid Level" ); + return false; + } + } + + //all the tags in the dataset should be in that tag list + //otherwise, it's not valid + //also, while the level tag must be present, and the language tag can be + //present (but does not have to be), some other tag must show up as well + //so, have two counts: 1 for tags that are found, 1 for tags that are not + //if there are no found tags, then the query is invalid + //if there is one improper tag found, then the query is invalid + DataSet::ConstIterator itor; + Attribute<0x0008, 0x0005> language; + if( inStrict ) + { + unsigned int thePresentTagCount = 0; + for (itor = ds.Begin(); itor != ds.End(); itor++) + { + Tag t = itor->GetTag(); + if (t == level.GetTag()) continue; + if (t == language.GetTag()) continue; + if (std::find(tags.begin(), tags.end(), t) == tags.end()) + { + //check to see if it's a language tag, 8,5, and if it is, ignore if it's one + //of the possible language tag values + //well, for now, just allow it if it's present. + gdcmWarningMacro( "You have an extra tag: " << t ); + theReturn = false; + break; + } + else + { + // Ok this tags is in Unique/Required or Optional, need to check + // if it is in Required/Unique now: + //std::copy( hiertags.begin(), hiertags.end(), + // std::ostream_iterator( std::cout, "," ) ); + if (std::find(hiertags.begin(), hiertags.end(), t) != + hiertags.end()) + { + gdcmDebugMacro( "Found at least one key: " << t ); + thePresentTagCount++; + } + } + } + if( thePresentTagCount != hiertags.size() ) + { + gdcmWarningMacro( "Missing Key found (within the hierachical search ones)" ); + theReturn = false; + } + } + return theReturn; +} + +UIDs::TSName MoveStudyRootQuery::GetAbstractSyntaxUID() const +{ + return UIDs::StudyRootQueryRetrieveInformationModelMOVE; +} + +} // end namespace gdcm diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmMoveStudyRootQuery.h b/gdcm/Source/MessageExchangeDefinition/gdcmMoveStudyRootQuery.h new file mode 100644 index 0000000..787539e --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmMoveStudyRootQuery.h @@ -0,0 +1,42 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMMOVESTUDYROOTQUERY_H +#define GDCMMOVESTUDYROOTQUERY_H + +#include "gdcmBaseRootQuery.h" + +namespace gdcm +{ +/** + * \brief MoveStudyRootQuery + * contains: the class which will produce a dataset for C-MOVE with study root + */ +class GDCM_EXPORT MoveStudyRootQuery : public BaseRootQuery +{ + friend class QueryFactory; +public: + MoveStudyRootQuery(); + + void InitializeDataSet(const EQueryLevel& inQueryLevel); + + std::vector GetTagListByLevel(const EQueryLevel& inQueryLevel); + + bool ValidateQuery(bool inStrict = true) const; + + UIDs::TSName GetAbstractSyntaxUID() const; +}; + +} // end namespace gdcm + +#endif // GDCMMOVESTUDYROOTQUERY_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmNetworkEvents.h b/gdcm/Source/MessageExchangeDefinition/gdcmNetworkEvents.h new file mode 100644 index 0000000..5188203 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmNetworkEvents.h @@ -0,0 +1,60 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +/* +The NetworkEvents enumeration defines the inputs into the state of the network connection. + +These inputs can come either from user input or input from other things on the socket, +ie, responses from the peer or ARTIM timeouts. + +Note that this enumeration is not 'power of two', like the states, because you can't have +multiple simultaneous events. Multiple state outputs in transition tables, however, is possible. + +*/ +#ifndef GDCMNETWORKEVENTS_H +#define GDCMNETWORKEVENTS_H + +namespace gdcm { + namespace network{ + typedef enum { + eAASSOCIATERequestLocalUser = 0, + eTransportConnConfirmLocal, + eASSOCIATE_ACPDUreceived, + eASSOCIATE_RJPDUreceived, + eTransportConnIndicLocal, + eAASSOCIATE_RQPDUreceived, + eAASSOCIATEresponseAccept, + eAASSOCIATEresponseReject, + ePDATArequest, + ePDATATFPDU, + eARELEASERequest, + eARELEASE_RQPDUReceivedOpen, + eARELEASE_RPPDUReceived, + eARELEASEResponse, + eAABORTRequest, + eAABORTPDUReceivedOpen, + eTransportConnectionClosed, + eARTIMTimerExpired, + eUnrecognizedPDUReceived, + eEventDoesNotExist + } EEventID; + + const int cMaxEventID = eEventDoesNotExist; + } +} + +#endif //NETWORKEVENTS_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmNetworkStateID.h b/gdcm/Source/MessageExchangeDefinition/gdcmNetworkStateID.h new file mode 100644 index 0000000..98f6fec --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmNetworkStateID.h @@ -0,0 +1,89 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#ifndef GDCMNETWORKSTATEID_H +#define GDCMNETWORKSTATEID_H + +namespace gdcm { + namespace network { + +/** + * Each network connection will be in a particular state at any given time. + * Those states have IDs as described in the standard ps3.8-2009, roughly 1-13. + * This enumeration lists those states. The actual ULState class will contain more information + * about transitions to other states. + * + * name and date: 16 sept 2010 mmr + */ + enum EStateID { + eStaDoesNotExist = 0, + eSta1Idle = 1, + eSta2Open = 2, + eSta3WaitLocalAssoc = 4, + eSta4LocalAssocDone = 8, + eSta5WaitRemoteAssoc = 16, + eSta6TransferReady = 32, + eSta7WaitRelease = 64, + eSta8WaitLocalRelease = 128, + eSta9ReleaseCollisionRqLocal = 256, + eSta10ReleaseCollisionAc = 512, + eSta11ReleaseCollisionRq = 1024, + eSta12ReleaseCollisionAcLocal = 2048, + eSta13AwaitingClose = 4096 + }; + + const int cMaxStateID = 13; + + //the transition table is built on state indeces + //this function will produce the index from the power-of-two EStateID + inline int GetStateIndex(EStateID inState){ + switch (inState){ + case eStaDoesNotExist: + default: + return -1; + case eSta1Idle: + return 0; + case eSta2Open: + return 1; + case eSta3WaitLocalAssoc: + return 2; + case eSta4LocalAssocDone: + return 3; + case eSta5WaitRemoteAssoc: + return 4; + case eSta6TransferReady: + return 5; + case eSta7WaitRelease: + return 6; + case eSta8WaitLocalRelease: + return 7; + case eSta9ReleaseCollisionRqLocal: + return 8; + case eSta10ReleaseCollisionAc: + return 9; + case eSta11ReleaseCollisionRq: + return 10; + case eSta12ReleaseCollisionAcLocal: + return 11; + case eSta13AwaitingClose: + return 12; + } + } + } +} + +#endif //GDCMNETWORKSTATEID_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmPDUFactory.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmPDUFactory.cxx new file mode 100644 index 0000000..31bbc2b --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmPDUFactory.cxx @@ -0,0 +1,256 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +/* +basically, given an initial byte, construct the appropriate PDU. +this way, the event loop doesn't have to know about all the different PDU types. + +name and date: 25 Sept 2010 mmr + +Updte on 27 sept 2010 mmr: since this is where all PDUs are included, also use this +class to construct specific instances of PDUs, and return the BasePDU class. +*/ +#include "gdcmPDUFactory.h" +#include "gdcmAAbortPDU.h" +#include "gdcmAAssociateACPDU.h" +#include "gdcmAAssociateRJPDU.h" +#include "gdcmAAssociateRQPDU.h" +#include "gdcmAReleaseRPPDU.h" +#include "gdcmAReleaseRQPDU.h" +#include "gdcmPDataTFPDU.h" +#include "gdcmCompositeMessageFactory.h" +#include "gdcmBaseRootQuery.h" +#include "gdcmBasePDU.h" + +namespace gdcm +{ +namespace network +{ + +//eventually needs to be smartpointer'd +BasePDU* PDUFactory::ConstructPDU(uint8_t itemtype) +{ + BasePDU* thePDU = NULL; + switch (itemtype) + { + case 0x01: + thePDU = new AAssociateRQPDU; + break; + case 0x02: + thePDU = new AAssociateACPDU; + break; + case 0x03: + thePDU = new AAssociateRJPDU; + break; + case 0x04: + thePDU = new PDataTFPDU; + break; + case 0x05: + thePDU = new AReleaseRQPDU; + break; + case 0x06: + thePDU = new AReleaseRPPDU; + break; + case 0x07: + thePDU = new AAbortPDU; + break; + //default is that the PDU remains null + } + if( !thePDU ) + { + gdcmErrorMacro( "Could not construct PDU for itemtype: " << (int)itemtype ); + } + return thePDU; +} + +//determine which event was received by the PDU type +EEventID PDUFactory::DetermineEventByPDU(const BasePDU* inPDU) +{ + if(inPDU) + { + const AAssociateRQPDU* theAAssociateRQPDU = dynamic_cast(inPDU); + if (theAAssociateRQPDU != NULL) + { + return eAASSOCIATE_RQPDUreceived; + } + const AAssociateACPDU* theAAssociateACPDU = dynamic_cast(inPDU); + if (theAAssociateACPDU != NULL) + { + return eASSOCIATE_ACPDUreceived; + } + const AAssociateRJPDU* theAAssociateRJPDU = dynamic_cast(inPDU); + if (theAAssociateRJPDU != NULL) + { + return eASSOCIATE_RJPDUreceived; + } + const PDataTFPDU* thePDataTFPDU = dynamic_cast(inPDU); + if (thePDataTFPDU != NULL) + { + /// + const PresentationDataValue &pdv = thePDataTFPDU->GetPresentationDataValue(0); + (void)pdv; +#if 0 + int mh = pdv.GetMessageHeader(); + if( mh == 3 ) + { + // E.2 MESSAGE CONTROL HEADER ENCODING + // If bit 1 is set to 1, the following fragment shall contain the last + // fragment of a Message Data Set or of a Message Command. + std::cout << "This was the last fragment of the message data set" << std::endl; + } +#endif + return ePDATATFPDU; + } + const AReleaseRQPDU* theAReleaseRQPDU = dynamic_cast(inPDU); + if (theAReleaseRQPDU != NULL) + { + return eARELEASE_RQPDUReceivedOpen; + } + const AReleaseRPPDU* theAReleaseRPPDU = dynamic_cast(inPDU); + if (theAReleaseRPPDU != NULL) + { + return eARELEASE_RPPDUReceived; + } + const AAbortPDU* theAAbortPDU = dynamic_cast(inPDU); + if (theAAbortPDU != NULL) + { + return eAABORTPDUReceivedOpen; + } + } + return eEventDoesNotExist; +} + +BasePDU* PDUFactory::ConstructReleasePDU() +{ + AReleaseRQPDU* theAReleaseRQPDU = new AReleaseRQPDU(); + + return theAReleaseRQPDU; +} +BasePDU* PDUFactory::ConstructAbortPDU() +{ + AAbortPDU* theAAbortPDU = new AAbortPDU(); + + return theAAbortPDU; +} +std::vector PDUFactory::CreateCEchoPDU(const ULConnection& inConnection) +{ + std::vector pdv = + CompositeMessageFactory::ConstructCEchoRQ(inConnection); + std::vector::iterator pdvItor; + std::vector outVector; + for (pdvItor = pdv.begin(); pdvItor < pdv.end(); pdvItor++) + { + PDataTFPDU* thePDataTFPDU = new PDataTFPDU(); + thePDataTFPDU->AddPresentationDataValue( *pdvItor ); + outVector.push_back(thePDataTFPDU); + } + return outVector; +} + +std::vector PDUFactory::CreateCMovePDU(const ULConnection& + inConnection, const BaseRootQuery* inRootQuery) +{ + std::vector pdv = + CompositeMessageFactory::ConstructCMoveRQ(inConnection, inRootQuery ); + std::vector::iterator pdvItor; + std::vector outVector; + for (pdvItor = pdv.begin(); pdvItor < pdv.end(); pdvItor++) + { + PDataTFPDU* thePDataTFPDU = new PDataTFPDU(); + thePDataTFPDU->AddPresentationDataValue( *pdvItor ); + outVector.push_back(thePDataTFPDU); + } + return outVector; +} + +std::vector PDUFactory::CreateCStoreRQPDU(const ULConnection& inConnection, + const File& file) +{ + std::vector pdv = + CompositeMessageFactory::ConstructCStoreRQ(inConnection, file); + std::vector::iterator pdvItor; + std::vector outVector; + for (pdvItor = pdv.begin(); pdvItor < pdv.end(); pdvItor++) + { + PDataTFPDU* thePDataTFPDU = new PDataTFPDU; + thePDataTFPDU->AddPresentationDataValue( *pdvItor ); + outVector.push_back(thePDataTFPDU); + } + return outVector; +} + +std::vector PDUFactory::CreateCStoreRSPPDU(const DataSet* inDataSet, + const BasePDU* inPDU) +{ + std::vector pdv = + CompositeMessageFactory::ConstructCStoreRSP(inDataSet, inPDU ); + std::vector::iterator pdvItor; + std::vector outVector; + for (pdvItor = pdv.begin(); pdvItor < pdv.end(); pdvItor++) + { + PDataTFPDU* thePDataTFPDU = new PDataTFPDU; + thePDataTFPDU->AddPresentationDataValue( *pdvItor ); + outVector.push_back(thePDataTFPDU); + } + return outVector; +} + +std::vector PDUFactory::CreateCFindPDU(const ULConnection& inConnection, + const BaseRootQuery* inRootQuery) +{ +//still have to build this! + std::vector pdv = + CompositeMessageFactory::ConstructCFindRQ(inConnection, inRootQuery ); + std::vector::iterator pdvItor; + std::vector outVector; + for (pdvItor = pdv.begin(); pdvItor < pdv.end(); pdvItor++) + { + PDataTFPDU* thePDataTFPDU = new PDataTFPDU(); + thePDataTFPDU->AddPresentationDataValue( *pdvItor ); + outVector.push_back(thePDataTFPDU); + } + return outVector; + + +} + + +//given data pdus, produce the presentation data values stored within. +//all operations have these as the payload of the data sending operation +//however, echo does not have a dataset in the pdv. +std::vector PDUFactory::GetPDVs(const std::vector & inDataPDUs) +{ + std::vector::const_iterator itor; + std::vector outPDVs; + for (itor = inDataPDUs.begin(); itor < inDataPDUs.end(); itor++) + { + PDataTFPDU* thePDataTFPDU = dynamic_cast(*itor); + if (thePDataTFPDU == NULL) + { + assert(0); //shouldn't really get here. + return outPDVs; //just stop now, no longer with data pdus. + } + size_t theNumPDVsinPDU = thePDataTFPDU->GetNumberOfPresentationDataValues(); + for (size_t i = 0; i < theNumPDVsinPDU; i++) + { + outPDVs.push_back(thePDataTFPDU->GetPresentationDataValue(i)); + } + } + return outPDVs; +} +} // end namespace network +} // end namespace gdcm diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmPDUFactory.h b/gdcm/Source/MessageExchangeDefinition/gdcmPDUFactory.h new file mode 100644 index 0000000..9c3bb72 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmPDUFactory.h @@ -0,0 +1,62 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#ifndef GDCMPDUFACTORY_H +#define GDCMPDUFACTORY_H + +#include "gdcmTypes.h" +#include "gdcmNetworkEvents.h" +#include "gdcmULConnection.h" +#include "gdcmPresentationDataValue.h" + +namespace gdcm{ + class BaseRootQuery; + class File; + namespace network{ + class BasePDU; + +/** + * \brief PDUFactory basically, given an initial byte, construct the + * appropriate PDU. This way, the event loop doesn't have to know about all + * the different PDU types. + */ + class PDUFactory { + public: + static BasePDU* ConstructPDU(uint8_t itemtype);//eventually needs to be smartpointer'd + static EEventID DetermineEventByPDU(const BasePDU* inPDU); + static BasePDU* ConstructReleasePDU(); + static BasePDU* ConstructAbortPDU(); + + //these are the composite PDU construction methods for the PDataPDUs. + //basically, builds a pdatapdu, and then puts the appropriate information in + //for the appropriate composite service (c-echo, c-find, c-store, c-get, c-move) + //the connection is necessary to construct the stream of PDVs that will + //be then placed into the vector of PDUs + static std::vector CreateCEchoPDU(const ULConnection& inConnection); + static std::vector CreateCStoreRQPDU(const ULConnection& inConnection, const File &file); + static std::vector CreateCStoreRSPPDU(const DataSet *inDataSet, const BasePDU* inPC); + static std::vector CreateCFindPDU(const ULConnection& inConnection, const BaseRootQuery* inRootQuery); + static std::vector CreateCMovePDU(const ULConnection& inConnection, const BaseRootQuery* inRootQuery); + + //given data pdus, produce the presentation data values stored within. + //all operations have these as the payload of the data sending operation + //however, echo does not have a dataset in the pdv. + static std::vector GetPDVs(const std::vector & inDataPDUs); + }; + } +} +#endif //GDCMPDUFACTORY_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmPDataTFPDU.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmPDataTFPDU.cxx new file mode 100644 index 0000000..6dd4e14 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmPDataTFPDU.cxx @@ -0,0 +1,138 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmPDataTFPDU.h" +#include "gdcmSwapper.h" + +namespace gdcm +{ +namespace network +{ +const uint8_t PDataTFPDU::ItemType = 0x04; // PDUType ? +const uint8_t PDataTFPDU::Reserved2 = 0x00; + +PDataTFPDU::PDataTFPDU() +{ + assert(Size() < std::numeric_limits::max()); + ItemLength = (uint32_t)Size() - 6; + assert( (ItemLength + 4 + 1 + 1) == Size() ); +} + +std::istream &PDataTFPDU::Read(std::istream &is) +{ + //uint8_t itemtype = 0; + //is.read( (char*)&itemtype, sizeof(ItemType) ); + //assert( itemtype == ItemType ); + uint8_t reserved2 = 0; + is.read( (char*)&reserved2, sizeof(Reserved2) ); + uint32_t itemlength = ItemLength; + is.read( (char*)&itemlength, sizeof(ItemLength) ); + SwapperDoOp::SwapArray(&itemlength,1); + ItemLength = itemlength; + + size_t curlen = 0; + while( curlen < ItemLength ) + { + PresentationDataValue pdv; + pdv.Read( is ); + V.push_back( pdv ); + curlen += pdv.Size(); + } + assert( curlen == ItemLength ); + assert( (ItemLength + 4 + 1 + 1) == Size() ); + + return is; +} + +std::istream &PDataTFPDU::ReadInto(std::istream &is, std::ostream &os) +{ + uint8_t itemtype = 0; + is.read( (char*)&itemtype, sizeof(ItemType) ); + assert( itemtype == ItemType ); + uint8_t reserved2 = 0; + is.read( (char*)&reserved2, sizeof(Reserved2) ); + uint32_t itemlength = ItemLength; + is.read( (char*)&itemlength, sizeof(ItemLength) ); + SwapperDoOp::SwapArray(&itemlength,1); + ItemLength = itemlength; + + size_t curlen = 0; + while( curlen < ItemLength ) + { + PresentationDataValue pdv; + pdv.ReadInto( is, os ); + V.push_back( pdv ); + curlen += pdv.Size(); + } + assert( curlen == ItemLength ); + assert( (ItemLength + 4 + 1 + 1) == Size() ); + + return is; +} + +const std::ostream &PDataTFPDU::Write(std::ostream &os) const +{ + assert( (ItemLength + 4 + 1 + 1) == Size() ); + os.write( (char*)&ItemType, sizeof(ItemType) ); + os.write( (char*)&Reserved2, sizeof(Reserved2) ); + //os.write( (char*)&ItemLength, sizeof(ItemLength) ); + uint32_t copy = ItemLength; + SwapperDoOp::SwapArray(©,1); + os.write( (char*)©, sizeof(ItemLength) ); + std::vector::const_iterator it = V.begin(); + for( ; it != V.end(); ++it ) + { + it->Write( os ); + } + + return os; +} + +size_t PDataTFPDU::Size() const +{ + size_t ret = 0; + ret += sizeof(ItemType); + ret += sizeof(Reserved2); + ret += sizeof(ItemLength); + std::vector::const_iterator it = V.begin(); + for( ; it != V.end(); ++it ) + { + ret += it->Size( ); + } + + return ret; +} + +void PDataTFPDU::Print(std::ostream &os) const +{ + //static const uint8_t ItemType; // PDUType ? + //static const uint8_t Reserved2; + os << "ItemLength: " << ItemLength << std::endl; // PDU Length ? + os << "PresentationDataValue: " << std::endl; + std::vector::const_iterator it = V.begin(); + for( ; it != V.end(); ++it ) + { + it->Print( os ); + } + os << std::endl; +} + + +bool PDataTFPDU::IsLastFragment() const +{ + if (V.empty()) return true; + return V[V.size()-1].GetIsLastFragment(); +} + +} // end namespace network +} // end namespace gdcm diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmPDataTFPDU.h b/gdcm/Source/MessageExchangeDefinition/gdcmPDataTFPDU.h new file mode 100644 index 0000000..d867e02 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmPDataTFPDU.h @@ -0,0 +1,74 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMPDATATFPDU_H +#define GDCMPDATATFPDU_H + +#include "gdcmTypes.h" +#include "gdcmPresentationDataValue.h" +#include "gdcmBasePDU.h" +#include + +namespace gdcm +{ + +namespace network +{ + +/** + * \brief PDataTFPDU + * Table 9-22 + * P-DATA-TF PDU FIELDS + */ +class GDCM_EXPORT PDataTFPDU : public BasePDU +{ +public: + PDataTFPDU(); + std::istream &Read(std::istream &is); + const std::ostream &Write(std::ostream &os) const; + + /// \internal Compute Size + size_t Size() const; + + void AddPresentationDataValue( PresentationDataValue const &pdv ) { + V.push_back( pdv ); + assert(Size() < std::numeric_limits::max()); + ItemLength = (uint32_t)Size() - 6; + } + + typedef std::vector::size_type SizeType; + PresentationDataValue const &GetPresentationDataValue(SizeType i) const { + assert( !V.empty() && i < V.size() ); + return V[i]; + } + SizeType GetNumberOfPresentationDataValues() const { + return V.size(); + } + + void Print(std::ostream &os) const; + bool IsLastFragment() const; + +protected: + std::istream &ReadInto(std::istream &is, std::ostream &os); +private: + static const uint8_t ItemType; // PDUType ? + static const uint8_t Reserved2; + uint32_t ItemLength; // PDU Length ? + std::vector V; +}; + +} // end namespace network + +} // end namespace gdcm + +#endif //GDCMPDATATFPDU_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmPresentationContext.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmPresentationContext.cxx new file mode 100644 index 0000000..c98448e --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmPresentationContext.cxx @@ -0,0 +1,67 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmPresentationContext.h" + +#include "gdcmUIDs.h" +#include "gdcmAttribute.h" +#include "gdcmMediaStorage.h" +#include "gdcmTransferSyntax.h" + +#include + +namespace gdcm +{ + +PresentationContext::PresentationContext( ) +{ + ID = 0x01; +} + +PresentationContext::PresentationContext( UIDs::TSName asname, UIDs::TSName tsname ) +{ + ID = 0x01; + const char *asnamestr = UIDs::GetUIDString( asname ); + AbstractSyntax = asnamestr; + + const char *tsnamestr = UIDs::GetUIDString( tsname ); + AddTransferSyntax( tsnamestr ); +} + +void PresentationContext::AddTransferSyntax( const char *tsstr ) +{ + TransferSyntaxes.push_back( tsstr ); +} + +void PresentationContext::SetPresentationContextID( uint8_t id ) +{ + assert( id ); + ID = id; +} + +uint8_t PresentationContext::GetPresentationContextID() const +{ + return ID; +} + +void PresentationContext::Print(std::ostream &os) const +{ + os << "AbstractSyntax:" << AbstractSyntax << std::endl; + std::vector::const_iterator it = TransferSyntaxes.begin(); + for( ; it != TransferSyntaxes.end(); ++it ) + { + os << *it << std::endl; + } +} + +} // end namespace gdcm diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmPresentationContext.h b/gdcm/Source/MessageExchangeDefinition/gdcmPresentationContext.h new file mode 100644 index 0000000..991317e --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmPresentationContext.h @@ -0,0 +1,69 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMPRESENTATIONCONTEXT_H +#define GDCMPRESENTATIONCONTEXT_H + +#include "gdcmTypes.h" +#include "gdcmUIDs.h" + +#include + +namespace gdcm +{ + +/** + * \brief PresentationContext + * \see PresentationContextAC PresentationContextRQ + */ +class GDCM_EXPORT PresentationContext +{ +public: + PresentationContext(); + + /// Initialize Presentation Context with AbstractSyntax set to asname + /// and with a single TransferSyntax set to tsname (default to Implicit VR + /// LittleEndian when not specified ). + PresentationContext( UIDs::TSName asname, + UIDs::TSName tsname = UIDs::ImplicitVRLittleEndianDefaultTransferSyntaxforDICOM ); + + void SetAbstractSyntax( const char *as ) { AbstractSyntax = as; } + const char *GetAbstractSyntax() const { return AbstractSyntax.c_str(); } + + void AddTransferSyntax( const char *tsstr ); + typedef std::vector TransferSyntaxArrayType; + typedef TransferSyntaxArrayType::size_type SizeType; + const char *GetTransferSyntax(SizeType i) const { return TransferSyntaxes[i].c_str(); } + SizeType GetNumberOfTransferSyntaxes() const { return TransferSyntaxes.size(); } + + void SetPresentationContextID( uint8_t id ); + uint8_t GetPresentationContextID() const; + + void Print(std::ostream &os) const; + + bool operator==(const PresentationContext & pc) const + { + assert( TransferSyntaxes.size() == 1 ); // TODO + assert( pc.TransferSyntaxes.size() == 1 ); + return AbstractSyntax == pc.AbstractSyntax && TransferSyntaxes == pc.TransferSyntaxes; + } + +private: + std::string AbstractSyntax; + std::vector TransferSyntaxes; + uint8_t /*PresentationContext*/ID; +}; + +} // end namespace gdcm + +#endif //GDCMPRESENTATIONCONTEXT_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmPresentationContextAC.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmPresentationContextAC.cxx new file mode 100644 index 0000000..08274c9 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmPresentationContextAC.cxx @@ -0,0 +1,119 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmPresentationContextAC.h" +#include "gdcmSwapper.h" + +#include + +namespace gdcm +{ +namespace network +{ +const uint8_t PresentationContextAC::ItemType = 0x21; +const uint8_t PresentationContextAC::Reserved2 = 0x00; +const uint8_t PresentationContextAC::Reserved6 = 0x00; +const uint8_t PresentationContextAC::Reserved8 = 0x00; + +PresentationContextAC::PresentationContextAC() +{ + ID = 1; // odd [1-255] + Result = 0; + ItemLength = 8; + assert( (size_t)ItemLength + 4 == Size() ); +} + +std::istream &PresentationContextAC::Read(std::istream &is) +{ + //uint8_t itemtype = 0x0; + //is.read( (char*)&itemtype, sizeof(ItemType) ); + //assert( itemtype == ItemType ); + uint8_t reserved2; + is.read( (char*)&reserved2, sizeof(Reserved2) ); + uint16_t itemlength; + is.read( (char*)&itemlength, sizeof(ItemLength) ); + SwapperDoOp::SwapArray(&itemlength,1); + ItemLength = itemlength; + uint8_t id; + is.read( (char*)&id, sizeof(ID) ); + ID = id; + uint8_t reserved6; + is.read( (char*)&reserved6, sizeof(Reserved6) ); + uint8_t result; + is.read( (char*)&result, sizeof(Result) ); + Result = result; // 0-4 + uint8_t reserved8; + is.read( (char*)&reserved8, sizeof(Reserved6) ); + SubItems.Read( is ); + + assert( (size_t)ItemLength + 4 == Size() ); + return is; +} + +const std::ostream &PresentationContextAC::Write(std::ostream &os) const +{ + os.write( (char*)&ItemType, sizeof(ItemType) ); + os.write( (char*)&Reserved2, sizeof(Reserved2) ); + //os.write( (char*)&ItemLength, sizeof(ItemLength) ); + uint16_t copy = ItemLength; + SwapperDoOp::SwapArray(©,1); + os.write( (char*)©, sizeof(ItemLength) ); + os.write( (char*)&ID, sizeof(ID) ); + os.write( (char*)&Reserved6, sizeof(Reserved6) ); + os.write( (char*)&Result, sizeof(Result) ); + os.write( (char*)&Reserved8, sizeof(Reserved8) ); + SubItems.Write(os); + + assert( (size_t)ItemLength + 4 == Size() ); + return os; +} + +size_t PresentationContextAC::Size() const +{ + size_t ret = 0; + ret += sizeof(ItemType); + ret += sizeof(Reserved2); + ret += sizeof(ItemLength); + ret += sizeof(ID); + ret += sizeof(Reserved6); + ret += sizeof(Result); + ret += sizeof(Reserved8); + ret += SubItems.Size(); + + assert(ret <= (size_t)std::numeric_limits::max); + assert(ret >= 4); + return ret; +} + +void PresentationContextAC::SetTransferSyntax( TransferSyntaxSub const &ts ) +{ + SubItems = ts; + ItemLength = (uint16_t)(Size() - 4); + assert( (size_t)ItemLength + 4 == Size() ); +} + +void PresentationContextAC::Print(std::ostream &os) const +{ + os << "ID: " << (int)ID << std::endl; + os << "Result: " << (int)Result << std::endl; + os << "TransferSyntax: "; + SubItems.Print( os ); +} + +void PresentationContextAC::SetPresentationContextID( uint8_t id ) +{ + ID = id; +} + +} // end namespace network +} // end namespace gdcm diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmPresentationContextAC.h b/gdcm/Source/MessageExchangeDefinition/gdcmPresentationContextAC.h new file mode 100644 index 0000000..9e7fe41 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmPresentationContextAC.h @@ -0,0 +1,70 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMPRESENTATIONCONTEXTAC_H +#define GDCMPRESENTATIONCONTEXTAC_H + +#include "gdcmTypes.h" +#include "gdcmTransferSyntaxSub.h" + +namespace gdcm +{ + +namespace network +{ + +/** + * \brief PresentationContextAC + * Table 9-18 + * PRESENTATION CONTEXT ITEM FIELDS + * \see PresentationContext + */ +class PresentationContextAC +{ +public: + PresentationContextAC(); + std::istream &Read(std::istream &is); + const std::ostream &Write(std::ostream &os) const; + + size_t Size() const; + + void SetTransferSyntax( TransferSyntaxSub const &ts ); + void SetPresentationContextID( uint8_t id ); + + void Print(std::ostream &os) const; + + uint8_t GetPresentationContextID() const + { + return ID; + } + TransferSyntaxSub const & GetTransferSyntax() const { return SubItems; } + + void SetReason( uint8_t r ) { Result = r; } + uint8_t GetReason() const { return Result; } + +private: + static const uint8_t ItemType; + static const uint8_t Reserved2; + uint16_t ItemLength; // len of last transfer syntax + uint8_t /*PresentationContext*/ID; + static const uint8_t Reserved6; + uint8_t /*Reason*/Result; + static const uint8_t Reserved8; + TransferSyntaxSub SubItems; +}; + +} // end namespace network + +} // end namespace gdcm + +#endif //GDCMPRESENTATIONCONTEXTAC_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmPresentationContextGenerator.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmPresentationContextGenerator.cxx new file mode 100644 index 0000000..bdcb5de --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmPresentationContextGenerator.cxx @@ -0,0 +1,171 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmPresentationContextGenerator.h" + +#include "gdcmReader.h" +#include "gdcmTransferSyntax.h" + +#include // std::find + +namespace gdcm +{ +std::string PresentationContextGenerator::DefaultTransferSyntax = "1.2.840.10008.1.2"; + +const char *PresentationContextGenerator::GetDefaultTransferSyntax() const +{ + return DefaultTransferSyntax.c_str(); +} + +void PresentationContextGenerator::SetDefaultTransferSyntax( const TransferSyntax &ts ) +{ + DefaultTransferSyntax = ts.GetString(); +} + +PresentationContextGenerator::PresentationContextGenerator() {} + +//bool PresentationContextGenerator::GenerateFromQuery(BaseRootQuery *query) +//{ +//} + +bool PresentationContextGenerator::GenerateFromUID(UIDs::TSName asname) +{ + PresContext.clear(); + + const char *asnamestr = UIDs::GetUIDString( asname ); + const char *tsnamestr = GetDefaultTransferSyntax(); + + // There is a special case for MOVE operations. Need to have alternate FIND operations + if( asname == UIDs::PatientRootQueryRetrieveInformationModelMOVE ) + { + const char *asnamestr0 = UIDs::GetUIDString( + UIDs::PatientRootQueryRetrieveInformationModelFIND ); + AddPresentationContext( asnamestr0, tsnamestr ); + } + else if( asname == UIDs::StudyRootQueryRetrieveInformationModelMOVE ) + { + const char *asnamestr0 = UIDs::GetUIDString( + UIDs::StudyRootQueryRetrieveInformationModelFIND ); + AddPresentationContext( asnamestr0, tsnamestr ); + } + // Always set the *MOVE after the *FIND one + AddPresentationContext( asnamestr, tsnamestr ); + + return true; +} + +bool PresentationContextGenerator::GenerateFromFilenames(const Directory::FilenamesType &filenames) +{ + PresContext.clear(); + + // By design GDCM C-STORE implementation only setup the association for any dataset we are + // about to send. This is therefore very important to gather all possible SOP Class + // we are about to send otherwise the other end will simply disconnect us + // this imply that C-STORE will refuse any DataSet without SOP Clas or SOP Instances + Tag tsuid(0x2,0x10); + Tag mediasopclass(0x2,0x2); + Tag sopclass(0x8,0x16); +#if 0 + Scanner sc; + sc.AddTag( tsuid ); + sc.AddTag( mediasopclass ); + sc.AddTag( sopclass ); + if( !sc.Scan( filenames ) ) + { + gdcmErrorMacro( "Could not scan filenames" ); + return 1; + } +#endif + + Directory::FilenamesType::const_iterator file = filenames.begin(); + std::set skiptags; + for(; file != filenames.end(); ++file) + { + // I cannot use gdcm::Scanner as I need the TS of the file. When the file + // only contains the DataSet I cannot know if this is Explicit or Implicit + // Instead re-use the lower level bricks of gdcm::Scanner here: + const char *fn = file->c_str(); + Reader reader; + reader.SetFileName( fn ); + // NOTE: There is a small overhead right here: what if we are sending Deflated + // TS encoded file. We should not need to read up to tag 8,16 ... + if( reader.ReadUpToTag( sopclass, skiptags ) ) + { + DataSet const & ds = reader.GetFile().GetDataSet(); + if( ds.FindDataElement( sopclass ) ) + { + // by design gdcmscu will not send/retrieve a dataset that cannot be read + // this should not be too restricitive + const TransferSyntax &fmits = reader.GetFile().GetHeader().GetDataSetTransferSyntax(); + //const char *tsuidvalue = sc.GetValue(fn, tsuid); + const char *tsuidvalue = fmits.GetString(); + //const char *sopclassvalue = sc.GetValue(fn, sopclass ); + + const DataElement &tsde = ds.GetDataElement( sopclass ); + //const char *sopclassvalue = sc.GetValue(fn, sopclass ); + // Passing pointer directly. We do not try to analyze what Media Storage + // it is. We should be able to support to send/receive unknwon media storage + const ByteValue *bv = tsde.GetByteValue(); + std::string buffer( bv->GetPointer(), bv->GetLength() ); + const char *sopclassvalue = buffer.c_str(); + + AddPresentationContext( sopclassvalue, tsuidvalue ); + } + } + else + { + gdcmErrorMacro( "Could not read: " << fn ); + } + } + + return true; +} + +bool PresentationContextGenerator::AddPresentationContext( const char *as, const char * ts ) +{ + // \precondition + assert( as ); + assert( ts ); + + SizeType n = PresContext.size(); + PresentationContext pc; + pc.SetAbstractSyntax( as ); + SizeType idn = 2*n + 1; + assert( idn <= std::numeric_limits::max() ); + pc.SetPresentationContextID( (uint8_t)idn ); + pc.AddTransferSyntax( ts ); + + PresentationContextArrayType::const_iterator it = + std::find( PresContext.begin(), PresContext.end(), pc ); + + // default mode it to only append when pc is not present already: + // warning dcmtk 3.5.4 will segfault if no PresentationContext is found + // (fixed in 3.6.0) + if( it == PresContext.end() ) + { + PresContext.push_back( pc ); + } + + return true; +} + +void PresentationContextGenerator::SetMergeModeToAbstractSyntax() +{ +} + +void PresentationContextGenerator::SetMergeModeToTransferSyntax() +{ + assert( 0 && "TODO" ); +} + +} // end namespace gdcm diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmPresentationContextGenerator.h b/gdcm/Source/MessageExchangeDefinition/gdcmPresentationContextGenerator.h new file mode 100644 index 0000000..9bb8e43 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmPresentationContextGenerator.h @@ -0,0 +1,93 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMPRESENTATIONCONTEXTGENERATOR_H +#define GDCMPRESENTATIONCONTEXTGENERATOR_H + +#include "gdcmDirectory.h" +#include "gdcmPresentationContext.h" + +namespace gdcm +{ +class TransferSyntax; + +/** + * \brief PresentationContextGenerator + * This class is responsible for generating the proper PresentationContext that + * will be used in subsequent operation during a DICOM Query/Retrieve + * association. The step of the association is very sensible as special care + * need to be taken to explicitly define what instance are going to be send + * and how they are encoded. + * + * For example a PresentationContext will express that negotiation requires + * that CT Image Storage are send using JPEG Lossless, while US Image Storage + * are sent using RLE Transfer Syntax. + * + * Two very different API are exposed one which will always default to little + * endian transfer syntax see GenerateFromUID() + * This API is used for C-ECHO, C-FIND and C-MOVE (SCU). + * Another API: GenerateFromFilenames() is used for C-STORE (SCU) as it will + * loop over all filenames argument to detect the actual encoding. and + * therefore find the proper encoding to be used. + * + * Two modes are available. The default mode (SetMergeModeToAbstractSyntax) + * append PresentationContext (one AbstractSyntax and one TransferSyntax), as + * long a they are different. Eg MR Image Storage/JPEG2000 and MR Image + * Storage/JPEGLossless would be considered different. the other mode + * SetMergeModeToTransferSyntax merge any new TransferSyntax to the already + * existing PresentationContext in order to re-use the same AbstractSyntax. + * + * \see PresentationContext + */ +class GDCM_EXPORT PresentationContextGenerator +{ +public: + PresentationContextGenerator(); + + // Set MergeMode + // Default mode, each pair AbstractSyntax/TransferSyntax are only merged when + // exactly identical + void SetMergeModeToAbstractSyntax(); + + // Set MergeMode + // Merge is done on a per AbstractSyntax basis. Any new TransferSyntax for a + // given AbstractSyntax is merge to the existing PresentationContext refering + // to that AbstractSyntax + void SetMergeModeToTransferSyntax(); + + /// Generate the PresentationContext array from a UID (eg. VerificationSOPClass) + bool GenerateFromUID(UIDs::TSName asname); + + /// Generate the PresentationContext array from a File-Set. File specified needs to + /// be valid DICOM files. + /// Used for C-STORE operations + bool GenerateFromFilenames(const Directory::FilenamesType &files); + + typedef std::vector PresentationContextArrayType; + typedef PresentationContextArrayType::size_type SizeType; + PresentationContextArrayType const &GetPresentationContexts() { return PresContext; } + + /// Not implemented for now. GDCM internally uses Implicit Little Endian + void SetDefaultTransferSyntax( const TransferSyntax &ts ); +protected: + bool AddPresentationContext( const char *as, const char *ts ); + const char *GetDefaultTransferSyntax() const; + +private: + std::vector PresContext; + static std::string DefaultTransferSyntax; +}; + +} // end namespace gdcm + +#endif //GDCMPRESENTATIONCONTEXTGENERATOR_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmPresentationContextRQ.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmPresentationContextRQ.cxx new file mode 100644 index 0000000..01feb73 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmPresentationContextRQ.cxx @@ -0,0 +1,199 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmPresentationContextRQ.h" + +#include "gdcmPresentationContext.h" +#include "gdcmUIDs.h" +#include "gdcmSwapper.h" +#include "gdcmAttribute.h" +#include "gdcmGlobal.h" +#include "gdcmMediaStorage.h" + +#include + +namespace gdcm +{ +namespace network +{ +const uint8_t PresentationContextRQ::ItemType = 0x20; +const uint8_t PresentationContextRQ::Reserved2 = 0x00; +const uint8_t PresentationContextRQ::Reserved6 = 0x00; +const uint8_t PresentationContextRQ::Reserved7 = 0x00; +const uint8_t PresentationContextRQ::Reserved8 = 0x00; + +PresentationContextRQ::PresentationContextRQ() +{ + ID = 0x01; + ItemLength = 8; + assert( (size_t)ItemLength + 4 == Size() ); +} + +PresentationContextRQ::PresentationContextRQ( UIDs::TSName asname, UIDs::TSName tsname ) +{ + ID = 0x01; + AbstractSyntax as; + as.SetNameFromUID( asname ); + SetAbstractSyntax( as ); + + TransferSyntaxSub ts; + ts.SetNameFromUID( tsname ); + assert( TransferSyntaxes.empty() ); + AddTransferSyntax( ts ); +} + +std::istream &PresentationContextRQ::Read(std::istream &is) +{ + //uint8_t itemtype = 0x0; + //is.read( (char*)&itemtype, sizeof(ItemType) ); + //assert( itemtype == ItemType ); + uint8_t reserved2; + is.read( (char*)&reserved2, sizeof(Reserved2) ); + uint16_t itemlength; + is.read( (char*)&itemlength, sizeof(ItemLength) ); + SwapperDoOp::SwapArray(&itemlength,1); + ItemLength = itemlength; + uint8_t id; + is.read( (char*)&id, sizeof(ID) ); + ID = id; + uint8_t reserved6; + is.read( (char*)&reserved6, sizeof(Reserved6) ); + uint8_t reserved7; + is.read( (char*)&reserved7, sizeof(Reserved7) ); +// assert( reserved7 == 0 ); + //no need for this assert--'This reserved field shall be sent with a value 00H but not tested to this value when received.' + uint8_t reserved8; + is.read( (char*)&reserved8, sizeof(Reserved6) ); + SubItems.Read( is ); + + size_t curlen = 0; + size_t offset = SubItems.Size() + 4; + while( curlen + offset < ItemLength ) + { + TransferSyntaxSub ts; + ts.Read( is ); + TransferSyntaxes.push_back( ts ); + curlen += ts.Size(); + } + assert( curlen + offset == ItemLength ); + + assert( (size_t)ItemLength + 4 == Size() ); + return is; +} + +const std::ostream &PresentationContextRQ::Write(std::ostream &os) const +{ + assert( (size_t)ItemLength + 4 == Size() ); + os.write( (char*)&ItemType, sizeof(ItemType) ); + os.write( (char*)&Reserved2, sizeof(Reserved2) ); + uint16_t copy = ItemLength; + SwapperDoOp::SwapArray(©,1); + os.write( (char*)©, sizeof(ItemLength) ); + + os.write( (char*)&ID, sizeof(ID) ); + os.write( (char*)&Reserved6, sizeof(Reserved6) ); + os.write( (char*)&Reserved7, sizeof(Reserved7) ); + os.write( (char*)&Reserved8, sizeof(Reserved8) ); + SubItems.Write(os); + std::vector::const_iterator it = TransferSyntaxes.begin(); + for( ; it != TransferSyntaxes.end(); ++it ) + { + it->Write( os ); + } + + return os; +} + +size_t PresentationContextRQ::Size() const +{ + size_t ret = 0; + ret += sizeof(ItemType); + ret += sizeof(Reserved2); + ret += sizeof(ItemLength); + ret += sizeof(ID); + ret += sizeof(Reserved6); + ret += sizeof(Reserved7); + ret += sizeof(Reserved8); + ret += SubItems.Size(); + std::vector::const_iterator it = TransferSyntaxes.begin(); + for( ; it != TransferSyntaxes.end(); ++it ) + { + ret += it->Size(); + } + + assert(ret <= (size_t)std::numeric_limits::max); + assert(ret >= 4); + return ret; +} + +void PresentationContextRQ::SetAbstractSyntax( AbstractSyntax const & as ) +{ + SubItems = as; + ItemLength = (uint16_t)(Size() - 4); + assert( (size_t)ItemLength + 4 == Size() ); +} + +void PresentationContextRQ::AddTransferSyntax( TransferSyntaxSub const &ts ) +{ + TransferSyntaxes.push_back( ts ); + ItemLength = (uint16_t)(Size() - 4); + assert( (size_t)ItemLength + 4 == Size() ); +} + +void PresentationContextRQ::SetPresentationContextID( uint8_t id ) +{ + assert( id ); + ID = id; +} + +uint8_t PresentationContextRQ::GetPresentationContextID() const +{ + return ID; +} + +void PresentationContextRQ::Print(std::ostream &os) const +{ + //static const uint8_t ItemType; + //static const uint8_t Reserved2; + os << "ItemLength: " << ItemLength << std::endl; // len of last transfer syntax + os << "PresentationContext ID: " << (int)ID << std::endl; + //static const uint8_t Reserved6; + //static const uint8_t Reserved7; + //static const uint8_t Reserved8; + SubItems.Print( os ); + std::vector::const_iterator it = TransferSyntaxes.begin(); + for( ; it != TransferSyntaxes.end(); ++it ) + { + it->Print( os ); + } +} + +PresentationContextRQ::PresentationContextRQ(const PresentationContext & in) +{ + AbstractSyntax as; + as.SetName( in.GetAbstractSyntax() ); + SetAbstractSyntax( as ); + size_t n = in.GetNumberOfTransferSyntaxes(); + TransferSyntaxes.clear(); + for( size_t j = 0; j < n; ++j ) + { + TransferSyntaxSub ts; + ts.SetName( in.GetTransferSyntax(j) ); + AddTransferSyntax( ts ); + } + SetPresentationContextID( in.GetPresentationContextID() ); + assert( GetNumberOfTransferSyntaxes() == in.GetNumberOfTransferSyntaxes() ); +} + +} // end namespace network +} // end namespace gdcm diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmPresentationContextRQ.h b/gdcm/Source/MessageExchangeDefinition/gdcmPresentationContextRQ.h new file mode 100644 index 0000000..db06a9f --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmPresentationContextRQ.h @@ -0,0 +1,96 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMPRESENTATIONCONTEXTRQ_H +#define GDCMPRESENTATIONCONTEXTRQ_H + +#include "gdcmTypes.h" +#include "gdcmAbstractSyntax.h" +#include "gdcmTransferSyntaxSub.h" +#include "gdcmDataSet.h" + +namespace gdcm +{ +class PresentationContext; +namespace network +{ + +/** + * \brief PresentationContextRQ + * Table 9-13 + * PRESENTATION CONTEXT ITEM FIELDS + * \see PresentationContextAC + */ +class GDCM_EXPORT PresentationContextRQ +{ +public: + PresentationContextRQ(); + + /// Initialize Presentation Context with AbstractSyntax set to asname + /// and with a single TransferSyntax set to tsname (dfault to Implicit VR + /// LittleEndian when not specified ). + PresentationContextRQ( UIDs::TSName asname, UIDs::TSName tsname = + UIDs::ImplicitVRLittleEndianDefaultTransferSyntaxforDICOM ); + + std::istream &Read(std::istream &is); + const std::ostream &Write(std::ostream &os) const; + size_t Size() const; + + void SetAbstractSyntax( AbstractSyntax const & as ); + AbstractSyntax const &GetAbstractSyntax() const { return SubItems; } + AbstractSyntax &GetAbstractSyntax() { return SubItems; } + + void AddTransferSyntax( TransferSyntaxSub const &ts ); + typedef std::vector::size_type SizeType; + TransferSyntaxSub const & GetTransferSyntax(SizeType i) const { return TransferSyntaxes[i]; } + TransferSyntaxSub & GetTransferSyntax(SizeType i) { return TransferSyntaxes[i]; } + std::vector const & GetTransferSyntaxes() const {return TransferSyntaxes; } + SizeType GetNumberOfTransferSyntaxes() const { return TransferSyntaxes.size(); } + + void SetPresentationContextID( uint8_t id ); + uint8_t GetPresentationContextID() const; + + void Print(std::ostream &os) const; + + bool operator==(const PresentationContextRQ & pc) const + { + assert( TransferSyntaxes.size() == 1 ); // TODO + assert( pc.TransferSyntaxes.size() == 1 ); + return SubItems == pc.SubItems && TransferSyntaxes == pc.TransferSyntaxes; + } + + PresentationContextRQ(const PresentationContext & pc); + +private: + static const uint8_t ItemType; + static const uint8_t Reserved2; + uint16_t ItemLength; // len of last transfer syntax + uint8_t /*PresentationContext*/ID; + static const uint8_t Reserved6; + static const uint8_t Reserved7; + static const uint8_t Reserved8; + /* + This variable field shall contain the following sub-items: one Abstract + Syntax and one or more Transfer Syntax(es). For a complete + description of the use and encoding of these sub-items see Sections + 9.3.2.2.1 and 9.3.2.2.2. + */ + AbstractSyntax SubItems; + std::vector TransferSyntaxes; +}; + +} // end namespace network + +} // end namespace gdcm + +#endif //GDCMPRESENTATIONCONTEXTRQ_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmPresentationDataValue.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmPresentationDataValue.cxx new file mode 100644 index 0000000..c87f8b6 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmPresentationDataValue.cxx @@ -0,0 +1,272 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmPresentationDataValue.h" +#include "gdcmSwapper.h" +#include "gdcmFile.h" +#include "gdcmAttribute.h" +#include "gdcmCommandDataSet.h" +#include "gdcmPrinter.h" + +#include + +namespace gdcm +{ +namespace network +{ + +PresentationDataValue::PresentationDataValue() +{ + MessageHeader = 0; + PresentationContextID = 0; //MUST BE SET BY THE CALLER! + + // postcondition + assert(Size() < std::numeric_limits::max()); + ItemLength = (uint32_t)Size() - 4; + assert (ItemLength + 4 == Size() ); +} + +std::istream &PresentationDataValue::Read(std::istream &is) +{ + uint32_t itemlength = ItemLength; + is.read( (char*)&itemlength, sizeof(ItemLength) ); + SwapperDoOp::SwapArray(&itemlength,1); + ItemLength = itemlength; + is.read( (char*)&PresentationContextID, sizeof(PresentationContextID) ); + + uint8_t mh; + is.read( (char*)&mh, 1 ); + MessageHeader = mh; + if ( MessageHeader > 3 ) + { + gdcmDebugMacro( "Bizarre MessageHeader: " << MessageHeader ); + } + + assert( ItemLength > 2 ); + uint32_t vl = ItemLength - 2; + Blob.resize( vl ); + is.read( &Blob[0], vl ); + + assert (ItemLength + 4 == Size() ); + return is; +} + +std::istream &PresentationDataValue::ReadInto(std::istream &is, std::ostream &os) +{ + uint32_t itemlength = ItemLength; + is.read( (char*)&itemlength, sizeof(ItemLength) ); + SwapperDoOp::SwapArray(&itemlength,1); + ItemLength = itemlength; + is.read( (char*)&PresentationContextID, sizeof(PresentationContextID) ); + + uint8_t mh; + is.read( (char*)&mh, 1 ); + MessageHeader = mh; + if ( MessageHeader > 3 ) + { + gdcmDebugMacro( "Bizarre MessageHeader: " << MessageHeader ); + } + + assert( ItemLength > 2 ); + uint32_t vl = ItemLength - 2; + Blob.resize( vl ); + is.read( &Blob[0], vl ); + os.write( &Blob[0], vl ); + + assert (ItemLength + 4 == Size() ); + return is; +} + +const std::ostream &PresentationDataValue::Write(std::ostream &os) const +{ + uint32_t copy = ItemLength; + SwapperDoOp::SwapArray(©,1); + os.write( (char*)©, sizeof(ItemLength) ); + assert( os.good() ); + os.write( (char*)&PresentationContextID, sizeof(PresentationContextID) ); + assert( os.good() ); + + assert( MessageHeader <= 3 ); + uint8_t t = MessageHeader; + os.write( (char*)&t, 1 ); + assert( os.good() ); + + os.write( Blob.c_str(), Blob.size() ); + + assert( Blob.size() == ItemLength - 2 ); + assert (ItemLength + 4 == Size() ); + + return os; +} + +size_t PresentationDataValue::Size() const +{ + size_t ret = 0; + ret += sizeof(ItemLength); + ret += sizeof(PresentationContextID); + ret += sizeof(MessageHeader); // MESSAGE CONTROL HEADER ENCODING + ret += Blob.size(); + + return ret; +} + +void PresentationDataValue::SetBlob(const std::string & partialblob) +{ + assert( !partialblob.empty() ); + Blob = partialblob; + assert(Size() < std::numeric_limits::max()); + ItemLength = (uint32_t)Size() - 4; + assert (ItemLength + 4 == Size() ); +} + +void PresentationDataValue::SetDataSet(const DataSet & ds) +{ + std::stringstream ss; + //!!FIXME-- have to make sure that the transfer syntax is known and accounted for! + ds.Write( ss ); + SetBlob( ss.str() ); +} + +const std::string &PresentationDataValue::GetBlob() const +{ + return Blob; +} + +//should only be one data set per chunk of pdvs. So, only return one; the +//loop that gets the results from the scp will be clever and only enter this function +//when the pdu has its 'last bit' set to true (ie, when all the pdvs can be sent in at once, +//but the are all part of the same data set) +DataSet PresentationDataValue::ConcatenatePDVBlobs(const std::vector& inPDVs) +{ + //size_t s = inPDVs.size(); + + std::string theEntireBuffer;//could do it as streams. but apparently, std isn't letting me + std::vector::const_iterator itor; + for (itor = inPDVs.begin(); itor < inPDVs.end(); itor++){ + const std::string & theBlobString = itor->GetBlob(); + theEntireBuffer.insert(theEntireBuffer.end(), theBlobString.begin(), theBlobString.end()); + } + + DataSet outDataSet; + + std::stringstream ss; + ss.str( theEntireBuffer ); + +#if 0 + char fn[512]; + static int i = 0; + sprintf( fn, "/tmp/debugimp%d", i++ ); + std::ofstream d( fn, std::ios::binary ); + d.write( theEntireBuffer.c_str(), theEntireBuffer.size() ); + d.close(); +#endif + + outDataSet.Read( ss ); + //outDataSet.Read( ss ); + + + return outDataSet; +} + +DataSet PresentationDataValue::ConcatenatePDVBlobsAsExplicit(const std::vector& inPDVs) +{ +#if 0 + std::stringstream ss; + std::vector::const_iterator itor; + for (itor = inPDVs.begin(); itor < inPDVs.end(); itor++) + { + const std::string & theBlobString = itor->GetBlob(); + ss.write( &theBlobString[0], theBlobString.size() ); + } +#else + std::string theEntireBuffer;//could do it as streams. but apparently, std isn't letting me + std::vector::const_iterator itor; + for (itor = inPDVs.begin(); itor < inPDVs.end(); itor++){ + const std::string & theBlobString = itor->GetBlob(); + theEntireBuffer.insert(theEntireBuffer.end(), theBlobString.begin(), theBlobString.end()); + } + + + std::stringstream ss; + ss.str( theEntireBuffer ); + +#endif + +#if 0 + char fn[512]; + static int i = 0; + sprintf( fn, "/tmp/debugex%d", i++ ); + std::ofstream d( fn, std::ios::binary ); + d.write( theEntireBuffer.c_str(), theEntireBuffer.size() ); + d.close(); +#endif + + DataSet outDataSet; + //outDataSet.Read( ss ); + VL length = (uint32_t)theEntireBuffer.size(); + //gdcm::Trace::DebugOn(); + outDataSet.ReadWithLength( ss, length ); + + return outDataSet; +} + +void PresentationDataValue::Print(std::ostream &os) const +{ + os << "ItemLength: " << ItemLength << std::endl; + os << "PresentationContextID: " << (int)PresentationContextID << std::endl; + os << "MessageHeader: " << (int)MessageHeader << std::endl; + std::vector thePDVs; + thePDVs.push_back(*this); + DataSet ds = ConcatenatePDVBlobs(thePDVs); + Printer thePrinter; + thePrinter.PrintDataSet(ds, os); +} + +void PresentationDataValue::SetCommand(bool inCommand) +{ + const uint8_t flipped = ~1; + if (inCommand) + { + MessageHeader |= 1; + } + else + { + MessageHeader &= flipped; + } +} + +void PresentationDataValue::SetLastFragment(bool inLast) +{ + const uint8_t flipped = ~2; + if (inLast) + { + MessageHeader |= 2; + } + else + { + MessageHeader &= flipped;//set the second field to zero + } +} + +bool PresentationDataValue::GetIsCommand() const +{ + return (MessageHeader & 1) == 1; +} + +bool PresentationDataValue::GetIsLastFragment() const +{ + return (MessageHeader & 2) == 2; +} + +} // end namespace network +} // end namespace gdcm diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmPresentationDataValue.h b/gdcm/Source/MessageExchangeDefinition/gdcmPresentationDataValue.h new file mode 100644 index 0000000..a2dbcf8 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmPresentationDataValue.h @@ -0,0 +1,92 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMPRESENTATIONDATAVALUE_H +#define GDCMPRESENTATIONDATAVALUE_H + +#include "gdcmTypes.h" + +#include + +namespace gdcm +{ +class DataSet; +namespace network +{ + +/** + * \brief PresentationDataValue + * Table 9-23 + * PRESENTATION-DATA-VALUE ITEM FIELDS + */ +class GDCM_EXPORT PresentationDataValue +{ +public: + PresentationDataValue(); + std::istream &Read(std::istream &is); + std::istream &ReadInto(std::istream &is, std::ostream &os); + + const std::ostream &Write(std::ostream &os) const; + + /// \internal Compute Size + size_t Size() const; + + /// Set DataSet. Write DataSet in implicit. + /// \warning size of dataset should be below maxpdusize + void SetDataSet(const DataSet & ds); + void SetBlob(const std::string & partialblob); + const std::string &GetBlob() const; + + uint8_t GetPresentationContextID() const { return PresentationContextID; } + void SetPresentationContextID(uint8_t id) { + assert( id ); + PresentationContextID = id; + } + uint8_t GetMessageHeader() const { + assert( MessageHeader <= 0x3 ); + return MessageHeader; + } + // E.2 MESSAGE CONTROL HEADER ENCODING + // Only the first two bits are considered + void SetMessageHeader(uint8_t messageheader) { + MessageHeader = messageheader; + assert( MessageHeader <= 0x3 ); + } + //flip the least significant bit of the message header to 1 + //if this is a command, else set it to 0. + void SetCommand(bool inCommand); + void SetLastFragment(bool inLast);//set to true if this is the last PDV of a set + + bool GetIsCommand() const; + bool GetIsLastFragment() const; + + void Print(std::ostream &os) const; + + //NOTE that the PDVs have to be given in the order in which they were received! + //also note that a dataset may be across multiple PDVs + /// \warning DataSet will be read as Implicit Little Endian TS + static DataSet ConcatenatePDVBlobs(const std::vector& inPDVs); + + static DataSet ConcatenatePDVBlobsAsExplicit(const std::vector& inPDVs); + +private: + uint32_t ItemLength; + uint8_t PresentationContextID; + uint8_t MessageHeader; + std::string Blob; +}; +} // end namespace network + +} // end namespace gdcm + +#endif //GDCMPRESENTATIONDATAVALUE_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmQueryBase.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmQueryBase.cxx new file mode 100644 index 0000000..702aa5a --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmQueryBase.cxx @@ -0,0 +1,38 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmQueryBase.h" +#include "gdcmBaseRootQuery.h" + +namespace gdcm +{ + +std::vector QueryBase::GetAllTags(const ERootType& inRootType) const +{ + std::vector theReturn = GetRequiredTags(inRootType); + std::vector theNext = GetUniqueTags(inRootType); + theReturn.insert(theReturn.end(), theNext.begin(), theNext.end()); + theNext = GetOptionalTags(inRootType); + theReturn.insert(theReturn.end(), theNext.begin(), theNext.end()); + return theReturn; +} + +std::vector QueryBase::GetAllRequiredTags(const ERootType& inRootType) const +{ + std::vector theReturn = GetRequiredTags(inRootType); + std::vector theNext = GetUniqueTags(inRootType); + theReturn.insert(theReturn.end(), theNext.begin(), theNext.end()); + return theReturn; +} + +} // end namespace gdcm diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmQueryBase.h b/gdcm/Source/MessageExchangeDefinition/gdcmQueryBase.h new file mode 100644 index 0000000..bd035c3 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmQueryBase.h @@ -0,0 +1,92 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#ifndef GDCMQUERYBASE_H +#define GDCMQUERYBASE_H + +#include "gdcmTag.h" +#include "gdcmDataElement.h" + +#include + +namespace gdcm +{ + enum ERootType + { + ePatientRootType, + eStudyRootType + }; + +/** + * \brief QueryBase + * contains: the base class for constructing a query dataset for a C-FIND and a + * C-MOVE + * + * There are four levels of C-FIND and C-MOVE query: + * \li Patient + * \li Study + * \li Series + * \li Image + * + * Each one has its own required and optional tags. This class provides an + * interface for getting those tags. This is an interface class. + * + * See 3.4 C 6.1 and 3.4 C 6.2 for the patient and study root query types. + * These sections define the tags allowed by a particular query. The caller + * must pass in which root type they want, patient or study. A third root type, + * Modality Worklist Query, isn't yet supported. + * + * This class (or rather it's derived classes) will be held in the RootQuery + * types. These query types actually make the dataset, and will use this + * dataset to list the required, unique, and optional tags for each type of + * query. This design is somewhat overly complicated, but is kept so that if we + * ever wanted to try to guess the query type from the given tags, we could do + * so. + */ +class GDCM_EXPORT QueryBase +{ + public: + virtual ~QueryBase() {} + + virtual std::vector GetRequiredTags(const ERootType& inRootType) const = 0; + virtual std::vector GetUniqueTags(const ERootType& inRootType) const = 0; + virtual std::vector GetOptionalTags(const ERootType& inRootType) const = 0; + // C.4.1.2.1 Baseline Behavior of SCU + // All C-FIND SCUs shall be capable of generating query requests which + // meet the requirements of the Hierarchical Search. + // The Identifier contained in a C-FIND request shall contain a single + // value in the Unique Key Attribute for each level above the + // Query/Retrieve level. No Required or Optional Keys shall be + // specified which are associated with levels above the Query/Retrieve + // level. + /// Return all Unique Key for a particular Query Root type (from the same level and above). + virtual std::vector GetHierachicalSearchTags(const ERootType& inRootType) const = 0; + + /// In order to validate a query dataset, just check for the presence + /// of a tag, not it's requirement level in the spec + std::vector GetAllTags(const ERootType& inRootType) const; + + /// In order to validate a query dataset we need to check that there + /// exists at least one required (or unique) key + std::vector GetAllRequiredTags(const ERootType& inRootType) const; + + virtual const char * GetName() const = 0; + virtual DataElement GetQueryLevel() const = 0; + }; +} + +#endif //GDCMQUERYBASE_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmQueryFactory.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmQueryFactory.cxx new file mode 100644 index 0000000..dd8e7e6 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmQueryFactory.cxx @@ -0,0 +1,243 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#include "gdcmQueryFactory.h" +#include "gdcmFindPatientRootQuery.h" +#include "gdcmMovePatientRootQuery.h" +#include "gdcmFindStudyRootQuery.h" +#include "gdcmMoveStudyRootQuery.h" + +#include + +namespace gdcm +{ +BaseRootQuery* QueryFactory::ProduceQuery(ERootType inRootType, EQueryType inQueryType, + EQueryLevel inQueryLevel) +{ + BaseRootQuery* theReturn = NULL; + switch (inQueryType) + { + case eFind: + switch (inRootType) + { + case ePatientRootType: + theReturn = new FindPatientRootQuery(); + break; + case eStudyRootType: + if (inQueryLevel != ePatient) + theReturn = new FindStudyRootQuery(); + break; + } + break; + case eMove: + switch (inRootType) + { + case ePatientRootType: + theReturn = new MovePatientRootQuery(); + break; + case eStudyRootType: + if (inQueryLevel != ePatient) + theReturn = new MoveStudyRootQuery(); + break; + } + break; + } + if( theReturn ) + theReturn->InitializeDataSet(inQueryLevel); + return theReturn; +} + +/* +LATIN1 ISO 8859-1 +LATIN2 ISO 8859-2 +LATIN3 ISO 8859-3 +LATIN4 ISO 8859-4 +ISO_8859_5 ISO 8859-5 Latin/Cyrillic +ISO_8859_6 ISO 8859-6 Latin/Arabic +ISO_8859_7 ISO 8859-7 Latin/Greek +ISO_8859_8 ISO 8859-8 Latin/Hebrew +LATIN5 ISO 8859-9 +LATIN6 ISO 8859-10 +LATIN7 ISO 8859-13 +LATIN8 ISO 8859-14 +LATIN9 ISO 8859-15 +LATIN10 ISO 8859-16 +*/ +ECharSet QueryFactory::GetCharacterFromCurrentLocale() +{ + const char *charset = System::GetLocaleCharset(); + if( charset ) + { + // UTF-8 (this is the default for UNIX): + if( strcmp( charset, "UTF-8" ) == 0 ) return eUTF8; + // US-ASCII, simply return latin1 + else if( strcmp( charset, "US-ASCII" ) == 0 ) return eLatin1; + else if( strcmp( charset, "ANSI_X3.4-1968" ) == 0 ) return eLatin1; + // Latin-1 + else if( strcmp( charset, "ISO-8859-1" ) == 0 ) return eLatin1; + else if( strcmp( charset, "ISO-8859-2" ) == 0 ) return eLatin2; + else if( strcmp( charset, "ISO-8859-3" ) == 0 ) return eLatin3; + else if( strcmp( charset, "ISO-8859-4" ) == 0 ) return eLatin4; + else if( strcmp( charset, "ISO-8859-5" ) == 0 ) return eCyrillic; + else if( strcmp( charset, "ISO-8859-6" ) == 0 ) return eArabic; + else if( strcmp( charset, "ISO-8859-7" ) == 0 ) return eGreek; + else if( strcmp( charset, "ISO-8859-8" ) == 0 ) return eHebrew; + else if( strcmp( charset, "ISO-8859-9" ) == 0 ) return eLatin5; + // + else if( strcmp( charset, "EUC-JP" ) == 0 ) return eJapanese; + else if( strcmp( charset, "TIS-620" ) == 0 ) return eThai; + else if( strcmp( charset, "EUC-JP" ) == 0 ) return eJapaneseKanjiMultibyte; + else if( strcmp( charset, "EUC-JP" ) == 0 ) return eJapaneseSupplementaryKanjiMultibyte; + else if( strcmp( charset, "EUC-KR" ) == 0 ) return eKoreanHangulHanjaMultibyte; + //else if( strcmp( charset, "UTF-8" ) == 0 ) return eUTF8; + else if( strcmp( charset, "GB18030" ) == 0 ) return eGB18030; + gdcmWarningMacro( "Problem mapping Locale Charset: " << charset ); + } + gdcmWarningMacro( "Default to Latin-1" ); + return eLatin1; +} + +///This function will produce the appropriate dataelement given a list of charsets. +///The first charset will be used directly, while the second and subsequent +///will be prepended with "ISO2022 ". Redundant character sets are not permitted, +///so if they are encountered, they will just be skipped. +///if UTF8 or GB18030 is used, no subsequent character sets will be used +DataElement QueryFactory::ProduceCharacterSetDataElement(const std::vector& inCharSetType) +{ + DataElement theReturn; + //use the 'visited' array to make sure that if a redundant character set is entered, + //it's skipped rather than produce a malformed tag. + bool visited[eGB18030+1]; + memset(visited, 0, (eGB18030+1)*sizeof(bool)); + + if (inCharSetType.empty()) + return theReturn; + + std::vector::const_iterator itor; + std::string theOutputString; + for (itor = inCharSetType.begin(); itor < inCharSetType.end(); itor++) + { + if (itor > inCharSetType.begin()) + { + theOutputString += "ISO 2022 "; + } + else + { + theOutputString += "ISO_IR "; + } + + if (visited[*itor]) continue; + switch (*itor) + { + default: + case eLatin1: + theOutputString += "100"; + break; + case eLatin2: + theOutputString += "101"; + break; + case eLatin3: + theOutputString += "109"; + break; + case eLatin4: + theOutputString += "110"; + break; + case eCyrillic: + theOutputString += "144"; + break; + case eArabic: + theOutputString += "127"; + break; + case eGreek: + theOutputString += "126"; + break; + case eHebrew: + theOutputString += "138"; + break; + case eLatin5: + theOutputString += "148"; + break; + case eJapanese: + theOutputString += "13"; + break; + case eThai: + theOutputString += "166"; + break; + case eJapaneseKanjiMultibyte: + theOutputString += "87"; + break; + case eJapaneseSupplementaryKanjiMultibyte: + theOutputString += "159"; + break; + case eKoreanHangulHanjaMultibyte: + theOutputString += "149"; + break; + //for the next two, they are only valid if they are + //the only ones that appear + case eUTF8: + theOutputString = "ISO_IR 192"; + itor = inCharSetType.end() - 1; //stop the loop + break; + case eGB18030: + theOutputString = "GB13080"; + itor = inCharSetType.end() - 1; //stop the loop + break; + } + if (itor < (inCharSetType.end()-1)) + { + theOutputString += "\\"; + // the following code will not work for UTF-8 and eGB18030 + assert( itor < inCharSetType.end() ); + visited[*itor] = true; + } + } + + if( theOutputString.size() % 2 ) + theOutputString.push_back( ' ' ); // no \0 ! + theReturn.SetByteValue(theOutputString.c_str(), + (uint32_t)theOutputString.length()); + theReturn.SetTag(Tag(0x0008, 0x0005)); + return theReturn; +} + + +void QueryFactory::ListCharSets(std::ostream& os) +{ + os << "The following character sets are supported by GDCM Network Queries." << std::endl; + os << "The number in the parenthesis is the index to select." << std::endl; + os << "Note that multiple selections are possible." << std::endl; + os << "Latin1 (0): This is the default if nothing is specified." <& inCharSetType); + + /// This function will return the corresponding ECharSet associated with the + /// current locale of the running system (based on the value of locale() ). + static ECharSet GetCharacterFromCurrentLocale(); + + /// List all possible CharSet + static void ListCharSets(std::ostream& os); +}; + +} // end namespace gdcm + +#endif // GDCMQUERYFACTORY_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmQueryImage.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmQueryImage.cxx new file mode 100644 index 0000000..d3871cd --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmQueryImage.cxx @@ -0,0 +1,95 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +/* +contains: class to construct an image-based query for c-find and c-move + +note that at the series and image levels, there is no distinction between the +root query types. + */ + +#include "gdcmQueryImage.h" +#include "gdcmQueryPatient.h" +#include "gdcmQueryStudy.h" +#include "gdcmQuerySeries.h" +#include "gdcmAttribute.h" + +namespace gdcm +{ + +std::vector QueryImage::GetRequiredTags(const ERootType& ) const +{ + std::vector theReturn;//see 3.4 C.6.1.1.5 + theReturn.push_back(Tag(0x0020, 0x0013)); + return theReturn; +} + +std::vector QueryImage::GetUniqueTags(const ERootType& ) const +{ + std::vector theReturn;//see 3.4 C.6.1.1.5 + theReturn.push_back(Tag(0x0008, 0x0018)); + return theReturn; +} + +std::vector QueryImage::GetOptionalTags(const ERootType& ) const +{ + std::vector theReturn;//see 3.4 C.6.1.1.5 + theReturn.push_back(Tag(0x0008, 0x0016));//SOP class UID + //theReturn.push_back(Tag(0x0008, 0x3001));//alternate representation + theReturn.push_back(Tag(0x0008, 0x001A));//related General SOP Class UID + //sequence tags, not including for now + //theReturn.push_back(Tag(0x0040, 0xA504)); + //theReturn.push_back(Tag(0x0040, 0x0512)); + //theReturn.push_back(Tag(0x0040, 0x0560)); + return theReturn; +} + +std::vector QueryImage::GetHierachicalSearchTags(const ERootType& inRootType) const +{ + std::vector tags; + if( inRootType == ePatientRootType ) + { + QueryPatient qp; + tags = qp.GetUniqueTags(inRootType); + } + // add study level + QueryStudy qst; + std::vector qsttags = qst.GetUniqueTags(inRootType); + tags.insert(tags.end(), qsttags.begin(), qsttags.end()); + // add series level + QuerySeries qse; + std::vector qsetags = qse.GetUniqueTags(inRootType); + tags.insert(tags.end(), qsetags.begin(), qsetags.end()); + // add image level + std::vector utags = GetUniqueTags(inRootType); + tags.insert(tags.end(), utags.begin(), utags.end()); + return tags; +} + +DataElement QueryImage::GetQueryLevel() const +{ + const Attribute<0x0008, 0x0052> level = { "IMAGE " }; + return level.GetAsDataElement(); +} + +static const char QueryImageString[] = "Composite Object Instance (Image)"; +const char *QueryImage::GetName() const +{ + return QueryImageString; +} + +} diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmQueryImage.h b/gdcm/Source/MessageExchangeDefinition/gdcmQueryImage.h new file mode 100644 index 0000000..899f038 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmQueryImage.h @@ -0,0 +1,45 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#ifndef GDCMQUERYIMAGE_H +#define GDCMQUERYIMAGE_H + +#include "gdcmQueryBase.h" +#include "gdcmDataSet.h" + +namespace gdcm +{ +/** + * \brief QueryImage + * contains: class to construct an image-based query for C-FIND and C-MOVE + */ +class GDCM_EXPORT QueryImage : public QueryBase +{ +public: + std::vector GetRequiredTags(const ERootType& inRootType) const; + std::vector GetUniqueTags(const ERootType& inRootType) const; + std::vector GetOptionalTags(const ERootType& inRootType) const; + std::vector GetHierachicalSearchTags(const ERootType& inRootType) const; + + const char * GetName() const; + + DataElement GetQueryLevel() const; +}; + +} // end namespace gdcm + +#endif // GDCMQUERYIMAGE_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmQueryPatient.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmQueryPatient.cxx new file mode 100644 index 0000000..b8caaa1 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmQueryPatient.cxx @@ -0,0 +1,108 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +//note that at the series and image levels, there is no distinction between +//the root query types. + +#include "gdcmQueryPatient.h" +#include "gdcmAttribute.h" + +namespace gdcm +{ + +std::vector QueryPatient::GetRequiredTags(const ERootType& inRootType) const +{ + std::vector theReturn;//see 3.4 C.6.1.1.2 + switch (inRootType) + { + case ePatientRootType: + default: + theReturn.push_back(Tag(0x0010, 0x0010)); + break; + case eStudyRootType: + //do nothing + break; + } + return theReturn; +} + +std::vector QueryPatient::GetUniqueTags(const ERootType& inRootType) const +{ + std::vector theReturn;//see 3.4 C.6.1.1.2 + switch (inRootType) + { + case ePatientRootType: + default: + theReturn.push_back(Tag(0x0010, 0x0020)); + break; + case eStudyRootType: + //do nothing + break; + } + return theReturn; +} + +std::vector QueryPatient::GetHierachicalSearchTags(const ERootType& inRootType) const +{ + assert( inRootType == ePatientRootType ); + std::vector tags; + // Patient is always toplevel ! + // just return Required and Unique + std::vector utags = GetUniqueTags(inRootType); + tags.insert(tags.end(), utags.begin(), utags.end()); + return tags; +} + +std::vector QueryPatient::GetOptionalTags(const ERootType& inRootType) const +{ + std::vector theReturn;//see 3.4 C.6.1.1.2 + switch (inRootType){ + case ePatientRootType: + default: + theReturn.push_back(Tag(0x0010, 0x0021)); + theReturn.push_back(Tag(0x0008, 0x1120)); + theReturn.push_back(Tag(0x0010, 0x0030)); + theReturn.push_back(Tag(0x0010, 0x0032)); + theReturn.push_back(Tag(0x0010, 0x0040)); + theReturn.push_back(Tag(0x0010, 0x1000)); + theReturn.push_back(Tag(0x0010, 0x1001)); + theReturn.push_back(Tag(0x0010, 0x2160)); + theReturn.push_back(Tag(0x0010, 0x4000)); + theReturn.push_back(Tag(0x0020, 0x1200)); + theReturn.push_back(Tag(0x0020, 0x1202)); + theReturn.push_back(Tag(0x0020, 0x1204)); + break; + case eStudyRootType: + //do nothing + break; + } + return theReturn; +} + +DataElement QueryPatient::GetQueryLevel() const +{ + const Attribute<0x0008, 0x0052> level = { "PATIENT " }; + return level.GetAsDataElement(); +} + +static const char QueryPatientString[] = "Patient"; +const char * QueryPatient::GetName() const +{ + return QueryPatientString; +} + +} diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmQueryPatient.h b/gdcm/Source/MessageExchangeDefinition/gdcmQueryPatient.h new file mode 100644 index 0000000..da46589 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmQueryPatient.h @@ -0,0 +1,43 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#ifndef GDCMQUERYPATIENT_H +#define GDCMQUERYPATIENT_H + +#include "gdcmQueryBase.h" + +namespace gdcm +{ +/** + * \brief QueryPatient + * contains: class to construct a patient-based query for c-find and c-move + */ +class GDCM_EXPORT QueryPatient : public QueryBase +{ +public: + std::vector GetRequiredTags(const ERootType& inRootType) const; + std::vector GetUniqueTags(const ERootType& inRootType) const; + std::vector GetOptionalTags(const ERootType& inRootType) const; + std::vector GetHierachicalSearchTags(const ERootType& inRootType) const; + + const char * GetName() const; + DataElement GetQueryLevel() const; +}; + +} // end namespace gdcm + +#endif //GDCMQUERYPATIENT_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmQuerySeries.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmQuerySeries.cxx new file mode 100644 index 0000000..64d4c83 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmQuerySeries.cxx @@ -0,0 +1,84 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ + +//note that at the series and image levels, there is no distinction between +//the root query types. + +#include "gdcmQuerySeries.h" +#include "gdcmQueryPatient.h" +#include "gdcmQueryStudy.h" +#include "gdcmAttribute.h" + +namespace gdcm +{ + +std::vector QuerySeries::GetRequiredTags(const ERootType& ) const +{ + std::vector theReturn;//see 3.4 C.6.1.1.4 + theReturn.push_back(Tag(0x0008, 0x0060)); + theReturn.push_back(Tag(0x0020, 0x0011)); + return theReturn; +} + +std::vector QuerySeries::GetUniqueTags(const ERootType& ) const +{ + std::vector theReturn;//see 3.4 C.6.1.1.4 + theReturn.push_back(Tag(0x0020, 0x000E)); + + return theReturn; +} + +std::vector QuerySeries::GetOptionalTags(const ERootType& ) const +{ + std::vector theReturn;//see 3.4 C.6.1.1.4 + theReturn.push_back(Tag(0x0020, 0x1209)); + return theReturn; +} + +std::vector QuerySeries::GetHierachicalSearchTags(const ERootType& inRootType) const +{ + std::vector tags; + if( inRootType == ePatientRootType ) + { + QueryPatient qp; + tags = qp.GetUniqueTags(inRootType); + } + // add study level + QueryStudy qs; + std::vector qstags = qs.GetUniqueTags(inRootType); + tags.insert(tags.end(), qstags.begin(), qstags.end()); + // add series level + std::vector utags = GetUniqueTags(inRootType); + tags.insert(tags.end(), utags.begin(), utags.end()); + return tags; +} + +DataElement QuerySeries::GetQueryLevel() const +{ + const Attribute<0x0008, 0x0052> level = { "SERIES" }; + return level.GetAsDataElement(); +} + +static const char QuerySeriesString[] = "Series"; + +const char * QuerySeries::GetName() const +{ + return QuerySeriesString; +} + +} diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmQuerySeries.h b/gdcm/Source/MessageExchangeDefinition/gdcmQuerySeries.h new file mode 100644 index 0000000..fe7f951 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmQuerySeries.h @@ -0,0 +1,43 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#ifndef GDCMQUERYSERIES_H +#define GDCMQUERYSERIES_H + +#include "gdcmQueryBase.h" + +namespace gdcm +{ +/** + * \brief QuerySeries + * contains: class to construct a series-based query for c-find and c-move + */ +class GDCM_EXPORT QuerySeries : public QueryBase +{ +public: + std::vector GetRequiredTags(const ERootType& inRootType) const; + std::vector GetUniqueTags(const ERootType& inRootType) const; + std::vector GetOptionalTags(const ERootType& inRootType) const; + std::vector GetHierachicalSearchTags(const ERootType& inRootType) const; + + const char * GetName() const; + DataElement GetQueryLevel() const; +}; + +} // end namespace gdcm + +#endif //GDCMQUERYSERIES_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmQueryStudy.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmQueryStudy.cxx new file mode 100644 index 0000000..9121e88 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmQueryStudy.cxx @@ -0,0 +1,143 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +//note that at the series and image levels, there is no distinction between +//the root query types. + +#include "gdcmQueryStudy.h" +#include "gdcmQueryPatient.h" +#include "gdcmAttribute.h" + +namespace gdcm +{ + +std::vector QueryStudy::GetRequiredTags(const ERootType& inRootType) const +{ + std::vector theReturn;//see 3.4 C.6.1.1.3 + switch (inRootType){ + case ePatientRootType: + default: + theReturn.push_back(Tag(0x0008, 0x0020)); + theReturn.push_back(Tag(0x0008, 0x0030)); + theReturn.push_back(Tag(0x0008, 0x0050)); + theReturn.push_back(Tag(0x0020, 0x0010)); + break; + case eStudyRootType: + theReturn.push_back(Tag(0x0008, 0x0020)); + theReturn.push_back(Tag(0x0008, 0x0030)); + theReturn.push_back(Tag(0x0008, 0x0050)); + theReturn.push_back(Tag(0x0010, 0x0010)); + theReturn.push_back(Tag(0x0010, 0x0020)); + theReturn.push_back(Tag(0x0020, 0x0010)); + break; + } + return theReturn; +} + +std::vector QueryStudy::GetUniqueTags(const ERootType& ) const +{ + std::vector theReturn;//see 3.4 C.6.2.1.2 + theReturn.push_back(Tag(0x0020, 0x000d)); + return theReturn; +} + +std::vector QueryStudy::GetOptionalTags(const ERootType& inRootType) const +{ + std::vector theReturn;//see 3.4 C.6.1.1.3 + switch (inRootType) + { + case ePatientRootType: + default: + theReturn.push_back(Tag(0x0008, 0x0061)); + theReturn.push_back(Tag(0x0008, 0x0062)); + theReturn.push_back(Tag(0x0008, 0x0090)); + theReturn.push_back(Tag(0x0008, 0x1030)); + theReturn.push_back(Tag(0x0008, 0x1032)); + theReturn.push_back(Tag(0x0008, 0x1060)); + theReturn.push_back(Tag(0x0008, 0x1080)); + theReturn.push_back(Tag(0x0008, 0x1110)); + theReturn.push_back(Tag(0x0010, 0x1010)); + theReturn.push_back(Tag(0x0010, 0x1020)); + theReturn.push_back(Tag(0x0010, 0x1030)); + theReturn.push_back(Tag(0x0010, 0x2180)); + theReturn.push_back(Tag(0x0010, 0x21B0)); + theReturn.push_back(Tag(0x0020, 0x1070)); + theReturn.push_back(Tag(0x0020, 0x1206)); + theReturn.push_back(Tag(0x0020, 0x1208)); + break; + case eStudyRootType: + theReturn.push_back(Tag(0x0008, 0x0061)); + theReturn.push_back(Tag(0x0008, 0x0062)); + theReturn.push_back(Tag(0x0008, 0x0090)); + theReturn.push_back(Tag(0x0008, 0x1030)); + theReturn.push_back(Tag(0x0008, 0x1032)); + theReturn.push_back(Tag(0x0008, 0x1060)); + theReturn.push_back(Tag(0x0008, 0x1080)); + theReturn.push_back(Tag(0x0008, 0x1110)); + theReturn.push_back(Tag(0x0008, 0x1120)); + theReturn.push_back(Tag(0x0010, 0x0021)); + theReturn.push_back(Tag(0x0010, 0x0030)); + theReturn.push_back(Tag(0x0010, 0x0032)); + theReturn.push_back(Tag(0x0010, 0x0040)); + theReturn.push_back(Tag(0x0010, 0x1000)); + theReturn.push_back(Tag(0x0010, 0x1001)); + theReturn.push_back(Tag(0x0010, 0x1010)); + theReturn.push_back(Tag(0x0010, 0x1020)); + theReturn.push_back(Tag(0x0010, 0x1030)); + theReturn.push_back(Tag(0x0010, 0x2160)); + theReturn.push_back(Tag(0x0010, 0x2180)); + theReturn.push_back(Tag(0x0010, 0x21B0)); + theReturn.push_back(Tag(0x0010, 0x4000)); + + theReturn.push_back(Tag(0x0020, 0x1070)); + theReturn.push_back(Tag(0x0020, 0x1200)); + theReturn.push_back(Tag(0x0020, 0x1202)); + theReturn.push_back(Tag(0x0020, 0x1204)); + theReturn.push_back(Tag(0x0020, 0x1206)); + theReturn.push_back(Tag(0x0020, 0x1208)); + break; + } + return theReturn; +} + +std::vector QueryStudy::GetHierachicalSearchTags(const ERootType& inRootType) const +{ + std::vector tags; + if( inRootType == ePatientRootType ) + { + QueryPatient qp; + tags = qp.GetUniqueTags(inRootType); + } + // add study level + std::vector utags = GetUniqueTags(inRootType); + tags.insert(tags.end(), utags.begin(), utags.end()); + return tags; +} + +DataElement QueryStudy::GetQueryLevel() const +{ + const Attribute<0x0008, 0x0052> level = { "STUDY " }; + return level.GetAsDataElement(); +} + +static const char QueryStudyString[] = "Study"; +const char * QueryStudy::GetName() const +{ + return QueryStudyString; +} + +} // end namespace gdcm diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmQueryStudy.h b/gdcm/Source/MessageExchangeDefinition/gdcmQueryStudy.h new file mode 100644 index 0000000..51d3546 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmQueryStudy.h @@ -0,0 +1,43 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#ifndef GDCMQUERYSTUDY_H +#define GDCMQUERYSTUDY_H + +#include "gdcmQueryBase.h" + +namespace gdcm +{ +/** + * \brief QueryStudy.h + * contains: class to construct a study-based query for C-FIND and C-MOVE + */ +class GDCM_EXPORT QueryStudy : public QueryBase +{ +public: + std::vector GetRequiredTags(const ERootType& inRootType) const; + std::vector GetUniqueTags(const ERootType& inRootType) const; + std::vector GetOptionalTags(const ERootType& inRootType) const; + std::vector GetHierachicalSearchTags(const ERootType& inRootType) const; + + const char *GetName() const; + DataElement GetQueryLevel() const; +}; + +} // end namespace gdcm + +#endif //GDCMQUERYSTUDY_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmRoleSelectionSub.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmRoleSelectionSub.cxx new file mode 100644 index 0000000..d381401 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmRoleSelectionSub.cxx @@ -0,0 +1,154 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmRoleSelectionSub.h" +#include "gdcmFileMetaInformation.h" +#include "gdcmSwapper.h" + +namespace gdcm +{ +namespace network +{ +const uint8_t RoleSelectionSub::ItemType = 0x54; +const uint8_t RoleSelectionSub::Reserved2 = 0x00; + +RoleSelectionSub::RoleSelectionSub() +{ + ItemLength = 0; + UIDLength = 0; + SCURole = 0; + SCPRole = 0; + + ItemLength = (uint16_t)(Size() - 4); + assert( (size_t)ItemLength + 4 == Size() ); +} + +std::istream &RoleSelectionSub::Read(std::istream &is) +{ + //uint8_t itemtype = 0x0; + //is.read( (char*)&itemtype, sizeof(ItemType) ); + //assert( itemtype == ItemType ); + uint8_t reserved2; + is.read( (char*)&reserved2, sizeof(Reserved2) ); + uint16_t itemlength; + is.read( (char*)&itemlength, sizeof(ItemLength) ); + SwapperDoOp::SwapArray(&itemlength,1); + ItemLength = itemlength; + + uint16_t uidlength; + is.read( (char*)&uidlength, sizeof(UIDLength) ); + SwapperDoOp::SwapArray(&uidlength,1); + UIDLength = uidlength; + + char name[256]; + assert( uidlength < 256 ); + is.read( name, uidlength ); + Name = std::string(name,uidlength); + + uint8_t scurole; + is.read( (char*)&scurole, sizeof(SCURole) ); + SCURole = scurole; + + uint8_t scprole; + is.read( (char*)&scprole, sizeof(SCPRole) ); + SCPRole = scprole; + + assert( (size_t)ItemLength + 4 == Size() ); + + return is; +} + +const std::ostream &RoleSelectionSub::Write(std::ostream &os) const +{ + assert( (size_t)ItemLength + 4 == Size() ); + + os.write( (char*)&ItemType, sizeof(ItemType) ); + os.write( (char*)&Reserved2, sizeof(Reserved2) ); + //os.write( (char*)&ItemLength, sizeof(ItemLength) ); + uint16_t copy = ItemLength; + SwapperDoOp::SwapArray(©,1); + os.write( (char*)©, sizeof(ItemLength) ); + + assert( ItemLength > UIDLength ); + uint16_t uidlength = UIDLength; + SwapperDoOp::SwapArray(&uidlength,1); + os.write( (char*)&uidlength, sizeof(UIDLength) ); + + assert( (size_t)UIDLength == Name.size() ); + os.write( Name.c_str(), Name.size() ); + + uint8_t scurole = SCURole; + assert( scurole == 0 || scurole == 1 ); + os.write( (char*)&scurole, sizeof(SCURole) ); + + uint8_t scprole = SCPRole; + assert( scprole == 0 || scprole == 1 ); + os.write( (char*)&scprole, sizeof(SCPRole) ); + + return os; +} + +size_t RoleSelectionSub::Size() const +{ + size_t ret = 0; + ret += sizeof(ItemType); + ret += sizeof(Reserved2); + ret += sizeof(ItemLength); + ret += sizeof(UIDLength); + assert( Name.size() == UIDLength ); + ret += UIDLength; + ret += sizeof(SCURole); + ret += sizeof(SCPRole); + + return ret; +} + +/* +SCU-role This byte field shall contain the SCU-role as defined for the + Association-requester in Section D.3.3.4. It shall be encoded + as an unsigned binary and shall use one of the following + values: + 0 - non support of the SCU role + 1 - support of the SCU role + +SCP-role This byte field shall contain the SCP-role as defined for the + Association-requester in Section D.3.3.4. It shall be encoded + as an unsigned binary and shall use one of the following + values: + 0 - non support of the SCP role + 1 - support of the SCP role. +*/ +void RoleSelectionSub::SetTuple(const char *uid, uint8_t scurole, uint8_t scprole) +{ + if( uid ) + { + Name = uid; + UIDLength = (uint16_t)strlen( uid ); + assert( (size_t)UIDLength == Name.size() ); + SCURole = scurole % 2; + SCPRole = scprole % 2; + ItemLength = (uint16_t)(Size() - 4); + } + // post condition + assert( (size_t)ItemLength + 4 == Size() ); +} + +void RoleSelectionSub::Print(std::ostream &os) const +{ + os << "SOP-class-uid" << Name << std::endl; + os << "SCURole: " << (int)SCURole << std::endl; + os << "SCPRole: " << (int)SCPRole << std::endl; +} + +} // end namespace network +} // end namespace gdcm diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmRoleSelectionSub.h b/gdcm/Source/MessageExchangeDefinition/gdcmRoleSelectionSub.h new file mode 100644 index 0000000..de964aa --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmRoleSelectionSub.h @@ -0,0 +1,57 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMROLESELECTIONSUB_H +#define GDCMROLESELECTIONSUB_H + +#include "gdcmTypes.h" + +namespace gdcm +{ + +namespace network +{ + +/** + * \brief RoleSelectionSub + * PS 3.7 + * Table D.3-9 + * SCP/SCU ROLE SELECTION SUB-ITEM FIELDS (A-ASSOCIATE-RQ) + */ +class RoleSelectionSub +{ +public: + RoleSelectionSub(); + std::istream &Read(std::istream &is); + const std::ostream &Write(std::ostream &os) const; + + size_t Size() const; + void Print(std::ostream &os) const; + + void SetTuple(const char *uid, uint8_t scurole, uint8_t scprole); + +private: + static const uint8_t ItemType; + static const uint8_t Reserved2; + uint16_t ItemLength; + uint16_t UIDLength; + std::string /*SOP-class-uid*/ Name; // UID + uint8_t SCURole; + uint8_t SCPRole; +}; + +} // end namespace network + +} // end namespace gdcm + +#endif // GDCMROLESELECTIONSUB_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmSOPClassExtendedNegociationSub.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmSOPClassExtendedNegociationSub.cxx new file mode 100644 index 0000000..6193d0d --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmSOPClassExtendedNegociationSub.cxx @@ -0,0 +1,127 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmSOPClassExtendedNegociationSub.h" +#include "gdcmFileMetaInformation.h" +#include "gdcmSwapper.h" + +namespace gdcm +{ +namespace network +{ +const uint8_t SOPClassExtendedNegociationSub::ItemType = 0x56; +const uint8_t SOPClassExtendedNegociationSub::Reserved2 = 0x00; + +SOPClassExtendedNegociationSub::SOPClassExtendedNegociationSub() +{ + ItemLength = 0; + UIDLength = 0; + + ItemLength = (uint16_t)(Size() - 4); + assert( (size_t)ItemLength + 4 == Size() ); +} + +std::istream &SOPClassExtendedNegociationSub::Read(std::istream &is) +{ + //uint8_t itemtype = 0x0; + //is.read( (char*)&itemtype, sizeof(ItemType) ); + //assert( itemtype == ItemType ); + uint8_t reserved2; + is.read( (char*)&reserved2, sizeof(Reserved2) ); + uint16_t itemlength; + is.read( (char*)&itemlength, sizeof(ItemLength) ); + SwapperDoOp::SwapArray(&itemlength,1); + ItemLength = itemlength; + + uint16_t uidlength; + is.read( (char*)&uidlength, sizeof(UIDLength) ); + SwapperDoOp::SwapArray(&uidlength,1); + UIDLength = uidlength; + + char name[256]; + assert( uidlength < 256 ); + is.read( name, uidlength ); + Name = std::string(name,uidlength); + + assert( uidlength < ItemLength ); + uint16_t bloblength = (uint16_t)(ItemLength - 2 - uidlength); + assert( bloblength == 6 ); (void)bloblength; + SCAI.Read( is ); + + return is; +} + +const std::ostream &SOPClassExtendedNegociationSub::Write(std::ostream &os) const +{ + os.write( (char*)&ItemType, sizeof(ItemType) ); + os.write( (char*)&Reserved2, sizeof(Reserved2) ); + //os.write( (char*)&ItemLength, sizeof(ItemLength) ); + uint16_t copy = ItemLength; + SwapperDoOp::SwapArray(©,1); + os.write( (char*)©, sizeof(ItemLength) ); + + uint16_t uidlength = UIDLength; + SwapperDoOp::SwapArray(&uidlength,1); + os.write( (char*)&uidlength, sizeof(UIDLength) ); + + os.write( Name.c_str(), Name.size() ); + SCAI.Write( os ); + + return os; +} + +size_t SOPClassExtendedNegociationSub::Size() const +{ + size_t ret = 0; + ret += sizeof(ItemType); + ret += sizeof(Reserved2); + ret += sizeof(ItemLength); + ret += sizeof(UIDLength); + ret += UIDLength; + ret += SCAI.Size(); + + return ret; +} + +void SOPClassExtendedNegociationSub::Print(std::ostream &os) const +{ + os << "SOP-class-uid: " << Name << std::endl; // UID + os << "Service-class-application-information:"; + SCAI.Print( os ); +#if 0 + const char *beg = Blob.c_str(); + const char *end = beg + Blob.size(); + for( const char *p = beg; p != end; ++p ) + { + if ( p != beg ) os << " "; + os << "0x" << (int)*p; + } + os << "]" << std::endl; +#endif +} + +void SOPClassExtendedNegociationSub::SetTuple(const char *uid, uint8_t levelofsupport, uint8_t levelofdigitalsig, uint8_t elementcoercion) +{ + if( uid ) + { + Name = uid; + UIDLength = (uint16_t)strlen( uid ); + SCAI.SetTuple( levelofsupport, levelofdigitalsig, elementcoercion); + ItemLength = (uint16_t)(Size() - 4); + } + // post condition + assert( (size_t)ItemLength + 4 == Size() ); +} + +} // end namespace network +} // end namespace gdcm diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmSOPClassExtendedNegociationSub.h b/gdcm/Source/MessageExchangeDefinition/gdcmSOPClassExtendedNegociationSub.h new file mode 100644 index 0000000..fd2024d --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmSOPClassExtendedNegociationSub.h @@ -0,0 +1,58 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMSOPCLASSEXTENDEDNEGOCIATIONSUB_H +#define GDCMSOPCLASSEXTENDEDNEGOCIATIONSUB_H + +#include "gdcmServiceClassApplicationInformation.h" + +namespace gdcm +{ +namespace network +{ + +/** + * \brief SOPClassExtendedNegociationSub + * PS 3.7 + * Table D.3-11 + * SOP CLASS EXTENDED NEGOTIATION SUB-ITEM FIELDS + * (A-ASSOCIATE-RQ and A-ASSOCIATE-AC) + */ +class SOPClassExtendedNegociationSub +{ +public: + SOPClassExtendedNegociationSub(); + std::istream &Read(std::istream &is); + const std::ostream &Write(std::ostream &os) const; + + size_t Size() const; + void Print(std::ostream &os) const; + + void SetTuple(const char *uid, uint8_t levelofsupport = 3, + uint8_t levelofdigitalsig = 0, + uint8_t elementcoercion = 2); + +private: + static const uint8_t ItemType; + static const uint8_t Reserved2; + uint16_t ItemLength; + uint16_t UIDLength; + std::string /*SOP-class-uid*/ Name; // UID + ServiceClassApplicationInformation SCAI; +}; + +} // end namespace network + +} // end namespace gdcm + +#endif // GDCMSOPCLASSEXTENDEDNEGOCIATIONSUB_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmServiceClassApplicationInformation.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmServiceClassApplicationInformation.cxx new file mode 100644 index 0000000..303de42 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmServiceClassApplicationInformation.cxx @@ -0,0 +1,113 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmServiceClassApplicationInformation.h" + +namespace gdcm +{ +namespace network +{ + +ServiceClassApplicationInformation::ServiceClassApplicationInformation() +{ + InternalArray[0] = 3; // Level of Support + InternalArray[1] = 0; // Reserved + InternalArray[2] = 0; // Level of Digital Signature support + InternalArray[3] = 0; // Reserved + InternalArray[4] = 2; // Element coercion + InternalArray[5] = 0; // Reserved +} + +std::istream &ServiceClassApplicationInformation::Read(std::istream &is) +{ + is.read( (char*)InternalArray, sizeof(InternalArray) ); + return is; +} + +const std::ostream &ServiceClassApplicationInformation::Write(std::ostream &os) const +{ + assert( InternalArray[0] < 4 ); + assert( InternalArray[1] == 0 ); + assert( InternalArray[2] < 4 ); + assert( InternalArray[3] == 0 ); + assert( InternalArray[4] < 3 ); + assert( InternalArray[5] == 0 ); + os.write( (char*)InternalArray, sizeof(InternalArray) ); + return os; +} + +size_t ServiceClassApplicationInformation::Size() const +{ + assert( sizeof(InternalArray) == 6 ); + return 6; +} + +void ServiceClassApplicationInformation::Print(std::ostream &os) const +{ + os << "ServiceClassApplicationInformation: " << std::endl; + os << " Level of Support: " << (int)InternalArray[0] << std::endl; + os << " Level of Digital Signature support: " << (int)InternalArray[2] << std::endl; + os << " Element coercion: " << (int)InternalArray[4] << std::endl; +} + +/* +Level of support This byte field defines the supported storage level of the + Association-acceptor. It shall be encoded as an + unsigned binary integer and shall use one of the + following values: + 0 - level 0 SCP + 1 - level 1 SCP + 2 - level 2 SCP + 3 - N/A - Association-acceptor is SCU only + If extended negotiation is not supported, no + assumptions shall be made by the Association- + requester about the capabilities of the Association- + acceptor based upon this extended negotiation. + + Level of Digital A Level 2 SCP may further define its behavior in this +Signature support byte field. + 0 – The signature level is unspecified, the AE is an + SCU only, or the AE is not a level 2 SCP + 1 – signature level 1 + 2 – signature level 2 + 3 – signature level 3 + If extended negotiation is not supported, no + assumptions shall be made by the Association- + requester about the capabilities of the Association- + acceptor based upon this extended negotiation. + +Element Coercion This byte field defines whether the Association-acceptor + may coerce Data Elements. It shall be encoded as an + unsigned binary integer and shall use one of the + following values: + 0 - does not coerce any Data Element + 1 - may coerce Data Elements + 2 - N/A - Association-acceptor is SCU only + If extended negotiation is not supported, no + assumptions shall be made by the Association- + requester about the capabilities of the Association- + acceptor based upon this extended negotiation. +*/ + +void ServiceClassApplicationInformation::SetTuple(uint8_t levelofsupport, uint8_t levelofdigitalsig, uint8_t elementcoercion) +{ + if( levelofsupport < 4 ) + InternalArray[0] = levelofsupport; + if( levelofdigitalsig < 4 ) + InternalArray[2] = levelofdigitalsig; + if( elementcoercion < 3 ) + InternalArray[4] = elementcoercion; +} + +} // end namespace network +} // end namespace gdcm diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmServiceClassApplicationInformation.h b/gdcm/Source/MessageExchangeDefinition/gdcmServiceClassApplicationInformation.h new file mode 100644 index 0000000..bd8dcb9 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmServiceClassApplicationInformation.h @@ -0,0 +1,50 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMSERVICECLASSAPPLICATIONINFORMATION_H +#define GDCMSERVICECLASSAPPLICATIONINFORMATION_H + +#include "gdcmTypes.h" + +namespace gdcm +{ + +namespace network +{ + +/** + * PS 3.4 + * Table B.3-1 + * SERVICE-CLASS-APPLICATION-INFORMATION (A-ASSOCIATE-RQ) + */ +class ServiceClassApplicationInformation +{ +public: + ServiceClassApplicationInformation(); + std::istream &Read(std::istream &is); + const std::ostream &Write(std::ostream &os) const; + + size_t Size() const; + void SetTuple(uint8_t levelofsupport, uint8_t levelofdigitalsig, + uint8_t elementcoercion); + + void Print(std::ostream &os) const; +private: + uint8_t InternalArray[6]; +}; + +} // end namespace network + +} // end namespace gdcm + +#endif //GDCMSERVICECLASSAPPLICATIONINFORMATION_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmServiceClassUser.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmServiceClassUser.cxx new file mode 100644 index 0000000..2be14ac --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmServiceClassUser.cxx @@ -0,0 +1,1076 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmServiceClassUser.h" + +#include "gdcmULTransitionTable.h" +#include "gdcmULConnection.h" +#include "gdcmULConnectionInfo.h" +#include "gdcmPresentationContextAC.h" +#include "gdcmPresentationDataValue.h" +#include "gdcmULConnectionCallback.h" +#include "gdcmULBasicCallback.h" +#include "gdcmPDUFactory.h" +#include "gdcmAttribute.h" +#include "gdcmULWritingCallback.h" + +#include "gdcmPrinter.h" // FIXME +#include "gdcmReader.h" // FIXME + +namespace gdcm +{ +static const char GDCM_AETITLE[] = "GDCMSCU"; + +using namespace network; +class ServiceClassUserInternals +{ +public: + ULConnection* mConnection; + ULConnection* mSecondaryConnection; + ULTransitionTable mTransitions; + + std::string hostname; + int port; + int portscp; + std::string aetitle; + std::string calledaetitle; + double timeout; + + ServiceClassUserInternals():mConnection(NULL),mSecondaryConnection(NULL){} + ~ServiceClassUserInternals(){ + delete mConnection; + delete mSecondaryConnection; + } +}; + +ServiceClassUser::ServiceClassUser() +{ + Internals = new ServiceClassUserInternals; + Internals->hostname = "localhost"; + Internals->port = 104; + Internals->portscp = 104; + Internals->aetitle = GDCM_AETITLE; + Internals->calledaetitle = "ANY-SCP"; + Internals->timeout = 10; +} + +ServiceClassUser::~ServiceClassUser() +{ + delete Internals; +} + +void ServiceClassUser::SetPresentationContexts(std::vector const & pcs) +{ + if( Internals->mConnection ) + { + Internals->mConnection->SetPresentationContexts(pcs); + } +} + +bool ServiceClassUser::IsPresentationContextAccepted(const PresentationContext& pc) const +{ + bool found = false; + const std::vector &acceptedContexts = + Internals->mConnection->GetAcceptedPresentationContexts(); + std::vector::const_iterator itor; + uint8_t contextID = pc.GetPresentationContextID(); + + for (itor = acceptedContexts.begin(); + itor != acceptedContexts.end() && !found; + itor++) + { + if (contextID == itor->GetPresentationContextID()) + found = true; + } + + return found; +} + +bool ServiceClassUser::InitializeConnection() +{ + UserInformation userInfo; + ULConnectionInfo connectInfo; + if (Internals->aetitle.size() > 16) + { + return false; + } + if (Internals->calledaetitle.size() > 16) + { + return false; + } + if (!Internals->port) + { + return false; + } + if (Internals->hostname.empty()) + { + return false; + } + if (!connectInfo.Initialize(userInfo, Internals->calledaetitle.c_str(), + Internals->aetitle.c_str(), 0, Internals->port, Internals->hostname)) + { + return false; + } + + ULConnection* mConnection = Internals->mConnection; + if (mConnection) + { + delete mConnection; + } + Internals->mConnection = new ULConnection(connectInfo); + Internals->mConnection->GetTimer().SetTimeout(Internals->timeout); + + return true; +} + +bool ServiceClassUser::StartAssociation() +{ + // need to make sure no cached PresContAC are around: + Internals->mConnection->GetAcceptedPresentationContexts().clear(); + if( Internals->mConnection->GetPresentationContexts().empty() ) + { + return false; + } + + ULEvent theEvent(eAASSOCIATERequestLocalUser, NULL); + network::EStateID theState = RunEventLoop(theEvent, Internals->mConnection, NULL, false); + if(theState != eSta6TransferReady) + { + std::vector const & thePDUs = theEvent.GetPDUs(); + for( std::vector::const_iterator itor + = thePDUs.begin(); itor != thePDUs.end(); itor++) + { + assert(*itor); + if (*itor == NULL) continue; //can have a nulled pdu, apparently + (*itor)->Print(Trace::GetErrorStream()); + } + } + + return theState == eSta6TransferReady; +} + +bool ServiceClassUser::StopAssociation() +{ + ULConnection* mConnection = Internals->mConnection; + + BasePDU* thePDU = PDUFactory::ConstructReleasePDU(); + ULEvent theEvent(eARELEASERequest, thePDU); + EStateID theState = RunEventLoop(theEvent, mConnection, NULL, false); + + return theState == eSta1Idle; +} + +void ServiceClassUser::SetTimeout(double t) +{ + Internals->timeout = t; +} + +double ServiceClassUser::GetTimeout() const +{ + return Internals->timeout; +} + +void ServiceClassUser::SetCalledAETitle(const char *aetitle) +{ + if( aetitle ) + Internals->calledaetitle = aetitle; +} + +void ServiceClassUser::SetAETitle(const char *aetitle) +{ + if( aetitle ) + Internals->aetitle = aetitle; +} + +const char *ServiceClassUser::GetCalledAETitle() const +{ + return Internals->calledaetitle.c_str(); +} + +const char *ServiceClassUser::GetAETitle() const +{ + return Internals->aetitle.c_str(); +} + +void ServiceClassUser::SetHostname( const char *hostname ) +{ + if( hostname ) + Internals->hostname = hostname; +} + +void ServiceClassUser::SetPort( uint16_t port ) +{ + Internals->port = port; +} + +void ServiceClassUser::SetPortSCP( uint16_t portscp ) +{ + Internals->portscp = portscp; +} + +bool ServiceClassUser::SendEcho() +{ + ULConnection* mConnection = Internals->mConnection; + std::vector theDataPDU = PDUFactory::CreateCEchoPDU(*mConnection); + ULEvent theEvent(ePDATArequest, theDataPDU); + + EStateID theState = RunEventLoop(theEvent, mConnection, NULL, false); + + return theState == eSta6TransferReady; +} + +bool ServiceClassUser::SendStore(const char *filename) +{ + if( !filename ) return false; + Reader reader; + reader.SetFileName( filename ); + bool b = reader.Read(); + if( !b ) + { + gdcmDebugMacro( "Could not read: " << filename ); + return false; + } + const File & file = reader.GetFile(); + return SendStore( file ); +} + +bool ServiceClassUser::SendStore(DataSet const &ds) +{ + SmartPointer file = new File; + file->SetDataSet( ds ); + file->GetHeader().SetDataSetTransferSyntax( TransferSyntax::ImplicitVRLittleEndian ); + file->GetHeader().FillFromDataSet( ds ); + return SendStore(*file); +} + +bool ServiceClassUser::SendStore(File const &file) +{ + ULConnection* mConnection = Internals->mConnection; + + std::vector theDataPDU; + try + { + theDataPDU = PDUFactory::CreateCStoreRQPDU(*mConnection, file); + } + catch ( std::exception &ex ) + { + (void)ex; //to avoid unreferenced variable warning on release + gdcmErrorMacro( "Could not C-STORE: " << ex.what() ); + return false; + } + + network::ULBasicCallback theCallback; + network::ULConnectionCallback* inCallback = &theCallback; + + ULEvent theEvent(ePDATArequest, theDataPDU); + EStateID stateid = RunEventLoop(theEvent, mConnection, inCallback, false); + assert( stateid == eSta6TransferReady ); (void)stateid; + std::vector const &theDataSets = theCallback.GetResponses(); + + bool ret = true; + assert( theDataSets.size() == 1 ); + const DataSet &ds = theDataSets[0]; + assert ( ds.FindDataElement(Tag(0x0, 0x0900)) ); + DataElement const & de = ds.GetDataElement(Tag(0x0,0x0900)); + Attribute<0x0,0x0900> at; + at.SetFromDataElement( de ); + // PS 3.4 - 2011 + // Table W.4-1 C-STORE RESPONSE STATUS VALUES + const uint16_t theVal = at.GetValue(); + switch( theVal ) + { + case 0x0: + gdcmDebugMacro( "C-Store of file was successful." ); + break; + case 0xA700: + case 0xA900: + case 0xC000: + { + // TODO: value from 0901 ? + gdcmErrorMacro( "C-Store of file was a failure." ); + Attribute<0x0,0x0902> errormsg; + errormsg.SetFromDataSet( ds ); + const char *themsg = errormsg.GetValue(); + assert( themsg ); (void)themsg; + gdcmErrorMacro( "Response Status: " << themsg ); + ret = false; // at least one file was not sent correctly + } + break; + default: + gdcmErrorMacro( "Unhandle error code: " << theVal ); + gdcmAssertAlwaysMacro( 0 ); + } + + return ret; +} + +bool ServiceClassUser::SendFind(const BaseRootQuery* query, std::vector &retDataSets) +{ + ULConnection* mConnection = Internals->mConnection; + network::ULBasicCallback theCallback; + network::ULConnectionCallback* inCallback = &theCallback; + + std::vector theDataPDU = PDUFactory::CreateCFindPDU( *mConnection, query); + ULEvent theEvent(ePDATArequest, theDataPDU); + RunEventLoop(theEvent, mConnection, inCallback, false); + + std::vector const & theDataSets = theCallback.GetDataSets(); + std::vector const & theResponses = theCallback.GetResponses(); + + bool ret = false; // by default an error + assert( theResponses.size() >= 1 ); + // take the last one: + const DataSet &ds = theResponses[ theResponses.size() - 1 ]; // FIXME + assert ( ds.FindDataElement(Tag(0x0, 0x0900)) ); + Attribute<0x0,0x0900> at; + at.SetFromDataSet( ds ); + + // Table CC.2.8-2 + //C-FIND RESPONSE STATUS VALUES + const uint16_t theVal = at.GetValue(); + switch( theVal ) + { + case 0x0: // Matching is complete - No final Identifier is supplied. + gdcmDebugMacro( "C-Find was successful." ); + // Append the new DataSet to the ret one: + retDataSets.insert( retDataSets.end(), theDataSets.begin(), theDataSets.end() ); + ret = true; + break; + case 0xA900: // Identifier Does Not Match SOP Class + { + Attribute<0x0,0x0901> errormsg; + if( ds.FindDataElement( errormsg.GetTag() ) ) + { + errormsg.SetFromDataSet( ds ); + gdcm::Tag const & t = errormsg.GetValue(); + gdcmErrorMacro( "Offending Element: " << t ); (void)t; + } + else + { + gdcmErrorMacro( "Offending Element ??" ); + } + } + break; + case 0xA700: // Refused: Out of Resources + { + Attribute<0x0,0x0902> errormsg; + errormsg.SetFromDataSet( ds ); + const char *themsg = errormsg.GetValue(); + assert( themsg ); (void)themsg; + gdcmErrorMacro( "Response Status: [" << themsg << "]" ); + } + break; + case 0x0122: // SOP Class not Supported + gdcmErrorMacro( "SOP Class not Supported" ); + break; + case 0xfe00: // Matching terminated due to Cancel request + gdcmErrorMacro( "Matching terminated due to Cancel request" ); + break; + default: + { + if( theVal >= 0xC000 && theVal <= 0xCFFF ) // Unable to process + { + Attribute<0x0,0x0902> errormsg; + errormsg.SetFromDataSet( ds ); + const char *themsg = errormsg.GetValue(); + assert( themsg ); (void)themsg; + gdcmErrorMacro( "Response Status: " << themsg ); + } + } + } + + return ret; +} + +bool ServiceClassUser::SendMove(const BaseRootQuery* query, const char *outputdir) +{ + UserInformation userInfo2; + ULConnectionInfo connectInfo2; + if (!connectInfo2.Initialize(userInfo2, Internals->aetitle.c_str(), + Internals->calledaetitle.c_str(), 0, Internals->portscp, Internals->hostname)) + { + return false; + } + + // let's start the secondary connection + ULConnection* mSecondaryConnection = Internals->mSecondaryConnection; + if (mSecondaryConnection) + { + delete mSecondaryConnection; + } + Internals->mSecondaryConnection = new ULConnection(connectInfo2); + Internals->mSecondaryConnection->GetTimer().SetTimeout(Internals->timeout); + + ULConnection* mConnection = Internals->mConnection; + network::ULWritingCallback theCallback; + theCallback.SetDirectory(outputdir); + network::ULConnectionCallback* inCallback = &theCallback; + + std::vector theDataPDU = PDUFactory::CreateCMovePDU( *mConnection, query ); + ULEvent theEvent(ePDATArequest, theDataPDU); + EStateID stateid = RunMoveEventLoop(theEvent, inCallback); + if( stateid != gdcm::network::eSta6TransferReady ) + { + return false; + } + + return true; +} + +bool ServiceClassUser::SendMove(const BaseRootQuery* query, std::vector &retDataSets) +{ + UserInformation userInfo2; + ULConnectionInfo connectInfo2; + if (!connectInfo2.Initialize(userInfo2, Internals->aetitle.c_str(), + Internals->calledaetitle.c_str(), 0, Internals->portscp, Internals->hostname)) + { + return false; + } + + // let's start the secondary connection + ULConnection* mSecondaryConnection = Internals->mSecondaryConnection; + if (mSecondaryConnection) + { + delete mSecondaryConnection; + } + Internals->mSecondaryConnection = new ULConnection(connectInfo2); + Internals->mSecondaryConnection->GetTimer().SetTimeout(Internals->timeout); + + ULConnection* mConnection = Internals->mConnection; + network::ULBasicCallback theCallback; + network::ULConnectionCallback* inCallback = &theCallback; + + std::vector theDataPDU = PDUFactory::CreateCMovePDU( *mConnection, query ); + ULEvent theEvent(ePDATArequest, theDataPDU); + EStateID stateid = RunMoveEventLoop(theEvent, inCallback); + if( stateid != gdcm::network::eSta6TransferReady ) + { + return false; + } + + std::vector const & theDataSets = theCallback.GetDataSets(); + retDataSets.insert( retDataSets.end(), theDataSets.begin(), theDataSets.end() ); + + return true; +} + +bool ServiceClassUser::SendMove(const BaseRootQuery* query, std::vector &retFiles) +{ + (void)query; + (void)retFiles; + assert( 0 && "unimplemented do not use" ); + return false; +} + +//event handler loop. +//will just keep running until the current event is nonexistent. +//at which point, it will return the current state of the connection +//to do this, execute an event, and then see if there's a response on the +//incoming connection (with a reasonable amount of timeout). +//if no response, assume that the connection is broken. +//if there's a response, then yay. +//note that this is the ARTIM timeout event +EStateID ServiceClassUser::RunEventLoop(network::ULEvent& currentEvent, + network::ULConnection* inWhichConnection, + network::ULConnectionCallback* inCallback, + const bool& startWaiting = false) +{ + EStateID theState = eStaDoesNotExist; + bool waitingForEvent = startWaiting;//overwritten if not starting waiting, but if waiting, then wait + EEventID raisedEvent; + + bool receivingData = false; + //bool justWaiting = startWaiting; + //not sure justwaiting is useful; for now, go back to waiting for event + + //when receiving data from a find, etc, then justWaiting is true and only receiving is done + //eventually, could add cancel into the mix... but that would be through a callback or something similar + do { + raisedEvent = eEventDoesNotExist; + if (!waitingForEvent){//justWaiting){ + Internals->mTransitions.HandleEvent(this, currentEvent, *inWhichConnection, waitingForEvent, raisedEvent); + //this gathering of the state is for scus that have just sent out a request + theState = inWhichConnection->GetState(); + } + std::istream &is = *inWhichConnection->GetProtocol(); + //std::ostream &os = *inWhichConnection->GetProtocol(); + + BasePDU* theFirstPDU = NULL;// the first pdu read in during this event loop, + //used to make sure the presentation context ID is correct + + //read the connection, as that's an event as well. + //waiting for an object to come back across the connection, so that it can get handled. + //ie, accept, reject, timeout, etc. + //of course, if the connection is down, just leave the loop. + //also leave the loop if nothing's waiting. + //use the PDUFactory to create the appropriate pdu, which has its own + //internal mechanisms for handling itself (but will, of course, be put inside the event object). + //but, and here's the important thing, only read on the socket when we should. + std::vector incomingPDUs; + if (waitingForEvent){ + while (waitingForEvent){//loop for reading in the events that come down the wire + uint8_t itemtype = 0x0; + try { + is.read( (char*)&itemtype, 1 ); + //what happens if nothing's read? + theFirstPDU = PDUFactory::ConstructPDU(itemtype); + if (theFirstPDU != NULL){ + incomingPDUs.push_back(theFirstPDU); + theFirstPDU->Read(is); + gdcmDebugMacro("PDU code: " << static_cast(itemtype) << std::endl); + if (Trace::GetDebugFlag()) + { + theFirstPDU->Print(Trace::GetStream()); + } + + if (theFirstPDU->IsLastFragment()) waitingForEvent = false; + } else { + waitingForEvent = false; //because no PDU means not waiting anymore + } + } + catch (...) + { + //handle the exception, which is basically that nothing came in over the pipe. + assert( 0 ); + } + } + //now, we have to figure out the event that just happened based on the PDU that was received. + //this state gathering is for scps, especially the cstore for cmove. + theState = inWhichConnection->GetState(); + if (!incomingPDUs.empty()){ + currentEvent.SetEvent(PDUFactory::DetermineEventByPDU(incomingPDUs[0])); + currentEvent.SetPDU(incomingPDUs); + //here's the scp handling code + if (Internals->mConnection->GetTimer().GetHasExpired()){ + currentEvent.SetEvent(eARTIMTimerExpired); + } + switch(currentEvent.GetEvent()){ + case ePDATATFPDU: + { + //if (theState == eSta6TransferReady){//ie, finished the transitions + //with find, the results now come down the wire. + //the pdu we already have from the event will tell us how many to expect. + uint32_t pendingDE1, pendingDE2, success, theVal; + pendingDE1 = 0xff01; + pendingDE2 = 0xff00; + success = 0x0000; + theVal = pendingDE1; + uint32_t theCommandCode = 0;//for now, a nothing value + DataSet theRSP = + PresentationDataValue::ConcatenatePDVBlobs( + PDUFactory::GetPDVs(currentEvent.GetPDUs())); + if (inCallback) + { + inCallback->HandleResponse(theRSP); + } + + if (theRSP.FindDataElement(Tag(0x0, 0x0900))){ + DataElement de = theRSP.GetDataElement(Tag(0x0,0x0900)); + Attribute<0x0,0x0900> at; + at.SetFromDataElement( de ); + theVal = at.GetValues()[0]; + //if theVal is Pending or Success, then we need to enter the loop below, + //because we need the data PDUs. + //so, the loop below is a do/while loop; there should be at least a second packet + //with the dataset, even if the status is 'success' + //success == 0000H + } + if (Trace::GetDebugFlag()) + { + Printer thePrinter; + thePrinter.PrintDataSet(theRSP, Trace::GetStream()); + } + + //check to see if this is a cstorerq + if (theRSP.FindDataElement(Tag(0x0, 0x0100))) + { + DataElement de2 = theRSP.GetDataElement(Tag(0x0,0x0100)); + Attribute<0x0,0x0100> at2; + at2.SetFromDataElement( de2 ); + theCommandCode = at2.GetValues()[0]; + } + + if (theVal != pendingDE1 && theVal != pendingDE2 && theVal != success) + { + //check for other error fields + const ByteValue *err1 = NULL, *err2 = NULL; + gdcmErrorMacro( "Transfer failed with code " << theVal << std::endl); + switch (theVal){ + case 0xA701: + gdcmErrorMacro( "Refused: Out of Resources Unable to calculate number of matches" << std::endl); + break; + case 0xA702: + gdcmErrorMacro( "Refused: Out of Resources Unable to perform sub-operations" << std::endl); + break; + case 0xA801: + gdcmErrorMacro( "Refused: Move Destination unknown" << std::endl); + break; + case 0xA900: + gdcmErrorMacro( "Identifier does not match SOP Class" << std::endl); + break; + case 0xAA00: + gdcmErrorMacro( "None of the frames requested were found in the SOP Instance" << std::endl); + break; + case 0xAA01: + gdcmErrorMacro( "Unable to create new object for this SOP class" << std::endl); + break; + case 0xAA02: + gdcmErrorMacro( "Unable to extract frames" << std::endl); + break; + case 0xAA03: + gdcmErrorMacro( "Time-based request received for a non-time-based original SOP Instance. " << std::endl); + break; + case 0xAA04: + gdcmErrorMacro( "Invalid Request" << std::endl); + break; + case 0xFE00: + gdcmErrorMacro( "Sub-operations terminated due to Cancel Indication" << std::endl); + break; + case 0xB000: + gdcmErrorMacro( "Sub-operations Complete One or more Failures or Warnings" << std::endl); + break; + default: + gdcmErrorMacro( "Unable to process" << std::endl); + break; + } + if (theRSP.FindDataElement(Tag(0x0,0x0901))){ + DataElement de = theRSP.GetDataElement(Tag(0x0,0x0901)); + err1 = de.GetByteValue(); + gdcmErrorMacro( " Tag 0x0,0x901 reported as " << *err1 << std::endl); (void)err1; + } + if (theRSP.FindDataElement(Tag(0x0,0x0902))){ + DataElement de = theRSP.GetDataElement(Tag(0x0,0x0902)); + err2 = de.GetByteValue(); + gdcmErrorMacro( " Tag 0x0,0x902 reported as " << *err2 << std::endl); (void)err2; + } + } + + receivingData = false; + //justWaiting = false; + if (theVal == pendingDE1 || theVal == pendingDE2) { + receivingData = true; //wait for more data as more PDUs (findrsps, for instance) + //justWaiting = true; + waitingForEvent = true; + } + if (theVal == pendingDE1 || theVal == pendingDE2 /*|| theVal == success*/){//keep looping if we haven't succeeded or failed; these are the values for 'pending' + //first, dynamically cast that pdu in the event + //should be a data pdu + //then, look for tag 0x0,0x900 + + //only add datasets that are _not_ part of the network response + std::vector final; + std::vector theData; + BasePDU* thePDU;//outside the loop for the do/while stopping condition + bool interrupted = false; + do { + uint8_t itemtype = 0x0; + is.read( (char*)&itemtype, 1 ); + //what happens if nothing's read? + thePDU = PDUFactory::ConstructPDU(itemtype); + if (itemtype != 0x4 && thePDU != NULL){ //ie, not a pdatapdu + std::vector interruptingPDUs; + interruptingPDUs.push_back(thePDU); + currentEvent.SetEvent(PDUFactory::DetermineEventByPDU(interruptingPDUs[0])); + currentEvent.SetPDU(interruptingPDUs); + interrupted= true; + break; + } + if (thePDU != NULL){ + // FIXME: How do I find out how many PData we are receiving ? + // This is needed for proper progress report + thePDU->Read(is); + theData.push_back(thePDU); + } else{ + break; + } + //!!!need to handle incoming PDUs that are not data, ie, an abort + } while(!thePDU->IsLastFragment()); + if (!interrupted){//ie, if the remote server didn't hang up + DataSet theCompleteFindResponse = + PresentationDataValue::ConcatenatePDVBlobs(PDUFactory::GetPDVs(theData)); + //note that it's the responsibility of the event to delete the PDU in theFindRSP + for (size_t i = 0; i < theData.size(); i++) + { + delete theData[i]; + } + //outDataSet.push_back(theCompleteFindResponse); + if (inCallback) + { + inCallback->HandleDataSet(theCompleteFindResponse); + } + // DataSetEvent dse( &theCompleteFindResponse ); + // this->InvokeEvent( dse ); + + + if (theCommandCode == 1){//if we're doing cstore scp stuff, send information back along the connection. + std::vector theCStoreRSPPDU = PDUFactory::CreateCStoreRSPPDU(&theRSP, theFirstPDU);//pass NULL for C-Echo + //send them directly back over the connection + //ideall, should go through the transition table, but we know this should work + //and it won't change the state (unless something breaks?, but then an exception should throw) + std::vector::iterator itor; + for (itor = theCStoreRSPPDU.begin(); itor < theCStoreRSPPDU.end(); itor++){ + (*itor)->Write(*inWhichConnection->GetProtocol()); + } + + inWhichConnection->GetProtocol()->flush(); + + // FIXME added MM / Oct 30 2010 + //AReleaseRPPDU rel; + //rel.Write( *inWhichConnection->GetProtocol() ); + //inWhichConnection->GetProtocol()->flush(); + + receivingData = false; //gotta get data on the other connection for a cmove + } + } + } + } + break; + case eARELEASERequest://process this via the transition table + waitingForEvent = false; + break; + case eARELEASE_RQPDUReceivedOpen://process this via the transition table + waitingForEvent = false; + receivingData = true; //to continue the loop to process the release + break; + case eAABORTRequest: + waitingForEvent = false; + inWhichConnection->StopProtocol(); + break; + case eASSOCIATE_ACPDUreceived: + default: + waitingForEvent = false; + break; + } + } + //} else { + // raisedEvent = eEventDoesNotExist; + // waitingForEvent = false; + //} + } + else { + currentEvent.SetEvent(raisedEvent);//actions that cause transitions in the state table + //locally just raise local events that will therefore cause the trigger to be pulled. + } + } while (currentEvent.GetEvent() != eEventDoesNotExist && + theState != eStaDoesNotExist && theState != eSta13AwaitingClose && theState != eSta1Idle && + (theState != eSta6TransferReady || (theState == eSta6TransferReady && receivingData ))); + //stop when the AE is done, or when ready to transfer data (ie, the next PDU should be sent in), + //or when the connection is idle after a disconnection. + //or, if in state 6 and receiving data, until all data is received. + + return theState; +} + +EStateID ServiceClassUser::RunMoveEventLoop(ULEvent& currentEvent, ULConnectionCallback* inCallback){ + EStateID theState = eStaDoesNotExist; + bool waitingForEvent; + EEventID raisedEvent; + + bool receivingData = false; + bool justWaiting = false; + //when receiving data from a find, etc, then justWaiting is true and only receiving is done + //eventually, could add cancel into the mix... but that would be through a callback or something similar + do { + if (!justWaiting){ + Internals->mTransitions.HandleEvent(this,currentEvent, *Internals->mConnection, waitingForEvent, raisedEvent); + } + + theState = Internals->mConnection->GetState(); + std::istream &is = *Internals->mConnection->GetProtocol(); + //std::ostream &os = *mConnection->GetProtocol(); + + + //When doing a C-MOVE we receive the Requested DataSet over + //another channel (technically this is send to an SCP) + //in our case we use another port to receive it. + EStateID theCStoreStateID = eSta6TransferReady; + bool secondConnectionEstablished = false; + if (Internals->mSecondaryConnection->GetProtocol() == NULL){ + //establish the connection + //can fail if is_readready doesn't return true, ie, the connection + //wasn't opened on the other side because the other side isn't sending data yet + //for whatever reason (maybe there's nothing to get?) + try + { + secondConnectionEstablished = + Internals->mSecondaryConnection->InitializeIncomingConnection(); + } + catch ( std::exception & e ) + { + gdcmErrorMacro( "Error 2nd connection:" << e.what() ); + } + catch ( ... ) + { + assert( 0 ); + } + } + if (secondConnectionEstablished && + (Internals->mSecondaryConnection->GetState()== eSta1Idle || + Internals->mSecondaryConnection->GetState() == eSta2Open)){ + ULEvent theCStoreEvent(eEventDoesNotExist, NULL);//have to fill this in, we're in passive mode now + theCStoreStateID = RunEventLoop(theCStoreEvent, Internals->mSecondaryConnection, inCallback, true); + } + + //just as for the regular event loop, but we have to alternate between the connections. + //it may be that nothing comes back over the is connection, but lots over the + //isSCP connection. So, if is fails, meh. But if isSCP fails, that's not so meh. + //we care only about the datasets coming back from isSCP, ultimately, though the datasets + //from is will contain progress info. + std::vector incomingPDUs; + if (waitingForEvent){ + while (waitingForEvent) + {//loop for reading in the events that come down the wire + uint8_t itemtype = 0x0; + is.read( (char*)&itemtype, 1 ); + + BasePDU* thePDU = PDUFactory::ConstructPDU(itemtype); + if (thePDU != NULL) + { + incomingPDUs.push_back(thePDU); + thePDU->Read(is); + gdcmDebugMacro("PDU code: " << static_cast(itemtype) << std::endl); + if (Trace::GetDebugFlag()) + { + thePDU->Print(Trace::GetStream()); + } + if (thePDU->IsLastFragment()) waitingForEvent = false; + } + else + { + waitingForEvent = false; //because no PDU means not waiting anymore + } + } + //now, we have to figure out the event that just happened based on the PDU that was received. + if (!incomingPDUs.empty()) + { + currentEvent.SetEvent(PDUFactory::DetermineEventByPDU(incomingPDUs[0])); + currentEvent.SetPDU(incomingPDUs); + if (Internals->mConnection->GetTimer().GetHasExpired()) + { + currentEvent.SetEvent(eARTIMTimerExpired); + } + if (theState == eSta6TransferReady){//ie, finished the transitions + //with find, the results now come down the wire. + //the pdu we already have from the event will tell us how many to expect. + uint32_t pendingDE1, pendingDE2, success, theVal; + pendingDE1 = 0xff01; + pendingDE2 = 0xff00; + success = 0x0000; + theVal = pendingDE1; + uint32_t theNumLeft = 0; // the number of pending sub operations left. + //so here's the thing: dcmtk responds with 'success' as it first cmove rsp + //which is retarded and, I think, wrong. However, dcm4chee responds with 'pending' + //so, we look either for pending, or for the number of operations left + // (tag 0000, 1020) if the value is success, and that number should be 0. + DataSet theRSP = PresentationDataValue::ConcatenatePDVBlobs(PDUFactory::GetPDVs(currentEvent.GetPDUs())); + if (Trace::GetDebugFlag()){ + Printer thePrinter; + thePrinter.PrintDataSet(theRSP, Trace::GetStream()); + } + if (theRSP.FindDataElement(Tag(0x0, 0x0900))){ + DataElement de = theRSP.GetDataElement(Tag(0x0,0x0900)); + Attribute<0x0,0x0900> at; + at.SetFromDataElement( de ); + theVal = at.GetValues()[0]; + //if theVal is Pending or Success, then we need to enter the loop below, + //because we need the data PDUs. + //so, the loop below is a do/while loop; there should be at least a second packet + //with the dataset, even if the status is 'success' + //success == 0000H + } + uint32_t theCommandCode = 0; + if (theRSP.FindDataElement(Tag(0x0,0x0100))){ + DataElement de = theRSP.GetDataElement(Tag(0x0,0x0100)); + Attribute<0x0,0x0100> at; + at.SetFromDataElement( de ); + theCommandCode = at.GetValues()[0]; + } + if (theRSP.FindDataElement(Tag(0x0, 0x1020))){ + DataElement de = theRSP.GetDataElement(Tag(0x0,0x1020)); + Attribute<0x0,0x1020> at; + at.SetFromDataElement( de ); + theNumLeft = at.GetValues()[0]; + //if theVal is Pending or Success, then we need to enter the loop below, + //because we need the data PDUs. + //so, the loop below is a do/while loop; there should be at least a second packet + //with the dataset, even if the status is 'success' + //success == 0000H + } + if (theVal != pendingDE1 && theVal != pendingDE2 && theVal != success){ + //check for other error fields + const ByteValue *err1 = NULL, *err2 = NULL; + gdcmErrorMacro( "Transfer failed with code " << theVal << std::endl); + switch (theVal){ + case 0xA701: + gdcmErrorMacro( "Refused: Out of Resources Unable to calculate number of matches" << std::endl); + break; + case 0xA702: + gdcmErrorMacro( "Refused: Out of Resources Unable to perform sub-operations" << std::endl); + break; + case 0xA801: + gdcmErrorMacro( "Refused: Move Destination unknown" << std::endl); + break; + case 0xA900: + gdcmErrorMacro( "Identifier does not match SOP Class" << std::endl); + break; + case 0xAA00: + gdcmErrorMacro( "None of the frames requested were found in the SOP Instance" << std::endl); + break; + case 0xAA01: + gdcmErrorMacro( "Unable to create new object for this SOP class" << std::endl); + break; + case 0xAA02: + gdcmErrorMacro( "Unable to extract frames" << std::endl); + break; + case 0xAA03: + gdcmErrorMacro( "Time-based request received for a non-time-based original SOP Instance. " << std::endl); + break; + case 0xAA04: + gdcmErrorMacro( "Invalid Request" << std::endl); + break; + case 0xFE00: + gdcmErrorMacro( "Sub-operations terminated due to Cancel Indication" << std::endl); + break; + case 0xB000: + gdcmErrorMacro( "Sub-operations Complete One or more Failures or Warnings" << std::endl); + break; + default: + gdcmErrorMacro( "Unable to process" << std::endl); + break; + } + if (theRSP.FindDataElement(Tag(0x0,0x0901))){ + DataElement de = theRSP.GetDataElement(Tag(0x0,0x0901)); + err1 = de.GetByteValue(); + gdcmErrorMacro( " Tag 0x0,0x901 reported as " << *err1 << std::endl); (void)err1; + } + if (theRSP.FindDataElement(Tag(0x0,0x0902))){ + DataElement de = theRSP.GetDataElement(Tag(0x0,0x0902)); + err2 = de.GetByteValue(); + gdcmErrorMacro( " Tag 0x0,0x902 reported as " << *err2 << std::endl); (void)err2; + } + } + receivingData = false; + justWaiting = false; + if (theVal == pendingDE1 || theVal == pendingDE2 || (theVal == success && theNumLeft != 0)) { + receivingData = true; //wait for more data as more PDUs (findrsps, for instance) + justWaiting = true; + waitingForEvent = true; + + //ok, if we're pending, then let's open the cstorescp connection here + //(if it's not already open), and then from here start a storescp event loop. + //just don't listen to the cmove event loop until this is done. + //could cause a pileup on the main connection, I suppose. + //could also report the progress here, if we liked. + if (theCommandCode == 0x8021){//cmove response, so prep the retrieval loop on the back connection + + bool dataSetCountIncremented = true;//false once the number of incoming datasets doesn't change. + if (Internals->mSecondaryConnection->GetProtocol() == NULL){ + //establish the connection + //can fail if is_readready doesn't return true, ie, the connection + //wasn't opened on the other side because the other side isn't sending data yet + //for whatever reason (maybe there's nothing to get?) + secondConnectionEstablished = + Internals->mSecondaryConnection->InitializeIncomingConnection(); + if (secondConnectionEstablished && + (Internals->mSecondaryConnection->GetState()== eSta1Idle || + Internals->mSecondaryConnection->GetState() == eSta2Open)){ + ULEvent theCStoreEvent(eEventDoesNotExist, NULL);//have to fill this in, we're in passive mode now + theCStoreStateID = RunEventLoop(theCStoreEvent, Internals->mSecondaryConnection, inCallback, true); + } else {//something broke, can't establish secondary move connection here + gdcmErrorMacro( "Unable to establish secondary connection with server, aborting." << std::endl); + return eStaDoesNotExist; + } + } + if (secondConnectionEstablished){ + while (theCStoreStateID == eSta6TransferReady && dataSetCountIncremented){ + ULEvent theCStoreEvent(eEventDoesNotExist, NULL);//have to fill this in, we're in passive mode now + //now, get data from across the network + theCStoreStateID = RunEventLoop(theCStoreEvent, Internals->mSecondaryConnection, inCallback, true); + if (inCallback){ + dataSetCountIncremented = true; + inCallback->ResetHandledDataSet(); + } else { + dataSetCountIncremented = false; + } + } + } + //force the abort from our side + // ULEvent theCStoreEvent(eAABORTRequest, NULL);//have to fill this in, we're in passive mode now + // theCStoreStateID = RunEventLoop(theCStoreEvent, outDataSet, mSecondaryConnection, true); + } else {//not dealing with cmove progress updates, apparently + //keep looping if we haven't succeeded or failed; these are the values for 'pending' + //first, dynamically cast that pdu in the event + //should be a data pdu + //then, look for tag 0x0,0x900 + + //only add datasets that are _not_ part of the network response + std::vector final; + std::vector theData; + BasePDU* thePDU;//outside the loop for the do/while stopping condition + bool interrupted = false; + do { + uint8_t itemtype = 0x0; + is.read( (char*)&itemtype, 1 ); + //what happens if nothing's read? + thePDU = PDUFactory::ConstructPDU(itemtype); + if (itemtype != 0x4 && thePDU != NULL){ //ie, not a pdatapdu + std::vector interruptingPDUs; + currentEvent.SetEvent(PDUFactory::DetermineEventByPDU(interruptingPDUs[0])); + currentEvent.SetPDU(interruptingPDUs); + interrupted= true; + break; + } + if (thePDU != NULL){ + thePDU->Read(is); + theData.push_back(thePDU); + } else{ + break; + } + //!!!need to handle incoming PDUs that are not data, ie, an abort + } while(/*!is.eof() &&*/ !thePDU->IsLastFragment()); + if (!interrupted){//ie, if the remote server didn't hang up + DataSet theCompleteFindResponse = + PresentationDataValue::ConcatenatePDVBlobs(PDUFactory::GetPDVs(theData)); + //note that it's the responsibility of the event to delete the PDU in theFindRSP + for (size_t i = 0; i < theData.size(); i++){ + delete theData[i]; + } + //outDataSet.push_back(theCompleteFindResponse); + if (inCallback){ + inCallback->HandleDataSet(theCompleteFindResponse); + } + } + } + } + } + } else { + raisedEvent = eEventDoesNotExist; + waitingForEvent = false; + } + } + else { + currentEvent.SetEvent(raisedEvent);//actions that cause transitions in the state table + //locally just raise local events that will therefore cause the trigger to be pulled. + } + } while (currentEvent.GetEvent() != eEventDoesNotExist && + theState != eStaDoesNotExist && theState != eSta13AwaitingClose && theState != eSta1Idle && + (theState != eSta6TransferReady || (theState == eSta6TransferReady && receivingData ))); + //stop when the AE is done, or when ready to transfer data (ie, the next PDU should be sent in), + //or when the connection is idle after a disconnection. + //or, if in state 6 and receiving data, until all data is received. + + return theState; +} + + +} // end namespace gdcm diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmServiceClassUser.h b/gdcm/Source/MessageExchangeDefinition/gdcmServiceClassUser.h new file mode 100644 index 0000000..892156e --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmServiceClassUser.h @@ -0,0 +1,124 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMSERVICECLASSUSER_H +#define GDCMSERVICECLASSUSER_H + +#include "gdcmSubject.h" + +#include "gdcmPresentationContext.h" +#include "gdcmFile.h" + +#include "gdcmNetworkStateID.h" // EStateID + +namespace gdcm +{ +class ServiceClassUserInternals; +class BaseRootQuery; +namespace network{ +class ULEvent; +class ULConnection; +class ULConnectionCallback; +} +/** + * \brief ServiceClassUser + */ +class GDCM_EXPORT ServiceClassUser : public Subject +{ +public: + /// Construct a SCU with default: + /// - hostname = localhost + /// - port = 104 + ServiceClassUser(); + ~ServiceClassUser(); + + /// Set the name of the called hostname (hostname or IP address) + void SetHostname( const char *hostname ); + + /// Set port of remote host (called application) + void SetPort( uint16_t port ); + + /// Set the port for any incoming C-STORE-SCP operation (typically in a return of C-MOVE) + void SetPortSCP( uint16_t portscp ); + + /// set calling ae title + void SetAETitle(const char *aetitle); + const char *GetAETitle() const; + + /// set called ae title + void SetCalledAETitle(const char *aetitle); + const char *GetCalledAETitle() const; + + /// set/get Timeout + void SetTimeout(double t); + double GetTimeout() const; + + /// Will try to connect + /// This will setup the actual timeout used during the whole connection time. Need to call + /// SetTimeout first + bool InitializeConnection(); + + /// Set the Presentation Context used for the Association + void SetPresentationContexts(std::vector const & pcs); + + /// Return if the passed in presentation was accepted during association negotiation. + bool IsPresentationContextAccepted(const PresentationContext& pc) const; + + /// Start the association. Need to call SetPresentationContexts before + bool StartAssociation(); + + /// Stop the running association + bool StopAssociation(); + + /// C-ECHO + bool SendEcho(); + + /// Execute a C-STORE on file on disk, named filename + bool SendStore(const char *filename); + /// Execute a C-STORE on a File, the transfer syntax used for the query is based on the + /// file. + bool SendStore(File const &file); + /// Execute a C-STORE on a DataSet, the transfer syntax used will be Implicit + bool SendStore(DataSet const &ds); + + /// C-FIND a query, return result are in retDatasets + bool SendFind(const BaseRootQuery* query, std::vector &retDatasets); + + /// Execute a C-MOVE, based on query, return files are written in outputdir + bool SendMove(const BaseRootQuery* query, const char *outputdir); + /// Execute a C-MOVE, based on query, returned dataset are Implicit + bool SendMove(const BaseRootQuery* query, std::vector &retDatasets); + /// Execute a C-MOVE, based on query, returned Files are stored in vector + bool SendMove(const BaseRootQuery* query, std::vector &retFile); + + /// for wrapped language: instanciate a reference counted object + static SmartPointer New() { return new ServiceClassUser; } + +private: + network::EStateID RunEventLoop(network::ULEvent& inEvent, + network::ULConnection* inWhichConnection, + network::ULConnectionCallback* inCallback, const bool& startWaiting); + network::EStateID RunMoveEventLoop(network::ULEvent& inEvent, + network::ULConnectionCallback* inCallback); + +private: + ServiceClassUser(const ServiceClassUser&); + void operator=(const ServiceClassUser &); + +private: + ServiceClassUserInternals *Internals; +}; + +} // end namespace gdcm + +#endif // GDCMSERVICECLASSUSER_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmTransferSyntaxSub.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmTransferSyntaxSub.cxx new file mode 100644 index 0000000..cb2a6b2 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmTransferSyntaxSub.cxx @@ -0,0 +1,124 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmTransferSyntaxSub.h" +#include "gdcmSwapper.h" + +#include + +namespace gdcm +{ +namespace network +{ +const uint8_t TransferSyntaxSub::ItemType = 0x40; +const uint8_t TransferSyntaxSub::Reserved2 = 0x00; + +TransferSyntaxSub::TransferSyntaxSub() +{ + //UpdateName( "1.2.840.10008.1.1" ); + ItemLength = 0; +} + +void TransferSyntaxSub::SetName( const char *name ) +{ + if( name ) + { + Name = name; + assert( Name.size() <= std::numeric_limits::max() ); + ItemLength = (uint16_t)Name.size(); + } +} + +std::istream &TransferSyntaxSub::Read(std::istream &is) +{ + uint8_t itemtype = 0xf; + is.read( (char*)&itemtype, sizeof(ItemType) ); + assert( itemtype == ItemType ); + uint8_t reserved2; + is.read( (char*)&reserved2, sizeof(Reserved2) ); + uint16_t itemlength; + is.read( (char*)&itemlength, sizeof(ItemLength) ); + SwapperDoOp::SwapArray(&itemlength,1); + ItemLength = itemlength; + + char name[256]; + assert( itemlength < 256 ); + is.read( name, itemlength ); + Name = std::string(name,itemlength); + + return is; +} + +const std::ostream &TransferSyntaxSub::Write(std::ostream &os) const +{ + os.write( (char*)&ItemType, sizeof(ItemType) ); + os.write( (char*)&Reserved2, sizeof(Reserved2) ); + //os.write( (char*)&ItemLength, sizeof(ItemLength) ); + uint16_t copy = ItemLength; + SwapperDoOp::SwapArray(©,1); + os.write( (char*)©, sizeof(ItemLength) ); + + assert( Name.size() < 256 ); + os.write( Name.c_str(), Name.size() ); + return os; +} + +size_t TransferSyntaxSub::Size() const +{ + size_t ret = 0; + assert( Name.size() == ItemLength ); + ret += sizeof(ItemType); + ret += sizeof(Reserved2); + ret += sizeof(ItemLength); + ret += ItemLength; + return ret; +} + +void TransferSyntaxSub::UpdateName( const char *name ) +{ + if( name ) + { + UIDs uids; + bool b = uids.SetFromUID( name ); + if( b ) + { + Name = name; + ItemLength = (uint16_t)Name.size(); + assert( (size_t)ItemLength + 4 == Size() ); + return; + } + } + + gdcmErrorMacro( "Invalid Name: " << name ); + throw "Invalid Name"; +} + +void TransferSyntaxSub::SetNameFromUID( UIDs::TSName tsname ) +{ + const char *name = UIDs::GetUIDString( tsname ); + UpdateName( name ); +} + +void TransferSyntaxSub::Print(std::ostream &os) const +{ + os << "Name: " << Name; + UIDs uids; + if( uids.SetFromUID( Name.c_str() ) ) + { + os << " (" << uids.GetName() << ")" << std::endl; + } + os << std::endl; +} + +} // end namespace network +} // end namespace gdcm diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmTransferSyntaxSub.h b/gdcm/Source/MessageExchangeDefinition/gdcmTransferSyntaxSub.h new file mode 100644 index 0000000..01c9114 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmTransferSyntaxSub.h @@ -0,0 +1,69 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMTRANSFERSYNTAXSUB_H +#define GDCMTRANSFERSYNTAXSUB_H + +#include "gdcmTypes.h" +#include "gdcmTransferSyntax.h" +#include "gdcmUIDs.h" + +namespace gdcm +{ + +namespace network +{ + +/** + * \brief TransferSyntaxSub + * Table 9-15 + * TRANSFER SYNTAX SUB-ITEM FIELDS + * + * TODO what is the goal of : + * + * Table 9-19 + * TRANSFER SYNTAX SUB-ITEM FIELDS + */ +class TransferSyntaxSub +{ +public: + TransferSyntaxSub(); + void SetName( const char *name ); + const char *GetName() const { return Name.c_str(); } + + // accept a UIDs::TSType also... + void SetNameFromUID( UIDs::TSName tsname ); + + std::istream &Read(std::istream &is); + const std::ostream &Write(std::ostream &os) const; + size_t Size() const; + void Print(std::ostream &os) const; + + bool operator==(const TransferSyntaxSub & ts) const + { + return Name == ts.Name; + } + +private: + void UpdateName( const char *name ); + static const uint8_t ItemType; + static const uint8_t Reserved2; + uint16_t ItemLength; // len of + std::string /*TransferSyntaxSub*/ Name; // UID +}; + +} // end namespace network + +} // end namespace gdcm + +#endif //GDCMTRANSFERSYNTAXSUB_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmULAction.h b/gdcm/Source/MessageExchangeDefinition/gdcmULAction.h new file mode 100644 index 0000000..63a8084 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmULAction.h @@ -0,0 +1,81 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#ifndef GDCMULACTION_H +#define GDCMULACTION_H + +#include "gdcmNetworkStateID.h" +#include "gdcmULEvent.h" +#include "gdcmULConnection.h" + +namespace gdcm { +class Subject; + namespace network { + +/** + * \brief ULAction + * A ULConnection in a given ULState can perform certain ULActions. This base class + * provides the interface for running those ULActions on a given ULConnection. + * + * Essentially, the ULConnectionManager will take this object, determined from the current + * ULState of the ULConnection, and pass the ULConnection object to the ULAction. The ULAction + * will then invoke whatever necessary commands are required by a given action. + * + * The result of a ULAction is a ULEvent (ie, what happened as a result of the action). + * + * This ULEvent is passed to the ULState, so that the transition to the next state can occur. + * + * Actions are associated with Payloads-- be thos filestreams, AETitles to establish connections, + * whatever. The actual parameters that the user will pass via an action will come through + * a Payload object, which should, in itself, be some gdcm-based object (but not all objects can + * be payloads; sending a single dataelement as a payload isn't meaningful). As such, each action + * has its own particular payload. + * + * For the sake of keeping files together, both the particular payload class and the action class + * will be defined in the same header file. Payloads should JUST be data (or streams), NO METHODS. + * + * Some actions perform changes that should raise events on the local system, and some + * actions perform changes that will require waiting for events from the remote system. + * + * Therefore, this base action has been modified so that those events are set by each action. + * When the event loop runs an action, it will then test to see if a local event was raised by the + * action, and if so, perform the appropriate subsequent action. If the action requires waiting + * for a response from the remote system, then the event loop will sit there (presumably with the + * ARTIM timer running) and wait for a response from the remote system. Once a response is + * obtained, then the the rest of the state transitions can happen. + * + */ +class ULAction { + private: + //cannot copy a ULAction + ULAction(const ULAction& inAction); + + protected: + + + public: + ULAction() {}; + //make sure destructors are virtual to avoid memory leaks + virtual ~ULAction() {}; + + virtual EStateID PerformAction(Subject *s, ULEvent& inEvent, ULConnection& inConnection, + bool& outWaitingForEvent, EEventID& outRaisedEvent) = 0; + }; + } +} + +#endif // GDCMULACTION_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmULActionAA.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmULActionAA.cxx new file mode 100644 index 0000000..476db3d --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmULActionAA.cxx @@ -0,0 +1,114 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +/* +This file contains the implementation for the classes for the AA Actions, +Association Abort Related Actions (Table 9-9 of ps 3.8-2009). + +Since each class is essentially a placeholder for a function pointer, I'm breaking with having +each class have its own file for the sake of brevity of the number of files. + +*/ + +#include "gdcmULActionAA.h" +#include "gdcmARTIMTimer.h" +#include "gdcmAAbortPDU.h" +#include + +namespace gdcm +{ +namespace network +{ + +//Send A-ABORT PDU (service-user source) and start (or restart if already started) ARTIM timer +EStateID ULActionAA1::PerformAction(Subject *, ULEvent& , ULConnection& inConnection, + bool& , EEventID& ){ + + AAbortPDU thePDU; + thePDU.Write(*inConnection.GetProtocol()); + inConnection.GetTimer().Start(); + + return eSta13AwaitingClose; +} + +//Stop ARTIM timer if running. Close transport connection. +EStateID ULActionAA2::PerformAction(Subject *, ULEvent& , ULConnection& inConnection, + bool& , EEventID& ){ + + + inConnection.GetTimer().Stop(); + inConnection.StopProtocol(); + + return eSta1Idle; +} + +//If (service-user initiated abort) +//- issue A-ABORT indication and close transport connection +//otherwise (service-provider initiated abort): +//- issue A-P-ABORT indication and close transport connection +EStateID ULActionAA3::PerformAction(Subject *, ULEvent& , ULConnection& , + bool& , EEventID& ){ + + return eSta1Idle; +} + +//Issue A-P-ABORT indication primitive +EStateID ULActionAA4::PerformAction(Subject *, ULEvent& , ULConnection& , + bool& , EEventID& ){ + + return eSta1Idle; +} + +//Stop ARTIM timer +EStateID ULActionAA5::PerformAction(Subject *, ULEvent& , ULConnection& inConnection, + bool& , EEventID& ){ + + inConnection.GetTimer().Stop(); + + return eSta1Idle; +} + +//Ignore PDU +EStateID ULActionAA6::PerformAction(Subject *, ULEvent& , ULConnection& , + bool& , EEventID& ){ + //do nothing, I guess. + return eSta13AwaitingClose; +} + +//Send A-ABORT PDU +EStateID ULActionAA7::PerformAction(Subject *, ULEvent& , ULConnection& inConnection, + bool& , EEventID& ){ + + AAbortPDU thePDU;//for now, use Matheiu's default values + thePDU.Write(*inConnection.GetProtocol()); + + return eSta13AwaitingClose; +} + +//Send A-ABORT PDU (service-provider source), issue an A-P-ABORT indication, and start ARTIM timer +EStateID ULActionAA8::PerformAction(Subject *, ULEvent& , ULConnection& inConnection, + bool& , EEventID& ){ + + + AAbortPDU thePDU;//for now, use Matheiu's default values + thePDU.Write(*inConnection.GetProtocol()); + inConnection.GetTimer().Start(); + + return eSta13AwaitingClose; +} +} // end namespace network +} // end namespace gdcm diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmULActionAA.h b/gdcm/Source/MessageExchangeDefinition/gdcmULActionAA.h new file mode 100644 index 0000000..007c2bf --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmULActionAA.h @@ -0,0 +1,103 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#ifndef GDCMULACTIONAA_H +#define GDCMULACTIONAA_H + +#include "gdcmULAction.h" + +/** +This header defines the classes for the AA Actions, +Association Abort Related Actions (Table 9-9 of ps 3.8-2009). + +Since each class is essentially a placeholder for a function pointer, I'm breaking with having +each class have its own file for the sake of brevity of the number of files. +*/ + +namespace gdcm { + namespace network { + + //Send A-ABORT PDU (service-user source) and start (or restart if already started) ARTIM timer + //Next State: eSta13AwaitingClose + class ULActionAA1 : public ULAction { + public: + EStateID PerformAction(Subject *s, ULEvent& inEvent, ULConnection& inConnection, + bool& outWaitingForEvent, EEventID& outRaisedEvent); + }; + + //Stop ARTIM timer if running. Close transport connection. + //Next State: eSta1Idle + class ULActionAA2 : public ULAction { + public: + EStateID PerformAction(Subject *s, ULEvent& inEvent, ULConnection& inConnection, + bool& outWaitingForEvent, EEventID& outRaisedEvent); + }; + + //If (service-user initiated abort) + //- issue A-ABORT indication and close transport connection + //otherwise (service-provider initiated abort): + //- issue A-P-ABORT indication and close transport connection + //Next State: eSta1Idle + class ULActionAA3 : public ULAction { + public: + EStateID PerformAction(Subject *s, ULEvent& inEvent, ULConnection& inConnection, + bool& outWaitingForEvent, EEventID& outRaisedEvent); + }; + + //Issue A-P-ABORT indication primitive + //Next State: eSta1Idle + class ULActionAA4 : public ULAction { + public: + EStateID PerformAction(Subject *s, ULEvent& inEvent, ULConnection& inConnection, + bool& outWaitingForEvent, EEventID& outRaisedEvent); + }; + + //Stop ARTIM timer + //Next State: eSta1Idle + class ULActionAA5 : public ULAction { + public: + EStateID PerformAction(Subject *s, ULEvent& inEvent, ULConnection& inConnection, + bool& outWaitingForEvent, EEventID& outRaisedEvent); + }; + + //Ignore PDU + //Next State: eSta13AwaitingClose + class ULActionAA6 : public ULAction { + public: + EStateID PerformAction(Subject *s, ULEvent& inEvent, ULConnection& inConnection, + bool& outWaitingForEvent, EEventID& outRaisedEvent); + }; + + //Send A-ABORT PDU + //Next State: eSta13AwaitingClose + class ULActionAA7 : public ULAction { + public: + EStateID PerformAction(Subject *s, ULEvent& inEvent, ULConnection& inConnection, + bool& outWaitingForEvent, EEventID& outRaisedEvent); + }; + + //Send A-ABORT PDU (service-provider source), issue an A-P-ABORT indication, and start ARTIM timer + //Next State: eSta13AwaitingClose + class ULActionAA8 : public ULAction { + public: + EStateID PerformAction(Subject *s, ULEvent& inEvent, ULConnection& inConnection, + bool& outWaitingForEvent, EEventID& outRaisedEvent); + }; + } +} + +#endif // GDCMULACTIONAA_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmULActionAE.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmULActionAE.cxx new file mode 100644 index 0000000..2be8e4d --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmULActionAE.cxx @@ -0,0 +1,277 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +/* + +This file contains the implementation for the classes for the AE Actions, +Association Establishment Related Actions (Table 9-6 of ps 3.8-2009). + +Since each class is essentially a placeholder for a function pointer, I'm breaking with having +each class have its own file for the sake of brevity of the number of files. + +*/ + +#include "gdcmULActionAE.h" +#include "gdcmARTIMTimer.h" +#include "gdcmAAssociateRQPDU.h" +#include "gdcmAAssociateACPDU.h" +#include "gdcmAAssociateRJPDU.h" + +#include //for setting up the local socket + +namespace gdcm +{ +namespace network +{ + +//Issue TRANSPORT CONNECT request primitive to local transport service. +EStateID ULActionAE1::PerformAction(Subject *, ULEvent& , ULConnection& inConnection, + bool& outWaitingForEvent, EEventID& outRaisedEvent){ + + //opening a local socket + outWaitingForEvent = false; + if (!inConnection.InitializeConnection()) + { + outRaisedEvent = eEventDoesNotExist; + return eSta1Idle; + } + else + { + outRaisedEvent = eTransportConnConfirmLocal; + } + return eSta4LocalAssocDone; +} + +//Send A-ASSOCIATE-RQ-PDU +EStateID ULActionAE2::PerformAction(Subject *, ULEvent& , ULConnection& inConnection, + bool& outWaitingForEvent, EEventID& outRaisedEvent) +{ + AAssociateRQPDU thePDU; + + thePDU.SetCallingAETitle( inConnection.GetConnectionInfo().GetCallingAETitle() ); + thePDU.SetCalledAETitle( inConnection.GetConnectionInfo().GetCalledAETitle() ); + + //the presentation context is now defined when the connection is first + //desired to be established. The connection proposes these different + //presentation contexts. ideally, we could refine it further to a particular + //presentation context, but if the server supports many and we support many, + //then an arbitrary decision can be made. + std::vector const & thePCS = + inConnection.GetPresentationContexts(); + + std::vector::const_iterator itor; + for (itor = thePCS.begin(); itor < thePCS.end(); itor++) + { + thePDU.AddPresentationContext(*itor); + } + + thePDU.Write(*inConnection.GetProtocol()); + inConnection.GetProtocol()->flush(); + + outWaitingForEvent = true; + outRaisedEvent = eEventDoesNotExist; + + return eSta5WaitRemoteAssoc; +} + +//Issue A-ASSOCIATE confirmation (accept) primitive +// NOTE: A-ASSOCIATE is NOT A-ASSOCIATE-AC +// PS 3.7 / Annex D for A-ASSOCIATE definition +EStateID ULActionAE3::PerformAction(Subject *, ULEvent& inEvent, ULConnection& inConnection, + bool& outWaitingForEvent, EEventID& outRaisedEvent){ + + + // Mark please check this junk: + assert(!inEvent.GetPDUs().empty()); + AAssociateACPDU* acpdu; + acpdu = dynamic_cast(inEvent.GetPDUs()[0]); + assert( acpdu ); + uint32_t maxpdu = acpdu->GetUserInformation().GetMaximumLengthSub().GetMaximumLength(); + inConnection.SetMaxPDUSize(maxpdu); + + // once again duplicate AAssociateACPDU vs ULConnection + for( unsigned int index = 0; index < acpdu->GetNumberOfPresentationContextAC(); index++ ){ + PresentationContextAC const &pc = acpdu->GetPresentationContextAC(index); + inConnection.AddAcceptedPresentationContext(pc); + } + + outWaitingForEvent = false; + outRaisedEvent = eEventDoesNotExist;//no event is raised, + //wait for the user to try to send some data. + return eSta6TransferReady; +} + +//Issue A-ASSOCIATE confirmation (reject) primitive and close transport connection +EStateID ULActionAE4::PerformAction(Subject *, ULEvent& , ULConnection& , + bool& outWaitingForEvent, EEventID& outRaisedEvent){ + + outWaitingForEvent = false; + outRaisedEvent = eASSOCIATE_RJPDUreceived; + return eSta1Idle; +} + +//Issue Transport connection response primitive, start ARTIM timer +EStateID ULActionAE5::PerformAction(Subject *, ULEvent& , ULConnection& inConnection, + bool& outWaitingForEvent, EEventID& outRaisedEvent){ + + //issue response primitive; have to set that up + inConnection.GetTimer().Start(); + + outWaitingForEvent = false; + outRaisedEvent = eTransportConnConfirmLocal; + return eSta2Open; +} + +//Stop ARTIM timer and if A-ASSOCIATE-RQ acceptable by service-provider: +//- issue A-ASSOCIATE indication primitive +//Next state: eSta3WaitLocalAssoc +//otherwise: +//- issue A-ASSOCIATE-RJ-PDU and start ARTIM timer +//Next state: eSta13AwaitingClose +EStateID ULActionAE6::PerformAction(Subject *, ULEvent& inEvent, ULConnection& inConnection, + bool& outWaitingForEvent, EEventID& outRaisedEvent){ + + // we are in a C-MOVE + + inConnection.GetTimer().Stop(); + + //have to determine 'acceptability' + //this is more server side than client, so it's a bit empty now + //we have one server type, a store scp started on a cmove + //so, it's defined as acceptable. + bool acceptable = true;//for now, always accept + if (inEvent.GetPDUs().empty()){ + acceptable = false; //can't accept an empty set of pdus. + //also, requrie little endian, not sure how to set that, but it should be here. + } + AAssociateRQPDU* rqpdu; + if (acceptable){ + rqpdu = dynamic_cast(inEvent.GetPDUs()[0]); + if (rqpdu == NULL){ + acceptable = false; + } + } + if (acceptable){ + outWaitingForEvent = false;//not waiting, now want to get the + //sending of data underway. Have to get info now + outRaisedEvent = eAASSOCIATEresponseAccept; + + TransferSyntaxSub ts1; + ts1.SetNameFromUID( UIDs::ImplicitVRLittleEndianDefaultTransferSyntaxforDICOM ); + + AAssociateACPDU acpdu; + + assert( rqpdu->GetNumberOfPresentationContext() ); + for( unsigned int index = 0; index < rqpdu->GetNumberOfPresentationContext(); index++ ) + { + // FIXME / HARDCODED We only ever accept Little Endian + // FIXME we should check : + // rqpdu.GetAbstractSyntax() contains LittleEndian + PresentationContextAC pcac1; + PresentationContextRQ const &pc = rqpdu->GetPresentationContext(index); + //add the presentation context back into the connection, + //so later functions will know what's allowed on this connection + // BOGUS (MM): + //inConnection.AddAcceptedPresentationContext(pc); + + const uint8_t id = pc.GetPresentationContextID(); + + std::vector const & tsSet = pc.GetTransferSyntaxes(); + std::vector::const_iterator tsitor; + // PS 3.8 Table 9-18 PRESENTATION CONTEXT ITEM FIELDS + uint8_t result = 4; // transfer-syntaxes-not-supported (provider rejection) + for (tsitor = tsSet.begin(); tsitor < tsSet.end(); tsitor++) + { + //gdcmDebugMacro( "Checking: [" << tsitor->GetName() << "] vs [" << ts1.GetName() << "]" << std::endl ); + if (strcmp(tsitor->GetName(), ts1.GetName()) == 0 ) + { + result = 0; // 0 - acceptance + inConnection.SetCStoreTransferSyntax( ts1 ); + pcac1.SetTransferSyntax( ts1 ); + } + } + if( result ) + { + gdcmWarningMacro( "Could not find Implicit or Explicit Little Endian in Response. Giving another try" ); + // Okay little endian implicit was not found, this happen sometimes, for eg with DVTk, let's be nice and accept also Explicit + TransferSyntaxSub ts2; + ts2.SetNameFromUID( UIDs::ExplicitVRLittleEndian ); + for (tsitor = tsSet.begin(); tsitor < tsSet.end(); tsitor++) + { + //gdcmDebugMacro( "Checking: [" << tsitor->GetName() << "] vs [" << ts1.GetName() << "]" << std::endl ); + if (strcmp(tsitor->GetName(), ts2.GetName()) == 0 ) + { + result = 0; // 0 - acceptance + inConnection.SetCStoreTransferSyntax( ts2 ); + pcac1.SetTransferSyntax( ts2 ); + } + } + } + if( result ) + { + gdcmErrorMacro( "Could not find Implicit or Explicit Little Endian in Response. Giving up" ); + } + pcac1.SetPresentationContextID( id ); + pcac1.SetReason( result ); + acpdu.AddPresentationContextAC( pcac1 ); + } + assert( acpdu.GetNumberOfPresentationContextAC() ); + + // Init AE-Titles: + acpdu.InitFromRQ( *rqpdu ); + + acpdu.Write( *inConnection.GetProtocol() ); + inConnection.GetProtocol()->flush(); + + return eSta3WaitLocalAssoc; + } else { + + outWaitingForEvent = false; + outRaisedEvent = eAASSOCIATEresponseReject; + AAssociateRJPDU thePDU; + thePDU.Write(*inConnection.GetProtocol()); + inConnection.GetProtocol()->flush(); + inConnection.GetTimer().Stop(); + return eSta13AwaitingClose; + } + +} + +//Send A-ASSOCIATE-AC PDU +EStateID ULActionAE7::PerformAction(Subject *, ULEvent& , ULConnection& , + bool& outWaitingForEvent, EEventID& outRaisedEvent) +{ + outWaitingForEvent = true; + outRaisedEvent = eEventDoesNotExist; + return eSta6TransferReady; +} + +//Send A-ASSOCIATE-RJ PDU and start ARTIM timer +EStateID ULActionAE8::PerformAction(Subject *, ULEvent& , ULConnection& inConnection, + bool& outWaitingForEvent, EEventID& outRaisedEvent) +{ + AAssociateRJPDU thePDU; + thePDU.Write(*inConnection.GetProtocol()); + inConnection.GetTimer().Start(); + outWaitingForEvent = false; + outRaisedEvent = eAASSOCIATEresponseReject; + + return eSta13AwaitingClose; +} + +} // end namespace network +} // end namespace gdcm diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmULActionAE.h b/gdcm/Source/MessageExchangeDefinition/gdcmULActionAE.h new file mode 100644 index 0000000..1cb5071 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmULActionAE.h @@ -0,0 +1,103 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#ifndef GDCMULACTIONAE_H +#define GDCMULACTIONAE_H + +#include "gdcmULAction.h" + +/** +This header defines the classes for the AE Actions, +Association Establishment Related Actions (Table 9-6 of ps 3.8-2009). + +Since each class is essentially a placeholder for a function pointer, I'm breaking with having +each class have its own file for the sake of brevity of the number of files. + +*/ + +namespace gdcm { + namespace network { + + //Issue TRANSPORT CONNECT request primitive to local transport service. + class ULActionAE1 : public ULAction { + public: + EStateID PerformAction(Subject *s, ULEvent& inEvent, ULConnection& inConnection, + bool& outWaitingForEvent, EEventID& outRaisedEvent); + }; + + //Send A-ASSOCIATE-RQ-PDU + //Next State: eSta5WaitRemoteAssoc + class ULActionAE2 : public ULAction { + public: + EStateID PerformAction(Subject *s, ULEvent& inEvent, ULConnection& inConnection, + bool& outWaitingForEvent, EEventID& outRaisedEvent); + }; + + //Issue A-ASSOCIATE confirmation (accept) primitive + //Next State: eSta6TransferReady + class ULActionAE3 : public ULAction { + public: + EStateID PerformAction(Subject *s, ULEvent& inEvent, ULConnection& inConnection, + bool& outWaitingForEvent, EEventID& outRaisedEvent); + }; + + //Issue A-ASSOCIATE confirmation (reject) primitive and close transport connection + //Next State: eSta1Idle + class ULActionAE4 : public ULAction { + public: + EStateID PerformAction(Subject *s, ULEvent& inEvent, ULConnection& inConnection, + bool& outWaitingForEvent, EEventID& outRaisedEvent); + }; + + //Issue Transport connection response primitive, start ARTIM timer + //Next State: eSta2Open + class ULActionAE5 : public ULAction { + public: + EStateID PerformAction(Subject *s, ULEvent& inEvent, ULConnection& inConnection, + bool& outWaitingForEvent, EEventID& outRaisedEvent); + }; + + //Stop ARTIM timer and if A-ASSOCIATE-RQ acceptable by service-provider: + //- issue A-ASSOCIATE indication primitive + //Next state: eSta3WaitLocalAssoc + //otherwise: + //- issue A-ASSOCIATE-RJ-PDU and start ARTIM timer + //Next state: eSta13AwaitingClose + class ULActionAE6 : public ULAction { + public: + EStateID PerformAction(Subject *s, ULEvent& inEvent, ULConnection& inConnection, + bool& outWaitingForEvent, EEventID& outRaisedEvent); + }; + + //Send A-ASSOCIATE-AC PDU + //Next State: eSta6TransferReady + class ULActionAE7 : public ULAction { + public: + EStateID PerformAction(Subject *s, ULEvent& inEvent, ULConnection& inConnection, + bool& outWaitingForEvent, EEventID& outRaisedEvent); + }; + + //Send A-ASSOCIATE-RJ PDU and start ARTIM timer + //Next State: eSta13AwaitingClose + class ULActionAE8 : public ULAction { + public: + EStateID PerformAction(Subject *s, ULEvent& inEvent, ULConnection& inConnection, + bool& outWaitingForEvent, EEventID& outRaisedEvent); + }; + } +} +#endif // GDCMULACTIONAE_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmULActionAR.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmULActionAR.cxx new file mode 100644 index 0000000..869eb4c --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmULActionAR.cxx @@ -0,0 +1,160 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +/* +This file contains the implementation for the classes for the AR Actions, +Association Release Related Actions (Table 9-8 of ps 3.8-2009). + +Since each class is essentially a placeholder for a function pointer, I'm breaking with having +each class have its own file for the sake of brevity of the number of files. +*/ + +#include "gdcmULActionAR.h" +#include "gdcmARTIMTimer.h" +#include "gdcmAReleaseRQPDU.h" +#include "gdcmAReleaseRPPDU.h" +#include "gdcmPDataTFPDU.h" + +namespace gdcm +{ +namespace network +{ + +//Send A-RELEASE-RQ-PDU +EStateID ULActionAR1::PerformAction(Subject *, ULEvent& , ULConnection& inConnection, + bool& outWaitingForEvent, EEventID& ){ + + AReleaseRQPDU thePDU;//for now, use Matheiu's default values + thePDU.Write(*inConnection.GetProtocol()); + inConnection.GetProtocol()->flush(); // important + + + outWaitingForEvent = true; + + return eSta7WaitRelease; +} + +//Issue A-RELEASE indication primitive +EStateID ULActionAR2::PerformAction(Subject *, ULEvent& , ULConnection& inConnection, + bool& outWaitingForEvent, EEventID& outRaisedEvent){ + + outWaitingForEvent = false; + outRaisedEvent = eARELEASERequest;//here's the primitive being sent + + //this is very stupid. + //the A-release indication primitive is given to determine whether or not the + //server wants to send an a-release, an a-abort, or a pdata pdu. + //we just want to send an a-release. + //therfore, this function will directly send the release. + //ar8 does the same thing, but so far, we have not had that collision yet. + + AReleaseRPPDU thePDU;//for now, use Matheiu's default values + thePDU.Write(*inConnection.GetProtocol()); + inConnection.GetProtocol()->flush(); + + //if we hadn't actually just performed the primitive right here, we sould be in sta8 + //as it is, we should be in sta13 +// return eSta8WaitLocalRelease; + return eSta13AwaitingClose; +} + +//Issue A-RELEASE confirmation primitive, and close transport connection +EStateID ULActionAR3::PerformAction(Subject *, ULEvent& , ULConnection& inConnection, + bool& outWaitingForEvent, EEventID& outRaisedEvent){ + + outWaitingForEvent = false; + outRaisedEvent = eARELEASERequest; + inConnection.StopProtocol(); + return eSta1Idle; +} + +//Issue A-RELEASE-RP PDU and start ARTIM timer +EStateID ULActionAR4::PerformAction(Subject *, ULEvent& , ULConnection& inConnection, + bool& outWaitingForEvent, EEventID& outRaisedEvent){ + + AReleaseRPPDU thePDU;//for now, use Matheiu's default values + thePDU.Write(*inConnection.GetProtocol()); + inConnection.GetProtocol()->flush(); + inConnection.GetTimer().Start(); + outWaitingForEvent = false; + outRaisedEvent = eARELEASERequest; + + return eSta13AwaitingClose; +} + +//Stop ARTIM timer +EStateID ULActionAR5::PerformAction(Subject *, ULEvent& , ULConnection& inConnection, + bool& , EEventID& ){ + + inConnection.GetTimer().Stop(); + return eSta1Idle; +} + +//Issue P-DATA indication +EStateID ULActionAR6::PerformAction(Subject *, ULEvent& , ULConnection& , + bool& outWaitingForEvent, EEventID& outRaisedEvent){ + + outWaitingForEvent = true; + outRaisedEvent = eEventDoesNotExist; + return eSta7WaitRelease; +} + +//Issue P-DATA-TF PDU +EStateID ULActionAR7::PerformAction(Subject *, ULEvent& , ULConnection& inConnection, + bool& , EEventID& ){ + +assert(0); + PDataTFPDU thePDU;//for now, use Matheiu's default values + thePDU.Write(*inConnection.GetProtocol()); + inConnection.GetProtocol()->flush(); + return eSta8WaitLocalRelease; +} + +//Issue A-RELEASE indication (release collision): +//- If association-requestor, next state is eSta9ReleaseCollisionRqLocal +//- if not, next state is eSta10ReleaseCollisionAc +EStateID ULActionAR8::PerformAction(Subject *, ULEvent& , ULConnection& , + bool& , EEventID& ){ + +assert(0); + return eSta10ReleaseCollisionAc; +} + +//Send A-RELEASE-RP PDU +EStateID ULActionAR9::PerformAction(Subject *, ULEvent& , ULConnection& inConnection, + bool& outWaitingForEvent, EEventID& ){ + + AReleaseRPPDU thePDU;//for now, use Matheiu's default values + thePDU.Write(*inConnection.GetProtocol()); + inConnection.GetProtocol()->flush(); + + outWaitingForEvent = true; + return eSta11ReleaseCollisionRq; +} + +//Issue A-RELEASE confirmation primitive +EStateID ULActionAR10::PerformAction(Subject *, ULEvent& , ULConnection& , + bool& outWaitingForEvent, EEventID& outRaisedEvent){ + + outWaitingForEvent = false; + outRaisedEvent = eARELEASEResponse; + + return eSta12ReleaseCollisionAcLocal; +} + +} // end namespace network +} // end namespace gdcm diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmULActionAR.h b/gdcm/Source/MessageExchangeDefinition/gdcmULActionAR.h new file mode 100644 index 0000000..fa25d03 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmULActionAR.h @@ -0,0 +1,116 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#ifndef GDCMULACTIONAR_H +#define GDCMULACTIONAR_H + +#include "gdcmULAction.h" + +/** +This header defines the classes for the AR Actions, +Association Release Related Actions (Table 9-8 of ps 3.8-2009). + +Since each class is essentially a placeholder for a function pointer, I'm breaking with having +each class have its own file for the sake of brevity of the number of files. +*/ + +namespace gdcm { + namespace network { + + //Send A-RELEASE-RQ-PDU + //Next State: eSta7WaitRelease + class ULActionAR1 : public ULAction { + public: + EStateID PerformAction(Subject *s, ULEvent& inEvent, ULConnection& inConnection, + bool& outWaitingForEvent, EEventID& outRaisedEvent); + }; + + //Issue A-RELEASE indication primitive + //Next State: eSta8WaitLocalRelease + class ULActionAR2 : public ULAction { + public: + EStateID PerformAction(Subject *s, ULEvent& inEvent, ULConnection& inConnection, + bool& outWaitingForEvent, EEventID& outRaisedEvent); + }; + + //Issue A-RELEASE confirmation primitive, and close transport connection + //Next State: eSta1Idle + class ULActionAR3 : public ULAction { + public: + EStateID PerformAction(Subject *s, ULEvent& inEvent, ULConnection& inConnection, + bool& outWaitingForEvent, EEventID& outRaisedEvent); + }; + + //Issue A-RELEASE-RP PDU and start ARTIM timer + //Next State: eSta13AwaitingClose + class ULActionAR4 : public ULAction { + public: + EStateID PerformAction(Subject *s, ULEvent& inEvent, ULConnection& inConnection, + bool& outWaitingForEvent, EEventID& outRaisedEvent); + }; + + //Stop ARTIM timer + //Next State: eSta1Idle + class ULActionAR5 : public ULAction { + public: + EStateID PerformAction(Subject *s, ULEvent& inEvent, ULConnection& inConnection, + bool& outWaitingForEvent, EEventID& outRaisedEvent); + }; + + //Issue P-Data indication + //Next State: eSta7WaitRelease + class ULActionAR6 : public ULAction { + public: + EStateID PerformAction(Subject *s, ULEvent& inEvent, ULConnection& inConnection, + bool& outWaitingForEvent, EEventID& outRaisedEvent); + }; + + //Issue P-DATA-TF PDU + //Next State: eSta8WaitLocalRelease + class ULActionAR7 : public ULAction { + public: + EStateID PerformAction(Subject *s, ULEvent& inEvent, ULConnection& inConnection, + bool& outWaitingForEvent, EEventID& outRaisedEvent); + }; + + //Issue A-RELEASE indication (release collision): + //- If association-requestor, next state is eSta9ReleaseCollisionRqLocal + //- if not, next state is eSta10ReleaseCollisionAc + class ULActionAR8 : public ULAction { + public: + EStateID PerformAction(Subject *s, ULEvent& inEvent, ULConnection& inConnection, + bool& outWaitingForEvent, EEventID& outRaisedEvent); + }; + + //Send A-RELEASE-RP PDU + //Next State: eSta11ReleaseCollisionRq + class ULActionAR9 : public ULAction { + public: + EStateID PerformAction(Subject *s, ULEvent& inEvent, ULConnection& inConnection, + bool& outWaitingForEvent, EEventID& outRaisedEvent); + }; + + //Issue A-RELEASE confirmation primitive + //Next State: eSta12ReleaseCollisionAcLocal + class ULActionAR10 : public ULAction { + public: + EStateID PerformAction(Subject *s, ULEvent& inEvent, ULConnection& inConnection, + bool& outWaitingForEvent, EEventID& outRaisedEvent); + }; + } +} +#endif // GDCMULACTIONAR_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmULActionDT.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmULActionDT.cxx new file mode 100644 index 0000000..a982cc7 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmULActionDT.cxx @@ -0,0 +1,247 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +/* +This file contains the implementation for the classes for the DT Actions, +Data Transfer Related Actions (Table 9-8 of ps 3.8-2009). + +Since each class is essentially a placeholder for a function pointer, I'm breaking with having +each class have its own file for the sake of brevity of the number of files. +*/ + +#include "gdcmULActionDT.h" +#include "gdcmARTIMTimer.h" +#include "gdcmPDataTFPDU.h" + +#include "gdcmPDataTFPDU.h" +#include "gdcmAttribute.h" +#include "gdcmProgressEvent.h" +#include "gdcmFile.h" +#include "gdcmDataSet.h" +#include "gdcmAReleaseRPPDU.h" +#include "gdcmAAssociateRQPDU.h" +#include "gdcmAAssociateACPDU.h" +#include "gdcmAReleaseRQPDU.h" +#include "gdcmSubject.h" + +#include //for setting up the local socket + +namespace gdcm +{ +namespace network + { +#if USE_PROCESS_INPUT +static void process_input(iosockinet& sio) +{ + uint8_t itemtype = 0x0; + sio.read( (char*)&itemtype, 1 ); + assert( itemtype == 0x1 ); + + AAssociateRQPDU rqpdu; + //rqpdu.SetCallingAETitle( "MOTESCU" ); + rqpdu.Read( sio ); + rqpdu.Print( std::cout ); + + //std::cout << "done AAssociateRQPDU !" << std::endl; + + TransferSyntaxSub ts1; + ts1.SetNameFromUID( UIDs::ImplicitVRLittleEndianDefaultTransferSyntaxforDICOM ); + + AAssociateACPDU acpdu; + + for( unsigned int index = 0; index < rqpdu.GetNumberOfPresentationContext(); index++ ) + { + // FIXME / HARDCODED We only ever accept Little Endian + // FIXME we should check : + // rqpdu.GetAbstractSyntax() contains LittleENdian + PresentationContextAC pcac1; + PresentationContext const &pc = rqpdu.GetPresentationContext(index); + uint8_t id = pc.GetPresentationContextID(); + + pcac1.SetPresentationContextID( id ); + pcac1.SetTransferSyntax( ts1 ); + acpdu.AddPresentationContextAC( pcac1 ); + } + + acpdu.Write( sio ); + sio.flush(); + + //std::cout << "done AAssociateACPDU !" << std::endl; + + sio.read( (char*)&itemtype, 1 ); + assert( itemtype == 0x4 ); + + PDataTFPDU pdata; + pdata.Read( sio ); + pdata.Print( std::cout ); + // pick the first one: + size_t n = pdata.GetNumPDVs(); + + assert( n == 1 ); + PresentationDataValue const &input_pdv = pdata.GetPresentationDataValue(0); + + //std::cout << "done PDataTFPDU 1!" << std::endl; + + uint8_t messageheader; + messageheader = input_pdv.GetMessageHeader(); + + //std::cout << "Start with MessageHeader : " << (int)messageheader << std::endl; + + Attribute<0x0,0x800> at = { 0 }; + //at.SetFromDataSet( input_pdv.GetDataSet() ); + unsigned short commanddatasettype = at.GetValue(); + //std::cout << "CommandDataSetType: " << at.GetValue() << std::endl; + assert( messageheader == 3 ); + + // C-STORE + if( commanddatasettype == 0 ) + { + std::ofstream out( "movescu.dcm", std::ios::binary ); + int i = 0; + do + { + PDataTFPDU pdata2; + pdata2.ReadInto( sio, out ); + //pdata2.Print( std::cout ); + size_t n2 = pdata.GetNumPDVs(); + assert( n2 == 1 ); + PresentationDataValue const &pdv = pdata2.GetPresentationDataValue(0); + messageheader = pdv.GetMessageHeader(); + //std::cout << "---------------- done PDataTFPDU: " << i << std::endl; + //std::cout << "---------------- done MessageHeader: " << (int)messageheader << std::endl; + ++i; + } + while( messageheader == 0 ); + assert( messageheader == 2 ); // end of data + out.close(); + + PresentationDataValue pdv; + pdv.SetPresentationContextID( input_pdv.GetPresentationContextID() ); + std::vector inpdvs; + inpdvs.push_back( input_pdv ); + DataSet ds1 = PresentationDataValue::ConcatenatePDVBlobs( inpdvs ); + + const DataElement &de1 = ds1.GetDataElement( Tag( 0x0000,0x0002 ) ); + const ByteValue *bv1 = de1.GetByteValue(); + std::string s1( bv1->GetPointer(), bv1->GetLength() ); + const DataElement &de2 = ds1.GetDataElement( Tag( 0x0000,0x1000 ) ); + const ByteValue *bv2 = de2.GetByteValue(); + std::string s2( bv2->GetPointer(), bv2->GetLength() ); + + //pdv.MyInit2( s1.c_str(), s2.c_str() ); + + //std::cout << "Compare:" << std::endl; + //input_pdv.Print( std::cout ); + //std::cout << "To:" << std::endl; + //pdv.Print( std::cout ); + + PDataTFPDU pdata4; + pdata4.AddPresentationDataValue( pdv ); + pdata4.Write( sio ); + //sio.flush(); + } + + //sio.read( (char*)&itemtype, 1 ); + //assert( itemtype == 0x4 ); + //AReleaseRQPDU rel0; + //rel0.Read( sio ); + + // send release: + AReleaseRPPDU rel; + rel.Write( sio ); + sio.flush(); + + //std::cout << "done AReleaseRPPDU!" << std::endl; + + AReleaseRPPDU rel2; + //rel2.Write( sio ); + //sio.flush(); +} +#endif //USE_PROCESS_INPUT +//Send P-DATA-TF PDU +EStateID ULActionDT1::PerformAction(Subject *s, ULEvent& inEvent, ULConnection& inConnection, + bool& outWaitingForEvent, EEventID& outRaisedEvent) +{ + std::vector theDataPDUs = inEvent.GetPDUs(); + std::vector::const_iterator itor = theDataPDUs.begin(); + //they can all be sent at once because of the structure in 3.8 7.6-- pdata + //does not wait for a response. + double Progress = 0; + const double progresstick = 1. / (double)theDataPDUs.size(); + + for (itor = theDataPDUs.begin(); itor < theDataPDUs.end(); itor++) { + + PDataTFPDU* dataPDU = dynamic_cast(*itor); + if (dataPDU == NULL) + { + throw Exception("Data sending event PDU malformed."); + } + dataPDU->Write(*inConnection.GetProtocol()); + Progress += progresstick; + ProgressEvent pe; + pe.SetProgress( Progress ); + s->InvokeEvent( pe ); + + //if( !inConnection.GetProtocol()->good() ); + // { + // throw new Exception("Protocol is not good."); + // return eStaDoesNotExist; + // } + inConnection.GetProtocol()->flush(); + } + + // When doing a C-MOVE we recevie the Requested DataSet over + // another chanel (technically this is send to an SCP) + // in our case we use another port to receive it. + +#if USE_PROCESS_INPUT + //wait for the user to try to send some data. + sockinetbuf sin (sockbuf::sock_stream); + + sin.bind( 5677 ); + + //std::cout << "localhost = " << sin.localhost() << std::endl + // << "localport = " << sin.localport() << std::endl; + + sin.listen(); + +// for(;;) + { + iosockinet s (sin.accept()); + process_input(s); + } +#endif + + + outWaitingForEvent = true;//wait for a response that the data got there. + outRaisedEvent = ePDATArequest; + + return eSta6TransferReady; +} + +//Send P-DATA indication primitive +//for now, does nothing, stops the event loop +EStateID ULActionDT2::PerformAction(Subject *, ULEvent& , ULConnection& , + bool& outWaitingForEvent, EEventID& outRaisedEvent) +{ + outWaitingForEvent = false; + outRaisedEvent = ePDATArequest; + return eSta6TransferReady; +} + +} // end namespace network +} // end namespace gdcm diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmULActionDT.h b/gdcm/Source/MessageExchangeDefinition/gdcmULActionDT.h new file mode 100644 index 0000000..1e9baa4 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmULActionDT.h @@ -0,0 +1,51 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#ifndef GDCMULACTIONDT_H +#define GDCMULACTIONDT_H + +#include "gdcmULAction.h" + +/** +This header defines the classes for the DT Actions, +Data Transfer Related Actions (Table 9-8 of ps 3.8-2009). + +Since each class is essentially a placeholder for a function pointer, I'm breaking with having +each class have its own file for the sake of brevity of the number of files. +*/ + +namespace gdcm { + namespace network { + + //Send P-DATA-TF PDU + //Next state: eSta6TransferReady + class ULActionDT1 : public ULAction { + public: + EStateID PerformAction(Subject *s, ULEvent& inEvent, ULConnection& inConnection, + bool& outWaitingForEvent, EEventID& outRaisedEvent); + }; + + //Send P-DATA indication primitive + //Next state: eSta6TransferReady + class ULActionDT2 : public ULAction { + public: + EStateID PerformAction(Subject *s, ULEvent& inEvent, ULConnection& inConnection, + bool& outWaitingForEvent, EEventID& outRaisedEvent); + }; + } +} +#endif // GDCMULACTIONDT_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmULBasicCallback.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmULBasicCallback.cxx new file mode 100644 index 0000000..3cae28c --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmULBasicCallback.cxx @@ -0,0 +1,46 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ + +#include "gdcmULBasicCallback.h" + +namespace gdcm { +namespace network { + +void ULBasicCallback::HandleDataSet(const DataSet& inDataSet) +{ + mDataSets.push_back(inDataSet); + DataSetHandled(); +} + +std::vector const & ULBasicCallback::GetDataSets() const +{ + return mDataSets; +} + +void ULBasicCallback::HandleResponse(const DataSet& inDataSet) +{ + mResponses.push_back(inDataSet); +} + +std::vector const & ULBasicCallback::GetResponses() const +{ + return mResponses; +} + +} // end namespace network +} // end namespace gdcm diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmULBasicCallback.h b/gdcm/Source/MessageExchangeDefinition/gdcmULBasicCallback.h new file mode 100644 index 0000000..299ce17 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmULBasicCallback.h @@ -0,0 +1,55 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#ifndef GDCMULCONNECTIONBASICCALLBACK_H +#define GDCMULCONNECTIONBASICCALLBACK_H + +#include "gdcmULConnectionCallback.h" +#include "gdcmDataSet.h" +#include + +namespace gdcm +{ + namespace network + { + /** + * \brief ULBasicCallback + * This is the most basic of callbacks for how the ULConnectionManager handles + * incoming datasets. DataSets are just concatenated to the mDataSets vector, + * and the result can be pulled out of the vector by later code. + * Alternatives to this method include progress updates, saving to disk, etc. + * This class is NOT THREAD SAFE. Access the dataset vector after the + * entire set of datasets has been returned by the ULConnectionManager. + */ + class GDCM_EXPORT ULBasicCallback : public ULConnectionCallback + { + std::vector mDataSets; + std::vector mResponses; + public: + ULBasicCallback() {}; + virtual ~ULBasicCallback() {} //empty, for later inheritance + + virtual void HandleDataSet(const DataSet& inDataSet); + virtual void HandleResponse(const DataSet& inDataSet); + + std::vector const & GetDataSets() const; + std::vector const & GetResponses() const; + }; + } // end namespace network +} // end namespace gdcm + +#endif // GDCMULCONNECTIONBASICCALLBACK_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmULConnection.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmULConnection.cxx new file mode 100644 index 0000000..f65bc89 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmULConnection.cxx @@ -0,0 +1,351 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#include "gdcmULConnection.h" + +#include // std::find +#include + +namespace gdcm +{ +namespace network +{ +ULConnection::ULConnection(const ULConnectionInfo& inConnectInfo) +{ + mCurrentState = eSta1Idle; + mSocket = NULL; + mEcho = NULL; + mInfo = inConnectInfo; + + TransferSyntaxSub ts1; + ts1.SetNameFromUID( UIDs::ImplicitVRLittleEndianDefaultTransferSyntaxforDICOM ); + SetCStoreTransferSyntax( ts1 ); +} + +ULConnection::~ULConnection() +{ + if (mEcho != NULL) + { + delete mEcho; + mEcho = NULL; + } + if (mSocket != NULL) + { + delete mSocket; + mSocket = NULL; + } +} + +EStateID ULConnection::GetState() const +{ + return mCurrentState; +} + +void ULConnection::SetState(const EStateID& inState) +{ + mCurrentState = inState; +} + +//echo* ULConnection::GetProtocol(){ +std::iostream* ULConnection::GetProtocol() +{ + if (mEcho) + { + return mEcho; + } + //be careful-- the socket doesn't get removed when the protocol is stopped, + //because then subsequent cstores will break. + if (mSocket) + { + return mSocket; + } + return NULL; +} + +ARTIMTimer& ULConnection::GetTimer() +{ + return mTimer; +} + +const ULConnectionInfo &ULConnection::GetConnectionInfo() const +{ + return mInfo; +} + +void ULConnection::SetMaxPDUSize(uint32_t inSize) +{ + mMaxPDUSize = inSize; +} + +uint32_t ULConnection::GetMaxPDUSize() const +{ + return mMaxPDUSize; +} + +std::vector const & +ULConnection::GetPresentationContexts() const +{ + return mPresentationContexts; +} + +void ULConnection::SetPresentationContexts( + const std::vector& inContexts) +{ + mPresentationContexts.clear(); + for( size_t i = 0; i < inContexts.size(); ++i ) + { + PresentationContext const &in = inContexts[i]; + mPresentationContexts.push_back( in ); + } +} + +void ULConnection::SetPresentationContexts( + const std::vector& inContexts) +{ + mPresentationContexts = inContexts; +} + +std::vector & ULConnection::GetAcceptedPresentationContexts() +{ + return mAcceptedPresentationContexts; +} + +std::vector const & ULConnection::GetAcceptedPresentationContexts() const +{ + return mAcceptedPresentationContexts; +} +void ULConnection::AddAcceptedPresentationContext(const PresentationContextAC& inPC) +{ + mAcceptedPresentationContexts.push_back(inPC); +} + +//given a particular data element, presumably the SOP class, +//find the presentation context for that SOP +//NOT YET IMPLEMENTED +PresentationContextRQ ULConnection::FindContext(const DataElement& ) const +{ + PresentationContextRQ empty; + assert( 0 && "TODO" ); + return empty; +} + +bool ULConnection::InitializeConnection() +{ + try + { + echo* p = new echo(protocol::tcp); + if (GetConnectionInfo().GetCalledIPPort() == 0) + { + if (!GetConnectionInfo().GetCalledComputerName().empty()) + (*p)->connect(GetConnectionInfo().GetCalledComputerName().c_str()); + else + (*p)->connect(GetConnectionInfo().GetCalledIPAddress()); + } + else + { + if (!GetConnectionInfo().GetCalledComputerName().empty()) + (*p)->connect(GetConnectionInfo().GetCalledComputerName().c_str(), + GetConnectionInfo().GetCalledIPPort()); + } + //make sure to convert timeouts to platform appropriate values. + (*p)->recvtimeout((int)GetTimer().GetTimeout()); + (*p)->sendtimeout((int)GetTimer().GetTimeout()); + if (mEcho != NULL) + { + delete mEcho; + mEcho = NULL; + } + if (mSocket != NULL) + { + delete mSocket; + mSocket = NULL; + } + mEcho = p; + } + catch ( sockerr &err ) + { + (void)err; //to avoid unreferenced variable warning on release + gdcmWarningMacro( "Unable to open connection with exception " << err.what() + << std::endl ); + return false; + } + catch (std::exception& ex) + { + (void)ex; //to avoid unreferenced variable warning on release + //unable to establish connection, so break off. + gdcmWarningMacro( "Unable to open connection with exception " << ex.what() + << std::endl ); + return false; + } + return true; +} + +bool ULConnection::InitializeIncomingConnection() +{ + try + { + if (mEcho != NULL) + { + delete mEcho; + mEcho = NULL; + } + if (mSocket != NULL) + { + delete mSocket; + mSocket = NULL; + } + sockinetbuf sin (sockbuf::sock_stream); + // http://hea-www.harvard.edu/~fine/Tech/addrinuse.html + int val = 1; + sin.setopt( SO_REUSEADDR, &val, sizeof(val) ); + sin.bind( mInfo.GetCalledIPPort() ); + //int theRecvTimeout = + sin.recvtimeout(60);//(int)GetTimer().GetTimeout()); + //int theSendTimeout = + sin.sendtimeout(60);//(int)GetTimer().GetTimeout()); + sin.listen(); + //sin.debug( true ); + if (sin.is_readready(60, 0)) + { + mSocket = new iosockinet(sin.accept()); + } + else + { + gdcmDebugMacro( "Call to is_readready failed" ); + SetState(eStaDoesNotExist); + return false; //no connection here, so have to initialize later. + } + SetState(eSta2Open); + + /* + if (mSocket != NULL){ + delete mSocket; + } + mSocket = new protocol(); + sockinetaddr theAddy(GetConnectionInfo().GetCalledComputerName().c_str(), + GetConnectionInfo().GetCalledIPPort()); + mSocket->rdbuf()->connect(theAddy); + mSocket->rdbuf()->recvtimeout((int)GetTimer().GetTimeout()); + mSocket->rdbuf()->sendtimeout((int)GetTimer().GetTimeout()); + */ + } + catch (sockerr& ex) + { + //unable to establish connection, so break off. + (void)ex; //to avoid unreferenced variable warning on release + gdcmErrorMacro("Unable to open connection with exception " << ex.what() << + " and " << ex.operation() << " on port: " << mInfo.GetCalledIPPort() << + std::endl); + return false; + } + catch (std::exception& ex) + { + //unable to establish connection, so break off. + (void)ex; //to avoid unreferenced variable warning on release + gdcmErrorMacro("Unable to open connection with exception " << ex.what() << std::endl); + return false; + } + return true; +} + +void ULConnection::StopProtocol() +{ + if (mEcho != NULL) + { + delete mEcho; + mEcho = NULL; + SetState(eSta1Idle); + } + else + { + //don't actually kill the connection, just kill the association. + //this is just for a cstorescp initialized by a cmove + SetState(eSta2Open); + } +} + +const PresentationContextRQ *ULConnection::GetPresentationContextRQByID(uint8_t id) const +{ + // one day ULConnection will actually use a AAssociateRQPDU as internal implementation + // for now duplicate code from AAssociateRQPDU::GetPresentationContextFromAbstractSyntax + std::vector::const_iterator it = mPresentationContexts.begin(); + for( ; it != mPresentationContexts.end(); ++it) + { + if( it->GetPresentationContextID() == id ) + { + return &*it; + } + } + + return NULL; +} + +const PresentationContextAC *ULConnection::GetPresentationContextACByID(uint8_t id) const +{ + // one day ULConnection will actually use a AAssociateRQPDU as internal implementation + // for now duplicate code from AAssociateRQPDU::GetPresentationContextFromAbstractSyntax + std::vector::const_iterator it = mAcceptedPresentationContexts.begin(); + for( ; it != mAcceptedPresentationContexts.end(); ++it) + { + if( it->GetPresentationContextID() == id ) + { + return &*it; + } + } + + return NULL; +} + +uint8_t ULConnection::GetPresentationContextIDFromPresentationContext(PresentationContextRQ const & pc) const +{ + // one day ULConnection will actually use a AAssociateRQPDU as internal implementation + // for now duplicate code from AAssociateRQPDU::GetPresentationContextIDFromAbstractSyntax + uint8_t ret = 0; + + std::vector::const_iterator it = + std::find( mPresentationContexts.begin(), mPresentationContexts.end(), pc ); + if( it != mPresentationContexts.end() ) + { + ret = it->GetPresentationContextID(); + } + + assert( ret ); + return ret; +} + +void ULConnection::SetCStoreTransferSyntax( TransferSyntaxSub const & ts ) +{ + cstorets = ts; +} + +TransferSyntaxSub const & ULConnection::GetCStoreTransferSyntax( ) const +{ + TransferSyntaxSub ts1; + ts1.SetNameFromUID( UIDs::ImplicitVRLittleEndianDefaultTransferSyntaxforDICOM ); + + TransferSyntaxSub ts2; + ts2.SetNameFromUID( UIDs::ExplicitVRLittleEndian ); + + assert( strcmp(cstorets.GetName(), ts1.GetName()) == 0 + || strcmp(cstorets.GetName(), ts2.GetName()) == 0 + ); + + return cstorets; +} + +} // end namespace network +} // end namespace gdcm diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmULConnection.h b/gdcm/Source/MessageExchangeDefinition/gdcmULConnection.h new file mode 100644 index 0000000..837b7f5 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmULConnection.h @@ -0,0 +1,140 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#ifndef GDCMULCONNECTION_H +#define GDCMULCONNECTION_H + +#include "gdcmNetworkStateID.h" +#include "gdcmARTIMTimer.h" +#include "gdcmULConnectionInfo.h" +#include "gdcmPresentationContextRQ.h" +#include "gdcmDataElement.h" +#include "gdcmPresentationContextAC.h" +#include "gdcmPresentationContext.h" + +class iosockinet; +class echo; +namespace gdcm{ + namespace network{ + +/** + * \brief ULConnection + * This is the class that contains the socket to another machine, and passes + * data through itself, as well as maintaining a sense of state. + * + * The ULConnectionManager tells the ULConnection what data can actually be + * sent. + * + * This class is done this way so that it can be eventually be replaced with a + * ULSecureConnection, if such a protocol is warranted, so that all data that + * passes through can be managed through a secure connection. For now, this + * class provides a simple pass-through mechanism to the socket itself. + * + * So, for instance, a gdcm object will be passes to this object, and it will + * then get passed along the connection, if that connection is in the proper + * state to do so. + * + * For right now, this class is not directly intended to be inherited from, but + * the potential for future ULSecureConnection warrants the addition, rather + * than having everything be managed from within the ULConnectionManager (or + * this class) without a wrapper. + * + */ +class ULConnection +{ + ULConnectionInfo mInfo; + //this is a dirty dirty hack + //but to establish an outgoing connection (scu), we need the echo service + //to establish incoming, we just need a port and localhost, so an iosockinet works while an + //echo would fail (probably because one already exists) + echo* mEcho; + iosockinet* mSocket;//of the three protocols offered by socket++-- echo, smtp, and ftp-- + //echo most closely matches what the DICOM standard describes as a network connection + ARTIMTimer mTimer; + + EStateID mCurrentState; + + std::vector mPresentationContexts; + //this is our list of presentation contexts of what we can send + uint32_t mMaxPDUSize; + + std::vector mAcceptedPresentationContexts;//these come back from the server + //and tell us what can be sent over this connection + + TransferSyntaxSub cstorets; + + friend class ULActionAE6; + void SetCStoreTransferSyntax( TransferSyntaxSub const & ts ); + friend class ULConnectionManager; + TransferSyntaxSub const & GetCStoreTransferSyntax( ) const; + public: + + ULConnection(const ULConnectionInfo& inUserInformation); + //destructors are virtual to prevent memory leaks by inherited classes + virtual ~ULConnection(); + + EStateID GetState() const; + void SetState(const EStateID& inState);//must be able to update state... + + //echo* GetProtocol(); + std::iostream* GetProtocol(); + void StopProtocol(); + + ARTIMTimer& GetTimer(); + + const ULConnectionInfo &GetConnectionInfo() const; + + //when the connection is first associated, the connection is told + //the max packet/PDU size and the way in which to present data + //(presentation contexts, etc). Store that here. + void SetMaxPDUSize(uint32_t inSize); + uint32_t GetMaxPDUSize() const; + + const PresentationContextAC *GetPresentationContextACByID(uint8_t id) const; + const PresentationContextRQ *GetPresentationContextRQByID(uint8_t id) const; + + /// return 0 upon error + uint8_t GetPresentationContextIDFromPresentationContext(PresentationContextRQ const & pc) const; + + std::vector const & GetPresentationContexts() const; + void SetPresentationContexts(const std::vector& inContexts); + + void SetPresentationContexts(const std::vector& inContexts); + + //given a particular data element, presumably the SOP class, + //find the presentation context for that SOP + //NOT YET IMPLEMENTED + PresentationContextRQ FindContext(const DataElement& de) const; + + std::vector const & GetAcceptedPresentationContexts() const; + std::vector & GetAcceptedPresentationContexts(); + void AddAcceptedPresentationContext(const PresentationContextAC& inPC); + + /// used to establish scu connections + bool InitializeConnection(); + + /// used to establish scp connections + bool InitializeIncomingConnection(); +private: + ULConnection(const ULConnection&); // Not implemented. + void operator=(const ULConnection&); // Not implemented. + + }; + } +} + +#endif // ULCONNECTION_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmULConnectionCallback.h b/gdcm/Source/MessageExchangeDefinition/gdcmULConnectionCallback.h new file mode 100644 index 0000000..c21254f --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmULConnectionCallback.h @@ -0,0 +1,58 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#ifndef GDCMULCONNECTIONCALLBACK_H +#define GDCMULCONNECTIONCALLBACK_H + +#include "gdcmTypes.h" //to be able to export the class + +namespace gdcm +{ + class DataSet; + namespace network + { + ///When a dataset comes back from a query/move/etc, the result can either be + ///stored entirely in memory, or could be stored on disk. This class provides + ///a mechanism to indicate what the ULConnectionManager should do with datasets + ///that are produced through query results. + ///The ULConnectionManager will call the HandleDataSet function during the course + ///of receiving datasets. Particular implementations should fill in what that + ///function does, including updating progress, etc. + ///NOTE: since cmove requires that multiple event loops be employed, + ///the callback function MUST set mHandledDataSet to true. + ///otherwise, the cmove event loop handler will not know data was received, and + ///proceed to end the loop prematurely. + class GDCM_EXPORT ULConnectionCallback { + bool mHandledDataSet; + protected: + bool mImplicit; + //inherited callbacks MUST call this function for the cmove loop to work properly + void DataSetHandled() { mHandledDataSet = true; } + public: + ULConnectionCallback():mHandledDataSet(false),mImplicit(true){} + virtual ~ULConnectionCallback() {}; //placeholder for inherited objects + virtual void HandleDataSet(const DataSet& inDataSet) = 0; + virtual void HandleResponse(const DataSet& inDataSet) = 0; + + bool DataSetHandles() const { return mHandledDataSet; } + void ResetHandledDataSet() { mHandledDataSet = false; } + + void SetImplicitFlag( const bool imp ) { mImplicit = imp; } + }; + } +} +#endif //GDCMULCONNECTIONCALLBACK_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmULConnectionInfo.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmULConnectionInfo.cxx new file mode 100644 index 0000000..24850e8 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmULConnectionInfo.cxx @@ -0,0 +1,113 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ + +//this class contains all the information about a particular connection +//as established by the user. That is, it's: +// User Information +// Calling AE Title +// Called AE Title +// IP address/computer name +// IP Port +//A connection must be established with this information, that's subsequently +//placed into various primitives for actual communication. +#include "gdcmULConnectionInfo.h" +#include "gdcmAAssociateRQPDU.h" + +#include //for setting up the local socket + +#if defined(_WIN32) +#else +#include +#include +#include +#include +#endif + +namespace gdcm +{ +namespace network +{ + +ULConnectionInfo::ULConnectionInfo() +{ +} + + //it is possible to misinitialize this object, so + //have it return false if something breaks (ie, given AEs are bigger than 16 characters, + //no name or IP address). +bool ULConnectionInfo::Initialize(UserInformation const & inUserInformation, + const char *inCalledAETitle, const char *inCallingAETitle, + unsigned long inCalledIPAddress, int inCalledIPPort, + std::string inCalledComputerName) +{ + if (inCalledIPAddress == 0 && inCalledComputerName.empty()){ + return false; + } + assert( inCalledAETitle ); + assert( inCallingAETitle ); + assert( AAssociateRQPDU::IsAETitleValid( inCalledAETitle ) ); + assert( AAssociateRQPDU::IsAETitleValid( inCallingAETitle ) ); + const size_t lcalled = strlen( inCalledAETitle ); + const size_t lcalling = strlen( inCallingAETitle ); + mCalledAETitle = std::string(inCalledAETitle, lcalled > 16 ? 16 : lcalled ); + mCallingAETitle = std::string(inCallingAETitle, lcalling > 16 ? 16 : lcalling ); + mCalledComputerName = inCalledComputerName; + mCalledIPPort = inCalledIPPort; + mCalledIPAddress = inCalledIPAddress; + + //test to see if the given computer name is actually an IP address + if (mCalledIPAddress == 0 && !mCalledComputerName.empty()){ + mCalledIPAddress = inet_addr(mCalledComputerName.c_str()); + // if (mCalledIPAddress != 0) + // mCalledComputerName = ""; + } + + //mUserInformation = inUserInformation; + (void)inUserInformation; + return true; +} + +//UserInformation ULConnectionInfo::GetUserInformation() const{ +// return mUserInformation; +//} +const char* ULConnectionInfo::GetCalledAETitle() const{ + return mCalledAETitle.c_str(); +} +const char* ULConnectionInfo::GetCallingAETitle() const{ + return mCallingAETitle.c_str(); +} + +unsigned long ULConnectionInfo::GetCalledIPAddress() const{ + return mCalledIPAddress; +} +int ULConnectionInfo::GetCalledIPPort() const{ + return mCalledIPPort; +} +std::string ULConnectionInfo::GetCalledComputerName() const{ + return mCalledComputerName; +} + +void ULConnectionInfo::SetMaxPDULength(unsigned long inMaxPDULength){ + mMaxPDULength = inMaxPDULength; +} +unsigned long ULConnectionInfo::GetMaxPDULength() const{ + return mMaxPDULength; +} + +} // end namespace network +} // end namespace gdcm diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmULConnectionInfo.h b/gdcm/Source/MessageExchangeDefinition/gdcmULConnectionInfo.h new file mode 100644 index 0000000..88a4211 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmULConnectionInfo.h @@ -0,0 +1,76 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#ifndef GDCMULCONNECTIONINFO_H +#define GDCMULCONNECTIONINFO_H + +#include "gdcmUserInformation.h" +#include + +namespace gdcm{ + namespace network { +/** + * \brief ULConnectionInfo + * this class contains all the information about a particular connection + * as established by the user. That is, it's: + * User Information + * Calling AE Title + * Called AE Title + * IP address/computer name + * IP Port + * A connection must be established with this information, that's subsequently + * placed into various primitives for actual communication. + */ +class ULConnectionInfo { + UserInformation mUserInformation; + + std::string mCalledAETitle; + std::string mCallingAETitle; + + unsigned long mCalledIPAddress; + int mCalledIPPort; + std::string mCalledComputerName; //either the IP or the name has to be filled in + + unsigned long mMaxPDULength; + public: + ULConnectionInfo(); + + //it is possible to misinitialize this object, so + //have it return false if something breaks (ie, given AEs are bigger than 16 characters, + //no name or IP address). + bool Initialize(UserInformation const &inUserInformation, + const char *inCalledAETitle, const char *inCallingAETitle, + unsigned long inCalledIPAddress, int inCalledIPPort, + std::string inCalledComputerName); + + //UserInformation GetUserInformation() const; + const char* GetCalledAETitle() const; + const char* GetCallingAETitle() const; + + unsigned long GetCalledIPAddress() const; + int GetCalledIPPort() const; + std::string GetCalledComputerName() const; + + //CStore needs to know the max pdu length, so the value gets initialized + //when a cstore connection is established (but not for the others). + void SetMaxPDULength(unsigned long inMaxPDULength); + unsigned long GetMaxPDULength() const; + }; + } +} + +#endif //GDCMULCONNECTIONINFO_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmULConnectionManager.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmULConnectionManager.cxx new file mode 100644 index 0000000..75630fe --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmULConnectionManager.cxx @@ -0,0 +1,1105 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#include "gdcmULConnectionManager.h" + +#include "gdcmUserInformation.h" +#include "gdcmULEvent.h" +#include "gdcmPDUFactory.h" +#include "gdcmReader.h" +#include "gdcmAAssociateRQPDU.h" +#include "gdcmAttribute.h" +#include "gdcmBaseRootQuery.h" +#include "gdcmDataSetEvent.h" + +#include "gdcmAReleaseRPPDU.h" + +#include "gdcmULBasicCallback.h" + +#include +#include //for setting up the local socket +#include "gdcmTrace.h" +#include "gdcmPrinter.h" + +namespace gdcm +{ +namespace network +{ + + +ULConnectionManager::ULConnectionManager() +{ + mConnection = NULL; + mSecondaryConnection = NULL; +} + +ULConnectionManager::~ULConnectionManager() +{ + if (mConnection != NULL) + { + delete mConnection; + mConnection = NULL; + } + if (mSecondaryConnection != NULL) + { + delete mSecondaryConnection; + mSecondaryConnection = NULL; + } +} + +bool ULConnectionManager::EstablishConnection(const std::string& inAETitle, + const std::string& inConnectAETitle, + const std::string& inComputerName, long inIPAddress, + unsigned short inConnectPort, double inTimeout, + std::vector const & pcVector) +{ + + //generate a ULConnectionInfo object + UserInformation userInfo; + ULConnectionInfo connectInfo; + if (inConnectAETitle.size() > 16) + return false;//too long an AETitle, probably need better failure message + if (inAETitle.size() > 16) return false; //as above + if (!connectInfo.Initialize(userInfo, inConnectAETitle.c_str(), + inAETitle.c_str(), inIPAddress, inConnectPort, inComputerName)) + { + return false; + } + + if (mConnection != NULL) + { + delete mConnection; + } + mConnection = new ULConnection(connectInfo); + + mConnection->GetTimer().SetTimeout(inTimeout); + + // Warning PresentationContextID is important + // this is a sort of uniq key used by the recevier. Eg. + // if one push_pack + // (1, Secondary) + // (1, Verification) + // Then the last one is prefered (DCMTK 3.5.5) + + // The following only works for C-STORE / C-ECHO + // however it does not make much sense to add a lot of abstract syntax + // when doing only C-ECHO. + // FIXME is there a way to know here if we are in C-ECHO ? + //there is now! + //the presentation context will now be part of the connection, so that this + //initialization for the association-rq will use parameters from the connection + + +#if 0 + AbstractSyntax as; + std::vector pcVector; + PresentationContextRQ pc; + TransferSyntaxSub ts; + ts.SetNameFromUID( UIDs::ImplicitVRLittleEndianDefaultTransferSyntaxforDICOM ); + pc.AddTransferSyntax( ts ); + ts.SetNameFromUID( UIDs::ExplicitVRLittleEndian ); + //ts.SetNameFromUID( UIDs::JPEGLosslessNonHierarchicalFirstOrderPredictionProcess14SelectionValue1DefaultTransferSyntaxforLosslessJPEGImageCompression); + //pc.AddTransferSyntax( ts ); // we do not support explicit (mm) + switch (inConnectionType){ + case eEcho: + pc.SetPresentationContextID( eVerificationSOPClass ); + as.SetNameFromUID( UIDs::VerificationSOPClass ); + pc.SetAbstractSyntax( as ); + pcVector.push_back(pc); + break; + case eFind: + pc.SetPresentationContextID( ePatientRootQueryRetrieveInformationModelFIND ); + as.SetNameFromUID( UIDs::PatientRootQueryRetrieveInformationModelFIND ); + pc.SetAbstractSyntax( as ); + pcVector.push_back(pc); + pc.SetPresentationContextID(eStudyRootQueryRetrieveInformationModelFIND ); + as.SetNameFromUID( UIDs::StudyRootQueryRetrieveInformationModelFIND ); + pc.SetAbstractSyntax( as ); + pcVector.push_back(pc); + pc.SetPresentationContextID( ePatientStudyOnlyQueryRetrieveInformationModelFINDRetired ); + as.SetNameFromUID( UIDs::PatientStudyOnlyQueryRetrieveInformationModelFINDRetired ); + pc.SetAbstractSyntax( as ); + pcVector.push_back(pc); + pc.SetPresentationContextID( eModalityWorklistInformationModelFIND ); + as.SetNameFromUID( UIDs::ModalityWorklistInformationModelFIND ); + pc.SetAbstractSyntax( as ); + pcVector.push_back(pc); + pc.SetPresentationContextID( eGeneralPurposeWorklistInformationModelFIND ); + as.SetNameFromUID( UIDs::GeneralPurposeWorklistInformationModelFIND ); + pc.SetAbstractSyntax( as ); + pcVector.push_back(pc); + break; + //our spec does not require C-GET support +// case eGet: +// break; +/* case eMove: + // should we also send stuff from FIND ? + // E: Move PresCtx but no Find (accepting for now) + pc.SetPresentationContextID( ePatientRootQueryRetrieveInformationModelFIND ); + as.SetNameFromUID( UIDs::PatientRootQueryRetrieveInformationModelFIND ); + pc.SetAbstractSyntax( as ); + pcVector.push_back(pc); + // move + pc.SetPresentationContextID( ePatientRootQueryRetrieveInformationModelMOVE ); + as.SetNameFromUID( UIDs::PatientRootQueryRetrieveInformationModelMOVE ); + pc.SetAbstractSyntax( as ); + pcVector.push_back(pc); + pc.SetPresentationContextID( eStudyRootQueryRetrieveInformationModelFIND ); + as.SetNameFromUID( UIDs::StudyRootQueryRetrieveInformationModelFIND ); + pc.SetAbstractSyntax( as ); + pcVector.push_back(pc); + pc.SetPresentationContextID( eStudyRootQueryRetrieveInformationModelMOVE ); + as.SetNameFromUID( UIDs::StudyRootQueryRetrieveInformationModelMOVE ); + pc.SetAbstractSyntax( as ); + pcVector.push_back(pc); + break;*/ + case eStore: + std::string uidName; + pc.SetPresentationContextID( PresentationContextRQ::AssignPresentationContextID(inDS, uidName) ); + if (pc.GetPresentationContextID() != eVerificationSOPClass){ + as.SetNameFromUIDString( uidName ); + pc.SetAbstractSyntax( as ); + pcVector.push_back(pc); + } + break; + } + if (pcVector.empty()){ + gdcmWarningMacro("Unable to establish presentation context; ensure that dataset has tags 0x8,0x16 and 0x8,0x18 defined." <SetPresentationContexts(pcVector); + + + //now, try to establish a connection by starting the transition table and the event loop. + //here's the thing + //if there's nothing on the event loop, assume that it's done & the function can exit. + //otherwise, keep rolling the event loop + ULEvent theEvent(eAASSOCIATERequestLocalUser, NULL); + //no callback, assume that no data is transferred back, because there shouldn't be any + EStateID theState = RunEventLoop(theEvent, mConnection, NULL, false); + + if(theState != eSta6TransferReady) + { + std::vector const & thePDUs = theEvent.GetPDUs(); + for( std::vector::const_iterator itor + = thePDUs.begin(); itor != thePDUs.end(); itor++) + { + //assert(*itor); + if (*itor == NULL) continue; //can have a nulled pdu, apparently + (*itor)->Print(Trace::GetErrorStream()); + } + } + else if (Trace::GetDebugFlag()) + { + std::vector const & thePDUs = theEvent.GetPDUs(); + for( std::vector::const_iterator itor + = thePDUs.begin(); itor != thePDUs.end(); itor++) + { + assert(*itor); + if (*itor == NULL) continue; //can have a nulled pdu, apparently + (*itor)->Print(Trace::GetDebugStream()); + } + } + + return (theState == eSta6TransferReady);//ie, finished the transitions +} + + + +/// returns true for above reasons, but contains the special 'move' port +bool ULConnectionManager::EstablishConnectionMove(const std::string& inAETitle, + const std::string& inConnectAETitle, + const std::string& inComputerName, long inIPAddress, + uint16_t inConnectPort, double inTimeout, + uint16_t inReturnPort, + std::vector const & pcVector) +{ + gdcmDebugMacro( "Start EstablishConnectionMove" ); + //generate a ULConnectionInfo object + UserInformation userInfo; + ULConnectionInfo connectInfo; + if (inConnectAETitle.size() > 16) return false;//too long an AETitle, probably need better failure message + if (inAETitle.size() > 16) return false; //as above + if (!connectInfo.Initialize(userInfo,inAETitle.c_str(), inConnectAETitle.c_str(), + inIPAddress, inReturnPort, inComputerName)) + { + gdcmDebugMacro( "Could not Initialize connectInfo" ); + return false; + } + gdcmDebugMacro( "SCP: First connection established on port " << inReturnPort ); + + if (mSecondaryConnection != NULL) + { + gdcmDebugMacro( "delete mSecondaryConnection" ); + delete mSecondaryConnection; + } + mSecondaryConnection = new ULConnection(connectInfo); + mSecondaryConnection->GetTimer().SetTimeout(inTimeout); + + //generate a ULConnectionInfo object + UserInformation userInfo2; + ULConnectionInfo connectInfo2; + if (inConnectAETitle.size() > 16) return false;//too long an AETitle, probably need better failure message + if (inAETitle.size() > 16) return false; //as above + if (!connectInfo2.Initialize(userInfo2, inConnectAETitle.c_str(), + inAETitle.c_str(), inIPAddress, inConnectPort, inComputerName)) + { + gdcmDebugMacro( "Could not Initialize connectInfo2" ); + return false; + } + gdcmDebugMacro( "SCU: Second connection established on port " << inConnectPort ); + + if (mConnection!= NULL) + { + gdcmDebugMacro( "delete mConnection" ); + delete mConnection; + } + mConnection = new ULConnection(connectInfo2); + mConnection->GetTimer().SetTimeout(inTimeout); + + + // Warning PresentationContextID is important + // this is a sort of uniq key used by the recevier. Eg. + // if one push_pack + // (1, Secondary) + // (1, Verification) + // Then the last one is prefered (DCMTK 3.5.5) + + // The following only works for C-STORE / C-ECHO + // however it does not make much sense to add a lot of abstract syntax + // when doing only C-ECHO. + // FIXME is there a way to know here if we are in C-ECHO ? + //there is now! + //the presentation context will now be part of the connection, so that this + //initialization for the association-rq will use parameters from the connection + + AbstractSyntax as; + +#if 0 + std::vector pcVector; + PresentationContextRQ pc; + TransferSyntaxSub ts; + ts.SetNameFromUID( UIDs::ImplicitVRLittleEndianDefaultTransferSyntaxforDICOM ); + pc.AddTransferSyntax( ts ); + ts.SetNameFromUID( UIDs::ExplicitVRLittleEndian ); + //pc.AddTransferSyntax( ts ); // we do not support explicit (mm) + // should we also send stuff from FIND ? + // E: Move PresCtx but no Find (accepting for now) + pc.SetPresentationContextID( ePatientRootQueryRetrieveInformationModelFIND ); + as.SetNameFromUID( UIDs::PatientRootQueryRetrieveInformationModelFIND ); + pc.SetAbstractSyntax( as ); + pcVector.push_back(pc); + // move + pc.SetPresentationContextID( ePatientRootQueryRetrieveInformationModelMOVE ); + as.SetNameFromUID( UIDs::PatientRootQueryRetrieveInformationModelMOVE ); + pc.SetAbstractSyntax( as ); + pcVector.push_back(pc); + pc.SetPresentationContextID( eStudyRootQueryRetrieveInformationModelFIND ); + as.SetNameFromUID( UIDs::StudyRootQueryRetrieveInformationModelFIND ); + pc.SetAbstractSyntax( as ); + pcVector.push_back(pc); + pc.SetPresentationContextID( eStudyRootQueryRetrieveInformationModelMOVE ); + as.SetNameFromUID( UIDs::StudyRootQueryRetrieveInformationModelMOVE ); + pc.SetAbstractSyntax( as ); + pcVector.push_back(pc); +#endif + mConnection->SetPresentationContexts(pcVector); + + + //now, try to establish a connection by starting the transition table and the event loop. + //here's the thing + //if there's nothing on the event loop, assume that it's done & the function can exit. + //otherwise, keep rolling the event loop + ULEvent theEvent(eAASSOCIATERequestLocalUser, NULL); + std::vector empty; + //No data should be returned when connections are established + EStateID theState = RunEventLoop(theEvent, mConnection, NULL, false); + + if (Trace::GetDebugFlag()) + { + std::vector thePDUs = theEvent.GetPDUs(); + std::vector::iterator itor; + for (itor = thePDUs.begin(); itor != thePDUs.end(); itor++) + { + if (*itor == NULL) continue; //can have a nulled pdu, apparently + (*itor)->Print(Trace::GetStream()); + } + } + + return (theState == eSta6TransferReady);//ie, finished the transitions +} + +//send the Data PDU associated with Echo (ie, a default DataPDU) +//this lets the user confirm that the connection is alive. +//the user should look to cout to see the response of the echo command +std::vector ULConnectionManager::SendEcho(){ + + std::vector theDataPDU = PDUFactory::CreateCEchoPDU(*mConnection);//pass NULL for C-Echo + ULEvent theEvent(ePDATArequest, theDataPDU); + + EStateID theState = RunEventLoop(theEvent, mConnection, NULL, false); + //theEvent should contain the PDU for the echo! + + if (theState == eSta6TransferReady){//ie, finished the transitions + return PDUFactory::GetPDVs(theEvent.GetPDUs()); + } else { + std::vector empty; + return empty; + } +} + +std::vector ULConnectionManager::SendMove(const BaseRootQuery* inRootQuery) +{ + ULBasicCallback theCallback; + SendMove(inRootQuery, &theCallback); + return theCallback.GetDataSets(); +} + +bool ULConnectionManager::SendMove(const BaseRootQuery* inRootQuery, + ULConnectionCallback* inCallback) +{ + if (mConnection == NULL) + { + gdcmErrorMacro( "mConnection is NULL" ); + return false; + } + std::vector theDataPDU = PDUFactory::CreateCMovePDU( *mConnection, inRootQuery ); + ULEvent theEvent(ePDATArequest, theDataPDU); + EStateID stateid = RunMoveEventLoop(theEvent, inCallback); + gdcmDebugMacro( "Final StateID: " << (int) stateid ); + return stateid == gdcm::network::eSta6TransferReady; +} + +std::vector ULConnectionManager::SendFind(const BaseRootQuery* inRootQuery) +{ + ULBasicCallback theCallback; + SendFind(inRootQuery, &theCallback); + return theCallback.GetDataSets(); +} + +void ULConnectionManager::SendFind(const BaseRootQuery* inRootQuery, ULConnectionCallback* inCallback) +{ + if (mConnection == NULL) + { + return; + } + std::vector theDataPDU = PDUFactory::CreateCFindPDU( *mConnection, inRootQuery ); + ULEvent theEvent(ePDATArequest, theDataPDU); + RunEventLoop(theEvent, mConnection, inCallback, false); +} + +std::vector ULConnectionManager::SendStore(const File &file) +{ + ULBasicCallback theCallback; + SendStore(file, &theCallback); + return theCallback.GetResponses(); +} + +void ULConnectionManager::SendStore(const File & file, ULConnectionCallback* inCallback) +{ + if (mConnection == NULL) + { + return; + } + std::vector theDataPDU = PDUFactory::CreateCStoreRQPDU(*mConnection, file); + const DataSet* inDataSet = &file.GetDataSet(); + DataSetEvent dse( inDataSet ); + this->InvokeEvent( dse ); + + ULEvent theEvent(ePDATArequest, theDataPDU); + EStateID theState = RunEventLoop(theEvent, mConnection, inCallback, false); + assert( theState == eSta6TransferReady || theState == eStaDoesNotExist ); (void)theState; +} + +bool ULConnectionManager::BreakConnection(const double& inTimeOut){ + std::vector theResult; + if (mConnection == NULL){ + return false; + } + BasePDU* thePDU = PDUFactory::ConstructReleasePDU(); + ULEvent theEvent(eARELEASERequest, thePDU); + mConnection->GetTimer().SetTimeout(inTimeOut); + + //assume no data coming back when dying, no need for callback + EStateID theState = RunEventLoop(theEvent, mConnection, NULL, false); + + return (theState == eSta1Idle);//ie, finished the transitions +} + +void ULConnectionManager::BreakConnectionNow(){ + BasePDU* thePDU = PDUFactory::ConstructAbortPDU(); + ULEvent theEvent(eAABORTRequest, thePDU); + + //assume no data coming back when dying, no need for callback + EStateID theState = RunEventLoop(theEvent, mConnection, NULL, false); + (void)theState; +} + +//event handler loop for move-- will interweave the two event loops, +//one for storescp and the other for movescu. Perhaps complicated, but +//avoids starting a second process. +EStateID ULConnectionManager::RunMoveEventLoop(ULEvent& currentEvent, ULConnectionCallback* inCallback){ + gdcmDebugMacro( "Start RunMoveEventLoop" ); + EStateID theState = eStaDoesNotExist; + bool waitingForEvent; + EEventID raisedEvent; + + bool receivingData = false; + bool justWaiting = false; + //when receiving data from a find, etc, then justWaiting is true and only receiving is done + //eventually, could add cancel into the mix... but that would be through a callback or something similar + do { + gdcmDebugMacro( "Before mTransitions.HandleEvent" ); + if (!justWaiting){ + mTransitions.HandleEvent(this,currentEvent, *mConnection, waitingForEvent, raisedEvent); + } + + theState = mConnection->GetState(); + std::istream &is = *mConnection->GetProtocol(); + //std::ostream &os = *mConnection->GetProtocol(); + + + //When doing a C-MOVE we receive the Requested DataSet over + //another channel (technically this is send to an SCP) + //in our case we use another port to receive it. + EStateID theCStoreStateID = eSta6TransferReady; + bool secondConnectionEstablished = false; + gdcmDebugMacro( "Before mSecondaryConnection.GetProtocol" ); + if (mSecondaryConnection->GetProtocol() == NULL){ + //establish the connection + //can fail if is_readready doesn't return true, ie, the connection + //wasn't opened on the other side because the other side isn't sending data yet + //for whatever reason (maybe there's nothing to get?) + gdcmDebugMacro( "Before mSecondaryConnection.InitializeIncomingConnection" ); + secondConnectionEstablished = + mSecondaryConnection->InitializeIncomingConnection(); + } + gdcmDebugMacro( "After mSecondaryConnection.InitializeIncomingConnection: " << + "secondConnectionEstablished=" << secondConnectionEstablished << + " GetState() =" << (int)mSecondaryConnection->GetState() + ); + if (!secondConnectionEstablished ) + { + gdcmErrorMacro( "Could not establish 2nd connection" ); + //return eStaDoesNotExist; + } + if (secondConnectionEstablished && + (mSecondaryConnection->GetState()== eSta1Idle || + mSecondaryConnection->GetState() == eSta2Open)){ + ULEvent theCStoreEvent(eEventDoesNotExist, NULL);//have to fill this in, we're in passive mode now + theCStoreStateID = RunEventLoop(theCStoreEvent, mSecondaryConnection, inCallback, true); + } + gdcmDebugMacro( "After mSecondaryConnection / RunEventLoop: " << (int)theCStoreStateID ); + + //just as for the regular event loop, but we have to alternate between the connections. + //it may be that nothing comes back over the is connection, but lots over the + //isSCP connection. So, if is fails, meh. But if isSCP fails, that's not so meh. + //we care only about the datasets coming back from isSCP, ultimately, though the datasets + //from is will contain progress info. + std::vector incomingPDUs; + if (waitingForEvent){ + while (waitingForEvent) + {//loop for reading in the events that come down the wire + uint8_t itemtype = 0x0; + gdcmDebugMacro( "Waiting for ItemType (#2)" ); + is.read( (char*)&itemtype, 1 ); + + BasePDU* thePDU = PDUFactory::ConstructPDU(itemtype); + if (thePDU != NULL) + { + incomingPDUs.push_back(thePDU); + thePDU->Read(is); + gdcmDebugMacro("PDU code: " << static_cast(itemtype) << std::endl); + if (Trace::GetDebugFlag()) + { + thePDU->Print(Trace::GetStream()); + } + if (thePDU->IsLastFragment()) waitingForEvent = false; + } + else + { + waitingForEvent = false; //because no PDU means not waiting anymore + } + } + //now, we have to figure out the event that just happened based on the PDU that was received. + if (!incomingPDUs.empty()) + { + currentEvent.SetEvent(PDUFactory::DetermineEventByPDU(incomingPDUs[0])); + currentEvent.SetPDU(incomingPDUs); + if (mConnection->GetTimer().GetHasExpired()) + { + currentEvent.SetEvent(eARTIMTimerExpired); + } + if (theState == eSta6TransferReady){//ie, finished the transitions + //with find, the results now come down the wire. + //the pdu we already have from the event will tell us how many to expect. + uint32_t pendingDE1, pendingDE2, success, theVal; + pendingDE1 = 0xff01; + pendingDE2 = 0xff00; + success = 0x0000; + theVal = pendingDE1; + uint32_t theNumLeft = 0; // the number of pending sub operations left. + //so here's the thing: dcmtk responds with 'success' as it first cmove rsp + //which is retarded and, I think, wrong. However, dcm4chee responds with 'pending' + //so, we look either for pending, or for the number of operations left + // (tag 0000, 1020) if the value is success, and that number should be 0. + DataSet theRSP = PresentationDataValue::ConcatenatePDVBlobs(PDUFactory::GetPDVs(currentEvent.GetPDUs())); + if (Trace::GetDebugFlag()) + { + Printer thePrinter; + Trace::GetStream() << "Response: " << std::endl; + thePrinter.PrintDataSet(theRSP, Trace::GetStream()); + Trace::GetStream() << std::endl; + } + if (theRSP.FindDataElement(Tag(0x0, 0x0800))){ + DataElement const & de = theRSP.GetDataElement(Tag(0x0,0x0800)); + Attribute<0x0,0x0800> at; + at.SetFromDataElement( de ); + unsigned short datasettype = at.GetValue(); + assert( datasettype == 0x0101 || datasettype == 0x1 ); (void)datasettype; + } + if (theRSP.FindDataElement(Tag(0x0, 0x0900))){ + DataElement const & de = theRSP.GetDataElement(Tag(0x0,0x0900)); + Attribute<0x0,0x0900> at; + at.SetFromDataElement( de ); + theVal = at.GetValues()[0]; + //if theVal is Pending or Success, then we need to enter the loop below, + //because we need the data PDUs. + //so, the loop below is a do/while loop; there should be at least a second packet + //with the dataset, even if the status is 'success' + //success == 0000H + } + uint32_t theCommandCode = 0; + if (theRSP.FindDataElement(Tag(0x0,0x0100))){ + DataElement const & de = theRSP.GetDataElement(Tag(0x0,0x0100)); + Attribute<0x0,0x0100> at; + at.SetFromDataElement( de ); + theCommandCode = at.GetValues()[0]; + } + if (theRSP.FindDataElement(Tag(0x0, 0x1020))){ + DataElement de = theRSP.GetDataElement(Tag(0x0,0x1020)); + Attribute<0x0,0x1020> at; + at.SetFromDataElement( de ); + theNumLeft = at.GetValues()[0]; + //if theVal is Pending or Success, then we need to enter the loop below, + //because we need the data PDUs. + //so, the loop below is a do/while loop; there should be at least a second packet + //with the dataset, even if the status is 'success' + //success == 0000H + } + if (theVal != pendingDE1 && theVal != pendingDE2 && theVal != success){ + //check for other error fields + const ByteValue *err1 = NULL, *err2 = NULL; + gdcmErrorMacro( "Transfer failed with code " << theVal << std::endl); + switch (theVal){ + case 0xA701: + gdcmErrorMacro( "Refused: Out of Resources Unable to calculate number of matches" << std::endl); + break; + case 0xA702: + gdcmErrorMacro( "Refused: Out of Resources Unable to perform sub-operations" << std::endl); + break; + case 0xA801: + gdcmErrorMacro( "Refused: Move Destination unknown" << std::endl); + break; + case 0xA900: + gdcmErrorMacro( "Identifier does not match SOP Class" << std::endl); + break; + case 0xAA00: + gdcmErrorMacro( "None of the frames requested were found in the SOP Instance" << std::endl); + break; + case 0xAA01: + gdcmErrorMacro( "Unable to create new object for this SOP class" << std::endl); + break; + case 0xAA02: + gdcmErrorMacro( "Unable to extract frames" << std::endl); + break; + case 0xAA03: + gdcmErrorMacro( "Time-based request received for a non-time-based original SOP Instance. " << std::endl); + break; + case 0xAA04: + gdcmErrorMacro( "Invalid Request" << std::endl); + break; + case 0xFE00: + gdcmErrorMacro( "Sub-operations terminated due to Cancel Indication" << std::endl); + break; + case 0xB000: + gdcmErrorMacro( "Sub-operations Complete One or more Failures or Warnings" << std::endl); + break; + default: + gdcmErrorMacro( "Unable to process" << std::endl); + break; + } + if (theRSP.FindDataElement(Tag(0x0,0x0901))){ + DataElement de = theRSP.GetDataElement(Tag(0x0,0x0901)); + err1 = de.GetByteValue(); + gdcmErrorMacro( " Tag 0x0,0x901 reported as " << *err1 << std::endl); (void)err1; + } + if (theRSP.FindDataElement(Tag(0x0,0x0902))){ + DataElement de = theRSP.GetDataElement(Tag(0x0,0x0902)); + err2 = de.GetByteValue(); + gdcmErrorMacro( " Tag 0x0,0x902 reported as " << *err2 << std::endl); (void)err2; + } + } + receivingData = false; + justWaiting = false; + if (theVal == pendingDE1 || theVal == pendingDE2 || (theVal == success && theNumLeft != 0)) { + receivingData = true; //wait for more data as more PDUs (findrsps, for instance) + justWaiting = true; + waitingForEvent = true; + + //ok, if we're pending, then let's open the cstorescp connection here + //(if it's not already open), and then from here start a storescp event loop. + //just don't listen to the cmove event loop until this is done. + //could cause a pileup on the main connection, I suppose. + //could also report the progress here, if we liked. + if (theCommandCode == 0x8021){//cmove response, so prep the retrieval loop on the back connection + + bool dataSetCountIncremented = true;//false once the number of incoming datasets doesn't change. + if (mSecondaryConnection->GetProtocol() == NULL){ + //establish the connection + //can fail if is_readready doesn't return true, ie, the connection + //wasn't opened on the other side because the other side isn't sending data yet + //for whatever reason (maybe there's nothing to get?) + secondConnectionEstablished = + mSecondaryConnection->InitializeIncomingConnection(); + if (secondConnectionEstablished && + (mSecondaryConnection->GetState()== eSta1Idle || + mSecondaryConnection->GetState() == eSta2Open)){ + ULEvent theCStoreEvent(eEventDoesNotExist, NULL);//have to fill this in, we're in passive mode now + theCStoreStateID = RunEventLoop(theCStoreEvent, mSecondaryConnection, inCallback, true); + } else {//something broke, can't establish secondary move connection here + gdcmErrorMacro( "Unable to establish secondary connection with server, aborting." << std::endl); + return eStaDoesNotExist; + } + } + if (secondConnectionEstablished){ + while (theCStoreStateID == eSta6TransferReady && dataSetCountIncremented){ + ULEvent theCStoreEvent(eEventDoesNotExist, NULL);//have to fill this in, we're in passive mode now + //now, get data from across the network + theCStoreStateID = RunEventLoop(theCStoreEvent, mSecondaryConnection, inCallback, true); + if (inCallback){ + dataSetCountIncremented = true; + inCallback->ResetHandledDataSet(); + } else { + dataSetCountIncremented = false; + } + } + } + //force the abort from our side + // ULEvent theCStoreEvent(eAABORTRequest, NULL);//have to fill this in, we're in passive mode now + // theCStoreStateID = RunEventLoop(theCStoreEvent, outDataSet, mSecondaryConnection, true); + } else {//not dealing with cmove progress updates, apparently + //keep looping if we haven't succeeded or failed; these are the values for 'pending' + //first, dynamically cast that pdu in the event + //should be a data pdu + //then, look for tag 0x0,0x900 + + //only add datasets that are _not_ part of the network response + std::vector final; + std::vector theData; + BasePDU* thePDU;//outside the loop for the do/while stopping condition + bool interrupted = false; + do { + uint8_t itemtype = 0x0; + is.read( (char*)&itemtype, 1 ); + //what happens if nothing's read? + thePDU = PDUFactory::ConstructPDU(itemtype); + if (itemtype != 0x4 && thePDU != NULL){ //ie, not a pdatapdu + std::vector interruptingPDUs; + currentEvent.SetEvent(PDUFactory::DetermineEventByPDU(interruptingPDUs[0])); + currentEvent.SetPDU(interruptingPDUs); + interrupted= true; + break; + } + if (thePDU != NULL){ + thePDU->Read(is); + theData.push_back(thePDU); + } else{ + break; + } + //!!!need to handle incoming PDUs that are not data, ie, an abort + } while(/*!is.eof() &&*/ !thePDU->IsLastFragment()); + if (!interrupted){//ie, if the remote server didn't hang up + DataSet theCompleteFindResponse = + PresentationDataValue::ConcatenatePDVBlobs(PDUFactory::GetPDVs(theData)); + //note that it's the responsibility of the event to delete the PDU in theFindRSP + for (size_t i = 0; i < theData.size(); i++){ + delete theData[i]; + } + //outDataSet.push_back(theCompleteFindResponse); + if (inCallback){ + inCallback->HandleDataSet(theCompleteFindResponse); + } + } + } + } + } + } else { + raisedEvent = eEventDoesNotExist; + waitingForEvent = false; + } + } + else { + currentEvent.SetEvent(raisedEvent);//actions that cause transitions in the state table + //locally just raise local events that will therefore cause the trigger to be pulled. + } + } while (currentEvent.GetEvent() != eEventDoesNotExist && + theState != eStaDoesNotExist && theState != eSta13AwaitingClose && theState != eSta1Idle && + (theState != eSta6TransferReady || (theState == eSta6TransferReady && receivingData ))); + //stop when the AE is done, or when ready to transfer data (ie, the next PDU should be sent in), + //or when the connection is idle after a disconnection. + //or, if in state 6 and receiving data, until all data is received. + + return theState; +} + + +//event handler loop. +//will just keep running until the current event is nonexistent. +//at which point, it will return the current state of the connection +//to do this, execute an event, and then see if there's a response on the +//incoming connection (with a reasonable amount of timeout). +//if no response, assume that the connection is broken. +//if there's a response, then yay. +//note that this is the ARTIM timeout event +EStateID ULConnectionManager::RunEventLoop(ULEvent& currentEvent, ULConnection* inWhichConnection, + ULConnectionCallback* inCallback, const bool& startWaiting = false){ + gdcmDebugMacro( "Start RunEventLoop" ); + EStateID theState = eStaDoesNotExist; + bool waitingForEvent = startWaiting;//overwritten if not starting waiting, but if waiting, then wait + EEventID raisedEvent; + + bool receivingData = false; + //bool justWaiting = startWaiting; + //not sure justwaiting is useful; for now, go back to waiting for event + + //when receiving data from a find, etc, then justWaiting is true and only receiving is done + //eventually, could add cancel into the mix... but that would be through a callback or something similar + do { + gdcmDebugMacro( "Before mTransitions.HandleEvent #2" ); + raisedEvent = eEventDoesNotExist; + if (!waitingForEvent){//justWaiting){ + mTransitions.HandleEvent(this, currentEvent, *inWhichConnection, waitingForEvent, raisedEvent); + //this gathering of the state is for scus that have just sent out a request + theState = inWhichConnection->GetState(); + } + std::istream &is = *inWhichConnection->GetProtocol(); + //std::ostream &os = *inWhichConnection->GetProtocol(); + + BasePDU* theFirstPDU = NULL;// the first pdu read in during this event loop, + //used to make sure the presentation context ID is correct + + //read the connection, as that's an event as well. + //waiting for an object to come back across the connection, so that it can get handled. + //ie, accept, reject, timeout, etc. + //of course, if the connection is down, just leave the loop. + //also leave the loop if nothing's waiting. + //use the PDUFactory to create the appropriate pdu, which has its own + //internal mechanisms for handling itself (but will, of course, be put inside the event object). + //but, and here's the important thing, only read on the socket when we should. + std::vector incomingPDUs; + if (waitingForEvent){ + while (waitingForEvent){//loop for reading in the events that come down the wire + uint8_t itemtype = 0x0; + try { + gdcmDebugMacro( "Waiting for ItemType" ); + is.read( (char*)&itemtype, 1 ); + gdcmDebugMacro( "Received ItemType #" << (int)itemtype ); + //what happens if nothing's read? + theFirstPDU = PDUFactory::ConstructPDU(itemtype); + if (theFirstPDU != NULL){ + incomingPDUs.push_back(theFirstPDU); + theFirstPDU->Read(is); + gdcmDebugMacro("PDU code: " << static_cast(itemtype) << std::endl); + if (Trace::GetDebugFlag()) + { + theFirstPDU->Print(Trace::GetStream()); + } + + if (theFirstPDU->IsLastFragment()) waitingForEvent = false; + } else { + gdcmDebugMacro( "NULL theFirstPDU for ItemType" << (int)itemtype ); + waitingForEvent = false; //because no PDU means not waiting anymore + return eStaDoesNotExist; + } + } + catch (...) + { + //handle the exception, which is basically that nothing came in over the pipe. + gdcmAssertAlwaysMacro( 0 ); + } + } + //now, we have to figure out the event that just happened based on the PDU that was received. + //this state gathering is for scps, especially the cstore for cmove. + theState = inWhichConnection->GetState(); + if (!incomingPDUs.empty()){ + currentEvent.SetEvent(PDUFactory::DetermineEventByPDU(incomingPDUs[0])); + currentEvent.SetPDU(incomingPDUs); + //here's the scp handling code + if (mConnection->GetTimer().GetHasExpired()){ + currentEvent.SetEvent(eARTIMTimerExpired); + } + switch(currentEvent.GetEvent()){ + case ePDATATFPDU: + { + //if (theState == eSta6TransferReady){//ie, finished the transitions + //with find, the results now come down the wire. + //the pdu we already have from the event will tell us how many to expect. + uint32_t pendingDE1, pendingDE2, success, theVal; + pendingDE1 = 0xff01; + pendingDE2 = 0xff00; + success = 0x0000; + theVal = pendingDE1; + uint32_t theCommandCode = 0;//for now, a nothing value + DataSet theRSP = + PresentationDataValue::ConcatenatePDVBlobs( + PDUFactory::GetPDVs(currentEvent.GetPDUs())); + if (inCallback) + { + inCallback->HandleResponse(theRSP); + } + + if (theRSP.FindDataElement(Tag(0x0, 0x0900))){ + DataElement de = theRSP.GetDataElement(Tag(0x0,0x0900)); + Attribute<0x0,0x0900> at; + at.SetFromDataElement( de ); + theVal = at.GetValues()[0]; + //if theVal is Pending or Success, then we need to enter the loop below, + //because we need the data PDUs. + //so, the loop below is a do/while loop; there should be at least a second packet + //with the dataset, even if the status is 'success' + //success == 0000H + } + if (Trace::GetDebugFlag()) + { + Printer thePrinter; + thePrinter.PrintDataSet(theRSP, Trace::GetStream()); + } + + //check to see if this is a cstorerq + if (theRSP.FindDataElement(Tag(0x0, 0x0100))) + { + DataElement de2 = theRSP.GetDataElement(Tag(0x0,0x0100)); + Attribute<0x0,0x0100> at2; + at2.SetFromDataElement( de2 ); + theCommandCode = at2.GetValues()[0]; + } + + if (theVal != pendingDE1 && theVal != pendingDE2 && theVal != success) + { + //check for other error fields + const ByteValue *err1 = NULL, *err2 = NULL; + gdcmErrorMacro( "Transfer failed with code " << theVal << std::endl); + switch (theVal){ + case 0xA701: + gdcmErrorMacro( "Refused: Out of Resources Unable to calculate number of matches" << std::endl); + break; + case 0xA702: + gdcmErrorMacro( "Refused: Out of Resources Unable to perform sub-operations" << std::endl); + break; + case 0xA801: + gdcmErrorMacro( "Refused: Move Destination unknown" << std::endl); + break; + case 0xA900: + gdcmErrorMacro( "Identifier does not match SOP Class" << std::endl); + break; + case 0xAA00: + gdcmErrorMacro( "None of the frames requested were found in the SOP Instance" << std::endl); + break; + case 0xAA01: + gdcmErrorMacro( "Unable to create new object for this SOP class" << std::endl); + break; + case 0xAA02: + gdcmErrorMacro( "Unable to extract frames" << std::endl); + break; + case 0xAA03: + gdcmErrorMacro( "Time-based request received for a non-time-based original SOP Instance. " << std::endl); + break; + case 0xAA04: + gdcmErrorMacro( "Invalid Request" << std::endl); + break; + case 0xFE00: + gdcmErrorMacro( "Sub-operations terminated due to Cancel Indication" << std::endl); + break; + case 0xB000: + gdcmErrorMacro( "Sub-operations Complete One or more Failures or Warnings" << std::endl); + break; + default: + gdcmErrorMacro( "Unable to process" << std::endl); + break; + } + if (theRSP.FindDataElement(Tag(0x0,0x0901))){ + DataElement de = theRSP.GetDataElement(Tag(0x0,0x0901)); + err1 = de.GetByteValue(); + gdcmErrorMacro( " Tag 0x0,0x901 reported as " << *err1 << std::endl); (void)err1; + } + if (theRSP.FindDataElement(Tag(0x0,0x0902))){ + DataElement de = theRSP.GetDataElement(Tag(0x0,0x0902)); + err2 = de.GetByteValue(); + gdcmErrorMacro( " Tag 0x0,0x902 reported as " << *err2 << std::endl); (void)err2; + } + } + + receivingData = false; + //justWaiting = false; + if (theVal == pendingDE1 || theVal == pendingDE2) { + receivingData = true; //wait for more data as more PDUs (findrsps, for instance) + //justWaiting = true; + waitingForEvent = true; + } + if (theVal == pendingDE1 || theVal == pendingDE2 /*|| theVal == success*/){//keep looping if we haven't succeeded or failed; these are the values for 'pending' + //first, dynamically cast that pdu in the event + //should be a data pdu + //then, look for tag 0x0,0x900 + + //only add datasets that are _not_ part of the network response + std::vector final; + std::vector theData; + BasePDU* thePDU;//outside the loop for the do/while stopping condition + bool interrupted = false; + do { + uint8_t itemtype = 0x0; + is.read( (char*)&itemtype, 1 ); + //what happens if nothing's read? + thePDU = PDUFactory::ConstructPDU(itemtype); + if (itemtype != 0x4 && thePDU != NULL){ //ie, not a pdatapdu + std::vector interruptingPDUs; + interruptingPDUs.push_back(thePDU); + currentEvent.SetEvent(PDUFactory::DetermineEventByPDU(interruptingPDUs[0])); + currentEvent.SetPDU(interruptingPDUs); + interrupted= true; + break; + } + if (thePDU != NULL){ + thePDU->Read(is); + theData.push_back(thePDU); + } else{ + break; + } + //!!!need to handle incoming PDUs that are not data, ie, an abort + } while(!thePDU->IsLastFragment()); + if (!interrupted){//ie, if the remote server didn't hang up + bool useimplicit = true; + TransferSyntaxSub ts1; + ts1.SetNameFromUID( UIDs::ImplicitVRLittleEndianDefaultTransferSyntaxforDICOM ); + if( mSecondaryConnection ) + { + const TransferSyntaxSub & ts_ = mSecondaryConnection->GetCStoreTransferSyntax(); + if( strcmp(ts_.GetName(), ts1.GetName()) != 0) + { + useimplicit = false; + } + } + DataSet theCompleteFindResponse; + if( useimplicit ) + { + inCallback->SetImplicitFlag(true); + theCompleteFindResponse = + PresentationDataValue::ConcatenatePDVBlobs(PDUFactory::GetPDVs(theData)); + } + else + { + inCallback->SetImplicitFlag(false); + theCompleteFindResponse = + PresentationDataValue::ConcatenatePDVBlobsAsExplicit(PDUFactory::GetPDVs(theData)); + } + //note that it's the responsibility of the event to delete the PDU in theFindRSP + for (size_t i = 0; i < theData.size(); i++) + { + delete theData[i]; + } + //outDataSet.push_back(theCompleteFindResponse); + if (inCallback) + { + inCallback->HandleDataSet(theCompleteFindResponse); + } + // DataSetEvent dse( &theCompleteFindResponse ); + // this->InvokeEvent( dse ); + + + if (theCommandCode == 1){//if we're doing cstore scp stuff, send information back along the connection. + std::vector theCStoreRSPPDU = PDUFactory::CreateCStoreRSPPDU(&theRSP, theFirstPDU);//pass NULL for C-Echo + //send them directly back over the connection + //ideall, should go through the transition table, but we know this should work + //and it won't change the state (unless something breaks?, but then an exception should throw) + std::vector::iterator itor; + for (itor = theCStoreRSPPDU.begin(); itor < theCStoreRSPPDU.end(); itor++){ + (*itor)->Write(*inWhichConnection->GetProtocol()); + } + + inWhichConnection->GetProtocol()->flush(); + + // FIXME added MM / Oct 30 2010 + //AReleaseRPPDU rel; + //rel.Write( *inWhichConnection->GetProtocol() ); + //inWhichConnection->GetProtocol()->flush(); + + receivingData = false; //gotta get data on the other connection for a cmove + + // cleanup + for (itor = theCStoreRSPPDU.begin(); itor < theCStoreRSPPDU.end(); itor++){ + delete *itor; + } + } + } + } + } + break; + case eARELEASERequest://process this via the transition table + waitingForEvent = false; + break; + case eARELEASE_RQPDUReceivedOpen://process this via the transition table + waitingForEvent = false; + receivingData = true; //to continue the loop to process the release + break; + case eAABORTPDUReceivedOpen: + { + raisedEvent = eEventDoesNotExist; + theState = eStaDoesNotExist; + } // explicitely declare fall-through for some picky compiler + case eAABORTRequest: + waitingForEvent = false; + inWhichConnection->StopProtocol(); + break; + case eASSOCIATE_ACPDUreceived: + default: + waitingForEvent = false; + break; + } + } + //} else { + // raisedEvent = eEventDoesNotExist; + // waitingForEvent = false; + //} + } + else { + currentEvent.SetEvent(raisedEvent);//actions that cause transitions in the state table + //locally just raise local events that will therefore cause the trigger to be pulled. + } + } while (currentEvent.GetEvent() != eEventDoesNotExist && + theState != eStaDoesNotExist && theState != eSta13AwaitingClose && theState != eSta1Idle && + (theState != eSta6TransferReady || (theState == eSta6TransferReady && receivingData ))); + //stop when the AE is done, or when ready to transfer data (ie, the next PDU should be sent in), + //or when the connection is idle after a disconnection. + //or, if in state 6 and receiving data, until all data is received. + + return theState; +} + +} // end namespace network +} // end namespace gdcm diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmULConnectionManager.h b/gdcm/Source/MessageExchangeDefinition/gdcmULConnectionManager.h new file mode 100644 index 0000000..341cc77 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmULConnectionManager.h @@ -0,0 +1,144 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#ifndef GDCMULCONNECTIONMANAGER_H +#define GDCMULCONNECTIONMANAGER_H + +#include "gdcmULTransitionTable.h" +#include "gdcmULConnection.h" +#include "gdcmULConnectionInfo.h" +#include "gdcmPresentationDataValue.h" +#include "gdcmULConnectionCallback.h" +#include "gdcmSubject.h" +#include "gdcmPresentationContext.h" + +namespace gdcm { + class File; + class BaseRootQuery; + + namespace network { + +/** + * \brief ULConnectionManager + * The ULConnectionManager performs actions on the ULConnection given inputs + * from the user and from the state of what's going on around the connection + * (ie, timeouts of the ARTIM timer, responses from the peer across the + * connection, etc). + * + * Its inputs are ULEvents, and it performs ULActions. + */ + class GDCM_EXPORT ULConnectionManager : public Subject + { + private: + ULConnection* mConnection; + ULConnection* mSecondaryConnection; + ULTransitionTable mTransitions; + + //no copying + ULConnectionManager(const ULConnectionManager& inCM); + + //event handler loop. + //will just keep running until the current event is nonexistent. + //at which point, it will return the current state of the connection + //this starts by initiating an action, but can be put into a passive mode + //for a cmove/cstore combination by setting startWaiting to true + EStateID RunEventLoop(ULEvent& inEvent, ULConnection* inWhichConnection, + ULConnectionCallback* inCallback, const bool& startWaiting); + + //like the above, but will manage the event loop for a move event (which + //is basically two simultaneous connections interwoven, one inbound and + //the other outbound. Note, for instance, that cmoversp's can be sent back + //during the other connection's operation. + EStateID RunMoveEventLoop(ULEvent& inEvent, ULConnectionCallback* inCallback); + + public: + ULConnectionManager(); + ~ULConnectionManager(); + + // NOTE: (MM) The following two functions are difficults to use, therefore marking + // them as internal for now. + + // \internal + /// returns true if a connection of the given AETitle (ie, 'this' program) + /// is able to connect to the given AETitle and Port in a certain amount of + /// time providing the connection type will establish the proper exchange + /// syntax with a server; if a different functionality is required, a + /// different connection should be established. + /// returns false if the connection type is 'move'-- have to give a return + /// port for move to work as specified. + bool EstablishConnection(const std::string& inAETitle, + const std::string& inConnectAETitle, + const std::string& inComputerName, long inIPAddress, + uint16_t inConnectPort, double inTimeout, + std::vector const & pcVector ); + + /// returns true for above reasons, but contains the special 'move' port + /// \internal + bool EstablishConnectionMove(const std::string& inAETitle, + const std::string& inConnectAETitle, + const std::string& inComputerName, long inIPAddress, + uint16_t inConnectPort, double inTimeout, + uint16_t inReturnPort, + std::vector const & pcVector); + // \endinternal + + + //bool ReestablishConnection(const EConnectionType& inConnectionType, + // const DataSet& inDS); + + //allows for a connection to be broken, but waits for an acknowledgement + //of the breaking for a certain amount of time. Returns true of the + //other side acknowledges the break + bool BreakConnection(const double& inTimeout); + + //severs the connection, if it's open, without waiting for any kind of response. + //typically done if the program is going down. + void BreakConnectionNow(); + + //This function will send a given piece of data + //across the network connection. It will return true if the + //sending worked, false otherwise. + //note that sending is asynchronous; as such, there's + //also a 'receive' option, but that requires a callback function. + //bool SendData(); + + //send the Data PDU associated with Echo (ie, a default DataPDU) + //this lets the user confirm that the connection is alive. + //the user should look to cout to see the response of the echo command + //returns the PresentationDataValue that was returned by the remote + //host. Note that the PDV can be uninitialized, which would indicate failure. + //Echo does not use a callback for results. + std::vector SendEcho(); + + // \internal + // API will change... + std::vector SendStore(const File &file); + std::vector SendFind(const BaseRootQuery* inRootQuery); + std::vector SendMove(const BaseRootQuery* inRootQuery); + // \endinternal + + ///callback based API + void SendStore(const File & file, ULConnectionCallback* inCallback); + void SendFind(const BaseRootQuery* inRootQuery, ULConnectionCallback* inCallback); + /// return false upon error + bool SendMove(const BaseRootQuery* inRootQuery, ULConnectionCallback* inCallback); + + }; + } +} + +#endif // GDCMULCONNECTIONMANAGER_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmULEvent.h b/gdcm/Source/MessageExchangeDefinition/gdcmULEvent.h new file mode 100644 index 0000000..7ecdac4 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmULEvent.h @@ -0,0 +1,76 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#ifndef GDCMULEVENT_H +#define GDCMULEVENT_H + +#include "gdcmNetworkStateID.h" +#include "gdcmNetworkEvents.h" +#include "gdcmBasePDU.h" +#include + +namespace gdcm { + namespace network { + +/** + * \brief ULEvent + * base class for network events. + * + * An event consists of the event ID and the data associated with that event. + * + * Note that once a PDU is created, it is now the responsibility of the associated event to destroy it! + */ +class ULEvent { + EEventID mEvent; + std::vector mBasePDU; + + void DeletePDUVector(){ + std::vector::iterator baseItor; + for (baseItor = mBasePDU.begin(); baseItor < mBasePDU.end(); baseItor++){ + if (*baseItor != NULL){ + delete *baseItor; + *baseItor = NULL; + } + } + } + + public: + ULEvent(const EEventID& inEventID, std::vector const & inBasePDU){ + mEvent = inEventID; + mBasePDU = inBasePDU; + } + ULEvent(const EEventID& inEventID, BasePDU* inBasePDU){ + mEvent = inEventID; + mBasePDU.push_back(inBasePDU); + } + ~ULEvent(){ + DeletePDUVector(); + } + + EEventID GetEvent() const { return mEvent; } + std::vector const & GetPDUs() const { return mBasePDU; } + + void SetEvent(const EEventID& inEvent) { mEvent = inEvent; } + void SetPDU(std::vector const & inPDU) { + DeletePDUVector(); + mBasePDU = inPDU; + } + }; + } +} + +#endif //GDCMULEVENT_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmULTransitionTable.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmULTransitionTable.cxx new file mode 100644 index 0000000..6a3249f --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmULTransitionTable.cxx @@ -0,0 +1,352 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ + + +/* + * This file is the implementation of the ULTransitionTable class, including + * the actual event handling as well as the construction of the table itself. + */ + +#include "gdcmULTransitionTable.h" +#include "gdcmULActionAA.h" +#include "gdcmULActionAE.h" +#include "gdcmULActionAR.h" +#include "gdcmULActionDT.h" + +namespace gdcm +{ +namespace network +{ +//construct the table +ULTransitionTable::ULTransitionTable() +{ +//row 1 +// A-ASSOCIATE Request (local user) + mTable[eAASSOCIATERequestLocalUser].transitions[GetStateIndex(eSta1Idle)] = + Transition::MakeNew(eSta4LocalAssocDone, new ULActionAE1()); +//row 2 +// Transport Conn. Confirmn (local transport service) + mTable[eTransportConnConfirmLocal].transitions[GetStateIndex(eSta4LocalAssocDone)] = + Transition::MakeNew(eSta5WaitRemoteAssoc, new ULActionAE2()); +//row 3 +// A-ASSOCIATE-AC PDU (received on transport connection) + mTable[eASSOCIATE_ACPDUreceived].transitions[GetStateIndex(eSta2Open)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA1()); + mTable[eASSOCIATE_ACPDUreceived].transitions[GetStateIndex(eSta3WaitLocalAssoc)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[eASSOCIATE_ACPDUreceived].transitions[GetStateIndex(eSta5WaitRemoteAssoc)] = + Transition::MakeNew(eSta6TransferReady, new ULActionAE3()); + mTable[eASSOCIATE_ACPDUreceived].transitions[GetStateIndex(eSta6TransferReady)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[eASSOCIATE_ACPDUreceived].transitions[GetStateIndex(eSta7WaitRelease)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[eASSOCIATE_ACPDUreceived].transitions[GetStateIndex(eSta8WaitLocalRelease)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[eASSOCIATE_ACPDUreceived].transitions[GetStateIndex(eSta9ReleaseCollisionRqLocal)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[eASSOCIATE_ACPDUreceived].transitions[GetStateIndex(eSta10ReleaseCollisionAc)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[eASSOCIATE_ACPDUreceived].transitions[GetStateIndex(eSta11ReleaseCollisionRq)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[eASSOCIATE_ACPDUreceived].transitions[GetStateIndex(eSta12ReleaseCollisionAcLocal)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[eASSOCIATE_ACPDUreceived].transitions[GetStateIndex(eSta13AwaitingClose)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA6()); + +//row 4 +// A-ASSOCIATE-RJ PDU (received on transport connection) + mTable[eASSOCIATE_RJPDUreceived].transitions[GetStateIndex(eSta2Open)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA1()); + mTable[eASSOCIATE_RJPDUreceived].transitions[GetStateIndex(eSta3WaitLocalAssoc)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[eASSOCIATE_RJPDUreceived].transitions[GetStateIndex(eSta5WaitRemoteAssoc)] = + Transition::MakeNew(eSta1Idle, new ULActionAE4()); + mTable[eASSOCIATE_RJPDUreceived].transitions[GetStateIndex(eSta6TransferReady)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[eASSOCIATE_RJPDUreceived].transitions[GetStateIndex(eSta7WaitRelease)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[eASSOCIATE_RJPDUreceived].transitions[GetStateIndex(eSta8WaitLocalRelease)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[eASSOCIATE_RJPDUreceived].transitions[GetStateIndex(eSta9ReleaseCollisionRqLocal)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[eASSOCIATE_RJPDUreceived].transitions[GetStateIndex(eSta10ReleaseCollisionAc)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[eASSOCIATE_RJPDUreceived].transitions[GetStateIndex(eSta11ReleaseCollisionRq)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[eASSOCIATE_RJPDUreceived].transitions[GetStateIndex(eSta12ReleaseCollisionAcLocal)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[eASSOCIATE_RJPDUreceived].transitions[GetStateIndex(eSta13AwaitingClose)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA6()); +//row 5 +// Transport Connection Indication (local transport service) + mTable[eTransportConnIndicLocal].transitions[GetStateIndex(eSta1Idle)] = + Transition::MakeNew(eSta2Open, new ULActionAE5()); +//row 6 +// A-ASSOCIATE-RQ PDU (received on transport connection) + mTable[eAASSOCIATE_RQPDUreceived].transitions[GetStateIndex(eSta2Open)] = + Transition::MakeNew(eSta3WaitLocalAssoc | eSta13AwaitingClose, new ULActionAE6()); + mTable[eAASSOCIATE_RQPDUreceived].transitions[GetStateIndex(eSta3WaitLocalAssoc)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[eAASSOCIATE_RQPDUreceived].transitions[GetStateIndex(eSta5WaitRemoteAssoc)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[eAASSOCIATE_RQPDUreceived].transitions[GetStateIndex(eSta6TransferReady)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[eAASSOCIATE_RQPDUreceived].transitions[GetStateIndex(eSta7WaitRelease)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[eAASSOCIATE_RQPDUreceived].transitions[GetStateIndex(eSta8WaitLocalRelease)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[eAASSOCIATE_RQPDUreceived].transitions[GetStateIndex(eSta9ReleaseCollisionRqLocal)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[eAASSOCIATE_RQPDUreceived].transitions[GetStateIndex(eSta10ReleaseCollisionAc)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[eAASSOCIATE_RQPDUreceived].transitions[GetStateIndex(eSta11ReleaseCollisionRq)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[eAASSOCIATE_RQPDUreceived].transitions[GetStateIndex(eSta12ReleaseCollisionAcLocal)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[eAASSOCIATE_RQPDUreceived].transitions[GetStateIndex(eSta13AwaitingClose)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA7()); +//row 7 +// A-ASSOCIATE response primitive (accept) + mTable[eAASSOCIATEresponseAccept].transitions[GetStateIndex(eSta3WaitLocalAssoc)] = + Transition::MakeNew(eSta7WaitRelease, new ULActionAE7()); +//row 8 +// A-ASSOCIATE response primitive (reject) + mTable[eAASSOCIATEresponseReject].transitions[GetStateIndex(eSta3WaitLocalAssoc)] = + Transition::MakeNew(eSta7WaitRelease, new ULActionAE7()); +//Row 9 +// P-DATA request primitive + mTable[ePDATArequest].transitions[GetStateIndex(eSta6TransferReady)] = + Transition::MakeNew(eSta6TransferReady, new ULActionDT1()); + mTable[ePDATArequest].transitions[GetStateIndex(eSta8WaitLocalRelease)] = + Transition::MakeNew(eSta8WaitLocalRelease, new ULActionAR7()); +//row 10 +// P-DATA-TF PDU + mTable[ePDATATFPDU].transitions[GetStateIndex(eSta2Open)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA1()); + mTable[ePDATATFPDU].transitions[GetStateIndex(eSta3WaitLocalAssoc)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[ePDATATFPDU].transitions[GetStateIndex(eSta5WaitRemoteAssoc)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[ePDATATFPDU].transitions[GetStateIndex(eSta6TransferReady)] = + Transition::MakeNew(eSta6TransferReady, new ULActionDT2()); + mTable[ePDATATFPDU].transitions[GetStateIndex(eSta7WaitRelease)] = + Transition::MakeNew(eSta7WaitRelease, new ULActionAR6()); + mTable[ePDATATFPDU].transitions[GetStateIndex(eSta8WaitLocalRelease)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[ePDATATFPDU].transitions[GetStateIndex(eSta9ReleaseCollisionRqLocal)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[ePDATATFPDU].transitions[GetStateIndex(eSta10ReleaseCollisionAc)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[ePDATATFPDU].transitions[GetStateIndex(eSta11ReleaseCollisionRq)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[ePDATATFPDU].transitions[GetStateIndex(eSta12ReleaseCollisionAcLocal)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[ePDATATFPDU].transitions[GetStateIndex(eSta13AwaitingClose)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA6()); +//row 11 +// A-RELEASE Request primitive + mTable[eARELEASERequest].transitions[GetStateIndex(eSta6TransferReady)] = + Transition::MakeNew(eSta7WaitRelease, new ULActionAR1()); +//row 12 +// A-RELEASE-RQ PDU (received on open transport connection) + mTable[eARELEASE_RQPDUReceivedOpen].transitions[GetStateIndex(eSta2Open)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA1()); + mTable[eARELEASE_RQPDUReceivedOpen].transitions[GetStateIndex(eSta3WaitLocalAssoc)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[eARELEASE_RQPDUReceivedOpen].transitions[GetStateIndex(eSta5WaitRemoteAssoc)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[eARELEASE_RQPDUReceivedOpen].transitions[GetStateIndex(eSta6TransferReady)] = + Transition::MakeNew(eSta8WaitLocalRelease, new ULActionAR2()); + mTable[eARELEASE_RQPDUReceivedOpen].transitions[GetStateIndex(eSta7WaitRelease)] = + Transition::MakeNew(eSta9ReleaseCollisionRqLocal | eSta10ReleaseCollisionAc, new ULActionAR8()); + mTable[eARELEASE_RQPDUReceivedOpen].transitions[GetStateIndex(eSta8WaitLocalRelease)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[eARELEASE_RQPDUReceivedOpen].transitions[GetStateIndex(eSta9ReleaseCollisionRqLocal)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[eARELEASE_RQPDUReceivedOpen].transitions[GetStateIndex(eSta10ReleaseCollisionAc)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[eARELEASE_RQPDUReceivedOpen].transitions[GetStateIndex(eSta11ReleaseCollisionRq)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[eARELEASE_RQPDUReceivedOpen].transitions[GetStateIndex(eSta12ReleaseCollisionAcLocal)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[eARELEASE_RQPDUReceivedOpen].transitions[GetStateIndex(eSta13AwaitingClose)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA6()); +//row 13 +// A-RELEASE-RP PDU (received on transport connection) + mTable[eARELEASE_RPPDUReceived].transitions[GetStateIndex(eSta2Open)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA1()); + mTable[eARELEASE_RPPDUReceived].transitions[GetStateIndex(eSta3WaitLocalAssoc)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[eARELEASE_RPPDUReceived].transitions[GetStateIndex(eSta5WaitRemoteAssoc)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[eARELEASE_RPPDUReceived].transitions[GetStateIndex(eSta6TransferReady)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[eARELEASE_RPPDUReceived].transitions[GetStateIndex(eSta7WaitRelease)] = + Transition::MakeNew(eSta1Idle, new ULActionAR3()); + mTable[eARELEASE_RPPDUReceived].transitions[GetStateIndex(eSta8WaitLocalRelease)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[eARELEASE_RPPDUReceived].transitions[GetStateIndex(eSta9ReleaseCollisionRqLocal)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[eARELEASE_RPPDUReceived].transitions[GetStateIndex(eSta10ReleaseCollisionAc)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[eARELEASE_RPPDUReceived].transitions[GetStateIndex(eSta11ReleaseCollisionRq)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[eARELEASE_RPPDUReceived].transitions[GetStateIndex(eSta12ReleaseCollisionAcLocal)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[eARELEASE_RPPDUReceived].transitions[GetStateIndex(eSta13AwaitingClose)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA6()); +// Row 14 +// A-RELEASE Response primitive + mTable[eARELEASEResponse].transitions[GetStateIndex(eSta8WaitLocalRelease)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAR4()); + mTable[eARELEASEResponse].transitions[GetStateIndex(eSta9ReleaseCollisionRqLocal)] = + Transition::MakeNew(eSta11ReleaseCollisionRq, new ULActionAR9); + mTable[eARELEASEResponse].transitions[GetStateIndex(eSta12ReleaseCollisionAcLocal)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAR4()); +// row 15 +// A-ABORT Request primitive + mTable[eAABORTRequest].transitions[GetStateIndex(eSta3WaitLocalAssoc)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA1()); + mTable[eAABORTRequest].transitions[GetStateIndex(eSta4LocalAssocDone)] = + Transition::MakeNew(eSta1Idle, new ULActionAA2()); + mTable[eAABORTRequest].transitions[GetStateIndex(eSta5WaitRemoteAssoc)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA1()); + mTable[eAABORTRequest].transitions[GetStateIndex(eSta6TransferReady)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA1()); + mTable[eAABORTRequest].transitions[GetStateIndex(eSta7WaitRelease)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA1()); + mTable[eAABORTRequest].transitions[GetStateIndex(eSta8WaitLocalRelease)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA1()); + mTable[eAABORTRequest].transitions[GetStateIndex(eSta9ReleaseCollisionRqLocal)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA1()); + mTable[eAABORTRequest].transitions[GetStateIndex(eSta10ReleaseCollisionAc)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA1()); + mTable[eAABORTRequest].transitions[GetStateIndex(eSta11ReleaseCollisionRq)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA1()); + mTable[eAABORTRequest].transitions[GetStateIndex(eSta12ReleaseCollisionAcLocal)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA1()); +// row 16 +// A-ABORT PDU (received on open transport connection) + mTable[eAABORTPDUReceivedOpen].transitions[GetStateIndex(eSta2Open)] = + Transition::MakeNew(eSta1Idle, new ULActionAA2()); + mTable[eAABORTPDUReceivedOpen].transitions[GetStateIndex(eSta3WaitLocalAssoc)] = + Transition::MakeNew(eSta1Idle, new ULActionAA3()); + mTable[eAABORTPDUReceivedOpen].transitions[GetStateIndex(eSta5WaitRemoteAssoc)] = + Transition::MakeNew(eSta1Idle, new ULActionAA3()); + mTable[eAABORTPDUReceivedOpen].transitions[GetStateIndex(eSta6TransferReady)] = + Transition::MakeNew(eSta1Idle, new ULActionAA3()); + mTable[eAABORTPDUReceivedOpen].transitions[GetStateIndex(eSta7WaitRelease)] = + Transition::MakeNew(eSta1Idle, new ULActionAA3()); + mTable[eAABORTPDUReceivedOpen].transitions[GetStateIndex(eSta8WaitLocalRelease)] = + Transition::MakeNew(eSta1Idle, new ULActionAA3()); + mTable[eAABORTPDUReceivedOpen].transitions[GetStateIndex(eSta9ReleaseCollisionRqLocal)] = + Transition::MakeNew(eSta1Idle, new ULActionAA3()); + mTable[eAABORTPDUReceivedOpen].transitions[GetStateIndex(eSta10ReleaseCollisionAc)] = + Transition::MakeNew(eSta1Idle, new ULActionAA3()); + mTable[eAABORTPDUReceivedOpen].transitions[GetStateIndex(eSta11ReleaseCollisionRq)] = + Transition::MakeNew(eSta1Idle, new ULActionAA3()); + mTable[eAABORTPDUReceivedOpen].transitions[GetStateIndex(eSta12ReleaseCollisionAcLocal)] = + Transition::MakeNew(eSta1Idle, new ULActionAA3()); + mTable[eAABORTPDUReceivedOpen].transitions[GetStateIndex(eSta13AwaitingClose)] = + Transition::MakeNew(eSta1Idle, new ULActionAA2()); +//row 17 +// Transport connection closed indication (local transport service), + mTable[eTransportConnectionClosed].transitions[GetStateIndex(eSta2Open)] = + Transition::MakeNew(eSta1Idle, new ULActionAA5()); + mTable[eTransportConnectionClosed].transitions[GetStateIndex(eSta3WaitLocalAssoc)] = + Transition::MakeNew(eSta1Idle, new ULActionAA4()); + mTable[eTransportConnectionClosed].transitions[GetStateIndex(eSta4LocalAssocDone)] = + Transition::MakeNew(eSta1Idle, new ULActionAA4()); + mTable[eTransportConnectionClosed].transitions[GetStateIndex(eSta5WaitRemoteAssoc)] = + Transition::MakeNew(eSta1Idle, new ULActionAA4()); + mTable[eTransportConnectionClosed].transitions[GetStateIndex(eSta6TransferReady)] = + Transition::MakeNew(eSta1Idle, new ULActionAA4()); + mTable[eTransportConnectionClosed].transitions[GetStateIndex(eSta7WaitRelease)] = + Transition::MakeNew(eSta1Idle, new ULActionAA4()); + mTable[eTransportConnectionClosed].transitions[GetStateIndex(eSta8WaitLocalRelease)] = + Transition::MakeNew(eSta1Idle, new ULActionAA4()); + mTable[eTransportConnectionClosed].transitions[GetStateIndex(eSta9ReleaseCollisionRqLocal)] = + Transition::MakeNew(eSta1Idle, new ULActionAA4()); + mTable[eTransportConnectionClosed].transitions[GetStateIndex(eSta10ReleaseCollisionAc)] = + Transition::MakeNew(eSta1Idle, new ULActionAA4()); + mTable[eTransportConnectionClosed].transitions[GetStateIndex(eSta11ReleaseCollisionRq)] = + Transition::MakeNew(eSta1Idle, new ULActionAA4()); + mTable[eTransportConnectionClosed].transitions[GetStateIndex(eSta12ReleaseCollisionAcLocal)] = + Transition::MakeNew(eSta1Idle, new ULActionAA4()); + mTable[eTransportConnectionClosed].transitions[GetStateIndex(eSta13AwaitingClose)] = + Transition::MakeNew(eSta1Idle, new ULActionAA5()); +//row 18 +// ARTIM timer expired (Association reject/release timer), + mTable[eARTIMTimerExpired].transitions[GetStateIndex(eSta2Open)] = + Transition::MakeNew(eSta1Idle, new ULActionAA2()); + mTable[eARTIMTimerExpired].transitions[GetStateIndex(eSta13AwaitingClose)] = + Transition::MakeNew(eSta1Idle, new ULActionAA2()); +//row 19 +// Unrecognized or invalid PDU received + mTable[eUnrecognizedPDUReceived].transitions[GetStateIndex(eSta3WaitLocalAssoc)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA1()); + mTable[eUnrecognizedPDUReceived].transitions[GetStateIndex(eSta13AwaitingClose)] = + Transition::MakeNew(eSta1Idle, new ULActionAA8()); + mTable[eUnrecognizedPDUReceived].transitions[GetStateIndex(eSta5WaitRemoteAssoc)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[eUnrecognizedPDUReceived].transitions[GetStateIndex(eSta6TransferReady)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[eUnrecognizedPDUReceived].transitions[GetStateIndex(eSta7WaitRelease)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[eUnrecognizedPDUReceived].transitions[GetStateIndex(eSta8WaitLocalRelease)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[eUnrecognizedPDUReceived].transitions[GetStateIndex(eSta9ReleaseCollisionRqLocal)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[eUnrecognizedPDUReceived].transitions[GetStateIndex(eSta10ReleaseCollisionAc)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[eUnrecognizedPDUReceived].transitions[GetStateIndex(eSta11ReleaseCollisionRq)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA8()); + mTable[eUnrecognizedPDUReceived].transitions[GetStateIndex(eSta12ReleaseCollisionAcLocal)] = + Transition::MakeNew(eSta13AwaitingClose, new ULActionAA7()); +} + +//given the event and the state of the connection, call the appropriate action +void ULTransitionTable::HandleEvent(Subject *s, ULEvent& inEvent, ULConnection& inConnection, + bool& outWaitingForEvent, EEventID& outRaisedEvent) const{ + //first, find the Event + EEventID eventID = inEvent.GetEvent(); + if (eventID >= 0 && eventID < eEventDoesNotExist) + { //make sure that the event exists + //have to convert the state ID into an index + int stateIndex = GetStateIndex(inConnection.GetState()); + if (stateIndex >= 0 && stateIndex < cMaxStateID) + { + if ( mTable[eventID].transitions[stateIndex] ) + { + if (mTable[eventID].transitions[stateIndex]->mAction != NULL) + { + gdcmDebugMacro( "Process: Event:" << (int)eventID << ", State:" << stateIndex ); + inConnection.SetState(mTable[eventID].transitions[stateIndex]->mAction-> + PerformAction(s,inEvent, inConnection, outWaitingForEvent, outRaisedEvent)); + } + } + else + { + gdcmDebugMacro( "Transition failed (NULL) for event:" << (int)eventID << ", State:" << stateIndex ); + } + } + } +} + +} // end namespace network +} // end namespace gdcm diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmULTransitionTable.h b/gdcm/Source/MessageExchangeDefinition/gdcmULTransitionTable.h new file mode 100644 index 0000000..e89cd41 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmULTransitionTable.h @@ -0,0 +1,112 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#ifndef GDCMULTRANSITIONTABLE_H +#define GDCMULTRANSITIONTABLE_H + +#include "gdcmNetworkStateID.h" +#include "gdcmNetworkEvents.h" +#include "gdcmULAction.h" + +#include // NULL + +namespace gdcm { +class Subject; + namespace network{ +class ULConnection; +class ULAction; +class ULEvent; + + //The transition dictates the action that should be taken from the start state to the end state + struct Transition { + int mEnd; + ULAction* mAction; + Transition(){ + mEnd = eStaDoesNotExist; + mAction = NULL; + } + ~Transition(){ + if (mAction != NULL){ + delete mAction; + mAction = NULL; + } + } + Transition(int inEndState, ULAction* inAction){ + mEnd = inEndState; + mAction = inAction; + } + static Transition* MakeNew(int inEndState, ULAction* inAction){ + return new Transition(inEndState, inAction); + } + }; + + //used to define a row in table 9-10 of 3.8 2009 + //the transition table is events, then state, + //then the transition itself (which has the event + //and start state implied by their starting locations) + //don't need to store the event; that's implicitly defined in the Table itself by location + class TableRow{ + public: + TableRow() { + for(int stateIndex = 0; stateIndex < cMaxStateID; ++stateIndex) + { + transitions[stateIndex] = NULL; + } + } + ~TableRow() { + for(int stateIndex = 0; stateIndex < cMaxStateID; ++stateIndex) + { + Transition *t = transitions[stateIndex]; + delete t; + } + } + Transition *transitions[cMaxStateID]; + + //copy constructor for stl additions into the transition table below. + }; + +/** + * \brief ULTransitionTable + * The transition table of all the ULEvents, new ULActions, and ULStates. + * + * Based roughly on the solutions in player2.cpp in the boost examples and this + * so question: + * http://stackoverflow.com/questions/1647631/c-state-machine-design + * + * The transition table is constructed of TableRows. Each row is based on an + * event, and an event handler in the TransitionTable object takes a given + * event, and then finds the given row. + * + * Then, given the current state of the connection, determines the appropriate + * action to take and then the state to transition to next. + * + */ +class ULTransitionTable +{ + private: + TableRow mTable[cMaxEventID]; + public: + ULTransitionTable(); + + void HandleEvent(Subject*s,ULEvent& inEvent, ULConnection& inConnection, + bool& outWaitingForEvent, EEventID& outRaisedEvent) const; + + void PrintTable() const; //so that the table can be printed and verified against the DICOM standard + }; + } +} +#endif // GDCMULTRANSITIONTABLE_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmULWritingCallback.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmULWritingCallback.cxx new file mode 100644 index 0000000..e8afa71 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmULWritingCallback.cxx @@ -0,0 +1,72 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#include "gdcmULWritingCallback.h" + +#include "gdcmFile.h" +#include "gdcmWriter.h" + +namespace gdcm +{ + +namespace network +{ + +// writes the data set to disk immediately, rather than keeping it memory. +// could have potential timing issues if datasets come over the network faster than +// they can be written, which could be the case on very fast connections with slow disks +void ULWritingCallback::HandleDataSet(const DataSet& inDataSet) +{ + if (inDataSet.FindDataElement(Tag(0x0008,0x0018)) && + !inDataSet.GetDataElement(Tag(0x0008,0x0018)).IsEmpty() ) + { + const DataElement &de = inDataSet.GetDataElement(Tag(0x0008,0x0018)); + const ByteValue *bv = de.GetByteValue(); + const std::string sopclassuid_str( bv->GetPointer(), bv->GetLength() ); + Writer w; + std::string theLoc = mDirectoryName + "/" + sopclassuid_str.c_str() + ".dcm"; + w.SetFileName(theLoc.c_str()); + File &f = w.GetFile(); + f.SetDataSet(inDataSet); + FileMetaInformation &fmi = f.GetHeader(); + if( mImplicit ) + fmi.SetDataSetTransferSyntax( TransferSyntax::ImplicitVRLittleEndian ); + else + fmi.SetDataSetTransferSyntax( TransferSyntax::ExplicitVRLittleEndian ); + w.SetCheckFileMetaInformation( true ); + if (!w.Write()) + { + gdcmErrorMacro("Failed to write " << sopclassuid_str.c_str() << std::endl); + } + else + { + gdcmDebugMacro( "Wrote " << sopclassuid_str.c_str() << " to disk. " << std::endl); + } + } + else + { + gdcmErrorMacro( "Failed to write data set, could not find tag 0x0008, 0x0018" << std::endl); + } + DataSetHandled(); +} + +void ULWritingCallback::HandleResponse(const DataSet& ) +{ +} + +} // end namespace network +} // end namespace gdcm diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmULWritingCallback.h b/gdcm/Source/MessageExchangeDefinition/gdcmULWritingCallback.h new file mode 100644 index 0000000..e321cc3 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmULWritingCallback.h @@ -0,0 +1,50 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#ifndef GDCMULCONNECTIONWRITINGCALLBACK_H +#define GDCMULCONNECTIONWRITINGCALLBACK_H + +#include "gdcmULConnectionCallback.h" + +namespace gdcm +{ +class DataSet; +namespace network +{ +/* \brief ULWritingCallback + * This is the most basic of callbacks for how the ULConnectionManager handles + * incoming datasets. DataSets are immediately written to disk as soon as they + * are received. NOTE that if the incoming connection is faster than the disk + * writing speed, this callback could cause some pileups! + */ +class GDCM_EXPORT ULWritingCallback : public ULConnectionCallback +{ + std::string mDirectoryName; +public: + ULWritingCallback() {}; + virtual ~ULWritingCallback() {} //empty, for later inheritance + + ///provide the directory into which all files are written. + void SetDirectory(const std::string& inDirectoryName) { mDirectoryName = inDirectoryName; } + + virtual void HandleDataSet(const DataSet& inDataSet); + virtual void HandleResponse(const DataSet& inDataSet); +}; +} // end namespace network +} // end namespace gdcm + +#endif //GDCMULCONNECTIONWRITINGCALLBACK_H diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmUserInformation.cxx b/gdcm/Source/MessageExchangeDefinition/gdcmUserInformation.cxx new file mode 100644 index 0000000..2522bc8 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmUserInformation.cxx @@ -0,0 +1,328 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmUserInformation.h" +#include "gdcmSwapper.h" +#include "gdcmAsynchronousOperationsWindowSub.h" +#include "gdcmRoleSelectionSub.h" +#include "gdcmSOPClassExtendedNegociationSub.h" + +#include + +namespace gdcm +{ +namespace network +{ + +const uint8_t UserInformation::ItemType = 0x50; +const uint8_t UserInformation::Reserved2 = 0x00; + +struct RoleSelectionSubItems +{ + void Print(std::ostream &os) const + { + std::vector::const_iterator it = RSSArray.begin(); + for( ; it != RSSArray.end(); ++it ) + { + it->Print(os); + } + } + const std::ostream &Write(std::ostream &os) const + { + std::vector::const_iterator it = RSSArray.begin(); + for( ; it != RSSArray.end(); ++it ) + { + it->Write(os); + } + return os; + } + void AddTuple(const char *uid, uint8_t scurole, uint8_t scprole) + { + RoleSelectionSub rss; + rss.SetTuple( uid, scurole, scprole ); + RSSArray.push_back( rss ); + } + bool Empty() const + { + return RSSArray.empty(); + } + size_t Size() const + { + size_t s = 0; + std::vector::const_iterator it = RSSArray.begin(); + for( ; it != RSSArray.end(); ++it ) + { + s += it->Size(); + } + return s; + } + std::vector RSSArray; +}; + +struct SOPClassExtendedNegociationSubItems +{ + void Print(std::ostream &os) const + { + std::vector::const_iterator it = SOPCENSArray.begin(); + for( ; it != SOPCENSArray.end(); ++it ) + { + it->Print(os); + } + } + const std::ostream &Write(std::ostream &os) const + { + std::vector::const_iterator it = SOPCENSArray.begin(); + for( ; it != SOPCENSArray.end(); ++it ) + { + it->Write(os); + } + return os; + } + void AddDefault(const char *uid) + { + SOPClassExtendedNegociationSub sub; + sub.SetTuple( uid ); + SOPCENSArray.push_back( sub ); + } + bool Empty() const + { + return SOPCENSArray.empty(); + } + size_t Size() const + { + size_t s = 0; + std::vector::const_iterator it = SOPCENSArray.begin(); + for( ; it != SOPCENSArray.end(); ++it ) + { + s += it->Size(); + } + return s; + } + std::vector SOPCENSArray; +}; + +UserInformation::UserInformation() +{ + AOWS = NULL; + RSSI = new RoleSelectionSubItems; + SOPCENSI = new SOPClassExtendedNegociationSubItems; +#if 0 + RSSI->AddTuple("1.2.840.10008.5.1.4.1.1.2", 1, 1); // DEBUG + RSSI->AddTuple("1.2.840.10008.5.1.4.1.1.4", 1, 1); // DEBUG + RSSI->AddTuple("1.2.840.10008.5.1.4.1.1.7", 1, 1); // DEBUG + SOPCENSI->AddDefault("1.2.840.10008.5.1.4.1.1.2"); // DEBUG + SOPCENSI->AddDefault("1.2.840.10008.5.1.4.1.1.4"); // DEBUG + SOPCENSI->AddDefault("1.2.840.10008.5.1.4.1.1.7"); // DEBUG +#endif + size_t t0 = MLS.Size(); + size_t t1 = ICUID.Size(); + size_t t2 = 0; //AOWS.Size(); + size_t t3 = IVNS.Size(); + ItemLength = (uint16_t)(t0 + t1 + t2 + t3); +#if 0 + if( !RSSI->Empty() ) ItemLength += RSSI->Size(); + if( !SOPCENSI->Empty() ) ItemLength += SOPCENSI->Size(); +#endif + assert( (size_t)ItemLength + 4 == Size() ); +} + +UserInformation::~UserInformation() +{ + delete AOWS; + delete SOPCENSI; + delete RSSI; +} + +std::istream &UserInformation::Read(std::istream &is) +{ + //uint8_t itemtype = 0x0; + //is.read( (char*)&itemtype, sizeof(ItemType) ); + //assert( itemtype == ItemType ); + uint8_t reserved2; + is.read( (char*)&reserved2, sizeof(Reserved2) ); + uint16_t itemlength; + is.read( (char*)&itemlength, sizeof(ItemLength) ); + SwapperDoOp::SwapArray(&itemlength,1); + ItemLength = itemlength; + + uint8_t itemtype2 = 0x0; + size_t curlen = 0; +#if 0 + RSSI->RSSArray.clear(); // DEBUG + SOPCENSI->SOPCENSArray.clear(); // DEBUG +#endif + while( curlen < ItemLength ) + { + is.read( (char*)&itemtype2, sizeof(ItemType) ); + switch ( itemtype2 ) + { + case 0x51: // MaximumLengthSub + MLS.Read( is ); + curlen += MLS.Size(); + break; + case 0x52: // ImplementationClassUIDSub + ICUID.Read(is); + curlen += ICUID.Size(); + break; + case 0x53: // AsynchronousOperationsWindowSub + assert( !AOWS ); + AOWS = new AsynchronousOperationsWindowSub; + AOWS->Read( is ); + curlen += AOWS->Size(); + break; + case 0x54: // RoleSelectionSub + assert( RSSI ); + { + RoleSelectionSub rss; + rss.Read( is ); + curlen += rss.Size(); + RSSI->RSSArray.push_back( rss ); + } + break; + case 0x55: // ImplementationVersionNameSub + IVNS.Read( is ); + curlen += IVNS.Size(); + break; + case 0x56: // SOPClassExtendedNegociationSub + assert( SOPCENSI ); + { + SOPClassExtendedNegociationSub sopcens; + sopcens.Read( is ); + curlen += sopcens.Size(); + SOPCENSI->SOPCENSArray.push_back( sopcens ); + } + break; + default: + gdcmErrorMacro( "Unknown ItemType: " << std::hex << (int) itemtype2 ); + curlen = ItemLength; // make sure to exit + assert(0); + break; + } + } + assert( curlen == ItemLength ); + + assert( (size_t)ItemLength + 4 == Size() ); + return is; +} + +const std::ostream &UserInformation::Write(std::ostream &os) const +{ + assert( (size_t)ItemLength + 4 == Size() ); + os.write( (char*)&ItemType, sizeof(ItemType) ); + os.write( (char*)&Reserved2, sizeof(Reserved2) ); + uint16_t copy = ItemLength; + SwapperDoOp::SwapArray(©,1); + os.write( (char*)©, sizeof(ItemLength) ); + + MLS.Write(os); + ICUID.Write(os); + if( AOWS ) + { + AOWS->Write(os); + } + if( !RSSI->Empty() ) + { + RSSI->Write(os); + } + IVNS.Write(os); + if( !SOPCENSI->Empty() ) + { + SOPCENSI->Write(os); + } + + assert( (size_t)ItemLength + 4 == Size() ); + + return os; +} + +size_t UserInformation::Size() const +{ + size_t ret = 0; + ret += sizeof(ItemType); + ret += sizeof(Reserved2); + ret += sizeof(ItemLength); // len of + ret += MLS.Size(); + ret += ICUID.Size(); + if( AOWS ) + ret += AOWS->Size(); + if( !RSSI->Empty() ) + ret += RSSI->Size(); + ret += IVNS.Size(); + if( !SOPCENSI->Empty() ) + ret += SOPCENSI->Size(); + + return ret; +} + +void UserInformation::Print(std::ostream &os) const +{ + os << "MaximumLengthSub: "; + MLS.Print( os ); + os << "ImplementationClassUIDSub: "; + ICUID.Print( os ); + if( AOWS ) + { + os << "AsynchronousOperationsWindowSub: "; + AOWS->Print( os ); + } + if( !RSSI->Empty() ) + { + os << "RoleSelectionSub: "; + RSSI->Print( os ); + } + os << "ImplementationVersionNameSub: "; + IVNS.Print( os ); + if( !SOPCENSI->Empty() ) + { + os << "SOPClassExtendedNegociationSub: "; + SOPCENSI->Print( os ); + } + os << std::endl; +} + +UserInformation &UserInformation::operator=(const UserInformation& ui) +{ + ItemLength = ui.ItemLength; + MLS = ui.MLS; + ICUID = ui.ICUID; + if( ui.AOWS ) + { + delete AOWS; + AOWS = new AsynchronousOperationsWindowSub; + *AOWS = *ui.AOWS; + } + *RSSI = *ui.RSSI; + *SOPCENSI = *ui.SOPCENSI; + IVNS = ui.IVNS; + + assert( (size_t)ItemLength + 4 == Size() ); + + return *this; +} + +void UserInformation::AddRoleSelectionSub( RoleSelectionSub const & rss ) +{ + RSSI->RSSArray.push_back( rss ); + ItemLength = (uint16_t)(Size() - 4); + assert( (size_t)ItemLength + 4 == Size() ); +} + +void UserInformation::AddSOPClassExtendedNegociationSub( SOPClassExtendedNegociationSub const & sopcens ) +{ + SOPCENSI->SOPCENSArray.push_back( sopcens ); + ItemLength = (uint16_t)(Size() - 4); + assert( (size_t)ItemLength + 4 == Size() ); +} + +} // end namespace network +} // end namespace gdcm diff --git a/gdcm/Source/MessageExchangeDefinition/gdcmUserInformation.h b/gdcm/Source/MessageExchangeDefinition/gdcmUserInformation.h new file mode 100644 index 0000000..06ada30 --- /dev/null +++ b/gdcm/Source/MessageExchangeDefinition/gdcmUserInformation.h @@ -0,0 +1,80 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMUSERINFORMATION_H +#define GDCMUSERINFORMATION_H + +#include "gdcmTypes.h" +#include "gdcmMaximumLengthSub.h" +#include "gdcmImplementationVersionNameSub.h" +#include "gdcmImplementationClassUIDSub.h" + +namespace gdcm +{ + +namespace network +{ + +class AsynchronousOperationsWindowSub; +class RoleSelectionSub; +struct RoleSelectionSubItems; +class SOPClassExtendedNegociationSub; +struct SOPClassExtendedNegociationSubItems; +/** + * \brief UserInformation + * Table 9-16 + * USER INFORMATION ITEM FIELDS + * + * TODO what is the goal of : + * + * Table 9-20 + * USER INFORMATION ITEM FIELDS + */ +class UserInformation +{ +public: + UserInformation(); + ~UserInformation(); + std::istream &Read(std::istream &is); + const std::ostream &Write(std::ostream &os) const; + size_t Size() const; + + void Print(std::ostream &os) const; + + const MaximumLengthSub &GetMaximumLengthSub() const { return MLS; } + MaximumLengthSub &GetMaximumLengthSub() { return MLS; } + + void AddRoleSelectionSub( RoleSelectionSub const & r ); + void AddSOPClassExtendedNegociationSub( SOPClassExtendedNegociationSub const & s ); + +private: + static const uint8_t ItemType; + static const uint8_t Reserved2; + uint16_t ItemLength; // len of + MaximumLengthSub MLS; + ImplementationClassUIDSub ICUID; + AsynchronousOperationsWindowSub *AOWS; + RoleSelectionSubItems *RSSI; + SOPClassExtendedNegociationSubItems *SOPCENSI; + ImplementationVersionNameSub IVNS; + + UserInformation(const UserInformation&); // Not implemented +public: + UserInformation &operator=(const UserInformation&); +}; + +} // end namespace network + +} // end namespace gdcm + +#endif //GDCMUSERINFORMATION_H diff --git a/gdcm/Testing/.NoDartCoverage b/gdcm/Testing/.NoDartCoverage new file mode 100644 index 0000000..3c99729 --- /dev/null +++ b/gdcm/Testing/.NoDartCoverage @@ -0,0 +1 @@ +# do not do coverage in this directory diff --git a/gdcm/Testing/CMakeLists.txt b/gdcm/Testing/CMakeLists.txt new file mode 100644 index 0000000..66fc2da --- /dev/null +++ b/gdcm/Testing/CMakeLists.txt @@ -0,0 +1,40 @@ + +find_package(DCMTK) +find_package(DICOM3TOOLS) + +subdirs( + Source + ) + +#----------------------------------------------------------------------------- +# Here is one cool test: you can pretty much test all configuration using +# ctest...well except one, the case where a user set BUILD_TESTING=OFF +# since this would deactivate the dashboard and would not submit...doh! +# So instead let's create a test that would build gdcm with this option +if(GDCM_TEST_BOOTSTRAP) + add_test(BuildGDCM ${CMAKE_CTEST_COMMAND} + --build-and-test ${GDCM_SOURCE_DIR} ${GDCM_BINARY_DIR}/GDCMLocal + --build-two-config + --build-generator ${CMAKE_GENERATOR} + --build-makeprogram ${CMAKE_MAKE_PROGRAM} + --build-project GDCMLOCAL + --build-options -DGDCM_BUILD_TESTING:BOOL=OFF -DGDCM_BUILD_SHARED_LIBS:BOOL=ON -DGDCM_WRAP_PYTHON:BOOL=ON -DGDCM_WRAP_CSHARP:BOOL=ON -DGDCM_SUPPORT_BROKEN_IMPLEMENTATION:BOOL=OFF + ) + add_test(InstallGDCM ${CMAKE_CTEST_COMMAND} + --build-and-test ${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} + --build-generator ${CMAKE_GENERATOR} + --build-project GDCM + --build-makeprogram ${CMAKE_MAKE_PROGRAM} + --build-noclean + --build-target install + ) + add_test(BuildStaticGDCM ${CMAKE_CTEST_COMMAND} + --build-and-test ${GDCM_SOURCE_DIR} ${GDCM_BINARY_DIR}/GDCMLocal2 + --build-two-config + --build-generator ${CMAKE_GENERATOR} + --build-makeprogram ${CMAKE_MAKE_PROGRAM} + --build-project GDCMLOCAL2 + --build-options -DGDCM_BUILD_TESTING:BOOL=ON -DGDCM_BUILD_SHARED_LIBS:BOOL=OFF -DGDCM_SUPPORT_BROKEN_IMPLEMENTATION:BOOL=OFF -DGDCM_LEGACY_REMOVE:BOOL=ON + --test-command ${CMAKE_CTEST_COMMAND} + ) +endif() diff --git a/gdcm/Testing/Source/Attribute/CMakeLists.txt b/gdcm/Testing/Source/Attribute/CMakeLists.txt new file mode 100644 index 0000000..e69de29 diff --git a/gdcm/Testing/Source/CMakeLists.txt b/gdcm/Testing/Source/CMakeLists.txt new file mode 100644 index 0000000..6d1a464 --- /dev/null +++ b/gdcm/Testing/Source/CMakeLists.txt @@ -0,0 +1,19 @@ +# All the tests + +# ADD_SUBDIRECTORY is required here to properly get the definition variables later on: +add_subdirectory(Data) +# Get the variables defined in Data subdirs: +get_directory_property(gdcm_data_dicomdir_filenames_glob DIRECTORY Data DEFINITION GDCM_DATA_DICOMDIR_FILENAMES_GLOB) +get_directory_property(gdcm_data_image_filenames_glob DIRECTORY Data DEFINITION GDCM_DATA_IMAGE_FILENAMES_GLOB) +get_directory_property(gdcm_data_filenames_glob DIRECTORY Data DEFINITION GDCM_DATA_FILENAMES_GLOB) +get_directory_property(black_list_reader DIRECTORY Data DEFINITION BLACK_LIST_READER) + +subdirs( + Attribute + Common + DataDictionary + DataStructureAndEncodingDefinition + InformationObjectDefinition + MediaStorageAndFileFormat + MessageExchangeDefinition +) diff --git a/gdcm/Testing/Source/Common/CMakeLists.txt b/gdcm/Testing/Source/Common/CMakeLists.txt new file mode 100644 index 0000000..5fee2e1 --- /dev/null +++ b/gdcm/Testing/Source/Common/CMakeLists.txt @@ -0,0 +1,5 @@ +subdirs(Cxx) + +if(GDCM_WRAP_PYTHON) + subdirs(Python) +endif() diff --git a/gdcm/Testing/Source/Common/Cxx/CMakeLists.txt b/gdcm/Testing/Source/Common/Cxx/CMakeLists.txt new file mode 100644 index 0000000..11af96a --- /dev/null +++ b/gdcm/Testing/Source/Common/Cxx/CMakeLists.txt @@ -0,0 +1,58 @@ +# Define the tests for Common +# Common +set(Common_TEST_SRCS + TestVersion + TestCommand + TestCryptographicMessageSyntax + TestDummyValueGenerator + TestASN1 + TestTesting + TestSystem3 + TestSwapper + TestByteSwap + TestString + TestString2 + TestTerminal + TestFilenameGenerator + TestObject + TestSmartPointer + TestSwapCode + TestSystem1 + TestSystem2 + TestTrace + TestTypes + TestUnpacker12Bits + TestBase64 + ) + +if(GDCM_DATA_ROOT) +list(APPEND Common_TEST_SRCS + TestDirectory + TestFilename + TestMD5 + ) +if(GDCM_USE_SYSTEM_OPENSSL) + list(APPEND Common_TEST_SRCS TestSHA1) +endif() +endif() + +# Add the include paths +include_directories( + "${GDCM_BINARY_DIR}/Source/Common" + "${GDCM_SOURCE_DIR}/Source/Common" + "${GDCM_SOURCE_DIR}/Source/DataStructureAndEncodingDefinition" + ) + +create_test_sourcelist(CommonTests gdcmCommonTests.cxx ${Common_TEST_SRCS} + EXTRA_INCLUDE gdcmTestDriver.h + ) +add_executable(gdcmCommonTests ${CommonTests}) +target_link_libraries(gdcmCommonTests gdcmCommon) + +#Don't understand why I need that ?? +set(GDCM_Common_TESTS "${EXECUTABLE_OUTPUT_PATH}/gdcmCommonTests") + +# Loop over files and create executables +foreach(name ${Common_TEST_SRCS}) + add_test(NAME ${name} COMMAND ${GDCM_Common_TESTS} ${name}) +endforeach() diff --git a/gdcm/Testing/Source/Common/Cxx/TestASN1.cxx b/gdcm/Testing/Source/Common/Cxx/TestASN1.cxx new file mode 100644 index 0000000..f2472a8 --- /dev/null +++ b/gdcm/Testing/Source/Common/Cxx/TestASN1.cxx @@ -0,0 +1,37 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmASN1.h" + +struct MyASN1 : public gdcm::ASN1 +{ + int TestPBKDF2() + { + return this->gdcm::ASN1::TestPBKDF2(); + } +}; + +int TestASN1(int argc, char *argv[]) +{ + if( argc < 1 ) + { + return 1; + } + const char *filename = argv[1]; + MyASN1 asn1; + asn1.ParseDumpFile( filename ); + + asn1.TestPBKDF2(); + + return 0; +} diff --git a/gdcm/Testing/Source/Common/Cxx/TestBase64.cxx b/gdcm/Testing/Source/Common/Cxx/TestBase64.cxx new file mode 100644 index 0000000..e2132cc --- /dev/null +++ b/gdcm/Testing/Source/Common/Cxx/TestBase64.cxx @@ -0,0 +1,112 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmBase64.h" +#include "gdcmTesting.h" +#include "gdcmSystem.h" + +#include + +int TestBase64(int , char *[]) +{ + const char str[] = "GDCM Test Base64 Encoding"; + //const char str64[] = "R0RDTSBUZXN0IEJhc2U2NCBFbmNvZGluZwA="; (contains trailing \0 ) + const char str64[] = "R0RDTSBUZXN0IEJhc2U2NCBFbmNvZGluZw=="; + + //std::cout << "sizeof:" << sizeof(str) << std::endl; + //std::cout << "strlen:" << strlen(str) << std::endl; + const size_t l1 = gdcm::Base64::GetEncodeLength( str, strlen(str) ); + if( l1 != 36 ) + { + std::cerr << "Fail 1: " << l1 << std::endl; + return 1; + } + + char buffer[256] = {}; + if( l1 > sizeof(buffer) ) + { + std::cerr << "Fail 2" << std::endl; + return 1; + } + + size_t l2 = gdcm::Base64::Encode( buffer, sizeof(buffer), str, strlen(str) ); + if( l2 == 0 ) + { + std::cerr << "Fail 3: " << l2 << std::endl; + return 1; + } + + if( strcmp( buffer, str64 ) != 0 ) + { + std::cerr << "Found: " << buffer << " instead of " << str64 << std::endl; + return 1; + } + + size_t lbuffer = strlen(buffer); + if( lbuffer != l1 ) + { + std::cerr << "Fail 4" << std::endl; + return 1; + } + + const size_t l3 = gdcm::Base64::GetDecodeLength( buffer, l1 ); + if( l3 != 25 ) + { + std::cerr << "Fail 5: " << l3 << std::endl; + return 1; + } + + if( l3 != sizeof(str) - 1 ) + { + std::cerr << "Fail 6" << std::endl; + return 1; + } + + char buffer2[256]; + if( l3 > sizeof(buffer2) ) + { + std::cerr << "Fail 7" << std::endl; + return 1; + } + const size_t l4 = gdcm::Base64::Decode( buffer2, sizeof(buffer2), buffer, l1); + if( l4 == 0 ) + { + std::cerr << "Fail 8" << std::endl; + return 1; + } + + if( strncmp( str, buffer2, strlen(str) ) != 0 ) + { + std::cerr << "Fail 9: " << str << " vs " << buffer2 << std::endl; + return 1; + } + + const unsigned char bin[] = { 0x00, 0x00, 0xc8, 0x43 }; + const char bin64[] = "AADIQw=="; + + const size_t l5 = gdcm::Base64::Decode( buffer2, sizeof(buffer2), bin64, strlen(bin64) ); + if( l5 == 0 ) + { + std::cerr << "Fail 10" << std::endl; + return 1; + } + + if( memcmp( bin, buffer2, sizeof(bin) ) != 0 ) + { + std::cerr << "Fail 11" << std::endl; + return 1; + } + + + return 0; +} diff --git a/gdcm/Testing/Source/Common/Cxx/TestByteSwap.cxx b/gdcm/Testing/Source/Common/Cxx/TestByteSwap.cxx new file mode 100644 index 0000000..4b4c431 --- /dev/null +++ b/gdcm/Testing/Source/Common/Cxx/TestByteSwap.cxx @@ -0,0 +1,145 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmTypes.h" +#include "gdcmSwapCode.h" +#include "gdcmByteSwap.h" + +#include // memcpy + +int myfunc() +{ + char vl_str[4]; + const char raw[] = "\000\000\000\004"; + memcpy(vl_str, raw, 4); + uint32_t vl; + gdcm::ByteSwap::SwapRangeFromSwapCodeIntoSystem((uint32_t*)(&vl_str), gdcm::SwapCode::BigEndian, 1); + memcpy(&vl, vl_str, 4); + if( vl != 0x00000004 ) + { + std::cerr << std::hex << "vl: " << vl << std::endl; + return 1; + } + + gdcm::ByteSwap::SwapFromSwapCodeIntoSystem(vl, gdcm::SwapCode::LittleEndian); + if( vl != 0x00000004 ) + { + std::cerr << std::hex << "vl: " << vl << std::endl; + return 1; + } + + gdcm::ByteSwap::SwapFromSwapCodeIntoSystem(vl, gdcm::SwapCode::BigEndian); + std::cout << std::hex << "vl: " << vl << std::endl; + if( vl != 0x4000000 ) + { + return 1; + } + + return 0; +} + +int TestByteSwap(int , char *[]) +{ + gdcm::SwapCode sc = gdcm::SwapCode::Unknown; + if ( gdcm::ByteSwap::SystemIsBigEndian() ) + { + sc = gdcm::SwapCode::BigEndian; + } + else if ( gdcm::ByteSwap::SystemIsLittleEndian() ) + { + sc = gdcm::SwapCode::LittleEndian; + } + if( sc == gdcm::SwapCode::Unknown ) + { + return 1; + } + + std::cout << "sc: " << sc << std::endl; + + uint16_t t = 0x1234; + gdcm::ByteSwap::SwapFromSwapCodeIntoSystem(t, sc); + if( sc == gdcm::SwapCode::BigEndian ) + { + if( t != 0x3412 ) + { + std::cerr << std::hex << "t: " << t << std::endl; + return 1; + } + // ok test pass rest value to old one + t = 0x1234; + } + else if ( sc == gdcm::SwapCode::LittleEndian ) + { + if( t != 0x1234 ) + { + std::cerr << std::hex << "t: " << t << std::endl; + return 1; + } + } + + union { char n[2]; uint16_t tn; } u16; + memcpy(u16.n, &t, 2 ); + gdcm::ByteSwap::SwapRangeFromSwapCodeIntoSystem(&u16.tn, sc, 1); + uint16_t tn = u16.tn; + if( sc == gdcm::SwapCode::BigEndian ) + { + if( tn != 0x3412 ) + { + std::cerr << std::hex << "tn: " << tn << std::endl; + return 1; + } + // ok test pass rest value to old one + t = 0x1234; + } + else if ( sc == gdcm::SwapCode::LittleEndian ) + { + if( tn != 0x1234 ) + { + std::cerr << std::hex << "tn: " << tn << std::endl; + return 1; + } + } + gdcm::ByteSwap::SwapRangeFromSwapCodeIntoSystem(&u16.tn, gdcm::SwapCode::BigEndian, 1); + tn = u16.tn; + if( sc == gdcm::SwapCode::LittleEndian ) + { + if( tn != 0x3412 ) + { + std::cerr << std::hex << "tn: " << tn << std::endl; + return 1; + } + } + else if ( sc == gdcm::SwapCode::BigEndian ) + { + if( tn != 0x1234 ) + { + std::cerr << std::hex << "tn: " << tn << std::endl; + return 1; + } + } + + if( myfunc() ) + { + return 1; + } + + uint16_t array[] = { 0x1234 }; + gdcm::ByteSwap::SwapRangeFromSwapCodeIntoSystem(array, + gdcm::SwapCode::BigEndian,2); + if ( array[0] != 0x3412 ) + { + return 1; + } + + return 0; +} diff --git a/gdcm/Testing/Source/Common/Cxx/TestCommand.cxx b/gdcm/Testing/Source/Common/Cxx/TestCommand.cxx new file mode 100644 index 0000000..2344c76 --- /dev/null +++ b/gdcm/Testing/Source/Common/Cxx/TestCommand.cxx @@ -0,0 +1,34 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmCommand.h" +#include "gdcmEvent.h" +#include "gdcmSmartPointer.h" + +using gdcm::SmartPointer; + +struct Watcher {}; + +void foo(gdcm::Command *c) +{ + c->Execute((gdcm::Subject*)0, gdcm::AnyEvent() ); +} + +int TestCommand(int , char *[]) +{ + SmartPointer > mc = gdcm::MemberCommand::New(); + foo(mc); + SmartPointer > smc = gdcm::SimpleMemberCommand::New(); + foo(smc); + return 0; +} diff --git a/gdcm/Testing/Source/Common/Cxx/TestCryptographicMessageSyntax.cxx b/gdcm/Testing/Source/Common/Cxx/TestCryptographicMessageSyntax.cxx new file mode 100644 index 0000000..923893b --- /dev/null +++ b/gdcm/Testing/Source/Common/Cxx/TestCryptographicMessageSyntax.cxx @@ -0,0 +1,314 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmCryptoFactory.h" +#include +#include +#include +#include + +#include "gdcmFilename.h" +#include "gdcmTesting.h" + +static bool LoadFile(const char * filename, char* & buffer, size_t & bufLen) +{ + FILE * f = fopen(filename, "rb"); + if (f == NULL) + { + //gdcmErrorMacro("Couldn't open the file: " << filename); + return false; + } + fseek(f, 0L, SEEK_END); + long sz = ftell(f); + rewind(f); + buffer = new char[sz]; + bufLen = sz; + while (sz) + sz -= fread(buffer + bufLen - sz, sizeof(char), sz, f); + return true; +} + +static const gdcm::CryptographicMessageSyntax::CipherTypes ciphers[] = { + gdcm::CryptographicMessageSyntax::AES128_CIPHER, + gdcm::CryptographicMessageSyntax::AES192_CIPHER, + gdcm::CryptographicMessageSyntax::AES256_CIPHER, + gdcm::CryptographicMessageSyntax::DES3_CIPHER + }; + +static std::pair cip2str_data[] = { + std::make_pair(gdcm::CryptographicMessageSyntax::AES128_CIPHER, "AES128"), + std::make_pair(gdcm::CryptographicMessageSyntax::AES192_CIPHER, "AES192"), + std::make_pair(gdcm::CryptographicMessageSyntax::AES256_CIPHER, "AES256"), + std::make_pair(gdcm::CryptographicMessageSyntax::DES3_CIPHER, "3DES") +}; + +static std::map cip2str(cip2str_data, + cip2str_data + sizeof cip2str_data / sizeof cip2str_data[0]); + +const char * const tstr = "12345"; +const size_t tstr_l = strlen(tstr); +#define BUFSZ 5000 + +bool TestCMSProvider(gdcm::CryptographicMessageSyntax& cms, const char * provName) +{ + const std::string certpath = gdcm::Filename::Join(gdcm::Testing::GetSourceDirectory(), "/Testing/Source/Data/certificate.pem" ); + const std::string keypath = gdcm::Filename::Join(gdcm::Testing::GetSourceDirectory(), "/Testing/Source/Data/privatekey.pem" ); + const std::string encrypted_vector = gdcm::Filename::Join(gdcm::Testing::GetSourceDirectory(), "/Testing/Source/Data/encrypted_text" ); + + bool ret = true; + for (unsigned int i = 0; i < 4; i++) + { + char encout[BUFSZ] = {0}, decout[BUFSZ] = {0}; + size_t encoutlen = BUFSZ, decoutlen = BUFSZ; + cms.SetCipherType(ciphers[i]); + bool encryptSuccess = cms.Encrypt(encout, encoutlen, tstr, tstr_l); + if (!encryptSuccess) + { + std::cerr << provName << " using " << cip2str[ciphers[i]] << ": encryption failed" << std::endl; + ret = false; + continue; + } + bool decryptSuccess = cms.Decrypt(decout, decoutlen, encout, encoutlen); + if (!decryptSuccess) + { + std::cerr << provName << " using " << cip2str[ciphers[i]] << ": decryption failed" << std::endl; + ret = false; + continue; + } + if (decoutlen != tstr_l) + { + std::cerr << provName << " using " << cip2str[ciphers[i]] << ": decryted length different from original (" << decoutlen << " != " << tstr_l << ")" << std::endl; + ret = false; + continue; + } + if (memcmp(tstr, decout, tstr_l) != 0) + { + std::cerr << provName << " using " << cip2str[ciphers[i]] << ": decryted data different from original" << std::endl; + ret = false; + continue; + } + } + + return ret; +} + +bool TestCMSVector(gdcm::CryptographicMessageSyntax& cms, const char * provName) +{ + char decout[BUFSZ] = {0}; + size_t decoutlen = BUFSZ; + std::string encrypted_filename = gdcm::Filename::Join(gdcm::Testing::GetSourceDirectory(), "/Testing/Source/Data/encrypted_text" ); + const char * tv_plaintext = "1234567890abcdefghijklmnopqrstuvwxyz"; + size_t tv_plaintext_len = strlen(tv_plaintext); + + char * test_vector; + // FIXME : should I delete test_vector ? + size_t tvlen; + if (!LoadFile(encrypted_filename.c_str(), test_vector, tvlen)) + { + std::cerr << "Couldn't load encrypted file: " << encrypted_filename << std::endl; + return false; + } + bool decryptSuccess = cms.Decrypt(decout, decoutlen, test_vector, tvlen); + if (!decryptSuccess) + { + std::cerr << provName << " test vector decryption failed" << std::endl; + return false; + } + if (decoutlen != tv_plaintext_len) + { + std::cerr << provName << " test vector decryted length different from original (" << decoutlen << " != " << tstr_l << ")" << std::endl; + return false; + } + if (memcmp(tv_plaintext, decout, tv_plaintext_len) != 0) + { + std::cerr << provName << " test vector decryted data different from original" << std::endl; + return false; + } + + return true; +} + +bool TestCMSCompatibility(gdcm::CryptographicMessageSyntax& cms1, const char * provName1, gdcm::CryptographicMessageSyntax& cms2, const char * provName2) +{ + const std::string encrypted_vector = gdcm::Filename::Join(gdcm::Testing::GetSourceDirectory(), "/Testing/Source/Data/encrypted_text" ); + + bool ret = true; + for (int i = 0; i < 4; i++) + { + char encout[BUFSZ] = {0}, decout[BUFSZ] = {0}; + size_t encoutlen = BUFSZ, decoutlen = BUFSZ; + cms1.SetCipherType(ciphers[i]); + cms2.SetCipherType(ciphers[i]); + + bool encryptSuccess = cms1.Encrypt(encout, encoutlen, tstr, tstr_l); + if (!encryptSuccess) + { + std::cerr << provName1 << " & " << provName2 << " using " << cip2str[ciphers[i]] << ": encryption failed" << std::endl; + ret = false; + break; + } + bool decryptSuccess = cms2.Decrypt(decout, decoutlen, encout, encoutlen); + if (!decryptSuccess) + { + std::cerr << provName1 << " & " << provName2 << " using " << cip2str[ciphers[i]] << ": decryption failed" << std::endl; + ret = false; + break; + } + if (decoutlen != tstr_l) + { + std::cerr << provName1 << " & " << provName2 << " using " << cip2str[ciphers[i]] << ": decryted length different from original (" << decoutlen << " != " << tstr_l << ")" << std::endl; + ret = false; + break; + } + if (memcmp(tstr, decout, tstr_l) != 0) + { + std::cerr << provName1 << " & " << provName2 << " using " << cip2str[ciphers[i]] << ": decryted data different from original" << std::endl; + ret = false; + break; + } + } + + /* + char encout[BUFSZ] = {0}, decout[BUFSZ] = {0}; + size_t encoutlen = BUFSZ, decoutlen = BUFSZ; + for (int i = 0; i < 4; i++) + { + bool ret = true; + char encout[BUFSZ] = {0}, decout[BUFSZ] = {0}; + size_t encoutlen = BUFSZ, decoutlen = BUFSZ; + cms1.SetCipherType(ciphers[i]); + cms2.SetCipherType(ciphers[i]); + //cms2.Encrypt(encout, encoutlen, tstr, tstr_l); + //cms1.Decrypt(decout, decoutlen, encout, encoutlen); + //assert(decoutlen == tstr_l); + //assert(memcmp(tstr, decout, tstr_l) == 0); + + bool encryptSuccess = cms1.Encrypt(encout, encoutlen, tstr, tstr_l); + if (!encryptSuccess) + { + std::cerr << provName1 << " & " << provName2 << " using " << cip2str[ciphers[i]] << ": encryption failed" << std::endl; + ret = false; + break; + } + bool decryptSuccess = cms2.Decrypt(decout, decoutlen, encout, encoutlen); + if (!decryptSuccess) + { + std::cerr << provName1 << " & " << provName2 << " using " << cip2str[ciphers[i]] << ": decryption failed" << std::endl; + ret = false; + break; + } + if (decoutlen != tstr_l) + { + std::cerr << provName1 << " & " << provName2 << " using " << cip2str[ciphers[i]] << ": decryted length different from original (" << decoutlen << " != " << tstr_l << ")" << std::endl; + ret = false; + break; + } + if (memcmp(tstr, decout, tstr_l) != 0) + { + std::cerr << provName1 << " & " << provName2 << " using " << cip2str[ciphers[i]] << ": decryted data different from original" << std::endl; + ret = false; + break; + } + }*/ + return ret; +} + +int TestCryptographicMessageSyntax(int, char *[]) +{ + std::string certpath = gdcm::Filename::Join(gdcm::Testing::GetSourceDirectory(), "/Testing/Source/Data/certificate.pem" ); + std::string keypath = gdcm::Filename::Join(gdcm::Testing::GetSourceDirectory(), "/Testing/Source/Data/privatekey.pem" ); + bool bret = true; + //typedef std::tuple StringCMSPairType; + std::vector availableCMS; + std::vector availableCMSName; + + +#ifdef GDCM_USE_SYSTEM_OPENSSL + gdcm::CryptoFactory* osslp7 = gdcm::CryptoFactory::GetFactoryInstance(gdcm::CryptoFactory::OPENSSLP7); + std::auto_ptr ocmsp7(osslp7->CreateCMSProvider()); + ocmsp7->ParseKeyFile(keypath.c_str()); + ocmsp7->ParseCertificateFile(certpath.c_str()); + bret = TestCMSProvider(*ocmsp7, "OpenSSL PKCS7") && bret; + bret = TestCMSVector(*ocmsp7, "OpenSSL PKCS7") && bret; + availableCMS.push_back(ocmsp7.get()); + availableCMSName.push_back("OpenSSL PKCS7"); +#endif + +#ifdef GDCM_USE_SYSTEM_OPENSSL +#ifdef GDCM_HAVE_CMS_RECIPIENT_PASSWORD + gdcm::CryptoFactory* ossl = gdcm::CryptoFactory::GetFactoryInstance(gdcm::CryptoFactory::OPENSSL); + std::auto_ptr ocms(ossl->CreateCMSProvider()); + ocms->ParseKeyFile(keypath.c_str()); + ocms->ParseCertificateFile(certpath.c_str()); + bret = TestCMSProvider(*ocms, "OpenSSL CMS") && bret; + bret = TestCMSVector(*ocms, "OpenSSL CMS") && bret; + availableCMS.push_back(ocms.get()); + availableCMSName.push_back("OpenSSL CMS"); +#endif +#endif + +#ifdef WIN32 + gdcm::CryptoFactory* capi = gdcm::CryptoFactory::GetFactoryInstance(gdcm::CryptoFactory::CAPI); + std::auto_ptr ccms(capi->CreateCMSProvider()); + ccms->ParseCertificateFile(certpath.c_str()); + ccms->ParseKeyFile(keypath.c_str()); + bret = TestCMSProvider(*ccms, "CAPI") && bret; + bret = TestCMSVector(*ccms, "CAPI") && bret; + availableCMS.push_back(ccms.get()); + availableCMSName.push_back("CAPI"); +#endif + + for (size_t i = 0; i < availableCMS.size(); ++i) + for (size_t j = i+1; j < availableCMS.size(); ++j) + bret = TestCMSCompatibility(*availableCMS[i], availableCMSName[i].c_str(), *availableCMS[j], availableCMSName[j].c_str()) && bret; + + return (bret ? 0 : 1); +} + +int TestPasswordBasedEncryption(int, char *[]) +{ + const char *directory = gdcm::Testing::GetDataRoot(); + std::string encrypted_dicomdir = + gdcm::Filename::Join(directory, "/securedicomfileset/DICOMDIR" ); + std::string encrypted_image = + gdcm::Filename::Join(directory, "/securedicomfileset/IMAGES/IMAGE1" ); + +#ifdef GDCM_USE_SYSTEM_OPENSSL + gdcm::CryptoFactory* ossl = gdcm::CryptoFactory::GetFactoryInstance(gdcm::CryptoFactory::OPENSSL); + std::auto_ptr ocms(ossl->CreateCMSProvider()); + + ocms->SetPassword("password", strlen("password")); + if (!TestCMSProvider(*ocms, "OpenSSL")) + return 1; + + char decout[BUFSZ] = {0}; + size_t decoutlen = BUFSZ; + char * ddir = new char[5000]; + size_t ddirlen = 5000; + LoadFile(encrypted_dicomdir.c_str(), ddir, ddirlen); + bool decryptSuccess = ocms->Decrypt(decout, decoutlen, ddir, ddirlen); + if (!decryptSuccess) + { + std::cerr << "OpenSSL sample DICOMDIR decryption failed" << std::endl; + return 1; + } + if (decoutlen == 0) + { + std::cerr << "OpenSSL sample DICOMDIR decrypted length == 0" << std::endl; + return 1; + } + +#endif + + return 0; +} diff --git a/gdcm/Testing/Source/Common/Cxx/TestDirectory.cxx b/gdcm/Testing/Source/Common/Cxx/TestDirectory.cxx new file mode 100644 index 0000000..d64493d --- /dev/null +++ b/gdcm/Testing/Source/Common/Cxx/TestDirectory.cxx @@ -0,0 +1,71 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmDirectory.h" +#include "gdcmTesting.h" +#include "gdcmSystem.h" + +#include // atoi + +int TestOneDirectory(const char *path, bool recursive = false ) +{ + if( !gdcm::System::FileIsDirectory(path) ) + { + std::cerr << path << " is not a directory" << std::endl; + return 1; + } + + gdcm::Directory d; + d.Load( path, recursive ); + //d.Print( std::cout ); + + if( d.GetToplevel() != path ) + { + std::cerr << d.GetToplevel() << " != " << path << std::endl; + return 1; + } + gdcm::Directory::FilenamesType const &files = d.GetFilenames(); + for(gdcm::Directory::FilenamesType::const_iterator it = files.begin(); it != files.end(); ++it ) + { + const char *filename = it->c_str(); + if( !gdcm::System::FileExists(filename) ) + { + return 1; + } + } + + return 0; +} + +int TestDirectory(int argc, char *argv[]) +{ + int res = 0; + if( argc > 1 ) + { + bool recursive = false; + if ( argc > 2 ) + { + recursive = (atoi(argv[2]) > 0 ? true : false); + } + res += TestOneDirectory( argv[1], recursive); + } + else + { + const char *path = gdcm::Testing::GetDataRoot(); + res += TestOneDirectory( path ); + } + + //res += TestOneDirectory( "" ); + + return res; +} diff --git a/gdcm/Testing/Source/Common/Cxx/TestDummyValueGenerator.cxx b/gdcm/Testing/Source/Common/Cxx/TestDummyValueGenerator.cxx new file mode 100644 index 0000000..d953813 --- /dev/null +++ b/gdcm/Testing/Source/Common/Cxx/TestDummyValueGenerator.cxx @@ -0,0 +1,38 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmDummyValueGenerator.h" +#include "gdcmTesting.h" + +int TestDummyValueGenerator(int , char *[]) +{ + gdcm::DummyValueGenerator dvg; (void)dvg; + const char patientid1[] = "hello"; + const char patientid2[] = "hello "; + // Because patientid1 & patientid2 are equivalent in DICOM we need to be able to generate + // identical replacement value in case of de-identifier operation: + + const char *ptr1 = gdcm::DummyValueGenerator::Generate( patientid1 ); + const char *ptr2 = gdcm::DummyValueGenerator::Generate( patientid2 ); + if( !ptr1 || !ptr2 ) return 1; + + std::string str1 = ptr1; + std::string str2 = ptr2; + + if( str1 != str2 ) + { + return 1; + } + + return 0; +} diff --git a/gdcm/Testing/Source/Common/Cxx/TestFilename.cxx b/gdcm/Testing/Source/Common/Cxx/TestFilename.cxx new file mode 100644 index 0000000..23917f8 --- /dev/null +++ b/gdcm/Testing/Source/Common/Cxx/TestFilename.cxx @@ -0,0 +1,237 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmFilename.h" +#include "gdcmSystem.h" +#include "gdcmTesting.h" + +#include +#include +#include // EXIT_FAILURE + +/*! + * \test TestFilename + * bla coucou + */ +int TestFilename(int argc, char *argv[]) +{ + (void)argc;(void)argv; + std::string path = "/gdcm/is/a/dicom/"; + std::string name = "library.dcm"; + std::string fullpath = path; + fullpath += '/'; + fullpath += name; + gdcm::Filename f( fullpath.c_str() ); + std::cout << f.GetPath() << std::endl; + std::cout << f.GetName() << std::endl; + std::cout << f.GetExtension() << std::endl; + std::cout << f << std::endl; + + if( f.GetPath() != path ) + { + std::cerr << "Wrong path" << std::endl; + return 1; + } + if( f.GetName() != name) + { + std::cerr << "Wrong name" << std::endl; + return 1; + } + if( f.GetExtension() != std::string( ".dcm" ) ) + { + std::cerr << "Wrong extension" << std::endl; + return 1; + } +// if( std::string( "/tmp/debug.dcm" ) != f ) +// { +// return 1; +// } + + std::string dataroot = gdcm::Testing::GetDataRoot(); + std::string current = dataroot + "/test.acr"; + if( !gdcm::System::FileExists( current.c_str() ) ) + { + std::cerr << "File does not exist: " << current << std::endl; + return 1; + } + std::cerr << "Current:" << current << std::endl; + gdcm::Filename fn0(current.c_str()); + std::cerr << fn0.GetPath() << std::endl; + std::string current2 = fn0.GetPath(); + current2 += "/./"; + current2 += fn0.GetName(); + std::cerr << current2 << std::endl; + if( current2 == current ) + { + return 1; + } + gdcm::Filename fn2(current2.c_str()); + if( !fn0.IsIdentical(fn2)) + { + return 1; + } + + { + const char *curprocfn = gdcm::System::GetCurrentProcessFileName(); + if( curprocfn ) + { + gdcm::Filename fn( curprocfn ); + std::string str = fn.GetPath(); + std::cout << str << std::endl; + } + } + +{ +#ifdef GDCM_HAVE_WCHAR_IFSTREAM + const wchar_t ifn[] = L"UnicodeFileName.dcm"; + const wchar_t* fn = gdcm::Testing::GetTempFilenameW(ifn); + std::ofstream outputFileStream( fn ); + if ( ! outputFileStream.is_open() ) + { + std::cerr << "Failed to read UTF-16: " << fn << std::endl; + return EXIT_FAILURE; + } + outputFileStream.close(); +#else + //char ifn2[] = "α.dcm"; //MM: I do not think this is legal C++... + const char ifn2[] = "\xCE\xB1.dcm"; // this is the proper way to write it (portable) + const char ifn1[] = { + (char)0xCE, + (char)0xB1, + '.', + 'd', + 'c', + 'm', + 0}; // trailing NULL char + std::string sfn1 = gdcm::Testing::GetTempFilename(ifn1); + const char *csfn1 = sfn1.c_str(); + std::string sfn2 = gdcm::Testing::GetTempFilename(ifn2); + const char *csfn2 = sfn2.c_str(); + std::ofstream outputFileStream( csfn1 ); + if ( ! outputFileStream.is_open() ) + { + std::cerr << "Failed to create UTF-8 file: " << csfn1 << std::endl; + return EXIT_FAILURE; + } + const char secret[]= "My_secret_pass_phrase"; + outputFileStream << secret; + outputFileStream.close(); + if( !gdcm::System::FileExists(csfn1) ) + { + std::cerr << "File does not exist: " << csfn1 << std::endl; + return EXIT_FAILURE; + } + + // Now open version 2 (different encoding) + std::ifstream inputFileStream( csfn2 ); + if ( ! inputFileStream.is_open() ) + { + std::cerr << "Failed to open UTF-8 file: " << csfn2 << std::endl; + return EXIT_FAILURE; + } + std::string ssecret; + inputFileStream >> ssecret; + inputFileStream.close(); + if( ssecret != secret ) + { + std::cerr << "Found: " << ssecret << " should have been " << secret << std::endl; + return EXIT_FAILURE; + } + + if( !gdcm::System::RemoveFile(csfn1) ) + { + std::cerr << "Could not remvoe #1: " << csfn1 << std::endl; + return EXIT_FAILURE; + } + // cannot remove twice the same file: + if( gdcm::System::RemoveFile(csfn2) ) + { + std::cerr << "Could remvoe #2 a second time...seriously " << csfn2 << std::endl; + return EXIT_FAILURE; + } +#endif +} + +{ + +//#define TESTLONGPATHNAMES +#ifdef TESTLONGPATHNAMES + //why are we testing this? This is the operating system's deal, not GDCM's. + //GDCM is not responsible for long path names, and cannot fix this issue. + //if we want to move this to a configuration option (ie, test for long pathnames), + //then we can--otherwise, windows users should just beware of this issue. + //This path limit has been the case since Windows 95, and is unlikely to change any time soon. + + // Apparently there is an issue with long pathanem i nWin32 system: + // http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx#maxpath + // The only way to work around the 260 byte limitation it appears as if we + // have to deal with universal naming convention (UNC) path. + const char subdir[] = + "very/long/pathname/foobar/hello_world/toreproduceabugindpkg/pleaseconsider/" + "very/long/pathname/foobar/hello_world/toreproduceabugindpkg/pleaseconsider/" + "very/long/pathname/foobar/hello_world/toreproduceabugindpkg/pleaseconsider/" + "very/long/pathname/foobar/hello_world/toreproduceabugindpkg/pleaseconsider/"; + const char *directory_ = gdcm::Testing::GetTempDirectory(subdir); +#ifdef _WIN32 + gdcm::Filename mydir( directory_ ); + std::string unc = "\\\\?\\";//on Windows, to use UNC, you need to: + //a) append this string + //b) use a network drive (ie, the gdcm file is made on a network drive) that + //c) you have access to. + //I don't think this is a good or useful test. mmr + unc += mydir.ToWindowsSlashes(); + const char *directory = unc.c_str(); +#else + const char *directory = directory_; +#endif + if( !gdcm::System::MakeDirectory(directory)) + { + std::cerr << "Failed to create directory with long path: " << directory << std::endl; + return EXIT_FAILURE; + } + std::string sfn = gdcm::Testing::GetTempFilename( "dummy.dcm", subdir ); + std::cerr << "Long path is: " << sfn.size() << std::endl; + std::cerr << "Long path is: " << sfn << std::endl; + if( sfn.size() > 260 ) + { + const char *fn = sfn.c_str(); + // Should demontrate the issue + std::ofstream outputFileStream( fn ); + if ( ! outputFileStream.is_open() ) + { + std::cerr << "Failed to create file with long path: " << fn << std::endl; + return EXIT_FAILURE; + } + outputFileStream.close(); + if( !gdcm::System::FileExists(fn) ) + { + std::cerr << "File does not exist: " << fn << std::endl; + return EXIT_FAILURE; + } + if( !gdcm::System::RemoveFile(fn) ) + { + std::cerr << "Could not remvoe: " << fn << std::endl; + return EXIT_FAILURE; + } + + } +else +{ + std::cerr << "seriously " << fn << std::endl; + return EXIT_FAILURE; +} +#endif //TESTLONGPATHNAMES +} + + return 0; +} diff --git a/gdcm/Testing/Source/Common/Cxx/TestFilenameGenerator.cxx b/gdcm/Testing/Source/Common/Cxx/TestFilenameGenerator.cxx new file mode 100644 index 0000000..cf929f5 --- /dev/null +++ b/gdcm/Testing/Source/Common/Cxx/TestFilenameGenerator.cxx @@ -0,0 +1,36 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmFilenameGenerator.h" + +#include + +int TestFilenameGenerator(int , char *[]) +{ + gdcm::FilenameGenerator fg; + const char pattern[] = "/tmp/bla%01d"; + const unsigned int nfiles = 11; + fg.SetPattern( pattern ); + fg.SetNumberOfFilenames( nfiles ); + if( !fg.Generate() ) + { + std::cerr << "Could not generate" << std::endl; + return 1; + } + for( unsigned int i = 0; i < nfiles; ++i ) + { + std::cout << fg.GetFilename( i ) << std::endl; + } + + return 0; +} diff --git a/gdcm/Testing/Source/Common/Cxx/TestMD5.cxx b/gdcm/Testing/Source/Common/Cxx/TestMD5.cxx new file mode 100644 index 0000000..18bd8e6 --- /dev/null +++ b/gdcm/Testing/Source/Common/Cxx/TestMD5.cxx @@ -0,0 +1,305 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmMD5.h" +#include "gdcmFilename.h" +#include "gdcmSystem.h" +#include "gdcmTrace.h" +#include "gdcmTesting.h" + +#include +#include // strcmp + +static const char * const gdcmMD5SumFiles[][2] = { +{ "f5ae1418f6ec07ae13522c18ff1e067a" , "00191113.dcm" }, +{ "c2fdbb35ba2a179939a8608e1320c7ac" , "012345.002.050.dcm" }, +{ "4b8bed2f8da2fa6a260764e62eb3731b" , "05115014-mr-siemens-avanto-syngo-with-palette-icone.dcm" }, +{ "a01a44c67a88d5a98ecdc214e412c585" , "05148044-mr-siemens-avanto-syngo.dcm" }, +{ "7ddb7cc42cf3191a248a60f66661b380" , "3E768EB7.dcm" }, +{ "a0452c3bb9303ad8ebc7f8a166cc8190" , "ACUSON-24-YBR_FULL-RLE-b.dcm" }, +{ "916b12bdf36d60a0b0ae39451d86ddb4" , "ACUSON-24-YBR_FULL-RLE.dcm" }, +{ "a4d1faf3a3a4c8b0cdf8605ef0ab48b5" , "ALOKA_SSD-8-MONO2-RLE-SQ.dcm" }, +{ "00c78123ea2d8a9f1452f0da37383d85" , "BugGDCM2_UndefItemWrongVL.dcm" }, +{ "0b4cfdaebfa3944940bed290c0a29a5b" , "CR-MONO1-10-chest.dcm" }, +{ "d4f286ee295ac03856370e4ff0fe60a9" , "CT_16b_signed-UsedBits13.dcm" }, +{ "0e03332d250a8a1a5d3c0699b1cf6b1d" , "CT-MONO2-12-lomb-an2.acr" }, +{ "102528014fa6ff9758c76745090b7550" , "CT-MONO2-16-ankle.dcm" }, +{ "a21649de46e5f5609ef6e227999a1dc8" , "CT-MONO2-16-brain.dcm" }, +{ "56caa0050cd61dee0bfb41559dbd6a33" , "CT-MONO2-16-chest.dcm" }, +{ "5e8efa7ebe3a4c47c01a64f80b244b2c" , "CT-MONO2-16-ort.dcm" }, +{ "abe6a2e0b1a1d636b6a775291b44b7d0" , "CT-MONO2-8-abdo.dcm" }, +{ "442e1966eba2fd0eb8fab685c99cc388" , "CT-SIEMENS-Icone-With-PaletteColor.dcm" }, +{ "7dbc75bccddcb7177796c1fa3509ab09" , "CT-SIEMENS-MissingPixelDataInIconSQ.dcm" }, +{ "6155e751818ede1db17aa848d882beda" , "D_CLUNIE_CT1_J2KI.dcm" }, +{ "7e59d70ed013175815a6c8a498d481f1" , "D_CLUNIE_CT1_J2KR.dcm" }, +{ "073960e6c249b45bd6341e3397637478" , "D_CLUNIE_CT1_JPLL.dcm" }, +{ "53d722b71a881e386005ec3c83bd78a1" , "D_CLUNIE_CT1_RLE.dcm" }, +{ "8577a89b3906c01731641e177dda0f88" , "D_CLUNIE_CT2_JPLL.dcm" }, +{ "681c50b2a496cb5c2d7bb964108649d2" , "D_CLUNIE_CT2_RLE.dcm" }, +{ "64f39d9d812d999b689cb9dad069ed3a" , "D_CLUNIE_MR1_JPLL.dcm" }, +{ "c14fd84b399f305ddd71a547ecbaaa13" , "D_CLUNIE_MR1_JPLY.dcm" }, +{ "45346d785b6c3a8be12b271abb745b13" , "D_CLUNIE_MR1_RLE.dcm" }, +{ "82093a4fc15b10b791b3d884a1cdc9c6" , "D_CLUNIE_MR2_JPLL.dcm" }, +{ "43867bf684f5c8eb56e7595c76e02e7a" , "D_CLUNIE_MR2_JPLY.dcm" }, +{ "072779b40d39e704ec4c002226bdfceb" , "D_CLUNIE_MR2_RLE.dcm" }, +{ "60852d347647758175d8f65d2c81e7a6" , "D_CLUNIE_MR3_JPLL.dcm" }, +{ "8e60bb51feba032aa141385f48465ef8" , "D_CLUNIE_MR3_JPLY.dcm" }, +{ "cf1e84527b2a6095037a8c2cfe801335" , "D_CLUNIE_MR3_RLE.dcm" }, +{ "caa51957b182d1048f1077af1c3d99fb" , "D_CLUNIE_MR4_JPLL.dcm" }, +{ "810033c798a3168f051389e0a0a8bcb7" , "D_CLUNIE_MR4_JPLY.dcm" }, +{ "af6b015679b368bb0e066874730a5cb9" , "D_CLUNIE_MR4_RLE.dcm" }, +{ "9a1008f0b45537614523e1fc8dce1b37" , "D_CLUNIE_NM1_JPLL.dcm" }, +{ "dbd2aedf74ca7297ea213d7d19934bba" , "D_CLUNIE_NM1_JPLY.dcm" }, +{ "01b95bc55f4684d0d7f2cb990a4c870f" , "D_CLUNIE_NM1_RLE.dcm" }, +{ "510e107dc1ca40a577af88a20f71a0b4" , "D_CLUNIE_RG1_JPLL.dcm" }, +{ "418bef1f3e70cb02205999bce74fed8e" , "D_CLUNIE_RG1_RLE.dcm" }, +{ "7596cda97de4782951827104f616f7ea" , "D_CLUNIE_RG2_JPLL.dcm" }, +{ "f03d1b8dc233c8c902c9fb4800ec6fe2" , "D_CLUNIE_RG2_JPLY.dcm" }, +{ "2fbc6e918c2d4ad7115addf46d870e78" , "D_CLUNIE_RG2_RLE.dcm" }, +{ "9966b6dbec23248fb2b6da9e7769ba20" , "D_CLUNIE_RG3_JPLL.dcm" }, +{ "d06de3e3b941dce6c2c2c896fe42584b" , "D_CLUNIE_RG3_JPLY.dcm" }, +{ "4ed3c3920c7763b883c234bf8bf95662" , "D_CLUNIE_RG3_RLE.dcm" }, +{ "41dc2884a4f98d484da80c2bdb7e5fcc" , "D_CLUNIE_SC1_JPLY.dcm" }, +{ "ec344a1d113d5070cabebf17c0fa3330" , "D_CLUNIE_SC1_RLE.dcm" }, +{ "14f4e54540008a39b53725800962f703" , "D_CLUNIE_US1_RLE.dcm" }, +{ "44a550cd8bccba4f157dd825489a5e87" , "D_CLUNIE_VL1_RLE.dcm" }, +{ "f4274cbe83a3368d99ee8332421448fe" , "D_CLUNIE_VL2_RLE.dcm" }, +{ "ea3d6a0fe2a65244c285c31eac5066ab" , "D_CLUNIE_VL3_RLE.dcm" }, +{ "6452ff527ac71f780445cf5ff083b0af" , "D_CLUNIE_VL4_RLE.dcm" }, +{ "53be8cfa8cb9709c08732908bb37410a" , "D_CLUNIE_VL6_RLE.dcm" }, +{ "9178b1d061641464ecaf271fc4328948" , "D_CLUNIE_XA1_JPLL.dcm" }, +{ "1f050eec29d9eeed3d406570ea1b9168" , "D_CLUNIE_XA1_JPLY.dcm" }, +{ "99040c48b80d40d6f7d6eed6a3cbc824" , "D_CLUNIE_XA1_RLE.dcm" }, +{ "9cf394a4dde294fc740e7577529ba5ca" , "D_CLUNIE_CT1_JLSL.dcm" }, +{ "b4d14dc9e820e6f1cf17730833a0373a" , "D_CLUNIE_CT1_JLSN.dcm" }, +{ "de20088d529a3bb211933c2d3b7604aa" , "DCMTK_JPEGExt_12Bits.dcm" }, +{ "e959b1f056d40bb4b21d0cbff1f67310" , "DermaColorLossLess.dcm" }, +{ "dee54ccedfed2d4d5562b52a1a7a5cfc" , "DICOMDIR" }, +{ "81ba5ff6f512289c30efdc757c6de231" , "dicomdir_Acusson_WithPrivate_WithSR" }, +{ "7c75c6a8957298bd70bf9b51efd39da1" , "DICOMDIR_MR_B_VA12A" }, +{ "7339affc644067bbd4be9134b597c515" , "DICOMDIR-Philips-EasyVision-4200-Entries" }, +{ "de270e5b601d5f9e235ea651932b546c" , "dicomdir_Pms_With_heavy_embedded_sequence" }, +{ "1ef216d2a08420432172581e0b4b9ffa" , "dicomdir_Pms_WithVisit_WithPrivate_WithStudyComponents" }, +{ "19c0a3e4ba48de7b35f19013bf7ceaa7" , "dicomdir_With_embedded_icons" }, +{ "33e6ad84c695d0d2c8be46ae79cfb5be" , "DMCPACS_ExplicitImplicit_BogusIOP.dcm" }, +{ "e692180e794a05a284edc985728af12b" , "DX_GE_FALCON_SNOWY-VOI.dcm" }, +{ "4838485dda77a0ff1a51463e1742f1c1" , "DX_J2K_0Padding.dcm" }, +{ "16f951766461b7cf1ec318f53c396c3b" , "ELSCINT1_JP2vsJ2K.dcm" }, +{ "e1e3c870656147b186361ab2439379ae" , "ELSCINT1_LOSSLESS_RICE.dcm" }, +{ "c5a985457952a33a10c90139c5812e56" , "ELSCINT1_PMSCT_RLE1.dcm" }, +{ "f2429f2bf3d2d7951a358e94a848977b" , "ExplicitVRforPublicElementsImplicitVRforShadowElements.dcm" }, +{ "b92edb08527b520df5f624f6753fb47a" , "fffc0000UN.dcm" }, +{ "40cff8d72a15be2b91d3c972b5c8a481" , "FUJI-10-MONO1-ACR_NEMA_2.dcm" }, +{ "74fc5c1975c8c8277a2900a803e56260" , "gdcm-ACR-LibIDO.acr" }, +{ "bd4c340a9d225c16f1507dbc9013ff47" , "gdcm-CR-DCMTK-16-NonSamplePerPix.dcm" }, +{ "04528010e8679cd668ee3e89cb9b7058" , "gdcm-JPEG-Extended.dcm" }, +{ "95953bc725582368ac5ddac7eb73e73f" , "gdcm-JPEG-LossLess3a.dcm" }, +{ "f715e4b9f640ff3b3b98b87d10f81c36" , "gdcm-JPEG-LossLessThoravision.dcm" }, +{ "06fc6d07dc486b2cb87077ea74774220" , "gdcm-MR-PHILIPS-16-Multi-Seq.dcm" }, +{ "4b09787d27dbd36a02a0ae7d4d3abe16" , "gdcm-MR-PHILIPS-16-NonSquarePixels.dcm" }, +{ "765d1cae48ebac57f675193734f6477c" , "gdcm-MR-SIEMENS-16-2.acr" }, +{ "20e289bad9be67e22d179174f3bc1694" , "gdcm-US-ALOKA-16.dcm" }, +{ "64e2f50c3e3b9b7400f3f29e144b4a34" , "GE_CT_With_Private_compressed-icon.dcm" }, +{ "012993a90206a659e92f6af305889f0b" , "GE_DLX-8-MONO2-Multiframe.dcm" }, +{ "1bec471d81dcb3a39852c03d261c22cd" , "GE_DLX-8-MONO2-Multiframe-Jpeg_Lossless.dcm" }, +{ "44f09f83983a2b45a6cd42deb1cbcf0a" , "GE_DLX-8-MONO2-PrivateSyntax.dcm" }, +{ "1ef5dca6cda8c21b01ff779e6aa67692" , "GE_GENESIS-16-MONO2-Uncompressed-UnusualVR.dcm" }, +{ "34483fff69d88d647a2edfd8d55210a3" , "GE_GENESIS-16-MONO2-WrongLengthItem.dcm" }, +{ "1a7c56cb02d6e742cc9c856a8ac182e3" , "GE_LOGIQBook-8-RGB-HugePreview.dcm" }, +{ "7285d6a7261889c33626310e1d581ef8" , "GE_MR_0025xx1bProtocolDataBlock.dcm" }, +{ "309d063fbe3bd73dad534e72de032f97" , "GE_RHAPSODE-16-MONO2-JPEG-Fragments.dcm" }, +{ "76d57d019a5af8cd5a7cd2afb1e40f4b" , "IM-0001-0066.dcm" }, +{ "b479bb01798444128d75d90d37cf8546" , "ITK_GDCM124_MultiframeSecondaryCaptureInvalid.dcm" }, +{ "1bb147010022b15e021eabe0eae1a231" , "JDDICOM_Sample2.dcm" }, +{ "cd9afab2d9d31de0029bf4ed1995186c" , "JDDICOM_Sample2-dcmdjpeg.dcm" }, +{ "e4b43fa2fdb4dde13e2a7fd018323241" , "JPEG_LossyYBR.dcm" }, +{ "118dc6986862bf76326ba542813049d2" , "KODAK-12-MONO1-Odd_Terminated_Sequence.dcm" }, +{ "499661b964e8df08860655c8dcc17661" , "KODAK_CompressedIcon.dcm" }, +{ "21de4aa50000b4ed74e4531c2b1d0cc1" , "LEADTOOLS_FLOWERS-16-MONO2-JpegLossless.dcm" }, +{ "042ca0b7551bd96b501fbbdd4275342f" , "LEADTOOLS_FLOWERS-16-MONO2-RLE.dcm" }, +{ "31c7e4c1a2f39871b886c443c6376ba7" , "LEADTOOLS_FLOWERS-16-MONO2-Uncompressed.dcm" }, +{ "9f884f686020c37be9f41a617b9ec8e8" , "LEADTOOLS_FLOWERS-24-RGB-JpegLossless.dcm" }, +{ "bc38dd9c27150dd3d67250830644e609" , "LEADTOOLS_FLOWERS-24-RGB-JpegLossy.dcm" }, +{ "32ad312f99c425b1631e6e05881e3e33" , "LEADTOOLS_FLOWERS-24-RGB-Uncompressed.dcm" }, +{ "82c2343f6f4b55bf6a31f6cc0f9cf83e" , "LEADTOOLS_FLOWERS-8-MONO2-JpegLossy.dcm" }, +{ "f78abbd1df9ef87ba21d805083d6e3b3" , "LEADTOOLS_FLOWERS-8-MONO2-RLE.dcm" }, +{ "afe156b36b3af19b6a889d640296c710" , "LEADTOOLS_FLOWERS-8-MONO2-Uncompressed.dcm" }, +{ "deaf5e62e2132996ebe759a438195f95" , "LEADTOOLS_FLOWERS-8-PAL-RLE.dcm" }, +{ "6b04366e28facddd808b9ea149745309" , "LEADTOOLS_FLOWERS-8-PAL-Uncompressed.dcm" }, +{ "f1b63522a4d6ae89eb6bc728cebc14ff" , "libido1.0-vol.acr" }, +{ "b90b87245eddfcb53b26e61cfaa40fcc" , "LIBIDO-16-ACR_NEMA-Volume.dcm" }, +{ "454accc7d6688c0478461f575461c607" , "LIBIDO-24-ACR_NEMA-Rectangle.dcm" }, +{ "3d8ee51f870495bf22b7a51ba0661f90" , "LIBIDO-8-ACR_NEMA-Lena_128_128.acr" }, +{ "9c8b67c4205880f78347b751268af0fa" , "LJPEG_BuginGDCM12.dcm" }, +{ "335428b3dde0d390dbd8bb49f32c673c" , "MARCONI_MxTWin-12-MONO2-JpegLossless-ZeroLengthSQ.dcm" }, +{ "abd7b36703f82e3b491e4b3b95cc1c43" , "MAROTECH_CT_JP2Lossy.dcm" }, +{ "63f178c91a573f13e28aabe8b7eaf1bd" , "MR-Brucker-CineTagging-NonSquarePixels.dcm" }, +{ "746a17465b70119264762ead8f1a6763" , "MR_ELSCINT1_00e1_1042_SQ_feff_00e0_Item.dcm" }, +{ "c87dd2eac7b55cb3eade01eaa373b4e3" , "MR_GE_with_Private_Compressed_Icon_0009_1110.dcm" }, +{ "ca8cd1b0a7c64139919deba04dbddfc9" , "MR-MONO2-12-an2.acr" }, +{ "cb32c2e0c3f9c52939440d39f9fe7b4f" , "MR-MONO2-12-angio-an1.acr" }, +{ "fb0565a0a591ed83106e90d5b76e0cfe" , "MR-MONO2-12-shoulder.dcm" }, +{ "97d9f3dcc35e54478522ead748e24956" , "MR-MONO2-16-head.dcm" }, +{ "fc72513cfea2caf6035dd8910c53bb9a" , "MR-MONO2-8-16x-heart.dcm" }, +{ "1a2e4f0aa20448fdd7783ff938bf99e6" , "MR_Philips-Intera_BreaksNOSHADOW.dcm" }, +{ "aa07de9c01765602fe722e9ef2d8b92a" , "MR_Philips_Intera_No_PrivateSequenceImplicitVR.dcm" }, +{ "a8091f92ae895c2ef70143487e29b7d3" , "MR_Philips_Intera_PrivateSequenceExplicitVR_in_SQ_2001_e05f_item_wrong_lgt_use_NOSHADOWSEQ.dcm" }, +{ "5d893aee8147f12b975cde73abdb5d84" , "MR_Philips_Intera_PrivateSequenceImplicitVR.dcm" }, +{ "3bbffc4c87f4f5554fafad5f8a002552" , "MR_Philips_Intera_SwitchIndianess_noLgtSQItem_in_trueLgtSeq.dcm" }, +{ "32f899e8f1506bc3fa155da22e9c8813" , "MR-SIEMENS-DICOM-WithOverlays.dcm" }, +{ "db7370f6d18ce7a9c8ab05179eb82cc6" , "MR-SIEMENS-DICOM-WithOverlays-extracted-overlays.dcm" }, +{ "15ef679db745d4a3a59cab0456a82ace" , "MR_SIEMENS_forceLoad29-1010_29-1020.dcm" }, +{ "be2ce86e93fe5a0cc33c2351b6a4ac66" , "MR_Spectroscopy_SIEMENS_OF.dcm" }, +{ "473dd7ad8ec7c50dbd20470b525eb859" , "NM-MONO2-16-13x-heart.dcm" }, +{ "cc1dd93cd2e2fc19815b015663ea8e66" , "OT-MONO2-8-a7.dcm" }, +{ "61dfde4beae2ecd7fd4acc9cab412daa" , "OT-PAL-8-face.dcm" }, +{ "d97af0d265cee784f3fd6391f17cf8fd" , "PET-cardio-Multiframe-Papyrus.dcm" }, +{ "826226301791aaa2e1dfacb9f56775ae" , "PHILIPS_Brilliance_ExtraBytesInOverlay.dcm" }, +{ "fe35f6ff5e85392143c7216a9e4bc92d" , "PHILIPS_Gyroscan-12-Jpeg_Extended_Process_2_4.dcm" }, +{ "d6ea0b68da84829a1b4cbd07d7cf6ef5" , "PHILIPS_Gyroscan-12-MONO2-Jpeg_Lossless.dcm" }, +{ "cc8bbb35c017acd32ba29d20df12ac8b" , "PHILIPS_Gyroscan-8-MONO2-Odd_Sequence.dcm" }, +{ "f80468faedc918845fc31accc247125f" , "PHILIPS_Intera-16-MONO2-Uncompress.dcm" }, +{ "43469b245a5fbbea69db6ed9507a86e4" , "PICKER-16-MONO2-Nested_icon.dcm" }, +{ "2cd10ed50b409549a6a25c4feaa5a989" , "PICKER-16-MONO2-No_DicomV3_Preamble.dcm" }, +{ "9d4f1c087ababf655297bf2129c01911" , "PrivateGEImplicitVRBigEndianTransferSyntax16Bits.dcm" }, +{ "8e902a2371c37b9e6f636c3c53ef1f5c" , "RadBWLossLess.dcm" }, +{ "a0e664672011dab175f593bf61026ffc" , "rle16loo.dcm" }, +{ "f35d850d15021800175c585f856a8f54" , "rle16sti.dcm" }, +{ "148b28cb580e6f56d9adce46a985c692" , "SIEMENS-12-Jpeg_Process_2_4-Lossy-a.dcm" }, +{ "90336859a2e275900931d54c41fe033a" , "SIEMENS_CSA2.dcm" }, +{ "4b1498f0edd79cc0f5273f22a4e03615" , "SIEMENS_GBS_III-16-ACR_NEMA_1.acr" }, +{ "c54eb37190f783c79504554990761efd" , "SIEMENS_GBS_III-16-ACR_NEMA_1-ULis2Bytes.dcm" }, +{ "bf49f9fdab81e97482b8fe6f579bc3f7" , "SIEMENS_ImageLocationUN.dcm" }, +{ "765d1cae48ebac57f675193734f6477c" , "SIEMENS_MAGNETOM-12-ACR_NEMA_2-Modern.dcm" }, +{ "6884e1143f2edf6188643e896e796463" , "SIEMENS_MAGNETOM-12-MONO2-FileSeq0.dcm" }, +{ "340b9006e47d48bd6d5abe5af628026b" , "SIEMENS_MAGNETOM-12-MONO2-FileSeq1.dcm" }, +{ "59cc16618e978026cff79e61e17174ec" , "SIEMENS_MAGNETOM-12-MONO2-FileSeq2.dcm" }, +{ "fde3a66d449ae3788b4c431fde7a7a50" , "SIEMENS_MAGNETOM-12-MONO2-FileSeq3.dcm" }, +{ "6facfeecd3c531b3a536064aa046fa9e" , "SIEMENS_MAGNETOM-12-MONO2-GDCM12-VRUN.dcm" }, +{ "ba687ec0b2e49f5eedd3e22573ba2094" , "SIEMENS_MAGNETOM-12-MONO2-Uncompressed.dcm" }, +{ "7e00f1e50bd0bedc5db64dff0dea3848" , "SIEMENS_MAGNETOM-12-MONO2-VRUN.dcm" }, +{ "c80b1be0d50619955e54d81bca451a05" , "SIEMENS_MOSAIC_12BitsStored-16BitsJPEG.dcm" }, +{ "544a1fde6df0817ef03ad56f7ff539a8" , "SIEMENS-MR-RGB-16Bits.dcm" }, +{ "33f4765c31a5d2f61f4e3fa4571e2f88" , "SIEMENS_SOMATOM-12-ACR_NEMA-ZeroLengthUs.acr" }, +{ "08443d1e07d98554a695c482ecba2014" , "SIEMENS_Sonata-12-MONO2-SQ.dcm" }, +{ "f49aeced38187d9d8502cf79fb690e0d" , "SIEMENS_Sonata-16-MONO2-Value_Multiplicity.dcm" }, +{ "fd22f759b7dd4b8cccd64f5f5096887b" , "SignedShortLosslessBug.dcm" }, +{ "c8c3e1d395aa50795ca831e12051d9d0" , "simpleImageWithIcon.dcm" }, +{ "c634e9e559b61ea65d222a1d5c5a9d5e" , "test.acr" }, +{ "fc733f08120936e25cb11af6df6f65bf" , "TG18-CH-2k-01.dcm" }, +{ "47a35db3d33ab798e7b41449e22d1120" , "THERALYS-12-MONO2-Uncompressed-Even_Length_Tag.dcm" }, +{ "d85505c6a7be835b482175fbed85ce98" , "TheralysGDCM120Bug.dcm" }, +{ "db53b838d4ed4aca22999d6c70558305" , "TOSHIBA_MRT150-16-MONO2-ACR_NEMA_2.dcm" }, +{ "b3bc682102873b761491839df5686adf" , "undefined_length_un_vr.dcm" }, +{ "98473e5af6a5694ae08d63780bcea96c" , "US-GE-4AICL142.dcm" }, +{ "1b12a27ca6075d55000d1d170949b789" , "US-IRAD-NoPreambleStartWith0003.dcm" }, +{ "44f97431146a33e320ae08fb7dc09a59" , "US-IRAD-NoPreambleStartWith0005.dcm" }, +{ "1006e4c95b63539608adf62060d7fc46" , "US-MONO2-8-8x-execho.dcm" }, +{ "83574afcb319337222472db44f91cbd8" , "US-PAL-8-10x-echo.dcm" }, +{ "0b3ae440e8dbb144205074a664228c1e" , "US-RGB-8-epicard.dcm" }, +{ "0ae1d92cc14706add796368622deaa26" , "US-RGB-8-esopecho.dcm" }, +{ "d23db052b02b2a2c510104486cdf40b2" , "XA-MONO2-8-12x-catheter.dcm" }, +{ "231bb6c25d482422745bb839d6f8610a" , "PHILIPS_GDCM12xBug2.dcm" }, +{ "e2558e4e01d937bfac33b7e0fb07b7b5" , "PHILIPS_GDCM12xBug.dcm" }, +{ "434c7aa1172ce3af0c306d9a2cb28c17" , "AMIInvalidPrivateDefinedLengthSQasUN.dcm" }, +{ "346ba438ade47d75c41e637858a419f8" , "OsirixFake16BitsStoredFakeSpacing.dcm" }, +{ "efe1ff2da3fc0bfcc5df834fa390d5cf" , "MR16BitsAllocated_8BitsStored.dcm" }, +{ "7900d059078278ad0387f7c4aaf2027d" , "JPEGDefinedLengthSequenceOfFragments.dcm" }, +{ "dacb240b2fc701416d80193ad18baad5" , "IM-0001-0066.CommandTag00.dcm" }, +{ "7f2f84d3adef913bb5531f583eceb004" , "UnexpectedSequenceDelimiterInFixedLengthSequence.dcm" }, +{ "f4bf27280aad0ff38d1fe3871a0a8afb" , "GDCMJ2K_TextGBR.dcm" }, +{ "f445a6dc674e2c12c14bf3583c6c3e6f" , "NM_Kakadu44_SOTmarkerincons.dcm" }, +{ "7c0c4eb0c73b4dc5b3a4d961653fc4e2" , "PhilipsInteraSeqTermInvLen.dcm" }, +{ "64528209839b0369c2da530249f4ca58" , "TOSHIBA_J2K_SIZ1_PixRep0.dcm" }, +{ "2498ca4aaf62991c8a1f629a804bfa44" , "TOSHIBA_J2K_OpenJPEGv2Regression.dcm" }, +{ "e4d559b6db04679b54bea40c763b09e4" , "TOSHIBA_J2K_SIZ0_PixRep1.dcm" }, +{ "58ab110be40303952e05d50e64823192" , "NM-PAL-16-PixRep1.dcm" }, +{ "deb7e4ee592efca5d475aaa6fab06459" , "MEDILABInvalidCP246_EVRLESQasUN.dcm" }, +{ "52f727de4f831ff2bae850fdd8b1413a" , "JPEGInvalidSecondFrag.dcm" }, + +{ NULL, NULL} +}; + +int TestMD5Func(const char* filename, const char *md5ref, bool verbose = false) +{ + if( !filename || !md5ref) return 1; + + if( verbose ) + std::cout << "TestRead: " << filename << std::endl; + const char *dataroot = gdcm::Testing::GetDataRoot(); + std::string path = dataroot; + path += "/"; + path += filename; + path = filename; + char md5[2*16+1] = {}; + bool b = gdcm::MD5::ComputeFile( path.c_str(), md5); + if( !b ) + { + std::cerr << "Fail ComputeFile: " << path << std::endl; + return 1; + } + if( strcmp( md5, md5ref) != 0 ) + { + std::cout << "Problem with: " << path << std::endl; + std::cout << "Ref: " << md5ref << " vs " << md5 << std::endl; + // Let's remove this buggy file: + //std::cout << "Removing: " << path << std::endl; + //gdcm::System::RemoveFile(path.c_str()); + return 1; + } + return 0; +} + +static const char *GetMD5Sum(const char *filename) +{ + typedef const char * const (*md5pair)[2]; + const char *md5filename; + md5pair md5filenames = gdcmMD5SumFiles; + int i = 0; + while( ( md5filename = md5filenames[i][1] ) ) + { + gdcm::Filename fn( filename ); + if( strcmp( md5filename, fn.GetName() ) == 0 ) + { + return md5filenames[i][0]; + } + ++i; + } + std::cerr << "Missing Md5 for: " << filename << std::endl; + return 0; +} + +int TestMD5(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + const char *md5 = GetMD5Sum( filename ); + return TestMD5Func(filename, md5, true); + } + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + const char *md5 = GetMD5Sum( filename ); + r += TestMD5Func( filename, md5 ); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/Common/Cxx/TestObject.cxx b/gdcm/Testing/Source/Common/Cxx/TestObject.cxx new file mode 100644 index 0000000..a305068 --- /dev/null +++ b/gdcm/Testing/Source/Common/Cxx/TestObject.cxx @@ -0,0 +1,22 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmObject.h" + +int TestObject(int, char *[]) +{ + gdcm::Object o; + (void)o; + + return 0; +} diff --git a/gdcm/Testing/Source/Common/Cxx/TestSHA1.cxx b/gdcm/Testing/Source/Common/Cxx/TestSHA1.cxx new file mode 100644 index 0000000..8e757ea --- /dev/null +++ b/gdcm/Testing/Source/Common/Cxx/TestSHA1.cxx @@ -0,0 +1,302 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmSHA1.h" +#include "gdcmFilename.h" +#include "gdcmTrace.h" +#include "gdcmTesting.h" + +#include +#include // strcmp + +static const char * const gdcmSHA1SumFiles[][2] = { +{ "265465a2e3b204ab9a094f2de56bbec96d55ab74" , "00191113.dcm" }, +{ "ab316e51539a56053e216017c8445a246a978590" , "012345.002.050.dcm" }, +{ "750ff7a9df7a12c13f7149c514664db7c68c3125" , "05115014-mr-siemens-avanto-syngo-with-palette-icone.dcm" }, +{ "4efeffa6a7b535df85dda198a26e074866b0ed88" , "05148044-mr-siemens-avanto-syngo.dcm" }, +{ "9d1e3fdf69f8d5b46105e4c259b3d84e7f281a45" , "3E768EB7.dcm" }, +{ "f08ff36b45cd50d4349f4c6c17a75b3f653bb11e" , "ACUSON-24-YBR_FULL-RLE-b.dcm" }, +{ "dac2ffa6ccf59f2d91e78f632e45b08d1537715c" , "ACUSON-24-YBR_FULL-RLE.dcm" }, +{ "cf749c5323866c343255805cf781ae87e6bb598a" , "ALOKA_SSD-8-MONO2-RLE-SQ.dcm" }, +{ "7202bfac6d4196aeb2655e879bc91e4dcf40a463" , "BugGDCM2_UndefItemWrongVL.dcm" }, +{ "1d227106140c2a24dbe8c6becd4649761dd117a2" , "CR-MONO1-10-chest.dcm" }, +{ "74e7de8b0f5903b8571294e2d8f960dc7329a0ca" , "CT_16b_signed-UsedBits13.dcm" }, +{ "c0e08333984692bcef149c946e23bb46e01b9b7c" , "CT-MONO2-12-lomb-an2.acr" }, +{ "594ce3215ca94f640fd7502d614651cc755a9d7e" , "CT-MONO2-16-ankle.dcm" }, +{ "ce0bd0c9635db3f04b4996648c1d41e10daffa77" , "CT-MONO2-16-brain.dcm" }, +{ "f9ad8311fa69835c55314e740ca55ab71e038c17" , "CT-MONO2-16-chest.dcm" }, +{ "507fdef01d9357dfb99981ae6c18ab88931271b5" , "CT-MONO2-16-ort.dcm" }, +{ "ad5c2b6d0816761d5f5dc1fcc83e44f3eea4666d" , "CT-MONO2-8-abdo.dcm" }, +{ "76e6ae295b326a46d37f1ad5056ee18b6ee3d6f2" , "CT-SIEMENS-Icone-With-PaletteColor.dcm" }, +{ "7bce2465ca918a5d2a9b8f9c6a9cce1b6b94b44b" , "CT-SIEMENS-MissingPixelDataInIconSQ.dcm" }, +{ "1b75f84318351449b5d841d094297d7975e8ac5b" , "D_CLUNIE_CT1_J2KI.dcm" }, +{ "1d40f08bf78a29e0729742ff5f5731477ab5a9ff" , "D_CLUNIE_CT1_J2KR.dcm" }, +{ "6f6027b38ec184af8cdf31077cd669bd35270ccb" , "D_CLUNIE_CT1_JPLL.dcm" }, +{ "3df887253b24f3296f078fc618e6a682cae4c1d6" , "D_CLUNIE_CT1_RLE.dcm" }, +{ "5336a791f09fe080688b5c1fad04691b39588978" , "D_CLUNIE_CT2_JPLL.dcm" }, +{ "37beaf412c74e435cfdf351cc95f02b62820e3ea" , "D_CLUNIE_CT2_RLE.dcm" }, +{ "fa118c4661e14878a9113032b6549dc7666b773b" , "D_CLUNIE_MR1_JPLL.dcm" }, +{ "f464c45fceb6f5dc234150064c1b7999cd0db2ff" , "D_CLUNIE_MR1_JPLY.dcm" }, +{ "4f6a484fd77238f8bc245fbfadc449cb3ec40a75" , "D_CLUNIE_MR1_RLE.dcm" }, +{ "111bed6926dbf4ad3f61bd9c95e36095475265a1" , "D_CLUNIE_MR2_JPLL.dcm" }, +{ "eec3ed081ec196e036d2cac9e0043bef1038665e" , "D_CLUNIE_MR2_JPLY.dcm" }, +{ "c2ab10273241fe18401f4584a42c76c5257219f0" , "D_CLUNIE_MR2_RLE.dcm" }, +{ "fb04e8143117a8ecdd9cece68c08d4ee3b3ed040" , "D_CLUNIE_MR3_JPLL.dcm" }, +{ "ef2d3fe28424e42963ca52f097b3d1309c95f43d" , "D_CLUNIE_MR3_JPLY.dcm" }, +{ "08dd62d2f452e145dea7905b64e43836504c8a2e" , "D_CLUNIE_MR3_RLE.dcm" }, +{ "e2fa66c4074e9f75b582eb6cf5261a6ac064c5cb" , "D_CLUNIE_MR4_JPLL.dcm" }, +{ "7426ae6aa6cb2f13138878a68183d69ed8d42b1e" , "D_CLUNIE_MR4_JPLY.dcm" }, +{ "2cf735f7ced248c20d4bd8af760523e8b1c88c44" , "D_CLUNIE_MR4_RLE.dcm" }, +{ "f0632988a652cf186a2c1199bb19389534617952" , "D_CLUNIE_NM1_JPLL.dcm" }, +{ "8e4a062c60bda83a7a118b505f9da29454eb77e1" , "D_CLUNIE_NM1_JPLY.dcm" }, +{ "0933067b799d0b4407e190e0b3a58f0e97c92371" , "D_CLUNIE_NM1_RLE.dcm" }, +{ "c72d14184a995b367682f42c3e3b62de7a5b4c7e" , "D_CLUNIE_RG1_JPLL.dcm" }, +{ "b71f33df55502266ca2f4966cd5fc88b2b766385" , "D_CLUNIE_RG1_RLE.dcm" }, +{ "8c337359cca8d2bf1002209589ff19699e530908" , "D_CLUNIE_RG2_JPLL.dcm" }, +{ "c6188f2ae06a55d596d4d6b4d914b404f7bf5786" , "D_CLUNIE_RG2_JPLY.dcm" }, +{ "5035a6298cf8590932605cb4bb10f128df971fcb" , "D_CLUNIE_RG2_RLE.dcm" }, +{ "d2a56de2e035095c3dea9be80878f9607c63728d" , "D_CLUNIE_RG3_JPLL.dcm" }, +{ "41abc80638b12a2601e7764805a9c4ddc385bdc5" , "D_CLUNIE_RG3_JPLY.dcm" }, +{ "eb417a88c6b3fe6c5768ab705990fc0d54558816" , "D_CLUNIE_RG3_RLE.dcm" }, +{ "8e27c853a156038e1f6daebb04f2c9059ebfbd82" , "D_CLUNIE_SC1_JPLY.dcm" }, +{ "6a6ca811ae87ae1ca4549f49724b58562eea714b" , "D_CLUNIE_SC1_RLE.dcm" }, +{ "94737b44e512c8b84e1fb880e04b0ae6f069bd96" , "D_CLUNIE_US1_RLE.dcm" }, +{ "6cc2ad34df402a9aa5c6a2c5436ff0e775a59768" , "D_CLUNIE_VL1_RLE.dcm" }, +{ "4432f4bba584c5bf93264050a0aef0237c8cc9a5" , "D_CLUNIE_VL2_RLE.dcm" }, +{ "c11e1487e94b332f32c041d7e8889d1fe91c2db6" , "D_CLUNIE_VL3_RLE.dcm" }, +{ "345bde73f67171cc6f90cd890d67108aa6039656" , "D_CLUNIE_VL4_RLE.dcm" }, +{ "e52694c1e9be0f4d1c44eab3ac44aa4225b593b0" , "D_CLUNIE_VL6_RLE.dcm" }, +{ "37bf802b1918f36fcf7c6fb89b40ee1da1124419" , "D_CLUNIE_XA1_JPLL.dcm" }, +{ "ff7b9c99731732b55bcff577037542689efe9c72" , "D_CLUNIE_XA1_JPLY.dcm" }, +{ "f384b5f1ae912d97e7784558d5519dc74b853f10" , "D_CLUNIE_XA1_RLE.dcm" }, +{ "cc3641d1f25549a0ee06d2a5e87081cf6c407bf0" , "D_CLUNIE_CT1_JLSL.dcm" }, +{ "ac9f4592e6cfad438de5c928b9e01591006683d8" , "D_CLUNIE_CT1_JLSN.dcm" }, +{ "cc72ee9f3e671321e231103eb562063078b67bf8" , "DCMTK_JPEGExt_12Bits.dcm" }, +{ "fb9da9ae84e5da97c992398ac0222fffafa028f6" , "DermaColorLossLess.dcm" }, +{ "6f53ebd046c0c39ad04b7aa3767ced2647b02c83" , "DICOMDIR" }, +{ "436f0de1319089bc203b699a6e64687a9b27fd8c" , "dicomdir_Acusson_WithPrivate_WithSR" }, +{ "3c73737e44852b9f30cc4fe4e8cc600cdf63ee0a" , "DICOMDIR_MR_B_VA12A" }, +{ "86687243468f6e8243081adbff3374c8fbeb1166" , "DICOMDIR-Philips-EasyVision-4200-Entries" }, +{ "623523dedebccddb38ab6fbb76e01c1458bd0d98" , "dicomdir_Pms_With_heavy_embedded_sequence" }, +{ "0c0c0b72d980a6675897fc50854c98176582e7d5" , "dicomdir_Pms_WithVisit_WithPrivate_WithStudyComponents" }, +{ "9a90f8c949d99f9e9e7523f442b8995bb2b2ae3d" , "dicomdir_With_embedded_icons" }, +{ "eb0b632f7feccde2b7d88d6a82f51857ef5de521" , "DMCPACS_ExplicitImplicit_BogusIOP.dcm" }, +{ "abb8fb269447e046fe10306e4e5f54fe988a0069" , "DX_GE_FALCON_SNOWY-VOI.dcm" }, +{ "861ff0760754f6ebb0056f52adcdcd60f0cd3bfa" , "DX_J2K_0Padding.dcm" }, +{ "8275a7e217807273fb0027a64f46cba8656f699a" , "ELSCINT1_JP2vsJ2K.dcm" }, +{ "399e80d60843e62b817322ba9e82278258f9a222" , "ELSCINT1_LOSSLESS_RICE.dcm" }, +{ "3598e59bf8ff6cb5217473f9f23ad763638a27e0" , "ELSCINT1_PMSCT_RLE1.dcm" }, +{ "3514c92127b0c78b63efce1fb6053e202da86d3f" , "ExplicitVRforPublicElementsImplicitVRforShadowElements.dcm" }, +{ "cc80ee94edf9b3d7fd4c1402b2c6ae99eb832685" , "fffc0000UN.dcm" }, +{ "374bf25ac4279a7458d848b595b23ed50580400b" , "FUJI-10-MONO1-ACR_NEMA_2.dcm" }, +{ "ada05095c6d64767af77eafeb2e6fc305f2ba2c8" , "gdcm-ACR-LibIDO.acr" }, +{ "f2d333278c7ebb985916011ecb808342205b9815" , "gdcm-CR-DCMTK-16-NonSamplePerPix.dcm" }, +{ "09f0d023545047704beb2fa8168bd7fadca845e2" , "gdcm-JPEG-Extended.dcm" }, +{ "70da750cb898c6510ba079a1e71b4869faf66dd7" , "gdcm-JPEG-LossLess3a.dcm" }, +{ "736c14572e7ee964d24b2b5c5b2a607ca50ebc05" , "gdcm-JPEG-LossLessThoravision.dcm" }, +{ "765541a6e32671891fc0787e69c4917c7166a77a" , "gdcm-MR-PHILIPS-16-Multi-Seq.dcm" }, +{ "b7d171ebfcb288ec44647f3000515f3683dfef50" , "gdcm-MR-PHILIPS-16-NonSquarePixels.dcm" }, +{ "6f1e68d6a8586862c31ac7d7a2d2c8d317865263" , "gdcm-MR-SIEMENS-16-2.acr" }, +{ "a525344659d1767787c6929bb2b080286106e881" , "gdcm-US-ALOKA-16.dcm" }, +{ "5b8c8d45b6c06f5d2fb90df6205606accfedfc6c" , "GE_CT_With_Private_compressed-icon.dcm" }, +{ "58c81390cbb3a033c0f1fe15760bd14d87ca8313" , "GE_DLX-8-MONO2-Multiframe.dcm" }, +{ "53b514276db021a5a8e26cddd3f09c43dad49747" , "GE_DLX-8-MONO2-Multiframe-Jpeg_Lossless.dcm" }, +{ "86ae2ce4b9676110db10ebc6aaba1d49bfa26537" , "GE_DLX-8-MONO2-PrivateSyntax.dcm" }, +{ "34a42605c83313dbd6d0af4670c2dfabaf270319" , "GE_GENESIS-16-MONO2-Uncompressed-UnusualVR.dcm" }, +{ "a3f130a256fea9804cc2b9e05dedb4b3af517421" , "GE_GENESIS-16-MONO2-WrongLengthItem.dcm" }, +{ "da85472c37599dc02c83f2e4c24e3fd5a2617f92" , "GE_LOGIQBook-8-RGB-HugePreview.dcm" }, +{ "a47f7d0d1d40c213666ccc67d3ce83464a5fa9b8" , "GE_MR_0025xx1bProtocolDataBlock.dcm" }, +{ "36bcff2d268dbf8e92b296a9cd0894f5b4dcb5ed" , "GE_RHAPSODE-16-MONO2-JPEG-Fragments.dcm" }, +{ "f84803d8879bc0a461f03c39ec896704796d8376" , "IM-0001-0066.dcm" }, +{ "fb563954a0b3e8f521248cfac294233e85c517c9" , "ITK_GDCM124_MultiframeSecondaryCaptureInvalid.dcm" }, +{ "5a21779c6db335b0f6a989c292b66e2d1939aaae" , "JDDICOM_Sample2.dcm" }, +{ "9f2559b3e74c09e04c1ccca0424f6bbb3480fe9e" , "JDDICOM_Sample2-dcmdjpeg.dcm" }, +{ "9af362dd8ba13c358b869ebaf9c70dd2c34a9b49" , "JPEG_LossyYBR.dcm" }, +{ "e99bd082c18b4f0a150737d5f1a18e00c6bb73d8" , "KODAK-12-MONO1-Odd_Terminated_Sequence.dcm" }, +{ "12fc320b12b35822da90155a2b92586f8ff4adf0" , "KODAK_CompressedIcon.dcm" }, +{ "3e554827c2110cd94ab29f65ea4bb8155ae11be8" , "LEADTOOLS_FLOWERS-16-MONO2-JpegLossless.dcm" }, +{ "1b8c958f48da2aaa1bbc085aec4410f5c2545875" , "LEADTOOLS_FLOWERS-16-MONO2-RLE.dcm" }, +{ "7be91a03cca70febe383fd4df821f5475cc02c8d" , "LEADTOOLS_FLOWERS-16-MONO2-Uncompressed.dcm" }, +{ "f6046930f93017ac0586f389d2f69cc47d139615" , "LEADTOOLS_FLOWERS-24-RGB-JpegLossless.dcm" }, +{ "7de6449beccbeda52d95b027d24448abad1194bc" , "LEADTOOLS_FLOWERS-24-RGB-JpegLossy.dcm" }, +{ "6a8f88021d04488bf1d8f5160b49bc9245a5da2c" , "LEADTOOLS_FLOWERS-24-RGB-Uncompressed.dcm" }, +{ "d5b043ad7c367c4ac5156c8137125d481201f8b6" , "LEADTOOLS_FLOWERS-8-MONO2-JpegLossy.dcm" }, +{ "3f3d48adcbbe43cd88ec4dd38c0eabac1518cbb1" , "LEADTOOLS_FLOWERS-8-MONO2-RLE.dcm" }, +{ "a6e1d158e76362545a32d90adfdbc06d0a795aa8" , "LEADTOOLS_FLOWERS-8-MONO2-Uncompressed.dcm" }, +{ "53e1a8442e52b8e7fb0024f38a3ba47cd1557af4" , "LEADTOOLS_FLOWERS-8-PAL-RLE.dcm" }, +{ "f1cf42d9fbd847f7bebaa2b2e05ad669401bceeb" , "LEADTOOLS_FLOWERS-8-PAL-Uncompressed.dcm" }, +{ "5c768b7fa2940546d9f3c49e76d8734ebae41b9b" , "libido1.0-vol.acr" }, +{ "fe7170c9acf67f99977f12ab41429e082bca4440" , "LIBIDO-16-ACR_NEMA-Volume.dcm" }, +{ "4d3d23112591bcbbf130e2d83768c59af69c6740" , "LIBIDO-24-ACR_NEMA-Rectangle.dcm" }, +{ "971bf05ef2a29cdddfb28279b73444fd5dedb046" , "LIBIDO-8-ACR_NEMA-Lena_128_128.acr" }, +{ "f6cf7fb8470a33f82beef9dcf55b7379464db068" , "LJPEG_BuginGDCM12.dcm" }, +{ "483032c54da529824e6d1f587dba9a9c5c6f4888" , "MARCONI_MxTWin-12-MONO2-JpegLossless-ZeroLengthSQ.dcm" }, +{ "9033fd528b9008273cbb277f0adb21abe8a1d35a" , "MAROTECH_CT_JP2Lossy.dcm" }, +{ "88534f6f5c247a198b860108c4d3a5b5f7fb7048" , "MR-Brucker-CineTagging-NonSquarePixels.dcm" }, +{ "73817e417b440a961dfcc273eeae6007fc004f61" , "MR_ELSCINT1_00e1_1042_SQ_feff_00e0_Item.dcm" }, +{ "2f210cc06d8e05b762b8fd996ac730f2442b258a" , "MR_GE_with_Private_Compressed_Icon_0009_1110.dcm" }, +{ "73eae004f6305c3ef10f710dd51ef750b7ced8ab" , "MR-MONO2-12-an2.acr" }, +{ "80cb279b9cfe4cd5f8209dc1fd81a0de789fb561" , "MR-MONO2-12-angio-an1.acr" }, +{ "30a35164282f20ffc38eeb4d0a94b74159f72a38" , "MR-MONO2-12-shoulder.dcm" }, +{ "c6376ebdfda8ca05bb3d2f2796b2f4ce4cf5417a" , "MR-MONO2-16-head.dcm" }, +{ "e4b6f0ea147335d048ef1cf271f1f8ea9b3a947a" , "MR-MONO2-8-16x-heart.dcm" }, +{ "482282eab5270a9b49da1fe52955029c90665318" , "MR_Philips-Intera_BreaksNOSHADOW.dcm" }, +{ "0edaefb39107ede69cbfef9fa5d646734859560a" , "MR_Philips_Intera_No_PrivateSequenceImplicitVR.dcm" }, +{ "002496c378b8d74cde8034c8e64ac06278aaac64" , "MR_Philips_Intera_PrivateSequenceExplicitVR_in_SQ_2001_e05f_item_wrong_lgt_use_NOSHADOWSEQ.dcm" }, +{ "7b32e317ab15df08cbc22e5c71c19be0236c4a71" , "MR_Philips_Intera_PrivateSequenceImplicitVR.dcm" }, +{ "d201a0399638b90dab2d147e8505b12dc3f22abf" , "MR_Philips_Intera_SwitchIndianess_noLgtSQItem_in_trueLgtSeq.dcm" }, +{ "f86689b7eacfa0c477168f6d95e5f554ba9db2f6" , "MR-SIEMENS-DICOM-WithOverlays.dcm" }, +{ "4ca412d03202693ea4dbe5189681afb25341e7d7" , "MR-SIEMENS-DICOM-WithOverlays-extracted-overlays.dcm" }, +{ "ddc7ed9fc533413dec8795c35c0dc45485a64422" , "MR_SIEMENS_forceLoad29-1010_29-1020.dcm" }, +{ "af658128f2acfb72b95892435a34d983194adb85" , "MR_Spectroscopy_SIEMENS_OF.dcm" }, +{ "a28aa38246dbce06692f5a977ca320cf26bb9260" , "NM-MONO2-16-13x-heart.dcm" }, +{ "5ca8093b12ff8c78875af95091a96965a94acb19" , "OT-MONO2-8-a7.dcm" }, +{ "9bf3ca1db0420baede3c257e9c102fe5d27a0554" , "OT-PAL-8-face.dcm" }, +{ "38a8505e4a5f4119c76636e6eaf754edff1e8122" , "PET-cardio-Multiframe-Papyrus.dcm" }, +{ "a011aaddce1295f42d9d8fbd14b1558ed04b0b6c" , "PHILIPS_Brilliance_ExtraBytesInOverlay.dcm" }, +{ "cd88e741f78d2267a7c8a83a0fb4b009fce706f8" , "PHILIPS_Gyroscan-12-Jpeg_Extended_Process_2_4.dcm" }, +{ "05fe55371a99bd6e233b4605eef8b47d5d21f243" , "PHILIPS_Gyroscan-12-MONO2-Jpeg_Lossless.dcm" }, +{ "09a07901bb4b6ca120648c3fa478a4172811b4db" , "PHILIPS_Gyroscan-8-MONO2-Odd_Sequence.dcm" }, +{ "d4a5ce137aac5d979a68b5a62593cf99096a485d" , "PHILIPS_Intera-16-MONO2-Uncompress.dcm" }, +{ "f64181bf0abfacf2853ce3eeb60149f2c3cf7507" , "PICKER-16-MONO2-Nested_icon.dcm" }, +{ "aef5bc2a2132e2c11a4f8fc5e1dd7655300d0c1f" , "PICKER-16-MONO2-No_DicomV3_Preamble.dcm" }, +{ "0fc0e0168128517472e3a4a69808331aaffe4bb5" , "PrivateGEImplicitVRBigEndianTransferSyntax16Bits.dcm" }, +{ "38e925d7c30ef5b0cf829ea520e271482ea89c7d" , "RadBWLossLess.dcm" }, +{ "7a57d75599fd8521210835f6506dd77204f16883" , "rle16loo.dcm" }, +{ "77d3e4e78f0452f4ebb0855fa367e19044014244" , "rle16sti.dcm" }, +{ "3d9e8bf00e3509fc7210a8a67c3d15622c03b15e" , "SIEMENS-12-Jpeg_Process_2_4-Lossy-a.dcm" }, +{ "292433a76c4ef0a8341c76b23d030950fbe7865a" , "SIEMENS_CSA2.dcm" }, +{ "b67eecea6c2099fa0bb0d558ad2fb281e0c14811" , "SIEMENS_GBS_III-16-ACR_NEMA_1.acr" }, +{ "89c6d755e1f183b18c3711ccce0bdb243d11f05c" , "SIEMENS_GBS_III-16-ACR_NEMA_1-ULis2Bytes.dcm" }, +{ "521b21eb0b5ec9ebb77de6d7730971a3d5ce5542" , "SIEMENS_ImageLocationUN.dcm" }, +{ "6f1e68d6a8586862c31ac7d7a2d2c8d317865263" , "SIEMENS_MAGNETOM-12-ACR_NEMA_2-Modern.dcm" }, +{ "32da5e531a2df100b4a6bc5334c0128a7603c62f" , "SIEMENS_MAGNETOM-12-MONO2-FileSeq0.dcm" }, +{ "f7cf7f2d62113863f76580bac6a0465638ebd050" , "SIEMENS_MAGNETOM-12-MONO2-FileSeq1.dcm" }, +{ "8708d74b623b3317631a982b9c316c8521c1b220" , "SIEMENS_MAGNETOM-12-MONO2-FileSeq2.dcm" }, +{ "461959350160a422e7806a9e8201146b29a3a21f" , "SIEMENS_MAGNETOM-12-MONO2-FileSeq3.dcm" }, +{ "e5152fe2ada738f5b0c86af0858dc6d6b3ed9520" , "SIEMENS_MAGNETOM-12-MONO2-GDCM12-VRUN.dcm" }, +{ "bcba71eae5a0e3e43d836c410118e5992f6a6fb7" , "SIEMENS_MAGNETOM-12-MONO2-Uncompressed.dcm" }, +{ "38284e6f4591418be8a572aaa190a86b9487ed6f" , "SIEMENS_MAGNETOM-12-MONO2-VRUN.dcm" }, +{ "61b1b8768cde82a51fa8f5238713d65f16aeff68" , "SIEMENS_MOSAIC_12BitsStored-16BitsJPEG.dcm" }, +{ "a3646e926f9b8dd6a536b95ab8a86ee35f74f612" , "SIEMENS-MR-RGB-16Bits.dcm" }, +{ "542213ababb9f3410be5516d28adece7ca9aa4ad" , "SIEMENS_SOMATOM-12-ACR_NEMA-ZeroLengthUs.acr" }, +{ "6d08c8b6f34de509166fa4d1e456e12861ab86e7" , "SIEMENS_Sonata-12-MONO2-SQ.dcm" }, +{ "4204cf122c096365f7fa14009a4dd62c49e9e5cf" , "SIEMENS_Sonata-16-MONO2-Value_Multiplicity.dcm" }, +{ "cd2c42d837702aab1f85de4dc000962dda1fe2f7" , "SignedShortLosslessBug.dcm" }, +{ "d6e3e55033bd06e8b3e67ef83168d7425cf63c2f" , "simpleImageWithIcon.dcm" }, +{ "55d4b449f51012c6bcad025a99eea672ba880a60" , "test.acr" }, +{ "918939283378898524dfa449fd9c9bc12b6dd189" , "TG18-CH-2k-01.dcm" }, +{ "d70be071b03866d8b561588588b9541ad4c370d7" , "THERALYS-12-MONO2-Uncompressed-Even_Length_Tag.dcm" }, +{ "1f06affc50bfd1382efbf1960f5c601f79db841d" , "TheralysGDCM120Bug.dcm" }, +{ "16d9e8000e9b19dd3bdb36b3a829780aa43c8b74" , "TOSHIBA_MRT150-16-MONO2-ACR_NEMA_2.dcm" }, +{ "f188be58d7378e0949b0ee21ef72906ec1c7e236" , "undefined_length_un_vr.dcm" }, +{ "acf081a99759cef05711ec51d5da9e910396024d" , "US-GE-4AICL142.dcm" }, +{ "7330de615594148320e2f48a6aecb2e65607fa31" , "US-IRAD-NoPreambleStartWith0003.dcm" }, +{ "3ffd40a0aba42431d2b2deeed07013e66afb0328" , "US-IRAD-NoPreambleStartWith0005.dcm" }, +{ "035d7791c0fce801078854697fef86292a97eef1" , "US-MONO2-8-8x-execho.dcm" }, +{ "8e9ef1a7516ab9bc0fbe894e25c28c7d15dd848d" , "US-PAL-8-10x-echo.dcm" }, +{ "b401f77c8c78a82422baad6f6d42dcc275b7f0e0" , "US-RGB-8-epicard.dcm" }, +{ "f4368f3e10ebbd70fbe00c3d4b29d30df3adee85" , "US-RGB-8-esopecho.dcm" }, +{ "750f15609a6f442c0517173138e404894849b374" , "XA-MONO2-8-12x-catheter.dcm" }, +{ "cdc423e6abfb6fd678a3e65675cd5ce42f304b0d" , "PHILIPS_GDCM12xBug2.dcm" }, +{ "916938d82884fcb77a54dade49481e15049e50b6" , "PHILIPS_GDCM12xBug.dcm" }, +{ "0f058542379c201e26ef233a4b116862283bc81e" , "AMIInvalidPrivateDefinedLengthSQasUN.dcm" }, +{ "ec4a0d2ff24e9c2f3281b75c479914aff3215fb7" , "OsirixFake16BitsStoredFakeSpacing.dcm" }, +{ "27277c296a9703f22b2ef033ec326dd22b4bacc9" , "MR16BitsAllocated_8BitsStored.dcm" }, +{ "6260235b715af050f47494e098fcaa2ada3a11a5" , "JPEGDefinedLengthSequenceOfFragments.dcm" }, +{ "b1977dfddff0d88742bc6f6368d56eb9d3325dd9" , "IM-0001-0066.CommandTag00.dcm" }, +{ "f9d31313e26c335d26e4fd9126d88f1467425117" , "UnexpectedSequenceDelimiterInFixedLengthSequence.dcm" }, +{ "ac491044a7c69d3a365f31f163db3a4bf1085afa" , "GDCMJ2K_TextGBR.dcm" }, +{ "ed38be73d76c7a326012f86034c7472aa02d83ee" , "NM_Kakadu44_SOTmarkerincons.dcm" }, +{ "c06aae794ed5690ae82237f4f153ca7795ddd5b7" , "PhilipsInteraSeqTermInvLen.dcm" }, +{ "c14634b31dc52e4ed2b0c626aa61af4de207f6e4" , "TOSHIBA_J2K_SIZ1_PixRep0.dcm" }, +{ "bf68f33e0922508d6075f0893298d339d817aa86" , "TOSHIBA_J2K_OpenJPEGv2Regression.dcm" }, +{ "6d21ac7b5b4ad32b7d91750a70b574a732b679a7" , "TOSHIBA_J2K_SIZ0_PixRep1.dcm" }, +{ "94cadb9e79e0d04f3c212cf6fa069b3cf3f09a76" , "NM-PAL-16-PixRep1.dcm" }, +{ "156463350047cada3ec091396695d3f3ef660c9a" , "MEDILABInvalidCP246_EVRLESQasUN.dcm" }, +{ "9775e8206011b9d5cedfcba16946060cb047f826" , "JPEGInvalidSecondFrag.dcm" }, + +{ NULL, NULL} +}; + +int TestSHA1Func(const char* filename, const char *sha1ref, bool verbose = false) +{ + if( !filename || !sha1ref) return 1; + + if( verbose ) + std::cout << "TestRead: " << filename << std::endl; + const char *dataroot = gdcm::Testing::GetDataRoot(); + std::string path = dataroot; + path += "/"; + path += filename; + path = filename; + char sha1[2*20+1] = {}; + bool b = gdcm::SHA1::ComputeFile( path.c_str(), sha1 ); + if( !b ) + { + std::cerr << "Fail ComputeFile: " << path << std::endl; + return 1; + } + if( strcmp( sha1, sha1ref) != 0 ) + { + std::cout << "Problem with: " << path << std::endl; + std::cout << "Ref: " << sha1ref << " vs " << sha1 << std::endl; + return 1; + } + return 0; +} + +static const char *GetSHA1Sum(const char *filename) +{ + typedef const char * const (*sha1pair)[2]; + const char *sha1filename; + sha1pair sha1filenames = gdcmSHA1SumFiles; + int i = 0; + while( ( sha1filename = sha1filenames[i][1] ) ) + { + gdcm::Filename fn( filename ); + if( strcmp( sha1filename, fn.GetName() ) == 0 ) + { + return sha1filenames[i][0]; + } + ++i; + } + std::cerr << "Missing SHA1 for: " << filename << std::endl; + return 0; +} + + +int TestSHA1(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + const char *sha1 = GetSHA1Sum( filename ); + return TestSHA1Func(filename, sha1, true); + } + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + const char *sha1 = GetSHA1Sum( filename ); + r += TestSHA1Func( filename, sha1 ); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/Common/Cxx/TestSmartPointer.cxx b/gdcm/Testing/Source/Common/Cxx/TestSmartPointer.cxx new file mode 100644 index 0000000..e1f03a0 --- /dev/null +++ b/gdcm/Testing/Source/Common/Cxx/TestSmartPointer.cxx @@ -0,0 +1,121 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmSmartPointer.h" +#include "gdcmObject.h" + +#include + +using gdcm::Object; +using gdcm::SmartPointer; + +class Foo : public Object { + public: + void foo() { // Does exist in Object as far as I know :) + std::cout << "foo" << std::endl; + } +}; + +class Containter { +public: + Containter():Instance(0) {} + SmartPointer Instance; +}; + +void Fill(SmartPointer &p) +{ + SmartPointer in = new Foo; + // p = in; + Foo & rp = *in; + p = &rp; +} + +SmartPointer gf; + +SmartPointer TestReturn(int i) +{ + static int n = 0; + if( !n ) + { + ++n; + gf = new Foo; + } + + if( i == 0 ) + { + return gf; + } + else if( i == 1 ) + { + SmartPointer f = new Foo; + return f; + } + else if( i == 2 ) + { + return new Foo; + } + return 0; +} + +//class Object2 : public Foo {}; + +int TestSmartPointer(int, char *[]) +{ + SmartPointer p = new Object; + SmartPointer p2 = new Foo; + p2->foo(); + SmartPointer p3 = new Foo; + //p3->foo(); // should not compile + + //std::cout << p << std::endl; + //std::cout << p2 << std::endl; + //std::cout << p3 << std::endl; + + if( p == p2 + || p == p3 + || p2 == p3 ) + { + return 1; + } + + // SmartPointer + SmartPointer p4 = p2; + SmartPointer p5 = p3; + + // Pointer: + SmartPointer p6 = &(*p2); + + SmartPointer p7; + Fill(p7); + Foo &foo = *p7; + foo.foo(); + + Containter c1; + Containter c2; + c2 = c1; + + // TODO: + //SmartPointer s = new Foo; + //delete s; + + for(int i = 0; i < 5; ++i) + { + SmartPointer f = TestReturn(i); + if( f ) + { + f->foo(); + } + } + + return 0; +} diff --git a/gdcm/Testing/Source/Common/Cxx/TestString.cxx b/gdcm/Testing/Source/Common/Cxx/TestString.cxx new file mode 100644 index 0000000..8104772 --- /dev/null +++ b/gdcm/Testing/Source/Common/Cxx/TestString.cxx @@ -0,0 +1,115 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmString.h" +#include + +typedef gdcm::String<'\\',64> CSComp; + +void Print(CSComp v) +{ + std::cout << v << std::endl; +} + +int TestString(int , char *[]) +{ +{ + gdcm::String<'\\'> s = "coucou"; + std::cout << s << std::endl; + + const char str[] = "WINDOW1\\WINDOW2\\WINDOW3"; + //const size_t lenstr = strlen(str); + + gdcm::String<'\\'> ms1, ms2, ms3; + std::stringstream ss; + ss << str; + ss >> ms1; + ss.get(); // discard backslash + std::cout << ms1 << std::endl; + if( ms1 != "WINDOW1" ) return 1; + ss >> ms2; + ss.get(); + std::cout << ms2 << std::endl; + if( ms2 != "WINDOW2" ) return 1; + ss >> ms3; + ss.get(); + std::cout << ms3 << std::endl; + if( ms3 != "WINDOW3" ) return 1; + + // we are at the end: + if( !!ss ) + { + std::cerr << "not at the end" << std::endl; + return 1; + } +} +{ + gdcm::String<'^'> s = "coucou"; + std::cout << s << std::endl; + + const char str[] = "WINDOW1^WINDOW2^WINDOW3"; + //const size_t lenstr = strlen(str); + + gdcm::String<'^'> ms1, ms2, ms3; + std::stringstream ss; + ss << str; + ss >> ms1; + ss.get(); // discard backslash + std::cout << ms1 << std::endl; + if( ms1 != "WINDOW1" ) return 1; + ss >> ms2; + ss.get(); + std::cout << ms2 << std::endl; + if( ms2 != "WINDOW2" ) return 1; + ss >> ms3; + ss.get(); + std::cout << ms3 << std::endl; + if( ms3 != "WINDOW3" ) return 1; + + // we are at the end: + if( !!ss ) return 1; +} +{ + gdcm::String<> s = "coucou"; + std::cout << s << std::endl; + + const char str[] = "WINDOW1^WINDOW2^WINDOW3"; + //const size_t lenstr = strlen(str); + + gdcm::String<> ms1; + std::stringstream ss; + ss << str; + ss >> ms1; + std::cout << ms1 << std::endl; + ss.get(); // discard \n + if ( ms1 != str ) return 1; + + // we are at the end: + if( !!ss ) return 1; +} + + std::string privatecreator = " CREATOR SMS-AX "; + std::cout << "[" << privatecreator << "]" << std::endl; + privatecreator.erase(privatecreator.find_last_not_of(' ') + 1); + std::cout << "[" << privatecreator << "]" << std::endl; + + static const CSComp values[] = {"DERIVED","SECONDARY"}; + std::cout << values[0] << std::endl; + Print( values[0] ); + + const char trim[] = "8 "; + gdcm::String<> strim( trim ); + std::cout << "|" << strim.Trim() << "|" << std::endl; + + return 0; +} diff --git a/gdcm/Testing/Source/Common/Cxx/TestString2.cxx b/gdcm/Testing/Source/Common/Cxx/TestString2.cxx new file mode 100644 index 0000000..59e81c7 --- /dev/null +++ b/gdcm/Testing/Source/Common/Cxx/TestString2.cxx @@ -0,0 +1,50 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmString.h" + +#include + +#include // strlen +#include // EOF + +int TestString2(int , char *[]) +{ + gdcm::String<> s1 = "coucou"; + std::cout << s1 << " -> " << s1.size() << std::endl; + + gdcm::String<> s2 = "coucou!"; + std::cout << s2 << " -> " << s2.size() << std::endl; + + gdcm::String s3 = "coucou"; + std::cout << s3.c_str() << " -> " << s3.size() << std::endl; + + gdcm::String s4 = "coucou!"; + std::cout << s4.c_str() << " -> " << s4.size() << std::endl; + + const char *s = "coucou!"; + gdcm::String s5( s, strlen(s) ); + std::cout << s5.c_str() << " -> " << s5.size() << std::endl; + + std::string ss = "coucou!"; + gdcm::String s6( ss ); + std::cout << s6.c_str() << " -> " << s6.size() << std::endl; + + gdcm::String s7( ss, 1, 5 ); + std::cout << s7.c_str() << " -> " << s7.size() << std::endl; + + gdcm::String s8( ss, 1, 6 ); + std::cout << s8.c_str() << " -> " << s8.size() << std::endl; + + return 0; +} diff --git a/gdcm/Testing/Source/Common/Cxx/TestSwapCode.cxx b/gdcm/Testing/Source/Common/Cxx/TestSwapCode.cxx new file mode 100644 index 0000000..ad0660f --- /dev/null +++ b/gdcm/Testing/Source/Common/Cxx/TestSwapCode.cxx @@ -0,0 +1,19 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmSwapCode.h" + +int TestSwapCode(int, char *[]) +{ + return 0; +} diff --git a/gdcm/Testing/Source/Common/Cxx/TestSwapper.cxx b/gdcm/Testing/Source/Common/Cxx/TestSwapper.cxx new file mode 100644 index 0000000..92f31bf --- /dev/null +++ b/gdcm/Testing/Source/Common/Cxx/TestSwapper.cxx @@ -0,0 +1,44 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmSwapper.h" + + +int TestSwapper(int argc, char *argv[]) +{ + (void)argv; (void)argc; + int res = 0; + + typedef union { + uint64_t v64; + uint32_t v32[2]; + uint16_t v16[4]; + uint8_t v8[8]; + } testswapper; + testswapper t; + for(uint_fast8_t i = 0; i < 8; ++i) t.v8[i] = i; + + testswapper val; + val.v64 = gdcm::SwapperDoOp::Swap(t.v64); + //for(int i = 0; i < 8; ++i) std::cout << (int)val.v8[i] << std::endl; + for(int i = 0; i < 8; ++i) + { + if( val.v8[i] != 8 - i - 1) + { + ++res; + } + } + + + return res; +} diff --git a/gdcm/Testing/Source/Common/Cxx/TestSystem1.cxx b/gdcm/Testing/Source/Common/Cxx/TestSystem1.cxx new file mode 100644 index 0000000..ab6f7e1 --- /dev/null +++ b/gdcm/Testing/Source/Common/Cxx/TestSystem1.cxx @@ -0,0 +1,404 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmSystem.h" +#include "gdcmTesting.h" +#include "gdcmFilename.h" +#include +#include + +#include // strlen + +#include + +int TestGetTimeOfDay() +{ + time_t t = time(0); + char date[22]; + if( !gdcm::System::GetCurrentDateTime(date) ) + { + std::cerr << "Error" << std::endl; + return 1; + } + char time_date[22]; + if( !gdcm::System::FormatDateTime(time_date, t) ) + { + std::cerr << "Error" << std::endl; + return 1; + } + //std::cout << date << std::endl; + //std::cout << time_date << std::endl; + + if ( strncmp( date, time_date, strlen("20090511172802.") ) != 0 ) + { + std::cerr << "Error" << std::endl; + return 1; + } + return 0; +} + +int TestSystem1(int, char *[]) +{ + const char s1[] = "HELLO, wORLD !"; + const char s2[] = "Hello, World !"; + if( gdcm::System::StrCaseCmp(s1,s2) != 0 ) + { + return 1; + } + if( gdcm::System::StrNCaseCmp(s1,s2, strlen(s1)) != 0 ) + { + return 1; + } + const char s3[] = "Hello, World ! "; + if( gdcm::System::StrCaseCmp(s1,s3) == 0 ) + { + return 1; + } + if( gdcm::System::StrNCaseCmp(s1,s3, strlen(s1)) != 0 ) + { + return 1; + } + if( gdcm::System::StrNCaseCmp(s1,s3, strlen(s3)) == 0 ) + { + return 1; + } + + // struct stat { + // off_t st_size; /* total size, in bytes */ + // } + + //unsigned long size1 = sizeof(off_t); + unsigned long size2 = sizeof(size_t); + unsigned long size4 = sizeof(std::streamsize); +#if 0 + if( size1 > size2 ) + { + std::cerr << "size_t is not appropriate on this system" << std::endl; // fails on some macosx + return 1; + } + unsigned long size3 = sizeof(uintmax_t); + if( size2 != size3 ) + { + std::cerr << "size_t is diff from uintmax_t: " << size2 << " " << size3 << std::endl; + return 1; + } +#endif + if( size2 != size4 ) + { + std::cerr << "size_t is diff from std::streamsize: " << size2 << " " << size4 << std::endl; + return 1; + } + + char datetime[22]; + bool bres = gdcm::System::GetCurrentDateTime(datetime); + if( !bres ) + { + std::cerr << "bres" << std::endl; + return 1; + } + assert( datetime[21] == 0 ); + std::cerr << datetime << std::endl; + + const char *cwd = gdcm::System::GetCWD(); + std::cerr << "cwd:" << cwd << std::endl; + // GDCM_EXECUTABLE_OUTPUT_PATH "/../" "/Testing/Source/Common/Cxx" + + /* + * I can do this kind of testing here since I know testing: + * - cannot be installed (no rule in cmakelists) + * - they cannot be moved around since cmake is not relocatable + * thus this is safe to assume that current process directory is actually the executable output + * path as computed by cmake: + * + * TODO: there can be trailing slash... + */ + const char *path = gdcm::System::GetCurrentProcessFileName(); + if( !path ) + { + std::cerr << "Missing implemnetation for GetCurrentProcessFileName" << std::endl; + return 1; + } + gdcm::Filename fn( path ); +//std::cerr << path << std::endl; + if( strncmp(GDCM_EXECUTABLE_OUTPUT_PATH, fn.GetPath(), strlen(GDCM_EXECUTABLE_OUTPUT_PATH)) != 0 ) + { + std::cerr << GDCM_EXECUTABLE_OUTPUT_PATH << " != " << fn.GetPath() << std::endl; + gdcm::Filename fn_debug1( GDCM_EXECUTABLE_OUTPUT_PATH ); + gdcm::Filename fn_debug2( fn.GetPath() ); + std::cerr << fn_debug1.GetFileName() << " , " << fn_debug2.GetFileName() << std::endl; + std::cerr << std::boolalpha << fn_debug1.IsIdentical( fn_debug2 ) << std::endl; + return 1; + } + // gdcmCommonTests + const char exename[] = "gdcmCommonTests"; + if( strncmp(exename, fn.GetName(), strlen(exename)) != 0 ) + { + std::cerr << exename << " != " << fn.GetName() << std::endl; + return 1; + } + +{ + char date[22]; + if( !gdcm::System::GetCurrentDateTime( date ) ) + { + std::cerr << "GetCurrentDateTime: " << date << std::endl; + return 1; + } + assert( date[21] == 0 ); + time_t timep; long milliseconds; + if( !gdcm::System::ParseDateTime(timep, milliseconds, date) ) + { + std::cerr << "Could not re-parse: " << date << std::endl; + return 1; + } + char date2[22]; + if( !gdcm::System::FormatDateTime(date2, timep, milliseconds) ) + { + return 1; + } + assert( date2[21] == 0 ); + + if( strcmp( date, date2 ) != 0 ) + { + std::cerr << "date1=" << date << std::endl; + std::cerr << "date2=" << date2 << std::endl; + return 1; + } +} + // Skip millisecond this time: +{ + char date[22+1]; + if( !gdcm::System::GetCurrentDateTime( date ) ) + { + std::cerr << "GetCurrentDateTime: " << date << std::endl; + return 1; + } + date[14] = 0; + std::cout << date << std::endl; + time_t timep; + if( !gdcm::System::ParseDateTime(timep, date) ) + { + std::cerr << "ParseDateTime" << std::endl; + return 1; + } + char date2[22+1]; + date2[22] = 0; + if( !gdcm::System::FormatDateTime(date2, timep) ) + { + std::cerr << "FormatDateTime" << std::endl; + return 1; + } + + // FormatDateTime always print millisecond, only compare the date up to the millisecond: + if( strncmp( date, date2, strlen(date) ) != 0 ) + { + std::cerr << "date1=" << date << std::endl; + std::cerr << "date2=" << date2 << std::endl; + return 1; + } +} + + // Check some valid date +{ + // YYYYMMDDHHMMSS.FFFFFF&ZZXX + static const char *dates[] = { + "2001", + "200101", + "20010102", + "2001010203", + "200101020304", + "20010102030405", + "20010102030405", + "20010102030405.01", + "20010102030405.0101", + "20010102030405.010101", + }; + for(int i = 0; i < 10; ++i ) + { + const char *date = dates[i]; + time_t timep; long milliseconds; + if( !gdcm::System::ParseDateTime(timep, milliseconds, date) ) + { + std::cerr << "Should accept: " << date << std::endl; + return 1; + } + } +} + // Check some invalid date +{ + // YYYYMMDDHHMMSS.FFFFFF&ZZXX + static const char *dates[] = { + "200", + "200121", + "20010142", + "2001010233", + "200101020374", + "20010102030485", + "20010102030405.", + "20010102030405-0000000", + "20010102030405.0000001", + "20010102030405.0000001", + }; + for(int i = 0; i < 10; ++i ) + { + const char *date = dates[i]; + time_t timep; long milliseconds; + if( gdcm::System::ParseDateTime(timep, milliseconds, date) ) + { + char buffer[22]; + gdcm::System::FormatDateTime(buffer, timep, milliseconds); + std::cerr << "Should not accept: " << date << std::endl; + std::cerr << "rendered as: " << buffer << std::endl; + return 1; + } + } +} + + //const char long_str8[] = " 0123456789"; + //long l = 0; + //int n = sscanf( long_str8, "%8ld", &l ); + //std::cout << "Long:" << l << std::endl; + + char hostname[255+1]; + hostname[255] = 0; + if( gdcm::System::GetHostName( hostname ) ) + { + std::cout << "Host:" << hostname << std::endl; + } + else + { + return 1; + } + + //time_t t = gdcm::System::FileTime("/etc/debian_version"); + //char date3[22]; + //gdcm::System::FormatDateTime(date3, t); + //std::cout << date3 << std::endl; + + const char fixed_date[] = "20090428172557.515500"; + if( strlen( fixed_date ) != 21 ) + { + std::cerr << "fixed_date" << std::endl; + return 1; + } + time_t fixed_timep; + long fixed_milliseconds; + if( !gdcm::System::ParseDateTime(fixed_timep, fixed_milliseconds, fixed_date) ) + { + std::cerr << "ParseDateTime" << std::endl; + return 1; + } + if( fixed_milliseconds != 515500 ) +{ + std::cerr << "fixed_milliseconds" << std::endl; +return 1; +} + char fixed_date2[22]; + if( !gdcm::System::FormatDateTime(fixed_date2, fixed_timep, fixed_milliseconds) ) +{ + std::cerr << "FormatDateTime" << std::endl; + return 1; +} +assert( fixed_date2[21] == 0 ); + if( strcmp( fixed_date, fixed_date2 ) != 0 ) +{ + std::cerr << "fixed_date | fixed_date2" << std::endl; + return 1; +} + + const char invalid_date1[] = "20090428172557."; +if( gdcm::System::ParseDateTime(fixed_timep, fixed_milliseconds, invalid_date1) ) +{ +std::cerr << "should reject:" << invalid_date1 << std::endl; +return 1; +} + const char invalid_date2[] = "200"; +if( gdcm::System::ParseDateTime(fixed_timep, fixed_milliseconds, invalid_date2) ) +{ +std::cerr << "should reject:" << invalid_date2 << std::endl; +return 1; +} +// const char invalid_date3[] = "17890714172557"; +//if( gdcm::System::ParseDateTime(fixed_timep, fixed_milliseconds, invalid_date3) ) +//{ +//std::cerr << "should reject:" << invalid_date3 << std::endl; +//char buffer[22]; +//gdcm::System::FormatDateTime( buffer, fixed_timep, fixed_milliseconds ); +//std::cerr << "Found" << buffer << std::endl; +//return 1; +//} +// const char invalid_date4[] = "19891714172557"; +//if( gdcm::System::ParseDateTime(fixed_timep, fixed_milliseconds, invalid_date4) ) +//{ +//std::cerr << "should reject:" << invalid_date4 << std::endl; +//char buffer[22]; +//gdcm::System::FormatDateTime( buffer, fixed_timep, fixed_milliseconds ); +//std::cerr << "Found" << buffer << std::endl; +// +//return 1; +//} +// const char invalid_date5[] = "19890014172557"; +//if( gdcm::System::ParseDateTime(fixed_timep, fixed_milliseconds, invalid_date5) ) +//{ +//std::cerr << "should reject:" << invalid_date5 << std::endl; +//char buffer[22]; +//gdcm::System::FormatDateTime( buffer, fixed_timep, fixed_milliseconds ); +//std::cerr << "Found" << buffer << std::endl; +// +//return 1; +//} + const char valid_date1[] = "19890714172557"; +if( !gdcm::System::ParseDateTime(fixed_timep, fixed_milliseconds, valid_date1) ) +{ +std::cerr << "should accept:" << valid_date1 << std::endl; +return 1; +} + int res = 0; + res += TestGetTimeOfDay(); + + const char * testfilesize = gdcm::Testing::GetTempFilename( "filesize.bin" ); +if( gdcm::System::FileExists( testfilesize ) ) +{ + gdcm::System::RemoveFile(testfilesize); +} + + size_t ss1 = gdcm::System::FileSize( testfilesize ); +if( ss1 != 0 ) +{ +std::cerr << "found:" << ss1 << std::endl; + ++res; +} + + std::ofstream os( testfilesize, std::ios::binary ); + const char coucou[] = "coucou"; + os << coucou; + os.flush(); + os.close(); + + size_t ss2 = gdcm::System::FileSize( testfilesize ); + if( ss2 != strlen( coucou ) ) +{ +std::cerr << "found:" << ss2 << std::endl; + res++; +} + + + const char *codeset = gdcm::System::GetLocaleCharset(); +if( !codeset ) +{ +std::cerr << "Could nto find Charset on your system. Please report." << std::endl; +res++; +} + + return res; +} diff --git a/gdcm/Testing/Source/Common/Cxx/TestSystem2.cxx b/gdcm/Testing/Source/Common/Cxx/TestSystem2.cxx new file mode 100644 index 0000000..1d35040 --- /dev/null +++ b/gdcm/Testing/Source/Common/Cxx/TestSystem2.cxx @@ -0,0 +1,73 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmSystem.h" +#include "gdcmTesting.h" + +#define _FILE_OFFSET_BITS 64 +#include + +static bool mybool; +static size_t actualde; + +static bool check( const int64_t inslen ) +{ + std::cerr << "check:" << inslen << std::endl; + if( inslen < 0 ) return true; + return false; +} + +static bool append( size_t len ) +{ + off_t newlen = len; +#if 1 + newlen -= actualde; + return check( newlen ); +#else + return check( newlen - actualde ); +#endif +} + +int TestSystem2(int, char *[]) +{ + const int soff = sizeof( off_t ); + std::cerr << soff << std::endl; + mybool = true; + actualde = 26; + + off_t o0 = -1; + off_t o1 = 0; + //off_t o2 = 1; + + std::cerr << "t:" << o0 << std::endl; + if( o0 > o1 ) + { + std::cerr << "Not a long value" << std::endl; + return 1; + } + int val1 = 5; + int val2 = 10; + size_t size = 2; + const off_t o = size; + + if( !check( o + val1 - val2 ) ) + { + return 1; + } + if( !append( 2 ) ) + { + return 1; + } + + return 0; +} diff --git a/gdcm/Testing/Source/Common/Cxx/TestSystem3.cxx b/gdcm/Testing/Source/Common/Cxx/TestSystem3.cxx new file mode 100644 index 0000000..3161203 --- /dev/null +++ b/gdcm/Testing/Source/Common/Cxx/TestSystem3.cxx @@ -0,0 +1,63 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmSystem.h" +#include "gdcmTesting.h" + +#include +#include // strdup + +int TestSystem3(int, char *[]) +{ + const char isostr[] = "\\ISO 2022 IR 13\\ISO 2022 IR 87"; + + const char delim[] = "\\"; + char *token; +{ + char *query = strdup( isostr ); + char *str1; + char *saveptr1; + + std::vector< std::string > v; + for (str1 = query; ; str1 = NULL) + { + token = gdcm::System::StrTokR(str1, delim, &saveptr1); + if (token == NULL) + break; + //std::cout << "[" << token << "]" << std::endl; + v.push_back( token ); + } + free( query ); + + if( v.size() != 2 ) return 1; + if( v[0] != "ISO 2022 IR 13" ) return 1; + if( v[1] != "ISO 2022 IR 87" ) return 1; +} + +{ + std::vector< std::string > v; + char *string = strdup( isostr ); + while ((token = gdcm::System::StrSep(&string, delim)) != NULL) + { + //printf("token=%s\n", token); + v.push_back( token ); + } + free( string ); + if( v.size() != 3 ) return 1; + if( v[0] != "" ) return 1; + if( v[1] != "ISO 2022 IR 13" ) return 1; + if( v[2] != "ISO 2022 IR 87" ) return 1; +} + + return 0; +} diff --git a/gdcm/Testing/Source/Common/Cxx/TestTerminal.cxx b/gdcm/Testing/Source/Common/Cxx/TestTerminal.cxx new file mode 100644 index 0000000..047a59b --- /dev/null +++ b/gdcm/Testing/Source/Common/Cxx/TestTerminal.cxx @@ -0,0 +1,60 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmTerminal.h" + +#include + +namespace term = gdcm::terminal; + +void TestAll() +{ + std::cout << term::setattribute( term::bright ) << "bright" << std::endl; + std::cout << term::setattribute( term::dim ) << "dim" << std::endl; + std::cout << term::setattribute( term::underline ) << "underline" << std::endl; + std::cout << term::setattribute( term::blink ) << "blink" << std::endl; + std::cout << term::setattribute( term::reverse ) << "reverse" << std::endl; + std::cout << term::setattribute( term::reset ) << "reset" << std::endl; + std::cout << term::setfgcolor( term::black ) << "fg:black" << std::endl; + std::cout << term::setfgcolor( term::red ) << "fg:red " << std::endl; + std::cout << term::setfgcolor( term::green ) << "fg:green" << std::endl; + std::cout << term::setfgcolor( term::yellow ) << "fg:yellow" << std::endl; + std::cout << term::setfgcolor( term::blue ) << "fg:blue" << std::endl; + std::cout << term::setfgcolor( term::magenta ) << "fg:magenta" << std::endl; + std::cout << term::setfgcolor( term::cyan ) << "fg:cyan" << std::endl; + std::cout << term::setfgcolor( term::white ) << "fg:white" << std::endl; + std::cout << term::setattribute( term::reverse ) << term::setfgcolor( term::white ) << "fg:white" << std::endl; + std::cout << term::setbgcolor( term::black ) << "bg:black" << std::endl; + std::cout << term::setbgcolor( term::red ) << "bg:red " << std::endl; + std::cout << term::setbgcolor( term::green ) << "bg:green" << std::endl; + std::cout << term::setbgcolor( term::yellow ) << "bg:yellow" << std::endl; + std::cout << term::setbgcolor( term::blue ) << "bg:blue" << std::endl; + std::cout << term::setbgcolor( term::magenta ) << "bg:magenta" << std::endl; + std::cout << term::setbgcolor( term::cyan ) << "bg:cyan" << std::endl; + std::cout << term::setbgcolor( term::white ) << "bg:white" << std::endl; + std::cout << term::setattribute( term::reset ) << "reset" << std::endl; + //std::cerr << term::setbgcolor( term::blue ) << "cerr:bg:blue" << std::endl; +} + +int TestTerminal(int , char *[]) +{ + // Typically for WIN32 + term::setmode( term::CONSOLE ); + TestAll(); + // For all *NIX + // rxvt is WIN32 app, but is a VT100 compatible TERM + term::setmode( term::VT100 ); + TestAll(); + + return 0; +} diff --git a/gdcm/Testing/Source/Common/Cxx/TestTesting.cxx b/gdcm/Testing/Source/Common/Cxx/TestTesting.cxx new file mode 100644 index 0000000..3820394 --- /dev/null +++ b/gdcm/Testing/Source/Common/Cxx/TestTesting.cxx @@ -0,0 +1,49 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmTesting.h" +#include "gdcmSystem.h" + +int TestTesting(int , char *[]) +{ + gdcm::Testing testing; + testing.Print( std::cout ); + + const char *f = gdcm::Testing::GetFileName( 100000 ); + if( f ) return 1; + + std::cout << "Num:" << gdcm::Testing::GetNumberOfFileNames() << std::endl; + + const char * const * md5 = gdcm::Testing::GetMD5DataImage( 100000 ); + if( !md5 ) return 1; + if( md5[0] || md5[1] ) return 1; + + const char * const *null = gdcm::Testing::GetMD5DataImage(1000000000u); + if( null[0] != NULL || null[1] != NULL ) + { + return 1; + } + + + const char *tmp = gdcm::Testing::GetTempDirectory(); + if( !gdcm::System::FileExists(tmp) ) + { + return 1; + } + if( !gdcm::System::FileIsDirectory(tmp) ) + { + return 1; + } + + return 0; +} diff --git a/gdcm/Testing/Source/Common/Cxx/TestTrace.cxx b/gdcm/Testing/Source/Common/Cxx/TestTrace.cxx new file mode 100644 index 0000000..a828606 --- /dev/null +++ b/gdcm/Testing/Source/Common/Cxx/TestTrace.cxx @@ -0,0 +1,119 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmTrace.h" + +#include + +int TestTrace(int, char *[]) +{ + gdcm::Trace t; //initializes all macros to 'off' + + gdcmDebugMacro( "DebugKO" ); + gdcmWarningMacro( "WarningKO" ); + gdcmErrorMacro( "ErrorKO" ); + + // test the SetStream interface + std::ostringstream useros; + gdcm::Trace::SetStream( useros ); + + gdcmDebugMacro( "DebugOK_OFF" ); + gdcmWarningMacro( "WarningOK_OFF" ); + gdcmErrorMacro( "ErrorOK_OFF" ); + + gdcm::Trace::DebugOn(); + gdcm::Trace::WarningOn(); + gdcm::Trace::ErrorOn(); + + gdcmDebugMacro( "DebugOK_ON" ); + gdcmWarningMacro( "WarningOK_ON" ); + gdcmErrorMacro( "ErrorOK_ON" ); + + //in release mode, tracing just doesn't work any more, so this test isn't valid. +#ifndef NDEBUG + std::string result = useros.str(); + if( result.find( "KO" ) != std::string::npos ) + { + std::cerr << result << std::endl; + return 1; + } + if( result.find( "OFF" ) != std::string::npos ) + { + std::cerr << result << std::endl; + return 1; + } + + // opposite: + if( result.find( "OK" ) == std::string::npos ) + { + std::cerr << result << std::endl; + return 1; + } + if( result.find( "ON" ) == std::string::npos ) + { + std::cerr << result << std::endl; + return 1; + } +#endif + + // Test Debug/Warning/Error interface: + std::ostringstream debug; + std::ostringstream warning; + std::ostringstream error; + + gdcm::Trace::SetDebugStream( debug ); + gdcm::Trace::SetWarningStream( warning ); + gdcm::Trace::SetErrorStream( error ); + + gdcmDebugMacro( "Debug1234" ); + gdcmWarningMacro( "Warning1234" ); + gdcmErrorMacro( "Error1234" ); + +#ifndef NDEBUG + std::string result1 = debug.str(); + std::string result2 = warning.str(); + std::string result3 = error.str(); + if( result1.find( "Debug1234" ) == std::string::npos ) + { + std::cerr << result1 << std::endl; + return 1; + } + if( result2.find( "Warning1234" ) == std::string::npos ) + { + std::cerr << result2 << std::endl; + return 1; + } + if( result3.find( "Error1234" ) == std::string::npos ) + { + std::cerr << result3 << std::endl; + return 1; + } + if( result1.find( "Warning1234" ) != std::string::npos ) + { + std::cerr << result1 << std::endl; + return 1; + } + if( result2.find( "Error1234" ) != std::string::npos ) + { + std::cerr << result2 << std::endl; + return 1; + } + if( result3.find( "Debug1234" ) != std::string::npos ) + { + std::cerr << result3 << std::endl; + return 1; + } +#endif + + return 0; +} diff --git a/gdcm/Testing/Source/Common/Cxx/TestTypes.cxx b/gdcm/Testing/Source/Common/Cxx/TestTypes.cxx new file mode 100644 index 0000000..faf5ea3 --- /dev/null +++ b/gdcm/Testing/Source/Common/Cxx/TestTypes.cxx @@ -0,0 +1,33 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmTypes.h" + +int TestTypes(int argc, char *argv[]) +{ + (void)argc; + (void)argv; + + if( sizeof(int8_t) != 1 ) return 1; + if( sizeof(int16_t) != 2 ) return 1; + if( sizeof(int32_t) != 4 ) return 1; + if( sizeof(uint8_t) != 1 ) return 1; + if( sizeof(uint16_t) != 2 ) return 1; + if( sizeof(uint32_t) != 4 ) return 1; + if( sizeof(uint64_t) != 8 ) return 1; + + if( sizeof(float) != 4 ) return 1; + if( sizeof(double) != 8 ) return 1; + + return 0; +} diff --git a/gdcm/Testing/Source/Common/Cxx/TestUnpacker12Bits.cxx b/gdcm/Testing/Source/Common/Cxx/TestUnpacker12Bits.cxx new file mode 100644 index 0000000..d6639f9 --- /dev/null +++ b/gdcm/Testing/Source/Common/Cxx/TestUnpacker12Bits.cxx @@ -0,0 +1,136 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmUnpacker12Bits.h" + +#include +#include +#include + +#include + +int TestUnpacker12Bits(int, char *[]) +{ + int res = 0; +{ + const size_t len = (256 / 3 ) * 3; + char *values = new char[len]; + for( size_t i = 0; i < len; ++i) + { + values[i] = (char)i; + } + //const char values[] = {0, 1, 2}; + //const size_t len = sizeof(values) / sizeof(*values); + const size_t outlen = 16 * len / 12; + char * output = new char[outlen]; + bool b = gdcm::Unpacker12Bits::Unpack(output, values, len); + if( b ) + { + std::set out; + short * output_s = (short*)output; + for( size_t i = 0; i < outlen / 2; ++i ) + { + const short &v = output_s[i]; + // There is no way we can have values greater than a 12bits integer: + if( v >= 4096 || v < 0 ) + { + std::cerr << "Too big:" << v << std::endl; + res = 1; + } + // no duplicate possible + std::pair< std::set::iterator, bool> p = out.insert( v ); + if( p.second == false ) + { + std::cerr << "duplicate:" << v << std::endl; + res = 1; + } + //std::cout << v << std::endl; + } + } + else + { + res = 1; + } + delete[] values; + delete[] output; +} + +{ + const unsigned char values[] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }; + const size_t len = sizeof(values) / sizeof(*values); + const size_t outlen = 16 * len / 12; + char * output = new char[outlen]; + bool b = gdcm::Unpacker12Bits::Unpack(output, (char*)values, len); + if (!b) res = 1; + if( b ) + { + unsigned short * output_s = (unsigned short*)output; + const unsigned short outputvalues[] = { 0x301, 0x452, 0x967, 0xab8 }; + const size_t outputlen = sizeof(outputvalues) / sizeof(*outputvalues); + assert( outlen / 2 == outputlen ); + for(size_t i = 0; i < outputlen; ++i) + { + if( outputvalues[i] != output_s[i] ) + { + ++res; + } + } + } + delete[] output; +} + +{ + const unsigned short input[] = { 0x301, 0x452, 0x967, 0xab8 }; + unsigned char values[6] = {}; + const unsigned char ref[] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }; + bool b = gdcm::Unpacker12Bits::Pack((char*)values, (char*)input, 8); // 4 * sizeof(us) == 8 + if(!b) + { + return 1; + } + for(size_t i = 0; i < 6; ++i) + { + if( values[i] != ref[i] ) + { + assert(0); + ++res; + } + } +} +{ + //struct uint12_t { unsigned short v:12; }; + std::vector v; + for(uint16_t val = 0; val < 4096; ++val) + { + v.push_back( val ); + } + assert( v.size() == 4096 ); + assert( v[0] == 0 ); + const size_t outsize = 4096 / 2 * 3; + unsigned char outvalues[outsize] = {}; + gdcm::Unpacker12Bits::Pack( (char*)outvalues, (char*)&v[0], 4096 * sizeof(unsigned short) ); + unsigned short outvalues2[4096] = {}; + gdcm::Unpacker12Bits::Unpack( (char*)outvalues2, (char*)outvalues, outsize); + + for(uint16_t val = 0; val < 4096; ++val) + { + if( v[val] != outvalues2[val] ) + { + ++res; + } + } + +} + + return res; +} diff --git a/gdcm/Testing/Source/Common/Cxx/TestVersion.cxx b/gdcm/Testing/Source/Common/Cxx/TestVersion.cxx new file mode 100644 index 0000000..0a99363 --- /dev/null +++ b/gdcm/Testing/Source/Common/Cxx/TestVersion.cxx @@ -0,0 +1,32 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmVersion.h" + +int TestVersion(int, char *[]) +{ + // The following statements just test whether those functions are callable: + const char *version = gdcm::Version::GetVersion(); + (void)version; + const int majorVersion = gdcm::Version::GetMajorVersion(); + (void)majorVersion; + const int minorVersion = gdcm::Version::GetMinorVersion(); + (void)minorVersion; + const int buildVersion = gdcm::Version::GetBuildVersion(); + (void)buildVersion; + + gdcm::Version v; + v.Print( std::cout ); + + return 0; +} diff --git a/gdcm/Testing/Source/Common/Python/CMakeLists.txt b/gdcm/Testing/Source/Common/Python/CMakeLists.txt new file mode 100644 index 0000000..11cf827 --- /dev/null +++ b/gdcm/Testing/Source/Common/Python/CMakeLists.txt @@ -0,0 +1,12 @@ +# Define the tests for gdcm-python +# gdcm-python +set(GDCM_PYTHON_TEST_SRCS + TestTesting + TestDirectory + ) + + +# Loop over files and create executables +foreach(name ${GDCM_PYTHON_TEST_SRCS}) + ADD_PYTHON_TEST(${name}Python ${name}.py ${GDCM_DATA_ROOT}/test.acr) +endforeach() diff --git a/gdcm/Testing/Source/Common/Python/TestDirectory.py b/gdcm/Testing/Source/Common/Python/TestDirectory.py new file mode 100644 index 0000000..ac15e31 --- /dev/null +++ b/gdcm/Testing/Source/Common/Python/TestDirectory.py @@ -0,0 +1,37 @@ +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +import gdcm +import os,sys + +dir = gdcm.Directory() +t = gdcm.Testing() +dataroot = t.GetDataRoot() + +system = gdcm.System() +if not system.FileIsDirectory(dataroot): + sys.exit(1) + +nfiles = dir.Load(dataroot) + +if nfiles == 0: + sys.exit(1) + +#print dir.GetFilenames() + +for file in dir.GetFilenames(): + print(file) + +# Test succeed ? +#sys.exit(sucess != 1) diff --git a/gdcm/Testing/Source/Common/Python/TestTesting.py b/gdcm/Testing/Source/Common/Python/TestTesting.py new file mode 100644 index 0000000..2a10150 --- /dev/null +++ b/gdcm/Testing/Source/Common/Python/TestTesting.py @@ -0,0 +1,29 @@ +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +import gdcm +import os,sys + +t = gdcm.Testing() +nfiles = t.GetNumberOfFileNames() +print(nfiles) +for i in range(0,nfiles): + print(t.GetFileName(i)) + +print(t.GetFileName(10000)) + +print(t.GetDataRoot()) + +# Test succeed ? +#sys.exit(sucess != 1) diff --git a/gdcm/Testing/Source/Data/CMakeLists.txt b/gdcm/Testing/Source/Data/CMakeLists.txt new file mode 100644 index 0000000..b2a3b6e --- /dev/null +++ b/gdcm/Testing/Source/Data/CMakeLists.txt @@ -0,0 +1,127 @@ +#----------------------------------------------------------------------------- + +# We need to test the reading of all dicom images in the gdcmData directory +# First parse this directory and extract all images + +set(GDCM_DATA_IMAGE_FILENAMES_GLOB_EXPR + "${GDCM_DATA_ROOT}/*.acr" + "${GDCM_DATA_ROOT}/*.nema" + "${GDCM_DATA_ROOT}/*.dcm" +) + +set(GDCM_DATA_DICOMDIR_FILENAMES_GLOB_EXPR + # Those files do not have any extension, special regex: + "${GDCM_DATA_ROOT}/dicomdir*" +) + +# Case sensitive system: +if(UNIX) + set(GDCM_DATA_IMAGE_FILENAMES_GLOB_EXPR + ${GDCM_DATA_IMAGE_FILENAMES_GLOB_EXPR} + "${GDCM_DATA_ROOT}/*.DCM" + ) + set(GDCM_DATA_DICOMDIR_FILENAMES_GLOB_EXPR + ${GDCM_DATA_DICOMDIR_FILENAMES_GLOB_EXPR} + "${GDCM_DATA_ROOT}/DICOMDIR*" + ) +endif() + +# GLOB expression ! +file(GLOB GDCM_DATA_IMAGE_FILENAMES_GLOB + ${GDCM_DATA_IMAGE_FILENAMES_GLOB_EXPR} + ) + +# Same for DICOMDIR: +file(GLOB GDCM_DATA_DICOMDIR_FILENAMES_GLOB + ${GDCM_DATA_DICOMDIR_FILENAMES_GLOB_EXPR} + ) + +set(GDCM_DATA_FILENAMES_GLOB + ${GDCM_DATA_IMAGE_FILENAMES_GLOB} + ${GDCM_DATA_DICOMDIR_FILENAMES_GLOB} +) + +# List of images that are technically difficult to read +# Hopefully we will soon be able to read them +set(BLACK_LIST_READER +# grrrrrr do not handle swapping correctly (implicit dataset are such a pain) + LIBIDO-16-ACR_NEMA-Volume.dcm +# Papyrus: + PET-cardio-Multiframe-Papyrus.dcm +# No way to read this image: + ELSCINT1_LOSSLESS_RICE.dcm +# Toshiba US Private Data Storage 1.2.392.200036.9116.7.8.1.1.1 + TOSHIBA_MDW_HEADER.dcm +# TODO, nasty: + PhilipsLosslessRice.dcm + +# This file is incorrect + IM-0001-0066.dcm +# Problem with RLE + SIEMENS_GBS_III-16-ACR_NEMA_1.acr + SIEMENS_GBS_III-16-ACR_NEMA_1-ULis2Bytes.dcm +# TestImageChangeTransferSyntax1 + MR-MONO2-12-angio-an1.acr +# Openjpeg / Part 2: + lena512_rot90.j2k.dcm +) +if(NOT GDCM_USE_PVRG) + set(BLACK_LIST_READER + # The following should really fails according to JPEG spec, IJG is failing and even when forcing + # decompression using IJG output is different from PVRG... + # Apparently pvrg likes it this way... + # PHILIPS_Gyroscan-12-Jpeg_Extended_Process_2_4.dcm + ${BLACK_LIST_READER} + PHILIPS_Gyroscan-12-Jpeg_Extended_Process_2_4.dcm + ) +endif() +if(GDCM_WORDS_BIGENDIAN) + set(BLACK_LIST_READER + ${BLACK_LIST_READER} + MR_Philips_Intera_PrivateSequenceExplicitVR_in_SQ_2001_e05f_item_wrong_lgt_use_NOSHADOWSEQ.dcm + MR_Philips_Intera_SwitchIndianess_noLgtSQItem_in_trueLgtSeq.dcm + PHILIPS_Intera-16-MONO2-Uncompress.dcm + SIEMENS_MAGNETOM-12-MONO2-GDCM12-VRUN.dcm + PICKER-16-MONO2-No_DicomV3_Preamble.dcm + ) +endif() + +if(NOT GDCM_SUPPORT_BROKEN_IMPLEMENTATION) + set(BLACK_LIST_READER + ${BLACK_LIST_READER} + GE_GENESIS-16-MONO2-WrongLengthItem.dcm # can't read odd length + PHILIPS_GDCM12xBug2.dcm # odd length + KODAK-12-MONO1-Odd_Terminated_Sequence.dcmq # odd length + PrivateGEImplicitVRBigEndianTransferSyntax16Bits.dcm # odd length + PHILIPS_Gyroscan-8-MONO2-Odd_Sequence.dcm # odd length + BugGDCM2_UndefItemWrongVL.dcm # odd length + THERALYS-12-MONO2-Uncompressed-Even_Length_Tag.dcm + CT-SIEMENS-MissingPixelDataInIconSQ.dcm # odd length + 00191113.dcm + MR_Philips_Intera_PrivateSequenceImplicitVR.dcm + PICKER-16-MONO2-Nested_icon.dcm + PHILIPS_GDCM12xBug.dcm # odd length + MR_Philips-Intera_BreaksNOSHADOW.dcm + NM_Kakadu44_SOTmarkerincons.dcm + MARCONI_MxTWin-12-MONO2-JpegLossless-ZeroLengthSQ.dcm + ) +endif() + +set(GDCM_DATA_FILENAMES) +set(GDCM_BLACK_LIST_READER_DATA_FILENAMES) +foreach(filename ${GDCM_DATA_FILENAMES_GLOB}) + get_filename_component(filename_name ${filename} NAME) + string(REGEX MATCH ${filename_name} bad_dicom ${BLACK_LIST_READER}) + if(NOT bad_dicom) + set(GDCM_DATA_FILENAMES "${GDCM_DATA_FILENAMES}\n\"${filename}\",") + else() + set(GDCM_BLACK_LIST_READER_DATA_FILENAMES "${GDCM_BLACK_LIST_READER_DATA_FILENAMES}\n\"${filename}\",") + endif() +endforeach() + + +# Populate GDCM_DATA_FILENAMES: +configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/gdcmDataFileNames.cxx.in" + "${CMAKE_CURRENT_BINARY_DIR}/gdcmDataFileNames.cxx" + ) diff --git a/gdcm/Testing/Source/Data/NativeDICOM.rnc b/gdcm/Testing/Source/Data/NativeDICOM.rnc new file mode 100644 index 0000000..61816db --- /dev/null +++ b/gdcm/Testing/Source/Data/NativeDICOM.rnc @@ -0,0 +1,60 @@ +# PS 3.19-2011 +# A.1.6 Schema +# The Normative version of the XML Schema for the Native DICOM Model follows: +default namespace="http://dicom.nema.org/PS3.19/models/NativeDICOM" + +# This schema was created as an intermediary, a means of describing +# native binary encoded DICOM objects as XML Infosets, thus allowing +# one to manipulate binary DICOM objects using familiar XML tools. +# As such, the schema is designed to facilitate a simple, mechanical, +# bi-directional translation between binary encoded DICOM and XML-like +# constructs without constraints, and to simplify identifying portions +# of a DICOM object using XPath statements. +# +# Since this schema has minimal type checking, it is neither intended +# to be used for any operation that involves hand coding, nor to +# describe a definitive, fully validating encoding of DICOM concepts +# into XML, as what one might use, for example, in a robust XML +# database system or in XML-based forms, though it may be used +# as a means for translating binary DICOM Objects into such a form +# (e.g. through an XSLT script). + +start = element NativeDicomModel { DicomDataSet } + +# A DICOM Data Set is as defined in PS3.5. It does not appear +# as an XML Element, since it does not appear in the binary encoded +# DICOM objects. It exists here merely as a documentation aid. +DicomDataSet = DicomAttribute* + +DicomAttribute = element DicomAttribute { + Tag, VR, Keyword?, PrivateCreator?, + ( BulkData | Value+ | Item+ | PersonName+ )? +} +BulkData = element BulkData{ UUID } +Value = element Value { Number, xsd:string } +Item = element Item { Number, DicomDataSet } +PersonName = element PersonName { + Number, + element SingleByte { NameComponents }?, + element Ideographic { NameComponents }?, + element Phonetic { NameComponents }? +} + +NameComponents = + element FamilyName {xsd:string}?, + element GivenName {xsd:string}?, + element MiddleName {xsd:string}?, + element NamePrefix {xsd:string}?, + element NameSuffix {xsd:string}? + +# keyword is the attribute tag from PS3.6 +# (derived from the DICOM Attribute's name) +Keyword = attribute keyword { xsd:token } +# canonical XML definition of Hex, with lowercase letters disallowed +Tag = attribute tag { xsd:string{ minLength="8" maxLength="8" pattern="[0-9A-F]{8}" } } +VR = attribute vr { "AE" | "AS" | "AT" | "CS" | "DA" | "DS" | "DT" | "FL" | "FD" + | "IS" | "LO" | "LT" | "OB" | "OF" | "OW" | "PN" | "SH" | "SL" + | "SQ" | "SS" | "ST" | "TM" | "UI" | "UL" | "UN" | "US" | "UT" } +PrivateCreator = attribute privateCreator{ xsd:string } +UUID = attribute uuid { xsd:string } +Number = attribute number { xsd:positiveInteger } diff --git a/gdcm/Testing/Source/Data/NativeDICOM.rng b/gdcm/Testing/Source/Data/NativeDICOM.rng new file mode 100644 index 0000000..860c990 --- /dev/null +++ b/gdcm/Testing/Source/Data/NativeDICOM.rng @@ -0,0 +1,197 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 8 + 8 + [0-9A-F]{8} + + + + + + + AE + AS + AT + CS + DA + DS + DT + FL + FD + IS + LO + LT + OB + OF + OW + PN + SH + SL + SQ + SS + ST + TM + UI + UL + UN + US + UT + + + + + + + + + + + + + + + + + + + diff --git a/gdcm/Testing/Source/Data/QIDO-RS_examplesup166.json b/gdcm/Testing/Source/Data/QIDO-RS_examplesup166.json new file mode 100644 index 0000000..a63daad --- /dev/null +++ b/gdcm/Testing/Source/Data/QIDO-RS_examplesup166.json @@ -0,0 +1,289 @@ +// The following example is a QIDO-RS SearchForStudies response consisting +// of two matching studies, corresponding to the example QIDO-RS request: +// GET http://qido.nema.org/studies?PatientID=12345&includefield=all&limit=2 +[ +{ // Result 1 + "SpecificCharacterSet": { + "Tag": "00080005", + "VR": "CS", + "Value": [ "ISO_IR192" ] + }, + "StudyDate": { + "Tag": "00080020", + "VR": "DT", + "Value": [ "20130409" ] + }, + "StudyTime": { + "Tag": "00080030", + "VR": "TM", + "Value": [ "131600.0000" ] + }, + "AccessionNumber": { + "Tag": "00080050", + "VR": "SH", + "Value": [ "11235813" ] + }, + "InstanceAvailability": { + "Tag": "00080056", + "VR": "CS", + "Value": [ "ONLINE" ] + }, + "ModalitiesInStudy": { + "Tag": "00080061", + "VR": "CS", + "Value": [ + "CT", + "PET" + ] + }, + "ReferringPhysiciansName": { + "Tag": "00080090", + "VR": "PN", + "PersonName": [ + { + "SingleByte": "^Bob^^Dr." + } + ] + }, + "00090010": { + "Tag": "00090010", + "VR": "LO", + "Value": [ "Vendor A" ] + }, + "00091002": { + "Tag": "00091002", + "VR": "UN", + "PrivateCreator": "Vendor A", + "Value": [ "z0x9c8v7" ] + }, + "PatientName": { + "Tag": "00100010", + "VR": "PN", + "PersonName": [ + { + "SingleByte": "Wang^XiaoDong", + "Ideographic": "王^å°æ±" + } + ] + }, + "PatientID": { + "Tag": "00100020", + "VR": "LO", + "Value": [ "12345" ] + }, + "IssuerOfPatientID": { + "Tag": "00100021", + "VR": "LO", + "Value": [ "Hospital A" ] + }, + "PatientsBirthDate": { + "Tag": "00100030", + "VR": "DT", + "Value": [ "19670701" ] + }, + "PatientsSex": { + "Tag": "00100040", + "VR": "CS", + "Value": [ "M" ] + }, + "OtherPatientIDsSequence": { + "Tag": "00101002", + "VR": "SQ", + "Sequence": [ + { + "PatientID": { + "Tag": "00100020", + "VR": "LO", + "Value": [ "54321" ] + }, + "IssuerOfPatientID": { + "Tag": "00100021", + "VR": "LO", + "Value": [ "Hospital B" ] + } + }, + { + "PatientID": { + "Tag": "00100020", + "VR": "LO", + "Value": [ "24680" ] + }, + "IssuerOfPatientID": { + "Tag": "00100021", + "VR": "LO", + "Value": [ "Hospital C" ] + } + } + ] + }, + "StudyID": { + "Tag": "00200010", + "VR": "SH", + "Value": [ "11235813" ] + }, + "StudyInstanceUID": { + "Tag": "0020000D", + "VR": "UI", + "Value": [ + "1.2.392.200036.9116.2.2.2.1762893313.1029997326.945873" ] + }, + "NumberOfStudyRelatedSeries": { + "Tag": "00201206", + "VR": "IS", + "Value": [ "4" ] + }, + "NumberOfStudyRelatedInstances": { + "Tag": "00201208", + "VR": "IS", + "Value": [ "942" ] + }, + "RetrieveURL": { + "Tag": "00081190", + "VR": "UT", + "Value": [ + "http://wado.nema.org/studies/1.2.392.200036.9116.2.2.2.1762893313.1029997326.945873" ] + } +}, +{ // Result 2 + "SpecificCharacterSet": { + "Tag": "00080005", + "VR": "CS", + "Value": [ "ISO_IR192" ] + }, + "StudyDate": { + "Tag": "00080020", + "VR": "DT", + "Value": [ "20130309" ] + }, + "StudyTime": { + "Tag": "00080030", + "VR": "TM", + "Value": [ "111900.0000" ] + }, + "AccessionNumber": { + "Tag": "00080050", + "VR": "SH", + "Value": [ "11235821" ] + }, + "InstanceAvailability": { + "Tag": "00080056", + "VR": "CS", + "Value": [ "ONLINE" ] + }, + "ModalitiesInStudy": { + "Tag": "00080061", + "VR": "CS", + "Value": [ + "CT", + "PET" + ] + }, + "ReferringPhysiciansName": { + "Tag": "00080090", + "VR": "PN", + "PersonName": [ + { + "SingleByte": "^Bob^^Dr." + } + ] + }, + "00090010": { + "Tag": "00090010", + "VR": "LO", + "Value": [ "Vendor A" ] + }, + "00091002": { + "Tag": "00091002", + "VR": "UN", + "PrivateCreator": "Modality Vendor A", + "Value": [ "z0x9c8v7" ] + }, + "PatientName": { + "Tag": "00100010", + "VR": "PN", + "PersonName": [ + { + "SingleByte": "Wang^XiaoDong", + "Ideographic": "王^å°æ±" + } + ] + }, + "PatientID": { + "Tag": "00100020", + "VR": "LO", + "Value": [ "12345" ] + }, + "IssuerOfPatientID": { + "Tag": "00100021", + "VR": "LO", + "Value": [ "Hospital A" ] + }, + "PatientsBirthDate": { + "Tag": "00100030", + "VR": "DT", + "Value": [ "19670701" ] + }, + "PatientsSex": { + "Tag": "00100040", + "VR": "CS", + "Value": [ "M" ] + }, + "OtherPatientIDsSequence": { + "Tag": "00101002", + "VR": "SQ", + "Sequence": [ + { + "PatientID": { + "Tag": "00100020", + "VR": "LO", + "Value": [ "54321" ] + }, + "IssuerOfPatientID": { + "Tag": "00100021", + "VR": "LO", + "Value": [ "Hospital B" ] + } + }, + { + "PatientID": { + "Tag": "00100020", + "VR": "LO", + "Value": [ "24680" ] + }, + "IssuerOfPatientID": { + "Tag": "00100021", + "VR": "LO", + "Value": [ "Hospital C" ] + } + } + ] + }, + "StudyID": { + "Tag": "00200010", + "VR": "SH", + "Value": [ "11235821" ] + }, + "StudyInstanceUID": { + "Tag": "0020000D", + "VR": "UI", + "Value": [ + "1.2.392.200036.9116.2.2.2.2162893313.1029997326.945876" ] + }, + "NumberOfStudyRelatedSeries": { + "Tag": "00201206", + "VR": "IS", + "Value": [ "5" ] + }, + "NumberOfStudyRelatedInstances": { + "Tag": "00201208", + "VR": "IS", + "Value": [ "1123" ] + }, + "RetrieveURL": { + "Tag": "00081190", + "VR": "UT", + "Value": [ + "http://wado.nema.org/studies/1.2.392.200036.9116.2.2.2.2162893313.1029997326.945876" ] + } +} +] diff --git a/gdcm/Testing/Source/Data/certificate.pem b/gdcm/Testing/Source/Data/certificate.pem new file mode 100644 index 0000000..f6020e3 --- /dev/null +++ b/gdcm/Testing/Source/Data/certificate.pem @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDtTCCAp2gAwIBAgIJAKyWbYh4elG0MA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQwHhcNMDkwNDI3MDk1NzE1WhcNMTAwNDI3MDk1NzE1WjBF +MQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50 +ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEA4k5GEgO9mI5K2UuywuGxcO4xJdygQlpvL2IS9XEbXOWBEwJZx1tccfzC +a929DCijlJE6/f5KBzDNPdLpPt3eyUKB3n7mOos7ATWEFCZgE7RWGRBhIfN2R9LD +kLT2eaUhXDzsk7L1qmKPP9nSdAXoUB6sj0EmHrQQWIPEZwGcPcvMUhcUpjD/hnmC +X6DAWHVCvE7vhbHntNYFwu1Bmau5ZY6Ywk5lQ/ZTfEYcRD1ZmUB2Wkzv4InvRc1z +YbTBpL/Lkft1B9/A7+LzJJRHoNvHaMN5pRF2qFyZW3sb+bh8z8SC0oJNzIbrWZvW +M9TEnQ8P+GCw4y68juSvlcLcBsoxCQIDAQABo4GnMIGkMB0GA1UdDgQWBBTNWfHq +ZOUwrkeH39jLz0qgBV1LaDB1BgNVHSMEbjBsgBTNWfHqZOUwrkeH39jLz0qgBV1L +aKFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNV +BAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAKyWbYh4elG0MAwGA1UdEwQF +MAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAMvT7rwSoHwOUMr1ZnjCYccuBsWND1Vt +JvMzELX/IUs2f0BbDVZeyn1NC7VyoAOfvgJwLccK6v49p2J/SbBaAiixlgGAi670 +V7VkwMaDKIAR/AEIbORwcRoogHYSft4to1kNcPmYOhiny2VFWSp3Fmoc/egU3Cbo +pVH/ixjcCT7q/6MIuklnvULGSOajtE/+fz+KzlX8nZyD22oMk/TtxVsys8F0qWtZ +HsGoXUY15xg+HjHcSCOBeU7pAglCyRCLyO3mhAgfE3o4T5HBp4opjfRGDaVd+uPj +XRjzAZgfgLQAmiUixyCzzG8wDgpFVdoOcWQ9RcNnR9XgIw5Omas75so= +-----END CERTIFICATE----- diff --git a/gdcm/Testing/Source/Data/encrypted_text b/gdcm/Testing/Source/Data/encrypted_text new file mode 100644 index 0000000000000000000000000000000000000000..7bceebef2b0862ba7efbf14d3288a89bc9f9d1af GIT binary patch literal 473 zcmXqLV!X=6snzDu_MMlJoq0hM<1vFK#zRbu42DgNc|c|skZBNP;A+Tiz{$oO%EBhh zYpRQcD!VGgHztONtc&N-7n6 zN>Z3O8P-h8?Wm{<++x5Bx0aESm4T&+k-=2ymVSNhjv&U@TpfZ zyP3bV?bWgT$}85Z{HH00-l~`SU1)#i&717;CJ>h2ayFQmWJDJ@>+9p`&na!2@EN_YHZ$3Ht>cA2|J^K2pb0^TA0~c zIA$BaSav-&nnoPDTkeDk?S HY^OZ{$8X4w literal 0 HcmV?d00001 diff --git a/gdcm/Testing/Source/Data/gdcmDataFileNames.cxx.in b/gdcm/Testing/Source/Data/gdcmDataFileNames.cxx.in new file mode 100644 index 0000000..d4f2411 --- /dev/null +++ b/gdcm/Testing/Source/Data/gdcmDataFileNames.cxx.in @@ -0,0 +1,35 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* Hardcode the path to GDCM_DATA_ROOT */ +static const char GDCM_DATA_ROOT[] = "@GDCM_DATA_ROOT@"; + +static const char GDCM_DATA_EXTRA_ROOT[] = "@GDCM_DATA_EXTRA_ROOT@"; + +static const char GDCM_PIXEL_SPACING_DATA_ROOT[] = "@GDCM_PIXEL_SPACING_DATA_ROOT@"; + +/* Hardcode the path to GDCM_TEMP_DIRECTORY */ +static const char GDCM_TEMP_DIRECTORY[] = "@GDCM_TEMP_DIRECTORY@"; + + +static const char * const gdcmDataFileNames[] = { + @GDCM_DATA_FILENAMES@ +0 }; + +static const char * const gdcmBlackListReaderDataFileNames[] = { + @GDCM_BLACK_LIST_READER_DATA_FILENAMES@ +0 }; + +//const char * const gdcmBlackListWriterDataImages[] = { +// @GDCM_BLACK_LIST_WRITER_DATA_IMAGES@ +//0 }; diff --git a/gdcm/Testing/Source/Data/gdcmMD5DataBrokenImages.cxx b/gdcm/Testing/Source/Data/gdcmMD5DataBrokenImages.cxx new file mode 100644 index 0000000..bad37f5 --- /dev/null +++ b/gdcm/Testing/Source/Data/gdcmMD5DataBrokenImages.cxx @@ -0,0 +1,98 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http:/gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + + +/* + * See TestWriter + */ + +// This is the full md5 of the rewriten file. The file was manually check +// and is (should be) exactly what should have been written in the first place +// test was done using dcmtk 3.5.4 / dicom3tools +static const char * const gdcmMD5DataBrokenImages[][2] = { +// file has some garbage at the end, replace with a trailing end item. +{ "e8ed75f5e13cc20e96ee716bcc78351b" , "gdcm-JPEG-LossLess3a.dcm" }, // size match + +// files are little endian implicit meta data header: +{ "8cb29ba0173c66e7adb4c54c6b0a5896" , "GE_DLX-8-MONO2-PrivateSyntax.dcm" }, +{ "ed93b34819bf2acbacefb510476e8d4a" , "PICKER-16-MONO2-No_DicomV3_Preamble.dcm" }, + +// stupidest file ever, 0x6 was sent in place of 0x4 ... sigh +{ "c8cce480eac80770a3c6e456c7d8d66f" , "SIEMENS_MAGNETOM-12-MONO2-Uncompressed.dcm" }, // size match + +// big endian / little endian nightmare from PMS +{ "df0e01aae299317db1719e4de72b8937" , "MR_Philips_Intera_SwitchIndianess_noLgtSQItem_in_trueLgtSeq.dcm" }, // size match and CheckbigEndian match => ok ! +{ "df632a3b5ca38340faa612a23b907ac4" , "PHILIPS_Intera-16-MONO2-Uncompress.dcm" }, // size match and CheckbigEndian match => ok ! +{ "6bf002815fad665392acab24f09caa5e" , "MR_Philips_Intera_PrivateSequenceExplicitVR_in_SQ_2001_e05f_item_wrong_lgt_use_NOSHADOWSEQ.dcm" }, // size match and CheckbigEndian match => ok ! + +// little endian implicit meta header + a couple of attribute sent with correct, but odd length: +{ "e1b2956f781685fc9e46e0da26b8a0fd" , "THERALYS-12-MONO2-Uncompressed-Even_Length_Tag.dcm" }, + +// name says it all. dcmtk does not support this. dicom3tools confirmed that dataset is compatible +{ "66a75503221ef32b0236cf9f78e169ff" , "ExplicitVRforPublicElementsImplicitVRforShadowElements.dcm" }, // size mismatch + +// item length are supposed to be 0, not FFFF... +{ "3cc629fa470efb114a14ca3909117eb8" , "SIEMENS-MR-RGB-16Bits.dcm" }, // size match +{ "0fb0cb12f2b038bbfe1014bbf2935026" , "MR-SIEMENS-DICOM-WithOverlays-extracted-overlays.dcm" }, // size match + + +// this is a private syntax from ge with a little endian dataset and big endian pixel data +// FMI is little endian implicit, it also contained a couple of odd length attributes. +// using dcmtk it looks like file are identical +{ "2d23a8d55425c88bdd5e90f866a11607" , "PrivateGEImplicitVRBigEndianTransferSyntax16Bits.dcm" }, // size mismatch + +// couple of weird stuff going on... dcdump confirmed dataset is identical in both file +{ "34abc36682a6e6ba22d7295931b39d85" , "DMCPACS_ExplicitImplicit_BogusIOP.dcm" }, // size mismatch + +// weird stuff going on. dcdump confirmed dataset are identical. dcmdump can read output, and size match. +{ "82fda19e1f2046a289fe1307b70510af" , "gdcm-MR-PHILIPS-16-Multi-Seq.dcm" }, + +// yet another stupidest ever bug, 0xd was replaced with 0xa ... don't ask +{ "a047110a3935dc0fdda24d3b9e4769af" , "GE_GENESIS-16-MONO2-WrongLengthItem.dcm" }, // size match + +// empty 16bits after VR should be 0 not garbage... +{ "6cded0f160edfab809cddfce2d562671" , "JDDICOM_Sample2.dcm" }, // size match + +// simple issue, last fragment is odd, simply need to pad (easy, should be handle by most implementation) +{ "6234a50361f02cb9a739755d63cdd673" , "00191113.dcm" }, // size mismatch (obviously) +{ "28f9d4114b0699630a77d027910e5e41" , "MARCONI_MxTWin-12-MONO2-JpegLossless-ZeroLengthSQ.dcm" }, + +// serious bug from gdcm 1.2.0, where VR=UN would be written on 16bits length sigh... no toolkit will ever be able to deal with that thing (and should not anyway) +{ "50752239f24669697897c4b6542bc161" , "SIEMENS_MAGNETOM-12-MONO2-GDCM12-VRUN.dcm" }, + +// unordered dataset +{ "f221e76c6f0758877aa3cf13632480f4" , "dicomdir_Pms_WithVisit_WithPrivate_WithStudyComponents" }, // size match + +// frankenstein-type dicom file: +// 1. Implicit encoding is used any time it is not known (most of the time, private element) +// 2. > (0x2001,0x1068) SQ ? VR= VL=<0xffffffff> is sent twice (don't ask), second entry cannot be stored... +// dcdump kindda show file are somewhat compatible. +{ "69ca7a4300967cf2841da34d7904c6c4" , "TheralysGDCM120Bug.dcm" }, // size mismatch + +// GDCM 1.0 generated file. At that time, VL for a start/end item delimitor would be set to 0xFFF... instead of 0x0 +// dcmtk / dicom3tools do not seems to care about the value stored for VL, so does GDCM (now). +// As a side note the FMI was set to Little Endian Implicit ... +{ "ddf83cd708e58021a633588927d55ab8" , "BugGDCM2_UndefItemWrongVL.dcm" }, // size mismatch + +{ "cb43a6ad60b8eacf718687b82126f625" , "NM_Kakadu44_SOTmarkerincons.dcm" }, // item size mismatch + +// Item length are bogus (explicit length) +{ "1225ea0a03b93393f70c73be35e2619d" , "PhilipsInteraSeqTermInvLen.dcm" }, + +// Two Items in a single Frame JPEG compressed DICOM image: +{ "cd00658f54dbd2d2a9d02d64c6f6497e" , "JPEGInvalidSecondFrag.dcm" }, + +{ 0 ,0 } +}; + diff --git a/gdcm/Testing/Source/Data/gdcmMD5DataImages.cxx b/gdcm/Testing/Source/Data/gdcmMD5DataImages.cxx new file mode 100644 index 0000000..0e4299d --- /dev/null +++ b/gdcm/Testing/Source/Data/gdcmMD5DataImages.cxx @@ -0,0 +1,690 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +// See tst2md5 in GDCM/Utilities/md5 +// +// Another way to do it is: +// +// dcmdrle ACUSON-24-YBR_FULL-RLE.dcm bla.dcm +// gdcmraw -i bla.dcm -o bla.raw +// md5sum bla.raw +// So this md5 checksum should match the one in dcmtk...hopefully :) +// +static const char * const gdcmMD5DataImages[][2] = { +/* gdcm 512 512 4 8 1 */ +{ "bfff320d1b058e91b4819aa4560c16f7" , "00191113.dcm" }, +/* gdcm 256 256 1 16 1 */ +{ "d594a5e2fde12f32b6633ca859b4d4a6" , "012345.002.050.dcm" }, +/* gdcm 512 512 1 16 1 */ +{ "c68cf1c4ae59903930e334498389ea88" , "05115014-mr-siemens-avanto-syngo-with-palette-icone.dcm" }, +/* gdcm 448 336 1 16 1 */ +{ "a9d455ca171294fe56d29bf714f4f845" , "05119865-mr-siemens-avanto-syngo.dcm" }, +/* gdcm 192 192 1 16 1 */ +{ "9acdd9969f5d0584ddd67e994f00b7c7" , "05148044-mr-siemens-avanto-syngo.dcm" }, +/* gdcm 512 512 1 16 1 */ +{ "c3541091a3794753065022f4defc4343" , "3E768EB7.dcm" }, +/* gdcm 768 576 40 8 3 */ +{ "6a796be399aefebc1479e924f6051d69" , "ACUSON-24-YBR_FULL_422-Jpeg_Baseline_1.dcm" }, +/* gdcm 384 288 1 8 3 */ +//{ "2a922d5c606354612bfdbece1421d863" , "ACUSON-24-YBR_FULL-RLE-b.dcm" }, +//{ "22b32f23beb118f7b64c13bf04bc2809" , "ACUSON-24-YBR_FULL-RLE-b.dcm" }, +{ "2d7a28cae6c3b3183284d1b4ae08307f" , "ACUSON-24-YBR_FULL-RLE-b.dcm" }, +/* gdcm 768 576 1 8 3 */ +//{ "f9bb8a37acabdf8b0cfa4fd1b471e6aa" , "ACUSON-24-YBR_FULL-RLE.dcm" }, +//{ "435c66f7e113d11d226d500294aae865" , "ACUSON-24-YBR_FULL-RLE.dcm" }, +{ "429f31f0b70bd515b3feeda5dea5eac0" , "ACUSON-24-YBR_FULL-RLE.dcm" }, +/* gdcm 768 576 25 8 3 */ +{ "e36350b0711fd34eb86c386164554679" , "ACUSON-8-YBR_FULL-JPEG-TrailingInfo.dcm" }, +/* gdcm 608 420 1 8 1 */ +{ "7d8858e3419392b7f39a99fdc8028064" , "ALOKA_SSD-8-MONO2-RLE-SQ.dcm" }, +/* gdcm 440 440 1 16 1 */ +//{ "8acaa88edcc2c29d3be3ee373fbaed5e" , "CR-MONO1-10-chest.dcm" }, +{ "1f772b4849727a9750931b60d920436f" , "CR-MONO1-10-chest.dcm" }, +/* gdcm 512 512 1 16 1 */ +{ "8c8b9d99ad12fb4d231182d4fc14c042" , "CT_16b_signed-UsedBits13.dcm" }, +/* gdcm 512 512 1 16 1 */ +{ "160c0b4432cfab8d36531b5a3693ff3e" , "CT-MONO2-12-lomb-an2.acr" }, +/* gdcm 512 512 1 16 1 */ +{ "90cca03ada67c6a1fcb48cfcc2b52eeb" , "CT-MONO2-16-ankle.dcm" }, +/* gdcm 512 512 1 16 1 */ +{ "a6cf43e05087b6c31644c1d360701ff2" , "CT-MONO2-16-brain.dcm" }, +/* gdcm 512 400 1 16 1 */ +{ "78bb9ea4b746ff2aa5559be567f95030" , "CT-MONO2-16-chest.dcm" }, +/* gdcm 512 512 1 16 1 */ +{ "dcb3aa1defd85d93d69d445e3e9b3074" , "CT-MONO2-16-ort.dcm" }, +/* gdcm 512 512 1 8 1 */ +{ "86d3e09a5858aa3844cb3be1b822a069" , "CT-MONO2-8-abdo.dcm" }, +/* gdcm 512 614 1 16 1 */ +{ "3695d167c298646b877efccaeff92682" , "CT_Phillips_JPEG2K_Decompr_Problem.dcm" }, +/* gdcm 512 512 1 16 1 */ +{ "3372195a35448b76daee682d23502090" , "CT-SIEMENS-Icone-With-PaletteColor.dcm" }, +/* gdcm 512 512 1 16 1 */ +{ "05bbdbcc81081791f6f9f8a1ffa648c8" , "D_CLUNIE_CT1_J2KI.dcm" }, +/* gdcm 512 512 1 16 1 */ +{ "f3a3d0e739e5f4fbeddd1452b81f4d89" , "D_CLUNIE_CT1_J2KR.dcm" }, +/* gdcm 512 512 1 16 1 */ +{ "f3a3d0e739e5f4fbeddd1452b81f4d89" , "D_CLUNIE_CT1_JPLL.dcm" }, +/* gdcm 512 512 1 16 1 */ +{ "f3a3d0e739e5f4fbeddd1452b81f4d89" , "D_CLUNIE_CT1_RLE.dcm" }, +/* gdcm 512 512 1 16 1 */ +{ "2e389ddbfc1b29d55c52c97e7f2c6f9c" , "D_CLUNIE_CT2_JPLL.dcm" }, +/* gdcm 512 512 1 16 1 */ +{ "2e389ddbfc1b29d55c52c97e7f2c6f9c" , "D_CLUNIE_CT2_RLE.dcm" }, +/* gdcm 3064 4664 1 16 1 */ +{ "d9b97ad9199d429960123dcc1e74bdbc" , "D_CLUNIE_MG1_JPLL.dcm" }, +/* gdcm 3064 4664 1 16 1 */ +{ "02742062fcad004500d73d7c61b9b9e6" , "D_CLUNIE_MG1_JPLY.dcm" }, +/* gdcm 3064 4664 1 16 1 */ +{ "d9b97ad9199d429960123dcc1e74bdbc" , "D_CLUNIE_MG1_RLE.dcm" }, +/* gdcm 512 512 1 16 1 */ +{ "7b7424e6115931c371f3c94c2f5d32d9" , "D_CLUNIE_MR1_JPLL.dcm" }, +/* gdcm 512 512 1 16 1 */ +{ "2824e914ecae250a755a8a0bb1a7d4b1" , "D_CLUNIE_MR1_JPLY.dcm" }, +/* gdcm 512 512 1 16 1 */ +{ "7b7424e6115931c371f3c94c2f5d32d9" , "D_CLUNIE_MR1_RLE.dcm" }, +/* gdcm 1024 1024 1 16 1 */ +{ "a70676f0e60a58f55a5ac517ff662e7e" , "D_CLUNIE_MR2_JPLL.dcm" }, +/* gdcm 1024 1024 1 16 1 */ +{ "981510df3a57e98141c7d192b45bd93f" , "D_CLUNIE_MR2_JPLY.dcm" }, +/* gdcm 1024 1024 1 16 1 */ +{ "a70676f0e60a58f55a5ac517ff662e7e" , "D_CLUNIE_MR2_RLE.dcm" }, +/* gdcm 512 512 1 16 1 */ +{ "fb03254fad02d2330d404225c3ea9b4e" , "D_CLUNIE_MR3_JPLL.dcm" }, +/* gdcm 512 512 1 16 1 */ +{ "d7009808a147f59a9bdf58d5c5924ef2" , "D_CLUNIE_MR3_JPLY.dcm" }, +/* gdcm 512 512 1 16 1 */ +{ "fb03254fad02d2330d404225c3ea9b4e" , "D_CLUNIE_MR3_RLE.dcm" }, +/* gdcm 512 512 1 16 1 */ +{ "14fa2ae9f63742af6944edd4a61145e8" , "D_CLUNIE_MR4_JPLL.dcm" }, +/* gdcm 512 512 1 16 1 */ +{ "a33ad864b49ae7daa59cfaabdf751976" , "D_CLUNIE_MR4_JPLY.dcm" }, +/* gdcm 512 512 1 16 1 */ +{ "14fa2ae9f63742af6944edd4a61145e8" , "D_CLUNIE_MR4_RLE.dcm" }, +/* gdcm 256 1024 1 16 1 */ +{ "6b5c1eff0ef65e36b0565f96507e96fd" , "D_CLUNIE_NM1_JPLL.dcm" }, +/* gdcm 256 1024 1 16 1 */ +{ "812050a7fc53b5735f7740b60969cb6b" , "D_CLUNIE_NM1_JPLY.dcm" }, +/* gdcm 256 1024 1 16 1 */ +{ "6b5c1eff0ef65e36b0565f96507e96fd" , "D_CLUNIE_NM1_RLE.dcm" }, +/* gdcm 1841 1955 1 16 1 */ +//{ "01518af70491372814fb056d536ffb7e" , "D_CLUNIE_RG1_JPLL.dcm" }, +{ "ae141f6fb91f63769a6adc572a942fb9" , "D_CLUNIE_RG1_JPLL.dcm" }, +/* gdcm 1841 1955 1 16 1 */ +//{ "01518af70491372814fb056d536ffb7e" , "D_CLUNIE_RG1_RLE.dcm" }, +{ "ae141f6fb91f63769a6adc572a942fb9" , "D_CLUNIE_RG1_RLE.dcm" }, +/* gdcm 1760 2140 1 16 1 */ +{ "06900ee4323a91b7f5ffab8655e3c845" , "D_CLUNIE_RG2_JPLL.dcm" }, +/* gdcm 1760 2140 1 16 1 */ +{ "27fa50d4cf6b31baa669e9746ce10f63" , "D_CLUNIE_RG2_JPLY.dcm" }, +/* gdcm 1760 2140 1 16 1 */ +{ "06900ee4323a91b7f5ffab8655e3c845" , "D_CLUNIE_RG2_RLE.dcm" }, +/* gdcm 1760 1760 1 16 1 */ +//{ "6588b7b8e6e53b2276d919a053316153" , "D_CLUNIE_RG3_JPLL.dcm" }, +{ "e7c857ef7e6a2c81498297a072a0332e" , "D_CLUNIE_RG3_JPLL.dcm" }, +/* gdcm 1760 1760 1 16 1 */ +//{ "cb381c53172242404346b237bf741eb4" , "D_CLUNIE_RG3_JPLY.dcm" }, +{ "cc2968949ffbb6548288ffde7e5202e4" , "D_CLUNIE_RG3_JPLY.dcm" }, +/* gdcm 1760 1760 1 16 1 */ +//{ "6588b7b8e6e53b2276d919a053316153" , "D_CLUNIE_RG3_RLE.dcm" }, +{ "e7c857ef7e6a2c81498297a072a0332e" , "D_CLUNIE_RG3_RLE.dcm" }, +/* gdcm 2048 2487 1 16 1 */ +{ "bd0cccbfd8db465c0af306ba0f482d72" , "D_CLUNIE_SC1_JPLL.dcm" }, +/* gdcm 2048 2487 1 16 1 */ +{ "994a5abb70d3f5968672ce4970a9d4da" , "D_CLUNIE_SC1_JPLY.dcm" }, +/* gdcm 2048 2487 1 16 1 */ +{ "bd0cccbfd8db465c0af306ba0f482d72" , "D_CLUNIE_SC1_RLE.dcm" }, +/* gdcm 640 480 1 8 3 */ +{ "eb52dce9eed5ad677364baadf6144ac4" , "D_CLUNIE_US1_RLE.dcm" }, +/* gdcm 756 486 1 8 3 */ +{ "b07e34ec35ba1be62ee7d4a404cf0b90" , "D_CLUNIE_VL1_RLE.dcm" }, +/* gdcm 756 486 1 8 3 */ +{ "d215c88125359d34474a741d793c2215" , "D_CLUNIE_VL2_RLE.dcm" }, +/* gdcm 756 486 1 8 3 */ +{ "65cd359ea4c6c13ca89b906215a4b762" , "D_CLUNIE_VL3_RLE.dcm" }, +/* gdcm 2226 1868 1 8 3 */ +{ "e2fdf24d2c03dd0991b4f4e9d6e84ed6" , "D_CLUNIE_VL4_RLE.dcm" }, +/* gdcm 2670 3340 1 8 3 */ +{ "0ed86ef35d1fb443e1b63c28afe84bd0" , "D_CLUNIE_VL5_RLE.dcm" }, +/* gdcm 756 486 1 8 3 */ +{ "b825c0ed35c7c896fb707c14b534c233" , "D_CLUNIE_VL6_RLE.dcm" }, +/* gdcm 1024 1024 1 16 1 */ +{ "6111657e6b01ec7b243d63f5dec6ec48" , "D_CLUNIE_XA1_JPLL.dcm" }, +/* gdcm 1024 1024 1 16 1 */ +{ "51af0d83fe795f9c9544c20d0bbac11c" , "D_CLUNIE_XA1_JPLY.dcm" }, +/* gdcm 1024 1024 1 16 1 */ +{ "6111657e6b01ec7b243d63f5dec6ec48" , "D_CLUNIE_XA1_RLE.dcm" }, +/* gdcm 117 181 1 8 3 */ +{ "b4f442047a209a98af015c89b4a3c4ed" , "DermaColorLossLess.dcm" }, +/* gdcm 1024 1024 1 16 1 */ +{ "0b4dff77726ccf037fa83c42cc186a98" , "ExplicitVRforPublicElementsImplicitVRforShadowElements.dcm" }, +/* gdcm 512 512 1 16 1 */ +{ "6b92115ec7a394c4aaad74e88d7dbc98" , "FLAIR-wrong-group-length.dcm" }, +/* gdcm 1670 2010 1 16 1 */ +//{ "9ca80d44bfb1af2f96495fac4b57fa29" , "FUJI-10-MONO1-ACR_NEMA_2.dcm" }, +{ "da2415a1e58b4ca2e588d0de18274f60" , "FUJI-10-MONO1-ACR_NEMA_2.dcm" }, +/* gdcm 512 301 1 8 1 */ +{ "59d9851ca0f214d57fdfd6a8c13bc91c" , "gdcm-ACR-LibIDO.acr" }, +/* gdcm 750 750 1 8 1 */ +{ "73f20916abaea83abebe9135c365d81a" , "gdcm-CR-DCMTK-16-NonSamplePerPix.dcm" }, +/* gdcm 512 512 1 16 1 */ +{ "f2c026beea9da0a78404f1299c4628bb" , "gdcm-JPEG-Extended-Allready_present.dcm" }, +/* gdcm 512 512 1 16 1 */ +{ "f2c026beea9da0a78404f1299c4628bb" , "gdcm-JPEG-Extended.dcm" }, +/* gdcm 512 512 1 16 1 */ +{ "ad67e448e8923c34f1e019c3395e616c" , "gdcm-JPEG-LossLess3a.dcm" }, +/* gdcm 1876 2076 1 16 1 */ +{ "c15c1e18a0c41970fbded48b20e834a1" , "gdcm-JPEG-LossLessThoravision.dcm" }, +/* gdcm 128 128 1 16 1 */ +{ "ad85be428c08ab4166347ef04bda9637" , "gdcm-MR-PHILIPS-16-Multi-Seq.dcm" }, +/* gdcm 160 64 1 16 1 */ +{ "2f7f9ef80b49111c5a7cfdb60a97f523" , "gdcm-MR-PHILIPS-16-NonSquarePixels.dcm" }, +/* gdcm 512 512 1 16 1 */ +{ "864e2c5d6acf5a371fe9eaa7ee0dcf5f" , "gdcm-MR-SIEMENS-16-2.acr" }, +/* gdcm 640 480 1 16 1 */ +{ "f85ff02a143c426edc4b2f6b9a175305" , "gdcm-US-ALOKA-16.dcm" }, +/* gdcm 512 512 1 16 1 */ +{ "80527e9c17a4a3d12d408e9a354f37f9" , "GE_CT_With_Private_compressed-icon.dcm" }, +/* gdcm 512 512 67 8 1 */ +{ "b8bcbccd17b76a0f8e3d4c342f855f9f" , "GE_DLX-8-MONO2-Multiframe-Jpeg_Lossless.dcm" }, +/* gdcm 512 512 56 8 1 */ +{ "71e4ea61df4f7ada2955799c91f93e74" , "GE_DLX-8-MONO2-Multiframe.dcm" }, +/* gdcm 512 512 54 8 1 */ +{ "51c998d3474c069b5703e98313258a1e" , "GE_DLX-8-MONO2-PrivateSyntax.dcm" }, +/* gdcm 256 256 1 16 1 */ +{ "8ac7f7891fb4506e2cd3ae2f0f7e9f46" , "GE_GENESIS-16-MONO2-Uncompressed-UnusualVR.dcm" }, +/* gdcm 256 256 1 16 1 */ +{ "1497fb9d7467b1eb36d5618e254aac76" , "GE_GENESIS-16-MONO2-WrongLengthItem.dcm" }, +/* gdcm 640 480 1 8 3 */ +{ "13fd8c7e533a3d7199bb78de45710f5c" , "GE_LOGIQBook-8-RGB-HugePreview.dcm" }, +/* gdcm 512 512 1 16 1 */ +{ "f3a3d0e739e5f4fbeddd1452b81f4d89" , "GE_RHAPSODE-16-MONO2-JPEG-Fragments.dcm" }, +/* gdcm 1792 2392 1 16 1 */ +//{ "821acfdb5d5ad9dc13275d3ad3827d43" , "KODAK-12-MONO1-Odd_Terminated_Sequence.dcm" }, +{ "c1ed06d39821a5fd65abc397982e2ac1" , "KODAK-12-MONO1-Odd_Terminated_Sequence.dcm" }, +/* gdcm 800 535 1 16 1 */ +{ "70166425c4dca767e22d3f25f737922b" , "LEADTOOLS_FLOWERS-16-MONO2-JpegLossless.dcm" }, +/* gdcm 800 535 1 16 1 */ +{ "70166425c4dca767e22d3f25f737922b" , "LEADTOOLS_FLOWERS-16-MONO2-RLE.dcm" }, +/* gdcm 800 535 1 16 1 */ +{ "70166425c4dca767e22d3f25f737922b" , "LEADTOOLS_FLOWERS-16-MONO2-Uncompressed.dcm" }, +/* gdcm 800 535 1 8 3 */ +{ "279e2b0363394a553ff8571cf3540c6c" , "LEADTOOLS_FLOWERS-24-RGB-JpegLossless.dcm" }, +/* gdcm 800 535 1 8 3 */ +{ "38c2784aa485733fef45b6517479a4f5" , "LEADTOOLS_FLOWERS-24-RGB-JpegLossy.dcm" }, +/* gdcm 800 535 1 8 3 */ +{ "279e2b0363394a553ff8571cf3540c6c" , "LEADTOOLS_FLOWERS-24-RGB-Uncompressed.dcm" }, +/* gdcm 800 535 1 8 1 */ +{ "fa08fec923f34e009ec89f77232e52ad" , "LEADTOOLS_FLOWERS-8-MONO2-JpegLossy.dcm" }, +/* gdcm 800 535 1 8 1 */ +{ "3cd8bd92db17bff54e376885dfefdd8d" , "LEADTOOLS_FLOWERS-8-MONO2-RLE.dcm" }, +/* gdcm 800 535 1 8 1 */ +{ "3cd8bd92db17bff54e376885dfefdd8d" , "LEADTOOLS_FLOWERS-8-MONO2-Uncompressed.dcm" }, +/* gdcm 800 535 1 8 3 */ +//{ "d613050ca0f9c924fb5282d140281fcc" , "LEADTOOLS_FLOWERS-8-PAL-RLE.dcm" }, +{ "16e999d6afc5574bcb075f296c3bcbbc" , "LEADTOOLS_FLOWERS-8-PAL-RLE.dcm" }, +/* gdcm 800 535 1 8 3 */ +//{ "d613050ca0f9c924fb5282d140281fcc" , "LEADTOOLS_FLOWERS-8-PAL-Uncompressed.dcm" }, +{ "16e999d6afc5574bcb075f296c3bcbbc" , "LEADTOOLS_FLOWERS-8-PAL-Uncompressed.dcm" }, +/* duh ! This should be the exact same md5...if only the testing was a little + * smarter */ +{ "d613050ca0f9c924fb5282d140281fcc" , "LEADTOOLS_FLOWERS-8-PAL-RAW.dcm" }, +/* gdcm 50 50 262 16 1 */ +{ "ce1cc8ebb1efb86213d5912a1cfde843" , "LIBIDO-16-ACR_NEMA-Volume.dcm" }, +/* gdcm 400 100 1 8 3 */ +{ "81a40454eec2b18f4331cfd1ba4e501e" , "LIBIDO-24-ACR_NEMA-Rectangle.dcm" }, +/* gdcm 128 128 1 8 1 */ +{ "fc5db4e2e7fca8445342b83799ff16d8" , "LIBIDO-8-ACR_NEMA-Lena_128_128.acr" }, +/* gdcm 512 512 1 16 1 */ +{ "b1476cacdd32216b3295d2a494af2945" , "MARCONI_MxTWin-12-MONO2-JpegLossless-ZeroLengthSQ.dcm" }, +/* gdcm 256 192 1 16 1 */ +{ "d9f47017de79e8755e4bc5d3c9146ebd" , "MR-Brucker-CineTagging-NonSquarePixels.dcm" }, +/* gdcm 512 512 1 16 1 */ +{ "8fe67e8e1f849c1b61f59e70d2d53cf7" , "MR_GE_with_Private_Compressed_Icon_0009_1110.dcm" }, +/* gdcm 256 256 1 16 1 */ +{ "f54c7ea520ab3ec32b6303581ecd262f" , "MR-MONO2-12-an2.acr" }, +/* gdcm 256 256 1 16 1 */ +//{ "48345bccbd67f57b4c13060b6a9a0d35" , "MR-MONO2-12-angio-an1.acr" }, +//{ "19cd553b53c8c35b8f2c20f27ed31d2d" , "MR-MONO2-12-angio-an1.acr" }, +{ "ae5c00b60a58849b19aaabfc6521eeed" , "MR-MONO2-12-angio-an1.acr" }, +/* gdcm 1024 1024 1 16 1 */ +{ "a70676f0e60a58f55a5ac517ff662e7e" , "MR-MONO2-12-shoulder.dcm" }, +/* gdcm 256 256 1 16 1 */ +{ "83be31fb5e5cee60dedaf485bf592ac3" , "MR-MONO2-16-head.dcm" }, +/* gdcm 256 256 16 8 1 */ +{ "01db0d71100c47013e588082d5f39bab" , "MR-MONO2-8-16x-heart.dcm" }, +/* gdcm 256 256 1 16 1 */ +{ "b606add66c681bbe674f972799c6d336" , "MR_Philips-Intera_BreaksNOSHADOW.dcm" }, +/* gdcm 1024 1024 1 16 1 */ +{ "0b4dff77726ccf037fa83c42cc186a98" , "MR_Philips_Intera_No_PrivateSequenceImplicitVR.dcm" }, +/* gdcm 512 512 1 16 1 */ +{ "f69bca6228b0ca07d97ee11c0ab3b989" , "MR_Philips_Intera_PrivateSequenceImplicitVR.dcm" }, +/* gdcm 1024 1024 1 16 1 */ +{ "0b4dff77726ccf037fa83c42cc186a98" , "MR_Philips_Intera_SwitchIndianess_noLgtSQItem_in_trueLgtSeq.dcm" }, +/* ?? */ +{ "7775ffdd374994b7dd029f45f198844f" , "MR_Philips_Intera_PrivateSequenceExplicitVR_in_SQ_2001_e05f_item_wrong_lgt_use_NOSHADOWSEQ.dcm" }, +/* gdcm 484 484 1 8 1 */ +{ "8b636107a6d8e6a6b3d1d7eed966d7a0" , "MR-SIEMENS-DICOM-WithOverlays-extracted-overlays.dcm" }, +/* gdcm 484 484 1 16 1 */ +{ "3027eda10630e5c845f456264dc65210" , "MR-SIEMENS-DICOM-WithOverlays.dcm" }, +/* gdcm 128 128 1 16 1 */ +{ "6a925f871c58553f84ad24195e155c52" , "MR_SIEMENS_forceLoad29-1010_29-1020.dcm" }, +/* gdcm 64 64 13 16 1 */ +{ "c83ef2159abef677229d3afd26f9e6a0" , "NM-MONO2-16-13x-heart.dcm" }, +/* gdcm 512 512 1 8 1 */ +{ "a155c3004bb902ed3f2d78f482923b32" , "OT-MONO2-8-a7.dcm" }, +/* gdcm 640 480 1 8 3 */ +//{ "47715f0a5d5089268bbef6f83251a8ad" , "OT-PAL-8-face.dcm" }, +{ "d7c30d57af821b02c67103250a744235" , "OT-PAL-8-face.dcm" }, +/* gdcm 512 512 1 16 1 */ +//{ "4b0021efe5a675f24c82e1ff28a1e2eb" , "PHILIPS_Gyroscan-12-Jpeg_Extended_Process_2_4.dcm" }, +{ "d93d2f78d845c7a132489aab92eadd32" , "PHILIPS_Gyroscan-12-Jpeg_Extended_Process_2_4.dcm" }, +/* gdcm 256 256 1 16 1 */ +{ "b78366162d9d43b2852d2637c5365c89" , "PHILIPS_Gyroscan-12-MONO2-Jpeg_Lossless.dcm" }, +/* gdcm 256 256 1 16 1 */ +{ "4842ccbaac5b563ce915d2e21eb4c06e" , "PHILIPS_Gyroscan-8-MONO2-Odd_Sequence.dcm" }, +/* gdcm 512 512 76 8 1 */ +{ "1f8951a6f8b599ad4ebc97efd7aab6be" , "PHILIPS_Integris_H-8-MONO2-Multiframe.dcm" }, +/* gdcm 1024 1024 31 16 1 */ +{ "3d005cd3270c6d2562c2a8d9069c9295" , "PHILIPS_Integris_V-10-MONO2-Multiframe.dcm" }, +/* gdcm 1024 1024 1 16 1 */ +{ "0b4dff77726ccf037fa83c42cc186a98" , "PHILIPS_Intera-16-MONO2-Uncompress.dcm" }, +/* gdcm 512 512 1 16 1 */ +{ "6c9e477330d70d4a1360888121c7c3d3" , "PICKER-16-MONO2-Nested_icon.dcm" }, +/* gdcm 512 512 1 16 1 */ +{ "5ea911b29f472f371d21f2da2fd6b016" , "PICKER-16-MONO2-No_DicomV3_Preamble.dcm" }, +/* gdcm 512 512 1 16 1 */ +{ "498f80fd27882351b9a09e6ceef470bc" , "PrivateGEImplicitVRBigEndianTransferSyntax16Bits.dcm" }, +/* gdcm 136 92 1 16 1 */ +{ "dbbf39ac11a39372b1e961f40ac6f62a" , "RadBWLossLess.dcm" }, +/* gdcm 600 430 1 16 3 */ +//{ "964ea27345a7004325896d34b257f289" , "rle16sti.dcm" }, +{ "f799773abbe36a1a8a3a881e27f8084d" , "rle16sti.dcm" }, +/* gdcm 512 512 1 16 1 */ +{ "80527e9c17a4a3d12d408e9a354f37f9" , "ser002img00026.dcm" }, +/* gdcm 512 512 1 16 1 */ +{ "7b55fd124331adde6276416678543048" , "SIEMENS-12-Jpeg_Process_2_4-Lossy-a.dcm" }, +/* gdcm 256 256 1 16 1 */ +{ "ea24c09f475a4e9643e27f6d470edc67" , "SIEMENS_GBS_III-16-ACR_NEMA_1.acr" }, +/* gdcm 512 512 1 16 1 */ +{ "864e2c5d6acf5a371fe9eaa7ee0dcf5f" , "SIEMENS_MAGNETOM-12-ACR_NEMA_2-Modern.dcm" }, +/* gdcm 128 128 1 16 1 */ +{ "a13466d96b2f068c4844240797069f13" , "SIEMENS_MAGNETOM-12-MONO2-FileSeq0.dcm" }, +/* gdcm 128 128 1 16 1 */ +{ "73f5986082729c2661cdc8de81fd26d0" , "SIEMENS_MAGNETOM-12-MONO2-FileSeq1.dcm" }, +/* gdcm 128 128 1 16 1 */ +{ "f932a194df62ec99aef676c563893496" , "SIEMENS_MAGNETOM-12-MONO2-FileSeq2.dcm" }, +/* gdcm 128 128 1 16 1 */ +{ "b6e4780d8aa8c1d3642377a60a5302dd" , "SIEMENS_MAGNETOM-12-MONO2-FileSeq3.dcm" }, +/* gdcm 512 512 1 16 1 */ +{ "4b426d4cd570bd4c998f3d19cfddfbb8" , "SIEMENS_MAGNETOM-12-MONO2-Uncompressed.dcm" }, +/* gdcm 192 256 1 16 3 */ +{ "faff9970b905458c0844400b5b869e25" , "SIEMENS-MR-RGB-16Bits.dcm" }, +/* gdcm 512 512 1 16 1 */ +{ "7ccf7c7c4b2a5fa9d337ea8b01f75c42" , "SIEMENS_SOMATOM-12-ACR_NEMA-ZeroLengthUs.acr" }, +/* gdcm 192 192 1 16 1 */ +{ "a3009bc70444148c5ea2441a099f9dc6" , "SIEMENS_Sonata-12-MONO2-SQ.dcm" }, +/* gdcm 256 208 1 16 1 */ +{ "017237320ccded3a367f07b44851788e" , "SIEMENS_Sonata-16-MONO2-Value_Multiplicity.dcm" }, +/* gdcm 512 512 1 8 1 */ +{ "f845c8f283d39a0204c325654493ba53" , "test.acr" }, +/* gdcm 256 256 1 16 1 */ +{ "62c98e89a37c9a527d95d5ac3e2548b0" , "THERALYS-12-MONO2-Uncompressed-E_Film_Template.dcm" }, +/* gdcm 256 256 1 16 1 */ +{ "0121cd64c3b9957f76dd338d27454bc6" , "THERALYS-12-MONO2-Uncompressed-Even_Length_Tag.dcm" }, +/* gdcm 512 512 1 16 1 */ +{ "09661bd8516aeb5a6f09239f9ca1b092" , "TOSHIBA_MRT150-16-MONO2-ACR_NEMA_2.dcm" }, +/* gdcm 636 434 1 8 3 */ +{ "23ec8ed09e1ecc353c2e6436a1de6cb2" , "US-GE-4AICL142.dcm" }, +/* gdcm 640 480 1 8 1 */ +{ "ba092234639594ee9091b46997532cce" , "US-IRAD-NoPreambleStartWith0003.dcm" }, +/* gdcm 640 480 1 8 1 */ +{ "1bde104ba256fb73528c5d9a02e363d7" , "US-IRAD-NoPreambleStartWith0005.dcm" }, +/* gdcm 128 120 8 8 1 */ +{ "bf63affde325b3fa81cd5a700f30bd5b" , "US-MONO2-8-8x-execho.dcm" }, +/* gdcm 600 430 10 8 3 */ +//{ "c70309b66045140b8e08c11aa319c0ab" , "US-PAL-8-10x-echo.dcm" }, +{ "1785f4d8af4717c17bfb78ba74c18ea5" , "US-PAL-8-10x-echo.dcm" }, +/* gdcm 640 480 1 8 3 */ +//{ "fe2d477d699e327be2d3d65eb76203e9" , "US-RGB-8-epicard.dcm" }, +{ "eb3433568c6b0cee90688ccf228ffc02" , "US-RGB-8-epicard.dcm" }, +/* gdcm 256 120 1 8 3 */ +{ "4b350b9353a93c747917c7c3bf9b8f44" , "US-RGB-8-esopecho.dcm" }, +/* gdcm 512 512 12 8 1 */ +{ "136eaf8f7d654bbb08741c201a945561" , "XA-MONO2-8-12x-catheter.dcm" }, + + +// Those where added manually: +// If you are lucky and the image is raw (MONOCHROME2) you simply need to +// do (assuming you are under UNIX) +// $ ./bin/gdcmraw -i 42166745.dcm -o bla.raw +// $ md5sum bla.raw +// For JPEG and RLE file, you need to check result against dcmtk (dcmdjpeg, +// dcmdrle will help you). +// Image1 & Image2 are crap, some kind of decompression went wrong +// and PixelData is raw so not much you can do... +{ "1b0768a3518a6b6ed425c3c1d7a7ea3b" , "Image1.dcm" }, +{ "a41c7f4e75cf637ae8912f5c3cd2c69d" , "Image2.dcm" }, +{ "22c9be23446a7be61a90d3578f3c9739" , "deflate_image.dcm" }, +{ "d5681b156af55899835293286c57d887" , "brain.dcm" }, +{ "d4d365f0500f2ccff932317833d8804b" , "abdominal.dcm" }, +{ "138d9bd642c6f1cdc427ef6f99132677" , "ankle.dcm" }, +{ "ff8d450e47e8989478a1b6f19d0988cc" , "spine.dcm" }, +{ "c78c1721a5ac585a12cf9a52abc25d4c" , "42166745.dcm" }, +{ "d48ae6ccc815fd171169591a1048c5ed" , "JDDICOM_Sample4.dcm" }, +{ "63c45c2e73403af781d07ae02247654f" , "I20051107115955.dcm" }, +{ "938ac04374eadbe6ac4d7df80e5aa178" , "JDDICOM_Sample1.dcm" }, +// This one can not be decompressed properly with dcmdjpeg. Until +// they fix dcmdjpeg I'll assume decompression went right +{ "33aa469ec024188d692262d03e7108a0" , "JDDICOM_Sample2.dcm" }, +// Same problem +{ "308b1b6fbc01df4dc3fb168830777cb1" , "JDDICOM_Sample3.dcm" }, +// Same thing +{ "b8b5030261f92574227fe91902738558" , "JDDICOM_Sample5.dcm" }, +// This one was computed from dcmtk, gdcm 1.x fails to read it... +//{ "49ca8ad45fa7f24b0406a5a03ba8aff6" , "rle16loo.dcm" }, +{ "04b42f011bdcf56e8a22607cb715447c" , "rle16loo.dcm" }, +// Name is poorly choosen since it's actually a Dicom Objects bug +// Cannot only be read by gdcm 1.2.x +{ "f1436c1800ccbba8da82acb7f2dff29d" , "GE_JPEG-Broken.dcm" }, +// For some reason the numbers gets funny +{ "73dd2a43ab7c2810714a8ea1079f3c38" , "10200901_8b_Palette_RLE_blinker.dcm" }, +{ "609ede096636ae804dbb0fb4d78be2c2" , "10200900_8b_Palette_RLE_blinker.dcm" }, +{ "ed6078d83f467f9eda5d8cd06f87080f" , "10200905_8b_Palette_RLE_blinker.dcm" }, +// This is the same image as rle16loo ... +{ "49ca8ad45fa7f24b0406a5a03ba8aff6" , "rle16loop_16b_Palette_RLE.dcm" }, +// dummy image, this is the same as US-IRAD-NoPreambleStartWith0005.dcm +{ "1bde104ba256fb73528c5d9a02e363d7" , "US.irad.27702.1.dcm"}, +// ACR NEMA with a PhotometricInterpretation.. +{ "1e3acacba2ae92b52011804ebddbf5df" , "acc-max.dcm" }, +{ "d5037d66855c7815f55185b808e48750" , "Originale_015.dcm" }, +{ "bbca0e3e26acdd1ab4f6c4871810ac50" , "PETAt001_PT001.dcm" }, +{ "5a33e3a2cd414d734984c7a6a5a32a41" , "i0116.dcm" }, +{ "5a0ebe04ffe50d4373624e444093b855" , "eclipse_dose.dcm" }, +{ "c4e4589b884cfee49db81746cd18a41c" , "MRMN1786V1L.dcm" }, +{ "bc8f9791b75916e85c91e458cd1364a3" , "MRMN1786V1T.dcm" }, +{ "6cee5011d0dcce93d259d272eb94336f" , "MRMN1786V2L.dcm" }, +{ "793d177bd10188e66483ddc04cbca9e7" , "gdcm-CT-GE-16-GantryTilt.dcm" }, +{ "7db6d7da455d94ed1a3afda437c3f09e" , "MRMN1786V2T.dcm" }, +// JPEG lossy: +{ "bea6e06fe30abd455288e35aaf47477d" , "angiograms.dcm" }, +{ "350aea8820dbbdbb15eabc88f3dd3b16" , "image09-bis.dcm" }, +// The same as US-IRAD-NoPreambleStartWith0003.dcm +{ "ba092234639594ee9091b46997532cce" , "US.irad.28317.1.dcm" }, +{ "21a11f961726c81684be3241eb961819" , "PETAt001_PT204.dcm" }, +{ "23b5d0a918fb882c08c458c1507c39f7" , "SiemensIcon.dcm" }, +{ "0121cd64c3b9957f76dd338d27454bc6" , "RMI_Mattes_1_150_001_7_150_cEval0_038.dcm" }, +{ "350aea8820dbbdbb15eabc88f3dd3b16" , "image09.dcm" }, +{ "1bde104ba256fb73528c5d9a02e363d7" , "image12.dcm" }, +{ "417ca9bf1db40dd8656cfb6de0aef181" , "JPEGLosslessLongSQ.dcm" }, +{ "d5037d66855c7815f55185b808e48750" , "readWrite.dcm" }, +// Visible Human written in DICOM with ITK-GDCM (1.2) +{ "e114252b9acf985cf53b06c39118a290" , "vhm.1001.dcm" }, +{ "0b4dff77726ccf037fa83c42cc186a98" , "MR_Philips_Intera_Kosher.dcm" }, +{ "f9d9898ad844a73c0656539388fec85c" , "0001.dcm" }, +{ "c4031c607b7312952bb560e55cbbb072" , "exp000.dcm" }, +{ "2bb620b2c516b66faeef7397d30b83f1" , "exp001.dcm" }, +{ "0dfbe8aa4c20b52e1b8bf3cb6cbdf193" , "RMI_Mattes_unevenLengthTags.dcm" }, +// The famous Siemens 0029-1010/1020 +{ "6a925f871c58553f84ad24195e155c52" , "MR_forceLoad29-1010_29-1020.dcm" }, +{ "255769e6c9d8a161fce520c958c94de7" , "MR_Siemens_ShadowGroupsImplicitVR.dcm" }, +{ "5c25c435ecd8eeac124ab427668186de" , "01f7_7fdf.dcm" }, +{ "0dfbe8aa4c20b52e1b8bf3cb6cbdf193" , "RMI_Mattes_1_1_001_7_1_cEval0_000.dcm" }, +{ "620012cfec4ae2e6dd0137b2e16947d7" , "ElemZeroNotGroupLength.dcm" }, +{ "57994245238730f4b4c5eaed21c4144b" , "File000138.dcm" }, +{ "826b6bc1e36efda1b727b08248a71dd2" , "File000139.dcm" }, +{ "6b26a5561678b26aa2f21a68ea334819" , "SYNGORTImage.dcm" }, +{ "a198893279520631657781d47c4097b2" , "Implicit-0001.dcm" }, +{ "99540b33d088646b8e424a57afdccbe6" , "CT_PET001_CT001.dcm" }, +{ "343e27f0867b55af74b21a5ba55bd9cc" , "rattag.dcm" }, +{ "0038402afc09d44d3c75ed207171976b" , "i0002.dcm" }, + +{ "0ad4eca25cc0f783bd60c07b2d73f8b0" , "fudd_post.dcm" }, +{ "b85ca0e38d91ba0ee3a97f9c709415ac" , "brain_001.dcm" }, +{ "f1436c1800ccbba8da82acb7f2dff29d" , "SignedShortLosslessBug.dcm" }, +{ "eb87ca4a01e55dc7a7f1c92f0aa31017" , "ATTMA002_DS.dcm" }, +{ "f17cf873a3c07f3d91dc88f34664bf0d" , "libido1.0-vol.acr" }, +{ "d2fab61e0fff8869e448d69951f1084d" , "SIEMENS_MAGNETOM-12-MONO2-GDCM12-VRUN.dcm" }, +{ "e0221ddcc9febdc3c266bb8cd0fcf14f" , "undefined_length_un_vr.dcm" }, +{ "a136e501bcd1b8ee0835981d2bc8dd87" , "fffc0000UN.dcm" }, +{ "33aa469ec024188d692262d03e7108a0" , "JDDICOM_Sample2-dcmdjpeg.dcm" }, // mismatch DICOM / JPEG +{ "d2fab61e0fff8869e448d69951f1084d" , "SIEMENS_MAGNETOM-12-MONO2-VRUN.dcm" }, +{ "fc5db4e2e7fca8445342b83799ff16d8" , "simpleImageWithIcon.dcm" }, + +// Following need to be proof checked: +{ "0b4dff77726ccf037fa83c42cc186a98" , "imp.dcm" }, +{ "eb5fc6c9e86a69c27b7208d72370a92d" , "Renal_Clearance.dcm" }, +{ "1b130fa646f8d6b3c14b9443b35c80b4" , "IM0046A0.dcm" }, +{ "8c00e7f797d8bb4a629ae1e4b08084b9" , "rvg_analysis.dcm" }, +{ "0d7c2f8714ed3c7dec8194c6e4b359c3" , "BRTUM001.dcm" }, +{ "e5dbfc8673ea25dd73c95f4df3353b10" , "3DDCM011.dcm" }, +{ "12150f9067ea72bc56c75d83c42c8108" , "MIRA.dcm" }, +{ "ae9a191c716dfda2651a147728910a89" , "NM.dcm" }, +{ "d4444bcca0ee13919f867e486a8f3553" , "QCpatternC-v1.dcm" }, +{ "ad85be428c08ab4166347ef04bda9637" , "gdcm-MR-PHILIPS-16-Multi-Seq-Correct.dcm" }, +{ "9c390fc010105325427e3ff29a9b186c" , "SIEMENS_ORIGINAL.dcm" }, +{ "0b4dff77726ccf037fa83c42cc186a98" , "venticles32004-11-09-08-55-57-6750000000.dcm" }, +{ "bfff320d1b058e91b4819aa4560c16f7" , "test.dcm" }, +{ "8c9666cef26a0cc76491a7a8a5239b85" , "Renal_Flow.dcm" }, +{ "f3a3d0e739e5f4fbeddd1452b81f4d89" , "dclunie.dcm" }, +{ "78dae0e2d9b7a124fe63300b6356ded4" , "Toshiba7005.dcm" }, +{ "8240955d1e4b72989f8f49549f1617b2" , "PhilipsWith15Overlays.dcm" }, +{ "3cd8bd92db17bff54e376885dfefdd8d" , "toto.dcm" }, +{ "14ad8ae28cc5e5e5dc4c4d010c291a7f" , "test20.dcm" }, +{ "e7408198028983cd6643a00fd7668c00" , "testacr-jpll.dcm" }, +{ "6633fb8bce0a648763e7ed2b7de1db5c" , "1_172.dcm" }, +{ "29cfe7038fae548abd4af4551b2a37cb" , "example.dcm" }, +{ "6b18e445fbc917e7d6f55b616f17d3e1" , "WrongVRFor00271033.dcm" }, +{ "0b4dff77726ccf037fa83c42cc186a98" , "ExplicitVRforPublicElementsImplicitVRforShadowElementsCorrected.dcm" }, +{ "9570a06da59988ff3a7271cdde14abf5" , "3DT1_5138_0077.dcm" }, +{ "20c5f63d65732703e3fffeb8d67c62ed" , "FluroWithDisplayShutter.dcm" }, +{ "92b62f22fc44b8563c19f5536d9e499f" , "fudd_ant.dcm" }, +{ "b92a22ef55d6a1fbd24a6a24a7a84a7f" , "yazhi.dcm" }, +{ "2b69286289543afc3be7df0400abb8fc" , "IM_0001.dcm" }, +//{ "67d86e26740882586b6bf3fe7e09c831" , "PMMA-Treppe.dcm" }, +{ "287e002ebf84424fe66558b642c51bce" , "PMMA-Treppe.dcm" }, +{ "82a8d3398c98d23e1b34f5364f967287" , "PERFORM_T1_Symphony_VA25.dcm" }, +//{ "00b4b3282855c96744355892caf9d310" , "Al-Treppe.dcm" }, +{ "2c0ccfeff0a6d4afd7929a672dec0cc0" , "Al-Treppe.dcm" }, +{ "f891eae2cdfecd578b2204ebbb93f606" , "ImplicitDeclaredAsExplicit.dcm" }, +{ "7ceb7886f9fbcb7ae979fdb6f1305414" , "CR-Preamble-NoMeta.dcm" }, +{ "d2fab61e0fff8869e448d69951f1084d" , "db318_MR_STN_stimulator_T2_TSE_TRA__20071005161618048_4.dcm" }, +{ "2b4d7fb6b039b43145f2766b2339c460" , "0019004_Baseline_IMG1.dcm" }, +{ "f02e48f4b7df2ff4855733febc92e4e6" , "SIEMENS_GBS_III-16-ACR_NEMA_1.acr.ovly.6002.dcm" }, +{ "6a34b606135c4cd1c31511164e2cb235" , "SIEMENS_GBS_III-16-ACR_NEMA_1.acr.ovly.6000.dcm" }, +{ "65f961aca90fb61952d723feec6dec89" , "SIEMENS_GBS_III-16-ACR_NEMA_1.acr.ovly.6006.dcm" }, +{ "fc137690ae436bb44a695fb2f1e49d85" , "SIEMENS_GBS_III-16-ACR_NEMA_1.acr.ovly.6004.dcm" }, + +// No tested: + +{ "864e2c5d6acf5a371fe9eaa7ee0dcf5f" , "acr_image_with_non_printable_in_0051_1010.acr" }, +{ "7efed1c332c62ea34d5edad901081c36" , "mr_r_opptak000_20000925_t2.nema" }, +{ "d6995bd1d76eb36913c985c8397ff02d" , "mr_r_opptak000_20000925_t1.nema" }, +{ "dc549f804f1f59bfee245ddf100ee26b" , "SIEMENS-IncompletePixelData.dcm" }, +{ "51b7e83cdc569b8f355662d80bd7036d" , "20061119171007906.dcm" }, +{ "01db0d71100c47013e588082d5f39bab" , "MR0001.dcm" }, +{ "d9df75ff0394bb9a3753b625933d94fc" , "ModalityLUT.dcm" }, +{ "acd3f756192a9f0484c971db2869d70b" , "PublicElementsImplicitInExplicitDataSet.dcm" }, +{ "820575fcc05338f3e95296107d9ddf7a" , "MR3.dcm" }, +{ "3c6984afa2af4257565d8f622f7f5e5b" , "SIEMENS-JPEG-CorruptFragClean.dcm" }, +{ "cc2968949ffbb6548288ffde7e5202e4" , "D_CLUNIE_RG3_JPLY_dcmtk.dcm" }, +{ "83656f4989a2d4be8f9ad56d83a907f5" , "5decf5b5-6695-4557-867e-a1f97321cd80.dcm" }, +{ "92655f77a55eb9c316223b9e73d55800" , "PMS-IncompletePixelData.dcm" }, +{ "6a23c9f150a360381c8fbceb2277efc5" , "TOSHIBA-CurveData2.dcm" }, +{ "6ad75566935554fcc60ca35a003fba6d" , "IM_00003.dcm" }, +{ "ab7cab6e7b5f9043f8fa7c0ae3f1b282" , "19872890.dcm" }, +{ "48eb24e37d41faca8b629b3807c20d92" , "rm6_DICM.dcm" }, +{ "201c9761ed911ad12508248252f4ff16" , "T2*_1484_0009.dcm" }, +{ "90017033c3916259cad63615385a1d02" , "BogugsItemAndSequenceLength.dcm" }, +{ "b09dc714f6d56d29005996b3204eec25" , "TOSHIBA-CurveData1.dcm" }, +{ "5ed3d1de2a086ac7efd31a6f1463f129" , "SCIsMR.dcm" }, +{ "9bbb1d908401299e73e636ad5b19a225" , "Siemens_CT_Sensation64_has_VR_RT.dcm" }, +{ "13e41624a8b86c18ac257e3588f818ce" , "tst_ok.dcm" }, +{ "17f514732d5f7e9484ed33c35bddc930" , "ImplicitVRInExplicitDataSet.dcm" }, +{ "0826b8cc512a8e4d726c1c019af2eaf9" , "29627381.dcm" }, +{ "727383f164107aaa9ee6c2182f94b91d" , "1.2.752.24.6.1820537353.20080220145707750.8.1.dcm" }, +{ "5588652e673e745ad56441f5a26c2305" , "22484474.dcm" }, +{ "cf6fde116c90e4e56512b22004503d96" , "PHILIPS_PrivateSeqWithPublicElems.dcm" }, +{ "098bba76d4e75a3148c9b62aee35f950" , "GEMS-IncompletePixelData.dcm" }, +{ "1fe71a52a211d1a56cc49cdcb71c1dbb" , "IM03.dcm" }, +{ "b857b6cce2afd7033476526b89ed9678" , "TheralysGDCM1.dcm" }, +{ "e998bbfca8b892fd0955c95b6f1584ea" , "Theralys2048Thingy.dcm" }, +{ "0508d28682e209f87d28184ae10060bd" , "Compress_16bit_noPVRG.dcm" }, +{ "90017033c3916259cad63615385a1d02" , "BogugsItemAndSequenceLengthCorrected.dcm" }, +{ "51b7e83cdc569b8f355662d80bd7036d" , "debian_medcon_401529.dcm" }, +{ "51b7e83cdc569b8f355662d80bd7036d" , "BogusItemStartItemEnd.dcm" }, +{ "3c6984afa2af4257565d8f622f7f5e5b" , "SIEMENS-JPEG-CorruptFrag.dcm" }, +{ "192f5ebd4d8f6164a4142421408172b2" , "PhilipsByteSwapping.dcm" }, +{ "2438b8feef6c8f682b2f468aff4475e5" , "MismatchSOPClassUID.dcm" }, +{ "738092e703655b6ae22a907d9f9f0c9c" , "YBRisGray.dcm" }, +{ "635e947fc156c89a8d10ced8317ace82" , "2mAs.dcm" }, +{ "54d648704507de7cd6e4be12061a5fb2" , "OSIRIX_MONOCHROME2_BUG.dcm" }, +{ "1db40fc52b962c8b6823980fe9dad6d8" , "5mAs.dcm" }, +{ "1b130fa646f8d6b3c14b9443b35c80b4" , "IM0046A0_2.dcm" }, +{ "cdfb45de5ddad3e7e2b0053c848d0d2b" , "ImplicitVRInExplicitDataSet2.dcm" }, +{ "ec5c421832df7cc43801d038705cd2cf" , "OverlayPrivateDataInBetween.dcm" }, +{ "9a375c3b2a72a6ccf687250b17f646c9" , "ItemTerminatorVLnot0.dcm" }, +{ "5269176094127c6f106cbcf9dbdf55b0" , "I0000017.dcm" }, +{ "eb87ca4a01e55dc7a7f1c92f0aa31017" , "EmptyItemStarter.dcm" }, +{ "cae8f644373163cb3970999f7ac00fd3" , "169585.dcm" }, +{ "5ea911b29f472f371d21f2da2fd6b016" , "VRUNInMetaHeader.dcm" }, +{ "ad7b664eed26e95f790c24cdb3060fb9" , "IM000450.dcm" }, +{ "4f113f33863067b8ca8d560cb194da09" , "TOSHIBA-CurveData3.dcm" }, +{ "14fa2ae9f63742af6944edd4a61145e8" , "mrbrainR.dcm" }, +{ "ba17ae006314a097fef7a32fa1a624b0" , "c42g57hg64ca02.dcm" }, +{ "10047ec574a6401ad90606e63304de6e" , "0020.DCM" }, +{ "5184839806c9a9583fe192d43cede939" , "001005XA" }, +{ "5291e36a7d54d4c8e00d5765cd0b3d17" , "001007XA" }, +{ "a57df7bc23977977832f98bfb662cdb4" , "001003XA" }, +{ "b36329c27f359daede3205d7c57cccd1" , "001009XA" }, +{ "1d173a6f31e0e4dd1078adf3557774c7" , "001008XA" }, +{ "9b42aa4e5d3b5f889164b5a734b954b3" , "001010XA" }, +{ "87f72a961292c83f8a9230e8eefecc6b" , "001004XA" }, +{ "6c7a303d25b418988ef9a37c4315a746" , "001001XA" }, +{ "9dde002e4e99218891df5f98da56ec9d" , "001002XA" }, +{ "6c7a303d25b418988ef9a37c4315a746" , "001001XA.1" }, +{ "8891d44376bc53c7bd0d36d2b776cd9b" , "001006XA" }, +{ "a6d10a3de9499d8853c6667b82628e86" , "TOSHIBA-EnhancedCT.dcm" }, +{ "71b3b19571f5b9e7ec931071bf5157dd" , "CroppedArm.dcm" }, +{ "bab06b7112dbce4f528bab5c1b89abc1" , "Bug_Philips_ItemTag_3F3F.dcm" }, + + +{ "8d3a64a67b4d8d15561fb586fd0706ee" , "Nm.dcm" }, +{ "05392d4f7a0c05223eeb957ee60203a9" , "MergeCOM3_330_IM50.dcm" }, +{ "635c2dbedea549a89f88e959934ed93c" , "ELSCINT1_OW.dcm" }, +{ "594995a6eb12a565247cd98f967a378d" , "KONICA_VROX.dcm" }, +{ "1497b865a4c6ab73cd6797b8834baa9f" , "TheralysNoModalityNoObject.dcm" }, +{ "d1f8cbdb279d038e2674ec0907afffe1" , "gastrolateral.dcm" }, +{ "ea24c09f475a4e9643e27f6d470edc67" , "SIEMENS_GBS_III-16-ACR_NEMA_1-ULis2Bytes.dcm" }, +{ "ecd26fb1fa914918ff9292c4f7340050" , "MR00010001.dcm" }, +{ "c56567bbb8f1924d6c0c6fd8ca7f239d" , "006872.003.107.dcm" }, +{ "228e9af71b8ce00cae3066e3fdd3641f" , "SIEMENS_MONOCHROME2_LUT_MOCO.dcm" }, +{ "ef8c3435ee7a9b332976f2dc56833d3a" , "GENESIS_SIGNA-JPEG-CorruptFrag.dcm" }, // FIXME ! +{ "42a4f33eb34456e3e82f30d707c84870" , "DCMOBJ_IMG57.dcm" }, +{ "3a85617df95abbb63cd84a183515c697" , "image.acr" }, +{ "8c5a627c461688cfa5dc708a170c5eda" , "IM-0001-0001.dcm" }, +{ "ec87a838931d4d5d2e94a04644788a55" , "test_att.acr" }, +{ "0621954acd5815e0b4f7b65fcc6506b1" , "SIEMENS_ImageLocationUN.dcm" }, + +{ "e1e34e81050d17b07a20c0e43c355187" , "GDCMFakeJPEG.dcm" }, +{ "ef9f915086db838334ddc656a10486f2" , "DMCPACS_ExplicitImplicit_BogusIOP.dcm" }, +{ "498f80fd27882351b9a09e6ceef470bc" , "ELSCINT1_GDCM12Bug.dcm" }, +{ "34b5c1ce40f09f0dbede87ebf3f6ed3c" , "korean_agfa_infinitt_2008-3.dcm" }, +{ "2c8b8ee9950582af472cf652005f07d4" , "c_vf1001.dcm" }, +{ "a1ea6633f17ef1e0d702cdd46434b393" , "MARTIN_ALBERT-20010502-2-1.nema" }, +{ "d85237c7ff838f5246643a027d3727ae" , "GDCMPrinterDisplayUNasSQ.dcm" }, +{ "2dbe2da7fbcf1bd73e2221e9cd4ad7ee" , "MissingPixelRepresentation.dcm" }, +{ "a3009bc70444148c5ea2441a099f9dc6" , "E00001S03I0015.dcm" }, +{ "afe5937be25ac657e48b1270b52e6d98" , "Martin.dcm" }, + + + +{ "4d790e17ee35572d64e37c55dbc36725" , "MR_ELSCINT1_00e1_1042_SQ_feff_00e0_Item.dcm" }, +{ "93ddc0c3d642af60f55630232d2801ae" , "CT_Image_Storage_multiframe.dcm" }, +{ "6127740892542f23e37e6ab516b17caf" , "ELSCINT1_JP2vsJ2K.dcm" }, +{ "b620a57170941e26dfd07ff334c73cb4" , "GE_MR_0025xx1bProtocolDataBlock.dcm" }, +{ "4b5423b34ab4e104c222359a91448a5d" , "CT-SIEMENS-MissingPixelDataInIconSQ.dcm" }, +{ "79b8705f2e6c7464bd3e2fc7e1d3483b" , "KODAK_CompressedIcon.dcm" }, +{ "59071590099d21dd439896592338bf95" , "ima43.dcm" }, +{ "46bf12c412590767bb8cd7f0d53eaa87" , "TG18-CH-2k-01.dcm" }, +{ "9214cc4f62fbea873ffad88e1be877c5" , "LJPEG_BuginGDCM12.dcm" }, +{ "52607a16af1eaddbbc71c14d32e489d8" , "DX_J2K_0Padding.dcm" }, + + +{ "6af53848fe77feb56a12aba74dadea8e" , "TheralysGDCM120Bug.dcm" }, +{ "79b8705f2e6c7464bd3e2fc7e1d3483b" , "TestVRSQUN2.dcm" }, +{ "71e4ea61df4f7ada2955799c91f93e74" , "TestVRSQUN1.dcm" }, + +{ "6396332b75b15bf30b1dd1cd0f212691" , "SIEMENS_MOSAIC_12BitsStored-16BitsJPEG.dcm" }, +{ "ba8dae4b43075c7e8562f5addf5f95c3" , "DX_GE_FALCON_SNOWY-VOI.dcm" }, +{ "d6fb1fb06318dd305a461db9c84cf825" , "JPEG_LossyYBR.dcm" }, +{ "43f33c06d56f239ce9ed5ca0d66a69d2" , "PHILIPS_Brilliance_ExtraBytesInOverlay.dcm" }, +{ "dae9d2e2b412646fd0a0f31dc2d17aa4" , "BugGDCM2_UndefItemWrongVL.dcm" }, + + +{ "62687f0a17e9c4153f18b55c8abfcef3" , "SIEMENS_CSA2.dcm" }, +{ "a02fa05065b3a93a391f820ac38bd9ee" , "MAROTECH_CT_JP2Lossy.dcm" }, +{ "8b5e38699887158c3defd47900a68fc5" , "ITK_GDCM124_MultiframeSecondaryCaptureInvalid.dcm" }, + + +{ "c57035e2dac52e339b27e8c965251b3d" , "DCMTK_JPEGExt_12Bits.dcm" }, // checked with dcmdjpeg v3.5.4+ 2009-05-07 + +{ "d7673c8575cb2765f8ae25aa3899c77e" , "PHILIPS_GDCM12xBug.dcm"}, +{ "a597540a79306be4710f4f04497fc23a" , "PHILIPS_GDCM12xBug2.dcm"}, + +{ "1e8843c2d247f9e9e7a44c9c6de43f6d" , "multiframegrayscalewordscis.dcm" }, +{ "928b41468193f0eecaea216866bbe735" , "signedtruecoloroldsc.dcm" }, +{ "209bc9b02004a712f0436a1ca5e676b4" , "multiframesinglebitscis.dcm" }, +{ "c8698fa1ec0b227113f244954b8e88f4" , "multiframegrayscalebytescis.dcm" }, +{ "dce1513162a762bf43dcc3c9d5c5c3f7" , "multiframetruecolorscis.dcm" }, + +{ "6bf95a48f366bdf8af3a198c7b723c77" , "SinglePrecisionSC.dcm" }, + +{ "a870a7a7cab8c17646d118ae146be588" , "MR16BitsAllocated_8BitsStored.dcm" }, + +{ "da153c2f438d6dd4277e0c6ad2aeae74" , "OsirixFake16BitsStoredFakeSpacing.dcm" }, +{ "1c485e1ac2b2bdbeeba14391b8c1e0c8" , "JPEGDefinedLengthSequenceOfFragments.dcm" }, + +{ "ae1290d59c63b0c334a4834c5995fe45" , "AMIInvalidPrivateDefinedLengthSQasUN.dcm" }, + +{ "f3a3d0e739e5f4fbeddd1452b81f4d89" , "D_CLUNIE_CT1_JLSL.dcm" }, +{ "5e9085c66976d2f5f9989d88bf7a90c4" , "D_CLUNIE_CT1_JLSN.dcm" }, + +{ "9eb513314b2fcf25d895e18ffb2ead0b" , "UnexpectedSequenceDelimiterInFixedLengthSequence.dcm" }, +{ "12d1567ed81236cf3b01dc12766581a0" , "IM-0001-0066.CommandTag00.dcm" }, +{ "6f26e552a1b71d386483118779d192ad" , "NM_Kakadu44_SOTmarkerincons.dcm" }, +{ "56238d3665ebdb0251d1161fb7f4edc6" , "GDCMJ2K_TextGBR.dcm" }, +{ "f8a1f4ce85b51527267e670a8aa0c308" , "PhilipsInteraSeqTermInvLen.dcm" }, + +// following 3 md5 computes with kdu_expand v6.3.1 +{ "d6347ed051d7b887bdaad1a91433c6ba" , "TOSHIBA_J2K_SIZ1_PixRep0.dcm" }, +{ "d6347ed051d7b887bdaad1a91433c6ba" , "TOSHIBA_J2K_SIZ0_PixRep1.dcm" }, +{ "94414d8b4300aa3d8cbe4475d34e8e54" , "TOSHIBA_J2K_OpenJPEGv2Regression.dcm" }, + +{ "304f147752d46adfdcff71a30cd03d0a" , "NM-PAL-16-PixRep1.dcm" }, +{ "20b1e4de7b864d44fcd0dda1fc42402c" , "MEDILABInvalidCP246_EVRLESQasUN.dcm" }, + +// gdcmDataExtra: +{ "cb26bfacea534b5cd6881bc36520ecfc" , "US_512x512x2496_JPEG_BaseLine_Process_1.dcm" }, +{ "d40e2d27988f0c546b0daeb67fcbfba8" , "i32.XADC.7.215MegaBytes.dcm" }, +{ "c383b244fd43cb0a9db764b71cb59741" , "1.3.46.670589.7.5.10.80002138018.20001204.181556.9.1.1.dcm" }, + +{ "f111ed4eea73f535261039d3f7b112e9" , "JPEGInvalidSecondFrag.dcm" }, + +// Computed with kakadu: +{ "a218fcee00e16d430f30ec7ebd4937dc" , "lena512_rot90.j2k.dcm" }, + + +/* Stopping condition */ +{ 0 ,0 } +}; diff --git a/gdcm/Testing/Source/Data/gdcmMediaStorageDataFiles.cxx b/gdcm/Testing/Source/Data/gdcmMediaStorageDataFiles.cxx new file mode 100644 index 0000000..7a24de0 --- /dev/null +++ b/gdcm/Testing/Source/Data/gdcmMediaStorageDataFiles.cxx @@ -0,0 +1,242 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http:/gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + + +/* + * gdcmscanner -d /path/to/gdcmData/ -t 8,16 -p + */ + +static const char * const gdcmMediaStorageDataFiles[][2] = { +{ "LEADTOOLS_FLOWERS-8-PAL-Uncompressed.dcm","1.2.840.10008.5.1.4.1.1.7" }, +{ "SIEMENS_GBS_III-16-ACR_NEMA_1.acr", "1.2.840.10008.5.1.4.1.1.4"}, +{ "00191113.dcm","1.2.840.10008.5.1.4.1.1.12.1"}, +{ "SignedShortLosslessBug.dcm","1.2.840.10008.5.1.4.1.1.2"}, +{ "gdcm-MR-PHILIPS-16-NonSquarePixels.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "MARCONI_MxTWin-12-MONO2-JpegLossless-ZeroLengthSQ.dcm","1.2.840.10008.5.1.4.1.1.2"}, +{ "ACUSON-24-YBR_FULL-RLE.dcm","1.2.840.10008.5.1.4.1.1.6.1"}, +{ "D_CLUNIE_VL2_RLE.dcm","1.2.840.10008.5.1.4.1.1.7"}, +{ "MR_Philips_Intera_No_PrivateSequenceImplicitVR.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "MR_Philips-Intera_BreaksNOSHADOW.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "D_CLUNIE_MR2_JPLL.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "D_CLUNIE_XA1_JPLL.dcm","1.2.840.10008.5.1.4.1.1.7"}, +{ "JPEG_LossyYBR.dcm","1.2.840.10008.5.1.4.1.1.6.1"}, +{ "ALOKA_SSD-8-MONO2-RLE-SQ.dcm","1.2.840.10008.5.1.4.1.1.6.1"}, +{ "PHILIPS_Gyroscan-8-MONO2-Odd_Sequence.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "PHILIPS_Gyroscan-12-MONO2-Jpeg_Lossless.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "MR-MONO2-12-shoulder.dcm","1.2.840.10008.5.1.4.1.1.4"}, +//{ "MR_SIEMENS_forceLoad29-1010_29-1020.README.txt (could not be read)}, +//{ "ExplicitVRforPublicElementsImplicitVRforShadowElements.README.txt (could not be read)}, +{ "D_CLUNIE_RG3_JPLY.dcm","1.2.840.10008.5.1.4.1.1.1"}, +{ "SIEMENS_SOMATOM-12-ACR_NEMA-ZeroLengthUs.acr","1.2.840.10008.5.1.4.1.1.2"}, +{ "PHILIPS_Gyroscan-12-Jpeg_Extended_Process_2_4.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "DICOMDIR_MR_B_VA12A" , "1.2.840.10008.1.3.10" }, +{ "MR-MONO2-8-16x-heart.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "SIEMENS_ImageLocationUN.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "US-PAL-8-10x-echo.dcm","1.2.840.10008.5.1.4.1.1.3.1"}, +{ "PHILIPS_Brilliance_ExtraBytesInOverlay.dcm","1.2.840.10008.5.1.4.1.1.7"}, +{ "SIEMENS_MAGNETOM-12-MONO2-Uncompressed.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "MR-MONO2-12-an2.acr","1.2.840.10008.5.1.4.1.1.4"}, +{ "LEADTOOLS_FLOWERS-8-PAL-RLE.dcm","1.2.840.10008.5.1.4.1.1.7"}, +{ "US-RGB-8-esopecho.dcm","1.2.840.10008.5.1.4.1.1.6"}, +{ "GE_RHAPSODE-16-MONO2-JPEG-Fragments.dcm","1.2.840.10008.5.1.4.1.1.2"}, +{ "CT-SIEMENS-Icone-With-PaletteColor.dcm","1.2.840.10008.5.1.4.1.1.2"}, +{ "gdcm-ACR-LibIDO.acr" , "1.2.840.10008.5.1.4.1.1.7"}, // COMPAT +{ "LEADTOOLS_FLOWERS-16-MONO2-Uncompressed.dcm","1.2.840.10008.5.1.4.1.1.7"}, +{ "FUJI-10-MONO1-ACR_NEMA_2.dcm","1.2.840.10008.5.1.4.1.1.1"}, +{ "D_CLUNIE_CT1_RLE.dcm","1.2.840.10008.5.1.4.1.1.2"}, +{ "undefined_length_un_vr.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "D_CLUNIE_MR4_JPLL.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "PET-cardio-Multiframe-Papyrus.dcm", "" }, +{ "dicomdir_Pms_WithVisit_WithPrivate_WithStudyComponents" , "1.2.840.10008.1.3.10"}, +{ "CT_16b_signed-UsedBits13.dcm","1.2.840.10008.5.1.4.1.1.2"}, +//{ "TestAllEntryVerifyReference.txt (could not be read)}, +{ "DX_J2K_0Padding.dcm","1.2.840.10008.5.1.4.1.1.1.1"}, +{ "KODAK_CompressedIcon.dcm","1.2.840.10008.5.1.4.1.1.1"}, +{ "D_CLUNIE_CT2_JPLL.dcm","1.2.840.10008.5.1.4.1.1.2"}, +{ "DermaColorLossLess.dcm","1.2.840.10008.5.1.4.1.1.7"}, +{ "DICOMDIR" , "1.2.840.10008.1.3.10" }, +{ "LIBIDO-24-ACR_NEMA-Rectangle.dcm", "" }, +{ "GE_GENESIS-16-MONO2-Uncompressed-UnusualVR.dcm","1.2.840.10008.5.1.4.1.1.4"}, +//{ "MR-SIEMENS-DICOM-WithOverlays.README.txt (could not be read)}, +{ "D_CLUNIE_NM1_JPLY.dcm","1.2.840.10008.5.1.4.1.1.7"}, +{ "MR_Philips_Intera_SwitchIndianess_noLgtSQItem_in_trueLgtSeq.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "LEADTOOLS_FLOWERS-24-RGB-JpegLossy.dcm","1.2.840.10008.5.1.4.1.1.7"}, +{ "D_CLUNIE_CT1_J2KR.dcm","1.2.840.10008.5.1.4.1.1.2"}, +{ "LEADTOOLS_FLOWERS-16-MONO2-RLE.dcm","1.2.840.10008.5.1.4.1.1.7"}, +{ "US-RGB-8-epicard.dcm","1.2.840.10008.5.1.4.1.1.6.1"}, +{ "D_CLUNIE_MR3_RLE.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "test.acr" ,"1.2.840.10008.5.1.4.1.1.7"}, // COMPAT +{ "LEADTOOLS_FLOWERS-8-MONO2-Uncompressed.dcm","1.2.840.10008.5.1.4.1.1.7"}, +{ "US-IRAD-NoPreambleStartWith0005.dcm","1.2.840.10008.5.1.4.1.1.6"}, +{ "D_CLUNIE_RG2_JPLL.dcm","1.2.840.10008.5.1.4.1.1.1"}, +{ "ELSCINT1_PMSCT_RLE1.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "DMCPACS_ExplicitImplicit_BogusIOP.dcm","1.2.840.10008.5.1.4.1.1.2"}, +{ "MR_ELSCINT1_00e1_1042_SQ_feff_00e0_Item.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "LIBIDO-16-ACR_NEMA-Volume.dcm", "" }, +//{ "Changelog (could not be read)}, +//{ "ELSCINT1_LOSSLESS_RICE.txt (could not be read)}, +{ "MR-SIEMENS-DICOM-WithOverlays.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "SIEMENS_MOSAIC_12BitsStored-16BitsJPEG.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "JDDICOM_Sample2-dcmdjpeg.dcm", "" }, +{ "SIEMENS_MAGNETOM-12-MONO2-FileSeq2.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "D_CLUNIE_MR3_JPLY.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "MR_Philips_Intera_PrivateSequenceExplicitVR_in_SQ_2001_e05f_item_wrong_lgt_use_NOSHADOWSEQ.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "TheralysGDCM120Bug.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "PrivateGEImplicitVRBigEndianTransferSyntax16Bits.dcm","1.2.840.10008.5.1.4.1.1.2"}, +{ "US-GE-4AICL142.dcm","1.2.840.10008.5.1.4.1.1.6.1"}, +{ "3E768EB7.dcm","1.2.840.10008.5.1.4.1.1.2"}, +//{ "gdcm-MR-PHILIPS-16-Multi-Seq.README.txt (could not be read)}, +{ "SIEMENS_Sonata-16-MONO2-Value_Multiplicity.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "GE_MR_0025xx1bProtocolDataBlock.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "MR_GE_with_Private_Compressed_Icon_0009_1110.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "ExplicitVRforPublicElementsImplicitVRforShadowElements.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "D_CLUNIE_SC1_JPLY.dcm","1.2.840.10008.5.1.4.1.1.7"}, +//{ "imagesWithOverlays.README.txt (could not be read)}, +{ "CT-MONO2-16-chest.dcm","1.2.840.10008.5.1.4.1.1.2"}, +{ "D_CLUNIE_MR4_RLE.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "gdcm-CR-DCMTK-16-NonSamplePerPix.dcm" , "" }, +{ "SIEMENS_MAGNETOM-12-MONO2-FileSeq1.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "ELSCINT1_JP2vsJ2K.dcm","1.2.840.10008.5.1.4.1.1.2"}, +{ "D_CLUNIE_CT2_RLE.dcm","1.2.840.10008.5.1.4.1.1.2"}, +{ "D_CLUNIE_MR2_RLE.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "OT-MONO2-8-a7.dcm","1.2.840.10008.5.1.4.1.1.7"}, +{ "MR-MONO2-16-head.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "PICKER-16-MONO2-No_DicomV3_Preamble.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "gdcm-JPEG-Extended.dcm","1.2.840.10008.5.1.4.1.1.2"}, +{ "MR-MONO2-12-angio-an1.acr", ""}, +{ "BugGDCM2_UndefItemWrongVL.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "D_CLUNIE_MR1_RLE.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "ELSCINT1_LOSSLESS_RICE.dcm","1.2.840.10008.5.1.4.1.1.2"}, +{ "dicomdir_Pms_With_heavy_embedded_sequence" , "1.2.840.10008.1.3.10" }, +{ "PICKER-16-MONO2-Nested_icon.dcm","1.2.840.10008.5.1.4.1.1.2"}, +{ "D_CLUNIE_VL4_RLE.dcm","1.2.840.10008.5.1.4.1.1.7"}, +{ "D_CLUNIE_RG1_RLE.dcm","1.2.840.10008.5.1.4.1.1.1"}, +{ "JDDICOM_Sample2.dcm", "" }, +{ "SIEMENS_MAGNETOM-12-MONO2-FileSeq3.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "CT-MONO2-8-abdo.dcm","1.2.840.10008.5.1.4.1.1.7"}, +{ "D_CLUNIE_SC1_RLE.dcm","1.2.840.10008.5.1.4.1.1.7"}, +{ "LEADTOOLS_FLOWERS-24-RGB-JpegLossless.dcm","1.2.840.10008.5.1.4.1.1.7"}, +{ "LIBIDO-8-ACR_NEMA-Lena_128_128.acr" , "" }, +{ "D_CLUNIE_RG3_JPLL.dcm","1.2.840.10008.5.1.4.1.1.1"}, +{ "SIEMENS_CSA2.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "SIEMENS_GBS_III-16-ACR_NEMA_1-ULis2Bytes.dcm", "" }, +{ "LJPEG_BuginGDCM12.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "CT-SIEMENS-MissingPixelDataInIconSQ.dcm","1.2.840.10008.5.1.4.1.1.2"}, +{ "05115014-mr-siemens-avanto-syngo-with-palette-icone.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "libido1.0-vol.acr" , "" }, +{ "MR_Spectroscopy_SIEMENS_OF.dcm","1.2.840.10008.5.1.4.1.1.4.2"}, +{ "GE_CT_With_Private_compressed-icon.dcm","1.2.840.10008.5.1.4.1.1.2"}, +{ "D_CLUNIE_XA1_JPLY.dcm","1.2.840.10008.5.1.4.1.1.7"}, +{ "012345.002.050.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "TOSHIBA_MRT150-16-MONO2-ACR_NEMA_2.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "LEADTOOLS_FLOWERS-8-MONO2-JpegLossy.dcm","1.2.840.10008.5.1.4.1.1.7"}, +{ "gdcm-US-ALOKA-16.dcm","1.2.840.10008.5.1.4.1.1.6.1"}, +{ "THERALYS-12-MONO2-Uncompressed-Even_Length_Tag.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "D_CLUNIE_CT1_JPLL.dcm","1.2.840.10008.5.1.4.1.1.2"}, +{ "rle16loo.dcm","1.2.840.10008.5.1.4.1.1.3.1"}, +{ "D_CLUNIE_US1_RLE.dcm","1.2.840.10008.5.1.4.1.1.6.1"}, +{ "LEADTOOLS_FLOWERS-8-MONO2-RLE.dcm","1.2.840.10008.5.1.4.1.1.7"}, +{ "RadBWLossLess.dcm","1.2.840.10008.5.1.4.1.1.7"}, +{ "dicomdir_Acusson_WithPrivate_WithSR" , "1.2.840.10008.1.3.10"}, +{ "D_CLUNIE_MR1_JPLY.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "GE_DLX-8-MONO2-PrivateSyntax.dcm","1.2.840.10008.5.1.4.1.1.12.1"}, +{ "gdcm-JPEG-LossLess3a.dcm","1.2.840.10008.5.1.4.1.1.2"}, +{ "TG18-CH-2k-01.dcm","1.2.840.10008.5.1.4.1.1.7"}, +{ "OT-PAL-8-face.dcm","1.2.840.10008.5.1.4.1.1.7"}, +{ "D_CLUNIE_NM1_RLE.dcm","1.2.840.10008.5.1.4.1.1.7"}, +{ "rle16sti.dcm","1.2.840.10008.5.1.4.1.1.6.1"}, +{ "GE_GENESIS-16-MONO2-WrongLengthItem.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "D_CLUNIE_CT1_J2KI.dcm","1.2.840.10008.5.1.4.1.1.2"}, +{ "SIEMENS_MAGNETOM-12-MONO2-FileSeq0.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "LEADTOOLS_FLOWERS-24-RGB-Uncompressed.dcm","1.2.840.10008.5.1.4.1.1.7"}, +{ "D_CLUNIE_MR4_JPLY.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "D_CLUNIE_RG3_RLE.dcm","1.2.840.10008.5.1.4.1.1.1"}, +{ "SIEMENS-12-Jpeg_Process_2_4-Lossy-a.dcm","1.2.840.10008.5.1.4.1.1.2"}, +{ "DICOMDIR-Philips-EasyVision-4200-Entries", "1.2.840.10008.1.3.10"}, +{ "CT-MONO2-16-brain.dcm","1.2.840.10008.5.1.4.1.1.2"}, +{ "D_CLUNIE_RG2_JPLY.dcm","1.2.840.10008.5.1.4.1.1.1"}, +{ "MAROTECH_CT_JP2Lossy.dcm","1.2.840.10008.5.1.4.1.1.2"}, +{ "D_CLUNIE_MR1_JPLL.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "ITK_GDCM124_MultiframeSecondaryCaptureInvalid.dcm","1.2.840.10008.5.1.4.1.1.7"}, +{ "dicomdir_With_embedded_icons", "1.2.840.10008.1.3.10"}, +{ "SIEMENS_MAGNETOM-12-ACR_NEMA_2-Modern.dcm", "" }, +{ "MR_SIEMENS_forceLoad29-1010_29-1020.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "simpleImageWithIcon.dcm","1.2.840.10008.5.1.4.1.1.7"}, +{ "D_CLUNIE_MR3_JPLL.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "D_CLUNIE_RG1_JPLL.dcm","1.2.840.10008.5.1.4.1.1.1"}, +{ "US-MONO2-8-8x-execho.dcm","1.2.840.10008.5.1.4.1.1.3"}, +{ "XA-MONO2-8-12x-catheter.dcm","1.2.840.10008.5.1.4.1.1.12.1"}, +//{ "TheralysGDCM120Bug.README.txt (could not be read)}, +{ "GE_LOGIQBook-8-RGB-HugePreview.dcm","1.2.840.10008.5.1.4.1.1.7"}, +//{ "MR_Philips_Intera_PrivateSequenceImplicitVR.README.txt (could not be read)}, +{ "gdcm-MR-SIEMENS-16-2.acr", ""}, +{ "gdcm-MR-PHILIPS-16-Multi-Seq.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "D_CLUNIE_XA1_RLE.dcm","1.2.840.10008.5.1.4.1.1.7"}, +{ "NM-MONO2-16-13x-heart.dcm","1.2.840.10008.5.1.4.1.1.20"}, +{ "gdcm-JPEG-LossLessThoravision.dcm","1.2.840.10008.5.1.4.1.1.1"}, +//{ "SIEMENS_MAGNETOM-12-MONO2-GDCM12-VRUN.txt (could not be read)}, +{ "GE_DLX-8-MONO2-Multiframe.dcm","1.2.840.10008.5.1.4.1.1.12.1"}, +{ "PHILIPS_Intera-16-MONO2-Uncompress.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "D_CLUNIE_MR2_JPLY.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "05148044-mr-siemens-avanto-syngo.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "D_CLUNIE_VL3_RLE.dcm","1.2.840.10008.5.1.4.1.1.7"}, +{ "D_CLUNIE_RG2_RLE.dcm","1.2.840.10008.5.1.4.1.1.1"}, +{ "SIEMENS_MAGNETOM-12-MONO2-GDCM12-VRUN.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "KODAK-12-MONO1-Odd_Terminated_Sequence.dcm","1.2.840.10008.5.1.4.1.1.1"}, +{ "SIEMENS-MR-RGB-16Bits.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "CR-MONO1-10-chest.dcm","1.2.840.10008.5.1.4.1.1.1"}, +{ "DX_GE_FALCON_SNOWY-VOI.dcm","1.2.840.10008.5.1.4.1.1.1.1"}, +{ "US-IRAD-NoPreambleStartWith0003.dcm","1.2.840.10008.5.1.4.1.1.6"}, +{ "MR-Brucker-CineTagging-NonSquarePixels.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "D_CLUNIE_VL6_RLE.dcm","1.2.840.10008.5.1.4.1.1.7"}, +{ "MR_Philips_Intera_PrivateSequenceImplicitVR.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "fffc0000UN.dcm","1.2.840.10008.5.1.4.1.1.7"}, +{ "CT-MONO2-12-lomb-an2.acr" , "" }, +{ "SIEMENS_Sonata-12-MONO2-SQ.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "ACUSON-24-YBR_FULL-RLE-b.dcm","1.2.840.10008.5.1.4.1.1.6.1"}, +{ "CT-MONO2-16-ankle.dcm","1.2.840.10008.5.1.4.1.1.7"}, +{ "GE_DLX-8-MONO2-Multiframe-Jpeg_Lossless.dcm","1.2.840.10008.5.1.4.1.1.12.1"}, +{ "MR-SIEMENS-DICOM-WithOverlays-extracted-overlays.dcm","1.2.840.10008.5.1.4.1.1.7"}, +{ "CT-MONO2-16-ort.dcm","1.2.840.10008.5.1.4.1.1.2"}, +{ "LEADTOOLS_FLOWERS-16-MONO2-JpegLossless.dcm","1.2.840.10008.5.1.4.1.1.7"}, +{ "D_CLUNIE_NM1_JPLL.dcm","1.2.840.10008.5.1.4.1.1.7"}, +{ "D_CLUNIE_VL1_RLE.dcm","1.2.840.10008.5.1.4.1.1.7"}, +{ "IM-0001-0066.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "SIEMENS_MAGNETOM-12-MONO2-VRUN.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "PhilipsInteraSeqTermInvLen.dcm","1.2.840.10008.5.1.4.1.1.4"}, +{ "PHILIPS_GDCM12xBug.dcm" , "1.2.840.10008.5.1.4.1.1.4" }, +{ "OsirixFake16BitsStoredFakeSpacing.dcm", "1.2.840.10008.5.1.4.1.1.7" }, +{ "IM-0001-0066.CommandTag00.dcm", "1.2.840.10008.5.1.4.1.1.4" }, +{ "AMIInvalidPrivateDefinedLengthSQasUN.dcm" , "1.2.840.10008.5.1.4.1.1.4" }, +{ "GDCMJ2K_TextGBR.dcm" , "1.2.840.10008.5.1.4.1.1.7" }, +{ "MR16BitsAllocated_8BitsStored.dcm" , "1.2.840.10008.5.1.4.1.1.4" }, +{ "D_CLUNIE_CT1_JLSL.dcm", "1.2.840.10008.5.1.4.1.1.2" }, +{ "JPEGDefinedLengthSequenceOfFragments.dcm" , "1.2.840.10008.5.1.4.1.1.2" }, +{ "PHILIPS_GDCM12xBug2.dcm" , "1.2.840.10008.5.1.4.1.1.4" }, +{ "DCMTK_JPEGExt_12Bits.dcm" , "1.2.840.10008.5.1.4.1.1.7" }, +{ "UnexpectedSequenceDelimiterInFixedLengthSequence.dcm" , "1.2.840.10008.5.1.4.1.1.20" }, +{ "NM_Kakadu44_SOTmarkerincons.dcm" , "1.2.840.10008.5.1.4.1.1.1" }, +{ "D_CLUNIE_CT1_JLSN.dcm", "1.2.840.10008.5.1.4.1.1.2" }, +{ "TOSHIBA_J2K_SIZ1_PixRep0.dcm", "1.2.840.10008.5.1.4.1.1.2"}, +{ "TOSHIBA_J2K_SIZ0_PixRep1.dcm", "1.2.840.10008.5.1.4.1.1.2" }, +{ "TOSHIBA_J2K_OpenJPEGv2Regression.dcm", "1.2.840.10008.5.1.4.1.1.2" }, +{ "NM-PAL-16-PixRep1.dcm", "1.2.840.10008.5.1.4.1.1.20" }, +{ "MEDILABInvalidCP246_EVRLESQasUN.dcm", "1.2.840.10008.5.1.4.1.1.2" }, +{ "JPEGInvalidSecondFrag.dcm", "1.2.840.10008.5.1.4.1.1.2" }, +{ "ELSCINT1_PMSCT_RLE1_priv.dcm", "1.2.840.10008.5.1.4.1.1.2" }, +{ "unreadable.dcm", "1.2.840.10008.5.1.4.1.1.2" }, + +/* Stopping condition */ +{ 0 ,0 } +}; diff --git a/gdcm/Testing/Source/Data/gdcmSelectedTagsOffsetDataFiles.cxx b/gdcm/Testing/Source/Data/gdcmSelectedTagsOffsetDataFiles.cxx new file mode 100644 index 0000000..ba6a1a8 --- /dev/null +++ b/gdcm/Testing/Source/Data/gdcmSelectedTagsOffsetDataFiles.cxx @@ -0,0 +1,233 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http:/gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + + +/* + * See TestReaderSelectedTags + */ + +#if 0 +struct StreamOffset +{ + const char *filename; + std::streamoff offset; +}; +#endif + +static const StreamOffset gdcmSelectedTagsOffsetDataFiles[] = { +{ "CT-MONO2-12-lomb-an2.acr",1222 }, +{ "LIBIDO-8-ACR_NEMA-Lena_128_128.acr",174 }, +{ "MR-MONO2-12-an2.acr",1858 }, +{ "SIEMENS_SOMATOM-12-ACR_NEMA-ZeroLengthUs.acr",5056 }, +{ "gdcm-ACR-LibIDO.acr",174 }, +{ "gdcm-MR-SIEMENS-16-2.acr",6044 }, +{ "libido1.0-vol.acr",162 }, +{ "test.acr",174 }, +{ "00191113.dcm",922 }, +{ "012345.002.050.dcm",9592 }, +{ "05115014-mr-siemens-avanto-syngo-with-palette-icone.dcm",41936 }, +{ "05148044-mr-siemens-avanto-syngo.dcm",55872 }, +{ "3E768EB7.dcm",3222 }, +{ "ACUSON-24-YBR_FULL-RLE-b.dcm",2020 }, +{ "ACUSON-24-YBR_FULL-RLE.dcm",1908 }, +{ "ALOKA_SSD-8-MONO2-RLE-SQ.dcm",1386 }, +{ "AMIInvalidPrivateDefinedLengthSQasUN.dcm",12732 }, +{ "BugGDCM2_UndefItemWrongVL.dcm",9562 }, +{ "CR-MONO1-10-chest.dcm",768 }, +{ "CT-MONO2-16-ankle.dcm",1140 }, +{ "CT-MONO2-16-brain.dcm",1668 }, +{ "CT-MONO2-16-chest.dcm",1626 }, +{ "CT-MONO2-16-ort.dcm",1666 }, +{ "CT-MONO2-8-abdo.dcm",788 }, +{ "CT-SIEMENS-Icone-With-PaletteColor.dcm",8150 }, +{ "CT-SIEMENS-MissingPixelDataInIconSQ.dcm",20496 }, +{ "CT_16b_signed-UsedBits13.dcm",2574 }, +{ "DCMTK_JPEGExt_12Bits.dcm",784 }, +{ "DMCPACS_ExplicitImplicit_BogusIOP.dcm",20018 }, +{ "DX_GE_FALCON_SNOWY-VOI.dcm",104002 }, +{ "DX_J2K_0Padding.dcm",1482 }, +{ "D_CLUNIE_CT1_J2KI.dcm",6584 }, +{ "D_CLUNIE_CT1_J2KR.dcm",6484 }, +{ "D_CLUNIE_CT1_JLSL.dcm",6452 }, +{ "D_CLUNIE_CT1_JLSN.dcm",6566 }, +{ "D_CLUNIE_CT1_JPLL.dcm",6456 }, +{ "D_CLUNIE_CT1_RLE.dcm",6390 }, +{ "D_CLUNIE_CT2_JPLL.dcm",1744 }, +{ "D_CLUNIE_CT2_RLE.dcm",1676 }, +{ "D_CLUNIE_MR1_JPLL.dcm",1750 }, +{ "D_CLUNIE_MR1_JPLY.dcm",1836 }, +{ "D_CLUNIE_MR1_RLE.dcm",1682 }, +{ "D_CLUNIE_MR2_JPLL.dcm",1946 }, +{ "D_CLUNIE_MR2_JPLY.dcm",2034 }, +{ "D_CLUNIE_MR2_RLE.dcm",1878 }, +{ "D_CLUNIE_MR3_JPLL.dcm",9570 }, +{ "D_CLUNIE_MR3_JPLY.dcm",9658 }, +{ "D_CLUNIE_MR3_RLE.dcm",9504 }, +{ "D_CLUNIE_MR4_JPLL.dcm",1968 }, +{ "D_CLUNIE_MR4_JPLY.dcm",2056 }, +{ "D_CLUNIE_MR4_RLE.dcm",1900 }, +{ "D_CLUNIE_NM1_JPLL.dcm",2890 }, +{ "D_CLUNIE_NM1_JPLY.dcm",2978 }, +{ "D_CLUNIE_NM1_RLE.dcm",2826 }, +{ "D_CLUNIE_RG1_JPLL.dcm",1858 }, +{ "D_CLUNIE_RG1_RLE.dcm",1794 }, +{ "D_CLUNIE_RG2_JPLL.dcm",1444 }, +{ "D_CLUNIE_RG2_JPLY.dcm",1532 }, +{ "D_CLUNIE_RG2_RLE.dcm",1368 }, +{ "D_CLUNIE_RG3_JPLL.dcm",1514 }, +{ "D_CLUNIE_RG3_JPLY.dcm",1602 }, +{ "D_CLUNIE_RG3_RLE.dcm",1432 }, +{ "D_CLUNIE_SC1_JPLY.dcm",1340 }, +{ "D_CLUNIE_SC1_RLE.dcm",1176 }, +{ "D_CLUNIE_US1_RLE.dcm",1306 }, +{ "D_CLUNIE_VL1_RLE.dcm",1188 }, +{ "D_CLUNIE_VL2_RLE.dcm",1186 }, +{ "D_CLUNIE_VL3_RLE.dcm",1198 }, +{ "D_CLUNIE_VL4_RLE.dcm",1180 }, +{ "D_CLUNIE_VL6_RLE.dcm",1198 }, +{ "D_CLUNIE_XA1_JPLL.dcm",1192 }, +{ "D_CLUNIE_XA1_JPLY.dcm",1280 }, +{ "D_CLUNIE_XA1_RLE.dcm",1116 }, +{ "DermaColorLossLess.dcm",928 }, +{ "ELSCINT1_JP2vsJ2K.dcm",1808 }, +{ "ELSCINT1_PMSCT_RLE1.dcm",67912 }, +{ "ExplicitVRforPublicElementsImplicitVRforShadowElements.dcm",9534 }, +{ "FUJI-10-MONO1-ACR_NEMA_2.dcm",854 }, +{ "GDCMJ2K_TextGBR.dcm",758 }, +{ "GE_CT_With_Private_compressed-icon.dcm",10798 }, +{ "GE_DLX-8-MONO2-Multiframe-Jpeg_Lossless.dcm",14126 }, +{ "GE_DLX-8-MONO2-Multiframe.dcm",4976 }, +{ "GE_DLX-8-MONO2-PrivateSyntax.dcm",2912 }, +{ "GE_GENESIS-16-MONO2-Uncompressed-UnusualVR.dcm",9654 }, +{ "GE_GENESIS-16-MONO2-WrongLengthItem.dcm",1922 }, +{ "GE_LOGIQBook-8-RGB-HugePreview.dcm",935596 }, +{ "GE_MR_0025xx1bProtocolDataBlock.dcm",11870 }, +{ "GE_RHAPSODE-16-MONO2-JPEG-Fragments.dcm",6456 }, +{ "IM-0001-0066.CommandTag00.dcm",3042 }, +{ "ITK_GDCM124_MultiframeSecondaryCaptureInvalid.dcm",1132 }, +{ "JDDICOM_Sample2-dcmdjpeg.dcm",836 }, +{ "JDDICOM_Sample2.dcm",822 }, +{ "JPEGDefinedLengthSequenceOfFragments.dcm",2862 }, +{ "JPEG_LossyYBR.dcm",2366 }, +{ "KODAK-12-MONO1-Odd_Terminated_Sequence.dcm",9126 }, +{ "KODAK_CompressedIcon.dcm",8634 }, +{ "LEADTOOLS_FLOWERS-16-MONO2-JpegLossless.dcm",1932 }, +{ "LEADTOOLS_FLOWERS-16-MONO2-RLE.dcm",1930 }, +{ "LEADTOOLS_FLOWERS-16-MONO2-Uncompressed.dcm",1930 }, +{ "LEADTOOLS_FLOWERS-24-RGB-JpegLossless.dcm",1924 }, +{ "LEADTOOLS_FLOWERS-24-RGB-JpegLossy.dcm",1924 }, +{ "LEADTOOLS_FLOWERS-24-RGB-Uncompressed.dcm",1922 }, +{ "LEADTOOLS_FLOWERS-8-MONO2-JpegLossy.dcm",1932 }, +{ "LEADTOOLS_FLOWERS-8-MONO2-RLE.dcm",1930 }, +{ "LEADTOOLS_FLOWERS-8-MONO2-Uncompressed.dcm",1930 }, +{ "LEADTOOLS_FLOWERS-8-PAL-RLE.dcm",3526 }, +{ "LEADTOOLS_FLOWERS-8-PAL-Uncompressed.dcm",3526 }, +{ "LIBIDO-24-ACR_NEMA-Rectangle.dcm",174 }, +{ "LJPEG_BuginGDCM12.dcm",2236 }, +{ "MARCONI_MxTWin-12-MONO2-JpegLossless-ZeroLengthSQ.dcm",1904 }, +{ "MAROTECH_CT_JP2Lossy.dcm",33844 }, +{ "MEDILABInvalidCP246_EVRLESQasUN.dcm",19162 }, +{ "MR-Brucker-CineTagging-NonSquarePixels.dcm",1530 }, +{ "MR-MONO2-12-shoulder.dcm",1568 }, +{ "MR-MONO2-16-head.dcm",1796 }, +{ "MR-MONO2-8-16x-heart.dcm",908 }, +{ "MR-SIEMENS-DICOM-WithOverlays-extracted-overlays.dcm",42600 }, +{ "MR-SIEMENS-DICOM-WithOverlays.dcm",42404 }, +{ "MR16BitsAllocated_8BitsStored.dcm",928 }, +{ "MR_ELSCINT1_00e1_1042_SQ_feff_00e0_Item.dcm",7696 }, +{ "MR_GE_with_Private_Compressed_Icon_0009_1110.dcm",20700 }, +{ "MR_Philips-Intera_BreaksNOSHADOW.dcm",7618 }, +{ "MR_Philips_Intera_No_PrivateSequenceImplicitVR.dcm",9500 }, +{ "MR_Philips_Intera_PrivateSequenceExplicitVR_in_SQ_2001_e05f_item_wrong_lgt_use_NOSHADOWSEQ.dcm",7512 }, +{ "MR_Philips_Intera_PrivateSequenceImplicitVR.dcm",7018 }, +{ "MR_Philips_Intera_SwitchIndianess_noLgtSQItem_in_trueLgtSeq.dcm",9264 }, +{ "MR_SIEMENS_forceLoad29-1010_29-1020.dcm",60556 }, +{ "MR_Spectroscopy_SIEMENS_OF.dcm",2102344 }, +{ "NM-MONO2-16-13x-heart.dcm",1222 }, +{ "NM-PAL-16-PixRep1.dcm",4432 }, +{ "NM_Kakadu44_SOTmarkerincons.dcm",1564 }, +{ "OT-MONO2-8-a7.dcm",430 }, +{ "OT-PAL-8-face.dcm",1646 }, +{ "OsirixFake16BitsStoredFakeSpacing.dcm",1306 }, +{ "PHILIPS_Brilliance_ExtraBytesInOverlay.dcm",34538 }, +{ "PHILIPS_GDCM12xBug.dcm",9330 }, +{ "PHILIPS_GDCM12xBug2.dcm",9662 }, +{ "PHILIPS_Gyroscan-12-Jpeg_Extended_Process_2_4.dcm",5944 }, +{ "PHILIPS_Gyroscan-12-MONO2-Jpeg_Lossless.dcm",15366 }, +{ "PHILIPS_Gyroscan-8-MONO2-Odd_Sequence.dcm",6576 }, +{ "PHILIPS_Intera-16-MONO2-Uncompress.dcm",9264 }, +{ "PICKER-16-MONO2-Nested_icon.dcm",18220 }, +{ "PICKER-16-MONO2-No_DicomV3_Preamble.dcm",1398 }, +{ "PhilipsInteraSeqTermInvLen.dcm",7440 }, +{ "PrivateGEImplicitVRBigEndianTransferSyntax16Bits.dcm",14964 }, +{ "RadBWLossLess.dcm",930 }, +{ "SIEMENS-12-Jpeg_Process_2_4-Lossy-a.dcm",3032 }, +{ "SIEMENS-MR-RGB-16Bits.dcm",49840 }, +{ "SIEMENS_CSA2.dcm",104340 }, +{ "SIEMENS_ImageLocationUN.dcm",6336 }, +{ "SIEMENS_MAGNETOM-12-ACR_NEMA_2-Modern.dcm",6044 }, +{ "SIEMENS_MAGNETOM-12-MONO2-FileSeq0.dcm",6422 }, +{ "SIEMENS_MAGNETOM-12-MONO2-FileSeq1.dcm",6422 }, +{ "SIEMENS_MAGNETOM-12-MONO2-FileSeq2.dcm",6422 }, +{ "SIEMENS_MAGNETOM-12-MONO2-FileSeq3.dcm",6422 }, +{ "SIEMENS_MAGNETOM-12-MONO2-GDCM12-VRUN.dcm",5158 }, +{ "SIEMENS_MAGNETOM-12-MONO2-Uncompressed.dcm",5148 }, +{ "SIEMENS_MAGNETOM-12-MONO2-VRUN.dcm",5290 }, +{ "SIEMENS_MOSAIC_12BitsStored-16BitsJPEG.dcm",105714 }, +{ "SIEMENS_Sonata-12-MONO2-SQ.dcm",51792 }, +{ "SIEMENS_Sonata-16-MONO2-Value_Multiplicity.dcm",25674 }, +{ "SignedShortLosslessBug.dcm",1772 }, +{ "TG18-CH-2k-01.dcm",2300 }, +{ "THERALYS-12-MONO2-Uncompressed-Even_Length_Tag.dcm",1831 }, +{ "TOSHIBA_J2K_OpenJPEGv2Regression.dcm",2350 }, +{ "TOSHIBA_J2K_SIZ0_PixRep1.dcm",2334 }, +{ "TOSHIBA_J2K_SIZ1_PixRep0.dcm",2350 }, +{ "TOSHIBA_MRT150-16-MONO2-ACR_NEMA_2.dcm",1122 }, +{ "TheralysGDCM120Bug.dcm",8438 }, +{ "US-GE-4AICL142.dcm",14060 }, +{ "US-IRAD-NoPreambleStartWith0003.dcm",3322 }, +{ "US-IRAD-NoPreambleStartWith0005.dcm",2482 }, +{ "US-MONO2-8-8x-execho.dcm",964 }, +{ "US-PAL-8-10x-echo.dcm",2416 }, +{ "US-RGB-8-epicard.dcm",1000 }, +{ "US-RGB-8-esopecho.dcm",892 }, +{ "UnexpectedSequenceDelimiterInFixedLengthSequence.dcm",4178 }, +{ "XA-MONO2-8-12x-catheter.dcm",994 }, +{ "fffc0000UN.dcm",1142 }, +{ "gdcm-CR-DCMTK-16-NonSamplePerPix.dcm",728 }, +{ "gdcm-JPEG-Extended.dcm",2934 }, +{ "gdcm-JPEG-LossLess3a.dcm",2528 }, +{ "gdcm-JPEG-LossLessThoravision.dcm",3132 }, +{ "gdcm-MR-PHILIPS-16-Multi-Seq.dcm",35834 }, +{ "gdcm-MR-PHILIPS-16-NonSquarePixels.dcm",4998 }, +{ "gdcm-US-ALOKA-16.dcm",258732 }, +{ "rle16loo.dcm",394214 }, +{ "rle16sti.dcm",394158 }, +{ "simpleImageWithIcon.dcm",17466 }, +{ "undefined_length_un_vr.dcm",9156 }, +{ "JPEGInvalidSecondFrag.dcm",4788 }, +{ "lena512_rot90.j2k.dcm",756 }, +{ "ELSCINT1_PMSCT_RLE1_priv.dcm",298002 }, +{ "00191113.dcm",922 }, +{ "dicomdir_Acusson_WithPrivate_WithSR",3826 }, +{ "dicomdir_Pms_WithVisit_WithPrivate_WithStudyComponents",37218 }, +{ "dicomdir_Pms_With_heavy_embedded_sequence",3003414 }, +{ "dicomdir_With_embedded_icons",7125212 }, +{ "DICOMDIR",1112434 }, +{ "DICOMDIR-Philips-EasyVision-4200-Entries",1297194 }, +{ "DICOMDIR_MR_B_VA12A",14853880 }, + +/* Stopping condition */ +{ 0 ,0 }, +}; diff --git a/gdcm/Testing/Source/Data/gdcmStreamOffsetDataFiles.cxx b/gdcm/Testing/Source/Data/gdcmStreamOffsetDataFiles.cxx new file mode 100644 index 0000000..b12ee3c --- /dev/null +++ b/gdcm/Testing/Source/Data/gdcmStreamOffsetDataFiles.cxx @@ -0,0 +1,232 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http:/gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + + +/* + * See TestReaderUpToTag + */ +struct StreamOffset +{ + const char *filename; + std::streamoff offset; +}; + +static const StreamOffset gdcmStreamOffsetDataFiles[] = { +{ "00191113.dcm",934 }, +{ "012345.002.050.dcm",9604 }, +{ "05115014-mr-siemens-avanto-syngo-with-palette-icone.dcm",41948 }, +{ "05148044-mr-siemens-avanto-syngo.dcm",55884 }, +{ "3E768EB7.dcm",3234 }, +{ "ACUSON-24-YBR_FULL-RLE-b.dcm",2032 }, +{ "ACUSON-24-YBR_FULL-RLE.dcm",1920 }, +{ "ALOKA_SSD-8-MONO2-RLE-SQ.dcm",1398 }, +{ "AMIInvalidPrivateDefinedLengthSQasUN.dcm", 12744 }, +{ "BugGDCM2_UndefItemWrongVL.dcm",9570 }, +{ "CR-MONO1-10-chest.dcm",776 }, +{ "CT-MONO2-12-lomb-an2.acr",1230 }, +{ "CT-MONO2-16-ankle.dcm",1148 }, +{ "CT-MONO2-16-brain.dcm",1680 }, +{ "CT-MONO2-16-chest.dcm",1638 }, +{ "CT-MONO2-16-ort.dcm",1674 }, +{ "CT-MONO2-8-abdo.dcm",796 }, +{ "CT-SIEMENS-Icone-With-PaletteColor.dcm",8162 }, +{ "CT-SIEMENS-MissingPixelDataInIconSQ.dcm",20504 }, +{ "CT_16b_signed-UsedBits13.dcm",2582 }, +{ "DCMTK_JPEGExt_12Bits.dcm",796 }, +{ "DICOMDIR",1112434 }, +{ "DICOMDIR-Philips-EasyVision-4200-Entries",1297194 }, +{ "DICOMDIR_MR_B_VA12A", 14853880}, +{ "DMCPACS_ExplicitImplicit_BogusIOP.dcm",66618 }, +{ "DX_GE_FALCON_SNOWY-VOI.dcm",104014 }, +{ "DX_J2K_0Padding.dcm",1494 }, +{ "D_CLUNIE_CT1_J2KI.dcm",6596 }, +{ "D_CLUNIE_CT1_J2KR.dcm",6496 }, +{ "D_CLUNIE_CT1_JLSL.dcm", 6464 }, +{ "D_CLUNIE_CT1_JLSN.dcm", 6578 }, +{ "D_CLUNIE_CT1_JPLL.dcm",6468 }, +{ "D_CLUNIE_CT1_RLE.dcm",6402 }, +{ "D_CLUNIE_CT2_JPLL.dcm",1756 }, +{ "D_CLUNIE_CT2_RLE.dcm",1688 }, +{ "D_CLUNIE_MR1_JPLL.dcm",1762 }, +{ "D_CLUNIE_MR1_JPLY.dcm",1848 }, +{ "D_CLUNIE_MR1_RLE.dcm",1694 }, +{ "D_CLUNIE_MR2_JPLL.dcm",1958 }, +{ "D_CLUNIE_MR2_JPLY.dcm",2046 }, +{ "D_CLUNIE_MR2_RLE.dcm",1890 }, +{ "D_CLUNIE_MR3_JPLL.dcm",9582 }, +{ "D_CLUNIE_MR3_JPLY.dcm",9670 }, +{ "D_CLUNIE_MR3_RLE.dcm",9516 }, +{ "D_CLUNIE_MR4_JPLL.dcm",1980 }, +{ "D_CLUNIE_MR4_JPLY.dcm",2068 }, +{ "D_CLUNIE_MR4_RLE.dcm",1912 }, +{ "D_CLUNIE_NM1_JPLL.dcm",2902 }, +{ "D_CLUNIE_NM1_JPLY.dcm",2990 }, +{ "D_CLUNIE_NM1_RLE.dcm",2838 }, +{ "D_CLUNIE_RG1_JPLL.dcm",1870 }, +{ "D_CLUNIE_RG1_RLE.dcm",1806 }, +{ "D_CLUNIE_RG2_JPLL.dcm",1456 }, +{ "D_CLUNIE_RG2_JPLY.dcm",1544 }, +{ "D_CLUNIE_RG2_RLE.dcm",1380 }, +{ "D_CLUNIE_RG3_JPLL.dcm",1526 }, +{ "D_CLUNIE_RG3_JPLY.dcm",1614 }, +{ "D_CLUNIE_RG3_RLE.dcm",1444 }, +{ "D_CLUNIE_SC1_JPLY.dcm",1352 }, +{ "D_CLUNIE_SC1_RLE.dcm",1188 }, +{ "D_CLUNIE_US1_RLE.dcm",1318 }, +{ "D_CLUNIE_VL1_RLE.dcm",1200 }, +{ "D_CLUNIE_VL2_RLE.dcm",1198 }, +{ "D_CLUNIE_VL3_RLE.dcm",1210 }, +{ "D_CLUNIE_VL4_RLE.dcm",1192 }, +{ "D_CLUNIE_VL6_RLE.dcm",1210 }, +{ "D_CLUNIE_XA1_JPLL.dcm",1204 }, +{ "D_CLUNIE_XA1_JPLY.dcm",1292 }, +{ "D_CLUNIE_XA1_RLE.dcm",1128 }, +{ "DermaColorLossLess.dcm",940 }, +{ "ELSCINT1_JP2vsJ2K.dcm",1820 }, +{ "ELSCINT1_PMSCT_RLE1.dcm",67912 }, +{ "ExplicitVRforPublicElementsImplicitVRforShadowElements.dcm",9546 }, +{ "FUJI-10-MONO1-ACR_NEMA_2.dcm",862 }, +{ "GE_CT_With_Private_compressed-icon.dcm",10810 }, +{ "GE_DLX-8-MONO2-Multiframe-Jpeg_Lossless.dcm",14138 }, +{ "GE_DLX-8-MONO2-Multiframe.dcm",4984 }, +{ "GE_DLX-8-MONO2-PrivateSyntax.dcm",2920 }, +{ "GE_GENESIS-16-MONO2-Uncompressed-UnusualVR.dcm",9666 }, +{ "GE_GENESIS-16-MONO2-WrongLengthItem.dcm",1930 }, +{ "GE_LOGIQBook-8-RGB-HugePreview.dcm",935608 }, +{ "GE_MR_0025xx1bProtocolDataBlock.dcm",11882 }, +{ "GE_RHAPSODE-16-MONO2-JPEG-Fragments.dcm",6468 }, +{ "ITK_GDCM124_MultiframeSecondaryCaptureInvalid.dcm",1144 }, +{ "JDDICOM_Sample2-dcmdjpeg.dcm",848 }, +{ "JDDICOM_Sample2.dcm",834 }, +{ "JPEGDefinedLengthSequenceOfFragments.dcm",2874 }, +{ "JPEG_LossyYBR.dcm",2378 }, +{ "KODAK-12-MONO1-Odd_Terminated_Sequence.dcm",9134 }, +{ "KODAK_CompressedIcon.dcm",8646 }, +{ "LEADTOOLS_FLOWERS-16-MONO2-JpegLossless.dcm",1944 }, +{ "LEADTOOLS_FLOWERS-16-MONO2-RLE.dcm",1942 }, +{ "LEADTOOLS_FLOWERS-16-MONO2-Uncompressed.dcm",1942 }, +{ "LEADTOOLS_FLOWERS-24-RGB-JpegLossless.dcm",1936 }, +{ "LEADTOOLS_FLOWERS-24-RGB-JpegLossy.dcm",1936 }, +{ "LEADTOOLS_FLOWERS-24-RGB-Uncompressed.dcm",1934 }, +{ "LEADTOOLS_FLOWERS-8-MONO2-JpegLossy.dcm",1944 }, +{ "LEADTOOLS_FLOWERS-8-MONO2-RLE.dcm",1942 }, +{ "LEADTOOLS_FLOWERS-8-MONO2-Uncompressed.dcm",1942 }, +{ "LEADTOOLS_FLOWERS-8-PAL-RLE.dcm",3538 }, +{ "LEADTOOLS_FLOWERS-8-PAL-Uncompressed.dcm",3538 }, +{ "LIBIDO-8-ACR_NEMA-Lena_128_128.acr",182 }, +{ "LJPEG_BuginGDCM12.dcm",2248 }, +{ "MARCONI_MxTWin-12-MONO2-JpegLossless-ZeroLengthSQ.dcm",1916 }, +{ "MAROTECH_CT_JP2Lossy.dcm",33856 }, +{ "MR-Brucker-CineTagging-NonSquarePixels.dcm",1542 }, +{ "MR-MONO2-12-an2.acr",1866 }, +{ "MR-MONO2-12-angio-an1.acr",650 }, +{ "MR-MONO2-12-shoulder.dcm",1580 }, +{ "MR-MONO2-16-head.dcm",1804 }, +{ "MR-MONO2-8-16x-heart.dcm",920 }, +{ "MR-SIEMENS-DICOM-WithOverlays-extracted-overlays.dcm", 42612 }, +{ "MR-SIEMENS-DICOM-WithOverlays.dcm",42416 }, +{ "MR16BitsAllocated_8BitsStored.dcm",940 }, +{ "MR_ELSCINT1_00e1_1042_SQ_feff_00e0_Item.dcm",7704 }, +{ "MR_GE_with_Private_Compressed_Icon_0009_1110.dcm",20712 }, +{ "MR_Philips-Intera_BreaksNOSHADOW.dcm",7626 }, +{ "MR_Philips_Intera_No_PrivateSequenceImplicitVR.dcm",9508 }, +{ "MR_Philips_Intera_PrivateSequenceExplicitVR_in_SQ_2001_e05f_item_wrong_lgt_use_NOSHADOWSEQ.dcm",7524 }, +{ "MR_Philips_Intera_PrivateSequenceImplicitVR.dcm",7026 }, +{ "MR_Philips_Intera_SwitchIndianess_noLgtSQItem_in_trueLgtSeq.dcm",9276 }, +{ "MR_SIEMENS_forceLoad29-1010_29-1020.dcm",60564 }, +{ "MR_Spectroscopy_SIEMENS_OF.dcm",2102344 }, +{ "NM-MONO2-16-13x-heart.dcm",1234 }, +{ "OT-MONO2-8-a7.dcm",438 }, +{ "OT-PAL-8-face.dcm",1654 }, +{ "OsirixFake16BitsStoredFakeSpacing.dcm",1318 }, +{ "PHILIPS_Brilliance_ExtraBytesInOverlay.dcm",34550 }, +{ "PHILIPS_GDCM12xBug.dcm",9338 }, +{ "PHILIPS_GDCM12xBug2.dcm",9670 }, +{ "PHILIPS_Gyroscan-12-MONO2-Jpeg_Lossless.dcm",15378 }, +{ "PHILIPS_Gyroscan-8-MONO2-Odd_Sequence.dcm", 6584 }, +{ "PHILIPS_Intera-16-MONO2-Uncompress.dcm",9276 }, +{ "PICKER-16-MONO2-Nested_icon.dcm",18228 }, +{ "PICKER-16-MONO2-No_DicomV3_Preamble.dcm",1406 }, +{ "PrivateGEImplicitVRBigEndianTransferSyntax16Bits.dcm",14972 }, +{ "RadBWLossLess.dcm",942 }, +{ "SIEMENS-12-Jpeg_Process_2_4-Lossy-a.dcm",3044 }, +{ "SIEMENS-MR-RGB-16Bits.dcm",49852 }, +{ "SIEMENS_CSA2.dcm",104352 }, +{ "SIEMENS_ImageLocationUN.dcm",6348 }, +{ "SIEMENS_MAGNETOM-12-ACR_NEMA_2-Modern.dcm",6052 }, +{ "SIEMENS_MAGNETOM-12-MONO2-FileSeq0.dcm",6430 }, +{ "SIEMENS_MAGNETOM-12-MONO2-FileSeq1.dcm",6430 }, +{ "SIEMENS_MAGNETOM-12-MONO2-FileSeq2.dcm",6430 }, +{ "SIEMENS_MAGNETOM-12-MONO2-FileSeq3.dcm",6430 }, +{ "SIEMENS_MAGNETOM-12-MONO2-GDCM12-VRUN.dcm",5170 }, +{ "SIEMENS_MAGNETOM-12-MONO2-Uncompressed.dcm",5160 }, +{ "SIEMENS_MAGNETOM-12-MONO2-VRUN.dcm",5302 }, +{ "SIEMENS_MOSAIC_12BitsStored-16BitsJPEG.dcm",105726 }, +{ "SIEMENS_SOMATOM-12-ACR_NEMA-ZeroLengthUs.acr",5064 }, +{ "SIEMENS_Sonata-12-MONO2-SQ.dcm",51804 }, +{ "SIEMENS_Sonata-16-MONO2-Value_Multiplicity.dcm",25686 }, +{ "SignedShortLosslessBug.dcm",1784 }, +{ "TG18-CH-2k-01.dcm",2308 }, +{ "THERALYS-12-MONO2-Uncompressed-Even_Length_Tag.dcm",1839 }, +{ "TOSHIBA_MRT150-16-MONO2-ACR_NEMA_2.dcm",1130 }, +{ "TheralysGDCM120Bug.dcm",8450 }, +{ "US-GE-4AICL142.dcm",14072 }, +{ "US-IRAD-NoPreambleStartWith0003.dcm",3330 }, +{ "US-IRAD-NoPreambleStartWith0005.dcm",2490 }, +{ "US-MONO2-8-8x-execho.dcm",976 }, +{ "US-PAL-8-10x-echo.dcm",2428 }, +{ "US-RGB-8-epicard.dcm",1012 }, +{ "US-RGB-8-esopecho.dcm",904 }, +{ "XA-MONO2-8-12x-catheter.dcm",1006 }, +{ "dicomdir_Acusson_WithPrivate_WithSR",3826 }, +{ "dicomdir_Pms_WithVisit_WithPrivate_WithStudyComponents",37218 }, +{ "dicomdir_Pms_With_heavy_embedded_sequence",3003414 }, +{ "dicomdir_With_embedded_icons", 7125212 }, +{ "fffc0000UN.dcm",1154 }, +{ "gdcm-ACR-LibIDO.acr",182 }, +{ "gdcm-CR-DCMTK-16-NonSamplePerPix.dcm",740 }, +{ "gdcm-JPEG-Extended.dcm",2946 }, +{ "gdcm-JPEG-LossLess3a.dcm",2540 }, +{ "gdcm-JPEG-LossLessThoravision.dcm",3144 }, +{ "gdcm-MR-PHILIPS-16-Multi-Seq.dcm",35846 }, +{ "gdcm-MR-PHILIPS-16-NonSquarePixels.dcm",5010 }, +{ "gdcm-MR-SIEMENS-16-2.acr",6052 }, +{ "gdcm-US-ALOKA-16.dcm",258740 }, +{ "libido1.0-vol.acr",170 }, +{ "rle16loo.dcm",394226 }, +{ "rle16sti.dcm",394170 }, +{ "simpleImageWithIcon.dcm",17478 }, +{ "test.acr",182 }, +{ "undefined_length_un_vr.dcm",9168 }, +{ "IM-0001-0066.CommandTag00.dcm", 3050 }, +{ "PHILIPS_Gyroscan-12-Jpeg_Extended_Process_2_4.dcm", 5956 }, +{ "UnexpectedSequenceDelimiterInFixedLengthSequence.dcm", 4190 }, +{ "GDCMJ2K_TextGBR.dcm", 770 }, +{ "NM_Kakadu44_SOTmarkerincons.dcm", 1576 }, +{ "PhilipsInteraSeqTermInvLen.dcm", 7452}, +{ "LIBIDO-24-ACR_NEMA-Rectangle.dcm", 182 }, +{ "TOSHIBA_J2K_SIZ1_PixRep0.dcm", 2362 }, +{ "TOSHIBA_J2K_OpenJPEGv2Regression.dcm", 2362 }, +{ "TOSHIBA_J2K_SIZ0_PixRep1.dcm", 2346 }, +{ "NM-PAL-16-PixRep1.dcm", 4444 }, +{ "MEDILABInvalidCP246_EVRLESQasUN.dcm", 19174 }, +{ "JPEGInvalidSecondFrag.dcm", 4800 }, +{ "lena512_rot90.j2k.dcm", 768 }, +{ "ELSCINT1_PMSCT_RLE1_priv.dcm", 298002 }, +{ "unreadable.dcm", 249230 }, + + +/* Stopping condition */ +{ 0 ,0 }, +}; diff --git a/gdcm/Testing/Source/Data/out.bin b/gdcm/Testing/Source/Data/out.bin new file mode 100644 index 0000000000000000000000000000000000000000..38dfcfff3ad1fc47ec39e5cee398c1d86b531dd5 GIT binary patch literal 473 zcmXqLV!X=6snzDu_MMlJoq0hM<1vFK#zRbu42DgNc|c|skZBNP;A+Tiz{$oO%EBhh zYpRQcD!VGgHztONtc&N-7n6 zN>Z3O8P-h8?Wm{<++x5Bx0aESm4T&+k>RMGaOSzA_gAca_w%YT&r^5zhB?)$%E|_smzcFWLI;=<27P-P7Z| zEN8LJDq~%;WZy|0uQ|@!l9zWp(vK)?;xw6@rc_qjYUlHM;p6kW|41!7P}safQ~9cO z$`RXVn_ZIaq>HV+_8Cn)vcdbj4X0|%y|DJ+tnLkFL7mTcTH1Xza5#0+!~K4z)SpF9 zXW3d$zwRV{#;4d(?b5u9)8=lFp0z45c@ppItuwwR)i^Jmm6e`2GxFri>jfVJmYj9k z*4}gD + +int TestDicts(int, char *[]) +{ + gdcm::Dicts dicts; + //const gdcm::Dict &d = dicts.GetPublicDict(); + //std::cout << d << std::endl; + + const gdcm::Global& g = gdcm::GlobalInstance; + // get the Part 6 dicts from it: + const gdcm::Dicts &ds = g.GetDicts(); + const gdcm::Dict &pub = ds.GetPublicDict(); + gdcm::Dict::ConstIterator it = pub.Begin(); + int ret = 0; + std::set names; + for( ; it != pub.End(); ++it) + { + const gdcm::Tag &t = it->first; + const gdcm::DictEntry &de = it->second; + // A couple of tests: + if( t.GetElement() == 0x0 ) + { + // Check group length + if( de.GetVR() != gdcm::VR::UL || de.GetVM() != gdcm::VM::VM1 ) + { + std::cerr << "Group length issue: Problem with tag: " << t << " " << de << std::endl; + ++ret; + } + } + // I need a test that check there is no duplicate name for data elements since python-gdcm + // will rely on it + if( names.count( de.GetName() ) != 0 ) + { + //std::cerr << "Name issue: Problem with tag: " << t << " " << de << std::endl; + //++ret; + } + names.insert( de.GetName() ); + } + + return ret; +} diff --git a/gdcm/Testing/Source/DataDictionary/Cxx/TestGlobal.cxx b/gdcm/Testing/Source/DataDictionary/Cxx/TestGlobal.cxx new file mode 100644 index 0000000..f140a81 --- /dev/null +++ b/gdcm/Testing/Source/DataDictionary/Cxx/TestGlobal.cxx @@ -0,0 +1,118 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmGlobal.h" +#include "gdcmDicts.h" +#include "gdcmDict.h" +#include "gdcmDefs.h" + +int TestGlobal(int, char *[]) +{ + // case 1 + // Get the global singleton: + gdcm::Trace::DebugOn(); + gdcm::Global& g = gdcm::Global::GetInstance(); + if( !g.LoadResourcesFiles() ) + { + std::cerr << "Could not LoadResourcesFiles" << std::endl; + return 1; + } + gdcm::Trace::DebugOff(); + // get the Part 6 dicts from it: + const gdcm::Dicts &ds = g.GetDicts(); + const gdcm::Dict &pub = ds.GetPublicDict(); + const gdcm::PrivateDict &priv = ds.GetPrivateDict(); + + // case 2 + gdcm::Dicts dicts; + const gdcm::Dict &d1 = dicts.GetPublicDict(); + + // case 3 + gdcm::Dict d2; + + // This one will be empty: + std::cout << "Empty dict:" << std::endl; + std::cout << d1 << std::endl; + if( !d1.IsEmpty() ) + { + return 1; + } + // This one will be empty: + std::cout << "Empty dict:" << std::endl; + std::cout << d2 << std::endl; + if( !d2.IsEmpty() ) + { + return 1; + } + // This should should be filled in: + std::cout << "Global pub dict:" << std::endl; + //std::cout << pub << std::endl; + if( pub.IsEmpty() ) + { + return 1; + } + // This should should be filled in: + std::cout << "Global priv dict:" << std::endl; + //std::cout << priv << std::endl; + if( priv.IsEmpty() ) + { + return 1; + } +#if 0 + // FIXME I do not understand what was wrong before... + // I had to change the PrivateTag to use lower case to support this: + const gdcm::DictEntry& de1 = priv.GetDictEntry( gdcm::PrivateTag(0x2001,0x0001,"Philips Imaging DD 001") ); + std::cout << de1 << std::endl; + + const gdcm::DictEntry& de2 = priv.GetDictEntry( gdcm::PrivateTag(0x2001,0x0001,"PHILIPS IMAGING DD 001") ); + std::cout << de2 << std::endl; + if( &de1 != &de2 ) + { + return 1; + } + + const gdcm::DictEntry& de3 = priv.GetDictEntry( gdcm::PrivateTag(0x2001,0x0003,"Philips Imaging DD 001") ); + std::cout << de3 << std::endl; + + const gdcm::DictEntry& de4 = priv.GetDictEntry( gdcm::PrivateTag(0x2001,0x0003,"PHILIPS IMAGING DD 001") ); + std::cout << de4 << std::endl; + if( &de4 != &de3 ) + { + return 1; + } +#endif + +#if 0 + const char *empty = ""; + std::string s = empty; + std::cout << s.empty() << std::endl; + const gdcm::DictEntry& de = pub.GetDictEntry( gdcm::Tag(0x0028,0x0015) ); + const char *v = de.GetName(); + //assert( v ); + std::cout << "TOTO:" << de << std::endl; +#endif + + const gdcm::Defs &defs = g.GetDefs(); + + const gdcm::Modules &modules = defs.GetModules(); + std::cout << modules << std::endl; + + const gdcm::Macros ¯os = defs.GetMacros(); + std::cout << macros << std::endl; + + const gdcm::IODs &iods = defs.GetIODs(); + std::cout << iods << std::endl; + + + return 0; +} diff --git a/gdcm/Testing/Source/DataDictionary/Cxx/TestGroupDict.cxx b/gdcm/Testing/Source/DataDictionary/Cxx/TestGroupDict.cxx new file mode 100644 index 0000000..1b02b50 --- /dev/null +++ b/gdcm/Testing/Source/DataDictionary/Cxx/TestGroupDict.cxx @@ -0,0 +1,24 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmGroupDict.h" + +#include + +int TestGroupDict(int , char *[]) +{ + gdcm::GroupDict gd; + std::cout << gd << std::endl; + + return 0; +} diff --git a/gdcm/Testing/Source/DataDictionary/Cxx/TestSOPClassUIDToIOD.cxx b/gdcm/Testing/Source/DataDictionary/Cxx/TestSOPClassUIDToIOD.cxx new file mode 100644 index 0000000..90afe19 --- /dev/null +++ b/gdcm/Testing/Source/DataDictionary/Cxx/TestSOPClassUIDToIOD.cxx @@ -0,0 +1,41 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmSOPClassUIDToIOD.h" + +#include + +int TestSOPClassUIDToIOD(int, char *[]) +{ + + gdcm::SOPClassUIDToIOD::SOPClassUIDToIODType& s = gdcm::SOPClassUIDToIOD::GetSOPClassUIDToIOD(0); + std::cout << s[0] << std::endl; + if( std::string(s[0] ) != "1.2.840.10008.1.3.10" ) return 1; + std::cout << s[1] << std::endl; + if( std::string(s[1] ) != "Basic Directory IOD Modules" ) return 1; + + gdcm::SOPClassUIDToIOD::SOPClassUIDToIODType& s2 = gdcm::SOPClassUIDToIOD::GetSOPClassUIDToIOD(100); + std::cout << ( s2[0] == 0 ) << std::endl; + if( !(s2[0] == 0) ) return 1; + std::cout << ( s2[1] == 0 ) << std::endl; + if( !(s2[1] == 0) ) return 1; + + const char *sopclassuid = gdcm::SOPClassUIDToIOD::GetSOPClassUIDFromIOD( s[1] ); + const char *iod = gdcm::SOPClassUIDToIOD::GetIODFromSOPClassUID( s[0] ); + std::cout << sopclassuid << std::endl; + std::cout << iod << std::endl; + if( std::string(sopclassuid) != s[0] ) return 1; + if( std::string(iod) != s[1] ) return 1; + + return 0; +} diff --git a/gdcm/Testing/Source/DataDictionary/Cxx/TestTagKeywords.cxx b/gdcm/Testing/Source/DataDictionary/Cxx/TestTagKeywords.cxx new file mode 100644 index 0000000..811aa83 --- /dev/null +++ b/gdcm/Testing/Source/DataDictionary/Cxx/TestTagKeywords.cxx @@ -0,0 +1,22 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmTagKeywords.h" + +int TestTagKeywords(int, char *[]) +{ + gdcm::Keywords::FileMetaInformationVersion at1; + + if( at1.GetTag() != gdcm::Tag( 0x2, 0x1 ) ) return 1; + return 0; +} diff --git a/gdcm/Testing/Source/DataDictionary/Cxx/TestTagToType.cxx b/gdcm/Testing/Source/DataDictionary/Cxx/TestTagToType.cxx new file mode 100644 index 0000000..5f3bc80 --- /dev/null +++ b/gdcm/Testing/Source/DataDictionary/Cxx/TestTagToType.cxx @@ -0,0 +1,2668 @@ + +// GENERATED FILE DO NOT EDIT +// $ xsltproc TestTagToType.xsl DICOMV3.xml > TestTagToType.cxx + +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#include "gdcmTagToType.h" + +int TestTagToType(int, char *[]) +{ + gdcm::TagToType<0x0000,0x0000> x00000000; (void)x00000000; + gdcm::TagToType<0x0000,0x0001> x00000001; (void)x00000001; + gdcm::TagToType<0x0000,0x0002> x00000002; (void)x00000002; + gdcm::TagToType<0x0000,0x0003> x00000003; (void)x00000003; + gdcm::TagToType<0x0000,0x0010> x00000010; (void)x00000010; + gdcm::TagToType<0x0000,0x0100> x00000100; (void)x00000100; + gdcm::TagToType<0x0000,0x0110> x00000110; (void)x00000110; + gdcm::TagToType<0x0000,0x0120> x00000120; (void)x00000120; + gdcm::TagToType<0x0000,0x0200> x00000200; (void)x00000200; + gdcm::TagToType<0x0000,0x0300> x00000300; (void)x00000300; + gdcm::TagToType<0x0000,0x0400> x00000400; (void)x00000400; + gdcm::TagToType<0x0000,0x0600> x00000600; (void)x00000600; + gdcm::TagToType<0x0000,0x0700> x00000700; (void)x00000700; + gdcm::TagToType<0x0000,0x0800> x00000800; (void)x00000800; + gdcm::TagToType<0x0000,0x0850> x00000850; (void)x00000850; + gdcm::TagToType<0x0000,0x0860> x00000860; (void)x00000860; + gdcm::TagToType<0x0000,0x0900> x00000900; (void)x00000900; + gdcm::TagToType<0x0000,0x0901> x00000901; (void)x00000901; + gdcm::TagToType<0x0000,0x0902> x00000902; (void)x00000902; + gdcm::TagToType<0x0000,0x0903> x00000903; (void)x00000903; + gdcm::TagToType<0x0000,0x1000> x00001000; (void)x00001000; + gdcm::TagToType<0x0000,0x1001> x00001001; (void)x00001001; + gdcm::TagToType<0x0000,0x1002> x00001002; (void)x00001002; + gdcm::TagToType<0x0000,0x1005> x00001005; (void)x00001005; + gdcm::TagToType<0x0000,0x1008> x00001008; (void)x00001008; + gdcm::TagToType<0x0000,0x1020> x00001020; (void)x00001020; + gdcm::TagToType<0x0000,0x1021> x00001021; (void)x00001021; + gdcm::TagToType<0x0000,0x1022> x00001022; (void)x00001022; + gdcm::TagToType<0x0000,0x1023> x00001023; (void)x00001023; + gdcm::TagToType<0x0000,0x1030> x00001030; (void)x00001030; + gdcm::TagToType<0x0000,0x1031> x00001031; (void)x00001031; + gdcm::TagToType<0x0000,0x4000> x00004000; (void)x00004000; + gdcm::TagToType<0x0000,0x4010> x00004010; (void)x00004010; + gdcm::TagToType<0x0000,0x5010> x00005010; (void)x00005010; + gdcm::TagToType<0x0000,0x5020> x00005020; (void)x00005020; + gdcm::TagToType<0x0000,0x5110> x00005110; (void)x00005110; + gdcm::TagToType<0x0000,0x5120> x00005120; (void)x00005120; + gdcm::TagToType<0x0000,0x5130> x00005130; (void)x00005130; + gdcm::TagToType<0x0000,0x5140> x00005140; (void)x00005140; + gdcm::TagToType<0x0000,0x5150> x00005150; (void)x00005150; + gdcm::TagToType<0x0000,0x5160> x00005160; (void)x00005160; + gdcm::TagToType<0x0000,0x5170> x00005170; (void)x00005170; + gdcm::TagToType<0x0000,0x5180> x00005180; (void)x00005180; + gdcm::TagToType<0x0000,0x5190> x00005190; (void)x00005190; + gdcm::TagToType<0x0000,0x51a0> x000051a0; (void)x000051a0; + gdcm::TagToType<0x0000,0x51b0> x000051b0; (void)x000051b0; + gdcm::TagToType<0x0002,0x0000> x00020000; (void)x00020000; + gdcm::TagToType<0x0002,0x0001> x00020001; (void)x00020001; + gdcm::TagToType<0x0002,0x0002> x00020002; (void)x00020002; + gdcm::TagToType<0x0002,0x0003> x00020003; (void)x00020003; + gdcm::TagToType<0x0002,0x0010> x00020010; (void)x00020010; + gdcm::TagToType<0x0002,0x0012> x00020012; (void)x00020012; + gdcm::TagToType<0x0002,0x0013> x00020013; (void)x00020013; + gdcm::TagToType<0x0002,0x0016> x00020016; (void)x00020016; + gdcm::TagToType<0x0002,0x0100> x00020100; (void)x00020100; + gdcm::TagToType<0x0002,0x0102> x00020102; (void)x00020102; + gdcm::TagToType<0x0004,0x1130> x00041130; (void)x00041130; + gdcm::TagToType<0x0004,0x1141> x00041141; (void)x00041141; + gdcm::TagToType<0x0004,0x1142> x00041142; (void)x00041142; + gdcm::TagToType<0x0004,0x1200> x00041200; (void)x00041200; + gdcm::TagToType<0x0004,0x1202> x00041202; (void)x00041202; + gdcm::TagToType<0x0004,0x1212> x00041212; (void)x00041212; + gdcm::TagToType<0x0004,0x1220> x00041220; (void)x00041220; + gdcm::TagToType<0x0004,0x1400> x00041400; (void)x00041400; + gdcm::TagToType<0x0004,0x1410> x00041410; (void)x00041410; + gdcm::TagToType<0x0004,0x1420> x00041420; (void)x00041420; + gdcm::TagToType<0x0004,0x1430> x00041430; (void)x00041430; + gdcm::TagToType<0x0004,0x1432> x00041432; (void)x00041432; + gdcm::TagToType<0x0004,0x1500> x00041500; (void)x00041500; + gdcm::TagToType<0x0004,0x1504> x00041504; (void)x00041504; + gdcm::TagToType<0x0004,0x1510> x00041510; (void)x00041510; + gdcm::TagToType<0x0004,0x1511> x00041511; (void)x00041511; + gdcm::TagToType<0x0004,0x1512> x00041512; (void)x00041512; + gdcm::TagToType<0x0004,0x151a> x0004151a; (void)x0004151a; + gdcm::TagToType<0x0004,0x1600> x00041600; (void)x00041600; + gdcm::TagToType<0x0008,0x0001> x00080001; (void)x00080001; + gdcm::TagToType<0x0008,0x0005> x00080005; (void)x00080005; + gdcm::TagToType<0x0008,0x0008> x00080008; (void)x00080008; + gdcm::TagToType<0x0008,0x0010> x00080010; (void)x00080010; + gdcm::TagToType<0x0008,0x0012> x00080012; (void)x00080012; + gdcm::TagToType<0x0008,0x0013> x00080013; (void)x00080013; + gdcm::TagToType<0x0008,0x0014> x00080014; (void)x00080014; + gdcm::TagToType<0x0008,0x0016> x00080016; (void)x00080016; + gdcm::TagToType<0x0008,0x0018> x00080018; (void)x00080018; + gdcm::TagToType<0x0008,0x001a> x0008001a; (void)x0008001a; + gdcm::TagToType<0x0008,0x001b> x0008001b; (void)x0008001b; + gdcm::TagToType<0x0008,0x0020> x00080020; (void)x00080020; + gdcm::TagToType<0x0008,0x0021> x00080021; (void)x00080021; + gdcm::TagToType<0x0008,0x0022> x00080022; (void)x00080022; + gdcm::TagToType<0x0008,0x0023> x00080023; (void)x00080023; + gdcm::TagToType<0x0008,0x0024> x00080024; (void)x00080024; + gdcm::TagToType<0x0008,0x0025> x00080025; (void)x00080025; + gdcm::TagToType<0x0008,0x002a> x0008002a; (void)x0008002a; + gdcm::TagToType<0x0008,0x0030> x00080030; (void)x00080030; + gdcm::TagToType<0x0008,0x0031> x00080031; (void)x00080031; + gdcm::TagToType<0x0008,0x0032> x00080032; (void)x00080032; + gdcm::TagToType<0x0008,0x0033> x00080033; (void)x00080033; + gdcm::TagToType<0x0008,0x0034> x00080034; (void)x00080034; + gdcm::TagToType<0x0008,0x0035> x00080035; (void)x00080035; + gdcm::TagToType<0x0008,0x0040> x00080040; (void)x00080040; + gdcm::TagToType<0x0008,0x0041> x00080041; (void)x00080041; + gdcm::TagToType<0x0008,0x0042> x00080042; (void)x00080042; + gdcm::TagToType<0x0008,0x0050> x00080050; (void)x00080050; + gdcm::TagToType<0x0008,0x0052> x00080052; (void)x00080052; + gdcm::TagToType<0x0008,0x0054> x00080054; (void)x00080054; + gdcm::TagToType<0x0008,0x0056> x00080056; (void)x00080056; + gdcm::TagToType<0x0008,0x0058> x00080058; (void)x00080058; + gdcm::TagToType<0x0008,0x0060> x00080060; (void)x00080060; + gdcm::TagToType<0x0008,0x0061> x00080061; (void)x00080061; + gdcm::TagToType<0x0008,0x0062> x00080062; (void)x00080062; + gdcm::TagToType<0x0008,0x0064> x00080064; (void)x00080064; + gdcm::TagToType<0x0008,0x0068> x00080068; (void)x00080068; + gdcm::TagToType<0x0008,0x0070> x00080070; (void)x00080070; + gdcm::TagToType<0x0008,0x0080> x00080080; (void)x00080080; + gdcm::TagToType<0x0008,0x0081> x00080081; (void)x00080081; + gdcm::TagToType<0x0008,0x0082> x00080082; (void)x00080082; + gdcm::TagToType<0x0008,0x0090> x00080090; (void)x00080090; + gdcm::TagToType<0x0008,0x0092> x00080092; (void)x00080092; + gdcm::TagToType<0x0008,0x0094> x00080094; (void)x00080094; + gdcm::TagToType<0x0008,0x0096> x00080096; (void)x00080096; + gdcm::TagToType<0x0008,0x0100> x00080100; (void)x00080100; + gdcm::TagToType<0x0008,0x0102> x00080102; (void)x00080102; + gdcm::TagToType<0x0008,0x0103> x00080103; (void)x00080103; + gdcm::TagToType<0x0008,0x0104> x00080104; (void)x00080104; + gdcm::TagToType<0x0008,0x0105> x00080105; (void)x00080105; + gdcm::TagToType<0x0008,0x0106> x00080106; (void)x00080106; + gdcm::TagToType<0x0008,0x0107> x00080107; (void)x00080107; + gdcm::TagToType<0x0008,0x010b> x0008010b; (void)x0008010b; + gdcm::TagToType<0x0008,0x010c> x0008010c; (void)x0008010c; + gdcm::TagToType<0x0008,0x010d> x0008010d; (void)x0008010d; + gdcm::TagToType<0x0008,0x010f> x0008010f; (void)x0008010f; + gdcm::TagToType<0x0008,0x0110> x00080110; (void)x00080110; + gdcm::TagToType<0x0008,0x0112> x00080112; (void)x00080112; + gdcm::TagToType<0x0008,0x0114> x00080114; (void)x00080114; + gdcm::TagToType<0x0008,0x0115> x00080115; (void)x00080115; + gdcm::TagToType<0x0008,0x0116> x00080116; (void)x00080116; + gdcm::TagToType<0x0008,0x0201> x00080201; (void)x00080201; + gdcm::TagToType<0x0008,0x1000> x00081000; (void)x00081000; + gdcm::TagToType<0x0008,0x1010> x00081010; (void)x00081010; + gdcm::TagToType<0x0008,0x1030> x00081030; (void)x00081030; + gdcm::TagToType<0x0008,0x1032> x00081032; (void)x00081032; + gdcm::TagToType<0x0008,0x103e> x0008103e; (void)x0008103e; + gdcm::TagToType<0x0008,0x1040> x00081040; (void)x00081040; + gdcm::TagToType<0x0008,0x1048> x00081048; (void)x00081048; + gdcm::TagToType<0x0008,0x1049> x00081049; (void)x00081049; + gdcm::TagToType<0x0008,0x1050> x00081050; (void)x00081050; + gdcm::TagToType<0x0008,0x1052> x00081052; (void)x00081052; + gdcm::TagToType<0x0008,0x1060> x00081060; (void)x00081060; + gdcm::TagToType<0x0008,0x1062> x00081062; (void)x00081062; + gdcm::TagToType<0x0008,0x1070> x00081070; (void)x00081070; + gdcm::TagToType<0x0008,0x1072> x00081072; (void)x00081072; + gdcm::TagToType<0x0008,0x1080> x00081080; (void)x00081080; + gdcm::TagToType<0x0008,0x1084> x00081084; (void)x00081084; + gdcm::TagToType<0x0008,0x1090> x00081090; (void)x00081090; + gdcm::TagToType<0x0008,0x1100> x00081100; (void)x00081100; + gdcm::TagToType<0x0008,0x1110> x00081110; (void)x00081110; + gdcm::TagToType<0x0008,0x1111> x00081111; (void)x00081111; + gdcm::TagToType<0x0008,0x1115> x00081115; (void)x00081115; + gdcm::TagToType<0x0008,0x1120> x00081120; (void)x00081120; + gdcm::TagToType<0x0008,0x1125> x00081125; (void)x00081125; + gdcm::TagToType<0x0008,0x1130> x00081130; (void)x00081130; + gdcm::TagToType<0x0008,0x113a> x0008113a; (void)x0008113a; + gdcm::TagToType<0x0008,0x1140> x00081140; (void)x00081140; + gdcm::TagToType<0x0008,0x1145> x00081145; (void)x00081145; + gdcm::TagToType<0x0008,0x114a> x0008114a; (void)x0008114a; + gdcm::TagToType<0x0008,0x114b> x0008114b; (void)x0008114b; + gdcm::TagToType<0x0008,0x1150> x00081150; (void)x00081150; + gdcm::TagToType<0x0008,0x1155> x00081155; (void)x00081155; + gdcm::TagToType<0x0008,0x115a> x0008115a; (void)x0008115a; + gdcm::TagToType<0x0008,0x1160> x00081160; (void)x00081160; + gdcm::TagToType<0x0008,0x1195> x00081195; (void)x00081195; + gdcm::TagToType<0x0008,0x1197> x00081197; (void)x00081197; + gdcm::TagToType<0x0008,0x1198> x00081198; (void)x00081198; + gdcm::TagToType<0x0008,0x1199> x00081199; (void)x00081199; + gdcm::TagToType<0x0008,0x1200> x00081200; (void)x00081200; + gdcm::TagToType<0x0008,0x1250> x00081250; (void)x00081250; + gdcm::TagToType<0x0008,0x2110> x00082110; (void)x00082110; + gdcm::TagToType<0x0008,0x2111> x00082111; (void)x00082111; + gdcm::TagToType<0x0008,0x2112> x00082112; (void)x00082112; + gdcm::TagToType<0x0008,0x2120> x00082120; (void)x00082120; + gdcm::TagToType<0x0008,0x2122> x00082122; (void)x00082122; + gdcm::TagToType<0x0008,0x2124> x00082124; (void)x00082124; + gdcm::TagToType<0x0008,0x2127> x00082127; (void)x00082127; + gdcm::TagToType<0x0008,0x2128> x00082128; (void)x00082128; + gdcm::TagToType<0x0008,0x2129> x00082129; (void)x00082129; + gdcm::TagToType<0x0008,0x212a> x0008212a; (void)x0008212a; + gdcm::TagToType<0x0008,0x2130> x00082130; (void)x00082130; + gdcm::TagToType<0x0008,0x2132> x00082132; (void)x00082132; + gdcm::TagToType<0x0008,0x2142> x00082142; (void)x00082142; + gdcm::TagToType<0x0008,0x2143> x00082143; (void)x00082143; + gdcm::TagToType<0x0008,0x2144> x00082144; (void)x00082144; + gdcm::TagToType<0x0008,0x2200> x00082200; (void)x00082200; + gdcm::TagToType<0x0008,0x2204> x00082204; (void)x00082204; + gdcm::TagToType<0x0008,0x2208> x00082208; (void)x00082208; + gdcm::TagToType<0x0008,0x2218> x00082218; (void)x00082218; + gdcm::TagToType<0x0008,0x2220> x00082220; (void)x00082220; + gdcm::TagToType<0x0008,0x2228> x00082228; (void)x00082228; + gdcm::TagToType<0x0008,0x2229> x00082229; (void)x00082229; + gdcm::TagToType<0x0008,0x2230> x00082230; (void)x00082230; + gdcm::TagToType<0x0008,0x2240> x00082240; (void)x00082240; + gdcm::TagToType<0x0008,0x2242> x00082242; (void)x00082242; + gdcm::TagToType<0x0008,0x2244> x00082244; (void)x00082244; + gdcm::TagToType<0x0008,0x2246> x00082246; (void)x00082246; + gdcm::TagToType<0x0008,0x2251> x00082251; (void)x00082251; + gdcm::TagToType<0x0008,0x2253> x00082253; (void)x00082253; + gdcm::TagToType<0x0008,0x2255> x00082255; (void)x00082255; + gdcm::TagToType<0x0008,0x2256> x00082256; (void)x00082256; + gdcm::TagToType<0x0008,0x2257> x00082257; (void)x00082257; + gdcm::TagToType<0x0008,0x2258> x00082258; (void)x00082258; + gdcm::TagToType<0x0008,0x2259> x00082259; (void)x00082259; + gdcm::TagToType<0x0008,0x225a> x0008225a; (void)x0008225a; + gdcm::TagToType<0x0008,0x225c> x0008225c; (void)x0008225c; + gdcm::TagToType<0x0008,0x3001> x00083001; (void)x00083001; + gdcm::TagToType<0x0008,0x3010> x00083010; (void)x00083010; + gdcm::TagToType<0x0008,0x4000> x00084000; (void)x00084000; + gdcm::TagToType<0x0008,0x9007> x00089007; (void)x00089007; + gdcm::TagToType<0x0008,0x9092> x00089092; (void)x00089092; + gdcm::TagToType<0x0008,0x9121> x00089121; (void)x00089121; + gdcm::TagToType<0x0008,0x9123> x00089123; (void)x00089123; + gdcm::TagToType<0x0008,0x9124> x00089124; (void)x00089124; + gdcm::TagToType<0x0008,0x9154> x00089154; (void)x00089154; + gdcm::TagToType<0x0008,0x9205> x00089205; (void)x00089205; + gdcm::TagToType<0x0008,0x9206> x00089206; (void)x00089206; + gdcm::TagToType<0x0008,0x9207> x00089207; (void)x00089207; + gdcm::TagToType<0x0008,0x9208> x00089208; (void)x00089208; + gdcm::TagToType<0x0008,0x9209> x00089209; (void)x00089209; + gdcm::TagToType<0x0008,0x9215> x00089215; (void)x00089215; + gdcm::TagToType<0x0008,0x9237> x00089237; (void)x00089237; + gdcm::TagToType<0x0008,0x9410> x00089410; (void)x00089410; + gdcm::TagToType<0x0008,0x9458> x00089458; (void)x00089458; + gdcm::TagToType<0x0008,0x9459> x00089459; (void)x00089459; + gdcm::TagToType<0x0008,0x9460> x00089460; (void)x00089460; + gdcm::TagToType<0x0010,0x0010> x00100010; (void)x00100010; + gdcm::TagToType<0x0010,0x0020> x00100020; (void)x00100020; + gdcm::TagToType<0x0010,0x0021> x00100021; (void)x00100021; + gdcm::TagToType<0x0010,0x0022> x00100022; (void)x00100022; + gdcm::TagToType<0x0010,0x0030> x00100030; (void)x00100030; + gdcm::TagToType<0x0010,0x0032> x00100032; (void)x00100032; + gdcm::TagToType<0x0010,0x0040> x00100040; (void)x00100040; + gdcm::TagToType<0x0010,0x0050> x00100050; (void)x00100050; + gdcm::TagToType<0x0010,0x0101> x00100101; (void)x00100101; + gdcm::TagToType<0x0010,0x0102> x00100102; (void)x00100102; + gdcm::TagToType<0x0010,0x1000> x00101000; (void)x00101000; + gdcm::TagToType<0x0010,0x1001> x00101001; (void)x00101001; + gdcm::TagToType<0x0010,0x1002> x00101002; (void)x00101002; + gdcm::TagToType<0x0010,0x1005> x00101005; (void)x00101005; + gdcm::TagToType<0x0010,0x1010> x00101010; (void)x00101010; + gdcm::TagToType<0x0010,0x1020> x00101020; (void)x00101020; + gdcm::TagToType<0x0010,0x1030> x00101030; (void)x00101030; + gdcm::TagToType<0x0010,0x1040> x00101040; (void)x00101040; + gdcm::TagToType<0x0010,0x1050> x00101050; (void)x00101050; + gdcm::TagToType<0x0010,0x1060> x00101060; (void)x00101060; + gdcm::TagToType<0x0010,0x1080> x00101080; (void)x00101080; + gdcm::TagToType<0x0010,0x1081> x00101081; (void)x00101081; + gdcm::TagToType<0x0010,0x1090> x00101090; (void)x00101090; + gdcm::TagToType<0x0010,0x2000> x00102000; (void)x00102000; + gdcm::TagToType<0x0010,0x2110> x00102110; (void)x00102110; + gdcm::TagToType<0x0010,0x2150> x00102150; (void)x00102150; + gdcm::TagToType<0x0010,0x2152> x00102152; (void)x00102152; + gdcm::TagToType<0x0010,0x2154> x00102154; (void)x00102154; + gdcm::TagToType<0x0010,0x2160> x00102160; (void)x00102160; + gdcm::TagToType<0x0010,0x2180> x00102180; (void)x00102180; + gdcm::TagToType<0x0010,0x21a0> x001021a0; (void)x001021a0; + gdcm::TagToType<0x0010,0x21b0> x001021b0; (void)x001021b0; + gdcm::TagToType<0x0010,0x21c0> x001021c0; (void)x001021c0; + gdcm::TagToType<0x0010,0x21d0> x001021d0; (void)x001021d0; + gdcm::TagToType<0x0010,0x21f0> x001021f0; (void)x001021f0; + gdcm::TagToType<0x0010,0x2201> x00102201; (void)x00102201; + gdcm::TagToType<0x0010,0x2202> x00102202; (void)x00102202; + gdcm::TagToType<0x0010,0x2203> x00102203; (void)x00102203; + gdcm::TagToType<0x0010,0x2292> x00102292; (void)x00102292; + gdcm::TagToType<0x0010,0x2293> x00102293; (void)x00102293; + gdcm::TagToType<0x0010,0x2294> x00102294; (void)x00102294; + gdcm::TagToType<0x0010,0x2295> x00102295; (void)x00102295; + gdcm::TagToType<0x0010,0x2296> x00102296; (void)x00102296; + gdcm::TagToType<0x0010,0x2297> x00102297; (void)x00102297; + gdcm::TagToType<0x0010,0x2298> x00102298; (void)x00102298; + gdcm::TagToType<0x0010,0x2299> x00102299; (void)x00102299; + gdcm::TagToType<0x0010,0x4000> x00104000; (void)x00104000; + gdcm::TagToType<0x0010,0x9431> x00109431; (void)x00109431; + gdcm::TagToType<0x0012,0x0010> x00120010; (void)x00120010; + gdcm::TagToType<0x0012,0x0020> x00120020; (void)x00120020; + gdcm::TagToType<0x0012,0x0021> x00120021; (void)x00120021; + gdcm::TagToType<0x0012,0x0030> x00120030; (void)x00120030; + gdcm::TagToType<0x0012,0x0031> x00120031; (void)x00120031; + gdcm::TagToType<0x0012,0x0040> x00120040; (void)x00120040; + gdcm::TagToType<0x0012,0x0042> x00120042; (void)x00120042; + gdcm::TagToType<0x0012,0x0050> x00120050; (void)x00120050; + gdcm::TagToType<0x0012,0x0051> x00120051; (void)x00120051; + gdcm::TagToType<0x0012,0x0060> x00120060; (void)x00120060; + gdcm::TagToType<0x0012,0x0062> x00120062; (void)x00120062; + gdcm::TagToType<0x0012,0x0063> x00120063; (void)x00120063; + gdcm::TagToType<0x0012,0x0064> x00120064; (void)x00120064; + gdcm::TagToType<0x0012,0x0071> x00120071; (void)x00120071; + gdcm::TagToType<0x0012,0x0072> x00120072; (void)x00120072; + gdcm::TagToType<0x0018,0x0010> x00180010; (void)x00180010; + gdcm::TagToType<0x0018,0x0012> x00180012; (void)x00180012; + gdcm::TagToType<0x0018,0x0014> x00180014; (void)x00180014; + gdcm::TagToType<0x0018,0x0015> x00180015; (void)x00180015; + gdcm::TagToType<0x0018,0x0020> x00180020; (void)x00180020; + gdcm::TagToType<0x0018,0x0021> x00180021; (void)x00180021; + gdcm::TagToType<0x0018,0x0022> x00180022; (void)x00180022; + gdcm::TagToType<0x0018,0x0023> x00180023; (void)x00180023; + gdcm::TagToType<0x0018,0x0024> x00180024; (void)x00180024; + gdcm::TagToType<0x0018,0x0025> x00180025; (void)x00180025; + gdcm::TagToType<0x0018,0x0026> x00180026; (void)x00180026; + gdcm::TagToType<0x0018,0x0027> x00180027; (void)x00180027; + gdcm::TagToType<0x0018,0x0028> x00180028; (void)x00180028; + gdcm::TagToType<0x0018,0x0029> x00180029; (void)x00180029; + gdcm::TagToType<0x0018,0x002a> x0018002a; (void)x0018002a; + gdcm::TagToType<0x0018,0x0030> x00180030; (void)x00180030; + gdcm::TagToType<0x0018,0x0031> x00180031; (void)x00180031; + gdcm::TagToType<0x0018,0x0032> x00180032; (void)x00180032; + gdcm::TagToType<0x0018,0x0033> x00180033; (void)x00180033; + gdcm::TagToType<0x0018,0x0034> x00180034; (void)x00180034; + gdcm::TagToType<0x0018,0x0035> x00180035; (void)x00180035; + gdcm::TagToType<0x0018,0x0036> x00180036; (void)x00180036; + gdcm::TagToType<0x0018,0x0037> x00180037; (void)x00180037; + gdcm::TagToType<0x0018,0x0038> x00180038; (void)x00180038; + gdcm::TagToType<0x0018,0x0039> x00180039; (void)x00180039; + gdcm::TagToType<0x0018,0x003a> x0018003a; (void)x0018003a; + gdcm::TagToType<0x0018,0x0040> x00180040; (void)x00180040; + gdcm::TagToType<0x0018,0x0050> x00180050; (void)x00180050; + gdcm::TagToType<0x0018,0x0060> x00180060; (void)x00180060; + gdcm::TagToType<0x0018,0x0070> x00180070; (void)x00180070; + gdcm::TagToType<0x0018,0x0071> x00180071; (void)x00180071; + gdcm::TagToType<0x0018,0x0072> x00180072; (void)x00180072; + gdcm::TagToType<0x0018,0x0073> x00180073; (void)x00180073; + gdcm::TagToType<0x0018,0x0074> x00180074; (void)x00180074; + gdcm::TagToType<0x0018,0x0075> x00180075; (void)x00180075; + gdcm::TagToType<0x0018,0x0080> x00180080; (void)x00180080; + gdcm::TagToType<0x0018,0x0081> x00180081; (void)x00180081; + gdcm::TagToType<0x0018,0x0082> x00180082; (void)x00180082; + gdcm::TagToType<0x0018,0x0083> x00180083; (void)x00180083; + gdcm::TagToType<0x0018,0x0084> x00180084; (void)x00180084; + gdcm::TagToType<0x0018,0x0085> x00180085; (void)x00180085; + gdcm::TagToType<0x0018,0x0086> x00180086; (void)x00180086; + gdcm::TagToType<0x0018,0x0087> x00180087; (void)x00180087; + gdcm::TagToType<0x0018,0x0088> x00180088; (void)x00180088; + gdcm::TagToType<0x0018,0x0089> x00180089; (void)x00180089; + gdcm::TagToType<0x0018,0x0090> x00180090; (void)x00180090; + gdcm::TagToType<0x0018,0x0091> x00180091; (void)x00180091; + gdcm::TagToType<0x0018,0x0093> x00180093; (void)x00180093; + gdcm::TagToType<0x0018,0x0094> x00180094; (void)x00180094; + gdcm::TagToType<0x0018,0x0095> x00180095; (void)x00180095; + gdcm::TagToType<0x0018,0x1000> x00181000; (void)x00181000; + gdcm::TagToType<0x0018,0x1002> x00181002; (void)x00181002; + gdcm::TagToType<0x0018,0x1003> x00181003; (void)x00181003; + gdcm::TagToType<0x0018,0x1004> x00181004; (void)x00181004; + gdcm::TagToType<0x0018,0x1005> x00181005; (void)x00181005; + gdcm::TagToType<0x0018,0x1006> x00181006; (void)x00181006; + gdcm::TagToType<0x0018,0x1007> x00181007; (void)x00181007; + gdcm::TagToType<0x0018,0x1008> x00181008; (void)x00181008; + gdcm::TagToType<0x0018,0x1010> x00181010; (void)x00181010; + gdcm::TagToType<0x0018,0x1011> x00181011; (void)x00181011; + gdcm::TagToType<0x0018,0x1012> x00181012; (void)x00181012; + gdcm::TagToType<0x0018,0x1014> x00181014; (void)x00181014; + gdcm::TagToType<0x0018,0x1016> x00181016; (void)x00181016; + gdcm::TagToType<0x0018,0x1017> x00181017; (void)x00181017; + gdcm::TagToType<0x0018,0x1018> x00181018; (void)x00181018; + gdcm::TagToType<0x0018,0x1019> x00181019; (void)x00181019; + gdcm::TagToType<0x0018,0x101a> x0018101a; (void)x0018101a; + gdcm::TagToType<0x0018,0x101b> x0018101b; (void)x0018101b; + gdcm::TagToType<0x0018,0x1020> x00181020; (void)x00181020; + gdcm::TagToType<0x0018,0x1022> x00181022; (void)x00181022; + gdcm::TagToType<0x0018,0x1023> x00181023; (void)x00181023; + gdcm::TagToType<0x0018,0x1030> x00181030; (void)x00181030; + gdcm::TagToType<0x0018,0x1040> x00181040; (void)x00181040; + gdcm::TagToType<0x0018,0x1041> x00181041; (void)x00181041; + gdcm::TagToType<0x0018,0x1042> x00181042; (void)x00181042; + gdcm::TagToType<0x0018,0x1043> x00181043; (void)x00181043; + gdcm::TagToType<0x0018,0x1044> x00181044; (void)x00181044; + gdcm::TagToType<0x0018,0x1045> x00181045; (void)x00181045; + gdcm::TagToType<0x0018,0x1046> x00181046; (void)x00181046; + gdcm::TagToType<0x0018,0x1047> x00181047; (void)x00181047; + gdcm::TagToType<0x0018,0x1048> x00181048; (void)x00181048; + gdcm::TagToType<0x0018,0x1049> x00181049; (void)x00181049; + gdcm::TagToType<0x0018,0x1050> x00181050; (void)x00181050; + gdcm::TagToType<0x0018,0x1060> x00181060; (void)x00181060; + gdcm::TagToType<0x0018,0x1061> x00181061; (void)x00181061; + gdcm::TagToType<0x0018,0x1062> x00181062; (void)x00181062; + gdcm::TagToType<0x0018,0x1063> x00181063; (void)x00181063; + gdcm::TagToType<0x0018,0x1064> x00181064; (void)x00181064; + gdcm::TagToType<0x0018,0x1065> x00181065; (void)x00181065; + gdcm::TagToType<0x0018,0x1066> x00181066; (void)x00181066; + gdcm::TagToType<0x0018,0x1067> x00181067; (void)x00181067; + gdcm::TagToType<0x0018,0x1068> x00181068; (void)x00181068; + gdcm::TagToType<0x0018,0x1069> x00181069; (void)x00181069; + gdcm::TagToType<0x0018,0x106a> x0018106a; (void)x0018106a; + gdcm::TagToType<0x0018,0x106c> x0018106c; (void)x0018106c; + gdcm::TagToType<0x0018,0x106e> x0018106e; (void)x0018106e; + gdcm::TagToType<0x0018,0x1070> x00181070; (void)x00181070; + gdcm::TagToType<0x0018,0x1071> x00181071; (void)x00181071; + gdcm::TagToType<0x0018,0x1072> x00181072; (void)x00181072; + gdcm::TagToType<0x0018,0x1073> x00181073; (void)x00181073; + gdcm::TagToType<0x0018,0x1074> x00181074; (void)x00181074; + gdcm::TagToType<0x0018,0x1075> x00181075; (void)x00181075; + gdcm::TagToType<0x0018,0x1076> x00181076; (void)x00181076; + gdcm::TagToType<0x0018,0x1077> x00181077; (void)x00181077; + gdcm::TagToType<0x0018,0x1078> x00181078; (void)x00181078; + gdcm::TagToType<0x0018,0x1079> x00181079; (void)x00181079; + gdcm::TagToType<0x0018,0x1080> x00181080; (void)x00181080; + gdcm::TagToType<0x0018,0x1081> x00181081; (void)x00181081; + gdcm::TagToType<0x0018,0x1082> x00181082; (void)x00181082; + gdcm::TagToType<0x0018,0x1083> x00181083; (void)x00181083; + gdcm::TagToType<0x0018,0x1084> x00181084; (void)x00181084; + gdcm::TagToType<0x0018,0x1085> x00181085; (void)x00181085; + gdcm::TagToType<0x0018,0x1086> x00181086; (void)x00181086; + gdcm::TagToType<0x0018,0x1088> x00181088; (void)x00181088; + gdcm::TagToType<0x0018,0x1090> x00181090; (void)x00181090; + gdcm::TagToType<0x0018,0x1094> x00181094; (void)x00181094; + gdcm::TagToType<0x0018,0x1100> x00181100; (void)x00181100; + gdcm::TagToType<0x0018,0x1110> x00181110; (void)x00181110; + gdcm::TagToType<0x0018,0x1111> x00181111; (void)x00181111; + gdcm::TagToType<0x0018,0x1114> x00181114; (void)x00181114; + gdcm::TagToType<0x0018,0x1120> x00181120; (void)x00181120; + gdcm::TagToType<0x0018,0x1121> x00181121; (void)x00181121; + gdcm::TagToType<0x0018,0x1130> x00181130; (void)x00181130; + gdcm::TagToType<0x0018,0x1131> x00181131; (void)x00181131; + gdcm::TagToType<0x0018,0x1134> x00181134; (void)x00181134; + gdcm::TagToType<0x0018,0x1135> x00181135; (void)x00181135; + gdcm::TagToType<0x0018,0x1136> x00181136; (void)x00181136; + gdcm::TagToType<0x0018,0x1137> x00181137; (void)x00181137; + gdcm::TagToType<0x0018,0x1138> x00181138; (void)x00181138; + gdcm::TagToType<0x0018,0x113a> x0018113a; (void)x0018113a; + gdcm::TagToType<0x0018,0x1140> x00181140; (void)x00181140; + gdcm::TagToType<0x0018,0x1141> x00181141; (void)x00181141; + gdcm::TagToType<0x0018,0x1142> x00181142; (void)x00181142; + gdcm::TagToType<0x0018,0x1143> x00181143; (void)x00181143; + gdcm::TagToType<0x0018,0x1144> x00181144; (void)x00181144; + gdcm::TagToType<0x0018,0x1145> x00181145; (void)x00181145; + gdcm::TagToType<0x0018,0x1146> x00181146; (void)x00181146; + gdcm::TagToType<0x0018,0x1147> x00181147; (void)x00181147; + gdcm::TagToType<0x0018,0x1149> x00181149; (void)x00181149; + gdcm::TagToType<0x0018,0x1150> x00181150; (void)x00181150; + gdcm::TagToType<0x0018,0x1151> x00181151; (void)x00181151; + gdcm::TagToType<0x0018,0x1152> x00181152; (void)x00181152; + gdcm::TagToType<0x0018,0x1153> x00181153; (void)x00181153; + gdcm::TagToType<0x0018,0x1154> x00181154; (void)x00181154; + gdcm::TagToType<0x0018,0x1155> x00181155; (void)x00181155; + gdcm::TagToType<0x0018,0x1156> x00181156; (void)x00181156; + gdcm::TagToType<0x0018,0x115a> x0018115a; (void)x0018115a; + gdcm::TagToType<0x0018,0x115e> x0018115e; (void)x0018115e; + gdcm::TagToType<0x0018,0x1160> x00181160; (void)x00181160; + gdcm::TagToType<0x0018,0x1161> x00181161; (void)x00181161; + gdcm::TagToType<0x0018,0x1162> x00181162; (void)x00181162; + gdcm::TagToType<0x0018,0x1164> x00181164; (void)x00181164; + gdcm::TagToType<0x0018,0x1166> x00181166; (void)x00181166; + gdcm::TagToType<0x0018,0x1170> x00181170; (void)x00181170; + gdcm::TagToType<0x0018,0x1180> x00181180; (void)x00181180; + gdcm::TagToType<0x0018,0x1181> x00181181; (void)x00181181; + gdcm::TagToType<0x0018,0x1182> x00181182; (void)x00181182; + gdcm::TagToType<0x0018,0x1183> x00181183; (void)x00181183; + gdcm::TagToType<0x0018,0x1184> x00181184; (void)x00181184; + gdcm::TagToType<0x0018,0x1190> x00181190; (void)x00181190; + gdcm::TagToType<0x0018,0x1191> x00181191; (void)x00181191; + gdcm::TagToType<0x0018,0x11a0> x001811a0; (void)x001811a0; + gdcm::TagToType<0x0018,0x11a2> x001811a2; (void)x001811a2; + gdcm::TagToType<0x0018,0x1200> x00181200; (void)x00181200; + gdcm::TagToType<0x0018,0x1201> x00181201; (void)x00181201; + gdcm::TagToType<0x0018,0x1210> x00181210; (void)x00181210; + gdcm::TagToType<0x0018,0x1240> x00181240; (void)x00181240; + gdcm::TagToType<0x0018,0x1242> x00181242; (void)x00181242; + gdcm::TagToType<0x0018,0x1243> x00181243; (void)x00181243; + gdcm::TagToType<0x0018,0x1244> x00181244; (void)x00181244; + gdcm::TagToType<0x0018,0x1250> x00181250; (void)x00181250; + gdcm::TagToType<0x0018,0x1251> x00181251; (void)x00181251; + gdcm::TagToType<0x0018,0x1260> x00181260; (void)x00181260; + gdcm::TagToType<0x0018,0x1261> x00181261; (void)x00181261; + gdcm::TagToType<0x0018,0x1300> x00181300; (void)x00181300; + gdcm::TagToType<0x0018,0x1301> x00181301; (void)x00181301; + gdcm::TagToType<0x0018,0x1302> x00181302; (void)x00181302; + gdcm::TagToType<0x0018,0x1310> x00181310; (void)x00181310; + gdcm::TagToType<0x0018,0x1312> x00181312; (void)x00181312; + gdcm::TagToType<0x0018,0x1314> x00181314; (void)x00181314; + gdcm::TagToType<0x0018,0x1315> x00181315; (void)x00181315; + gdcm::TagToType<0x0018,0x1316> x00181316; (void)x00181316; + gdcm::TagToType<0x0018,0x1318> x00181318; (void)x00181318; + gdcm::TagToType<0x0018,0x1400> x00181400; (void)x00181400; + gdcm::TagToType<0x0018,0x1401> x00181401; (void)x00181401; + gdcm::TagToType<0x0018,0x1402> x00181402; (void)x00181402; + gdcm::TagToType<0x0018,0x1403> x00181403; (void)x00181403; + gdcm::TagToType<0x0018,0x1404> x00181404; (void)x00181404; + gdcm::TagToType<0x0018,0x1405> x00181405; (void)x00181405; + gdcm::TagToType<0x0018,0x1450> x00181450; (void)x00181450; + gdcm::TagToType<0x0018,0x1460> x00181460; (void)x00181460; + gdcm::TagToType<0x0018,0x1470> x00181470; (void)x00181470; + gdcm::TagToType<0x0018,0x1480> x00181480; (void)x00181480; + gdcm::TagToType<0x0018,0x1490> x00181490; (void)x00181490; + gdcm::TagToType<0x0018,0x1491> x00181491; (void)x00181491; + gdcm::TagToType<0x0018,0x1495> x00181495; (void)x00181495; + gdcm::TagToType<0x0018,0x1500> x00181500; (void)x00181500; + gdcm::TagToType<0x0018,0x1508> x00181508; (void)x00181508; + gdcm::TagToType<0x0018,0x1510> x00181510; (void)x00181510; + gdcm::TagToType<0x0018,0x1511> x00181511; (void)x00181511; + gdcm::TagToType<0x0018,0x1520> x00181520; (void)x00181520; + gdcm::TagToType<0x0018,0x1521> x00181521; (void)x00181521; + gdcm::TagToType<0x0018,0x1530> x00181530; (void)x00181530; + gdcm::TagToType<0x0018,0x1531> x00181531; (void)x00181531; + gdcm::TagToType<0x0018,0x1600> x00181600; (void)x00181600; + gdcm::TagToType<0x0018,0x1602> x00181602; (void)x00181602; + gdcm::TagToType<0x0018,0x1604> x00181604; (void)x00181604; + gdcm::TagToType<0x0018,0x1606> x00181606; (void)x00181606; + gdcm::TagToType<0x0018,0x1608> x00181608; (void)x00181608; + gdcm::TagToType<0x0018,0x1610> x00181610; (void)x00181610; + gdcm::TagToType<0x0018,0x1612> x00181612; (void)x00181612; + gdcm::TagToType<0x0018,0x1620> x00181620; (void)x00181620; + gdcm::TagToType<0x0018,0x1622> x00181622; (void)x00181622; + gdcm::TagToType<0x0018,0x1623> x00181623; (void)x00181623; + gdcm::TagToType<0x0018,0x1624> x00181624; (void)x00181624; + gdcm::TagToType<0x0018,0x1700> x00181700; (void)x00181700; + gdcm::TagToType<0x0018,0x1702> x00181702; (void)x00181702; + gdcm::TagToType<0x0018,0x1704> x00181704; (void)x00181704; + gdcm::TagToType<0x0018,0x1706> x00181706; (void)x00181706; + gdcm::TagToType<0x0018,0x1708> x00181708; (void)x00181708; + gdcm::TagToType<0x0018,0x1710> x00181710; (void)x00181710; + gdcm::TagToType<0x0018,0x1712> x00181712; (void)x00181712; + gdcm::TagToType<0x0018,0x1720> x00181720; (void)x00181720; + gdcm::TagToType<0x0018,0x1800> x00181800; (void)x00181800; + gdcm::TagToType<0x0018,0x1801> x00181801; (void)x00181801; + gdcm::TagToType<0x0018,0x1802> x00181802; (void)x00181802; + gdcm::TagToType<0x0018,0x1803> x00181803; (void)x00181803; + gdcm::TagToType<0x0018,0x2001> x00182001; (void)x00182001; + gdcm::TagToType<0x0018,0x2002> x00182002; (void)x00182002; + gdcm::TagToType<0x0018,0x2003> x00182003; (void)x00182003; + gdcm::TagToType<0x0018,0x2004> x00182004; (void)x00182004; + gdcm::TagToType<0x0018,0x2005> x00182005; (void)x00182005; + gdcm::TagToType<0x0018,0x2006> x00182006; (void)x00182006; + gdcm::TagToType<0x0018,0x2010> x00182010; (void)x00182010; + gdcm::TagToType<0x0018,0x2020> x00182020; (void)x00182020; + gdcm::TagToType<0x0018,0x2030> x00182030; (void)x00182030; + gdcm::TagToType<0x0018,0x3100> x00183100; (void)x00183100; + gdcm::TagToType<0x0018,0x3101> x00183101; (void)x00183101; + gdcm::TagToType<0x0018,0x3102> x00183102; (void)x00183102; + gdcm::TagToType<0x0018,0x3103> x00183103; (void)x00183103; + gdcm::TagToType<0x0018,0x3104> x00183104; (void)x00183104; + gdcm::TagToType<0x0018,0x3105> x00183105; (void)x00183105; + gdcm::TagToType<0x0018,0x4000> x00184000; (void)x00184000; + gdcm::TagToType<0x0018,0x5000> x00185000; (void)x00185000; + gdcm::TagToType<0x0018,0x5010> x00185010; (void)x00185010; + gdcm::TagToType<0x0018,0x5012> x00185012; (void)x00185012; + gdcm::TagToType<0x0018,0x5020> x00185020; (void)x00185020; + gdcm::TagToType<0x0018,0x5021> x00185021; (void)x00185021; + gdcm::TagToType<0x0018,0x5022> x00185022; (void)x00185022; + gdcm::TagToType<0x0018,0x5024> x00185024; (void)x00185024; + gdcm::TagToType<0x0018,0x5026> x00185026; (void)x00185026; + gdcm::TagToType<0x0018,0x5027> x00185027; (void)x00185027; + gdcm::TagToType<0x0018,0x5028> x00185028; (void)x00185028; + gdcm::TagToType<0x0018,0x5029> x00185029; (void)x00185029; + gdcm::TagToType<0x0018,0x5030> x00185030; (void)x00185030; + gdcm::TagToType<0x0018,0x5040> x00185040; (void)x00185040; + gdcm::TagToType<0x0018,0x5050> x00185050; (void)x00185050; + gdcm::TagToType<0x0018,0x5100> x00185100; (void)x00185100; + gdcm::TagToType<0x0018,0x5101> x00185101; (void)x00185101; + gdcm::TagToType<0x0018,0x5104> x00185104; (void)x00185104; + gdcm::TagToType<0x0018,0x5210> x00185210; (void)x00185210; + gdcm::TagToType<0x0018,0x5212> x00185212; (void)x00185212; + gdcm::TagToType<0x0018,0x6000> x00186000; (void)x00186000; + gdcm::TagToType<0x0018,0x6011> x00186011; (void)x00186011; + gdcm::TagToType<0x0018,0x6012> x00186012; (void)x00186012; + gdcm::TagToType<0x0018,0x6014> x00186014; (void)x00186014; + gdcm::TagToType<0x0018,0x6016> x00186016; (void)x00186016; + gdcm::TagToType<0x0018,0x6018> x00186018; (void)x00186018; + gdcm::TagToType<0x0018,0x601a> x0018601a; (void)x0018601a; + gdcm::TagToType<0x0018,0x601c> x0018601c; (void)x0018601c; + gdcm::TagToType<0x0018,0x601e> x0018601e; (void)x0018601e; + gdcm::TagToType<0x0018,0x6020> x00186020; (void)x00186020; + gdcm::TagToType<0x0018,0x6022> x00186022; (void)x00186022; + gdcm::TagToType<0x0018,0x6024> x00186024; (void)x00186024; + gdcm::TagToType<0x0018,0x6026> x00186026; (void)x00186026; + gdcm::TagToType<0x0018,0x6028> x00186028; (void)x00186028; + gdcm::TagToType<0x0018,0x602a> x0018602a; (void)x0018602a; + gdcm::TagToType<0x0018,0x602c> x0018602c; (void)x0018602c; + gdcm::TagToType<0x0018,0x602e> x0018602e; (void)x0018602e; + gdcm::TagToType<0x0018,0x6030> x00186030; (void)x00186030; + gdcm::TagToType<0x0018,0x6031> x00186031; (void)x00186031; + gdcm::TagToType<0x0018,0x6032> x00186032; (void)x00186032; + gdcm::TagToType<0x0018,0x6034> x00186034; (void)x00186034; + gdcm::TagToType<0x0018,0x6036> x00186036; (void)x00186036; + gdcm::TagToType<0x0018,0x6038> x00186038; (void)x00186038; + gdcm::TagToType<0x0018,0x6039> x00186039; (void)x00186039; + gdcm::TagToType<0x0018,0x603a> x0018603a; (void)x0018603a; + gdcm::TagToType<0x0018,0x603b> x0018603b; (void)x0018603b; + gdcm::TagToType<0x0018,0x603c> x0018603c; (void)x0018603c; + gdcm::TagToType<0x0018,0x603d> x0018603d; (void)x0018603d; + gdcm::TagToType<0x0018,0x603e> x0018603e; (void)x0018603e; + gdcm::TagToType<0x0018,0x603f> x0018603f; (void)x0018603f; + gdcm::TagToType<0x0018,0x6040> x00186040; (void)x00186040; + gdcm::TagToType<0x0018,0x6041> x00186041; (void)x00186041; + gdcm::TagToType<0x0018,0x6042> x00186042; (void)x00186042; + gdcm::TagToType<0x0018,0x6043> x00186043; (void)x00186043; + gdcm::TagToType<0x0018,0x6044> x00186044; (void)x00186044; + gdcm::TagToType<0x0018,0x6046> x00186046; (void)x00186046; + gdcm::TagToType<0x0018,0x6048> x00186048; (void)x00186048; + gdcm::TagToType<0x0018,0x604a> x0018604a; (void)x0018604a; + gdcm::TagToType<0x0018,0x604c> x0018604c; (void)x0018604c; + gdcm::TagToType<0x0018,0x604e> x0018604e; (void)x0018604e; + gdcm::TagToType<0x0018,0x6050> x00186050; (void)x00186050; + gdcm::TagToType<0x0018,0x6052> x00186052; (void)x00186052; + gdcm::TagToType<0x0018,0x6054> x00186054; (void)x00186054; + gdcm::TagToType<0x0018,0x6056> x00186056; (void)x00186056; + gdcm::TagToType<0x0018,0x6058> x00186058; (void)x00186058; + gdcm::TagToType<0x0018,0x605a> x0018605a; (void)x0018605a; + gdcm::TagToType<0x0018,0x6060> x00186060; (void)x00186060; + gdcm::TagToType<0x0018,0x7000> x00187000; (void)x00187000; + gdcm::TagToType<0x0018,0x7001> x00187001; (void)x00187001; + gdcm::TagToType<0x0018,0x7004> x00187004; (void)x00187004; + gdcm::TagToType<0x0018,0x7005> x00187005; (void)x00187005; + gdcm::TagToType<0x0018,0x7006> x00187006; (void)x00187006; + gdcm::TagToType<0x0018,0x7008> x00187008; (void)x00187008; + gdcm::TagToType<0x0018,0x700a> x0018700a; (void)x0018700a; + gdcm::TagToType<0x0018,0x700c> x0018700c; (void)x0018700c; + gdcm::TagToType<0x0018,0x700e> x0018700e; (void)x0018700e; + gdcm::TagToType<0x0018,0x7010> x00187010; (void)x00187010; + gdcm::TagToType<0x0018,0x7011> x00187011; (void)x00187011; + gdcm::TagToType<0x0018,0x7012> x00187012; (void)x00187012; + gdcm::TagToType<0x0018,0x7014> x00187014; (void)x00187014; + gdcm::TagToType<0x0018,0x7016> x00187016; (void)x00187016; + gdcm::TagToType<0x0018,0x701a> x0018701a; (void)x0018701a; + gdcm::TagToType<0x0018,0x7020> x00187020; (void)x00187020; + gdcm::TagToType<0x0018,0x7022> x00187022; (void)x00187022; + gdcm::TagToType<0x0018,0x7024> x00187024; (void)x00187024; + gdcm::TagToType<0x0018,0x7026> x00187026; (void)x00187026; + gdcm::TagToType<0x0018,0x7028> x00187028; (void)x00187028; + gdcm::TagToType<0x0018,0x702a> x0018702a; (void)x0018702a; + gdcm::TagToType<0x0018,0x702b> x0018702b; (void)x0018702b; + gdcm::TagToType<0x0018,0x7030> x00187030; (void)x00187030; + gdcm::TagToType<0x0018,0x7032> x00187032; (void)x00187032; + gdcm::TagToType<0x0018,0x7034> x00187034; (void)x00187034; + gdcm::TagToType<0x0018,0x7040> x00187040; (void)x00187040; + gdcm::TagToType<0x0018,0x7041> x00187041; (void)x00187041; + gdcm::TagToType<0x0018,0x7042> x00187042; (void)x00187042; + gdcm::TagToType<0x0018,0x7044> x00187044; (void)x00187044; + gdcm::TagToType<0x0018,0x7046> x00187046; (void)x00187046; + gdcm::TagToType<0x0018,0x7048> x00187048; (void)x00187048; + gdcm::TagToType<0x0018,0x704c> x0018704c; (void)x0018704c; + gdcm::TagToType<0x0018,0x7050> x00187050; (void)x00187050; + gdcm::TagToType<0x0018,0x7052> x00187052; (void)x00187052; + gdcm::TagToType<0x0018,0x7054> x00187054; (void)x00187054; + gdcm::TagToType<0x0018,0x7060> x00187060; (void)x00187060; + gdcm::TagToType<0x0018,0x7062> x00187062; (void)x00187062; + gdcm::TagToType<0x0018,0x7064> x00187064; (void)x00187064; + gdcm::TagToType<0x0018,0x7065> x00187065; (void)x00187065; + gdcm::TagToType<0x0018,0x8150> x00188150; (void)x00188150; + gdcm::TagToType<0x0018,0x8151> x00188151; (void)x00188151; + gdcm::TagToType<0x0018,0x9004> x00189004; (void)x00189004; + gdcm::TagToType<0x0018,0x9005> x00189005; (void)x00189005; + gdcm::TagToType<0x0018,0x9006> x00189006; (void)x00189006; + gdcm::TagToType<0x0018,0x9008> x00189008; (void)x00189008; + gdcm::TagToType<0x0018,0x9009> x00189009; (void)x00189009; + gdcm::TagToType<0x0018,0x9010> x00189010; (void)x00189010; + gdcm::TagToType<0x0018,0x9011> x00189011; (void)x00189011; + gdcm::TagToType<0x0018,0x9012> x00189012; (void)x00189012; + gdcm::TagToType<0x0018,0x9014> x00189014; (void)x00189014; + gdcm::TagToType<0x0018,0x9015> x00189015; (void)x00189015; + gdcm::TagToType<0x0018,0x9016> x00189016; (void)x00189016; + gdcm::TagToType<0x0018,0x9017> x00189017; (void)x00189017; + gdcm::TagToType<0x0018,0x9018> x00189018; (void)x00189018; + gdcm::TagToType<0x0018,0x9019> x00189019; (void)x00189019; + gdcm::TagToType<0x0018,0x9020> x00189020; (void)x00189020; + gdcm::TagToType<0x0018,0x9021> x00189021; (void)x00189021; + gdcm::TagToType<0x0018,0x9022> x00189022; (void)x00189022; + gdcm::TagToType<0x0018,0x9024> x00189024; (void)x00189024; + gdcm::TagToType<0x0018,0x9025> x00189025; (void)x00189025; + gdcm::TagToType<0x0018,0x9026> x00189026; (void)x00189026; + gdcm::TagToType<0x0018,0x9027> x00189027; (void)x00189027; + gdcm::TagToType<0x0018,0x9028> x00189028; (void)x00189028; + gdcm::TagToType<0x0018,0x9029> x00189029; (void)x00189029; + gdcm::TagToType<0x0018,0x9030> x00189030; (void)x00189030; + gdcm::TagToType<0x0018,0x9032> x00189032; (void)x00189032; + gdcm::TagToType<0x0018,0x9033> x00189033; (void)x00189033; + gdcm::TagToType<0x0018,0x9034> x00189034; (void)x00189034; + gdcm::TagToType<0x0018,0x9035> x00189035; (void)x00189035; + gdcm::TagToType<0x0018,0x9036> x00189036; (void)x00189036; + gdcm::TagToType<0x0018,0x9037> x00189037; (void)x00189037; + gdcm::TagToType<0x0018,0x9041> x00189041; (void)x00189041; + gdcm::TagToType<0x0018,0x9042> x00189042; (void)x00189042; + gdcm::TagToType<0x0018,0x9043> x00189043; (void)x00189043; + gdcm::TagToType<0x0018,0x9044> x00189044; (void)x00189044; + gdcm::TagToType<0x0018,0x9045> x00189045; (void)x00189045; + gdcm::TagToType<0x0018,0x9046> x00189046; (void)x00189046; + gdcm::TagToType<0x0018,0x9047> x00189047; (void)x00189047; + gdcm::TagToType<0x0018,0x9048> x00189048; (void)x00189048; + gdcm::TagToType<0x0018,0x9049> x00189049; (void)x00189049; + gdcm::TagToType<0x0018,0x9050> x00189050; (void)x00189050; + gdcm::TagToType<0x0018,0x9051> x00189051; (void)x00189051; + gdcm::TagToType<0x0018,0x9052> x00189052; (void)x00189052; + gdcm::TagToType<0x0018,0x9053> x00189053; (void)x00189053; + gdcm::TagToType<0x0018,0x9054> x00189054; (void)x00189054; + gdcm::TagToType<0x0018,0x9058> x00189058; (void)x00189058; + gdcm::TagToType<0x0018,0x9059> x00189059; (void)x00189059; + gdcm::TagToType<0x0018,0x9060> x00189060; (void)x00189060; + gdcm::TagToType<0x0018,0x9061> x00189061; (void)x00189061; + gdcm::TagToType<0x0018,0x9062> x00189062; (void)x00189062; + gdcm::TagToType<0x0018,0x9063> x00189063; (void)x00189063; + gdcm::TagToType<0x0018,0x9064> x00189064; (void)x00189064; + gdcm::TagToType<0x0018,0x9065> x00189065; (void)x00189065; + gdcm::TagToType<0x0018,0x9066> x00189066; (void)x00189066; + gdcm::TagToType<0x0018,0x9067> x00189067; (void)x00189067; + gdcm::TagToType<0x0018,0x9069> x00189069; (void)x00189069; + gdcm::TagToType<0x0018,0x9070> x00189070; (void)x00189070; + gdcm::TagToType<0x0018,0x9073> x00189073; (void)x00189073; + gdcm::TagToType<0x0018,0x9074> x00189074; (void)x00189074; + gdcm::TagToType<0x0018,0x9075> x00189075; (void)x00189075; + gdcm::TagToType<0x0018,0x9076> x00189076; (void)x00189076; + gdcm::TagToType<0x0018,0x9077> x00189077; (void)x00189077; + gdcm::TagToType<0x0018,0x9078> x00189078; (void)x00189078; + gdcm::TagToType<0x0018,0x9079> x00189079; (void)x00189079; + gdcm::TagToType<0x0018,0x9080> x00189080; (void)x00189080; + gdcm::TagToType<0x0018,0x9081> x00189081; (void)x00189081; + gdcm::TagToType<0x0018,0x9082> x00189082; (void)x00189082; + gdcm::TagToType<0x0018,0x9083> x00189083; (void)x00189083; + gdcm::TagToType<0x0018,0x9084> x00189084; (void)x00189084; + gdcm::TagToType<0x0018,0x9085> x00189085; (void)x00189085; + gdcm::TagToType<0x0018,0x9087> x00189087; (void)x00189087; + gdcm::TagToType<0x0018,0x9089> x00189089; (void)x00189089; + gdcm::TagToType<0x0018,0x9090> x00189090; (void)x00189090; + gdcm::TagToType<0x0018,0x9091> x00189091; (void)x00189091; + gdcm::TagToType<0x0018,0x9093> x00189093; (void)x00189093; + gdcm::TagToType<0x0018,0x9094> x00189094; (void)x00189094; + gdcm::TagToType<0x0018,0x9095> x00189095; (void)x00189095; + gdcm::TagToType<0x0018,0x9096> x00189096; (void)x00189096; + gdcm::TagToType<0x0018,0x9098> x00189098; (void)x00189098; + gdcm::TagToType<0x0018,0x9100> x00189100; (void)x00189100; + gdcm::TagToType<0x0018,0x9101> x00189101; (void)x00189101; + gdcm::TagToType<0x0018,0x9103> x00189103; (void)x00189103; + gdcm::TagToType<0x0018,0x9104> x00189104; (void)x00189104; + gdcm::TagToType<0x0018,0x9105> x00189105; (void)x00189105; + gdcm::TagToType<0x0018,0x9106> x00189106; (void)x00189106; + gdcm::TagToType<0x0018,0x9107> x00189107; (void)x00189107; + gdcm::TagToType<0x0018,0x9112> x00189112; (void)x00189112; + gdcm::TagToType<0x0018,0x9114> x00189114; (void)x00189114; + gdcm::TagToType<0x0018,0x9115> x00189115; (void)x00189115; + gdcm::TagToType<0x0018,0x9117> x00189117; (void)x00189117; + gdcm::TagToType<0x0018,0x9118> x00189118; (void)x00189118; + gdcm::TagToType<0x0018,0x9119> x00189119; (void)x00189119; + gdcm::TagToType<0x0018,0x9125> x00189125; (void)x00189125; + gdcm::TagToType<0x0018,0x9126> x00189126; (void)x00189126; + gdcm::TagToType<0x0018,0x9127> x00189127; (void)x00189127; + gdcm::TagToType<0x0018,0x9147> x00189147; (void)x00189147; + gdcm::TagToType<0x0018,0x9151> x00189151; (void)x00189151; + gdcm::TagToType<0x0018,0x9152> x00189152; (void)x00189152; + gdcm::TagToType<0x0018,0x9155> x00189155; (void)x00189155; + gdcm::TagToType<0x0018,0x9159> x00189159; (void)x00189159; + gdcm::TagToType<0x0018,0x9166> x00189166; (void)x00189166; + gdcm::TagToType<0x0018,0x9168> x00189168; (void)x00189168; + gdcm::TagToType<0x0018,0x9169> x00189169; (void)x00189169; + gdcm::TagToType<0x0018,0x9170> x00189170; (void)x00189170; + gdcm::TagToType<0x0018,0x9171> x00189171; (void)x00189171; + gdcm::TagToType<0x0018,0x9172> x00189172; (void)x00189172; + gdcm::TagToType<0x0018,0x9173> x00189173; (void)x00189173; + gdcm::TagToType<0x0018,0x9174> x00189174; (void)x00189174; + gdcm::TagToType<0x0018,0x9175> x00189175; (void)x00189175; + gdcm::TagToType<0x0018,0x9176> x00189176; (void)x00189176; + gdcm::TagToType<0x0018,0x9177> x00189177; (void)x00189177; + gdcm::TagToType<0x0018,0x9178> x00189178; (void)x00189178; + gdcm::TagToType<0x0018,0x9179> x00189179; (void)x00189179; + gdcm::TagToType<0x0018,0x9180> x00189180; (void)x00189180; + gdcm::TagToType<0x0018,0x9181> x00189181; (void)x00189181; + gdcm::TagToType<0x0018,0x9182> x00189182; (void)x00189182; + gdcm::TagToType<0x0018,0x9183> x00189183; (void)x00189183; + gdcm::TagToType<0x0018,0x9184> x00189184; (void)x00189184; + gdcm::TagToType<0x0018,0x9185> x00189185; (void)x00189185; + gdcm::TagToType<0x0018,0x9186> x00189186; (void)x00189186; + gdcm::TagToType<0x0018,0x9195> x00189195; (void)x00189195; + gdcm::TagToType<0x0018,0x9196> x00189196; (void)x00189196; + gdcm::TagToType<0x0018,0x9197> x00189197; (void)x00189197; + gdcm::TagToType<0x0018,0x9198> x00189198; (void)x00189198; + gdcm::TagToType<0x0018,0x9199> x00189199; (void)x00189199; + gdcm::TagToType<0x0018,0x9200> x00189200; (void)x00189200; + gdcm::TagToType<0x0018,0x9214> x00189214; (void)x00189214; + gdcm::TagToType<0x0018,0x9217> x00189217; (void)x00189217; + gdcm::TagToType<0x0018,0x9218> x00189218; (void)x00189218; + gdcm::TagToType<0x0018,0x9219> x00189219; (void)x00189219; + gdcm::TagToType<0x0018,0x9220> x00189220; (void)x00189220; + gdcm::TagToType<0x0018,0x9226> x00189226; (void)x00189226; + gdcm::TagToType<0x0018,0x9227> x00189227; (void)x00189227; + gdcm::TagToType<0x0018,0x9231> x00189231; (void)x00189231; + gdcm::TagToType<0x0018,0x9232> x00189232; (void)x00189232; + gdcm::TagToType<0x0018,0x9234> x00189234; (void)x00189234; + gdcm::TagToType<0x0018,0x9236> x00189236; (void)x00189236; + gdcm::TagToType<0x0018,0x9239> x00189239; (void)x00189239; + gdcm::TagToType<0x0018,0x9240> x00189240; (void)x00189240; + gdcm::TagToType<0x0018,0x9241> x00189241; (void)x00189241; + gdcm::TagToType<0x0018,0x9295> x00189295; (void)x00189295; + gdcm::TagToType<0x0018,0x9296> x00189296; (void)x00189296; + gdcm::TagToType<0x0018,0x9301> x00189301; (void)x00189301; + gdcm::TagToType<0x0018,0x9302> x00189302; (void)x00189302; + gdcm::TagToType<0x0018,0x9303> x00189303; (void)x00189303; + gdcm::TagToType<0x0018,0x9304> x00189304; (void)x00189304; + gdcm::TagToType<0x0018,0x9305> x00189305; (void)x00189305; + gdcm::TagToType<0x0018,0x9306> x00189306; (void)x00189306; + gdcm::TagToType<0x0018,0x9307> x00189307; (void)x00189307; + gdcm::TagToType<0x0018,0x9308> x00189308; (void)x00189308; + gdcm::TagToType<0x0018,0x9309> x00189309; (void)x00189309; + gdcm::TagToType<0x0018,0x9310> x00189310; (void)x00189310; + gdcm::TagToType<0x0018,0x9311> x00189311; (void)x00189311; + gdcm::TagToType<0x0018,0x9312> x00189312; (void)x00189312; + gdcm::TagToType<0x0018,0x9313> x00189313; (void)x00189313; + gdcm::TagToType<0x0018,0x9314> x00189314; (void)x00189314; + gdcm::TagToType<0x0018,0x9315> x00189315; (void)x00189315; + gdcm::TagToType<0x0018,0x9316> x00189316; (void)x00189316; + gdcm::TagToType<0x0018,0x9317> x00189317; (void)x00189317; + gdcm::TagToType<0x0018,0x9318> x00189318; (void)x00189318; + gdcm::TagToType<0x0018,0x9319> x00189319; (void)x00189319; + gdcm::TagToType<0x0018,0x9320> x00189320; (void)x00189320; + gdcm::TagToType<0x0018,0x9321> x00189321; (void)x00189321; + gdcm::TagToType<0x0018,0x9322> x00189322; (void)x00189322; + gdcm::TagToType<0x0018,0x9323> x00189323; (void)x00189323; + gdcm::TagToType<0x0018,0x9324> x00189324; (void)x00189324; + gdcm::TagToType<0x0018,0x9325> x00189325; (void)x00189325; + gdcm::TagToType<0x0018,0x9326> x00189326; (void)x00189326; + gdcm::TagToType<0x0018,0x9327> x00189327; (void)x00189327; + gdcm::TagToType<0x0018,0x9328> x00189328; (void)x00189328; + gdcm::TagToType<0x0018,0x9329> x00189329; (void)x00189329; + gdcm::TagToType<0x0018,0x9330> x00189330; (void)x00189330; + gdcm::TagToType<0x0018,0x9332> x00189332; (void)x00189332; + gdcm::TagToType<0x0018,0x9333> x00189333; (void)x00189333; + gdcm::TagToType<0x0018,0x9334> x00189334; (void)x00189334; + gdcm::TagToType<0x0018,0x9335> x00189335; (void)x00189335; + gdcm::TagToType<0x0018,0x9337> x00189337; (void)x00189337; + gdcm::TagToType<0x0018,0x9338> x00189338; (void)x00189338; + gdcm::TagToType<0x0018,0x9340> x00189340; (void)x00189340; + gdcm::TagToType<0x0018,0x9341> x00189341; (void)x00189341; + gdcm::TagToType<0x0018,0x9342> x00189342; (void)x00189342; + gdcm::TagToType<0x0018,0x9343> x00189343; (void)x00189343; + gdcm::TagToType<0x0018,0x9344> x00189344; (void)x00189344; + gdcm::TagToType<0x0018,0x9345> x00189345; (void)x00189345; + gdcm::TagToType<0x0018,0x9346> x00189346; (void)x00189346; + gdcm::TagToType<0x0018,0x9351> x00189351; (void)x00189351; + gdcm::TagToType<0x0018,0x9352> x00189352; (void)x00189352; + gdcm::TagToType<0x0018,0x9360> x00189360; (void)x00189360; + gdcm::TagToType<0x0018,0x9401> x00189401; (void)x00189401; + gdcm::TagToType<0x0018,0x9402> x00189402; (void)x00189402; + gdcm::TagToType<0x0018,0x9403> x00189403; (void)x00189403; + gdcm::TagToType<0x0018,0x9404> x00189404; (void)x00189404; + gdcm::TagToType<0x0018,0x9405> x00189405; (void)x00189405; + gdcm::TagToType<0x0018,0x9406> x00189406; (void)x00189406; + gdcm::TagToType<0x0018,0x9407> x00189407; (void)x00189407; + gdcm::TagToType<0x0018,0x9412> x00189412; (void)x00189412; + gdcm::TagToType<0x0018,0x9417> x00189417; (void)x00189417; + gdcm::TagToType<0x0018,0x9420> x00189420; (void)x00189420; + gdcm::TagToType<0x0018,0x9423> x00189423; (void)x00189423; + gdcm::TagToType<0x0018,0x9424> x00189424; (void)x00189424; + gdcm::TagToType<0x0018,0x9425> x00189425; (void)x00189425; + gdcm::TagToType<0x0018,0x9426> x00189426; (void)x00189426; + gdcm::TagToType<0x0018,0x9427> x00189427; (void)x00189427; + gdcm::TagToType<0x0018,0x9428> x00189428; (void)x00189428; + gdcm::TagToType<0x0018,0x9429> x00189429; (void)x00189429; + gdcm::TagToType<0x0018,0x9430> x00189430; (void)x00189430; + gdcm::TagToType<0x0018,0x9432> x00189432; (void)x00189432; + gdcm::TagToType<0x0018,0x9433> x00189433; (void)x00189433; + gdcm::TagToType<0x0018,0x9434> x00189434; (void)x00189434; + gdcm::TagToType<0x0018,0x9435> x00189435; (void)x00189435; + gdcm::TagToType<0x0018,0x9436> x00189436; (void)x00189436; + gdcm::TagToType<0x0018,0x9437> x00189437; (void)x00189437; + gdcm::TagToType<0x0018,0x9438> x00189438; (void)x00189438; + gdcm::TagToType<0x0018,0x9439> x00189439; (void)x00189439; + gdcm::TagToType<0x0018,0x9440> x00189440; (void)x00189440; + gdcm::TagToType<0x0018,0x9441> x00189441; (void)x00189441; + gdcm::TagToType<0x0018,0x9442> x00189442; (void)x00189442; + gdcm::TagToType<0x0018,0x9447> x00189447; (void)x00189447; + gdcm::TagToType<0x0018,0x9449> x00189449; (void)x00189449; + gdcm::TagToType<0x0018,0x9451> x00189451; (void)x00189451; + gdcm::TagToType<0x0018,0x9452> x00189452; (void)x00189452; + gdcm::TagToType<0x0018,0x9455> x00189455; (void)x00189455; + gdcm::TagToType<0x0018,0x9456> x00189456; (void)x00189456; + gdcm::TagToType<0x0018,0x9457> x00189457; (void)x00189457; + gdcm::TagToType<0x0018,0x9461> x00189461; (void)x00189461; + gdcm::TagToType<0x0018,0x9462> x00189462; (void)x00189462; + gdcm::TagToType<0x0018,0x9463> x00189463; (void)x00189463; + gdcm::TagToType<0x0018,0x9464> x00189464; (void)x00189464; + gdcm::TagToType<0x0018,0x9465> x00189465; (void)x00189465; + gdcm::TagToType<0x0018,0x9466> x00189466; (void)x00189466; + gdcm::TagToType<0x0018,0x9467> x00189467; (void)x00189467; + gdcm::TagToType<0x0018,0x9468> x00189468; (void)x00189468; + gdcm::TagToType<0x0018,0x9469> x00189469; (void)x00189469; + gdcm::TagToType<0x0018,0x9470> x00189470; (void)x00189470; + gdcm::TagToType<0x0018,0x9471> x00189471; (void)x00189471; + gdcm::TagToType<0x0018,0x9472> x00189472; (void)x00189472; + gdcm::TagToType<0x0018,0x9473> x00189473; (void)x00189473; + gdcm::TagToType<0x0018,0x9474> x00189474; (void)x00189474; + gdcm::TagToType<0x0018,0x9476> x00189476; (void)x00189476; + gdcm::TagToType<0x0018,0x9477> x00189477; (void)x00189477; + gdcm::TagToType<0x0018,0x9504> x00189504; (void)x00189504; + gdcm::TagToType<0x0018,0x9506> x00189506; (void)x00189506; + gdcm::TagToType<0x0018,0x9507> x00189507; (void)x00189507; + gdcm::TagToType<0x0018,0x9508> x00189508; (void)x00189508; + gdcm::TagToType<0x0018,0x9509> x00189509; (void)x00189509; + gdcm::TagToType<0x0018,0x9510> x00189510; (void)x00189510; + gdcm::TagToType<0x0018,0x9511> x00189511; (void)x00189511; + gdcm::TagToType<0x0018,0x9514> x00189514; (void)x00189514; + gdcm::TagToType<0x0018,0x9515> x00189515; (void)x00189515; + gdcm::TagToType<0x0018,0x9516> x00189516; (void)x00189516; + gdcm::TagToType<0x0018,0x9517> x00189517; (void)x00189517; + gdcm::TagToType<0x0018,0x9524> x00189524; (void)x00189524; + gdcm::TagToType<0x0018,0x9525> x00189525; (void)x00189525; + gdcm::TagToType<0x0018,0x9526> x00189526; (void)x00189526; + gdcm::TagToType<0x0018,0x9527> x00189527; (void)x00189527; + gdcm::TagToType<0x0018,0x9528> x00189528; (void)x00189528; + gdcm::TagToType<0x0018,0x9530> x00189530; (void)x00189530; + gdcm::TagToType<0x0018,0x9531> x00189531; (void)x00189531; + gdcm::TagToType<0x0018,0x9538> x00189538; (void)x00189538; + gdcm::TagToType<0x0018,0x9601> x00189601; (void)x00189601; + gdcm::TagToType<0x0018,0x9602> x00189602; (void)x00189602; + gdcm::TagToType<0x0018,0x9603> x00189603; (void)x00189603; + gdcm::TagToType<0x0018,0x9604> x00189604; (void)x00189604; + gdcm::TagToType<0x0018,0x9605> x00189605; (void)x00189605; + gdcm::TagToType<0x0018,0x9606> x00189606; (void)x00189606; + gdcm::TagToType<0x0018,0x9607> x00189607; (void)x00189607; + gdcm::TagToType<0x0018,0xa001> x0018a001; (void)x0018a001; + gdcm::TagToType<0x0018,0xa002> x0018a002; (void)x0018a002; + gdcm::TagToType<0x0018,0xa003> x0018a003; (void)x0018a003; + gdcm::TagToType<0x0020,0x000d> x0020000d; (void)x0020000d; + gdcm::TagToType<0x0020,0x000e> x0020000e; (void)x0020000e; + gdcm::TagToType<0x0020,0x0010> x00200010; (void)x00200010; + gdcm::TagToType<0x0020,0x0011> x00200011; (void)x00200011; + gdcm::TagToType<0x0020,0x0012> x00200012; (void)x00200012; + gdcm::TagToType<0x0020,0x0013> x00200013; (void)x00200013; + gdcm::TagToType<0x0020,0x0014> x00200014; (void)x00200014; + gdcm::TagToType<0x0020,0x0015> x00200015; (void)x00200015; + gdcm::TagToType<0x0020,0x0016> x00200016; (void)x00200016; + gdcm::TagToType<0x0020,0x0017> x00200017; (void)x00200017; + gdcm::TagToType<0x0020,0x0018> x00200018; (void)x00200018; + gdcm::TagToType<0x0020,0x0019> x00200019; (void)x00200019; + gdcm::TagToType<0x0020,0x0020> x00200020; (void)x00200020; + gdcm::TagToType<0x0020,0x0022> x00200022; (void)x00200022; + gdcm::TagToType<0x0020,0x0024> x00200024; (void)x00200024; + gdcm::TagToType<0x0020,0x0026> x00200026; (void)x00200026; + gdcm::TagToType<0x0020,0x0030> x00200030; (void)x00200030; + gdcm::TagToType<0x0020,0x0032> x00200032; (void)x00200032; + gdcm::TagToType<0x0020,0x0035> x00200035; (void)x00200035; + gdcm::TagToType<0x0020,0x0037> x00200037; (void)x00200037; + gdcm::TagToType<0x0020,0x0050> x00200050; (void)x00200050; + gdcm::TagToType<0x0020,0x0052> x00200052; (void)x00200052; + gdcm::TagToType<0x0020,0x0060> x00200060; (void)x00200060; + gdcm::TagToType<0x0020,0x0062> x00200062; (void)x00200062; + gdcm::TagToType<0x0020,0x0070> x00200070; (void)x00200070; + gdcm::TagToType<0x0020,0x0080> x00200080; (void)x00200080; + gdcm::TagToType<0x0020,0x0100> x00200100; (void)x00200100; + gdcm::TagToType<0x0020,0x0105> x00200105; (void)x00200105; + gdcm::TagToType<0x0020,0x0110> x00200110; (void)x00200110; + gdcm::TagToType<0x0020,0x0200> x00200200; (void)x00200200; + gdcm::TagToType<0x0020,0x1000> x00201000; (void)x00201000; + gdcm::TagToType<0x0020,0x1001> x00201001; (void)x00201001; + gdcm::TagToType<0x0020,0x1002> x00201002; (void)x00201002; + gdcm::TagToType<0x0020,0x1003> x00201003; (void)x00201003; + gdcm::TagToType<0x0020,0x1004> x00201004; (void)x00201004; + gdcm::TagToType<0x0020,0x1005> x00201005; (void)x00201005; + gdcm::TagToType<0x0020,0x1020> x00201020; (void)x00201020; + gdcm::TagToType<0x0020,0x1040> x00201040; (void)x00201040; + gdcm::TagToType<0x0020,0x1041> x00201041; (void)x00201041; + gdcm::TagToType<0x0020,0x1070> x00201070; (void)x00201070; + gdcm::TagToType<0x0020,0x1200> x00201200; (void)x00201200; + gdcm::TagToType<0x0020,0x1202> x00201202; (void)x00201202; + gdcm::TagToType<0x0020,0x1204> x00201204; (void)x00201204; + gdcm::TagToType<0x0020,0x1206> x00201206; (void)x00201206; + gdcm::TagToType<0x0020,0x1208> x00201208; (void)x00201208; + gdcm::TagToType<0x0020,0x1209> x00201209; (void)x00201209; + gdcm::TagToType<0x0020,0x3401> x00203401; (void)x00203401; + gdcm::TagToType<0x0020,0x3402> x00203402; (void)x00203402; + gdcm::TagToType<0x0020,0x3403> x00203403; (void)x00203403; + gdcm::TagToType<0x0020,0x3404> x00203404; (void)x00203404; + gdcm::TagToType<0x0020,0x3405> x00203405; (void)x00203405; + gdcm::TagToType<0x0020,0x3406> x00203406; (void)x00203406; + gdcm::TagToType<0x0020,0x4000> x00204000; (void)x00204000; + gdcm::TagToType<0x0020,0x5000> x00205000; (void)x00205000; + gdcm::TagToType<0x0020,0x5002> x00205002; (void)x00205002; + gdcm::TagToType<0x0020,0x9056> x00209056; (void)x00209056; + gdcm::TagToType<0x0020,0x9057> x00209057; (void)x00209057; + gdcm::TagToType<0x0020,0x9071> x00209071; (void)x00209071; + gdcm::TagToType<0x0020,0x9072> x00209072; (void)x00209072; + gdcm::TagToType<0x0020,0x9111> x00209111; (void)x00209111; + gdcm::TagToType<0x0020,0x9113> x00209113; (void)x00209113; + gdcm::TagToType<0x0020,0x9116> x00209116; (void)x00209116; + gdcm::TagToType<0x0020,0x9128> x00209128; (void)x00209128; + gdcm::TagToType<0x0020,0x9153> x00209153; (void)x00209153; + gdcm::TagToType<0x0020,0x9156> x00209156; (void)x00209156; + gdcm::TagToType<0x0020,0x9157> x00209157; (void)x00209157; + gdcm::TagToType<0x0020,0x9158> x00209158; (void)x00209158; + gdcm::TagToType<0x0020,0x9161> x00209161; (void)x00209161; + gdcm::TagToType<0x0020,0x9162> x00209162; (void)x00209162; + gdcm::TagToType<0x0020,0x9163> x00209163; (void)x00209163; + gdcm::TagToType<0x0020,0x9164> x00209164; (void)x00209164; + gdcm::TagToType<0x0020,0x9165> x00209165; (void)x00209165; + gdcm::TagToType<0x0020,0x9167> x00209167; (void)x00209167; + gdcm::TagToType<0x0020,0x9213> x00209213; (void)x00209213; + gdcm::TagToType<0x0020,0x9221> x00209221; (void)x00209221; + gdcm::TagToType<0x0020,0x9222> x00209222; (void)x00209222; + gdcm::TagToType<0x0020,0x9228> x00209228; (void)x00209228; + gdcm::TagToType<0x0020,0x9238> x00209238; (void)x00209238; + gdcm::TagToType<0x0020,0x9241> x00209241; (void)x00209241; + gdcm::TagToType<0x0020,0x9245> x00209245; (void)x00209245; + gdcm::TagToType<0x0020,0x9246> x00209246; (void)x00209246; + gdcm::TagToType<0x0020,0x9247> x00209247; (void)x00209247; + gdcm::TagToType<0x0020,0x9248> x00209248; (void)x00209248; + gdcm::TagToType<0x0020,0x9249> x00209249; (void)x00209249; + gdcm::TagToType<0x0020,0x9250> x00209250; (void)x00209250; + gdcm::TagToType<0x0020,0x9251> x00209251; (void)x00209251; + gdcm::TagToType<0x0020,0x9252> x00209252; (void)x00209252; + gdcm::TagToType<0x0020,0x9253> x00209253; (void)x00209253; + gdcm::TagToType<0x0020,0x9254> x00209254; (void)x00209254; + gdcm::TagToType<0x0020,0x9255> x00209255; (void)x00209255; + gdcm::TagToType<0x0020,0x9256> x00209256; (void)x00209256; + gdcm::TagToType<0x0020,0x9257> x00209257; (void)x00209257; + gdcm::TagToType<0x0020,0x9421> x00209421; (void)x00209421; + gdcm::TagToType<0x0020,0x9450> x00209450; (void)x00209450; + gdcm::TagToType<0x0020,0x9453> x00209453; (void)x00209453; + gdcm::TagToType<0x0020,0x9518> x00209518; (void)x00209518; + gdcm::TagToType<0x0020,0x9529> x00209529; (void)x00209529; + gdcm::TagToType<0x0020,0x9536> x00209536; (void)x00209536; + gdcm::TagToType<0x0022,0x0001> x00220001; (void)x00220001; + gdcm::TagToType<0x0022,0x0002> x00220002; (void)x00220002; + gdcm::TagToType<0x0022,0x0003> x00220003; (void)x00220003; + gdcm::TagToType<0x0022,0x0004> x00220004; (void)x00220004; + gdcm::TagToType<0x0022,0x0005> x00220005; (void)x00220005; + gdcm::TagToType<0x0022,0x0006> x00220006; (void)x00220006; + gdcm::TagToType<0x0022,0x0007> x00220007; (void)x00220007; + gdcm::TagToType<0x0022,0x0008> x00220008; (void)x00220008; + gdcm::TagToType<0x0022,0x0009> x00220009; (void)x00220009; + gdcm::TagToType<0x0022,0x000a> x0022000a; (void)x0022000a; + gdcm::TagToType<0x0022,0x000b> x0022000b; (void)x0022000b; + gdcm::TagToType<0x0022,0x000c> x0022000c; (void)x0022000c; + gdcm::TagToType<0x0022,0x000d> x0022000d; (void)x0022000d; + gdcm::TagToType<0x0022,0x000e> x0022000e; (void)x0022000e; + gdcm::TagToType<0x0022,0x0010> x00220010; (void)x00220010; + gdcm::TagToType<0x0022,0x0011> x00220011; (void)x00220011; + gdcm::TagToType<0x0022,0x0012> x00220012; (void)x00220012; + gdcm::TagToType<0x0022,0x0013> x00220013; (void)x00220013; + gdcm::TagToType<0x0022,0x0014> x00220014; (void)x00220014; + gdcm::TagToType<0x0022,0x0015> x00220015; (void)x00220015; + gdcm::TagToType<0x0022,0x0016> x00220016; (void)x00220016; + gdcm::TagToType<0x0022,0x0017> x00220017; (void)x00220017; + gdcm::TagToType<0x0022,0x0018> x00220018; (void)x00220018; + gdcm::TagToType<0x0022,0x0019> x00220019; (void)x00220019; + gdcm::TagToType<0x0022,0x001a> x0022001a; (void)x0022001a; + gdcm::TagToType<0x0022,0x001b> x0022001b; (void)x0022001b; + gdcm::TagToType<0x0022,0x001c> x0022001c; (void)x0022001c; + gdcm::TagToType<0x0022,0x001d> x0022001d; (void)x0022001d; + gdcm::TagToType<0x0022,0x0020> x00220020; (void)x00220020; + gdcm::TagToType<0x0022,0x0021> x00220021; (void)x00220021; + gdcm::TagToType<0x0022,0x0022> x00220022; (void)x00220022; + gdcm::TagToType<0x0022,0x0030> x00220030; (void)x00220030; + gdcm::TagToType<0x0022,0x0031> x00220031; (void)x00220031; + gdcm::TagToType<0x0022,0x0032> x00220032; (void)x00220032; + gdcm::TagToType<0x0022,0x0035> x00220035; (void)x00220035; + gdcm::TagToType<0x0022,0x0036> x00220036; (void)x00220036; + gdcm::TagToType<0x0022,0x0037> x00220037; (void)x00220037; + gdcm::TagToType<0x0022,0x0038> x00220038; (void)x00220038; + gdcm::TagToType<0x0022,0x0039> x00220039; (void)x00220039; + gdcm::TagToType<0x0022,0x0041> x00220041; (void)x00220041; + gdcm::TagToType<0x0022,0x0042> x00220042; (void)x00220042; + gdcm::TagToType<0x0022,0x0048> x00220048; (void)x00220048; + gdcm::TagToType<0x0022,0x0049> x00220049; (void)x00220049; + gdcm::TagToType<0x0022,0x004e> x0022004e; (void)x0022004e; + gdcm::TagToType<0x0022,0x0055> x00220055; (void)x00220055; + gdcm::TagToType<0x0022,0x0056> x00220056; (void)x00220056; + gdcm::TagToType<0x0022,0x0057> x00220057; (void)x00220057; + gdcm::TagToType<0x0022,0x0058> x00220058; (void)x00220058; + gdcm::TagToType<0x0028,0x0002> x00280002; (void)x00280002; + gdcm::TagToType<0x0028,0x0003> x00280003; (void)x00280003; + gdcm::TagToType<0x0028,0x0004> x00280004; (void)x00280004; + gdcm::TagToType<0x0028,0x0005> x00280005; (void)x00280005; + gdcm::TagToType<0x0028,0x0006> x00280006; (void)x00280006; + gdcm::TagToType<0x0028,0x0008> x00280008; (void)x00280008; + gdcm::TagToType<0x0028,0x0009> x00280009; (void)x00280009; + gdcm::TagToType<0x0028,0x000a> x0028000a; (void)x0028000a; + gdcm::TagToType<0x0028,0x0010> x00280010; (void)x00280010; + gdcm::TagToType<0x0028,0x0011> x00280011; (void)x00280011; + gdcm::TagToType<0x0028,0x0012> x00280012; (void)x00280012; + gdcm::TagToType<0x0028,0x0014> x00280014; (void)x00280014; + gdcm::TagToType<0x0028,0x0030> x00280030; (void)x00280030; + gdcm::TagToType<0x0028,0x0031> x00280031; (void)x00280031; + gdcm::TagToType<0x0028,0x0032> x00280032; (void)x00280032; + gdcm::TagToType<0x0028,0x0034> x00280034; (void)x00280034; + gdcm::TagToType<0x0028,0x0040> x00280040; (void)x00280040; + gdcm::TagToType<0x0028,0x0050> x00280050; (void)x00280050; + gdcm::TagToType<0x0028,0x0051> x00280051; (void)x00280051; + gdcm::TagToType<0x0028,0x005f> x0028005f; (void)x0028005f; + gdcm::TagToType<0x0028,0x0060> x00280060; (void)x00280060; + gdcm::TagToType<0x0028,0x0061> x00280061; (void)x00280061; + gdcm::TagToType<0x0028,0x0062> x00280062; (void)x00280062; + gdcm::TagToType<0x0028,0x0063> x00280063; (void)x00280063; + gdcm::TagToType<0x0028,0x0065> x00280065; (void)x00280065; + gdcm::TagToType<0x0028,0x0066> x00280066; (void)x00280066; + gdcm::TagToType<0x0028,0x0068> x00280068; (void)x00280068; + gdcm::TagToType<0x0028,0x0069> x00280069; (void)x00280069; + gdcm::TagToType<0x0028,0x0070> x00280070; (void)x00280070; + gdcm::TagToType<0x0028,0x0080> x00280080; (void)x00280080; + gdcm::TagToType<0x0028,0x0081> x00280081; (void)x00280081; + gdcm::TagToType<0x0028,0x0082> x00280082; (void)x00280082; + gdcm::TagToType<0x0028,0x0090> x00280090; (void)x00280090; + gdcm::TagToType<0x0028,0x0091> x00280091; (void)x00280091; + gdcm::TagToType<0x0028,0x0092> x00280092; (void)x00280092; + gdcm::TagToType<0x0028,0x0093> x00280093; (void)x00280093; + gdcm::TagToType<0x0028,0x0094> x00280094; (void)x00280094; + gdcm::TagToType<0x0028,0x0100> x00280100; (void)x00280100; + gdcm::TagToType<0x0028,0x0101> x00280101; (void)x00280101; + gdcm::TagToType<0x0028,0x0102> x00280102; (void)x00280102; + gdcm::TagToType<0x0028,0x0103> x00280103; (void)x00280103; + gdcm::TagToType<0x0028,0x0200> x00280200; (void)x00280200; + gdcm::TagToType<0x0028,0x0300> x00280300; (void)x00280300; + gdcm::TagToType<0x0028,0x0301> x00280301; (void)x00280301; + gdcm::TagToType<0x0028,0x0400> x00280400; (void)x00280400; + gdcm::TagToType<0x0028,0x0401> x00280401; (void)x00280401; + gdcm::TagToType<0x0028,0x0402> x00280402; (void)x00280402; + gdcm::TagToType<0x0028,0x0403> x00280403; (void)x00280403; + gdcm::TagToType<0x0028,0x0404> x00280404; (void)x00280404; + gdcm::TagToType<0x0028,0x0700> x00280700; (void)x00280700; + gdcm::TagToType<0x0028,0x0701> x00280701; (void)x00280701; + gdcm::TagToType<0x0028,0x0702> x00280702; (void)x00280702; + gdcm::TagToType<0x0028,0x0710> x00280710; (void)x00280710; + gdcm::TagToType<0x0028,0x0720> x00280720; (void)x00280720; + gdcm::TagToType<0x0028,0x0721> x00280721; (void)x00280721; + gdcm::TagToType<0x0028,0x0722> x00280722; (void)x00280722; + gdcm::TagToType<0x0028,0x0730> x00280730; (void)x00280730; + gdcm::TagToType<0x0028,0x0740> x00280740; (void)x00280740; + gdcm::TagToType<0x0028,0x0a02> x00280a02; (void)x00280a02; + gdcm::TagToType<0x0028,0x0a04> x00280a04; (void)x00280a04; + gdcm::TagToType<0x0028,0x1040> x00281040; (void)x00281040; + gdcm::TagToType<0x0028,0x1041> x00281041; (void)x00281041; + gdcm::TagToType<0x0028,0x1050> x00281050; (void)x00281050; + gdcm::TagToType<0x0028,0x1051> x00281051; (void)x00281051; + gdcm::TagToType<0x0028,0x1052> x00281052; (void)x00281052; + gdcm::TagToType<0x0028,0x1053> x00281053; (void)x00281053; + gdcm::TagToType<0x0028,0x1054> x00281054; (void)x00281054; + gdcm::TagToType<0x0028,0x1055> x00281055; (void)x00281055; + gdcm::TagToType<0x0028,0x1056> x00281056; (void)x00281056; + gdcm::TagToType<0x0028,0x1080> x00281080; (void)x00281080; + gdcm::TagToType<0x0028,0x1090> x00281090; (void)x00281090; + gdcm::TagToType<0x0028,0x1199> x00281199; (void)x00281199; + gdcm::TagToType<0x0028,0x1201> x00281201; (void)x00281201; + gdcm::TagToType<0x0028,0x1202> x00281202; (void)x00281202; + gdcm::TagToType<0x0028,0x1203> x00281203; (void)x00281203; + gdcm::TagToType<0x0028,0x1211> x00281211; (void)x00281211; + gdcm::TagToType<0x0028,0x1212> x00281212; (void)x00281212; + gdcm::TagToType<0x0028,0x1213> x00281213; (void)x00281213; + gdcm::TagToType<0x0028,0x1214> x00281214; (void)x00281214; + gdcm::TagToType<0x0028,0x1221> x00281221; (void)x00281221; + gdcm::TagToType<0x0028,0x1222> x00281222; (void)x00281222; + gdcm::TagToType<0x0028,0x1223> x00281223; (void)x00281223; + gdcm::TagToType<0x0028,0x1300> x00281300; (void)x00281300; + gdcm::TagToType<0x0028,0x1350> x00281350; (void)x00281350; + gdcm::TagToType<0x0028,0x1351> x00281351; (void)x00281351; + gdcm::TagToType<0x0028,0x1352> x00281352; (void)x00281352; + gdcm::TagToType<0x0028,0x135a> x0028135a; (void)x0028135a; + gdcm::TagToType<0x0028,0x2000> x00282000; (void)x00282000; + gdcm::TagToType<0x0028,0x2110> x00282110; (void)x00282110; + gdcm::TagToType<0x0028,0x2112> x00282112; (void)x00282112; + gdcm::TagToType<0x0028,0x2114> x00282114; (void)x00282114; + gdcm::TagToType<0x0028,0x3000> x00283000; (void)x00283000; + gdcm::TagToType<0x0028,0x3003> x00283003; (void)x00283003; + gdcm::TagToType<0x0028,0x3004> x00283004; (void)x00283004; + gdcm::TagToType<0x0028,0x3010> x00283010; (void)x00283010; + gdcm::TagToType<0x0028,0x3110> x00283110; (void)x00283110; + gdcm::TagToType<0x0028,0x4000> x00284000; (void)x00284000; + gdcm::TagToType<0x0028,0x5000> x00285000; (void)x00285000; + gdcm::TagToType<0x0028,0x6010> x00286010; (void)x00286010; + gdcm::TagToType<0x0028,0x6020> x00286020; (void)x00286020; + gdcm::TagToType<0x0028,0x6022> x00286022; (void)x00286022; + gdcm::TagToType<0x0028,0x6023> x00286023; (void)x00286023; + gdcm::TagToType<0x0028,0x6030> x00286030; (void)x00286030; + gdcm::TagToType<0x0028,0x6040> x00286040; (void)x00286040; + gdcm::TagToType<0x0028,0x6100> x00286100; (void)x00286100; + gdcm::TagToType<0x0028,0x6101> x00286101; (void)x00286101; + gdcm::TagToType<0x0028,0x6102> x00286102; (void)x00286102; + gdcm::TagToType<0x0028,0x6110> x00286110; (void)x00286110; + gdcm::TagToType<0x0028,0x6112> x00286112; (void)x00286112; + gdcm::TagToType<0x0028,0x6114> x00286114; (void)x00286114; + gdcm::TagToType<0x0028,0x6120> x00286120; (void)x00286120; + gdcm::TagToType<0x0028,0x6190> x00286190; (void)x00286190; + gdcm::TagToType<0x0028,0x7fe0> x00287fe0; (void)x00287fe0; + gdcm::TagToType<0x0028,0x9001> x00289001; (void)x00289001; + gdcm::TagToType<0x0028,0x9002> x00289002; (void)x00289002; + gdcm::TagToType<0x0028,0x9003> x00289003; (void)x00289003; + gdcm::TagToType<0x0028,0x9099> x00289099; (void)x00289099; + gdcm::TagToType<0x0028,0x9108> x00289108; (void)x00289108; + gdcm::TagToType<0x0028,0x9110> x00289110; (void)x00289110; + gdcm::TagToType<0x0028,0x9132> x00289132; (void)x00289132; + gdcm::TagToType<0x0028,0x9145> x00289145; (void)x00289145; + gdcm::TagToType<0x0028,0x9235> x00289235; (void)x00289235; + gdcm::TagToType<0x0028,0x9411> x00289411; (void)x00289411; + gdcm::TagToType<0x0028,0x9415> x00289415; (void)x00289415; + gdcm::TagToType<0x0028,0x9416> x00289416; (void)x00289416; + gdcm::TagToType<0x0028,0x9422> x00289422; (void)x00289422; + gdcm::TagToType<0x0028,0x9443> x00289443; (void)x00289443; + gdcm::TagToType<0x0028,0x9444> x00289444; (void)x00289444; + gdcm::TagToType<0x0028,0x9445> x00289445; (void)x00289445; + gdcm::TagToType<0x0028,0x9446> x00289446; (void)x00289446; + gdcm::TagToType<0x0028,0x9454> x00289454; (void)x00289454; + gdcm::TagToType<0x0028,0x9474> x00289474; (void)x00289474; + gdcm::TagToType<0x0028,0x9520> x00289520; (void)x00289520; + gdcm::TagToType<0x0028,0x9537> x00289537; (void)x00289537; + gdcm::TagToType<0x0032,0x000a> x0032000a; (void)x0032000a; + gdcm::TagToType<0x0032,0x000c> x0032000c; (void)x0032000c; + gdcm::TagToType<0x0032,0x0012> x00320012; (void)x00320012; + gdcm::TagToType<0x0032,0x0032> x00320032; (void)x00320032; + gdcm::TagToType<0x0032,0x0033> x00320033; (void)x00320033; + gdcm::TagToType<0x0032,0x0034> x00320034; (void)x00320034; + gdcm::TagToType<0x0032,0x0035> x00320035; (void)x00320035; + gdcm::TagToType<0x0032,0x1000> x00321000; (void)x00321000; + gdcm::TagToType<0x0032,0x1001> x00321001; (void)x00321001; + gdcm::TagToType<0x0032,0x1010> x00321010; (void)x00321010; + gdcm::TagToType<0x0032,0x1011> x00321011; (void)x00321011; + gdcm::TagToType<0x0032,0x1020> x00321020; (void)x00321020; + gdcm::TagToType<0x0032,0x1021> x00321021; (void)x00321021; + gdcm::TagToType<0x0032,0x1030> x00321030; (void)x00321030; + gdcm::TagToType<0x0032,0x1031> x00321031; (void)x00321031; + gdcm::TagToType<0x0032,0x1032> x00321032; (void)x00321032; + gdcm::TagToType<0x0032,0x1033> x00321033; (void)x00321033; + gdcm::TagToType<0x0032,0x1040> x00321040; (void)x00321040; + gdcm::TagToType<0x0032,0x1041> x00321041; (void)x00321041; + gdcm::TagToType<0x0032,0x1050> x00321050; (void)x00321050; + gdcm::TagToType<0x0032,0x1051> x00321051; (void)x00321051; + gdcm::TagToType<0x0032,0x1055> x00321055; (void)x00321055; + gdcm::TagToType<0x0032,0x1060> x00321060; (void)x00321060; + gdcm::TagToType<0x0032,0x1064> x00321064; (void)x00321064; + gdcm::TagToType<0x0032,0x1070> x00321070; (void)x00321070; + gdcm::TagToType<0x0032,0x4000> x00324000; (void)x00324000; + gdcm::TagToType<0x0038,0x0004> x00380004; (void)x00380004; + gdcm::TagToType<0x0038,0x0008> x00380008; (void)x00380008; + gdcm::TagToType<0x0038,0x0010> x00380010; (void)x00380010; + gdcm::TagToType<0x0038,0x0011> x00380011; (void)x00380011; + gdcm::TagToType<0x0038,0x0016> x00380016; (void)x00380016; + gdcm::TagToType<0x0038,0x001a> x0038001a; (void)x0038001a; + gdcm::TagToType<0x0038,0x001b> x0038001b; (void)x0038001b; + gdcm::TagToType<0x0038,0x001c> x0038001c; (void)x0038001c; + gdcm::TagToType<0x0038,0x001d> x0038001d; (void)x0038001d; + gdcm::TagToType<0x0038,0x001e> x0038001e; (void)x0038001e; + gdcm::TagToType<0x0038,0x0020> x00380020; (void)x00380020; + gdcm::TagToType<0x0038,0x0021> x00380021; (void)x00380021; + gdcm::TagToType<0x0038,0x0030> x00380030; (void)x00380030; + gdcm::TagToType<0x0038,0x0032> x00380032; (void)x00380032; + gdcm::TagToType<0x0038,0x0040> x00380040; (void)x00380040; + gdcm::TagToType<0x0038,0x0044> x00380044; (void)x00380044; + gdcm::TagToType<0x0038,0x0050> x00380050; (void)x00380050; + gdcm::TagToType<0x0038,0x0060> x00380060; (void)x00380060; + gdcm::TagToType<0x0038,0x0061> x00380061; (void)x00380061; + gdcm::TagToType<0x0038,0x0062> x00380062; (void)x00380062; + gdcm::TagToType<0x0038,0x0100> x00380100; (void)x00380100; + gdcm::TagToType<0x0038,0x0300> x00380300; (void)x00380300; + gdcm::TagToType<0x0038,0x0400> x00380400; (void)x00380400; + gdcm::TagToType<0x0038,0x0500> x00380500; (void)x00380500; + gdcm::TagToType<0x0038,0x0502> x00380502; (void)x00380502; + gdcm::TagToType<0x0038,0x4000> x00384000; (void)x00384000; + gdcm::TagToType<0x003a,0x0004> x003a0004; (void)x003a0004; + gdcm::TagToType<0x003a,0x0005> x003a0005; (void)x003a0005; + gdcm::TagToType<0x003a,0x0010> x003a0010; (void)x003a0010; + gdcm::TagToType<0x003a,0x001a> x003a001a; (void)x003a001a; + gdcm::TagToType<0x003a,0x0020> x003a0020; (void)x003a0020; + gdcm::TagToType<0x003a,0x0200> x003a0200; (void)x003a0200; + gdcm::TagToType<0x003a,0x0202> x003a0202; (void)x003a0202; + gdcm::TagToType<0x003a,0x0203> x003a0203; (void)x003a0203; + gdcm::TagToType<0x003a,0x0205> x003a0205; (void)x003a0205; + gdcm::TagToType<0x003a,0x0208> x003a0208; (void)x003a0208; + gdcm::TagToType<0x003a,0x0209> x003a0209; (void)x003a0209; + gdcm::TagToType<0x003a,0x020a> x003a020a; (void)x003a020a; + gdcm::TagToType<0x003a,0x020c> x003a020c; (void)x003a020c; + gdcm::TagToType<0x003a,0x0210> x003a0210; (void)x003a0210; + gdcm::TagToType<0x003a,0x0211> x003a0211; (void)x003a0211; + gdcm::TagToType<0x003a,0x0212> x003a0212; (void)x003a0212; + gdcm::TagToType<0x003a,0x0213> x003a0213; (void)x003a0213; + gdcm::TagToType<0x003a,0x0214> x003a0214; (void)x003a0214; + gdcm::TagToType<0x003a,0x0215> x003a0215; (void)x003a0215; + gdcm::TagToType<0x003a,0x0218> x003a0218; (void)x003a0218; + gdcm::TagToType<0x003a,0x021a> x003a021a; (void)x003a021a; + gdcm::TagToType<0x003a,0x0220> x003a0220; (void)x003a0220; + gdcm::TagToType<0x003a,0x0221> x003a0221; (void)x003a0221; + gdcm::TagToType<0x003a,0x0222> x003a0222; (void)x003a0222; + gdcm::TagToType<0x003a,0x0223> x003a0223; (void)x003a0223; + gdcm::TagToType<0x003a,0x0230> x003a0230; (void)x003a0230; + gdcm::TagToType<0x003a,0x0231> x003a0231; (void)x003a0231; + gdcm::TagToType<0x003a,0x0240> x003a0240; (void)x003a0240; + gdcm::TagToType<0x003a,0x0241> x003a0241; (void)x003a0241; + gdcm::TagToType<0x003a,0x0242> x003a0242; (void)x003a0242; + gdcm::TagToType<0x003a,0x0244> x003a0244; (void)x003a0244; + gdcm::TagToType<0x003a,0x0245> x003a0245; (void)x003a0245; + gdcm::TagToType<0x003a,0x0246> x003a0246; (void)x003a0246; + gdcm::TagToType<0x003a,0x0247> x003a0247; (void)x003a0247; + gdcm::TagToType<0x003a,0x0248> x003a0248; (void)x003a0248; + gdcm::TagToType<0x003a,0x0300> x003a0300; (void)x003a0300; + gdcm::TagToType<0x003a,0x0301> x003a0301; (void)x003a0301; + gdcm::TagToType<0x003a,0x0302> x003a0302; (void)x003a0302; + gdcm::TagToType<0x0040,0x0001> x00400001; (void)x00400001; + gdcm::TagToType<0x0040,0x0002> x00400002; (void)x00400002; + gdcm::TagToType<0x0040,0x0003> x00400003; (void)x00400003; + gdcm::TagToType<0x0040,0x0004> x00400004; (void)x00400004; + gdcm::TagToType<0x0040,0x0005> x00400005; (void)x00400005; + gdcm::TagToType<0x0040,0x0006> x00400006; (void)x00400006; + gdcm::TagToType<0x0040,0x0007> x00400007; (void)x00400007; + gdcm::TagToType<0x0040,0x0008> x00400008; (void)x00400008; + gdcm::TagToType<0x0040,0x0009> x00400009; (void)x00400009; + gdcm::TagToType<0x0040,0x000a> x0040000a; (void)x0040000a; + gdcm::TagToType<0x0040,0x000b> x0040000b; (void)x0040000b; + gdcm::TagToType<0x0040,0x0010> x00400010; (void)x00400010; + gdcm::TagToType<0x0040,0x0011> x00400011; (void)x00400011; + gdcm::TagToType<0x0040,0x0012> x00400012; (void)x00400012; + gdcm::TagToType<0x0040,0x0020> x00400020; (void)x00400020; + gdcm::TagToType<0x0040,0x0100> x00400100; (void)x00400100; + gdcm::TagToType<0x0040,0x0220> x00400220; (void)x00400220; + gdcm::TagToType<0x0040,0x0241> x00400241; (void)x00400241; + gdcm::TagToType<0x0040,0x0242> x00400242; (void)x00400242; + gdcm::TagToType<0x0040,0x0243> x00400243; (void)x00400243; + gdcm::TagToType<0x0040,0x0244> x00400244; (void)x00400244; + gdcm::TagToType<0x0040,0x0245> x00400245; (void)x00400245; + gdcm::TagToType<0x0040,0x0250> x00400250; (void)x00400250; + gdcm::TagToType<0x0040,0x0251> x00400251; (void)x00400251; + gdcm::TagToType<0x0040,0x0252> x00400252; (void)x00400252; + gdcm::TagToType<0x0040,0x0253> x00400253; (void)x00400253; + gdcm::TagToType<0x0040,0x0254> x00400254; (void)x00400254; + gdcm::TagToType<0x0040,0x0255> x00400255; (void)x00400255; + gdcm::TagToType<0x0040,0x0260> x00400260; (void)x00400260; + gdcm::TagToType<0x0040,0x0270> x00400270; (void)x00400270; + gdcm::TagToType<0x0040,0x0275> x00400275; (void)x00400275; + gdcm::TagToType<0x0040,0x0280> x00400280; (void)x00400280; + gdcm::TagToType<0x0040,0x0281> x00400281; (void)x00400281; + gdcm::TagToType<0x0040,0x0293> x00400293; (void)x00400293; + gdcm::TagToType<0x0040,0x0294> x00400294; (void)x00400294; + gdcm::TagToType<0x0040,0x0295> x00400295; (void)x00400295; + gdcm::TagToType<0x0040,0x0296> x00400296; (void)x00400296; + gdcm::TagToType<0x0040,0x0300> x00400300; (void)x00400300; + gdcm::TagToType<0x0040,0x0301> x00400301; (void)x00400301; + gdcm::TagToType<0x0040,0x0302> x00400302; (void)x00400302; + gdcm::TagToType<0x0040,0x0303> x00400303; (void)x00400303; + gdcm::TagToType<0x0040,0x0306> x00400306; (void)x00400306; + gdcm::TagToType<0x0040,0x0307> x00400307; (void)x00400307; + gdcm::TagToType<0x0040,0x030e> x0040030e; (void)x0040030e; + gdcm::TagToType<0x0040,0x0310> x00400310; (void)x00400310; + gdcm::TagToType<0x0040,0x0312> x00400312; (void)x00400312; + gdcm::TagToType<0x0040,0x0314> x00400314; (void)x00400314; + gdcm::TagToType<0x0040,0x0316> x00400316; (void)x00400316; + gdcm::TagToType<0x0040,0x0318> x00400318; (void)x00400318; + gdcm::TagToType<0x0040,0x0320> x00400320; (void)x00400320; + gdcm::TagToType<0x0040,0x0321> x00400321; (void)x00400321; + gdcm::TagToType<0x0040,0x0324> x00400324; (void)x00400324; + gdcm::TagToType<0x0040,0x0330> x00400330; (void)x00400330; + gdcm::TagToType<0x0040,0x0340> x00400340; (void)x00400340; + gdcm::TagToType<0x0040,0x0400> x00400400; (void)x00400400; + gdcm::TagToType<0x0040,0x0440> x00400440; (void)x00400440; + gdcm::TagToType<0x0040,0x0441> x00400441; (void)x00400441; + gdcm::TagToType<0x0040,0x050a> x0040050a; (void)x0040050a; + gdcm::TagToType<0x0040,0x0550> x00400550; (void)x00400550; + gdcm::TagToType<0x0040,0x0551> x00400551; (void)x00400551; + gdcm::TagToType<0x0040,0x0552> x00400552; (void)x00400552; + gdcm::TagToType<0x0040,0x0553> x00400553; (void)x00400553; + gdcm::TagToType<0x0040,0x0555> x00400555; (void)x00400555; + gdcm::TagToType<0x0040,0x0556> x00400556; (void)x00400556; + gdcm::TagToType<0x0040,0x059a> x0040059a; (void)x0040059a; + gdcm::TagToType<0x0040,0x06fa> x004006fa; (void)x004006fa; + gdcm::TagToType<0x0040,0x071a> x0040071a; (void)x0040071a; + gdcm::TagToType<0x0040,0x072a> x0040072a; (void)x0040072a; + gdcm::TagToType<0x0040,0x073a> x0040073a; (void)x0040073a; + gdcm::TagToType<0x0040,0x074a> x0040074a; (void)x0040074a; + gdcm::TagToType<0x0040,0x08d8> x004008d8; (void)x004008d8; + gdcm::TagToType<0x0040,0x08da> x004008da; (void)x004008da; + gdcm::TagToType<0x0040,0x08ea> x004008ea; (void)x004008ea; + gdcm::TagToType<0x0040,0x09f8> x004009f8; (void)x004009f8; + gdcm::TagToType<0x0040,0x1001> x00401001; (void)x00401001; + gdcm::TagToType<0x0040,0x1002> x00401002; (void)x00401002; + gdcm::TagToType<0x0040,0x1003> x00401003; (void)x00401003; + gdcm::TagToType<0x0040,0x1004> x00401004; (void)x00401004; + gdcm::TagToType<0x0040,0x1005> x00401005; (void)x00401005; + gdcm::TagToType<0x0040,0x1006> x00401006; (void)x00401006; + gdcm::TagToType<0x0040,0x1007> x00401007; (void)x00401007; + gdcm::TagToType<0x0040,0x1008> x00401008; (void)x00401008; + gdcm::TagToType<0x0040,0x1009> x00401009; (void)x00401009; + gdcm::TagToType<0x0040,0x100a> x0040100a; (void)x0040100a; + gdcm::TagToType<0x0040,0x1010> x00401010; (void)x00401010; + gdcm::TagToType<0x0040,0x1011> x00401011; (void)x00401011; + gdcm::TagToType<0x0040,0x1101> x00401101; (void)x00401101; + gdcm::TagToType<0x0040,0x1102> x00401102; (void)x00401102; + gdcm::TagToType<0x0040,0x1103> x00401103; (void)x00401103; + gdcm::TagToType<0x0040,0x1400> x00401400; (void)x00401400; + gdcm::TagToType<0x0040,0x2001> x00402001; (void)x00402001; + gdcm::TagToType<0x0040,0x2004> x00402004; (void)x00402004; + gdcm::TagToType<0x0040,0x2005> x00402005; (void)x00402005; + gdcm::TagToType<0x0040,0x2006> x00402006; (void)x00402006; + gdcm::TagToType<0x0040,0x2007> x00402007; (void)x00402007; + gdcm::TagToType<0x0040,0x2008> x00402008; (void)x00402008; + gdcm::TagToType<0x0040,0x2009> x00402009; (void)x00402009; + gdcm::TagToType<0x0040,0x2010> x00402010; (void)x00402010; + gdcm::TagToType<0x0040,0x2016> x00402016; (void)x00402016; + gdcm::TagToType<0x0040,0x2017> x00402017; (void)x00402017; + gdcm::TagToType<0x0040,0x2400> x00402400; (void)x00402400; + gdcm::TagToType<0x0040,0x3001> x00403001; (void)x00403001; + gdcm::TagToType<0x0040,0x4001> x00404001; (void)x00404001; + gdcm::TagToType<0x0040,0x4002> x00404002; (void)x00404002; + gdcm::TagToType<0x0040,0x4003> x00404003; (void)x00404003; + gdcm::TagToType<0x0040,0x4004> x00404004; (void)x00404004; + gdcm::TagToType<0x0040,0x4005> x00404005; (void)x00404005; + gdcm::TagToType<0x0040,0x4006> x00404006; (void)x00404006; + gdcm::TagToType<0x0040,0x4007> x00404007; (void)x00404007; + gdcm::TagToType<0x0040,0x4009> x00404009; (void)x00404009; + gdcm::TagToType<0x0040,0x4010> x00404010; (void)x00404010; + gdcm::TagToType<0x0040,0x4011> x00404011; (void)x00404011; + gdcm::TagToType<0x0040,0x4015> x00404015; (void)x00404015; + gdcm::TagToType<0x0040,0x4016> x00404016; (void)x00404016; + gdcm::TagToType<0x0040,0x4018> x00404018; (void)x00404018; + gdcm::TagToType<0x0040,0x4019> x00404019; (void)x00404019; + gdcm::TagToType<0x0040,0x4020> x00404020; (void)x00404020; + gdcm::TagToType<0x0040,0x4021> x00404021; (void)x00404021; + gdcm::TagToType<0x0040,0x4022> x00404022; (void)x00404022; + gdcm::TagToType<0x0040,0x4023> x00404023; (void)x00404023; + gdcm::TagToType<0x0040,0x4025> x00404025; (void)x00404025; + gdcm::TagToType<0x0040,0x4026> x00404026; (void)x00404026; + gdcm::TagToType<0x0040,0x4027> x00404027; (void)x00404027; + gdcm::TagToType<0x0040,0x4028> x00404028; (void)x00404028; + gdcm::TagToType<0x0040,0x4029> x00404029; (void)x00404029; + gdcm::TagToType<0x0040,0x4030> x00404030; (void)x00404030; + gdcm::TagToType<0x0040,0x4031> x00404031; (void)x00404031; + gdcm::TagToType<0x0040,0x4032> x00404032; (void)x00404032; + gdcm::TagToType<0x0040,0x4033> x00404033; (void)x00404033; + gdcm::TagToType<0x0040,0x4034> x00404034; (void)x00404034; + gdcm::TagToType<0x0040,0x4035> x00404035; (void)x00404035; + gdcm::TagToType<0x0040,0x4036> x00404036; (void)x00404036; + gdcm::TagToType<0x0040,0x4037> x00404037; (void)x00404037; + gdcm::TagToType<0x0040,0x8302> x00408302; (void)x00408302; + gdcm::TagToType<0x0040,0x9094> x00409094; (void)x00409094; + gdcm::TagToType<0x0040,0x9096> x00409096; (void)x00409096; + gdcm::TagToType<0x0040,0x9098> x00409098; (void)x00409098; + gdcm::TagToType<0x0040,0x9210> x00409210; (void)x00409210; + gdcm::TagToType<0x0040,0x9212> x00409212; (void)x00409212; + gdcm::TagToType<0x0040,0x9224> x00409224; (void)x00409224; + gdcm::TagToType<0x0040,0x9225> x00409225; (void)x00409225; + gdcm::TagToType<0x0040,0xa010> x0040a010; (void)x0040a010; + gdcm::TagToType<0x0040,0xa027> x0040a027; (void)x0040a027; + gdcm::TagToType<0x0040,0xa030> x0040a030; (void)x0040a030; + gdcm::TagToType<0x0040,0xa032> x0040a032; (void)x0040a032; + gdcm::TagToType<0x0040,0xa040> x0040a040; (void)x0040a040; + gdcm::TagToType<0x0040,0xa043> x0040a043; (void)x0040a043; + gdcm::TagToType<0x0040,0xa050> x0040a050; (void)x0040a050; + gdcm::TagToType<0x0040,0xa073> x0040a073; (void)x0040a073; + gdcm::TagToType<0x0040,0xa075> x0040a075; (void)x0040a075; + gdcm::TagToType<0x0040,0xa078> x0040a078; (void)x0040a078; + gdcm::TagToType<0x0040,0xa07a> x0040a07a; (void)x0040a07a; + gdcm::TagToType<0x0040,0xa07c> x0040a07c; (void)x0040a07c; + gdcm::TagToType<0x0040,0xa080> x0040a080; (void)x0040a080; + gdcm::TagToType<0x0040,0xa082> x0040a082; (void)x0040a082; + gdcm::TagToType<0x0040,0xa084> x0040a084; (void)x0040a084; + gdcm::TagToType<0x0040,0xa088> x0040a088; (void)x0040a088; + gdcm::TagToType<0x0040,0xa090> x0040a090; (void)x0040a090; + gdcm::TagToType<0x0040,0xa0b0> x0040a0b0; (void)x0040a0b0; + gdcm::TagToType<0x0040,0xa120> x0040a120; (void)x0040a120; + gdcm::TagToType<0x0040,0xa121> x0040a121; (void)x0040a121; + gdcm::TagToType<0x0040,0xa122> x0040a122; (void)x0040a122; + gdcm::TagToType<0x0040,0xa123> x0040a123; (void)x0040a123; + gdcm::TagToType<0x0040,0xa124> x0040a124; (void)x0040a124; + gdcm::TagToType<0x0040,0xa130> x0040a130; (void)x0040a130; + gdcm::TagToType<0x0040,0xa132> x0040a132; (void)x0040a132; + gdcm::TagToType<0x0040,0xa136> x0040a136; (void)x0040a136; + gdcm::TagToType<0x0040,0xa138> x0040a138; (void)x0040a138; + gdcm::TagToType<0x0040,0xa13a> x0040a13a; (void)x0040a13a; + gdcm::TagToType<0x0040,0xa160> x0040a160; (void)x0040a160; + gdcm::TagToType<0x0040,0xa168> x0040a168; (void)x0040a168; + gdcm::TagToType<0x0040,0xa170> x0040a170; (void)x0040a170; + gdcm::TagToType<0x0040,0xa180> x0040a180; (void)x0040a180; + gdcm::TagToType<0x0040,0xa195> x0040a195; (void)x0040a195; + gdcm::TagToType<0x0040,0xa300> x0040a300; (void)x0040a300; + gdcm::TagToType<0x0040,0xa301> x0040a301; (void)x0040a301; + gdcm::TagToType<0x0040,0xa30a> x0040a30a; (void)x0040a30a; + gdcm::TagToType<0x0040,0xa353> x0040a353; (void)x0040a353; + gdcm::TagToType<0x0040,0xa354> x0040a354; (void)x0040a354; + gdcm::TagToType<0x0040,0xa360> x0040a360; (void)x0040a360; + gdcm::TagToType<0x0040,0xa370> x0040a370; (void)x0040a370; + gdcm::TagToType<0x0040,0xa372> x0040a372; (void)x0040a372; + gdcm::TagToType<0x0040,0xa375> x0040a375; (void)x0040a375; + gdcm::TagToType<0x0040,0xa385> x0040a385; (void)x0040a385; + gdcm::TagToType<0x0040,0xa390> x0040a390; (void)x0040a390; + gdcm::TagToType<0x0040,0xa491> x0040a491; (void)x0040a491; + gdcm::TagToType<0x0040,0xa492> x0040a492; (void)x0040a492; + gdcm::TagToType<0x0040,0xa493> x0040a493; (void)x0040a493; + gdcm::TagToType<0x0040,0xa494> x0040a494; (void)x0040a494; + gdcm::TagToType<0x0040,0xa504> x0040a504; (void)x0040a504; + gdcm::TagToType<0x0040,0xa525> x0040a525; (void)x0040a525; + gdcm::TagToType<0x0040,0xa730> x0040a730; (void)x0040a730; + gdcm::TagToType<0x0040,0xb020> x0040b020; (void)x0040b020; + gdcm::TagToType<0x0040,0xdb00> x0040db00; (void)x0040db00; + gdcm::TagToType<0x0040,0xdb06> x0040db06; (void)x0040db06; + gdcm::TagToType<0x0040,0xdb07> x0040db07; (void)x0040db07; + gdcm::TagToType<0x0040,0xdb0b> x0040db0b; (void)x0040db0b; + gdcm::TagToType<0x0040,0xdb0c> x0040db0c; (void)x0040db0c; + gdcm::TagToType<0x0040,0xdb0d> x0040db0d; (void)x0040db0d; + gdcm::TagToType<0x0040,0xdb73> x0040db73; (void)x0040db73; + gdcm::TagToType<0x0040,0xe001> x0040e001; (void)x0040e001; + gdcm::TagToType<0x0040,0xe004> x0040e004; (void)x0040e004; + gdcm::TagToType<0x0040,0xe006> x0040e006; (void)x0040e006; + gdcm::TagToType<0x0040,0xe010> x0040e010; (void)x0040e010; + gdcm::TagToType<0x0042,0x0010> x00420010; (void)x00420010; + gdcm::TagToType<0x0042,0x0011> x00420011; (void)x00420011; + gdcm::TagToType<0x0042,0x0012> x00420012; (void)x00420012; + gdcm::TagToType<0x0042,0x0013> x00420013; (void)x00420013; + gdcm::TagToType<0x0042,0x0014> x00420014; (void)x00420014; + gdcm::TagToType<0x0044,0x0001> x00440001; (void)x00440001; + gdcm::TagToType<0x0044,0x0002> x00440002; (void)x00440002; + gdcm::TagToType<0x0044,0x0003> x00440003; (void)x00440003; + gdcm::TagToType<0x0044,0x0004> x00440004; (void)x00440004; + gdcm::TagToType<0x0044,0x0007> x00440007; (void)x00440007; + gdcm::TagToType<0x0044,0x0008> x00440008; (void)x00440008; + gdcm::TagToType<0x0044,0x0009> x00440009; (void)x00440009; + gdcm::TagToType<0x0044,0x000a> x0044000a; (void)x0044000a; + gdcm::TagToType<0x0044,0x000b> x0044000b; (void)x0044000b; + gdcm::TagToType<0x0044,0x0010> x00440010; (void)x00440010; + gdcm::TagToType<0x0044,0x0011> x00440011; (void)x00440011; + gdcm::TagToType<0x0044,0x0012> x00440012; (void)x00440012; + gdcm::TagToType<0x0044,0x0013> x00440013; (void)x00440013; + gdcm::TagToType<0x0044,0x0019> x00440019; (void)x00440019; + gdcm::TagToType<0x0050,0x0004> x00500004; (void)x00500004; + gdcm::TagToType<0x0050,0x0010> x00500010; (void)x00500010; + gdcm::TagToType<0x0050,0x0014> x00500014; (void)x00500014; + gdcm::TagToType<0x0050,0x0016> x00500016; (void)x00500016; + gdcm::TagToType<0x0050,0x0017> x00500017; (void)x00500017; + gdcm::TagToType<0x0050,0x0018> x00500018; (void)x00500018; + gdcm::TagToType<0x0050,0x0019> x00500019; (void)x00500019; + gdcm::TagToType<0x0050,0x0020> x00500020; (void)x00500020; + gdcm::TagToType<0x0054,0x0010> x00540010; (void)x00540010; + gdcm::TagToType<0x0054,0x0011> x00540011; (void)x00540011; + gdcm::TagToType<0x0054,0x0012> x00540012; (void)x00540012; + gdcm::TagToType<0x0054,0x0013> x00540013; (void)x00540013; + gdcm::TagToType<0x0054,0x0014> x00540014; (void)x00540014; + gdcm::TagToType<0x0054,0x0015> x00540015; (void)x00540015; + gdcm::TagToType<0x0054,0x0016> x00540016; (void)x00540016; + gdcm::TagToType<0x0054,0x0017> x00540017; (void)x00540017; + gdcm::TagToType<0x0054,0x0018> x00540018; (void)x00540018; + gdcm::TagToType<0x0054,0x0020> x00540020; (void)x00540020; + gdcm::TagToType<0x0054,0x0021> x00540021; (void)x00540021; + gdcm::TagToType<0x0054,0x0022> x00540022; (void)x00540022; + gdcm::TagToType<0x0054,0x0030> x00540030; (void)x00540030; + gdcm::TagToType<0x0054,0x0031> x00540031; (void)x00540031; + gdcm::TagToType<0x0054,0x0032> x00540032; (void)x00540032; + gdcm::TagToType<0x0054,0x0033> x00540033; (void)x00540033; + gdcm::TagToType<0x0054,0x0036> x00540036; (void)x00540036; + gdcm::TagToType<0x0054,0x0038> x00540038; (void)x00540038; + gdcm::TagToType<0x0054,0x0039> x00540039; (void)x00540039; + gdcm::TagToType<0x0054,0x0050> x00540050; (void)x00540050; + gdcm::TagToType<0x0054,0x0051> x00540051; (void)x00540051; + gdcm::TagToType<0x0054,0x0052> x00540052; (void)x00540052; + gdcm::TagToType<0x0054,0x0053> x00540053; (void)x00540053; + gdcm::TagToType<0x0054,0x0060> x00540060; (void)x00540060; + gdcm::TagToType<0x0054,0x0061> x00540061; (void)x00540061; + gdcm::TagToType<0x0054,0x0062> x00540062; (void)x00540062; + gdcm::TagToType<0x0054,0x0063> x00540063; (void)x00540063; + gdcm::TagToType<0x0054,0x0070> x00540070; (void)x00540070; + gdcm::TagToType<0x0054,0x0071> x00540071; (void)x00540071; + gdcm::TagToType<0x0054,0x0072> x00540072; (void)x00540072; + gdcm::TagToType<0x0054,0x0073> x00540073; (void)x00540073; + gdcm::TagToType<0x0054,0x0080> x00540080; (void)x00540080; + gdcm::TagToType<0x0054,0x0081> x00540081; (void)x00540081; + gdcm::TagToType<0x0054,0x0090> x00540090; (void)x00540090; + gdcm::TagToType<0x0054,0x0100> x00540100; (void)x00540100; + gdcm::TagToType<0x0054,0x0101> x00540101; (void)x00540101; + gdcm::TagToType<0x0054,0x0200> x00540200; (void)x00540200; + gdcm::TagToType<0x0054,0x0202> x00540202; (void)x00540202; + gdcm::TagToType<0x0054,0x0210> x00540210; (void)x00540210; + gdcm::TagToType<0x0054,0x0211> x00540211; (void)x00540211; + gdcm::TagToType<0x0054,0x0220> x00540220; (void)x00540220; + gdcm::TagToType<0x0054,0x0222> x00540222; (void)x00540222; + gdcm::TagToType<0x0054,0x0300> x00540300; (void)x00540300; + gdcm::TagToType<0x0054,0x0302> x00540302; (void)x00540302; + gdcm::TagToType<0x0054,0x0304> x00540304; (void)x00540304; + gdcm::TagToType<0x0054,0x0306> x00540306; (void)x00540306; + gdcm::TagToType<0x0054,0x0308> x00540308; (void)x00540308; + gdcm::TagToType<0x0054,0x0400> x00540400; (void)x00540400; + gdcm::TagToType<0x0054,0x0410> x00540410; (void)x00540410; + gdcm::TagToType<0x0054,0x0412> x00540412; (void)x00540412; + gdcm::TagToType<0x0054,0x0414> x00540414; (void)x00540414; + gdcm::TagToType<0x0054,0x0500> x00540500; (void)x00540500; + gdcm::TagToType<0x0054,0x1000> x00541000; (void)x00541000; + gdcm::TagToType<0x0054,0x1001> x00541001; (void)x00541001; + gdcm::TagToType<0x0054,0x1002> x00541002; (void)x00541002; + gdcm::TagToType<0x0054,0x1004> x00541004; (void)x00541004; + gdcm::TagToType<0x0054,0x1100> x00541100; (void)x00541100; + gdcm::TagToType<0x0054,0x1101> x00541101; (void)x00541101; + gdcm::TagToType<0x0054,0x1102> x00541102; (void)x00541102; + gdcm::TagToType<0x0054,0x1103> x00541103; (void)x00541103; + gdcm::TagToType<0x0054,0x1104> x00541104; (void)x00541104; + gdcm::TagToType<0x0054,0x1105> x00541105; (void)x00541105; + gdcm::TagToType<0x0054,0x1200> x00541200; (void)x00541200; + gdcm::TagToType<0x0054,0x1201> x00541201; (void)x00541201; + gdcm::TagToType<0x0054,0x1202> x00541202; (void)x00541202; + gdcm::TagToType<0x0054,0x1203> x00541203; (void)x00541203; + gdcm::TagToType<0x0054,0x1210> x00541210; (void)x00541210; + gdcm::TagToType<0x0054,0x1220> x00541220; (void)x00541220; + gdcm::TagToType<0x0054,0x1300> x00541300; (void)x00541300; + gdcm::TagToType<0x0054,0x1310> x00541310; (void)x00541310; + gdcm::TagToType<0x0054,0x1311> x00541311; (void)x00541311; + gdcm::TagToType<0x0054,0x1320> x00541320; (void)x00541320; + gdcm::TagToType<0x0054,0x1321> x00541321; (void)x00541321; + gdcm::TagToType<0x0054,0x1322> x00541322; (void)x00541322; + gdcm::TagToType<0x0054,0x1323> x00541323; (void)x00541323; + gdcm::TagToType<0x0054,0x1324> x00541324; (void)x00541324; + gdcm::TagToType<0x0054,0x1330> x00541330; (void)x00541330; + gdcm::TagToType<0x0054,0x1400> x00541400; (void)x00541400; + gdcm::TagToType<0x0054,0x1401> x00541401; (void)x00541401; + gdcm::TagToType<0x0060,0x3000> x00603000; (void)x00603000; + gdcm::TagToType<0x0060,0x3002> x00603002; (void)x00603002; + gdcm::TagToType<0x0060,0x3008> x00603008; (void)x00603008; + gdcm::TagToType<0x0060,0x3010> x00603010; (void)x00603010; + gdcm::TagToType<0x0060,0x3020> x00603020; (void)x00603020; + gdcm::TagToType<0x0062,0x0001> x00620001; (void)x00620001; + gdcm::TagToType<0x0062,0x0002> x00620002; (void)x00620002; + gdcm::TagToType<0x0062,0x0003> x00620003; (void)x00620003; + gdcm::TagToType<0x0062,0x0004> x00620004; (void)x00620004; + gdcm::TagToType<0x0062,0x0005> x00620005; (void)x00620005; + gdcm::TagToType<0x0062,0x0006> x00620006; (void)x00620006; + gdcm::TagToType<0x0062,0x0008> x00620008; (void)x00620008; + gdcm::TagToType<0x0062,0x0009> x00620009; (void)x00620009; + gdcm::TagToType<0x0062,0x000a> x0062000a; (void)x0062000a; + gdcm::TagToType<0x0062,0x000b> x0062000b; (void)x0062000b; + gdcm::TagToType<0x0062,0x000c> x0062000c; (void)x0062000c; + gdcm::TagToType<0x0062,0x000d> x0062000d; (void)x0062000d; + gdcm::TagToType<0x0062,0x000e> x0062000e; (void)x0062000e; + gdcm::TagToType<0x0062,0x000f> x0062000f; (void)x0062000f; + gdcm::TagToType<0x0062,0x0010> x00620010; (void)x00620010; + gdcm::TagToType<0x0064,0x0002> x00640002; (void)x00640002; + gdcm::TagToType<0x0064,0x0003> x00640003; (void)x00640003; + gdcm::TagToType<0x0064,0x0005> x00640005; (void)x00640005; + gdcm::TagToType<0x0064,0x0007> x00640007; (void)x00640007; + gdcm::TagToType<0x0064,0x0008> x00640008; (void)x00640008; + gdcm::TagToType<0x0064,0x0009> x00640009; (void)x00640009; + gdcm::TagToType<0x0064,0x000f> x0064000f; (void)x0064000f; + gdcm::TagToType<0x0064,0x0010> x00640010; (void)x00640010; + gdcm::TagToType<0x0070,0x0001> x00700001; (void)x00700001; + gdcm::TagToType<0x0070,0x0002> x00700002; (void)x00700002; + gdcm::TagToType<0x0070,0x0003> x00700003; (void)x00700003; + gdcm::TagToType<0x0070,0x0004> x00700004; (void)x00700004; + gdcm::TagToType<0x0070,0x0005> x00700005; (void)x00700005; + gdcm::TagToType<0x0070,0x0006> x00700006; (void)x00700006; + gdcm::TagToType<0x0070,0x0008> x00700008; (void)x00700008; + gdcm::TagToType<0x0070,0x0009> x00700009; (void)x00700009; + gdcm::TagToType<0x0070,0x0010> x00700010; (void)x00700010; + gdcm::TagToType<0x0070,0x0011> x00700011; (void)x00700011; + gdcm::TagToType<0x0070,0x0012> x00700012; (void)x00700012; + gdcm::TagToType<0x0070,0x0014> x00700014; (void)x00700014; + gdcm::TagToType<0x0070,0x0015> x00700015; (void)x00700015; + gdcm::TagToType<0x0070,0x0020> x00700020; (void)x00700020; + gdcm::TagToType<0x0070,0x0021> x00700021; (void)x00700021; + gdcm::TagToType<0x0070,0x0022> x00700022; (void)x00700022; + gdcm::TagToType<0x0070,0x0023> x00700023; (void)x00700023; + gdcm::TagToType<0x0070,0x0024> x00700024; (void)x00700024; + gdcm::TagToType<0x0070,0x0040> x00700040; (void)x00700040; + gdcm::TagToType<0x0070,0x0041> x00700041; (void)x00700041; + gdcm::TagToType<0x0070,0x0042> x00700042; (void)x00700042; + gdcm::TagToType<0x0070,0x0050> x00700050; (void)x00700050; + gdcm::TagToType<0x0070,0x0051> x00700051; (void)x00700051; + gdcm::TagToType<0x0070,0x0052> x00700052; (void)x00700052; + gdcm::TagToType<0x0070,0x0053> x00700053; (void)x00700053; + gdcm::TagToType<0x0070,0x005a> x0070005a; (void)x0070005a; + gdcm::TagToType<0x0070,0x0060> x00700060; (void)x00700060; + gdcm::TagToType<0x0070,0x0062> x00700062; (void)x00700062; + gdcm::TagToType<0x0070,0x0066> x00700066; (void)x00700066; + gdcm::TagToType<0x0070,0x0067> x00700067; (void)x00700067; + gdcm::TagToType<0x0070,0x0068> x00700068; (void)x00700068; + gdcm::TagToType<0x0070,0x0080> x00700080; (void)x00700080; + gdcm::TagToType<0x0070,0x0081> x00700081; (void)x00700081; + gdcm::TagToType<0x0070,0x0082> x00700082; (void)x00700082; + gdcm::TagToType<0x0070,0x0083> x00700083; (void)x00700083; + gdcm::TagToType<0x0070,0x0084> x00700084; (void)x00700084; + gdcm::TagToType<0x0070,0x0086> x00700086; (void)x00700086; + gdcm::TagToType<0x0070,0x0100> x00700100; (void)x00700100; + gdcm::TagToType<0x0070,0x0101> x00700101; (void)x00700101; + gdcm::TagToType<0x0070,0x0102> x00700102; (void)x00700102; + gdcm::TagToType<0x0070,0x0103> x00700103; (void)x00700103; + gdcm::TagToType<0x0070,0x0306> x00700306; (void)x00700306; + gdcm::TagToType<0x0070,0x0308> x00700308; (void)x00700308; + gdcm::TagToType<0x0070,0x0309> x00700309; (void)x00700309; + gdcm::TagToType<0x0070,0x030a> x0070030a; (void)x0070030a; + gdcm::TagToType<0x0070,0x030c> x0070030c; (void)x0070030c; + gdcm::TagToType<0x0070,0x030d> x0070030d; (void)x0070030d; + gdcm::TagToType<0x0070,0x030f> x0070030f; (void)x0070030f; + gdcm::TagToType<0x0070,0x0310> x00700310; (void)x00700310; + gdcm::TagToType<0x0070,0x0311> x00700311; (void)x00700311; + gdcm::TagToType<0x0070,0x0312> x00700312; (void)x00700312; + gdcm::TagToType<0x0070,0x0314> x00700314; (void)x00700314; + gdcm::TagToType<0x0070,0x0318> x00700318; (void)x00700318; + gdcm::TagToType<0x0070,0x031a> x0070031a; (void)x0070031a; + gdcm::TagToType<0x0070,0x031c> x0070031c; (void)x0070031c; + gdcm::TagToType<0x0070,0x031e> x0070031e; (void)x0070031e; + gdcm::TagToType<0x0070,0x0401> x00700401; (void)x00700401; + gdcm::TagToType<0x0070,0x0402> x00700402; (void)x00700402; + gdcm::TagToType<0x0070,0x0403> x00700403; (void)x00700403; + gdcm::TagToType<0x0070,0x0404> x00700404; (void)x00700404; + gdcm::TagToType<0x0070,0x0405> x00700405; (void)x00700405; + gdcm::TagToType<0x0072,0x0002> x00720002; (void)x00720002; + gdcm::TagToType<0x0072,0x0004> x00720004; (void)x00720004; + gdcm::TagToType<0x0072,0x0006> x00720006; (void)x00720006; + gdcm::TagToType<0x0072,0x0008> x00720008; (void)x00720008; + gdcm::TagToType<0x0072,0x000a> x0072000a; (void)x0072000a; + gdcm::TagToType<0x0072,0x000c> x0072000c; (void)x0072000c; + gdcm::TagToType<0x0072,0x000e> x0072000e; (void)x0072000e; + gdcm::TagToType<0x0072,0x0010> x00720010; (void)x00720010; + gdcm::TagToType<0x0072,0x0012> x00720012; (void)x00720012; + gdcm::TagToType<0x0072,0x0014> x00720014; (void)x00720014; + gdcm::TagToType<0x0072,0x0020> x00720020; (void)x00720020; + gdcm::TagToType<0x0072,0x0022> x00720022; (void)x00720022; + gdcm::TagToType<0x0072,0x0024> x00720024; (void)x00720024; + gdcm::TagToType<0x0072,0x0026> x00720026; (void)x00720026; + gdcm::TagToType<0x0072,0x0028> x00720028; (void)x00720028; + gdcm::TagToType<0x0072,0x0030> x00720030; (void)x00720030; + gdcm::TagToType<0x0072,0x0032> x00720032; (void)x00720032; + gdcm::TagToType<0x0072,0x0034> x00720034; (void)x00720034; + gdcm::TagToType<0x0072,0x0038> x00720038; (void)x00720038; + gdcm::TagToType<0x0072,0x003a> x0072003a; (void)x0072003a; + gdcm::TagToType<0x0072,0x003c> x0072003c; (void)x0072003c; + gdcm::TagToType<0x0072,0x003e> x0072003e; (void)x0072003e; + gdcm::TagToType<0x0072,0x0040> x00720040; (void)x00720040; + gdcm::TagToType<0x0072,0x0050> x00720050; (void)x00720050; + gdcm::TagToType<0x0072,0x0052> x00720052; (void)x00720052; + gdcm::TagToType<0x0072,0x0054> x00720054; (void)x00720054; + gdcm::TagToType<0x0072,0x0056> x00720056; (void)x00720056; + gdcm::TagToType<0x0072,0x0060> x00720060; (void)x00720060; + gdcm::TagToType<0x0072,0x0062> x00720062; (void)x00720062; + gdcm::TagToType<0x0072,0x0064> x00720064; (void)x00720064; + gdcm::TagToType<0x0072,0x0066> x00720066; (void)x00720066; + gdcm::TagToType<0x0072,0x0068> x00720068; (void)x00720068; + gdcm::TagToType<0x0072,0x006a> x0072006a; (void)x0072006a; + gdcm::TagToType<0x0072,0x006c> x0072006c; (void)x0072006c; + gdcm::TagToType<0x0072,0x006e> x0072006e; (void)x0072006e; + gdcm::TagToType<0x0072,0x0070> x00720070; (void)x00720070; + gdcm::TagToType<0x0072,0x0072> x00720072; (void)x00720072; + gdcm::TagToType<0x0072,0x0074> x00720074; (void)x00720074; + gdcm::TagToType<0x0072,0x0076> x00720076; (void)x00720076; + gdcm::TagToType<0x0072,0x0078> x00720078; (void)x00720078; + gdcm::TagToType<0x0072,0x007a> x0072007a; (void)x0072007a; + gdcm::TagToType<0x0072,0x007c> x0072007c; (void)x0072007c; + gdcm::TagToType<0x0072,0x007e> x0072007e; (void)x0072007e; + gdcm::TagToType<0x0072,0x0080> x00720080; (void)x00720080; + gdcm::TagToType<0x0072,0x0100> x00720100; (void)x00720100; + gdcm::TagToType<0x0072,0x0102> x00720102; (void)x00720102; + gdcm::TagToType<0x0072,0x0104> x00720104; (void)x00720104; + gdcm::TagToType<0x0072,0x0106> x00720106; (void)x00720106; + gdcm::TagToType<0x0072,0x0108> x00720108; (void)x00720108; + gdcm::TagToType<0x0072,0x010a> x0072010a; (void)x0072010a; + gdcm::TagToType<0x0072,0x010c> x0072010c; (void)x0072010c; + gdcm::TagToType<0x0072,0x010e> x0072010e; (void)x0072010e; + gdcm::TagToType<0x0072,0x0200> x00720200; (void)x00720200; + gdcm::TagToType<0x0072,0x0202> x00720202; (void)x00720202; + gdcm::TagToType<0x0072,0x0203> x00720203; (void)x00720203; + gdcm::TagToType<0x0072,0x0204> x00720204; (void)x00720204; + gdcm::TagToType<0x0072,0x0206> x00720206; (void)x00720206; + gdcm::TagToType<0x0072,0x0208> x00720208; (void)x00720208; + gdcm::TagToType<0x0072,0x0210> x00720210; (void)x00720210; + gdcm::TagToType<0x0072,0x0212> x00720212; (void)x00720212; + gdcm::TagToType<0x0072,0x0214> x00720214; (void)x00720214; + gdcm::TagToType<0x0072,0x0216> x00720216; (void)x00720216; + gdcm::TagToType<0x0072,0x0218> x00720218; (void)x00720218; + gdcm::TagToType<0x0072,0x0300> x00720300; (void)x00720300; + gdcm::TagToType<0x0072,0x0302> x00720302; (void)x00720302; + gdcm::TagToType<0x0072,0x0304> x00720304; (void)x00720304; + gdcm::TagToType<0x0072,0x0306> x00720306; (void)x00720306; + gdcm::TagToType<0x0072,0x0308> x00720308; (void)x00720308; + gdcm::TagToType<0x0072,0x0310> x00720310; (void)x00720310; + gdcm::TagToType<0x0072,0x0312> x00720312; (void)x00720312; + gdcm::TagToType<0x0072,0x0314> x00720314; (void)x00720314; + gdcm::TagToType<0x0072,0x0316> x00720316; (void)x00720316; + gdcm::TagToType<0x0072,0x0318> x00720318; (void)x00720318; + gdcm::TagToType<0x0072,0x0320> x00720320; (void)x00720320; + gdcm::TagToType<0x0072,0x0330> x00720330; (void)x00720330; + gdcm::TagToType<0x0072,0x0400> x00720400; (void)x00720400; + gdcm::TagToType<0x0072,0x0402> x00720402; (void)x00720402; + gdcm::TagToType<0x0072,0x0404> x00720404; (void)x00720404; + gdcm::TagToType<0x0072,0x0406> x00720406; (void)x00720406; + gdcm::TagToType<0x0072,0x0500> x00720500; (void)x00720500; + gdcm::TagToType<0x0072,0x0510> x00720510; (void)x00720510; + gdcm::TagToType<0x0072,0x0512> x00720512; (void)x00720512; + gdcm::TagToType<0x0072,0x0514> x00720514; (void)x00720514; + gdcm::TagToType<0x0072,0x0516> x00720516; (void)x00720516; + gdcm::TagToType<0x0072,0x0520> x00720520; (void)x00720520; + gdcm::TagToType<0x0072,0x0600> x00720600; (void)x00720600; + gdcm::TagToType<0x0072,0x0602> x00720602; (void)x00720602; + gdcm::TagToType<0x0072,0x0604> x00720604; (void)x00720604; + gdcm::TagToType<0x0072,0x0700> x00720700; (void)x00720700; + gdcm::TagToType<0x0072,0x0702> x00720702; (void)x00720702; + gdcm::TagToType<0x0072,0x0704> x00720704; (void)x00720704; + gdcm::TagToType<0x0072,0x0706> x00720706; (void)x00720706; + gdcm::TagToType<0x0072,0x0710> x00720710; (void)x00720710; + gdcm::TagToType<0x0072,0x0712> x00720712; (void)x00720712; + gdcm::TagToType<0x0072,0x0714> x00720714; (void)x00720714; + gdcm::TagToType<0x0072,0x0716> x00720716; (void)x00720716; + gdcm::TagToType<0x0072,0x0717> x00720717; (void)x00720717; + gdcm::TagToType<0x0072,0x0718> x00720718; (void)x00720718; + gdcm::TagToType<0x0074,0x1000> x00741000; (void)x00741000; + gdcm::TagToType<0x0074,0x1002> x00741002; (void)x00741002; + gdcm::TagToType<0x0074,0x1004> x00741004; (void)x00741004; + gdcm::TagToType<0x0074,0x1006> x00741006; (void)x00741006; + gdcm::TagToType<0x0074,0x1008> x00741008; (void)x00741008; + gdcm::TagToType<0x0074,0x100a> x0074100a; (void)x0074100a; + gdcm::TagToType<0x0074,0x100c> x0074100c; (void)x0074100c; + gdcm::TagToType<0x0074,0x100e> x0074100e; (void)x0074100e; + gdcm::TagToType<0x0074,0x1020> x00741020; (void)x00741020; + gdcm::TagToType<0x0074,0x1022> x00741022; (void)x00741022; + gdcm::TagToType<0x0074,0x1024> x00741024; (void)x00741024; + gdcm::TagToType<0x0074,0x1030> x00741030; (void)x00741030; + gdcm::TagToType<0x0074,0x1032> x00741032; (void)x00741032; + gdcm::TagToType<0x0074,0x1034> x00741034; (void)x00741034; + gdcm::TagToType<0x0074,0x1036> x00741036; (void)x00741036; + gdcm::TagToType<0x0074,0x1038> x00741038; (void)x00741038; + gdcm::TagToType<0x0074,0x103a> x0074103a; (void)x0074103a; + gdcm::TagToType<0x0074,0x1040> x00741040; (void)x00741040; + gdcm::TagToType<0x0074,0x1042> x00741042; (void)x00741042; + gdcm::TagToType<0x0074,0x1044> x00741044; (void)x00741044; + gdcm::TagToType<0x0074,0x1046> x00741046; (void)x00741046; + gdcm::TagToType<0x0074,0x1048> x00741048; (void)x00741048; + gdcm::TagToType<0x0074,0x104a> x0074104a; (void)x0074104a; + gdcm::TagToType<0x0074,0x104c> x0074104c; (void)x0074104c; + gdcm::TagToType<0x0074,0x104e> x0074104e; (void)x0074104e; + gdcm::TagToType<0x0074,0x1050> x00741050; (void)x00741050; + gdcm::TagToType<0x0074,0x1052> x00741052; (void)x00741052; + gdcm::TagToType<0x0074,0x1054> x00741054; (void)x00741054; + gdcm::TagToType<0x0074,0x1056> x00741056; (void)x00741056; + gdcm::TagToType<0x0074,0x1200> x00741200; (void)x00741200; + gdcm::TagToType<0x0074,0x1202> x00741202; (void)x00741202; + gdcm::TagToType<0x0074,0x1204> x00741204; (void)x00741204; + gdcm::TagToType<0x0074,0x1210> x00741210; (void)x00741210; + gdcm::TagToType<0x0074,0x1212> x00741212; (void)x00741212; + gdcm::TagToType<0x0074,0x1216> x00741216; (void)x00741216; + gdcm::TagToType<0x0074,0x1220> x00741220; (void)x00741220; + gdcm::TagToType<0x0074,0x1222> x00741222; (void)x00741222; + gdcm::TagToType<0x0074,0x1230> x00741230; (void)x00741230; + gdcm::TagToType<0x0074,0x1234> x00741234; (void)x00741234; + gdcm::TagToType<0x0074,0x1236> x00741236; (void)x00741236; + gdcm::TagToType<0x0074,0x1238> x00741238; (void)x00741238; + gdcm::TagToType<0x0074,0x1242> x00741242; (void)x00741242; + gdcm::TagToType<0x0074,0x1244> x00741244; (void)x00741244; + gdcm::TagToType<0x0074,0x1246> x00741246; (void)x00741246; + gdcm::TagToType<0x0088,0x0130> x00880130; (void)x00880130; + gdcm::TagToType<0x0088,0x0140> x00880140; (void)x00880140; + gdcm::TagToType<0x0088,0x0200> x00880200; (void)x00880200; + gdcm::TagToType<0x0088,0x0904> x00880904; (void)x00880904; + gdcm::TagToType<0x0088,0x0906> x00880906; (void)x00880906; + gdcm::TagToType<0x0088,0x0910> x00880910; (void)x00880910; + gdcm::TagToType<0x0088,0x0912> x00880912; (void)x00880912; + gdcm::TagToType<0x0100,0x0410> x01000410; (void)x01000410; + gdcm::TagToType<0x0100,0x0420> x01000420; (void)x01000420; + gdcm::TagToType<0x0100,0x0424> x01000424; (void)x01000424; + gdcm::TagToType<0x0100,0x0426> x01000426; (void)x01000426; + gdcm::TagToType<0x0400,0x0005> x04000005; (void)x04000005; + gdcm::TagToType<0x0400,0x0010> x04000010; (void)x04000010; + gdcm::TagToType<0x0400,0x0015> x04000015; (void)x04000015; + gdcm::TagToType<0x0400,0x0020> x04000020; (void)x04000020; + gdcm::TagToType<0x0400,0x0100> x04000100; (void)x04000100; + gdcm::TagToType<0x0400,0x0105> x04000105; (void)x04000105; + gdcm::TagToType<0x0400,0x0110> x04000110; (void)x04000110; + gdcm::TagToType<0x0400,0x0115> x04000115; (void)x04000115; + gdcm::TagToType<0x0400,0x0120> x04000120; (void)x04000120; + gdcm::TagToType<0x0400,0x0305> x04000305; (void)x04000305; + gdcm::TagToType<0x0400,0x0310> x04000310; (void)x04000310; + gdcm::TagToType<0x0400,0x0401> x04000401; (void)x04000401; + gdcm::TagToType<0x0400,0x0402> x04000402; (void)x04000402; + gdcm::TagToType<0x0400,0x0403> x04000403; (void)x04000403; + gdcm::TagToType<0x0400,0x0404> x04000404; (void)x04000404; + gdcm::TagToType<0x0400,0x0500> x04000500; (void)x04000500; + gdcm::TagToType<0x0400,0x0510> x04000510; (void)x04000510; + gdcm::TagToType<0x0400,0x0520> x04000520; (void)x04000520; + gdcm::TagToType<0x0400,0x0550> x04000550; (void)x04000550; + gdcm::TagToType<0x0400,0x0561> x04000561; (void)x04000561; + gdcm::TagToType<0x0400,0x0562> x04000562; (void)x04000562; + gdcm::TagToType<0x0400,0x0563> x04000563; (void)x04000563; + gdcm::TagToType<0x0400,0x0564> x04000564; (void)x04000564; + gdcm::TagToType<0x0400,0x0565> x04000565; (void)x04000565; + gdcm::TagToType<0x2000,0x0010> x20000010; (void)x20000010; + gdcm::TagToType<0x2000,0x001e> x2000001e; (void)x2000001e; + gdcm::TagToType<0x2000,0x0020> x20000020; (void)x20000020; + gdcm::TagToType<0x2000,0x0030> x20000030; (void)x20000030; + gdcm::TagToType<0x2000,0x0040> x20000040; (void)x20000040; + gdcm::TagToType<0x2000,0x0050> x20000050; (void)x20000050; + gdcm::TagToType<0x2000,0x0060> x20000060; (void)x20000060; + gdcm::TagToType<0x2000,0x0061> x20000061; (void)x20000061; + gdcm::TagToType<0x2000,0x0062> x20000062; (void)x20000062; + gdcm::TagToType<0x2000,0x0063> x20000063; (void)x20000063; + gdcm::TagToType<0x2000,0x0065> x20000065; (void)x20000065; + gdcm::TagToType<0x2000,0x0067> x20000067; (void)x20000067; + gdcm::TagToType<0x2000,0x0069> x20000069; (void)x20000069; + gdcm::TagToType<0x2000,0x006a> x2000006a; (void)x2000006a; + gdcm::TagToType<0x2000,0x00a0> x200000a0; (void)x200000a0; + gdcm::TagToType<0x2000,0x00a1> x200000a1; (void)x200000a1; + gdcm::TagToType<0x2000,0x00a2> x200000a2; (void)x200000a2; + gdcm::TagToType<0x2000,0x00a4> x200000a4; (void)x200000a4; + gdcm::TagToType<0x2000,0x00a8> x200000a8; (void)x200000a8; + gdcm::TagToType<0x2000,0x0500> x20000500; (void)x20000500; + gdcm::TagToType<0x2000,0x0510> x20000510; (void)x20000510; + gdcm::TagToType<0x2010,0x0010> x20100010; (void)x20100010; + gdcm::TagToType<0x2010,0x0030> x20100030; (void)x20100030; + gdcm::TagToType<0x2010,0x0040> x20100040; (void)x20100040; + gdcm::TagToType<0x2010,0x0050> x20100050; (void)x20100050; + gdcm::TagToType<0x2010,0x0052> x20100052; (void)x20100052; + gdcm::TagToType<0x2010,0x0054> x20100054; (void)x20100054; + gdcm::TagToType<0x2010,0x0060> x20100060; (void)x20100060; + gdcm::TagToType<0x2010,0x0080> x20100080; (void)x20100080; + gdcm::TagToType<0x2010,0x00a6> x201000a6; (void)x201000a6; + gdcm::TagToType<0x2010,0x00a7> x201000a7; (void)x201000a7; + gdcm::TagToType<0x2010,0x00a8> x201000a8; (void)x201000a8; + gdcm::TagToType<0x2010,0x00a9> x201000a9; (void)x201000a9; + gdcm::TagToType<0x2010,0x0100> x20100100; (void)x20100100; + gdcm::TagToType<0x2010,0x0110> x20100110; (void)x20100110; + gdcm::TagToType<0x2010,0x0120> x20100120; (void)x20100120; + gdcm::TagToType<0x2010,0x0130> x20100130; (void)x20100130; + gdcm::TagToType<0x2010,0x0140> x20100140; (void)x20100140; + gdcm::TagToType<0x2010,0x0150> x20100150; (void)x20100150; + gdcm::TagToType<0x2010,0x0152> x20100152; (void)x20100152; + gdcm::TagToType<0x2010,0x0154> x20100154; (void)x20100154; + gdcm::TagToType<0x2010,0x015e> x2010015e; (void)x2010015e; + gdcm::TagToType<0x2010,0x0160> x20100160; (void)x20100160; + gdcm::TagToType<0x2010,0x0376> x20100376; (void)x20100376; + gdcm::TagToType<0x2010,0x0500> x20100500; (void)x20100500; + gdcm::TagToType<0x2010,0x0510> x20100510; (void)x20100510; + gdcm::TagToType<0x2010,0x0520> x20100520; (void)x20100520; + gdcm::TagToType<0x2020,0x0010> x20200010; (void)x20200010; + gdcm::TagToType<0x2020,0x0020> x20200020; (void)x20200020; + gdcm::TagToType<0x2020,0x0030> x20200030; (void)x20200030; + gdcm::TagToType<0x2020,0x0040> x20200040; (void)x20200040; + gdcm::TagToType<0x2020,0x0050> x20200050; (void)x20200050; + gdcm::TagToType<0x2020,0x00a0> x202000a0; (void)x202000a0; + gdcm::TagToType<0x2020,0x00a2> x202000a2; (void)x202000a2; + gdcm::TagToType<0x2020,0x0110> x20200110; (void)x20200110; + gdcm::TagToType<0x2020,0x0111> x20200111; (void)x20200111; + gdcm::TagToType<0x2020,0x0130> x20200130; (void)x20200130; + gdcm::TagToType<0x2020,0x0140> x20200140; (void)x20200140; + gdcm::TagToType<0x2030,0x0010> x20300010; (void)x20300010; + gdcm::TagToType<0x2030,0x0020> x20300020; (void)x20300020; + gdcm::TagToType<0x2040,0x0010> x20400010; (void)x20400010; + gdcm::TagToType<0x2040,0x0011> x20400011; (void)x20400011; + gdcm::TagToType<0x2040,0x0020> x20400020; (void)x20400020; + gdcm::TagToType<0x2040,0x0060> x20400060; (void)x20400060; + gdcm::TagToType<0x2040,0x0070> x20400070; (void)x20400070; + gdcm::TagToType<0x2040,0x0072> x20400072; (void)x20400072; + gdcm::TagToType<0x2040,0x0074> x20400074; (void)x20400074; + gdcm::TagToType<0x2040,0x0080> x20400080; (void)x20400080; + gdcm::TagToType<0x2040,0x0082> x20400082; (void)x20400082; + gdcm::TagToType<0x2040,0x0090> x20400090; (void)x20400090; + gdcm::TagToType<0x2040,0x0100> x20400100; (void)x20400100; + gdcm::TagToType<0x2040,0x0500> x20400500; (void)x20400500; + gdcm::TagToType<0x2050,0x0010> x20500010; (void)x20500010; + gdcm::TagToType<0x2050,0x0020> x20500020; (void)x20500020; + gdcm::TagToType<0x2050,0x0500> x20500500; (void)x20500500; + gdcm::TagToType<0x2100,0x0010> x21000010; (void)x21000010; + gdcm::TagToType<0x2100,0x0020> x21000020; (void)x21000020; + gdcm::TagToType<0x2100,0x0030> x21000030; (void)x21000030; + gdcm::TagToType<0x2100,0x0040> x21000040; (void)x21000040; + gdcm::TagToType<0x2100,0x0050> x21000050; (void)x21000050; + gdcm::TagToType<0x2100,0x0070> x21000070; (void)x21000070; + gdcm::TagToType<0x2100,0x0140> x21000140; (void)x21000140; + gdcm::TagToType<0x2100,0x0160> x21000160; (void)x21000160; + gdcm::TagToType<0x2100,0x0170> x21000170; (void)x21000170; + gdcm::TagToType<0x2100,0x0500> x21000500; (void)x21000500; + gdcm::TagToType<0x2110,0x0010> x21100010; (void)x21100010; + gdcm::TagToType<0x2110,0x0020> x21100020; (void)x21100020; + gdcm::TagToType<0x2110,0x0030> x21100030; (void)x21100030; + gdcm::TagToType<0x2110,0x0099> x21100099; (void)x21100099; + gdcm::TagToType<0x2120,0x0010> x21200010; (void)x21200010; + gdcm::TagToType<0x2120,0x0050> x21200050; (void)x21200050; + gdcm::TagToType<0x2120,0x0070> x21200070; (void)x21200070; + gdcm::TagToType<0x2130,0x0010> x21300010; (void)x21300010; + gdcm::TagToType<0x2130,0x0015> x21300015; (void)x21300015; + gdcm::TagToType<0x2130,0x0030> x21300030; (void)x21300030; + gdcm::TagToType<0x2130,0x0040> x21300040; (void)x21300040; + gdcm::TagToType<0x2130,0x0050> x21300050; (void)x21300050; + gdcm::TagToType<0x2130,0x0060> x21300060; (void)x21300060; + gdcm::TagToType<0x2130,0x0080> x21300080; (void)x21300080; + gdcm::TagToType<0x2130,0x00a0> x213000a0; (void)x213000a0; + gdcm::TagToType<0x2130,0x00c0> x213000c0; (void)x213000c0; + gdcm::TagToType<0x2200,0x0001> x22000001; (void)x22000001; + gdcm::TagToType<0x2200,0x0002> x22000002; (void)x22000002; + gdcm::TagToType<0x2200,0x0003> x22000003; (void)x22000003; + gdcm::TagToType<0x2200,0x0004> x22000004; (void)x22000004; + gdcm::TagToType<0x2200,0x0005> x22000005; (void)x22000005; + gdcm::TagToType<0x2200,0x0006> x22000006; (void)x22000006; + gdcm::TagToType<0x2200,0x0007> x22000007; (void)x22000007; + gdcm::TagToType<0x2200,0x0008> x22000008; (void)x22000008; + gdcm::TagToType<0x2200,0x0009> x22000009; (void)x22000009; + gdcm::TagToType<0x2200,0x000a> x2200000a; (void)x2200000a; + gdcm::TagToType<0x2200,0x000b> x2200000b; (void)x2200000b; + gdcm::TagToType<0x2200,0x000c> x2200000c; (void)x2200000c; + gdcm::TagToType<0x2200,0x000d> x2200000d; (void)x2200000d; + gdcm::TagToType<0x2200,0x000e> x2200000e; (void)x2200000e; + gdcm::TagToType<0x2200,0x000f> x2200000f; (void)x2200000f; + gdcm::TagToType<0x2200,0x0020> x22000020; (void)x22000020; + gdcm::TagToType<0x3002,0x0002> x30020002; (void)x30020002; + gdcm::TagToType<0x3002,0x0003> x30020003; (void)x30020003; + gdcm::TagToType<0x3002,0x0004> x30020004; (void)x30020004; + gdcm::TagToType<0x3002,0x000a> x3002000a; (void)x3002000a; + gdcm::TagToType<0x3002,0x000c> x3002000c; (void)x3002000c; + gdcm::TagToType<0x3002,0x000d> x3002000d; (void)x3002000d; + gdcm::TagToType<0x3002,0x000e> x3002000e; (void)x3002000e; + gdcm::TagToType<0x3002,0x0010> x30020010; (void)x30020010; + gdcm::TagToType<0x3002,0x0011> x30020011; (void)x30020011; + gdcm::TagToType<0x3002,0x0012> x30020012; (void)x30020012; + gdcm::TagToType<0x3002,0x0020> x30020020; (void)x30020020; + gdcm::TagToType<0x3002,0x0022> x30020022; (void)x30020022; + gdcm::TagToType<0x3002,0x0024> x30020024; (void)x30020024; + gdcm::TagToType<0x3002,0x0026> x30020026; (void)x30020026; + gdcm::TagToType<0x3002,0x0028> x30020028; (void)x30020028; + gdcm::TagToType<0x3002,0x0029> x30020029; (void)x30020029; + gdcm::TagToType<0x3002,0x0030> x30020030; (void)x30020030; + gdcm::TagToType<0x3002,0x0032> x30020032; (void)x30020032; + gdcm::TagToType<0x3002,0x0034> x30020034; (void)x30020034; + gdcm::TagToType<0x3002,0x0040> x30020040; (void)x30020040; + gdcm::TagToType<0x3002,0x0041> x30020041; (void)x30020041; + gdcm::TagToType<0x3002,0x0042> x30020042; (void)x30020042; + gdcm::TagToType<0x3004,0x0001> x30040001; (void)x30040001; + gdcm::TagToType<0x3004,0x0002> x30040002; (void)x30040002; + gdcm::TagToType<0x3004,0x0004> x30040004; (void)x30040004; + gdcm::TagToType<0x3004,0x0006> x30040006; (void)x30040006; + gdcm::TagToType<0x3004,0x0008> x30040008; (void)x30040008; + gdcm::TagToType<0x3004,0x000a> x3004000a; (void)x3004000a; + gdcm::TagToType<0x3004,0x000c> x3004000c; (void)x3004000c; + gdcm::TagToType<0x3004,0x000e> x3004000e; (void)x3004000e; + gdcm::TagToType<0x3004,0x0010> x30040010; (void)x30040010; + gdcm::TagToType<0x3004,0x0012> x30040012; (void)x30040012; + gdcm::TagToType<0x3004,0x0014> x30040014; (void)x30040014; + gdcm::TagToType<0x3004,0x0040> x30040040; (void)x30040040; + gdcm::TagToType<0x3004,0x0042> x30040042; (void)x30040042; + gdcm::TagToType<0x3004,0x0050> x30040050; (void)x30040050; + gdcm::TagToType<0x3004,0x0052> x30040052; (void)x30040052; + gdcm::TagToType<0x3004,0x0054> x30040054; (void)x30040054; + gdcm::TagToType<0x3004,0x0056> x30040056; (void)x30040056; + gdcm::TagToType<0x3004,0x0058> x30040058; (void)x30040058; + gdcm::TagToType<0x3004,0x0060> x30040060; (void)x30040060; + gdcm::TagToType<0x3004,0x0062> x30040062; (void)x30040062; + gdcm::TagToType<0x3004,0x0070> x30040070; (void)x30040070; + gdcm::TagToType<0x3004,0x0072> x30040072; (void)x30040072; + gdcm::TagToType<0x3004,0x0074> x30040074; (void)x30040074; + gdcm::TagToType<0x3006,0x0002> x30060002; (void)x30060002; + gdcm::TagToType<0x3006,0x0004> x30060004; (void)x30060004; + gdcm::TagToType<0x3006,0x0006> x30060006; (void)x30060006; + gdcm::TagToType<0x3006,0x0008> x30060008; (void)x30060008; + gdcm::TagToType<0x3006,0x0009> x30060009; (void)x30060009; + gdcm::TagToType<0x3006,0x0010> x30060010; (void)x30060010; + gdcm::TagToType<0x3006,0x0012> x30060012; (void)x30060012; + gdcm::TagToType<0x3006,0x0014> x30060014; (void)x30060014; + gdcm::TagToType<0x3006,0x0016> x30060016; (void)x30060016; + gdcm::TagToType<0x3006,0x0020> x30060020; (void)x30060020; + gdcm::TagToType<0x3006,0x0022> x30060022; (void)x30060022; + gdcm::TagToType<0x3006,0x0024> x30060024; (void)x30060024; + gdcm::TagToType<0x3006,0x0026> x30060026; (void)x30060026; + gdcm::TagToType<0x3006,0x0028> x30060028; (void)x30060028; + gdcm::TagToType<0x3006,0x002a> x3006002a; (void)x3006002a; + gdcm::TagToType<0x3006,0x002c> x3006002c; (void)x3006002c; + gdcm::TagToType<0x3006,0x0030> x30060030; (void)x30060030; + gdcm::TagToType<0x3006,0x0033> x30060033; (void)x30060033; + gdcm::TagToType<0x3006,0x0036> x30060036; (void)x30060036; + gdcm::TagToType<0x3006,0x0038> x30060038; (void)x30060038; + gdcm::TagToType<0x3006,0x0039> x30060039; (void)x30060039; + gdcm::TagToType<0x3006,0x0040> x30060040; (void)x30060040; + gdcm::TagToType<0x3006,0x0042> x30060042; (void)x30060042; + gdcm::TagToType<0x3006,0x0044> x30060044; (void)x30060044; + gdcm::TagToType<0x3006,0x0045> x30060045; (void)x30060045; + gdcm::TagToType<0x3006,0x0046> x30060046; (void)x30060046; + gdcm::TagToType<0x3006,0x0048> x30060048; (void)x30060048; + gdcm::TagToType<0x3006,0x0049> x30060049; (void)x30060049; + gdcm::TagToType<0x3006,0x0050> x30060050; (void)x30060050; + gdcm::TagToType<0x3006,0x0080> x30060080; (void)x30060080; + gdcm::TagToType<0x3006,0x0082> x30060082; (void)x30060082; + gdcm::TagToType<0x3006,0x0084> x30060084; (void)x30060084; + gdcm::TagToType<0x3006,0x0085> x30060085; (void)x30060085; + gdcm::TagToType<0x3006,0x0086> x30060086; (void)x30060086; + gdcm::TagToType<0x3006,0x0088> x30060088; (void)x30060088; + gdcm::TagToType<0x3006,0x00a0> x300600a0; (void)x300600a0; + gdcm::TagToType<0x3006,0x00a4> x300600a4; (void)x300600a4; + gdcm::TagToType<0x3006,0x00a6> x300600a6; (void)x300600a6; + gdcm::TagToType<0x3006,0x00b0> x300600b0; (void)x300600b0; + gdcm::TagToType<0x3006,0x00b2> x300600b2; (void)x300600b2; + gdcm::TagToType<0x3006,0x00b4> x300600b4; (void)x300600b4; + gdcm::TagToType<0x3006,0x00b6> x300600b6; (void)x300600b6; + gdcm::TagToType<0x3006,0x00b7> x300600b7; (void)x300600b7; + gdcm::TagToType<0x3006,0x00b8> x300600b8; (void)x300600b8; + gdcm::TagToType<0x3006,0x00c0> x300600c0; (void)x300600c0; + gdcm::TagToType<0x3006,0x00c2> x300600c2; (void)x300600c2; + gdcm::TagToType<0x3006,0x00c4> x300600c4; (void)x300600c4; + gdcm::TagToType<0x3006,0x00c6> x300600c6; (void)x300600c6; + gdcm::TagToType<0x3006,0x00c8> x300600c8; (void)x300600c8; + gdcm::TagToType<0x3008,0x0010> x30080010; (void)x30080010; + gdcm::TagToType<0x3008,0x0012> x30080012; (void)x30080012; + gdcm::TagToType<0x3008,0x0014> x30080014; (void)x30080014; + gdcm::TagToType<0x3008,0x0016> x30080016; (void)x30080016; + gdcm::TagToType<0x3008,0x0020> x30080020; (void)x30080020; + gdcm::TagToType<0x3008,0x0021> x30080021; (void)x30080021; + gdcm::TagToType<0x3008,0x0022> x30080022; (void)x30080022; + gdcm::TagToType<0x3008,0x0024> x30080024; (void)x30080024; + gdcm::TagToType<0x3008,0x0025> x30080025; (void)x30080025; + gdcm::TagToType<0x3008,0x002a> x3008002a; (void)x3008002a; + gdcm::TagToType<0x3008,0x002b> x3008002b; (void)x3008002b; + gdcm::TagToType<0x3008,0x002c> x3008002c; (void)x3008002c; + gdcm::TagToType<0x3008,0x0030> x30080030; (void)x30080030; + gdcm::TagToType<0x3008,0x0032> x30080032; (void)x30080032; + gdcm::TagToType<0x3008,0x0033> x30080033; (void)x30080033; + gdcm::TagToType<0x3008,0x0036> x30080036; (void)x30080036; + gdcm::TagToType<0x3008,0x0037> x30080037; (void)x30080037; + gdcm::TagToType<0x3008,0x003a> x3008003a; (void)x3008003a; + gdcm::TagToType<0x3008,0x003b> x3008003b; (void)x3008003b; + gdcm::TagToType<0x3008,0x0040> x30080040; (void)x30080040; + gdcm::TagToType<0x3008,0x0041> x30080041; (void)x30080041; + gdcm::TagToType<0x3008,0x0042> x30080042; (void)x30080042; + gdcm::TagToType<0x3008,0x0044> x30080044; (void)x30080044; + gdcm::TagToType<0x3008,0x0045> x30080045; (void)x30080045; + gdcm::TagToType<0x3008,0x0046> x30080046; (void)x30080046; + gdcm::TagToType<0x3008,0x0047> x30080047; (void)x30080047; + gdcm::TagToType<0x3008,0x0048> x30080048; (void)x30080048; + gdcm::TagToType<0x3008,0x0050> x30080050; (void)x30080050; + gdcm::TagToType<0x3008,0x0052> x30080052; (void)x30080052; + gdcm::TagToType<0x3008,0x0054> x30080054; (void)x30080054; + gdcm::TagToType<0x3008,0x0056> x30080056; (void)x30080056; + gdcm::TagToType<0x3008,0x005a> x3008005a; (void)x3008005a; + gdcm::TagToType<0x3008,0x0060> x30080060; (void)x30080060; + gdcm::TagToType<0x3008,0x0061> x30080061; (void)x30080061; + gdcm::TagToType<0x3008,0x0062> x30080062; (void)x30080062; + gdcm::TagToType<0x3008,0x0063> x30080063; (void)x30080063; + gdcm::TagToType<0x3008,0x0064> x30080064; (void)x30080064; + gdcm::TagToType<0x3008,0x0065> x30080065; (void)x30080065; + gdcm::TagToType<0x3008,0x0066> x30080066; (void)x30080066; + gdcm::TagToType<0x3008,0x0068> x30080068; (void)x30080068; + gdcm::TagToType<0x3008,0x006a> x3008006a; (void)x3008006a; + gdcm::TagToType<0x3008,0x0070> x30080070; (void)x30080070; + gdcm::TagToType<0x3008,0x0072> x30080072; (void)x30080072; + gdcm::TagToType<0x3008,0x0074> x30080074; (void)x30080074; + gdcm::TagToType<0x3008,0x0076> x30080076; (void)x30080076; + gdcm::TagToType<0x3008,0x0078> x30080078; (void)x30080078; + gdcm::TagToType<0x3008,0x007a> x3008007a; (void)x3008007a; + gdcm::TagToType<0x3008,0x0080> x30080080; (void)x30080080; + gdcm::TagToType<0x3008,0x0082> x30080082; (void)x30080082; + gdcm::TagToType<0x3008,0x0090> x30080090; (void)x30080090; + gdcm::TagToType<0x3008,0x0092> x30080092; (void)x30080092; + gdcm::TagToType<0x3008,0x00a0> x300800a0; (void)x300800a0; + gdcm::TagToType<0x3008,0x00b0> x300800b0; (void)x300800b0; + gdcm::TagToType<0x3008,0x00c0> x300800c0; (void)x300800c0; + gdcm::TagToType<0x3008,0x00d0> x300800d0; (void)x300800d0; + gdcm::TagToType<0x3008,0x00e0> x300800e0; (void)x300800e0; + gdcm::TagToType<0x3008,0x00f0> x300800f0; (void)x300800f0; + gdcm::TagToType<0x3008,0x00f2> x300800f2; (void)x300800f2; + gdcm::TagToType<0x3008,0x00f4> x300800f4; (void)x300800f4; + gdcm::TagToType<0x3008,0x00f6> x300800f6; (void)x300800f6; + gdcm::TagToType<0x3008,0x0100> x30080100; (void)x30080100; + gdcm::TagToType<0x3008,0x0105> x30080105; (void)x30080105; + gdcm::TagToType<0x3008,0x0110> x30080110; (void)x30080110; + gdcm::TagToType<0x3008,0x0116> x30080116; (void)x30080116; + gdcm::TagToType<0x3008,0x0120> x30080120; (void)x30080120; + gdcm::TagToType<0x3008,0x0122> x30080122; (void)x30080122; + gdcm::TagToType<0x3008,0x0130> x30080130; (void)x30080130; + gdcm::TagToType<0x3008,0x0132> x30080132; (void)x30080132; + gdcm::TagToType<0x3008,0x0134> x30080134; (void)x30080134; + gdcm::TagToType<0x3008,0x0136> x30080136; (void)x30080136; + gdcm::TagToType<0x3008,0x0138> x30080138; (void)x30080138; + gdcm::TagToType<0x3008,0x013a> x3008013a; (void)x3008013a; + gdcm::TagToType<0x3008,0x013c> x3008013c; (void)x3008013c; + gdcm::TagToType<0x3008,0x0140> x30080140; (void)x30080140; + gdcm::TagToType<0x3008,0x0142> x30080142; (void)x30080142; + gdcm::TagToType<0x3008,0x0150> x30080150; (void)x30080150; + gdcm::TagToType<0x3008,0x0152> x30080152; (void)x30080152; + gdcm::TagToType<0x3008,0x0160> x30080160; (void)x30080160; + gdcm::TagToType<0x3008,0x0162> x30080162; (void)x30080162; + gdcm::TagToType<0x3008,0x0164> x30080164; (void)x30080164; + gdcm::TagToType<0x3008,0x0166> x30080166; (void)x30080166; + gdcm::TagToType<0x3008,0x0168> x30080168; (void)x30080168; + gdcm::TagToType<0x3008,0x0200> x30080200; (void)x30080200; + gdcm::TagToType<0x3008,0x0202> x30080202; (void)x30080202; + gdcm::TagToType<0x3008,0x0220> x30080220; (void)x30080220; + gdcm::TagToType<0x3008,0x0223> x30080223; (void)x30080223; + gdcm::TagToType<0x3008,0x0224> x30080224; (void)x30080224; + gdcm::TagToType<0x3008,0x0230> x30080230; (void)x30080230; + gdcm::TagToType<0x3008,0x0240> x30080240; (void)x30080240; + gdcm::TagToType<0x3008,0x0250> x30080250; (void)x30080250; + gdcm::TagToType<0x3008,0x0251> x30080251; (void)x30080251; + gdcm::TagToType<0x300a,0x0002> x300a0002; (void)x300a0002; + gdcm::TagToType<0x300a,0x0003> x300a0003; (void)x300a0003; + gdcm::TagToType<0x300a,0x0004> x300a0004; (void)x300a0004; + gdcm::TagToType<0x300a,0x0006> x300a0006; (void)x300a0006; + gdcm::TagToType<0x300a,0x0007> x300a0007; (void)x300a0007; + gdcm::TagToType<0x300a,0x0009> x300a0009; (void)x300a0009; + gdcm::TagToType<0x300a,0x000a> x300a000a; (void)x300a000a; + gdcm::TagToType<0x300a,0x000b> x300a000b; (void)x300a000b; + gdcm::TagToType<0x300a,0x000c> x300a000c; (void)x300a000c; + gdcm::TagToType<0x300a,0x000e> x300a000e; (void)x300a000e; + gdcm::TagToType<0x300a,0x0010> x300a0010; (void)x300a0010; + gdcm::TagToType<0x300a,0x0012> x300a0012; (void)x300a0012; + gdcm::TagToType<0x300a,0x0013> x300a0013; (void)x300a0013; + gdcm::TagToType<0x300a,0x0014> x300a0014; (void)x300a0014; + gdcm::TagToType<0x300a,0x0015> x300a0015; (void)x300a0015; + gdcm::TagToType<0x300a,0x0016> x300a0016; (void)x300a0016; + gdcm::TagToType<0x300a,0x0018> x300a0018; (void)x300a0018; + gdcm::TagToType<0x300a,0x001a> x300a001a; (void)x300a001a; + gdcm::TagToType<0x300a,0x0020> x300a0020; (void)x300a0020; + gdcm::TagToType<0x300a,0x0021> x300a0021; (void)x300a0021; + gdcm::TagToType<0x300a,0x0022> x300a0022; (void)x300a0022; + gdcm::TagToType<0x300a,0x0023> x300a0023; (void)x300a0023; + gdcm::TagToType<0x300a,0x0025> x300a0025; (void)x300a0025; + gdcm::TagToType<0x300a,0x0026> x300a0026; (void)x300a0026; + gdcm::TagToType<0x300a,0x0027> x300a0027; (void)x300a0027; + gdcm::TagToType<0x300a,0x0028> x300a0028; (void)x300a0028; + gdcm::TagToType<0x300a,0x002a> x300a002a; (void)x300a002a; + gdcm::TagToType<0x300a,0x002b> x300a002b; (void)x300a002b; + gdcm::TagToType<0x300a,0x002c> x300a002c; (void)x300a002c; + gdcm::TagToType<0x300a,0x002d> x300a002d; (void)x300a002d; + gdcm::TagToType<0x300a,0x0040> x300a0040; (void)x300a0040; + gdcm::TagToType<0x300a,0x0042> x300a0042; (void)x300a0042; + gdcm::TagToType<0x300a,0x0043> x300a0043; (void)x300a0043; + gdcm::TagToType<0x300a,0x0044> x300a0044; (void)x300a0044; + gdcm::TagToType<0x300a,0x0046> x300a0046; (void)x300a0046; + gdcm::TagToType<0x300a,0x0048> x300a0048; (void)x300a0048; + gdcm::TagToType<0x300a,0x004a> x300a004a; (void)x300a004a; + gdcm::TagToType<0x300a,0x004b> x300a004b; (void)x300a004b; + gdcm::TagToType<0x300a,0x004c> x300a004c; (void)x300a004c; + gdcm::TagToType<0x300a,0x004e> x300a004e; (void)x300a004e; + gdcm::TagToType<0x300a,0x004f> x300a004f; (void)x300a004f; + gdcm::TagToType<0x300a,0x0050> x300a0050; (void)x300a0050; + gdcm::TagToType<0x300a,0x0051> x300a0051; (void)x300a0051; + gdcm::TagToType<0x300a,0x0052> x300a0052; (void)x300a0052; + gdcm::TagToType<0x300a,0x0053> x300a0053; (void)x300a0053; + gdcm::TagToType<0x300a,0x0055> x300a0055; (void)x300a0055; + gdcm::TagToType<0x300a,0x0070> x300a0070; (void)x300a0070; + gdcm::TagToType<0x300a,0x0071> x300a0071; (void)x300a0071; + gdcm::TagToType<0x300a,0x0072> x300a0072; (void)x300a0072; + gdcm::TagToType<0x300a,0x0078> x300a0078; (void)x300a0078; + gdcm::TagToType<0x300a,0x0079> x300a0079; (void)x300a0079; + gdcm::TagToType<0x300a,0x007a> x300a007a; (void)x300a007a; + gdcm::TagToType<0x300a,0x007b> x300a007b; (void)x300a007b; + gdcm::TagToType<0x300a,0x0080> x300a0080; (void)x300a0080; + gdcm::TagToType<0x300a,0x0082> x300a0082; (void)x300a0082; + gdcm::TagToType<0x300a,0x0084> x300a0084; (void)x300a0084; + gdcm::TagToType<0x300a,0x0086> x300a0086; (void)x300a0086; + gdcm::TagToType<0x300a,0x0088> x300a0088; (void)x300a0088; + gdcm::TagToType<0x300a,0x0089> x300a0089; (void)x300a0089; + gdcm::TagToType<0x300a,0x008a> x300a008a; (void)x300a008a; + gdcm::TagToType<0x300a,0x00a0> x300a00a0; (void)x300a00a0; + gdcm::TagToType<0x300a,0x00a2> x300a00a2; (void)x300a00a2; + gdcm::TagToType<0x300a,0x00a4> x300a00a4; (void)x300a00a4; + gdcm::TagToType<0x300a,0x00b0> x300a00b0; (void)x300a00b0; + gdcm::TagToType<0x300a,0x00b2> x300a00b2; (void)x300a00b2; + gdcm::TagToType<0x300a,0x00b3> x300a00b3; (void)x300a00b3; + gdcm::TagToType<0x300a,0x00b4> x300a00b4; (void)x300a00b4; + gdcm::TagToType<0x300a,0x00b6> x300a00b6; (void)x300a00b6; + gdcm::TagToType<0x300a,0x00b8> x300a00b8; (void)x300a00b8; + gdcm::TagToType<0x300a,0x00ba> x300a00ba; (void)x300a00ba; + gdcm::TagToType<0x300a,0x00bb> x300a00bb; (void)x300a00bb; + gdcm::TagToType<0x300a,0x00bc> x300a00bc; (void)x300a00bc; + gdcm::TagToType<0x300a,0x00be> x300a00be; (void)x300a00be; + gdcm::TagToType<0x300a,0x00c0> x300a00c0; (void)x300a00c0; + gdcm::TagToType<0x300a,0x00c2> x300a00c2; (void)x300a00c2; + gdcm::TagToType<0x300a,0x00c3> x300a00c3; (void)x300a00c3; + gdcm::TagToType<0x300a,0x00c4> x300a00c4; (void)x300a00c4; + gdcm::TagToType<0x300a,0x00c6> x300a00c6; (void)x300a00c6; + gdcm::TagToType<0x300a,0x00c7> x300a00c7; (void)x300a00c7; + gdcm::TagToType<0x300a,0x00c8> x300a00c8; (void)x300a00c8; + gdcm::TagToType<0x300a,0x00ca> x300a00ca; (void)x300a00ca; + gdcm::TagToType<0x300a,0x00cc> x300a00cc; (void)x300a00cc; + gdcm::TagToType<0x300a,0x00ce> x300a00ce; (void)x300a00ce; + gdcm::TagToType<0x300a,0x00d0> x300a00d0; (void)x300a00d0; + gdcm::TagToType<0x300a,0x00d1> x300a00d1; (void)x300a00d1; + gdcm::TagToType<0x300a,0x00d2> x300a00d2; (void)x300a00d2; + gdcm::TagToType<0x300a,0x00d3> x300a00d3; (void)x300a00d3; + gdcm::TagToType<0x300a,0x00d4> x300a00d4; (void)x300a00d4; + gdcm::TagToType<0x300a,0x00d5> x300a00d5; (void)x300a00d5; + gdcm::TagToType<0x300a,0x00d6> x300a00d6; (void)x300a00d6; + gdcm::TagToType<0x300a,0x00d7> x300a00d7; (void)x300a00d7; + gdcm::TagToType<0x300a,0x00d8> x300a00d8; (void)x300a00d8; + gdcm::TagToType<0x300a,0x00d9> x300a00d9; (void)x300a00d9; + gdcm::TagToType<0x300a,0x00da> x300a00da; (void)x300a00da; + gdcm::TagToType<0x300a,0x00db> x300a00db; (void)x300a00db; + gdcm::TagToType<0x300a,0x00dc> x300a00dc; (void)x300a00dc; + gdcm::TagToType<0x300a,0x00dd> x300a00dd; (void)x300a00dd; + gdcm::TagToType<0x300a,0x00e0> x300a00e0; (void)x300a00e0; + gdcm::TagToType<0x300a,0x00e1> x300a00e1; (void)x300a00e1; + gdcm::TagToType<0x300a,0x00e2> x300a00e2; (void)x300a00e2; + gdcm::TagToType<0x300a,0x00e3> x300a00e3; (void)x300a00e3; + gdcm::TagToType<0x300a,0x00e4> x300a00e4; (void)x300a00e4; + gdcm::TagToType<0x300a,0x00e5> x300a00e5; (void)x300a00e5; + gdcm::TagToType<0x300a,0x00e6> x300a00e6; (void)x300a00e6; + gdcm::TagToType<0x300a,0x00e7> x300a00e7; (void)x300a00e7; + gdcm::TagToType<0x300a,0x00e8> x300a00e8; (void)x300a00e8; + gdcm::TagToType<0x300a,0x00e9> x300a00e9; (void)x300a00e9; + gdcm::TagToType<0x300a,0x00ea> x300a00ea; (void)x300a00ea; + gdcm::TagToType<0x300a,0x00eb> x300a00eb; (void)x300a00eb; + gdcm::TagToType<0x300a,0x00ec> x300a00ec; (void)x300a00ec; + gdcm::TagToType<0x300a,0x00ed> x300a00ed; (void)x300a00ed; + gdcm::TagToType<0x300a,0x00ee> x300a00ee; (void)x300a00ee; + gdcm::TagToType<0x300a,0x00f0> x300a00f0; (void)x300a00f0; + gdcm::TagToType<0x300a,0x00f2> x300a00f2; (void)x300a00f2; + gdcm::TagToType<0x300a,0x00f3> x300a00f3; (void)x300a00f3; + gdcm::TagToType<0x300a,0x00f4> x300a00f4; (void)x300a00f4; + gdcm::TagToType<0x300a,0x00f5> x300a00f5; (void)x300a00f5; + gdcm::TagToType<0x300a,0x00f6> x300a00f6; (void)x300a00f6; + gdcm::TagToType<0x300a,0x00f7> x300a00f7; (void)x300a00f7; + gdcm::TagToType<0x300a,0x00f8> x300a00f8; (void)x300a00f8; + gdcm::TagToType<0x300a,0x00f9> x300a00f9; (void)x300a00f9; + gdcm::TagToType<0x300a,0x00fa> x300a00fa; (void)x300a00fa; + gdcm::TagToType<0x300a,0x00fb> x300a00fb; (void)x300a00fb; + gdcm::TagToType<0x300a,0x00fc> x300a00fc; (void)x300a00fc; + gdcm::TagToType<0x300a,0x00fe> x300a00fe; (void)x300a00fe; + gdcm::TagToType<0x300a,0x0100> x300a0100; (void)x300a0100; + gdcm::TagToType<0x300a,0x0102> x300a0102; (void)x300a0102; + gdcm::TagToType<0x300a,0x0104> x300a0104; (void)x300a0104; + gdcm::TagToType<0x300a,0x0106> x300a0106; (void)x300a0106; + gdcm::TagToType<0x300a,0x0107> x300a0107; (void)x300a0107; + gdcm::TagToType<0x300a,0x0108> x300a0108; (void)x300a0108; + gdcm::TagToType<0x300a,0x0109> x300a0109; (void)x300a0109; + gdcm::TagToType<0x300a,0x010a> x300a010a; (void)x300a010a; + gdcm::TagToType<0x300a,0x010c> x300a010c; (void)x300a010c; + gdcm::TagToType<0x300a,0x010e> x300a010e; (void)x300a010e; + gdcm::TagToType<0x300a,0x0110> x300a0110; (void)x300a0110; + gdcm::TagToType<0x300a,0x0111> x300a0111; (void)x300a0111; + gdcm::TagToType<0x300a,0x0112> x300a0112; (void)x300a0112; + gdcm::TagToType<0x300a,0x0114> x300a0114; (void)x300a0114; + gdcm::TagToType<0x300a,0x0115> x300a0115; (void)x300a0115; + gdcm::TagToType<0x300a,0x0116> x300a0116; (void)x300a0116; + gdcm::TagToType<0x300a,0x0118> x300a0118; (void)x300a0118; + gdcm::TagToType<0x300a,0x011a> x300a011a; (void)x300a011a; + gdcm::TagToType<0x300a,0x011c> x300a011c; (void)x300a011c; + gdcm::TagToType<0x300a,0x011e> x300a011e; (void)x300a011e; + gdcm::TagToType<0x300a,0x011f> x300a011f; (void)x300a011f; + gdcm::TagToType<0x300a,0x0120> x300a0120; (void)x300a0120; + gdcm::TagToType<0x300a,0x0121> x300a0121; (void)x300a0121; + gdcm::TagToType<0x300a,0x0122> x300a0122; (void)x300a0122; + gdcm::TagToType<0x300a,0x0123> x300a0123; (void)x300a0123; + gdcm::TagToType<0x300a,0x0124> x300a0124; (void)x300a0124; + gdcm::TagToType<0x300a,0x0125> x300a0125; (void)x300a0125; + gdcm::TagToType<0x300a,0x0126> x300a0126; (void)x300a0126; + gdcm::TagToType<0x300a,0x0128> x300a0128; (void)x300a0128; + gdcm::TagToType<0x300a,0x0129> x300a0129; (void)x300a0129; + gdcm::TagToType<0x300a,0x012a> x300a012a; (void)x300a012a; + gdcm::TagToType<0x300a,0x012c> x300a012c; (void)x300a012c; + gdcm::TagToType<0x300a,0x012e> x300a012e; (void)x300a012e; + gdcm::TagToType<0x300a,0x0130> x300a0130; (void)x300a0130; + gdcm::TagToType<0x300a,0x0134> x300a0134; (void)x300a0134; + gdcm::TagToType<0x300a,0x0140> x300a0140; (void)x300a0140; + gdcm::TagToType<0x300a,0x0142> x300a0142; (void)x300a0142; + gdcm::TagToType<0x300a,0x0144> x300a0144; (void)x300a0144; + gdcm::TagToType<0x300a,0x0146> x300a0146; (void)x300a0146; + gdcm::TagToType<0x300a,0x0148> x300a0148; (void)x300a0148; + gdcm::TagToType<0x300a,0x014a> x300a014a; (void)x300a014a; + gdcm::TagToType<0x300a,0x014c> x300a014c; (void)x300a014c; + gdcm::TagToType<0x300a,0x014e> x300a014e; (void)x300a014e; + gdcm::TagToType<0x300a,0x0180> x300a0180; (void)x300a0180; + gdcm::TagToType<0x300a,0x0182> x300a0182; (void)x300a0182; + gdcm::TagToType<0x300a,0x0183> x300a0183; (void)x300a0183; + gdcm::TagToType<0x300a,0x0184> x300a0184; (void)x300a0184; + gdcm::TagToType<0x300a,0x0190> x300a0190; (void)x300a0190; + gdcm::TagToType<0x300a,0x0192> x300a0192; (void)x300a0192; + gdcm::TagToType<0x300a,0x0194> x300a0194; (void)x300a0194; + gdcm::TagToType<0x300a,0x0196> x300a0196; (void)x300a0196; + gdcm::TagToType<0x300a,0x0198> x300a0198; (void)x300a0198; + gdcm::TagToType<0x300a,0x0199> x300a0199; (void)x300a0199; + gdcm::TagToType<0x300a,0x019a> x300a019a; (void)x300a019a; + gdcm::TagToType<0x300a,0x01a0> x300a01a0; (void)x300a01a0; + gdcm::TagToType<0x300a,0x01a2> x300a01a2; (void)x300a01a2; + gdcm::TagToType<0x300a,0x01a4> x300a01a4; (void)x300a01a4; + gdcm::TagToType<0x300a,0x01a6> x300a01a6; (void)x300a01a6; + gdcm::TagToType<0x300a,0x01a8> x300a01a8; (void)x300a01a8; + gdcm::TagToType<0x300a,0x01b0> x300a01b0; (void)x300a01b0; + gdcm::TagToType<0x300a,0x01b2> x300a01b2; (void)x300a01b2; + gdcm::TagToType<0x300a,0x01b4> x300a01b4; (void)x300a01b4; + gdcm::TagToType<0x300a,0x01b6> x300a01b6; (void)x300a01b6; + gdcm::TagToType<0x300a,0x01b8> x300a01b8; (void)x300a01b8; + gdcm::TagToType<0x300a,0x01ba> x300a01ba; (void)x300a01ba; + gdcm::TagToType<0x300a,0x01bc> x300a01bc; (void)x300a01bc; + gdcm::TagToType<0x300a,0x01d0> x300a01d0; (void)x300a01d0; + gdcm::TagToType<0x300a,0x01d2> x300a01d2; (void)x300a01d2; + gdcm::TagToType<0x300a,0x01d4> x300a01d4; (void)x300a01d4; + gdcm::TagToType<0x300a,0x01d6> x300a01d6; (void)x300a01d6; + gdcm::TagToType<0x300a,0x0200> x300a0200; (void)x300a0200; + gdcm::TagToType<0x300a,0x0202> x300a0202; (void)x300a0202; + gdcm::TagToType<0x300a,0x0206> x300a0206; (void)x300a0206; + gdcm::TagToType<0x300a,0x0210> x300a0210; (void)x300a0210; + gdcm::TagToType<0x300a,0x0212> x300a0212; (void)x300a0212; + gdcm::TagToType<0x300a,0x0214> x300a0214; (void)x300a0214; + gdcm::TagToType<0x300a,0x0216> x300a0216; (void)x300a0216; + gdcm::TagToType<0x300a,0x0218> x300a0218; (void)x300a0218; + gdcm::TagToType<0x300a,0x021a> x300a021a; (void)x300a021a; + gdcm::TagToType<0x300a,0x0222> x300a0222; (void)x300a0222; + gdcm::TagToType<0x300a,0x0224> x300a0224; (void)x300a0224; + gdcm::TagToType<0x300a,0x0226> x300a0226; (void)x300a0226; + gdcm::TagToType<0x300a,0x0228> x300a0228; (void)x300a0228; + gdcm::TagToType<0x300a,0x0229> x300a0229; (void)x300a0229; + gdcm::TagToType<0x300a,0x022a> x300a022a; (void)x300a022a; + gdcm::TagToType<0x300a,0x022b> x300a022b; (void)x300a022b; + gdcm::TagToType<0x300a,0x022c> x300a022c; (void)x300a022c; + gdcm::TagToType<0x300a,0x022e> x300a022e; (void)x300a022e; + gdcm::TagToType<0x300a,0x0230> x300a0230; (void)x300a0230; + gdcm::TagToType<0x300a,0x0232> x300a0232; (void)x300a0232; + gdcm::TagToType<0x300a,0x0234> x300a0234; (void)x300a0234; + gdcm::TagToType<0x300a,0x0236> x300a0236; (void)x300a0236; + gdcm::TagToType<0x300a,0x0238> x300a0238; (void)x300a0238; + gdcm::TagToType<0x300a,0x0240> x300a0240; (void)x300a0240; + gdcm::TagToType<0x300a,0x0242> x300a0242; (void)x300a0242; + gdcm::TagToType<0x300a,0x0244> x300a0244; (void)x300a0244; + gdcm::TagToType<0x300a,0x0250> x300a0250; (void)x300a0250; + gdcm::TagToType<0x300a,0x0260> x300a0260; (void)x300a0260; + gdcm::TagToType<0x300a,0x0262> x300a0262; (void)x300a0262; + gdcm::TagToType<0x300a,0x0263> x300a0263; (void)x300a0263; + gdcm::TagToType<0x300a,0x0264> x300a0264; (void)x300a0264; + gdcm::TagToType<0x300a,0x0266> x300a0266; (void)x300a0266; + gdcm::TagToType<0x300a,0x026a> x300a026a; (void)x300a026a; + gdcm::TagToType<0x300a,0x026c> x300a026c; (void)x300a026c; + gdcm::TagToType<0x300a,0x0280> x300a0280; (void)x300a0280; + gdcm::TagToType<0x300a,0x0282> x300a0282; (void)x300a0282; + gdcm::TagToType<0x300a,0x0284> x300a0284; (void)x300a0284; + gdcm::TagToType<0x300a,0x0286> x300a0286; (void)x300a0286; + gdcm::TagToType<0x300a,0x0288> x300a0288; (void)x300a0288; + gdcm::TagToType<0x300a,0x028a> x300a028a; (void)x300a028a; + gdcm::TagToType<0x300a,0x028c> x300a028c; (void)x300a028c; + gdcm::TagToType<0x300a,0x0290> x300a0290; (void)x300a0290; + gdcm::TagToType<0x300a,0x0291> x300a0291; (void)x300a0291; + gdcm::TagToType<0x300a,0x0292> x300a0292; (void)x300a0292; + gdcm::TagToType<0x300a,0x0294> x300a0294; (void)x300a0294; + gdcm::TagToType<0x300a,0x0296> x300a0296; (void)x300a0296; + gdcm::TagToType<0x300a,0x0298> x300a0298; (void)x300a0298; + gdcm::TagToType<0x300a,0x029c> x300a029c; (void)x300a029c; + gdcm::TagToType<0x300a,0x029e> x300a029e; (void)x300a029e; + gdcm::TagToType<0x300a,0x02a0> x300a02a0; (void)x300a02a0; + gdcm::TagToType<0x300a,0x02a2> x300a02a2; (void)x300a02a2; + gdcm::TagToType<0x300a,0x02a4> x300a02a4; (void)x300a02a4; + gdcm::TagToType<0x300a,0x02b0> x300a02b0; (void)x300a02b0; + gdcm::TagToType<0x300a,0x02b2> x300a02b2; (void)x300a02b2; + gdcm::TagToType<0x300a,0x02b3> x300a02b3; (void)x300a02b3; + gdcm::TagToType<0x300a,0x02b4> x300a02b4; (void)x300a02b4; + gdcm::TagToType<0x300a,0x02b8> x300a02b8; (void)x300a02b8; + gdcm::TagToType<0x300a,0x02ba> x300a02ba; (void)x300a02ba; + gdcm::TagToType<0x300a,0x02c8> x300a02c8; (void)x300a02c8; + gdcm::TagToType<0x300a,0x02d0> x300a02d0; (void)x300a02d0; + gdcm::TagToType<0x300a,0x02d2> x300a02d2; (void)x300a02d2; + gdcm::TagToType<0x300a,0x02d4> x300a02d4; (void)x300a02d4; + gdcm::TagToType<0x300a,0x02d6> x300a02d6; (void)x300a02d6; + gdcm::TagToType<0x300a,0x02e0> x300a02e0; (void)x300a02e0; + gdcm::TagToType<0x300a,0x02e1> x300a02e1; (void)x300a02e1; + gdcm::TagToType<0x300a,0x02e2> x300a02e2; (void)x300a02e2; + gdcm::TagToType<0x300a,0x02e3> x300a02e3; (void)x300a02e3; + gdcm::TagToType<0x300a,0x02e4> x300a02e4; (void)x300a02e4; + gdcm::TagToType<0x300a,0x02e5> x300a02e5; (void)x300a02e5; + gdcm::TagToType<0x300a,0x02e6> x300a02e6; (void)x300a02e6; + gdcm::TagToType<0x300a,0x02e7> x300a02e7; (void)x300a02e7; + gdcm::TagToType<0x300a,0x02e8> x300a02e8; (void)x300a02e8; + gdcm::TagToType<0x300a,0x02ea> x300a02ea; (void)x300a02ea; + gdcm::TagToType<0x300a,0x02eb> x300a02eb; (void)x300a02eb; + gdcm::TagToType<0x300a,0x0302> x300a0302; (void)x300a0302; + gdcm::TagToType<0x300a,0x0304> x300a0304; (void)x300a0304; + gdcm::TagToType<0x300a,0x0306> x300a0306; (void)x300a0306; + gdcm::TagToType<0x300a,0x0308> x300a0308; (void)x300a0308; + gdcm::TagToType<0x300a,0x030a> x300a030a; (void)x300a030a; + gdcm::TagToType<0x300a,0x030c> x300a030c; (void)x300a030c; + gdcm::TagToType<0x300a,0x030d> x300a030d; (void)x300a030d; + gdcm::TagToType<0x300a,0x030f> x300a030f; (void)x300a030f; + gdcm::TagToType<0x300a,0x0312> x300a0312; (void)x300a0312; + gdcm::TagToType<0x300a,0x0314> x300a0314; (void)x300a0314; + gdcm::TagToType<0x300a,0x0316> x300a0316; (void)x300a0316; + gdcm::TagToType<0x300a,0x0318> x300a0318; (void)x300a0318; + gdcm::TagToType<0x300a,0x0320> x300a0320; (void)x300a0320; + gdcm::TagToType<0x300a,0x0322> x300a0322; (void)x300a0322; + gdcm::TagToType<0x300a,0x0330> x300a0330; (void)x300a0330; + gdcm::TagToType<0x300a,0x0332> x300a0332; (void)x300a0332; + gdcm::TagToType<0x300a,0x0334> x300a0334; (void)x300a0334; + gdcm::TagToType<0x300a,0x0336> x300a0336; (void)x300a0336; + gdcm::TagToType<0x300a,0x0338> x300a0338; (void)x300a0338; + gdcm::TagToType<0x300a,0x033a> x300a033a; (void)x300a033a; + gdcm::TagToType<0x300a,0x033c> x300a033c; (void)x300a033c; + gdcm::TagToType<0x300a,0x0340> x300a0340; (void)x300a0340; + gdcm::TagToType<0x300a,0x0342> x300a0342; (void)x300a0342; + gdcm::TagToType<0x300a,0x0344> x300a0344; (void)x300a0344; + gdcm::TagToType<0x300a,0x0346> x300a0346; (void)x300a0346; + gdcm::TagToType<0x300a,0x0348> x300a0348; (void)x300a0348; + gdcm::TagToType<0x300a,0x034a> x300a034a; (void)x300a034a; + gdcm::TagToType<0x300a,0x034c> x300a034c; (void)x300a034c; + gdcm::TagToType<0x300a,0x0350> x300a0350; (void)x300a0350; + gdcm::TagToType<0x300a,0x0352> x300a0352; (void)x300a0352; + gdcm::TagToType<0x300a,0x0354> x300a0354; (void)x300a0354; + gdcm::TagToType<0x300a,0x0356> x300a0356; (void)x300a0356; + gdcm::TagToType<0x300a,0x0358> x300a0358; (void)x300a0358; + gdcm::TagToType<0x300a,0x035a> x300a035a; (void)x300a035a; + gdcm::TagToType<0x300a,0x0360> x300a0360; (void)x300a0360; + gdcm::TagToType<0x300a,0x0362> x300a0362; (void)x300a0362; + gdcm::TagToType<0x300a,0x0364> x300a0364; (void)x300a0364; + gdcm::TagToType<0x300a,0x0366> x300a0366; (void)x300a0366; + gdcm::TagToType<0x300a,0x0370> x300a0370; (void)x300a0370; + gdcm::TagToType<0x300a,0x0372> x300a0372; (void)x300a0372; + gdcm::TagToType<0x300a,0x0374> x300a0374; (void)x300a0374; + gdcm::TagToType<0x300a,0x0380> x300a0380; (void)x300a0380; + gdcm::TagToType<0x300a,0x0382> x300a0382; (void)x300a0382; + gdcm::TagToType<0x300a,0x0384> x300a0384; (void)x300a0384; + gdcm::TagToType<0x300a,0x0386> x300a0386; (void)x300a0386; + gdcm::TagToType<0x300a,0x0388> x300a0388; (void)x300a0388; + gdcm::TagToType<0x300a,0x038a> x300a038a; (void)x300a038a; + gdcm::TagToType<0x300a,0x0390> x300a0390; (void)x300a0390; + gdcm::TagToType<0x300a,0x0392> x300a0392; (void)x300a0392; + gdcm::TagToType<0x300a,0x0394> x300a0394; (void)x300a0394; + gdcm::TagToType<0x300a,0x0396> x300a0396; (void)x300a0396; + gdcm::TagToType<0x300a,0x0398> x300a0398; (void)x300a0398; + gdcm::TagToType<0x300a,0x039a> x300a039a; (void)x300a039a; + gdcm::TagToType<0x300a,0x03a0> x300a03a0; (void)x300a03a0; + gdcm::TagToType<0x300a,0x03a2> x300a03a2; (void)x300a03a2; + gdcm::TagToType<0x300a,0x03a4> x300a03a4; (void)x300a03a4; + gdcm::TagToType<0x300a,0x03a6> x300a03a6; (void)x300a03a6; + gdcm::TagToType<0x300a,0x03a8> x300a03a8; (void)x300a03a8; + gdcm::TagToType<0x300a,0x03aa> x300a03aa; (void)x300a03aa; + gdcm::TagToType<0x300a,0x03ac> x300a03ac; (void)x300a03ac; + gdcm::TagToType<0x300a,0x0401> x300a0401; (void)x300a0401; + gdcm::TagToType<0x300a,0x0402> x300a0402; (void)x300a0402; + gdcm::TagToType<0x300a,0x0410> x300a0410; (void)x300a0410; + gdcm::TagToType<0x300a,0x0412> x300a0412; (void)x300a0412; + gdcm::TagToType<0x300a,0x0420> x300a0420; (void)x300a0420; + gdcm::TagToType<0x300a,0x0421> x300a0421; (void)x300a0421; + gdcm::TagToType<0x300a,0x0422> x300a0422; (void)x300a0422; + gdcm::TagToType<0x300a,0x0423> x300a0423; (void)x300a0423; + gdcm::TagToType<0x300a,0x0424> x300a0424; (void)x300a0424; + gdcm::TagToType<0x300c,0x0002> x300c0002; (void)x300c0002; + gdcm::TagToType<0x300c,0x0004> x300c0004; (void)x300c0004; + gdcm::TagToType<0x300c,0x0006> x300c0006; (void)x300c0006; + gdcm::TagToType<0x300c,0x0007> x300c0007; (void)x300c0007; + gdcm::TagToType<0x300c,0x0008> x300c0008; (void)x300c0008; + gdcm::TagToType<0x300c,0x0009> x300c0009; (void)x300c0009; + gdcm::TagToType<0x300c,0x000a> x300c000a; (void)x300c000a; + gdcm::TagToType<0x300c,0x000c> x300c000c; (void)x300c000c; + gdcm::TagToType<0x300c,0x000e> x300c000e; (void)x300c000e; + gdcm::TagToType<0x300c,0x0020> x300c0020; (void)x300c0020; + gdcm::TagToType<0x300c,0x0022> x300c0022; (void)x300c0022; + gdcm::TagToType<0x300c,0x0040> x300c0040; (void)x300c0040; + gdcm::TagToType<0x300c,0x0042> x300c0042; (void)x300c0042; + gdcm::TagToType<0x300c,0x0050> x300c0050; (void)x300c0050; + gdcm::TagToType<0x300c,0x0051> x300c0051; (void)x300c0051; + gdcm::TagToType<0x300c,0x0055> x300c0055; (void)x300c0055; + gdcm::TagToType<0x300c,0x0060> x300c0060; (void)x300c0060; + gdcm::TagToType<0x300c,0x006a> x300c006a; (void)x300c006a; + gdcm::TagToType<0x300c,0x0080> x300c0080; (void)x300c0080; + gdcm::TagToType<0x300c,0x00a0> x300c00a0; (void)x300c00a0; + gdcm::TagToType<0x300c,0x00b0> x300c00b0; (void)x300c00b0; + gdcm::TagToType<0x300c,0x00c0> x300c00c0; (void)x300c00c0; + gdcm::TagToType<0x300c,0x00d0> x300c00d0; (void)x300c00d0; + gdcm::TagToType<0x300c,0x00e0> x300c00e0; (void)x300c00e0; + gdcm::TagToType<0x300c,0x00f0> x300c00f0; (void)x300c00f0; + gdcm::TagToType<0x300c,0x00f2> x300c00f2; (void)x300c00f2; + gdcm::TagToType<0x300c,0x00f4> x300c00f4; (void)x300c00f4; + gdcm::TagToType<0x300c,0x00f6> x300c00f6; (void)x300c00f6; + gdcm::TagToType<0x300c,0x0100> x300c0100; (void)x300c0100; + gdcm::TagToType<0x300c,0x0102> x300c0102; (void)x300c0102; + gdcm::TagToType<0x300c,0x0104> x300c0104; (void)x300c0104; + gdcm::TagToType<0x300e,0x0002> x300e0002; (void)x300e0002; + gdcm::TagToType<0x300e,0x0004> x300e0004; (void)x300e0004; + gdcm::TagToType<0x300e,0x0005> x300e0005; (void)x300e0005; + gdcm::TagToType<0x300e,0x0008> x300e0008; (void)x300e0008; + gdcm::TagToType<0x4000,0x0010> x40000010; (void)x40000010; + gdcm::TagToType<0x4000,0x4000> x40004000; (void)x40004000; + gdcm::TagToType<0x4008,0x0040> x40080040; (void)x40080040; + gdcm::TagToType<0x4008,0x0042> x40080042; (void)x40080042; + gdcm::TagToType<0x4008,0x0050> x40080050; (void)x40080050; + gdcm::TagToType<0x4008,0x0100> x40080100; (void)x40080100; + gdcm::TagToType<0x4008,0x0101> x40080101; (void)x40080101; + gdcm::TagToType<0x4008,0x0102> x40080102; (void)x40080102; + gdcm::TagToType<0x4008,0x0103> x40080103; (void)x40080103; + gdcm::TagToType<0x4008,0x0108> x40080108; (void)x40080108; + gdcm::TagToType<0x4008,0x0109> x40080109; (void)x40080109; + gdcm::TagToType<0x4008,0x010a> x4008010a; (void)x4008010a; + gdcm::TagToType<0x4008,0x010b> x4008010b; (void)x4008010b; + gdcm::TagToType<0x4008,0x010c> x4008010c; (void)x4008010c; + gdcm::TagToType<0x4008,0x0111> x40080111; (void)x40080111; + gdcm::TagToType<0x4008,0x0112> x40080112; (void)x40080112; + gdcm::TagToType<0x4008,0x0113> x40080113; (void)x40080113; + gdcm::TagToType<0x4008,0x0114> x40080114; (void)x40080114; + gdcm::TagToType<0x4008,0x0115> x40080115; (void)x40080115; + gdcm::TagToType<0x4008,0x0117> x40080117; (void)x40080117; + gdcm::TagToType<0x4008,0x0118> x40080118; (void)x40080118; + gdcm::TagToType<0x4008,0x0119> x40080119; (void)x40080119; + gdcm::TagToType<0x4008,0x011a> x4008011a; (void)x4008011a; + gdcm::TagToType<0x4008,0x0200> x40080200; (void)x40080200; + gdcm::TagToType<0x4008,0x0202> x40080202; (void)x40080202; + gdcm::TagToType<0x4008,0x0210> x40080210; (void)x40080210; + gdcm::TagToType<0x4008,0x0212> x40080212; (void)x40080212; + gdcm::TagToType<0x4008,0x0300> x40080300; (void)x40080300; + gdcm::TagToType<0x4008,0x4000> x40084000; (void)x40084000; + gdcm::TagToType<0x4ffe,0x0001> x4ffe0001; (void)x4ffe0001; + gdcm::TagToType<0x5000,0x0005> x50000005; (void)x50000005; + gdcm::TagToType<0x5000,0x0010> x50000010; (void)x50000010; + gdcm::TagToType<0x5000,0x0020> x50000020; (void)x50000020; + gdcm::TagToType<0x5000,0x0022> x50000022; (void)x50000022; + gdcm::TagToType<0x5000,0x0030> x50000030; (void)x50000030; + gdcm::TagToType<0x5000,0x0040> x50000040; (void)x50000040; + gdcm::TagToType<0x5000,0x0103> x50000103; (void)x50000103; + gdcm::TagToType<0x5000,0x0104> x50000104; (void)x50000104; + gdcm::TagToType<0x5000,0x0105> x50000105; (void)x50000105; + gdcm::TagToType<0x5000,0x0106> x50000106; (void)x50000106; + gdcm::TagToType<0x5000,0x0110> x50000110; (void)x50000110; + gdcm::TagToType<0x5000,0x0112> x50000112; (void)x50000112; + gdcm::TagToType<0x5000,0x0114> x50000114; (void)x50000114; + gdcm::TagToType<0x5000,0x1001> x50001001; (void)x50001001; + gdcm::TagToType<0x5000,0x2000> x50002000; (void)x50002000; + gdcm::TagToType<0x5000,0x2002> x50002002; (void)x50002002; + gdcm::TagToType<0x5000,0x2004> x50002004; (void)x50002004; + gdcm::TagToType<0x5000,0x2006> x50002006; (void)x50002006; + gdcm::TagToType<0x5000,0x2008> x50002008; (void)x50002008; + gdcm::TagToType<0x5000,0x200a> x5000200a; (void)x5000200a; + gdcm::TagToType<0x5000,0x200e> x5000200e; (void)x5000200e; + gdcm::TagToType<0x5000,0x2500> x50002500; (void)x50002500; + gdcm::TagToType<0x5000,0x2600> x50002600; (void)x50002600; + gdcm::TagToType<0x5000,0x2610> x50002610; (void)x50002610; + gdcm::TagToType<0x5200,0x9229> x52009229; (void)x52009229; + gdcm::TagToType<0x5200,0x9230> x52009230; (void)x52009230; + gdcm::TagToType<0x5400,0x0100> x54000100; (void)x54000100; + gdcm::TagToType<0x5400,0x1004> x54001004; (void)x54001004; + gdcm::TagToType<0x5400,0x1006> x54001006; (void)x54001006; + gdcm::TagToType<0x5600,0x0010> x56000010; (void)x56000010; + gdcm::TagToType<0x5600,0x0020> x56000020; (void)x56000020; + gdcm::TagToType<0x6000,0x0010> x60000010; (void)x60000010; + gdcm::TagToType<0x6000,0x0011> x60000011; (void)x60000011; + gdcm::TagToType<0x6000,0x0012> x60000012; (void)x60000012; + gdcm::TagToType<0x6000,0x0015> x60000015; (void)x60000015; + gdcm::TagToType<0x6000,0x0022> x60000022; (void)x60000022; + gdcm::TagToType<0x6000,0x0040> x60000040; (void)x60000040; + gdcm::TagToType<0x6000,0x0045> x60000045; (void)x60000045; + gdcm::TagToType<0x6000,0x0050> x60000050; (void)x60000050; + gdcm::TagToType<0x6000,0x0051> x60000051; (void)x60000051; + gdcm::TagToType<0x6000,0x0052> x60000052; (void)x60000052; + gdcm::TagToType<0x6000,0x0060> x60000060; (void)x60000060; + gdcm::TagToType<0x6000,0x0061> x60000061; (void)x60000061; + gdcm::TagToType<0x6000,0x0062> x60000062; (void)x60000062; + gdcm::TagToType<0x6000,0x0063> x60000063; (void)x60000063; + gdcm::TagToType<0x6000,0x0066> x60000066; (void)x60000066; + gdcm::TagToType<0x6000,0x0068> x60000068; (void)x60000068; + gdcm::TagToType<0x6000,0x0069> x60000069; (void)x60000069; + gdcm::TagToType<0x6000,0x0100> x60000100; (void)x60000100; + gdcm::TagToType<0x6000,0x0102> x60000102; (void)x60000102; + gdcm::TagToType<0x6000,0x0110> x60000110; (void)x60000110; + gdcm::TagToType<0x6000,0x0200> x60000200; (void)x60000200; + gdcm::TagToType<0x6000,0x0800> x60000800; (void)x60000800; + gdcm::TagToType<0x6000,0x0802> x60000802; (void)x60000802; + gdcm::TagToType<0x6000,0x0803> x60000803; (void)x60000803; + gdcm::TagToType<0x6000,0x0804> x60000804; (void)x60000804; + gdcm::TagToType<0x6000,0x1001> x60001001; (void)x60001001; + gdcm::TagToType<0x6000,0x1100> x60001100; (void)x60001100; + gdcm::TagToType<0x6000,0x1101> x60001101; (void)x60001101; + gdcm::TagToType<0x6000,0x1102> x60001102; (void)x60001102; + gdcm::TagToType<0x6000,0x1103> x60001103; (void)x60001103; + gdcm::TagToType<0x6000,0x1200> x60001200; (void)x60001200; + gdcm::TagToType<0x6000,0x1201> x60001201; (void)x60001201; + gdcm::TagToType<0x6000,0x1202> x60001202; (void)x60001202; + gdcm::TagToType<0x6000,0x1203> x60001203; (void)x60001203; + gdcm::TagToType<0x6000,0x1301> x60001301; (void)x60001301; + gdcm::TagToType<0x6000,0x1302> x60001302; (void)x60001302; + gdcm::TagToType<0x6000,0x1303> x60001303; (void)x60001303; + gdcm::TagToType<0x6000,0x1500> x60001500; (void)x60001500; + gdcm::TagToType<0x6000,0x4000> x60004000; (void)x60004000; + gdcm::TagToType<0x7fe0,0x0020> x7fe00020; (void)x7fe00020; + gdcm::TagToType<0x7fe0,0x0030> x7fe00030; (void)x7fe00030; + gdcm::TagToType<0x7fe0,0x0040> x7fe00040; (void)x7fe00040; + gdcm::TagToType<0x7f00,0x0011> x7f000011; (void)x7f000011; + gdcm::TagToType<0x7f00,0x0020> x7f000020; (void)x7f000020; + gdcm::TagToType<0x7f00,0x0030> x7f000030; (void)x7f000030; + gdcm::TagToType<0x7f00,0x0040> x7f000040; (void)x7f000040; + gdcm::TagToType<0xfffa,0xfffa> xfffafffa; (void)xfffafffa; + gdcm::TagToType<0xfffc,0xfffc> xfffcfffc; (void)xfffcfffc; + + return 0; +} diff --git a/gdcm/Testing/Source/DataDictionary/Cxx/TestTagToType.xsl b/gdcm/Testing/Source/DataDictionary/Cxx/TestTagToType.xsl new file mode 100644 index 0000000..38a40f6 --- /dev/null +++ b/gdcm/Testing/Source/DataDictionary/Cxx/TestTagToType.xsl @@ -0,0 +1,64 @@ + + + + + + + + +// GENERATED FILE DO NOT EDIT +// $ xsltproc TestTagToType.xsl DICOMV3.xml > TestTagToType.cxx + +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#include "gdcmTagToType.h" + +int TestTagToType(int, char *[]) +{ + + + + + + gdcm::TagToType<0x + + ,0x + + > + + ; (void) + + ; + + + + + return 0; +} + + + diff --git a/gdcm/Testing/Source/DataDictionary/Cxx/TestUIDs.cxx b/gdcm/Testing/Source/DataDictionary/Cxx/TestUIDs.cxx new file mode 100644 index 0000000..e607d3b --- /dev/null +++ b/gdcm/Testing/Source/DataDictionary/Cxx/TestUIDs.cxx @@ -0,0 +1,495 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmUIDs.h" +#include "gdcmTesting.h" + +#include + +#include // strcmp +#include // strcmp + + +// This list was retrieved from: +// http://cardiacatlas.wiki.sourceforge.net/DICOM+Service+Class+Definitions +// Hum...there is not a single difference, exact same number of white space... +// apparently last modifier is 'solidether' +// http://cardiacatlas.wiki.sourceforge.net/page/diff/DICOM+Service+Class+Definitions?v1=209104&v2=209124 +// could this be that they copy/paste stuff from gdcm itself ? +// how else could you explain the: +// { "1.2.840.113543.6.6.1.3.10002","Unregistred (?) Philips3D" }, + + +static const char * const sopclassuids[][2] = { +{ "1.2.840.10008.1.1","Verification SOP Class" }, +{ "1.2.840.10008.1.2","Implicit VR Little Endian: Default Transfer Syntax for DICOM" }, +{ "1.2.840.10008.1.2.1","Explicit VR Little Endian" }, +{ "1.2.840.10008.1.2.1.99","Deflated Explicit VR Little Endian" }, +{ "1.2.840.10008.1.2.2","Explicit VR Big Endian" }, +{ "1.2.840.10008.1.2.4.50","JPEG Baseline (Process 1): Default Transfer Syntax for Lossy JPEG 8 Bit Image Compression" }, +{ "1.2.840.10008.1.2.4.51","JPEG Extended (Process 2 & 4): Default Transfer Syntax for Lossy JPEG 12 Bit Image Compression (Process 4 only)" }, +{ "1.2.840.10008.1.2.4.52","JPEG Extended (Process 3 & 5)" }, +{ "1.2.840.10008.1.2.4.53","JPEG Spectral Selection, Non-Hierarchical (Process 6 & 8)" }, +{ "1.2.840.10008.1.2.4.54","JPEG Spectral Selection, Non-Hierarchical (Process 7 & 9)" }, +{ "1.2.840.10008.1.2.4.55","JPEG Full Progression, Non-Hierarchical (Process 10 & 12)" }, +{ "1.2.840.10008.1.2.4.56","JPEG Full Progression, Non-Hierarchical (Process 11 & 13)" }, +{ "1.2.840.10008.1.2.4.57","JPEG Lossless, Non-Hierarchical (Process 14)" }, +{ "1.2.840.10008.1.2.4.58","JPEG Lossless, Non-Hierarchical (Process 15)" }, +{ "1.2.840.10008.1.2.4.59","JPEG Extended, Hierarchical (Process 16 & 18)" }, +{ "1.2.840.10008.1.2.4.60","JPEG Extended, Hierarchical (Process 17 & 19)" }, +{ "1.2.840.10008.1.2.4.61","JPEG Spectral Selection, Hierarchical (Process 20 & 22)" }, +{ "1.2.840.10008.1.2.4.62","JPEG Spectral Selection, Hierarchical (Process 21 & 23)" }, +{ "1.2.840.10008.1.2.4.63","JPEG Full Progression, Hierarchical (Process 24 & 26)" }, +{ "1.2.840.10008.1.2.4.64","JPEG Full Progression, Hierarchical (Process 25 & 27)" }, +{ "1.2.840.10008.1.2.4.65","JPEG Lossless, Hierarchical (Process 28)" }, +{ "1.2.840.10008.1.2.4.66","JPEG Lossless, Hierarchical (Process 29)" }, +{ "1.2.840.10008.1.2.4.70","JPEG Lossless, Non-Hierarchical, First-Order Prediction (Process 14 [Selection Value 1]): Default Transfer Syntax for Lossless JPEG Image Compression" }, +{ "1.2.840.10008.1.2.4.80","JPEG-LS Lossless Image Compression" }, +{ "1.2.840.10008.1.2.4.81","JPEG-LS Lossy (Near-Lossless) Image Compression" }, +{ "1.2.840.10008.1.2.4.90","JPEG 2000 Image Compression (Lossless Only)" }, +{ "1.2.840.10008.1.2.4.91","JPEG 2000 Image Compression" }, +{ "1.2.840.10008.1.2.4.92","JPEG 2000 Part 2 Multi-component Image Compression (Lossless Only)" }, +{ "1.2.840.10008.1.2.4.93","JPEG 2000 Part 2 Multi-component Image Compression" }, +{ "1.2.840.10008.1.2.4.94","JPIP Referenced" }, +{ "1.2.840.10008.1.2.4.95","JPIP Referenced Deflate" }, +{ "1.2.840.10008.1.2.4.100","MPEG2 Main Profile @ Main Level" }, +{ "1.2.840.10008.1.2.5","RLE Lossless" }, +{ "1.2.840.10008.1.2.6.1","RFC 2557 MIME encapsulation" }, +{ "1.2.840.10008.1.2.6.2","XML Encoding" }, +{ "1.2.840.10008.1.3.10","Media Storage Directory Storage" }, +{ "1.2.840.10008.1.4.1.1","Talairach Brain Atlas Frame of Reference" }, +{ "1.2.840.10008.1.4.1.2","SPM2 T1 Frame of Reference" }, +{ "1.2.840.10008.1.4.1.3","SPM2 T2 Frame of Reference" }, +{ "1.2.840.10008.1.4.1.4","SPM2 PD Frame of Reference" }, +{ "1.2.840.10008.1.4.1.5","SPM2 EPI Frame of Reference" }, +{ "1.2.840.10008.1.4.1.6","SPM2 FIL T1 Frame of Reference" }, +{ "1.2.840.10008.1.4.1.7","SPM2 PET Frame of Reference" }, +{ "1.2.840.10008.1.4.1.8","SPM2 TRANSM Frame of Reference" }, +{ "1.2.840.10008.1.4.1.9","SPM2 SPECT Frame of Reference" }, +{ "1.2.840.10008.1.4.1.10","SPM2 GRAY Frame of Reference" }, +{ "1.2.840.10008.1.4.1.11","SPM2 WHITE Frame of Reference" }, +{ "1.2.840.10008.1.4.1.12","SPM2 CSF Frame of Reference" }, +{ "1.2.840.10008.1.4.1.13","SPM2 BRAINMASK Frame of Reference" }, +{ "1.2.840.10008.1.4.1.14","SPM2 AVG305T1 Frame of Reference" }, +{ "1.2.840.10008.1.4.1.15","SPM2 AVG152T1 Frame of Reference" }, +{ "1.2.840.10008.1.4.1.16","SPM2 AVG152T2 Frame of Reference" }, +{ "1.2.840.10008.1.4.1.17","SPM2 AVG152PD Frame of Reference" }, +{ "1.2.840.10008.1.4.1.18","SPM2 SINGLESUBJT1 Frame of Reference" }, +{ "1.2.840.10008.1.4.2.1","ICBM 452 T1 Frame of Reference" }, +{ "1.2.840.10008.1.4.2.2","ICBM Single Subject MRI Frame of Reference" }, +{ "1.2.840.10008.1.9","Basic Study Content Notification SOP Class" }, +{ "1.2.840.10008.1.20.1","Storage Commitment Push Model SOP Class" }, +{ "1.2.840.10008.1.20.1.1","Storage Commitment Push Model SOP Instance" }, +{ "1.2.840.10008.1.20.2","Storage Commitment Pull Model SOP Class" }, +{ "1.2.840.10008.1.20.2.1","Storage Commitment Pull Model SOP Instance" }, +{ "1.2.840.10008.1.40","Procedural Event Logging SOP Class" }, +{ "1.2.840.10008.1.40.1","Procedural Event Logging SOP Instance" }, +{ "1.2.840.10008.1.42","Substance Administration Logging SOP Class" }, +{ "1.2.840.10008.1.42.1","Substance Administration Logging SOP Instance" }, +{ "1.2.840.10008.2.6.1","DICOM UID Registry" }, +{ "1.2.840.10008.2.16.4","DICOM Controlled Terminology" }, +{ "1.2.840.10008.3.1.1.1","DICOM Application Context Name" }, +{ "1.2.840.10008.3.1.2.1.1","Detached Patient Management SOP Class" }, +{ "1.2.840.10008.3.1.2.1.4","Detached Patient Management Meta SOP Class" }, +{ "1.2.840.10008.3.1.2.2.1","Detached Visit Management SOP Class" }, +{ "1.2.840.10008.3.1.2.3.1","Detached Study Management SOP Class" }, +{ "1.2.840.10008.3.1.2.3.2","Study Component Management SOP Class" }, +{ "1.2.840.10008.3.1.2.3.3","Modality Performed Procedure Step SOP Class" }, +{ "1.2.840.10008.3.1.2.3.4","Modality Performed Procedure Step Retrieve SOP Class" }, +{ "1.2.840.10008.3.1.2.3.5","Modality Performed Procedure Step Notification SOP Class" }, +{ "1.2.840.10008.3.1.2.5.1","Detached Results Management SOP Class" }, +{ "1.2.840.10008.3.1.2.5.4","Detached Results Management Meta SOP Class" }, +{ "1.2.840.10008.3.1.2.5.5","Detached Study Management Meta SOP Class" }, +{ "1.2.840.10008.3.1.2.6.1","Detached Interpretation Management SOP Class" }, +{ "1.2.840.10008.4.2","Storage Service Class" }, +{ "1.2.840.10008.5.1.1.1","Basic Film Session SOP Class" }, +{ "1.2.840.10008.5.1.1.2","Basic Film Box SOP Class" }, +{ "1.2.840.10008.5.1.1.4","Basic Grayscale Image Box SOP Class" }, +{ "1.2.840.10008.5.1.1.4.1","Basic Color Image Box SOP Class" }, +{ "1.2.840.10008.5.1.1.4.2","Referenced Image Box SOP Class" }, +{ "1.2.840.10008.5.1.1.9","Basic Grayscale Print Management Meta SOP Class" }, +{ "1.2.840.10008.5.1.1.9.1","Referenced Grayscale Print Management Meta SOP Class" }, +{ "1.2.840.10008.5.1.1.14","Print Job SOP Class" }, +{ "1.2.840.10008.5.1.1.15","Basic Annotation Box SOP Class" }, +{ "1.2.840.10008.5.1.1.16","Printer SOP Class" }, +{ "1.2.840.10008.5.1.1.16.376","Printer Configuration Retrieval SOP Class" }, +{ "1.2.840.10008.5.1.1.17","Printer SOP Instance" }, +{ "1.2.840.10008.5.1.1.17.376","Printer Configuration Retrieval SOP Instance" }, +{ "1.2.840.10008.5.1.1.18","Basic Color Print Management Meta SOP Class" }, +{ "1.2.840.10008.5.1.1.18.1","Referenced Color Print Management Meta SOP Class" }, +{ "1.2.840.10008.5.1.1.22","VOI LUT Box SOP Class" }, +{ "1.2.840.10008.5.1.1.23","Presentation LUT SOP Class" }, +{ "1.2.840.10008.5.1.1.24","Image Overlay Box SOP Class" }, +{ "1.2.840.10008.5.1.1.24.1","Basic Print Image Overlay Box SOP Class" }, +{ "1.2.840.10008.5.1.1.25","Print Queue SOP Instance" }, +{ "1.2.840.10008.5.1.1.26","Print Queue Management SOP Class" }, +{ "1.2.840.10008.5.1.1.27","Stored Print Storage SOP Class" }, +{ "1.2.840.10008.5.1.1.29","Hardcopy Grayscale Image Storage SOP Class" }, +{ "1.2.840.10008.5.1.1.30","Hardcopy Color Image Storage SOP Class" }, +{ "1.2.840.10008.5.1.1.31","Pull Print Request SOP Class" }, +{ "1.2.840.10008.5.1.1.32","Pull Stored Print Management Meta SOP Class" }, +{ "1.2.840.10008.5.1.1.33","Media Creation Management SOP Class UID" }, +{ "1.2.840.10008.5.1.4.1.1.1","Computed Radiography Image Storage" }, +{ "1.2.840.10008.5.1.4.1.1.1.1","Digital X-Ray Image Storage - For Presentation" }, +{ "1.2.840.10008.5.1.4.1.1.1.1.1","Digital X-Ray Image Storage - For Processing" }, +{ "1.2.840.10008.5.1.4.1.1.1.2","Digital Mammography X-Ray Image Storage - For Presentation" }, +{ "1.2.840.10008.5.1.4.1.1.1.2.1","Digital Mammography X-Ray Image Storage - For Processing" }, +{ "1.2.840.10008.5.1.4.1.1.1.3","Digital Intra-oral X-Ray Image Storage - For Presentation" }, +{ "1.2.840.10008.5.1.4.1.1.1.3.1","Digital Intra-oral X-Ray Image Storage - For Processing" }, +{ "1.2.840.10008.5.1.4.1.1.2","CT Image Storage" }, +{ "1.2.840.10008.5.1.4.1.1.2.1","Enhanced CT Image Storage" }, +{ "1.2.840.10008.5.1.4.1.1.3","Ultrasound Multi-frame Image Storage" }, +{ "1.2.840.10008.5.1.4.1.1.3.1","Ultrasound Multi-frame Image Storage" }, +{ "1.2.840.10008.5.1.4.1.1.4","MR Image Storage" }, +{ "1.2.840.10008.5.1.4.1.1.4.1","Enhanced MR Image Storage" }, +{ "1.2.840.10008.5.1.4.1.1.4.2","MR Spectroscopy Storage" }, +{ "1.2.840.10008.5.1.4.1.1.5","Nuclear Medicine Image Storage" }, +{ "1.2.840.10008.5.1.4.1.1.6","Ultrasound Image Storage" }, +{ "1.2.840.10008.5.1.4.1.1.6.1","Ultrasound Image Storage" }, +{ "1.2.840.10008.5.1.4.1.1.7","Secondary Capture Image Storage" }, +{ "1.2.840.10008.5.1.4.1.1.7.1","Multi-frame Single Bit Secondary Capture Image Storage" }, +{ "1.2.840.10008.5.1.4.1.1.7.2","Multi-frame Grayscale Byte Secondary Capture Image Storage" }, +{ "1.2.840.10008.5.1.4.1.1.7.3","Multi-frame Grayscale Word Secondary Capture Image Storage" }, +{ "1.2.840.10008.5.1.4.1.1.7.4","Multi-frame True Color Secondary Capture Image Storage" }, +{ "1.2.840.10008.5.1.4.1.1.8","Standalone Overlay Storage" }, +{ "1.2.840.10008.5.1.4.1.1.9","Standalone Curve Storage" }, +{ "1.2.840.10008.5.1.4.1.1.9.1","Waveform Storage - Trial" }, +{ "1.2.840.10008.5.1.4.1.1.9.1.1","12-lead ECG Waveform Storage" }, +{ "1.2.840.10008.5.1.4.1.1.9.1.2","General ECG Waveform Storage" }, +{ "1.2.840.10008.5.1.4.1.1.9.1.3","Ambulatory ECG Waveform Storage" }, +{ "1.2.840.10008.5.1.4.1.1.9.2.1","Hemodynamic Waveform Storage" }, +{ "1.2.840.10008.5.1.4.1.1.9.3.1","Cardiac Electrophysiology Waveform Storage" }, +{ "1.2.840.10008.5.1.4.1.1.9.4.1","Basic Voice Audio Waveform Storage" }, +{ "1.2.840.10008.5.1.4.1.1.10","Standalone Modality LUT Storage" }, +{ "1.2.840.10008.5.1.4.1.1.11","Standalone VOI LUT Storage" }, +{ "1.2.840.10008.5.1.4.1.1.11.1","Grayscale Softcopy Presentation State Storage SOP Class" }, +{ "1.2.840.10008.5.1.4.1.1.11.2","Color Softcopy Presentation State Storage SOP Class" }, +{ "1.2.840.10008.5.1.4.1.1.11.3","Pseudo-Color Softcopy Presentation State Storage SOP Class" }, +{ "1.2.840.10008.5.1.4.1.1.11.4","Blending Softcopy Presentation State Storage SOP Class" }, +{ "1.2.840.10008.5.1.4.1.1.12.1","X-Ray Angiographic Image Storage" }, +{ "1.2.840.10008.5.1.4.1.1.12.1.1","Enhanced XA Image Storage" }, +{ "1.2.840.10008.5.1.4.1.1.12.2","X-Ray Radiofluoroscopic Image Storage" }, +{ "1.2.840.10008.5.1.4.1.1.12.2.1","Enhanced XRF Image Storage" }, +{ "1.2.840.10008.5.1.4.1.1.13.1.1","X-Ray 3D Angiographic Image Storage" }, +{ "1.2.840.10008.5.1.4.1.1.13.1.2","X-Ray 3D Craniofacial Image Storage" }, +{ "1.2.840.10008.5.1.4.1.1.12.3","X-Ray Angiographic Bi-Plane Image Storage" }, +{ "1.2.840.10008.5.1.4.1.1.20","Nuclear Medicine Image Storage" }, +{ "1.2.840.10008.5.1.4.1.1.66","Raw Data Storage" }, +{ "1.2.840.10008.5.1.4.1.1.66.1","Spatial Registration Storage" }, +{ "1.2.840.10008.5.1.4.1.1.66.2","Spatial Fiducials Storage" }, +{ "1.2.840.10008.5.1.4.1.1.66.3","Deformable Spatial Registration Storage" }, +{ "1.2.840.10008.5.1.4.1.1.66.4","Segmentation Storage" }, +{ "1.2.840.10008.5.1.4.1.1.67","Real World Value Mapping Storage" }, +{ "1.2.840.10008.5.1.4.1.1.77.1","VL Image Storage - Trial" }, +{ "1.2.840.10008.5.1.4.1.1.77.2","VL Multi-frame Image Storage - Trial" }, +{ "1.2.840.10008.5.1.4.1.1.77.1.1","VL Endoscopic Image Storage" }, +{ "1.2.840.10008.5.1.4.1.1.77.1.1.1","Video Endoscopic Image Storage" }, +{ "1.2.840.10008.5.1.4.1.1.77.1.2","VL Microscopic Image Storage" }, +{ "1.2.840.10008.5.1.4.1.1.77.1.2.1","Video Microscopic Image Storage" }, +{ "1.2.840.10008.5.1.4.1.1.77.1.3","VL Slide-Coordinates Microscopic Image Storage" }, +{ "1.2.840.10008.5.1.4.1.1.77.1.4","VL Photographic Image Storage" }, +{ "1.2.840.10008.5.1.4.1.1.77.1.4.1","Video Photographic Image Storage" }, +{ "1.2.840.10008.5.1.4.1.1.77.1.5.1","Ophthalmic Photography 8 Bit Image Storage" }, +{ "1.2.840.10008.5.1.4.1.1.77.1.5.2","Ophthalmic Photography 16 Bit Image Storage" }, +{ "1.2.840.10008.5.1.4.1.1.77.1.5.3","Stereometric Relationship Storage" }, +{ "1.2.840.10008.5.1.4.1.1.77.1.5.4","Ophthalmic Tomography Image Storage" }, +{ "1.2.840.10008.5.1.4.1.1.88.1","Text SR Storage - Trial" }, +{ "1.2.840.10008.5.1.4.1.1.88.2","Audio SR Storage - Trial" }, +{ "1.2.840.10008.5.1.4.1.1.88.3","Detail SR Storage - Trial" }, +{ "1.2.840.10008.5.1.4.1.1.88.4","Comprehensive SR Storage - Trial" }, +{ "1.2.840.10008.5.1.4.1.1.88.11","Basic Text SR Storage" }, +{ "1.2.840.10008.5.1.4.1.1.88.22","Enhanced SR Storage" }, +{ "1.2.840.10008.5.1.4.1.1.88.33","Comprehensive SR Storage" }, +{ "1.2.840.10008.5.1.4.1.1.88.40","Procedure Log Storage" }, +{ "1.2.840.10008.5.1.4.1.1.88.50","Mammography CAD SR Storage" }, +{ "1.2.840.10008.5.1.4.1.1.88.59","Key Object Selection Document Storage" }, +{ "1.2.840.10008.5.1.4.1.1.88.65","Chest CAD SR Storage" }, +{ "1.2.840.10008.5.1.4.1.1.88.67","X-Ray Radiation Dose SR Storage" }, +{ "1.2.840.10008.5.1.4.1.1.104.1","Encapsulated PDF Storage" }, +{ "1.2.840.10008.5.1.4.1.1.104.2","Encapsulated CDA Storage" }, +{ "1.2.840.10008.5.1.4.1.1.128","Positron Emission Tomography Image Storage" }, +{ "1.2.840.10008.5.1.4.1.1.129","Standalone PET Curve Storage" }, +{ "1.2.840.10008.5.1.4.1.1.481.1","RT Image Storage" }, +{ "1.2.840.10008.5.1.4.1.1.481.2","RT Dose Storage" }, +{ "1.2.840.10008.5.1.4.1.1.481.3","RT Structure Set Storage" }, +{ "1.2.840.10008.5.1.4.1.1.481.4","RT Beams Treatment Record Storage" }, +{ "1.2.840.10008.5.1.4.1.1.481.5","RT Plan Storage" }, +{ "1.2.840.10008.5.1.4.1.1.481.6","RT Brachy Treatment Record Storage" }, +{ "1.2.840.10008.5.1.4.1.1.481.7","RT Treatment Summary Record Storage" }, +{ "1.2.840.10008.5.1.4.1.1.481.8","RT Ion Plan Storage" }, +{ "1.2.840.10008.5.1.4.1.1.481.9","RT Ion Beams Treatment Record Storage" }, +{ "1.2.840.10008.5.1.4.1.2.1.1","Patient Root Query/Retrieve Information Model - FIND" }, +{ "1.2.840.10008.5.1.4.1.2.1.2","Patient Root Query/Retrieve Information Model - MOVE" }, +{ "1.2.840.10008.5.1.4.1.2.1.3","Patient Root Query/Retrieve Information Model - GET" }, +{ "1.2.840.10008.5.1.4.1.2.2.1","Study Root Query/Retrieve Information Model - FIND" }, +{ "1.2.840.10008.5.1.4.1.2.2.2","Study Root Query/Retrieve Information Model - MOVE" }, +{ "1.2.840.10008.5.1.4.1.2.2.3","Study Root Query/Retrieve Information Model - GET" }, +{ "1.2.840.10008.5.1.4.1.2.3.1","Patient/Study Only Query/Retrieve Information Model - FIND" }, +{ "1.2.840.10008.5.1.4.1.2.3.2","Patient/Study Only Query/Retrieve Information Model - MOVE" }, +{ "1.2.840.10008.5.1.4.1.2.3.3","Patient/Study Only Query/Retrieve Information Model - GET" }, +{ "1.2.840.10008.5.1.4.31","Modality Worklist Information Model - FIND" }, +{ "1.2.840.10008.5.1.4.32.1","General Purpose Worklist Information Model - FIND" }, +{ "1.2.840.10008.5.1.4.32.2","General Purpose Scheduled Procedure Step SOP Class" }, +{ "1.2.840.10008.5.1.4.32.3","General Purpose Performed Procedure Step SOP Class" }, +{ "1.2.840.10008.5.1.4.32","General Purpose Worklist Management Meta SOP Class" }, +{ "1.2.840.10008.5.1.4.33","Instance Availability Notification SOP Class" }, +{ "1.2.840.10008.5.1.4.34.1","RT Beams Delivery Instruction Storage (Supplement 74 Frozen Draft)" }, +{ "1.2.840.10008.5.1.4.34.2","RT Conventional Machine Verification (Supplement 74 Frozen Draft)" }, +{ "1.2.840.10008.5.1.4.34.3","RT Ion Machine Verification (Supplement 74 Frozen Draft)" }, +{ "1.2.840.10008.5.1.4.34.4","Unified Worklist and Procedure Step Service Class" }, +{ "1.2.840.10008.5.1.4.34.4.1","Unified Procedure Step - Push SOP Class" }, +{ "1.2.840.10008.5.1.4.34.4.2","Unified Procedure Step - Watch SOP Class" }, +{ "1.2.840.10008.5.1.4.34.4.3","Unified Procedure Step - Pull SOP Class" }, +{ "1.2.840.10008.5.1.4.34.4.4","Unified Procedure Step - Event SOP Class" }, +{ "1.2.840.10008.5.1.4.34.5","Unified Worklist and Procedure Step SOP Instance" }, +{ "1.2.840.10008.5.1.4.37.1","General Relevant Patient Information Query" }, +{ "1.2.840.10008.5.1.4.37.2","Breast Imaging Relevant Patient Information Query" }, +{ "1.2.840.10008.5.1.4.37.3","Cardiac Relevant Patient Information Query" }, +{ "1.2.840.10008.5.1.4.38.1","Hanging Protocol Storage" }, +{ "1.2.840.10008.5.1.4.38.2","Hanging Protocol Information Model - FIND" }, +{ "1.2.840.10008.5.1.4.38.3","Hanging Protocol Information Model - MOVE" }, +{ "1.2.840.10008.5.1.4.41","Product Characteristics Query SOP Class" }, +{ "1.2.840.10008.5.1.4.42","Substance Approval Query SOP Class" }, +{ "1.2.840.10008.15.0.3.1","dicomDeviceName" }, +{ "1.2.840.10008.15.0.3.2","dicomDescription" }, +{ "1.2.840.10008.15.0.3.3","dicomManufacturer" }, +{ "1.2.840.10008.15.0.3.4","dicomManufacturerModelName" }, +{ "1.2.840.10008.15.0.3.5","dicomSoftwareVersion" }, +{ "1.2.840.10008.15.0.3.6","dicomVendorData" }, +{ "1.2.840.10008.15.0.3.7","dicomAETitle" }, +{ "1.2.840.10008.15.0.3.8","dicomNetworkConnectionReference" }, +{ "1.2.840.10008.15.0.3.9","dicomApplicationCluster" }, +{ "1.2.840.10008.15.0.3.10","dicomAssociationInitiator" }, +{ "1.2.840.10008.15.0.3.11","dicomAssociationAcceptor" }, +{ "1.2.840.10008.15.0.3.12","dicomHostname" }, +{ "1.2.840.10008.15.0.3.13","dicomPort" }, +{ "1.2.840.10008.15.0.3.14","dicomSOPClass" }, +{ "1.2.840.10008.15.0.3.15","dicomTransferRole" }, +{ "1.2.840.10008.15.0.3.16","dicomTransferSyntax" }, +{ "1.2.840.10008.15.0.3.17","dicomPrimaryDeviceType" }, +{ "1.2.840.10008.15.0.3.18","dicomRelatedDeviceReference" }, +{ "1.2.840.10008.15.0.3.19","dicomPreferredCalledAETitle" }, +{ "1.2.840.10008.15.0.3.20","dicomTLSCyphersuite" }, +{ "1.2.840.10008.15.0.3.21","dicomAuthorizedNodeCertificateReference" }, +{ "1.2.840.10008.15.0.3.22","dicomThisNodeCertificateReference" }, +{ "1.2.840.10008.15.0.3.23","dicomInstalled" }, +{ "1.2.840.10008.15.0.3.24","dicomStationName" }, +{ "1.2.840.10008.15.0.3.25","dicomDeviceSerialNumber" }, +{ "1.2.840.10008.15.0.3.26","dicomInstitutionName" }, +{ "1.2.840.10008.15.0.3.27","dicomInstitutionAddress" }, +{ "1.2.840.10008.15.0.3.28","dicomInstitutionDepartmentName" }, +{ "1.2.840.10008.15.0.3.29","dicomIssuerOfPatientID" }, +{ "1.2.840.10008.15.0.3.30","dicomPreferredCallingAETitle" }, +{ "1.2.840.10008.15.0.3.31","dicomSupportedCharacterSet" }, +{ "1.2.840.10008.15.0.4.1","dicomConfigurationRoot" }, +{ "1.2.840.10008.15.0.4.2","dicomDevicesRoot" }, +{ "1.2.840.10008.15.0.4.3","dicomUniqueAETitlesRegistryRoot" }, +{ "1.2.840.10008.15.0.4.4","dicomDevice" }, +{ "1.2.840.10008.15.0.4.5","dicomNetworkAE" }, +{ "1.2.840.10008.15.0.4.6","dicomNetworkConnection" }, +{ "1.2.840.10008.15.0.4.7","dicomUniqueAETitle" }, +{ "1.2.840.10008.15.0.4.8","dicomTransferCapability" }, +{ "1.2.840.113619.4.2","General Electric Magnetic Resonance Image Storage" }, +{ "1.2.840.113619.4.3","General Electric Computed Tomography Image Storage" }, +{ "1.3.12.2.1107.5.9.1","CSA Non-Image Storage" }, +{ "1.2.840.113619.4.26","GE Private 3D Model Storage" }, +{ "1.2.840.113619.4.30","GE Advance (PET) Raw Data Storage" }, +{ "2.16.840.1.113709.1.5.1","GEPACS_PRIVATE_IMS_INFO Storage" }, +{ "1.2.840.113543.6.6.1.3.10002","Unregistred (?) Philips3D" }, +{ "1.2.392.200036.9116.7.8.1.1.1","Toshiba Private Data Storage" }, +{ "1.2.840.113619.4.27","GE Nuclear Medicine private SOP Class" }, +//{ "1.3.46.670589.11.0.0.12.1","Philips Private Gyroscan MR Spectrum" }, +{ "1.3.46.670589.11.0.0.12.1","Philips Private MR Spectrum Storage" }, +//{ "1.3.46.670589.11.0.0.12.2","Philips Private Gyroscan MR Serie Data" }, +{ "1.3.46.670589.11.0.0.12.2","Philips Private MR Series Data Storage" }, +{ "1.3.46.670589.2.3.1.1","Philips Private Specialized XA Image" }, +{ "1.3.46.670589.2.4.1.1","Philips Private CX Image Storage" }, +{ "1.3.46.670589.2.5.1.1","Philips iE33 private 3D Object Storage" }, +{ "1.3.46.670589.5.0.1","Philips Private Volume Storage" }, +{ "1.3.46.670589.5.0.1.1","Philips Private Volume Image Reference" }, +{ "1.3.46.670589.5.0.10","Philips Private MR Synthetic Image Storage" }, +{ "1.3.46.670589.5.0.11","Philips Private MR Cardio Analysis Storage" }, +{ "1.3.46.670589.5.0.11.1","Philips Private MR Cardio Analysis Data" }, +{ "1.3.46.670589.5.0.12","Philips Private CX Synthetic Image Storage" }, +{ "1.3.46.670589.5.0.13","Philips Private Perfusion Image Reference" }, +{ "1.3.46.670589.5.0.14","Philips Private Perfusion Analysis Data" }, +{ "1.3.46.670589.5.0.2","Philips Private 3D Object Storage" }, +{ "1.3.46.670589.5.0.2.1","Philips Private 3D Object 2 Storage" }, +{ "1.3.46.670589.5.0.3","Philips Private Surface Storage" }, +{ "1.3.46.670589.5.0.3.1","Philips Private Surface 2 Storage" }, +{ "1.3.46.670589.5.0.4","Philips Private Composite Object Storage" }, +{ "1.3.46.670589.5.0.7","Philips Private MR Cardio Profile" }, +{ "1.3.46.670589.5.0.8","Philips Private MR Cardio" }, +{ "1.3.46.670589.5.0.9","Philips Private CT Synthetic Image Storage" }, +{ "1.2.752.24.3.7.6","Sectra Compression (Private Syntax)" }, +{ "1.2.752.24.3.7.7","Sectra Compression LS (Private Syntax)" }, +{ "1.2.840.113619.5.2","Implicit VR Big Endian DLX (G.E Private)" }, +{ NULL, NULL} +}; + +// Custom list: +static const char * const sopclassuids2[] = { +"1.2.840.10008.1.3.10", +"1.2.840.10008.5.1.4.1.1.1", +"1.2.840.10008.5.1.4.1.1.1.1", +"1.2.840.10008.5.1.4.1.1.11.1", +"1.2.840.10008.5.1.4.1.1.1.2", +"1.2.840.10008.5.1.4.1.1.12.1", +"1.2.840.10008.5.1.4.1.1.12.2", +"1.2.840.10008.5.1.4.1.1.128", +"1.2.840.10008.5.1.4.1.1.2", +"1.2.840.10008.5.1.4.1.1.20", +"1.2.840.10008.5.1.4.1.1.3.1", +"1.2.840.10008.5.1.4.1.1.4", +"1.2.840.10008.5.1.4.1.1.4.1", +"1.2.840.10008.5.1.4.1.1.481.3", +"1.2.840.10008.5.1.4.1.1.5", +"1.2.840.10008.5.1.4.1.1.6", +"1.2.840.10008.5.1.4.1.1.6.1", +"1.2.840.10008.5.1.4.1.1.66", +"1.2.840.10008.5.1.4.1.1.7", +"1.2.840.10008.5.1.4.1.1.88.11", +"1.2.840.10008.5.1.4.1.1.88.22", +"1.2.840.10008.5.1.4.1.1.88.3", +"1.2.840.10008.5.1.4.1.1.88.59", +"1.2.840.10008.5.1.4.1.1.9", +"1.2.840.10008.5.1.4.1.1.9.4.1", +"1.2.840.10008.5.1.4.38.1", +"1.2.840.113619.4.26", +"1.3.12.2.1107.5.9.1", +"1.3.46.670589.11.0.0.12.2", +"1.3.46.670589.5.0.1", +"1.3.46.670589.5.0.10", +"1.3.46.670589.5.0.1.1", +"1.3.46.670589.5.0.11", +"1.3.46.670589.5.0.13", +"1.3.46.670589.5.0.14", +"1.3.46.670589.5.0.2", +"1.3.46.670589.5.0.2.1", +"1.3.46.670589.5.0.3", +"1.3.46.670589.5.0.8", +//"1.3.6.1.4.1.20468.1.10", // invalid +NULL +}; + +int TestUIDs(int, char *[]) +{ + const char* s0 = gdcm::UIDs::GetUIDString( 0 ); + if(s0) return 1; + + // {"1.2.840.10008.5.1.4.1.1.2.1","Enhanced CT Image Storage"}, + // uid_1_2_840_10008_5_1_4_1_1_2_1 = 117, // Enhanced CT Image Storage + const char* s = gdcm::UIDs::GetUIDString( gdcm::UIDs::uid_1_2_840_10008_5_1_4_1_1_2_1 ); + if(!s) return 1; + std::cout << s << std::endl; + const char* n = gdcm::UIDs::GetUIDName( gdcm::UIDs::uid_1_2_840_10008_5_1_4_1_1_2_1 ); + if(!n) return 1; + std::cout << n << std::endl; + const char* s1 = gdcm::UIDs::GetUIDString( gdcm::UIDs::EnhancedCTImageStorage ); + if(!s1) return 1; + std::cout << s1 << std::endl; + const char* n1 = gdcm::UIDs::GetUIDName( gdcm::UIDs::EnhancedCTImageStorage ); + if(!n1) return 1; + std::cout << n1 << std::endl; + + gdcm::UIDs uid; + // valid: + if( !uid.SetFromUID( "1.2.840.10008.5.1.4.1.1.2.1" ) ) + { + return 1; + } + std::cout << "This is : " << uid.GetName() << std::endl; + std::cout << "This is : " << uid.GetString() << std::endl; + std::cout << uid << std::endl; + // invalid + if( uid.SetFromUID( "prosper youpla boum c'est le roi du pain d'epices" ) ) + { + return 1; + } + if( uid.GetName() ) return 1; + if( uid.SetFromUID( "1.2" ) ) + { + return 1; + } + if( uid.GetName() ) return 1; + if( uid.SetFromUID( "" ) ) + { + return 1; + } + if( uid.GetName() ) return 1; + // black box: + if( uid.SetFromUID( NULL ) ) + { + return 1; + } + if( uid.GetName() ) return 1; + + typedef const char* const (*mytype)[2]; + mytype sopclassuid = sopclassuids; + while( *sopclassuid[0] ) + { + const char *uid_str = (*sopclassuid)[0]; + const char *name_str = (*sopclassuid)[1]; + //std::cout << uid_str << std::endl; + if( !uid.SetFromUID( uid_str ) ) + { + std::cerr << "Invalid UID:" << uid_str << std::endl; + return 1; + } + const char *name = uid.GetName(); + if( !name ) + { + std::cerr << "problem with: " << uid_str << std::endl; + return 1; + } + if( strcmp( name, name_str) != 0 ) + { + std::cerr << "Error: " << name << " vs " << name_str << std::endl; + return 1; + } + + ++sopclassuid; + } + + std::cout << "Custom List:" << std::endl; + const char * const *s2 = sopclassuids2; + while( *s2 ) + { + const char *uid_str = *s2; + if( !uid.SetFromUID( uid_str ) ) + { + std::cerr << "Invalid UID:" << uid_str << std::endl; + return 1; + } + + const char *name = uid.GetName(); + if( !name ) + { + return 1; + } + //std::cout << uid_str << "," << name << std::endl; + s2++; + } + + // Print all + std::cout << "All:" << std::endl; + for(unsigned int i = 0; i < gdcm::UIDs::GetNumberOfTransferSyntaxStrings(); ++i) + { + //const char * const * str_pair = gdcm::UIDs::GetTransferSyntaxString(i); + uid.SetFromUID( gdcm::UIDs::GetUIDString( i+1 ) ); + //std::cout << uid << std::endl; + if( !uid.GetName() || !uid.GetString() ) return 1; + } + + return 0; +} diff --git a/gdcm/Testing/Source/DataDictionary/Python/CMakeLists.txt b/gdcm/Testing/Source/DataDictionary/Python/CMakeLists.txt new file mode 100644 index 0000000..5c3e62c --- /dev/null +++ b/gdcm/Testing/Source/DataDictionary/Python/CMakeLists.txt @@ -0,0 +1,11 @@ +# Define the tests for gdcm-python +# gdcm-python +set(GDCM_PYTHON_TEST_SRCS + TestGlobal + TestDict + ) + +# Loop over files and create executables +foreach(name ${GDCM_PYTHON_TEST_SRCS}) + ADD_PYTHON_TEST(${name}Python ${name}.py) +endforeach() diff --git a/gdcm/Testing/Source/DataDictionary/Python/TestDict.py b/gdcm/Testing/Source/DataDictionary/Python/TestDict.py new file mode 100644 index 0000000..3ad8775 --- /dev/null +++ b/gdcm/Testing/Source/DataDictionary/Python/TestDict.py @@ -0,0 +1,41 @@ +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +import gdcm +import os,sys + +if __name__ == "__main__": + + singleton = gdcm.Global.GetInstance() + dicts = singleton.GetDicts() + d = dicts.GetPublicDict() + t = gdcm.Tag(0x0010,0x0010) + keyword = d.GetKeywordFromTag( t ) + if keyword != 'PatientName': + sys.exit(1) + print(keyword) + + p = d.GetDictEntryByKeyword( keyword ) + if p[0].GetKeyword() != keyword: + sys.exit(1) + print(p[0].GetKeyword()) + + p = d.GetDictEntryByKeyword( 'foobar' ) + undef = gdcm.Tag(0xffff,0xffff) + if p[1] != undef: + sys.exit(1) + print(p[1]) + + # Test succeed ? + sys.exit(0) diff --git a/gdcm/Testing/Source/DataDictionary/Python/TestGlobal.py b/gdcm/Testing/Source/DataDictionary/Python/TestGlobal.py new file mode 100644 index 0000000..cd802c3 --- /dev/null +++ b/gdcm/Testing/Source/DataDictionary/Python/TestGlobal.py @@ -0,0 +1,34 @@ +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +import gdcm +import os,sys + +if __name__ == "__main__": + + #gi = gdcm.GlobalInstance + #print gi + singleton = gdcm.Global.GetInstance() + print(singleton) + d = singleton.GetDicts() + print(d) + t = gdcm.Tag(0x0010,0x0010) + entry = d.GetDictEntry( t ) + print(entry) + print(entry.GetName()) + #print entry.GetVM() + print(entry.GetVR()) + + # Test succeed ? + sys.exit(0) diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/CMakeLists.txt b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/CMakeLists.txt new file mode 100644 index 0000000..2e31593 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/CMakeLists.txt @@ -0,0 +1,9 @@ +subdirs(Cxx) + +if(GDCM_WRAP_PYTHON) + subdirs(Python) +endif() + +if(GDCM_WRAP_JAVA) + subdirs(Java) +endif() diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/CMakeLists.txt b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/CMakeLists.txt new file mode 100644 index 0000000..752526d --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/CMakeLists.txt @@ -0,0 +1,130 @@ +# Define the tests for Data Structure and Encoding Definitions +# DSED +set(DSED_TEST_SRCS + TestAttribute + TestCodeString + TestAttribute1 + TestAttribute7 + #TestReadPatientName + TestLO + TestCSAElement + #TestByteBuffer + #TestByteValue + TestPreamble + TestReader + TestReader4 + TestReaderUpToTag + TestReaderUpToTag2 + TestReaderSelectedTags + TestReaderSelectedPrivateGroups + TestReaderCanRead + TestWriter + TestWriter2 + TestCSAHeader + TestByteSwapFilter + TestBasicOffsetTable + TestComposite + TestDataElement + TestDataSet + #TestVRDS + TestDS + TestVRLT + TestVRUI + TestElement + #TestExplicitDataElement + TestFileMetaInformation + TestFile + TestFileSet + TestFragment + #TestImplicitDataElement + TestItem + #TestParser + TestSequenceOfFragments + TestSequenceOfItems + TestTag + TestPrivateTag + TestTransferSyntax + TestMediaStorage + TestVL + TestVM + TestVR + #TestValue + #TestTorture + TestElement2 + TestElement4 + TestElement5 + ) +if(GDCM_TESTING_USE_LC_NUMERIC) +# The test expect to be able to set fr as locale only turn if user +# set the appropriate & hidden cmake variable +set(DSED_TEST_SRCS + ${DSED_TEST_SRCS} + TestLCNumeric +) +endif() +if(GDCM_DATA_ROOT) +set(DSED_TEST_SRCS + ${DSED_TEST_SRCS} + TestReader2 + TestAttribute8 + TestPDBHeader + TestSequenceOfItems2 + ) +endif() +if(GDCM_DATA_EXTRA_ROOT) +set(DSED_TEST_SRCS + ${DSED_TEST_SRCS} + TestInvalidDICOMFiles + ) +endif() + +CHECK_INCLUDE_FILE("sys/mman.h" GDCM_HAVE_SYS_MMAN_H) + +# Need mmap +if(GDCM_HAVE_SYS_MMAN_H) + set(DSED_TEST_SRCS ${DSED_TEST_SRCS} + TestReader3 + ) +endif() + +option(SHARED_PTR "shared_ptr" OFF) +mark_as_advanced(SHARED_PTR) +if(SHARED_PTR) + set(DSED_TEST_SRCS + ${DSED_TEST_SRCS} + TestCopyValue + ) +endif() + +# Add the include paths +include_directories( + "${GDCM_BINARY_DIR}/Source/Common" + "${GDCM_SOURCE_DIR}/Source/Common" + "${GDCM_SOURCE_DIR}/Source/DataDictionary" + "${GDCM_SOURCE_DIR}/Source/DataStructureAndEncodingDefinition" + "${GDCM_BINARY_DIR}/Utilities/zlib" + "${GDCM_SOURCE_DIR}/Utilities" + ) + +create_test_sourcelist(DSEDTests gdcmDSEDTests.cxx ${DSED_TEST_SRCS} + EXTRA_INCLUDE gdcmTestDriver.h + ) +add_executable(gdcmDSEDTests ${DSEDTests}) +target_link_libraries(gdcmDSEDTests gdcmDSED) +if(CMAKE_COMPILER_IS_GNUCXX AND MINGW) + set_target_properties( gdcmDSEDTests PROPERTIES LINK_FLAGS "-Wl,--allow-multiple-definition") +endif() + +#Don't understand why I need that ?? +set(GDCM_DSED_TESTS "${EXECUTABLE_OUTPUT_PATH}/gdcmDSEDTests") + +# Loop over files and create executables +foreach(name ${DSED_TEST_SRCS}) + add_test(NAME ${name} COMMAND ${GDCM_DSED_TESTS} ${name}) +endforeach() + +# FIXME +#add_executable(TestAttribute2 TestAttribute2.cxx) +#add_executable(TestAttribute3 TestAttribute3.cxx) +#add_executable(TestAttribute4 TestAttribute4.cxx) +#add_executable(TestAttribute5 TestAttribute5.cxx) diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestAttribute.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestAttribute.cxx new file mode 100644 index 0000000..1e3e293 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestAttribute.cxx @@ -0,0 +1,2644 @@ + +// GENERATED FILE DO NOT EDIT +// $ xsltproc TestAttribute.xsl DICOMV3.xml > TestAttribute.cxx + +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#include "gdcmAttribute.h" + +int TestAttribute(int, char *[]) +{ + gdcm::Attribute<0x0000,0x0000> a00000000; (void)a00000000; + gdcm::Attribute<0x0000,0x0001> a00000001; (void)a00000001; + gdcm::Attribute<0x0000,0x0002> a00000002; (void)a00000002; + gdcm::Attribute<0x0000,0x0003> a00000003; (void)a00000003; + gdcm::Attribute<0x0000,0x0010> a00000010; (void)a00000010; + gdcm::Attribute<0x0000,0x0100> a00000100; (void)a00000100; + gdcm::Attribute<0x0000,0x0110> a00000110; (void)a00000110; + gdcm::Attribute<0x0000,0x0120> a00000120; (void)a00000120; + gdcm::Attribute<0x0000,0x0200> a00000200; (void)a00000200; + gdcm::Attribute<0x0000,0x0300> a00000300; (void)a00000300; + gdcm::Attribute<0x0000,0x0400> a00000400; (void)a00000400; + gdcm::Attribute<0x0000,0x0600> a00000600; (void)a00000600; + gdcm::Attribute<0x0000,0x0700> a00000700; (void)a00000700; + gdcm::Attribute<0x0000,0x0800> a00000800; (void)a00000800; + gdcm::Attribute<0x0000,0x0850> a00000850; (void)a00000850; + gdcm::Attribute<0x0000,0x0860> a00000860; (void)a00000860; + gdcm::Attribute<0x0000,0x0900> a00000900; (void)a00000900; + gdcm::Attribute<0x0000,0x0901> a00000901; (void)a00000901; + gdcm::Attribute<0x0000,0x0902> a00000902; (void)a00000902; + gdcm::Attribute<0x0000,0x0903> a00000903; (void)a00000903; + gdcm::Attribute<0x0000,0x1000> a00001000; (void)a00001000; + gdcm::Attribute<0x0000,0x1001> a00001001; (void)a00001001; + gdcm::Attribute<0x0000,0x1002> a00001002; (void)a00001002; + gdcm::Attribute<0x0000,0x1005> a00001005; (void)a00001005; + gdcm::Attribute<0x0000,0x1008> a00001008; (void)a00001008; + gdcm::Attribute<0x0000,0x1020> a00001020; (void)a00001020; + gdcm::Attribute<0x0000,0x1021> a00001021; (void)a00001021; + gdcm::Attribute<0x0000,0x1022> a00001022; (void)a00001022; + gdcm::Attribute<0x0000,0x1023> a00001023; (void)a00001023; + gdcm::Attribute<0x0000,0x1030> a00001030; (void)a00001030; + gdcm::Attribute<0x0000,0x1031> a00001031; (void)a00001031; + gdcm::Attribute<0x0000,0x4000> a00004000; (void)a00004000; + gdcm::Attribute<0x0000,0x4010> a00004010; (void)a00004010; + gdcm::Attribute<0x0000,0x5010> a00005010; (void)a00005010; + gdcm::Attribute<0x0000,0x5020> a00005020; (void)a00005020; + gdcm::Attribute<0x0000,0x5110> a00005110; (void)a00005110; + gdcm::Attribute<0x0000,0x5120> a00005120; (void)a00005120; + gdcm::Attribute<0x0000,0x5130> a00005130; (void)a00005130; + gdcm::Attribute<0x0000,0x5140> a00005140; (void)a00005140; + gdcm::Attribute<0x0000,0x5150> a00005150; (void)a00005150; + gdcm::Attribute<0x0000,0x5160> a00005160; (void)a00005160; + gdcm::Attribute<0x0000,0x5170> a00005170; (void)a00005170; + gdcm::Attribute<0x0000,0x5180> a00005180; (void)a00005180; + gdcm::Attribute<0x0000,0x5190> a00005190; (void)a00005190; + gdcm::Attribute<0x0000,0x51a0> a000051a0; (void)a000051a0; + gdcm::Attribute<0x0000,0x51b0> a000051b0; (void)a000051b0; + gdcm::Attribute<0x0002,0x0000> a00020000; (void)a00020000; + gdcm::Attribute<0x0002,0x0001> a00020001; (void)a00020001; + gdcm::Attribute<0x0002,0x0002> a00020002; (void)a00020002; + gdcm::Attribute<0x0002,0x0003> a00020003; (void)a00020003; + gdcm::Attribute<0x0002,0x0010> a00020010; (void)a00020010; + gdcm::Attribute<0x0002,0x0012> a00020012; (void)a00020012; + gdcm::Attribute<0x0002,0x0013> a00020013; (void)a00020013; + gdcm::Attribute<0x0002,0x0016> a00020016; (void)a00020016; + gdcm::Attribute<0x0002,0x0100> a00020100; (void)a00020100; + gdcm::Attribute<0x0002,0x0102> a00020102; (void)a00020102; + gdcm::Attribute<0x0004,0x1130> a00041130; (void)a00041130; + gdcm::Attribute<0x0004,0x1142> a00041142; (void)a00041142; + gdcm::Attribute<0x0004,0x1200> a00041200; (void)a00041200; + gdcm::Attribute<0x0004,0x1202> a00041202; (void)a00041202; + gdcm::Attribute<0x0004,0x1212> a00041212; (void)a00041212; + gdcm::Attribute<0x0004,0x1220> a00041220; (void)a00041220; + gdcm::Attribute<0x0004,0x1400> a00041400; (void)a00041400; + gdcm::Attribute<0x0004,0x1410> a00041410; (void)a00041410; + gdcm::Attribute<0x0004,0x1420> a00041420; (void)a00041420; + gdcm::Attribute<0x0004,0x1430> a00041430; (void)a00041430; + gdcm::Attribute<0x0004,0x1432> a00041432; (void)a00041432; + gdcm::Attribute<0x0004,0x1504> a00041504; (void)a00041504; + gdcm::Attribute<0x0004,0x1510> a00041510; (void)a00041510; + gdcm::Attribute<0x0004,0x1511> a00041511; (void)a00041511; + gdcm::Attribute<0x0004,0x1512> a00041512; (void)a00041512; + gdcm::Attribute<0x0004,0x151a> a0004151a; (void)a0004151a; + gdcm::Attribute<0x0004,0x1600> a00041600; (void)a00041600; + gdcm::Attribute<0x0008,0x0001> a00080001; (void)a00080001; + gdcm::Attribute<0x0008,0x0005> a00080005; (void)a00080005; + gdcm::Attribute<0x0008,0x0008> a00080008; (void)a00080008; + gdcm::Attribute<0x0008,0x0010> a00080010; (void)a00080010; + gdcm::Attribute<0x0008,0x0012> a00080012; (void)a00080012; + gdcm::Attribute<0x0008,0x0013> a00080013; (void)a00080013; + gdcm::Attribute<0x0008,0x0014> a00080014; (void)a00080014; + gdcm::Attribute<0x0008,0x0016> a00080016; (void)a00080016; + gdcm::Attribute<0x0008,0x0018> a00080018; (void)a00080018; + gdcm::Attribute<0x0008,0x001a> a0008001a; (void)a0008001a; + gdcm::Attribute<0x0008,0x001b> a0008001b; (void)a0008001b; + gdcm::Attribute<0x0008,0x0020> a00080020; (void)a00080020; + gdcm::Attribute<0x0008,0x0021> a00080021; (void)a00080021; + gdcm::Attribute<0x0008,0x0022> a00080022; (void)a00080022; + gdcm::Attribute<0x0008,0x0023> a00080023; (void)a00080023; + gdcm::Attribute<0x0008,0x0024> a00080024; (void)a00080024; + gdcm::Attribute<0x0008,0x0025> a00080025; (void)a00080025; + gdcm::Attribute<0x0008,0x002a> a0008002a; (void)a0008002a; + gdcm::Attribute<0x0008,0x0030> a00080030; (void)a00080030; + gdcm::Attribute<0x0008,0x0031> a00080031; (void)a00080031; + gdcm::Attribute<0x0008,0x0032> a00080032; (void)a00080032; + gdcm::Attribute<0x0008,0x0033> a00080033; (void)a00080033; + gdcm::Attribute<0x0008,0x0034> a00080034; (void)a00080034; + gdcm::Attribute<0x0008,0x0035> a00080035; (void)a00080035; + gdcm::Attribute<0x0008,0x0040> a00080040; (void)a00080040; + gdcm::Attribute<0x0008,0x0041> a00080041; (void)a00080041; + gdcm::Attribute<0x0008,0x0042> a00080042; (void)a00080042; + gdcm::Attribute<0x0008,0x0050> a00080050; (void)a00080050; + gdcm::Attribute<0x0008,0x0052> a00080052; (void)a00080052; + gdcm::Attribute<0x0008,0x0054> a00080054; (void)a00080054; + gdcm::Attribute<0x0008,0x0056> a00080056; (void)a00080056; + gdcm::Attribute<0x0008,0x0058> a00080058; (void)a00080058; + gdcm::Attribute<0x0008,0x0060> a00080060; (void)a00080060; + gdcm::Attribute<0x0008,0x0061> a00080061; (void)a00080061; + gdcm::Attribute<0x0008,0x0062> a00080062; (void)a00080062; + gdcm::Attribute<0x0008,0x0064> a00080064; (void)a00080064; + gdcm::Attribute<0x0008,0x0068> a00080068; (void)a00080068; + gdcm::Attribute<0x0008,0x0070> a00080070; (void)a00080070; + gdcm::Attribute<0x0008,0x0080> a00080080; (void)a00080080; + gdcm::Attribute<0x0008,0x0081> a00080081; (void)a00080081; + gdcm::Attribute<0x0008,0x0082> a00080082; (void)a00080082; + gdcm::Attribute<0x0008,0x0090> a00080090; (void)a00080090; + gdcm::Attribute<0x0008,0x0092> a00080092; (void)a00080092; + gdcm::Attribute<0x0008,0x0094> a00080094; (void)a00080094; + gdcm::Attribute<0x0008,0x0096> a00080096; (void)a00080096; + gdcm::Attribute<0x0008,0x0100> a00080100; (void)a00080100; + gdcm::Attribute<0x0008,0x0102> a00080102; (void)a00080102; + gdcm::Attribute<0x0008,0x0103> a00080103; (void)a00080103; + gdcm::Attribute<0x0008,0x0104> a00080104; (void)a00080104; + gdcm::Attribute<0x0008,0x0105> a00080105; (void)a00080105; + gdcm::Attribute<0x0008,0x0106> a00080106; (void)a00080106; + gdcm::Attribute<0x0008,0x0107> a00080107; (void)a00080107; + gdcm::Attribute<0x0008,0x010b> a0008010b; (void)a0008010b; + gdcm::Attribute<0x0008,0x010c> a0008010c; (void)a0008010c; + gdcm::Attribute<0x0008,0x010d> a0008010d; (void)a0008010d; + gdcm::Attribute<0x0008,0x010f> a0008010f; (void)a0008010f; + gdcm::Attribute<0x0008,0x0110> a00080110; (void)a00080110; + gdcm::Attribute<0x0008,0x0112> a00080112; (void)a00080112; + gdcm::Attribute<0x0008,0x0114> a00080114; (void)a00080114; + gdcm::Attribute<0x0008,0x0115> a00080115; (void)a00080115; + gdcm::Attribute<0x0008,0x0116> a00080116; (void)a00080116; + gdcm::Attribute<0x0008,0x0201> a00080201; (void)a00080201; + gdcm::Attribute<0x0008,0x1000> a00081000; (void)a00081000; + gdcm::Attribute<0x0008,0x1010> a00081010; (void)a00081010; + gdcm::Attribute<0x0008,0x1030> a00081030; (void)a00081030; + gdcm::Attribute<0x0008,0x1032> a00081032; (void)a00081032; + gdcm::Attribute<0x0008,0x103e> a0008103e; (void)a0008103e; + gdcm::Attribute<0x0008,0x1040> a00081040; (void)a00081040; + gdcm::Attribute<0x0008,0x1048> a00081048; (void)a00081048; + gdcm::Attribute<0x0008,0x1049> a00081049; (void)a00081049; + gdcm::Attribute<0x0008,0x1050> a00081050; (void)a00081050; + gdcm::Attribute<0x0008,0x1052> a00081052; (void)a00081052; + gdcm::Attribute<0x0008,0x1060> a00081060; (void)a00081060; + gdcm::Attribute<0x0008,0x1062> a00081062; (void)a00081062; + gdcm::Attribute<0x0008,0x1070> a00081070; (void)a00081070; + gdcm::Attribute<0x0008,0x1072> a00081072; (void)a00081072; + gdcm::Attribute<0x0008,0x1080> a00081080; (void)a00081080; + gdcm::Attribute<0x0008,0x1084> a00081084; (void)a00081084; + gdcm::Attribute<0x0008,0x1090> a00081090; (void)a00081090; + gdcm::Attribute<0x0008,0x1100> a00081100; (void)a00081100; + gdcm::Attribute<0x0008,0x1110> a00081110; (void)a00081110; + gdcm::Attribute<0x0008,0x1111> a00081111; (void)a00081111; + gdcm::Attribute<0x0008,0x1115> a00081115; (void)a00081115; + gdcm::Attribute<0x0008,0x1120> a00081120; (void)a00081120; + gdcm::Attribute<0x0008,0x1125> a00081125; (void)a00081125; + gdcm::Attribute<0x0008,0x1130> a00081130; (void)a00081130; + gdcm::Attribute<0x0008,0x113a> a0008113a; (void)a0008113a; + gdcm::Attribute<0x0008,0x1140> a00081140; (void)a00081140; + gdcm::Attribute<0x0008,0x1145> a00081145; (void)a00081145; + gdcm::Attribute<0x0008,0x114a> a0008114a; (void)a0008114a; + gdcm::Attribute<0x0008,0x114b> a0008114b; (void)a0008114b; + gdcm::Attribute<0x0008,0x1150> a00081150; (void)a00081150; + gdcm::Attribute<0x0008,0x1155> a00081155; (void)a00081155; + gdcm::Attribute<0x0008,0x115a> a0008115a; (void)a0008115a; + gdcm::Attribute<0x0008,0x1160> a00081160; (void)a00081160; + gdcm::Attribute<0x0008,0x1195> a00081195; (void)a00081195; + gdcm::Attribute<0x0008,0x1197> a00081197; (void)a00081197; + gdcm::Attribute<0x0008,0x1198> a00081198; (void)a00081198; + gdcm::Attribute<0x0008,0x1199> a00081199; (void)a00081199; + gdcm::Attribute<0x0008,0x1200> a00081200; (void)a00081200; + gdcm::Attribute<0x0008,0x1250> a00081250; (void)a00081250; + gdcm::Attribute<0x0008,0x2110> a00082110; (void)a00082110; + gdcm::Attribute<0x0008,0x2111> a00082111; (void)a00082111; + gdcm::Attribute<0x0008,0x2112> a00082112; (void)a00082112; + gdcm::Attribute<0x0008,0x2120> a00082120; (void)a00082120; + gdcm::Attribute<0x0008,0x2122> a00082122; (void)a00082122; + gdcm::Attribute<0x0008,0x2124> a00082124; (void)a00082124; + gdcm::Attribute<0x0008,0x2127> a00082127; (void)a00082127; + gdcm::Attribute<0x0008,0x2128> a00082128; (void)a00082128; + gdcm::Attribute<0x0008,0x2129> a00082129; (void)a00082129; + gdcm::Attribute<0x0008,0x212a> a0008212a; (void)a0008212a; + gdcm::Attribute<0x0008,0x2130> a00082130; (void)a00082130; + gdcm::Attribute<0x0008,0x2132> a00082132; (void)a00082132; + gdcm::Attribute<0x0008,0x2142> a00082142; (void)a00082142; + gdcm::Attribute<0x0008,0x2143> a00082143; (void)a00082143; + gdcm::Attribute<0x0008,0x2144> a00082144; (void)a00082144; + gdcm::Attribute<0x0008,0x2200> a00082200; (void)a00082200; + gdcm::Attribute<0x0008,0x2204> a00082204; (void)a00082204; + gdcm::Attribute<0x0008,0x2208> a00082208; (void)a00082208; + gdcm::Attribute<0x0008,0x2218> a00082218; (void)a00082218; + gdcm::Attribute<0x0008,0x2220> a00082220; (void)a00082220; + gdcm::Attribute<0x0008,0x2228> a00082228; (void)a00082228; + gdcm::Attribute<0x0008,0x2229> a00082229; (void)a00082229; + gdcm::Attribute<0x0008,0x2230> a00082230; (void)a00082230; + gdcm::Attribute<0x0008,0x2240> a00082240; (void)a00082240; + gdcm::Attribute<0x0008,0x2242> a00082242; (void)a00082242; + gdcm::Attribute<0x0008,0x2244> a00082244; (void)a00082244; + gdcm::Attribute<0x0008,0x2246> a00082246; (void)a00082246; + gdcm::Attribute<0x0008,0x2251> a00082251; (void)a00082251; + gdcm::Attribute<0x0008,0x2253> a00082253; (void)a00082253; + gdcm::Attribute<0x0008,0x2255> a00082255; (void)a00082255; + gdcm::Attribute<0x0008,0x2256> a00082256; (void)a00082256; + gdcm::Attribute<0x0008,0x2257> a00082257; (void)a00082257; + gdcm::Attribute<0x0008,0x2258> a00082258; (void)a00082258; + gdcm::Attribute<0x0008,0x2259> a00082259; (void)a00082259; + gdcm::Attribute<0x0008,0x225a> a0008225a; (void)a0008225a; + gdcm::Attribute<0x0008,0x225c> a0008225c; (void)a0008225c; + gdcm::Attribute<0x0008,0x3001> a00083001; (void)a00083001; + gdcm::Attribute<0x0008,0x3010> a00083010; (void)a00083010; + gdcm::Attribute<0x0008,0x4000> a00084000; (void)a00084000; + gdcm::Attribute<0x0008,0x9007> a00089007; (void)a00089007; + gdcm::Attribute<0x0008,0x9092> a00089092; (void)a00089092; + gdcm::Attribute<0x0008,0x9121> a00089121; (void)a00089121; + gdcm::Attribute<0x0008,0x9123> a00089123; (void)a00089123; + gdcm::Attribute<0x0008,0x9124> a00089124; (void)a00089124; + gdcm::Attribute<0x0008,0x9154> a00089154; (void)a00089154; + gdcm::Attribute<0x0008,0x9205> a00089205; (void)a00089205; + gdcm::Attribute<0x0008,0x9206> a00089206; (void)a00089206; + gdcm::Attribute<0x0008,0x9207> a00089207; (void)a00089207; + gdcm::Attribute<0x0008,0x9208> a00089208; (void)a00089208; + gdcm::Attribute<0x0008,0x9209> a00089209; (void)a00089209; + gdcm::Attribute<0x0008,0x9215> a00089215; (void)a00089215; + gdcm::Attribute<0x0008,0x9237> a00089237; (void)a00089237; + gdcm::Attribute<0x0008,0x9410> a00089410; (void)a00089410; + gdcm::Attribute<0x0008,0x9458> a00089458; (void)a00089458; + gdcm::Attribute<0x0008,0x9459> a00089459; (void)a00089459; + gdcm::Attribute<0x0008,0x9460> a00089460; (void)a00089460; + gdcm::Attribute<0x0010,0x0010> a00100010; (void)a00100010; + gdcm::Attribute<0x0010,0x0020> a00100020; (void)a00100020; + gdcm::Attribute<0x0010,0x0021> a00100021; (void)a00100021; + gdcm::Attribute<0x0010,0x0022> a00100022; (void)a00100022; + gdcm::Attribute<0x0010,0x0030> a00100030; (void)a00100030; + gdcm::Attribute<0x0010,0x0032> a00100032; (void)a00100032; + gdcm::Attribute<0x0010,0x0040> a00100040; (void)a00100040; + gdcm::Attribute<0x0010,0x0050> a00100050; (void)a00100050; + gdcm::Attribute<0x0010,0x0101> a00100101; (void)a00100101; + gdcm::Attribute<0x0010,0x0102> a00100102; (void)a00100102; + gdcm::Attribute<0x0010,0x1000> a00101000; (void)a00101000; + gdcm::Attribute<0x0010,0x1001> a00101001; (void)a00101001; + gdcm::Attribute<0x0010,0x1002> a00101002; (void)a00101002; + gdcm::Attribute<0x0010,0x1005> a00101005; (void)a00101005; + gdcm::Attribute<0x0010,0x1010> a00101010; (void)a00101010; + gdcm::Attribute<0x0010,0x1020> a00101020; (void)a00101020; + gdcm::Attribute<0x0010,0x1030> a00101030; (void)a00101030; + gdcm::Attribute<0x0010,0x1040> a00101040; (void)a00101040; + gdcm::Attribute<0x0010,0x1050> a00101050; (void)a00101050; + gdcm::Attribute<0x0010,0x1060> a00101060; (void)a00101060; + gdcm::Attribute<0x0010,0x1080> a00101080; (void)a00101080; + gdcm::Attribute<0x0010,0x1081> a00101081; (void)a00101081; + gdcm::Attribute<0x0010,0x1090> a00101090; (void)a00101090; + gdcm::Attribute<0x0010,0x2000> a00102000; (void)a00102000; + gdcm::Attribute<0x0010,0x2110> a00102110; (void)a00102110; + gdcm::Attribute<0x0010,0x2150> a00102150; (void)a00102150; + gdcm::Attribute<0x0010,0x2152> a00102152; (void)a00102152; + gdcm::Attribute<0x0010,0x2154> a00102154; (void)a00102154; + gdcm::Attribute<0x0010,0x2160> a00102160; (void)a00102160; + gdcm::Attribute<0x0010,0x2180> a00102180; (void)a00102180; + gdcm::Attribute<0x0010,0x21a0> a001021a0; (void)a001021a0; + gdcm::Attribute<0x0010,0x21b0> a001021b0; (void)a001021b0; + gdcm::Attribute<0x0010,0x21c0> a001021c0; (void)a001021c0; + gdcm::Attribute<0x0010,0x21d0> a001021d0; (void)a001021d0; + gdcm::Attribute<0x0010,0x21f0> a001021f0; (void)a001021f0; + gdcm::Attribute<0x0010,0x2201> a00102201; (void)a00102201; + gdcm::Attribute<0x0010,0x2202> a00102202; (void)a00102202; + gdcm::Attribute<0x0010,0x2203> a00102203; (void)a00102203; + gdcm::Attribute<0x0010,0x2292> a00102292; (void)a00102292; + gdcm::Attribute<0x0010,0x2293> a00102293; (void)a00102293; + gdcm::Attribute<0x0010,0x2294> a00102294; (void)a00102294; + gdcm::Attribute<0x0010,0x2295> a00102295; (void)a00102295; + gdcm::Attribute<0x0010,0x2296> a00102296; (void)a00102296; + gdcm::Attribute<0x0010,0x2297> a00102297; (void)a00102297; + gdcm::Attribute<0x0010,0x2298> a00102298; (void)a00102298; + gdcm::Attribute<0x0010,0x2299> a00102299; (void)a00102299; + gdcm::Attribute<0x0010,0x4000> a00104000; (void)a00104000; + gdcm::Attribute<0x0010,0x9431> a00109431; (void)a00109431; + gdcm::Attribute<0x0012,0x0010> a00120010; (void)a00120010; + gdcm::Attribute<0x0012,0x0020> a00120020; (void)a00120020; + gdcm::Attribute<0x0012,0x0021> a00120021; (void)a00120021; + gdcm::Attribute<0x0012,0x0030> a00120030; (void)a00120030; + gdcm::Attribute<0x0012,0x0031> a00120031; (void)a00120031; + gdcm::Attribute<0x0012,0x0040> a00120040; (void)a00120040; + gdcm::Attribute<0x0012,0x0042> a00120042; (void)a00120042; + gdcm::Attribute<0x0012,0x0050> a00120050; (void)a00120050; + gdcm::Attribute<0x0012,0x0051> a00120051; (void)a00120051; + gdcm::Attribute<0x0012,0x0060> a00120060; (void)a00120060; + gdcm::Attribute<0x0012,0x0062> a00120062; (void)a00120062; + gdcm::Attribute<0x0012,0x0063> a00120063; (void)a00120063; + gdcm::Attribute<0x0012,0x0064> a00120064; (void)a00120064; + gdcm::Attribute<0x0012,0x0071> a00120071; (void)a00120071; + gdcm::Attribute<0x0012,0x0072> a00120072; (void)a00120072; + gdcm::Attribute<0x0018,0x0010> a00180010; (void)a00180010; + gdcm::Attribute<0x0018,0x0012> a00180012; (void)a00180012; + gdcm::Attribute<0x0018,0x0014> a00180014; (void)a00180014; + gdcm::Attribute<0x0018,0x0015> a00180015; (void)a00180015; + gdcm::Attribute<0x0018,0x0020> a00180020; (void)a00180020; + gdcm::Attribute<0x0018,0x0021> a00180021; (void)a00180021; + gdcm::Attribute<0x0018,0x0022> a00180022; (void)a00180022; + gdcm::Attribute<0x0018,0x0023> a00180023; (void)a00180023; + gdcm::Attribute<0x0018,0x0024> a00180024; (void)a00180024; + gdcm::Attribute<0x0018,0x0025> a00180025; (void)a00180025; + gdcm::Attribute<0x0018,0x0026> a00180026; (void)a00180026; + gdcm::Attribute<0x0018,0x0027> a00180027; (void)a00180027; + gdcm::Attribute<0x0018,0x0028> a00180028; (void)a00180028; + gdcm::Attribute<0x0018,0x0029> a00180029; (void)a00180029; + gdcm::Attribute<0x0018,0x002a> a0018002a; (void)a0018002a; + gdcm::Attribute<0x0018,0x0030> a00180030; (void)a00180030; + gdcm::Attribute<0x0018,0x0031> a00180031; (void)a00180031; + gdcm::Attribute<0x0018,0x0032> a00180032; (void)a00180032; + gdcm::Attribute<0x0018,0x0033> a00180033; (void)a00180033; + gdcm::Attribute<0x0018,0x0034> a00180034; (void)a00180034; + gdcm::Attribute<0x0018,0x0035> a00180035; (void)a00180035; + gdcm::Attribute<0x0018,0x0036> a00180036; (void)a00180036; + gdcm::Attribute<0x0018,0x0037> a00180037; (void)a00180037; + gdcm::Attribute<0x0018,0x0038> a00180038; (void)a00180038; + gdcm::Attribute<0x0018,0x0039> a00180039; (void)a00180039; + gdcm::Attribute<0x0018,0x003a> a0018003a; (void)a0018003a; + gdcm::Attribute<0x0018,0x0040> a00180040; (void)a00180040; + gdcm::Attribute<0x0018,0x0050> a00180050; (void)a00180050; + gdcm::Attribute<0x0018,0x0060> a00180060; (void)a00180060; + gdcm::Attribute<0x0018,0x0070> a00180070; (void)a00180070; + gdcm::Attribute<0x0018,0x0071> a00180071; (void)a00180071; + gdcm::Attribute<0x0018,0x0072> a00180072; (void)a00180072; + gdcm::Attribute<0x0018,0x0073> a00180073; (void)a00180073; + gdcm::Attribute<0x0018,0x0074> a00180074; (void)a00180074; + gdcm::Attribute<0x0018,0x0075> a00180075; (void)a00180075; + gdcm::Attribute<0x0018,0x0080> a00180080; (void)a00180080; + gdcm::Attribute<0x0018,0x0081> a00180081; (void)a00180081; + gdcm::Attribute<0x0018,0x0082> a00180082; (void)a00180082; + gdcm::Attribute<0x0018,0x0083> a00180083; (void)a00180083; + gdcm::Attribute<0x0018,0x0084> a00180084; (void)a00180084; + gdcm::Attribute<0x0018,0x0085> a00180085; (void)a00180085; + gdcm::Attribute<0x0018,0x0086> a00180086; (void)a00180086; + gdcm::Attribute<0x0018,0x0087> a00180087; (void)a00180087; + gdcm::Attribute<0x0018,0x0088> a00180088; (void)a00180088; + gdcm::Attribute<0x0018,0x0089> a00180089; (void)a00180089; + gdcm::Attribute<0x0018,0x0090> a00180090; (void)a00180090; + gdcm::Attribute<0x0018,0x0091> a00180091; (void)a00180091; + gdcm::Attribute<0x0018,0x0093> a00180093; (void)a00180093; + gdcm::Attribute<0x0018,0x0094> a00180094; (void)a00180094; + gdcm::Attribute<0x0018,0x0095> a00180095; (void)a00180095; + gdcm::Attribute<0x0018,0x1000> a00181000; (void)a00181000; + gdcm::Attribute<0x0018,0x1002> a00181002; (void)a00181002; + gdcm::Attribute<0x0018,0x1003> a00181003; (void)a00181003; + gdcm::Attribute<0x0018,0x1004> a00181004; (void)a00181004; + gdcm::Attribute<0x0018,0x1005> a00181005; (void)a00181005; + gdcm::Attribute<0x0018,0x1006> a00181006; (void)a00181006; + gdcm::Attribute<0x0018,0x1007> a00181007; (void)a00181007; + gdcm::Attribute<0x0018,0x1008> a00181008; (void)a00181008; + gdcm::Attribute<0x0018,0x1010> a00181010; (void)a00181010; + gdcm::Attribute<0x0018,0x1011> a00181011; (void)a00181011; + gdcm::Attribute<0x0018,0x1012> a00181012; (void)a00181012; + gdcm::Attribute<0x0018,0x1014> a00181014; (void)a00181014; + gdcm::Attribute<0x0018,0x1016> a00181016; (void)a00181016; + gdcm::Attribute<0x0018,0x1017> a00181017; (void)a00181017; + gdcm::Attribute<0x0018,0x1018> a00181018; (void)a00181018; + gdcm::Attribute<0x0018,0x1019> a00181019; (void)a00181019; + gdcm::Attribute<0x0018,0x101a> a0018101a; (void)a0018101a; + gdcm::Attribute<0x0018,0x101b> a0018101b; (void)a0018101b; + gdcm::Attribute<0x0018,0x1020> a00181020; (void)a00181020; + gdcm::Attribute<0x0018,0x1022> a00181022; (void)a00181022; + gdcm::Attribute<0x0018,0x1023> a00181023; (void)a00181023; + gdcm::Attribute<0x0018,0x1030> a00181030; (void)a00181030; + gdcm::Attribute<0x0018,0x1040> a00181040; (void)a00181040; + gdcm::Attribute<0x0018,0x1041> a00181041; (void)a00181041; + gdcm::Attribute<0x0018,0x1042> a00181042; (void)a00181042; + gdcm::Attribute<0x0018,0x1043> a00181043; (void)a00181043; + gdcm::Attribute<0x0018,0x1044> a00181044; (void)a00181044; + gdcm::Attribute<0x0018,0x1045> a00181045; (void)a00181045; + gdcm::Attribute<0x0018,0x1046> a00181046; (void)a00181046; + gdcm::Attribute<0x0018,0x1047> a00181047; (void)a00181047; + gdcm::Attribute<0x0018,0x1048> a00181048; (void)a00181048; + gdcm::Attribute<0x0018,0x1049> a00181049; (void)a00181049; + gdcm::Attribute<0x0018,0x1050> a00181050; (void)a00181050; + gdcm::Attribute<0x0018,0x1060> a00181060; (void)a00181060; + gdcm::Attribute<0x0018,0x1061> a00181061; (void)a00181061; + gdcm::Attribute<0x0018,0x1062> a00181062; (void)a00181062; + gdcm::Attribute<0x0018,0x1063> a00181063; (void)a00181063; + gdcm::Attribute<0x0018,0x1064> a00181064; (void)a00181064; + gdcm::Attribute<0x0018,0x1065> a00181065; (void)a00181065; + gdcm::Attribute<0x0018,0x1066> a00181066; (void)a00181066; + gdcm::Attribute<0x0018,0x1067> a00181067; (void)a00181067; + gdcm::Attribute<0x0018,0x1068> a00181068; (void)a00181068; + gdcm::Attribute<0x0018,0x1069> a00181069; (void)a00181069; + gdcm::Attribute<0x0018,0x106a> a0018106a; (void)a0018106a; + gdcm::Attribute<0x0018,0x106c> a0018106c; (void)a0018106c; + gdcm::Attribute<0x0018,0x106e> a0018106e; (void)a0018106e; + gdcm::Attribute<0x0018,0x1070> a00181070; (void)a00181070; + gdcm::Attribute<0x0018,0x1071> a00181071; (void)a00181071; + gdcm::Attribute<0x0018,0x1072> a00181072; (void)a00181072; + gdcm::Attribute<0x0018,0x1073> a00181073; (void)a00181073; + gdcm::Attribute<0x0018,0x1074> a00181074; (void)a00181074; + gdcm::Attribute<0x0018,0x1075> a00181075; (void)a00181075; + gdcm::Attribute<0x0018,0x1076> a00181076; (void)a00181076; + gdcm::Attribute<0x0018,0x1077> a00181077; (void)a00181077; + gdcm::Attribute<0x0018,0x1078> a00181078; (void)a00181078; + gdcm::Attribute<0x0018,0x1079> a00181079; (void)a00181079; + gdcm::Attribute<0x0018,0x1080> a00181080; (void)a00181080; + gdcm::Attribute<0x0018,0x1081> a00181081; (void)a00181081; + gdcm::Attribute<0x0018,0x1082> a00181082; (void)a00181082; + gdcm::Attribute<0x0018,0x1083> a00181083; (void)a00181083; + gdcm::Attribute<0x0018,0x1084> a00181084; (void)a00181084; + gdcm::Attribute<0x0018,0x1085> a00181085; (void)a00181085; + gdcm::Attribute<0x0018,0x1086> a00181086; (void)a00181086; + gdcm::Attribute<0x0018,0x1088> a00181088; (void)a00181088; + gdcm::Attribute<0x0018,0x1090> a00181090; (void)a00181090; + gdcm::Attribute<0x0018,0x1094> a00181094; (void)a00181094; + gdcm::Attribute<0x0018,0x1100> a00181100; (void)a00181100; + gdcm::Attribute<0x0018,0x1110> a00181110; (void)a00181110; + gdcm::Attribute<0x0018,0x1111> a00181111; (void)a00181111; + gdcm::Attribute<0x0018,0x1114> a00181114; (void)a00181114; + gdcm::Attribute<0x0018,0x1120> a00181120; (void)a00181120; + gdcm::Attribute<0x0018,0x1121> a00181121; (void)a00181121; + gdcm::Attribute<0x0018,0x1130> a00181130; (void)a00181130; + gdcm::Attribute<0x0018,0x1131> a00181131; (void)a00181131; + gdcm::Attribute<0x0018,0x1134> a00181134; (void)a00181134; + gdcm::Attribute<0x0018,0x1135> a00181135; (void)a00181135; + gdcm::Attribute<0x0018,0x1136> a00181136; (void)a00181136; + gdcm::Attribute<0x0018,0x1137> a00181137; (void)a00181137; + gdcm::Attribute<0x0018,0x1138> a00181138; (void)a00181138; + gdcm::Attribute<0x0018,0x113a> a0018113a; (void)a0018113a; + gdcm::Attribute<0x0018,0x1140> a00181140; (void)a00181140; + gdcm::Attribute<0x0018,0x1141> a00181141; (void)a00181141; + gdcm::Attribute<0x0018,0x1142> a00181142; (void)a00181142; + gdcm::Attribute<0x0018,0x1143> a00181143; (void)a00181143; + gdcm::Attribute<0x0018,0x1144> a00181144; (void)a00181144; + gdcm::Attribute<0x0018,0x1145> a00181145; (void)a00181145; + gdcm::Attribute<0x0018,0x1146> a00181146; (void)a00181146; + gdcm::Attribute<0x0018,0x1147> a00181147; (void)a00181147; + gdcm::Attribute<0x0018,0x1150> a00181150; (void)a00181150; + gdcm::Attribute<0x0018,0x1151> a00181151; (void)a00181151; + gdcm::Attribute<0x0018,0x1152> a00181152; (void)a00181152; + gdcm::Attribute<0x0018,0x1153> a00181153; (void)a00181153; + gdcm::Attribute<0x0018,0x1154> a00181154; (void)a00181154; + gdcm::Attribute<0x0018,0x1155> a00181155; (void)a00181155; + gdcm::Attribute<0x0018,0x1156> a00181156; (void)a00181156; + gdcm::Attribute<0x0018,0x115a> a0018115a; (void)a0018115a; + gdcm::Attribute<0x0018,0x115e> a0018115e; (void)a0018115e; + gdcm::Attribute<0x0018,0x1160> a00181160; (void)a00181160; + gdcm::Attribute<0x0018,0x1161> a00181161; (void)a00181161; + gdcm::Attribute<0x0018,0x1162> a00181162; (void)a00181162; + gdcm::Attribute<0x0018,0x1164> a00181164; (void)a00181164; + gdcm::Attribute<0x0018,0x1166> a00181166; (void)a00181166; + gdcm::Attribute<0x0018,0x1170> a00181170; (void)a00181170; + gdcm::Attribute<0x0018,0x1180> a00181180; (void)a00181180; + gdcm::Attribute<0x0018,0x1181> a00181181; (void)a00181181; + gdcm::Attribute<0x0018,0x1190> a00181190; (void)a00181190; + gdcm::Attribute<0x0018,0x1191> a00181191; (void)a00181191; + gdcm::Attribute<0x0018,0x11a0> a001811a0; (void)a001811a0; + gdcm::Attribute<0x0018,0x11a2> a001811a2; (void)a001811a2; + gdcm::Attribute<0x0018,0x1200> a00181200; (void)a00181200; + gdcm::Attribute<0x0018,0x1201> a00181201; (void)a00181201; + gdcm::Attribute<0x0018,0x1210> a00181210; (void)a00181210; + gdcm::Attribute<0x0018,0x1240> a00181240; (void)a00181240; + gdcm::Attribute<0x0018,0x1242> a00181242; (void)a00181242; + gdcm::Attribute<0x0018,0x1243> a00181243; (void)a00181243; + gdcm::Attribute<0x0018,0x1244> a00181244; (void)a00181244; + gdcm::Attribute<0x0018,0x1250> a00181250; (void)a00181250; + gdcm::Attribute<0x0018,0x1251> a00181251; (void)a00181251; + gdcm::Attribute<0x0018,0x1260> a00181260; (void)a00181260; + gdcm::Attribute<0x0018,0x1261> a00181261; (void)a00181261; + gdcm::Attribute<0x0018,0x1300> a00181300; (void)a00181300; + gdcm::Attribute<0x0018,0x1301> a00181301; (void)a00181301; + gdcm::Attribute<0x0018,0x1302> a00181302; (void)a00181302; + gdcm::Attribute<0x0018,0x1310> a00181310; (void)a00181310; + gdcm::Attribute<0x0018,0x1312> a00181312; (void)a00181312; + gdcm::Attribute<0x0018,0x1314> a00181314; (void)a00181314; + gdcm::Attribute<0x0018,0x1315> a00181315; (void)a00181315; + gdcm::Attribute<0x0018,0x1316> a00181316; (void)a00181316; + gdcm::Attribute<0x0018,0x1318> a00181318; (void)a00181318; + gdcm::Attribute<0x0018,0x1400> a00181400; (void)a00181400; + gdcm::Attribute<0x0018,0x1401> a00181401; (void)a00181401; + gdcm::Attribute<0x0018,0x1402> a00181402; (void)a00181402; + gdcm::Attribute<0x0018,0x1403> a00181403; (void)a00181403; + gdcm::Attribute<0x0018,0x1404> a00181404; (void)a00181404; + gdcm::Attribute<0x0018,0x1405> a00181405; (void)a00181405; + gdcm::Attribute<0x0018,0x1450> a00181450; (void)a00181450; + gdcm::Attribute<0x0018,0x1460> a00181460; (void)a00181460; + gdcm::Attribute<0x0018,0x1470> a00181470; (void)a00181470; + gdcm::Attribute<0x0018,0x1480> a00181480; (void)a00181480; + gdcm::Attribute<0x0018,0x1490> a00181490; (void)a00181490; + gdcm::Attribute<0x0018,0x1491> a00181491; (void)a00181491; + gdcm::Attribute<0x0018,0x1495> a00181495; (void)a00181495; + gdcm::Attribute<0x0018,0x1500> a00181500; (void)a00181500; + gdcm::Attribute<0x0018,0x1508> a00181508; (void)a00181508; + gdcm::Attribute<0x0018,0x1510> a00181510; (void)a00181510; + gdcm::Attribute<0x0018,0x1511> a00181511; (void)a00181511; + gdcm::Attribute<0x0018,0x1520> a00181520; (void)a00181520; + gdcm::Attribute<0x0018,0x1521> a00181521; (void)a00181521; + gdcm::Attribute<0x0018,0x1530> a00181530; (void)a00181530; + gdcm::Attribute<0x0018,0x1531> a00181531; (void)a00181531; + gdcm::Attribute<0x0018,0x1602> a00181602; (void)a00181602; + gdcm::Attribute<0x0018,0x1604> a00181604; (void)a00181604; + gdcm::Attribute<0x0018,0x1606> a00181606; (void)a00181606; + gdcm::Attribute<0x0018,0x1608> a00181608; (void)a00181608; + gdcm::Attribute<0x0018,0x1610> a00181610; (void)a00181610; + gdcm::Attribute<0x0018,0x1612> a00181612; (void)a00181612; + gdcm::Attribute<0x0018,0x1620> a00181620; (void)a00181620; + gdcm::Attribute<0x0018,0x1622> a00181622; (void)a00181622; + gdcm::Attribute<0x0018,0x1623> a00181623; (void)a00181623; + gdcm::Attribute<0x0018,0x1624> a00181624; (void)a00181624; + gdcm::Attribute<0x0018,0x1702> a00181702; (void)a00181702; + gdcm::Attribute<0x0018,0x1704> a00181704; (void)a00181704; + gdcm::Attribute<0x0018,0x1706> a00181706; (void)a00181706; + gdcm::Attribute<0x0018,0x1708> a00181708; (void)a00181708; + gdcm::Attribute<0x0018,0x1710> a00181710; (void)a00181710; + gdcm::Attribute<0x0018,0x1712> a00181712; (void)a00181712; + gdcm::Attribute<0x0018,0x1720> a00181720; (void)a00181720; + gdcm::Attribute<0x0018,0x1800> a00181800; (void)a00181800; + gdcm::Attribute<0x0018,0x1801> a00181801; (void)a00181801; + gdcm::Attribute<0x0018,0x1802> a00181802; (void)a00181802; + gdcm::Attribute<0x0018,0x1803> a00181803; (void)a00181803; + gdcm::Attribute<0x0018,0x2001> a00182001; (void)a00182001; + gdcm::Attribute<0x0018,0x2002> a00182002; (void)a00182002; + gdcm::Attribute<0x0018,0x2003> a00182003; (void)a00182003; + gdcm::Attribute<0x0018,0x2004> a00182004; (void)a00182004; + gdcm::Attribute<0x0018,0x2005> a00182005; (void)a00182005; + gdcm::Attribute<0x0018,0x2006> a00182006; (void)a00182006; + gdcm::Attribute<0x0018,0x2010> a00182010; (void)a00182010; + gdcm::Attribute<0x0018,0x2020> a00182020; (void)a00182020; + gdcm::Attribute<0x0018,0x2030> a00182030; (void)a00182030; + gdcm::Attribute<0x0018,0x3100> a00183100; (void)a00183100; + gdcm::Attribute<0x0018,0x3101> a00183101; (void)a00183101; + gdcm::Attribute<0x0018,0x3102> a00183102; (void)a00183102; + gdcm::Attribute<0x0018,0x3103> a00183103; (void)a00183103; + gdcm::Attribute<0x0018,0x3104> a00183104; (void)a00183104; + gdcm::Attribute<0x0018,0x3105> a00183105; (void)a00183105; + gdcm::Attribute<0x0018,0x4000> a00184000; (void)a00184000; + gdcm::Attribute<0x0018,0x5000> a00185000; (void)a00185000; + gdcm::Attribute<0x0018,0x5010> a00185010; (void)a00185010; + gdcm::Attribute<0x0018,0x5012> a00185012; (void)a00185012; + gdcm::Attribute<0x0018,0x5020> a00185020; (void)a00185020; + gdcm::Attribute<0x0018,0x5021> a00185021; (void)a00185021; + gdcm::Attribute<0x0018,0x5022> a00185022; (void)a00185022; + gdcm::Attribute<0x0018,0x5024> a00185024; (void)a00185024; + gdcm::Attribute<0x0018,0x5026> a00185026; (void)a00185026; + gdcm::Attribute<0x0018,0x5027> a00185027; (void)a00185027; + gdcm::Attribute<0x0018,0x5028> a00185028; (void)a00185028; + gdcm::Attribute<0x0018,0x5029> a00185029; (void)a00185029; + gdcm::Attribute<0x0018,0x5030> a00185030; (void)a00185030; + gdcm::Attribute<0x0018,0x5040> a00185040; (void)a00185040; + gdcm::Attribute<0x0018,0x5050> a00185050; (void)a00185050; + gdcm::Attribute<0x0018,0x5100> a00185100; (void)a00185100; + gdcm::Attribute<0x0018,0x5101> a00185101; (void)a00185101; + gdcm::Attribute<0x0018,0x5104> a00185104; (void)a00185104; + gdcm::Attribute<0x0018,0x5210> a00185210; (void)a00185210; + gdcm::Attribute<0x0018,0x5212> a00185212; (void)a00185212; + gdcm::Attribute<0x0018,0x6000> a00186000; (void)a00186000; + gdcm::Attribute<0x0018,0x6011> a00186011; (void)a00186011; + gdcm::Attribute<0x0018,0x6012> a00186012; (void)a00186012; + gdcm::Attribute<0x0018,0x6014> a00186014; (void)a00186014; + gdcm::Attribute<0x0018,0x6016> a00186016; (void)a00186016; + gdcm::Attribute<0x0018,0x6018> a00186018; (void)a00186018; + gdcm::Attribute<0x0018,0x601a> a0018601a; (void)a0018601a; + gdcm::Attribute<0x0018,0x601c> a0018601c; (void)a0018601c; + gdcm::Attribute<0x0018,0x601e> a0018601e; (void)a0018601e; + gdcm::Attribute<0x0018,0x6020> a00186020; (void)a00186020; + gdcm::Attribute<0x0018,0x6022> a00186022; (void)a00186022; + gdcm::Attribute<0x0018,0x6024> a00186024; (void)a00186024; + gdcm::Attribute<0x0018,0x6026> a00186026; (void)a00186026; + gdcm::Attribute<0x0018,0x6028> a00186028; (void)a00186028; + gdcm::Attribute<0x0018,0x602a> a0018602a; (void)a0018602a; + gdcm::Attribute<0x0018,0x602c> a0018602c; (void)a0018602c; + gdcm::Attribute<0x0018,0x602e> a0018602e; (void)a0018602e; + gdcm::Attribute<0x0018,0x6030> a00186030; (void)a00186030; + gdcm::Attribute<0x0018,0x6031> a00186031; (void)a00186031; + gdcm::Attribute<0x0018,0x6032> a00186032; (void)a00186032; + gdcm::Attribute<0x0018,0x6034> a00186034; (void)a00186034; + gdcm::Attribute<0x0018,0x6036> a00186036; (void)a00186036; + gdcm::Attribute<0x0018,0x6038> a00186038; (void)a00186038; + gdcm::Attribute<0x0018,0x6039> a00186039; (void)a00186039; + gdcm::Attribute<0x0018,0x603a> a0018603a; (void)a0018603a; + gdcm::Attribute<0x0018,0x603b> a0018603b; (void)a0018603b; + gdcm::Attribute<0x0018,0x603c> a0018603c; (void)a0018603c; + gdcm::Attribute<0x0018,0x603d> a0018603d; (void)a0018603d; + gdcm::Attribute<0x0018,0x603e> a0018603e; (void)a0018603e; + gdcm::Attribute<0x0018,0x603f> a0018603f; (void)a0018603f; + gdcm::Attribute<0x0018,0x6040> a00186040; (void)a00186040; + gdcm::Attribute<0x0018,0x6041> a00186041; (void)a00186041; + gdcm::Attribute<0x0018,0x6042> a00186042; (void)a00186042; + gdcm::Attribute<0x0018,0x6043> a00186043; (void)a00186043; + gdcm::Attribute<0x0018,0x6044> a00186044; (void)a00186044; + gdcm::Attribute<0x0018,0x6046> a00186046; (void)a00186046; + gdcm::Attribute<0x0018,0x6048> a00186048; (void)a00186048; + gdcm::Attribute<0x0018,0x604a> a0018604a; (void)a0018604a; + gdcm::Attribute<0x0018,0x604c> a0018604c; (void)a0018604c; + gdcm::Attribute<0x0018,0x604e> a0018604e; (void)a0018604e; + gdcm::Attribute<0x0018,0x6050> a00186050; (void)a00186050; + gdcm::Attribute<0x0018,0x6052> a00186052; (void)a00186052; + gdcm::Attribute<0x0018,0x6054> a00186054; (void)a00186054; + gdcm::Attribute<0x0018,0x6056> a00186056; (void)a00186056; + gdcm::Attribute<0x0018,0x6058> a00186058; (void)a00186058; + gdcm::Attribute<0x0018,0x605a> a0018605a; (void)a0018605a; + gdcm::Attribute<0x0018,0x6060> a00186060; (void)a00186060; + gdcm::Attribute<0x0018,0x7000> a00187000; (void)a00187000; + gdcm::Attribute<0x0018,0x7001> a00187001; (void)a00187001; + gdcm::Attribute<0x0018,0x7004> a00187004; (void)a00187004; + gdcm::Attribute<0x0018,0x7005> a00187005; (void)a00187005; + gdcm::Attribute<0x0018,0x7006> a00187006; (void)a00187006; + gdcm::Attribute<0x0018,0x7008> a00187008; (void)a00187008; + gdcm::Attribute<0x0018,0x700a> a0018700a; (void)a0018700a; + gdcm::Attribute<0x0018,0x700c> a0018700c; (void)a0018700c; + gdcm::Attribute<0x0018,0x700e> a0018700e; (void)a0018700e; + gdcm::Attribute<0x0018,0x7010> a00187010; (void)a00187010; + gdcm::Attribute<0x0018,0x7011> a00187011; (void)a00187011; + gdcm::Attribute<0x0018,0x7012> a00187012; (void)a00187012; + gdcm::Attribute<0x0018,0x7014> a00187014; (void)a00187014; + gdcm::Attribute<0x0018,0x7016> a00187016; (void)a00187016; + gdcm::Attribute<0x0018,0x701a> a0018701a; (void)a0018701a; + gdcm::Attribute<0x0018,0x7020> a00187020; (void)a00187020; + gdcm::Attribute<0x0018,0x7022> a00187022; (void)a00187022; + gdcm::Attribute<0x0018,0x7024> a00187024; (void)a00187024; + gdcm::Attribute<0x0018,0x7028> a00187028; (void)a00187028; + gdcm::Attribute<0x0018,0x702a> a0018702a; (void)a0018702a; + gdcm::Attribute<0x0018,0x702b> a0018702b; (void)a0018702b; + gdcm::Attribute<0x0018,0x7030> a00187030; (void)a00187030; + gdcm::Attribute<0x0018,0x7032> a00187032; (void)a00187032; + gdcm::Attribute<0x0018,0x7034> a00187034; (void)a00187034; + gdcm::Attribute<0x0018,0x7040> a00187040; (void)a00187040; + gdcm::Attribute<0x0018,0x7041> a00187041; (void)a00187041; + gdcm::Attribute<0x0018,0x7042> a00187042; (void)a00187042; + gdcm::Attribute<0x0018,0x7044> a00187044; (void)a00187044; + gdcm::Attribute<0x0018,0x7046> a00187046; (void)a00187046; + gdcm::Attribute<0x0018,0x7048> a00187048; (void)a00187048; + gdcm::Attribute<0x0018,0x704c> a0018704c; (void)a0018704c; + gdcm::Attribute<0x0018,0x7050> a00187050; (void)a00187050; + gdcm::Attribute<0x0018,0x7052> a00187052; (void)a00187052; + gdcm::Attribute<0x0018,0x7054> a00187054; (void)a00187054; + gdcm::Attribute<0x0018,0x7060> a00187060; (void)a00187060; + gdcm::Attribute<0x0018,0x7062> a00187062; (void)a00187062; + gdcm::Attribute<0x0018,0x7064> a00187064; (void)a00187064; + gdcm::Attribute<0x0018,0x7065> a00187065; (void)a00187065; + gdcm::Attribute<0x0018,0x8150> a00188150; (void)a00188150; + gdcm::Attribute<0x0018,0x8151> a00188151; (void)a00188151; + gdcm::Attribute<0x0018,0x9004> a00189004; (void)a00189004; + gdcm::Attribute<0x0018,0x9005> a00189005; (void)a00189005; + gdcm::Attribute<0x0018,0x9006> a00189006; (void)a00189006; + gdcm::Attribute<0x0018,0x9008> a00189008; (void)a00189008; + gdcm::Attribute<0x0018,0x9009> a00189009; (void)a00189009; + gdcm::Attribute<0x0018,0x9010> a00189010; (void)a00189010; + gdcm::Attribute<0x0018,0x9011> a00189011; (void)a00189011; + gdcm::Attribute<0x0018,0x9012> a00189012; (void)a00189012; + gdcm::Attribute<0x0018,0x9014> a00189014; (void)a00189014; + gdcm::Attribute<0x0018,0x9015> a00189015; (void)a00189015; + gdcm::Attribute<0x0018,0x9016> a00189016; (void)a00189016; + gdcm::Attribute<0x0018,0x9017> a00189017; (void)a00189017; + gdcm::Attribute<0x0018,0x9018> a00189018; (void)a00189018; + gdcm::Attribute<0x0018,0x9019> a00189019; (void)a00189019; + gdcm::Attribute<0x0018,0x9020> a00189020; (void)a00189020; + gdcm::Attribute<0x0018,0x9021> a00189021; (void)a00189021; + gdcm::Attribute<0x0018,0x9022> a00189022; (void)a00189022; + gdcm::Attribute<0x0018,0x9024> a00189024; (void)a00189024; + gdcm::Attribute<0x0018,0x9025> a00189025; (void)a00189025; + gdcm::Attribute<0x0018,0x9026> a00189026; (void)a00189026; + gdcm::Attribute<0x0018,0x9027> a00189027; (void)a00189027; + gdcm::Attribute<0x0018,0x9028> a00189028; (void)a00189028; + gdcm::Attribute<0x0018,0x9029> a00189029; (void)a00189029; + gdcm::Attribute<0x0018,0x9030> a00189030; (void)a00189030; + gdcm::Attribute<0x0018,0x9032> a00189032; (void)a00189032; + gdcm::Attribute<0x0018,0x9033> a00189033; (void)a00189033; + gdcm::Attribute<0x0018,0x9034> a00189034; (void)a00189034; + gdcm::Attribute<0x0018,0x9035> a00189035; (void)a00189035; + gdcm::Attribute<0x0018,0x9036> a00189036; (void)a00189036; + gdcm::Attribute<0x0018,0x9037> a00189037; (void)a00189037; + gdcm::Attribute<0x0018,0x9041> a00189041; (void)a00189041; + gdcm::Attribute<0x0018,0x9042> a00189042; (void)a00189042; + gdcm::Attribute<0x0018,0x9043> a00189043; (void)a00189043; + gdcm::Attribute<0x0018,0x9044> a00189044; (void)a00189044; + gdcm::Attribute<0x0018,0x9045> a00189045; (void)a00189045; + gdcm::Attribute<0x0018,0x9046> a00189046; (void)a00189046; + gdcm::Attribute<0x0018,0x9047> a00189047; (void)a00189047; + gdcm::Attribute<0x0018,0x9048> a00189048; (void)a00189048; + gdcm::Attribute<0x0018,0x9049> a00189049; (void)a00189049; + gdcm::Attribute<0x0018,0x9050> a00189050; (void)a00189050; + gdcm::Attribute<0x0018,0x9051> a00189051; (void)a00189051; + gdcm::Attribute<0x0018,0x9054> a00189054; (void)a00189054; + gdcm::Attribute<0x0018,0x9058> a00189058; (void)a00189058; + gdcm::Attribute<0x0018,0x9059> a00189059; (void)a00189059; + gdcm::Attribute<0x0018,0x9062> a00189062; (void)a00189062; + gdcm::Attribute<0x0018,0x9064> a00189064; (void)a00189064; + gdcm::Attribute<0x0018,0x9067> a00189067; (void)a00189067; + gdcm::Attribute<0x0018,0x9069> a00189069; (void)a00189069; + gdcm::Attribute<0x0018,0x9070> a00189070; (void)a00189070; + gdcm::Attribute<0x0018,0x9073> a00189073; (void)a00189073; + gdcm::Attribute<0x0018,0x9074> a00189074; (void)a00189074; + gdcm::Attribute<0x0018,0x9075> a00189075; (void)a00189075; + gdcm::Attribute<0x0018,0x9076> a00189076; (void)a00189076; + gdcm::Attribute<0x0018,0x9077> a00189077; (void)a00189077; + gdcm::Attribute<0x0018,0x9078> a00189078; (void)a00189078; + gdcm::Attribute<0x0018,0x9079> a00189079; (void)a00189079; + gdcm::Attribute<0x0018,0x9080> a00189080; (void)a00189080; + gdcm::Attribute<0x0018,0x9081> a00189081; (void)a00189081; + gdcm::Attribute<0x0018,0x9082> a00189082; (void)a00189082; + gdcm::Attribute<0x0018,0x9083> a00189083; (void)a00189083; + gdcm::Attribute<0x0018,0x9084> a00189084; (void)a00189084; + gdcm::Attribute<0x0018,0x9085> a00189085; (void)a00189085; + gdcm::Attribute<0x0018,0x9087> a00189087; (void)a00189087; + gdcm::Attribute<0x0018,0x9089> a00189089; (void)a00189089; + gdcm::Attribute<0x0018,0x9090> a00189090; (void)a00189090; + gdcm::Attribute<0x0018,0x9091> a00189091; (void)a00189091; + gdcm::Attribute<0x0018,0x9093> a00189093; (void)a00189093; + gdcm::Attribute<0x0018,0x9094> a00189094; (void)a00189094; + gdcm::Attribute<0x0018,0x9095> a00189095; (void)a00189095; + gdcm::Attribute<0x0018,0x9096> a00189096; (void)a00189096; + gdcm::Attribute<0x0018,0x9101> a00189101; (void)a00189101; + gdcm::Attribute<0x0018,0x9103> a00189103; (void)a00189103; + gdcm::Attribute<0x0018,0x9104> a00189104; (void)a00189104; + gdcm::Attribute<0x0018,0x9105> a00189105; (void)a00189105; + gdcm::Attribute<0x0018,0x9106> a00189106; (void)a00189106; + gdcm::Attribute<0x0018,0x9107> a00189107; (void)a00189107; + gdcm::Attribute<0x0018,0x9112> a00189112; (void)a00189112; + gdcm::Attribute<0x0018,0x9114> a00189114; (void)a00189114; + gdcm::Attribute<0x0018,0x9115> a00189115; (void)a00189115; + gdcm::Attribute<0x0018,0x9117> a00189117; (void)a00189117; + gdcm::Attribute<0x0018,0x9118> a00189118; (void)a00189118; + gdcm::Attribute<0x0018,0x9119> a00189119; (void)a00189119; + gdcm::Attribute<0x0018,0x9125> a00189125; (void)a00189125; + gdcm::Attribute<0x0018,0x9126> a00189126; (void)a00189126; + gdcm::Attribute<0x0018,0x9127> a00189127; (void)a00189127; + gdcm::Attribute<0x0018,0x9147> a00189147; (void)a00189147; + gdcm::Attribute<0x0018,0x9151> a00189151; (void)a00189151; + gdcm::Attribute<0x0018,0x9152> a00189152; (void)a00189152; + gdcm::Attribute<0x0018,0x9155> a00189155; (void)a00189155; + gdcm::Attribute<0x0018,0x9159> a00189159; (void)a00189159; + gdcm::Attribute<0x0018,0x9166> a00189166; (void)a00189166; + gdcm::Attribute<0x0018,0x9168> a00189168; (void)a00189168; + gdcm::Attribute<0x0018,0x9169> a00189169; (void)a00189169; + gdcm::Attribute<0x0018,0x9170> a00189170; (void)a00189170; + gdcm::Attribute<0x0018,0x9171> a00189171; (void)a00189171; + gdcm::Attribute<0x0018,0x9172> a00189172; (void)a00189172; + gdcm::Attribute<0x0018,0x9173> a00189173; (void)a00189173; + gdcm::Attribute<0x0018,0x9174> a00189174; (void)a00189174; + gdcm::Attribute<0x0018,0x9175> a00189175; (void)a00189175; + gdcm::Attribute<0x0018,0x9176> a00189176; (void)a00189176; + gdcm::Attribute<0x0018,0x9177> a00189177; (void)a00189177; + gdcm::Attribute<0x0018,0x9178> a00189178; (void)a00189178; + gdcm::Attribute<0x0018,0x9179> a00189179; (void)a00189179; + gdcm::Attribute<0x0018,0x9180> a00189180; (void)a00189180; + gdcm::Attribute<0x0018,0x9181> a00189181; (void)a00189181; + gdcm::Attribute<0x0018,0x9182> a00189182; (void)a00189182; + gdcm::Attribute<0x0018,0x9183> a00189183; (void)a00189183; + gdcm::Attribute<0x0018,0x9184> a00189184; (void)a00189184; + gdcm::Attribute<0x0018,0x9185> a00189185; (void)a00189185; + gdcm::Attribute<0x0018,0x9186> a00189186; (void)a00189186; + gdcm::Attribute<0x0018,0x9195> a00189195; (void)a00189195; + gdcm::Attribute<0x0018,0x9196> a00189196; (void)a00189196; + gdcm::Attribute<0x0018,0x9197> a00189197; (void)a00189197; + gdcm::Attribute<0x0018,0x9198> a00189198; (void)a00189198; + gdcm::Attribute<0x0018,0x9199> a00189199; (void)a00189199; + gdcm::Attribute<0x0018,0x9200> a00189200; (void)a00189200; + gdcm::Attribute<0x0018,0x9214> a00189214; (void)a00189214; + gdcm::Attribute<0x0018,0x9217> a00189217; (void)a00189217; + gdcm::Attribute<0x0018,0x9218> a00189218; (void)a00189218; + gdcm::Attribute<0x0018,0x9219> a00189219; (void)a00189219; + gdcm::Attribute<0x0018,0x9220> a00189220; (void)a00189220; + gdcm::Attribute<0x0018,0x9226> a00189226; (void)a00189226; + gdcm::Attribute<0x0018,0x9227> a00189227; (void)a00189227; + gdcm::Attribute<0x0018,0x9231> a00189231; (void)a00189231; + gdcm::Attribute<0x0018,0x9232> a00189232; (void)a00189232; + gdcm::Attribute<0x0018,0x9234> a00189234; (void)a00189234; + gdcm::Attribute<0x0018,0x9236> a00189236; (void)a00189236; + gdcm::Attribute<0x0018,0x9239> a00189239; (void)a00189239; + gdcm::Attribute<0x0018,0x9240> a00189240; (void)a00189240; + gdcm::Attribute<0x0018,0x9241> a00189241; (void)a00189241; + gdcm::Attribute<0x0018,0x9295> a00189295; (void)a00189295; + gdcm::Attribute<0x0018,0x9296> a00189296; (void)a00189296; + gdcm::Attribute<0x0018,0x9301> a00189301; (void)a00189301; + gdcm::Attribute<0x0018,0x9302> a00189302; (void)a00189302; + gdcm::Attribute<0x0018,0x9303> a00189303; (void)a00189303; + gdcm::Attribute<0x0018,0x9304> a00189304; (void)a00189304; + gdcm::Attribute<0x0018,0x9305> a00189305; (void)a00189305; + gdcm::Attribute<0x0018,0x9306> a00189306; (void)a00189306; + gdcm::Attribute<0x0018,0x9307> a00189307; (void)a00189307; + gdcm::Attribute<0x0018,0x9308> a00189308; (void)a00189308; + gdcm::Attribute<0x0018,0x9309> a00189309; (void)a00189309; + gdcm::Attribute<0x0018,0x9310> a00189310; (void)a00189310; + gdcm::Attribute<0x0018,0x9311> a00189311; (void)a00189311; + gdcm::Attribute<0x0018,0x9312> a00189312; (void)a00189312; + gdcm::Attribute<0x0018,0x9313> a00189313; (void)a00189313; + gdcm::Attribute<0x0018,0x9314> a00189314; (void)a00189314; + gdcm::Attribute<0x0018,0x9315> a00189315; (void)a00189315; + gdcm::Attribute<0x0018,0x9316> a00189316; (void)a00189316; + gdcm::Attribute<0x0018,0x9317> a00189317; (void)a00189317; + gdcm::Attribute<0x0018,0x9318> a00189318; (void)a00189318; + gdcm::Attribute<0x0018,0x9319> a00189319; (void)a00189319; + gdcm::Attribute<0x0018,0x9320> a00189320; (void)a00189320; + gdcm::Attribute<0x0018,0x9321> a00189321; (void)a00189321; + gdcm::Attribute<0x0018,0x9322> a00189322; (void)a00189322; + gdcm::Attribute<0x0018,0x9323> a00189323; (void)a00189323; + gdcm::Attribute<0x0018,0x9324> a00189324; (void)a00189324; + gdcm::Attribute<0x0018,0x9325> a00189325; (void)a00189325; + gdcm::Attribute<0x0018,0x9326> a00189326; (void)a00189326; + gdcm::Attribute<0x0018,0x9327> a00189327; (void)a00189327; + gdcm::Attribute<0x0018,0x9328> a00189328; (void)a00189328; + gdcm::Attribute<0x0018,0x9329> a00189329; (void)a00189329; + gdcm::Attribute<0x0018,0x9330> a00189330; (void)a00189330; + gdcm::Attribute<0x0018,0x9332> a00189332; (void)a00189332; + gdcm::Attribute<0x0018,0x9333> a00189333; (void)a00189333; + gdcm::Attribute<0x0018,0x9334> a00189334; (void)a00189334; + gdcm::Attribute<0x0018,0x9335> a00189335; (void)a00189335; + gdcm::Attribute<0x0018,0x9337> a00189337; (void)a00189337; + gdcm::Attribute<0x0018,0x9338> a00189338; (void)a00189338; + gdcm::Attribute<0x0018,0x9340> a00189340; (void)a00189340; + gdcm::Attribute<0x0018,0x9341> a00189341; (void)a00189341; + gdcm::Attribute<0x0018,0x9342> a00189342; (void)a00189342; + gdcm::Attribute<0x0018,0x9343> a00189343; (void)a00189343; + gdcm::Attribute<0x0018,0x9344> a00189344; (void)a00189344; + gdcm::Attribute<0x0018,0x9345> a00189345; (void)a00189345; + gdcm::Attribute<0x0018,0x9346> a00189346; (void)a00189346; + gdcm::Attribute<0x0018,0x9351> a00189351; (void)a00189351; + gdcm::Attribute<0x0018,0x9352> a00189352; (void)a00189352; + gdcm::Attribute<0x0018,0x9360> a00189360; (void)a00189360; + gdcm::Attribute<0x0018,0x9401> a00189401; (void)a00189401; + gdcm::Attribute<0x0018,0x9402> a00189402; (void)a00189402; + gdcm::Attribute<0x0018,0x9403> a00189403; (void)a00189403; + gdcm::Attribute<0x0018,0x9404> a00189404; (void)a00189404; + gdcm::Attribute<0x0018,0x9405> a00189405; (void)a00189405; + gdcm::Attribute<0x0018,0x9406> a00189406; (void)a00189406; + gdcm::Attribute<0x0018,0x9407> a00189407; (void)a00189407; + gdcm::Attribute<0x0018,0x9412> a00189412; (void)a00189412; + gdcm::Attribute<0x0018,0x9417> a00189417; (void)a00189417; + gdcm::Attribute<0x0018,0x9420> a00189420; (void)a00189420; + gdcm::Attribute<0x0018,0x9423> a00189423; (void)a00189423; + gdcm::Attribute<0x0018,0x9424> a00189424; (void)a00189424; + gdcm::Attribute<0x0018,0x9425> a00189425; (void)a00189425; + gdcm::Attribute<0x0018,0x9426> a00189426; (void)a00189426; + gdcm::Attribute<0x0018,0x9427> a00189427; (void)a00189427; + gdcm::Attribute<0x0018,0x9429> a00189429; (void)a00189429; + gdcm::Attribute<0x0018,0x9430> a00189430; (void)a00189430; + gdcm::Attribute<0x0018,0x9432> a00189432; (void)a00189432; + gdcm::Attribute<0x0018,0x9433> a00189433; (void)a00189433; + gdcm::Attribute<0x0018,0x9434> a00189434; (void)a00189434; + gdcm::Attribute<0x0018,0x9435> a00189435; (void)a00189435; + gdcm::Attribute<0x0018,0x9436> a00189436; (void)a00189436; + gdcm::Attribute<0x0018,0x9437> a00189437; (void)a00189437; + gdcm::Attribute<0x0018,0x9438> a00189438; (void)a00189438; + gdcm::Attribute<0x0018,0x9439> a00189439; (void)a00189439; + gdcm::Attribute<0x0018,0x9440> a00189440; (void)a00189440; + gdcm::Attribute<0x0018,0x9441> a00189441; (void)a00189441; + gdcm::Attribute<0x0018,0x9442> a00189442; (void)a00189442; + gdcm::Attribute<0x0018,0x9447> a00189447; (void)a00189447; + gdcm::Attribute<0x0018,0x9449> a00189449; (void)a00189449; + gdcm::Attribute<0x0018,0x9451> a00189451; (void)a00189451; + gdcm::Attribute<0x0018,0x9452> a00189452; (void)a00189452; + gdcm::Attribute<0x0018,0x9455> a00189455; (void)a00189455; + gdcm::Attribute<0x0018,0x9456> a00189456; (void)a00189456; + gdcm::Attribute<0x0018,0x9457> a00189457; (void)a00189457; + gdcm::Attribute<0x0018,0x9462> a00189462; (void)a00189462; + gdcm::Attribute<0x0018,0x9463> a00189463; (void)a00189463; + gdcm::Attribute<0x0018,0x9464> a00189464; (void)a00189464; + gdcm::Attribute<0x0018,0x9465> a00189465; (void)a00189465; + gdcm::Attribute<0x0018,0x9466> a00189466; (void)a00189466; + gdcm::Attribute<0x0018,0x9467> a00189467; (void)a00189467; + gdcm::Attribute<0x0018,0x9468> a00189468; (void)a00189468; + gdcm::Attribute<0x0018,0x9469> a00189469; (void)a00189469; + gdcm::Attribute<0x0018,0x9470> a00189470; (void)a00189470; + gdcm::Attribute<0x0018,0x9471> a00189471; (void)a00189471; + gdcm::Attribute<0x0018,0x9472> a00189472; (void)a00189472; + gdcm::Attribute<0x0018,0x9473> a00189473; (void)a00189473; + gdcm::Attribute<0x0018,0x9474> a00189474; (void)a00189474; + gdcm::Attribute<0x0018,0x9476> a00189476; (void)a00189476; + gdcm::Attribute<0x0018,0x9477> a00189477; (void)a00189477; + gdcm::Attribute<0x0018,0x9504> a00189504; (void)a00189504; + gdcm::Attribute<0x0018,0x9506> a00189506; (void)a00189506; + gdcm::Attribute<0x0018,0x9507> a00189507; (void)a00189507; + gdcm::Attribute<0x0018,0x9508> a00189508; (void)a00189508; + gdcm::Attribute<0x0018,0x9509> a00189509; (void)a00189509; + gdcm::Attribute<0x0018,0x9510> a00189510; (void)a00189510; + gdcm::Attribute<0x0018,0x9511> a00189511; (void)a00189511; + gdcm::Attribute<0x0018,0x9514> a00189514; (void)a00189514; + gdcm::Attribute<0x0018,0x9515> a00189515; (void)a00189515; + gdcm::Attribute<0x0018,0x9516> a00189516; (void)a00189516; + gdcm::Attribute<0x0018,0x9517> a00189517; (void)a00189517; + gdcm::Attribute<0x0018,0x9524> a00189524; (void)a00189524; + gdcm::Attribute<0x0018,0x9525> a00189525; (void)a00189525; + gdcm::Attribute<0x0018,0x9526> a00189526; (void)a00189526; + gdcm::Attribute<0x0018,0x9527> a00189527; (void)a00189527; + gdcm::Attribute<0x0018,0x9528> a00189528; (void)a00189528; + gdcm::Attribute<0x0018,0x9530> a00189530; (void)a00189530; + gdcm::Attribute<0x0018,0x9531> a00189531; (void)a00189531; + gdcm::Attribute<0x0018,0x9538> a00189538; (void)a00189538; + gdcm::Attribute<0x0018,0x9601> a00189601; (void)a00189601; + gdcm::Attribute<0x0018,0x9602> a00189602; (void)a00189602; + gdcm::Attribute<0x0018,0x9603> a00189603; (void)a00189603; + gdcm::Attribute<0x0018,0x9604> a00189604; (void)a00189604; + gdcm::Attribute<0x0018,0x9605> a00189605; (void)a00189605; + gdcm::Attribute<0x0018,0x9606> a00189606; (void)a00189606; + gdcm::Attribute<0x0018,0x9607> a00189607; (void)a00189607; + gdcm::Attribute<0x0018,0xa001> a0018a001; (void)a0018a001; + gdcm::Attribute<0x0018,0xa002> a0018a002; (void)a0018a002; + gdcm::Attribute<0x0018,0xa003> a0018a003; (void)a0018a003; + gdcm::Attribute<0x0020,0x000d> a0020000d; (void)a0020000d; + gdcm::Attribute<0x0020,0x000e> a0020000e; (void)a0020000e; + gdcm::Attribute<0x0020,0x0010> a00200010; (void)a00200010; + gdcm::Attribute<0x0020,0x0011> a00200011; (void)a00200011; + gdcm::Attribute<0x0020,0x0012> a00200012; (void)a00200012; + gdcm::Attribute<0x0020,0x0013> a00200013; (void)a00200013; + gdcm::Attribute<0x0020,0x0014> a00200014; (void)a00200014; + gdcm::Attribute<0x0020,0x0015> a00200015; (void)a00200015; + gdcm::Attribute<0x0020,0x0016> a00200016; (void)a00200016; + gdcm::Attribute<0x0020,0x0017> a00200017; (void)a00200017; + gdcm::Attribute<0x0020,0x0018> a00200018; (void)a00200018; + gdcm::Attribute<0x0020,0x0019> a00200019; (void)a00200019; + gdcm::Attribute<0x0020,0x0020> a00200020; (void)a00200020; + gdcm::Attribute<0x0020,0x0022> a00200022; (void)a00200022; + gdcm::Attribute<0x0020,0x0024> a00200024; (void)a00200024; + gdcm::Attribute<0x0020,0x0026> a00200026; (void)a00200026; + gdcm::Attribute<0x0020,0x0030> a00200030; (void)a00200030; + gdcm::Attribute<0x0020,0x0032> a00200032; (void)a00200032; + gdcm::Attribute<0x0020,0x0035> a00200035; (void)a00200035; + gdcm::Attribute<0x0020,0x0037> a00200037; (void)a00200037; + gdcm::Attribute<0x0020,0x0050> a00200050; (void)a00200050; + gdcm::Attribute<0x0020,0x0052> a00200052; (void)a00200052; + gdcm::Attribute<0x0020,0x0060> a00200060; (void)a00200060; + gdcm::Attribute<0x0020,0x0062> a00200062; (void)a00200062; + gdcm::Attribute<0x0020,0x0070> a00200070; (void)a00200070; + gdcm::Attribute<0x0020,0x0080> a00200080; (void)a00200080; + gdcm::Attribute<0x0020,0x0100> a00200100; (void)a00200100; + gdcm::Attribute<0x0020,0x0105> a00200105; (void)a00200105; + gdcm::Attribute<0x0020,0x0110> a00200110; (void)a00200110; + gdcm::Attribute<0x0020,0x0200> a00200200; (void)a00200200; + gdcm::Attribute<0x0020,0x1000> a00201000; (void)a00201000; + gdcm::Attribute<0x0020,0x1001> a00201001; (void)a00201001; + gdcm::Attribute<0x0020,0x1002> a00201002; (void)a00201002; + gdcm::Attribute<0x0020,0x1003> a00201003; (void)a00201003; + gdcm::Attribute<0x0020,0x1004> a00201004; (void)a00201004; + gdcm::Attribute<0x0020,0x1005> a00201005; (void)a00201005; + gdcm::Attribute<0x0020,0x1020> a00201020; (void)a00201020; + gdcm::Attribute<0x0020,0x1040> a00201040; (void)a00201040; + gdcm::Attribute<0x0020,0x1041> a00201041; (void)a00201041; + gdcm::Attribute<0x0020,0x1070> a00201070; (void)a00201070; + gdcm::Attribute<0x0020,0x1200> a00201200; (void)a00201200; + gdcm::Attribute<0x0020,0x1202> a00201202; (void)a00201202; + gdcm::Attribute<0x0020,0x1204> a00201204; (void)a00201204; + gdcm::Attribute<0x0020,0x1206> a00201206; (void)a00201206; + gdcm::Attribute<0x0020,0x1208> a00201208; (void)a00201208; + gdcm::Attribute<0x0020,0x1209> a00201209; (void)a00201209; + gdcm::Attribute<0x0020,0x3401> a00203401; (void)a00203401; + gdcm::Attribute<0x0020,0x3402> a00203402; (void)a00203402; + gdcm::Attribute<0x0020,0x3403> a00203403; (void)a00203403; + gdcm::Attribute<0x0020,0x3404> a00203404; (void)a00203404; + gdcm::Attribute<0x0020,0x3405> a00203405; (void)a00203405; + gdcm::Attribute<0x0020,0x3406> a00203406; (void)a00203406; + gdcm::Attribute<0x0020,0x4000> a00204000; (void)a00204000; + gdcm::Attribute<0x0020,0x5000> a00205000; (void)a00205000; + gdcm::Attribute<0x0020,0x5002> a00205002; (void)a00205002; + gdcm::Attribute<0x0020,0x9056> a00209056; (void)a00209056; + gdcm::Attribute<0x0020,0x9057> a00209057; (void)a00209057; + gdcm::Attribute<0x0020,0x9071> a00209071; (void)a00209071; + gdcm::Attribute<0x0020,0x9072> a00209072; (void)a00209072; + gdcm::Attribute<0x0020,0x9111> a00209111; (void)a00209111; + gdcm::Attribute<0x0020,0x9113> a00209113; (void)a00209113; + gdcm::Attribute<0x0020,0x9116> a00209116; (void)a00209116; + gdcm::Attribute<0x0020,0x9128> a00209128; (void)a00209128; + gdcm::Attribute<0x0020,0x9153> a00209153; (void)a00209153; + gdcm::Attribute<0x0020,0x9156> a00209156; (void)a00209156; + gdcm::Attribute<0x0020,0x9157> a00209157; (void)a00209157; + gdcm::Attribute<0x0020,0x9158> a00209158; (void)a00209158; + gdcm::Attribute<0x0020,0x9161> a00209161; (void)a00209161; + gdcm::Attribute<0x0020,0x9162> a00209162; (void)a00209162; + gdcm::Attribute<0x0020,0x9163> a00209163; (void)a00209163; + gdcm::Attribute<0x0020,0x9164> a00209164; (void)a00209164; + gdcm::Attribute<0x0020,0x9165> a00209165; (void)a00209165; + gdcm::Attribute<0x0020,0x9167> a00209167; (void)a00209167; + gdcm::Attribute<0x0020,0x9213> a00209213; (void)a00209213; + gdcm::Attribute<0x0020,0x9221> a00209221; (void)a00209221; + gdcm::Attribute<0x0020,0x9222> a00209222; (void)a00209222; + gdcm::Attribute<0x0020,0x9228> a00209228; (void)a00209228; + gdcm::Attribute<0x0020,0x9238> a00209238; (void)a00209238; + gdcm::Attribute<0x0020,0x9241> a00209241; (void)a00209241; + gdcm::Attribute<0x0020,0x9245> a00209245; (void)a00209245; + gdcm::Attribute<0x0020,0x9246> a00209246; (void)a00209246; + gdcm::Attribute<0x0020,0x9247> a00209247; (void)a00209247; + gdcm::Attribute<0x0020,0x9248> a00209248; (void)a00209248; + gdcm::Attribute<0x0020,0x9249> a00209249; (void)a00209249; + gdcm::Attribute<0x0020,0x9250> a00209250; (void)a00209250; + gdcm::Attribute<0x0020,0x9251> a00209251; (void)a00209251; + gdcm::Attribute<0x0020,0x9252> a00209252; (void)a00209252; + gdcm::Attribute<0x0020,0x9253> a00209253; (void)a00209253; + gdcm::Attribute<0x0020,0x9254> a00209254; (void)a00209254; + gdcm::Attribute<0x0020,0x9255> a00209255; (void)a00209255; + gdcm::Attribute<0x0020,0x9256> a00209256; (void)a00209256; + gdcm::Attribute<0x0020,0x9257> a00209257; (void)a00209257; + gdcm::Attribute<0x0020,0x9421> a00209421; (void)a00209421; + gdcm::Attribute<0x0020,0x9450> a00209450; (void)a00209450; + gdcm::Attribute<0x0020,0x9453> a00209453; (void)a00209453; + gdcm::Attribute<0x0020,0x9518> a00209518; (void)a00209518; + gdcm::Attribute<0x0020,0x9529> a00209529; (void)a00209529; + gdcm::Attribute<0x0020,0x9536> a00209536; (void)a00209536; + gdcm::Attribute<0x0022,0x0001> a00220001; (void)a00220001; + gdcm::Attribute<0x0022,0x0002> a00220002; (void)a00220002; + gdcm::Attribute<0x0022,0x0003> a00220003; (void)a00220003; + gdcm::Attribute<0x0022,0x0004> a00220004; (void)a00220004; + gdcm::Attribute<0x0022,0x0005> a00220005; (void)a00220005; + gdcm::Attribute<0x0022,0x0006> a00220006; (void)a00220006; + gdcm::Attribute<0x0022,0x0007> a00220007; (void)a00220007; + gdcm::Attribute<0x0022,0x0008> a00220008; (void)a00220008; + gdcm::Attribute<0x0022,0x0009> a00220009; (void)a00220009; + gdcm::Attribute<0x0022,0x000a> a0022000a; (void)a0022000a; + gdcm::Attribute<0x0022,0x000b> a0022000b; (void)a0022000b; + gdcm::Attribute<0x0022,0x000c> a0022000c; (void)a0022000c; + gdcm::Attribute<0x0022,0x000d> a0022000d; (void)a0022000d; + gdcm::Attribute<0x0022,0x000e> a0022000e; (void)a0022000e; + gdcm::Attribute<0x0022,0x0010> a00220010; (void)a00220010; + gdcm::Attribute<0x0022,0x0011> a00220011; (void)a00220011; + gdcm::Attribute<0x0022,0x0012> a00220012; (void)a00220012; + gdcm::Attribute<0x0022,0x0013> a00220013; (void)a00220013; + gdcm::Attribute<0x0022,0x0014> a00220014; (void)a00220014; + gdcm::Attribute<0x0022,0x0015> a00220015; (void)a00220015; + gdcm::Attribute<0x0022,0x0016> a00220016; (void)a00220016; + gdcm::Attribute<0x0022,0x0017> a00220017; (void)a00220017; + gdcm::Attribute<0x0022,0x0018> a00220018; (void)a00220018; + gdcm::Attribute<0x0022,0x0019> a00220019; (void)a00220019; + gdcm::Attribute<0x0022,0x001a> a0022001a; (void)a0022001a; + gdcm::Attribute<0x0022,0x001b> a0022001b; (void)a0022001b; + gdcm::Attribute<0x0022,0x001c> a0022001c; (void)a0022001c; + gdcm::Attribute<0x0022,0x001d> a0022001d; (void)a0022001d; + gdcm::Attribute<0x0022,0x0020> a00220020; (void)a00220020; + gdcm::Attribute<0x0022,0x0021> a00220021; (void)a00220021; + gdcm::Attribute<0x0022,0x0022> a00220022; (void)a00220022; + gdcm::Attribute<0x0022,0x0030> a00220030; (void)a00220030; + gdcm::Attribute<0x0022,0x0031> a00220031; (void)a00220031; + gdcm::Attribute<0x0022,0x0032> a00220032; (void)a00220032; + gdcm::Attribute<0x0022,0x0035> a00220035; (void)a00220035; + gdcm::Attribute<0x0022,0x0036> a00220036; (void)a00220036; + gdcm::Attribute<0x0022,0x0037> a00220037; (void)a00220037; + gdcm::Attribute<0x0022,0x0038> a00220038; (void)a00220038; + gdcm::Attribute<0x0022,0x0039> a00220039; (void)a00220039; + gdcm::Attribute<0x0022,0x0041> a00220041; (void)a00220041; + gdcm::Attribute<0x0022,0x0042> a00220042; (void)a00220042; + gdcm::Attribute<0x0022,0x0048> a00220048; (void)a00220048; + gdcm::Attribute<0x0022,0x0049> a00220049; (void)a00220049; + gdcm::Attribute<0x0022,0x004e> a0022004e; (void)a0022004e; + gdcm::Attribute<0x0022,0x0055> a00220055; (void)a00220055; + gdcm::Attribute<0x0022,0x0056> a00220056; (void)a00220056; + gdcm::Attribute<0x0022,0x0057> a00220057; (void)a00220057; + gdcm::Attribute<0x0022,0x0058> a00220058; (void)a00220058; + gdcm::Attribute<0x0028,0x0002> a00280002; (void)a00280002; + gdcm::Attribute<0x0028,0x0003> a00280003; (void)a00280003; + gdcm::Attribute<0x0028,0x0004> a00280004; (void)a00280004; + gdcm::Attribute<0x0028,0x0005> a00280005; (void)a00280005; + gdcm::Attribute<0x0028,0x0006> a00280006; (void)a00280006; + gdcm::Attribute<0x0028,0x0008> a00280008; (void)a00280008; + gdcm::Attribute<0x0028,0x0009> a00280009; (void)a00280009; + gdcm::Attribute<0x0028,0x000a> a0028000a; (void)a0028000a; + gdcm::Attribute<0x0028,0x0010> a00280010; (void)a00280010; + gdcm::Attribute<0x0028,0x0011> a00280011; (void)a00280011; + gdcm::Attribute<0x0028,0x0012> a00280012; (void)a00280012; + gdcm::Attribute<0x0028,0x0014> a00280014; (void)a00280014; + gdcm::Attribute<0x0028,0x0030> a00280030; (void)a00280030; + gdcm::Attribute<0x0028,0x0031> a00280031; (void)a00280031; + gdcm::Attribute<0x0028,0x0032> a00280032; (void)a00280032; + gdcm::Attribute<0x0028,0x0034> a00280034; (void)a00280034; + gdcm::Attribute<0x0028,0x0040> a00280040; (void)a00280040; + gdcm::Attribute<0x0028,0x0050> a00280050; (void)a00280050; + gdcm::Attribute<0x0028,0x0051> a00280051; (void)a00280051; + gdcm::Attribute<0x0028,0x005f> a0028005f; (void)a0028005f; + gdcm::Attribute<0x0028,0x0060> a00280060; (void)a00280060; + gdcm::Attribute<0x0028,0x0061> a00280061; (void)a00280061; + gdcm::Attribute<0x0028,0x0062> a00280062; (void)a00280062; + gdcm::Attribute<0x0028,0x0063> a00280063; (void)a00280063; + gdcm::Attribute<0x0028,0x0065> a00280065; (void)a00280065; + gdcm::Attribute<0x0028,0x0066> a00280066; (void)a00280066; + gdcm::Attribute<0x0028,0x0068> a00280068; (void)a00280068; + gdcm::Attribute<0x0028,0x0069> a00280069; (void)a00280069; + gdcm::Attribute<0x0028,0x0070> a00280070; (void)a00280070; + gdcm::Attribute<0x0028,0x0080> a00280080; (void)a00280080; + gdcm::Attribute<0x0028,0x0081> a00280081; (void)a00280081; + gdcm::Attribute<0x0028,0x0082> a00280082; (void)a00280082; + gdcm::Attribute<0x0028,0x0090> a00280090; (void)a00280090; + gdcm::Attribute<0x0028,0x0091> a00280091; (void)a00280091; + gdcm::Attribute<0x0028,0x0092> a00280092; (void)a00280092; + gdcm::Attribute<0x0028,0x0093> a00280093; (void)a00280093; + gdcm::Attribute<0x0028,0x0094> a00280094; (void)a00280094; + gdcm::Attribute<0x0028,0x0100> a00280100; (void)a00280100; + gdcm::Attribute<0x0028,0x0101> a00280101; (void)a00280101; + gdcm::Attribute<0x0028,0x0102> a00280102; (void)a00280102; + gdcm::Attribute<0x0028,0x0103> a00280103; (void)a00280103; + gdcm::Attribute<0x0028,0x0200> a00280200; (void)a00280200; + gdcm::Attribute<0x0028,0x0300> a00280300; (void)a00280300; + gdcm::Attribute<0x0028,0x0301> a00280301; (void)a00280301; + gdcm::Attribute<0x0028,0x0400> a00280400; (void)a00280400; + gdcm::Attribute<0x0028,0x0401> a00280401; (void)a00280401; + gdcm::Attribute<0x0028,0x0402> a00280402; (void)a00280402; + gdcm::Attribute<0x0028,0x0403> a00280403; (void)a00280403; + gdcm::Attribute<0x0028,0x0404> a00280404; (void)a00280404; + gdcm::Attribute<0x0028,0x0700> a00280700; (void)a00280700; + gdcm::Attribute<0x0028,0x0701> a00280701; (void)a00280701; + gdcm::Attribute<0x0028,0x0702> a00280702; (void)a00280702; + gdcm::Attribute<0x0028,0x0710> a00280710; (void)a00280710; + gdcm::Attribute<0x0028,0x0720> a00280720; (void)a00280720; + gdcm::Attribute<0x0028,0x0721> a00280721; (void)a00280721; + gdcm::Attribute<0x0028,0x0722> a00280722; (void)a00280722; + gdcm::Attribute<0x0028,0x0730> a00280730; (void)a00280730; + gdcm::Attribute<0x0028,0x0740> a00280740; (void)a00280740; + gdcm::Attribute<0x0028,0x0a02> a00280a02; (void)a00280a02; + gdcm::Attribute<0x0028,0x0a04> a00280a04; (void)a00280a04; + gdcm::Attribute<0x0028,0x1040> a00281040; (void)a00281040; + gdcm::Attribute<0x0028,0x1041> a00281041; (void)a00281041; + gdcm::Attribute<0x0028,0x1050> a00281050; (void)a00281050; + gdcm::Attribute<0x0028,0x1051> a00281051; (void)a00281051; + gdcm::Attribute<0x0028,0x1052> a00281052; (void)a00281052; + gdcm::Attribute<0x0028,0x1053> a00281053; (void)a00281053; + gdcm::Attribute<0x0028,0x1054> a00281054; (void)a00281054; + gdcm::Attribute<0x0028,0x1055> a00281055; (void)a00281055; + gdcm::Attribute<0x0028,0x1056> a00281056; (void)a00281056; + gdcm::Attribute<0x0028,0x1080> a00281080; (void)a00281080; + gdcm::Attribute<0x0028,0x1090> a00281090; (void)a00281090; + gdcm::Attribute<0x0028,0x1199> a00281199; (void)a00281199; + gdcm::Attribute<0x0028,0x1201> a00281201; (void)a00281201; + gdcm::Attribute<0x0028,0x1202> a00281202; (void)a00281202; + gdcm::Attribute<0x0028,0x1203> a00281203; (void)a00281203; + gdcm::Attribute<0x0028,0x1211> a00281211; (void)a00281211; + gdcm::Attribute<0x0028,0x1212> a00281212; (void)a00281212; + gdcm::Attribute<0x0028,0x1213> a00281213; (void)a00281213; + gdcm::Attribute<0x0028,0x1214> a00281214; (void)a00281214; + gdcm::Attribute<0x0028,0x1221> a00281221; (void)a00281221; + gdcm::Attribute<0x0028,0x1222> a00281222; (void)a00281222; + gdcm::Attribute<0x0028,0x1223> a00281223; (void)a00281223; + gdcm::Attribute<0x0028,0x1300> a00281300; (void)a00281300; + gdcm::Attribute<0x0028,0x1350> a00281350; (void)a00281350; + gdcm::Attribute<0x0028,0x1351> a00281351; (void)a00281351; + gdcm::Attribute<0x0028,0x1352> a00281352; (void)a00281352; + gdcm::Attribute<0x0028,0x135a> a0028135a; (void)a0028135a; + gdcm::Attribute<0x0028,0x2000> a00282000; (void)a00282000; + gdcm::Attribute<0x0028,0x2110> a00282110; (void)a00282110; + gdcm::Attribute<0x0028,0x2112> a00282112; (void)a00282112; + gdcm::Attribute<0x0028,0x2114> a00282114; (void)a00282114; + gdcm::Attribute<0x0028,0x3000> a00283000; (void)a00283000; + gdcm::Attribute<0x0028,0x3003> a00283003; (void)a00283003; + gdcm::Attribute<0x0028,0x3004> a00283004; (void)a00283004; + gdcm::Attribute<0x0028,0x3010> a00283010; (void)a00283010; + gdcm::Attribute<0x0028,0x3110> a00283110; (void)a00283110; + gdcm::Attribute<0x0028,0x4000> a00284000; (void)a00284000; + gdcm::Attribute<0x0028,0x5000> a00285000; (void)a00285000; + gdcm::Attribute<0x0028,0x6010> a00286010; (void)a00286010; + gdcm::Attribute<0x0028,0x6020> a00286020; (void)a00286020; + gdcm::Attribute<0x0028,0x6022> a00286022; (void)a00286022; + gdcm::Attribute<0x0028,0x6023> a00286023; (void)a00286023; + gdcm::Attribute<0x0028,0x6030> a00286030; (void)a00286030; + gdcm::Attribute<0x0028,0x6040> a00286040; (void)a00286040; + gdcm::Attribute<0x0028,0x6100> a00286100; (void)a00286100; + gdcm::Attribute<0x0028,0x6101> a00286101; (void)a00286101; + gdcm::Attribute<0x0028,0x6102> a00286102; (void)a00286102; + gdcm::Attribute<0x0028,0x6110> a00286110; (void)a00286110; + gdcm::Attribute<0x0028,0x6112> a00286112; (void)a00286112; + gdcm::Attribute<0x0028,0x6114> a00286114; (void)a00286114; + gdcm::Attribute<0x0028,0x6120> a00286120; (void)a00286120; + gdcm::Attribute<0x0028,0x6190> a00286190; (void)a00286190; + gdcm::Attribute<0x0028,0x7fe0> a00287fe0; (void)a00287fe0; + gdcm::Attribute<0x0028,0x9001> a00289001; (void)a00289001; + gdcm::Attribute<0x0028,0x9002> a00289002; (void)a00289002; + gdcm::Attribute<0x0028,0x9003> a00289003; (void)a00289003; + gdcm::Attribute<0x0028,0x9099> a00289099; (void)a00289099; + gdcm::Attribute<0x0028,0x9108> a00289108; (void)a00289108; + gdcm::Attribute<0x0028,0x9110> a00289110; (void)a00289110; + gdcm::Attribute<0x0028,0x9132> a00289132; (void)a00289132; + gdcm::Attribute<0x0028,0x9145> a00289145; (void)a00289145; + gdcm::Attribute<0x0028,0x9235> a00289235; (void)a00289235; + gdcm::Attribute<0x0028,0x9411> a00289411; (void)a00289411; + gdcm::Attribute<0x0028,0x9415> a00289415; (void)a00289415; + gdcm::Attribute<0x0028,0x9416> a00289416; (void)a00289416; + gdcm::Attribute<0x0028,0x9422> a00289422; (void)a00289422; + gdcm::Attribute<0x0028,0x9443> a00289443; (void)a00289443; + gdcm::Attribute<0x0028,0x9444> a00289444; (void)a00289444; + gdcm::Attribute<0x0028,0x9445> a00289445; (void)a00289445; + gdcm::Attribute<0x0028,0x9446> a00289446; (void)a00289446; + gdcm::Attribute<0x0028,0x9454> a00289454; (void)a00289454; + gdcm::Attribute<0x0028,0x9474> a00289474; (void)a00289474; + gdcm::Attribute<0x0028,0x9520> a00289520; (void)a00289520; + gdcm::Attribute<0x0028,0x9537> a00289537; (void)a00289537; + gdcm::Attribute<0x0032,0x000a> a0032000a; (void)a0032000a; + gdcm::Attribute<0x0032,0x000c> a0032000c; (void)a0032000c; + gdcm::Attribute<0x0032,0x0012> a00320012; (void)a00320012; + gdcm::Attribute<0x0032,0x0032> a00320032; (void)a00320032; + gdcm::Attribute<0x0032,0x0033> a00320033; (void)a00320033; + gdcm::Attribute<0x0032,0x0034> a00320034; (void)a00320034; + gdcm::Attribute<0x0032,0x0035> a00320035; (void)a00320035; + gdcm::Attribute<0x0032,0x1000> a00321000; (void)a00321000; + gdcm::Attribute<0x0032,0x1001> a00321001; (void)a00321001; + gdcm::Attribute<0x0032,0x1010> a00321010; (void)a00321010; + gdcm::Attribute<0x0032,0x1011> a00321011; (void)a00321011; + gdcm::Attribute<0x0032,0x1020> a00321020; (void)a00321020; + gdcm::Attribute<0x0032,0x1021> a00321021; (void)a00321021; + gdcm::Attribute<0x0032,0x1030> a00321030; (void)a00321030; + gdcm::Attribute<0x0032,0x1031> a00321031; (void)a00321031; + gdcm::Attribute<0x0032,0x1032> a00321032; (void)a00321032; + gdcm::Attribute<0x0032,0x1033> a00321033; (void)a00321033; + gdcm::Attribute<0x0032,0x1040> a00321040; (void)a00321040; + gdcm::Attribute<0x0032,0x1041> a00321041; (void)a00321041; + gdcm::Attribute<0x0032,0x1050> a00321050; (void)a00321050; + gdcm::Attribute<0x0032,0x1051> a00321051; (void)a00321051; + gdcm::Attribute<0x0032,0x1055> a00321055; (void)a00321055; + gdcm::Attribute<0x0032,0x1060> a00321060; (void)a00321060; + gdcm::Attribute<0x0032,0x1064> a00321064; (void)a00321064; + gdcm::Attribute<0x0032,0x1070> a00321070; (void)a00321070; + gdcm::Attribute<0x0032,0x4000> a00324000; (void)a00324000; + gdcm::Attribute<0x0038,0x0004> a00380004; (void)a00380004; + gdcm::Attribute<0x0038,0x0008> a00380008; (void)a00380008; + gdcm::Attribute<0x0038,0x0010> a00380010; (void)a00380010; + gdcm::Attribute<0x0038,0x0011> a00380011; (void)a00380011; + gdcm::Attribute<0x0038,0x0016> a00380016; (void)a00380016; + gdcm::Attribute<0x0038,0x001a> a0038001a; (void)a0038001a; + gdcm::Attribute<0x0038,0x001b> a0038001b; (void)a0038001b; + gdcm::Attribute<0x0038,0x001c> a0038001c; (void)a0038001c; + gdcm::Attribute<0x0038,0x001d> a0038001d; (void)a0038001d; + gdcm::Attribute<0x0038,0x001e> a0038001e; (void)a0038001e; + gdcm::Attribute<0x0038,0x0020> a00380020; (void)a00380020; + gdcm::Attribute<0x0038,0x0021> a00380021; (void)a00380021; + gdcm::Attribute<0x0038,0x0030> a00380030; (void)a00380030; + gdcm::Attribute<0x0038,0x0032> a00380032; (void)a00380032; + gdcm::Attribute<0x0038,0x0040> a00380040; (void)a00380040; + gdcm::Attribute<0x0038,0x0044> a00380044; (void)a00380044; + gdcm::Attribute<0x0038,0x0050> a00380050; (void)a00380050; + gdcm::Attribute<0x0038,0x0060> a00380060; (void)a00380060; + gdcm::Attribute<0x0038,0x0061> a00380061; (void)a00380061; + gdcm::Attribute<0x0038,0x0062> a00380062; (void)a00380062; + gdcm::Attribute<0x0038,0x0100> a00380100; (void)a00380100; + gdcm::Attribute<0x0038,0x0300> a00380300; (void)a00380300; + gdcm::Attribute<0x0038,0x0400> a00380400; (void)a00380400; + gdcm::Attribute<0x0038,0x0500> a00380500; (void)a00380500; + gdcm::Attribute<0x0038,0x0502> a00380502; (void)a00380502; + gdcm::Attribute<0x0038,0x4000> a00384000; (void)a00384000; + gdcm::Attribute<0x003a,0x0004> a003a0004; (void)a003a0004; + gdcm::Attribute<0x003a,0x0005> a003a0005; (void)a003a0005; + gdcm::Attribute<0x003a,0x0010> a003a0010; (void)a003a0010; + gdcm::Attribute<0x003a,0x001a> a003a001a; (void)a003a001a; + gdcm::Attribute<0x003a,0x0020> a003a0020; (void)a003a0020; + gdcm::Attribute<0x003a,0x0200> a003a0200; (void)a003a0200; + gdcm::Attribute<0x003a,0x0202> a003a0202; (void)a003a0202; + gdcm::Attribute<0x003a,0x0203> a003a0203; (void)a003a0203; + gdcm::Attribute<0x003a,0x0205> a003a0205; (void)a003a0205; + gdcm::Attribute<0x003a,0x0208> a003a0208; (void)a003a0208; + gdcm::Attribute<0x003a,0x0209> a003a0209; (void)a003a0209; + gdcm::Attribute<0x003a,0x020a> a003a020a; (void)a003a020a; + gdcm::Attribute<0x003a,0x020c> a003a020c; (void)a003a020c; + gdcm::Attribute<0x003a,0x0210> a003a0210; (void)a003a0210; + gdcm::Attribute<0x003a,0x0211> a003a0211; (void)a003a0211; + gdcm::Attribute<0x003a,0x0212> a003a0212; (void)a003a0212; + gdcm::Attribute<0x003a,0x0213> a003a0213; (void)a003a0213; + gdcm::Attribute<0x003a,0x0214> a003a0214; (void)a003a0214; + gdcm::Attribute<0x003a,0x0215> a003a0215; (void)a003a0215; + gdcm::Attribute<0x003a,0x0218> a003a0218; (void)a003a0218; + gdcm::Attribute<0x003a,0x021a> a003a021a; (void)a003a021a; + gdcm::Attribute<0x003a,0x0220> a003a0220; (void)a003a0220; + gdcm::Attribute<0x003a,0x0221> a003a0221; (void)a003a0221; + gdcm::Attribute<0x003a,0x0222> a003a0222; (void)a003a0222; + gdcm::Attribute<0x003a,0x0223> a003a0223; (void)a003a0223; + gdcm::Attribute<0x003a,0x0230> a003a0230; (void)a003a0230; + gdcm::Attribute<0x003a,0x0231> a003a0231; (void)a003a0231; + gdcm::Attribute<0x003a,0x0240> a003a0240; (void)a003a0240; + gdcm::Attribute<0x003a,0x0241> a003a0241; (void)a003a0241; + gdcm::Attribute<0x003a,0x0242> a003a0242; (void)a003a0242; + gdcm::Attribute<0x003a,0x0244> a003a0244; (void)a003a0244; + gdcm::Attribute<0x003a,0x0245> a003a0245; (void)a003a0245; + gdcm::Attribute<0x003a,0x0246> a003a0246; (void)a003a0246; + gdcm::Attribute<0x003a,0x0247> a003a0247; (void)a003a0247; + gdcm::Attribute<0x003a,0x0248> a003a0248; (void)a003a0248; + gdcm::Attribute<0x003a,0x0300> a003a0300; (void)a003a0300; + gdcm::Attribute<0x003a,0x0301> a003a0301; (void)a003a0301; + gdcm::Attribute<0x003a,0x0302> a003a0302; (void)a003a0302; + gdcm::Attribute<0x0040,0x0001> a00400001; (void)a00400001; + gdcm::Attribute<0x0040,0x0002> a00400002; (void)a00400002; + gdcm::Attribute<0x0040,0x0003> a00400003; (void)a00400003; + gdcm::Attribute<0x0040,0x0004> a00400004; (void)a00400004; + gdcm::Attribute<0x0040,0x0005> a00400005; (void)a00400005; + gdcm::Attribute<0x0040,0x0006> a00400006; (void)a00400006; + gdcm::Attribute<0x0040,0x0007> a00400007; (void)a00400007; + gdcm::Attribute<0x0040,0x0008> a00400008; (void)a00400008; + gdcm::Attribute<0x0040,0x0009> a00400009; (void)a00400009; + gdcm::Attribute<0x0040,0x000a> a0040000a; (void)a0040000a; + gdcm::Attribute<0x0040,0x000b> a0040000b; (void)a0040000b; + gdcm::Attribute<0x0040,0x0010> a00400010; (void)a00400010; + gdcm::Attribute<0x0040,0x0011> a00400011; (void)a00400011; + gdcm::Attribute<0x0040,0x0012> a00400012; (void)a00400012; + gdcm::Attribute<0x0040,0x0020> a00400020; (void)a00400020; + gdcm::Attribute<0x0040,0x0100> a00400100; (void)a00400100; + gdcm::Attribute<0x0040,0x0220> a00400220; (void)a00400220; + gdcm::Attribute<0x0040,0x0241> a00400241; (void)a00400241; + gdcm::Attribute<0x0040,0x0242> a00400242; (void)a00400242; + gdcm::Attribute<0x0040,0x0243> a00400243; (void)a00400243; + gdcm::Attribute<0x0040,0x0244> a00400244; (void)a00400244; + gdcm::Attribute<0x0040,0x0245> a00400245; (void)a00400245; + gdcm::Attribute<0x0040,0x0250> a00400250; (void)a00400250; + gdcm::Attribute<0x0040,0x0251> a00400251; (void)a00400251; + gdcm::Attribute<0x0040,0x0252> a00400252; (void)a00400252; + gdcm::Attribute<0x0040,0x0253> a00400253; (void)a00400253; + gdcm::Attribute<0x0040,0x0254> a00400254; (void)a00400254; + gdcm::Attribute<0x0040,0x0255> a00400255; (void)a00400255; + gdcm::Attribute<0x0040,0x0260> a00400260; (void)a00400260; + gdcm::Attribute<0x0040,0x0270> a00400270; (void)a00400270; + gdcm::Attribute<0x0040,0x0275> a00400275; (void)a00400275; + gdcm::Attribute<0x0040,0x0280> a00400280; (void)a00400280; + gdcm::Attribute<0x0040,0x0281> a00400281; (void)a00400281; + gdcm::Attribute<0x0040,0x0293> a00400293; (void)a00400293; + gdcm::Attribute<0x0040,0x0294> a00400294; (void)a00400294; + gdcm::Attribute<0x0040,0x0295> a00400295; (void)a00400295; + gdcm::Attribute<0x0040,0x0296> a00400296; (void)a00400296; + gdcm::Attribute<0x0040,0x0300> a00400300; (void)a00400300; + gdcm::Attribute<0x0040,0x0301> a00400301; (void)a00400301; + gdcm::Attribute<0x0040,0x0302> a00400302; (void)a00400302; + gdcm::Attribute<0x0040,0x0306> a00400306; (void)a00400306; + gdcm::Attribute<0x0040,0x0307> a00400307; (void)a00400307; + gdcm::Attribute<0x0040,0x030e> a0040030e; (void)a0040030e; + gdcm::Attribute<0x0040,0x0310> a00400310; (void)a00400310; + gdcm::Attribute<0x0040,0x0312> a00400312; (void)a00400312; + gdcm::Attribute<0x0040,0x0314> a00400314; (void)a00400314; + gdcm::Attribute<0x0040,0x0316> a00400316; (void)a00400316; + gdcm::Attribute<0x0040,0x0318> a00400318; (void)a00400318; + gdcm::Attribute<0x0040,0x0320> a00400320; (void)a00400320; + gdcm::Attribute<0x0040,0x0321> a00400321; (void)a00400321; + gdcm::Attribute<0x0040,0x0324> a00400324; (void)a00400324; + gdcm::Attribute<0x0040,0x0330> a00400330; (void)a00400330; + gdcm::Attribute<0x0040,0x0340> a00400340; (void)a00400340; + gdcm::Attribute<0x0040,0x0400> a00400400; (void)a00400400; + gdcm::Attribute<0x0040,0x0440> a00400440; (void)a00400440; + gdcm::Attribute<0x0040,0x0441> a00400441; (void)a00400441; + gdcm::Attribute<0x0040,0x050a> a0040050a; (void)a0040050a; + gdcm::Attribute<0x0040,0x0550> a00400550; (void)a00400550; + gdcm::Attribute<0x0040,0x0551> a00400551; (void)a00400551; + gdcm::Attribute<0x0040,0x0552> a00400552; (void)a00400552; + gdcm::Attribute<0x0040,0x0553> a00400553; (void)a00400553; + gdcm::Attribute<0x0040,0x0555> a00400555; (void)a00400555; + gdcm::Attribute<0x0040,0x0556> a00400556; (void)a00400556; + gdcm::Attribute<0x0040,0x059a> a0040059a; (void)a0040059a; + gdcm::Attribute<0x0040,0x06fa> a004006fa; (void)a004006fa; + gdcm::Attribute<0x0040,0x071a> a0040071a; (void)a0040071a; + gdcm::Attribute<0x0040,0x072a> a0040072a; (void)a0040072a; + gdcm::Attribute<0x0040,0x073a> a0040073a; (void)a0040073a; + gdcm::Attribute<0x0040,0x074a> a0040074a; (void)a0040074a; + gdcm::Attribute<0x0040,0x08d8> a004008d8; (void)a004008d8; + gdcm::Attribute<0x0040,0x08da> a004008da; (void)a004008da; + gdcm::Attribute<0x0040,0x08ea> a004008ea; (void)a004008ea; + gdcm::Attribute<0x0040,0x09f8> a004009f8; (void)a004009f8; + gdcm::Attribute<0x0040,0x1001> a00401001; (void)a00401001; + gdcm::Attribute<0x0040,0x1002> a00401002; (void)a00401002; + gdcm::Attribute<0x0040,0x1003> a00401003; (void)a00401003; + gdcm::Attribute<0x0040,0x1004> a00401004; (void)a00401004; + gdcm::Attribute<0x0040,0x1005> a00401005; (void)a00401005; + gdcm::Attribute<0x0040,0x1006> a00401006; (void)a00401006; + gdcm::Attribute<0x0040,0x1007> a00401007; (void)a00401007; + gdcm::Attribute<0x0040,0x1008> a00401008; (void)a00401008; + gdcm::Attribute<0x0040,0x1009> a00401009; (void)a00401009; + gdcm::Attribute<0x0040,0x100a> a0040100a; (void)a0040100a; + gdcm::Attribute<0x0040,0x1010> a00401010; (void)a00401010; + gdcm::Attribute<0x0040,0x1011> a00401011; (void)a00401011; + gdcm::Attribute<0x0040,0x1101> a00401101; (void)a00401101; + gdcm::Attribute<0x0040,0x1102> a00401102; (void)a00401102; + gdcm::Attribute<0x0040,0x1103> a00401103; (void)a00401103; + gdcm::Attribute<0x0040,0x1400> a00401400; (void)a00401400; + gdcm::Attribute<0x0040,0x2001> a00402001; (void)a00402001; + gdcm::Attribute<0x0040,0x2004> a00402004; (void)a00402004; + gdcm::Attribute<0x0040,0x2005> a00402005; (void)a00402005; + gdcm::Attribute<0x0040,0x2006> a00402006; (void)a00402006; + gdcm::Attribute<0x0040,0x2007> a00402007; (void)a00402007; + gdcm::Attribute<0x0040,0x2008> a00402008; (void)a00402008; + gdcm::Attribute<0x0040,0x2009> a00402009; (void)a00402009; + gdcm::Attribute<0x0040,0x2010> a00402010; (void)a00402010; + gdcm::Attribute<0x0040,0x2016> a00402016; (void)a00402016; + gdcm::Attribute<0x0040,0x2017> a00402017; (void)a00402017; + gdcm::Attribute<0x0040,0x2400> a00402400; (void)a00402400; + gdcm::Attribute<0x0040,0x3001> a00403001; (void)a00403001; + gdcm::Attribute<0x0040,0x4001> a00404001; (void)a00404001; + gdcm::Attribute<0x0040,0x4002> a00404002; (void)a00404002; + gdcm::Attribute<0x0040,0x4003> a00404003; (void)a00404003; + gdcm::Attribute<0x0040,0x4004> a00404004; (void)a00404004; + gdcm::Attribute<0x0040,0x4005> a00404005; (void)a00404005; + gdcm::Attribute<0x0040,0x4006> a00404006; (void)a00404006; + gdcm::Attribute<0x0040,0x4007> a00404007; (void)a00404007; + gdcm::Attribute<0x0040,0x4009> a00404009; (void)a00404009; + gdcm::Attribute<0x0040,0x4010> a00404010; (void)a00404010; + gdcm::Attribute<0x0040,0x4011> a00404011; (void)a00404011; + gdcm::Attribute<0x0040,0x4015> a00404015; (void)a00404015; + gdcm::Attribute<0x0040,0x4016> a00404016; (void)a00404016; + gdcm::Attribute<0x0040,0x4018> a00404018; (void)a00404018; + gdcm::Attribute<0x0040,0x4019> a00404019; (void)a00404019; + gdcm::Attribute<0x0040,0x4020> a00404020; (void)a00404020; + gdcm::Attribute<0x0040,0x4021> a00404021; (void)a00404021; + gdcm::Attribute<0x0040,0x4022> a00404022; (void)a00404022; + gdcm::Attribute<0x0040,0x4023> a00404023; (void)a00404023; + gdcm::Attribute<0x0040,0x4025> a00404025; (void)a00404025; + gdcm::Attribute<0x0040,0x4026> a00404026; (void)a00404026; + gdcm::Attribute<0x0040,0x4027> a00404027; (void)a00404027; + gdcm::Attribute<0x0040,0x4028> a00404028; (void)a00404028; + gdcm::Attribute<0x0040,0x4029> a00404029; (void)a00404029; + gdcm::Attribute<0x0040,0x4030> a00404030; (void)a00404030; + gdcm::Attribute<0x0040,0x4031> a00404031; (void)a00404031; + gdcm::Attribute<0x0040,0x4032> a00404032; (void)a00404032; + gdcm::Attribute<0x0040,0x4033> a00404033; (void)a00404033; + gdcm::Attribute<0x0040,0x4034> a00404034; (void)a00404034; + gdcm::Attribute<0x0040,0x4035> a00404035; (void)a00404035; + gdcm::Attribute<0x0040,0x4036> a00404036; (void)a00404036; + gdcm::Attribute<0x0040,0x4037> a00404037; (void)a00404037; + gdcm::Attribute<0x0040,0x8302> a00408302; (void)a00408302; + gdcm::Attribute<0x0040,0x9094> a00409094; (void)a00409094; + gdcm::Attribute<0x0040,0x9096> a00409096; (void)a00409096; + gdcm::Attribute<0x0040,0x9098> a00409098; (void)a00409098; + gdcm::Attribute<0x0040,0x9210> a00409210; (void)a00409210; + gdcm::Attribute<0x0040,0x9212> a00409212; (void)a00409212; + gdcm::Attribute<0x0040,0x9224> a00409224; (void)a00409224; + gdcm::Attribute<0x0040,0x9225> a00409225; (void)a00409225; + gdcm::Attribute<0x0040,0xa010> a0040a010; (void)a0040a010; + gdcm::Attribute<0x0040,0xa027> a0040a027; (void)a0040a027; + gdcm::Attribute<0x0040,0xa030> a0040a030; (void)a0040a030; + gdcm::Attribute<0x0040,0xa032> a0040a032; (void)a0040a032; + gdcm::Attribute<0x0040,0xa040> a0040a040; (void)a0040a040; + gdcm::Attribute<0x0040,0xa043> a0040a043; (void)a0040a043; + gdcm::Attribute<0x0040,0xa050> a0040a050; (void)a0040a050; + gdcm::Attribute<0x0040,0xa073> a0040a073; (void)a0040a073; + gdcm::Attribute<0x0040,0xa075> a0040a075; (void)a0040a075; + gdcm::Attribute<0x0040,0xa078> a0040a078; (void)a0040a078; + gdcm::Attribute<0x0040,0xa07a> a0040a07a; (void)a0040a07a; + gdcm::Attribute<0x0040,0xa07c> a0040a07c; (void)a0040a07c; + gdcm::Attribute<0x0040,0xa080> a0040a080; (void)a0040a080; + gdcm::Attribute<0x0040,0xa082> a0040a082; (void)a0040a082; + gdcm::Attribute<0x0040,0xa084> a0040a084; (void)a0040a084; + gdcm::Attribute<0x0040,0xa088> a0040a088; (void)a0040a088; + gdcm::Attribute<0x0040,0xa090> a0040a090; (void)a0040a090; + gdcm::Attribute<0x0040,0xa0b0> a0040a0b0; (void)a0040a0b0; + gdcm::Attribute<0x0040,0xa120> a0040a120; (void)a0040a120; + gdcm::Attribute<0x0040,0xa121> a0040a121; (void)a0040a121; + gdcm::Attribute<0x0040,0xa122> a0040a122; (void)a0040a122; + gdcm::Attribute<0x0040,0xa123> a0040a123; (void)a0040a123; + gdcm::Attribute<0x0040,0xa124> a0040a124; (void)a0040a124; + gdcm::Attribute<0x0040,0xa130> a0040a130; (void)a0040a130; + gdcm::Attribute<0x0040,0xa132> a0040a132; (void)a0040a132; + gdcm::Attribute<0x0040,0xa136> a0040a136; (void)a0040a136; + gdcm::Attribute<0x0040,0xa138> a0040a138; (void)a0040a138; + gdcm::Attribute<0x0040,0xa13a> a0040a13a; (void)a0040a13a; + gdcm::Attribute<0x0040,0xa160> a0040a160; (void)a0040a160; + gdcm::Attribute<0x0040,0xa168> a0040a168; (void)a0040a168; + gdcm::Attribute<0x0040,0xa170> a0040a170; (void)a0040a170; + gdcm::Attribute<0x0040,0xa180> a0040a180; (void)a0040a180; + gdcm::Attribute<0x0040,0xa195> a0040a195; (void)a0040a195; + gdcm::Attribute<0x0040,0xa300> a0040a300; (void)a0040a300; + gdcm::Attribute<0x0040,0xa301> a0040a301; (void)a0040a301; + gdcm::Attribute<0x0040,0xa30a> a0040a30a; (void)a0040a30a; + gdcm::Attribute<0x0040,0xa353> a0040a353; (void)a0040a353; + gdcm::Attribute<0x0040,0xa354> a0040a354; (void)a0040a354; + gdcm::Attribute<0x0040,0xa360> a0040a360; (void)a0040a360; + gdcm::Attribute<0x0040,0xa370> a0040a370; (void)a0040a370; + gdcm::Attribute<0x0040,0xa372> a0040a372; (void)a0040a372; + gdcm::Attribute<0x0040,0xa375> a0040a375; (void)a0040a375; + gdcm::Attribute<0x0040,0xa385> a0040a385; (void)a0040a385; + gdcm::Attribute<0x0040,0xa390> a0040a390; (void)a0040a390; + gdcm::Attribute<0x0040,0xa491> a0040a491; (void)a0040a491; + gdcm::Attribute<0x0040,0xa492> a0040a492; (void)a0040a492; + gdcm::Attribute<0x0040,0xa493> a0040a493; (void)a0040a493; + gdcm::Attribute<0x0040,0xa494> a0040a494; (void)a0040a494; + gdcm::Attribute<0x0040,0xa504> a0040a504; (void)a0040a504; + gdcm::Attribute<0x0040,0xa525> a0040a525; (void)a0040a525; + gdcm::Attribute<0x0040,0xa730> a0040a730; (void)a0040a730; + gdcm::Attribute<0x0040,0xb020> a0040b020; (void)a0040b020; + gdcm::Attribute<0x0040,0xdb00> a0040db00; (void)a0040db00; + gdcm::Attribute<0x0040,0xdb06> a0040db06; (void)a0040db06; + gdcm::Attribute<0x0040,0xdb07> a0040db07; (void)a0040db07; + gdcm::Attribute<0x0040,0xdb0b> a0040db0b; (void)a0040db0b; + gdcm::Attribute<0x0040,0xdb0c> a0040db0c; (void)a0040db0c; + gdcm::Attribute<0x0040,0xdb0d> a0040db0d; (void)a0040db0d; + gdcm::Attribute<0x0040,0xdb73> a0040db73; (void)a0040db73; + gdcm::Attribute<0x0040,0xe001> a0040e001; (void)a0040e001; + gdcm::Attribute<0x0040,0xe004> a0040e004; (void)a0040e004; + gdcm::Attribute<0x0040,0xe006> a0040e006; (void)a0040e006; + gdcm::Attribute<0x0040,0xe010> a0040e010; (void)a0040e010; + gdcm::Attribute<0x0042,0x0010> a00420010; (void)a00420010; + gdcm::Attribute<0x0042,0x0011> a00420011; (void)a00420011; + gdcm::Attribute<0x0042,0x0012> a00420012; (void)a00420012; + gdcm::Attribute<0x0042,0x0013> a00420013; (void)a00420013; + gdcm::Attribute<0x0042,0x0014> a00420014; (void)a00420014; + gdcm::Attribute<0x0044,0x0001> a00440001; (void)a00440001; + gdcm::Attribute<0x0044,0x0002> a00440002; (void)a00440002; + gdcm::Attribute<0x0044,0x0003> a00440003; (void)a00440003; + gdcm::Attribute<0x0044,0x0004> a00440004; (void)a00440004; + gdcm::Attribute<0x0044,0x0007> a00440007; (void)a00440007; + gdcm::Attribute<0x0044,0x0008> a00440008; (void)a00440008; + gdcm::Attribute<0x0044,0x0009> a00440009; (void)a00440009; + gdcm::Attribute<0x0044,0x000a> a0044000a; (void)a0044000a; + gdcm::Attribute<0x0044,0x000b> a0044000b; (void)a0044000b; + gdcm::Attribute<0x0044,0x0010> a00440010; (void)a00440010; + gdcm::Attribute<0x0044,0x0011> a00440011; (void)a00440011; + gdcm::Attribute<0x0044,0x0012> a00440012; (void)a00440012; + gdcm::Attribute<0x0044,0x0013> a00440013; (void)a00440013; + gdcm::Attribute<0x0044,0x0019> a00440019; (void)a00440019; + gdcm::Attribute<0x0050,0x0004> a00500004; (void)a00500004; + gdcm::Attribute<0x0050,0x0010> a00500010; (void)a00500010; + gdcm::Attribute<0x0050,0x0014> a00500014; (void)a00500014; + gdcm::Attribute<0x0050,0x0016> a00500016; (void)a00500016; + gdcm::Attribute<0x0050,0x0017> a00500017; (void)a00500017; + gdcm::Attribute<0x0050,0x0018> a00500018; (void)a00500018; + gdcm::Attribute<0x0050,0x0019> a00500019; (void)a00500019; + gdcm::Attribute<0x0050,0x0020> a00500020; (void)a00500020; + gdcm::Attribute<0x0054,0x0010> a00540010; (void)a00540010; + gdcm::Attribute<0x0054,0x0011> a00540011; (void)a00540011; + gdcm::Attribute<0x0054,0x0012> a00540012; (void)a00540012; + gdcm::Attribute<0x0054,0x0013> a00540013; (void)a00540013; + gdcm::Attribute<0x0054,0x0014> a00540014; (void)a00540014; + gdcm::Attribute<0x0054,0x0015> a00540015; (void)a00540015; + gdcm::Attribute<0x0054,0x0016> a00540016; (void)a00540016; + gdcm::Attribute<0x0054,0x0017> a00540017; (void)a00540017; + gdcm::Attribute<0x0054,0x0018> a00540018; (void)a00540018; + gdcm::Attribute<0x0054,0x0020> a00540020; (void)a00540020; + gdcm::Attribute<0x0054,0x0021> a00540021; (void)a00540021; + gdcm::Attribute<0x0054,0x0022> a00540022; (void)a00540022; + gdcm::Attribute<0x0054,0x0030> a00540030; (void)a00540030; + gdcm::Attribute<0x0054,0x0031> a00540031; (void)a00540031; + gdcm::Attribute<0x0054,0x0032> a00540032; (void)a00540032; + gdcm::Attribute<0x0054,0x0033> a00540033; (void)a00540033; + gdcm::Attribute<0x0054,0x0036> a00540036; (void)a00540036; + gdcm::Attribute<0x0054,0x0038> a00540038; (void)a00540038; + gdcm::Attribute<0x0054,0x0039> a00540039; (void)a00540039; + gdcm::Attribute<0x0054,0x0050> a00540050; (void)a00540050; + gdcm::Attribute<0x0054,0x0051> a00540051; (void)a00540051; + gdcm::Attribute<0x0054,0x0052> a00540052; (void)a00540052; + gdcm::Attribute<0x0054,0x0053> a00540053; (void)a00540053; + gdcm::Attribute<0x0054,0x0060> a00540060; (void)a00540060; + gdcm::Attribute<0x0054,0x0061> a00540061; (void)a00540061; + gdcm::Attribute<0x0054,0x0062> a00540062; (void)a00540062; + gdcm::Attribute<0x0054,0x0063> a00540063; (void)a00540063; + gdcm::Attribute<0x0054,0x0070> a00540070; (void)a00540070; + gdcm::Attribute<0x0054,0x0071> a00540071; (void)a00540071; + gdcm::Attribute<0x0054,0x0072> a00540072; (void)a00540072; + gdcm::Attribute<0x0054,0x0073> a00540073; (void)a00540073; + gdcm::Attribute<0x0054,0x0080> a00540080; (void)a00540080; + gdcm::Attribute<0x0054,0x0081> a00540081; (void)a00540081; + gdcm::Attribute<0x0054,0x0090> a00540090; (void)a00540090; + gdcm::Attribute<0x0054,0x0100> a00540100; (void)a00540100; + gdcm::Attribute<0x0054,0x0101> a00540101; (void)a00540101; + gdcm::Attribute<0x0054,0x0200> a00540200; (void)a00540200; + gdcm::Attribute<0x0054,0x0202> a00540202; (void)a00540202; + gdcm::Attribute<0x0054,0x0210> a00540210; (void)a00540210; + gdcm::Attribute<0x0054,0x0211> a00540211; (void)a00540211; + gdcm::Attribute<0x0054,0x0220> a00540220; (void)a00540220; + gdcm::Attribute<0x0054,0x0222> a00540222; (void)a00540222; + gdcm::Attribute<0x0054,0x0300> a00540300; (void)a00540300; + gdcm::Attribute<0x0054,0x0302> a00540302; (void)a00540302; + gdcm::Attribute<0x0054,0x0304> a00540304; (void)a00540304; + gdcm::Attribute<0x0054,0x0306> a00540306; (void)a00540306; + gdcm::Attribute<0x0054,0x0308> a00540308; (void)a00540308; + gdcm::Attribute<0x0054,0x0400> a00540400; (void)a00540400; + gdcm::Attribute<0x0054,0x0410> a00540410; (void)a00540410; + gdcm::Attribute<0x0054,0x0412> a00540412; (void)a00540412; + gdcm::Attribute<0x0054,0x0414> a00540414; (void)a00540414; + gdcm::Attribute<0x0054,0x0500> a00540500; (void)a00540500; + gdcm::Attribute<0x0054,0x1000> a00541000; (void)a00541000; + gdcm::Attribute<0x0054,0x1001> a00541001; (void)a00541001; + gdcm::Attribute<0x0054,0x1002> a00541002; (void)a00541002; + gdcm::Attribute<0x0054,0x1004> a00541004; (void)a00541004; + gdcm::Attribute<0x0054,0x1100> a00541100; (void)a00541100; + gdcm::Attribute<0x0054,0x1101> a00541101; (void)a00541101; + gdcm::Attribute<0x0054,0x1102> a00541102; (void)a00541102; + gdcm::Attribute<0x0054,0x1103> a00541103; (void)a00541103; + gdcm::Attribute<0x0054,0x1104> a00541104; (void)a00541104; + gdcm::Attribute<0x0054,0x1105> a00541105; (void)a00541105; + gdcm::Attribute<0x0054,0x1200> a00541200; (void)a00541200; + gdcm::Attribute<0x0054,0x1201> a00541201; (void)a00541201; + gdcm::Attribute<0x0054,0x1202> a00541202; (void)a00541202; + gdcm::Attribute<0x0054,0x1203> a00541203; (void)a00541203; + gdcm::Attribute<0x0054,0x1210> a00541210; (void)a00541210; + gdcm::Attribute<0x0054,0x1220> a00541220; (void)a00541220; + gdcm::Attribute<0x0054,0x1300> a00541300; (void)a00541300; + gdcm::Attribute<0x0054,0x1310> a00541310; (void)a00541310; + gdcm::Attribute<0x0054,0x1311> a00541311; (void)a00541311; + gdcm::Attribute<0x0054,0x1320> a00541320; (void)a00541320; + gdcm::Attribute<0x0054,0x1321> a00541321; (void)a00541321; + gdcm::Attribute<0x0054,0x1322> a00541322; (void)a00541322; + gdcm::Attribute<0x0054,0x1323> a00541323; (void)a00541323; + gdcm::Attribute<0x0054,0x1324> a00541324; (void)a00541324; + gdcm::Attribute<0x0054,0x1330> a00541330; (void)a00541330; + gdcm::Attribute<0x0054,0x1400> a00541400; (void)a00541400; + gdcm::Attribute<0x0054,0x1401> a00541401; (void)a00541401; + gdcm::Attribute<0x0060,0x3000> a00603000; (void)a00603000; + gdcm::Attribute<0x0060,0x3002> a00603002; (void)a00603002; + gdcm::Attribute<0x0060,0x3008> a00603008; (void)a00603008; + gdcm::Attribute<0x0060,0x3010> a00603010; (void)a00603010; + gdcm::Attribute<0x0060,0x3020> a00603020; (void)a00603020; + gdcm::Attribute<0x0062,0x0001> a00620001; (void)a00620001; + gdcm::Attribute<0x0062,0x0002> a00620002; (void)a00620002; + gdcm::Attribute<0x0062,0x0003> a00620003; (void)a00620003; + gdcm::Attribute<0x0062,0x0004> a00620004; (void)a00620004; + gdcm::Attribute<0x0062,0x0005> a00620005; (void)a00620005; + gdcm::Attribute<0x0062,0x0006> a00620006; (void)a00620006; + gdcm::Attribute<0x0062,0x0008> a00620008; (void)a00620008; + gdcm::Attribute<0x0062,0x0009> a00620009; (void)a00620009; + gdcm::Attribute<0x0062,0x000a> a0062000a; (void)a0062000a; + gdcm::Attribute<0x0062,0x000b> a0062000b; (void)a0062000b; + gdcm::Attribute<0x0062,0x000c> a0062000c; (void)a0062000c; + gdcm::Attribute<0x0062,0x000d> a0062000d; (void)a0062000d; + gdcm::Attribute<0x0062,0x000e> a0062000e; (void)a0062000e; + gdcm::Attribute<0x0062,0x000f> a0062000f; (void)a0062000f; + gdcm::Attribute<0x0062,0x0010> a00620010; (void)a00620010; + gdcm::Attribute<0x0064,0x0002> a00640002; (void)a00640002; + gdcm::Attribute<0x0064,0x0003> a00640003; (void)a00640003; + gdcm::Attribute<0x0064,0x0005> a00640005; (void)a00640005; + gdcm::Attribute<0x0064,0x0007> a00640007; (void)a00640007; + gdcm::Attribute<0x0064,0x0008> a00640008; (void)a00640008; + gdcm::Attribute<0x0064,0x0009> a00640009; (void)a00640009; + gdcm::Attribute<0x0064,0x000f> a0064000f; (void)a0064000f; + gdcm::Attribute<0x0064,0x0010> a00640010; (void)a00640010; + gdcm::Attribute<0x0070,0x0001> a00700001; (void)a00700001; + gdcm::Attribute<0x0070,0x0002> a00700002; (void)a00700002; + gdcm::Attribute<0x0070,0x0003> a00700003; (void)a00700003; + gdcm::Attribute<0x0070,0x0004> a00700004; (void)a00700004; + gdcm::Attribute<0x0070,0x0005> a00700005; (void)a00700005; + gdcm::Attribute<0x0070,0x0006> a00700006; (void)a00700006; + gdcm::Attribute<0x0070,0x0008> a00700008; (void)a00700008; + gdcm::Attribute<0x0070,0x0009> a00700009; (void)a00700009; + gdcm::Attribute<0x0070,0x0010> a00700010; (void)a00700010; + gdcm::Attribute<0x0070,0x0011> a00700011; (void)a00700011; + gdcm::Attribute<0x0070,0x0012> a00700012; (void)a00700012; + gdcm::Attribute<0x0070,0x0014> a00700014; (void)a00700014; + gdcm::Attribute<0x0070,0x0015> a00700015; (void)a00700015; + gdcm::Attribute<0x0070,0x0020> a00700020; (void)a00700020; + gdcm::Attribute<0x0070,0x0021> a00700021; (void)a00700021; + gdcm::Attribute<0x0070,0x0022> a00700022; (void)a00700022; + gdcm::Attribute<0x0070,0x0023> a00700023; (void)a00700023; + gdcm::Attribute<0x0070,0x0024> a00700024; (void)a00700024; + gdcm::Attribute<0x0070,0x0040> a00700040; (void)a00700040; + gdcm::Attribute<0x0070,0x0041> a00700041; (void)a00700041; + gdcm::Attribute<0x0070,0x0042> a00700042; (void)a00700042; + gdcm::Attribute<0x0070,0x0050> a00700050; (void)a00700050; + gdcm::Attribute<0x0070,0x0051> a00700051; (void)a00700051; + gdcm::Attribute<0x0070,0x0052> a00700052; (void)a00700052; + gdcm::Attribute<0x0070,0x0053> a00700053; (void)a00700053; + gdcm::Attribute<0x0070,0x005a> a0070005a; (void)a0070005a; + gdcm::Attribute<0x0070,0x0060> a00700060; (void)a00700060; + gdcm::Attribute<0x0070,0x0062> a00700062; (void)a00700062; + gdcm::Attribute<0x0070,0x0066> a00700066; (void)a00700066; + gdcm::Attribute<0x0070,0x0067> a00700067; (void)a00700067; + gdcm::Attribute<0x0070,0x0068> a00700068; (void)a00700068; + gdcm::Attribute<0x0070,0x0080> a00700080; (void)a00700080; + gdcm::Attribute<0x0070,0x0081> a00700081; (void)a00700081; + gdcm::Attribute<0x0070,0x0082> a00700082; (void)a00700082; + gdcm::Attribute<0x0070,0x0083> a00700083; (void)a00700083; + gdcm::Attribute<0x0070,0x0084> a00700084; (void)a00700084; + gdcm::Attribute<0x0070,0x0086> a00700086; (void)a00700086; + gdcm::Attribute<0x0070,0x0100> a00700100; (void)a00700100; + gdcm::Attribute<0x0070,0x0101> a00700101; (void)a00700101; + gdcm::Attribute<0x0070,0x0102> a00700102; (void)a00700102; + gdcm::Attribute<0x0070,0x0103> a00700103; (void)a00700103; + gdcm::Attribute<0x0070,0x0306> a00700306; (void)a00700306; + gdcm::Attribute<0x0070,0x0308> a00700308; (void)a00700308; + gdcm::Attribute<0x0070,0x0309> a00700309; (void)a00700309; + gdcm::Attribute<0x0070,0x030a> a0070030a; (void)a0070030a; + gdcm::Attribute<0x0070,0x030c> a0070030c; (void)a0070030c; + gdcm::Attribute<0x0070,0x030d> a0070030d; (void)a0070030d; + gdcm::Attribute<0x0070,0x030f> a0070030f; (void)a0070030f; + gdcm::Attribute<0x0070,0x0310> a00700310; (void)a00700310; + gdcm::Attribute<0x0070,0x0311> a00700311; (void)a00700311; + gdcm::Attribute<0x0070,0x0312> a00700312; (void)a00700312; + gdcm::Attribute<0x0070,0x0314> a00700314; (void)a00700314; + gdcm::Attribute<0x0070,0x0318> a00700318; (void)a00700318; + gdcm::Attribute<0x0070,0x031a> a0070031a; (void)a0070031a; + gdcm::Attribute<0x0070,0x031c> a0070031c; (void)a0070031c; + gdcm::Attribute<0x0070,0x031e> a0070031e; (void)a0070031e; + gdcm::Attribute<0x0070,0x0401> a00700401; (void)a00700401; + gdcm::Attribute<0x0070,0x0402> a00700402; (void)a00700402; + gdcm::Attribute<0x0070,0x0403> a00700403; (void)a00700403; + gdcm::Attribute<0x0070,0x0404> a00700404; (void)a00700404; + gdcm::Attribute<0x0070,0x0405> a00700405; (void)a00700405; + gdcm::Attribute<0x0072,0x0002> a00720002; (void)a00720002; + gdcm::Attribute<0x0072,0x0004> a00720004; (void)a00720004; + gdcm::Attribute<0x0072,0x0006> a00720006; (void)a00720006; + gdcm::Attribute<0x0072,0x0008> a00720008; (void)a00720008; + gdcm::Attribute<0x0072,0x000a> a0072000a; (void)a0072000a; + gdcm::Attribute<0x0072,0x000c> a0072000c; (void)a0072000c; + gdcm::Attribute<0x0072,0x000e> a0072000e; (void)a0072000e; + gdcm::Attribute<0x0072,0x0010> a00720010; (void)a00720010; + gdcm::Attribute<0x0072,0x0012> a00720012; (void)a00720012; + gdcm::Attribute<0x0072,0x0014> a00720014; (void)a00720014; + gdcm::Attribute<0x0072,0x0020> a00720020; (void)a00720020; + gdcm::Attribute<0x0072,0x0022> a00720022; (void)a00720022; + gdcm::Attribute<0x0072,0x0024> a00720024; (void)a00720024; + gdcm::Attribute<0x0072,0x0026> a00720026; (void)a00720026; + gdcm::Attribute<0x0072,0x0028> a00720028; (void)a00720028; + gdcm::Attribute<0x0072,0x0030> a00720030; (void)a00720030; + gdcm::Attribute<0x0072,0x0032> a00720032; (void)a00720032; + gdcm::Attribute<0x0072,0x0034> a00720034; (void)a00720034; + gdcm::Attribute<0x0072,0x0038> a00720038; (void)a00720038; + gdcm::Attribute<0x0072,0x003a> a0072003a; (void)a0072003a; + gdcm::Attribute<0x0072,0x003c> a0072003c; (void)a0072003c; + gdcm::Attribute<0x0072,0x003e> a0072003e; (void)a0072003e; + gdcm::Attribute<0x0072,0x0040> a00720040; (void)a00720040; + gdcm::Attribute<0x0072,0x0050> a00720050; (void)a00720050; + gdcm::Attribute<0x0072,0x0052> a00720052; (void)a00720052; + gdcm::Attribute<0x0072,0x0054> a00720054; (void)a00720054; + gdcm::Attribute<0x0072,0x0056> a00720056; (void)a00720056; + gdcm::Attribute<0x0072,0x0060> a00720060; (void)a00720060; + gdcm::Attribute<0x0072,0x0062> a00720062; (void)a00720062; + gdcm::Attribute<0x0072,0x0064> a00720064; (void)a00720064; + gdcm::Attribute<0x0072,0x0066> a00720066; (void)a00720066; + gdcm::Attribute<0x0072,0x0068> a00720068; (void)a00720068; + gdcm::Attribute<0x0072,0x006a> a0072006a; (void)a0072006a; + gdcm::Attribute<0x0072,0x006c> a0072006c; (void)a0072006c; + gdcm::Attribute<0x0072,0x006e> a0072006e; (void)a0072006e; + gdcm::Attribute<0x0072,0x0070> a00720070; (void)a00720070; + gdcm::Attribute<0x0072,0x0072> a00720072; (void)a00720072; + gdcm::Attribute<0x0072,0x0074> a00720074; (void)a00720074; + gdcm::Attribute<0x0072,0x0076> a00720076; (void)a00720076; + gdcm::Attribute<0x0072,0x0078> a00720078; (void)a00720078; + gdcm::Attribute<0x0072,0x007a> a0072007a; (void)a0072007a; + gdcm::Attribute<0x0072,0x007c> a0072007c; (void)a0072007c; + gdcm::Attribute<0x0072,0x007e> a0072007e; (void)a0072007e; + gdcm::Attribute<0x0072,0x0080> a00720080; (void)a00720080; + gdcm::Attribute<0x0072,0x0100> a00720100; (void)a00720100; + gdcm::Attribute<0x0072,0x0102> a00720102; (void)a00720102; + gdcm::Attribute<0x0072,0x0104> a00720104; (void)a00720104; + gdcm::Attribute<0x0072,0x0106> a00720106; (void)a00720106; + gdcm::Attribute<0x0072,0x0108> a00720108; (void)a00720108; + gdcm::Attribute<0x0072,0x010a> a0072010a; (void)a0072010a; + gdcm::Attribute<0x0072,0x010c> a0072010c; (void)a0072010c; + gdcm::Attribute<0x0072,0x010e> a0072010e; (void)a0072010e; + gdcm::Attribute<0x0072,0x0200> a00720200; (void)a00720200; + gdcm::Attribute<0x0072,0x0202> a00720202; (void)a00720202; + gdcm::Attribute<0x0072,0x0203> a00720203; (void)a00720203; + gdcm::Attribute<0x0072,0x0204> a00720204; (void)a00720204; + gdcm::Attribute<0x0072,0x0206> a00720206; (void)a00720206; + gdcm::Attribute<0x0072,0x0208> a00720208; (void)a00720208; + gdcm::Attribute<0x0072,0x0210> a00720210; (void)a00720210; + gdcm::Attribute<0x0072,0x0212> a00720212; (void)a00720212; + gdcm::Attribute<0x0072,0x0214> a00720214; (void)a00720214; + gdcm::Attribute<0x0072,0x0216> a00720216; (void)a00720216; + gdcm::Attribute<0x0072,0x0218> a00720218; (void)a00720218; + gdcm::Attribute<0x0072,0x0300> a00720300; (void)a00720300; + gdcm::Attribute<0x0072,0x0302> a00720302; (void)a00720302; + gdcm::Attribute<0x0072,0x0304> a00720304; (void)a00720304; + gdcm::Attribute<0x0072,0x0306> a00720306; (void)a00720306; + gdcm::Attribute<0x0072,0x0308> a00720308; (void)a00720308; + gdcm::Attribute<0x0072,0x0310> a00720310; (void)a00720310; + gdcm::Attribute<0x0072,0x0312> a00720312; (void)a00720312; + gdcm::Attribute<0x0072,0x0314> a00720314; (void)a00720314; + gdcm::Attribute<0x0072,0x0316> a00720316; (void)a00720316; + gdcm::Attribute<0x0072,0x0318> a00720318; (void)a00720318; + gdcm::Attribute<0x0072,0x0320> a00720320; (void)a00720320; + gdcm::Attribute<0x0072,0x0330> a00720330; (void)a00720330; + gdcm::Attribute<0x0072,0x0400> a00720400; (void)a00720400; + gdcm::Attribute<0x0072,0x0402> a00720402; (void)a00720402; + gdcm::Attribute<0x0072,0x0404> a00720404; (void)a00720404; + gdcm::Attribute<0x0072,0x0406> a00720406; (void)a00720406; + gdcm::Attribute<0x0072,0x0500> a00720500; (void)a00720500; + gdcm::Attribute<0x0072,0x0510> a00720510; (void)a00720510; + gdcm::Attribute<0x0072,0x0512> a00720512; (void)a00720512; + gdcm::Attribute<0x0072,0x0514> a00720514; (void)a00720514; + gdcm::Attribute<0x0072,0x0516> a00720516; (void)a00720516; + gdcm::Attribute<0x0072,0x0520> a00720520; (void)a00720520; + gdcm::Attribute<0x0072,0x0600> a00720600; (void)a00720600; + gdcm::Attribute<0x0072,0x0602> a00720602; (void)a00720602; + gdcm::Attribute<0x0072,0x0604> a00720604; (void)a00720604; + gdcm::Attribute<0x0072,0x0700> a00720700; (void)a00720700; + gdcm::Attribute<0x0072,0x0702> a00720702; (void)a00720702; + gdcm::Attribute<0x0072,0x0704> a00720704; (void)a00720704; + gdcm::Attribute<0x0072,0x0706> a00720706; (void)a00720706; + gdcm::Attribute<0x0072,0x0710> a00720710; (void)a00720710; + gdcm::Attribute<0x0072,0x0712> a00720712; (void)a00720712; + gdcm::Attribute<0x0072,0x0714> a00720714; (void)a00720714; + gdcm::Attribute<0x0072,0x0716> a00720716; (void)a00720716; + gdcm::Attribute<0x0072,0x0717> a00720717; (void)a00720717; + gdcm::Attribute<0x0072,0x0718> a00720718; (void)a00720718; + gdcm::Attribute<0x0074,0x1000> a00741000; (void)a00741000; + gdcm::Attribute<0x0074,0x1002> a00741002; (void)a00741002; + gdcm::Attribute<0x0074,0x1004> a00741004; (void)a00741004; + gdcm::Attribute<0x0074,0x1006> a00741006; (void)a00741006; + gdcm::Attribute<0x0074,0x1008> a00741008; (void)a00741008; + gdcm::Attribute<0x0074,0x100a> a0074100a; (void)a0074100a; + gdcm::Attribute<0x0074,0x100c> a0074100c; (void)a0074100c; + gdcm::Attribute<0x0074,0x100e> a0074100e; (void)a0074100e; + gdcm::Attribute<0x0074,0x1020> a00741020; (void)a00741020; + gdcm::Attribute<0x0074,0x1022> a00741022; (void)a00741022; + gdcm::Attribute<0x0074,0x1024> a00741024; (void)a00741024; + gdcm::Attribute<0x0074,0x1030> a00741030; (void)a00741030; + gdcm::Attribute<0x0074,0x1032> a00741032; (void)a00741032; + gdcm::Attribute<0x0074,0x1034> a00741034; (void)a00741034; + gdcm::Attribute<0x0074,0x1036> a00741036; (void)a00741036; + gdcm::Attribute<0x0074,0x1038> a00741038; (void)a00741038; + gdcm::Attribute<0x0074,0x103a> a0074103a; (void)a0074103a; + gdcm::Attribute<0x0074,0x1040> a00741040; (void)a00741040; + gdcm::Attribute<0x0074,0x1042> a00741042; (void)a00741042; + gdcm::Attribute<0x0074,0x1044> a00741044; (void)a00741044; + gdcm::Attribute<0x0074,0x1046> a00741046; (void)a00741046; + gdcm::Attribute<0x0074,0x1048> a00741048; (void)a00741048; + gdcm::Attribute<0x0074,0x104a> a0074104a; (void)a0074104a; + gdcm::Attribute<0x0074,0x104c> a0074104c; (void)a0074104c; + gdcm::Attribute<0x0074,0x104e> a0074104e; (void)a0074104e; + gdcm::Attribute<0x0074,0x1050> a00741050; (void)a00741050; + gdcm::Attribute<0x0074,0x1052> a00741052; (void)a00741052; + gdcm::Attribute<0x0074,0x1054> a00741054; (void)a00741054; + gdcm::Attribute<0x0074,0x1056> a00741056; (void)a00741056; + gdcm::Attribute<0x0074,0x1200> a00741200; (void)a00741200; + gdcm::Attribute<0x0074,0x1202> a00741202; (void)a00741202; + gdcm::Attribute<0x0074,0x1204> a00741204; (void)a00741204; + gdcm::Attribute<0x0074,0x1210> a00741210; (void)a00741210; + gdcm::Attribute<0x0074,0x1212> a00741212; (void)a00741212; + gdcm::Attribute<0x0074,0x1216> a00741216; (void)a00741216; + gdcm::Attribute<0x0074,0x1220> a00741220; (void)a00741220; + gdcm::Attribute<0x0074,0x1222> a00741222; (void)a00741222; + gdcm::Attribute<0x0074,0x1230> a00741230; (void)a00741230; + gdcm::Attribute<0x0074,0x1234> a00741234; (void)a00741234; + gdcm::Attribute<0x0074,0x1236> a00741236; (void)a00741236; + gdcm::Attribute<0x0074,0x1238> a00741238; (void)a00741238; + gdcm::Attribute<0x0074,0x1242> a00741242; (void)a00741242; + gdcm::Attribute<0x0074,0x1244> a00741244; (void)a00741244; + gdcm::Attribute<0x0074,0x1246> a00741246; (void)a00741246; + gdcm::Attribute<0x0088,0x0130> a00880130; (void)a00880130; + gdcm::Attribute<0x0088,0x0140> a00880140; (void)a00880140; + gdcm::Attribute<0x0088,0x0200> a00880200; (void)a00880200; + gdcm::Attribute<0x0088,0x0904> a00880904; (void)a00880904; + gdcm::Attribute<0x0088,0x0906> a00880906; (void)a00880906; + gdcm::Attribute<0x0088,0x0910> a00880910; (void)a00880910; + gdcm::Attribute<0x0100,0x0410> a01000410; (void)a01000410; + gdcm::Attribute<0x0100,0x0420> a01000420; (void)a01000420; + gdcm::Attribute<0x0100,0x0424> a01000424; (void)a01000424; + gdcm::Attribute<0x0100,0x0426> a01000426; (void)a01000426; + gdcm::Attribute<0x0400,0x0005> a04000005; (void)a04000005; + gdcm::Attribute<0x0400,0x0010> a04000010; (void)a04000010; + gdcm::Attribute<0x0400,0x0015> a04000015; (void)a04000015; + gdcm::Attribute<0x0400,0x0020> a04000020; (void)a04000020; + gdcm::Attribute<0x0400,0x0100> a04000100; (void)a04000100; + gdcm::Attribute<0x0400,0x0105> a04000105; (void)a04000105; + gdcm::Attribute<0x0400,0x0110> a04000110; (void)a04000110; + gdcm::Attribute<0x0400,0x0115> a04000115; (void)a04000115; + gdcm::Attribute<0x0400,0x0120> a04000120; (void)a04000120; + gdcm::Attribute<0x0400,0x0305> a04000305; (void)a04000305; + gdcm::Attribute<0x0400,0x0310> a04000310; (void)a04000310; + gdcm::Attribute<0x0400,0x0401> a04000401; (void)a04000401; + gdcm::Attribute<0x0400,0x0402> a04000402; (void)a04000402; + gdcm::Attribute<0x0400,0x0403> a04000403; (void)a04000403; + gdcm::Attribute<0x0400,0x0404> a04000404; (void)a04000404; + gdcm::Attribute<0x0400,0x0500> a04000500; (void)a04000500; + gdcm::Attribute<0x0400,0x0510> a04000510; (void)a04000510; + gdcm::Attribute<0x0400,0x0520> a04000520; (void)a04000520; + gdcm::Attribute<0x0400,0x0550> a04000550; (void)a04000550; + gdcm::Attribute<0x0400,0x0561> a04000561; (void)a04000561; + gdcm::Attribute<0x0400,0x0562> a04000562; (void)a04000562; + gdcm::Attribute<0x0400,0x0563> a04000563; (void)a04000563; + gdcm::Attribute<0x0400,0x0564> a04000564; (void)a04000564; + gdcm::Attribute<0x0400,0x0565> a04000565; (void)a04000565; + gdcm::Attribute<0x2000,0x0010> a20000010; (void)a20000010; + gdcm::Attribute<0x2000,0x001e> a2000001e; (void)a2000001e; + gdcm::Attribute<0x2000,0x0020> a20000020; (void)a20000020; + gdcm::Attribute<0x2000,0x0030> a20000030; (void)a20000030; + gdcm::Attribute<0x2000,0x0040> a20000040; (void)a20000040; + gdcm::Attribute<0x2000,0x0050> a20000050; (void)a20000050; + gdcm::Attribute<0x2000,0x0060> a20000060; (void)a20000060; + gdcm::Attribute<0x2000,0x0061> a20000061; (void)a20000061; + gdcm::Attribute<0x2000,0x0062> a20000062; (void)a20000062; + gdcm::Attribute<0x2000,0x0063> a20000063; (void)a20000063; + gdcm::Attribute<0x2000,0x0065> a20000065; (void)a20000065; + gdcm::Attribute<0x2000,0x0067> a20000067; (void)a20000067; + gdcm::Attribute<0x2000,0x0069> a20000069; (void)a20000069; + gdcm::Attribute<0x2000,0x006a> a2000006a; (void)a2000006a; + gdcm::Attribute<0x2000,0x00a0> a200000a0; (void)a200000a0; + gdcm::Attribute<0x2000,0x00a1> a200000a1; (void)a200000a1; + gdcm::Attribute<0x2000,0x00a2> a200000a2; (void)a200000a2; + gdcm::Attribute<0x2000,0x00a4> a200000a4; (void)a200000a4; + gdcm::Attribute<0x2000,0x00a8> a200000a8; (void)a200000a8; + gdcm::Attribute<0x2000,0x0500> a20000500; (void)a20000500; + gdcm::Attribute<0x2000,0x0510> a20000510; (void)a20000510; + gdcm::Attribute<0x2010,0x0010> a20100010; (void)a20100010; + gdcm::Attribute<0x2010,0x0030> a20100030; (void)a20100030; + gdcm::Attribute<0x2010,0x0040> a20100040; (void)a20100040; + gdcm::Attribute<0x2010,0x0050> a20100050; (void)a20100050; + gdcm::Attribute<0x2010,0x0052> a20100052; (void)a20100052; + gdcm::Attribute<0x2010,0x0054> a20100054; (void)a20100054; + gdcm::Attribute<0x2010,0x0060> a20100060; (void)a20100060; + gdcm::Attribute<0x2010,0x0080> a20100080; (void)a20100080; + gdcm::Attribute<0x2010,0x00a6> a201000a6; (void)a201000a6; + gdcm::Attribute<0x2010,0x00a7> a201000a7; (void)a201000a7; + gdcm::Attribute<0x2010,0x00a8> a201000a8; (void)a201000a8; + gdcm::Attribute<0x2010,0x00a9> a201000a9; (void)a201000a9; + gdcm::Attribute<0x2010,0x0100> a20100100; (void)a20100100; + gdcm::Attribute<0x2010,0x0110> a20100110; (void)a20100110; + gdcm::Attribute<0x2010,0x0120> a20100120; (void)a20100120; + gdcm::Attribute<0x2010,0x0130> a20100130; (void)a20100130; + gdcm::Attribute<0x2010,0x0140> a20100140; (void)a20100140; + gdcm::Attribute<0x2010,0x0150> a20100150; (void)a20100150; + gdcm::Attribute<0x2010,0x0152> a20100152; (void)a20100152; + gdcm::Attribute<0x2010,0x0154> a20100154; (void)a20100154; + gdcm::Attribute<0x2010,0x015e> a2010015e; (void)a2010015e; + gdcm::Attribute<0x2010,0x0160> a20100160; (void)a20100160; + gdcm::Attribute<0x2010,0x0376> a20100376; (void)a20100376; + gdcm::Attribute<0x2010,0x0500> a20100500; (void)a20100500; + gdcm::Attribute<0x2010,0x0510> a20100510; (void)a20100510; + gdcm::Attribute<0x2010,0x0520> a20100520; (void)a20100520; + gdcm::Attribute<0x2020,0x0010> a20200010; (void)a20200010; + gdcm::Attribute<0x2020,0x0020> a20200020; (void)a20200020; + gdcm::Attribute<0x2020,0x0030> a20200030; (void)a20200030; + gdcm::Attribute<0x2020,0x0040> a20200040; (void)a20200040; + gdcm::Attribute<0x2020,0x0050> a20200050; (void)a20200050; + gdcm::Attribute<0x2020,0x00a0> a202000a0; (void)a202000a0; + gdcm::Attribute<0x2020,0x00a2> a202000a2; (void)a202000a2; + gdcm::Attribute<0x2020,0x0110> a20200110; (void)a20200110; + gdcm::Attribute<0x2020,0x0111> a20200111; (void)a20200111; + gdcm::Attribute<0x2020,0x0130> a20200130; (void)a20200130; + gdcm::Attribute<0x2020,0x0140> a20200140; (void)a20200140; + gdcm::Attribute<0x2030,0x0010> a20300010; (void)a20300010; + gdcm::Attribute<0x2030,0x0020> a20300020; (void)a20300020; + gdcm::Attribute<0x2040,0x0010> a20400010; (void)a20400010; + gdcm::Attribute<0x2040,0x0020> a20400020; (void)a20400020; + gdcm::Attribute<0x2040,0x0060> a20400060; (void)a20400060; + gdcm::Attribute<0x2040,0x0070> a20400070; (void)a20400070; + gdcm::Attribute<0x2040,0x0072> a20400072; (void)a20400072; + gdcm::Attribute<0x2040,0x0074> a20400074; (void)a20400074; + gdcm::Attribute<0x2040,0x0080> a20400080; (void)a20400080; + gdcm::Attribute<0x2040,0x0082> a20400082; (void)a20400082; + gdcm::Attribute<0x2040,0x0090> a20400090; (void)a20400090; + gdcm::Attribute<0x2040,0x0100> a20400100; (void)a20400100; + gdcm::Attribute<0x2040,0x0500> a20400500; (void)a20400500; + gdcm::Attribute<0x2050,0x0010> a20500010; (void)a20500010; + gdcm::Attribute<0x2050,0x0020> a20500020; (void)a20500020; + gdcm::Attribute<0x2050,0x0500> a20500500; (void)a20500500; + gdcm::Attribute<0x2100,0x0010> a21000010; (void)a21000010; + gdcm::Attribute<0x2100,0x0020> a21000020; (void)a21000020; + gdcm::Attribute<0x2100,0x0030> a21000030; (void)a21000030; + gdcm::Attribute<0x2100,0x0040> a21000040; (void)a21000040; + gdcm::Attribute<0x2100,0x0050> a21000050; (void)a21000050; + gdcm::Attribute<0x2100,0x0070> a21000070; (void)a21000070; + gdcm::Attribute<0x2100,0x0140> a21000140; (void)a21000140; + gdcm::Attribute<0x2100,0x0160> a21000160; (void)a21000160; + gdcm::Attribute<0x2100,0x0170> a21000170; (void)a21000170; + gdcm::Attribute<0x2100,0x0500> a21000500; (void)a21000500; + gdcm::Attribute<0x2110,0x0010> a21100010; (void)a21100010; + gdcm::Attribute<0x2110,0x0020> a21100020; (void)a21100020; + gdcm::Attribute<0x2110,0x0030> a21100030; (void)a21100030; + gdcm::Attribute<0x2110,0x0099> a21100099; (void)a21100099; + gdcm::Attribute<0x2120,0x0010> a21200010; (void)a21200010; + gdcm::Attribute<0x2120,0x0050> a21200050; (void)a21200050; + gdcm::Attribute<0x2120,0x0070> a21200070; (void)a21200070; + gdcm::Attribute<0x2130,0x0010> a21300010; (void)a21300010; + gdcm::Attribute<0x2130,0x0015> a21300015; (void)a21300015; + gdcm::Attribute<0x2130,0x0030> a21300030; (void)a21300030; + gdcm::Attribute<0x2130,0x0040> a21300040; (void)a21300040; + gdcm::Attribute<0x2130,0x0050> a21300050; (void)a21300050; + gdcm::Attribute<0x2130,0x0060> a21300060; (void)a21300060; + gdcm::Attribute<0x2130,0x0080> a21300080; (void)a21300080; + gdcm::Attribute<0x2130,0x00a0> a213000a0; (void)a213000a0; + gdcm::Attribute<0x2130,0x00c0> a213000c0; (void)a213000c0; + gdcm::Attribute<0x2200,0x0001> a22000001; (void)a22000001; + gdcm::Attribute<0x2200,0x0002> a22000002; (void)a22000002; + gdcm::Attribute<0x2200,0x0003> a22000003; (void)a22000003; + gdcm::Attribute<0x2200,0x0004> a22000004; (void)a22000004; + gdcm::Attribute<0x2200,0x0005> a22000005; (void)a22000005; + gdcm::Attribute<0x2200,0x0006> a22000006; (void)a22000006; + gdcm::Attribute<0x2200,0x0007> a22000007; (void)a22000007; + gdcm::Attribute<0x2200,0x0008> a22000008; (void)a22000008; + gdcm::Attribute<0x2200,0x0009> a22000009; (void)a22000009; + gdcm::Attribute<0x2200,0x000a> a2200000a; (void)a2200000a; + gdcm::Attribute<0x2200,0x000b> a2200000b; (void)a2200000b; + gdcm::Attribute<0x2200,0x000c> a2200000c; (void)a2200000c; + gdcm::Attribute<0x2200,0x000d> a2200000d; (void)a2200000d; + gdcm::Attribute<0x2200,0x000e> a2200000e; (void)a2200000e; + gdcm::Attribute<0x2200,0x000f> a2200000f; (void)a2200000f; + gdcm::Attribute<0x2200,0x0020> a22000020; (void)a22000020; + gdcm::Attribute<0x3002,0x0002> a30020002; (void)a30020002; + gdcm::Attribute<0x3002,0x0003> a30020003; (void)a30020003; + gdcm::Attribute<0x3002,0x0004> a30020004; (void)a30020004; + gdcm::Attribute<0x3002,0x000a> a3002000a; (void)a3002000a; + gdcm::Attribute<0x3002,0x000c> a3002000c; (void)a3002000c; + gdcm::Attribute<0x3002,0x000d> a3002000d; (void)a3002000d; + gdcm::Attribute<0x3002,0x000e> a3002000e; (void)a3002000e; + gdcm::Attribute<0x3002,0x0010> a30020010; (void)a30020010; + gdcm::Attribute<0x3002,0x0011> a30020011; (void)a30020011; + gdcm::Attribute<0x3002,0x0012> a30020012; (void)a30020012; + gdcm::Attribute<0x3002,0x0020> a30020020; (void)a30020020; + gdcm::Attribute<0x3002,0x0022> a30020022; (void)a30020022; + gdcm::Attribute<0x3002,0x0024> a30020024; (void)a30020024; + gdcm::Attribute<0x3002,0x0026> a30020026; (void)a30020026; + gdcm::Attribute<0x3002,0x0028> a30020028; (void)a30020028; + gdcm::Attribute<0x3002,0x0029> a30020029; (void)a30020029; + gdcm::Attribute<0x3002,0x0030> a30020030; (void)a30020030; + gdcm::Attribute<0x3002,0x0032> a30020032; (void)a30020032; + gdcm::Attribute<0x3002,0x0034> a30020034; (void)a30020034; + gdcm::Attribute<0x3002,0x0040> a30020040; (void)a30020040; + gdcm::Attribute<0x3002,0x0041> a30020041; (void)a30020041; + gdcm::Attribute<0x3002,0x0042> a30020042; (void)a30020042; + gdcm::Attribute<0x3004,0x0001> a30040001; (void)a30040001; + gdcm::Attribute<0x3004,0x0002> a30040002; (void)a30040002; + gdcm::Attribute<0x3004,0x0004> a30040004; (void)a30040004; + gdcm::Attribute<0x3004,0x0006> a30040006; (void)a30040006; + gdcm::Attribute<0x3004,0x0008> a30040008; (void)a30040008; + gdcm::Attribute<0x3004,0x000a> a3004000a; (void)a3004000a; + gdcm::Attribute<0x3004,0x000c> a3004000c; (void)a3004000c; + gdcm::Attribute<0x3004,0x000e> a3004000e; (void)a3004000e; + gdcm::Attribute<0x3004,0x0010> a30040010; (void)a30040010; + gdcm::Attribute<0x3004,0x0012> a30040012; (void)a30040012; + gdcm::Attribute<0x3004,0x0040> a30040040; (void)a30040040; + gdcm::Attribute<0x3004,0x0042> a30040042; (void)a30040042; + gdcm::Attribute<0x3004,0x0050> a30040050; (void)a30040050; + gdcm::Attribute<0x3004,0x0052> a30040052; (void)a30040052; + gdcm::Attribute<0x3004,0x0054> a30040054; (void)a30040054; + gdcm::Attribute<0x3004,0x0056> a30040056; (void)a30040056; + gdcm::Attribute<0x3004,0x0058> a30040058; (void)a30040058; + gdcm::Attribute<0x3004,0x0060> a30040060; (void)a30040060; + gdcm::Attribute<0x3004,0x0062> a30040062; (void)a30040062; + gdcm::Attribute<0x3004,0x0070> a30040070; (void)a30040070; + gdcm::Attribute<0x3004,0x0072> a30040072; (void)a30040072; + gdcm::Attribute<0x3004,0x0074> a30040074; (void)a30040074; + gdcm::Attribute<0x3006,0x0002> a30060002; (void)a30060002; + gdcm::Attribute<0x3006,0x0004> a30060004; (void)a30060004; + gdcm::Attribute<0x3006,0x0006> a30060006; (void)a30060006; + gdcm::Attribute<0x3006,0x0008> a30060008; (void)a30060008; + gdcm::Attribute<0x3006,0x0009> a30060009; (void)a30060009; + gdcm::Attribute<0x3006,0x0010> a30060010; (void)a30060010; + gdcm::Attribute<0x3006,0x0012> a30060012; (void)a30060012; + gdcm::Attribute<0x3006,0x0014> a30060014; (void)a30060014; + gdcm::Attribute<0x3006,0x0016> a30060016; (void)a30060016; + gdcm::Attribute<0x3006,0x0020> a30060020; (void)a30060020; + gdcm::Attribute<0x3006,0x0022> a30060022; (void)a30060022; + gdcm::Attribute<0x3006,0x0024> a30060024; (void)a30060024; + gdcm::Attribute<0x3006,0x0026> a30060026; (void)a30060026; + gdcm::Attribute<0x3006,0x0028> a30060028; (void)a30060028; + gdcm::Attribute<0x3006,0x002a> a3006002a; (void)a3006002a; + gdcm::Attribute<0x3006,0x002c> a3006002c; (void)a3006002c; + gdcm::Attribute<0x3006,0x0030> a30060030; (void)a30060030; + gdcm::Attribute<0x3006,0x0033> a30060033; (void)a30060033; + gdcm::Attribute<0x3006,0x0036> a30060036; (void)a30060036; + gdcm::Attribute<0x3006,0x0038> a30060038; (void)a30060038; + gdcm::Attribute<0x3006,0x0039> a30060039; (void)a30060039; + gdcm::Attribute<0x3006,0x0040> a30060040; (void)a30060040; + gdcm::Attribute<0x3006,0x0042> a30060042; (void)a30060042; + gdcm::Attribute<0x3006,0x0044> a30060044; (void)a30060044; + gdcm::Attribute<0x3006,0x0045> a30060045; (void)a30060045; + gdcm::Attribute<0x3006,0x0046> a30060046; (void)a30060046; + gdcm::Attribute<0x3006,0x0048> a30060048; (void)a30060048; + gdcm::Attribute<0x3006,0x0049> a30060049; (void)a30060049; + gdcm::Attribute<0x3006,0x0050> a30060050; (void)a30060050; + gdcm::Attribute<0x3006,0x0080> a30060080; (void)a30060080; + gdcm::Attribute<0x3006,0x0082> a30060082; (void)a30060082; + gdcm::Attribute<0x3006,0x0084> a30060084; (void)a30060084; + gdcm::Attribute<0x3006,0x0085> a30060085; (void)a30060085; + gdcm::Attribute<0x3006,0x0086> a30060086; (void)a30060086; + gdcm::Attribute<0x3006,0x0088> a30060088; (void)a30060088; + gdcm::Attribute<0x3006,0x00a0> a300600a0; (void)a300600a0; + gdcm::Attribute<0x3006,0x00a4> a300600a4; (void)a300600a4; + gdcm::Attribute<0x3006,0x00a6> a300600a6; (void)a300600a6; + gdcm::Attribute<0x3006,0x00b0> a300600b0; (void)a300600b0; + gdcm::Attribute<0x3006,0x00b2> a300600b2; (void)a300600b2; + gdcm::Attribute<0x3006,0x00b4> a300600b4; (void)a300600b4; + gdcm::Attribute<0x3006,0x00b6> a300600b6; (void)a300600b6; + gdcm::Attribute<0x3006,0x00b7> a300600b7; (void)a300600b7; + gdcm::Attribute<0x3006,0x00b8> a300600b8; (void)a300600b8; + gdcm::Attribute<0x3006,0x00c0> a300600c0; (void)a300600c0; + gdcm::Attribute<0x3006,0x00c2> a300600c2; (void)a300600c2; + gdcm::Attribute<0x3006,0x00c4> a300600c4; (void)a300600c4; + gdcm::Attribute<0x3006,0x00c6> a300600c6; (void)a300600c6; + gdcm::Attribute<0x3006,0x00c8> a300600c8; (void)a300600c8; + gdcm::Attribute<0x3008,0x0010> a30080010; (void)a30080010; + gdcm::Attribute<0x3008,0x0012> a30080012; (void)a30080012; + gdcm::Attribute<0x3008,0x0014> a30080014; (void)a30080014; + gdcm::Attribute<0x3008,0x0016> a30080016; (void)a30080016; + gdcm::Attribute<0x3008,0x0020> a30080020; (void)a30080020; + gdcm::Attribute<0x3008,0x0021> a30080021; (void)a30080021; + gdcm::Attribute<0x3008,0x0022> a30080022; (void)a30080022; + gdcm::Attribute<0x3008,0x0024> a30080024; (void)a30080024; + gdcm::Attribute<0x3008,0x0025> a30080025; (void)a30080025; + gdcm::Attribute<0x3008,0x002a> a3008002a; (void)a3008002a; + gdcm::Attribute<0x3008,0x002b> a3008002b; (void)a3008002b; + gdcm::Attribute<0x3008,0x002c> a3008002c; (void)a3008002c; + gdcm::Attribute<0x3008,0x0030> a30080030; (void)a30080030; + gdcm::Attribute<0x3008,0x0032> a30080032; (void)a30080032; + gdcm::Attribute<0x3008,0x0033> a30080033; (void)a30080033; + gdcm::Attribute<0x3008,0x0036> a30080036; (void)a30080036; + gdcm::Attribute<0x3008,0x0037> a30080037; (void)a30080037; + gdcm::Attribute<0x3008,0x003a> a3008003a; (void)a3008003a; + gdcm::Attribute<0x3008,0x003b> a3008003b; (void)a3008003b; + gdcm::Attribute<0x3008,0x0040> a30080040; (void)a30080040; + gdcm::Attribute<0x3008,0x0041> a30080041; (void)a30080041; + gdcm::Attribute<0x3008,0x0042> a30080042; (void)a30080042; + gdcm::Attribute<0x3008,0x0044> a30080044; (void)a30080044; + gdcm::Attribute<0x3008,0x0045> a30080045; (void)a30080045; + gdcm::Attribute<0x3008,0x0046> a30080046; (void)a30080046; + gdcm::Attribute<0x3008,0x0047> a30080047; (void)a30080047; + gdcm::Attribute<0x3008,0x0048> a30080048; (void)a30080048; + gdcm::Attribute<0x3008,0x0050> a30080050; (void)a30080050; + gdcm::Attribute<0x3008,0x0052> a30080052; (void)a30080052; + gdcm::Attribute<0x3008,0x0054> a30080054; (void)a30080054; + gdcm::Attribute<0x3008,0x0056> a30080056; (void)a30080056; + gdcm::Attribute<0x3008,0x005a> a3008005a; (void)a3008005a; + gdcm::Attribute<0x3008,0x0060> a30080060; (void)a30080060; + gdcm::Attribute<0x3008,0x0061> a30080061; (void)a30080061; + gdcm::Attribute<0x3008,0x0062> a30080062; (void)a30080062; + gdcm::Attribute<0x3008,0x0063> a30080063; (void)a30080063; + gdcm::Attribute<0x3008,0x0064> a30080064; (void)a30080064; + gdcm::Attribute<0x3008,0x0065> a30080065; (void)a30080065; + gdcm::Attribute<0x3008,0x0066> a30080066; (void)a30080066; + gdcm::Attribute<0x3008,0x0068> a30080068; (void)a30080068; + gdcm::Attribute<0x3008,0x006a> a3008006a; (void)a3008006a; + gdcm::Attribute<0x3008,0x0070> a30080070; (void)a30080070; + gdcm::Attribute<0x3008,0x0072> a30080072; (void)a30080072; + gdcm::Attribute<0x3008,0x0074> a30080074; (void)a30080074; + gdcm::Attribute<0x3008,0x0076> a30080076; (void)a30080076; + gdcm::Attribute<0x3008,0x0078> a30080078; (void)a30080078; + gdcm::Attribute<0x3008,0x007a> a3008007a; (void)a3008007a; + gdcm::Attribute<0x3008,0x0080> a30080080; (void)a30080080; + gdcm::Attribute<0x3008,0x0082> a30080082; (void)a30080082; + gdcm::Attribute<0x3008,0x0090> a30080090; (void)a30080090; + gdcm::Attribute<0x3008,0x0092> a30080092; (void)a30080092; + gdcm::Attribute<0x3008,0x00a0> a300800a0; (void)a300800a0; + gdcm::Attribute<0x3008,0x00b0> a300800b0; (void)a300800b0; + gdcm::Attribute<0x3008,0x00c0> a300800c0; (void)a300800c0; + gdcm::Attribute<0x3008,0x00d0> a300800d0; (void)a300800d0; + gdcm::Attribute<0x3008,0x00e0> a300800e0; (void)a300800e0; + gdcm::Attribute<0x3008,0x00f0> a300800f0; (void)a300800f0; + gdcm::Attribute<0x3008,0x00f2> a300800f2; (void)a300800f2; + gdcm::Attribute<0x3008,0x00f4> a300800f4; (void)a300800f4; + gdcm::Attribute<0x3008,0x00f6> a300800f6; (void)a300800f6; + gdcm::Attribute<0x3008,0x0100> a30080100; (void)a30080100; + gdcm::Attribute<0x3008,0x0105> a30080105; (void)a30080105; + gdcm::Attribute<0x3008,0x0110> a30080110; (void)a30080110; + gdcm::Attribute<0x3008,0x0116> a30080116; (void)a30080116; + gdcm::Attribute<0x3008,0x0120> a30080120; (void)a30080120; + gdcm::Attribute<0x3008,0x0122> a30080122; (void)a30080122; + gdcm::Attribute<0x3008,0x0130> a30080130; (void)a30080130; + gdcm::Attribute<0x3008,0x0132> a30080132; (void)a30080132; + gdcm::Attribute<0x3008,0x0134> a30080134; (void)a30080134; + gdcm::Attribute<0x3008,0x0136> a30080136; (void)a30080136; + gdcm::Attribute<0x3008,0x0138> a30080138; (void)a30080138; + gdcm::Attribute<0x3008,0x013a> a3008013a; (void)a3008013a; + gdcm::Attribute<0x3008,0x013c> a3008013c; (void)a3008013c; + gdcm::Attribute<0x3008,0x0140> a30080140; (void)a30080140; + gdcm::Attribute<0x3008,0x0142> a30080142; (void)a30080142; + gdcm::Attribute<0x3008,0x0150> a30080150; (void)a30080150; + gdcm::Attribute<0x3008,0x0152> a30080152; (void)a30080152; + gdcm::Attribute<0x3008,0x0160> a30080160; (void)a30080160; + gdcm::Attribute<0x3008,0x0162> a30080162; (void)a30080162; + gdcm::Attribute<0x3008,0x0164> a30080164; (void)a30080164; + gdcm::Attribute<0x3008,0x0166> a30080166; (void)a30080166; + gdcm::Attribute<0x3008,0x0168> a30080168; (void)a30080168; + gdcm::Attribute<0x3008,0x0200> a30080200; (void)a30080200; + gdcm::Attribute<0x3008,0x0202> a30080202; (void)a30080202; + gdcm::Attribute<0x3008,0x0220> a30080220; (void)a30080220; + gdcm::Attribute<0x3008,0x0223> a30080223; (void)a30080223; + gdcm::Attribute<0x3008,0x0224> a30080224; (void)a30080224; + gdcm::Attribute<0x3008,0x0230> a30080230; (void)a30080230; + gdcm::Attribute<0x3008,0x0240> a30080240; (void)a30080240; + gdcm::Attribute<0x3008,0x0250> a30080250; (void)a30080250; + gdcm::Attribute<0x3008,0x0251> a30080251; (void)a30080251; + gdcm::Attribute<0x300a,0x0002> a300a0002; (void)a300a0002; + gdcm::Attribute<0x300a,0x0003> a300a0003; (void)a300a0003; + gdcm::Attribute<0x300a,0x0004> a300a0004; (void)a300a0004; + gdcm::Attribute<0x300a,0x0006> a300a0006; (void)a300a0006; + gdcm::Attribute<0x300a,0x0007> a300a0007; (void)a300a0007; + gdcm::Attribute<0x300a,0x0009> a300a0009; (void)a300a0009; + gdcm::Attribute<0x300a,0x000a> a300a000a; (void)a300a000a; + gdcm::Attribute<0x300a,0x000b> a300a000b; (void)a300a000b; + gdcm::Attribute<0x300a,0x000c> a300a000c; (void)a300a000c; + gdcm::Attribute<0x300a,0x000e> a300a000e; (void)a300a000e; + gdcm::Attribute<0x300a,0x0010> a300a0010; (void)a300a0010; + gdcm::Attribute<0x300a,0x0012> a300a0012; (void)a300a0012; + gdcm::Attribute<0x300a,0x0013> a300a0013; (void)a300a0013; + gdcm::Attribute<0x300a,0x0014> a300a0014; (void)a300a0014; + gdcm::Attribute<0x300a,0x0015> a300a0015; (void)a300a0015; + gdcm::Attribute<0x300a,0x0016> a300a0016; (void)a300a0016; + gdcm::Attribute<0x300a,0x0018> a300a0018; (void)a300a0018; + gdcm::Attribute<0x300a,0x001a> a300a001a; (void)a300a001a; + gdcm::Attribute<0x300a,0x0020> a300a0020; (void)a300a0020; + gdcm::Attribute<0x300a,0x0021> a300a0021; (void)a300a0021; + gdcm::Attribute<0x300a,0x0022> a300a0022; (void)a300a0022; + gdcm::Attribute<0x300a,0x0023> a300a0023; (void)a300a0023; + gdcm::Attribute<0x300a,0x0025> a300a0025; (void)a300a0025; + gdcm::Attribute<0x300a,0x0026> a300a0026; (void)a300a0026; + gdcm::Attribute<0x300a,0x0027> a300a0027; (void)a300a0027; + gdcm::Attribute<0x300a,0x0028> a300a0028; (void)a300a0028; + gdcm::Attribute<0x300a,0x002a> a300a002a; (void)a300a002a; + gdcm::Attribute<0x300a,0x002b> a300a002b; (void)a300a002b; + gdcm::Attribute<0x300a,0x002c> a300a002c; (void)a300a002c; + gdcm::Attribute<0x300a,0x002d> a300a002d; (void)a300a002d; + gdcm::Attribute<0x300a,0x0040> a300a0040; (void)a300a0040; + gdcm::Attribute<0x300a,0x0042> a300a0042; (void)a300a0042; + gdcm::Attribute<0x300a,0x0043> a300a0043; (void)a300a0043; + gdcm::Attribute<0x300a,0x0044> a300a0044; (void)a300a0044; + gdcm::Attribute<0x300a,0x0046> a300a0046; (void)a300a0046; + gdcm::Attribute<0x300a,0x0048> a300a0048; (void)a300a0048; + gdcm::Attribute<0x300a,0x004a> a300a004a; (void)a300a004a; + gdcm::Attribute<0x300a,0x004b> a300a004b; (void)a300a004b; + gdcm::Attribute<0x300a,0x004c> a300a004c; (void)a300a004c; + gdcm::Attribute<0x300a,0x004e> a300a004e; (void)a300a004e; + gdcm::Attribute<0x300a,0x004f> a300a004f; (void)a300a004f; + gdcm::Attribute<0x300a,0x0050> a300a0050; (void)a300a0050; + gdcm::Attribute<0x300a,0x0051> a300a0051; (void)a300a0051; + gdcm::Attribute<0x300a,0x0052> a300a0052; (void)a300a0052; + gdcm::Attribute<0x300a,0x0053> a300a0053; (void)a300a0053; + gdcm::Attribute<0x300a,0x0055> a300a0055; (void)a300a0055; + gdcm::Attribute<0x300a,0x0070> a300a0070; (void)a300a0070; + gdcm::Attribute<0x300a,0x0071> a300a0071; (void)a300a0071; + gdcm::Attribute<0x300a,0x0072> a300a0072; (void)a300a0072; + gdcm::Attribute<0x300a,0x0078> a300a0078; (void)a300a0078; + gdcm::Attribute<0x300a,0x0079> a300a0079; (void)a300a0079; + gdcm::Attribute<0x300a,0x007a> a300a007a; (void)a300a007a; + gdcm::Attribute<0x300a,0x007b> a300a007b; (void)a300a007b; + gdcm::Attribute<0x300a,0x0080> a300a0080; (void)a300a0080; + gdcm::Attribute<0x300a,0x0082> a300a0082; (void)a300a0082; + gdcm::Attribute<0x300a,0x0084> a300a0084; (void)a300a0084; + gdcm::Attribute<0x300a,0x0086> a300a0086; (void)a300a0086; + gdcm::Attribute<0x300a,0x0088> a300a0088; (void)a300a0088; + gdcm::Attribute<0x300a,0x0089> a300a0089; (void)a300a0089; + gdcm::Attribute<0x300a,0x008a> a300a008a; (void)a300a008a; + gdcm::Attribute<0x300a,0x00a0> a300a00a0; (void)a300a00a0; + gdcm::Attribute<0x300a,0x00a2> a300a00a2; (void)a300a00a2; + gdcm::Attribute<0x300a,0x00a4> a300a00a4; (void)a300a00a4; + gdcm::Attribute<0x300a,0x00b0> a300a00b0; (void)a300a00b0; + gdcm::Attribute<0x300a,0x00b2> a300a00b2; (void)a300a00b2; + gdcm::Attribute<0x300a,0x00b3> a300a00b3; (void)a300a00b3; + gdcm::Attribute<0x300a,0x00b4> a300a00b4; (void)a300a00b4; + gdcm::Attribute<0x300a,0x00b6> a300a00b6; (void)a300a00b6; + gdcm::Attribute<0x300a,0x00b8> a300a00b8; (void)a300a00b8; + gdcm::Attribute<0x300a,0x00ba> a300a00ba; (void)a300a00ba; + gdcm::Attribute<0x300a,0x00bb> a300a00bb; (void)a300a00bb; + gdcm::Attribute<0x300a,0x00bc> a300a00bc; (void)a300a00bc; + gdcm::Attribute<0x300a,0x00be> a300a00be; (void)a300a00be; + gdcm::Attribute<0x300a,0x00c0> a300a00c0; (void)a300a00c0; + gdcm::Attribute<0x300a,0x00c2> a300a00c2; (void)a300a00c2; + gdcm::Attribute<0x300a,0x00c3> a300a00c3; (void)a300a00c3; + gdcm::Attribute<0x300a,0x00c4> a300a00c4; (void)a300a00c4; + gdcm::Attribute<0x300a,0x00c6> a300a00c6; (void)a300a00c6; + gdcm::Attribute<0x300a,0x00c7> a300a00c7; (void)a300a00c7; + gdcm::Attribute<0x300a,0x00c8> a300a00c8; (void)a300a00c8; + gdcm::Attribute<0x300a,0x00ca> a300a00ca; (void)a300a00ca; + gdcm::Attribute<0x300a,0x00cc> a300a00cc; (void)a300a00cc; + gdcm::Attribute<0x300a,0x00ce> a300a00ce; (void)a300a00ce; + gdcm::Attribute<0x300a,0x00d0> a300a00d0; (void)a300a00d0; + gdcm::Attribute<0x300a,0x00d1> a300a00d1; (void)a300a00d1; + gdcm::Attribute<0x300a,0x00d2> a300a00d2; (void)a300a00d2; + gdcm::Attribute<0x300a,0x00d3> a300a00d3; (void)a300a00d3; + gdcm::Attribute<0x300a,0x00d4> a300a00d4; (void)a300a00d4; + gdcm::Attribute<0x300a,0x00d5> a300a00d5; (void)a300a00d5; + gdcm::Attribute<0x300a,0x00d6> a300a00d6; (void)a300a00d6; + gdcm::Attribute<0x300a,0x00d7> a300a00d7; (void)a300a00d7; + gdcm::Attribute<0x300a,0x00d8> a300a00d8; (void)a300a00d8; + gdcm::Attribute<0x300a,0x00d9> a300a00d9; (void)a300a00d9; + gdcm::Attribute<0x300a,0x00da> a300a00da; (void)a300a00da; + gdcm::Attribute<0x300a,0x00db> a300a00db; (void)a300a00db; + gdcm::Attribute<0x300a,0x00dc> a300a00dc; (void)a300a00dc; + gdcm::Attribute<0x300a,0x00dd> a300a00dd; (void)a300a00dd; + gdcm::Attribute<0x300a,0x00e0> a300a00e0; (void)a300a00e0; + gdcm::Attribute<0x300a,0x00e1> a300a00e1; (void)a300a00e1; + gdcm::Attribute<0x300a,0x00e2> a300a00e2; (void)a300a00e2; + gdcm::Attribute<0x300a,0x00e3> a300a00e3; (void)a300a00e3; + gdcm::Attribute<0x300a,0x00e4> a300a00e4; (void)a300a00e4; + gdcm::Attribute<0x300a,0x00e5> a300a00e5; (void)a300a00e5; + gdcm::Attribute<0x300a,0x00e6> a300a00e6; (void)a300a00e6; + gdcm::Attribute<0x300a,0x00e7> a300a00e7; (void)a300a00e7; + gdcm::Attribute<0x300a,0x00e8> a300a00e8; (void)a300a00e8; + gdcm::Attribute<0x300a,0x00e9> a300a00e9; (void)a300a00e9; + gdcm::Attribute<0x300a,0x00ea> a300a00ea; (void)a300a00ea; + gdcm::Attribute<0x300a,0x00eb> a300a00eb; (void)a300a00eb; + gdcm::Attribute<0x300a,0x00ec> a300a00ec; (void)a300a00ec; + gdcm::Attribute<0x300a,0x00ed> a300a00ed; (void)a300a00ed; + gdcm::Attribute<0x300a,0x00ee> a300a00ee; (void)a300a00ee; + gdcm::Attribute<0x300a,0x00f0> a300a00f0; (void)a300a00f0; + gdcm::Attribute<0x300a,0x00f2> a300a00f2; (void)a300a00f2; + gdcm::Attribute<0x300a,0x00f3> a300a00f3; (void)a300a00f3; + gdcm::Attribute<0x300a,0x00f4> a300a00f4; (void)a300a00f4; + gdcm::Attribute<0x300a,0x00f5> a300a00f5; (void)a300a00f5; + gdcm::Attribute<0x300a,0x00f6> a300a00f6; (void)a300a00f6; + gdcm::Attribute<0x300a,0x00f7> a300a00f7; (void)a300a00f7; + gdcm::Attribute<0x300a,0x00f8> a300a00f8; (void)a300a00f8; + gdcm::Attribute<0x300a,0x00f9> a300a00f9; (void)a300a00f9; + gdcm::Attribute<0x300a,0x00fa> a300a00fa; (void)a300a00fa; + gdcm::Attribute<0x300a,0x00fb> a300a00fb; (void)a300a00fb; + gdcm::Attribute<0x300a,0x00fc> a300a00fc; (void)a300a00fc; + gdcm::Attribute<0x300a,0x00fe> a300a00fe; (void)a300a00fe; + gdcm::Attribute<0x300a,0x0100> a300a0100; (void)a300a0100; + gdcm::Attribute<0x300a,0x0102> a300a0102; (void)a300a0102; + gdcm::Attribute<0x300a,0x0104> a300a0104; (void)a300a0104; + gdcm::Attribute<0x300a,0x0106> a300a0106; (void)a300a0106; + gdcm::Attribute<0x300a,0x0107> a300a0107; (void)a300a0107; + gdcm::Attribute<0x300a,0x0108> a300a0108; (void)a300a0108; + gdcm::Attribute<0x300a,0x0109> a300a0109; (void)a300a0109; + gdcm::Attribute<0x300a,0x010a> a300a010a; (void)a300a010a; + gdcm::Attribute<0x300a,0x010c> a300a010c; (void)a300a010c; + gdcm::Attribute<0x300a,0x010e> a300a010e; (void)a300a010e; + gdcm::Attribute<0x300a,0x0110> a300a0110; (void)a300a0110; + gdcm::Attribute<0x300a,0x0111> a300a0111; (void)a300a0111; + gdcm::Attribute<0x300a,0x0112> a300a0112; (void)a300a0112; + gdcm::Attribute<0x300a,0x0114> a300a0114; (void)a300a0114; + gdcm::Attribute<0x300a,0x0115> a300a0115; (void)a300a0115; + gdcm::Attribute<0x300a,0x0116> a300a0116; (void)a300a0116; + gdcm::Attribute<0x300a,0x0118> a300a0118; (void)a300a0118; + gdcm::Attribute<0x300a,0x011a> a300a011a; (void)a300a011a; + gdcm::Attribute<0x300a,0x011c> a300a011c; (void)a300a011c; + gdcm::Attribute<0x300a,0x011e> a300a011e; (void)a300a011e; + gdcm::Attribute<0x300a,0x011f> a300a011f; (void)a300a011f; + gdcm::Attribute<0x300a,0x0120> a300a0120; (void)a300a0120; + gdcm::Attribute<0x300a,0x0121> a300a0121; (void)a300a0121; + gdcm::Attribute<0x300a,0x0122> a300a0122; (void)a300a0122; + gdcm::Attribute<0x300a,0x0123> a300a0123; (void)a300a0123; + gdcm::Attribute<0x300a,0x0124> a300a0124; (void)a300a0124; + gdcm::Attribute<0x300a,0x0125> a300a0125; (void)a300a0125; + gdcm::Attribute<0x300a,0x0126> a300a0126; (void)a300a0126; + gdcm::Attribute<0x300a,0x0128> a300a0128; (void)a300a0128; + gdcm::Attribute<0x300a,0x0129> a300a0129; (void)a300a0129; + gdcm::Attribute<0x300a,0x012a> a300a012a; (void)a300a012a; + gdcm::Attribute<0x300a,0x012c> a300a012c; (void)a300a012c; + gdcm::Attribute<0x300a,0x012e> a300a012e; (void)a300a012e; + gdcm::Attribute<0x300a,0x0130> a300a0130; (void)a300a0130; + gdcm::Attribute<0x300a,0x0134> a300a0134; (void)a300a0134; + gdcm::Attribute<0x300a,0x0140> a300a0140; (void)a300a0140; + gdcm::Attribute<0x300a,0x0142> a300a0142; (void)a300a0142; + gdcm::Attribute<0x300a,0x0144> a300a0144; (void)a300a0144; + gdcm::Attribute<0x300a,0x0146> a300a0146; (void)a300a0146; + gdcm::Attribute<0x300a,0x0148> a300a0148; (void)a300a0148; + gdcm::Attribute<0x300a,0x014a> a300a014a; (void)a300a014a; + gdcm::Attribute<0x300a,0x014c> a300a014c; (void)a300a014c; + gdcm::Attribute<0x300a,0x014e> a300a014e; (void)a300a014e; + gdcm::Attribute<0x300a,0x0180> a300a0180; (void)a300a0180; + gdcm::Attribute<0x300a,0x0182> a300a0182; (void)a300a0182; + gdcm::Attribute<0x300a,0x0183> a300a0183; (void)a300a0183; + gdcm::Attribute<0x300a,0x0184> a300a0184; (void)a300a0184; + gdcm::Attribute<0x300a,0x0190> a300a0190; (void)a300a0190; + gdcm::Attribute<0x300a,0x0192> a300a0192; (void)a300a0192; + gdcm::Attribute<0x300a,0x0194> a300a0194; (void)a300a0194; + gdcm::Attribute<0x300a,0x0196> a300a0196; (void)a300a0196; + gdcm::Attribute<0x300a,0x0198> a300a0198; (void)a300a0198; + gdcm::Attribute<0x300a,0x0199> a300a0199; (void)a300a0199; + gdcm::Attribute<0x300a,0x019a> a300a019a; (void)a300a019a; + gdcm::Attribute<0x300a,0x01a0> a300a01a0; (void)a300a01a0; + gdcm::Attribute<0x300a,0x01a2> a300a01a2; (void)a300a01a2; + gdcm::Attribute<0x300a,0x01a4> a300a01a4; (void)a300a01a4; + gdcm::Attribute<0x300a,0x01a6> a300a01a6; (void)a300a01a6; + gdcm::Attribute<0x300a,0x01a8> a300a01a8; (void)a300a01a8; + gdcm::Attribute<0x300a,0x01b0> a300a01b0; (void)a300a01b0; + gdcm::Attribute<0x300a,0x01b2> a300a01b2; (void)a300a01b2; + gdcm::Attribute<0x300a,0x01b4> a300a01b4; (void)a300a01b4; + gdcm::Attribute<0x300a,0x01b6> a300a01b6; (void)a300a01b6; + gdcm::Attribute<0x300a,0x01b8> a300a01b8; (void)a300a01b8; + gdcm::Attribute<0x300a,0x01ba> a300a01ba; (void)a300a01ba; + gdcm::Attribute<0x300a,0x01bc> a300a01bc; (void)a300a01bc; + gdcm::Attribute<0x300a,0x01d0> a300a01d0; (void)a300a01d0; + gdcm::Attribute<0x300a,0x01d2> a300a01d2; (void)a300a01d2; + gdcm::Attribute<0x300a,0x01d4> a300a01d4; (void)a300a01d4; + gdcm::Attribute<0x300a,0x01d6> a300a01d6; (void)a300a01d6; + gdcm::Attribute<0x300a,0x0200> a300a0200; (void)a300a0200; + gdcm::Attribute<0x300a,0x0202> a300a0202; (void)a300a0202; + gdcm::Attribute<0x300a,0x0206> a300a0206; (void)a300a0206; + gdcm::Attribute<0x300a,0x0210> a300a0210; (void)a300a0210; + gdcm::Attribute<0x300a,0x0212> a300a0212; (void)a300a0212; + gdcm::Attribute<0x300a,0x0214> a300a0214; (void)a300a0214; + gdcm::Attribute<0x300a,0x0216> a300a0216; (void)a300a0216; + gdcm::Attribute<0x300a,0x0218> a300a0218; (void)a300a0218; + gdcm::Attribute<0x300a,0x021a> a300a021a; (void)a300a021a; + gdcm::Attribute<0x300a,0x0222> a300a0222; (void)a300a0222; + gdcm::Attribute<0x300a,0x0224> a300a0224; (void)a300a0224; + gdcm::Attribute<0x300a,0x0226> a300a0226; (void)a300a0226; + gdcm::Attribute<0x300a,0x0228> a300a0228; (void)a300a0228; + gdcm::Attribute<0x300a,0x0229> a300a0229; (void)a300a0229; + gdcm::Attribute<0x300a,0x022a> a300a022a; (void)a300a022a; + gdcm::Attribute<0x300a,0x022b> a300a022b; (void)a300a022b; + gdcm::Attribute<0x300a,0x022c> a300a022c; (void)a300a022c; + gdcm::Attribute<0x300a,0x022e> a300a022e; (void)a300a022e; + gdcm::Attribute<0x300a,0x0230> a300a0230; (void)a300a0230; + gdcm::Attribute<0x300a,0x0232> a300a0232; (void)a300a0232; + gdcm::Attribute<0x300a,0x0234> a300a0234; (void)a300a0234; + gdcm::Attribute<0x300a,0x0236> a300a0236; (void)a300a0236; + gdcm::Attribute<0x300a,0x0238> a300a0238; (void)a300a0238; + gdcm::Attribute<0x300a,0x0240> a300a0240; (void)a300a0240; + gdcm::Attribute<0x300a,0x0242> a300a0242; (void)a300a0242; + gdcm::Attribute<0x300a,0x0244> a300a0244; (void)a300a0244; + gdcm::Attribute<0x300a,0x0250> a300a0250; (void)a300a0250; + gdcm::Attribute<0x300a,0x0260> a300a0260; (void)a300a0260; + gdcm::Attribute<0x300a,0x0262> a300a0262; (void)a300a0262; + gdcm::Attribute<0x300a,0x0263> a300a0263; (void)a300a0263; + gdcm::Attribute<0x300a,0x0264> a300a0264; (void)a300a0264; + gdcm::Attribute<0x300a,0x0266> a300a0266; (void)a300a0266; + gdcm::Attribute<0x300a,0x026a> a300a026a; (void)a300a026a; + gdcm::Attribute<0x300a,0x026c> a300a026c; (void)a300a026c; + gdcm::Attribute<0x300a,0x0280> a300a0280; (void)a300a0280; + gdcm::Attribute<0x300a,0x0282> a300a0282; (void)a300a0282; + gdcm::Attribute<0x300a,0x0284> a300a0284; (void)a300a0284; + gdcm::Attribute<0x300a,0x0286> a300a0286; (void)a300a0286; + gdcm::Attribute<0x300a,0x0288> a300a0288; (void)a300a0288; + gdcm::Attribute<0x300a,0x028a> a300a028a; (void)a300a028a; + gdcm::Attribute<0x300a,0x028c> a300a028c; (void)a300a028c; + gdcm::Attribute<0x300a,0x0290> a300a0290; (void)a300a0290; + gdcm::Attribute<0x300a,0x0291> a300a0291; (void)a300a0291; + gdcm::Attribute<0x300a,0x0292> a300a0292; (void)a300a0292; + gdcm::Attribute<0x300a,0x0294> a300a0294; (void)a300a0294; + gdcm::Attribute<0x300a,0x0296> a300a0296; (void)a300a0296; + gdcm::Attribute<0x300a,0x0298> a300a0298; (void)a300a0298; + gdcm::Attribute<0x300a,0x029c> a300a029c; (void)a300a029c; + gdcm::Attribute<0x300a,0x029e> a300a029e; (void)a300a029e; + gdcm::Attribute<0x300a,0x02a0> a300a02a0; (void)a300a02a0; + gdcm::Attribute<0x300a,0x02a2> a300a02a2; (void)a300a02a2; + gdcm::Attribute<0x300a,0x02a4> a300a02a4; (void)a300a02a4; + gdcm::Attribute<0x300a,0x02b0> a300a02b0; (void)a300a02b0; + gdcm::Attribute<0x300a,0x02b2> a300a02b2; (void)a300a02b2; + gdcm::Attribute<0x300a,0x02b3> a300a02b3; (void)a300a02b3; + gdcm::Attribute<0x300a,0x02b4> a300a02b4; (void)a300a02b4; + gdcm::Attribute<0x300a,0x02b8> a300a02b8; (void)a300a02b8; + gdcm::Attribute<0x300a,0x02ba> a300a02ba; (void)a300a02ba; + gdcm::Attribute<0x300a,0x02c8> a300a02c8; (void)a300a02c8; + gdcm::Attribute<0x300a,0x02d0> a300a02d0; (void)a300a02d0; + gdcm::Attribute<0x300a,0x02d2> a300a02d2; (void)a300a02d2; + gdcm::Attribute<0x300a,0x02d4> a300a02d4; (void)a300a02d4; + gdcm::Attribute<0x300a,0x02d6> a300a02d6; (void)a300a02d6; + gdcm::Attribute<0x300a,0x02e0> a300a02e0; (void)a300a02e0; + gdcm::Attribute<0x300a,0x02e1> a300a02e1; (void)a300a02e1; + gdcm::Attribute<0x300a,0x02e2> a300a02e2; (void)a300a02e2; + gdcm::Attribute<0x300a,0x02e3> a300a02e3; (void)a300a02e3; + gdcm::Attribute<0x300a,0x02e4> a300a02e4; (void)a300a02e4; + gdcm::Attribute<0x300a,0x02e5> a300a02e5; (void)a300a02e5; + gdcm::Attribute<0x300a,0x02e6> a300a02e6; (void)a300a02e6; + gdcm::Attribute<0x300a,0x02e7> a300a02e7; (void)a300a02e7; + gdcm::Attribute<0x300a,0x02e8> a300a02e8; (void)a300a02e8; + gdcm::Attribute<0x300a,0x02ea> a300a02ea; (void)a300a02ea; + gdcm::Attribute<0x300a,0x02eb> a300a02eb; (void)a300a02eb; + gdcm::Attribute<0x300a,0x0302> a300a0302; (void)a300a0302; + gdcm::Attribute<0x300a,0x0304> a300a0304; (void)a300a0304; + gdcm::Attribute<0x300a,0x0306> a300a0306; (void)a300a0306; + gdcm::Attribute<0x300a,0x0308> a300a0308; (void)a300a0308; + gdcm::Attribute<0x300a,0x030a> a300a030a; (void)a300a030a; + gdcm::Attribute<0x300a,0x030c> a300a030c; (void)a300a030c; + gdcm::Attribute<0x300a,0x030d> a300a030d; (void)a300a030d; + gdcm::Attribute<0x300a,0x030f> a300a030f; (void)a300a030f; + gdcm::Attribute<0x300a,0x0312> a300a0312; (void)a300a0312; + gdcm::Attribute<0x300a,0x0314> a300a0314; (void)a300a0314; + gdcm::Attribute<0x300a,0x0316> a300a0316; (void)a300a0316; + gdcm::Attribute<0x300a,0x0318> a300a0318; (void)a300a0318; + gdcm::Attribute<0x300a,0x0320> a300a0320; (void)a300a0320; + gdcm::Attribute<0x300a,0x0322> a300a0322; (void)a300a0322; + gdcm::Attribute<0x300a,0x0330> a300a0330; (void)a300a0330; + gdcm::Attribute<0x300a,0x0332> a300a0332; (void)a300a0332; + gdcm::Attribute<0x300a,0x0334> a300a0334; (void)a300a0334; + gdcm::Attribute<0x300a,0x0336> a300a0336; (void)a300a0336; + gdcm::Attribute<0x300a,0x0338> a300a0338; (void)a300a0338; + gdcm::Attribute<0x300a,0x033a> a300a033a; (void)a300a033a; + gdcm::Attribute<0x300a,0x033c> a300a033c; (void)a300a033c; + gdcm::Attribute<0x300a,0x0340> a300a0340; (void)a300a0340; + gdcm::Attribute<0x300a,0x0342> a300a0342; (void)a300a0342; + gdcm::Attribute<0x300a,0x0344> a300a0344; (void)a300a0344; + gdcm::Attribute<0x300a,0x0346> a300a0346; (void)a300a0346; + gdcm::Attribute<0x300a,0x0348> a300a0348; (void)a300a0348; + gdcm::Attribute<0x300a,0x034a> a300a034a; (void)a300a034a; + gdcm::Attribute<0x300a,0x034c> a300a034c; (void)a300a034c; + gdcm::Attribute<0x300a,0x0350> a300a0350; (void)a300a0350; + gdcm::Attribute<0x300a,0x0352> a300a0352; (void)a300a0352; + gdcm::Attribute<0x300a,0x0354> a300a0354; (void)a300a0354; + gdcm::Attribute<0x300a,0x0356> a300a0356; (void)a300a0356; + gdcm::Attribute<0x300a,0x0358> a300a0358; (void)a300a0358; + gdcm::Attribute<0x300a,0x035a> a300a035a; (void)a300a035a; + gdcm::Attribute<0x300a,0x0360> a300a0360; (void)a300a0360; + gdcm::Attribute<0x300a,0x0362> a300a0362; (void)a300a0362; + gdcm::Attribute<0x300a,0x0364> a300a0364; (void)a300a0364; + gdcm::Attribute<0x300a,0x0366> a300a0366; (void)a300a0366; + gdcm::Attribute<0x300a,0x0370> a300a0370; (void)a300a0370; + gdcm::Attribute<0x300a,0x0372> a300a0372; (void)a300a0372; + gdcm::Attribute<0x300a,0x0374> a300a0374; (void)a300a0374; + gdcm::Attribute<0x300a,0x0380> a300a0380; (void)a300a0380; + gdcm::Attribute<0x300a,0x0382> a300a0382; (void)a300a0382; + gdcm::Attribute<0x300a,0x0384> a300a0384; (void)a300a0384; + gdcm::Attribute<0x300a,0x0386> a300a0386; (void)a300a0386; + gdcm::Attribute<0x300a,0x0388> a300a0388; (void)a300a0388; + gdcm::Attribute<0x300a,0x038a> a300a038a; (void)a300a038a; + gdcm::Attribute<0x300a,0x0390> a300a0390; (void)a300a0390; + gdcm::Attribute<0x300a,0x0392> a300a0392; (void)a300a0392; + gdcm::Attribute<0x300a,0x0394> a300a0394; (void)a300a0394; + gdcm::Attribute<0x300a,0x0396> a300a0396; (void)a300a0396; + gdcm::Attribute<0x300a,0x0398> a300a0398; (void)a300a0398; + gdcm::Attribute<0x300a,0x039a> a300a039a; (void)a300a039a; + gdcm::Attribute<0x300a,0x03a0> a300a03a0; (void)a300a03a0; + gdcm::Attribute<0x300a,0x03a2> a300a03a2; (void)a300a03a2; + gdcm::Attribute<0x300a,0x03a4> a300a03a4; (void)a300a03a4; + gdcm::Attribute<0x300a,0x03a6> a300a03a6; (void)a300a03a6; + gdcm::Attribute<0x300a,0x03a8> a300a03a8; (void)a300a03a8; + gdcm::Attribute<0x300a,0x03aa> a300a03aa; (void)a300a03aa; + gdcm::Attribute<0x300a,0x03ac> a300a03ac; (void)a300a03ac; + gdcm::Attribute<0x300a,0x0401> a300a0401; (void)a300a0401; + gdcm::Attribute<0x300a,0x0402> a300a0402; (void)a300a0402; + gdcm::Attribute<0x300a,0x0410> a300a0410; (void)a300a0410; + gdcm::Attribute<0x300a,0x0412> a300a0412; (void)a300a0412; + gdcm::Attribute<0x300a,0x0420> a300a0420; (void)a300a0420; + gdcm::Attribute<0x300a,0x0421> a300a0421; (void)a300a0421; + gdcm::Attribute<0x300a,0x0422> a300a0422; (void)a300a0422; + gdcm::Attribute<0x300a,0x0423> a300a0423; (void)a300a0423; + gdcm::Attribute<0x300a,0x0424> a300a0424; (void)a300a0424; + gdcm::Attribute<0x300c,0x0002> a300c0002; (void)a300c0002; + gdcm::Attribute<0x300c,0x0004> a300c0004; (void)a300c0004; + gdcm::Attribute<0x300c,0x0006> a300c0006; (void)a300c0006; + gdcm::Attribute<0x300c,0x0007> a300c0007; (void)a300c0007; + gdcm::Attribute<0x300c,0x0008> a300c0008; (void)a300c0008; + gdcm::Attribute<0x300c,0x0009> a300c0009; (void)a300c0009; + gdcm::Attribute<0x300c,0x000a> a300c000a; (void)a300c000a; + gdcm::Attribute<0x300c,0x000c> a300c000c; (void)a300c000c; + gdcm::Attribute<0x300c,0x000e> a300c000e; (void)a300c000e; + gdcm::Attribute<0x300c,0x0020> a300c0020; (void)a300c0020; + gdcm::Attribute<0x300c,0x0022> a300c0022; (void)a300c0022; + gdcm::Attribute<0x300c,0x0040> a300c0040; (void)a300c0040; + gdcm::Attribute<0x300c,0x0042> a300c0042; (void)a300c0042; + gdcm::Attribute<0x300c,0x0050> a300c0050; (void)a300c0050; + gdcm::Attribute<0x300c,0x0051> a300c0051; (void)a300c0051; + gdcm::Attribute<0x300c,0x0055> a300c0055; (void)a300c0055; + gdcm::Attribute<0x300c,0x0060> a300c0060; (void)a300c0060; + gdcm::Attribute<0x300c,0x006a> a300c006a; (void)a300c006a; + gdcm::Attribute<0x300c,0x0080> a300c0080; (void)a300c0080; + gdcm::Attribute<0x300c,0x00a0> a300c00a0; (void)a300c00a0; + gdcm::Attribute<0x300c,0x00b0> a300c00b0; (void)a300c00b0; + gdcm::Attribute<0x300c,0x00c0> a300c00c0; (void)a300c00c0; + gdcm::Attribute<0x300c,0x00d0> a300c00d0; (void)a300c00d0; + gdcm::Attribute<0x300c,0x00e0> a300c00e0; (void)a300c00e0; + gdcm::Attribute<0x300c,0x00f0> a300c00f0; (void)a300c00f0; + gdcm::Attribute<0x300c,0x00f2> a300c00f2; (void)a300c00f2; + gdcm::Attribute<0x300c,0x00f4> a300c00f4; (void)a300c00f4; + gdcm::Attribute<0x300c,0x00f6> a300c00f6; (void)a300c00f6; + gdcm::Attribute<0x300c,0x0100> a300c0100; (void)a300c0100; + gdcm::Attribute<0x300c,0x0102> a300c0102; (void)a300c0102; + gdcm::Attribute<0x300c,0x0104> a300c0104; (void)a300c0104; + gdcm::Attribute<0x300e,0x0002> a300e0002; (void)a300e0002; + gdcm::Attribute<0x300e,0x0004> a300e0004; (void)a300e0004; + gdcm::Attribute<0x300e,0x0005> a300e0005; (void)a300e0005; + gdcm::Attribute<0x300e,0x0008> a300e0008; (void)a300e0008; + gdcm::Attribute<0x4000,0x0010> a40000010; (void)a40000010; + gdcm::Attribute<0x4000,0x4000> a40004000; (void)a40004000; + gdcm::Attribute<0x4008,0x0040> a40080040; (void)a40080040; + gdcm::Attribute<0x4008,0x0042> a40080042; (void)a40080042; + gdcm::Attribute<0x4008,0x0050> a40080050; (void)a40080050; + gdcm::Attribute<0x4008,0x0100> a40080100; (void)a40080100; + gdcm::Attribute<0x4008,0x0101> a40080101; (void)a40080101; + gdcm::Attribute<0x4008,0x0102> a40080102; (void)a40080102; + gdcm::Attribute<0x4008,0x0103> a40080103; (void)a40080103; + gdcm::Attribute<0x4008,0x0108> a40080108; (void)a40080108; + gdcm::Attribute<0x4008,0x0109> a40080109; (void)a40080109; + gdcm::Attribute<0x4008,0x010a> a4008010a; (void)a4008010a; + gdcm::Attribute<0x4008,0x010b> a4008010b; (void)a4008010b; + gdcm::Attribute<0x4008,0x010c> a4008010c; (void)a4008010c; + gdcm::Attribute<0x4008,0x0111> a40080111; (void)a40080111; + gdcm::Attribute<0x4008,0x0112> a40080112; (void)a40080112; + gdcm::Attribute<0x4008,0x0113> a40080113; (void)a40080113; + gdcm::Attribute<0x4008,0x0114> a40080114; (void)a40080114; + gdcm::Attribute<0x4008,0x0115> a40080115; (void)a40080115; + gdcm::Attribute<0x4008,0x0117> a40080117; (void)a40080117; + gdcm::Attribute<0x4008,0x0118> a40080118; (void)a40080118; + gdcm::Attribute<0x4008,0x0119> a40080119; (void)a40080119; + gdcm::Attribute<0x4008,0x011a> a4008011a; (void)a4008011a; + gdcm::Attribute<0x4008,0x0200> a40080200; (void)a40080200; + gdcm::Attribute<0x4008,0x0202> a40080202; (void)a40080202; + gdcm::Attribute<0x4008,0x0210> a40080210; (void)a40080210; + gdcm::Attribute<0x4008,0x0212> a40080212; (void)a40080212; + gdcm::Attribute<0x4008,0x0300> a40080300; (void)a40080300; + gdcm::Attribute<0x4008,0x4000> a40084000; (void)a40084000; + gdcm::Attribute<0x4ffe,0x0001> a4ffe0001; (void)a4ffe0001; + gdcm::Attribute<0x5000,0x0005> a50000005; (void)a50000005; + gdcm::Attribute<0x5000,0x0010> a50000010; (void)a50000010; + gdcm::Attribute<0x5000,0x0020> a50000020; (void)a50000020; + gdcm::Attribute<0x5000,0x0022> a50000022; (void)a50000022; + gdcm::Attribute<0x5000,0x0030> a50000030; (void)a50000030; + gdcm::Attribute<0x5000,0x0040> a50000040; (void)a50000040; + gdcm::Attribute<0x5000,0x0103> a50000103; (void)a50000103; + gdcm::Attribute<0x5000,0x0104> a50000104; (void)a50000104; + gdcm::Attribute<0x5000,0x0105> a50000105; (void)a50000105; + gdcm::Attribute<0x5000,0x0106> a50000106; (void)a50000106; + gdcm::Attribute<0x5000,0x0110> a50000110; (void)a50000110; + gdcm::Attribute<0x5000,0x0112> a50000112; (void)a50000112; + gdcm::Attribute<0x5000,0x0114> a50000114; (void)a50000114; + gdcm::Attribute<0x5000,0x1001> a50001001; (void)a50001001; + gdcm::Attribute<0x5000,0x2000> a50002000; (void)a50002000; + gdcm::Attribute<0x5000,0x2002> a50002002; (void)a50002002; + gdcm::Attribute<0x5000,0x2004> a50002004; (void)a50002004; + gdcm::Attribute<0x5000,0x2006> a50002006; (void)a50002006; + gdcm::Attribute<0x5000,0x2008> a50002008; (void)a50002008; + gdcm::Attribute<0x5000,0x200a> a5000200a; (void)a5000200a; + gdcm::Attribute<0x5000,0x200e> a5000200e; (void)a5000200e; + gdcm::Attribute<0x5000,0x2500> a50002500; (void)a50002500; + gdcm::Attribute<0x5000,0x2600> a50002600; (void)a50002600; + gdcm::Attribute<0x5000,0x2610> a50002610; (void)a50002610; + gdcm::Attribute<0x5200,0x9229> a52009229; (void)a52009229; + gdcm::Attribute<0x5200,0x9230> a52009230; (void)a52009230; + gdcm::Attribute<0x5400,0x0100> a54000100; (void)a54000100; + gdcm::Attribute<0x5400,0x1004> a54001004; (void)a54001004; + gdcm::Attribute<0x5400,0x1006> a54001006; (void)a54001006; + gdcm::Attribute<0x5600,0x0010> a56000010; (void)a56000010; + gdcm::Attribute<0x5600,0x0020> a56000020; (void)a56000020; + gdcm::Attribute<0x6000,0x0010> a60000010; (void)a60000010; + gdcm::Attribute<0x6000,0x0011> a60000011; (void)a60000011; + gdcm::Attribute<0x6000,0x0012> a60000012; (void)a60000012; + gdcm::Attribute<0x6000,0x0015> a60000015; (void)a60000015; + gdcm::Attribute<0x6000,0x0022> a60000022; (void)a60000022; + gdcm::Attribute<0x6000,0x0040> a60000040; (void)a60000040; + gdcm::Attribute<0x6000,0x0045> a60000045; (void)a60000045; + gdcm::Attribute<0x6000,0x0050> a60000050; (void)a60000050; + gdcm::Attribute<0x6000,0x0051> a60000051; (void)a60000051; + gdcm::Attribute<0x6000,0x0052> a60000052; (void)a60000052; + gdcm::Attribute<0x6000,0x0060> a60000060; (void)a60000060; + gdcm::Attribute<0x6000,0x0061> a60000061; (void)a60000061; + gdcm::Attribute<0x6000,0x0062> a60000062; (void)a60000062; + gdcm::Attribute<0x6000,0x0063> a60000063; (void)a60000063; + gdcm::Attribute<0x6000,0x0066> a60000066; (void)a60000066; + gdcm::Attribute<0x6000,0x0068> a60000068; (void)a60000068; + gdcm::Attribute<0x6000,0x0069> a60000069; (void)a60000069; + gdcm::Attribute<0x6000,0x0100> a60000100; (void)a60000100; + gdcm::Attribute<0x6000,0x0102> a60000102; (void)a60000102; + gdcm::Attribute<0x6000,0x0110> a60000110; (void)a60000110; + gdcm::Attribute<0x6000,0x0200> a60000200; (void)a60000200; + gdcm::Attribute<0x6000,0x0800> a60000800; (void)a60000800; + gdcm::Attribute<0x6000,0x0802> a60000802; (void)a60000802; + gdcm::Attribute<0x6000,0x0803> a60000803; (void)a60000803; + gdcm::Attribute<0x6000,0x0804> a60000804; (void)a60000804; + gdcm::Attribute<0x6000,0x1001> a60001001; (void)a60001001; + gdcm::Attribute<0x6000,0x1100> a60001100; (void)a60001100; + gdcm::Attribute<0x6000,0x1101> a60001101; (void)a60001101; + gdcm::Attribute<0x6000,0x1102> a60001102; (void)a60001102; + gdcm::Attribute<0x6000,0x1103> a60001103; (void)a60001103; + gdcm::Attribute<0x6000,0x1200> a60001200; (void)a60001200; + gdcm::Attribute<0x6000,0x1201> a60001201; (void)a60001201; + gdcm::Attribute<0x6000,0x1202> a60001202; (void)a60001202; + gdcm::Attribute<0x6000,0x1203> a60001203; (void)a60001203; + gdcm::Attribute<0x6000,0x1301> a60001301; (void)a60001301; + gdcm::Attribute<0x6000,0x1302> a60001302; (void)a60001302; + gdcm::Attribute<0x6000,0x1303> a60001303; (void)a60001303; + gdcm::Attribute<0x6000,0x1500> a60001500; (void)a60001500; + gdcm::Attribute<0x6000,0x4000> a60004000; (void)a60004000; + gdcm::Attribute<0x7fe0,0x0020> a7fe00020; (void)a7fe00020; + gdcm::Attribute<0x7fe0,0x0030> a7fe00030; (void)a7fe00030; + gdcm::Attribute<0x7fe0,0x0040> a7fe00040; (void)a7fe00040; + gdcm::Attribute<0x7f00,0x0011> a7f000011; (void)a7f000011; + gdcm::Attribute<0x7f00,0x0020> a7f000020; (void)a7f000020; + gdcm::Attribute<0x7f00,0x0030> a7f000030; (void)a7f000030; + gdcm::Attribute<0x7f00,0x0040> a7f000040; (void)a7f000040; + gdcm::Attribute<0xfffa,0xfffa> afffafffa; (void)afffafffa; + gdcm::Attribute<0xfffc,0xfffc> afffcfffc; (void)afffcfffc; + + return 0; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestAttribute.xsl b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestAttribute.xsl new file mode 100644 index 0000000..bbe68cd --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestAttribute.xsl @@ -0,0 +1,64 @@ + + + + + + + + +// GENERATED FILE DO NOT EDIT +// $ xsltproc TestAttribute.xsl DICOMV3.xml > TestAttribute.cxx + +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#include "gdcmAttribute.h" + +int TestAttribute(int, char *[]) +{ + + + + + + gdcm::Attribute<0x + + ,0x + + > + + ; (void) + + ; + + + + + return 0; +} + + + diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestAttribute1.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestAttribute1.cxx new file mode 100644 index 0000000..a91ad5e --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestAttribute1.cxx @@ -0,0 +1,249 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmAttribute.h" + +#include +#include // fabs + +int TestAttributeAE() { return 0; } +int TestAttributeAS() { return 0; } +int TestAttributeAT() { return 0; } + +/* +int TestAttributeCS() +{ + // (0008,9007) CS [ORIGINAL\PRIMARY\T1\NONE] # 24, 4 FrameType + static const char* values[] = {"ORIGINAL","PRIMARY","T1","NONE"}; + static const char* newvalues[] = {"DERIVED","SECONDARY","T2","ALL"}; + const unsigned int numvalues = sizeof(values) / sizeof(values[0]); + if( numvalues != 4 ) return 1; + + gdcm::Attribute<0x0008,0x9007> it = {"ORIGINAL","PRIMARY","T1","NONE"}; + // FIXME HARDCODED: + if( it.GetVM() != gdcm::VM::VM4 ) return 1; + if( it.GetVR() != gdcm::VR::CS ) return 1; + // END FIXME + + if( it.GetNumberOfValues() != numvalues ) return 1; + + for(unsigned int i = 0; i < numvalues; ++i) + if( it.GetValue(i) != values[i] ) return 1; + + it.Print( std::cout ); + std::cout << std::endl; + + gdcm::DataElement de = it.GetAsDataElement(); + std::cout << de << std::endl; + + // new values: + // Using implicit cstor of gdcm::String from const char * + for(unsigned int i = 0; i < numvalues; ++i) + it.SetValue( newvalues[i], i ); + if( it.GetNumberOfValues() != numvalues ) return 1; + + for(unsigned int i = 0; i < numvalues; ++i) + if( it.GetValue(i) != newvalues[i] ) return 1; + + // const char * is not a gdcm::String, need an array of gdcm::String + static const gdcm::String<> newvalues2[] = {"DERIVED","SECONDARY","T2","ALL"}; + const unsigned int numnewvalues2 = sizeof(newvalues2) / sizeof(newvalues2[0]); + it.SetValues( newvalues2 ); + + it.Print( std::cout ); + std::cout << std::endl; + + de = it.GetAsDataElement(); + std::cout << de << std::endl; + + // (0008,0008) CS [DERIVED\PRIMARY\AXIAL] # 22, 3 ImageType + gdcm::Attribute<0x0008,0x0008> it1; + if( it1.GetVM() != gdcm::VM::VM2_n ) + { + std::cerr << "Wrong VM:" << it1.GetVM() << std::endl; + return 1; + } + it1.SetValues( newvalues2, numnewvalues2 ); + + it1.Print( std::cout ); + std::cout << std::endl; + + de = it1.GetAsDataElement(); + std::cout << de << std::endl; + + // redo the same but this time copy the values: + it1.SetValues( newvalues2, numnewvalues2, true ); + + it1.Print( std::cout ); + std::cout << std::endl; + + de = it1.GetAsDataElement(); + std::cout << de << std::endl; + + return 0; +} +*/ + +int TestAttributeDA() { return 0; } + +int TestAttributeDS() +{ + // (0020,0032) DS [-158.135803\-179.035797\-75.699997] # 34, 3 ImagePositionPatient + const double values[] = {-158.135803,-179.035797,-75.699997}; + const double newvalues[] = {12.34,56.78,90.0}; + const unsigned int numvalues = sizeof(values) / sizeof(values[0]); + + gdcm::Attribute<0x0020,0x0032> ipp = {{-158.135803,-179.035797,-75.699997}}; + // FIXME HARDCODED: + if( ipp.GetVM() != gdcm::VM::VM3 ) return 1; + if( ipp.GetVR() != gdcm::VR::DS ) return 1; + // END FIXME + if( ipp.GetNumberOfValues() != numvalues ) return 1; + + for(unsigned int i = 0; i < numvalues; ++i) + if( fabs(ipp.GetValue(i) - values[i]) > std::numeric_limits::epsilon() ) return 1; + + ipp.Print( std::cout ); + std::cout << std::endl; + + gdcm::DataElement de = ipp.GetAsDataElement(); + std::cout << de << std::endl; + + // new values: + ipp.SetValues( newvalues ); + if( ipp.GetNumberOfValues() != numvalues ) return 1; + + for(unsigned int i = 0; i < numvalues; ++i) + if( fabs(ipp.GetValue(i) - newvalues[i]) > std::numeric_limits::epsilon() ) return 1; + + ipp.Print( std::cout ); + std::cout << std::endl; + + de = ipp.GetAsDataElement(); + std::cout << de << std::endl; + +{ + //const char v[] = "0.960000000000662 "; // not working + const char v[] = "1.960000000000662 "; + gdcm::DataElement invalid( gdcm::Tag(0x10,0x1030) ); // Patient's Weight + invalid.SetVR( gdcm::VR::DS ); + invalid.SetByteValue( v, (uint32_t)strlen(v) ); + + gdcm::Attribute<0x0010,0x1030> pw; + pw.SetFromDataElement( invalid ); + + gdcm::DataElement valid = pw.GetAsDataElement(); + std::ostringstream os; + os << valid.GetValue(); + size_t l = os.str().size(); + if( l > 16 ) + { + return 1; + } + + +} + + return 0; +} + +int TestAttributeDT() { return 0; } +int TestAttributeFL() { return 0; } +int TestAttributeFD() { return 0; } +int TestAttributeIS() +{ + // + // This case is slightly more complex it is up to the user to say what is the VM: + gdcm::Attribute<0x0018,0x1182, gdcm::VR::IS, gdcm::VM::VM1> fd1 = {0}; + if( fd1.GetVM() != gdcm::VM::VM1 ) return 1; + + gdcm::Attribute<0x0018,0x1182, gdcm::VR::IS, gdcm::VM::VM2> fd2 = {{0,1}}; + if( fd2.GetVM() != gdcm::VM::VM2 ) return 1; + + // this one should not be allowed, I need a special CTest macro... + //gdcm::Attribute<0x0018,0x1182, gdcm::VR::IS, gdcm::VM::VM3> fd3 = {0,1}; + //return 1; + + return 0; +} + +int TestAttributeLO() { return 0; } +int TestAttributeLT() { return 0; } +int TestAttributeOB() { return 0; } +int TestAttributeOF() +{ + gdcm::DataSet ds; + const float array[] = { 0, 1, 2, 3, 4 }; + gdcm::Attribute<0x5600,0x0020, gdcm::VR::OF, gdcm::VM::VM1_n> at; + at.SetValues( array, sizeof( array ) / sizeof( *array ) ); + ds.Insert( at.GetAsDataElement() ); + + if( at.GetNumberOfValues() != 5 ) return 1; + + // Sup 132 + // Tag : (0x0066,0x0016), VR : OF, VM : 1, Type : 1 + gdcm::Attribute<0x0066,0x0016> at1; + float value = 1.f; + at1.SetValue( value ); + ds.Insert( at1.GetAsDataElement() ); + + return 0; +} +int TestAttributeOW() { return 0; } +int TestAttributePN() { return 0; } +int TestAttributeSH() { return 0; } +int TestAttributeSL() { return 0; } +int TestAttributeSQ() { return 0; } +int TestAttributeSS() { return 0; } +int TestAttributeST() { return 0; } +int TestAttributeTM() { return 0; } +int TestAttributeUI() { return 0; } +int TestAttributeUL() { return 0; } +int TestAttributeUN() { return 0; } +int TestAttributeUS() { return 0; } +int TestAttributeUT() { return 0; } + + +int TestAttribute1(int , char *[]) +{ + int numerrors = 0; + numerrors += TestAttributeAE(); + numerrors += TestAttributeAS(); + numerrors += TestAttributeAT(); + //numerrors += TestAttributeCS(); + numerrors += TestAttributeDA(); + numerrors += TestAttributeDS(); + numerrors += TestAttributeDT(); + numerrors += TestAttributeFL(); + numerrors += TestAttributeFD(); + numerrors += TestAttributeIS(); + numerrors += TestAttributeLO(); + numerrors += TestAttributeLT(); + numerrors += TestAttributeOB(); + numerrors += TestAttributeOF(); + numerrors += TestAttributeOW(); + numerrors += TestAttributePN(); + numerrors += TestAttributeSH(); + numerrors += TestAttributeSL(); + numerrors += TestAttributeSQ(); + numerrors += TestAttributeSS(); + numerrors += TestAttributeST(); + numerrors += TestAttributeTM(); + numerrors += TestAttributeUI(); + numerrors += TestAttributeUL(); + numerrors += TestAttributeUN(); + numerrors += TestAttributeUS(); + numerrors += TestAttributeUT(); + + return numerrors; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestAttribute2.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestAttribute2.cxx new file mode 100644 index 0000000..df28b31 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestAttribute2.cxx @@ -0,0 +1,112 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmAttribute.h" + +/* + (0008,0000) UL 38 + (0008,0001) UL 262302 + (0008,0010) LO [ACRNEMA_LIBIDO_1.1] + (0028,0000) UL 100 + (0028,0005) US 2 + (0028,0010) US 512 + (0028,0011) US 512 + (0028,0015) ?? 00\00 + (0028,0016) ?? 00\00 + (0028,0100) US 8 + (0028,0101) US 8 + (0028,0102) US 7 + (0028,0103) US 0 + (0028,0199) ?? 70\00 + (7fe0,0000) UL 262152 + (7fe0,0010) OW ea00\eaea\e9e9\e9e9\e9e9\e +*/ + + +int main(int argc, char *argv[]) +{ + const char *filename; + if( argc < 2 ) + { + filename = "/tmp/dummy.dcm"; + } + else + { + filename = argv[1]; + } + //std::cout << "Reading: " << filename << std::endl; + std::ifstream is(filename, std::ios::binary ); + + gdcm::Attribute<0x0008,0x0000, gdcm::VR::UL, gdcm::VM::VM1> a; + a.Read(is); + a.Print( std::cout << std::endl ); + gdcm::Attribute<0x0008,0x0001, gdcm::VR::UL, gdcm::VM::VM1> b; + b.Read(is); + b.Print( std::cout << std::endl ); + gdcm::Attribute<0x0008,0x0010, gdcm::VR::LO, gdcm::VM::VM24> c = {}; + c.Read(is); + c.Print( std::cout << std::endl ); + gdcm::Attribute<0x0028,0x0000, gdcm::VR::UL, gdcm::VM::VM1> d; + d.Read(is); + d.Print( std::cout << std::endl ); + gdcm::Attribute<0x0028,0x0005, gdcm::VR::US, gdcm::VM::VM1> e; + e.Read(is); + e.Print( std::cout << std::endl ); + gdcm::Attribute<0x0028,0x0010, gdcm::VR::US, gdcm::VM::VM1> f; + f.Read(is); + f.Print( std::cout << std::endl ); + gdcm::Attribute<0x0028,0x0011, gdcm::VR::US, gdcm::VM::VM1> g; + g.Read(is); + g.Print( std::cout << std::endl ); + +// 0028 0015 US 1 UsedNbX ACR Special (RET) +// 0028 0016 US 1 UsedNbY ACR Special (RET) + + gdcm::Attribute<0x0028,0x0015, gdcm::VR::US, gdcm::VM::VM1> h; + h.Read(is); + h.Print( std::cout << std::endl ); + gdcm::Attribute<0x0028,0x0016, gdcm::VR::US, gdcm::VM::VM1> i; + i.Read(is); + i.Print( std::cout << std::endl ); + gdcm::Attribute<0x0028,0x0100, gdcm::VR::US, gdcm::VM::VM1> j; + j.Read(is); + j.Print( std::cout << std::endl ); + gdcm::Attribute<0x0028,0x0101, gdcm::VR::US, gdcm::VM::VM1> k; + k.Read(is); + k.Print( std::cout << std::endl ); + gdcm::Attribute<0x0028,0x0102, gdcm::VR::US, gdcm::VM::VM1> l; + l.Read(is); + l.Print( std::cout << std::endl ); + gdcm::Attribute<0x0028,0x0103, gdcm::VR::US, gdcm::VM::VM1> m; + m.Read(is); + m.Print( std::cout << std::endl ); +// 0028 0199 US 1 Special Code (RET) + gdcm::Attribute<0x0028,0x0199, gdcm::VR::US, gdcm::VM::VM1> n; + n.Read(is); + n.Print( std::cout << std::endl ); + gdcm::Attribute<0x7fe0,0x0000, gdcm::VR::UL, gdcm::VM::VM1> o; + o.Read(is); + o.Print( std::cout << std::endl ); + gdcm::Attribute<0x7fe0,0x0010, gdcm::VR::OW, gdcm::VM::VM1> p; + // + char bytes[512*512]; + p.SetBytes(bytes, 512*512); + p.Read(is); + p.Print( std::cout << std::endl ); + + std::streampos pos = is.tellg(); + std::cout << "Pos=" << (int)pos << std::endl; + is.close(); + + return 0; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestAttribute3.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestAttribute3.cxx new file mode 100644 index 0000000..504f672 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestAttribute3.cxx @@ -0,0 +1,69 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmAttribute.h" + +int main(int argc, char *argv[]) +{ + gdcm::Attribute<0x0008,0x0000> a = { 38 }; + a.Print( std::cout << std::endl ); + + gdcm::Attribute<0x0018,0x106c> b = { 123, 456 }; + b.Print( std::cout << std::endl ); + + gdcm::Attribute<0x0018,0x1624> c = { 123, 456, 789 }; + c.Print( std::cout << std::endl ); + + gdcm::Attribute<0x0072,0x0108> d = { 1.2, 3.4, 5.6, 7.8 }; + d.Print( std::cout << std::endl ); + + gdcm::Attribute<0x3002,0x0010> e = { 1.2, 3.4, 5.6, 7.8, 9.0, 10. }; + e.Print( std::cout << std::endl ); + + gdcm::Attribute<0x0018,0x1149, gdcm::VR::IS, gdcm::VM::VM2> f = { 12 , 13 }; + f.Print( std::cout << std::endl ); + + gdcm::Attribute<0x0018,0x1149, gdcm::VR::IS, gdcm::VM::VM1> g = { 12 }; + g.Print( std::cout << std::endl ); + + // grrrr.... too dangerous for users + gdcm::Attribute<0x0018,0x1149, gdcm::VR::IS, gdcm::VM::VM1 > h = { 12 }; + h.Print( std::cout << std::endl ); + + typedef gdcm::Attribute<0x3002,0x0010>::ArrayType type; + const type &val = e.GetValue(2); + std::cout << std::endl << "val=" << val; + e.SetValue( 123.456, 2 ); + std::cout << std::endl << "val=" << val; + + // gdcm::Attribute<0x3002,0x0010>::VMType == 6, let's check that: + const type my[ gdcm::Attribute<0x3002,0x0010>::VMType ] = { 1.2 }; + e.SetValues( my ); + e.Print( std::cout << std::endl ); + + + // TODO: +// gdcm::Attribute<0x0002,0x0001> i = { '0', '1' }; +// i.Print( std::cout << std::endl ); + + gdcm::Attribute<0x0002, 0x0002> m1 = { "1.2.840.10008.5.1.4.1.1.2" }; + m1.Print( std::cout << std::endl ); + gdcm::Attribute<0x0008, 0x0016> m2 = { "1.2.840.10008.5.1.4.1.1.3" }; + m2.Print( std::cout << std::endl ); + m1.SetValues( m2.GetValues() ); // copy all the 64+1 char + m1.Print( std::cout << std::endl ); + + std::cout << std::endl; + + return 0; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestAttribute4.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestAttribute4.cxx new file mode 100644 index 0000000..cea5563 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestAttribute4.cxx @@ -0,0 +1,41 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmAttribute.h" + +int main() +{ + gdcm::Attribute<0x0018,0x1182, gdcm::VR::IS, gdcm::VM::VM1> fd = {0}; + fd.Print( std::cout ); + +/* + bool b = gdcm::VR::OB & gdcm::VR::UL; + std::cout << b << std::endl; + + gdcm::VR vr = fd.GetVR(); + gdcm::VR dictvr = fd.GetDictVR(); + b = vr & dictvr; + std::cout << vr << " " << dictvr << std::endl; + std::cout << b << std::endl; + + gdcm::VM vm = fd.GetVM(); + gdcm::VM dictvm = fd.GetDictVM(); + b = vm & dictvm; + std::cout << vm << " " << dictvm << std::endl; + std::cout << b << std::endl; + + // Let's if we can construct a private element: + gdcm::Attribute<0x1233,0x5678, gdcm::VR::IS, gdcm::VM::VM1> fd2 = {0}; +*/ + return 0; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestAttribute5.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestAttribute5.cxx new file mode 100644 index 0000000..ba1c146 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestAttribute5.cxx @@ -0,0 +1,128 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmAttribute.h" + +/* + (0008,0000) UL 38 + (0008,0001) UL 262302 + (0008,0010) LO [ACRNEMA_LIBIDO_1.1] + (0028,0000) UL 100 + (0028,0005) US 2 + (0028,0010) US 512 + (0028,0011) US 512 + (0028,0015) ?? 00\00 + (0028,0016) ?? 00\00 + (0028,0100) US 8 + (0028,0101) US 8 + (0028,0102) US 7 + (0028,0103) US 0 + (0028,0199) ?? 70\00 + (7fe0,0000) UL 262152 + (7fe0,0010) OW ea00\eaea\e9e9\e9e9\e9e9\e +*/ + + +struct dummy { + int u; + char v[5]; +}; + +int TestAttribute(int argc, char *argv[]) +{ + + dummy du = { 2, "date" }; + + const char *filename; + if( argc < 2 ) + { + filename = "/tmp/dummy.dcm"; + } + else + { + filename = argv[1]; + } + std::ofstream os(filename, std::ios::binary); + + //gdcm::Attribute<0x0008,0x0000, gdcm::VR::UL, gdcm::VM::VM1> a = { 38 }; + gdcm::Attribute<0x0008,0x0000> a = { 38 }; + a.Print( std::cout << std::endl ); + a.Write(os); + gdcm::Attribute<0x0008,0x0001, gdcm::VR::UL, gdcm::VM::VM1> b = { 262302 }; + b.Print( std::cout << std::endl ); + b.Write(os); + gdcm::Attribute<0x0008,0x0010, gdcm::VR::LO, gdcm::VM::VM1> c = { "ACRNEMA_LIBIDO_1.1" }; + c.Print( std::cout << std::endl ); + c.Write(os); + +// 0008 0082 SQ 1 Institution Code Sequence + gdcm::Attribute<0x0008,0x0082, gdcm::VR::SQ, gdcm::VM::VM1, + gdcm::Attribute<0x0008,0x0080, gdcm::VR::LO> + > sq = { + "Institution Name" + }; + sq.Print( std::cout << std::endl ); + sq.Write(os); + + gdcm::Attribute<0x0028,0x0000, gdcm::VR::UL, gdcm::VM::VM1> d = { 100 }; + d.Print( std::cout << std::endl ); + d.Write(os); + gdcm::Attribute<0x0028,0x0005, gdcm::VR::US, gdcm::VM::VM1> e = { 2 }; + e.Print( std::cout << std::endl ); + e.Write(os); + gdcm::Attribute<0x0028,0x0010, gdcm::VR::US, gdcm::VM::VM1> f = { 512 }; + f.Print( std::cout << std::endl ); + f.Write(os); + gdcm::Attribute<0x0028,0x0011, gdcm::VR::US, gdcm::VM::VM1> g = { 512 }; + g.Print( std::cout << std::endl ); + g.Write(os); + +// 0028 0015 US 1 UsedNbX ACR Special (RET) +// 0028 0016 US 1 UsedNbY ACR Special (RET) + + gdcm::Attribute<0x0028,0x0015, gdcm::VR::US, gdcm::VM::VM1> h = { 0 }; + h.Print( std::cout << std::endl ); + h.Write(os); + gdcm::Attribute<0x0028,0x0016, gdcm::VR::US, gdcm::VM::VM1> i = { 0 }; + i.Print( std::cout << std::endl ); + i.Write(os); + gdcm::Attribute<0x0028,0x0100, gdcm::VR::US, gdcm::VM::VM1> j = { 8 }; + j.Print( std::cout << std::endl ); + j.Write(os); + gdcm::Attribute<0x0028,0x0101, gdcm::VR::US, gdcm::VM::VM1> k = { 8 }; + k.Print( std::cout << std::endl ); + k.Write(os); + gdcm::Attribute<0x0028,0x0102, gdcm::VR::US, gdcm::VM::VM1> l = { 7 }; + l.Print( std::cout << std::endl ); + l.Write(os); + gdcm::Attribute<0x0028,0x0103, gdcm::VR::US, gdcm::VM::VM1> m = { 0 }; + m.Print( std::cout << std::endl ); + m.Write(os); +// 0028 0199 US 1 Special Code (RET) + gdcm::Attribute<0x0028,0x0199, gdcm::VR::US, gdcm::VM::VM1> n = { 112 }; + n.Print( std::cout << std::endl ); + n.Write(os); + gdcm::Attribute<0x7fe0,0x0000, gdcm::VR::UL, gdcm::VM::VM1> o = { 262152 }; + o.Print( std::cout << std::endl ); + o.Write(os); + gdcm::Attribute<0x7fe0,0x0010, gdcm::VR::OW, gdcm::VM::VM1> p; + // + char bytes[512*512] = {}; + p.SetBytes(bytes, 512*512); + p.Print( std::cout << std::endl ); + p.Write(os); + + os.close(); + + return 0; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestAttribute6.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestAttribute6.cxx new file mode 100644 index 0000000..cea5563 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestAttribute6.cxx @@ -0,0 +1,41 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmAttribute.h" + +int main() +{ + gdcm::Attribute<0x0018,0x1182, gdcm::VR::IS, gdcm::VM::VM1> fd = {0}; + fd.Print( std::cout ); + +/* + bool b = gdcm::VR::OB & gdcm::VR::UL; + std::cout << b << std::endl; + + gdcm::VR vr = fd.GetVR(); + gdcm::VR dictvr = fd.GetDictVR(); + b = vr & dictvr; + std::cout << vr << " " << dictvr << std::endl; + std::cout << b << std::endl; + + gdcm::VM vm = fd.GetVM(); + gdcm::VM dictvm = fd.GetDictVM(); + b = vm & dictvm; + std::cout << vm << " " << dictvm << std::endl; + std::cout << b << std::endl; + + // Let's if we can construct a private element: + gdcm::Attribute<0x1233,0x5678, gdcm::VR::IS, gdcm::VM::VM1> fd2 = {0}; +*/ + return 0; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestAttribute7.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestAttribute7.cxx new file mode 100644 index 0000000..4b17670 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestAttribute7.cxx @@ -0,0 +1,33 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmAttribute.h" + +int TestAttribute7(int, char *[]) +{ + const char bytes[] = "\030\000e\020"; + gdcm::DataElement de( gdcm::Tag(0x28,0x9) ); + de.SetVR( gdcm::VR::INVALID ); + de.SetByteValue( bytes, 4 ); + + gdcm::Attribute<0x28,0x9, gdcm::VR::AT, gdcm::VM::VM1 > at; + at.SetFromDataElement( de ); + std::cout << at.GetValue() << std::endl; + + gdcm::Attribute<0x3004, 0x0014> tissue; + //std::cout << tissue.GetVR() << std::endl; + if( tissue.GetVR() != gdcm::VR::CS ) return 1; + + + return 0; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestAttribute8.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestAttribute8.cxx new file mode 100644 index 0000000..a1d14a1 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestAttribute8.cxx @@ -0,0 +1,80 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmAttribute.h" +#include "gdcmReader.h" +#include "gdcmFileMetaInformation.h" +#include "gdcmFile.h" +#include "gdcmTesting.h" +#include "gdcmMediaStorage.h" + +/* + * Contributed by Michele Bosi on gdcm-dev ML + */ +int TestAttribute8Func(const char *filename, bool verbose = false) +{ + if( verbose ) + std::cout << "TestRead: " << filename << std::endl; + + gdcm::Reader reader; + reader.SetFileName( filename ); + if ( !reader.Read() ) + { + std::cerr << "TestReadError: Failed to read: " << filename << std::endl; + return 1; + } + + //const gdcm::FileMetaInformation &h = reader.GetFile().GetHeader(); + //h is unused + //std::cout << h << std::endl; + + const gdcm::DataSet &ds = reader.GetFile().GetDataSet(); + +// gdcm::DataSet& ds = file.GetDataSet(); + + gdcm::Attribute<0x28,0x1050> win_center; + const gdcm::DataElement& de = ds.GetDataElement( win_center.GetTag() ); + if(!de.IsEmpty()) + { + win_center.SetFromDataElement( de ); + std::cout << win_center.GetNumberOfValues() << ": "; + for( unsigned int i = 0; i < win_center.GetNumberOfValues(); ++i) + std::cout << win_center[i] << ","; + } + std::cout << std::endl; + + return 0; +} + +int TestAttribute8(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestAttribute8Func(filename, true); + } + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestAttribute8Func( filename ); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestBasicOffsetTable.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestBasicOffsetTable.cxx new file mode 100644 index 0000000..9ddee95 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestBasicOffsetTable.cxx @@ -0,0 +1,20 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmBasicOffsetTable.h" + +int TestBasicOffsetTable(int, char *[]) +{ + gdcm::BasicOffsetTable bot; + return 0; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestByteBuffer.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestByteBuffer.cxx new file mode 100644 index 0000000..3d89a45 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestByteBuffer.cxx @@ -0,0 +1,55 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmByteBuffer.h" +#include + +int TestByteBuffer(int, char *[]) +{ + const int size = 128; + gdcm::ByteBuffer b; + char buffer[size]; + + int r = 0; + for(int i=-size; i<0; ++i) + { + buffer[i+size] = (char)(i); + } + memcpy(b.Get(size), buffer, size); + const char *start = b.GetStart(); + for(int i=size; i>0; --i) + { + if( (int)start[size-i] != -i ) + { + std::cout << (int)start[size-i] << " " << -i << std::endl; + ++r; + } + } + + for(int i=0; i( ss ); + std::cout << bv2 << std::endl; + if( memcmp(bv2.GetPointer(), array, len ) != 0 ) + { + return 1; + } + if( !(bv1 == bv2) ) + { + return 1; + } + + gdcm::ByteValue bv3(bv2); + if( memcmp(bv3.GetPointer(), array, len ) != 0 ) + { + return 1; + } + if( !(bv3 == bv1) ) + { + return 1; + } + gdcm::ByteValue bv4 = bv3; + if( memcmp(bv4.GetPointer(), array, len ) != 0 ) + { + return 1; + } + if( !(bv4 == bv1) ) + { + return 1; + } + gdcm::ByteValue bv5; + if( bv5 == bv1 ) + { + return 1; + } + + return 0; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestCSAElement.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestCSAElement.cxx new file mode 100644 index 0000000..6b45d31 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestCSAElement.cxx @@ -0,0 +1,21 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmCSAElement.h" + +int TestCSAElement(int , char * []) +{ + gdcm::CSAElement el; + + return 0; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestCSAHeader.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestCSAHeader.cxx new file mode 100644 index 0000000..be3e2c7 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestCSAHeader.cxx @@ -0,0 +1,31 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmCSAHeader.h" + +int TestCSAHeader(int , char * []) +{ + gdcm::CSAHeader h; +/* + try + { + const gdcm::CSAElement &foo = csa.GetCSAElementByName( "foo" ); + } + catch( gdcm::CSAElementNameException &ex ) + { + std::cout << ex.what() << std::endl; + } +*/ + + return 0; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestCodeString.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestCodeString.cxx new file mode 100644 index 0000000..f9fedb3 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestCodeString.cxx @@ -0,0 +1,148 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmCodeString.h" +#include "gdcmAttribute.h" + +#include + +int TestCodeString(int , char *[]) +{ + const char fn1[] = "IMG01"; + + gdcm::Attribute< 0x0004, 0x1500 > at; + at.SetNumberOfValues( 1 ); + at.SetValue( fn1 ); + + unsigned int n = at.GetNumberOfValues(); + if( n != 1 ) return 1; + + const char fn2[] = "SUBDIR\\IMG01"; + at.SetNumberOfValues( 2 ); + at.SetValue( fn2 ); + n = at.GetNumberOfValues(); + if( n != 2 ) return 1; + + const char fn3[] = "SUBDIR1\\SUBDIR2\\IMG01 "; + +{ + gdcm::DataElement de( at.GetTag() ); + de.SetByteValue( fn3, (uint32_t)strlen(fn3) ); + + at.SetFromDataElement( de ); + n = at.GetNumberOfValues(); + //std::cout << n << std::endl; + if( n != 3 ) return 1; + + for( unsigned int i = 0; i < n; ++i) + { + gdcm::CodeString cs = at.GetValue( i ); + if( !cs.IsValid() ) + { + std::cerr << "Invalid CS: " << cs << std::endl; + return 1; + } + } +} + + const char fn4[] = "SUBDIR1\\SUBDIR2\\IMG01"; +{ + std::string copy = fn4; + if( copy.size() % 2 ) + { + copy.push_back( ' ' ); + } + gdcm::DataElement de( at.GetTag() ); + de.SetByteValue( copy.c_str(), (uint32_t)copy.size() ); + + at.SetFromDataElement( de ); + n = at.GetNumberOfValues(); + //std::cout << n << std::endl; + if( n != 3 ) return 1; + + for( unsigned int i = 0; i < n; ++i) + { + gdcm::CodeString cs = at.GetValue( i ); + if( !cs.IsValid() ) + { + std::cerr << "Invalid CS: " << cs << std::endl; + return 1; + } + } +} + + const char fn5[] = "SUBDIR1\\SUBDIR2\\LONGSUBDIR\\IMG01"; +{ + std::string copy = fn5; + if( copy.size() % 2 ) + { + copy.push_back( ' ' ); + } + + gdcm::DataElement de( at.GetTag() ); + de.SetByteValue( copy.c_str(), (uint32_t)copy.size() ); + + at.SetFromDataElement( de ); + n = at.GetNumberOfValues(); + //std::cout << n << std::endl; + if( n != 4 ) return 1; + + for( unsigned int i = 0; i < n; ++i) + { + gdcm::CodeString cs = at.GetValue( i ); + if( !cs.IsValid() ) + { + std::cerr << "Invalid CS: " << cs << std::endl; + return 1; + } + } + + if( strlen(at.GetValue(2) ) < 8 ) + { + return 1; + } +} + +{ + gdcm::CodeString cs0 = " SUB\\DIR "; + if( cs0.IsValid() ) return 1; + + gdcm::CodeString cs1 = " SUBDIR "; + if( !cs1.IsValid() ) return 1; + + gdcm::CodeString cs2 = " SUBDIR_0123456789 "; + // len == 19 => invalid + if( cs2.IsValid() ) return 1; + + gdcm::CodeString cs3 = " IMG_0123456789 "; + if( !cs3.IsValid() ) return 1; + + // cstor should trim on the fly: + gdcm::CodeString cs4 = " IMG_0123456789 "; + if( !cs4.IsValid() ) return 1; + + if( !(cs3 == cs4) ) return 1; + + if( cs3 != cs4 ) return 1; + + gdcm::CodeString cs5 = "IMG"; + if( cs5 != "IMG ") + return 1; + + + // Begin ugly internals. + +} + + return 0; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestComposite.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestComposite.cxx new file mode 100644 index 0000000..5346642 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestComposite.cxx @@ -0,0 +1,22 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +//#include "gdcmSequenceOfItems.h" + +int TestComposite(int argc, char *argv[]) +{ + (void)argc; + (void)argv; + + return 0; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestCopyValue.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestCopyValue.cxx new file mode 100644 index 0000000..0704b65 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestCopyValue.cxx @@ -0,0 +1,78 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmValue.h" +#include "gdcmByteValue.h" + +#include + +//namespace std { namespace tr1 = Boost; } + +void RawPtr(const char *array, const size_t len) +{ + std::cout << "RawPtr" << std::endl; + gdcm::ByteValue *bv1 = new gdcm::ByteValue(array, len); + std::cout << *bv1 << std::endl; + gdcm::ByteValue *bv2 = new gdcm::ByteValue(array, len); + std::cout << *bv2 << std::endl; + + const gdcm::Value &ref1 = *bv1; + std::cout << ref1 << std::endl; + + const gdcm::Value &ref2 = *bv2; + std::cout << ref2 << std::endl; + + // Need to delete: + delete bv1; + delete bv2; +} + +typedef std::tr1::shared_ptr ValuePtr; +void SharedPtr(const char *array, const size_t len) +{ + std::cout << "SharedPtr" << std::endl; + + //ValuePtr w; + //std::cout << w << std::endl; + ValuePtr bv1 ( new gdcm::ByteValue(array, len) ); + std::cout << *bv1 << std::endl; + ValuePtr bv2 ( new gdcm::ByteValue(array, len) ); + std::cout << *bv2 << std::endl; + + const gdcm::Value &ref1 = *bv1; + std::cout << ref1 << std::endl; + + const gdcm::Value &ref2 = *bv2; + std::cout << ref2 << std::endl; + + // No need to delete :) +} + +int TestCopyValue(int , char *[]) +{ + + const char array[] = "GDCM is yet another DICOM library."; + const size_t len = strlen( array ); + RawPtr(array, len); + SharedPtr(array, len); + + std::vector v; + v.push_back( ValuePtr(new gdcm::ByteValue(array, len) )); + v.push_back( ValuePtr(new gdcm::ByteValue(array, len) )); + v.push_back( ValuePtr(new gdcm::ByteValue(array, len) )); + v.push_back( ValuePtr(new gdcm::ByteValue(array, len) )); + v.push_back( ValuePtr(new gdcm::ByteValue(array, len) )); + // no delete :) + + return 0; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestDS.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestDS.cxx new file mode 100644 index 0000000..433a35d --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestDS.cxx @@ -0,0 +1,458 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmVR.h" +#include "gdcmAttribute.h" +#include "gdcmByteValue.h" + +#include +#include +#include + +#include // atof +#include // std::rand() +#include // min_exponent10 and max_exponent10 + + +// WARNING: The number of digits in exponent can be dependent from compiler. +// gcc uses 2 digits if the exponent is < 100 and 3 digits if >=, but +// some compilers (i.e. MSVC) may always use 3 digits in exponent. +// If some other compiler with this behaviour is detected, should be +// added here. +#if defined(_MSC_VER) + #define ALWAYS_3_DIGITS_IN_EXPONENT +#endif + + +#ifdef ALWAYS_3_DIGITS_IN_EXPONENT + #define MIN_NEGATIVE_EXP 6 //MSVC always use 3 digits in exponent. +#else + #define MIN_NEGATIVE_EXP 5 +#endif + +template < typename Float > +std::string to_string ( Float data ) { + + std::stringstream in; + // in.imbue(std::locale::classic()); // This is not required AFAIK + + unsigned long digits = 0; + + // 16 integer digits number or 15 integer digits negative number + if ( (data >= 1e+15 && data < 1e16) || (data <= -1e14 && data > -1e+15)) + in << std::fixed; + else + { + digits = 15; // 16 - 1 (dot) + + // negative number + if (data < 0) + digits -= 1; // (minus) + + if (data != 0) + { + Float ldata = log10(fabs(data)); + + // numbers that need std::scientific representation + if ( ldata > 16 || (ldata > 15 && data < 0) || ldata < -MIN_NEGATIVE_EXP+1 ) + { + in << std::scientific; +#ifdef ALWAYS_3_DIGITS_IN_EXPONENT + digits -= 6; // (first digit + exponent) +#else + digits -= 5; // (first digit + exponent) + // 3 digits in exponent + if ( ldata >= 100 || ldata < -99 ) + digits -=1; +#endif + } + else if( ldata < 0){ + //since ldata is negative, to have the test pass, + //the right casting has to be done to avoid a casting warning here + unsigned long uldata = (unsigned long)(fabs(ldata)+1.0); + digits -= uldata; // (zeros before first significant digit) + } + } + } + /* + // I don't know if you really need this check + unsigned long const max_digits = + static_cast< unsigned long >( + - std::log( std::numeric_limits::epsilon() ) + / std::log( 10.0 ) ); + digits = (digits > max_digits) ? max_digits : digits; + */ + + if ( in << std::dec << std::setprecision((int)digits) << data ) + return ( in.str() ); + else + throw "Impossible Conversion"; // should not happen ... +} + + + +bool checkerror(double d, std::string s) +{ + double theConverted = atof(s.c_str()); + double error = fabs(d - theConverted); + + int Log = (int)log10(fabs(d)); + int eo = ( Log - 14 ); + + if ( Log <= -1 && Log >= -4 ) + eo = -13; +#ifdef ALWAYS_3_DIGITS_IN_EXPONENT + else if ( Log >= 15 ) + eo = ( Log - 9); +#else + else if ( Log >= 99 ) + eo = ( Log - 9 ); + else if ( Log >= 15 ) + eo = ( Log - 10); +#endif + + if (d<0) + eo += 1; + + + //if (error > pow(10., eo) ) + //pow will underflow at 10^-308, so errors lower than -308 will appear to be + //larger than pow(10., eo), because the 'pow' result will be 0 in vs2010 + if (log10(error) > eo) + { + std::cout << "ERROR: Absoulte Error is too large (error = " << error << ", should be < " << pow(10., eo) << ")" << std::endl; + return true; + } +// else if (error != 0.0) std::cout << "OK (error = " << error << ", is < " << pow(10, eo) << ")" << std::endl; + + return false; +} + +bool checkerror(double d, std::string s, bool se) +{ + double error = fabs(d - atof( s.c_str() )); + bool has_error = (error != 0); + + if (has_error) + { + std::cout << "\tError is: " << error; + } + std::cout << std::endl; + + if( has_error != se ) + { + std::cout << "ERROR: has_error = " << has_error << " (should be " << se << ")" << std::endl; + return true; + } + return checkerror(d,s); +} + + + + +/* + d = double to test + sz = size expected + se = true if there should be an error +*/ +bool singleTestDS(double d, int sz, bool se = false) +{ + bool fail = false; + std::cout << " -|----------------|-" << std::endl; + std::string s = to_string( d ); + std::cout << " Result: " << s << std::flush; + + if ( checkerror(d, s, se) ) + fail = true; + + assert(sz >= 0); + if( s.size() != (unsigned int)sz ) + { + std::cout << "ERROR: Size = " << s.size() << " (should be " << sz << ")" << std::endl; + fail = true; + } + + std::cout << std::endl; + + return fail; +} + + +#define TEST(x, y, z) { \ + std::cout << " Testing: " << #x << std::endl; \ + err_count += singleTestDS(x, y, z); \ + test_count++; } + + +/* + * Test to make sure that double precision ieee 'double' is ok for DICOM VR = 'DS' + */ +int TestDS(int, char *[]) +{ + int err_count = 0; + int test_count = 0; + + TEST( 118.242525316066 , 16, false); // 3 digits + dot + 12 digits => 16 chars + TEST( -118.242525316066 , 16, true); // minus + 3 digits + dot + 12 digits => 16 chars + ERROR + TEST( 118.24252531606 , 15, false); // minus + 3 digits + dot + 11 digits => 16 chars + TEST( -118.24252531606 , 16, false); // minus + 3 digits + dot + 11 digits => 16 chars + + TEST( 0.059303515816892 , 16, true); // zero + dot + zero + 14 digits => 16 chars + ERROR + TEST( -0.059303515816892 , 16, true); // minus + zero + dot + zero + 14 digits => 16 chars + ERROR + TEST( 0.05930351581689 , 16, false); // zero + dot + zero + 13 digits => 16 chars + TEST( -0.05930351581689 , 16, true); // minus + zero + dot + zero + 13 digits => 16 chars + ERROR + TEST( 0.0593035158168 , 15, false); // zero + dot + zero + 12 digits => 15 chars + TEST( -0.0593035158168 , 16, false); // minus + zero + dot + zero + 12 digits => 16 chars + + TEST( 0.00149700609543456 , 16, true); // zero + dot + 2 zeros + 15 digits => 16 chars + ERROR + TEST( -0.00149700609543456 , 16, true); // zero + dot + 2 zeros + 15 digits => 16 chars + ERROR + TEST( 0.0014970060954345 , 16, true); // zero + dot + 2 zeros + 14 digits => 16 chars + ERROR + TEST( -0.0014970060954345 , 16, true); // zero + dot + 2 zeros + 14 digits => 16 chars + ERROR + TEST( 0.001497006095434 , 16, true); // zero + dot + 2 zeros + 13 digits => 16 chars + ERROR + TEST( -0.001497006095434 , 16, true); // zero + dot + 2 zeros + 13 digits => 16 chars + ERROR + TEST( 0.00149700609543 , 16, false); // zero + dot + 2 zeros + 12 digits => 16 chars + TEST( -0.00149700609543 , 16, true); // zero + dot + 2 zeros + 12 digits => 16 chars + ERROR + TEST( 0.0014970060954 , 15, false); // zero + dot + 2 zeros + 11 digits => 15 chars + TEST( -0.0014970060954 , 16, false); // zero + dot + 2 zeros + 11 digits => 16 chars + TEST( 0.000593035158168 , 16, true); // zero + dot + 3 zeros + 12 digits => 16 chars + ERROR + TEST( 5.93035158168e-04 , 16, true); // same number: cannot fit in 16 chars even in scientific notation (17 chars) + TEST( 0.00059303515816 , 16, false); // zero + dot + 3 zeros + 11 digits => 16 chars + TEST( -0.00059303515816 , 16, true); // minus + zero + dot + 3 zeros + 11 digits => 16 chars + ERROR + TEST( -5.9303515816e-04 , 16, true); // same number: cannot fit in 16 chars even in scientific notation (17 chars) + TEST( -0.0005930351581 , 16, false); // minus + zero + dot + 3 zeros + 10 digits => 16 chars + + TEST( 0.0000593035158168 , 16, true); // zero + dot + 4 zeros + 12 digits => 16 chars (w/ scientific notation) + ERROR + TEST( 0.00005930351581 , 16, false); // zero + dot + 4 zeros + 10 digits => 16 chars + TEST( -0.000059303515816 , 16, true); // minus + zero + dot + 4 zeros + 10 digits => 16 chars (w/ scientific notation) + ERROR + TEST( -0.0000593035158 , 16, false); // minus + zero + dot + 4 zeros + 10 digits => 16 chars + +#ifdef ALWAYS_3_DIGITS_IN_EXPONENT + TEST( 0.000059303515816 , 16, true); // zero + dot + 4 zeros + 11 digits => 16 chars (w/ scientific notation) + ERROR + TEST( -0.00005930351581 , 16, true); // minus + zero + dot + 4 zeros + 10 digits => 16 chars (w/ scientific notation) + ERROR +#else + TEST( 0.000059303515816 , 16, false); // zero + dot + 4 zeros + 11 digits => 16 chars (w/ scientific notation) + TEST( -0.00005930351581 , 16, false); // minus + zero + dot + 4 zeros + 10 digits => 16 chars (w/ scientific notation) +#endif + + TEST( 123456789012.1 , 14, false); // 12 digits + dot + 1 digit => 14 chars + TEST( -123456789012.1 , 15, false); // minus + 12 digits + dot + 1 digit => 14 chars + TEST( 1234567890123.1 , 15, false); // 13 digits + dot + 1 digit => 15 chars + TEST( -1234567890123.1 , 16, false); // minus + 13 digits + dot + 1 digit => 15 chars + TEST( 1234567890123.12 , 16, false); // 13 digits + dot + 2 digit => 16 chars + TEST( -1234567890123.12 , 16, true); // minus + 13 digits + dot + 2 digit => 16 chars + ERROR + TEST( 1234567890123.123 , 16, true); // 13 digits + dot + 3 digit => 16 chars + ERROR + TEST( -1234567890123.123 , 16, true); // minus + 13 digits + dot + 3 digit => 16 chars + ERROR + +// TEST( 12345678901234 , 14, false); // 14 digits => 14 chars + TEST( 12345678901234. , 14, false); // same number + TEST( 12345678901234.0 , 14, false); // same number + TEST( 1.2345678901234e+13 , 14, false); // same number +// TEST( -12345678901234 , 15, false); // minus + 14 digits => 15 chars + TEST( -12345678901234. , 15, false); // same number + TEST( -12345678901234.0 , 15, false); // same number + TEST( -1.2345678901234e+13 , 15, false); // same number + + TEST( 12345678901234.1 , 16, false); // 14 digits + dot + 1 digit => 16 chars + TEST( -12345678901234.1 , 15, true); // minus + 14 digits + dot + 1 digit => 15 chars + ERROR + TEST( 12345678901234.12 , 16, true); // 14 digits + dot + 2 digit => 16 chars + ERROR + TEST( -12345678901234.12 , 15, true); // minus + 15 digits + dot + 1 digit => 15 chars + ERROR + +// TEST( 123456789012345 , 15, false); // 15 digit => 15 chars + TEST( 123456789012345. , 15, false); // same number + TEST( 123456789012345.0 , 15, false); // same number + TEST( 1.23456789012345e+14 , 15, false); // same number + +// TEST( -123456789012345 , 16, false); // minus + 15 digit => 16 chars + TEST( -123456789012345. , 16, false); // same number + TEST( -123456789012345.0 , 16, false); // same number + TEST( -1.23456789012345e+14 , 16, false); // same number + + TEST( 123456789012345.1 , 15, true); // 15 digits + dot + 1 digit => 15 chars + ERROR + TEST( -123456789012345.1 , 16, true); // minus + 15 digits + dot + 1 digit => 16 chars + ERROR + +// TEST( 1234567890123456 , 16, false); // 16 digits => 16 chars + TEST( 1234567890123456. , 16, false); // same number + TEST( 1234567890123456.0 , 16, false); // same number + TEST( 1.234567890123456e+15 , 16, false); // same number +// TEST( -1234567890123456 , 16, true); // minus + 6 digits => 16 chars + TEST( -1234567890123456. , 16, true); // same number + TEST( -1234567890123456.0 , 16, true); // same number + TEST( -1.234567890123456e+15 , 16, true); // same number + + TEST( 1234567890123456.2 , 16, true); // 16 digits + dot + 1 digit => 16 chars + ERROR + TEST( -1234567890123456.2 , 16, true); // minus + 16 digits + dot + 1 digit => 16 chars + ERROR + +// TEST( 12345678901234567 , 16, true); // 17 digits => 16 chars (w/ scientific notation) + ERROR + TEST( 12345678901234567. , 16, true); // same number + TEST( 1.2345678901234567e+16 , 16, true); // same number +// TEST( -12345678901234567 , 16, true); // minus + 17 digits => 16 chars (w/ scientific notation) + ERROR + TEST( -12345678901234567. , 16, true); // same number + TEST(-1.2345678901234567e+16 , 16, true); // same number + +// TEST( 123456789012345678 , 16, true); // 18 digits => 16 chars (w/ scientific notation) + ERROR + TEST( 123456789012345678. , 16, true); // same number + TEST(1.23456789012345678e+17 , 16, true); // same number +// TEST(-123456789012345678 , 16, true); // minus + 18 digits => 16 chars (w/ scientific notation) + ERROR + TEST(-123456789012345678. , 16, true); // same number + TEST(-1.23456789012345678e+17 , 16, true); // same number + +// TEST( 1234567890123456789 , 16, true); // 19 digits => 16 chars (w/ scientific notation) + ERROR + TEST( 1234567890123456789. , 16, true); // same number + TEST(1.234567890123456789e+18 , 16, true); // same number +// TEST(-1234567890123456789 , 16, true); // minus + 19 digits => 16 chars (w/ scientific notation) + ERROR + TEST(-1234567890123456789. , 16, true); // same number + TEST(-1.234567890123456789e+18 , 16, true); // same number + + TEST(1.2345678901234567891e+19 , 16, true); + TEST(-1.2345678901234567891e+19 , 16, true); + TEST(1.23456789012345678901e+20 , 16, true); + TEST(-1.23456789012345678901e+20 , 16, true); + + TEST(1.23456789012345678901e+99 , 16, true); + TEST(-1.23456789012345678901e+99 , 16, true); + TEST(1.23456789012345678901e+100 , 16, true); + TEST(-1.23456789012345678901e+100 , 16, true); + + TEST( 100000000000000. , 15, false); // 15 digits => 15 chars + TEST( -100000000000000. , 16, false); // minus + 15 digits => 15 chars + TEST( 999999999999999. , 15, false); // 15 digits => 15 chars + TEST( -999999999999999. , 16, false); // minus + 15 digits => 15 chars + TEST( 1000000000000000. , 16, false); // 16 chars + TEST( 1e+15 , 16, false); // same number + TEST( 9999999999999998. , 16, false); // 16 chars + TEST( -9999999999999998. , 16, true); // minus + 16 chars + TEST( -9999999990099999. , 16, true); + TEST( -10000000000000000. , 16, false); // minus + 17 chars => 16 digits (w/ scientific notation) + +#ifdef ALWAYS_3_DIGITS_IN_EXPONENT + TEST( 10000000000000000. , 6, false); // 17 chars => 6 digits (w/ scientific notation) + TEST( 1e16 , 6, false); + TEST( -1000000000000000. , 7, false); // minus + 7 chars (w/ scientific notation) + TEST( -1e+15 , 7, false); // same number +#else + TEST( 10000000000000000. , 5, false); // 17 chars => 5 digits (w/ scientific notation) + TEST( 1e16 , 5, false); + TEST( -1000000000000000. , 6, false); // minus + 7 chars (w/ scientific notation) + TEST( -1e+15 , 6, false); // same number +#endif + + TEST( -1e16 , 16, false); + TEST( 1e17 , 16, false); + TEST( -1e17 , 16, false); + TEST( 1e18 , 16, false); + TEST( -1e18 , 16, false); + TEST( 1e19 , 16, false); + TEST( -1e19 , 16, false); + TEST( 1e20 , 16, false); + TEST( -1e20 , 16, false); + + //TEST( 0 , 1, false); // zero => 1 char (MM: cannot execute this test with ftrapv) + TEST( 1 , 1, false); // 1 digit => 1 char + + TEST( 9.9999999999e-4 , 16, false); + +#ifdef ALWAYS_3_DIGITS_IN_EXPONENT + TEST( 1e-5 , 6, false); +#else + TEST( 1e-5 , 16, false); +#endif + + TEST( 5.1e-4 , 7, false); + +#ifdef ALWAYS_3_DIGITS_IN_EXPONENT + TEST( 5.1e-5 , 8, false); +#else + TEST( 5.1e-5 , 16, false); +#endif + + TEST( 5.1e-6 , 16, false); + TEST( 5.1e-7 , 16, false); + TEST( 5.1e-8 , 16, false); + TEST( 5.1e-9 , 16, false); + TEST( 5.1e-10 , 16, false); + TEST( 5.1e-11 , 16, false); + + TEST( 1e+99 , 16, false); + TEST( -1e+99 , 16, false); + TEST( 1e+100 , 16, false); + TEST( -1e+100 , 16, false); + TEST( 3.4584e+100 , 16, false); + TEST( -3.4584e+100 , 16, false); + TEST( 3.4584e+101 , 16, false); + TEST( -3.4584e+101 , 16, false); + TEST( 1e-99 , 16, false); + TEST( -1e-99 , 16, false); + TEST( 1e-100 , 16, false); + TEST( -1e-100 , 16, false); + TEST( 3.4584e-100 , 16, false); + TEST( -3.4584e-100 , 16, false); + TEST( 3.4584e-101 , 16, false); + TEST( -3.4584e-101 , 16, false); + + +// Tests failing due to double precision + + if (1234567890123456.1 != 1234567890123456.) + { TEST( 1234567890123456.1 , 16, true); } // 16 digits + dot + 1 digit => 16 chars + ERROR + else + { TEST( 1234567890123456.1 , 16, false); } // 16 digits + dot + 1 digit => 16 chars + NO ERROR + + + if ( 9999999999999999. != 1e+16 ) + { TEST( 9999999999999999. , 16, false); } // 16 chars => 16 digits + else + { TEST( 9999999999999999. , 5, false); } // 16 chars => 5 digits (w/ scientific notation) + + if ( -9999999998999999. != -9.999999999e+15 ) + { TEST( -9999999998999999. , 16, true); } + else + { TEST( -9999999998999999. , 16, false); } + + + std::cout << "---> Failed test(s): " << err_count << " of " << test_count << std::endl << std::endl; + +// ---- RANDOM TESTS: + + const unsigned int random_count = 100000; + int random_err_count = 0; + int min_exp = std::numeric_limits::min_exponent10; + int max_exp = std::numeric_limits::max_exponent10; + + std::cout << "Running " << random_count << " random tests." << std::endl << std::endl; + for (unsigned int i = 0; i(std::rand()) * pow(10., rand_exp); + if (rand != rand) {i--; continue;} // nan + if (rand == std::numeric_limits::infinity()) {i--; continue;} // inf + + std::string s = to_string( rand ); + //std::cout << s; + if (s.size() > 16 || !s.compare("inf") || !s.compare("nan") ) + { +// std::cout << "\t--- FAIL" << std::endl; + random_err_count += 1; + continue; + } + + if ( checkerror(rand, s) ) + random_err_count += 1; +// else +// std::cout << "\t--- OK" << std::endl; + } + + std::cout << "---> Failed random test(s): " << random_err_count << " of " << random_count << std::endl << std::endl; + + return err_count + random_err_count; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestDataElement.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestDataElement.cxx new file mode 100644 index 0000000..0f64863 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestDataElement.cxx @@ -0,0 +1,235 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmDataElement.h" +#include "gdcmExplicitDataElement.h" +#include "gdcmTag.h" + +#include "gdcmSwapper.h" + +#include + +inline void DebugElement(std::stringstream const &os) +{ + std::ofstream of("/tmp/bla.bin", std::ios::binary); + std::string str = os.str(); + of.write(str.c_str(), str.size()); + of.close(); +} + + +inline void WriteRead(gdcm::DataElement const &w, gdcm::DataElement &r) +{ + // w will be written + // r will be read back + std::stringstream ss; + w.Write(ss); + r.Read(ss); +} + +int TestDataElement1(const uint16_t group, const uint16_t element, + const uint16_t vl) +{ + const char *str; + std::stringstream ss; + // SimpleData Element, just group,element and length + str = reinterpret_cast(&group); + ss.write(str, sizeof(group)); + str = reinterpret_cast(&element); + ss.write(str, sizeof(element)); + str = reinterpret_cast(&vl); + ss.write(str, sizeof(vl)); + +// gdcm::DataElement de; +// de.Read( ss ); +// if( de.GetTag().GetGroup() != group || +// de.GetTag().GetElement() != element || +// de.GetVL() != vl ) +// { +// std::cerr << de << std::endl; +// return 1; +// } +// +// gdcm::DataElement de2; +// WriteRead(de, de2); +// if( !(de == de2) ) +// { +// std::cerr << de << std::endl; +// std::cerr << de2 << std::endl; +// return 1; +// } + + return 0; +} + +// Explicit +int TestDataElement2(const uint16_t group, const uint16_t element, + const char* vr, const char* value) +{ + const char *str; + const uint32_t vl = (uint32_t)strlen( value ); + std::stringstream ss; + // SimpleData Element, just group,element and length + str = reinterpret_cast(&group); + ss.write(str, sizeof(group)); + str = reinterpret_cast(&element); + ss.write(str, sizeof(element)); + if( gdcm::VR::GetVRType(vr) == gdcm::VR::INVALID ) + { + std::cerr << "Test buggy" << std::endl; + return 1; + } + ss.write(vr, strlen(vr) ); + str = reinterpret_cast(&vl); + ss.write(str, sizeof(vl)); + assert( !(strlen(value) % 2) ); + ss.write(value, strlen(value) ); + //DebugElement(ss); + + gdcm::ExplicitDataElement de; + de.Read( ss ); + if( de.GetTag().GetGroup() != group || + de.GetTag().GetElement() != element || + de.GetVL() != vl ) + { + std::cerr << de << std::endl; + return 1; + } + + gdcm::ExplicitDataElement de2; + WriteRead(de, de2); + if( !(de == de2) ) + { + std::cerr << de << std::endl; + std::cerr << de2 << std::endl; + return 1; + } + + return 0; +} + +namespace +{ + + // Tests operator== and operator!= for various gdcm::DataElement objects. + // Also tests comparing to itself, symmetry of the comparison operators + // with respect to their operands, and consistency between + // operator== and operator!=. + // Note: This function recursively calls itself, in order to get a pointer + // to an equivalent array of gdcm::DataElement objects. + int TestDataElementEqualityComparison( + const gdcm::DataElement* const equivalentDataElements = NULL) + { + const unsigned int numberOfDataElements = 6; + + gdcm::DataElement dataElements[numberOfDataElements] = + { + gdcm::DataElement(gdcm::Tag(0, 0), 0, gdcm::VR::INVALID), + gdcm::DataElement(gdcm::Tag(1, 1), 0, gdcm::VR::INVALID), + gdcm::DataElement(gdcm::Tag(1, 1), 1, gdcm::VR::INVALID), + gdcm::DataElement(gdcm::Tag(1, 1), 1, gdcm::VR::AE) + }; + + dataElements[4].SetByteValue("\0", 2); + dataElements[5].SetByteValue("123", 4); + + // Now all data elements of the array dataElements are different. + + if ( equivalentDataElements == NULL ) + { + return TestDataElementEqualityComparison(dataElements); + } + + // equivalentDataElements != NULL, and because this function + // is called recursively, equivalentDataElements[i] is equivalent + // to dataElements[i]. + + for (unsigned int i = 0; i < numberOfDataElements; ++i) + { + const gdcm::DataElement& dataElement = dataElements[i]; + + if ( ! (dataElement == dataElement) ) + { + std::cerr << + "Error: A data element should compare equal to itself!\n"; + return 1; + } + if ( dataElement != dataElement ) + { + std::cerr << + "Error: A data element should not compare unequal to itself!\n"; + return 1; + } + const gdcm::DataElement& equivalentDataElement = equivalentDataElements[i]; + + if ( ! (dataElement == equivalentDataElement) || + ! (equivalentDataElement == dataElement ) ) + { + std::cerr << + "Error: A data element should compare equal to an equivalent one!\n"; + return 1; + } + + if ( (dataElement != equivalentDataElement) || + (equivalentDataElement != dataElement) ) + { + std::cerr << + "Error: A data element should not compare unequal to an equivalent one!\n"; + return 1; + } + + for (unsigned int j = i + 1; j < numberOfDataElements; ++j) + { + // dataElements[j] is different from dataElements[i]. + + const gdcm::DataElement& differentDataElement = dataElements[j]; + + if ( (dataElement == differentDataElement) || + (differentDataElement == dataElement) ) + { + std::cerr << + "Error: A data element should not compare equal to a different one!\n"; + return 1; + } + + if ( !(dataElement != differentDataElement) || + !(differentDataElement != dataElement) ) + { + std::cerr << + "Error: A data element should compare unequal to a different one!\n"; + return 1; + } + } + } + return 0; + } + +} // End of unnamed namespace. + +// Test Data Element +int TestDataElement(int , char *[]) +{ + const uint16_t group = 0x0010; + const uint16_t element = 0x0012; + const uint16_t vl = 0x0; + int r = 0; + r += TestDataElement1(group, element, vl); + r += TestDataElementEqualityComparison(); + + // Full DataElement + //const char vr[] = "UN"; + //const char value[] = "ABCDEFGHIJKLMNOP"; + //r += TestDataElement2(group, element, vr, value); + + return r; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestDataSet.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestDataSet.cxx new file mode 100644 index 0000000..a0746f0 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestDataSet.cxx @@ -0,0 +1,72 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmDataSet.h" +#include "gdcmDataElement.h" +#include "gdcmExplicitDataElement.h" +#include "gdcmImplicitDataElement.h" + + +int TestDataSet(int , char *[]) +{ + gdcm::DataSet ds; + std::cout << sizeof ds << std::endl; + gdcm::DataElement d; + ds.Insert(d); + const gdcm::DataElement& r = + ds.GetDataElement( gdcm::Tag(0,0) ); + std::cout << r << std::endl; + + const gdcm::Tag t2 = gdcm::Tag(0x1234, 0x5678); + gdcm::DataElement d2(t2); + std::cout << d2 << std::endl; + ds.Insert(d2); + const gdcm::DataElement& r2 = + ds.GetDataElement( t2 ); + std::cout << r2 << std::endl; + + const gdcm::Tag t3 = gdcm::Tag(0x1234, 0x5679); + gdcm::DataElement d3(t3); + d3.SetVR( gdcm::VR::UL ); + std::cout << d3 << std::endl; + ds.Insert(d3); + const gdcm::DataElement& r3 = + ds.GetDataElement( t3 ); + std::cout << r3 << std::endl; + + std::cout << "Size:" << ds.Size() << std::endl; + if( ds.Size() != 3 ) + { + //return 1; + } + + std::cout << "Print Dataset:" << std::endl; + std::cout << ds << std::endl; + + const gdcm::DataElement &de1 = ds[ gdcm::Tag(0x0020,0x0037) ]; + const gdcm::DataElement &de2 = ds(0x0020,0x0037); + if( &de1 != &de2 ) return 1; + + std::cout << ds << std::endl; + + gdcm::DataElement de3; + std::cout << de3 << std::endl; + const gdcm::DataElement &de4 = ds(0x0,0x0); + std::cout << de4 << std::endl; + const gdcm::DataElement &de5 = ds(0x0,0x1); + std::cout << de5 << std::endl; + const gdcm::DataElement &de6 = ds(0x1,0x1); + std::cout << de6 << std::endl; + + return 0; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestElement.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestElement.cxx new file mode 100644 index 0000000..afe869f --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestElement.cxx @@ -0,0 +1,204 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmElement.h" +#include "gdcmDataSet.h" + +#define TPI 3.1415926535897931 + +namespace gdcm +{ + +int TestFL() +{ + Element a = {{ (float)TPI }}; + a.Print( std::cout ); + std::cout << std::endl; + + Element b = + {{ 0,1,2,3,4,5,6,7 }}; + b.Print( std::cout ); + std::cout << std::endl; + + float f[10] = {}; + Element c; + c.SetArray( f, sizeof(f), false); + c.Print( std::cout ); + std::cout << std::endl; + + // Make sure this is possible to output as DataElement + // an Element, in case one cannot use gdcm::Attribute + // Eg. Sup 145 are not available -yet- +{ + DataSet ds; + Element el; + el.SetValue(1.2f); + + DataElement de = el.GetAsDataElement(); + de.SetTag( Tag(0x0048,0x0201) ); + ds.Insert( de ); +} + + + return 0; +} + +int TestFD() +{ + Element a = {{ TPI }}; + std::ostringstream os; + a.Print( os ); + const std::string st = os.str(); // important + const char *s = st.c_str(); + std::cout << s << std::endl; + //double t = *reinterpret_cast(*s); + //std::cout << t << std::endl; + + Element b; + double array[] = { 1,2,3,4,5,6,7,9 }; + b = reinterpret_cast& >( array ); + b.Print( std::cout ); + std::cout << std::endl; + + return 0; +} + +int TestAS() +{ + Element a = { "019Y" }; + a.Print( std::cout ); + std::cout << std::endl; + + // TODO this should not compile: + Element b = {{ "019Yb" }}; + b = b;//to avoid the warning of b not being useful + + return 0; +} + +int TestUL() +{ + const char array[4] = {-78, 1, 0, 0}; // 434 + { + Element a; + // reinterpret_cast< const Element& > ( array ); + memcpy((void*)&a, array, 4); + a.Print( std::cout ); + } + std::cout << std::endl; + + return 0; +} + +int TestAT() +{ + // = (0020,5000) : (0010,0010)\(0010,0020)\(0020,0013) + Element a; + Tag list[3]; + list[0] = Tag(0x0010,0x0010); + list[1] = Tag(0x0010,0x0020); + list[2] = Tag(0x0020,0x0013); + memcpy(&a, list, sizeof(list)); + a.Print( std::cout ); + std::cout << std::endl; + + Element b; + b.SetArray( list, sizeof(list), false); + b.Print( std::cout ); + std::cout << std::endl; + + return 0; +} + +int TestOB() +{ + const unsigned char array[] = + { 0x00,0x00,0x00,0x01,0x42,0x12,0xf9,0x22,0x00,0x31,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x03,0xfe,0x02,0x71 }; + // Bad no such thing as 1-n for OB/OW: + Element a; + a.SetArray( array, sizeof(array), false); + // reinterpret_cast< const Element& > ( array ); + //memcpy((void*)&a, array, sizeof(array)); + a.Print( std::cout ); + std::cout << std::endl; + + Element b; + b.SetArray( array, sizeof(array), false); + // reinterpret_cast< const Element& > ( array ); + //memcpy((void*)&a, array, sizeof(array)); + b.Print( std::cout ); + std::cout << std::endl; + + return 0; +} + +int TestUSVM3() +{ + Element a = {{ 0x0001, 0x0002, 0x0003 }}; + a.Print( std::cout ); + std::cout << std::endl; + unsigned short tmp = a.GetValue(0); + if( tmp != 0x0001 ) + { + return 1; + } + tmp = a.GetValue(1); + if( tmp != 0x0002 ) + { + return 1; + } + tmp = a.GetValue(2); + if( tmp != 0x0003 ) + { + return 1; + } + std::stringstream ss; + a.Write( ss ); + + Element b; + b.Read( ss ); + b.Print( std::cout ); + tmp = b.GetValue(0); + if( tmp != 0x0001 ) + { + return 1; + } + tmp = b.GetValue(1); + if( tmp != 0x0002 ) + { + return 1; + } + tmp = b.GetValue(2); + if( tmp != 0x0003 ) + { + return 1; + } + std::cout << std::endl; + + return 0; +} +} + +int TestElement(int , char *[]) +{ + int r = 0; + r += gdcm::TestFL(); + r += gdcm::TestFD(); + r += gdcm::TestAS(); + r += gdcm::TestUSVM3(); + r += gdcm::TestUL(); + r += gdcm::TestOB(); + r += gdcm::TestAT(); + + return r; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestElement2.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestElement2.cxx new file mode 100644 index 0000000..84a7fb5 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestElement2.cxx @@ -0,0 +1,40 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmElement.h" +#include "gdcmVR.h" + +struct dummy +{ + unsigned short I[3]; +}; +// +// + +template struct TagToElement; +template<> struct TagToElement<0x0018,0x1624> { + typedef gdcm::Element Type; +}; + +int TestElement2(int, char *[]) +{ + gdcm::Element ref = {{0,1,2}}; + ref.Print(std::cout); + //dummy d = {{0,1,2}};//commenting out + + TagToElement<0x0018,0x1624>::Type t = {{1,2,3}}; + t.Print( std::cout ); + std::cout << std::endl; + + return 0; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestElement3.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestElement3.cxx new file mode 100644 index 0000000..4fec7f7 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestElement3.cxx @@ -0,0 +1,425 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include +#include +#include + +#include + +struct AE +{ + char Internal[16+1]; + void Print(std::ostream &os) { + os << Internal; + } +}; + +typedef enum { + DAY = 'D', + WEEK = 'W', + MONTH = 'M', + YEAR = 'Y' +} DateFormat; + +//template struct ASValid; +//template <> struct ASValid<'Y'> { }; +struct AS +{ + unsigned short N; + unsigned char Format; + void Print(std::ostream &os) { + if( N < 1000 && + (Format == 'D' || + Format == 'W' || + Format == 'M' || + Format == 'Y' )) + { + os << std::setw(3) << std::setfill('0') << N << Format; + } + else + { + os << ""; + } + } +}; + +struct AT +{ + // Tag Internal; +}; + +struct CS +{ + char Internal[16]; +}; + +struct DA +{ + unsigned short Year : 12; + unsigned short Month : 4; + unsigned short Day : 5; + void Print(std::ostream &os) + { + os << std::setw(4) << std::setfill('0') << Year; + os << std::setw(2) << std::setfill('0') << Month; + os << std::setw(2) << std::setfill('0') << Day; + } +}; + +struct date { + unsigned short day : 5; // 1 to 31 + unsigned short month : 4; // 1 to 12 + unsigned short year : 12; /* 0 to 9999 (technically :11 should be enough for a couple of years...) */ + void Print(std::ostream &os) + { + os << year << "." << (int)month << "." << (int)day; + + } + }; + +struct DS +{ + double Internal; + // 16 bytes as integer would mean we can have 10^16 as max int + // which only double can hold +}; + + +struct FL +{ + float Internal; +}; + +struct FD +{ + double Internal; +}; + +struct IS +{ + int Internal; + void Print(std::ostream &os) + { + os << Internal; + } +}; + +struct LO +{ + char Internal[64]; + void Print(std::ostream &os) { + os << Internal; + } +}; + +struct LT +{ + std::string Internal; + void Print(std::ostream &os) { + os << Internal.size(); + os << std::endl; + os << Internal; + } +}; + + +struct OB +{ + explicit OB(const char *array = 0, uint32_t length = 0):Internal(array),Length(length) {} + void Print( std::ostream &os ) + { + const char *p = Internal; + const char *end = Internal+Length; + while(p != end) + { + os << "\\" << (int)*p++; + } + } +private: + const char *Internal; + uint32_t Length; +}; + +struct OF; + +struct OW; + +struct PN +{ + char Component[5][64]; + void Print(std::ostream &os) + { + //os << "Family Name Complex: " << Component[0] << std::endl; + //os << "Given Name Complex: " << Component[1] << std::endl; + //os << "Middle Name : " << Component[2] << std::endl; + //os << "Name Suffix : " << Component[3] << std::endl; + //os << "Name Prefix : " << Component[4] << std::endl; + os << Component[0] << "^"; + os << Component[1] << "^"; + os << Component[2] << "^"; + os << Component[3] << "^"; + os << Component[4]; + } +}; + +struct SH +{ + char Internal[16+1]; +}; + +struct SL +{ + signed long Internal; +}; + +struct SQ; + +struct SS +{ + signed short Internal; +}; + +struct ST +{ + std::string Internal; +}; + +struct TM +{ + unsigned short hours:5; + unsigned short minutes:6; + unsigned short seconds:6; + unsigned int fracseconds:20; + void Print(std::ostream &os) { + os << std::setw(2) << std::setfill('0') << hours; + os << std::setw(2) << std::setfill('0') << minutes; + os << std::setw(2) << std::setfill('0') << seconds; + os << "."; + os << std::setw(6) << std::setfill('0') << fracseconds; + } +}; + +struct Tri +{ + short Internal:2; + //operator void *() const { return Internal; } + operator short () const { return Internal; } +}; + +struct DT +{ + DA da; + TM tm; + Tri OffsetSign; + unsigned short Hours:5; + unsigned short Minutes:6; +// YYYYMMDDHHMMSS.FFFFFF&ZZZZ + void Print ( std::ostream &os) + { + da.Print( os ); + tm.Print( os ); + if( OffsetSign ) + { + if ( OffsetSign == -1 ) os << "-"; + else if ( OffsetSign == +1 ) os << "+"; + else return; + os << std::setw(2) << std::setfill('0') << Hours; + os << std::setw(2) << std::setfill('0') << Minutes; + } + } +}; + + +struct UI +{ + char Internal[64+1]; + void Print(std::ostream &os) { + os << strlen(Internal) << std::endl; + os << Internal; + } +}; + +struct UL +{ + unsigned long Internal; +}; + +struct UN +{ + std::vector Internal; +}; + +struct US +{ + unsigned short Internal; +}; + +struct UT +{ + std::string Internal; +}; + +struct S +{ + union { char s[2]; } Internal; + //unsigned short Internal; + void Print( std::ostream &os ) + { + os << strlen( Internal.s ) << std::endl; + os << Internal.s; + } +}; + +int main() +{ + AE ae = { "application enti" }; + ae.Print( std::cout ); + std::cout << std::endl; + + AS as = { 1, 'Y' }; + as.Print( std::cout ); + std::cout << std::endl; + + DA da = { 10978, 11, 32 }; + da.Print( std::cout ); + std::cout << std::endl; + std::cout << "DA:" << sizeof (DA) << std::endl; + + double dd = 10*10*10*10*10*10*10*10; + std::cout << dd << std::endl; + DS ds = { 10*10*10*10*10*10*10*10 + 1 }; + std::cout << ds.Internal << std::endl; + + DT dt = { 1979, 7, 6 }; + dt.Print( std::cout << "DT: " ); + std::cout << std::endl; + + DT dt1 = { 1979, 7, 6, 23, 59, 59, 999999 }; + dt1.Print( std::cout << "DT: " ); + std::cout << std::endl; + + DT dt2 = { 1979, 7, 6, 23, 59, 59, 999999, -1, 12, 42 }; + dt2.Print( std::cout << "DT: " ); + std::cout << std::endl; + + DT dt3 = { 1979, 7, 6, 23, 59, 59, 999999, +1, 12, 42 }; + dt3.Print( std::cout << "DT: " ); + std::cout << std::endl; + + + IS is = { 2 << 30 }; + is.Print( std::cout ); + std::cout << std::endl; + + //std::cout << 8*8 << std::endl; + //std::cout << 8*8*8*8 << std::endl; + date d = {31, 12, 1978 }; + d.Print( std::cout ); + std::cout << std::endl; + std::cout << "date:" << sizeof (date) << std::endl; + + + LO lo = { "coucou" }; + lo.Print( std::cout ); + std::cout << std::endl; + + LT lt = { "very long text\0hello mathieu" }; + lt.Print( std::cout ); + std::cout << std::endl; + + OB ob("\0\1", 2); + ob.Print( std::cout ); + std::cout << std::endl; + + PN pn1 = { "abc123", "def", "ghi", "klm", "opq" }; + pn1.Print( std::cout ); + std::cout << std::endl; + + PN pn2 = { "malaterre", "mathieu olivier patrick"}; + pn2.Print( std::cout ); + std::cout << std::endl; + +// Rev. John Robert Quincy Adams, B.A. M.Div. “Adams^John Robert Quincy^^Rev.^B.A. M.Div.” [One family name; three given names; no middle name; one prefix; two suffixes.] + PN pn3 = { "Adams", "John Robert Quincy", "", "Rev.", "B.A. M.Div." }; + pn3.Print( std::cout ); + std::cout << std::endl; +// Susan Morrison-Jones, Ph.D., Chief Executive Officer “Morrison-Jones^Susan^^^Ph.D., Chief Executive Officer” [Two family names; one given name; no middle name; no prefix; two suffixes.] + PN pn4 = { "Morrison-Jones", "Susan", "", "", "Ph.D., Chief Executive Officer" }; + pn4.Print( std::cout ); + std::cout << std::endl; + +// John Doe “Doe^John” [One family name; one given name; no middle name, prefix, or suffix. Delimiters have been omitted for the three trailing null components.] + PN pn5 = { "Doe", "John" }; + pn5.Print( std::cout ); + std::cout << std::endl; + + +// (for examples of the encoding of Person Names using multi-byte character sets see Annex H) +// Smith^Fluffy [A cat, rather than a +//human, whose responsible party family name is Smith, and whose own name is Fluffy] + PN pn6 = { "Smith", "Fluffy" }; + pn6.Print( std::cout ); + std::cout << std::endl; +//ABC Farms^Running on Water [A horse whose responsible organization is named ABC Farms, and whose name is “Running On Water”] + PN pn7 = { "ABC Farms", "Running on Water" }; + pn7.Print( std::cout ); + std::cout << std::endl; + + + + + std::cout << "TM:" << sizeof (TM) << std::endl; + TM tm1 = { 7, 12, 49, 999999 }; + tm1.Print( std::cout ); + std::cout << std::endl; + + TM tm2 = { 23, 59, 59, 999999 }; + tm2.Print( std::cout ); + std::cout << std::endl; + + TM tm3 = { 0, 0, 0, 0 }; + tm3.Print( std::cout ); + std::cout << std::endl; + + + UI ui = { + "1234567890.1234567890.1234567890.1234567890.1234567890.123456789" }; + ui.Print( std::cout ); + std::cout << std::endl; + + //S s = "10"; + S s = { '1' }; + s.Print(std::cout); + std::cout << std::endl; + + std::cout << "Tri:" << std::endl; + Tri t1 = { 0 }; + std::cout << t1.Internal << std::endl; + Tri t2 = { 1 }; + std::cout << t2.Internal << std::endl; + Tri t3 = { 2 }; + std::cout << t3.Internal << std::endl; + Tri t4 = { 3 }; + std::cout << t4.Internal << std::endl; + Tri t5 = { '+' }; + std::cout << t5.Internal << std::endl; + Tri t6 = { '-' }; + std::cout << t6.Internal << std::endl; + Tri t7 = { -1 }; + std::cout << t7.Internal << std::endl; + + //DateFormat df = 'Y'; + + return 0; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestElement4.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestElement4.cxx new file mode 100644 index 0000000..0cceb0b --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestElement4.cxx @@ -0,0 +1,32 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include + +struct A +{ + float Internal; +}; + +struct B +{ + float Internal[1]; +}; + +int TestElement4(int, char *[]) +{ + std::cout << sizeof( A ) << std::endl; + std::cout << sizeof( B ) << std::endl; + + return 0; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestElement5.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestElement5.cxx new file mode 100644 index 0000000..97b9b20 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestElement5.cxx @@ -0,0 +1,64 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmElement.h" +#include "gdcmVR.h" + +#include + +int TestLO() +{ + gdcm::Element el; + const char str[] = "WINDOW1\\WINDOW2\\WINDOW3"; + const size_t lenstr = strlen(str); + std::stringstream ss; + ss.str( str ); + unsigned int count = gdcm::VM::GetNumberOfElementsFromArray(str, lenstr); + gdcm::VR vr = gdcm::VR::LO; + //gdcm::VM vm = gdcm::VM::VM2; + //gdcm::VR vr = gdcm::VR::DS; + //if( len != vr.GetSizeof() * vm.GetLength() ) + // { + // return 1; + // } + el.SetLength( count * vr.GetSizeof() ); + el.Read( ss ); + std::cout << el.GetLength() << std::endl; + std::cout << el.GetValue(0) << std::endl; + std::cout << el.GetValue(1) << std::endl; + return 1; +} + +int TestElement5(int , char *[]) +{ + gdcm::Element spacing; + const char strspacing[] = "1.2345\\6.7890"; + std::stringstream ss; + ss.str( strspacing ); + unsigned int len = 2 * sizeof(double); + gdcm::VM vm = gdcm::VM::VM2; + gdcm::VR vr = gdcm::VR::DS; + if( len != vr.GetSizeof() * vm.GetLength() ) + { + return 1; + } + spacing.SetLength( len ); + spacing.Read( ss ); + std::cout << spacing.GetValue() << std::endl; + std::cout << spacing.GetValue(1) << std::endl; + + //int res = + TestLO(); + + return 0; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestExplicitDataElement.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestExplicitDataElement.cxx new file mode 100644 index 0000000..fc6bab2 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestExplicitDataElement.cxx @@ -0,0 +1,121 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmExplicitDataElement.h" +#include "gdcmStringStream.h" +#include "gdcmSwapper.h" + +int TestExplicitDataElement1(const uint16_t group, + const uint16_t element, + const char* vr, + const uint32_t vl) +{ + const char *str; + std::stringstream ss; + str = reinterpret_cast(&group); + ss.write(str, sizeof(group)); + str = reinterpret_cast(&element); + ss.write(str, sizeof(element)); + str = vr; + ss.write(str, 2); + ss.write("\0\0", 2); + str = reinterpret_cast(&vl); + ss.write(str, sizeof(vl)); + + gdcm::ExplicitDataElement de; + if( !de.Read(ss) ) + { + std::cerr << de << std::endl; + return 1; + } + if( de.GetTag().GetGroup() != group || + de.GetTag().GetElement() != element || + de.GetVL() != vl ) + { + std::cerr << de << std::endl; + return 1; + } + std::cout << de << std::endl; + return 0; +} + +int TestExplicitDataElement2(const uint16_t group, + const uint16_t element, + const char *vr, + const char *value) +{ + const char *str; + const uint32_t vl = strlen(value); + std::stringstream ss; + str = reinterpret_cast(&group); + ss.write(str, sizeof(group)); + str = reinterpret_cast(&element); + ss.write(str, sizeof(element)); + str = vr; + ss.write(str, 2); + ss.write("\0\0", 2); + str = reinterpret_cast(&vl); + ss.write(str, sizeof(vl)); + str = value; + ss.write(str, vl); + + gdcm::ExplicitDataElement de; + if( !de.Read(ss) ) + { + std::cerr << de << std::endl; + return 1; + } + if( de.GetTag().GetGroup() != group || + de.GetTag().GetElement() != element || + de.GetVL() != vl ) + { + std::cerr << de << std::endl; + return 1; + } + std::cout << de << std::endl; + return 0; +} + +inline void WriteRead(gdcm::DataElement const &w, gdcm::DataElement &r) +{ + // w will be written + // r will be read back + std::stringstream ss; + w.Write(ss); + r.Read(ss); +} + +int TestExplicitDataElement(int, char *[]) +{ + const uint16_t group = 0x0010; + const uint16_t element = 0x0012; + const char vr[] = "UN"; // UN => 4bytes vl + const uint32_t vl = 0x0; // 4 bytes + const char value[] = "GDCM"; + + int r = 0; + r += TestExplicitDataElement1(group, element, vr, vl); + r += TestExplicitDataElement2(group, element, vr, value); + + gdcm::ExplicitDataElement de1(gdcm::Tag(0x1234, 0x5678), 0x4321); + gdcm::ExplicitDataElement de2(gdcm::Tag(0x1234, 0x6789), 0x9876); + WriteRead(de1, de2); + if( !(de1 == de2) ) + { + std::cerr << de1 << std::endl; + std::cerr << de2 << std::endl; + return 1; + } + + return r; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestFile.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestFile.cxx new file mode 100644 index 0000000..4614759 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestFile.cxx @@ -0,0 +1,30 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmFile.h" +#include "gdcmSmartPointer.h" + +int TestFile(int argc, char *argv[]) +{ + (void)argc; + (void)argv; + gdcm::File f; + + gdcm::SmartPointer pf = new gdcm::File; + { + gdcm::SmartPointer other = pf; + } + + + return 0; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestFileMetaInformation.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestFileMetaInformation.cxx new file mode 100644 index 0000000..ffef0a0 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestFileMetaInformation.cxx @@ -0,0 +1,22 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmFileMetaInformation.h" + +int TestFileMetaInformation(int argc, char *argv[]) +{ + (void)argc; + (void)argv; + + return 0; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestFileSet.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestFileSet.cxx new file mode 100644 index 0000000..c09f7ca --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestFileSet.cxx @@ -0,0 +1,28 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmFileSet.h" +#include "gdcmFile.h" + +int TestFileSet(int argc, char *argv[]) +{ + (void)argc; + (void)argv; + gdcm::FileSet fs; + std::string f1; + std::string f2; + fs.AddFile( f1.c_str() ); + fs.AddFile( f2.c_str() ); + + return 0; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestFragment.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestFragment.cxx new file mode 100644 index 0000000..b58a731 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestFragment.cxx @@ -0,0 +1,24 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmFragment.h" + +int TestFragment(int argc, char *argv[]) +{ + (void)argc; + (void)argv; + gdcm::Fragment frag; + std::cout << frag << std::endl; + + return 0; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestImplicitDataElement.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestImplicitDataElement.cxx new file mode 100644 index 0000000..f7d2df6 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestImplicitDataElement.cxx @@ -0,0 +1,121 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmImplicitDataElement.h" +#include "gdcmStringStream.h" +#include "gdcmSwapper.h" + +int TestImplicitDataElement1(const uint16_t group, + const uint16_t element, + const uint32_t vl) +{ + const char *str; + std::stringstream ss; + str = reinterpret_cast(&group); + ss.write(str, sizeof(group)); + str = reinterpret_cast(&element); + ss.write(str, sizeof(element)); + str = reinterpret_cast(&vl); + ss.write(str, sizeof(vl)); + + gdcm::ImplicitDataElement de; + if( !de.Read(ss) ) + { + std::cerr << de << std::endl; + return 1; + } + if( de.GetTag().GetGroup() != group || + de.GetTag().GetElement() != element || + de.GetVL() != vl ) + { + std::cerr << de << std::endl; + return 1; + } + std::cout << de << std::endl; + return 0; +} + +int TestImplicitDataElement2(const uint16_t group, + const uint16_t element, + const char *value) +{ + const char *str; + const uint32_t vl = strlen(value); + std::stringstream ss; + str = reinterpret_cast(&group); + ss.write(str, sizeof(group)); + str = reinterpret_cast(&element); + ss.write(str, sizeof(element)); + str = reinterpret_cast(&vl); + ss.write(str, sizeof(vl)); + str = value; + ss.write(str, vl); + + gdcm::ImplicitDataElement de; + if( !de.Read(ss) ) + { + std::cerr << de << std::endl; + return 1; + } + if( de.GetTag().GetGroup() != group || + de.GetTag().GetElement() != element || + de.GetVL() != vl ) + { + std::cerr << de << std::endl; + return 1; + } + const gdcm::ByteValue *bv = + dynamic_cast(&de.GetValue()); + if( !bv ) + { + return 1; + } + if( !(gdcm::ByteValue(value, vl) == *bv ) ) + { + return 1; + } + std::cout << de << std::endl; + return 0; +} + +inline void WriteRead(gdcm::DataElement const &w, gdcm::DataElement &r) +{ + // w will be written + // r will be read back + std::stringstream ss; + w.Write(ss); + r.Read(ss); +} + +int TestImplicitDataElement(int, char *[]) +{ + const uint16_t group = 0x0010; + const uint16_t element = 0x0012; + const uint32_t vl = 0x0; + const char value[] = "GDCM"; + int r = 0; + r += TestImplicitDataElement1(group, element, vl); + r += TestImplicitDataElement2(group, element, value); + + gdcm::ImplicitDataElement de1(gdcm::Tag(0x1234, 0x5678), 0x4321); + gdcm::ImplicitDataElement de2(gdcm::Tag(0x1234, 0x6789), 0x9876); + WriteRead(de1, de2); + if( !(de1 == de2) ) + { + std::cerr << de1 << std::endl; + std::cerr << de2 << std::endl; + return 1; + } + + return r; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestInvalidDICOMFiles.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestInvalidDICOMFiles.cxx new file mode 100644 index 0000000..f4ff5f8 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestInvalidDICOMFiles.cxx @@ -0,0 +1,156 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmReader.h" +#include "gdcmWriter.h" +#include "gdcmFileMetaInformation.h" +#include "gdcmFile.h" +#include "gdcmTesting.h" +#include "gdcmMediaStorage.h" +#include "gdcmSystem.h" + +struct element { + const char *in; + const char *inmd5; + const char *outmd5; + size_t outlen; +}; + +// non of the input file can be read by DCMTK +// output file was check against DCMTK on Aug 12 2010 (MM) +static const element list[] = { + { "Enhanced_MR_Image_Storage_PixelSpacingNotIn_0028_0030.dcm", + "854653ae806c224bfae3f196af250311", + "e6d42da08e33e526dab4626864a1580e", + 26851994 }, + { "Siemens_CT_Sensation64_has_VR_RT.dcm", + "3388c4f8e35cdb3d9512823f71e2415b", + "cc57ee3ff427b859d3022071c8f1be95", + 526460 }, + { "ITK-GDCM-1.2.2.saysExplicitVR-butIsImplicitVR.dcm", + "1158160333e00c0d1f8a7fdcbe352cac", + "7fb2ef887fa29b9a793242b28d4e8258", + 199218 }, + { "MR_Philips_Intera_in_SQ_2001_e05f_item_wrong_lgt_use_NOSHADOWSEQ.dcm", + "a8091f92ae895c2ef70143487e29b7d3", + "6bf002815fad665392acab24f09caa5e", + 138596 }, + { "MR_Philips_Intera_No_PrivateSequenceImplicitVR.dcm", // still an issue !!! + "aa07de9c01765602fe722e9ef2d8b92a", + "aa07de9c01765602fe722e9ef2d8b92a", + 2106660 }, + { "MR_Philips_Intera_PrivateSequenceExplicitVR.dcm", + "a8091f92ae895c2ef70143487e29b7d3", + "6bf002815fad665392acab24f09caa5e", + 138596 }, + { "MR_Philips_Intera_SwitchIndianess_noLgtSQItem_in_trueLgtSeq.dcm", + "3bbffc4c87f4f5554fafad5f8a002552", + "df0e01aae299317db1719e4de72b8937", + 2106428 }, + { "illegal_UN_stands_for_SQ.dcm", // JPR ?? + "2e1aa4fbebd08bbdf252f57b8343a79a", + "4c6832a4378f5d953c1e92fdcbe43666", + 33972 }, +}; + +int TestInvalidDICOMFiles(int , char *[]) +{ + int r = 0; + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + const char *extradataroot = gdcm::Testing::GetDataExtraRoot(); + if( !extradataroot ) + { + return 1; + } + if( !gdcm::System::FileIsDirectory(extradataroot) ) + { + std::cerr << "No such directory: " << extradataroot << std::endl; + return 1; + } + static const size_t n = sizeof( list ) / sizeof( element ); + for( size_t i = 0; i < n; ++i ) + { + const element &el = list[i]; + std::string sfilename = extradataroot; + sfilename += "/gdcmSampleData/images_of_interest/"; + sfilename += el.in; + + // dcmdump --disable-cp246 ... + const char *filename = sfilename.c_str(); + if( !gdcm::System::FileExists(filename) ) + { + std::cerr << "No such file: " << filename << std::endl; + return 1; + } + + gdcm::Reader reader; + reader.SetFileName( filename ); + if ( !reader.Read() ) + { + std::cerr << "TestReadError: Failed to read: " << filename << std::endl; + return 1; + } + + //const char *ref = gdcm::Testing::GetMediaStorageFromFile(filename); + //std::cerr << "ref:" << ref << std::endl; + char digest_str[33]; + bool b = gdcm::Testing::ComputeFileMD5(filename, digest_str); + if( !b ) return 1; + std::string md5ref = el.inmd5; + if( md5ref != digest_str ) + { + std::cerr << "pb: " << md5ref << " vs " << digest_str << std::endl; + ++r; + } + + const char subdir[] = "TestInvalidDICOMFiles"; + // Create directory first: + std::string tmpdir = gdcm::Testing::GetTempDirectory( subdir ); + if( !gdcm::System::FileIsDirectory( tmpdir.c_str() ) ) + { + gdcm::System::MakeDirectory( tmpdir.c_str() ); + } + std::string outfilename = gdcm::Testing::GetTempFilename( filename, subdir ); + std::cout << "Corrected to: " << outfilename << std::endl; + + gdcm::Writer writer; + writer.SetFileName( outfilename.c_str() ); + writer.SetFile( reader.GetFile() ); + writer.SetCheckFileMetaInformation( false ); + if( !writer.Write() ) + { + std::cerr << "Failed to write: " << outfilename << std::endl; + ++r; + } + + char digest_str2[33]; + bool b2 = gdcm::Testing::ComputeFileMD5(outfilename.c_str(), digest_str2); + if( !b2 ) return 1; + std::string md5ref2 = el.outmd5; + if( md5ref2 != digest_str2 ) + { + std::cerr << "pb: " << md5ref2 << " vs " << digest_str2 << std::endl; + ++r; + } + // paranoid: + size_t s = gdcm::System::FileSize(outfilename.c_str()); + if ( s != el.outlen ) // identical in size ! + { + std::cerr << "pb size: " << s << std::endl; + ++r; + } + } + + return r; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestItem.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestItem.cxx new file mode 100644 index 0000000..4364a3e --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestItem.cxx @@ -0,0 +1,78 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmItem.h" +//#include "gdcmStringStream.h" +#include "gdcmVR.h" +#include "gdcmExplicitDataElement.h" +#include "gdcmSwapper.h" + +void CreateDataElement(gdcm::ExplicitDataElement &de, int offset) +{ + std::stringstream ss; + + gdcm::Tag tag(0x1234, (uint16_t)(0x5678+offset)); + gdcm::VR vr = gdcm::VR::UN; + const char str[] = "GDCM"; + uint32_t len = strlen(str); + assert( sizeof(uint32_t) == 4 ); + gdcm::ByteValue val(str, len); + tag.Write(ss); + vr.Write(ss); + const char *slen = reinterpret_cast(&len); + ss.write( slen, 4); + val.Write(ss); +#ifdef GDCM_WORDS_BIGENDIAN + de.Read( ss ); +#else + de.Read( ss ); +#endif + + std::cout << de << std::endl; +} + +int TestItem(int , char *[]) +{ + gdcm::Item item; + std::cout << item << std::endl; + + gdcm::Item it1; + gdcm::Item it2; + + gdcm::DataSet ds; + gdcm::ExplicitDataElement xde; + CreateDataElement(xde,0); + ds.Insert( xde ); + CreateDataElement(xde,1); + ds.Insert( xde ); + CreateDataElement(xde,2); + ds.Insert( xde ); + CreateDataElement(xde,3); + ds.Insert( xde ); + + std::cout << ds << std::endl; + + // undefined by default: + gdcm::Item it3; + gdcm::VL vl = it3.GetVL(); + if( !vl.IsUndefined() ) + { + return 1; + } + if( !it3.IsUndefinedLength() ) + { + return 1; + } + + return 0; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestLCNumeric.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestLCNumeric.cxx new file mode 100644 index 0000000..ea75366 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestLCNumeric.cxx @@ -0,0 +1,74 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmAttribute.h" + +#include /* setenv */ +#include + + +int TestLCNumeric(int , char *[]) +{ + //setenv("LC_NUMERIC", "fr_FR", 1); + //const char ss[] = "LC_NUMERIC=fr_FR"; + //setlocale(LC_NUMERIC,"C"); + + // Seems to only affect the local sscanf + char *l = setlocale(LC_NUMERIC,"fr_FR.UTF-8"); + if( !l ) + { + std::cerr << "Could not set LC_NUMERIC" << std::endl; + return 1; + } + + float a = 1. / 3; + + printf("Float: %f\n", a ); + + // The following affect all ostringstream + try + { + //std::locale b = std::locale( "fr_FR" ); + std::locale::global( std::locale( "fr_FR.UTF-8" ) ) ; + + //char *copy = strdup(ss); + //putenv(copy); + //free(copy); + std::ostringstream os; + os.imbue(std::locale::classic()); + double d = 1.2; + os << d; + std::string s = os.str(); + std::cout << "s:" << s << std::endl; + std::string::size_type pos_comma = s.find( "," ); + if( pos_comma != std::string::npos ) + { + std::cerr << "We found the comma symbol" << std::endl; + return 1; + } + std::string::size_type pos_dot = s.find( "." ); + if( pos_dot == std::string::npos ) + { + std::cerr << "We did not found the dot symbol" << std::endl; + return 1; + } + } + catch(std::exception &ex) + { + // ok something went wrong when setting up fr_FR locale. + // just ignore for now + std::cerr << "What: " << ex.what() << std::endl; + } + + return 0; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestLO.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestLO.cxx new file mode 100644 index 0000000..31e8fdd --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestLO.cxx @@ -0,0 +1,42 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmLO.h" +#include + +int TestLO(int , char *[]) +{ + gdcm::LO lo = "hello world !"; + if( !lo.IsValid() ) return 1; + + const char str[] = "this is LO1 \\this is LO2 \\ this is LO 3 "; + gdcm::LO lo1, lo2, lo3; + std::stringstream ss; + ss << str; + ss >> lo1; + ss.get(); + std::cout << lo1 << std::endl; + ss >> lo2; + ss.get(); + std::cout << lo2 << std::endl; + ss >> lo3; + ss.get(); + std::cout << lo3 << std::endl; + + std::string toolong(65, ' '); + gdcm::LO lo4 = gdcm::LO(toolong); + std::cout << lo4.size() << std::endl; + if ( lo4.IsValid() ) return 1; + + return 0; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestMediaStorage.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestMediaStorage.cxx new file mode 100644 index 0000000..2071eb4 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestMediaStorage.cxx @@ -0,0 +1,77 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmMediaStorage.h" + +int TestMediaStorage(int argc, char *argv[]) +{ + (void)argc; + (void)argv; + gdcm::MediaStorage ms; + if( !ms.IsUndefined() ) + { + std::cerr << "ms.IsUndefined" << std::endl; + return 1; + } + ms = gdcm::MediaStorage::SecondaryCaptureImageStorage; + if( ms != gdcm::MediaStorage::SecondaryCaptureImageStorage ) + { + std::cerr << "SecondaryCaptureImageStorage" << std::endl; + return 1; + } + ms.GuessFromModality( "MR" ); + if( ms != gdcm::MediaStorage::MRImageStorage ) + { + std::cerr << "MRImageStorage" << std::endl; + return 1; + } + ms.GuessFromModality( "MR" , 3 ); + if( ms != gdcm::MediaStorage::EnhancedMRImageStorage ) + { + std::cerr << "EnhancedMRImageStorage" << std::endl; + return 1; + } + //checks *MSStrings[] and MSModalityTypes[] length + gdcm::MediaStorage::MSType mst; + for ( mst = gdcm::MediaStorage::MediaStorageDirectoryStorage; mst < gdcm::MediaStorage::MS_END; mst = (gdcm::MediaStorage::MSType)(mst + 1) ) + { + if ( gdcm::MediaStorage::GetMSString(mst) == 0 ) + { + std::cerr << "GetMSString" << std::endl; + return 1; + } + } + mst = gdcm::MediaStorage::MS_END; + if ( gdcm::MediaStorage::GetMSString(mst) != 0 ) + { + std::cerr << "2: GetMSString" << std::endl; + return 1; + } + gdcm::MediaStorage ms2; + if ( ms2.GetModality() ) + { + return 1; + } + + // MediaStorage is really poorly implemented. We need to add a test to avoid dev shooting themself in the foot. + unsigned int nMSType = gdcm::MediaStorage::GetNumberOfMSType(); + unsigned int nMSString = gdcm::MediaStorage::GetNumberOfMSString(); + unsigned int nMSMod = gdcm::MediaStorage::GetNumberOfModality(); + if( nMSType != nMSString || nMSType != nMSMod ) + { + std::cerr << "you are shooting yourself in the foot, dear.: " << nMSType << "," << nMSString << "," << nMSMod << std::endl; + return 1; + } + + return 0; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestPDBHeader.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestPDBHeader.cxx new file mode 100644 index 0000000..1fa9a31 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestPDBHeader.cxx @@ -0,0 +1,60 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmPDBHeader.h" +#include "gdcmTesting.h" +#include "gdcmReader.h" + +int TestPDBHeader(int , char *[]) +{ + const char *dataroot = gdcm::Testing::GetDataRoot(); + // gdcmData/GE_MR_0025xx1bProtocolDataBlock.dcm + std::string filename = dataroot; + filename += "/GE_MR_0025xx1bProtocolDataBlock.dcm"; + gdcm::Reader reader; + reader.SetFileName( filename.c_str() ); + if( !reader.Read() ) + { + std::cerr << "Failed to read: " << filename << std::endl; + return 1; + } + + gdcm::PDBHeader pdb; + const gdcm::DataSet& ds = reader.GetFile().GetDataSet(); + + const gdcm::PrivateTag &t1 = pdb.GetPDBInfoTag(); + + bool found = false; + int ret = 0; + if( ds.FindDataElement( t1 ) ) + { + pdb.LoadFromDataElement( ds.GetDataElement( t1 ) ); + pdb.Print( std::cout ); + found = true; + } + if( !found ) + { + std::cerr << "no pdb tag found" << std::endl; + ret = 1; + } + + const gdcm::PDBElement &pe = pdb.GetPDBElementByName( "SEDESC" ); + std::cout << pe << std::endl; + if( pe.GetValue() != std::string("AX FSE T2") ) + { + std::cerr << "Value found: " << pe.GetValue() << std::endl; + ret = 1; + } + + return ret; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestParseException.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestParseException.cxx new file mode 100644 index 0000000..678a5aa --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestParseException.cxx @@ -0,0 +1,20 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmParseException.h" + +int TestParseException(int, char *[]) +{ + gdcm::ParseException pe; + return 0; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestParser.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestParser.cxx new file mode 100644 index 0000000..9e47c3b --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestParser.cxx @@ -0,0 +1,80 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + * Pseudo code for ultimately a SAX-like (Simple API for DICOM) + */ +#include "gdcmParser.h" + +#include +#include + +#include // for putchar + +namespace gdcm +{ + // FIXME +#define XML_FMT_INT_MOD "l" + +static void startElement(void *userData, const Tag &name, + const char *atts[]) +{ + int i; + int *depthPtr = (int *)userData; + for (i = 0; i < *depthPtr; i++) + putchar('\t'); + std::cout << name << std::endl; + *depthPtr += 1; +} + +static void endElement(void *userData, const Tag &name) +{ + int *depthPtr = (int *)userData; + *depthPtr -= 1; +} + +} // end namespace gdcm + +int TestParser(int argc, char *argv[]) +{ + if( argc < 2 ) + { + return 1; + } + std::string filename = argv[1]; + std::ifstream is( filename.c_str(), std::ios::binary ); + std::cout << "---------------------------Parsing file :[" << filename << "]" + << std::endl; + char buf[BUFSIZ]; + gdcm::Parser parser; + bool done; + int depth = 0; + parser.SetUserData(&depth); + parser.SetElementHandler(gdcm::startElement, gdcm::endElement); + do { + is.read(buf, sizeof(buf)); + size_t len = is.gcount(); + done = len < sizeof(buf); + if ( parser.Parse(buf, len, done) ) + { + fprintf(stderr, + "%s at line %" XML_FMT_INT_MOD "u\n", + gdcm::Parser::GetErrorString(parser.GetErrorCode()), + parser.GetCurrentByteIndex()); + return 1; + } + } while (!done); + + is.close(); + return 0; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestPreamble.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestPreamble.cxx new file mode 100644 index 0000000..cf16296 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestPreamble.cxx @@ -0,0 +1,31 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmPreamble.h" +#include "gdcmFileMetaInformation.h" + +int TestPreamble(int, char *[]) +{ +{ + gdcm::Preamble p; +} + gdcm::FileMetaInformation * m_pFileMetaInformation = new gdcm::FileMetaInformation(); + gdcm::Preamble *p = new gdcm::Preamble(); + + m_pFileMetaInformation->SetPreamble( *p ); + m_pFileMetaInformation->Clear(); + delete m_pFileMetaInformation; + m_pFileMetaInformation = NULL ; + delete p; + return 0; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestPrivateTag.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestPrivateTag.cxx new file mode 100644 index 0000000..0a9b6ec --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestPrivateTag.cxx @@ -0,0 +1,93 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmPrivateTag.h" + +int TestPrivateTag(int , char * []) +{ + gdcm::PrivateTag pt(0x29,0x1018,"SIEMENS CSA HEADER"); + if( pt != gdcm::Tag(0x0029,0x18) ) + { + std::cerr << pt << std::endl; + return 1; + } + if( pt.GetOwner() != std::string("SIEMENS CSA HEADER") ) + { + std::cerr << "[" << pt.GetOwner() << "]" << std::endl; + return 1; + } + + const char str[] = "0029,1019,SIEMENS CSA HEADER"; + + if( !pt.ReadFromCommaSeparatedString( str ) ) return 1; + + if( pt != gdcm::Tag(0x0029,0x19) ) + { + std::cerr << pt << std::endl; + return 1; + } + if( pt.GetOwner() != std::string("SIEMENS CSA HEADER") ) + { + std::cerr << "[" << pt.GetOwner() << "]" << std::endl; + return 1; + } + + const gdcm::PrivateTag pt1(0x1,0x2,"BLA"); + const char str0[] = ""; + const char str1[] = "1,2,BLA"; + const char str2[] = "1,65536,BLU"; + const char str3[] = "65536,2,BLU"; + const char str4[] = "65536,2"; + if( pt.ReadFromCommaSeparatedString( NULL ) ) + { + return 1; + } + if( pt.ReadFromCommaSeparatedString( str0 ) ) + { + return 1; + } + if( !pt.ReadFromCommaSeparatedString( str1 ) ) + { + return 1; + } + if( pt != pt1 ) + { + return 1; + } + if( pt.ReadFromCommaSeparatedString( str2 ) ) + { + return 1; + } + if( pt.ReadFromCommaSeparatedString( str3 ) ) + { + return 1; + } + if( pt.ReadFromCommaSeparatedString( str4 ) ) + { + return 1; + } + + gdcm::PrivateTag null(0x0,0x0,0); + if( null.GetOwner() == 0 ) + { + return 1; + } + + const gdcm::PrivateTag nospaces(0x12,0x34,"Philips MR Imaging DD 001"); + gdcm::PrivateTag spaces(0x12,0x34," Philips MR Imaging DD 001 "); + if( nospaces != spaces ) return 1; + spaces.SetOwner(" Philips MR Imaging DD 001 "); + if( nospaces != spaces ) return 1; + + return 0; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestReadPatientName.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestReadPatientName.cxx new file mode 100644 index 0000000..8a0dfb6 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestReadPatientName.cxx @@ -0,0 +1,29 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcm.h" + +int TestReadPatientName(int argc, char *argv[]) +{ + (void)argc; + gdcm::Parser p; + std::string filename = argv[1]; + p.SetFileName( filename ); + gdcm::Tag t(0x0010, 0x0010); + const char *v = p.Request( t ); + gdcm::Attributes pn( v ); + + std::cout << pn << std::endl; + + return 0; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestReader.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestReader.cxx new file mode 100644 index 0000000..179aeb7 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestReader.cxx @@ -0,0 +1,90 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmReader.h" +#include "gdcmFileMetaInformation.h" +#include "gdcmFile.h" +#include "gdcmTesting.h" +#include "gdcmMediaStorage.h" + +int TestRead(const char* filename, bool verbose = false) +{ + if( verbose ) + std::cout << "TestRead: " << filename << std::endl; + + gdcm::Reader reader; + reader.SetFileName( filename ); + if ( !reader.Read() ) + { + std::cerr << "TestReadError: Failed to read: " << filename << std::endl; + return 1; + } + +//commenting out the fmi and ds to avoid warnings + //const gdcm::FileMetaInformation &h = reader.GetFile().GetHeader(); + //std::cout << h << std::endl; + + //const gdcm::DataSet &ds = reader.GetFile().GetDataSet(); + //std::cout << ds << std::endl; + + const char *ref = gdcm::Testing::GetMediaStorageFromFile(filename); + gdcm::MediaStorage ms; + ms.SetFromFile( reader.GetFile() ); + if( !ref ) + { + std::cerr << "TestReadError: Missing MediaStorage: " << filename << std::endl; + std::cerr << "It should be: " << ms << std::endl; + return 1; + } + + if( ms.IsUndefined() && ref && *ref != 0 ) + { + std::cerr << "TestReadError: MediaStorage: " << filename << std::endl; + std::cerr << "It should be instead: " << ref << std::endl; + return 1; + } + + // Make sure it is the right one: + + if( ref && *ref != 0 && ms != gdcm::MediaStorage::GetMSType(ref) ) + { + std::cerr << "Error: Found MediaStorage: " << ms << " for " << filename << std::endl; + std::cerr << "It should be instead: " << ref << std::endl; + return 1; + } + + return 0; +} + +int TestReader(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestRead(filename, true); + } + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestRead( filename ); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestReader2.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestReader2.cxx new file mode 100644 index 0000000..f0757cd --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestReader2.cxx @@ -0,0 +1,61 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmReader.h" + +#include "gdcmAttribute.h" +#include "gdcmElement.h" +#include "gdcmTesting.h" + +// D_CLUNIE_CT1_J2KI.dcm +// +int TestReader2(int , char *[]) +{ + //const char *filename = argv[1]; + std::string dataroot = gdcm::Testing::GetDataRoot(); + std::string filename = dataroot + "/012345.002.050.dcm"; + + gdcm::Reader reader; + reader.SetFileName( filename.c_str() ); + if ( !reader.Read() ) + { + std::cerr << "Failed to read: " << filename << std::endl; + return 1; + } + + const gdcm::DataSet &ds = reader.GetFile().GetDataSet(); + //gdcm::Attribute<0x0008,0x0008> a1; + //a1.Set( ds[ gdcm::Tag(0x0008,0x0008) ].GetValue() ); + //a1.Print( std::cout ); + + gdcm::Attribute<0x0020,0x0037> a2; + a2.SetFromDataElement( ds[ gdcm::Tag(0x0020,0x0037) ] ); + a2.Print( std::cout ); + std::cout << std::endl; + +/* + // (0043,1013) SS 107\21\4\2\20 # 10, 5 ReconKernelParameters + gdcm::Element el1; + el1.Set( ds[ gdcm::Tag(0x0043,0x1013) ].GetValue() ); + el1.Print( std::cout ); + std::cout << std::endl; + + // (0043,1031) DS [-11.200000\9.700000] # 20, 2 RACoordOfTargetReconCentre + gdcm::Element el2; + el2.Set( ds[ gdcm::Tag(0x0043,0x1031) ].GetValue() ); + el2.Print( std::cout ); + std::cout << std::endl; +*/ + + return 0; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestReader3.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestReader3.cxx new file mode 100644 index 0000000..ad173c0 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestReader3.cxx @@ -0,0 +1,261 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + * OS Specific: need a POSIX system with mmap functionality + */ +#include +#include +#include + +// fstat +#include +#include +#include /* close */ + +// open +#include +#include +#include + +// mmap +#include + +#include "gdcmFile.h" +#include "gdcmDataSet.h" +#include "gdcmFileMetaInformation.h" +#include "gdcmSmartPointer.h" +#include "gdcmReader.h" +#include "gdcmWriter.h" +#include "gdcmSystem.h" +#include "gdcmTesting.h" +#include "gdcmAttribute.h" + +#if 0 +class membuf: public std::streambuf +{ + public: + membuf(const char* filename) + :std::streambuf() + { + hFile = CreateFileA( + filename, + GENERIC_READ, + 0, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_READONLY, + NULL); + hFileMappingObject = CreateFileMapping( + hFile, + NULL, + PAGE_READONLY, + 0, + 0, + NULL); + beg = MapViewOfFile(hFileMappingObject, + FILE_MAP_READ, + 0, + 0, + 0); + char* e = (char*)beg; + e += GetFileSize( hFile, NULL ); + setg((char*)beg,(char*)beg,e); + setp(&outBuf,&outBuf); + } + /// Close the memory mapping and the opened + /// file. + ~membuf() + { + UnmapViewOfFile(beg); + CloseHandle( hFileMappingObject ); + CloseHandle( hFile ); + } + private: + /// We can't copy this. + membuf(const membuf&); + membuf& operator=(const membuf&); + /// Outbuf buffer that is not used since we + /// don't write to the memory map. + char outBuf; + HANDLE hFile,hFileMappingObject; + /// Pointer to the beginning of the mapped + /// memory area. + LPVOID beg; +}; +#endif + +/* + * http://beej.us/guide/bgipc/output/html/multipage/mmap.html + * http://www.dba-oracle.com/oracle_tips_mount_options.htm + */ + +class membuf : public std::streambuf +{ +public: + membuf(char* mem, size_t length) + { + setg(mem, mem, mem + length); + setp(mem, mem + length); + } + std::streampos seekpos(std::streampos pos, std::ios_base::openmode) + { + char *p = eback() + pos; + if(p>=eback() && p <=egptr()) + { + setg(eback(),p,egptr()); + return pos; + } + else + return -1; + } + + std::streampos seekoff(std::streamoff off, + std::ios_base::seekdir dir, std::ios_base::openmode) + { + char *p; + switch(dir) + { + case std::ios_base::beg: + p = eback() + off; + break; + case std::ios_base::cur: + p = gptr() + off; + break; + case std::ios_base::end: + p = egptr() + off; + break; + default: + p = 0; + break; + } + if(p>=eback() && p <= egptr()) + { + setg(eback(),p,egptr()); + return std::streampos(p-egptr()); + } + else + return -1; + } +}; + +std::istream & DoTheMMapRead(std::istream &is) +{ + gdcm::Reader reader; + reader.SetStream(is); + reader.Read(); + + //gdcm::Dumper printer; + //printer.SetFile ( reader.GetFile() ); + //printer.Print( std::cout ); + return is; +} + +int TestRead3(const char *subdir, const char * filename) +{ +/// FIXME Because GDCM is seeging back and forth in the DICOM file +// we cannot just apply mmap on any file, so let's clean them first: +// + gdcm::Reader r; + r.SetFileName( filename ); + if( !r.Read() ) + { + return 1; + } + // + // Create directory first: + const char * tmpdir = gdcm::Testing::GetTempDirectory( subdir ); + if( !gdcm::System::FileIsDirectory( tmpdir ) ) + { + gdcm::System::MakeDirectory( tmpdir ); + //return 1; + } + const char * outfilename = gdcm::Testing::GetTempFilename( filename, subdir ); + + // HACK: + gdcm::DataSet &ds = r.GetFile().GetDataSet(); + gdcm::Attribute<0x0008,0x0018> at; + if( !ds.FindDataElement( at.GetTag() ) || ds.GetDataElement( at.GetTag() ).IsEmpty() ) + { + const gdcm::UIComp dummyuid = "1.2.3.4.5.6.7.8.9.0"; + at.SetValue( dummyuid ); + ds.Replace( at.GetAsDataElement() ); + } + gdcm::Writer w; + w.SetFile( r.GetFile() ); + w.SetFileName( outfilename ); + if( !w.Write() ) + { + return 1; + } + const char *path = outfilename; + bool readonly = true; + int flags = (readonly ? O_RDONLY : O_RDWR); + + int handle = ::open(path, flags, S_IRWXU); + + struct stat info; + const bool success = ::fstat(handle, &info) != -1; + if( !success ) return 1; + off_t size = info.st_size; + + off_t offset = 0; + char* hint = 0; + void* data = ::mmap( hint, size, + readonly ? PROT_READ : (PROT_READ | PROT_WRITE), + readonly ? MAP_PRIVATE : MAP_SHARED, + handle, offset ); + if (data == MAP_FAILED) { + return 1; + } + char *chardata = reinterpret_cast(data); + + membuf mb( chardata, size ); + std::istream is(&mb) ; + + DoTheMMapRead(is); + + // cleanup + assert( handle ); + bool error = false; + error = ::munmap(data, size) != 0 || error; + error = ::close(handle) != 0 || error; + handle = 0; + + if ( error ) return 1; + + return 0; +} + +int TestReader3(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestRead3(argv[0], filename); + } + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestRead3( argv[0], filename ); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestReader4.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestReader4.cxx new file mode 100644 index 0000000..e861a87 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestReader4.cxx @@ -0,0 +1,51 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmReader.h" + +#include "gdcmTesting.h" + +// Reproduce issue #3538586 +int TestReader4(int , char *[]) +{ + const char subdir[] = "TestReader4"; + std::string tmpdir = gdcm::Testing::GetTempDirectory( subdir ); + if( !gdcm::System::FileIsDirectory( tmpdir.c_str() ) ) + { + gdcm::System::MakeDirectory( tmpdir.c_str() ); + } + std::string outfilename = tmpdir; + outfilename += "/"; + outfilename += "fake.jpg"; + + const unsigned char jpeg[] = { 0xFF,0xD8,0xFF,0xE0,0x00,0x10,0x4A,0x46 }; + std::ofstream out( outfilename.c_str() ); + out.write( (char*)jpeg, sizeof( jpeg ) ); + out.close(); + + const char *filename = outfilename.c_str(); + gdcm::Reader reader; + reader.SetFileName( filename ); + if ( reader.Read() ) + { + std::cerr << "Success to read zip file !: " << filename << std::endl; + return 1; + } + if ( reader.Read() ) + { + std::cerr << "Success to read zip file !: " << filename << std::endl; + return 1; + } + + return 0; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestReaderCanRead.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestReaderCanRead.cxx new file mode 100644 index 0000000..acc16ad --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestReaderCanRead.cxx @@ -0,0 +1,163 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmReader.h" +#include "gdcmTesting.h" + +#include "gdcmFilename.h" +#include "gdcmSystem.h" +#include "gdcmWriter.h" +#include "gdcmDirectory.h" + +int TestReadCanRead(const char *subdir, const char* filename, bool verbose = false) +{ + if( verbose ) + std::cout << "TestReadCanRead: " << filename << std::endl; + + bool b1, b2; + + gdcm::Reader reader; + reader.SetFileName( filename ); + b1 = reader.CanRead(); + b2 = reader.Read(); + + gdcm::Filename fn( filename ); + const char *name = fn.GetName(); + int ret = 1; + const char dicomdir_bad[] = + "gdcmSampleData/ForSeriesTesting/Perfusion/DICOMDIR"; + if( fn.EndWith( dicomdir_bad ) ) + { + ret = 0; + } + // This is not an error if you are in the black list: + if( strcmp(name, "BuggedDicomWorksImage_Hopeless.dcm" ) != 0 + || strcmp(name, "Philips_Wrong_Terminator_XX_0277" ) != 0 + || strcmp(name, "DICOMDIR_noPATIENT_noSTUDY" ) != 0 + || strcmp(name, "JpegLosslessMultiframePapyrus.pap" ) != 0 + || strcmp(name, "Fish-1.img" ) != 0 + || strcmp(name, "NM_FromJulius_Caesar.dcm" ) != 0 + || strcmp(name, "Siemens-leonardo-bugged.dcm" ) != 0 + || strcmp(name, "illegal_UN_stands_for_OB.dcm" ) != 0 + || strcmp(name, "MR_PHILIPS_LargePreamble.dcm" ) != 0 + || strcmp(name, "illegal_UN_stands_for_OB.dcm.secu" ) != 0 ) + { + ret = 0; + } + if ( (b1 && !b2) || (!b1 && b2) ) + { + std::cerr << "TestReadCanRead: incompatible result " << filename << std::endl; + if( b1 ) + std::cerr << "TestReadCanRead: CanRead was true: " << filename << std::endl; + //assert( !ret ); + return ret; + } + + // Create directory first: + std::string tmpdir = gdcm::Testing::GetTempDirectory( subdir ); + if( !gdcm::System::FileIsDirectory( tmpdir.c_str() ) ) + { + gdcm::System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + std::string outfilename = gdcm::Testing::GetTempFilename( filename, subdir ); + + if( b1 && b2 ) + { + + gdcm::Writer writer; + writer.SetFileName( outfilename.c_str() ); + writer.GetFile().GetHeader().SetDataSetTransferSyntax( + reader.GetFile().GetHeader().GetDataSetTransferSyntax() ); + writer.GetFile().SetDataSet( reader.GetFile().GetDataSet() ); + writer.SetCheckFileMetaInformation( false ); + if( !writer.Write() ) + { + std::cerr << "Failed to write: " << outfilename << std::endl; + return 1; + } + + gdcm::Reader reader2; + reader2.SetFileName( outfilename.c_str() ); + b1 = reader2.CanRead( ); + //reader2.GetFile().GetHeader().GetPreamble().Remove(); + //assert( reader2.GetFile().GetHeader().GetPreamble().IsEmpty() ); + b2 = reader2.Read(); + if ( (b1 && !b2) || (!b1 && b2) ) + { + std::cerr << "TestReadCanRead|Write: incompatible result " << outfilename << std::endl; + if( b1 ) + std::cerr << "TestReadCanRead|Write: CanRead was true: " << outfilename << std::endl; + return 1; + } + } + + return 0; +} + +int TestReadCanReadExtra() +{ + const char *extradataroot = gdcm::Testing::GetDataExtraRoot(); + if( !extradataroot ) + { + return 0; + } + if( !gdcm::System::FileIsDirectory(extradataroot) ) + { + std::cerr << "No such directory: " << extradataroot << std::endl; + return 0; + } + + gdcm::Directory d; + unsigned int nfiles = d.Load( extradataroot, true ); // no recursion + std::cout << "done retrieving file list. " << nfiles << " files found." << std::endl; + + gdcm::Directory::FilenamesType const & fns = d.GetFilenames(); + int r = 0; + for( gdcm::Directory::FilenamesType::const_iterator it = fns.begin(); + it != fns.end(); ++it ) + { + const char *filename = it->c_str(); + r += TestReadCanRead( "TestReaderCanReadExtra", filename ); + } + + return r; +} + +int TestReaderCanRead(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestReadCanRead(argv[0], filename, true); + } + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + gdcm::Trace::ErrorOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestReadCanRead( argv[0], filename ); + ++i; + } + + //int r2 = + TestReadCanReadExtra(); + //r += r2; + + return r; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestReaderSelectedPrivateGroups.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestReaderSelectedPrivateGroups.cxx new file mode 100644 index 0000000..ed42294 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestReaderSelectedPrivateGroups.cxx @@ -0,0 +1,81 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmReader.h" +#include "gdcmFileMetaInformation.h" +#include "gdcmFile.h" +#include "gdcmTesting.h" +#include "gdcmMediaStorage.h" +#include "gdcmSystem.h" +#include "gdcmDirectory.h" + +int TestReadSelectedPrivateGroups(const char* filename, bool verbose = false) +{ + if( verbose ) + std::cout << "TestRead: " << filename << std::endl; + + std::ifstream is( filename, std::ios::binary ); + gdcm::Reader reader; + reader.SetStream( is ); + gdcm::PrivateTag group9(0x9,0x10,"GEMS_IDEN_01"); + std::set selectedtags; + selectedtags.insert ( group9 ); + if ( !reader.ReadSelectedPrivateTags( selectedtags ) ) + { + std::cerr << "TestReadSelectedGroups: Failed to read: " << filename << std::endl; + return 1; + } + + gdcm::File & file = reader.GetFile(); + gdcm::DataSet & ds = file.GetDataSet(); + std::cout << ds << std::endl; + + std::streamoff outStreamOffset = is.tellg(); + + if(verbose) + std::cout << "{ \"" << filename << "\"," << outStreamOffset << " }," << std::endl; + std::streamoff refoffset = gdcm::Testing::GetSelectedTagsOffsetFromFile(filename); + if( refoffset != outStreamOffset ) + { + std::cerr << filename << ": " << outStreamOffset << " should be " << refoffset << std::endl; + return 1; + } + is.close(); + + return 0; +} + + +int TestReaderSelectedPrivateGroups(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestReadSelectedPrivateGroups(filename, true); + } + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + gdcm::Trace::ErrorOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestReadSelectedPrivateGroups( filename ); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestReaderSelectedTags.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestReaderSelectedTags.cxx new file mode 100644 index 0000000..2566439 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestReaderSelectedTags.cxx @@ -0,0 +1,146 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmReader.h" +#include "gdcmFileMetaInformation.h" +#include "gdcmFile.h" +#include "gdcmTesting.h" +#include "gdcmMediaStorage.h" +#include "gdcmSystem.h" +#include "gdcmDirectory.h" +#include "gdcmFilename.h" + +int TestReadSelectedTags(const char* filename, bool verbose = false) +{ + if( verbose ) std::cout << "TestRead: " << filename << std::endl; + + std::ifstream is( filename, std::ios::binary ); + gdcm::Reader reader; + reader.SetStream( is ); + // Let's read up to Pixel Data Group Length el... + gdcm::Tag pixeldatagl (0x7fe0,0x0000); + std::set selectedtags; + selectedtags.insert ( pixeldatagl ); + if ( !reader.ReadSelectedTags( selectedtags ) ) + { + std::cerr << "TestReadSelectedTags : Failed to read: " << filename << std::endl; + return 1; + } + + std::streamoff outStreamOffset = is.tellg(); + + if(verbose) + std::cout << "{ \"" << filename << "\"," << outStreamOffset << " }," << std::endl; + std::streamoff refoffset = gdcm::Testing::GetSelectedTagsOffsetFromFile(filename); + if( refoffset != outStreamOffset ) + { + std::cerr << filename << ": " << outStreamOffset << " should be " << refoffset << std::endl; + return 1; + } + size_t filesize = gdcm::System::FileSize(filename); + assert( (size_t)refoffset <= filesize ); + + std::streamoff refoffset2 = gdcm::Testing::GetStreamOffsetFromFile(filename); + (void)refoffset2; + const gdcm::File & file = reader.GetFile(); + //const gdcm::DataSet & ds = file.GetDataSet(); + //const bool isfound = ds.FindDataElement( pixeldatagl ); + const gdcm::FileMetaInformation & fmi = file.GetHeader(); + const gdcm::TransferSyntax & ts = fmi.GetDataSetTransferSyntax(); + + gdcm::Filename fn( filename ); + const char *name = fn.GetName(); + // Special handling: + bool checkconsist = true; + if( strcmp(name, "DMCPACS_ExplicitImplicit_BogusIOP.dcm" ) == 0 + ) + { + checkconsist = false; + } + + if( (size_t)refoffset != filesize ) + { + if( checkconsist ) + { + if( ts.GetNegociatedType() == gdcm::TransferSyntax::Explicit ) + { + assert( refoffset + 12 == refoffset2 ); + } + else + { + assert( refoffset + 8 == refoffset2 ); + } + } + } + + is.close(); + + return 0; +} + +int TestReadSelectedTagsExtra() +{ + const char *extradataroot = gdcm::Testing::GetDataExtraRoot(); + if( !extradataroot ) + { + return 1; + } + if( !gdcm::System::FileIsDirectory(extradataroot) ) + { + std::cerr << "No such directory: " << extradataroot << std::endl; + return 1; + } + + gdcm::Directory d; + unsigned int nfiles = d.Load( extradataroot, true ); // no recursion + std::cout << "done retrieving file list. " << nfiles << " files found." << std::endl; + + gdcm::Directory::FilenamesType const & fns = d.GetFilenames(); + int r = 0; + for( gdcm::Directory::FilenamesType::const_iterator it = fns.begin(); + it != fns.end(); ++it ) + { + const char *filename = it->c_str(); + r += TestReadSelectedTags( filename ); + } + + return r; +} + +int TestReaderSelectedTags(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestReadSelectedTags(filename, true); + } + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + gdcm::Trace::ErrorOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestReadSelectedTags( filename ); + //r += TestReadSelectedTags( filename , true); + ++i; + } + + // puposely discard gdcmDataExtra test, this is just an 'extra' test... + int b2 = TestReadSelectedTagsExtra(); (void)b2; + + return r; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestReaderUpToTag.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestReaderUpToTag.cxx new file mode 100644 index 0000000..a4ca3a6 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestReaderUpToTag.cxx @@ -0,0 +1,116 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmReader.h" +#include "gdcmFileMetaInformation.h" +#include "gdcmFile.h" +#include "gdcmTesting.h" +#include "gdcmMediaStorage.h" +#include "gdcmSystem.h" +#include "gdcmDirectory.h" + +static int TestReadUpToTag(const char* filename, bool verbose = false) +{ + if( verbose ) + std::cout << "TestRead: " << filename << std::endl; + + std::ifstream is( filename, std::ios::binary ); + gdcm::Reader reader; + reader.SetStream( is ); + // Let's read up to Pixel Data el... + gdcm::Tag pixeldata (0x7fe0,0x0010); + std::set skiptags; + // ... but do not read it (to skip mem allocation) + skiptags.insert( pixeldata ); + if ( !reader.ReadUpToTag( pixeldata, skiptags) ) + { + std::cerr << "TestReadError: Failed to read: " << filename << std::endl; + return 1; + } + is.clear(); + std::streamoff outStreamOffset = is.tellg(); + +#if 0 + const gdcm::FileMetaInformation &h = reader.GetFile().GetHeader(); + const gdcm::DataSet &ds = reader.GetFile().GetDataSet(); + std::cout << ds << std::endl; +#endif + + if(verbose) + std::cout << "{ \"" << filename << "\"," << outStreamOffset << " }," << std::endl; + std::streamoff refoffset = gdcm::Testing::GetStreamOffsetFromFile(filename); + if( refoffset != outStreamOffset ) + { + std::cerr << filename << ": " << outStreamOffset << " should be " << refoffset << std::endl; + return 1; + } + is.close(); + + return 0; +} + +static int TestReadUpToTagExtra() +{ + const char *extradataroot = gdcm::Testing::GetDataExtraRoot(); + if( !extradataroot ) + { + return 1; + } + if( !gdcm::System::FileIsDirectory(extradataroot) ) + { + std::cerr << "No such directory: " << extradataroot << std::endl; + return 1; + } + + gdcm::Directory d; + unsigned int nfiles = d.Load( extradataroot, true ); // no recursion + std::cout << "done retrieving file list. " << nfiles << " files found." << std::endl; + + gdcm::Directory::FilenamesType const & fns = d.GetFilenames(); + int r = 0; + for( gdcm::Directory::FilenamesType::const_iterator it = fns.begin(); + it != fns.end(); ++it ) + { + const char *filename = it->c_str(); + r += TestReadUpToTag( filename ); + } + + return r; +} + +int TestReaderUpToTag(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestReadUpToTag(filename, true); + } + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + gdcm::Trace::ErrorOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestReadUpToTag( filename ); + ++i; + } + + // puposely discard gdcmDataExtra test, this is just an 'extra' test... + int b2 = TestReadUpToTagExtra(); (void)b2; + + return r; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestReaderUpToTag2.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestReaderUpToTag2.cxx new file mode 100644 index 0000000..1cb7670 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestReaderUpToTag2.cxx @@ -0,0 +1,126 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmReader.h" +#include "gdcmFileMetaInformation.h" +#include "gdcmFile.h" +#include "gdcmTesting.h" +#include "gdcmMediaStorage.h" +#include "gdcmSystem.h" +#include "gdcmDirectory.h" + +static int TestReadUpToTag2(const char* filename, bool verbose = false) +{ + if( verbose ) + std::cout << "TestRead: " << filename << std::endl; + + std::ifstream is( filename, std::ios::binary ); + gdcm::Reader reader; + reader.SetStream( is ); + // Let's read up to end + gdcm::Tag maxDataSetTag(0xffff,0xffff); + gdcm::Tag pixeldata (0x7fe0,0x0010); + std::set skiptags; + // ... but do not read Pixel Data attribute (to skip mem allocation) + skiptags.insert( pixeldata ); + if ( !reader.ReadUpToTag( maxDataSetTag, skiptags) ) + { + std::cerr << "TestReadError: Failed to read: " << filename << std::endl; + return 1; + } + std::streamoff outStreamOffset = is.tellg(); + bool iseof = is.eof(); + + //commenting out for warning avoidance + //const gdcm::FileMetaInformation &h = reader.GetFile().GetHeader(); + const gdcm::DataSet &ds = reader.GetFile().GetDataSet(); + if( ds.FindDataElement( pixeldata ) ) + { + std::cerr << "Found Pixel Data for: " << filename << std::endl; + return 1; + } + + if( !iseof ) + { + std::cerr << "Lost in out of space: " << outStreamOffset << " -> " << filename << std::endl; + return 1; + } + + if(verbose) + std::cout << "{ \"" << filename << "\"," << outStreamOffset << " }," << std::endl; + const std::streamoff refoffset = -1; + if( refoffset != outStreamOffset ) + { + std::cerr << filename << ": " << outStreamOffset << " " << iseof << " should be " << refoffset << std::endl; + return 1; + } + is.close(); + + return 0; +} + +static int TestReadUpToTag2Extra() +{ + const char *extradataroot = gdcm::Testing::GetDataExtraRoot(); + if( !extradataroot ) + { + return 1; + } + if( !gdcm::System::FileIsDirectory(extradataroot) ) + { + std::cerr << "No such directory: " << extradataroot << std::endl; + return 1; + } + + gdcm::Directory d; + unsigned int nfiles = d.Load( extradataroot, true ); // no recursion + std::cout << "done retrieving file list. " << nfiles << " files found." << std::endl; + + gdcm::Directory::FilenamesType const & fns = d.GetFilenames(); + int r = 0; + for( gdcm::Directory::FilenamesType::const_iterator it = fns.begin(); + it != fns.end(); ++it ) + { + const char *filename = it->c_str(); + r += TestReadUpToTag2( filename ); + } + + return r; +} + +int TestReaderUpToTag2(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestReadUpToTag2(filename, true); + } + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + gdcm::Trace::ErrorOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestReadUpToTag2( filename ); + ++i; + } + + // puposely discard gdcmDataExtra test, this is just an 'extra' test... + int b2 = TestReadUpToTag2Extra(); (void)b2; + + return r; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestSequenceOfFragments.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestSequenceOfFragments.cxx new file mode 100644 index 0000000..011018e --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestSequenceOfFragments.cxx @@ -0,0 +1,22 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmSequenceOfFragments.h" + +int TestSequenceOfFragments(int, char *[]) +{ + gdcm::SequenceOfFragments sf; + std::cout << sf << std::endl; + + return 0; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestSequenceOfItems.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestSequenceOfItems.cxx new file mode 100644 index 0000000..2ee7887 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestSequenceOfItems.cxx @@ -0,0 +1,42 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmSequenceOfItems.h" + +int TestSequenceOfItems(int, char *[]) +{ + gdcm::SequenceOfItems si; + std::cout << si << std::endl; + + gdcm::VL vl = si.GetLength(); + if( !vl.IsUndefined() ) + { + return 1; + } + if( !si.IsUndefinedLength() ) + { + return 1; + } + + gdcm::SmartPointer sq = new gdcm::SequenceOfItems(); + gdcm::DataElement des( gdcm::Tag(0xdead,0xbeef) ); + des.SetVR(gdcm::VR::SQ); + des.SetValue(*sq); + + if( !des.GetValueAsSQ()->IsUndefinedLength() ) + { + return 1; + } + + return 0; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestSequenceOfItems2.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestSequenceOfItems2.cxx new file mode 100644 index 0000000..a9e546a --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestSequenceOfItems2.cxx @@ -0,0 +1,80 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmSequenceOfItems.h" +#include "gdcmReader.h" +#include "gdcmTesting.h" +#include "gdcmPrivateTag.h" + +int TestSequenceOfItems2(int, char *[]) +{ + const char *dataroot = gdcm::Testing::GetDataRoot(); + // gdcmData/AMIInvalidPrivateDefinedLengthSQasUN.dcm + std::string filename = dataroot; + filename += "/AMIInvalidPrivateDefinedLengthSQasUN.dcm"; + gdcm::Reader reader; + reader.SetFileName( filename.c_str() ); + if( !reader.Read() ) + { + std::cerr << "Failed to read: " << filename << std::endl; + return 1; + } + + gdcm::PrivateTag pt(0x0009,0x10,"GEIIS"); + const gdcm::DataSet& ds = reader.GetFile().GetDataSet(); + + if( !ds.FindDataElement( pt ) ) + { + return 1; + } + + const gdcm::DataElement &de = ds.GetDataElement( pt ); + if( de.IsEmpty() ) return 1; + + std::cout << de << std::endl; + + gdcm::SmartPointer sqi = de.GetValueAsSQ(); + if( !sqi ) return 1; + + //std::cout << *sqi << std::endl; + //sqi->Print( std::cout ); + gdcm::SequenceOfItems::SizeType n = sqi->GetNumberOfItems(); + if( n != 1 ) return 1; + + const gdcm::Item & item = sqi->GetItem( 1 ); + const gdcm::DataSet &subds = item.GetNestedDataSet(); + + // std::cout << subds << std::endl; + gdcm::Tag ticonpixeldata(0x7fe0,0x0010); + //const gdcm::DataElement &iconpixeldata = subds.GetDataElement( ticonpixeldata ); +// const gdcm::ByteValue *bv = iconpixeldata.GetByteValue();//unused unless that lower #def is set to true + + // I could test that gdcm::JPEGCodec::GetHeaderInfo return JPEG file: + // JPEG image data, JFIF standard 1.01 + + gdcm::PrivateTag tgeiiscompressiontype(0x7fd1,0x10,"GEIIS"); + const gdcm::DataElement &geiiscompressiontype = subds.GetDataElement( tgeiiscompressiontype ); + gdcm::Element el; + el.SetFromDataElement( geiiscompressiontype ); + + unsigned int v = el.GetValue(); + if( v != 26 ) return 1; + +#if 0 + std::ofstream of( "/tmp/o.jpg", std::ios::binary ); + of.write( bv->GetPointer(), bv->GetLength() ); + of.close(); +#endif + + return 0; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestTag.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestTag.cxx new file mode 100644 index 0000000..9da93a6 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestTag.cxx @@ -0,0 +1,372 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmTag.h" + +#include "gdcmSwapper.h" + +int TestPrivate() +{ + gdcm::Tag t1(0x0009,0x0000); + if( t1.IsPublic() ) + { + return 1; + } + if( !t1.IsPrivate() ) + { + return 1; + } + if( t1.IsPrivateCreator() ) + { + return 1; + } + + gdcm::Tag t2(0x0009,0x0001); + if( t2.IsPublic() ) + { + return 1; + } + if( !t2.IsPrivate() ) + { + return 1; + } + if( t2.IsPrivateCreator() ) + { + return 1; + } + + gdcm::Tag t3(0x0009,0x0010); + if( t3.IsPublic() ) + { + return 1; + } + if( !t3.IsPrivate() ) + { + return 1; + } + if( !t3.IsPrivateCreator() ) + { + return 1; + } + + gdcm::Tag t4(0x0009,0x1010); + gdcm::Tag t4_creator(0x0009,0x0010); + if( t4.IsPublic() ) + { + return 1; + } + if( !t4.IsPrivate() ) + { + return 1; + } + if( t4.IsPrivateCreator() ) + { + return 1; + } + if( t4.GetPrivateCreator() != t4_creator ) + { + return 1; + } + return 0; +} + +int TestPipePrintRead() +{ + gdcm::Tag t(0x1234,0x5678); + const char pipesep[] = "1234|5678"; + + gdcm::Tag tprime(0x0,0x0); + if( !tprime.ReadFromPipeSeparatedString(pipesep) ) + { + return 1; + } + + if( tprime != t ) return 1; + + std::string str = t.PrintAsPipeSeparatedString(); + + if( str != pipesep ) return 1; + + return 0; +} + +int TestOperator() +{ + gdcm::Tag t1(0x1234,0x5678); + gdcm::Tag t1bis(0x1234,0x5678); + gdcm::Tag t2(0x1234,0x5679); + if( t2 < t1 ) + { + return 1; + } + if( !(t1 < t2) ) + { + return 1; + } + if( !(t1 == t1bis) ) + { + return 1; + } + if( !(t1 <= t1bis) ) + { + return 1; + } + return 0; +} + +int TestTag(int , char * []) +{ +{ + const uint32_t dummy = 0x12345678; + gdcm::Tag t16(0x1234, 0x5678); + std::stringstream ss; + t16.Write( ss ); + gdcm::Tag t16_2; + t16_2.Read( ss ); + + gdcm::Tag t32( dummy ); + if( t32 != t16 ) + { + return 1; + } + + gdcm::Tag t1; + gdcm::Tag t2(0,0); + if ( t1[0] != 0 ) + { + std::cerr << "1" << std::endl; + return 1; + } + if (t1[1] != 0 ) + {std::cout << "2" << std::endl ; return 1; } + + if (t2[0] != 0 ) + {std::cout << "3" << std::endl ; return 1; } + if (t2[1] != 0 ) + {std::cout << "4" << std::endl ; return 1; } + + if ( !(t1 == t2) ) + {std::cout << "5" << std::endl ; return 1; } + if ( t1 != t2 ) + {std::cout << "6" << std::endl ; return 1; } + if ( t1 < t2 ) + {std::cout << "7" << std::endl ; return 1; } + + unsigned int i; + + const uint32_t tag = dummy; + std::cout << "Just to inform : uint32_t value=" << std::hex << tag ; + std::cout << " stored in RAM as :"; + for (i=0;i> tag2; + //std::istringstream is; + //is.str( "1234567890" ); + //is >> tag2; + if( tag != tag2 ) + { + std::cout << tag << std::endl; + std::cout << tag2 << std::endl; + return 1; + } +} + + return 0; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestTorture.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestTorture.cxx new file mode 100644 index 0000000..171bfc4 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestTorture.cxx @@ -0,0 +1,62 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmReader.h" +#include "gdcmFileMetaInformation.h" + +#include "gdcmDataImages.h" + +int TestTortureRead(const char* filename) +{ + // TODO + unsigned long copy = rand()*original_size; + std::copy(new_file, filename); + + gdcm::Reader reader; + reader.SetFileName( new_file ); + if ( !reader.Read() ) + { + std::cerr << "Failed to read: " << filename << std::endl; + return 1; + } + + std::cerr << "Success to read: " << filename << std::endl; + + const gdcm::FileMetaInformation &h = reader.GetHeader(); + std::cout << h << std::endl; + + const gdcm::DataSet &ds = reader.GetDataSet(); + std::cout << ds << std::endl; + + return 0; +} + +int TestTorture(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestRead(filename); + } + + // else + int r = 0, i = 0; + const char *filename; + while( (filename = gdcmDataImages[i]) ) + { + r += TestRead( filename ); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestTransferSyntax.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestTransferSyntax.cxx new file mode 100644 index 0000000..9ca9463 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestTransferSyntax.cxx @@ -0,0 +1,116 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmTransferSyntax.h" + +static const int losslylosslessarray[][3] = { + { 0, 1, 1 }, // ImplicitVRLittleEndian = 0, + { 0, 1, 1 }, // ImplicitVRBigEndianPrivateGE, + { 0, 1, 1 }, // ExplicitVRLittleEndian, + { 0, 1, 1 }, // DeflatedExplicitVRLittleEndian, + { 0, 1, 1 }, // ExplicitVRBigEndian, + { 1, 0, 1 }, // JPEGBaselineProcess1, + { 1, 0, 1 }, // JPEGExtendedProcess2_4, + { 1, 0, 1 }, // JPEGExtendedProcess3_5, + { 1, 0, 1 }, // JPEGSpectralSelectionProcess6_8, + { 1, 0, 1 }, // JPEGFullProgressionProcess10_12, + { 0, 1, 0 }, // JPEGLosslessProcess14, + { 0, 1, 0 }, // JPEGLosslessProcess14_1, + { 0, 1, 0 }, // JPEGLSLossless, + { 1, 1, 1 }, // JPEGLSNearLossless, + { 0, 1, 0 }, // JPEG2000Lossless, + { 1, 1, 1 }, // JPEG2000, + { 0, 1, 0 }, // JPEG2000Part2Lossless, + { 1, 1, 1 }, // JPEG2000Part2, + { 0, 1, 0 }, // RLELossless, + { 1, 0, 1 }, // MPEG2MainProfile, + { 0, 1, 1 }, // ImplicitVRBigEndianACRNEMA, + { 0, 1, 1 }, // WeirdPapryus, + { 0, 1, 1 }, // CT_private_ELE, + { 1, 1, 1 }, // JPIPReferenced +}; + +static int TestTransferSyntaxAll() +{ + for(int i = 0; i < gdcm::TransferSyntax::TS_END; ++i ) + { + gdcm::TransferSyntax ts = (gdcm::TransferSyntax::TSType)i; + const int *ll = losslylosslessarray[i]; + if( ll[0] ) + { + if( !ts.IsLossy() ) + { + std::cerr << "Lossy Problem with: " << gdcm::TransferSyntax::GetTSString( ts ) << std::endl; + return 1; + } + } + if( ll[1] ) + { + if( !ts.IsLossless() ) + { + std::cerr << "Lossless Problem with: " << gdcm::TransferSyntax::GetTSString( ts ) << std::endl; + return 1; + } + } + if( ll[2] ) + { + if( !ts.CanStoreLossy() ) + { + std::cerr << "CanLossy Problem with: " << gdcm::TransferSyntax::GetTSString( ts ) << std::endl; + return 1; + } + } + } + return 0; +} + +int TestTransferSyntax(int argc, char *argv[]) +{ + (void)argc; + (void)argv; + if( TestTransferSyntaxAll() ) + { + return 1; + } + gdcm::TransferSyntax ts; + + ts = gdcm::TransferSyntax::JPEG2000; + if( !ts.IsLossless() ) + { + return 1; + } + if( !ts.IsLossy() ) + { + return 1; + } + ts = gdcm::TransferSyntax::JPEGLosslessProcess14_1; + if( !ts.IsLossless() ) + { + return 1; + } + if( ts.IsLossy() ) + { + return 1; + } + ts = gdcm::TransferSyntax::DeflatedExplicitVRLittleEndian; + if( !ts.IsLossless() ) + { + return 1; + } + if( ts.IsLossy() ) + { + return 1; + } + + return 0; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestVL.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestVL.cxx new file mode 100644 index 0000000..3e17725 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestVL.cxx @@ -0,0 +1,25 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmVL.h" + +int TestVL(int, char *[]) +{ + gdcm::VL vl; + if( vl != 0 ) + { + return 1; + } + + return 0; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestVM.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestVM.cxx new file mode 100644 index 0000000..1be049a --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestVM.cxx @@ -0,0 +1,188 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmVM.h" +#include // strcmp + +int TestVM(int, char *[]) +{ + //gdcm::VM::VMType vm = gdcm::LengthToVM<1>::TVM; + + const char str1[] = " 1\\2"; + unsigned int count1 = gdcm::VM::GetNumberOfElementsFromArray(str1, (unsigned int)strlen(str1) ); + if( count1 != 2 ) return 1; + + const char str2[] = " 1\\2\\3"; + unsigned int count2 = gdcm::VM::GetNumberOfElementsFromArray(str2, (unsigned int)strlen(str2) ); + if( count2 != 3 ) return 1; + + const char str3[] = " 1"; + unsigned int count3 = gdcm::VM::GetNumberOfElementsFromArray(str3, (unsigned int)strlen(str3) ); + if( count3 != 1 ) return 1; + + const char str4[] = ""; + unsigned int count4 = gdcm::VM::GetNumberOfElementsFromArray(str4, (unsigned int)strlen(str4) ); + if( count4 != 0 ) return 1; + + const char *str5 = 0; + unsigned int count5 = gdcm::VM::GetNumberOfElementsFromArray(str5, 0); + if( count5 != 0 ) return 1; + + const char str6[] = " 1"; + unsigned int count6 = gdcm::VM::GetNumberOfElementsFromArray(str6, (unsigned int)strlen(str6) ); + if( count6 != 1 ) return 1; + + const char str7[] = " 1 \\ 2 "; + unsigned int count7 = gdcm::VM::GetNumberOfElementsFromArray(str7, (unsigned int)strlen(str7) ); + if( count7 != 2 ) return 1; + + const char str8[] = " "; + unsigned int count8 = gdcm::VM::GetNumberOfElementsFromArray(str8, (unsigned int)strlen(str8) ); + if( count8 != 0 ) + { + std::cerr << "count8 failed" << std::endl; + return 1; + } + + const char str9[] = " \\ "; + unsigned int count9 = gdcm::VM::GetNumberOfElementsFromArray(str9, (unsigned int)strlen(str9) ); + if( count9 != 0 ) return 1; + + const char str10[] = " 3 \\ "; + unsigned int count10 = gdcm::VM::GetNumberOfElementsFromArray(str10, (unsigned int)strlen(str10) ); + if( count10 != 1 ) return 1; + + if( gdcm::VM::VM1 & gdcm::VM::VM2 ) return 1; + if( gdcm::VM::VM1 & gdcm::VM::VM3 ) return 1; + if( gdcm::VM::VM1 & gdcm::VM::VM32 ) return 1; + + if( !(gdcm::VM::VM1 & gdcm::VM::VM1_2) ) return 1; + if( !(gdcm::VM::VM2 & gdcm::VM::VM1_2) ) return 1; + + if( !(gdcm::VM::VM1 & gdcm::VM::VM1_3) ) return 1; + if( !(gdcm::VM::VM2 & gdcm::VM::VM1_3) ) return 1; + if( !(gdcm::VM::VM3 & gdcm::VM::VM1_3) ) return 1; + + if( !(gdcm::VM::VM1 & gdcm::VM::VM1_n) ) return 1; + + if( gdcm::VM::VM1 & gdcm::VM::VM2_n ) return 1; + if( !(gdcm::VM::VM2 & gdcm::VM::VM2_n) ) return 1; + + if( gdcm::VM::VM1 & gdcm::VM::VM3_4 ) return 1; + if( !(gdcm::VM::VM3 & gdcm::VM::VM3_4) ) return 1; + if( !(gdcm::VM::VM4 & gdcm::VM::VM3_4) ) return 1; + + if( gdcm::VM::VM1 & gdcm::VM::VM3_3n ) return 1; + if( !(gdcm::VM::VM3 & gdcm::VM::VM3_3n) ) return 1; + if( !(gdcm::VM::VM9 & gdcm::VM::VM3_3n) ) return 1; + if( !(gdcm::VM::VM99 & gdcm::VM::VM3_3n) ) return 1; + + if( gdcm::VM::VM1 & gdcm::VM::VM4_4n ) return 1; + if( !(gdcm::VM::VM4 & gdcm::VM::VM4_4n) ) return 1; + + const char *vm1 = gdcm::VM::GetVMString( gdcm::VM::VM1 ); + if( strcmp(vm1, "1" ) != 0 ) + { + std::cerr << "Error:" << vm1 << std::endl; + return 1; + } + + const char *vm8 = gdcm::VM::GetVMString( gdcm::VM::VM8 ); + if( strcmp(vm8, "8" ) != 0 ) + { + std::cerr << "Error:" << vm8 << std::endl; + return 1; + } + + gdcm::VM vm = gdcm::VM::VM0; + std::cout << vm << std::endl; + vm = gdcm::VM::VM1; + std::cout << vm << std::endl; + vm = gdcm::VM::VM2; + std::cout << vm << std::endl; + vm = gdcm::VM::VM3; + std::cout << vm << std::endl; + vm = gdcm::VM::VM4; + std::cout << vm << std::endl; + vm = gdcm::VM::VM5; + std::cout << vm << std::endl; + vm = gdcm::VM::VM6; + std::cout << vm << std::endl; + vm = gdcm::VM::VM8; + std::cout << vm << std::endl; + vm = gdcm::VM::VM9; + std::cout << vm << std::endl; + vm = gdcm::VM::VM10; + std::cout << vm << std::endl; + vm = gdcm::VM::VM12; + std::cout << vm << std::endl; + vm = gdcm::VM::VM16; + std::cout << vm << std::endl; + vm = gdcm::VM::VM18; + std::cout << vm << std::endl; + vm = gdcm::VM::VM24; + std::cout << vm << std::endl; + vm = gdcm::VM::VM28; + std::cout << vm << std::endl; + vm = gdcm::VM::VM32; + std::cout << vm << std::endl; + vm = gdcm::VM::VM35; + std::cout << vm << std::endl; + vm = gdcm::VM::VM99; + std::cout << vm << std::endl; + vm = gdcm::VM::VM256; + std::cout << vm << std::endl; + vm = gdcm::VM::VM1_2; + std::cout << vm << std::endl; + vm = gdcm::VM::VM1_3; + std::cout << vm << std::endl; + vm = gdcm::VM::VM1_4; + std::cout << vm << std::endl; + vm = gdcm::VM::VM1_5; + std::cout << vm << std::endl; + vm = gdcm::VM::VM1_8; + std::cout << vm << std::endl; + vm = gdcm::VM::VM1_32; + std::cout << vm << std::endl; + vm = gdcm::VM::VM1_99; + std::cout << vm << std::endl; + vm = gdcm::VM::VM1_n; + std::cout << vm << std::endl; + vm = gdcm::VM::VM2_2n; + std::cout << vm << std::endl; + vm = gdcm::VM::VM2_n; + std::cout << vm << std::endl; + vm = gdcm::VM::VM3_4; + std::cout << vm << std::endl; + vm = gdcm::VM::VM3_3n; + std::cout << vm << std::endl; + vm = gdcm::VM::VM3_n; + std::cout << vm << std::endl; + vm = gdcm::VM::VM4_4n; + std::cout << vm << std::endl; + vm = gdcm::VM::VM7_7n; + std::cout << vm << std::endl; + //vm = gdcm::VM::VM_END; + //std::cout << vm << std::endl; + +{ + gdcm::VM vm1_ = gdcm::VM::VM8; + gdcm::VM vm2_ = gdcm::VM::VM1_n; + if ( !vm2_.Compatible( vm1_ ) ) + { + return 1; + } +} + + return 0; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestVR.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestVR.cxx new file mode 100644 index 0000000..06419cd --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestVR.cxx @@ -0,0 +1,256 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmVR.h" + +#include + +// Not used... +int verify() +{ + // avoid INVALID = 0 + for(int i = 1; i < 27; ++i) + { + gdcm::VR t = (gdcm::VR::VRType)(1 << i); + if( gdcm::VR::IsASCII( t ) != gdcm::VR::IsASCII2( t ) ) + { + std::cerr << t << std::endl; + return 1; + } + //if( gdcm::VR::IsBinary( t ) != gdcm::VR::IsBinary2( t ) ) + // { + // std::cerr << t << std::endl; + //// return 1; + // } + } + return 0; +} + +int TestValue() +{ + int k = 0; + gdcm::VR vr; + vr = gdcm::VR::INVALID; // = 0, + if( (int)vr != 0 ) + return 1; + vr = gdcm::VR::AE; // = 1, + if( (int)vr != (1 << k++) ) + return 1; + vr = gdcm::VR::AS; // = 2, + if( (int)vr != (1 << k++) ) + return 1; + vr = gdcm::VR::AT; // = 4, + if( (int)vr != (1 << k++) ) + return 1; + vr = gdcm::VR::CS; // = 8, + if( (int)vr != (1 << k++) ) + return 1; + vr = gdcm::VR::DA; // = 16, + if( (int)vr != (1 << k++) ) + return 1; + vr = gdcm::VR::DS; // = 32, + if( (int)vr != (1 << k++) ) + return 1; + vr = gdcm::VR::DT; // = 64, + if( (int)vr != (1 << k++) ) + return 1; + vr = gdcm::VR::FD; // = 256, + if( (int)vr != (1 << k++) ) + return 1; + vr = gdcm::VR::FL; // = 128, + if( (int)vr != (1 << k++) ) + return 1; + vr = gdcm::VR::IS; // = 512, + if( (int)vr != (1 << k++) ) + return 1; + vr = gdcm::VR::LO; // = 1024, + if( (int)vr != (1 << k++) ) + return 1; + vr = gdcm::VR::LT; // = 2048, + if( (int)vr != (1 << k++) ) + return 1; + vr = gdcm::VR::OB; // = 4096, + if( (int)vr != (1 << k++) ) + return 1; + vr = gdcm::VR::OF; // = 8192, + if( (int)vr != (1 << k++) ) + return 1; + vr = gdcm::VR::OW; // = 16384, + if( (int)vr != (1 << k++) ) + return 1; + vr = gdcm::VR::PN; // = 32768, + if( (int)vr != (1 << k++) ) + return 1; + vr = gdcm::VR::SH; // = 65536, + if( (int)vr != (1 << k++) ) + return 1; + vr = gdcm::VR::SL; // = 131072, + if( (int)vr != (1 << k++) ) + return 1; + vr = gdcm::VR::SQ; // = 262144, + if( (int)vr != (1 << k++) ) + return 1; + vr = gdcm::VR::SS; // = 524288, + if( (int)vr != (1 << k++) ) + return 1; + vr = gdcm::VR::ST; // = 1048576, + if( (int)vr != (1 << k++) ) + return 1; + vr = gdcm::VR::TM; // = 2097152, + if( (int)vr != (1 << k++) ) + return 1; + vr = gdcm::VR::UI; // = 4194304, + if( (int)vr != (1 << k++) ) + return 1; + vr = gdcm::VR::UL; // = 8388608, + if( (int)vr != (1 << k++) ) + return 1; + vr = gdcm::VR::UN; // = 16777216, + if( (int)vr != (1 << k++) ) + return 1; + vr = gdcm::VR::US; // = 33554432, + if( (int)vr != (1 << k++) ) + return 1; + vr = gdcm::VR::UT; // = 67108864, + if( (int)vr != (1 << k++) ) + return 1; + + return 0; +} + +int TestVR(int, char *[]) +{ + if( TestValue() ) + return 1; + + gdcm::VR vr = gdcm::VR::INVALID; + const char *inv = gdcm::VR::GetVRString(vr); + std::cout << 0 << "," << inv << std::endl; + int i; + for(i=0; i<27; i++) + { + int j = 1 << i; + //int k = gdcm::VR::GetIndex((gdcm::VR::VRType)j); + std::cout << "2^" << i << "=" << (int)j << "," << gdcm::VR::GetVRString((gdcm::VR::VRType)j) << std::endl; + } + + vr = gdcm::VR::OB_OW; + //int k = gdcm::VR::GetIndex(vr); + std::cout << i++ << "," << gdcm::VR::GetVRString(vr) << std::endl; + vr = gdcm::VR::US_SS; + //k = gdcm::VR::GetIndex(vr); + std::cout << i++ << "," << gdcm::VR::GetVRString(vr) << std::endl; + vr = gdcm::VR::US_SS_OW; + //k = gdcm::VR::GetIndex(vr); + std::cout << i++ << "," << gdcm::VR::GetVRString(vr) << std::endl; + + std::string s = "OB"; + vr = gdcm::VR::GetVRType(s.c_str()); + if( s != gdcm::VR::GetVRString(vr)) + return 1; + s = "UT"; + vr = gdcm::VR::GetVRType(s.c_str()); + if( s != gdcm::VR::GetVRString(vr)) + return 1; + std::string s2 = "OB or OW"; + gdcm::VR ob_ow = gdcm::VR::OB_OW; + vr = gdcm::VR::GetVRType(s2.c_str()); + if( vr != ob_ow ) + return 1; + if( s2 != gdcm::VR::GetVRString(vr)) + return 1; + // Check that "OB" is in "OB or OW" + s = "OB"; + if( !gdcm::VR::IsValid(s.c_str(), vr) ) + return 1; + std::string s3 = "US or SS or OW"; + vr = gdcm::VR::GetVRType(s3.c_str()); + // Check that "OB" is not in "US or SS or OW" + if( gdcm::VR::IsValid(s.c_str(), vr) ) + return 1; + s = "XX"; //invalid + vr = gdcm::VR::GetVRType(s.c_str()); + if( vr != gdcm::VR::VR_END ) + return 1; + const char *t = gdcm::VR::GetVRString(vr); + if( t != 0 ) + return 1; + + s = "??"; //invalid + vr = gdcm::VR::GetVRType(s.c_str()); + if( vr != gdcm::VR::INVALID) + return 1; + + // Test Partial Match + s = "US or SS"; + vr = gdcm::VR::GetVRType(s.c_str()); + if( vr == gdcm::VR::US ) + return 1; + +{ + vr = gdcm::VR::AE; + if( vr & gdcm::VR::VRASCII ) + { + std::cout << vr << "is ASCII\n"; + } + else + { + return 1; + } + vr = gdcm::VR::UI; + if( vr & gdcm::VR::VRASCII ) + { + std::cout << vr << "is ASCII\n"; + } + else + { + return 1; + } + vr = gdcm::VR::OB; + if( vr & gdcm::VR::VRBINARY ) + { + std::cout << vr << "is Binary\n"; + } + else + { + return 1; + } + vr = gdcm::VR::UI; + if( vr & (gdcm::VR::OB | gdcm::VR::OF | gdcm::VR::OW /*| gdcm::VR::SQ*/ | gdcm::VR::UN) ) + { + return 1; + } +} + + + // Let's check the & operator +{ + vr = gdcm::VR::OB; + if( !( vr.Compatible( gdcm::VR::OB_OW ) ) ) + { + return 1; + } +// if( !( vr.Compatible( gdcm::VR::INVALID) ) ) +// { +// return 1; +// } +} + // Make sure VR::UT is the last valid VR that can be found in a file: + //if( gdcm::VR::OB_OW <= gdcm::VR::UT ) return 1; + //else if( gdcm::VR::US_SS <= gdcm::VR::UT ) return 1; + //else if( gdcm::VR::US_SS_OW <= gdcm::VR::UT ) return 1; + //else if( gdcm::VR::VL32 <= gdcm::VR::UT ) return 1; + + + return 0; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestVRDS.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestVRDS.cxx new file mode 100644 index 0000000..5681949 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestVRDS.cxx @@ -0,0 +1,100 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmVR.h" +#include "gdcmAttribute.h" +#include "gdcmByteValue.h" + +#include +#include +#include + + +template +std::string TestVRDSFunc(const char *str) +{ + std::istringstream is( str ); + T d; + is >> d; + std::ostringstream os; + os << std::setprecision(MAXBYTES); + os << d; + std::cout << std::setprecision(MAXBYTES); + std::cout << d << std::endl; + std::string copy = os.str(); + return copy; +} + +/* + * Test to make sure that double precision ieee 'double' is ok for DICOM VR = 'DS' + */ +int TestVRDS(int, char *[]) +{ + const unsigned int dsmaxbytes = 16; + const char str0[dsmaxbytes+1] = "0.123456789123"; + std::string copy; + + // Let's demonstrate the float can easily fails; + if( (copy = TestVRDSFunc(str0)) == str0 ) + { + std::cerr << "Float works:" << copy << " vs " << str0 << std::endl; + return 1; + } + + // Repeat with double, it works this time + if( (copy = TestVRDSFunc(str0)) != str0 ) + { + std::cerr << "Double does not work:" << copy << " vs " << str0 << std::endl; + return 1; + } + + const double d1 = -118.242525316066; + const double d2 = 0.00149700609543456; + const double d3 = 0.059303515816892; + + gdcm::Attribute<0x20,0x32> at; + at.SetValue( d1, 0); + at.SetValue( d2, 1); + at.SetValue( d3, 2); + + gdcm::DataElement de = at.GetAsDataElement(); + std::cout << de << std::endl; + + const gdcm::ByteValue* bv = de.GetByteValue(); +{ + std::string str = bv->GetPointer(); + std::string::size_type pos1 = str.find("\\"); + std::string::size_type pos2 = str.find("\\", pos1 + 1); + + if( pos1 > dsmaxbytes ) + { + std::string s = str.substr(0, pos1); + std::cout << "Problem with: " << s << " " << s.size() << std::endl; + return 1; + } + if( (pos2 - pos1) > dsmaxbytes ) + { + std::string s = str.substr(pos1 + 1, pos2 - pos1 - 1); + std::cout << "Problem with: " << s << " " << s.size() << std::endl; + return 1; + } + if( (str.size() - pos2) > dsmaxbytes ) + { + std::string s = str.substr(pos2 + 1); + std::cout << "Problem with: " << s << " " << s.size() << std::endl; + return 1; + } +} + + return 0; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestVRLT.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestVRLT.cxx new file mode 100644 index 0000000..54fe7a4 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestVRLT.cxx @@ -0,0 +1,36 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmVR.h" + +#include +#include +#include + +using gdcm::LTComp; + +int TestVRLT(int, char *[]) +{ + LTComp lt = "hello"; + std::cout << lt << std::endl; + if( lt.size() % 2 ) + { + return 1; + } + if( lt[ lt.size() - 1] != ' ' ) + { + return 1; + } + + return 0; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestVRUI.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestVRUI.cxx new file mode 100644 index 0000000..639e7c4 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestVRUI.cxx @@ -0,0 +1,36 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmVR.h" + +#include +#include +#include + +using gdcm::UIComp; + +int TestVRUI(int, char *[]) +{ + UIComp ui = "1.2.3.4"; + std::cout << ui << "/" << ui.size() << std::endl; + if( ui.size() % 2 ) + { + return 1; + } + if( ui[ ui.size() - 1] != 0 ) + { + return 1; + } + + return 0; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestValue.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestValue.cxx new file mode 100644 index 0000000..4ce0d05 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestValue.cxx @@ -0,0 +1,68 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmByteValue.h" +#include "gdcmSequenceOfItems.h" +#include "gdcmStringStream.h" + +#include "gdcmSwapper.h" + +void PrintStream(IStream &is) +{ + char c; + while(is.get(c)) + { + std::cout << (int)c << std::endl; + } +} + +int CheckStream(IStream &is, int size) +{ + char c; + int t = 0; + while(is.get(c) && (int)c == t) + { + std::cerr << (int)c << std::endl; + ++t; + } + return t != size; +} + +int TestValue(int , char *[]) +{ + int r = 0; + gdcm::Value *v; + gdcm::SequenceOfItems si; + gdcm::ByteValue bv; + v = &si; + v = &bv; + + const int size = 128; + char buffer[size]; + for(int i=0; i(i); + } + std::stringstream ss; + ss.write(buffer, size); + //PrintStream(ss); + + v->SetLength( size ); + v->Read(ss); + std::stringstream ss2; + v->Write(ss2); + //PrintStream(ss2); + r += CheckStream(ss2, size); + + return r; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestWriter.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestWriter.cxx new file mode 100644 index 0000000..f8e46f6 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestWriter.cxx @@ -0,0 +1,146 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmReader.h" +#include "gdcmWriter.h" +#include "gdcmFilename.h" +#include "gdcmSystem.h" +#include "gdcmTesting.h" + +//bool IsImpossibleToRewrite(const char *filename) +//{ +// const char *impossible; +// int i = 0; +// while( (impossible= gdcmBlackListWriterDataImages[i]) ) +// { +// if( strcmp( impossible, filename ) == 0 ) +// { +// return true; +// } +// ++i; +// } +// return false; +//} + +namespace gdcm +{ + + +int TestWrite(const char *subdir, const char* filename, bool recursing, bool verbose = false) +{ + Reader reader; + reader.SetFileName( filename ); + if ( !reader.Read() ) + { + std::cerr << "Failed to read: " << filename << std::endl; + return 1; + } + + // Create directory first: + std::string tmpdir = Testing::GetTempDirectory( subdir ); + if( !System::FileIsDirectory( tmpdir.c_str() ) ) + { + System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + std::string outfilename = Testing::GetTempFilename( filename, subdir ); + + Writer writer; + writer.SetFileName( outfilename.c_str() ); + writer.SetFile( reader.GetFile() ); + writer.SetCheckFileMetaInformation( false ); + if( !writer.Write() ) + { + std::cerr << "Failed to write: " << outfilename << std::endl; + return 1; + } + + // Ok we have now two files let's compare their md5 sum: + char digest[33], outdigest[33]; + Testing::ComputeFileMD5(filename, digest); + Testing::ComputeFileMD5(outfilename.c_str(), outdigest); + if( strcmp(digest, outdigest) ) + { + if (recursing) + return 1; + // too bad the file is not identical, so let's be paranoid and + // try to reread-rewrite this just-writen file: + // TODO: Copy file System::CopyFile( ); + std::string subsubdir = subdir; + subsubdir += "/"; + subsubdir += subdir; + if( TestWrite(subsubdir.c_str(), outfilename.c_str(), true ) ) + { + std::cerr << filename << " and " + << outfilename << " are different\n"; + return 1; + } + const char * ref = Testing::GetMD5FromBrokenFile(filename); + if( ref ) + { + if( strcmp(ref, outdigest) == 0 ) + { + // ok this situation was already analyzed and the writen file is + // readable by dcmtk and such + //size_t size1 = System::FileSize( filename ); + //size_t size2 = System::FileSize( outfilename.c_str() ); + //assert( size1 == size2 ); // cannot deal with implicit VR meta data header + return 0; + } + std::cerr << "incompatible ref: " << ref << " vs " << outdigest << " for file: " << filename << " & " << outfilename << std::endl; + return 1; // ref exist but does not match, how is that possible ? + } + //if( !ref ) + // { + // return 1; + // } + // In theory I need to compare the two documents to check they + // are identical... TODO + std::cerr << filename << " and " + << outfilename << " are different, output can be read though. Need manual intervention\n"; + return 1; + } + else + { + size_t size1 = System::FileSize( filename ); + size_t size2 = System::FileSize( outfilename.c_str() ); + if( size1 != size2 ) return 1; + if(verbose) + std::cerr << filename << " and " << outfilename << " are identical\n"; + return 0; + } +} +} + +int TestWriter(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return gdcm::TestWrite(argv[0], filename, false, true); + } + + // else + int r = 0, i = 0; + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += gdcm::TestWrite(argv[0], filename, false ); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestWriter2.cxx b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestWriter2.cxx new file mode 100644 index 0000000..9d3e7e4 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestWriter2.cxx @@ -0,0 +1,121 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmReader.h" +#include "gdcmWriter.h" +#include "gdcmFilename.h" +#include "gdcmSystem.h" +#include "gdcmTesting.h" + +namespace gdcm +{ +/* + * we are only testing that we can convert an implicit dataset to explicit all the time... + */ +int TestWrite2(const char *subdir, const char* filename, bool ) +{ + Reader reader; + reader.SetFileName( filename ); + if ( !reader.Read() ) + { + std::cerr << "Failed to read: " << filename << std::endl; + return 1; + } + + // Create directory first: + std::string tmpdir = Testing::GetTempDirectory( subdir ); + if( !System::FileIsDirectory( tmpdir.c_str() ) ) + { + System::MakeDirectory( tmpdir.c_str() ); + } + std::string outfilename = Testing::GetTempFilename( filename, subdir ); + + // Invert Transfer Syntax just for fun: + const TransferSyntax &ts = reader.GetFile().GetHeader().GetDataSetTransferSyntax(); + if( ts.IsExplicit() && ts == TransferSyntax::ExplicitVRLittleEndian ) + { + reader.GetFile().GetHeader().SetDataSetTransferSyntax( gdcm::TransferSyntax::ImplicitVRLittleEndian ); + } + else if( ts.IsImplicit() ) + { + gdcm::FileMetaInformation &fmi = reader.GetFile().GetHeader(); + gdcm::TransferSyntax ts2 = gdcm::TransferSyntax::ImplicitVRLittleEndian; + ts2 = gdcm::TransferSyntax::ExplicitVRLittleEndian; + + const char *tsuid = gdcm::TransferSyntax::GetTSString( ts2 ); + gdcm::DataElement de( gdcm::Tag(0x0002,0x0010) ); + de.SetByteValue( tsuid, (uint32_t)strlen(tsuid) ); + de.SetVR( VR::UI ); //gdcm::Attribute<0x0002, 0x0010>::GetVR() ); + fmi.Replace( de ); + + reader.GetFile().GetHeader().SetDataSetTransferSyntax( gdcm::TransferSyntax::ExplicitVRLittleEndian ); + } + else + { + // nothing to test + return 0; + } + + const char str[] = "1.2.3.4.5.6.8.9.0"; + DataElement xde; + xde.SetByteValue(str, (uint32_t)strlen(str)); + xde.SetVR( VR::UI ); + xde.SetTag( Tag(0x0008,0x0018) ); + reader.GetFile().GetDataSet().Insert( xde ); + + + Writer writer; + writer.SetFileName( outfilename.c_str() ); + writer.SetFile( reader.GetFile() ); + //writer.SetCheckFileMetaInformation( true ); + if( !writer.Write() ) + { + std::cerr << "Failed to write: " << outfilename << std::endl; + return 1; + } + + Reader reader2; + reader2.SetFileName( outfilename.c_str() ); + if ( !reader2.Read() ) + { + std::cerr << "Failed to re-read: " << outfilename << std::endl; + return 1; + } + + return 0; + +} +} + +int TestWriter2(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return gdcm::TestWrite2(argv[0], filename, false ); + } + + // else + int r = 0, i = 0; + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += gdcm::TestWrite2(argv[0], filename, false ); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Java/CMakeLists.txt b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Java/CMakeLists.txt new file mode 100644 index 0000000..3d3f010 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Java/CMakeLists.txt @@ -0,0 +1,34 @@ +# Define the tests for gdcm-java +set(GDCM_JAVA_TEST_SRCS + TestReader + ) + +# Do not change anything after here: +find_package(Java REQUIRED) # javac, jar +find_package(JNI REQUIRED) +include_directories( + ${JNI_INCLUDE_PATH} + ) + +set(classfilesdep) + +foreach(example ${GDCM_JAVA_TEST_SRCS}) + add_custom_command( + OUTPUT ${EXECUTABLE_OUTPUT_PATH}/${example}.class + COMMAND ${Java_JAVAC_EXECUTABLE} ARGS ${CMAKE_CURRENT_SOURCE_DIR}/${example}.java -d ${EXECUTABLE_OUTPUT_PATH} -source 1.5 -target 1.5 -classpath ${LIBRARY_OUTPUT_PATH}/gdcm.jar + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${example}.java + COMMENT "javac ${example}.java" + ) + list(APPEND classfilesdep ${EXECUTABLE_OUTPUT_PATH}/${example}.class) + set_source_files_properties(${EXECUTABLE_OUTPUT_PATH}/${example}.class PROPERTIES CLASSPATH "${EXECUTABLE_OUTPUT_PATH}/gdcm.jar") + ADD_JAVA_TEST(${example}Java ${EXECUTABLE_OUTPUT_PATH}/${example}) +endforeach() + +# 3. ok now add the target +add_custom_target(GDCMJavaDSEDTests ALL + DEPENDS ${classfilesdep} + COMMENT "building gdcm java dsed tests" +) +# make sure gdcm.jar is built +add_dependencies(GDCMJavaDSEDTests GDCMJavaJar) diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Java/TestReader.java b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Java/TestReader.java new file mode 100644 index 0000000..c458454 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Java/TestReader.java @@ -0,0 +1,69 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + */ +import gdcm.*; +import java.util.Properties; +import java.util.Enumeration; + +public class TestReader +{ + public static void main(String[] args) throws Exception + { +/* + System.out.println("PATH : " + + System.getProperty("java.library.path")); + Properties p = System.getProperties(); + Enumeration keys = p.keys(); + while (keys.hasMoreElements()) { + String key = (String)keys.nextElement(); + String value = (String)p.get(key); + System.out.println(key + ": " + value); + } +*/ + + long nfiles = Testing.GetNumberOfFileNames(); + Trace.DebugOff(); + Trace.WarningOff(); + + for( long i = 0; i < nfiles; ++i ) + { + String filename = Testing.GetFileName( i ); + //System.out.println("Success reading: " + filename ); + Reader reader = new Reader(); + reader.SetFileName( filename ); + if ( !reader.Read() ) + { + throw new Exception("Could not read: " + filename ); + } + String ref = Testing.GetMediaStorageFromFile(filename); + if( ref == null ) + { + throw new Exception("Missing ref for: " + filename ); + } + MediaStorage ms = new MediaStorage(); + ms.SetFromFile( reader.GetFile() ); + if( ms.IsUndefined() && !"".equals( ref ) ) + { + // gdcm-CR-DCMTK-16-NonSamplePerPix.dcm is empty + throw new Exception("ref is undefined for: " + filename + " should be " + ref ); + } + MediaStorage.MSType ref_mstype = MediaStorage.GetMSType( ref ); + if( !"".equals( ref ) && ms.GetType() != ref_mstype ) + { + throw new Exception("incompatible type: " + ref + " vs " + ms.GetString() + " for " + filename ); + } + } + } +} diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Python/CMakeLists.txt b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Python/CMakeLists.txt new file mode 100644 index 0000000..225c63f --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Python/CMakeLists.txt @@ -0,0 +1,11 @@ +# Define the tests for gdcm-python +# gdcm-python +set(GDCM_PYTHON_TEST_SRCS + TestReader + TestTag + ) + +# Loop over files and create executables +foreach(name ${GDCM_PYTHON_TEST_SRCS}) + ADD_PYTHON_TEST(${name}Python ${name}.py) +endforeach() diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Python/TestReader.py b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Python/TestReader.py new file mode 100644 index 0000000..b765dd7 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Python/TestReader.py @@ -0,0 +1,43 @@ +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +import gdcm +import os,sys + +def TestRead(filename, verbose = False): + r = gdcm.Reader() + r.SetFileName( filename ) + sucess = r.Read() + #if verbose: print r.GetFile() + if verbose: print(r.GetFile().GetDataSet()) + return sucess + +if __name__ == "__main__": + sucess = 0 + try: + filename = os.sys.argv[1] + sucess += TestRead( filename, True ) + except: + # loop over all files: + gdcm.Trace.DebugOff() + gdcm.Trace.WarningOff() + t = gdcm.Testing() + nfiles = t.GetNumberOfFileNames() + for i in range(0,nfiles): + filename = t.GetFileName(i) + sucess += TestRead( filename ) + + + # Test succeed ? + sys.exit(sucess == 0) diff --git a/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Python/TestTag.py b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Python/TestTag.py new file mode 100644 index 0000000..e4c3a06 --- /dev/null +++ b/gdcm/Testing/Source/DataStructureAndEncodingDefinition/Python/TestTag.py @@ -0,0 +1,38 @@ +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +import gdcm +import os,sys + +if __name__ == "__main__": + o1 = gdcm.Tag(0x0000,0x0000) + o2 = gdcm.Tag(0x0010,0x0000) + o3 = gdcm.Tag(0x0000,0x0010) + o4 = gdcm.Tag(0x0010,0x0010) + + if o1 == o2: + sys.exit(1) + if o1 == o3: + sys.exit(1) + if o1 == o4: + sys.exit(1) + + if o1 != o1: + sys.exit(1) + + if o1 > o2: + print("Fail o1 > o2") + sys.exit(1) + + sys.exit(0) diff --git a/gdcm/Testing/Source/InformationObjectDefinition/CMakeLists.txt b/gdcm/Testing/Source/InformationObjectDefinition/CMakeLists.txt new file mode 100644 index 0000000..5fee2e1 --- /dev/null +++ b/gdcm/Testing/Source/InformationObjectDefinition/CMakeLists.txt @@ -0,0 +1,5 @@ +subdirs(Cxx) + +if(GDCM_WRAP_PYTHON) + subdirs(Python) +endif() diff --git a/gdcm/Testing/Source/InformationObjectDefinition/Cxx/CMakeLists.txt b/gdcm/Testing/Source/InformationObjectDefinition/Cxx/CMakeLists.txt new file mode 100644 index 0000000..11a2fa0 --- /dev/null +++ b/gdcm/Testing/Source/InformationObjectDefinition/Cxx/CMakeLists.txt @@ -0,0 +1,48 @@ +# Define the tests for Information Object Definition +# IOD +set(IOD_TEST_SRCS + TestTableReader + TestTable + TestTableEntry + TestType + TestModule + TestModules + TestModuleEntry + TestNestedModuleEntries + TestIODEntry + TestIOD + TestIODs + TestDefs + TestPatient + TestSeries + TestStudy + TestDefinedTerms + TestEnumeratedValues + TestUsage + #TestXMLDictReader + #TestXMLPrivateDictReader + ) + +# Add the include paths +include_directories( + "${GDCM_BINARY_DIR}/Source/Common" + "${GDCM_SOURCE_DIR}/Source/Common" + "${GDCM_SOURCE_DIR}/Source/DataStructureAndEncodingDefinition" + "${GDCM_SOURCE_DIR}/Source/DataDictionary" + "${GDCM_SOURCE_DIR}/Source/InformationObjectDefinition" + "${GDCM_BINARY_DIR}/Source/InformationObjectDefinition" # gdcmTables.h + ) + +create_test_sourcelist(IODTests gdcmIODTests.cxx ${IOD_TEST_SRCS} + EXTRA_INCLUDE gdcmTestDriver.h + ) +add_executable(gdcmIODTests ${IODTests}) +target_link_libraries(gdcmIODTests gdcmIOD gdcmMSFF) + +#Don't understand why I need that ?? +set(GDCM_IOD_TESTS "${EXECUTABLE_OUTPUT_PATH}/gdcmIODTests") + +# Loop over files and create executables +foreach(name ${IOD_TEST_SRCS}) + add_test(NAME ${name} COMMAND ${GDCM_IOD_TESTS} ${name}) +endforeach() diff --git a/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestDefinedTerms.cxx b/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestDefinedTerms.cxx new file mode 100644 index 0000000..b927947 --- /dev/null +++ b/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestDefinedTerms.cxx @@ -0,0 +1,20 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmDefinedTerms.h" + +int TestDefinedTerms(int, char *[]) +{ + gdcm::DefinedTerms dt; + return 0; +} diff --git a/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestDefs.cxx b/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestDefs.cxx new file mode 100644 index 0000000..cdb5c03 --- /dev/null +++ b/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestDefs.cxx @@ -0,0 +1,91 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmDefs.h" +#include "gdcmUIDs.h" +#include "gdcmGlobal.h" +#include "gdcmMediaStorage.h" +#include "gdcmSOPClassUIDToIOD.h" + +int TestDefs(int, char *[]) +{ + using gdcm::MediaStorage; + gdcm::Global& g = gdcm::Global::GetInstance(); + if( !g.LoadResourcesFiles() ) + { + std::cerr << "Could not LoadResourcesFiles" << std::endl; + return 1; + } + + const gdcm::Defs &defs = g.GetDefs(); + //std::cout << defs.GetMacros() << std::endl; + + int ret = 0; + gdcm::MediaStorage::MSType mst; + for ( mst = gdcm::MediaStorage::MediaStorageDirectoryStorage; + mst < gdcm::MediaStorage::MS_END; mst = (gdcm::MediaStorage::MSType)(mst + 1) ) + { + const char *iod = defs.GetIODNameFromMediaStorage(mst); + gdcm::UIDs uid; + uid.SetFromUID( gdcm::MediaStorage::GetMSString(mst) /*mst.GetString()*/ ); + if( !iod ) + { + // We do not support Private IODs (for now??) + if( mst != MediaStorage::PhilipsPrivateMRSyntheticImageStorage + && mst != MediaStorage::ToshibaPrivateDataStorage + && mst != MediaStorage::GEPrivate3DModelStorage + && mst != MediaStorage::Philips3D + && mst != MediaStorage::CSANonImageStorage + && mst != MediaStorage::GeneralElectricMagneticResonanceImageStorage ) + { + std::cerr << "Missing iod for MS: " << (int)mst << " " << + gdcm::MediaStorage::GetMSString(mst) << " "; //std::endl; + std::cerr << "MediaStorage is " << (int)mst << " [" << uid.GetName() << "]" << std::endl; + ++ret; + } + } + else + { + const char *iod_ref = gdcm::SOPClassUIDToIOD::GetIOD(uid); + if( !iod_ref ) + { + std::cerr << "Could not find IOD for SOPClass: " << uid << std::endl; + ++ret; + } + else + { + std::string iod_ref_str = iod_ref; + //iod_ref_str += " IOD Modules"; + if( iod_ref_str != iod ) + { + std::cerr << "UID: " << uid << " "; + std::cerr << "Incompatible IODs: [" << iod << "] versus ref= [" << + iod_ref_str << "]" << std::endl; + ++ret; + } + } + } + } + + unsigned int nm = MediaStorage::GetNumberOfModality(); + unsigned int nsop = gdcm::SOPClassUIDToIOD::GetNumberOfSOPClassToIOD(); + if( nm != nsop ) + { + std::cerr << "Incompatible MediaStorage knows: " << nm << + " SOP Classes while SOPClassUIDToIOD knows: " << nsop << " classes" << std::endl; + ++ret; + } + + //return ret; + return 0; +} diff --git a/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestEnumeratedValues.cxx b/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestEnumeratedValues.cxx new file mode 100644 index 0000000..ec49ea3 --- /dev/null +++ b/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestEnumeratedValues.cxx @@ -0,0 +1,20 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmEnumeratedValues.h" + +int TestEnumeratedValues(int, char *[]) +{ + gdcm::EnumeratedValues ev; + return 0; +} diff --git a/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestIOD.cxx b/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestIOD.cxx new file mode 100644 index 0000000..b44e324 --- /dev/null +++ b/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestIOD.cxx @@ -0,0 +1,57 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmIOD.h" +#include "gdcmDefs.h" +#include "gdcmGlobal.h" +#include "gdcmDicts.h" +#include "gdcmDict.h" +#include "gdcmType.h" +#include "gdcmIODs.h" + +int TestIOD(int, char *[]) +{ + using namespace gdcm; + gdcm::Global& g = gdcm::Global::GetInstance(); + if( !g.LoadResourcesFiles() ) + { + std::cerr << "Could not LoadResourcesFiles" << std::endl; + return 1; + } + + static const Defs &defs = g.GetDefs(); + static const gdcm::Dicts &dicts = g.GetDicts(); + static const IODs &iods = defs.GetIODs(); + static const gdcm::Dict &pubdict = dicts.GetPublicDict(); + + //const IOD& iod = defs.GetIODFromFile(*F); + + IODs::IODMapTypeConstIterator it = iods.Begin(); + for( ; it != iods.End(); ++it ) + { + const IODs::IODName &name = it->first; + (void)name; + const IOD &iod = it->second; + + gdcm::Dict::ConstIterator dictit = pubdict.Begin(); + for(; dictit != pubdict.End(); ++dictit) + { + const gdcm::Tag &tag = dictit->first; + gdcm::Type t = iod.GetTypeFromTag(defs, tag); + (void)t; + //std::cout << t << std::endl; + } + } + + return 0; +} diff --git a/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestIODEntry.cxx b/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestIODEntry.cxx new file mode 100644 index 0000000..51cb745 --- /dev/null +++ b/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestIODEntry.cxx @@ -0,0 +1,20 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmIODEntry.h" + +int TestIODEntry(int, char *[]) +{ + gdcm::IODEntry iode; + return 0; +} diff --git a/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestIODs.cxx b/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestIODs.cxx new file mode 100644 index 0000000..580958e --- /dev/null +++ b/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestIODs.cxx @@ -0,0 +1,20 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmIODs.h" + +int TestIODs(int, char *[]) +{ + gdcm::IODs iods; + return 0; +} diff --git a/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestModule.cxx b/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestModule.cxx new file mode 100644 index 0000000..fa116c8 --- /dev/null +++ b/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestModule.cxx @@ -0,0 +1,21 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmModule.h" + +int TestModule(int , char *[]) +{ + gdcm::Module module; + + return 0; +} diff --git a/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestModuleEntry.cxx b/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestModuleEntry.cxx new file mode 100644 index 0000000..48db674 --- /dev/null +++ b/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestModuleEntry.cxx @@ -0,0 +1,20 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmModuleEntry.h" + +int TestModuleEntry(int, char *[]) +{ + gdcm::ModuleEntry me("Image Type","1","Image identification characteristics. See C.8.3.1.1.1 for specialization."); + return 0; +} diff --git a/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestModules.cxx b/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestModules.cxx new file mode 100644 index 0000000..2b83b4d --- /dev/null +++ b/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestModules.cxx @@ -0,0 +1,21 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmModules.h" + +int TestModules(int , char *[]) +{ + gdcm::Modules modules; + + return 0; +} diff --git a/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestNestedModuleEntries.cxx b/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestNestedModuleEntries.cxx new file mode 100644 index 0000000..b86441a --- /dev/null +++ b/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestNestedModuleEntries.cxx @@ -0,0 +1,20 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmNestedModuleEntries.h" + +int TestNestedModuleEntries(int, char *[]) +{ + gdcm::NestedModuleEntries nme; + return 0; +} diff --git a/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestPatient.cxx b/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestPatient.cxx new file mode 100644 index 0000000..81d0ddb --- /dev/null +++ b/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestPatient.cxx @@ -0,0 +1,20 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmPatient.h" + +int TestPatient(int, char *[]) +{ + gdcm::Patient pat; + return 0; +} diff --git a/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestSeries.cxx b/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestSeries.cxx new file mode 100644 index 0000000..e4cf97d --- /dev/null +++ b/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestSeries.cxx @@ -0,0 +1,20 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmSeries.h" + +int TestSeries(int, char *[]) +{ + gdcm::Series series; + return 0; +} diff --git a/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestStudy.cxx b/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestStudy.cxx new file mode 100644 index 0000000..a6a3b10 --- /dev/null +++ b/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestStudy.cxx @@ -0,0 +1,20 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmStudy.h" + +int TestStudy(int, char *[]) +{ + gdcm::Study study; + return 0; +} diff --git a/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestTable.cxx b/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestTable.cxx new file mode 100644 index 0000000..69ed91c --- /dev/null +++ b/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestTable.cxx @@ -0,0 +1,20 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmTable.h" + +int TestTable(int, char *[]) +{ + gdcm::Table t; + return 0; +} diff --git a/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestTableEntry.cxx b/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestTableEntry.cxx new file mode 100644 index 0000000..5649ce3 --- /dev/null +++ b/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestTableEntry.cxx @@ -0,0 +1,20 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmTableEntry.h" + +int TestTableEntry(int , char *[]) +{ + gdcm::TableEntry te; + return 0; +} diff --git a/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestTableReader.cxx b/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestTableReader.cxx new file mode 100644 index 0000000..bf6849f --- /dev/null +++ b/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestTableReader.cxx @@ -0,0 +1,57 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmTableReader.h" +#include "gdcmModules.h" + +// generated file: +#include "gdcmTables.h" + +void TestReadTable(const char *filename) +{ + gdcm::Defs defs; + gdcm::TableReader tr(defs); + tr.SetFilename(filename); + tr.Read(); + + + const gdcm::Modules &modules = defs.GetModules(); + std::cout << modules << std::endl; + + const gdcm::Macros ¯os = defs.GetMacros(); + std::cout << macros << std::endl; + + const gdcm::IODs &iods = defs.GetIODs(); + std::cout << iods << std::endl; +} + +int TestTableReader(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + TestReadTable(filename); + return 0; + } + + // else + int i = 0; + const char *filename; + while( (filename = gdcmTables[i]) ) + { + TestReadTable( filename ); + ++i; + } + + return 0; +} diff --git a/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestType.cxx b/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestType.cxx new file mode 100644 index 0000000..9173a3f --- /dev/null +++ b/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestType.cxx @@ -0,0 +1,21 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#include "gdcmType.h" + +int TestType(int, char *[]) +{ + gdcm::Type type; + return 0; +} diff --git a/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestUsage.cxx b/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestUsage.cxx new file mode 100644 index 0000000..08cb93e --- /dev/null +++ b/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestUsage.cxx @@ -0,0 +1,20 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmUsage.h" + +int TestUsage(int, char *[]) +{ + gdcm::Usage u; + return 0; +} diff --git a/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestXMLDictReader.cxx b/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestXMLDictReader.cxx new file mode 100644 index 0000000..47d9d95 --- /dev/null +++ b/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestXMLDictReader.cxx @@ -0,0 +1,30 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmXMLDictReader.h" + +int TestXMLDictReader(int argc, char *argv[]) +{ + if( argc < 2 ) + { + return 1; + } + const char *filename = argv[1]; + gdcm::XMLDictReader tr; + tr.SetFilename(filename); + tr.Read(); + + std::cout << tr.GetDict() << std::endl; + + return 0; +} diff --git a/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestXMLPrivateDictReader.cxx b/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestXMLPrivateDictReader.cxx new file mode 100644 index 0000000..e0ba681 --- /dev/null +++ b/gdcm/Testing/Source/InformationObjectDefinition/Cxx/TestXMLPrivateDictReader.cxx @@ -0,0 +1,31 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmXMLPrivateDictReader.h" + +int TestXMLPrivateDictReader(int argc, char *argv[]) +{ + if( argc < 2 ) + { + return 1; + } + const char *filename = argv[1]; + gdcm::XMLPrivateDictReader tr; + tr.SetFilename(filename); + tr.Read(); + + std::cout << tr.GetPrivateDict() << std::endl; + //tr.GetPrivateDict().PrintXML(); + + return 0; +} diff --git a/gdcm/Testing/Source/InformationObjectDefinition/Python/CMakeLists.txt b/gdcm/Testing/Source/InformationObjectDefinition/Python/CMakeLists.txt new file mode 100644 index 0000000..8408758 --- /dev/null +++ b/gdcm/Testing/Source/InformationObjectDefinition/Python/CMakeLists.txt @@ -0,0 +1,10 @@ +# Define the tests for gdcm-python +# gdcm-python +set(GDCM_PYTHON_TEST_SRCS + TestMRModule + ) + +# Loop over files and create executables +foreach(name ${GDCM_PYTHON_TEST_SRCS}) + ADD_PYTHON_TEST(${name}Python ${name}.py) +endforeach() diff --git a/gdcm/Testing/Source/InformationObjectDefinition/Python/TestMRModule.py b/gdcm/Testing/Source/InformationObjectDefinition/Python/TestMRModule.py new file mode 100644 index 0000000..5afcb88 --- /dev/null +++ b/gdcm/Testing/Source/InformationObjectDefinition/Python/TestMRModule.py @@ -0,0 +1,34 @@ +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +import gdcm +import os,sys + +g = gdcm.Global.GetInstance() +g.LoadResourcesFiles() +defs = g.GetDefs() +modules = defs.GetModules() +macros = defs.GetMacros() +#module = modules.GetModule( "MR Image Module Attributes" ) +module = modules.GetModule( "C.8.3.1" ) +#print dir(module) + +mentry = module.GetModuleEntryInMacros( macros, gdcm.Tag(0x0018,0x0087) ) +#print dir(mentry) +print(mentry) +mentry = module.GetModuleEntryInMacros( macros, gdcm.Tag(0x0018,0x1080) ) +print(mentry) + +# Test succeed ? +sys.exit(0) diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/CMakeLists.txt b/gdcm/Testing/Source/MediaStorageAndFileFormat/CMakeLists.txt new file mode 100644 index 0000000..b93263c --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/CMakeLists.txt @@ -0,0 +1,6 @@ +# Always +subdirs(Cxx) + +if(GDCM_WRAP_PYTHON) + subdirs(Python) +endif() diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/CMakeLists.txt b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/CMakeLists.txt new file mode 100644 index 0000000..25c8b05 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/CMakeLists.txt @@ -0,0 +1,308 @@ +# Define the tests for Media Storage and File Format +# MSFF +set(MSFF_TEST_SRCS + TestAnonymizer + TestFileChangeTransferSyntax1 + TestFileStreamer1 + TestFileStreamer2 + TestFileStreamer3 + TestFileStreamer4 + TestFileStreamer5 + TestFileStreamer6 + TestFileAnonymizer1 + TestFileAnonymizer2 + TestFileAnonymizer3 + TestIconImageFilter + TestIconImageGenerator + TestIconImageGenerator2 + TestIconImageGenerator3 + TestIconImageGenerator4 + TestParseXPATH + TestValidate + TestAnonymizeEvent + TestFileDerivation + TestSegmentedPaletteColorLookupTable + TestPNMCodec + TestSpacing + TestSerieHelper + TestFileExplicitFilter + TestImageFragmentSplitter + TestTagPath + TestOrientation + TestIconImage + TestImageHelper + TestImageToImageFilter + TestImageChangeTransferSyntax1 + #TestImageChangePhotometricInterpretation + #TestImageChangePhotometricInterpretation2 # does not compile on mingw... + TestImageChangeTransferSyntax2 + TestImageChangeTransferSyntax3 + TestImageChangeTransferSyntax4 + # see below + TestImageChangeTransferSyntax6 + TestImageChangeTransferSyntax7 + TestImageApplyLookupTable + TestImageChangePlanarConfiguration + TestCoder + TestDecoder + TestRescaler + TestDumper + TestDictPrinter + TestApplicationEntity + TestStringFilter + TestUIDGenerator + TestUUIDGenerator + #TestUIDGenerator3 + TestXMLPrinter + TestPrinter + TestPrint + TestSorter + TestImageReader + TestStreamImageReader + TestImageRegionReader1 + TestImageRegionReader2 + TestImageRegionReader3 + #TestStreamImageWriter + TestImageReaderRandomEmpty + TestDirectionCosines + TestImageWriter + TestCodec + TestPDFCodec + TestRLECodec + TestAudioCodec + TestImage + TestPhotometricInterpretation + TestLookupTable + TestOverlay + TestOverlay3 + TestCurve + TestCurve2 + TestPixelFormat + TestPersonName + TestImageCodec + TestImageConverter + TestJPEGCodec + TestRAWCodec + TestDICOMDIR + TestWaveform + TestFiducials + TestEncapsulatedDocument + TestSpectroscopy + TestSurfaceWriter + TestSurfaceWriter2 + ) + +if(GDCM_DATA_ROOT) + set(MSFF_TEST_SRCS + ${MSFF_TEST_SRCS} + TestScanner + TestPrinter2 + TestIPPSorter + TestIPPSorter2 + TestIPPSorter3 + TestCopyDataSet + TestDataElementValueAsSQ + TestImageWriter2 + TestDICOMDIRGenerator1 # Must be after TestImageChangeTransferSyntax4 + TestDICOMDIRGenerator2 # Must be after TestImageChangeTransferSyntax4 + ) + # Those tests requires that openssl be linked in: + if(GDCM_USE_SYSTEM_OPENSSL) + set(MSFF_TEST_SRCS + ${MSFF_TEST_SRCS} + TestAnonymizer2 + TestAnonymizer3 + ) + endif() + if(GDCM_USE_SYSTEM_JSON) + set(MSFF_TEST_SRCS + ${MSFF_TEST_SRCS} + TestJSON1 + ) + endif() +endif() + +# gdcmDataExtra +if(GDCM_DATA_EXTRA_ROOT) + set(MSFF_TEST_SRCS + ${MSFF_TEST_SRCS} + TestSplitMosaicFilter + TestOverlay2 + TestImageRegionReader4 + ) +endif() + +if(GDCM_USE_JPEGLS) + set(MSFF_TEST_SRCS + ${MSFF_TEST_SRCS} + TestImageChangeTransferSyntax5 + ) +endif() + +if(GDCM_HAVE_PTHREAD_H) + set(MSFF_TEST_SRCS + ${MSFF_TEST_SRCS} + TestUIDGenerator2 + ) +endif() + +if(GDCM_PIXEL_SPACING_DATA_ROOT) + set(MSFF_TEST_SRCS + ${MSFF_TEST_SRCS} + TestImageReaderPixelSpacing + ) +endif() + +# Add the include paths +include_directories( + "${GDCM_BINARY_DIR}/Source/Common" + "${GDCM_SOURCE_DIR}/Source/Common" + "${GDCM_SOURCE_DIR}/Testing/Source/Data" + "${GDCM_BINARY_DIR}/Testing/Source/Data" + "${GDCM_SOURCE_DIR}/Source/DataStructureAndEncodingDefinition" + "${GDCM_SOURCE_DIR}/Source/DataDictionary" + "${GDCM_SOURCE_DIR}/Source/MediaStorageAndFileFormat" + ) + +create_test_sourcelist(MSFFTests gdcmMSFFTests.cxx ${MSFF_TEST_SRCS} + EXTRA_INCLUDE gdcmTestDriver.h + ) +add_executable(gdcmMSFFTests ${MSFFTests}) +target_link_libraries(gdcmMSFFTests gdcmMSFF) +if(GDCM_HAVE_PTHREAD_H) +target_link_libraries(gdcmMSFFTests pthread) +endif() + +#Don't understand why I need that ?? +set(GDCM_MSFF_TESTS "${EXECUTABLE_OUTPUT_PATH}/gdcmMSFFTests") + +# Loop over files and create executables +foreach(name ${MSFF_TEST_SRCS}) + add_test(NAME ${name} COMMAND ${GDCM_MSFF_TESTS} ${name}) +endforeach() +if(GDCM_DATA_ROOT) + set_tests_properties(TestDICOMDIRGenerator2 PROPERTIES WILL_FAIL ON) +endif() + +# We can only run the dcmtk cross-checking test *only* after all the tests have run +# in particular once the TestWriter is done. +foreach(filename ${gdcm_data_filenames_glob}) + get_filename_component(filename_name ${filename} NAME) + string(REGEX MATCH ${filename_name} bad_dicom ${black_list_reader}) + if(NOT bad_dicom) + if(GDCM_TEST_DCMTK) + if(DCMTK_DCMDUMP_EXECUTABLE) + # -M : load short tags + # -dc: disable correction + add_test(NAME "DCMDUMP-${filename_name}" COMMAND ${DCMTK_DCMDUMP_EXECUTABLE} -M -dc + "${GDCM_TEMP_DIRECTORY}/TestWriter/${filename_name}") + endif() + endif() + endif() +endforeach() + +# Repeat for dcdump +foreach(filename ${gdcm_data_filenames_glob}) + get_filename_component(filename_name ${filename} NAME) + string(REGEX MATCH ${filename_name} bad_dicom ${black_list_reader}) + if(NOT bad_dicom) + if(GDCM_TEST_DICOM3TOOLS) + if(DCDUMP_EXECUTABLE) + add_test(NAME "DCDUMP-${filename_name}" COMMAND "${DCDUMP_EXECUTABLE}" + "${GDCM_TEMP_DIRECTORY}/TestWriter/${filename_name}") + endif() + endif() + endif() +endforeach() + +# There is a new test that compress all images using the jpeg compression alg: +# try to decompress them with dcmtk: +file(MAKE_DIRECTORY "${GDCM_TEMP_DIRECTORY}/TestImageChangeTransferSyntax/dcmdjpeg/") + +foreach(filename ${gdcm_data_filenames_glob}) + get_filename_component(filename_name ${filename} NAME) + string(REGEX MATCH ${filename_name} bad_dicom ${black_list_reader}) + if(NOT bad_dicom) + if(GDCM_TEST_DCMTK) + if(DCMTK_DCMDJPEG_EXECUTABLE) + add_test(NAME "DCMDJPEG-${filename_name}" COMMAND ${DCMTK_DCMDJPEG_EXECUTABLE} + "${GDCM_TEMP_DIRECTORY}/TestImageChangeTransferSyntax/${filename_name}" + "${GDCM_TEMP_DIRECTORY}/TestImageChangeTransferSyntax/dcmdjpeg/${filename_name}") + # Special handling of the DICOMDIR files: + string(REGEX MATCH ${filename_name} is_dicomdir ${gdcm_data_dicomdir_filenames_glob}) + if(is_dicomdir) + #message("IS DICOMDIR ${filename_name}") + set_tests_properties("DCMDJPEG-${filename_name}" PROPERTIES WILL_FAIL TRUE) + endif() + endif() + endif() + endif() +endforeach() + +file(MAKE_DIRECTORY "${GDCM_TEMP_DIRECTORY}/TestImageChangeTransferSyntax3/dcmdrle/") + +foreach(filename ${gdcm_data_filenames_glob}) + get_filename_component(filename_name ${filename} NAME) + string(REGEX MATCH ${filename_name} bad_dicom ${black_list_reader}) + if(NOT bad_dicom) + if(GDCM_TEST_DCMTK) + if(DCMTK_DCMDRLE_EXECUTABLE) + add_test(NAME "DCMDRLE-${filename_name}" COMMAND ${DCMTK_DCMDRLE_EXECUTABLE} + "${GDCM_TEMP_DIRECTORY}/TestImageChangeTransferSyntax3/${filename_name}" + "${GDCM_TEMP_DIRECTORY}/TestImageChangeTransferSyntax3/dcmdrle/${filename_name}") + # Special handling of the DICOMDIR files: + string(REGEX MATCH ${filename_name} is_dicomdir ${gdcm_data_dicomdir_filenames_glob}) + if(is_dicomdir) + #message("IS DICOMDIR ${filename_name}") + set_tests_properties("DCMDRLE-${filename_name}" PROPERTIES WILL_FAIL TRUE) + endif() + # + endif() + endif() + endif() +endforeach() + +file(MAKE_DIRECTORY "${GDCM_TEMP_DIRECTORY}/TestImageChangeTransferSyntax5/dcmdjpls/") + +foreach(filename ${gdcm_data_filenames_glob}) + get_filename_component(filename_name ${filename} NAME) + string(REGEX MATCH ${filename_name} bad_dicom ${black_list_reader}) + if(NOT bad_dicom) + if(GDCM_TEST_DCMTK) + if(DCMTK_DCMDJPLS_EXECUTABLE) + #if(EXISTS "${GDCM_TEMP_DIRECTORY}/TestImageChangeTransferSyntax5/${filename_name}") + add_test(NAME "DCMDJPLS-${filename_name}" COMMAND ${DCMTK_DCMDJPLS_EXECUTABLE} + "${GDCM_TEMP_DIRECTORY}/TestImageChangeTransferSyntax5/${filename_name}" + "${GDCM_TEMP_DIRECTORY}/TestImageChangeTransferSyntax5/dcmdjpls/${filename_name}") + # Special handling of the DICOMDIR files: + string(REGEX MATCH ${filename_name} is_dicomdir ${gdcm_data_dicomdir_filenames_glob}) + if(is_dicomdir) + #message("IS DICOMDIR ${filename_name}") + set_tests_properties("DCMDJPLS-${filename_name}" PROPERTIES WILL_FAIL TRUE) + endif() + #endif() + # + endif() + endif() + endif() +endforeach() + +# Need to SET_TESTS_PROPERTIES only *after* the loop is done (test need to have been declared first) +if(GDCM_TEST_DCMTK) + if(GDCM_DATA_ROOT) + if(DCMTK_DCMDJPLS_EXECUTABLE) + # No pixel data + set_tests_properties("DCMDJPLS-ELSCINT1_PMSCT_RLE1.dcm" PROPERTIES WILL_FAIL TRUE) + endif() + if(DCMTK_DCMDJPEG_EXECUTABLE) + # No pixel data + set_tests_properties("DCMDJPEG-ELSCINT1_PMSCT_RLE1.dcm" PROPERTIES WILL_FAIL TRUE) + endif() + if(DCMTK_DCMDRLE_EXECUTABLE) + # No pixel data + set_tests_properties("DCMDRLE-ELSCINT1_PMSCT_RLE1.dcm" PROPERTIES WILL_FAIL TRUE) + # It is missing the very last pixel, so technically is illegal + set_tests_properties("DCMDRLE-ALOKA_SSD-8-MONO2-RLE-SQ.dcm" PROPERTIES WILL_FAIL TRUE) + endif() + endif() +endif() diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestAnonymizeEvent.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestAnonymizeEvent.cxx new file mode 100644 index 0000000..fdd5389 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestAnonymizeEvent.cxx @@ -0,0 +1,20 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmAnonymizeEvent.h" + +int TestAnonymizeEvent(int, char *[]) +{ + gdcm::AnonymizeEvent ae; + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestAnonymizer.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestAnonymizer.cxx new file mode 100644 index 0000000..ffa4ae3 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestAnonymizer.cxx @@ -0,0 +1,120 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmAnonymizer.h" +#include "gdcmReader.h" +#include "gdcmWriter.h" +#include "gdcmTesting.h" +#include "gdcmSystem.h" +#include "gdcmUIDGenerator.h" + +namespace gdcm +{ +int TestAnonymize(const char *subdir, const char* filename) +{ + Reader reader; + reader.SetFileName( filename ); + if ( !reader.Read() ) + { + return 1; + } + + Anonymizer anonymizer; + anonymizer.SetFile( reader.GetFile() ); + // Setup some actions: + const char patname[] = "test^anonymize"; + const Tag pattag = Tag(0x0010,0x0010); + anonymizer.Replace( pattag , patname ); + anonymizer.Remove( Tag(0x0008,0x2112) ); + anonymizer.Empty( Tag(0x0008,0x0070) ); + UIDGenerator uid; + // Those two are very special, since (0008,0016) needs to be propagated to (0002,0002) and + // (0008,0018) needs to be propagated to (0002,0003) + std::string newuid = uid.Generate(); + anonymizer.Replace( Tag(0x0008,0x0018), newuid.c_str() ); + anonymizer.Replace( Tag(0x0008,0x0016), "1.2.840.10008.5.1.4.1.1.1" ); // Make it a CT + if( !anonymizer.RemovePrivateTags() ) + { + return 1; + } + + // Create directory first: + std::string tmpdir = Testing::GetTempDirectory( subdir ); + if( !System::FileIsDirectory( tmpdir.c_str() ) ) + { + System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + std::string outfilename = Testing::GetTempFilename( filename, subdir ); + + Writer writer; + writer.SetFileName( outfilename.c_str() ); + writer.SetFile( reader.GetFile() ); + writer.SetCheckFileMetaInformation( false ); + if( !writer.Write() ) + { + std::cerr << "Failed to write: " << outfilename << std::endl; + return 1; + } + std::cout << "Success to write: " << outfilename << std::endl; + + // now let's try to read it back in: + Reader reader2; + reader2.SetFileName( outfilename.c_str() ); + if ( !reader2.Read() ) + { + std::cerr << "Could not reread written file: " << outfilename << std::endl; + return 1; + } + + const DataSet & ds = reader.GetFile().GetDataSet(); + //std::cout << ds << std::endl; + + const ByteValue *bv = ds.GetDataElement( pattag ).GetByteValue(); + if( !bv ) + { + return 1; + } + if (strncmp( bv->GetPointer(), patname, strlen(patname) ) != 0 ) + { + return 1; + } + if( bv->GetLength() != strlen(patname) ) + { + return 1; + } + + return 0; +} +} + +int TestAnonymizer(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return gdcm::TestAnonymize(argv[0], filename); + } + + // else + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += gdcm::TestAnonymize( argv[0], filename ); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestAnonymizer2.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestAnonymizer2.cxx new file mode 100644 index 0000000..f6627f3 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestAnonymizer2.cxx @@ -0,0 +1,213 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmAnonymizer.h" +#include "gdcmSimpleSubjectWatcher.h" +#include "gdcmFilename.h" +#include "gdcmTesting.h" +#include "gdcmCryptographicMessageSyntax.h" + +#include "gdcmCryptoFactory.h" + +#include "gdcmSmartPointer.h" +#include "gdcmReader.h" +#include "gdcmWriter.h" +#include "gdcmGlobal.h" +#include "gdcmSystem.h" + +#include // std::auto_ptr + +namespace gdcm +{ +int TestAnonymize2(const char *subdir, const char *filename) +{ + gdcm::Global& g = gdcm::Global::GetInstance(); + if( !g.LoadResourcesFiles() ) + { + return 1; + } + + std::string certpath = gdcm::Filename::Join(gdcm::Testing::GetSourceDirectory(), "/Testing/Source/Data/certificate.pem" ); + std::string keypath = gdcm::Filename::Join(gdcm::Testing::GetSourceDirectory(), "/Testing/Source/Data/privatekey.pem" ); + + // Create directory first: + std::string tmpdir = Testing::GetTempDirectory( subdir ); + if( !System::FileIsDirectory( tmpdir.c_str() ) ) + { + System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + std::string outfilename = Testing::GetTempFilename( filename, subdir ); + + // Create directory first: + const char subdir2[] = "TestAnonymizer2_2"; + std::string tmpdir2 = Testing::GetTempDirectory( subdir2 ); + if( !System::FileIsDirectory( tmpdir2.c_str() ) ) + { + System::MakeDirectory( tmpdir2.c_str() ); + //return 1; + } + std::string outfilename2 = Testing::GetTempFilename( filename, subdir2 ); + +// Encrypt +{ + gdcm::CryptoFactory* cryptoFactory = gdcm::CryptoFactory::GetFactoryInstance(); + if (cryptoFactory == NULL) + { + std::cerr << "Crypto library not available" << std::endl; + return 1; + } + std::auto_ptr cms_ptr(cryptoFactory->CreateCMSProvider()); + gdcm::CryptographicMessageSyntax& cms = *cms_ptr; + + if( !cms.ParseCertificateFile( certpath.c_str() ) ) + { + std::cerr << "Could not parse cert: " << certpath << std::endl; + return 1; + } + + gdcm::SmartPointer ano = new gdcm::Anonymizer; + ano->SetCryptographicMessageSyntax( &cms ); + + //gdcm::SimpleSubjectWatcher watcher(ano, "Anonymizer"); + + gdcm::Reader reader; + reader.SetFileName( filename ); + if( !reader.Read() ) + { + std::cerr << "Could not read: " << filename << std::endl; + return 1; + } + + const DataSet &ds = reader.GetFile().GetDataSet(); + bool hasinstanceuid = true; + if( !ds.FindDataElement( Tag(0x0008,0x0018) ) + || ds.GetDataElement( Tag(0x0008,0x0018) ).IsEmpty() ) + { + hasinstanceuid = false; + } + + gdcm::MediaStorage ms; + ms.SetFromFile( reader.GetFile() ); + + ano->SetFile( reader.GetFile() ); + if( !ano->BasicApplicationLevelConfidentialityProfile() ) + { + if( ms != gdcm::MediaStorage::MS_END ) + { + std::cerr << "BasicApplicationLevelConfidentialityProfile fails for: " << filename << std::endl; + return 1; + } + } + + gdcm::Writer writer; + //writer.SetFileName( "/tmp/ano.dcm" ); + writer.SetFileName( outfilename.c_str() ); + writer.SetFile( reader.GetFile() ); + if( !writer.Write() ) + { + if( hasinstanceuid ) + { + std::cerr << "Failed to write: " << outfilename << std::endl; + return 1; + } + return 0; + } +} +// Decrypt +{ + gdcm::CryptoFactory* cryptoFactory = gdcm::CryptoFactory::GetFactoryInstance(); + if (cryptoFactory == NULL) + { + std::cerr << "Crypto library not available" << std::endl; + return 1; + } + std::auto_ptr cms_ptr(cryptoFactory->CreateCMSProvider()); + gdcm::CryptographicMessageSyntax& cms = *cms_ptr; + if( !cms.ParseKeyFile( keypath.c_str() ) ) + { + std::cerr << "Could not parse key: " << keypath << std::endl; + return 1; + } + + gdcm::SmartPointer ano = new gdcm::Anonymizer; + ano->SetCryptographicMessageSyntax( &cms ); + + //gdcm::SimpleSubjectWatcher watcher(ano, "Anonymizer"); + + gdcm::Reader reader; + reader.SetFileName( outfilename.c_str() ); + if( !reader.Read() ) + { + std::cerr << "Could not read: " << outfilename << std::endl; + return 1; + } + + ano->SetFile( reader.GetFile() ); + if( !ano->BasicApplicationLevelConfidentialityProfile(false) ) + { + std::cerr << "BasicApplicationLevelConfidentialityProfile (false) fails for: " << outfilename << std::endl; + return 1; + } + + const DataSet &ds = reader.GetFile().GetDataSet(); + bool hasinstanceuid = true; + if( !ds.FindDataElement( Tag(0x0008,0x0018) ) + || ds.GetDataElement( Tag(0x0008,0x0018) ).IsEmpty() ) + { + hasinstanceuid = false; + } + + // TODO Need to compare filename to decrypted one. + gdcm::Writer writer; + writer.SetFileName( outfilename2.c_str() ); + writer.SetFile( reader.GetFile() ); + if( !writer.Write() ) + { + if( hasinstanceuid ) + { + std::cerr << "Failed to write (2): " << outfilename2 << std::endl; + std::cerr << "Orig file was : " << outfilename << std::endl; + return 1; + } + return 0; + } +} + + return 0; +} +} + +int TestAnonymizer2(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return gdcm::TestAnonymize2(argv[0], filename); + } + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + gdcm::Trace::ErrorOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += gdcm::TestAnonymize2( argv[0], filename ); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestAnonymizer3.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestAnonymizer3.cxx new file mode 100644 index 0000000..0b23286 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestAnonymizer3.cxx @@ -0,0 +1,264 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmAnonymizer.h" +#include "gdcmSimpleSubjectWatcher.h" +#include "gdcmUIDGenerator.h" +#include "gdcmFilename.h" +#include "gdcmTesting.h" +#include "gdcmCryptographicMessageSyntax.h" +#include "gdcmSmartPointer.h" +#include "gdcmReader.h" +#include "gdcmWriter.h" +#include "gdcmGlobal.h" +#include "gdcmFileDerivation.h" +#include "gdcmSystem.h" + +#include "gdcmCryptoFactory.h" +#include // std::auto_ptr + +int TestAnonymizer3(int , char *[]) +{ + using namespace gdcm; + gdcm::Global& g = gdcm::Global::GetInstance(); + if( !g.LoadResourcesFiles() ) + { + return 1; + } + const char *directory = gdcm::Testing::GetDataRoot(); + std::string sfilename = std::string(directory) + "/012345.002.050.dcm"; + const char *filename = sfilename.c_str(); + + std::string certpath = gdcm::Filename::Join(gdcm::Testing::GetSourceDirectory(), "/Testing/Source/Data/certificate.pem" ); + std::string keypath = gdcm::Filename::Join(gdcm::Testing::GetSourceDirectory(), "/Testing/Source/Data/privatekey.pem" ); + + // Create directory first: + const char subdir[] = "TestAnonymizer3"; + std::string tmpdir = Testing::GetTempDirectory( subdir ); + if( !System::FileIsDirectory( tmpdir.c_str() ) ) + { + System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + std::string outfilename = Testing::GetTempFilename( filename, subdir ); + std::string outfilenamelossy = Testing::GetTempFilename( "012345.002.050.lossy.dcm" , subdir ); + std::string outfilenamelossy2 = Testing::GetTempFilename( "012345.002.050.lossy.anon.dcm" , subdir ); + +// Derive +{ + gdcm::Reader reader; + reader.SetFileName( filename ); + if( !reader.Read() ) + { + std::cerr << "Could not read: " << filename << std::endl; + return 1; + } + + File& file = reader.GetFile(); + DataSet &ds = file.GetDataSet(); + + DataElement instanceuid = ds.GetDataElement( Tag(0x8,0x18) ); + UIDGenerator uid; + const char *s = uid.Generate(); + instanceuid.SetByteValue( s, (uint32_t)strlen(s) ); + ds.Replace( instanceuid ); + + FileDerivation fd; + fd.SetFile( file ); + // FIXME hardcoded: + fd.AddReference( "1.2.840.10008.5.1.4.1.1.4", + "1.2.840.113619.2.5.1762386977.1328.985934491.693" ); + + // CID 7202 Source Image Purposes of Reference + // {"DCM",121320,"Uncompressed predecessor"}, + fd.SetPurposeOfReferenceCodeSequenceCodeValue( 121320 ); + + // CID 7203 Image Derivation + // { "DCM",113040,"Lossy Compression" }, + fd.SetDerivationCodeSequenceCodeValue( 113040 ); + fd.SetDerivationDescription( "lossy conversion" ); + if( !fd.Derive() ) + { + std::cerr << "Sorry could not derive using input info" << std::endl; + return 1; + } + + gdcm::Writer writer; + writer.SetFileName( outfilenamelossy.c_str() ); + writer.SetFile( fd.GetFile() ); + if( !writer.Write() ) + { + std::cerr << "Failed to write: " << outfilenamelossy << std::endl; + return 1; + } +} + +// Encrypt +{ + gdcm::CryptoFactory* cryptoFactory = gdcm::CryptoFactory::GetFactoryInstance(); + if (cryptoFactory == NULL) + { + std::cerr << "Crypto library not available" << std::endl; + return 1; + } + std::auto_ptr cms_ptr(cryptoFactory->CreateCMSProvider()); + gdcm::CryptographicMessageSyntax& cms = *cms_ptr; + if( !cms.ParseCertificateFile( certpath.c_str() ) ) + { + return 1; + } + + gdcm::SmartPointer ano = new gdcm::Anonymizer; + ano->SetCryptographicMessageSyntax( &cms ); + +{ + // original file + gdcm::Reader reader; + reader.SetFileName( filename ); + if( !reader.Read() ) + { + std::cerr << "Could not read: " << filename << std::endl; + return 1; + } + + // order of operation is important + ano->SetFile( reader.GetFile() ); + if( !ano->BasicApplicationLevelConfidentialityProfile() ) + { + return 1; + } + + gdcm::Writer writer; + writer.SetFileName( outfilename.c_str() ); + writer.SetFile( reader.GetFile() ); + if( !writer.Write() ) + { + std::cerr << "Failed to write: " << outfilename << std::endl; + return 1; + } +} + +{ + // derived file + gdcm::Reader reader; + reader.SetFileName( outfilenamelossy.c_str() ); + if( !reader.Read() ) + { + std::cerr << "Could not read: " << outfilenamelossy << std::endl; + return 1; + } + + // order of operation is important + ano->SetFile( reader.GetFile() ); + if( !ano->BasicApplicationLevelConfidentialityProfile() ) + { + return 1; + } + + gdcm::Writer writer; + writer.SetFileName( outfilenamelossy2.c_str() ); + writer.SetFile( reader.GetFile() ); + if( !writer.Write() ) + { + std::cerr << "Failed to write: " << outfilenamelossy2 << std::endl; + return 1; + } +} +} + +// Make sure UID is consistant: +{ + std::string sopinstanceuid_str1; +{ + // original anonymized file + gdcm::Reader reader; + reader.SetFileName( outfilename.c_str() ); + if( !reader.Read() ) + { + std::cerr << "Could not read: " << filename << std::endl; + return 1; + } + File &file = reader.GetFile(); + DataSet &ds = file.GetDataSet(); + + if( !ds.FindDataElement( Tag(0x0008,0x0018) ) + || ds.GetDataElement( Tag(0x0008,0x0018) ).IsEmpty() ) + { + return 1; + } + const DataElement &sopinstanceuid = ds.GetDataElement( Tag(0x0008,0x0018) ); + sopinstanceuid_str1 = std::string( sopinstanceuid.GetByteValue()->GetPointer(), sopinstanceuid.GetByteValue()->GetLength() ); +} + + std::string sopinstanceuid_str2; + std::string refsopinstanceuid_str2; +{ + // derived anonymized file + gdcm::Reader reader; + reader.SetFileName( outfilenamelossy2.c_str() ); + if( !reader.Read() ) + { + std::cerr << "Could not read: " << outfilenamelossy << std::endl; + return 1; + } + File &file = reader.GetFile(); + DataSet &ds = file.GetDataSet(); + + if( !ds.FindDataElement( Tag(0x0008,0x0018) ) + || ds.GetDataElement( Tag(0x0008,0x0018) ).IsEmpty() ) + { + return 1; + } + const DataElement &sopinstanceuid = ds.GetDataElement( Tag(0x0008,0x0018) ); + sopinstanceuid_str2 = std::string( sopinstanceuid.GetByteValue()->GetPointer(), sopinstanceuid.GetByteValue()->GetLength() ); + + // Source Image Sequence + if( !ds.FindDataElement( Tag(0x0008,0x2112) ) + || ds.GetDataElement( Tag(0x0008,0x2112) ).IsEmpty() ) + { + return 1; + } + + const DataElement &sourceimagesq = ds.GetDataElement( Tag(0x0008,0x2112) ); + SmartPointer sq = sourceimagesq.GetValueAsSQ(); + gdcm::SequenceOfItems::SizeType n = sq->GetNumberOfItems(); + if( n != 1 ) return 1; + Item &item = sq->GetItem( 1 ); + DataSet &nested = item.GetNestedDataSet(); + + if( !nested.FindDataElement( Tag(0x0008,0x1155) ) + || nested.GetDataElement( Tag(0x0008,0x1155) ).IsEmpty() ) + { + return 1; + } + const DataElement &refsopinstanceuid = nested.GetDataElement( + Tag(0x0008,0x1155) ); + refsopinstanceuid_str2 = std::string( refsopinstanceuid.GetByteValue()->GetPointer(), refsopinstanceuid.GetByteValue()->GetLength() ); + +} + std::cout << sopinstanceuid_str1 << std::endl; + std::cout << sopinstanceuid_str2 << std::endl; + std::cout << refsopinstanceuid_str2 << std::endl; + +if( sopinstanceuid_str1 == sopinstanceuid_str2 ) +{ + return 1; +} +if( sopinstanceuid_str1 != refsopinstanceuid_str2 ) +{ + return 1; +} +} + + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestApplicationEntity.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestApplicationEntity.cxx new file mode 100644 index 0000000..c314392 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestApplicationEntity.cxx @@ -0,0 +1,20 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmApplicationEntity.h" + +int TestApplicationEntity(int, char *[]) +{ + gdcm::ApplicationEntity ae; + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestAudioCodec.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestAudioCodec.cxx new file mode 100644 index 0000000..cd624cc --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestAudioCodec.cxx @@ -0,0 +1,22 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmAudioCodec.h" + +int TestAudioCodec(int , char *[]) +{ + gdcm::AudioCodec c; + (void)c; + + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestCodec.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestCodec.cxx new file mode 100644 index 0000000..e33e8dd --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestCodec.cxx @@ -0,0 +1,32 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmCodec.h" + +namespace gdcm +{ +class DummyCodec : public Codec +{ +public: + bool CanDecode(TransferSyntax const &) const { return false; } + bool CanCode(TransferSyntax const &) const { return false; } +}; +} + +int TestCodec(int , char *[]) +{ + gdcm::DummyCodec c; + (void)c; + + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestCoder.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestCoder.cxx new file mode 100644 index 0000000..9b3899a --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestCoder.cxx @@ -0,0 +1,29 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmCoder.h" + +namespace gdcm +{ +class DummyCoder : public Coder +{ +public: + bool CanCode(TransferSyntax const &) const { return false; } +}; +} + +int TestCoder(int, char *[]) +{ + gdcm::DummyCoder c; + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestCopyDataSet.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestCopyDataSet.cxx new file mode 100644 index 0000000..7c5280f --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestCopyDataSet.cxx @@ -0,0 +1,57 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmReader.h" +#include "gdcmDataSet.h" +#include "gdcmWriter.h" +#include "gdcmTesting.h" + +int TestCopyDataSet(int, char *[]) +{ + std::string dataroot = gdcm::Testing::GetDataRoot(); + std::string filename = dataroot + "/test.acr"; + gdcm::Reader reader; + reader.SetFileName( filename.c_str() ); + if ( !reader.Read() ) + { + return 1; + } + + const gdcm::DataSet &ds = reader.GetFile().GetDataSet(); + + gdcm::DataSet ds_copy = ds; + + gdcm::DataElement n( gdcm::Tag(0x0028,0x0005) ); + n.SetByteValue( "3", 1 ); + std::cout << n << std::endl; + + ds_copy.Replace( n ); + + std::cout << ds_copy << std::endl; + // roup="0018" element="1020" vr="LO" vm="1-n" na + gdcm::DataElement n2( gdcm::Tag(0x0018,0x1020) ); + //const char versions[] = "1234567890\\1234567890\\1234567890\\1234567890\\1234567890\\1234567890"; + const char versions[] = "12345678901234567890123456789012345678901234567890123\\45678901234567890"; + n2.SetByteValue( versions, (uint32_t)strlen(versions) ); + ds_copy.Replace( n2 ); + + std::string outfilename = gdcm::Testing::GetTempFilename( "TestCopyDataSet.dcm" ); + gdcm::Writer writer; + writer.SetFile( reader.GetFile() ); + writer.GetFile().GetDataSet().Replace( n2 ); + writer.SetFileName( outfilename.c_str() ); + writer.SetCheckFileMetaInformation( false ); + writer.Write(); + + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestCurve.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestCurve.cxx new file mode 100644 index 0000000..fe35a7f --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestCurve.cxx @@ -0,0 +1,28 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmCurve.h" + +int TestCurve(int, char *[]) +{ + gdcm::Curve c; + c.SetTypeOfData( "TAC" ); + //c.SetTypeOfData( "PROF" ); + //c.SetTypeOfData( "PRESSURE" ); + //c.SetTypeOfData( "RESP" ); + //c.SetTypeOfData( "dummy" ); + std::cout << c.GetTypeOfData() << std::endl; + std::cout << c.GetTypeOfDataDescription() << std::endl; + + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestCurve2.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestCurve2.cxx new file mode 100644 index 0000000..7d72976 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestCurve2.cxx @@ -0,0 +1,188 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmCurve.h" +#include "gdcmFileMetaInformation.h" +#include "gdcmSystem.h" +#include "gdcmImageReader.h" +#include "gdcmFilename.h" +#include "gdcmByteSwap.h" +#include "gdcmTrace.h" +#include "gdcmTesting.h" + +struct curveinfo +{ + unsigned short dimensions; + unsigned short numpts; + const char *typeofdata; + unsigned short datavaluerepresentation; + const char *datamd5; +}; + +static const curveinfo numptsarray1[] = { { 1, 1126, "PHYSIO", 0, "0fee912671ae158390efc7b49fe39f9b" } }; +static const curveinfo numptsarray2[] = { { 1, 969, "PHYSIO", 0, "b46d2c6eed2944f1e16c46125022d2d4" } }; +static const curveinfo numptsarray3[] = { { 2, 1864, "ECG ", 0, "22aadb1260fcb53a487a2e9e9ee445b3" } }; +static const curveinfo numptsarray4[] = { { 2, 1590, "PRESSURE", 0, "6b4125d8a00c65feddb8c7c6f157e6ce" } , { 2, 1588, "ECG ", 0, "7a8e1cf198e74dd37738dbce5262c49d" } }; + +struct curveel +{ + const char *name; + size_t numcurves; + const curveinfo *info; +}; + +static const curveel arraycurve[] = { +// gdcmData +{ "GE_DLX-8-MONO2-Multiframe-Jpeg_Lossless.dcm", 1, numptsarray1 }, +{ "GE_DLX-8-MONO2-Multiframe.dcm", 1, numptsarray2 }, +// gdcmDataExtra +{ "xa_integris.dcm", 1, numptsarray3 }, +// random stuff: +{ "XA.1.2.826.0.1.3680043.3.29.1.3230389164.20272.1340974735.2.3.0.000001.dcm", 2, numptsarray4 }, +}; + +static const curveel *getcurveelfromname(const char *filename) +{ + static const size_t nel = sizeof( arraycurve ) / sizeof( *arraycurve ); + for( size_t i = 0; i < nel; ++i ) + { + const curveel &c = arraycurve[i]; + if( strcmp( filename, c.name) == 0 ) + { + return &c; + } + } + return NULL; +} + +static int TestCurve2Read(const char* filename, bool verbose = false) +{ + if( verbose ) + std::cerr << "Reading: " << filename << std::endl; + gdcm::ImageReader reader; + reader.SetFileName( filename ); + if ( !reader.Read() ) + { + } + int res = 0; + const gdcm::Image &img = reader.GetImage(); + size_t numcurves = img.GetNumberOfCurves(); + gdcm::Filename fn( filename ); + if( numcurves ) + { + const curveel *c = getcurveelfromname( fn.GetName() ); + if( c == NULL ) + { + std::cerr << "Cant find: " << filename << std::endl; + return 1; + } + if( c->numcurves != numcurves ) + { + std::cerr << "Should be: " << numcurves << " while " << c->numcurves << std::endl; + return 1; + } + const curveinfo *info = c->info; + for( size_t idx = 0; idx < numcurves; ++idx ) + { + const gdcm::Curve &curve = img.GetCurve(idx); + //curve.Print( std::cout ); + unsigned short dim = curve.GetDimensions(); + if( info[idx].dimensions != dim ) + { + std::cerr << "Should be: " << dim << " while " << info[idx].dimensions << " for idx: " << idx << std::endl; + return 1; + } + unsigned short npts = curve.GetNumberOfPoints(); + if( info[idx].numpts != npts ) + { + std::cerr << "Should be: " << npts << " while " << info[idx].numpts << " for idx: " << idx << std::endl; + return 1; + } + const char *tofdata = curve.GetTypeOfData(); + if( strcmp(info[idx].typeofdata, tofdata ) != 0 ) + { + std::cerr << "Should be: [" << tofdata << "] while [" << info[idx].typeofdata << "] for idx: " << idx << std::endl; + return 1; + } + unsigned short dvr = curve.GetDataValueRepresentation(); + if( info[idx].datavaluerepresentation != dvr ) + { + std::cerr << "Should be: " << dvr << " while " << info[idx].datavaluerepresentation << " for idx: " << idx << std::endl; + return 1; + } + std::vector points; + points.resize( 3 * npts ); + curve.GetAsPoints( (float*)&points[0] ); +#if 0 + for( size_t i = 0; i < npts; i += 3 ) + { + std::cout << points[i + 0] << "," + << points[i + 1] << "," + << points[i + 2] << "\n"; + } +#endif + char digest[33]; + const char *buffer = (char*)&points[0]; + size_t len = sizeof(float) * 3 * npts; + const char *ref = info[idx].datamd5; + gdcm::Testing::ComputeMD5(buffer, len, digest); + if( verbose ) + { + std::cout << "ref=" << ref << std::endl; + std::cout << "md5=" << digest << std::endl; + } + if( !ref ) + { + // new regression image needs a md5 sum + std::cout << "Missing md5 " << digest << " for: " << filename << std::endl; + //assert(0); + res = 1; + } + else if( strcmp(digest, ref) ) + { + std::cerr << "Problem reading image from: " << filename << std::endl; + std::cerr << "Found " << digest << " instead of " << ref << std::endl; + res = 1; + } + + + } + } + + return res; +} + +int TestCurve2(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestCurve2Read(filename, true); + } + + // else + // First of get rid of warning/debug message + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + gdcm::Trace::ErrorOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestCurve2Read(filename); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestDICOMDIR.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestDICOMDIR.cxx new file mode 100644 index 0000000..8e4937f --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestDICOMDIR.cxx @@ -0,0 +1,32 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmDICOMDIR.h" +#include "gdcmFileSet.h" + +int TestDICOMDIR(int argc, char *argv[]) +{ + (void)argc; + (void)argv; + gdcm::DICOMDIR dd; + + gdcm::FileSet fs; + gdcm::File f1; + gdcm::File f2; + fs.AddFile( f1 ); + fs.AddFile( f2 ); + + gdcm::DICOMDIR dd2(fs); + + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestDICOMDIRGenerator1.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestDICOMDIRGenerator1.cxx new file mode 100644 index 0000000..9938592 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestDICOMDIRGenerator1.cxx @@ -0,0 +1,90 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmDICOMDIRGenerator.h" +#include "gdcmDirectory.h" +#include "gdcmWriter.h" +#include "gdcmTesting.h" +#include "gdcmSystem.h" +#include "gdcmFilenameGenerator.h" + +int TestDICOMDIRGenerator1(int argc, char *argv[]) +{ + (void)argc; + (void)argv; + + gdcm::Directory::FilenamesType filenames; + gdcm::Directory::FilenamesType outfilenames; + + const char outsubdir[] = "TestDICOMDIRGenerator1"; + std::string outtmpdir = gdcm::Testing::GetTempDirectory( outsubdir ); + if( !gdcm::System::FileIsDirectory( outtmpdir.c_str() ) ) + { + gdcm::System::MakeDirectory( outtmpdir.c_str() ); + } + + const char subdir[] = "TestImageChangeTransferSyntax4"; + std::string directory = gdcm::Testing::GetTempDirectory( subdir ); + + std::string file0 = std::string(directory) + "/SIEMENS_MAGNETOM-12-MONO2-FileSeq0.dcm"; + std::string file1 = std::string(directory) + "/SIEMENS_MAGNETOM-12-MONO2-FileSeq1.dcm"; + std::string file2 = std::string(directory) + "/SIEMENS_MAGNETOM-12-MONO2-FileSeq2.dcm"; + std::string file3 = std::string(directory) + "/SIEMENS_MAGNETOM-12-MONO2-FileSeq3.dcm"; + filenames.push_back( file1 ); + filenames.push_back( file3 ); + filenames.push_back( file2 ); + filenames.push_back( file0 ); + size_t nfiles = filenames.size(); + + gdcm::FilenameGenerator fg; + const char pattern[] = "FILE%03d"; + fg.SetPattern( pattern ); + fg.SetNumberOfFilenames( nfiles ); + if( !fg.Generate() ) + { + std::cerr << "Could not generate" << std::endl; + return 1; + } + for( unsigned int i = 0; i < nfiles; ++i ) + { + std::string copy = outtmpdir; + copy += "/"; + copy += fg.GetFilename( i ); + std::cerr << filenames[i] << " -> " << copy << std::endl; + std::ifstream f1(filenames[i].c_str(), std::fstream::binary); + std::ofstream f2(copy.c_str(), std::fstream::binary); + f2 << f1.rdbuf(); + outfilenames.push_back( copy ); + } + + gdcm::DICOMDIRGenerator gen; + gen.SetFilenames( outfilenames ); + gen.SetRootDirectory( outtmpdir ); + gen.SetDescriptor( "MYDESCRIPTOR" ); + if( !gen.Generate() ) + { + return 1; + } + + gdcm::Writer writer; + writer.SetFile( gen.GetFile() ); + std::string outfilename = outtmpdir; + outfilename += "/DICOMDIR"; + writer.SetFileName( outfilename.c_str() ); + if( !writer.Write() ) + { + return 1; + } + + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestDICOMDIRGenerator2.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestDICOMDIRGenerator2.cxx new file mode 100644 index 0000000..6237eab --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestDICOMDIRGenerator2.cxx @@ -0,0 +1,93 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmDICOMDIRGenerator.h" +#include "gdcmDirectory.h" +#include "gdcmWriter.h" +#include "gdcmTesting.h" +#include "gdcmSystem.h" +#include "gdcmFilenameGenerator.h" + +int TestDICOMDIRGenerator2(int argc, char *argv[]) +{ + (void)argc; + const char *directory = gdcm::Testing::GetDataRoot(); + (void)argv; + + gdcm::Directory::FilenamesType filenames; + gdcm::Directory::FilenamesType outfilenames; + gdcm::Directory dir; + int recursive = 0; + unsigned int nfiles = 1; + + const char subdir[] = "TestImageChangeTransferSyntax4"; + std::string tmpdir = gdcm::Testing::GetTempDirectory( subdir ); + if( !gdcm::System::FileIsDirectory( tmpdir.c_str() ) ) + { + std::cerr << "Need to run TestImageChangeTransferSyntax4 before" << std::endl; + return 1; + } + directory = tmpdir.c_str(); + + const char outsubdir[] = "TestDICOMDIRGenerator2"; + std::string outtmpdir = gdcm::Testing::GetTempDirectory( outsubdir ); + if( !gdcm::System::FileIsDirectory( outtmpdir.c_str() ) ) + { + gdcm::System::MakeDirectory( outtmpdir.c_str() ); + } + + nfiles = dir.Load(directory, (recursive > 0 ? true : false)); + + gdcm::FilenameGenerator fg; + const char pattern[] = "FILE%03d"; + fg.SetPattern( pattern ); + fg.SetNumberOfFilenames( nfiles ); + if( !fg.Generate() ) + { + std::cerr << "Could not generate" << std::endl; + return 1; + } + filenames = dir.GetFilenames(); + for( unsigned int i = 0; i < nfiles; ++i ) + { + std::string copy = outtmpdir; + copy += "/"; + copy += fg.GetFilename( i ); + std::cerr << filenames[i] << " -> " << copy << std::endl; + std::ifstream f1(filenames[i].c_str(), std::fstream::binary); + std::ofstream f2(copy.c_str(), std::fstream::binary); + f2 << f1.rdbuf(); + outfilenames.push_back( copy ); + } + + gdcm::DICOMDIRGenerator gen; + gen.SetFilenames( outfilenames ); + gen.SetRootDirectory( outtmpdir ); + gen.SetDescriptor( "MYDESCRIPTOR" ); + if( !gen.Generate() ) + { + return 1; + } + + gdcm::Writer writer; + writer.SetFile( gen.GetFile() ); + std::string outfilename = outtmpdir; + outfilename += "/DICOMDIR"; + writer.SetFileName( outfilename.c_str() ); + if( !writer.Write() ) + { + return 1; + } + + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestDataElementValueAsSQ.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestDataElementValueAsSQ.cxx new file mode 100644 index 0000000..bf1b3ae --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestDataElementValueAsSQ.cxx @@ -0,0 +1,63 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmTesting.h" +#include "gdcmReader.h" +#include "gdcmDataElement.h" +#include "gdcmSequenceOfItems.h" + +int TestDataElementValueAsSQ(int , char *[]) +{ + int ret = 0; + const char *filenames[] = { + "D_CLUNIE_CT1_J2KI.dcm", + "PET-cardio-Multiframe-Papyrus.dcm" + }; + const gdcm::Tag tags[] = { + gdcm::Tag(0x8,0x2112), + gdcm::Tag(0x41,0x1010) + }; + const unsigned int nfiles = sizeof(filenames)/sizeof(*filenames); + const char *root = gdcm::Testing::GetDataRoot(); + if( !root || !*root ) + { + std::cerr << "root is not defiend" << std::endl; + return 1; + } + std::string sroot = root; + //sroot += "/DISCIMG/IMAGES/"; + sroot += "/"; + for(unsigned int i = 0; i < nfiles; ++i) + { + std::string filename = sroot + filenames[i]; + //std::cout << filename << std::endl; + gdcm::Reader r; + r.SetFileName( filename.c_str() ); + if( !r.Read() ) + { + ret++; + std::cerr << "could not read: " << filename << std::endl; + } + const gdcm::Tag &tag = tags[i]; + gdcm::DataSet &ds = r.GetFile().GetDataSet(); + const gdcm::DataElement &roicsq = ds.GetDataElement( tag ); + gdcm::SmartPointer sqi = roicsq.GetValueAsSQ(); + if(!sqi) + { + ++ret; + std::cerr << "could not get SQ " << tag << " from: " << filename << std::endl; + } + } + + return ret; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestDecoder.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestDecoder.cxx new file mode 100644 index 0000000..5d23e10 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestDecoder.cxx @@ -0,0 +1,29 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmDecoder.h" + +namespace gdcm +{ +class DummyDecoder : public Decoder +{ +public: + bool CanDecode(TransferSyntax const &) const { return false; } +}; +} + +int TestDecoder(int, char *[]) +{ + gdcm::DummyDecoder d; + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestDictPrinter.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestDictPrinter.cxx new file mode 100644 index 0000000..3a7b0f9 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestDictPrinter.cxx @@ -0,0 +1,20 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmDictPrinter.h" + +int TestDictPrinter(int, char *[]) +{ + gdcm::DictPrinter dp; + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestDirectionCosines.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestDirectionCosines.cxx new file mode 100644 index 0000000..d532f87 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestDirectionCosines.cxx @@ -0,0 +1,130 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmDirectionCosines.h" +#include +#include + +/* + * Let's use the CrossDot API to compare IOP safely + */ +static const char * ImageOrientationPatientList[] = { +"0.999081\\0.0426953\\0.00369275\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426953\\0.00369272\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426953\\0.00369275\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426953\\0.00369272\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426953\\0.00369275\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426952\\0.00369272\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426953\\0.00369272\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426953\\0.00369274\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426953\\0.00369274\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426953\\0.00369272\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426953\\0.00369272\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426953\\0.00369273\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426953\\0.00369273\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426953\\0.00369273\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426952\\0.00369273\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426953\\0.00369273\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426953\\0.00369273\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426953\\0.00369273\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426953\\0.00369273\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426953\\0.00369273\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426953\\0.00369273\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426953\\0.00369273\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426952\\0.00369273\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426953\\0.00369273\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426953\\0.00369273\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426953\\0.00369274\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426953\\0.00369274\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426953\\0.00369274\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426953\\0.00369275\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426953\\0.00369272\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426953\\0.00369275\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426953\\0.00369272\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426953\\0.00369275\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426952\\0.00369272\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426953\\0.00369272\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426953\\0.00369274\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426953\\0.00369274\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426953\\0.00369272\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426953\\0.00369272\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426953\\0.00369273\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426953\\0.00369273\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426953\\0.00369273\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426952\\0.00369273\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426953\\0.00369273\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426953\\0.00369273\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426953\\0.00369273\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426953\\0.00369273\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426953\\0.00369273\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426953\\0.00369273\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426953\\0.00369273\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426952\\0.00369273\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426953\\0.00369273\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426953\\0.00369273\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426953\\0.00369274\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426953\\0.00369274\\-0.0419025\\0.955059\\0.293439", +"0.999081\\0.0426953\\0.00369274\\-0.0419025\\0.955059\\0.293439", +}; + +bool TestCrossDot() +{ + std::set< std::string > myset; + const unsigned int nipp = sizeof(ImageOrientationPatientList) / sizeof(*ImageOrientationPatientList); + for( unsigned int i = 0; i < nipp; ++i ) + { + myset.insert( ImageOrientationPatientList[i] ); + } + + if( myset.size() <= 1 ) return false; + + std::set< std::string >::const_iterator it = myset.begin(); + gdcm::DirectionCosines ref; + gdcm::DirectionCosines dc; + for( ; it != myset.end(); ++it ) + { + ref.SetFromString( it->c_str() ); + for( unsigned int i = 0; i < nipp; ++i ) + { + dc.SetFromString( ImageOrientationPatientList[i] ); + const double crossdot = ref.CrossDot( dc); + const double eps = 1. - crossdot; + if( eps > 1e-6 || eps < 0 ) return false; + } + } + return true; +} + +int TestDirectionCosines(int, char *[]) +{ + gdcm::DirectionCosines dc; + //const double *dircos = dc; + if( !dc.IsValid() ) + { + return 1; + } + const double cross[3] = {0,0,1}; + double z[3]; + dc.Cross(z); + if( z[0] != cross[0] + || z[1] != cross[1] + || z[2] != cross[2] ) + { + return 1; + } + + bool b = TestCrossDot(); + if( !b ) return 1; + + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestDumper.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestDumper.cxx new file mode 100644 index 0000000..b4fc783 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestDumper.cxx @@ -0,0 +1,85 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmReader.h" +#include "gdcmDumper.h" +#include "gdcmTesting.h" +#include "gdcmCSAHeader.h" + +int TestDump(const char *filename) +{ + gdcm::Reader r; + r.SetFileName( filename ); + if( !r.Read() ) + { + return 1; + } + + std::ostringstream out; +{ + gdcm::Dumper p; + p.SetFile( r.GetFile() ); + //p.Print( std::cout ); + p.Print( out ); +} + + // Test CSA Header here too + gdcm::CSAHeader csa; + const gdcm::DataSet& ds = r.GetFile().GetDataSet(); + const gdcm::PrivateTag &t1 = csa.GetCSAImageHeaderInfoTag(); + const gdcm::PrivateTag &t2 = csa.GetCSASeriesHeaderInfoTag(); + + if( ds.FindDataElement( t1 ) ) + { + csa.LoadFromDataElement( ds.GetDataElement( t1 ) ); + csa.Print( std::cout ); + } + if( ds.FindDataElement( t2 ) ) + { + csa.LoadFromDataElement( ds.GetDataElement( t2 ) ); + csa.Print( std::cout ); + } + if( csa.GetFormat() == gdcm::CSAHeader::DATASET_FORMAT ) + { + gdcm::Dumper p; + gdcm::File f; + f.SetDataSet( csa.GetDataSet() ); + p.SetFile( f ); + //p.Print( std::cout ); + p.Print( out ); + } + + return 0; +} + + +int TestDumper(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestDump(filename); + } + + // else + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestDump( filename ); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestEncapsulatedDocument.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestEncapsulatedDocument.cxx new file mode 100644 index 0000000..86b368d --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestEncapsulatedDocument.cxx @@ -0,0 +1,23 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmEncapsulatedDocument.h" + +int TestEncapsulatedDocument(int argc, char *argv[]) +{ + (void)argc; + (void)argv; + gdcm::EncapsulatedDocument w; + + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFiducials.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFiducials.cxx new file mode 100644 index 0000000..0df28e0 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFiducials.cxx @@ -0,0 +1,23 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmFiducials.h" + +int TestFiducials(int argc, char *argv[]) +{ + (void)argc; + (void)argv; + gdcm::Fiducials f; + + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFileAnonymizer1.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFileAnonymizer1.cxx new file mode 100644 index 0000000..07ef647 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFileAnonymizer1.cxx @@ -0,0 +1,128 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmFileAnonymizer.h" + +#include "gdcmTesting.h" +#include "gdcmSystem.h" +#include "gdcmReader.h" +#include "gdcmFilename.h" + +int TestFileAnonymize1(const char *filename, bool verbose = false) +{ + using namespace gdcm; + if( verbose ) + std::cout << "Processing: " << filename << std::endl; + + // Create directory first: + const char subdir[] = "TestFileAnonymize1"; + std::string tmpdir = Testing::GetTempDirectory( subdir ); + if( !System::FileIsDirectory( tmpdir.c_str() ) ) + { + System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + std::string outfilename = Testing::GetTempFilename( filename, subdir ); + + const gdcm::Tag t1(0x0018,0x5100); + const gdcm::Tag t2(0x0018,0x1312); + const gdcm::Tag t3(0x0018,0x1313); + const gdcm::Tag t4(0x0018,0x1317); + const gdcm::Tag t5(0x0008,0x2112); + const gdcm::Tag t6(0x0008,0x9215); + const gdcm::Tag t7(0x0018,0x1020); + const gdcm::Tag t8(0x0004,0x1130); // Test DICOMDIR ! + const gdcm::Tag t9(0x0008,0x0000); // Earliest possible Data Element + const gdcm::Tag t0(0xffff,0xffff); // Latest Possible Element + + std::vector tags; + tags.push_back( t0 ); + tags.push_back( t1 ); + tags.push_back( t2 ); + tags.push_back( t3 ); + tags.push_back( t4 ); + tags.push_back( t5 ); + tags.push_back( t6 ); + tags.push_back( t7 ); + tags.push_back( t8 ); + tags.push_back( t9 ); + + gdcm::FileAnonymizer fa; + fa.SetInputFileName( filename ); + fa.SetOutputFileName( outfilename.c_str() ); + for( std::vector::const_iterator it = tags.begin(); + it != tags.end(); ++it ) + { + fa.Remove( *it ); + } + if( !fa.Write() ) + { + std::cerr << "Failed to write: " << outfilename << std::endl; + return 1; + } + + // Read back and check: + gdcm::Reader r; + r.SetFileName( outfilename.c_str() ); + if( !r.Read() ) + { + std::cerr << "Failed to read: " << outfilename << std::endl; + return 1; + } + const File &f = r.GetFile(); + const DataSet &ds = f.GetDataSet(); + for( std::vector::const_iterator it = tags.begin(); + it != tags.end(); ++it ) + { + const gdcm::Tag & t = *it; + if( ds.FindDataElement( t ) ) + { + gdcm::Filename fn( filename ); + std::cerr << "Found element: " << t << " in " << outfilename << std::endl; + gdcm::MediaStorage ms; + ms.SetFromFile( f ); + const bool isdicomdir = (ms == gdcm::MediaStorage::MediaStorageDirectoryStorage); // de-activate for now + if( strcmp(fn.GetName(), "ExplicitVRforPublicElementsImplicitVRforShadowElements.dcm") == 0 || isdicomdir ) + { + return 0; + } + return 1; + } + } + + return 0; +} + +int TestFileAnonymizer1(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestFileAnonymize1(filename, true); + } + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + gdcm::Trace::ErrorOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestFileAnonymize1( filename ); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFileAnonymizer2.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFileAnonymizer2.cxx new file mode 100644 index 0000000..42ce8ec --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFileAnonymizer2.cxx @@ -0,0 +1,144 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmFileAnonymizer.h" + +#include "gdcmTesting.h" +#include "gdcmSystem.h" +#include "gdcmReader.h" +#include "gdcmFilename.h" + +static int TestFileAnonymize2(const char *filename, bool verbose = false) +{ + using namespace gdcm; + if( verbose ) + std::cout << "Processing: " << filename << std::endl; + + // Create directory first: + const char subdir[] = "TestFileAnonymize2"; + std::string tmpdir = Testing::GetTempDirectory( subdir ); + if( !System::FileIsDirectory( tmpdir.c_str() ) ) + { + System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + std::string outfilename = Testing::GetTempFilename( filename, subdir ); + + const gdcm::Tag t1(0x0018,0x5100); + const gdcm::Tag t2(0x0018,0x1312); + const gdcm::Tag t3(0x0018,0x1313); + const gdcm::Tag t4(0x0018,0x1317); + const gdcm::Tag t5(0x0008,0x2112); + const gdcm::Tag t6(0x0008,0x9215); + const gdcm::Tag t7(0x0018,0x1020); + const gdcm::Tag t8(0x0004,0x1130); // Test DICOMDIR ! + const gdcm::Tag t9(0x0008,0x0000); // Earliest possible Data Element + const gdcm::Tag t0(0xffff,0xffff); // Latest Possible Element + + std::vector tags; + tags.push_back( t0 ); + tags.push_back( t1 ); + tags.push_back( t2 ); + tags.push_back( t3 ); + tags.push_back( t4 ); + tags.push_back( t5 ); + tags.push_back( t6 ); + tags.push_back( t7 ); + tags.push_back( t8 ); + tags.push_back( t9 ); + + gdcm::FileAnonymizer fa; + fa.SetInputFileName( filename ); + fa.SetOutputFileName( outfilename.c_str() ); + for( std::vector::const_iterator it = tags.begin(); + it != tags.end(); ++it ) + { + fa.Empty( *it ); + } + if( !fa.Write() ) + { + std::cerr << "Failed to write: " << outfilename << std::endl; + return 1; + } + + // Read back and check: + gdcm::Reader r; + r.SetFileName( outfilename.c_str() ); + if( !r.Read() ) + { + gdcm::Filename fn( filename ); + std::cerr << "Failed to read: " << outfilename << std::endl; + if( strcmp(fn.GetName(), "SIEMENS_MAGNETOM-12-MONO2-GDCM12-VRUN.dcm") == 0 + || strcmp(fn.GetName(), "DMCPACS_ExplicitImplicit_BogusIOP.dcm") == 0 + || strcmp(fn.GetName(), "ExplicitVRforPublicElementsImplicitVRforShadowElements.dcm") == 0 ) + { + return 0; + } + return 1; + } + const File &f = r.GetFile(); + gdcm::MediaStorage ms; + ms.SetFromFile( f ); + + const DataSet &ds = f.GetDataSet(); + for( std::vector::const_iterator it = tags.begin(); + it != tags.end(); ++it ) + { + const gdcm::Tag & t = *it; + // Special handling of t8 (DICOMDIR only) + const bool iserror = (ms == gdcm::MediaStorage::MediaStorageDirectoryStorage && t == t8) && false; // de-activate for now + if( !ds.FindDataElement( t ) ) + { + if( iserror ) + { + std::cerr << "Not found element: " << t << " in " << outfilename << std::endl; + return 1; + } + } + const gdcm::DataElement & de = ds.GetDataElement( t ); + if( de.GetVL() != 0 ) + { + if( iserror ) + { + std::cerr << "Wrong VL for: " << t << " in " << outfilename << std::endl; + return 1; + } + } + } + + return 0; +} + +int TestFileAnonymizer2(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestFileAnonymize2(filename, true); + } + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + gdcm::Trace::ErrorOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestFileAnonymize2( filename ); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFileAnonymizer3.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFileAnonymizer3.cxx new file mode 100644 index 0000000..12bfef9 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFileAnonymizer3.cxx @@ -0,0 +1,147 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmFileAnonymizer.h" + +#include "gdcmTesting.h" +#include "gdcmSystem.h" +#include "gdcmReader.h" +#include "gdcmFilename.h" + +#include + +static int TestFileAnonymize3(const char *filename, bool verbose = false) +{ + using namespace gdcm; + if( verbose ) + std::cout << "Processing: " << filename << std::endl; + + // Create directory first: + const char subdir[] = "TestFileAnonymize3"; + std::string tmpdir = Testing::GetTempDirectory( subdir ); + if( !System::FileIsDirectory( tmpdir.c_str() ) ) + { + System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + std::string outfilename = Testing::GetTempFilename( filename, subdir ); + if( verbose ) + std::cout << "Generating: " << outfilename << std::endl; + + const gdcm::Tag t1(0x0018,0x5100); + const gdcm::Tag t2(0x0018,0x1312); + const gdcm::Tag t3(0x0018,0x1313); + const gdcm::Tag t4(0x0018,0x1317); + //const gdcm::Tag t5(0x0008,0x2112); // SQ + //const gdcm::Tag t6(0x0008,0x9215); // SQ + const gdcm::Tag t7(0x0018,0x1020); + const gdcm::Tag t8(0x0004,0x1130); // Test DICOMDIR ! + const gdcm::Tag t9(0x0008,0x0000); // Earliest possible Data Element + const gdcm::Tag t0(0xffff,0xffff); // Latest Possible Element + + std::vector tags; + tags.push_back( t0 ); + tags.push_back( t1 ); + tags.push_back( t2 ); + tags.push_back( t3 ); + tags.push_back( t4 ); + tags.push_back( t7 ); + tags.push_back( t8 ); + tags.push_back( t9 ); + + gdcm::FileAnonymizer fa; + fa.SetInputFileName( filename ); + fa.SetOutputFileName( outfilename.c_str() ); + for( std::vector::const_iterator it = tags.begin(); + it != tags.end(); ++it ) + { + fa.Replace( *it, "TOTO" ); + } + if( !fa.Write() ) + { + std::cerr << "Failed to write: " << outfilename << std::endl; + return 1; + } + + // Read back and check: + gdcm::Reader r; + r.SetFileName( outfilename.c_str() ); + if( !r.Read() ) + { + gdcm::Filename fn( filename ); + std::cerr << "Failed to read: " << outfilename << std::endl; + if( strcmp(fn.GetName(), "SIEMENS_MAGNETOM-12-MONO2-GDCM12-VRUN.dcm") == 0 + || strcmp(fn.GetName(), "DMCPACS_ExplicitImplicit_BogusIOP.dcm") == 0 + || strcmp(fn.GetName(), "ExplicitVRforPublicElementsImplicitVRforShadowElements.dcm") == 0 ) + { + return 0; + } + return 1; + } + const File &f = r.GetFile(); + gdcm::MediaStorage ms; + ms.SetFromFile( f ); + + const DataSet &ds = f.GetDataSet(); + for( std::vector::const_iterator it = tags.begin(); + it != tags.end(); ++it ) + { + const gdcm::Tag & t = *it; + // Special handling of t8 (DICOMDIR only) + const bool iserror = (ms == gdcm::MediaStorage::MediaStorageDirectoryStorage && t == t8) && false; // de-activate for now + if( !ds.FindDataElement( t ) ) + { + if( iserror ) + { + std::cerr << "Not found element: " << t << " in " << outfilename << std::endl; + return 1; + } + } + const gdcm::DataElement & de = ds.GetDataElement( t ); + if( de.GetVL() != 4 ) + { + if( iserror ) + { + std::cerr << "Wrong VL for: " << t << " in " << outfilename << std::endl; + return 1; + } + } + } + + + return 0; +} + +int TestFileAnonymizer3(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestFileAnonymize3(filename, true); + } + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + gdcm::Trace::ErrorOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestFileAnonymize3( filename ); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFileChangeTransferSyntax1.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFileChangeTransferSyntax1.cxx new file mode 100644 index 0000000..30f4ea9 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFileChangeTransferSyntax1.cxx @@ -0,0 +1,208 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmFileChangeTransferSyntax.h" + +#include "gdcmTesting.h" +#include "gdcmSystem.h" +#include "gdcmReader.h" +#include "gdcmImageReader.h" +#include "gdcmFilename.h" +#include "gdcmImageChangePlanarConfiguration.h" +#include "gdcmByteSwap.h" + +int TestFileChangeTransferSyntax1Func(const char *filename, bool verbose = false) +{ + using namespace gdcm; + if( verbose ) + std::cout << "Processing: " << filename << std::endl; + + // Create directory first: + const char subdir[] = "TestFileChangeTransferSyntax1"; + std::string tmpdir = Testing::GetTempDirectory( subdir ); + if( !System::FileIsDirectory( tmpdir.c_str() ) ) + { + System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + std::string outfilename = Testing::GetTempFilename( filename, subdir ); + if( verbose ) + std::cout << "Generating: " << outfilename << std::endl; + + const gdcm::TransferSyntax ts( TransferSyntax::JPEGLosslessProcess14_1 ); + + gdcm::FileChangeTransferSyntax fcts; + fcts.SetTransferSyntax( ts ); + fcts.SetInputFileName( filename ); + fcts.SetOutputFileName( outfilename.c_str() ); + + ImageCodec *ic = fcts.GetCodec(); + if( !ic ) + { + return 1; + } + + if( !fcts.Change() ) + { + gdcm::Reader reader; + reader.SetFileName( filename ); + if( !reader.Read() ) + { + std::cerr << "not dicom" << std::endl; + return 1; + } + const gdcm::File & file = reader.GetFile(); + const gdcm::FileMetaInformation & fmi = file.GetHeader(); + const TransferSyntax &tsref = fmi.GetDataSetTransferSyntax(); + if( tsref.IsEncapsulated() ) + { + if( verbose ) + std::cout << "Will not generate (encaps): " << outfilename << std::endl; + return 0; + } + + gdcm::Filename fn( filename ); + const char *name = fn.GetName(); + // Special handling: + if( strcmp(name, "CT-MONO2-12-lomb-an2.acr" ) == 0 + || strcmp(name, "LIBIDO-8-ACR_NEMA-Lena_128_128.acr") == 0 + || strcmp(name, "gdcm-ACR-LibIDO.acr") == 0 + || strcmp(name, "gdcm-MR-SIEMENS-16-2.acr") == 0 + || strcmp(name, "libido1.0-vol.acr") == 0 + || strcmp(name, "test.acr") == 0 + || strcmp(name, "LIBIDO-24-ACR_NEMA-Rectangle.dcm") == 0 + || strcmp(name, "MR_Spectroscopy_SIEMENS_OF.dcm") == 0 // not an image + || strcmp(name, "ELSCINT1_PMSCT_RLE1.dcm") == 0 + || strcmp(name, "ELSCINT1_PMSCT_RLE1_priv.dcm") == 0 + || strcmp(name, "gdcm-CR-DCMTK-16-NonSamplePerPix.dcm") == 0 + || strcmp(name, "SIEMENS_MAGNETOM-12-ACR_NEMA_2-Modern.dcm") == 0 + || strcmp(name, "PrivateGEImplicitVRBigEndianTransferSyntax16Bits.dcm") == 0 // Implicit VR Big Endian DLX (G.E Private) + || strcmp(name, "MR_GE_with_Private_Compressed_Icon_0009_1110.dcm") == 0 // Explicit VR Big Endian + || strcmp(name, "US-RGB-8-epicard.dcm") == 0 // Explicit VR Big Endian + || strcmp(name, "GE_DLX-8-MONO2-PrivateSyntax.dcm") == 0 // Implicit VR Big Endian DLX (G.E Private) + || strcmp(name, "GE_CT_With_Private_compressed-icon.dcm") == 0 // Explicit VR Big Endian + || strcmp(name, "JDDICOM_Sample2-dcmdjpeg.dcm") == 0 // cannot recreate FMI + || strcmp(name, "DMCPACS_ExplicitImplicit_BogusIOP.dcm") == 0 // ImageRegionReader does not handle it + || strcmp(name, "unreadable.dcm") == 0 // No Pixel Data (old ACR-NEMA) + || strncmp(name, "DICOMDIR", 8) == 0 // DICOMDIR* + || strncmp(name, "dicomdir", 8) == 0 // dicomdir* + ) + { + if( verbose ) + std::cout << "Will not generate: " << outfilename << std::endl; + return 0; + } + std::cerr << "Could not change: " << filename << std::endl; + return 1; + } + + // Let's read that file back in ! + gdcm::ImageReader reader2; + reader2.SetFileName( outfilename.c_str() ); + if ( !reader2.Read() ) + { + std::cerr << "Could not even reread our generated file : " << outfilename << std::endl; + return 1; + } + // Check that after decompression we still find the same thing: + int res = 0; + gdcm::Image img = reader2.GetImage(); + int pc = 0; + + // When recompressing: US-RGB-8-epicard.dcm, make sure to compute the md5 using the + // same original Planar Configuration... + if( (int)img.GetPlanarConfiguration() != pc ) + { + gdcm::ImageChangePlanarConfiguration icpc; + icpc.SetInput( reader2.GetImage() ); + icpc.SetPlanarConfiguration( pc ); + icpc.Change(); + img = icpc.GetOutput(); + } + //std::cerr << "Success to read image from file: " << filename << std::endl; + unsigned long len = img.GetBufferLength(); + char* buffer = new char[len]; + bool res2 = img.GetBuffer(buffer); + if( !res2 ) + { + std::cerr << "could not get buffer: " << outfilename << std::endl; + return 1; + } + // On big Endian system we have byteswapped the buffer (duh!) + // Since the md5sum is byte based there is now way it would detect + // that the file is written in big endian word, so comparing against + // a md5sum computed on LittleEndian would fail. Thus we need to + // byteswap (again!) here: +#ifdef GDCM_WORDS_BIGENDIAN + if( img.GetPixelFormat().GetBitsAllocated() == 16 ) + { + assert( !(len % 2) ); + assert( img.GetPhotometricInterpretation() == gdcm::PhotometricInterpretation::MONOCHROME1 + || img.GetPhotometricInterpretation() == gdcm::PhotometricInterpretation::MONOCHROME2 ); + gdcm::ByteSwap::SwapRangeFromSwapCodeIntoSystem( + (unsigned short*)buffer, gdcm::SwapCode::LittleEndian, len/2); + } +#endif + const char *ref = gdcm::Testing::GetMD5FromFile(filename); + + char digest[33]; + gdcm::Testing::ComputeMD5(buffer, len, digest); + if( !ref ) + { + // new regression image needs a md5 sum + std::cerr << "Missing md5 " << digest << " for: " << filename << std::endl; + //assert(0); + res = 1; + } + else if( strcmp(digest, ref) ) + { + std::cerr << "Problem reading image from: " << filename << std::endl; + std::cerr << "Found " << digest << " instead of " << ref << std::endl; + res = 1; + } + if(res) + { + std::cerr << "problem with: " << outfilename << std::endl; + } + if( verbose ) + { + std::cout << "file was written in: " << outfilename << std::endl; + } + + delete[] buffer; + return res; +} + +int TestFileChangeTransferSyntax1(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestFileChangeTransferSyntax1Func(filename, true); + } + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + gdcm::Trace::ErrorOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestFileChangeTransferSyntax1Func( filename ); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFileDerivation.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFileDerivation.cxx new file mode 100644 index 0000000..b27a459 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFileDerivation.cxx @@ -0,0 +1,131 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmFileDerivation.h" +#include "gdcmReader.h" +#include "gdcmWriter.h" +#include "gdcmTesting.h" +#include "gdcmSystem.h" +#include "gdcmUIDGenerator.h" + +int TestFileDerive(const char *subdir, const char* filename) +{ + using namespace gdcm; + + Reader reader; + reader.SetFileName( filename ); + if ( !reader.Read() ) + { + std::cerr << "Failed to read: " << filename << std::endl; + return 1; + } + FileDerivation fd; + fd.SetFile( reader.GetFile() ); + // Setup some actions: + + // TODO we should reference the original image + File &file = reader.GetFile(); + DataSet &ds = file.GetDataSet(); + + if( !ds.FindDataElement( Tag(0x0008,0x0016) ) + || ds.GetDataElement( Tag(0x0008,0x0016) ).IsEmpty() ) + { + std::cerr << "Missing sop class giving up: " << filename << std::endl; + return 0; + } + if( !ds.FindDataElement( Tag(0x0008,0x0018) ) + || ds.GetDataElement( Tag(0x0008,0x0018) ).IsEmpty() ) + { + std::cerr << "Missing sop instance giving up: " << filename << std::endl; + return 0; + } + + const DataElement &sopclassuid = ds.GetDataElement( Tag(0x0008,0x0016) ); + const DataElement &sopinstanceuid = ds.GetDataElement( Tag(0x0008,0x0018) ); + // Make sure that const char* pointer will be properly padded with \0 char: + std::string sopclassuid_str( sopclassuid.GetByteValue()->GetPointer(), sopclassuid.GetByteValue()->GetLength() ); + std::string sopinstanceuid_str( sopinstanceuid.GetByteValue()->GetPointer(), sopinstanceuid.GetByteValue()->GetLength() ); + + fd.AddReference( sopclassuid_str.c_str(), sopinstanceuid_str.c_str() ); + + // CID 7202 Source Image Purposes of Reference + // {"DCM",121320,"Uncompressed predecessor"}, + fd.SetPurposeOfReferenceCodeSequenceCodeValue( 121320 ); + + // CID 7203 Image Derivation + // { "DCM",113040,"Lossy Compression" }, + fd.SetDerivationCodeSequenceCodeValue( 113040 ); + fd.SetDerivationDescription( "lossy conversion" ); + + if( !fd.Derive() ) + { + std::cerr << "Failed to derive: " << filename << std::endl; + if( ds.FindDataElement( Tag(0x8,0x2112) ) ) + { + return 0; + } + return 1; + } + + // Create directory first: + std::string tmpdir = Testing::GetTempDirectory( subdir ); + if( !System::FileIsDirectory( tmpdir.c_str() ) ) + { + System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + std::string outfilename = Testing::GetTempFilename( filename, subdir ); + + Writer writer; + writer.SetFileName( outfilename.c_str() ); + writer.SetFile( reader.GetFile() ); + if( !writer.Write() ) + { + std::cerr << "Failed to write: " << outfilename << std::endl; + return 1; + } + + // now let's try to read it back in: + Reader reader2; + reader2.SetFileName( outfilename.c_str() ); + if ( !reader2.Read() ) + { + std::cerr << "Could not reread written file: " << outfilename << std::endl; + return 1; + } + + return 0; +} + +int TestFileDerivation( int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestFileDerive( argv[0], filename); + } + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestFileDerive( argv[0], filename ); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFileExplicitFilter.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFileExplicitFilter.cxx new file mode 100644 index 0000000..ec7c594 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFileExplicitFilter.cxx @@ -0,0 +1,116 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmFileExplicitFilter.h" +#include "gdcmReader.h" +#include "gdcmWriter.h" +#include "gdcmTesting.h" +#include "gdcmSystem.h" + +int TestFileExplicitFilt(const char *subdir, const char *filename, bool verbose = false) +{ + if( verbose ) + std::cerr << "Reading: " << filename << std::endl; + gdcm::Reader reader; + reader.SetFileName( filename ); + if ( !reader.Read() ) + { + std::cerr << "could not read: " << filename << std::endl; + return 1; + } + //const gdcm::FileMetaInformation &h = reader.GetFile().GetHeader(); + //const gdcm::DataSet &ds = reader.GetFile().GetDataSet(); + + gdcm::FileExplicitFilter im2ex; + im2ex.SetFile( reader.GetFile() ); + if( !im2ex.Change() ) + { + std::cerr << "Could not im2ex change: " << filename << std::endl; + return 1; + } + + // Create directory first: + std::string tmpdir = gdcm::Testing::GetTempDirectory( subdir ); + if( !gdcm::System::FileIsDirectory( tmpdir.c_str() ) ) + { + gdcm::System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + std::string outfilename = gdcm::Testing::GetTempFilename( filename, subdir ); + gdcm::Writer writer; + writer.SetFileName( outfilename.c_str() ); + writer.SetFile( reader.GetFile() ); + writer.SetCheckFileMetaInformation( false ); + if( !writer.Write() ) + { + std::cerr << "Failed to write: " << outfilename << std::endl; + return 1; + } + + if(verbose) + std::cerr << "write out: " << outfilename << std::endl; + + char digest1[33] = {}; + char digest2[33] = {}; + bool b1 = gdcm::Testing::ComputeFileMD5(filename, digest1); + if( !b1 ) + { + std::cerr << "Could not compute md5:" << filename << std::endl; + return 1; + } + bool b2 = gdcm::Testing::ComputeFileMD5(outfilename.c_str(), digest2); + if( !b2 ) + { + std::cerr << "Could not compute md5:" << outfilename << std::endl; + return 1; + } + if( strcmp(digest1, digest2 ) == 0 ) + { + // Easy case input file was explicit + return 0; + } + else + { + if(verbose) + { + std::cerr << "input file contained wrong VR: " << filename << std::endl; + std::cerr << "see: " << outfilename << std::endl; + } + } + + return 0; +} + +int TestFileExplicitFilter(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestFileExplicitFilt(argv[0], filename, true); + } + + // else + // First of get rid of warning/debug message + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestFileExplicitFilt( argv[0], filename ); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFileStreamer1.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFileStreamer1.cxx new file mode 100644 index 0000000..86f09d7 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFileStreamer1.cxx @@ -0,0 +1,151 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmFileStreamer.h" + +#include "gdcmTesting.h" +#include "gdcmSystem.h" +#include "gdcmReader.h" +#include "gdcmDataSet.h" +#include "gdcmPrivateTag.h" +#include "gdcmFilename.h" + +int TestFileStream1(const char *filename, bool verbose = false) +{ + using namespace gdcm; + if( verbose ) + std::cout << "Processing: " << filename << std::endl; + + // Create directory first: + const char subdir[] = "TestFileStreamer1"; + std::string tmpdir = Testing::GetTempDirectory( subdir ); + if( !System::FileIsDirectory( tmpdir.c_str() ) ) + { + System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + std::string outfilename = Testing::GetTempFilename( filename, subdir ); + if( verbose ) + std::cout << "Generating: " << outfilename << std::endl; + + gdcm::Filename fn( filename ); + const char *name = fn.GetName(); + // Special handling: + bool checktemplate = false; + if( strcmp(name, "DMCPACS_ExplicitImplicit_BogusIOP.dcm" ) == 0 + || strcmp(name, "ExplicitVRforPublicElementsImplicitVRforShadowElements.dcm") == 0 + || strcmp(name, "SIEMENS_MAGNETOM-12-MONO2-GDCM12-VRUN.dcm") == 0 + ) + { + checktemplate = true; + } + + gdcm::FileStreamer fs; + fs.SetTemplateFileName( filename ); + fs.CheckTemplateFileName( checktemplate ); + fs.SetOutputFileName( outfilename.c_str() ); + + std::vector vbuffer; + vbuffer.resize( 8192 ); + const char *buffer = &vbuffer[0]; + const size_t len = vbuffer.size(); + PrivateTag pt( Tag(0x9,0x10), "MYTEST" ); + if( !fs.ReserveGroupDataElement( 20 ) ) + { + return 1; + } + const uint8_t startoffset = 0x13; // why not ? + fs.StartGroupDataElement( pt, 1000, startoffset ); + fs.AppendToGroupDataElement( pt, buffer, len ); + fs.AppendToGroupDataElement( pt, buffer, len ); + fs.StopGroupDataElement( pt ); + + // Read back and check: + gdcm::Reader r; + r.SetFileName( outfilename.c_str() ); + if( !r.Read() ) + { + std::cerr << "Failed to read: " << outfilename << std::endl; + return 1; + } + + gdcm::File & f = r.GetFile(); + gdcm::DataSet & ds = f.GetDataSet(); + + const DataElement private_creator = pt.GetAsDataElement(); + if( !ds.FindDataElement( private_creator.GetTag() ) ) + { + std::cerr << "Could not find priv creator: " << outfilename << std::endl; + return 1; + } + // Check all the group: + const size_t nels = (2 * vbuffer.size() + 999) / 1000; + if( nels != 17 ) return 1; + PrivateTag check = pt; + for( size_t i = startoffset; i < startoffset + nels; ++i ) + { +#if 1 + check.SetElement( (uint16_t)i ); + check.SetPrivateCreator( pt ); +#else + check.SetElement( check.GetElement() + 1 ); +#endif + if( !ds.FindDataElement( check ) ) + { + std::cerr << "Could not find priv tag: " << check << " " << outfilename << std::endl; + return 1; + } + const DataElement & de = ds.GetDataElement( check ); + const int vl = de.GetVL(); + int reflen = 0; + if( i == (startoffset + nels - 1) ) + { + reflen = 384; + } + else + { + reflen = 1000; + } + if( vl != reflen ) + { + std::cerr << "Wrong length for: " << check << ":" << vl << " should be :" << reflen << std::endl; + return 1; + } + } + + return 0; +} + +int TestFileStreamer1(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestFileStream1(filename, true); + } + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + gdcm::Trace::ErrorOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestFileStream1( filename ); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFileStreamer2.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFileStreamer2.cxx new file mode 100644 index 0000000..2722416 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFileStreamer2.cxx @@ -0,0 +1,138 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmFileStreamer.h" + +#include "gdcmTesting.h" +#include "gdcmSystem.h" +#include "gdcmReader.h" +#include "gdcmFilename.h" + +int TestFileStream2(const char *filename, bool verbose = false) +{ + using namespace gdcm; + if( verbose ) + std::cout << "Processing: " << filename << std::endl; + + // Create directory first: + const char subdir[] = "TestFileStreamer2"; + std::string tmpdir = Testing::GetTempDirectory( subdir ); + if( !System::FileIsDirectory( tmpdir.c_str() ) ) + { + System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + std::string outfilename = Testing::GetTempFilename( filename, subdir ); + if( verbose ) + std::cout << "Generating: " << outfilename << std::endl; + + const gdcm::Tag t1(0x0042,0x0011); + + gdcm::Filename fn( filename ); + const char *name = fn.GetName(); + // Special handling: + bool checktemplate = false; + if( strcmp(name, "DMCPACS_ExplicitImplicit_BogusIOP.dcm" ) == 0 + || strcmp(name, "ExplicitVRforPublicElementsImplicitVRforShadowElements.dcm") == 0 + || strcmp(name, "SIEMENS_MAGNETOM-12-MONO2-GDCM12-VRUN.dcm") == 0 + ) + { + checktemplate = true; + } + + gdcm::FileStreamer fs; + fs.SetTemplateFileName( filename ); + fs.CheckTemplateFileName( checktemplate ); + fs.SetOutputFileName( outfilename.c_str() ); + + const char buffer[10] = { 0, 1, 2 , 3, 4, 5, 6, 7, 8, 9 }; + const size_t len = sizeof( buffer ); + //fs.ReserveDataElement( 36 ); + fs.StartDataElement( t1 ); + fs.AppendToDataElement( t1, buffer, len ); + fs.AppendToDataElement( t1, buffer, len ); + fs.AppendToDataElement( t1, buffer, len ); + fs.AppendToDataElement( t1, buffer, len / 2 + 0 ); + fs.StopDataElement( t1 ); + + // Read back and check: + gdcm::Reader r; + r.SetFileName( outfilename.c_str() ); + if( !r.Read() ) + { + std::cerr << "Failed to read: " << outfilename << std::endl; + return 1; + } + + gdcm::File & f = r.GetFile(); + gdcm::DataSet & ds = f.GetDataSet(); + + if( !ds.FindDataElement( t1 ) ) + { + std::cerr << "Could not find tag: " << t1 << std::endl; + return 1; + } + const DataElement & de = ds.GetDataElement( t1 ); + const int vl = de.GetVL(); + + if( vl != 36 ) // 35 + padding + { + return 1; + } + const ByteValue *bv = de.GetByteValue(); + const char *ptr = bv->GetPointer(); + const int b1 = memcmp( ptr + 0 * len, buffer, len ); + const int b2 = memcmp( ptr + 1 * len, buffer, len ); + const int b3 = memcmp( ptr + 2 * len, buffer, len ); + const int b4 = memcmp( ptr + 3 * len, buffer, len / 2 ); + if( b1 || b2 || b3 || b4 ) + { + std::cerr << "Problem:" << b1 << " " + << b2 << " " + << b3 << " " + << b4 << std::endl; + return 1; + } + // NULL padding + if( ptr[35] != 0x0 ) + { + std::cerr << "Error in padding" << std::endl; + return 1; + } + + return 0; +} + +int TestFileStreamer2(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestFileStream2(filename, true); + } + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + gdcm::Trace::ErrorOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestFileStream2( filename ); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFileStreamer3.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFileStreamer3.cxx new file mode 100644 index 0000000..cd0ef1e --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFileStreamer3.cxx @@ -0,0 +1,173 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmFileStreamer.h" + +#include "gdcmTesting.h" +#include "gdcmSystem.h" +#include "gdcmReader.h" +#include "gdcmFilename.h" + +int TestFileStream3(const char *filename, bool verbose = false) +{ + using namespace gdcm; + if( verbose ) + std::cout << "Processing: " << filename << std::endl; + + // Create directory first: + const char subdir[] = "TestFileStreamer3"; + std::string tmpdir = Testing::GetTempDirectory( subdir ); + if( !System::FileIsDirectory( tmpdir.c_str() ) ) + { + System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + std::string outfilename = Testing::GetTempFilename( filename, subdir ); + if( verbose ) + std::cout << "Generating: " << outfilename << std::endl; + + gdcm::Filename fn( filename ); + const char *name = fn.GetName(); + // Special handling: + bool checktemplate = false; + if( strcmp(name, "DMCPACS_ExplicitImplicit_BogusIOP.dcm" ) == 0 + || strcmp(name, "ExplicitVRforPublicElementsImplicitVRforShadowElements.dcm") == 0 + || strcmp(name, "SIEMENS_MAGNETOM-12-MONO2-GDCM12-VRUN.dcm") == 0 + ) + { + checktemplate = true; + } + + gdcm::FileStreamer fs; + fs.SetTemplateFileName( filename ); + fs.CheckTemplateFileName( checktemplate ); + fs.SetOutputFileName( outfilename.c_str() ); + + const gdcm::Tag t1(0x0008,0x0010); + const gdcm::Tag t2(0x0010,0x0010); + + // Try a small buffer to find a case where existing element is larger + bool b; + const char buffer[] = " "; + const size_t len = strlen( buffer ); + // Recognition Code + b = fs.StartDataElement( t1 ); + if( !b ) + { + std::cerr << "Could not StartDataElement" << std::endl; + return 1; + } + b = fs.AppendToDataElement( t1, buffer, len ); + if( !b ) + { + std::cerr << "Could not AppendToDataElement (t1)" << std::endl; + return 1; + } + b = fs.StopDataElement( t1 ); + if( !b ) + { + std::cerr << "Could not StopDataElement" << std::endl; + return 1; + } + // Patient's Name + b = fs.StartDataElement( t2 ); + if( !b ) + { + std::cerr << "Could not StartDataElement" << std::endl; + return 1; + } + b = fs.AppendToDataElement( t2, buffer, len ); + if( !b ) + { + std::cerr << "Could not AppendToDataElement" << std::endl; + return 1; + } + b = fs.StopDataElement( t2 ); + if( !b ) + { + std::cerr << "Could not StopDataElement" << std::endl; + return 1; + } + + // Read back and check: + gdcm::Reader r; + r.SetFileName( outfilename.c_str() ); + if( !r.Read() ) + { + std::cerr << "Failed to read: " << outfilename << std::endl; + return 1; + } + + gdcm::File & f = r.GetFile(); + gdcm::DataSet & ds = f.GetDataSet(); + + if( !ds.FindDataElement( t1 ) ) + { + std::cerr << "Could not find tag: " << t1 << std::endl; + return 1; + } + +{ + const DataElement & de = ds.GetDataElement( t1 ); + const ByteValue * bv = de.GetByteValue(); + if( !bv ) return 1; + if( bv->GetLength() != 2 ) + { + std::cerr << "Wrong length: " << bv->GetLength() << std::endl; + return 1; + } + if( memcmp( bv->GetPointer(), buffer, 2 ) ) + { + std::cerr << "Wrong content" << std::endl; + return 1; + } +} + +{ + const DataElement & de = ds.GetDataElement( t2 ); + const ByteValue * bv = de.GetByteValue(); + if( !bv ) return 1; + if( bv->GetLength() != 2 ) return 1; + if( memcmp( bv->GetPointer(), buffer, 2 ) ) + { + std::cerr << "Wrong content" << std::endl; + return 1; + } +} + + return 0; +} + +int TestFileStreamer3(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestFileStream3(filename, true); + } + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + gdcm::Trace::ErrorOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestFileStream3( filename ); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFileStreamer4.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFileStreamer4.cxx new file mode 100644 index 0000000..debe375 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFileStreamer4.cxx @@ -0,0 +1,183 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmFileStreamer.h" + +#include "gdcmTesting.h" +#include "gdcmSystem.h" +#include "gdcmReader.h" +#include "gdcmFilename.h" +#include "gdcmImageRegionReader.h" +#include "gdcmImageHelper.h" + +int TestFileStream4(const char *filename, bool verbose = false) +{ + using namespace gdcm; + + // Create directory first: + const char subdir[] = "TestFileStreamer4"; + std::string tmpdir = Testing::GetTempDirectory( subdir ); + if( !System::FileIsDirectory( tmpdir.c_str() ) ) + { + System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + std::string outfilename = Testing::GetTempFilename( filename, subdir ); + + gdcm::Filename fn( filename ); + const char *name = fn.GetName(); + // Special handling: + bool checktemplate = false; + if( strcmp(name, "DMCPACS_ExplicitImplicit_BogusIOP.dcm" ) == 0 + || strcmp(name, "ExplicitVRforPublicElementsImplicitVRforShadowElements.dcm") == 0 + || strcmp(name, "SIEMENS_MAGNETOM-12-MONO2-GDCM12-VRUN.dcm") == 0 + ) + { + checktemplate = true; + } + + gdcm::ImageRegionReader irr; + irr.SetFileName( filename ); + if( !irr.ReadInformation() ) + { + //std::cerr << "not an image: " << filename << std::endl; + return 0; + } + + gdcm::File & file = irr.GetFile(); + std::vector dims = + gdcm::ImageHelper::GetDimensionsValue(file); + PixelFormat pf = gdcm::ImageHelper::GetPixelFormatValue(file); + int pixsize = pf.GetPixelSize(); + const size_t computedlen = dims[0] * dims[1] * dims[2] * pixsize; + + const FileMetaInformation &header = file.GetHeader(); + const TransferSyntax &ts = header.GetDataSetTransferSyntax(); + + if( verbose ) + { + std::cout << "Processing: " << filename << std::endl; + std::cout << "Generating: " << outfilename << std::endl; + } + + std::vector vbuffer; + assert( dims[0] ); + vbuffer.resize( dims[0] * pixsize ); + char *buffer = &vbuffer[0]; + const size_t len = vbuffer.size(); + + gdcm::FileStreamer fs; + fs.ReserveDataElement( computedlen ); + fs.SetTemplateFileName( filename ); + fs.CheckTemplateFileName( checktemplate ); + fs.SetOutputFileName( outfilename.c_str() ); + + const gdcm::Tag pixeldata(0x7fe0,0x0010); + + bool b; + b = fs.CheckDataElement( pixeldata ); // will be checking file size + if( !b ) + { + std::cerr << "Failed to CheckDataElement: " << outfilename << std::endl; + return 1; + } + b = fs.StartDataElement( pixeldata ); + if( !b ) + { + std::cerr << "Failed to StartDataElement: " << outfilename << std::endl; + return 1; + } + for( unsigned int z = 0; z < dims[2]; ++z ) + for( unsigned int y = 0; y < dims[1]; ++y ) + { + b = fs.AppendToDataElement( pixeldata, buffer, len ); + if( !b ) + { + std::cerr << "Failed to AppendToDataElement: " << outfilename << std::endl; + return 1; + } + } + if( !fs.StopDataElement( pixeldata ) ) + { + if( ts.IsEncapsulated() ) + { + // Everything is under control + return 0; + } + std::cerr << "Failed to StopDataElement: " << outfilename << std::endl; + return 1; + } + + // Read back and check: + gdcm::Reader r; + r.SetFileName( outfilename.c_str() ); + if( !r.Read() ) + { + std::cerr << "Failed to read: " << outfilename << std::endl; + return 1; + } + + gdcm::File & f = r.GetFile(); + gdcm::DataSet & ds = f.GetDataSet(); + + if( !ds.FindDataElement( pixeldata ) ) + { + std::cerr << "No pixel data: " << outfilename << std::endl; + return 1; + } + const gdcm::DataElement & de = ds.GetDataElement( pixeldata ); + const gdcm::ByteValue *bv = de.GetByteValue(); + if( bv->GetLength() != computedlen ) + { + std::cerr << "Mismatch len: " << outfilename << " : " << bv->GetLength() << + " vs " << computedlen << std::endl; + return 1; + } + const char *p = bv->GetPointer(); + const char *end = p + dims[0] * dims[1] * dims[2]; + int res = 0; + for( ; p != end; ++p ) + { + res += *p; + } + if( res ) + { + std::cerr << "Mismatch: " << outfilename << std::endl; + } + + return res; +} + +int TestFileStreamer4(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestFileStream4(filename, true); + } + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + gdcm::Trace::ErrorOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestFileStream4( filename ); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFileStreamer5.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFileStreamer5.cxx new file mode 100644 index 0000000..f6c41c4 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFileStreamer5.cxx @@ -0,0 +1,96 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmFileStreamer.h" + +#include "gdcmTesting.h" +#include "gdcmSystem.h" +#include "gdcmReader.h" +#include "gdcmDataSet.h" +#include "gdcmPrivateTag.h" +#include "gdcmFilename.h" + +int TestFileStream5(const char *filename, bool verbose = false) +{ + using namespace gdcm; + if( verbose ) + std::cout << "Processing: " << filename << std::endl; + + // Create directory first: + const char subdir[] = "TestFileStreamer5"; + std::string tmpdir = Testing::GetTempDirectory( subdir ); + if( !System::FileIsDirectory( tmpdir.c_str() ) ) + { + System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + std::string outfilename = Testing::GetTempFilename( filename, subdir ); + if( verbose ) + std::cout << "Generating: " << outfilename << std::endl; + + gdcm::Filename fn( filename ); + const char *name = fn.GetName(); + // Special handling: + bool checktemplate = false; + if( strcmp(name, "DMCPACS_ExplicitImplicit_BogusIOP.dcm" ) == 0 + || strcmp(name, "ExplicitVRforPublicElementsImplicitVRforShadowElements.dcm") == 0 + || strcmp(name, "SIEMENS_MAGNETOM-12-MONO2-GDCM12-VRUN.dcm") == 0 + ) + { + checktemplate = true; + } + + gdcm::FileStreamer fs; + fs.SetTemplateFileName( filename ); + fs.CheckTemplateFileName( checktemplate ); + fs.SetOutputFileName( outfilename.c_str() ); + + std::vector vbuffer; + vbuffer.resize( 8192 ); + const char *buffer = &vbuffer[0]; + const size_t len = vbuffer.size(); + PrivateTag pt( Tag(0x9,0x10), "MYTEST" ); + fs.StartGroupDataElement( pt, 10 ); + if( fs.AppendToGroupDataElement( pt, buffer, len ) ) + { + std::cerr << "We should not succeed, we should fail this test" << std::endl; + return 1; + } + fs.StopGroupDataElement( pt ); + + return 0; +} + +int TestFileStreamer5(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestFileStream5(filename, true); + } + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + gdcm::Trace::ErrorOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestFileStream5( filename ); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFileStreamer6.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFileStreamer6.cxx new file mode 100644 index 0000000..11726ec --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFileStreamer6.cxx @@ -0,0 +1,129 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmFileStreamer.h" + +#include "gdcmTesting.h" +#include "gdcmSystem.h" +#include "gdcmReader.h" +#include "gdcmDataSet.h" +#include "gdcmPrivateTag.h" +#include "gdcmFilename.h" + +/* + * Make sure pseudo-private element also works: + */ +int TestFileStream6(const char *filename, bool verbose = false) +{ + using namespace gdcm; + if( verbose ) + std::cout << "Processing: " << filename << std::endl; + + // Create directory first: + const char subdir[] = "TestFileStreamer6"; + std::string tmpdir = Testing::GetTempDirectory( subdir ); + if( !System::FileIsDirectory( tmpdir.c_str() ) ) + { + System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + std::string outfilename = Testing::GetTempFilename( filename, subdir ); + if( verbose ) + std::cout << "Generating: " << outfilename << std::endl; + + gdcm::Filename fn( filename ); + const char *name = fn.GetName(); + // Special handling: + bool checktemplate = false; + if( strcmp(name, "DMCPACS_ExplicitImplicit_BogusIOP.dcm" ) == 0 + || strcmp(name, "ExplicitVRforPublicElementsImplicitVRforShadowElements.dcm") == 0 + || strcmp(name, "SIEMENS_MAGNETOM-12-MONO2-GDCM12-VRUN.dcm") == 0 + ) + { + checktemplate = true; + } + + gdcm::FileStreamer fs; + fs.SetTemplateFileName( filename ); + fs.CheckTemplateFileName( checktemplate ); + fs.SetOutputFileName( outfilename.c_str() ); + + std::vector vbuffer; + vbuffer.resize( 8192 ); + const char *buffer = &vbuffer[0]; + const size_t len = vbuffer.size(); + Tag t( Tag(0x9,0x1010) ); + fs.StartDataElement( t ); + fs.AppendToDataElement( t, buffer, len ); + fs.StopDataElement( t ); + + // Read back and check: + gdcm::Reader r; + r.SetFileName( outfilename.c_str() ); + if( !r.Read() ) + { + std::cerr << "Failed to read: " << outfilename << std::endl; + return 1; + } + + gdcm::File & f = r.GetFile(); + gdcm::DataSet & ds = f.GetDataSet(); + + if( !ds.FindDataElement( t ) ) + { + return 1; + } + + const gdcm::DataElement & de = ds.GetDataElement( t ); + const gdcm::ByteValue * bv = de.GetByteValue(); + if( !bv ) return 1; + if( bv->GetLength() != 8192 ) return 1; + + const char *p = bv->GetPointer(); + const char *end = p + bv->GetLength(); + int res = 0; + for( ; p != end; ++p ) + { + res += *p; + } + if( res ) + { + std::cerr << "Mismatch: " << outfilename << std::endl; + } + + return res; +} + +int TestFileStreamer6(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestFileStream6(filename, true); + } + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + gdcm::Trace::ErrorOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestFileStream6( filename ); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFloatingPointDouble.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFloatingPointDouble.cxx new file mode 100644 index 0000000..8596bac --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestFloatingPointDouble.cxx @@ -0,0 +1,31 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include +#include +#include +#include + +int TestFloatingPointDouble(int, char *[]) +{ + // Not applicable + const char strnan[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x7F}; + const char strinf[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x7F}; + double inf = std::numeric_limits::infinity(); + double nan = std::numeric_limits::quiet_NaN(); + std::cout << inf << std::endl; + std::cout << nan << std::endl; + + + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestIPPSorter.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestIPPSorter.cxx new file mode 100644 index 0000000..e57a80c --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestIPPSorter.cxx @@ -0,0 +1,80 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmIPPSorter.h" +#include "gdcmDirectory.h" +#include "gdcmTesting.h" +#include "gdcmSystem.h" +#include "gdcmTrace.h" + +int TestIPPSorter(int argc, char *argv[]) +{ + const char *directory = gdcm::Testing::GetDataRoot(); + std::vector filenames; + if( argc == 2 ) + { + gdcm::Trace::DebugOn(); + directory = argv[1]; + if( gdcm::System::FileIsDirectory( directory ) ) + { + gdcm::Directory d; + unsigned int nfiles = d.Load( directory ); // no recursion + d.Print( std::cout ); + std::cout << "done retrieving file list. " << nfiles << " files found." << std::endl; + filenames = d.GetFilenames(); + } + else + { + std::cerr << "file:" << directory << " is not a directory" << std::endl; + return 1; + } + } + else + { + // default execution (nightly test) + // let's take 4 files that can be sorted: + std::string file0 = std::string(directory) + "/SIEMENS_MAGNETOM-12-MONO2-FileSeq0.dcm"; + std::string file1 = std::string(directory) + "/SIEMENS_MAGNETOM-12-MONO2-FileSeq1.dcm"; + std::string file2 = std::string(directory) + "/SIEMENS_MAGNETOM-12-MONO2-FileSeq2.dcm"; + std::string file3 = std::string(directory) + "/SIEMENS_MAGNETOM-12-MONO2-FileSeq3.dcm"; + // let's push them in random order (oh my god how are we going to succeed ??) + filenames.push_back( file1 ); + filenames.push_back( file3 ); + filenames.push_back( file2 ); + filenames.push_back( file0 ); + } + + gdcm::IPPSorter s; + s.SetComputeZSpacing( true ); + s.SetZSpacingTolerance( 1e-10 ); + bool b = s.Sort( filenames ); + if( !b ) + { + std::cerr << "Failed to sort: " << directory << std::endl; + return 1; + } + + std::cout << "Sorting succeeded:" << std::endl; + s.Print( std::cout ); + + double zspacing = s.GetZSpacing(); + if(!zspacing) + { + std::cerr << "computation of ZSpacing failed." << std::endl; + return 1; + } + std::cout << "Found z-spacing:" << std::endl; + std::cout << s.GetZSpacing() << std::endl; + + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestIPPSorter2.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestIPPSorter2.cxx new file mode 100644 index 0000000..a3dbecd --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestIPPSorter2.cxx @@ -0,0 +1,98 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmIPPSorter.h" +#include "gdcmDirectory.h" +#include "gdcmTesting.h" +#include "gdcmSystem.h" +#include "gdcmTrace.h" +#include "gdcmAttribute.h" + +// Sort image using Instance Number: +bool mysort(gdcm::DataSet const & ds1, gdcm::DataSet const & ds2 ) +{ + gdcm::Attribute<0x0020,0x0013> at1; // Instance Number + at1.Set( ds1 ); + gdcm::Attribute<0x0020,0x0013> at2; + at2.Set( ds2 ); + return at1 < at2; +} + + +int TestIPPSorter2(int argc, char *argv[]) +{ + const char *directory = gdcm::Testing::GetDataRoot(); + std::vector filenames; + if( argc == 2 ) + { + gdcm::Trace::DebugOn(); + directory = argv[1]; + if( gdcm::System::FileIsDirectory( directory ) ) + { + gdcm::Directory d; + unsigned int nfiles = d.Load( directory ); // no recursion + d.Print( std::cout ); + std::cout << "done retrieving file list. " << nfiles << " files found." << std::endl; + filenames = d.GetFilenames(); + } + else + { + std::cerr << "file:" << directory << " is not a directory" << std::endl; + return 1; + } + } + else + { + // default execution (nightly test) + // let's take 4 files that can be sorted: + std::string file0 = std::string(directory) + "/SIEMENS_MAGNETOM-12-MONO2-FileSeq0.dcm"; + std::string file1 = std::string(directory) + "/SIEMENS_MAGNETOM-12-MONO2-FileSeq1.dcm"; + std::string file2 = std::string(directory) + "/SIEMENS_MAGNETOM-12-MONO2-FileSeq2.dcm"; + std::string file3 = std::string(directory) + "/SIEMENS_MAGNETOM-12-MONO2-FileSeq3.dcm"; + // let's push them in random order (oh my god how are we going to succeed ??) + filenames.push_back( file1 ); + filenames.push_back( file3 ); + filenames.push_back( file2 ); + filenames.push_back( file0 ); + } + + gdcm::IPPSorter s; + s.SetComputeZSpacing( true ); + s.SetZSpacingTolerance( 1e-10 ); + bool b = s.Sort( filenames ); + if( !b ) + { + std::cerr << "Failed to sort:" << directory << std::endl; + return 1; + } + + std::cout << "Sorting succeeded:" << std::endl; + s.Print( std::cout ); + + double zspacing = s.GetZSpacing(); + if(!zspacing) + { + std::cerr << "computation of ZSpacing failed." << std::endl; + return 1; + } + std::cout << "Found z-spacing:" << std::endl; + std::cout << s.GetZSpacing() << std::endl; + + // Now apply a StableSort on them: + s.SetSortFunction( mysort ); + s.StableSort( s.GetFilenames() ); + + s.Print( std::cout ); + + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestIPPSorter3.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestIPPSorter3.cxx new file mode 100644 index 0000000..5cb830e --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestIPPSorter3.cxx @@ -0,0 +1,106 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmIPPSorter.h" +#include "gdcmDirectory.h" +#include "gdcmTesting.h" +#include "gdcmSystem.h" +#include "gdcmTrace.h" +#include "gdcmReader.h" +#include "gdcmWriter.h" + +int TestIPPSorter3(int , char *[]) +{ + const char *directory = gdcm::Testing::GetDataRoot(); + std::vector filenames; + // let's take 4 files that can be sorted: + std::string file0 = std::string(directory) + "/SIEMENS_MAGNETOM-12-MONO2-FileSeq0.dcm"; + std::string file1 = std::string(directory) + "/SIEMENS_MAGNETOM-12-MONO2-FileSeq1.dcm"; + std::string file2 = std::string(directory) + "/SIEMENS_MAGNETOM-12-MONO2-FileSeq2.dcm"; + std::string file3 = std::string(directory) + "/SIEMENS_MAGNETOM-12-MONO2-FileSeq3.dcm"; + + // Make a fake copy: + const char * reference = file0.c_str(); + gdcm::Reader reader; + reader.SetFileName( reference ); + if( !reader.Read() ) return 1; + + // Create directory first: + const char subdir[] = "TestIPPSorter3"; + std::string tmpdir = gdcm::Testing::GetTempDirectory( subdir ); + if( !gdcm::System::FileIsDirectory( tmpdir.c_str() ) ) + { + gdcm::System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + + std::string outfilename = gdcm::Testing::GetTempFilename( reference, subdir ); + + // Tweak the orientation just a little: + // [001.000000E+00\-0.000000E+00\-0.000000E+00\00.000000E+00\01.000000E+00\-0.000000E+00] + gdcm::Writer writer; + writer.SetFileName( outfilename.c_str() ); + + //const char iop_orig[] = "1\\-0\\-0\\0\\1\\-0"; + const char iop[] = "1\\-0\\-0\\0\\0.99999\\0.00001"; + gdcm::DataElement de( gdcm::Tag(0x0020,0x0037) ); + de.SetByteValue( iop, (uint32_t)strlen( iop ) ); + reader.GetFile().GetDataSet().Replace( de ); + + writer.SetFile( reader.GetFile() ); + if( !writer.Write() ) + { + return 1; + } + + // let's push them in random order (oh my god how are we going to succeed ??) + filenames.push_back( file1 ); + filenames.push_back( file3 ); + filenames.push_back( outfilename ); + filenames.push_back( file2 ); + //filenames.push_back( file0 ); + + gdcm::IPPSorter s; + s.SetComputeZSpacing( true ); + s.SetZSpacingTolerance( 1e-10 ); + s.SetDirectionCosinesTolerance( 1e-6 ); + bool b = s.Sort( filenames ); + if( b ) + { + std::cerr << "Success to sort (we should have failed): " << directory << std::endl; + return 1; + } + + // Lower the threshold: + s.SetDirectionCosinesTolerance( 1e-5 ); + b = s.Sort( filenames ); + if( !b ) + { + std::cerr << "Failed to sort: " << directory << std::endl; + return 1; + } + +// std::cout << "Sorting succeeded:" << std::endl; +// s.Print( std::cout ); + + double zspacing = s.GetZSpacing(); + if(!zspacing) + { + std::cerr << "computation of ZSpacing failed." << std::endl; + return 1; + } + std::cout << "Found z-spacing:" << std::endl; + std::cout << s.GetZSpacing() << std::endl; + + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestIconImage.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestIconImage.cxx new file mode 100644 index 0000000..a0cbcd6 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestIconImage.cxx @@ -0,0 +1,43 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmIconImage.h" + +// FIXME: +// gdcmData/US-GE-4AICL142.dcm has a private data element that is an Icon: +/* +(6003,0010) LO [GEMS_Ultrasound_ImageGroup_001] # 30, 1 PrivateCreator +(6003,1010) SQ (Sequence with explicit length #=1) # 12522, 1 Unknown Tag & Data + (fffe,e000) na (Item with explicit length #=15) # 12514, 1 Item + (0002,0010) UI =LittleEndianExplicit # 20, 1 TransferSyntaxUID + (0008,0008) CS [DERIVED\SECONDARY] # 18, 2 ImageType + (0008,2111) ST [SmallPreview] # 12, 1 DerivationDescription + (0028,0002) US 3 # 2, 1 SamplesPerPixel + (0028,0004) CS [RGB] # 4, 1 PhotometricInterpretation + (0028,0006) US 0 # 2, 1 PlanarConfiguration + (0028,0010) US 64 # 2, 1 Rows + (0028,0011) US 64 # 2, 1 Columns + (0028,0014) US 1 # 2, 1 UltrasoundColorDataPresent + (0028,0100) US 8 # 2, 1 BitsAllocated + (0028,0101) US 8 # 2, 1 BitsStored + (0028,0102) US 7 # 2, 1 HighBit + (0028,0103) US 0 # 2, 1 PixelRepresentation + (6003,0010) LO [GEMS_Ultrasound_ImageGroup_001] # 30, 1 PrivateCreator + (6003,1011) OB 00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00... # 12288, 1 Unknown Tag & Data + (fffe,e00d) na (ItemDelimitationItem for re-encoding) # 0, 0 ItemDelimitationItem +*/ +int TestIconImage(int, char *[]) +{ + gdcm::IconImage icon; + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestIconImageFilter.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestIconImageFilter.cxx new file mode 100644 index 0000000..9e8af1b --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestIconImageFilter.cxx @@ -0,0 +1,144 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmIconImageFilter.h" +#include "gdcmTesting.h" +#include "gdcmFilename.h" +#include "gdcmSystem.h" +#include "gdcmImageReader.h" +#include "gdcmImageWriter.h" +#include "gdcmImage.h" + +static const char * const iconimagearray[][2] = { + { "b818c90fc4135423dfc118c3305d23ef" , "MR_GE_with_Private_Compressed_Icon_0009_1110.dcm" }, + { "57e43cf467d9bc4c4a43e0a97329075d" , "SIEMENS_CSA2.dcm" }, + { "fc5db4e2e7fca8445342b83799ff16d8" , "simpleImageWithIcon.dcm" }, + { "93c1b9e4c97cf5ff3501f3d8114c3b89" , "05115014-mr-siemens-avanto-syngo-with-palette-icone.dcm" }, + { "07950df5d3662740874e93d2c41dec18" , "MR-SIEMENS-DICOM-WithOverlays.dcm" }, + { "e1305d5341e8ced04caff40c706c23b0" , "AMIInvalidPrivateDefinedLengthSQasUN.dcm" }, + { "5f76af83e7b99cab45a70248824c2145" , "PICKER-16-MONO2-Nested_icon.dcm" }, + { "59d8479e0025d8bbb3244551d6535890" , "MR_ELSCINT1_00e1_1042_SQ_feff_00e0_Item.dcm" }, + { "9ad43e72601a228c4a3d021f08a09b69" , "CT-SIEMENS-Icone-With-PaletteColor.dcm" }, + { "a9c3c78082a46e2226a4b1ff499ccd74" , "PrivateGEImplicitVRBigEndianTransferSyntax16Bits.dcm" }, + { "50387cdd945b22ccbb5d1824e955deeb" , "05148044-mr-siemens-avanto-syngo.dcm" }, + { "e42ea2852be5d20f95083991728d8623" , "GE_LOGIQBook-8-RGB-HugePreview.dcm" }, + { "c38df20a8514714f5d5af1699a841c60" , "GE_CT_With_Private_compressed-icon.dcm" }, + { "61b2bf04c18a0f67b7e720e07804dcdd" , "KODAK_CompressedIcon.dcm" }, + { "620f0b67a91f7f74151bc5be745b7110" , "MR-SIEMENS-DICOM-WithOverlays-extracted-overlays.dcm" }, + { "938f6ea0bea13ff5c45c7934e603caac" , "US-GE-4AICL142.dcm" }, + + // VEPRO VIF + { "ea4673b2aa72f477188bac340e115f4c" , "PHILIPS_Gyroscan-12-MONO2-Jpeg_Lossless.dcm" }, + { "660417e04b9af62832a43bf82369e4fa" , "GE_DLX-8-MONO2-Multiframe-Jpeg_Lossless.dcm" }, + + // gdcmDataExtra + { "a144b851c9262c97dde567d4d3781733" , "2929J888_8b_YBR_RLE_PlanConf0_breaker.dcm" }, + + // sentinel + { 0, 0 } +}; + +int TestIconImageFilterFunc(const char *filename, bool verbose = false) +{ + gdcm::ImageReader reader; + reader.SetFileName( filename ); + if ( !reader.Read() ) + { + return 0; + } + + gdcm::IconImageFilter iif; + iif.SetFile( reader.GetFile() ); + bool b = iif.Extract(); + + gdcm::Filename fn( filename ); + const char *name = fn.GetName(); + + unsigned int i = 0; + const char *p = iconimagearray[i][1]; + while( p != 0 ) + { + if( strcmp( name, p ) == 0 ) + { + break; + } + ++i; + p = iconimagearray[i][1]; + } + const char *refmd5 = iconimagearray[i][0]; + + if( b ) + { + if( iif.GetNumberOfIconImages() != 1 ) return 1; + + const gdcm::IconImage &icon = iif.GetIconImage(0); + if( verbose ) icon.Print( std::cout ); + unsigned long len = icon.GetBufferLength(); + std::vector< char > vbuffer; + vbuffer.resize( len ); + char *buffer = &vbuffer[0]; + bool res2 = icon.GetBuffer(buffer); + if( !res2 ) + { + std::cerr << "res2 failure:" << filename << std::endl; + return 1; + } + char digest[33]; + gdcm::Testing::ComputeMD5(buffer, len, digest); + if( verbose ) + { + std::cout << "ref=" << refmd5 << std::endl; + std::cout << "md5=" << digest << std::endl; + } + if( !refmd5 ) + { + std::cerr << "Problem with : " << name << " missing md5= " << digest << std::endl; + return 1; + } + if( strcmp( refmd5, digest) ) + { + std::cerr << "Problem with : " << name << " " << refmd5 << " vs " << digest << std::endl; + return 1; + } + } + else + { + assert( refmd5 == 0 ); + } + + return 0; +} + +int TestIconImageFilter(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestIconImageFilterFunc(filename, true); + } + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + gdcm::Trace::ErrorOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestIconImageFilterFunc( filename ); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestIconImageGenerator.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestIconImageGenerator.cxx new file mode 100644 index 0000000..efcec4f --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestIconImageGenerator.cxx @@ -0,0 +1,359 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmImageReader.h" +#include "gdcmImageWriter.h" +#include "gdcmFilename.h" +#include "gdcmSystem.h" +#include "gdcmFileMetaInformation.h" +#include "gdcmTesting.h" +#include "gdcmByteSwap.h" +#include "gdcmIconImageGenerator.h" + +static const char * const iconimagearray[][2] = { + {"f4f187737b9646348844804cd4eda259" , "SIEMENS_SOMATOM-12-ACR_NEMA-ZeroLengthUs.acr" }, + {"8659bcbae5479e03925ea51af0d42170" , "gdcm-MR-SIEMENS-16-2.acr" }, + {"f50225bbd7de605fa5b32d47ab4d0f19" , "test.acr" }, + {"890bd3ca8ab288128f520fd2a0c33539" , "MR-MONO2-12-an2.acr" }, + {"8893470f6cbe6314c66763b709177c7a" , "CT-MONO2-12-lomb-an2.acr" }, + {"2134b4b992ded28502f24ab3f21c6432" , "LIBIDO-8-ACR_NEMA-Lena_128_128.acr" }, + {"f9d8a0796ebf5a6aabddb4e133d09770" , "gdcm-ACR-LibIDO.acr" }, + {"68525a2313b5416fb6cf1f6b4fdb8d48" , "libido1.0-vol.acr" }, + {"a6453c0e0abbaad98edd3fd2d76f9d31" , "SIEMENS_CSA2.dcm" }, + {"84b514b71413607571b40dcc73a1e73b" , "gdcm-JPEG-LossLessThoravision.dcm" }, + {"c58f9cbfa1fe616278f963b48b33ee9f" , "XA-MONO2-8-12x-catheter.dcm" }, + {"d383b49843c5226c8f21cd5ee89b6da4" , "gdcm-MR-PHILIPS-16-Multi-Seq.dcm" }, + {"5fd844186b04820e1a55d42e99d81466" , "PHILIPS_GDCM12xBug.dcm" }, + {"5ec31742812dc9d3fd2a4eca8e8b8a48" , "MR_Philips_Intera_PrivateSequenceExplicitVR_in_SQ_2001_e05f_item_wrong_lgt_use_NOSHADOWSEQ.dcm" }, + {"0132ce06e00b199446ebd14d957e6119" , "D_CLUNIE_CT1_J2KI.dcm" }, + {"3f7cae9b920adb3ca4a96ace2c0c91d7" , "rle16sti.dcm" }, + {"aa3c60bbe989c9f3ef5e59243e08af56" , "3E768EB7.dcm" }, + {"e3dae1f82b71857960bad4103524a72b" , "D_CLUNIE_MR2_JPLY.dcm" }, + {"5995fc49c087d64182a7dc2cabedb4b2" , "SIEMENS_MAGNETOM-12-MONO2-FileSeq1.dcm" }, + {"b7051f50189e469f6fc52d5108080b6d" , "SIEMENS_MAGNETOM-12-MONO2-FileSeq0.dcm" }, + {"17cd7bdeb852639b214377f0263a82d3" , "MR_Philips_Intera_SwitchIndianess_noLgtSQItem_in_trueLgtSeq.dcm" }, + {"365049df79c7491d14476c21083283ee" , "LEADTOOLS_FLOWERS-16-MONO2-Uncompressed.dcm" }, + {"2cc83519b459f49f22d37c56f0362c3a" , "D_CLUNIE_MR3_JPLY.dcm" }, + {"e8b529fbe615b4c540318695913d02e7" , "D_CLUNIE_VL2_RLE.dcm" }, + {"e223c80bb1ce7344559632777881fc98" , "OsirixFake16BitsStoredFakeSpacing.dcm" }, + {"e1b4e64a3a665d9ad74dc8a14cdc882b" , "GE_RHAPSODE-16-MONO2-JPEG-Fragments.dcm" }, + {"cb78acab107d772f3ef2353ffdc32360" , "MR_SIEMENS_forceLoad29-1010_29-1020.dcm" }, + {"4755c9b837968ca19b7a9882d4662c33" , "fffc0000UN.dcm" }, + {"796594769ee3570292de36fdb4509df1" , "LIBIDO-24-ACR_NEMA-Rectangle.dcm" }, + {"ffab5ebdfe60100e71295fe50412a98f" , "IM-0001-0066.CommandTag00.dcm" }, + {"4ce869f259e705d596bd459f7863c0ca" , "D_CLUNIE_NM1_JPLY.dcm" }, + {"e1b4e64a3a665d9ad74dc8a14cdc882b" , "D_CLUNIE_CT1_J2KR.dcm" }, + {"539914be101cd8a0fad88ea3e0827f59" , "TheralysGDCM120Bug.dcm" }, + {"20ac559d51fd5685236979d165178dd6" , "SIEMENS_MAGNETOM-12-MONO2-VRUN.dcm" }, + {"ed6e642ca59d3e90d7db08856330cf00" , "THERALYS-12-MONO2-Uncompressed-Even_Length_Tag.dcm" }, + {"209400d084e2c179c8c3d4973e75c66a" , "ALOKA_SSD-8-MONO2-RLE-SQ.dcm" }, + {"66bfea16c5837f976654e038b119af7a" , "GE_GENESIS-16-MONO2-WrongLengthItem.dcm" }, + {"d4669bd89971c1affd311c7d1d8b20c7" , "US-RGB-8-esopecho.dcm" }, + {"4b827f55ca36895f40bc47d27a0d7ea4" , "D_CLUNIE_MR4_RLE.dcm" }, + {"7d1c251e29dcd79af32c791a6f8e24e9" , "D_CLUNIE_MR2_JPLL.dcm" }, + {"5d642ed928e155551f3431f172e3378d" , "SIEMENS_Sonata-16-MONO2-Value_Multiplicity.dcm" }, + {"365049df79c7491d14476c21083283ee" , "LEADTOOLS_FLOWERS-16-MONO2-JpegLossless.dcm" }, + {"4305b70775ce53503ef93614815961e1" , "CT-MONO2-16-ankle.dcm" }, + {"1a27a48d4efe2999b83bc89d3003d05c" , "LEADTOOLS_FLOWERS-8-PAL-RLE.dcm" }, + {"2134b4b992ded28502f24ab3f21c6432" , "simpleImageWithIcon.dcm" }, + {"a13e29a4a0ca1a31338589a45f21a9e2" , "CR-MONO1-10-chest.dcm" }, + {"e1b4e64a3a665d9ad74dc8a14cdc882b" , "D_CLUNIE_CT1_RLE.dcm" }, + {"32931c4b9131f43496ab4a3518527af1" , "D_CLUNIE_NM1_JPLL.dcm" }, + {"efc58ca0ba4b51b511374f8e53f2af4e" , "MR_GE_with_Private_Compressed_Icon_0009_1110.dcm" }, + {"620f0b67a91f7f74151bc5be745b7110" , "NM-MONO2-16-13x-heart.dcm" }, + {"9abf5e3aadcfe2b9c1cfe41782b36704" , "US-IRAD-NoPreambleStartWith0003.dcm" }, + {"f778aac834d5a68acaa97d8faec18e72" , "MR-MONO2-16-head.dcm" }, + {"1a27a48d4efe2999b83bc89d3003d05c" , "LEADTOOLS_FLOWERS-8-PAL-Uncompressed.dcm" }, + {"09e18d103bc8c9cf08b1455af2717310" , "MAROTECH_CT_JP2Lossy.dcm" }, + {"bedb38b85f3bdb85c99b62e5b01a3ada" , "05115014-mr-siemens-avanto-syngo-with-palette-icone.dcm" }, + {"fb5402472ee00639ef8dc1b09692c299" , "US-PAL-8-10x-echo.dcm" }, + {"cea1ea10e8efc68bfb559bbefd1e4cc1" , "MR-SIEMENS-DICOM-WithOverlays.dcm" }, + {"6246c70687f0deab108c889eacda1b8e" , "D_CLUNIE_MR1_JPLL.dcm" }, + {"e1b4e64a3a665d9ad74dc8a14cdc882b" , "D_CLUNIE_CT1_JPLL.dcm" }, + {"db6293d8adc92a2273b6ae2fee13c2e7" , "AMIInvalidPrivateDefinedLengthSQasUN.dcm" }, + {"17cd7bdeb852639b214377f0263a82d3" , "ExplicitVRforPublicElementsImplicitVRforShadowElements.dcm" }, + {"b041b08aa1786195f3f26a75c1b84b85" , "PHILIPS_Gyroscan-12-Jpeg_Extended_Process_2_4.dcm" }, + {"9172854202523aa6688367efcbfc3bdc" , "D_CLUNIE_SC1_JPLY.dcm" }, + {"d29e7ff251d7d754ce8b5368f61032b0" , "gdcm-MR-PHILIPS-16-NonSquarePixels.dcm" }, + {"8a5d13f6c85b2eebc1c02432d729cd45" , "SIEMENS-MR-RGB-16Bits.dcm" }, + {"3e8618fee9c8baca508eeef8206a340a" , "US-IRAD-NoPreambleStartWith0005.dcm" }, + {"3a7816dc8359a0d8a935313909fcf817" , "PICKER-16-MONO2-Nested_icon.dcm" }, + {"be5490cac843a7325027e578067d4eb3" , "gdcm-JPEG-Extended.dcm" }, + {"c790d0a462907135c1991f10a4846f98" , "D_CLUNIE_US1_RLE.dcm" }, + {"3ac268f0ec6f1005a72db89d182f143c" , "D_CLUNIE_RG2_JPLY.dcm" }, + {"5e848e7bc12f27e598c3348a586def24" , "PHILIPS_Brilliance_ExtraBytesInOverlay.dcm" }, + {"3bbe5ebe2ff7e260d56e40f670e3e335" , "MR_ELSCINT1_00e1_1042_SQ_feff_00e0_Item.dcm" }, + {"9df1b097f3f7eb4a3725065e361b9213" , "TG18-CH-2k-01.dcm" }, + {"365049df79c7491d14476c21083283ee" , "LEADTOOLS_FLOWERS-16-MONO2-RLE.dcm" }, + {"27daf49ec13f58db1d800fc58378852e" , "OT-PAL-8-face.dcm" }, + {"07fef244d4e14358d453c144770b2a55" , "LEADTOOLS_FLOWERS-24-RGB-JpegLossy.dcm" }, + {"0c38dfd851a74ea2205a0a6b69c2ddf7" , "SIEMENS_MAGNETOM-12-MONO2-Uncompressed.dcm" }, + {"620f0b67a91f7f74151bc5be745b7110" , "GDCMJ2K_TextGBR.dcm" }, + {"5158679aaa379a50dec1e4a092d91455" , "MR16BitsAllocated_8BitsStored.dcm" }, + {"22103a2ee208d18f8c4e60dc15e5444a" , "GE_GENESIS-16-MONO2-Uncompressed-UnusualVR.dcm" }, + {"e1b4e64a3a665d9ad74dc8a14cdc882b" , "D_CLUNIE_CT1_JLSL.dcm" }, + {"719505e71eafd643fa2e114acc83496f" , "ELSCINT1_JP2vsJ2K.dcm" }, + {"09dd85a0f964f307f66f2b8727d22efb" , "D_CLUNIE_XA1_JPLL.dcm" }, + {"a5019730f663a81b50d559c8a98da4a6" , "SIEMENS_Sonata-12-MONO2-SQ.dcm" }, + {"ed0f5fc46b2e0bb6550d68686d956ca6" , "JPEGDefinedLengthSequenceOfFragments.dcm" }, + {"5aaee8a979cb11627e56ca5757e5d4e3" , "PHILIPS_GDCM12xBug2.dcm" }, + {"620f0b67a91f7f74151bc5be745b7110" , "ITK_GDCM124_MultiframeSecondaryCaptureInvalid.dcm" }, + {"e34c7c8d406ceec07ff1c8b82b59d2e5" , "D_CLUNIE_RG2_JPLL.dcm" }, + {"7478edd0202fde583138df8dfe2782f9" , "FUJI-10-MONO1-ACR_NEMA_2.dcm" }, + {"c5d8e44435241965c400935d30b0d654" , "D_CLUNIE_MR1_JPLY.dcm" }, + {"09dd85a0f964f307f66f2b8727d22efb" , "D_CLUNIE_XA1_RLE.dcm" }, + {"2783d3ac71623cd136de7eb8af13753b" , "BugGDCM2_UndefItemWrongVL.dcm" }, + {"8659bcbae5479e03925ea51af0d42170" , "SIEMENS_MAGNETOM-12-ACR_NEMA_2-Modern.dcm" }, + {"477d801b27ef3cb21a8685cedbc9b12e" , "JDDICOM_Sample2.dcm" }, + {"028dcdbc8e309eac282f73cff0751273" , "TOSHIBA_MRT150-16-MONO2-ACR_NEMA_2.dcm" }, + {"7e183442aefeadbfff9f0d79a7064a5d" , "DCMTK_JPEGExt_12Bits.dcm" }, + {"9f04afae98a960de78b31e416bdbe31b" , "US-MONO2-8-8x-execho.dcm" }, + {"7cc0d00a56ec460d4025d4f9cea4e445" , "UnexpectedSequenceDelimiterInFixedLengthSequence.dcm" }, + {"bee28068ae9edef69fef792583b3e20f" , "ACUSON-24-YBR_FULL-RLE-b.dcm" }, + {"b171f7581c9cf15b2d32cfd62e9b6038" , "gdcm-US-ALOKA-16.dcm" }, + {"b6ba84d4868436e0b44b19d75cefe239" , "DX_J2K_0Padding.dcm" }, + {"76b3e5225e1914e61010eb11c50b0d13" , "D_CLUNIE_CT2_RLE.dcm" }, + {"455aa24ef2085a6b57f8b29d4f42b558" , "D_CLUNIE_RG1_JPLL.dcm" }, + {"e0a3fd5917c5a13a16981e1d0346af4d" , "D_CLUNIE_VL3_RLE.dcm" }, + {"fd69a42d6ed9ac779fbdea5a874f27da" , "NM_Kakadu44_SOTmarkerincons.dcm" }, + {"5a622115e307a024aeb6003ad45c87d7" , "CT-SIEMENS-Icone-With-PaletteColor.dcm" }, + {"d687a5770da5430258c9354ef7283fb1" , "GE_DLX-8-MONO2-PrivateSyntax.dcm" }, + {"48843eac44f481073e2349a9b40034e6" , "CT_16b_signed-UsedBits13.dcm" }, + {"7b8f24a39d4d46d6898d0c868e2ead62" , "D_CLUNIE_RG3_JPLY.dcm" }, + {"a1b35156bf0be7f0fe5054e13b6dc11f" , "DX_GE_FALCON_SNOWY-VOI.dcm" }, + {"8745f035e70b8dad2a4b04b855c1974e" , "PrivateGEImplicitVRBigEndianTransferSyntax16Bits.dcm" }, + {"608d7fd9e8cf15f95b75a12072a209d9" , "CT-MONO2-16-brain.dcm" }, + {"c2de60330cda14759a117b937a7e5a95" , "D_CLUNIE_VL4_RLE.dcm" }, + {"b4213e55f351e2c9e013050652c8fad4" , "D_CLUNIE_MR3_RLE.dcm" }, + {"cdae2ce2d07ef1880f9eba78e72c7f03" , "undefined_length_un_vr.dcm" }, + {"1e456d9eb136554a3d035d65999ac72f" , "CT-MONO2-16-ort.dcm" }, + {"7022cd07ae0e9311ca2bb13372becee1" , "05148044-mr-siemens-avanto-syngo.dcm" }, + {"5d6aaab5766479ec6e27de4eaa4a6438" , "GE_LOGIQBook-8-RGB-HugePreview.dcm" }, + {"d8b9952cb72ea315ae4b81038ca7498f" , "RadBWLossLess.dcm" }, + {"b7b5b0a05dde85a672529e896ffd34cc" , "KODAK-12-MONO1-Odd_Terminated_Sequence.dcm" }, + {"c1b31ebeb79ba29263e59254af17eb88" , "CT-MONO2-16-chest.dcm" }, + {"4085155ff0a36230f55dfd17c07b016f" , "PhilipsInteraSeqTermInvLen.dcm" }, + {"4c80f49834a2f8cec23ff8c7c0e80613" , "D_CLUNIE_MR4_JPLY.dcm" }, + {"dc04449fe2bdd8c5ff26f2b6b4f3a1aa" , "D_CLUNIE_RG3_JPLL.dcm" }, + {"01d9c3bac1a49f874eb70640d9187657" , "MR_Philips-Intera_BreaksNOSHADOW.dcm" }, + {"f86eb566e712fa57bf5bdd13af9233c6" , "GE_CT_With_Private_compressed-icon.dcm" }, + {"b2ed24f5bad1fe7fe1ceb62a1a37bf03" , "D_CLUNIE_CT1_JLSN.dcm" }, + {"20ac559d51fd5685236979d165178dd6" , "SIEMENS_MAGNETOM-12-MONO2-GDCM12-VRUN.dcm" }, + {"cee47e57f6b1aaace74bb813e33a74eb" , "00191113.dcm" }, + {"645a354b8bfbbda1c3e01a79c583eca0" , "MARCONI_MxTWin-12-MONO2-JpegLossless-ZeroLengthSQ.dcm" }, + {"f8ef8fa89c0415c54ee8350db9bafc59" , "SignedShortLosslessBug.dcm" }, + {"9274ed6683e657a8e6c95278cb93a971" , "GE_DLX-8-MONO2-Multiframe.dcm" }, + {"cb7ccda2e8aed6d56df6350207c1d122" , "PHILIPS_Gyroscan-12-MONO2-Jpeg_Lossless.dcm" }, + {"788c5bf06000799bd630c70ce0418430" , "LJPEG_BuginGDCM12.dcm" }, + {"610b9ac0f1aac082eb1c0b140a85d2de" , "SIEMENS_MAGNETOM-12-MONO2-FileSeq3.dcm" }, + {"dc04449fe2bdd8c5ff26f2b6b4f3a1aa" , "D_CLUNIE_RG3_RLE.dcm" }, + {"587e56aa881d645ee67ac3afe317b11d" , "CT-SIEMENS-MissingPixelDataInIconSQ.dcm" }, + {"7d1c251e29dcd79af32c791a6f8e24e9" , "MR-MONO2-12-shoulder.dcm" }, + {"0b818ac3983d76cfdc535a46058a1a53" , "LEADTOOLS_FLOWERS-24-RGB-Uncompressed.dcm" }, + {"ba8fb87069401e40d9c0dd5bf0f2bb06" , "PICKER-16-MONO2-No_DicomV3_Preamble.dcm" }, + {"634fca1b1087cfb2dd4c74a567daf302" , "SIEMENS_MOSAIC_12BitsStored-16BitsJPEG.dcm" }, + {"ba0654f3e7aae75bca8fc24705ddb78a" , "CT-MONO2-8-abdo.dcm" }, + {"b4213e55f351e2c9e013050652c8fad4" , "D_CLUNIE_MR3_JPLL.dcm" }, + {"03f25fb3e6e8ae53b9565553e2026a66" , "D_CLUNIE_VL6_RLE.dcm" }, + {"365049df79c7491d14476c21083283ee" , "LEADTOOLS_FLOWERS-8-MONO2-RLE.dcm" }, + {"99b13adb3932f9fcf50c0aa936b6e367" , "PHILIPS_Gyroscan-8-MONO2-Odd_Sequence.dcm" }, + {"1f0795064ee1d19534780b7a4e92d5db" , "SIEMENS-12-Jpeg_Process_2_4-Lossy-a.dcm" }, + {"de42da38e961881e7a68f4d9337007cd" , "gdcm-JPEG-LossLess3a.dcm" }, + {"bec532ee78edb47bd0894dcbb2a7d1f5" , "D_CLUNIE_XA1_JPLY.dcm" }, + {"455aa24ef2085a6b57f8b29d4f42b558" , "D_CLUNIE_RG1_RLE.dcm" }, + {"e77b93eb953f2a21fa75d257da0514fb" , "US-RGB-8-epicard.dcm" }, + {"ddc56ce334439f64953f1b11c82aeeb9" , "GE_MR_0025xx1bProtocolDataBlock.dcm" }, + {"b9f48f54e75b7f1994cfe1a7152d9ab5" , "rle16loo.dcm" }, + {"50bf4b4c98228d2f11fb0d8c4b49e3cc" , "DMCPACS_ExplicitImplicit_BogusIOP.dcm" }, + {"76b3e5225e1914e61010eb11c50b0d13" , "D_CLUNIE_CT2_JPLL.dcm" }, + {"477d801b27ef3cb21a8685cedbc9b12e" , "JDDICOM_Sample2-dcmdjpeg.dcm" }, + {"17cd7bdeb852639b214377f0263a82d3" , "MR_Philips_Intera_No_PrivateSequenceImplicitVR.dcm" }, + {"19cd0ebffc7541a5ec944d25200923ad" , "KODAK_CompressedIcon.dcm" }, + {"486199008daf27f167efee9469fffd52" , "ACUSON-24-YBR_FULL-RLE.dcm" }, + {"7d1c251e29dcd79af32c791a6f8e24e9" , "D_CLUNIE_MR2_RLE.dcm" }, + {"b53c440c32a7bd20d24cc1997bd7c9e6" , "JPEG_LossyYBR.dcm" }, + {"4c54ea0d88336020167a5cb9437a1dec" , "012345.002.050.dcm" }, + {"e34c7c8d406ceec07ff1c8b82b59d2e5" , "D_CLUNIE_RG2_RLE.dcm" }, + {"b209bb00a5bb920ebfb52b50132bd3cb" , "MR_Philips_Intera_PrivateSequenceImplicitVR.dcm" }, + {"261065dc52f086beac57ed71977b40ec" , "SIEMENS_ImageLocationUN.dcm" }, + {"17cd7bdeb852639b214377f0263a82d3" , "PHILIPS_Intera-16-MONO2-Uncompress.dcm" }, + {"60e754c9dfc02bba3aee11e67653d844" , "MR-SIEMENS-DICOM-WithOverlays-extracted-overlays.dcm" }, + {"0b818ac3983d76cfdc535a46058a1a53" , "LEADTOOLS_FLOWERS-24-RGB-JpegLossless.dcm" }, + {"91b4da2ca9fd378ca404580c84c62984" , "US-GE-4AICL142.dcm" }, + {"5b24d4a43d7c72090eabb88a06b56f15" , "D_CLUNIE_SC1_RLE.dcm" }, + {"4b827f55ca36895f40bc47d27a0d7ea4" , "D_CLUNIE_MR4_JPLL.dcm" }, + {"95ccb6a943e1ca82f3be78ceaa72b9d4" , "MR-Brucker-CineTagging-NonSquarePixels.dcm" }, + {"552dd953ebd0575d124e44df0218b0ea" , "MR-MONO2-8-16x-heart.dcm" }, + {"e73b404ca6d9b4b7ba54f46d2662deca" , "LEADTOOLS_FLOWERS-8-MONO2-JpegLossy.dcm" }, + {"8a35a388332dbb40018ee6814ab27994" , "GE_DLX-8-MONO2-Multiframe-Jpeg_Lossless.dcm" }, + {"32931c4b9131f43496ab4a3518527af1" , "D_CLUNIE_NM1_RLE.dcm" }, + {"20e2f6cc2b60ae26adfdd3b3ee0e1915" , "D_CLUNIE_VL1_RLE.dcm" }, + {"0b1cb469990edd0cabfa34c8b6cb427d" , "SIEMENS_MAGNETOM-12-MONO2-FileSeq2.dcm" }, + {"620f0b67a91f7f74151bc5be745b7110" , "DermaColorLossLess.dcm" }, + {"b9395dcfbb50e1af31147f80e8e0c1e7" , "OT-MONO2-8-a7.dcm" }, + {"6246c70687f0deab108c889eacda1b8e" , "D_CLUNIE_MR1_RLE.dcm" }, + {"365049df79c7491d14476c21083283ee" , "LEADTOOLS_FLOWERS-8-MONO2-Uncompressed.dcm" }, + {"cee47e57f6b1aaace74bb813e33a74eb" , "00191113.dcm" }, + {"07b6f4e2fba920d28e2f29dbb037b640" , "TOSHIBA_J2K_SIZ1_PixRep0.dcm" }, + {"206713a8ff161546d664d1285f99f90b" , "TOSHIBA_J2K_OpenJPEGv2Regression.dcm" }, + {"dc70ae52689ebf8f5003320e1c7f216b" , "TOSHIBA_J2K_SIZ0_PixRep1.dcm" }, + {"3475cb96e0308cb84502be1c1531b588" , "NM-PAL-16-PixRep1.dcm" }, + {"bcac830aae8652a88f4c4aa6d9e7e116" , "MEDILABInvalidCP246_EVRLESQasUN.dcm" }, + {"5b8db1c8d42870f68bfd908529c58710" , "JPEGInvalidSecondFrag.dcm" }, + + // sentinel + { 0, 0 } +}; + +namespace gdcm +{ +int TestIconImageGenerate(const char *subdir, const char* filename, bool verbose = false) +{ + ImageReader reader; + reader.SetFileName( filename ); + if ( !reader.Read() ) + { + const FileMetaInformation &header = reader.GetFile().GetHeader(); + MediaStorage ms = header.GetMediaStorage(); + bool isImage = MediaStorage::IsImage( ms ); + bool pixeldata = reader.GetFile().GetDataSet().FindDataElement( Tag(0x7fe0,0x0010) ); + if( isImage && pixeldata ) + { + std::cerr << "Failed to read: " << filename << std::endl; + return 1; + } + else + { + // not an image give up... + std::cerr << "Problem with: " << filename << " but that's ok" << std::endl; + return 0; + } + } + + // Create directory first: + std::string tmpdir = Testing::GetTempDirectory( subdir ); + if( !System::FileIsDirectory( tmpdir.c_str() ) ) + { + System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + std::string outfilename = Testing::GetTempFilename( filename, subdir ); + + IconImageGenerator iig; + iig.SetPixmap( reader.GetImage() ); + const unsigned int idims[2] = { 64, 64 }; + iig.SetOutputDimensions( idims ); + bool b = iig.Generate(); + + gdcm::Filename fn( filename ); + const char *name = fn.GetName(); + + unsigned int i = 0; + const char *p = iconimagearray[i][1]; + while( p != 0 ) + { + if( strcmp( name, p ) == 0 ) + { + break; + } + ++i; + p = iconimagearray[i][1]; + } + const char *refmd5 = iconimagearray[i][0]; + + if( b ) + { + const gdcm::IconImage &icon = iig.GetIconImage(); + if( verbose ) icon.Print( std::cout ); + unsigned long len = icon.GetBufferLength(); + std::vector< char > vbuffer; + vbuffer.resize( len ); + char *buffer = &vbuffer[0]; + bool res2 = icon.GetBuffer(buffer); + if( !res2 ) + { + std::cerr << "res2 failure:" << filename << std::endl; + return 1; + } + char digest[33]; + gdcm::Testing::ComputeMD5(buffer, len, digest); + Image & img = reader.GetImage(); + img.SetIconImage( iig.GetIconImage() ); + + ImageWriter writer; + writer.SetFileName( outfilename.c_str() ); +#if 1 + writer.SetImage( img ); +#else + Image &ii = writer.GetImage(); + (Bitmap&)ii = iig.GetIconImage(); +#endif + if( !writer.Write() ) + { + std::cerr << "Failed to write: " << outfilename << std::endl; + return 1; + } + + if( verbose ) + { + std::cout << "success: " << outfilename << std::endl; + std::cout << "ref=" << refmd5 << std::endl; + std::cout << "md5=" << digest << std::endl; + } + + if( !refmd5 ) + { + std::cerr << " missing md5= {\"" << digest << "\" , \"" << name << "\" }," << std::endl; + return 1; + } + if( strcmp( refmd5, digest) ) + { + std::cerr << "Problem with : " << name << " " << refmd5 << " vs " << digest << std::endl; + return 1; + } + + } + else + { + assert( refmd5 == 0 ); + std::cerr << "Could not generate Icon for: " << filename << std::endl; + return 1; + } + + return 0; +} +} + +int TestIconImageGenerator(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return gdcm::TestIconImageGenerate(argv[0],filename, true); + } + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + gdcm::Trace::ErrorOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += gdcm::TestIconImageGenerate(argv[0], filename ); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestIconImageGenerator2.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestIconImageGenerator2.cxx new file mode 100644 index 0000000..66fe926 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestIconImageGenerator2.cxx @@ -0,0 +1,361 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmImageReader.h" +#include "gdcmImageWriter.h" +#include "gdcmFilename.h" +#include "gdcmSystem.h" +#include "gdcmFileMetaInformation.h" +#include "gdcmTesting.h" +#include "gdcmByteSwap.h" +#include "gdcmIconImageGenerator.h" + +static const char * const iconimagearray2[][2] = { + {"7e097b4a57af6a823bd692e37b131b1c" , "SIEMENS_SOMATOM-12-ACR_NEMA-ZeroLengthUs.acr" }, + {"7f2638cea652bf3452ada158d2ea67c4" , "gdcm-MR-SIEMENS-16-2.acr" }, + {"da0922a02f8e763ec878089617e0bc4c" , "test.acr" }, + {"e75ee90f23db1952a593393cdfaaf99f" , "MR-MONO2-12-an2.acr" }, + {"c9c46afd186531850af9576cf54c800b" , "CT-MONO2-12-lomb-an2.acr" }, + {"feb10d9a28e5166a3baf9ec6ef4f460a" , "LIBIDO-8-ACR_NEMA-Lena_128_128.acr" }, + {"f9d8a0796ebf5a6aabddb4e133d09770" , "gdcm-ACR-LibIDO.acr" }, + {"a1bce65e11c5fd2e26f7b38ebfdd1c53" , "libido1.0-vol.acr" }, + {"9edea7caea2b85aad952d35c64f1e092" , "SIEMENS_CSA2.dcm" }, + {"011d1f2abd9e27a2dc5d013bd4848104" , "gdcm-JPEG-LossLessThoravision.dcm" }, + {"ddb7e67d119eb2ce14731cd9007e36cc" , "XA-MONO2-8-12x-catheter.dcm" }, + {"1041bae356da40d2113210ff2adef923" , "gdcm-MR-PHILIPS-16-Multi-Seq.dcm" }, + {"a3a6b3bf75ccdc91f82effc60d005688" , "PHILIPS_GDCM12xBug.dcm" }, + {"a247e2ca32279956079c9a87403bd157" , "MR_Philips_Intera_PrivateSequenceExplicitVR_in_SQ_2001_e05f_item_wrong_lgt_use_NOSHADOWSEQ.dcm" }, + {"48b19e53bffc8feab8671fd23c869028" , "D_CLUNIE_CT1_J2KI.dcm" }, + {"3f7cae9b920adb3ca4a96ace2c0c91d7" , "rle16sti.dcm" }, + {"f706f740496e445ee59141b15f3baeb4" , "3E768EB7.dcm" }, + {"b38c113fffa4925f6f06a928b357f6a1" , "D_CLUNIE_MR2_JPLY.dcm" }, + {"c3d3a218fcec778476090bce4c8b3201" , "SIEMENS_MAGNETOM-12-MONO2-FileSeq1.dcm" }, + {"882a7327bab05d88571dcf29f902adf3" , "SIEMENS_MAGNETOM-12-MONO2-FileSeq0.dcm" }, + {"7944f0f8eb06466099fe6cd792ae8bfa" , "MR_Philips_Intera_SwitchIndianess_noLgtSQItem_in_trueLgtSeq.dcm" }, + {"af193ff3143f299826d55e00696b3218" , "LEADTOOLS_FLOWERS-16-MONO2-Uncompressed.dcm" }, + {"b9b499634bdaff3be7710722f75d9b5d" , "D_CLUNIE_MR3_JPLY.dcm" }, + {"e8b529fbe615b4c540318695913d02e7" , "D_CLUNIE_VL2_RLE.dcm" }, + {"8393213bd2c340a8cbd639f45a6b497e" , "OsirixFake16BitsStoredFakeSpacing.dcm" }, + {"205a3ba253b61bf5ebb374523c366ccb" , "GE_RHAPSODE-16-MONO2-JPEG-Fragments.dcm" }, + {"c265bf6c3bf4417987ff81b92ca4ca6c" , "MR_SIEMENS_forceLoad29-1010_29-1020.dcm" }, + {"fa7da45d1a8eb16b092880ceff5a50e5" , "fffc0000UN.dcm" }, + {"796594769ee3570292de36fdb4509df1" , "LIBIDO-24-ACR_NEMA-Rectangle.dcm" }, + {"32b10fd4f13cfb4d74e1145f166e9dae" , "IM-0001-0066.CommandTag00.dcm" }, + {"619f8c1650962cddf7695e39f43e8c49" , "D_CLUNIE_NM1_JPLY.dcm" }, + {"205a3ba253b61bf5ebb374523c366ccb" , "D_CLUNIE_CT1_J2KR.dcm" }, + {"30a530ea4df623cbec31f752637e234b" , "TheralysGDCM120Bug.dcm" }, + {"3120b59e3635a912c6a60897f734b2ff" , "SIEMENS_MAGNETOM-12-MONO2-VRUN.dcm" }, + {"5bdb2335ceb2dac83c2248d6ff8e0a49" , "THERALYS-12-MONO2-Uncompressed-Even_Length_Tag.dcm" }, + {"30ff6655c5eb98ad34cd20836418a5a7" , "ALOKA_SSD-8-MONO2-RLE-SQ.dcm" }, + {"992e4ef2b01f9d79514d7ab22c354be9" , "GE_GENESIS-16-MONO2-WrongLengthItem.dcm" }, + {"d4669bd89971c1affd311c7d1d8b20c7" , "US-RGB-8-esopecho.dcm" }, + {"85124dd05ab0567aecaf896373f780da" , "D_CLUNIE_MR4_RLE.dcm" }, + {"07964ed19883cb96460d1407795f4306" , "D_CLUNIE_MR2_JPLL.dcm" }, + {"096547f2834609ae4dbc115169806fc4" , "SIEMENS_Sonata-16-MONO2-Value_Multiplicity.dcm" }, + {"af193ff3143f299826d55e00696b3218" , "LEADTOOLS_FLOWERS-16-MONO2-JpegLossless.dcm" }, + {"da7002947725a950c3226cd23aa8d718" , "CT-MONO2-16-ankle.dcm" }, + {"1a27a48d4efe2999b83bc89d3003d05c" , "LEADTOOLS_FLOWERS-8-PAL-RLE.dcm" }, + {"feb10d9a28e5166a3baf9ec6ef4f460a" , "simpleImageWithIcon.dcm" }, + {"aeb28d2cfb5376e2bb1ac4aac0b4807c" , "CR-MONO1-10-chest.dcm" }, + {"205a3ba253b61bf5ebb374523c366ccb" , "D_CLUNIE_CT1_RLE.dcm" }, + {"4d469f85f51b3b81bdf38ebba23a68e7" , "D_CLUNIE_NM1_JPLL.dcm" }, + {"8ffdae8852e9388369935d65b8afa408" , "MR_GE_with_Private_Compressed_Icon_0009_1110.dcm" }, + {"abe1950da247d18196fe5bea54cb26f1" , "NM-MONO2-16-13x-heart.dcm" }, + {"6bd67bbd6e3e65808db8598fe0913f86" , "US-IRAD-NoPreambleStartWith0003.dcm" }, + {"99672e03104c9176595bc0002cd8edf8" , "MR-MONO2-16-head.dcm" }, + {"1a27a48d4efe2999b83bc89d3003d05c" , "LEADTOOLS_FLOWERS-8-PAL-Uncompressed.dcm" }, + {"af8491953e762c12feb93a80a1575edf" , "MAROTECH_CT_JP2Lossy.dcm" }, + {"932281859be22ffae33a2669b34cc2e6" , "05115014-mr-siemens-avanto-syngo-with-palette-icone.dcm" }, + {"fb5402472ee00639ef8dc1b09692c299" , "US-PAL-8-10x-echo.dcm" }, + {"038acb53133733a9f2c54528b8029511" , "MR-SIEMENS-DICOM-WithOverlays.dcm" }, + {"890d0a5afdbf77398d857b523f86e83a" , "D_CLUNIE_MR1_JPLL.dcm" }, + {"205a3ba253b61bf5ebb374523c366ccb" , "D_CLUNIE_CT1_JPLL.dcm" }, + {"7e971371b523cc1db53f3fc7f2ac5441" , "AMIInvalidPrivateDefinedLengthSQasUN.dcm" }, + {"7944f0f8eb06466099fe6cd792ae8bfa" , "ExplicitVRforPublicElementsImplicitVRforShadowElements.dcm" }, + {"3443eba48f11dd9aadb4632c8c896b39" , "PHILIPS_Gyroscan-12-Jpeg_Extended_Process_2_4.dcm" }, + {"b72e483ad977e18b8016c7cc916c4bbd" , "D_CLUNIE_SC1_JPLY.dcm" }, + {"582df1a47c5992cc4f37496dab8c5130" , "gdcm-MR-PHILIPS-16-NonSquarePixels.dcm" }, + {"8a5d13f6c85b2eebc1c02432d729cd45" , "SIEMENS-MR-RGB-16Bits.dcm" }, + {"aacd6f6257e068cf53cdec5c7e172513" , "US-IRAD-NoPreambleStartWith0005.dcm" }, + {"6a9ecd676ce47b0fda111a804b58b054" , "PICKER-16-MONO2-Nested_icon.dcm" }, + {"9b720fd0aa079bc2f3f9545bd0e207c6" , "gdcm-JPEG-Extended.dcm" }, + {"c790d0a462907135c1991f10a4846f98" , "D_CLUNIE_US1_RLE.dcm" }, + {"4689c053642dcee7a2a9d0475c1b6528" , "D_CLUNIE_RG2_JPLY.dcm" }, + {"b3b8a60e7b7b20c029eec1d5006e2b9c" , "PHILIPS_Brilliance_ExtraBytesInOverlay.dcm" }, + {"91533007e5e07353012dea33149d920f" , "MR_ELSCINT1_00e1_1042_SQ_feff_00e0_Item.dcm" }, + {"c8902cc14f285f2687866f60e45c7d86" , "TG18-CH-2k-01.dcm" }, + {"af193ff3143f299826d55e00696b3218" , "LEADTOOLS_FLOWERS-16-MONO2-RLE.dcm" }, + {"27daf49ec13f58db1d800fc58378852e" , "OT-PAL-8-face.dcm" }, + {"07fef244d4e14358d453c144770b2a55" , "LEADTOOLS_FLOWERS-24-RGB-JpegLossy.dcm" }, + {"ad96e04c3c50d463cccdfca68b49b071" , "SIEMENS_MAGNETOM-12-MONO2-Uncompressed.dcm" }, + {"620f0b67a91f7f74151bc5be745b7110" , "GDCMJ2K_TextGBR.dcm" }, + {"d1f5dfac9c3213f548df6a1f9e86acd0" , "MR16BitsAllocated_8BitsStored.dcm" }, + {"dab7df42898362213062eb0d493eb38e" , "GE_GENESIS-16-MONO2-Uncompressed-UnusualVR.dcm" }, + {"205a3ba253b61bf5ebb374523c366ccb" , "D_CLUNIE_CT1_JLSL.dcm" }, + {"719505e71eafd643fa2e114acc83496f" , "ELSCINT1_JP2vsJ2K.dcm" }, + {"7132fec8839d9c8b26cba4a4f17000da" , "D_CLUNIE_XA1_JPLL.dcm" }, + {"cdf5908902fb63e321b224fae86a4128" , "SIEMENS_Sonata-12-MONO2-SQ.dcm" }, + {"bc1774acbf5c025aa3b57184213cc98c" , "JPEGDefinedLengthSequenceOfFragments.dcm" }, + {"e9faa2ce59db8563d7abe50432f91351" , "PHILIPS_GDCM12xBug2.dcm" }, + {"620f0b67a91f7f74151bc5be745b7110" , "ITK_GDCM124_MultiframeSecondaryCaptureInvalid.dcm" }, + {"52d0b90aa78a20cbff6b0beb3bd2c2b3" , "D_CLUNIE_RG2_JPLL.dcm" }, + {"50dd1ae0bf918a9144b50229fa04f8e0" , "FUJI-10-MONO1-ACR_NEMA_2.dcm" }, + {"d7e55bf3c6eb7a627823b532bcac7e16" , "D_CLUNIE_MR1_JPLY.dcm" }, + {"7132fec8839d9c8b26cba4a4f17000da" , "D_CLUNIE_XA1_RLE.dcm" }, + {"ddb5ac3f32badb154ce9a8a18c09c2c0" , "BugGDCM2_UndefItemWrongVL.dcm" }, + {"7f2638cea652bf3452ada158d2ea67c4" , "SIEMENS_MAGNETOM-12-ACR_NEMA_2-Modern.dcm" }, + {"477d801b27ef3cb21a8685cedbc9b12e" , "JDDICOM_Sample2.dcm" }, + {"cae77b420f407118f288c14eeb81e11f" , "TOSHIBA_MRT150-16-MONO2-ACR_NEMA_2.dcm" }, + {"524014ef866b31e3fd2e33a6148d31bb" , "DCMTK_JPEGExt_12Bits.dcm" }, + {"84ea2f46ad98332a06875da922709007" , "US-MONO2-8-8x-execho.dcm" }, + {"19d6f17c8a0b2cd04049828dcb304046" , "UnexpectedSequenceDelimiterInFixedLengthSequence.dcm" }, + {"bee28068ae9edef69fef792583b3e20f" , "ACUSON-24-YBR_FULL-RLE-b.dcm" }, + {"b171f7581c9cf15b2d32cfd62e9b6038" , "gdcm-US-ALOKA-16.dcm" }, + {"80be78c9365f6a1604191dd703c84ac5" , "DX_J2K_0Padding.dcm" }, + {"a9a72d44b888fb4f1f727af88109cfb3" , "D_CLUNIE_CT2_RLE.dcm" }, + {"151376fcac2fbd55c3b5c5a155e16d26" , "D_CLUNIE_RG1_JPLL.dcm" }, + {"e0a3fd5917c5a13a16981e1d0346af4d" , "D_CLUNIE_VL3_RLE.dcm" }, + {"28ea47a62e1f2ca9d7dcd10ef868701d" , "NM_Kakadu44_SOTmarkerincons.dcm" }, + {"e95cec3c8078cea91b287e45d751cf78" , "CT-SIEMENS-Icone-With-PaletteColor.dcm" }, + {"eacd1cabeaf78554804ca627344cba91" , "GE_DLX-8-MONO2-PrivateSyntax.dcm" }, + {"8f40712ff8e4a7691be144d884546a17" , "CT_16b_signed-UsedBits13.dcm" }, + {"da9fb19d564fa01e4633df5c105f5a58" , "D_CLUNIE_RG3_JPLY.dcm" }, + {"6510f44ff1dd8daf9b49100fd2c81d85" , "DX_GE_FALCON_SNOWY-VOI.dcm" }, + {"5a15bd50c589c9611636dc7813493c03" , "PrivateGEImplicitVRBigEndianTransferSyntax16Bits.dcm" }, + {"4948235091edc01603344f79a29835e1" , "CT-MONO2-16-brain.dcm" }, + {"c2de60330cda14759a117b937a7e5a95" , "D_CLUNIE_VL4_RLE.dcm" }, + {"db07030ff68debba674a6ca5c3e6eeb3" , "D_CLUNIE_MR3_RLE.dcm" }, + {"72f55d5cf022e983783185195b77d0e6" , "undefined_length_un_vr.dcm" }, + {"a8e2e35044384f31afc1dcf9163154ff" , "CT-MONO2-16-ort.dcm" }, + {"0fefcf91a55062f1cb20945b3f726eda" , "05148044-mr-siemens-avanto-syngo.dcm" }, + {"5d6aaab5766479ec6e27de4eaa4a6438" , "GE_LOGIQBook-8-RGB-HugePreview.dcm" }, + {"acad4e43da617035315bcddc4bbb96bd" , "RadBWLossLess.dcm" }, + {"b69e23b6479de4d9c3b4ed51aa748f73" , "KODAK-12-MONO1-Odd_Terminated_Sequence.dcm" }, + {"e8458a5483e72cced4d46f93eed1699e" , "CT-MONO2-16-chest.dcm" }, + {"728a698e308f7863ba3d103b80dffc45" , "PhilipsInteraSeqTermInvLen.dcm" }, + {"35144f65c704edf2d69abc40405c3ea7" , "D_CLUNIE_MR4_JPLY.dcm" }, + {"904b38f362b86f626ea7d89eed455709" , "D_CLUNIE_RG3_JPLL.dcm" }, + {"707e26b0fa27f670c35ca5cc2bf3eda2" , "MR_Philips-Intera_BreaksNOSHADOW.dcm" }, + {"04b97df84da7a126be30993cf9cff942" , "GE_CT_With_Private_compressed-icon.dcm" }, + {"04cb0299587f38ba369e1fdcbf07dc25" , "D_CLUNIE_CT1_JLSN.dcm" }, + {"3120b59e3635a912c6a60897f734b2ff" , "SIEMENS_MAGNETOM-12-MONO2-GDCM12-VRUN.dcm" }, + {"cee47e57f6b1aaace74bb813e33a74eb" , "00191113.dcm" }, + {"99ba02caa6813cafd254f97fb8377f60" , "MARCONI_MxTWin-12-MONO2-JpegLossless-ZeroLengthSQ.dcm" }, + {"0a9449186ab107120640910a58a38ec4" , "SignedShortLosslessBug.dcm" }, + {"2b306840879792f3509e1c1ccedee81d" , "GE_DLX-8-MONO2-Multiframe.dcm" }, + {"fde7dc022ec854a98ffdc2190ceef424" , "PHILIPS_Gyroscan-12-MONO2-Jpeg_Lossless.dcm" }, + {"f4b5fc5cc1440b865f1a99b85b170ecd" , "LJPEG_BuginGDCM12.dcm" }, + {"ba2717c0d839213e788a74cccf37f1d4" , "SIEMENS_MAGNETOM-12-MONO2-FileSeq3.dcm" }, + {"904b38f362b86f626ea7d89eed455709" , "D_CLUNIE_RG3_RLE.dcm" }, + {"5e51e64ee21c2f643c13257e054c2990" , "CT-SIEMENS-MissingPixelDataInIconSQ.dcm" }, + {"07964ed19883cb96460d1407795f4306" , "MR-MONO2-12-shoulder.dcm" }, + {"0b818ac3983d76cfdc535a46058a1a53" , "LEADTOOLS_FLOWERS-24-RGB-Uncompressed.dcm" }, + {"7f7aaee92f20ffcd64bebf8ce105bf5d" , "PICKER-16-MONO2-No_DicomV3_Preamble.dcm" }, + {"fde3b9c4853c597383fab1050b491202" , "SIEMENS_MOSAIC_12BitsStored-16BitsJPEG.dcm" }, + {"ba0654f3e7aae75bca8fc24705ddb78a" , "CT-MONO2-8-abdo.dcm" }, + {"db07030ff68debba674a6ca5c3e6eeb3" , "D_CLUNIE_MR3_JPLL.dcm" }, + {"03f25fb3e6e8ae53b9565553e2026a66" , "D_CLUNIE_VL6_RLE.dcm" }, + {"af193ff3143f299826d55e00696b3218" , "LEADTOOLS_FLOWERS-8-MONO2-RLE.dcm" }, + {"d46afca30969faa05583e87b0f6e5211" , "PHILIPS_Gyroscan-8-MONO2-Odd_Sequence.dcm" }, + {"5885ade0feaaf967f5a1c22724c10d02" , "SIEMENS-12-Jpeg_Process_2_4-Lossy-a.dcm" }, + {"13758e32fe34c17b897efcbd26e7e03b" , "gdcm-JPEG-LossLess3a.dcm" }, + {"1e61c6d50ae3ef3ac0550277f166bd1c" , "D_CLUNIE_XA1_JPLY.dcm" }, + {"151376fcac2fbd55c3b5c5a155e16d26" , "D_CLUNIE_RG1_RLE.dcm" }, + {"e77b93eb953f2a21fa75d257da0514fb" , "US-RGB-8-epicard.dcm" }, + {"a101ddd933114bcc0145d047d74f41c9" , "GE_MR_0025xx1bProtocolDataBlock.dcm" }, + {"b9f48f54e75b7f1994cfe1a7152d9ab5" , "rle16loo.dcm" }, + {"cc61470afd2b80014749abbb5bd9109d" , "DMCPACS_ExplicitImplicit_BogusIOP.dcm" }, + {"a9a72d44b888fb4f1f727af88109cfb3" , "D_CLUNIE_CT2_JPLL.dcm" }, + {"477d801b27ef3cb21a8685cedbc9b12e" , "JDDICOM_Sample2-dcmdjpeg.dcm" }, + {"7944f0f8eb06466099fe6cd792ae8bfa" , "MR_Philips_Intera_No_PrivateSequenceImplicitVR.dcm" }, + {"323c2919ea590363dd6eb4105a2566a7" , "KODAK_CompressedIcon.dcm" }, + {"486199008daf27f167efee9469fffd52" , "ACUSON-24-YBR_FULL-RLE.dcm" }, + {"07964ed19883cb96460d1407795f4306" , "D_CLUNIE_MR2_RLE.dcm" }, + {"b53c440c32a7bd20d24cc1997bd7c9e6" , "JPEG_LossyYBR.dcm" }, + {"23bf148e163ea7d3f1dbadfc590618fe" , "012345.002.050.dcm" }, + {"52d0b90aa78a20cbff6b0beb3bd2c2b3" , "D_CLUNIE_RG2_RLE.dcm" }, + {"e44869a1044b611e08a9f1396432a44b" , "MR_Philips_Intera_PrivateSequenceImplicitVR.dcm" }, + {"f92d6349e1d80bbdba34a9e1b84eb737" , "SIEMENS_ImageLocationUN.dcm" }, + {"7944f0f8eb06466099fe6cd792ae8bfa" , "PHILIPS_Intera-16-MONO2-Uncompress.dcm" }, + {"0e82ac528c72a2dd69fa1b52e5370d82" , "MR-SIEMENS-DICOM-WithOverlays-extracted-overlays.dcm" }, + {"0b818ac3983d76cfdc535a46058a1a53" , "LEADTOOLS_FLOWERS-24-RGB-JpegLossless.dcm" }, + {"91b4da2ca9fd378ca404580c84c62984" , "US-GE-4AICL142.dcm" }, + {"2ff486489d600e0ab5f8c829960c516f" , "D_CLUNIE_SC1_RLE.dcm" }, + {"85124dd05ab0567aecaf896373f780da" , "D_CLUNIE_MR4_JPLL.dcm" }, + {"ece67fa0c8a99f8147b26081252cd0a5" , "MR-Brucker-CineTagging-NonSquarePixels.dcm" }, + {"bdf48b10871ac0b3c14587eaba9ca998" , "MR-MONO2-8-16x-heart.dcm" }, + {"0c65a403a0a24957e523bb29e84c31ef" , "LEADTOOLS_FLOWERS-8-MONO2-JpegLossy.dcm" }, + {"f92a60ad3cbc2783db57cac5f800a9c0" , "GE_DLX-8-MONO2-Multiframe-Jpeg_Lossless.dcm" }, + {"4d469f85f51b3b81bdf38ebba23a68e7" , "D_CLUNIE_NM1_RLE.dcm" }, + {"20e2f6cc2b60ae26adfdd3b3ee0e1915" , "D_CLUNIE_VL1_RLE.dcm" }, + {"84462b24809f4e9d151c7c27004f7922" , "SIEMENS_MAGNETOM-12-MONO2-FileSeq2.dcm" }, + {"620f0b67a91f7f74151bc5be745b7110" , "DermaColorLossLess.dcm" }, + {"72e203ca5756f4491d84d8240c82a59b" , "OT-MONO2-8-a7.dcm" }, + {"890d0a5afdbf77398d857b523f86e83a" , "D_CLUNIE_MR1_RLE.dcm" }, + {"af193ff3143f299826d55e00696b3218" , "LEADTOOLS_FLOWERS-8-MONO2-Uncompressed.dcm" }, + {"cee47e57f6b1aaace74bb813e33a74eb" , "00191113.dcm" }, + {"07b6f4e2fba920d28e2f29dbb037b640" , "TOSHIBA_J2K_SIZ1_PixRep0.dcm" }, + {"93f60acbb450c62992a1db09a6c19c05" , "TOSHIBA_J2K_OpenJPEGv2Regression.dcm" }, + {"fa02ad71bdf3e6970e18fc9a9df03a2d" , "TOSHIBA_J2K_SIZ0_PixRep1.dcm" }, + {"3475cb96e0308cb84502be1c1531b588" , "NM-PAL-16-PixRep1.dcm" }, + {"2ec6d7c60d6786665cff2b7a31aaeedf" , "MEDILABInvalidCP246_EVRLESQasUN.dcm" }, + {"54b1cec013420f771142ca6ec6c274a4" , "JPEGInvalidSecondFrag.dcm" }, + + // sentinel + { 0, 0 } +}; + +namespace gdcm +{ +int TestIconImageGenerate2(const char *subdir, const char* filename, bool verbose = false) +{ + ImageReader reader; + reader.SetFileName( filename ); + if ( !reader.Read() ) + { + const FileMetaInformation &header = reader.GetFile().GetHeader(); + MediaStorage ms = header.GetMediaStorage(); + bool isImage = MediaStorage::IsImage( ms ); + bool pixeldata = reader.GetFile().GetDataSet().FindDataElement( Tag(0x7fe0,0x0010) ); + if( isImage && pixeldata ) + { + std::cerr << "Failed to read: " << filename << std::endl; + return 1; + } + else + { + // not an image give up... + std::cerr << "Problem with: " << filename << " but that's ok" << std::endl; + return 0; + } + } + + // Create directory first: + std::string tmpdir = Testing::GetTempDirectory( subdir ); + if( !System::FileIsDirectory( tmpdir.c_str() ) ) + { + System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + std::string outfilename = Testing::GetTempFilename( filename, subdir ); + + IconImageGenerator iig; + iig.SetPixmap( reader.GetImage() ); + iig.AutoPixelMinMax(true); + const unsigned int idims[2] = { 64, 64 }; + //const unsigned int idims[2] = { 600,430 }; + iig.SetOutputDimensions( idims ); + bool b = iig.Generate(); + + gdcm::Filename fn( filename ); + const char *name = fn.GetName(); + + unsigned int i = 0; + const char *p = iconimagearray2[i][1]; + while( p != 0 ) + { + if( strcmp( name, p ) == 0 ) + { + break; + } + ++i; + p = iconimagearray2[i][1]; + } + const char *refmd5 = iconimagearray2[i][0]; + + if( b ) + { + const gdcm::IconImage &icon = iig.GetIconImage(); + if( verbose ) icon.Print( std::cout ); + unsigned long len = icon.GetBufferLength(); + std::vector< char > vbuffer; + vbuffer.resize( len ); + char *buffer = &vbuffer[0]; + bool res2 = icon.GetBuffer(buffer); + if( !res2 ) + { + std::cerr << "res2 failure:" << filename << std::endl; + return 1; + } + char digest[33]; + gdcm::Testing::ComputeMD5(buffer, len, digest); + Image & img = reader.GetImage(); + img.SetIconImage( iig.GetIconImage() ); + + ImageWriter writer; + writer.SetFileName( outfilename.c_str() ); +#if 1 + writer.SetImage( img ); +#else + Image &ii = writer.GetImage(); + (Bitmap&)ii = iig.GetIconImage(); +#endif + if( !writer.Write() ) + { + std::cerr << "Failed to write: " << outfilename << std::endl; + return 1; + } + + if( verbose ) + { + std::cout << "success: " << outfilename << std::endl; + std::cout << "ref=" << refmd5 << std::endl; + std::cout << "md5=" << digest << std::endl; + } + + if( !refmd5 ) + { + std::cerr << " missing md5= {\"" << digest << "\" , \"" << name << "\" }," << std::endl; + return 1; + } + if( strcmp( refmd5, digest) ) + { + std::cerr << "Problem with : " << name << " " << refmd5 << " vs " << digest << std::endl; + return 1; + } + + } + else + { + assert( refmd5 == 0 ); + std::cerr << "Could not generate Icon for: " << filename << std::endl; + return 1; + } + + return 0; +} +} + +int TestIconImageGenerator2(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return gdcm::TestIconImageGenerate2(argv[0],filename, true); + } + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + gdcm::Trace::ErrorOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += gdcm::TestIconImageGenerate2(argv[0], filename ); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestIconImageGenerator3.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestIconImageGenerator3.cxx new file mode 100644 index 0000000..e141ae9 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestIconImageGenerator3.cxx @@ -0,0 +1,361 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmImageReader.h" +#include "gdcmImageWriter.h" +#include "gdcmFilename.h" +#include "gdcmSystem.h" +#include "gdcmFileMetaInformation.h" +#include "gdcmTesting.h" +#include "gdcmByteSwap.h" +#include "gdcmIconImageGenerator.h" + +static const char * const iconimagearray3[][2] = { + {"18de6726bc64732057fb57ffa6f63482" , "SIEMENS_SOMATOM-12-ACR_NEMA-ZeroLengthUs.acr" }, + {"e751b44ccfa55354e08ba04fade91687" , "gdcm-MR-SIEMENS-16-2.acr" }, + {"a7ff57ec105e45b72d91ac750953befc" , "test.acr" }, + {"464cc3218d282f534326f2323264f8ca" , "MR-MONO2-12-an2.acr" }, + {"e23711964e5606b7cf8a9bf194e46a27" , "CT-MONO2-12-lomb-an2.acr" }, + {"fc5db4e2e7fca8445342b83799ff16d8" , "LIBIDO-8-ACR_NEMA-Lena_128_128.acr" }, + {"50ab781df5647feb681c6c24a1245d0d" , "gdcm-ACR-LibIDO.acr" }, + {"ce338fe6899778aacfc28414f2d9498b" , "libido1.0-vol.acr" }, + {"7acad6aa0274edfc797492128c2dd2bf" , "SIEMENS_CSA2.dcm" }, + {"231db66c0b1a60cab9e8e879711ebc16" , "gdcm-JPEG-LossLessThoravision.dcm" }, + {"353a62510cef13ce252f5e3a7ece54dc" , "XA-MONO2-8-12x-catheter.dcm" }, + {"b992b65f8beed6adc2224541be339d68" , "gdcm-MR-PHILIPS-16-Multi-Seq.dcm" }, + {"a9b91f5b18b1d7078ce597ec611a2c43" , "PHILIPS_GDCM12xBug.dcm" }, + {"a0b26e46dc8920167cd6b9b5ed57d8df" , "MR_Philips_Intera_PrivateSequenceExplicitVR_in_SQ_2001_e05f_item_wrong_lgt_use_NOSHADOWSEQ.dcm" }, + {"eff839f187f2dfa07204b6550a96d4b6" , "D_CLUNIE_CT1_J2KI.dcm" }, + {"4f94be538667ad8d39abf42ee604bf7d" , "rle16sti.dcm" }, + {"7acd654cb0176b7b6f1982245593e8e6" , "3E768EB7.dcm" }, + {"6fe22e9a0983a07c5b1dde43373c36f3" , "D_CLUNIE_MR2_JPLY.dcm" }, + {"f17269f3d2447ed0b523b41a98b03129" , "SIEMENS_MAGNETOM-12-MONO2-FileSeq1.dcm" }, + {"311524ab5c9cb14812256c561c78e573" , "SIEMENS_MAGNETOM-12-MONO2-FileSeq0.dcm" }, + {"35619ea28ae211558d526e63429d5cbb" , "MR_Philips_Intera_SwitchIndianess_noLgtSQItem_in_trueLgtSeq.dcm" }, + {"a189258582a49855ae002d381016d02f" , "LEADTOOLS_FLOWERS-16-MONO2-Uncompressed.dcm" }, + {"b9291915007d8fae5c2a67a691c33236" , "D_CLUNIE_MR3_JPLY.dcm" }, + {"e2100ad66e70220df75ee60e9f69acdd" , "D_CLUNIE_VL2_RLE.dcm" }, + {"985dd349809ef7d63feeb511a63b05d1" , "OsirixFake16BitsStoredFakeSpacing.dcm" }, + {"046896d4baee6361e58217bd0a046162" , "GE_RHAPSODE-16-MONO2-JPEG-Fragments.dcm" }, + {"54307dbe02cab5ee23efa8360eb0cbd5" , "MR_SIEMENS_forceLoad29-1010_29-1020.dcm" }, + {"7e8bfa2560d883b45a0f868a81daac4d" , "fffc0000UN.dcm" }, + {"00f59e7e071f7fdf7d2e700df06a1d6b" , "LIBIDO-24-ACR_NEMA-Rectangle.dcm" }, + {"c1d31936337a3c65bba3edf67466a139" , "IM-0001-0066.CommandTag00.dcm" }, + {"6d95a1855031ac5401ec2c8ba7ff8b18" , "D_CLUNIE_NM1_JPLY.dcm" }, + {"046896d4baee6361e58217bd0a046162" , "D_CLUNIE_CT1_J2KR.dcm" }, + {"a439396c24ce353e108bd0308e8a80e2" , "TheralysGDCM120Bug.dcm" }, + {"e5155757353de1ad5c2b68c88fd34901" , "SIEMENS_MAGNETOM-12-MONO2-VRUN.dcm" }, + {"338d45d1ee3ec0202cdfa637c491669a" , "THERALYS-12-MONO2-Uncompressed-Even_Length_Tag.dcm" }, + {"5f90ef6a0621c658cfd2ae1f2bba351e" , "ALOKA_SSD-8-MONO2-RLE-SQ.dcm" }, + {"c881ef5c9a6a643ac7e890279ffc010f" , "GE_GENESIS-16-MONO2-WrongLengthItem.dcm" }, + {"13d97ddbcff7e14a89a6e5c337611881" , "US-RGB-8-esopecho.dcm" }, + {"0464a1b7160b097ea33f25865cce8fc9" , "D_CLUNIE_MR4_RLE.dcm" }, + {"3703d1695f0c02fa7a5cbe7142c8fc6f" , "D_CLUNIE_MR2_JPLL.dcm" }, + {"f0b59feaa0499a68038b627f2df71d93" , "SIEMENS_Sonata-16-MONO2-Value_Multiplicity.dcm" }, + {"a189258582a49855ae002d381016d02f" , "LEADTOOLS_FLOWERS-16-MONO2-JpegLossless.dcm" }, + {"dcce1e8c7b5cdc15d315807b4ec2d34b" , "CT-MONO2-16-ankle.dcm" }, + {"75c3cb93e002c788acc7eff4a93e2b5b" , "TOSHIBA_J2K_SIZ1_PixRep0.dcm" }, + {"4e8c0f3b4154f54ae04756d61fb1c2f5" , "LEADTOOLS_FLOWERS-8-PAL-RLE.dcm" }, + {"fc5db4e2e7fca8445342b83799ff16d8" , "simpleImageWithIcon.dcm" }, + {"1c582b9b521c398ed55776bcd615af3e" , "CR-MONO1-10-chest.dcm" }, + {"046896d4baee6361e58217bd0a046162" , "D_CLUNIE_CT1_RLE.dcm" }, + {"f00d34662aeb08d14bcaf230053bfd5f" , "D_CLUNIE_NM1_JPLL.dcm" }, + {"39faf30ee66e8c70dd2e772fcdbb1078" , "MR_GE_with_Private_Compressed_Icon_0009_1110.dcm" }, + {"ce338fe6899778aacfc28414f2d9498b" , "NM-MONO2-16-13x-heart.dcm" }, + {"5a4101fb01068d1b48afcacc9bca9f7e" , "US-IRAD-NoPreambleStartWith0003.dcm" }, + {"3c18da99b3d3d53399d622aabdd96b64" , "MR-MONO2-16-head.dcm" }, + {"4e8c0f3b4154f54ae04756d61fb1c2f5" , "LEADTOOLS_FLOWERS-8-PAL-Uncompressed.dcm" }, + {"443c20bd84b91d30037ad1da84568c6e" , "MAROTECH_CT_JP2Lossy.dcm" }, + {"488e407541a6c353f0540049ba36d61c" , "05115014-mr-siemens-avanto-syngo-with-palette-icone.dcm" }, + {"50057b97e7c585ba31144867cd40c363" , "US-PAL-8-10x-echo.dcm" }, + {"e189b6b3a44a8d929f654105f9842707" , "MR-SIEMENS-DICOM-WithOverlays.dcm" }, + {"139f2ba3c6f578f883125d090163e730" , "D_CLUNIE_MR1_JPLL.dcm" }, + {"046896d4baee6361e58217bd0a046162" , "D_CLUNIE_CT1_JPLL.dcm" }, + {"bbc89a7b6e41d668f22b6e612cfb13e7" , "AMIInvalidPrivateDefinedLengthSQasUN.dcm" }, + {"35619ea28ae211558d526e63429d5cbb" , "ExplicitVRforPublicElementsImplicitVRforShadowElements.dcm" }, + {"8b2eca7c4d23a79a9e6d9437bff66d67" , "PHILIPS_Gyroscan-12-Jpeg_Extended_Process_2_4.dcm" }, + {"4ef7021ed6522a730693574a37759940" , "D_CLUNIE_SC1_JPLY.dcm" }, + {"ce338fe6899778aacfc28414f2d9498b" , "gdcm-MR-PHILIPS-16-NonSquarePixels.dcm" }, + {"b92f9dcf1acd6dd998539d22a5296f74" , "SIEMENS-MR-RGB-16Bits.dcm" }, + {"07c92897d0cbd052060f8a9d13a6386a" , "US-IRAD-NoPreambleStartWith0005.dcm" }, + {"64b228a9c05e2f1b4a6371abf1ac7e21" , "PICKER-16-MONO2-Nested_icon.dcm" }, + {"41d6ffef9d2edbad51c94a8d476bb1ab" , "gdcm-JPEG-Extended.dcm" }, + {"5d8f3a1415c53f2b8b6ea459b4f3f6c1" , "D_CLUNIE_US1_RLE.dcm" }, + {"d0dcc34bad0aa031269d3101fa044e4b" , "D_CLUNIE_RG2_JPLY.dcm" }, + {"4a56065c6ab80bc0a32b39a143e58d5c" , "PHILIPS_Brilliance_ExtraBytesInOverlay.dcm" }, + {"2888e58bfe4d11b2671f2cd6a35f9b7c" , "MR_ELSCINT1_00e1_1042_SQ_feff_00e0_Item.dcm" }, + {"00d2f91bbf1f1d5c248f98220f85a860" , "TG18-CH-2k-01.dcm" }, + {"a189258582a49855ae002d381016d02f" , "LEADTOOLS_FLOWERS-16-MONO2-RLE.dcm" }, + {"703d03c5fb65c9493775c7ed6a9aa001" , "OT-PAL-8-face.dcm" }, + {"12919f48891b07e74651efd5a2a52676" , "LEADTOOLS_FLOWERS-24-RGB-JpegLossy.dcm" }, + {"94e0346dc7594b042c6e67a0f8ebfa71" , "SIEMENS_MAGNETOM-12-MONO2-Uncompressed.dcm" }, + {"06148d96de1833da4518b6d97fdd4165" , "GDCMJ2K_TextGBR.dcm" }, + {"59f3e40cbdd708b43dd818a953bd5ca0" , "MR16BitsAllocated_8BitsStored.dcm" }, + {"fe4ee9d2fc8f068c7e5b61e8dc90811d" , "GE_GENESIS-16-MONO2-Uncompressed-UnusualVR.dcm" }, + {"046896d4baee6361e58217bd0a046162" , "D_CLUNIE_CT1_JLSL.dcm" }, + {"9f04eeafdcd85d84cc6f8edad761e3a1" , "ELSCINT1_JP2vsJ2K.dcm" }, + {"531bfd1059c6396e9da4c9a4f5436e86" , "D_CLUNIE_XA1_JPLL.dcm" }, + {"12ea2d93daec9fda8f26666dbaf21c30" , "SIEMENS_Sonata-12-MONO2-SQ.dcm" }, + {"acf0d5ea13eb09415ffe3ec2d0800590" , "JPEGDefinedLengthSequenceOfFragments.dcm" }, + {"6b9e6ee648acb3ca92814bc6642d0b96" , "PHILIPS_GDCM12xBug2.dcm" }, + {"ce338fe6899778aacfc28414f2d9498b" , "ITK_GDCM124_MultiframeSecondaryCaptureInvalid.dcm" }, + {"941378c3e000b34264342b1d46ce6dce" , "D_CLUNIE_RG2_JPLL.dcm" }, + {"9efc87377ac56dd01476046bbbd5bf7b" , "FUJI-10-MONO1-ACR_NEMA_2.dcm" }, + {"99b4254ecb0b4075b8005b775b02bea1" , "D_CLUNIE_MR1_JPLY.dcm" }, + {"531bfd1059c6396e9da4c9a4f5436e86" , "D_CLUNIE_XA1_RLE.dcm" }, + {"8058ebaf622a0108d12a387c75de5aae" , "BugGDCM2_UndefItemWrongVL.dcm" }, + {"e751b44ccfa55354e08ba04fade91687" , "SIEMENS_MAGNETOM-12-ACR_NEMA_2-Modern.dcm" }, + {"c860f1795d0be70b310f5b653b34f06f" , "JDDICOM_Sample2.dcm" }, + {"5fcd3432874ea0f3cbc59a317534a0b0" , "TOSHIBA_MRT150-16-MONO2-ACR_NEMA_2.dcm" }, + {"ce338fe6899778aacfc28414f2d9498b" , "DCMTK_JPEGExt_12Bits.dcm" }, + {"7abf9227edf8f7106198b320c5daa538" , "US-MONO2-8-8x-execho.dcm" }, + {"16fff764b95a60d83e4b6781da292cea" , "UnexpectedSequenceDelimiterInFixedLengthSequence.dcm" }, + {"d600407a5f79393f294518be3bba7fed" , "ACUSON-24-YBR_FULL-RLE-b.dcm" }, + {"eb1c07547d036c3f778700cfef1ad24c" , "gdcm-US-ALOKA-16.dcm" }, + {"9805da917d916632cf3a22b6b9140bce" , "DX_J2K_0Padding.dcm" }, + {"4d6a3590ae425105315a0995f8a7da41" , "D_CLUNIE_CT2_RLE.dcm" }, + {"f1b14732b392da7ea5fba9b47225945c" , "D_CLUNIE_RG1_JPLL.dcm" }, + {"86362d24addeeaaa8b1b4e485ff49ea7" , "D_CLUNIE_VL3_RLE.dcm" }, + {"5d590fa042089bbd62f771e403ad3068" , "NM_Kakadu44_SOTmarkerincons.dcm" }, + {"790f684146906a7f0b9d8c3838066579" , "CT-SIEMENS-Icone-With-PaletteColor.dcm" }, + {"336e557af65d34ae7cb5dcc18582b12b" , "GE_DLX-8-MONO2-PrivateSyntax.dcm" }, + {"848ee1315da8c58064a685e70378dae5" , "CT_16b_signed-UsedBits13.dcm" }, + {"29db994be059e339ab881eb760878a54" , "D_CLUNIE_RG3_JPLY.dcm" }, + {"d1bd49bdf8ce55652f7802f8f8820f97" , "DX_GE_FALCON_SNOWY-VOI.dcm" }, + {"7dcb5cdba4bfc242dbcc0d275ad14970" , "PrivateGEImplicitVRBigEndianTransferSyntax16Bits.dcm" }, + {"d66fddd6bc26af655f500cd37de3b135" , "CT-MONO2-16-brain.dcm" }, + {"351d2c3befec588fe7798ae0884908e7" , "D_CLUNIE_VL4_RLE.dcm" }, + {"97e8c927ca201a2f932b5b3ecc6453e5" , "D_CLUNIE_MR3_RLE.dcm" }, + {"bbb1be6461a9c8b1a0fd507b5c19ec20" , "undefined_length_un_vr.dcm" }, + {"ae8fe4406652ca3e6b93d2ade029d94e" , "CT-MONO2-16-ort.dcm" }, + {"ab976b85e44c2332d826067520f6c2e6" , "05148044-mr-siemens-avanto-syngo.dcm" }, + {"8a9c001007c43fff520fada2b75e1e72" , "GE_LOGIQBook-8-RGB-HugePreview.dcm" }, + {"3808ac31fbf6ede5d0a1ca47ff604f8d" , "RadBWLossLess.dcm" }, + {"0ceae99a40ae6ee2ad5cf1fa06a86820" , "KODAK-12-MONO1-Odd_Terminated_Sequence.dcm" }, + {"e8dd9e61c1eb37c4ab54003ef9fd2842" , "CT-MONO2-16-chest.dcm" }, + {"63808ab2b6faa36b6914e01907358eb7" , "PhilipsInteraSeqTermInvLen.dcm" }, + {"3a1f7960887aa18084a6f7347926c8b5" , "D_CLUNIE_MR4_JPLY.dcm" }, + {"91c2703f4a5dec2d780539c29b450d47" , "D_CLUNIE_RG3_JPLL.dcm" }, + {"96f9a1224838a0695b3d2cc8b0b26b97" , "MR_Philips-Intera_BreaksNOSHADOW.dcm" }, + {"c75d2a8866ccdb2a96f7634bcc81adef" , "GE_CT_With_Private_compressed-icon.dcm" }, + {"4c600037ef23dbf2da360db9f8d7e28b" , "TOSHIBA_J2K_OpenJPEGv2Regression.dcm" }, + {"6c004779f7e43673883f04742aae9541" , "D_CLUNIE_CT1_JLSN.dcm" }, + {"e5155757353de1ad5c2b68c88fd34901" , "SIEMENS_MAGNETOM-12-MONO2-GDCM12-VRUN.dcm" }, + {"afccf775abd15a6c053c7f134b204762" , "00191113.dcm" }, + {"9670e5f8c163087d75cc4044356359c3" , "MARCONI_MxTWin-12-MONO2-JpegLossless-ZeroLengthSQ.dcm" }, + {"ac1abc22d5d52b21c74c9f34b6178cd1" , "SignedShortLosslessBug.dcm" }, + {"0f5efe869ef6b9846707e89fbef18f2c" , "GE_DLX-8-MONO2-Multiframe.dcm" }, + {"6763fff05fa5b5dc2b842a40573b18a3" , "PHILIPS_Gyroscan-12-MONO2-Jpeg_Lossless.dcm" }, + {"10151c9ee27d40cfd58f0d79e693f38e" , "LJPEG_BuginGDCM12.dcm" }, + {"d1779fd58242dc231aa021cbd9687b04" , "SIEMENS_MAGNETOM-12-MONO2-FileSeq3.dcm" }, + {"91c2703f4a5dec2d780539c29b450d47" , "D_CLUNIE_RG3_RLE.dcm" }, + {"ab0815dcb84bd5a42972134ea9c0493d" , "CT-SIEMENS-MissingPixelDataInIconSQ.dcm" }, + {"3703d1695f0c02fa7a5cbe7142c8fc6f" , "MR-MONO2-12-shoulder.dcm" }, + {"5a898d46c28350c4f55b9915b9001852" , "LEADTOOLS_FLOWERS-24-RGB-Uncompressed.dcm" }, + {"654e4af3861f475c16bf498efc5df861" , "PICKER-16-MONO2-No_DicomV3_Preamble.dcm" }, + {"885cd1e48a980257534d3c88380ec259" , "SIEMENS_MOSAIC_12BitsStored-16BitsJPEG.dcm" }, + {"dbe025b7a22b829898b6eb2b35580171" , "CT-MONO2-8-abdo.dcm" }, + {"97e8c927ca201a2f932b5b3ecc6453e5" , "D_CLUNIE_MR3_JPLL.dcm" }, + {"5cffc4c262df7534f4008aa49aaef3ae" , "D_CLUNIE_VL6_RLE.dcm" }, + {"a189258582a49855ae002d381016d02f" , "LEADTOOLS_FLOWERS-8-MONO2-RLE.dcm" }, + {"051d73b41bb387005e1dbcc3af7253b3" , "PHILIPS_Gyroscan-8-MONO2-Odd_Sequence.dcm" }, + {"e20e59c88037bbe676e8c67bee2a9540" , "TOSHIBA_J2K_SIZ0_PixRep1.dcm" }, + {"ca3a2e9d6d2813df183a9fd9c9d2e9a1" , "SIEMENS-12-Jpeg_Process_2_4-Lossy-a.dcm" }, + {"f073eb11257017c6422158aa5cfb372c" , "gdcm-JPEG-LossLess3a.dcm" }, + {"9b2dfd69af52cd8625fe1faa73f51493" , "D_CLUNIE_XA1_JPLY.dcm" }, + {"f1b14732b392da7ea5fba9b47225945c" , "D_CLUNIE_RG1_RLE.dcm" }, + {"8b86324f5b7b88f06dffe975a06f1544" , "US-RGB-8-epicard.dcm" }, + {"5a478d37f436a6687a07fd43aaef79ee" , "GE_MR_0025xx1bProtocolDataBlock.dcm" }, + {"43d75fbe29085c5760d6ff4c083a9726" , "rle16loo.dcm" }, + {"cbebb7b25f11a1c39194566b194e84e5" , "DMCPACS_ExplicitImplicit_BogusIOP.dcm" }, + {"4d6a3590ae425105315a0995f8a7da41" , "D_CLUNIE_CT2_JPLL.dcm" }, + {"c860f1795d0be70b310f5b653b34f06f" , "JDDICOM_Sample2-dcmdjpeg.dcm" }, + {"35619ea28ae211558d526e63429d5cbb" , "MR_Philips_Intera_No_PrivateSequenceImplicitVR.dcm" }, + {"2f2f0a482fc0c1b8d99db02a57122b22" , "KODAK_CompressedIcon.dcm" }, + {"1b28808b244d86f4b6ec626b4d538680" , "ACUSON-24-YBR_FULL-RLE.dcm" }, + {"3703d1695f0c02fa7a5cbe7142c8fc6f" , "D_CLUNIE_MR2_RLE.dcm" }, + {"22a67114d4ae8e036665e1a1a508ca8d" , "JPEG_LossyYBR.dcm" }, + {"3646c27f6fb60d66ab916934d331d550" , "012345.002.050.dcm" }, + {"941378c3e000b34264342b1d46ce6dce" , "D_CLUNIE_RG2_RLE.dcm" }, + {"0ba3c7de165ffe7fb43733f25de2fdf1" , "MR_Philips_Intera_PrivateSequenceImplicitVR.dcm" }, + {"e344c9a95328db382caf8a7b86c91992" , "SIEMENS_ImageLocationUN.dcm" }, + {"35619ea28ae211558d526e63429d5cbb" , "PHILIPS_Intera-16-MONO2-Uncompress.dcm" }, + {"42aa4fa1ac9421f083927baaf7230cf6" , "MR-SIEMENS-DICOM-WithOverlays-extracted-overlays.dcm" }, + {"5a898d46c28350c4f55b9915b9001852" , "LEADTOOLS_FLOWERS-24-RGB-JpegLossless.dcm" }, + {"00e15542d31e48490442eb4c336103e8" , "US-GE-4AICL142.dcm" }, + {"2bacf42b57e957883e35451c5ff26f50" , "D_CLUNIE_SC1_RLE.dcm" }, + {"0464a1b7160b097ea33f25865cce8fc9" , "D_CLUNIE_MR4_JPLL.dcm" }, + {"9b801c57776e5f7c4b45f2c6c47795d8" , "MR-Brucker-CineTagging-NonSquarePixels.dcm" }, + {"373a42fc21d411b4c060d2cf2a4e85f4" , "MR-MONO2-8-16x-heart.dcm" }, + {"6e9d26218dce3f54b41efbe442a2154b" , "LEADTOOLS_FLOWERS-8-MONO2-JpegLossy.dcm" }, + {"ccda9f1170c12f443d83990e9777ca8e" , "GE_DLX-8-MONO2-Multiframe-Jpeg_Lossless.dcm" }, + {"f00d34662aeb08d14bcaf230053bfd5f" , "D_CLUNIE_NM1_RLE.dcm" }, + {"a2b00a80955b1f368dcff51264b9e2e7" , "D_CLUNIE_VL1_RLE.dcm" }, + {"f00ef30b32dd57515c2c0d5c921c6ee1" , "SIEMENS_MAGNETOM-12-MONO2-FileSeq2.dcm" }, + {"0638ee027ccf94fd7ecca641b6fd402c" , "DermaColorLossLess.dcm" }, + {"5340e9111251343c6a932992241b299e" , "OT-MONO2-8-a7.dcm" }, + {"139f2ba3c6f578f883125d090163e730" , "D_CLUNIE_MR1_RLE.dcm" }, + {"a189258582a49855ae002d381016d02f" , "LEADTOOLS_FLOWERS-8-MONO2-Uncompressed.dcm" }, + {"afccf775abd15a6c053c7f134b204762" , "00191113.dcm" }, + {"f4f35d60b3cc18aaa6d8d92f0cd3708a" , "NM-PAL-16-PixRep1.dcm" }, + {"843f097f2161014cd1b11be5413eace9" , "MEDILABInvalidCP246_EVRLESQasUN.dcm" }, + {"c103d405ae61aa4ed148e17157e5afc1" , "JPEGInvalidSecondFrag.dcm" }, + + // sentinel + { 0, 0 } +}; + +namespace gdcm +{ +int TestIconImageGenerate3(const char *subdir, const char* filename, bool verbose = false) +{ + ImageReader reader; + reader.SetFileName( filename ); + if ( !reader.Read() ) + { + const FileMetaInformation &header = reader.GetFile().GetHeader(); + MediaStorage ms = header.GetMediaStorage(); + bool isImage = MediaStorage::IsImage( ms ); + bool pixeldata = reader.GetFile().GetDataSet().FindDataElement( Tag(0x7fe0,0x0010) ); + if( isImage && pixeldata ) + { + std::cerr << "Failed to read: " << filename << std::endl; + return 1; + } + else + { + // not an image give up... + std::cerr << "Problem with: " << filename << " but that's ok" << std::endl; + return 0; + } + } + + // Create directory first: + std::string tmpdir = Testing::GetTempDirectory( subdir ); + if( !System::FileIsDirectory( tmpdir.c_str() ) ) + { + System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + std::string outfilename = Testing::GetTempFilename( filename, subdir ); + + IconImageGenerator iig; + iig.SetPixmap( reader.GetImage() ); + iig.ConvertRGBToPaletteColor( false ); + const unsigned int idims[2] = { 128, 128}; + //const unsigned int idims[2] = { 552,421 }; + iig.SetOutputDimensions( idims ); + bool b = iig.Generate(); + + gdcm::Filename fn( filename ); + const char *name = fn.GetName(); + + unsigned int i = 0; + const char *p = iconimagearray3[i][1]; + while( p != 0 ) + { + if( strcmp( name, p ) == 0 ) + { + break; + } + ++i; + p = iconimagearray3[i][1]; + } + const char *refmd5 = iconimagearray3[i][0]; + + if( b ) + { + const gdcm::IconImage &icon = iig.GetIconImage(); + if( verbose ) icon.Print( std::cout ); + unsigned long len = icon.GetBufferLength(); + std::vector< char > vbuffer; + vbuffer.resize( len ); + char *buffer = &vbuffer[0]; + bool res2 = icon.GetBuffer(buffer); + if( !res2 ) + { + std::cerr << "res2 failure:" << filename << std::endl; + return 1; + } + char digest[33]; + gdcm::Testing::ComputeMD5(buffer, len, digest); + Image & img = reader.GetImage(); + img.SetIconImage( iig.GetIconImage() ); + + ImageWriter writer; + writer.SetFileName( outfilename.c_str() ); +#if 1 + writer.SetImage( img ); +#else + Image &ii = writer.GetImage(); + (Bitmap&)ii = iig.GetIconImage(); +#endif + if( !writer.Write() ) + { + std::cerr << "Failed to write: " << outfilename << std::endl; + return 1; + } + + if( verbose ) + { + std::cout << "success: " << outfilename << std::endl; + std::cout << "ref=" << refmd5 << std::endl; + std::cout << "md5=" << digest << std::endl; + } + + if( !refmd5 ) + { + std::cerr << " missing md5= {\"" << digest << "\" , \"" << name << "\" }," << std::endl; + return 1; + } + if( strcmp( refmd5, digest) ) + { + std::cerr << "Problem with : " << name << " " << refmd5 << " vs " << digest << std::endl; + return 1; + } + + } + else + { + assert( refmd5 == 0 ); + std::cerr << "Could not generate Icon for: " << filename << std::endl; + return 1; + } + + return 0; +} +} + +int TestIconImageGenerator3(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return gdcm::TestIconImageGenerate3(argv[0],filename, true); + } + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + gdcm::Trace::ErrorOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += gdcm::TestIconImageGenerate3(argv[0], filename ); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestIconImageGenerator4.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestIconImageGenerator4.cxx new file mode 100644 index 0000000..5b750eb --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestIconImageGenerator4.cxx @@ -0,0 +1,382 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmImageReader.h" +#include "gdcmImageWriter.h" +#include "gdcmFilename.h" +#include "gdcmSystem.h" +#include "gdcmFileMetaInformation.h" +#include "gdcmTesting.h" +#include "gdcmByteSwap.h" +#include "gdcmIconImageGenerator.h" +#include "gdcmAttribute.h" +#include "gdcmStringFilter.h" + +static const char * const iconimagearray4[][2] = { + {"7e097b4a57af6a823bd692e37b131b1c" , "SIEMENS_SOMATOM-12-ACR_NEMA-ZeroLengthUs.acr" }, + {"7f2638cea652bf3452ada158d2ea67c4" , "gdcm-MR-SIEMENS-16-2.acr" }, + {"da0922a02f8e763ec878089617e0bc4c" , "test.acr" }, + {"e75ee90f23db1952a593393cdfaaf99f" , "MR-MONO2-12-an2.acr" }, + {"c9c46afd186531850af9576cf54c800b" , "CT-MONO2-12-lomb-an2.acr" }, + {"feb10d9a28e5166a3baf9ec6ef4f460a" , "LIBIDO-8-ACR_NEMA-Lena_128_128.acr" }, + {"f9d8a0796ebf5a6aabddb4e133d09770" , "gdcm-ACR-LibIDO.acr" }, + {"a1bce65e11c5fd2e26f7b38ebfdd1c53" , "libido1.0-vol.acr" }, + {"9edea7caea2b85aad952d35c64f1e092" , "SIEMENS_CSA2.dcm" }, + {"011d1f2abd9e27a2dc5d013bd4848104" , "gdcm-JPEG-LossLessThoravision.dcm" }, + {"ddb7e67d119eb2ce14731cd9007e36cc" , "XA-MONO2-8-12x-catheter.dcm" }, + {"1041bae356da40d2113210ff2adef923" , "gdcm-MR-PHILIPS-16-Multi-Seq.dcm" }, + {"a3a6b3bf75ccdc91f82effc60d005688" , "PHILIPS_GDCM12xBug.dcm" }, + {"a247e2ca32279956079c9a87403bd157" , "MR_Philips_Intera_PrivateSequenceExplicitVR_in_SQ_2001_e05f_item_wrong_lgt_use_NOSHADOWSEQ.dcm" }, + {"b29a7fe847f942e3afdda5ddf23c03c3" , "D_CLUNIE_CT1_J2KI.dcm" }, + {"3f7cae9b920adb3ca4a96ace2c0c91d7" , "rle16sti.dcm" }, + {"f706f740496e445ee59141b15f3baeb4" , "3E768EB7.dcm" }, + {"b38c113fffa4925f6f06a928b357f6a1" , "D_CLUNIE_MR2_JPLY.dcm" }, + {"c3d3a218fcec778476090bce4c8b3201" , "SIEMENS_MAGNETOM-12-MONO2-FileSeq1.dcm" }, + {"882a7327bab05d88571dcf29f902adf3" , "SIEMENS_MAGNETOM-12-MONO2-FileSeq0.dcm" }, + {"1f4ae64fab8745e6affb72721ffdfaec" , "MR_Philips_Intera_SwitchIndianess_noLgtSQItem_in_trueLgtSeq.dcm" }, + {"af193ff3143f299826d55e00696b3218" , "LEADTOOLS_FLOWERS-16-MONO2-Uncompressed.dcm" }, + {"f6a020bb9aab2e59a289064b2add00ec" , "D_CLUNIE_MR3_JPLY.dcm" }, + {"e8b529fbe615b4c540318695913d02e7" , "D_CLUNIE_VL2_RLE.dcm" }, + {"8393213bd2c340a8cbd639f45a6b497e" , "OsirixFake16BitsStoredFakeSpacing.dcm" }, + {"c50f0f97e1e36a4387620634e7a9b152" , "GE_RHAPSODE-16-MONO2-JPEG-Fragments.dcm" }, + {"c265bf6c3bf4417987ff81b92ca4ca6c" , "MR_SIEMENS_forceLoad29-1010_29-1020.dcm" }, + {"fa7da45d1a8eb16b092880ceff5a50e5" , "fffc0000UN.dcm" }, + {"796594769ee3570292de36fdb4509df1" , "LIBIDO-24-ACR_NEMA-Rectangle.dcm" }, + {"32b10fd4f13cfb4d74e1145f166e9dae" , "IM-0001-0066.CommandTag00.dcm" }, + {"619f8c1650962cddf7695e39f43e8c49" , "D_CLUNIE_NM1_JPLY.dcm" }, + {"c50f0f97e1e36a4387620634e7a9b152" , "D_CLUNIE_CT1_J2KR.dcm" }, + {"30a530ea4df623cbec31f752637e234b" , "TheralysGDCM120Bug.dcm" }, + {"3120b59e3635a912c6a60897f734b2ff" , "SIEMENS_MAGNETOM-12-MONO2-VRUN.dcm" }, + {"5bdb2335ceb2dac83c2248d6ff8e0a49" , "THERALYS-12-MONO2-Uncompressed-Even_Length_Tag.dcm" }, + {"30ff6655c5eb98ad34cd20836418a5a7" , "ALOKA_SSD-8-MONO2-RLE-SQ.dcm" }, + {"992e4ef2b01f9d79514d7ab22c354be9" , "GE_GENESIS-16-MONO2-WrongLengthItem.dcm" }, + {"d4669bd89971c1affd311c7d1d8b20c7" , "US-RGB-8-esopecho.dcm" }, + {"85124dd05ab0567aecaf896373f780da" , "D_CLUNIE_MR4_RLE.dcm" }, + {"07964ed19883cb96460d1407795f4306" , "D_CLUNIE_MR2_JPLL.dcm" }, + {"096547f2834609ae4dbc115169806fc4" , "SIEMENS_Sonata-16-MONO2-Value_Multiplicity.dcm" }, + {"af193ff3143f299826d55e00696b3218" , "LEADTOOLS_FLOWERS-16-MONO2-JpegLossless.dcm" }, + {"da7002947725a950c3226cd23aa8d718" , "CT-MONO2-16-ankle.dcm" }, + {"1a27a48d4efe2999b83bc89d3003d05c" , "LEADTOOLS_FLOWERS-8-PAL-RLE.dcm" }, + {"feb10d9a28e5166a3baf9ec6ef4f460a" , "simpleImageWithIcon.dcm" }, + {"aeb28d2cfb5376e2bb1ac4aac0b4807c" , "CR-MONO1-10-chest.dcm" }, + {"c50f0f97e1e36a4387620634e7a9b152" , "D_CLUNIE_CT1_RLE.dcm" }, + {"4d469f85f51b3b81bdf38ebba23a68e7" , "D_CLUNIE_NM1_JPLL.dcm" }, + {"f7f066f0597791fcc147603ab5af6387" , "MR_GE_with_Private_Compressed_Icon_0009_1110.dcm" }, + {"abe1950da247d18196fe5bea54cb26f1" , "NM-MONO2-16-13x-heart.dcm" }, + {"6bd67bbd6e3e65808db8598fe0913f86" , "US-IRAD-NoPreambleStartWith0003.dcm" }, + {"99672e03104c9176595bc0002cd8edf8" , "MR-MONO2-16-head.dcm" }, + {"1a27a48d4efe2999b83bc89d3003d05c" , "LEADTOOLS_FLOWERS-8-PAL-Uncompressed.dcm" }, + {"af8491953e762c12feb93a80a1575edf" , "MAROTECH_CT_JP2Lossy.dcm" }, + {"932281859be22ffae33a2669b34cc2e6" , "05115014-mr-siemens-avanto-syngo-with-palette-icone.dcm" }, + {"fb5402472ee00639ef8dc1b09692c299" , "US-PAL-8-10x-echo.dcm" }, + {"038acb53133733a9f2c54528b8029511" , "MR-SIEMENS-DICOM-WithOverlays.dcm" }, + {"890d0a5afdbf77398d857b523f86e83a" , "D_CLUNIE_MR1_JPLL.dcm" }, + {"c50f0f97e1e36a4387620634e7a9b152" , "D_CLUNIE_CT1_JPLL.dcm" }, + {"7897424399822301bdbedbcaf34c7c84" , "AMIInvalidPrivateDefinedLengthSQasUN.dcm" }, + {"1f4ae64fab8745e6affb72721ffdfaec" , "ExplicitVRforPublicElementsImplicitVRforShadowElements.dcm" }, + {"3443eba48f11dd9aadb4632c8c896b39" , "PHILIPS_Gyroscan-12-Jpeg_Extended_Process_2_4.dcm" }, + {"b72e483ad977e18b8016c7cc916c4bbd" , "D_CLUNIE_SC1_JPLY.dcm" }, + {"582df1a47c5992cc4f37496dab8c5130" , "gdcm-MR-PHILIPS-16-NonSquarePixels.dcm" }, + {"8a5d13f6c85b2eebc1c02432d729cd45" , "SIEMENS-MR-RGB-16Bits.dcm" }, + {"aacd6f6257e068cf53cdec5c7e172513" , "US-IRAD-NoPreambleStartWith0005.dcm" }, + {"6a9ecd676ce47b0fda111a804b58b054" , "PICKER-16-MONO2-Nested_icon.dcm" }, + {"9b720fd0aa079bc2f3f9545bd0e207c6" , "gdcm-JPEG-Extended.dcm" }, + {"c790d0a462907135c1991f10a4846f98" , "D_CLUNIE_US1_RLE.dcm" }, + {"4689c053642dcee7a2a9d0475c1b6528" , "D_CLUNIE_RG2_JPLY.dcm" }, + {"b3b8a60e7b7b20c029eec1d5006e2b9c" , "PHILIPS_Brilliance_ExtraBytesInOverlay.dcm" }, + {"91533007e5e07353012dea33149d920f" , "MR_ELSCINT1_00e1_1042_SQ_feff_00e0_Item.dcm" }, + {"c8902cc14f285f2687866f60e45c7d86" , "TG18-CH-2k-01.dcm" }, + {"af193ff3143f299826d55e00696b3218" , "LEADTOOLS_FLOWERS-16-MONO2-RLE.dcm" }, + {"27daf49ec13f58db1d800fc58378852e" , "OT-PAL-8-face.dcm" }, + {"07fef244d4e14358d453c144770b2a55" , "LEADTOOLS_FLOWERS-24-RGB-JpegLossy.dcm" }, + {"ad96e04c3c50d463cccdfca68b49b071" , "SIEMENS_MAGNETOM-12-MONO2-Uncompressed.dcm" }, + {"620f0b67a91f7f74151bc5be745b7110" , "GDCMJ2K_TextGBR.dcm" }, + {"d1f5dfac9c3213f548df6a1f9e86acd0" , "MR16BitsAllocated_8BitsStored.dcm" }, + {"cc2aaa869f08908e1f37ccdd314841ab" , "GE_GENESIS-16-MONO2-Uncompressed-UnusualVR.dcm" }, + {"c50f0f97e1e36a4387620634e7a9b152" , "D_CLUNIE_CT1_JLSL.dcm" }, + {"719505e71eafd643fa2e114acc83496f" , "ELSCINT1_JP2vsJ2K.dcm" }, + {"7132fec8839d9c8b26cba4a4f17000da" , "D_CLUNIE_XA1_JPLL.dcm" }, + {"cdf5908902fb63e321b224fae86a4128" , "SIEMENS_Sonata-12-MONO2-SQ.dcm" }, + {"bc1774acbf5c025aa3b57184213cc98c" , "JPEGDefinedLengthSequenceOfFragments.dcm" }, + {"e9faa2ce59db8563d7abe50432f91351" , "PHILIPS_GDCM12xBug2.dcm" }, + {"620f0b67a91f7f74151bc5be745b7110" , "ITK_GDCM124_MultiframeSecondaryCaptureInvalid.dcm" }, + {"52d0b90aa78a20cbff6b0beb3bd2c2b3" , "D_CLUNIE_RG2_JPLL.dcm" }, + {"50dd1ae0bf918a9144b50229fa04f8e0" , "FUJI-10-MONO1-ACR_NEMA_2.dcm" }, + {"d7e55bf3c6eb7a627823b532bcac7e16" , "D_CLUNIE_MR1_JPLY.dcm" }, + {"7132fec8839d9c8b26cba4a4f17000da" , "D_CLUNIE_XA1_RLE.dcm" }, + {"f48ea76ff11ca6ca4958df9c186422f4" , "BugGDCM2_UndefItemWrongVL.dcm" }, + {"7f2638cea652bf3452ada158d2ea67c4" , "SIEMENS_MAGNETOM-12-ACR_NEMA_2-Modern.dcm" }, + {"477d801b27ef3cb21a8685cedbc9b12e" , "JDDICOM_Sample2.dcm" }, + {"cae77b420f407118f288c14eeb81e11f" , "TOSHIBA_MRT150-16-MONO2-ACR_NEMA_2.dcm" }, + {"524014ef866b31e3fd2e33a6148d31bb" , "DCMTK_JPEGExt_12Bits.dcm" }, + {"84ea2f46ad98332a06875da922709007" , "US-MONO2-8-8x-execho.dcm" }, + {"19d6f17c8a0b2cd04049828dcb304046" , "UnexpectedSequenceDelimiterInFixedLengthSequence.dcm" }, + {"bee28068ae9edef69fef792583b3e20f" , "ACUSON-24-YBR_FULL-RLE-b.dcm" }, + {"b171f7581c9cf15b2d32cfd62e9b6038" , "gdcm-US-ALOKA-16.dcm" }, + {"80be78c9365f6a1604191dd703c84ac5" , "DX_J2K_0Padding.dcm" }, + {"a9a72d44b888fb4f1f727af88109cfb3" , "D_CLUNIE_CT2_RLE.dcm" }, + {"151376fcac2fbd55c3b5c5a155e16d26" , "D_CLUNIE_RG1_JPLL.dcm" }, + {"e0a3fd5917c5a13a16981e1d0346af4d" , "D_CLUNIE_VL3_RLE.dcm" }, + {"28ea47a62e1f2ca9d7dcd10ef868701d" , "NM_Kakadu44_SOTmarkerincons.dcm" }, + {"e95cec3c8078cea91b287e45d751cf78" , "CT-SIEMENS-Icone-With-PaletteColor.dcm" }, + {"eacd1cabeaf78554804ca627344cba91" , "GE_DLX-8-MONO2-PrivateSyntax.dcm" }, + {"8f40712ff8e4a7691be144d884546a17" , "CT_16b_signed-UsedBits13.dcm" }, + {"da9fb19d564fa01e4633df5c105f5a58" , "D_CLUNIE_RG3_JPLY.dcm" }, + {"6510f44ff1dd8daf9b49100fd2c81d85" , "DX_GE_FALCON_SNOWY-VOI.dcm" }, + {"5a15bd50c589c9611636dc7813493c03" , "PrivateGEImplicitVRBigEndianTransferSyntax16Bits.dcm" }, + {"4948235091edc01603344f79a29835e1" , "CT-MONO2-16-brain.dcm" }, + {"c2de60330cda14759a117b937a7e5a95" , "D_CLUNIE_VL4_RLE.dcm" }, + {"599ac7bd3a573451f3cd53494ace8cdf" , "D_CLUNIE_MR3_RLE.dcm" }, + {"72f55d5cf022e983783185195b77d0e6" , "undefined_length_un_vr.dcm" }, + {"a8e2e35044384f31afc1dcf9163154ff" , "CT-MONO2-16-ort.dcm" }, + {"0fefcf91a55062f1cb20945b3f726eda" , "05148044-mr-siemens-avanto-syngo.dcm" }, + {"5d6aaab5766479ec6e27de4eaa4a6438" , "GE_LOGIQBook-8-RGB-HugePreview.dcm" }, + {"acad4e43da617035315bcddc4bbb96bd" , "RadBWLossLess.dcm" }, + {"b69e23b6479de4d9c3b4ed51aa748f73" , "KODAK-12-MONO1-Odd_Terminated_Sequence.dcm" }, + {"e8458a5483e72cced4d46f93eed1699e" , "CT-MONO2-16-chest.dcm" }, + {"728a698e308f7863ba3d103b80dffc45" , "PhilipsInteraSeqTermInvLen.dcm" }, + {"35144f65c704edf2d69abc40405c3ea7" , "D_CLUNIE_MR4_JPLY.dcm" }, + {"904b38f362b86f626ea7d89eed455709" , "D_CLUNIE_RG3_JPLL.dcm" }, + {"707e26b0fa27f670c35ca5cc2bf3eda2" , "MR_Philips-Intera_BreaksNOSHADOW.dcm" }, + {"04b97df84da7a126be30993cf9cff942" , "GE_CT_With_Private_compressed-icon.dcm" }, + {"04cb0299587f38ba369e1fdcbf07dc25" , "D_CLUNIE_CT1_JLSN.dcm" }, + {"3120b59e3635a912c6a60897f734b2ff" , "SIEMENS_MAGNETOM-12-MONO2-GDCM12-VRUN.dcm" }, + {"cee47e57f6b1aaace74bb813e33a74eb" , "00191113.dcm" }, + {"99ba02caa6813cafd254f97fb8377f60" , "MARCONI_MxTWin-12-MONO2-JpegLossless-ZeroLengthSQ.dcm" }, + {"46c2e032f2858831691a184aa6cdb0da" , "SignedShortLosslessBug.dcm" }, + {"2b306840879792f3509e1c1ccedee81d" , "GE_DLX-8-MONO2-Multiframe.dcm" }, + {"fde7dc022ec854a98ffdc2190ceef424" , "PHILIPS_Gyroscan-12-MONO2-Jpeg_Lossless.dcm" }, + {"f4b5fc5cc1440b865f1a99b85b170ecd" , "LJPEG_BuginGDCM12.dcm" }, + {"ba2717c0d839213e788a74cccf37f1d4" , "SIEMENS_MAGNETOM-12-MONO2-FileSeq3.dcm" }, + {"904b38f362b86f626ea7d89eed455709" , "D_CLUNIE_RG3_RLE.dcm" }, + {"5e51e64ee21c2f643c13257e054c2990" , "CT-SIEMENS-MissingPixelDataInIconSQ.dcm" }, + {"07964ed19883cb96460d1407795f4306" , "MR-MONO2-12-shoulder.dcm" }, + {"0b818ac3983d76cfdc535a46058a1a53" , "LEADTOOLS_FLOWERS-24-RGB-Uncompressed.dcm" }, + {"7f7aaee92f20ffcd64bebf8ce105bf5d" , "PICKER-16-MONO2-No_DicomV3_Preamble.dcm" }, + {"fde3b9c4853c597383fab1050b491202" , "SIEMENS_MOSAIC_12BitsStored-16BitsJPEG.dcm" }, + {"ba0654f3e7aae75bca8fc24705ddb78a" , "CT-MONO2-8-abdo.dcm" }, + {"599ac7bd3a573451f3cd53494ace8cdf" , "D_CLUNIE_MR3_JPLL.dcm" }, + {"03f25fb3e6e8ae53b9565553e2026a66" , "D_CLUNIE_VL6_RLE.dcm" }, + {"af193ff3143f299826d55e00696b3218" , "LEADTOOLS_FLOWERS-8-MONO2-RLE.dcm" }, + {"d46afca30969faa05583e87b0f6e5211" , "PHILIPS_Gyroscan-8-MONO2-Odd_Sequence.dcm" }, + {"5885ade0feaaf967f5a1c22724c10d02" , "SIEMENS-12-Jpeg_Process_2_4-Lossy-a.dcm" }, + {"13758e32fe34c17b897efcbd26e7e03b" , "gdcm-JPEG-LossLess3a.dcm" }, + {"1e61c6d50ae3ef3ac0550277f166bd1c" , "D_CLUNIE_XA1_JPLY.dcm" }, + {"151376fcac2fbd55c3b5c5a155e16d26" , "D_CLUNIE_RG1_RLE.dcm" }, + {"e77b93eb953f2a21fa75d257da0514fb" , "US-RGB-8-epicard.dcm" }, + {"a101ddd933114bcc0145d047d74f41c9" , "GE_MR_0025xx1bProtocolDataBlock.dcm" }, + {"b9f48f54e75b7f1994cfe1a7152d9ab5" , "rle16loo.dcm" }, + {"cc61470afd2b80014749abbb5bd9109d" , "DMCPACS_ExplicitImplicit_BogusIOP.dcm" }, + {"a9a72d44b888fb4f1f727af88109cfb3" , "D_CLUNIE_CT2_JPLL.dcm" }, + {"477d801b27ef3cb21a8685cedbc9b12e" , "JDDICOM_Sample2-dcmdjpeg.dcm" }, + {"1f4ae64fab8745e6affb72721ffdfaec" , "MR_Philips_Intera_No_PrivateSequenceImplicitVR.dcm" }, + {"323c2919ea590363dd6eb4105a2566a7" , "KODAK_CompressedIcon.dcm" }, + {"486199008daf27f167efee9469fffd52" , "ACUSON-24-YBR_FULL-RLE.dcm" }, + {"07964ed19883cb96460d1407795f4306" , "D_CLUNIE_MR2_RLE.dcm" }, + {"b53c440c32a7bd20d24cc1997bd7c9e6" , "JPEG_LossyYBR.dcm" }, + {"2b098d933de8c90b317619658f698cc5" , "012345.002.050.dcm" }, + {"52d0b90aa78a20cbff6b0beb3bd2c2b3" , "D_CLUNIE_RG2_RLE.dcm" }, + {"e44869a1044b611e08a9f1396432a44b" , "MR_Philips_Intera_PrivateSequenceImplicitVR.dcm" }, + {"f92d6349e1d80bbdba34a9e1b84eb737" , "SIEMENS_ImageLocationUN.dcm" }, + {"1f4ae64fab8745e6affb72721ffdfaec" , "PHILIPS_Intera-16-MONO2-Uncompress.dcm" }, + {"0e82ac528c72a2dd69fa1b52e5370d82" , "MR-SIEMENS-DICOM-WithOverlays-extracted-overlays.dcm" }, + {"0b818ac3983d76cfdc535a46058a1a53" , "LEADTOOLS_FLOWERS-24-RGB-JpegLossless.dcm" }, + {"91b4da2ca9fd378ca404580c84c62984" , "US-GE-4AICL142.dcm" }, + {"2ff486489d600e0ab5f8c829960c516f" , "D_CLUNIE_SC1_RLE.dcm" }, + {"85124dd05ab0567aecaf896373f780da" , "D_CLUNIE_MR4_JPLL.dcm" }, + {"ece67fa0c8a99f8147b26081252cd0a5" , "MR-Brucker-CineTagging-NonSquarePixels.dcm" }, + {"bdf48b10871ac0b3c14587eaba9ca998" , "MR-MONO2-8-16x-heart.dcm" }, + {"0c65a403a0a24957e523bb29e84c31ef" , "LEADTOOLS_FLOWERS-8-MONO2-JpegLossy.dcm" }, + {"f92a60ad3cbc2783db57cac5f800a9c0" , "GE_DLX-8-MONO2-Multiframe-Jpeg_Lossless.dcm" }, + {"4d469f85f51b3b81bdf38ebba23a68e7" , "D_CLUNIE_NM1_RLE.dcm" }, + {"20e2f6cc2b60ae26adfdd3b3ee0e1915" , "D_CLUNIE_VL1_RLE.dcm" }, + {"84462b24809f4e9d151c7c27004f7922" , "SIEMENS_MAGNETOM-12-MONO2-FileSeq2.dcm" }, + {"620f0b67a91f7f74151bc5be745b7110" , "DermaColorLossLess.dcm" }, + {"72e203ca5756f4491d84d8240c82a59b" , "OT-MONO2-8-a7.dcm" }, + {"890d0a5afdbf77398d857b523f86e83a" , "D_CLUNIE_MR1_RLE.dcm" }, + {"af193ff3143f299826d55e00696b3218" , "LEADTOOLS_FLOWERS-8-MONO2-Uncompressed.dcm" }, + {"cee47e57f6b1aaace74bb813e33a74eb" , "00191113.dcm" }, + {"07b6f4e2fba920d28e2f29dbb037b640" , "TOSHIBA_J2K_SIZ1_PixRep0.dcm" }, + {"93f60acbb450c62992a1db09a6c19c05" , "TOSHIBA_J2K_OpenJPEGv2Regression.dcm" }, + {"fa02ad71bdf3e6970e18fc9a9df03a2d" , "TOSHIBA_J2K_SIZ0_PixRep1.dcm" }, + {"3475cb96e0308cb84502be1c1531b588" , "NM-PAL-16-PixRep1.dcm" }, + {"2ec6d7c60d6786665cff2b7a31aaeedf" , "MEDILABInvalidCP246_EVRLESQasUN.dcm" }, + {"560881eca73809ac358aa14733ee64af" , "JPEGInvalidSecondFrag.dcm" }, + + // sentinel + { 0, 0 } +}; + +namespace gdcm +{ +int TestIconImageGenerate4(const char *subdir, const char* filename, bool verbose = false) +{ + ImageReader reader; + reader.SetFileName( filename ); + if ( !reader.Read() ) + { + const FileMetaInformation &header = reader.GetFile().GetHeader(); + MediaStorage ms = header.GetMediaStorage(); + bool isImage = MediaStorage::IsImage( ms ); + bool pixeldata = reader.GetFile().GetDataSet().FindDataElement( Tag(0x7fe0,0x0010) ); + if( isImage && pixeldata ) + { + std::cerr << "Failed to read: " << filename << std::endl; + return 1; + } + else + { + // not an image give up... + std::cerr << "Problem with: " << filename << " but that's ok" << std::endl; + return 0; + } + } + + // Create directory first: + std::string tmpdir = Testing::GetTempDirectory( subdir ); + if( !System::FileIsDirectory( tmpdir.c_str() ) ) + { + System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + std::string outfilename = Testing::GetTempFilename( filename, subdir ); + + IconImageGenerator iig; + iig.SetPixmap( reader.GetImage() ); + iig.AutoPixelMinMax(true); + gdcm::StringFilter sf; + sf.SetFile( reader.GetFile() ); +/* + const DataSet & ds = reader.GetFile().GetDataSet(); + if( ds.FindDataElement( gdcm::Tag(0x0028,0x0120) ) && !ds.GetDataElement(gdcm::Tag(0x0028,0x0120)).IsEmpty() ) + { + // gdcm::Attribute<0x28,0x120> at; + iig.SetOutsideValuePixel( -2000 ); + } +*/ + std::string strval = sf.ToString(gdcm::Tag(0x0028,0x0120)); + double val; + std::istringstream is; + is.str( strval ); + if( is >> val ) + { + iig.SetOutsideValuePixel( val ); + assert( !strval.empty() ); + } + const unsigned int idims[2] = { 64, 64 }; + //const unsigned int idims[2] = { 600,430 }; + iig.SetOutputDimensions( idims ); + bool b = iig.Generate(); + + gdcm::Filename fn( filename ); + const char *name = fn.GetName(); + + unsigned int i = 0; + const char *p = iconimagearray4[i][1]; + while( p != 0 ) + { + if( strcmp( name, p ) == 0 ) + { + break; + } + ++i; + p = iconimagearray4[i][1]; + } + const char *refmd5 = iconimagearray4[i][0]; + + if( b ) + { + const gdcm::IconImage &icon = iig.GetIconImage(); + if( verbose ) icon.Print( std::cout ); + unsigned long len = icon.GetBufferLength(); + std::vector< char > vbuffer; + vbuffer.resize( len ); + char *buffer = &vbuffer[0]; + bool res2 = icon.GetBuffer(buffer); + if( !res2 ) + { + std::cerr << "res2 failure:" << filename << std::endl; + return 1; + } + char digest[33]; + gdcm::Testing::ComputeMD5(buffer, len, digest); + Image & img = reader.GetImage(); + img.SetIconImage( iig.GetIconImage() ); + + ImageWriter writer; + writer.SetFileName( outfilename.c_str() ); +#if 1 + writer.SetImage( img ); +#else + Image &ii = writer.GetImage(); + (Bitmap&)ii = iig.GetIconImage(); +#endif + if( !writer.Write() ) + { + std::cerr << "Failed to write: " << outfilename << std::endl; + return 1; + } + + if( verbose ) + { + std::cout << "success: " << outfilename << std::endl; + std::cout << "ref=" << refmd5 << std::endl; + std::cout << "md5=" << digest << std::endl; + } + + if( !refmd5 ) + { + std::cerr << " missing md5= {\"" << digest << "\" , \"" << name << "\" }," << std::endl; + return 1; + } + if( strcmp( refmd5, digest) ) + { + std::cerr << "Problem with : " << name << " " << refmd5 << " vs " << digest << std::endl; + return 1; + } + + } + else + { + assert( refmd5 == 0 ); + std::cerr << "Could not generate Icon for: " << filename << std::endl; + return 1; + } + + return 0; +} +} + +int TestIconImageGenerator4(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return gdcm::TestIconImageGenerate4(argv[0],filename, true); + } + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + gdcm::Trace::ErrorOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += gdcm::TestIconImageGenerate4(argv[0], filename ); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImage.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImage.cxx new file mode 100644 index 0000000..a54ff65 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImage.cxx @@ -0,0 +1,70 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmImage.h" +#include "gdcmImageReader.h" + +int TestImage(int, char *[]) +{ + gdcm::Image img; + + gdcm::ImageReader reader; + const gdcm::Image &img2 = reader.GetImage(); + img2.Print(std::cout);//just to avoid the warning of img2 being unused + +#if 0 +{ + gdcm::Image img3 = reader.GetImage(); +} + gdcm::SmartPointer img4 = const_cast(&img2); + + gdcm::ImageReader r; + //r.SetFileName( "/home/mathieu/Creatis/gdcmData/test.acr" ); + r.SetFileName( "/home/mathieu/Creatis/gdcmData/DermaColorLossLess.dcm" ); + r.Read(); + + //std::vector< gdcm::SmartPointer > images; + std::vector< gdcm::Image > images; + +{ + const gdcm::Image &ref = r.GetImage(); + images.push_back( ref ); + + ref.Print(std::cout); + gdcm::Image copy1 = ref; + + copy1.Print(std::cout); + + gdcm::SmartPointer copy2; + copy2 = r.GetImage(); + copy2->Print(std::cout); + + gdcm::ImageReader r2; + r2.SetFileName( "/home/mathieu/Creatis/gdcmData/012345.002.050.dcm" ); + r2.Read(); + +std::cout << " ------------------ " << std::endl; + + images.push_back( r2.GetImage() ); + + ref.Print(std::cout); + copy1.Print(std::cout); + copy2->Print(std::cout); +} + + images[0].Print( std::cout ); + images[1].Print( std::cout ); +#endif + + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageApplyLookupTable.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageApplyLookupTable.cxx new file mode 100644 index 0000000..f0145f7 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageApplyLookupTable.cxx @@ -0,0 +1,164 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmImageApplyLookupTable.h" +#include "gdcmTesting.h" +#include "gdcmSystem.h" +#include "gdcmImageReader.h" +#include "gdcmImageWriter.h" +#include "gdcmImage.h" +#include "gdcmFilename.h" + +static const char * const lutarray[][2] = { + { "d613050ca0f9c924fb5282d140281fcc", "LEADTOOLS_FLOWERS-8-PAL-RLE.dcm" }, + { "d613050ca0f9c924fb5282d140281fcc", "LEADTOOLS_FLOWERS-8-PAL-Uncompressed.dcm" }, + { "7b8d795eaf99f1fff176c43f9cf76bfb", "NM-PAL-16-PixRep1.dcm" }, + { "47715f0a5d5089268bbef6f83251a8ad", "OT-PAL-8-face.dcm" }, + { "c70309b66045140b8e08c11aa319c0ab", "US-PAL-8-10x-echo.dcm" }, + { "c370ca934dc910eb4b629a2fa8650b67", "gdcm-US-ALOKA-16.dcm" }, + { "49ca8ad45fa7f24b0406a5a03ba8aff6", "rle16loo.dcm" }, + { "964ea27345a7004325896d34b257f289", "rle16sti.dcm" }, + + // sentinel + { 0, 0 } +}; + +int TestImageApplyLookupTableFunc(const char *filename, bool verbose = false) +{ + gdcm::ImageReader reader; + reader.SetFileName( filename ); + if ( !reader.Read() ) + { + const gdcm::FileMetaInformation &header = reader.GetFile().GetHeader(); + gdcm::MediaStorage ms = header.GetMediaStorage(); + bool isImage = gdcm::MediaStorage::IsImage( ms ); + bool pixeldata = reader.GetFile().GetDataSet().FindDataElement( gdcm::Tag(0x7fe0,0x0010) ); + if( isImage && pixeldata ) + { + std::cout << "Could not read: " << filename << std::endl; + return 1; + } + return 0; + } + const gdcm::Image &image = reader.GetImage(); + + const gdcm::PhotometricInterpretation &pi = image.GetPhotometricInterpretation(); + if( pi != gdcm::PhotometricInterpretation::PALETTE_COLOR ) + { + // yeah well not much I can do here... + if( verbose ) + { + std::cout << "PhotometricInterpretation is: " << pi << " cannot apply LUT then..." << std::endl; + } + return 0; + } + + gdcm::ImageApplyLookupTable lutfilt; + lutfilt.SetInput( image ); + bool b = lutfilt.Apply(); + if( !b ) + { + std::cerr << "Could not apply lut: " << filename << std::endl; + return 1; + } + + // Create directory first: + const char subdir[] = "TestImageApplyLookupTable"; + std::string tmpdir = gdcm::Testing::GetTempDirectory( subdir ); + if( !gdcm::System::FileIsDirectory( tmpdir.c_str() ) ) + { + gdcm::System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + std::string outfilename = gdcm::Testing::GetTempFilename( filename, subdir ); + + gdcm::ImageWriter writer; + writer.SetFileName( outfilename.c_str() ); + //writer.SetFile( reader.GetFile() ); // increase test goal + writer.SetImage( lutfilt.GetOutput() ); + if( !writer.Write() ) + { + std::cerr << "Failed to write: " << outfilename << std::endl; + return 1; + } + + // Let's read that file back in ! + gdcm::ImageReader reader2; + reader2.SetFileName( outfilename.c_str() ); + if ( !reader2.Read() ) + { + std::cerr << "Failed to read back: " << outfilename << std::endl; + return 1; + } + + const gdcm::Image &img = reader2.GetImage(); + unsigned long len = img.GetBufferLength(); + char* buffer = new char[len]; + img.GetBuffer(buffer); + + gdcm::Filename fn( filename ); + const char *name = fn.GetName(); + unsigned int i = 0; + const char *p = lutarray[i][1]; + while( p != 0 ) + { + if( strcmp( name, p ) == 0 ) + { + break; + } + ++i; + p = lutarray[i][1]; + } + const char *ref = lutarray[i][0]; + + char digest[33] = {}; + gdcm::Testing::ComputeMD5(buffer, len, digest); + int res = 0; + if( !ref ) + { + std::cerr << "Missing LUT-applied MD5 for image from: " << filename << std::endl; + res = 1; + } + else if( strcmp(digest, ref) ) + { + std::cerr << "Problem reading image from: " << filename << std::endl; + std::cerr << "Found " << digest << " instead of " << ref << std::endl; + res = 1; + } + delete[] buffer; + + return res; +} + +int TestImageApplyLookupTable(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestImageApplyLookupTableFunc(filename, true); + } + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestImageApplyLookupTableFunc( filename ); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageChangePhotometricInterpretation.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageChangePhotometricInterpretation.cxx new file mode 100644 index 0000000..c0dd7a9 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageChangePhotometricInterpretation.cxx @@ -0,0 +1,115 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmImageChangePhotometricInterpretation.h" +#include "gdcmImageReader.h" +#include "gdcmImageWriter.h" +#include "gdcmTesting.h" +#include "gdcmSystem.h" + +namespace gdcm +{ +PhotometricInterpretation InvertPI(PhotometricInterpretation pi) +{ + assert( pi == PhotometricInterpretation::MONOCHROME1 || pi == PhotometricInterpretation::MONOCHROME2 ); + if( pi == PhotometricInterpretation::MONOCHROME1 ) + { + return PhotometricInterpretation::MONOCHROME2; + } + return PhotometricInterpretation::MONOCHROME1; +} +} + +int TestImageChangePhotometricInterpretationFunc(const char *filename, bool verbose = false) +{ + gdcm::ImageReader reader; + reader.SetFileName( filename ); + if ( !reader.Read() ) + { + const gdcm::FileMetaInformation &header = reader.GetFile().GetHeader(); + gdcm::MediaStorage ms = header.GetMediaStorage(); + bool isImage = gdcm::MediaStorage::IsImage( ms ); + bool pixeldata = reader.GetFile().GetDataSet().FindDataElement( gdcm::Tag(0x7fe0,0x0010) ); + if( isImage && pixeldata ) + { + std::cout << "Could not read: " << filename << std::endl; + return 1; + } + return 0; + } + const gdcm::Image &image = reader.GetImage(); + + //unsigned int pc = image.GetPlanarConfiguration(); + gdcm::PhotometricInterpretation pi = image.GetPhotometricInterpretation(); + if( pi != gdcm::PhotometricInterpretation::MONOCHROME1 && pi != gdcm::PhotometricInterpretation::MONOCHROME2 ) + { + // nothing to do: + return 0; + } + gdcm::PhotometricInterpretation invert_pi = gdcm::InvertPI(pi); + + gdcm::ImageChangePhotometricInterpretation pcfilt; + pcfilt.SetInput( image ); + pcfilt.SetPhotometricInterpretation( invert_pi ); + bool b = pcfilt.Change(); + if( !b ) + { + std::cerr << "Could not apply pcfilt: " << filename << std::endl; + return 1; + } + + // Create directory first: + const char subdir[] = "TestImageChangePhotometricInterpretation"; + std::string tmpdir = gdcm::Testing::GetTempDirectory( subdir ); + if( !gdcm::System::FileIsDirectory( tmpdir.c_str() ) ) + { + gdcm::System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + std::string outfilename = gdcm::Testing::GetTempFilename( filename, subdir ); + + gdcm::ImageWriter writer; + writer.SetFileName( outfilename.c_str() ); + //writer.SetFile( reader.GetFile() ); // increase test goal + writer.SetImage( pcfilt.GetOutput() ); + if( !writer.Write() ) + { + std::cerr << "Failed to write: " << outfilename << std::endl; + return 1; + } + + return 0; +} + +int TestImageChangePhotometricInterpretation(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestImageChangePhotometricInterpretationFunc(filename, true); + } + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestImageChangePhotometricInterpretationFunc( filename ); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageChangePhotometricInterpretation2.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageChangePhotometricInterpretation2.cxx new file mode 100644 index 0000000..76ecc69 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageChangePhotometricInterpretation2.cxx @@ -0,0 +1,92 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmImageChangePhotometricInterpretation.h" + +#include + +template +double diff(T rgb1[3], T rgb2[2]) +{ + double sum = 0; + for(int i = 0; i < 3; ++i) + sum += fabs((double)(rgb1[i] - rgb2[i])); + return sum < 1e-3 ? 0 : sum; + //return sum; +} + +int TestImageChangePhotometricInterpretation2(int argc, char *argv[]) +{ + //typedef float Type; + //typedef double Type; + //typedef int Type; + typedef unsigned char Type; + double sdiff = 0; + double max = 0; + int nerrors = 0; + int res = 0; + Type error[3] = {}; + Type error2[3] = {}; + Type yerror[3] = {}; + for(int r = 0; r < 256; ++r) + for(int g = 0; g < 256; ++g) + for(int b = 0; b < 256; ++b) + { + Type rgb[3]; + Type ybr[3] = {}; + Type rgb2[3] = {}; + rgb[0] = r; + rgb[1] = g; + rgb[1] = 128; + rgb[2] = b; + rgb[2] = 128; + // convert rgb 2 ybr: + //gdcm::ImageChangePhotometricInterpretation::RGB2YBR(ybr,rgb); + gdcm::ImageChangePhotometricInterpretation::YBR2RGB(ybr,rgb); + // convert back: + //gdcm::ImageChangePhotometricInterpretation::YBR2RGB(rgb2,ybr); + gdcm::ImageChangePhotometricInterpretation::RGB2YBR(rgb2,ybr); + if( memcmp(rgb,rgb2,3*sizeof(Type)) != 0 ) + { + //std::cerr << "Problem with R,G,B=" << r << "," << g << "," << b << + //" instead of " << (int)rgb2[0] << "," << (int)rgb2[1] << "," << (int)rgb2[2] << std::endl; + //std::cerr << "diff:" << diff(rgb,rgb2) << std::endl; + double d = diff(rgb,rgb2); + sdiff += d; + if( d > max ) + { + error2[0] = rgb2[0]; + error2[1] = rgb2[1]; + error2[2] = rgb2[2]; + error[0] = rgb[0]; + error[1] = rgb[1]; + error[2] = rgb[2]; + yerror[0] = ybr[0]; + yerror[1] = ybr[1]; + yerror[2] = ybr[2]; + } + max = std::max(d,max); + res = 1; + ++nerrors; + } + } + + std::cerr << "nerrors=" << nerrors << std::endl; + std::cerr << "sdiff=" << sdiff<< std::endl; + std::cerr << "max=" << max << std::endl; + std::cerr << "max error=" << (double)error[0] << "," << (double)error[1] << "," << (double)error[2] << std::endl; + std::cerr << "max error2=" << (double)error2[0] << "," << (double)error2[1] << "," << (double)error2[2] << std::endl; + std::cerr << "max yerror=" << (double)yerror[0] << "," << (double)yerror[1] << "," << (double)yerror[2] << std::endl; + + return res; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageChangePlanarConfiguration.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageChangePlanarConfiguration.cxx new file mode 100644 index 0000000..7a6b871 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageChangePlanarConfiguration.cxx @@ -0,0 +1,101 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmImageChangePlanarConfiguration.h" +#include "gdcmImageReader.h" +#include "gdcmImageWriter.h" +#include "gdcmTesting.h" +#include "gdcmSystem.h" + +int TestImageChangePlanarConfigurationFunc(const char *filename, bool verbose = false) +{ + (void)verbose; + gdcm::ImageReader reader; + reader.SetFileName( filename ); + if ( !reader.Read() ) + { + const gdcm::FileMetaInformation &header = reader.GetFile().GetHeader(); + gdcm::MediaStorage ms = header.GetMediaStorage(); + bool isImage = gdcm::MediaStorage::IsImage( ms ); + bool pixeldata = reader.GetFile().GetDataSet().FindDataElement( gdcm::Tag(0x7fe0,0x0010) ); + if( isImage && pixeldata ) + { + std::cout << "Could not read: " << filename << std::endl; + return 1; + } + return 0; + } + const gdcm::Image &image = reader.GetImage(); + + //unsigned int pc = image.GetPlanarConfiguration(); + + gdcm::ImageChangePlanarConfiguration pcfilt; + pcfilt.SetInput( image ); + bool b = pcfilt.Change(); + if( !b ) + { + unsigned short ba = reader.GetImage().GetPixelFormat().GetBitsAllocated(); + if( ba == 12 ) + { + std::cerr << "fail to change, but that's ok" << std::endl; + return 0; + } + std::cerr << "Could not apply pcfilt: " << filename << std::endl; + return 1; + } + + // Create directory first: + const char subdir[] = "TestImageChangePlanarConfiguration"; + std::string tmpdir = gdcm::Testing::GetTempDirectory( subdir ); + if( !gdcm::System::FileIsDirectory( tmpdir.c_str() ) ) + { + gdcm::System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + std::string outfilename = gdcm::Testing::GetTempFilename( filename, subdir ); + + gdcm::ImageWriter writer; + writer.SetFileName( outfilename.c_str() ); + //writer.SetFile( reader.GetFile() ); // increase test goal + writer.SetImage( pcfilt.GetOutput() ); + if( !writer.Write() ) + { + std::cerr << "Failed to write: " << outfilename << std::endl; + return 1; + } + + return 0; +} + +int TestImageChangePlanarConfiguration(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestImageChangePlanarConfigurationFunc(filename, true); + } + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestImageChangePlanarConfigurationFunc( filename ); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageChangeTransferSyntax1.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageChangeTransferSyntax1.cxx new file mode 100644 index 0000000..5807593 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageChangeTransferSyntax1.cxx @@ -0,0 +1,188 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmImageChangeTransferSyntax.h" +#include "gdcmImageReader.h" +#include "gdcmImageWriter.h" +#include "gdcmFilename.h" +#include "gdcmSystem.h" +#include "gdcmFileMetaInformation.h" +#include "gdcmTesting.h" +#include "gdcmByteSwap.h" +#include "gdcmImageChangePlanarConfiguration.h" + +namespace gdcm +{ + +int TestImageChangeTransferSyntaxJPEG(const char *filename, bool verbose = false) +{ + ImageReader reader; + reader.SetFileName( filename ); + if ( !reader.Read() ) + { + const FileMetaInformation &header = reader.GetFile().GetHeader(); + MediaStorage ms = header.GetMediaStorage(); + bool isImage = MediaStorage::IsImage( ms ); + bool pixeldata = reader.GetFile().GetDataSet().FindDataElement( Tag(0x7fe0,0x0010) ); + if( isImage && pixeldata ) + { + std::cerr << "Failed to read: " << filename << std::endl; + return 1; + } + else + { + // not an image give up... + std::cerr << "Problem with: " << filename << " but that's ok" << std::endl; + return 0; + } + } + + const gdcm::Image &image = reader.GetImage(); + int pc = image.GetPlanarConfiguration(); + + gdcm::ImageChangeTransferSyntax change; + change.SetTransferSyntax( gdcm::TransferSyntax::JPEGLosslessProcess14_1 ); + change.SetInput( image ); + bool b = change.Change(); + if( !b ) + { + unsigned short ba = reader.GetImage().GetPixelFormat().GetBitsAllocated(); + if( ba == 12 ) + { + std::cerr << "fail to change, but that's ok" << std::endl; + return 0; + } + std::cerr << "Could not change the Transfer Syntax: " << filename << std::endl; + return 1; + } + + // Create directory first: + const char subdir[] = "TestImageChangeTransferSyntax"; + std::string tmpdir = Testing::GetTempDirectory( subdir ); + if( !System::FileIsDirectory( tmpdir.c_str() ) ) + { + System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + std::string outfilename = Testing::GetTempFilename( filename, subdir ); + + ImageWriter writer; + writer.SetFileName( outfilename.c_str() ); + writer.SetFile( reader.GetFile() ); // increase test goal + writer.SetImage( change.GetOutput() ); + if( !writer.Write() ) + { + std::cerr << "Failed to write: " << outfilename << std::endl; + return 1; + } + + // Let's read that file back in ! + ImageReader reader2; + + reader2.SetFileName( outfilename.c_str() ); + if ( !reader2.Read() ) + { + std::cerr << "Could not even reread our generated file : " << outfilename << std::endl; + return 1; + } + // Check that after decompression we still find the same thing: + int res = 0; + gdcm::Image img = reader2.GetImage(); + // When recompressing: US-RGB-8-epicard.dcm, make sure to compute the md5 using the + // same original Planar Configuration... + if( (int)img.GetPlanarConfiguration() != pc ) + { + gdcm::ImageChangePlanarConfiguration icpc; + icpc.SetInput( reader2.GetImage() ); + icpc.SetPlanarConfiguration( pc ); + icpc.Change(); + img = icpc.GetOutput(); + } + //std::cerr << "Success to read image from file: " << filename << std::endl; + unsigned long len = img.GetBufferLength(); + char* buffer = new char[len]; + bool res2 = img.GetBuffer(buffer); + if( !res2 ) + { + std::cerr << "could not get buffer: " << outfilename << std::endl; + return 1; + } + // On big Endian system we have byteswapped the buffer (duh!) + // Since the md5sum is byte based there is now way it would detect + // that the file is written in big endian word, so comparing against + // a md5sum computed on LittleEndian would fail. Thus we need to + // byteswap (again!) here: +#ifdef GDCM_WORDS_BIGENDIAN + if( img.GetPixelFormat().GetBitsAllocated() == 16 ) + { + assert( !(len % 2) ); + assert( img.GetPhotometricInterpretation() == gdcm::PhotometricInterpretation::MONOCHROME1 + || img.GetPhotometricInterpretation() == gdcm::PhotometricInterpretation::MONOCHROME2 ); + gdcm::ByteSwap::SwapRangeFromSwapCodeIntoSystem( + (unsigned short*)buffer, gdcm::SwapCode::LittleEndian, len/2); + } +#endif + const char *ref = gdcm::Testing::GetMD5FromFile(filename); + + char digest[33]; + gdcm::Testing::ComputeMD5(buffer, len, digest); + if( !ref ) + { + // new regression image needs a md5 sum + std::cerr << "Missing md5 " << digest << " for: " << filename << std::endl; + //assert(0); + res = 1; + } + else if( strcmp(digest, ref) ) + { + std::cerr << "Problem reading image from: " << filename << std::endl; + std::cerr << "Found " << digest << " instead of " << ref << std::endl; + res = 1; + } + if(res) + { + std::cerr << "problem with: " << outfilename << std::endl; + } + if( verbose ) + { + std::cout << "file was written in: " << outfilename << std::endl; + } + + delete[] buffer; + return res; +} + +} // end namespace gdcm + +int TestImageChangeTransferSyntax1(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return gdcm::TestImageChangeTransferSyntaxJPEG(filename, true); + } + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += gdcm::TestImageChangeTransferSyntaxJPEG( filename ); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageChangeTransferSyntax2.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageChangeTransferSyntax2.cxx new file mode 100644 index 0000000..3b170c7 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageChangeTransferSyntax2.cxx @@ -0,0 +1,188 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmImageChangeTransferSyntax.h" +#include "gdcmImageReader.h" +#include "gdcmImageWriter.h" +#include "gdcmFilename.h" +#include "gdcmSystem.h" +#include "gdcmFileMetaInformation.h" +#include "gdcmTesting.h" +#include "gdcmByteSwap.h" +#include "gdcmImageChangePlanarConfiguration.h" + +namespace gdcm +{ + +int TestImageChangeTransferSyntaxJ2K(const char *filename, bool verbose = false) +{ + ImageReader reader; + reader.SetFileName( filename ); + if ( !reader.Read() ) + { + const FileMetaInformation &header = reader.GetFile().GetHeader(); + MediaStorage ms = header.GetMediaStorage(); + bool isImage = MediaStorage::IsImage( ms ); + bool pixeldata = reader.GetFile().GetDataSet().FindDataElement( Tag(0x7fe0,0x0010) ); + if( isImage && pixeldata ) + { + std::cerr << "Failed to read: " << filename << std::endl; + return 1; + } + else + { + // not an image give up... + std::cerr << "Problem with: " << filename << " but that's ok" << std::endl; + return 0; + } + } + + const gdcm::Image &image = reader.GetImage(); + int pc = image.GetPlanarConfiguration(); + + gdcm::ImageChangeTransferSyntax change; + change.SetTransferSyntax( gdcm::TransferSyntax::JPEG2000Lossless ); + change.SetInput( image ); + bool b = change.Change(); + if( !b ) + { + unsigned short ba = reader.GetImage().GetPixelFormat().GetBitsAllocated(); + if( ba == 12 ) + { + std::cerr << "fail to change, but that's ok: " << filename << std::endl; + return 0; + } + std::cerr << "Could not change the Transfer Syntax: " << filename << std::endl; + return 1; + } + + // Create directory first: + const char subdir[] = "TestImageChangeTransferSyntax2"; + std::string tmpdir = Testing::GetTempDirectory( subdir ); + if( !System::FileIsDirectory( tmpdir.c_str() ) ) + { + System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + std::string outfilename = Testing::GetTempFilename( filename, subdir ); + + ImageWriter writer; + writer.SetFileName( outfilename.c_str() ); + //writer.SetFile( reader.GetFile() ); // increase test goal + writer.SetImage( change.GetOutput() ); + if( !writer.Write() ) + { + std::cerr << "Failed to write: " << outfilename << std::endl; + return 1; + } + + // Let's read that file back in ! + ImageReader reader2; + + reader2.SetFileName( outfilename.c_str() ); + if ( !reader2.Read() ) + { + std::cerr << "Could not even reread our generated file : " << outfilename << std::endl; + return 1; + } + // Check that after decompression we still find the same thing: + int res = 0; + gdcm::Image img = reader2.GetImage(); + // When recompressing: US-RGB-8-epicard.dcm, make sure to compute the md5 using the + // same original Planar Configuration... + if( (int)img.GetPlanarConfiguration() != pc ) + { + gdcm::ImageChangePlanarConfiguration icpc; + icpc.SetInput( reader2.GetImage() ); + icpc.SetPlanarConfiguration( pc ); + icpc.Change(); + img = icpc.GetOutput(); + } + //std::cerr << "Success to read image from file: " << filename << std::endl; + unsigned long len = img.GetBufferLength(); + char* buffer = new char[len]; + bool res2 = img.GetBuffer(buffer); + if( !res2 ) + { + std::cerr << "could not get buffer: " << outfilename << std::endl; + return 1; + } + // On big Endian system we have byteswapped the buffer (duh!) + // Since the md5sum is byte based there is now way it would detect + // that the file is written in big endian word, so comparing against + // a md5sum computed on LittleEndian would fail. Thus we need to + // byteswap (again!) here: +#ifdef GDCM_WORDS_BIGENDIAN + if( img.GetPixelFormat().GetBitsAllocated() == 16 ) + { + assert( !(len % 2) ); + assert( img.GetPhotometricInterpretation() == gdcm::PhotometricInterpretation::MONOCHROME1 + || img.GetPhotometricInterpretation() == gdcm::PhotometricInterpretation::MONOCHROME2 ); + gdcm::ByteSwap::SwapRangeFromSwapCodeIntoSystem( + (unsigned short*)buffer, gdcm::SwapCode::LittleEndian, len/2); + } +#endif + const char *ref = gdcm::Testing::GetMD5FromFile(filename); + + char digest[33]; + gdcm::Testing::ComputeMD5(buffer, len, digest); + if( !ref ) + { + // new regression image needs a md5 sum + std::cerr << "Missing md5 " << digest << " for: " << filename << std::endl; + //assert(0); + res = 1; + } + else if( strcmp(digest, ref) ) + { + std::cerr << "Problem reading image from: " << filename << std::endl; + std::cerr << "Found " << digest << " instead of " << ref << std::endl; + res = 1; + } + if(res) + { + std::cerr << "problem with: " << outfilename << std::endl; + } + if( verbose ) + { + std::cout << "file was written in: " << outfilename << std::endl; + } + + delete[] buffer; + return res; +} + +} // end namespace gdcm + +int TestImageChangeTransferSyntax2(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return gdcm::TestImageChangeTransferSyntaxJ2K(filename, true); + } + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += gdcm::TestImageChangeTransferSyntaxJ2K( filename ); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageChangeTransferSyntax3.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageChangeTransferSyntax3.cxx new file mode 100644 index 0000000..901eec1 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageChangeTransferSyntax3.cxx @@ -0,0 +1,176 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmImageChangeTransferSyntax.h" +#include "gdcmImageReader.h" +#include "gdcmImageWriter.h" +#include "gdcmFilename.h" +#include "gdcmSystem.h" +#include "gdcmFileMetaInformation.h" +#include "gdcmTesting.h" +#include "gdcmByteSwap.h" + +namespace gdcm +{ + +int TestImageChangeTransferSyntaxRLE(const char *filename, bool verbose = false) +{ + ImageReader reader; + reader.SetFileName( filename ); + if ( !reader.Read() ) + { + const FileMetaInformation &header = reader.GetFile().GetHeader(); + MediaStorage ms = header.GetMediaStorage(); + bool isImage = MediaStorage::IsImage( ms ); + bool pixeldata = reader.GetFile().GetDataSet().FindDataElement( Tag(0x7fe0,0x0010) ); + if( isImage && pixeldata ) + { + std::cerr << "Failed to read: " << filename << std::endl; + return 1; + } + else + { + // not an image give up... + std::cerr << "Problem with: " << filename << " but that's ok" << std::endl; + return 0; + } + } + + const gdcm::Image &image = reader.GetImage(); + + gdcm::ImageChangeTransferSyntax change; + change.SetTransferSyntax( gdcm::TransferSyntax::RLELossless ); + change.SetInput( image ); + bool b = change.Change(); + if( !b ) + { + unsigned short ba = reader.GetImage().GetPixelFormat().GetBitsAllocated(); + if( ba == 12 ) + { + std::cerr << "fail to change, but that's ok" << std::endl; + return 0; + } + std::cerr << "Could not change the Transfer Syntax: " << filename << std::endl; + return 1; + } + + // Create directory first: + const char subdir[] = "TestImageChangeTransferSyntax3"; + std::string tmpdir = Testing::GetTempDirectory( subdir ); + if( !System::FileIsDirectory( tmpdir.c_str() ) ) + { + System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + std::string outfilename = Testing::GetTempFilename( filename, subdir ); + + ImageWriter writer; + writer.SetFileName( outfilename.c_str() ); + //writer.SetFile( reader.GetFile() ); // increase test goal + writer.SetImage( change.GetOutput() ); + if( !writer.Write() ) + { + std::cerr << "Failed to write: " << outfilename << std::endl; + return 1; + } + + // Let's read that file back in ! + ImageReader reader2; + + reader2.SetFileName( outfilename.c_str() ); + if ( !reader2.Read() ) + { + std::cerr << "Could not even reread our generated file : " << outfilename << std::endl; + return 1; + } + // Check that after decompression we still find the same thing: + int res = 0; + const gdcm::Image &img = reader2.GetImage(); + //std::cerr << "Success to read image from file: " << filename << std::endl; + unsigned long len = img.GetBufferLength(); + char* buffer = new char[len]; + bool res2 = img.GetBuffer(buffer); + if( !res2 ) + { + std::cerr << "could not get buffer: " << outfilename << std::endl; + return 1; + } + // On big Endian system we have byteswapped the buffer (duh!) + // Since the md5sum is byte based there is now way it would detect + // that the file is written in big endian word, so comparing against + // a md5sum computed on LittleEndian would fail. Thus we need to + // byteswap (again!) here: +#ifdef GDCM_WORDS_BIGENDIAN + if( img.GetPixelFormat().GetBitsAllocated() == 16 ) + { + assert( !(len % 2) ); + assert( img.GetPhotometricInterpretation() == gdcm::PhotometricInterpretation::MONOCHROME1 + || img.GetPhotometricInterpretation() == gdcm::PhotometricInterpretation::MONOCHROME2 ); + gdcm::ByteSwap::SwapRangeFromSwapCodeIntoSystem( + (unsigned short*)buffer, gdcm::SwapCode::LittleEndian, len/2); + } +#endif + const char *ref = gdcm::Testing::GetMD5FromFile(filename); + + char digest[33]; + gdcm::Testing::ComputeMD5(buffer, len, digest); + if( !ref ) + { + // new regression image needs a md5 sum + std::cerr << "Missing md5 " << digest << " for: " << filename << std::endl; + //assert(0); + res = 1; + } + else if( strcmp(digest, ref) ) + { + std::cerr << "Problem reading image from: " << filename << std::endl; + std::cerr << "Found " << digest << " instead of " << ref << std::endl; + res = 1; + } + if(res) + { + std::cerr << "problem with: " << outfilename << std::endl; + } + if( verbose ) + { + std::cout << "file was written in: " << outfilename << std::endl; + } + + delete[] buffer; + return res; +} + +} // end namespace gdcm + +int TestImageChangeTransferSyntax3(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return gdcm::TestImageChangeTransferSyntaxRLE(filename, true); + } + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += gdcm::TestImageChangeTransferSyntaxRLE( filename ); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageChangeTransferSyntax4.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageChangeTransferSyntax4.cxx new file mode 100644 index 0000000..7b73c1d --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageChangeTransferSyntax4.cxx @@ -0,0 +1,180 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmImageChangeTransferSyntax.h" +#include "gdcmImageReader.h" +#include "gdcmImageWriter.h" +#include "gdcmFilename.h" +#include "gdcmSystem.h" +#include "gdcmFileMetaInformation.h" +#include "gdcmTesting.h" +#include "gdcmByteSwap.h" + +namespace gdcm +{ + +int TestImageChangeTransferSyntaxRAW(const char *filename, bool verbose = false) +{ + ImageReader reader; + reader.SetFileName( filename ); + if ( !reader.Read() ) + { + const FileMetaInformation &header = reader.GetFile().GetHeader(); + MediaStorage ms = header.GetMediaStorage(); + bool isImage = MediaStorage::IsImage( ms ); + bool pixeldata = reader.GetFile().GetDataSet().FindDataElement( Tag(0x7fe0,0x0010) ); + if( isImage && pixeldata ) + { + std::cerr << "Failed to read: " << filename << std::endl; + return 1; + } + else + { + // not an image give up... + std::cerr << "Problem with: " << filename << " but that's ok" << std::endl; + return 0; + } + } + + const gdcm::Image &image = reader.GetImage(); + const TransferSyntax &ts = reader.GetFile().GetHeader().GetDataSetTransferSyntax(); + + gdcm::ImageChangeTransferSyntax change; + if( ts == gdcm::TransferSyntax::ExplicitVRLittleEndian ) + { + // TODO: I think that duplicate goals of TestImageWriter2 ... + //change.SetTransferSyntax( gdcm::TransferSyntax::ImplicitVRLittleEndian ); + change.SetTransferSyntax( gdcm::TransferSyntax::ExplicitVRLittleEndian ); + } + else + { + change.SetTransferSyntax( gdcm::TransferSyntax::ExplicitVRLittleEndian ); + } + change.SetInput( image ); + bool b = change.Change(); + if( !b ) + { + std::cerr << "Could not change the Transfer Syntax: " << filename << std::endl; + return 1; + } + + // Create directory first: + const char subdir[] = "TestImageChangeTransferSyntax4"; + std::string tmpdir = Testing::GetTempDirectory( subdir ); + if( !System::FileIsDirectory( tmpdir.c_str() ) ) + { + System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + std::string outfilename = Testing::GetTempFilename( filename, subdir ); + + ImageWriter writer; + writer.SetFileName( outfilename.c_str() ); + writer.SetFile( reader.GetFile() ); // increase test goal + writer.SetImage( change.GetOutput() ); + if( !writer.Write() ) + { + std::cerr << "Failed to write: " << outfilename << std::endl; + return 1; + } + + // Let's read that file back in ! + ImageReader reader2; + + reader2.SetFileName( outfilename.c_str() ); + if ( !reader2.Read() ) + { + std::cerr << "Could not even reread our generated file : " << outfilename << std::endl; + return 1; + } + // Check that after decompression we still find the same thing: + int res = 0; + const gdcm::Image &img = reader2.GetImage(); + //std::cerr << "Success to read image from file: " << filename << std::endl; + unsigned long len = img.GetBufferLength(); + char* buffer = new char[len]; + bool res2 = img.GetBuffer(buffer); + if( !res2 ) + { + std::cerr << "could not get buffer: " << outfilename << std::endl; + return 1; + } + // On big Endian system we have byteswapped the buffer (duh!) + // Since the md5sum is byte based there is now way it would detect + // that the file is written in big endian word, so comparing against + // a md5sum computed on LittleEndian would fail. Thus we need to + // byteswap (again!) here: +#ifdef GDCM_WORDS_BIGENDIAN + if( img.GetPixelFormat().GetBitsAllocated() == 16 ) + { + assert( !(len % 2) ); + assert( img.GetPhotometricInterpretation() == gdcm::PhotometricInterpretation::MONOCHROME1 + || img.GetPhotometricInterpretation() == gdcm::PhotometricInterpretation::MONOCHROME2 ); + gdcm::ByteSwap::SwapRangeFromSwapCodeIntoSystem( + (unsigned short*)buffer, gdcm::SwapCode::LittleEndian, len/2); + } +#endif + const char *ref = gdcm::Testing::GetMD5FromFile(filename); + + char digest[33]; + gdcm::Testing::ComputeMD5(buffer, len, digest); + if( !ref ) + { + // new regression image needs a md5 sum + std::cerr << "Missing md5 " << digest << " for: " << filename << std::endl; + //assert(0); + res = 1; + } + else if( strcmp(digest, ref) ) + { + std::cerr << "Problem reading image from: " << filename << std::endl; + std::cerr << "Found " << digest << " instead of " << ref << std::endl; + res = 1; + } + if(res) + { + std::cerr << "problem with: " << outfilename << std::endl; + } + if( verbose ) + { + std::cout << "file was written in: " << outfilename << std::endl; + } + + delete[] buffer; + return res; +} + +} // end namespace gdcm + +int TestImageChangeTransferSyntax4(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return gdcm::TestImageChangeTransferSyntaxRAW(filename, true); + } + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += gdcm::TestImageChangeTransferSyntaxRAW( filename ); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageChangeTransferSyntax5.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageChangeTransferSyntax5.cxx new file mode 100644 index 0000000..ae48505 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageChangeTransferSyntax5.cxx @@ -0,0 +1,170 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmImageChangeTransferSyntax.h" +#include "gdcmImageReader.h" +#include "gdcmImageWriter.h" +#include "gdcmFilename.h" +#include "gdcmSystem.h" +#include "gdcmFileMetaInformation.h" +#include "gdcmTesting.h" +#include "gdcmByteSwap.h" + +namespace gdcm +{ + +int TestImageChangeTransferSyntaxJPEGLS(const char *filename, bool verbose = false) +{ + ImageReader reader; + reader.SetFileName( filename ); + if ( !reader.Read() ) + { + const FileMetaInformation &header = reader.GetFile().GetHeader(); + MediaStorage ms = header.GetMediaStorage(); + bool isImage = MediaStorage::IsImage( ms ); + bool pixeldata = reader.GetFile().GetDataSet().FindDataElement( Tag(0x7fe0,0x0010) ); + if( isImage && pixeldata ) + { + std::cerr << "Failed to read: " << filename << std::endl; + return 1; + } + else + { + // not an image give up... + std::cerr << "Problem with: " << filename << " but that's ok" << std::endl; + return 0; + } + } + + const gdcm::Image &image = reader.GetImage(); + + gdcm::ImageChangeTransferSyntax change; + change.SetTransferSyntax( gdcm::TransferSyntax::JPEGLSLossless ); + change.SetInput( image ); + bool b = change.Change(); + if( !b ) + { + std::cerr << "Could not change the Transfer Syntax: " << filename << std::endl; + return 1; + } + + // Create directory first: + const char subdir[] = "TestImageChangeTransferSyntax5"; + std::string tmpdir = Testing::GetTempDirectory( subdir ); + if( !System::FileIsDirectory( tmpdir.c_str() ) ) + { + System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + std::string outfilename = Testing::GetTempFilename( filename, subdir ); + + ImageWriter writer; + writer.SetFileName( outfilename.c_str() ); + writer.SetFile( reader.GetFile() ); // increase test goal + writer.SetImage( change.GetOutput() ); + if( !writer.Write() ) + { + std::cerr << "Failed to write: " << outfilename << std::endl; + return 1; + } + + // Let's read that file back in ! + ImageReader reader2; + + reader2.SetFileName( outfilename.c_str() ); + if ( !reader2.Read() ) + { + std::cerr << "Could not even reread our generated file : " << outfilename << std::endl; + return 1; + } + // Check that after decompression we still find the same thing: + int res = 0; + const gdcm::Image &img = reader2.GetImage(); + //std::cerr << "Success to read image from file: " << filename << std::endl; + unsigned long len = img.GetBufferLength(); + char* buffer = new char[len]; + bool res2 = img.GetBuffer(buffer); + if( !res2 ) + { + std::cerr << "could not get buffer: " << outfilename << std::endl; + return 1; + } + // On big Endian system we have byteswapped the buffer (duh!) + // Since the md5sum is byte based there is now way it would detect + // that the file is written in big endian word, so comparing against + // a md5sum computed on LittleEndian would fail. Thus we need to + // byteswap (again!) here: +#ifdef GDCM_WORDS_BIGENDIAN + if( img.GetPixelFormat().GetBitsAllocated() == 16 ) + { + assert( !(len % 2) ); + assert( img.GetPhotometricInterpretation() == gdcm::PhotometricInterpretation::MONOCHROME1 + || img.GetPhotometricInterpretation() == gdcm::PhotometricInterpretation::MONOCHROME2 ); + gdcm::ByteSwap::SwapRangeFromSwapCodeIntoSystem( + (unsigned short*)buffer, gdcm::SwapCode::LittleEndian, len/2); + } +#endif + const char *ref = gdcm::Testing::GetMD5FromFile(filename); + + char digest[33]; + gdcm::Testing::ComputeMD5(buffer, len, digest); + if( !ref ) + { + // new regression image needs a md5 sum + std::cerr << "Missing md5 " << digest << " for: " << filename << std::endl; + //assert(0); + res = 1; + } + else if( strcmp(digest, ref) ) + { + std::cerr << "Problem reading image from: " << filename << std::endl; + std::cerr << "Found " << digest << " instead of " << ref << std::endl; + res = 1; + } + if(res) + { + std::cerr << "problem with: " << outfilename << std::endl; + } + if( verbose ) + { + std::cout << "file was written in: " << outfilename << std::endl; + } + + delete[] buffer; + return res; +} + +} // end namespace gdcm + +int TestImageChangeTransferSyntax5(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return gdcm::TestImageChangeTransferSyntaxJPEGLS(filename, true); + } + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += gdcm::TestImageChangeTransferSyntaxJPEGLS( filename ); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageChangeTransferSyntax6.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageChangeTransferSyntax6.cxx new file mode 100644 index 0000000..b224c0c --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageChangeTransferSyntax6.cxx @@ -0,0 +1,171 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmImageChangeTransferSyntax.h" +#include "gdcmImageReader.h" +#include "gdcmImageWriter.h" +#include "gdcmFilename.h" +#include "gdcmSystem.h" +#include "gdcmFileMetaInformation.h" +#include "gdcmTesting.h" +#include "gdcmByteSwap.h" + +namespace gdcm +{ + +int TestImageChangeTransferSyntaxRAWBE(const char *filename, bool verbose = false) +{ + ImageReader reader; + reader.SetFileName( filename ); + if ( !reader.Read() ) + { + const FileMetaInformation &header = reader.GetFile().GetHeader(); + MediaStorage ms = header.GetMediaStorage(); + bool isImage = MediaStorage::IsImage( ms ); + bool pixeldata = reader.GetFile().GetDataSet().FindDataElement( Tag(0x7fe0,0x0010) ); + if( isImage && pixeldata ) + { + std::cerr << "Failed to read: " << filename << std::endl; + return 1; + } + else + { + // not an image give up... + std::cerr << "Problem with: " << filename << " but that's ok" << std::endl; + return 0; + } + } + + const gdcm::Image &image = reader.GetImage(); + //const TransferSyntax &ts = reader.GetFile().GetHeader().GetDataSetTransferSyntax(); + + gdcm::ImageChangeTransferSyntax change; + change.SetTransferSyntax( gdcm::TransferSyntax::ExplicitVRBigEndian ); + change.SetInput( image ); + bool b = change.Change(); + if( !b ) + { + std::cerr << "Could not change the Transfer Syntax: " << filename << std::endl; + return 1; + } + + // Create directory first: + const char subdir[] = "TestImageChangeTransferSyntax6"; + std::string tmpdir = Testing::GetTempDirectory( subdir ); + if( !System::FileIsDirectory( tmpdir.c_str() ) ) + { + System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + std::string outfilename = Testing::GetTempFilename( filename, subdir ); + + ImageWriter writer; + writer.SetFileName( outfilename.c_str() ); + writer.SetFile( reader.GetFile() ); // increase test goal + writer.SetImage( change.GetOutput() ); + if( !writer.Write() ) + { + std::cerr << "Failed to write: " << outfilename << std::endl; + return 1; + } + + // Let's read that file back in ! + ImageReader reader2; + + reader2.SetFileName( outfilename.c_str() ); + if ( !reader2.Read() ) + { + std::cerr << "Could not even reread our generated file : " << outfilename << std::endl; + return 1; + } + // Check that after decompression we still find the same thing: + int res = 0; + const gdcm::Image &img = reader2.GetImage(); + //std::cerr << "Success to read image from file: " << filename << std::endl; + unsigned long len = img.GetBufferLength(); + char* buffer = new char[len]; + bool res2 = img.GetBuffer(buffer); + if( !res2 ) + { + std::cerr << "could not get buffer: " << outfilename << std::endl; + return 1; + } + // On big Endian system we have byteswapped the buffer (duh!) + // Since the md5sum is byte based there is now way it would detect + // that the file is written in big endian word, so comparing against + // a md5sum computed on LittleEndian would fail. Thus we need to + // byteswap (again!) here: +#ifdef GDCM_WORDS_BIGENDIAN + if( img.GetPixelFormat().GetBitsAllocated() == 16 ) + { + assert( !(len % 2) ); + assert( img.GetPhotometricInterpretation() == gdcm::PhotometricInterpretation::MONOCHROME1 + || img.GetPhotometricInterpretation() == gdcm::PhotometricInterpretation::MONOCHROME2 ); + gdcm::ByteSwap::SwapRangeFromSwapCodeIntoSystem( + (unsigned short*)buffer, gdcm::SwapCode::LittleEndian, len/2); + } +#endif + const char *ref = gdcm::Testing::GetMD5FromFile(filename); + + char digest[33]; + gdcm::Testing::ComputeMD5(buffer, len, digest); + if( !ref ) + { + // new regression image needs a md5 sum + std::cerr << "Missing md5 " << digest << " for: " << filename << std::endl; + //assert(0); + res = 1; + } + else if( strcmp(digest, ref) ) + { + std::cerr << "Problem reading image from: " << filename << std::endl; + std::cerr << "Found " << digest << " instead of " << ref << std::endl; + res = 1; + } + if(res) + { + std::cerr << "problem with: " << outfilename << std::endl; + } + if( verbose ) + { + std::cout << "file was written in: " << outfilename << std::endl; + } + + delete[] buffer; + return res; +} + +} // end namespace gdcm + +int TestImageChangeTransferSyntax6(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return gdcm::TestImageChangeTransferSyntaxRAWBE(filename, true); + } + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += gdcm::TestImageChangeTransferSyntaxRAWBE( filename ); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageChangeTransferSyntax7.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageChangeTransferSyntax7.cxx new file mode 100644 index 0000000..59b7bfd --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageChangeTransferSyntax7.cxx @@ -0,0 +1,213 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmImageChangeTransferSyntax.h" +#include "gdcmImageReader.h" +#include "gdcmImageWriter.h" +#include "gdcmFilename.h" +#include "gdcmSystem.h" +#include "gdcmFileMetaInformation.h" +#include "gdcmTesting.h" +#include "gdcmByteSwap.h" + +namespace gdcm +{ + +int TestImageChangeTransferSyntaxIM2RAWBE(const char *filename, bool verbose = false) +{ + ImageReader reader; + reader.SetFileName( filename ); + if ( !reader.Read() ) + { + const FileMetaInformation &header = reader.GetFile().GetHeader(); + MediaStorage ms = header.GetMediaStorage(); + bool isImage = MediaStorage::IsImage( ms ); + bool pixeldata = reader.GetFile().GetDataSet().FindDataElement( Tag(0x7fe0,0x0010) ); + if( isImage && pixeldata ) + { + std::cerr << "Failed to read: " << filename << std::endl; + return 1; + } + else + { + // not an image give up... + std::cerr << "Problem with: " << filename << " but that's ok" << std::endl; + return 0; + } + } + + const gdcm::Image &image = reader.GetImage(); + + gdcm::ImageChangeTransferSyntax change; + change.SetTransferSyntax( gdcm::TransferSyntax::ImplicitVRLittleEndian ); + change.SetInput( image ); + bool b = change.Change(); + if( !b ) + { + std::cerr << "Could not change the Transfer Syntax: " << filename << std::endl; + return 1; + } + + // Create directory first: + const char subdir[] = "TestImageChangeTransferSyntax7"; + std::string tmpdir = Testing::GetTempDirectory( subdir ); + if( !System::FileIsDirectory( tmpdir.c_str() ) ) + { + System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + std::string outfilename = Testing::GetTempFilename( filename, subdir ); + + ImageWriter writer; + writer.SetFileName( outfilename.c_str() ); + writer.SetFile( reader.GetFile() ); // increase test goal + writer.SetImage( change.GetOutput() ); + if( !writer.Write() ) + { + std::cerr << "Failed to write: " << outfilename << std::endl; + return 1; + } + + // Let's read that file back in ! + ImageReader reader2; + + reader2.SetFileName( outfilename.c_str() ); + if ( !reader2.Read() ) + { + std::cerr << "Could not even reread our generated file : " << outfilename << std::endl; + return 1; + } + + gdcm::ImageChangeTransferSyntax change2; + change2.SetTransferSyntax( gdcm::TransferSyntax::ExplicitVRBigEndian ); + const gdcm::Image &image2 = reader2.GetImage(); + change2.SetInput( image2 ); + b = change2.Change(); + if( !b ) + { + std::cerr << "Could not change the Transfer Syntax: " << outfilename << std::endl; + return 1; + } + + // Create directory first: + const char subdir2[] = "TestImageChangeTransferSyntax7_2"; + std::string tmpdir2 = Testing::GetTempDirectory( subdir2 ); + if( !System::FileIsDirectory( tmpdir2.c_str() ) ) + { + System::MakeDirectory( tmpdir2.c_str() ); + //return 1; + } + + std::string outfilename2 = Testing::GetTempFilename( filename, subdir2 ); + + ImageWriter writer2; + writer2.SetFileName( outfilename2.c_str() ); + writer2.SetFile( reader2.GetFile() ); // increase test goal + writer2.SetImage( change2.GetOutput() ); + if( !writer2.Write() ) + { + std::cerr << "Failed to write: " << outfilename2 << std::endl; + return 1; + } + + // Let's read that file back in ! + ImageReader reader3; + + reader3.SetFileName( outfilename2.c_str() ); + if ( !reader3.Read() ) + { + std::cerr << "Could not even reread our generated file : " << outfilename2 << std::endl; + return 1; + } + + // Check that after decompression we still find the same thing: + int res = 0; + const gdcm::Image &img = reader3.GetImage(); + //std::cerr << "Success to read image from file: " << filename << std::endl; + unsigned long len = img.GetBufferLength(); + char* buffer = new char[len]; + bool res2 = img.GetBuffer(buffer); + if( !res2 ) + { + std::cerr << "could not get buffer: " << outfilename << std::endl; + return 1; + } + // On big Endian system we have byteswapped the buffer (duh!) + // Since the md5sum is byte based there is now way it would detect + // that the file is written in big endian word, so comparing against + // a md5sum computed on LittleEndian would fail. Thus we need to + // byteswap (again!) here: +#ifdef GDCM_WORDS_BIGENDIAN + if( img.GetPixelFormat().GetBitsAllocated() == 16 ) + { + assert( !(len % 2) ); + assert( img.GetPhotometricInterpretation() == gdcm::PhotometricInterpretation::MONOCHROME1 + || img.GetPhotometricInterpretation() == gdcm::PhotometricInterpretation::MONOCHROME2 ); + gdcm::ByteSwap::SwapRangeFromSwapCodeIntoSystem( + (unsigned short*)buffer, gdcm::SwapCode::LittleEndian, len/2); + } +#endif + const char *ref = gdcm::Testing::GetMD5FromFile(filename); + + char digest[33]; + gdcm::Testing::ComputeMD5(buffer, len, digest); + if( !ref ) + { + // new regression image needs a md5 sum + std::cerr << "Missing md5 " << digest << " for: " << filename << std::endl; + //assert(0); + res = 1; + } + else if( strcmp(digest, ref) ) + { + std::cerr << "Problem reading image from: " << filename << std::endl; + std::cerr << "Found " << digest << " instead of " << ref << std::endl; + res = 1; + } + if(res) + { + std::cerr << "problem with: " << outfilename2 << std::endl; + } + if( verbose ) + { + std::cout << "file was written in: " << outfilename2 << std::endl; + } + + delete[] buffer; + return res; +} + +} // end namespace gdcm + +int TestImageChangeTransferSyntax7(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return gdcm::TestImageChangeTransferSyntaxIM2RAWBE(filename, true); + } + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += gdcm::TestImageChangeTransferSyntaxIM2RAWBE( filename ); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageCodec.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageCodec.cxx new file mode 100644 index 0000000..1220978 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageCodec.cxx @@ -0,0 +1,22 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmImageCodec.h" + +int TestImageCodec(int argc, char *argv[]) +{ + (void)argc; + (void)argv; + + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageConverter.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageConverter.cxx new file mode 100644 index 0000000..c8d86ca --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageConverter.cxx @@ -0,0 +1,22 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmImageConverter.h" + +int TestImageConverter(int argc, char *argv[]) +{ + (void)argc; + (void)argv; + + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageFragmentSplitter.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageFragmentSplitter.cxx new file mode 100644 index 0000000..90c5604 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageFragmentSplitter.cxx @@ -0,0 +1,129 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmImageFragmentSplitter.h" +#include "gdcmTesting.h" +#include "gdcmSystem.h" +#include "gdcmImageReader.h" +#include "gdcmImageWriter.h" +#include "gdcmTransferSyntax.h" +#include "gdcmImage.h" +#include "gdcmFilename.h" + +int TestImageFragmentSplitterFunc(const char *filename, bool verbose = false) +{ + gdcm::ImageReader reader; + reader.SetFileName( filename ); + if ( !reader.Read() ) + { + const gdcm::FileMetaInformation &header = reader.GetFile().GetHeader(); + gdcm::MediaStorage ms = header.GetMediaStorage(); + bool isImage = gdcm::MediaStorage::IsImage( ms ); + if( isImage ) + { + if( reader.GetFile().GetDataSet().FindDataElement( gdcm::Tag(0x7fe0,0x0010) ) ) + { + std::cerr << "Could not read: " << filename << std::endl; + return 1; + } + } + return 0; + } + const gdcm::Image &image = reader.GetImage(); + const unsigned int *dims = image.GetDimensions(); + if( dims[2] != 1 ) + { + return 0; // nothing to do + } + const gdcm::File &file = reader.GetFile(); + const gdcm::FileMetaInformation &header = file.GetHeader(); + //gdcm::MediaStorage ms = header.GetMediaStorage(); + if( header.GetDataSetTransferSyntax() == gdcm::TransferSyntax::ImplicitVRLittleEndian + || header.GetDataSetTransferSyntax() == gdcm::TransferSyntax::ImplicitVRBigEndianPrivateGE + || header.GetDataSetTransferSyntax() == gdcm::TransferSyntax::ExplicitVRLittleEndian + || header.GetDataSetTransferSyntax() == gdcm::TransferSyntax::DeflatedExplicitVRLittleEndian + || header.GetDataSetTransferSyntax() == gdcm::TransferSyntax::ExplicitVRBigEndian + ) + { + return 0; // nothing to do + } + + gdcm::ImageFragmentSplitter splitter; + splitter.SetInput( image ); + splitter.SetFragmentSizeMax( 65536 ); + bool b = splitter.Split(); + if( !b ) + { + const gdcm::DataElement &pixeldata = file.GetDataSet().GetDataElement( gdcm::Tag(0x7fe0,0x0010) ); + const gdcm::SequenceOfFragments* sqf = pixeldata.GetSequenceOfFragments(); + if( sqf && dims[2] == 1 ) + { + return 0; + } + gdcm::Filename fn( filename ); + if( fn.GetName() == std::string("JPEGDefinedLengthSequenceOfFragments.dcm" ) ) + { + // JPEG Fragments are packed in a VR:OB Attribute + return 0; + } + std::cerr << "Could not apply splitter: " << filename << std::endl; + return 1; + } + + // Create directory first: + const char subdir[] = "TestImageFragmentSplitter"; + std::string tmpdir = gdcm::Testing::GetTempDirectory( subdir ); + if( !gdcm::System::FileIsDirectory( tmpdir.c_str() ) ) + { + gdcm::System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + std::string outfilename = gdcm::Testing::GetTempFilename( filename, subdir ); + + gdcm::ImageWriter writer; + writer.SetFileName( outfilename.c_str() ); + //writer.SetFile( reader.GetFile() ); // increase test goal + writer.SetImage( splitter.GetOutput() ); + if( !writer.Write() ) + { + std::cerr << "Failed to write: " << outfilename << std::endl; + return 1; + } + if( verbose ) + std::cout << "Success to write: " << outfilename << std::endl; + + return 0; +} + +int TestImageFragmentSplitter(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestImageFragmentSplitterFunc(filename, true); + } + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestImageFragmentSplitterFunc( filename ); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageHelper.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageHelper.cxx new file mode 100644 index 0000000..1a6116f --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageHelper.cxx @@ -0,0 +1,106 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmImageHelper.h" +#include "gdcmMediaStorage.h" +#include "gdcmDataSet.h" +#include "gdcmAttribute.h" +#include "gdcmDirectionCosines.h" + +int TestImageHelper(int, char *[]) +{ +// gdcm::ImageHelper sh; + const double pos[] = { 0,0,0, + 1,1,1}; + //const double answer[3] = {1,1,1}; + + std::vector impos(pos,pos+6); + std::vector spacing; + spacing.resize(3); + if( !gdcm::ImageHelper::ComputeSpacingFromImagePositionPatient(impos, spacing) ) + { + return 1; + } + std::cout << spacing[0] << std::endl; + std::cout << spacing[1] << std::endl; + std::cout << spacing[2] << std::endl; + + + std::vector dircos; + // make it an invalid call + dircos.resize(6); + dircos[0] = 1; + dircos[1] = 0; + dircos[2] = 0; + dircos[3] = 1; + dircos[4] = 0; + dircos[5] = 0; + // Try SC +{ + gdcm::MediaStorage ms( gdcm::MediaStorage::SecondaryCaptureImageStorage ); + gdcm::DataSet ds; + + gdcm::DataElement de( gdcm::Tag(0x0008, 0x0016) ); + const char* msstr = gdcm::MediaStorage::GetMSString(ms); + de.SetByteValue( msstr, (uint32_t)strlen(msstr) ); + de.SetVR( gdcm::Attribute<0x0008, 0x0016>::GetVR() ); + ds.Insert( de ); + + // Since SC this is a no-op + gdcm::ImageHelper::SetDirectionCosinesValue( ds, dircos ); + + // previous call removed the attribute + gdcm::Tag iop(0x0020,0x0037); + if( ds.FindDataElement( iop ) ) return 1; +} + + // MR now +{ + gdcm::MediaStorage ms( gdcm::MediaStorage::MRImageStorage ); + gdcm::DataSet ds; + + gdcm::DataElement de( gdcm::Tag(0x0008, 0x0016) ); + const char* msstr = gdcm::MediaStorage::GetMSString(ms); + de.SetByteValue( msstr, (uint32_t)strlen(msstr) ); + de.SetVR( gdcm::Attribute<0x0008, 0x0016>::GetVR() ); + ds.Insert( de ); + + // Since SC this is a no-op + gdcm::ImageHelper::SetDirectionCosinesValue( ds, dircos ); + + // previous call should not have replaced tag with default value + gdcm::Tag iop(0x0020,0x0037); + if( !ds.FindDataElement( iop ) ) return 1; + + const gdcm::DataElement &iopde = ds.GetDataElement( iop ); + gdcm::Attribute<0x0020,0x0037> at; + at.SetFromDataElement( iopde ); + + dircos.clear(); + dircos.push_back( at.GetValue(0) ); + dircos.push_back( at.GetValue(1) ); + dircos.push_back( at.GetValue(2) ); + dircos.push_back( at.GetValue(3) ); + dircos.push_back( at.GetValue(4) ); + dircos.push_back( at.GetValue(5) ); + gdcm::DirectionCosines dc( &dircos[0] ); + if (!dc.IsValid()) return 1; + + + if ( (at.GetValue(0) != 1) || (at.GetValue(1) != 0) || (at.GetValue(2) != 0) || + (at.GetValue(3) != 0) || (at.GetValue(4) != 1) || (at.GetValue(5) != 0) ) return 1; + +} + + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageReader.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageReader.cxx new file mode 100644 index 0000000..c7adf21 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageReader.cxx @@ -0,0 +1,153 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmImageReader.h" +#include "gdcmFileMetaInformation.h" +#include "gdcmSystem.h" +#include "gdcmFilename.h" +#include "gdcmByteSwap.h" +#include "gdcmTrace.h" +#include "gdcmTesting.h" + +int TestImageRead(const char* filename, bool verbose = false, bool lossydump = false) +{ + if( verbose ) + std::cerr << "Reading: " << filename << std::endl; + gdcm::ImageReader reader; + + reader.SetFileName( filename ); + if ( reader.Read() ) + { + int res = 0; + const gdcm::Image &img = reader.GetImage(); + //std::cerr << "Success to read image from file: " << filename << std::endl; + unsigned long len = img.GetBufferLength(); + if ( lossydump ) + { + int lossy = img.IsLossy(); + std::cout << lossy << "," << filename << std::endl; + } + int reflossy = gdcm::Testing::GetLossyFlagFromFile( filename ); + if( reflossy == -1 ) + { + std::cerr << "Missing lossy flag for: " << filename << std::endl; + return 1; + } + if( img.IsLossy() != (reflossy > 0 ? true : false) )//vs10 has a stupid bool/int cast warning + { + std::cerr << "Inconsistency for lossy flag for: " << filename << std::endl; + return 1; + } + char* buffer = new char[len]; + bool res2 = img.GetBuffer(buffer); + if( !res2 ) + { + std::cerr << "res2 failure: " << filename << std::endl; + return 1; + } + // On big Endian system we have byteswapped the buffer (duh!) + // Since the md5sum is byte based there is now way it would detect + // that the file is written in big endian word, so comparing against + // a md5sum computed on LittleEndian would fail. Thus we need to + // byteswap (again!) here: +#ifdef GDCM_WORDS_BIGENDIAN + if( img.GetPixelFormat().GetBitsAllocated() == 16 ) + { + assert( !(len % 2) ); + // gdcm-US-ALOKA is a 16 bits image with PALETTE + //assert( img.GetPhotometricInterpretation() == gdcm::PhotometricInterpretation::MONOCHROME1 + // || img.GetPhotometricInterpretation() == gdcm::PhotometricInterpretation::MONOCHROME2 ); + gdcm::ByteSwap::SwapRangeFromSwapCodeIntoSystem( + (unsigned short*)buffer, gdcm::SwapCode::LittleEndian, len/2); + } +#endif + const char *ref = gdcm::Testing::GetMD5FromFile(filename); + + char digest[33]; + gdcm::Testing::ComputeMD5(buffer, len, digest); + if( verbose ) + { + std::cout << "ref=" << ref << std::endl; + std::cout << "md5=" << digest << std::endl; + } + if( !ref ) + { + // new regression image needs a md5 sum + std::cout << "Missing md5 " << digest << " for: " << filename << std::endl; + //assert(0); + res = 1; + } + else if( strcmp(digest, ref) ) + { + std::cerr << "Problem reading image from: " << filename << std::endl; + std::cerr << "Found " << digest << " instead of " << ref << std::endl; + res = 1; +#if 0 + std::ofstream debug("/tmp/dump.gray",std::ios::binary); + debug.write(buffer, len); + debug.close(); + //assert(0); +#endif + } + delete[] buffer; + return res; + } + + const gdcm::FileMetaInformation &header = reader.GetFile().GetHeader(); + gdcm::MediaStorage ms = header.GetMediaStorage(); + bool isImage = gdcm::MediaStorage::IsImage( ms ); + if( isImage ) + { + if( reader.GetFile().GetDataSet().FindDataElement( gdcm::Tag(0x7fe0,0x0010) ) ) + { + std::cerr << "Failed to read image from file: " << filename << std::endl; + return 1; + } + else + { + std::cerr << "no Pixel Data Element found in the file:" << filename << std::endl; + return 0; + } + } + // else + // well this is not an image, so thankfully we fail to read it + std::cerr << "Could not read image(" << filename << "), since file is a: " << ms << std::endl; + //assert( ms != gdcm::MediaStorage::MS_END ); + return 0; +} + +int TestImageReader(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestImageRead(filename, true); + } + + // else + // First of get rid of warning/debug message + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + gdcm::Trace::ErrorOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestImageRead( filename); + //r += TestImageRead( filename, false, true ); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageReaderPixelSpacing.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageReaderPixelSpacing.cxx new file mode 100644 index 0000000..0553c50 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageReaderPixelSpacing.cxx @@ -0,0 +1,57 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmTesting.h" +#include "gdcmImageReader.h" +#include "gdcmImage.h" + +int TestImageReaderPixelSpacing(int argc, char *argv[]) +{ + int ret = 0; + const char *filenames[] = { "CRIMAGE", "DXIMAGE", "MGIMAGE" }; + const unsigned int nfiles = sizeof(filenames)/sizeof(*filenames); + const char *root = gdcm::Testing::GetPixelSpacingDataRoot(); + if( !root || !*root ) + { + std::cerr << "root is not defiend" << std::endl; + return 1; + } + std::string sroot = root; + sroot += "/DISCIMG/IMAGES/"; + const double spacing_ref[] = {0.5, 0.5}; + for(unsigned int i = 0; i < nfiles; ++i) + { + std::string filename = sroot + filenames[i]; + //std::cout << filename << std::endl; + gdcm::ImageReader r; + r.SetFileName( filename.c_str() ); + if( !r.Read() ) + { + ret++; + std::cerr << "could not read: " << filename << std::endl; + } + const gdcm::Image &image = r.GetImage(); + const double *spacing = image.GetSpacing(); + std::cout << spacing[0] << "," + << spacing[1] << "," + << spacing[2] << std::endl; + if( spacing[0] != spacing_ref[0] + || spacing[1] != spacing_ref[1] ) + { + std::cerr << "Wrong spacing for: " << filename << std::endl; + ++ret; + } + } + + return ret; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageReaderRandomEmpty.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageReaderRandomEmpty.cxx new file mode 100644 index 0000000..f740a55 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageReaderRandomEmpty.cxx @@ -0,0 +1,117 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmImageReader.h" +#include "gdcmFileMetaInformation.h" +#include "gdcmSystem.h" +#include "gdcmWriter.h" +#include "gdcmFilename.h" +#include "gdcmAnonymizer.h" +#include "gdcmByteSwap.h" +#include "gdcmTrace.h" +#include "gdcmTesting.h" + +#include + +int TestImageReaderRandomEmptyFunc(const char *subdir, const char* filename, bool verbose = false, bool lossydump = false) +{ + (void)lossydump; + if( verbose ) + std::cerr << "Reading: " << filename << std::endl; + gdcm::ImageReader reader; + + reader.SetFileName( filename ); + if( !reader.Read() ) + { + return 0;//this is NOT a test of the ImageReader read function + //this is a test of the anonymizer. As such, if the reader can't read this file, + //that should be handled in the TestImageReader test, NOT here. + //There is a lot of logic involved in testing non-standard images that should not be + //duplicated here. + } + + const gdcm::File &file = reader.GetFile(); + const gdcm::DataSet &ds = file.GetDataSet(); + const gdcm::FileMetaInformation &fmi = file.GetHeader(); + gdcm::DataSet::ConstIterator it = ds.Begin(); + + // Create directory first: + std::string tmpdir = gdcm::Testing::GetTempDirectory( subdir ); + if( !gdcm::System::FileIsDirectory( tmpdir.c_str() ) ) + { + gdcm::System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + std::string outfilename = gdcm::Testing::GetTempFilename( filename, subdir ); + + int ret = 0; + int i = 0; + for( ; it != ds.End(); ++it, ++i ) + { + //std::cout << "Processing Tag: " << *it << std::endl; + gdcm::Writer writer; + gdcm::File &filecopy = writer.GetFile(); + filecopy.SetDataSet( ds ); + filecopy.SetHeader( fmi ); + + gdcm::Anonymizer ano; + ano.SetFile( filecopy ); + ano.Empty( it->GetTag() ); + + //std::ostringstream os; + //os << "/tmp/ddd"; + //os << i; + //os << ".dcm"; + //std::string outfn = os.str(); + std::string outfn = outfilename; + writer.SetFile( ano.GetFile() ); + writer.CheckFileMetaInformationOff(); // FIXME ? + writer.SetFileName( outfn.c_str() ); + if( !writer.Write() ) + { + std::cerr << "Could not write: " << outfn << std::endl; + ret++; + } + + gdcm::ImageReader readercopy; + readercopy.SetFileName( outfn.c_str() ); + readercopy.Read(); + } + + return ret; +} + +int TestImageReaderRandomEmpty(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestImageReaderRandomEmptyFunc(argv[0], filename, true); + } + + // else + // First of get rid of warning/debug message + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + gdcm::Trace::ErrorOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestImageReaderRandomEmptyFunc( argv[0], filename); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageRegionReader1.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageRegionReader1.cxx new file mode 100644 index 0000000..b1bccc9 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageRegionReader1.cxx @@ -0,0 +1,123 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmImageRegionReader.h" +#include "gdcmImageHelper.h" +#include "gdcmFilename.h" +#include "gdcmBoxRegion.h" + +#include "gdcmTesting.h" + +static int TestImageRegionRead(const char* filename, bool verbose = false) +{ + if( verbose ) + std::cerr << "Reading: " << filename << std::endl; + gdcm::ImageRegionReader reader; + + gdcm::Filename fn( filename ); + // DMCPACS_ExplicitImplicit_BogusIOP.dcm is very difficult to handle since + // we need to read 3 attribute to detect the "well known" bug. However the third + // attribute is (b500,b700) which make ReadUpToTag(7fe0,0010) fails... + if( strcmp(fn.GetName(), "DMCPACS_ExplicitImplicit_BogusIOP.dcm" ) == 0 + || strcmp(fn.GetName(), "PHILIPS_Gyroscan-12-Jpeg_Extended_Process_2_4.dcm" ) == 0 ) // bogus JPEG cannot be streamed + { + std::cerr << "Skipping impossible file: " << filename << std::endl; + return 0; + } + + reader.SetFileName( filename ); + bool canReadInformation = reader.ReadInformation(); + if (!canReadInformation) + { + //std::cerr << "Cannot ReadInformation: " << filename << std::endl; + return 0; //unable to read tags as expected. + } + + int res = 0; + + //std::cout << reader.GetFile().GetDataSet() << std::endl; + std::vector dims = + gdcm::ImageHelper::GetDimensionsValue(reader.GetFile()); + gdcm::BoxRegion box; + box.SetDomain(0, dims[0] - 1, 0, dims[1] - 1, 0, dims[2] - 1); + reader.SetRegion( box ); + size_t len = reader.ComputeBufferLength(); + if( !len ) + { + std::cerr << "No length for: " << filename << std::endl; + return 1; + } + std::vector vbuffer; + vbuffer.resize( len ); + char* buffer = &vbuffer[0]; + bool b = reader.ReadIntoBuffer(buffer, len); + if( !b ) + { + std::cerr << "Could not ReadIntoBuffer" << std::endl; + return 1; + } +#if 0 + std::ofstream of( "/tmp/dd.raw", std::ios::binary ); + of.write( buffer, len ); + of.close(); +#endif + + const char *ref = gdcm::Testing::GetMD5FromFile(filename); + + char digest[33]; + gdcm::Testing::ComputeMD5(buffer, len, digest); + if( verbose ) + { + std::cout << "ref=" << ref << std::endl; + std::cout << "md5=" << digest << std::endl; + } + if( !ref ) + { + // new regression image needs a md5 sum + std::cout << "Missing md5 " << digest << " for: " << filename << std::endl; + res = 1; + } + else if( strcmp(digest, ref) ) + { + std::cerr << "Problem reading image from: " << filename << std::endl; + std::cerr << "Found " << digest << " instead of " << ref << std::endl; + res = 1; + } + + return res; +} + + +int TestImageRegionReader1(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestImageRegionRead(filename, true); + } + + // else + // First of get rid of warning/debug message + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestImageRegionRead(filename); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageRegionReader2.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageRegionReader2.cxx new file mode 100644 index 0000000..a7d6839 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageRegionReader2.cxx @@ -0,0 +1,129 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmImageRegionReader.h" +#include "gdcmImageHelper.h" +#include "gdcmFilename.h" +#include "gdcmBoxRegion.h" + +#include "gdcmTesting.h" + +static int TestImageRegionRead(const char* filename, bool verbose = false) +{ + if( verbose ) + std::cerr << "Reading: " << filename << std::endl; + gdcm::ImageRegionReader reader; + + gdcm::Filename fn( filename ); + // DMCPACS_ExplicitImplicit_BogusIOP.dcm is very difficult to handle since + // we need to read 3 attribute to detect the "well known" bug. However the third + // attribute is (b500,b700) which make ReadUpToTag(7fe0,0010) fails... + if( strcmp(fn.GetName(), "DMCPACS_ExplicitImplicit_BogusIOP.dcm" ) == 0 + || strcmp(fn.GetName(), "PHILIPS_Gyroscan-12-Jpeg_Extended_Process_2_4.dcm" ) == 0 ) // bogus JPEG cannot be streamed + { + std::cerr << "Skipping impossible file" << std::endl; + return 0; + } + + reader.SetFileName( filename ); + bool canReadInformation = reader.ReadInformation(); + if (!canReadInformation) + { + std::cerr << "Cannot ReadInformation: " << filename << std::endl; + return 0; //unable to read tags as expected. + } + + int res = 0; + + size_t len = 0; + std::vector vbuffer; + std::vector dims = + gdcm::ImageHelper::GetDimensionsValue(reader.GetFile()); + gdcm::BoxRegion box; + for( unsigned int z = 0; z < dims[2]; ++z ) + { + box.SetDomain(0, dims[0] - 1, 0, dims[1] - 1, z, z); + reader.SetRegion( box ); + + size_t zlen = reader.ComputeBufferLength(); + if( !zlen ) + { + std::cerr << "No length for: " << filename << std::endl; + return 1; + } + size_t oldlen = vbuffer.size(); + len += zlen; + vbuffer.resize( oldlen + zlen ); + char* buffer = &vbuffer[0] + oldlen; + bool b = reader.ReadIntoBuffer(buffer, zlen); + if( !b ) + { + std::cerr << "Could not ReadIntoBuffer" << std::endl; + return 1; + } + } + const char *ref = gdcm::Testing::GetMD5FromFile(filename); + + char digest[33]; + char* buffer = &vbuffer[0]; +#if 0 + std::ofstream of( "/tmp/dd.raw", std::ios::binary ); + of.write( buffer, len ); + of.close(); +#endif + gdcm::Testing::ComputeMD5(buffer, len, digest); + if( verbose ) + { + std::cout << "ref=" << ref << std::endl; + std::cout << "md5=" << digest << std::endl; + } + if( !ref ) + { + // new regression image needs a md5 sum + std::cout << "Missing md5 " << digest << " for: " << filename << std::endl; + res = 1; + } + else if( strcmp(digest, ref) ) + { + std::cerr << "Problem reading image from: " << filename << std::endl; + std::cerr << "Found " << digest << " instead of " << ref << std::endl; + res = 1; + } + + return res; +} + + +int TestImageRegionReader2(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestImageRegionRead(filename, true); + } + + // else + // First of get rid of warning/debug message + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestImageRegionRead(filename); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageRegionReader3.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageRegionReader3.cxx new file mode 100644 index 0000000..26413b5 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageRegionReader3.cxx @@ -0,0 +1,145 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmImageRegionReader.h" +#include "gdcmImageHelper.h" +#include "gdcmFilename.h" +#include "gdcmBoxRegion.h" + +#include "gdcmTesting.h" + +static int TestImageRegionRead(const char* filename, bool verbose = false) +{ + using gdcm::System; + using gdcm::Testing; + + if( verbose ) + std::cerr << "Reading: " << filename << std::endl; + + gdcm::Filename fn( filename ); + // DMCPACS_ExplicitImplicit_BogusIOP.dcm is very difficult to handle since + // we need to read 3 attribute to detect the "well known" bug. However the third + // attribute is (b500,b700) which make ReadUpToTag(7fe0,0010) fails... + if( strcmp(fn.GetName(), "DMCPACS_ExplicitImplicit_BogusIOP.dcm" ) == 0 + || strcmp(fn.GetName(), "PHILIPS_Gyroscan-12-Jpeg_Extended_Process_2_4.dcm" ) == 0 ) // bogus JPEG cannot be streamed + { + std::cerr << "Skipping impossible file" << std::endl; + return 0; + } + + gdcm::ImageRegionReader reader; + reader.SetFileName( filename ); + bool canReadInformation = reader.ReadInformation(); + if (!canReadInformation) + { + std::cerr << "Cannot ReadInformation: " << filename << std::endl; + return 0; //unable to read tags as expected. + } + + // Create directory first: + const char subdir[] = "TestImageRegionReader3"; + std::string tmpdir = Testing::GetTempDirectory( subdir ); + if( !System::FileIsDirectory( tmpdir.c_str() ) ) + { + System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + std::string outfilename = Testing::GetTempFilename( filename, subdir ); + outfilename += ".raw"; + + + std::ofstream of( outfilename.c_str(), std::ios::binary ); + + int res = 0; + + std::vector dims = + gdcm::ImageHelper::GetDimensionsValue(reader.GetFile()); + std::vector vbuffer; + gdcm::BoxRegion box; + for( unsigned int z = 0; z < dims[2]; ++z ) + { + const unsigned int xdelta = dims[0] / 1; + const unsigned int ydelta = dims[1] / 4; + size_t zlen; + bool b; + + for( unsigned int y = 0; y < 4; ++y ) + { + unsigned int maxy = ydelta + y * ydelta; + if( y == 3 ) maxy = dims[1]; + box.SetDomain(0, xdelta - 1, 0 + y * ydelta, (unsigned int)(maxy - 1), z, z); + reader.SetRegion(box); + zlen = reader.ComputeBufferLength(); + assert( zlen ); + vbuffer.resize( zlen ); + char* buffer = &vbuffer[0]; + b = reader.ReadIntoBuffer(buffer, zlen); + assert( zlen ); assert( b ); (void)b; + of.write( buffer, zlen ); + } + } + of.close(); + + char digest[33]; + bool b = gdcm::Testing::ComputeFileMD5(outfilename.c_str(), digest); + if( !b ) + { + std::cerr << "Could not ComputeFileMD5: " << outfilename << std::endl; + return 1; + } + const char *ref = gdcm::Testing::GetMD5FromFile(filename); + if( verbose ) + { + std::cout << "ref=" << ref << std::endl; + std::cout << "md5=" << digest << std::endl; + } + if( !ref ) + { + // new regression image needs a md5 sum + std::cout << "Missing md5 " << digest << " for: " << filename << std::endl; + res = 1; + } + else if( strcmp(digest, ref) ) + { + std::cerr << "Problem reading image from: " << filename << std::endl; + std::cerr << "Found " << digest << " instead of " << ref << std::endl; + res = 1; + } + + return res; +} + + +int TestImageRegionReader3(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestImageRegionRead(filename, true); + } + + // else + // First of get rid of warning/debug message + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestImageRegionRead(filename); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageRegionReader4.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageRegionReader4.cxx new file mode 100644 index 0000000..2188aea --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageRegionReader4.cxx @@ -0,0 +1,142 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmImageRegionReader.h" +#include "gdcmImageHelper.h" +#include "gdcmFilename.h" +#include "gdcmBoxRegion.h" + +#include "gdcmTesting.h" +#include "gdcmSystem.h" + +static int TestImageRegionRead(const char* filename, bool verbose = false) +{ + using gdcm::System; + using gdcm::Testing; + if( verbose ) + std::cerr << "Reading: " << filename << std::endl; + gdcm::ImageRegionReader reader; + + reader.SetFileName( filename ); + bool canReadInformation = reader.ReadInformation(); + if (!canReadInformation) + { + std::cerr << "Cannot ReadInformation: " << filename << std::endl; + return 1; + } + + // Create directory first: + const char subdir[] = "TestImageRegionReader4"; + std::string tmpdir = Testing::GetTempDirectory( subdir ); + if( !System::FileIsDirectory( tmpdir.c_str() ) ) + { + System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + std::string outfilename = Testing::GetTempFilename( filename, subdir ); + outfilename += ".raw"; + + std::ofstream of( outfilename.c_str(), std::ios::binary ); + + int res = 0; + + std::vector dims = + gdcm::ImageHelper::GetDimensionsValue(reader.GetFile()); + std::vector vbuffer; + gdcm::BoxRegion box; + for( unsigned int z = 0; z < dims[2]; ++z ) + { + box.SetDomain(0, dims[0] - 1, 0, dims[1] - 1, z, z); + reader.SetRegion( box ); + size_t len = reader.ComputeBufferLength(); + if( !len ) + { + std::cerr << "No length for: " << filename << std::endl; + return 1; + } + vbuffer.resize( len ); + char* buffer = &vbuffer[0]; + bool b = reader.ReadIntoBuffer(buffer, len); + if( !b ) + { + std::cerr << "Could not ReadIntoBuffer" << std::endl; + return 1; + } + of.write( buffer, len ); + } + of.close(); + + char digest[33]; + bool b = gdcm::Testing::ComputeFileMD5(outfilename.c_str(), digest); + if( !b ) + { + std::cerr << "Could not ComputeFileMD5: " << outfilename << std::endl; + return 1; + } + + const char *ref = gdcm::Testing::GetMD5FromFile(filename); + if( verbose ) + { + std::cout << "ref=" << ref << std::endl; + std::cout << "md5=" << digest << std::endl; + } + if( !ref ) + { + // new regression image needs a md5 sum + std::cout << "Missing md5 " << digest << " for: " << filename << std::endl; + res = 1; + } + else if( strcmp(digest, ref) ) + { + std::cerr << "Problem reading image from: " << filename << std::endl; + std::cerr << "Into: " << outfilename << std::endl; + std::cerr << "Found " << digest << " instead of " << ref << std::endl; + res = 1; + } + + return res; +} + + +int TestImageRegionReader4(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestImageRegionRead(filename, true); + } + + // else + // First of get rid of warning/debug message + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + int r = 0, i = 0; + const char *extradataroot = gdcm::Testing::GetDataExtraRoot(); + static const char *names[] = { + "/gdcmSampleData/images_of_interest/US_512x512x2496_JPEG_BaseLine_Process_1.dcm", + "/gdcmSampleData/images_of_interest/PHILIPS_Integris_V-10-MONO2-Multiframe.dcm", + "/gdcmSampleData/ForSeriesTesting/MultiFramesSingleSerieXR/1.3.46.670589.7.5.10.80002138018.20001204.181556.9.1.1.dcm", + "/gdcmSampleData/images_of_interest/i32.XADC.7.215MegaBytes.dcm", + NULL + }; + const char *filename; + while( (filename = names[i]) ) + { + std::string fn = extradataroot; + fn += filename; + r += TestImageRegionRead(fn.c_str()); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageToImageFilter.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageToImageFilter.cxx new file mode 100644 index 0000000..29887d9 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageToImageFilter.cxx @@ -0,0 +1,20 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmImageToImageFilter.h" + +int TestImageToImageFilter(int, char *[]) +{ + gdcm::ImageToImageFilter f; + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageWriter.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageWriter.cxx new file mode 100644 index 0000000..082bf7e --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageWriter.cxx @@ -0,0 +1,175 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmImageReader.h" +#include "gdcmImageWriter.h" +#include "gdcmFilename.h" +#include "gdcmSystem.h" +#include "gdcmFileMetaInformation.h" +#include "gdcmTesting.h" +#include "gdcmByteSwap.h" + +namespace gdcm +{ +int TestImageWrite(const char *subdir, const char* filename) +{ + ImageReader reader; + reader.SetFileName( filename ); + if ( !reader.Read() ) + { + const FileMetaInformation &header = reader.GetFile().GetHeader(); + MediaStorage ms = header.GetMediaStorage(); + bool isImage = MediaStorage::IsImage( ms ); + bool pixeldata = reader.GetFile().GetDataSet().FindDataElement( Tag(0x7fe0,0x0010) ); + if( isImage && pixeldata ) + { + std::cerr << "Failed to read: " << filename << std::endl; + return 1; + } + else + { + // not an image give up... + std::cerr << "Problem with: " << filename << " but that's ok" << std::endl; + return 0; + } + } + + // Create directory first: + std::string tmpdir = Testing::GetTempDirectory( subdir ); + if( !System::FileIsDirectory( tmpdir.c_str() ) ) + { + System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + std::string outfilename = Testing::GetTempFilename( filename, subdir ); + + ImageWriter writer; + writer.SetFileName( outfilename.c_str() ); + writer.SetImage( reader.GetImage() ); + if( !writer.Write() ) + { + std::cerr << "Failed to write: " << outfilename << std::endl; + return 1; + } + std::cout << "success: " << outfilename << std::endl; + + // Let's read that file back in ! + ImageReader reader2; + + reader2.SetFileName( outfilename.c_str() ); + if ( reader2.Read() ) + { + int res = 0; + const Image &img = reader2.GetImage(); + //std::cerr << "Success to read image from file: " << filename << std::endl; + unsigned long len = img.GetBufferLength(); + char* buffer = new char[len]; + img.GetBuffer(buffer); + // On big Endian system we have byteswapped the buffer (duh!) + // Since the md5sum is byte based there is now way it would detect + // that the file is written in big endian word, so comparing against + // a md5sum computed on LittleEndian would fail. Thus we need to + // byteswap (again!) here: +#ifdef GDCM_WORDS_BIGENDIAN + if( img.GetPixelFormat().GetBitsAllocated() == 16 ) + { + assert( !(len % 2) ); + assert( img.GetPhotometricInterpretation() == PhotometricInterpretation::MONOCHROME1 + || img.GetPhotometricInterpretation() == PhotometricInterpretation::MONOCHROME2 ); + ByteSwap::SwapRangeFromSwapCodeIntoSystem( + (unsigned short*)buffer, SwapCode::LittleEndian, len/2); + } +#endif + // reuse the filename, since outfilename is simply the new representation of the old filename + const char *ref = Testing::GetMD5FromFile(filename); + + char digest[33] = {}; + Testing::ComputeMD5(buffer, len, digest); + if( !ref ) + { + // new regression image needs a md5 sum + std::cout << "Missing md5 " << digest << " for: " << outfilename << std::endl; + //assert(0); + res = 1; + } + else if( strcmp(digest, ref) ) + { + std::cerr << "Problem reading image from: " << outfilename << std::endl; + std::cerr << "Found " << digest << " instead of " << ref << std::endl; + res = 1; +#if 0 + std::ofstream debug("/tmp/dump.gray", std::ios::binary); + debug.write(buffer, len); + debug.close(); + //assert(0); +#endif + } + delete[] buffer; + return res; + } + +#if 0 + // Ok we have now two files let's compare their md5 sum: + char digest[33], outdigest[33]; + System::ComputeFileMD5(filename, digest); + System::ComputeFileMD5(outfilename.c_str(), outdigest); + if( strcmp(digest, outdigest) ) + { + // too bad the file is not identical, so let's be paranoid and + // try to reread-rewrite this just-writen file: + // TODO: Copy file System::CopyFile( ); + if( TestImageWrite( outfilename.c_str() ) ) + { + std::cerr << filename << " and " + << outfilename << " are different\n"; + return 1; + } + // In theory I need to compare the two documents to check they + // are identical... TODO + std::cerr << filename << " and " + << outfilename << " should be compatible\n"; + return 0; + } + else + { + std::cerr << filename << " and " + << outfilename << " are identical\n"; + return 0; + } +#endif + return 0; +} +} + +int TestImageWriter(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return gdcm::TestImageWrite(argv[0],filename); + } + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += gdcm::TestImageWrite(argv[0], filename ); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageWriter2.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageWriter2.cxx new file mode 100644 index 0000000..907a0ed --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestImageWriter2.cxx @@ -0,0 +1,201 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmImageWriter.h" +#include "gdcmImageReader.h" +#include "gdcmImage.h" +#include "gdcmTesting.h" +#include "gdcmSystem.h" +#include "gdcmTrace.h" +#include "gdcmAttribute.h" + +/* +Let's test the relation in between lossless transfer syntax and lossless compressed stream. + +D_CLUNIE_CT1_J2KR.dcm +D_CLUNIE_CT1_J2KI.dcm + +D_CLUNIE_MR1_JPLL.dcm +D_CLUNIE_MR1_JPLY.dcm + +D_CLUNIE_CT1_JLSL.dcm +D_CLUNIE_CT1_JLSN.dcm + +*/ + +struct LossLessTest +{ + const char *lossyfile; + const char *losslessfile; + gdcm::TransferSyntax::TSType lossyts; + gdcm::TransferSyntax::TSType losslessts; +}; + +static const LossLessTest LossLessTestArray[] = { + { "/D_CLUNIE_CT1_J2KI.dcm", "/D_CLUNIE_CT1_J2KR.dcm", gdcm::TransferSyntax::JPEG2000, gdcm::TransferSyntax::JPEG2000Lossless }, + { "/D_CLUNIE_MR1_JPLY.dcm", "/D_CLUNIE_MR1_JPLL.dcm", gdcm::TransferSyntax::JPEGExtendedProcess2_4, gdcm::TransferSyntax::JPEGLosslessProcess14_1 }, + { "/D_CLUNIE_CT1_JLSN.dcm", "/D_CLUNIE_CT1_JLSL.dcm", gdcm::TransferSyntax::JPEGLSNearLossless, gdcm::TransferSyntax::JPEGLSLossless } +}; + +int TestImageWriter2(int , char *[]) +{ + const char *directory = gdcm::Testing::GetDataRoot(); + gdcm::Trace::WarningOff(); + static const unsigned int ntests = sizeof( LossLessTestArray ) / sizeof( *LossLessTestArray ); + for( unsigned int test = 0; test < ntests; ++test ) + { + const LossLessTest <est = LossLessTestArray[test]; + + const char *j2k_filename1 = ltest.lossyfile; + const char *j2k_filename2 = ltest.losslessfile; + //const char j2k_filename1[] = "/D_CLUNIE_CT1_J2KI.dcm"; + //const char j2k_filename2[] = "/D_CLUNIE_CT1_J2KR.dcm"; + std::string filename_lossy = directory; + filename_lossy += j2k_filename1; + std::string filename_lossless = directory; + filename_lossless += j2k_filename2; + + // Create directory first: + const char subdir[] = "TestImageWriter2"; + std::string tmpdir = gdcm::Testing::GetTempDirectory( subdir ); + if( !gdcm::System::FileIsDirectory( tmpdir.c_str() ) ) + { + gdcm::System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + std::string outfilename_lossy = gdcm::Testing::GetTempFilename( filename_lossy.c_str(), subdir ); + std::string outfilename_lossless = gdcm::Testing::GetTempFilename( filename_lossless.c_str(), subdir ); + + { + gdcm::ImageReader reader; + reader.SetFileName( filename_lossy.c_str() ); + if( !reader.Read() ) + { + return 1; + } + + gdcm::Image &ir = reader.GetImage(); + if( !ir.IsLossy() ) + { + std::cerr << "Image is not lossy" << std::endl; + std::cerr << filename_lossy << std::endl; + return 1; + } + + //if( ir.GetTransferSyntax() != gdcm::TransferSyntax::JPEG2000 ) + if( ir.GetTransferSyntax() != ltest.lossyts ) + { + std::cerr << filename_lossy << " " << filename_lossless << std::endl; + std::cerr << ir.GetTransferSyntax() << " vs " << gdcm::TransferSyntax::GetTSString( ltest.lossyts ) << std::endl; + return 1; + } + + //ir.SetTransferSyntax( gdcm::TransferSyntax::JPEG2000Lossless ); + ir.SetTransferSyntax( ltest.losslessts ); + + gdcm::ImageWriter writer; + writer.SetImage( ir ); + writer.SetFileName( outfilename_lossy.c_str() ); + // We should never authorized writing of image that was lossy compress and declare as lossless + if( writer.Write() ) + { + gdcm::Attribute<0x0028,0x2110> at; + at.Set( writer.GetFile().GetDataSet() ); + if( at.GetValue() != "01" ) + { + std::cerr << "We should never authorize writing of image that was lossy " + "compress and declare as lossless" << std::endl; + std::cerr << filename_lossy << " " << filename_lossless << std::endl; + return 1; + } + } + } + + // But the contrary is ok: + { + gdcm::ImageReader reader; + reader.SetFileName( filename_lossless.c_str() ); + if( !reader.Read() ) + { + return 1; + } + + gdcm::Image &ir = reader.GetImage(); + //if( ir.GetTransferSyntax() != gdcm::TransferSyntax::JPEG2000Lossless ) + if( ir.GetTransferSyntax() != ltest.losslessts ) + { + return 1; + } + + //ir.SetTransferSyntax( gdcm::TransferSyntax::JPEG2000 ); + ir.SetTransferSyntax( ltest.lossyts ); + + gdcm::ImageWriter writer; + writer.SetImage( ir ); + writer.SetFileName( outfilename_lossless.c_str() ); + // It is ok to save a lossless file and declare transfer syntax to JPEG2000 + if( !writer.Write() ) + { + return 1; + } + } + } + +#if 0 + const gdcm::Image &ir = reader.GetImage(); + + gdcm::Image image; + image.SetNumberOfDimensions( ir.GetNumberOfDimensions() ); + + const unsigned int *dims = ir.GetDimensions(); + image.SetDimension(0, dims[0] ); + image.SetDimension(1, dims[1] ); + + const gdcm::PixelFormat &pixeltype = ir.GetPixelFormat(); + image.SetPixelFormat( pixeltype ); + + const gdcm::PhotometricInterpretation &pi = ir.GetPhotometricInterpretation(); + image.SetPhotometricInterpretation( pi ); + + unsigned long len = image.GetBufferLength(); + assert( len = ir.GetBufferLength() ); + std::vector buffer; + buffer.resize(len); // black image + + gdcm::ByteValue *bv = new gdcm::ByteValue(buffer); + gdcm::DataElement pixeldata( gdcm::Tag(0x7fe0,0x0010) ); + pixeldata.SetValue( *bv ); + image.SetDataElement( pixeldata ); + + const char filename[] = "toto.dcm"; + gdcm::ImageWriter writer; + writer.SetImage( image ); + writer.SetFileName( filename ); + + gdcm::File& file = writer.GetFile(); + gdcm::DataSet& ds = file.GetDataSet(); + + gdcm::DataElement de( gdcm::Tag(0x0010,0x0010) ); + const char s[] = "GDCM^Rocks"; + de.SetByteValue( s, strlen( s ) ); + ds.Insert( de ); + + if( !writer.Write() ) + { + return 1; + } + + return 0; +#endif + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestJPEGCodec.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestJPEGCodec.cxx new file mode 100644 index 0000000..c527c33 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestJPEGCodec.cxx @@ -0,0 +1,19 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmJPEGCodec.h" + +int TestJPEGCodec(int, char *[]) +{ + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestJSON1.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestJSON1.cxx new file mode 100644 index 0000000..85af7c2 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestJSON1.cxx @@ -0,0 +1,55 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmJSON.h" +#include "gdcmFilename.h" +#include "gdcmTesting.h" +#include "gdcmDataSet.h" +#include "gdcmWriter.h" +#include "gdcmFile.h" + +int TestJSON1(int, char *[]) +{ + //std::string sup166 = gdcm::Filename::Join(gdcm::Testing::GetSourceDirectory(), "/Testing/Source/Data/QIDO-RS_examplesup166.json" ); + std::string sup166 = gdcm::Filename::Join(gdcm::Testing::GetSourceDirectory(), "/Testing/Source/Data/QIDO-RS_examplesup166_2.json" ); + if( !gdcm::System::FileExists( sup166.c_str() ) ) + { + std::cerr << sup166 << std::endl; + return 1; + } + + std::ifstream is( sup166.c_str() ); + gdcm::JSON json; + json.PrettyPrintOn(); + +#if 1 + gdcm::DataSet ds; + json.Decode(is, ds ); + //std::cout << ds << std::endl; +#else + gdcm::Writer w; + gdcm::File & ff = w.GetFile(); + gdcm::DataSet &ds = ff.GetDataSet(); + ff.GetHeader().SetDataSetTransferSyntax( gdcm::TransferSyntax::ExplicitVRLittleEndian ); + json.Decode(is, ff.GetDataSet() ); + w.SetFileName( "/tmp/debug2.dcm" ); + if( !w.Write() ) return 1; +#endif + + std::stringstream ss; + json.Code(ds, ss ); + + std::cout << ss.str() << std::endl; + + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestLookupTable.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestLookupTable.cxx new file mode 100644 index 0000000..a73fe03 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestLookupTable.cxx @@ -0,0 +1,20 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmLookupTable.h" + +int TestLookupTable(int, char *[]) +{ + gdcm::LookupTable lut; + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestOrientation.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestOrientation.cxx new file mode 100644 index 0000000..1835936 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestOrientation.cxx @@ -0,0 +1,62 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmOrientation.h" + +#include + +int TestOrientation(int, char *[]) +{ + gdcm::Orientation o; +{ + double dircos[] = { 1, 0, 0, 0, 1, 0 }; + gdcm::Orientation::OrientationType type = gdcm::Orientation::GetType(dircos); + + if( type != gdcm::Orientation::AXIAL ) + { + std::cerr << "Should be AXIAL: " << gdcm::Orientation::GetLabel( type ) << std::endl; + return 1; + } +} +{ + double dircos[] = { 1, 0, 0, 0, 0, 1 }; + gdcm::Orientation::OrientationType type = gdcm::Orientation::GetType(dircos); + + if( type != gdcm::Orientation::CORONAL ) + { + return 1; + } +} +{ + double dircos[] = { 0, 1, 0, 0, 0, -1 }; + gdcm::Orientation::OrientationType type = gdcm::Orientation::GetType(dircos); + + if( type != gdcm::Orientation::SAGITTAL ) + { + return 1; + } +} + + + if( o.GetObliquityThresholdCosineValue() != 0.8 ) + { + return 1; + } + gdcm::Orientation::SetObliquityThresholdCosineValue( 0.75 ); + if( o.GetObliquityThresholdCosineValue() != 0.75 ) + { + return 1; + } + + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestOverlay.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestOverlay.cxx new file mode 100644 index 0000000..93d9102 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestOverlay.cxx @@ -0,0 +1,21 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmOverlay.h" + +int TestOverlay(int, char *[]) +{ + gdcm::Overlay o; + o.Print( std::cout ); + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestOverlay2.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestOverlay2.cxx new file mode 100644 index 0000000..27842c7 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestOverlay2.cxx @@ -0,0 +1,64 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmOverlay.h" +#include "gdcmPixmapReader.h" +#include "gdcmTesting.h" +#include "gdcmSystem.h" + +int TestOverlay2(int, char *[]) +{ + const char *extradataroot = gdcm::Testing::GetDataExtraRoot(); + if( !extradataroot ) + { + return 1; + } + if( !gdcm::System::FileIsDirectory(extradataroot) ) + { + std::cerr << "No such directory: " << extradataroot << std::endl; + return 1; + } + + std::string filename = extradataroot; + filename += "/gdcmSampleData/images_of_interest/XA_GE_JPEG_02_with_Overlays.dcm"; + if( !gdcm::System::FileExists(filename.c_str()) ) + { + return 1; + } + + gdcm::PixmapReader reader; + reader.SetFileName( filename.c_str() ); + if( !reader.Read() ) + { + std::cerr << "could not read: " << filename << std::endl; + return 1; + } + gdcm::Pixmap &pixmap = reader.GetPixmap(); + + if( pixmap.GetNumberOfOverlays() != 8 ) + { + return 1; + } + size_t numoverlays = pixmap.GetNumberOfOverlays(); + for( size_t ovidx = 0; ovidx < numoverlays; ++ovidx ) + { + const gdcm::Overlay& ov = pixmap.GetOverlay(ovidx); + if( ov.GetTypeAsEnum() != gdcm::Overlay::Graphics ) + { + std::cerr << "Wrong Type for overlay #" << ovidx << std::endl; + return 1; + } + } + + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestOverlay3.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestOverlay3.cxx new file mode 100644 index 0000000..fad5467 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestOverlay3.cxx @@ -0,0 +1,176 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmOverlay.h" +#include "gdcmImageReader.h" +#include "gdcmTesting.h" +#include "gdcmSystem.h" +#include "gdcmFilename.h" + +using namespace gdcm; + +struct ovel +{ + const char *md5; + const char *fn; + unsigned int idx; + Overlay::OverlayType type; +}; + +static const ovel overlay3array[] = { +// gdcmData + {"d42bff3545ed8c5fccb39d9a61828992", "MR-SIEMENS-DICOM-WithOverlays-extracted-overlays.dcm", 0, Overlay::Graphics }, + {"2cf60257b75a034fbdc98e560881184e", "PHILIPS_Brilliance_ExtraBytesInOverlay.dcm", 0, Overlay::Graphics }, + {"b2dd1007e018b3b9691761cf93f77552", "05115014-mr-siemens-avanto-syngo-with-palette-icone.dcm", 0, Overlay::Graphics }, + {"d42bff3545ed8c5fccb39d9a61828992", "MR-SIEMENS-DICOM-WithOverlays.dcm", 0, Overlay::Graphics }, +// gdcmDataExtra + {"4b0240033afba211eeac42a44417d4c9", "05119848_IS_Black_hasOverlayData.dcm", 0, Overlay::Graphics }, + {"349d1f9510f64467ecf73eeea46c9c6e", "45909476", 0, Overlay::Graphics }, + {"6a5f8038cc8cf753bf74422164adc24c", "45909517", 0, Overlay::Graphics }, + {"1a3bf73e42b0f6dc282a9be59c054027", "OverlayDICOMDataSet.dcm", 0, Overlay::Graphics }, +// gdcmConformanceTests + {"040560796c1a53ffce0d2f7e90c9dc26", "CT_OSIRIX_OddOverlay.dcm", 0, Overlay::Graphics }, + // random +// {"f7e43de189a1bc08044c13aefac73fed", "1.dcm", 0 }, +// {"e7859c818f26202fb63a2b205ff16297", "1.dcm", 1 }, +// {"aa4c726bc52e13b750ac8c94c7b06e07", "0.dcm", 0 }, +// {"31d58476326722793379fbcda55a4856", "0.dcm", 1 }, + + // sentinel + { 0, 0, 0, Overlay::Invalid } +}; + +static int TestReadOverlay(const char* filename, bool verbose = false) +{ + if( verbose ) + std::cerr << "Reading: " << filename << std::endl; + gdcm::ImageReader reader; + + reader.SetFileName( filename ); + int ret = 0; + if ( reader.Read() ) + { + gdcm::Filename fn( filename ); + const char *name = fn.GetName(); + + std::vector overlay; + const gdcm::Image &img = reader.GetImage(); + size_t numoverlays = img.GetNumberOfOverlays(); + for( size_t ovidx = 0; ovidx < numoverlays; ++ovidx ) + { + const gdcm::Overlay& ov = img.GetOverlay(ovidx); + size_t len = ov.GetUnpackBufferLength(); + overlay.resize( len ); + if( !ov.GetUnpackBuffer(&overlay[0], len) ) + { + std::cerr << "GetUnpackBuffer: Problem with Overlay: #" << ovidx << std::endl; + ++ret; + } + char digest1[33]; + if( !gdcm::Testing::ComputeMD5(&overlay[0], len, digest1) ) + { + std::cerr << "ComputeMD5: Problem with Overlay: #" << ovidx << std::endl; + ++ret; + } + std::stringstream overlay2; + ov.Decompress(overlay2); + Overlay::OverlayType type = ov.GetTypeAsEnum(); + const std::string soverlay2 = overlay2.str(); + if( soverlay2.size() != len ) + { + std::cerr << "Decompress: Problem with Overlay: #" << ovidx << std::endl; + std::cerr << "Size is: " << soverlay2.size() << " vs " << len << std::endl; + ++ret; + } + char digest2[33]; + if( !gdcm::Testing::ComputeMD5(soverlay2.c_str(), soverlay2.size(), digest2) ) + { + std::cerr << "ComputeMD5: Problem with Overlay: #" << ovidx << std::endl; + ++ret; + } + + Overlay::OverlayType reftype = Overlay::Invalid; + const char *refmd5 = NULL; + { + unsigned int i = 0; + const char *p = overlay3array[i].fn; + unsigned int idx = overlay3array[i].idx; + while( p != 0 ) + { + if( strcmp( name, p ) == 0 && ovidx == idx ) + { + break; + } + ++i; + p = overlay3array[i].fn; + idx = overlay3array[i].idx; + } + refmd5 = overlay3array[i].md5; + reftype = overlay3array[i].type; + } + + if( !refmd5 ) + { + std::cerr << "refmd5: Problem with Overlay: #" << ovidx << std::endl; + std::cerr << name << std::endl; + ++ret; + } + if( refmd5 && strcmp(digest1, refmd5) ) + { + std::cerr << "strcmp/ref: Problem with Overlay: #" << ovidx << std::endl; + std::cerr << "ref: " << refmd5 << " vs " << digest1 << std::endl; + ++ret; + } + if( strcmp(digest1, digest2) ) + { + std::cerr << "strcmp/1/2: Problem with Overlay: #" << ovidx << std::endl; + std::cerr << "digest1: " << digest1 << " vs " << digest2 << std::endl; + ++ret; + } + if( reftype != type ) + { + std::cerr << "OverlayType: Problem with Overlay: #" << ovidx << std::endl; + std::cerr << "reftype: " << (int)reftype << " vs " << (int)type << std::endl; + std::cerr << name << std::endl; + ++ret; + } + } + } + + return ret; +} + +int TestOverlay3(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestReadOverlay(filename, true); + } + + // else + // First of get rid of warning/debug message + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + gdcm::Trace::ErrorOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestReadOverlay( filename); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestPDFCodec.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestPDFCodec.cxx new file mode 100644 index 0000000..99fc034 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestPDFCodec.cxx @@ -0,0 +1,23 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmPDFCodec.h" +#include "gdcmTransferSyntax.h" + +int TestPDFCodec(int , char *[]) +{ + gdcm::PDFCodec c; + c.CanCode(gdcm::TransferSyntax()); + + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestPNMCodec.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestPNMCodec.cxx new file mode 100644 index 0000000..5ea94f5 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestPNMCodec.cxx @@ -0,0 +1,22 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmPNMCodec.h" +#include "gdcmTransferSyntax.h" + +int TestPNMCodec(int, char *[]) +{ + gdcm::PNMCodec pnm; + pnm.CanDecode( gdcm::TransferSyntax::ImplicitVRLittleEndian ); + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestParseXPATH.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestParseXPATH.cxx new file mode 100644 index 0000000..73c6320 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestParseXPATH.cxx @@ -0,0 +1,109 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmReader.h" +#include "gdcmDataSet.h" +#include "gdcmDict.h" +#include "gdcmDicts.h" +#include "gdcmGlobal.h" +#include "gdcmStringFilter.h" +#include "gdcmTesting.h" +#include "gdcmFilename.h" + +static bool CheckResult( std::string const & filename, std::string const & value ) +{ + if( + filename == "D_CLUNIE_MR3_JPLY.dcm" + || filename == "D_CLUNIE_RG3_JPLY.dcm" + || filename == "D_CLUNIE_NM1_JPLY.dcm" + || filename == "D_CLUNIE_MR4_JPLY.dcm" + || filename == "D_CLUNIE_CT1_J2KI.dcm" + || filename == "D_CLUNIE_CT1_JLSN.dcm" + || filename == "D_CLUNIE_MR1_JPLY.dcm" + || filename == "D_CLUNIE_SC1_JPLY.dcm" + || filename == "D_CLUNIE_MR2_JPLY.dcm" + || filename == "D_CLUNIE_RG2_JPLY.dcm" + || filename == "D_CLUNIE_XA1_JPLY.dcm" ) + { + return value == "Lossy Compression "; + } + else if ( filename == "JPEG_LossyYBR.dcm" + || filename == "MEDILABInvalidCP246_EVRLESQasUN.dcm" ) + return value == "Full fidelity image, uncompressed or lossless compressed"; + else if ( filename == "NM-PAL-16-PixRep1.dcm" ) + return value == "Full fidelity image "; + else + return value == ""; +} + +int TestParseXPATHFile(const char* filename, bool verbose = false ) +{ + (void)verbose; + //static gdcm::Global &g = gdcm::Global::GetInstance(); + //static const gdcm::Dicts &dicts = g.GetDicts(); + //static const gdcm::Dict &pubdict = dicts.GetPublicDict(); + + gdcm::Reader reader; +// reader.SetFileName( "/home/mathieu/Creatis/gdcmData/D_CLUNIE_CT1_J2KI.dcm" ); + reader.SetFileName( filename ); + if( !reader.Read() ) + { + return 1; + } + + gdcm::StringFilter sf; + sf.SetFile( reader.GetFile() ); + + const char query_const[] = "/DicomNativeModel/DicomAttribute[@keyword='DerivationCodeSequence']/Item[@number=1]//DicomAttribute[@keyword='CodeMeaning']/Value[@number=1]"; + + std::string value; + bool ret = sf.ExecuteQuery( query_const, value ); + + if( !ret ) + { + return 1; + } + + gdcm::Filename fn( filename ); + + bool b = CheckResult( fn.GetName(), value ); + if( !b ) + { + std::cerr << "Problem with: " << filename << " -> " << value << std::endl; + } + + return !b; +} + +int TestParseXPATH(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestParseXPATHFile(filename, true); + } + + // else + // First of get rid of warning/debug message + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestParseXPATHFile(filename); + ++i; + } + return EXIT_SUCCESS; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestPersonName.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestPersonName.cxx new file mode 100644 index 0000000..6c178cb --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestPersonName.cxx @@ -0,0 +1,79 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmPersonName.h" +#include "gdcmByteValue.h" + +#include + +int TestPersonName(int, char *[]) +{ + typedef gdcm::PersonName PN; + + PN pn0; + pn0.SetComponents(); + std::cout << "NumComp:" << pn0.GetNumberOfComponents() << std::endl; + pn0.Print( std::cout ); + std::cout << std::endl; + + + PN pn00 = {{ "" }}; + std::cout << "NumComp:" << pn00.GetNumberOfComponents() << std::endl; + + PN pn1 = {{ "abc123", "def", "ghi", "klm", "opq" }}; + pn1.Print( std::cout ); + std::cout << std::endl; + std::cout << "NumComp:" << pn1.GetNumberOfComponents() << std::endl; + + PN pn2 = {{ "malaterre", "mathieu olivier patrick"}}; + pn2.Print( std::cout ); + std::cout << std::endl; + std::cout << "NumComp:" << pn2.GetNumberOfComponents() << std::endl; + +// Rev. John Robert Quincy Adams, B.A. M.Div. Adams^John Robert Quincy^^Rev.^B.A. M.Div. [One family name; three given names; no middle name; one prefix; two suffixes.] + PN pn3 = {{ "Adams", "John Robert Quincy", "", "Rev.", "B.A. M.Div." }}; + pn3.Print( std::cout ); + std::cout << std::endl; + std::cout << "NumComp:" << pn3.GetNumberOfComponents() << std::endl; +// Susan Morrison-Jones, Ph.D., Chief Executive Officer Morrison-Jones^Susan^^^Ph.D., Chief Executive Officer [Two family names; one given name; no middle name; no prefix; two suffixes.] + PN pn4 = {{ "Morrison-Jones", "Susan", "", "", "Ph.D., Chief Executive Officer" }}; + pn4.Print( std::cout ); + std::cout << std::endl; + std::cout << "NumComp:" << pn4.GetNumberOfComponents() << std::endl; + +// John Doe Doe^John [One family name; one given name; no middle name, prefix, or suffix. Delimiters have been omitted for the three trailing null components.] + PN pn5 = {{ "Doe", "John" }}; + pn5.Print( std::cout ); + std::cout << std::endl; + std::cout << "NumComp:" << pn5.GetNumberOfComponents() << std::endl; + + +// (for examples of the encoding of Person Names using multi-byte character sets see Annex H) +// Smith^Fluffy [A cat, rather than a +//human, whose responsible party family name is Smith, and whose own name is Fluffy] + PN pn6 = {{ "Smith", "Fluffy" }}; + pn6.Print( std::cout ); + std::cout << std::endl; + std::cout << "NumComp:" << pn6.GetNumberOfComponents() << std::endl; +//ABC Farms^Running on Water [A horse whose responsible organization is named ABC Farms, and whose name is Running On Water] + PN pn7 = {{ "ABC Farms", "Running on Water" }}; + pn7.Print( std::cout ); + std::cout << std::endl; + std::cout << "NumComp:" << pn7.GetNumberOfComponents() << std::endl; + + gdcm::ByteValue bv; + PN pn8; + pn8.SetBlob( bv ); + + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestPhotometricInterpretation.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestPhotometricInterpretation.cxx new file mode 100644 index 0000000..63c8210 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestPhotometricInterpretation.cxx @@ -0,0 +1,97 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmPhotometricInterpretation.h" + +#include // strlen + +int TestPhotometricInterpretation(int, char *[]) +{ + gdcm::PhotometricInterpretation pi; + int end = gdcm::PhotometricInterpretation::PI_END; + for( int i = 0; i < end; ++i) + { + const char *pistr = gdcm::PhotometricInterpretation::GetPIString( (gdcm::PhotometricInterpretation::PIType)i ); + if( strlen( pistr ) % 2 ) + { + std::cerr << pistr << std::endl; + return 1; + } + } + + pi = gdcm::PhotometricInterpretation::RGB; + + pi = gdcm::PhotometricInterpretation::GetPIType( "MONOCHROME2" ); + if( pi != gdcm::PhotometricInterpretation::MONOCHROME2 ) + { + std::cerr << "PhotometricInterpretation: " << pi << std::endl; + return 1; + } + pi = gdcm::PhotometricInterpretation::GetPIType( "MONOCHROME2 " ); + if( pi != gdcm::PhotometricInterpretation::MONOCHROME2 ) + { + std::cerr << "PhotometricInterpretation: " << pi << std::endl; + return 1; + } + pi = gdcm::PhotometricInterpretation::GetPIType( " MONOCHROME2 " ); + if( pi != gdcm::PhotometricInterpretation::MONOCHROME2 ) + { + std::cerr << "PhotometricInterpretation: " << pi << std::endl; + return 1; + } + pi = gdcm::PhotometricInterpretation::GetPIType( " MONOCHROME2 " ); + if( pi != gdcm::PhotometricInterpretation::MONOCHROME2 ) + { + std::cerr << "PhotometricInterpretation: " << pi << std::endl; + return 1; + } + pi = gdcm::PhotometricInterpretation::GetPIType( " MONOCHROME2 " ); + if( pi != gdcm::PhotometricInterpretation::MONOCHROME2 ) + { + std::cerr << "PhotometricInterpretation: " << pi << std::endl; + return 1; + } + pi = gdcm::PhotometricInterpretation::GetPIType( "MONOCHROME" ); + if( pi != gdcm::PhotometricInterpretation::MONOCHROME1 ) + { + std::cerr << "PhotometricInterpretation: " << pi << std::endl; + return 1; + } + pi = gdcm::PhotometricInterpretation::GetPIType( "YBR_PARTIAL_42 " ); + if( pi != gdcm::PhotometricInterpretation::YBR_PARTIAL_422) + { + std::cerr << "PhotometricInterpretation: " << pi << std::endl; + return 1; + } + pi = gdcm::PhotometricInterpretation::GetPIType( "PALETTE" ); + if( pi != gdcm::PhotometricInterpretation::PALETTE_COLOR ) + { + std::cerr << "PhotometricInterpretation: " << pi << std::endl; + return 1; + } + pi = gdcm::PhotometricInterpretation::GetPIType( "YBR_FULL_4" ); + if( pi != gdcm::PhotometricInterpretation::YBR_FULL_422) + { + std::cerr << "PhotometricInterpretation: " << pi << std::endl; + return 1; + } + // FIXME ? + pi = gdcm::PhotometricInterpretation::GetPIType( "YBR_FUL" ); + if( pi != gdcm::PhotometricInterpretation::YBR_FULL ) + { + std::cerr << "PhotometricInterpretation: " << pi << std::endl; + return 1; + } + + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestPixelFormat.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestPixelFormat.cxx new file mode 100644 index 0000000..7ded0d7 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestPixelFormat.cxx @@ -0,0 +1,121 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmPixelFormat.h" + +int TestPixelFormat(int , char *[]) +{ + using gdcm::PixelFormat; + gdcm::PixelFormat pf; + pf.SetScalarType( gdcm::PixelFormat::UNKNOWN ); + if( pf.GetScalarType() != gdcm::PixelFormat::UNKNOWN ) + { + return 1; + } + pf.SetScalarType( gdcm::PixelFormat::UINT32 ); + static const int64_t values[][2] = { + { 0LL,255LL }, + { 0LL,4095LL }, + { 0LL,65535LL }, + { 0LL,4294967295LL }, + { -128LL,127LL }, + { -2048LL,2047LL }, + { -32768LL,32767LL }, + { -2147483648LL,2147483647LL }, + }; + static const size_t n = sizeof( values ) / sizeof( *values ); + size_t c = 0; + pf.SetBitsStored( 8 ); + if( pf.GetMin() != values[c][0] || pf.GetMax() != values[c][1] ) + { + std::cerr << pf.GetMin() << "," << pf.GetMax() << std::endl; + return 1; + } + ++c; + pf.SetBitsStored( 12 ); + if( pf.GetMin() != values[c][0] || pf.GetMax() != values[c][1] ) + { + std::cerr << pf.GetMin() << "," << pf.GetMax() << std::endl; + return 1; + } + ++c; + pf.SetBitsStored( 16 ); + if( pf.GetMin() != values[c][0] || pf.GetMax() != values[c][1] ) + { + std::cerr << pf.GetMin() << "," << pf.GetMax() << std::endl; + return 1; + } + ++c; + pf.SetBitsStored( 32 ); + if( pf.GetMin() != values[c][0] || pf.GetMax() != values[c][1] ) + { + std::cerr << pf.GetMin() << "," << pf.GetMax() << std::endl; + return 1; + } + + pf.SetPixelRepresentation( 1 ); + + ++c; + pf.SetBitsStored( 8 ); + if( pf.GetMin() != values[c][0] || pf.GetMax() != values[c][1] ) + { + std::cerr << pf.GetMin() << "," << pf.GetMax() << std::endl; + return 1; + } + ++c; + pf.SetBitsStored( 12 ); + if( pf.GetMin() != values[c][0] || pf.GetMax() != values[c][1] ) + { + std::cerr << pf.GetMin() << "," << pf.GetMax() << std::endl; + return 1; + } + ++c; + pf.SetBitsStored( 16 ); + if( pf.GetMin() != values[c][0] || pf.GetMax() != values[c][1] ) + { + std::cerr << pf.GetMin() << "," << pf.GetMax() << std::endl; + return 1; + } + ++c; + pf.SetBitsStored( 32 ); + if( pf.GetMin() != values[c][0] || pf.GetMax() != values[c][1] ) + { + std::cerr << pf.GetMin() << "," << pf.GetMax() << std::endl; + return 1; + } + ++c; + if ( c != n ) return 1; + + for(unsigned int i = 0; i < PixelFormat::UNKNOWN; ++i) + { + PixelFormat::ScalarType st = (PixelFormat::ScalarType)i; + pf.SetScalarType( st ); + gdcm::PixelFormat pf2 = st; + std::cout << pf << std::endl; + std::cout << pf.GetPixelRepresentation() << std::endl; + std::cout << pf.GetScalarTypeAsString() << std::endl; + if( pf2 != pf ) return 1; + } + + // make to avoid user mistakes: + gdcm::PixelFormat pf3 = PixelFormat::UINT8; + if( pf3.GetBitsStored() != 8 ) return 1; + pf3.SetBitsStored( 32 ); + // previous call should not execute + if( pf3.GetBitsStored() != 8 ) return 1; + pf3.SetHighBit( 8 ); + if( pf3.GetHighBit() != 7 ) return 1; + + return 0; +} + diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestPrint.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestPrint.cxx new file mode 100644 index 0000000..09bb080 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestPrint.cxx @@ -0,0 +1,65 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmStringFilter.h" +#include "gdcmReader.h" +#include "gdcmSequenceOfItems.h" +#include "gdcmTrace.h" +#include "gdcmTesting.h" + +int TestSimplePrint(const char *filename, bool verbose = false) +{ + gdcm::Reader r; + r.SetFileName( filename ); + if( !r.Read() ) + { + return 1; + } + gdcm::DataSet const& ds = r.GetFile().GetDataSet(); + + int ret = 0; + gdcm::DataSet::ConstIterator it = ds.Begin(); + std::ostringstream os; + for( ; it != ds.End(); ++it) + { + const gdcm::DataElement &ref = *it; + os << ref << std::endl; + } + if( verbose ) std::cout << os.str(); + + return ret; +} + +int TestPrint(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestSimplePrint(filename, true); + } + + // else + // First of get rid of warning/debug message + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestSimplePrint( filename ); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestPrinter.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestPrinter.cxx new file mode 100644 index 0000000..a176fbd --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestPrinter.cxx @@ -0,0 +1,324 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmReader.h" +#include "gdcmPrinter.h" +#include "gdcmFilename.h" +#include "gdcmTesting.h" + +// the following list has been generated using gdcm, git: df760b9d8b3c9b280ad423153c649190f6e21204 +// This correspond to the commit just before: +// BUG: an explicit length VR=SQ dataelement would not have been loaded as +// expected and a call to GetSequenceOfItems would fails. Thus downstream filter +// would fail load the SQ as expected. Introducing the more robust interface: +// GetValueAsSQ to solve that issue. +static const char * const printmd5[][2] = { +{ "a19bffac370df32acbf6b4991d1cbafe" , "00191113.dcm" } , +{ "28f356915bc519137e2555db87e9914e" , "012345.002.050.dcm" } , +{ "94f8c6ab090bdc11e61625bfc2dd39b7" , "05115014-mr-siemens-avanto-syngo-with-palette-icone.dcm" } , +{ "20c11831c616eb121a405cd73de5cba2" , "05148044-mr-siemens-avanto-syngo.dcm" } , +{ "ec10dcbf1b13ace8a6c0cc5b24c6c870" , "3E768EB7.dcm" } , +{ "fde1da68a1707dcc687ddffd57e6b3c3" , "ACUSON-24-YBR_FULL-RLE-b.dcm" } , +{ "a27c6628d6379783a3be223481d5cba4" , "ACUSON-24-YBR_FULL-RLE.dcm" } , +{ "9f3aa114b955a812942f815b6b456eaf" , "ALOKA_SSD-8-MONO2-RLE-SQ.dcm" } , +// MM: Check on Fri Jan 21 08:54:17 CET 2011, for AMIInvalidPrivateDefinedLengthSQasUN.dcm +{ "7e7c192969966d13823aff31482fd66e" , "AMIInvalidPrivateDefinedLengthSQasUN.dcm" } , +{ "9bd2c821bdc3a53b5a6a09b581ef3b9c" , "BugGDCM2_UndefItemWrongVL.dcm" } , +{ "6d2af85d2af299c223b684538d42d9e5" , "CR-MONO1-10-chest.dcm" } , +{ "820d45cefd528e011921ea129bec9084" , "CT_16b_signed-UsedBits13.dcm" } , +{ "2c956e431c1eb19464519a7101134848" , "CT-MONO2-12-lomb-an2.acr" } , +{ "0e4137f63819c706dfa370405d662c79" , "CT-MONO2-16-ankle.dcm" } , +{ "f00a663066627e7ecdd1a7379137d396" , "CT-MONO2-16-brain.dcm" } , +{ "87eadd3a3460c13593c9468bc533aa58" , "CT-MONO2-16-chest.dcm" } , +{ "8b0efbe7cfd72a7d14cef44683fbacab" , "CT-MONO2-16-ort.dcm" } , +{ "32c8e40e0726bbcc374f20771d37a312" , "CT-MONO2-8-abdo.dcm" } , +{ "c5ffd15172c43b200e3654d5e3e45f3e" , "CT-SIEMENS-Icone-With-PaletteColor.dcm" } , +{ "ca0e93a8995fccad9d031e0125ea1a29" , "CT-SIEMENS-MissingPixelDataInIconSQ.dcm" } , +{ "a46ca467a0df5e1c71c8017b6b6768e7" , "D_CLUNIE_CT1_J2KI.dcm" } , +{ "d2698545b07ad721faa71fdc1cf4a35d" , "D_CLUNIE_CT1_J2KR.dcm" } , +{ "78f619a764a94a2c2bdc084d53ad2577" , "D_CLUNIE_CT1_JPLL.dcm" } , +{ "4aaa4a602d7a1fd80c023acba36d6a84" , "D_CLUNIE_CT1_RLE.dcm" } , +{ "9ee24f3a3291cd86f0bc78fddc3417e7" , "D_CLUNIE_CT2_JPLL.dcm" } , +{ "b01b2b28aa3caa945b05865a9c440349" , "D_CLUNIE_CT2_RLE.dcm" } , +{ "7d6531dc92c53ad25835b75fa5505b66" , "D_CLUNIE_MR1_JPLL.dcm" } , +{ "e8a970a1c861192331a98162146ee0f9" , "D_CLUNIE_MR1_JPLY.dcm" } , +{ "6f8b7b128c86c5a670a284e7eac38391" , "D_CLUNIE_MR1_RLE.dcm" } , +{ "b770b1ca257d7c1c885f69a5a1b58808" , "D_CLUNIE_MR2_JPLL.dcm" } , +{ "da74aefef4e8ac49dbe1a4dd3b1dcb26" , "D_CLUNIE_MR2_JPLY.dcm" } , +{ "023eb2a9ecbfd3c04bb148ec339865f0" , "D_CLUNIE_MR2_RLE.dcm" } , +{ "923d4103e1b063db6ed895fb67395750" , "D_CLUNIE_MR3_JPLL.dcm" } , +{ "11b9cfc714d6f8eadc7b8b9c871f7b7d" , "D_CLUNIE_MR3_JPLY.dcm" } , +{ "6773ea516bf525ed1278d23e402a4e78" , "D_CLUNIE_MR3_RLE.dcm" } , +{ "1646ec013060ef3f261849db705f80f3" , "D_CLUNIE_MR4_JPLL.dcm" } , +{ "fbbfe4caab2179641bd0de5d8ccf79ae" , "D_CLUNIE_MR4_JPLY.dcm" } , +{ "fafdb8499580e59c2f6d9047894272ea" , "D_CLUNIE_MR4_RLE.dcm" } , +{ "bc35454da5d8c0825236ccae83adcb82" , "D_CLUNIE_NM1_JPLL.dcm" } , +{ "03527dbfa9b0b82fee7d6eb601abf470" , "D_CLUNIE_NM1_JPLY.dcm" } , +{ "9488a473e2cd1fc981f36643e7dc1b82" , "D_CLUNIE_NM1_RLE.dcm" } , +{ "d9da8798488b1c825dbd4ef940e386b9" , "D_CLUNIE_RG1_JPLL.dcm" } , +{ "68a498853d26cce827eefb0f8be3581d" , "D_CLUNIE_RG1_RLE.dcm" } , +{ "9f652b621320650c6be743b6bafcf539" , "D_CLUNIE_RG2_JPLL.dcm" } , +{ "1f0e2edba097f4491b7d45fed604729d" , "D_CLUNIE_RG2_JPLY.dcm" } , +{ "403e0e40507608cdcd61ee461de91226" , "D_CLUNIE_RG2_RLE.dcm" } , +{ "73ecf348f874e7fb69f5dbfb4637979e" , "D_CLUNIE_RG3_JPLL.dcm" } , +{ "b97b49d7f0bc3a3c3cb421292d8f13b5" , "D_CLUNIE_RG3_JPLY.dcm" } , +{ "ec7dcf6857238547f0fb43f51317b05f" , "D_CLUNIE_RG3_RLE.dcm" } , +{ "af35b9ad269b8a37df3d25389655272e" , "D_CLUNIE_SC1_JPLY.dcm" } , +{ "50f92b02a370e2858632dfde330a2881" , "D_CLUNIE_SC1_RLE.dcm" } , +{ "ad377bc5cc50cb1b6312e9035417b2f1" , "D_CLUNIE_US1_RLE.dcm" } , +{ "e6ea16c1ba4a8e8f97383811fd91288a" , "D_CLUNIE_VL1_RLE.dcm" } , +{ "291ac2ee3c48a76ae0ab9a095199997c" , "D_CLUNIE_VL2_RLE.dcm" } , +{ "91c92c4d1330c283012d2bdd3a91dc2f" , "D_CLUNIE_VL3_RLE.dcm" } , +{ "fcc44b14754a56879e0f3afc8161c1c0" , "D_CLUNIE_VL4_RLE.dcm" } , +{ "d7ded36c6827f41d61790bed41b963e3" , "D_CLUNIE_VL6_RLE.dcm" } , +{ "75801e9732698ea89740f935052f28d6" , "D_CLUNIE_XA1_JPLL.dcm" } , +{ "79d8daf6837a4b5aefaa963b1fb88df1" , "D_CLUNIE_XA1_JPLY.dcm" } , +{ "e2bda8297745ab7a77ca84242ad4c980" , "D_CLUNIE_XA1_RLE.dcm" } , +{ "bb52d9f7a9116c87103066dd18a60e68" , "D_CLUNIE_CT1_JLSN.dcm" } , +{ "8984d6319cd913d0f88fdb61989412f2" , "D_CLUNIE_CT1_JLSL.dcm" } , +{ "4ef94d44a83066b80b39d254fb2a1c28" , "DCMTK_JPEGExt_12Bits.dcm" } , +{ "d982dca9cc6c9db94a6233ca76e52f26" , "DermaColorLossLess.dcm" } , +{ "ee354d9b221360982f15b630e1fdb046" , "DICOMDIR" } , +{ "3082f3a587959183b5c24ae8d7ec5b08" , "dicomdir_Acusson_WithPrivate_WithSR" } , +{ "9934ab3c8adca82cad0fe8997b6c5cd3" , "DICOMDIR_MR_B_VA12A" } , +{ "6a4cfd1ddd6eea5538dd7f8cf1ba1e1f" , "DICOMDIR-Philips-EasyVision-4200-Entries" } , +{ "4254e4123245565e43a86e191acff01b" , "dicomdir_Pms_With_heavy_embedded_sequence" } , +{ "9afc3c3e9d208292430b45867a9981e1" , "dicomdir_Pms_WithVisit_WithPrivate_WithStudyComponents" } , +{ "356f30be965bbe4e335a56c6c5fe1928" , "dicomdir_With_embedded_icons" } , +{ "d174a9f2dea0da9e013eb3180317ebbc" , "DMCPACS_ExplicitImplicit_BogusIOP.dcm" } , +{ "c4aadaeb6c526040dcc035e40ee739a5" , "DX_GE_FALCON_SNOWY-VOI.dcm" } , +{ "1cbeb77ea2d6e0171dd38e0d6d5cb0b9" , "DX_J2K_0Padding.dcm" } , +{ "3493bf0e698798529fde6ef488289879" , "ELSCINT1_JP2vsJ2K.dcm" } , +{ "8f5581be656bd6f1ab6c9ec94f302284" , "ELSCINT1_LOSSLESS_RICE.dcm" } , +{ "54f138a1aa6819ec1560a7ed344cde1a" , "ELSCINT1_PMSCT_RLE1.dcm" } , +{ "177e832e1ccacfeb4c46fec80840cd62" , "ExplicitVRforPublicElementsImplicitVRforShadowElements.dcm" } , +{ "3199cd21166043d619209d7a2073fb56" , "fffc0000UN.dcm" } , +{ "9b426b02521cbc2f3ee25ab383ca835e" , "FUJI-10-MONO1-ACR_NEMA_2.dcm" } , +{ "b920721186daa8b36a1db4a9fb0e568a" , "gdcm-ACR-LibIDO.acr" } , +{ "b808c747b59f9d1a91a01491103abea5" , "gdcm-CR-DCMTK-16-NonSamplePerPix.dcm" } , +{ "e7b5089a2a007221993ee5a7e6d44959" , "gdcm-JPEG-Extended.dcm" } , +{ "20894653d750b4edf6034258a8dc3cf7" , "gdcm-JPEG-LossLess3a.dcm" } , +{ "5011206e2a744c8a6f2cedb1ff7e5e11" , "gdcm-JPEG-LossLessThoravision.dcm" } , +{ "899271699b9bd83c0ebd0e3e21785489" , "gdcm-MR-PHILIPS-16-Multi-Seq.dcm" } , +{ "3ada4145885084c465fc0d2969299428" , "gdcm-MR-PHILIPS-16-NonSquarePixels.dcm" } , +{ "f6cf42e1b54868bd2bfb3ffacebfbb1b" , "gdcm-MR-SIEMENS-16-2.acr" } , +{ "48c49a7a41a7efea9ea0eadcd89ac9fa" , "gdcm-US-ALOKA-16.dcm" } , +{ "9e9f42e825db2951519320c2e907d936" , "GE_CT_With_Private_compressed-icon.dcm" } , +{ "9e126a24f81534e1cd653f16739a6192" , "GE_DLX-8-MONO2-Multiframe.dcm" } , +{ "6b66f8c38fe96db805e7dedd9a997811" , "GE_DLX-8-MONO2-Multiframe-Jpeg_Lossless.dcm" } , +{ "61ca6c5115e6f74565f6f2ca06647444" , "GE_DLX-8-MONO2-PrivateSyntax.dcm" } , +{ "2ed065d325227d88abfaaa7b6b693b75" , "GE_GENESIS-16-MONO2-Uncompressed-UnusualVR.dcm" } , +{ "8d398fce426d3a248d8c3f7582e3751d" , "GE_GENESIS-16-MONO2-WrongLengthItem.dcm" } , +{ "bb5d500a0391a399b035968496b6fd5d" , "GE_LOGIQBook-8-RGB-HugePreview.dcm" } , +{ "4baf83d23aa101ba8853193478764bda" , "GE_MR_0025xx1bProtocolDataBlock.dcm" } , +{ "d5efa34d8091e1ad04683eefb41f33c7" , "GE_RHAPSODE-16-MONO2-JPEG-Fragments.dcm" } , +{ "d41d8cd98f00b204e9800998ecf8427e" , "IM-0001-0066.dcm" } , +{ "cd085d783924d8a7fa2270ff40c6dc3e" , "ITK_GDCM124_MultiframeSecondaryCaptureInvalid.dcm" } , +{ "b47e43977843d8ceae0fcd957baf2692" , "JDDICOM_Sample2.dcm" } , +{ "132cb5de391304c8a4f7653118d72d99" , "JDDICOM_Sample2-dcmdjpeg.dcm" } , +{ "26d62bfecd2133f20a8d622c9fe15b9a" , "JPEGDefinedLengthSequenceOfFragments.dcm" } , +{ "9c0548b6cc474c309686cfc3bdff7723" , "JPEG_LossyYBR.dcm" } , +{ "aabb6942cee8e8d2ecbd8706e6c10a53" , "KODAK-12-MONO1-Odd_Terminated_Sequence.dcm" } , +{ "492ba4d8a4b904a15a4f14fe35b31a16" , "KODAK_CompressedIcon.dcm" } , +{ "9a085a611f192d6939b992be4e02fc8f" , "LEADTOOLS_FLOWERS-16-MONO2-JpegLossless.dcm" } , +{ "4c884d7e06658c53275c932358e83f50" , "LEADTOOLS_FLOWERS-16-MONO2-RLE.dcm" } , +{ "b879261a881099f66c6417487b5727e6" , "LEADTOOLS_FLOWERS-16-MONO2-Uncompressed.dcm" } , +{ "792f30183573b0a228a8d372de1fd3e2" , "LEADTOOLS_FLOWERS-24-RGB-JpegLossless.dcm" } , +{ "9163d48f9b103792d7cc2401bd880efc" , "LEADTOOLS_FLOWERS-24-RGB-JpegLossy.dcm" } , +{ "0b88e68d7629601e885db6126bdec0e5" , "LEADTOOLS_FLOWERS-24-RGB-Uncompressed.dcm" } , +{ "3cbcc077573136a5cc96bd9cc4c6d42e" , "LEADTOOLS_FLOWERS-8-MONO2-JpegLossy.dcm" } , +{ "a3074d046c5f382f62e6ee6b3f9561ea" , "LEADTOOLS_FLOWERS-8-MONO2-RLE.dcm" } , +{ "b31da32c67ac695376cc928150be98d2" , "LEADTOOLS_FLOWERS-8-MONO2-Uncompressed.dcm" } , +{ "ea9f4285ce92f9db2e349c7132fb849e" , "LEADTOOLS_FLOWERS-8-PAL-RLE.dcm" } , +{ "9bac4c50cd8afce8f9995cefd542760f" , "LEADTOOLS_FLOWERS-8-PAL-Uncompressed.dcm" } , +{ "b33f1a1050fc7135295a02627be88514" , "libido1.0-vol.acr" } , +{ "05fe8714421e16371d62ae2c280b7107" , "LIBIDO-16-ACR_NEMA-Volume.dcm" } , +{ "c0b5d6b5cd8bf16e94f8d5db64aa9a4a" , "LIBIDO-24-ACR_NEMA-Rectangle.dcm" } , +{ "3338d3db1705db1b9a6474043b4772e3" , "LIBIDO-8-ACR_NEMA-Lena_128_128.acr" } , +{ "e39e4923be2d8bb2fb19c6c8deae216f" , "LJPEG_BuginGDCM12.dcm" } , +{ "e6bc657d132abebb01a675ade04129f1" , "MARCONI_MxTWin-12-MONO2-JpegLossless-ZeroLengthSQ.dcm" } , +{ "174d5848257864f700c2e32d8441d0c5" , "MAROTECH_CT_JP2Lossy.dcm" } , +{ "497d6ea45b8f3f7f6a3bf8125dcc43b1" , "MR16BitsAllocated_8BitsStored.dcm" } , +{ "5b23ccf10ad6358b253a7ec185deb2a9" , "MR-Brucker-CineTagging-NonSquarePixels.dcm" } , +{ "31246836410a24124acf6bea5a36a942" , "MR_ELSCINT1_00e1_1042_SQ_feff_00e0_Item.dcm" } , +{ "c5042379519ac6b25df96b4ada96e9b1" , "MR_GE_with_Private_Compressed_Icon_0009_1110.dcm" } , +{ "299776ad327c80f5caed305943f26041" , "MR-MONO2-12-an2.acr" } , +{ "b4058b67ec1eb3d3d3acde27d51eb24a" , "MR-MONO2-12-angio-an1.acr" } , +{ "f782f6ea25928310bd69c3ca5c6a97d2" , "MR-MONO2-12-shoulder.dcm" } , +{ "7f6bccb00b34a7d277eacaffd2bb0362" , "MR-MONO2-16-head.dcm" } , +{ "9bd4d79cc59c66b19c21577e12cd6226" , "MR-MONO2-8-16x-heart.dcm" } , +{ "d1b3b9ee6905b49ec70338f1f1c718bb" , "MR_Philips-Intera_BreaksNOSHADOW.dcm" } , +{ "216e2c1f7f7f27e2a7d0bcefd49ab23c" , "MR_Philips_Intera_No_PrivateSequenceImplicitVR.dcm" } , +{ "abce00bceef1711dca51e26950fc7a61" , "MR_Philips_Intera_PrivateSequenceExplicitVR_in_SQ_2001_e05f_item_wrong_lgt_use_NOSHADOWSEQ.dcm" } , +{ "1cad78e854ba2eea2d5fbe9c8c1bbcd4" , "MR_Philips_Intera_PrivateSequenceImplicitVR.dcm" } , +{ "a812bbfd98e706b09ca6f9c9b06d16fc" , "MR_Philips_Intera_SwitchIndianess_noLgtSQItem_in_trueLgtSeq.dcm" } , +{ "5797c9dfe94e4a4bccfbf81ab0aaa957" , "MR-SIEMENS-DICOM-WithOverlays.dcm" } , +{ "df28467760104edc923d0625a0e2a778" , "MR-SIEMENS-DICOM-WithOverlays-extracted-overlays.dcm" } , +{ "bf324a1c91d3a09d9136f54f5910e570" , "MR_SIEMENS_forceLoad29-1010_29-1020.dcm" } , +{ "f4df164cd5dbfd69f48fd3bfd5f85a8c" , "MR_Spectroscopy_SIEMENS_OF.dcm" } , +{ "1a5646a7b05840813c067d8c8dfa507e" , "NM-MONO2-16-13x-heart.dcm" } , +{ "8d8c3b8eb830b57b162e7c9f2d64b214" , "OsirixFake16BitsStoredFakeSpacing.dcm" } , +{ "bf793beb0e96f2399e467409e3cf5311" , "OT-MONO2-8-a7.dcm" } , +{ "7f4cddc9a88f8c5147b89f769eb1cae7" , "OT-PAL-8-face.dcm" } , +{ "5fce2728bd9457d4fc1224a374829e2f" , "PET-cardio-Multiframe-Papyrus.dcm" } , +{ "071b840050588d14fde61646e058e1c6" , "PHILIPS_Brilliance_ExtraBytesInOverlay.dcm" } , +{ "308e32440ff9db54a01aa6aa7ed9d361" , "PHILIPS_GDCM12xBug2.dcm" } , +{ "396d76f4143e544782ac23df3394b542" , "PHILIPS_GDCM12xBug.dcm" } , +{ "aa4e366280c194b4012083851d30e5dc" , "PHILIPS_Gyroscan-12-Jpeg_Extended_Process_2_4.dcm" } , +{ "7817b32c5ac02e52b4d7d84f8729357a" , "PHILIPS_Gyroscan-12-MONO2-Jpeg_Lossless.dcm" } , +{ "61dc10a3cf58063848b1eb8075b04337" , "PHILIPS_Gyroscan-8-MONO2-Odd_Sequence.dcm" } , +{ "211eee5dbca0899f762c788acc1fb3c2" , "PHILIPS_Intera-16-MONO2-Uncompress.dcm" } , +{ "4f34474ed72e6a5960fc4691e588f8e0" , "PICKER-16-MONO2-Nested_icon.dcm" } , +{ "629da04611e097e2cc532d6fe5e6454d" , "PICKER-16-MONO2-No_DicomV3_Preamble.dcm" } , +{ "3aaca1826b4a4deb9e41ebf2af4fa6b2" , "PrivateGEImplicitVRBigEndianTransferSyntax16Bits.dcm" } , +{ "6dc48ff6f48d3c09db2fe877630ab003" , "RadBWLossLess.dcm" } , +{ "c2f13224f3f0bc3aa8bbfa6f4a0a23ec" , "rle16loo.dcm" } , +{ "bd5d9b2f994cfc0c6a95cca8c586533a" , "rle16sti.dcm" } , +{ "631c5bb2e2f046215999072d13316363" , "SIEMENS-12-Jpeg_Process_2_4-Lossy-a.dcm" } , +{ "593324f844b730f77bb4a337f51f3b3d" , "SIEMENS_CSA2.dcm" } , +{ "fa919f3ee7cef3af1f362dd166d53103" , "SIEMENS_GBS_III-16-ACR_NEMA_1.acr" } , +{ "825580733e8cfaf5d8679348889db40d" , "SIEMENS_GBS_III-16-ACR_NEMA_1-ULis2Bytes.dcm" } , +{ "ff6bf3c70ef86ca08244317afd7fb98a" , "SIEMENS_ImageLocationUN.dcm" } , +{ "f6cf42e1b54868bd2bfb3ffacebfbb1b" , "SIEMENS_MAGNETOM-12-ACR_NEMA_2-Modern.dcm" } , +{ "5202b5e2521b1a5b480317864081beae" , "SIEMENS_MAGNETOM-12-MONO2-FileSeq0.dcm" } , +{ "8969371a42ecebc02f316a344a887c81" , "SIEMENS_MAGNETOM-12-MONO2-FileSeq1.dcm" } , +{ "c32e8171b87f3825bf6a37c4ed4b627a" , "SIEMENS_MAGNETOM-12-MONO2-FileSeq2.dcm" } , +{ "ea85da9fae20a585af6a71467916fa4a" , "SIEMENS_MAGNETOM-12-MONO2-FileSeq3.dcm" } , +{ "1e22b1b3ef16b82cac4299279018282a" , "SIEMENS_MAGNETOM-12-MONO2-GDCM12-VRUN.dcm" } , +{ "16f02a1ee88f8753978a3dad9a5968ac" , "SIEMENS_MAGNETOM-12-MONO2-Uncompressed.dcm" } , +{ "09fc7fb4d8d2fce59ad12f51da0bddfd" , "SIEMENS_MAGNETOM-12-MONO2-VRUN.dcm" } , +{ "082dbd9bea567b86cc4415d66ff158e5" , "SIEMENS_MOSAIC_12BitsStored-16BitsJPEG.dcm" } , +{ "be0b7098b442990aebf3364d747af482" , "SIEMENS-MR-RGB-16Bits.dcm" } , +{ "2dc5ec56d0973eabf54df71a4844db7c" , "SIEMENS_SOMATOM-12-ACR_NEMA-ZeroLengthUs.acr" } , +{ "5fc4be2074b6186d3993818cd1baeb89" , "SIEMENS_Sonata-12-MONO2-SQ.dcm" } , +{ "c56ae357244ed3d4203c2b28fe3ab447" , "SIEMENS_Sonata-16-MONO2-Value_Multiplicity.dcm" } , +{ "7176eb4ec64dab63578eb6826318c87d" , "SignedShortLosslessBug.dcm" } , +{ "ba40a5d86160fb17474759e7408c5326" , "simpleImageWithIcon.dcm" } , +{ "9331b13c9d8945a07656d4d08bf4820b" , "test.acr" } , +{ "0c2c475f6d21ae0aeadbf16565dcdbc4" , "TG18-CH-2k-01.dcm" } , +{ "e8cc7ed19eedf9bed9ab60683f3dbfa1" , "THERALYS-12-MONO2-Uncompressed-Even_Length_Tag.dcm" } , +{ "8c80dcb91b204820e7d57ad0bdb2e945" , "TheralysGDCM120Bug.dcm" } , +{ "e8819809884c214fe78ee2b227417e5c" , "TOSHIBA_MRT150-16-MONO2-ACR_NEMA_2.dcm" } , +{ "408d556013117b9e60b610d97f41c211" , "undefined_length_un_vr.dcm" } , +{ "787ca80c8dd1aa619d5f85610862380b" , "US-GE-4AICL142.dcm" } , +{ "f1e9c893391e1d458cffa2a1e0904160" , "US-IRAD-NoPreambleStartWith0003.dcm" } , +{ "d1d9be67c9d066fabc8e1c4ae124f9a0" , "US-IRAD-NoPreambleStartWith0005.dcm" } , +{ "17222122d388f2c1185884c644c041db" , "US-MONO2-8-8x-execho.dcm" } , +{ "d58a4930f5b436939d297730b883d5b9" , "US-PAL-8-10x-echo.dcm" } , +{ "e0552f839d327506c32c4b9ceeb56459" , "US-RGB-8-epicard.dcm" } , +{ "77bd6ff6dcac8e4fb763253e047dbdd2" , "US-RGB-8-esopecho.dcm" } , +{ "7a3535f869f4a450b8de3d73a268e713" , "XA-MONO2-8-12x-catheter.dcm" } , +{ "167af475c7e2f4605544fa1602c34d50" , "IM-0001-0066.CommandTag00.dcm" }, +{ "d2cb6962750eb8f92c480e6cc2f4d104" , "GDCMJ2K_TextGBR.dcm" }, +{ "2e039bbc7520f809963e051ff5144ccf" , "UnexpectedSequenceDelimiterInFixedLengthSequence.dcm" }, +{ "0a90894370ba84dbe31acd1290ff9999" , "NM_Kakadu44_SOTmarkerincons.dcm" }, +{ "504f0fae0f9e6e1ed2a03a5c96c0500f" , "PhilipsInteraSeqTermInvLen.dcm" }, +{ "2940bd46f097f79012d24f47504c3c8c" , "TOSHIBA_J2K_OpenJPEGv2Regression.dcm" }, +{ "696917fea41e83b9980bad82b609162c" , "TOSHIBA_J2K_SIZ0_PixRep1.dcm" }, +{ "7ef3da46c43e51cfe2eb82e4d23dd623" , "TOSHIBA_J2K_SIZ1_PixRep0.dcm" }, +{ "7f69568a362343fe7ff0266db7b3614f" , "NM-PAL-16-PixRep1.dcm" }, +{ "8272b02db757629bf21b2cbea24e6e93" , "MEDILABInvalidCP246_EVRLESQasUN.dcm" }, +{ "7483119e9d4facc0cfcc1fb0532fc4a0" , "JPEGInvalidSecondFrag.dcm" }, + +{ 0 ,0 } +}; + +int TestPrint(const char *filename, bool verbose= false) +{ + gdcm::Reader r; + r.SetFileName( filename ); + if( !r.Read() ) + { + std::cerr << "Could not read: " << filename << std::endl; + return 1; + } + + gdcm::Printer print; + print.SetFile( r.GetFile() ); + std::ostringstream out; + if( verbose ) + print.Print( std::cout ); + print.Print( out ); + + gdcm::Filename fn( filename ); + const char *name = fn.GetName(); + + std::string buf = out.str(); + if( buf.find( "GDCM:UNKNOWN" ) != std::string::npos ) + { + if( strcmp(name, "test.acr" ) != 0 + && strcmp(name, "LIBIDO-8-ACR_NEMA-Lena_128_128.acr" ) != 0 + && strcmp(name, "gdcm-ACR-LibIDO.acr" ) != 0 + && strcmp(name, "SIEMENS_GBS_III-16-ACR_NEMA_1.acr" ) != 0 + && strcmp(name, "LIBIDO-24-ACR_NEMA-Rectangle.dcm" ) != 0 + && strcmp(name, "NM_Kakadu44_SOTmarkerincons.dcm" ) != 0 + ) + { + std::cerr << "UNKNOWN Attribute with : " << name << std::endl; + return 1; + } + } + char digest[33]; + gdcm::Testing::ComputeMD5(&buf[0], buf.size(), digest); + + unsigned int i = 0; + const char *p = printmd5[i][1]; + while( p != 0 ) + { + if( strcmp( name, p ) == 0 ) + { + break; + } + ++i; + p = printmd5[i][1]; + } + + const char *refmd5 = printmd5[i][0]; + if( !refmd5 ) + { + std::cerr << "Problem with : " << name << " missing md5= " << digest << std::endl; + return 1; + } + if( strcmp( refmd5, digest) ) + { + std::cerr << "Problem with : " << name << " " << refmd5 << " vs " << digest << std::endl; + return 1; + } + + return 0; +} + + +int TestPrinter(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestPrint(filename, true); + } + + // else + int r = 0, i = 0; + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + gdcm::Trace::ErrorOff(); + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestPrint( filename ); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestPrinter2.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestPrinter2.cxx new file mode 100644 index 0000000..8a10903 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestPrinter2.cxx @@ -0,0 +1,72 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmReader.h" +#include "gdcmPrinter.h" +#include "gdcmFilename.h" +#include "gdcmTesting.h" +#include "gdcmGlobal.h" +#include "gdcmDicts.h" + +/* + This test exercise a very obscure section of gdcm::Printer + when it handles a SQ when it is hiden as VR::UN + undefined + length which means this is a Implicit VR Little Endian + encoded SQ in an Explicit VR Little Endian DataSet +*/ +int TestPrinter2(int , char *[]) +{ + const char *directory = gdcm::Testing::GetDataRoot(); + std::string filename = std::string(directory) + "/undefined_length_un_vr.dcm"; + + gdcm::Reader r; + r.SetFileName( filename.c_str() ); + if( !r.Read() ) + { + return 1; + } + + gdcm::Printer print; + print.SetFile( r.GetFile() ); + std::ostringstream out; + print.Print( out ); + + gdcm::Global &g = gdcm::Global::GetInstance(); + gdcm::Dicts &dicts = g.GetDicts(); + gdcm::PrivateDict &priv_dict = dicts.GetPrivateDict(); + + gdcm::PrivateTag pt(0x2001,0x005f,"Philips Imaging DD 001"); + if( !priv_dict.RemoveDictEntry( pt ) ) + { + return 1; + } + + gdcm::Reader r2; + r2.SetFileName( filename.c_str() ); + if( !r2.Read() ) + { + return 1; + } + + gdcm::Printer print2; + print2.SetFile( r.GetFile() ); + std::ostringstream out2; + print2.Print( out2 ); + +// if( out2.str() != out.str() ) +// { +// return 1; +// } + + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestRAWCodec.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestRAWCodec.cxx new file mode 100644 index 0000000..6687c0f --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestRAWCodec.cxx @@ -0,0 +1,22 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmRAWCodec.h" + +int TestRAWCodec(int argc, char *argv[]) +{ + (void)argc; + (void)argv; + + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestRLECodec.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestRLECodec.cxx new file mode 100644 index 0000000..67c8e98 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestRLECodec.cxx @@ -0,0 +1,21 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmTypes.h" + +int TestRLECodec(int, char *[]) +{ + // Compress a black images: should give a good result + // Compress a checkboard (black/white alternate). Should give a mediocre result + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestRescaler.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestRescaler.cxx new file mode 100644 index 0000000..06c30e0 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestRescaler.cxx @@ -0,0 +1,137 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmRescaler.h" +#include + +#include // atof + +int TestRescaler(int, char *[]) +{ + gdcm::Rescaler ir; + + /* +gdcmData/MR-MONO2-12-shoulder.dcm +(gdb) p intercept +$1 = 6.0999999999999999e-05 +(gdb) p slope +$2 = 3.774114 +(gdb) p in[i] +$3 = 3.77417493 +... +p (in[i] - intercept)/slope +$7 = 0.99999998109891775 + +$10 = {Intercept = 6.0999999999999999e-05, Slope = 3.774114, PF = {SamplesPerPixel = 1, BitsAllocated = 32, BitsStored = 32, HighBit = 31, PixelRepresentation = 3}, ScalarRangeMin = 6.0999998822808266e-05, + ScalarRangeMax = 247336.561051} + +*/ + + // (0028,1052) DS [0.000061] # 8, 1 RescaleIntercept + // (0028,1053) DS [3.774114] # 8, 1 RescaleSlope + + const double intercept = atof( "0.000061" ); + const double slope = atof( "3.774114" ); + ir.SetIntercept( intercept ); + ir.SetSlope( slope ); + ir.SetPixelFormat( gdcm::PixelFormat::FLOAT64 ); + const double smin = 6.0999998822808266e-05; + const double smax = 247336.561051; + ir.SetMinMaxForPixelType( smin, smax ); + + double outref[] = { 0 }; + { + char *copy = (char*)outref; + const uint16_t in[] = { 1 }; + const char *tempimage = (char*)in; + size_t vtklen = sizeof(in); + ir.SetPixelFormat( gdcm::PixelFormat::UINT16 ); + bool b = ir.Rescale(copy,tempimage,vtklen); + if( !b ) return 1; + + std::cout << outref[0] << std::endl; + } + + ir.SetPixelFormat( gdcm::PixelFormat::FLOAT64 ); + uint16_t out[] = { 0 }; + char *copy = (char*)out; + //const double in[] = { 3.77417493 }; + const double in[] = { 3.774175 }; + if( outref[0] != in[0] ) + { + std::cerr << "Wrong input/output:" << std::endl; + std::cerr << outref[0] << " vs " << in[0] << std::endl; + std::cerr << (outref[0] - in[0]) << std::endl; + return 1; + } + const char *tempimage = (char*)in; + size_t vtklen = sizeof(in); + ir.InverseRescale(copy,tempimage,vtklen); + + std::cout << out[0] << std::endl; + if( out[0] != 1 ) + { + return 1; + } + + // Let's make sure that rescaler works in the simpliest case + // it should be idempotent: +{ + gdcm::PixelFormat pixeltype = gdcm::PixelFormat::INT16; + gdcm::Rescaler r; + r.SetIntercept( 0.0 ); + r.SetSlope( 1.0 ); + r.SetPixelFormat( pixeltype ); + gdcm::PixelFormat::ScalarType outputpt; + outputpt = r.ComputeInterceptSlopePixelType(); + + if( outputpt != pixeltype ) + { + return 1; + } + if( ! (outputpt == pixeltype) ) + { + return 1; + } +} + +{ + gdcm::PixelFormat::ScalarType outputpt ; + double shift = -1024; + double scale = 1; + // gdcmData/CT-MONO2-16-ort.dcm + gdcm::PixelFormat pixeltype( 1, 16, 16, 15, 1 ); + gdcm::Rescaler r; + r.SetIntercept( shift ); + r.SetSlope( scale ); + r.SetPixelFormat( pixeltype ); + outputpt = r.ComputeInterceptSlopePixelType(); + // min,max = [-33792, 31743] + // we need at least int32 to store that + if( outputpt != gdcm::PixelFormat::INT32 ) + { + return 1; + } + // let's pretend image is really the full range: + // FIXME: I think it is ok to compute this way since shift is double anyway: + r.SetMinMaxForPixelType(std::numeric_limits::min() + shift,std::numeric_limits::max() + shift ); + + gdcm::PixelFormat pf2 = r.ComputePixelTypeFromMinMax(); + if( pf2 != pixeltype ) + { + return 1; + } +} + + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestScanner.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestScanner.cxx new file mode 100644 index 0000000..9d58ee3 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestScanner.cxx @@ -0,0 +1,234 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmScanner.h" +#include "gdcmDirectory.h" +#include "gdcmSystem.h" +#include "gdcmTesting.h" +#include "gdcmTrace.h" + +// dcmdump /path/to/image/*.dcm 2>&/dev/null| grep 0020 | grep "000e\|000d" | sort | uniq +// +// $ find /images/ -type f -exec dcmdump -s +P 0010,0010 {} \; + +int TestScannerExtra() +{ + const char *extradataroot = gdcm::Testing::GetDataExtraRoot(); + if( !extradataroot ) + { + return 1; + } + if( !gdcm::System::FileIsDirectory(extradataroot) ) + { + std::cerr << "No such directory: " << extradataroot << std::endl; + return 1; + } + + gdcm::Directory d; + unsigned int nfiles = d.Load( extradataroot, true ); // no recursion + std::cout << "done retrieving file list. " << nfiles << " files found." << std::endl; + + gdcm::Scanner s; + const gdcm::Tag t1(0x0020,0x000d); // Study Instance UID + const gdcm::Tag t2(0x0020,0x000e); // Series Instance UID + const gdcm::Tag t3(0x0010,0x0010); // Patient's Name + const gdcm::Tag t4(0x0004,0x5678); // DUMMY element + const gdcm::Tag t5(0x0028,0x0010); // Rows + const gdcm::Tag t6(0x0028,0x0011); // Columns + s.AddTag( t1 ); + s.AddTag( t2 ); + s.AddTag( t3 ); + s.AddTag( t4 ); + s.AddTag( t5 ); + s.AddTag( t6 ); + bool b = s.Scan( d.GetFilenames() ); + if( !b ) + { + std::cerr << "Scanner failed" << std::endl; + return 1; + } + //s.Print( std::cout ); + return 0; +} + +int TestScanner(int argc, char *argv[]) +{ + gdcm::Trace::WarningOff(); + gdcm::Trace::ErrorOff(); + const char *directory = gdcm::Testing::GetDataRoot(); + if( argc == 2 ) + { + directory = argv[1]; + } + + if( !gdcm::System::FileIsDirectory(directory) ) + { + std::cerr << "No such directory: " << directory << std::endl; + return 1; + } + + gdcm::Directory d; + unsigned int nfiles = d.Load( directory ); // no recursion +// d.Print( std::cout ); + std::cout << "done retrieving file list. " << nfiles << " files found." << std::endl; + + gdcm::Scanner s; + const gdcm::Tag t1(0x0020,0x000d); // Study Instance UID + const gdcm::Tag t2(0x0020,0x000e); // Series Instance UID + const gdcm::Tag t3(0x0010,0x0010); // Patient's Name + const gdcm::Tag t4(0x0004,0x5678); // DUMMY element + const gdcm::Tag t5(0x0028,0x0010); // Rows + const gdcm::Tag t6(0x0028,0x0011); // Columns + const gdcm::Tag t7(0x0008,0x0016); // + s.AddTag( t1 ); + s.AddTag( t2 ); + s.AddTag( t3 ); + s.AddTag( t4 ); + s.AddTag( t5 ); + s.AddTag( t6 ); + s.AddTag( t7 ); + bool b = s.Scan( d.GetFilenames() ); + if( !b ) + { + std::cerr << "Scanner failed" << std::endl; + return 1; + } +// s.Print( std::cout ); + + gdcm::Directory::FilenamesType const & files = s.GetFilenames(); + if( files != d.GetFilenames() ) + { + return 1; + } + + int numerrors = 0; + for( gdcm::Directory::FilenamesType::const_iterator it = files.begin(); it != files.end(); ++it ) + { + const char *filename = it->c_str(); + const char* value = s.GetValue(filename, t7); + const char *msstr = gdcm::Testing::GetMediaStorageFromFile(filename); + if( msstr && strcmp(msstr, "1.2.840.10008.1.3.10" ) == 0 ) + { + // would need to check (0002,0002)... + } + if( value && msstr ) + { + if( strcmp( value, msstr ) != 0 ) + { + std::cerr << "Problem with file " << filename << std::endl; + std::cerr << value << "/" << msstr << std::endl; + ++numerrors; + } + } + else + { + if ( !msstr ) + { + std::cerr << "Problem with file " << filename << std::endl; + if( value ) std::cerr << "Value found: " << value << std::endl; + ++numerrors; + } + } + } + + if( numerrors ) + return numerrors; + + // Check dummy filename: + bool iskey = s.IsKey( "gdcm.rocks.invalid.name" ); + if( iskey ) + { + std::cout << "IsKey returned: " << iskey << std::endl; + return 1; + } + + // Let's get the value for tag t1 in first file: + gdcm::Scanner::MappingType const &mt = s.GetMappings(); + std::string sfilename; + sfilename = gdcm::Testing::GetDataRoot(); + sfilename+= "/test.acr"; +{ + //const char *filename = d.GetFilenames()[0].c_str(); + const char *filename = sfilename.c_str(); + // The following breaks with Papyrus file: PET-cardio-Multiframe-Papyrus.dcm + unsigned int i = 0; + gdcm::Scanner::MappingType::const_iterator it = mt.find(filename); + assert( it != mt.end() ); + while( it == mt.end() ) + { + ++i; + if( i == d.GetFilenames().size() ) + { + return 1; + } + filename = d.GetFilenames()[i].c_str(); + it = mt.find(filename); + } + std::cout << "Mapping for " << filename << " is :" << std::endl; + const gdcm::Scanner::TagToValue &tv = it->second; + //const std::string &filename = d.GetFilenames()[0]; + gdcm::Scanner::TagToValue::const_iterator it2 = tv.find( t5 ); + if( it2 == tv.end() || t5 != it2->first ) + { + std::cerr << "Could not find tag:" << t5 << std::endl; + return 1; + } + const char * t1value = it2->second; + std::cout << filename << " -> " << t1 << " = " << (*t1value ? t1value : "none" ) << std::endl; +} + + const gdcm::Directory::FilenamesType &filenames = d.GetFilenames(); +{ + gdcm::Directory::FilenamesType::const_iterator it = filenames.begin(); + for(; it != filenames.end(); ++it) + { + const char *filename = it->c_str(); + const gdcm::Tag &reftag = t6; + const char *value = s.GetValue( filename, reftag ); + if( value ) + { + assert( value ); + std::cout << filename << " has " << reftag << " = " << value << std::endl; + } + else + { + std::cout << filename << " has " << reftag << " = no value or not DICOM" << std::endl; + } + } +} +/* +{ + std::vector keys = s.GetKeys(); + for( std::vector::const_iterator it = keys.begin(); it != keys.end(); ++it) + { + const char *filename = *it; + const gdcm::Directory::FilenamesType::const_iterator it2 + = std::find(filenames.begin(), filenames.end(), filename); + if( it2 == filenames.end() ) + { + return 1; + } + if( !s.IsKey( filename ) ) + { + return 1; + } + } +} +*/ + + // puposely discard gdcmDataExtra test, this is just an 'extra' test... + int b2 = TestScannerExtra(); (void)b2; + + + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestSegmentedPaletteColorLookupTable.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestSegmentedPaletteColorLookupTable.cxx new file mode 100644 index 0000000..275555c --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestSegmentedPaletteColorLookupTable.cxx @@ -0,0 +1,20 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmSegmentedPaletteColorLookupTable.h" + +int TestSegmentedPaletteColorLookupTable(int, char *[]) +{ + gdcm::SegmentedPaletteColorLookupTable o; + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestSerieHelper.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestSerieHelper.cxx new file mode 100644 index 0000000..d85f7ef --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestSerieHelper.cxx @@ -0,0 +1,20 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmSerieHelper.h" + +int TestSerieHelper(int, char *[]) +{ + gdcm::SerieHelper sh; + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestSorter.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestSorter.cxx new file mode 100644 index 0000000..d1feefb --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestSorter.cxx @@ -0,0 +1,51 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmSorter.h" +#include "gdcmTesting.h" + +int TestSorter(int argc, char *argv[]) +{ + // Black box: + gdcm::Directory::FilenamesType fns; + gdcm::Sorter s; + // No sort function and fns is empty + if( !s.Sort( fns ) ) + { + return 1; + } + + // White box: + const char *directory = gdcm::Testing::GetDataRoot(); + if( argc == 2 ) + { + directory = argv[1]; + } + gdcm::Directory d; + unsigned int nfiles = d.Load( directory ); // no recursion + d.Print( std::cout ); + std::cout << "done retrieving file list. " << nfiles << " files found." << std::endl; + +/* bool b = s.Sort( d.GetFilenames() ); + + if( !b ) + { + std::cerr << "Failed to sort:" << directory << std::endl; + return 1; + } + + std::cout << "Sorting succeeded:" << std::endl; + s.Print( std::cout ); +*/ + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestSpacing.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestSpacing.cxx new file mode 100644 index 0000000..ca4562e --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestSpacing.cxx @@ -0,0 +1,46 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmSpacing.h" + +int TestSpacing(int argc, char *argv[]) +{ + (void)argc; + (void)argv; + gdcm::Spacing s; + + // gdcmData/gdcm-MR-PHILIPS-16-NonSquarePixels.dcm + // (0028,0030) DS [ 0.487416\0.194966] # 18,2 Pixel Spacing + // 0.487416 / 0.194966 = 2.5000051290994327 + + // Simple case ratio 1:1 + gdcm::Attribute<0x28,0x30> pixelspacing = {{0.5, 0.5}}; + gdcm::Attribute<0x28,0x34> par = gdcm::Spacing::ComputePixelAspectRatioFromPixelSpacing(pixelspacing); + if( par[0] != 1 || par[1] != 1 ) + { + std::cerr << "par[0] = " << par[0] << " par[1]=" << par[1] << std::endl; + return 1; + } + + // More complex + pixelspacing[0] = 0.487416; + pixelspacing[1] = 0.194966; + par = gdcm::Spacing::ComputePixelAspectRatioFromPixelSpacing(pixelspacing); + if( par[0] != 5 || par[1] != 2 ) + { + std::cerr << "par[0] = " << par[0] << " par[1]=" << par[1] << std::endl; + return 1; + } + + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestSpectroscopy.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestSpectroscopy.cxx new file mode 100644 index 0000000..026fcab --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestSpectroscopy.cxx @@ -0,0 +1,23 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmSpectroscopy.h" + +int TestSpectroscopy(int argc, char *argv[]) +{ + (void)argc; + (void)argv; + gdcm::Spectroscopy w; + + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestSplitMosaicFilter.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestSplitMosaicFilter.cxx new file mode 100644 index 0000000..bb63114 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestSplitMosaicFilter.cxx @@ -0,0 +1,131 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmSplitMosaicFilter.h" +#include "gdcmTesting.h" +#include "gdcmSystem.h" +#include "gdcmImageReader.h" + +static bool reorganize_mosaic_invert(unsigned short *input, + const unsigned int *inputdims, unsigned int square, + const unsigned int *outputdims, const unsigned short *output ) +{ + for(unsigned x = 0; x < outputdims[0]; ++x) + { + for(unsigned y = 0; y < outputdims[1]; ++y) + { + for(unsigned z = 0; z < outputdims[2]; ++z) + { + size_t outputidx = x + y*outputdims[0] + z*outputdims[0]*outputdims[1]; + size_t inputidx = (x + (z%square)*outputdims[0]) + + (y + (z/square)*outputdims[0])*inputdims[0]; + input[ inputidx ] = output[ outputidx ]; + } + } + } + return true; +} + +int TestSplitMosaicFilter(int argc, char *argv[]) +{ + std::string filename; + if( argc == 2 ) + { + filename = argv[1]; + } + else + { + const char *extradataroot = gdcm::Testing::GetDataExtraRoot(); + if( !extradataroot ) + { + return 1; + } + if( !gdcm::System::FileIsDirectory(extradataroot) ) + { + std::cerr << "No such directory: " << extradataroot << std::endl; + return 1; + } + + filename = extradataroot; + filename += "/gdcmSampleData/images_of_interest/MR-sonata-3D-as-Tile.dcm"; + } + gdcm::SplitMosaicFilter s; + + // std::cout << filename << std::endl; + if( !gdcm::System::FileExists(filename.c_str()) ) + { + return 1; + } + + gdcm::ImageReader reader; + reader.SetFileName( filename.c_str() ); + if( !reader.Read() ) + { + std::cerr << "could not read: " << filename << std::endl; + return 1; + } + const gdcm::Image &image = reader.GetImage(); + unsigned int inputdims[3] = { 0, 0, 1 }; + const unsigned int *dims = image.GetDimensions(); + inputdims[0] = dims[0]; + inputdims[1] = dims[1]; + + gdcm::SplitMosaicFilter filter; + filter.SetImage( reader.GetImage() ); + filter.SetFile( reader.GetFile() ); + bool b = filter.Split(); + if( !b ) + { + std::cerr << "Could not split << " << filename << std::endl; + return 1; + } + +// const gdcm::Image &image = filter.GetImage(); + + unsigned long l = image.GetBufferLength(); + std::vector buf; + buf.resize(l); + if( !image.GetBuffer( &buf[0] ) ) + { + std::cerr << "Could not GetBuffer << " << filename << std::endl; + return 1; + } + + std::vector outbuf; + unsigned long ll = inputdims[0] * inputdims[1] * sizeof( unsigned short ); + outbuf.resize(ll); + + const unsigned int *mos_dims = image.GetDimensions(); + unsigned int div = (unsigned int )ceil(sqrt( (double)mos_dims[2]) ); + + reorganize_mosaic_invert((unsigned short *)&outbuf[0], inputdims, + div, mos_dims, (const unsigned short*)&buf[0] ); + +#if 0 + std::ofstream o( "/tmp/debug", std::ios::binary ); + o.write( &outbuf[0], ll ); + o.close(); +#endif + + char digest[33]; + gdcm::Testing::ComputeMD5(&outbuf[0], ll, digest); + + // $ gdcminfo --md5sum gdcmSampleData/images_of_interest/MR-sonata-3D-as-Tile.dcm + if( strcmp(digest, "be96c01db8a0ec0753bd43f6a985345c" ) != 0 ) + { + std::cerr << "Problem found: " << digest << std::endl; + return 1; + } + + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestStreamImageReader.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestStreamImageReader.cxx new file mode 100644 index 0000000..bf0652e --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestStreamImageReader.cxx @@ -0,0 +1,232 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmStreamImageReader.h" +#include "gdcmFileMetaInformation.h" +#include "gdcmSystem.h" +#include "gdcmFilename.h" +#include "gdcmByteSwap.h" +#include "gdcmTrace.h" +#include "gdcmTesting.h" +#include "gdcmImageHelper.h" +#include "gdcmImageReader.h" + +#include "gdcmImage.h" +#include "gdcmMediaStorage.h" + +#include "gdcmRAWCodec.h" +#include "gdcmJPEGLSCodec.h" + +int TestStreamImageRead(const char* filename, bool verbose = false, bool lossydump = false) +{ + (void)lossydump; + if( verbose ) + std::cerr << "Reading: " << filename << std::endl; + gdcm::StreamImageReader reader; + + reader.SetFileName( filename ); + bool canReadImageInformation = reader.ReadImageInformation(); + if (!canReadImageInformation) + { + return 0; //unable to read tags as expected. + } + else + { + int res = 0; + + //let's be tricky; each image will be read in portions, first the top half, then the bottom + //that way, we can test how the stream handles fragmentation of the data + //we could also loop this to get various different size combinations, but I'm not sure + //that's useful, yet. + std::vector extent = + gdcm::ImageHelper::GetDimensionsValue(reader.GetFile()); + + //at this point, these values aren't used, but may be in the future + //unsigned short xmin = 0; + //unsigned short xmax = extent[0]; + //unsigned short ymin = 0; + //unsigned short ymax = extent[1]; + //unsigned short zmin = 0; + //unsigned short zmax = extent[2]; + + reader.DefinePixelExtent(0, (uint16_t)extent[0], 0, (uint16_t)extent[1], 0, (uint16_t)extent[2]); + unsigned long len = reader.DefineProperBufferLength(); + char* finalBuffer = new char[len]; + memset(finalBuffer, 0, sizeof(char)*len); + if (reader.CanReadImage()){ + bool result = reader.Read(finalBuffer, len); + if( !result ){ + std::cerr << "res2 failure:" << filename << std::endl; + delete [] finalBuffer; + return 1; + } + } else { + delete [] finalBuffer; + return 0; //essentially, we're going to skip this file since it can't be read by the streamer + } +/* + //now, read in smaller buffer extents + reader.DefinePixelExtent(xmin, xmax, ymin, ymax); + len = reader.DefineProperBufferLength(); + + char* buffer = new char[len]; + bool res2 = reader.Read(buffer, len); + if( !res2 ){ + std::cerr << "res2 failure:" << filename << std::endl; + return 1; + } + //copy the result into finalBuffer + memcpy(finalBuffer, buffer, len); + + //now read the next half of the image + ymin = ymax; + ymax = extent[1]; + + reader.DefinePixelExtent(xmin, xmax, ymin, ymax); + + //std::cerr << "Success to read image from file: " << filename << std::endl; + unsigned long len2 = reader.DefineProperBufferLength(); + + char* buffer2 = new char[len2]; + bool res3 = reader.Read(buffer2, len2); + if( !res3 ){ + std::cerr << "res3 failure:" << filename << std::endl; + return 1; + } + //copy the result into finalBuffer + memcpy(&(finalBuffer[len]), buffer2, len2); + + delete [] buffer; + delete [] buffer2; +*/ + // On big Endian system we have byteswapped the buffer (duh!) + // Since the md5sum is byte based there is now way it would detect + // that the file is written in big endian word, so comparing against + // a md5sum computed on LittleEndian would fail. Thus we need to + // byteswap (again!) here: + const char *ref = gdcm::Testing::GetMD5FromFile(filename); + const char *correct_ref = gdcm::Testing::GetMD5FromBrokenFile(filename); + + char digest[33]; + gdcm::Testing::ComputeMD5(finalBuffer, len, digest); + if( verbose ) + { + std::cout << "ref=" << ref << std::endl; + std::cout << "md5=" << digest << std::endl; + } + if( !ref ) + { + // new regression image needs a md5 sum + std::cout << "Missing md5 " << digest << " for: " << filename << std::endl; + //assert(0); + res = 1; + } + else if( strcmp(digest, ref) ) + { + + // let's be nice for now and only truly fails when file is proper DICOM + if( correct_ref && !strcmp(correct_ref, ref) ) + { + std::cerr << "Problem reading image from: " << filename << std::endl; + std::cerr << "Found " << digest << " instead of " << ref << std::endl; + /* + //uncomment this code to explicitly read and check the md5 hash + gdcm::ImageReader reader; + + reader.SetFileName( filename ); + if (reader.Read()) + { + const gdcm::Image &img = reader.GetImage(); + //std::cerr << "Success to read image from file: " << filename << std::endl; + unsigned long len2 = img.GetBufferLength(); + + char* buffer2 = new char[len]; + bool res3 = img.GetBuffer(buffer2); + if (res3) + { + char digest2[33]; + gdcm::Testing::ComputeMD5(buffer2, len2, digest2); + if (strcmp(digest2, digest)) + { + std::cerr << "Second check read " << digest2 << " not " << digest << std::endl; + } + } + delete [] buffer2; + } + */ + res = 1; + } +#if 0 + std::ofstream debug("/tmp/dump.gray",std::ios::binary); + debug.write(finalBuffer, len); + debug.close(); +#endif + } + delete[] finalBuffer; + if (res == 0) + { + //uncomment this line to determine if a file was correctly read + //std::cerr << "Correctly read " << filename << std::endl; + } + return res; + } + +#if 0 + const gdcm::FileMetaInformation &header = reader.GetFile().GetHeader(); + gdcm::MediaStorage ms = header.GetMediaStorage(); + bool isImage = gdcm::MediaStorage::IsImage( ms ); + if( isImage ) + { + if( reader.GetFile().GetDataSet().FindDataElement( gdcm::Tag(0x7fe0,0x0010) ) ) + { + std::cerr << "Failed to read image from file: " << filename << std::endl; + return 1; + } + else + { + std::cerr << "no Pixel Data Element found in the file:" << filename << std::endl; + return 0; + } + } + // else + // well this is not an image, so thankfully we fail to read it + std::cerr << "Could not read image(" << filename << "), since file is a: " << ms << std::endl; + //assert( ms != gdcm::MediaStorage::MS_END ); + return 0; +#endif +} + + +int TestStreamImageReader(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestStreamImageRead(filename, true); + } + + // else + // First of get rid of warning/debug message + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestStreamImageRead( filename); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestStreamImageWriter.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestStreamImageWriter.cxx new file mode 100644 index 0000000..80d9547 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestStreamImageWriter.cxx @@ -0,0 +1,233 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmStreamImageReader.h" +#include "gdcmStreamImageWriter.h" +#include "gdcmFileMetaInformation.h" +#include "gdcmSystem.h" +#include "gdcmFilename.h" +#include "gdcmByteSwap.h" +#include "gdcmTrace.h" +#include "gdcmTesting.h" +#include "gdcmImageHelper.h" +#include "gdcmImageReader.h" +#include "gdcmImage.h" + +int TestStreamImageWrite(const char *subdir, const char* filename, bool verbose = false, bool lossydump = false) +{ + (void)lossydump; + if( verbose ) + std::cerr << "Reading and writing: " << filename << std::endl; + gdcm::ImageReader theImageReaderOriginal; + gdcm::ImageReader theImageReader; + gdcm::StreamImageWriter theStreamWriter; + + theImageReaderOriginal.SetFileName( filename ); + + // Create directory first: + std::string tmpdir = gdcm::Testing::GetTempDirectory( subdir ); + if( !gdcm::System::FileIsDirectory( tmpdir.c_str() ) ) + { + gdcm::System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + std::string outfilename = gdcm::Testing::GetTempFilename( filename, subdir ); + + + if ( theImageReaderOriginal.Read() ) + { + //int res = 0; + + //to test the writer out, we have to read an image and then + //write it out one line at a time. + //a _real_ test would include both the streamimagereader and writer. + //so, this test is: + //1) read in the image via the stream reader + //2) write it out line by line + //3) read it in by a reader + //4) compare the image from step 1 with step 3 + //5) go to step2, replace step 3 with a regular image reader. + //for now, we'll do 1-4 + + //pull image information prior to messing with the file + gdcm::Image theOriginalImage = theImageReaderOriginal.GetImage(); + char* theOriginalBuffer = new char[theOriginalImage.GetBufferLength()]; + if (!theOriginalImage.GetBuffer(theOriginalBuffer)){ + std::cerr << "Unable to get original image buffer, stopping." << std::endl; + delete [] theOriginalBuffer; + return 1; + } + + //first, check that the image information can be written + //theStreamReader.GetFile().GetDataSet().Print( std::cout ); + + theStreamWriter.SetFile(theImageReaderOriginal.GetFile()); +#if 0 + theStreamWriter.SetFileName(outfilename.c_str()); +#else + std::ofstream of; + of.open( outfilename.c_str(), std::ios::out | std::ios::binary ); + theStreamWriter.SetStream(of); +#endif + if (!theStreamWriter.CanWriteFile()){ + delete [] theOriginalBuffer; + return 0;//this means that the file was unwritable, period. + //very similar to a ReadImageInformation failure + } + if (!theStreamWriter.WriteImageInformation()){ + std::cerr << "unable to write image information" << std::endl; + delete [] theOriginalBuffer; + return 1; //the CanWrite function should prevent getting here, else, + //that's a test failure + } + std::vector extent = + gdcm::ImageHelper::GetDimensionsValue(theImageReaderOriginal.GetFile()); + + unsigned short xmax = (unsigned short)extent[0]; + unsigned short ymax = (unsigned short)extent[1]; + unsigned short theChunkSize = 4; + unsigned short ychunk = (unsigned short)(extent[1]/theChunkSize); //go in chunk sizes of theChunkSize + unsigned short zmax = (unsigned short)extent[2]; + + if (xmax == 0 || ymax == 0) + { + std::cerr << "Image has no size, unable to write zero-sized image." << std::endl; + return 0; + } + + int z, y, nexty; + unsigned long prevLen = 0; //when going through the char buffer, make sure to grab + //the bytes sequentially. So, store how far you got in the buffer with each iteration. + for (z = 0; z < zmax; ++z){ + for (y = 0; y < ymax; y += ychunk){ + nexty = y + ychunk; + if (nexty > ymax) nexty = ymax; + theStreamWriter.DefinePixelExtent(0, (uint16_t)xmax, (uint16_t)y, (uint16_t)nexty, (uint16_t)z, (uint16_t)(z+1)); + unsigned long len = theStreamWriter.DefineProperBufferLength(); + char* finalBuffer = new char[len]; + memcpy(finalBuffer, &(theOriginalBuffer[prevLen]), len); + + if (!theStreamWriter.Write(finalBuffer, len)){ + std::cerr << "writing failure:" << outfilename << " at y = " << y << " and z= " << z << std::endl; + delete [] theOriginalBuffer; + delete [] finalBuffer; + return 1; + } + delete [] finalBuffer; + prevLen += len; + } + } + delete [] theOriginalBuffer; + theImageReader.SetFileName(outfilename.c_str()); + if (!theImageReader.Read()){ + std::cerr << "unable to read in the written test file: " << outfilename << std::endl; + return 1; + } else { + int res = 0; + const gdcm::Image &img = theImageReader.GetImage(); + //std::cerr << "Success to read image from file: " << filename << std::endl; + unsigned long len = img.GetBufferLength(); + char* buffer = new char[len]; + img.GetBuffer(buffer); + // On big Endian system we have byteswapped the buffer (duh!) + // Since the md5sum is byte based there is now way it would detect + // that the file is written in big endian word, so comparing against + // a md5sum computed on LittleEndian would fail. Thus we need to + // byteswap (again!) here: + const char *ref = gdcm::Testing::GetMD5FromFile(filename); + const char *correct_ref = gdcm::Testing::GetMD5FromBrokenFile(filename); + + char digest[33]; + gdcm::Testing::ComputeMD5(buffer, len, digest); + if( verbose ) + { + std::cout << "ref=" << ref << std::endl; + std::cout << "md5=" << digest << std::endl; + } + if( !ref ) + { + // new regression image needs a md5 sum + std::cout << "Missing md5 " << digest << " for: " << filename << std::endl; + //assert(0); + res = 1; + } + else if( strcmp(digest, ref) ) + { + + // let's be nice for now and only truly fails when file is proper DICOM + if( correct_ref && !strcmp(correct_ref, ref)) + { + std::cerr << "Problem reading image from: " << filename << std::endl; + std::cerr << "Found " << digest << " instead of " << ref << std::endl; + res = 1; + } + } + delete[] buffer; + return res; + } + } + else + { + //std::cerr << "Unable to read test file: " << filename << std::endl; + //return 1; + return 0; //this is NOT a test of the reader, but a test of streaming writing + } + +#if 0 + const gdcm::FileMetaInformation &header = reader.GetFile().GetHeader(); + gdcm::MediaStorage ms = header.GetMediaStorage(); + bool isImage = gdcm::MediaStorage::IsImage( ms ); + if( isImage ) + { + if( reader.GetFile().GetDataSet().FindDataElement( gdcm::Tag(0x7fe0,0x0010) ) ) + { + std::cerr << "Failed to read image from file: " << filename << std::endl; + return 1; + } + else + { + std::cerr << "no Pixel Data Element found in the file:" << filename << std::endl; + return 0; + } + } + // else + // well this is not an image, so thankfully we fail to read it + std::cerr << "Could not read image(" << filename << "), since file is a: " << ms << std::endl; + //assert( ms != gdcm::MediaStorage::MS_END ); +#endif + return 0; +} + +int TestStreamImageWriter(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestStreamImageWrite(argv[0], filename, true); + } + + // else + // First of get rid of warning/debug message + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestStreamImageWrite( argv[0], filename); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestStringFilter.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestStringFilter.cxx new file mode 100644 index 0000000..918ac4f --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestStringFilter.cxx @@ -0,0 +1,85 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmStringFilter.h" +#include "gdcmReader.h" +#include "gdcmSequenceOfItems.h" +#include "gdcmTesting.h" +#include "gdcmTrace.h" + +int TestStringFilt(const char *filename) +{ + gdcm::StringFilter sf; + gdcm::Reader r; + r.SetFileName( filename ); + if( !r.Read() ) + { + return 1; + } + gdcm::DataSet const& ds = r.GetFile().GetDataSet(); + sf.SetFile( r.GetFile() ); + + int ret = 0; + gdcm::DataSet::ConstIterator it = ds.Begin(); + for( ; it != ds.End(); ++it) + { + const gdcm::DataElement &ref = *it; + std::pair s = sf.ToStringPair( ref.GetTag() ); + if( !s.second.empty() || ref.GetVL() == 0 ) + { + std::cout << s.first << " -> " << s.second << std::endl; + std::string s2 = sf.FromString( ref.GetTag(), s.second.c_str(), s.second.size() ); + //std::cout << s.first << " -> " << s2 << std::endl; + } + else if( !ref.GetByteValue() ) // It means it's a SQ + { + std::cout << "SQ:" << ref.GetTag() << std::endl; + } + else if( ref.GetTag().IsPrivate() ) + { + //std::cout << "Private:" << ref.GetTag() << std::endl; + std::string s2 = sf.FromString( ref.GetTag(), s.second.c_str(), s.second.size() ); + } + else + { + std::cerr << "Not supported: " << ref << std::endl; + //ret += 1; + } + } + + return ret; +} + +int TestStringFilter(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestStringFilt(filename); + } + + // else + // First of get rid of warning/debug message + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestStringFilt( filename ); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestSurfaceWriter.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestSurfaceWriter.cxx new file mode 100644 index 0000000..bb7a848 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestSurfaceWriter.cxx @@ -0,0 +1,123 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmTesting.h" +#include "gdcmSurfaceWriter.h" +#include "gdcmSurfaceReader.h" +#include "gdcmFileMetaInformation.h" +#include "gdcmFilename.h" +#include "gdcmSystem.h" +#include "gdcmAttribute.h" + +namespace gdcm +{ + +int TestSurfaceWriter(const char *subdir, const char* filename) +{ + SurfaceReader reader; + reader.SetFileName( filename ); + if ( !reader.Read() ) + { + int ret = 1; + gdcm::MediaStorage ms; + if( ms.SetFromFile( reader.GetFile() ) ) + { + if( ms == gdcm::MediaStorage::SurfaceSegmentationStorage ) + { + ret = 0; + } + } + if( !ret ) + { + std::cerr << "Failed to read: " << filename << std::endl; + std::cerr << "MediaStorage is: " << ms.GetString() << std::endl; + } + return !ret; + } + + // Get content of filename + const File & FReader = reader.GetFile(); + const FileMetaInformation & fmiReader = FReader.GetHeader(); + const DataSet & dsReader = FReader.GetDataSet(); + + // Create directory first: + std::string tmpdir = Testing::GetTempDirectory( subdir ); + if( !System::FileIsDirectory( tmpdir.c_str() ) ) + { + System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + std::string outfilename = Testing::GetTempFilename( filename, subdir ); + + // Write file from content reader + SurfaceWriter writer; + writer.SetFileName( outfilename.c_str() ); + SegmentReader::SegmentVector segments = reader.GetSegments(); + writer.SetSegments( segments ); + writer.SetNumberOfSurfaces( reader.GetNumberOfSurfaces() ); + + // Set content from filename + File & FWriter = writer.GetFile(); + FWriter.SetHeader(fmiReader); + FWriter.SetDataSet(dsReader); + + if( !writer.Write() ) + { + std::cerr << "Failed to write: " << outfilename << std::endl; + return 1; + } + + // reuse the filename, since outfilename is simply the new representation + // of the old filename + const char * ref = Testing::GetMD5FromFile(filename); + char digest[33] = {}; + Testing::ComputeFileMD5(outfilename.c_str(), digest); + if( ref == 0 ) + { + // new regression file needs a md5 sum + std::cout << "Missing md5 " << digest << " for: " << outfilename << std::endl; + return 1; + } + else if( strcmp(digest, ref) != 0 ) + { + std::cerr << "Found " << digest << " instead of " << ref << std::endl; + return 1; + } + + return 0; +} + +} + +int TestSurfaceWriter(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return gdcm::TestSurfaceWriter(argv[0],filename); + } + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += gdcm::TestSurfaceWriter(argv[0], filename ); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestSurfaceWriter2.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestSurfaceWriter2.cxx new file mode 100644 index 0000000..ac17e84 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestSurfaceWriter2.cxx @@ -0,0 +1,242 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmTesting.h" +#include "gdcmSurfaceWriter.h" +#include "gdcmSurfaceReader.h" +#include "gdcmFileMetaInformation.h" +#include "gdcmFilename.h" +#include "gdcmSystem.h" +#include "gdcmAttribute.h" + +#include + +namespace gdcm +{ + +/** + * Test surface reading and writing method. + */ +int TestSurfaceWriter2(const char *subdir, const char* filename) +{ + SurfaceReader reader; + reader.SetFileName( filename ); + if ( !reader.Read() ) + { + int ret = 1; + gdcm::MediaStorage ms; + if( ms.SetFromFile( reader.GetFile() ) ) + { + if( ms == gdcm::MediaStorage::SurfaceSegmentationStorage ) + { + ret = 0; + } + } + if( !ret ) + { + std::cerr << "Failed to read: " << filename << std::endl; + std::cerr << "MediaStorage is: " << ms.GetString() << std::endl; + } + return !ret; + } + // std::cout << "success to read" << std::endl; + + if (reader.GetNumberOfSurfaces() < 2) + { + std::cerr << "File with not enough surfaces (min : 2): " << filename << std::endl; + return 1; + } + + // Modify data to test other writing/reading way + SmartPointer< Segment > segment = new Segment; + srand( (unsigned int)time(NULL)); + SegmentHelper::BasicCodedEntry processingAlgo("123", "TEST", "Test123"); + { + SegmentReader::SegmentVector segments = reader.GetSegments(); + Segment::SurfaceVector tmp; + SegmentReader::SegmentVector::iterator itSegments = segments.begin(); + SegmentReader::SegmentVector::iterator itEndSegments = segments.end(); + for (; itSegments != itEndSegments; itSegments++) + { + tmp = (*itSegments)->GetSurfaces(); + Segment::SurfaceVector::iterator itSurfaces = tmp.begin(); + Segment::SurfaceVector::iterator itEndSurfaces = tmp.end(); + for (; itSurfaces != itEndSurfaces; itSurfaces++) + { + SmartPointer< Surface > surf = *itSurfaces; + surf->SetSurfaceProcessing( true ); + surf->SetSurfaceProcessingRatio( 0.42f ); + surf->SetSurfaceProcessingDescription( "Test processing" ); + surf->SetProcessingAlgorithm( processingAlgo ); + + if (surf->GetNumberOfVectors() > 0) + surf->SetNumberOfVectors( 42 ); + + surf->SetSurfaceNumber( rand()%1000 ); + + segment->AddSurface(surf); + } + } + + segment->SetSegmentDescription("Surface test"); + // segment.SetSurfaceCount( segment.GetSurfaces().size() ); + } + + // Create directory first: + std::string tmpdir = Testing::GetTempDirectory( subdir ); + if( !System::FileIsDirectory( tmpdir.c_str() ) ) + { + System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + std::string outfilename = Testing::GetTempFilename( filename, subdir ); + + // Write file from content reader + { + SurfaceWriter writer; + writer.SetFileName( outfilename.c_str() ); + writer.AddSegment( segment ); + // writer.SetNumberOfSurfaces( segment.GetSurfaces().size() ); + + // Set same header to write file + const FileMetaInformation & header = reader.GetFile().GetHeader(); + writer.GetFile().SetHeader( header ); + + if( !writer.Write() ) + { + std::cerr << "Failed to write: " << outfilename << std::endl; + return 1; + } + // std::cout << "success to write" << std::endl; + } + + SurfaceReader reader2; + reader2.SetFileName( outfilename.c_str() ); + if ( !reader2.Read() ) + { + std::cerr << "Failed to read again: " << outfilename << std::endl; + return 1; + } + // std::cout << "success to read again" << std::endl; + + SegmentReader::SegmentVector segments2 = reader2.GetSegments(); + if ( strcmp(segment->GetSegmentDescription(), segments2[0]->GetSegmentDescription()) != 0) + { + std::cerr << "Find different segment description"<< std::endl; + return 1; + } + + Segment::SurfaceVector surfaces2 = segments2[0]->GetSurfaces(); + if ( segment->GetSurfaces().size() != surfaces2.size() ) + { + std::cerr << "Find different surface count"<< std::endl; + return 1; + } + + Segment::SurfaceVector::iterator itSurfaces2 = surfaces2.begin(); + Segment::SurfaceVector::iterator itEndSurfaces2 = surfaces2.end(); + SegmentHelper::BasicCodedEntry processingAlgo2; + + Segment::SurfaceVector surfaces = segment->GetSurfaces(); + Segment::SurfaceVector::iterator itSurfaces = surfaces.begin(); + Segment::SurfaceVector::iterator itEndSurfaces = surfaces.end(); + for (; itSurfaces2 != itEndSurfaces2; itSurfaces2++) + { + SmartPointer< Surface > surf = *itSurfaces2; + + if (!surf->GetSurfaceProcessing()) + { + std::cerr << "Find different surface processing"<< std::endl; + return 1; + } + + if ( 0.41 > surf->GetSurfaceProcessingRatio() || surf->GetSurfaceProcessingRatio() > 0.43) + { + std::cerr << "Find different surface processing ratio"<< std::endl; + return 1; + } + + String<> str; + str = surf->GetSurfaceProcessingDescription(); + if (str.Trim() != "Test processing") + { + std::cerr << "Find different surface processing description"<< std::endl; + return 1; + } + + processingAlgo2 = surf->GetProcessingAlgorithm(); + str = processingAlgo2.CV; + processingAlgo2.CV = str.Trim(); + str = processingAlgo2.CSD; + processingAlgo2.CSD = str.Trim(); + str = processingAlgo2.CM; + processingAlgo2.CM = str.Trim(); + + if (processingAlgo2.CV != processingAlgo.CV + || processingAlgo2.CSD != processingAlgo.CSD + || processingAlgo2.CM != processingAlgo.CM ) + { + std::cerr << "Find different surface processing algorithm"<< std::endl; + return 1; + } + + if (itSurfaces != itEndSurfaces) + { + if (surf->GetSurfaceNumber() != (*itSurfaces)->GetSurfaceNumber()) + { + std::cerr << "Find different surface number"<< std::endl; + return 1; + } + + if (surf->GetNumberOfVectors() > 0) + { + std::cerr << "Find different number of vectors"<< std::endl; + return 1; + } + + itSurfaces++; + } + else + { + std::cerr << "Find different surface organization"<< std::endl; + return 1; + } + } + + return 0; +} + +} + +int TestSurfaceWriter2(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return gdcm::TestSurfaceWriter2(argv[0],filename); + } + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += gdcm::TestSurfaceWriter2(argv[0], filename ); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestTagPath.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestTagPath.cxx new file mode 100644 index 0000000..9ab36a5 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestTagPath.cxx @@ -0,0 +1,65 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmTagPath.h" +#include "gdcmTag.h" + +int TestTagPath(int argc, char *argv[]) +{ + (void)argc; + (void)argv; + gdcm::TagPath tp; + + const char path[] = "/0010,0010"; + if( !gdcm::TagPath::IsValid( path ) ) + { + return 1; + } + if( !tp.ConstructFromString( path ) ) + { + return 1; + } + + tp.Print( std::cout ); + + const char path2[] = "/0010,0011/*/1234,5678"; + if( !gdcm::TagPath::IsValid( path2 ) ) + { + return 1; + } + if( !tp.ConstructFromString( path2 ) ) + { + return 1; + } + + std::cout << "FromString:" << std::endl; + tp.Print( std::cout ); + + const unsigned int n = 10; + gdcm::Tag list[n]; + for(unsigned i = 0; i < n; ++i) + { + list[i].SetGroup( 0x1234 ); + list[i].SetElement( (uint16_t)i ); + } + + if( !tp.ConstructFromTagList( list, n ) ) + { + return 1; + } + std::cout << "TagList:" << std::endl; + tp.Print( std::cout ); + + + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestUIDGenerator.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestUIDGenerator.cxx new file mode 100644 index 0000000..e5a9217 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestUIDGenerator.cxx @@ -0,0 +1,175 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmUIDGenerator.h" + +#include +#include +#include + +#include + +int TestUIDGeneratorValid() +{ + gdcm::UIDGenerator uid; + uid.SetRoot( "1.2.3.4.0.0.1" ); + const char *s = uid.Generate(); + if( !gdcm::UIDGenerator::IsValid( s ) ) + { + return 1; + } + const char invalid0[] = ".0.123"; + if( gdcm::UIDGenerator::IsValid( invalid0 ) ) + { + return 1; + } + const char invalid1[] = "abcd"; + if( gdcm::UIDGenerator::IsValid( invalid1 ) ) + { + return 1; + } + const char invalid2[] = "1.2.3.4.0.0.123.a"; + if( gdcm::UIDGenerator::IsValid( invalid2 ) ) + { + return 1; + } + const char invalid3[] = "1.2.3.4.0.0.123.."; + if( gdcm::UIDGenerator::IsValid( invalid3 ) ) + { + return 1; + } + const char invalid4[] = "1.2.3.4.0.0..123"; + if( gdcm::UIDGenerator::IsValid( invalid4 ) ) + { + return 1; + } + const char invalid5[] = "1.2.3.4.00.123"; + if( gdcm::UIDGenerator::IsValid( invalid5 ) ) + { + return 1; + } + const char invalid6[] = "1.2.3.4.00.123."; + if( gdcm::UIDGenerator::IsValid( invalid6 ) ) + { + return 1; + } + const char invalid7[] = "1234567890.1234567890.1234567890.1234567890.1234567890.1234567890"; + if( gdcm::UIDGenerator::IsValid( invalid7 ) ) + { + return 1; + } + const char invalid8[] = "1234567890.1234567890.1234567890.1234567890.1234567890/123456789"; + if( gdcm::UIDGenerator::IsValid( invalid8 ) ) + { + return 1; + } + const char invalid9[] = ""; + if( gdcm::UIDGenerator::IsValid( invalid9 ) ) + { + return 1; + } + const char invalid10[] = "."; + if( gdcm::UIDGenerator::IsValid( invalid10 ) ) + { + return 1; + } + return 0; // no error +} + +int TestUIDGenerator(int , char *[]) +{ + gdcm::UIDGenerator uid; + std::cout << gdcm::UIDGenerator::GetGDCMUID() << std::endl; + std::cout << uid.GetRoot() << std::endl; + if( strcmp( gdcm::UIDGenerator::GetGDCMUID(), uid.GetRoot() ) != 0 ) + { + return 1; + } + /* + * Purposely take a very long root, to test the robustness of the generator + * since we are left with fewer bytes to still generate uniq UID + */ + // let's test 27 bytes root: + const char myroot[] = "9876543210.9876543210.98765"; // 26 bytes is the length of GDCM root + //if( strlen(myroot) != 26 ) + // { + // return 1; + // } + uid.SetRoot( myroot ); + std::cerr << "before generate" << std::endl; + const char *s = uid.Generate(); + std::cerr << "after generate" << std::endl; + std::cout << "s:" << s << std::endl; + if( strcmp( myroot, uid.GetRoot() ) != 0 ) + { + std::cerr << "1 failed" << std::endl; + return 1; + } + if( strcmp( gdcm::UIDGenerator::GetGDCMUID(), myroot ) == 0 ) + { + std::cerr << "2 failed" << std::endl; + return 1; + } + if( strncmp( s, uid.GetRoot(), strlen( uid.GetRoot() ) ) != 0 ) + { + std::cerr << "3 failed" << std::endl; + return 1; + } + +/* + std::string s0 = "123456"; + std::cout << (s0.c_str() + s0.find_first_not_of('0')) << std::endl; + std::string s1 = "0123456"; + std::cout << (s1.c_str() + s1.find_first_not_of('0')) << std::endl; + std::string s2 = "00123456"; + std::cout << (s2.c_str() + s2.find_first_not_of('0')) << std::endl; + std::string s3 = "000"; + if( s3.find_first_not_of('0') != std::string::npos ) + std::cout << (s3.c_str() + s3.find_first_not_of('0')) << std::endl; +*/ + + // Threading issue, make sure that two different UIDs cannot generate same UID + gdcm::UIDGenerator uid1; + gdcm::UIDGenerator uid2; + const unsigned int n = 100; + std::set uids; + for(unsigned int i = 0; i < n; ++i) + { + const char *unique1 = uid1.Generate(); + const char *unique2 = uid2.Generate(); + if( !unique1 || !unique2 ) return 1; + std::cout << unique1 << std::endl; + std::cout << unique2 << std::endl; + if ( uids.count(unique1) == 1 ) + { + std::cerr << "Already found: " << unique1 << std::endl; + return 1; + } + uids.insert( unique1 ); + if ( uids.count(unique2) == 1 ) + { + std::cerr << "Already found: " << unique2 << std::endl; + return 1; + } + uids.insert( unique2 ); + if( strcmp(unique1 , unique2 ) == 0 ) + { + // That would be very bad ! + return 1; + } + } + int ret = 0; + ret += TestUIDGeneratorValid(); + + return ret; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestUIDGenerator2.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestUIDGenerator2.cxx new file mode 100644 index 0000000..4d55f86 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestUIDGenerator2.cxx @@ -0,0 +1,83 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmUIDGenerator.h" + +#include +#include +#include +#include +#include + +#include + +const unsigned int nuids = 100; + +void* func (void* argc) +{ + gdcm::UIDGenerator g; + std::set *uids= reinterpret_cast< std::set* >(argc); + for(unsigned int i = 0; i < nuids; i++) + { + const char *s = g.Generate(); + //std::cout << s << std::endl; + if ( uids->count(s) == 1 ) + { + std::cerr << "Already found: " << s << std::endl; + //pthread_exit(); // How do I say this is an error... + } + uids->insert( s ); + } + return NULL; +} + +int TestUIDGenerator2(int , char *[]) +{ + const unsigned int nthreads = 10; // multiple of 2 please + pthread_t th[nthreads]; + std::set uids[nthreads]; + unsigned int i; + for (i = 0; i < nthreads; i++) + { + const int ret = pthread_create (&th[i], NULL, func, (void*)(uids+i)); + if( ret ) return 1; + } + for (i = 0; i < nthreads; i++) + pthread_join (th[i], NULL); + + std::vector v_one(nuids*nthreads); + std::vector::iterator it = v_one.begin(); + for(i = 0; i < nthreads; i+=2) + { + std::set_union(uids[i].begin(), uids[i].end(), + uids[i+1].begin(), uids[i+1].end(), it); + it += nuids*2; + } + std::cout << v_one.size() << std::endl; + assert( v_one.size() == nuids * nthreads ); // programmer error + + std::copy(v_one.begin(), v_one.end(), std::ostream_iterator(std::cout, "\n")); + + std::set global; + for(it = v_one.begin(); it != v_one.end(); ++it) + { + global.insert( *it ); + } + std::cout << "set:" << global.size() << std::endl; + if( global.size() != nuids * nthreads ) + { + return 1; + } + + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestUIDGenerator3.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestUIDGenerator3.cxx new file mode 100644 index 0000000..496008f --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestUIDGenerator3.cxx @@ -0,0 +1,69 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmUIDGenerator.h" +#include "gdcmSystem.h" + +#include +#include + +int TestUIDGenerator3(int argc, char *argv[]) +{ + char randbytesbuf[200]; + gdcm::UIDGenerator uid; + unsigned char data[16]; + for(unsigned int i = 0; i < 100; ++i) + { + uid.GenerateUUID( data ); + + size_t len = gdcm::System::EncodeBytes(randbytesbuf, data, sizeof(data)); + //std::cout << randbytesbuf << std::endl; + + std::bitset<8> x; + //x.reset(); + //std::cout << x << std::endl; + //x.flip(); + //std::cout << x << std::endl; + //std::cout << sizeof(x) << std::endl; + //std::cout << sizeof(data) << std::endl; + x = data[0]; + //std::cout << x << std::endl; + //std::cout << (int)data[0] << std::endl; + //x = data[5]; + //std::cout << x << std::endl; + x[2+0] = 0; + x[2+1] = 0; + x[2+2] = 0; + x[2+3] = 0; + x[2+4] = 0; + x[2+5] = 0; + data[0] = x.to_ulong(); + //std::cout << x << std::endl; + //std::cout << (int)data[0] << std::endl; + + len = gdcm::System::EncodeBytes(randbytesbuf, data, sizeof(data)); + std::cout << randbytesbuf << std::endl; + if( len > 37 ) + { + return 1; + } + // Can't use the following, this would declare x2 as a function + //std::bitset<128> x2( std::string(randbytesbuf) ); + // instead split it out : + //std::string s(randbytesbuf); + //std::bitset<128> x2( s ); + //std::cout << x2 << std::endl; + + } + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestUUIDGenerator.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestUUIDGenerator.cxx new file mode 100644 index 0000000..9fd10e7 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestUUIDGenerator.cxx @@ -0,0 +1,46 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmUUIDGenerator.h" + +#include + +int TestUUIDGenerator(int , char *[]) +{ + gdcm::UUIDGenerator uid; + + const char *suid = uid.Generate(); + if( !gdcm::UUIDGenerator::IsValid( suid ) ) + { + std::cerr << "Invalid: " << suid << std::endl; + return 1; + } + + const char *valids[] = { + "00000000-0000-0000-0000-000000000000", + "ba209999-0c6c-11d2-97cf-00c04f8eea45", + "67C8770B-44F1-410A-AB9A-F9B5446F13EE" + }; + const size_t nv = sizeof( valids ) / sizeof( *valids ); + for( size_t i = 0; i < nv; ++i ) + { + const char *valid = valids[i]; + if( !gdcm::UUIDGenerator::IsValid( valid ) ) + { + std::cerr << "Invalid: " << valid << std::endl; + return 1; + } + } + + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestValidate.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestValidate.cxx new file mode 100644 index 0000000..340f5ef --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestValidate.cxx @@ -0,0 +1,21 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmValidate.h" + +int TestValidate(int, char *[]) +{ + gdcm::Validate v; + v.Validation(); + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestWaveform.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestWaveform.cxx new file mode 100644 index 0000000..813b100 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestWaveform.cxx @@ -0,0 +1,23 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmWaveform.h" + +int TestWaveform(int argc, char *argv[]) +{ + (void)argc; + (void)argv; + gdcm::Waveform w; + + return 0; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestWriter2.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestWriter2.cxx new file mode 100644 index 0000000..f552ff1 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestWriter2.cxx @@ -0,0 +1,36 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +int TestWriter2(int argc, char *argv[]) +{ + const char *filename = argv[1]; + const char *outfilename = argv[2]; + + Reader reader; + reader.SetFileName( filename ); + if ( !reader.Read() ) + { + std::cerr << "Failed to read: " << filename << std::endl; + return 1; + } + + + Writer writer; + writer.SetFileName( outfilename ); + writer.SetFile( reader.GetFile() ); + if( !writer.Write() ) + { + std::cerr << "Failed to write: " << outfilename << std::endl; + return 1; + } +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestXMLPrinter.cxx b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestXMLPrinter.cxx new file mode 100644 index 0000000..870e61b --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Cxx/TestXMLPrinter.cxx @@ -0,0 +1,72 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmReader.h" +#include "gdcmXMLPrinter.h" +#include "gdcmFilename.h" +#include "gdcmTesting.h" + +int TestXMLPrint(const char *filename, bool verbose= false) +{ + gdcm::Reader r; + r.SetFileName( filename ); + if( !r.Read() ) + { + std::cerr << "Could not read: " << filename << std::endl; + return 1; + } + + gdcm::XMLPrinter print; + //print.SetStyle( gdcm::XMLPrinter::LOADBULKDATA ); + print.SetFile( r.GetFile() ); + std::ostringstream out; + if( verbose ) + print.Print( std::cout ); + print.Print( out ); + + gdcm::Filename fn( filename ); + const char *name = fn.GetName(); + + std::string buf = out.str(); + if( buf.find( "GDCM:UNKNOWN" ) != std::string::npos ) + { + std::cerr << "UNKNOWN Attribute with : " << name << std::endl; + return 1; + } + return 0; +} + + +int TestXMLPrinter(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestXMLPrint(filename, true); + } + + // else + int r = 0, i = 0; + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + gdcm::Trace::ErrorOff(); + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestXMLPrint( filename ); + ++i; + } + + return r; +} diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Python/CMakeLists.txt b/gdcm/Testing/Source/MediaStorageAndFileFormat/Python/CMakeLists.txt new file mode 100644 index 0000000..ecd0336 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Python/CMakeLists.txt @@ -0,0 +1,39 @@ +# Define the tests for gdcm-python +# gdcm-python +set(GDCM_PYTHON_TEST_SRCS + TestScanner + TestImageReader + TestUIDGenerator + TestModifyFields + TestAnonymizer + #TestStringFilter + TestOrientation + TestIPPSorter + #TestPythonFilter + ) +if(BUILD_APPLICATIONS) + if(DCMTK_DCMDUMP_EXECUTABLE) + if(UNIX) + set(GDCM_PYTHON_TEST_SRCS + ${GDCM_PYTHON_TEST_SRCS} + TestDCMTKMD5 # need dcmdrle and dcmdjpeg + ) + endif() + endif() +endif() + +# Loop over files and create executables +foreach(name ${GDCM_PYTHON_TEST_SRCS}) + ADD_PYTHON_TEST(${name}Python ${name}.py) +endforeach() + +# Special test that need extra arg: +# TestKakaduDecompressionMD5 +find_package(KAKADU) +if(BUILD_APPLICATIONS) + if(KDU_EXPAND_EXECUTABLE) + if(UNIX) + ADD_PYTHON_TEST(TestKakaduDecompressionMD5Python TestKakaduDecompressionMD5.py ${KDU_EXPAND_EXECUTABLE}) + endif() + endif() +endif() diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Python/TestAnonymizer.py b/gdcm/Testing/Source/MediaStorageAndFileFormat/Python/TestAnonymizer.py new file mode 100644 index 0000000..5e8344e --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Python/TestAnonymizer.py @@ -0,0 +1,81 @@ +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +import gdcm +import os,sys + +def TestAnonymizer(filename, verbose = False): + r = gdcm.Reader() + r.SetFileName( filename ) + sucess = r.Read() + if( not sucess ): return 1 + #print r.GetFile().GetDataSet() + + ano = gdcm.Anonymizer() + ano.SetFile( r.GetFile() ) + # 1. Replace with another value + ano.Replace( gdcm.Tag(0x0010,0x0010), "Test^Anonymize" ) + # 2. Remove a tag (even a SQ) + ano.Remove( gdcm.Tag(0x0008,0x2112) ) + # 3. Make a tag empty + ano.Empty( gdcm.Tag(0x0008,0x0070) ) + # Call the main function: + sucess = ano.RemovePrivateTags() # do it ! + if( not sucess ): return 1 + + # Check we can also change value from binary field + #ano.Replace( gdcm.Tag(0x0010,0x0010), "16", gdcm. ) + + # Let's check if our anonymization worked: + if verbose: + print(ano.GetFile().GetDataSet()) + + # So at that point r.GetFile() was modified, let's simply passed it to the Writer: + # First find a place where to write it out: + subdir = "TestAnonymizerPython" + tmpdir = gdcm.Testing.GetTempDirectory( subdir ) + if not gdcm.System.FileIsDirectory( tmpdir ): + gdcm.System.MakeDirectory( tmpdir ) + # Ok directory does exist now, extract the name of the input file, and merge it in + # our newly created tmpdir: + outfilename = gdcm.Testing.GetTempFilename( filename, subdir ) + + w = gdcm.Writer() + w.SetFileName( outfilename ) + w.SetFile( r.GetFile() ) + w.SetCheckFileMetaInformation( False ) + sucess = w.Write() + if( not sucess ): return 1 + + if verbose: + print("Success to write: %s"%outfilename) + + return sucess + +if __name__ == "__main__": + sucess = 0 + try: + filename = os.sys.argv[1] + sucess += TestAnonymizer( filename, True ) + except: + # loop over all files: + t = gdcm.Testing() + nfiles = t.GetNumberOfFileNames() + for i in range(0,nfiles): + filename = t.GetFileName(i) + sucess += TestAnonymizer( filename ) + + + # Test succeed ? + sys.exit(sucess == 0) diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Python/TestDCMTKMD5.py b/gdcm/Testing/Source/MediaStorageAndFileFormat/Python/TestDCMTKMD5.py new file mode 100644 index 0000000..b72d791 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Python/TestDCMTKMD5.py @@ -0,0 +1,190 @@ +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +import gdcm +import os,sys,re + +""" +You need to have dcmdump/dcmdrle/dcmdjpeg in your PATH +""" + +def TestDCMTKMD5( filename, verbose = False ): + blacklist = [ + # Get rid of DICOMDIR if any: + 'DICOMDIR', + 'DICOMDIR_MR_B_VA12A', + 'DICOMDIR-Philips-EasyVision-4200-Entries', + 'dicomdir_Acusson_WithPrivate_WithSR', + 'dicomdir_Pms_With_heavy_embedded_sequence', + 'dicomdir_Pms_WithVisit_WithPrivate_WithStudyComponents', + 'dicomdir_With_embedded_icons', + # Unsupported file: + 'MR_Spectroscopy_SIEMENS_OF.dcm', + 'gdcm-CR-DCMTK-16-NonSamplePerPix.dcm', # this is not an image + 'ELSCINT1_PMSCT_RLE1.dcm', + 'SignedShortLosslessBug.dcm', + 'JPEGDefinedLengthSequenceOfFragments.dcm', # dcmtk 3.6.0 gives garbage + 'GE_DLX-8-MONO2-PrivateSyntax.dcm', + 'PrivateGEImplicitVRBigEndianTransferSyntax16Bits.dcm', + #'DermaColorLossLess.dcm', # technically I could support this one... + #'LEADTOOLS_FLOWERS-24-RGB-JpegLossy.dcm', # idem + 'ALOKA_SSD-8-MONO2-RLE-SQ.dcm'] # this one is not supported by dcmtk 3.5.4 + for f in blacklist: + if f in filename: + print("%s is on the black list, giving up"%filename) + return 0 + #print filename + # + #dcmdump_exec = "dcmdump -dc -E +P 2,10 -s " + filename + " 2> /dev/null" + # I had to remove the -dc for the following file: + # GE_GENESIS-16-MONO2-Uncompressed-UnusualVR.dcm there is trailing space instead of \0 + dcmdump_exec = "dcmdump -E +P 2,10 -s " + filename + " 2> /dev/null" + #print dcmdump_exec + f = os.popen(dcmdump_exec) + ret = f.read() + #assert ret == 0 + #print ret + jpegre = re.compile('^.*JPEGLossless.*$') + jpegre2 = re.compile('^.*JPEGExtended.*$') + jpegre3 = re.compile('^.*JPEGBaseline.*$') + j2kre = re.compile('^.*JPEG2000.*$') + jplsre = re.compile('^.*JPEGLS.*$') + rlere = re.compile('^.*RLELossless.*$') + lexre = re.compile('^.*LittleEndianExplicit.*$') + leire = re.compile('^.*LittleEndianImplicit.*$') + beire = re.compile('^.*BigEndianExplicit.*$') + testing = gdcm.Testing() + outputdir = testing.GetTempDirectory( "TestDCMTKMD5" ) + gdcm.System.MakeDirectory( outputdir ) + outputfilename = testing.GetTempFilename( filename, "TestDCMTKMD5" ) + executable_output_path = gdcm.GDCM_EXECUTABLE_OUTPUT_PATH + gdcmraw = executable_output_path + '/gdcmraw -P' + + if not ret: + #print "empty, problem with:", filename + return 0 + elif type(ret) != type(''): + print("problem of type with:", filename) + return 0 + #print ret + #print ret.__class__ + elif( jpegre.match( ret ) or jpegre2.match(ret) or jpegre3.match(ret) ): + #print "jpeg: ",filename + # +cn : conv-never + # +px : color by pixel + dcmdjpeg_exec = "dcmdjpeg +cn +px " + filename + " " + outputfilename + ret = os.system( dcmdjpeg_exec ) + if ret: + print("dcmdjpeg failed to decompress file. giving up") + return 0 + + gdcmraw_args = ' -i ' + outputfilename + ' -o ' + outputfilename + ".raw" + gdcmraw += gdcmraw_args + #print gdcmraw + ret = os.system( gdcmraw ) + md5 = gdcm.Testing.ComputeFileMD5( outputfilename + ".raw" ) + ref = gdcm.Testing.GetMD5FromFile(filename) + #print md5 + retval = 0 + if ref != md5: + print("md5 are different: %s should be: %s for file %s"%(md5,ref,filename)) + retval = 1 + #print outputfilename + return retval + elif( jplsre.match( ret ) ): + #print "jpegls: ",filename + dcmdjpls_exec = "dcmdjpls " + filename + " " + outputfilename + ret = os.system( dcmdjpls_exec ) + if ret: + print("failed with: ", dcmdjpls_exec) + return 1 + + gdcmraw_args = ' -i ' + outputfilename + ' -o ' + outputfilename + ".raw" + gdcmraw += gdcmraw_args + #print gdcmraw + ret = os.system( gdcmraw ) + md5 = gdcm.Testing.ComputeFileMD5( outputfilename + ".raw" ) + ref = gdcm.Testing.GetMD5FromFile(filename) + #print md5 + retval = 0 + if ref != md5: + print("md5 are different: %s should be: %s for file %s"%(md5,ref,filename)) + retval = 1 + #print outputfilename + return retval + elif( rlere.match( ret ) ): + #print "rle: ",filename + dcmdrle_exec = "dcmdrle " + filename + " " + outputfilename + ret = os.system( dcmdrle_exec ) + if ret: + print("failed with: ", dcmdrle_exec) + return 1 + + gdcmraw_args = ' -i ' + outputfilename + ' -o ' + outputfilename + ".raw" + gdcmraw += gdcmraw_args + #print gdcmraw + ret = os.system( gdcmraw ) + md5 = gdcm.Testing.ComputeFileMD5( outputfilename + ".raw" ) + ref = gdcm.Testing.GetMD5FromFile(filename) + #print md5 + retval = 0 + if ref != md5: + print("md5 are different: %s should be: %s for file %s"%(md5,ref,filename)) + retval = 1 + #print outputfilename + return retval + elif( j2kre.match( ret ) ): + return 0 + elif( lexre.match( ret ) or leire.match(ret) or beire.match(ret) ): + #print "rle: ",filename + #dcmdrle_exec = "dcmdrle " + filename + " " + outputfilename + #ret = os.system( dcmdrle_exec ) + + gdcmraw_args = ' -i ' + filename + ' -o ' + outputfilename + ".raw" + gdcmraw += gdcmraw_args + #print gdcmraw + ret = os.system( gdcmraw ) + if ret: + print("failed with: ", gdcmraw) + return 1 + md5 = gdcm.Testing.ComputeFileMD5( outputfilename + ".raw" ) + ref = gdcm.Testing.GetMD5FromFile(filename) + #print md5 + retval = 0 + if ref != md5: + print("md5 are different: %s should be: %s for file %s"%(md5,ref,filename)) + retval = 1 + #print outputfilename + return retval + #else + print("Unhandled:",filename,"with ret=",ret) + return 1 + +if __name__ == "__main__": + sucess = 0 + try: + filename = os.sys.argv[1] + sucess += TestDCMTKMD5( filename, True ) + except: + # loop over all files: + t = gdcm.Testing() + gdcm.Trace.WarningOff() + gdcm.Trace.DebugOff() + nfiles = t.GetNumberOfFileNames() + for i in range(0,nfiles): + filename = t.GetFileName(i) + sucess += TestDCMTKMD5( filename ) + + # Test succeed ? + sys.exit(sucess) diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Python/TestIPPSorter.py b/gdcm/Testing/Source/MediaStorageAndFileFormat/Python/TestIPPSorter.py new file mode 100644 index 0000000..6283041 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Python/TestIPPSorter.py @@ -0,0 +1,25 @@ +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +import gdcm +import os,sys + +if __name__ == "__main__": + sucess = 0 + s = gdcm.IPPSorter() + # black box test: + if not s.Sort([]): + sys.exit(1) + + sys.exit(0) diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Python/TestImageReader.py b/gdcm/Testing/Source/MediaStorageAndFileFormat/Python/TestImageReader.py new file mode 100644 index 0000000..aeba8af --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Python/TestImageReader.py @@ -0,0 +1,42 @@ +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +import gdcm +import os,sys + +def TestImageRead(filename, verbose = False): + r = gdcm.ImageReader() + r.SetFileName( filename ) + success = r.Read() + if verbose: print(r.GetImage()) + return success + +if __name__ == "__main__": + sucess = 0 + try: + filename = os.sys.argv[1] + sucess += TestImageRead( filename, True ) + except: + # loop over all files: + gdcm.Trace.DebugOff() + gdcm.Trace.WarningOff() + t = gdcm.Testing() + nfiles = t.GetNumberOfFileNames() + for i in range(0,nfiles): + #print t.GetFileName(i) + filename = t.GetFileName(i) + sucess += TestImageRead( filename ) + + # Test succeed ? + sys.exit(sucess == 0) diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Python/TestKakaduDecompressionMD5.py b/gdcm/Testing/Source/MediaStorageAndFileFormat/Python/TestKakaduDecompressionMD5.py new file mode 100644 index 0000000..cf45e42 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Python/TestKakaduDecompressionMD5.py @@ -0,0 +1,95 @@ +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +import gdcm +import os,sys + +def TestKakadu(filename, kdu_expand): + fn = gdcm.Filename(filename) + testdir = fn.GetPath() + testbasename = fn.GetName() + ext = fn.GetExtension() + #print ext + #kakadu_path = '/home/mmalaterre/Software/Kakadu60' + kakadu_path = os.path.dirname( kdu_expand ) + #kdu_expand = kakadu_path + '/kdu_expand' + kdu_args = ' -quiet -i ' + output_dcm = testdir + '/kakadu/' + testbasename + output_j2k = output_dcm + '.j2k' + output_ppm = output_dcm + '.ppm' # + output_raw = output_dcm + '.rawl' # FIXME: little endian only... + kdu_expand += kdu_args + output_j2k + ' -o ' + output_raw + # $ ./bin/gdcmraw -i .../TestImageChangeTransferSyntax2/012345.002.050.dcm -o toto.j2k + executable_output_path = gdcm.GDCM_EXECUTABLE_OUTPUT_PATH + gdcmraw = executable_output_path + '/gdcmraw' + outputfilename = output_j2k + gdcmraw_args = ' -i ' + filename + ' -o ' + outputfilename + gdcmraw += gdcmraw_args + #print gdcmraw + ret = os.system( gdcmraw ) + #print "ret:",ret + #print kdu_expand + os.environ["LD_LIBRARY_PATH"]=kakadu_path + ret = os.system( kdu_expand ) + # now need to skip the ppm header: + dd_cmd = 'dd bs=15 skip=1 if=%s of = %s'%(output_ppm,output_raw) + #print "ret:",ret + md5 = gdcm.Testing.ComputeFileMD5( output_raw ) + # ok this is the md5 as computed after decompression using kdu_expand + # let see if it match out previously (stored) md5: + ref = gdcm.Testing.GetMD5FromFile(filename) + #print ref + retval = 0 + if ref != md5: + img = gdcm.ImageReader() + img.SetFileName( filename ) + img.Read() + if img.GetImage().GetDimension(2) != 1: + print("Test do not handle multiframes for now") + elif img.GetImage().GetPixelFormat().GetSamplesPerPixel() != 1: + print("Test do not handle RGB for now. kdu_expand expand as RRR GGG BBB by default") + else: + print("md5 are different: %s should be: %s for file %s"%(md5,ref,filename)) + print("raw file was: %s"%(output_raw)) + retval = 1 + + return retval + +if __name__ == "__main__": + sucess = 0 + #try: + # filename = os.sys.argv[1] + # sucess += TestKakadu( filename ) + #except: + # loop over all files: + #t = gdcm.Testing() + #nfiles = t.GetNumberOfFileNames() + #for i in range(0,nfiles): + # filename = t.GetFileName(i) + # sucess += TestKakadu( filename ) + d = gdcm.Directory() + tempdir = gdcm.Testing.GetTempDirectory() + j2ksubdir = 'TestImageChangeTransferSyntax2' # FIXME hardcoded ! + nfiles = d.Load( tempdir + '/' + j2ksubdir ) + # make sure the output dir for temporary j2k files exists: + md = gdcm.System.MakeDirectory( tempdir + '/' + j2ksubdir + '/kakadu' ); + if not md: + sys.exit(1) + files = d.GetFilenames() + for i in range(0,nfiles): + filename = files[i] + sucess += TestKakadu( filename, os.sys.argv[1] ) + + # Test succeed ? + sys.exit(sucess) diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Python/TestModifyFields.py b/gdcm/Testing/Source/MediaStorageAndFileFormat/Python/TestModifyFields.py new file mode 100644 index 0000000..069578e --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Python/TestModifyFields.py @@ -0,0 +1,84 @@ +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +import gdcm +import os,sys + +def TestModifyFields(filename): + outfilename = filename + ".rewrite" + r = gdcm.Reader() + r.SetFileName( filename ) + sucess = r.Read() + #print r.GetFile().GetDataSet() + + ds = r.GetFile().GetDataSet() + #print dir(ds) + # eg, let's remove a tag + removetag = gdcm.Tag(0x0043,0x106f) + if ds.FindDataElement( removetag ): + ds.Remove( removetag ) + + # let's replace a value: + replacetag = gdcm.Tag(0x0010,0x0010) + if ds.FindDataElement( replacetag ): + de = ds.GetDataElement( replacetag ) + #print dir(de) + patname = "This^is^an^example" + vl = gdcm.VL( len(patname) ) + de.SetByteValue( patname, vl ) + + # let's insert a new dataelement + # + pir = gdcm.DataElement( gdcm.Tag(0x0012,0x0062) ) + pir.SetVR( gdcm.VR( gdcm.VR.CS ) ) # specify the VR explicitely + yes = "YES" + pir.SetByteValue( yes, gdcm.VL(len(yes)) ) + ds.Insert( pir ) + + # try again but pretend we don't know the VR + # + deidmethod = gdcm.Tag(0x0012,0x0063) + # retrieve the supreme global instance, sum of all knowledge in da whole universe: + dicomdicts = gdcm.GlobalInstance.GetDicts() + dictel = dicomdicts.GetDictEntry( deidmethod ) + #print dictel.GetVR() + deid = gdcm.DataElement( deidmethod ) + deid.SetVR( dictel.GetVR() ) + methodstr = "Well known Company" + #deid.SetByteValue( methodstr, gdcm.VL(len(methodstr)) ) + deid.SetByteValue( methodstr, gdcm.VL(len(methodstr)) ) + ds.Insert( deid ) + + #w = gdcm.Writer() + #w.SetFileName( outfilename ) + #w.SetFile( r.GetFile() ) + #sucess = w.Write() + return sucess + +if __name__ == "__main__": + sucess = 0 + try: + filename = os.sys.argv[1] + sucess += TestModifyFields( filename, True ) + except: + # loop over all files: + t = gdcm.Testing() + nfiles = t.GetNumberOfFileNames() + for i in range(0,nfiles): + filename = t.GetFileName(i) + sucess += TestModifyFields( filename ) + + + # Test succeed ? + sys.exit(sucess == 0) diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Python/TestOrientation.py b/gdcm/Testing/Source/MediaStorageAndFileFormat/Python/TestOrientation.py new file mode 100644 index 0000000..8f3dcc7 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Python/TestOrientation.py @@ -0,0 +1,56 @@ +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +import gdcm +import os,sys + +if __name__ == "__main__": + sucess = True + + ori1 = (1,0,0,0,1,0) + ori2 = (1,0,0,0,0,1) + ori3 = (0,1,0,0,0,1) + + label1 = gdcm.Orientation.GetLabel( gdcm.Orientation.GetType( ori1 ) ) + if label1 != 'AXIAL': + print("Found:",label1) + sucess = False + label2 = gdcm.Orientation.GetLabel( gdcm.Orientation.GetType( ori2 ) ) + if label2 != 'CORONAL': + print("Found:",label2) + sucess = False + label3 = gdcm.Orientation.GetLabel( gdcm.Orientation.GetType( ori3 ) ) + if label3 != 'SAGITTAL': + print("Found:",label3) + sucess = False + + image = gdcm.Image() + image.SetNumberOfDimensions(2) + print(image) + print(image.GetDimensions()) + print(image.GetOrigin()) + print(image.GetSpacing()) + print(image.GetDirectionCosines()) + + image.SetNumberOfDimensions(3) + image.SetDimensions( (512,256,128) ) + print(image.GetDimensions()) + + #dircos = gdcm.DirectionCosines( (1,0,0,0,0,-1) ) + dircos = gdcm.DirectionCosines() + print(dircos) + #print dircos.Cross() + + # Test succeed ? + sys.exit(sucess == False) diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Python/TestPythonFilter.py b/gdcm/Testing/Source/MediaStorageAndFileFormat/Python/TestPythonFilter.py new file mode 100644 index 0000000..eaac6fb --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Python/TestPythonFilter.py @@ -0,0 +1,64 @@ +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +import gdcm +import os,sys + +def TestPythonFilter(filename, verbose = False): + r = gdcm.Reader() + r.SetFileName( filename ) + sucess = r.Read() + if( not sucess ): return 1 + + file = r.GetFile() + ds = file.GetDataSet() + # Change gdcm struct into something swig can digest: + pds = gdcm.PythonDataSet(ds) + sf = gdcm.PythonFilter() + pds.Start() # Make iterator go at begining + dic1={} + dic2={} + sf.SetFile(file) # extremely important + while(not pds.IsAtEnd() ): + t = str(pds.GetCurrent().GetTag()) + print(t) + res = sf.ToPyObject( pds.GetCurrent().GetTag() ) + dic2[t] = res[1] + dic1[res[0]] = res[1] + pds.Next() + #print dic1 + #print dic2 + try: + print("Pixel Representation=",dic2[ '(0028,0103)' ]) + except KeyError: + print("Tag not found in dataset") + return 0 + +if __name__ == "__main__": + sucess = 0 + try: + filename = os.sys.argv[1] + sucess += TestPythonFilter( filename, True ) + except: + # loop over all files: + gdcm.Trace.WarningOff() + t = gdcm.Testing() + nfiles = t.GetNumberOfFileNames() + for i in range(0,nfiles): + filename = t.GetFileName(i) + sucess += TestPythonFilter( filename ) + + + # Test succeed ? + sys.exit(sucess == 0) diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Python/TestScanner.py b/gdcm/Testing/Source/MediaStorageAndFileFormat/Python/TestScanner.py new file mode 100644 index 0000000..814e2cd --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Python/TestScanner.py @@ -0,0 +1,93 @@ +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +import gdcm +import os,sys + +def TestScan(dirname, recursive = False): + # Check the dirname is indeed a directory + system = gdcm.System() + if not system.FileIsDirectory(dirname): + print("Need a directory") + sys.exit(1) + + # Retrieve all the files within that dir (recursively?) + d = gdcm.Directory() + nfiles = d.Load( dirname, recursive ) + print("done retrieving all the",nfiles,"files") + + s = gdcm.Scanner() + t1 = gdcm.Tag(0x0020,0x000d) # VR::UI + t2 = gdcm.Tag(0x0020,0x000e) # VR::UI + t3 = gdcm.Tag(0x0028,0x0011) # VR::US + # Some fun tags, with dual VR: + t4 = gdcm.Tag(0x0028,0x0106) # VR::US_SS + t5 = gdcm.Tag(0x0028,0x0107) # VR::US_SS + s.AddTag( t1 ) + s.AddTag( t2 ) + s.AddTag( t3 ) + s.AddTag( t4 ) + s.AddTag( t5 ) + b = s.Scan( d.GetFilenames() ) + if not b: + print("Scanner failed") + sys.exit(1) + + # Raw Values found: + values = s.GetValues() + print("Values found for all tags are:") + print(values) + + # get the main super-map : + mappings = s.GetMappings() + + #file1 = d.GetFilenames()[0]; + #print file1 + #m1 = s.GetMapping( file1 ) + #print m1 + #print dir(m1) + + #for k,v in m1.iteritems(): + # print "item", k,v + + + # For each file get the value for tag t1: + for f in d.GetFilenames(): + print("Working on:",f) + mapping = s.GetMapping(f) + pttv = gdcm.PythonTagToValue(mapping) + # reset iterator to start position + pttv.Start() + # iterate until the end: + while( not pttv.IsAtEnd() ): + # get current value for tag and associated value: + # if tag was not found, then it was simply not added to the internal std::map + # Warning value can be None + tag = pttv.GetCurrentTag() + value = pttv.GetCurrentValue() + print(tag,"->",value) + # increment iterator + pttv.Next() + +if __name__ == "__main__": + try: + dirname = os.sys.argv[1] + recursive = True + except: + t = gdcm.Testing() + dirname = t.GetDataRoot() + recursive = False + TestScan( dirname, recursive) + + sys.exit(0) diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Python/TestStringFilter.py b/gdcm/Testing/Source/MediaStorageAndFileFormat/Python/TestStringFilter.py new file mode 100644 index 0000000..f1b8490 --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Python/TestStringFilter.py @@ -0,0 +1,63 @@ +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +import gdcm +import os,sys + +def TestStringFilter(filename, verbose = False): + r = gdcm.Reader() + r.SetFileName( filename ) + sucess = r.Read() + if( not sucess ): return 1 + + file = r.GetFile() + ds = file.GetDataSet() + # Change gdcm struct into something swig can digest: + pds = gdcm.PythonDataSet(ds) + sf = gdcm.StringFilter() + pds.Start() # Make iterator go at begining + dic1={} + dic2={} + sf.SetFile(file) # extremely important + while(not pds.IsAtEnd() ): + t = str(pds.GetCurrent().GetTag()) + res = sf.ToStringPair( pds.GetCurrent().GetTag() ) + dic2[t] = res[1] + dic1[res[0]] = res[1] + pds.Next() + #print dic1 + #print dic2 + try: + print "Pixel Representation=",dic2[ '(0028,0103)' ] + except KeyError: + print "Tag not found in dataset" + return 0 + +if __name__ == "__main__": + sucess = 0 + try: + filename = os.sys.argv[1] + sucess += TestStringFilter( filename, True ) + except: + # loop over all files: + gdcm.Trace.WarningOff() + t = gdcm.Testing() + nfiles = t.GetNumberOfFileNames() + for i in range(0,nfiles): + filename = t.GetFileName(i) + sucess += TestStringFilter( filename ) + + + # Test succeed ? + sys.exit(sucess == 0) diff --git a/gdcm/Testing/Source/MediaStorageAndFileFormat/Python/TestUIDGenerator.py b/gdcm/Testing/Source/MediaStorageAndFileFormat/Python/TestUIDGenerator.py new file mode 100644 index 0000000..f145e2e --- /dev/null +++ b/gdcm/Testing/Source/MediaStorageAndFileFormat/Python/TestUIDGenerator.py @@ -0,0 +1,32 @@ +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +import gdcm +import os,sys + +if __name__ == "__main__": + uid = gdcm.UIDGenerator() + for i in range(0,100): + print(uid.Generate()) + + MY_ROOT = "1.2.3.4" + + # static function: + gdcm.UIDGenerator_SetRoot( MY_ROOT ) + for i in range(0,100): + print(uid.Generate()) + + + # Test succeed ? + sys.exit(0) diff --git a/gdcm/Testing/Source/MessageExchangeDefinition/CMakeLists.txt b/gdcm/Testing/Source/MessageExchangeDefinition/CMakeLists.txt new file mode 100644 index 0000000..ccbaece --- /dev/null +++ b/gdcm/Testing/Source/MessageExchangeDefinition/CMakeLists.txt @@ -0,0 +1 @@ +subdirs(Cxx) diff --git a/gdcm/Testing/Source/MessageExchangeDefinition/Cxx/CMakeLists.txt b/gdcm/Testing/Source/MessageExchangeDefinition/Cxx/CMakeLists.txt new file mode 100644 index 0000000..5497383 --- /dev/null +++ b/gdcm/Testing/Source/MessageExchangeDefinition/Cxx/CMakeLists.txt @@ -0,0 +1,69 @@ +# MEXD Testing +set(MEXD_TEST_SRCS + TestPresentationContextRQ + TestQueryFactory + TestULConnectionManager + TestServiceClassUser1 + TestServiceClassUser2 + TestServiceClassUser3 + TestSCUValidation + TestEcho + TestFind + #TestULTransitionTable # symbols are not exported, mainly used for debugging + TestFindStudyRootQuery + TestFindPatientRootQuery + ) +if(GDCM_DATA_ROOT) + set(MEXD_TEST_SRCS + ${MEXD_TEST_SRCS} + TestSCUFunctions + ) +endif() + +# Add the include paths +include_directories( + "${GDCM_BINARY_DIR}/Source/Common" + "${GDCM_SOURCE_DIR}/Source/Common" + "${GDCM_SOURCE_DIR}/Testing/Source/Data" + "${GDCM_BINARY_DIR}/Testing/Source/Data" + "${GDCM_SOURCE_DIR}/Source/DataStructureAndEncodingDefinition" + "${GDCM_SOURCE_DIR}/Source/DataDictionary" + "${GDCM_SOURCE_DIR}/Source/MediaStorageAndFileFormat" + "${GDCM_SOURCE_DIR}/Source/MessageExchangeDefinition" + ) + +create_test_sourcelist(MEXDTests gdcmMEXDTests.cxx ${MEXD_TEST_SRCS} + EXTRA_INCLUDE gdcmTestDriver.h + ) +add_executable(gdcmMEXDTests ${MEXDTests}) +target_link_libraries(gdcmMEXDTests gdcmMEXD gdcmMSFF gdcmDSED gdcmDICT gdcmCommon) + +#Don't understand why I need that ?? +set(GDCM_MEXD_TESTS "${EXECUTABLE_OUTPUT_PATH}/gdcmMEXDTests") + +# Loop over files and create executables +foreach(name ${MEXD_TEST_SRCS}) + if(${name} STREQUAL "TestSCUFunctions" + OR ${name} STREQUAL "TestServiceClassUser1" + OR ${name} STREQUAL "TestServiceClassUser2" + OR ${name} STREQUAL "TestServiceClassUser3" + ) + if(GDCM_DICOM_SERVER_AETITLE) + add_test(NAME ${name} COMMAND ${GDCM_MEXD_TESTS} ${name} ${GDCM_DICOM_CLIENT_AETITLE} + ${GDCM_DICOM_SERVER_AETITLE} ${GDCM_DICOM_SERVER_PORT} + ${GDCM_DICOM_CLIENT_PORT} ${GDCM_DICOM_SERVER_PEER}) + endif() + else() + add_test(NAME ${name} COMMAND ${GDCM_MEXD_TESTS} ${name}) + endif() +endforeach() + +set(DCMQRSCP_HOSTNAME gotlib) +set(DCMQRSCP_PORT 5677) +set(DCMQRSCP_DIRECTORY ${GDCM_TEMP_DIRECTORY}) +configure_file( + ${GDCM_SOURCE_DIR}/CMake/dcmqrscp.cfg.in + ${CMAKE_CURRENT_BINARY_DIR}/dcmqrscp.cfg + ) +# execute_process(COMMAND ${DCMTK_DCMQRSCP_EXECUTABLE} +# --verbose --debug -c ${CMAKE_CURRENT_BINARY_DIR}/dcmqrscp.cfg) diff --git a/gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestEcho.cxx b/gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestEcho.cxx new file mode 100644 index 0000000..9d74344 --- /dev/null +++ b/gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestEcho.cxx @@ -0,0 +1,34 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ + +#include "gdcmCompositeNetworkFunctions.h" +#include "gdcmTag.h" +#include "gdcmQueryFactory.h" + +int TestEcho(int , char *[]) +{ + std::string hostname = "www.dicomserver.co.uk"; + uint16_t port = 11112; + std::string callaetitle = "GDCM_ROCKS"; + std::string callingaetitle = "ACME1"; + + bool didItWork = gdcm::CompositeNetworkFunctions::CEcho( hostname.c_str(), port, + callingaetitle.c_str(), callaetitle.c_str() ); + + return (didItWork ? 0:1); +} diff --git a/gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestFind.cxx b/gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestFind.cxx new file mode 100644 index 0000000..e6109cb --- /dev/null +++ b/gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestFind.cxx @@ -0,0 +1,65 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ + +#include "gdcmCompositeNetworkFunctions.h" +#include "gdcmTag.h" +#include "gdcmQueryFactory.h" +#include "gdcmMovePatientRootQuery.h" + + +int TestFind(int , char *[]) +{ + std::string hostname = "www.dicomserver.co.uk"; + uint16_t port = 11112; + std::string callaetitle = "GDCM_ROCKS"; + std::string callingaetitle = "ACME1"; + + + gdcm::Tag theTag(0x0010, 0x0010); + std::string theName = "F*"; + std::pair theTagPair = + std::make_pair(theTag, theName); + + std::vector > theTags; + theTags.push_back(theTagPair); + + gdcm::BaseRootQuery* theQuery = gdcm::CompositeNetworkFunctions::ConstructQuery( + gdcm::ePatientRootType, gdcm::ePatient, theTags); + + if (!theQuery) { + std::cerr << "Query construction failed!" << std::endl; + return 1; + } + + if (!theQuery->ValidateQuery(false)) + { + std::cerr << "Find query is not valid. Please try again." << std::endl; + delete theQuery; + return 1; + } + + std::vector theDataSet ; + bool b = + gdcm::CompositeNetworkFunctions::CFind(hostname.c_str(), port, + theQuery, theDataSet , callingaetitle.c_str(), callaetitle.c_str()); + if( !b ) return 1; + + //need to put some kind of validation of theDataSet here + + return (theDataSet.empty() ? 1:0);//shouldn't be a zero-sized dataset +} diff --git a/gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestFindPatientRootQuery.cxx b/gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestFindPatientRootQuery.cxx new file mode 100644 index 0000000..caf4e87 --- /dev/null +++ b/gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestFindPatientRootQuery.cxx @@ -0,0 +1,253 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmFindPatientRootQuery.h" + +#include "gdcmCompositeNetworkFunctions.h" +#include "gdcmTrace.h" + +/* + * STUDY: + * $ findscu --call GDCM_STORE --aetitle GDCMDASH -P server 11112 -k 8,52="PATIENT" -k 10,20="1*" + * $ findscu --call GDCM_STORE --aetitle GDCMDASH -S server 11112 -k 8,52="STUDY" -k 10,20="FOO" + * + * SERIES: + * $ findscu --call GDCM_STORE --aetitle GDCMDASH -S lirispat 11112 -k 8,52="SERIES" -k 20,d="1.2.3" -k 8,60 + */ + +int TestFindPatientRootQuery(int , char *[]) +{ + //gdcm::Trace::DebugOn(); + gdcm::Trace::WarningOff(); + + // PATIENT: + gdcm::ERootType theRoot = gdcm::ePatientRootType; + gdcm::EQueryLevel theLevel = gdcm::ePatient; + { + std::vector< std::pair > keys; + gdcm::SmartPointer theQuery = + gdcm::CompositeNetworkFunctions::ConstructQuery(theRoot, theLevel ,keys); + if( theQuery->ValidateQuery( true ) ) + { + // No key found is an error + return 1; + } + } + { + std::vector< std::pair > keys; + keys.push_back( std::make_pair( gdcm::Tag(0x10,0x10), "patient" ) ) ; + gdcm::SmartPointer theQuery = + gdcm::CompositeNetworkFunctions::ConstructQuery(theRoot, theLevel ,keys); + if( theQuery->ValidateQuery( true ) ) + { + // required key + return 1; + } + } + { + std::vector< std::pair > keys; + keys.push_back( std::make_pair( gdcm::Tag(0x10,0x20), "patientid" ) ) ; + gdcm::SmartPointer theQuery = + gdcm::CompositeNetworkFunctions::ConstructQuery(theRoot, theLevel ,keys); + if( !theQuery->ValidateQuery( true ) ) + { + // unique key + return 1; + } + } + { + std::vector< std::pair > keys; + keys.push_back( std::make_pair( gdcm::Tag(0x10,0x20), "patientid" ) ) ; + keys.push_back( std::make_pair( gdcm::Tag(0x10,0x10), "patient" ) ) ; + gdcm::SmartPointer theQuery = + gdcm::CompositeNetworkFunctions::ConstructQuery(theRoot, theLevel ,keys); + if( !theQuery->ValidateQuery( true ) ) + { + // unique key + required + return 1; + } + } + + // STUDY: + theLevel = gdcm::eStudy; + { + std::vector< std::pair > keys; + keys.push_back( std::make_pair( gdcm::Tag(0x10,0x10), "PATIENT" ) ) ; + gdcm::SmartPointer theQuery = + gdcm::CompositeNetworkFunctions::ConstructQuery(theRoot, theLevel ,keys); + if( theQuery->ValidateQuery( true ) ) + { + // Patient Id is a Required Key in Study + return 1; + } + } + { + std::vector< std::pair > keys; + keys.push_back( std::make_pair( gdcm::Tag(0x20,0x10), "studyid" ) ) ; + gdcm::SmartPointer theQuery = + gdcm::CompositeNetworkFunctions::ConstructQuery(theRoot, theLevel ,keys); + if( theQuery->ValidateQuery( true ) ) + { + // Study Id is a required tag + return 1; + } + } + { + std::vector< std::pair > keys; + keys.push_back( std::make_pair( gdcm::Tag(0x8,0x90), "physician" ) ) ; + gdcm::SmartPointer theQuery = + gdcm::CompositeNetworkFunctions::ConstructQuery(theRoot, theLevel ,keys); + if( theQuery->ValidateQuery( true ) ) + { + // ref physician's name is optional + return 1; + } + } + { + std::vector< std::pair > keys; + keys.push_back( std::make_pair( gdcm::Tag(0x10,0x20), "patientid" ) ) ; + keys.push_back( std::make_pair( gdcm::Tag(0x20,0xd), "studyuid" ) ) ; + gdcm::SmartPointer theQuery = + gdcm::CompositeNetworkFunctions::ConstructQuery(theRoot, theLevel ,keys); + if( !theQuery->ValidateQuery( true ) ) + { + // Study UID is the unique tag + return 1; + } + } + + // SERIES: + theLevel = gdcm::eSeries; + { + std::vector< std::pair > keys; + gdcm::SmartPointer theQuery = + gdcm::CompositeNetworkFunctions::ConstructQuery(theRoot, theLevel ,keys); + if( theQuery->ValidateQuery( true ) ) + { + // No key found is an error + return 1; + } + } + { + std::vector< std::pair > keys; + keys.push_back( std::make_pair( gdcm::Tag(0x20,0xd), "1.2.3" ) ) ; + gdcm::SmartPointer theQuery = + gdcm::CompositeNetworkFunctions::ConstructQuery(theRoot, theLevel ,keys); + if( theQuery->ValidateQuery( true ) ) + { + // No key at level Series + return 1; + } + } + { + std::vector< std::pair > keys; + keys.push_back( std::make_pair( gdcm::Tag(0x20,0xd), "1.2.3" ) ) ; + keys.push_back( std::make_pair( gdcm::Tag(0x8,0x60), "" ) ) ; + gdcm::SmartPointer theQuery = + gdcm::CompositeNetworkFunctions::ConstructQuery(theRoot, theLevel ,keys); + if( theQuery->ValidateQuery( true ) ) + { + // missing unique at series level + return 1; + } + } + { + std::vector< std::pair > keys; + keys.push_back( std::make_pair( gdcm::Tag(0x20,0xd), "1.2.3" ) ) ; + keys.push_back( std::make_pair( gdcm::Tag(0x20,0xe), "4.5.6" ) ) ; + gdcm::SmartPointer theQuery = + gdcm::CompositeNetworkFunctions::ConstructQuery(theRoot, theLevel ,keys); + if( !theQuery->ValidateQuery( true ) ) + { + // all unique keys present + return 1; + } + } + { + std::vector< std::pair > keys; + keys.push_back( std::make_pair( gdcm::Tag(0x20,0xd), "1.2.3" ) ) ; + keys.push_back( std::make_pair( gdcm::Tag(0x20,0xe), "4.5.6" ) ) ; + keys.push_back( std::make_pair( gdcm::Tag(0x8,0x60), "" ) ) ; + gdcm::SmartPointer theQuery = + gdcm::CompositeNetworkFunctions::ConstructQuery(theRoot, theLevel ,keys); + if( !theQuery->ValidateQuery( true ) ) + { + // all unique keys present and required is correct level + return 1; + } + } + { + std::vector< std::pair > keys; + keys.push_back( std::make_pair( gdcm::Tag(0x20,0xd), "1.2.3" ) ) ; + keys.push_back( std::make_pair( gdcm::Tag(0x20,0xe), "4.5.6" ) ) ; + keys.push_back( std::make_pair( gdcm::Tag(0x8,0x20), "" ) ) ; + gdcm::SmartPointer theQuery = + gdcm::CompositeNetworkFunctions::ConstructQuery(theRoot, theLevel ,keys); + if( theQuery->ValidateQuery( true ) ) + { + // all unique keys present and required is incorrect level + return 1; + } + } + + // IMAGES: + + theLevel = gdcm::eImage; + { + std::vector< std::pair > keys; + keys.push_back( std::make_pair( gdcm::Tag(0x20,0xd), "1.2.3" ) ) ; + keys.push_back( std::make_pair( gdcm::Tag(0x20,0xe), "4.5.6" ) ) ; + keys.push_back( std::make_pair( gdcm::Tag(0x8,0x18), "7.8.9" ) ) ; + gdcm::SmartPointer theQuery = + gdcm::CompositeNetworkFunctions::ConstructQuery(theRoot, theLevel ,keys); + if( !theQuery->ValidateQuery( true ) ) + { + // all unique keys present + return 1; + } + } + + { + std::vector< std::pair > keys; + keys.push_back( std::make_pair( gdcm::Tag(0x20,0xd), "1.2.3" ) ) ; + keys.push_back( std::make_pair( gdcm::Tag(0x20,0xe), "4.5.6" ) ) ; + keys.push_back( std::make_pair( gdcm::Tag(0x8,0x18), "7.8.9" ) ) ; + keys.push_back( std::make_pair( gdcm::Tag(0x20,0x13), "" ) ) ; + gdcm::SmartPointer theQuery = + gdcm::CompositeNetworkFunctions::ConstructQuery(theRoot, theLevel ,keys); + if( !theQuery->ValidateQuery( true ) ) + { + // all unique keys present + required correct level + return 1; + } + } + + { + std::vector< std::pair > keys; + keys.push_back( std::make_pair( gdcm::Tag(0x20,0xd), "1.2.3" ) ) ; + keys.push_back( std::make_pair( gdcm::Tag(0x20,0xe), "4.5.6" ) ) ; + keys.push_back( std::make_pair( gdcm::Tag(0x8,0x18), "7.8.9" ) ) ; + keys.push_back( std::make_pair( gdcm::Tag(0x20,0x13), "" ) ) ; + keys.push_back( std::make_pair( gdcm::Tag(0x20,0x11), "" ) ) ; // series level + gdcm::SmartPointer theQuery = + gdcm::CompositeNetworkFunctions::ConstructQuery(theRoot, theLevel ,keys); + if( theQuery->ValidateQuery( true ) ) + { + // all unique keys present + required correct level + one incorrect + return 1; + } + } + + //std::cout << "sucess" << std::endl; + return 0; +} diff --git a/gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestFindStudyRootQuery.cxx b/gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestFindStudyRootQuery.cxx new file mode 100644 index 0000000..eb72c4e --- /dev/null +++ b/gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestFindStudyRootQuery.cxx @@ -0,0 +1,218 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmFindStudyRootQuery.h" + +#include "gdcmCompositeNetworkFunctions.h" +#include "gdcmTrace.h" + +/* + * STUDY: + * $ findscu --call GDCM_STORE --aetitle GDCMDASH -P server 11112 -k 8,52="PATIENT" -k 10,20="1*" + * $ findscu --call GDCM_STORE --aetitle GDCMDASH -S server 11112 -k 8,52="STUDY" -k 10,20="FOO" + * + * SERIES: + * $ findscu --call GDCM_STORE --aetitle GDCMDASH -S lirispat 11112 -k 8,52="SERIES" -k 20,d="1.2.3" -k 8,60 + */ + +int TestFindStudyRootQuery(int , char *[]) +{ + //gdcm::Trace::DebugOn(); + gdcm::Trace::WarningOff(); + + // STUDY: + gdcm::ERootType theRoot = gdcm::eStudyRootType; + gdcm::EQueryLevel theLevel = gdcm::eStudy; + + { + std::vector< std::pair > keys; + gdcm::SmartPointer theQuery = + gdcm::CompositeNetworkFunctions::ConstructQuery(theRoot, theLevel ,keys); + if( theQuery->ValidateQuery( true ) ) + { + // No key found is an error + return 1; + } + } + { + std::vector< std::pair > keys; + keys.push_back( std::make_pair( gdcm::Tag(0x10,0x10), "PATIENT" ) ) ; + gdcm::SmartPointer theQuery = + gdcm::CompositeNetworkFunctions::ConstructQuery(theRoot, theLevel ,keys); + if( theQuery->ValidateQuery( true ) ) + { + // Patient Id is a Required Key in Study + return 1; + } + } + { + std::vector< std::pair > keys; + keys.push_back( std::make_pair( gdcm::Tag(0x20,0x10), "studyid" ) ) ; + gdcm::SmartPointer theQuery = + gdcm::CompositeNetworkFunctions::ConstructQuery(theRoot, theLevel ,keys); + if( theQuery->ValidateQuery( true ) ) + { + // Study Id is a required tag + return 1; + } + } + { + std::vector< std::pair > keys; + keys.push_back( std::make_pair( gdcm::Tag(0x8,0x90), "physician" ) ) ; + gdcm::SmartPointer theQuery = + gdcm::CompositeNetworkFunctions::ConstructQuery(theRoot, theLevel ,keys); + if( theQuery->ValidateQuery( true ) ) + { + // ref physician's name is optional + return 1; + } + } + { + std::vector< std::pair > keys; + keys.push_back( std::make_pair( gdcm::Tag(0x20,0xd), "studyuid" ) ) ; + gdcm::SmartPointer theQuery = + gdcm::CompositeNetworkFunctions::ConstructQuery(theRoot, theLevel ,keys); + if( !theQuery->ValidateQuery( true ) ) + { + // Study UID is the unique tag + return 1; + } + } + + // SERIES: + + theLevel = gdcm::eSeries; + + { + std::vector< std::pair > keys; + gdcm::SmartPointer theQuery = + gdcm::CompositeNetworkFunctions::ConstructQuery(theRoot, theLevel ,keys); + if( theQuery->ValidateQuery( true ) ) + { + // No key found is an error + return 1; + } + } + { + std::vector< std::pair > keys; + keys.push_back( std::make_pair( gdcm::Tag(0x20,0xd), "1.2.3" ) ) ; + gdcm::SmartPointer theQuery = + gdcm::CompositeNetworkFunctions::ConstructQuery(theRoot, theLevel ,keys); + if( theQuery->ValidateQuery( true ) ) + { + // No key at level Series + return 1; + } + } + { + std::vector< std::pair > keys; + keys.push_back( std::make_pair( gdcm::Tag(0x20,0xd), "1.2.3" ) ) ; + keys.push_back( std::make_pair( gdcm::Tag(0x8,0x60), "" ) ) ; + gdcm::SmartPointer theQuery = + gdcm::CompositeNetworkFunctions::ConstructQuery(theRoot, theLevel ,keys); + if( theQuery->ValidateQuery( true ) ) + { + // missing unique at series level + return 1; + } + } + { + std::vector< std::pair > keys; + keys.push_back( std::make_pair( gdcm::Tag(0x20,0xd), "1.2.3" ) ) ; + keys.push_back( std::make_pair( gdcm::Tag(0x20,0xe), "4.5.6" ) ) ; + gdcm::SmartPointer theQuery = + gdcm::CompositeNetworkFunctions::ConstructQuery(theRoot, theLevel ,keys); + if( !theQuery->ValidateQuery( true ) ) + { + // all unique keys present + return 1; + } + } + { + std::vector< std::pair > keys; + keys.push_back( std::make_pair( gdcm::Tag(0x20,0xd), "1.2.3" ) ) ; + keys.push_back( std::make_pair( gdcm::Tag(0x20,0xe), "4.5.6" ) ) ; + keys.push_back( std::make_pair( gdcm::Tag(0x8,0x60), "" ) ) ; + gdcm::SmartPointer theQuery = + gdcm::CompositeNetworkFunctions::ConstructQuery(theRoot, theLevel ,keys); + if( !theQuery->ValidateQuery( true ) ) + { + // all unique keys present and required is correct level + return 1; + } + } + { + std::vector< std::pair > keys; + keys.push_back( std::make_pair( gdcm::Tag(0x20,0xd), "1.2.3" ) ) ; + keys.push_back( std::make_pair( gdcm::Tag(0x20,0xe), "4.5.6" ) ) ; + keys.push_back( std::make_pair( gdcm::Tag(0x8,0x20), "" ) ) ; + gdcm::SmartPointer theQuery = + gdcm::CompositeNetworkFunctions::ConstructQuery(theRoot, theLevel ,keys); + if( theQuery->ValidateQuery( true ) ) + { + // all unique keys present and required is incorrect level + return 1; + } + } + + // IMAGES: + + theLevel = gdcm::eImage; + { + std::vector< std::pair > keys; + keys.push_back( std::make_pair( gdcm::Tag(0x20,0xd), "1.2.3" ) ) ; + keys.push_back( std::make_pair( gdcm::Tag(0x20,0xe), "4.5.6" ) ) ; + keys.push_back( std::make_pair( gdcm::Tag(0x8,0x18), "7.8.9" ) ) ; + gdcm::SmartPointer theQuery = + gdcm::CompositeNetworkFunctions::ConstructQuery(theRoot, theLevel ,keys); + if( !theQuery->ValidateQuery( true ) ) + { + // all unique keys present + return 1; + } + } + + { + std::vector< std::pair > keys; + keys.push_back( std::make_pair( gdcm::Tag(0x20,0xd), "1.2.3" ) ) ; + keys.push_back( std::make_pair( gdcm::Tag(0x20,0xe), "4.5.6" ) ) ; + keys.push_back( std::make_pair( gdcm::Tag(0x8,0x18), "7.8.9" ) ) ; + keys.push_back( std::make_pair( gdcm::Tag(0x20,0x13), "" ) ) ; + gdcm::SmartPointer theQuery = + gdcm::CompositeNetworkFunctions::ConstructQuery(theRoot, theLevel ,keys); + if( !theQuery->ValidateQuery( true ) ) + { + // all unique keys present + required correct level + return 1; + } + } + + { + std::vector< std::pair > keys; + keys.push_back( std::make_pair( gdcm::Tag(0x20,0xd), "1.2.3" ) ) ; + keys.push_back( std::make_pair( gdcm::Tag(0x20,0xe), "4.5.6" ) ) ; + keys.push_back( std::make_pair( gdcm::Tag(0x8,0x18), "7.8.9" ) ) ; + keys.push_back( std::make_pair( gdcm::Tag(0x20,0x13), "" ) ) ; + keys.push_back( std::make_pair( gdcm::Tag(0x20,0x11), "" ) ) ; // series level + gdcm::SmartPointer theQuery = + gdcm::CompositeNetworkFunctions::ConstructQuery(theRoot, theLevel ,keys); + if( theQuery->ValidateQuery( true ) ) + { + // all unique keys present + required correct level + one incorrect + return 1; + } + } + + //std::cout << "sucess" << std::endl; + return 0; +} diff --git a/gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestPresentationContextRQ.cxx b/gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestPresentationContextRQ.cxx new file mode 100644 index 0000000..fc12a0f --- /dev/null +++ b/gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestPresentationContextRQ.cxx @@ -0,0 +1,24 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#include "gdcmPresentationContextRQ.h" + +int TestPresentationContextRQ(int , char *[]) +{ + gdcm::network::PresentationContextRQ o; + return 0; +} diff --git a/gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestQueryFactory.cxx b/gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestQueryFactory.cxx new file mode 100644 index 0000000..5d72fb9 --- /dev/null +++ b/gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestQueryFactory.cxx @@ -0,0 +1,25 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#include "gdcmQueryFactory.h" + +int TestQueryFactory(int , char *[]) +{ + gdcm::QueryFactory o; + (void)o; + return 0; +} diff --git a/gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestSCUFunctions.cxx b/gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestSCUFunctions.cxx new file mode 100644 index 0000000..87422be --- /dev/null +++ b/gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestSCUFunctions.cxx @@ -0,0 +1,312 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ + +#include "gdcmCompositeNetworkFunctions.h" +#include "gdcmBaseRootQuery.h" + +//#include "gdcmDirectory.h" +#include "gdcmScanner.h" +#include "gdcmTesting.h" +#include "gdcmReader.h" +#include "gdcmWriter.h" +#include "gdcmAttribute.h" +#include "gdcmGlobal.h" + +#include +#include + +//this should maybe override == ? +bool AreDataSetsEqual(const gdcm::DataSet& ds1, const gdcm::DataSet& ds2){ + gdcm::DataSet::ConstIterator it1 = ds1.Begin(); + gdcm::DataSet::ConstIterator it2 = ds2.Begin(); + + const gdcm::DataElement &de1 = *it1; + const gdcm::DataElement &de2 = *it2; + if( de1 == de2 ) + { + } + while( it1 != ds1.End() && it2 != ds2.End() && *it1 == *it2 ) + { + ++it1; + ++it2; + } + + if( it1 != ds1.End() || it2 != ds2.End() ) + { + std::cerr << "Problem with:" << std::endl; + if( it1 != ds1.End() ) + { + std::cerr << "ds1: " << *it1 << std::endl; + } + if( it2 != ds2.End() ) + { + std::cerr << "ds2: " << *it2 << std::endl; + } + return false; + } + + return true; +} + +bool checkbl( const char *filename ) +{ + static const char *blacklist[] = { + "PHILIPS_GDCM12xBug2.dcm", // #3196213 + // W: DIMSE Warning: (GDCMSCU,ANY-SCP): DIMSE receiveDataSetInMemory: + // dset->read() Failed (Corrupted data) + "MR_Philips_Intera_No_PrivateSequenceImplicitVR.dcm", + "MR_Philips_Intera_PrivateSequenceImplicitVR.dcm", + "GE_DLX-8-MONO2-PrivateSyntax.dcm", // Implicit VR Big Endian DLX (G.E Private) + "PrivateGEImplicitVRBigEndianTransferSyntax16Bits.dcm", // Implicit VR Big Endian DLX (G.E Private) + // W: DIMSE Warning: (STORESCU,ANY-SCP): sendMessage: unable to convert + // dataset from 'JPEG Lossless, Non-hierarchical, Process 14' transfer + // syntax to 'Big Endian Explicit' + "SignedShortLosslessBug.dcm", + "MR-MONO2-12-shoulder.dcm", + // difficult for now: + "SIEMENS_SOMATOM-12-ACR_NEMA-ZeroLengthUs.acr", + "MR-MONO2-12-an2.acr", + "ExplicitVRforPublicElementsImplicitVRforShadowElements.dcm", + NULL + }; + for( const char **bl = blacklist; *bl; ++bl ) + { + const char *res = strstr( filename, *bl ); + if( res ) + { + return true; + } + } + return false; +} + +int TestSCUFunctions(int argc, char *argv[]) +{ + if( argc < 6 ) + { + std::cerr << argv[0] << " aetitle call portno moveReturnPort remote" << std::endl; + return 1; + } + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + std::string aetitle = argv[1]; // the ae title of this computer + std::string call = argv[2]; // the ae title of the server + uint16_t portno = (uint16_t)atoi(argv[3]); // the port of the server + uint16_t moveReturnPort = (uint16_t)atoi(argv[4]); // the port over which return cstore scps are done for cmove + std::string remote = argv[5]; //the ip address of the remote server + std::string tmpdir = gdcm::Testing::GetTempDirectory( "TestSCUFunctions" ); + std::string outputDir = tmpdir; //place to where data is returned by cmove + //std::string inputDir = gdcm::Testing::GetDataRoot(); //input collection of data to transfer + + bool didItWork = gdcm::CompositeNetworkFunctions::CEcho( remote.c_str(), portno, + aetitle.c_str(), call.c_str() ); + + if (!didItWork) + { + std::cerr << "Echo failed." << std::endl; + return 1; + } + + std::vector theFilenames; + const char *filename; + int i = 0; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + theFilenames.push_back( filename ); + ++i; + } + + // Fow now lets eliminate invalid candidates: + // - no SOP Class UID + // - no SOP Instance UID + gdcm::Scanner sc; + gdcm::Tag tts(0x0002,0x0010); + gdcm::Tag sopclass(0x8,0x16); + gdcm::Tag sopinstance(0x8,0x18); + sc.AddTag( tts ); + sc.AddTag( sopclass ); + sc.AddTag( sopinstance ); + if( !sc.Scan( theFilenames ) ) + { + return 1; + } + + std::vector< gdcm::UIComp > validuids; + validuids.push_back( "1.2.840.10008.1.2" ); + validuids.push_back( "1.2.840.10008.1.2.1" ); + //validuids.push_back( "1.2.840.10008.1.2.2" ); + // remove any file without SOP Instance UID + for( + gdcm::Directory::FilenamesType::iterator it = theFilenames.begin(); + it != theFilenames.end(); ) + { + const char *file = it->c_str(); + const char* v1 = sc.GetValue(file, sopclass ); + const char* v2 = sc.GetValue(file, sopinstance ); + const char* v3 = sc.GetValue(file, tts ); + gdcm::UIComp v3uid; + if ( v3 ) v3uid = v3; + std::vector< gdcm::UIComp >::const_iterator it2 = std::find( validuids.begin(), + validuids.end(), v3uid ); + if( !v1 || !v2 || !*v1 || !*v2 ) it = theFilenames.erase( it ); + else if( checkbl( file ) ) it = theFilenames.erase( it ); + else if( v3 && it2 == validuids.end() ) + { + //std::cerr << "erase: " << *it << " [" << v3uid << "]" << std::endl; + it = theFilenames.erase( it ); + } + else ++it; + } + + //store the datasets remotely + didItWork = gdcm::CompositeNetworkFunctions::CStore(remote.c_str(), portno, theFilenames, + aetitle.c_str(), call.c_str()); + + if (!didItWork) + { + std::cerr << "Store failed." << std::endl; + return 1; + } + + std::vector::iterator fitor; + for (fitor = theFilenames.begin(); fitor < theFilenames.end(); ++fitor) + { + //read in the file + gdcm::Reader theReader; + theReader.SetFileName(fitor->c_str()); + if (!theReader.Read()) + { + std::cerr << "Test failed, dicom file " << *fitor << " failed to load." < > keys; + gdcm::Tag theTag(0x0010, 0x0010); + gdcm::Tag theIDTag(0x0010, 0x0020); + if (ds.FindDataElement(theTag)) + { + gdcm::DataElement de = ds.GetDataElement(theTag); + const gdcm::ByteValue* bv = de.GetByteValue(); + int theBufferLen = bv->GetLength(); + if (theBufferLen < 2) continue; + char* theBuf = new char[theBufferLen]; + bv->GetBuffer(theBuf, theBufferLen); + gdcm::UIComp theSearchStringRaw(theBuf, theBufferLen/2); + delete [] theBuf; + // HACK: + std::string theSearchString = theSearchStringRaw.Trim(); + std::replace( theSearchString.begin(), theSearchString.end(), ' ', '?'); + theSearchString += "*"; + std::cerr << "search for: [" << theSearchString << "]" << std::endl; + if (theSearchString.size() %2 == 1) + { + theSearchString += " "; //to make sure everything is double spaced + } + keys.push_back(std::make_pair(theTag, theSearchString)); + } + else + { + continue; + } + std::string theEmptyString; + keys.push_back(std::make_pair(theIDTag, theEmptyString)); + + gdcm::BaseRootQuery *theQuery = + gdcm::CompositeNetworkFunctions::ConstructQuery(gdcm::ePatientRootType, gdcm::ePatient, keys); + + std::vector theDataSets; + bool b = gdcm::CompositeNetworkFunctions::CFind(remote.c_str(), portno, theQuery, theDataSets, aetitle.c_str(), call.c_str()); + + //std::cout << theQuery->GetQueryDataSet() << std::endl; + delete theQuery; + if( !b ) + { + std::cerr << "Problem in CFind" << std::endl; + return 1; + } + + if (theDataSets.empty()) + { + std::cerr << "Unable to find the dataset that was just sent to the server, " << *fitor << std::endl; + return 1; + } + + keys.clear(); + //if it's not empty, then pull it. + std::vector::iterator itor; + for (itor = theDataSets.begin(); itor != theDataSets.end(); itor++) + { + if (itor->FindDataElement(theIDTag)) + { + gdcm::DataElement de = itor->GetDataElement(theIDTag); + const gdcm::ByteValue *bv = de.GetByteValue(); + int theBufferLen = bv->GetLength(); + char* theBuf = new char[theBufferLen]; + bv->GetBuffer(theBuf, theBufferLen); + std::string theSearchString(theBuf, theBuf + theBufferLen); + delete [] theBuf; + keys.push_back(std::make_pair(theIDTag, theSearchString)); + + gdcm::DataElement de2 = ds.GetDataElement(theIDTag); + de2.SetVR( gdcm::VR::INVALID ); + de.SetVR( gdcm::VR::INVALID ); + if (!(de == de2)) + { + std::cerr << "Sent dataset does not match returned dataset ID. " << std::endl; + std::cerr << de << std::endl; + std::cerr << " vs " << std::endl; + std::cerr << de2 << std::endl; + std::cerr << "File: " << *fitor << std::endl; + return 1; + } + break; + } + else + { + continue; + } + } + + if (keys.empty()) + { + std::cerr << "Sent dataset " << *fitor << " was not found by resulting CFind query. " << std::endl; + return 1; + } + + theQuery = gdcm::CompositeNetworkFunctions::ConstructQuery(gdcm::ePatientRootType, gdcm::ePatient, keys, true); + didItWork = gdcm::CompositeNetworkFunctions::CMove(remote.c_str(), portno, theQuery, + moveReturnPort, aetitle.c_str(), call.c_str(), outputDir.c_str() ); + if ( !didItWork ) + { + std::cerr << "CMove failed for file " << *fitor << std::endl; + return 1; + } + delete theQuery; + + + std::cout << "File " << *fitor << " moved back to server." << std::endl; + } + + return 0; +} diff --git a/gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestSCUValidation.cxx b/gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestSCUValidation.cxx new file mode 100644 index 0000000..9f29172 --- /dev/null +++ b/gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestSCUValidation.cxx @@ -0,0 +1,207 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmULConnectionManager.h" +#include "gdcmPresentationContextGenerator.h" +#include "gdcmReader.h" +#include "gdcmAttribute.h" +#include "gdcmDataSet.h" +#include "gdcmUIDGenerator.h" +#include "gdcmStringFilter.h" +#include "gdcmWriter.h" + +#include "gdcmDirectory.h" +#include "gdcmImageReader.h" +#include "gdcmQueryFactory.h" +#include "gdcmGlobal.h" + +const char *AETitle = "ANY"; +const char *PeerAETitle = "ANY"; +const char *ComputerName = "87.106.65.167"; // www.dicomserver.co.uk +int port = 11112; + +gdcm::network::ULConnectionManager *GetConnectionManager(gdcm::BaseRootQuery* theQuery) +{ + gdcm::PresentationContextGenerator generator; + if( !generator.GenerateFromUID( theQuery->GetAbstractSyntaxUID() ) ) + { + gdcmErrorMacro( "Failed to generate pres context." ); + return NULL; + } + + gdcm::network::ULConnectionManager *theManager = + new gdcm::network::ULConnectionManager(); + if (!theManager->EstablishConnection(AETitle, PeerAETitle, ComputerName, 0, + (uint16_t)port, 1000, generator.GetPresentationContexts() )) + { + throw gdcm::Exception("Failed to establish connection."); + } + return theManager; +} + +std::vector GetPatientInfo(bool validateQuery, bool inStrictQuery) +{ + std::vector theDataSets; + gdcm::BaseRootQuery* theQuery = + gdcm::QueryFactory::ProduceQuery(gdcm::ePatientRootType, gdcm::eFind, + gdcm::ePatient); + theQuery->SetSearchParameter(gdcm::Tag(0x8, 0x52), "PATIENT"); //Query/Retrieval Level + theQuery->SetSearchParameter(gdcm::Tag(0x10,0x20), ""); //Patient ID + theQuery->SetSearchParameter(gdcm::Tag(0x10,0x10), "*"); //Patient Name + if(validateQuery && !theQuery->ValidateQuery(inStrictQuery)) + { + return theDataSets; + } + + gdcm::network::ULConnectionManager *theManager = GetConnectionManager( theQuery ); + theDataSets = theManager->SendFind( theQuery ); + return theDataSets; +} + +std::vector GetStudyInfo(const char *patientID, bool validateQuery, bool inStrictQuery) +{ + std::vector theDataSets; + gdcm::BaseRootQuery* theQuery = + gdcm::QueryFactory::ProduceQuery(gdcm::eStudyRootType, gdcm::eFind, gdcm::eStudy); + theQuery->SetSearchParameter(gdcm::Tag(0x8, 0x52), "STUDY"); //Query/Retrieval Level + + theQuery->SetSearchParameter(gdcm::Tag(0x10,0x20), patientID); //Patient ID + theQuery->SetSearchParameter(gdcm::Tag(0x20, 0x10), ""); //Study ID + theQuery->SetSearchParameter(gdcm::Tag(0x20, 0xD), ""); //Study Instance UID + theQuery->SetSearchParameter(gdcm::Tag(0x20, 0xE), ""); //Series Instance UID + if(validateQuery && !theQuery->ValidateQuery(inStrictQuery)) + { + return theDataSets; + } + + gdcm::network::ULConnectionManager *theManager = GetConnectionManager( theQuery ); + theDataSets = theManager->SendFind( theQuery ); + return theDataSets; +} + +std::vector GetSeriesInfo(const char *patientID, const char *studyInstanceUID, bool validateQuery, bool inStrictQuery) +{ + std::vector theDataSets; + gdcm::BaseRootQuery* theQuery = + gdcm::QueryFactory::ProduceQuery(gdcm::eStudyRootType, gdcm::eFind, gdcm::eSeries); + theQuery->SetSearchParameter(gdcm::Tag(0x8, 0x52), "SERIES"); //Query/Retrieval Level + + theQuery->SetSearchParameter(gdcm::Tag(0x10,0x20), patientID); //Patient ID + theQuery->SetSearchParameter(gdcm::Tag(0x20, 0xD), studyInstanceUID); //Study Instance UID + theQuery->SetSearchParameter(gdcm::Tag(0x20, 0xE), ""); //Series Instance UID + if(validateQuery && !theQuery->ValidateQuery(inStrictQuery)) + { + return theDataSets; + } + gdcm::network::ULConnectionManager *theManager = GetConnectionManager( theQuery ); + theDataSets = theManager->SendFind( theQuery ); + return theDataSets; +} + +std::vector GetImageInfo(const char *patientID, + const char *studyInstanceUID, const char *seriesInstanceUID, bool validateQuery, bool inStrictQuery) +{ + std::vector theDataSets; + gdcm::BaseRootQuery* theQuery = + gdcm::QueryFactory::ProduceQuery(gdcm::eStudyRootType, gdcm::eFind, gdcm::eImage); + theQuery->SetSearchParameter(gdcm::Tag(0x8, 0x52), "SERIES"); //Query/Retrieval Level + + theQuery->SetSearchParameter(gdcm::Tag(0x10,0x20), patientID); //Patient ID + theQuery->SetSearchParameter(gdcm::Tag(0x20, 0xD), studyInstanceUID); //Study Instance UID + theQuery->SetSearchParameter(gdcm::Tag(0x20, 0xE), seriesInstanceUID); //Series Instance UID + theQuery->SetSearchParameter(gdcm::Tag(0x8, 0x18), ""); //SOP Instance UID + if(validateQuery && !theQuery->ValidateQuery(inStrictQuery)) + { + return theDataSets; + } + gdcm::network::ULConnectionManager *theManager = GetConnectionManager( theQuery ); + theDataSets = theManager->SendFind( theQuery ); + return theDataSets; +} + +void PrintDataSets(std::vector theDataSets) +{ + std::vector::iterator itor; + for (itor = theDataSets.begin(); itor < theDataSets.end(); itor++) + itor->Print(std::cout); +} + + +int TestSCUValidation(int , char *[]) +{ + //set this to true to use a strict interpretation of the DICOM standard for query validation + bool theUseStrictQueries = false; + + //Case 1: + //Here I want to retrieve Study Information for the known Patient. + //Here i pass the PatientID as a input and i need to reterive the StudyId, + //StudyDate and Series Instance UID. + std::vector theDataSets = GetStudyInfo("Z354998", true, theUseStrictQueries); + PrintDataSets(theDataSets); + //In the above i validated the constructed Query. This will not allow to add the + //Series Instance UID as a search parameter for the query. On the result of + //this i can't get the SeriesInstanceUID from the study level. + + //Case 2: + //Here I execute the above same CFind Query with out validating. + //This will send the Query which is having the SeriesInstanceUID tag + //in search parameter to the CFind. This will executed successfully and + //returns the SeriesInsanceUID related to the given StudyUID. + theDataSets = GetStudyInfo("Z354998", false, theUseStrictQueries); + PrintDataSets(theDataSets); + + //case 3: + //If i validated the Query Like case 1, i cant get the Series Instance UID from + //Study level. With out SeriesInstanceUID i can't retrieve the other series Information. + //In Series Level also i cant add the StudyInstanceUID or other study information + //as a search parameter. It allows only SeriesInstanceUID, Modality and SeriesNumber + //as a search parameter. + theDataSets = GetSeriesInfo("Z354998", + "1.2.826.0.1.3680043.4.1.19990124221049.2", true, theUseStrictQueries); + PrintDataSets(theDataSets); + + //case 4: + //If i execute the above same CFind Query for Get Series with out validating + //the query, it will return the requested SeriesInstanceUID for Known Study level. + theDataSets = GetSeriesInfo("Z354998", + "1.2.826.0.1.3680043.4.1.19990124221049.2", false, theUseStrictQueries); + PrintDataSets(theDataSets); + //In StudyLevel I cant get the Series information(Ref:Case 2). In Series Level + //also i cant get the Series information for the known Study Level(Ref:Case 3). + //How should i get the Series level information for the known patient and study + //level information??? + + //case 5: + //For retrieve the Image Level Information (SOP Instance UID) for the known + //Patient,Study and Series level information, the Image level query is not + //allowing. It allows only SOP Instance UID and SOP Instance Number as a + //search Query. + theDataSets = GetImageInfo("Z354998", + "1.2.826.0.1.3680043.4.1.19990124221049.2", + "1.2.826.0.1.3680043.4.1.19990124221049.3", true, theUseStrictQueries); + PrintDataSets(theDataSets); + + //case 6: + //Image Level retrieval also give the required information with out + //validate the generated Query. + theDataSets = GetImageInfo("Z354998", + "1.2.826.0.1.3680043.4.1.19990124221049.2", + "1.2.826.0.1.3680043.4.1.19990124221049.3", false, theUseStrictQueries); + PrintDataSets(theDataSets); + + //I want the Following things to do in CFind Query. + // 1. Reterive the Study Level Information for the known Patient. + // 2. Reterive the Series Level Information for the known Patient and Study. + // 3. Reterive the Image Level Information for the known Patient, Study and Series. + return 0; +} diff --git a/gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestServiceClassUser1.cxx b/gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestServiceClassUser1.cxx new file mode 100644 index 0000000..b83c2b7 --- /dev/null +++ b/gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestServiceClassUser1.cxx @@ -0,0 +1,320 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmServiceClassUser.h" +#include "gdcmDataEvent.h" +#include "gdcmSimpleSubjectWatcher.h" +#include "gdcmPresentationContextGenerator.h" +#include "gdcmAttribute.h" +#include "gdcmCompositeNetworkFunctions.h" +#include "gdcmTransferSyntax.h" +#include "gdcmWriter.h" + +#include "gdcmTesting.h" + +/* + * This small example show how the association pipeline works. + * the start association is an important step as it will define all the object + * to be send in subsequence C-operation (c-echo, c-store, c-find, c-move). + * In this example we will demonstrate how we can send a JPEG-Lossless object + * and then further on, a non-jpeg encapsulated file + * + * The test also uses the Subject/Observer API for progress report. + */ + +int TestServiceClassUser1(int argc, char *argv[]) +{ + if( argc < 5 ) + { + std::cerr << argv[0] << " aetitle call portno moveReturnPort remote" << std::endl; + return 1; + } + std::string aetitle = argv[1]; // the ae title of this computer + std::string call = argv[2]; // the ae title of the server + uint16_t portno = (uint16_t)atoi(argv[3]); // the port of the server + uint16_t moveReturnPort = (uint16_t)atoi(argv[4]); // the port over which return cstore scps are done for cmove + std::string remote = argv[5]; //the ip address of the remote server + + gdcm::SmartPointer scup = new gdcm::ServiceClassUser; + gdcm::ServiceClassUser &scu = *scup; + gdcm::SimpleSubjectWatcher w( &scu, "TestServiceClassUser1" ); + + scu.SetHostname( remote.c_str() ); + scu.SetPort( portno ); + scu.SetTimeout( 1000 ); + scu.SetCalledAETitle( call.c_str() ); + scu.SetAETitle( aetitle.c_str() ); + + std::ostringstream error_log; + gdcm::Trace::SetErrorStream( error_log ); + + if( !scu.InitializeConnection() ) + { + return 1; + } + + gdcm::PresentationContextGenerator generator; + if( !generator.GenerateFromUID( gdcm::UIDs::VerificationSOPClass ) ) + { + return 1; + } + + // make sure to fail if no pres contexts: + if( scu.StartAssociation() ) + { + return 1; + } + + scu.SetPresentationContexts( generator.GetPresentationContexts() ); + + if( !scu.StartAssociation() ) + { + std::cerr << "Could not StartAssociation" << std::endl; + std::cerr << "Error log is:" << std::endl; + std::cerr << error_log.str() << std::endl; + return 1; + } + + // C-ECHO + if( !scu.SendEcho() ) + { + std::cerr << "Could not Echo" << std::endl; + std::cerr << "Error log is:" << std::endl; + std::cerr << error_log.str() << std::endl; + return 1; + } + + if( !scu.StopAssociation() ) + { + return 1; + } + + gdcm::Directory::FilenamesType filenames; + const char *directory = gdcm::Testing::GetDataRoot(); + // DEBUG: + // storescu -R -xs --call GDCM_STORE macminig4 11112 gdcmData/012345.002.050.dcm + std::string filename = std::string(directory) + "/012345.002.050.dcm"; + filenames.push_back( filename ); + + if( !generator.GenerateFromFilenames(filenames) ) + { + return 1; + } + + scu.SetPresentationContexts( generator.GetPresentationContexts() ); + + if( !scu.StartAssociation() ) + { + return 1; + } + + // C-STORE MRImageStorage/JPEGLossless + if( !scu.SendStore( filename.c_str() ) ) + { + std::cerr << "Could not C-Store" << std::endl; + std::cerr << "Error log is:" << std::endl; + std::cerr << error_log.str() << std::endl; + return 1; + } + + if( !scu.StopAssociation() ) + { + return 1; + } + + //filename = std::string(directory) + "/MR-MONO2-12-an2.acr"; + filename = std::string(directory) + "/MR_Spectroscopy_SIEMENS_OF.dcm"; + filenames.clear(); + filenames.push_back( filename ); + + if( !generator.GenerateFromFilenames(filenames) ) + { + return 1; + } + + scu.SetPresentationContexts( generator.GetPresentationContexts() ); + + if( !scu.StartAssociation() ) + { + return 1; + } + + // C-STORE MRImageStorage/LittleEndianImplicit + if( !scu.SendStore( filename.c_str() ) ) + { + std::cerr << "Could not SendStore" << std::endl; + std::cerr << "Error log is:" << std::endl; + std::cerr << error_log.str() << std::endl; + return 1; + } + + if( !scu.StopAssociation() ) + { + return 1; + } + + // customize the find query + gdcm::DataSet findds; + gdcm::Attribute<0x10,0x10> pn1 ={"ABCDEFGH^IJKLM"}; + findds.Insert( pn1.GetAsDataElement() ); + gdcm::Attribute<0x10,0x20> pid; + findds.Insert( pid.GetAsDataElement() ); + + gdcm::SmartPointer findquery = + gdcm::CompositeNetworkFunctions::ConstructQuery( + gdcm::ePatientRootType, gdcm::ePatient, findds); + + // make sure the query is valid + if (!findquery->ValidateQuery()) + { + return 1; + } + + // Generate the PresentationContext array from the query UID: + if( !generator.GenerateFromUID( findquery->GetAbstractSyntaxUID() ) ) + { + return 1; + } + + scu.SetPresentationContexts( generator.GetPresentationContexts() ); + + if( !scu.StartAssociation() ) + { + return 1; + } + + // C-FIND + std::vector datasets; + if( !scu.SendFind(findquery, datasets) ) + { + return 1; + } + + // Need to make sure we have one dataset + if( datasets.size() != 1 ) + { + std::cerr << "size: " << datasets.size() << std::endl; + return 1; + } + datasets[0].Print( std::cout ); + + // C-find the second patient + gdcm::Attribute<0x10,0x10> pn2 ={"XXXXXXXXXXX"}; + findquery->GetQueryDataSet().Replace( pn2.GetAsDataElement() ); + if( !scu.SendFind(findquery, datasets) ) + { + return 1; + } + + if( datasets.size() != 2 ) + { + std::cerr << "size: " << datasets.size() << std::endl; + return 1; + } + std::cout << std::endl; + + datasets[1].Print( std::cout ); + + if( !scu.StopAssociation() ) + { + return 1; + } + + // C-MOVE + // customize the move query + gdcm::DataSet moveds; + // use results from the c-find to construct the c-move query: + moveds.Insert( datasets[0].GetDataElement( pid.GetTag() ) ); + + gdcm::SmartPointer movequery = + gdcm::CompositeNetworkFunctions::ConstructQuery( + gdcm::ePatientRootType, gdcm::ePatient, moveds, true); + // make sure the query is valid + if (!movequery->ValidateQuery()) + { + return 1; + } + + //generator.SetDefaultTransferSyntax( gdcm::TransferSyntax::JPEGLosslessProcess14_1 ); + + // Generate the PresentationContext array from the query UID: + if( !generator.GenerateFromUID( movequery->GetAbstractSyntaxUID() ) ) + { + return 1; + } + + scu.SetPresentationContexts( generator.GetPresentationContexts() ); + + scu.SetPortSCP( moveReturnPort ); + + if( !scu.StartAssociation() ) + { + return 1; + } + + // C-MOVE + std::vector data; + if( !scu.SendMove(movequery, data) ) + { + return 1; + } + + if( data.size() != 1 ) + { + std::cerr << "data size: " << data.size() << std::endl; + return 1; + } + + // SendMove + dataset is implicit by default: + gdcm::Writer writer; + writer.GetFile().GetHeader().SetDataSetTransferSyntax( + gdcm::TransferSyntax::ImplicitVRLittleEndian ); + writer.GetFile().SetDataSet( data[0] ); + const char *outfilename = "dummy.dcm"; + writer.SetFileName( outfilename ); + if( !writer.Write() ) + { + return 1; + } + + if( !gdcm::System::FileExists(outfilename) ) + { + std::cerr << "FileExists: " << outfilename << std::endl; + return 1; + } + + char digest_str[33]; + if( !gdcm::Testing::ComputeFileMD5(outfilename, digest_str) ) + { + return 1; + } + + if( strcmp( digest_str, "ae1f9a1bfc617f73ae8f72f81777dc03") != 0 ) + { + std::cerr << "md5: " << digest_str << std::endl; + return 1; + } + + // TODO: testing of CMove + JPEG Lossless is a *lot* more difficult + // since we have to assume some behavior on the remote side (SCP) which + // we cannot query. + + if( !scu.StopAssociation() ) + { + return 1; + } + + // scu dstor will close the connection (!= association) + + return 0; +} diff --git a/gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestServiceClassUser2.cxx b/gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestServiceClassUser2.cxx new file mode 100644 index 0000000..8ded5eb --- /dev/null +++ b/gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestServiceClassUser2.cxx @@ -0,0 +1,286 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmServiceClassUser.h" +#include "gdcmDataEvent.h" +#include "gdcmSimpleSubjectWatcher.h" +#include "gdcmPresentationContextGenerator.h" +#include "gdcmAttribute.h" +#include "gdcmCompositeNetworkFunctions.h" +#include "gdcmTransferSyntax.h" +#include "gdcmWriter.h" +#include "gdcmReader.h" +#include "gdcmUIDGenerator.h" + +#include "gdcmTesting.h" + +/* + * This test make sure we can send/receive as many dataset as we want + */ + +int TestServiceClassUser2(int argc, char *argv[]) +{ + if( argc < 5 ) + { + std::cerr << argv[0] << " aetitle call portno moveReturnPort remote" << std::endl; + return 1; + } + std::string aetitle = argv[1]; // the ae title of this computer + std::string call = argv[2]; // the ae title of the server + uint16_t portno = (uint16_t)atoi(argv[3]); // the port of the server + uint16_t moveReturnPort = (uint16_t)atoi(argv[4]); // the port over which return cstore scps are done for cmove + std::string remote = argv[5]; //the ip address of the remote server + + gdcm::SmartPointer scup = new gdcm::ServiceClassUser; + gdcm::ServiceClassUser &scu = *scup; + gdcm::SimpleSubjectWatcher w( &scu, "TestServiceClassUser2" ); + + scu.SetHostname( remote.c_str() ); + scu.SetPort( portno ); + scu.SetTimeout( 1000 ); + scu.SetCalledAETitle( call.c_str() ); + scu.SetAETitle( aetitle.c_str() ); + + std::ostringstream error_log; + gdcm::Trace::SetErrorStream( error_log ); + + if( !scu.InitializeConnection() ) + { + return 1; + } + + gdcm::PresentationContextGenerator generator; + if( !generator.GenerateFromUID( gdcm::UIDs::VerificationSOPClass ) ) + { + return 1; + } + + // make sure to fail if no pres contexts: + if( scu.StartAssociation() ) + { + return 1; + } + + scu.SetPresentationContexts( generator.GetPresentationContexts() ); + + if( !scu.StartAssociation() ) + { + return 1; + } + + // C-ECHO + if( !scu.SendEcho() ) + { + return 1; + } + + if( !scu.StopAssociation() ) + { + return 1; + } + + gdcm::Directory::FilenamesType filenames; + const char *directory = gdcm::Testing::GetDataRoot(); + // storescu -R -xs --call GDCM_STORE macminig4 11112 gdcmData/gdcm-MR-PHILIPS-16-NonSquarePixels.dcm + std::string filename = std::string(directory) + "/gdcm-MR-PHILIPS-16-NonSquarePixels.dcm"; + filenames.push_back( filename ); + + if( !generator.GenerateFromUID( gdcm::UIDs::MRImageStorage ) ) + { + return 1; + } + + scu.SetPresentationContexts( generator.GetPresentationContexts() ); + + if( !scu.StartAssociation() ) + { + return 1; + } + + gdcm::Reader reader; + reader.SetFileName( filename.c_str() ); + if( !reader.Read() ) + { + return 1; + } + + gdcm::File & file = reader.GetFile(); + gdcm::UIDGenerator uid; + const int nmax = 500; + for( int i = 0; i < nmax; ++i ) + { + gdcm::DataSet & ds = file.GetDataSet(); + std::string instance_uid = uid.Generate(); + { + gdcm::Attribute<0x8,0x18> at; + at.SetValue( instance_uid.c_str() ); + ds.Replace( at.GetAsDataElement() ); + } + { + gdcm::Attribute<0x10,0x20> at; + at.SetValue( "TestServiceClassUser2" ); + ds.Replace( at.GetAsDataElement() ); + } + if( !scu.SendStore( file.GetDataSet() ) ) + { + return 1; + } + } + + if( !scu.StopAssociation() ) + { + return 1; + } + + // customize the find query + gdcm::DataSet findds; + gdcm::Attribute<0x10,0x20> pid ={"TestServiceClassUser2"}; + findds.Insert( pid.GetAsDataElement() ); + gdcm::Attribute<0x8,0x18> iuid; + findds.Insert( iuid.GetAsDataElement() ); + + gdcm::SmartPointer findquery = + gdcm::CompositeNetworkFunctions::ConstructQuery( + gdcm::ePatientRootType, gdcm::eImage, findds); + + // make sure the query is valid + if (!findquery->ValidateQuery(false)) + { + return 1; + } + + // Generate the PresentationContext array from the query UID: + if( !generator.GenerateFromUID( findquery->GetAbstractSyntaxUID() ) ) + { + return 1; + } + + scu.SetPresentationContexts( generator.GetPresentationContexts() ); + + if( !scu.StartAssociation() ) + { + return 1; + } + + // C-FIND + // $ findscu --call GDCM_STORE -P macminig4 11112 -k 8,52=IMAGE -k + // 10,20=TestServiceClassUser2 -k 20,d -k 20,e -k 8,18 + // gdcmscu --find --call GDCM_STORE --image --patientroot macminig4 11112 + // -k 10,20=TestServiceClassUser2 -k 8,18 + std::vector datasets; + if( !scu.SendFind(findquery, datasets) ) + { + return 1; + } + + if( !scu.StopAssociation() ) + { + return 1; + } + + // C-MOVE + // customize the move query + gdcm::DataSet moveds1; + // use results from the C-FIND to construct the c-move query: + moveds1.Insert( datasets[0].GetDataElement( gdcm::Tag(0x10,0x20) ) ); + moveds1.Insert( datasets[0].GetDataElement( gdcm::Tag(0x20,0xd) ) ); + moveds1.Insert( datasets[0].GetDataElement( gdcm::Tag(0x20,0xe) ) ); + + gdcm::SmartPointer movequery1 = + gdcm::CompositeNetworkFunctions::ConstructQuery( + gdcm::ePatientRootType, gdcm::eImage, moveds1, true); + + // Generate the PresentationContext array from the query UID: + if( !generator.GenerateFromUID( movequery1->GetAbstractSyntaxUID() ) ) + { + return 1; + } + + scu.SetPresentationContexts( generator.GetPresentationContexts() ); + + scu.SetPortSCP( moveReturnPort ); + + if( !scu.StartAssociation() ) + { + return 1; + } + + size_t ndatasets = 0; + for( + std::vector::const_iterator cfind_it = datasets.begin(); + cfind_it != datasets.end(); ++cfind_it ) + { + gdcm::DataSet &queryds = movequery1->GetQueryDataSet(); + const gdcm::DataElement &instanceuid = cfind_it->GetDataElement( gdcm::Tag(0x8,0x18) ); + queryds.Replace( instanceuid ); + + // C-MOVE + std::vector data; + if( !scu.SendMove(movequery1, data) ) + { + std::cerr << "CMove Failure for: " << instanceuid << std::endl; + std::cerr << "Error log is:" << std::endl; + std::cerr << error_log.str() << std::endl; + return 1; + } + if( data.size() != 1 ) + { + std::cerr << "data size: " << data.size() << std::endl; + return 1; + } + ++ndatasets; + } + + //std::cerr << "Total number of dataset: " << ndatasets << std::endl; + + // Now let's do this again with a simplier request: + gdcm::DataSet moveds2; + moveds2.Insert( pid.GetAsDataElement() ); + gdcm::SmartPointer movequery2 = + gdcm::CompositeNetworkFunctions::ConstructQuery( + gdcm::ePatientRootType, gdcm::ePatient, moveds2, true); + + const char outputdir[] = "TestServiceClassUser2"; + // Make sure output dir exist, it will not be created + if( gdcm::System::FileIsDirectory( outputdir ) ) + { + // cleanups old files: + gdcm::System::DeleteDirectory( outputdir ); + } + gdcm::System::MakeDirectory( outputdir ); + + if( !scu.SendMove(movequery2, outputdir) ) + { + std::cerr << "CMove Failure for Patient ID: " << pid.GetValue() << std::endl; + return 1; + } + + // Compare results: + gdcm::Directory dir; + unsigned int ndatasets2 = dir.Load( outputdir, true ); + + if( ndatasets != ndatasets2 ) + { + std::cerr << "Incompatible number of results: " << ndatasets << " vs " << + ndatasets2 << std::endl; + return 1; + } + + if( !scu.StopAssociation() ) + { + return 1; + } + // scu dstor will close the connection (!= association) + + return 0; +} diff --git a/gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestServiceClassUser3.cxx b/gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestServiceClassUser3.cxx new file mode 100644 index 0000000..6e3101f --- /dev/null +++ b/gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestServiceClassUser3.cxx @@ -0,0 +1,146 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmServiceClassUser.h" +#include "gdcmDataEvent.h" +#include "gdcmSimpleSubjectWatcher.h" +#include "gdcmPresentationContextGenerator.h" +#include "gdcmAttribute.h" +#include "gdcmCompositeNetworkFunctions.h" +#include "gdcmTransferSyntax.h" +#include "gdcmWriter.h" +#include "gdcmReader.h" +#include "gdcmUIDGenerator.h" + +#include "gdcmTesting.h" + +/* + * This test actually fails on D. Clunie PACS, but succeed on DicomObject (www.dicomserver.co.uk)... + * + * $ findscu 184.73.255.26 11112 --call AWSPIXELMEDPUB -P -k 8,52=IMAGE -k 8,16="1.*" -k 20,d + * $ gdcmscu --find 184.73.255.26 11112 --call AWSPIXELMEDPUB --patientroot --image -k 8,16="1.*" -k 20,d + */ + +int TestServiceClassUser3(int argc, char *argv[]) +{ + if( argc < 5 ) + { + std::cerr << argv[0] << " aetitle call portno moveReturnPort remote" << std::endl; + return 1; + } + std::string aetitle = argv[1]; // the ae title of this computer + std::string call = argv[2]; // the ae title of the server + uint16_t portno = (uint16_t)atoi(argv[3]); // the port of the server + uint16_t moveReturnPort = (uint16_t)atoi(argv[4]); // the port over which return cstore scps are done for cmove + std::string remote = argv[5]; //the ip address of the remote server + (void)moveReturnPort; + + gdcm::SmartPointer scup = new gdcm::ServiceClassUser; + gdcm::ServiceClassUser &scu = *scup; + gdcm::SimpleSubjectWatcher w( &scu, "TestServiceClassUser3" ); + + std::ostringstream error_log; + gdcm::Trace::SetErrorStream( error_log ); + + scu.SetHostname( remote.c_str() ); + scu.SetPort( portno ); + scu.SetTimeout( 1000 ); + scu.SetCalledAETitle( call.c_str() ); + scu.SetAETitle( aetitle.c_str() ); + + if( !scu.InitializeConnection() ) + { + return 1; + } + + gdcm::PresentationContextGenerator generator; + if( !generator.GenerateFromUID( gdcm::UIDs::VerificationSOPClass ) ) + { + return 1; + } + + // make sure to fail if no pres contexts: + if( scu.StartAssociation() ) + { + return 1; + } + + scu.SetPresentationContexts( generator.GetPresentationContexts() ); + + if( !scu.StartAssociation() ) + { + return 1; + } + + // C-ECHO + if( !scu.SendEcho() ) + { + return 1; + } + + if( !scu.StopAssociation() ) + { + return 1; + } + + // customize the find query + gdcm::DataSet findds; + gdcm::Attribute<0x8,0x16> sop ={"1.*"}; + findds.Insert( sop.GetAsDataElement() ); + gdcm::Attribute<0x20,0xd> uid; + findds.Insert( uid.GetAsDataElement() ); + + gdcm::SmartPointer findquery = + gdcm::CompositeNetworkFunctions::ConstructQuery( + gdcm::ePatientRootType, gdcm::eImage, findds); + + // make sure the query is valid + findquery->Print( std::cout ); + if (!findquery->ValidateQuery(false)) + { + return 1; + } + + // Generate the PresentationContext array from the query UID: + if( !generator.GenerateFromUID( findquery->GetAbstractSyntaxUID() ) ) + { + return 1; + } + + scu.SetPresentationContexts( generator.GetPresentationContexts() ); + + if( !scu.StartAssociation() ) + { + return 1; + } + + // C-FIND + std::vector datasets; + // This is an error if the previous query succeed: + if( scu.SendFind(findquery, datasets) ) + { + std::cerr << "Could SendFind, this is not possible !" << std::endl; + std::cerr << "Error log is:" << std::endl; + std::cerr << error_log.str() << std::endl; + return 1; + } + + if( !scu.StopAssociation() ) + { + return 1; + } + + // scu dstor will close the connection (!= association) + + return 0; +} diff --git a/gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestULConnectionManager.cxx b/gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestULConnectionManager.cxx new file mode 100644 index 0000000..6e7c663 --- /dev/null +++ b/gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestULConnectionManager.cxx @@ -0,0 +1,24 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#include "gdcmULConnectionManager.h" + +int TestULConnectionManager(int , char *[]) +{ + gdcm::network::ULConnectionManager o; + return 0; +} diff --git a/gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestULTransitionTable.cxx b/gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestULTransitionTable.cxx new file mode 100644 index 0000000..86b5d34 --- /dev/null +++ b/gdcm/Testing/Source/MessageExchangeDefinition/Cxx/TestULTransitionTable.cxx @@ -0,0 +1,30 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmULTransitionTable.h" +#include "gdcmULActionAA.h" + +int TestULTransitionTable(int , char *[]) +{ + gdcm::network::Transition t1; + gdcm::network::Transition *t2 = + gdcm::network::Transition::MakeNew( + gdcm::network::eSta1Idle, + new gdcm::network::ULActionAA2() + ); + gdcm::network::TableRow tr1; + //tr1.transitions[0] = &t1; // no stack please + tr1.transitions[1] = t2; + gdcm::network::ULTransitionTable o; + return 0; +} diff --git a/gdcm/Utilities/C99/CMakeLists.txt b/gdcm/Utilities/C99/CMakeLists.txt new file mode 100644 index 0000000..bab7759 --- /dev/null +++ b/gdcm/Utilities/C99/CMakeLists.txt @@ -0,0 +1,8 @@ +# C99 install rules: +#if(WIN32 AND NOT CYGWIN) + +if(NOT GDCM_INSTALL_NO_DEVELOPMENT) + install(FILES stdint.h + DESTINATION ${GDCM_INSTALL_INCLUDE_DIR} COMPONENT Headers + ) +endif() diff --git a/gdcm/Utilities/C99/COPYING b/gdcm/Utilities/C99/COPYING new file mode 100644 index 0000000..704312b --- /dev/null +++ b/gdcm/Utilities/C99/COPYING @@ -0,0 +1,30 @@ +// ISO C9x compliant stdint.h for Microsoft Visual Studio +// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 +// +// Copyright (c) 2006 Alexander Chemeris +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. The name of the author may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +/////////////////////////////////////////////////////////////////////////////// diff --git a/gdcm/Utilities/C99/README.txt b/gdcm/Utilities/C99/README.txt new file mode 100644 index 0000000..7be9fc2 --- /dev/null +++ b/gdcm/Utilities/C99/README.txt @@ -0,0 +1 @@ +wget http://msinttypes.googlecode.com/svn/trunk/stdint.h diff --git a/gdcm/Utilities/C99/stdint.h b/gdcm/Utilities/C99/stdint.h new file mode 100644 index 0000000..c66fbb8 --- /dev/null +++ b/gdcm/Utilities/C99/stdint.h @@ -0,0 +1,247 @@ +// ISO C9x compliant stdint.h for Microsoft Visual Studio +// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 +// +// Copyright (c) 2006-2008 Alexander Chemeris +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. The name of the author may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _MSC_VER // [ +#error "Use this header only with Microsoft Visual C++ compilers!" +#endif // _MSC_VER ] + +#ifndef _MSC_STDINT_H_ // [ +#define _MSC_STDINT_H_ + +#if _MSC_VER > 1000 +#pragma once +#endif + +#include + +// For Visual Studio 6 in C++ mode and for many Visual Studio versions when +// compiling for ARM we should wrap include with 'extern "C++" {}' +// or compiler give many errors like this: +// error C2733: second C linkage of overloaded function 'wmemchr' not allowed +#ifdef __cplusplus +extern "C" { +#endif +# include +#ifdef __cplusplus +} +#endif + +// Define _W64 macros to mark types changing their size, like intptr_t. +#ifndef _W64 +# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 +# define _W64 __w64 +# else +# define _W64 +# endif +#endif + + +// 7.18.1 Integer types + +// 7.18.1.1 Exact-width integer types + +// Visual Studio 6 and Embedded Visual C++ 4 doesn't +// realize that, e.g. char has the same size as __int8 +// so we give up on __intX for them. +#if (_MSC_VER < 1300) + typedef signed char int8_t; + typedef signed short int16_t; + typedef signed int int32_t; + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + typedef unsigned int uint32_t; +#else + typedef signed __int8 int8_t; + typedef signed __int16 int16_t; + typedef signed __int32 int32_t; + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; +#endif +typedef signed __int64 int64_t; +typedef unsigned __int64 uint64_t; + + +// 7.18.1.2 Minimum-width integer types +typedef int8_t int_least8_t; +typedef int16_t int_least16_t; +typedef int32_t int_least32_t; +typedef int64_t int_least64_t; +typedef uint8_t uint_least8_t; +typedef uint16_t uint_least16_t; +typedef uint32_t uint_least32_t; +typedef uint64_t uint_least64_t; + +// 7.18.1.3 Fastest minimum-width integer types +typedef int8_t int_fast8_t; +typedef int16_t int_fast16_t; +typedef int32_t int_fast32_t; +typedef int64_t int_fast64_t; +typedef uint8_t uint_fast8_t; +typedef uint16_t uint_fast16_t; +typedef uint32_t uint_fast32_t; +typedef uint64_t uint_fast64_t; + +// 7.18.1.4 Integer types capable of holding object pointers +#ifdef _WIN64 // [ + typedef signed __int64 intptr_t; + typedef unsigned __int64 uintptr_t; +#else // _WIN64 ][ + typedef _W64 signed int intptr_t; + typedef _W64 unsigned int uintptr_t; +#endif // _WIN64 ] + +// 7.18.1.5 Greatest-width integer types +typedef int64_t intmax_t; +typedef uint64_t uintmax_t; + + +// 7.18.2 Limits of specified-width integer types + +#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 + +// 7.18.2.1 Limits of exact-width integer types +#define INT8_MIN ((int8_t)_I8_MIN) +#define INT8_MAX _I8_MAX +#define INT16_MIN ((int16_t)_I16_MIN) +#define INT16_MAX _I16_MAX +#define INT32_MIN ((int32_t)_I32_MIN) +#define INT32_MAX _I32_MAX +#define INT64_MIN ((int64_t)_I64_MIN) +#define INT64_MAX _I64_MAX +#define UINT8_MAX _UI8_MAX +#define UINT16_MAX _UI16_MAX +#define UINT32_MAX _UI32_MAX +#define UINT64_MAX _UI64_MAX + +// 7.18.2.2 Limits of minimum-width integer types +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST8_MAX INT8_MAX +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST16_MAX INT16_MAX +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST32_MAX INT32_MAX +#define INT_LEAST64_MIN INT64_MIN +#define INT_LEAST64_MAX INT64_MAX +#define UINT_LEAST8_MAX UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define UINT_LEAST64_MAX UINT64_MAX + +// 7.18.2.3 Limits of fastest minimum-width integer types +#define INT_FAST8_MIN INT8_MIN +#define INT_FAST8_MAX INT8_MAX +#define INT_FAST16_MIN INT16_MIN +#define INT_FAST16_MAX INT16_MAX +#define INT_FAST32_MIN INT32_MIN +#define INT_FAST32_MAX INT32_MAX +#define INT_FAST64_MIN INT64_MIN +#define INT_FAST64_MAX INT64_MAX +#define UINT_FAST8_MAX UINT8_MAX +#define UINT_FAST16_MAX UINT16_MAX +#define UINT_FAST32_MAX UINT32_MAX +#define UINT_FAST64_MAX UINT64_MAX + +// 7.18.2.4 Limits of integer types capable of holding object pointers +#ifdef _WIN64 // [ +# define INTPTR_MIN INT64_MIN +# define INTPTR_MAX INT64_MAX +# define UINTPTR_MAX UINT64_MAX +#else // _WIN64 ][ +# define INTPTR_MIN INT32_MIN +# define INTPTR_MAX INT32_MAX +# define UINTPTR_MAX UINT32_MAX +#endif // _WIN64 ] + +// 7.18.2.5 Limits of greatest-width integer types +#define INTMAX_MIN INT64_MIN +#define INTMAX_MAX INT64_MAX +#define UINTMAX_MAX UINT64_MAX + +// 7.18.3 Limits of other integer types + +#ifdef _WIN64 // [ +# define PTRDIFF_MIN _I64_MIN +# define PTRDIFF_MAX _I64_MAX +#else // _WIN64 ][ +# define PTRDIFF_MIN _I32_MIN +# define PTRDIFF_MAX _I32_MAX +#endif // _WIN64 ] + +#define SIG_ATOMIC_MIN INT_MIN +#define SIG_ATOMIC_MAX INT_MAX + +#ifndef SIZE_MAX // [ +# ifdef _WIN64 // [ +# define SIZE_MAX _UI64_MAX +# else // _WIN64 ][ +# define SIZE_MAX _UI32_MAX +# endif // _WIN64 ] +#endif // SIZE_MAX ] + +// WCHAR_MIN and WCHAR_MAX are also defined in +#ifndef WCHAR_MIN // [ +# define WCHAR_MIN 0 +#endif // WCHAR_MIN ] +#ifndef WCHAR_MAX // [ +# define WCHAR_MAX _UI16_MAX +#endif // WCHAR_MAX ] + +#define WINT_MIN 0 +#define WINT_MAX _UI16_MAX + +#endif // __STDC_LIMIT_MACROS ] + + +// 7.18.4 Limits of other integer types + +#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 + +// 7.18.4.1 Macros for minimum-width integer constants + +#define INT8_C(val) val##i8 +#define INT16_C(val) val##i16 +#define INT32_C(val) val##i32 +#define INT64_C(val) val##i64 + +#define UINT8_C(val) val##ui8 +#define UINT16_C(val) val##ui16 +#define UINT32_C(val) val##ui32 +#define UINT64_C(val) val##ui64 + +// 7.18.4.2 Macros for greatest-width integer constants +#define INTMAX_C INT64_C +#define UINTMAX_C UINT64_C + +#endif // __STDC_CONSTANT_MACROS ] + + +#endif // _MSC_STDINT_H_ ] diff --git a/gdcm/Utilities/CMakeLists.txt b/gdcm/Utilities/CMakeLists.txt new file mode 100644 index 0000000..2b7b083 --- /dev/null +++ b/gdcm/Utilities/CMakeLists.txt @@ -0,0 +1,143 @@ +# Wrapping and stuff + +# Do jpeg (8,12, 16 lossly lossless). From ijg +APPEND_COPYRIGHT(${CMAKE_CURRENT_SOURCE_DIR}/gdcmjpeg/COPYRIGHT.dcmtk) +if(NOT GDCM_USE_SYSTEM_LJPEG) + set(JPEG_NAMESPACE "GDCMJPEG") + set(JPEG_INSTALL_NO_LIBRARIES ${GDCM_INSTALL_NO_LIBRARIES}) + set(JPEG_INSTALL_BIN_DIR ${GDCM_INSTALL_BIN_DIR}) + set(JPEG_INSTALL_LIB_DIR ${GDCM_INSTALL_LIB_DIR}) + set(JPEG_INSTALL_INCLUDE_DIR ${GDCM_INSTALL_INCLUDE_DIR}/gdcmjpeg) + subdirs(gdcmjpeg) +endif() + +# Do expat +APPEND_COPYRIGHT(${CMAKE_CURRENT_SOURCE_DIR}/gdcmexpat/COPYING) +if(NOT GDCM_USE_SYSTEM_EXPAT) + set(EXPAT_NAMESPACE "GDCMEXPAT") + set(EXPAT_INSTALL_NO_LIBRARIES ${GDCM_INSTALL_NO_LIBRARIES}) + set(EXPAT_INSTALL_BIN_DIR ${GDCM_INSTALL_BIN_DIR}) + set(EXPAT_INSTALL_LIB_DIR ${GDCM_INSTALL_LIB_DIR}) + subdirs(gdcmexpat) +endif() + +# Do openjpeg (jpeg2000 implementation) +if(GDCM_USE_OPENJPEG_V2) + APPEND_COPYRIGHT(${CMAKE_CURRENT_SOURCE_DIR}/gdcmopenjpeg-v2/license.txt) +else() + APPEND_COPYRIGHT(${CMAKE_CURRENT_SOURCE_DIR}/gdcmopenjpeg-v1/LICENSE) +endif() +if(NOT GDCM_USE_SYSTEM_OPENJPEG) + set(OPENJPEG_NAMESPACE "GDCMOPENJPEG") + set(OPENJPEG_INSTALL_NO_LIBRARIES ${GDCM_INSTALL_NO_LIBRARIES}) + set(OPENJPEG_INSTALL_BIN_DIR ${GDCM_INSTALL_BIN_DIR}) + set(OPENJPEG_INSTALL_LIB_DIR ${GDCM_INSTALL_LIB_DIR}) + set(OPENJPEG_INSTALL_INCLUDE_DIR ${GDCM_INSTALL_INCLUDE_DIR}/gdcmopenjpeg) + if(GDCM_USE_OPENJPEG_V2) + subdirs(gdcmopenjpeg-v2) + else() + subdirs(gdcmopenjpeg-v1) + endif() +endif() + +# Do jpegls (JPEG-LS aka near lossless implementation) +APPEND_COPYRIGHT(${CMAKE_CURRENT_SOURCE_DIR}/gdcmcharls/License.txt) +if(GDCM_USE_JPEGLS) +if(NOT GDCM_USE_SYSTEM_CHARLS) + set(CHARLS_NAMESPACE "GDCMCHARLS") + set(CHARLS_INSTALL_NO_LIBRARIES ${GDCM_INSTALL_NO_LIBRARIES}) + set(CHARLS_INSTALL_BIN_DIR ${GDCM_INSTALL_BIN_DIR}) + set(CHARLS_INSTALL_LIB_DIR ${GDCM_INSTALL_LIB_DIR}) + set(CHARLS_INSTALL_INCLUDE_DIR ${GDCM_INSTALL_INCLUDE_DIR}/gdcmcharls) + subdirs(gdcmcharls) +endif() +endif() + +# Do md5 +APPEND_COPYRIGHT(${CMAKE_CURRENT_SOURCE_DIR}/gdcmmd5/COPYING) +if(GDCM_BUILD_TESTING) +if(NOT GDCM_USE_SYSTEM_MD5) + set(MD5_NAMESPACE "GDCMMD5") + set(MD5_INSTALL_NO_LIBRARIES ${GDCM_INSTALL_NO_LIBRARIES}) + set(MD5_INSTALL_BIN_DIR ${GDCM_INSTALL_BIN_DIR}) + set(MD5_INSTALL_LIB_DIR ${GDCM_INSTALL_LIB_DIR}) + subdirs(gdcmmd5) +endif() +endif() + +# Do zlib +APPEND_COPYRIGHT(${CMAKE_CURRENT_SOURCE_DIR}/gdcmzlib/COPYING) +if(NOT GDCM_USE_SYSTEM_ZLIB) + set(ZLIB_NAMESPACE "GDCMZLIB") + set(ZLIB_INSTALL_NO_LIBRARIES ${GDCM_INSTALL_NO_LIBRARIES}) + set(ZLIB_INSTALL_BIN_DIR ${GDCM_INSTALL_BIN_DIR}) + set(ZLIB_INSTALL_LIB_DIR ${GDCM_INSTALL_LIB_DIR}) + subdirs(gdcmzlib) +endif() + +# Do getopt +APPEND_COPYRIGHT(${CMAKE_CURRENT_SOURCE_DIR}/getopt/COPYING) +if(WIN32 AND NOT CYGWIN) + set(GETOPT_NAMESPACE "GDCMGETOPT") + set(GETOPT_INSTALL_NO_LIBRARIES ${GDCM_INSTALL_NO_LIBRARIES}) + set(GETOPT_INSTALL_BIN_DIR ${GDCM_INSTALL_BIN_DIR}) + set(GETOPT_INSTALL_LIB_DIR ${GDCM_INSTALL_LIB_DIR}) + subdirs(getopt) +endif() + +subdirs(doxygen) + +# you could be running mingw32 on linux in which case you do NOT want the gdcmuuid lib +APPEND_COPYRIGHT(${CMAKE_CURRENT_SOURCE_DIR}/gdcmuuid/COPYING) +if(NOT WIN32 AND NOT MINGW) + if(NOT GDCM_USE_SYSTEM_UUID) + set(UUID_NAMESPACE "GDCMUUID") + set(UUID_INSTALL_NO_LIBRARIES ${GDCM_INSTALL_NO_LIBRARIES}) + set(UUID_INSTALL_BIN_DIR ${GDCM_INSTALL_BIN_DIR}) + set(UUID_INSTALL_LIB_DIR ${GDCM_INSTALL_LIB_DIR}) + subdirs(gdcmuuid) + endif() +endif() + +APPEND_COPYRIGHT(${CMAKE_CURRENT_SOURCE_DIR}/pvrg/COPYING) +if(GDCM_USE_PVRG) + if(NOT GDCM_USE_SYSTEM_PVRG) + subdirs(pvrg) + endif() +endif() + +if(GDCM_USE_RLE) + subdirs(rle) +endif() + +# Do C99 +APPEND_COPYRIGHT(${CMAKE_CURRENT_SOURCE_DIR}/C99/COPYING) + +# Do wxVTK +APPEND_COPYRIGHT(${CMAKE_CURRENT_SOURCE_DIR}/wxWidgets/Copyright.txt) + +#if(NOT GDCM_INSTALL_NO_DEVELOPMENT) +## file(GLOB header_files "*.h" "*.txx") +# install(FILES +##${header_files} +#gdcm_expat.h +##gdcm_md5.h # In an install tree there should not be the need for the md5 lib... +#gdcm_openjpeg.h +#gdcm_uuid.h +#gdcm_zlib.h +# DESTINATION ${GDCM_INSTALL_INCLUDE_DIR} COMPONENT Headers +# ) +#endif() + +#if(GDCM_USE_KWSTYLE) + subdirs(KWStyle) +#endif() + +if(NOT GDCM_USE_SYSTEM_SOCKETXX) +#set(SOCKETXX_NAMESPACE "GDCMSOCKETXX") + set(SOCKETXX_INSTALL_NO_LIBRARIES ${GDCM_INSTALL_NO_LIBRARIES}) + set(SOCKETXX_INSTALL_BIN_DIR ${GDCM_INSTALL_BIN_DIR}) + set(SOCKETXX_INSTALL_LIB_DIR ${GDCM_INSTALL_LIB_DIR}) + set(SOCKETXX_INSTALL_INCLUDE_DIR ${GDCM_INSTALL_INCLUDE_DIR}/socketxx) + subdirs(socketxx) +endif() diff --git a/gdcm/Utilities/KWStyle/CMakeLists.txt b/gdcm/Utilities/KWStyle/CMakeLists.txt new file mode 100644 index 0000000..228d500 --- /dev/null +++ b/gdcm/Utilities/KWStyle/CMakeLists.txt @@ -0,0 +1,31 @@ +#----------------------------------------------------------------------------- +# GDCM uses KWStyle for checking the coding style +option(GDCM_USE_KWSTYLE "Run KWStyle in order to check for violations of the coding standard." OFF) +mark_as_advanced(GDCM_USE_KWSTYLE) + +if(GDCM_USE_KWSTYLE) + find_package(KWStyle) + + configure_file(${GDCM_SOURCE_DIR}/Utilities/KWStyle/GDCM.kws.xml.in + ${GDCM_BINARY_DIR}/Utilities/KWStyle/GDCM.kws.xml) + #configure_file(${GDCM_SOURCE_DIR}/Utilities/KWStyle/GDCMMoreChecks.kws.xml.in + # ${GDCM_BINARY_DIR}/GDCMMoreChecks.kws.xml) + + configure_file(${GDCM_SOURCE_DIR}/Utilities/KWStyle/GDCMFiles.txt.in + ${GDCM_BINARY_DIR}/Utilities/KWStyle/GDCMFiles.txt) + + add_custom_command( + OUTPUT ${GDCM_BINARY_DIR}/KWStyleReport.txt + COMMAND ${KWSTYLE_EXECUTABLE} + ARGS -xml ${GDCM_BINARY_DIR}/Utilities/KWStyle/GDCM.kws.xml -o ${GDCM_SOURCE_DIR}/Utilities/KWStyle/GDCMOverwrite.txt -v ${KWSTYLE_ARGUMENTS} -D ${GDCM_BINARY_DIR}/Utilities/KWStyle/GDCMFiles.txt + COMMENT "Coding Style Checker" + ) + + #add_custom_target(MoreStyleChecks + # COMMAND ${KWSTYLE_EXECUTABLE} + # -xml ${GDCM_BINARY_DIR}/GDCMMoreChecks.kws.xml -html ${GDCM_BINARY_DIR}/html -o ${GDCM_SOURCE_DIR}/Utilities/KWStyle/GDCMOverwrite.txt -v ${KWSTYLE_ARGUMENTS} -D ${GDCM_BINARY_DIR}/GDCMKWSFiles.txt + # COMMENT "Coding Style Checker, more checks enabled" + # ) + + add_custom_target(StyleCheck DEPENDS ${GDCM_BINARY_DIR}/KWStyleReport.txt) +endif() diff --git a/gdcm/Utilities/KWStyle/GDCM.kws.xml.in b/gdcm/Utilities/KWStyle/GDCM.kws.xml.in new file mode 100644 index 0000000..139cc31 --- /dev/null +++ b/gdcm/Utilities/KWStyle/GDCM.kws.xml.in @@ -0,0 +1,11 @@ + + +81 + + diff --git a/gdcm/Utilities/KWStyle/GDCMFiles.txt.in b/gdcm/Utilities/KWStyle/GDCMFiles.txt.in new file mode 100644 index 0000000..4d500d5 --- /dev/null +++ b/gdcm/Utilities/KWStyle/GDCMFiles.txt.in @@ -0,0 +1,11 @@ +"@GDCM_SOURCE_DIR@/Source/Common/*.h" +"@GDCM_SOURCE_DIR@/Source/Common/*.cxx" +"@GDCM_SOURCE_DIR@/Source/Common/*.txx" +"@GDCM_SOURCE_DIR@/Source/DataDictionary/*.h" +"@GDCM_SOURCE_DIR@/Source/DataDictionary/*.cxx" +"@GDCM_SOURCE_DIR@/Source/DataStructureAndEncodingDefinition/*.h" +"@GDCM_SOURCE_DIR@/Source/DataStructureAndEncodingDefinition/*.cxx" +"@GDCM_SOURCE_DIR@/Source/InformationObjectDefinition/*.h" +"@GDCM_SOURCE_DIR@/Source/InformationObjectDefinition/*.cxx" +"@GDCM_SOURCE_DIR@/Source/MediaStorageAndFileFormat/*.h" +"@GDCM_SOURCE_DIR@/Source/MediaStorageAndFileFormat/*.cxx" diff --git a/gdcm/Utilities/KWStyle/GDCMHeader.h b/gdcm/Utilities/KWStyle/GDCMHeader.h new file mode 100644 index 0000000..951c92e --- /dev/null +++ b/gdcm/Utilities/KWStyle/GDCMHeader.h @@ -0,0 +1,13 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ diff --git a/gdcm/Utilities/KWStyle/GDCMOverwrite.txt b/gdcm/Utilities/KWStyle/GDCMOverwrite.txt new file mode 100644 index 0000000..c384656 --- /dev/null +++ b/gdcm/Utilities/KWStyle/GDCMOverwrite.txt @@ -0,0 +1 @@ +zipstreamimpl.hpp Header Disable diff --git a/gdcm/Utilities/Release/README.txt b/gdcm/Utilities/Release/README.txt new file mode 100644 index 0000000..b93a777 --- /dev/null +++ b/gdcm/Utilities/Release/README.txt @@ -0,0 +1,4 @@ +1. For now need to make sure docstrings.i is up to date +2. Run release.sh +3. Run release.bat +4. Done ! diff --git a/gdcm/Utilities/Release/bootstrap.sh b/gdcm/Utilities/Release/bootstrap.sh new file mode 100644 index 0000000..1de33ae --- /dev/null +++ b/gdcm/Utilities/Release/bootstrap.sh @@ -0,0 +1,75 @@ +#!/bin/sh + +rm -rf $HOME/.wine + +SETUPVS=no + +if [ "$SETUPVS" = "yes"]; then +# install gecko stuff: +winetricks apps list +# install VS 2005 +# see http://bugs.winehq.org/show_bug.cgi?id=31052 for reason option no-isolate: +winetricks --no-isolate vc2005express +#export WINEPREFIX=$HOME/.local/share/wineprefixes/vc2005express +# required see: http://bugs.winehq.org/show_bug.cgi?id=20110#c8 +#winetricks vcrun2005 + +mkdir -p $HOME/.cache/winetricks/junk +cd $HOME/.cache/winetricks/junk + +# install VS 2005/SP1 +# see why: https://code.google.com/p/winetricks/issues/detail?id=18 +wget -c http://download.microsoft.com/download/7/7/3/7737290f-98e8-45bf-9075-85cc6ae34bf1/VS80sp1-KB926748-X86-INTL.exe +# now instal SP1 +#wine VS80sp1-KB926748-X86-INTL.exe +fi + +SETUP3RD=no +if [ "$SETUP3RD" = "yes"]; then +wget -c http://msysgit.googlecode.com/files/Git-1.7.11-preview20120620.exe +wget -c http://www.cmake.org/files/v2.8/cmake-2.8.8-win32-x86.exe +wget -c http://prdownloads.sourceforge.net/swig/swigwin-2.0.7.zip +wget -c http://slproweb.com/download/Win32OpenSSL-1_0_1c.exe +#wget "http://download.oracle.com/otn-pub/java/jdk/6u25-b06/jdk-6u25-windows-i586.exe?AuthParam=1340870089_b98e26f4e28100ecbb9c7ca9d3c3353f" +# have to manually download it at: +# http://www.oracle.com/technetwork/java/javase/downloads/jdk6-downloads-1637591.html +wget -c http://www.python.org/ftp/python/2.7.3/python-2.7.3.msi + +# install ! + +wine cmake-2.8.8-win32-x86.exe +wine Git-1.7.11-preview20120620.exe +msiexec /i python-2.7.3.msi +# dont ask: +#winetricks vcrun2005 +# call twice in case of failure: +#wine VS80sp1-KB926748-X86-INTL.exe +wine Win32OpenSSL-1_0_1c.exe +wine jdk-6u33-windows-i586.exe + +mkdir "$HOME/.wine/drive_c/Program Files/Swig" +unzip -d "$HOME/.wine/drive_c/Program Files/Swig" swigwin-2.0.7.zip +fi + +# You will need wine 1.5.7 otherwise you get: + +# Unhandled exception: unimplemented function msvcp90.dll.??0?$basic_ifstream@DU?$char_traits@D@std@@@std@@QAE@PBDHH@Z called in 32-bit code (0x7b83bbb2). +# -> http://bugs.winehq.org/show_bug.cgi?id=28228#c15 + +# you should then be stuck on: +# Unhandled exception: unimplemented function msvcp90.dll.??0?$basic_ostringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@H@Z called in 32-bit code (0x7b83bcb2). +# See: http://bugs.winehq.org/show_bug.cgi?id=26832 + +#winetricks vcrun2008 +#winetricks --no-isolate psdk2003 + +# impossible to install SDK Win7: +#winetricks --no-isolate psdkwin7 + +# local vs2008express installation: +cd $HOME/.cache/winetricks/vc2008express +wget -c http://download.microsoft.com/download/e/8/e/e8eeb394-7f42-4963-a2d8-29559b738298/VS2008ExpressWithSP1ENUX1504728.iso +7z x VS2008ExpressWithSP1ENUX1504728.iso +# http://appdb.winehq.org/objectManager.php?sClass=version&iId=11210 +winetricks dotnet35 +wine VCExpress/autorun.exe diff --git a/gdcm/Utilities/Release/config.linux b/gdcm/Utilities/Release/config.linux new file mode 100644 index 0000000..5113e3f --- /dev/null +++ b/gdcm/Utilities/Release/config.linux @@ -0,0 +1,20 @@ +CMAKE_BUILD_TYPE:STRING=Release +GDCM_BUILD_APPLICATIONS:BOOL=ON +GDCM_BUILD_EXAMPLES:BOOL=OFF +GDCM_BUILD_SHARED_LIBS:BOOL=ON +GDCM_BUILD_TESTING:BOOL=OFF +GDCM_DOCUMENTATION:BOOL=ON +GDCM_PDF_DOCUMENTATION:BOOL=ON +GDCM_USE_VTK:BOOL=OFF +GDCM_USE_JPEGLS:BOOL=ON +GDCM_USE_PVRG:BOOL=ON +GDCM_USE_SYSTEM_OPENJPEG:BOOL=OFF +GDCM_USE_SYSTEM_OPENSSL:BOOL=OFF +GDCM_USE_SYSTEM_EXPAT:BOOL=OFF +GDCM_USE_SYSTEM_POPPLER:BOOL=OFF +GDCM_USE_SYSTEM_UUID:BOOL=OFF +GDCM_USE_SYSTEM_ZLIB:BOOL=OFF +GDCM_WRAP_CSHARP:BOOL=ON +GDCM_WRAP_JAVA:BOOL=ON +GDCM_WRAP_PYTHON:BOOL=ON +CPACK_SOURCE_ZIP:BOOL=OFF diff --git a/gdcm/Utilities/Release/config.win32 b/gdcm/Utilities/Release/config.win32 new file mode 100644 index 0000000..557b530 --- /dev/null +++ b/gdcm/Utilities/Release/config.win32 @@ -0,0 +1,20 @@ +CMAKE_BUILD_TYPE:STRING=Release +GDCM_BUILD_APPLICATIONS:BOOL=ON +GDCM_BUILD_EXAMPLES:BOOL=OFF +GDCM_BUILD_SHARED_LIBS:BOOL=ON +GDCM_BUILD_TESTING:BOOL=OFF +GDCM_DOCUMENTATION:BOOL=OFF +GDCM_PDF_DOCUMENTATION:BOOL=OFF +GDCM_USE_VTK:BOOL=OFF +GDCM_USE_JPEGLS:BOOL=ON +GDCM_USE_PVRG:BOOL=OFF +GDCM_USE_SYSTEM_OPENJPEG:BOOL=OFF +GDCM_USE_SYSTEM_OPENSSL:BOOL=ON +GDCM_USE_SYSTEM_EXPAT:BOOL=OFF +GDCM_USE_SYSTEM_POPPLER:BOOL=OFF +#GDCM_USE_SYSTEM_UUID:BOOL=ON +GDCM_USE_SYSTEM_ZLIB:BOOL=OFF +GDCM_WRAP_CSHARP:BOOL=ON +GDCM_WRAP_JAVA:BOOL=ON +GDCM_WRAP_PYTHON:BOOL=ON +CPACK_SOURCE_ZIP:BOOL=ON diff --git a/gdcm/Utilities/Release/makerelease.sh b/gdcm/Utilities/Release/makerelease.sh new file mode 100644 index 0000000..47f4fc0 --- /dev/null +++ b/gdcm/Utilities/Release/makerelease.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +# http://www.winehq.org/docs/winedev-guide/dbg-control +WINEDEBUG=-all wineconsole --backend=curses cmd /c release.bat diff --git a/gdcm/Utilities/Release/release.bat b/gdcm/Utilities/Release/release.bat new file mode 100644 index 0000000..691048d --- /dev/null +++ b/gdcm/Utilities/Release/release.bat @@ -0,0 +1,73 @@ +@rem +@rem Program: GDCM (Grassroots DICOM). A DICOM library +@rem +@rem Copyright (c) 2006-2011 Mathieu Malaterre +@rem All rights reserved. +@rem See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +@rem +@rem This software is distributed WITHOUT ANY WARRANTY; without even +@rem the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +@rem PURPOSE. See the above copyright notice for more information. +@rem + +@rem generate GDCM release on Windows + +@rem get tmpdir: +set TMPDIR=%TMP%\gdcm_release + +set major=2 +set minor=2 +set patch=5 +set version="%major%.%minor%.%patch%" + +@rem use VCExpress 2008 for compatibilities with OpenSSL binaries +call "%VS90COMNTOOLS%vsvars32.bat" + +@rem User32.lib and al. +SET LIB=C:\Program Files\Microsoft SDKs\Windows\v6.0A\Lib;%LIB% +SET INCLUDE=C:\Program Files\Microsoft SDKs\Windows\v6.0A\Include;%INCLUDE% + +@rem GDCM deps: + +@rem IF "%ProgramFiles(x86)%"=="" ( +SET PATH=%PATH%;%ProgramFiles%\Git\bin +SET PATH=%PATH%;%ProgramFiles%\Swig\swigwin-2.0.7 +SET PATH=%PATH%;%ProgramFiles%\Java\jdk1.6.0_25\bin +@rem ) ELSE ( +@rem SET PATH=%PATH%;%ProgramFiles(x86)%\Git\bin +@rem SET PATH=%PATH%;%ProgramFiles(x86)%\Swig\swigwin-2.0.8 +@rem SET PATH=%PATH%;%ProgramFiles(x86)%\Java\jdk1.6.0_34\bin +@rem ) +ECHO %PATH% +PAUSE +@rem needed to get RC.EXE: +SET PATH=C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin;%PATH% + +@rem prepare target dir +mkdir %TMPDIR% +mkdir %TMPDIR%\gdcm-build + +copy config.win32 %TMPDIR%\gdcm-build\CMakeCache.txt + +c: +cd %TMPDIR% +@rem git is itselft a batch: +call git clone --branch release git://git.code.sf.net/p/gdcm/gdcm > git.log 2>&1 +cd gdcm +call git checkout "v%version%" +cd .. + +cd %TMPDIR%\gdcm-build +cmake -G "NMake Makefiles" ..\gdcm > config.log 2>&1 + +@rem build gdcm +nmake > nmake.log 2>&1 + +@rem create NSIS installer +cpack -G NSIS > nsis.log 2>&1 + +@rem create binary zip +cpack -G ZIP > zip.log 2>&1 + +@rem create source zip +cpack -G ZIP --config CPackSourceConfig.cmake szip.log 2>&1 diff --git a/gdcm/Utilities/Release/release.sh b/gdcm/Utilities/Release/release.sh new file mode 100644 index 0000000..dc0aa2b --- /dev/null +++ b/gdcm/Utilities/Release/release.sh @@ -0,0 +1,148 @@ +#!/bin/sh +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +echo "Start release" +date +echo "" + +major=2 +minor=2 +patch=5 +version="$major.$minor.$patch" +version2="$major-$minor-$patch" + +basedir="/tmp/gdcm_release" + +check_exit_value() +{ + VALUE="$1" + if [ "$VALUE" != "0" ]; then + echo "error in $2" + exit 1 + fi +} + +if [ ! -d $basedir ]; then + mkdir $basedir +else + echo "$basedir already exist" + echo "$basedir/gdcm already exist, cleaning it up:" + rm -rf $basedir/gdcm +fi + +echo "Checking out gdcm" +git clone --branch release git://git.code.sf.net/p/gdcm/gdcm $basedir/gdcm +check_exit_value $? "git did not return properly" || exit 1 + +# Get the specific tag +# There is no way apparently to directly clone and checkout a tag; you can do +# that only for branch name +cd $basedir/gdcm +git checkout "v$version" +check_exit_value $? "git checkout did not return properly" || exit 1 + +if [ ! -d $basedir/gdcm-build ]; then + mkdir $basedir/gdcm-build +else + echo "$basedir/gdcm-build already exist, cleaning it up:" + rm -rf $basedir/gdcm-build + mkdir $basedir/gdcm-build +fi + +cd $basedir/gdcm-build + +# debian default: +export JAVA_HOME=/usr/lib/jvm/default-java + +cat > $basedir/gdcm-build/CMakeCache.txt << EOT +CMAKE_BUILD_TYPE:STRING=Release +GDCM_BUILD_APPLICATIONS:BOOL=ON +GDCM_BUILD_EXAMPLES:BOOL=OFF +GDCM_BUILD_SHARED_LIBS:BOOL=ON +GDCM_BUILD_TESTING:BOOL=OFF +GDCM_DOCUMENTATION:BOOL=ON +GDCM_PDF_DOCUMENTATION:BOOL=ON +GDCM_USE_VTK:BOOL=OFF +GDCM_USE_JPEGLS:BOOL=ON +GDCM_USE_PVRG:BOOL=ON +GDCM_USE_SYSTEM_OPENJPEG:BOOL=OFF +GDCM_USE_SYSTEM_OPENSSL:BOOL=OFF +GDCM_USE_SYSTEM_EXPAT:BOOL=OFF +GDCM_USE_SYSTEM_POPPLER:BOOL=OFF +GDCM_USE_SYSTEM_UUID:BOOL=OFF +GDCM_USE_SYSTEM_ZLIB:BOOL=OFF +GDCM_WRAP_CSHARP:BOOL=ON +GDCM_WRAP_JAVA:BOOL=ON +GDCM_WRAP_PYTHON:BOOL=ON +CPACK_SOURCE_ZIP:BOOL=ON +EOT + +cmake $basedir/gdcm +#cmake $basedir/gdcm -DCMAKE_TOOLCHAIN_FILE=$basedir/gdcm/CMake/Toolchain-gcc-m32.cmake +check_exit_value $? "cmake did not return properly" || exit 1 + +make -j2 +check_exit_value $? "make did not return properly" || exit 1 + +cpack -G TGZ +check_exit_value $? "cpack did not return properly" || exit 1 + +cpack -G TBZ2 +check_exit_value $? "cpack did not return properly" || exit 1 + +# source release +cpack -G ZIP --config CPackSourceConfig.cmake +check_exit_value $? "cpack did not return properly" || exit 1 + +cpack -G TGZ --config CPackSourceConfig.cmake +check_exit_value $? "cpack did not return properly" || exit 1 + +cpack -G TBZ2 --config CPackSourceConfig.cmake +check_exit_value $? "cpack did not return properly" || exit 1 + +# Let's start doing the VTK documentation then: +cmake -DGDCM_VTK_DOCUMENTATION:BOOL=ON -DGDCM_USE_VTK:BOOL=ON -DVTK_DIR:PATH=/home/mathieu/Kitware/vtk-5.10-gcc . +check_exit_value $? "cmake did not return properly" || exit 1 +#make -j4 +make rebuild_cache +make vtkgdcmDoxygenDoc +check_exit_value $? "vtkgdcmDoxygenDoc did not return properly" || exit 1 + +rsync -av -r Utilities/doxygen/html malat,gdcm@web.sourceforge.net:htdocs/2.2 +check_exit_value $? "rsync recursive html did not return properly" || exit 1 +rsync -av Utilities/doxygen/gdcm-$version-doc.tar.gz malat,gdcm@web.sourceforge.net:htdocs/2.2 +check_exit_value $? "rsync tarball did not return properly" || exit 1 +rsync -av Utilities/doxygen/latex/gdcm-$version.pdf malat,gdcm@web.sourceforge.net:htdocs/2.2 +check_exit_value $? "rsync pdf did not return properly" || exit 1 + +# Warning need to create /manually/ the subfolder: +# https://sourceforge.net/project/admin/explorer.php?group_id=137895 +# https://sourceforge.net/projects/gdcm/files/gdcm%202.x/#folder-create + +rsync -e ssh GDCM-$version-Linux-x86_64.tar.gz "malat,gdcm@frs.sourceforge.net:/home/frs/project/g/gd/gdcm/gdcm\ 2.x/GDCM\ $version" +check_exit_value $? "rsync did not return properly" || exit 1 +rsync -e ssh GDCM-$version-Linux-x86_64.tar.bz2 "malat,gdcm@frs.sourceforge.net:/home/frs/project/g/gd/gdcm/gdcm\ 2.x/GDCM\ $version" +check_exit_value $? "rsync did not return properly" || exit 1 +rsync -e ssh gdcm-$version.zip "malat,gdcm@frs.sourceforge.net:/home/frs/project/g/gd/gdcm/gdcm\ 2.x/GDCM\ $version" +check_exit_value $? "rsync did not return properly" || exit 1 +rsync -e ssh gdcm-$version.tar.gz "malat,gdcm@frs.sourceforge.net:/home/frs/project/g/gd/gdcm/gdcm\ 2.x/GDCM\ $version" +check_exit_value $? "rsync did not return properly" || exit 1 +rsync -e ssh gdcm-$version.tar.bz2 "malat,gdcm@frs.sourceforge.net:/home/frs/project/g/gd/gdcm/gdcm\ 2.x/GDCM\ $version" +check_exit_value $? "rsync did not return properly" || exit 1 +rsync -e ssh Utilities/doxygen/latex/gdcm-$version.pdf "malat,gdcm@frs.sourceforge.net:/home/frs/project/g/gd/gdcm/gdcm\ 2.x/GDCM\ $version" +check_exit_value $? "rsync did not return properly" || exit 1 +rsync -e ssh Utilities/doxygen/gdcm-$version-doc.tar.gz "malat,gdcm@frs.sourceforge.net:/home/frs/project/g/gd/gdcm/gdcm\ 2.x/GDCM\ $version" +check_exit_value $? "rsync did not return properly" || exit 1 + diff --git a/gdcm/Utilities/Tools/CMakeLists.txt b/gdcm/Utilities/Tools/CMakeLists.txt new file mode 100644 index 0000000..0c8d7f4 --- /dev/null +++ b/gdcm/Utilities/Tools/CMakeLists.txt @@ -0,0 +1,3 @@ +project(TOOLS) + +add_executable(upsidedown upsidedown.c) diff --git a/gdcm/Utilities/Tools/upsidedown.c b/gdcm/Utilities/Tools/upsidedown.c new file mode 100644 index 0000000..66f1a9d --- /dev/null +++ b/gdcm/Utilities/Tools/upsidedown.c @@ -0,0 +1,46 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#include +#include +#include + +int main(int argc, char *argv[]) +{ + const unsigned int x = 420; + const unsigned int y = 608; + const unsigned int bit = 1; + char *buffer = malloc(x*y*bit); + int i = 1; + size_t len; + const char *filename, *outfilename; + FILE *in, *out; + if( argc < 3 ) + return 1; + filename = argv[1]; + outfilename = argv[2]; + in = fopen(filename, "rb" ); + out = fopen(outfilename, "wb" ); + len = fread(buffer,1,bit*x*y,in); + assert( len == x*y*bit ); + + for(i = y; i > 0; --i) + { + fwrite(buffer+bit*x*(i-1),1,bit*x,out); + } + fclose(in); + fclose(out); + free(buffer); + return 0; +} diff --git a/gdcm/Utilities/VTK/.NoDartCoverage b/gdcm/Utilities/VTK/.NoDartCoverage new file mode 100644 index 0000000..3c99729 --- /dev/null +++ b/gdcm/Utilities/VTK/.NoDartCoverage @@ -0,0 +1 @@ +# do not do coverage in this directory diff --git a/gdcm/Utilities/VTK/Applications/CMakeLists.txt b/gdcm/Utilities/VTK/Applications/CMakeLists.txt new file mode 100644 index 0000000..6e17dd9 --- /dev/null +++ b/gdcm/Utilities/VTK/Applications/CMakeLists.txt @@ -0,0 +1,57 @@ +# Build the vtk-gdcm simple viewer +include_directories( + ${GDCM_SOURCE_DIR}/Utilities/VTK + ) + +if(WIN32 AND NOT CYGWIN) + include_directories( + "${GDCM_SOURCE_DIR}/Utilities/getopt" + ) +endif() +if(WIN32) + if (BUILD_SHARED_LIBS) + add_definitions(-DGETOPT_DLL) + endif () +endif() + +set(GDCM_VTK_APPS + gdcm2vtk + ) +if(VTK_USE_RENDERING OR vtkRenderingCore_LOADED) + set(GDCM_VTK_APPS + ${GDCM_VTK_APPS} + gdcmviewer # vtkImageViewer2 + gdcm2pnm + ) +endif() + +foreach(app ${GDCM_VTK_APPS}) + add_executable(${app} ${app}.cxx) + if(GDCM_EXECUTABLE_PROPERTIES) + set_target_properties(${app} PROPERTIES ${GDCM_EXECUTABLE_PROPERTIES}) + endif() + target_link_libraries(${app} ${VTKGDCM_NAME}) + target_link_libraries(${app} gdcmDSED gdcmMSFF gdcmCommon) + if( "${VTK_MAJOR_VERSION}.${VTK_MINOR_VERSION}" LESS 6.0 ) + target_link_libraries(${app} vtkCommon vtkFiltering vtkIO vtkImaging) + if(VTK_USE_RENDERING) + target_link_libraries(${app} vtkRendering) + endif() + if( "${VTK_MAJOR_VERSION}.${VTK_MINOR_VERSION}" GREATER 5.0 ) + target_link_libraries(${app} vtkWidgets) + endif() + else() + # >= 6.0 + target_link_libraries(${app} ${VTK_LIBRARIES} vtkIOXML) + endif() + if(WIN32 AND NOT CYGWIN) + target_link_libraries(${app} gdcmgetopt) + endif() + if(NOT GDCM_INSTALL_NO_RUNTIME) + install(TARGETS ${app} + RUNTIME DESTINATION ${GDCM_INSTALL_BIN_DIR} COMPONENT VTKApplications + LIBRARY DESTINATION ${GDCM_INSTALL_LIB_DIR} COMPONENT VTKLibraries + ARCHIVE DESTINATION ${GDCM_INSTALL_LIB_DIR} COMPONENT VTKDebugDevel + ) + endif() +endforeach() diff --git a/gdcm/Utilities/VTK/Applications/gdcm2pnm.cxx b/gdcm/Utilities/VTK/Applications/gdcm2pnm.cxx new file mode 100644 index 0000000..aace818 --- /dev/null +++ b/gdcm/Utilities/VTK/Applications/gdcm2pnm.cxx @@ -0,0 +1,98 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkGDCMImageReader.h" +#include "vtkRenderWindow.h" +#include "vtkRenderer.h" +#include "vtkImageMapToWindowLevelColors.h" +#include "vtkImageActor.h" +#include "vtkPNGWriter.h" +#include "vtkWindowToImageFilter.h" +#include "vtkMedicalImageProperties.h" + +/* + * Inspired by dcm2pnm from DCMTK toolkit + * for now it always output PNG file and does not handle very well window/level + * since it needs to be stored in the DICOM file... + * It also only takes the first window/level from the list + */ +int main(int argc, char *argv[]) +{ + if( argc < 3 ) + { + std::cerr << argv[0] << " input.dcm output.pnm" << std::endl; + return 1; + } + const char *filename = argv[1]; + const char *outfilename = argv[2]; + + vtkGDCMImageReader *reader = vtkGDCMImageReader::New(); + reader->SetFileName( filename ); + reader->Update(); // important to read the window/level info + + vtkMedicalImageProperties *prop = reader->GetMedicalImageProperties(); + + vtkRenderWindow *renWin = vtkRenderWindow::New(); + renWin->OffScreenRenderingOn(); + + vtkRenderer *renderer = vtkRenderer::New(); + renWin->AddRenderer(renderer); + + vtkImageMapToWindowLevelColors *windowlevel = vtkImageMapToWindowLevelColors::New(); +#if (VTK_MAJOR_VERSION >= 6) + windowlevel->SetInputConnection( reader->GetOutputPort() ); +#else + windowlevel->SetInput( reader->GetOutput() ); +#endif + unsigned int n = prop->GetNumberOfWindowLevelPresets(); + if( n ) + { + // Take the first one by default: + const double *wl = prop->GetNthWindowLevelPreset(0); + windowlevel->SetWindow( wl[0] ); + windowlevel->SetLevel( wl[1] ); + } + + vtkImageActor *actor = vtkImageActor::New(); +#if (VTK_MAJOR_VERSION >= 6) + actor->SetInputData( windowlevel->GetOutput() ); +#else + actor->SetInput( windowlevel->GetOutput() ); +#endif + + renderer->AddActor( actor ); + + renWin->Render(); + + vtkWindowToImageFilter *w2if = vtkWindowToImageFilter::New(); + w2if->SetInput ( renWin ); + + vtkPNGWriter *wr = vtkPNGWriter::New(); +#if (VTK_MAJOR_VERSION >= 6) + wr->SetInputConnection( w2if->GetOutputPort() ); +#else + wr->SetInput( w2if->GetOutput() ); +#endif + wr->SetFileName ( outfilename ); + wr->Write(); + + reader->Delete(); + renWin->Delete(); + renderer->Delete(); + windowlevel->Delete(); + actor->Delete(); + w2if->Delete(); + wr->Delete(); + + return 0; +} diff --git a/gdcm/Utilities/VTK/Applications/gdcm2vtk.cxx b/gdcm/Utilities/VTK/Applications/gdcm2vtk.cxx new file mode 100644 index 0000000..fdba54c --- /dev/null +++ b/gdcm/Utilities/VTK/Applications/gdcm2vtk.cxx @@ -0,0 +1,969 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + * TODO: This app should be a suclass of gdcmimg application to avoid code duplication + */ +#include "vtkGDCMImageReader.h" +#include "vtkGDCMImageWriter.h" + +#include "vtkVersion.h" +#include "vtkErrorCode.h" +#include "vtkStringArray.h" +//#include "vtkImageCast.h" // DEBUG +#include "vtkImageReader2Factory.h" +#include "vtkImageReader2.h" +#include "vtkImageData.h" +#include "vtkTIFFWriter.h" +#include "vtkPNGWriter.h" +#include "vtkPNMWriter.h" +#include "vtkBMPWriter.h" +#if VTK_MAJOR_VERSION >= 5 && VTK_MINOR_VERSION > 0 +#include "vtkMetaImageReader.h" +#include "vtkXMLImageDataReader.h" +#include "vtkMetaImageWriter.h" +#include "vtkDICOMImageReader.h" +#include "vtkMINCImageReader.h" +#include "vtkMINCImageAttributes.h" +#include "vtk_tiff.h" // ORIENTATION_BOTLEFT +#include "vtkImageRGBToYBR.h" +#endif +#include "vtkMedicalImageProperties.h" +#include "vtkTIFFReader.h" +#include "vtkGESignaReader.h" +#include "vtkImageExtractComponents.h" +#include "vtkJPEGReader.h" +#include "vtkBMPReader.h" +#include "vtkLookupTable.h" +#include "vtkPointData.h" +#include "vtkStructuredPointsReader.h" +#include "vtkStructuredPointsWriter.h" +#include "vtkStructuredPoints.h" +#include "vtkXMLImageDataWriter.h" + +#include "gdcmFilename.h" +#include "gdcmTrace.h" +#include "gdcmVersion.h" +#include "gdcmImageHelper.h" +#include "gdcmFileMetaInformation.h" +#include "gdcmSystem.h" +#include "gdcmUIDGenerator.h" +#include "gdcmDirectory.h" + +#include + +void PrintVersion() +{ + std::cout << "gdcm2vtk: gdcm " << gdcm::Version::GetVersion() << " "; + const char date[] = "$Date$"; + std::cout << date << std::endl; + //std::cout << " VTK " << vtkVersion::GetVTKVersion() << std::endl; + std::cout << " " << vtkVersion::GetVTKSourceVersion() << std::endl; +} + +void PrintHelp() +{ + PrintVersion(); + std::cout << "Usage: gdcm2vtk [OPTION] input output" << std::endl; + std::cout << "Convert a vtk-supported file into DICOM.\n"; + std::cout << "Options:" << std::endl; + std::cout << " --force-rescale force rescale." << std::endl; + std::cout << " --force-spacing force spacing." << std::endl; + std::cout << " --palette-color when supported generate a PALETTE COLOR file." << std::endl; + std::cout << " --argb when supported generate a ARGB file." << std::endl; + std::cout << " --compress when supported generate a compressed file." << std::endl; + std::cout << " --use-vtkdicom Use vtkDICOMImageReader (instead of GDCM)." << std::endl; + std::cout << " --modality set Modality." << std::endl; + std::cout << " --lower-left set lower left." << std::endl; + std::cout << " --shift set shift." << std::endl; + std::cout << " --scale set scale." << std::endl; + std::cout << " --compress set compressoin (MetaIO)." << std::endl; + std::cout << " -T --study-uid Study UID." << std::endl; + std::cout << " -S --series-uid Series UID." << std::endl; + std::cout << " --root-uid Root UID." << std::endl; + std::cout << " --imageformat Image Format [1-8] (aka PhotometricInterpretation)." << std::endl; + std::cout << "Compression Types (lossless):" << std::endl; + std::cout << " -J --jpeg Compress image in jpeg." << std::endl; + std::cout << " -K --j2k Compress image in j2k." << std::endl; + std::cout << " -L --jpegls Compress image in jpeg-ls." << std::endl; + std::cout << " -R --rle Compress image in rle (lossless only)." << std::endl; + std::cout << "General Options:" << std::endl; + std::cout << " -V --verbose more verbose (warning+error)." << std::endl; + std::cout << " -W --warning print warning info." << std::endl; + std::cout << " -D --debug print debug info." << std::endl; + std::cout << " -E --error print error info." << std::endl; + std::cout << " -h --help print help." << std::endl; + std::cout << " -v --version print version." << std::endl; + std::cout << "Env var:" << std::endl; + std::cout << " GDCM_ROOT_UID Root UID" << std::endl; +} + +int main(int argc, char *argv[]) +{ + int retcode = 0; + int c; + //int digit_optind = 0; + + std::string root_uid; + int rootuid = 0; + std::vector filenames; + int forcerescale = 0; + int forcespacing = 0; + int palettecolor = 0; + int argb = 0; + int modality = 0; + std::string modality_str; + int studyuid = 0; + int seriesuid = 0; + // compression + int jpeg = 0; + int jpegls = 0; + int j2k = 0; + int rle = 0; + int usevtkdicom = 0; + int compress = 0; + int lowerleft = 0; + int oshift = 0; + int oscale = 0; + int oimageformat = 0; + double shift = 0.; + double scale = 1.; + int imageformat = 0; + + int verbose = 0; + int warning = 0; + int debug = 0; + int error = 0; + int help = 0; + int version = 0; + + gdcm::UIDGenerator uid; + std::string series_uid = uid.Generate(); + std::string study_uid = uid.Generate(); + while (1) { + //int this_option_optind = optind ? optind : 1; + int option_index = 0; + static struct option long_options[] = { + {"force-rescale", 0, &forcerescale, 1}, + {"force-spacing", 0, &forcespacing, 1}, + {"palette-color", 0, &palettecolor, 1}, + {"argb", 0, &argb, 1}, + {"modality", 1, &modality, 1}, + {"study-uid", 1, &studyuid, 1}, + {"series-uid", 1, &seriesuid, 1}, + {"root-uid", 1, &rootuid, 1}, // specific Root (not GDCM) + {"jpeg", 0, &jpeg, 1}, // JPEG lossy / lossless + {"jpegls", 0, &jpegls, 1}, // JPEG-LS: lossy / lossless + {"j2k", 0, &j2k, 1}, // J2K: lossy / lossless + {"rle", 0, &rle, 1}, // lossless ! + {"compress", 0, &compress, 1}, // compress with using MetaIO + {"use-vtkdicom", 0, &usevtkdicom, 1}, // use vtkDICOMImageReader + {"lower-left", 0, &lowerleft, 1}, // use FileLowerLeftOn + {"shift", 1, &oshift, 1}, // + {"scale", 1, &oscale, 1}, // + {"imageformat", 1, &oimageformat, 1}, // + +// General options ! + {"verbose", 0, &verbose, 1}, + {"warning", 0, &warning, 1}, + {"debug", 0, &debug, 1}, + {"error", 0, &error, 1}, + {"help", 0, &help, 1}, + {"version", 0, &version, 1}, + + {0, 0, 0, 0} + }; + + c = getopt_long (argc, argv, "JKLRT:S:VWDEhv", + long_options, &option_index); + if (c == -1) + { + break; + } + + switch (c) + { + case 0: + { + const char *s = long_options[option_index].name; (void)s; + //printf ("option %s", s); + if (optarg) + { + if( option_index == 0 ) /* input */ + { + assert( strcmp(s, "input") == 0 ); + //assert( filename.empty() ); + //filename = optarg; + } + else if( option_index == 4 ) /* modality */ + { + assert( strcmp(s, "modality") == 0 ); + //assert( filename.empty() ); + modality_str = optarg; + } + else if( option_index == 5 ) /* study-uid */ + { + assert( strcmp(s, "study-uid") == 0 ); + series_uid = optarg; + } + else if( option_index == 6 ) /* series-uid */ + { + assert( strcmp(s, "series-uid") == 0 ); + study_uid = optarg; + } + else if( option_index == 7 ) /* root-uid */ + { + assert( strcmp(s, "root-uid") == 0 ); + root_uid = optarg; + } + else if( option_index == 15 ) /* shift */ + { + assert( strcmp(s, "shift") == 0 ); + shift = atof(optarg); + } + else if( option_index == 16 ) /* scale */ + { + assert( strcmp(s, "scale") == 0 ); + scale = atof(optarg); + } + else if( option_index == 17 ) /* imageformat */ + { + assert( strcmp(s, "imageformat") == 0 ); + imageformat = atoi(optarg); + } + //printf (" with arg %s", optarg); + } + //printf ("\n"); + } + break; + + case 'J': + jpeg = 1; + break; + + case 'K': + j2k = 1; + break; + + case 'L': + jpegls = 1; + break; + + case 'R': + rle = 1; + break; + + case 'T': + studyuid = 1; + study_uid = optarg; + break; + + case 'S': + seriesuid = 1; + series_uid = optarg; + break; + + case 'V': + verbose = 1; + break; + + case 'W': + warning = 1; + break; + + case 'D': + debug = 1; + break; + + case 'E': + error = 1; + break; + + case 'h': + help = 1; + break; + + case 'v': + version = 1; + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + //printf ("non-option ARGV-elements: "); + while (optind < argc) + { + //printf ("%s ", argv[optind]); + filenames.push_back( argv[optind++] ); + } + //printf ("\n"); + } + + if( version ) + { + //std::cout << "version" << std::endl; + PrintVersion(); + return 0; + } + + if( help ) + { + //std::cout << "help" << std::endl; + PrintHelp(); + return 0; + } + + // Debug is a little too verbose + gdcm::Trace::SetDebug( debug ); + gdcm::Trace::SetWarning( warning ); + gdcm::Trace::SetError( error ); + // when verbose is true, make sure warning+error are turned on: + if( verbose ) + { + gdcm::Trace::SetWarning( verbose ); + gdcm::Trace::SetError( verbose); + } + + if( filenames.empty() ) + { + PrintHelp(); + return 1; + } + + int recursive = 0; + const char *outfilename = NULL; + vtkStringArray *names = vtkStringArray::New(); + { + // Is it a single directory ? If so loop over all files contained in it: + //const char *filename = argv[1]; + if( filenames.size() == 2 && gdcm::System::FileIsDirectory( filenames[0].c_str() ) ) + { + if( verbose ) + std::cout << "Loading directory: " << filenames[0] << std::endl; + gdcm::Directory d; + d.Load(filenames[0].c_str(), recursive); + gdcm::Directory::FilenamesType const &files = d.GetFilenames(); + for( gdcm::Directory::FilenamesType::const_iterator it = files.begin(); it != files.end(); ++it ) + { + names->InsertNextValue( it->c_str() ); + } + outfilename = filenames[1].c_str(); + } + else // list of files passed directly on the cmd line: + // discard non-existing or directory + { + for(std::vector::const_iterator it = filenames.begin(); it != filenames.end() - 1; ++it) + { + const std::string & filename = *it; + if( gdcm::System::FileExists( filename.c_str() ) ) + { + if( gdcm::System::FileIsDirectory( filename.c_str() ) ) + { + if(verbose) + std::cerr << "Discarding directory: " << filename << std::endl; + } + else + { + names->InsertNextValue( filename.c_str() ); + } + } + else + { + if(verbose) + std::cerr << "Discarding non existing file: " << filename << std::endl; + } + } + outfilename = filenames[ filenames.size() - 1 ].c_str(); + } + } + + if( !names->GetNumberOfValues() ) + { + std::cerr << "Missing parameters on the command line" << std::endl; + return 1; + } + const char *filename = names->GetValue( 0 ).c_str(); + + gdcm::ImageHelper::SetForceRescaleInterceptSlope(forcerescale); + gdcm::ImageHelper::SetForcePixelSpacing(forcespacing); + + vtkGDCMImageReader *gdcmreader = vtkGDCMImageReader::New(); + +#if VTK_MAJOR_VERSION >= 5 && VTK_MINOR_VERSION > 0 + vtkDICOMImageReader *dicomreader = vtkDICOMImageReader::New(); +#endif + if( debug ) + { + gdcmreader->DebugOn(); +#if VTK_MAJOR_VERSION >= 5 && VTK_MINOR_VERSION > 0 + dicomreader->DebugOn(); +#endif + } + + vtkImageReader2Factory* imgfactory = vtkImageReader2Factory::New(); +#if VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION <= 4 + // warning vtk 5.4 is broken metaimage are not added to factory + // by default + vtkMetaImageReader *d = vtkMetaImageReader::New(); + imgfactory->RegisterReader( d ); + d->Delete(); +#endif + if( usevtkdicom ) +#if VTK_MAJOR_VERSION >= 5 && VTK_MINOR_VERSION > 0 + imgfactory->RegisterReader( dicomreader ); +#else + (void)0; +#endif + else + imgfactory->RegisterReader( gdcmreader ); + vtkImageReader2* imgreader = + imgfactory->CreateImageReader2(filename); + vtkStructuredPointsReader *datareader = vtkStructuredPointsReader::New(); + datareader->SetFileName( filename ); + vtkXMLReader *xmlreader = vtkXMLImageDataReader::New(); + int res = 0; + if( !imgreader ) + { + int xmlres = xmlreader->CanReadFile( filename ); + if( !xmlres ) + { + res = datareader->IsFileStructuredPoints(); + if( !res ) + { + std::cerr << "could not find no reader to handle file: " << filename << std::endl; + return 1; + } + } + } + imgfactory->Delete(); + + vtkImageData *imgdata = NULL; + std::string image_comments; + if( imgreader ) + { + imgreader->SetFileLowerLeft( lowerleft ); + if( names->GetNumberOfValues() == 1 ) + imgreader->SetFileName( names->GetValue(0) ); + else + imgreader->SetFileNames(names); + imgreader->Update(); + if( imgreader->GetErrorCode() ) + { + std::cerr << "There was an error: " << vtkErrorCode::GetStringFromErrorCode(imgreader->GetErrorCode()) << std::endl; + return 1; + } + imgdata = imgreader->GetOutput(); + if( verbose ) + std::cout << "imgreader classname: " << imgreader->GetClassName() << std::endl; + } + else if( res ) + { + datareader->Update(); + if( datareader->GetErrorCode() ) + { + std::cerr << "There was an error: " << vtkErrorCode::GetStringFromErrorCode(datareader->GetErrorCode()) << std::endl; + return 1; + } + imgdata = datareader->GetOutput(); + if( datareader->GetHeader() ) + { + image_comments = datareader->GetHeader(); + } + } + else if( xmlreader->CanReadFile( filename ) ) + { + xmlreader->SetFileName(filename); + xmlreader->Update(); + imgdata = vtkXMLImageDataReader::SafeDownCast(xmlreader)->GetOutput(); + } + + gdcm::Filename fn = outfilename; + const char *outputextension = fn.GetExtension(); + + if ( outputextension ) + { + if( gdcm::System::StrCaseCmp(outputextension,".vtk") == 0 ) + { + vtkStructuredPointsWriter * writer = vtkStructuredPointsWriter::New(); + writer->SetFileName( outfilename ); + writer->SetFileTypeToBinary(); +#if (VTK_MAJOR_VERSION >= 6) + writer->SetInputData( imgdata ); +#else + writer->SetInput( imgdata ); +#endif + writer->Write(); +#if VTK_MAJOR_VERSION >= 5 && VTK_MINOR_VERSION > 0 + if( writer->GetErrorCode() ) + { + std::cerr << "There was an error: " << vtkErrorCode::GetStringFromErrorCode(writer->GetErrorCode()) << std::endl; + retcode = 1; + } +#endif + writer->Delete(); + goto cleanup; + } + else if( gdcm::System::StrCaseCmp(outputextension,".bmp") == 0 ) + { + vtkBMPWriter * writer = vtkBMPWriter::New(); + writer->SetFileName( outfilename ); +#if (VTK_MAJOR_VERSION >= 6) + writer->SetInputData( imgdata ); +#else + writer->SetInput( imgdata ); +#endif + writer->Write(); +#if VTK_MAJOR_VERSION >= 5 && VTK_MINOR_VERSION > 0 + if( writer->GetErrorCode() ) + { + std::cerr << "There was an error: " << vtkErrorCode::GetStringFromErrorCode(writer->GetErrorCode()) << std::endl; + retcode = 1; + } +#endif + writer->Delete(); + goto cleanup; + } + else if( gdcm::System::StrCaseCmp(outputextension,".pgm") == 0 + || gdcm::System::StrCaseCmp(outputextension,".pnm") == 0 + || gdcm::System::StrCaseCmp(outputextension,".ppm") == 0 ) + { + vtkPNMWriter * writer = vtkPNMWriter::New(); + writer->SetFileName( outfilename ); +#if (VTK_MAJOR_VERSION >= 6) + writer->SetInputData( imgdata ); +#else + writer->SetInput( imgdata ); +#endif + writer->Write(); +#if VTK_MAJOR_VERSION >= 5 && VTK_MINOR_VERSION > 0 + if( writer->GetErrorCode() ) + { + std::cerr << "There was an error: " << vtkErrorCode::GetStringFromErrorCode(writer->GetErrorCode()) << std::endl; + retcode = 1; + } +#endif + writer->Delete(); + goto cleanup; + } + else if( gdcm::System::StrCaseCmp(outputextension,".png") == 0 ) + { + vtkPNGWriter * writer = vtkPNGWriter::New(); + writer->SetFileName( outfilename ); +#if (VTK_MAJOR_VERSION >= 6) + writer->SetInputData( imgdata ); +#else + writer->SetInput( imgdata ); +#endif + writer->Write(); +#if VTK_MAJOR_VERSION >= 5 && VTK_MINOR_VERSION > 0 + if( writer->GetErrorCode() ) + { + std::cerr << "There was an error: " << vtkErrorCode::GetStringFromErrorCode(writer->GetErrorCode()) << std::endl; + retcode = 1; + } +#endif + writer->Delete(); + goto cleanup; + } + else if( gdcm::System::StrCaseCmp(outputextension,".tif") == 0 + || gdcm::System::StrCaseCmp(outputextension,".tiff") == 0 ) // + { + vtkTIFFWriter * writer = vtkTIFFWriter::New(); + writer->SetFileName( outfilename ); +#if (VTK_MAJOR_VERSION >= 6) + writer->SetInputData( imgdata ); +#else + writer->SetInput( imgdata ); +#endif + writer->Write(); +#if VTK_MAJOR_VERSION >= 5 && VTK_MINOR_VERSION > 0 + if( writer->GetErrorCode() ) + { + std::cerr << "There was an error: " << vtkErrorCode::GetStringFromErrorCode(writer->GetErrorCode()) << std::endl; + retcode = 1; + } +#endif + writer->Delete(); + goto cleanup; + } + else if( gdcm::System::StrCaseCmp(outputextension,".vti") == 0 ) // vtkXMLImageDataWriter::GetDefaultFileExtension() + { + vtkXMLImageDataWriter * writer = vtkXMLImageDataWriter::New(); + writer->SetFileName( outfilename ); + writer->SetDataModeToBinary(); +#if (VTK_MAJOR_VERSION >= 6) + writer->SetInputData( imgdata ); +#else + writer->SetInput( imgdata ); +#endif + writer->Write(); +#if VTK_MAJOR_VERSION >= 5 && VTK_MINOR_VERSION > 0 + if( writer->GetErrorCode() ) + { + std::cerr << "There was an error: " << vtkErrorCode::GetStringFromErrorCode(writer->GetErrorCode()) << std::endl; + retcode = 1; + } +#endif + writer->Delete(); + goto cleanup; + } +#if VTK_MAJOR_VERSION >= 5 && VTK_MINOR_VERSION > 0 + else if( gdcm::System::StrCaseCmp(outputextension,".mha") == 0 || + gdcm::System::StrCaseCmp(outputextension,".mhd") == 0 ) // vtkMetaImageReader::GetFileExtensions() + { + //vtkImageCast * cast = vtkImageCast::New(); + //cast->SetInput( imgdata ); + //cast->SetOutputScalarTypeToShort (); + + // Weird, the writer does not offer the same API as the Reader, for instance + // One cannot set the patient name to store (see vtkMetaImageReader::GetPatientName ...) + vtkMetaImageWriter * writer = vtkMetaImageWriter::New(); + writer->SetFileName( outfilename ); +#if (VTK_MAJOR_VERSION >= 6) + writer->SetInputData( imgdata ); +#else + writer->SetInput( imgdata ); +#endif + //writer->SetInput( cast->GetOutput() ); + writer->SetCompression( compress ); + //writer->FileLowerLeftOff(); // not used in the implementation + writer->Write(); + if( writer->GetErrorCode() ) + { + std::cerr << "There was an error: " << vtkErrorCode::GetStringFromErrorCode(writer->GetErrorCode()) << std::endl; + retcode = 1; + } + writer->Delete(); + goto cleanup; + } +#endif + } +// else + { + + vtkGDCMImageWriter * writer = vtkGDCMImageWriter::New(); + //writer->SetFileLowerLeft( 1 ); + if( studyuid ) + { + writer->SetStudyUID( study_uid.c_str() ); + } + if( seriesuid ) + { + writer->SetSeriesUID( series_uid.c_str() ); + } + + // Default: + writer->SetCompressionType( vtkGDCMImageWriter::NO_COMPRESSION ); // Implicit VR Little Endian + if( jpeg ) + { + writer->SetCompressionType( vtkGDCMImageWriter::JPEG_COMPRESSION ); + } + else if( j2k ) + { + writer->SetCompressionType( vtkGDCMImageWriter::JPEG2000_COMPRESSION ); + } + else if( jpegls ) + { + writer->SetCompressionType( vtkGDCMImageWriter::JPEGLS_COMPRESSION ); + } + else if( rle ) + { + writer->SetCompressionType( vtkGDCMImageWriter::RLE_COMPRESSION ); + } + + // HACK: call it *after* instanciating vtkGDCMImageWriter + if( !gdcm::UIDGenerator::IsValid( study_uid.c_str() ) ) + { + std::cerr << "Invalid UID for Study UID: " << study_uid << std::endl; + return 1; + } + if( !gdcm::UIDGenerator::IsValid( series_uid.c_str() ) ) + { + std::cerr << "Invalid UID for Series UID: " << series_uid << std::endl; + return 1; + } + gdcm::FileMetaInformation::SetSourceApplicationEntityTitle( "gdcm2vtk" ); + if( !rootuid ) + { + // only read the env var is no explicit cmd line option + // maybe there is an env var defined... let's check + const char *rootuid_env = getenv("GDCM_ROOT_UID"); + if( rootuid_env ) + { + rootuid = 1; + root_uid = rootuid_env; + } + } + if( rootuid ) + { + if( !gdcm::UIDGenerator::IsValid( root_uid.c_str() ) ) + { + std::cerr << "specified Root UID is not valid: " << root_uid << std::endl; + return 1; + } + gdcm::UIDGenerator::SetRoot( root_uid.c_str() ); + } + + writer->SetFileName( outfilename ); + + if( imgreader && imgreader->GetOutput()->GetNumberOfScalarComponents() == 4 && !argb ) + { + if( verbose ) + { + std::cout << "alpha channel will be lost " << imgreader->GetOutput()->GetNumberOfScalarComponents() << std::endl; + } + vtkImageExtractComponents *extract = vtkImageExtractComponents::New(); +#if (VTK_MAJOR_VERSION >= 6) + extract->SetInputConnection( imgreader->GetOutputPort() ); +#else + extract->SetInput( imgreader->GetOutput() ); +#endif + extract->SetComponents( 0,1,2 ); +#if (VTK_MAJOR_VERSION >= 6) + writer->SetInputConnection( extract->GetOutputPort() ); +#else + writer->SetInput( extract->GetOutput() ); +#endif + extract->Delete(); + } + else + { + //writer->SetInput( imgreader->GetOutput() ); +#if (VTK_MAJOR_VERSION >= 6) + writer->SetInputData( imgdata ); +#else + writer->SetInput( imgdata ); +#endif + +#if 0 + vtkImageRGBToYBR * rgb2ybr = vtkImageRGBToYBR::New(); + rgb2ybr->SetInput( imgreader->GetOutput() ); + writer->SetInput( rgb2ybr->GetOutput() ); + writer->SetImageFormat( VTK_YBR ); +#endif + } + + // If input is 3D, let's write output as 3D if possible: + if( imgdata->GetDimensions()[2] != 1 ) + { + writer->SetFileDimensionality( 3 ); + } + + if( imgreader ) + { + if( vtkGDCMImageReader * reader0 = vtkGDCMImageReader::SafeDownCast(imgreader) ) + { + writer->SetMedicalImageProperties( reader0->GetMedicalImageProperties() ); + writer->SetDirectionCosines( reader0->GetDirectionCosines() ); + writer->SetShift( reader0->GetShift() ); + writer->SetScale( reader0->GetScale() ); + writer->SetImageFormat( reader0->GetImageFormat() ); + writer->SetLossyFlag( reader0->GetLossyFlag() ); + if( verbose ) + { + reader0->GetOutput()->Print( std::cout ); + reader0->GetMedicalImageProperties()->Print( std::cout ); + } + } +#if VTK_MAJOR_VERSION >= 5 && VTK_MINOR_VERSION > 0 + else if( vtkDICOMImageReader * reader1 = vtkDICOMImageReader::SafeDownCast(imgreader) ) + { + const float* iop = reader1->GetImageOrientationPatient(); + double dircos[6]; + for(int i = 0; i < 6; ++i) + dircos[i] = iop[i]; + writer->SetDirectionCosinesFromImageOrientationPatient( dircos ); + + writer->GetMedicalImageProperties()->SetModality( "MR" ); // FIXME + writer->GetMedicalImageProperties()->SetPatientName( reader1->GetPatientName() ); + //writer->GetMedicalImageProperties()->SetStudyUID( reader1->GetStudyUID() ); // TODO + writer->GetMedicalImageProperties()->SetStudyID( reader1->GetStudyID() ); + //writer->GetMedicalImageProperties()->SetGantryTilt( reader1->GetGantryAngle() ); // TODO +#if VTK_MAJOR_VERSION >= 5 && VTK_MINOR_VERSION > 2 + writer->GetMedicalImageProperties()->SetDirectionCosine( dircos[0], + dircos[1], + dircos[2], + dircos[3], + dircos[4], + dircos[5] + ); +#endif + writer->SetShift( reader1->GetRescaleOffset() ); + writer->SetScale( reader1->GetRescaleSlope() ); + //writer->SetImageFormat( reader1->GetImageFormat() ); + //writer->SetLossyFlag( reader1->GetLossyFlag() ); + } +#endif + else if( vtkJPEGReader * reader2 = vtkJPEGReader::SafeDownCast(imgreader) ) + { + (void)reader2; + // vtk JPEG reader only read 8bits lossy file + writer->SetLossyFlag( 1 ); + // TODO: It would be nice to specify the original encoder was JPEG -> ISO_10918_1 + } + else if( vtkBMPReader * reader3 = vtkBMPReader::SafeDownCast(imgreader) ) + { + if( palettecolor ) + reader3->Allow8BitBMPOn( ); + reader3->Update( ); + //reader3->GetLookupTable()->Print( std::cout ); + if( palettecolor ) + { + if( reader3->GetNumberOfScalarComponents() == 1 ) + { + reader3->GetOutput()->GetPointData()->GetScalars()->SetLookupTable( reader3->GetLookupTable() ); + writer->SetImageFormat( VTK_LOOKUP_TABLE ); + } + } + } + else if( vtkGESignaReader * reader4 = vtkGESignaReader::SafeDownCast(imgreader) ) + { +#if VTK_MAJOR_VERSION >= 5 && VTK_MINOR_VERSION > 0 + writer->SetMedicalImageProperties( reader4->GetMedicalImageProperties() ); +#endif + //reader4->GetMedicalImageProperties()->Print( std::cout ); + } +#if VTK_MAJOR_VERSION >= 5 && VTK_MINOR_VERSION > 0 + else if( vtkMINCImageReader *reader5 = vtkMINCImageReader::SafeDownCast( imgreader ) ) + { + writer->SetDirectionCosines( reader5->GetDirectionCosines() ); + //writer->GetMedicalImageProperties()->SetModality( "MR" ); + // the following does not work with VTKData/Data/t3_grid_0.mnc + //writer->SetScale( reader5->GetRescaleSlope() ); + //writer->SetShift( reader5->GetRescaleIntercept() ); + if( verbose ) + reader5->GetImageAttributes()->PrintFileHeader(); + } +#endif + else if( vtkTIFFReader *reader6 = vtkTIFFReader::SafeDownCast( imgreader ) ) + { + // TIFF has resolution (spacing), and VTK make sure to set set in mm + // For some reason vtkTIFFReader is all skrew up and will load the image in whatever orientation + // as stored on file, thus this is up to the user to set it properly... + // If anyone has any clue why... +#if VTK_MAJOR_VERSION >= 5 && VTK_MINOR_VERSION > 0 + reader6->SetOrientationType( ORIENTATION_BOTLEFT ); +#endif + } +#if VTK_MAJOR_VERSION >= 5 && VTK_MINOR_VERSION > 0 + else if( vtkMetaImageReader *reader7 = vtkMetaImageReader::SafeDownCast( imgreader ) ) + { +// vtkGetMacro(RescaleSlope, double); +// vtkGetMacro(RescaleOffset, double); + writer->SetScale( reader7->GetRescaleSlope() ); + writer->SetShift( reader7->GetRescaleOffset() ); +// vtkGetStringMacro(Modality); + writer->GetMedicalImageProperties()->SetModality( reader7->GetModality() ); + writer->SetFileLowerLeft( lowerleft ); + +// vtkGetStringMacro(DistanceUnits); + // -> this one is insane, the default behavior is 'um' . What in the world is 'um' unit ? + // I think I should discard any non 'mm' distance unit, simple as that + +// The following looks nice from the API, but the VTK implementation only sets them to '?' ... weird +// vtkGetMacro(BitsAllocated, int); +// vtkGetStringMacro(AnatomicalOrientation); +// vtkGetMacro(GantryAngle, double); +// vtkGetStringMacro(PatientName); +// vtkGetStringMacro(PatientID); +// vtkGetStringMacro(Date); +// vtkGetStringMacro(Series); +// vtkGetStringMacro(ImageNumber); +// vtkGetStringMacro(StudyID); +// vtkGetStringMacro(StudyUID); +// vtkGetStringMacro(TransferSyntaxUID); + } +#endif + } + // nothing special need to be done for vtkStructuredPointsReader + + // Handle here the specific modality: + if ( modality ) + { + if( !modality_str.empty() ) + writer->GetMedicalImageProperties()->SetModality( modality_str.c_str() );; + } + + // I would like to use vtkStructuredPointsReader::GetHeader as Image Comments, + // however this is not possible with the current vtkMedicalImageProperties... + if( !image_comments.empty() ) + { + writer->GetMedicalImageProperties()->SetSeriesDescription( image_comments.c_str() );; + } + + // Let's do that at the end to be sure it always overwrite any other default + if( oshift ) + { + writer->SetShift( shift ); + } + if( oscale ) + { + writer->SetScale( scale ); + } + if( oimageformat ) + { + writer->SetImageFormat( imageformat ); + } + + // Pass on the filetime of input file + time_t studydatetime = gdcm::System::FileTime( filename ); + char date[22]; + gdcm::System::FormatDateTime(date, studydatetime); + // ContentDate + const size_t datelen = 8; + { + // Do not copy the whole cstring: + std::string s( date, date+datelen ); + writer->GetMedicalImageProperties()->SetImageDate( s.c_str() );; + } + // ContentTime + const size_t timelen = 6; // get rid of milliseconds + { + // Do not copy the whole cstring: + std::string s( date+datelen, timelen ); + writer->GetMedicalImageProperties()->SetImageTime( s.c_str() );; + } + + writer->Write(); +#if VTK_MAJOR_VERSION >= 5 && VTK_MINOR_VERSION > 0 + if( writer->GetErrorCode() ) + { + std::cerr << "There was an error: " << vtkErrorCode::GetStringFromErrorCode(writer->GetErrorCode()) << std::endl; + return 1; + } +#endif + + if( verbose ) + writer->GetInput()->Print( std::cout ); + writer->Delete(); +} + +cleanup: + if( imgreader ) imgreader->Delete(); + names->Delete(); + xmlreader->Delete(); + datareader->Delete(); + gdcmreader->Delete(); +#if VTK_MAJOR_VERSION >= 5 && VTK_MINOR_VERSION > 0 + dicomreader->Delete(); +#endif + + return retcode; +} diff --git a/gdcm/Utilities/VTK/Applications/gdcmviewer.cxx b/gdcm/Utilities/VTK/Applications/gdcmviewer.cxx new file mode 100644 index 0000000..57facd6 --- /dev/null +++ b/gdcm/Utilities/VTK/Applications/gdcmviewer.cxx @@ -0,0 +1,1011 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + * TODO: vtkPlaybackWidget would be cool for 4D images... + * should I do it here, or a specified 4Dviewer application that will reexecute the reader (TIME* + * stuff in vtk) + */ +#include "vtkGDCMImageReader.h" + +#include "vtkVersion.h" +#include "vtkErrorCode.h" +#include "vtkMedicalImageProperties.h" +#include "vtkXMLImageDataWriter.h" +#include "vtkInteractorStyleImage.h" +#include "vtkCornerAnnotation.h" +#include "vtkPNGWriter.h" +#include "vtkImageShiftScale.h" +#include "vtkOutlineFilter.h" +#include "vtkMath.h" +#include "vtkPolyDataMapper2D.h" +#include "vtkImageReslice.h" +#include "vtkRenderWindowInteractor.h" +#include "vtkImageViewer.h" +#include "vtkPointData.h" +#include "vtkImageMapToColors.h" +#include "vtkLookupTable.h" +#include "vtkActor2D.h" +#include "vtkImageMapToWindowLevelColors.h" +#include "vtkImageActor.h" +#include "vtkWindowToImageFilter.h" +#if VTK_MAJOR_VERSION >= 5 && VTK_MINOR_VERSION > 0 +#include "vtkImageMapToColors16.h" +#include "vtkBalloonWidget.h" +#include "vtkBalloonRepresentation.h" +#include "vtkLogoWidget.h" +#include "vtkLogoRepresentation.h" +#include "vtkAngleWidget.h" +#include "vtkAngleRepresentation2D.h" +#include "vtkBiDimensionalWidget.h" +#include "vtkBiDimensionalRepresentation2D.h" +#include "vtkDistanceWidget.h" +#include "vtkContourWidget.h" +#include "vtkOrientedGlyphContourRepresentation.h" +#include "vtkPointHandleRepresentation2D.h" +#include "vtkDistanceRepresentation2D.h" +#include "vtkLegendScaleActor.h" +#include "vtkProperty2D.h" +#else +class vtkLogoWidget; +class vtkBiDimensionalWidget; +class vtkDistanceWidget; +class vtkLogoRepresentation; +class vtkContourWidget; +class vtkAngleWidget; +#endif +#if VTK_MAJOR_VERSION >= 5 +#include "vtkImageYBRToRGB.h" +#include "vtkImageColorViewer.h" +#else +#include "vtkImageViewer2.h" +#endif +#include "vtkImageData.h" +#include "vtkCommand.h" +#include "vtkRenderer.h" +#include "vtkStringArray.h" +#include "vtkDebugLeaks.h" +#include "vtkWorldPointPicker.h" +#include "vtkMultiThreader.h" + +#include "gdcmFilename.h" +#include "gdcmSystem.h" +#include "gdcmDirectory.h" +#include "gdcmImageHelper.h" +#include "gdcmReader.h" +#include "gdcmTrace.h" +#include "gdcmVersion.h" + +#include +#include +//---------------------------------------------------------------------------- +// vtkImageViewer2 new interface wants SetSlice, but vtkImageViewer does not have +// this new interface (what a pain), so let's fake a new interface to +// vtkImageViewer without patching VTK +class vtkGDCMImageViewer : public vtkImageViewer +{ +public: + vtkTypeRevisionMacro(vtkGDCMImageViewer,vtkImageViewer); + + static vtkGDCMImageViewer *New() + { +#ifdef VTK_DEBUG_LEAKS + vtkDebugLeaks::ConstructClass("vtkGDCMImageViewer"); +#endif + return new vtkGDCMImageViewer; + } + int GetSlice() { return this->GetZSlice(); } + void SetSlice(int s) { this->SetZSlice(s); } + + int GetSliceMin() { return this->GetWholeZMin(); } + int GetSliceMax() { return this->GetWholeZMax(); } +#if VTK_MAJOR_VERSION >= 5 + // TODO: + void AddInputConnection(vtkAlgorithmOutput* input) {(void)input;} +#else + void AddInput(vtkImageData * input) {(void)input;} +#endif + double GetOverlayVisibility() { return 0; } + void SetOverlayVisibility(double vis) {(void)vis;} +}; +vtkCxxRevisionMacro(vtkGDCMImageViewer, "$Revision: 1.30 $") +vtkInstantiatorNewMacro(vtkGDCMImageViewer) + +#if VTK_MAJOR_VERSION >= 5 +#else +class vtkImageColorViewer : public vtkImageViewer2 +{ +public: + vtkTypeRevisionMacro(vtkImageColorViewer,vtkImageViewer2); + + static vtkImageColorViewer *New() + { +#ifdef VTK_DEBUG_LEAKS + vtkDebugLeaks::ConstructClass("vtkImageColorViewer"); +#endif + return new vtkImageColorViewer; + } + vtkImageColorViewer() { + OverlayImageActor = vtkImageActor::New(); + } + ~vtkImageColorViewer() { + OverlayImageActor->Delete(); + } + double GetOverlayVisibility() { return 0; } + void SetOverlayVisibility(double vis) {} + void AddInput(vtkImageData * input) + { + vtkRenderWindow *renwin = this->GetRenderWindow (); + renwin->SetNumberOfLayers(2); + vtkRenderer *Renderer = vtkRenderer::New(); + Renderer->SetLayer(0); + //OverlayImageActor->SetOpacity(0.5); + //OverlayImageActor->GetProperty()->SetOpacity(1.0); + vtkImageMapToWindowLevelColors *WindowLevel = vtkImageMapToWindowLevelColors::New(); + WindowLevel->SetInput(input); + OverlayImageActor->SetInput(WindowLevel->GetOutput()); + Renderer->AddProp(OverlayImageActor); + OverlayImageActor->SetVisibility(1); + + renwin->AddRenderer(Renderer); + Renderer->Delete(); + WindowLevel->Delete(); + } +private: + vtkImageActor *OverlayImageActor; +}; +vtkCxxRevisionMacro(vtkImageColorViewer, "$Revision: 1.30 $") +vtkInstantiatorNewMacro(vtkImageColorViewer) +#endif + +//---------------------------------------------------------------------------- +// Callback for the interaction +template +class vtkGDCMObserver : public vtkCommand +{ +public: + static vtkGDCMObserver *New() + { + return new vtkGDCMObserver; + } + vtkGDCMObserver() + { + ImageViewer = NULL; + IconWidget = NULL; + DistanceWidget = NULL; + BiDimWidget = NULL; + AngleWidget = NULL; + ContourWidget = NULL; + picker = vtkWorldPointPicker::New(); + } + ~vtkGDCMObserver() + { + picker->Delete(); + } + virtual void Execute(vtkObject *caller, unsigned long event, void* /*calldata*/) + { + if ( this->ImageViewer ) + { + vtkRenderWindowInteractor * rwi = vtkRenderWindowInteractor::SafeDownCast( caller ); + if ( event == vtkCommand::CharEvent ) + { + char keycode = 0; + if( rwi ) keycode = rwi->GetKeyCode(); + // 'o' is a special key for overlay visibility + if ( keycode == 'o' ) + { + ImageViewer->SetOverlayVisibility( 1 - ImageViewer->GetOverlayVisibility() ); + ImageViewer->Render(); + //std::cerr << ImageViewer->GetOverlayVisibility() << std::endl; + } + else if ( keycode == 's' ) + { + vtkPNGWriter * writer = vtkPNGWriter::New(); + vtkWindowToImageFilter * w2i = vtkWindowToImageFilter::New(); + w2i->SetInput( rwi->GetRenderWindow() ); +#if (VTK_MAJOR_VERSION >= 6) + writer->SetInputConnection( w2i->GetOutputPort() ); +#else + writer->SetInput( w2i->GetOutput() ); +#endif + writer->SetFileName( "snapshot.png" ); + writer->Write(); + writer->Delete(); + w2i->Delete(); + //std::cerr << "Screenshort saved to snapshot.png" << std::endl; + } +#if VTK_MAJOR_VERSION >= 5 && VTK_MINOR_VERSION > 0 + else if ( keycode == 'l' ) + { + IconWidget->Off(); + } + else if ( keycode == 'a' ) + { + AngleWidget->On(); + } + else if ( keycode == 'b' ) + { + BiDimWidget->On(); + } + else if ( keycode == 'c' ) + { + ContourWidget->On(); + } + else if ( keycode == 'd' ) + { + DistanceWidget->On(); + } + else if ( keycode == 'p' ) + { + } +#endif + else + { +#if (VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 ) + int max = ImageViewer->GetSliceMax(); + int slice = (ImageViewer->GetSlice() + 1) % ++max; + ImageViewer->SetSlice( slice ); + ImageViewer->GetRenderer()->ResetCamera(); +#else + int max = ImageViewer->GetWholeZMax(); + int slice = (ImageViewer->GetZSlice() + 1 ) % ++max; + ImageViewer->SetZSlice( slice ); + ImageViewer->GetRenderer()->ResetCameraClippingRange(); +#endif + ImageViewer->Render(); + } + } + else if ( event == vtkCommand::EndPickEvent ) + { + //std::cerr << "EndPickEvent" << std::endl; + int *pick = rwi->GetEventPosition(); + vtkRenderer *ren1 = ImageViewer->GetRenderer(); + picker->Pick((double)pick[0], (double)pick[1], 0.0, ren1); + vtkFloatingPointType *pos = picker->GetPickPosition (); + std::cout << pos[0] << "," << pos[1] << "," << pos[2] << std::endl; + } + else + { + std::cerr << "Unhandled even:" << event << std::endl; + } + } + } + TViewer *ImageViewer; + vtkWorldPointPicker *picker; + vtkLogoWidget *IconWidget; + vtkDistanceWidget *DistanceWidget; + vtkAngleWidget *AngleWidget; + vtkBiDimensionalWidget *BiDimWidget; + vtkContourWidget *ContourWidget; + +}; + +int verbose; + +#if VTK_MAJOR_VERSION >= 5 && VTK_MINOR_VERSION > 0 +class vtkBalloonCallback : public vtkCommand +{ +public: + static vtkBalloonCallback *New() + { return new vtkBalloonCallback; } + virtual void Execute(vtkObject *caller, unsigned long, void*) + { + vtkBalloonWidget *balloonWidget = reinterpret_cast(caller); + if ( balloonWidget->GetCurrentProp() != NULL ) + { + cout << "Prop selected\n"; + } + } +}; +#endif + +void FillCornerFromMedProp( vtkCornerAnnotation *ca, vtkMedicalImageProperties *medprop ) +{ + std::string bottomleft = "S: "; + if( medprop->GetSeriesNumber() ) + bottomleft += medprop->GetSeriesNumber(); + bottomleft += "\nI: "; + if( medprop->GetImageNumber() ) + bottomleft += medprop->GetImageNumber(); + bottomleft += "\n"; + ca->SetText(0, bottomleft.c_str()); + if( medprop->GetStationName() ) + { + const std::string bottomright = medprop->GetStationName(); + ca->SetText(1, bottomright.c_str()); + } + std::string topleft; + if( medprop->GetInstitutionName() ) + topleft += medprop->GetInstitutionName(); + topleft += "\n"; + if( medprop->GetPatientName() ) + topleft += medprop->GetPatientName(); + ca->SetText(2, topleft.c_str()); + std::string topright; + if( medprop->GetStudyDate() ) + topright += medprop->GetStudyDate(); + topright += "\n"; + if( medprop->GetAcquisitionTime() ) + topright += medprop->GetAcquisitionTime(); + ca->SetText(3, topright.c_str()); +} + +// A feature in VS6 make it painfull to write template code +// that do not contain the template parameter in the function +// signature. Thus always pass parameter in the function: +template +void ExecuteViewer(TViewer *viewer, vtkStringArray *filenames) +{ + vtkGDCMImageReader *reader = vtkGDCMImageReader::New(); + if( filenames->GetSize() == 1 ) // Backward compatible... + { + reader->SetFileName( filenames->GetValue(0) ); + } + else + { + reader->SetFileNames( filenames ); + } + + vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New(); + // For a single medical image, it would be more efficient to use + // 0028|1050 [DS] [Window Center] + // 0028|1051 [DS] [Window Width] + // but gdcmviewer doesn't know about them :-( + + //reader->FileLowerLeftOn(); + reader->Update(); + if( reader->GetErrorCode() ) + { + std::cerr << "There was an error: " << vtkErrorCode:: + GetStringFromErrorCode(reader->GetErrorCode()) << std::endl; + return; + } + + //reader->Print( cout ); + if( verbose ) + reader->GetOutput()->Print( cout ); + //reader->GetOutput(1)->Print( cout ); + vtkFloatingPointType range[2]; + reader->GetOutput()->GetScalarRange(range); +#if (VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 ) + viewer->SetInputConnection ( reader->GetOutputPort(0) ); + // Technically we could just simple always call AddInputConnection on the overlay + // but there is something wrong going on, when overlay visibility is set to 0 at startup + // thus we need to make it visible by default which is annoying, so activate only + // if overlays are found: + if( reader->GetNumberOfOverlays() ) + { + // Add first overlay: + // WARNING: gdcmviewer2 only ! + viewer->AddInputConnection ( reader->GetOverlayPort(0) ); + } + // TODO: Icon can be added using the vtkLogoWidget +#if VTK_MAJOR_VERSION >= 5 && VTK_MINOR_VERSION > 0 + vtkPointHandleRepresentation2D *handle = vtkPointHandleRepresentation2D::New(); + handle->GetProperty()->SetColor(1,0,0); + vtkDistanceRepresentation2D *drep = vtkDistanceRepresentation2D::New(); + drep->SetHandleRepresentation(handle); + handle->Delete(); + + vtkDistanceWidget *dwidget = vtkDistanceWidget::New(); + dwidget->SetInteractor(iren); + dwidget->CreateDefaultRepresentation(); + dwidget->SetRepresentation(drep); + drep->Delete(); + + vtkAngleRepresentation2D *anglerep = vtkAngleRepresentation2D::New(); + vtkAngleWidget *anglewidget = vtkAngleWidget::New(); + anglewidget->SetInteractor(iren); + anglewidget->SetRepresentation(anglerep); + anglerep->Delete(); + + vtkBiDimensionalRepresentation2D *brep = vtkBiDimensionalRepresentation2D::New(); + vtkBiDimensionalWidget *bwidget = vtkBiDimensionalWidget::New(); + bwidget->SetInteractor(iren); + bwidget->SetRepresentation(brep); + brep->Delete(); + + vtkOrientedGlyphContourRepresentation *contourRep = vtkOrientedGlyphContourRepresentation::New(); + vtkContourWidget *contourWidget = vtkContourWidget::New(); + contourWidget->SetInteractor(iren); + contourWidget->SetRepresentation(contourRep); + contourRep->Delete(); + + vtkBalloonRepresentation *balloonrep = vtkBalloonRepresentation::New(); + balloonrep->SetBalloonLayoutToImageRight(); + + vtkBalloonWidget *balloonwidget = vtkBalloonWidget::New(); + balloonwidget->SetInteractor(iren); + balloonwidget->SetRepresentation(balloonrep); + balloonrep->Delete(); + //balloonwidget->AddBalloon(viewer->GetImageActor(),"This is a DICOM image",NULL); + + vtkBalloonCallback *cbk = vtkBalloonCallback::New(); + balloonwidget->AddObserver(vtkCommand::WidgetActivateEvent,cbk); + + vtkLogoWidget * iconwidget = 0; + if( reader->GetNumberOfIconImages() ) + { + vtkLogoRepresentation *rep = vtkLogoRepresentation::New(); + rep->SetImage(reader->GetIconImage()); + //reader->GetIconImage()->Print( std::cout ); + if( reader->GetIconImage()->GetPointData()->GetScalars() + && reader->GetIconImage()->GetPointData()->GetScalars()->GetLookupTable() ) + { + vtkLookupTable *lut = reader->GetIconImage()->GetPointData()->GetScalars()->GetLookupTable(); + vtkImageMapToColors *map = vtkImageMapToColors::New (); +#if (VTK_MAJOR_VERSION >= 6) + map->SetInputData(reader->GetIconImage()); +#else + map->SetInput (reader->GetIconImage()); +#endif + map->SetLookupTable ( lut ); + //FIXME there is no way to know the type of LUT the icon is using: + //if( reader->GetImageFormat() == VTK_LOOKUP_TABLE ) + { + map->SetOutputFormatToRGB(); + } + //else if( reader->GetImageFormat() == VTK_INVERSE_LUMINANCE ) + // { + // map->SetOutputFormatToLuminance(); + // } + map->Update(); + //map->GetOutput()->GetScalarRange(range); + //viewer->SetInput( map->GetOutput() ); + //map->GetOutput()->Print( std::cout ); + rep->SetImage( map->GetOutput() ); + map->Delete(); + + //vtkPNGWriter *iconw = vtkPNGWriter::New(); + //iconw->SetInput( map->GetOutput() ); + //iconw->SetFileName( "/tmp/icon.png" ); + //iconw->Write(); + //iconw->Delete(); + + } + + //reader->GetIconImage()->Print( std::cout ); + + //vtkPropCollection *pc = vtkPropCollection::New(); + //rep->GetActors2D(pc); + //balloonwidget->AddBalloon(pc->GetLastProp(),"This is a DICOM thumbnail image",NULL); + + vtkLogoWidget *widget = vtkLogoWidget::New(); + widget->SetInteractor(iren); + widget->SetRepresentation(rep); + iconwidget = widget; + //widget->Delete(); + rep->Delete(); + + //viewer->AddInputConnection ( reader->GetIconImagePort() ); + } +#endif +#else + viewer->SetInput( reader->GetOutput(0) ); + if( reader->GetNumberOfOverlays() ) + { + viewer->AddInput( reader->GetOverlay(0) ); + } +#endif /*(VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 )*/ + + // IconImage: + //if( reader->GetNumberOfIconImages() ) + // { + // std::cerr << "NumberOfIconImages:" << reader->GetNumberOfIconImages() << std::endl; + // reader->GetIconImage()->Print( std::cerr ); + // vtkPNGWriter *writer = vtkPNGWriter::New(); + // writer->SetInput( reader->GetIconImage() ); + // writer->SetFileName( "icon.png" ); + // //writer->Write(); + // writer->Delete(); + // } + + // In case of palette color, let's tell VTK to map color: + // MONOCHROME1 is also implemented with a lookup table + if( reader->GetImageFormat() == VTK_LOOKUP_TABLE || reader->GetImageFormat() == VTK_INVERSE_LUMINANCE ) + { +#if VTK_MAJOR_VERSION >= 5 && VTK_MINOR_VERSION > 0 + assert( reader->GetOutput()->GetPointData()->GetScalars() + && reader->GetOutput()->GetPointData()->GetScalars()->GetLookupTable() ); +#endif + //convert to color: + vtkLookupTable *lut = reader->GetOutput()->GetPointData()->GetScalars()->GetLookupTable(); + if( !lut ) + { + // This must be a Segmented Palette and on VTK 4.4 this is not supported + std::cerr << "Not implemented. You will not see the Color LUT" << std::endl; + } +#if VTK_MAJOR_VERSION >= 5 && VTK_MINOR_VERSION > 0 + if( lut->IsA( "vtkLookupTable16" ) ) + { + vtkImageMapToColors16 *map = vtkImageMapToColors16::New (); +#if (VTK_MAJOR_VERSION >= 6) + map->SetInputConnection (reader->GetOutputPort()); +#else + map->SetInput (reader->GetOutput()); +#endif + map->SetLookupTable (reader->GetOutput()->GetPointData()->GetScalars()->GetLookupTable()); + if( reader->GetImageFormat() == VTK_LOOKUP_TABLE ) + { + map->SetOutputFormatToRGB(); + } + else if( reader->GetImageFormat() == VTK_INVERSE_LUMINANCE ) + { + map->SetOutputFormatToLuminance(); + } + map->Update(); + map->GetOutput()->GetScalarRange(range); +#if (VTK_MAJOR_VERSION >= 6) + viewer->SetInputConnection( map->GetOutputPort() ); +#else + viewer->SetInput( map->GetOutput() ); +#endif + map->Delete(); + } + else +#endif + { + vtkImageMapToColors *map = vtkImageMapToColors::New (); +#if (VTK_MAJOR_VERSION >= 6) + map->SetInputConnection (reader->GetOutputPort()); +#else + map->SetInput (reader->GetOutput()); +#endif + map->SetLookupTable (reader->GetOutput()->GetPointData()->GetScalars()->GetLookupTable()); + if( reader->GetImageFormat() == VTK_LOOKUP_TABLE ) + { + map->SetOutputFormatToRGB(); + } + else if( reader->GetImageFormat() == VTK_INVERSE_LUMINANCE ) + { + map->SetOutputFormatToLuminance(); + } + map->Update(); + map->GetOutput()->GetScalarRange(range); +#if (VTK_MAJOR_VERSION >= 6) + viewer->SetInputConnection( map->GetOutputPort() ); +#else + viewer->SetInput( map->GetOutput() ); +#endif + map->Delete(); + } + } + else if( reader->GetImageFormat() == VTK_YBR ) + { +#if VTK_MAJOR_VERSION >= 5 + vtkImageYBRToRGB *filter = vtkImageYBRToRGB::New(); +#if (VTK_MAJOR_VERSION >= 6) + filter->SetInputConnection( reader->GetOutputPort() ); +#else + filter->SetInput( reader->GetOutput() ); +#endif + filter->Update(); + filter->GetOutput()->GetScalarRange(range); +#if (VTK_MAJOR_VERSION >= 6) + viewer->SetInputConnection( filter->GetOutputPort() ); +#else + viewer->SetInput( filter->GetOutput() ); +#endif + filter->Delete(); +#else + std::cerr << "Not implemented" << std::endl; +#endif + } + else if( reader->GetImageFormat() == VTK_RGB + || reader->GetImageFormat() == VTK_RGBA ) + { + // easy case ! + } +// vtkImageShiftScale *ss = vtkImageShiftScale::New(); +// ss->SetInput( reader->GetOutput() ); +// ss->SetShift( -1024 ); +// ss->SetOutputScalarTypeToShort(); +// ss->Update(); +// ss->GetOutput()->GetScalarRange(range); +// viewer->SetInput( ss->GetOutput() ); +// ss->Delete(); + + if( reader->GetCurve() ) + { + vtkPolyDataMapper2D * rectMapper = vtkPolyDataMapper2D::New(); +#if (VTK_MAJOR_VERSION >= 6) + rectMapper->SetInputData( reader->GetCurve() ); +#else + rectMapper->SetInput( reader->GetCurve() ); +#endif + + vtkActor2D * rectActor = vtkActor2D::New(); + rectActor->SetMapper( rectMapper ); + viewer->GetRenderer()->AddActor2D( rectActor ); + rectActor->Delete(); + rectMapper->Delete(); + } + +#if 0 + vtkImageReslice * slicer = vtkImageReslice::New(); + slicer->SetInput( reader->GetOutput() ); + slicer->InterpolateOn(); + //slicer->SetResliceAxesOrigin(0, 0, 0); + //slicer->SetResliceAxesOrigin( reader->GetImagePositionPatient() ); + //slicer->SetResliceAxes( reader->GetDirectionCosines() ); + const double *dircos = reader->GetImageOrientationPatient(); + double dcos[9]; + for(int i=0;i<6;++i) + dcos[i] = dircos[i]; + dcos[6] = dircos[1] * dircos[5] - dircos[2] * dircos[4]; + dcos[7] = dircos[2] * dircos[3] - dircos[0] * dircos[5]; + dcos[8] = dircos[0] * dircos[4] - dircos[3] * dircos[1]; + double dummy[3]; + double dot = vtkMath::Dot(dircos, dircos+3); + std::cout << dot << std::endl; + vtkMath::Cross(dircos, dircos+3, dummy); + std::cout << dcos[6] << "," << dcos[7] << "," << dcos[8] << std::endl; + std::cout << dummy[0] << "," << dummy[1] << "," << dummy[2] << std::endl; + dot = vtkMath::Dot(dircos, dummy); + std::cout << dot << std::endl; + dot = vtkMath::Dot(dircos+3, dummy); + std::cout << dot << std::endl; + slicer->SetResliceAxesDirectionCosines(dcos); + slicer->Update(); + slicer->GetOutput()->Print( std::cout ); + //viewer->SetInput( slicer->GetOutput() ); + vtkOutlineFilter * outline = vtkOutlineFilter::New(); + outline->SetInput( slicer->GetOutput() ); + outline->GetOutput()->Print( std::cout ); + //slicer->AddInput( (vtkPolyData*)outline->GetOutput() ); +#endif + + // Always overwriting default is not always nice looking... + viewer->SetColorLevel (0.5 * (range[1] + range[0])); + viewer->SetColorWindow (range[1] - range[0]); + if( verbose ) + std::cout << "Range: " << range[0] << " " << range[1] << std::endl; + + viewer->SetupInteractor (iren); + +// vtkInteractorStyleImage *is = viewer->GetInteractorStyle(); +// viewer->GetInteractorStyle()->AutoAdjustCameraClippingRangeOn(); + vtkCornerAnnotation * ca = vtkCornerAnnotation::New(); + ca->SetImageActor( viewer->GetImageActor() ); + ca->SetWindowLevel( (vtkImageMapToWindowLevelColors*)viewer->GetWindowLevel() ); + vtkMedicalImageProperties * medprop = reader->GetMedicalImageProperties(); + FillCornerFromMedProp( ca, medprop ); +#if VTK_MAJOR_VERSION >= 5 + viewer->GetRenderer()->AddViewProp( ca ); +#else + viewer->GetRenderer()->AddProp( ca ); +#endif + + int dims[3]; + reader->GetOutput()->GetDimensions(dims); + // Make sure to display on most screen + dims[0] = (dims[0] < 600 ) ? dims[0] : 600; + dims[1] = (dims[1] < 600 ) ? dims[1] : 600; + viewer->Render(); // EXTREMELY IMPORTANT for vtkImageViewer2 + viewer->GetRenderer()->ResetCamera(); + + viewer->SetSize( dims ); + + // Here is where we setup the observer, + vtkGDCMObserver *obs = vtkGDCMObserver::New(); + obs->ImageViewer = viewer; +#if VTK_MAJOR_VERSION >= 5 && VTK_MINOR_VERSION > 0 + if(iconwidget) iconwidget->On(); + obs->IconWidget = iconwidget; + obs->DistanceWidget = dwidget; + obs->AngleWidget = anglewidget; + obs->BiDimWidget = bwidget; + obs->ContourWidget = contourWidget; + balloonwidget->On(); +#endif + iren->AddObserver(vtkCommand::CharEvent,obs); + iren->AddObserver(vtkCommand::EndPickEvent,obs); + obs->Delete(); + + //vtkLegendScaleActor *legend = vtkLegendScaleActor::New(); + //viewer->GetRenderer()->AddActor( legend ); + + iren->Initialize(); + iren->Start(); + + //if you wish you can export dicom to a vtk file +#if 0 + vtkXMLImageDataWriter *writer = vtkXMLImageDataWriter::New(); + writer->SetInputConnection( reader->GetOutputPort()); + writer->SetFileName( "debug.vtk" ); + writer->SetDataModeToBinary(); + writer->Write(); + writer->Delete(); +#endif + +#if 0 + vtkPNGWriter *writer = vtkPNGWriter::New(); + //writer->SetInputConnection( reader->GetOutputPort() ); + writer->SetInputConnection( reader->GetOutputPort(1) ); + //range = overlay->GetScalarRange(); + //std::cerr << "Range: " << range[0] << " " << range[1] << std::endl; + //overlay->Print( std::cout ); + //writer->SetInput( overlay ); + writer->SetFileName( "debug.png" ); + writer->Write(); + writer->Delete(); +#endif + + reader->Delete(); +#if VTK_MAJOR_VERSION >= 5 && VTK_MINOR_VERSION > 0 + cbk->Delete(); + dwidget->Off(); + balloonwidget->Off(); + balloonwidget->Delete(); + dwidget->Delete(); + anglewidget->Off(); + anglewidget->Delete(); + bwidget->Off(); + bwidget->Delete(); + contourWidget->Off(); + contourWidget->Delete(); + if( iconwidget ) + { + iconwidget->Off(); + iconwidget->Delete(); + } +#endif + iren->Delete(); + viewer->Delete(); +} + +void PrintVersion() +{ + std::cout << "gdcmviewer: gdcm " << gdcm::Version::GetVersion() << " "; + const char date[] = "$Date$"; + std::cout << date << std::endl; + //std::cout << " VTK " << vtkVersion::GetVTKVersion() << std::endl; + std::cout << " " << vtkVersion::GetVTKSourceVersion() << std::endl; +} + +void PrintHelp() +{ + PrintVersion(); + std::cout << "Usage: gdcmviewer [OPTION] filename1.dcm [filename2.dcm...]" << std::endl; + std::cout << "or : gdcmviewer [OPTION] directory" << std::endl; + std::cout << "Display a DICOM image file.\n"; + std::cout << "Options:" << std::endl; + std::cout << " --force-rescale force rescale." << std::endl; + std::cout << " --force-spacing force spacing." << std::endl; + std::cout << " -r --recursive Recusively descend directory." << std::endl; + std::cout << "General Options:" << std::endl; + std::cout << " -V --verbose more verbose (warning+error)." << std::endl; + std::cout << " -W --warning print warning info." << std::endl; + std::cout << " -D --debug print debug info." << std::endl; + std::cout << " -E --error print error info." << std::endl; + std::cout << " -h --help print help." << std::endl; + std::cout << " -v --version print version." << std::endl; +} + + +int main(int argc, char *argv[]) +{ + int c; + //int digit_optind = 0; + + std::vector filenames; + int forcerescale = 0; + int forcespacing = 0; + int recursive = 0; + + verbose = 0; + int warning = 0; + int debug = 0; + int error = 0; + int help = 0; + int version = 0; + + while (1) { + //int this_option_optind = optind ? optind : 1; + int option_index = 0; + static struct option long_options[] = { + {"force-rescale", 0, &forcerescale, 1}, + {"force-spacing", 0, &forcespacing, 1}, + {"recursive", 0, &recursive, 1}, + +// General options ! + {"verbose", 0, &verbose, 1}, + {"warning", 0, &warning, 1}, + {"debug", 0, &debug, 1}, + {"error", 0, &error, 1}, + {"help", 0, &help, 1}, + {"version", 0, &version, 1}, + + {0, 0, 0, 0} + }; + + c = getopt_long (argc, argv, "rVWDEhv", + long_options, &option_index); + if (c == -1) + { + break; + } + + switch (c) + { + case 0: + { + const char *s = long_options[option_index].name; (void)s; + //printf ("option %s", s); + if (optarg) + { + if( option_index == 0 ) /* input */ + { + assert( strcmp(s, "input") == 0 ); + //assert( filename.empty() ); + //filename = optarg; + } + printf (" with arg %s", optarg); + } + //printf ("\n"); + } + break; + + case 'r': + recursive = 1; + break; + + case 'V': + verbose = 1; + break; + + case 'W': + warning = 1; + break; + + case 'D': + debug = 1; + break; + + case 'E': + error = 1; + break; + + case 'h': + help = 1; + break; + + case 'v': + version = 1; + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + //printf ("non-option ARGV-elements: "); + while (optind < argc) + { + //printf ("%s ", argv[optind]); + filenames.push_back( argv[optind++] ); + } + //printf ("\n"); + } + + if( version ) + { + //std::cout << "version" << std::endl; + PrintVersion(); + return 0; + } + + if( help ) + { + //std::cout << "help" << std::endl; + PrintHelp(); + return 0; + } + + // Debug is a little too verbose + gdcm::Trace::SetDebug( debug ); + gdcm::Trace::SetWarning( warning ); + gdcm::Trace::SetError( error ); + // when verbose is true, make sure warning+error are turned on: + if( verbose ) + { + gdcm::Trace::SetWarning( verbose ); + gdcm::Trace::SetError( verbose); + } + + //vtkMultiThreader::SetGlobalMaximumNumberOfThreads(1); + gdcm::ImageHelper::SetForceRescaleInterceptSlope(forcerescale); + gdcm::ImageHelper::SetForcePixelSpacing(forcespacing); + + if( filenames.empty() ) + { + PrintHelp(); + return 1; + } + gdcm::Reader testreader; + vtkStringArray *names = vtkStringArray::New(); + { + // Is it a single directory ? If so loop over all files contained in it: + //const char *filename = argv[1]; + if( filenames.size() == 1 && gdcm::System::FileIsDirectory( filenames[0].c_str() ) ) + { + if( verbose ) + std::cout << "Loading directory: " << filenames[0] << std::endl; + gdcm::Directory d; + d.Load(filenames[0].c_str(), recursive); + gdcm::Directory::FilenamesType const &files = d.GetFilenames(); + for( gdcm::Directory::FilenamesType::const_iterator it = files.begin(); it != files.end(); ++it ) + { + testreader.SetFileName( it->c_str() ); + if( testreader.CanRead() ) + { + names->InsertNextValue( it->c_str() ); + } + else + { + if(verbose) + std::cerr << "Discarding non DICOM file: " << it->c_str() << std::endl; + } + } + } + else // list of files passed directly on the cmd line: + // discard non-existing or directory + { + //for(int i=1; i < argc; ++i) + for(std::vector::const_iterator it = filenames.begin(); it != filenames.end(); ++it) + { + //filename = argv[i]; + const std::string & filename = *it; + if( gdcm::System::FileExists( filename.c_str() ) ) + { + if( gdcm::System::FileIsDirectory( filename.c_str() ) ) + { + if(verbose) + std::cerr << "Discarding directory: " << filename << std::endl; + } + else + { + testreader.SetFileName( filename.c_str() ); + if( testreader.CanRead() ) + { + names->InsertNextValue( filename.c_str() ); + } + else + { + if(verbose) + std::cerr << "Discarding non DICOM file: " << filename.c_str() << std::endl; + } + } + } + else + { + if(verbose) + std::cerr << "Discarding non existing file: " << filename << std::endl; + } + } + } + //names->Print( std::cout ); + } + + vtkImageColorViewer *viewer = vtkImageColorViewer::New(); + ExecuteViewer(viewer, names); + + names->Delete(); + + return 0; +} diff --git a/gdcm/Utilities/VTK/AssemblyInfo.cs.in b/gdcm/Utilities/VTK/AssemblyInfo.cs.in new file mode 100644 index 0000000..4782fc4 --- /dev/null +++ b/gdcm/Utilities/VTK/AssemblyInfo.cs.in @@ -0,0 +1,73 @@ +#region License +/*========================================================================= + + BSD License [http://www.opensource.org/licenses/bsd-license.php] + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither name of Mathieu Malaterre, or CREATIS, nor the names of any + contributors (CNRS, INSERM, UCB, Universite Lyon I), may be used to + endorse or promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=========================================================================*/ +#endregion License + +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following +// attributes. +// +// change them to the information which is associated with the assembly +// you compile. + +[assembly: AssemblyTitle("VTK-GDCM Framework Binding For .NET")] +[assembly: AssemblyDescription("VTK-GDCM Framework Binding For .NET")] +[assembly: AssemblyConfiguration("Retail")] +[assembly: AssemblyCompany("GDCM -- http://gdcm.sourceforge.net")] +[assembly: AssemblyProduct("vtkgdcm-sharp.dll")] +[assembly: AssemblyDefaultAlias("vtkgdcm-sharp")] +[assembly: AssemblyCopyright("Copyright ©2006-2011 Mathieu Malaterre. All rights reserved.")] +[assembly: AssemblyTrademark("GDCM -- http://gdcm.sourceforge.net")] +[assembly: AssemblyCulture("")] + +// The assembly version has following format : +// +// Major.Minor.Build.Revision +// +// You can specify all values by your own or you can build default build and revision +// numbers with the '*' character (the default): + +[assembly: AssemblyVersion("@GDCM_API_VERSION@")] +[assembly: AssemblyFileVersion("@GDCM_API_VERSION@")] +[assembly: AssemblyInformationalVersion("@GDCM_API_VERSION@")] + +// The following attributes specify the key for the sign of your assembly. See the +// .NET Framework documentation for more information about signing. +// This is not required, if you don't want signing let these attributes like they're. +[assembly: AssemblyDelaySign(false)] +[assembly: AssemblyKeyFile("key.snk")] +//[assembly: AssemblyKeyName("")] diff --git a/gdcm/Utilities/VTK/CMakeLists.txt b/gdcm/Utilities/VTK/CMakeLists.txt new file mode 100644 index 0000000..5563d47 --- /dev/null +++ b/gdcm/Utilities/VTK/CMakeLists.txt @@ -0,0 +1,816 @@ +project(vtkgdcm) +# We need VTK +# Technically we require VTK 5.0 and above + +# Define the src for the vtk-gdcm bridge +set(vtkgdcm_SRCS + vtkGDCMTesting.cxx + vtkGDCMImageReader.cxx + vtkGDCMImageWriter.cxx + vtkGDCMMedicalImageProperties.cxx + ) + +if(GDCM_HAVE_PTHREAD_H AND CMAKE_USE_PTHREADS) + set(vtkgdcm_SRCS ${vtkgdcm_SRCS} + vtkGDCMThreadedImageReader.cxx + ) +endif() + +include(${VTK_USE_FILE}) + +if( ${VTK_MAJOR_VERSION} GREATER 5 ) + list(APPEND vtkgdcm_SRCS + vtkGDCMImageReader2.cxx + ) +endif() + +include(CheckCXXSourceCompiles) +set(CMAKE_REQUIRED_INCLUDES ${VTK_INCLUDE_DIRS}) +CHECK_CXX_SOURCE_COMPILES( + "\#include \nint main() { vtkSmartVolumeMapper* p; return 0;}" + VTK_HAS_SMARTVOLUMEMAPPER) +CHECK_CXX_SOURCE_COMPILES( + "\#include \nint main() { vtkImageResliceMapper* p; return 0;}" + VTK_HAS_IMAGERESLICEMAPPER) + +include_directories( + ${GDCM_BINARY_DIR}/Source/Common + ${GDCM_SOURCE_DIR}/Source/Common + ${GDCM_SOURCE_DIR}/Source/DataStructureAndEncodingDefinition + ${GDCM_SOURCE_DIR}/Source/MediaStorageAndFileFormat + ${GDCM_SOURCE_DIR}/Source/DataDictionary + ${GDCM_SOURCE_DIR}/Utilities/VTK + ) + +# FIXME: temp fix +#if(UNIX) +# link_directories(/usr/X11R6/lib) +#endif() + +# List the kits from VTK that are needed by this project. +if("${VTK_MAJOR_VERSION}" LESS 6) + set(vtkgdcm_LIBS + vtkCommon + vtkIO + vtkImaging + ) + if(VTK_USE_RENDERING) + set(vtkgdcm_LIBS + ${vtkgdcm_LIBS} + vtkRendering + ) + endif() +else() + set(vtkgdcm_LIBS + vtkCommonCore + vtkImagingCore + vtkImagingSources + vtkIOImage + vtksys + ) + set(vtkgdcm_COND_LIBS + vtkIOMPIImage + vtkInteractionStyle + vtkRenderingCore + vtkRenderingFreeType + vtkRenderingFreeTypeOpenGL + vtkRenderingOpenGL + ) + foreach(TMP_LIB ${VTK_LIBRARIES}) + foreach(TRY_LIB ${vtkgdcm_COND_LIBS}) + if("${TMP_LIB}" STREQUAL "${TRY_LIB}") + set(vtkgdcm_LIBS ${vtkgdcm_LIBS} "${TRY_LIB}") + endif() + endforeach() + endforeach() +endif() + +# Use wrapping hints for this project. +#set(VTK_WRAP_HINTS "${PROJECT_SOURCE_DIR}/hints") + +set(VTKGDCM_NAME vtkgdcm CACHE STRING "vtk-gdcm lib name") +mark_as_advanced(VTKGDCM_NAME) + +# Create the instantiator for these classes. +# FIXME: Are instantiator really needed when only doing python wrapping ? +if( "${VTK_MAJOR_VERSION}.${VTK_MINOR_VERSION}" LESS 4.5 ) + set(vtkgdcm_SRCS ${vtkgdcm_SRCS} + ${CMAKE_CURRENT_SOURCE_DIR}/VTK4/vtkMedicalImageProperties.cxx + ${CMAKE_CURRENT_SOURCE_DIR}/VTK4/vtkStringArray.cxx + ) + # Setup vtkInstantiator registration for this library's classes. + include_directories( + ${GDCM_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/VTK4 + ) + VTK_MAKE_INSTANTIATOR2( + "${VTKGDCM_NAME}Instantiator" + vtkgdcmInstantiator_SRCS + "${vtkgdcm_SRCS}" + EXPORT_MACRO "" #GDCM_EXPORT + HEADER_LOCATION ${GDCM_BINARY_DIR} + ) +else() + set(vtkgdcm_SRCS ${vtkgdcm_SRCS} + ${CMAKE_CURRENT_SOURCE_DIR}/vtkImageMapToWindowLevelColors2.cxx + ${CMAKE_CURRENT_SOURCE_DIR}/vtkImageYBRToRGB.cxx + ${CMAKE_CURRENT_SOURCE_DIR}/vtkImageRGBToYBR.cxx + ${CMAKE_CURRENT_SOURCE_DIR}/vtkGDCMPolyDataReader.cxx + ${CMAKE_CURRENT_SOURCE_DIR}/vtkGDCMPolyDataWriter.cxx + ${CMAKE_CURRENT_SOURCE_DIR}/vtkRTStructSetProperties.cxx + ${CMAKE_CURRENT_SOURCE_DIR}/vtkLookupTable16.cxx + ${CMAKE_CURRENT_SOURCE_DIR}/vtkImageMapToColors16.cxx + #${CMAKE_CURRENT_SOURCE_DIR}/vtkImagePlanarComponentsToComponents.cxx + ) + + if(VTK_USE_RENDERING OR vtkRenderingCore_LOADED) + set(vtkgdcm_SRCS ${vtkgdcm_SRCS} + ${CMAKE_CURRENT_SOURCE_DIR}/vtkImageColorViewer.cxx + ) + endif() + + #if(GDCM_HAVE_PTHREAD_H) + set(vtkgdcm_SRCS ${vtkgdcm_SRCS} + vtkGDCMThreadedImageReader2.cxx + ) + #endif() + + if( "${VTK_MAJOR_VERSION}.${VTK_MINOR_VERSION}" LESS 6.0 ) + set(VTK_USE_INSTANTIATOR_NEW 1) + VTK_MAKE_INSTANTIATOR3( + "${VTKGDCM_NAME}Instantiator" + vtkgdcmInstantiator_SRCS + "${vtkgdcm_SRCS}" + "" #"VTK_${VTKGDCM_NAME}_EXPORT" + ${PROJECT_BINARY_DIR} + "" #"${VTKGDCM_NAME}Configure.h" + ) + endif() +endif() + +#Hum... not sure why this is needed. +#if(NOT VTK_BUILD_SHARED_LIBS AND GDCM_BUILD_SHARED_LIBS) +# add_library(vtkgdcm STATIC ${vtkgdcm_SRCS} ${vtkgdcmInstantiator_SRCS}) +#else() + add_library(${VTKGDCM_NAME} ${vtkgdcm_SRCS} ${vtkgdcmInstantiator_SRCS}) +#endif() + +set_target_properties(${VTKGDCM_NAME} PROPERTIES ${GDCM_LIBRARY_PROPERTIES}) +target_link_libraries(${VTKGDCM_NAME} gdcmMSFF ${vtkgdcm_LIBS}) +if(GDCM_HAVE_PTHREAD_H) + target_link_libraries(${VTKGDCM_NAME} pthread) +endif() +# prevent viral dep of vtkgdcm +set_property(TARGET ${VTKGDCM_NAME} PROPERTY LINK_INTERFACE_LIBRARIES "") +if(NOT GDCM_INSTALL_NO_LIBRARIES) + install(TARGETS ${VTKGDCM_NAME} + EXPORT ${GDCM_TARGETS_NAME} + RUNTIME DESTINATION ${GDCM_INSTALL_BIN_DIR} COMPONENT VTKLibraries + LIBRARY DESTINATION ${GDCM_INSTALL_LIB_DIR} COMPONENT VTKLibraries #${NAMELINK_SKIP} + ARCHIVE DESTINATION ${GDCM_INSTALL_LIB_DIR} COMPONENT VTKDebugDevel + ) +#if(NAMELINK_ONLY) +# install(TARGETS vtkgdcm +# LIBRARY DESTINATION ${GDCM_INSTALL_LIB_DIR} COMPONENT DebugDevel ${NAMELINK_ONLY} +# ) +# endif() +endif() + +if(NOT GDCM_INSTALL_NO_DEVELOPMENT) + set(header_files_glob "*.h" "*.txx") + if( "${VTK_MAJOR_VERSION}.${VTK_MINOR_VERSION}" LESS 4.5 ) + set(header_files_glob ${header_files_glob} + "VTK4/*.h" + ) + endif() + file(GLOB header_files ${header_files_glob}) + install(FILES ${header_files} + DESTINATION ${GDCM_INSTALL_INCLUDE_DIR} COMPONENT VTKHeaders + ) +endif() + +if(GDCM_WRAP_PHP) + if( "${VTK_MAJOR_VERSION}.${VTK_MINOR_VERSION}" LESS 4.5 ) + message(FATAL_ERROR "you need a newer VTK version >= 5.0") + endif() + + find_package(PHP5 REQUIRED) + include_directories( + ${PHP5_INCLUDE_PATH} + ) + + find_package(SWIG REQUIRED) + mark_as_advanced(SWIG_DIR SWIG_EXECUTABLE SWIG_VERSION) + include(${SWIG_USE_FILE}) + set_source_files_properties(vtkgdcm.i PROPERTIES CPLUSPLUS ON) + #set_source_files_properties(vtkgdcm.i PROPERTIES COMPILE_FLAGS -DUSEACTIVIZ) + #if(GDCM_USE_ACTIVIZ) + #set(CMAKE_SWIG_FLAGS "-namespace vtkgdcm -dllimport vtkgdcmsharpglue -DUSEACTIVIZ") + #else() + #set(CMAKE_SWIG_FLAGS "-namespace vtkgdcm -dllimport vtkgdcmsharpglue") + #endif() + #separate_arguments(CMAKE_SWIG_FLAGS) + + SWIG_ADD_MODULE(php_vtkgdcm php vtkgdcm.i) + SWIG_LINK_LIBRARIES(php_vtkgdcm vtkgdcm) + target_link_libraries(${SWIG_MODULE_php_vtkgdcm_REAL_NAME} ${vtkgdcm_LIBS}) + if(UNIX) + set_target_properties(${SWIG_MODULE_php_vtkgdcm_REAL_NAME} PROPERTIES OUTPUT_NAME "vtkgdcm") + endif() + set_target_properties(${SWIG_MODULE_php_vtkgdcm_REAL_NAME} PROPERTIES PREFIX "") + set_target_properties(${SWIG_MODULE_php_vtkgdcm_REAL_NAME} PROPERTIES LINK_INTERFACE_LIBRARIES "") + set_property(TARGET ${SWIG_MODULE_php_vtkgdcm_REAL_NAME} PROPERTY NO_SONAME 1) + +if(NOT GDCM_INSTALL_NO_LIBRARIES) + install(TARGETS ${SWIG_MODULE_php_vtkgdcm_REAL_NAME} + EXPORT ${GDCM_TARGETS_NAME} + RUNTIME DESTINATION ${GDCM_INSTALL_BIN_DIR} COMPONENT Applications + LIBRARY DESTINATION ${GDCM_INSTALL_LIB_DIR} COMPONENT Libraries + ) +#if(NAMELINK_ONLY) +# install(TARGETS ${SWIG_MODULE_vtkgdcmsharpglue_REAL_NAME} +# LIBRARY DESTINATION ${GDCM_INSTALL_LIB_DIR} COMPONENT DebugDevel ${NAMELINK_ONLY} +# ) +# endif() + +# See gdcm bug #3175803 +if(${SWIG_VERSION} LESS 2.0.2) +add_custom_command(TARGET ${SWIG_MODULE_php_vtkgdcm_REAL_NAME} + PRE_BUILD + COMMAND sed -i -e 's/zend_error_noreturn/zend_error/g' "${swig_generated_file_fullname}" + COMMENT "Patching zend_error_noreturn into zend_error" + ) +endif() + +# Let's copy vtkgdcm.php into the bin dir: +add_custom_command( + OUTPUT ${LIBRARY_OUTPUT_PATH}/vtkgdcm.php + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/vtkgdcm.php ${LIBRARY_OUTPUT_PATH}/vtkgdcm.php + DEPENDS "${swig_generated_file_fullname}" + COMMENT "copying vtkgdcm.php" +) +add_custom_target(VTKGDCMPHP ALL + DEPENDS ${LIBRARY_OUTPUT_PATH}/vtkgdcm.php + COMMENT "building vtkgdcm.php" +) + install(FILES ${LIBRARY_OUTPUT_PATH}/vtkgdcm.php + DESTINATION ${GDCM_INSTALL_LIB_DIR} COMPONENT VTKPythonModule + ) + +endif() +endif() + +if(GDCM_WRAP_CSHARP) + if( "${VTK_MAJOR_VERSION}.${VTK_MINOR_VERSION}" LESS 4.5 ) + message(FATAL_ERROR "you need a newer VTK version >= 5.0") + endif() + if(GDCM_USE_ACTIVIZ) + find_package(ACTIVIZ REQUIRED) + else() + message(STATUS "You are using the SWIG version of VTKGDCM. This is not compatible with Activiz") + find_package(SWIG REQUIRED) + mark_as_advanced(SWIG_DIR SWIG_EXECUTABLE SWIG_VERSION) + include(${SWIG_USE_FILE}) + set_source_files_properties(vtkgdcm.i PROPERTIES CPLUSPLUS ON) + #set_source_files_properties(vtkgdcm.i PROPERTIES COMPILE_FLAGS -DUSEACTIVIZ) + endif() + if(GDCM_USE_ACTIVIZ) + #set(CMAKE_SWIG_FLAGS "-namespace vtkgdcm -dllimport vtkgdcmsharpglue -DUSEACTIVIZ") + else() + set(CMAKE_SWIG_FLAGS "-namespace vtkgdcm -dllimport vtkgdcmsharpglue") + separate_arguments(CMAKE_SWIG_FLAGS) + SWIG_ADD_MODULE(vtkgdcmsharpglue csharp vtkgdcm.i) + SWIG_LINK_LIBRARIES(vtkgdcmsharpglue vtkgdcm) + # Stupid cmake-swig module is doing that for us, when not needed + if(UNIX) + set_target_properties(${SWIG_MODULE_vtkgdcmsharpglue_REAL_NAME} PROPERTIES PREFIX "lib") + endif() + target_link_libraries(${SWIG_MODULE_vtkgdcmsharpglue_REAL_NAME} ${vtkgdcm_LIBS}) + if(NOT GDCM_INSTALL_NO_LIBRARIES) + install(TARGETS ${SWIG_MODULE_vtkgdcmsharpglue_REAL_NAME} + EXPORT ${GDCM_TARGETS_NAME} + RUNTIME DESTINATION ${GDCM_VTK_INSTALL_CSHARPMODULE_DIR} COMPONENT Applications + LIBRARY DESTINATION ${GDCM_VTK_INSTALL_CSHARPMODULE_DIR} COMPONENT Libraries + ) + endif() + endif() + + configure_file( + ${GDCM_SOURCE_DIR}/Wrapping/Csharp/key.snk + ${CMAKE_CURRENT_BINARY_DIR}/key.snk + COPYONLY) + + if(GDCM_USE_ACTIVIZ) + find_package(Mummy REQUIRED) + mark_as_advanced(Mummy_DIR) + if(NOT Mummy_BASE_DIR) + message(FATAL_ERROR "error: Mummy_BASE_DIR not defined. Please set Mummy_DIR to the directory containing MummyConfig.cmake") + endif() + include("${Mummy_DIR}/MummyCMakeMacros.cmake") + if(NOT mummy_EXECUTABLE) + find_program(mummy_EXECUTABLE mummy) + endif() + mark_as_advanced(mummy_EXECUTABLE) + if(NOT mummy_EXECUTABLE) + message(FATAL_ERROR "error: mummy not found. mummy_EXECUTABLE='${mummy_EXECUTABLE}'") + endif() + + if(NOT gccxml_EXECUTABLE) + find_program(gccxml_EXECUTABLE gccxml) + endif() + mark_as_advanced(gccxml_EXECUTABLE) + if(NOT gccxml_EXECUTABLE) + message(FATAL_ERROR "error: gccxml not found. gccxml_EXECUTABLE='${gccxml_EXECUTABLE}'") + endif() + set(gccxml_compiler "${CMAKE_CXX_COMPILER}") + if(MSVC80) + set(gccxml_compiler "msvc8") + endif() + if(MSVC90) + set(gccxml_compiler "msvc9") + endif() + #message(STATUS "gccxml_compiler='${gccxml_compiler}'...") + set(gccxml_include_args "") + foreach(dir ${Mummy_INCLUDE_DIRS} ${VTK_INCLUDE_DIRS}) + set(gccxml_include_args ${gccxml_include_args} "-I${dir}") + endforeach() + configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/MummySettings.xml.in" + "${CMAKE_CURRENT_BINARY_DIR}/xml/MummySettings.xml" + @ONLY + ) + file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/csharp") + file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/export-layer") + + set(theclasslist + vtkGDCMImageReader + vtkGDCMImageWriter + vtkGDCMMedicalImageProperties + vtkGDCMPolyDataReader + vtkGDCMPolyDataWriter + vtkGDCMTesting + vtkGDCMThreadedImageReader + vtkGDCMThreadedImageReader2 + vtkImageColorViewer + vtkImageMapToColors16 + vtkImageMapToWindowLevelColors2 + #vtkImagePlanarComponentsToComponents + vtkImageRGBToYBR + vtkImageYBRToRGB + vtkLookupTable16 + vtkRTStructSetProperties + ) + set(kits gdcm) + # foreach kit + set(kit gdcm) + foreach(class ${theclasslist}) + if(NOT VTK_CLASS_WRAP_EXCLUDE_${class}) + #set(header "${VTK_${ukit}_HEADER_DIR}/${class}.h") + set(header "${CMAKE_CURRENT_SOURCE_DIR}/${class}.h") + set(cxxclass "${class}") + + # handle full paths + if("${class}" MATCHES "^(\\/|.\\/|.\\\\|.:\\/|.:\\\\)") + set(header "${class}.h") + string(REGEX MATCH "[^/]*$" cxxclass "${class}") + + get_filename_component(dir "${header}" PATH) + include_directories("${dir}") + endif() + + set(abstract 0) + if(VTK_CLASS_ABSTRACT_${class}) + set(abstract 1) + set_source_files_properties(${header} PROPERTIES ABSTRACT 1) + endif() + + # Build one master in-memory table so that we don't have to re-do all the + # logic in this nested FOREACH loop later on... Instead we'll simply iterate + # the in-memory table built here: + # + set(WRAPPED_CLASS_TABLE ${WRAPPED_CLASS_TABLE} "${cxxclass} ${kit} ${abstract} ${header}") + + + set(include_source_text "") + string(REGEX REPLACE "(.*).h" "\\1.cxx" source "${header}") + if(EXISTS "${source}") + set(include_source_text "#include \"${source}\"") + else() + #message(FATAL_ERROR "error: Source file '${source}' does not exist...") + endif() + + configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/gccxml.cxx.in" + "${CMAKE_CURRENT_BINARY_DIR}/xml/${cxxclass}_gccxml.cxx" + @ONLY + ) + + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/xml/${cxxclass}.xml + COMMAND ${gccxml_EXECUTABLE} + ARGS + -fxml=${CMAKE_CURRENT_BINARY_DIR}/xml/${cxxclass}.xml + -fxml-start=_cable_ + ${gccxml_include_args} -DCABLE_CONFIGURATION + --gccxml-compiler ${gccxml_compiler} + ${CMAKE_CURRENT_BINARY_DIR}/xml/${cxxclass}_gccxml.cxx + DEPENDS + ${CMAKE_CURRENT_BINARY_DIR}/xml/${cxxclass}_gccxml.cxx + ${header} + ${gccxml_EXECUTABLE} + ) + +# +# *before* custom command re-arranging: +# +# OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/csharp/${cxxclass}.cs +# ${CMAKE_CURRENT_BINARY_DIR}/export-layer/${cxxclass}EL.cxx +# +# Do not list the *.cs or *EL.cxx files as outputs of this custom command. +# If you do, the custom command chains out into other targets rather than +# being defined solely in the "generate wrappers" custom target. +# +# The output of this command is the generated sentinel file that the +# "generate wrappers" target depends on. The other files are generated as an +# intentional "side effect" and after the target is done building, the other +# targets that build the generated source code may build... That is controlled +# by target level dependencies to reduce complexity. +# + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/csharp/${cxxclass}-sentinel.txt + COMMAND ${mummy_EXECUTABLE} + --suppress-warnings 6005 6006 6009 6010 6012 6013 6015 6016 6017 6018 6019 + --settings-file ${CMAKE_CURRENT_BINARY_DIR}/xml/MummySettings.xml + --gccxml-file ${CMAKE_CURRENT_BINARY_DIR}/xml/${cxxclass}.xml + --csharp-file ${CMAKE_CURRENT_BINARY_DIR}/csharp/${cxxclass}.cs + --export-layer-file ${CMAKE_CURRENT_BINARY_DIR}/export-layer/${cxxclass}EL.cxx + COMMAND ${CMAKE_COMMAND} -E touch + ${CMAKE_CURRENT_BINARY_DIR}/csharp/${cxxclass}-sentinel.txt + DEPENDS + ${CMAKE_CURRENT_BINARY_DIR}/xml/${cxxclass}.xml + ${CMAKE_CURRENT_BINARY_DIR}/xml/MummySettings.xml + ${mummy_EXECUTABLE} + ${${cxxclass}_EXTRA_DEPENDENCIES} + ) + + set(${kit}_EL_SOURCES ${${kit}_EL_SOURCES} "${CMAKE_CURRENT_BINARY_DIR}/export-layer/${cxxclass}EL.cxx") + set(ALLKITS_EL_SOURCES ${ALLKITS_EL_SOURCES} "${CMAKE_CURRENT_BINARY_DIR}/export-layer/${cxxclass}EL.cxx") + + set(${kit}_CS_SOURCES ${${kit}_CS_SOURCES} "${CMAKE_CURRENT_BINARY_DIR}/csharp/${cxxclass}.cs") + set(ALLKITS_CS_SOURCES ${ALLKITS_CS_SOURCES} "${CMAKE_CURRENT_BINARY_DIR}/csharp/${cxxclass}.cs") + + set(${kit}_SENTINELS ${${kit}_SENTINELS} "${CMAKE_CURRENT_BINARY_DIR}/csharp/${cxxclass}-sentinel.txt") + set(ALLKITS_SENTINELS ${ALLKITS_SENTINELS} "${CMAKE_CURRENT_BINARY_DIR}/csharp/${cxxclass}-sentinel.txt") + endif() + endforeach() + + add_custom_target( + "vtk${kit}GenerateWrappers" ALL + DEPENDS ${${kit}_SENTINELS} + ) + set_source_files_properties( + ${ALLKITS_EL_SOURCES} + ${ALLKITS_CS_SOURCES} + PROPERTIES GENERATED 1) + + if(VTK_BUILD_SHARED_LIBS) + set(MV_ONE_EXPORT_LAYER_DLL 0) + else() + set(MV_ONE_EXPORT_LAYER_DLL 1) + endif() + + if(MV_ONE_EXPORT_LAYER_DLL) + message(FATAL_ERROR "Unimplemented") + #set(AVDN_INSTALL_TARGETS ${AVDN_INSTALL_TARGETS} "Kitware.VTK.Unmanaged") + #add_library(Kitware.VTK.Unmanaged SHARED ${ALLKITS_EL_SOURCES}) + #set(unmanaged_targets ${unmanaged_targets} "Kitware.VTK.Unmanaged") + #set(unmanaged_dlls ${unmanaged_dlls} "${CMAKE_SHARED_LIBRARY_PREFIX}Kitware.VTK.Unmanaged${CMAKE_SHARED_LIBRARY_SUFFIX}") + #if(WIN32) + # target_link_libraries(Kitware.VTK.Unmanaged "${exe_dir}/Kitware.mummy.Runtime.Unmanaged.lib") + #else() + # target_link_libraries(Kitware.VTK.Unmanaged "${exe_dir}/${CMAKE_SHARED_LIBRARY_PREFIX}Kitware.mummy.Runtime.Unmanaged${CMAKE_SHARED_LIBRARY_SUFFIX}") + #endif() + ## TODO -- rename this CopyLibraries here too... + #add_dependencies(Kitware.VTK.Unmanaged Kitware.mummy.CopyLibraries2) + #foreach(kit ${kits}) + # target_link_libraries(Kitware.VTK.Unmanaged vtk${kit}) + # add_dependencies(Kitware.VTK.Unmanaged "vtk${kit}GenerateWrappers") + #endforeach() + else() + include_directories(${Mummy_INCLUDE_DIRS}) + foreach(kit ${kits}) + set(AVDN_INSTALL_TARGETS ${AVDN_INSTALL_TARGETS} "Kitware.VTK.vtk${kit}.Unmanaged") + add_library(Kitware.VTK.vtk${kit}.Unmanaged SHARED ${${kit}_EL_SOURCES}) + set(unmanaged_targets ${unmanaged_targets} "Kitware.VTK.vtk${kit}.Unmanaged") + set(unmanaged_dlls ${unmanaged_dlls} "${CMAKE_SHARED_LIBRARY_PREFIX}Kitware.VTK.vtk${kit}.Unmanaged${CMAKE_SHARED_LIBRARY_SUFFIX}") + if(WIN32) + target_link_libraries(Kitware.VTK.vtk${kit}.Unmanaged "${exe_dir}/Kitware.mummy.Runtime.Unmanaged.lib") + else() + target_link_libraries(Kitware.VTK.vtk${kit}.Unmanaged ${Mummy_RUNTIME_LINK_LIBRARIES}) + endif() + target_link_libraries(Kitware.VTK.vtk${kit}.Unmanaged vtk${kit}) + target_link_libraries(Kitware.VTK.vtk${kit}.Unmanaged vtkCommon) + set_property(TARGET Kitware.VTK.vtk${kit}.Unmanaged PROPERTY NO_SONAME 1) + # TODO -- rename this CopyLibraries here too... + add_dependencies(Kitware.VTK.vtk${kit}.Unmanaged Kitware.mummy.CopyLibraries2) + add_dependencies(Kitware.VTK.vtk${kit}.Unmanaged "vtk${kit}GenerateWrappers") + endforeach() + endif() + + set(csc_EXECUTABLE ${CMAKE_CSHARP_COMPILER}) + # Set list of export-layer dlls in C# syntax as CMake variable + # MV_EXPORTLAYER_DLL_VARIABLES. This gets configured into + # WrappedObject.cs below. + # + set(MV_EXPORTLAYER_DLL_VARIABLES "") + foreach(kit ${kits}) + set(MV_EXPORTLAYER_DLL_VARIABLES "${MV_EXPORTLAYER_DLL_VARIABLES} /// \n") + set(MV_EXPORTLAYER_DLL_VARIABLES "${MV_EXPORTLAYER_DLL_VARIABLES} /// Export layer functions for 'vtk${kit}' are exported from\n") + set(MV_EXPORTLAYER_DLL_VARIABLES "${MV_EXPORTLAYER_DLL_VARIABLES} /// the DLL named by the value of this variable.\n") + set(MV_EXPORTLAYER_DLL_VARIABLES "${MV_EXPORTLAYER_DLL_VARIABLES} /// \n") + + if(MV_ONE_EXPORT_LAYER_DLL) + set(MV_EXPORTLAYER_DLL_VARIABLES "${MV_EXPORTLAYER_DLL_VARIABLES} public const string vtk${kit}EL_dll = \"${CMAKE_SHARED_LIBRARY_PREFIX}Kitware.VTK.Unmanaged${CMAKE_SHARED_LIBRARY_SUFFIX}\";\n") + else() + set(MV_EXPORTLAYER_DLL_VARIABLES "${MV_EXPORTLAYER_DLL_VARIABLES} public const string vtk${kit}EL_dll = \"${CMAKE_SHARED_LIBRARY_PREFIX}Kitware.VTK.vtk${kit}.Unmanaged${CMAKE_SHARED_LIBRARY_SUFFIX}\";\n") + endif() + endforeach() + + set(csharp_namespace "Kitware.VTK.GDCM") + configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/AssemblyInfo.cs.in" + "${CMAKE_CURRENT_BINARY_DIR}/csharp/AssemblyInfo.cs" + @ONLY + ) + + set(ALLKITS_CS_SOURCES + ${ALLKITS_CS_SOURCES} + "${CMAKE_CURRENT_BINARY_DIR}/csharp/AssemblyInfo.cs" + ${CMAKE_CURRENT_SOURCE_DIR}/vtkGDCMImageReader_Extra.cs + ) + + set(AVDN_VTK_CSC_REFS ${ACTIVIZ_KITWARE_VTK_LIBRARY} ${ACTIVIZ_KITWARE_MUMMY_RUNTIME_LIBRARY}) + ADD_CSHARP_LIBRARY( + "Kitware.VTK.GDCM" # name of library + "${unmanaged_targets}" # list of CMake targets that need to build first + "${AVDN_VTK_CSC_REFS}" # list of csc "/reference:" args + "${unmanaged_dlls}" # list of csc "/linkresource:" args + "${AVDN_SNKEYFILE}" # strong name signing keyfile + # Source files: + ${ALLKITS_CS_SOURCES} + ) + + foreach(kit ${kits}) + add_dependencies(Kitware.VTK.GDCM "vtk${kit}GenerateWrappers") + endforeach() + + # add_custom_command( + # OUTPUT ${GDCM_LIBRARY_DIR}/vtkgdcm-sharp.dll + # COMMAND ${CMAKE_CSHARP_COMPILER} ARGS "/r:${ACTIVIZ_KITWARE_VTK_LIBRARY}" "/r:${ACTIVIZ_KITWARE_MUMMY_RUNTIME_LIBRARY}" "/t:library" "/out:${GDCM_LIBRARY_DIR}/vtkgdcm-sharp.dll" "*.cs" + # #COMMAND ${CMAKE_CSHARP_COMPILER} ARGS "/t:library" "/out:${GDCM_LIBRARY_DIR}/vtkgdcm-sharp.dll" "*.cs" + # WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + # DEPENDS "${swig_generated_file_fullname}" + # ${CMAKE_CURRENT_BINARY_DIR}/AssemblyInfo.cs + # COMMENT "csc *.cs" + # ) + + install(FILES + ${GDCM_LIBRARY_DIR}/Kitware.VTK.GDCM.dll + ${GDCM_LIBRARY_DIR}/Kitware.VTK.GDCM.xml + DESTINATION ${GDCM_INSTALL_LIB_DIR} COMPONENT VTKCSharpModule + ) + install(TARGETS Kitware.VTK.vtk${kit}.Unmanaged + EXPORT ${GDCM_TARGETS_NAME} + RUNTIME DESTINATION ${GDCM_INSTALL_BIN_DIR} COMPONENT VTKLibraries + LIBRARY DESTINATION ${GDCM_INSTALL_LIB_DIR} COMPONENT VTKLibraries #${NAMELINK_SKIP} + ARCHIVE DESTINATION ${GDCM_INSTALL_LIB_DIR} COMPONENT VTKDebugDevel + ) + else() + configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/AssemblyInfo.cs.in + ${CMAKE_CURRENT_BINARY_DIR}/AssemblyInfo.cs + @ONLY) + + add_custom_command( + OUTPUT ${GDCM_LIBRARY_DIR}/vtkgdcm-sharp.dll + COMMAND ${CMAKE_CSHARP_COMPILER} ARGS "/t:library" "/out:${GDCM_LIBRARY_DIR}/vtkgdcm-sharp.dll" "*.cs" + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS "${swig_generated_file_fullname}" + ${CMAKE_CURRENT_BINARY_DIR}/AssemblyInfo.cs + COMMENT "csc *.cs" + ) + add_custom_target(VTKGDCMCSharp ALL + DEPENDS + ${GDCM_LIBRARY_DIR}/vtkgdcm-sharp.dll + #${GDCM_LIBRARY_DIR}/vtkgdcm-sharp.dll.config + #${GDCM_EXECUTABLE_DIR}/HelloWorld.exe + COMMENT "building vtkgdcm-sharp.dll" + ) + # because vtkgdcm-sharp.dll is constructed with custom commands, it need the install(FILES signature: + set(GDCM_LIBRARY_DIR2 ${LIBRARY_OUTPUT_PATH}/\${BUILD_TYPE}) + install(FILES + ${GDCM_LIBRARY_DIR2}/vtkgdcm-sharp.dll + #${GDCM_LIBRARY_DIR2}/vtkgdcm-sharp.dll.config + DESTINATION ${GDCM_INSTALL_LIB_DIR} COMPONENT VTKCSharpModule + ) + endif() + + #add_custom_command( + # OUTPUT ${GDCM_LIBRARY_DIR}/vtkgdcm-sharp.dll.config + # COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/vtkgdcm-sharp.dll.config ${GDCM_LIBRARY_DIR} + # DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/vtkgdcm-sharp.dll.config + # COMMENT "Copying vtkgdcm-sharp.dll.config" + #) + +endif() + +if(GDCM_WRAP_JAVA) + if(VTK_WRAP_JAVA) + find_package(Java 1.5 REQUIRED) # javac, jar + find_package(JNI REQUIRED) + include_directories(${JNI_INCLUDE_DIRS}) + set(VTK_WRAP_JAVA3_INIT_DIR "${CMAKE_CURRENT_SOURCE_DIR}") + # Lars Matthäus patch (package vtk => imply vtk subdir ) + set(VTK_JAVA_HOME ${CMAKE_CURRENT_BINARY_DIR}/java/vtk) + # This is *required* don't ask + file(MAKE_DIRECTORY ${VTK_JAVA_HOME}) + include(${VTK_CMAKE_DIR}/vtkWrapJava.cmake) + include_directories(${CMAKE_CURRENT_SOURCE_DIR}) + + VTK_WRAP_JAVA3(${VTKGDCM_NAME}Java vtkgdcmJAVA_SRCS "${vtkgdcm_SRCS}") + # libvtk-java is a pain to handle... + if(EXISTS ${VTK_JAVA_JAR}) + # http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=533193 + set(GDCM_VTK_JAVA_JAR ${VTK_JAVA_JAR}) + endif() + if(EXISTS /usr/lib/jni/libvtkCommonJava.so) + # http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=533198 + message(STATUS "Implicitely adding debian package layout...") + link_directories("/usr/lib/jni") + endif() + mark_as_advanced(GDCM_VTK_JAVA_JAR) + if(EXISTS ${GDCM_VTK_JAVA_JAR}) + else() + message(FATAL_ERROR "Could not find vtk.jar file, VTK_JAVA_JAR is wrong: ${VTK_JAVA_JAR}, please set proper GDCM_VTK_JAVA_JAR: ${GDCM_VTK_JAVA_JAR} replacement var") + endif() + add_library(${VTKGDCM_NAME}Java SHARED ${vtkgdcmJAVA_SRCS}) + # special jnilib extension: + if(APPLE) + set_target_properties(${VTKGDCM_NAME}Java PROPERTIES SUFFIX ".jnilib") + endif() + target_link_libraries(${VTKGDCM_NAME}Java ${VTKGDCM_NAME}) + set_property(TARGET ${VTKGDCM_NAME}Java PROPERTY NO_SONAME 1) + foreach(c ${vtkgdcm_LIBS}) + target_link_libraries(${VTKGDCM_NAME}Java ${c}Java) + endforeach() + # Create the jar file: + # I am pretty sure this *.java thingy will bite me one day, when someone will try + # to recompile from an existing build tree with invalid generated *.java file... + set(jflags $ENV{JFLAGS}) + add_custom_command( + OUTPUT ${LIBRARY_OUTPUT_PATH}/vtkgdcm.jar + #COMMAND ${Java_JAVAC_EXECUTABLE} ARGS -cp ${GDCM_VTK_JAVA_JAR} "vtk/*.java" + # No such thing as -cp for javac only java is listed: + # http://java.sun.com/j2se/1.5.0/docs/tooldocs/windows/classpath.html + COMMAND ${Java_JAVAC_EXECUTABLE} ARGS ${jflags} -source 1.5 -target 1.5 -classpath ${GDCM_VTK_JAVA_JAR} "vtk/*.java" + COMMAND ${Java_JAR_EXECUTABLE} ARGS -cvfm ${LIBRARY_OUTPUT_PATH}/${PROJECT_NAME}.jar ${CMAKE_CURRENT_SOURCE_DIR}/manifest.txt vtk/*.class + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/java + DEPENDS ${VTKGDCM_NAME}Java + #${VTK_JAVA_DEPENDENCIES} + #vtkgdcmJavaJavaClasses + COMMENT "javac *.java -> jar; jar cvf -> vtkgdcm.jar" + ) + # Target to execute custom command: + add_custom_target(VTKGDCMJavaJar ALL + DEPENDS ${LIBRARY_OUTPUT_PATH}/vtkgdcm.jar + COMMENT "building vtkgdcm.jar" + ) + add_dependencies(VTKGDCMJavaJar vtkgdcmJavaJavaClasses) + + # Install rules: + if(NOT GDCM_INSTALL_NO_LIBRARIES) + install(TARGETS ${VTKGDCM_NAME}Java + EXPORT ${GDCM_TARGETS_NAME} + RUNTIME DESTINATION ${GDCM_VTK_INSTALL_JAVAMODULE_DIR} COMPONENT VTKJavaModule + LIBRARY DESTINATION ${GDCM_VTK_INSTALL_JAVAMODULE_DIR} COMPONENT VTKJavaModule + ) + #DebugDevel + #if(NAMELINK_ONLY) + # install(TARGETS ${VTKGDCM_NAME}Java + # LIBRARY DESTINATION ${GDCM_INSTALL_LIB_DIR} COMPONENT VTKJavaModule ${NAMELINK_ONLY} + # ) + #endif() + + # because vtkgdcm.jar is constructed with custom commands, it need the + # install(FILES signature: + install(FILES ${LIBRARY_OUTPUT_PATH}/vtkgdcm.jar + DESTINATION ${GDCM_VTK_INSTALL_JARMODULE_DIR} COMPONENT VTKJavaModule + ) + endif() + + else() + message(STATUS "GDCM_WRAP_JAVA canot be build without VTK_WRAP_JAVA") + endif() +endif() + +if(GDCM_WRAP_PYTHON) + if(VTK_WRAP_PYTHON) + set(DEXTENSION "") + if( "${VTK_MAJOR_VERSION}.${VTK_MINOR_VERSION}" LESS 4.5 ) + VTK_WRAP_PYTHON2(${VTKGDCM_NAME}Python vtkgdcmPYTHON_SRCS ${vtkgdcm_SRCS}) + else() + include(${VTK_CMAKE_DIR}/vtkWrapPython.cmake) + include_directories( + ${PYTHON_INCLUDE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} + ) + VTK_WRAP_PYTHON3(${VTKGDCM_NAME}Python vtkgdcmPYTHON_SRCS "${vtkgdcm_SRCS}") + set(DEXTENSION "D") + endif() + add_library(${VTKGDCM_NAME}PythonD ${vtkgdcmPYTHON_SRCS}) + # this is a library set the version: + # do not set the version on the Python module: + set_target_properties(${VTKGDCM_NAME}PythonD PROPERTIES ${GDCM_LIBRARY_PROPERTIES}) + add_library(${VTKGDCM_NAME}Python MODULE ${VTKGDCM_NAME}PythonInit.cxx) + # do not set the version on the Python module: + #set_target_properties(${VTKGDCM_NAME}Python PROPERTIES ${GDCM_LIBRARY_PROPERTIES}) + target_link_libraries(${VTKGDCM_NAME}PythonD ${VTKGDCM_NAME} ${PYTHON_LIBRARY}) + foreach(c ${vtkgdcm_LIBS} vtkFiltering) + target_link_libraries(${VTKGDCM_NAME}PythonD ${c}Python${DEXTENSION}) + endforeach() + if(TARGET vtkPythonCore) + target_link_libraries(${VTKGDCM_NAME}PythonD vtkPythonCore) + endif() + target_link_libraries(${VTKGDCM_NAME}Python ${VTKGDCM_NAME}PythonD) + if(NOT GDCM_NO_PYTHON_LIBS_LINKING) + target_link_libraries(${VTKGDCM_NAME}Python ${PYTHON_LIBRARY}) + endif() + set_property(TARGET ${VTKGDCM_NAME}PythonD PROPERTY LINK_INTERFACE_LIBRARIES "") + set_property(TARGET ${VTKGDCM_NAME}Python PROPERTY NO_SONAME 1) + #set_property(TARGET ${VTKGDCM_NAME}PythonD PROPERTY NO_SONAME 1) + # Python extension modules on Windows must have the extension ".pyd" + # instead of ".dll" as of Python 2.5. Older python versions do support + # this suffix. + if(WIN32 AND NOT CYGWIN) + set_target_properties(${VTKGDCM_NAME}Python PROPERTIES SUFFIX ".pyd") + endif() + + add_custom_command( + TARGET ${VTKGDCM_NAME}Python + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/vtkgdcm.py ${LIBRARY_OUTPUT_PATH}/${CMAKE_CFG_INTDIR} + DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/vtkgdcm.py" + COMMENT "Copy vtkgdcm.py into ${LIBRARY_OUTPUT_PATH}" + ) + if(NOT GDCM_INSTALL_NO_LIBRARIES) + install(TARGETS ${VTKGDCM_NAME}Python + EXPORT ${GDCM_TARGETS_NAME} + RUNTIME DESTINATION ${GDCM_VTK_INSTALL_PYTHONMODULE_DIR} COMPONENT VTKPythonModule + LIBRARY DESTINATION ${GDCM_VTK_INSTALL_PYTHONMODULE_DIR} COMPONENT VTKPythonModule #${NAMELINK_SKIP} + ) + install(TARGETS ${VTKGDCM_NAME}PythonD + EXPORT ${GDCM_TARGETS_NAME} + RUNTIME DESTINATION ${GDCM_INSTALL_BIN_DIR} COMPONENT VTKPythonModule + LIBRARY DESTINATION ${GDCM_INSTALL_LIB_DIR} COMPONENT VTKPythonModule #${NAMELINK_ONLY} + ) + # the python file is not a dev file, but part of the gdcm module... + install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/vtkgdcm.py + DESTINATION ${GDCM_VTK_INSTALL_PYTHONMODULE_DIR} COMPONENT VTKPythonModule + ) + endif() + + else() + message(STATUS "GDCM_WRAP_PYTHON canot be build without VTK_WRAP_PYTHON") + endif() +endif() + +if(BUILD_TESTING) + subdirs(Testing) +endif() + +if(BUILD_APPLICATIONS) + subdirs(Applications) +endif() + +if(BUILD_EXAMPLES) + subdirs(Examples) +endif() + +if(GDCM_USE_PARAVIEW) + # http://www.cmake.org/Wiki/Plugin_HowTo#Adding_a_Reader + find_package(ParaView REQUIRED) + include(${PARAVIEW_USE_FILE}) + ADD_PARAVIEW_PLUGIN(GDCMImageReader "1.0" + SERVER_MANAGER_SOURCES vtkGDCMImageReader.cxx + SERVER_MANAGER_XML GDCMImageReader.xml + GUI_RESOURCE_FILES GDCMImageGUI.xml) + target_link_libraries(GDCMImageReader ${VTKGDCM_NAME}) + install(TARGETS GDCMImageReader + EXPORT ${GDCM_TARGETS_NAME} + RUNTIME DESTINATION ${GDCM_INSTALL_BIN_DIR} COMPONENT ParaViewModule + LIBRARY DESTINATION ${GDCM_INSTALL_LIB_DIR} COMPONENT ParaViewModule + ARCHIVE DESTINATION ${GDCM_INSTALL_LIB_DIR} COMPONENT ParaViewModule + ) + +endif() diff --git a/gdcm/Utilities/VTK/CscArgs.txt.in b/gdcm/Utilities/VTK/CscArgs.txt.in new file mode 100644 index 0000000..c12e624 --- /dev/null +++ b/gdcm/Utilities/VTK/CscArgs.txt.in @@ -0,0 +1 @@ +@CscArgs@ diff --git a/gdcm/Utilities/VTK/Examples/CMakeLists.txt b/gdcm/Utilities/VTK/Examples/CMakeLists.txt new file mode 100644 index 0000000..503d069 --- /dev/null +++ b/gdcm/Utilities/VTK/Examples/CMakeLists.txt @@ -0,0 +1,12 @@ +#subdirs(Cxx Python) +subdirs(Cxx) + +if(GDCM_WRAP_CSHARP) + subdirs(Csharp) +endif() + +if(GDCM_WRAP_JAVA) + if(VTK_WRAP_JAVA) + subdirs(Java) + endif() +endif() diff --git a/gdcm/Utilities/VTK/Examples/Csharp/CMakeLists.txt b/gdcm/Utilities/VTK/Examples/Csharp/CMakeLists.txt new file mode 100644 index 0000000..8bb3046 --- /dev/null +++ b/gdcm/Utilities/VTK/Examples/Csharp/CMakeLists.txt @@ -0,0 +1,59 @@ +set(DEP) +if(GDCM_USE_ACTIVIZ) + set(examples + #HelloActiviz + HelloActiviz2 + HelloActiviz3 + HelloActiviz4 + HelloActiviz5 + RefCounting + MetaImageMD5Activiz + ) + foreach(example ${examples}) + file(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/${example}.cs result) + add_custom_command( + OUTPUT ${GDCM_EXECUTABLE_DIR}/${example}.exe + COMMAND ${CMAKE_CSHARP_COMPILER} ARGS "/r:${ACTIVIZ_KITWARE_VTK_LIBRARY}" "/r:${ACTIVIZ_KITWARE_MUMMY_RUNTIME_LIBRARY}" "/r:${GDCM_LIBRARY_DIR}/Kitware.VTK.GDCM.dll" "/r:${GDCM_LIBRARY_DIR}/gdcm-sharp.dll" "/out:${GDCM_EXECUTABLE_DIR}/${example}.exe" ${result} + DEPENDS ${GDCM_LIBRARY_DIR}/Kitware.VTK.GDCM.dll + ${CMAKE_CURRENT_SOURCE_DIR}/${example}.cs + COMMENT "Create ${example}.exe" + ) + set(DEP ${DEP} ${GDCM_EXECUTABLE_DIR}/${example}.exe) + endforeach() + + if(BUILD_TESTING) + get_filename_component(runtimepath ${ACTIVIZ_KITWARE_VTK_LIBRARY} PATH) + if(GDCM_DATA_ROOT) + set_source_files_properties(${GDCM_EXECUTABLE_DIR}/HelloActiviz5.exe PROPERTIES RUNTIMEPATH ${runtimepath}) + ADD_CSHARP_TEST(TestHelloActiviz5CSharp ${GDCM_EXECUTABLE_DIR}/HelloActiviz5.exe) + endif() + set_source_files_properties(${GDCM_EXECUTABLE_DIR}/RefCounting.exe PROPERTIES RUNTIMEPATH ${runtimepath}) + ADD_CSHARP_TEST(TestRefCountingCSharp ${GDCM_EXECUTABLE_DIR}/RefCounting.exe) + endif() + +else() + + set(CSHARP_EXAMPLES + HelloVTKWorld + HelloVTKWorld2 + ) + + foreach(example ${CSHARP_EXAMPLES}) + file(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/${example}.cs result) + # WORKING_DIRECTORY is set to the src dir because of a strange issue with CSC compiler on Win32 system: + # http://groups.google.com/group/microsoft.public.dotnet.languages.csharp/browse_thread/thread/9d3ac7eb9f7f56be + add_custom_command( + OUTPUT ${GDCM_EXECUTABLE_DIR}/${example}.exe + COMMAND ${CMAKE_CSHARP_COMPILER} ARGS "/r:${GDCM_LIBRARY_DIR}/vtkgdcm-sharp.dll" "/out:${GDCM_EXECUTABLE_DIR}/${example}.exe" ${result} + DEPENDS ${GDCM_LIBRARY_DIR}/vtkgdcm-sharp.dll + ${CMAKE_CURRENT_SOURCE_DIR}/${example}.cs + COMMENT "Create ${example}.exe" + ) + set(DEP ${DEP} ${GDCM_EXECUTABLE_DIR}/${example}.exe) + endforeach() +endif() + +add_custom_target(VTKGDCMExampleCSharp ALL + DEPENDS ${DEP} + COMMENT "building examples" +) diff --git a/gdcm/Utilities/VTK/Examples/Csharp/HelloActiviz.cs b/gdcm/Utilities/VTK/Examples/Csharp/HelloActiviz.cs new file mode 100644 index 0000000..617214b --- /dev/null +++ b/gdcm/Utilities/VTK/Examples/Csharp/HelloActiviz.cs @@ -0,0 +1,113 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +using vtkgdcm; +using Kitware.VTK; +using System; +using System.Runtime.InteropServices; + +/* + * This example shows how vtkgdcm can be connected to Kitware.VTK Activiz product. + * Three (3) arguments are required: + * 1. Input DICOM file (SWIG) + * 2. Temporary PNG (intermediate) file (Activiz) + * 3. Final DICOM file (SWIG) + * + * $ export MONO_PATH=/usr/lib/cli/ActiViz.NET/:/usr/lib/cli/Kitware.mummy.Runtime-1.0 + * $ mono ./bin/HelloActiviz.exe ~/Creatis/gdcmData/test.acr out.png toto.dcm + * + * Footnote: + * this test originally used vtkBMPWriter / vtkBMPReader combination to store intermediate + * image file, but BMP file are 24bits by default. Instead use PNG format which supports seems + * to be closer to what was expected in this simple test. + */ +public class HelloActiviz +{ + // Does not work with ActiViz.NET-5.4.0.455-Linux-x86_64-Personal +/* + static void ConnectSWIGToActiviz(Kitware.VTK.vtkImageExport imgin, Kitware.VTK.vtkImageImport imgout) + { + imgout.SetUpdateInformationCallback(imgin.GetUpdateInformationCallback()); + imgout.SetPipelineModifiedCallback(imgin.GetPipelineModifiedCallback()); + imgout.SetWholeExtentCallback(imgin.GetWholeExtentCallback()); + imgout.SetSpacingCallback(imgin.GetSpacingCallback()); + imgout.SetOriginCallback(imgin.GetOriginCallback()); + imgout.SetScalarTypeCallback(imgin.GetScalarTypeCallback()); + imgout.SetNumberOfComponentsCallback(imgin.GetNumberOfComponentsCallback()); + imgout.SetPropagateUpdateExtentCallback(imgin.GetPropagateUpdateExtentCallback()); + imgout.SetUpdateDataCallback(imgin.GetUpdateDataCallback()); + imgout.SetDataExtentCallback(imgin.GetDataExtentCallback()); + imgout.SetBufferPointerCallback(imgin.GetBufferPointerCallback()); + imgout.SetCallbackUserData(imgin.GetCallbackUserData()); + } +*/ + + static Kitware.VTK.vtkImageData ConnectSWIGToActiviz(vtkgdcm.vtkImageData imgin) + { + HandleRef rawCppThis = imgin.GetCppThis(); + Kitware.VTK.vtkImageData imgout = new Kitware.VTK.vtkImageData( rawCppThis.Handle, false, false); + return imgout; + } + + static vtkgdcm.vtkImageData ConnectActivizToSWIG(Kitware.VTK.vtkImageData imgin) + { + HandleRef rawCppThis = imgin.GetCppThis(); + vtkgdcm.vtkImageData imgout = new vtkgdcm.vtkImageData( rawCppThis ); + return imgout; + } + + + public static int Main(string[] args) + { + string filename = args[0]; + string outfilename = args[1]; + + // Step 1. Test SWIG -> Activiz + vtkGDCMImageReader reader = vtkGDCMImageReader.New(); + reader.SetFileName( filename ); + //reader.Update(); // DO NOT call Update to check pipeline execution + + Kitware.VTK.vtkImageData imgout = ConnectSWIGToActiviz(reader.GetOutput()); + + System.Console.WriteLine( imgout.ToString() ); // not initialized as expected + + vtkPNGWriter writer = new vtkPNGWriter(); + writer.SetInput( imgout ); + writer.SetFileName( outfilename ); + writer.Write(); + + // Step 2. Test Activiz -> SWIG + vtkPNGReader bmpreader = new vtkPNGReader(); + bmpreader.SetFileName( outfilename ); + //bmpreader.Update(); // DO NOT update to check pipeline execution + + System.Console.WriteLine( bmpreader.GetOutput().ToString() ); // not initialized as expected + + vtkgdcm.vtkImageData imgout2 = ConnectActivizToSWIG(bmpreader.GetOutput()); + + System.Console.WriteLine( imgout2.ToString() ); // not initialized as expected + + + Kitware.VTK.vtkMedicalImageProperties prop = new Kitware.VTK.vtkMedicalImageProperties(); + prop.SetModality( "MR" ); + + string outfilename2 = args[2]; + vtkGDCMImageWriter writer2 = vtkGDCMImageWriter.New(); + writer2.SetMedicalImageProperties( prop.CastToActiviz() ); + writer2.SetFileName( outfilename2 ); + writer2.SetInput( imgout2 ); + writer2.Write(); + + return 0; + } +} diff --git a/gdcm/Utilities/VTK/Examples/Csharp/HelloActiviz2.cs b/gdcm/Utilities/VTK/Examples/Csharp/HelloActiviz2.cs new file mode 100644 index 0000000..c13b7ed --- /dev/null +++ b/gdcm/Utilities/VTK/Examples/Csharp/HelloActiviz2.cs @@ -0,0 +1,87 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +using Kitware.VTK; +using Kitware.VTK.GDCM; + +/* + * Usage: + * $ export MONO_PATH=/usr/lib/cli/ActiViz.NET/:/usr/lib/cli/Kitware.mummy.Runtime-1.0 + * $ mono ./bin/HelloActiviz2.exe gdcmData/test.acr bla.png bla2.dcm + */ + +/* + * From the outside view, no-one can detect that object pass to/from + * vtkGDCMImageWriter/vtkGDCMImageReader are not Activiz object. + * + * TODO: Test Command/Observer + */ +public class HelloActiviz2 +{ + public static int Main(string[] args) + { + string filename = args[0]; + string outfilename = args[1]; + string outfilename2 = args[2]; + + vtkGDCMImageReader reader = new Kitware.VTK.GDCM.vtkGDCMImageReader(); + reader.SetFileName( filename ); + + // When calling multiple times creation of C# object from the same C++ object it triggers a: +//error: potential refcounting error: Duplicate rawCppThis - weak reference that is still alive. Attempting to add '0x00b2dc10' again. +// Allowing new wrapped object to take over table key... +// Original object should *not* have been destroyed while we still had it in our table without notifying us... + //reader.GetOutput(); + //reader.GetOutput(); + + System.Console.WriteLine( reader.ToString() ); // Test the ToString compat with Activiz + + vtkGDCMImageWriter writer = new vtkGDCMImageWriter(); + writer.SetInput( reader.GetOutput() ); + writer.SetFileName( outfilename2 ); + writer.Write(); + + System.Console.WriteLine( reader.GetOutput().ToString() ); // Test the ToString compat with Activiz + + System.Console.WriteLine( writer.ToString() ); // Test the ToString compat with Activiz + + vtkPNGWriter pngwriter = new vtkPNGWriter(); + pngwriter.SetInput( reader.GetOutput() ); + pngwriter.SetFileName( outfilename ); + pngwriter.Write(); + + // at that point the .Write() should have triggered an Update() on the reader: + if( reader.GetImageFormat() == vtkgdcm.VTK_LUMINANCE ) // MONOCHROME2 + { + System.Console.WriteLine( "Image is MONOCHROME2" ); // + } + + vtkPNGReader bmpreader = new vtkPNGReader(); + bmpreader.SetFileName( outfilename ); + + vtkMedicalImageProperties prop = new vtkMedicalImageProperties(); + prop.SetModality( "MR" ); + + vtkMatrix4x4 dircos = reader.GetDirectionCosines(); + dircos.Invert(); + + vtkGDCMImageWriter writer2 = new vtkGDCMImageWriter(); + writer2.SetFileName( outfilename2 ); + writer2.SetDirectionCosines( dircos ); + writer2.SetMedicalImageProperties( prop ); + writer2.SetInput( bmpreader.GetOutput() ); + writer2.Write(); + + return 0; + } +} diff --git a/gdcm/Utilities/VTK/Examples/Csharp/HelloActiviz3.cs b/gdcm/Utilities/VTK/Examples/Csharp/HelloActiviz3.cs new file mode 100644 index 0000000..ae4cec9 --- /dev/null +++ b/gdcm/Utilities/VTK/Examples/Csharp/HelloActiviz3.cs @@ -0,0 +1,49 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +using Kitware.VTK; +using Kitware.VTK.GDCM; + +/* + * $ export MONO_PATH=/usr/lib/cli/ActiViz.NET/:/usr/lib/cli/Kitware.mummy.Runtime-1.0 + * $ mono ./bin/HelloActiviz3.exe ~/Creatis/gdcmData/test.acr + */ +public class HelloActiviz3 +{ + public static int Main(string[] args) + { + string filename = args[0]; + + vtkGDCMImageReader reader = vtkGDCMImageReader.New(); + vtkStringArray array = vtkStringArray.New(); + array.InsertNextValue(filename); + + reader.SetFileNames(array); + reader.Update(); + + //System.Console.Write(reader.GetOutput()); + + vtkRenderWindowInteractor iren = vtkRenderWindowInteractor.New(); + + vtkImageViewer2 viewer = vtkImageViewer2.New(); + viewer.SetInput(reader.GetOutput()); + viewer.SetupInteractor(iren); + viewer.SetSize(600, 600); + viewer.Render(); + + iren.Initialize(); + iren.Start(); + + return 0; + } +} diff --git a/gdcm/Utilities/VTK/Examples/Csharp/HelloActiviz4.cs b/gdcm/Utilities/VTK/Examples/Csharp/HelloActiviz4.cs new file mode 100644 index 0000000..808155a --- /dev/null +++ b/gdcm/Utilities/VTK/Examples/Csharp/HelloActiviz4.cs @@ -0,0 +1,49 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +using Kitware.VTK; +using Kitware.VTK.GDCM; + +/* + * $ export MONO_PATH=/usr/lib/cli/ActiViz.NET/:/usr/lib/cli/Kitware.mummy.Runtime-1.0 + * $ mono ./bin/HelloActiviz4.exe ~/Creatis/gdcmData/test.acr + */ +public class HelloActiviz4 +{ + public static int Main(string[] args) + { + string filename = args[0]; + + vtkGDCMImageReader reader = new vtkGDCMImageReader(); + vtkStringArray array = vtkStringArray.New(); + array.InsertNextValue(filename); + + reader.SetFileNames(array); + reader.Update(); + + //System.Console.Write(reader.GetOutput()); + + vtkRenderWindowInteractor iren = vtkRenderWindowInteractor.New(); + + vtkImageViewer viewer = vtkImageViewer.New(); + viewer.SetInput(reader.GetOutput()); + viewer.SetupInteractor(iren); + viewer.SetSize(600, 600); + viewer.Render(); + + iren.Initialize(); + iren.Start(); + + return 0; + } +} diff --git a/gdcm/Utilities/VTK/Examples/Csharp/HelloActiviz5.cs b/gdcm/Utilities/VTK/Examples/Csharp/HelloActiviz5.cs new file mode 100644 index 0000000..ea5276a --- /dev/null +++ b/gdcm/Utilities/VTK/Examples/Csharp/HelloActiviz5.cs @@ -0,0 +1,98 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +using Kitware.VTK; +using Kitware.VTK.GDCM; + +// The command line arguments are: +// -I => run in interactive mode; unless this is used, the program will +// not allow interaction and exit +// -D => path to the data; the data should be in /Data/ + +/* + * $ export MONO_PATH=/usr/lib/cli/ActiViz.NET/:/usr/lib/cli/Kitware.mummy.Runtime-1.0 + * $ mono ./bin/HelloActiviz5.exe -I + */ +public class HelloActiviz5 +{ + public static int Main(string[] args) + { + vtkTesting testHelper = vtkTesting.New(); + for ( int cc = 0; cc < args.Length; cc++ ) + { + //testHelper.AddArguments(argc,const_cast(argv)); + //System.Console.Write( "args: " + args[cc] + "\n" ); + testHelper.AddArgument( args[cc] ); + } + if ( testHelper.IsFlagSpecified("-D") != 0 ) + { + string VTK_DATA_ROOT = vtkGDCMTesting.GetVTKDataRoot(); + if( VTK_DATA_ROOT != null ) + { + //System.Console.Write( "VTK_DATA_ROOT: " + VTK_DATA_ROOT + "\n" ); + testHelper.SetDataRoot(VTK_DATA_ROOT); + testHelper.AddArgument("-D"); + testHelper.AddArgument(VTK_DATA_ROOT); + } + } + + string dataRoot = testHelper.GetDataRoot(); + string filename = dataRoot; + filename += "/Data/mr.001"; + + vtkDirectory dir = vtkDirectory.New(); + if( dir.FileIsDirectory( dataRoot ) == 0 ) + { + filename = vtkGDCMTesting.GetGDCMDataRoot() + "/test.acr"; + } + //System.Console.Write( "dataRoot: " + dataRoot + "\n" ); + System.Console.Write( "filename being used is: " + filename + "\n" ); + + vtkGDCMImageReader reader = vtkGDCMImageReader.New(); + vtkStringArray array = vtkStringArray.New(); + array.InsertNextValue(filename); + reader.SetFileNames(array); + reader.Update(); + + System.Console.Write(reader.GetOutput()); + + vtkRenderWindowInteractor iren = vtkRenderWindowInteractor.New(); + + vtkRenderer ren1 = vtkRenderer.New(); + vtkRenderWindow renWin = vtkRenderWindow.New(); + renWin.AddRenderer(ren1); + + vtkImageActor actor = vtkImageActor.New(); + + vtkImageMapToWindowLevelColors coronalColors = vtkImageMapToWindowLevelColors.New(); + coronalColors.SetInput(reader.GetOutput()); + + actor.SetInput(coronalColors.GetOutput()); + + ren1.AddActor(actor); + iren.SetRenderWindow(renWin); + + iren.Initialize(); + + renWin.Render(); + + int retVal = testHelper.IsInteractiveModeSpecified(); + + if( retVal != 0 ) + { + iren.Start(); + } + + return 0; + } +} diff --git a/gdcm/Utilities/VTK/Examples/Csharp/HelloVTKWorld.cs b/gdcm/Utilities/VTK/Examples/Csharp/HelloVTKWorld.cs new file mode 100644 index 0000000..19437ff --- /dev/null +++ b/gdcm/Utilities/VTK/Examples/Csharp/HelloVTKWorld.cs @@ -0,0 +1,54 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +using vtkgdcm; + +/* + * This test only test the SWIG/VTK part, you do not need Activiz + */ +public class HelloVTKWorld +{ + public static int Main(string[] args) + { + string filename = args[0]; + vtkGDCMImageReader reader = vtkGDCMImageReader.New(); + reader.SetFileName( filename ); + reader.Update(); + + vtkMedicalImageProperties prop = reader.GetMedicalImageProperties(); + System.Console.WriteLine( prop.GetPatientName() ); // + + if( reader.GetImageFormat() == vtkgdcm.vtkgdcm.VTK_LUMINANCE ) // MONOCHROME2 + { + System.Console.WriteLine( "Image is MONOCHROME2" ); // + } + + // Just for fun, invert the direction cosines, output should reflect that: + vtkMatrix4x4 dircos = reader.GetDirectionCosines(); + dircos.Invert(); + + string outfilename = args[1]; + vtkGDCMImageWriter writer = vtkGDCMImageWriter.New(); + writer.SetMedicalImageProperties( reader.GetMedicalImageProperties() ); + writer.SetDirectionCosines( dircos ); + writer.SetShift( reader.GetShift() ); + writer.SetScale( reader.GetScale() ); + writer.SetImageFormat( reader.GetImageFormat() ); + writer.SetFileName( outfilename ); + //writer.SetInputConnection( reader.GetOutputPort() ); // new + writer.SetInput( reader.GetOutput() ); // old + writer.Write(); + + return 0; + } +} diff --git a/gdcm/Utilities/VTK/Examples/Csharp/HelloVTKWorld2.cs b/gdcm/Utilities/VTK/Examples/Csharp/HelloVTKWorld2.cs new file mode 100644 index 0000000..b5145ac --- /dev/null +++ b/gdcm/Utilities/VTK/Examples/Csharp/HelloVTKWorld2.cs @@ -0,0 +1,47 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +using vtkgdcm; + +/* + * This test only test the SWIG/VTK part, you do not need Activiz + */ +public class HelloVTKWorld2 +{ + public static int Main(string[] args) + { + string VTK_DATA_ROOT = vtkGDCMTesting.GetVTKDataRoot(); + + vtkVolume16Reader reader = vtkVolume16Reader.New(); + reader.SetDataDimensions(64, 64); + reader.SetDataByteOrderToLittleEndian(); + reader.SetFilePrefix(VTK_DATA_ROOT + "/Data/headsq/quarter"); + reader.SetImageRange(1, 93); + reader.SetDataSpacing(3.2, 3.2, 1.5); + + vtkImageCast cast = vtkImageCast.New(); + cast.SetInput( reader.GetOutput() ); + cast.SetOutputScalarTypeToUnsignedChar(); + + // By default this is creating a Multiframe Grayscale Word Secondary Capture Image Storage + vtkGDCMImageWriter writer = vtkGDCMImageWriter.New(); + writer.SetFileName( "headsq.dcm" ); + writer.SetInput( reader.GetOutput() ); + // cast -> Multiframe Grayscale Byte Secondary Capture Image Storage + // writer.SetInput( cast.GetOutput() ); + writer.SetFileDimensionality( 3 ); + writer.Write(); + + return 0; + } +} diff --git a/gdcm/Utilities/VTK/Examples/Csharp/MetaImageMD5Activiz.cs b/gdcm/Utilities/VTK/Examples/Csharp/MetaImageMD5Activiz.cs new file mode 100644 index 0000000..b12232a --- /dev/null +++ b/gdcm/Utilities/VTK/Examples/Csharp/MetaImageMD5Activiz.cs @@ -0,0 +1,112 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +using Kitware.VTK; +using Kitware.VTK.GDCM; +using gdcm; + +/* + * $ export MONO_PATH=/usr/lib/cli/ActiViz.NET/:/usr/lib/cli/Kitware.mummy.Runtime-1.0 + * $ mono ./bin/MetaImageMD5Activiz.exe gdcmData/012345.002.050.dcm + */ +public class MetaImageMD5Activiz +{ + public static int ProcessOneMHDMD5(string filename) + { + vtkGDCMImageReader reader = vtkGDCMImageReader.New(); + reader.FileLowerLeftOn(); + reader.DebugOff(); + int canread = reader.CanReadFile( filename ); + if( canread == 0 ) + { + string refms = gdcm.Testing.GetMediaStorageFromFile(filename); + if( gdcm.MediaStorage.IsImage( gdcm.MediaStorage.GetMSType(refms) ) ) + { + System.Console.Write( "Problem with file: " + filename + "\n" ); + return 1; + } + // not an image + return 0; + } + + reader.SetFileName( filename ); + reader.Update(); + + // System.Console.Write(reader.GetOutput()); + + vtkMetaImageWriter writer = vtkMetaImageWriter.New(); + writer.SetCompression( false ); + writer.SetInput( reader.GetOutput() ); + string subdir = "MetaImageMD5Activiz"; + string tmpdir = gdcm.Testing.GetTempDirectory( subdir ); + if( !gdcm.PosixEmulation.FileIsDirectory( tmpdir ) ) + { + gdcm.PosixEmulation.MakeDirectory( tmpdir ); + } + string mhdfile = gdcm.Testing.GetTempFilename( filename, subdir ); + + string rawfile = mhdfile; + mhdfile += ".mhd"; + rawfile += ".raw"; + writer.SetFileName( mhdfile ); + writer.Write(); + + string digestmhd = gdcm.Testing.ComputeFileMD5( mhdfile ); + string digestraw = gdcm.Testing.ComputeFileMD5( rawfile ); + + string mhdref = vtkGDCMTesting.GetMHDMD5FromFile(filename); + string rawref = vtkGDCMTesting.GetRAWMD5FromFile(filename); + + if( mhdref != digestmhd ) + { + System.Console.Write( "Problem with mhd file: " + filename + "\n" ); + System.Console.Write( digestmhd ); + System.Console.Write( "\n" ); + System.Console.Write( mhdref ); + System.Console.Write( "\n" ); + return 1; + } + if( rawref != digestraw ) + { + System.Console.Write( "Problem with raw file: " + filename + "\n" ); + System.Console.Write( digestraw ); + System.Console.Write( "\n" ); + System.Console.Write( rawref ); + System.Console.Write( "\n" ); + return 1; + } + + return 0; + } + public static int Main(string[] args) + { + if ( args.Length == 1 ) + { + string filename = args[0]; + return ProcessOneMHDMD5( filename ); + } + // Loop over all gdcmData + gdcm.Trace.DebugOff(); + gdcm.Trace.WarningOff(); + gdcm.Trace.ErrorOff(); + + uint n = gdcm.Testing.GetNumberOfFileNames(); + int ret = 0; + for( uint i = 0; i < n; ++i ) + { + string filename = gdcm.Testing.GetFileName( i ); + ret += ProcessOneMHDMD5( filename ); + } + return ret; + } +} diff --git a/gdcm/Utilities/VTK/Examples/Csharp/RefCounting.cs b/gdcm/Utilities/VTK/Examples/Csharp/RefCounting.cs new file mode 100644 index 0000000..1872e5f --- /dev/null +++ b/gdcm/Utilities/VTK/Examples/Csharp/RefCounting.cs @@ -0,0 +1,54 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +using Kitware.VTK; +using Kitware.VTK.GDCM; + +/* + * this is not so much an example but simply a test to make sure cstor / dstor work as expected + * and call the ::New and ->Delete() of VTK style. + */ +public class RefCounting +{ + public static int Main(string[] args) + { + vtkGDCMTesting testing1 = vtkGDCMTesting.New(); + vtkGDCMTesting testing2 = new vtkGDCMTesting(); // just in case people do not read STYLE documentation + + vtkGDCMImageReader reader1 = vtkGDCMImageReader.New(); + vtkGDCMImageReader reader2 = new vtkGDCMImageReader(); + + vtkGDCMImageWriter writer1 = vtkGDCMImageWriter.New(); + vtkGDCMImageWriter writer2 = new vtkGDCMImageWriter(); + + using (vtkGDCMTesting testing3 = new vtkGDCMTesting()) + { + System.Console.Write( "GetReferenceCount: " + testing1.GetReferenceCount() + "\n"); + System.Console.Write( "GetReferenceCount: " + testing2.GetReferenceCount() + "\n"); + System.Console.Write( "GetReferenceCount: " + testing3.GetReferenceCount() + "\n"); + } + + using (vtkGDCMImageReader reader3 = new vtkGDCMImageReader()) + { + System.Console.Write( "GetReferenceCount: " + reader3.GetReferenceCount() + "\n"); + } + + using (vtkGDCMImageWriter writer3 = vtkGDCMImageWriter.New()) + { + System.Console.Write( "GetReferenceCount: " + writer3.GetReferenceCount() + "\n"); + } + + // C# destructor will call ->Delete on all C++ object as expected. + return 0; + } +} diff --git a/gdcm/Utilities/VTK/Examples/Cxx/CMakeLists.txt b/gdcm/Utilities/VTK/Examples/Cxx/CMakeLists.txt new file mode 100644 index 0000000..5bf9d5e --- /dev/null +++ b/gdcm/Utilities/VTK/Examples/Cxx/CMakeLists.txt @@ -0,0 +1,76 @@ +include_directories( + ${GDCM_SOURCE_DIR}/Utilities/VTK + ) + + +if( "${VTK_MAJOR_VERSION}.${VTK_MINOR_VERSION}" GREATER 5.0 ) + set(GDCM_VTK_APPS + ConvertSingleBitTo8Bits + GenerateRTSTRUCT + offscreenimage + ) + if(VTK_USE_RENDERING OR vtkRenderingCore_LOADED) + set(GDCM_VTK_APPS + ${GDCM_VTK_APPS} + gdcmorthoplanes + gdcmreslice + gdcmrtionplan + gdcmrtplan + gdcmscene + gdcmtexture + gdcmvolume + rtstructapp + ) + endif() + if(GDCM_BUILD_TESTING) + set(GDCM_VTK_APPS + ${GDCM_VTK_APPS} + ConvertRGBToLuminance + Convert16BitsTo8Bits + ConvertMultiFrameToSingleFrame + MagnifyFile + ) + if(GDCM_DATA_EXTRA_ROOT) + if(VTK_USE_RENDERING OR vtkRenderingCore_LOADED) + set(GDCM_VTK_APPS + ${GDCM_VTK_APPS} + reslicesphere + ) + endif() + endif() + endif() +endif() + +foreach(app ${GDCM_VTK_APPS}) + add_executable(${app} ${app}.cxx) + #set_target_properties(${app} PROPERTIES ${GDCM_EXECUTABLE_PROPERTIES}) + target_link_libraries(${app} ${VTKGDCM_NAME} ${vtkgdcm_LIBS}) + target_link_libraries(${app} gdcmDSED gdcmMSFF gdcmCommon) + if(GDCM_BUILD_TESTING) + # gdcmTesting is in Common: + target_link_libraries(${app} gdcmCommon) + endif() + if( "${VTK_MAJOR_VERSION}.${VTK_MINOR_VERSION}" GREATER 6.0 ) + target_link_libraries(${app} ${VTK_LIBRARIES}) + else() + if( "${VTK_MAJOR_VERSION}.${VTK_MINOR_VERSION}" GREATER 5.0 ) + if(VTK_USE_RENDERING) + target_link_libraries(${app} vtkWidgets vtkVolumeRendering) + endif() + endif() + endif() +endforeach() + +if(GDCM_HAVE_PTHREAD_H) +# Dev only: I dont need to install that one: + add_executable(threadgdcm threadgdcm.cxx) + target_link_libraries(threadgdcm gdcmMSFF pthread ) + if( "${VTK_MAJOR_VERSION}.${VTK_MINOR_VERSION}" GREATER 6.0 ) + target_link_libraries(threadgdcm ${VTK_LIBRARIES}) + else() + target_link_libraries(threadgdcm vtkIO) + endif() +endif() + +#add_executable(gdcm2vtk gdcm2vtk.cxx) +#target_link_libraries(gdcm2vtk gdcmMSFF pthread) diff --git a/gdcm/Utilities/VTK/Examples/Cxx/Convert16BitsTo8Bits.cxx b/gdcm/Utilities/VTK/Examples/Cxx/Convert16BitsTo8Bits.cxx new file mode 100644 index 0000000..e02ba8a --- /dev/null +++ b/gdcm/Utilities/VTK/Examples/Cxx/Convert16BitsTo8Bits.cxx @@ -0,0 +1,64 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkGDCMImageReader.h" +#include "vtkGDCMImageWriter.h" +#include "vtkImageData.h" +#include "vtkImageCast.h" + +#include "gdcmTesting.h" +// The following file is 16/16/15 but the scalar range of the image is [0,192] +// it could be safely stored as 8bits instead: +// gdcmData/012345.002.050.dcm + +int main(int, char *[]) +{ + const char *directory = gdcm::Testing::GetDataRoot(); + if(!directory) return 1; + std::string file = std::string(directory) + "/012345.002.050.dcm"; + std::cout << file << std::endl; + + vtkGDCMImageReader *reader = vtkGDCMImageReader::New(); + reader->SetFileName( file.c_str() ); + reader->Update(); + //reader->GetOutput()->Print( std::cout ); + + vtkImageCast *cast = vtkImageCast::New(); +#if (VTK_MAJOR_VERSION >= 6) + cast->SetInputConnection( reader->GetOutputPort() ); +#else + cast->SetInput( reader->GetOutput() ); +#endif + cast->SetOutputScalarTypeToUnsignedChar(); + + + vtkGDCMImageWriter *writer = vtkGDCMImageWriter::New(); + writer->SetFileName( "/tmp/cast.dcm" ); +#if (VTK_MAJOR_VERSION >= 6) + writer->SetInputConnection( cast->GetOutputPort() ); +#else + writer->SetInput( cast->GetOutput() ); +#endif + writer->SetImageFormat( reader->GetImageFormat() ); + writer->SetMedicalImageProperties( reader->GetMedicalImageProperties() ); + writer->SetDirectionCosines( reader->GetDirectionCosines() ); + writer->SetShift( reader->GetShift() ); + writer->SetScale( reader->GetScale() ); + writer->Write(); + + reader->Delete(); + cast->Delete(); + writer->Delete(); + + return 0; +} diff --git a/gdcm/Utilities/VTK/Examples/Cxx/ConvertMultiFrameToSingleFrame.cxx b/gdcm/Utilities/VTK/Examples/Cxx/ConvertMultiFrameToSingleFrame.cxx new file mode 100644 index 0000000..f05d94e --- /dev/null +++ b/gdcm/Utilities/VTK/Examples/Cxx/ConvertMultiFrameToSingleFrame.cxx @@ -0,0 +1,88 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkGDCMImageReader.h" +#include "vtkGDCMImageWriter.h" +#include "vtkImageData.h" +#include "vtkStringArray.h" + +#include "gdcmTesting.h" +#include "gdcmFilenameGenerator.h" + +int main(int argc, char *argv[]) +{ + std::string filename; + if( argc <= 1 ) + { + const char *directory = gdcm::Testing::GetDataRoot(); + if(!directory) return 1; + std::string file = std::string(directory) + "/US-PAL-8-10x-echo.dcm"; + filename = file; + } + else + { + filename = argv[1]; + } + std::cout << "file: " << filename << std::endl; + + vtkGDCMImageReader *reader = vtkGDCMImageReader::New(); + reader->SetFileName( filename.c_str() ); + reader->Update(); + //reader->GetOutput()->Print( std::cout ); + + int dims[3]; + reader->GetOutput()->GetDimensions( dims ); + + std::ostringstream os; + os << "singleframe"; + os << "%04d.dcm"; + gdcm::FilenameGenerator fg; + fg.SetPattern( os.str().c_str() ); + unsigned int nfiles = dims[2]; + fg.SetNumberOfFilenames( nfiles ); + bool b = fg.Generate(); + if( !b ) + { + std::cerr << "FilenameGenerator::Generate() failed" << std::endl; + return 1; + } + if( !fg.GetNumberOfFilenames() ) + { + std::cerr << "FilenameGenerator::Generate() failed somehow..." << std::endl; + return 1; + } + + // By default write them as Secondary Capture (for portability) + vtkGDCMImageWriter *writer = vtkGDCMImageWriter::New(); + vtkStringArray *filenames = vtkStringArray::New(); + for(unsigned int i = 0; i < fg.GetNumberOfFilenames(); ++i) + { + filenames->InsertNextValue( fg.GetFilename(i) ); + } + assert( filenames->GetNumberOfValues() == (int)fg.GetNumberOfFilenames() ); + writer->SetFileNames( filenames ); + filenames->Delete(); + writer->SetFileDimensionality( 2 ); +#if (VTK_MAJOR_VERSION >= 6) + writer->SetInputConnection( reader->GetOutputPort() ); +#else + writer->SetInput( reader->GetOutput() ); +#endif + writer->SetImageFormat( reader->GetImageFormat() ); + writer->Write(); + + reader->Delete(); + writer->Delete(); + + return 0; +} diff --git a/gdcm/Utilities/VTK/Examples/Cxx/ConvertRGBToLuminance.cxx b/gdcm/Utilities/VTK/Examples/Cxx/ConvertRGBToLuminance.cxx new file mode 100644 index 0000000..6eec916 --- /dev/null +++ b/gdcm/Utilities/VTK/Examples/Cxx/ConvertRGBToLuminance.cxx @@ -0,0 +1,65 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkGDCMImageReader.h" +#include "vtkGDCMImageWriter.h" +#include "vtkImageData.h" +#include "vtkImageLuminance.h" + +#include "gdcmTesting.h" + +// There is no such thing as MR Image Storage + Photometric Interpretation = RGB +// let's rewrite that into a proper single component image: +int main(int, char *[]) +{ + const char *directory = gdcm::Testing::GetDataRoot(); + if(!directory) return 1; + std::string file = std::string(directory) + "/SIEMENS-MR-RGB-16Bits.dcm"; + std::cout << file << std::endl; + + vtkGDCMImageReader *reader = vtkGDCMImageReader::New(); + reader->SetFileName( file.c_str() ); + reader->Update(); + //reader->GetOutput()->Print( std::cout ); + + vtkImageLuminance *luminance = vtkImageLuminance::New(); +#if (VTK_MAJOR_VERSION >= 6) + luminance->SetInputConnection( reader->GetOutputPort() ); +#else + luminance->SetInput( reader->GetOutput() ); +#endif + + + vtkGDCMImageWriter *writer = vtkGDCMImageWriter::New(); + writer->SetFileName( "/tmp/bla.dcm" ); +#if (VTK_MAJOR_VERSION >= 6) + writer->SetInputConnection( luminance->GetOutputPort() ); +#else + writer->SetInput( luminance->GetOutput() ); +#endif + //writer->SetImageFormat( reader->GetImageFormat() ); // Do NOT pass image format + writer->SetMedicalImageProperties( reader->GetMedicalImageProperties() ); + writer->SetDirectionCosines( reader->GetDirectionCosines() ); + writer->SetShift( reader->GetShift() ); + writer->SetScale( reader->GetScale() ); + writer->Write(); + + // TODO: + //vtkImageAppendComponents.h + + reader->Delete(); + luminance->Delete(); + writer->Delete(); + + return 0; +} diff --git a/gdcm/Utilities/VTK/Examples/Cxx/ConvertSingleBitTo8Bits.cxx b/gdcm/Utilities/VTK/Examples/Cxx/ConvertSingleBitTo8Bits.cxx new file mode 100644 index 0000000..4e17e92 --- /dev/null +++ b/gdcm/Utilities/VTK/Examples/Cxx/ConvertSingleBitTo8Bits.cxx @@ -0,0 +1,83 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkGDCMImageReader.h" +#include "vtkGDCMImageWriter.h" +#include "vtkImageData.h" +#include "vtkImageCast.h" +#include "vtkPointData.h" +#include "vtkBitArray.h" +#include "vtkUnsignedCharArray.h" + +int main(int argc, char *argv[]) +{ + if( argc < 3 ) + { + return 1; + } + const char *filename = argv[1]; + const char *outfilename = argv[2]; + + vtkGDCMImageReader *reader = vtkGDCMImageReader::New(); + reader->SetFileName( filename ); + reader->Update(); + //reader->GetOutput()->Print( std::cout ); + + vtkDataArray* array = reader->GetOutput()->GetPointData()->GetScalars(); + vtkBitArray *barray = vtkBitArray::SafeDownCast( array ); + if( !barray ) return false; + vtkIdType nvalues = array->GetNumberOfTuples(); + vtkUnsignedCharArray *uarray = vtkUnsignedCharArray::New(); + uarray->SetNumberOfTuples( nvalues ); + for(vtkIdType i = 0; i < nvalues; ++i) + { + uarray->SetValue( i, (unsigned char)barray->GetValue(i) ); + } + + vtkImageData *copy = vtkImageData::New(); + // http://www.vtk.org/Wiki/VTK/VTK_6_Migration/Changes_to_Scalars_Manipulation_Functions#AllocateScalars.28.29 + copy->SetExtent( reader->GetOutput()->GetExtent() ); +#if (VTK_MAJOR_VERSION >= 6) + copy->AllocateScalars(VTK_UNSIGNED_CHAR, 3); +#else + copy->SetScalarType( VTK_UNSIGNED_CHAR ); + copy->AllocateScalars(); +#endif + + //uarray->Print( std::cout ); + //copy->GetPointData()->GetScalars()->Print( std::cout ); + copy->GetPointData()->SetScalars( uarray ); + uarray->Delete(); + + vtkGDCMImageWriter *writer = vtkGDCMImageWriter::New(); + writer->SetFileName( outfilename ); + //writer->SetInput( cast->GetOutput() ); +#if (VTK_MAJOR_VERSION >= 6) + writer->SetInputData( copy ); +#else + writer->SetInput( copy ); +#endif + writer->SetImageFormat( reader->GetImageFormat() ); + writer->SetMedicalImageProperties( reader->GetMedicalImageProperties() ); + writer->SetDirectionCosines( reader->GetDirectionCosines() ); + writer->SetShift( reader->GetShift() ); + writer->SetScale( reader->GetScale() ); + writer->SetFileDimensionality( reader->GetFileDimensionality( ) ); + writer->Write(); + + reader->Delete(); + copy->Delete(); + writer->Delete(); + + return 0; +} diff --git a/gdcm/Utilities/VTK/Examples/Cxx/GenerateRTSTRUCT.cxx b/gdcm/Utilities/VTK/Examples/Cxx/GenerateRTSTRUCT.cxx new file mode 100644 index 0000000..eeb3437 --- /dev/null +++ b/gdcm/Utilities/VTK/Examples/Cxx/GenerateRTSTRUCT.cxx @@ -0,0 +1,213 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkGDCMPolyDataWriter.h" +#include "vtkGDCMPolyDataReader.h" +#include "vtkPolyData.h" +#include "vtkPolyDataReader.h" +#include "vtkMedicalImageProperties.h" +#include "vtkRTStructSetProperties.h" +#include "vtkStringArray.h" +#include "vtkAppendPolyData.h" +#include "vtkPolyDataWriter.h" +#include "vtkPolyDataMapper.h" +#include "vtkPolyDataMapper2D.h" +#include "vtkActor2D.h" +#include "vtkRenderWindowInteractor.h" +#include "vtkMedicalImageProperties.h" +#include "vtkRenderWindow.h" +#include "vtkRenderer.h" +#include "vtkCamera.h" +#include "vtkProperty.h" +#include "vtkProperty2D.h" +#include "vtkImageData.h" + +#include //for std::find + +#include "gdcmDirectoryHelper.h" + +using namespace gdcm; + +//view each organ independently of the others, to make sure that +//organ names correspond to actual segmentations. +void ShowOrgan(vtkPolyData* inData) +{ + // Now we'll look at it. + vtkPolyDataMapper *cubeMapper = vtkPolyDataMapper::New(); +#if (VTK_MAJOR_VERSION >= 6) + cubeMapper->SetInputData( inData ); +#else + cubeMapper->SetInput( inData ); +#endif + cubeMapper->SetScalarRange(0,7); + vtkActor *cubeActor = vtkActor::New(); + cubeActor->SetMapper(cubeMapper); + vtkProperty * property = cubeActor->GetProperty(); + property->SetRepresentationToWireframe(); + + vtkRenderer *renderer = vtkRenderer::New(); + vtkRenderWindow *renWin = vtkRenderWindow::New(); + renWin->AddRenderer(renderer); + + vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New(); + iren->SetRenderWindow(renWin); + + renderer->AddActor(cubeActor); + renderer->ResetCamera(); + renderer->SetBackground(1,1,1); + + renWin->SetSize(300,300); + + renWin->Render(); + iren->Start(); + + cubeMapper->Delete(); + cubeActor->Delete(); + renderer->Delete(); + renWin->Delete(); + iren->Delete(); +} + +/* + * Full application which ... RTSTUCT + */ +int main(int argc, char *argv[]) +{ + if( argc < 2 ) + { + std::cerr << argv[0] << " directory-with-rtstruct-and-ct-images\n"; + return 1; + } + std::string theDirName(argv[1]); + Directory::FilenamesType theRTSeries = + DirectoryHelper::GetRTStructSeriesUIDs(theDirName); + + gdcm::Directory theDir; + theDir.Load(argv[1]); + + if (theRTSeries.empty()) + { + std::cerr << "No RTStructs found for the test, ending." << std::endl; + return 1; + } + + for (size_t q = 0; q < theRTSeries.size(); q++) + { + Directory::FilenamesType theRTNames = + DirectoryHelper::GetFilenamesFromSeriesUIDs(theDirName, theRTSeries[q]); + + if (theRTNames.empty()){ + std::cerr << "Unable to load RT Series " << theRTSeries[q] << ", continuing. " << std::endl; + continue; + } + + vtkGDCMPolyDataReader * reader = vtkGDCMPolyDataReader::New(); + reader->SetFileName( theRTNames[0].c_str() ); + reader->Update(); + + //std::cout << reader->GetMedicalImageProperties()->GetStudyDate() << std::endl; + + vtkGDCMPolyDataWriter * writer = vtkGDCMPolyDataWriter::New(); + int numMasks = reader->GetNumberOfOutputPorts() + 1;//add a blank one in + writer->SetNumberOfInputPorts( numMasks ); + std::string thePotentialName = theDirName + "/" + "GDCMTestRTStruct." + theRTSeries[q] + ".dcm"; + gdcm::Directory::FilenamesType theFileNames = theDir.GetFilenames(); + //keep renaming the output until we get something that doesn't overwrite what was there already + int count = 0; + while (std::find(theFileNames.begin(), theFileNames.end(), thePotentialName) != theFileNames.end()) + { + char buff[255]; + sprintf(buff,"%d",count); + thePotentialName = theDirName + "/" + "GDCMTestRTStruct." + buff + "." + theRTSeries[q] + ".dcm"; + } + writer->SetFileName( thePotentialName.c_str()); + writer->SetMedicalImageProperties( reader->GetMedicalImageProperties() ); + //this line is cheating, we won't have the same stuff, and may not have a struct + //to start with. + //have to go back to the original data to reconstruct the RTStructureSetProperties + //writer->SetRTStructSetProperties( reader->GetRTStructSetProperties() ); + //writer->Write(); + + //loop through the outputs in order to write them out as if they had been created and appended + vtkStringArray* roiNames = vtkStringArray::New(); + vtkStringArray* roiAlgorithms = vtkStringArray::New(); + vtkStringArray* roiTypes = vtkStringArray::New(); + roiNames->SetNumberOfValues(numMasks); + roiAlgorithms->SetNumberOfValues(numMasks); + roiTypes->SetNumberOfValues(numMasks); + vtkAppendPolyData* append = vtkAppendPolyData::New(); + + //ok, now we'll add a blank organ + //the blank organ is to test to ensure that blank organs work; there have been crash reports + //this code is added at the beginning to ensure that the blank organs are read + //and preserved as individual organs. + vtkPolyData* blank = vtkPolyData::New(); +#if (VTK_MAJOR_VERSION >= 6) + writer->SetInputData(0, blank); +#else + writer->SetInput(0, blank); +#endif + roiNames->InsertValue(0, "blank"); + roiAlgorithms->InsertValue(0, "blank"); + roiTypes->InsertValue(0, "ORGAN"); + + //note the offsets used to place the blank rtstruct at the beginning of the newly generated RT. + //the idea is to run the program twice; first to generate an rtstruct with a blank mask (making + //sure that that functionality works), and then a second time to make sure that everything is + //being read properly. Multiple organs with the same name could cause some strangenesses. + for (int i = 1; i < numMasks; ++i) + { +#if (VTK_MAJOR_VERSION >= 6) + writer->SetInputConnection(i, reader->GetOutputPort(i-1)); + append->AddInputConnection(reader->GetOutputPort(i-1)); +#else + writer->SetInput(i, reader->GetOutput(i-1)); + append->AddInput(reader->GetOutput(i-1)); +#endif + std::string theString = reader->GetRTStructSetProperties()->GetStructureSetROIName(i-1); + roiNames->InsertValue(i, theString); + theString = reader->GetRTStructSetProperties()->GetStructureSetROIGenerationAlgorithm(i-1); + roiAlgorithms->InsertValue(i, theString); + theString = reader->GetRTStructSetProperties()->GetStructureSetRTROIInterpretedType(i-1); + roiTypes->InsertValue(i, theString); + + ShowOrgan(reader->GetOutput(i-1)); + } + + vtkRTStructSetProperties* theProperties = vtkRTStructSetProperties::New(); + writer->SetRTStructSetProperties(theProperties); + writer->InitializeRTStructSet(theDirName, + reader->GetRTStructSetProperties()->GetStructureSetLabel(), + reader->GetRTStructSetProperties()->GetStructureSetName(), + roiNames, roiAlgorithms, roiTypes); + + writer->SetRTStructSetProperties(theProperties); + writer->Write(); + + // print reader output: + reader->Print( std::cout ); + // print first output: + reader->GetOutput()->Print( std::cout ); + + reader->Delete(); + append->Delete(); + roiNames->Delete(); + roiTypes->Delete(); + theProperties->Delete(); + roiAlgorithms->Delete(); + blank->Delete(); + + writer->Delete(); + } + return 0; +} diff --git a/gdcm/Utilities/VTK/Examples/Cxx/MagnifyFile.cxx b/gdcm/Utilities/VTK/Examples/Cxx/MagnifyFile.cxx new file mode 100644 index 0000000..0ac6798 --- /dev/null +++ b/gdcm/Utilities/VTK/Examples/Cxx/MagnifyFile.cxx @@ -0,0 +1,79 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkGDCMImageReader.h" +#include "vtkGDCMImageWriter.h" +#include "vtkImageData.h" +#include "vtkImageMagnify.h" +#include "vtkImageCast.h" + +#include "gdcmTesting.h" +#include "gdcmSystem.h" + +// This is a simple test to magnify an image that is known to give excellent +// compression ratio. This will be our test for those large image +int main(int, char *[]) +{ + const char *directory = gdcm::Testing::GetDataRoot(); + if(!directory) return 1; + std::string file = std::string(directory) + "/test.acr"; + std::cout << file << std::endl; + if( !gdcm::System::FileExists( file.c_str() ) ) return 1; + + vtkGDCMImageReader *reader = vtkGDCMImageReader::New(); + reader->SetFileName( file.c_str() ); + reader->Update(); + //reader->GetOutput()->Print( std::cout ); + + vtkImageCast *cast = vtkImageCast::New(); +#if (VTK_MAJOR_VERSION >= 6) + cast->SetInputConnection( reader->GetOutputPort() ); +#else + cast->SetInput( reader->GetOutput() ); +#endif + cast->SetOutputScalarTypeToUnsignedShort(); + + vtkImageMagnify *magnify = vtkImageMagnify::New(); +#if (VTK_MAJOR_VERSION >= 6) + magnify->SetInputConnection( cast->GetOutputPort() ); +#else + magnify->SetInput( cast->GetOutput() ); +#endif + magnify->SetInterpolate( 1 ); + magnify->SetInterpolate( 0 ); + int factor = 100; + magnify->SetMagnificationFactors (factor, factor, 1); + + vtkGDCMImageWriter *writer = vtkGDCMImageWriter::New(); + writer->SetFileName( "/tmp/bla.dcm" ); +#if (VTK_MAJOR_VERSION >= 6) + writer->SetInputConnection( magnify->GetOutputPort() ); +#else + writer->SetInput( magnify->GetOutput() ); +#endif + writer->SetImageFormat( reader->GetImageFormat() ); + writer->SetMedicalImageProperties( reader->GetMedicalImageProperties() ); + writer->SetDirectionCosines( reader->GetDirectionCosines() ); + writer->SetShift( reader->GetShift() ); + writer->SetScale( reader->GetScale() ); + writer->Write(); + + // TODO: + //vtkImageAppendComponents.h + + reader->Delete(); + magnify->Delete(); + writer->Delete(); + + return 0; +} diff --git a/gdcm/Utilities/VTK/Examples/Cxx/gdcmorthoplanes.cxx b/gdcm/Utilities/VTK/Examples/Cxx/gdcmorthoplanes.cxx new file mode 100644 index 0000000..d86101a --- /dev/null +++ b/gdcm/Utilities/VTK/Examples/Cxx/gdcmorthoplanes.cxx @@ -0,0 +1,488 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#include "vtkActor.h" +#include "vtkCamera.h" +#include "vtkMatrix4x4.h" +#include "vtkTransform.h" +#include "vtkAssembly.h" +#include "vtkCellPicker.h" +#include "vtkCommand.h" +#include "vtkImageActor.h" +#include "vtkImageMapToColors.h" +#include "vtkImageOrthoPlanes.h" +#include "vtkImagePlaneWidget.h" +#include "vtkImageReader.h" +#include "vtkInteractorEventRecorder.h" +#include "vtkLookupTable.h" +#include "vtkOutlineFilter.h" +#include "vtkPolyDataMapper.h" +#include "vtkProperty.h" +#include "vtkRenderWindow.h" +#include "vtkRenderWindowInteractor.h" +#include "vtkRenderer.h" +#include "vtkVolume16Reader.h" +#include "vtkImageData.h" +#include "vtkImageChangeInformation.h" +#include "vtkOrientationMarkerWidget.h" +#include "vtkAnnotatedCubeActor.h" +#include "vtkAxesActor.h" +#include "vtkCaptionActor2D.h" +#include "vtkTextProperty.h" +#include "vtkPropAssembly.h" + +#include "vtkGDCMImageReader.h" +#include "vtkGDCMImageWriter.h" +#include "vtkStringArray.h" + +#include "gdcmSystem.h" +#include "gdcmDirectory.h" +#include "gdcmIPPSorter.h" + +#ifndef vtkFloatingPointType +#define vtkFloatingPointType float +#endif + +//---------------------------------------------------------------------------- +class vtkOrthoPlanesCallback : public vtkCommand +{ +public: + static vtkOrthoPlanesCallback *New() + { return new vtkOrthoPlanesCallback; } + + void Execute( vtkObject *caller, unsigned long vtkNotUsed( event ), + void *callData ) + { + vtkImagePlaneWidget* self = + reinterpret_cast< vtkImagePlaneWidget* >( caller ); + if(!self) return; + + double* wl = static_cast( callData ); + + if ( self == this->WidgetX ) + { + this->WidgetY->SetWindowLevel(wl[0],wl[1],1); + this->WidgetZ->SetWindowLevel(wl[0],wl[1],1); + } + else if( self == this->WidgetY ) + { + this->WidgetX->SetWindowLevel(wl[0],wl[1],1); + this->WidgetZ->SetWindowLevel(wl[0],wl[1],1); + } + else if (self == this->WidgetZ) + { + this->WidgetX->SetWindowLevel(wl[0],wl[1],1); + this->WidgetY->SetWindowLevel(wl[0],wl[1],1); + } + } + + vtkOrthoPlanesCallback():WidgetX( 0 ), WidgetY( 0 ), WidgetZ ( 0 ) {} + + vtkImagePlaneWidget* WidgetX; + vtkImagePlaneWidget* WidgetY; + vtkImagePlaneWidget* WidgetZ; +}; + +int main( int argc, char *argv[] ) +{ + //char* fname = vtkTestUtilities::ExpandDataFileName(argc, argv, "Data/headsq/quarter"); + + //vtkVolume16Reader* v16 = vtkVolume16Reader::New(); + // v16->SetDataDimensions( 64, 64); + // v16->SetDataByteOrderToLittleEndian(); + // v16->SetImageRange( 1, 93); + // v16->SetDataSpacing( 3.2, 3.2, 1.5); + // v16->SetFilePrefix( fname ); + // v16->SetDataMask( 0x7fff); + // v16->Update(); + std::vector filenames; + if( argc < 2 ) + { + std::cerr << argv[0] << " filename1.dcm [filename2.dcm ...]\n"; + return 1; + } + else + { + // Is it a single directory ? If so loop over all files contained in it: + const char *filename = argv[1]; + if( argc == 2 && gdcm::System::FileIsDirectory( filename ) ) + { + std::cout << "Loading directory: " << filename << std::endl; + bool recursive = false; + gdcm::Directory d; + d.Load(filename, recursive); + gdcm::Directory::FilenamesType const &files = d.GetFilenames(); + for( gdcm::Directory::FilenamesType::const_iterator it = files.begin(); it != files.end(); ++it ) + { + filenames.push_back( it->c_str() ); + } + } + else // list of files passed directly on the cmd line: + // discard non-existing or directory + { + for(int i=1; i < argc; ++i) + { + filename = argv[i]; + if( gdcm::System::FileExists( filename ) ) + { + if( gdcm::System::FileIsDirectory( filename ) ) + { + std::cerr << "Discarding directory: " << filename << std::endl; + } + else + { + filenames.push_back( filename ); + } + } + else + { + std::cerr << "Discarding non existing file: " << filename << std::endl; + } + } + } + //names->Print( std::cout ); + } + + vtkGDCMImageReader * reader = vtkGDCMImageReader::New(); + double ippzspacing; + if( filenames.size() > 1 ) + { + //gdcm::Trace::DebugOn(); + //gdcm::Trace::WarningOn(); + gdcm::IPPSorter s; + s.SetComputeZSpacing( true ); + s.SetZSpacingTolerance( 1e-3 ); + bool b = s.Sort( filenames ); + if( !b ) + { + std::cerr << "Failed to sort files" << std::endl; + return 1; + } + std::cout << "Sorting succeeded:" << std::endl; + s.Print( std::cout ); + + std::cout << "Found z-spacing:" << std::endl; + std::cout << s.GetZSpacing() << std::endl; + ippzspacing = s.GetZSpacing(); + + const std::vector & sorted = s.GetFilenames(); + vtkStringArray *files = vtkStringArray::New(); + std::vector< std::string >::const_iterator it = sorted.begin(); + for( ; it != sorted.end(); ++it) + { + const std::string &f = *it; + files->InsertNextValue( f.c_str() ); + } + reader->SetFileNames( files ); + //reader->SetFileLowerLeft( 1 ); + reader->Update(); // important + files->Delete(); + } + else + { + reader->SetFileName( argv[1] ); + reader->Update(); // important + ippzspacing = reader->GetOutput()->GetSpacing()[2]; + ippzspacing = 4; + } + + //reader->GetOutput()->Print( std::cout ); + //vtkFloatingPointType range[2]; + //reader->GetOutput()->GetScalarRange(range); + //std::cout << "Range: " << range[0] << " " << range[1] << std::endl; + + const vtkFloatingPointType *spacing = reader->GetOutput()->GetSpacing(); + + vtkImageChangeInformation *v16 = vtkImageChangeInformation::New(); +#if (VTK_MAJOR_VERSION >= 6) + v16->SetInputConnection( reader->GetOutputPort() ); +#else + v16->SetInput( reader->GetOutput() ); +#endif + v16->SetOutputSpacing( spacing[0], spacing[1], ippzspacing ); + v16->Update(); + +#if 0 + vtkGDCMImageWriter *writer = vtkGDCMImageWriter::New(); + writer->SetInput( v16->GetOutput() ); + writer->SetFileLowerLeft( reader->GetFileLowerLeft() ); + writer->SetDirectionCosines( reader->GetDirectionCosines() ); + writer->SetImageFormat( reader->GetImageFormat() ); + writer->SetFileDimensionality( 3); //reader->GetFileDimensionality() ); + writer->SetMedicalImageProperties( reader->GetMedicalImageProperties() ); + writer->SetShift( reader->GetShift() ); + writer->SetScale( reader->GetScale() ); + writer->SetFileName( "out.dcm" ); + writer->Write(); +#endif + + + vtkOutlineFilter* outline = vtkOutlineFilter::New(); + outline->SetInputConnection(v16->GetOutputPort()); + + vtkPolyDataMapper* outlineMapper = vtkPolyDataMapper::New(); + outlineMapper->SetInputConnection(outline->GetOutputPort()); + + vtkActor* outlineActor = vtkActor::New(); + outlineActor->SetMapper( outlineMapper); + + vtkRenderer* ren1 = vtkRenderer::New(); + vtkRenderer* ren2 = vtkRenderer::New(); + + vtkRenderWindow* renWin = vtkRenderWindow::New(); + renWin->AddRenderer(ren2); + renWin->AddRenderer(ren1); + + vtkRenderWindowInteractor* iren = vtkRenderWindowInteractor::New(); + iren->SetRenderWindow(renWin); + + vtkCellPicker* picker = vtkCellPicker::New(); + picker->SetTolerance(0.005); + + vtkProperty* ipwProp = vtkProperty::New(); + //assign default props to the ipw's texture plane actor + + vtkImagePlaneWidget* planeWidgetX = vtkImagePlaneWidget::New(); + planeWidgetX->SetInteractor( iren); + planeWidgetX->SetKeyPressActivationValue('x'); + planeWidgetX->SetPicker(picker); + planeWidgetX->RestrictPlaneToVolumeOn(); + planeWidgetX->GetPlaneProperty()->SetColor(1,0,0); + planeWidgetX->SetTexturePlaneProperty(ipwProp); + planeWidgetX->TextureInterpolateOff(); + planeWidgetX->SetResliceInterpolateToNearestNeighbour(); +#if (VTK_MAJOR_VERSION >= 6) + planeWidgetX->SetInputConnection(v16->GetOutputPort()); +#else + planeWidgetX->SetInput(v16->GetOutput()); +#endif + planeWidgetX->SetPlaneOrientationToXAxes(); + //planeWidgetX->SetSliceIndex(32); + planeWidgetX->DisplayTextOn(); + planeWidgetX->On(); + planeWidgetX->InteractionOff(); + planeWidgetX->InteractionOn(); + + vtkImagePlaneWidget* planeWidgetY = vtkImagePlaneWidget::New(); + planeWidgetY->SetInteractor( iren); + planeWidgetY->SetKeyPressActivationValue('y'); + planeWidgetY->SetPicker(picker); + planeWidgetY->GetPlaneProperty()->SetColor(1,1,0); + planeWidgetY->SetTexturePlaneProperty(ipwProp); + planeWidgetY->TextureInterpolateOn(); + planeWidgetY->SetResliceInterpolateToLinear(); +#if (VTK_MAJOR_VERSION >= 6) + planeWidgetY->SetInputConnection(v16->GetOutputPort()); +#else + planeWidgetY->SetInput(v16->GetOutput()); +#endif + planeWidgetY->SetPlaneOrientationToYAxes(); + //planeWidgetY->SetSlicePosition(102.4); + planeWidgetY->SetLookupTable( planeWidgetX->GetLookupTable()); + planeWidgetY->DisplayTextOn(); + planeWidgetY->UpdatePlacement(); + planeWidgetY->On(); + + vtkImagePlaneWidget* planeWidgetZ = vtkImagePlaneWidget::New(); + planeWidgetZ->SetInteractor( iren); + planeWidgetZ->SetKeyPressActivationValue('z'); + planeWidgetZ->SetPicker(picker); + planeWidgetZ->GetPlaneProperty()->SetColor(0,0,1); + planeWidgetZ->SetTexturePlaneProperty(ipwProp); + planeWidgetZ->TextureInterpolateOn(); + planeWidgetZ->SetResliceInterpolateToCubic(); +#if (VTK_MAJOR_VERSION >= 6) + planeWidgetZ->SetInputConnection(v16->GetOutputPort()); +#else + planeWidgetZ->SetInput(v16->GetOutput()); +#endif + planeWidgetZ->SetPlaneOrientationToZAxes(); + //planeWidgetZ->SetSliceIndex(25); + planeWidgetZ->SetLookupTable( planeWidgetX->GetLookupTable()); + planeWidgetZ->DisplayTextOn(); + planeWidgetZ->On(); + + vtkImageOrthoPlanes *orthoPlanes = vtkImageOrthoPlanes::New(); + orthoPlanes->SetPlane(0, planeWidgetX); + orthoPlanes->SetPlane(1, planeWidgetY); + orthoPlanes->SetPlane(2, planeWidgetZ); + orthoPlanes->ResetPlanes(); + + vtkOrthoPlanesCallback* cbk = vtkOrthoPlanesCallback::New(); + cbk->WidgetX = planeWidgetX; + cbk->WidgetY = planeWidgetY; + cbk->WidgetZ = planeWidgetZ; + planeWidgetX->AddObserver( vtkCommand::EndWindowLevelEvent, cbk ); + planeWidgetY->AddObserver( vtkCommand::EndWindowLevelEvent, cbk ); + planeWidgetZ->AddObserver( vtkCommand::EndWindowLevelEvent, cbk ); + cbk->Delete(); + + double wl[2]; + planeWidgetZ->GetWindowLevel(wl); + + // Add a 2D image to test the GetReslice method + // + vtkImageMapToColors* colorMap = vtkImageMapToColors::New(); + colorMap->PassAlphaToOutputOff(); + colorMap->SetActiveComponent(0); + colorMap->SetOutputFormatToLuminance(); +#if (VTK_MAJOR_VERSION >= 6) + colorMap->SetInputData(planeWidgetZ->GetResliceOutput()); +#else + colorMap->SetInput(planeWidgetZ->GetResliceOutput()); +#endif + colorMap->SetLookupTable(planeWidgetX->GetLookupTable()); + + vtkImageActor* imageActor = vtkImageActor::New(); + imageActor->PickableOff(); +#if (VTK_MAJOR_VERSION >= 6) + imageActor->SetInputData(colorMap->GetOutput()); +#else + imageActor->SetInput(colorMap->GetOutput()); +#endif + + // Add the actors + // + ren1->AddActor( outlineActor); + ren2->AddActor( imageActor); + + ren1->SetBackground( 0.1, 0.1, 0.2); + ren2->SetBackground( 0.2, 0.1, 0.2); + + renWin->SetSize( 600, 350); + + ren1->SetViewport(0,0,0.58333,1); + ren2->SetViewport(0.58333,0,1,1); + + // Set the actors' postions + // + renWin->Render(); + //iren->SetEventPosition( 175,175); + //iren->SetKeyCode('r'); + //iren->InvokeEvent(vtkCommand::CharEvent,NULL); + //iren->SetEventPosition( 475,175); + //iren->SetKeyCode('r'); + //iren->InvokeEvent(vtkCommand::CharEvent,NULL); + //renWin->Render(); + + //ren1->GetActiveCamera()->Elevation(110); + //ren1->GetActiveCamera()->SetViewUp(0, 0, -1); + //ren1->GetActiveCamera()->Azimuth(45); + //ren1->GetActiveCamera()->Dolly(1.15); + ren1->ResetCameraClippingRange(); + + vtkAnnotatedCubeActor* cube = vtkAnnotatedCubeActor::New(); + cube->SetXPlusFaceText ( "R" ); + cube->SetXMinusFaceText( "L" ); + cube->SetYPlusFaceText ( "A" ); + cube->SetYMinusFaceText( "P" ); + cube->SetZPlusFaceText ( "H" ); + cube->SetZMinusFaceText( "F" ); + cube->SetFaceTextScale( 0.666667 ); + + vtkAxesActor* axes2 = vtkAxesActor::New(); + + vtkMatrix4x4 *invert = vtkMatrix4x4::New(); + invert->DeepCopy( reader->GetDirectionCosines() ); + invert->Invert(); + + // simulate a left-handed coordinate system + // + vtkTransform *transform = vtkTransform::New(); + transform->Identity(); + //transform->RotateY(90); + transform->Concatenate(invert); + axes2->SetShaftTypeToCylinder(); + axes2->SetUserTransform( transform ); + cube->GetAssembly()->SetUserTransform( transform ); + + axes2->SetTotalLength( 1.5, 1.5, 1.5 ); + axes2->SetCylinderRadius( 0.500 * axes2->GetCylinderRadius() ); + axes2->SetConeRadius ( 1.025 * axes2->GetConeRadius() ); + axes2->SetSphereRadius ( 1.500 * axes2->GetSphereRadius() ); + + vtkTextProperty* tprop = axes2->GetXAxisCaptionActor2D()-> + GetCaptionTextProperty(); + tprop->ItalicOn(); + tprop->ShadowOn(); + tprop->SetFontFamilyToTimes(); + + axes2->GetYAxisCaptionActor2D()->GetCaptionTextProperty()->ShallowCopy( tprop ); + axes2->GetZAxisCaptionActor2D()->GetCaptionTextProperty()->ShallowCopy( tprop ); + + vtkPropAssembly* assembly = vtkPropAssembly::New(); + assembly->AddPart( axes2 ); + assembly->AddPart( cube ); + + vtkOrientationMarkerWidget* widget = vtkOrientationMarkerWidget::New(); + widget->SetOutlineColor( 0.9300, 0.5700, 0.1300 ); + widget->SetOrientationMarker( assembly ); + widget->SetInteractor( iren ); + widget->SetViewport( 0.0, 0.0, 0.4, 0.4 ); + widget->SetEnabled( 1 ); + widget->InteractiveOff(); + widget->InteractiveOn(); + + // Playback recorded events + // + //vtkInteractorEventRecorder *recorder = vtkInteractorEventRecorder::New(); + //recorder->SetInteractor(iren); + //recorder->ReadFromInputStringOn(); + //recorder->SetInputString(IOPeventLog); + + // Interact with data + // Render the image + // + iren->Initialize(); + renWin->Render(); + + // Test SetKeyPressActivationValue for one of the widgets + // + //iren->SetKeyCode('z'); + //iren->InvokeEvent(vtkCommand::CharEvent,NULL); + //iren->SetKeyCode('z'); + //iren->InvokeEvent(vtkCommand::CharEvent,NULL); + + //int retVal = vtkRegressionTestImage( renWin ); + // + //if ( retVal == vtkRegressionTester::DO_INTERACTOR) + { + iren->Start(); + } + + // Clean up + // + //recorder->Off(); + //recorder->Delete(); + + ipwProp->Delete(); + orthoPlanes->Delete(); + planeWidgetX->Delete(); + planeWidgetY->Delete(); + planeWidgetZ->Delete(); + colorMap->Delete(); + imageActor->Delete(); + picker->Delete(); + outlineActor->Delete(); + outlineMapper->Delete(); + outline->Delete(); + iren->Delete(); + renWin->Delete(); + ren1->Delete(); + ren2->Delete(); + v16->Delete(); + reader->Delete(); + + return 0; +} diff --git a/gdcm/Utilities/VTK/Examples/Cxx/gdcmreslice.cxx b/gdcm/Utilities/VTK/Examples/Cxx/gdcmreslice.cxx new file mode 100644 index 0000000..5a65103 --- /dev/null +++ b/gdcm/Utilities/VTK/Examples/Cxx/gdcmreslice.cxx @@ -0,0 +1,161 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkGDCMImageReader.h" + +#include "vtkRenderer.h" +#include "vtkAssembly.h" +#include "vtkImageFlip.h" +#include "vtkImageReslice.h" +#include "vtkRenderWindow.h" +#include "vtkAnnotatedCubeActor.h" +#include "vtkTransform.h" +#include "vtkAxesActor.h" +#include "vtkTextProperty.h" +#include "vtkCaptionActor2D.h" +#include "vtkPropAssembly.h" +#include "vtkOrientationMarkerWidget.h" +#include "vtkRenderWindowInteractor.h" +#include "vtkPolyDataMapper.h" +#include "vtkActor.h" +#include "vtkImageData.h" +#include "vtkLookupTable.h" +#include "vtkTexture.h" +#include "vtkPlaneSource.h" + +int main( int argc, char *argv[] ) +{ + if( argc < 2 ) return 1; + vtkGDCMImageReader *reader = vtkGDCMImageReader::New(); + reader->SetFileName( argv[1] ); + //reader->FileLowerLeftOn(); + reader->Update(); + + vtkImageFlip *flip = vtkImageFlip::New(); +#if (VTK_MAJOR_VERSION >= 6) + flip->SetInputConnection(reader->GetOutputPort()); +#else + flip->SetInput(reader->GetOutput()); +#endif + flip->SetFilteredAxis(0); + flip->Update(); + + vtkImageReslice *reslice = vtkImageReslice::New(); + //reslice->SetInput(reader->GetOutput()); +#if (VTK_MAJOR_VERSION >= 6) + reslice->SetInputConnection(flip->GetOutputPort()); +#else + reslice->SetInput(flip->GetOutput()); +#endif + //reslice->SetResliceAxesDirectionCosines() + reader->GetDirectionCosines()->Print(std::cout); + vtkMatrix4x4 *invert = vtkMatrix4x4::New(); + invert->DeepCopy( reader->GetDirectionCosines() ); + invert->Invert(); + + //reslice->SetResliceAxes( reader->GetDirectionCosines() ); + reslice->SetResliceAxes( invert ); + reslice->Update(); + vtkImageData* ima = reslice->GetOutput(); + + vtkLookupTable* table = vtkLookupTable::New(); + table->SetNumberOfColors(1000); + table->SetTableRange(0,1000); + table->SetSaturationRange(0,0); + table->SetHueRange(0,1); + table->SetValueRange(0,1); + table->SetAlphaRange(1,1); + table->Build(); + + // Texture + vtkTexture* texture = vtkTexture::New(); +#if (VTK_MAJOR_VERSION >= 6) + texture->SetInputData(ima); +#else + texture->SetInput(ima); +#endif + texture->InterpolateOn(); + texture->SetLookupTable(table); + + // PlaneSource + vtkPlaneSource* plane = vtkPlaneSource::New(); + + // PolyDataMapper + vtkPolyDataMapper *planeMapper = vtkPolyDataMapper::New(); +#if (VTK_MAJOR_VERSION >= 6) + planeMapper->SetInputConnection(plane->GetOutputPort()); +#else + planeMapper->SetInput(plane->GetOutput()); +#endif + + // Actor + vtkActor* planeActor = vtkActor::New(); + planeActor->SetTexture(texture); + planeActor->SetMapper(planeMapper); + planeActor->PickableOn(); + + // Final rendering with simple interactor: + vtkRenderer *ren = vtkRenderer::New(); + vtkRenderWindow *renwin = vtkRenderWindow::New(); + renwin->AddRenderer(ren); + vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New(); + iren->SetRenderWindow(renwin); + ren->AddActor(planeActor); + ren->SetBackground(0,0,0.5); + + // DICOM is RAH: + vtkAnnotatedCubeActor* cube = vtkAnnotatedCubeActor::New(); + cube->SetXPlusFaceText ( "R" ); + cube->SetXMinusFaceText( "L" ); + cube->SetYPlusFaceText ( "A" ); + cube->SetYMinusFaceText( "P" ); + cube->SetZPlusFaceText ( "H" ); + cube->SetZMinusFaceText( "F" ); + + vtkAxesActor* axes2 = vtkAxesActor::New(); + + vtkTransform *transform = vtkTransform::New(); + transform->Identity(); + //reader->GetDirectionCosines()->Print(std::cout); + transform->Concatenate(invert); + //axes2->SetShaftTypeToCylinder(); + axes2->SetUserTransform( transform ); + cube->GetAssembly()->SetUserTransform( transform ); // cant get it to work + + vtkPropAssembly* assembly = vtkPropAssembly::New(); + assembly->AddPart( axes2 ); + assembly->AddPart( cube ); + + vtkOrientationMarkerWidget* widget = vtkOrientationMarkerWidget::New(); + widget->SetOrientationMarker( assembly ); + widget->SetInteractor( iren ); + widget->SetEnabled( 1 ); + widget->InteractiveOff(); + widget->InteractiveOn(); + + renwin->Render(); + iren->Start(); + + // Clean up: + reader->Delete(); + table->Delete(); + texture->Delete(); + plane->Delete(); + planeMapper->Delete(); + planeActor->Delete(); + ren->Delete(); + renwin->Delete(); + iren->Delete(); + + return 0; +} diff --git a/gdcm/Utilities/VTK/Examples/Cxx/gdcmrtionplan.cxx b/gdcm/Utilities/VTK/Examples/Cxx/gdcmrtionplan.cxx new file mode 100644 index 0000000..2cc6bdc --- /dev/null +++ b/gdcm/Utilities/VTK/Examples/Cxx/gdcmrtionplan.cxx @@ -0,0 +1,325 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkImageData.h" +#include "vtkPointData.h" +#include "vtkPolyData.h" +#include "vtkProperty.h" +#include "vtkPolyDataMapper.h" +#include "vtkActor.h" +#include "vtkRenderer.h" +#include "vtkCellArray.h" +#include "vtkPoints.h" +#include "vtkDoubleArray.h" +#include +#include +#include +#include + +#include "gdcmReader.h" +#include "gdcmAttribute.h" + +/* + This example is just for fun. We found a RT Ion Plan Storage and simply extracted the viz stuff for VTK + + RTIonPlanStorage, // 1.2.840.10008.5.1.4.1.1.481.8 +*/ +int main(int argc, char *argv[]) +{ + if( argc < 3 ) + { + std::cerr << argv[0] << " filename.dcm outfile.vti\n"; + return 1; + } + const char * filename = argv[1]; + const char * outfilename = argv[2]; + const char * outfilename2 = argv[3]; + + gdcm::Reader reader; + reader.SetFileName( filename ); + if( !reader.Read() ) + { + return 1; + } + + gdcm::MediaStorage ms; + ms.SetFromFile( reader.GetFile() ); + if( ms != gdcm::MediaStorage::RTIonPlanStorage ) + { + return 1; + } + +/* +(300a,03a2) SQ # u/l,1 Ion Beam Sequence + (fffe,e000) na (Item with undefined length) + (0008,1040) LO [Test] # 4,1 Institutional Department Name + (300a,00b2) SH (no value) # 0,1 Treatment Machine Name + (300a,00b3) CS [MU] # 2,1 Primary Dosimeter Unit + (300a,00c0) IS [1 ] # 2,1 Beam Number + (300a,00c2) LO [1 ] # 2,1 Beam Name + (300a,00c4) CS [STATIC] # 6,1 Beam Type + (300a,00c6) CS [PROTON] # 6,1 Radiation Type + (300a,00ce) CS [TREATMENT ] # 10,1 Treatment Delivery Type + (300a,00d0) IS [0 ] # 2,1 Number of Wedges + (300a,00e0) IS [1 ] # 2,1 Number of Compensators + (300a,00ed) IS [0 ] # 2,1 Number of Boli + (300a,00f0) IS [1 ] # 2,1 Number of Blocks + (300a,0110) IS [2 ] # 2,1 Number of Control Points + (300a,02ea) SQ # u/l,1 Ion Range Compensator Sequence + (fffe,e000) na (Item with undefined length) + (300a,00e1) SH [lucite] # 6,1 Material ID + (300a,00e4) IS [1 ] # 2,1 Compensator Number + (300a,00e5) SH [75hdhe5 ] # 8,1 Compensator ID + (300a,00e7) IS [35] # 2,1 Compensator Rows + (300a,00e8) IS [37] # 2,1 Compensator Columns + (300a,00e9) DS [3.679991\4.249288 ] # 18,2 Compensator Pixel Spacing + (300a,00ea) DS [-76.00\62.50] # 12,2 Compensator Position + (300a,00ec) DS [52.13\52.13\52.13\53.18\54.04\54.04\47.11\40.06\40.06\38.79\34.87\33.28\33.28\33.28\33.28\35.43\35.43\34.54\34.54\34.71\36.10\38.62\44.88\44.88\44.88\45.00\45.00\45.00\45.66\45.66\46.42\39.77\39.77\39.77\39.77\39.77\43.52\52.13\52.13\52.13\53.18\53.52\54.0] # 7618,1-n Compensator Thickness Data + (300a,02e0) CS [ABSENT] # 6,1 Compensator Divergence + (300a,02e1) CS [SOURCE_SIDE ] # 12,1 Compensator Mounting Position + (300a,02e4) FL 39.2 # 4,1 Isocenter to Compensator Tray Distance + (300a,02e5) FL 2.12 # 4,1 Compensator Column Offset + (300a,02e8) FL 4.76 # 4,1 Compensator Milling Tool Diameter + (fffe,e00d) +*/ + const gdcm::DataSet& ds = reader.GetFile().GetDataSet(); + gdcm::Tag tbeamsq(0x300a,0x03a2); + if( !ds.FindDataElement( tbeamsq ) ) + { + return 1; + } + const gdcm::DataElement &beamsq = ds.GetDataElement( tbeamsq ); + //std::cout << beamsq << std::endl; + gdcm::SmartPointer sqi = beamsq.GetValueAsSQ(); + if( !sqi || !sqi->GetNumberOfItems() ) + { + return 1; + } + + //for(unsigned int pd = 0; pd < sqi->GetNumberOfItems(); ++pd) + // { + //const gdcm::Item & item = sqi->GetItem(1); // Item start at #1 + const gdcm::Item & item = sqi->GetItem(1); // Item start at #1 + const gdcm::DataSet& nestedds = item.GetNestedDataSet(); + //std::cout << nestedds << std::endl; + gdcm::Tag tcompensatorsq(0x300a,0x02ea); + if( !nestedds.FindDataElement( tcompensatorsq ) ) + { + return 1; + } + const gdcm::DataElement &compensatorsq = nestedds.GetDataElement( tcompensatorsq ); + //std::cout << compensatorsq << std::endl; + gdcm::SmartPointer ssqi = compensatorsq.GetValueAsSQ(); + const gdcm::Item & item2 = ssqi->GetItem(1); // Item start at #1 + const gdcm::DataSet& nestedds2 = item2.GetNestedDataSet(); + //std::cout << nestedds2 << std::endl; + gdcm::Tag tcompensatorthicknessdata(0x300a,0x00ec); + if( !nestedds2.FindDataElement( tcompensatorthicknessdata ) ) + { + return 1; + } + const gdcm::DataElement &compensatorthicknessdata = nestedds2.GetDataElement( tcompensatorthicknessdata ); + // std::cout << compensatorthicknessdata << std::endl; + gdcm::Attribute<0x300a,0x00ec> at; + at.SetFromDataElement( compensatorthicknessdata ); + const double* pts = at.GetValues(); + // (300a,00e7) IS [35] # 2,1 Compensator Rows + gdcm::Attribute<0x300a,0x00e7> at1; + const gdcm::DataElement &compensatorrows = nestedds2.GetDataElement( at1.GetTag() ); + at1.SetFromDataElement( compensatorrows ); + std::cout << at1.GetValue() << std::endl; + // (300a,00e8) IS [37] # 2,1 Compensator Columns + gdcm::Attribute<0x300a,0x00e8> at2; + const gdcm::DataElement &compensatorcols = nestedds2.GetDataElement( at2.GetTag() ); + at2.SetFromDataElement( compensatorcols ); + std::cout << at2.GetValue() << std::endl; + + // (300a,00e9) DS [3.679991\4.249288 ] # 18,2 Compensator Pixel Spacing + gdcm::Attribute<0x300a,0x00e9> at3; + const gdcm::DataElement &compensatorpixelspacing = nestedds2.GetDataElement( at3.GetTag() ); + at3.SetFromDataElement( compensatorpixelspacing ); + std::cout << at3.GetValue(0) << std::endl; + // (300a,00ea) DS [-76.00\62.50] # 12,2 Compensator Position + gdcm::Attribute<0x300a,0x00ea> at4; + const gdcm::DataElement &compensatorposition = nestedds2.GetDataElement( at4.GetTag() ); + at4.SetFromDataElement( compensatorposition ); + std::cout << at4.GetValue(0) << std::endl; + + vtkDoubleArray *d = vtkDoubleArray::New(); + d->SetArray( (double*)pts , at1.GetValue() * at2.GetValue() , 0 ); + + vtkImageData *img = vtkImageData::New(); + img->Initialize(); + img->SetDimensions( at2.GetValue(), at1.GetValue(), 1 ); + //imgb->SetExtent(1, xdim, 1, ydim, 1, zdim); +#if (VTK_MAJOR_VERSION >= 6) + assert(0); +#else + img->SetScalarTypeToDouble(); +#endif + img->SetSpacing( at3.GetValue(1), at3.GetValue(0), 1); // FIXME image is upside down + img->SetOrigin( at4.GetValue(0), at4.GetValue(1), 1); +#if (VTK_MAJOR_VERSION >= 6) + assert(0); +#else + img->SetNumberOfScalarComponents(1); +#endif + img->GetPointData()->SetScalars(d); + +#if (VTK_MAJOR_VERSION >= 6) +#else + img->Update(); +#endif + img->Print(std::cout); + + vtkXMLImageDataWriter *writeb= vtkXMLImageDataWriter::New(); +#if (VTK_MAJOR_VERSION >= 6) + writeb->SetInputData( img ); +#else + writeb->SetInput( img ); +#endif + writeb->SetFileName( outfilename ); + writeb->Write( ); +/* + (300a,03a6) SQ # u/l,1 Ion Block Sequence + (fffe,e000) na (Item with undefined length) + (300a,00e1) SH [brass ] # 6,1 Material ID + (300a,00f7) FL 95.03 # 4,1 Isocenter to Block Tray Distance + (300a,00f8) CS [APERTURE] # 8,1 Block Type + (300a,00fa) CS [ABSENT] # 6,1 Block Divergence + (300a,00fb) CS [SOURCE_SIDE ] # 12,1 Block Mounting Position + (300a,00fc) IS [1 ] # 2,1 Block Number + (300a,0100) DS [50.00 ] # 6,1 Block Thickness + (300a,0104) IS [179 ] # 4,1 Block Number of Points + (300a,0106) DS [1.7\50.0\14.3\50.0\16.7\49.4\18.7\48.2\19.4\47.7\20.1\47.1\21.0\47.0\22.3\47.0\23.7\46.8\25.7\46.2\27.0\45.6\27.2\45.4\28.2\44.6\28.9\44.2\29.7\43.9\31.5\43.5\33.0\42.8\33.7\42.4\35.2\41.3\38.2\40.4\39.6\39.7\40.0\39.5\41.5\37.9\42 +2\37.4\43.0\37.1\44.7\36] # 1934,2-2n Block Data + (fffe,e00d) + (fffe,e0dd) + +*/ + gdcm::Tag tblocksq(0x300a,0x03a6); + if( !nestedds.FindDataElement( tblocksq ) ) + { + return 1; + } + const gdcm::DataElement &blocksq = nestedds.GetDataElement( tblocksq ); + //std::cout << blocksq << std::endl; + gdcm::SmartPointer sssqi = blocksq.GetValueAsSQ(); + const gdcm::Item & item3 = sssqi->GetItem(1); // Item start at #1 + const gdcm::DataSet& nestedds3 = item3.GetNestedDataSet(); + + gdcm::Tag tblockdata(0x300a,0x0106); + if( !nestedds3.FindDataElement( tblockdata ) ) + { + return 1; + } + const gdcm::DataElement &blockdata = nestedds3.GetDataElement( tblockdata ); + // std::cout << blockdata << std::endl; + gdcm::Attribute<0x300a,0x0106> at_; + at_.SetFromDataElement( blockdata ); + + vtkDoubleArray *scalars = vtkDoubleArray::New(); + scalars->SetNumberOfComponents(3); + + gdcm::Attribute<0x300a,0x0104> bnpts; // IS [179 ] # 4,1 Block Number of Points + if( !nestedds3.FindDataElement( bnpts.GetTag() ) ) + { + return 1; + } + const gdcm::DataElement &blocknpts = nestedds3.GetDataElement( bnpts.GetTag() ); + bnpts.SetFromDataElement( blocknpts ); + //std::cout << bnpts.GetValue() << std::endl; + + vtkPolyData *output = vtkPolyData::New(); + vtkPoints *newPts = vtkPoints::New(); + vtkCellArray *polys = vtkCellArray::New(); + const double *ptr = at_.GetValues(); + //unsigned int npts = bnpts.GetNumberOfValues() / 2; + unsigned int npts = bnpts.GetValue(); + vtkIdType *ptIds = new vtkIdType[npts]; + for(unsigned int i = 0; i < npts; ++i) + { + float x[3] = {}; + x[0] = (float)ptr[2*i+0]; + x[1] = (float)ptr[2*i+1]; + //x[2] = pts[i+2]; + vtkIdType ptId = newPts->InsertNextPoint( x ); + //std::cout << x[0] << "," << x[1] << "," << x[2] << std::endl; + ptIds[i ] = ptId; + } + vtkIdType cellId = polys->InsertNextCell(npts , ptIds); + (void)cellId; + delete[] ptIds; + + output->SetPoints(newPts); + newPts->Delete(); + output->SetPolys(polys); + polys->Delete(); + //output->GetCellData()->SetScalars(scalars); + //scalars->Delete(); +#if (VTK_MAJOR_VERSION >= 6) +#else + output->Update(); +#endif + output->Print( std::cout ); + + + + + // } + + vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New(); + + vtkImageColorViewer *viewer = vtkImageColorViewer::New(); +#if (VTK_MAJOR_VERSION >= 6) + viewer->SetInputData(img); +#else + viewer->SetInput(img); +#endif + viewer->SetupInteractor(iren); + viewer->SetSize(600, 600); + viewer->GetRenderer()->ResetCameraClippingRange(); + viewer->Render(); + viewer->GetRenderer()->ResetCameraClippingRange(); + + vtkPolyDataMapper *cubeMapper = vtkPolyDataMapper::New(); + //vtkPolyDataMapper2D* cubeMapper = vtkPolyDataMapper2D::New(); +#if (VTK_MAJOR_VERSION >= 6) + cubeMapper->SetInputData( output ); +#else + cubeMapper->SetInput( output ); +#endif + cubeMapper->SetScalarRange(0,7); + vtkActor *cubeActor = vtkActor::New(); + //vtkActor2D* cubeActor = vtkActor2D::New(); + cubeActor->SetMapper(cubeMapper); + vtkProperty * property = cubeActor->GetProperty(); + property->SetRepresentationToWireframe(); + +viewer->GetRenderer()->AddActor( cubeActor ); + + vtkXMLPolyDataWriter *writec= vtkXMLPolyDataWriter::New(); +#if (VTK_MAJOR_VERSION >= 6) + writec->SetInputData( output ); +#else + writec->SetInput( output ); +#endif + writec->SetFileName( outfilename2 ); + writec->Write( ); + + iren->Initialize(); + iren->Start(); + + + return 0; +} diff --git a/gdcm/Utilities/VTK/Examples/Cxx/gdcmrtplan.cxx b/gdcm/Utilities/VTK/Examples/Cxx/gdcmrtplan.cxx new file mode 100644 index 0000000..15cfe07 --- /dev/null +++ b/gdcm/Utilities/VTK/Examples/Cxx/gdcmrtplan.cxx @@ -0,0 +1,298 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkImageData.h" +#include "vtkPointData.h" +#include "vtkPolyData.h" +#include "vtkProperty.h" +#include "vtkPolyDataMapper.h" +#include "vtkActor.h" +#include "vtkRenderer.h" +#include "vtkCellArray.h" +#include "vtkPoints.h" +#include "vtkDoubleArray.h" +#include +#include +#include + +#include "gdcmReader.h" +#include "gdcmAttribute.h" + +/* + This example is just for fun. We found a fake RT Ion Plan Storage and simply extracted the viz stuff for VTK + but this is rather a RT Plan storage +*/ +int main(int argc, char *argv[]) +{ + if( argc < 3 ) + { + std::cerr << argv[0] << " filename.dcm outfile.vti\n"; + return 1; + } + const char * filename = argv[1]; + const char * outfilename = argv[2]; + + gdcm::Reader reader; + reader.SetFileName( filename ); + if( !reader.Read() ) + { + return 1; + } + + gdcm::MediaStorage ms; + ms.SetFromFile( reader.GetFile() ); + if( ms != gdcm::MediaStorage::RTIonPlanStorage ) + { + return 1; + } + +/* +(300a,00b0) SQ # u/l,1 Beam Sequence + (fffe,e000) na (Item with undefined length) + (300a,00b2) SH (no value) # 0,1 Treatment Machine Name + (300a,00c0) IS [1 ] # 2,1 Beam Number + (300a,00c2) LO [1 ] # 2,1 Beam Name + (300a,00c4) CS [STATIC] # 6,1 Beam Type + (300a,00c6) CS [PROTON] # 6,1 Radiation Type + (300a,00ce) CS [TREATMENT ] # 10,1 Treatment Delivery Type + (300a,00e0) IS [1 ] # 2,1 Number of Compensators + (300a,00e3) SQ # u/l,1 Compensator Sequence + (fffe,e000) na (Item with undefined length) + (300a,00e1) SH [lucite] # 6,1 Material ID + (300a,00e4) IS [1 ] # 2,1 Compensator Number + (300a,00e5) SH [75hdhe5 ] # 8,1 Compensator ID + (300a,00e7) IS [35] # 2,1 Compensator Rows + (300a,00e8) IS [37] # 2,1 Compensator Columns + (300a,00e9) DS [3.679991\4.249288 ] # 18,2 Compensator Pixel Spacing + (300a,00ea) DS [-76.00\62.50] # 12,2 Compensator Position + (300a,00ec) DS [52.13\52.13\52.13\53.18\54.04\54.04\47.11\40.06\40.06\38.79\34.87\33.28\33.28\33.28\33.28\35.43\35.43\34.54\34.54\34.71\36.10\38.62\44.88\44.88\44.88\45.00\45.00\45.00\45.66\45.66\46.42\39.77\39.77\39.77\39.77\39.77\43.52\52.13\52.13\52.13\53.18\53.52\54.0] # 7618,1-n Compensator Thickness Data + (300a,02e0) CS [ABSENT] # 6,1 Compensator Divergence + (300a,02e1) CS [SOURCE_SIDE ] # 12,1 Compensator Mounting Position + (fffe,e00d) + (fffe,e000) na (Item with undefined length) + (fffe,e00d) + (fffe,e0dd) +*/ + const gdcm::DataSet& ds = reader.GetFile().GetDataSet(); + gdcm::Tag tbeamsq(0x300a,0x00b0); + if( !ds.FindDataElement( tbeamsq ) ) + { + return 1; + } + const gdcm::DataElement &beamsq = ds.GetDataElement( tbeamsq ); + //std::cout << beamsq << std::endl; + gdcm::SmartPointer sqi = beamsq.GetValueAsSQ(); + if( !sqi || !sqi->GetNumberOfItems() ) + { + return 1; + } + + //for(unsigned int pd = 0; pd < sqi->GetNumberOfItems(); ++pd) + // { + //const gdcm::Item & item = sqi->GetItem(1); // Item start at #1 + const gdcm::Item & item = sqi->GetItem(2); // Item start at #1 + const gdcm::DataSet& nestedds = item.GetNestedDataSet(); + //std::cout << nestedds << std::endl; + gdcm::Tag tcompensatorsq(0x300a,0x00e3); + if( !nestedds.FindDataElement( tcompensatorsq ) ) + { + return 1; + } + const gdcm::DataElement &compensatorsq = nestedds.GetDataElement( tcompensatorsq ); + //std::cout << compensatorsq << std::endl; + gdcm::SmartPointer ssqi = compensatorsq.GetValueAsSQ(); + const gdcm::Item & item2 = ssqi->GetItem(1); // Item start at #1 + const gdcm::DataSet& nestedds2 = item2.GetNestedDataSet(); + //std::cout << nestedds2 << std::endl; + gdcm::Tag tcompensatorthicknessdata(0x300a,0x00ec); + if( !nestedds2.FindDataElement( tcompensatorthicknessdata ) ) + { + return 1; + } + const gdcm::DataElement &compensatorthicknessdata = nestedds2.GetDataElement( tcompensatorthicknessdata ); + // std::cout << compensatorthicknessdata << std::endl; + gdcm::Attribute<0x300a,0x00ec> at; + at.SetFromDataElement( compensatorthicknessdata ); + const double* pts = at.GetValues(); + // (300a,00e7) IS [35] # 2,1 Compensator Rows + gdcm::Attribute<0x300a,0x00e7> at1; + const gdcm::DataElement &compensatorrows = nestedds2.GetDataElement( at1.GetTag() ); + at1.SetFromDataElement( compensatorrows ); + std::cout << at1.GetValue() << std::endl; + // (300a,00e8) IS [37] # 2,1 Compensator Columns + gdcm::Attribute<0x300a,0x00e8> at2; + const gdcm::DataElement &compensatorcols = nestedds2.GetDataElement( at2.GetTag() ); + at2.SetFromDataElement( compensatorcols ); + std::cout << at2.GetValue() << std::endl; + + // (300a,00e9) DS [3.679991\4.249288 ] # 18,2 Compensator Pixel Spacing + gdcm::Attribute<0x300a,0x00e9> at3; + const gdcm::DataElement &compensatorpixelspacing = nestedds2.GetDataElement( at3.GetTag() ); + at3.SetFromDataElement( compensatorpixelspacing ); + std::cout << at3.GetValue(0) << std::endl; + // (300a,00ea) DS [-76.00\62.50] # 12,2 Compensator Position + gdcm::Attribute<0x300a,0x00ea> at4; + const gdcm::DataElement &compensatorposition = nestedds2.GetDataElement( at4.GetTag() ); + at4.SetFromDataElement( compensatorposition ); + std::cout << at4.GetValue(0) << std::endl; + + vtkDoubleArray *d = vtkDoubleArray::New(); + d->SetArray( (double*)pts , at1.GetValue() * at2.GetValue() , 0 ); + + vtkImageData *img = vtkImageData::New(); + img->Initialize(); + img->SetDimensions( at2.GetValue(), at1.GetValue(), 1 ); + //imgb->SetExtent(1, xdim, 1, ydim, 1, zdim); +#if (VTK_MAJOR_VERSION >= 6) + assert(0); +#else + img->SetScalarTypeToDouble(); +#endif + img->SetSpacing( at3.GetValue(1), at3.GetValue(0), 1); // FIXME image is upside down + img->SetOrigin( at4.GetValue(0), at4.GetValue(1), 1); +#if (VTK_MAJOR_VERSION >= 6) + assert(0); +#else + img->SetNumberOfScalarComponents(1); +#endif + img->GetPointData()->SetScalars(d); + + vtkXMLImageDataWriter *writeb= vtkXMLImageDataWriter::New(); +#if (VTK_MAJOR_VERSION >= 6) + writeb->SetInputData( img ); +#else + writeb->SetInput( img ); +#endif + writeb->SetFileName( outfilename ); + writeb->Write( ); +/* + (300a,00f4) SQ # u/l,1 Block Sequence + (fffe,e000) na (Item with undefined length) + (300a,00e1) SH [brass ] # 6,1 Material ID + (300a,00f8) CS [APERTURE] # 8,1 Block Type + (300a,00fa) CS [ABSENT] # 6,1 Block Divergence + (300a,00fb) CS [SOURCE_SIDE ] # 12,1 Block Mounting Position + (300a,00fc) IS [1 ] # 2,1 Block Number + (300a,0100) DS [50.00 ] # 6,1 Block Thickness + (300a,0104) IS [179 ] # 4,1 Block Number of Points + (300a,0106) DS [1.7\50.0\14.3\50.0\16.7\49.4\18.7\48.2\19.4\47.7\20.1\47.1\21.0\47.0\22.3\47.0\23.7\46.8\25.7\46.2\27.0\45.6\27.2\45.4\28.2\44.6\28.9\44.2\29.7\43.9\31.5\43.5\33.0\42.8\33.7\42.4\35.2\41.3\38.2\40.4\39.6\39.7\40.0\39.5\41.5\37.9\42.2\37.4\43.0\37.1\44.7\36] # 1934,2-2n Block Data + (fffe,e00d) + (fffe,e000) na (Item with undefined length) + (fffe,e00d) + (fffe,e0dd) +*/ + gdcm::Tag tblocksq(0x300a,0x00f4); + if( !nestedds.FindDataElement( tblocksq ) ) + { + return 1; + } + const gdcm::DataElement &blocksq = nestedds.GetDataElement( tblocksq ); + //std::cout << blocksq << std::endl; + gdcm::SmartPointer sssqi = blocksq.GetValueAsSQ(); + const gdcm::Item & item3 = sssqi->GetItem(1); // Item start at #1 + const gdcm::DataSet& nestedds3 = item3.GetNestedDataSet(); + + gdcm::Tag tblockdata(0x300a,0x0106); + if( !nestedds3.FindDataElement( tblockdata ) ) + { + return 1; + } + const gdcm::DataElement &blockdata = nestedds3.GetDataElement( tblockdata ); + // std::cout << blockdata << std::endl; + gdcm::Attribute<0x300a,0x0106> at_; + at_.SetFromDataElement( blockdata ); + + vtkDoubleArray *scalars = vtkDoubleArray::New(); + scalars->SetNumberOfComponents(3); + + gdcm::Attribute<0x300a,0x0104> bnpts; // IS [179 ] # 4,1 Block Number of Points + if( !nestedds3.FindDataElement( bnpts.GetTag() ) ) + { + return 1; + } + const gdcm::DataElement &blocknpts = nestedds3.GetDataElement( bnpts.GetTag() ); + bnpts.SetFromDataElement( blocknpts ); + std::cout << bnpts.GetValue() << std::endl; + + vtkPolyData *output = vtkPolyData::New(); + vtkPoints *newPts = vtkPoints::New(); + vtkCellArray *polys = vtkCellArray::New(); + const double *ptr = at_.GetValues(); + //unsigned int npts = bnpts.GetNumberOfValues() / 2; + unsigned int npts = bnpts.GetValue(); + vtkIdType *ptIds = new vtkIdType[npts]; + for(unsigned int i = 0; i < npts; ++i) + { + float x[3] = {}; + x[0] = (float)ptr[2*i+0]; + x[1] = (float)ptr[2*i+1]; + //x[2] = pts[i+2]; + vtkIdType ptId = newPts->InsertNextPoint( x ); + //std::cout << x[0] << "," << x[1] << "," << x[2] << std::endl; + ptIds[i ] = ptId; + } + vtkIdType cellId = polys->InsertNextCell(npts , ptIds); + (void)cellId; + delete[] ptIds; + + output->SetPoints(newPts); + newPts->Delete(); + output->SetPolys(polys); + polys->Delete(); + //output->GetCellData()->SetScalars(scalars); + //scalars->Delete(); +#if (VTK_MAJOR_VERSION >= 6) +#else + output->Update(); +#endif + output->Print( std::cout ); + + + + + // } + + vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New(); + + vtkImageColorViewer *viewer = vtkImageColorViewer::New(); +#if (VTK_MAJOR_VERSION >= 6) + viewer->SetInputData(img); +#else + viewer->SetInput(img); +#endif + viewer->SetupInteractor(iren); + viewer->SetSize(600, 600); + viewer->Render(); + + vtkPolyDataMapper *cubeMapper = vtkPolyDataMapper::New(); + //vtkPolyDataMapper2D* cubeMapper = vtkPolyDataMapper2D::New(); +#if (VTK_MAJOR_VERSION >= 6) + cubeMapper->SetInputData( output ); +#else + cubeMapper->SetInput( output ); +#endif + cubeMapper->SetScalarRange(0,7); + vtkActor *cubeActor = vtkActor::New(); + //vtkActor2D* cubeActor = vtkActor2D::New(); + cubeActor->SetMapper(cubeMapper); + vtkProperty * property = cubeActor->GetProperty(); + property->SetRepresentationToWireframe(); + + viewer->GetRenderer()->AddActor( cubeActor ); + + iren->Initialize(); + iren->Start(); + + + return 0; +} diff --git a/gdcm/Utilities/VTK/Examples/Cxx/gdcmscene.cxx b/gdcm/Utilities/VTK/Examples/Cxx/gdcmscene.cxx new file mode 100644 index 0000000..a2a0337 --- /dev/null +++ b/gdcm/Utilities/VTK/Examples/Cxx/gdcmscene.cxx @@ -0,0 +1,134 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkGDCMPolyDataReader.h" +//#include "vtkGDCMPolyDataWriter.h" + +#include "vtkAppendPolyData.h" +#include "vtkPolyDataWriter.h" +#include "vtkPolyDataMapper.h" +#include "vtkPolyDataMapper2D.h" +#include "vtkActor2D.h" +#include "vtkRenderWindowInteractor.h" +#include "vtkRenderWindow.h" +#include "vtkRenderer.h" +#include "vtkCamera.h" +#include "vtkProperty.h" +#include "vtkProperty2D.h" + + +// gdcmDataExtra/gdcmNonImageData/exRT_Structure_Set_Storage.dcm +// gdcmDataExtra/gdcmNonImageData/RTSTRUCT_1.3.6.1.4.1.22213.1.1396.2.dcm +// gdcmDataExtra/gdcmNonImageData/RT/RTStruct.dcm + +int main(int argc, char *argv[]) +{ + if( argc < 2 ) + { + std::cerr << argv[0] << " filename1.dcm\n"; + return 1; + } + const char * filename = argv[1]; + + vtkGDCMPolyDataReader * reader = vtkGDCMPolyDataReader::New(); + reader->SetFileName( filename ); + reader->Update(); + +// vtkGDCMPolyDataWriter * writer2 = vtkGDCMPolyDataWriter::New(); +// for(int num = 0; num < reader->GetNumberOfOutputPorts(); ++num ) +// writer2->SetInput( num, reader->GetOutput(num) ); +// writer2->SetFileName( "rtstruct.dcm" ); +// writer2->Write(); + + // print reader output: + reader->Print( std::cout ); + // print first output: + reader->GetOutput()->Print( std::cout ); + + vtkAppendPolyData *append = vtkAppendPolyData::New(); + int n = reader->GetNumberOfOutputPorts(); + for(int i = 0; i < n; ++i) + { +#if (VTK_MAJOR_VERSION >= 6) + append->AddInputConnection( reader->GetOutputPort(i) ); +#else + append->AddInput( reader->GetOutput(i) ); +#endif + } + + vtkPolyDataWriter * writer = vtkPolyDataWriter::New(); +#if (VTK_MAJOR_VERSION >= 6) + writer->SetInputConnection( reader->GetOutputPort() ); +#else + writer->SetInput( reader->GetOutput() ); +#endif + writer->SetFileName( "rtstruct.vtk" ); + //writer->Write(); + + // Now we'll look at it. + vtkPolyDataMapper *cubeMapper = vtkPolyDataMapper::New(); + //vtkPolyDataMapper2D* cubeMapper = vtkPolyDataMapper2D::New(); + //cubeMapper->SetInput( reader->GetOutput() ); +#if (VTK_MAJOR_VERSION >= 6) + cubeMapper->SetInputConnection( append->GetOutputPort() ); +#else + cubeMapper->SetInput( append->GetOutput() ); +#endif + cubeMapper->SetScalarRange(0,7); + vtkActor *cubeActor = vtkActor::New(); + //vtkActor2D* cubeActor = vtkActor2D::New(); + cubeActor->SetMapper(cubeMapper); + vtkProperty * property = cubeActor->GetProperty(); + property->SetRepresentationToWireframe(); + //cubeActor->GetProperty()->SetColor(1, 0, 0); + + + // The usual rendering stuff. +// vtkCamera *camera = vtkCamera::New(); +// camera->SetPosition(1,1,1); +// camera->SetFocalPoint(0,0,0); + + vtkRenderer *renderer = vtkRenderer::New(); + vtkRenderWindow *renWin = vtkRenderWindow::New(); + renWin->AddRenderer(renderer); + + vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New(); + iren->SetRenderWindow(renWin); + + renderer->AddActor(cubeActor); + //renderer->AddActor2D(cubeActor); + //renderer->SetActiveCamera(camera); + renderer->ResetCamera(); + renderer->SetBackground(1,1,1); + + renWin->SetSize(300,300); + + // interact with data + renWin->Render(); + iren->Start(); + + + + reader->Delete(); + append->Delete(); + cubeMapper->Delete(); + cubeActor->Delete(); +// camera->Delete(); + renderer->Delete(); + renWin->Delete(); + iren->Delete(); + + writer->Delete(); + + return 0; +} diff --git a/gdcm/Utilities/VTK/Examples/Cxx/gdcmtexture.cxx b/gdcm/Utilities/VTK/Examples/Cxx/gdcmtexture.cxx new file mode 100644 index 0000000..65b5b91 --- /dev/null +++ b/gdcm/Utilities/VTK/Examples/Cxx/gdcmtexture.cxx @@ -0,0 +1,140 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkGDCMImageReader.h" + +#include "vtkRenderer.h" +#include "vtkAssembly.h" +#include "vtkRenderWindow.h" +#include "vtkAnnotatedCubeActor.h" +#include "vtkTransform.h" +#include "vtkAxesActor.h" +#include "vtkTextProperty.h" +#include "vtkCaptionActor2D.h" +#include "vtkPropAssembly.h" +#include "vtkOrientationMarkerWidget.h" +#include "vtkRenderWindowInteractor.h" +#include "vtkPolyDataMapper.h" +#include "vtkActor.h" +#include "vtkImageData.h" +#include "vtkLookupTable.h" +#include "vtkTexture.h" +#include "vtkPlaneSource.h" + +int main( int argc, char *argv[] ) +{ + if( argc < 2 ) return 1; + vtkGDCMImageReader *reader = vtkGDCMImageReader::New(); + reader->SetFileName( argv[1] ); + + reader->Update(); + vtkImageData* ima = reader->GetOutput(); + + vtkLookupTable* table = vtkLookupTable::New(); + table->SetNumberOfColors(1000); + table->SetTableRange(0,1000); + table->SetSaturationRange(0,0); + table->SetHueRange(0,1); + table->SetValueRange(0,1); + table->SetAlphaRange(1,1); + table->Build(); + + // Texture + vtkTexture* texture = vtkTexture::New(); +#if (VTK_MAJOR_VERSION >= 6) + texture->SetInputData(ima); +#else + texture->SetInput(ima); +#endif + texture->InterpolateOn(); + texture->SetLookupTable(table); + + // PlaneSource + vtkPlaneSource* plane = vtkPlaneSource::New(); + plane->SetOrigin( -0.5, -0.5, 0.0); + plane->SetPoint1( 0.5, -0.5, 0.0); + plane->SetPoint2( -0.5, 0.5, 0.0); + + // PolyDataMapper + vtkPolyDataMapper *planeMapper = vtkPolyDataMapper::New(); +#if (VTK_MAJOR_VERSION >= 6) + planeMapper->SetInputConnection(plane->GetOutputPort()); +#else + planeMapper->SetInput(plane->GetOutput()); +#endif + + // Actor + vtkActor* planeActor = vtkActor::New(); + planeActor->SetTexture(texture); + planeActor->SetMapper(planeMapper); + planeActor->PickableOn(); + + // Final rendering with simple interactor: + vtkRenderer *ren = vtkRenderer::New(); + vtkRenderWindow *renwin = vtkRenderWindow::New(); + renwin->AddRenderer(ren); + vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New(); + iren->SetRenderWindow(renwin); + ren->AddActor(planeActor); + ren->SetBackground(0,0,0.5); + + vtkAnnotatedCubeActor* cube = vtkAnnotatedCubeActor::New(); + cube->SetXPlusFaceText ( "L" ); + cube->SetXMinusFaceText( "R" ); + cube->SetYPlusFaceText ( "A" ); + cube->SetYMinusFaceText( "P" ); + cube->SetZPlusFaceText ( "H" ); + cube->SetZMinusFaceText( "F" ); + + vtkAxesActor* axes2 = vtkAxesActor::New(); + // simulate a left-handed coordinate system + // + vtkTransform *transform = vtkTransform::New(); + transform->Identity(); + //transform->RotateY(180); + reader->GetDirectionCosines()->Print(std::cout); + transform->Concatenate(reader->GetDirectionCosines()); + //axes2->SetShaftTypeToCylinder(); + axes2->SetUserTransform( transform ); + //cube->SetUserTransform( transform ); // cant get it to work + cube->GetAssembly()->SetUserTransform( transform ); // cant get it to work + + vtkPropAssembly* assembly = vtkPropAssembly::New(); + assembly->AddPart( axes2 ); + assembly->AddPart( cube ); + + vtkOrientationMarkerWidget* widget = vtkOrientationMarkerWidget::New(); + //widget->SetOutlineColor( 0.9300, 0.5700, 0.1300 ); + widget->SetOrientationMarker( assembly ); + widget->SetInteractor( iren ); + //widget->SetViewport( 0.0, 0.0, 0.4, 0.4 ); + widget->SetEnabled( 1 ); + widget->InteractiveOff(); + widget->InteractiveOn(); + + renwin->Render(); + iren->Start(); + + // Clean up: + reader->Delete(); + table->Delete(); + texture->Delete(); + plane->Delete(); + planeMapper->Delete(); + planeActor->Delete(); + ren->Delete(); + renwin->Delete(); + iren->Delete(); + + return 0; +} diff --git a/gdcm/Utilities/VTK/Examples/Cxx/gdcmvolume.cxx b/gdcm/Utilities/VTK/Examples/Cxx/gdcmvolume.cxx new file mode 100644 index 0000000..4d67dc9 --- /dev/null +++ b/gdcm/Utilities/VTK/Examples/Cxx/gdcmvolume.cxx @@ -0,0 +1,93 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkGDCMImageReader.h" +#include "vtkPiecewiseFunction.h" +#include "vtkColorTransferFunction.h" +#include "vtkVolume.h" +#include "vtkVolumeProperty.h" +#include "vtkVolumeTextureMapper3D.h" +#include "vtkFixedPointVolumeRayCastMapper.h" +#include "vtkInteractorStyleTrackballCamera.h" +#include "vtkRenderer.h" +#include "vtkRenderWindow.h" +#include "vtkImageClip.h" +#include "vtkRenderWindowInteractor.h" + + +// gdcmvolume gdcmData/GE_DLX-8-MONO2-Multiframe-Jpeg_Lossless.dcm +int main(int argc, char *argv[]) +{ + if( argc < 2 ) return 1; + vtkGDCMImageReader *reader = vtkGDCMImageReader::New(); + reader->SetFileName( argv[1] ); + reader->Update(); + + // Create the renderers, render window, and interactor + vtkRenderWindow *renWin = vtkRenderWindow::New(); + vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New(); + iren->SetRenderWindow(renWin); + vtkRenderer *ren = vtkRenderer::New(); + renWin->AddRenderer(ren); + + // Create a transfer function mapping scalar value to opacity + vtkPiecewiseFunction *oTFun = vtkPiecewiseFunction::New(); + //oTFun->AddSegment(0, 1.0, 256, 0.1); + oTFun->AddSegment(0, 1.0, 240, 0.1); + + vtkColorTransferFunction *cTFun = vtkColorTransferFunction::New(); + cTFun->AddRGBPoint( 0, 1.0, 1.0, 1.0 ); + //cTFun->AddRGBPoint( 255, 1.0, 1.0, 1.0 ); + cTFun->AddRGBPoint( 240, 1.0, 1.0, 1.0 ); + + // Need to crop to actually see minimum intensity + vtkImageClip *clip = vtkImageClip::New(); + clip->SetInputConnection( reader->GetOutputPort() ); + clip->SetOutputWholeExtent(0,66,0,66,30,37); + clip->ClipDataOn(); + + vtkVolumeProperty *property = vtkVolumeProperty::New(); + property->SetScalarOpacity(oTFun); + property->SetColor(cTFun); + property->SetInterpolationTypeToLinear(); + + vtkFixedPointVolumeRayCastMapper *mapper = vtkFixedPointVolumeRayCastMapper::New(); + mapper->SetBlendModeToMinimumIntensity(); + mapper->SetInputConnection( reader->GetOutputPort() ); + + vtkVolume *volume = vtkVolume::New(); + volume->SetMapper(mapper); + volume->SetProperty(property); + + + ren->AddViewProp(volume); + + renWin->Render(); + { + iren->Start(); + } + + volume->Delete(); + mapper->Delete(); + property->Delete(); + clip->Delete(); + cTFun->Delete(); + oTFun->Delete(); + reader->Delete(); + renWin->Delete(); + iren->Delete(); + ren->Delete(); + + + return 0; +} diff --git a/gdcm/Utilities/VTK/Examples/Cxx/offscreenimage.cxx b/gdcm/Utilities/VTK/Examples/Cxx/offscreenimage.cxx new file mode 100644 index 0000000..867051f --- /dev/null +++ b/gdcm/Utilities/VTK/Examples/Cxx/offscreenimage.cxx @@ -0,0 +1,90 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkGDCMImageReader.h" +#include "vtkRenderWindow.h" +#include "vtkRenderer.h" +#include "vtkImageMapToWindowLevelColors.h" +#include "vtkImageActor.h" +#include "vtkPNGWriter.h" +#include "vtkWindowToImageFilter.h" +#include "vtkMedicalImageProperties.h" + +int main(int argc, char *argv[]) +{ + if( argc < 2 ) + { + return 1; + } + const char *filename = argv[1]; + + vtkGDCMImageReader *reader = vtkGDCMImageReader::New(); + reader->SetFileName( filename ); + reader->Update(); // important to read the window/level info + + vtkMedicalImageProperties *prop = reader->GetMedicalImageProperties(); + + vtkRenderWindow *renWin = vtkRenderWindow::New(); + renWin->OffScreenRenderingOn(); + + vtkRenderer *renderer = vtkRenderer::New(); + renWin->AddRenderer(renderer); + + vtkImageMapToWindowLevelColors *windowlevel = vtkImageMapToWindowLevelColors::New(); +#if (VTK_MAJOR_VERSION >= 6) + windowlevel->SetInputConnection( reader->GetOutputPort() ); +#else + windowlevel->SetInput( reader->GetOutput() ); +#endif + unsigned int n = prop->GetNumberOfWindowLevelPresets(); + if( n ) + { + // Take the first one by default: + const double *wl = prop->GetNthWindowLevelPreset(0); + windowlevel->SetWindow( wl[0] ); + windowlevel->SetLevel( wl[1] ); + } + + vtkImageActor *actor = vtkImageActor::New(); +#if (VTK_MAJOR_VERSION >= 6) + actor->SetInputData( windowlevel->GetOutput() ); +#else + actor->SetInput( windowlevel->GetOutput() ); +#endif + + renderer->AddActor( actor ); + + renWin->Render(); + + vtkWindowToImageFilter *w2if = vtkWindowToImageFilter::New(); + w2if->SetInput ( renWin ); + + vtkPNGWriter *wr = vtkPNGWriter::New(); +#if (VTK_MAJOR_VERSION >= 6) + wr->SetInputConnection( w2if->GetOutputPort() ); +#else + wr->SetInput( w2if->GetOutput() ); +#endif + wr->SetFileName ( "offscreenimage.png" ); + wr->Write(); + + reader->Delete(); + renWin->Delete(); + renderer->Delete(); + windowlevel->Delete(); + actor->Delete(); + w2if->Delete(); + wr->Delete(); + + return 0; +} diff --git a/gdcm/Utilities/VTK/Examples/Cxx/reslicesphere.cxx b/gdcm/Utilities/VTK/Examples/Cxx/reslicesphere.cxx new file mode 100644 index 0000000..1a4edf4 --- /dev/null +++ b/gdcm/Utilities/VTK/Examples/Cxx/reslicesphere.cxx @@ -0,0 +1,631 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +// +// Load a DICOM series. +// Position a sphere within the volume. +// Allow the user to change between Axial, Sagittal, Coronal, and +// Oblique view of the images and move through the slices. +// The display should show the resliced image and the cross section +// of the sphere intersecting that plane. +// + + +/* +from Scott Johnson /Scott Johnson neuwave com/ +to VTK /vtkusers vtk.org/ +date Tue, May 11, 2010 at 7:01 PM +*/ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "vtkTransformPolyDataFilter.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gdcmDirectory.h" +#include "gdcmTesting.h" +#include "gdcmIPPSorter.h" + +// Change to match the path to find Raw_0.vti or provide +// the parameter when starting ResliceSphere. + +const double sphereCenter[3]={74, 219, 70}; + +// Angles (0, 0, 0) +const double AxialMatrix[] = { 1.0, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0 }; +// Angles (0, 90, 0) +const double SagittalMatrix[] = { 0.0, 0.0, 1.0, 0.0, + 0.0, 1.0, 0.0, 0.0, + -1.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 1.0 }; +// Angles (-90, 0, 0) +const double CoronalMatrix[] = { 1.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.0, -1.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 1.0 }; +// Angles (0, 90, 31) +const double ObliqueMatrix[] = { 0.0, -0.515038, 0.857167, 0.0, + 0.0, 0.857167, 0.515038, 0.0, + -1.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 1.0 }; + +class ResliceRender; + +// Class to handle key press events. +class KeyCallback : public vtkCommand +{ +public: + static KeyCallback* New() + { + return new KeyCallback(); + } + + void Execute(vtkObject* caller, unsigned long eventId, void *calldata); + void SetCallbackData(ResliceRender* reslice); + +protected: + ResliceRender* _reslice; +}; + +class ResliceRender +{ +public: + typedef enum _ORIENTATION + { + AXIAL = 0, + SAGITTAL = 1, + CORONAL = 2, + OBLIQUE = 3 + } ORIENTATION; + + ResliceRender() + { + _orientation=AXIAL; + } + + ~ResliceRender() + { + _transform->Delete(); + _reader->Delete(); + _reslice->Delete(); + _interactor->Delete(); + _imageViewer->Delete(); + + _sphere->Delete(); + _sphereMapper->Delete(); + _sphereActor->Delete(); + + _plane->Delete(); + _cutter->Delete(); + _polyTransform->Delete(); + _ROIMapper->Delete(); + _ROIActor->Delete(); + + _annotation->Delete(); + } + + void CreatePipeline(const char* fileName) + { + vtkProperty2D* props; + + //_reader=vtkXMLImageDataReader::New(); + //_reader->SetFileName(fileName); + //_reader->Update(); + + //_reader=qzDICOMImageReader::New(); + _reader=vtkGDCMImageReader::New(); + + //vtkDirectory *d = vtkDirectory::New(); + //d->Open(fileName); + //d->Print( std::cout ); + gdcm::Directory d; + d.Load(fileName); + gdcm::Directory::FilenamesType const &files = d.GetFilenames(); + + gdcm::IPPSorter s; + s.SetComputeZSpacing( true ); + s.SetZSpacingTolerance( 1e-3 ); + bool b = s.Sort( files ); + if( !b ) + { + std::cerr << "Failed to sort:" << fileName << std::endl; + //return ; + } + //std::cout << "Sorting succeeded:" << std::endl; + //s.Print( std::cout ); + + //std::cout << "Found z-spacing:" << std::endl; + //std::cout << s.GetZSpacing() << std::endl; + double ippzspacing = s.GetZSpacing(); + + const std::vector & sorted = s.GetFilenames(); + vtkStringArray *vtkfiles = vtkStringArray::New(); + std::vector< std::string >::const_iterator it = sorted.begin(); + for( ; it != sorted.end(); ++it) + { + const std::string &f = *it; + vtkfiles->InsertNextValue( f.c_str() ); + } + + //_reader->SetDirectoryName(fileName); + //_reader->SetFileNames( d->GetFiles() ); + _reader->SetFileNames( vtkfiles ); + _reader->Update(); + + const vtkFloatingPointType *spacing = _reader->GetOutput()->GetSpacing(); + + vtkImageChangeInformation *v16 = vtkImageChangeInformation::New(); +#if (VTK_MAJOR_VERSION >= 6) + v16->SetInputConnection( _reader->GetOutputPort() ); +#else + v16->SetInput( _reader->GetOutput() ); +#endif + v16->SetOutputSpacing( spacing[0], spacing[1], ippzspacing ); + v16->Update(); + + + _threshold=vtkImageThreshold::New(); + _threshold->ThresholdByUpper(-3024.0); + _threshold->ReplaceOutOn(); + _threshold->SetOutValue(0.0); + _threshold->SetInputConnection(v16->GetOutputPort()); + + _shift=vtkImageShiftScale::New(); + _shift->SetShift(0); + _shift->SetScale(1); + _shift->SetInputConnection(_threshold->GetOutputPort()); + + // Initialize the reslice with an axial orientation. + vtkSmartPointer matrix = + vtkSmartPointer::New(); + matrix->Identity(); + + _transform = vtkTransform::New(); + _transform->SetMatrix(matrix); + + _reslice = vtkImageReslice::New(); + _reslice->SetOutputDimensionality(3); + + // PROBLEM: + // The original intent was to connect the same transform + // to the vtkImageReslice and vtkTransformPolyDataFilter, + // but the resulting reslices appear different using the + // vtkTransform as opposed to explicitly setting the + // reslice axes via SetResliceAxes. Also, if the vtkTransform + // is connected and orientated other than axial, the extents + // don't seem to update resulting in VTK believing the slice + // is out of range. + + //_reslice->SetResliceTransform(_transform); + _reslice->SetResliceAxes(matrix); + //_reslice->SetInputConnection(_reader->GetOutputPort()); + _reslice->SetInputConnection(_shift->GetOutputPort()); + + // Create the sphere target shape. + _sphere=vtkSphereSource::New(); + _sphere->SetRadius(7.0); + _sphere->SetThetaResolution(16); + _sphere->SetPhiResolution(16); + _sphere->SetCenter(sphereCenter[0], sphereCenter[1], sphereCenter[2]); + + _sphereMapper=vtkPolyDataMapper::New(); + _sphereMapper->SetInputConnection(_sphere->GetOutputPort()); + + _sphereActor=vtkActor::New(); + _sphereActor->SetMapper(_sphereMapper); + _sphereActor->PickableOff(); + _sphereActor->GetProperty()->SetColor(1.0, 0.0, 0.0); + _sphereActor->GetProperty()->SetEdgeColor(1.0, 0.0, 0.0); + _sphereActor->GetProperty()->SetDiffuseColor(1.0, 0.0, 0.0); + _sphereActor->SetVisibility(true); + + // Create the cutting pipeline. + // This plane will be positioned in the original image coordinate system. + _plane = vtkPlane::New(); + _plane->SetNormal(0.0, 0.0, 1.0); + + _cutter = vtkCutter::New(); + _cutter->SetInputConnection(_sphere->GetOutputPort()); + _cutter->SetCutFunction(_plane); + _cutter->GenerateCutScalarsOn(); + _cutter->SetValue(0, 0.5); + + // The transform attached to _polyTransform should move the cut + // ROI into the resliced coordinate system, which should be the + // same as the coordinate system of the resliced images. + // PROBLEM: It doesn't. + _polyTransform = vtkTransformPolyDataFilter::New(); + _polyTransform->SetTransform(_transform); + _polyTransform->SetInputConnection(_cutter->GetOutputPort()); + + _ROIMapper = vtkPolyDataMapper2D::New(); + _ROIMapper->SetInputConnection(_polyTransform->GetOutputPort()); + + vtkCoordinate* coordinate = vtkCoordinate::New(); + coordinate->SetCoordinateSystemToWorld(); + _ROIMapper->SetTransformCoordinate(coordinate); + + _ROIActor = vtkActor2D::New(); + _ROIActor->SetMapper(_ROIMapper); + + // Make sure the cut can be seen, especially the edges. + props=_ROIActor->GetProperty(); + props->SetLineWidth(2); + props->SetOpacity(1.0); +// props->EdgeVisibilityOn(); +// props->SetDiffuse(0.8); +// props->SetSpecular(0.3); +// props->SetSpecularPower(20); +// props->SetRepresentationToSurface(); +// props->SetDiffuseColor(1.0, 0.0, 0.0); +// props->SetEdgeColor(1.0, 0.0, 0.0); + props->SetColor(1.0, 0.0, 0.0); + + _interactor = vtkRenderWindowInteractor::New(); + + // Create the image viewer and add the actor with the cut ROI. + _imageViewer = vtkImageViewer2::New(); + _imageViewer->SetupInteractor(_interactor); + _imageViewer->SetSize(400, 400); + _imageViewer->SetColorWindow(1024); + _imageViewer->SetColorLevel(800); + _imageViewer->SetInputConnection(_reslice->GetOutputPort()); + _imageViewer->GetImageActor()->SetOpacity(0.5); + + _annotation = vtkTextActor::New(); + _annotation->SetTextScaleModeToViewport(); + _imageViewer->GetRenderer()->AddActor(_annotation); + + // Add the cut shape actor to the renderer. + _imageViewer->GetRenderer()->AddActor(_ROIActor); + + // Set up the key handler. + vtkSmartPointer callback = vtkSmartPointer::New(); + callback->SetCallbackData(this); + _interactor->AddObserver(vtkCommand::KeyPressEvent, callback); + + _interactor->Initialize(); + } + + void Start() + { + _interactor->Start(); + } + + void ResetOrientation() + { + vtkSmartPointer matrix = + vtkSmartPointer::New(); + matrix->Identity(); + + SetOrientation(matrix); + } + + // Make sure the orientation of the vtkImageReslice and + // vtkTransform are in sync. + void SetOrientation(vtkMatrix4x4* matrix) + { + _reslice->SetResliceAxes(matrix); + _reslice->Update(); + + vtkMatrix4x4* inverse = vtkMatrix4x4::New(); + vtkMatrix4x4::Invert(matrix, inverse); + + _transform->SetMatrix(inverse); + _transform->Update(); + } + + // Set the current slice of the current view. + void SetSlice(int slice) + { + std::strstream posString; + + double center[3]; + double spacing[3]; + double origin[3]; + double point[4]; + double newPoint[4]; + + vtkImageData* imageData; + int newSlice; + + // Try to make sure the extents of the reslice are updated. + // PROBLEM: It doesn't seem to work when changing the orientation. + imageData=vtkImageData::SafeDownCast(_reslice->GetOutput()); +#if (VTK_MAJOR_VERSION >= 6) + assert(0); +#else + imageData->UpdateInformation(); +#endif + + // Let vtkImageViewer2 handle the slice limits. + _imageViewer->SetSlice(slice); + newSlice=GetSlice(); + + imageData->GetCenter(center); + imageData->GetSpacing(spacing); + imageData->GetOrigin(origin); + + // Compute the position of the center of the slice based on the + // spacing of the slices. The resliced axis will always + // be the "Z" axis. + point[0]=center[0]; + point[1]=center[1]; + point[2]=(newSlice * spacing[2]) + origin[2]; + point[3]=1.0; + + // Convert the coordinate from the reslice coordinate system to the + // original image coordinate system. + // PROBLEM: Logically this seems like it should have been multiplied + // by the inverse to translate from the resliced coordinate system to + // the original coordinate system. However, multiplying by the inverse + // sticks the plane in the wrong place completely. Using the original + // matrix at least gets the Z coordinate right. + vtkMatrix4x4* matrix=_reslice->GetResliceAxes(); + vtkSmartPointer inverse = + vtkSmartPointer::New(); + vtkMatrix4x4::Invert(matrix, inverse); + + matrix->MultiplyPoint(point, newPoint); + _plane->SetOrigin(newPoint[0], newPoint[1], newPoint[2]); + + // Annotate the image. + posString << "Position: (" << newPoint[0] << ", " << newPoint[1] + << ", " << newPoint[2] << ") Slice: " << newSlice; + _annotation->SetInput(posString.str()); + + _imageViewer->Render(); + } + + int GetSlice() + { + return _imageViewer->GetSlice(); + } + + // Set the orientation of the view. + void SetOrientation(ResliceRender::ORIENTATION orientation) + { + vtkCamera* camera=_imageViewer->GetRenderer()->GetActiveCamera(); + + double spacing[3]; + double origin[3]; + double point[4]; + double newPoint[4]; + double initialPosition; + double xDirCosine[3]; + double yDirCosine[3]; + double zDirCosine[3]; + double normal[3]; + + vtkImageData* imageData; + + vtkSmartPointer matrix = + vtkSmartPointer::New(); + + _orientation=orientation; + + // Reset ViewUp + camera->SetViewUp(0.0, 1.0, 0.0); + + // Compute the cut plane position to the input coordinate system. + imageData=vtkImageData::SafeDownCast(_reslice->GetInput()); +#if (VTK_MAJOR_VERSION >= 6) + assert(0); +#else + imageData->UpdateInformation(); +#endif + imageData->GetSpacing(spacing); + imageData->GetOrigin(origin); + + point[0]=origin[0]; + point[1]=origin[1]; + point[2]=origin[2]; + point[3]=1.0; + + switch (_orientation) + { + case AXIAL: + matrix->DeepCopy(AxialMatrix); + initialPosition=sphereCenter[2]; + break; + + case CORONAL: + matrix->DeepCopy(CoronalMatrix); + initialPosition=sphereCenter[1]; + break; + + case SAGITTAL: + matrix->DeepCopy(SagittalMatrix); + initialPosition=sphereCenter[0]; + break; + + case OBLIQUE: + matrix->DeepCopy(ObliqueMatrix); + initialPosition=sphereCenter[2]; + break; + } + + // Move the origin from the original image coordinate system to the + // resliced image coordinate system. + matrix->MultiplyPoint(point, newPoint); + matrix->SetElement(0, 3, newPoint[0]); + matrix->SetElement(1, 3, newPoint[1]); + matrix->SetElement(2, 3, newPoint[2]); + + ResetOrientation(); + SetOrientation(matrix); + + // Compute the cutting plane normal and set it. + // PROBLEM: If the transformation is connected rather than + // using SetResliceAxes, the Direction Cosines do not reflect + // the orientation of the vtkImageReslice. + _reslice->GetResliceAxesDirectionCosines(xDirCosine, yDirCosine, + zDirCosine); + vtkMath::Cross(xDirCosine, yDirCosine, normal); + _plane->SetNormal(normal); + + // Set the extents and spacing of the reslice to account for + // all of the data. + _reslice->SetOutputExtentToDefault(); + _reslice->SetOutputSpacing(spacing[0], spacing[0], spacing[0]); + + // Force the vtkImageViewer2 to update. + // PROBLEM: The whole extent does not seem to be set in time + // for the first render. This results in an error because the + // slice is positioned outside the old bounds. +#if (VTK_MAJOR_VERSION >= 6) + _imageViewer->SetInputData(NULL); +#else + _imageViewer->SetInput(NULL); +#endif + _imageViewer->SetInputConnection(_reslice->GetOutputPort()); + + _imageViewer->GetRenderer()->ResetCameraClippingRange(); + _imageViewer->GetRenderer()->ResetCamera(); + + // Set the initial slice to be at the center of the sphere. + // Divide by the spacing because this will be undone in SetSlice. + SetSlice( (int)(initialPosition / spacing[0])); + } + + vtkRenderWindowInteractor* GetInteractor() + { + return _interactor; + } + +protected: + ORIENTATION _orientation; + + //qzDICOMImageReader* _reader; + vtkGDCMImageReader* _reader; + vtkImageThreshold* _threshold; + vtkImageShiftScale* _shift; + vtkImageReslice* _reslice; + vtkRenderWindowInteractor* _interactor; + vtkImageViewer2* _imageViewer; + + vtkSphereSource* _sphere; + vtkPolyDataMapper* _sphereMapper; + vtkActor* _sphereActor; + + vtkPlane* _plane; + vtkCutter* _cutter; + vtkTransform* _transform; + vtkTransformPolyDataFilter* _polyTransform; + vtkPolyDataMapper2D* _ROIMapper; + vtkActor2D* _ROIActor; + + vtkTextActor* _annotation; +}; + + +// Catch KeyPress events. +// Up Arrow - increases the slice +// Down Arrow - decreases the slice +// 'A' - sets the view to Axial +// 'S' - sets the view to Sagittal +// 'C' - sets the view to Coronal +// 'O' - set the view to Oblique + +void KeyCallback::Execute(vtkObject* caller, unsigned long eventId, void *calldata) +{ + (void)caller; + (void)eventId; + (void)calldata; + std::string sym=_reslice->GetInteractor()->GetKeySym(); + + if (!sym.compare("Up")) + { + _reslice->SetSlice(_reslice->GetSlice() + 1); + } + else if (!sym.compare("Down")) + { + _reslice->SetSlice(_reslice->GetSlice() - 1); + } + else if ((!sym.compare("A")) || (!sym.compare("a"))) + { + _reslice->SetOrientation(ResliceRender::AXIAL); + } + else if ((!sym.compare("C")) || (!sym.compare("c"))) + { + _reslice->SetOrientation(ResliceRender::CORONAL); + } + else if ((!sym.compare("S")) || (!sym.compare("s"))) + { + _reslice->SetOrientation(ResliceRender::SAGITTAL); + } + else if ((!sym.compare("O")) || (!sym.compare("o"))) + { + _reslice->SetOrientation(ResliceRender::OBLIQUE); + } +} + +void KeyCallback::SetCallbackData(ResliceRender* reslice) +{ + _reslice=reslice; +} + +// Usage: ResliceSphere [fileName] +int main(int argc, char *argv[]) +{ + ResliceRender render; + + if (argc == 1) + { + const char *root = gdcm::Testing::GetDataExtraRoot(); + std::string dir3 = root; + dir3 += "/gdcmSampleData/ForSeriesTesting/Dentist/images/"; + render.CreatePipeline(dir3.c_str()); + } + else + { + render.CreatePipeline(argv[1]); + } + + render.SetOrientation(ResliceRender::AXIAL); + render.Start(); + + return EXIT_SUCCESS; +} diff --git a/gdcm/Utilities/VTK/Examples/Cxx/rtstructapp.cxx b/gdcm/Utilities/VTK/Examples/Cxx/rtstructapp.cxx new file mode 100644 index 0000000..f540c48 --- /dev/null +++ b/gdcm/Utilities/VTK/Examples/Cxx/rtstructapp.cxx @@ -0,0 +1,124 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkGDCMPolyDataReader.h" +#include "vtkGDCMPolyDataWriter.h" + +#include "vtkPolyDataWriter.h" +#include "vtkPolyDataMapper.h" +#include "vtkPolyDataMapper2D.h" +#include "vtkActor2D.h" +#include "vtkRenderWindowInteractor.h" +#include "vtkMedicalImageProperties.h" +#include "vtkRenderWindow.h" +#include "vtkRenderer.h" +#include "vtkCamera.h" +#include "vtkProperty.h" +#include "vtkProperty2D.h" +#include "vtkAppendPolyData.h" +#include "vtkImageData.h" + +/* + * Small example to read in a RTSTUCT and write it out (displays it too). + */ + +// gdcmDataExtra/gdcmNonImageData/exRT_Structure_Set_Storage.dcm +// gdcmDataExtra/gdcmNonImageData/RTSTRUCT_1.3.6.1.4.1.22213.1.1396.2.dcm +// gdcmDataExtra/gdcmNonImageData/RT/RTStruct.dcm + +int main(int argc, char *argv[]) +{ + if( argc < 3 ) + { + std::cerr << argv[0] << " input.dcm output.dcm\n"; + return 1; + } + const char * filename = argv[1]; + const char * outfilename = argv[2]; + vtkGDCMPolyDataReader * reader = vtkGDCMPolyDataReader::New(); + reader->SetFileName( filename ); + reader->Update(); + + //std::cout << reader->GetMedicalImageProperties()->GetStudyDate() << std::endl; + + vtkGDCMPolyDataWriter * writer = vtkGDCMPolyDataWriter::New(); + writer->SetNumberOfInputPorts( reader->GetNumberOfOutputPorts() ); + writer->SetFileName( outfilename ); + for(int num = 0; num < reader->GetNumberOfOutputPorts(); ++num ) +#if (VTK_MAJOR_VERSION >= 6) + writer->SetInputConnection( num, reader->GetOutputPort(num) ); +#else + writer->SetInput( num, reader->GetOutput(num) ); +#endif + //doesn't look like the medical properties are actually written out + writer->SetMedicalImageProperties( reader->GetMedicalImageProperties() ); + writer->SetRTStructSetProperties( reader->GetRTStructSetProperties() ); + writer->Write(); + + // print reader output: + reader->Print( std::cout ); + // print first output: + reader->GetOutput()->Print( std::cout ); + + vtkAppendPolyData *append = vtkAppendPolyData::New(); + + int n = reader->GetNumberOfOutputPorts(); + for(int i = 0; i < n; ++i) + { +#if (VTK_MAJOR_VERSION >= 6) + append->AddInputConnection( reader->GetOutputPort(i) ); +#else + append->AddInput( reader->GetOutput(i) ); +#endif + } + + // Now we'll look at it. + vtkPolyDataMapper *cubeMapper = vtkPolyDataMapper::New(); +#if (VTK_MAJOR_VERSION >= 6) + cubeMapper->SetInputConnection( append->GetOutputPort()); +#else + cubeMapper->SetInput( append->GetOutput()); +#endif + cubeMapper->SetScalarRange(0,7); + vtkActor *cubeActor = vtkActor::New(); + cubeActor->SetMapper(cubeMapper); + vtkProperty * property = cubeActor->GetProperty(); + property->SetRepresentationToWireframe(); + + vtkRenderer *renderer = vtkRenderer::New(); + vtkRenderWindow *renWin = vtkRenderWindow::New(); + renWin->AddRenderer(renderer); + + vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New(); + iren->SetRenderWindow(renWin); + + renderer->AddActor(cubeActor); + renderer->ResetCamera(); + renderer->SetBackground(1,1,1); + + renWin->SetSize(300,300); + + renWin->Render(); + iren->Start(); + + reader->Delete(); + append->Delete(); + cubeMapper->Delete(); + cubeActor->Delete(); + renderer->Delete(); + renWin->Delete(); + iren->Delete(); + writer->Delete(); + + return 0; +} diff --git a/gdcm/Utilities/VTK/Examples/Cxx/threadgdcm.cxx b/gdcm/Utilities/VTK/Examples/Cxx/threadgdcm.cxx new file mode 100644 index 0000000..2e6abaa --- /dev/null +++ b/gdcm/Utilities/VTK/Examples/Cxx/threadgdcm.cxx @@ -0,0 +1,275 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmReader.h" +#include "gdcmImageReader.h" +#include "gdcmDirectory.h" +#include "gdcmSystem.h" + +#include "vtkImageData.h" +#include "vtkStructuredPointsWriter.h" + +#include + +struct threadparams +{ + const char **filenames; + size_t nfiles; + char *scalarpointer; +// TODO I should also pass in the dim of the reference image just in case +}; + +void *ReadFilesThread(void *voidparams) +{ + const threadparams *params = static_cast (voidparams); + + const size_t nfiles = params->nfiles; + for(unsigned int file = 0; file < nfiles; ++file) + { + /* + // TODO: update progress + pthread_mutex_lock(¶ms->lock); + //section critique + ReadingProgress+=params->stepProgress; + pthread_mutex_unlock(¶ms->lock); + */ + const char *filename = params->filenames[file]; + //std::cerr << filename << std::endl; + + gdcm::ImageReader reader; + reader.SetFileName( filename ); + try + { + if( !reader.Read() ) + { + std::cerr << "Failed to read: " << filename << std::endl; + break; + } + } + catch( ... ) + { + std::cerr << "Failed to read: " << filename << std::endl; + break; + } + + const gdcm::Image &image = reader.GetImage(); + unsigned long len = image.GetBufferLength(); + char * pointer = params->scalarpointer; +#if 0 + char *tempimage = new char[len]; + image.GetBuffer(tempimage); + + memcpy(pointer + file*len, tempimage, len); + delete[] tempimage; +#else + char *tempimage = pointer + file * len; + image.GetBuffer(tempimage); +#endif + } + + return voidparams; +} + +void ShowFilenames(const threadparams ¶ms) +{ + std::cout << "start" << std::endl; + for(unsigned int i = 0; i < params.nfiles; ++i) + { + const char *filename = params.filenames[i]; + std::cout << filename << std::endl; + } + std::cout << "end" << std::endl; +} + +void ReadFiles(size_t nfiles, const char *filenames[]) +{ + // \precondition: nfiles > 0 + assert( nfiles > 0 ); + const char *reference= filenames[0]; // take the first image as reference + + gdcm::ImageReader reader; + reader.SetFileName( reference ); + if( !reader.Read() ) + { + // That would be very bad... + assert(0); + } + + const gdcm::Image &image = reader.GetImage(); + gdcm::PixelFormat pixeltype = image.GetPixelFormat(); + unsigned long len = image.GetBufferLength(); + const unsigned int *dims = image.GetDimensions(); + unsigned short pixelsize = pixeltype.GetPixelSize(); + (void)pixelsize; + assert( image.GetNumberOfDimensions() == 2 ); + + vtkImageData *output = vtkImageData::New(); + output->SetDimensions(dims[0], dims[1], (int)nfiles); + +#if (VTK_MAJOR_VERSION >= 6) + int numscal = pixeltype.GetSamplesPerPixel(); + switch( pixeltype ) + { + case gdcm::PixelFormat::INT8: + output->AllocateScalars( VTK_SIGNED_CHAR, numscal ); + break; + case gdcm::PixelFormat::UINT8: + output->AllocateScalars( VTK_UNSIGNED_CHAR, numscal ); + break; + case gdcm::PixelFormat::INT16: + output->AllocateScalars( VTK_SHORT, numscal ); + break; + case gdcm::PixelFormat::UINT16: + output->AllocateScalars( VTK_UNSIGNED_SHORT, numscal ); + break; + case gdcm::PixelFormat::INT32: + output->AllocateScalars( VTK_INT, numscal ); + break; + case gdcm::PixelFormat::UINT32: + output->AllocateScalars( VTK_UNSIGNED_INT, numscal ); + break; + default: + assert(0); + } +#else + switch( pixeltype ) + { + case gdcm::PixelFormat::INT8: +#if (VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 ) + output->SetScalarType ( VTK_SIGNED_CHAR ); +#else + output->SetScalarType ( VTK_CHAR ); +#endif + break; + case gdcm::PixelFormat::UINT8: + output->SetScalarType ( VTK_UNSIGNED_CHAR ); + break; + case gdcm::PixelFormat::INT16: + output->SetScalarType ( VTK_SHORT ); + break; + case gdcm::PixelFormat::UINT16: + output->SetScalarType ( VTK_UNSIGNED_SHORT ); + break; + case gdcm::PixelFormat::INT32: + output->SetScalarType ( VTK_INT ); + break; + case gdcm::PixelFormat::UINT32: + output->SetScalarType ( VTK_UNSIGNED_INT ); + break; + default: + assert(0); + } + output->SetNumberOfScalarComponents ( pixeltype.GetSamplesPerPixel() ); + output->AllocateScalars(); +#endif + char * scalarpointer = static_cast(output->GetScalarPointer()); + + const unsigned int nthreads = 4; + threadparams params[nthreads]; + + //pthread_mutex_t lock; + //pthread_mutex_init(&lock, NULL); + + pthread_t *pthread = new pthread_t[nthreads]; + + // There is nfiles, and nThreads + assert( nfiles > nthreads ); + const size_t partition = nfiles / nthreads; + for (unsigned int thread=0; thread < nthreads; ++thread) + { + params[thread].filenames = filenames + thread * partition; + params[thread].nfiles = partition; + if( thread == nthreads - 1 ) + { + // There is slightly more files to process in this thread: + params[thread].nfiles += nfiles % nthreads; + } + assert( thread * partition < nfiles ); + params[thread].scalarpointer = scalarpointer + thread * partition * len; + //assert( params[thread].scalarpointer < scalarpointer + 2 * dims[0] * dims[1] * dims[2] ); + // start thread: + int res = pthread_create( &pthread[thread], NULL, ReadFilesThread, ¶ms[thread]); + if( res ) + { + std::cerr << "Unable to start a new thread, pthread returned: " << res << std::endl; + assert(0); + } + //ShowFilenames(params[thread]); + } +// DEBUG + size_t total = 0; + for (unsigned int thread=0; thread < nthreads; ++thread) + { + total += params[thread].nfiles; + } + assert( total == nfiles ); +// END DEBUG + + for (unsigned int thread=0;thread= 6) + writer->SetInputData( output ); +#else + writer->SetInput( output ); +#endif + writer->SetFileName( "/tmp/threadgdcm.vtk" ); + writer->SetFileTypeToBinary(); + //writer->Write(); + writer->Delete(); + + //output->Print( std::cout ); + output->Delete(); +} + +int main(int argc, char *argv[]) +{ + if( argc < 2 ) + { + std::cerr << argv[0] << " [directory|list of filenames]\n"; + return 1; + } + + // Check if user pass in a single directory + if( argc == 2 && gdcm::System::FileIsDirectory( argv[1] ) ) + { + gdcm::Directory d; + d.Load( argv[1] ); + gdcm::Directory::FilenamesType l = d.GetFilenames(); + const size_t nfiles = l.size(); + const char **filenames = new const char* [ nfiles ]; + for(unsigned int i = 0; i < nfiles; ++i) + { + filenames[i] = l[i].c_str(); + } + ReadFiles(nfiles, filenames); + delete[] filenames; + } + else + { + // Simply copy all filenames into the vector: + const char **filenames = const_cast(argv+1); + const size_t nfiles = argc - 1; + ReadFiles(nfiles, filenames); + } + + + return 0; +} diff --git a/gdcm/Utilities/VTK/Examples/Java/AWTMedical3.java b/gdcm/Utilities/VTK/Examples/Java/AWTMedical3.java new file mode 100644 index 0000000..6911aee --- /dev/null +++ b/gdcm/Utilities/VTK/Examples/Java/AWTMedical3.java @@ -0,0 +1,322 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +package examples; + +import vtk.*; +//import gdcm.*; + +import vtk.util.VtkPanelContainer; +import vtk.util.VtkPanelUtil; +import vtk.util.VtkUtil; + +import java.util.ArrayList; + + +import javax.swing.*; +import java.awt.*; +import java.io.File; + +/** + * + * This class should show how to read an image and display it + * using gdcm and vtk, similar to gdcmorthoplanes + * + * used to test the transition from vtk 5.6 to vtk 5.9 + * @author mmroden + */ +public class AWTMedical3 extends JComponent implements VtkPanelContainer { + + private vtkPanel renWin; + + vtkImageData ReadDataFile(File inSelectedFile){ + + vtkImageData outImageData = null; + Directory theDir = new Directory(); + + String theInputDirectory = inSelectedFile.getPath(); + theDir.Load(theInputDirectory); + + Scanner theScanner = new Scanner(); + Tag theStudyTag = new Tag(0x0020,0x000d); + Tag theSeriesTag = new Tag(0x0020,0x000e); + theScanner.AddTag(theStudyTag);//get studies, + theScanner.AddTag(theSeriesTag);//get studies, + theScanner.Scan(theDir.GetFilenames()); + + FilenamesType theStudyValues = theScanner.GetOrderedValues(theStudyTag); + long theNumStudies = theStudyValues.size(); + //for now, take the first study, and nothing else. + //and the return is actually not FilenamesType, just a + //vector of strings + if (theNumStudies != 1) + return outImageData; + String theStudyVal = theStudyValues.get(0); + //now, get all the values from the scanner that are in that + //study, then from that get their different series + FilenamesType theFilenames = + theScanner.GetAllFilenamesFromTagToValue(theStudyTag, theStudyVal); + + //from that set of filenames, isolate individual series + //conclude that singleton series = RT struct (can do further + //checking for things like MIPs and the like) + //and multiple series entries = volumetric data + theScanner.Scan(theFilenames); + FilenamesType theSeriesValues = theScanner.GetOrderedValues(theSeriesTag); + String studyUID = theScanner.GetValue(theScanner.GetFilenames().get(0), theStudyTag); + long theNumSeries = theSeriesValues.size(); + for (int i = 0; i < theNumSeries; i++) { + FilenamesType theSeriesFiles = + theScanner.GetAllFilenamesFromTagToValue(theSeriesTag, theSeriesValues.get(i)); + long theNumFilesInSeries = theSeriesFiles.size(); + if (theNumFilesInSeries > 1) {//assume it's CT or volumetric data + //for now, assume a single volume + //could have multiples, like PET and CT + + IPPSorter sorter = new IPPSorter(); + sorter.SetComputeZSpacing(true); + sorter.SetZSpacingTolerance(0.001); + Boolean sorted = sorter.Sort(theSeriesFiles); + if (!sorted){ + //need some better way to handle failures here + return outImageData; + } + + FilenamesType sortedFT = sorter.GetFilenames(); + long theSize = sortedFT.size(); + vtkStringArray sa = new vtkStringArray(); + ArrayList theStrings = new ArrayList(); + + vtkGDCMImageReader gdcmReader = new vtkGDCMImageReader(); + for (int j = 0; j < theSize; j++) { + String theFileName = sortedFT.get(j); + if (gdcmReader.CanReadFile(theFileName) > 0){ + theStrings.add(theFileName); + sa.InsertNextValue(theFileName); + } else { + //this is a busted series + //need some more appropriate error here + return outImageData; + } + } + + gdcmReader.SetFileNames(sa); + + gdcmReader.Update(); + + outImageData = gdcmReader.GetOutput();//the zeroth output should be the image + } + } + String theImageInfo = ""; + if (outImageData != null){ + theImageInfo = outImageData.Print(); + } + return outImageData; + } + + //this function is a rewrite of Medical3 to see if data can + //be loaded via gdcm easily + public AWTMedical3(File inFile) { + // Create the buttons. + renWin = new vtkPanel(); + + vtkImageData theImageData = ReadDataFile(inFile); + + // An isosurface, or contour value of 500 is known to correspond to the + // skin of the patient. Once generated, a vtkPolyDataNormals filter is + // is used to create normals for smooth surface shading during rendering. + // The triangle stripper is used to create triangle strips from the + // isosurface these render much faster on some systems. + vtkContourFilter skinExtractor = new vtkContourFilter(); + skinExtractor.SetInput(theImageData); + skinExtractor.SetValue(0, 500); + vtkPolyDataNormals skinNormals = new vtkPolyDataNormals(); + skinNormals.SetInput(skinExtractor.GetOutput()); + skinNormals.SetFeatureAngle(60.0); +// vtkStripper skinStripper = new vtkStripper(); +// skinStripper.SetInput(skinNormals.GetOutput()); + vtkPolyDataMapper skinMapper = new vtkPolyDataMapper(); + skinMapper.SetInput(skinNormals.GetOutput()); + skinMapper.ScalarVisibilityOff(); + vtkActor skin = new vtkActor(); + skin.SetMapper(skinMapper); + skin.GetProperty().SetDiffuseColor(1, .49, .25); + skin.GetProperty().SetSpecular(.3); + skin.GetProperty().SetSpecularPower(20); + + // An isosurface, or contour value of 1150 is known to correspond to the + // skin of the patient. Once generated, a vtkPolyDataNormals filter is + // is used to create normals for smooth surface shading during rendering. + // The triangle stripper is used to create triangle strips from the + // isosurface these render much faster on some systems. + vtkContourFilter boneExtractor = new vtkContourFilter(); + boneExtractor.SetInput(theImageData); + boneExtractor.SetValue(0, 1150); + vtkPolyDataNormals boneNormals = new vtkPolyDataNormals(); + boneNormals.SetInput(boneExtractor.GetOutput()); + boneNormals.SetFeatureAngle(60.0); + vtkStripper boneStripper = new vtkStripper(); + boneStripper.SetInput(boneNormals.GetOutput()); + vtkPolyDataMapper boneMapper = new vtkPolyDataMapper(); + boneMapper.SetInput(boneStripper.GetOutput()); + boneMapper.ScalarVisibilityOff(); + vtkActor bone = new vtkActor(); + bone.SetMapper(boneMapper); + bone.GetProperty().SetDiffuseColor(1, 1, .9412); + + // An outline provides context around the data. + vtkOutlineFilter outlineData = new vtkOutlineFilter(); + outlineData.SetInput(theImageData); + vtkPolyDataMapper mapOutline = new vtkPolyDataMapper(); + mapOutline.SetInput(outlineData.GetOutput()); + vtkActor outline = new vtkActor(); + outline.SetMapper(mapOutline); + outline.GetProperty().SetColor(0, 0, 0); + + // Now we are creating three orthogonal planes passing through the + // volume. Each plane uses a different texture map and therefore has + // diferent coloration. + + // Start by creatin a black/white lookup table. + vtkLookupTable bwLut = new vtkLookupTable(); + bwLut.SetTableRange(0, 2000); + bwLut.SetSaturationRange(0, 0); + bwLut.SetHueRange(0, 0); + bwLut.SetValueRange(0, 1); + bwLut.Build(); + + // Now create a lookup table that consists of the full hue circle (from + // HSV);. + vtkLookupTable hueLut = new vtkLookupTable(); + hueLut.SetTableRange(0, 2000); + hueLut.SetHueRange(0, 1); + hueLut.SetSaturationRange(1, 1); + hueLut.SetValueRange(1, 1); + hueLut.Build(); + + // Finally, create a lookup table with a single hue but having a range + // in the saturation of the hue. + vtkLookupTable satLut = new vtkLookupTable(); + satLut.SetTableRange(0, 2000); + satLut.SetHueRange(.6, .6); + satLut.SetSaturationRange(0, 1); + satLut.SetValueRange(1, 1); + satLut.Build(); + + // Create the first of the three planes. The filter vtkImageMapToColors + // maps the data through the corresponding lookup table created above. + // The vtkImageActor is a type of vtkProp and conveniently displays an + // image on a single quadrilateral plane. It does this using texture + // mapping and as a result is quite fast. (Note: the input image has to + // be unsigned char values, which the vtkImageMapToColors produces.); + // Note also that by specifying the DisplayExtent, the pipeline + // requests data of this extent and the vtkImageMapToColors only + // processes a slice of data. + vtkImageMapToColors saggitalColors = new vtkImageMapToColors(); + saggitalColors.SetInput(theImageData); + saggitalColors.SetLookupTable(bwLut); + vtkImageActor saggital = new vtkImageActor(); + saggital.SetInput(saggitalColors.GetOutput()); + saggital.SetDisplayExtent(32, 32, 0, 63, 0, 92); + + // Create the second (axial); plane of the three planes. We use the same + // approach as before except that the extent differs. + vtkImageMapToColors axialColors = new vtkImageMapToColors(); + axialColors.SetInput(theImageData); + axialColors.SetLookupTable(hueLut); + vtkImageActor axial = new vtkImageActor(); + axial.SetInput(axialColors.GetOutput()); + axial.SetDisplayExtent(0, 63, 0, 63, 46, 46); + + // Create the third (coronal); plane of the three planes. We use the same + // approach as before except that the extent differs. + vtkImageMapToColors coronalColors = new vtkImageMapToColors(); + coronalColors.SetInput(theImageData); + coronalColors.SetLookupTable(satLut); + vtkImageActor coronal = new vtkImageActor(); + coronal.SetInput(coronalColors.GetOutput()); + coronal.SetDisplayExtent(0, 63, 32, 32, 0, 92); + + // It is convenient to create an initial view of the data. The FocalPoint + // and Position form a vector direction. Later on (ResetCamera() method) + // this vector is used to position the camera to look at the data in + // this direction. + vtkCamera aCamera = new vtkCamera(); + aCamera.SetViewUp(0, 0, -1); + aCamera.SetPosition(0, 1, 0); + aCamera.SetFocalPoint(0, 0, 0); + aCamera.ComputeViewPlaneNormal(); + + // Actors are added to the renderer. An initial camera view is created. + // The Dolly() method moves the camera towards the FocalPoint, + // thereby enlarging the image. + renWin.GetRenderer().AddActor(saggital); + renWin.GetRenderer().AddActor(axial); + renWin.GetRenderer().AddActor(coronal); + renWin.GetRenderer().AddActor(outline); + renWin.GetRenderer().AddActor(skin); + renWin.GetRenderer().AddActor(bone); + + // Turn off bone for this example. + bone.VisibilityOff(); + + // Set skin to semi-transparent. + skin.GetProperty().SetOpacity(0.5); + + // An initial camera view is created. The Dolly() method moves + // the camera towards the FocalPoint, thereby enlarging the image. + renWin.GetRenderer().SetActiveCamera(aCamera); + renWin.GetRenderer().ResetCamera(); + aCamera.Dolly(1.5); + + // Set a background color for the renderer and set the size of the + // render window (expressed in pixels). + renWin.GetRenderer().SetBackground(1, 1, 1); + VtkPanelUtil.setSize(renWin, 640, 480); + + // Note that when camera movement occurs (as it does in the Dolly() + // method), the clipping planes often need adjusting. Clipping planes + // consist of two planes: near and far along the view direction. The + // near plane clips out objects in front of the plane the far plane + // clips out objects behind the plane. This way only what is drawn + // between the planes is actually rendered. + renWin.GetRenderer().ResetCameraClippingRange(); + + // Setup panel + setLayout(new BorderLayout()); + add(renWin, BorderLayout.CENTER); + } + + + + public vtkPanel getRenWin() { + return renWin; + } + + + public static void main(String s[]) { + if (s.length == 0){ + return; //need a filename here + } + File theFile = new File(s[0]); + //File theFile = new File("/Users/mmroden/Documents/MVSDownloadDirectory/Documents/1.2.840.113704.1.111.3384.1271766367.5/"); + AWTMedical3 panel = new AWTMedical3(theFile); + + JFrame frame = new JFrame("AWTMedical3"); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.getContentPane().add("Center", panel); + frame.pack(); + frame.setVisible(true); + } + +} diff --git a/gdcm/Utilities/VTK/Examples/Java/CMakeLists.txt b/gdcm/Utilities/VTK/Examples/Java/CMakeLists.txt new file mode 100644 index 0000000..6e714cb --- /dev/null +++ b/gdcm/Utilities/VTK/Examples/Java/CMakeLists.txt @@ -0,0 +1,51 @@ +set(classpath ${LIBRARY_OUTPUT_PATH}/vtkgdcm.jar${JavaProp_PATH_SEPARATOR}${LIBRARY_OUTPUT_PATH}/gdcm.jar${JavaProp_PATH_SEPARATOR}${VTK_JAVA_JAR}${JavaProp_PATH_SEPARATOR}${GDCM_VTK_JAVA_JAR}) + +set(classfilesdep) +set(examples + HelloVTKWorld + ReadSeriesIntoVTK + #AWTMedical3 + MPRViewer2 + ) +if(VTK_HAS_IMAGERESLICEMAPPER) + set(examples + ${examples} + MPRViewer + ) +endif() +if(VTK_HAS_SMARTVOLUMEMAPPER) + set(examples + ${examples} + MIPViewer + ) +endif() +foreach(example ${examples}) + add_custom_command( + OUTPUT ${EXECUTABLE_OUTPUT_PATH}/${example}.class + COMMAND ${Java_JAVAC_EXECUTABLE} ARGS -source 1.5 -target 1.5 -classpath "${classpath}" + ${CMAKE_CURRENT_SOURCE_DIR}/${example}.java -d ${EXECUTABLE_OUTPUT_PATH} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${example}.java + COMMENT "javac ${example}.java" + ) + list(APPEND classfilesdep ${EXECUTABLE_OUTPUT_PATH}/${example}.class) +endforeach() + +# 3. ok now add the target +add_custom_target(GDCMJavaVTKExample ALL + DEPENDS ${classfilesdep} + COMMENT "building gdcm java example" +) +add_dependencies(GDCMJavaVTKExample VTKGDCMJavaJar) + +if(BUILD_TESTING) + if(GDCM_DATA_ROOT) + #set_source_files_properties(${EXECUTABLE_OUTPUT_PATH}/${test}.class PROPERTIES RUNTIMEPATH "${EXECUTABLE_OUTPUT_PATH}") + set_source_files_properties(${EXECUTABLE_OUTPUT_PATH}/HelloVTKWorld.class PROPERTIES CLASSPATH "${EXECUTABLE_OUTPUT_PATH}/vtkgdcm.jar:${GDCM_VTK_JAVA_JAR}") + ADD_JAVA_TEST(TestHelloVTKWorldJava ${EXECUTABLE_OUTPUT_PATH}/HelloVTKWorld ${GDCM_DATA_ROOT}/012345.002.050.dcm ${GDCM_TEMP_DIRECTORY}/HelloVTKWorld.dcm) + set_source_files_properties(${EXECUTABLE_OUTPUT_PATH}/ReadSeriesIntoVTK.class PROPERTIES CLASSPATH "${EXECUTABLE_OUTPUT_PATH}/vtkgdcm.jar:${GDCM_VTK_JAVA_JAR}") + ADD_JAVA_TEST(TestReadSeriesIntoVTKJava ${EXECUTABLE_OUTPUT_PATH}/ReadSeriesIntoVTK) + #set_source_files_properties(${EXECUTABLE_OUTPUT_PATH}/AWTMedical3.class PROPERTIES CLASSPATH "${EXECUTABLE_OUTPUT_PATH}/vtkgdcm.jar:${GDCM_VTK_JAVA_JAR}") + #ADD_JAVA_TEST(TestAWTMedical3Java ${EXECUTABLE_OUTPUT_PATH}/AWTMedical3) + endif() +endif() diff --git a/gdcm/Utilities/VTK/Examples/Java/HelloVTKWorld.java b/gdcm/Utilities/VTK/Examples/Java/HelloVTKWorld.java new file mode 100644 index 0000000..cc047bb --- /dev/null +++ b/gdcm/Utilities/VTK/Examples/Java/HelloVTKWorld.java @@ -0,0 +1,96 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +// We are required to call the package 'vtk' eventhough I (MM) would have prefered +// an import statement along the line of: +// import vtkgdcm.*; +import vtk.*; + +/* + * Compilation: + * CLASSPATH=vtkgdcm.jar:/usr/share/java/vtk.jar javac HelloVTKWorld.java + * + * Usage: + * LD_LIBRARY_PATH=/usr/lib/jvm/java-6-openjdk/jre/lib/amd64/xawt:/usr/lib/jni:. CLASSPATH=/usr/share/java/vtk.jar:vtkgdcm.jar:gdcm.jar:. java HelloVTKWorld gdcmData/012345.002.050.dcm bla.dcm + * + */ +public class HelloVTKWorld +{ + static { + System.loadLibrary("vtkCommonJava"); + System.loadLibrary("vtkFilteringJava"); + System.loadLibrary("vtkIOJava"); + System.loadLibrary("vtkImagingJava"); + System.loadLibrary("vtkGraphicsJava"); + System.loadLibrary("vtkgdcmJava"); + try { + System.loadLibrary("vtkRenderingJava"); + } catch (Throwable e) { + System.out.println("cannot load vtkHybrid, skipping..."); + } + try { + System.loadLibrary("vtkHybridJava"); + } catch (Throwable e) { + System.out.println("cannot load vtkHybrid, skipping..."); + } + try { + System.loadLibrary("vtkVolumeRenderingJava"); + } catch (Throwable e) { + System.out.println("cannot load vtkVolumeRendering, skipping..."); + } + } + + public static void main(String[] args) + { + String filename = args[0]; + vtkGDCMImageReader reader = new vtkGDCMImageReader(); + reader.SetFileName( filename ); + reader.Update(); + + vtkMedicalImageProperties prop = reader.GetMedicalImageProperties(); + System.out.println( prop.GetPatientName() ); // + +// if( reader.GetImageFormat() == vtkgdcm.vtkgdcm.VTK_LUMINANCE ) // MONOCHROME2 +// { +// System.out.println( "Image is MONOCHROME2" ); // +// } + + // Just for fun, invert the direction cosines, output should reflect that: + vtkMatrix4x4 dircos = reader.GetDirectionCosines(); + dircos.Invert(); + + // We need to maintain in sync information stored in vtkMedicalImageProperties: + double[] cosines = new double[6]; + cosines[0] = dircos.GetElement(0,0); + cosines[1] = dircos.GetElement(1,0); + cosines[2] = dircos.GetElement(2,0); + cosines[3] = dircos.GetElement(0,1); + cosines[4] = dircos.GetElement(1,1); + cosines[5] = dircos.GetElement(2,1); + reader.GetMedicalImageProperties().SetDirectionCosine( cosines ); + + String outfilename = args[1]; + vtkGDCMImageWriter writer = new vtkGDCMImageWriter(); + writer.SetMedicalImageProperties( reader.GetMedicalImageProperties() ); + writer.SetDirectionCosines( dircos ); + writer.SetShift( reader.GetShift() ); + writer.SetScale( reader.GetScale() ); + writer.SetImageFormat( reader.GetImageFormat() ); + writer.SetFileName( outfilename ); + //writer.SetInputConnection( reader.GetOutputPort() ); // new + writer.SetInput( reader.GetOutput() ); // old + writer.Write(); + + System.out.println("Success reading: " + filename ); + } +} diff --git a/gdcm/Utilities/VTK/Examples/Java/MIPViewer.java b/gdcm/Utilities/VTK/Examples/Java/MIPViewer.java new file mode 100644 index 0000000..e79f620 --- /dev/null +++ b/gdcm/Utilities/VTK/Examples/Java/MIPViewer.java @@ -0,0 +1,189 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +import vtk.*; +import gdcm.*; +import java.io.File; +import java.awt.Canvas; + +/* + * Compilation: + * CLASSPATH=vtkgdcm.jar:/usr/share/java/vtk.jar javac MIPViewer.java + * + * Usage: + * LD_LIBRARY_PATH=/usr/lib/jvm/java-6-openjdk/jre/lib/amd64/xawt:/usr/lib/jni:. CLASSPATH=/usr/share/java/vtk.jar:vtkgdcm.jar:gdcm.jar:. java MIPViewer BRAINX + * + */ +public class MIPViewer extends Canvas +{ + static { + // VTK + System.loadLibrary("vtkCommonJava"); + System.loadLibrary("vtkFilteringJava"); + System.loadLibrary("vtkIOJava"); + System.loadLibrary("vtkImagingJava"); + System.loadLibrary("vtkGraphicsJava"); + System.loadLibrary("vtkRenderingJava"); + System.loadLibrary("vtkVolumeRenderingJava"); // vtkSmartVolumeMapper + System.loadLibrary("vtkWidgetsJava"); // vtkBoxWidget + // VTK-GDCM + System.loadLibrary("vtkgdcmJava"); + } + + static FilenamesType fns = new FilenamesType(); + + protected native int Lock(); + + protected native int UnLock(); + + public static void process(String path) + { + fns.add( path ); + } + + // Process only files under dir + public static void visitAllFiles(File dir) + { + if (dir.isDirectory()) + { + String[] children = dir.list(); + for (int i=0; iSetFilename( "test.dcm" ); +$reader->Update(); + +$prop = $reader->GetMedicalImageProperties(); + +$n = $prop->GetNumberOfWindowLevelPresets(); +print( "coudou" ); +//print( "coucou %d", $n ); +if( $n != 0 ) +{ +// Take the first one by default: +$w = 0; +$l = 0; +$a = $prop->GetNthWindowLevelPreset(0); +print( $a[0] ); +//$windowlevel->SetWindow( wl[0] ); +//$windowlevel->SetLevel( wl[1] ); +} + +/* +$renderer = vtkRenderer::c_New(); + +$windowlevel = vtkImageMapToWindowLevelColors::c_New(); +$windowlevel->SetInput( $reader->GetOutput() ); + +$actor = vtkImageActor::c_New(); +$actor->SetInput( $windowlevel->GetOutput() ); + +$renderer->AddActor( actor ); + +$renWin = vtkRenderWindow::c_New(); +$renWin->OffScreenRenderingOn(); +$renWin->AddRenderer($renderer); + +$renWin->Render(); + +$w2if = vtkWindowToImageFilter::c_New(); +$w2if->SetInput ( $renWin ); + +$wr = vtkPNGWriter::c_New(); +$wr->SetInput( $w2if->GetOutput() ); +$wr->SetFileName ( "offscreenimage.png" ); +$wr->Write(); +*/ + +?> diff --git a/gdcm/Utilities/VTK/Examples/Python/CastConvertPhilips.py b/gdcm/Utilities/VTK/Examples/Python/CastConvertPhilips.py new file mode 100644 index 0000000..a6e5150 --- /dev/null +++ b/gdcm/Utilities/VTK/Examples/Python/CastConvertPhilips.py @@ -0,0 +1,185 @@ +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +""" +Usage: + + python --public /path/to/directory/ +or + python --private /path/to/directory/ + + python --public --extension bak /path/to/directory/ + +rename -f 's/\.bak$//' *.bak + +TODO: +http://docs.python.org/library/optparse.html#module-optparse +""" + +import vtkgdcm +import vtk +import sys +import gdcm + +def ProcessOneFilePublic(filename, outfilename, tmpfile): + gdcm.ImageHelper.SetForceRescaleInterceptSlope(True) + vtkreader = vtkgdcm.vtkGDCMImageReader() + vtkreader.SetFileName( filename ) + vtkreader.Update() + + cast = vtk.vtkImageCast() + cast.SetInput( vtkreader.GetOutput() ) + cast.SetOutputScalarTypeToUnsignedShort() + + # vtkGDCMImageWriter does not support Sequence, so let's write a tmp file first: + # Some operation will actually be discarded (we simply need a temp storage) + vtkwriter = vtkgdcm.vtkGDCMImageWriter() + vtkwriter.SetFileName( tmpfile ) + vtkwriter.SetMedicalImageProperties( vtkreader.GetMedicalImageProperties() ) + vtkwriter.SetDirectionCosines( vtkreader.GetDirectionCosines() ) + print "Format:",vtkreader.GetImageFormat() + vtkwriter.SetImageFormat( vtkreader.GetImageFormat() ) + vtkwriter.SetInput( cast.GetOutput() ) + #vtkwriter.Update() + vtkwriter.Write() + + # ok now rewrite the exact same file as the original (keep all info) + # but use the Pixel Data Element from the written file + tmpreader = gdcm.ImageReader() + tmpreader.SetFileName( tmpfile ) + if not tmpreader.Read(): + sys.exit(1) + + reader = gdcm.Reader() + reader.SetFileName( filename ) + if not reader.Read(): + sys.exit(1) + + # Make sure to remove Slope/Rescale to avoid re-execution + ds = reader.GetFile().GetDataSet() + tags = [ + gdcm.Tag(0x0028,0x1052), + gdcm.Tag(0x0028,0x1053), + gdcm.Tag(0x0028,0x1053), + ] + for tag in tags: + ds.Remove( tag ) + + writer = gdcm.ImageWriter() + writer.SetFileName( outfilename ) + # Pass image from vtk written file + writer.SetImage( tmpreader.GetImage() ) + # pass dataset from initial 'reader' + writer.SetFile( reader.GetFile() ) + if not writer.Write(): + sys.exit(1) + +def ProcessOneFilePrivate(filename, outfilename, tmpfile): + vtkreader = vtkgdcm.vtkGDCMImageReader() + vtkreader.SetFileName( filename ) + vtkreader.Update() + + + # (2005,1409) DS 4 0.0 + # (2005,140a) DS 16 1.52283272283272 + + # (2005,0014) LO 26 Philips MR Imaging DD 005 + tag1 = gdcm.PrivateTag(0x2005,0x09,"Philips MR Imaging DD 005") + tag2 = gdcm.PrivateTag(0x2005,0x0a,"Philips MR Imaging DD 005") + + + + # Need to access some private tags, reread the file (for now): + reader = gdcm.Reader() + reader.SetFileName( filename ) + if not reader.Read(): + sys.exit(1) + + ds = reader.GetFile().GetDataSet() + + el1 = ds.GetDataElement( tag1 ) + el2 = ds.GetDataElement( tag2 ) + + + #pf = gdcm.PythonFilter() + #pf.SetFile( reader.GetFile() ) + #print el1.GetTag() + + print el1.GetByteValue() + v1 = eval(el1.GetByteValue().GetBuffer()) + print el2.GetByteValue() + v2 = eval(el2.GetByteValue().GetBuffer()) + + print v1 + shift = v1 + print v2 + scale = v2 + + ss = vtk.vtkImageShiftScale() + ss.SetInput( vtkreader.GetOutput() ) + # because VTK image shift / scale convention is inverted from DICOM make sure shift is 0 + assert shift == 0 + ss.SetShift( shift ) + ss.SetScale( scale ) + ss.SetOutputScalarTypeToUnsignedShort () + ss.Update() + + # vtkGDCMImageWriter does not support Sequence, so let's write a tmp file first: + # Some operation will actually be discarded (we simply need a temp storage) + vtkwriter = vtkgdcm.vtkGDCMImageWriter() + vtkwriter.SetFileName( tmpfile ) + vtkwriter.SetMedicalImageProperties( vtkreader.GetMedicalImageProperties() ) + vtkwriter.SetDirectionCosines( vtkreader.GetDirectionCosines() ) + vtkwriter.SetImageFormat( reader.GetImageFormat() ) + # do not pass shift/scale again + vtkwriter.SetInput( ss.GetOutput() ) + #vtkwriter.Update() + vtkwriter.Write() + + # ok now rewrite the exact same file as the original (keep all info) + # but use the Pixel Data Element from the written file + tmpreader = gdcm.ImageReader() + tmpreader.SetFileName( tmpfile ) + if not tmpreader.Read(): + sys.exit(1) + + writer = gdcm.ImageWriter() + writer.SetFileName( outfilename ) + # Pass image from vtk written file + writer.SetImage( tmpreader.GetImage() ) + # pass dataset from initial 'reader' + writer.SetFile( reader.GetFile() ) + if not writer.Write(): + sys.exit(1) + +if __name__ == "__main__": + + gdcm.Trace.DebugOff() + gdcm.Trace.WarningOff() + #filename = sys.argv[1] + #outfilename = sys.argv[2] + tmpfile = "/tmp/philips_rescaled.dcm" + #ProcessOneFile( filename, outfilename, tmpfile ) + rescaletype = sys.argv[1] + assert rescaletype == "--public" or rescaletype == "--private" + dirname = sys.argv[2] + d = gdcm.Directory() + d.Load( dirname ) + + for f in d.GetFilenames(): + #print f + ProcessOneFilePublic( f, f + ".bak", tmpfile ) + + +print "success" diff --git a/gdcm/Utilities/VTK/Examples/Python/headsq2dcm.py b/gdcm/Utilities/VTK/Examples/Python/headsq2dcm.py new file mode 100644 index 0000000..54305d1 --- /dev/null +++ b/gdcm/Utilities/VTK/Examples/Python/headsq2dcm.py @@ -0,0 +1,43 @@ +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +""" +Usage: + python headsq2dcm.py -D /path/to/VTKData +""" + +import vtk +import vtkgdcm +from vtk.util.misc import vtkGetDataRoot +VTK_DATA_ROOT = vtkGetDataRoot() + +reader = vtk.vtkVolume16Reader() +reader.SetDataDimensions(64, 64) +reader.SetDataByteOrderToLittleEndian() +reader.SetFilePrefix(VTK_DATA_ROOT + "/Data/headsq/quarter") +reader.SetImageRange(1, 93) +reader.SetDataSpacing(3.2, 3.2, 1.5) + +cast = vtk.vtkImageCast() +cast.SetInput( reader.GetOutput() ) +cast.SetOutputScalarTypeToUnsignedChar() + +# By default this is creating a Multiframe Grayscale Word Secondary Capture Image Storage +writer = vtkgdcm.vtkGDCMImageWriter() +writer.SetFileName( "headsq.dcm" ) +writer.SetInput( reader.GetOutput() ) +# cast -> Multiframe Grayscale Byte Secondary Capture Image Storage +#writer.SetInput( cast.GetOutput() ) +writer.SetFileDimensionality( 3 ) +writer.Write() diff --git a/gdcm/Utilities/VTK/GDCMImageGUI.xml b/gdcm/Utilities/VTK/GDCMImageGUI.xml new file mode 100644 index 0000000..667951e --- /dev/null +++ b/gdcm/Utilities/VTK/GDCMImageGUI.xml @@ -0,0 +1,17 @@ + + + + + diff --git a/gdcm/Utilities/VTK/GDCMImageReader.xml b/gdcm/Utilities/VTK/GDCMImageReader.xml new file mode 100644 index 0000000..ba3d884 --- /dev/null +++ b/gdcm/Utilities/VTK/GDCMImageReader.xml @@ -0,0 +1,43 @@ + + + + + + + The GDCM Image reader reads DICOM files containing image data. The expected file extensions are .dcm. + + + + + This property specifies the file name for the GDCM Image reader. + + + + + + + + + + + + diff --git a/gdcm/Utilities/VTK/JavaDependencies.cmake.in b/gdcm/Utilities/VTK/JavaDependencies.cmake.in new file mode 100644 index 0000000..d60b476 --- /dev/null +++ b/gdcm/Utilities/VTK/JavaDependencies.cmake.in @@ -0,0 +1,4 @@ +# This file is automatically generated by CMake VTK_WRAP_JAVA +set(VTK_JAVA_DEPENDENCIES ${VTK_JAVA_DEPENDENCIES} +@VTK_JAVA_DEPENDENCIES_FILE@ +) diff --git a/gdcm/Utilities/VTK/MummySettings.xml.in b/gdcm/Utilities/VTK/MummySettings.xml.in new file mode 100644 index 0000000..5257c32 --- /dev/null +++ b/gdcm/Utilities/VTK/MummySettings.xml.in @@ -0,0 +1,196 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +@AVDN_EXTRA_EXCLUDE_CLASSES_XML@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdcm/Utilities/VTK/Testing/CMakeLists.txt b/gdcm/Utilities/VTK/Testing/CMakeLists.txt new file mode 100644 index 0000000..0b1ac49 --- /dev/null +++ b/gdcm/Utilities/VTK/Testing/CMakeLists.txt @@ -0,0 +1,11 @@ +subdirs(Cxx) + +if(VTK_WRAP_PYTHON) + subdirs(Python) +endif() + +if(GDCM_WRAP_JAVA) + if(VTK_WRAP_JAVA) + subdirs(Java) + endif() +endif() diff --git a/gdcm/Utilities/VTK/Testing/Cxx/CMakeLists.txt b/gdcm/Utilities/VTK/Testing/Cxx/CMakeLists.txt new file mode 100644 index 0000000..bb183dc --- /dev/null +++ b/gdcm/Utilities/VTK/Testing/Cxx/CMakeLists.txt @@ -0,0 +1,86 @@ +# Define the tests for vtk-gdcm +# vtkGDCM +set(VTK_GDCM_TEST_SRCS + TestvtkGDCMImageReader + TestvtkGDCMImageReader4 + TestvtkGDCMImageReaderIsLossy + TestvtkGDCMImageWriterIsLossy + #TestvtkImageChangeInformation + #TestvtkGDCMImageActor + #TestvtkGDCMImageViewer +) +if( "${VTK_MAJOR_VERSION}.${VTK_MINOR_VERSION}" GREATER 4.5 ) + set(VTK_GDCM_TEST_SRCS + ${VTK_GDCM_TEST_SRCS} + TestvtkGDCMImageWriter1 + TestvtkGDCMImageWriter2 + TestvtkGDCMThreadedImageReader2 + TestvtkGDCMMetaImageWriter + ) +endif() + +if( "${VTK_MAJOR_VERSION}.${VTK_MINOR_VERSION}" GREATER 6.0 ) + set(VTK_GDCM_TEST_SRCS + ${VTK_GDCM_TEST_SRCS} + TestvtkGDCMImageReader2_1 + TestvtkGDCMImageReader2_2 + TestvtkGDCMMetaImageWriter2 + ) +endif() + +# Need gdcmData +if(GDCM_DATA_ROOT) + set(VTK_GDCM_TEST_SRCS + ${VTK_GDCM_TEST_SRCS} + TestvtkGDCMImageReader1 + ) +endif() +# Need gdcmDataExtra +if(GDCM_DATA_EXTRA_ROOT) + set(VTK_GDCM_TEST_SRCS + ${VTK_GDCM_TEST_SRCS} + TestvtkGDCMImageReader3 + TestvtkGDCMPolyDataReader + ) +endif() + +if(VTK_USE_RENDERING) + if(GDCM_HAVE_PTHREAD_H AND CMAKE_USE_PTHREADS) + set(VTK_GDCM_TEST_SRCS + ${VTK_GDCM_TEST_SRCS} + TestvtkGDCMThreadedImageReader + ) + endif() +endif() + +# Add the include paths +include_directories( + "${GDCM_SOURCE_DIR}/Utilities/VTK" + "${GDCM_BINARY_DIR}/Testing/Source/Data" # for gdcmDataImages.h + ) + +create_test_sourcelist(vtkGDCMTests gdcmvtkGDCMTests.cxx ${VTK_GDCM_TEST_SRCS} + EXTRA_INCLUDE gdcmTestDriver.h + ) +add_executable(gdcmvtkGDCMTests ${vtkGDCMTests}) +target_link_libraries(gdcmvtkGDCMTests ${VTKGDCM_NAME} gdcmMSFF) +if(VTK_USE_RENDERING) + if( "${VTK_MAJOR_VERSION}.${VTK_MINOR_VERSION}" LESS 4.5 ) + target_link_libraries(gdcmvtkGDCMTests vtkRendering) + elseif( "${VTK_MAJOR_VERSION}.${VTK_MINOR_VERSION}" LESS 6.0 ) + target_link_libraries(gdcmvtkGDCMTests vtkVolumeRendering) + endif() +endif() +# VTK 6.0 does not set VTK_USE_RENDERING anymore ? +if( "${VTK_MAJOR_VERSION}.${VTK_MINOR_VERSION}" GREATER 6.0 ) + target_link_libraries(gdcmvtkGDCMTests ${vtkgdcm_LIBS}) + target_link_libraries(gdcmvtkGDCMTests vtkIOLegacy vtkCommonCore) +endif() + +# Need full path to executable: +set(GDCM_VTK_GDCM_TESTS "${EXECUTABLE_OUTPUT_PATH}/gdcmvtkGDCMTests") + +# Loop over files and create executables +foreach(name ${VTK_GDCM_TEST_SRCS}) + add_test(NAME ${name} COMMAND ${GDCM_VTK_GDCM_TESTS} ${name}) +endforeach() diff --git a/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMImageActor.cxx b/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMImageActor.cxx new file mode 100644 index 0000000..4d41ce9 --- /dev/null +++ b/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMImageActor.cxx @@ -0,0 +1,80 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkGDCMImageReader.h" + +#include "vtkPNGWriter.h" +#include "vtkImageData.h" +#include "vtkImageActor.h" +#include "vtkRenderWindowInteractor.h" +#include "vtkRenderWindow.h" +#include "vtkRenderer.h" +#include "vtkInteractorStyleImage.h" +#include + +#include "gdcmTesting.h" + +int TestvtkGDCMReadImageActor(const char *filename) +{ + vtkGDCMImageReader *reader = vtkGDCMImageReader::New(); + //reader->CanReadFile( filename ); + std::cerr << "Reading : " << filename << std::endl; + reader->SetFileName( filename ); + reader->Update(); + + //reader->GetOutput()->Print( cout ); + + vtkImageActor *ia = vtkImageActor::New(); + ia->SetInput( reader->GetOutput() ); + + // Create the RenderWindow, Renderer and both Actors + vtkRenderer *ren1 = vtkRenderer::New(); + vtkRenderWindow *renWin = vtkRenderWindow::New(); + renWin->AddRenderer (ren1); + vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New(); + iren->SetRenderWindow (renWin); + + // Add the actors to the renderer, set the background and size + ren1->AddActor (ia); + + vtkInteractorStyleImage *style = vtkInteractorStyleImage::New(); + iren->SetInteractorStyle( style ); + style->Delete(); + iren->Initialize(); + iren->Start(); + + reader->Delete(); + + return 0; +} + +int TestvtkGDCMImageActor(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestvtkGDCMReadImageActor(filename); + } + + // else + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestvtkGDCMReadImageActor( filename ); + ++i; + } + + return r; +} diff --git a/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMImageReader.cxx b/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMImageReader.cxx new file mode 100644 index 0000000..2ee3d7d --- /dev/null +++ b/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMImageReader.cxx @@ -0,0 +1,114 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkGDCMImageReader.h" +#include "vtkMedicalImageProperties.h" + +#include "vtkPNGWriter.h" +#include "vtkImageData.h" +#include "vtkStringArray.h" + +#include "gdcmFilename.h" +#include "gdcmTesting.h" +#include "gdcmSystem.h" +#include "gdcmTrace.h" +#include "gdcmDirectory.h" + +static int TestvtkGDCMImageRead(const char *filename, bool verbose) +{ + if( verbose ) + std::cerr << "Reading : " << filename << std::endl; + + vtkGDCMImageReader *reader = vtkGDCMImageReader::New(); + if( gdcm::System::FileIsDirectory( filename ) ) + { + verbose = false; + gdcm::Directory d; + d.Load( filename ); + gdcm::Directory::FilenamesType l = d.GetFilenames(); + const size_t nfiles = l.size(); + vtkStringArray *sarray = vtkStringArray::New(); + for(unsigned int i = 0; i < nfiles; ++i) + { + sarray->InsertNextValue( l[i] ); + } + assert( sarray->GetNumberOfValues() == (int)nfiles ); + reader->SetFileNames( sarray ); + sarray->Delete(); + } + else + { + reader->SetFileName( filename ); + } + + //int canread = reader->CanReadFile( filename ); + reader->Update(); + + if( verbose ) + { + reader->GetOutput()->Print( cout ); + reader->GetMedicalImageProperties()->Print( cout ); + } + + if( verbose && false ) + { + // Create directory first: + const char subdir[] = "TestvtkGDCMImageReader"; + std::string tmpdir = gdcm::Testing::GetTempDirectory( subdir ); + if( !gdcm::System::FileIsDirectory( tmpdir.c_str() ) ) + { + gdcm::System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + std::string pngfile = gdcm::Testing::GetTempFilename( filename, subdir ); + + vtkPNGWriter *writer = vtkPNGWriter::New(); +#if (VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 ) + writer->SetInputConnection( reader->GetOutputPort() ); +#else + writer->SetInput( reader->GetOutput() ); +#endif + pngfile += ".png"; + writer->SetFileName( pngfile.c_str() ); + //writer->Write(); + writer->Delete(); + cout << "Wrote PNG output into:" << pngfile << std::endl; + } + + reader->Delete(); + return 0; +} + +int TestvtkGDCMImageReader(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestvtkGDCMImageRead(filename, true); + } + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + gdcm::Trace::ErrorOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestvtkGDCMImageRead( filename, false ); + ++i; + } + + return r; +} diff --git a/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMImageReader1.cxx b/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMImageReader1.cxx new file mode 100644 index 0000000..21fa6e3 --- /dev/null +++ b/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMImageReader1.cxx @@ -0,0 +1,170 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkGDCMImageReader.h" +#include "vtkGDCMImageWriter.h" +#include "vtkStringArray.h" +#include "vtkImageData.h" +#include "vtkImageChangeInformation.h" + +#include "gdcmFilename.h" +#include "gdcmTesting.h" +#include "gdcmSystem.h" +#include "gdcmTrace.h" +#include "gdcmDirectory.h" +#include "gdcmIPPSorter.h" +#include "gdcmFilenameGenerator.h" + +#ifndef vtkFloatingPointType +#define vtkFloatingPointType float +#endif +/* + * Test to show the pipeline for + * IPPSorter -> vtkGDCMImageReader -> vtkImageChangeInformation + */ +int TestvtkGDCMImageReader1(int , char *[]) +{ + const char *directory = gdcm::Testing::GetDataRoot(); + std::vector filenames; + std::string file0 = std::string(directory) + "/SIEMENS_MAGNETOM-12-MONO2-FileSeq0.dcm"; + std::string file1 = std::string(directory) + "/SIEMENS_MAGNETOM-12-MONO2-FileSeq1.dcm"; + std::string file2 = std::string(directory) + "/SIEMENS_MAGNETOM-12-MONO2-FileSeq2.dcm"; + std::string file3 = std::string(directory) + "/SIEMENS_MAGNETOM-12-MONO2-FileSeq3.dcm"; + filenames.push_back( file1 ); + filenames.push_back( file3 ); + filenames.push_back( file2 ); + filenames.push_back( file0 ); + gdcm::IPPSorter s; + s.SetComputeZSpacing( true ); + s.SetZSpacingTolerance( 1e-10 ); + bool b = s.Sort( filenames ); + if( !b ) + { + std::cerr << "Failed to sort:" << directory << std::endl; + return 1; + } + std::cout << "Sorting succeeded:" << std::endl; + s.Print( std::cout ); + + std::cout << "Found z-spacing:" << std::endl; + std::cout << s.GetZSpacing() << std::endl; + double ippzspacing = s.GetZSpacing(); + if( ippzspacing != 5.5 ) + { + // This should be test in another specific test ... + return 1; + } + + const std::vector & sorted = s.GetFilenames(); + vtkGDCMImageReader * reader = vtkGDCMImageReader::New(); + vtkStringArray *files = vtkStringArray::New(); + std::vector< std::string >::const_iterator it = sorted.begin(); + for( ; it != sorted.end(); ++it) + { + const std::string &f = *it; + files->InsertNextValue( f.c_str() ); + } + reader->SetFileNames( files ); + reader->Update(); + + const vtkFloatingPointType *spacing = reader->GetOutput()->GetSpacing(); + std::cout << spacing[0] << "," << spacing[1] << "," << spacing[2] << std::endl; + int ret = 0; + if( spacing[2] != 0.5 ) + { + // Spacing Between Slice is set to 0.5 in those files + ret++; + } + + // try again but this time we want 5.5 to be the spacing + vtkGDCMImageReader * reader2 = vtkGDCMImageReader::New(); + reader2->SetDataSpacing( spacing[0], spacing[1], ippzspacing ); + reader2->SetFileNames( files ); + //reader2->FileLowerLeftOn(); // TODO + reader2->Update(); + const vtkFloatingPointType *spacing2 = reader2->GetOutput()->GetSpacing(); + std::cout << spacing2[0] << "," << spacing2[1] << "," << spacing2[2] << std::endl; + // You need to use this class to preserve spacing + // across pipeline re-execution + vtkImageChangeInformation *change = vtkImageChangeInformation::New(); +#if (VTK_MAJOR_VERSION >= 6) + change->SetInputConnection( reader2->GetOutputPort() ); +#else + change->SetInput( reader2->GetOutput() ); +#endif + change->SetOutputSpacing( spacing2[0], spacing2[1], ippzspacing ); + change->Update(); + + const vtkFloatingPointType *spacing3 = change->GetOutput()->GetSpacing(); + std::cout << spacing3[0] << "," << spacing3[1] << "," << spacing3[2] << std::endl; + if( spacing3[2] != 5.5 ) + { + ret++; + } + + // Ok Let's try to write this volume back to disk: + vtkGDCMImageWriter *writer = vtkGDCMImageWriter::New(); +#if (VTK_MAJOR_VERSION >= 6) + writer->SetInputData( change->GetOutput() ); +#else + writer->SetInput( change->GetOutput() ); +#endif + writer->SetFileDimensionality( 2 ); + //writer->SetFileLowerLeft( reader2->GetFileLowerLeft() ); // TODO + writer->SetMedicalImageProperties( reader2->GetMedicalImageProperties() ); // nasty + writer->SetDirectionCosines( reader2->GetDirectionCosines() ); + writer->SetImageFormat( reader2->GetImageFormat() ); + const char subdir[] = "TestvtkGDCMImageReader1"; + std::string tmpdir = gdcm::Testing::GetTempDirectory(subdir); + if( !gdcm::System::FileIsDirectory( tmpdir.c_str() ) ) + { + gdcm::System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + + tmpdir += "/"; + const char tfilename[] = "SIEMENS_MAGNETOM-12-MONO2-FileSeq%01d.dcm"; + tmpdir += tfilename; + gdcm::FilenameGenerator fg; + fg.SetPattern( tmpdir.c_str() ); + fg.SetNumberOfFilenames( files->GetNumberOfValues() ); + bool bb = fg.Generate(); + if( !bb ) + { + std::cerr << "FilenameGenerator::Generate failed" << std::endl; + return 1; + } + if( !fg.GetNumberOfFilenames() ) + { + std::cerr << "No filenames generated" << std::endl; + return 1; + } + vtkStringArray *wfilenames = vtkStringArray::New(); + for(unsigned int i = 0; i < fg.GetNumberOfFilenames(); ++i) + { + wfilenames->InsertNextValue( fg.GetFilename(i) ); + std::cerr << fg.GetFilename(i) << std::endl; + } + assert( (gdcm::FilenameGenerator::SizeType)wfilenames->GetNumberOfValues() == fg.GetNumberOfFilenames() ); + writer->SetFileNames( wfilenames ); + wfilenames->Delete(); + writer->Write(); + + change->Delete(); + reader->Delete(); + reader2->Delete(); + writer->Delete(); + files->Delete(); + + return ret; +} diff --git a/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMImageReader2_1.cxx b/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMImageReader2_1.cxx new file mode 100644 index 0000000..5a10354 --- /dev/null +++ b/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMImageReader2_1.cxx @@ -0,0 +1,110 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkGDCMImageReader2.h" +#include "vtkMedicalImageProperties.h" + +#include "vtkPNGWriter.h" +#include "vtkImageData.h" +#include "vtkStringArray.h" + +#include "gdcmFilename.h" +#include "gdcmTesting.h" +#include "gdcmSystem.h" +#include "gdcmTrace.h" +#include "gdcmDirectory.h" + +static int TestvtkGDCMImageRead(const char *filename, bool verbose) +{ + if( verbose ) + std::cerr << "Reading : " << filename << std::endl; + + vtkGDCMImageReader2 *reader = vtkGDCMImageReader2::New(); + if( gdcm::System::FileIsDirectory( filename ) ) + { + verbose = false; + gdcm::Directory d; + d.Load( filename ); + gdcm::Directory::FilenamesType l = d.GetFilenames(); + const size_t nfiles = l.size(); + vtkStringArray *sarray = vtkStringArray::New(); + for(unsigned int i = 0; i < nfiles; ++i) + { + sarray->InsertNextValue( l[i] ); + } + assert( sarray->GetNumberOfValues() == (int)nfiles ); + reader->SetFileNames( sarray ); + sarray->Delete(); + } + else + { + reader->SetFileName( filename ); + } + + //int canread = reader->CanReadFile( filename ); + reader->Update(); + + if( verbose ) + { + reader->GetOutput()->Print( cout ); + reader->GetMedicalImageProperties()->Print( cout ); + } + + if( verbose && false ) + { + // Create directory first: + const char subdir[] = "TestvtkGDCMImageReader2_1"; + std::string tmpdir = gdcm::Testing::GetTempDirectory( subdir ); + if( !gdcm::System::FileIsDirectory( tmpdir.c_str() ) ) + { + gdcm::System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + std::string pngfile = gdcm::Testing::GetTempFilename( filename, subdir ); + + vtkPNGWriter *writer = vtkPNGWriter::New(); + writer->SetInputConnection( reader->GetOutputPort() ); + pngfile += ".png"; + writer->SetFileName( pngfile.c_str() ); + //writer->Write(); + writer->Delete(); + cout << "Wrote PNG output into:" << pngfile << std::endl; + } + + reader->Delete(); + return 0; +} + +int TestvtkGDCMImageReader2_1(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestvtkGDCMImageRead(filename, true); + } + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + gdcm::Trace::ErrorOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestvtkGDCMImageRead( filename, false ); + ++i; + } + + return r; +} diff --git a/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMImageReader2_2.cxx b/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMImageReader2_2.cxx new file mode 100644 index 0000000..fae5295 --- /dev/null +++ b/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMImageReader2_2.cxx @@ -0,0 +1,117 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkGDCMImageReader2.h" +#include "vtkMedicalImageProperties.h" + +#include "vtkInformation.h" +#include "vtkStreamingDemandDrivenPipeline.h" +#include "vtkStringArray.h" +// DEBUG +#include "vtkImageColorViewer.h" +#include "vtkRenderWindowInteractor.h" + +#include "gdcmSystem.h" +#include "gdcmTesting.h" +#include "gdcmDirectory.h" + +static int TestvtkGDCMImageRead(const char *filename, bool verbose) +{ +// if( verbose ) + std::cerr << "Reading : " << filename << std::endl; + vtkGDCMImageReader2 *reader = vtkGDCMImageReader2::New(); + if( gdcm::System::FileIsDirectory( filename ) ) + { + gdcm::Directory d; + d.Load( filename ); + gdcm::Directory::FilenamesType l = d.GetFilenames(); + const size_t nfiles = l.size(); + vtkStringArray *sarray = vtkStringArray::New(); + for(unsigned int i = 0; i < nfiles; ++i) + { + sarray->InsertNextValue( l[i] ); + } + assert( sarray->GetNumberOfValues() == (int)nfiles ); + reader->SetFileNames( sarray ); + sarray->Delete(); + } + else + { + reader->SetFileName( filename ); + } + + reader->UpdateInformation(); + if( reader->GetErrorCode() ) + { + return 1; + } + int wext[6]; + reader->GetOutputInformation(0)->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), wext); + //reader->GetOutput()->Print( std::cout ); + const int mid = (wext[5] - wext[0]) / 2; + wext[4] = wext[5] = mid; + reader->SetUpdateExtent( wext ); + //reader->Update(); + int ret = reader->GetExecutive()->Update(); + if( !ret ) + { + std::cerr << "Problem with: " << filename << std::endl; + } + + if( verbose ) + { + reader->GetOutput()->Print( cout ); + reader->GetMedicalImageProperties()->Print( cout ); + } + + if( 0 ) + { + vtkImageColorViewer *viewer = vtkImageColorViewer::New(); + viewer->SetInputConnection( reader->GetOutputPort() ); + + vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New(); + + viewer->SetupInteractor( iren ); + viewer->Render(); + + iren->Initialize(); + iren->Start(); + } + + reader->Delete(); + return ret; +} + +int TestvtkGDCMImageReader2_2(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestvtkGDCMImageRead(filename, true); + } + + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + gdcm::Trace::ErrorOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestvtkGDCMImageRead( filename, false ); + ++i; + } + + return r; + +} diff --git a/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMImageReader3.cxx b/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMImageReader3.cxx new file mode 100644 index 0000000..b6a6469 --- /dev/null +++ b/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMImageReader3.cxx @@ -0,0 +1,163 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkGDCMImageReader.h" +#include "vtkImageData.h" +#include "vtkStringArray.h" + +#include "gdcmIPPSorter.h" +#include "gdcmFilename.h" +#include "gdcmTesting.h" +#include "gdcmSystem.h" +#include "gdcmTrace.h" +#include "gdcmDirectory.h" +#include "gdcmScanner.h" + +#include + +/* + * There is special case we need to handle here: + * What if the Series we are trying to read contained a changing shift/scale ? + */ + +int TestvtkGDCMImageRead3(const char *dir, const char *studyuid) +{ + std::cout << "Working on : " << dir << std::endl; + int ret = 0; + gdcm::Directory d; + d.Load( dir ); + const gdcm::Directory::FilenamesType &l1 = d.GetFilenames(); + const size_t nfiles = l1.size(); (void)nfiles; + + // Sub-select only the DICOM files in this directory: + gdcm::Scanner s; + const gdcm::Tag t1(0x0020,0x000d); // Study Instance UID + const gdcm::Tag t2(0x0020,0x000e); // Series Instance UID + const gdcm::Tag t3(0x0028,0x1052); // Rescale Intercept + const gdcm::Tag t4(0x0028,0x1053); // Rescale Slope + s.AddTag( t1 ); + s.AddTag( t2 ); + s.AddTag( t3 ); + s.AddTag( t4 ); + bool b = s.Scan( d.GetFilenames() ); + if( !b ) + { + std::cerr << "Scanner failed" << std::endl; + return 1; + } + //s.Print( std::cout ); + //std::cout << dir1 << std::endl; + //gdcm::Scanner::ValuesType const &v = s.GetValues(); + //std::cout << v.size() << std::endl; + //std::copy(v.begin(), v.end(), + // std::ostream_iterator(std::cout, "\n")); + + + // Let take all the following files and pretend there are part of the + // same Series: + // (0020,000d) UI [1.3.46.670589.11.30.6.106253130282775287] # 40, 1 StudyInstanceUID + // ... footnote : they are part of the same Study, but separate Series + gdcm::Directory::FilenamesType keys = s.GetKeys(); + gdcm::Directory::FilenamesType::const_iterator it = keys.begin(); + + std::vector wholebuffer; + vtkStringArray *sarray = vtkStringArray::New(); + for(; it != keys.end() /*&& i < 2*/; ++it) + { + const char *filename = it->c_str(); + assert( s.IsKey( filename ) ); + const gdcm::Tag &reftag = t1; + const char *value = s.GetValue( filename, reftag ); + if( value && strcmp( value, studyuid ) == 0 ) + { + //std::cout << "file: " << filename << std::endl; + sarray->InsertNextValue( filename ); + + // Read each file + vtkGDCMImageReader *singlereader = vtkGDCMImageReader::New(); + singlereader->SetFileName( filename ); + singlereader->Update(); + vtkImageData* img = singlereader->GetOutput(); + int ssize = img->GetScalarSize(); + vtkIdType npts = img->GetNumberOfPoints(); + char * ptr = (char*)img->GetScalarPointer(); + //std::vector buffer(ptr, ptr+npts*ssize); + wholebuffer.insert(wholebuffer.end(), ptr, ptr+npts*ssize); + singlereader->Delete(); + } + } + std::cout << "Found " << sarray->GetSize() << " files belonging to StudyUID: " << studyuid << std::endl; + vtkGDCMImageReader *reader = vtkGDCMImageReader::New(); + reader->SetFileNames( sarray ); + sarray->Delete(); + + reader->Update(); + + vtkImageData* img = reader->GetOutput(); + size_t ssize = img->GetScalarSize(); + vtkIdType npts = img->GetNumberOfPoints(); + char * ptr = (char*)img->GetScalarPointer(); + if( wholebuffer.size() != npts * ssize || wholebuffer.empty() ) + { + std::cerr << "Something went terribly wrong" << std::endl; + ret = 1; + } + + if( memcmp(&wholebuffer[0], ptr, wholebuffer.size() ) != 0 ) + { + std::cerr << "BUG: (n) Readers are not equivalent to a single reader !" << std::endl; + ret = 1; + } +#if 0 +std::ofstream o1("/tmp/debug1.raw", std::ios::binary); +o1.write(&wholebuffer[0], wholebuffer.size()); +o1.close(); + +std::ofstream o2("/tmp/debug2.raw", std::ios::binary); +o2.write(ptr, wholebuffer.size()); +o2.close(); +#endif + + reader->Delete(); + return ret; +} + + +int TestvtkGDCMImageReader3(int , char *[]) +{ + int ret = 0; + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + const char *root = gdcm::Testing::GetDataExtraRoot(); + std::string dir1 = root; + std::string dir2 = root; + std::string dir3 = root; + // dir1 & dir2 have changing 'Rescale Slope': + dir1 += "/gdcmSampleData/Philips_Medical_Images/mr711-mr712/"; + dir2 += "/gdcmSampleData/ForSeriesTesting/Perfusion/images/"; + // dir3 has RescaleSlope == 0 ! + dir3 += "/gdcmSampleData/ForSeriesTesting/Dentist/images/"; + + const char *studyuids[] = { + "1.3.46.670589.11.30.6.106253130282775287", + "1.2.250.1.38.2.1.12.7118916513228.20041110114508.431746279", + "1.76.380.18.1.10713.1.1335" + }; + + ret += TestvtkGDCMImageRead3(dir1.c_str(), studyuids[0]); + ret += TestvtkGDCMImageRead3(dir2.c_str(), studyuids[1]); + ret += TestvtkGDCMImageRead3(dir3.c_str(), studyuids[2]); + + + return ret; +} diff --git a/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMImageReader4.cxx b/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMImageReader4.cxx new file mode 100644 index 0000000..098ab04 --- /dev/null +++ b/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMImageReader4.cxx @@ -0,0 +1,157 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkGDCMImageReader.h" +#include "vtkGDCMImageWriter.h" +#include "vtkMedicalImageProperties.h" + +#include "vtkPNGWriter.h" +#include "vtkImageData.h" +#include "vtkStringArray.h" +//#include + +#include "gdcmFilename.h" +#include "gdcmTesting.h" +#include "gdcmSystem.h" +#include "gdcmTrace.h" +#include "gdcmDirectory.h" +#include "gdcmScanner.h" +#include "gdcmGlobal.h" +#include "gdcmDicts.h" + +/* + * This test shows how can one extent value stored in the vtkMedicalImageProperties + * For instance we will add the following two value in the struct: + * (0008,0005) CS [ISO_IR 100] # 10, 1 SpecificCharacterSet + * (0008,0008) CS [ORIGINAL\PRIMARY\AXIAL] # 22, 3 ImageType + */ +int TestvtkGDCMImageRead4(const char *filename, bool verbose) +{ + if( verbose ) + std::cerr << "Reading : " << filename << std::endl; + + gdcm::Directory::FilenamesType l; + vtkGDCMImageReader *reader = vtkGDCMImageReader::New(); + if( gdcm::System::FileIsDirectory( filename ) ) + { + verbose = false; + gdcm::Directory d; + d.Load( filename ); + l = d.GetFilenames(); + const size_t nfiles = l.size(); + vtkStringArray *sarray = vtkStringArray::New(); + for(unsigned int i = 0; i < nfiles; ++i) + { + sarray->InsertNextValue( l[i] ); + } + assert( sarray->GetNumberOfValues() == (int)nfiles ); + reader->SetFileNames( sarray ); + sarray->Delete(); + } + else + { + reader->SetFileName( filename ); + l.push_back( filename ); + } + + //int canread = reader->CanReadFile( filename ); + reader->Update(); + + gdcm::Scanner scanner; + // (0008,0005) CS [ISO_IR 100] # 10, 1 SpecificCharacterSet + // (0008,0008) CS [ORIGINAL\PRIMARY\AXIAL] # 22, 3 ImageType + const gdcm::Tag t1(0x0008,0x0005); + const gdcm::Tag t2(0x0008,0x0008); + scanner.AddTag( t1 ); + scanner.AddTag( t2 ); + const gdcm::Global& g = gdcm::Global::GetInstance(); + const gdcm::Dicts &ds = g.GetDicts(); + + bool b = scanner.Scan( l ); + if( !b ) + { + return 1; + } + + vtkMedicalImageProperties * medprop = reader->GetMedicalImageProperties(); + +#if ( VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION > 0 ) + const char *value1 = scanner.GetValue( filename, t1 ); + const gdcm::DictEntry& de1 = ds.GetDictEntry( t1 ); + medprop->AddUserDefinedValue(de1.GetName(), value1); + + const char *value2 = scanner.GetValue( filename, t2 ); + const gdcm::DictEntry& de2 = ds.GetDictEntry( t2 ); + medprop->AddUserDefinedValue(de2.GetName(), value2); +#endif + + if( verbose ) + { + reader->GetOutput()->Print( cout ); + reader->GetMedicalImageProperties()->Print( cout ); + } + + // Create directory first: + const char subdir[] = "TestvtkGDCMImageReader4"; + std::string tmpdir = gdcm::Testing::GetTempDirectory( subdir ); + if( !gdcm::System::FileIsDirectory( tmpdir.c_str() ) ) + { + gdcm::System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + std::string gdcmfile = gdcm::Testing::GetTempFilename( filename, subdir ); + + vtkGDCMImageWriter *writer = vtkGDCMImageWriter::New(); +#if (VTK_MAJOR_VERSION >= 6) + writer->SetInputConnection( reader->GetOutputPort() ); +#else + writer->SetInput( reader->GetOutput() ); +#endif + writer->SetFileLowerLeft( reader->GetFileLowerLeft() ); + writer->SetDirectionCosines( reader->GetDirectionCosines() ); + writer->SetImageFormat( reader->GetImageFormat() ); + writer->SetFileDimensionality( reader->GetFileDimensionality() ); + writer->SetMedicalImageProperties( reader->GetMedicalImageProperties() ); + writer->SetShift( reader->GetShift() ); + writer->SetScale( reader->GetScale() ); + writer->SetFileName( gdcmfile.c_str() ); + writer->Write(); + if( verbose ) std::cerr << "Write out: " << gdcmfile << std::endl; + + reader->Delete(); + writer->Delete(); + return 0; +} + +int TestvtkGDCMImageReader4(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestvtkGDCMImageRead4(filename, true); + } + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestvtkGDCMImageRead4( filename, false ); + ++i; + } + + return r; +} diff --git a/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMImageReaderIsLossy.cxx b/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMImageReaderIsLossy.cxx new file mode 100644 index 0000000..4f6d825 --- /dev/null +++ b/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMImageReaderIsLossy.cxx @@ -0,0 +1,84 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkGDCMImageReader.h" + +#include "vtkImageData.h" +#include "vtkMultiThreader.h" +#include "vtkMedicalImageProperties.h" + +#include "gdcmTesting.h" +#include "gdcmFilename.h" +#include "gdcmSystem.h" +#include "gdcmTrace.h" +#include "gdcmImageReader.h" + +#ifndef vtkFloatingPointType +#define vtkFloatingPointType float +#endif + +int TestvtkGDCMImageReaderIsLossyFunc(const char *filename, bool verbose = false) +{ + gdcm::Filename fn = filename; + vtkGDCMImageReader *reader = vtkGDCMImageReader::New(); + int canread = reader->CanReadFile( filename ); + int res = 0; + if( canread ) + { + reader->SetFileName( filename ); + reader->Update(); + if( verbose ) + { + reader->GetOutput()->Print( cout ); + reader->GetMedicalImageProperties()->Print( cout ); + } + int reflossy = gdcm::Testing::GetLossyFlagFromFile( filename ); + if( reader->GetLossyFlag() != reflossy ) + { + std::cerr << "Mismatch for " << filename << std::endl; + ++res; + } + } + else + { + std::cerr << "Could not read: " << filename << std::endl; + //++res; + } + reader->Delete(); + + return res; +} + +int TestvtkGDCMImageReaderIsLossy(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestvtkGDCMImageReaderIsLossyFunc(filename, true); + } + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + gdcm::Trace::ErrorOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestvtkGDCMImageReaderIsLossyFunc( filename ); + ++i; + } + + return r; +} diff --git a/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMImageViewer.cxx b/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMImageViewer.cxx new file mode 100644 index 0000000..6ec472f --- /dev/null +++ b/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMImageViewer.cxx @@ -0,0 +1,76 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkGDCMImageReader.h" + +#include "vtkPNGWriter.h" +#include "vtkImageColorViewer.h" +#include "vtkImageData.h" +#include "vtkImageActor.h" +#include "vtkRenderWindowInteractor.h" +#include "vtkRenderWindow.h" +#include "vtkRenderer.h" +#include "vtkInteractorStyleImage.h" +#include + +#include "gdcmTesting.h" + +int TestvtkGDCMReadImageViewer(const char *filename) +{ + vtkGDCMImageReader *reader = vtkGDCMImageReader::New(); + //reader->CanReadFile( filename ); + std::cerr << "Reading : " << filename << std::endl; + reader->SetFileName( filename ); + reader->Update(); + + reader->GetOutput()->Print( cout ); + + + vtkImageColorViewer *viewer = vtkImageColorViewer::New(); + viewer->SetInput( reader->GetOutput() ); + + + vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New(); + + viewer->SetupInteractor( iren ); + viewer->Render(); + + iren->Initialize(); + iren->Start(); + + reader->Delete(); + iren->Delete(); + + return 0; +} + +int TestvtkGDCMImageViewer(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestvtkGDCMReadImageViewer(filename); + } + + // else + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestvtkGDCMReadImageViewer( filename ); + ++i; + } + + return r; +} diff --git a/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMImageWriter1.cxx b/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMImageWriter1.cxx new file mode 100644 index 0000000..88309f7 --- /dev/null +++ b/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMImageWriter1.cxx @@ -0,0 +1,260 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkGDCMImageReader.h" +#include "vtkGDCMImageWriter.h" + +#include "vtkImageData.h" +#include "vtkMultiThreader.h" +#include "vtkMedicalImageProperties.h" + +#include "gdcmTesting.h" +#include "gdcmFilename.h" +#include "gdcmSystem.h" +#include "gdcmTrace.h" +#include "gdcmImageReader.h" + +#ifndef vtkFloatingPointType +#define vtkFloatingPointType float +#endif + +int TestvtkGDCMImageWrite(const char *filename, bool verbose = false) +{ + int res = 0; // no error + if( verbose ) + std::cerr << "Reading : " << filename << std::endl; + vtkGDCMImageReader *reader = vtkGDCMImageReader::New(); + reader->FileLowerLeftOn(); + int canread = reader->CanReadFile( filename ); + if( canread ) + { + reader->SetFileName( filename ); + reader->Update(); + if( verbose ) + { + reader->GetOutput()->Print( cout ); + reader->GetMedicalImageProperties()->Print( cout ); + } + + // Create directory first: + const char subdir[] = "TestvtkGDCMImageWriter"; + std::string tmpdir = gdcm::Testing::GetTempDirectory( subdir ); + if( !gdcm::System::FileIsDirectory( tmpdir.c_str() ) ) + { + gdcm::System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + std::string gdcmfile = gdcm::Testing::GetTempFilename( filename, subdir ); + + vtkGDCMImageWriter *writer = vtkGDCMImageWriter::New(); +#if (VTK_MAJOR_VERSION >= 6) + writer->SetInputConnection( reader->GetOutputPort() ); +#else + writer->SetInput( reader->GetOutput() ); +#endif + writer->SetFileLowerLeft( reader->GetFileLowerLeft() ); + writer->SetDirectionCosines( reader->GetDirectionCosines() ); + writer->SetImageFormat( reader->GetImageFormat() ); + writer->SetFileDimensionality( reader->GetFileDimensionality() ); + writer->SetMedicalImageProperties( reader->GetMedicalImageProperties() ); + writer->SetPlanarConfiguration( reader->GetPlanarConfiguration() ); + writer->SetShift( reader->GetShift() ); + writer->SetScale( reader->GetScale() ); + writer->SetFileName( gdcmfile.c_str() ); + writer->Write(); + if( verbose ) std::cerr << "Write out: " << gdcmfile << std::endl; + + writer->Delete(); + + // Need to check we can still read this image back: + gdcm::ImageReader r; + if( gdcm::System::FileExists( gdcmfile.c_str() ) ) + { + r.SetFileName( gdcmfile.c_str() ); + } + if( !r.Read() ) + { + std::cerr << "failed to read back:" << gdcmfile << std::endl; + res = 1; + } + else + { + // ok could read the file, now check origin is ok: + const gdcm::Image &image = r.GetImage(); + const double *origin = image.GetOrigin(); + if( origin ) + { + vtkImageData * vtkimg = reader->GetOutput(); + const vtkFloatingPointType *vtkorigin = vtkimg->GetOrigin(); + if( fabs(vtkorigin[0] - origin[0]) > 1.e-3 + || fabs(vtkorigin[1] - origin[1]) > 1.e-3 + || fabs(vtkorigin[2] - origin[2]) > 1.e-3 ) + { + std::cerr << "Problem:" << vtkorigin[0] << "," << vtkorigin[1] << "," << vtkorigin[2] ; + std::cerr << " should be:" << origin[0] << "," << origin[1] << "," << origin[2] << std::endl ; + std::cerr << filename << std::endl; + res = 1; + } + } + + gdcm::ImageReader r2; + r2.SetFileName( filename ); + if( !r2.Read() ) + { + std::cerr << "failed to re-read initial image...how is that possible ?:" << filename << std::endl; + res = 1; + } + const gdcm::Image &compimage = r2.GetImage(); + // Check that Media Storage is still correct: + // Well this is difficult to implement as Retired class are replaced with newer one automatically + gdcm::MediaStorage ms1; + ms1.SetFromFile( r.GetFile() ); // our rewritten file + gdcm::MediaStorage ms2; + ms2.SetFromFile( r2.GetFile() ); // original file + if( ms1 != ms2 ) + { + if( ms1 == gdcm::MediaStorage::MultiframeGrayscaleByteSecondaryCaptureImageStorage ) + { + // Hum I have this weird case when reading libido1.0-vol.acr... + } + else if( ms1 == gdcm::MediaStorage::XRayAngiographicImageStorage && ms2 == gdcm::MediaStorage::SecondaryCaptureImageStorage ) + { + // FIXME: D_CLUNIE_XA1_JPLL.dcm + } + else if( ms2 == gdcm::MediaStorage::XRayRadiofluoroscopingImageStorage ) + { + // gdcmData/JDDICOM_Sample5.dcm + } + else if( ms1 == gdcm::MediaStorage::EnhancedMRImageStorage && ms2 == gdcm::MediaStorage::MRImageStorage ) + { + // gdcmData/MR-MONO2-8-16x-heart.dcm + } + else if( ms1 == gdcm::MediaStorage::UltrasoundImageStorage && ms2 == gdcm::MediaStorage::UltrasoundImageStorageRetired ) + { + // gdcmData/US-RGB-8-esopecho.dcm + } + else if( ms1 == gdcm::MediaStorage::UltrasoundMultiFrameImageStorage && ms2 == gdcm::MediaStorage::UltrasoundMultiFrameImageStorageRetired ) + { + // gdcmData/US-MONO2-8-8x-execho.dcm + } + else if ( ms1 == gdcm::MediaStorage::NuclearMedicineImageStorage && ms2 == gdcm::MediaStorage::SecondaryCaptureImageStorage ) + { + // gdcmData/Renal_Flow.dcm + } + else if ( ms1 == gdcm::MediaStorage::CTImageStorage && ms2 == gdcm::MediaStorage::SecondaryCaptureImageStorage ) + { + // gdcmData/D_CLUNIE_SC1_JPLY.dcm + } + else if ( ms1 == gdcm::MediaStorage::EnhancedCTImageStorage && ms2 == gdcm::MediaStorage::CTImageStorage && compimage.GetNumberOfDimensions() == 3 ) + { + // gdcmData/CroppedArm.dcm + } + else if( ms1 == gdcm::MediaStorage::MRImageStorage && ms2 == gdcm::MediaStorage::GeneralElectricMagneticResonanceImageStorage ) + { + // gdcmData/MR00010001.dcm + } + else if( ms1 == gdcm::MediaStorage::UltrasoundImageStorage && ms2 == gdcm::MediaStorage::SecondaryCaptureImageStorage ) + { + // gdcmData/GE_LOGIQBook-8-RGB-HugePreview.dcm + } + else if( ms1 == gdcm::MediaStorage::DigitalXRayImageStorageForProcessing + && ms2 == gdcm::MediaStorage::DigitalXRayImageStorageForPresentation + ) + { + // gdcmData/DX_GE_FALCON_SNOWY-VOI.dcm + } + else + { + std::cerr << "MediaStorage incompatible: " << ms1 << " vs " << ms2 << " for file: " << filename << std::endl; + res = 1; + } + } + // Make sure that md5 is still ok: + unsigned long len = image.GetBufferLength(); + char* buffer = new char[len]; + bool res2 = image.GetBuffer(buffer); + if( !res2 ) + { + std::cerr << "Could not get buffer" << std::endl; + res = 1; + } + const char *ref = gdcm::Testing::GetMD5FromFile(filename); + char digest[33]; + gdcm::Testing::ComputeMD5(buffer, len, digest); + if( !ref ) + { + std::cerr << "Could not compute md5" << std::endl; + res = 1; + } + const gdcm::PixelFormat &comppf = compimage.GetPixelFormat(); + if( !ref ) + { + std::cerr << "Missing md5: " << digest << std::endl; + } + else if( strcmp(digest, ref) != 0 + // I do not support rewritting 12Bits pack image (illegal anyway) + && comppf != gdcm::PixelFormat::UINT12 + ) + { +#if 0 +{ +unsigned long len = compimage.GetBufferLength(); +char* buffer = new char[len]; +bool res2 = compimage.GetBuffer(buffer); +std::ofstream out("/tmp/debug.raw", std::ios::binary); +out.write( buffer, len ); +out.close(); +} +#endif + std::cerr << "Problem reading image from: " << filename << std::endl; + std::cerr << "Found " << digest << " instead of " << ref << std::endl; + std::cerr << "Original TransferSyntax was: " << compimage.GetTransferSyntax() << std::endl; + std::cerr << "Output image: " << gdcmfile << std::endl; + res = 1; + } + delete[] buffer; + } + } + else + { + if( verbose ) + std::cerr << "vtkGDCMImageReader cannot read: " << filename << std::endl; + } + reader->Delete(); + + return res; +} + +int TestvtkGDCMImageWriter1(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestvtkGDCMImageWrite(filename, true); + } + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + gdcm::Trace::ErrorOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestvtkGDCMImageWrite( filename ); + ++i; + } + + return r; +} diff --git a/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMImageWriter2.cxx b/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMImageWriter2.cxx new file mode 100644 index 0000000..403c2ca --- /dev/null +++ b/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMImageWriter2.cxx @@ -0,0 +1,185 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkGDCMImageReader.h" +#include "vtkGDCMImageWriter.h" + +#include "vtkImageData.h" +#include "vtkMultiThreader.h" +#include "vtkMedicalImageProperties.h" +#include "vtkStringArray.h" + +#include "gdcmTesting.h" +#include "gdcmFilename.h" +#include "gdcmSystem.h" +#include "gdcmTrace.h" +#include "gdcmFilenameGenerator.h" +#include "gdcmImageReader.h" + +#include + +#ifndef vtkFloatingPointType +#define vtkFloatingPointType float +#endif + +int TestvtkGDCMImageWrite2(const char *filename, bool verbose = false) +{ + int res = 0; // no error + if( verbose ) + std::cerr << "Reading : " << filename << std::endl; + vtkGDCMImageReader *reader = vtkGDCMImageReader::New(); + reader->FileLowerLeftOn(); + int canread = reader->CanReadFile( filename ); + if( canread ) + { + reader->SetFileName( filename ); + reader->Update(); + if( verbose ) + { + reader->GetOutput()->Print( cout ); + reader->GetMedicalImageProperties()->Print( cout ); + } + + // Create directory first: + const char subdir[] = "TestvtkGDCMImageWriter2"; + std::string tmpdir = gdcm::Testing::GetTempDirectory( subdir ); + if( !gdcm::System::FileIsDirectory( tmpdir.c_str() ) ) + { + gdcm::System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + std::string gdcmfile = gdcm::Testing::GetTempFilename( filename, subdir ); + //std::cerr << filename << std::endl; + //std::cerr << gdcmfile << std::endl; + + std::ostringstream os; + os << gdcmfile; + os << "%01d"; + gdcm::FilenameGenerator fg; + //fg.SetPattern( gdcmfile.c_str() ); + fg.SetPattern( os.str().c_str() ); + unsigned int nfiles = reader->GetOutput()->GetDimensions()[2]; + fg.SetNumberOfFilenames( nfiles ); + bool b = fg.Generate(); + if( !b ) + { + std::cerr << "FilenameGenerator::Generate() failed" << std::endl; + return 1; + } + if( !fg.GetNumberOfFilenames() ) + { + std::cerr << "FilenameGenerator::Generate() failed somehow..." << std::endl; + return 1; + } + + vtkGDCMImageWriter *writer = vtkGDCMImageWriter::New(); +#if (VTK_MAJOR_VERSION >= 6) + writer->SetInputConnection( reader->GetOutputPort() ); +#else + writer->SetInput( reader->GetOutput() ); +#endif + writer->SetFileLowerLeft( reader->GetFileLowerLeft() ); + writer->SetDirectionCosines( reader->GetDirectionCosines() ); + writer->SetImageFormat( reader->GetImageFormat() ); + writer->SetFileDimensionality( 2 ); // test the 3D to 2D writing mode + writer->SetMedicalImageProperties( reader->GetMedicalImageProperties() ); + writer->SetShift( reader->GetShift() ); + writer->SetScale( reader->GetScale() ); + //writer->SetFileName( gdcmfile.c_str() ); + vtkStringArray *filenames = vtkStringArray::New(); + for(unsigned int i = 0; i < fg.GetNumberOfFilenames(); ++i) + { + filenames->InsertNextValue( fg.GetFilename(i) ); + std::cerr << fg.GetFilename(i) << std::endl; + } + assert( filenames->GetNumberOfValues() == (int)fg.GetNumberOfFilenames() ); + writer->SetFileNames( filenames ); + writer->Write(); + //if( verbose ) std::cerr << "Write out: " << gdcmfile << std::endl; + + writer->Delete(); + + // Need to check we can still read those files back: + for(int file=0; fileGetNumberOfValues(); ++file) + { + const char *fname = filenames->GetValue(file); + gdcm::ImageReader r; + //r.SetFileName( gdcmfile.c_str() ); + r.SetFileName( fname ); + if( !r.Read() ) + { + std::cerr << "failed to read back:" << fname << std::endl; + res = 1; + } + else + { + if( file == 0 ) + { + // ok could read the file, now check origin is ok: + const gdcm::Image &image = r.GetImage(); + const double *origin = image.GetOrigin(); + if( origin ) + { +/* +FIXME: it would be nice if this test would also handle FileLowerLeftOff to do d'une pierre deux coups. +*/ + vtkImageData * vtkimg = reader->GetOutput(); + const vtkFloatingPointType *vtkorigin = vtkimg->GetOrigin(); + if( fabs(vtkorigin[0] - origin[0]) > 1.e-3 + || fabs(vtkorigin[1] - origin[1]) > 1.e-3 + || fabs(vtkorigin[2] - origin[2]) > 1.e-3 ) + { + std::cerr << "Problem:" << vtkorigin[0] << "," << vtkorigin[1] << "," << vtkorigin[2] ; + std::cerr << " should be:" << origin[0] << "," << origin[1] << "," << origin[2] << std::endl ; + res = 1; + } + } + } + } + } + + filenames->Delete(); + } + else + { + if( verbose ) + std::cerr << "vtkGDCMImageReader cannot read: " << filename << std::endl; + //res++; + } + reader->Delete(); + + return res; +} + +int TestvtkGDCMImageWriter2(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestvtkGDCMImageWrite2(filename, true); + } + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestvtkGDCMImageWrite2( filename ); + ++i; + } + + return r; +} diff --git a/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMImageWriterIsLossy.cxx b/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMImageWriterIsLossy.cxx new file mode 100644 index 0000000..c281940 --- /dev/null +++ b/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMImageWriterIsLossy.cxx @@ -0,0 +1,65 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkGDCMImageReader.h" + +#include "vtkImageNoiseSource.h" +#include "vtkGDCMImageWriter.h" + +#include "gdcmTesting.h" +#include "gdcmSystem.h" + +int TestvtkGDCMImageWriterIsLossy(int , char *[]) +{ + vtkImageNoiseSource * noise = vtkImageNoiseSource::New(); + noise->SetWholeExtent(1,256,1,256,0,0); + noise->SetMinimum(0.0); + noise->SetMaximum(255.0); + + // Create directory first: + const char subdir[] = "TestvtkGDCMImageWriterIsLossy"; + std::string tmpdir = gdcm::Testing::GetTempDirectory( subdir ); + if( !gdcm::System::FileIsDirectory( tmpdir.c_str() ) ) + { + gdcm::System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + const char *filename = "noise.dcm"; + std::string gdcmfile = gdcm::Testing::GetTempFilename( filename, subdir ); + + vtkGDCMImageWriter *writer = vtkGDCMImageWriter::New(); +#if (VTK_MAJOR_VERSION >= 6) + writer->SetInputConnection( noise->GetOutputPort() ); +#else + writer->SetInput( noise->GetOutput() ); +#endif + writer->SetShift( 0 ); + writer->SetScale( 1.5 ); + writer->SetLossyFlag( 1 ); + writer->SetFileName( gdcmfile.c_str() ); + writer->Write(); + + noise->Delete(); + writer->Delete(); + + vtkGDCMImageReader * reader = vtkGDCMImageReader::New(); + reader->SetFileName( gdcmfile.c_str() ); + reader->Update(); + + int lossyflag = reader->GetLossyFlag(); + reader->Delete(); + + if( lossyflag != 1 ) return 1; + + return 0; +} diff --git a/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMMetaImageWriter.cxx b/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMMetaImageWriter.cxx new file mode 100644 index 0000000..56cd947 --- /dev/null +++ b/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMMetaImageWriter.cxx @@ -0,0 +1,166 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkGDCMImageReader.h" +#include "vtkGDCMTesting.h" +#include "vtkMedicalImageProperties.h" + +#include "vtkMetaImageWriter.h" +#include "vtkImageData.h" +#include "vtkStringArray.h" +//#include + +#include "gdcmFilename.h" +#include "gdcmTesting.h" +#include "gdcmSystem.h" +#include "gdcmTrace.h" +#include "gdcmDirectory.h" +#include "gdcmMediaStorage.h" + +static int TestvtkGDCMMetaImageWrite(const char *filename, bool verbose) +{ + if( verbose ) + std::cerr << "Reading : " << filename << std::endl; + + vtkGDCMImageReader *reader = vtkGDCMImageReader::New(); + reader->FileLowerLeftOn(); + reader->DebugOff(); + + int canread = reader->CanReadFile( filename ); + if( !canread ) + { + reader->Delete(); + gdcm::Filename fn( filename ); + if( fn.GetName() == std::string("ELSCINT1_PMSCT_RLE1.dcm" ) ) + { + // No Pixel Data... + return 0; + } + const char *refms = gdcm::Testing::GetMediaStorageFromFile(filename); + if( gdcm::MediaStorage::IsImage( gdcm::MediaStorage::GetMSType(refms) ) ) + { + std::cerr << "Problem with: " << filename << std::endl; + return 1; + } + // not an image + return 0; + } + + const char *refms = gdcm::Testing::GetMediaStorageFromFile(filename); + if( !gdcm::MediaStorage::IsImage( gdcm::MediaStorage::GetMSType(refms) ) ) + { + if( !refms ) + { + std::cerr << "Missing SOP Class: " << filename << std::endl; + return 1; + } + } + + reader->SetFileName( filename ); + reader->Update(); + + if( verbose ) + { + reader->GetOutput()->Print( cout ); + reader->GetMedicalImageProperties()->Print( cout ); + } + +// if( verbose ) + { + // Create directory first: + const char subdir[] = "TestvtkGDCMMetaImageWriter"; + std::string tmpdir = gdcm::Testing::GetTempDirectory( subdir ); + if( !gdcm::System::FileIsDirectory( tmpdir.c_str() ) ) + { + gdcm::System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + std::string mhdfile = gdcm::Testing::GetTempFilename( filename, subdir ); + std::string rawfile = mhdfile; + + vtkMetaImageWriter *writer = vtkMetaImageWriter::New(); + writer->SetCompression( false ); + writer->SetInputConnection( reader->GetOutputPort() ); + mhdfile += ".mhd"; + rawfile += ".raw"; + writer->SetFileName( mhdfile.c_str() ); + writer->Write(); + writer->Delete(); + if( verbose ) + cout << "Wrote MHD output into: " << mhdfile << std::endl; + char digestmhd[33] = {}; + char digestraw[33] = {}; + bool bmhd = gdcm::Testing::ComputeFileMD5( mhdfile.c_str() , digestmhd ); + bool braw = gdcm::Testing::ComputeFileMD5( rawfile.c_str() , digestraw ); + assert( bmhd && braw ); (void)bmhd; (void)braw; + const char * mhdref = vtkGDCMTesting::GetMHDMD5FromFile(filename); + const char * rawref = vtkGDCMTesting::GetRAWMD5FromFile(filename); + if( !mhdref || !rawref ) + { + std::cout << "Found: \"" << filename << "\",\"" << digestmhd << "\", \"" << digestraw << "\"" << std::endl; + return 1; + } + else if( strcmp(digestraw, rawref) ) + { + std::cerr << "Problem reading RAW from: " << rawfile << std::endl; + std::cerr << "Found " << digestraw << " instead of " << rawref << std::endl; + + return 1; + } + else if( strcmp(digestmhd, mhdref) ) + { + std::cerr << "Problem reading MHD from: " << mhdfile << std::endl; + std::cerr << "Found " << digestmhd << " instead of " << mhdref << std::endl; + + return 1; + } + } + + reader->Delete(); + return 0; +} + +int TestvtkGDCMMetaImageWriter(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestvtkGDCMMetaImageWrite(filename, true); + } + +#if 0 + unsigned int n = vtkGDCMTesting::GetNumberOfMD5MetaImages(); + for( unsigned int i = 0; i < n; ++i ) + { + const char * const * p = vtkGDCMTesting::GetMD5MetaImage(i); + std::cout << p[1] << " " << p[0] << ".mhd" << std::endl; + std::cout << p[2] << " " << p[0] << ".raw" << std::endl; + } + return 0; +#endif + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + gdcm::Trace::ErrorOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestvtkGDCMMetaImageWrite( filename, false ); + ++i; + } + + return r; +} diff --git a/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMMetaImageWriter2.cxx b/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMMetaImageWriter2.cxx new file mode 100644 index 0000000..e3bcce5 --- /dev/null +++ b/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMMetaImageWriter2.cxx @@ -0,0 +1,166 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkGDCMImageReader2.h" +#include "vtkGDCMTesting.h" +#include "vtkMedicalImageProperties.h" + +#include "vtkMetaImageWriter.h" +#include "vtkImageData.h" +#include "vtkStringArray.h" +//#include + +#include "gdcmFilename.h" +#include "gdcmTesting.h" +#include "gdcmSystem.h" +#include "gdcmTrace.h" +#include "gdcmDirectory.h" +#include "gdcmMediaStorage.h" + +static int TestvtkGDCMMetaImageWrite(const char *filename, bool verbose) +{ + if( verbose ) + std::cerr << "Reading : " << filename << std::endl; + + vtkGDCMImageReader2 * reader = vtkGDCMImageReader2::New(); + reader->FileLowerLeftOn(); + reader->DebugOff(); + + int canread = reader->CanReadFile( filename ); + if( !canread ) + { + reader->Delete(); + gdcm::Filename fn( filename ); + if( fn.GetName() == std::string("ELSCINT1_PMSCT_RLE1.dcm" ) ) + { + // No Pixel Data... + return 0; + } + const char *refms = gdcm::Testing::GetMediaStorageFromFile(filename); + if( gdcm::MediaStorage::IsImage( gdcm::MediaStorage::GetMSType(refms) ) ) + { + std::cerr << "Problem with: " << filename << std::endl; + return 1; + } + // not an image + return 0; + } + + const char *refms = gdcm::Testing::GetMediaStorageFromFile(filename); + if( !gdcm::MediaStorage::IsImage( gdcm::MediaStorage::GetMSType(refms) ) ) + { + if( !refms ) + { + std::cerr << "Missing SOP Class: " << filename << std::endl; + return 1; + } + } + + reader->SetFileName( filename ); + reader->Update(); + + if( verbose ) + { + reader->GetOutput()->Print( cout ); + reader->GetMedicalImageProperties()->Print( cout ); + } + +// if( verbose ) + { + // Create directory first: + const char subdir[] = "TestvtkGDCMMetaImageWriter2"; + std::string tmpdir = gdcm::Testing::GetTempDirectory( subdir ); + if( !gdcm::System::FileIsDirectory( tmpdir.c_str() ) ) + { + gdcm::System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + std::string mhdfile = gdcm::Testing::GetTempFilename( filename, subdir ); + std::string rawfile = mhdfile; + + vtkMetaImageWriter *writer = vtkMetaImageWriter::New(); + writer->SetCompression( false ); + writer->SetInputConnection( reader->GetOutputPort() ); + mhdfile += ".mhd"; + rawfile += ".raw"; + writer->SetFileName( mhdfile.c_str() ); + writer->Write(); + writer->Delete(); + if( verbose ) + cout << "Wrote MHD output into: " << mhdfile << std::endl; + char digestmhd[33] = {}; + char digestraw[33] = {}; + bool bmhd = gdcm::Testing::ComputeFileMD5( mhdfile.c_str() , digestmhd ); + bool braw = gdcm::Testing::ComputeFileMD5( rawfile.c_str() , digestraw ); + assert( bmhd && braw ); (void)bmhd; (void)braw; + const char * mhdref = vtkGDCMTesting::GetMHDMD5FromFile(filename); + const char * rawref = vtkGDCMTesting::GetRAWMD5FromFile(filename); + if( !mhdref || !rawref ) + { + std::cout << "Found: \"" << filename << "\",\"" << digestmhd << "\", \"" << digestraw << "\"" << std::endl; + return 1; + } + else if( strcmp(digestraw, rawref) ) + { + std::cerr << "Problem reading RAW from: " << rawfile << std::endl; + std::cerr << "Found " << digestraw << " instead of " << rawref << std::endl; + + return 1; + } + else if( strcmp(digestmhd, mhdref) ) + { + std::cerr << "Problem reading MHD from: " << mhdfile << std::endl; + std::cerr << "Found " << digestmhd << " instead of " << mhdref << std::endl; + + return 1; + } + } + + reader->Delete(); + return 0; +} + +int TestvtkGDCMMetaImageWriter2(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestvtkGDCMMetaImageWrite(filename, true); + } + +#if 0 + unsigned int n = vtkGDCMTesting::GetNumberOfMD5MetaImages(); + for( unsigned int i = 0; i < n; ++i ) + { + const char * const * p = vtkGDCMTesting::GetMD5MetaImage(i); + std::cout << p[1] << " " << p[0] << ".mhd" << std::endl; + std::cout << p[2] << " " << p[0] << ".raw" << std::endl; + } + return 0; +#endif + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + gdcm::Trace::ErrorOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestvtkGDCMMetaImageWrite( filename, false ); + ++i; + } + + return r; +} diff --git a/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMPolyDataReader.cxx b/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMPolyDataReader.cxx new file mode 100644 index 0000000..d0de887 --- /dev/null +++ b/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMPolyDataReader.cxx @@ -0,0 +1,88 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkGDCMPolyDataReader.h" +#include "vtkMedicalImageProperties.h" + +#include "gdcmDirectory.h" +#include "gdcmTesting.h" +#include "gdcmTrace.h" + +static const char * rtstruct_files[] = { + "gdcmNonImageData/RTSTRUCT_1.3.6.1.4.1.22213.1.1396.2.dcm", + "gdcmNonImageData/RT/RTStruct.dcm", + "gdcmNonImageData/exRT_Structure_Set_Storage.dcm", + 0 +}; + +static const int rtstruct_files_nb[] = { + 9, + 4, + 10 +}; + +int TestvtkGDCMPolyDataRead(const char *filename, int nb, bool verbose) +{ + int ret = 0; + if( verbose ) + std::cerr << "Reading : " << filename << std::endl; + + vtkGDCMPolyDataReader *reader = vtkGDCMPolyDataReader::New(); + reader->SetFileName( filename ); + + //int canread = reader->CanReadFile( filename ); + reader->Update(); + + if( verbose ) + { + reader->GetOutput()->Print( cout ); + reader->GetMedicalImageProperties()->Print( cout ); + } + + //std::cout << reader->GetNumberOfOutputPorts() << std::endl; + if( nb != -1 && reader->GetNumberOfOutputPorts() != nb ) + { + ret = 1; + } + + reader->Delete(); + return ret; +} + +int TestvtkGDCMPolyDataReader(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestvtkGDCMPolyDataRead(filename, -1, true); + } + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + int r = 0, i = 0; + const char *filename; + //const char * const *filenames = gdcm::Testing::GetFileNames(); + //gdcmDataExtra + const char *extradataroot = gdcm::Testing::GetDataExtraRoot(); + while( (filename = rtstruct_files[i]) ) + { + std::string fullpath = extradataroot; + fullpath += "/"; + fullpath += filename; + r += TestvtkGDCMPolyDataRead( fullpath.c_str(), rtstruct_files_nb[i], true); + ++i; + } + + return r; +} diff --git a/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMThreadedImageReader.cxx b/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMThreadedImageReader.cxx new file mode 100644 index 0000000..ba6ad52 --- /dev/null +++ b/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMThreadedImageReader.cxx @@ -0,0 +1,268 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkGDCMThreadedImageReader.h" +#include "vtkGDCMImageReader.h" +#include "vtkCommand.h" + +#include "gdcmDirectory.h" +#include "gdcmSystem.h" +#include "gdcmImageReader.h" +#include "gdcmTesting.h" + +#include "vtkPNGWriter.h" +#include "vtkStringArray.h" +#include "vtkStructuredPointsWriter.h" +#include "vtkImageData.h" +#if (VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 ) +#include +#include "vtkVolumeTextureMapper3D.h" +#endif + +#include "vtkPiecewiseFunction.h" +#include "vtkColorTransferFunction.h" +#include "vtkVolumeProperty.h" +#include "vtkVolume.h" +#include "vtkRenderer.h" +#include "vtkRenderWindow.h" +#include "vtkRenderWindowInteractor.h" + + +class ProgressObserver : public vtkCommand +{ +public: + static ProgressObserver* New() { + return new ProgressObserver; + } + + virtual void Execute(vtkObject* caller, unsigned long event, void *callData) + { + (void)callData; + if( event == vtkCommand::ProgressEvent ) + { + std::cout << ((vtkGDCMThreadedImageReader*)caller)->GetProgress() << std::endl; + } + } +}; + + +template +int ExecuteInformation(const char *filename, TReader *vtkreader) +{ + gdcm::ImageReader reader; + reader.SetFileName( filename ); + if( !reader.Read() ) + { + return 0; + } + const gdcm::Image &image = reader.GetImage(); + const unsigned int *dims = image.GetDimensions(); + + // Set the Extents. + assert( image.GetNumberOfDimensions() >= 2 ); + int dataextent[6] = {}; + dataextent[0] = 0; + dataextent[1] = dims[0] - 1; + dataextent[2] = 0; + dataextent[3] = dims[1] - 1; + if( image.GetNumberOfDimensions() == 2 ) + { + vtkStringArray *filenames = vtkreader->GetFileNames(); + if ( filenames && filenames->GetNumberOfValues() > 1 ) + { + dataextent[4] = 0; + dataextent[5] = (int)filenames->GetNumberOfValues() - 1; + } + else + { + dataextent[4] = 0; + dataextent[5] = 0; + } + } + else + { + assert( image.GetNumberOfDimensions() == 3 ); + //this->FileDimensionality = 3; + dataextent[4] = 0; + dataextent[5] = dims[2] - 1; + } + //this->DataSpacing[0] = 1.; + //this->DataSpacing[1] = -1.; + //this->DataSpacing[2] = 1.; + + gdcm::PixelFormat pixeltype = image.GetPixelFormat(); + int datascalartype = VTK_VOID; + switch( pixeltype ) + { + case gdcm::PixelFormat::INT8: + datascalartype = VTK_CHAR; + break; + case gdcm::PixelFormat::UINT8: + datascalartype = VTK_UNSIGNED_CHAR; + break; + case gdcm::PixelFormat::INT16: + datascalartype = VTK_SHORT; + break; + case gdcm::PixelFormat::UINT16: + datascalartype = VTK_UNSIGNED_SHORT; + break; + case gdcm::PixelFormat::INT32: + datascalartype = VTK_INT; + break; + case gdcm::PixelFormat::UINT32: + datascalartype = VTK_UNSIGNED_INT; + break; + default: + ; + } + if( datascalartype == VTK_VOID ) + { + return 0; + } + + unsigned int numberOfScalarComponents = pixeltype.GetSamplesPerPixel(); + + vtkreader->SetDataExtent( dataextent ); + vtkreader->SetDataScalarType ( datascalartype ); + //vtkreader->SetShift( image.GetIntercept() ); + //vtkreader->SetScale( image.GetSlope() ); + vtkreader->SetNumberOfScalarComponents( numberOfScalarComponents ); + vtkreader->LoadOverlaysOff(); + if( image.GetNumberOfOverlays() ) + { + vtkreader->LoadOverlaysOn(); + } + + return 1; +} + +template +int TestvtkGDCMThreadedImageRead(const char *filename, bool verbose = false) +{ + TReader *reader = TReader::New(); + reader->FileLowerLeftOn(); + //reader->CanReadFile( filename ); + if( verbose) std::cerr << "Reading : " << filename << std::endl; + + const char *refimage = NULL; + if( gdcm::System::FileIsDirectory( filename ) ) + { + gdcm::Directory d; + d.Load( filename ); + gdcm::Directory::FilenamesType l = d.GetFilenames(); + const size_t nfiles = l.size(); + vtkStringArray *sarray = vtkStringArray::New(); + for(unsigned int i = 0; i < nfiles; ++i) + { + sarray->InsertNextValue( l[i] ); + } + assert( sarray->GetNumberOfValues() == (int)nfiles ); + reader->SetFileNames( sarray ); + sarray->Delete(); + refimage = sarray->GetValue( 0 ); // Ok since sarray is ref count + } + else + { + reader->SetFileName( filename ); + refimage = filename; + } + + // In all cases we need to explicitly say what the image type is: + if( !ExecuteInformation(refimage, reader) ) + { + std::cerr << "file: " << refimage << " is not an image. giving up" << std::endl; + reader->Delete(); + return 0; + } + + + ProgressObserver *obs = ProgressObserver::New(); + if( verbose ) + { + reader->AddObserver( vtkCommand::ProgressEvent, obs); + } + + reader->Update(); + obs->Delete(); + + //reader->GetOutput()->Print( cout ); + //reader->GetOutput(1)->Print( cout ); + + if( reader->GetNumberOfOverlays() ) + { + vtkPNGWriter *writer = vtkPNGWriter::New(); + writer->SetInput( reader->GetOutput(1) ); + const char subdir[] = "TestvtkGDCMThreadedImageReader"; + // Create directory first: + std::string tmpdir = gdcm::Testing::GetTempDirectory( subdir ); + if( !gdcm::System::FileIsDirectory( tmpdir.c_str() ) ) + { + gdcm::System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + std::string pngfile = gdcm::Testing::GetTempFilename( filename, subdir ); + //pngfile += vtksys::SystemTools::GetFilenameWithoutExtension( filename ); + pngfile += ".png"; + writer->SetFileName( pngfile.c_str() ); + if( verbose ) std::cerr << pngfile << std::endl; + //writer->Write(); + writer->Delete(); + } + +/* + vtkStructuredPointsWriter *writer = vtkStructuredPointsWriter::New(); + writer->SetInput( reader->GetOutput() ); + writer->SetFileName( "TestvtkGDCMThreadedImageReader.vtk" ); + writer->SetFileTypeToBinary(); + //writer->Write(); + writer->Delete(); +*/ + + bool compute = false; + if( verbose && compute ) + { +#if (VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 2 ) + double *s = reader->GetOutput()->GetScalarRange(); +#else + float *s = reader->GetOutput()->GetScalarRange(); +#endif + std::cout << s[0] << " " << s[1] << std::endl; + } + + reader->Delete(); + + return 0; +} + +int TestvtkGDCMThreadedImageReader(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestvtkGDCMThreadedImageRead(filename, true); + } + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestvtkGDCMThreadedImageRead( filename ); + ++i; + } + + return r; +} diff --git a/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMThreadedImageReader2.cxx b/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMThreadedImageReader2.cxx new file mode 100644 index 0000000..13718e9 --- /dev/null +++ b/gdcm/Utilities/VTK/Testing/Cxx/TestvtkGDCMThreadedImageReader2.cxx @@ -0,0 +1,262 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkGDCMThreadedImageReader2.h" +#include "vtkGDCMImageReader.h" +#include "vtkCommand.h" + +#include "gdcmDirectory.h" +#include "gdcmSystem.h" +#include "gdcmImageReader.h" +#include "gdcmTesting.h" + +#include "vtkPNGWriter.h" +#include "vtkStringArray.h" +#include "vtkStructuredPointsWriter.h" +#include "vtkImageData.h" +#if (VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 ) +#include +#endif + +class ProgressObserver : public vtkCommand +{ +public: + static ProgressObserver* New() { + return new ProgressObserver; + } + + virtual void Execute(vtkObject* caller, unsigned long event, void *callData) + { + (void)callData; + if( event == vtkCommand::ProgressEvent ) + { + std::cout << ((vtkGDCMThreadedImageReader2*)caller)->GetProgress() << std::endl; + } + } +}; + + +template +int ExecuteInformation(const char *filename, TReader *vtkreader) +{ + gdcm::ImageReader reader; + reader.SetFileName( filename ); + if( !reader.Read() ) + { + return 0; + } + const gdcm::Image &image = reader.GetImage(); + const unsigned int *dims = image.GetDimensions(); + + // Set the Extents. + assert( image.GetNumberOfDimensions() >= 2 ); + int dataextent[6] = {}; + dataextent[0] = 0; + dataextent[1] = dims[0] - 1; + dataextent[2] = 0; + dataextent[3] = dims[1] - 1; + if( image.GetNumberOfDimensions() == 2 ) + { + vtkStringArray *filenames = vtkreader->GetFileNames(); + if ( filenames && filenames->GetNumberOfValues() > 1 ) + { + dataextent[4] = 0; + dataextent[5] = (int)filenames->GetNumberOfValues() - 1; + } + else + { + dataextent[4] = 0; + dataextent[5] = 0; + } + } + else + { + assert( image.GetNumberOfDimensions() == 3 ); + //this->FileDimensionality = 3; + dataextent[4] = 0; + dataextent[5] = dims[2] - 1; + } + //this->DataSpacing[0] = 1.; + //this->DataSpacing[1] = -1.; + //this->DataSpacing[2] = 1.; + + gdcm::PixelFormat pixeltype = image.GetPixelFormat(); + int datascalartype = VTK_VOID; + switch( pixeltype ) + { + case gdcm::PixelFormat::INT8: + datascalartype = VTK_CHAR; + break; + case gdcm::PixelFormat::UINT8: + datascalartype = VTK_UNSIGNED_CHAR; + break; + case gdcm::PixelFormat::INT16: + datascalartype = VTK_SHORT; + break; + case gdcm::PixelFormat::UINT16: + datascalartype = VTK_UNSIGNED_SHORT; + break; + case gdcm::PixelFormat::INT32: + datascalartype = VTK_INT; + break; + case gdcm::PixelFormat::UINT32: + datascalartype = VTK_UNSIGNED_INT; + break; + default: + ; + } + if( datascalartype == VTK_VOID ) + { + return 0; + } + + unsigned int numberOfScalarComponents = pixeltype.GetSamplesPerPixel(); + + vtkreader->SetDataExtent( dataextent ); + vtkreader->SetDataScalarType ( datascalartype ); + //vtkreader->SetShift( image.GetIntercept() ); + //vtkreader->SetScale( image.GetSlope() ); + vtkreader->SetNumberOfScalarComponents( numberOfScalarComponents ); + vtkreader->LoadOverlaysOff(); + if( image.GetNumberOfOverlays() ) + { + vtkreader->LoadOverlaysOn(); + } + + return 1; +} + +template +int TestvtkGDCMThreadedImageRead2(const char *filename, bool verbose = false) +{ + TReader *reader = TReader::New(); + reader->FileLowerLeftOn(); + //reader->CanReadFile( filename ); + if( verbose) std::cerr << "Reading : " << filename << std::endl; + + const char *refimage = NULL; + if( gdcm::System::FileIsDirectory( filename ) ) + { + gdcm::Directory d; + d.Load( filename ); + gdcm::Directory::FilenamesType l = d.GetFilenames(); + const size_t nfiles = l.size(); + vtkStringArray *sarray = vtkStringArray::New(); + for(unsigned int i = 0; i < nfiles; ++i) + { + sarray->InsertNextValue( l[i] ); + } + assert( sarray->GetNumberOfValues() == (int)nfiles ); + reader->SetFileNames( sarray ); + sarray->Delete(); + refimage = sarray->GetValue( 0 ); // Ok since sarray is ref count + } + else + { + reader->SetFileName( filename ); + refimage = filename; + } + + // In all cases we need to explicitly say what the image type is: + if( !ExecuteInformation(refimage, reader) ) + { + std::cerr << "file: " << refimage << " is not an image. giving up" << std::endl; + reader->Delete(); + return 0; + } + + + ProgressObserver *obs = ProgressObserver::New(); + if( verbose ) + { + reader->AddObserver( vtkCommand::ProgressEvent, obs); + } + + reader->Update(); + obs->Delete(); + + //reader->GetOutput()->Print( cout ); + //reader->GetOutput(1)->Print( cout ); + + if( reader->GetNumberOfOverlays() ) + { + vtkPNGWriter *writer = vtkPNGWriter::New(); +#if (VTK_MAJOR_VERSION >= 6) + writer->SetInputConnection( reader->GetOutputPort(1) ); +#else + writer->SetInput( reader->GetOutput(1) ); +#endif + const char subdir[] = "TestvtkGDCMThreadedImageReader2"; + // Create directory first: + std::string tmpdir = gdcm::Testing::GetTempDirectory( subdir ); + if( !gdcm::System::FileIsDirectory( tmpdir.c_str() ) ) + { + gdcm::System::MakeDirectory( tmpdir.c_str() ); + //return 1; + } + std::string pngfile = gdcm::Testing::GetTempFilename( filename, subdir ); + //pngfile += vtksys::SystemTools::GetFilenameWithoutExtension( filename ); + pngfile += ".png"; + writer->SetFileName( pngfile.c_str() ); + if( verbose ) std::cerr << pngfile << std::endl; + //writer->Write(); + writer->Delete(); + } + +/* + vtkStructuredPointsWriter *writer = vtkStructuredPointsWriter::New(); + writer->SetInput( reader->GetOutput() ); + writer->SetFileName( "TestvtkGDCMThreadedImageReader2.vtk" ); + writer->SetFileTypeToBinary(); + //writer->Write(); + writer->Delete(); +*/ + + bool compute = false; + if( verbose && compute ) + { +#if (VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 2 ) + double *s = reader->GetOutput()->GetScalarRange(); +#else + float *s = reader->GetOutput()->GetScalarRange(); +#endif + std::cout << s[0] << " " << s[1] << std::endl; + } + + reader->Delete(); + + return 0; +} + +int TestvtkGDCMThreadedImageReader2(int argc, char *argv[]) +{ + if( argc == 2 ) + { + const char *filename = argv[1]; + return TestvtkGDCMThreadedImageRead2(filename, true); + } + + // else + gdcm::Trace::DebugOff(); + gdcm::Trace::WarningOff(); + int r = 0, i = 0; + const char *filename; + const char * const *filenames = gdcm::Testing::GetFileNames(); + while( (filename = filenames[i]) ) + { + r += TestvtkGDCMThreadedImageRead2( filename ); + ++i; + } + + return r; +} diff --git a/gdcm/Utilities/VTK/Testing/Cxx/TestvtkImageChangeInformation.cxx b/gdcm/Utilities/VTK/Testing/Cxx/TestvtkImageChangeInformation.cxx new file mode 100644 index 0000000..53c837a --- /dev/null +++ b/gdcm/Utilities/VTK/Testing/Cxx/TestvtkImageChangeInformation.cxx @@ -0,0 +1,87 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkGDCMImageReader.h" + +#include "vtkDirectory.h" +#include "vtkImageActor.h" +#include "vtkImageChangeInformation.h" +#include "vtkImageMapToWindowLevelColors.h" +#include "vtkRenderWindow.h" +#include "vtkRenderWindowInteractor.h" +#include "vtkRenderer.h" + +int TestvtkImageChangeInformation(int argc, char *argv[]) +{ + if( argc < 2 ) + { + std::cerr << "Need arg" << std::endl; + return 1; + } + const char *dirname = argv[1]; + + vtkDirectory * dir = vtkDirectory::New(); + int r = dir->Open( dirname ); + if( !r ) + { + std::cerr << "Cannot open dir:" << dirname << std::endl; + return 1; + } + vtkIdType nfiles = dir->GetNumberOfFiles(); + + vtkImageChangeInformation *ici = vtkImageChangeInformation::New(); + ici->SetOutputOrigin(0, 0, 0); + vtkImageMapToWindowLevelColors * windowlevel = vtkImageMapToWindowLevelColors::New(); + windowlevel->SetInput( ici->GetOutput() ); + vtkImageActor *imageactor = vtkImageActor::New(); + imageactor->SetInput( windowlevel->GetOutput() ); + + // Create the RenderWindow, Renderer and both Actors + vtkRenderer *ren = vtkRenderer::New(); + vtkRenderWindow *renWin = vtkRenderWindow::New(); + renWin->AddRenderer (ren); + + // Add the actors to the renderer, set the background and size + ren->AddActor (imageactor); + + double range[2]; + for ( vtkIdType file = 0; file < nfiles; ++file ) + { + vtkGDCMImageReader * reader = vtkGDCMImageReader::New(); + ici->SetInput( reader->GetOutput() ); + std::string filename = dir->GetFile(file); + if( filename.find( "dcm" ) != std::string::npos ) + { + std::string fullpath = dirname; + fullpath += "/"; + fullpath += filename; + std::cerr << "Processing: " << fullpath << std::endl; + + reader->SetFileName( fullpath.c_str() ); + //reader->Update(); + //ici->GetOutput()->Update(); // bad ! + ici->GetOutput()->GetScalarRange(range); + //reader->GetOutput()->GetScalarRange(range); + renWin->Render(); + std::cerr << "Range: " << range[0] << " " << range[1] << std::endl; + } + reader->Delete(); + } + + dir->Delete(); + ici->Delete(); + windowlevel->Delete(); + imageactor->Delete(); + + return 0; +} diff --git a/gdcm/Utilities/VTK/Testing/Java/CMakeLists.txt b/gdcm/Utilities/VTK/Testing/Java/CMakeLists.txt new file mode 100644 index 0000000..bd6ba94 --- /dev/null +++ b/gdcm/Utilities/VTK/Testing/Java/CMakeLists.txt @@ -0,0 +1,45 @@ +# Define the tests for vtkgdcm-java +set(VTKGDCM_JAVA_TEST_SRCS + TestvtkGDCMImageReader + ) + +set(classpath ${LIBRARY_OUTPUT_PATH}/vtkgdcm.jar${JavaProp_PATH_SEPARATOR}${LIBRARY_OUTPUT_PATH}/gdcm.jar${JavaProp_PATH_SEPARATOR}${VTK_JAVA_JAR}${JavaProp_PATH_SEPARATOR}${GDCM_VTK_JAVA_JAR}) + +if(IS_DIRECTORY ${VTK_DIR}) + if(IS_DIRECTORY ${VTK_DIR}/bin) + # this is a build-tree VTK + set(runtimepath "${VTK_DIR}/bin") + if(UNIX) + get_filename_component(dummyjava ${JAVA_MAWT_LIBRARY} PATH) + set(runtimepath "${runtimepath}:${JAVA_LIBRARY_PATH}:${dummyjava}") + endif() + endif() +endif() + +set(classfilesdep) + +foreach(example ${VTKGDCM_JAVA_TEST_SRCS}) + add_custom_command( + OUTPUT ${EXECUTABLE_OUTPUT_PATH}/${example}.class + COMMAND ${Java_JAVAC_EXECUTABLE} ARGS -source 1.5 -target 1.5 -classpath "${classpath}" + ${CMAKE_CURRENT_SOURCE_DIR}/${example}.java -d ${EXECUTABLE_OUTPUT_PATH} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${example}.java + COMMENT "javac ${example}.java" + ) + list(APPEND classfilesdep ${EXECUTABLE_OUTPUT_PATH}/${example}.class) + set_source_files_properties(${EXECUTABLE_OUTPUT_PATH}/${example}.class PROPERTIES RUNTIMEPATH "${runtimepath}") + set_source_files_properties(${EXECUTABLE_OUTPUT_PATH}/${example}.class PROPERTIES CLASSPATH "${classpath}") + if(GDCM_WRAP_JAVA) + ADD_JAVA_TEST(${example}Java ${EXECUTABLE_OUTPUT_PATH}/${example}) + endif() + +endforeach() + +# 3. ok now add the target +add_custom_target(VTKGDCMJavaTests ALL + DEPENDS ${classfilesdep} + COMMENT "building gdcm java vtk tests" +) +add_dependencies(VTKGDCMJavaTests VTKGDCMJavaJar + GDCMJavaJar) diff --git a/gdcm/Utilities/VTK/Testing/Java/TestvtkGDCMImageReader.java b/gdcm/Utilities/VTK/Testing/Java/TestvtkGDCMImageReader.java new file mode 100644 index 0000000..3bdfd62 --- /dev/null +++ b/gdcm/Utilities/VTK/Testing/Java/TestvtkGDCMImageReader.java @@ -0,0 +1,43 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +import gdcm.*; +import vtk.*; + +/* + */ +public class TestvtkGDCMImageReader +{ + static { + System.loadLibrary("vtkCommonJava"); + System.loadLibrary("vtkFilteringJava"); + System.loadLibrary("vtkIOJava"); + System.loadLibrary("vtkgdcmJava"); + } + + public static void main(String[] args) + { + long nfiles = Testing.GetNumberOfFileNames(); + Trace.DebugOff(); + Trace.WarningOff(); + + for( long i = 0; i < nfiles; ++i ) + { + String filename = Testing.GetFileName( i ); + //System.out.println("Success reading: " + filename ); + vtkGDCMImageReader reader = new vtkGDCMImageReader(); + reader.SetFileName( filename ); + reader.Update(); + } + } +} diff --git a/gdcm/Utilities/VTK/Testing/Python/CMakeLists.txt b/gdcm/Utilities/VTK/Testing/Python/CMakeLists.txt new file mode 100644 index 0000000..5e0c328 --- /dev/null +++ b/gdcm/Utilities/VTK/Testing/Python/CMakeLists.txt @@ -0,0 +1,46 @@ +# VTK-Python testing +if(GDCM_WRAP_PYTHON) + if(VTK_PYTHONPATH_DIRS) + if(WIN32) + #message(${VTK_PYTHONPATH_DIRS}) + #string(REGEX REPLACE ";" ";" UNIX_VTK_PYTHONPATH_DIRS "${VTK_PYTHONPATH_DIRS}") + set(UNIX_VTK_PYTHONPATH_DIRS "${VTK_PYTHONPATH_DIRS}") + else() + string(REGEX REPLACE ";" ":" UNIX_VTK_PYTHONPATH_DIRS "${VTK_PYTHONPATH_DIRS}") + endif() + else() + # if VTK_PYTHONPATH_DIRS is not given (very old VTK) then simply hope the user set his pythonpath properly: + # set(UNIX_VTK_PYTHONPATH_DIRS "$ENV{PYTHONPATH}") + # previous solution was not safe, let's hope the following are set properly: + if(WIN32) + set(PATH_SEPARATOR ";") + else() + set(PATH_SEPARATOR ":") + endif() + if(VTK_SOURCE_DIR) + set(UNIX_VTK_PYTHONPATH_DIRS "${VTK_SOURCE_DIR}/Wrapping/Python${PATH_SEPARATOR}${VTK_LIBRARY_DIRS}") + else() + # FIXME: hardcoded + set(UNIX_VTK_PYTHONPATH_DIRS "/usr/local/src/vtk/build/Wrapping/Python${PATH_SEPARATOR}${VTK_LIBRARY_DIRS}") + endif() + endif() + set(VTK_PYTHON_TESTS + TestvtkGDCMImageReader + TestvtkGDCMImageReader2 + TestvtkGDCMImageWriter + TestMultiframeGrayscaleWordSecondaryCaptureImageStorage + ) + if(GDCM_HAVE_PTHREAD_H) + set(VTK_PYTHON_TESTS ${VTK_PYTHON_TESTS} + #TestvtkGDCMThreadedImageReader + TestvtkGDCMThreadedImageReader2 + ) + endif() + + foreach(test ${VTK_PYTHON_TESTS}) + #message(${UNIX_VTK_PYTHONPATH_DIRS}) + set_source_files_properties(${test}.py PROPERTIES PYTHONPATH "${UNIX_VTK_PYTHONPATH_DIRS}") + ADD_PYTHON_TEST(${test}Python ${test}.py ${GDCM_DATA_ROOT}/test.acr) + endforeach() + +endif() diff --git a/gdcm/Utilities/VTK/Testing/Python/TestMultiframeGrayscaleWordSecondaryCaptureImageStorage.py b/gdcm/Utilities/VTK/Testing/Python/TestMultiframeGrayscaleWordSecondaryCaptureImageStorage.py new file mode 100644 index 0000000..09225a8 --- /dev/null +++ b/gdcm/Utilities/VTK/Testing/Python/TestMultiframeGrayscaleWordSecondaryCaptureImageStorage.py @@ -0,0 +1,46 @@ +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +import vtkgdcm +import vtk + +from vtk.util.misc import vtkGetDataRoot + +#print vtkGetDataRoot() +VTK_DATA_ROOT = vtkGetDataRoot() +print(VTK_DATA_ROOT) + +v16 = vtk.vtkVolume16Reader() +v16.SetDataDimensions(64, 64) +v16.SetDataByteOrderToLittleEndian() +v16.SetFilePrefix(VTK_DATA_ROOT + "/Data/headsq/quarter") +v16.SetImageRange(1, 93) +v16.SetDataSpacing(3.2, 3.2, 1.5) +#v16.Update() +# +#print v16.GetOutput() + +w = vtkgdcm.vtkGDCMImageWriter() +w.SetInput( v16.GetOutput() ) +w.SetFileDimensionality( 3 ) +w.SetFileName( "sc.dcm" ) +w.Write() + +# Now pretend this is an MR Image Storage: +# Since image is 3D it should default to the new Enhance MR Image Storage: +med = w.GetMedicalImageProperties() +med.SetModality( "MR" ) + +w.SetFileName( "mr.dcm" ) +w.Write() diff --git a/gdcm/Utilities/VTK/Testing/Python/TestvtkGDCMImageReader.py b/gdcm/Utilities/VTK/Testing/Python/TestvtkGDCMImageReader.py new file mode 100644 index 0000000..f010f90 --- /dev/null +++ b/gdcm/Utilities/VTK/Testing/Python/TestvtkGDCMImageReader.py @@ -0,0 +1,60 @@ +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +# Simply check that we can read mr.001 from VTKData + +import vtkgdcm +import vtk + +from vtk.util.misc import vtkGetDataRoot +VTK_DATA_ROOT = vtkGetDataRoot() + +r = vtkgdcm.vtkGDCMImageReader() +r.SetFileName( VTK_DATA_ROOT + "/Data/mr.001" ) +r.Update() + +#print r.GetOutput() + +# Pixel Spacing +# 0.78125, 0.78125, 0 + +# Image Position (Patient) +# -13.3034, -80.8219, 119.178 + +# try to rewrite it: +w = vtkgdcm.vtkGDCMImageWriter() +w.SetInput( r.GetOutput() ) +w.SetMedicalImageProperties( r.GetMedicalImageProperties() ) +w.SetDirectionCosines( r.GetDirectionCosines() ) +w.SetFileName( "mr.001.dcm" ) +w.Write() + +# beach.tif +#tiffreader = vtk.vtkTIFFReader() +#tiffreader.SetFileName( VTK_DATA_ROOT + "/Data/beach.tif" ) +#tiffreader.Update() +# print tiffreader.GetOutput() +# -> TIFF reader was apparently broken in VTK until some very recent +# version and thus image appear upside down, unless you also update VTKData :( + +jpegreader = vtk.vtkJPEGReader() +jpegreader.SetFileName( VTK_DATA_ROOT + "/Data/beach.jpg" ) +#jpegreader.Update() + +# Need a new writer otherwise MedicalImageProperties are re-used... +w2 = vtkgdcm.vtkGDCMImageWriter() +#w2.SetInput( tiffreader.GetOutput() ) +w2.SetInput( jpegreader.GetOutput() ) +w2.SetFileName( "beach.dcm" ) +w2.Write() diff --git a/gdcm/Utilities/VTK/Testing/Python/TestvtkGDCMImageReader2.py b/gdcm/Utilities/VTK/Testing/Python/TestvtkGDCMImageReader2.py new file mode 100644 index 0000000..562907a --- /dev/null +++ b/gdcm/Utilities/VTK/Testing/Python/TestvtkGDCMImageReader2.py @@ -0,0 +1,41 @@ +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +# Simply check that we can read mr.001 from VTKData + +import vtkgdcm +import vtk + +from vtk.util.misc import vtkGetDataRoot +VTK_DATA_ROOT = vtkGetDataRoot() + +fns = vtk.vtkStringArray() +fns.InsertNextValue( VTK_DATA_ROOT + "/Data/mr.001" ) +fns.InsertNextValue( VTK_DATA_ROOT + "/Data/mr.001" ) +fns.InsertNextValue( VTK_DATA_ROOT + "/Data/mr.001" ) + +r = vtkgdcm.vtkGDCMImageReader() +r.SetFileNames( fns ) +r.Update() + +print r.GetOutput() + +# try to rewrite it: +w = vtkgdcm.vtkGDCMImageWriter() +w.SetFileDimensionality( 3 ) +w.SetInput( r.GetOutput() ) +w.SetMedicalImageProperties( r.GetMedicalImageProperties() ) +w.SetDirectionCosines( r.GetDirectionCosines() ) +w.SetFileName( "mr3.001.dcm" ) +w.Write() diff --git a/gdcm/Utilities/VTK/Testing/Python/TestvtkGDCMImageWriter.py b/gdcm/Utilities/VTK/Testing/Python/TestvtkGDCMImageWriter.py new file mode 100644 index 0000000..7474939 --- /dev/null +++ b/gdcm/Utilities/VTK/Testing/Python/TestvtkGDCMImageWriter.py @@ -0,0 +1,45 @@ +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +import vtkgdcm +import os,sys + +def PrintProgress(object, event): + assert event == "ProgressEvent" + print("Progress:", object.GetProgress()) + +if __name__ == "__main__": + try: + filename = os.sys.argv[1] + except: + # failure + print("Need a filename") + sys.exit(1) + + # setup reader + r = vtkgdcm.vtkGDCMImageReader() + + r.SetFileName( filename ) + r.AddObserver("ProgressEvent", PrintProgress) + r.Update() + print(r.GetOutput()) + # Write output + writer = vtkgdcm.vtkGDCMImageWriter() + writer.SetInput( r.GetOutput() ) + writer.SetMedicalImageProperties( r.GetMedicalImageProperties() ) + writer.SetFileName( "TestvtkGDCMImageWriterPython.dcm" ) + writer.Write() + + # Test succeed ? + #sys.exit(sucess != 1) diff --git a/gdcm/Utilities/VTK/Testing/Python/TestvtkGDCMThreadedImageReader.py b/gdcm/Utilities/VTK/Testing/Python/TestvtkGDCMThreadedImageReader.py new file mode 100644 index 0000000..acb1be3 --- /dev/null +++ b/gdcm/Utilities/VTK/Testing/Python/TestvtkGDCMThreadedImageReader.py @@ -0,0 +1,121 @@ +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +# This is important for now to load the vtkgdcm module first +import vtkgdcm +from vtk import vtkImageGradient +from vtk import vtkMultiThreader +from vtk import vtkDirectory +from vtk import vtkStructuredPointsWriter +from vtk.util import vtkConstants as vtkType +from vtkgdcm import vtkStringArray +import gdcm # for gdcm.Directory +import os,sys + +def PrintProgress(object, event): + assert event == "ProgressEvent" + print "Progress:", object.GetProgress() + +# Helper function to extract image dimension and type +# this info could also be coming from a database for example instead of read from a particular file +def ExecuteInformation(reader, filename, dimz = 1): + import gdcm + reffile = filename # filenames.GetValue(0) # Take first image as reference + #print reader + r = gdcm.ImageReader() + r.SetFileName( reffile ) + sucess = r.Read() + assert sucess + #print r.GetImage().Print() + image = r.GetImage() + assert image.GetNumberOfDimensions() == 2 or image.GetNumberOfDimensions() == 3 + dims = [0,0,0] + dims[0] = image.GetDimension(0) + dims[1] = image.GetDimension(1) + dims[2] = dimz # filenames.GetNumberOfValues() + #print dims + #print image.GetPixelFormat().GetTPixelFormat() + pixelformat = image.GetPixelFormat().GetScalarType() + datascalartype = vtkType.VTK_VOID # dummy should not happen + if pixelformat == gdcm.PixelFormat.INT8: + datascalartype = vtkType.VTK_SIGNED_CHAR + elif pixelformat == gdcm.PixelFormat.UINT8: + datascalartype = vtkType.VTK_UNSIGNED_CHAR + elif pixelformat == gdcm.PixelFormat.INT16: + datascalartype = vtkType.VTK_SHORT + elif pixelformat == gdcm.PixelFormat.UINT16: + datascalartype = vtkType.VTK_UNSIGNED_SHORT + else: + print "Unhandled PixelFormat: ", pixelformat + sys.exit(1) + #print datascalartype + numberOfScalarComponents = image.GetPixelFormat().GetSamplesPerPixel() + #print numberOfScalarComponents + #print gdcm.PhotometricInterpretation.GetPIString( image.GetPhotometricInterpretation().PIType() ) + #reader.SetDataExtent( dataextent ); + reader.SetDataExtent( 0, dims[0] - 1, 0, dims[1] - 1, 0, dims[2] - 1 ) + reader.SetDataScalarType ( datascalartype ) + reader.SetNumberOfScalarComponents( numberOfScalarComponents ) + +if __name__ == "__main__": + try: + filename = os.sys.argv[1] + except: + # failure + print "Need a filename" + sys.exit(1) + + # setup reader + r = vtkgdcm.vtkGDCMThreadedImageReader() + r.FileLowerLeftOn() + #dir = vtkDirectory() + dir = gdcm.Directory() + + # Did user pass in a directory: + system = gdcm.System() + if system.FileIsDirectory( filename ): + nfiles = dir.Load( filename ) + files = dir.GetFilenames() + # Need to construct full path out of the simple filename + fullpath = vtkStringArray() + for file in files: + fullpath.InsertNextValue( file ) + r.SetFileNames( fullpath ) + assert fullpath.GetNumberOfValues() # Need at least one file + ExecuteInformation(r, fullpath.GetValue(0), fullpath.GetNumberOfValues() ) + r.AddObserver("ProgressEvent", PrintProgress) + r.Update() + #print r.GetOutput() + #print vtkMultiThreader.GetGlobalDefaultNumberOfThreads() + #g = vtkImageGradient() + #g.SetInput( r.GetOutput() ) + #g.AddObserver("ProgressEvent", PrintProgress) + #g.Update() + # Write output + writer = vtkStructuredPointsWriter() + writer.SetInput( r.GetOutput() ) + writer.SetFileName( "TestvtkGDCMThreadedImageReaderPython.vtk" ) + writer.SetFileTypeToBinary() + #writer.Write() + else: + # TODO + r.SetFileName( filename ) + ExecuteInformation(r, filename ) + r.Update() + print r.GetOutput() + #sys.exit(1) + + + # Test succeed ? + #sys.exit(sucess != 1) diff --git a/gdcm/Utilities/VTK/Testing/Python/TestvtkGDCMThreadedImageReader2.py b/gdcm/Utilities/VTK/Testing/Python/TestvtkGDCMThreadedImageReader2.py new file mode 100644 index 0000000..163f031 --- /dev/null +++ b/gdcm/Utilities/VTK/Testing/Python/TestvtkGDCMThreadedImageReader2.py @@ -0,0 +1,95 @@ +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +# This used to be important to load the vtkgdcm module first +# (VTK 5.2 contains the proper patch now) +import vtkgdcm +from vtkgdcm import vtkStringArray +from vtk.util import vtkConstants as vtkType +import gdcm # for gdcm.Directory +import os,sys + +def PrintProgress(object, event): + assert event == "ProgressEvent" + print("Progress:", object.GetProgress()) + +if __name__ == "__main__": + root = gdcm.Testing.GetDataExtraRoot() + dirname = os.path.join(root, "gdcmSampleData/ForSeriesTesting/Perfusion/images" ) + print(dirname) + + # setup reader + r = vtkgdcm.vtkGDCMThreadedImageReader2() + dir = gdcm.Directory() + + # Did user pass in a directory: + system = gdcm.System() + if system.FileIsDirectory( dirname ): + nfiles = dir.Load( dirname ) + files = dir.GetFilenames() + # Need to construct full path out of the simple filename + fullpath = vtkStringArray() + for file in files: + fullpath.InsertNextValue( file ) + r.SetFileNames( fullpath ) + assert fullpath.GetNumberOfValues() # Need at least one file + # Now specify the property of the image: + """ + Note (MM), I verified that even if there are multiple Series in this Study they are all compatible and thus + can be loaded as a fake 3D (VTK) volume, only origin is changing & shift/scale . + See: + $ for i in `ls ForSeriesTesting/Perfusion/images/1.*`; do gdcminfo $i; done | sort | uniq + """ + """ + gdcminfo ForSeriesTesting/Perfusion/images/1.3.46.670589.5.2.14.2198403904.1100092395.157798.dcm + MediaStorage is 1.2.840.10008.5.1.4.1.1.4 [MR Image Storage] + NumberOfDimensions: 2 + Dimensions: (256,256) + Origin: (-115,-125.969,-17.068) + Spacing: (0.898438,0.898438,5.5) + DirectionCosines: (1,0,0,0,0.949631,-0.31337) + Rescale Intercept/Slope: (-1985.36,1) + SamplesPerPixel :1 + BitsAllocated :16 + BitsStored :12 + HighBit :11 + PixelRepresentation:0 + Orientation Label: AXIAL + """ + dims = [0,0,0] + dims[0] = 256 + dims[1] = 256 + dims[2] = nfiles + # Even if Stored Pixel is UINT16, the World Value Pixel is Float + datascalartype = vtkType.VTK_FLOAT + spacing = [0.898438,0.898438,5.5] + origin = [-115,-125.969,-17.068] + intercept_slope = [-1985.36,1] + numberOfScalarComponents = 1 + r.SetDataExtent( 0, dims[0] - 1, 0, dims[1] - 1, 0, dims[2] - 1 ) + r.SetDataScalarType ( datascalartype ) + r.SetNumberOfScalarComponents( numberOfScalarComponents ) + r.SetDataOrigin( origin ) + r.SetDataSpacing( spacing ) + # Useless only for backward compatibily, the real shift/scale will be read from files: + #r.SetShift( intercept_slope[0] ) + #r.SetScale( intercept_slope[1] ) + + # Setup the ProgressEvent + r.AddObserver("ProgressEvent", PrintProgress) + r.Update() + print(r.GetOutput()) + + # Test succeed ? + #sys.exit(sucess != 1) diff --git a/gdcm/Utilities/VTK/VTK4/vtkMedicalImageProperties.cxx b/gdcm/Utilities/VTK/VTK4/vtkMedicalImageProperties.cxx new file mode 100644 index 0000000..34c55a7 --- /dev/null +++ b/gdcm/Utilities/VTK/VTK4/vtkMedicalImageProperties.cxx @@ -0,0 +1,1020 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/*========================================================================= + + Portions of this file are subject to the VTK Toolkit Version 3 copyright. + + Program: Visualization Toolkit + Module: vtkMedicalImageProperties.cxx,v + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkMedicalImageProperties.h" +#include "vtkObjectFactory.h" + +#include +#include +#include +#include +#include // for strftime +#include // for isdigit +#include + +//---------------------------------------------------------------------------- +vtkCxxRevisionMacro(vtkMedicalImageProperties, "1.21") +vtkStandardNewMacro(vtkMedicalImageProperties) + +static const char *vtkMedicalImagePropertiesOrientationString[] = { + "AXIAL", + "CORONAL", + "SAGITTAL", + NULL +}; + + +//---------------------------------------------------------------------------- +class vtkMedicalImagePropertiesInternals +{ +public: + class WindowLevelPreset + { + public: + double Window; + double Level; + std::string Comment; + }; + + class UserDefinedValue + { + public: + UserDefinedValue(const char *name = 0, const char *value = 0):Name(name ? name : ""),Value(value ? value : "") {} + std::string Name; + std::string Value; + // order for the std::set + bool operator<(const UserDefinedValue &udv) const + { + return Name < udv.Name; + } + }; + typedef std::set< UserDefinedValue > UserDefinedValues; + UserDefinedValues Mapping; + void AddUserDefinedValue(const char *name, const char *value) + { + if( name && *name && value && *value ) + { + Mapping.insert( UserDefinedValues::value_type(name, value) ); + } + // else raise a warning ? + } + const char *GetUserDefinedValue(const char *name) const + { + if( name && *name ) + { + UserDefinedValue key(name); + UserDefinedValues::const_iterator it = Mapping.find( key ); + assert( strcmp(it->Name.c_str(), name) == 0 ); + return it->Value.c_str(); + } + return NULL; + } + unsigned int GetNumberOfUserDefinedValues() const + { + return Mapping.size(); + } + const char *GetUserDefinedNameByIndex(unsigned int idx) + { + if( idx < Mapping.size() ) + { + UserDefinedValues::const_iterator it = Mapping.begin(); + while( idx ) + { + it++; + idx--; + } + return it->Name.c_str(); + } + return NULL; + } + const char *GetUserDefinedValueByIndex(unsigned int idx) + { + if( idx < Mapping.size() ) + { + UserDefinedValues::const_iterator it = Mapping.begin(); + while( idx ) + { + it++; + idx--; + } + return it->Value.c_str(); + } + return NULL; + } + + typedef std::vector WindowLevelPresetPoolType; + typedef std::vector::iterator WindowLevelPresetPoolIterator; + + WindowLevelPresetPoolType WindowLevelPresetPool; + +// It is also useful to have a mapping from DICOM UID to slice id, for application like VolView + typedef std::map< unsigned int, std::string> SliceUIDType; + typedef std::vector< SliceUIDType > VolumeSliceUIDType; + VolumeSliceUIDType UID; + void SetNumberOfVolumes(unsigned int n) + { + UID.resize(n); + Orientation.resize(n); + } + void SetUID(unsigned int vol, unsigned int slice, const char *uid) + { + SetNumberOfVolumes( vol + 1 ); + UID[vol][slice] = uid; + } + const char *GetUID(unsigned int vol, unsigned int slice) + { + assert( vol < UID.size() ); + assert( UID[vol].find(slice) != UID[vol].end() ); + //if( UID[vol].find(slice) == UID[vol].end() ) + // { + // this->Print( cerr, vtkIndent() ); + // } + return UID[vol].find(slice)->second.c_str(); + } + // Extensive lookup + int FindSlice(int &vol, const char *uid) + { + vol = -1; + for(unsigned int v = 0; v < UID.size(); ++v ) + { + SliceUIDType::const_iterator cit = UID[v].begin(); + while (cit != UID[v].end()) + { + if (cit->second == uid) + { + vol = v; + return (int)(cit->first); + } + ++cit; + } + } + return -1; // volume not found. + } + int GetSlice(unsigned int vol, const char *uid) + { + assert( vol < UID.size() ); + SliceUIDType::const_iterator cit = UID[vol].begin(); + while (cit != UID[vol].end()) + { + if (cit->second == uid) return (int)(cit->first); + ++cit; + } + return -1; // uid not found. + } + void Print(ostream &os, vtkIndent indent) + { + os << indent << "WindowLevel: \n"; + for( WindowLevelPresetPoolIterator it = WindowLevelPresetPool.begin(); it != WindowLevelPresetPool.end(); ++it ) + { + const WindowLevelPreset &wlp = *it; + os << indent << "Window:" << wlp.Window << endl; + os << indent << "Level:" << wlp.Level << endl; + os << indent << "Comment:" << wlp.Comment << endl; + } + os << indent << "UID(s): "; + for( VolumeSliceUIDType::const_iterator it = UID.begin(); + it != UID.end(); + ++it) + { + for( SliceUIDType::const_iterator it2 = it->begin(); + it2 != it->end(); + ++it2) + { + os << indent << it2->first << " " << it2->second << "\n"; + } + } + os << indent << "Orientation(s): "; + for( std::vector::const_iterator it = Orientation.begin(); + it != Orientation.end(); ++it) + { + os << indent << vtkMedicalImageProperties::GetStringFromOrientationType(*it) << endl; + } + } + std::vector Orientation; + void SetOrientation(unsigned int vol, unsigned int ori) + { + // see SetNumberOfVolumes for allocation + assert( ori <= vtkMedicalImageProperties::SAGITTAL ); + Orientation[vol] = ori; + } + unsigned int GetOrientation(unsigned int vol) + { + assert( vol < Orientation.size() ); + const unsigned int &val = Orientation[vol]; + assert( val <= vtkMedicalImageProperties::SAGITTAL ); + return val; + } + void DeepCopy(vtkMedicalImagePropertiesInternals *p) + { + WindowLevelPresetPool = p->WindowLevelPresetPool; + UID = p->UID; + Orientation = p->Orientation; + } +}; + +//---------------------------------------------------------------------------- +vtkMedicalImageProperties::vtkMedicalImageProperties() +{ + this->Internals = new vtkMedicalImagePropertiesInternals; + + this->StudyDate = NULL; + this->AcquisitionDate = NULL; + this->StudyTime = NULL; + this->AcquisitionTime = NULL; + this->ConvolutionKernel = NULL; + this->EchoTime = NULL; + this->EchoTrainLength = NULL; + this->Exposure = NULL; + this->ExposureTime = NULL; + this->GantryTilt = NULL; + this->ImageDate = NULL; + this->ImageNumber = NULL; + this->ImageTime = NULL; + this->InstitutionName = NULL; + this->KVP = NULL; + this->ManufacturerModelName = NULL; + this->Manufacturer = NULL; + this->Modality = NULL; + this->PatientAge = NULL; + this->PatientBirthDate = NULL; + this->PatientID = NULL; + this->PatientName = NULL; + this->PatientSex = NULL; + this->RepetitionTime = NULL; + this->SeriesDescription = NULL; + this->SeriesNumber = NULL; + this->SliceThickness = NULL; + this->StationName = NULL; + this->StudyDescription = NULL; + this->StudyID = NULL; + this->XRayTubeCurrent = NULL; +} + +//---------------------------------------------------------------------------- +vtkMedicalImageProperties::~vtkMedicalImageProperties() +{ + if (this->Internals) + { + delete this->Internals; + this->Internals = NULL; + } + + this->Clear(); +} + +//---------------------------------------------------------------------------- +void vtkMedicalImageProperties::AddUserDefinedValue(const char *name, const char *value) +{ + this->Internals->AddUserDefinedValue(name, value); +} + +//---------------------------------------------------------------------------- +const char *vtkMedicalImageProperties::GetUserDefinedValue(const char *name) +{ + return this->Internals->GetUserDefinedValue(name); +} + +//---------------------------------------------------------------------------- +unsigned int vtkMedicalImageProperties::GetNumberOfUserDefinedValues() +{ + return this->Internals->GetNumberOfUserDefinedValues(); +} + +//---------------------------------------------------------------------------- +const char *vtkMedicalImageProperties::GetUserDefinedValueByIndex(unsigned int idx) +{ + return this->Internals->GetUserDefinedValueByIndex(idx); +} + +//---------------------------------------------------------------------------- +const char *vtkMedicalImageProperties::GetUserDefinedNameByIndex(unsigned int idx) +{ + return this->Internals->GetUserDefinedNameByIndex(idx); +} + +//---------------------------------------------------------------------------- +void vtkMedicalImageProperties::Clear() +{ + this->SetStudyDate(NULL); + this->SetAcquisitionDate(NULL); + this->SetStudyTime(NULL); + this->SetAcquisitionTime(NULL); + this->SetConvolutionKernel(NULL); + this->SetEchoTime(NULL); + this->SetEchoTrainLength(NULL); + this->SetExposure(NULL); + this->SetExposureTime(NULL); + this->SetGantryTilt(NULL); + this->SetImageDate(NULL); + this->SetImageNumber(NULL); + this->SetImageTime(NULL); + this->SetInstitutionName(NULL); + this->SetKVP(NULL); + this->SetManufacturerModelName(NULL); + this->SetManufacturer(NULL); + this->SetModality(NULL); + this->SetPatientAge(NULL); + this->SetPatientBirthDate(NULL); + this->SetPatientID(NULL); + this->SetPatientName(NULL); + this->SetPatientSex(NULL); + this->SetRepetitionTime(NULL); + this->SetSeriesDescription(NULL); + this->SetSeriesNumber(NULL); + this->SetSliceThickness(NULL); + this->SetStationName(NULL); + this->SetStudyDescription(NULL); + this->SetStudyID(NULL); + this->SetXRayTubeCurrent(NULL); + + this->RemoveAllWindowLevelPresets(); +} + +//---------------------------------------------------------------------------- +void vtkMedicalImageProperties::DeepCopy(vtkMedicalImageProperties *p) +{ + if (p == NULL) + { + return; + } + + this->Clear(); + + this->SetStudyDate(p->GetStudyDate()); + this->SetAcquisitionDate(p->GetAcquisitionDate()); + this->SetStudyTime(p->GetStudyTime()); + this->SetAcquisitionTime(p->GetAcquisitionTime()); + this->SetConvolutionKernel(p->GetConvolutionKernel()); + this->SetEchoTime(p->GetEchoTime()); + this->SetEchoTrainLength(p->GetEchoTrainLength()); + this->SetExposure(p->GetExposure()); + this->SetExposureTime(p->GetExposureTime()); + this->SetGantryTilt(p->GetGantryTilt()); + this->SetImageDate(p->GetImageDate()); + this->SetImageNumber(p->GetImageNumber()); + this->SetImageTime(p->GetImageTime()); + this->SetInstitutionName(p->GetInstitutionName()); + this->SetKVP(p->GetKVP()); + this->SetManufacturerModelName(p->GetManufacturerModelName()); + this->SetManufacturer(p->GetManufacturer()); + this->SetModality(p->GetModality()); + this->SetPatientAge(p->GetPatientAge()); + this->SetPatientBirthDate(p->GetPatientBirthDate()); + this->SetPatientID(p->GetPatientID()); + this->SetPatientName(p->GetPatientName()); + this->SetPatientSex(p->GetPatientSex()); + this->SetRepetitionTime(p->GetRepetitionTime()); + this->SetSeriesDescription(p->GetSeriesDescription()); + this->SetSeriesNumber(p->GetSeriesNumber()); + this->SetSliceThickness(p->GetSliceThickness()); + this->SetStationName(p->GetStationName()); + this->SetStudyDescription(p->GetStudyDescription()); + this->SetStudyID(p->GetStudyID()); + this->SetXRayTubeCurrent(p->GetXRayTubeCurrent()); + + this->Internals->DeepCopy( p->Internals ); +} + +//---------------------------------------------------------------------------- +void vtkMedicalImageProperties::AddWindowLevelPreset( + double w, double l) +{ + if (!this->Internals || this->HasWindowLevelPreset(w, l)) + { + return; + } + + vtkMedicalImagePropertiesInternals::WindowLevelPreset preset; + preset.Window = w; + preset.Level = l; + this->Internals->WindowLevelPresetPool.push_back(preset); +} + +//---------------------------------------------------------------------------- +int vtkMedicalImageProperties::HasWindowLevelPreset(double w, double l) +{ + if (this->Internals) + { + vtkMedicalImagePropertiesInternals::WindowLevelPresetPoolIterator it = + this->Internals->WindowLevelPresetPool.begin(); + vtkMedicalImagePropertiesInternals::WindowLevelPresetPoolIterator end = + this->Internals->WindowLevelPresetPool.end(); + for (; it != end; ++it) + { + if ((*it).Window == w && (*it).Level == l) + { + return 1; + } + } + } + return 0; +} + +//---------------------------------------------------------------------------- +void vtkMedicalImageProperties::RemoveWindowLevelPreset(double w, double l) +{ + if (this->Internals) + { + vtkMedicalImagePropertiesInternals::WindowLevelPresetPoolIterator it = + this->Internals->WindowLevelPresetPool.begin(); + vtkMedicalImagePropertiesInternals::WindowLevelPresetPoolIterator end = + this->Internals->WindowLevelPresetPool.end(); + for (; it != end; ++it) + { + if ((*it).Window == w && (*it).Level == l) + { + this->Internals->WindowLevelPresetPool.erase(it); + break; + } + } + } +} + +//---------------------------------------------------------------------------- +void vtkMedicalImageProperties::RemoveAllWindowLevelPresets() +{ + if (this->Internals) + { + this->Internals->WindowLevelPresetPool.clear(); + } +} + +//---------------------------------------------------------------------------- +int vtkMedicalImageProperties::GetNumberOfWindowLevelPresets() +{ + return this->Internals ? this->Internals->WindowLevelPresetPool.size() : 0; +} + +//---------------------------------------------------------------------------- +int vtkMedicalImageProperties::GetNthWindowLevelPreset( + int idx, double *w, double *l) +{ + if (this->Internals && + idx >= 0 && idx < this->GetNumberOfWindowLevelPresets()) + { + *w = this->Internals->WindowLevelPresetPool[idx].Window; + *l = this->Internals->WindowLevelPresetPool[idx].Level; + return 1; + } + return 0; +} + +//---------------------------------------------------------------------------- +double* vtkMedicalImageProperties::GetNthWindowLevelPreset(int idx) + +{ + static double wl[2]; + if (this->GetNthWindowLevelPreset(idx, wl, wl + 1)) + { + return wl; + } + return NULL; +} + +//---------------------------------------------------------------------------- +const char* vtkMedicalImageProperties::GetNthWindowLevelPresetComment( + int idx) +{ + if (this->Internals && + idx >= 0 && idx < this->GetNumberOfWindowLevelPresets()) + { + return this->Internals->WindowLevelPresetPool[idx].Comment.c_str(); + } + return NULL; +} + +//---------------------------------------------------------------------------- +void vtkMedicalImageProperties::SetNthWindowLevelPresetComment( + int idx, const char *comment) +{ + if (this->Internals && + idx >= 0 && idx < this->GetNumberOfWindowLevelPresets()) + { + this->Internals->WindowLevelPresetPool[idx].Comment = + (comment ? comment : ""); + } +} + +//---------------------------------------------------------------------------- +const char *vtkMedicalImageProperties::GetInstanceUIDFromSliceID( + int volumeidx, int sliceid) +{ + return this->Internals->GetUID(volumeidx, sliceid); +} + +//---------------------------------------------------------------------------- +int vtkMedicalImageProperties::GetSliceIDFromInstanceUID( + int &volumeidx, const char *uid) +{ + if( volumeidx == -1 ) + { + return this->Internals->FindSlice(volumeidx, uid); + } + else + { + return this->Internals->GetSlice(volumeidx, uid); + } +} + +//---------------------------------------------------------------------------- +void vtkMedicalImageProperties::SetInstanceUIDFromSliceID( + int volumeidx, int sliceid, const char *uid) +{ + this->Internals->SetUID(volumeidx,sliceid, uid); +} + +//---------------------------------------------------------------------------- +void vtkMedicalImageProperties::SetOrientationType(int volumeidx, int orientation) +{ + this->Internals->SetOrientation(volumeidx, orientation); +} + +//---------------------------------------------------------------------------- +int vtkMedicalImageProperties::GetOrientationType(int volumeidx) +{ + return this->Internals->GetOrientation(volumeidx); +} + +//---------------------------------------------------------------------------- +const char *vtkMedicalImageProperties::GetStringFromOrientationType(unsigned int type) +{ + static unsigned int numtypes = 0; + // find length of table + if (!numtypes) + { + while (vtkMedicalImagePropertiesOrientationString[numtypes] != NULL) + { + numtypes++; + } + } + + if (type < numtypes) + { + return vtkMedicalImagePropertiesOrientationString[type]; + } + + return NULL; +} + +//---------------------------------------------------------------------------- +double vtkMedicalImageProperties::GetSliceThicknessAsDouble() +{ + if (this->SliceThickness) + { + return atof(this->SliceThickness); + } + return 0; +} + +//---------------------------------------------------------------------------- +double vtkMedicalImageProperties::GetGantryTiltAsDouble() +{ + if (this->GantryTilt) + { + return atof(this->GantryTilt); + } + return 0; +} +//---------------------------------------------------------------------------- +int vtkMedicalImageProperties::GetAgeAsFields(const char *age, int &year, + int &month, int &week, int &day) +{ + year = month = week = day = -1; + if( !age ) + { + return 0; + } + + size_t len = strlen(age); + if( len == 4 ) + { + // DICOM V3 + unsigned int val; + char type; + if( !isdigit(age[0]) + || !isdigit(age[1]) + || !isdigit(age[2])) + { + return 0; + } + if( sscanf(age, "%3u%c", &val, &type) != 2 ) + { + return 0; + } + switch(type) + { + case 'Y': + year = (int)val; + break; + case 'M': + month = (int)val; + break; + case 'W': + week = (int)val; + break; + case 'D': + day = (int)val; + break; + default: + return 0; + } + } + else + { + return 0; + } + + return 1; +} + +//---------------------------------------------------------------------------- +int vtkMedicalImageProperties::GetPatientAgeYear() +{ + const char *age = this->GetPatientAge(); + int year, month, week, day; + vtkMedicalImageProperties::GetAgeAsFields(age, year, month, week, day); + return year; +} +//---------------------------------------------------------------------------- +int vtkMedicalImageProperties::GetPatientAgeMonth() +{ + const char *age = this->GetPatientAge(); + int year, month, week, day; + vtkMedicalImageProperties::GetAgeAsFields(age, year, month, week, day); + return month; +} +//---------------------------------------------------------------------------- +int vtkMedicalImageProperties::GetPatientAgeWeek() +{ + const char *age = this->GetPatientAge(); + int year, month, week, day; + vtkMedicalImageProperties::GetAgeAsFields(age, year, month, week, day); + return week; +} +//---------------------------------------------------------------------------- +int vtkMedicalImageProperties::GetPatientAgeDay() +{ + const char *age = this->GetPatientAge(); + int year, month, week, day; + vtkMedicalImageProperties::GetAgeAsFields(age, year, month, week, day); + return day; +} + +//---------------------------------------------------------------------------- +int vtkMedicalImageProperties::GetDateAsFields(const char *date, int &year, + int &month, int &day) +{ + if( !date ) + { + return 0; + } + + size_t len = strlen(date); + if( len == 8 ) + { + // DICOM V3 + if( sscanf(date, "%04d%02d%02d", &year, &month, &day) != 3 ) + { + return 0; + } + } + else if( len == 10 ) + { + // Some *very* old ACR-NEMA + if( sscanf(date, "%04d.%02d.%02d", &year, &month, &day) != 3 ) + { + return 0; + } + } + else + { + return 0; + } + + return 1; +} + +//---------------------------------------------------------------------------- +// Some buggy versions of gcc complain about the use of %c: warning: `%c' +// yields only last 2 digits of year in some locales. Of course program- +// mers are encouraged to use %c, it gives the preferred date and time +// representation. One meets all kinds of strange obfuscations to circum- +// vent this gcc problem. A relatively clean one is to add an intermediate +// function. This is described as bug #3190 in gcc bugzilla: +// [-Wformat-y2k doesn't belong to -Wall - it's hard to avoid] +inline size_t +my_strftime(char *s, size_t max, const char *fmt, const struct tm *tm) +{ + return strftime(s, max, fmt, tm); +} +// Helper function to convert a DICOM iso date format into a locale one +// locale buffer should be typically char locale[200] +int vtkMedicalImageProperties::GetDateAsLocale(const char *iso, char *locale) +{ + int year, month, day; + if( vtkMedicalImageProperties::GetDateAsFields(iso, year, month, day) ) + { + struct tm date; + memset(&date,0, sizeof(date)); + date.tm_mday = day; + // month are expressed in the [0-11] range: + date.tm_mon = month - 1; + // structure is date starting at 1900 + date.tm_year = year - 1900; + my_strftime(locale, 200, "%x", &date); + return 1; + } + return 0; +} +//---------------------------------------------------------------------------- +int vtkMedicalImageProperties::GetPatientBirthDateYear() +{ + const char *date = this->GetPatientBirthDate(); + int year, month, day; + vtkMedicalImageProperties::GetDateAsFields(date, year, month, day); + return year; +} +//---------------------------------------------------------------------------- +int vtkMedicalImageProperties::GetPatientBirthDateMonth() +{ + const char *date = this->GetPatientBirthDate(); + int year, month, day; + vtkMedicalImageProperties::GetDateAsFields(date, year, month, day); + return month; +} +//---------------------------------------------------------------------------- +int vtkMedicalImageProperties::GetPatientBirthDateDay() +{ + const char *date = this->GetPatientBirthDate(); + int year, month, day; + vtkMedicalImageProperties::GetDateAsFields(date, year, month, day); + return day; +} +//---------------------------------------------------------------------------- +int vtkMedicalImageProperties::GetAcquisitionDateYear() +{ + const char *date = this->GetAcquisitionDate(); + int year, month, day; + vtkMedicalImageProperties::GetDateAsFields(date, year, month, day); + return year; +} +//---------------------------------------------------------------------------- +int vtkMedicalImageProperties::GetAcquisitionDateMonth() +{ + const char *date = this->GetAcquisitionDate(); + int year, month, day; + vtkMedicalImageProperties::GetDateAsFields(date, year, month, day); + return month; +} +//---------------------------------------------------------------------------- +int vtkMedicalImageProperties::GetAcquisitionDateDay() +{ + const char *date = this->GetAcquisitionDate(); + int year, month, day; + vtkMedicalImageProperties::GetDateAsFields(date, year, month, day); + return day; +} +//---------------------------------------------------------------------------- +int vtkMedicalImageProperties::GetImageDateYear() +{ + const char *date = this->GetImageDate(); + int year, month, day; + vtkMedicalImageProperties::GetDateAsFields(date, year, month, day); + return year; +} +//---------------------------------------------------------------------------- +int vtkMedicalImageProperties::GetImageDateMonth() +{ + const char *date = this->GetImageDate(); + int year, month, day; + vtkMedicalImageProperties::GetDateAsFields(date, year, month, day); + return month; +} +//---------------------------------------------------------------------------- +int vtkMedicalImageProperties::GetImageDateDay() +{ + const char *date = this->GetImageDate(); + int year, month, day; + vtkMedicalImageProperties::GetDateAsFields(date, year, month, day); + return day; +} + +//---------------------------------------------------------------------------- +void vtkMedicalImageProperties::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os, indent); + + os << "\n" << indent << "PatientName: "; + if (this->PatientName) + { + os << this->PatientName; + } + + os << "\n" << indent << "PatientID: "; + if (this->PatientID) + { + os << this->PatientID; + } + + os << "\n" << indent << "PatientAge: "; + if (this->PatientAge) + { + os << this->PatientAge; + } + + os << "\n" << indent << "PatientSex: "; + if (this->PatientSex) + { + os << this->PatientSex; + } + + os << "\n" << indent << "PatientBirthDate: "; + if (this->PatientBirthDate) + { + os << this->PatientBirthDate; + } + + os << "\n" << indent << "ImageDate: "; + if (this->ImageDate) + { + os << this->ImageDate; + } + + os << "\n" << indent << "ImageTime: "; + if (this->ImageTime) + { + os << this->ImageTime; + } + + os << "\n" << indent << "ImageNumber: "; + if (this->ImageNumber) + { + os << this->ImageNumber; + } + + os << "\n" << indent << "StudyDate: "; + if (this->StudyDate) + { + os << this->StudyDate; + } + + os << "\n" << indent << "AcquisitionDate: "; + if (this->AcquisitionDate) + { + os << this->AcquisitionDate; + } + + os << "\n" << indent << "StudyTime: "; + if (this->StudyTime) + { + os << this->StudyTime; + } + + os << "\n" << indent << "AcquisitionTime: "; + if (this->AcquisitionTime) + { + os << this->AcquisitionTime; + } + + os << "\n" << indent << "SeriesNumber: "; + if (this->SeriesNumber) + { + os << this->SeriesNumber; + } + + os << "\n" << indent << "SeriesDescription: "; + if (this->SeriesDescription) + { + os << this->SeriesDescription; + } + + os << "\n" << indent << "StudyDescription: "; + if (this->StudyDescription) + { + os << this->StudyDescription; + } + + os << "\n" << indent << "StudyID: "; + if (this->StudyID) + { + os << this->StudyID; + } + + os << "\n" << indent << "Modality: "; + if (this->Modality) + { + os << this->Modality; + } + + os << "\n" << indent << "ManufacturerModelName: "; + if (this->ManufacturerModelName) + { + os << this->ManufacturerModelName; + } + + os << "\n" << indent << "Manufacturer: "; + if (this->Manufacturer) + { + os << this->Manufacturer; + } + + os << "\n" << indent << "StationName: "; + if (this->StationName) + { + os << this->StationName; + } + + os << "\n" << indent << "InstitutionName: "; + if (this->InstitutionName) + { + os << this->InstitutionName; + } + + os << "\n" << indent << "ConvolutionKernel: "; + if (this->ConvolutionKernel) + { + os << this->ConvolutionKernel; + } + + os << "\n" << indent << "SliceThickness: "; + if (this->SliceThickness) + { + os << this->SliceThickness; + } + + os << "\n" << indent << "KVP: "; + if (this->KVP) + { + os << this->KVP; + } + + os << "\n" << indent << "GantryTilt: "; + if (this->GantryTilt) + { + os << this->GantryTilt; + } + + os << "\n" << indent << "EchoTime: "; + if (this->EchoTime) + { + os << this->EchoTime; + } + + os << "\n" << indent << "EchoTrainLength: "; + if (this->EchoTrainLength) + { + os << this->EchoTrainLength; + } + + os << "\n" << indent << "RepetitionTime: "; + if (this->RepetitionTime) + { + os << this->RepetitionTime; + } + + os << "\n" << indent << "ExposureTime: "; + if (this->ExposureTime) + { + os << this->ExposureTime; + } + + os << "\n" << indent << "XRayTubeCurrent: "; + if (this->XRayTubeCurrent) + { + os << this->XRayTubeCurrent; + } + + os << "\n" << indent << "Exposure: "; + if (this->Exposure) + { + os << this->Exposure; + } + + this->Internals->Print(os << "\n", indent.GetNextIndent() ); +} diff --git a/gdcm/Utilities/VTK/VTK4/vtkMedicalImageProperties.h b/gdcm/Utilities/VTK/VTK4/vtkMedicalImageProperties.h new file mode 100644 index 0000000..cdedd98 --- /dev/null +++ b/gdcm/Utilities/VTK/VTK4/vtkMedicalImageProperties.h @@ -0,0 +1,418 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/*========================================================================= + + Portions of this file are subject to the VTK Toolkit Version 3 copyright. + + Program: Visualization Toolkit + Module: $RCSfile: vtkMedicalImageProperties.h,v $ + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +// .NAME vtkMedicalImageProperties - some medical image properties. +// .SECTION Description +// vtkMedicalImageProperties is a helper class that can be used by medical +// image readers and applications to encapsulate medical image/acquisition +// properties. Later on, this should probably be extended to add +// any user-defined property. +// .SECTION See Also +// vtkMedicalImageReader2 + +#ifndef VTKMEDICALIMAGEPROPERTIES_H +#define VTKMEDICALIMAGEPROPERTIES_H + +#ifdef __vtkMedicalImageProperties_h +#error Something went terribly wrong +#endif + +#include "vtkObject.h" + +class vtkMedicalImagePropertiesInternals; + +class VTK_IO_EXPORT vtkMedicalImageProperties : public vtkObject +{ +public: + static vtkMedicalImageProperties *New(); + vtkTypeRevisionMacro(vtkMedicalImageProperties,vtkObject); + void PrintSelf(ostream& os, vtkIndent indent); + + // Description: + // Convenience method to reset all fields to an emptry string/value + virtual void Clear(); + + // Description: + // Patient name + // For ex: DICOM (0010,0010) = DOE,JOHN + vtkSetStringMacro(PatientName); + vtkGetStringMacro(PatientName); + + // Description: + // Patient ID + // For ex: DICOM (0010,0020) = 1933197 + vtkSetStringMacro(PatientID); + vtkGetStringMacro(PatientID); + + // Description: + // Patient age + // Format: nnnD, nnW, nnnM or nnnY (eventually nnD, nnW, nnY) + // with D (day), M (month), W (week), Y (year) + // For ex: DICOM (0010,1010) = 031Y + vtkSetStringMacro(PatientAge); + vtkGetStringMacro(PatientAge); + + // Description: + // Take as input a string in VR=AS (DICOM PS3.5) and extract either + // different fields namely: year month week day + // Return 0 on error, 1 on success + // One can test fields if they are different from -1 upon success + static int GetAgeAsFields(const char *age, int &year, int &month, int &week, int &day); + + // For Tcl: + // From C++ use GetPatientAge + GetAgeAsField + // Those function parse a DICOM string, and return the value of the number expressed + // this is either expressed in year, month or days. Thus if a string is expressed in years + // GetPatientAgeDay/GetPatientAgeWeek/GetPatientAgeMonth will return 0 + int GetPatientAgeYear(); + int GetPatientAgeMonth(); + int GetPatientAgeWeek(); + int GetPatientAgeDay(); + + // Description: + // Patient sex + // For ex: DICOM (0010,0040) = M + vtkSetStringMacro(PatientSex); + vtkGetStringMacro(PatientSex); + + // Description: + // Patient birth date + // Format: yyyymmdd + // For ex: DICOM (0010,0030) = 19680427 + vtkSetStringMacro(PatientBirthDate); + vtkGetStringMacro(PatientBirthDate); + + // For Tcl: + // From C++ use GetPatientBirthDate + GetDateAsFields + int GetPatientBirthDateYear(); + int GetPatientBirthDateMonth(); + int GetPatientBirthDateDay(); + + // Description: + // Study Date + // Format: yyyymmdd + // For ex: DICOM (0008,0020) = 20030617 + vtkSetStringMacro(StudyDate); + vtkGetStringMacro(StudyDate); + + // Description: + // Acquisition Date + // Format: yyyymmdd + // For ex: DICOM (0008,0022) = 20030617 + vtkSetStringMacro(AcquisitionDate); + vtkGetStringMacro(AcquisitionDate); + + // For Tcl: + // From C++ use GetAcquisitionDate + GetDateAsFields + int GetAcquisitionDateYear(); + int GetAcquisitionDateMonth(); + int GetAcquisitionDateDay(); + + // Description: + // Study Time + // Format: hhmmss.frac (any trailing component(s) can be ommited) + // For ex: DICOM (0008,0030) = 162552.0705 or 230012, or 0012 + vtkSetStringMacro(StudyTime); + vtkGetStringMacro(StudyTime); + + // Description: + // Acquisition time + // Format: hhmmss.frac (any trailing component(s) can be ommited) + // For ex: DICOM (0008,0032) = 162552.0705 or 230012, or 0012 + vtkSetStringMacro(AcquisitionTime); + vtkGetStringMacro(AcquisitionTime); + + // Description: + // Image Date aka Content Date + // Format: yyyymmdd + // For ex: DICOM (0008,0023) = 20030617 + vtkSetStringMacro(ImageDate); + vtkGetStringMacro(ImageDate); + + // For Tcl: + // From C++ use GetImageDate + GetDateAsFields + int GetImageDateYear(); + int GetImageDateMonth(); + int GetImageDateDay(); + + // Description: + // Take as input a string in ISO 8601 date (YYYY/MM/DD) and extract the + // different fields namely: year month day + // Return 0 on error, 1 on success + static int GetDateAsFields(const char *date, int &year, int &month, int &day); + + // Description: + // Take as input a string in ISO 8601 date (YYYY/MM/DD) and construct a + // locale date based on the different fields (see GetDateAsFields to extract + // different fields) + // Return 0 on error, 1 on success + static int GetDateAsLocale(const char *date, char *locale); + + // Description: + // Image Time + // Format: hhmmss.frac (any trailing component(s) can be ommited) + // For ex: DICOM (0008,0033) = 162552.0705 or 230012, or 0012 + vtkSetStringMacro(ImageTime); + vtkGetStringMacro(ImageTime); + + // Description: + // Image number + // For ex: DICOM (0020,0013) = 1 + vtkSetStringMacro(ImageNumber); + vtkGetStringMacro(ImageNumber); + + // Description: + // Series number + // For ex: DICOM (0020,0011) = 902 + vtkSetStringMacro(SeriesNumber); + vtkGetStringMacro(SeriesNumber); + + // Description: + // Series Description + // User provided description of the Series + // For ex: DICOM (0008,103e) = SCOUT + vtkSetStringMacro(SeriesDescription); + vtkGetStringMacro(SeriesDescription); + + // Description: + // Study ID + // For ex: DICOM (0020,0010) = 37481 + vtkSetStringMacro(StudyID); + vtkGetStringMacro(StudyID); + + // Description: + // Study description + // For ex: DICOM (0008,1030) = BRAIN/C-SP/FACIAL + vtkSetStringMacro(StudyDescription); + vtkGetStringMacro(StudyDescription); + + // Description: + // Modality + // For ex: DICOM (0008,0060)= CT + vtkSetStringMacro(Modality); + vtkGetStringMacro(Modality); + + // Description: + // Manufacturer + // For ex: DICOM (0008,0070) = Siemens + vtkSetStringMacro(Manufacturer); + vtkGetStringMacro(Manufacturer); + + // Description: + // Manufacturer's Model Name + // For ex: DICOM (0008,1090) = LightSpeed QX/i + vtkSetStringMacro(ManufacturerModelName); + vtkGetStringMacro(ManufacturerModelName); + + // Description: + // Station Name + // For ex: DICOM (0008,1010) = LSPD_OC8 + vtkSetStringMacro(StationName); + vtkGetStringMacro(StationName); + + // Description: + // Institution Name + // For ex: DICOM (0008,0080) = FooCity Medical Center + vtkSetStringMacro(InstitutionName); + vtkGetStringMacro(InstitutionName); + + // Description: + // Convolution Kernel (or algorithm used to reconstruct the data) + // For ex: DICOM (0018,1210) = Bone + vtkSetStringMacro(ConvolutionKernel); + vtkGetStringMacro(ConvolutionKernel); + + // Description: + // Slice Thickness (Nominal reconstructed slice thickness, in mm) + // For ex: DICOM (0018,0050) = 0.273438 + vtkSetStringMacro(SliceThickness); + vtkGetStringMacro(SliceThickness); + virtual double GetSliceThicknessAsDouble(); + + // Description: + // Peak kilo voltage output of the (x-ray) generator used + // For ex: DICOM (0018,0060) = 120 + vtkSetStringMacro(KVP); + vtkGetStringMacro(KVP); + + // Description: + // Gantry/Detector tilt (Nominal angle of tilt in degrees of the scanning + // gantry.) + // For ex: DICOM (0018,1120) = 15 + vtkSetStringMacro(GantryTilt); + vtkGetStringMacro(GantryTilt); + virtual double GetGantryTiltAsDouble(); + + // Description: + // Echo Time + // (Time in ms between the middle of the excitation pulse and the peak of + // the echo produced) + // For ex: DICOM (0018,0081) = 105 + vtkSetStringMacro(EchoTime); + vtkGetStringMacro(EchoTime); + + // Description: + // Echo Train Length + // (Number of lines in k-space acquired per excitation per image) + // For ex: DICOM (0018,0091) = 35 + vtkSetStringMacro(EchoTrainLength); + vtkGetStringMacro(EchoTrainLength); + + // Description: + // Repetition Time + // The period of time in msec between the beginning of a pulse sequence and + // the beginning of the succeeding (essentially identical) pulse sequence. + // For ex: DICOM (0018,0080) = 2040 + vtkSetStringMacro(RepetitionTime); + vtkGetStringMacro(RepetitionTime); + + // Description: + // Exposure time (time of x-ray exposure in msec) + // For ex: DICOM (0018,1150) = 5 + vtkSetStringMacro(ExposureTime); + vtkGetStringMacro(ExposureTime); + + // Description: + // X-ray tube current (in mA) + // For ex: DICOM (0018,1151) = 400 + vtkSetStringMacro(XRayTubeCurrent); + vtkGetStringMacro(XRayTubeCurrent); + + // Description: + // Exposure (The exposure expressed in mAs, for example calculated + // from Exposure Time and X-ray Tube Current) + // For ex: DICOM (0018,1152) = 114 + vtkSetStringMacro(Exposure); + vtkGetStringMacro(Exposure); + + // Interface to allow insertion of user define values, for instance in DICOM one would want to + // store the Protocol Name (0018,1030), in this case one would do: + // AddUserDefinedValue( "Protocol Name", "T1W/SE/1024" ); + void AddUserDefinedValue(const char *name, const char *value); + // Get a particular user value + const char *GetUserDefinedValue(const char *name); + // Get the number of user defined values + unsigned int GetNumberOfUserDefinedValues(); + // Get a name/value by index + const char *GetUserDefinedNameByIndex(unsigned int idx); + const char *GetUserDefinedValueByIndex(unsigned int idx); + + // Description: + // Copy the contents of p to this instance. + virtual void DeepCopy(vtkMedicalImageProperties *p); + + // Description: + // Add/Remove/Query the window/level presets that may have been associated + // to a medical image. Window is also known as 'width', level is also known + // as 'center'. The same window/level pair can not be added twice. + // As a convenience, a comment (aka Explanation) can be associated to a preset. + // For ex: DICOM Window Center (0028,1050) = 00045\000470 + // DICOM Window Width (0028,1051) = 0106\03412 + // DICOM Window Center Width Explanation (0028,1055) = WINDOW1\WINDOW2 + virtual void AddWindowLevelPreset(double w, double l); + virtual void RemoveWindowLevelPreset(double w, double l); + virtual void RemoveAllWindowLevelPresets(); + virtual int GetNumberOfWindowLevelPresets(); + virtual int HasWindowLevelPreset(double w, double l); + virtual int GetNthWindowLevelPreset(int idx, double *w, double *l); + virtual double* GetNthWindowLevelPreset(int idx); + virtual void SetNthWindowLevelPresetComment(int idx, const char *comment); + virtual const char* GetNthWindowLevelPresetComment(int idx); + + // Description: + // Mapping from a sliceidx within a volumeidx into a DICOM Instance UID + // Some DICOM reader can populate this structure so that later on from a slice index + // in a vtkImageData volume we can backtrack and find out which 2d slice it was coming from + const char *GetInstanceUIDFromSliceID(int volumeidx, int sliceid); + void SetInstanceUIDFromSliceID(int volumeidx, int sliceid, const char *uid); + + // Description: + // Provides the inverse mapping. Returns -1 if a slice for this uid is + // not found. + int GetSliceIDFromInstanceUID(int &volumeidx, const char *uid); + +//BTX + typedef enum { + AXIAL = 0, + CORONAL, + SAGITTAL + } OrientationType; +//ETX + int GetOrientationType(int volumeidx); + void SetOrientationType(int volumeidx, int orientation); + static const char *GetStringFromOrientationType(unsigned int type); + +protected: + vtkMedicalImageProperties(); + ~vtkMedicalImageProperties(); + + char *StudyDate; + char *AcquisitionDate; + char *StudyTime; + char *AcquisitionTime; + char *ConvolutionKernel; + char *EchoTime; + char *EchoTrainLength; + char *Exposure; + char *ExposureTime; + char *GantryTilt; + char *ImageDate; + char *ImageNumber; + char *ImageTime; + char *InstitutionName; + char *KVP; + char *ManufacturerModelName; + char *Manufacturer; + char *Modality; + char *PatientAge; + char *PatientBirthDate; + char *PatientID; + char *PatientName; + char *PatientSex; + char *RepetitionTime; + char *SeriesDescription; + char *SeriesNumber; + char *SliceThickness; + char *StationName; + char *StudyDescription; + char *StudyID; + char *XRayTubeCurrent; + + // Description: + // PIMPL Encapsulation for STL containers + //BTX + vtkMedicalImagePropertiesInternals *Internals; + //ETX + +private: + vtkMedicalImageProperties(const vtkMedicalImageProperties&); // Not implemented. + void operator=(const vtkMedicalImageProperties&); // Not implemented. +}; + +#endif diff --git a/gdcm/Utilities/VTK/VTK4/vtkStringArray.cxx b/gdcm/Utilities/VTK/VTK4/vtkStringArray.cxx new file mode 100644 index 0000000..940a9ba --- /dev/null +++ b/gdcm/Utilities/VTK/VTK4/vtkStringArray.cxx @@ -0,0 +1,71 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkStringArray.h" + +#include "vtkObjectFactory.h" + +#include +#include + +vtkCxxRevisionMacro(vtkStringArray, "$Revision: 1.1 $") +vtkStandardNewMacro(vtkStringArray) + +struct vtkStringArrayInternals +{ + std::vector< std::string > Internal; +}; + +vtkStringArray::vtkStringArray() +{ + Internal = new vtkStringArrayInternals; +} + +vtkStringArray::~vtkStringArray() +{ + delete Internal; +} + +//std::string &vtkStringArray::GetValue(unsigned int i) +const char *vtkStringArray::GetValue(unsigned int i) +{ + return Internal->Internal[i].c_str(); +} + +int vtkStringArray::GetNumberOfValues() +{ + return Internal->Internal.size(); +} + +vtkIdType vtkStringArray::InsertNextValue(const char *f) +{ + Internal->Internal.push_back( f ); + return Internal->Internal.size(); +} + +vtkIdType vtkStringArray::InsertNextValue(std::string const & f) +{ + Internal->Internal.push_back( f ); + return Internal->Internal.size(); +} + +vtkIdType vtkStringArray::GetSize() +{ + return Internal->Internal.size(); +} + +//---------------------------------------------------------------------------- +void vtkStringArray::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os,indent); +} diff --git a/gdcm/Utilities/VTK/VTK4/vtkStringArray.h b/gdcm/Utilities/VTK/VTK4/vtkStringArray.h new file mode 100644 index 0000000..90748d7 --- /dev/null +++ b/gdcm/Utilities/VTK/VTK4/vtkStringArray.h @@ -0,0 +1,61 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +// .NAME vtkStringArray - +// .SECTION Description +// +// .SECTION +// +// .SECTION See Also + +#ifndef VTKSTRINGARRAY_H +#define VTKSTRINGARRAY_H + +#ifdef __vtkStringArray_h +#error Something went terribly wrong +#endif + +#include "vtkObject.h" + +#include + +class vtkStringArrayInternals; +class VTK_EXPORT vtkStringArray : public vtkObject +{ +public: + static vtkStringArray *New(); + vtkTypeRevisionMacro(vtkStringArray,vtkObject); + virtual void PrintSelf(ostream& os, vtkIndent indent); + +//BTX + //std::string &GetValue(unsigned int i); + vtkIdType InsertNextValue(std::string const & f); +//ETX + const char *GetValue(unsigned int i); + int GetNumberOfValues(); + vtkIdType InsertNextValue(const char *f); + + vtkIdType GetSize(); + +protected: + vtkStringArray(); + ~vtkStringArray(); + +private: + vtkStringArray(const vtkStringArray&); // Not implemented. + void operator=(const vtkStringArray&); // Not implemented. + + vtkStringArrayInternals *Internal; +}; + +#endif diff --git a/gdcm/Utilities/VTK/dllexportconf.cs b/gdcm/Utilities/VTK/dllexportconf.cs new file mode 100644 index 0000000..7383b99 --- /dev/null +++ b/gdcm/Utilities/VTK/dllexportconf.cs @@ -0,0 +1 @@ +public const string vtkgdcmEL_dll = "libKitware.VTK.vtkgdcm.Unmanaged.so"; diff --git a/gdcm/Utilities/VTK/gccxml.cxx.in b/gdcm/Utilities/VTK/gccxml.cxx.in new file mode 100644 index 0000000..ce51d63 --- /dev/null +++ b/gdcm/Utilities/VTK/gccxml.cxx.in @@ -0,0 +1,16 @@ +#include "@header@" + +#ifdef CABLE_CONFIGURATION +namespace _cable_ +{ + const char* const package = "Kitware.VTK.GDCM"; + const char* const package_version = "@VTK_MAJOR_VERSION@.@VTK_MINOR_VERSION@.@VTK_BUILD_VERSION@"; + const char* const group = "vtk@kit@"; + + namespace wrappers + { + typedef @cxxclass@ @cxxclass@_W; + } + +} +#endif diff --git a/gdcm/Utilities/VTK/manifest.txt b/gdcm/Utilities/VTK/manifest.txt new file mode 100644 index 0000000..de78714 --- /dev/null +++ b/gdcm/Utilities/VTK/manifest.txt @@ -0,0 +1 @@ +Class-Path: vtk.jar diff --git a/gdcm/Utilities/VTK/vtkGDCMImageReader.cxx b/gdcm/Utilities/VTK/vtkGDCMImageReader.cxx new file mode 100644 index 0000000..300aae3 --- /dev/null +++ b/gdcm/Utilities/VTK/vtkGDCMImageReader.cxx @@ -0,0 +1,1531 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkGDCMImageReader.h" + +#include "vtkObjectFactory.h" +#include "vtkImageData.h" +#include "vtkErrorCode.h" +#include "vtkMath.h" +#include "vtkPolyData.h" +#include "vtkCellArray.h" +#include "vtkPoints.h" +#include "vtkMedicalImageProperties.h" +#include "vtkGDCMMedicalImageProperties.h" +#include "vtkStringArray.h" +#include "vtkPointData.h" +#include "vtkLookupTable.h" +#include "vtkWindowLevelLookupTable.h" +#if (VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 ) +#include "vtkLookupTable16.h" +#include "vtkInformationVector.h" +#include "vtkInformation.h" +#include "vtkDemandDrivenPipeline.h" +#include "vtkStreamingDemandDrivenPipeline.h" +#endif /*(VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 )*/ +#include "vtkMatrix4x4.h" +#include "vtkUnsignedCharArray.h" +//#include "vtkUnsignedShortArray.h" +#include "vtkBitArray.h" + +#include "gdcmImageReader.h" +#include "gdcmDataElement.h" +#include "gdcmByteValue.h" +#include "gdcmSwapper.h" +#include "gdcmUnpacker12Bits.h" +#include "gdcmRescaler.h" +#include "gdcmOrientation.h" +#include "gdcmTrace.h" +#include "gdcmImageChangePlanarConfiguration.h" +#include "gdcmDirectoryHelper.h" + +#include + +vtkCxxRevisionMacro(vtkGDCMImageReader, "$Revision: 1.1 $") +vtkStandardNewMacro(vtkGDCMImageReader) + +static inline bool vtkGDCMImageReader_IsCharTypeSigned() +{ +#ifndef VTK_TYPE_CHAR_IS_SIGNED + unsigned char uc = 255; + return (*reinterpret_cast(&uc) < 0) ? true : false; +#else + return VTK_TYPE_CHAR_IS_SIGNED; +#endif +} + +// Output Ports are as follow: +// #0: The image/volume (root PixelData element) +// #1: (if present): the Icon Image (0088,0200) +// #2-xx: (if present): the Overlay (60xx,3000) + +#define ICONIMAGEPORTNUMBER 1 +#define OVERLAYPORTNUMBER 2 + +vtkCxxSetObjectMacro(vtkGDCMImageReader,Curve,vtkPolyData) +vtkCxxSetObjectMacro(vtkGDCMImageReader,MedicalImageProperties,vtkMedicalImageProperties) + +//---------------------------------------------------------------------------- +vtkGDCMImageReader::vtkGDCMImageReader() +{ + // vtkDataArray has an internal vtkLookupTable why not used it ? + // vtkMedicalImageProperties is in the parent class + //this->FileLowerLeft = 1; + this->DirectionCosines = vtkMatrix4x4::New(); + this->DirectionCosines->Identity(); + //this->DirectionCosines->SetElement(0,0,1); // x0 + //this->DirectionCosines->SetElement(1,0,0); // x1 + //this->DirectionCosines->SetElement(2,0,0); // x2 + //this->DirectionCosines->SetElement(3,0,0); // + //this->DirectionCosines->SetElement(0,1,0); // y0 + //this->DirectionCosines->SetElement(1,1,1); // y1 + //this->DirectionCosines->SetElement(2,1,0); // y2 + //this->DirectionCosines->SetElement(3,1,0); // + //this->DirectionCosines->SetElement(0,2,0); // y0 + //this->DirectionCosines->SetElement(1,2,0); // y1 + //this->DirectionCosines->SetElement(2,2,1); // y2 + //this->DirectionCosines->SetElement(3,2,0); // +#if (VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 ) +#else + this->MedicalImageProperties = vtkMedicalImageProperties::New(); +#endif +#if (VTK_MAJOR_VERSION > 5) || ( VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION > 0 ) + //this->SetNumberOfInputPorts(0); +#else + this->FileNames = NULL; //vtkStringArray::New(); +#endif + this->LoadOverlays = 1; + this->LoadIconImage = 1; + this->NumberOfOverlays = 0; + this->NumberOfIconImages = 0; + memset(this->IconImageDataExtent,0,6*sizeof(int)); + this->ImageFormat = 0; // INVALID + this->ApplyInverseVideo = 0; + this->ApplyLookupTable = 0; + this->ApplyYBRToRGB = 0; + this->ApplyPlanarConfiguration = 1; + this->ApplyShiftScale = 1; + memset(this->ImagePositionPatient,0,3*sizeof(double)); + memset(this->ImageOrientationPatient,0,6*sizeof(double)); + this->Curve = 0; + this->Shift = 0.; + this->Scale = 1.; + this->IconDataScalarType = VTK_CHAR; + this->IconNumberOfScalarComponents = 1; + this->PlanarConfiguration = 0; + this->LossyFlag = 0; + + // DirectionCosine was added after 5.2 +#if ( VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION > 2 ) + this->MedicalImageProperties->SetDirectionCosine(1,0,0,0,1,0); +#endif + this->SetImageOrientationPatient(1,0,0,0,1,0); + + // this->SetMedicalImageProperties( vtkGDCMMedicalImageProperties::New() ); + this->ForceRescale = 0; +} + +//---------------------------------------------------------------------------- +vtkGDCMImageReader::~vtkGDCMImageReader() +{ + //delete this->Internals; + this->DirectionCosines->Delete(); +#if (VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 ) +#else + this->MedicalImageProperties->Delete(); +#endif +#if (VTK_MAJOR_VERSION > 5) || ( VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION > 0 ) +#else + if( this->FileNames ) + { + this->FileNames->Delete(); + } +#endif + if( this->Curve ) + { + this->Curve->Delete(); + } +} + +//---------------------------------------------------------------------------- +#if (VTK_MAJOR_VERSION > 5) || ( VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION > 0 ) +#else +void vtkGDCMImageReader::SetFileNames(vtkStringArray *filenames) +{ + if (filenames == this->FileNames) + { + return; + } + if (this->FileNames) + { + this->FileNames->Delete(); + this->FileNames = 0; + } + if (filenames) + { + this->FileNames = filenames; + this->FileNames->Register(this); + if (this->FileNames->GetNumberOfValues() > 0) + { + this->DataExtent[4] = 0; + this->DataExtent[5] = this->FileNames->GetNumberOfValues() - 1; + } + if (this->FilePrefix) + { + delete [] this->FilePrefix; + this->FilePrefix = NULL; + } + if (this->FileName) + { + delete [] this->FileName; + this->FileName = NULL; + } + } + + this->Modified(); +} +#endif + +//---------------------------------------------------------------------------- +#if (VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 ) +#else +void vtkGDCMImageReader::ExecuteInformation() +{ + //std::cerr << "ExecuteInformation" << std::endl; + + // FIXME: I think it only apply to VTK 4.2... + vtkImageData *output = this->GetOutput(); + output->SetUpdateExtentToWholeExtent(); // pipeline is not reexecuting properly without that... + + int res = RequestInformationCompat(); + if( !res ) + { + vtkErrorMacro( "ExecuteInformation failed" ); + this->SetErrorCode(vtkErrorCode::FileFormatError); + return; + } + + int numvol = 1; + if( this->LoadIconImage ) + { + numvol = 2; + } + if( this->LoadOverlays ) + { + // If not icon found, we still need to be associated to port #2: + numvol = 3; + } + this->SetNumberOfOutputs(numvol); + + // vtkImageReader2::ExecuteInformation only allocate first output + this->vtkImageReader2::ExecuteInformation(); + // Let's do the other ones ourselves: + for (int i=1; iOutputs[i]) + { + vtkImageData * img = vtkImageData::New(); + this->SetNthOutput(i, img); + img->Delete(); + } + vtkImageData *output = this->GetOutput(i); + switch(i) + { + case 0: + output->SetWholeExtent(this->DataExtent); + output->SetSpacing(this->DataSpacing); +#ifdef GDCMV2_0_COMPATIBILITY + output->SetOrigin(this->DataOrigin); +#endif + + output->SetScalarType(this->DataScalarType); + output->SetNumberOfScalarComponents(this->NumberOfScalarComponents); + break; + case ICONIMAGEPORTNUMBER: + output->SetWholeExtent(this->IconImageDataExtent); + output->SetScalarType( this->IconDataScalarType ); + output->SetNumberOfScalarComponents( this->IconNumberOfScalarComponents ); + break; + //case OVERLAYPORTNUMBER: + default: + output->SetWholeExtent(this->DataExtent[0],this->DataExtent[1], + this->DataExtent[2],this->DataExtent[3], + 0,0 + ); + //output->SetSpacing(this->DataSpacing); + //output->SetOrigin(this->DataOrigin); + output->SetScalarType(VTK_UNSIGNED_CHAR); + output->SetNumberOfScalarComponents(1); + break; + } + + } +} + +//---------------------------------------------------------------------------- +void vtkGDCMImageReader::ExecuteData(vtkDataObject *output) +{ + //std::cerr << "ExecuteData" << std::endl; + // In VTK 4.2 AllocateOutputData is reexecuting ExecuteInformation which is bad ! + //vtkImageData *data = this->AllocateOutputData(output); + vtkImageData *res = vtkImageData::SafeDownCast(output); + res->SetExtent(res->GetUpdateExtent()); + res->AllocateScalars(); + + if( this->LoadIconImage ) + { + vtkImageData *res = vtkImageData::SafeDownCast(this->Outputs[ICONIMAGEPORTNUMBER]); + res->SetUpdateExtentToWholeExtent(); + + res->SetExtent(res->GetUpdateExtent()); + res->AllocateScalars(); + } + if( this->LoadOverlays ) + { + vtkImageData *res = vtkImageData::SafeDownCast(this->Outputs[OVERLAYPORTNUMBER]); + res->SetUpdateExtentToWholeExtent(); + + res->SetExtent(res->GetUpdateExtent()); + res->AllocateScalars(); + } + //int * updateExtent = data->GetUpdateExtent(); + //std::cout << "UpdateExtent:" << updateExtent[4] << " " << updateExtent[5] << std::endl; + RequestDataCompat(); + +} + +#endif /*(VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 )*/ + +//---------------------------------------------------------------------------- +int vtkGDCMImageReader::CanReadFile(const char* fname) +{ + gdcm::ImageReader reader; + reader.SetFileName( fname ); + if( !reader.Read() ) + { + return 0; + } + // 3 means: I might be able to read... + return 3; +} + +//---------------------------------------------------------------------------- +#if (VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 ) +int vtkGDCMImageReader::ProcessRequest(vtkInformation* request, + vtkInformationVector** inputVector, + vtkInformationVector* outputVector) +{ + // generate the data + if(request->Has(vtkDemandDrivenPipeline::REQUEST_DATA())) + { + return this->RequestData(request, inputVector, outputVector); + } + + // execute information + if(request->Has(vtkDemandDrivenPipeline::REQUEST_INFORMATION())) + { + return this->RequestInformation(request, inputVector, outputVector); + } + + return this->Superclass::ProcessRequest(request, inputVector, outputVector); +} +#endif /*(VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 )*/ + + + + +//---------------------------------------------------------------------------- +void vtkGDCMImageReader::FillMedicalImageInformation(const gdcm::ImageReader &reader) +{ + const gdcm::File &file = reader.GetFile(); + const gdcm::DataSet &ds = file.GetDataSet(); + + // $ grep "vtkSetString\|DICOM" vtkMedicalImageProperties.h + // For ex: DICOM (0010,0010) = DOE,JOHN + this->MedicalImageProperties->SetPatientName( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0010,0x0010), ds).c_str() ); + // For ex: DICOM (0010,0020) = 1933197 + this->MedicalImageProperties->SetPatientID( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0010,0x0020), ds).c_str() ); + // For ex: DICOM (0010,1010) = 031Y + this->MedicalImageProperties->SetPatientAge( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0010,0x1010), ds).c_str() ); + // For ex: DICOM (0010,0040) = M + this->MedicalImageProperties->SetPatientSex( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0010,0x0040), ds).c_str() ); + // For ex: DICOM (0010,0030) = 19680427 + this->MedicalImageProperties->SetPatientBirthDate( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0010,0x0030), ds).c_str() ); +#if (VTK_MAJOR_VERSION > 5) || ( VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION > 0 ) + // For ex: DICOM (0008,0020) = 20030617 + this->MedicalImageProperties->SetStudyDate( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0008,0x0020), ds).c_str() ); +#endif + // For ex: DICOM (0008,0022) = 20030617 + this->MedicalImageProperties->SetAcquisitionDate( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0008,0x0022), ds).c_str() ); +#if (VTK_MAJOR_VERSION > 5) || ( VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION > 0 ) + // For ex: DICOM (0008,0030) = 162552.0705 or 230012, or 0012 + this->MedicalImageProperties->SetStudyTime( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0008,0x0030), ds).c_str() ); +#endif + // For ex: DICOM (0008,0032) = 162552.0705 or 230012, or 0012 + this->MedicalImageProperties->SetAcquisitionTime( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0008,0x0032), ds).c_str() ); + // For ex: DICOM (0008,0023) = 20030617 + this->MedicalImageProperties->SetImageDate( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0008,0x0023), ds).c_str() ); + // For ex: DICOM (0008,0033) = 162552.0705 or 230012, or 0012 + this->MedicalImageProperties->SetImageTime( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0008,0x0033), ds).c_str() ); + // For ex: DICOM (0020,0013) = 1 + this->MedicalImageProperties->SetImageNumber( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0020,0x0013), ds).c_str() ); + // For ex: DICOM (0020,0011) = 902 + this->MedicalImageProperties->SetSeriesNumber( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0020,0x0011), ds).c_str() ); + // For ex: DICOM (0008,103e) = SCOUT + this->MedicalImageProperties->SetSeriesDescription( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0008,0x103e), ds).c_str() ); + // For ex: DICOM (0020,0010) = 37481 + this->MedicalImageProperties->SetStudyID( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0020,0x0010), ds).c_str() ); + // For ex: DICOM (0008,1030) = BRAIN/C-SP/FACIAL + this->MedicalImageProperties->SetStudyDescription( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0008,0x1030), ds).c_str() ); + // For ex: DICOM (0008,0060)= CT + this->MedicalImageProperties->SetModality( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0008,0x0060), ds).c_str() ); + // For ex: DICOM (0008,0070) = Siemens + this->MedicalImageProperties->SetManufacturer( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0008,0x0070), ds).c_str() ); + // For ex: DICOM (0008,1090) = LightSpeed QX/i + this->MedicalImageProperties->SetManufacturerModelName( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0008,0x1090), ds).c_str() ); + // For ex: DICOM (0008,1010) = LSPD_OC8 + this->MedicalImageProperties->SetStationName( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0008,0x1010), ds).c_str() ); + // For ex: DICOM (0008,0080) = FooCity Medical Center + this->MedicalImageProperties->SetInstitutionName( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0008,0x0080), ds).c_str() ); + // For ex: DICOM (0018,1210) = Bone + this->MedicalImageProperties->SetConvolutionKernel( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0018,0x1210), ds).c_str() ); + // For ex: DICOM (0018,0050) = 0.273438 + this->MedicalImageProperties->SetSliceThickness( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0018,0x0050), ds).c_str() ); + // For ex: DICOM (0018,0060) = 120 + this->MedicalImageProperties->SetKVP( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0018,0x0060), ds).c_str() ); + // For ex: DICOM (0018,1120) = 15 + this->MedicalImageProperties->SetGantryTilt( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0018,0x1120), ds).c_str() ); + // For ex: DICOM (0018,0081) = 105 + this->MedicalImageProperties->SetEchoTime( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0018,0x0081), ds).c_str() ); + // For ex: DICOM (0018,0091) = 35 + this->MedicalImageProperties->SetEchoTrainLength( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0018,0x0091), ds).c_str() ); + // For ex: DICOM (0018,0080) = 2040 + this->MedicalImageProperties->SetRepetitionTime( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0018,0x0080), ds).c_str() ); + // For ex: DICOM (0018,1150) = 5 + this->MedicalImageProperties->SetExposureTime( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0018,0x1150), ds).c_str() ); + // For ex: DICOM (0018,1151) = 400 + this->MedicalImageProperties->SetXRayTubeCurrent( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0018,0x1151), ds).c_str() ); + // For ex: DICOM (0018,1152) = 114 + this->MedicalImageProperties->SetExposure( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0018,0x1152), ds).c_str() ); + + // virtual void AddWindowLevelPreset(double w, double l); + // (0028,1050) DS [ 498\ 498] # 12, 2 WindowCenter + // (0028,1051) DS [ 1063\ 1063] # 12, 2 WindowWidth + gdcm::Tag twindowcenter(0x0028,0x1050); + gdcm::Tag twindowwidth(0x0028,0x1051); + if( ds.FindDataElement( twindowcenter ) && ds.FindDataElement( twindowwidth) ) + { + const gdcm::DataElement& windowcenter = ds.GetDataElement( twindowcenter ); + const gdcm::DataElement& windowwidth = ds.GetDataElement( twindowwidth ); + const gdcm::ByteValue *bvwc = windowcenter.GetByteValue(); + const gdcm::ByteValue *bvww = windowwidth.GetByteValue(); + if( bvwc && bvww ) // Can be Type 2 + { + //gdcm::Attributes<0x0028,0x1050> at; + gdcm::Element elwc; + std::stringstream ss1; + std::string swc = std::string( bvwc->GetPointer(), bvwc->GetLength() ); + ss1.str( swc ); + gdcm::VR vr = gdcm::VR::DS; + unsigned int vrsize = vr.GetSizeof(); + unsigned int count = gdcm::VM::GetNumberOfElementsFromArray(swc.c_str(), (unsigned int)swc.size()); + elwc.SetLength( count * vrsize ); + elwc.Read( ss1 ); + std::stringstream ss2; + std::string sww = std::string( bvww->GetPointer(), bvww->GetLength() ); + ss2.str( sww ); + gdcm::Element elww; + elww.SetLength( count * vrsize ); + elww.Read( ss2 ); + //assert( elww.GetLength() == elwc.GetLength() ); + for(unsigned int i = 0; i < elwc.GetLength(); ++i) + { + this->MedicalImageProperties->AddWindowLevelPreset( elww.GetValue(i), elwc.GetValue(i) ); + } + } + } + gdcm::Tag twindowexplanation(0x0028,0x1055); + if( ds.FindDataElement( twindowexplanation ) ) + { + const gdcm::DataElement& windowexplanation = ds.GetDataElement( twindowexplanation ); + const gdcm::ByteValue *bvwe = windowexplanation.GetByteValue(); + if( bvwe ) // Can be Type 2 + { + unsigned int n = this->MedicalImageProperties->GetNumberOfWindowLevelPresets(); + gdcm::Element elwe; // window explanation + gdcm::VR vr = gdcm::VR::LO; + std::stringstream ss; + ss.str( "" ); + std::string swe = std::string( bvwe->GetPointer(), bvwe->GetLength() ); + unsigned int count = gdcm::VM::GetNumberOfElementsFromArray(swe.c_str(), (unsigned int)swe.size()); (void)count; + // I found a case with only one W/L but two comments: WINDOW1\WINDOW2 + // SIEMENS-IncompletePixelData.dcm + // oh wait but what if we have the countrary... + //assert( count >= (unsigned int)n ); + elwe.SetLength( count * vr.GetSizeof() ); + ss.str( swe ); + elwe.Read( ss ); + unsigned int c = std::min(n, count); + for(unsigned int i = 0; i < c; ++i) + { + this->MedicalImageProperties->SetNthWindowLevelPresetComment(i, elwe.GetValue(i).c_str() ); + } + } + } + +#if 0 + // gdcmData/JDDICOM_Sample4.dcm + // -> (0008,0060) CS [DM Digital microscopy] # 24, 1 Modality + gdcm::MediaStorage ms1 = gdcm::MediaStorage::SecondaryCaptureImageStorage; + ms1.GuessFromModality( this->MedicalImageProperties->GetModality(), this->FileDimensionality ); + gdcm::MediaStorage ms2; + ms2.SetFromFile( reader.GetFile() ); + if( ms2 != ms1 && ms2 != gdcm::MediaStorage::SecondaryCaptureImageStorage ) + { + vtkWarningMacro( "SHOULD NOT HAPPEN. Unrecognized Modality: " << this->MedicalImageProperties->GetModality() + << " Will be set instead to the known one: " << ms2.GetModality() ) + this->MedicalImageProperties->SetModality( ms2.GetModality() ); + } +#endif + + // Add more info: + vtkGDCMMedicalImageProperties *gdcmmip = + dynamic_cast( this->MedicalImageProperties ); + if( gdcmmip ) + { + gdcmmip->PushBackFile( file ); + } +} + +//---------------------------------------------------------------------------- +#if (VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 ) +int vtkGDCMImageReader::RequestInformation(vtkInformation *request, + vtkInformationVector **inputVector, + vtkInformationVector *outputVector) +{ + (void)request;(void)inputVector; + int res = RequestInformationCompat(); + if( !res ) + { + vtkErrorMacro( "RequestInformationCompat failed: " << res ); + this->SetErrorCode(vtkErrorCode::FileFormatError); + return 0; + } + + int numvol = 1; + if( this->LoadIconImage ) + { + numvol = 2; + } + if( this->LoadOverlays ) + { + // If no icon found, we still need to be associated to port #2: + numvol = 2 + this->NumberOfOverlays; + } + this->SetNumberOfOutputPorts(numvol); + // For each output: + for(int i = 0; i < numvol; ++i) + { + // Allocate ! + if( !this->GetOutput(i) ) + { + vtkImageData *img = vtkImageData::New(); + this->GetExecutive()->SetOutputData(i, img ); + img->Delete(); + } + vtkInformation *outInfo = outputVector->GetInformationObject(i); + switch(i) + { + // root Pixel Data + case 0: + outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), this->DataExtent, 6); + //outInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(), this->DataExtent, 6); + outInfo->Set(vtkDataObject::SPACING(), this->DataSpacing, 3); +#ifdef GDCMV2_0_COMPATIBILITY + outInfo->Set(vtkDataObject::ORIGIN(), this->DataOrigin, 3); +#endif + vtkDataObject::SetPointDataActiveScalarInfo(outInfo, this->DataScalarType, this->NumberOfScalarComponents); + break; + // Icon Image + case ICONIMAGEPORTNUMBER: + outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), this->IconImageDataExtent, 6); + vtkDataObject::SetPointDataActiveScalarInfo(outInfo, this->IconDataScalarType, this->IconNumberOfScalarComponents ); + break; + // Overlays: + //case OVERLAYPORTNUMBER: + default: + outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), + this->DataExtent[0], this->DataExtent[1], + this->DataExtent[2], this->DataExtent[3], + 0,0 ); + vtkDataObject::SetPointDataActiveScalarInfo(outInfo, VTK_UNSIGNED_CHAR, 1); + break; + } + } + + //return res; + return 1; +} +#endif + +static gdcm::PixelFormat::ScalarType +ComputePixelTypeFromFiles(const char *inputfilename, vtkStringArray *filenames, + gdcm::Image const & imageref) +{ + gdcm::PixelFormat::ScalarType outputpt ; + outputpt = gdcm::PixelFormat::UNKNOWN; + // there is a very subtle bug here. Let's imagine we have a collection of files + // they can all have different Rescale Slope / Intercept. In this case we should: + // 1. Make sure to read each Rescale Slope / Intercept individually + // 2. Make sure to decide which Pixel Type to use using *all* slices: + if( inputfilename ) + { + const gdcm::Image &image = imageref; + const gdcm::PixelFormat &pixeltype = image.GetPixelFormat(); + double shift = image.GetIntercept(); + double scale = image.GetSlope(); + + gdcm::Rescaler r; + r.SetIntercept( shift ); + r.SetSlope( scale ); + r.SetPixelFormat( pixeltype ); + outputpt = r.ComputeInterceptSlopePixelType(); + } + else if ( filenames && filenames->GetNumberOfValues() > 0 ) + { + std::set< gdcm::PixelFormat::ScalarType > pixeltypes; + std::set< unsigned short > samplesperpixel; + // FIXME a gdcm::Scanner would be much faster here: + for(int i = 0; i < filenames->GetNumberOfValues(); ++i ) + { + const char *filename = filenames->GetValue( i ); + gdcm::ImageReader reader; + reader.SetFileName( filename ); + if( !reader.Read() ) + { + vtkGenericWarningMacro( "ImageReader failed: " << filename ); + return gdcm::PixelFormat::UNKNOWN; + } + const gdcm::Image &image = reader.GetImage(); + const gdcm::PixelFormat &pixeltype = image.GetPixelFormat(); + samplesperpixel.insert( pixeltype.GetSamplesPerPixel() ); + + double shift = image.GetIntercept(); + double scale = image.GetSlope(); + + gdcm::PixelFormat::ScalarType outputpt2 = pixeltype; + gdcm::Rescaler r; + r.SetIntercept( shift ); + r.SetSlope( scale ); + r.SetPixelFormat( pixeltype ); + outputpt2 = r.ComputeInterceptSlopePixelType(); + //std::cout << "Found: " << outputpt << std::endl; + pixeltypes.insert( outputpt2 ); + } + if( pixeltypes.size() == 1 ) + { + assert( samplesperpixel.size() == 1 ); + // Ok easy case + outputpt = *pixeltypes.begin(); + } + else if( samplesperpixel.size() == 1 ) + { + // Hardcoded. If Pixel Type found is the maximum (as of PS 3.5 - 2008) + // There is nothing bigger that FLOAT64 + if( pixeltypes.count( gdcm::PixelFormat::FLOAT64 ) != 0 ) + { + outputpt = gdcm::PixelFormat::FLOAT64; + } + else + { + // should I just take the biggest value ? + // MM: I am not sure UINT16 and INT16 are really compatible + // so taking the biggest value might not be the solution + // In this case we could use INT32, but FLOAT64 also works... + // oh well, let's just use FLOAT64 always. + vtkGenericWarningMacro( "This may not always be optimized. Sorry" ); + outputpt = gdcm::PixelFormat::FLOAT64; + } + } + else + { + vtkGenericWarningMacro( "Could not compute Pixel Type. Sorry" ); + } + } + else + { + assert( 0 ); // I do not think this is possible + } + //gdcmAssertMacro( outputpt >= pixeltype_ref ); + //(void)pixeltype_ref; + + return outputpt; +} + +//---------------------------------------------------------------------------- +int vtkGDCMImageReader::RequestInformationCompat() +{ + // FIXME, need to implement the other modes too: + if( this->ApplyLookupTable || this->ApplyYBRToRGB || this->ApplyInverseVideo ) + { + vtkErrorMacro( "ApplyLookupTable/ApplyYBRToRGB/ApplyInverseVideo not compatible" ); + return 0; + } + // I do not think this is a good idea anyway to let the user decide + // wether or not she wants *not* to apply shift/scale... + if( !this->ApplyShiftScale ) + { + vtkErrorMacro("ApplyShiftScale not compatible" ); + return 0; + } + // I do not think this one will ever be implemented: + if( !this->ApplyPlanarConfiguration ) + { + vtkErrorMacro("ApplyPlanarConfiguration not compatible" ); + return 0; + } + + // Let's read the first file : + const char *filename; + if( this->FileName ) + { + filename = this->FileName; + } + else if ( this->FileNames && this->FileNames->GetNumberOfValues() > 0 ) + { + filename = this->FileNames->GetValue( 0 ); + } + else + { + // hey! I need at least one file to schew on ! + vtkErrorMacro( "You did not specify any filenames" ); + return 0; + } + gdcm::ImageReader reader; + reader.SetFileName( filename ); + if( !reader.Read() ) + { + vtkErrorMacro( "ImageReader failed on " << filename ); + return 0; + } + const gdcm::Image &image = reader.GetImage(); + this->LossyFlag = image.IsLossy(); + const unsigned int *dims = image.GetDimensions(); + + // Set the Extents. + assert( image.GetNumberOfDimensions() >= 2 ); + this->DataExtent[0] = 0; + this->DataExtent[1] = dims[0] - 1; + this->DataExtent[2] = 0; + this->DataExtent[3] = dims[1] - 1; + if( image.GetNumberOfDimensions() == 2 ) + { + // This is just so much painful to deal with DICOM / VTK + // they simply assume that number of file is equal to the dimension + // of the last axe (see vtkImageReader2::SetFileNames ) + if ( this->FileNames && this->FileNames->GetNumberOfValues() > 1 ) + { + this->DataExtent[4] = 0; + //this->DataExtent[5] = this->FileNames->GetNumberOfValues() - 1; + } + else + { + this->DataExtent[4] = 0; + this->DataExtent[5] = 0; + } + } + else + { + assert( image.GetNumberOfDimensions() == 3 ); + this->FileDimensionality = 3; + this->DataExtent[4] = 0; + this->DataExtent[5] = dims[2] - 1; + } + gdcm::MediaStorage ms; + ms.SetFromFile( reader.GetFile() ); + assert( gdcm::MediaStorage::IsImage( ms ) || ms == gdcm::MediaStorage::MRSpectroscopyStorage ); + // There is no point in adding world info to a SC object since noone but GDCM can use this info... + //if( ms != gdcm::MediaStorage::SecondaryCaptureImageStorage ) + + const double *spacing = image.GetSpacing(); + if( spacing ) + { + this->DataSpacing[0] = spacing[0]; + this->DataSpacing[1] = spacing[1]; + this->DataSpacing[2] = image.GetSpacing(2); + } + + const double *origin = image.GetOrigin(); + if( origin ) + { + this->ImagePositionPatient[0] = image.GetOrigin(0); + this->ImagePositionPatient[1] = image.GetOrigin(1); + this->ImagePositionPatient[2] = image.GetOrigin(2); + } + + const double *dircos = image.GetDirectionCosines(); + if( dircos ) + { + this->DirectionCosines->SetElement(0,0, dircos[0]); + this->DirectionCosines->SetElement(1,0, dircos[1]); + this->DirectionCosines->SetElement(2,0, dircos[2]); + this->DirectionCosines->SetElement(3,0, 0); + this->DirectionCosines->SetElement(0,1, dircos[3]); + this->DirectionCosines->SetElement(1,1, dircos[4]); + this->DirectionCosines->SetElement(2,1, dircos[5]); + this->DirectionCosines->SetElement(3,1, 0); + double dircosz[3]; + vtkMath::Cross(dircos, dircos+3, dircosz); + this->DirectionCosines->SetElement(0,2, dircosz[0]); + this->DirectionCosines->SetElement(1,2, dircosz[1]); + this->DirectionCosines->SetElement(2,2, dircosz[2]); + this->DirectionCosines->SetElement(3,2, 0); + //std::cout << "Det: " << this->DirectionCosines->Determinant() << std::endl; + + for(int i=0;i<6;++i) + this->ImageOrientationPatient[i] = dircos[i]; +#if ( VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION > 2 ) + this->MedicalImageProperties->SetDirectionCosine( this->ImageOrientationPatient ); +#endif + } + // Apply transform: +#ifdef GDCMV2_0_COMPATIBILITY + if( dircos && origin ) + { + if( this->FileLowerLeft ) + { + // Since we are not doing the VTK Y-flipping operation, Origin and Image Position (Patient) + // are the same: + this->DataOrigin[0] = origin[0]; + this->DataOrigin[1] = origin[1]; + this->DataOrigin[2] = origin[2]; + } + else + { + // We are doing the Y-flip: + // translate Image Position (Patient) along the Y-vector of the Image Orientation (Patient): + // Step 1: Compute norm of translation vector: + // Because position is in the center of the pixel, we need to substract 1 to the dimY: + assert( dims[1] >=1 ); + double norm = (dims[1] - 1) * this->DataSpacing[1]; + // Step 2: translate: + this->DataOrigin[0] = origin[0] + norm * dircos[3+0]; + this->DataOrigin[1] = origin[1] + norm * dircos[3+1]; + this->DataOrigin[2] = origin[2] + norm * dircos[3+2]; + } + } + // Need to set the rest to 0 ??? +#endif + + const gdcm::PixelFormat &pixeltype = image.GetPixelFormat(); + this->Shift = image.GetIntercept(); + this->Scale = image.GetSlope(); + + //gdcm::PixelFormat::ScalarType outputpt = pixeltype; + gdcm::PixelFormat::ScalarType outputpt = + ComputePixelTypeFromFiles(this->FileName, this->FileNames, image); + if( this->FileName ) + { + // We should test that outputpt is 8 when BitsAllocated = 16 / Bits Stored = 8 + // BUT we should test that output is 16 when BitsAllocated = 16 / BitsStored = 12 + // assert( outputpt == pixeltype ); + } + + // Compute output pixel format when Rescaling: +// if( this->Shift != 0 || this->Scale != 1. ) +// { +// gdcm::Rescaler r; +// r.SetIntercept( this->Shift ); +// r.SetSlope( this->Scale ); +// r.SetPixelFormat( pixeltype ); +// outputpt = r.ComputeInterceptSlopePixelType(); +// assert( pixeltype <= outputpt ); +// assert( pixeltype.GetSamplesPerPixel() == 1 && image.GetPhotometricInterpretation().GetSamplesPerPixel() == 1 ); +// assert( image.GetPhotometricInterpretation() != gdcm::PhotometricInterpretation::PALETTE_COLOR ); +// } + //if( pixeltype != outputpt ) assert( Shift != 0. || Scale != 1 ); + + this->ForceRescale = 0; // always reset this thing + // gdcmData/DCMTK_JPEGExt_12Bits.dcm + if( pixeltype != outputpt && pixeltype.GetBitsAllocated() != 12 ) + { + this->ForceRescale = 1; + } + + switch( outputpt ) + { + case gdcm::PixelFormat::INT8: +#if (VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 ) + this->DataScalarType = VTK_SIGNED_CHAR; +#else + if( !vtkGDCMImageReader_IsCharTypeSigned() ) + { + vtkErrorMacro( "Output Pixel Type will be incorrect, go get a newer VTK version" ); + } + this->DataScalarType = VTK_CHAR; +#endif + break; + case gdcm::PixelFormat::UINT8: + this->DataScalarType = VTK_UNSIGNED_CHAR; + break; + case gdcm::PixelFormat::INT16: + this->DataScalarType = VTK_SHORT; + break; + case gdcm::PixelFormat::UINT16: + this->DataScalarType = VTK_UNSIGNED_SHORT; + break; + // RT / SC have 32bits + case gdcm::PixelFormat::INT32: + this->DataScalarType = VTK_INT; + break; + case gdcm::PixelFormat::UINT32: + this->DataScalarType = VTK_UNSIGNED_INT; + break; + case gdcm::PixelFormat::INT12: + this->DataScalarType = VTK_SHORT; + break; + case gdcm::PixelFormat::UINT12: + this->DataScalarType = VTK_UNSIGNED_SHORT; + break; + //case gdcm::PixelFormat::FLOAT16: // TODO + case gdcm::PixelFormat::FLOAT32: + this->DataScalarType = VTK_FLOAT; + break; + case gdcm::PixelFormat::FLOAT64: + this->DataScalarType = VTK_DOUBLE; + break; + case gdcm::PixelFormat::SINGLEBIT: + this->DataScalarType = VTK_BIT; + break; + default: + this->SetErrorCode(vtkErrorCode::FileFormatError); + vtkErrorMacro( "Do not support this Pixel Type: " << (int)pixeltype.GetScalarType() + << " with " << (int)outputpt ); + return 0; + } + this->NumberOfScalarComponents = pixeltype.GetSamplesPerPixel(); + + // Ok let's fill in the 'extra' info: + this->FillMedicalImageInformation(reader); + + // Do the IconImage if requested: + const gdcm::IconImage& icon = image.GetIconImage(); + if( this->LoadIconImage && !icon.IsEmpty() ) + { + this->IconImageDataExtent[0] = 0; + this->IconImageDataExtent[1] = icon.GetColumns() - 1; + this->IconImageDataExtent[2] = 0; + this->IconImageDataExtent[3] = icon.GetRows() - 1; + // + const gdcm::PixelFormat &iconpixelformat = icon.GetPixelFormat(); + switch(iconpixelformat) + { + case gdcm::PixelFormat::INT8: +#if (VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 ) + this->IconDataScalarType = VTK_SIGNED_CHAR; +#else + this->IconDataScalarType = VTK_CHAR; +#endif + break; + case gdcm::PixelFormat::UINT8: + this->IconDataScalarType = VTK_UNSIGNED_CHAR; + break; + case gdcm::PixelFormat::INT16: + this->IconDataScalarType = VTK_SHORT; + break; + case gdcm::PixelFormat::UINT16: + this->IconDataScalarType = VTK_UNSIGNED_SHORT; + break; + default: + vtkErrorMacro( "Do not support this Icon Pixel Type: " << (int)iconpixelformat.GetScalarType() ); + return 0; + } + this->IconNumberOfScalarComponents = iconpixelformat.GetSamplesPerPixel(); + } + + // Overlay! + size_t numoverlays = image.GetNumberOfOverlays(); + if( this->LoadOverlays && numoverlays ) + { + // Do overlay specific stuff... + // what if overlay do not have the same data extent as image ? + for( unsigned int ovidx = 0; ovidx < numoverlays; ++ovidx ) + { + const gdcm::Overlay& ov = image.GetOverlay(ovidx); + assert( (unsigned int)ov.GetRows() == image.GetRows() ); (void)ov; + assert( (unsigned int)ov.GetColumns() == image.GetColumns() ); + } + this->NumberOfOverlays = (int)numoverlays; + } + +// return this->Superclass::RequestInformation( +// request, inputVector, outputVector); + + return 1; +} + +//---------------------------------------------------------------------------- +template +static inline unsigned long vtkImageDataGetTypeSize(T*, int a = 0,int b = 0) +{ + (void)a;(void)b; + return sizeof(T); +} + +//---------------------------------------------------------------------------- +static void InPlaceYFlipImage(vtkImageData* data, const int dext[6]) +{ + unsigned long outsize = data->GetNumberOfScalarComponents(); + if( dext[1] == dext[0] && dext[0] == 0 ) return; + + // Multiply by the number of bytes per scalar + switch (data->GetScalarType()) + { +#if (VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 ) + case VTK_BIT: { outsize /= 8; }; break; + vtkTemplateMacro( + outsize *= vtkImageDataGetTypeSize(static_cast(0)) + ); +#else + case VTK_BIT: { outsize /= 8; }; break; + vtkTemplateMacro3( + outsize *= vtkImageDataGetTypeSize, static_cast(0), 0, 0 + ); +#endif + default: + //vtkErrorMacro("do not support scalar type: " << data->GetScalarType() ); + assert(0); + } + outsize *= (dext[1] - dext[0] + 1); + char * ref = static_cast(data->GetScalarPointer()); + char * pointer = static_cast(data->GetScalarPointer()); + assert( pointer ); + + char *line = new char[outsize]; + + for(int j = dext[4]; j <= dext[5]; ++j) + { + char *start = pointer; + assert( start == ref + j * outsize * (dext[3] - dext[2] + 1) ); (void)ref; + // Swap two-lines at a time + // when Rows is odd number (359) then dext[3] == 178 + // so we should avoid copying the line right in the center of the image + // since memcpy does not like copying on itself... + for(int i = dext[2]; i < (dext[3]+1) / 2; ++i) + { + // image: + char * end = start+(dext[3] - i)*outsize; + assert( (end - pointer) >= (int)outsize ); + memcpy(line,end,outsize); // duplicate line + memcpy(end,pointer,outsize); + memcpy(pointer,line,outsize); + pointer += outsize; + } + // because the for loop iterated only over 1/2 all lines, skip to the next slice: + assert( dext[2] == 0 ); + pointer += (dext[3] + 1 - (dext[3]+1)/2 )*outsize; + } + // Did we reach the end ? + assert( pointer == ref + (dext[5]-dext[4]+1)*(dext[3]-dext[2]+1)*outsize ); + delete[] line; +} + +//---------------------------------------------------------------------------- +int vtkGDCMImageReader::LoadSingleFile(const char *filename, char *pointer, unsigned long &outlen) +{ + int *dext = this->GetDataExtent(); + vtkImageData *data = this->GetOutput(0); + //bool filelowerleft = this->FileLowerLeft ? true : false; + + //char * pointer = static_cast(data->GetScalarPointer()); + + gdcm::ImageReader reader; + reader.SetFileName( filename ); + if( !reader.Read() ) + { + vtkErrorMacro( "ImageReader failed: " << filename ); + return 0; + } + gdcm::Image &image = reader.GetImage(); + this->LossyFlag = image.IsLossy(); + //VTK does not cope with Planar Configuration, so let's schew the work to please it + assert( this->PlanarConfiguration == 0 || this->PlanarConfiguration == 1 ); + // Store the PlanarConfiguration before inverting it ! + this->PlanarConfiguration = image.GetPlanarConfiguration(); + //assert( this->PlanarConfiguration == 0 || this->PlanarConfiguration == 1 ); + if( image.GetPlanarConfiguration() == 1 ) + { + gdcm::ImageChangePlanarConfiguration icpc; + icpc.SetInput( image ); + icpc.SetPlanarConfiguration( 0 ); + icpc.Change(); + image = icpc.GetOutput(); + } + + const gdcm::PixelFormat &pixeltype = image.GetPixelFormat(); + assert( image.GetNumberOfDimensions() == 2 || image.GetNumberOfDimensions() == 3 ); + /*const*/ unsigned long len = image.GetBufferLength(); + outlen = len; + unsigned long overlaylen = 0; + //image.GetBuffer(pointer); + // HACK: Make sure that Shift/Scale are the one from the file: + this->Shift = image.GetIntercept(); + this->Scale = image.GetSlope(); + + if( (this->Scale != 1.0 || this->Shift != 0.0) || this->ForceRescale ) + { + assert( pixeltype.GetSamplesPerPixel() == 1 ); + gdcm::Rescaler r; + r.SetIntercept( Shift ); // FIXME + r.SetSlope( Scale ); // FIXME + gdcm::PixelFormat::ScalarType targetpixeltype = gdcm::PixelFormat::UNKNOWN; + // r.SetTargetPixelType( gdcm::PixelFormat::FLOAT64 ); + int scalarType = data->GetScalarType(); + switch( scalarType ) + { + case VTK_CHAR: + if( vtkGDCMImageReader_IsCharTypeSigned() ) + targetpixeltype = gdcm::PixelFormat::INT8; + else + targetpixeltype = gdcm::PixelFormat::UINT8; + break; +#if (VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 ) + case VTK_SIGNED_CHAR: + targetpixeltype = gdcm::PixelFormat::INT8; + break; +#endif + case VTK_UNSIGNED_CHAR: + targetpixeltype = gdcm::PixelFormat::UINT8; + break; + case VTK_SHORT: + targetpixeltype = gdcm::PixelFormat::INT16; + break; + case VTK_UNSIGNED_SHORT: + targetpixeltype = gdcm::PixelFormat::UINT16; + break; + case VTK_INT: + targetpixeltype = gdcm::PixelFormat::INT32; + break; + case VTK_UNSIGNED_INT: + targetpixeltype = gdcm::PixelFormat::UINT32; + break; + case VTK_FLOAT: + targetpixeltype = gdcm::PixelFormat::FLOAT32; + break; + case VTK_DOUBLE: + targetpixeltype = gdcm::PixelFormat::FLOAT64; + break; + case VTK_BIT: + targetpixeltype = gdcm::PixelFormat::SINGLEBIT; + break; + default: + vtkErrorMacro( "Do not support this Pixel Type: " << scalarType ); + assert( 0 ); + return 0; + } + r.SetTargetPixelType( targetpixeltype ); + + r.SetUseTargetPixelType(true); + r.SetPixelFormat( pixeltype ); + char * copy = new char[len]; + //memcpy(copy, pointer, len); + image.GetBuffer(copy); + if( !r.Rescale(pointer,copy,len) ) + { + vtkErrorMacro( "Could not Rescale" ); + // problem with gdcmData/3E768EB7.dcm + return 0; + } + delete[] copy; + // WARNING: sizeof(Real World Value) != sizeof(Stored Pixel) + outlen = data->GetScalarSize() * data->GetNumberOfPoints() / data->GetDimensions()[2]; + assert( data->GetNumberOfScalarComponents() == 1 ); + } + else + { + image.GetBuffer(pointer); + } + + // Do the Icon Image: + if( this->LoadIconImage ) + { + this->NumberOfIconImages = image.GetIconImage().IsEmpty() ? 0 : 1; + if( this->NumberOfIconImages ) + { + char * iconpointer = static_cast(this->GetOutput(ICONIMAGEPORTNUMBER)->GetScalarPointer()); + assert( iconpointer ); + image.GetIconImage().GetBuffer( iconpointer ); + if ( image.GetIconImage().GetPhotometricInterpretation() == gdcm::PhotometricInterpretation::PALETTE_COLOR ) + { + const gdcm::LookupTable &lut = image.GetIconImage().GetLUT(); + assert( lut.GetBitSample() == 8 ); + { + vtkLookupTable *vtklut = vtkLookupTable::New(); + vtklut->SetNumberOfTableValues(256); + // SOLVED: GetPointer(0) is skrew up, need to replace it with WritePointer(0,4) ... + if( !lut.GetBufferAsRGBA( vtklut->WritePointer(0,4) ) ) + { + vtkWarningMacro( "Could not get values from LUT" ); + return 0; + } + vtklut->SetRange(0,255); + this->GetOutput(ICONIMAGEPORTNUMBER)->GetPointData()->GetScalars()->SetLookupTable( vtklut ); + vtklut->Delete(); + } + } + } + } + + // Do the Curve: + size_t numcurves = image.GetNumberOfCurves(); + if( numcurves ) + { + const gdcm::Curve& curve = image.GetCurve(); + //curve.Print( std::cout ); + vtkPoints * pts = vtkPoints::New(); + pts->SetNumberOfPoints( curve.GetNumberOfPoints() ); + curve.GetAsPoints( (float*)pts->GetVoidPointer(0) ); + vtkCellArray *polys = vtkCellArray::New(); + for(unsigned int i = 0; i < curve.GetNumberOfPoints(); i+=2 ) + { + polys->InsertNextCell(2); + polys->InsertCellPoint(i); + polys->InsertCellPoint(i+1); + } + vtkPolyData *cube = vtkPolyData::New(); + cube->SetPoints(pts); + pts->Delete(); + cube->SetLines(polys); + polys->Delete(); + SetCurve(cube); + cube->Delete(); + } + + // Do the Overlay: + if( this->LoadOverlays ) + { + size_t numoverlays = image.GetNumberOfOverlays(); + long overlayoutsize = (dext[1] - dext[0] + 1); + //this->NumberOfOverlays = numoverlays; + //if( numoverlays ) + if( !this->LoadOverlays ) assert( this->NumberOfOverlays == 0 ); + for( int ovidx = 0; ovidx < this->NumberOfOverlays; ++ovidx ) + { + vtkImageData *vtkimage = this->GetOutput(OVERLAYPORTNUMBER + ovidx); + // vtkOpenGLImageMapper::RenderData does not support bit array (since OpenGL does not either) + // we have to decompress the bit overlay into an unsigned char array to please everybody: + const gdcm::Overlay& ov1 = image.GetOverlay(ovidx); + vtkUnsignedCharArray *chararray = vtkUnsignedCharArray::New(); + chararray->SetNumberOfTuples( overlayoutsize * ( dext[3] - dext[2] + 1 ) ); + overlaylen = overlayoutsize * ( dext[3] - dext[2] + 1 ); + assert( (unsigned long)ov1.GetRows()*ov1.GetColumns() <= overlaylen ); + const signed short *origin = ov1.GetOrigin(); + if( (unsigned long)ov1.GetRows()*ov1.GetColumns() != overlaylen ) + { + vtkWarningMacro( "vtkImageData Overlay have an extent that do not match the one of the image" ); + } + if( origin[0] != 1 || origin[1] != 1 ) + { + // Table C.9-2 OVERLAY PLANE MODULE ATTRIBUTES + vtkWarningMacro( "Overlay with origin are not supported right now" ); + } + vtkimage->GetPointData()->SetScalars( chararray ); + vtkimage->GetPointData()->GetScalars()->SetName( ov1.GetDescription() ); + chararray->Delete(); + + assert( vtkimage->GetScalarType() == VTK_UNSIGNED_CHAR ); + char * overlaypointer = static_cast(vtkimage->GetScalarPointer()); + assert( overlaypointer ); + //assert( image->GetPointData()->GetScalars() != 0 ); + + //memset(overlaypointer,0,overlaylen); // FIXME: can be optimized + if( !ov1.GetUnpackBuffer( overlaypointer, overlaylen ) ) + { + vtkErrorMacro( "Problem in GetUnpackBuffer" ); + } + } + if( numoverlays ) assert( (unsigned long)overlayoutsize * ( dext[3] - dext[2] + 1 ) == overlaylen ); + } + + //const gdcm::PixelFormat &pixeltype = image.GetPixelFormat(); + // Do the LUT + if ( image.GetPhotometricInterpretation() == gdcm::PhotometricInterpretation::PALETTE_COLOR ) + { + this->ImageFormat = VTK_LOOKUP_TABLE; + const gdcm::LookupTable &lut = image.GetLUT(); + if( lut.GetBitSample() == 8 ) + { + vtkLookupTable *vtklut = vtkLookupTable::New(); + vtklut->SetNumberOfTableValues(256); + // SOLVED: GetPointer(0) is skrew up, need to replace it with WritePointer(0,4) ... + if( !lut.GetBufferAsRGBA( vtklut->WritePointer(0,4) ) ) + { + vtkWarningMacro( "Could not get values from LUT" ); + return 0; + } + vtklut->SetRange(0,255); + data->GetPointData()->GetScalars()->SetLookupTable( vtklut ); + vtklut->Delete(); + } + else + { +#if (VTK_MAJOR_VERSION >= 5) + assert( lut.GetBitSample() == 16 ); + vtkLookupTable16 *vtklut = vtkLookupTable16::New(); + vtklut->SetNumberOfTableValues(256*256); + // SOLVED: GetPointer(0) is skrew up, need to replace it with WritePointer(0,4) ... + if( !lut.GetBufferAsRGBA( (unsigned char*)vtklut->WritePointer(0,4) ) ) + { + vtkWarningMacro( "Could not get values from LUT" ); + return 0; + } + vtklut->SetRange(0,256*256-1); + data->GetPointData()->GetScalars()->SetLookupTable( vtklut ); + vtklut->Delete(); +#else + vtkWarningMacro( "Unhandled" ); +#endif + } + } + else if ( image.GetPhotometricInterpretation() == gdcm::PhotometricInterpretation::MONOCHROME1 ) + { + this->ImageFormat = VTK_INVERSE_LUMINANCE; + vtkWindowLevelLookupTable *vtklut = vtkWindowLevelLookupTable::New(); + // Technically we could also use the first of the Window Width / Window Center + // oh well, if they are missing let's just compute something: + const double min = (double)pixeltype.GetMin(); + const double max = (double)pixeltype.GetMax(); + vtklut->SetWindow( max - min ); + vtklut->SetLevel( 0.5 * (max + min) ); + //vtklut->SetWindow(1024); // WindowWidth + //vtklut->SetLevel(550); // WindowCenter + vtklut->InverseVideoOn(); + data->GetPointData()->GetScalars()->SetLookupTable( vtklut ); + vtklut->Delete(); + } + else if ( image.GetPhotometricInterpretation() == gdcm::PhotometricInterpretation::YBR_FULL_422 ) + { + this->ImageFormat = VTK_YBR; + } + else if ( image.GetPhotometricInterpretation() == gdcm::PhotometricInterpretation::YBR_FULL ) + { + this->ImageFormat = VTK_YBR; + } + else if ( image.GetPhotometricInterpretation() == gdcm::PhotometricInterpretation::RGB ) + { + this->ImageFormat = VTK_RGB; + } + else if ( image.GetPhotometricInterpretation() == gdcm::PhotometricInterpretation::MONOCHROME2 ) + { + this->ImageFormat = VTK_LUMINANCE; + } + else if ( image.GetPhotometricInterpretation() == gdcm::PhotometricInterpretation::YBR_RCT ) + { + this->ImageFormat = VTK_RGB; + } + else if ( image.GetPhotometricInterpretation() == gdcm::PhotometricInterpretation::YBR_ICT ) + { + this->ImageFormat = VTK_RGB; + } + else if ( image.GetPhotometricInterpretation() == gdcm::PhotometricInterpretation::CMYK ) + { + this->ImageFormat = VTK_CMYK; + } + else if ( image.GetPhotometricInterpretation() == gdcm::PhotometricInterpretation::ARGB ) + { + this->ImageFormat = VTK_RGBA; + } + else + { + // HSV / CMYK ??? + // let's just give up for now + vtkErrorMacro( "Does not handle: " << image.GetPhotometricInterpretation().GetString() ); + //return 0; + } + //assert( this->ImageFormat ); + + long outsize; + if( data->GetScalarType() == VTK_BIT ) + { + outsize = (dext[1] - dext[0] + 1) / 8; + } + else + { + outsize = pixeltype.GetPixelSize()*(dext[1] - dext[0] + 1); + } + + if( this->FileName) assert( (unsigned long)outsize * (dext[3] - dext[2]+1) * (dext[5]-dext[4]+1) == len ); + + return 1; // success +} + + +//---------------------------------------------------------------------------- +#if (VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 ) +int vtkGDCMImageReader::RequestData(vtkInformation *vtkNotUsed(request), + vtkInformationVector **vtkNotUsed(inputVector), + vtkInformationVector *outputVector) +{ + //this->UpdateProgress(0.2); + + // Make sure the output dimension is OK, and allocate its scalars + + for(int i = 0; i < this->GetNumberOfOutputPorts(); ++i) + { +#if (VTK_MAJOR_VERSION >= 6) + vtkInformation* outInfo = outputVector->GetInformationObject(i); + vtkImageData *data = static_cast(outInfo->Get(vtkDataObject::DATA_OBJECT())); + // Make sure that this output is an image + if (data) + { + int extent[6]; + outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(), extent); + this->AllocateOutputData(data, outInfo, extent); + } +#else + (void)outputVector; + // Copy/paste from vtkImageAlgorithm::AllocateScalars. Cf. "this needs to be fixed -Ken" + vtkStreamingDemandDrivenPipeline *sddp = + vtkStreamingDemandDrivenPipeline::SafeDownCast(this->GetExecutive()); + if (sddp) + { + int extent[6]; + sddp->GetOutputInformation(i)->Get(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(),extent); + this->GetOutput(i)->SetExtent(extent); + } + this->GetOutput(i)->AllocateScalars(); +#endif + } + int res = RequestDataCompat(); + return res; +} +#endif + +//---------------------------------------------------------------------------- +int vtkGDCMImageReader::RequestDataCompat() +{ + vtkImageData *output = this->GetOutput(0); + output->GetPointData()->GetScalars()->SetName("GDCMImage"); + + // The outExt is the allocated data extent + int outExt[6]; + output->GetExtent(outExt); + // The dext is the whole extent (includes not-loaded data) + int *dext = this->GetDataExtent(); + //vtkIdType outInc[3]; + //data->GetIncrements(outInc); + //int outSize[3]; + //data->GetDimensions(outSize); + + //void *outPtr = data->GetScalarPointerForExtent(outExt); + + char * pointer = static_cast(output->GetScalarPointerForExtent(outExt)); + if( this->FileName ) + { + const char *filename = this->FileName; + unsigned long len; + int load = this->LoadSingleFile( filename, pointer, len ); (void)len; + if( !load ) + { + // FIXME: I need to fill the buffer with 0, shouldn't I ? + return 0; + } + } + else if( this->FileNames && this->FileNames->GetNumberOfValues() >= 1 ) + { + // Load each 2D files + // HACK: len is moved out of the loop so that when file > 1 start failing we can still know + // the len of the buffer...technically all files should have the same len (not checked for now) + unsigned long len = 0; + for(int j = dext[4]; !this->AbortExecute && j <= dext[5]; ++j) + { + assert( j >= 0 && j <= this->FileNames->GetNumberOfValues() ); + const char *filename = this->FileNames->GetValue( j ); + int load = this->LoadSingleFile( filename, pointer, len ); + if( !load ) + { + // hum... we could not read this file within the series, let's just fill + // the slice with 0 value, hopefully this should be the right thing to do + memset( pointer, 0, len); + } + assert( len ); + pointer += len; + this->UpdateProgress( (double)(j - dext[4] ) / ( dext[5] - dext[4] )); + } + } + else + { + return 0; + } + // Y-flip image + if (!this->FileLowerLeft) + { + InPlaceYFlipImage(this->GetOutput(0), dext); + if( this->LoadIconImage ) + { + int *iiext = this->IconImageDataExtent; + InPlaceYFlipImage(this->GetOutput(ICONIMAGEPORTNUMBER), iiext); + } + for( int ovidx = 0; ovidx < this->NumberOfOverlays; ++ovidx ) + { + assert( this->LoadOverlays ); + int oext[6]; + this->GetDataExtent(oext); + oext[4] = 0; + oext[5] = 0; + InPlaceYFlipImage(this->GetOutput(OVERLAYPORTNUMBER+ovidx), oext); + } + } + + return 1; +} + +//---------------------------------------------------------------------------- +#if (VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 ) +vtkAlgorithmOutput* vtkGDCMImageReader::GetOverlayPort(int index) +{ + if( index >= 0 && index < this->NumberOfOverlays) + return this->GetOutputPort(index+OVERLAYPORTNUMBER); + return NULL; +} +vtkAlgorithmOutput* vtkGDCMImageReader::GetIconImagePort() +{ + const int index = 0; + if( index >= 0 && index < this->NumberOfIconImages) + return this->GetOutputPort(index+ICONIMAGEPORTNUMBER); + return NULL; +} +#endif + +//---------------------------------------------------------------------------- +vtkImageData* vtkGDCMImageReader::GetOverlay(int i) +{ + if( i >= 0 && i < this->NumberOfOverlays) + return this->GetOutput(i+OVERLAYPORTNUMBER); + return NULL; +} + +//---------------------------------------------------------------------------- +vtkImageData* vtkGDCMImageReader::GetIconImage() +{ + const int i = 0; + if( i >= 0 && i < this->NumberOfIconImages) + return this->GetOutput(i+ICONIMAGEPORTNUMBER); + return NULL; +} + +//---------------------------------------------------------------------------- +void vtkGDCMImageReader::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os,indent); +} diff --git a/gdcm/Utilities/VTK/vtkGDCMImageReader.h b/gdcm/Utilities/VTK/vtkGDCMImageReader.h new file mode 100644 index 0000000..bf016f1 --- /dev/null +++ b/gdcm/Utilities/VTK/vtkGDCMImageReader.h @@ -0,0 +1,316 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +// .NAME vtkGDCMImageReader - read DICOM Image files (Pixel Data) +// .SECTION Description +// vtkGDCMImageReader is a source object that reads some DICOM files +// this reader is single threaded. +// .SECTION Implementation note: when FileLowerLeft is set to on the image is not flipped +// upside down as VTK would expect, use this option only if you know what you are doing. +// .SECTION Implementation note: when reading a series of 2D slices, user is +// expected to provide an ordered list of filenames. No sorting will be applied afterward. +// .SECTION Implementation note: Although 99% of the time the Zspacing as read +// from a tag in a 2D DICOM file should be correct, there has been reports that this +// value can be missing, or incorrect, in which case users are advised to override this +// value using the return value from gdcm::IPPSorter::GetZSpacing() and set it via +// vtkImageChangeInformation on the reader itself. +// .SECTION TODO +// This reader does not handle a series of 3D images, only a single 3D (multi frame) or a +// list of 2D files are supported for now. +// .SECTION TODO +// Did not implement SetFilePattern / SetFilePrefix API, move it to protected section for now. +// .SECTION BUG +// Overlay are assumed to have the same extent as image. Right now if overlay origin is not +// 0,0 the overlay will have an offset... +// Only the very first overlay is loaded at the VTK level, for now (even if there are more than one in the file) +// .SECTION DataOrigin +// When the reader is instanciated with FileLowerLeftOn the DataOrigin and Image Position (Patient) are +// identical. But when FileLowerLeft is Off, we have to reorder the Y-line of the image, and thus the DataOrigin +// is then translated to the other side of the image. +// .SECTION Spacing +// When reading a 3D volume, the spacing along the Z dimension might be negative (so as to respect up-side-down) +// as specified in the Image Orientation (Patient) tag. When Z-spacing is 0, this means the multi-frame object +// contains image which do not represent uniform volume. +// .SECTION Warning +// When using vtkGDCMPolyDataReader in conjonction with vtkGDCMImageReader +// it is *required* that FileLowerLeft is set to ON as coordinate system +// would be inconsistent in between the two data structures. +// .SECTION Color Space mapping: +// * VTK_LUMINANCE <-> MONOCHROME2 +// * VTK_LUMINANCE_ALPHA <-> Not supported +// * VTK_RGB <-> RGB +// * VTK_RGBA <-> ARGB (deprecated, DICOM 2008) +// * VTK_INVERSE_LUMINANCE <-> MONOCHROME1 +// * VTK_LOOKUP_TABLE <-> PALETTE COLOR +// * VTK_YBR <-> YBR_FULL +// +// For detailed information on color space transformation and true lossless transformation see: +// http://gdcm.sourceforge.net/wiki/index.php/Color_Space_Transformations + +// .SECTION See Also +// vtkMedicalImageReader2 vtkMedicalImageProperties vtkGDCMPolyDataReader vtkGDCMImageWriter +// vtkDICOMImageReader + +#ifndef VTKGDCMIMAGEREADER_H +#define VTKGDCMIMAGEREADER_H + +#include "vtkMedicalImageReader2.h" +#include "vtkImageData.h" + +#if (VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 ) +#else +class vtkMedicalImageProperties; +#endif +#if (VTK_MAJOR_VERSION > 5) || ( VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION > 0 ) +#else +class vtkStringArray; +#endif +class vtkPolyData; + +// vtkSystemIncludes.h defines: +// #define VTK_LUMINANCE 1 +// #define VTK_LUMINANCE_ALPHA 2 +// #define VTK_RGB 3 +// #define VTK_RGBA 4 +#ifndef VTK_INVERSE_LUMINANCE +#define VTK_INVERSE_LUMINANCE 5 +#endif +#ifndef VTK_LOOKUP_TABLE +#define VTK_LOOKUP_TABLE 6 +#endif +#ifndef VTK_YBR +#define VTK_YBR 7 +#endif +#ifndef VTK_CMYK +#define VTK_CMYK 8 +#endif + +//BTX +namespace gdcm { class ImageReader; } +//ETX +class vtkMatrix4x4; +class VTK_EXPORT vtkGDCMImageReader : public vtkMedicalImageReader2 +{ +public: + static vtkGDCMImageReader *New(); + vtkTypeRevisionMacro(vtkGDCMImageReader,vtkMedicalImageReader2); + virtual void PrintSelf(ostream& os, vtkIndent indent); + + // Description: is the given file name a DICOM file containing an image ? + virtual int CanReadFile(const char* fname); + + // Description: + // Valid extensions + virtual const char* GetFileExtensions() + { + // I would like to get rid of ACR/NEMA/IMA so only allow dcm extension for now + return ".dcm .DCM"; + } + + // Description: + // A descriptive name for this format + virtual const char* GetDescriptiveName() + { + return "DICOM"; + } + + // Description: + // Get the Image Position (Patient) as stored in the DICOM file + // This is a read-only data member + vtkGetObjectMacro(DirectionCosines, vtkMatrix4x4); + +#if (VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 ) +#else + // Description: + // Get the medical image properties object + vtkGetObjectMacro(MedicalImageProperties, vtkMedicalImageProperties); +#endif + virtual void SetMedicalImageProperties(vtkMedicalImageProperties *pd); + +#if (VTK_MAJOR_VERSION > 5) || ( VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION > 0 ) +#else + virtual void SetFileNames(vtkStringArray*); + vtkGetObjectMacro(FileNames, vtkStringArray); +#endif + + // Description: + // Specifically request to load the overlay into the gdcm-VTK layer (gdcm always loads them when found). + // If no overlay is found in the image, then the vtkImageData for the overlay will be empty. + vtkGetMacro(LoadOverlays,int); + vtkSetMacro(LoadOverlays,int); + vtkBooleanMacro(LoadOverlays,int); + + // Description: + // Set/Get whether or not to load the Icon as vtkImageData (if found in the DICOM file) + vtkGetMacro(LoadIconImage,int); + vtkSetMacro(LoadIconImage,int); + vtkBooleanMacro(LoadIconImage,int); + + // Description: + // Set/Get whether or not the image was compressed using a lossy compression algorithm + vtkGetMacro(LossyFlag,int); + vtkSetMacro(LossyFlag,int); + vtkBooleanMacro(LossyFlag,int); + + // Description: + // Read only: number of overlays as found in this image (multiple overlays per slice is allowed) + // Only valid when LoadOverlays is true + vtkGetMacro(NumberOfOverlays,int); + + // Description: + // Read only: number of icon image (there can only be zero or one icon per file) + // Only valid when LoadIconImage is true + vtkGetMacro(NumberOfIconImages,int); + + // Description: + // Get Overlay/IconImage + // Remember to ALWAYS use those methods in your code, as the internal number for the output port + // is not garantee to remain the same, as features are added to the reader +#if (VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 ) +//FIXME: Need to get rid of BTX/ETX if only the Python Wrapper of VTK 4.2 would let me +//BTX + vtkAlgorithmOutput* GetOverlayPort(int index); + vtkAlgorithmOutput* GetIconImagePort(); +//ETX +#endif + vtkImageData* GetOverlay(int i); + vtkImageData* GetIconImage(); + + // Description: + // Load image with its associated Lookup Table + vtkGetMacro(ApplyLookupTable,int); + vtkSetMacro(ApplyLookupTable,int); + vtkBooleanMacro(ApplyLookupTable,int); + + // Description: + // Load image as YBR + vtkGetMacro(ApplyYBRToRGB,int) + vtkSetMacro(ApplyYBRToRGB,int) + vtkBooleanMacro(ApplyYBRToRGB,int); + + // Description: + // Return VTK_LUMINANCE, VTK_INVERSE_LUMINANCE, VTK_RGB, VTK_RGBA, VTK_LOOKUP_TABLE, VTK_YBR or VTK_CMYK + // or 0 when ImageFormat is not handled. + // Warning: For color image, PlanarConfiguration need to be taken into account. + vtkGetMacro(ImageFormat,int); + + // Description: + // Return the Planar Configuration. This simply means that the internal DICOM image was stored + // using a particular planar configuration (most of the time: 0) + // For monochrome image, PlanarConfiguration is always 0 + vtkGetMacro(PlanarConfiguration,int); + + // Description: + // Return the 'raw' information stored in the DICOM file: + // In case of a series of multiple files, only the first file is considered. The Image Orientation (Patient) + // is garantee to remain the same, and image Image Position (Patient) in other slice can be computed + // using the ZSpacing (3rd dimension) + // (0020,0032) DS [87.774866\-182.908510\168.629671] # 32, 3 ImagePositionPatient + // (0020,0037) DS [0.001479\0.999989\-0.004376\-0.002039\-0.004372\-0.999988] # 58, 6 ImageOrientationPatient + vtkGetVector3Macro(ImagePositionPatient,double); + vtkGetVector6Macro(ImageOrientationPatient,double); + + // Description: + // Set/Get the first Curve Data: + vtkGetObjectMacro(Curve,vtkPolyData); + virtual void SetCurve(vtkPolyData *pd); + + // Description: + // \DEPRECATED: + // Modality LUT + // Value returned by GetShift/GetScale might be innacurate since Shift/Scale could be + // varying along the Series read. Therefore user are advices not to use those functions + // anymore + vtkGetMacro(Shift,double); + vtkGetMacro(Scale,double); + +protected: + vtkGDCMImageReader(); + ~vtkGDCMImageReader(); + + vtkSetVector6Macro(ImageOrientationPatient,double); + +//BTX + void FillMedicalImageInformation(const gdcm::ImageReader &reader); +//ETX + int RequestInformationCompat(); + int RequestDataCompat(); + +#if (VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 ) + int ProcessRequest(vtkInformation* request, + vtkInformationVector** inputVector, + vtkInformationVector* outputVector); + int RequestInformation(vtkInformation *request, + vtkInformationVector **inputVector, + vtkInformationVector *outputVector); + int RequestData(vtkInformation *request, + vtkInformationVector **inputVector, + vtkInformationVector *outputVector); +#else /*(VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 )*/ + void ExecuteInformation(); + void ExecuteData(vtkDataObject *out); +#endif /*(VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 )*/ + +protected: +#if (VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 ) +#else + // Description: + // Medical Image properties + vtkMedicalImageProperties *MedicalImageProperties; +#endif +#if (VTK_MAJOR_VERSION > 5) || ( VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION > 0 ) +#else + vtkStringArray *FileNames; +#endif + + vtkMatrix4x4 *DirectionCosines; + int LoadOverlays; + int NumberOfOverlays; + int LoadIconImage; + int NumberOfIconImages; + int IconImageDataExtent[6]; + double ImagePositionPatient[3]; + double ImageOrientationPatient[6]; + vtkPolyData *Curve; + + int ImageFormat; + // the following 3, should remain optional + int ApplyInverseVideo; + int ApplyLookupTable; + int ApplyYBRToRGB; + // I think that planar configuration need to always be applied as far as VTK is concerned + int ApplyPlanarConfiguration; + int ApplyShiftScale; + + int LoadSingleFile(const char *filename, char *pointer, unsigned long &outlen); + + double Shift; + double Scale; + int IconDataScalarType; + int IconNumberOfScalarComponents; + int PlanarConfiguration; + int LossyFlag; + int ForceRescale; + +protected: + // TODO / FIXME + void SetFilePrefix(const char *) {} + vtkGetStringMacro(FilePrefix); + void SetFilePattern(const char *) {} + vtkGetStringMacro(FilePattern); + +private: + vtkGDCMImageReader(const vtkGDCMImageReader&); // Not implemented. + void operator=(const vtkGDCMImageReader&); // Not implemented. +}; +#endif diff --git a/gdcm/Utilities/VTK/vtkGDCMImageReader2.cxx b/gdcm/Utilities/VTK/vtkGDCMImageReader2.cxx new file mode 100644 index 0000000..a5d268e --- /dev/null +++ b/gdcm/Utilities/VTK/vtkGDCMImageReader2.cxx @@ -0,0 +1,1248 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkGDCMImageReader2.h" + +#include "vtkObjectFactory.h" +#include "vtkImageData.h" +#include "vtkErrorCode.h" +#include "vtkMath.h" +#include "vtkPolyData.h" +#include "vtkCellArray.h" +#include "vtkPoints.h" +#include "vtkMedicalImageProperties.h" +#include "vtkGDCMMedicalImageProperties.h" +#include "vtkStringArray.h" +#include "vtkPointData.h" +#include "vtkLookupTable.h" +#include "vtkWindowLevelLookupTable.h" +#include "vtkLookupTable16.h" +#include "vtkInformationVector.h" +#include "vtkInformation.h" +#include "vtkDemandDrivenPipeline.h" +#include "vtkStreamingDemandDrivenPipeline.h" +#include "vtkMatrix4x4.h" +#include "vtkUnsignedCharArray.h" +#include "vtkBitArray.h" + +#include "gdcmImageRegionReader.h" +#include "gdcmDataElement.h" +#include "gdcmByteValue.h" +#include "gdcmSwapper.h" +#include "gdcmUnpacker12Bits.h" +#include "gdcmRescaler.h" +#include "gdcmOrientation.h" +#include "gdcmTrace.h" +#include "gdcmImageChangePlanarConfiguration.h" +#include "gdcmDirectoryHelper.h" +#include "gdcmBoxRegion.h" + +#include + +vtkCxxRevisionMacro(vtkGDCMImageReader2, "$Revision: 1.1 $") +vtkStandardNewMacro(vtkGDCMImageReader2) + +static inline bool vtkGDCMImageReader2_IsCharTypeSigned() +{ +#ifndef VTK_TYPE_CHAR_IS_SIGNED + unsigned char uc = 255; + return (*reinterpret_cast(&uc) < 0) ? true : false; +#else + return VTK_TYPE_CHAR_IS_SIGNED; +#endif +} + +// Output Ports are as follow: +// #0: The image/volume (root PixelData element) +// #1: (if present): the Icon Image (0088,0200) +// #2-xx: (if present): the Overlay (60xx,3000) + +#define ICONIMAGEPORTNUMBER 1 +#define OVERLAYPORTNUMBER 2 + +vtkCxxSetObjectMacro(vtkGDCMImageReader2,Curve,vtkPolyData) +vtkCxxSetObjectMacro(vtkGDCMImageReader2,MedicalImageProperties,vtkMedicalImageProperties) + +//---------------------------------------------------------------------------- +vtkGDCMImageReader2::vtkGDCMImageReader2() +{ + this->DirectionCosines = vtkMatrix4x4::New(); + this->DirectionCosines->Identity(); + this->LoadOverlays = 1; + this->LoadIconImage = 1; + this->NumberOfOverlays = 0; + this->NumberOfIconImages = 0; + memset(this->IconImageDataExtent,0,6*sizeof(int)); + this->ImageFormat = 0; // INVALID + this->ApplyInverseVideo = 0; + this->ApplyLookupTable = 0; + this->ApplyYBRToRGB = 0; + this->ApplyPlanarConfiguration = 1; + this->ApplyShiftScale = 1; + memset(this->ImagePositionPatient,0,3*sizeof(double)); + memset(this->ImageOrientationPatient,0,6*sizeof(double)); + this->Curve = 0; + this->Shift = 0.; + this->Scale = 1.; + this->IconDataScalarType = VTK_CHAR; + this->IconNumberOfScalarComponents = 1; + this->PlanarConfiguration = 0; + this->LossyFlag = 0; + + this->MedicalImageProperties->SetDirectionCosine(1,0,0,0,1,0); + this->SetImageOrientationPatient(1,0,0,0,1,0); + this->ForceRescale = 0; +} + +//---------------------------------------------------------------------------- +vtkGDCMImageReader2::~vtkGDCMImageReader2() +{ + this->DirectionCosines->Delete(); + if( this->Curve ) + { + this->Curve->Delete(); + } +} + +//---------------------------------------------------------------------------- +int vtkGDCMImageReader2::CanReadFile(const char* fname) +{ + gdcm::ImageReader reader; + reader.SetFileName( fname ); + if( !reader.Read() ) + { + return 0; + } + // 3 means: I might be able to read... + return 3; +} + +//---------------------------------------------------------------------------- +int vtkGDCMImageReader2::ProcessRequest(vtkInformation* request, + vtkInformationVector** inputVector, + vtkInformationVector* outputVector) +{ + // generate the data + if(request->Has(vtkDemandDrivenPipeline::REQUEST_DATA())) + { + return this->RequestData(request, inputVector, outputVector); + } + + // execute information + if(request->Has(vtkDemandDrivenPipeline::REQUEST_INFORMATION())) + { + return this->RequestInformation(request, inputVector, outputVector); + } + + return this->Superclass::ProcessRequest(request, inputVector, outputVector); +} + +//---------------------------------------------------------------------------- +void vtkGDCMImageReader2::FillMedicalImageInformation(const gdcm::ImageReader &reader) +{ + const gdcm::File &file = reader.GetFile(); + const gdcm::DataSet &ds = file.GetDataSet(); + + // $ grep "vtkSetString\|DICOM" vtkMedicalImageProperties.h + // For ex: DICOM (0010,0010) = DOE,JOHN + this->MedicalImageProperties->SetPatientName( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0010,0x0010), ds).c_str() ); + // For ex: DICOM (0010,0020) = 1933197 + this->MedicalImageProperties->SetPatientID( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0010,0x0020), ds).c_str() ); + // For ex: DICOM (0010,1010) = 031Y + this->MedicalImageProperties->SetPatientAge( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0010,0x1010), ds).c_str() ); + // For ex: DICOM (0010,0040) = M + this->MedicalImageProperties->SetPatientSex( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0010,0x0040), ds).c_str() ); + // For ex: DICOM (0010,0030) = 19680427 + this->MedicalImageProperties->SetPatientBirthDate( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0010,0x0030), ds).c_str() ); + // For ex: DICOM (0008,0020) = 20030617 + this->MedicalImageProperties->SetStudyDate( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0008,0x0020), ds).c_str() ); + // For ex: DICOM (0008,0022) = 20030617 + this->MedicalImageProperties->SetAcquisitionDate( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0008,0x0022), ds).c_str() ); + // For ex: DICOM (0008,0030) = 162552.0705 or 230012, or 0012 + this->MedicalImageProperties->SetStudyTime( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0008,0x0030), ds).c_str() ); + // For ex: DICOM (0008,0032) = 162552.0705 or 230012, or 0012 + this->MedicalImageProperties->SetAcquisitionTime( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0008,0x0032), ds).c_str() ); + // For ex: DICOM (0008,0023) = 20030617 + this->MedicalImageProperties->SetImageDate( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0008,0x0023), ds).c_str() ); + // For ex: DICOM (0008,0033) = 162552.0705 or 230012, or 0012 + this->MedicalImageProperties->SetImageTime( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0008,0x0033), ds).c_str() ); + // For ex: DICOM (0020,0013) = 1 + this->MedicalImageProperties->SetImageNumber( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0020,0x0013), ds).c_str() ); + // For ex: DICOM (0020,0011) = 902 + this->MedicalImageProperties->SetSeriesNumber( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0020,0x0011), ds).c_str() ); + // For ex: DICOM (0008,103e) = SCOUT + this->MedicalImageProperties->SetSeriesDescription( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0008,0x103e), ds).c_str() ); + // For ex: DICOM (0020,0010) = 37481 + this->MedicalImageProperties->SetStudyID( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0020,0x0010), ds).c_str() ); + // For ex: DICOM (0008,1030) = BRAIN/C-SP/FACIAL + this->MedicalImageProperties->SetStudyDescription( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0008,0x1030), ds).c_str() ); + // For ex: DICOM (0008,0060)= CT + this->MedicalImageProperties->SetModality( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0008,0x0060), ds).c_str() ); + // For ex: DICOM (0008,0070) = Siemens + this->MedicalImageProperties->SetManufacturer( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0008,0x0070), ds).c_str() ); + // For ex: DICOM (0008,1090) = LightSpeed QX/i + this->MedicalImageProperties->SetManufacturerModelName( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0008,0x1090), ds).c_str() ); + // For ex: DICOM (0008,1010) = LSPD_OC8 + this->MedicalImageProperties->SetStationName( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0008,0x1010), ds).c_str() ); + // For ex: DICOM (0008,0080) = FooCity Medical Center + this->MedicalImageProperties->SetInstitutionName( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0008,0x0080), ds).c_str() ); + // For ex: DICOM (0018,1210) = Bone + this->MedicalImageProperties->SetConvolutionKernel( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0018,0x1210), ds).c_str() ); + // For ex: DICOM (0018,0050) = 0.273438 + this->MedicalImageProperties->SetSliceThickness( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0018,0x0050), ds).c_str() ); + // For ex: DICOM (0018,0060) = 120 + this->MedicalImageProperties->SetKVP( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0018,0x0060), ds).c_str() ); + // For ex: DICOM (0018,1120) = 15 + this->MedicalImageProperties->SetGantryTilt( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0018,0x1120), ds).c_str() ); + // For ex: DICOM (0018,0081) = 105 + this->MedicalImageProperties->SetEchoTime( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0018,0x0081), ds).c_str() ); + // For ex: DICOM (0018,0091) = 35 + this->MedicalImageProperties->SetEchoTrainLength( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0018,0x0091), ds).c_str() ); + // For ex: DICOM (0018,0080) = 2040 + this->MedicalImageProperties->SetRepetitionTime( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0018,0x0080), ds).c_str() ); + // For ex: DICOM (0018,1150) = 5 + this->MedicalImageProperties->SetExposureTime( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0018,0x1150), ds).c_str() ); + // For ex: DICOM (0018,1151) = 400 + this->MedicalImageProperties->SetXRayTubeCurrent( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0018,0x1151), ds).c_str() ); + // For ex: DICOM (0018,1152) = 114 + this->MedicalImageProperties->SetExposure( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0018,0x1152), ds).c_str() ); + + // virtual void AddWindowLevelPreset(double w, double l); + // (0028,1050) DS [ 498\ 498] # 12, 2 WindowCenter + // (0028,1051) DS [ 1063\ 1063] # 12, 2 WindowWidth + gdcm::Tag twindowcenter(0x0028,0x1050); + gdcm::Tag twindowwidth(0x0028,0x1051); + if( ds.FindDataElement( twindowcenter ) && ds.FindDataElement( twindowwidth) ) + { + const gdcm::DataElement& windowcenter = ds.GetDataElement( twindowcenter ); + const gdcm::DataElement& windowwidth = ds.GetDataElement( twindowwidth ); + const gdcm::ByteValue *bvwc = windowcenter.GetByteValue(); + const gdcm::ByteValue *bvww = windowwidth.GetByteValue(); + if( bvwc && bvww ) // Can be Type 2 + { + gdcm::Element elwc; + std::stringstream ss1; + std::string swc = std::string( bvwc->GetPointer(), bvwc->GetLength() ); + ss1.str( swc ); + gdcm::VR vr = gdcm::VR::DS; + unsigned int vrsize = vr.GetSizeof(); + unsigned int count = gdcm::VM::GetNumberOfElementsFromArray(swc.c_str(), (unsigned int)swc.size()); + elwc.SetLength( count * vrsize ); + elwc.Read( ss1 ); + std::stringstream ss2; + std::string sww = std::string( bvww->GetPointer(), bvww->GetLength() ); + ss2.str( sww ); + gdcm::Element elww; + elww.SetLength( count * vrsize ); + elww.Read( ss2 ); + for(unsigned int i = 0; i < elwc.GetLength(); ++i) + { + this->MedicalImageProperties->AddWindowLevelPreset( elww.GetValue(i), elwc.GetValue(i) ); + } + } + } + gdcm::Tag twindowexplanation(0x0028,0x1055); + if( ds.FindDataElement( twindowexplanation ) ) + { + const gdcm::DataElement& windowexplanation = ds.GetDataElement( twindowexplanation ); + const gdcm::ByteValue *bvwe = windowexplanation.GetByteValue(); + if( bvwe ) // Can be Type 2 + { + unsigned int n = this->MedicalImageProperties->GetNumberOfWindowLevelPresets(); + gdcm::Element elwe; // window explanation + gdcm::VR vr = gdcm::VR::LO; + std::stringstream ss; + ss.str( "" ); + std::string swe = std::string( bvwe->GetPointer(), bvwe->GetLength() ); + unsigned int count = gdcm::VM::GetNumberOfElementsFromArray(swe.c_str(), (unsigned int)swe.size()); (void)count; + // I found a case with only one W/L but two comments: WINDOW1\WINDOW2 + // SIEMENS-IncompletePixelData.dcm + // oh wait but what if we have the countrary... + //assert( count >= (unsigned int)n ); + elwe.SetLength( count * vr.GetSizeof() ); + ss.str( swe ); + elwe.Read( ss ); + unsigned int c = std::min(n, count); + for(unsigned int i = 0; i < c; ++i) + { + this->MedicalImageProperties->SetNthWindowLevelPresetComment(i, elwe.GetValue(i).c_str() ); + } + } + } + + // Add more info: + vtkGDCMMedicalImageProperties *gdcmmip = + dynamic_cast( this->MedicalImageProperties ); + if( gdcmmip ) + { + gdcmmip->PushBackFile( file ); + } +} + +//---------------------------------------------------------------------------- +int vtkGDCMImageReader2::RequestInformation(vtkInformation *request, + vtkInformationVector **inputVector, + vtkInformationVector *outputVector) +{ + int res = RequestInformationCompat(); + if( !res ) + { + vtkErrorMacro( "RequestInformationCompat failed: " << res ); + this->SetErrorCode(vtkErrorCode::FileFormatError); + return 0; + } + + int numvol = 1; + if( this->LoadIconImage ) + { + numvol = 2; + } + if( this->LoadOverlays ) + { + // If no icon found, we still need to be associated to port #2: + numvol = 2 + this->NumberOfOverlays; + } + this->SetNumberOfOutputPorts(numvol); + // For each output: + for(int i = 0; i < numvol; ++i) + { + // Allocate ! + if( !this->GetOutput(i) ) + { + vtkImageData *img = vtkImageData::New(); + this->GetExecutive()->SetOutputData(i, img ); + img->Delete(); + } + vtkInformation *outInfo = outputVector->GetInformationObject(i); + switch(i) + { + // root Pixel Data + case 0: + outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), this->DataExtent, 6); + //outInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(), this->DataExtent, 6); + outInfo->Set(vtkDataObject::SPACING(), this->DataSpacing, 3); +#ifdef GDCMV2_0_COMPATIBILITY + outInfo->Set(vtkDataObject::ORIGIN(), this->DataOrigin, 3); +#endif + vtkDataObject::SetPointDataActiveScalarInfo(outInfo, this->DataScalarType, this->NumberOfScalarComponents); + break; + // Icon Image + case ICONIMAGEPORTNUMBER: + outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), this->IconImageDataExtent, 6); + vtkDataObject::SetPointDataActiveScalarInfo(outInfo, this->IconDataScalarType, this->IconNumberOfScalarComponents ); + break; + // Overlays: + //case OVERLAYPORTNUMBER: + default: + outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), + this->DataExtent[0], this->DataExtent[1], + this->DataExtent[2], this->DataExtent[3], + 0,0 ); + vtkDataObject::SetPointDataActiveScalarInfo(outInfo, VTK_UNSIGNED_CHAR, 1); + break; + } + } + + return 1; +} + +static gdcm::PixelFormat::ScalarType +ComputePixelTypeFromFiles(const char *inputfilename, vtkStringArray *filenames, + gdcm::Image const & imageref) +{ + gdcm::PixelFormat::ScalarType outputpt ; + outputpt = gdcm::PixelFormat::UNKNOWN; + // there is a very subtle bug here. Let's imagine we have a collection of files + // they can all have different Rescale Slope / Intercept. In this case we should: + // 1. Make sure to read each Rescale Slope / Intercept individually + // 2. Make sure to decide which Pixel Type to use using *all* slices: + if( inputfilename ) + { + const gdcm::Image &image = imageref; + const gdcm::PixelFormat &pixeltype = image.GetPixelFormat(); + double shift = image.GetIntercept(); + double scale = image.GetSlope(); + + gdcm::Rescaler r; + r.SetIntercept( shift ); + r.SetSlope( scale ); + r.SetPixelFormat( pixeltype ); + outputpt = r.ComputeInterceptSlopePixelType(); + } + else if ( filenames && filenames->GetNumberOfValues() > 0 ) + { + std::set< gdcm::PixelFormat::ScalarType > pixeltypes; + std::set< unsigned short > samplesperpixel; + // FIXME a gdcm::Scanner would be much faster here: + for(int i = 0; i < filenames->GetNumberOfValues(); ++i ) + { + const char *filename = filenames->GetValue( i ); + gdcm::ImageReader reader; + reader.SetFileName( filename ); + if( !reader.Read() ) + { + vtkGenericWarningMacro( "ImageReader failed: " << filename ); + return gdcm::PixelFormat::UNKNOWN; + } + const gdcm::Image &image = reader.GetImage(); + const gdcm::PixelFormat &pixeltype = image.GetPixelFormat(); + samplesperpixel.insert( pixeltype.GetSamplesPerPixel() ); + + double shift = image.GetIntercept(); + double scale = image.GetSlope(); + + gdcm::PixelFormat::ScalarType outputpt2 = pixeltype; + gdcm::Rescaler r; + r.SetIntercept( shift ); + r.SetSlope( scale ); + r.SetPixelFormat( pixeltype ); + outputpt2 = r.ComputeInterceptSlopePixelType(); + pixeltypes.insert( outputpt2 ); + } + if( pixeltypes.size() == 1 ) + { + assert( samplesperpixel.size() == 1 ); + // Ok easy case + outputpt = *pixeltypes.begin(); + } + else if( samplesperpixel.size() == 1 ) + { + // Hardcoded. If Pixel Type found is the maximum (as of PS 3.5 - 2008) + // There is nothing bigger that FLOAT64 + if( pixeltypes.count( gdcm::PixelFormat::FLOAT64 ) != 0 ) + { + outputpt = gdcm::PixelFormat::FLOAT64; + } + else + { + // should I just take the biggest value ? + // MM: I am not sure UINT16 and INT16 are really compatible + // so taking the biggest value might not be the solution + // In this case we could use INT32, but FLOAT64 also works... + // oh well, let's just use FLOAT64 always. + vtkGenericWarningMacro( "This may not always be optimized. Sorry" ); + outputpt = gdcm::PixelFormat::FLOAT64; + } + } + else + { + vtkGenericWarningMacro( "Could not compute Pixel Type. Sorry" ); + } + } + else + { + assert( 0 ); // I do not think this is possible + } + + return outputpt; +} + +//---------------------------------------------------------------------------- +int vtkGDCMImageReader2::RequestInformationCompat() +{ + // FIXME, need to implement the other modes too: + if( this->ApplyLookupTable || this->ApplyYBRToRGB || this->ApplyInverseVideo ) + { + vtkErrorMacro( "ApplyLookupTable/ApplyYBRToRGB/ApplyInverseVideo not compatible" ); + return 0; + } + // I do not think this is a good idea anyway to let the user decide + // wether or not she wants *not* to apply shift/scale... + if( !this->ApplyShiftScale ) + { + vtkErrorMacro("ApplyShiftScale not compatible" ); + return 0; + } + // I do not think this one will ever be implemented: + if( !this->ApplyPlanarConfiguration ) + { + vtkErrorMacro("ApplyPlanarConfiguration not compatible" ); + return 0; + } + + // Let's read the first file : + const char *filename; + if( this->FileName ) + { + filename = this->FileName; + } + else if ( this->FileNames && this->FileNames->GetNumberOfValues() > 0 ) + { + filename = this->FileNames->GetValue( 0 ); + } + else + { + // hey! I need at least one file to schew on ! + vtkErrorMacro( "You did not specify any filenames" ); + return 0; + } +#if 0 + gdcm::ImageRegionReader reader; + reader.SetFileName( filename ); + if( !reader.ReadInformation() ) +#else + gdcm::ImageReader reader; + reader.SetFileName( filename ); + if( !reader.Read() ) +#endif + { + vtkErrorMacro( "ImageReader failed on " << filename ); + return 0; + } + const gdcm::Image &image = reader.GetImage(); + this->LossyFlag = image.IsLossy(); + const unsigned int *dims = image.GetDimensions(); + + // Set the Extents. + assert( image.GetNumberOfDimensions() >= 2 ); + this->DataExtent[0] = 0; + this->DataExtent[1] = dims[0] - 1; + this->DataExtent[2] = 0; + this->DataExtent[3] = dims[1] - 1; + if( image.GetNumberOfDimensions() == 2 ) + { + // This is just so much painful to deal with DICOM / VTK + // they simply assume that number of file is equal to the dimension + // of the last axe (see vtkImageReader2::SetFileNames ) + if ( this->FileNames && this->FileNames->GetNumberOfValues() > 1 ) + { + this->DataExtent[4] = 0; + } + else + { + this->DataExtent[4] = 0; + this->DataExtent[5] = 0; + } + } + else + { + assert( image.GetNumberOfDimensions() == 3 ); + this->FileDimensionality = 3; + this->DataExtent[4] = 0; + this->DataExtent[5] = dims[2] - 1; + } + gdcm::MediaStorage ms; + ms.SetFromFile( reader.GetFile() ); + assert( gdcm::MediaStorage::IsImage( ms ) ); + + const double *spacing = image.GetSpacing(); + if( spacing ) + { + this->DataSpacing[0] = spacing[0]; + this->DataSpacing[1] = spacing[1]; + this->DataSpacing[2] = image.GetSpacing(2); + } + + const double *origin = image.GetOrigin(); + if( origin ) + { + this->ImagePositionPatient[0] = image.GetOrigin(0); + this->ImagePositionPatient[1] = image.GetOrigin(1); + this->ImagePositionPatient[2] = image.GetOrigin(2); + } + + const double *dircos = image.GetDirectionCosines(); + if( dircos ) + { + this->DirectionCosines->SetElement(0,0, dircos[0]); + this->DirectionCosines->SetElement(1,0, dircos[1]); + this->DirectionCosines->SetElement(2,0, dircos[2]); + this->DirectionCosines->SetElement(3,0, 0); + this->DirectionCosines->SetElement(0,1, dircos[3]); + this->DirectionCosines->SetElement(1,1, dircos[4]); + this->DirectionCosines->SetElement(2,1, dircos[5]); + this->DirectionCosines->SetElement(3,1, 0); + double dircosz[3]; + vtkMath::Cross(dircos, dircos+3, dircosz); + this->DirectionCosines->SetElement(0,2, dircosz[0]); + this->DirectionCosines->SetElement(1,2, dircosz[1]); + this->DirectionCosines->SetElement(2,2, dircosz[2]); + this->DirectionCosines->SetElement(3,2, 0); + + for(int i=0;i<6;++i) + this->ImageOrientationPatient[i] = dircos[i]; + this->MedicalImageProperties->SetDirectionCosine( this->ImageOrientationPatient ); + } + // Apply transform: +#ifdef GDCMV2_0_COMPATIBILITY + if( dircos && origin ) + { + if( this->FileLowerLeft ) + { + // Since we are not doing the VTK Y-flipping operation, Origin and Image Position (Patient) + // are the same: + this->DataOrigin[0] = origin[0]; + this->DataOrigin[1] = origin[1]; + this->DataOrigin[2] = origin[2]; + } + else + { + // We are doing the Y-flip: + // translate Image Position (Patient) along the Y-vector of the Image Orientation (Patient): + // Step 1: Compute norm of translation vector: + // Because position is in the center of the pixel, we need to substract 1 to the dimY: + assert( dims[1] >=1 ); + double norm = (dims[1] - 1) * this->DataSpacing[1]; + // Step 2: translate: + this->DataOrigin[0] = origin[0] + norm * dircos[3+0]; + this->DataOrigin[1] = origin[1] + norm * dircos[3+1]; + this->DataOrigin[2] = origin[2] + norm * dircos[3+2]; + } + } + // Need to set the rest to 0 ??? +#endif + + const gdcm::PixelFormat &pixeltype = image.GetPixelFormat(); + this->Shift = image.GetIntercept(); + this->Scale = image.GetSlope(); + + gdcm::PixelFormat::ScalarType outputpt = + ComputePixelTypeFromFiles(this->FileName, this->FileNames, image); + if( this->FileName ) + { + // We should test that outputpt is 8 when BitsAllocated = 16 / Bits Stored = 8 + // BUT we should test that output is 16 when BitsAllocated = 16 / BitsStored = 12 + // assert( outputpt == pixeltype ); + } + + this->ForceRescale = 0; // always reset this thing + // gdcmData/DCMTK_JPEGExt_12Bits.dcm + if( pixeltype != outputpt && pixeltype.GetBitsAllocated() != 12 ) + { + this->ForceRescale = 1; + } + + switch( outputpt ) + { + case gdcm::PixelFormat::INT8: + this->DataScalarType = VTK_SIGNED_CHAR; + break; + case gdcm::PixelFormat::UINT8: + this->DataScalarType = VTK_UNSIGNED_CHAR; + break; + case gdcm::PixelFormat::INT16: + this->DataScalarType = VTK_SHORT; + break; + case gdcm::PixelFormat::UINT16: + this->DataScalarType = VTK_UNSIGNED_SHORT; + break; + // RT / SC have 32bits + case gdcm::PixelFormat::INT32: + this->DataScalarType = VTK_INT; + break; + case gdcm::PixelFormat::UINT32: + this->DataScalarType = VTK_UNSIGNED_INT; + break; + case gdcm::PixelFormat::INT12: + this->DataScalarType = VTK_SHORT; + break; + case gdcm::PixelFormat::UINT12: + this->DataScalarType = VTK_UNSIGNED_SHORT; + break; + //case gdcm::PixelFormat::FLOAT16: // TODO + case gdcm::PixelFormat::FLOAT32: + this->DataScalarType = VTK_FLOAT; + break; + case gdcm::PixelFormat::FLOAT64: + this->DataScalarType = VTK_DOUBLE; + break; + case gdcm::PixelFormat::SINGLEBIT: + this->DataScalarType = VTK_BIT; + break; + default: + this->SetErrorCode(vtkErrorCode::FileFormatError); + vtkErrorMacro( "Do not support this Pixel Type: " << (int)pixeltype.GetScalarType() + << " with " << (int)outputpt ); + return 0; + } + this->NumberOfScalarComponents = pixeltype.GetSamplesPerPixel(); + + // Ok let's fill in the 'extra' info: + this->FillMedicalImageInformation(reader); + + // Do the IconImage if requested: + const gdcm::IconImage& icon = image.GetIconImage(); + if( this->LoadIconImage && !icon.IsEmpty() ) + { + this->IconImageDataExtent[0] = 0; + this->IconImageDataExtent[1] = icon.GetColumns() - 1; + this->IconImageDataExtent[2] = 0; + this->IconImageDataExtent[3] = icon.GetRows() - 1; + // + const gdcm::PixelFormat &iconpixelformat = icon.GetPixelFormat(); + switch(iconpixelformat) + { + case gdcm::PixelFormat::INT8: + this->IconDataScalarType = VTK_SIGNED_CHAR; + break; + case gdcm::PixelFormat::UINT8: + this->IconDataScalarType = VTK_UNSIGNED_CHAR; + break; + case gdcm::PixelFormat::INT16: + this->IconDataScalarType = VTK_SHORT; + break; + case gdcm::PixelFormat::UINT16: + this->IconDataScalarType = VTK_UNSIGNED_SHORT; + break; + default: + vtkErrorMacro( "Do not support this Icon Pixel Type: " << (int)iconpixelformat.GetScalarType() ); + return 0; + } + this->IconNumberOfScalarComponents = iconpixelformat.GetSamplesPerPixel(); + } + + // Overlay! + size_t numoverlays = image.GetNumberOfOverlays(); + if( this->LoadOverlays && numoverlays ) + { + // Do overlay specific stuff... + // what if overlay do not have the same data extent as image ? + for( unsigned int ovidx = 0; ovidx < numoverlays; ++ovidx ) + { + const gdcm::Overlay& ov = image.GetOverlay(ovidx); + assert( (unsigned int)ov.GetRows() == image.GetRows() ); (void)ov; + assert( (unsigned int)ov.GetColumns() == image.GetColumns() ); + } + this->NumberOfOverlays = (int)numoverlays; + } + + return 1; +} + +//---------------------------------------------------------------------------- +template +static inline unsigned long vtkImageDataGetTypeSize(T*, int a = 0, int b = 0) +{ + (void)a;(void)b; + return sizeof(T); +} + +//---------------------------------------------------------------------------- +static void InPlaceYFlipImage2(vtkImageData* data, const int dext[6]) +{ + unsigned long outsize = data->GetNumberOfScalarComponents(); + if( dext[1] == dext[0] && dext[0] == 0 ) return; + + // Multiply by the number of bytes per scalar + switch (data->GetScalarType()) + { + case VTK_BIT: { outsize /= 8; }; break; + vtkTemplateMacro( + outsize *= vtkImageDataGetTypeSize(static_cast(0)) + ); + default: + //vtkErrorMacro("do not support scalar type: " << data->GetScalarType() ); + assert(0); + } + outsize *= (dext[1] - dext[0] + 1); + char * ref = static_cast(data->GetScalarPointer()); + char * pointer = static_cast(data->GetScalarPointer()); + assert( pointer ); + + char *line = new char[outsize]; + + for(int j = dext[4]; j <= dext[5]; ++j) + { + char *start = pointer; +/* assert( start == ref + j * outsize * (dext[3] - dext[2] + 1) ); (void)ref; */ + // Swap two-lines at a time + // when Rows is odd number (359) then dext[3] == 178 + // so we should avoid copying the line right in the center of the image + // since memcpy does not like copying on itself... + for(int i = dext[2]; i < (dext[3]+1) / 2; ++i) + { + // image: + char * end = start+(dext[3] - i)*outsize; + assert( (end - pointer) >= (int)outsize ); + memcpy(line,end,outsize); // duplicate line + memcpy(end,pointer,outsize); + memcpy(pointer,line,outsize); + pointer += outsize; + } + // because the for loop iterated only over 1/2 all lines, skip to the next slice: + assert( dext[2] == 0 ); + pointer += (dext[3] + 1 - (dext[3]+1)/2 )*outsize; + } + // Did we reach the end ? + assert( pointer == ref + (dext[5]-dext[4]+1)*(dext[3]-dext[2]+1)*outsize ); + delete[] line; +} + +//---------------------------------------------------------------------------- +int vtkGDCMImageReader2::LoadSingleFile(const char *filename, char *pointer, unsigned long &outlen) +{ + int *dext = this->GetDataExtent(); + vtkImageData *data = this->GetOutput(0); + + int outExt[6]; + data->GetExtent(outExt); + + gdcm::ImageRegionReader reader; + reader.SetFileName( filename ); + if( !reader.ReadInformation() ) + { + vtkErrorMacro( "ImageRegionReader failed: " << filename ); + return 0; + } + +#if 0 + // TODO could check compat: + std::vector dims = + gdcm::ImageHelper::GetDimensionsValue(reader.GetFile()); +#endif + + gdcm::BoxRegion box; + box.SetDomain(outExt[0], outExt[1], outExt[2], outExt[3], outExt[4], outExt[5]); + reader.SetRegion( box ); + + gdcm::Image &image = reader.GetImage(); + this->LossyFlag = image.IsLossy(); + //VTK does not cope with Planar Configuration, so let's schew the work to please it + assert( this->PlanarConfiguration == 0 || this->PlanarConfiguration == 1 ); + // Store the PlanarConfiguration before inverting it ! + this->PlanarConfiguration = image.GetPlanarConfiguration(); + //assert( this->PlanarConfiguration == 0 || this->PlanarConfiguration == 1 ); + if( image.GetPlanarConfiguration() == 1 ) + { + vtkErrorMacro( "vtkGDCMImageReader2 does not handle Planar Configuration: " << filename ); + return 0; + } + + const gdcm::PixelFormat &pixeltype = image.GetPixelFormat(); + assert( image.GetNumberOfDimensions() == 2 || image.GetNumberOfDimensions() == 3 ); + /* unsigned long len = image.GetBufferLength(); */ + unsigned long len = reader.ComputeBufferLength(); + outlen = len; + unsigned long overlaylen = 0; + // HACK: Make sure that Shift/Scale are the one from the file: + this->Shift = image.GetIntercept(); + this->Scale = image.GetSlope(); + + if( (this->Scale != 1.0 || this->Shift != 0.0) || this->ForceRescale ) + { + assert( pixeltype.GetSamplesPerPixel() == 1 ); + gdcm::Rescaler r; + r.SetIntercept( Shift ); // FIXME + r.SetSlope( Scale ); // FIXME + gdcm::PixelFormat::ScalarType targetpixeltype = gdcm::PixelFormat::UNKNOWN; + // r.SetTargetPixelType( gdcm::PixelFormat::FLOAT64 ); + int scalarType = data->GetScalarType(); + switch( scalarType ) + { + case VTK_CHAR: + if( vtkGDCMImageReader2_IsCharTypeSigned() ) + targetpixeltype = gdcm::PixelFormat::INT8; + else + targetpixeltype = gdcm::PixelFormat::UINT8; + break; + case VTK_SIGNED_CHAR: + targetpixeltype = gdcm::PixelFormat::INT8; + break; + case VTK_UNSIGNED_CHAR: + targetpixeltype = gdcm::PixelFormat::UINT8; + break; + case VTK_SHORT: + targetpixeltype = gdcm::PixelFormat::INT16; + break; + case VTK_UNSIGNED_SHORT: + targetpixeltype = gdcm::PixelFormat::UINT16; + break; + case VTK_INT: + targetpixeltype = gdcm::PixelFormat::INT32; + break; + case VTK_UNSIGNED_INT: + targetpixeltype = gdcm::PixelFormat::UINT32; + break; + case VTK_FLOAT: + targetpixeltype = gdcm::PixelFormat::FLOAT32; + break; + case VTK_DOUBLE: + targetpixeltype = gdcm::PixelFormat::FLOAT64; + break; + case VTK_BIT: + targetpixeltype = gdcm::PixelFormat::SINGLEBIT; + break; + default: + vtkErrorMacro( "Do not support this Pixel Type: " << scalarType ); + assert( 0 ); + return 0; + } + r.SetTargetPixelType( targetpixeltype ); + + r.SetUseTargetPixelType(true); + r.SetPixelFormat( pixeltype ); + char * copy = new char[len]; + /*image.GetBuffer(copy);*/ + bool b = reader.ReadIntoBuffer(copy, len); + assert( b ); + if( !r.Rescale(pointer,copy,len) ) + { + delete[] copy; + vtkErrorMacro( "Could not Rescale" ); + // problem with gdcmData/3E768EB7.dcm + return 0; + } + delete[] copy; + // WARNING: sizeof(Real World Value) != sizeof(Stored Pixel) + outlen = data->GetScalarSize() * data->GetNumberOfPoints() / data->GetDimensions()[2]; + assert( data->GetNumberOfScalarComponents() == 1 ); + } + else + { + /* image.GetBuffer(pointer); */ + bool b = reader.ReadIntoBuffer(pointer, len); + assert( b ); + } + + // Do the Icon Image: + if( this->LoadIconImage ) + { + this->NumberOfIconImages = image.GetIconImage().IsEmpty() ? 0 : 1; + if( this->NumberOfIconImages ) + { + char * iconpointer = static_cast(this->GetOutput(ICONIMAGEPORTNUMBER)->GetScalarPointer()); + assert( iconpointer ); + image.GetIconImage().GetBuffer( iconpointer ); + if ( image.GetIconImage().GetPhotometricInterpretation() == gdcm::PhotometricInterpretation::PALETTE_COLOR ) + { + const gdcm::LookupTable &lut = image.GetIconImage().GetLUT(); + assert( lut.GetBitSample() == 8 ); + { + vtkLookupTable *vtklut = vtkLookupTable::New(); + vtklut->SetNumberOfTableValues(256); + // SOLVED: GetPointer(0) is skrew up, need to replace it with WritePointer(0,4) ... + if( !lut.GetBufferAsRGBA( vtklut->WritePointer(0,4) ) ) + { + vtkWarningMacro( "Could not get values from LUT" ); + return 0; + } + vtklut->SetRange(0,255); + this->GetOutput(ICONIMAGEPORTNUMBER)->GetPointData()->GetScalars()->SetLookupTable( vtklut ); + vtklut->Delete(); + } + } + } + } + + // Do the Curve: + size_t numcurves = image.GetNumberOfCurves(); + if( numcurves ) + { + const gdcm::Curve& curve = image.GetCurve(); + vtkPoints * pts = vtkPoints::New(); + pts->SetNumberOfPoints( curve.GetNumberOfPoints() ); + curve.GetAsPoints( (float*)pts->GetVoidPointer(0) ); + vtkCellArray *polys = vtkCellArray::New(); + for(unsigned int i = 0; i < curve.GetNumberOfPoints(); i+=2 ) + { + polys->InsertNextCell(2); + polys->InsertCellPoint(i); + polys->InsertCellPoint(i+1); + } + vtkPolyData *cube = vtkPolyData::New(); + cube->SetPoints(pts); + pts->Delete(); + cube->SetLines(polys); + polys->Delete(); + SetCurve(cube); + cube->Delete(); + } + + // Do the Overlay: + if( this->LoadOverlays ) + { + size_t numoverlays = image.GetNumberOfOverlays(); + long overlayoutsize = (dext[1] - dext[0] + 1); + if( !this->LoadOverlays ) assert( this->NumberOfOverlays == 0 ); + for( int ovidx = 0; ovidx < this->NumberOfOverlays; ++ovidx ) + { + vtkImageData *vtkimage = this->GetOutput(OVERLAYPORTNUMBER + ovidx); + // vtkOpenGLImageMapper::RenderData does not support bit array (since OpenGL does not either) + // we have to decompress the bit overlay into an unsigned char array to please everybody: + const gdcm::Overlay& ov1 = image.GetOverlay(ovidx); + vtkUnsignedCharArray *chararray = vtkUnsignedCharArray::New(); + chararray->SetNumberOfTuples( overlayoutsize * ( dext[3] - dext[2] + 1 ) ); + overlaylen = overlayoutsize * ( dext[3] - dext[2] + 1 ); + assert( (unsigned long)ov1.GetRows()*ov1.GetColumns() <= overlaylen ); + const signed short *origin = ov1.GetOrigin(); + if( (unsigned long)ov1.GetRows()*ov1.GetColumns() != overlaylen ) + { + vtkWarningMacro( "vtkImageData Overlay have an extent that do not match the one of the image" ); + } + if( origin[0] != 1 || origin[1] != 1 ) + { + // Table C.9-2 OVERLAY PLANE MODULE ATTRIBUTES + vtkWarningMacro( "Overlay with origin are not supported right now" ); + } + vtkimage->GetPointData()->SetScalars( chararray ); + vtkimage->GetPointData()->GetScalars()->SetName( ov1.GetDescription() ); + chararray->Delete(); + + assert( vtkimage->GetScalarType() == VTK_UNSIGNED_CHAR ); + char * overlaypointer = static_cast(vtkimage->GetScalarPointer()); + assert( overlaypointer ); + + if( !ov1.GetUnpackBuffer( overlaypointer, overlaylen ) ) + { + vtkErrorMacro( "Problem in GetUnpackBuffer" ); + } + } + if( numoverlays ) assert( (unsigned long)overlayoutsize * ( dext[3] - dext[2] + 1 ) == overlaylen ); + } + + // Do the LUT + if ( image.GetPhotometricInterpretation() == gdcm::PhotometricInterpretation::PALETTE_COLOR ) + { + this->ImageFormat = VTK_LOOKUP_TABLE; + const gdcm::LookupTable &lut = image.GetLUT(); + if( lut.GetBitSample() == 8 ) + { + vtkLookupTable *vtklut = vtkLookupTable::New(); + vtklut->SetNumberOfTableValues(256); + // SOLVED: GetPointer(0) is skrew up, need to replace it with WritePointer(0,4) ... + if( !lut.GetBufferAsRGBA( vtklut->WritePointer(0,4) ) ) + { + vtkWarningMacro( "Could not get values from LUT" ); + return 0; + } + vtklut->SetRange(0,255); + data->GetPointData()->GetScalars()->SetLookupTable( vtklut ); + vtklut->Delete(); + } + else + { + assert( lut.GetBitSample() == 16 ); + vtkLookupTable16 *vtklut = vtkLookupTable16::New(); + vtklut->SetNumberOfTableValues(256*256); + // SOLVED: GetPointer(0) is skrew up, need to replace it with WritePointer(0,4) ... + if( !lut.GetBufferAsRGBA( (unsigned char*)vtklut->WritePointer(0,4) ) ) + { + vtkWarningMacro( "Could not get values from LUT" ); + return 0; + } + vtklut->SetRange(0,256*256-1); + data->GetPointData()->GetScalars()->SetLookupTable( vtklut ); + vtklut->Delete(); + } + } + else if ( image.GetPhotometricInterpretation() == gdcm::PhotometricInterpretation::MONOCHROME1 ) + { + this->ImageFormat = VTK_INVERSE_LUMINANCE; + vtkWindowLevelLookupTable *vtklut = vtkWindowLevelLookupTable::New(); + // Technically we could also use the first of the Window Width / Window Center + // oh well, if they are missing let's just compute something: + const double min = (double)pixeltype.GetMin(); + const double max = (double)pixeltype.GetMax(); + vtklut->SetWindow( max - min ); + vtklut->SetLevel( 0.5 * (max + min) ); + //vtklut->SetWindow(1024); // WindowWidth + //vtklut->SetLevel(550); // WindowCenter + vtklut->InverseVideoOn(); + data->GetPointData()->GetScalars()->SetLookupTable( vtklut ); + vtklut->Delete(); + } + else if ( image.GetPhotometricInterpretation() == gdcm::PhotometricInterpretation::YBR_FULL_422 ) + { + this->ImageFormat = VTK_YBR; + } + else if ( image.GetPhotometricInterpretation() == gdcm::PhotometricInterpretation::YBR_FULL ) + { + this->ImageFormat = VTK_YBR; + } + else if ( image.GetPhotometricInterpretation() == gdcm::PhotometricInterpretation::RGB ) + { + this->ImageFormat = VTK_RGB; + } + else if ( image.GetPhotometricInterpretation() == gdcm::PhotometricInterpretation::MONOCHROME2 ) + { + this->ImageFormat = VTK_LUMINANCE; + } + else if ( image.GetPhotometricInterpretation() == gdcm::PhotometricInterpretation::YBR_RCT ) + { + this->ImageFormat = VTK_RGB; + } + else if ( image.GetPhotometricInterpretation() == gdcm::PhotometricInterpretation::YBR_ICT ) + { + this->ImageFormat = VTK_RGB; + } + else if ( image.GetPhotometricInterpretation() == gdcm::PhotometricInterpretation::CMYK ) + { + this->ImageFormat = VTK_CMYK; + } + else if ( image.GetPhotometricInterpretation() == gdcm::PhotometricInterpretation::ARGB ) + { + this->ImageFormat = VTK_RGBA; + } + else + { + // HSV / CMYK ??? + // let's just give up for now + vtkErrorMacro( "Does not handle: " << image.GetPhotometricInterpretation().GetString() ); + //return 0; + } + //assert( this->ImageFormat ); + + long outsize; + if( data->GetScalarType() == VTK_BIT ) + { + outsize = (dext[1] - dext[0] + 1) / 8; + } + else + { + outsize = pixeltype.GetPixelSize()*(dext[1] - dext[0] + 1); + } + + if( this->FileName ) + { + assert( (unsigned long)outsize * (outExt[3] - outExt[2]+1) * (outExt[5] - outExt[4]+1) == len ); + } + + return 1; // success +} + + +//---------------------------------------------------------------------------- +int vtkGDCMImageReader2::RequestData(vtkInformation *vtkNotUsed(request), + vtkInformationVector **vtkNotUsed(inputVector), + vtkInformationVector *outputVector) +{ + // Make sure the output dimension is OK, and allocate its scalars + for(int i = 0; i < this->GetNumberOfOutputPorts(); ++i) + { + vtkInformation* outInfo = outputVector->GetInformationObject(i); + vtkImageData *data = static_cast(outInfo->Get(vtkDataObject::DATA_OBJECT())); + // Make sure that this output is an image + if (data) + { + int extent[6]; + outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(), extent); + this->AllocateOutputData(data, outInfo, extent); + } + } + int res = RequestDataCompat(); + return res; +} + +//---------------------------------------------------------------------------- +int vtkGDCMImageReader2::RequestDataCompat() +{ + vtkImageData *output = this->GetOutput(0); + output->GetPointData()->GetScalars()->SetName("GDCMImage"); + + // The outExt is the allocated data extent + int outExt[6]; + output->GetExtent(outExt); + // The dext is the whole extent (includes not-loaded data) + int *dext = this->GetDataExtent(); + + char * pointer = static_cast(output->GetScalarPointerForExtent(outExt)); + if( this->FileName ) + { + const char *filename = this->FileName; + unsigned long len; + int load = this->LoadSingleFile( filename, pointer, len ); (void)len; + if( !load ) + { + // FIXME: I need to fill the buffer with 0, shouldn't I ? + return 0; + } + } + else if( this->FileNames && this->FileNames->GetNumberOfValues() >= 1 ) + { + // Load each 2D files + // HACK: len is moved out of the loop so that when file > 1 start failing we can still know + // the len of the buffer...technically all files should have the same len (not checked for now) + unsigned long len = 0; + for(int j = outExt[4]; !this->AbortExecute && j <= outExt[5]; ++j) + { + assert( j >= 0 && j <= this->FileNames->GetNumberOfValues() ); + const char *filename = this->FileNames->GetValue( j ); + int load = this->LoadSingleFile( filename, pointer, len ); + vtkDebugMacro( "LoadSingleFile: " << filename ); + if( !load ) + { + // hum... we could not read this file within the series, let's just fill + // the slice with 0 value, hopefully this should be the right thing to do + memset( pointer, 0, len); + } + assert( len ); + pointer += len; + this->UpdateProgress( (double)(j - outExt[4] ) / ( outExt[5] - outExt[4] )); + } + } + else + { + return 0; + } + // Y-flip image + if (!this->FileLowerLeft) + { + InPlaceYFlipImage2(this->GetOutput(0), outExt); + if( this->LoadIconImage ) + { + int *iiext = this->IconImageDataExtent; + InPlaceYFlipImage2(this->GetOutput(ICONIMAGEPORTNUMBER), iiext); + } + for( int ovidx = 0; ovidx < this->NumberOfOverlays; ++ovidx ) + { + assert( this->LoadOverlays ); + int oext[6]; + this->GetDataExtent(oext); + oext[4] = 0; + oext[5] = 0; + InPlaceYFlipImage2(this->GetOutput(OVERLAYPORTNUMBER+ovidx), oext); + } + } + + return 1; +} + +//---------------------------------------------------------------------------- +vtkAlgorithmOutput* vtkGDCMImageReader2::GetOverlayPort(int index) +{ + if( index >= 0 && index < this->NumberOfOverlays) + return this->GetOutputPort(index+OVERLAYPORTNUMBER); + return NULL; +} + +//---------------------------------------------------------------------------- +vtkAlgorithmOutput* vtkGDCMImageReader2::GetIconImagePort() +{ + const int index = 0; + if( index >= 0 && index < this->NumberOfIconImages) + return this->GetOutputPort(index+ICONIMAGEPORTNUMBER); + return NULL; +} + +//---------------------------------------------------------------------------- +vtkImageData* vtkGDCMImageReader2::GetOverlay(int i) +{ + if( i >= 0 && i < this->NumberOfOverlays) + return this->GetOutput(i+OVERLAYPORTNUMBER); + return NULL; +} + +//---------------------------------------------------------------------------- +vtkImageData* vtkGDCMImageReader2::GetIconImage() +{ + const int i = 0; + if( i >= 0 && i < this->NumberOfIconImages) + return this->GetOutput(i+ICONIMAGEPORTNUMBER); + return NULL; +} + +//---------------------------------------------------------------------------- +void vtkGDCMImageReader2::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os,indent); +} diff --git a/gdcm/Utilities/VTK/vtkGDCMImageReader2.h b/gdcm/Utilities/VTK/vtkGDCMImageReader2.h new file mode 100644 index 0000000..4e3e09b --- /dev/null +++ b/gdcm/Utilities/VTK/vtkGDCMImageReader2.h @@ -0,0 +1,275 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +// .NAME vtkGDCMImageReader2 - read DICOM Image files (Pixel Data) +// .SECTION Description +// vtkGDCMImageReader2 is a source object that reads some DICOM files +// this reader is single threaded. +// .SECTION Implementation note: when FileLowerLeft is set to on the image is not flipped +// upside down as VTK would expect, use this option only if you know what you are doing. +// .SECTION Implementation note: when reading a series of 2D slices, user is +// expected to provide an ordered list of filenames. No sorting will be applied afterward. +// .SECTION Implementation note: Although 99% of the time the Zspacing as read +// from a tag in a 2D DICOM file should be correct, there has been reports that this +// value can be missing, or incorrect, in which case users are advised to override this +// value using the return value from gdcm::IPPSorter::GetZSpacing() and set it via +// vtkImageChangeInformation on the reader itself. +// .SECTION TODO +// This reader does not handle a series of 3D images, only a single 3D (multi frame) or a +// list of 2D files are supported for now. +// .SECTION TODO +// Did not implement SetFilePattern / SetFilePrefix API, move it to protected section for now. +// .SECTION BUG +// Overlay are assumed to have the same extent as image. Right now if overlay origin is not +// 0,0 the overlay will have an offset... +// Only the very first overlay is loaded at the VTK level, for now (even if there are more than one in the file) +// .SECTION DataOrigin +// When the reader is instanciated with FileLowerLeftOn the DataOrigin and Image Position (Patient) are +// identical. But when FileLowerLeft is Off, we have to reorder the Y-line of the image, and thus the DataOrigin +// is then translated to the other side of the image. +// .SECTION Spacing +// When reading a 3D volume, the spacing along the Z dimension might be negative (so as to respect up-side-down) +// as specified in the Image Orientation (Patient) tag. When Z-spacing is 0, this means the multi-frame object +// contains image which do not represent uniform volume. +// .SECTION Warning +// When using vtkGDCMPolyDataReader in conjonction with vtkGDCMImageReader2 +// it is *required* that FileLowerLeft is set to ON as coordinate system +// would be inconsistent in between the two data structures. +// .SECTION Color Space mapping: +// * VTK_LUMINANCE <-> MONOCHROME2 +// * VTK_LUMINANCE_ALPHA <-> Not supported +// * VTK_RGB <-> RGB +// * VTK_RGBA <-> ARGB (deprecated, DICOM 2008) +// * VTK_INVERSE_LUMINANCE <-> MONOCHROME1 +// * VTK_LOOKUP_TABLE <-> PALETTE COLOR +// * VTK_YBR <-> YBR_FULL +// +// For detailed information on color space transformation and true lossless transformation see: +// http://gdcm.sourceforge.net/wiki/index.php/Color_Space_Transformations + +// .SECTION See Also +// vtkMedicalImageReader2 vtkMedicalImageProperties vtkGDCMPolyDataReader vtkGDCMImageWriter +// vtkDICOMImageReader + +#ifndef VTKGDCMIMAGEREADER2_H +#define VTKGDCMIMAGEREADER2_H + +#include "vtkMedicalImageReader2.h" +#include "vtkImageData.h" + +class vtkPolyData; + +// vtkSystemIncludes.h defines: +// #define VTK_LUMINANCE 1 +// #define VTK_LUMINANCE_ALPHA 2 +// #define VTK_RGB 3 +// #define VTK_RGBA 4 +#ifndef VTK_INVERSE_LUMINANCE +#define VTK_INVERSE_LUMINANCE 5 +#endif +#ifndef VTK_LOOKUP_TABLE +#define VTK_LOOKUP_TABLE 6 +#endif +#ifndef VTK_YBR +#define VTK_YBR 7 +#endif +#ifndef VTK_CMYK +#define VTK_CMYK 8 +#endif + +//BTX +namespace gdcm { class ImageReader; } +//ETX +class vtkMatrix4x4; +class VTK_EXPORT vtkGDCMImageReader2 : public vtkMedicalImageReader2 +{ +public: + static vtkGDCMImageReader2 *New(); + vtkTypeRevisionMacro(vtkGDCMImageReader2,vtkMedicalImageReader2); + virtual void PrintSelf(ostream& os, vtkIndent indent); + + // Description: is the given file name a DICOM file containing an image ? + virtual int CanReadFile(const char* fname); + + // Description: + // Valid extensions + virtual const char* GetFileExtensions() + { + // I would like to get rid of ACR/NEMA/IMA so only allow dcm extension for now + return ".dcm .DCM"; + } + + // Description: + // A descriptive name for this format + virtual const char* GetDescriptiveName() + { + return "DICOM"; + } + + // Description: + // Get the Image Position (Patient) as stored in the DICOM file + // This is a read-only data member + vtkGetObjectMacro(DirectionCosines, vtkMatrix4x4); + + virtual void SetMedicalImageProperties(vtkMedicalImageProperties *pd); + + // Description: + // Specifically request to load the overlay into the gdcm-VTK layer (gdcm always loads them when found). + // If no overlay is found in the image, then the vtkImageData for the overlay will be empty. + vtkGetMacro(LoadOverlays,int); + vtkSetMacro(LoadOverlays,int); + vtkBooleanMacro(LoadOverlays,int); + + // Description: + // Set/Get whether or not to load the Icon as vtkImageData (if found in the DICOM file) + vtkGetMacro(LoadIconImage,int); + vtkSetMacro(LoadIconImage,int); + vtkBooleanMacro(LoadIconImage,int); + + // Description: + // Set/Get whether or not the image was compressed using a lossy compression algorithm + vtkGetMacro(LossyFlag,int); + vtkSetMacro(LossyFlag,int); + vtkBooleanMacro(LossyFlag,int); + + // Description: + // Read only: number of overlays as found in this image (multiple overlays per slice is allowed) + // Only valid when LoadOverlays is true + vtkGetMacro(NumberOfOverlays,int); + + // Description: + // Read only: number of icon image (there can only be zero or one icon per file) + // Only valid when LoadIconImage is true + vtkGetMacro(NumberOfIconImages,int); + + // Description: + // Get Overlay/IconImage + // Remember to ALWAYS use those methods in your code, as the internal number for the output port + // is not garantee to remain the same, as features are added to the reader + vtkAlgorithmOutput* GetOverlayPort(int index); + vtkAlgorithmOutput* GetIconImagePort(); + vtkImageData* GetOverlay(int i); + vtkImageData* GetIconImage(); + + // Description: + // Load image with its associated Lookup Table + vtkGetMacro(ApplyLookupTable,int); + vtkSetMacro(ApplyLookupTable,int); + vtkBooleanMacro(ApplyLookupTable,int); + + // Description: + // Load image as YBR + vtkGetMacro(ApplyYBRToRGB,int) + vtkSetMacro(ApplyYBRToRGB,int) + vtkBooleanMacro(ApplyYBRToRGB,int); + + // Description: + // Return VTK_LUMINANCE, VTK_INVERSE_LUMINANCE, VTK_RGB, VTK_RGBA, VTK_LOOKUP_TABLE, VTK_YBR or VTK_CMYK + // or 0 when ImageFormat is not handled. + // Warning: For color image, PlanarConfiguration need to be taken into account. + vtkGetMacro(ImageFormat,int); + + // Description: + // Return the Planar Configuration. This simply means that the internal DICOM image was stored + // using a particular planar configuration (most of the time: 0) + // For monochrome image, PlanarConfiguration is always 0 + vtkGetMacro(PlanarConfiguration,int); + + // Description: + // Return the 'raw' information stored in the DICOM file: + // In case of a series of multiple files, only the first file is considered. The Image Orientation (Patient) + // is garantee to remain the same, and image Image Position (Patient) in other slice can be computed + // using the ZSpacing (3rd dimension) + // (0020,0032) DS [87.774866\-182.908510\168.629671] # 32, 3 ImagePositionPatient + // (0020,0037) DS [0.001479\0.999989\-0.004376\-0.002039\-0.004372\-0.999988] # 58, 6 ImageOrientationPatient + vtkGetVector3Macro(ImagePositionPatient,double); + vtkGetVector6Macro(ImageOrientationPatient,double); + + // Description: + // Set/Get the first Curve Data: + vtkGetObjectMacro(Curve,vtkPolyData); + virtual void SetCurve(vtkPolyData *pd); + + // Description: + // \DEPRECATED: + // Modality LUT + // Value returned by GetShift/GetScale might be innacurate since Shift/Scale could be + // varying along the Series read. Therefore user are advices not to use those functions + // anymore + vtkGetMacro(Shift,double); + vtkGetMacro(Scale,double); + +protected: + vtkGDCMImageReader2(); + ~vtkGDCMImageReader2(); + + vtkSetVector6Macro(ImageOrientationPatient,double); + +//BTX + void FillMedicalImageInformation(const gdcm::ImageReader &reader); +//ETX + int RequestInformationCompat(); + int RequestDataCompat(); + + int ProcessRequest(vtkInformation* request, + vtkInformationVector** inputVector, + vtkInformationVector* outputVector); + int RequestInformation(vtkInformation *request, + vtkInformationVector **inputVector, + vtkInformationVector *outputVector); + int RequestData(vtkInformation *request, + vtkInformationVector **inputVector, + vtkInformationVector *outputVector); + +protected: + vtkMatrix4x4 *DirectionCosines; + int LoadOverlays; + int NumberOfOverlays; + int LoadIconImage; + int NumberOfIconImages; + int IconImageDataExtent[6]; + double ImagePositionPatient[3]; + double ImageOrientationPatient[6]; + vtkPolyData *Curve; + + int ImageFormat; + // the following 3, should remain optional + int ApplyInverseVideo; + int ApplyLookupTable; + int ApplyYBRToRGB; + // I think that planar configuration need to always be applied as far as VTK is concerned + int ApplyPlanarConfiguration; + int ApplyShiftScale; + + int LoadSingleFile(const char *filename, char *pointer, unsigned long &outlen); + + double Shift; + double Scale; + int IconDataScalarType; + int IconNumberOfScalarComponents; + int PlanarConfiguration; + int LossyFlag; + int ForceRescale; + +protected: + // TODO / FIXME + void SetFilePrefix(const char *) {} + vtkGetStringMacro(FilePrefix); + void SetFilePattern(const char *) {} + vtkGetStringMacro(FilePattern); + +private: + vtkGDCMImageReader2(const vtkGDCMImageReader2&); // Not implemented. + void operator=(const vtkGDCMImageReader2&); // Not implemented. +}; +#endif diff --git a/gdcm/Utilities/VTK/vtkGDCMImageReader_Extra.cs b/gdcm/Utilities/VTK/vtkGDCMImageReader_Extra.cs new file mode 100644 index 0000000..f9d4eb1 --- /dev/null +++ b/gdcm/Utilities/VTK/vtkGDCMImageReader_Extra.cs @@ -0,0 +1,28 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +namespace Kitware.VTK.GDCM +{ +public class vtkgdcm { +// FIXME why isn't mummy doing it ? + public static readonly int VTK_LUMINANCE = 1; + public static readonly int VTK_LUMINANCE_ALPHA = 2; + public static readonly int VTK_RGB = 3; + public static readonly int VTK_RGBA = 4; + public static readonly int VTK_INVERSE_LUMINANCE = 5; + public static readonly int VTK_LOOKUP_TABLE = 6; + public static readonly int VTK_YBR = 7; + public static readonly int VTK_CMYK = 8; +} +} diff --git a/gdcm/Utilities/VTK/vtkGDCMImageWriter.cxx b/gdcm/Utilities/VTK/vtkGDCMImageWriter.cxx new file mode 100644 index 0000000..bd2dc09 --- /dev/null +++ b/gdcm/Utilities/VTK/vtkGDCMImageWriter.cxx @@ -0,0 +1,1318 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkGDCMImageWriter.h" + +#include "vtkVersion.h" +#include "vtkObjectFactory.h" +#include "vtkImageData.h" +#include "vtkLookupTable.h" +#include "vtkLookupTable16.h" +#include "vtkMath.h" +#include "vtkMatrix4x4.h" +#include "vtkMedicalImageProperties.h" +#include "vtkGDCMMedicalImageProperties.h" +#include "vtkStringArray.h" +#include "vtkPointData.h" +#include "vtkGDCMImageReader.h" +#if (VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 ) +#include "vtkInformationVector.h" +#include "vtkStreamingDemandDrivenPipeline.h" +#include "vtkInformation.h" +#endif /*(VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 )*/ + +#include "gdcmImageWriter.h" +#include "gdcmByteValue.h" +#include "gdcmUIDGenerator.h" +#include "gdcmAnonymizer.h" +#include "gdcmAttribute.h" +#include "gdcmRescaler.h" +#include "gdcmGlobal.h" +#include "gdcmDicts.h" +#include "gdcmDict.h" +#include "gdcmTag.h" +#include "gdcmImageHelper.h" +#include "gdcmImageChangePlanarConfiguration.h" +#include "gdcmImageChangeTransferSyntax.h" + +#include + +vtkCxxRevisionMacro(vtkGDCMImageWriter, "$Revision: 1.1 $") +vtkStandardNewMacro(vtkGDCMImageWriter) + +//vtkCxxSetObjectMacro(vtkGDCMImageWriter,LookupTable,vtkLookupTable) +vtkCxxSetObjectMacro(vtkGDCMImageWriter,MedicalImageProperties,vtkMedicalImageProperties) +vtkCxxSetObjectMacro(vtkGDCMImageWriter,FileNames,vtkStringArray) +vtkCxxSetObjectMacro(vtkGDCMImageWriter,DirectionCosines,vtkMatrix4x4) + +inline bool vtkGDCMImageWriter_IsCharTypeSigned() +{ +#ifndef VTK_TYPE_CHAR_IS_SIGNED + unsigned char uc = 255; + return (*reinterpret_cast(&uc) < 0) ? true : false; +#else + return VTK_TYPE_CHAR_IS_SIGNED; +#endif +} + +#ifndef vtkFloatingPointType +#define vtkFloatingPointType float +#endif + +//---------------------------------------------------------------------------- +vtkGDCMImageWriter::vtkGDCMImageWriter() +{ + this->DataUpdateExtent[0] = 0; + this->DataUpdateExtent[1] = 0; + this->DataUpdateExtent[2] = 0; + this->DataUpdateExtent[3] = 0; + this->DataUpdateExtent[4] = 0; + this->DataUpdateExtent[5] = 0; + + //this->LookupTable = vtkLookupTable::New(); + this->MedicalImageProperties = vtkMedicalImageProperties::New(); + this->FileNames = vtkStringArray::New(); + this->StudyUID = 0; + this->SeriesUID = 0; + this->DirectionCosines = vtkMatrix4x4::New(); + this->DirectionCosines->SetElement(0,0,1); + this->DirectionCosines->SetElement(1,0,0); + this->DirectionCosines->SetElement(2,0,0); + this->DirectionCosines->SetElement(0,1,0); + this->DirectionCosines->SetElement(1,1,1); + this->DirectionCosines->SetElement(2,1,0); + + // This is the same root as ITK, but implementation version will be different... + gdcm::UIDGenerator::SetRoot( "1.2.826.0.1.3680043.2.1125" ); + + // echo "VTK" | od -b + gdcm::FileMetaInformation::AppendImplementationClassUID( "126.124.113" ); + const std::string project_name = std::string("GDCM/VTK ") + vtkVersion::GetVTKVersion(); + gdcm::FileMetaInformation::SetSourceApplicationEntityTitle( project_name.c_str() ); + + this->ImageFormat = 0; // invalid + + this->Shift = 0.; + this->Scale = 1.; + this->FileLowerLeft = 0; // same default as vtkImageReader2 + this->PlanarConfiguration = 0; + this->LossyFlag = 0; + this->CompressionType = NO_COMPRESSION; + + // For both case (2d file or 3d file) we need a common uid for the Series/Study: + gdcm::UIDGenerator uidgen; + const char *uid = uidgen.Generate(); + this->SetStudyUID(uid); + uid = uidgen.Generate(); + this->SetSeriesUID(uid); +} + +//---------------------------------------------------------------------------- +vtkGDCMImageWriter::~vtkGDCMImageWriter() +{ + //this->LookupTable->Delete(); + this->MedicalImageProperties->Delete(); + this->FileNames->Delete(); + this->SetStudyUID(NULL); + this->SetSeriesUID(NULL); + this->DirectionCosines->Delete(); +} + +//---------------------------------------------------------------------------- +#if (VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 ) +int vtkGDCMImageWriter::FillInputPortInformation( + int port, vtkInformation *info) +{ + if (!this->Superclass::FillInputPortInformation(port, info)) + { + return 0; + } + info->Set(vtkAlgorithm::INPUT_IS_REPEATABLE(), 1); + return 1; +} +//--------------------------------------------------------------------------- +int vtkGDCMImageWriter::RequestInformation( + vtkInformation *vtkNotUsed(request), + vtkInformationVector **inputVector, + vtkInformationVector *vtkNotUsed(outputVector)) +{ + // Check to make sure that all input information agrees + int mismatchedInputs = 0; + + double spacing[3]; + double origin[3]; + int extent[6]; + int components = 0; + int dataType = 0; + + // For each connection on port 0, check against the first connection + for (int i = 0; i < this->GetNumberOfInputConnections(0); i++) + { + vtkInformation *inInfo = inputVector[0]->GetInformationObject(i); + if (i == 0) + { + inInfo->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), extent); + inInfo->Get(vtkDataObject::SPACING(), spacing); + inInfo->Get(vtkDataObject::ORIGIN(), origin); + components = inInfo->Get(vtkDataObject::FIELD_NUMBER_OF_COMPONENTS()); + dataType = inInfo->Get(vtkDataObject::FIELD_ARRAY_TYPE()); + continue; + } + + if (memcmp(inInfo->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT()), + extent, sizeof(extent)) || + memcmp(inInfo->Get(vtkDataObject::SPACING()), spacing, + sizeof(spacing)) || + memcmp(inInfo->Get(vtkDataObject::ORIGIN()), origin, + sizeof(origin)) || + inInfo->Get(vtkDataObject::FIELD_NUMBER_OF_COMPONENTS()) + != components || + inInfo->Get(vtkDataObject::FIELD_ARRAY_TYPE()) != dataType) + { + mismatchedInputs = 1; + return 0; + } + } + + // Technically we should be much more paranoid with the shift scale (like value bigger + // then stored pixel type: does this even make sense ?) + // Let's do the easy one here: + // do I really need to comment on this one: + if( this->Scale == 0 ) + { + return 0; + } + + return 1; +} + +//-------------------------------------------------------------------------- +int vtkGDCMImageWriter::RequestUpdateExtent( + vtkInformation *vtkNotUsed(request), + vtkInformationVector **inputVector, + vtkInformationVector *vtkNotUsed(outputVector)) +{ + // Set the UpdateExtent from the DataUpdateExtent for the current slice + int n = inputVector[0]->GetNumberOfInformationObjects(); + for (int i = 0; i < n; i++) + { + vtkInformation *inInfo = inputVector[0]->GetInformationObject(i); + inInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(), + this->DataUpdateExtent, 6); + } + + return 1; +} + +//-------------------------------------------------------------------------- +int vtkGDCMImageWriter::RequestData( + vtkInformation* vtkNotUsed(request), + vtkInformationVector** inputVector, + vtkInformationVector* vtkNotUsed(outputVector)) +{ + // Go through the inputs and write the data for each + int numTimeSteps = inputVector[0]->GetNumberOfInformationObjects(); + + for (int timeStep = 0; timeStep < numTimeSteps; timeStep++) + { + vtkInformation *inInfo = + inputVector[0]->GetInformationObject(timeStep); + vtkImageData *input = + vtkImageData::SafeDownCast(inInfo->Get(vtkDataObject::DATA_OBJECT())); + + // Error checking + if (input == NULL) + { + // Close file, set GDCMFileID to zero + //this->CloseFile(this->GDCMFileId); + //this->GDCMFileId = 0; + vtkErrorMacro(<<"Write: Please specify an input!"); + return 0; + } + // Call WriteGDCMData for each input + if (this->WriteGDCMData(input, timeStep) == 0) + { + return 0; + } + } + + return 1; +} +#endif /*(VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 )*/ + +//---------------------------------------------------------------------------- +/*const*/ char *vtkGDCMImageWriter::GetFileName() +{ + if( this->FileNames->GetNumberOfValues() ) + { + const char *filename = this->FileNames->GetValue(0); + return (char*)filename; + } + return this->Superclass::GetFileName(); +} + +//---------------------------------------------------------------------------- +#if (VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 ) +void vtkGDCMImageWriter::Write() +{ + if (this->GetFileName() == 0) + { + vtkErrorMacro("Write: You must supply a file name."); + return; + } + + // Get the first input and update its information. + vtkImageData *input = this->GetImageDataInput(0); + + if (input == 0) + { + vtkErrorMacro("Write: No input supplied."); + return; + } +#if (VTK_MAJOR_VERSION >= 6) +#else + input->UpdateInformation(); +#endif + + // Update the rest. + this->UpdateInformation(); + + // Get the whole extent of the input +#if (VTK_MAJOR_VERSION >= 6) + vtkInformation *inInfo = this->GetInputInformation(0, 0); + inInfo->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), this->DataUpdateExtent); +#else + input->GetWholeExtent(this->DataUpdateExtent); +#endif + + if (this->DataUpdateExtent[0] == (this->DataUpdateExtent[1] + 1) || + this->DataUpdateExtent[2] == (this->DataUpdateExtent[3] + 1) || + this->DataUpdateExtent[4] == (this->DataUpdateExtent[5] + 1)) + { + vtkErrorMacro("Write: Empty input supplied."); + return; + } + + + // For both case (2d file or 3d file) we need a common uid for the Series/Study: + //gdcm::UIDGenerator uidgen; + //const char *uid = uidgen.Generate(); + //this->SetStudyUID(uid); + //uid = uidgen.Generate(); + //this->SetSeriesUID(uid); + + // Did the user specified dim of output file to be 2 ? + if( this->FileDimensionality == 2 ) + { + int dimIndex = 2; + int firstSlice = this->DataUpdateExtent[2*dimIndex]; + int lastSlice = this->DataUpdateExtent[2*dimIndex+1]; + assert( lastSlice >= firstSlice ); + if( lastSlice - firstSlice ) // will be == 0 when only a single slice + { + if( lastSlice - firstSlice + 1 != this->FileNames->GetNumberOfValues() ) + { + vtkErrorMacro("Wrong number of filenames: " << this->FileNames->GetNumberOfValues() + << " should be " << lastSlice - firstSlice + 1); + return; + } + } + + // Go through data slice-by-slice using file-order slices + for (int slice = firstSlice; slice <= lastSlice; slice++) + { + //std::cerr << "Slice:" << slice << std::endl; + // Set the DataUpdateExtent to the slice extent we want to write + this->DataUpdateExtent[2*dimIndex] = slice; + this->DataUpdateExtent[2*dimIndex+1] = slice; + this->Modified(); + + // Call Update to execute pipeline and write slice to disk. + this->Update(); + } + } + else if( this->FileDimensionality == 3 ) + { + // Call Update to execute pipeline and write slice to disk. + this->Update(); + } + else + { + vtkErrorMacro( "Unhandled: " << this->FileDimensionality ); + } + +} +#else +//---------------------------------------------------------------------------- +// Writes all the data from the input. +void vtkGDCMImageWriter::Write() +{ + // Error checking + if ( this->GetInput() == NULL ) + { + vtkErrorMacro(<<"Write:Please specify an input!"); + return; + } +// if (!this->WriteToMemory && !this->FileName && !this->FilePattern) +// { +// vtkErrorMacro(<<"Write:Please specify either a FileName or a file prefix and pattern"); +// return; +// } + + // Make sure the file name is allocated + this->InternalFileName = 0; +// new char[(this->FileName ? strlen(this->FileName) : 1) + +// (this->FilePrefix ? strlen(this->FilePrefix) : 1) + +// (this->FilePattern ? strlen(this->FilePattern) : 1) + 10]; + + // Fill in image information. + this->GetInput()->UpdateInformation(); + int *wExtent; + wExtent = this->GetInput()->GetWholeExtent(); + this->FileNumber = this->GetInput()->GetWholeExtent()[4]; + this->UpdateProgress(0.0); + // loop over the z axis and write the slices + for (this->FileNumber = wExtent[4]; this->FileNumber <= wExtent[5]; + ++this->FileNumber) + { + this->GetInput()->SetUpdateExtent(wExtent[0], wExtent[1], + wExtent[2], wExtent[3], + this->FileNumber, + this->FileNumber); + // determine the name +/* + if (this->FileName) + { + sprintf(this->InternalFileName,"%s",this->FileName); + } + else + { + if (this->FilePrefix) + { + sprintf(this->InternalFileName, this->FilePattern, + this->FilePrefix, this->FileNumber); + } + else + { + sprintf(this->InternalFileName, this->FilePattern,this->FileNumber); + } + } +*/ + this->GetInput()->UpdateData(); + this->WriteSlice(this->GetInput()); + this->UpdateProgress((this->FileNumber - wExtent[4])/ + (wExtent[5] - wExtent[4] + 1.0)); + } + //delete [] this->InternalFileName; + //this->InternalFileName = NULL; +} + +//---------------------------------------------------------------------------- +void vtkGDCMImageWriter::WriteSlice(vtkImageData *data) +{ + this->WriteGDCMData(data, 0); +} + +#endif + +//---------------------------------------------------------------------------- +//void SetStringValueFromTag(const char *s, const gdcm::Tag& t, gdcm::DataSet& ds) +static void SetStringValueFromTag(const char *s, const gdcm::Tag& t, gdcm::Anonymizer & ano) +{ + if( s && *s ) + { +#if 0 + gdcm::DataElement de( t ); + de.SetByteValue( s, strlen( s ) ); + const gdcm::Global& g = gdcm::Global::GetInstance(); + const gdcm::Dicts &dicts = g.GetDicts(); + // FIXME: we know the tag at compile time we could save some time + // Using the static dict instead of the run-time one: + const gdcm::DictEntry &dictentry = dicts.GetDictEntry( t ); + de.SetVR( dictentry.GetVR() ); + ds.Insert( de ); +#else + ano.Replace(t, s); +#endif + } +} + + +//---------------------------------------------------------------------------- +int vtkGDCMImageWriter::WriteGDCMData(vtkImageData *data, int timeStep) +{ + //std::cerr << "Calling WriteGDCMData" << std::endl; + assert( timeStep >= 0 ); +#if (VTK_MAJOR_VERSION >= 6) + vtkInformation *inInfo = this->GetInputInformation(0, timeStep); + int inWholeExt[6]; + inInfo->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), inWholeExt); + int inExt[6]; + inInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(), inExt); +#else + int inWholeExt[6]; + data->GetWholeExtent(inWholeExt); + int inExt[6]; + data->GetUpdateExtent(inExt); +#endif +#if (VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 2 ) + vtkIdType inInc[3]; +#else + int inInc[3]; +#endif + data->GetIncrements(inInc); + + //data->Update(); + //data->Print( std::cout ); + //const char * filename = this->GetFileName(); + //std::cerr << data->GetDataDimension() << std::endl; + + gdcm::ImageWriter writer; + //writer.SetImage( image ); + gdcm::ImageChangeTransferSyntax change; + + //gdcm::Image &image = writer.GetImage(); + gdcm::Image &image = change.GetInput(); + + image.SetLossyFlag( this->LossyFlag ); + // Nowadays this is the default one: +#ifdef GDCM_WORDS_BIGENDIAN + // FIXME: this is not the default syntax, but should be a little faster on big endian machine + // let see if people complain dataset cannot be sent + image.SetTransferSyntax( gdcm::TransferSyntax::ExplicitVRBigEndian ); +#else + // that's the default syntax AND it is the fastest syntax to write to disk. + image.SetTransferSyntax( gdcm::TransferSyntax::ExplicitVRLittleEndian ); +#endif + image.SetNumberOfDimensions( 2 ); // good default + const int *dims = data->GetDimensions(); + assert( dims[0] >= 0 && dims[1] >= 0 && dims[2] >= 0 ); + image.SetDimension(0, dims[0] ); + image.SetDimension(1, dims[1] ); +#if (VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 2 ) + const double *spacing = data->GetSpacing(); +#else + const float *spacing = data->GetSpacing(); +#endif + image.SetSpacing(0, spacing[0] ); + image.SetSpacing(1, spacing[1] ); + if( dims[2] > 1 && this->FileDimensionality == 3 ) + { + // resize num of dim to 3: + image.SetNumberOfDimensions( 3 ); + image.SetDimension(2, dims[2] ); + } + // Even in case of 2D image, pass the 3rd dimension spacing, this might + // Be needed for example in MR : Spacing Between Slice tag + image.SetSpacing(2, spacing[2] ); // should always be valid... + // TODO: need to do Origin / Image Position (Patient) + // For now FileDimensionality should match File Dimension + //this->FileDimensionality + int scalarType = data->GetScalarType(); + gdcm::PixelFormat pixeltype = gdcm::PixelFormat::UNKNOWN; + switch( scalarType ) + { + case VTK_BIT: + pixeltype = gdcm::PixelFormat::SINGLEBIT; + break; + case VTK_CHAR: + if( vtkGDCMImageWriter_IsCharTypeSigned() ) + pixeltype = gdcm::PixelFormat::INT8; + else + pixeltype = gdcm::PixelFormat::UINT8; + break; +#if (VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 ) + case VTK_SIGNED_CHAR: + pixeltype = gdcm::PixelFormat::INT8; + break; +#endif + case VTK_UNSIGNED_CHAR: + pixeltype = gdcm::PixelFormat::UINT8; + break; + case VTK_SHORT: + pixeltype = gdcm::PixelFormat::INT16; + break; + case VTK_UNSIGNED_SHORT: + pixeltype = gdcm::PixelFormat::UINT16; + break; + case VTK_INT: + pixeltype = gdcm::PixelFormat::INT32; + break; + case VTK_UNSIGNED_INT: + pixeltype = gdcm::PixelFormat::UINT32; + break; + case VTK_FLOAT: + if( this->Shift == (int)this->Shift && this->Scale == (int)this->Scale ) + { + // I cannot consider that this is a problem, afterall a floating point type image + // could in fact really be only integer type, only print a warning to inform dummy user + vtkWarningMacro( "Image is floating point type, but rescale type is integer type. Rescaling anyway" ); + } + /* + Note to myself: should I allow people to squeeze into unsigned char ? Or can I assume most people + will be doing unsigned short anyway... + */ + pixeltype = gdcm::PixelFormat::FLOAT32; + break; + case VTK_DOUBLE: + if( this->Shift == (int)this->Shift && this->Scale == (int)this->Scale ) + { + // I cannot consider that this is a problem, afterall a floating point type image + // could in fact really be only integer type, only print a warning to inform dummy user + vtkWarningMacro( "Image is floating point type, but rescale type is integer type. Rescaling anyway" ); + } + /* + Note to myself: should I allow people to squeeze into unsigned char ? Or can I assume most people + will be doing unsigned short anyway... + */ + pixeltype = gdcm::PixelFormat::FLOAT64; + break; + default: + vtkErrorMacro( "Do not support this Pixel Type: " << scalarType ); + return 0; + } + + gdcm::PhotometricInterpretation pi; + if( this->ImageFormat ) + { + // We have been passed the proper image format, let's use it ! + switch( this->ImageFormat ) + { + case VTK_LUMINANCE: + pi = gdcm::PhotometricInterpretation::MONOCHROME2; + break; + case VTK_RGB: + pi = gdcm::PhotometricInterpretation::RGB; + break; + case VTK_RGBA: + pi = gdcm::PhotometricInterpretation::ARGB; + break; + case VTK_INVERSE_LUMINANCE: + pi = gdcm::PhotometricInterpretation::MONOCHROME1; + break; + case VTK_LOOKUP_TABLE: + pi = gdcm::PhotometricInterpretation::PALETTE_COLOR; + break; + case VTK_YBR: + pi = gdcm::PhotometricInterpretation::YBR_FULL; + break; + default: + vtkErrorMacro( "Unknown ImageFormat:" << this->ImageFormat ); + return 0; + } + } + else + { + // Attempt a guess + if( data->GetNumberOfScalarComponents() == 1 ) + { + pi = gdcm::PhotometricInterpretation::MONOCHROME2; + } + else if( data->GetNumberOfScalarComponents() == 3 ) + { + // It could well be YBR ... oh well + pi = gdcm::PhotometricInterpretation::RGB; + // (0028,0006) US 0 # 2, 1 PlanarConfiguration + } + else if( data->GetNumberOfScalarComponents() == 4 ) + { + // It could well be CMYK ... oh well + pi = gdcm::PhotometricInterpretation::ARGB; + } + else + { + return 0; + } + } + + // Let's try to fake out the SOP Class UID here: + gdcm::MediaStorage ms = gdcm::MediaStorage::SecondaryCaptureImageStorage; + ms.GuessFromModality( this->MedicalImageProperties->GetModality(), this->FileDimensionality ); // Will override SC only if something is found... + + // store in a safe place the 'raw' pixeltype from vtk + gdcm::PixelFormat savepixeltype = pixeltype; + if( this->Shift == 0 && this->Scale == 1 ) + { + //assert( pixeltype == outputpt ); + } + else + { + gdcm::Rescaler ir2; + ir2.SetIntercept( this->Shift ); + ir2.SetSlope( this->Scale ); + ir2.SetPixelFormat( pixeltype ); + // TODO: Hum...ScalarRange is -I believe- computed on the WholeExtent... + vtkFloatingPointType srange[2]; + data->GetScalarRange(srange); + // HACK !!! + // MR Image Storage cannot have Shift / Rescale , however it looks like people are doing it + // anyway, so let's make GDCM just as bad as any other library, by providing a fix: + if( ms == gdcm::MediaStorage::MRImageStorage /*&& pixeltype.GetBitsAllocated() == 8*/ ) + { + srange[1] = std::numeric_limits::max() * this->Scale + this->Shift; + } + ir2.SetMinMaxForPixelType( srange[0], srange[1] ); + //gdcm::PixelFormat::ScalarType outputpt = ir2.ComputeInterceptSlopePixelType(); + gdcm::PixelFormat outputpt = ir2.ComputePixelTypeFromMinMax(); + // override pixeltype with what is found by Rescaler + pixeltype = outputpt; + } + + pixeltype.SetSamplesPerPixel( (unsigned short)data->GetNumberOfScalarComponents() ); + image.SetPhotometricInterpretation( pi ); + image.SetPixelFormat( pixeltype ); + image.SetPlanarConfiguration( 0 ); // VTK default + + // Setup LUT if any: + if( pi == gdcm::PhotometricInterpretation::PALETTE_COLOR ) + { + assert( pixeltype.GetSamplesPerPixel() == 1 ); + vtkLookupTable * vtklut = data->GetPointData()->GetScalars()->GetLookupTable(); + //vtkLookupTable * vtklut = this->LookupTable; + assert( vtklut ); + //const char *name = vtklut->GetClassName (); + vtkLookupTable16 * vtklut16 = vtkLookupTable16::SafeDownCast( vtklut ); + //assert( vtklut->GetNumberOfTableValues() == 256 ); + //vtkIdType vtknumcolors = vtklut->GetNumberOfTableValues(); + unsigned int lutlen = 256; + assert( pixeltype.GetBitsAllocated() == 8 || pixeltype.GetBitsAllocated() == 16 ); + if( pixeltype.GetBitsAllocated() == 8 ) + { + lutlen = 256; + } + else + { + //assert( pixeltype.GetBitsAllocated() == 16 ); + lutlen = 65536; + } + gdcm::SmartPointer lut = new gdcm::LookupTable; + lut->Allocate( pixeltype.GetBitsAllocated() ); + lut->InitializeLUT( gdcm::LookupTable::RED, (unsigned short)lutlen, 0, 16 ); + lut->InitializeLUT( gdcm::LookupTable::GREEN, (unsigned short)lutlen, 0, 16 ); + lut->InitializeLUT( gdcm::LookupTable::BLUE, (unsigned short)lutlen, 0, 16 ); + bool b; + if( vtklut16 ) + b = lut->WriteBufferAsRGBA( vtklut16->WritePointer(0,4) ); + else + b = lut->WriteBufferAsRGBA( vtklut->WritePointer(0,4) ); + if( !b ) + { + vtkWarningMacro( "Could not get values from LUT" ); + return 0; + } + + image.SetLUT( *lut ); + } + + unsigned long len = image.GetBufferLength(); + vtkIdType npts = (vtkIdType)(inExt[5] - inExt[4] + 1) * (inExt[3] - inExt[2] + 1) * (inExt[1] - inExt[0] + 1); + if( npts < 0 ) + { + vtkErrorMacro( "Could not Get number of points" ); + return 0; + } + //assert( npts >= 0 ); + //assert( npts == data->GetNumberOfPoints() ); + int ssize = data->GetScalarSize(); + unsigned long vtklen = npts * ssize; + if( ssize == 0 ) + { + assert( data->GetScalarType() == VTK_BIT ); + vtklen = npts / 8; + } + else + { + vtklen = npts * ssize; + assert( vtklen >= (unsigned long)npts ); + } + //unsigned long vtklen = npts * ssize; + //assert( vtklen == len * ssize ); + + gdcm::DataElement pixeldata( gdcm::Tag(0x7fe0,0x0010) ); + gdcm::ByteValue *bv = new gdcm::ByteValue(); // (char*)data->GetScalarPointer(), len ); + bv->SetLength( (uint32_t)len ); // allocate ! + +// std::ofstream of( "/tmp/bla.raw", std::ios::binary ); +// of.write( (char*)data->GetScalarPointer(), len); +// of.close(); + // re shuffle the line within ByteValue: + // + char *pointer = (char*)bv->GetPointer(); + //const char *tempimage = (char*)data->GetScalarPointer(); + const char *tempimage = (char*)data->GetScalarPointerForExtent(inExt); + //std::cerr << "Pointer:" << (unsigned int)tempimage << std::endl; + int *dext = data->GetExtent(); + long outsize; + if( data->GetScalarType() == VTK_BIT ) + { + outsize = (dext[1] - dext[0] + 1) / 8; + } + else + { + outsize = pixeltype.GetPixelSize()*(dext[1] - dext[0] + 1); + } + int jj = dext[4]; + + + bool rescaled = false; + char * copy = NULL; + // Whenever shift / scale is needed... do it ! + if( this->Shift != 0 || this->Scale != 1 ) + { + assert( this->PlanarConfiguration == 0 ); + // rescale from float to unsigned short + gdcm::Rescaler ir; + ir.SetIntercept( this->Shift ); + ir.SetSlope( this->Scale ); + ir.SetPixelFormat( savepixeltype ); + vtkFloatingPointType srange[2]; + data->GetScalarRange(srange); + // HACK !!! + // MR Image Storage cannot have Shift / Rescale , however it looks like people are doing it + // anyway, so let's make GDCM just as bad as any other library, by providing a fix: + if( ms == gdcm::MediaStorage::MRImageStorage /*&& pixeltype.GetBitsAllocated() == 8*/ ) + { + srange[1] = std::numeric_limits::max() * this->Scale + this->Shift; + } + ir.SetMinMaxForPixelType( srange[0], srange[1] ); + image.SetIntercept( this->Shift ); + image.SetSlope( this->Scale ); + copy = new char[len]; + ir.InverseRescale(copy,tempimage,vtklen); + rescaled = true; + tempimage = copy; + } + + //std::cerr << "dext[4]:" << j << std::endl; + //std::cerr << "inExt[4]:" << inExt[4] << std::endl; + if( this->FileLowerLeft ) + { + memcpy(pointer,tempimage,len); + } + else + { + if( dims[2] > 1 && this->FileDimensionality == 3 ) + { + for(int j = dext[4]; j <= dext[5]; ++j) + { + for(int i = dext[2]; i <= dext[3]; ++i) + { + memcpy(pointer, + tempimage+((dext[3] - i)+j*(dext[3]+1))*outsize, outsize); + pointer += outsize; + } + } + } + else + { + for(int i = dext[2]; i <= dext[3]; ++i) + { + memcpy(pointer, + tempimage+((dext[3] - i)+jj*(dext[3]+1))*outsize, outsize); + pointer += outsize; + } + } + } + if( rescaled ) + { + delete[] copy; + } + + pixeldata.SetValue( *bv ); + image.SetDataElement( pixeldata ); + +// DEBUG +#ifndef NDEBUG + const gdcm::DataElement &pixeldata2 = image.GetDataElement(); + //const gdcm::Value &v = image.GetValue(); + //const gdcm::ByteValue *bv1 = dynamic_cast(&v); + const gdcm::ByteValue *bv1 = pixeldata2.GetByteValue(); + assert( bv1 && bv1 == bv ); + //image.Print( std::cerr ); +#endif +// END DEBUG + + // Do PlanarConfiguration + if( this->PlanarConfiguration ) + { + gdcm::ImageChangePlanarConfiguration icpc; + icpc.SetInput( image ); + icpc.SetPlanarConfiguration( 1 ); + icpc.Change(); + image = icpc.GetOutput(); + assert( image.GetPlanarConfiguration() == 1 ); + } + + + int year, month, day; + gdcm::File& file = writer.GetFile(); + gdcm::DataSet& ds = file.GetDataSet(); + vtkGDCMMedicalImageProperties *gdcmmip = + dynamic_cast( this->MedicalImageProperties ); + gdcm::Anonymizer ano; + if( gdcmmip ) + { + gdcm::File const &f = gdcmmip->GetFile(timeStep); + writer.SetFile( f ); + ano.SetFile( writer.GetFile() ); + } + else + { + ano.SetFile( file ); + // For ex: DICOM (0010,0010) = DOE,JOHN + SetStringValueFromTag(this->MedicalImageProperties->GetPatientName(), gdcm::Tag(0x0010,0x0010), ano); + // For ex: DICOM (0010,0020) = 1933197 + SetStringValueFromTag( this->MedicalImageProperties->GetPatientID(), gdcm::Tag(0x0010,0x0020), ano); + // For ex: DICOM (0010,1010) = 031Y + SetStringValueFromTag( this->MedicalImageProperties->GetPatientAge(), gdcm::Tag(0x0010,0x1010), ano); + // For ex: DICOM (0010,0040) = M + SetStringValueFromTag( this->MedicalImageProperties->GetPatientSex(), gdcm::Tag(0x0010,0x0040), ano); + // For ex: DICOM (0010,0030) = 19680427 + SetStringValueFromTag( this->MedicalImageProperties->GetPatientBirthDate(), gdcm::Tag(0x0010,0x0030), ano); +#if ( VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION > 0 ) + // For ex: DICOM (0008,0020) = 20030617 + if( vtkMedicalImageProperties::GetDateAsFields( this->MedicalImageProperties->GetStudyDate(), year, month, day ) ) + SetStringValueFromTag( this->MedicalImageProperties->GetStudyDate(), gdcm::Tag(0x0008,0x0020), ano); +#endif + // For ex: DICOM (0008,0022) = 20030617 + SetStringValueFromTag( this->MedicalImageProperties->GetAcquisitionDate(), gdcm::Tag(0x0008,0x0022), ano); +#if ( VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION > 0 ) + // For ex: DICOM (0008,0030) = 162552.0705 or 230012, or 0012 +#if 0 + int hour, minute, second; + if( vtkMedicalImageProperties::GetTimeAsFields( this->MedicalImageProperties->GetStudyTime(), hour, minute, second ) ) +#else + time_t studytime; + char date[22] = { ' ' }; + strcpy( date, "19000101" ); + if( this->MedicalImageProperties->GetStudyTime() ) + strncpy( date + 8 , this->MedicalImageProperties->GetStudyTime(), 22 - 8 ); + date[21] = 0; + if( gdcm::System::ParseDateTime(studytime, date ) ) +#endif + SetStringValueFromTag( this->MedicalImageProperties->GetStudyTime(), gdcm::Tag(0x0008,0x0030), ano); +#endif + // For ex: DICOM (0008,0032) = 162552.0705 or 230012, or 0012 + SetStringValueFromTag( this->MedicalImageProperties->GetAcquisitionTime(), gdcm::Tag(0x0008,0x0032), ano); + // For ex: DICOM (0008,0023) = 20030617 + SetStringValueFromTag( this->MedicalImageProperties->GetImageDate(), gdcm::Tag(0x0008,0x0023), ano); + // For ex: DICOM (0008,0033) = 162552.0705 or 230012, or 0012 + SetStringValueFromTag( this->MedicalImageProperties->GetImageTime(), gdcm::Tag(0x0008,0x0033), ano); + // For ex: DICOM (0020,0013) = 1 + SetStringValueFromTag( this->MedicalImageProperties->GetImageNumber(), gdcm::Tag(0x0020,0x0013), ano); + // For ex: DICOM (0020,0011) = 902 + SetStringValueFromTag( this->MedicalImageProperties->GetSeriesNumber(), gdcm::Tag(0x0020,0x0011), ano); + // For ex: DICOM (0008,103e) = SCOUT + SetStringValueFromTag( this->MedicalImageProperties->GetSeriesDescription(), gdcm::Tag(0x0008,0x103e), ano); + // For ex: DICOM (0020,0010) = 37481 + SetStringValueFromTag( this->MedicalImageProperties->GetStudyID(), gdcm::Tag(0x0020,0x0010), ano); + // For ex: DICOM (0008,1030) = BRAIN/C-SP/FACIAL + SetStringValueFromTag( this->MedicalImageProperties->GetStudyDescription(), gdcm::Tag(0x0008,0x1030), ano); + // For ex: DICOM (0008,0060)= CT + SetStringValueFromTag( this->MedicalImageProperties->GetModality(), gdcm::Tag(0x0008,0x0060), ano); + // For ex: DICOM (0008,0070) = Siemens + SetStringValueFromTag( this->MedicalImageProperties->GetManufacturer(), gdcm::Tag(0x0008,0x0070), ano); + // For ex: DICOM (0008,1090) = LightSpeed QX/i + SetStringValueFromTag( this->MedicalImageProperties->GetManufacturerModelName(), gdcm::Tag(0x0008,0x1090), ano); + // For ex: DICOM (0008,1010) = LSPD_OC8 + SetStringValueFromTag( this->MedicalImageProperties->GetStationName(), gdcm::Tag(0x0008,0x1010), ano); + // For ex: DICOM (0008,0080) = FooCity Medical Center + SetStringValueFromTag( this->MedicalImageProperties->GetInstitutionName(), gdcm::Tag(0x0008,0x0080), ano); + // For ex: DICOM (0018,1210) = Bone + SetStringValueFromTag( this->MedicalImageProperties->GetConvolutionKernel(), gdcm::Tag(0x0018,0x1210), ano); + // For ex: DICOM (0018,0050) = 0.273438 + SetStringValueFromTag( this->MedicalImageProperties->GetSliceThickness(), gdcm::Tag(0x0018,0x0050), ano); + // For ex: DICOM (0018,0060) = 120 + SetStringValueFromTag( this->MedicalImageProperties->GetKVP(), gdcm::Tag(0x0018,0x0060), ano); + // For ex: DICOM (0018,1120) = 15 + SetStringValueFromTag( this->MedicalImageProperties->GetGantryTilt(), gdcm::Tag(0x0018,0x1120), ano); + // For ex: DICOM (0018,0081) = 105 + SetStringValueFromTag( this->MedicalImageProperties->GetEchoTime(), gdcm::Tag(0x0018,0x0081), ano); + // For ex: DICOM (0018,0091) = 35 + SetStringValueFromTag( this->MedicalImageProperties->GetEchoTrainLength(), gdcm::Tag(0x0018,0x0091), ano); + // For ex: DICOM (0018,0080) = 2040 + SetStringValueFromTag( this->MedicalImageProperties->GetRepetitionTime(), gdcm::Tag(0x0018,0x0080), ano); + // For ex: DICOM (0018,1150) = 5 + SetStringValueFromTag( this->MedicalImageProperties->GetExposureTime(), gdcm::Tag(0x0018,0x1150), ano); + // For ex: DICOM (0018,1151) = 400 + SetStringValueFromTag( this->MedicalImageProperties->GetXRayTubeCurrent(), gdcm::Tag(0x0018,0x1151), ano); + // For ex: DICOM (0018,1152) = 114 + SetStringValueFromTag( this->MedicalImageProperties->GetExposure(), gdcm::Tag(0x0018,0x1152), ano); + + // Window Level / Window Center + int numwl = this->MedicalImageProperties->GetNumberOfWindowLevelPresets(); + if( numwl ) + { + gdcm::VR vr = gdcm::VR::DS; + gdcm::Element elwc; + elwc.SetLength( numwl * vr.GetSizeof() ); + gdcm::Element elww; + elww.SetLength( numwl * vr.GetSizeof() ); + vr = gdcm::VR::LO; + gdcm::Element elwe; + elwe.SetLength( numwl * vr.GetSizeof() ); + for(int i = 0; i < numwl; ++i) + { + const double *wl = this->MedicalImageProperties->GetNthWindowLevelPreset(i); + elww.SetValue( wl[0], i ); + elwc.SetValue( wl[1], i ); + const char* we = this->MedicalImageProperties->GetNthWindowLevelPresetComment(i); + elwe.SetValue( we, i ); + } + { + gdcm::DataElement de = elwc.GetAsDataElement(); + de.SetTag( gdcm::Tag(0x0028,0x1050) ); + ds.Insert( de ); + } + { + gdcm::DataElement de = elww.GetAsDataElement(); + de.SetTag( gdcm::Tag(0x0028,0x1051) ); + ds.Insert( de ); + } + { + gdcm::DataElement de = elwe.GetAsDataElement(); + de.SetTag( gdcm::Tag(0x0028,0x1055) ); + ds.Insert( de ); + } + } +#if ( VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION > 0 ) + // User defined value + // Remap any user defined value from the DICOM name to the DICOM tag + unsigned int nvalues = this->MedicalImageProperties->GetNumberOfUserDefinedValues(); + for(unsigned int i = 0; i < nvalues; ++i) + { + const char *name = this->MedicalImageProperties->GetUserDefinedNameByIndex(i); + const char *value = this->MedicalImageProperties->GetUserDefinedValueByIndex(i); + assert( name && value && *name && *value ); + // Only deal with public elements: + const gdcm::Global& g = gdcm::Global::GetInstance(); + const gdcm::Dicts &dicts = g.GetDicts(); + const gdcm::Dict &pubdict = dicts.GetPublicDict(); + gdcm::Tag t; + // Lookup up tag by name is truly inefficient : 0(n) + const gdcm::DictEntry &de = pubdict.GetDictEntryByName(name, t); (void)de; + SetStringValueFromTag( value, t, ano); + } +#endif + } + + + if( this->FileDimensionality != 2 && ( + ms == gdcm::MediaStorage::SecondaryCaptureImageStorage || + ms == gdcm::MediaStorage::MultiframeSingleBitSecondaryCaptureImageStorage + ) ) + { + // A.8.3.4 Multi-frame Grayscale Byte SC Image IOD Content Constraints +/* +- Samples per Pixel (0028,0002) shall be 1 +- Photometric Interpretation (0028,0004) shall be MONOCHROME2 +- Bits Allocated (0028,0100) shall be 8 +- Bits Stored (0028,0101) shall be 8 +- High Bit (0028,0102) shall be 7 +- Pixel Representation (0028,0103) shall be 0 +- Planar Configuration (0028,0006) shall not be present +*/ + if( this->FileDimensionality == 3 && + pixeltype.GetSamplesPerPixel() == 1 && + pi == gdcm::PhotometricInterpretation::MONOCHROME2 && + pixeltype.GetBitsAllocated() == 8 && + pixeltype.GetBitsStored() == 8 && + pixeltype.GetHighBit() == 7 && + pixeltype.GetPixelRepresentation() == 0 + // image.GetPlanarConfiguration() + ) + { + ms = gdcm::MediaStorage::MultiframeGrayscaleByteSecondaryCaptureImageStorage; + if( this->Shift != 0 || this->Scale != 1 ) + { + // Table C.8-25b SC MULTI-FRAME IMAGE MODULE ATTRIBUTES + // Note: This specifies an identity Modality LUT transformation. + vtkErrorMacro( "Cannot have shift/scale" ); + return 0; + } + } + else if( this->FileDimensionality == 3 && + pixeltype.GetSamplesPerPixel() == 1 && + pi == gdcm::PhotometricInterpretation::MONOCHROME2 && + pixeltype.GetBitsAllocated() == 1 && + pixeltype.GetBitsStored() == 1 && + pixeltype.GetHighBit() == 0 && + pixeltype.GetPixelRepresentation() == 0 + // image.GetPlanarConfiguration() + ) + { + ms = gdcm::MediaStorage::MultiframeSingleBitSecondaryCaptureImageStorage; + if( this->Shift != 0 || this->Scale != 1 ) + { + vtkErrorMacro( "Cannot have shift/scale" ); + return 0; + } + } + else if( this->FileDimensionality == 3 && + pixeltype.GetSamplesPerPixel() == 1 && + pi == gdcm::PhotometricInterpretation::MONOCHROME2 && + pixeltype.GetBitsAllocated() == 16 && + pixeltype.GetBitsStored() <= 16 && pixeltype.GetBitsStored() >= 9 && + pixeltype.GetHighBit() == pixeltype.GetBitsStored() - 1 && + pixeltype.GetPixelRepresentation() == 0 + // image.GetPlanarConfiguration() + ) + { + ms = gdcm::MediaStorage::MultiframeGrayscaleWordSecondaryCaptureImageStorage; + if( this->Shift != 0 || this->Scale != 1 ) + { + vtkErrorMacro( "Cannot have shift/scale" ); + return 0; + } + } + else if( this->FileDimensionality == 3 && + pixeltype.GetSamplesPerPixel() == 3 && + pi == gdcm::PhotometricInterpretation::RGB && + pixeltype.GetBitsAllocated() == 8 && + pixeltype.GetBitsStored() == 8 && + pixeltype.GetHighBit() == 7 && + pixeltype.GetPixelRepresentation() == 0 + // image.GetPlanarConfiguration() + ) + { + ms = gdcm::MediaStorage::MultiframeTrueColorSecondaryCaptureImageStorage; + if( this->Shift != 0 || this->Scale != 1 ) + { + vtkErrorMacro( "Cannot have shift/scale" ); + return 0; + } + } + else + { + vtkErrorMacro( "Cannot handle Multi Frame image in SecondaryCaptureImageStorage" ); + return 0; + } + } + + // FIXME: new Secondary object handle multi frames... + assert( gdcm::MediaStorage::IsImage( ms ) ); + { + gdcm::DataElement de( gdcm::Tag(0x0008, 0x0016) ); + const char* msstr = gdcm::MediaStorage::GetMSString(ms); + assert( msstr ); + de.SetByteValue( msstr, (uint32_t)strlen(msstr) ); + de.SetVR( gdcm::Attribute<0x0008, 0x0016>::GetVR() ); + ds.Insert( de ); + } + + // Image Type is pretty much always required: + gdcm::Attribute<0x0008,0x0008> imagetype; + const gdcm::CSComp values[] = { "ORIGINAL", "PRIMARY" }; + imagetype.SetValues( values, 2 ); + ds.Insert( imagetype.GetAsDataElement() ); + + // Image Orientation (Patient) + //gdcm::Attribute<0x0020,0x0037> iop = {{1,0,0,0,1,0}}; // default value + std::vector iop; + iop.resize(6); + const vtkMatrix4x4 *dircos = this->DirectionCosines; + for(int i = 0; i < 3; ++i) + { + iop[i] = dircos->GetElement(i,0); + } + + for(int i = 0; i < 3; ++i) + { + iop[i+3] = dircos->GetElement(i,1); + } +#if ( VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION > 2 ) + const double *iop_mip = this->MedicalImageProperties->GetDirectionCosine(); + if( iop[0] != iop_mip[0] + || iop[1] != iop_mip[1] + || iop[2] != iop_mip[2] + || iop[3] != iop_mip[3] + || iop[4] != iop_mip[4] + || iop[5] != iop_mip[5] + ) + { + vtkErrorMacro( "DirectionCosines is not compatible with vtkMedicalImageProperties::DirectionCosine" ); + return 0; + } +#endif + + image.SetDirectionCosines( &iop[0] ); + + std::vector ipp; + ipp.resize(3); + // Image Position (Patient) + // cross product of direction cosines gives the direction along + // which the slices are stacked + const double *iop1 = &iop[0]; + const double *iop2 = iop1+3; + double zaxis[3]; + vtkMath::Cross(iop1, iop2, zaxis); + + // determine the relative index of the current slice + // in the case of a single volume, this will be 0 + // since inExt (UpdateExtent) and WholeExt are the same + int n = inExt[4] - inWholeExt[4]; + const vtkFloatingPointType *vtkorigin = data->GetOrigin(); + vtkFloatingPointType origin[3]; + if( this->FileLowerLeft ) + { + origin[0] = vtkorigin[0]; + origin[1] = vtkorigin[1]; + origin[2] = vtkorigin[2]; + } + else + { + double norm = (dims[1] - 1) * spacing[1]; + origin[0] = vtkorigin[0] - norm * iop[3+0]; + origin[1] = vtkorigin[1] - norm * iop[3+1]; + origin[2] = vtkorigin[2] - norm * iop[3+2]; + } + double new_origin[3]; + // In order to compute the newer Image Position (Patient) we need to have a valid spacing along + // 3rd dimension. Simply give up in case 0: + // FIXME: Actually if user decides to write a series of SC object it is ok... + if( spacing[2] == 0. && dims[2] > 1 ) + { + vtkErrorMacro( "Z-spacing cannot be 0 for multiframe image" ); + return 0; + } + for (int i = 0; i < 3; i++) + { + // the n'th slice is n * z-spacing aloung the IOP-derived + // z-axis + new_origin[i] = origin[i] + zaxis[i] * n * spacing[2]; + } + + for(int i = 0; i < 3; ++i) + ipp[i] = new_origin[i]; + + image.SetOrigin(0, ipp[0] ); + image.SetOrigin(1, ipp[1] ); + image.SetOrigin(2, ipp[2] ); + assert( ipp.size() < 3 || image.GetOrigin(2) == ipp[2] ); + //gdcm::ImageHelper::SetOriginValue(ds, ipp, dims[2], spacing[2]); + + + // Here come the important part: generate proper UID for Series/Study so that people knows this is the same Study/Series + const char *studyuid = this->StudyUID; + assert( studyuid ); // programmer error + { + gdcm::DataElement de( gdcm::Tag(0x0020,0x000d) ); // Study + de.SetByteValue( studyuid, (uint32_t)strlen(studyuid) ); + de.SetVR( gdcm::Attribute<0x0020, 0x000d>::GetVR() ); + ds.Insert( de ); + } + const char *seriesuid = this->SeriesUID; + assert( seriesuid ); // programmer error + { + gdcm::DataElement de( gdcm::Tag(0x0020,0x000e) ); // Series + de.SetByteValue( seriesuid, (uint32_t)strlen(seriesuid) ); + de.SetVR( gdcm::Attribute<0x0020, 0x000e>::GetVR() ); + ds.Insert( de ); + } + + const char *filename = NULL; + int k = inExt[4]; + if( this->FileNames->GetNumberOfValues() ) + { + //int n = this->FileNames->GetNumberOfValues(); + filename = this->FileNames->GetValue(k); + } + else + { + filename = this->GetFileName(); + } + assert( filename ); + + // Let's add an Instance Number just for fun, unless we have a vtkGDCMMedicalImageProperties + if( !gdcmmip ) + { + std::ostringstream os; + os << k; + // Will only be added if none found + SetStringValueFromTag(os.str().c_str(), gdcm::Tag(0x0020,0x0013), ano); + } + + switch( this->CompressionType ) + { + /* + * 10.1 DICOM DEFAULT TRANSFER SYNTAX + * DICOM defines a default Transfer Syntax, the DICOM Implicit VR Little Endian Transfer Syntax (UID = + * "1.2.840.10008.1.2"), which shall be supported by every conformant DICOM Implementation. + */ + case NO_COMPRESSION: + change.SetTransferSyntax( gdcm::TransferSyntax::ImplicitVRLittleEndian ); + break; + case JPEG_COMPRESSION: + change.SetTransferSyntax( gdcm::TransferSyntax::JPEGLosslessProcess14_1 ); + break; + case JPEG2000_COMPRESSION: + change.SetTransferSyntax( gdcm::TransferSyntax::JPEG2000Lossless ); + break; + case JPEGLS_COMPRESSION: + change.SetTransferSyntax( gdcm::TransferSyntax::JPEGLSLossless ); + break; + case RLE_COMPRESSION: + change.SetTransferSyntax( gdcm::TransferSyntax::RLELossless ); + break; + } + if( !change.Change() ) + { + vtkErrorMacro( "Could not change the Transfer Syntax for Compression Type: " ); + return 0; + } + writer.SetImage( change.GetOutput() ); + writer.SetFileName( filename ); + if( !writer.Write() ) + { + vtkErrorMacro( "Could not write" ); + return 0; + } + + return 1; +} + +//void vtkGDCMImageWriter::SetCompressionTypeFromString(const char *) +//{ +//} +// +//const char *vtkGDCMImageWriter::GetCompressionTypeAsString() +//{ +// NO_COMPRESSION = 0, // raw (default) +// JPEG_COMPRESSION, // JPEG +// JPEG2000_COMPRESSION, // J2K +// JPEGLS_COMPRESSION, // JPEG-LS +// RLE_COMPRESSION // RLE +//} +void vtkGDCMImageWriter::SetDirectionCosinesFromImageOrientationPatient(const double dircos[6]) +{ + this->DirectionCosines->SetElement(0,0, dircos[0]); + this->DirectionCosines->SetElement(1,0, dircos[1]); + this->DirectionCosines->SetElement(2,0, dircos[2]); + this->DirectionCosines->SetElement(3,0, 0); + this->DirectionCosines->SetElement(0,1, dircos[3]); + this->DirectionCosines->SetElement(1,1, dircos[4]); + this->DirectionCosines->SetElement(2,1, dircos[5]); + this->DirectionCosines->SetElement(3,1, 0); + double dircosz[3]; + vtkMath::Cross(dircos, dircos+3, dircosz); + this->DirectionCosines->SetElement(0,2, dircosz[0]); + this->DirectionCosines->SetElement(1,2, dircosz[1]); + this->DirectionCosines->SetElement(2,2, dircosz[2]); + this->DirectionCosines->SetElement(3,2, 0); +} + +//---------------------------------------------------------------------------- +void vtkGDCMImageWriter::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os,indent); +} diff --git a/gdcm/Utilities/VTK/vtkGDCMImageWriter.h b/gdcm/Utilities/VTK/vtkGDCMImageWriter.h new file mode 100644 index 0000000..2fc8760 --- /dev/null +++ b/gdcm/Utilities/VTK/vtkGDCMImageWriter.h @@ -0,0 +1,188 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +// .NAME vtkGDCMImageWriter - write DICOM files +// .SECTION Description +// vtkGDCMImageWriter is a sink object that write DICOM files +// this writer is single threaded (see vtkGDCMThreadedImageReader2 for multi-thread) +// +// .SECTION Warning: vtkLookupTable from the vtkImageData object taken into account +// only if ImageFormat is set to VTK_LOOKUP_TABLE +// +// .SECTION NOTE We are not using the usual API SetFilePrefix / SetFilePattern, +// but instead a list of filenames: see SetFileNames and class gdcm::FilenameGenerator +// +// .SECTION Warning +// You need to specify the correct ImageFormat (taken from the reader) +// You need to explicitly specify the DirectionCosines (taken from the reader) +// Since VTK 5.4 vtkMedicalImageProperties has its own DirectionCosine (no 's') +// user need to make sure the vtkMatrix4x4 is compatible with the 6-vector DirectionCosine. +// +// .SECTION NOTE Shift/Scale are global to all DICOM frames (=files) written +// as 2D slice, therefore the shift/scale operation might not be optimized for +// all slices. This is not recommended for image with a large dynamic range. +// +// .SECTION See Also +// vtkImageWriter vtkMedicalImageProperties vtkGDCMImageReader + +#ifndef VTKGDCMIMAGEWRITER_H +#define VTKGDCMIMAGEWRITER_H + +#include "vtkImageWriter.h" + +class vtkLookupTable; +class vtkMedicalImageProperties; +class vtkMatrix4x4; +class vtkStringArray; +class VTK_EXPORT vtkGDCMImageWriter : public vtkImageWriter +{ +public: + static vtkGDCMImageWriter *New(); + vtkTypeRevisionMacro(vtkGDCMImageWriter,vtkImageWriter); + virtual void PrintSelf(ostream& os, vtkIndent indent); + + // Description: + // Pass in the vtkmedicalimageproperties object for medical information + // to be mapped to DICOM attributes. + vtkGetObjectMacro(MedicalImageProperties, vtkMedicalImageProperties); + virtual void SetMedicalImageProperties(vtkMedicalImageProperties*); + + // Description: + // Pass in the list of filename to be used to write out the DICOM file(s) + virtual void SetFileNames(vtkStringArray*); + vtkGetObjectMacro(FileNames, vtkStringArray); + + // Description: + // Set/Get whether or not the image was compressed using a lossy compression algorithm + vtkGetMacro(LossyFlag,int); + vtkSetMacro(LossyFlag,int); + vtkBooleanMacro(LossyFlag,int); + + // I need that... + virtual void Write(); + + // Description: + // Get the entension for this file format. + virtual const char* GetFileExtensions() { + return ".dcm .DCM"; } + + // Description: + // Get the name of this file format. + virtual const char* GetDescriptiveName() { + return "DICOM"; } + + // Description: + // You need to manually specify the direction the image is in to write a valid DICOM file + // since vtkImageData do not contains one (eg. MR Image Storage, CT Image Storage...) + virtual void SetDirectionCosines(vtkMatrix4x4 *matrix); + vtkGetObjectMacro(DirectionCosines, vtkMatrix4x4); + virtual void SetDirectionCosinesFromImageOrientationPatient(const double dircos[6]); + + // Description: + // Modality LUT + vtkSetMacro(Shift, double); + vtkGetMacro(Shift, double); + vtkSetMacro(Scale, double); + vtkGetMacro(Scale, double); + + // Description: + // See vtkGDCMImageReader for list of ImageFormat + vtkGetMacro(ImageFormat,int); + vtkSetMacro(ImageFormat,int); + + // Description: + // Set/Get whether the data comes from the file starting in the lower left + // corner or upper left corner. + vtkBooleanMacro(FileLowerLeft, int); + vtkGetMacro(FileLowerLeft, int); + vtkSetMacro(FileLowerLeft, int); + + // Description: + // For color image (more than a single comp) you can specify the planar configuration you prefer + vtkSetMacro(PlanarConfiguration,int); + vtkGetMacro(PlanarConfiguration,int); + + // Description: + // Set/Get specific StudyUID / SeriesUID + vtkSetStringMacro(StudyUID); + vtkGetStringMacro(StudyUID); + vtkSetStringMacro(SeriesUID); + vtkGetStringMacro(SeriesUID); + +//BTX + enum CompressionTypes { + NO_COMPRESSION = 0, // raw (default) + JPEG_COMPRESSION, // JPEG + JPEG2000_COMPRESSION, // J2K + JPEGLS_COMPRESSION, // JPEG-LS + RLE_COMPRESSION // RLE + }; +//ETX + // Set/Get the compression type + vtkSetMacro(CompressionType, int); + vtkGetMacro(CompressionType, int); + + //void SetCompressionTypeFromString(const char *); + //const char *GetCompressionTypeAsString(); + +protected: + vtkGDCMImageWriter(); + ~vtkGDCMImageWriter(); + +#if (VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 ) + int FillInputPortInformation(int port, vtkInformation *info); + int RequestInformation( + vtkInformation *request, + vtkInformationVector **inputVector, + vtkInformationVector *outputVector); + int RequestUpdateExtent( + vtkInformation *request, + vtkInformationVector **inputVector, + vtkInformationVector *outputVector); + int RequestData( + vtkInformation *request, + vtkInformationVector **inputVector, + vtkInformationVector *outputVector); +#else + void WriteSlice(vtkImageData *data); +#endif /*(VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 )*/ + int WriteGDCMData(vtkImageData *data, int timeStep); + +protected: + virtual /*const*/ char *GetFileName(); + +private: + vtkGDCMImageWriter(const vtkGDCMImageWriter&); // Not implemented. + void operator=(const vtkGDCMImageWriter&); // Not implemented. + + // VTK structs: + //vtkLookupTable *LookupTable; + vtkMedicalImageProperties *MedicalImageProperties; + char *StudyUID; + char *SeriesUID; + + int DataUpdateExtent[6]; + int ImageFormat; + + vtkStringArray *FileNames; + vtkMatrix4x4 *DirectionCosines; + + double Shift; + double Scale; + int FileLowerLeft; + int PlanarConfiguration; + int LossyFlag; + int CompressionType; +}; + +#endif diff --git a/gdcm/Utilities/VTK/vtkGDCMMedicalImageProperties.cxx b/gdcm/Utilities/VTK/vtkGDCMMedicalImageProperties.cxx new file mode 100644 index 0000000..5b1a955 --- /dev/null +++ b/gdcm/Utilities/VTK/vtkGDCMMedicalImageProperties.cxx @@ -0,0 +1,71 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkGDCMMedicalImageProperties.h" +#include "vtkObjectFactory.h" + +#include "gdcmFile.h" + +//---------------------------------------------------------------------------- +vtkCxxRevisionMacro(vtkGDCMMedicalImageProperties, "1.21") +vtkStandardNewMacro(vtkGDCMMedicalImageProperties) + +class vtkGDCMMedicalImagePropertiesInternals +{ +public: + std::vector< gdcm::SmartPointer > Files; +}; + +//---------------------------------------------------------------------------- +vtkGDCMMedicalImageProperties::vtkGDCMMedicalImageProperties() +{ + this->Internals = new vtkGDCMMedicalImagePropertiesInternals; +} + +//---------------------------------------------------------------------------- +vtkGDCMMedicalImageProperties::~vtkGDCMMedicalImageProperties() +{ + if (this->Internals) + { + delete this->Internals; + this->Internals = NULL; + } + this->Clear(); +} + +//---------------------------------------------------------------------------- +void vtkGDCMMedicalImageProperties::Clear() +{ + this->Superclass::Clear(); +} + +//---------------------------------------------------------------------------- +void vtkGDCMMedicalImageProperties::PushBackFile(gdcm::File const &f) +{ + this->Internals->Files.push_back( f ); + size_t i = this->Internals->Files.size(); + gdcm::DataSet &ds = this->Internals->Files[ i - 1 ]->GetDataSet(); + ds.Remove( gdcm::Tag( 0x7fe0, 0x0010 ) ); +} + +//---------------------------------------------------------------------------- +gdcm::File const & vtkGDCMMedicalImageProperties::GetFile(unsigned int t) +{ + return *this->Internals->Files[ t ]; +} + +//---------------------------------------------------------------------------- +void vtkGDCMMedicalImageProperties::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os, indent); +} diff --git a/gdcm/Utilities/VTK/vtkGDCMMedicalImageProperties.h b/gdcm/Utilities/VTK/vtkGDCMMedicalImageProperties.h new file mode 100644 index 0000000..e6ab087 --- /dev/null +++ b/gdcm/Utilities/VTK/vtkGDCMMedicalImageProperties.h @@ -0,0 +1,374 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +// .NAME vtkGDCMMedicalImageProperties - some medical image properties. +// .SECTION Description +// vtkGDCMMedicalImageProperties is a helper class that can be used by medical +// image readers and applications to encapsulate medical image/acquisition +// properties. Later on, this should probably be extended to add +// any user-defined property. +// .SECTION See Also +// vtkMedicalImageReader2 + +#ifndef VTKGDCMMEDICALIMAGEPROPERTIES_H +#define VTKGDCMMEDICALIMAGEPROPERTIES_H + +#include "vtkMedicalImageProperties.h" + +class vtkGDCMMedicalImagePropertiesInternals; +//BTX +namespace gdcm { class File; } +//ETX + +class VTK_EXPORT vtkGDCMMedicalImageProperties : public vtkMedicalImageProperties +{ +public: + static vtkGDCMMedicalImageProperties *New(); + vtkTypeRevisionMacro(vtkGDCMMedicalImageProperties,vtkMedicalImageProperties); + void PrintSelf(ostream& os, vtkIndent indent); + + // Description: + // Convenience method to reset all fields to an emptry string/value + virtual void Clear(); + +/* + // Description: + // Patient name + // For ex: DICOM (0010,0010) = DOE,JOHN + vtkSetStringMacro(PatientName); + vtkGetStringMacro(PatientName); + + // Description: + // Patient ID + // For ex: DICOM (0010,0020) = 1933197 + vtkSetStringMacro(PatientID); + vtkGetStringMacro(PatientID); + + // Description: + // Patient age + // Format: nnnD, nnW, nnnM or nnnY (eventually nnD, nnW, nnY) + // with D (day), M (month), W (week), Y (year) + // For ex: DICOM (0010,1010) = 031Y + vtkSetStringMacro(PatientAge); + vtkGetStringMacro(PatientAge); + + // Description: + // Take as input a string in VR=AS (DICOM PS3.5) and extract either + // different fields namely: year month week day + // Return 0 on error, 1 on success + // One can test fields if they are different from -1 upon success + static int GetAgeAsFields(const char *age, int &year, int &month, int &week, int &day); + + // For Tcl: + // From C++ use GetPatientAge + GetAgeAsField + // Those function parse a DICOM string, and return the value of the number expressed + // this is either expressed in year, month or days. Thus if a string is expressed in years + // GetPatientAgeDay/GetPatientAgeWeek/GetPatientAgeMonth will return 0 + int GetPatientAgeYear(); + int GetPatientAgeMonth(); + int GetPatientAgeWeek(); + int GetPatientAgeDay(); + + // Description: + // Patient sex + // For ex: DICOM (0010,0040) = M + vtkSetStringMacro(PatientSex); + vtkGetStringMacro(PatientSex); + + // Description: + // Patient birth date + // Format: yyyymmdd + // For ex: DICOM (0010,0030) = 19680427 + vtkSetStringMacro(PatientBirthDate); + vtkGetStringMacro(PatientBirthDate); + + // For Tcl: + // From C++ use GetPatientBirthDate + GetDateAsFields + int GetPatientBirthDateYear(); + int GetPatientBirthDateMonth(); + int GetPatientBirthDateDay(); + + // Description: + // Study Date + // Format: yyyymmdd + // For ex: DICOM (0008,0020) = 20030617 + vtkSetStringMacro(StudyDate); + vtkGetStringMacro(StudyDate); + + // Description: + // Acquisition Date + // Format: yyyymmdd + // For ex: DICOM (0008,0022) = 20030617 + vtkSetStringMacro(AcquisitionDate); + vtkGetStringMacro(AcquisitionDate); + + // For Tcl: + // From C++ use GetAcquisitionDate + GetDateAsFields + int GetAcquisitionDateYear(); + int GetAcquisitionDateMonth(); + int GetAcquisitionDateDay(); + + // Description: + // Study Time + // Format: hhmmss.frac (any trailing component(s) can be ommited) + // For ex: DICOM (0008,0030) = 162552.0705 or 230012, or 0012 + vtkSetStringMacro(StudyTime); + vtkGetStringMacro(StudyTime); + + // Description: + // Acquisition time + // Format: hhmmss.frac (any trailing component(s) can be ommited) + // For ex: DICOM (0008,0032) = 162552.0705 or 230012, or 0012 + vtkSetStringMacro(AcquisitionTime); + vtkGetStringMacro(AcquisitionTime); + + // Description: + // Image Date aka Content Date + // Format: yyyymmdd + // For ex: DICOM (0008,0023) = 20030617 + vtkSetStringMacro(ImageDate); + vtkGetStringMacro(ImageDate); + + // For Tcl: + // From C++ use GetImageDate + GetDateAsFields + int GetImageDateYear(); + int GetImageDateMonth(); + int GetImageDateDay(); + + // Description: + // Take as input a string in ISO 8601 date (YYYY/MM/DD) and extract the + // different fields namely: year month day + // Return 0 on error, 1 on success + static int GetDateAsFields(const char *date, int &year, int &month, int &day); + + // Description: + // Take as input a string in ISO 8601 date (YYYY/MM/DD) and construct a + // locale date based on the different fields (see GetDateAsFields to extract + // different fields) + // Return 0 on error, 1 on success + static int GetDateAsLocale(const char *date, char *locale); + + // Description: + // Image Time + // Format: hhmmss.frac (any trailing component(s) can be ommited) + // For ex: DICOM (0008,0033) = 162552.0705 or 230012, or 0012 + vtkSetStringMacro(ImageTime); + vtkGetStringMacro(ImageTime); + + // Description: + // Image number + // For ex: DICOM (0020,0013) = 1 + vtkSetStringMacro(ImageNumber); + vtkGetStringMacro(ImageNumber); + + // Description: + // Series number + // For ex: DICOM (0020,0011) = 902 + vtkSetStringMacro(SeriesNumber); + vtkGetStringMacro(SeriesNumber); + + // Description: + // Series Description + // User provided description of the Series + // For ex: DICOM (0008,103e) = SCOUT + vtkSetStringMacro(SeriesDescription); + vtkGetStringMacro(SeriesDescription); + + // Description: + // Study ID + // For ex: DICOM (0020,0010) = 37481 + vtkSetStringMacro(StudyID); + vtkGetStringMacro(StudyID); + + // Description: + // Study description + // For ex: DICOM (0008,1030) = BRAIN/C-SP/FACIAL + vtkSetStringMacro(StudyDescription); + vtkGetStringMacro(StudyDescription); + + // Description: + // Modality + // For ex: DICOM (0008,0060)= CT + vtkSetStringMacro(Modality); + vtkGetStringMacro(Modality); + + // Description: + // Manufacturer + // For ex: DICOM (0008,0070) = Siemens + vtkSetStringMacro(Manufacturer); + vtkGetStringMacro(Manufacturer); + + // Description: + // Manufacturer's Model Name + // For ex: DICOM (0008,1090) = LightSpeed QX/i + vtkSetStringMacro(ManufacturerModelName); + vtkGetStringMacro(ManufacturerModelName); + + // Description: + // Station Name + // For ex: DICOM (0008,1010) = LSPD_OC8 + vtkSetStringMacro(StationName); + vtkGetStringMacro(StationName); + + // Description: + // Institution Name + // For ex: DICOM (0008,0080) = FooCity Medical Center + vtkSetStringMacro(InstitutionName); + vtkGetStringMacro(InstitutionName); + + // Description: + // Convolution Kernel (or algorithm used to reconstruct the data) + // For ex: DICOM (0018,1210) = Bone + vtkSetStringMacro(ConvolutionKernel); + vtkGetStringMacro(ConvolutionKernel); + + // Description: + // Slice Thickness (Nominal reconstructed slice thickness, in mm) + // For ex: DICOM (0018,0050) = 0.273438 + vtkSetStringMacro(SliceThickness); + vtkGetStringMacro(SliceThickness); + virtual double GetSliceThicknessAsDouble(); + + // Description: + // Peak kilo voltage output of the (x-ray) generator used + // For ex: DICOM (0018,0060) = 120 + vtkSetStringMacro(KVP); + vtkGetStringMacro(KVP); + + // Description: + // Gantry/Detector tilt (Nominal angle of tilt in degrees of the scanning + // gantry.) + // For ex: DICOM (0018,1120) = 15 + vtkSetStringMacro(GantryTilt); + vtkGetStringMacro(GantryTilt); + virtual double GetGantryTiltAsDouble(); + + // Description: + // Echo Time + // (Time in ms between the middle of the excitation pulse and the peak of + // the echo produced) + // For ex: DICOM (0018,0081) = 105 + vtkSetStringMacro(EchoTime); + vtkGetStringMacro(EchoTime); + + // Description: + // Echo Train Length + // (Number of lines in k-space acquired per excitation per image) + // For ex: DICOM (0018,0091) = 35 + vtkSetStringMacro(EchoTrainLength); + vtkGetStringMacro(EchoTrainLength); + + // Description: + // Repetition Time + // The period of time in msec between the beginning of a pulse sequence and + // the beginning of the succeeding (essentially identical) pulse sequence. + // For ex: DICOM (0018,0080) = 2040 + vtkSetStringMacro(RepetitionTime); + vtkGetStringMacro(RepetitionTime); + + // Description: + // Exposure time (time of x-ray exposure in msec) + // For ex: DICOM (0018,1150) = 5 + vtkSetStringMacro(ExposureTime); + vtkGetStringMacro(ExposureTime); + + // Description: + // X-ray tube current (in mA) + // For ex: DICOM (0018,1151) = 400 + vtkSetStringMacro(XRayTubeCurrent); + vtkGetStringMacro(XRayTubeCurrent); + + // Description: + // Exposure (The exposure expressed in mAs, for example calculated + // from Exposure Time and X-ray Tube Current) + // For ex: DICOM (0018,1152) = 114 + vtkSetStringMacro(Exposure); + vtkGetStringMacro(Exposure); + + // Interface to allow insertion of user define values, for instance in DICOM one would want to + // store the Protocol Name (0018,1030), in this case one would do: + // AddUserDefinedValue( "Protocol Name", "T1W/SE/1024" ); + void AddUserDefinedValue(const char *name, const char *value); + // Get a particular user value + const char *GetUserDefinedValue(const char *name); + // Get the number of user defined values + unsigned int GetNumberOfUserDefinedValues(); + // Get a name/value by index + const char *GetUserDefinedNameByIndex(unsigned int idx); + const char *GetUserDefinedValueByIndex(unsigned int idx); + + // Description: + // Copy the contents of p to this instance. + virtual void DeepCopy(vtkGDCMMedicalImageProperties *p); + + // Description: + // Add/Remove/Query the window/level presets that may have been associated + // to a medical image. Window is also known as 'width', level is also known + // as 'center'. The same window/level pair can not be added twice. + // As a convenience, a comment (aka Explanation) can be associated to a preset. + // For ex: DICOM Window Center (0028,1050) = 00045\000470 + // DICOM Window Width (0028,1051) = 0106\03412 + // DICOM Window Center Width Explanation (0028,1055) = WINDOW1\WINDOW2 + virtual void AddWindowLevelPreset(double w, double l); + virtual void RemoveWindowLevelPreset(double w, double l); + virtual void RemoveAllWindowLevelPresets(); + virtual int GetNumberOfWindowLevelPresets(); + virtual int HasWindowLevelPreset(double w, double l); + virtual int GetNthWindowLevelPreset(int idx, double *w, double *l); + virtual double* GetNthWindowLevelPreset(int idx); + virtual void SetNthWindowLevelPresetComment(int idx, const char *comment); + virtual const char* GetNthWindowLevelPresetComment(int idx); + + // Description: + // Mapping from a sliceidx within a volumeidx into a DICOM Instance UID + // Some DICOM reader can populate this structure so that later on from a slice index + // in a vtkImageData volume we can backtrack and find out which 2d slice it was coming from + const char *GetInstanceUIDFromSliceID(int volumeidx, int sliceid); + void SetInstanceUIDFromSliceID(int volumeidx, int sliceid, const char *uid); + + // Description: + // Provides the inverse mapping. Returns -1 if a slice for this uid is + // not found. + int GetSliceIDFromInstanceUID(int &volumeidx, const char *uid); + +//BTX + typedef enum { + AXIAL = 0, + CORONAL, + SAGITTAL + } OrientationType; +//ETX + int GetOrientationType(int volumeidx); + void SetOrientationType(int volumeidx, int orientation); + static const char *GetStringFromOrientationType(unsigned int type); +*/ +protected: + vtkGDCMMedicalImageProperties(); + ~vtkGDCMMedicalImageProperties(); + +//BTX + friend class vtkGDCMImageReader; + friend class vtkGDCMImageReader2; + friend class vtkGDCMImageWriter; + void PushBackFile(gdcm::File const &f); + gdcm::File const & GetFile(unsigned int t); +//ETX + +private: + vtkGDCMMedicalImagePropertiesInternals *Internals; + + vtkGDCMMedicalImageProperties(const vtkGDCMMedicalImageProperties&); // Not implemented. + void operator=(const vtkGDCMMedicalImageProperties&); // Not implemented. +}; + +#endif diff --git a/gdcm/Utilities/VTK/vtkGDCMPolyDataReader.cxx b/gdcm/Utilities/VTK/vtkGDCMPolyDataReader.cxx new file mode 100644 index 0000000..7875ede --- /dev/null +++ b/gdcm/Utilities/VTK/vtkGDCMPolyDataReader.cxx @@ -0,0 +1,833 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkGDCMPolyDataReader.h" + +#include "vtkObjectFactory.h" +#include "vtkInformation.h" +#include "vtkInformationVector.h" +#include "vtkPolyData.h" +#include "vtkStreamingDemandDrivenPipeline.h" +#include "vtkDoubleArray.h" +#include "vtkCellArray.h" +#include "vtkCellData.h" +#include "vtkMedicalImageProperties.h" +#include "vtkRTStructSetProperties.h" +#include "vtkEmptyCell.h" +#include "gdcmReader.h" +#include "gdcmSmartPointer.h" +#include "gdcmAttribute.h" +#include "gdcmSequenceOfItems.h" +#include "gdcmDirectoryHelper.h" + +vtkCxxRevisionMacro(vtkGDCMPolyDataReader, "$Revision: 1.74 $") +vtkStandardNewMacro(vtkGDCMPolyDataReader) + +//---------------------------------------------------------------------------- +vtkGDCMPolyDataReader::vtkGDCMPolyDataReader() +{ + this->FileName = NULL; + this->SetNumberOfInputPorts(0); + this->MedicalImageProperties = vtkMedicalImageProperties::New(); + this->RTStructSetProperties = vtkRTStructSetProperties::New(); +} + +//---------------------------------------------------------------------------- +vtkGDCMPolyDataReader::~vtkGDCMPolyDataReader() +{ + this->SetFileName(0); + this->MedicalImageProperties->Delete(); + this->RTStructSetProperties->Delete(); +} + + +//---------------------------------------------------------------------------- +void vtkGDCMPolyDataReader::FillMedicalImageInformation(const gdcm::Reader &reader) +{ + const gdcm::File &file = reader.GetFile(); + const gdcm::DataSet &ds = file.GetDataSet(); + + this->RTStructSetProperties->SetStructureSetLabel( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x3006,0x0002), ds).c_str() ); + this->RTStructSetProperties->SetStructureSetName( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x3006,0x0004), ds).c_str() ); + this->RTStructSetProperties->SetStructureSetDate( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x3006,0x0008), ds).c_str() ); + this->RTStructSetProperties->SetStructureSetTime( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x3006,0x0009), ds).c_str() ); + this->RTStructSetProperties->SetSOPInstanceUID( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0008,0x0018), ds).c_str() ); + this->RTStructSetProperties->SetStudyInstanceUID( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0020,0x000d), ds).c_str() ); + this->RTStructSetProperties->SetSeriesInstanceUID( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0020,0x000e), ds).c_str() ); + + // $ grep "vtkSetString\|DICOM" vtkMedicalImageProperties.h + // For ex: DICOM (0010,0010) = DOE,JOHN + this->MedicalImageProperties->SetPatientName( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0010,0x0010), ds).c_str() ); + // For ex: DICOM (0010,0020) = 1933197 + this->MedicalImageProperties->SetPatientID( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0010,0x0020), ds).c_str() ); + // For ex: DICOM (0010,1010) = 031Y + this->MedicalImageProperties->SetPatientAge( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0010,0x1010), ds).c_str() ); + // For ex: DICOM (0010,0040) = M + this->MedicalImageProperties->SetPatientSex( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0010,0x0040), ds).c_str() ); + // For ex: DICOM (0010,0030) = 19680427 + this->MedicalImageProperties->SetPatientBirthDate( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0010,0x0030), ds).c_str() ); +#if ( VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION > 0 ) + // For ex: DICOM (0008,0020) = 20030617 + this->MedicalImageProperties->SetStudyDate( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0008,0x0020), ds).c_str() ); +#endif + // For ex: DICOM (0008,0022) = 20030617 + this->MedicalImageProperties->SetAcquisitionDate( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0008,0x0022), ds).c_str() ); +#if ( VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION > 0 ) + // For ex: DICOM (0008,0030) = 162552.0705 or 230012, or 0012 + this->MedicalImageProperties->SetStudyTime( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0008,0x0030), ds).c_str() ); +#endif + // For ex: DICOM (0008,0032) = 162552.0705 or 230012, or 0012 + this->MedicalImageProperties->SetAcquisitionTime( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0008,0x0032), ds).c_str() ); + // For ex: DICOM (0008,0023) = 20030617 + this->MedicalImageProperties->SetImageDate( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0008,0x0023), ds).c_str() ); + // For ex: DICOM (0008,0033) = 162552.0705 or 230012, or 0012 + this->MedicalImageProperties->SetImageTime( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0008,0x0033), ds).c_str() ); + // For ex: DICOM (0020,0013) = 1 + this->MedicalImageProperties->SetImageNumber( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0020,0x0013), ds).c_str() ); + // For ex: DICOM (0020,0011) = 902 + this->MedicalImageProperties->SetSeriesNumber( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0020,0x0011), ds).c_str() ); + // For ex: DICOM (0008,103e) = SCOUT + this->MedicalImageProperties->SetSeriesDescription( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0008,0x103e), ds).c_str() ); + // For ex: DICOM (0020,0010) = 37481 + this->MedicalImageProperties->SetStudyID( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0020,0x0010), ds).c_str() ); + // For ex: DICOM (0008,1030) = BRAIN/C-SP/FACIAL + this->MedicalImageProperties->SetStudyDescription( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0008,0x1030), ds).c_str() ); + // For ex: DICOM (0008,0060)= CT + this->MedicalImageProperties->SetModality( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0008,0x0060), ds).c_str() ); + // For ex: DICOM (0008,0070) = Siemens + this->MedicalImageProperties->SetManufacturer( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0008,0x0070), ds).c_str() ); + // For ex: DICOM (0008,1090) = LightSpeed QX/i + this->MedicalImageProperties->SetManufacturerModelName( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0008,0x1090), ds).c_str() ); + // For ex: DICOM (0008,1010) = LSPD_OC8 + this->MedicalImageProperties->SetStationName( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0008,0x1010), ds).c_str() ); + // For ex: DICOM (0008,0080) = FooCity Medical Center + this->MedicalImageProperties->SetInstitutionName( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0008,0x0080), ds).c_str() ); + // For ex: DICOM (0018,1210) = Bone + this->MedicalImageProperties->SetConvolutionKernel( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0018,0x1210), ds).c_str() ); + // For ex: DICOM (0018,0050) = 0.273438 + this->MedicalImageProperties->SetSliceThickness( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0018,0x0050), ds).c_str() ); + // For ex: DICOM (0018,0060) = 120 + this->MedicalImageProperties->SetKVP( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0018,0x0060), ds).c_str() ); + // For ex: DICOM (0018,1120) = 15 + this->MedicalImageProperties->SetGantryTilt( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0018,0x1120), ds).c_str() ); + // For ex: DICOM (0018,0081) = 105 + this->MedicalImageProperties->SetEchoTime( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0018,0x0081), ds).c_str() ); + // For ex: DICOM (0018,0091) = 35 + this->MedicalImageProperties->SetEchoTrainLength( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0018,0x0091), ds).c_str() ); + // For ex: DICOM (0018,0080) = 2040 + this->MedicalImageProperties->SetRepetitionTime( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0018,0x0080), ds).c_str() ); + // For ex: DICOM (0018,1150) = 5 + this->MedicalImageProperties->SetExposureTime( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0018,0x1150), ds).c_str() ); + // For ex: DICOM (0018,1151) = 400 + this->MedicalImageProperties->SetXRayTubeCurrent( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0018,0x1151), ds).c_str() ); + // For ex: DICOM (0018,1152) = 114 + this->MedicalImageProperties->SetExposure( gdcm::DirectoryHelper::GetStringValueFromTag( gdcm::Tag(0x0018,0x1152), ds).c_str() ); + + // virtual void AddWindowLevelPreset(double w, double l); + // (0028,1050) DS [ 498\ 498] # 12, 2 WindowCenter + // (0028,1051) DS [ 1063\ 1063] # 12, 2 WindowWidth + gdcm::Tag twindowcenter(0x0028,0x1050); + gdcm::Tag twindowwidth(0x0028,0x1051); + if( ds.FindDataElement( twindowcenter ) && ds.FindDataElement( twindowwidth) ) + { + const gdcm::DataElement& windowcenter = ds.GetDataElement( twindowcenter ); + const gdcm::DataElement& windowwidth = ds.GetDataElement( twindowwidth ); + const gdcm::ByteValue *bvwc = windowcenter.GetByteValue(); + const gdcm::ByteValue *bvww = windowwidth.GetByteValue(); + if( bvwc && bvww ) // Can be Type 2 + { + //gdcm::Attributes<0x0028,0x1050> at; + gdcm::Element elwc; + std::stringstream ss1; + std::string swc = std::string( bvwc->GetPointer(), bvwc->GetLength() ); + ss1.str( swc ); + gdcm::VR vr = gdcm::VR::DS; + unsigned int vrsize = vr.GetSizeof(); + unsigned int count = gdcm::VM::GetNumberOfElementsFromArray(swc.c_str(), (unsigned int)swc.size()); + elwc.SetLength( count * vrsize ); + elwc.Read( ss1 ); + std::stringstream ss2; + std::string sww = std::string( bvww->GetPointer(), bvww->GetLength() ); + ss2.str( sww ); + gdcm::Element elww; + elww.SetLength( count * vrsize ); + elww.Read( ss2 ); + //assert( elww.GetLength() == elwc.GetLength() ); + for(unsigned int i = 0; i < elwc.GetLength(); ++i) + { + this->MedicalImageProperties->AddWindowLevelPreset( elww.GetValue(i), elwc.GetValue(i) ); + } + } + } + gdcm::Tag twindowexplanation(0x0028,0x1055); + if( ds.FindDataElement( twindowexplanation ) ) + { + const gdcm::DataElement& windowexplanation = ds.GetDataElement( twindowexplanation ); + const gdcm::ByteValue *bvwe = windowexplanation.GetByteValue(); + if( bvwe ) // Can be Type 2 + { + int n = this->MedicalImageProperties->GetNumberOfWindowLevelPresets(); + gdcm::Element elwe; // window explanation + gdcm::VR vr = gdcm::VR::LO; + std::stringstream ss; + ss.str( "" ); + std::string swe = std::string( bvwe->GetPointer(), bvwe->GetLength() ); + unsigned int count = gdcm::VM::GetNumberOfElementsFromArray(swe.c_str(), (unsigned int)swe.size()); (void)count; + // I found a case with only one W/L but two comments: WINDOW1\WINDOW2 + // SIEMENS-IncompletePixelData.dcm + //assert( count >= (unsigned int)n ); + elwe.SetLength( /*count*/ n * vr.GetSizeof() ); + ss.str( swe ); + elwe.Read( ss ); + for(int i = 0; i < n; ++i) + { + this->MedicalImageProperties->SetNthWindowLevelPresetComment(i, elwe.GetValue(i).c_str() ); + } + } + } + +#if 0 + // gdcmData/JDDICOM_Sample4.dcm + // -> (0008,0060) CS [DM Digital microscopy] # 24, 1 Modality + gdcm::MediaStorage ms1 = gdcm::MediaStorage::SecondaryCaptureImageStorage; + ms1.GuessFromModality( this->MedicalImageProperties->GetModality(), this->FileDimensionality ); + gdcm::MediaStorage ms2; + ms2.SetFromFile( reader.GetFile() ); + if( ms2 != ms1 && ms2 != gdcm::MediaStorage::SecondaryCaptureImageStorage ) + { + vtkWarningMacro( "SHOULD NOT HAPPEN. Unrecognized Modality: " << this->MedicalImageProperties->GetModality() + << " Will be set instead to the known one: " << ms2.GetModality() ) + this->MedicalImageProperties->SetModality( ms2.GetModality() ); + } +#endif + + // Add more info: + +} + +//(3006,0022) ?? (IS) [2 ] # 2,1 ROI Number +//(3006,0024) ?? (UI) [2.16.840.1.114362.1.759508.1251415878280.193] # 44,1 Referenced Frame of Reference UID +//(3006,0026) ?? (LO) [Bladder ] # 8,1 ROI Name +//(3006,0028) ST [STATIC] # 6, 1 ROIDescription +//(3006,0036) ?? (CS) [MANUAL] # 6,1 ROI Generation Algorithm + +int vtkGDCMPolyDataReader::RequestData_RTStructureSetStorage(gdcm::Reader const &reader, + vtkInformationVector *outputVector) +{ +// This is done in RequestInformation +// gdcm::MediaStorage ms; +// ms.SetFromFile( reader.GetFile() ); +// //std::cout << ms << std::endl; +// if( ms != gdcm::MediaStorage::RTStructureSetStorage ) +// { +// return 0; +// } + + const gdcm::DataSet& ds = reader.GetFile().GetDataSet(); + // (3006,0010) SQ (Sequence with undefined length #=1) # u/l, 1 ReferencedFrameOfReferenceSequence + // (3006,0020) SQ (Sequence with explicit length #=4) # 370, 1 StructureSetROISequence + // (3006,0039) SQ (Sequence with explicit length #=4) # 24216, 1 ROIContourSequence + gdcm::Tag troicsq(0x3006,0x0039); + if( !ds.FindDataElement( troicsq ) ) + { + return 0; + } + gdcm::Tag tssroisq(0x3006,0x0020); + if( !ds.FindDataElement( tssroisq ) ) + { + return 0; + } + gdcm::Tag trefframerefsq(0x3006,0x0010); + if( !ds.FindDataElement( trefframerefsq ) ) + { + return 0; + } + const gdcm::DataElement &refframerefsq = ds.GetDataElement( trefframerefsq ); + gdcm::SmartPointer sqi0 = refframerefsq.GetValueAsSQ(); + if( !sqi0 || !sqi0->GetNumberOfItems() ) + { + return 0; + } + assert( sqi0->GetNumberOfItems() == 1 ); + for(unsigned int pd = 0; pd < sqi0->GetNumberOfItems(); ++pd) + { + const gdcm::Item & item0 = sqi0->GetItem(pd+1); // Item start at #1 + const gdcm::DataSet& nestedds0 = item0.GetNestedDataSet(); + // (3006,0012) SQ (Sequence with undefined length #=1) # u/l, 1 RTReferencedStudySequence + gdcm::Attribute<0x0020,0x052> frameofreferenceuid; + frameofreferenceuid.SetFromDataSet( nestedds0 ); + this->RTStructSetProperties->SetReferenceFrameOfReferenceUID( + frameofreferenceuid.GetValue() ); + gdcm::Tag trtrefstudysq(0x3006,0x0012); + if( !nestedds0.FindDataElement( trtrefstudysq) ) + { + return 0; + } + const gdcm::DataElement &rtrefstudysq = nestedds0.GetDataElement( trtrefstudysq ); + gdcm::SmartPointer sqi00 = rtrefstudysq.GetValueAsSQ(); + if( !sqi00 || !sqi00->GetNumberOfItems() ) + { + return 0; + } + assert( sqi00->GetNumberOfItems() == 1 ); + for(unsigned int pd0 = 0; pd0 < sqi00->GetNumberOfItems(); ++pd0) + { + const gdcm::Item & item00 = sqi00->GetItem(pd0+1); // Item start at #1 + const gdcm::DataSet& nestedds00 = item00.GetNestedDataSet(); + + // (3006,0014) SQ (Sequence with undefined length #=1) # u/l, 1 RTReferencedSeriesSequence + gdcm::Tag trtrefseriessq(0x3006,0x0014); + if( !nestedds00.FindDataElement( trtrefseriessq) ) + { + return 0; + } + const gdcm::DataElement &rtrefseriessq = nestedds00.GetDataElement( trtrefseriessq); + + gdcm::SmartPointer sqi000 = rtrefseriessq.GetValueAsSQ(); + if( !sqi000 || !sqi000->GetNumberOfItems() ) + { + return 0; + } + assert( sqi000->GetNumberOfItems() == 1 ); + for(unsigned int pd00 = 0; pd00 < sqi000->GetNumberOfItems(); ++pd00) + { + const gdcm::Item & item000 = sqi000->GetItem(pd00+1); // Item start at #1 + const gdcm::DataSet& nestedds000 = item000.GetNestedDataSet(); + + gdcm::Attribute<0x0020,0x000e> seriesinstanceuid; + seriesinstanceuid.SetFromDataSet( nestedds000 ); + this->RTStructSetProperties->SetReferenceSeriesInstanceUID( + seriesinstanceuid.GetValue() ); + + // (3006,0016) SQ (Sequence with undefined length #=162) # u/l, 1 ContourImageSequence + gdcm::Tag tcontourimageseq(0x3006,0x0016); + if( !nestedds000.FindDataElement( tcontourimageseq) ) + { + return 0; + } + const gdcm::DataElement &contourimageseq = nestedds000.GetDataElement( tcontourimageseq ); + gdcm::SmartPointer sqi0000 = contourimageseq.GetValueAsSQ(); + if( !sqi0000 || !sqi0000->GetNumberOfItems() ) + { + return 0; + } + + assert( sqi0000->GetNumberOfItems() != 1 ); + for(unsigned int pd000 = 0; pd000 < sqi0000->GetNumberOfItems(); ++pd000) + { + const gdcm::Item & item = sqi0000->GetItem(pd000+1); // Item start at #1 + const gdcm::DataSet& nestedds = item.GetNestedDataSet(); + gdcm::Attribute<0x0008,0x1150> refsopclassuid; + refsopclassuid.SetFromDataSet( nestedds ); + gdcm::Attribute<0x0008,0x1155> refinstanceuid; + refinstanceuid.SetFromDataSet( nestedds ); + this->RTStructSetProperties->AddReferencedFrameOfReference( refsopclassuid.GetValue().c_str(), +refinstanceuid.GetValue().c_str() ); + } + + } + + } + } + + const gdcm::DataElement &roicsq = ds.GetDataElement( troicsq ); + //std::cout << roicsq << std::endl; + //const gdcm::SequenceOfItems *sqi_debug = roicsq.GetSequenceOfItems(); + gdcm::SmartPointer sqi = roicsq.GetValueAsSQ(); + if( !sqi || !sqi->GetNumberOfItems() ) + { + return 0; + } + const gdcm::DataElement &ssroisq = ds.GetDataElement( tssroisq ); + //const gdcm::SequenceOfItems *ssqi = ssroisq.GetSequenceOfItems(); + gdcm::SmartPointer ssqi = ssroisq.GetValueAsSQ(); + if( !ssqi || !ssqi->GetNumberOfItems() ) + { + return 0; + } + + // For each Item in the DataSet create a vtkPolyData + for(unsigned int pd = 0; pd < sqi->GetNumberOfItems(); ++pd) + { + //StructureSetROI structuresetroi; + // get the info object + vtkInformation *outInfo1 = outputVector->GetInformationObject(pd); + + // get the ouptut + vtkPolyData *output = vtkPolyData::SafeDownCast( + outInfo1->Get(vtkDataObject::DATA_OBJECT())); + + + const gdcm::Item & item = sqi->GetItem(pd+1); // Item start at #1 + //std::cout << item << std::endl; + const gdcm::Item & sitem = ssqi->GetItem(pd+1); // Item start at #1 + const gdcm::DataSet& snestedds = sitem.GetNestedDataSet(); + // (3006,0026) ?? (LO) [date] # 4,1 ROI Name + gdcm::Tag stcsq(0x3006,0x0026); + if( !snestedds.FindDataElement( stcsq ) ) + { + continue; + } + const gdcm::DataElement &sde = snestedds.GetDataElement( stcsq ); + std::string s(sde.GetByteValue()->GetPointer(), sde.GetByteValue()->GetLength()); + //structuresetroi.ROIName = s; + gdcm::Attribute<0x3006,0x0022> roinumber; + roinumber.SetFromDataSet( snestedds ); + //structuresetroi.ROINumber = roinumber.GetValue(); + gdcm::Attribute<0x3006,0x0024> refframeuid; + refframeuid.SetFromDataSet( snestedds ); + //structuresetroi.RefFrameRefUID = refframeuid.GetValue(); + gdcm::Attribute<0x3006,0x0026> roiname; + roiname.SetFromDataSet( snestedds ); + gdcm::Attribute<0x3006,0x0028> roidesc; + roidesc.SetFromDataSet( snestedds ); + assert( s == roiname.GetValue() ); + gdcm::Attribute<0x3006,0x0036> roigenalg; + roigenalg.SetFromDataSet( snestedds ); + //structuresetroi.ROIGenerationAlgorithm = roigenalg.GetValue(); + //structuresetrois.push_back( structuresetroi ); + + this->RTStructSetProperties->AddStructureSetROI( + roinumber.GetValue(), + refframeuid.GetValue(), + roiname.GetValue(), + roigenalg.GetValue(), + roidesc.GetValue() + ); + + const gdcm::DataSet& nestedds = item.GetNestedDataSet(); + //std::cout << nestedds << std::endl; + //(3006,002a) IS [255\192\96] # 10,3 ROI Display Color + gdcm::Tag troidc(0x3006,0x002a); + gdcm::Attribute<0x3006,0x002a> color; + bool hasColor = false;//so that color[0] isn't referenced if the color isn't present. + if( nestedds.FindDataElement( troidc) ) + { + const gdcm::DataElement &decolor = nestedds.GetDataElement( troidc ); + color.SetFromDataElement( decolor ); + hasColor = true; + //std::cout << "color: " << roinumber.GetValue() << " -> " << color[0] << "," << color[1] << "," << color[2] << std::endl; + } + //(3006,0040) SQ (Sequence with explicit length #=8) # 4326, 1 ContourSequence + gdcm::Tag tcsq(0x3006,0x0040); + if( !nestedds.FindDataElement( tcsq ) ) + { + // FIXME: What if a contour sequence is empty but the color is set to + // -say- 0/255/0 Since we are skipping entirely the contour sequence (no + // vtkCellArray) we will not save the color. which means it will be + // reported as 0/0/0 in the output DICOM file. + continue; + } + const gdcm::DataElement& csq = nestedds.GetDataElement( tcsq ); + //std::cout << csq << std::endl; + + //const gdcm::SequenceOfItems *sqi2 = csq.GetSequenceOfItems(); + gdcm::SmartPointer sqi2 = csq.GetValueAsSQ(); + if( !sqi2 )//|| !sqi2->GetNumberOfItems() ) + { + continue; + } + size_t nitems = sqi2->GetNumberOfItems(); + //std::cout << nitems << std::endl; + //this->SetNumberOfOutputPorts(nitems); + vtkDoubleArray *scalars = vtkDoubleArray::New(); + scalars->SetNumberOfComponents(3); + scalars->SetName( roiname.GetValue().c_str() ); + + vtkCellArray *polys = vtkCellArray::New(); + if (nitems == 0) + { + //still have to insert colors in blank masks, else they can get written incorrectly. + //also because the number of points of a contour should not define whether or not the color is used. + //looks kind of wonky to have a zero-sized polydata, but the polydata does need to still define organ color. + vtkEmptyCell* theEmptyCell = vtkEmptyCell::New(); + vtkIdType cellId = polys->InsertNextCell(theEmptyCell); + if (hasColor) + { + scalars->InsertTuple3(cellId, (double)color[0]/255.0, (double)color[1]/255.0, (double)color[2]/255.0); + } + else + { + scalars->InsertTuple3(cellId, 0,0,0); + } + theEmptyCell->Delete(); + output->GetCellData()->SetScalars(scalars); + scalars->Delete(); + polys->Delete(); + continue; + } + + + vtkPoints *newPts = vtkPoints::New(); + newPts->SetDataTypeToDouble();//ensure that full precision is retained + //std::string s(sde.GetByteValue()->GetPointer(), sde.GetByteValue()->GetLength()); + //std::cout << s << std::endl; + //newPts->GetData()->SetName( s.c_str() ); + // In VTK there is no API to specify the name of a vtkPolyData, you can only specify Name + // for the scalars (pointdata or celldata), so let's do that... + //scalars->SetName( structuresetroi.ROIName.c_str() ); + for(unsigned int ii = 0; ii < nitems; ++ii) + { + const gdcm::Item & item2 = sqi2->GetItem(ii+1); // Item start at #1 + + const gdcm::DataSet& nestedds2 = item2.GetNestedDataSet(); + //std::cout << nestedds2 << std::endl; + // (3006,0050) DS [43.57636\65.52504\-10.0\46.043102\62.564945\-10.0\49.126537\60.714... # 398,48 ContourData + gdcm::Tag tcontourdata(0x3006,0x0050); + const gdcm::DataElement & contourdata = nestedds2.GetDataElement( tcontourdata ); + //std::cout << contourdata << std::endl; + + //const gdcm::ByteValue *bv = contourdata.GetByteValue(); + gdcm::Attribute<0x3006,0x0042> contgeotype; + contgeotype.SetFromDataSet( nestedds2 ); + assert( contgeotype.GetValue() == "CLOSED_PLANAR " || contgeotype.GetValue() == "POINT " ); + + gdcm::Attribute<0x3006,0x0046> numcontpoints; + numcontpoints.SetFromDataSet( nestedds2 ); + + if( contgeotype.GetValue() == "POINT " ) + { + assert( numcontpoints.GetValue() == 1 ); + } + + gdcm::Attribute<0x3006,0x0050> at; + at.SetFromDataElement( contourdata ); + + if( contgeotype.GetValue() == "CLOSED_PLANAR " ) + { + assert( nestedds2.FindDataElement( gdcm::Tag(0x3006,0x0016) ) ); + const gdcm::DataElement &contourimagesequence = nestedds2.GetDataElement( gdcm::Tag(0x3006,0x0016) ); + gdcm::SmartPointer contourimagesequence_sqi = contourimagesequence.GetValueAsSQ(); + assert( contourimagesequence_sqi && contourimagesequence_sqi->GetNumberOfItems() == 1 ); + const gdcm::Item & theitem = contourimagesequence_sqi->GetItem(1); + const gdcm::DataSet& thenestedds = theitem.GetNestedDataSet(); + + gdcm::Attribute<0x0008,0x1150> classat; + classat.SetFromDataSet( thenestedds ); + gdcm::Attribute<0x0008,0x1155> instat; + instat.SetFromDataSet( thenestedds ); + + this->RTStructSetProperties->AddContourReferencedFrameOfReference( pd, + classat.GetValue(), instat.GetValue() ); + } + + //newPts->SetNumberOfPoints( at.GetNumberOfValues() / 3 ); + //assert( at.GetNumberOfValues() % 3 == 0); // FIXME + const double* pts = at.GetValues(); + vtkIdType *ptIds; + unsigned int npts = at.GetNumberOfValues() / 3; + assert( npts == (unsigned int)numcontpoints.GetValue() ); + assert( npts * 3 == at.GetNumberOfValues() ); + ptIds = new vtkIdType[npts]; + for(unsigned int i = 0; i < npts * 3; i+=3) + { + double x[3];//must be double precision, as that's the precision in vtk + x[0] = pts[i+0]; + x[1] = pts[i+1]; + x[2] = pts[i+2]; + vtkIdType ptId = newPts->InsertNextPoint( x ); + assert( i / 3 < npts ); + ptIds[i / 3] = ptId; + } + // Each Contour Data is in fact a Cell: + vtkIdType cellId = polys->InsertNextCell( npts , ptIds); + if (hasColor) + { + scalars->InsertTuple3(cellId, (double)color[0]/255.0, (double)color[1]/255.0, (double)color[2]/255.0); + } + else + { + scalars->InsertTuple3(cellId, 0,0,0); + } + delete[] ptIds; + ptIds = NULL; + } + output->SetPoints(newPts); + newPts->Delete(); + output->SetPolys(polys); + polys->Delete(); + output->GetCellData()->SetScalars(scalars); + scalars->Delete(); + } + + // Add the Observations: + // we can only be doing it here once all RT are loaded, since we will + // attach observation to *existing* rtstruct + gdcm::Tag trtroiobssq(0x3006,0x0080); + if( !ds.FindDataElement( trtroiobssq ) ) + { + return 0; + } + const gdcm::DataElement &rtroiobssq = ds.GetDataElement( trtroiobssq ); + gdcm::SmartPointer rtroiobssqsqi = rtroiobssq.GetValueAsSQ(); + size_t theNumberOfItems = rtroiobssqsqi->GetNumberOfItems(); + if( !rtroiobssqsqi )// || !rtroiobssqsqi->GetNumberOfItems() ) + { + return 0; + } + for(unsigned int obs = 0; obs < theNumberOfItems ; ++obs) + { + const gdcm::Item & item = rtroiobssqsqi->GetItem(obs+1); // Item start at #1 + const gdcm::DataSet& nestedds = item.GetNestedDataSet(); + gdcm::Attribute<0x3006,0x0082> observationnumber; + observationnumber.SetFromDataSet( nestedds ); + gdcm::Attribute<0x3006,0x0084> referencedroinumber; + referencedroinumber.SetFromDataSet( nestedds ); + gdcm::Attribute<0x3006,0x0085> roiobservationlabel; + roiobservationlabel.SetFromDataSet( nestedds ); + gdcm::Attribute<0x3006,0x00a4> rtroiinterpretedtype; + rtroiinterpretedtype.SetFromDataSet( nestedds ); + gdcm::Attribute<0x3006,0x00a6> roiinterpreter; + roiinterpreter.SetFromDataSet( nestedds ); + this->RTStructSetProperties-> + AddStructureSetROIObservation( referencedroinumber.GetValue(), + observationnumber.GetValue(), + rtroiinterpretedtype.GetValue(), + roiinterpreter.GetValue(), + roiobservationlabel.GetValue() + ); + } + + return 1; +} + +int vtkGDCMPolyDataReader::RequestData_HemodynamicWaveformStorage(gdcm::Reader const &reader, + vtkInformationVector *outputVector) +{ + const gdcm::DataSet& ds = reader.GetFile().GetDataSet(); + // (5400,0100) SQ (Sequence with undefined length #=1) # u/l, 1 WaveformSequence + gdcm::Tag twsq(0x5400,0x0100); + if( !ds.FindDataElement( twsq) ) + { + return 0; + } + const gdcm::DataElement &wsq = ds.GetDataElement( twsq ); + //std::cout << wsq << std::endl; + //const gdcm::SequenceOfItems *sqi = wsq.GetSequenceOfItems(); + gdcm::SmartPointer sqi = wsq.GetValueAsSQ(); + if( !sqi || !sqi->GetNumberOfItems() ) + { + return 0; + } + + const gdcm::Item & item = sqi->GetItem(1); // Item start at #1 + const gdcm::DataSet& nestedds = item.GetNestedDataSet(); + + // (5400,1004) US 16 # 2, 1 WaveformBitsAllocated + gdcm::Tag twba(0x5400,0x1004); + if( !nestedds.FindDataElement( twba ) ) + { + return 0; + } + const gdcm::DataElement &wba= nestedds.GetDataElement( twba ); + (void)wba; + + //std::cout << wba << std::endl; + // (5400,1006) CS [SS] # 2, 1 WaveformSampleInterpretation + // (5400,1010) OW 00ba\0030\ff76\ff8b\00a2\ffd3\ffae\ff50\0062\00c4\011e\00c2\00ba... # 57600, 1 WaveformData + gdcm::Tag twd(0x5400,0x1010); + if( !nestedds.FindDataElement( twd ) ) + { + return 0; + } + const gdcm::DataElement &wd = nestedds.GetDataElement( twd ); + const gdcm::ByteValue *bv = wd.GetByteValue(); + size_t len = bv->GetLength(); + int16_t *p = (int16_t*)bv; + + // get the info object + int pd = 0; + vtkInformation *outInfo1 = outputVector->GetInformationObject(pd); + + // get the ouptut + vtkPolyData *output = vtkPolyData::SafeDownCast( + outInfo1->Get(vtkDataObject::DATA_OBJECT())); + + vtkPoints *newPts = vtkPoints::New(); + size_t npts = len / 2; + //npts = 10; // DEBUG ! + for(size_t i = 0; i < npts; ++i ) + { + float x[3]; + x[0] = (float)p[i] / 8800; + //std::cout << p[i] << std::endl; + x[1] = (float)i; + x[2] = 0; + vtkIdType ptId = newPts->InsertNextPoint( x ); + (void)ptId; + } + output->SetPoints(newPts); + newPts->Delete(); + + vtkCellArray* lines = vtkCellArray::New(); + for ( int i = 0; i < newPts->GetNumberOfPoints() - 1; ++i ) + { + vtkIdType topol[2]; + topol[0] = i; + topol[1] = i+1; + lines->InsertNextCell( 2, topol ); + } + + output->SetLines(lines); + lines->Delete(); + output->BuildCells(); + //output->GetCellData()->SetScalars(scalars); + //scalars->Delete(); + + return 1; +} + +//---------------------------------------------------------------------------- +int vtkGDCMPolyDataReader::RequestData( + vtkInformation *vtkNotUsed(request), + vtkInformationVector **vtkNotUsed(inputVector), + vtkInformationVector *outputVector) +{ + vtkInformation *outInfo = outputVector->GetInformationObject(0); + //vtkPoints *newPts, *mergedPts; + //vtkCellArray *newPolys, *mergedPolys; + //vtkFloatArray *newScalars=0, *mergedScalars=0; + + // All of the data in the first piece. + if (outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER()) > 0) + { + return 0; + } + + if ( !this->FileName || !*this->FileName ) + { + vtkErrorMacro(<<"A FileName must be specified."); + return 0; + } + + gdcm::Reader reader; + reader.SetFileName( this->FileName ); + if( !reader.Read() ) + { + return 0; + } + + gdcm::MediaStorage ms; + ms.SetFromFile( reader.GetFile() ); + + int ret; + if( ms == gdcm::MediaStorage::RTStructureSetStorage ) + { + ret = this->RequestData_RTStructureSetStorage(reader, outputVector); + } + else if( ms == gdcm::MediaStorage::HemodynamicWaveformStorage) + { + ret = this->RequestData_HemodynamicWaveformStorage(reader, outputVector); + } + else + { + // not handled assume error + ret = 0; + } + + return ret; +} + +int vtkGDCMPolyDataReader::RequestInformation_RTStructureSetStorage(gdcm::Reader const & reader) +{ + const gdcm::DataSet& ds = reader.GetFile().GetDataSet(); + // (3006,0020) SQ (Sequence with explicit length #=4) # 370, 1 StructureSetROISequence + gdcm::Tag tssroisq(0x3006,0x0020); + if( !ds.FindDataElement( tssroisq ) ) + { + return 0; + } + + const gdcm::DataElement &ssroisq = ds.GetDataElement( tssroisq ); + //const gdcm::SequenceOfItems *sqi = ssroisq.GetSequenceOfItems(); + gdcm::SmartPointer sqi = ssroisq.GetValueAsSQ(); + if( !sqi || !sqi->GetNumberOfItems() ) + { + return 0; + } + size_t npds = sqi->GetNumberOfItems(); + + //std::cout << "Nb pd:" << npds << std::endl; + this->SetNumberOfOutputPorts( (int)npds ); + + // Allocate + for(unsigned int i = 1; i < npds; ++i) // first output is allocated for us + { + vtkPolyData *output2 = vtkPolyData::New(); + this->GetExecutive()->SetOutputData(i, output2); + output2->Delete(); + } + return 1; +} + +int vtkGDCMPolyDataReader::RequestInformation_HemodynamicWaveformStorage(gdcm::Reader const & ) +{ + return 1; +} + +//---------------------------------------------------------------------------- +int vtkGDCMPolyDataReader::RequestInformation( + vtkInformation *vtkNotUsed(request), + vtkInformationVector **vtkNotUsed(inputVector), + vtkInformationVector *vtkNotUsed(outputVector)) +{ + // get the info object +// vtkInformation *outInfo = outputVector->GetInformationObject(0); +// +// outInfo->Set(vtkStreamingDemandDrivenPipeline::MAXIMUM_NUMBER_OF_PIECES(), +// -1); + gdcm::Reader reader; + reader.SetFileName( this->FileName ); + if( !reader.Read() ) + { + return 0; + } + + gdcm::MediaStorage ms; + ms.SetFromFile( reader.GetFile() ); + + int ret; + if( ms == gdcm::MediaStorage::RTStructureSetStorage ) + { + ret = this->RequestInformation_RTStructureSetStorage(reader); + } + else if( ms == gdcm::MediaStorage::HemodynamicWaveformStorage) + { + ret = this->RequestInformation_HemodynamicWaveformStorage(reader); + } + else + { + // not handled assume error + ret = 0; + } + + if( ret ) + { + // Ok let's fill in the 'extra' info: + this->FillMedicalImageInformation(reader); + } + + return ret; +} + + +//---------------------------------------------------------------------------- +void vtkGDCMPolyDataReader::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os,indent); + + os << indent << "File Name: " + << (this->FileName ? this->FileName : "(none)") << "\n"; + + +} diff --git a/gdcm/Utilities/VTK/vtkGDCMPolyDataReader.h b/gdcm/Utilities/VTK/vtkGDCMPolyDataReader.h new file mode 100644 index 0000000..251cacb --- /dev/null +++ b/gdcm/Utilities/VTK/vtkGDCMPolyDataReader.h @@ -0,0 +1,84 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +// .NAME vtkGDCMPolyDataReader - read DICOM PolyData files (Contour Data...) +// .SECTION Description +// For now only support RTSTRUCT (RT Structure Set Storage) +// .SECTION TODO +// Need to do the same job for DVH Sequence/DVH Data... +// .SECTION Warning +// When using vtkGDCMPolyDataReader in conjonction with vtkGDCMImageReader +// it is *required* that FileLowerLeft is set to ON as coordinate system +// would be inconsistent in between the two data structures. +// +// .SECTION See Also +// vtkGDCMImageReader vtkGDCMPolyDataWriter vtkRTStructSetProperties + + +#ifndef VTKGDCMPOLYDATAREADER_H +#define VTKGDCMPOLYDATAREADER_H + +#include "vtkPolyDataAlgorithm.h" + +class vtkMedicalImageProperties; +class vtkRTStructSetProperties; +//BTX +namespace gdcm { class Reader; } +//ETX +class VTK_EXPORT vtkGDCMPolyDataReader : public vtkPolyDataAlgorithm +{ +public: + static vtkGDCMPolyDataReader *New(); + vtkTypeRevisionMacro(vtkGDCMPolyDataReader,vtkPolyDataAlgorithm); + virtual void PrintSelf(ostream& os, vtkIndent indent); + + // Description: + // Set/Get the filename of the file to be read + vtkSetStringMacro(FileName); + vtkGetStringMacro(FileName); + + // Description: + // Get the medical image properties object + vtkGetObjectMacro(MedicalImageProperties, vtkMedicalImageProperties); + + vtkGetObjectMacro(RTStructSetProperties, vtkRTStructSetProperties); + +protected: + vtkGDCMPolyDataReader(); + ~vtkGDCMPolyDataReader(); + + char *FileName; + vtkMedicalImageProperties *MedicalImageProperties; + vtkRTStructSetProperties *RTStructSetProperties; +//BTX + void FillMedicalImageInformation(const gdcm::Reader &reader); +//ETX + + int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); + int RequestInformation( + vtkInformation *vtkNotUsed(request), + vtkInformationVector **vtkNotUsed(inputVector), + vtkInformationVector *outputVector); +//BTX + int RequestInformation_RTStructureSetStorage(gdcm::Reader const & reader); + int RequestData_RTStructureSetStorage(gdcm::Reader const &reader, vtkInformationVector *outputVector); + int RequestInformation_HemodynamicWaveformStorage(gdcm::Reader const & reader); + int RequestData_HemodynamicWaveformStorage(gdcm::Reader const &reader, vtkInformationVector *outputVector); +//ETX + +private: + vtkGDCMPolyDataReader(const vtkGDCMPolyDataReader&); // Not implemented. + void operator=(const vtkGDCMPolyDataReader&); // Not implemented. +}; + +#endif diff --git a/gdcm/Utilities/VTK/vtkGDCMPolyDataWriter.cxx b/gdcm/Utilities/VTK/vtkGDCMPolyDataWriter.cxx new file mode 100644 index 0000000..5a908fb --- /dev/null +++ b/gdcm/Utilities/VTK/vtkGDCMPolyDataWriter.cxx @@ -0,0 +1,791 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkGDCMPolyDataWriter.h" + +#include "vtkObjectFactory.h" +#include "vtkInformation.h" +#include "vtkDoubleArray.h" +#include "vtkPointData.h" +#include "vtkInformationVector.h" +#include "vtkPolyData.h" +#include "vtkStreamingDemandDrivenPipeline.h" +#include "vtkFloatArray.h" +#include "vtkCellArray.h" +#include "vtkCellData.h" +#include "vtkErrorCode.h" +#include "vtkMedicalImageProperties.h" +#include "vtkRTStructSetProperties.h" +#include "gdcmSystem.h" + +#include "gdcmWriter.h" +#include "gdcmUIDs.h" +#include "gdcmUIDGenerator.h" +#include "gdcmSmartPointer.h" +#include "gdcmAttribute.h" +#include "gdcmSmartPointer.h" +#include "gdcmSequenceOfItems.h" +#include "gdcmAnonymizer.h" +#include "gdcmIPPSorter.h" +#include "gdcmAttribute.h" +#include "gdcmDirectoryHelper.h" + +vtkCxxRevisionMacro(vtkGDCMPolyDataWriter, "$Revision: 1.74 $") +vtkStandardNewMacro(vtkGDCMPolyDataWriter) +vtkCxxSetObjectMacro(vtkGDCMPolyDataWriter,MedicalImageProperties,vtkMedicalImageProperties) +vtkCxxSetObjectMacro(vtkGDCMPolyDataWriter,RTStructSetProperties,vtkRTStructSetProperties) + +//---------------------------------------------------------------------------- +vtkGDCMPolyDataWriter::vtkGDCMPolyDataWriter() +{ + this->SetNumberOfInputPorts(1); + this->MedicalImageProperties = vtkMedicalImageProperties::New(); + this->RTStructSetProperties = vtkRTStructSetProperties::New(); +} + +//---------------------------------------------------------------------------- +vtkGDCMPolyDataWriter::~vtkGDCMPolyDataWriter() +{ + this->MedicalImageProperties->Delete(); + this->RTStructSetProperties->Delete(); +} + +static void SetStringValueFromTag(const char *s, const gdcm::Tag& t, gdcm::Anonymizer & ano) +{ + if( s && *s ) + { +#if 0 + gdcm::DataElement de( t ); + de.SetByteValue( s, strlen( s ) ); + const gdcm::Global& g = gdcm::Global::GetInstance(); + const gdcm::Dicts &dicts = g.GetDicts(); + // FIXME: we know the tag at compile time we could save some time + // Using the static dict instead of the run-time one: + const gdcm::DictEntry &dictentry = dicts.GetDictEntry( t ); + de.SetVR( dictentry.GetVR() ); + ds.Insert( de ); +#else + ano.Replace(t, s); +#endif + } +} + +using namespace gdcm; + +//---------------------------------------------------------------------------- +void vtkGDCMPolyDataWriter::WriteData() +{ + if ( this->FileName == NULL) + { + vtkErrorMacro(<< "Please specify FileName to write"); + this->SetErrorCode(vtkErrorCode::NoFileNameError); + return; + } + Writer writer; + writer.SetFileName( this->FileName ); + File &file = writer.GetFile(); + + this->WriteRTSTRUCTInfo(file); + + int numInputs = this->GetNumberOfInputPorts(); + for(int input = 0; input < numInputs; ++input ) + { + this->WriteRTSTRUCTData(file, input); + } + + if( !writer.Write() ) + { + vtkErrorMacro(<< "Could not write"); + this->SetErrorCode(vtkErrorCode::FileFormatError); + return; + } + +} + +//---------------------------------------------------------------------------- +void vtkGDCMPolyDataWriter::WriteRTSTRUCTInfo(gdcm::File &file) +{ + DataSet& ds = file.GetDataSet(); +{ + const Tag sisq(0x3006,0x0039); + DataElement de( sisq ); + de.SetVR( VR::SQ ); + SmartPointer sqi1 = 0; + sqi1 = new SequenceOfItems; + de.SetValue( *sqi1 ); + de.SetVLToUndefined(); + ds.Insert( de ); +} + + UIDGenerator uid; + + { + const char *sop = uid.Generate(); + DataElement de( Tag(0x0008,0x0018) ); + VL::Type strlenSOP = (VL::Type) strlen(sop); + de.SetByteValue( sop, strlenSOP ); + de.SetVR( Attribute<0x0008, 0x0018>::GetVR() ); + ds.ReplaceEmpty( de ); + } + { + //this is incorrect. + //the study MUST be the same as the image from which this object is derived. +// const char *study = uid.Generate(); +// DataElement de( Tag(0x0020,0x000d) ); +// VL::Type strlenStudy= (VL::Type)strlen(study); +// de.SetByteValue( study, strlenStudy ); +// de.SetVR( Attribute<0x0020, 0x000d>::GetVR() ); +// ds.ReplaceEmpty( de ); + } + { + const char *series = uid.Generate(); + DataElement de( Tag(0x0020,0x000e) ); + VL::Type strlenSeries= (VL::Type)strlen(series); + de.SetByteValue( series, strlenSeries ); + de.SetVR( Attribute<0x0020, 0x000e>::GetVR() ); + ds.ReplaceEmpty( de ); + } + + FileMetaInformation &fmi = file.GetHeader(); + TransferSyntax ts = TransferSyntax::ImplicitVRLittleEndian; + { + const char *tsuid = TransferSyntax::GetTSString( ts ); + DataElement de( Tag(0x0002,0x0010) ); + VL::Type strlenTSUID = (VL::Type)strlen(tsuid); + de.SetByteValue( tsuid, strlenTSUID ); + de.SetVR( Attribute<0x0002, 0x0010>::GetVR() ); + fmi.Replace( de ); + fmi.SetDataSetTransferSyntax(ts); + } + MediaStorage ms = MediaStorage::RTStructureSetStorage ; + const char* msstr = MediaStorage::GetMSString(ms); + { + DataElement de( Tag(0x0008, 0x0016 ) ); + VL::Type strlenMsstr = (VL::Type)strlen(msstr); + de.SetByteValue( msstr, strlenMsstr); + de.SetVR( Attribute<0x0008, 0x0016>::GetVR() ); + ds.Insert( de ); + } + + int year, month, day; + gdcm::Anonymizer ano; + ano.SetFile( file ); + + SetStringValueFromTag(this->RTStructSetProperties->GetStructureSetLabel(), gdcm::Tag(0x3006,0x0002), ano); + SetStringValueFromTag(this->RTStructSetProperties->GetStructureSetName(), gdcm::Tag(0x3006,0x0004), ano); + SetStringValueFromTag(this->RTStructSetProperties->GetStructureSetDate(), gdcm::Tag(0x3006,0x0008), ano); + SetStringValueFromTag(this->RTStructSetProperties->GetStructureSetTime(), gdcm::Tag(0x3006,0x0009), ano); + SetStringValueFromTag(this->RTStructSetProperties->GetSOPInstanceUID(), gdcm::Tag(0x0008,0x0018), ano); + SetStringValueFromTag(this->RTStructSetProperties->GetStudyInstanceUID(), gdcm::Tag(0x0020,0x000d), ano); + SetStringValueFromTag(this->RTStructSetProperties->GetSeriesInstanceUID(), gdcm::Tag(0x0020,0x000e), ano); + +{ + SmartPointer sqi; + sqi = new SequenceOfItems; + vtkIdType n = this->RTStructSetProperties->GetNumberOfReferencedFrameOfReferences(); + for( vtkIdType id = 0; id < n; ++id ) + { + const char *sopclass = this->RTStructSetProperties->GetReferencedFrameOfReferenceClassUID(id); + const char *instanceuid = this->RTStructSetProperties->GetReferencedFrameOfReferenceInstanceUID(id); + Item item; + item.SetVLToUndefined(); + DataSet &subds = item.GetNestedDataSet(); +{ + Attribute<0x0008,0x1150> at; + at.SetValue( sopclass ); + subds.Insert( at.GetAsDataElement() ); +} +{ + Attribute<0x0008,0x1155> at; + at.SetValue( instanceuid ); + subds.Insert( at.GetAsDataElement() ); +} + + sqi->AddItem( item ); + } + + DataElement de1( Tag(0x3006,0x0010) ); + de1.SetVR( VR::SQ ); + SmartPointer sqi1 = new SequenceOfItems; + de1.SetValue( *sqi1 ); + de1.SetVLToUndefined(); + ds.Insert( de1 ); + + Item item1; + item1.SetVLToUndefined(); + DataSet &ds2 = item1.GetNestedDataSet(); + + gdcm::Attribute<0x0020,0x052> frameofreferenceuid; + if( this->RTStructSetProperties->GetReferenceFrameOfReferenceUID() ) + frameofreferenceuid.SetValue( + this->RTStructSetProperties->GetReferenceFrameOfReferenceUID() ); + ds2.Insert( frameofreferenceuid.GetAsDataElement() ); + + DataElement de2( Tag(0x3006,0x0012) ); + de2.SetVR( VR::SQ ); + SmartPointer sqi2 = new SequenceOfItems; + de2.SetValue( *sqi2 ); + de2.SetVLToUndefined(); + ds2.Insert( de2 ); + + Item item2; + item2.SetVLToUndefined(); + DataSet &ds3 = item2.GetNestedDataSet(); + + Attribute<0x0008,0x1150> refsopclassuid; + const char *rtuid = gdcm::UIDs::GetUIDString( + gdcm::UIDs::RTStructureSetStorage); + refsopclassuid.SetValue ( rtuid ); + ds3.Insert( refsopclassuid.GetAsDataElement() ); + Attribute<0x0008,0x1155> refsopinstuid; + if( this->RTStructSetProperties->GetStudyInstanceUID() ) + refsopinstuid.SetValue ( this->RTStructSetProperties->GetStudyInstanceUID() ); + ds3.Insert( refsopinstuid.GetAsDataElement() ); + + DataElement de3( Tag(0x3006,0x0014) ); + de3.SetVR( VR::SQ ); + SmartPointer sqi3 = new SequenceOfItems; + de3.SetValue( *sqi3 ); + de3.SetVLToUndefined(); + ds3.Insert( de3 ); + + Item item3; + item3.SetVLToUndefined(); + DataSet &ds4 = item3.GetNestedDataSet(); + + gdcm::Attribute<0x0020,0x000e> seriesinstanceuid; + if ( this->RTStructSetProperties->GetReferenceSeriesInstanceUID() ) + seriesinstanceuid.SetValue( + this->RTStructSetProperties->GetReferenceSeriesInstanceUID() ); + ds4.Insert( seriesinstanceuid.GetAsDataElement() ); + + DataElement de4( Tag(0x3006,0x0016) ); + de4.SetVR( VR::SQ ); + //SmartPointer sqi4 = new SequenceOfItems; + de4.SetValue( *sqi ); + de4.SetVLToUndefined(); + ds4.Insert( de4 ); + + //Item item4; + //item4.SetVLToUndefined(); + //DataSet &ds5 = item4.GetNestedDataSet(); + + //sqi4->AddItem( item4 ); + + sqi3->AddItem( item3 ); + + sqi2->AddItem( item2 ); + + sqi1->AddItem( item1 ); +} +{ + SmartPointer sqi; + sqi = new SequenceOfItems; + SmartPointer sqiobs; + sqiobs = new SequenceOfItems; + vtkIdType n = this->RTStructSetProperties->GetNumberOfStructureSetROIs(); + for( vtkIdType id = 0; id < n; ++id ) + { + int roinumber = this->RTStructSetProperties->GetStructureSetROINumber(id); + const char *refframerefuid = this->RTStructSetProperties->GetStructureSetROIRefFrameRefUID(id); + const char *roiname = this->RTStructSetProperties->GetStructureSetROIName(id); + const char *roigenalgo = this->RTStructSetProperties->GetStructureSetROIGenerationAlgorithm(id); + const char *roidesc = this->RTStructSetProperties->GetStructureSetROIDescription(id); + Item item; + item.SetVLToUndefined(); + DataSet &subds = item.GetNestedDataSet(); + + gdcm::Attribute<0x3006,0x0022> atroinumber; + atroinumber.SetValue( roinumber ); + subds.Insert( atroinumber.GetAsDataElement() ); + + gdcm::Attribute<0x3006,0x0024> atrefframeuid; + atrefframeuid.SetValue( refframerefuid ); + subds.Insert( atrefframeuid.GetAsDataElement() ); + + gdcm::Attribute<0x3006,0x0026> atroiname; + atroiname.SetValue( roiname ); + subds.Insert( atroiname.GetAsDataElement() ); + + if( roidesc && *roidesc ) + { + gdcm::Attribute<0x3006,0x0028> atroidesc; + atroidesc.SetValue( roidesc ); + subds.Insert( atroidesc.GetAsDataElement() ); + } + + gdcm::Attribute<0x3006,0x0036> atroigenalg; + atroigenalg.SetValue( roigenalgo ); + subds.Insert( atroigenalg.GetAsDataElement() ); + + // do the obs stuff + Item itemobs; + itemobs.SetVLToUndefined(); + DataSet &subdsobs = itemobs.GetNestedDataSet(); + + int observationnumber = this->RTStructSetProperties->GetStructureSetObservationNumber(id); + gdcm::Attribute<0x3006,0x0082> atobservationnumber; + atobservationnumber.SetValue( observationnumber ); + subdsobs.Insert( atobservationnumber.GetAsDataElement() ); + + gdcm::Attribute<0x3006,0x0084> atreferencedroinumber; + atreferencedroinumber.SetValue( roinumber ); + subdsobs.Insert( atreferencedroinumber.GetAsDataElement() ); + + const char *roiobservationlabel = this->RTStructSetProperties->GetStructureSetROIObservationLabel(id); + if( roiobservationlabel && *roiobservationlabel ) + { + gdcm::Attribute<0x3006,0x0085> atroiobservationlabel; + atroiobservationlabel.SetValue( roiobservationlabel ); + subdsobs.Insert( atroiobservationlabel.GetAsDataElement() ); + } + + const char *rtroiinterpretedtype = this->RTStructSetProperties->GetStructureSetRTROIInterpretedType(id); + gdcm::Attribute<0x3006,0x00a4> atrtroiinterpretedtype; + atrtroiinterpretedtype.SetValue( rtroiinterpretedtype ); + subdsobs.Insert( atrtroiinterpretedtype.GetAsDataElement() ); + + gdcm::Attribute<0x3006,0x00a6> atroiinterpreter; + //atroiinterpreter.SetValue( rtroiinterpretedtype ); + subdsobs.Insert( atroiinterpreter.GetAsDataElement() ); + + sqiobs->AddItem( itemobs ); + sqi->AddItem( item ); + } + DataElement de1( Tag(0x3006,0x0020) ); + de1.SetVR( VR::SQ ); + de1.SetValue( *sqi ); + de1.SetVLToUndefined(); + ds.Insert( de1 ); + + DataElement de2( Tag(0x3006,0x0080) ); + de2.SetVR( VR::SQ ); + de2.SetValue( *sqiobs ); + de2.SetVLToUndefined(); + ds.Insert( de2 ); +} + + // For ex: DICOM (0010,0010) = DOE,JOHN + SetStringValueFromTag(this->MedicalImageProperties->GetPatientName(), gdcm::Tag(0x0010,0x0010), ano); + // For ex: DICOM (0010,0020) = 1933197 + SetStringValueFromTag( this->MedicalImageProperties->GetPatientID(), gdcm::Tag(0x0010,0x0020), ano); + // For ex: DICOM (0010,1010) = 031Y + SetStringValueFromTag( this->MedicalImageProperties->GetPatientAge(), gdcm::Tag(0x0010,0x1010), ano); + // For ex: DICOM (0010,0040) = M + SetStringValueFromTag( this->MedicalImageProperties->GetPatientSex(), gdcm::Tag(0x0010,0x0040), ano); + // For ex: DICOM (0010,0030) = 19680427 + SetStringValueFromTag( this->MedicalImageProperties->GetPatientBirthDate(), gdcm::Tag(0x0010,0x0030), ano); +#if ( VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION > 0 ) + // For ex: DICOM (0008,0020) = 20030617 + if( vtkMedicalImageProperties::GetDateAsFields( this->MedicalImageProperties->GetStudyDate(), year, month, day ) ) + SetStringValueFromTag( this->MedicalImageProperties->GetStudyDate(), gdcm::Tag(0x0008,0x0020), ano); +#endif + // For ex: DICOM (0008,0022) = 20030617 + SetStringValueFromTag( this->MedicalImageProperties->GetAcquisitionDate(), gdcm::Tag(0x0008,0x0022), ano); +#if ( VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION > 0 ) + // For ex: DICOM (0008,0030) = 162552.0705 or 230012, or 0012 +#if ( VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION > 4 ) + int hour, minute, second; + if( vtkMedicalImageProperties::GetTimeAsFields( this->MedicalImageProperties->GetStudyTime(), hour, minute, second ) ) +#endif + SetStringValueFromTag( this->MedicalImageProperties->GetStudyTime(), gdcm::Tag(0x0008,0x0030), ano); +#endif + // For ex: DICOM (0008,0032) = 162552.0705 or 230012, or 0012 + SetStringValueFromTag( this->MedicalImageProperties->GetAcquisitionTime(), gdcm::Tag(0x0008,0x0032), ano); + // For ex: DICOM (0008,0023) = 20030617 + SetStringValueFromTag( this->MedicalImageProperties->GetImageDate(), gdcm::Tag(0x0008,0x0023), ano); + // For ex: DICOM (0008,0033) = 162552.0705 or 230012, or 0012 + SetStringValueFromTag( this->MedicalImageProperties->GetImageTime(), gdcm::Tag(0x0008,0x0033), ano); + // For ex: DICOM (0020,0013) = 1 + SetStringValueFromTag( this->MedicalImageProperties->GetImageNumber(), gdcm::Tag(0x0020,0x0013), ano); + // For ex: DICOM (0020,0011) = 902 + SetStringValueFromTag( this->MedicalImageProperties->GetSeriesNumber(), gdcm::Tag(0x0020,0x0011), ano); + // For ex: DICOM (0008,103e) = SCOUT + SetStringValueFromTag( this->MedicalImageProperties->GetSeriesDescription(), gdcm::Tag(0x0008,0x103e), ano); + // For ex: DICOM (0020,0010) = 37481 + SetStringValueFromTag( this->MedicalImageProperties->GetStudyID(), gdcm::Tag(0x0020,0x0010), ano); + // For ex: DICOM (0008,1030) = BRAIN/C-SP/FACIAL + SetStringValueFromTag( this->MedicalImageProperties->GetStudyDescription(), gdcm::Tag(0x0008,0x1030), ano); + // For ex: DICOM (0008,0060)= CT + SetStringValueFromTag( this->MedicalImageProperties->GetModality(), gdcm::Tag(0x0008,0x0060), ano); + // For ex: DICOM (0008,0070) = Siemens + SetStringValueFromTag( this->MedicalImageProperties->GetManufacturer(), gdcm::Tag(0x0008,0x0070), ano); + // For ex: DICOM (0008,1090) = LightSpeed QX/i + SetStringValueFromTag( this->MedicalImageProperties->GetManufacturerModelName(), gdcm::Tag(0x0008,0x1090), ano); + // For ex: DICOM (0008,1010) = LSPD_OC8 + SetStringValueFromTag( this->MedicalImageProperties->GetStationName(), gdcm::Tag(0x0008,0x1010), ano); + // For ex: DICOM (0008,0080) = FooCity Medical Center + SetStringValueFromTag( this->MedicalImageProperties->GetInstitutionName(), gdcm::Tag(0x0008,0x0080), ano); + // For ex: DICOM (0018,1210) = Bone + SetStringValueFromTag( this->MedicalImageProperties->GetConvolutionKernel(), gdcm::Tag(0x0018,0x1210), ano); + // For ex: DICOM (0018,0050) = 0.273438 + SetStringValueFromTag( this->MedicalImageProperties->GetSliceThickness(), gdcm::Tag(0x0018,0x0050), ano); + // For ex: DICOM (0018,0060) = 120 + SetStringValueFromTag( this->MedicalImageProperties->GetKVP(), gdcm::Tag(0x0018,0x0060), ano); + // For ex: DICOM (0018,1120) = 15 + SetStringValueFromTag( this->MedicalImageProperties->GetGantryTilt(), gdcm::Tag(0x0018,0x1120), ano); + // For ex: DICOM (0018,0081) = 105 + SetStringValueFromTag( this->MedicalImageProperties->GetEchoTime(), gdcm::Tag(0x0018,0x0081), ano); + // For ex: DICOM (0018,0091) = 35 + SetStringValueFromTag( this->MedicalImageProperties->GetEchoTrainLength(), gdcm::Tag(0x0018,0x0091), ano); + // For ex: DICOM (0018,0080) = 2040 + SetStringValueFromTag( this->MedicalImageProperties->GetRepetitionTime(), gdcm::Tag(0x0018,0x0080), ano); + // For ex: DICOM (0018,1150) = 5 + SetStringValueFromTag( this->MedicalImageProperties->GetExposureTime(), gdcm::Tag(0x0018,0x1150), ano); + // For ex: DICOM (0018,1151) = 400 + SetStringValueFromTag( this->MedicalImageProperties->GetXRayTubeCurrent(), gdcm::Tag(0x0018,0x1151), ano); + // For ex: DICOM (0018,1152) = 114 + SetStringValueFromTag( this->MedicalImageProperties->GetExposure(), gdcm::Tag(0x0018,0x1152), ano); + +} + +//---------------------------------------------------------------------------- +void vtkGDCMPolyDataWriter::WriteRTSTRUCTData(gdcm::File &file, int pdidx ) +{ + vtkPolyData *input = this->GetInput(pdidx); + assert( input ); + vtkPoints *pts; + vtkCellArray *polys; + + polys = input->GetPolys(); + vtkCellArray* lines = input->GetLines(); + pts = input->GetPoints(); + vtkDataArray *scalars = input->GetCellData()->GetScalars(); + vtkDoubleArray *darray = vtkDoubleArray::SafeDownCast( scalars ); + vtkFloatArray *farray = vtkFloatArray::SafeDownCast( scalars ); + + if (pts == NULL || polys == NULL || lines == NULL) + { + vtkWarningMacro(<<"No data to write!");//should be a warning, not an error, because + //it's entirely possible to have a blank ROI + //return;//ok, you have to put the observation here, even if it's blank + //if it's blank, the color and so forth are still defined. Otherwise, + //the observation will be incomplete. + } + +/* +(3006,0039) ?? (SQ) # u/l,1 ROI Contour Sequence + (fffe,e000) na (Item with undefined length) + (3006,002a) ?? (IS) [220\160\120 ] # 12,3 ROI Display Color + (3006,0040) ?? (SQ) # u/l,1 Contour Sequence + (fffe,e000) na (Item with undefined length) + (3006,0016) ?? (SQ) # u/l,1 Contour Image Sequence + (fffe,e000) na (Item with undefined length) + (0008,1150) ?? (UI) [1.2.840.10008.5.1.4.1.1.2] # 26,1 Referenced SOP Class UID + (0008,1155) ?? (UI) [1.3.6.1.4.1.22213.1.1396.148] # 28,1 Referenced SOP Instance UID + (fffe,e00d) + (fffe,e0dd) + (3006,0042) ?? (CS) [CLOSED_PLANAR ] # 14,1 Contour Geometric Type + (3006,0046) ?? (IS) [139 ] # 4,1 Number of Contour Points + (3006,0050) ?? (DS) [-209.81171875\-392.41171875\...] # 5004,3-3n Contour Data + (fffe,e00d) + +*/ + SmartPointer sqi; + sqi = new SequenceOfItems; + + vtkIdType npts = 0; + vtkIdType *indx = 0; + double v[3]; + unsigned int cellnum = 0; + + //choose to use either polys or lines + //the result of vtk marching cubes->stripper->appendpolydata is a set of lines, + //not polys, so favor that one for now. + //choose by the number of polys/lines available. + vtkCellArray* theCells = lines; + if (!lines || lines->GetNumberOfCells() == 0){ + theCells = polys; + } + + std::vector cellpoints; + for (theCells->InitTraversal(); theCells->GetNextCell(npts,indx); cellnum++ ){ + cellpoints.resize(0); + for(vtkIdType index = 0; index < npts; ++index){ + pts->GetPoint(indx[index],v); + //precision problems are _definitely_ here by this point + //this a crude hack to the get the 9999's under control, + //or pollution by switching from doubles to floats and back again + //cellpoints.push_back( (double)((int)(v[0]*10000.0))/10000.0 ); + //cellpoints.push_back( (double)((int)(v[1]*10000.0))/10000.0 ); + //cellpoints.push_back( (double)((int)(v[2]*10000.0))/10000.0 ); + cellpoints.push_back( v[0] ); + cellpoints.push_back( v[1] ); + cellpoints.push_back( v[2 ]); + } + Item item0; + item0.SetVLToUndefined(); + DataSet &subds0 = item0.GetNestedDataSet(); + Attribute<0x3006,0x0050> at; + at.SetValues( &cellpoints[0], (unsigned int)cellpoints.size(), false ); + subds0.Insert( at.GetAsDataElement() ); + + Attribute<0x3006,0x0046> numcontpoints; + numcontpoints.SetValue( (int)npts ); + subds0.Insert( numcontpoints.GetAsDataElement() ); + Attribute<0x3006,0x0042> contgeotype; + contgeotype.SetValue( "CLOSED_PLANAR " ); + subds0.Insert( contgeotype.GetAsDataElement() ); + + SmartPointer thesqi = new SequenceOfItems; + { + Item item; + item.SetVLToUndefined(); + DataSet &subds = item.GetNestedDataSet(); + + gdcm::Attribute<0x0008,0x1150> classat; + classat.SetValue ( this->RTStructSetProperties-> + GetContourReferencedFrameOfReferenceClassUID( pdidx, cellnum )); + subds.Insert( classat.GetAsDataElement() ); + gdcm::Attribute<0x0008,0x1155> instat; + instat.SetValue ( this->RTStructSetProperties-> + GetContourReferencedFrameOfReferenceInstanceUID( pdidx, cellnum )); + subds.Insert( instat.GetAsDataElement() ); + thesqi->AddItem( item ); + } + + DataElement contimsq = DataElement( Tag(0x3006,0x0016) ); + contimsq.SetVR( VR::SQ ); + contimsq.SetValue( *thesqi ); + contimsq.SetVLToUndefined(); + subds0.Insert( contimsq ); + + + sqi->AddItem( item0 ); + } + DataSet& ds = file.GetDataSet(); +{ + const Tag sisq(0x3006,0x0039); + SmartPointer sqi1 = 0; + sqi1 = ds.GetDataElement( sisq ).GetValueAsSQ(); + assert( sqi1 ); + + Item item; + item.SetVLToUndefined(); + DataSet &subds = item.GetNestedDataSet(); + + gdcm::Attribute<0x3006,0x0084> referencedroinumber; + //referencedroinumber.SetValue ( pdidx ); + referencedroinumber.SetValue( this->RTStructSetProperties->GetStructureSetROINumber(pdidx) ); + subds.Insert( referencedroinumber.GetAsDataElement() ); + + //(3006,002a) IS [220\160\120] # 12, 3 ROIDisplayColor + gdcm::Attribute<0x3006,0x002a> roidispcolor; + int32_t intcolor[3] = {0,0,0}; + //assert( darray || farray ); + if( darray ) + { + double tuple[3]; + darray->GetTupleValue( 0, tuple ); + intcolor[0] = (int32_t)(tuple[0] * 255.); + intcolor[1] = (int32_t)(tuple[1] * 255.); + intcolor[2] = (int32_t)(tuple[2] * 255.); + } + else if( farray ) + { + float ftuple[3]; + farray->GetTupleValue( 0, ftuple ); + intcolor[0] = (int32_t)(ftuple[0] * 255.); + intcolor[1] = (int32_t)(ftuple[1] * 255.); + intcolor[2] = (int32_t)(ftuple[2] * 255.); + } + else + { + vtkDebugMacro( "No color" ); + } + roidispcolor.SetValues( intcolor, 3 ); + subds.Insert( roidispcolor.GetAsDataElement() ); + + if( sqi->GetNumberOfItems() ) + { + const Tag sisq2(0x3006,0x0040); + DataElement de2( sisq2 ); + de2.SetVR( VR::SQ ); + de2.SetValue( *sqi ); + de2.SetVLToUndefined(); + subds.Insert( de2 ); + } + + sqi1->AddItem( item ); +} + +} + +//---------------------------------------------------------------------------- +void vtkGDCMPolyDataWriter::SetNumberOfInputPorts(int n) +{ + Superclass::SetNumberOfInputPorts(n); +} + +//---------------------------------------------------------------------------- +void vtkGDCMPolyDataWriter::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os,indent); +} + + +//this function will initialize the contained rtstructset with +//the inputs of the writer and the various extra information +//necessary for writing a complete rtstructset. +//NOTE: inputs must be set BEFORE calling this function! +//NOTE: the number of outputs for the appendpolydata MUST MATCH the organ vectors! +void vtkGDCMPolyDataWriter::InitializeRTStructSet(vtkStdString inDirectory, + vtkStdString inStructLabel, + vtkStdString inStructName, + vtkStringArray* inROINames, + vtkStringArray* inROIAlgorithmName, + vtkStringArray* inROIType) +{ + gdcm::Directory::FilenamesType theCTSeries = + gdcm::DirectoryHelper::GetCTImageSeriesUIDs(inDirectory); + if (theCTSeries.size() > 1) + { + gdcmWarningMacro("More than one CT series detected, only reading series UID: " + << theCTSeries[0]); + } + if (theCTSeries.empty()) + { + gdcmWarningMacro("No CT Series found, trying MR."); + theCTSeries = gdcm::DirectoryHelper::GetMRImageSeriesUIDs(inDirectory); + if (theCTSeries.size() > 1) + { + gdcmWarningMacro("More than one MR series detected, only reading series UID: " + << theCTSeries[0]); + } + if (theCTSeries.empty()) + { + gdcmWarningMacro("No CT or MR series found, throwing."); + return;// false; + } + } + //load the images in the CT series + std::vector theCTDataSets = + gdcm::DirectoryHelper::LoadImageFromFiles(inDirectory, theCTSeries[0]); + if (theCTDataSets.empty()) + { + gdcmWarningMacro("No CT or MR Images loaded, throwing."); + return;// false; + } + + //now, armed with this set of images, we can begin to properly construct the RTStructureSet + vtkRTStructSetProperties* theRTStruct = RTStructSetProperties;//initially, this function was a static construction + //but that doesn't jive with swig wrapping easily + theRTStruct->SetStructureSetLabel(inStructLabel.c_str()); + theRTStruct->SetStructureSetName(inStructName.c_str()); + //theRTStruct->SetSOPInstanceUID(<#const char *_arg#>);//should be autogenerated by the object itself + { + const ByteValue* theValue = theCTDataSets[0].FindNextDataElement(Tag(0x0020,0x000d)).GetByteValue(); + std::string theStringValue(theValue->GetPointer(), theValue->GetLength()); + theRTStruct->SetStudyInstanceUID(theStringValue.c_str()); + } + { + const ByteValue* theValue = theCTDataSets[0].FindNextDataElement(Tag(0x0020,0x000e)).GetByteValue(); + std::string theStringValue(theValue->GetPointer(), theValue->GetLength()); + theRTStruct->SetReferenceSeriesInstanceUID(theStringValue.c_str()); + } + { + const ByteValue* theValue = theCTDataSets[0].FindNextDataElement(Tag(0x0020,0x0052)).GetByteValue(); + std::string theStringValue(theValue->GetPointer(), theValue->GetLength()); + theRTStruct->SetReferenceFrameOfReferenceUID(theStringValue.c_str()); + } + //the series UID should be set automatically, and happen during creation + //set the date and time to be now + + char date[22]; + const size_t datelen = 8; + int res = System::GetCurrentDateTime(date); + assert( res ); + (void)res;//warning removal//causes java wrapping to fail + //the date is the first 8 chars + std::string dateString; + dateString.insert(dateString.begin(), &(date[0]), &(date[datelen])); + theRTStruct->SetStructureSetDate(dateString.c_str()); + std::string timeString; + const size_t timelen = 6; //for now, only need hhmmss + timeString.insert(timeString.begin(), &(date[datelen]), &(date[datelen+timelen])); + theRTStruct->SetStructureSetTime(timeString.c_str()); + + //for each image, we need to fill in the sop class and instance UIDs for the frame of reference + std::string theSOPClassID = DirectoryHelper::GetSOPClassUID(theCTDataSets).c_str(); + for (unsigned long i = 0; i < theCTDataSets.size(); i++) + { + theRTStruct->AddReferencedFrameOfReference(theSOPClassID.c_str(), + DirectoryHelper::RetrieveSOPInstanceUIDFromIndex((int)i,theCTDataSets).c_str()); + } + + //now, we have go to through each vtkPolyData, assign the ROI names per polydata, and then also assign the + //reference SOP instance UIDs on a per-plane basis. + int theNumPorts = GetNumberOfInputPorts(); + for (int j = 0; j < theNumPorts; j++) + { + int contour = j; + theRTStruct->AddStructureSetROI(contour, + theRTStruct->GetReferenceFrameOfReferenceUID(), + inROINames->GetValue(j).c_str(), + inROIAlgorithmName->GetValue(j).c_str()); + + theRTStruct->AddStructureSetROIObservation(contour, + contour, inROIType->GetValue(j).c_str(), ""); + //for each organ, gotta go through and add in the right planes in the + //order that the tuples appear, as well as the colors + //right now, each cell in the vtkpolydata is a contour in an xy plane + //that's what MUST be passed in + vtkPolyData* theData = dynamic_cast(GetInput(j)); + if (theData == NULL) + { + gdcmWarningMacro("theData for input " << j << " is NULL, continuing"); + continue; + } + unsigned int cellnum = 0; + vtkPoints *pts; + vtkCellArray *polys; + vtkIdType npts = 0; + vtkIdType *indx = 0; + pts = theData->GetPoints(); + polys = theData->GetPolys(); + vtkCellArray* lines = theData->GetLines(); + + //choose to use either polys or lines + //the result of vtk marching cubes->stripper->appendpolydata is a set of lines, + //not polys, so favor that one for now. + //choose by the number of polys/lines available. + vtkCellArray* theCells = lines; + if (!lines || lines->GetNumberOfCells() == 0) + { + theCells = polys; + } + double v[3]; + vtkIdType theNumCells = theCells->GetNumberOfCells(); + gdcmDebugMacro("The number of cells:" << theNumCells); + if (theNumCells == 0) continue;// no observation of blank organs + + for (theCells->InitTraversal(); theCells->GetNextCell(npts,indx); cellnum++ ) + { + if (npts < 1) + { + gdcmWarningMacro("theCells for input " << j << " is less than 1, continuing"); + continue; + } + pts->GetPoint(indx[0],v); + double theZ = v[2]; + std::string theSOPInstance = + DirectoryHelper::RetrieveSOPInstanceUIDFromZPosition(theZ, theCTDataSets); + //j is correct here, because it's adding, as in there's an internal vector + //that's growing. + gdcmDebugMacro("SOP Instance for plane " << theZ << " is " << theSOPInstance); + + theRTStruct->AddContourReferencedFrameOfReference(contour, + theSOPClassID.c_str(), theSOPInstance.c_str()); + } + } +} diff --git a/gdcm/Utilities/VTK/vtkGDCMPolyDataWriter.h b/gdcm/Utilities/VTK/vtkGDCMPolyDataWriter.h new file mode 100644 index 0000000..aa456f3 --- /dev/null +++ b/gdcm/Utilities/VTK/vtkGDCMPolyDataWriter.h @@ -0,0 +1,90 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +// .NAME vtkGDCMPolyDataWriter - writer DICOM PolyData files (Contour Data...) +// .SECTION Description +// For now only support RTSTRUCT (RT Structure Set Storage) +// .SECTION TODO +// Need to do the same job for DVH Sequence/DVH Data... +// .SECTION Warning +// +// .SECTION See Also +// vtkGDCMImageReader vtkGDCMPolyDataReader vtkRTStructSetProperties + + +#ifndef VTKGDCMPOLYDATAWRITER_H +#define VTKGDCMPOLYDATAWRITER_H + +#include "vtkPolyDataWriter.h" +#include "vtkStringArray.h" +#include "vtkStdString.h" + + +class vtkMedicalImageProperties; +class vtkRTStructSetProperties; +//BTX +namespace gdcm { class File; } +//ETX +class VTK_EXPORT vtkGDCMPolyDataWriter : public vtkPolyDataWriter +{ +public: + static vtkGDCMPolyDataWriter *New(); + vtkTypeRevisionMacro(vtkGDCMPolyDataWriter,vtkPolyDataWriter); + virtual void PrintSelf(ostream& os, vtkIndent indent); + + // Description: + // Set/Get the filename of the file to be read +// vtkSetStringMacro(FileName); +// vtkGetStringMacro(FileName); + + // Description: + // Get the medical image properties object +// vtkGetObjectMacro(MedicalImageProperties, vtkMedicalImageProperties); + virtual void SetMedicalImageProperties(vtkMedicalImageProperties *pd); + + virtual void SetRTStructSetProperties(vtkRTStructSetProperties *pd); + + + //this function will initialize the contained rtstructset with + //the inputs of the writer and the various extra information + //necessary for writing a complete rtstructset. + //NOTE: inputs must be set BEFORE calling this function! + //NOTE: the number of outputs for the appendpolydata MUST MATCH the ROI vectors! + void InitializeRTStructSet(vtkStdString inDirectory, + vtkStdString inStructLabel, vtkStdString inStructName, + vtkStringArray* inROINames, + vtkStringArray* inROIAlgorithmName, + vtkStringArray* inROIType); + + // make parent class public... + void SetNumberOfInputPorts(int n); + +protected: + vtkGDCMPolyDataWriter(); + ~vtkGDCMPolyDataWriter(); + + vtkMedicalImageProperties *MedicalImageProperties; + vtkRTStructSetProperties *RTStructSetProperties; + + void WriteData(); +//BTX + void WriteRTSTRUCTInfo(gdcm::File &file); + void WriteRTSTRUCTData(gdcm::File &file, int num); +//ETX + +private: + vtkGDCMPolyDataWriter(const vtkGDCMPolyDataWriter&); // Not implemented. + void operator=(const vtkGDCMPolyDataWriter&); // Not implemented. +}; + +#endif diff --git a/gdcm/Utilities/VTK/vtkGDCMTesting.cxx b/gdcm/Utilities/VTK/vtkGDCMTesting.cxx new file mode 100644 index 0000000..21c2214 --- /dev/null +++ b/gdcm/Utilities/VTK/vtkGDCMTesting.cxx @@ -0,0 +1,320 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkGDCMTesting.h" + +#include "vtkObjectFactory.h" +#include "vtkToolkits.h" +#include "gdcmTesting.h" +#include "gdcmFilename.h" + +vtkCxxRevisionMacro(vtkGDCMTesting, "$Revision: 1.31 $") +vtkStandardNewMacro(vtkGDCMTesting) + +// DICOM Filename, MHD MD5, RAW MD5 +static const char * const vtkgdcmMD5MetaImages[][3] = { +{ "MR-SIEMENS-DICOM-WithOverlays-extracted-overlays.dcm","3d77fa60702897dd0ad601ee728f93d3", "8b636107a6d8e6a6b3d1d7eed966d7a0" }, +{ "PHILIPS_Gyroscan-8-MONO2-Odd_Sequence.dcm","3b22e8e2aea4354ed947786152504d4d", "cd301effb5e2020f539a2f5d24a429d7" }, +{ "SIEMENS_GBS_III-16-ACR_NEMA_1.acr","3864799d39588714e16c3a4482137c74", "ea24c09f475a4e9643e27f6d470edc67" }, +{ "SIEMENS_GBS_III-16-ACR_NEMA_1-ULis2Bytes.dcm","f285ebea4a7675457b916c16ff770934", "ea24c09f475a4e9643e27f6d470edc67" }, +{ "test.acr","06165c1b4e64898394fdc0598eb5971a", "f845c8f283d39a0204c325654493ba53" }, +{ "MR-MONO2-12-angio-an1.acr","849ce36c711f742e64c5bd5a161bb849", "ae5c00b60a58849b19aaabfc6521eeed" }, +{ "CT-MONO2-12-lomb-an2.acr","554cc0adb0dea2023d255d0eccbb21a6", "672d4cd82896c2b0dc09b6fe3eb748b0" }, +{ "SIEMENS_SOMATOM-12-ACR_NEMA-ZeroLengthUs.acr","ac6311f0db183e427e69650ba2e632b4", "a909e448b66303df6f5a512d169921d5" }, +{ "gdcm-MR-SIEMENS-16-2.acr","670ba858ad6f6eefb4b59cb24e5a3b31", "864e2c5d6acf5a371fe9eaa7ee0dcf5f" }, +{ "LIBIDO-8-ACR_NEMA-Lena_128_128.acr","e186747fca1e99d9f5b0c1607f19a9cb", "fc5db4e2e7fca8445342b83799ff16d8" }, +{ "libido1.0-vol.acr","b10050e7aa8fa72228d8d33bf0504238", "f17cf873a3c07f3d91dc88f34664bf0d" }, +{ "gdcm-ACR-LibIDO.acr","eb59c5fd7a6cc0bc1223e15e08a3637d", "59d9851ca0f214d57fdfd6a8c13bc91c" }, +{ "MR-MONO2-12-an2.acr","356cb716cc543209113c0e2b535faba9", "f54c7ea520ab3ec32b6303581ecd262f" }, +{ "012345.002.050.dcm","ea9ca1be179f269583c5c27e89c0a46d", "d594a5e2fde12f32b6633ca859b4d4a6" }, +{ "GE_MR_0025xx1bProtocolDataBlock.dcm","c9d8d1f0e94a06a98469926ec83a08da", "b620a57170941e26dfd07ff334c73cb4" }, +{ "MR_GE_with_Private_Compressed_Icon_0009_1110.dcm","91fb4352059cf7f7ba023599ec2c39a9", "8fe67e8e1f849c1b61f59e70d2d53cf7" }, +{ "gdcm-JPEG-LossLessThoravision.dcm","e5cb57f774e3be543169af242d27c93d", "c15c1e18a0c41970fbded48b20e834a1" }, +{ "SIEMENS_MAGNETOM-12-MONO2-Uncompressed.dcm","0a6af461c022adb1cdbef8836a3426f7", "4b426d4cd570bd4c998f3d19cfddfbb8" }, +{ "MR-MONO2-12-shoulder.dcm","ab968254870fdc9e41055d2adfe9ffef", "a70676f0e60a58f55a5ac517ff662e7e" }, +{ "PICKER-16-MONO2-No_DicomV3_Preamble.dcm","ff5f52a1ffd97d0cc6dad2c59e371b95", "5ea911b29f472f371d21f2da2fd6b016" }, +{ "LEADTOOLS_FLOWERS-8-PAL-Uncompressed.dcm","92629f1a782a3d10998d01a8af5df991", "16e999d6afc5574bcb075f296c3bcbbc" }, +{ "D_CLUNIE_CT1_JPLL.dcm","74360148191955d7e5664952d85ad01c", "a109da372df2b85ff0a705fba62e9589" }, +{ "DMCPACS_ExplicitImplicit_BogusIOP.dcm","3f434e2196fbe53d0024704c707254e9", "ef9f915086db838334ddc656a10486f2" }, +{ "PHILIPS_GDCM12xBug2.dcm","f3bb3e8fbf262a37621a805357b0b1c6", "a597540a79306be4710f4f04497fc23a" }, +{ "PICKER-16-MONO2-Nested_icon.dcm","2642d6b9be2d28d57f85abffc661bdb7", "954c99e48a083cc54de16ad07d553005" }, +{ "RadBWLossLess.dcm","1cbcd5c44f8ffe7c448520971233afb4", "dbbf39ac11a39372b1e961f40ac6f62a" }, +{ "gdcm-JPEG-Extended.dcm","4873a6ad617c2a8f86d130c853c5e127", "f05174b105604a462af0fa733fceebde" }, +{ "DX_J2K_0Padding.dcm","6986a0e25c3c39e30ad30f5cdb17cbfe", "52607a16af1eaddbbc71c14d32e489d8" }, +{ "CT-MONO2-16-ort.dcm","f758d2ad7de59ccf49473db31bb07825", "ca3c1630965318e6321daac7b39d8883" }, +{ "D_CLUNIE_XA1_RLE.dcm","6992adfe56cdd43fdb5c4ae832be0bb3", "6111657e6b01ec7b243d63f5dec6ec48" }, +{ "OT-MONO2-8-a7.dcm","7611df3cbfd9ac2e137a78d732d98603", "a155c3004bb902ed3f2d78f482923b32" }, +{ "fffc0000UN.dcm","1ca6fabea6962185ade0592a7e0db06a", "a136e501bcd1b8ee0835981d2bc8dd87" }, +{ "LEADTOOLS_FLOWERS-16-MONO2-RLE.dcm","9e1e8d58a04142531c21f3a39664edb0", "70166425c4dca767e22d3f25f737922b" }, +{ "gdcm-US-ALOKA-16.dcm","6dfc2e8a30cd515b12a3c0891b1496b5", "f85ff02a143c426edc4b2f6b9a175305" }, +{ "TG18-CH-2k-01.dcm","ff2121ad1e7471cd9f5c75d74664c8a1", "46bf12c412590767bb8cd7f0d53eaa87" }, +{ "05115014-mr-siemens-avanto-syngo-with-palette-icone.dcm","5d007c4979f5c401c623b8b1d095a339", "c68cf1c4ae59903930e334498389ea88" }, +{ "D_CLUNIE_RG1_RLE.dcm","e39a383f71c5f996cd2116e0312fc808", "ae141f6fb91f63769a6adc572a942fb9" }, +{ "PHILIPS_Brilliance_ExtraBytesInOverlay.dcm","675cb24b99d9c6cca3259e5e87bb6aea", "7f4158c2946981465bf409f2433ebaa7" }, +{ "MR_Philips_Intera_PrivateSequenceExplicitVR_in_SQ_2001_e05f_item_wrong_lgt_use_NOSHADOWSEQ.dcm","778a5b6f00dd312b2ecad0deac6b9577", "7775ffdd374994b7dd029f45f198844f" }, +{ "LEADTOOLS_FLOWERS-16-MONO2-JpegLossless.dcm","bd7bdc10de0df526ee6858da2c13018c", "70166425c4dca767e22d3f25f737922b" }, +{ "gdcm-JPEG-LossLess3a.dcm","62822559a854373b843ce8de2cc3ed7d", "a341e8cb1ec2aa07cb0e5b71bbe87087" }, +{ "D_CLUNIE_MR1_JPLY.dcm","0a4ce0b9f33ccf29ced7537327052978", "2824e914ecae250a755a8a0bb1a7d4b1" }, +{ "SIEMENS_MAGNETOM-12-MONO2-GDCM12-VRUN.dcm","a53035663a2de05df96871cf6a2773f1", "d2fab61e0fff8869e448d69951f1084d" }, +{ "PHILIPS_Gyroscan-12-MONO2-Jpeg_Lossless.dcm","adecccb2b55c791fb9a5f9adb9b5c7be", "b78366162d9d43b2852d2637c5365c89" }, +{ "SignedShortLosslessBug.dcm","dbf67ea5171e87a11ffbadc1ac8af3e8", "bdec90fcb90f68b34f0a306c40443610" }, +{ "SIEMENS_MAGNETOM-12-MONO2-FileSeq2.dcm","cc1e8af8bb7bf4d1e9ec20bad537cdfd", "f932a194df62ec99aef676c563893496" }, +{ "BugGDCM2_UndefItemWrongVL.dcm","84fc423a48309bdb0256ace6c7cf1458", "dae9d2e2b412646fd0a0f31dc2d17aa4" }, +{ "US-PAL-8-10x-echo.dcm","e83577771dbdb47f3046277bcdfe2758", "1785f4d8af4717c17bfb78ba74c18ea5" }, +{ "MR_Philips-Intera_BreaksNOSHADOW.dcm","aa9341fd51dd1dd640fa6420b274f507", "b606add66c681bbe674f972799c6d336" }, +{ "D_CLUNIE_RG3_RLE.dcm","df3d8699a986204038e3f9debde3a1d2", "e7c857ef7e6a2c81498297a072a0332e" }, +{ "JPEGDefinedLengthSequenceOfFragments.dcm","cc21f41e99625aac7308d9fdd01481d6", "484754f6dd1cc59325e9a5bbf76c5f2c" }, +{ "SIEMENS-MR-RGB-16Bits.dcm","56f175c3a227ca322245e90a625470a4", "faff9970b905458c0844400b5b869e25" }, +{ "JDDICOM_Sample2.dcm","76ef935051cf0e816a0e8864f88d4814", "33aa469ec024188d692262d03e7108a0" }, +{ "D_CLUNIE_MR2_JPLL.dcm","c3281801885ac42ec0e82af71636798d", "a70676f0e60a58f55a5ac517ff662e7e" }, +{ "PHILIPS_Intera-16-MONO2-Uncompress.dcm","89fc7c6e5ccc5ed3320197d9bdfc4dc6", "0b4dff77726ccf037fa83c42cc186a98" }, +{ "THERALYS-12-MONO2-Uncompressed-Even_Length_Tag.dcm","2a8441911c2135e94cd16f231c7ad8e6", "0121cd64c3b9957f76dd338d27454bc6" }, +{ "D_CLUNIE_CT2_RLE.dcm","74e31e7ac318cdcaffb172277f166e2e", "2e389ddbfc1b29d55c52c97e7f2c6f9c" }, +{ "ExplicitVRforPublicElementsImplicitVRforShadowElements.dcm","6f97e45b637beb9282e85c7b81b1473b", "0b4dff77726ccf037fa83c42cc186a98" }, +{ "D_CLUNIE_MR2_RLE.dcm","8bc2159b48a5a069ac7371f69694d761", "a70676f0e60a58f55a5ac517ff662e7e" }, +{ "SIEMENS_ImageLocationUN.dcm","4fd3c5e0b413ccfbec2b4706ad23200b", "0621954acd5815e0b4f7b65fcc6506b1" }, +{ "TOSHIBA_MRT150-16-MONO2-ACR_NEMA_2.dcm","a68236a0584e518d5ca9fce9136da38f", "09661bd8516aeb5a6f09239f9ca1b092" }, +{ "ACUSON-24-YBR_FULL-RLE-b.dcm","479d056e0a591bc2850eef632fc2345c", "22b32f23beb118f7b64c13bf04bc2809" }, +{ "D_CLUNIE_RG3_JPLL.dcm","351293952be98d7ce8e73ab574648daa", "e7c857ef7e6a2c81498297a072a0332e" }, +{ "AMIInvalidPrivateDefinedLengthSQasUN.dcm","0f5c34ef47b32554270a52201ce26daf", "ae1290d59c63b0c334a4834c5995fe45" }, +{ "CT-SIEMENS-Icone-With-PaletteColor.dcm","f0dc9d6c14c010948fdb64a4c6466565", "c6bdfac1d97c4dc60423b5b63a39a64a" }, +{ "SIEMENS_MAGNETOM-12-MONO2-FileSeq0.dcm","d351dce81724bbd2b0bea467ad6942ff", "a13466d96b2f068c4844240797069f13" }, +{ "LJPEG_BuginGDCM12.dcm","fb9e4419f90eaa9c2a6c4ae98b750348", "9214cc4f62fbea873ffad88e1be877c5" }, +{ "XA-MONO2-8-12x-catheter.dcm","639e46ee89a1204df2ed708e33c3357b", "136eaf8f7d654bbb08741c201a945561" }, +{ "LEADTOOLS_FLOWERS-16-MONO2-Uncompressed.dcm","e086859c0b556c3d22d51bf2a05db26a", "70166425c4dca767e22d3f25f737922b" }, +{ "TheralysGDCM120Bug.dcm","3bbfb2b54ec9d9e3f89fe046e5a954a4", "6af53848fe77feb56a12aba74dadea8e" }, +{ "D_CLUNIE_VL1_RLE.dcm","668904d73866455812fee0aabdbcff1e", "b07e34ec35ba1be62ee7d4a404cf0b90" }, +{ "D_CLUNIE_MR1_JPLL.dcm","087e123efb3e18f5e7693390926f08c6", "7b7424e6115931c371f3c94c2f5d32d9" }, +{ "GE_DLX-8-MONO2-Multiframe-Jpeg_Lossless.dcm","61c2a3757ad053c52eeeaa94f5d6cadd", "b8bcbccd17b76a0f8e3d4c342f855f9f" }, +{ "SIEMENS_Sonata-12-MONO2-SQ.dcm","91ee14eaab0a6f98b366ff3406b8d295", "a3009bc70444148c5ea2441a099f9dc6" }, +{ "3E768EB7.dcm","a8f6eb80f1aebdcc2716435b7049be6c", "a0fcdd5b68358d7078421e260fa749b7" }, +{ "DX_GE_FALCON_SNOWY-VOI.dcm","d3efd7ae0f764f26c22dfbfec46b13e9", "ba8dae4b43075c7e8562f5addf5f95c3" }, +{ "US-RGB-8-epicard.dcm","d139728ec75594e11fd2d489049756f5", "fe2d477d699e327be2d3d65eb76203e9" }, +{ "D_CLUNIE_NM1_JPLL.dcm","0210138626fc112253519cd202dac179", "6b5c1eff0ef65e36b0565f96507e96fd" }, +{ "SIEMENS_MAGNETOM-12-ACR_NEMA_2-Modern.dcm","3ec03618a9dcb12c636dae46cfa12bc5", "864e2c5d6acf5a371fe9eaa7ee0dcf5f" }, +{ "MR_SIEMENS_forceLoad29-1010_29-1020.dcm","d887c10d6058b568dd3a07c573faf5e1", "6a925f871c58553f84ad24195e155c52" }, +{ "D_CLUNIE_CT1_RLE.dcm","87ca724fcddef83277f918f7e7d4b235", "a109da372df2b85ff0a705fba62e9589" }, +{ "D_CLUNIE_XA1_JPLY.dcm","df8bca314462d849da13af4c971eb616", "51af0d83fe795f9c9544c20d0bbac11c" }, +{ "D_CLUNIE_MR3_JPLY.dcm","c2872e85ff9f155d80b6c703add04d8f", "d7009808a147f59a9bdf58d5c5924ef2" }, +{ "D_CLUNIE_CT1_J2KI.dcm","2923abe11b2f7898af31cfada0005cea", "bc127eee2ebf5f2ee2a6a1daeac364ce" }, +{ "CT_16b_signed-UsedBits13.dcm","2122e1b307aa75d602c665852a2daaff", "8c8b9d99ad12fb4d231182d4fc14c042" }, +{ "D_CLUNIE_VL6_RLE.dcm","04550649448200f4f3b5e478044c021a", "b825c0ed35c7c896fb707c14b534c233" }, +{ "DCMTK_JPEGExt_12Bits.dcm","1a9268135f0c200ffee17babd894352d", "c57035e2dac52e339b27e8c965251b3d" }, +{ "D_CLUNIE_MR4_RLE.dcm","d682f844f5cc19df26dc9acf434da818", "14fa2ae9f63742af6944edd4a61145e8" }, +{ "simpleImageWithIcon.dcm","eaf8ce3d45bf4f6e4991db6acbb4d673", "fc5db4e2e7fca8445342b83799ff16d8" }, +{ "gdcm-MR-PHILIPS-16-Multi-Seq.dcm","0af3267489f800c8e272f607f1d9a938", "ad85be428c08ab4166347ef04bda9637" }, +{ "D_CLUNIE_VL3_RLE.dcm","8ba4764396aa1d1c7fd84bf4132b273e", "65cd359ea4c6c13ca89b906215a4b762" }, +{ "CT-MONO2-16-brain.dcm","cdcf9ee879a4159cc686004f76745148", "a6cf43e05087b6c31644c1d360701ff2" }, +{ "CT-MONO2-16-ankle.dcm","803a459d3a6df6473c3f3e46129df147", "13e853d75ffe289b8210d1336e2394dd" }, +{ "MR_ELSCINT1_00e1_1042_SQ_feff_00e0_Item.dcm","4bb845dfa4b1f9b46fa53006e82bf4c8", "4d790e17ee35572d64e37c55dbc36725" }, +{ "LEADTOOLS_FLOWERS-24-RGB-JpegLossy.dcm","e91814bf121ae0dad75be63fbf1b1e93", "38c2784aa485733fef45b6517479a4f5" }, +{ "undefined_length_un_vr.dcm","fd3d95cd61c0fc391733f28f607fa506", "e0221ddcc9febdc3c266bb8cd0fcf14f" }, +{ "JPEG_LossyYBR.dcm","351424d0392db74bc69cf6f6537ddb88", "d6fb1fb06318dd305a461db9c84cf825" }, +{ "rle16loo.dcm","fd66e0089e5c343d3f24642710eb0129", "04b42f011bdcf56e8a22607cb715447c" }, +{ "D_CLUNIE_MR2_JPLY.dcm","013b4754a4224b10cb503dead5a6a79e", "981510df3a57e98141c7d192b45bd93f" }, +{ "DermaColorLossLess.dcm","2d02d5385526970fffbb5cebafd6b4df", "b4f442047a209a98af015c89b4a3c4ed" }, +{ "KODAK-12-MONO1-Odd_Terminated_Sequence.dcm","601f6ff54e324ccc4e9e5627c0593027", "c1ed06d39821a5fd65abc397982e2ac1" }, +{ "D_CLUNIE_RG1_JPLL.dcm","08a9f8187cfad52150fffc80e76efa9e", "ae141f6fb91f63769a6adc572a942fb9" }, +{ "D_CLUNIE_RG3_JPLY.dcm","3c39fb636e231a66e425d6c8645e086c", "cc2968949ffbb6548288ffde7e5202e4" }, +{ "D_CLUNIE_MR3_RLE.dcm","847c8b74671107b463b90cbfa6535f7f", "fb03254fad02d2330d404225c3ea9b4e" }, +{ "NM-MONO2-16-13x-heart.dcm","7bfdb71668190142a547899329c1d9c3", "c83ef2159abef677229d3afd26f9e6a0" }, +{ "LEADTOOLS_FLOWERS-8-MONO2-JpegLossy.dcm","bcfdeefa6f9808ae020586b164a29d99", "fa08fec923f34e009ec89f77232e52ad" }, +{ "CT-MONO2-16-chest.dcm","f9110218ff6bd9310e6eb089fdb4ab0a", "78bb9ea4b746ff2aa5559be567f95030" }, +{ "SIEMENS_Sonata-16-MONO2-Value_Multiplicity.dcm","aafebb62a52ad79ca0aea428fdfc7d1e", "017237320ccded3a367f07b44851788e" }, +{ "PrivateGEImplicitVRBigEndianTransferSyntax16Bits.dcm","3e1c33b362a0fb5a3c3009e681a6e546", "e5a0f7083de19fcc63dfdec9d754470f" }, +{ "US-GE-4AICL142.dcm","a9142c48ce2499d1f67e67db1b6f87d6", "23ec8ed09e1ecc353c2e6436a1de6cb2" }, +{ "gdcm-MR-PHILIPS-16-NonSquarePixels.dcm","68b7e492026a8a4da1e579802c2ef1ac", "2f7f9ef80b49111c5a7cfdb60a97f523" }, +{ "SIEMENS_MOSAIC_12BitsStored-16BitsJPEG.dcm","7433cf1900fbc331517e196daca6a4ef", "6396332b75b15bf30b1dd1cd0f212691" }, +{ "KODAK_CompressedIcon.dcm","2ad7b4697b63a2fe0082374ff6ea58d8", "79b8705f2e6c7464bd3e2fc7e1d3483b" }, +{ "D_CLUNIE_US1_RLE.dcm","14baf3e73f87d5b0893a9f305b11c87e", "eb52dce9eed5ad677364baadf6144ac4" }, +{ "D_CLUNIE_CT1_J2KR.dcm","0eb834e9d393fd41cf0ceb5b9c0c8959", "a109da372df2b85ff0a705fba62e9589" }, +{ "MAROTECH_CT_JP2Lossy.dcm","13a06166e548dc268ece0e22c860c387", "0e78a01c664550949071796339ac280e" }, +{ "CR-MONO1-10-chest.dcm","0cccf203c6c2a097383e8a017322b77b", "1f772b4849727a9750931b60d920436f" }, +{ "rle16sti.dcm","a225d3ea83666526eca91750e478b3ee", "f799773abbe36a1a8a3a881e27f8084d" }, +{ "D_CLUNIE_MR4_JPLL.dcm","355a76b3d43982ad2256e010d0230835", "14fa2ae9f63742af6944edd4a61145e8" }, +{ "US-IRAD-NoPreambleStartWith0003.dcm","27d939385c633d1db6943628a4e778cf", "ba092234639594ee9091b46997532cce" }, +{ "00191113.dcm","7c17afc7815f18ebaecd99b9b07950f1", "bfff320d1b058e91b4819aa4560c16f7" }, +{ "MR16BitsAllocated_8BitsStored.dcm","9d0266b04310ea377cf4d4c704ae44ba", "49b62d0b9004c2e1579317a36825cc5f" }, +{ "D_CLUNIE_XA1_JPLL.dcm","462a9583d0241ead2f5a1bab318e177a", "6111657e6b01ec7b243d63f5dec6ec48" }, +{ "MR-MONO2-8-16x-heart.dcm","379f882b2df9bdf115c38c4c68aea867", "01db0d71100c47013e588082d5f39bab" }, +{ "ACUSON-24-YBR_FULL-RLE.dcm","1715cfceb7141080e09954ac55f1640b", "435c66f7e113d11d226d500294aae865" }, +{ "D_CLUNIE_RG2_JPLL.dcm","ec91a9e10b3b9ba44305e62400db1ce9", "06900ee4323a91b7f5ffab8655e3c845" }, +{ "SIEMENS_MAGNETOM-12-MONO2-FileSeq3.dcm","366582d77fed1513d96acce3ba37da11", "b6e4780d8aa8c1d3642377a60a5302dd" }, +{ "GE_CT_With_Private_compressed-icon.dcm","48dd87fff8790e7fc2b1d31b03acd65a", "67206c434201b17a3a52ef42588b02e2" }, +{ "D_CLUNIE_NM1_JPLY.dcm","b0227cfc9911bb0d18402685fd437a84", "812050a7fc53b5735f7740b60969cb6b" }, +{ "US-RGB-8-esopecho.dcm","0916c89d6e3f3f28a52933829e5d0b3c", "4b350b9353a93c747917c7c3bf9b8f44" }, +{ "FUJI-10-MONO1-ACR_NEMA_2.dcm","98190f9abe6cdf82e565aee55288aaba", "da2415a1e58b4ca2e588d0de18274f60" }, +{ "JDDICOM_Sample2-dcmdjpeg.dcm","d883a2a8e69820f465865200cc726a4f", "33aa469ec024188d692262d03e7108a0" }, +{ "MR_Philips_Intera_PrivateSequenceImplicitVR.dcm","f89bb9670acce806d40f84e15a3143b0", "f69bca6228b0ca07d97ee11c0ab3b989" }, +{ "D_CLUNIE_RG2_JPLY.dcm","e4e64e50877ce1134a58824e4b3b0cda", "27fa50d4cf6b31baa669e9746ce10f63" }, +{ "ITK_GDCM124_MultiframeSecondaryCaptureInvalid.dcm","31a2d7476b505c01d77bf06333a3b797", "83601a7a4fa987c61b865b4b92f3caa0" }, +{ "GE_RHAPSODE-16-MONO2-JPEG-Fragments.dcm","12d33998ab1c371f3c2401fa362b2663", "a109da372df2b85ff0a705fba62e9589" }, +{ "PHILIPS_GDCM12xBug.dcm","7a2531acbdaf8053365099a844f46df8", "d7673c8575cb2765f8ae25aa3899c77e" }, +{ "OT-PAL-8-face.dcm","42c16b6897e32fbac5fd68a2d2523642", "d7c30d57af821b02c67103250a744235" }, +{ "D_CLUNIE_SC1_JPLY.dcm","46dc0d3ad79883f0f5866ceeeb43c979", "994a5abb70d3f5968672ce4970a9d4da" }, +{ "CT-MONO2-8-abdo.dcm","e94fa94ff3b7a34db63d40790995ce9c", "86d3e09a5858aa3844cb3be1b822a069" }, +{ "GE_LOGIQBook-8-RGB-HugePreview.dcm","08a05020b521684a67d2ec40c2dc1600", "13fd8c7e533a3d7199bb78de45710f5c" }, +{ "MR-Brucker-CineTagging-NonSquarePixels.dcm","e9c9b806ebf112c342426fc6b35f4471", "d9f47017de79e8755e4bc5d3c9146ebd" }, +{ "SIEMENS-12-Jpeg_Process_2_4-Lossy-a.dcm","21f5f8c1d2b221833b665fae40327ce9", "698d6a3e88b270d4ad5ecfb00c11b634" }, +{ "D_CLUNIE_CT2_JPLL.dcm","92f22a280db62906e4b894d0e7882550", "2e389ddbfc1b29d55c52c97e7f2c6f9c" }, +{ "SIEMENS_CSA2.dcm","eb1db86d50a09dcf607af389e823d985", "62687f0a17e9c4153f18b55c8abfcef3" }, +{ "MR-MONO2-16-head.dcm","49c0aea0ba79ac781a53dac56db530e1", "83be31fb5e5cee60dedaf485bf592ac3" }, +{ "ELSCINT1_JP2vsJ2K.dcm","7d24121c34065f054fd398b5cf663a43", "87f5809b641b7235bfe5900a6281862b" }, +{ "D_CLUNIE_MR4_JPLY.dcm","eb5b39beed663bec16b26bcfcaedddfe", "a33ad864b49ae7daa59cfaabdf751976" }, +{ "MR-SIEMENS-DICOM-WithOverlays.dcm","9ad170d29a5e16ec04229b356f34ad45", "3027eda10630e5c845f456264dc65210" }, +{ "GE_GENESIS-16-MONO2-Uncompressed-UnusualVR.dcm","24a56cb80de943a06d82042933d22ea2", "8ac7f7891fb4506e2cd3ae2f0f7e9f46" }, +{ "OsirixFake16BitsStoredFakeSpacing.dcm","a7f05bcbea7af6ab00c58950144fa86c", "68269299e8f4341120aaa13a933c6c11" }, +{ "D_CLUNIE_VL2_RLE.dcm","017c67d4a3fedafb9d37264b4a4a68a1", "d215c88125359d34474a741d793c2215" }, +{ "ALOKA_SSD-8-MONO2-RLE-SQ.dcm","6a8d9e3420077ef24de8cd0e490895ce", "7d8858e3419392b7f39a99fdc8028064" }, +{ "D_CLUNIE_NM1_RLE.dcm","926811c358070765622fb131b9d4a39f", "6b5c1eff0ef65e36b0565f96507e96fd" }, +{ "D_CLUNIE_SC1_RLE.dcm","2085edf780950a21167765481ad92811", "bd0cccbfd8db465c0af306ba0f482d72" }, +{ "MR_Philips_Intera_SwitchIndianess_noLgtSQItem_in_trueLgtSeq.dcm","ba1e9ecee0fee60f3037cd7fb2e7023e", "0b4dff77726ccf037fa83c42cc186a98" }, +{ "GE_DLX-8-MONO2-PrivateSyntax.dcm","24e671036bdc9facc372b1ec4737e751", "51c998d3474c069b5703e98313258a1e" }, +{ "D_CLUNIE_MR3_JPLL.dcm","baac36788bfa8d192455ca79f9b7af36", "fb03254fad02d2330d404225c3ea9b4e" }, +{ "05148044-mr-siemens-avanto-syngo.dcm","60d33c5aecfe33a238e8ab8957194f4a", "9acdd9969f5d0584ddd67e994f00b7c7" }, +{ "US-IRAD-NoPreambleStartWith0005.dcm","3c0377fbaca00a9dcd17fa0258caa2c0", "1bde104ba256fb73528c5d9a02e363d7" }, +{ "LEADTOOLS_FLOWERS-8-MONO2-RLE.dcm","95d5f4e573800918664796910c238ed0", "3cd8bd92db17bff54e376885dfefdd8d" }, +{ "US-MONO2-8-8x-execho.dcm","14a483a14e070ead0a31a96d86146311", "bf63affde325b3fa81cd5a700f30bd5b" }, +{ "D_CLUNIE_RG2_RLE.dcm","bda1db6bbe98fcf680c4073df99e7b18", "06900ee4323a91b7f5ffab8655e3c845" }, +{ "LEADTOOLS_FLOWERS-24-RGB-Uncompressed.dcm","d7292927bd1aef2298c25524055cc2ab", "279e2b0363394a553ff8571cf3540c6c" }, +{ "CT-SIEMENS-MissingPixelDataInIconSQ.dcm","eed1e36b9333d9a50458e19bd0203455", "a86e48680d8ca941aa694d81872e8490" }, +{ "LEADTOOLS_FLOWERS-8-PAL-RLE.dcm","ec48c6dda2fdff2dd59366764d1fb0bd", "16e999d6afc5574bcb075f296c3bcbbc" }, +{ "D_CLUNIE_VL4_RLE.dcm","c1bdaec5bf045ae322068790c2f304a8", "e2fdf24d2c03dd0991b4f4e9d6e84ed6" }, +{ "GE_GENESIS-16-MONO2-WrongLengthItem.dcm","97e495e5e6b9fd9e080c7b9e40589b84", "1497fb9d7467b1eb36d5618e254aac76" }, +{ "MARCONI_MxTWin-12-MONO2-JpegLossless-ZeroLengthSQ.dcm","a7da0400b907b86ef97af8e61658b569", "6bbe3a067ff90eae950bc901f0f92f9e" }, +{ "LEADTOOLS_FLOWERS-24-RGB-JpegLossless.dcm","09dc2ab46d45d47a3ad41e9d53bf3c8d", "279e2b0363394a553ff8571cf3540c6c" }, +{ "SIEMENS_MAGNETOM-12-MONO2-FileSeq1.dcm","c1bcf58ffa46cfe50a989847cdd3e3c9", "73f5986082729c2661cdc8de81fd26d0" }, +{ "SIEMENS_MAGNETOM-12-MONO2-VRUN.dcm","3c10ecf511e1316d367399eeb4ee70dd", "d2fab61e0fff8869e448d69951f1084d" }, +{ "D_CLUNIE_MR1_RLE.dcm","a9c04692b4126a69e2cffc81f567a516", "7b7424e6115931c371f3c94c2f5d32d9" }, +{ "MR_Philips_Intera_No_PrivateSequenceImplicitVR.dcm","eab7f8484a6c3d6e76a8e281213e56e4", "0b4dff77726ccf037fa83c42cc186a98" }, +{ "GE_DLX-8-MONO2-Multiframe.dcm","67c44b08178efe2857221f3015b0510f", "71e4ea61df4f7ada2955799c91f93e74" }, +{ "LEADTOOLS_FLOWERS-8-MONO2-Uncompressed.dcm","4a967f8f35bfb93262dc90e0b8acf6b8", "3cd8bd92db17bff54e376885dfefdd8d" }, +{ "00191113.dcm","7c17afc7815f18ebaecd99b9b07950f1", "bfff320d1b058e91b4819aa4560c16f7" }, +{ "D_CLUNIE_CT1_JLSL.dcm","4efffce4cded3f8785d5ac4d3b11da41", "a109da372df2b85ff0a705fba62e9589" }, +{ "D_CLUNIE_CT1_JLSN.dcm","bcf17a67d96046ce7a2b4de4495dbd4c", "7ca273fff6311586bd02ac983ccfbb6b" }, +{ "IM-0001-0066.CommandTag00.dcm","51450a7a49ce7bc0e6a4ce18eaef2fff", "12d1567ed81236cf3b01dc12766581a0" }, +{ "PHILIPS_Gyroscan-12-Jpeg_Extended_Process_2_4.dcm","2b1296ded36f37beb83e28fae108c280", "d93d2f78d845c7a132489aab92eadd32" }, +{ "UnexpectedSequenceDelimiterInFixedLengthSequence.dcm","f507ab11e56de33d6f0195dd185b5c62", "9eb513314b2fcf25d895e18ffb2ead0b" }, +{ "GDCMJ2K_TextGBR.dcm","9935ec525ea42203f3a535d4c1187ed4", "56238d3665ebdb0251d1161fb7f4edc6" }, +{ "NM_Kakadu44_SOTmarkerincons.dcm","99b60ec88d410b437adc06a809590127", "6f26e552a1b71d386483118779d192ad" }, +{ "PhilipsInteraSeqTermInvLen.dcm","6ccabe05841e29633d9e4fe1aec81039", "f8a1f4ce85b51527267e670a8aa0c308" }, +{ "LIBIDO-24-ACR_NEMA-Rectangle.dcm","28376a8bb2a64a9c8f6a50abfdbb336f", "81a40454eec2b18f4331cfd1ba4e501e" }, +{ "TOSHIBA_J2K_SIZ1_PixRep0.dcm","b7551911535d7ee21a336b700e4f0e4f", "d6347ed051d7b887bdaad1a91433c6ba" }, +{ "TOSHIBA_J2K_OpenJPEGv2Regression.dcm","f417f1a4552aeb03137ed91a04345fa2", "94414d8b4300aa3d8cbe4475d34e8e54" }, +{ "TOSHIBA_J2K_SIZ0_PixRep1.dcm","fcaab3ded5c41993b82d831c4251526e", "d6347ed051d7b887bdaad1a91433c6ba" }, +{ "NM-PAL-16-PixRep1.dcm","a04de15a87306cf77cd85ae5b720a0b2", "304f147752d46adfdcff71a30cd03d0a" }, +{ "MEDILABInvalidCP246_EVRLESQasUN.dcm","da13f42e41d36ef065af2cb5d770f70b", "d99ace99196e148522c8599803bacc28" }, +{ "JPEGInvalidSecondFrag.dcm","32ea68aea0c81d4cc75c5a234e1719ed", "8fb3a76c1f18b71b52d139ebd8406b50" }, + + +/* Stopping condition */ +{ 0 , 0 , 0 } +}; + +//static MD5MetaImagesType vtkGDCMTesting::GetMD5MetaImages() +//{ +//} + +unsigned int vtkGDCMTesting::GetNumberOfMD5MetaImages() +{ + // Do not count NULL value: + static const unsigned int size = sizeof(vtkgdcmMD5MetaImages)/sizeof(*vtkgdcmMD5MetaImages) - 1; + return size; +} + +const char * const * vtkGDCMTesting::GetMD5MetaImage(unsigned int file) +{ + if( file < vtkGDCMTesting::GetNumberOfMD5MetaImages() ) return vtkgdcmMD5MetaImages[file]; + return NULL; +} + +const char * vtkGDCMTesting::GetMHDMD5FromFile(const char *filepath) +{ + if(!filepath) return NULL; + unsigned int i = 0; +// MD5DataImagesType md5s = GetMD5DataImages(); + MD5MetaImagesType md5s = vtkgdcmMD5MetaImages; + const char *p = md5s[i][0]; + gdcm::Filename comp(filepath); + const char *filename = comp.GetName(); + while( p != 0 ) + { + if( strcmp( filename, p ) == 0 ) + { + break; + } + ++i; + p = md5s[i][0]; + } + // \postcondition always valid (before sentinel) +// assert( i <= GetNumberOfMD5DataImages() ); + return md5s[i][1]; +} + +const char * vtkGDCMTesting::GetRAWMD5FromFile(const char *filepath) +{ + if(!filepath) return NULL; + unsigned int i = 0; +// MD5DataImagesType md5s = GetMD5DataImages(); + MD5MetaImagesType md5s = vtkgdcmMD5MetaImages; + const char *p = md5s[i][0]; + gdcm::Filename comp(filepath); + const char *filename = comp.GetName(); + while( p != 0 ) + { + if( strcmp( filename, p ) == 0 ) + { + break; + } + ++i; + p = md5s[i][0]; + } + // \postcondition always valid (before sentinel) +// assert( i <= GetNumberOfMD5DataImages() ); + return md5s[i][2]; +} + +//---------------------------------------------------------------------------- +vtkGDCMTesting::vtkGDCMTesting() +{ +} + +vtkGDCMTesting::~vtkGDCMTesting() +{ +} + +//---------------------------------------------------------------------------- +const char *vtkGDCMTesting::GetVTKDataRoot() +{ +#ifdef VTK_DATA_ROOT + return VTK_DATA_ROOT; +#else + return NULL; +#endif +} + +//---------------------------------------------------------------------------- +const char *vtkGDCMTesting::GetGDCMDataRoot() +{ +#ifdef GDCM_BUILD_TESTING + return gdcm::Testing::GetDataRoot(); +#else + return NULL; +#endif +} + +//---------------------------------------------------------------------------- +void vtkGDCMTesting::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os,indent); +} diff --git a/gdcm/Utilities/VTK/vtkGDCMTesting.h b/gdcm/Utilities/VTK/vtkGDCMTesting.h new file mode 100644 index 0000000..57fe57d --- /dev/null +++ b/gdcm/Utilities/VTK/vtkGDCMTesting.h @@ -0,0 +1,54 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +// .NAME vtkGDCMTesting - GDCM Testing +// .SECTION Description +// GDCM Testing + +// .SECTION See Also +// vtkTesting + +#ifndef VTKGDCMTESTING_H +#define VTKGDCMTESTING_H + +#include "vtkObject.h" + +class VTK_EXPORT vtkGDCMTesting : public vtkObject +{ +public: + static vtkGDCMTesting *New(); + vtkTypeRevisionMacro(vtkGDCMTesting,vtkObject); + void PrintSelf(ostream& os, vtkIndent indent); + + static const char *GetVTKDataRoot(); + static const char *GetGDCMDataRoot(); + +//BTX + typedef const char* const (*MD5MetaImagesType)[3]; + static const char * const * GetMD5MetaImage(unsigned int file); +//ETX + static unsigned int GetNumberOfMD5MetaImages(); + + static const char * GetMHDMD5FromFile(const char *filepath); + static const char * GetRAWMD5FromFile(const char *filepath); + +protected: + vtkGDCMTesting(); + ~vtkGDCMTesting(); + +private: + vtkGDCMTesting(const vtkGDCMTesting&); // Not implemented. + void operator=(const vtkGDCMTesting&); // Not implemented. +}; + +#endif diff --git a/gdcm/Utilities/VTK/vtkGDCMThreadedImageReader.cxx b/gdcm/Utilities/VTK/vtkGDCMThreadedImageReader.cxx new file mode 100644 index 0000000..45b21ec --- /dev/null +++ b/gdcm/Utilities/VTK/vtkGDCMThreadedImageReader.cxx @@ -0,0 +1,613 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkGDCMThreadedImageReader.h" + +#include "vtkObjectFactory.h" +#include "vtkImageData.h" +#include "vtkMedicalImageProperties.h" +#include "vtkStringArray.h" +#if (VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 ) +#include "vtkInformationVector.h" +#include "vtkInformation.h" +#include "vtkDemandDrivenPipeline.h" +#include "vtkStreamingDemandDrivenPipeline.h" +#endif /* (VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 ) */ + +#include "gdcmImageReader.h" +#include "gdcmDataElement.h" +#include "gdcmByteValue.h" +#include "gdcmSwapper.h" + +#include + +#include +#include // sysconf + +#ifdef __APPLE__ +// For some reason sysconf + _SC_NPROCESSORS_ONLN is documented on macosx tiger, but it does not compile +#include +#include +#endif + +vtkCxxRevisionMacro(vtkGDCMThreadedImageReader, "$Revision: 1.1 $") +vtkStandardNewMacro(vtkGDCMThreadedImageReader) + +// Output Ports are as follow: +// #0: The image/volume (root PixelData element) +// #1: (if present): the Icon Image (0088,0200) +// #2-xx: (if present): the Overlay (60xx,3000) + +#define IconImagePortNumber 1 +#define OverlayPortNumber 2 + +vtkGDCMThreadedImageReader::vtkGDCMThreadedImageReader() +{ + this->LoadIconImage = 0; + this->UseShiftScale = 1; +} + +vtkGDCMThreadedImageReader::~vtkGDCMThreadedImageReader() +{ +} + +#if (VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 ) +#else /* (VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 ) */ +void vtkGDCMThreadedImageReader::ExecuteInformation() +{ + //std::cerr << "ExecuteInformation" << std::endl; + // This reader only implement case where image is flipped upside down + if( !this->FileLowerLeft ) + { + vtkErrorMacro( "You need to set the FileLowerLeft flag to On" ); + } + if( this->LoadIconImage ) + { + vtkErrorMacro( "Icon are not supported" ); + } + //int * updateExtent = this->Outputs[0]->GetUpdateExtent(); + //std::cout << "UpdateExtent:" << updateExtent[4] << " " << updateExtent[5] << std::endl; + + vtkImageData *output = this->GetOutput(); + output->SetUpdateExtentToWholeExtent(); // pipeline is not reexecuting properly without that... + + int numvol = 1; + if( this->LoadIconImage) + { + numvol = 2; + } + if( this->LoadOverlays ) + { + this->NumberOfOverlays = 1; + numvol = 3; + } + this->SetNumberOfOutputs(numvol); + assert( numvol == 1 || numvol == 3 ); + + // vtkImageReader2::ExecuteInformation only allocate first output + this->vtkImageReader2::ExecuteInformation(); + // Let's do the other ones ourselves: + for (int i=1; iOutputs[i]) + { + vtkImageData * img = vtkImageData::New(); + this->SetNthOutput(i, img); + img->Delete(); + } + vtkImageData *output = this->GetOutput(i); + switch(i) + { + case 0: + output->SetWholeExtent(this->DataExtent); + output->SetSpacing(this->DataSpacing); + output->SetOrigin(this->DataOrigin); + + output->SetScalarType(this->DataScalarType); + output->SetNumberOfScalarComponents(this->NumberOfScalarComponents); + break; + case IconImagePortNumber: + output->SetWholeExtent(this->IconImageDataExtent); + output->SetScalarType( VTK_UNSIGNED_CHAR ); + output->SetNumberOfScalarComponents( 1 ); + break; + //case OverlayPortNumber: + default: + output->SetWholeExtent(this->DataExtent[0],this->DataExtent[1], + this->DataExtent[2],this->DataExtent[3], + 0,0 + ); + //output->SetSpacing(this->DataSpacing); + //output->SetOrigin(this->DataOrigin); + output->SetScalarType(VTK_UNSIGNED_CHAR); + output->SetNumberOfScalarComponents(1); + break; + } + } +} + +void vtkGDCMThreadedImageReader::ExecuteData(vtkDataObject *output) +{ + //std::cerr << "ExecuteData" << std::endl; + // In VTK 4.2 AllocateOutputData is reexecuting ExecuteInformation which is bad ! + //vtkImageData *data = this->AllocateOutputData(output); + vtkImageData *res = vtkImageData::SafeDownCast(output); + res->SetExtent(res->GetUpdateExtent()); + res->AllocateScalars(); + + if( this->LoadIconImage ) + { +/* + vtkImageData *res = vtkImageData::SafeDownCast(this->Outputs[IconImagePortNumber]); + res->SetUpdateExtentToWholeExtent(); + + res->SetExtent(res->GetUpdateExtent()); + res->AllocateScalars(); +*/ + vtkErrorMacro( "IconImage are not supported" ); + } + if( this->LoadOverlays ) + { + vtkImageData *res = vtkImageData::SafeDownCast(this->Outputs[OverlayPortNumber]); + res->SetUpdateExtentToWholeExtent(); + + res->SetExtent(res->GetUpdateExtent()); + res->AllocateScalars(); + } + +// if( data->UpdateExtentIsEmpty() ) +// { +// return; +// } + //int * updateExtent = data->GetUpdateExtent(); + //std::cout << "UpdateExtent:" << updateExtent[4] << " " << updateExtent[5] << std::endl; + RequestDataCompat(); +} +#endif /* (VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 ) */ + +//---------------------------------------------------------------------------- +#if (VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 ) +int vtkGDCMThreadedImageReader::RequestInformation(vtkInformation *request, + vtkInformationVector **inputVector, + vtkInformationVector *outputVector) +{ + (void)request;(void)inputVector;(void)outputVector; + // Some information need to have been set outside (user specified) + //assert( this->GetOutput(0)->GetNumberOfPoints() != 0 ); + // For now only handles series: + if( !this->FileNames && !this->FileName ) + { + return 0; + } + + // This reader only implement case where image is flipped upside down + if( !this->FileLowerLeft ) + { + vtkErrorMacro( "You need to set the FileLowerLeft flag to On" ); + return 0; + } + + if( this->FileNames ) + { + int zmin = 0; + int zmax = 0; + zmax = (int)this->FileNames->GetNumberOfValues() - 1; + if( this->DataExtent[4] != zmin || this->DataExtent[5] != zmax ) + { + vtkErrorMacro( "Problem with extent" ); + return 0; + } + } + // Cannot deduce anything else otherwise... + + int numvol = 1; + if( this->LoadIconImage ) + { + numvol = 2; + return 0; + } + if( this->LoadOverlays ) + { + this->NumberOfOverlays = 1; + numvol = 3; + } + assert( numvol == 1 || numvol == 3 ); + this->SetNumberOfOutputPorts(numvol); + assert( this->DataScalarType != VTK_VOID ); + // For each output: + for(int i = 0; i < numvol; ++i) + { + // Allocate ! + if( !this->GetOutput(i) ) + { + vtkImageData *img = vtkImageData::New(); + this->GetExecutive()->SetOutputData(i, img ); + img->Delete(); + } + vtkInformation *outInfo = outputVector->GetInformationObject(i); + switch(i) + { + // root Pixel Data + case 0: + outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), this->DataExtent, 6); + //outInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(), this->DataExtent, 6); + outInfo->Set(vtkDataObject::SPACING(), this->DataSpacing, 3); + outInfo->Set(vtkDataObject::ORIGIN(), this->DataOrigin, 3); + vtkDataObject::SetPointDataActiveScalarInfo(outInfo, this->DataScalarType, this->NumberOfScalarComponents); + break; + // Icon Image + case IconImagePortNumber: + outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), this->IconImageDataExtent, 6); + vtkDataObject::SetPointDataActiveScalarInfo(outInfo, VTK_UNSIGNED_CHAR, 1); + break; + // Overlays: + //case OverlayPortNumber: + default: + outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), + this->DataExtent[0], this->DataExtent[1], + this->DataExtent[2], this->DataExtent[3], + 0,0 ); + vtkDataObject::SetPointDataActiveScalarInfo(outInfo, VTK_UNSIGNED_CHAR, 1); + break; + } + + } + + // Ok let's fill in the 'extra' info: + //FillMedicalImageInformation(reader); + + return 1; +} +#endif /*(VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 )*/ + +struct threadparams +{ + unsigned int threadid; + unsigned int nthreads; + const char **filenames; // array of filenames thread will process (order is important!) + unsigned int nfiles; // number of files the thread will process + char *scalarpointer; // start of the image buffer affected to the thread + char *overlayscalarpointer; + unsigned long len; // This is not required but useful to check if files are consistant + unsigned long overlaylen; + unsigned long totalfiles; // total number of files being processed (needed to compute progress) + pthread_mutex_t lock; // critial section for updating progress + vtkGDCMThreadedImageReader *reader; // needed for calling updateprogress +}; + +void *ReadFilesThread(void *voidparams) +{ + threadparams *params = static_cast (voidparams); + assert( params ); + + const unsigned int nfiles = params->nfiles; + assert( nfiles ); // + // pre compute progress delta for one file: + assert( params->totalfiles ); + const double progressdelta = 1. / (double)params->totalfiles; + for(unsigned int file = 0; file < nfiles; ++file) + { + const char *filename = params->filenames[file]; + //std::cerr << filename << std::endl; + + gdcm::ImageReader reader; + reader.SetFileName( filename ); + if( !reader.Read() ) + { + return 0; + } + + // Update progress + // We are done reading one file, let's shout it loud: + assert( params->reader->GetDebug() == 0 ); + const double progress = params->reader->GetProgress(); // other thread might have updated it also... + if( params->threadid == 0 ) + { + // IMPLEMENTATION NOTE (WARNING) + // I think this is ok to assume that thread are equally distributed and the progress of thread 0 + // actually represent nthreads times the local progress... + params->reader->UpdateProgress( progress + params->nthreads*progressdelta ); + } + // BUG: + //const double shift = params->reader->GetShift(); + //const double scale = params->reader->GetScale(); + // This is NOT safe to assume that shift/scale is constant thoughout the Series, this is better to + // read the shift/scale from the image + const gdcm::Image &image = reader.GetImage(); + + const double shift = image.GetIntercept(); + const double scale = image.GetSlope(); + + unsigned long len = image.GetBufferLength(); + // When not applying a transform: + // len -> sizeof stored image + // params->len sizeof world value image (after transform) + if( shift == 1 && scale == 0 ) + assert( len == params->len ); // that would be very bad + + char * pointer = params->scalarpointer; + //memcpy(pointer + file*len, tempimage, len); + // image + char *tempimage = pointer + file*params->len; + image.GetBuffer(tempimage); + // overlay + size_t numoverlays = image.GetNumberOfOverlays(); + //if( numoverlays && !params->reader->GetLoadOverlays() ) + //params->reader->SetNumberOfOverlays( numoverlays ); + if( numoverlays ) + { + const gdcm::Overlay& ov = image.GetOverlay(); + char * overlaypointer = params->overlayscalarpointer; + char *tempimage2 = overlaypointer + file*params->overlaylen; + memset(tempimage2,0,params->overlaylen); + assert( (unsigned long)ov.GetRows()*ov.GetColumns() <= params->overlaylen ); + if( !ov.GetUnpackBuffer(tempimage2, params->overlaylen) ) + { + vtkGenericWarningMacro( "Problem in GetUnpackBuffer" ); + } + } + //if( params->reader->GetShift() != 1 || params->reader->GetScale() != 0 ) + if( params->reader->GetUseShiftScale() && (shift != 1 || scale != 0) ) + { + const int shift_int = (int)shift; + const int scale_int = (int)scale; + if( scale == 1 && shift == (double)shift_int ) + { + unsigned short *out = (unsigned short*)(pointer + file * params->len); + unsigned short *pout = out; + for( ; pout != out + params->len / sizeof(unsigned short); ++pout ) + { + *pout = (unsigned short)(*pout + (short)shift); + } + } + else if ( shift == 0 && scale != (double)scale_int ) + { + // FIXME TODO tempimage stored the DICOM image at the beginning of the buffer, + // we could avoid duplicating the memory by iterating over the buffer starting + // from the end and filling out the target buffer by the end... + // scale is a float !! + char * duplicate = new char[len]; + memcpy(duplicate,tempimage,len); + const unsigned short *in = (unsigned short*)duplicate; + const unsigned short *pin = in; + float *out = (float*)(pointer + file * params->len); + float *pout = out; + for( ; pout != out + params->len / sizeof(float); ++pout ) + { + // scale is a double, but DICOM specify 32bits for floating point value + *pout = (float)((double)*pin * (float)scale); + ++pin; + } + //assert( pin == in + len / sizeof(unsigned short) ); + delete[] duplicate; + } + else + { + //assert( 0 && "Not Implemented" ); + vtkGenericWarningMacro( "Not Implemented" ); + } + } + } + + return voidparams; +} + +void ShowFilenames(const threadparams ¶ms) +{ + std::cout << "start" << std::endl; + for(unsigned int i = 0; i < params.nfiles; ++i) + { + const char *filename = params.filenames[i]; + std::cout << filename << std::endl; + } + std::cout << "end" << std::endl; +} + +//---------------------------------------------------------------------------- +void vtkGDCMThreadedImageReader::ReadFiles(unsigned int nfiles, const char *filenames[]) +{ + // image data: + vtkImageData *output = this->GetOutput(0); + assert( output->GetNumberOfPoints() % nfiles == 0 ); + const unsigned long len = output->GetNumberOfPoints() * output->GetScalarSize() / nfiles; + const unsigned long overlaylen = output->GetNumberOfPoints() / nfiles; + char * scalarpointer = static_cast(output->GetScalarPointer()); + // overlay data: + char * overlayscalarpointer = 0; + if( this->LoadOverlays ) + { + vtkImageData *overlayoutput = this->GetOutput(OverlayPortNumber); +#if (VTK_MAJOR_VERSION >= 6) + // allocation is done in RequestData +#else + overlayoutput->SetScalarTypeToUnsignedChar(); + overlayoutput->AllocateScalars(); +#endif + overlayscalarpointer = static_cast(overlayoutput->GetScalarPointer()); + } + +#ifdef _WIN32 + // mingw + SYSTEM_INFO info; + GetSystemInfo (&info); + const unsigned int nprocs = info.dwNumberOfProcessors; +#else +#ifdef _SC_NPROCESSORS_ONLN + const unsigned int nprocs = (unsigned int)sysconf( _SC_NPROCESSORS_ONLN ); +#else +#ifdef __APPLE__ + int count = 1; + size_t size = sizeof(count); + int res = sysctlbyname("hw.ncpu",&count,&size,NULL,0); + if( res == -1 ) + { + count = 1; + } + const unsigned int nprocs = (unsigned int)count; +#endif // __APPLE__ +#endif // _SC_NPROCESSORS_ONLN +#endif // _WIN32 + const unsigned int nthreads = std::min( nprocs, nfiles ); + threadparams *params = new threadparams[nthreads]; + + pthread_mutex_t lock; + pthread_mutex_init(&lock, NULL); + + pthread_t *pthread = new pthread_t[nthreads]; + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setscope(&attr, PTHREAD_SCOPE_PROCESS); + this->Debug = 0; + + // There is nfiles, and nThreads + assert( nfiles >= nthreads ); + const unsigned int partition = nfiles / nthreads; + assert( partition ); + for (unsigned int thread=0; thread < nthreads; ++thread) + { + params[thread].filenames = filenames + thread * partition; + params[thread].nfiles = partition; + if( thread == nthreads - 1 ) + { + // There is slightly more files to process in this thread: + params[thread].nfiles += nfiles % nthreads; + } + assert( thread * partition < nfiles ); + //ShowFilenames(params[thread]); + params[thread].scalarpointer = scalarpointer + thread * partition * len; + params[thread].overlayscalarpointer = overlayscalarpointer + thread * partition * len; + params[thread].len = len; + params[thread].overlaylen = overlaylen; + params[thread].totalfiles = nfiles; + params[thread].threadid = thread; + params[thread].nthreads = nthreads; + params[thread].lock = lock; + assert( this->Debug == 0 ); + params[thread].reader = this; + assert( params[thread].reader->Debug == 0 ); + // start thread: + //int res = pthread_create( &pthread[thread], NULL, ReadFilesThread, ¶ms[thread]); + int res = pthread_create( &pthread[thread], &attr, ReadFilesThread, ¶ms[thread]); + if( res ) + { + std::cerr << "Unable to start a new thread, pthread returned: " << res << std::endl; + assert(0); + } + } +// DEBUG + unsigned int total = 0; + for (unsigned int thread=0; thread < nthreads; ++thread) + { + total += params[thread].nfiles; + } + assert( total == nfiles ); +// END DEBUG + + for (unsigned int thread=0;threadSetInput( output ); + writer->SetFileName( "/tmp/threadgdcm.vtk" ); + writer->SetFileTypeToBinary(); + //writer->Write(); + writer->Delete(); +#endif + + //output->Print( std::cout ); +} + +//---------------------------------------------------------------------------- +#if (VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 ) +int vtkGDCMThreadedImageReader::RequestData(vtkInformation *vtkNotUsed(request), + vtkInformationVector **vtkNotUsed(inputVector), + vtkInformationVector *outputVector) +{ + //this->UpdateProgress(0.2); + + // Make sure the output dimension is OK, and allocate its scalars + for(int i = 0; i < this->GetNumberOfOutputPorts(); ++i) + { +#if (VTK_MAJOR_VERSION >= 6) + vtkInformation* outInfo = outputVector->GetInformationObject(i); + vtkImageData *data = static_cast(outInfo->Get(vtkDataObject::DATA_OBJECT())); + // Make sure that this output is an image + if (data) + { + int extent[6]; + outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(), extent); + this->AllocateOutputData(data, outInfo, extent); + } +#else + (void)outputVector; + // Copy/paste from vtkImageAlgorithm::AllocateScalars. Cf. "this needs to be fixed -Ken" + vtkStreamingDemandDrivenPipeline *sddp = + vtkStreamingDemandDrivenPipeline::SafeDownCast(this->GetExecutive()); + if (sddp) + { + int extent[6]; + sddp->GetOutputInformation(i)->Get(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(),extent); + this->GetOutput(i)->SetExtent(extent); + } + this->GetOutput(i)->AllocateScalars(); +#endif + } + RequestDataCompat(); + return 1; +} +#endif /*(VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 )*/ + +void vtkGDCMThreadedImageReader::RequestDataCompat() +{ + int *dext = this->GetDataExtent(); + if( this->FileNames ) + { + // Make sure that each file is single slice + assert( dext[5] - dext[4] == this->FileNames->GetNumberOfValues() - 1 ); (void)dext; + const vtkIdType nfiles = this->FileNames->GetNumberOfValues(); + const char **filenames = new const char* [ nfiles ]; + for(unsigned int i = 0; i < nfiles; ++i) + { + filenames[i] = this->FileNames->GetValue( i ); + //std::cerr << filenames[i] << std::endl; + } + ReadFiles((unsigned int)nfiles, filenames); + delete[] filenames; + } + else if( this->FileName ) + { + // File can be a volume + const char *filename = this->FileName; + ReadFiles(1, &filename); + } + else + { + // Impossible case since ExecuteInformation would have failed earlier... + assert( 0 && "Impossible happen" ); + } + +} + +//---------------------------------------------------------------------------- +void vtkGDCMThreadedImageReader::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os,indent); +} diff --git a/gdcm/Utilities/VTK/vtkGDCMThreadedImageReader.h b/gdcm/Utilities/VTK/vtkGDCMThreadedImageReader.h new file mode 100644 index 0000000..dc38bec --- /dev/null +++ b/gdcm/Utilities/VTK/vtkGDCMThreadedImageReader.h @@ -0,0 +1,93 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +// .NAME vtkGDCMThreadedImageReader - read DICOM files with multiple threads +// .SECTION Description +// vtkGDCMThreadedImageReader is a source object that reads some DICOM files +// This reader is threaded. Meaning that on a multiple core CPU with N cpu, it will +// read approx N times faster than when reading in a single thread. +// +// .SECTION Warning: Advanced users only. Do not use this class in the general case, +// you have to understand how physicaly medium works first (sequential reading for +// instance) before playing with this class +// +// .SECTION Implementation note: when FileLowerLeft is set to on the image is not flipped +// upside down as VTK would expect, use this option only if you know what you are doing +// +// .SECTION FIXME: need to implement the other mode where FileLowerLeft is set to OFF +// +// .SECTION FIXME: you need to call SetFileName when reading a volume file (multiple slices DICOM) +// since SetFileNames expect each single file to be single slice (see parent class) +// +// .SECTION BUG: you should really consider using vtkGDCMThreadedImageReader2 instead ! +// +// .SECTION See Also +// vtkMedicalImageReader2 vtkMedicalImageProperties vtkGDCMThreadedImageReader2 + +#ifndef VTKGDCMTHREADEDIMAGEREADER_H +#define VTKGDCMTHREADEDIMAGEREADER_H + +#include "vtkGDCMImageReader.h" + +class VTK_EXPORT vtkGDCMThreadedImageReader : public vtkGDCMImageReader +{ +public: + static vtkGDCMThreadedImageReader *New(); + vtkTypeRevisionMacro(vtkGDCMThreadedImageReader,vtkGDCMImageReader); + virtual void PrintSelf(ostream& os, vtkIndent indent); + + // Description: + // Explicitely set the Rescale Intercept (0028,1052) + vtkSetMacro(Shift,double); + + // Description: + // Explicitely get/set the Rescale Slope (0028,1053) + vtkSetMacro(Scale,double); + + // Description: + // Determine whether or not reader should use value from Shift/Scale + // Default is 1 + vtkSetMacro(UseShiftScale,int); + vtkGetMacro(UseShiftScale,int); + vtkBooleanMacro(UseShiftScale,int); + + // Within this class this is allowed to set the Number of Overlays from outside + //vtkSetMacro(NumberOfOverlays,int); + +protected: + vtkGDCMThreadedImageReader(); + ~vtkGDCMThreadedImageReader(); + +#if (VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 ) + int RequestInformation(vtkInformation *request, + vtkInformationVector **inputVector, + vtkInformationVector *outputVector); + int RequestData(vtkInformation *request, + vtkInformationVector **inputVector, + vtkInformationVector *outputVector); +#else /*(VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 )*/ + void ExecuteInformation(); + void ExecuteData(vtkDataObject *out); +#endif /*(VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 )*/ + + void ReadFiles(unsigned int nfiles, const char *filenames[]); + void RequestDataCompat(); + +private: + vtkGDCMThreadedImageReader(const vtkGDCMThreadedImageReader&); // Not implemented. + void operator=(const vtkGDCMThreadedImageReader&); // Not implemented. + + int UseShiftScale; +}; + +#endif diff --git a/gdcm/Utilities/VTK/vtkGDCMThreadedImageReader2.cxx b/gdcm/Utilities/VTK/vtkGDCMThreadedImageReader2.cxx new file mode 100644 index 0000000..9a856bc --- /dev/null +++ b/gdcm/Utilities/VTK/vtkGDCMThreadedImageReader2.cxx @@ -0,0 +1,381 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkGDCMThreadedImageReader2.h" + +#include "vtkObjectFactory.h" +#include "vtkImageData.h" +#include "vtkStringArray.h" +#include "vtkInformationVector.h" +#include "vtkInformation.h" +#include "vtkDemandDrivenPipeline.h" +#include "vtkStreamingDemandDrivenPipeline.h" + +#include "gdcmImageReader.h" + +#include + +vtkCxxRevisionMacro(vtkGDCMThreadedImageReader2, "$Revision: 1.1 $") +vtkStandardNewMacro(vtkGDCMThreadedImageReader2) +vtkCxxSetObjectMacro(vtkGDCMThreadedImageReader2,FileNames,vtkStringArray) + +// Output Ports are as follow: +// #0: The image/volume (root PixelData element) +// #1: (if present): the Icon Image (0088,0200) +// #2-xx: (if present): the Overlay (60xx,3000) + +#define IconImagePortNumber 1 +#define OverlayPortNumber 2 + +vtkGDCMThreadedImageReader2::vtkGDCMThreadedImageReader2() +{ + this->SetNumberOfInputPorts(0); + this->FileLowerLeft = 1; + this->FileName = NULL; + this->FileNames = vtkStringArray::New(); + this->LoadIconImage = 0; + memset(this->DataExtent,0,6*sizeof(*DataExtent)); + this->LoadOverlays = 0; + this->NumberOfOverlays = 0; + this->DataScalarType = VTK_VOID; + + this->NumberOfScalarComponents = 1; + this->DataSpacing[0] = DataSpacing[1] = DataSpacing[2] = 1; + this->DataOrigin[0] = DataOrigin[1] = DataOrigin[2] = 0; + memset(this->IconImageDataExtent,0,6*sizeof(*IconImageDataExtent)); + this->Shift = 0.; + this->Scale = 1.; + this->UseShiftScale = 1; +} + +//---------------------------------------------------------------------------- +vtkGDCMThreadedImageReader2::~vtkGDCMThreadedImageReader2() +{ + if( this->FileNames ) + { + this->FileNames->Delete(); + } + this->SetFileName(NULL); +} + +//---------------------------------------------------------------------------- +const char *vtkGDCMThreadedImageReader2::GetFileName(int i) +{ + return this->FileNames->GetValue( i ); +} + +//---------------------------------------------------------------------------- +void vtkGDCMThreadedImageReader2::SetFileName(const char *filename) +{ + if( !filename ) + { + return; + } + //this->FileNames->Clear(); + this->FileNames->InsertNextValue( filename ); + assert( this->FileNames->GetNumberOfValues() == 1 ); +} + +//---------------------------------------------------------------------------- +// Description: +// This templated function executes the filter for any type of data. +template +void vtkGDCMThreadedImageReader2Execute(vtkGDCMThreadedImageReader2 *self, + vtkImageData **inDatas, int numFiles, vtkImageData *outData, + int outExt[6], int id, T*) +{ + (void)numFiles; (void)inDatas; + //printf("outExt:%d,%d,%d,%d,%d,%d\n", + // outExt[0], outExt[1], outExt[2], outExt[3], outExt[4], outExt[5]); + // FIXME: + // The code could be a little tidier, all I am trying to do here is differenciate the + // case where we have a series of 2D files and the case where we have a single multi-frames + // files... + vtkIdType maxfiles = self->GetFileNames()->GetNumberOfValues(); + const unsigned long params_len = self->GetOutput()->GetNumberOfPoints() * self->GetOutput()->GetScalarSize() / maxfiles; + for( int i = outExt[4]; i <= outExt[5] && i < maxfiles; ++i ) + { + assert( i < maxfiles ); + const char *filename = self->GetFileNames()->GetValue( i ); + //ReadOneFile( filename ); + //outData->GetPointData()->GetScalars()->SetName("GDCMImage"); + + if( id == 0 ) + { + // we only consider outExt here for computing the progress, while in fact we should really + // consider numFiles to compute exact update progress...oh well let's assume this is almost + // correct. + self->UpdateProgress(float(i)/float(outExt[5]-outExt[4]+1)); + } + + + //char * pointer = static_cast(outData->GetScalarPointerForExtent(outExt)); + char * pointer = static_cast(outData->GetScalarPointer(0,0,i)); + //printf("pointer:%i\n",*pointer); + gdcm::ImageReader reader; + reader.SetFileName( filename ); + if( !reader.Read() ) + { + vtkGenericWarningMacro( "Could not read: " << filename ); + //memset(pointer,); + return; + } + const gdcm::Image &image = reader.GetImage(); + unsigned long len = image.GetBufferLength(); + image.GetBuffer(pointer); + + size_t numoverlays = image.GetNumberOfOverlays(); + if( numoverlays ) + { + vtkImageData *vtkimage = self->GetOutput(OverlayPortNumber); + const gdcm::Overlay& ov = image.GetOverlay(); + const size_t overlaylen = (outExt[1]-outExt[0])*(outExt[3]-outExt[2]); + char * overlaypointer = static_cast(vtkimage->GetScalarPointer()); + if( !ov.GetUnpackBuffer(overlaypointer, overlaylen) ) + { + vtkGenericWarningMacro( "Problem in GetUnpackBuffer" ); + } + } + + const double shift = image.GetIntercept(); + const double scale = image.GetSlope(); + if( self->GetShift() != shift || self->GetScale() != scale ) + { + vtkGenericWarningMacro( "Specified Shift/Scale do not match file. This is not supported" ); + } + + //if( shift != 1 || scale != 0 ) + if( self->GetUseShiftScale() && (shift != 1 || scale != 0) ) + { + const int shift_int = (int)shift; + const int scale_int = (int)scale; + if( scale == 1 && shift == (double)shift_int ) + { + unsigned short *out = (unsigned short*)pointer; + unsigned short *pout = out; + for( ; pout != out + params_len / sizeof(unsigned short); ++pout ) + { + *pout = (unsigned short)(*pout + (short)shift); + } + } + else if ( shift == 0 && scale != (double)scale_int ) + { + // FIXME TODO tempimage stored the DICOM image at the beginning of the buffer, + // we could avoid duplicating the memory by iterating over the buffer starting + // from the end and filling out the target buffer by the end... + // scale is a float !! + char * duplicate = new char[len]; + memcpy(duplicate,pointer,len); + const unsigned short *in = (unsigned short*)duplicate; + const unsigned short *pin = in; + float *out = (float*)pointer; + float *pout = out; + for( ; pout != out + params_len / sizeof(float); ++pout ) + { + // scale is a double, but to be backward compatible we need the explicit cast + *pout = (float)((double)*pin * (float)scale); + ++pin; + } + //assert( pin == in + len / sizeof(unsigned short) ); + delete[] duplicate; + } + else + { + //assert( 0 && "Not Implemented" ); + vtkGenericWarningMacro( "Not Implemented" ); + } + } + } + +} + +//---------------------------------------------------------------------------- +int vtkGDCMThreadedImageReader2::RequestInformation ( + vtkInformation * request, + vtkInformationVector** inputVector, + vtkInformationVector *outputVector) +{ + (void)request;(void)inputVector;(void)outputVector; + // Some information need to have been set outside (user specified) + //assert( this->GetOutput(0)->GetNumberOfPoints() != 0 ); + // For now only handles series: + if( !this->FileNames && !this->FileName ) + { + return 0; + } + + // This reader only implement case where image is flipped upside down + if( !this->FileLowerLeft ) + { + vtkErrorMacro( "You need to set the FileLowerLeft flag to On" ); + return 0; + } + + /* + if( this->FileNames ) + { + int zmin = 0; + int zmax = 0; + zmax = this->FileNames->GetNumberOfValues() - 1; + if( this->DataExtent[4] != zmin || this->DataExtent[5] != zmax ) + { + vtkErrorMacro( "Problem with extent" ); + return 0; + } + } + */ + // Cannot deduce anything else otherwise... + + int numvol = 1; + if( this->LoadIconImage ) + { + numvol = 2; + return 0; + } + if( this->LoadOverlays ) + { + this->NumberOfOverlays = 1; + numvol = 3; + } + assert( numvol == 1 || numvol == 3 ); + this->SetNumberOfOutputPorts(numvol); + assert( this->DataScalarType != VTK_VOID ); + // For each output: + for(int i = 0; i < numvol; ++i) + { + // Allocate ! + if( !this->GetOutput(i) ) + { + vtkImageData *img = vtkImageData::New(); + this->GetExecutive()->SetOutputData(i, img ); + img->Delete(); + } + vtkInformation *outInfo = outputVector->GetInformationObject(i); + switch(i) + { + // root Pixel Data + case 0: + outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), this->DataExtent, 6); + //outInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(), this->DataExtent, 6); + outInfo->Set(vtkDataObject::SPACING(), this->DataSpacing, 3); + outInfo->Set(vtkDataObject::ORIGIN(), this->DataOrigin, 3); + vtkDataObject::SetPointDataActiveScalarInfo(outInfo, this->DataScalarType, this->NumberOfScalarComponents); + break; + // Icon Image + case IconImagePortNumber: + outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), this->IconImageDataExtent, 6); + vtkDataObject::SetPointDataActiveScalarInfo(outInfo, VTK_UNSIGNED_CHAR, 1); + break; + // Overlays: + //case OverlayPortNumber: + default: + outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), + this->DataExtent[0], this->DataExtent[1], + this->DataExtent[2], this->DataExtent[3], + 0,0 ); + vtkDataObject::SetPointDataActiveScalarInfo(outInfo, VTK_UNSIGNED_CHAR, 1); + break; + } + + } + + // Ok let's fill in the 'extra' info: + //FillMedicalImageInformation(reader); + + return 1; +} + +// For streaming and threads. Splits output update extent into num pieces. +// This method needs to be called num times. Results must not overlap for +// consistent starting extent. Subclass can override this method. +// This method returns the number of peices resulting from a successful split. +// This can be from 1 to "total". +// If 1 is returned, the extent cannot be split. +int vtkGDCMThreadedImageReader2::SplitExtent(int splitExt[6], int startExt[6], + int num, int total) +{ + memcpy(splitExt, startExt, 6 * sizeof(*splitExt)); + + vtkDebugMacro("SplitExtent: ( " << startExt[0] << ", " << startExt[1] << ", " + << startExt[2] << ", " << startExt[3] << ", " + << startExt[4] << ", " << startExt[5] << "), " + << num << " of " << total); + + // We should only split along the Z direction (only in the case of multiple files...) + int splitAxis = 2; + int min = startExt[4]; + int max = startExt[5]; + if( min >= max ) + { + assert ( min == 0 ); + assert ( max == 0 ); + return 1; + } + + // If single file always says 1: + // FIXME need to handle series of 3D files too... + if( this->GetFileNames()->GetNumberOfValues() == 1 ) + { + return 1; + } + // else normal SplitExtent as copied from vtkThreadedImageAlgorithm + + // determine the actual number of pieces that will be generated + int range = max - min + 1; + int valuesPerThread = static_cast(ceil(range/static_cast(total))); + int maxThreadIdUsed = static_cast(ceil(range/static_cast(valuesPerThread))) - 1; + if (num < maxThreadIdUsed) + { + splitExt[splitAxis*2] = splitExt[splitAxis*2] + num*valuesPerThread; + splitExt[splitAxis*2+1] = splitExt[splitAxis*2] + valuesPerThread - 1; + } + if (num == maxThreadIdUsed) + { + splitExt[splitAxis*2] = splitExt[splitAxis*2] + num*valuesPerThread; + } + + + return maxThreadIdUsed + 1; +} + +void vtkGDCMThreadedImageReader2::ThreadedRequestData ( + vtkInformation * vtkNotUsed( request ), + vtkInformationVector** vtkNotUsed( inputVector ), + vtkInformationVector * vtkNotUsed( outputVector ), + vtkImageData ***inData, + vtkImageData **outData, + int outExt[6], int id) +{ + (void)inData; + // printf("ThreadedRequestData::outExt:%d,%d,%d,%d,%d,%d\n", + // outExt[0], outExt[1], outExt[2], outExt[3], outExt[4], outExt[5]); + + assert( this->DataScalarType != VTK_VOID ); + + switch (this->GetDataScalarType()) + { + vtkTemplateMacro( + vtkGDCMThreadedImageReader2Execute(this , 0 , 3, + outData[0], outExt, id, static_cast(0)) + ); + default: + vtkErrorMacro(<< "Execute: Unknown ScalarType"); + return; + } +} + +//---------------------------------------------------------------------------- +void vtkGDCMThreadedImageReader2::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os,indent); +} diff --git a/gdcm/Utilities/VTK/vtkGDCMThreadedImageReader2.h b/gdcm/Utilities/VTK/vtkGDCMThreadedImageReader2.h new file mode 100644 index 0000000..c5ecf7a --- /dev/null +++ b/gdcm/Utilities/VTK/vtkGDCMThreadedImageReader2.h @@ -0,0 +1,150 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +// .NAME vtkGDCMThreadedImageReader2 - read DICOM files with multiple threads +// .SECTION Description +// vtkGDCMThreadedImageReader2 is a source object that reads some DICOM files +// This reader is threaded. Meaning that on a multiple core CPU with N cpu, it will +// read approx N times faster than when reading in a single thread assuming the IO is +// not a bottleneck operation. +// If looking for a single threaded class see: vtkGDCMImageReader +// +// .SECTION Warning: Advanced users only. Do not use this class in the general case, +// you have to understand how physicaly medium works first (sequential reading for +// instance) before playing with this class +// +// .SECTION Implementation note: when FileLowerLeft is set to on the image is not flipped +// upside down as VTK would expect, use this option only if you know what you are doing +// +// .SECTION FIXME: need to implement the other mode where FileLowerLeft is set to OFF +// +// .SECTION FIXME: need to implement reading of series of 3D files +// +// .SECTION Implementation note: this class is meant to superseed vtkGDCMThreadedImageReader +// because it had support for ProgressEvent support even from python layer. There is a +// subtle trick down in the threading mechanism in VTK were the main thread (talking to the +// python interpreter) is also part of the execution process (and the N-1 other thread +// are just there to execute the remaining of ThreadedRequestData), this separation into +// two types of thread is necessary to acheive a working implementation of UpdateProgress + +// .SECTION See Also +// vtkMedicalImageReader2 vtkMedicalImageProperties vtkGDCMImageReader + +#ifndef VTKGDCMTHREADEDIMAGEREADER2_H +#define VTKGDCMTHREADEDIMAGEREADER2_H + +#include "vtkThreadedImageAlgorithm.h" + +class vtkStringArray; +class VTK_EXPORT vtkGDCMThreadedImageReader2 : public vtkThreadedImageAlgorithm +{ +public: + static vtkGDCMThreadedImageReader2 *New(); + vtkTypeRevisionMacro(vtkGDCMThreadedImageReader2,vtkThreadedImageAlgorithm); + virtual void PrintSelf(ostream& os, vtkIndent indent); + + vtkGetMacro(FileLowerLeft,int); + vtkSetMacro(FileLowerLeft,int); + vtkBooleanMacro(FileLowerLeft,int); + + vtkGetMacro(NumberOfOverlays,int); + + vtkSetMacro(DataScalarType,int); + vtkGetMacro(DataScalarType,int); + + vtkSetMacro(NumberOfScalarComponents,int); + vtkGetMacro(NumberOfScalarComponents,int); + + vtkGetMacro(LoadOverlays,int); + vtkSetMacro(LoadOverlays,int); + vtkBooleanMacro(LoadOverlays,int); + + vtkSetVector6Macro(DataExtent,int); + vtkGetVector6Macro(DataExtent,int); + + vtkSetVector3Macro(DataOrigin,double); + vtkGetVector3Macro(DataOrigin,double); + + vtkSetVector3Macro(DataSpacing,double); + vtkGetVector3Macro(DataSpacing,double); + + //vtkGetStringMacro(FileName); + //vtkSetStringMacro(FileName); + virtual const char *GetFileName(int i = 0); + virtual void SetFileName(const char *filename); + + virtual void SetFileNames(vtkStringArray*); + vtkGetObjectMacro(FileNames, vtkStringArray); + + int SplitExtent(int splitExt[6], int startExt[6], + int num, int total); + + // Description: + // Explicitely set the Rescale Intercept (0028,1052) + vtkSetMacro(Shift,double); + vtkGetMacro(Shift,double); + + // Description: + // Explicitely get/set the Rescale Slope (0028,1053) + vtkSetMacro(Scale,double); + vtkGetMacro(Scale,double); + + // Description: + // Determine whether or not reader should use value from Shift/Scale + // Default is 1 + vtkSetMacro(UseShiftScale,int); + vtkGetMacro(UseShiftScale,int); + vtkBooleanMacro(UseShiftScale,int); + +protected: + vtkGDCMThreadedImageReader2(); + ~vtkGDCMThreadedImageReader2(); + + int RequestInformation(vtkInformation *request, + vtkInformationVector **inputVector, + vtkInformationVector *outputVector); + +protected: + void ThreadedRequestData ( + vtkInformation * request, + vtkInformationVector** inputVector, + vtkInformationVector * outputVector, + vtkImageData ***inData, + vtkImageData **outData, + int outExt[6], int id); + +private: + int FileLowerLeft; + char *FileName; + vtkStringArray *FileNames; + int LoadIconImage; + int DataExtent[6]; + int LoadOverlays; + int NumberOfOverlays; + int DataScalarType; + + int NumberOfScalarComponents; + double DataSpacing[3]; + double DataOrigin[3]; + int IconImageDataExtent[6]; + + double Shift; + double Scale; + int UseShiftScale; + +private: + vtkGDCMThreadedImageReader2(const vtkGDCMThreadedImageReader2&); // Not implemented. + void operator=(const vtkGDCMThreadedImageReader2&); // Not implemented. +}; + +#endif diff --git a/gdcm/Utilities/VTK/vtkImageColorViewer.cxx b/gdcm/Utilities/VTK/vtkImageColorViewer.cxx new file mode 100644 index 0000000..e1fa303 --- /dev/null +++ b/gdcm/Utilities/VTK/vtkImageColorViewer.cxx @@ -0,0 +1,966 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/*========================================================================= + + Portions of this file are subject to the VTK Toolkit Version 3 copyright. + + Program: Visualization Toolkit + Module: $RCSfile: vtkImageColorViewer.cxx,v $ + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkImageColorViewer.h" + +#include "vtkCamera.h" +#include "vtkCommand.h" +#include "vtkImageActor.h" +#include "vtkImageData.h" +#if (VTK_MAJOR_VERSION >= 6) +#include "vtkImageMapper3D.h" +#endif +#include "vtkImageData.h" +#include "vtkImageMapToWindowLevelColors2.h" +#include "vtkInteractorStyleImage.h" +#include "vtkObjectFactory.h" +#include "vtkRenderWindow.h" +#include "vtkRenderWindowInteractor.h" +#include "vtkRenderer.h" +#include "vtkPolyDataMapper.h" +#if (VTK_MAJOR_VERSION >= 5) +#include "vtkStreamingDemandDrivenPipeline.h" +#include "vtkInformation.h" +#endif + +vtkCxxRevisionMacro(vtkImageColorViewer, "$Revision: 1.3 $") +vtkStandardNewMacro(vtkImageColorViewer) + +//---------------------------------------------------------------------------- +vtkImageColorViewer::vtkImageColorViewer() +{ + this->RenderWindow = NULL; + this->Renderer = NULL; + this->ImageActor = vtkImageActor::New(); + this->OverlayImageActor = vtkImageActor::New(); + this->WindowLevel = vtkImageMapToWindowLevelColors2::New(); + this->Interactor = NULL; + this->InteractorStyle = NULL; + + this->Slice = 0; + this->FirstRender = 1; + this->SliceOrientation = vtkImageColorViewer::SLICE_ORIENTATION_XY; + + // Setup the pipeline + + vtkRenderWindow *renwin = vtkRenderWindow::New(); + this->SetRenderWindow(renwin); + renwin->Delete(); + + vtkRenderer *ren = vtkRenderer::New(); + this->SetRenderer(ren); + ren->Delete(); + + this->InstallPipeline(); +} + +//---------------------------------------------------------------------------- +vtkImageColorViewer::~vtkImageColorViewer() +{ + if (this->WindowLevel) + { + this->WindowLevel->Delete(); + this->WindowLevel = NULL; + } + + if (this->ImageActor) + { + this->ImageActor->Delete(); + this->ImageActor = NULL; + } + + if (this->OverlayImageActor) + { + this->OverlayImageActor->Delete(); + this->OverlayImageActor = NULL; + } + + if (this->Renderer) + { + this->Renderer->Delete(); + this->Renderer = NULL; + } + + if (this->RenderWindow) + { + this->RenderWindow->Delete(); + this->RenderWindow = NULL; + } + + if (this->Interactor) + { + this->Interactor->Delete(); + this->Interactor = NULL; + } + + if (this->InteractorStyle) + { + this->InteractorStyle->Delete(); + this->InteractorStyle = NULL; + } +} + +//---------------------------------------------------------------------------- +void vtkImageColorViewer::SetupInteractor(vtkRenderWindowInteractor *arg) +{ + if (this->Interactor == arg) + { + return; + } + + this->UnInstallPipeline(); + + if (this->Interactor) + { + this->Interactor->UnRegister(this); + } + + this->Interactor = arg; + + if (this->Interactor) + { + this->Interactor->Register(this); + } + + this->InstallPipeline(); + + if (this->Renderer) + { + this->Renderer->GetActiveCamera()->ParallelProjectionOn(); + } +} + +//---------------------------------------------------------------------------- +void vtkImageColorViewer::SetRenderWindow(vtkRenderWindow *arg) +{ + if (this->RenderWindow == arg) + { + return; + } + + this->UnInstallPipeline(); + + if (this->RenderWindow) + { + this->RenderWindow->UnRegister(this); + } + + this->RenderWindow = arg; + + if (this->RenderWindow) + { + this->RenderWindow->Register(this); + } + + this->InstallPipeline(); +} + +//---------------------------------------------------------------------------- +void vtkImageColorViewer::SetRenderer(vtkRenderer *arg) +{ + if (this->Renderer == arg) + { + return; + } + + this->UnInstallPipeline(); + + if (this->Renderer) + { + this->Renderer->UnRegister(this); + } + + this->Renderer = arg; + + if (this->Renderer) + { + this->Renderer->Register(this); + } + + this->InstallPipeline(); + this->UpdateOrientation(); +} + +//---------------------------------------------------------------------------- +void vtkImageColorViewer::SetSize(int a,int b) +{ + this->RenderWindow->SetSize(a, b); +} + +//---------------------------------------------------------------------------- +int* vtkImageColorViewer::GetSize() +{ + return this->RenderWindow->GetSize(); +} + +//---------------------------------------------------------------------------- +void vtkImageColorViewer::GetSliceRange(int &min, int &max) +{ +#if (VTK_MAJOR_VERSION >= 6) + vtkAlgorithm *input = this->GetInputAlgorithm(); +#else + vtkImageData *input = this->GetInput(); +#endif + if (input) + { + input->UpdateInformation(); +#if (VTK_MAJOR_VERSION >= 6) + int *w_ext = input->GetOutputInformation(0)->Get( + vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT()); +#else + int *w_ext = input->GetWholeExtent(); +#endif + min = w_ext[this->SliceOrientation * 2]; + max = w_ext[this->SliceOrientation * 2 + 1]; + } +} + +//---------------------------------------------------------------------------- +int* vtkImageColorViewer::GetSliceRange() +{ +#if (VTK_MAJOR_VERSION >= 6) + vtkAlgorithm *input = this->GetInputAlgorithm(); +#else + vtkImageData *input = this->GetInput(); +#endif + if (input) + { + input->UpdateInformation(); +#if (VTK_MAJOR_VERSION >= 6) + return input->GetOutputInformation(0)->Get( + vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT()) + + this->SliceOrientation * 2; +#else + return input->GetWholeExtent() + this->SliceOrientation * 2; +#endif + } + return NULL; +} + +//---------------------------------------------------------------------------- +int vtkImageColorViewer::GetSliceMin() +{ + int *range = this->GetSliceRange(); + if (range) + { + return range[0]; + } + return 0; +} + +//---------------------------------------------------------------------------- +int vtkImageColorViewer::GetSliceMax() +{ + int *range = this->GetSliceRange(); + if (range) + { + return range[1]; + } + return 0; +} + +//---------------------------------------------------------------------------- +void vtkImageColorViewer::SetSlice(int slice) +{ + int *range = this->GetSliceRange(); + if (range) + { + if (slice < range[0]) + { + slice = range[0]; + } + else if (slice > range[1]) + { + slice = range[1]; + } + } + + if (this->Slice == slice) + { + return; + } + + this->Slice = slice; + this->Modified(); + + this->UpdateDisplayExtent(); + this->Render(); +} + +//---------------------------------------------------------------------------- +void vtkImageColorViewer::SetSliceOrientation(int orientation) +{ + if (orientation < vtkImageColorViewer::SLICE_ORIENTATION_YZ || + orientation > vtkImageColorViewer::SLICE_ORIENTATION_XY) + { + vtkErrorMacro("Error - invalid slice orientation " << orientation); + return; + } + + if (this->SliceOrientation == orientation) + { + return; + } + + this->SliceOrientation = orientation; + + // Update the viewer + + int *range = this->GetSliceRange(); + if (range) + { + this->Slice = static_cast((range[0] + range[1]) * 0.5); + } + + this->UpdateOrientation(); + this->UpdateDisplayExtent(); + + if (this->Renderer && this->GetInput()) + { + double scale = this->Renderer->GetActiveCamera()->GetParallelScale(); + this->Renderer->ResetCamera(); + this->Renderer->GetActiveCamera()->SetParallelScale(scale); + } + + this->Render(); +} + +//---------------------------------------------------------------------------- +void vtkImageColorViewer::UpdateOrientation() +{ + // Set the camera position + + vtkCamera *cam = this->Renderer ? this->Renderer->GetActiveCamera() : NULL; + if (cam) + { + switch (this->SliceOrientation) + { + case vtkImageColorViewer::SLICE_ORIENTATION_XY: + cam->SetFocalPoint(0,0,0); + cam->SetPosition(0,0,1); // -1 if medical ? + cam->SetViewUp(0,1,0); + break; + + case vtkImageColorViewer::SLICE_ORIENTATION_XZ: + cam->SetFocalPoint(0,0,0); + cam->SetPosition(0,-1,0); // 1 if medical ? + cam->SetViewUp(0,0,1); + break; + + case vtkImageColorViewer::SLICE_ORIENTATION_YZ: + cam->SetFocalPoint(0,0,0); + cam->SetPosition(1,0,0); // -1 if medical ? + cam->SetViewUp(0,0,1); + break; + } + } +} + +//---------------------------------------------------------------------------- +void vtkImageColorViewer::UpdateDisplayExtent() +{ +#if (VTK_MAJOR_VERSION >= 6) + vtkAlgorithm *input = this->GetInputAlgorithm(); +#else + vtkImageData *input = this->GetInput(); +#endif + if (!input || !this->ImageActor) + { + return; + } + + input->UpdateInformation(); +#if (VTK_MAJOR_VERSION >= 6) + vtkInformation* outInfo = input->GetOutputInformation(0); + int *w_ext = outInfo->Get( + vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT()); +#else + int *w_ext = input->GetWholeExtent(); +#endif + + // Is the slice in range ? If not, fix it + + int slice_min = w_ext[this->SliceOrientation * 2]; + int slice_max = w_ext[this->SliceOrientation * 2 + 1]; + if (this->Slice < slice_min || this->Slice > slice_max) + { + this->Slice = static_cast((slice_min + slice_max) * 0.5); + } + + // Set the image actor + + switch (this->SliceOrientation) + { + case vtkImageColorViewer::SLICE_ORIENTATION_XY: + this->ImageActor->SetDisplayExtent( + w_ext[0], w_ext[1], w_ext[2], w_ext[3], this->Slice, this->Slice); + break; + + case vtkImageColorViewer::SLICE_ORIENTATION_XZ: + this->ImageActor->SetDisplayExtent( + w_ext[0], w_ext[1], this->Slice, this->Slice, w_ext[4], w_ext[5]); + break; + + case vtkImageColorViewer::SLICE_ORIENTATION_YZ: + this->ImageActor->SetDisplayExtent( + this->Slice, this->Slice, w_ext[2], w_ext[3], w_ext[4], w_ext[5]); + break; + } + + // Figure out the correct clipping range + + if (this->Renderer) + { + if (this->InteractorStyle && + this->InteractorStyle->GetAutoAdjustCameraClippingRange()) + { + this->Renderer->ResetCameraClippingRange(); + } + else + { + vtkCamera *cam = this->Renderer->GetActiveCamera(); + if (cam) + { + double bounds[6]; + this->ImageActor->GetBounds(bounds); + double spos = (double)bounds[this->SliceOrientation * 2]; + double cpos = (double)cam->GetPosition()[this->SliceOrientation]; + double range = fabs(spos - cpos); +#if (VTK_MAJOR_VERSION >= 6) + double *spacing = outInfo->Get(vtkDataObject::SPACING()); +#else + double *spacing = input->GetSpacing(); +#endif + double avg_spacing = + ((double)spacing[0] + (double)spacing[1] + (double)spacing[2]) / 3.0; + cam->SetClippingRange( + range - avg_spacing * 3.0, range + avg_spacing * 3.0); + } + } + } +} + +//---------------------------------------------------------------------------- +void vtkImageColorViewer::SetPosition(int a,int b) +{ + this->RenderWindow->SetPosition(a, b); +} + +//---------------------------------------------------------------------------- +int* vtkImageColorViewer::GetPosition() +{ + return this->RenderWindow->GetPosition(); +} + +//---------------------------------------------------------------------------- +void vtkImageColorViewer::SetDisplayId(void *a) +{ + this->RenderWindow->SetDisplayId(a); +} + +//---------------------------------------------------------------------------- +void vtkImageColorViewer::SetWindowId(void *a) +{ + this->RenderWindow->SetWindowId(a); +} + +//---------------------------------------------------------------------------- +void vtkImageColorViewer::SetParentId(void *a) +{ + this->RenderWindow->SetParentId(a); +} + +//---------------------------------------------------------------------------- +double vtkImageColorViewer::GetColorWindow() +{ + return this->WindowLevel->GetWindow(); +} + +//---------------------------------------------------------------------------- +double vtkImageColorViewer::GetColorLevel() +{ + return this->WindowLevel->GetLevel(); +} + +//---------------------------------------------------------------------------- +void vtkImageColorViewer::SetColorWindow(double s) +{ + this->WindowLevel->SetWindow(s); +} + +//---------------------------------------------------------------------------- +void vtkImageColorViewer::SetColorLevel(double s) +{ + this->WindowLevel->SetLevel(s); +} + +//---------------------------------------------------------------------------- +class vtkImageColorViewerCallback : public vtkCommand +{ +public: + static vtkImageColorViewerCallback *New() { return new vtkImageColorViewerCallback; } + + void Execute(vtkObject *caller, + unsigned long event, + void *vtkNotUsed(callData)) + { + if (this->IV->GetInput() == NULL) + { + return; + } + + // Reset + + if (event == vtkCommand::ResetWindowLevelEvent) + { +#if (VTK_MAJOR_VERSION >= 6) + this->IV->GetInputAlgorithm()->UpdateInformation(); + vtkStreamingDemandDrivenPipeline::SetUpdateExtent( + this->IV->GetInputInformation(), + vtkStreamingDemandDrivenPipeline::GetWholeExtent( + this->IV->GetInputInformation())); + this->IV->GetInputAlgorithm()->Update(); +#else + this->IV->GetInput()->UpdateInformation(); + this->IV->GetInput()->SetUpdateExtent + (this->IV->GetInput()->GetWholeExtent()); + this->IV->GetInput()->Update(); +#endif + double *range = this->IV->GetInput()->GetScalarRange(); + this->IV->SetColorWindow(range[1] - range[0]); + this->IV->SetColorLevel(0.5 * (range[1] + range[0])); + this->IV->Render(); + return; + } + + // Start + + if (event == vtkCommand::StartWindowLevelEvent) + { + this->InitialWindow = this->IV->GetColorWindow(); + this->InitialLevel = this->IV->GetColorLevel(); + return; + } + + // Adjust the window level here + + vtkInteractorStyleImage *isi = + static_cast(caller); + + int *size = this->IV->GetRenderWindow()->GetSize(); + double window = this->InitialWindow; + double level = this->InitialLevel; + + // Compute normalized delta + + double dx = 4.0 * + (isi->GetWindowLevelCurrentPosition()[0] - + isi->GetWindowLevelStartPosition()[0]) / size[0]; + double dy = 4.0 * + (isi->GetWindowLevelStartPosition()[1] - + isi->GetWindowLevelCurrentPosition()[1]) / size[1]; + + // Scale by current values + + if (fabs(window) > 0.01) + { + dx = dx * window; + } + else + { + dx = dx * (window < 0 ? -0.01 : 0.01); + } + if (fabs(level) > 0.01) + { + dy = dy * level; + } + else + { + dy = dy * (level < 0 ? -0.01 : 0.01); + } + + // Abs so that direction does not flip + + if (window < 0.0) + { + dx = -1*dx; + } + if (level < 0.0) + { + dy = -1*dy; + } + + // Compute new window level + + double newWindow = dx + window; + double newLevel; + newLevel = level - dy; + + // Stay away from zero and really + + if (fabs(newWindow) < 0.01) + { + newWindow = 0.01*(newWindow < 0 ? -1 : 1); + } + if (fabs(newLevel) < 0.01) + { + newLevel = 0.01*(newLevel < 0 ? -1 : 1); + } + + this->IV->SetColorWindow(newWindow); + this->IV->SetColorLevel(newLevel); + this->IV->Render(); + } + + vtkImageColorViewer *IV; + double InitialWindow; + double InitialLevel; +}; + +//---------------------------------------------------------------------------- +void vtkImageColorViewer::InstallPipeline() +{ + if (this->RenderWindow && this->Renderer) + { + this->RenderWindow->AddRenderer(this->Renderer); + } + + if (this->Interactor) + { + if (!this->InteractorStyle) + { + this->InteractorStyle = vtkInteractorStyleImage::New(); + vtkImageColorViewerCallback *cbk = vtkImageColorViewerCallback::New(); + cbk->IV = this; + this->InteractorStyle->AddObserver( + vtkCommand::WindowLevelEvent, cbk); + this->InteractorStyle->AddObserver( + vtkCommand::StartWindowLevelEvent, cbk); + this->InteractorStyle->AddObserver( + vtkCommand::ResetWindowLevelEvent, cbk); + cbk->Delete(); + } + + this->Interactor->SetInteractorStyle(this->InteractorStyle); + this->Interactor->SetRenderWindow(this->RenderWindow); + } + + if (this->Renderer && this->ImageActor) + { + this->Renderer->AddViewProp(this->ImageActor); + } + + if (this->ImageActor && this->WindowLevel) + { +#if (VTK_MAJOR_VERSION >= 6) + this->ImageActor->GetMapper()->SetInputConnection( + this->WindowLevel->GetOutputPort()); +#else + this->ImageActor->SetInput(this->WindowLevel->GetOutput()); +#endif + } +} + +//---------------------------------------------------------------------------- +void vtkImageColorViewer::UnInstallPipeline() +{ + if (this->ImageActor) + { +#if (VTK_MAJOR_VERSION >= 6) + this->ImageActor->GetMapper()->SetInputConnection(NULL); +#else + this->ImageActor->SetInput(NULL); +#endif + } + + if (this->Renderer && this->ImageActor) + { + this->Renderer->RemoveViewProp(this->ImageActor); + } + + if (this->RenderWindow && this->Renderer) + { + this->RenderWindow->RemoveRenderer(this->Renderer); + } + + if (this->Interactor) + { + this->Interactor->SetInteractorStyle(NULL); + this->Interactor->SetRenderWindow(NULL); + } +} + +//---------------------------------------------------------------------------- +void vtkImageColorViewer::Render() +{ + if (this->FirstRender) + { + // Initialize the size if not set yet + +#if (VTK_MAJOR_VERSION >= 6) + vtkAlgorithm *input = this->GetInputAlgorithm(); +#else + vtkImageData *input = this->GetInput(); +#endif + if (input) + { + input->UpdateInformation(); +#if (VTK_MAJOR_VERSION >= 6) + int *w_ext = this->GetInputInformation()->Get( + vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT()); +#else + int *w_ext = input->GetWholeExtent(); +#endif + int xs = 0, ys = 0; + + switch (this->SliceOrientation) + { + case vtkImageColorViewer::SLICE_ORIENTATION_XY: + default: + xs = w_ext[1] - w_ext[0] + 1; + ys = w_ext[3] - w_ext[2] + 1; + break; + + case vtkImageColorViewer::SLICE_ORIENTATION_XZ: + xs = w_ext[1] - w_ext[0] + 1; + ys = w_ext[5] - w_ext[4] + 1; + break; + + case vtkImageColorViewer::SLICE_ORIENTATION_YZ: + xs = w_ext[3] - w_ext[2] + 1; + ys = w_ext[5] - w_ext[4] + 1; + break; + } + + // if it would be smaller than 150 by 100 then limit to 150 by 100 + if (this->RenderWindow->GetSize()[0] == 0) + { + this->RenderWindow->SetSize( + xs < 150 ? 150 : xs, ys < 100 ? 100 : ys); + } + + if (this->Renderer) + { + this->Renderer->ResetCamera(); + this->Renderer->GetActiveCamera()->SetParallelScale( + xs < 150 ? 75 : (xs - 1 ) / 2.0); + } + this->FirstRender = 0; + } + } + if (this->GetInput()) + { + this->RenderWindow->Render(); + } +} + +//---------------------------------------------------------------------------- +const char* vtkImageColorViewer::GetWindowName() +{ + return this->RenderWindow->GetWindowName(); +} + +//---------------------------------------------------------------------------- +void vtkImageColorViewer::SetOffScreenRendering(int i) +{ + this->RenderWindow->SetOffScreenRendering(i); +} + +//---------------------------------------------------------------------------- +int vtkImageColorViewer::GetOffScreenRendering() +{ + return this->RenderWindow->GetOffScreenRendering(); +} + +//---------------------------------------------------------------------------- +#if (VTK_MAJOR_VERSION >= 6) +void vtkImageColorViewer::SetInputData(vtkImageData *in) +{ + this->WindowLevel->SetInputData(in); + this->UpdateDisplayExtent(); +} +#else +void vtkImageColorViewer::SetInput(vtkImageData *in) +{ + this->WindowLevel->SetInput(in); + this->UpdateDisplayExtent(); +} +#endif +//---------------------------------------------------------------------------- +vtkImageData* vtkImageColorViewer::GetInput() +{ + return vtkImageData::SafeDownCast(this->WindowLevel->GetInput()); +} +//---------------------------------------------------------------------------- +#if (VTK_MAJOR_VERSION >= 6) +vtkInformation* vtkImageColorViewer::GetInputInformation() +{ + return this->WindowLevel->GetInputInformation(); +} +//---------------------------------------------------------------------------- +vtkAlgorithm* vtkImageColorViewer::GetInputAlgorithm() +{ + return this->WindowLevel->GetInputAlgorithm(); +} +#endif +//---------------------------------------------------------------------------- +void vtkImageColorViewer::SetInputConnection(vtkAlgorithmOutput* input) +{ + this->WindowLevel->SetInputConnection(input); + this->UpdateDisplayExtent(); +} + +//---------------------------------------------------------------------------- +/* +void vtkImageColorViewer::AddInput(vtkPolyData * input) +{ + vtkRenderWindow *renwin = this->GetRenderWindow (); + vtkRenderer *Renderer = vtkRenderer::New(); + vtkPolyDataMapper * mapper = vtkPolyDataMapper::New(); + mapper->SetInput( input ); + vtkActor * actor = vtkActor::New(); + actor->SetMapper( mapper ); + Renderer->AddViewProp(actor); + + renwin->AddRenderer(Renderer); + Renderer->Delete(); + mapper->Delete(); + actor->Delete(); +} +*/ + +void vtkImageColorViewer::AddInput(vtkImageData * input) +{ + vtkRenderWindow *renwin = this->GetRenderWindow (); + renwin->SetNumberOfLayers(2); + vtkRenderer *renderer = vtkRenderer::New(); + renderer->SetLayer(1); + OverlayImageActor->SetOpacity(0.5); + vtkImageMapToWindowLevelColors2 *windowLevel = vtkImageMapToWindowLevelColors2::New(); +#if (VTK_MAJOR_VERSION >= 6) + windowLevel->SetInputData(input); + OverlayImageActor->SetInputData(windowLevel->GetOutput()); +#else + windowLevel->SetInput(input); + OverlayImageActor->SetInput(windowLevel->GetOutput()); +#endif + renderer->AddViewProp(OverlayImageActor); + OverlayImageActor->SetVisibility(1); + + renwin->AddRenderer(renderer); + renderer->Delete(); + windowLevel->Delete(); +} + +void vtkImageColorViewer::AddInputConnection(vtkAlgorithmOutput* input) +{ + vtkRenderWindow *renwin = this->GetRenderWindow (); + renwin->SetNumberOfLayers(2); + vtkRenderer *renderer = vtkRenderer::New(); + renderer->SetLayer(1); + OverlayImageActor->SetOpacity(0.5); + vtkImageMapToWindowLevelColors2 *windowLevel = vtkImageMapToWindowLevelColors2::New(); + windowLevel->SetInputConnection(input); +#if (VTK_MAJOR_VERSION >= 6) + OverlayImageActor->SetInputData(windowLevel->GetOutput()); +#else + OverlayImageActor->SetInput(windowLevel->GetOutput()); +#endif + renderer->AddViewProp(OverlayImageActor); + OverlayImageActor->SetVisibility(1); + + renwin->AddRenderer(renderer); + renderer->Delete(); + windowLevel->Delete(); +} + +double vtkImageColorViewer::GetOverlayVisibility() +{ + return this->OverlayImageActor->GetVisibility(); +} + +void vtkImageColorViewer::SetOverlayVisibility(double vis) +{ + this->OverlayImageActor->SetVisibility((int)vis); +} + +//---------------------------------------------------------------------------- +#ifndef VTK_LEGACY_REMOVE +int vtkImageColorViewer::GetWholeZMin() +{ + VTK_LEGACY_REPLACED_BODY(vtkImageColorViewer::GetWholeZMin, "VTK 5.0", + vtkImageColorViewer::GetSliceMin); + return this->GetSliceMin(); +} +int vtkImageColorViewer::GetWholeZMax() +{ + VTK_LEGACY_REPLACED_BODY(vtkImageColorViewer::GetWholeZMax, "VTK 5.0", + vtkImageColorViewer::GetSliceMax); + return this->GetSliceMax(); +} +int vtkImageColorViewer::GetZSlice() +{ + VTK_LEGACY_REPLACED_BODY(vtkImageColorViewer::GetZSlice, "VTK 5.0", + vtkImageColorViewer::GetSlice); + return this->GetSlice(); +} +void vtkImageColorViewer::SetZSlice(int s) +{ + VTK_LEGACY_REPLACED_BODY(vtkImageColorViewer::SetZSlice, "VTK 5.0", + vtkImageColorViewer::SetSlice); + this->SetSlice(s); +} +#endif + +//---------------------------------------------------------------------------- +void vtkImageColorViewer::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os, indent); + + os << indent << "RenderWindow:\n"; + this->RenderWindow->PrintSelf(os,indent.GetNextIndent()); + os << indent << "Renderer:\n"; + this->Renderer->PrintSelf(os,indent.GetNextIndent()); + os << indent << "ImageActor:\n"; + this->ImageActor->PrintSelf(os,indent.GetNextIndent()); + os << indent << "WindowLevel:\n" << endl; + this->WindowLevel->PrintSelf(os,indent.GetNextIndent()); + os << indent << "Slice: " << this->Slice << endl; + os << indent << "SliceOrientation: " << this->SliceOrientation << endl; + os << indent << "InteractorStyle: " << endl; + if (this->InteractorStyle) + { + os << "\n"; + this->InteractorStyle->PrintSelf(os,indent.GetNextIndent()); + } + else + { + os << "None"; + } +} diff --git a/gdcm/Utilities/VTK/vtkImageColorViewer.h b/gdcm/Utilities/VTK/vtkImageColorViewer.h new file mode 100644 index 0000000..6d83592 --- /dev/null +++ b/gdcm/Utilities/VTK/vtkImageColorViewer.h @@ -0,0 +1,249 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +// .NAME vtkImageColorViewer - Display a 2D image. +// .SECTION Description +// vtkImageColorViewer is a convenience class for displaying a 2D image. It +// packages up the functionality found in vtkRenderWindow, vtkRenderer, +// vtkImageActor and vtkImageMapToWindowLevelColors into a single easy to use +// class. This class also creates an image interactor style +// (vtkInteractorStyleImage) that allows zooming and panning of images, and +// supports interactive window/level operations on the image. Note that +// vtkImageColorViewer is simply a wrapper around these classes. +// +// vtkImageColorViewer uses the 3D rendering and texture mapping engine +// to draw an image on a plane. This allows for rapid rendering, +// zooming, and panning. The image is placed in the 3D scene at a +// depth based on the z-coordinate of the particular image slice. Each +// call to SetSlice() changes the image data (slice) displayed AND +// changes the depth of the displayed slice in the 3D scene. This can +// be controlled by the AutoAdjustCameraClippingRange ivar of the +// InteractorStyle member. +// +// It is possible to mix images and geometry, using the methods: +// +// viewer->SetInput( myImage ); +// viewer->GetRenderer()->AddActor( myActor ); +// +// This can be used to annotate an image with a PolyData of "edges" or +// or highlight sections of an image or display a 3D isosurface +// with a slice from the volume, etc. Any portions of your geometry +// that are in front of the displayed slice will be visible; any +// portions of your geometry that are behind the displayed slice will +// be obscured. A more general framework (with respect to viewing +// direction) for achieving this effect is provided by the +// vtkImagePlaneWidget . +// +// Note that pressing 'r' will reset the window/level and pressing +// shift+'r' or control+'r' will reset the camera. +// +// .SECTION See Also +// vtkRenderWindow vtkRenderer vtkImageActor vtkImageMapToWindowLevelColors + +#ifndef VTKIMAGECOLORVIEWER_H +#define VTKIMAGECOLORVIEWER_H + +#include "vtkObject.h" + +class vtkAlgorithm; +class vtkAlgorithmOutput; +class vtkImageActor; +class vtkImageData; +class vtkImageMapToWindowLevelColors2; +class vtkInformation; +class vtkInteractorStyleImage; +class vtkRenderWindow; +class vtkRenderer; +class vtkRenderWindowInteractor; +class vtkPolyData; + +class VTK_EXPORT vtkImageColorViewer : public vtkObject +{ +public: + static vtkImageColorViewer *New(); + vtkTypeRevisionMacro(vtkImageColorViewer,vtkObject); + void PrintSelf(ostream& os, vtkIndent indent); + + // Description: + // Get the name of rendering window. + virtual const char *GetWindowName(); + + // Description: + // Render the resulting image. + virtual void Render(void); + + // Description: + // Set/Get the input image to the viewer. +#if (VTK_MAJOR_VERSION >= 6) + virtual void SetInputData(vtkImageData *in); +#else + virtual void SetInput(vtkImageData *in); +#endif + virtual vtkImageData *GetInput(); + virtual void SetInputConnection(vtkAlgorithmOutput* input); + virtual void AddInputConnection(vtkAlgorithmOutput* input); + virtual void AddInput(vtkImageData * input); + //virtual void AddInput(vtkPolyData * input); + + double GetOverlayVisibility(); + void SetOverlayVisibility(double vis); + + // Description: + // Set/get the slice orientation + //BTX + enum + { + SLICE_ORIENTATION_YZ = 0, + SLICE_ORIENTATION_XZ = 1, + SLICE_ORIENTATION_XY = 2 + }; + //ETX + vtkGetMacro(SliceOrientation, int); + virtual void SetSliceOrientation(int orientation); + virtual void SetSliceOrientationToXY() + { this->SetSliceOrientation(vtkImageColorViewer::SLICE_ORIENTATION_XY); }; + virtual void SetSliceOrientationToYZ() + { this->SetSliceOrientation(vtkImageColorViewer::SLICE_ORIENTATION_YZ); }; + virtual void SetSliceOrientationToXZ() + { this->SetSliceOrientation(vtkImageColorViewer::SLICE_ORIENTATION_XZ); }; + + // Description: + // Set/Get the current slice to display (depending on the orientation + // this can be in X, Y or Z). + vtkGetMacro(Slice, int); + virtual void SetSlice(int s); + + // Description: + // Update the display extent manually so that the proper slice for the + // given orientation is displayed. It will also try to set a + // reasonable camera clipping range. + // This method is called automatically when the Input is changed, but + // most of the time the input of this class is likely to remain the same, + // i.e. connected to the output of a filter, or an image reader. When the + // input of this filter or reader itself is changed, an error message might + // be displayed since the current display extent is probably outside + // the new whole extent. Calling this method will ensure that the display + // extent is reset properly. + virtual void UpdateDisplayExtent(); + + // Description: + // Return the minimum and maximum slice values (depending on the orientation + // this can be in X, Y or Z). + virtual int GetSliceMin(); + virtual int GetSliceMax(); + virtual void GetSliceRange(int range[2]) + { this->GetSliceRange(range[0], range[1]); } + virtual void GetSliceRange(int &min, int &max); + virtual int* GetSliceRange(); + + // Description: + // Set window and level for mapping pixels to colors. + virtual double GetColorWindow(); + virtual double GetColorLevel(); + virtual void SetColorWindow(double s); + virtual void SetColorLevel(double s); + + // Description: + // These are here when using a Tk window. + virtual void SetDisplayId(void *a); + virtual void SetWindowId(void *a); + virtual void SetParentId(void *a); + + // Description: + // Set/Get the position in screen coordinates of the rendering window. + virtual int* GetPosition(); + virtual void SetPosition(int a,int b); + virtual void SetPosition(int a[2]) { this->SetPosition(a[0],a[1]); } + + // Description: + // Set/Get the size of the window in screen coordinates in pixels. + virtual int* GetSize(); + virtual void SetSize(int a, int b); + virtual void SetSize(int a[2]) { this->SetSize(a[0],a[1]); } + + // Description: + // Get the internal render window, renderer, image actor, and + // image map instances. + vtkGetObjectMacro(RenderWindow,vtkRenderWindow); + vtkGetObjectMacro(Renderer, vtkRenderer); + vtkGetObjectMacro(ImageActor,vtkImageActor); + vtkGetObjectMacro(WindowLevel,vtkImageMapToWindowLevelColors2); + vtkGetObjectMacro(InteractorStyle,vtkInteractorStyleImage); + + // Description: + // Set your own renderwindow and renderer + virtual void SetRenderWindow(vtkRenderWindow *arg); + virtual void SetRenderer(vtkRenderer *arg); + + // Description: + // Attach an interactor for the internal render window. + virtual void SetupInteractor(vtkRenderWindowInteractor*); + + // Description: + // Create a window in memory instead of on the screen. This may not + // be supported for every type of window and on some windows you may + // need to invoke this prior to the first render. + virtual void SetOffScreenRendering(int); + virtual int GetOffScreenRendering(); + vtkBooleanMacro(OffScreenRendering,int); + + // Description: + // @deprecated Replaced by vtkImageColorViewer::GetSliceMin() as of VTK 5.0. + VTK_LEGACY(int GetWholeZMin()); + + // Description: + // @deprecated Replaced by vtkImageColorViewer::GetSliceMax() as of VTK 5.0. + VTK_LEGACY(int GetWholeZMax()); + + // Description: + // @deprecated Replaced by vtkImageColorViewer::GetSlice() as of VTK 5.0. + VTK_LEGACY(int GetZSlice()); + + // Description: + // @deprecated Replaced by vtkImageColorViewer::SetSlice() as of VTK 5.0. + VTK_LEGACY(void SetZSlice(int)); + +protected: + vtkImageColorViewer(); + ~vtkImageColorViewer(); + + virtual void InstallPipeline(); + virtual void UnInstallPipeline(); + + vtkImageMapToWindowLevelColors2 *WindowLevel; + vtkRenderWindow *RenderWindow; + vtkRenderer *Renderer; + vtkImageActor *ImageActor; + vtkImageActor *OverlayImageActor; + vtkRenderWindowInteractor *Interactor; + vtkInteractorStyleImage *InteractorStyle; + + int SliceOrientation; + int FirstRender; + int Slice; + + virtual void UpdateOrientation(); + +#if (VTK_MAJOR_VERSION >= 6) + vtkAlgorithm* GetInputAlgorithm(); + vtkInformation* GetInputInformation(); +#endif + + friend class vtkImageColorViewerCallback; + +private: + vtkImageColorViewer(const vtkImageColorViewer&); // Not implemented. + void operator=(const vtkImageColorViewer&); // Not implemented. +}; + +#endif diff --git a/gdcm/Utilities/VTK/vtkImageMapToColors16.cxx b/gdcm/Utilities/VTK/vtkImageMapToColors16.cxx new file mode 100644 index 0000000..ae8d7e7 --- /dev/null +++ b/gdcm/Utilities/VTK/vtkImageMapToColors16.cxx @@ -0,0 +1,308 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/*========================================================================= + + Portions of this file are subject to the VTK Toolkit Version 3 copyright. + + Program: Visualization Toolkit + Module: $RCSfile: vtkImageMapToColors16.cxx,v $ + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkImageMapToColors16.h" + +#include "vtkImageData.h" +#include "vtkInformation.h" +#include "vtkInformationVector.h" +#include "vtkObjectFactory.h" +#include "vtkStreamingDemandDrivenPipeline.h" +#include "vtkScalarsToColors.h" +#include "vtkPointData.h" + +vtkCxxRevisionMacro(vtkImageMapToColors16, "$Revision: 1.30 $") +vtkStandardNewMacro(vtkImageMapToColors16) +vtkCxxSetObjectMacro(vtkImageMapToColors16,LookupTable,vtkScalarsToColors) + +//---------------------------------------------------------------------------- +// Constructor sets default values +vtkImageMapToColors16::vtkImageMapToColors16() +{ + this->OutputFormat = 4; + this->ActiveComponent = 0; + this->PassAlphaToOutput = 0; + this->LookupTable = NULL; + this->DataWasPassed = 0; +} + +//---------------------------------------------------------------------------- +vtkImageMapToColors16::~vtkImageMapToColors16() +{ + if (this->LookupTable != NULL) + { + this->LookupTable->UnRegister(this); + } +} + +//---------------------------------------------------------------------------- +unsigned long vtkImageMapToColors16::GetMTime() +{ + unsigned long t1, t2; + + t1 = this->Superclass::GetMTime(); + if (this->LookupTable) + { + t2 = this->LookupTable->GetMTime(); + if (t2 > t1) + { + t1 = t2; + } + } + return t1; +} + +//---------------------------------------------------------------------------- +// This method checks to see if we can simply reference the input data +int vtkImageMapToColors16::RequestData(vtkInformation *request, + vtkInformationVector **inputVector, + vtkInformationVector *outputVector) +{ + vtkInformation *inInfo = inputVector[0]->GetInformationObject(0); + vtkInformation *outInfo = outputVector->GetInformationObject(0); + + vtkImageData *outData = vtkImageData::SafeDownCast( + outInfo->Get(vtkDataObject::DATA_OBJECT())); + vtkImageData *inData = vtkImageData::SafeDownCast( + inInfo->Get(vtkDataObject::DATA_OBJECT())); + + // If LookupTable is null, just pass the data + if (this->LookupTable == NULL) + { + vtkDebugMacro("RequestData: LookupTable not set, "\ + "passing input to output."); + + outData->SetExtent(inData->GetExtent()); + outData->GetPointData()->PassData(inData->GetPointData()); + this->DataWasPassed = 1; + } + else // normal behaviour + { + this->LookupTable->Build(); //make sure table is built + + if (this->DataWasPassed) + { + outData->GetPointData()->SetScalars(NULL); + this->DataWasPassed = 0; + } + + return this->Superclass::RequestData(request, inputVector, outputVector); + } + + return 1; +} + +//---------------------------------------------------------------------------- +int vtkImageMapToColors16::RequestInformation ( + vtkInformation * vtkNotUsed(request), + vtkInformationVector **inputVector, + vtkInformationVector *outputVector) +{ + // get the info objects + vtkInformation* outInfo = outputVector->GetInformationObject(0); + vtkInformation *inInfo = inputVector[0]->GetInformationObject(0); + + int numComponents = 4; + + switch (this->OutputFormat) + { + case VTK_RGBA: + numComponents = 4; + break; + case VTK_RGB: + numComponents = 3; + break; + case VTK_LUMINANCE_ALPHA: + numComponents = 2; + break; + case VTK_LUMINANCE: + numComponents = 1; + break; + default: + vtkErrorMacro("RequestInformation: Unrecognized color format."); + break; + } + + if (this->LookupTable == NULL) + { + vtkInformation *scalarInfo = vtkDataObject::GetActiveFieldInformation(inInfo, + vtkDataObject::FIELD_ASSOCIATION_POINTS, vtkDataSetAttributes::SCALARS); + if ( scalarInfo->Get(vtkDataObject::FIELD_ARRAY_TYPE()) != VTK_UNSIGNED_CHAR ) + { + vtkErrorMacro( + "RequestInformation: No LookupTable was set but input data is not " + "VTK_UNSIGNED_CHAR, therefore input can't be passed through!"); + return 1; + } + else if ( numComponents != + scalarInfo->Get(vtkDataObject::FIELD_NUMBER_OF_COMPONENTS()) ) + { + vtkErrorMacro( + "RequestInformation: No LookupTable was set but number of components " + "in input doesn't match OutputFormat, therefore input can't be passed" + " through!"); + return 1; + } + } + +// vtkDataObject:: +// SetPointDataActiveScalarInfo(outInfo, VTK_UNSIGNED_CHAR, numComponents); + vtkDataObject:: + SetPointDataActiveScalarInfo(outInfo, VTK_UNSIGNED_SHORT, numComponents); + return 1; +} + +//---------------------------------------------------------------------------- +// This non-templated function executes the filter for any type of data. + +void vtkImageMapToColors16Execute(vtkImageMapToColors16 *self, + vtkImageData *inData, void *inPtr, + vtkImageData *outData, + unsigned short *outPtr, + int outExt[6], int id) +{ + int idxY, idxZ; + int extX, extY, extZ; + vtkIdType inIncX, inIncY, inIncZ; + vtkIdType outIncX, outIncY, outIncZ; + unsigned long count = 0; + unsigned long target; + int dataType = inData->GetScalarType(); + int scalarSize = inData->GetScalarSize(); + int numberOfComponents,numberOfOutputComponents,outputFormat; + int rowLength; + vtkScalarsToColors *lookupTable = self->GetLookupTable(); + unsigned short *outPtr1; + void *inPtr1; + + // find the region to loop over + extX = outExt[1] - outExt[0] + 1; + extY = outExt[3] - outExt[2] + 1; + extZ = outExt[5] - outExt[4] + 1; + + target = static_cast(extZ*extY/50.0); + target++; + + // Get increments to march through data + inData->GetContinuousIncrements(outExt, inIncX, inIncY, inIncZ); + // because we are using void * and char * we must take care + // of the scalar size in the increments + inIncY *= scalarSize; + inIncZ *= scalarSize; + outData->GetContinuousIncrements(outExt, outIncX, outIncY, outIncZ); + numberOfComponents = inData->GetNumberOfScalarComponents(); + numberOfOutputComponents = outData->GetNumberOfScalarComponents(); + outputFormat = self->GetOutputFormat(); + rowLength = extX*scalarSize*numberOfComponents; + + // Loop through output pixels + outPtr1 = outPtr; + inPtr1 = static_cast( + static_cast(inPtr) + self->GetActiveComponent()*scalarSize); + for (idxZ = 0; idxZ < extZ; idxZ++) + { + for (idxY = 0; !self->AbortExecute && idxY < extY; idxY++) + { + if (!id) + { + if (!(count%target)) + { + self->UpdateProgress((double)count/(50.0*(double)target)); + } + count++; + } + lookupTable->MapScalarsThroughTable2(inPtr1,(unsigned char*)outPtr1, + dataType,extX,numberOfComponents, + outputFormat); + //if (self->GetPassAlphaToOutput() && + // dataType == VTK_UNSIGNED_CHAR && numberOfComponents > 1 && + // (outputFormat == VTK_RGBA || outputFormat == VTK_LUMINANCE_ALPHA)) + // { + // unsigned char *outPtr2 = outPtr1 + numberOfOutputComponents - 1; + // unsigned char *inPtr2 = static_cast(inPtr1) + // - self->GetActiveComponent()*scalarSize + numberOfComponents - 1; + // for (int i = 0; i < extX; i++) + // { + // *outPtr2 = (*outPtr2 * *inPtr2)/255; + // outPtr2 += numberOfOutputComponents; + // inPtr2 += numberOfComponents; + // } + // } + outPtr1 += outIncY + extX*numberOfOutputComponents; + inPtr1 = static_cast( + static_cast(inPtr1) + inIncY + rowLength); + } + outPtr1 += outIncZ; + inPtr1 = static_cast(static_cast(inPtr1) + inIncZ); + } +} + +//---------------------------------------------------------------------------- +// This method is passed a input and output data, and executes the filter +// algorithm to fill the output from the input. + +void vtkImageMapToColors16::ThreadedRequestData( + vtkInformation *vtkNotUsed(request), + vtkInformationVector **vtkNotUsed(inputVector), + vtkInformationVector *vtkNotUsed(outputVector), + vtkImageData ***inData, + vtkImageData **outData, + int outExt[6], int id) +{ + void *inPtr = inData[0][0]->GetScalarPointerForExtent(outExt); + void *outPtr = outData[0]->GetScalarPointerForExtent(outExt); + + vtkImageMapToColors16Execute(this, inData[0][0], inPtr, + outData[0], static_cast(outPtr), + outExt, id); +} + +//---------------------------------------------------------------------------- +void vtkImageMapToColors16::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os,indent); + + os << indent << "OutputFormat: " << + (this->OutputFormat == VTK_RGBA ? "RGBA" : + (this->OutputFormat == VTK_RGB ? "RGB" : + (this->OutputFormat == VTK_LUMINANCE_ALPHA ? "LuminanceAlpha" : + (this->OutputFormat == VTK_LUMINANCE ? "Luminance" : "Unknown")))) + << "\n"; + os << indent << "ActiveComponent: " << this->ActiveComponent << "\n"; + os << indent << "PassAlphaToOutput: " << this->PassAlphaToOutput << "\n"; + os << indent << "LookupTable: "; + if (this->LookupTable) + { + this->LookupTable->PrintSelf(os << endl,indent.GetNextIndent()); + } + else + { + os << "(none)\n"; + } +} diff --git a/gdcm/Utilities/VTK/vtkImageMapToColors16.h b/gdcm/Utilities/VTK/vtkImageMapToColors16.h new file mode 100644 index 0000000..c7d0cd3 --- /dev/null +++ b/gdcm/Utilities/VTK/vtkImageMapToColors16.h @@ -0,0 +1,114 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/*========================================================================= + + Portions of this file are subject to the VTK Toolkit Version 3 copyright. + + Program: Visualization Toolkit + Module: $RCSfile: vtkImageMapToColors16.h,v $ + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +// .NAME vtkImageMapToColors16 - map the input image through a lookup table +// .SECTION Description +// The vtkImageMapToColors16 filter will take an input image of any valid +// scalar type, and map the first component of the image through a +// lookup table. The result is an image of type VTK_UNSIGNED_CHAR. +// If the lookup table is not set, or is set to NULL, then the input +// data will be passed through if it is already of type VTK_UNSIGNED_CHAR. + +// .SECTION See Also +// vtkLookupTable vtkScalarsToColors + +#ifndef VTKIMAGEMAPTOCOLORS16_H +#define VTKIMAGEMAPTOCOLORS16_H + + +#include "vtkThreadedImageAlgorithm.h" + +class vtkScalarsToColors; + +class VTK_EXPORT vtkImageMapToColors16 : public vtkThreadedImageAlgorithm +{ +public: + static vtkImageMapToColors16 *New(); + vtkTypeRevisionMacro(vtkImageMapToColors16,vtkThreadedImageAlgorithm); + void PrintSelf(ostream& os, vtkIndent indent); + + // Description: + // Set the lookup table. + virtual void SetLookupTable(vtkScalarsToColors*); + vtkGetObjectMacro(LookupTable,vtkScalarsToColors); + + // Description: + // Set the output format, the default is RGBA. + vtkSetMacro(OutputFormat,int); + vtkGetMacro(OutputFormat,int); + void SetOutputFormatToRGBA() { this->OutputFormat = VTK_RGBA; }; + void SetOutputFormatToRGB() { this->OutputFormat = VTK_RGB; }; + void SetOutputFormatToLuminanceAlpha() { this->OutputFormat = VTK_LUMINANCE_ALPHA; }; + void SetOutputFormatToLuminance() { this->OutputFormat = VTK_LUMINANCE; }; + + // Description: + // Set the component to map for multi-component images (default: 0) + vtkSetMacro(ActiveComponent,int); + vtkGetMacro(ActiveComponent,int); + + // Description: + // Use the alpha component of the input when computing the alpha component + // of the output (useful when converting monochrome+alpha data to RGBA) + vtkSetMacro(PassAlphaToOutput,int); + vtkBooleanMacro(PassAlphaToOutput,int); + vtkGetMacro(PassAlphaToOutput,int); + + // Description: + // We need to check the modified time of the lookup table too. + virtual unsigned long GetMTime(); + +protected: + vtkImageMapToColors16(); + ~vtkImageMapToColors16(); + + virtual int RequestInformation (vtkInformation *, vtkInformationVector **, vtkInformationVector *); + + void ThreadedRequestData(vtkInformation *request, + vtkInformationVector **inputVector, + vtkInformationVector *outputVector, + vtkImageData ***inData, vtkImageData **outData, + int extent[6], int id); + + virtual int RequestData(vtkInformation *request, + vtkInformationVector **inputVector, + vtkInformationVector *outputVector); + + vtkScalarsToColors *LookupTable; + int OutputFormat; + + int ActiveComponent; + int PassAlphaToOutput; + + int DataWasPassed; +private: + vtkImageMapToColors16(const vtkImageMapToColors16&); // Not implemented. + void operator=(const vtkImageMapToColors16&); // Not implemented. +}; + +#endif diff --git a/gdcm/Utilities/VTK/vtkImageMapToWindowLevelColors2.cxx b/gdcm/Utilities/VTK/vtkImageMapToWindowLevelColors2.cxx new file mode 100644 index 0000000..a9233e2 --- /dev/null +++ b/gdcm/Utilities/VTK/vtkImageMapToWindowLevelColors2.cxx @@ -0,0 +1,484 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/*========================================================================= + + Portions of this file are subject to the VTK Toolkit Version 3 copyright. + + Program: Visualization Toolkit + Module: $RCSfile: vtkImageMapToWindowLevelColors2.cxx,v $ + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkImageMapToWindowLevelColors2.h" + +#include "vtkDataArray.h" +#include "vtkImageData.h" +#include "vtkInformation.h" +#include "vtkInformationVector.h" +#include "vtkObjectFactory.h" +#include "vtkScalarsToColors.h" +#include "vtkPointData.h" + +vtkCxxRevisionMacro(vtkImageMapToWindowLevelColors2, "$Revision: 1.3 $") +vtkStandardNewMacro(vtkImageMapToWindowLevelColors2) + +// Constructor sets default values +vtkImageMapToWindowLevelColors2::vtkImageMapToWindowLevelColors2() +{ + this->Window = 255; + this->Level = 127.5; +} + +vtkImageMapToWindowLevelColors2::~vtkImageMapToWindowLevelColors2() +{ +} + +//---------------------------------------------------------------------------- +// This method checks to see if we can simply reference the input data +int vtkImageMapToWindowLevelColors2::RequestData( + vtkInformation *request, + vtkInformationVector **inputVector, + vtkInformationVector *outputVector) +{ + vtkInformation *outInfo = outputVector->GetInformationObject(0); + vtkInformation *inInfo = inputVector[0]->GetInformationObject(0); + + vtkImageData *outData = vtkImageData::SafeDownCast( + outInfo->Get(vtkDataObject::DATA_OBJECT())); + vtkImageData *inData = vtkImageData::SafeDownCast( + inInfo->Get(vtkDataObject::DATA_OBJECT())); + + // If LookupTable is null and window / level produces no change, + // then just pass the data + if (this->LookupTable == NULL && + (inData->GetScalarType() == VTK_UNSIGNED_CHAR && + this->Window == 255 && this->Level == 127.5)) + { + vtkDebugMacro("ExecuteData: LookupTable not set, "\ + "Window / Level at default, "\ + "passing input to output."); + + outData->SetExtent(inData->GetExtent()); + outData->GetPointData()->PassData(inData->GetPointData()); + this->DataWasPassed = 1; + } + else + // normal behaviour - skip up a level since we don't want to + // call the superclasses ExecuteData - it would pass the data if there + // is no lookup table even if there is a window / level - wrong + // behavior. + { + if (this->DataWasPassed) + { + outData->GetPointData()->SetScalars(NULL); + this->DataWasPassed = 0; + } + + return this->vtkThreadedImageAlgorithm::RequestData(request, inputVector, + outputVector); + } + + return 1; +} + +//---------------------------------------------------------------------------- +int vtkImageMapToWindowLevelColors2::RequestInformation ( + vtkInformation *vtkNotUsed(request), + vtkInformationVector **inputVector, + vtkInformationVector *outputVector) +{ + vtkInformation *inInfo = inputVector[0]->GetInformationObject(0); + vtkInformation *outInfo = outputVector->GetInformationObject(0); + + vtkInformation *inScalarInfo = + vtkDataObject::GetActiveFieldInformation(inInfo, + vtkDataObject::FIELD_ASSOCIATION_POINTS, vtkDataSetAttributes::SCALARS); + if (!inScalarInfo) + { + vtkErrorMacro("Missing scalar field on input information!"); + return 0; + } + + // If LookupTable is null and window / level produces no change, + // then the data will be passed + if ( this->LookupTable == NULL && + (inScalarInfo->Get(vtkDataObject::FIELD_ARRAY_TYPE()) == + VTK_UNSIGNED_CHAR && + this->Window == 255 && this->Level == 127.5) ) + { + if (inScalarInfo->Get(vtkDataObject::FIELD_ARRAY_TYPE()) != + VTK_UNSIGNED_CHAR) + { + vtkErrorMacro("ExecuteInformation: No LookupTable was set and input data is not VTK_UNSIGNED_CHAR!"); + } + else + { + // no lookup table, pass the input if it was UNSIGNED_CHAR + vtkDataObject::SetPointDataActiveScalarInfo + (outInfo, VTK_UNSIGNED_CHAR, + inScalarInfo->Get(vtkDataObject::FIELD_NUMBER_OF_COMPONENTS())); + } + } + else // the lookup table was set or window / level produces a change + { + int numComponents = 4; + switch (this->OutputFormat) + { + case VTK_RGBA: + numComponents = 4; + break; + case VTK_RGB: + numComponents = 3; + break; + case VTK_LUMINANCE_ALPHA: + numComponents = 2; + break; + case VTK_LUMINANCE: + numComponents = 1; + break; + default: + vtkErrorMacro("ExecuteInformation: Unrecognized color format."); + break; + } + vtkDataObject::SetPointDataActiveScalarInfo(outInfo, VTK_UNSIGNED_CHAR, numComponents); + } + + return 1; +} + +/* + * This templated routine calculates effective lower and upper limits + * for a window of values of type T, lower and upper. + */ +template +void vtkImageMapToWindowLevelClamps ( vtkImageData *data, double w, + double l, T& lower, T& upper, + unsigned char &lower_val, + unsigned char &upper_val) +{ + double f_lower, f_upper, f_lower_val, f_upper_val; + double adjustedLower, adjustedUpper; + double range[2]; + + data->GetPointData()->GetScalars()->GetDataTypeRange( range ); + + f_lower = l - fabs(w) / 2.0; + f_upper = f_lower + fabs(w); + + // Set the correct lower value + if ( f_lower <= range[1]) + { + if (f_lower >= range[0]) + { + lower = (T) f_lower; + adjustedLower = f_lower; + } + else + { + lower = (T) range[0]; + adjustedLower = range[0]; + } + } + else + { + lower = (T) range[1]; + adjustedLower = range[1]; + } + + // Set the correct upper value + if ( f_upper >= range[0]) + { + if (f_upper <= range[1]) + { + upper = (T) f_upper; + adjustedUpper = f_upper; + } + else + { + upper = (T) range[1]; + adjustedUpper = range[1]; + } + } + else + { + upper = (T) range [0]; + adjustedUpper = range [0]; + } + + // now compute the lower and upper values + if (w >= 0) + { + f_lower_val = 255.0*(adjustedLower - f_lower)/w; + f_upper_val = 255.0*(adjustedUpper - f_lower)/w; + } + else + { + f_lower_val = 255.0 + 255.0*(adjustedLower - f_lower)/w; + f_upper_val = 255.0 + 255.0*(adjustedUpper - f_lower)/w; + } + + if (f_upper_val > 255) + { + upper_val = 255; + } + else if (f_upper_val < 0) + { + upper_val = 0; + } + else + { + upper_val = (unsigned char)(f_upper_val); + } + + if (f_lower_val > 255) + { + lower_val = 255; + } + else if (f_lower_val < 0) + { + lower_val = 0; + } + else + { + lower_val = (unsigned char)(f_lower_val); + } +} + +//---------------------------------------------------------------------------- +// Small helper to do the clamp: +template +void vtkClampHelper1(T* iptr, unsigned char *optr, + T lower, T upper, + unsigned char lower_val, unsigned char upper_val, + double shift, double scale) +{ + unsigned short ushort_val; + if (*iptr <= lower) + { + ushort_val = lower_val; + } + else if (*iptr >= upper) + { + ushort_val = upper_val; + } + else + { + ushort_val = (unsigned char) (((double)*iptr + shift)*scale); + } + *optr = (unsigned char)((*optr * ushort_val) >> 8); +} + +//---------------------------------------------------------------------------- +template +void vtkClampHelper2(T* iptr, unsigned char *optr, + T lower, T upper, + unsigned char lower_val, unsigned char upper_val, + double shift, double scale) +{ + unsigned char result_val; + if (*iptr <= lower) + { + result_val = lower_val; + } + else if (*iptr >= upper) + { + result_val = upper_val; + } + else + { + result_val = (unsigned char) (((double)*iptr + shift)*scale); + } + *optr = result_val; +} + +//---------------------------------------------------------------------------- +// This non-templated function executes the filter for any type of data. +template +void vtkImageMapToWindowLevelColors2Execute( + vtkImageMapToWindowLevelColors2 *self, + vtkImageData *inData, T *inPtr, + vtkImageData *outData, + unsigned char *outPtr, + int outExt[6], int id) +{ + int idxX, idxY, idxZ; + int extX, extY, extZ; + vtkIdType inIncX, inIncY, inIncZ; + vtkIdType outIncX, outIncY, outIncZ; + unsigned long count = 0; + unsigned long target; + int dataType = inData->GetScalarType(); + int numberOfComponents,numberOfOutputComponents,outputFormat; + int rowLength; + vtkScalarsToColors *lookupTable = self->GetLookupTable(); + unsigned char *outPtr1; + T *inPtr1; + unsigned char *optr; + T *iptr; + double shift = self->GetWindow() / 2.0 - self->GetLevel(); + double scale = 255.0 / self->GetWindow(); + + T lower, upper; + unsigned char lower_val, upper_val; + vtkImageMapToWindowLevelClamps( inData, self->GetWindow(), + self->GetLevel(), + lower, upper, lower_val, upper_val ); + + // find the region to loop over + extX = outExt[1] - outExt[0] + 1; + extY = outExt[3] - outExt[2] + 1; + extZ = outExt[5] - outExt[4] + 1; + + target = (unsigned long)(extZ*extY/50.0); + target++; + + // Get increments to march through data + inData->GetContinuousIncrements(outExt, inIncX, inIncY, inIncZ); + + outData->GetContinuousIncrements(outExt, outIncX, outIncY, outIncZ); + numberOfComponents = inData->GetNumberOfScalarComponents(); + numberOfOutputComponents = outData->GetNumberOfScalarComponents(); + outputFormat = self->GetOutputFormat(); + + rowLength = extX*numberOfComponents; + + // Loop through output pixels + outPtr1 = outPtr; + inPtr1 = inPtr; + for (idxZ = 0; idxZ < extZ; idxZ++) + { + for (idxY = 0; !self->AbortExecute && idxY < extY; idxY++) + { + if (!id) + { + if (!(count%target)) + { + self->UpdateProgress((double)count/(50.0*(double)target)); + } + count++; + } + + iptr = inPtr1; + optr = outPtr1; + + if ( lookupTable ) + { + lookupTable->MapScalarsThroughTable2(inPtr1,(unsigned char *)outPtr1, + dataType,extX,numberOfComponents, + outputFormat); + + for (idxX = 0; idxX < extX; idxX++) + { + vtkClampHelper1(iptr,optr,lower,upper,lower_val,upper_val,shift,scale); + switch (outputFormat) + { + case VTK_RGBA: + vtkClampHelper1(iptr+(1%numberOfComponents),optr+1,lower,upper,lower_val,upper_val,shift,scale); + vtkClampHelper1(iptr+(2%numberOfComponents),optr+2,lower,upper,lower_val,upper_val,shift,scale); + *(optr+3) = 255; + break; + case VTK_RGB: + vtkClampHelper1(iptr+(1%numberOfComponents),optr+1,lower,upper,lower_val,upper_val,shift,scale); + vtkClampHelper1(iptr+(2%numberOfComponents),optr+2,lower,upper,lower_val,upper_val,shift,scale); + break; + case VTK_LUMINANCE_ALPHA: + *(optr+1) = 255; + break; + } + iptr += numberOfComponents; + optr += numberOfOutputComponents; + } + } + else + { + for (idxX = 0; idxX < extX; idxX++) + { + // We want to shift to the right position depending on the numberOfComponents from input + // if grayscale we should stay at the same position, otherwise need to shift to r,g,b + // (0%numberOfComponents) == 0 ... + // (1%numberOfComponents) == 0 or 1 + vtkClampHelper2(iptr,optr,lower,upper,lower_val,upper_val,shift,scale); + switch (outputFormat) + { + case VTK_RGBA: + vtkClampHelper2(iptr+(1%numberOfComponents),optr+1,lower,upper,lower_val,upper_val,shift,scale); + vtkClampHelper2(iptr+(2%numberOfComponents),optr+2,lower,upper,lower_val,upper_val,shift,scale); + *(optr+3) = 255; + break; + case VTK_RGB: + vtkClampHelper2(iptr+(1%numberOfComponents),optr+1,lower,upper,lower_val,upper_val,shift,scale); + vtkClampHelper2(iptr+(2%numberOfComponents),optr+2,lower,upper,lower_val,upper_val,shift,scale); + break; + case VTK_LUMINANCE_ALPHA: + *(optr+1) = 255; + break; + } + iptr += numberOfComponents; + optr += numberOfOutputComponents; + } + } + outPtr1 += outIncY + extX*numberOfOutputComponents; + inPtr1 += inIncY + rowLength; + } + outPtr1 += outIncZ; + inPtr1 += inIncZ; + } +} + +//---------------------------------------------------------------------------- +// This method is passed a input and output data, and executes the filter +// algorithm to fill the output from the input. + +void vtkImageMapToWindowLevelColors2::ThreadedRequestData( + vtkInformation *vtkNotUsed(request), + vtkInformationVector **vtkNotUsed(inputVector), + vtkInformationVector *vtkNotUsed(outputVector), + vtkImageData ***inData, + vtkImageData **outData, + int outExt[6], int id) +{ + void *inPtr = inData[0][0]->GetScalarPointerForExtent(outExt); + void *outPtr = outData[0]->GetScalarPointerForExtent(outExt); + + switch (inData[0][0]->GetScalarType()) + { + vtkTemplateMacro( + vtkImageMapToWindowLevelColors2Execute( this, + inData[0][0], + (VTK_TT *)(inPtr), + outData[0], + (unsigned char *)(outPtr), + outExt, + id)); + default: + vtkErrorMacro(<< "Execute: Unknown ScalarType"); + return; + } +} + +//---------------------------------------------------------------------------- +void vtkImageMapToWindowLevelColors2::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os,indent); + + os << indent << "Window: " << this->Window << endl; + os << indent << "Level: " << this->Level << endl; +} diff --git a/gdcm/Utilities/VTK/vtkImageMapToWindowLevelColors2.h b/gdcm/Utilities/VTK/vtkImageMapToWindowLevelColors2.h new file mode 100644 index 0000000..dc2db27 --- /dev/null +++ b/gdcm/Utilities/VTK/vtkImageMapToWindowLevelColors2.h @@ -0,0 +1,91 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/*========================================================================= + + Portions of this file are subject to the VTK Toolkit Version 3 copyright. + + Program: Visualization Toolkit + Module: $RCSfile: vtkImageMapToWindowLevelColors2.h,v $ + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +// .NAME vtkImageMapToWindowLevelColors2 - map the input image through a lookup table and window / level it +// .SECTION Description +// The vtkImageMapToWindowLevelColors2 filter will take an input image of any +// valid scalar type, and map the first component of the image through a +// lookup table. This resulting color will be modulated with value obtained +// by a window / level operation. The result is an image of type +// VTK_UNSIGNED_CHAR. If the lookup table is not set, or is set to NULL, then +// the input data will be passed through if it is already of type +// UNSIGNED_CHAR. +// +// .SECTION See Also +// vtkLookupTable vtkScalarsToColors + +#ifndef VTKIMAGEMAPTOWINDOWLEVELCOLORS2_H +#define VTKIMAGEMAPTOWINDOWLEVELCOLORS2_H + +#include "vtkImageMapToColors.h" + +class VTK_EXPORT vtkImageMapToWindowLevelColors2 : public vtkImageMapToColors +{ +public: + static vtkImageMapToWindowLevelColors2 *New(); + vtkTypeRevisionMacro(vtkImageMapToWindowLevelColors2,vtkImageMapToColors); + void PrintSelf(ostream& os, vtkIndent indent); + + // Description: + // Set / Get the Window to use -> modulation will be performed on the + // color based on (S - (L - W/2))/W where S is the scalar value, L is + // the level and W is the window. + vtkSetMacro( Window, double ); + vtkGetMacro( Window, double ); + + // Description: + // Set / Get the Level to use -> modulation will be performed on the + // color based on (S - (L - W/2))/W where S is the scalar value, L is + // the level and W is the window. + vtkSetMacro( Level, double ); + vtkGetMacro( Level, double ); + +protected: + vtkImageMapToWindowLevelColors2(); + ~vtkImageMapToWindowLevelColors2(); + + virtual int RequestInformation (vtkInformation *, vtkInformationVector **, vtkInformationVector *); + void ThreadedRequestData(vtkInformation *request, + vtkInformationVector **inputVector, + vtkInformationVector *outputVector, + vtkImageData ***inData, vtkImageData **outData, + int extent[6], int id); + virtual int RequestData(vtkInformation *request, + vtkInformationVector **inputVector, + vtkInformationVector *outputVector); + + double Window; + double Level; + +private: + vtkImageMapToWindowLevelColors2(const vtkImageMapToWindowLevelColors2&); // Not implemented. + void operator=(const vtkImageMapToWindowLevelColors2&); // Not implemented. +}; + +#endif diff --git a/gdcm/Utilities/VTK/vtkImagePlanarComponentsToComponents.cxx b/gdcm/Utilities/VTK/vtkImagePlanarComponentsToComponents.cxx new file mode 100644 index 0000000..01a189a --- /dev/null +++ b/gdcm/Utilities/VTK/vtkImagePlanarComponentsToComponents.cxx @@ -0,0 +1,149 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/*========================================================================= + + Portions of this file are subject to the VTK Toolkit Version 3 copyright. + + Program: Visualization Toolkit + Module: $RCSfile: vtkImagePlanarComponentsToComponents.cxx,v $ + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkImagePlanarComponentsToComponents.h" + +#include "vtkImageData.h" +#include "vtkImageProgressIterator.h" +#include "vtkMath.h" +#include "vtkInformation.h" +#include "vtkInformationVector.h" +#include "vtkObjectFactory.h" +#include "vtkStreamingDemandDrivenPipeline.h" + +#include "gdcmImageChangePlanarConfiguration.h" + +#include + +vtkCxxRevisionMacro(vtkImagePlanarComponentsToComponents, "$Revision: 1.31 $") +vtkStandardNewMacro(vtkImagePlanarComponentsToComponents) + +//---------------------------------------------------------------------------- +vtkImagePlanarComponentsToComponents::vtkImagePlanarComponentsToComponents() +{ + this->SetNumberOfInputPorts(1); + this->SetNumberOfOutputPorts(1); +} + + +//---------------------------------------------------------------------------- +// This templated function executes the filter for any type of data. +template +void vtkImagePlanarComponentsToComponentsExecute(vtkImagePlanarComponentsToComponents *self, + vtkImageData *inData, + vtkImageData *outData, + int outExt[6], int id, T *) +{ + int maxX, maxY, maxZ; + // find the region to loop over + maxX = outExt[1] - outExt[0]; + maxY = outExt[3] - outExt[2]; + maxZ = outExt[5] - outExt[4]; + (void)self; + (void)id; + + + //target = static_cast((maxZ+1)*(maxY+1)/50.0); + //target++; + + const T *inPtr = (T*)inData->GetScalarPointer(outExt[0],outExt[2],outExt[4]); + T *outPtr = static_cast(outData->GetScalarPointer(outExt[0],outExt[2],outExt[4])); + + // Loop through ouput pixels + + size_t framesize = (maxX+1) * (maxY+1) * 3; + for(int z = 0; z <= maxZ; ++z) + { + const T *frame = inPtr + z * framesize; + size_t size = framesize / 3; + const T *r = frame + 0; + const T *g = frame + size; + const T *b = frame + size + size; + + T *framecopy = outPtr + z * framesize; + gdcm::ImageChangePlanarConfiguration::RGBPlanesToRGBPixels(framecopy, r, g, b, size); + } + + +} + +//---------------------------------------------------------------------------- +int vtkImagePlanarComponentsToComponents::RequestData( + vtkInformation* vtkNotUsed(request), + vtkInformationVector** inputVector, + vtkInformationVector* outputVector) +{ + int idxX, idxY, idxZ; + vtkIdType outIncX, outIncY, outIncZ; + int *outExt; + double sum; + double yContrib, zContrib; + double temp, temp2; + unsigned long count = 0; + unsigned long target; + // + // get the input + vtkInformation* in1Info = inputVector[0]->GetInformationObject(0); + vtkImageData *inData = vtkImageData::SafeDownCast( + in1Info->Get(vtkDataObject::DATA_OBJECT())); + + vtkInformation *outInfo = outputVector->GetInformationObject(0); + vtkImageData *output = vtkImageData::SafeDownCast( + outInfo->Get(vtkDataObject::DATA_OBJECT())); + vtkImageData *data = this->AllocateOutputData(output); + + if (data->GetScalarType() != VTK_UNSIGNED_CHAR + && data->GetScalarType() != VTK_UNSIGNED_SHORT ) + { + vtkErrorMacro("Execute: This source only deal with uchar/ushort"); + } + + outExt = data->GetExtent(); + + // Get increments to march through data + data->GetContinuousIncrements(outExt, outIncX, outIncY, outIncZ); + + switch (inData->GetScalarType()) + { + vtkTemplateMacro( + vtkImagePlanarComponentsToComponentsExecute(this, inData, + data, outExt, 0, static_cast(0))); + default: + vtkErrorMacro(<< "Execute: Unknown ScalarType"); + return 0; + } + + return 1; +} + +//---------------------------------------------------------------------------- +void vtkImagePlanarComponentsToComponents::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os,indent); +} diff --git a/gdcm/Utilities/VTK/vtkImagePlanarComponentsToComponents.h b/gdcm/Utilities/VTK/vtkImagePlanarComponentsToComponents.h new file mode 100644 index 0000000..d9bb13f --- /dev/null +++ b/gdcm/Utilities/VTK/vtkImagePlanarComponentsToComponents.h @@ -0,0 +1,71 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/*========================================================================= + + Portions of this file are subject to the VTK Toolkit Version 3 copyright. + + Program: Visualization Toolkit + Module: $RCSfile: vtkImagePlanarComponentsToComponents.h,v $ + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +// .NAME vtkImagePlanarComponentsToComponents - Converts planar comp to pixel comp +// .SECTION Description + +// .SECTION See Also +// TODO: Can I make this filter threaded ? +// TODO: How do I handle the VTK-flipping (FileLowerLeft)? + +#ifndef VTKIMAGEPLANARCOMPONENTSTOCOMPONENTS_H +#define VTKIMAGEPLANARCOMPONENTSTOCOMPONENTS_H + +#include "vtkImageAlgorithm.h" + +// everything is now handled within the vtkGDCMImageReader as Planar Configuration can not +// be externalized (conflict with file lower left) + +#error do not use this class + +//class VTK_EXPORT vtkImagePlanarComponentsToComponents : public vtkThreadedImageAlgorithm +class VTK_EXPORT vtkImagePlanarComponentsToComponents : public vtkImageAlgorithm +{ +public: + static vtkImagePlanarComponentsToComponents *New(); + //vtkTypeRevisionMacro(vtkImagePlanarComponentsToComponents,vtkThreadedImageAlgorithm); + vtkTypeRevisionMacro(vtkImagePlanarComponentsToComponents,vtkImageAlgorithm); + + void PrintSelf(ostream& os, vtkIndent indent); + +protected: + vtkImagePlanarComponentsToComponents(); + ~vtkImagePlanarComponentsToComponents() {}; + +// void ThreadedExecute (vtkImageData *inData, vtkImageData *outData, +// int ext[6], int id); +// virtual int RequestInformation (vtkInformation *, vtkInformationVector**, vtkInformationVector *); + virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); + +private: + vtkImagePlanarComponentsToComponents(const vtkImagePlanarComponentsToComponents&); // Not implemented. + void operator=(const vtkImagePlanarComponentsToComponents&); // Not implemented. +}; + +#endif diff --git a/gdcm/Utilities/VTK/vtkImageRGBToYBR.cxx b/gdcm/Utilities/VTK/vtkImageRGBToYBR.cxx new file mode 100644 index 0000000..8914346 --- /dev/null +++ b/gdcm/Utilities/VTK/vtkImageRGBToYBR.cxx @@ -0,0 +1,143 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/*========================================================================= + + Portions of this file are subject to the VTK Toolkit Version 3 copyright. + + Program: Visualization Toolkit + Module: $RCSfile: vtkImageRGBToYBR.cxx,v $ + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkImageRGBToYBR.h" + +#include "vtkImageData.h" +#include "vtkImageProgressIterator.h" +#include "vtkMath.h" +#include "vtkObjectFactory.h" + +vtkCxxRevisionMacro(vtkImageRGBToYBR, "$Revision: 1.31 $") +vtkStandardNewMacro(vtkImageRGBToYBR) + +//---------------------------------------------------------------------------- +vtkImageRGBToYBR::vtkImageRGBToYBR() +{ + this->SetNumberOfInputPorts(1); + this->SetNumberOfOutputPorts(1); +} + + +//---------------------------------------------------------------------------- +// This templated function executes the filter for any type of data. +template +void vtkImageRGBToYBRExecute(vtkImageRGBToYBR *self, + vtkImageData *inData, + vtkImageData *outData, + int outExt[6], int id, T *) +{ + vtkImageIterator inIt(inData, outExt); + vtkImageProgressIterator outIt(outData, outExt, self, id); + int idxC; + + // find the region to loop over + int maxC = inData->GetNumberOfScalarComponents()-1; + + // Loop through ouput pixels + while (!outIt.IsAtEnd()) + { + T* inSI = inIt.BeginSpan(); + T* outSI = outIt.BeginSpan(); + T* outSIEnd = outIt.EndSpan(); + while (outSI != outSIEnd) + { + // http://lestourtereaux.free.fr/papers/data/yuvrgb.pdf + // Pixel operation + unsigned char r = (unsigned char)(*inSI); ++inSI; + unsigned char g = (unsigned char)(*inSI); ++inSI; + unsigned char b = (unsigned char)(*inSI); ++inSI; + + double y = 0.257 * r + 0.504 * g + 0.098 * b + 16; + double u = -0.148* r - 0.291 * g + 0.439 * b + 128; + double v = 0.439 * r - 0.368 * g - 0.071 * b + 128; + + // assign output. + *outSI = (T)(y); ++outSI; + *outSI = (T)(u); ++outSI; + *outSI = (T)(v); ++outSI; + + for (idxC = 3; idxC <= maxC; idxC++) + { + *outSI++ = *inSI++; + } + } + inIt.NextSpan(); + outIt.NextSpan(); + } +} + +//---------------------------------------------------------------------------- +void vtkImageRGBToYBR::ThreadedExecute (vtkImageData *inData, + vtkImageData *outData, + int outExt[6], int id) +{ + vtkDebugMacro(<< "Execute: inData = " << inData + << ", outData = " << outData); + + // this filter expects that input is the same type as output. + if (inData->GetScalarType() != outData->GetScalarType()) + { + vtkErrorMacro(<< "Execute: input ScalarType, " << inData->GetScalarType() + << ", must match out ScalarType " << outData->GetScalarType()); + return; + } + if (inData->GetScalarType() != VTK_UNSIGNED_CHAR ) + { + return; + } + + // need three components for input and output + if (inData->GetNumberOfScalarComponents() < 3) + { + vtkErrorMacro("Input has too few components"); + return; + } + if (outData->GetNumberOfScalarComponents() < 3) + { + vtkErrorMacro("Output has too few components"); + return; + } + + switch (inData->GetScalarType()) + { + vtkTemplateMacro( + vtkImageRGBToYBRExecute(this, inData, + outData, outExt, id, static_cast(0))); + default: + vtkErrorMacro(<< "Execute: Unknown ScalarType"); + return; + } +} + +//---------------------------------------------------------------------------- +void vtkImageRGBToYBR::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os,indent); +} diff --git a/gdcm/Utilities/VTK/vtkImageRGBToYBR.h b/gdcm/Utilities/VTK/vtkImageRGBToYBR.h new file mode 100644 index 0000000..132429b --- /dev/null +++ b/gdcm/Utilities/VTK/vtkImageRGBToYBR.h @@ -0,0 +1,63 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/*========================================================================= + + Portions of this file are subject to the VTK Toolkit Version 3 copyright. + + Program: Visualization Toolkit + Module: $RCSfile: vtkImageRGBToYBR.h,v $ + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +// .NAME vtkImageRGBToYBR - Converts YBR components to RGB. +// .SECTION Description +// For each pixel with hue, saturation and value components this filter +// outputs the color coded as red, green, blue. Output type must be the same +// as input type. + +// .SECTION See Also +// vtkImageRGBToHSV + +#ifndef VTKIMAGERGBTOYBR_H +#define VTKIMAGERGBTOYBR_H + +#include "vtkThreadedImageAlgorithm.h" + +class VTK_EXPORT vtkImageRGBToYBR : public vtkThreadedImageAlgorithm +{ +public: + static vtkImageRGBToYBR *New(); + vtkTypeRevisionMacro(vtkImageRGBToYBR,vtkThreadedImageAlgorithm); + + void PrintSelf(ostream& os, vtkIndent indent); + +protected: + vtkImageRGBToYBR(); + ~vtkImageRGBToYBR() {}; + + void ThreadedExecute (vtkImageData *inData, vtkImageData *outData, + int ext[6], int id); +private: + vtkImageRGBToYBR(const vtkImageRGBToYBR&); // Not implemented. + void operator=(const vtkImageRGBToYBR&); // Not implemented. +}; + +#endif diff --git a/gdcm/Utilities/VTK/vtkImageYBRToRGB.cxx b/gdcm/Utilities/VTK/vtkImageYBRToRGB.cxx new file mode 100644 index 0000000..06c54c7 --- /dev/null +++ b/gdcm/Utilities/VTK/vtkImageYBRToRGB.cxx @@ -0,0 +1,195 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/*========================================================================= + + Portions of this file are subject to the VTK Toolkit Version 3 copyright. + + Program: Visualization Toolkit + Module: $RCSfile: vtkImageYBRToRGB.cxx,v $ + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkImageYBRToRGB.h" + +#include "vtkImageData.h" +#include "vtkImageProgressIterator.h" +#include "vtkMath.h" +#include "vtkObjectFactory.h" + +vtkCxxRevisionMacro(vtkImageYBRToRGB, "$Revision: 1.31 $") +vtkStandardNewMacro(vtkImageYBRToRGB) + +//---------------------------------------------------------------------------- +vtkImageYBRToRGB::vtkImageYBRToRGB() +{ + this->SetNumberOfInputPorts(1); + this->SetNumberOfOutputPorts(1); +} + +//---------------------------------------------------------------------------- +// This templated function executes the filter for any type of data. +template +void vtkImageYBRToRGBExecute(vtkImageYBRToRGB *self, + vtkImageData *inData, + vtkImageData *outData, + int outExt[6], int id, T *) +{ + vtkImageIterator inIt(inData, outExt); + vtkImageProgressIterator outIt(outData, outExt, self, id); + int idxC; + + // find the region to loop over + int maxC = inData->GetNumberOfScalarComponents()-1; + + int R, G, B; + // Loop through ouput pixels + while (!outIt.IsAtEnd()) + { + T* inSI = inIt.BeginSpan(); + T* outSI = outIt.BeginSpan(); + T* outSIEnd = outIt.EndSpan(); + while (outSI != outSIEnd) + { + // Pixel operation +#if 1 +#if 1 + unsigned char a = (unsigned char)(*inSI); ++inSI; + unsigned char b = (unsigned char)(*inSI); ++inSI; + unsigned char c = (unsigned char)(*inSI); ++inSI; + + R = 38142 *(a-16) + 52298 *(c -128); + G = 38142 *(a-16) - 26640 *(c -128) - 12845 *(b -128); + B = 38142 *(a-16) + 66093 *(b -128); + + R = (R+16384)>>15; + G = (G+16384)>>15; + B = (B+16384)>>15; + +#else + int /*unsigned char*/ y = (unsigned char)(*inSI); ++inSI; + y -= 16; + unsigned char u = (unsigned char)(*inSI); ++inSI; + int Cb = (int)u - 128; + unsigned char v = (unsigned char)(*inSI); ++inSI; + int Cr = (int)v - 128; + + // R = y + (1.4075 * (v - 128)); + // G = y - (0.3455 * (u - 128) - (0.7169 * (v - 128))); + // B = y + (1.7790 * (u - 128)); + R = y + 1.40200 * Cr + 0.5; + G = y - 0.34414 * Cb - 0.71414 * Cr + 0.5; + B = y + 1.77200 * Cb + 0.5; + + + //int a = (int)y - 16; + //int b = (int)u - 128; + //int c = (int)v - 128; + + //R = ( 1.164 * a + 0. * b + 1.596 * c ); + //G = ( 1.164 * a + 0.391 * b + 0.813 * c ); + //B = ( 1.164 * a + 2.018 * b + 0. * c ); +#endif + if (R < 0) R = 0; + if (G < 0) G = 0; + if (B < 0) B = 0; + if (R > 255) R = 255; + if (G > 255) G = 255; + if (B > 255) B = 255; +#endif + +/* + double y = *inSI; ++inSI; + double u = *inSI; ++inSI; + double v = *inSI; ++inSI; + unsigned char R,G,B; + double maxval = 255.; + + double dr = y + 1.4020 * v - 0.7010 * maxval; + double dg = y - 0.3441 * u - 0.7141 * v + 0.5291 * maxval; + double db = y + 1.7720 * u - 0.8859 * maxval; + R = (dr < 0.0) ? 0 : ((dr+0.5) > maxval) ? maxval : (unsigned char)(dr+0.5); + G = (dg < 0.0) ? 0 : ((dg+0.5) > maxval) ? maxval : (unsigned char)(dg+0.5); + B = (db < 0.0) ? 0 : ((db+0.5) > maxval) ? maxval : (unsigned char)(db+0.5); +*/ + + // assign output. + *outSI = (T)(R); ++outSI; + *outSI = (T)(G); ++outSI; + *outSI = (T)(B); ++outSI; + + for (idxC = 3; idxC <= maxC; idxC++) + { + *outSI++ = *inSI++; + } + } + inIt.NextSpan(); + outIt.NextSpan(); + } +} + +//---------------------------------------------------------------------------- +void vtkImageYBRToRGB::ThreadedExecute (vtkImageData *inData, + vtkImageData *outData, + int outExt[6], int id) +{ + vtkDebugMacro(<< "Execute: inData = " << inData + << ", outData = " << outData); + + // this filter expects that input is the same type as output. + if (inData->GetScalarType() != outData->GetScalarType()) + { + vtkErrorMacro(<< "Execute: input ScalarType, " << inData->GetScalarType() + << ", must match out ScalarType " << outData->GetScalarType()); + return; + } + if (inData->GetScalarType() != VTK_UNSIGNED_CHAR ) + { + return; + } + + // need three components for input and output + if (inData->GetNumberOfScalarComponents() < 3) + { + vtkErrorMacro("Input has too few components"); + return; + } + if (outData->GetNumberOfScalarComponents() < 3) + { + vtkErrorMacro("Output has too few components"); + return; + } + + switch (inData->GetScalarType()) + { + vtkTemplateMacro( + vtkImageYBRToRGBExecute(this, inData, + outData, outExt, id, static_cast(0))); + default: + vtkErrorMacro(<< "Execute: Unknown ScalarType"); + return; + } +} + +//---------------------------------------------------------------------------- +void vtkImageYBRToRGB::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os,indent); +} diff --git a/gdcm/Utilities/VTK/vtkImageYBRToRGB.h b/gdcm/Utilities/VTK/vtkImageYBRToRGB.h new file mode 100644 index 0000000..d83cc57 --- /dev/null +++ b/gdcm/Utilities/VTK/vtkImageYBRToRGB.h @@ -0,0 +1,63 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/*========================================================================= + + Portions of this file are subject to the VTK Toolkit Version 3 copyright. + + Program: Visualization Toolkit + Module: $RCSfile: vtkImageYBRToRGB.h,v $ + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +// .NAME vtkImageYBRToRGB - Converts YBR components to RGB. +// .SECTION Description +// For each pixel with hue, saturation and value components this filter +// outputs the color coded as red, green, blue. Output type must be the same +// as input type. + +// .SECTION See Also +// vtkImageRGBToHSV + +#ifndef VTKIMAGEYBRTORGB_H +#define VTKIMAGEYBRTORGB_H + +#include "vtkThreadedImageAlgorithm.h" + +class VTK_EXPORT vtkImageYBRToRGB : public vtkThreadedImageAlgorithm +{ +public: + static vtkImageYBRToRGB *New(); + vtkTypeRevisionMacro(vtkImageYBRToRGB,vtkThreadedImageAlgorithm); + + void PrintSelf(ostream& os, vtkIndent indent); + +protected: + vtkImageYBRToRGB(); + ~vtkImageYBRToRGB() {}; + + void ThreadedExecute (vtkImageData *inData, vtkImageData *outData, + int ext[6], int id); +private: + vtkImageYBRToRGB(const vtkImageYBRToRGB&); // Not implemented. + void operator=(const vtkImageYBRToRGB&); // Not implemented. +}; + +#endif diff --git a/gdcm/Utilities/VTK/vtkLookupTable16.cxx b/gdcm/Utilities/VTK/vtkLookupTable16.cxx new file mode 100644 index 0000000..8559104 --- /dev/null +++ b/gdcm/Utilities/VTK/vtkLookupTable16.cxx @@ -0,0 +1,439 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/*========================================================================= + + Portions of this file are subject to the VTK Toolkit Version 3 copyright. + + Program: Visualization Toolkit + Module: $RCSfile: vtkLookupTable16.cxx,v $ + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkLookupTable16.h" +#include "vtkObjectFactory.h" + +#include + +vtkCxxRevisionMacro(vtkLookupTable16, "$Revision: 1.107 $") +vtkStandardNewMacro(vtkLookupTable16) + +vtkLookupTable16::vtkLookupTable16(int sze, int ext) + : vtkLookupTable(sze, ext) +{ + this->Table16 = vtkUnsignedShortArray::New(); + this->Table16->Register(this); + this->Table16->Delete(); + this->Table16->SetNumberOfComponents(4); + this->Table16->Allocate(4*sze,4*ext); +} + +//---------------------------------------------------------------------------- +vtkLookupTable16::~vtkLookupTable16() +{ + this->Table16->UnRegister(this); + this->Table16 = NULL; +} + +void vtkLookupTable16::Build() +{ +} + +void vtkLookupTable16::SetNumberOfTableValues(vtkIdType number) +{ + if (this->NumberOfColors == number) + { + return; + } + this->Modified(); + this->NumberOfColors = number; + this->Table16->SetNumberOfTuples(number); +} + +//---------------------------------------------------------------------------- +// Apply shift/scale to the scalar value v and do table lookup. +inline unsigned short *vtkLinearLookup16(double v, + unsigned short *table, + double maxIndex, + double shift, double scale) +{ + double findx = (v + shift)*scale; + if (findx < 0) + { + findx = 0; + } + if (findx > maxIndex) + { + findx = maxIndex; + } + return &table[4*static_cast(findx)]; + /* round + return &table[4*(int)(findx + 0.5f)]; + */ +} + +void vtkLookupTableLogRange16(double [2], double [2]) +{ + assert(0); +} + +inline double vtkApplyLogScale16(double , double [2], + double [2]) +{ + assert(0); + return 0; +} + +template +void vtkLookupTable16MapData(vtkLookupTable16 *self, T *input, + unsigned short *output, int length, + int inIncr, int outFormat) +{ + int i = length; + double *range = self->GetTableRange(); + double maxIndex = (double)self->GetNumberOfColors() - 1; + double shift, scale; + unsigned short *table = self->GetPointer(0); + unsigned short *cptr; + double alpha; + + if ( (alpha=self->GetAlpha()) >= 1.0 ) //no blending required + { + if (self->GetScale() == VTK_SCALE_LOG10) + { + double val; + double logRange[2]; + vtkLookupTableLogRange16(range, logRange); + shift = -logRange[0]; + if (logRange[1] <= logRange[0]) + { + scale = VTK_DOUBLE_MAX; + } + else + { + /* while this looks like the wrong scale, it is the correct scale + * taking into account the truncation to int that happens below. */ + scale = (maxIndex + 1)/(logRange[1] - logRange[0]); + } + if (outFormat == VTK_RGBA) + { + while (--i >= 0) + { + val = vtkApplyLogScale16((double)*input, range, logRange); + cptr = vtkLinearLookup16(val, table, maxIndex, shift, scale); + *output++ = *cptr++; + *output++ = *cptr++; + *output++ = *cptr++; + *output++ = *cptr++; + input += inIncr; + } + } + else if (outFormat == VTK_RGB) + { + while (--i >= 0) + { + val = vtkApplyLogScale16((double)*input, range, logRange); + cptr = vtkLinearLookup16(val, table, maxIndex, shift, scale); + *output++ = *cptr++; + *output++ = *cptr++; + *output++ = *cptr++; + input += inIncr; + } + } + else if (outFormat == VTK_LUMINANCE_ALPHA) + { + while (--i >= 0) + { + val = vtkApplyLogScale16((double)*input, range, logRange); + cptr = vtkLinearLookup16(val, table, maxIndex, shift, scale); + *output++ = static_cast(cptr[0]*0.30 + cptr[1]*0.59 + + cptr[2]*0.11 + 0.5); + *output++ = cptr[3]; + input += inIncr; + } + } + else // outFormat == VTK_LUMINANCE + { + while (--i >= 0) + { + val = vtkApplyLogScale16((double)*input, range, logRange); + cptr = vtkLinearLookup16(val, table, maxIndex, shift, scale); + *output++ = static_cast(cptr[0]*0.30 + cptr[1]*0.59 + + cptr[2]*0.11 + 0.5); + input += inIncr; + } + } + }//if log scale + + else //not log scale + { + shift = -range[0]; + if (range[1] <= range[0]) + { + scale = VTK_DOUBLE_MAX; + } + else + { + /* while this looks like the wrong scale, it is the correct scale + * taking into account the truncation to int that happens below. */ + scale = (maxIndex + 1)/(range[1] - range[0]); + } + + if (outFormat == VTK_RGBA) + { + while (--i >= 0) + { + cptr = vtkLinearLookup16((double)*input, table, maxIndex, shift, scale); + *output++ = *cptr++; + *output++ = *cptr++; + *output++ = *cptr++; + *output++ = *cptr++; + input += inIncr; + } + } + else if (outFormat == VTK_RGB) + { + while (--i >= 0) + { + cptr = vtkLinearLookup16((double)*input, table, maxIndex, shift, scale); + *output++ = *cptr++; + *output++ = *cptr++; + *output++ = *cptr++; + input += inIncr; + } + } + else if (outFormat == VTK_LUMINANCE_ALPHA) + { + while (--i >= 0) + { + cptr = vtkLinearLookup16((double)*input, table, maxIndex, shift, scale); + *output++ = static_cast(cptr[0]*0.30 + cptr[1]*0.59 + + cptr[2]*0.11 + 0.5); + *output++ = cptr[3]; + input += inIncr; + } + } + else // outFormat == VTK_LUMINANCE + { + while (--i >= 0) + { + cptr = vtkLinearLookup16((double)*input, table, maxIndex, shift, scale); + *output++ = static_cast(cptr[0]*0.30 + cptr[1]*0.59 + + cptr[2]*0.11 + 0.5); + input += inIncr; + } + } + }//if not log lookup + }//if blending not needed + + else //blend with the specified alpha + { + if (self->GetScale() == VTK_SCALE_LOG10) + { + double val; + double logRange[2]; + vtkLookupTableLogRange16(range, logRange); + shift = -logRange[0]; + if (logRange[1] <= logRange[0]) + { + scale = VTK_DOUBLE_MAX; + } + else + { + /* while this looks like the wrong scale, it is the correct scale + * taking into account the truncation to int that happens below. */ + scale = (maxIndex + 1)/(logRange[1] - logRange[0]); + } + if (outFormat == VTK_RGBA) + { + while (--i >= 0) + { + val = vtkApplyLogScale16((double)*input, range, logRange); + cptr = vtkLinearLookup16(val, table, maxIndex, shift, scale); + *output++ = *cptr++; + *output++ = *cptr++; + *output++ = *cptr++; + *output++ = static_cast((*cptr)*alpha); cptr++; + input += inIncr; + } + } + else if (outFormat == VTK_RGB) + { + while (--i >= 0) + { + val = vtkApplyLogScale16((double)*input, range, logRange); + cptr = vtkLinearLookup16(val, table, maxIndex, shift, scale); + *output++ = *cptr++; + *output++ = *cptr++; + *output++ = *cptr++; + input += inIncr; + } + } + else if (outFormat == VTK_LUMINANCE_ALPHA) + { + while (--i >= 0) + { + val = vtkApplyLogScale16((double)*input, range, logRange); + cptr = vtkLinearLookup16(val, table, maxIndex, shift, scale); + *output++ = static_cast(cptr[0]*0.30 + cptr[1]*0.59 + + cptr[2]*0.11 + 0.5); + *output++ = static_cast(alpha*cptr[3]); + input += inIncr; + } + } + else // outFormat == VTK_LUMINANCE + { + while (--i >= 0) + { + val = vtkApplyLogScale16((double)*input, range, logRange); + cptr = vtkLinearLookup16(val, table, maxIndex, shift, scale); + *output++ = static_cast(cptr[0]*0.30 + cptr[1]*0.59 + + cptr[2]*0.11 + 0.5); + input += inIncr; + } + } + }//log scale with blending + + else //no log scale with blending + { + shift = -range[0]; + if (range[1] <= range[0]) + { + scale = VTK_DOUBLE_MAX; + } + else + { + /* while this looks like the wrong scale, it is the correct scale + * taking into account the truncation to int that happens below. */ + scale = (maxIndex + 1)/(range[1] - range[0]); + } + + if (outFormat == VTK_RGBA) + { + while (--i >= 0) + { + cptr = vtkLinearLookup16((double)*input, table, maxIndex, shift, scale); + *output++ = *cptr++; + *output++ = *cptr++; + *output++ = *cptr++; + *output++ = static_cast((*cptr)*alpha); cptr++; + input += inIncr; + } + } + else if (outFormat == VTK_RGB) + { + while (--i >= 0) + { + cptr = vtkLinearLookup16((double)*input, table, maxIndex, shift, scale); + *output++ = *cptr++; + *output++ = *cptr++; + *output++ = *cptr++; + input += inIncr; + } + } + else if (outFormat == VTK_LUMINANCE_ALPHA) + { + while (--i >= 0) + { + cptr = vtkLinearLookup16((double)*input, table, maxIndex, shift, scale); + *output++ = static_cast(cptr[0]*0.30 + cptr[1]*0.59 + + cptr[2]*0.11 + 0.5); + *output++ = static_cast(cptr[3]*alpha); + input += inIncr; + } + } + else // outFormat == VTK_LUMINANCE + { + while (--i >= 0) + { + cptr = vtkLinearLookup16((double)*input, table, maxIndex, shift, scale); + *output++ = static_cast(cptr[0]*0.30 + cptr[1]*0.59 + + cptr[2]*0.11 + 0.5); + input += inIncr; + } + } + }//no log scale + }//alpha blending +} + +//---------------------------------------------------------------------------- +void vtkLookupTable16::MapScalarsThroughTable2(void *input, + unsigned char *output, + int inputDataType, + int numberOfValues, + int inputIncrement, + int outputFormat) +{ + if (this->UseMagnitude && inputIncrement > 1) + { +assert(0); +// switch (inputDataType) +// { +// vtkTemplateMacro( +// vtkLookupTableMapMag(this,static_cast(input),(unsigned short*)output, +// numberOfValues,inputIncrement,outputFormat); +// return +// ); +// case VTK_BIT: +// vtkErrorMacro("Cannot comput magnitude of bit array."); +// break; +// default: +// vtkErrorMacro(<< "MapImageThroughTable: Unknown input ScalarType"); +// } + } + + switch (inputDataType) + { + case VTK_BIT: + { +assert(0); + //vtkIdType i, id; + //vtkBitArray *bitArray = vtkBitArray::New(); + //bitArray->SetVoidArray(input,numberOfValues,1); + //vtkUnsignedCharArray *newInput = vtkUnsignedCharArray::New(); + //newInput->SetNumberOfValues(numberOfValues); + //for (id=i=0; iSetValue(i, bitArray->GetValue(id)); + // } + //vtkLookupTableMapData(this, + // static_cast(newInput->GetPointer(0)), + // output,numberOfValues, + // inputIncrement,outputFormat); + //newInput->Delete(); + //bitArray->Delete(); + } + break; + + vtkTemplateMacro( + vtkLookupTable16MapData(this,static_cast(input),(unsigned short*)output, + numberOfValues,inputIncrement,outputFormat) + ); + default: + vtkErrorMacro(<< "MapImageThroughTable: Unknown input ScalarType"); + return; + } +} + +void vtkLookupTable16::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os,indent); + +} diff --git a/gdcm/Utilities/VTK/vtkLookupTable16.h b/gdcm/Utilities/VTK/vtkLookupTable16.h new file mode 100644 index 0000000..ea65d67 --- /dev/null +++ b/gdcm/Utilities/VTK/vtkLookupTable16.h @@ -0,0 +1,87 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/*========================================================================= + + Portions of this file are subject to the VTK Toolkit Version 3 copyright. + + Program: Visualization Toolkit + Module: $RCSfile: vtkLookupTable16.h,v $ + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +// .NAME vtkLookupTable16 - +// .SECTION Description +// +// .SECTION Caveats +// +// .SECTION See Also +// vtkLookupTable + +#ifndef VTKLOOKUPTABLE16_H +#define VTKLOOKUPTABLE16_H + +#include "vtkLookupTable.h" +#include "vtkUnsignedShortArray.h" + +class VTK_EXPORT vtkLookupTable16 : public vtkLookupTable +{ +public: + static vtkLookupTable16 *New(); + + vtkTypeRevisionMacro(vtkLookupTable16,vtkLookupTable); + void PrintSelf(ostream& os, vtkIndent indent); + + void Build(); + + void SetNumberOfTableValues(vtkIdType number); + + unsigned char *WritePointer(const vtkIdType id, const int number); + + unsigned short *GetPointer(const vtkIdType id) { + return this->Table16->GetPointer(4*id); }; + +protected: + vtkLookupTable16(int sze=256, int ext=256); + ~vtkLookupTable16(); + + vtkUnsignedShortArray *Table16; + +void MapScalarsThroughTable2(void *input, + unsigned char *output, + int inputDataType, + int numberOfValues, + int inputIncrement, + int outputFormat); + +private: + vtkLookupTable16(const vtkLookupTable16&); // Not implemented. + void operator=(const vtkLookupTable16&); // Not implemented. +}; + +//---------------------------------------------------------------------------- +inline unsigned char *vtkLookupTable16::WritePointer(const vtkIdType id, + const int number) +{ + //this->InsertTime.Modified(); + return (unsigned char*)this->Table16->WritePointer(4*id,4*number); +} + +#endif diff --git a/gdcm/Utilities/VTK/vtkRTStructSetProperties.cxx b/gdcm/Utilities/VTK/vtkRTStructSetProperties.cxx new file mode 100644 index 0000000..6f03a6b --- /dev/null +++ b/gdcm/Utilities/VTK/vtkRTStructSetProperties.cxx @@ -0,0 +1,374 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkRTStructSetProperties.h" +#include "vtkObjectFactory.h" + +#include "gdcmDirectory.h" +#include "gdcmScanner.h" +#include "gdcmDataSet.h" +#include "gdcmReader.h" + +#include +#include +#include +#include +#include // for strftime +#include // for isdigit +#include + +//---------------------------------------------------------------------------- +vtkCxxRevisionMacro(vtkRTStructSetProperties, "1.21") +vtkStandardNewMacro(vtkRTStructSetProperties) + + + +struct StructureSetROI +{ + int ROINumber; + std::string RefFrameRefUID; + std::string ROIName; + std::string ROIGenerationAlgorithm; + std::string ROIDescription; + + // (3006,0080) SQ (Sequence with undefine)# u/l, 1 RTROIObservationsSequence + // (3006,0082) IS [0] # 2, 1 ObservationNumber + // (3006,0084) IS [0] # 2, 1 ReferencedROINumber + // (3006,0085) SH [Station 4L] # 10, 1 ROIObservationLabel + // (3006,00a4) CS [ORGAN] # 6, 1 RTROIInterpretedType + // (3006,00a6) PN (no value available) # 0, 0 ROIInterpreter + int ObservationNumber; + // RefROI is AFAIK simply ROINumber + std::string RTROIInterpretedType; + std::string ROIInterpreter; + std::string ROIObservationLabel; +}; + +//---------------------------------------------------------------------------- +class vtkRTStructSetPropertiesInternals +{ +public: + void Print(ostream &os, vtkIndent indent) + { + (void)os; + (void)indent; + } + void DeepCopy(vtkRTStructSetPropertiesInternals *p) + { + ReferencedFrameOfReferences = p->ReferencedFrameOfReferences; + } + vtkIdType GetNumberOfContourReferencedFrameOfReferences() + { + return ContourReferencedFrameOfReferences.size(); + } + vtkIdType GetNumberOfContourReferencedFrameOfReferences(vtkIdType pdnum) + { + return ContourReferencedFrameOfReferences[pdnum].size(); + } + const char *GetContourReferencedFrameOfReferenceClassUID( vtkIdType pdnum, vtkIdType id ) + { + return ContourReferencedFrameOfReferences[pdnum][ id ].first.c_str(); + } + const char *GetContourReferencedFrameOfReferenceInstanceUID( vtkIdType pdnum, vtkIdType id ) + { + return ContourReferencedFrameOfReferences[pdnum][ id ].second.c_str(); + } + vtkIdType GetNumberOfReferencedFrameOfReferences() + { + return ReferencedFrameOfReferences.size(); + } + const char *GetReferencedFrameOfReferenceClassUID( vtkIdType id ) + { + return ReferencedFrameOfReferences[ id ].first.c_str(); + } + const char *GetReferencedFrameOfReferenceInstanceUID(vtkIdType id ) + { + return ReferencedFrameOfReferences[ id ].second.c_str(); + } + void AddContourReferencedFrameOfReference( vtkIdType pdnum, const char *classuid , const char * instanceuid ) + { + ContourReferencedFrameOfReferences.resize(pdnum+1); + ContourReferencedFrameOfReferences[pdnum].push_back( + std::make_pair( classuid, instanceuid ) ); + } + std::vector< std::vector < std::pair< std::string, std::string > > > ContourReferencedFrameOfReferences; + void AddReferencedFrameOfReference( const char *classuid , const char * instanceuid ) + { + ReferencedFrameOfReferences.push_back( + std::make_pair( classuid, instanceuid ) ); + } + std::vector < std::pair< std::string, std::string > > ReferencedFrameOfReferences; + void AddStructureSetROIObservation( int refnumber, + int observationnumber, + const char *rtroiinterpretedtype, + const char *roiinterpreter, + const char *roiobservationlabel + ) + { + //std::cout << "AddStructureSetROIObservation: " << refnumber << std::endl; + std::vector::iterator it = StructureSetROIs.begin(); + bool found = false; + for( ; it != StructureSetROIs.end(); ++it ) + { + if( it->ROINumber == refnumber ) + { + assert( !found ); + found = true; + it->ObservationNumber = observationnumber; + if( rtroiinterpretedtype ) + it->RTROIInterpretedType = rtroiinterpretedtype; + if( roiinterpreter ) + it->ROIInterpreter = roiinterpreter; + if( roiobservationlabel ) + it->ROIObservationLabel = roiobservationlabel; + } + } + // postcond + assert( found ); + } + + void AddStructureSetROI( int roinumber, + const char* refframerefuid, + const char* roiname, + const char* roigenerationalgorithm, + const char* roidescription + ) + { + StructureSetROI structuresetroi; + structuresetroi.ROINumber = roinumber; + if( refframerefuid ) + structuresetroi.RefFrameRefUID = refframerefuid; + if( roiname ) + structuresetroi.ROIName = roiname; + if( roigenerationalgorithm ) + structuresetroi.ROIGenerationAlgorithm = roigenerationalgorithm; + if( roidescription ) + structuresetroi.ROIDescription = roidescription; + StructureSetROIs.push_back( structuresetroi ); + } + vtkIdType GetNumberOfStructureSetROIs() + { + return StructureSetROIs.size(); + } + int GetStructureSetObservationNumber(vtkIdType id) + { + return StructureSetROIs[id].ObservationNumber; + } + int GetStructureSetROINumber(vtkIdType id) + { + return StructureSetROIs[id].ROINumber; + } + const char *GetStructureSetRTROIInterpretedType(vtkIdType id) + { + return StructureSetROIs[id].RTROIInterpretedType.c_str(); + } + const char *GetStructureSetROIObservationLabel(vtkIdType id) + { + return StructureSetROIs[id].ROIObservationLabel.c_str(); + } + const char *GetStructureSetROIRefFrameRefUID(vtkIdType id) + { + return StructureSetROIs[id].RefFrameRefUID.c_str(); + } + const char *GetStructureSetROIName(vtkIdType id) + { + return StructureSetROIs[id].ROIName.c_str(); + } + const char *GetStructureSetROIGenerationAlgorithm(vtkIdType id) + { + return StructureSetROIs[id].ROIGenerationAlgorithm.c_str(); + } + const char *GetStructureSetROIDescription(vtkIdType id) + { + return StructureSetROIs[id].ROIDescription.c_str(); + } + + std::vector StructureSetROIs; +}; + +//---------------------------------------------------------------------------- +vtkRTStructSetProperties::vtkRTStructSetProperties() +{ + this->Internals = new vtkRTStructSetPropertiesInternals; + + this->StructureSetLabel = NULL; + this->StructureSetName = NULL; + this->StructureSetDate = NULL; + this->StructureSetTime = NULL; + + this->SOPInstanceUID= NULL; + this->StudyInstanceUID = NULL; + this->SeriesInstanceUID = NULL; + this->ReferenceSeriesInstanceUID = NULL; + this->ReferenceFrameOfReferenceUID = NULL; +} + +//---------------------------------------------------------------------------- +vtkRTStructSetProperties::~vtkRTStructSetProperties() +{ + delete this->Internals; + this->Clear(); +} + +//---------------------------------------------------------------------------- +void vtkRTStructSetProperties::AddContourReferencedFrameOfReference(vtkIdType pdnum, const char *classuid , const char * instanceuid ) +{ + this->Internals->AddContourReferencedFrameOfReference(pdnum, classuid, instanceuid ); +} +const char *vtkRTStructSetProperties::GetContourReferencedFrameOfReferenceClassUID( vtkIdType pdnum, vtkIdType id ) +{ + return this->Internals->GetContourReferencedFrameOfReferenceClassUID(pdnum, id ); +} + +const char *vtkRTStructSetProperties::GetContourReferencedFrameOfReferenceInstanceUID( vtkIdType pdnum, vtkIdType id ) +{ + return this->Internals->GetContourReferencedFrameOfReferenceInstanceUID(pdnum ,id ); +} + +vtkIdType vtkRTStructSetProperties::GetNumberOfContourReferencedFrameOfReferences() +{ + return this->Internals->GetNumberOfContourReferencedFrameOfReferences(); +} + +vtkIdType vtkRTStructSetProperties::GetNumberOfContourReferencedFrameOfReferences(vtkIdType pdnum) +{ + return this->Internals->GetNumberOfContourReferencedFrameOfReferences(pdnum); +} + +void vtkRTStructSetProperties::AddReferencedFrameOfReference( const char *classuid , const char * instanceuid ) +{ + this->Internals->AddReferencedFrameOfReference( classuid, instanceuid ); +} + +const char *vtkRTStructSetProperties::GetReferencedFrameOfReferenceClassUID( vtkIdType id ) +{ + return this->Internals->GetReferencedFrameOfReferenceClassUID(id ); +} + +const char *vtkRTStructSetProperties::GetReferencedFrameOfReferenceInstanceUID( vtkIdType id ) +{ + return this->Internals->GetReferencedFrameOfReferenceInstanceUID(id ); +} + +vtkIdType vtkRTStructSetProperties::GetNumberOfReferencedFrameOfReferences() +{ + return this->Internals->GetNumberOfReferencedFrameOfReferences(); +} +void vtkRTStructSetProperties::AddStructureSetROIObservation( int refnumber, + int observationnumber, + const char *rtroiinterpretedtype, + const char *roiinterpreter, + const char *roiobservationlabel +) +{ + this->Internals->AddStructureSetROIObservation( refnumber, observationnumber, rtroiinterpretedtype, roiinterpreter, roiobservationlabel ); +} + +void vtkRTStructSetProperties::AddStructureSetROI( int roinumber, + const char* refframerefuid, + const char* roiname, + const char* roigenerationalgorithm, + const char* roidescription + ) +{ + this->Internals->AddStructureSetROI( roinumber, refframerefuid, roiname, roigenerationalgorithm, roidescription ); +} + +vtkIdType vtkRTStructSetProperties::GetNumberOfStructureSetROIs() +{ + return this->Internals->GetNumberOfStructureSetROIs(); +} +int vtkRTStructSetProperties::GetStructureSetObservationNumber(vtkIdType id) +{ + return this->Internals->GetStructureSetObservationNumber(id); +} +int vtkRTStructSetProperties::GetStructureSetROINumber(vtkIdType id) +{ + return this->Internals->GetStructureSetROINumber(id); +} +const char *vtkRTStructSetProperties::GetStructureSetRTROIInterpretedType(vtkIdType id) +{ + return this->Internals->GetStructureSetRTROIInterpretedType(id); +} +const char *vtkRTStructSetProperties::GetStructureSetROIObservationLabel(vtkIdType id) +{ + return this->Internals->GetStructureSetROIObservationLabel(id); +} + +const char *vtkRTStructSetProperties::GetStructureSetROIRefFrameRefUID(vtkIdType id) +{ + return this->Internals->GetStructureSetROIRefFrameRefUID(id); +} +const char *vtkRTStructSetProperties::GetStructureSetROIName(vtkIdType id) +{ + return this->Internals->GetStructureSetROIName(id); +} +const char *vtkRTStructSetProperties::GetStructureSetROIGenerationAlgorithm(vtkIdType id) +{ + return this->Internals->GetStructureSetROIGenerationAlgorithm(id); +} +const char *vtkRTStructSetProperties::GetStructureSetROIDescription(vtkIdType id) +{ + return this->Internals->GetStructureSetROIDescription(id); +} + +//---------------------------------------------------------------------------- +void vtkRTStructSetProperties::Clear() +{ + this->SetStructureSetLabel(NULL); + this->SetStructureSetName(NULL); + this->SetStructureSetDate(NULL); + this->SetStructureSetTime(NULL); + + this->SetSOPInstanceUID( NULL ); + this->SetStudyInstanceUID ( NULL ); + this->SetSeriesInstanceUID ( NULL ); + this->SetReferenceSeriesInstanceUID ( NULL ); + this->SetReferenceFrameOfReferenceUID ( NULL ); + +} + +//---------------------------------------------------------------------------- +void vtkRTStructSetProperties::DeepCopy(vtkRTStructSetProperties *p) +{ + if (p == NULL) + { + return; + } + + this->Clear(); + + this->SetStructureSetDate(p->GetStructureSetDate()); + this->SetStructureSetTime(p->GetStructureSetTime()); + + this->Internals->DeepCopy( p->Internals ); +} + +//---------------------------------------------------------------------------- +void vtkRTStructSetProperties::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os, indent); + + os << "\n" << indent << "StructureSetDate: "; + if (this->StructureSetDate) + { + os << this->StructureSetDate; + } + os << "\n" << indent << "StructureSetTime: "; + if (this->StructureSetTime) + { + os << this->StructureSetTime; + } + + this->Internals->Print(os << "\n", indent.GetNextIndent() ); +} diff --git a/gdcm/Utilities/VTK/vtkRTStructSetProperties.h b/gdcm/Utilities/VTK/vtkRTStructSetProperties.h new file mode 100644 index 0000000..e47c757 --- /dev/null +++ b/gdcm/Utilities/VTK/vtkRTStructSetProperties.h @@ -0,0 +1,132 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +// .NAME vtkRTStructSetProperties - some rtstruct properties. +// .SECTION Description +// +// .SECTION See Also +// vtkGDCMPolyDataReader vtkGDCMPolyDataWriter + +#ifndef VTKRTSTRUCTSETPROPERTIES_H +#define VTKRTSTRUCTSETPROPERTIES_H + +#include "vtkObject.h" + +class vtkRTStructSetPropertiesInternals; + +class VTK_EXPORT vtkRTStructSetProperties : public vtkObject +{ +public: + static vtkRTStructSetProperties *New(); + vtkTypeRevisionMacro(vtkRTStructSetProperties,vtkObject); + void PrintSelf(ostream& os, vtkIndent indent); + + // Description: + // Convenience method to reset all fields to an emptry string/value + virtual void Clear(); + + // Description: + // + vtkSetStringMacro(StructureSetLabel); + vtkGetStringMacro(StructureSetLabel); + + vtkSetStringMacro(StructureSetName); + vtkGetStringMacro(StructureSetName); + + vtkSetStringMacro(StructureSetDate); + vtkGetStringMacro(StructureSetDate); + + vtkSetStringMacro(StructureSetTime); + vtkGetStringMacro(StructureSetTime); + + vtkSetStringMacro(SOPInstanceUID); + vtkGetStringMacro(SOPInstanceUID); + + vtkSetStringMacro(StudyInstanceUID); + vtkGetStringMacro(StudyInstanceUID); + + vtkSetStringMacro(SeriesInstanceUID); + vtkGetStringMacro(SeriesInstanceUID); + + vtkSetStringMacro(ReferenceSeriesInstanceUID); + vtkGetStringMacro(ReferenceSeriesInstanceUID); + + vtkSetStringMacro(ReferenceFrameOfReferenceUID); + vtkGetStringMacro(ReferenceFrameOfReferenceUID); + + // Description: + // Copy the contents of p to this instance. + virtual void DeepCopy(vtkRTStructSetProperties *p); + + void AddContourReferencedFrameOfReference( vtkIdType pdnum, const char *classuid , const char * instanceuid ); + const char *GetContourReferencedFrameOfReferenceClassUID( vtkIdType pdnum, vtkIdType id ); + const char *GetContourReferencedFrameOfReferenceInstanceUID( vtkIdType pdnum, vtkIdType id ); + vtkIdType GetNumberOfContourReferencedFrameOfReferences(); + vtkIdType GetNumberOfContourReferencedFrameOfReferences(vtkIdType pdnum); + + void AddReferencedFrameOfReference( const char *classuid , const char * instanceuid ); + const char *GetReferencedFrameOfReferenceClassUID( vtkIdType id ); + const char *GetReferencedFrameOfReferenceInstanceUID( vtkIdType id ); + vtkIdType GetNumberOfReferencedFrameOfReferences(); + + void AddStructureSetROI( int roinumber, + const char* refframerefuid, + const char* roiname, + const char* ROIGenerationAlgorithm, + const char* ROIDescription = 0 + ); + void AddStructureSetROIObservation( int refnumber, + int observationnumber, + const char *rtroiinterpretedtype, + const char *roiinterpreter, + const char *roiobservationlabel = 0 + ); + + vtkIdType GetNumberOfStructureSetROIs(); + int GetStructureSetObservationNumber(vtkIdType id); + int GetStructureSetROINumber(vtkIdType id); + const char *GetStructureSetROIRefFrameRefUID(vtkIdType); + const char *GetStructureSetROIName(vtkIdType); + const char *GetStructureSetROIGenerationAlgorithm(vtkIdType); + const char *GetStructureSetROIDescription(vtkIdType id); + const char *GetStructureSetRTROIInterpretedType(vtkIdType id); + const char *GetStructureSetROIObservationLabel(vtkIdType id); + +protected: + vtkRTStructSetProperties(); + ~vtkRTStructSetProperties(); + + char *StructureSetLabel; + char *StructureSetName; + char *StructureSetDate; + char *StructureSetTime; + + char *SOPInstanceUID; + char *StudyInstanceUID; + char *SeriesInstanceUID; + + char *ReferenceSeriesInstanceUID; + char *ReferenceFrameOfReferenceUID; + + // Description: + // PIMPL Encapsulation for STL containers + //BTX + vtkRTStructSetPropertiesInternals *Internals; + //ETX + +private: + vtkRTStructSetProperties(const vtkRTStructSetProperties&); // Not implemented. + void operator=(const vtkRTStructSetProperties&); // Not implemented. +}; + +#endif diff --git a/gdcm/Utilities/VTK/vtkgdcm.i b/gdcm/Utilities/VTK/vtkgdcm.i new file mode 100644 index 0000000..34ff285 --- /dev/null +++ b/gdcm/Utilities/VTK/vtkgdcm.i @@ -0,0 +1,534 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +%module(docstring="A VTK/GDCM binding") vtkgdcm +#pragma SWIG nowarn=504,510 + +//%pragma(csharp) moduleimports=%{ +//using Kitware.VTK; +//%} + +#if defined(SWIGCSHARP) +%{ +#define SWIGCSHARP +%} +#endif + +#if defined(SWIGPHP) +%{ +#define SWIGPHP +%} +#endif + +%{ +//#define VTK_MAJOR_VERSION 5 +//#define VTK_MINOR_VERSION 4 +//#define VTK_BUILD_VERSION 0 +//#define VTK_VERSION "5.4.0" +%} + + +%{ +// Let's reproduce the stack of include, when one would include vtkSetGet: +#include "vtkConfigure.h" +#include "vtkType.h" +#include "vtkSystemIncludes.h" +#include "vtkSetGet.h" +#include + +// Common stuff +#include "vtkObjectBase.h" +#include "vtkObject.h" + +#include "vtkStringArray.h" +#include "vtkMatrix4x4.h" +#include "vtkMedicalImageProperties.h" + +// Wrap vtkImageData +#include "vtkDataObject.h" +#include "vtkDataSet.h" +#include "vtkImageData.h" +#include "vtkPointSet.h" +#include "vtkPolyData.h" + +#include "vtkGDCMTesting.h" + +// same for vtkGDCMImageReader / vtkGDCMImageWriter so that we get all +// parent's member class functions properly wrapped. (Update, SetFileName ...) +#include "vtkAlgorithm.h" +#include "vtkImageAlgorithm.h" +#include "vtkThreadedImageAlgorithm.h" +#include "vtkImageWriter.h" +#include "vtkImageReader2.h" +#include "vtkMedicalImageReader2.h" +#include "vtkGDCMImageReader.h" +#include "vtkGDCMImageWriter.h" + +#include "vtkImageExport.h" +#include "vtkImageImport.h" +#include "vtkImageCast.h" +#include "vtkVolumeReader.h" +#include "vtkVolume16Reader.h" + +#include "vtkWindowToImageFilter.h" + +#include "vtkToolkits.h" // VTK_DATA_ROOT +%} + +//%typemap(csimports) vtkGDCMImageWriter %{ +//%typemap(csimports) SWIGTYPE %{ +//// I need to duplicate those also: +//using System; +//using System.Runtime.InteropServices; +//// my special import: +//using Kitware.VTK; +//using Kitware.mummy.Runtime; +//%} + +//%pragma(csharp) imclassimports=%{ +//using System; +//using System.Runtime.InteropServices; +//using My.Own.Namespace; +//%} + +#ifdef USEACTIVIZ +%typemap(csimports) SWIGTYPE %{ +// I need to duplicate those also: +using System; +using System.Runtime.InteropServices; +// my special import: +using Kitware.VTK; +//using Kitware.mummy.Runtime; +%} +#endif + +#define GDCM_EXPORT +#define VTK_EXPORT +#define VTK_COMMON_EXPORT +#define VTK_FILTERING_EXPORT +#define VTK_IO_EXPORT +#define VTK_IMAGING_EXPORT +#define VTK_RENDERING_EXPORT + + +// FIXME. Including #include vtkSetGet would not work on siwg 1.3.33 ... +#define vtkGetMacro(name,type) virtual type Get##name (); +#define vtkSetMacro(name,type) virtual void Set##name (type _arg); +#define vtkBooleanMacro(name,type) \ + virtual void name##On (); \ + virtual void name##Off (); +#define vtkGetVector3Macro(name,type) virtual type *Get##name (); +#define vtkGetVector6Macro(name,type) virtual type *Get##name (); +#define vtkGetObjectMacro(name,type) virtual type *Get##name (); +#define vtkSetClampMacro(name,type,min,max) virtual void Set##name (type _arg); +#define vtkSetStringMacro(name) virtual void Set##name (const char* _arg); +#define vtkGetStringMacro(name) virtual char* Get##name (); +#define vtkGetVectorMacro(name,type,count) virtual type *Get##name (); +#define vtkNotUsed(x) x +#define vtkGetVector2Macro(name,type) virtual type *Get##name (); +#define vtkSetVector2Macro(name,type) virtual void Set##name (type _arg1, type _arg2); +#define vtkSetVector3Macro(name,type) virtual void Set##name (type _arg1, type _arg2, type _arg3); + + +//%include "vtkConfigure.h" + +//%ignore vtkGDCMImageReader::GetOverlay; +//%ignore vtkGDCMImageReader::GetIconImage; +// +//%ignore vtkAlgorithm::GetOutputDataObject; +//%ignore vtkAlgorithm::GetInputDataObject; +// +//%ignore vtkImageAlgorithm::GetOutput; +//%ignore vtkImageAlgorithm::GetInput; +//%ignore vtkImageAlgorithm::GetImageDataInput; + +%ignore operator<<(ostream& os, vtkObjectBase& o); + +%ignore vtkMatrix4x4::operator[]; +%ignore vtkMatrix4x4::Determinant(vtkMatrix4x4 &); +%ignore vtkMatrix4x4::Adjoint(vtkMatrix4x4 *in, vtkMatrix4x4 *out); +%ignore vtkMatrix4x4::Invert(vtkMatrix4x4 *in, vtkMatrix4x4 *out); +%ignore vtkMatrix4x4::Transpose(vtkMatrix4x4 *in, vtkMatrix4x4 *out); +// In VTK 5.8 we have to ignore the const variant: +%ignore vtkMatrix4x4::Invert(const vtkMatrix4x4 *in, vtkMatrix4x4 *out); +%ignore vtkMatrix4x4::Transpose(const vtkMatrix4x4 *in, vtkMatrix4x4 *out); + +%ignore vtkImageWriter::GetInput; // I am getting a warning on swig 1.3.33 because of vtkImageAlgorithm.GetInput + +// Let's wrap the following constants: +// this is only a subset of vtkSystemIncludes.h : +#define VTK_LUMINANCE 1 +#define VTK_LUMINANCE_ALPHA 2 +#define VTK_RGB 3 +#define VTK_RGBA 4 + +//#include "vtkConfigure.h" +//#define VTK_USE_64BIT_IDS +// +//#ifdef VTK_USE_64BIT_IDS +//typedef long long vtkIdType; +//#else +//typedef int vtkIdType; +//#endif +//typedef vtkIdType2 vtkIdType; +//%apply vtkIdType { vtkIdType } +//#define vtkIdType vtkIdType; +//%include "vtkType.h" + +#ifdef USEACTIVIZ + +%typemap(cstype) vtkDataObject * "vtkDataObject" +%typemap(csin) vtkDataObject * "$csinput.GetCppThis()" +/* + public vtkDataObject GetOutputDataObject(int port) { + IntPtr cPtr = vtkgdcmPINVOKE.vtkAlgorithm_GetOutputDataObject(swigCPtr, port); + SWIGTYPE_p_vtkDataObject ret = (cPtr == IntPtr.Zero) ? null : new SWIGTYPE_p_vtkDataObject(cPtr, false); + return ret; + } +*/ +%typemap(csout) (vtkDataObject*) { + IntPtr rawCppThisSwig = $imcall; + vtkDataObject data = new vtkDataObject( rawCppThisSwig, false, false ); + return data; +} + +%typemap(cstype) vtkStringArray * "vtkStringArray" +%typemap(csin) vtkStringArray * "$csinput.GetCppThis()" +%typemap(csout) (vtkStringArray*) { + IntPtr rawCppThisSwig = $imcall; + vtkStringArray data = new vtkStringArray( rawCppThisSwig, false, false ); + return data; +} + +%typemap(cstype) vtkPolyData * "vtkPolyData" +%typemap(csin) vtkPolyData * "$csinput.GetCppThis()" +%typemap(csout) (vtkPolyData*) { + IntPtr rawCppThisSwig = $imcall; + vtkPolyData data = new vtkPolyData( rawCppThisSwig, false, false ); + return data; +} + +%typemap(cstype) vtkMatrix4x4 * "vtkMatrix4x4" +%typemap(csin) vtkMatrix4x4 * "$csinput.GetCppThis()" +%typemap(csout) (vtkMatrix4x4*) { + IntPtr rawCppThisSwig = $imcall; + vtkMatrix4x4 data = new vtkMatrix4x4( rawCppThisSwig, false, false ); + return data; +} + +%typemap(cstype) vtkMedicalImageProperties * "vtkMedicalImageProperties" +%typemap(csin) vtkMedicalImageProperties * "$csinput.GetCppThis()" +%typemap(csout) (vtkMedicalImageProperties*) { + IntPtr rawCppThisSwig = $imcall; + vtkMedicalImageProperties data = new vtkMedicalImageProperties( rawCppThisSwig, false, false ); + return data; +} + +%typemap(cstype) vtkImageData * "vtkImageData" +%typemap(csin) vtkImageData * "$csinput.GetCppThis()" +%typemap(csout) (vtkImageData *) { + IntPtr rawCppThisSwig = $imcall; + vtkImageData data = new vtkImageData( rawCppThisSwig, false, false ); + //vtkImageData data = null; + //bool created; + //if( IntPtr.Zero != rawCppThisSwig ) + // { + // data = (vtkImageData) Kitware.mummy.Runtime.Methods.CreateWrappedObject( + // vtkImageData.MRClassNameKey, rawCppThisSwig, false, out created); + // // created is true if the C# object was created by this call, false if it was already cached in the table + // } + return data; +} +// +//%typemap(csout) (vtkDataObject *) { +// vtkImageData data = null; +//// uint mteStatus = 0; +//// uint maxValue = uint.MaxValue; +//// uint rawRefCount = 0; +//// IntPtr rawCppThis = +////vtkImageAlgorithm_GetOutput_06(base.GetCppThis(), ref mteStatus, ref +////maxValue, ref rawRefCount); +//// IntPtr rawCppThisSwig = $imcall; +//// if (IntPtr.Zero != rawCppThisSwig) +//// { +//// bool flag; +//// data = (vtkImageData) Methods.CreateWrappedObject(mteStatus, +////maxValue, rawRefCount, rawCppThisSwig, true, out flag); +//// if (flag) +//// { +//// data.Register(null); +//// } +//// } +// return data; +//} +// +#endif //USEACTIVIZ + +#ifdef USEACTIVIZ +// By hiding all New operator I make sure that no-one will ever be +// able to create a swig wrap object I did not decide to allow. +// For instance the only two objects allowed for now are: +// - vtkGDCMImageReader +// - vtkGDCMImageWriter +// BUG: +// when using %ignore vtkObjectBase::New() +// the vtkObjectBase_New() function is not generated, which is used +// internally in the new cstor that I provide +%csmethodmodifiers vtkObjectBase::New() "internal new" +%csmethodmodifiers vtkObject::New() "internal new" +%csmethodmodifiers vtkAlgorithm::New() "internal new" +%csmethodmodifiers vtkImageAlgorithm::New() "internal new" +%csmethodmodifiers vtkImageWriter::New() "internal new" +%csmethodmodifiers vtkImageReader2::New() "internal new" +%csmethodmodifiers vtkMedicalImageReader2::New() "internal new" + +%csmethodmodifiers vtkGDCMImageReader::New() "public new" +%csmethodmodifiers vtkGDCMImageWriter::New() "public new" +%csmethodmodifiers vtkGDCMTesting::New() "public new" + +#endif + +%newobject vtkGDCMTesting::New(); +%newobject vtkGDCMImageWriter::New(); +%newobject vtkGDCMImageReader::New(); + +%delobject vtkObjectBase::Delete(); + +// TODO: I need to fix Delete and make sure SWIG owns the C++ ptr (call ->Delete in the Dispose layer) +//%ignore vtkObjectBase::Delete; +%ignore vtkObjectBase::FastDelete; +%ignore vtkObjectBase::PrintSelf; +%ignore vtkObjectBase::PrintHeader; +%ignore vtkObjectBase::PrintTrailer; +%ignore vtkObjectBase::Print; +%ignore vtkObjectBase::PrintRevisions; +%ignore vtkObject::PrintSelf; +%ignore vtkAlgorithm::PrintSelf; +%ignore vtkImageAlgorithm::PrintSelf; +%ignore vtkImageAlgorithm::ProcessRequest; +%ignore vtkImageWriter::PrintSelf; +%ignore vtkImageReader2::PrintSelf; +%ignore vtkMedicalImageReader2::PrintSelf; +%ignore vtkGDCMImageReader::PrintSelf; +%ignore vtkGDCMImageWriter::PrintSelf; + +%typemap(csdestruct_derived, methodname="Dispose", methodmodifiers="public") vtkGDCMTesting { + lock(this) { + if(swigCPtr.Handle != IntPtr.Zero && swigCMemOwn) { + swigCMemOwn = false; + vtkgdcmPINVOKE.vtkObjectBase_Delete(swigCPtr); + } + swigCPtr = new HandleRef(null, IntPtr.Zero); + GC.SuppressFinalize(this); + base.Dispose(); + } +} +%typemap(csdestruct_derived, methodname="Dispose", methodmodifiers="public") vtkGDCMImageReader { + lock(this) { + if(swigCPtr.Handle != IntPtr.Zero && swigCMemOwn) { + swigCMemOwn = false; + vtkgdcmPINVOKE.vtkObjectBase_Delete(swigCPtr); + } + swigCPtr = new HandleRef(null, IntPtr.Zero); + GC.SuppressFinalize(this); + base.Dispose(); + } +} +%typemap(csdestruct_derived, methodname="Dispose", methodmodifiers="public") vtkGDCMImageWriter { + lock(this) { + if(swigCPtr.Handle != IntPtr.Zero && swigCMemOwn) { + swigCMemOwn = false; + vtkgdcmPINVOKE.vtkObjectBase_Delete(swigCPtr); + } + swigCPtr = new HandleRef(null, IntPtr.Zero); + GC.SuppressFinalize(this); + base.Dispose(); + } +} + +%include "vtkObjectBase.h" +#ifdef SWIGCSHARP +%csmethodmodifiers vtkObjectBase::ToString() "public override" +#endif +%extend vtkObjectBase +{ + const char *ToString() + { + static std::string buffer; + std::ostringstream os; + self->Print( os ); + buffer = os.str(); + return buffer.c_str(); + } +}; + +%include "vtkObject.h" + +%defaultdtor vtkGDCMTesting; // FIXME does not seems to be working +%include "vtkGDCMTesting.h" + +#ifndef USEACTIVIZ +%include "vtkStringArray.h" +%include "vtkMatrix4x4.h" +%include "vtkMedicalImageProperties.h" +%include "vtkDataObject.h" +%include "vtkDataSet.h" +%include "vtkImageData.h" +%include "vtkPointSet.h" +%include "vtkPolyData.h" +#endif + +%include "vtkAlgorithm.h" +%include "vtkImageAlgorithm.h" +#ifndef USEACTIVIZ +%include "vtkThreadedImageAlgorithm.h" +#endif +%include "vtkImageWriter.h" + +/* +By default swig generates: + public virtual SWIGTYPE_p_double GetImageOrientationPatient() { + IntPtr cPtr = vtkgdcmPINVOKE.vtkGDCMImageReader_GetImageOrientationPatient(swigCPtr); + SWIGTYPE_p_double ret = (cPtr == IntPtr.Zero) ? null : new SWIGTYPE_p_double(cPtr, false); + return ret; + } +while we would want: + public virtual double[] GetImageOrientationPatient() { + IntPtr source = vtkgdcmPINVOKE.vtkGDCMImageReader_GetImageOrientationPatient(swigCPtr); + double[] ret = null; + if (IntPtr.Zero != source) + { + ret = new double[6]; + Marshal.Copy(source, destination, 0, destination.Length); + } + return ret; + } + +*/ + +//%typemap(ctype) double[] "double*" +%typemap(cstype) double * "double[]" +%typemap(csout) double* GetImagePositionPatient() { + IntPtr source = $imcall; + double[] destination = null; + if (IntPtr.Zero != source) { + destination = new double[3]; + Marshal.Copy(source, destination, 0, destination.Length); + } + return destination; + } + +%typemap(csout) double* GetImageOrientationPatient() { + IntPtr source = $imcall; + double[] destination = null; + if (IntPtr.Zero != source) { + destination = new double[6]; + Marshal.Copy(source, destination, 0, destination.Length); + } + return destination; + } + +%typemap(csout) double* GetDataSpacing() { + IntPtr source = $imcall; + double[] destination = null; + if (IntPtr.Zero != source) { + destination = new double[3]; + Marshal.Copy(source, destination, 0, destination.Length); + } + return destination; + } + +%typemap(csout) double* GetDataOrigin() { + IntPtr source = $imcall; + double[] destination = null; + if (IntPtr.Zero != source) { + destination = new double[3]; + Marshal.Copy(source, destination, 0, destination.Length); + } + return destination; + } + +%include "vtkImageReader2.h" +%include "vtkMedicalImageReader2.h" + +//%rename (vtkGDCMImageReaderInternal) vtkGDCMImageReader; +//%rename (vtkGDCMImageWriterInternal) vtkGDCMImageWriter; + +%include "vtkGDCMImageReader.h" +%include "vtkGDCMImageWriter.h" +%extend vtkGDCMTesting +{ +%typemap(cscode) vtkGDCMTesting +%{ + public vtkGDCMTesting() : this(vtkgdcmPINVOKE.vtkGDCMTesting_New(), true) { + } + ~vtkGDCMTesting() { + Dispose(); + } +%} +}; + +%extend vtkGDCMImageReader +{ +%typemap(cscode) vtkGDCMImageReader +%{ + public vtkGDCMImageReader() : this(vtkgdcmPINVOKE.vtkGDCMImageReader_New(), true) { + } + ~vtkGDCMImageReader() { + Dispose(); + } +%} +}; + +#ifdef SWIGPHP +%extend vtkGDCMImageReader +{ +//public function __construct2($res=null) { +// $this->_cPtr=vtkGDCMImageReader_Create(); +//} + +//%typemap(out) vtkGDCMImageReader* (vtkGDCMImageReader::New) +//%{ +//public function __construct($res=null) { +// $this->_cPtr=vtkGDCMImageReader_Create(); +//} +//%} +}; +#endif + +%extend vtkGDCMImageWriter +{ +%typemap(cscode) vtkGDCMImageWriter +%{ + public vtkGDCMImageWriter() : this(vtkgdcmPINVOKE.vtkGDCMImageWriter_New(), true) { + } + ~vtkGDCMImageWriter() { + Dispose(); + } +%} +}; +%clear double*; +%clear double* GetDataSpacing(); +%clear double* GetDataOrigin(); + +#ifdef SWIGPHP +%include "vtkWindowToImageFilter.h" +#endif + +#ifndef USEACTIVIZ +%include "vtkImageExport.h" +%include "vtkImageImport.h" +%include "vtkImageCast.h" +%include "vtkVolumeReader.h" +%include "vtkVolume16Reader.h" +#endif diff --git a/gdcm/Utilities/VTK/vtkgdcm.py b/gdcm/Utilities/VTK/vtkgdcm.py new file mode 100644 index 0000000..c1c6672 --- /dev/null +++ b/gdcm/Utilities/VTK/vtkgdcm.py @@ -0,0 +1,62 @@ +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +""" This module loads all the classes from the GDCM-VTK library into +its namespace. This is a required module.""" + +import os + +# FIXME: GDCM_WHEREAMI need also to be set here, since the lib is dlopen'ed before gdcm.py is +# actually read... +os.environ["GDCM_WHEREAMI"]=os.path.dirname(__file__) +if os.name == 'posix': + # extremely important ! + # http://gcc.gnu.org/faq.html#dso + # http://mail.python.org/pipermail/python-dev/2002-May/023923.html + # http://wiki.python.org/moin/boost.python/CrossExtensionModuleDependencies + # This is now merged in VTK 5.2: + # http://vtk.org/cgi-bin/viewcvs.cgi/Wrapping/Python/vtk/__init__.py?r1=1.13&r2=1.14 + import sys + orig_dlopen_flags = sys.getdlopenflags() + try: + import dl + except ImportError: + # are we on AMD64 ? + try: + import DLFCN as dl + except ImportError: + print("Could not import dl") + dl = None + if dl: + #print "dl was imported" + #sys.setdlopenflags(dl.RTLD_LAZY|dl.RTLD_GLOBAL) + sys.setdlopenflags(dl.RTLD_NOW|dl.RTLD_GLOBAL) + from libvtkgdcmPython import * + # revert: + sys.setdlopenflags(orig_dlopen_flags) + del sys, dl + del orig_dlopen_flags +else: + from vtkgdcmPython import * + +# to provide a compatibilty layer with VTK 4.2 and VTK 4.4 where vtkStringArray was not present +# and VTK 5.x where there is one... +try: + # if vtkStringArray can be found in vtk let's use it ! + from vtk import vtkStringArray +except: + print("Using compatibility layer (VTK 4) for vtkStringArray") + +# bye bye +del os diff --git a/gdcm/Utilities/dicom3tools/process.sh b/gdcm/Utilities/dicom3tools/process.sh new file mode 100644 index 0000000..240ac7b --- /dev/null +++ b/gdcm/Utilities/dicom3tools/process.sh @@ -0,0 +1,37 @@ +#!/bin/sh -xe + +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +# This script convert dicom3tools internal txt format into XML for GDCM + +# Usage: +# $ process.sh agfa.tpl + +# remove empty lines +sed '/^\s*$/d' $1 > /tmp/clean2.tpl +# remove comments: +sed '/^#/d' /tmp/clean2.tpl > /tmp/clean.tpl +# convert to xml +sed 's/^.*$/' /tmp/dummy.xml +# add end: +echo '' >> /tmp/dummy.xml +# format and check if valid xml +xmllint --format /tmp/dummy.xml -o `basename $1 tpl`xml diff --git a/gdcm/Utilities/doxygen/CMakeLists.txt b/gdcm/Utilities/doxygen/CMakeLists.txt new file mode 100644 index 0000000..f8f144b --- /dev/null +++ b/gdcm/Utilities/doxygen/CMakeLists.txt @@ -0,0 +1,227 @@ +# Documentation +# http://www.stack.nl/~dimitri/doxygen +# http://www.stack.nl/~dimitri/doxygen/commands.html#cmdsa +if(GDCM_DOCUMENTATION) + + find_package(Doxygen REQUIRED) + + if(GDCM_DOXYGEN_NO_FOOTER) + set(GDCM_HTML_FOOTER) + else() + # Otherwise use gdcm/piwik/sf.net footer: + set(GDCM_HTML_FOOTER ${GDCM_SOURCE_DIR}/Utilities/doxygen/footer.html) + endif() + configure_file( + ${GDCM_SOURCE_DIR}/Utilities/doxygen/doxyfile.in + ${GDCM_BINARY_DIR}/Utilities/doxygen/Doxyfile + ) + + file(GLOB_RECURSE headerfiles + "${GDCM_SOURCE_DIR}/Source/*.h" + "${GDCM_SOURCE_DIR}/Wrapping/*.h" + "${GDCM_SOURCE_DIR}/Utilities/VTK/*.h" + "${GDCM_SOURCE_DIR}/Utilities/doxygen/man/*.man" + ) + list(REMOVE_ITEM headerfiles + "${GDCM_SOURCE_DIR}/Source/DataDictionary/gdcmTagKeywords.h" + "${GDCM_SOURCE_DIR}/Source/DataDictionary/gdcmTagToType.h" + ) + #message(${headerfiles}) + # We are depending only on header files and README.txt but other files + # could be needed for complete dependencies + file(GLOB_RECURSE examplefiles + "${GDCM_SOURCE_DIR}/Examples/*.cxx" + "${GDCM_SOURCE_DIR}/Examples/*.cs" + "${GDCM_SOURCE_DIR}/Examples/*.java" + "${GDCM_SOURCE_DIR}/Examples/*.py" + ) + file(GLOB_RECURSE vtkexamplefiles + "${GDCM_SOURCE_DIR}/Utilities/VTK/Examples/*.cxx" + "${GDCM_SOURCE_DIR}/Utilities/VTK/Examples/*.cs" + "${GDCM_SOURCE_DIR}/Utilities/VTK/Examples/*.java" + "${GDCM_SOURCE_DIR}/Utilities/VTK/Examples/*.py" + ) + set(DOXYFILE_EXAMPLES) + foreach(file ${examplefiles} ${vtkexamplefiles}) + get_filename_component(f ${file} NAME) + set(DOXYFILE_EXAMPLES "${DOXYFILE_EXAMPLES}\n\\example ${f}") + endforeach() + configure_file( + ${GDCM_SOURCE_DIR}/Utilities/doxygen/TestsList.txt.in + ${GDCM_BINARY_DIR}/Utilities/doxygen/TestsList.txt + @ONLY + ) + if(GDCM_MINOR_VERSION MATCHES "[02468]$") + set(GDCM_DOC_PDF_LINK + "http://gdcm.sourceforge.net/${GDCM_MAJOR_VERSION}.${GDCM_MINOR_VERSION}/gdcm-${GDCM_VERSION}.pdf" + ) + set(GDCM_DOC_TARBALL_LINK + "http://gdcm.sourceforge.net/${GDCM_MAJOR_VERSION}.${GDCM_MINOR_VERSION}/gdcm-${GDCM_VERSION}-doc.tar.gz" + ) + else() + set(GDCM_DOC_PDF_LINK + "http://gdcm.sourceforge.net/gdcm-${GDCM_VERSION}.pdf" + ) + set(GDCM_DOC_TARBALL_LINK + "http://gdcm.sourceforge.net/gdcm-${GDCM_VERSION}-doc.tar.gz" + ) + endif() + configure_file( + ${GDCM_SOURCE_DIR}/Utilities/doxygen/README.txt.in + ${GDCM_BINARY_DIR}/Utilities/doxygen/README.txt + @ONLY + ) + set(GDCM_DOC_TARBALL + ${CMAKE_CURRENT_BINARY_DIR}/gdcm-${GDCM_VERSION}-doc.tar.gz + ) + # epstopdf is needed: sudo apt-get install texlive-extra-utils + # pdflatex is needed: sudo apt-get install texlive-latex-extra + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/html/index.html + ${CMAKE_CURRENT_BINARY_DIR}/latex/Makefile + # let's create the tarball within the same custom command to avoid complex dep. rules. + ${GDCM_DOC_TARBALL} + ${CMAKE_CURRENT_BINARY_DIR}/latex/refman.tex # output #1 (fake) + # 1. first thing first let's run doxygen + COMMAND ${DOXYGEN} + ARGS ${GDCM_BINARY_DIR}/Utilities/doxygen/Doxyfile + # 2. tarball gen. + COMMAND ${CMAKE_COMMAND} + ARGS -E tar cfz ${GDCM_DOC_TARBALL} html + DEPENDS ${GDCM_BINARY_DIR}/Utilities/doxygen/Doxyfile + ${GDCM_BINARY_DIR}/Utilities/doxygen/README.txt + ${GDCM_BINARY_DIR}/Utilities/doxygen/TestsList.txt + ${headerfiles} + COMMENT "GDCM: Creating doxygen doc + tarball" + #WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + ) + + # PDF building part: + # When building latex, we have to run a custom command to produce the pdf file: + if(UNIX AND GDCM_PDF_DOCUMENTATION) + find_program(PDFOPT_EXECUTABLE pdfopt) + find_program(SED_EXECUTABLE sed) + find_package(LATEX REQUIRED) + mark_as_advanced(PDFOPT_EXECUTABLE SED_EXECUTABLE) + # Let's customize the pdf tags a little usind sed: + # Apparently egrep is also needed... + # BAD: there is a circular dependency where refman.tex depend on refman.tex in the sed steps... + # hack our way in anyway by simply removing the dep... + #add_custom_command( + # ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/patchtex.cmake + #) + # TODO, foreach(*.tex) + # sed -i -e "/home/mmalaterre/Projects/" ... + string(REPLACE "/" "\\/" sed_gdcm_source_dir ${GDCM_SOURCE_DIR}) + #message(${sed_gdcm_source_dir}) + add_custom_command( + OUTPUT #${CMAKE_CURRENT_BINARY_DIR}/latex/refman.tex # output #1 (fake) + ${CMAKE_CURRENT_BINARY_DIR}/latex/refman.pdf # output #2 + # Command #1 + COMMAND ${SED_EXECUTABLE} + ARGS -i.tmp -e "'s/]{hyperref}/]{hyperref}\\\\hypersetup{pdftitle={GDCM ${GDCM_VERSION} Reference Manual},pdfauthor={Mathieu Malaterre and co.},pdfsubject={Grassroots DICOM API reference},pdfkeywords={GDCM,DICOM,Network,Query\\/Retrieve,JPEG,Lossless JPEG,JPEG-LS,J2K,JPEG 2000,RLE},pdfpagemode={UseOutlines},bookmarks,bookmarksopen,pdfstartview={FitH},backref,colorlinks,linkcolor={black},citecolor={black},urlcolor={black},baseurl={http:\\/\\/gdcm.sourceforge.net}}\\\\hyperbaseurl{http:\\/\\/gdcm.sourceforge.net}/g'" ${CMAKE_CURRENT_BINARY_DIR}/latex/refman.tex + # Command #2 + COMMAND ${SED_EXECUTABLE} + ARGS -i.tmp -e "'s/${sed_gdcm_source_dir}/gdcm/g'" ${CMAKE_CURRENT_BINARY_DIR}/latex/*.tex + # Command #3 + COMMAND ${CMAKE_MAKE_PROGRAM} + DEPENDS #${CMAKE_CURRENT_BINARY_DIR}/latex/refman.tex +${CMAKE_CURRENT_BINARY_DIR}/latex/Makefile + #${GDCM_DOC_TARBALL} + COMMENT "GDCM: Creating (patched) pdf of documentation" + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/latex + ) + if(PDFOPT_EXECUTABLE) + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/latex/gdcm-${GDCM_VERSION}.pdf + COMMAND ${PDFOPT_EXECUTABLE} + ARGS ${CMAKE_CURRENT_BINARY_DIR}/latex/refman.pdf + ${CMAKE_CURRENT_BINARY_DIR}/latex/gdcm-${GDCM_VERSION}.pdf + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/latex/refman.pdf + COMMENT "GDCM: Creating optimized pdf version of documentation" + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/latex + ) + else() + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/latex/gdcm-${GDCM_VERSION}.pdf + COMMAND ${CMAKE_COMMAND} -E copy + ARGS ${CMAKE_CURRENT_BINARY_DIR}/latex/refman.pdf + ${CMAKE_CURRENT_BINARY_DIR}/latex/gdcm-${GDCM_VERSION}.pdf + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/latex/refman.pdf + COMMENT "GDCM: Creating unoptimized pdf version of documentation" + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/latex + ) + endif() + # add target to 'ALL' + add_custom_target(GDCMDoxygenPDF + ALL + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/latex/gdcm-${GDCM_VERSION}.pdf + COMMENT "GDCM: Executing GDCMDoxygenPDF" + ) + install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/latex/gdcm-${GDCM_VERSION}.pdf + DESTINATION ${GDCM_INSTALL_DOC_DIR} + ) + else() + # make DoxygenDoc depends on the final tarball thus all file are garantee to be generated + add_custom_target(GDCMDoxygenDoc + ALL + DEPENDS ${GDCM_DOC_TARBALL} + COMMENT "GDCM: Executing GDCMDoxygenDoc" + ) + endif() + + # Install html pages: + #install(FILES + # ${CMAKE_CURRENT_BINARY_DIR}/html/gdcm2vtk.html + # ${CMAKE_CURRENT_BINARY_DIR}/html/gdcmconv.html + # ${CMAKE_CURRENT_BINARY_DIR}/html/gdcmanon.html + # ${CMAKE_CURRENT_BINARY_DIR}/html/gdcmgendir.html + # ${CMAKE_CURRENT_BINARY_DIR}/html/gdcmdump.html + # ${CMAKE_CURRENT_BINARY_DIR}/html/gdcmimg.html + # ${CMAKE_CURRENT_BINARY_DIR}/html/gdcminfo.html + # ${CMAKE_CURRENT_BINARY_DIR}/html/gdcmpdf.html + # ${CMAKE_CURRENT_BINARY_DIR}/html/gdcmraw.html + # ${CMAKE_CURRENT_BINARY_DIR}/html/gdcmscanner.html + # ${CMAKE_CURRENT_BINARY_DIR}/html/gdcmtar.html + # ${CMAKE_CURRENT_BINARY_DIR}/html/gdcmviewer.html + # DESTINATION ${GDCM_INSTALL_DOC_DIR} COMPONENT DebugDevel + #) + install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/man/man1/gdcm2vtk.1 + ${CMAKE_CURRENT_BINARY_DIR}/man/man1/gdcm2pnm.1 + ${CMAKE_CURRENT_BINARY_DIR}/man/man1/gdcmconv.1 + ${CMAKE_CURRENT_BINARY_DIR}/man/man1/gdcmpap3.1 + ${CMAKE_CURRENT_BINARY_DIR}/man/man1/gdcmxml.1 + ${CMAKE_CURRENT_BINARY_DIR}/man/man1/gdcmanon.1 + ${CMAKE_CURRENT_BINARY_DIR}/man/man1/gdcmgendir.1 + ${CMAKE_CURRENT_BINARY_DIR}/man/man1/gdcmdump.1 + ${CMAKE_CURRENT_BINARY_DIR}/man/man1/gdcmdiff.1 + ${CMAKE_CURRENT_BINARY_DIR}/man/man1/gdcmimg.1 + ${CMAKE_CURRENT_BINARY_DIR}/man/man1/gdcminfo.1 + ${CMAKE_CURRENT_BINARY_DIR}/man/man1/gdcmpdf.1 + ${CMAKE_CURRENT_BINARY_DIR}/man/man1/gdcmraw.1 + ${CMAKE_CURRENT_BINARY_DIR}/man/man1/gdcmscu.1 + ${CMAKE_CURRENT_BINARY_DIR}/man/man1/gdcmscanner.1 + ${CMAKE_CURRENT_BINARY_DIR}/man/man1/gdcmtar.1 + ${CMAKE_CURRENT_BINARY_DIR}/man/man1/gdcmviewer.1 + DESTINATION ${GDCM_INSTALL_MAN_DIR}/man1 COMPONENT DebugDevel + ) + install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html DESTINATION ${GDCM_INSTALL_DOC_DIR} + PATTERN "*.md5" EXCLUDE + PATTERN "*.dot" EXCLUDE + ) + + # http://lists.debian.org/debian-italian/2006/12/msg00878.html + # man2txt : man man | col -b | less + + if(GDCM_USE_VTK) + # Make this option a hidden option as vtkgdcm/doxygen stuff is a mess (copy/paste + # from paraview). It always rerun -sigh- + if(GDCM_VTK_DOCUMENTATION) + set(BUILD_DOCUMENTATION 1) + endif() + subdirs(vtk) + endif() + +endif() diff --git a/gdcm/Utilities/doxygen/README b/gdcm/Utilities/doxygen/README new file mode 100644 index 0000000..9ba05aa --- /dev/null +++ b/gdcm/Utilities/doxygen/README @@ -0,0 +1,15 @@ +If you are reading this you are wondering what are ll those doxygen options: + +- I need HTML output for the doc at: +http://gdcm.sourceforge.net/html/ + +- I need the MAN output for the generated man pages, for debian packaging +this is a lintian error when a cmd line tool does not prodivde a man-page. + +- I need XML output for the python help page. See also the doxy2swig.py +that is located in Wrapping/Python dir. + +- Specify a special FOOTER so that Piwik engine is on and will generate traffic +to sf.net. + +The rest of the non-default options is currently not documented... diff --git a/gdcm/Utilities/doxygen/README.txt.in b/gdcm/Utilities/doxygen/README.txt.in new file mode 100644 index 0000000..287f9ee --- /dev/null +++ b/gdcm/Utilities/doxygen/README.txt.in @@ -0,0 +1,15 @@ +/** +\mainpage GDCM Documentation + +This is the developpers documentation. + +A PDF version of this doxygen documentation can be found here: + +@GDCM_DOC_PDF_LINK@ + +A tarball version of this HTML doxygen documentation can be found here: + +@GDCM_DOC_TARBALL_LINK@ + +\author Mathieu Malaterre +*/ diff --git a/gdcm/Utilities/doxygen/TestsList.txt.in b/gdcm/Utilities/doxygen/TestsList.txt.in new file mode 100644 index 0000000..a1bcb11 --- /dev/null +++ b/gdcm/Utilities/doxygen/TestsList.txt.in @@ -0,0 +1,5 @@ +/** + +@DOXYFILE_EXAMPLES@ + +*/ diff --git a/gdcm/Utilities/doxygen/authors.xml b/gdcm/Utilities/doxygen/authors.xml new file mode 100644 index 0000000..935394d --- /dev/null +++ b/gdcm/Utilities/doxygen/authors.xml @@ -0,0 +1,58 @@ + + + + + + Fabrice Bellet <bellet@users.sourceforge.net> + + + Christina Roßmanith <chrrossmanith@users.sourceforge.net> + + + Charles Pareto <chuckdawit@users.sourceforge.net> + + + Charl P. Botha <cpbotha@users.sourceforge.net> + + + Dean Inglis <deaninglis@users.sourceforge.net> + + + Daniele E. Domenichelli <drdanz@users.sourceforge.net> + + + Jean-Pierre Roux <jprx@users.sourceforge.net> + + + Mathieu Malaterre <malat@users.sourceforge.net> + + + Niels Dekker + + + Rogue Research <rogueresearch@users.sourceforge.net> + + + Shane Blackett <sablackett@users.sourceforge.net> + + + Joel Spaltenstein <spalte@users.sourceforge.net> + + diff --git a/gdcm/Utilities/doxygen/doxyfile.in b/gdcm/Utilities/doxygen/doxyfile.in new file mode 100644 index 0000000..f735c65 --- /dev/null +++ b/gdcm/Utilities/doxygen/doxyfile.in @@ -0,0 +1,1652 @@ +# Doxyfile 1.7.1 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = GDCM + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = @GDCM_VERSION@ + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = @GDCM_BINARY_DIR@/Utilities/doxygen + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 2 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this +# tag. The format is ext=language, where ext is a file extension, and language +# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, +# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make +# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C +# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions +# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = YES + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen to replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penality. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will rougly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols + +SYMBOL_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespace are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = YES + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = YES + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. +# This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. The create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = YES + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = @GDCM_SOURCE_DIR@/Source \ + @GDCM_SOURCE_DIR@/Wrapping \ + @GDCM_SOURCE_DIR@/Utilities/VTK \ + @GDCM_SOURCE_DIR@/Utilities/doxygen/man \ + @GDCM_BINARY_DIR@/Utilities/doxygen/README.txt \ + @GDCM_BINARY_DIR@/Utilities/doxygen/TestsList.txt + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 + +FILE_PATTERNS = *.h \ + *.man \ + *.dox + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = @GDCM_SOURCE_DIR@/Source/DataDictionary/gdcmTagToType.h \ + @GDCM_SOURCE_DIR@/Source/DataDictionary/gdcmTagKeywords.h \ + @GDCM_SOURCE_DIR@/Source/Common/zipstreamimpl.h \ + @GDCM_SOURCE_DIR@/Source/Common/zipstreamimpl.hpp \ + @GDCM_SOURCE_DIR@/Source/MediaStorageAndFileFormat/gdcm_jp2.h \ + @GDCM_SOURCE_DIR@/Source/MediaStorageAndFileFormat/gdcm_j2k.h + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = */.git/* \ + */VTK4/* + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = @GDCM_SOURCE_DIR@/Examples \ + @GDCM_SOURCE_DIR@/Testing \ + @GDCM_SOURCE_DIR@/Applications \ + @GDCM_SOURCE_DIR@/Utilities/VTK/Examples \ + @GDCM_SOURCE_DIR@/Utilities/VTK/Testing \ + @GDCM_SOURCE_DIR@/Utilities/VTK/Applications + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = *.cxx \ + *.py \ + *.java \ + *.cs + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = YES + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. +# If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. +# Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. +# The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = YES + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. +# Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 3 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = @GDCM_HTML_FOOTER@ + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the stylesheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = NO + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = NO + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# +# Qt Help Project / Custom Filters. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# +# Qt Help Project / Filter Attributes. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 1 + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. + +GENERATE_TREEVIEW = NO + +# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list. + +USE_INLINE_TREES = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = NO + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a PHP enabled web server instead of at the web client +# using Javascript. Doxygen will generate the search PHP script and index +# file to put on the web server. The advantage of the server +# based approach is that it scales better to large projects and allows +# full text search. The disadvances is that it is more difficult to setup +# and does not have live searching capabilities. + +SERVER_BASED_SEARCH = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = YES + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = letter + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = YES + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = YES + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .1 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = YES + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. +# This is useful +# if you want to understand what is going on. +# On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = YES + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = YES + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = NO + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = "GDCM_LEGACY(x)= x;" \ + "gdcmEventMacro(classname,super)= class classname: public super {};" + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = @GDCM_BINARY_DIR@/Utilities/doxygen/GDCM.tag + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = YES + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 1 + +# By default doxygen will write a font called FreeSans.ttf to the output +# directory and reference it in all dot files that doxygen generates. This +# font does not include all possible unicode characters however, so when you need +# these (or just want a differently looking font) you can specify the font name +# using DOT_FONTNAME. You need need to make sure dot is able to find the font, +# which can be done by putting it in a standard location or by setting the +# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory +# containing the font. + +DOT_FONTNAME = FreeSans + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the output directory to look for the +# FreeSans.ttf font (which doxygen will put there itself). If you specify a +# different font using DOT_FONTNAME you can set the path where dot +# can find it using this tag. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = @DOXYGEN_DOT_PATH@ + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = YES + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = YES + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES diff --git a/gdcm/Utilities/doxygen/footer.html b/gdcm/Utilities/doxygen/footer.html new file mode 100644 index 0000000..24d4c26 --- /dev/null +++ b/gdcm/Utilities/doxygen/footer.html @@ -0,0 +1,31 @@ + + + + + + +
+
+Generated on $datetime for $projectname by doxygen $doxygenversion
+SourceForge.net Logo + diff --git a/gdcm/Utilities/doxygen/man/gdcm2pnm.man b/gdcm/Utilities/doxygen/man/gdcm2pnm.man new file mode 100644 index 0000000..0a0366b --- /dev/null +++ b/gdcm/Utilities/doxygen/man/gdcm2pnm.man @@ -0,0 +1,71 @@ +/*! + +\page gdcm2pnm off-screen rendering of DICOM images + +\section synopsis SYNOPSIS + +\verbatim +gdcmdiff [options] file-in bitmap-out +\endverbatim + +\section description DESCRIPTION + +The \b gdcm2pnm command line program takes as input a DICOM file and produces +a rendered bitmap file. + +\section parameters PARAMETERS + +\verbatim +file-in DICOM input filename + +bitmap-out Bitmap output filename +\endverbatim + +\section options OPTIONS + +\subsection options options +\verbatim +\endverbatim + +\subsection general_options general options +\verbatim + -h --help + print this help text and exit + + -v --version + print version information and exit + + -V --verbose + verbose mode (warning+error). + + -W --warning + warning mode, print warning information + + -E --error + error mode, print error information + + -D --debug + debug mode, print debug information +\endverbatim + +\section simple_usage Simple usage +\b gdcm2pnm will take as input DICOM and render it into a bitmap file using the +window/level attributes value. + +\verbatim +$ gdcm2pnm input.dcm output.png +\endverbatim + +It is much different from the gdcmraw or gdcmimg command line tool as it will +render a DICOM image. This means that the output will be rendered in 8bits +ready for display. + +\section see_also SEE ALSO + +gdcm2vtk(1), gdcmimg(1) + +\section copyright COPYRIGHT + +Copyright (c) 2006-2011 Mathieu Malaterre + +*/ diff --git a/gdcm/Utilities/doxygen/man/gdcm2vtk.man b/gdcm/Utilities/doxygen/man/gdcm2vtk.man new file mode 100644 index 0000000..4e2088e --- /dev/null +++ b/gdcm/Utilities/doxygen/man/gdcm2vtk.man @@ -0,0 +1,187 @@ +/*! + +\page gdcm2vtk Convert a file supported by VTK into DICOM. + +\section synopsis SYNOPSIS + +\verbatim +gdcm2vtk [options] file-in file-out +\endverbatim + +\section description DESCRIPTION + +The \b gdcm2vtk takes as input any file supported by VTK (including DICOM file) and will generate as output +a DICOM file. + +\section parameters PARAMETERS + +\verbatim +file-in input filename (DICOM or VTK supported) + +file-out output filename (DICOM or VTK supported) +\endverbatim + +\section options OPTIONS + +\subsection options options +\verbatim + --force-rescale force rescale. + --force-spacing force spacing. + --palette-color when supported generate a PALETTE COLOR file. + --argb when supported generate a ARGB file. + --compress when supported generate a compressed file. + --use-vtkdicom Use vtkDICOMImageReader (instead of GDCM). + --modality set Modality. + --lower-left set lower left. + --shift set shift. + --scale set scale. + --compress set compression (MetaIO). + -T --study-uid Study UID. + -S --series-uid Series UID. + --root-uid Root UID. +\endverbatim + +\subsection compression_options compression options +\verbatim + -J --jpeg Compress image in jpeg. + -K --j2k Compress image in j2k. + -L --jpegls Compress image in jpeg-ls. + -R --rle Compress image in rle (lossless only). +\endverbatim + +\subsection general_options general options +\verbatim + -h --help + print this help text and exit + + -v --version + print version information and exit + + -V --verbose + verbose mode (warning+error). + + -W --warning + warning mode, print warning information + + -E --error + error mode, print error information + + -D --debug + debug mode, print debug information +\endverbatim + +\subsection environment_variable environment variable +\verbatim + GDCM_ROOT_UID Root UID +\endverbatim + +\section description DESCRIPTION +Convert a file supported by VTK into DICOM. + +Typical usage is: + +\verbatim +$ gdcm2vtk inputfile output.dcm +\endverbatim + +It uses the internal factory mechanism of VTK to recognize a file (CanRead function). See VTK supported file here: + + * What image file formats can VTK read and write? http://www.vtk.org/Wiki/VTK_FAQ#What_image_file_formats_can_VTK_read_and_write.3F + +If your input file has 4 components, the 4th comp (alpha) will be removed from the output file as DICOM does not support alpha component anymore (see --argb option). + +Special care was taken for the following file format: + +\verbatim + 1. DICOM: Direction Cosines and vtkMedicalImageInformation are passed to the output + 2. BMP: The file can be saved with a Lookup Table (see --palette-color) + 3. GE Signa: vtkMedicalImageProperties is passed to the output + 4. MINC: Direction Cosines is passed to the output + 5. TIFF: vtkTIFFReader is currently in bad shape in VTK (different behavior in VTK 5.2 and git/master). Only use it, if you know what you are doing. +\endverbatim + +\subsection convert_meta CONVERT MetaImage (mhd, mha) + +\verbatim +$ gdcm2vtk inputfile output.mha +\endverbatim + +This command will convert the input DICOM file: inputfile into a MetaImage .mha file. Same goes for .mhd file. + +\subsection convert_mha CONVERT MHA/MHD + +\verbatim +$ gdcm2vtk inputfile output.mha +\endverbatim +or +\verbatim +$ gdcm2vtk inputfile output.mhd +\endverbatim + +This command will convert the input DICOM file: inputfile into a MetaImageData .mha/.mhd file. + +\subsection convert_vti CONVERT VTI + +\verbatim +$ gdcm2vtk inputfile output.vti +\endverbatim + +This command will convert the input DICOM file: inputfile into a XML VTK ImageData .vti file. + +\subsection convert_vtk CONVERT VTK + +\verbatim +$ gdcm2vtk inputfile output.vtk +\endverbatim + +This command will convert the input DICOM file: inputfile into an old VTK Structured PointSets .vtk file. + +\section convert_dicom CONVERT DICOM + +\verbatim +$ gdcm2vtk input.dcm output.dcm +\endverbatim + +vtkGDCMImageReader will be used to read in a DICOM file, not the default vtkDICOMImageReader. +See option --use-vtkdicom to use vtkDICOMImageReader. + +\section round_tripmhd RoundTrip DICOM to MHD to DICOM + +\verbatim +$ gdcm2vtk input_ybr.dcm output.mhd +$ gdcm2vtk --modality US --imageformat 7 output.mhd output.dcm +\endverbatim + +The above section shows how to convert a DICOM using the Photometric Interpretation of YBR_FULL +(or even YBR_FULL_422 is lossy) into another file format: MetaImage (mhd). Since this +file format does not handle color space, we have to explicitly set it using the --imageformat +command line option. +The --modality command line option is required in this case since the default Secondary Capture +Image Storage Class family does not allow for YBR Photometric Interpretation. + +\section gdcm2vtk_notes gdcm2vtk notes + +IMPORTANT NOTE: The internal VTK structured will be filled from the input +DICOM, and then pass to the output DICOM writer. Some information might be lost +during the conversion DICOM to VTK to DICOM. This option is mostly used to test +the vtkGDCMImageReader/vtkGDCMImageWriter combination. + +IMPORTANT NOTE: When converting from a lossy format such as JPEG, the +information of lossiness is important. The output DICOM will contains the +required Lossy Image Compression attribute that indicates that image was +lossy-compressed somewhere along the pipeline. See also gdcmimg (better +handling of JPEG in general). + +IMPORTANT NOTE: When using --use-vtkdicom the output DICOM file will always be +written as MR Image Storage as this information is not available from the +reader itself. This allow setting the Image Orientation (Patient) properly. + +\section see_also SEE ALSO + +gdcmdump(1), gdcmviewer(1), gdcmimg(1) + +\section copyright COPYRIGHT + +Copyright (c) 2006-2011 Mathieu Malaterre + +*/ diff --git a/gdcm/Utilities/doxygen/man/gdcmanon.man b/gdcm/Utilities/doxygen/man/gdcmanon.man new file mode 100644 index 0000000..e44b8b7 --- /dev/null +++ b/gdcm/Utilities/doxygen/man/gdcmanon.man @@ -0,0 +1,288 @@ +/*! + +\page gdcmanon Tool to anonymize a DICOM file. + +\section synopsis SYNOPSIS + +\verbatim +gdcmanon [options] file-in file-out +gdcmanon [options] dir-in dir-out +\endverbatim + +\section description DESCRIPTION + +The \b gdcmanon tool is an implementation of PS 3.15 / E.1 / Basic Application +Level Confidentiality Profile (Implementation of E.1.1 De-identify & E.1.2 +Re-identify) + +This tool is split into two very different operating mode: +\li An implementation of PS 3.15, see -e and -d flags +\li A dumb mode, see --dumb + +Dumb mode and PS 3.15 do not work well together, you should really only use one +type of anonymization. In case of doubt, avoid using --dumb. + +In order to use the PS 3.15 implementation (-d & -e flag), you'll need a +certificate to do de-identification operations, and the associated private key +to do the re-identification operation. If you are only doing a one-shot +anonymization and do not need to properly re-identify the DICOM file, you can +safely discard the private key and only keep the certificate. See OpenSSL +section below for an example on how to generate the private key/certificate +pair. + +gdcmanon will exit early if OpenSSL was not configured/build properly into the +library (see GDCM_USE_SYSTEM_OPENSSL in cmake). + +\section parameters PARAMETERS + +\verbatim +file-in DICOM input filename + +file-out DICOM output filename +\endverbatim + +or + +\verbatim +file-in DICOM input directory + +file-out DICOM output directory +\endverbatim + +\section options OPTIONS + +You need to specify at least one operating mode, from the following list (and +only one): + +\subsection required_params Required parameters +\verbatim + -e --de-identify De-identify DICOM (default) + -d --re-identify Re-identify DICOM + --dumb Dumb mode anonymizer +\endverbatim + +Warning when operating in dumb mode, you need to also specify an operation to +do, such as 'remove' or 'empty' a tag, see below the dumb mode options. + +\subsection options options +\verbatim + -i --input DICOM filename / directory + -o --output DICOM filename / directory + -r --recursive recursively process (sub-)directories. + --continue Do not stop when file found is not DICOM. + --root-uid Root UID. + --resources-path Resources path. + -k --key Path to RSA Private Key. + -c --certificate Path to Certificate. +\endverbatim + +\subsection encryption_options encryption options +\verbatim + --des DES. + --des3 Triple DES. + --aes128 AES 128. + --aes192 AES 192. + --aes256 AES 256. +\endverbatim + +\subsection dumb_mode_options dumb mode options +\verbatim + --empty %d,%d DICOM tag(s) to empty + --remove %d,%d DICOM tag(s) to remove + --replace %d,%d,%s DICOM tag(s) to replace +\endverbatim + +\subsection general_options general options +\verbatim + -h --help + print this help text and exit + + -v --version + print version information and exit + + -V --verbose + verbose mode (warning+error). + + -W --warning + warning mode, print warning information + + -E --error + error mode, print error information + + -D --debug + debug mode, print debug information +\endverbatim + +\subsection environment_variable environment variable +\verbatim + GDCM_ROOT_UID Root UID + GDCM_RESOURCES_PATH path pointing to resources files (Part3.xml, ...) +\endverbatim + +\section usage Typical usage +\subsection deident De-identification (anonymization, encrypt) + +The only thing required for this operation is a certificate file (in PEM +format). + +\verbatim +$ gdcmanon --certificate certificate.pem -e original.dcm original_anonymized.dcm +\endverbatim + +You can use --asn1 option from gdcmdump to dump the generated DataSet +as ASN1 structure (see gdcmdump(1) for example). + +\subsection reindent Re-identification (de-anonymization,decrypt) + +The only thing required for this operation is a private key (in PEM format). It +is required that the private key used for the re-identification process, was +the actual private key used to generate the certificate file (certificate.pem) +used during the de-identification step. + +\verbatim +$ gdcmanon --key privatekey.pem -d original_anonymized.dcm original_copy.dcm +\endverbatim + +You can then check that original.dcm and original_copy.dcm are identical. + +\subsection caveat Multiple files caveat + +It is very important to understand the following section, when anonymizing more +than one single file. When anonymizing multiple DICOM files, you are required +to use the directory input. You cannot call multiple time the gdcmanon command +line tool. Indeed the tool stores in memory during the process only a hash +table of conversion so that each time a particular value is found it get always +replaced by the same de-identified value (think: consistent Series Instance +UID). + +\subsection dumb Dumb mode + +This functionality is not described in the DICOM standard. Users are advised +that improper use of that mode is not recommended, meaning that important tag +can be emptied/removed/replaced resulting in illegal/invalid DICOM file. Only +use when you know what you are doing. If you delete a Type 1 attribute, chance +is that your DICOM file will be not accepted in most DICOM third party viewer. +Unfortunately this is often this mode that is implemented in popular DICOM +Viewer, always prefer what the DICOM standard describes, and avoid the dumb +mode. + +The following example shows how to use dumb mode and achieve 5 operations at the same time: +\li Empty the tag (0010,0010) Patient's Name, +\li Empty the tag (0010,0020) Patient ID, +\li Remove the tag (0010,0040) Patient's Sex +\li Remove the tag (0010,1010) Patient's Age +\li Replace the tag (0010,1030) Patient's Weight with the value '10' + +You are required to check which DICOM attribute is Type 1 and Type 1C, before +trying to \b 'Empty' or \b 'Remove' a particular DICOM attribute. For the same +reason, you are required to check what are valid value in a replace operation. + +\verbatim +$ gdcmanon --dumb --empty 10,10 --empty 10,20 --remove 10,40 --remove 10,1010 --replace 10,1030,10 012345.002.050.dcm out.dcm +\endverbatim + +Multiple operation of --dumb mode can take place, just reuse the output of the +previous operation. Always use gdcmdump on the input and output file to check +what was actually achieved. You can use a diff program to check only what +changed (see gdcmdiff(1) for example). + +\subsubsection irreversible_anon Irreversible Anonymization + +In some very rare cases, one would want to anonymize using the PS 3.15 mode so +as to take benefit of the automatic conversion of all content that could +contain Patient related information. + +In the end all Patient related information has been removed and has been +secretly stored in the 0400,0500 DICOM attribute. However to make sure that +no-one ever try to break that security using brute-force algorithm, one want +want to remove completely this DICOM attribute. This will make the DICOM: + +\li Completely free of any Patient related information (as per PS 3.15 specification) +\li Remove any mean of people to brute force attack the file to find out the identity of the Patient + +In this case one could simply do, as a first step execute the reversible anonymizer: + +\verbatim +$ gdcmanon -c certificate.pem input.dcm anonymized_reversible.dcm +\endverbatim + +and now completely remove the DICOM attribute containing the secretly encrypted Patient related +information: + +\verbatim +$ gdcmanon --dumb --remove 400,500 --remove 12,62 --remove 12,63 anonymized_reversible.dcm anonymized_irreversible.dcm +\endverbatim + +\remark +As mentionned in DICOM Sup 142, this anonymization is preferred over +de-identification since: +It is not required that the Encrypted Attributes Data Set be created; indeed, +there may be circumstances where the Dataset is expected to be archived long +enough that any contemporary encryption technology may be inadequate to provide +long term protection against unauthorized recovery of identification + +\section openssl OpenSSL + +On most system you can have access to OpenSSL to generate the Private +Key/Certificate pair. + +\subsection priv_key Generating a Private Key + +Command line to generate a rsa key (512bit) + +\verbatim +$ openssl genrsa -out CA_key.pem +\endverbatim + +Command line to generate a rsa key (2048bit) + +\verbatim +$ openssl genrsa -out CA_key.pem 2048 +\endverbatim + +Command line to generate a rsa key (2048bit) + passphrase + +\verbatim +$ openssl genrsa -des3 -out CA_key.pem 2048 +\endverbatim + +\subsection certificate Generating a Certificate + +From your previously generated Private Key, you can now generate a certificate +in PEM (DER format is currently not supported). + +\verbatim +$ openssl req -new -key CA_key.pem -x509 -days 365 -out CA_cert.cer +\endverbatim + +\section dicom_standard DICOM Standard: + +Page to the DICOM Standard: + +http://dicom.nema.org/ + +The DICOM Standard at the time of releasing gdcmanon is: + +ftp://medical.nema.org/medical/dicom/2008/ + +Direct link to PS 3.15-2008: + +ftp://medical.nema.org/medical/dicom/2008/08_15pu.pdf + +\section gdcmanon_warnings Warnings + +Certain attributes may still contains Protected Health Information (PHI) after +an anonymization step. This is typically the case for Patient's Address (0010,1040). +The reason is that this particular attribute is not supposed to be in the composite +IODs in the first place. DICOM Supp 142 includes it (however gdcmanon does not +implement it). + +\section see_also SEE ALSO + +gdcmconv(1), gdcmdump(1), gdcmdiff(1), openssl(1), dumpasn1(1) + +\section copyright COPYRIGHT + +Copyright (c) 2006-2011 Mathieu Malaterre + +*/ diff --git a/gdcm/Utilities/doxygen/man/gdcmconv.man b/gdcm/Utilities/doxygen/man/gdcmconv.man new file mode 100644 index 0000000..44c0e18 --- /dev/null +++ b/gdcm/Utilities/doxygen/man/gdcmconv.man @@ -0,0 +1,396 @@ +/*! + +\page gdcmconv Tool to convert DICOM to DICOM. + +\section synopsis SYNOPSIS + +\verbatim +gdcmconv [options] file-in file-out +\endverbatim + +\section description DESCRIPTION + +The \b gdcmconv command line program takes as input a DICOM file (file-in) and +process it to generate an output DICOM file (file-out). +The command line option dictate the type of operation(s) gdcmconv will use to +generate the output file. + +\section parameters PARAMETERS + +\verbatim +file-in DICOM input filename + +file-out DICOM output filename +\endverbatim + +\section options OPTIONS + +\subsection parameters parameters +\verbatim + -i --input DICOM filename + -o --output DICOM filename +\endverbatim + +\subsection options options +\verbatim + -X --explicit Change Transfer Syntax to explicit. + -M --implicit Change Transfer Syntax to implicit. + -U --use-dict Use dict for VR (only public by default). + --with-private-dict Use private dict for VR (advanced user only). + -C --check-meta Check File Meta Information (advanced user only). + --root-uid Root UID. + --remove-gl Remove group length (deprecated in DICOM 2008). + --remove-private-tags Remove private tags. + --remove-retired Remove retired tags. +\endverbatim + +\subsection image_options image options +\verbatim + -l --apply-lut Apply LUT (non-standard, advanced user only). + -P --photometric-interpretation %s Change Photometric Interpretation (when possible). + -w --raw Decompress image. + -d --deflated Compress using deflated (gzip). + -J --jpeg Compress image in jpeg. + -K --j2k Compress image in j2k. + -L --jpegls Compress image in jpeg-ls. + -R --rle Compress image in rle (lossless only). + -F --force Force decompression/merging before recompression/splitting. + --generate-icon Generate icon. + --icon-minmax %d,%d Min/Max value for icon. + --icon-auto-minmax Automatically commpute best Min/Max values for icon. + --compress-icon Decide whether icon follows main TransferSyntax or remains uncompressed. + --planar-configuration [01] Change planar configuration. + -Y --lossy Use the lossy (if possible) compressor. + -S --split %d Write 2D image with multiple fragments (using max size) +\endverbatim + +\subsection jpeg_options JPEG options +\verbatim + -q --quality %*f set quality. +\endverbatim + +\subsection jpegls_options JPEG-LS options +\verbatim + -e --lossy-error %*i set error. +\endverbatim + +\subsection j2k_options J2K options +\verbatim + -r --rate %*f set rate. + -q --quality %*f set quality. + -t --tile %d,%d set tile size. + -n --number-resolution %d set number of resolution. + --irreversible set irreversible. +\endverbatim + +\subsection general_options general options +\verbatim + -h --help + print this help text and exit + + -v --version + print version information and exit + + -V --verbose + verbose mode (warning+error). + + -W --warning + warning mode, print warning information + + -E --error + error mode, print error information + + -D --debug + debug mode, print debug information +\endverbatim + +\subsection special_options special options +\verbatim + -I --ignore-errors convert even if file is corrupted (advanced users only, see disclaimers). +\endverbatim + +\subsection environment_variable environment variable +\verbatim + GDCM_ROOT_UID Root UID +\endverbatim + +\section simple_usage Simple usage +\b gdcmconv is a great tool to convert broken DICOM implementation into +properly parsable DICOM file. Usage is simply: + +\verbatim +$ gdcmconv input.dcm output.dcm +\endverbatim + +or if you prefer being explicit: + +\verbatim +$ gdcmconv -i input.dcm -o output.dcm +\endverbatim + +Even though gdcmconv can overwrite directly on the same file (input.dcm = +output.dcm), it is recommended that user should first convert into a different +file to make sure the bug is properly handled by GDCM. + +Typical cases where you would want to use gdcmconv in its simple form: + +\li convert non-cp246 conforming file into conforming cp246, +\li convert implicit little endian transfer syntax file meta header into proper explicit little endian transfer syntax, +\li convert the GE-13 bytes bug, +\li convert dual syntax file: implicit/explicit, +\li convert Philips dual Little Endian/Big Endian file, +\li convert GDCM 1.2.0 broken UN-2-bytes fields, +\li \&... +\li All other broken files listed in the supported section. + +When no option other is used, only the dataset is inspected. So encapsulated +Pixel Data, for instance, is not inspected for well known bugs. + +When doing this kind of work, this is usually a good idea to perform some kind +of quality control, see gdcmconv Quality Control section (down below). + +\section usage Typical usage +\subsection file_meta File Meta Header + +Running + +\verbatim +$ gdcmconv input.dcm output.dcm +\endverbatim + +Is not enough to recompute file meta header, when input file is buggy. You may +want to use: --check-meta + +\verbatim +$ gdcmconv --check-meta input.dcm output.dcm +\endverbatim + +See typical cases such as: GE_DLX-8-MONO2-PrivateSyntax.dcm or +PICKER-16-MONO2-No_DicomV3_Preamble.dcm from gdcmData. + +\subsection explicit Conversion to Explicit Transfer Syntax + +To convert a file that was written using Implicit Transfer Syntax into Explicit +Transfer Syntax simply use: + +\verbatim +$ gdcmconv --explicit uncompressed.dcm compressed.dcm +\endverbatim + +\subsection lossless_jpeg Compressing to lossless JPEG +To compress an uncompressed DICOM file to a JPEG Lossless encapsulated format: + +\verbatim +$ gdcmconv --jpeg uncompressed.dcm compressed.dcm +\endverbatim + +\subsection lossy_jpeg Compressing to lossy JPEG +To compress an uncompressed DICOM file to a JPEG Lossy encapsulated format: + +\verbatim +$ gdcmconv --lossy --jpeg -q 90 uncompressed.dcm compressed.dcm +\endverbatim + +Note: + + * -q is just one of the many way to specify lossy quality, you need to inspect the other cmd line flag to specify lossyness properties. + +\subsection lossless_jpegls Compressing to lossless JPEG-LS + +To compress an uncompressed DICOM file to a JPEG-LS Lossless encapsulated +format: + +\verbatim +$ gdcmconv --jpegls uncompressed.dcm compressed.dcm +\endverbatim + +\subsection lossy_jpegls Compressing to lossy JPEG-LS + +To compress an uncompressed DICOM file to a JPEG-LS Lossy encapsulated format: + +\verbatim +$ gdcmconv --lossy --jpegls -e 2 uncompressed.dcm lossy_compressed.dcm +\endverbatim + +Note: + + -e (or --lossy-error) means that the maximum tolerate error is 2 for each pixel value + +\subsection lossless_j2k Compressing to lossless J2K + +To compress an uncompressed DICOM file to a JPEG-2000 Lossless encapsulated +format: + +\verbatim +$ gdcmconv --j2k uncompressed.dcm compressed.dcm +\endverbatim + +\subsection lossy_j2k Compressing to lossy J2K + +To compress an uncompressed DICOM file to a JPEG-2000 Lossy encapsulated +format: + +\verbatim +$ gdcmconv --lossy -q 55,50,45 --j2k uncompressed.dcm lossy_compressed.dcm +\endverbatim + +Note: + + * -q is just one of the many way to specify lossy quality, you need to inspect the other cmd line flag to specify lossyness properties. + +\subsection lossless_rle Compressing to lossless RLE + +To compress an uncompressed DICOM file to a RLE Lossless encapsulated format: + +\verbatim +$ gdcmconv --rle uncompressed.dcm compressed.dcm +\endverbatim + +There is no such thing as lossy RLE compression. + +\subsection split_encapsulated Split encapsulated DICOM: + +To split an encapsulated stream into smaller chunk (1024 bytes each): + +\verbatim +$ gdcmconv --split 1024 rle.dcm rle_1024.dcm +\endverbatim + +If an odd number of bytes is passed it will be rounded down to the next even +number (eg. 1025 -> 1024) since DICOM only allow even number for Value Length. + +\subsection force Forcing (re)compression + +Sometime it is necessary to use the --force option. By default when user +specify --j2k and input file is already in JPEG 2000 encapsulated DICOM format +then no operation takes places. By using --force you make sure that +(re)compression operation takes places. + +Real life example of why you would use --force: +\li When Pixel Data is missing data / is padded with junk +\li When you would like to make sure GDCM can handle decompression & recompression cycle + +\subsection decompress_raw Decompressing a Compressed DICOM + +\verbatim +$ gdcmconv --raw compressed.dcm uncompressed.dcm +\endverbatim + +\subsection compress_icon Compressing an uncompressed Icon + +By default when compressing a DICOM Image file, gdcmconv will not compress the +icon. A user option needs to be turned on to explicitly force the compression +of the Icon Image Sequence Pixel Data + +For example, by default we will not compress the Icon Image Sequence Pixel Data +attribute: + +\verbatim +$ gdcmconv --jpeg gdcmData/simpleImageWithIcon.dcm uncompressed_icon.dcm +\endverbatim + +In the following example we will explicitly compress the Icon Image Sequence +Pixel Data attibute. In that case the same Transfer Syntax is being used for +both the main Pixel Data and the Pixel Data from the Icon Image Sequence: + +\verbatim +$ gdcmconv --jpeg --compress-icon gdcmData/simpleImageWithIcon.dcm compressed_icon.dcm +\endverbatim + +\subsection generate_icon Generating an Icon + +For some application it might be necessary to produce a small preview of the main image +to be able to quickly load that short preview instead of the main image. In that case: + +\verbatim +$ gdcmconv --raw --generate-icon gdcmData/test.acr test_icon.dcm +\endverbatim + +In some cases the main Pixel Data element is expressed as pixel defined on +16bits. Since Icon can only store at most pixel of size 8bits, a rescale +operation needs to take place. In order to properly select a better interval +for doing the rescale operation user can specify the min max used for the +rescale operation: + +\verbatim +$ gdcmconv --raw --generate-icon --icon-minmax 0,192 gdcmData/012345.002.050.dcm icon_minmax.dcm +\endverbatim + +\subsection planar_configuration Changing the planar Configuration + +Often RLE files are compressed using a different Planar Configuration (RRR ... +GGG... BBB...) instead of the usual triplet (RGB ... RGB ... RGB ). So upon +decompression the Planar Configuration is 1. This is perfectly legal in DICOM, +however this is unconventional, and thus it may be a good idea to also change +the planar configuration and set it to the default : + +\verbatim +$ gdcmconv --raw --planar-configuration 0 compressed.dcm uncompressed1.dcm +\endverbatim + +To reinvert the planar configuration of file 'uncompressed1.dcm', simply do: + +\verbatim +$ gdcmconv --raw --planar-configuration 1 uncompressed1.dcm uncompressed2.dcm +\endverbatim + +\section lossless_conversion Lossless Conversion + +When talking about lossless conversion, there is an ambiguity that need to be +understood. To achieve higher compression ratio, the RGB color space is usually +not used, in favor of a YBR one. Changing from one color space to the other is +(bit level) not lossless. + +For more detail, see what are the true lossless transformations as described: + +http://gdcm.sourceforge.net/wiki/index.php/Color_Space_Transformations + +\section quality_control Quality Control + +One important part when using gdcmconv it to have a way to quality control the +output. + +You can use 3rd party tool to check the output of gdcmconv is correct. + +\subsection other_toolkit DCMTK / dicom3tools + +Using another DICOM implementation such as the one from DCMTK or dicom3tools +can be a good process to check the output of gdcmconv. +\li For DCMTK use: dcmdump +\li For dicom3tools use: dcdump + +For reference, gdcmconv --raw will act as dcmdjpeg +cn +px, since it never +tries to convert color space. + +\subsection vim VIM: vimdiff + +You can setup your favorite editor to compare the output, for instance in vim: + +\code +autocmd BufReadPre *.dcm set ro +autocmd BufReadPost *.dcm silent %!dcmdump -M +uc "%" +\endcode + +then simply do: + +\code +$ vimdiff input.dcm output.dcm +\endcode + +\subsection binary_diff vbindiff + +On UNIX you can visually compare binary file using the vbindiff command: + +\code +$ vbindiff input.dcm output.dcm +\endcode + +\section see_also SEE ALSO + +gdcmdump(1), gdcmraw(1), gdcminfo(1), gdcmdiff(1) + +\section copyright COPYRIGHT + +Copyright (c) 2006-2011 Mathieu Malaterre + +*/ diff --git a/gdcm/Utilities/doxygen/man/gdcmdiff.man b/gdcm/Utilities/doxygen/man/gdcmdiff.man new file mode 100644 index 0000000..39d8690 --- /dev/null +++ b/gdcm/Utilities/doxygen/man/gdcmdiff.man @@ -0,0 +1,68 @@ +/*! + +\page gdcmdiff dumps differences of two DICOM files + +\section synopsis SYNOPSIS + +\verbatim +gdcmdiff [options] file1 file2 +\endverbatim + +\section description DESCRIPTION + +The \b gdcmdiff command line program takes as input two DICOM files: file1 and +file2. + +\section parameters PARAMETERS + +\verbatim +file1 DICOM input filename + +file2 DICOM output filename +\endverbatim + +\section options OPTIONS + +\subsection options options +\verbatim + -m --meta Compare metainformation. Default is off. + -t --truncate String values trimmed to n characters. +\endverbatim + +\subsection general_options general options +\verbatim + -h --help + print this help text and exit + + -v --version + print version information and exit + + -V --verbose + verbose mode (warning+error). + + -W --warning + warning mode, print warning information + + -E --error + error mode, print error information + + -D --debug + debug mode, print debug information +\endverbatim + +\section simple_usage Simple usage +\b gdcmdiff is a great tool to produce a diff in between two DICOM files. Usage +is simply: + +\verbatim +$ gdcmdiff input1.dcm input2.dcm +\endverbatim + +\section see_also SEE ALSO + +gdcmdump(1), gdcminfo(1) + +\section copyright COPYRIGHT + +Copyright (c) 2006-2011 Mathieu Malaterre +*/ diff --git a/gdcm/Utilities/doxygen/man/gdcmdump.man b/gdcm/Utilities/doxygen/man/gdcmdump.man new file mode 100644 index 0000000..56b8757 --- /dev/null +++ b/gdcm/Utilities/doxygen/man/gdcmdump.man @@ -0,0 +1,411 @@ +/*! + +\page gdcmdump dumps a DICOM file, it will display the structure and values contained in the specified DICOM file. + +\section synopsis SYNOPSIS + +\verbatim +gdcmdump [options] dcm_file +gdcmdump [options] dcm_directory +\endverbatim + +\section description DESCRIPTION + +The \b gdcmdump command line program dumps a DICOM file to the console. +For those familiar with dcmdump (DCMTK) output, gdcmdump has some minor +differences. Namely: +\li For Implicit Transfer Syntax gdcmdump will print \b ?? instead of the dictionary VR + +gdcmdump has a limited private dictionary that is used to lookup private +element whenever possible. + +\section parameters PARAMETERS + +\verbatim +dcm_file DICOM input filename +dcm_directory DICOM input directory +\endverbatim + +\section options OPTIONS + +\subsection options options +\verbatim + -x --xml-dict generate the XML dict (only private elements for now). + -r --recursive recursive (input is a directory) + -d --dump dump value (limited use). + -p --print print value instead of simply dumping (default). + -c --color print in color. + -C --csa print SIEMENS CSA Header (0029,[12]0,SIEMENS CSA HEADER). + -P --pdb print GEMS Protocol Data Block (0025,1b,GEMS_SERS_01). + --elscint print ELSCINT Protocol Information (01f7,26,ELSCINT1). + --vepro print VEPRO Protocol Information (0055,20,VEPRO VIF 3.0 DATA). + or VEPRO Protocol Information (0055,20,VEPRO VIM 5.0 DATA). + --sds print Philips MR Series Data Storage (1.3.46.670589.11.0.0.12.2) Information (2005,32,Philips MR Imaging DD 002). + -A --asn1 print encapsulated ASN1 structure >(0400,0520). + --map-uid-names map UID to names. +\endverbatim + +\subsection general_options general options +\verbatim + -h --help + print this help text and exit + + -v --version + print version information and exit + + -V --verbose + verbose mode (warning+error). + + -W --warning + warning mode, print warning information + + -E --error + error mode, print error information + + -D --debug + debug mode, print debug information +\endverbatim + +\subsection special_options special options +\verbatim + -I --ignore-errors dumps even if file is corrupted (advanced users only, see disclaimers). +\endverbatim + +\section usage Typical usage +\subsection implicit Printing Implicit Transfer Syntax + +The VR are not found in the file, thus are presented with a "(??)", and right +next to it (if found) the correct VR. + +Eg.: + +\verbatim +$ gdcmdump GE_DLX-8-MONO2-PrivateSyntax.dcm +\endverbatim + +\verbatim +# Dicom-File-Format +\&... +(0008,0000) ?? (UL) 434 # 4,1 Generic Group Length +(0008,0005) ?? (CS) [ISO_IR 100] # 10,1-n Specific Character Set +(0008,0008) ?? (CS) [ORIGINAL\\PRIMARY\\SINGLE PLANE ] # 30,2-n Image Type +(0008,0016) ?? (UI) [1.2.840.10008.5.1.4.1.1.12.1] # 28,1 SOP Class UID +(0008,0018) ?? (UI) [1.2.840.113619.2.16.1.0.906539207.1.24207] # 42,1 SOP Instance UID +(0008,0020) ?? (DA) [19980923] # 8,1 Study Date +(0008,0021) ?? (DA) [19980923] # 8,1 Series Date +(0008,0022) ?? (DA) [19980923] # 8,1 Acquisition Date +(0008,0023) ?? (DA) [19980923] # 8,1 Content Date +(0008,0030) ?? (TM) [101229.000] # 10,1 Study Time +(0008,0031) ?? (TM) [101229.000] # 10,1 Series Time +(0008,0032) ?? (TM) [102653.000] # 10,1 Acquisition Time +(0008,0033) ?? (TM) [102653.000] # 10,1 Content Time +\&... +\endverbatim + +\subsection private_attribute Print Private Attributes + +GDCM has a limited private dictionary. Whenever possible, it will try to lookup +the private data element. + +\verbatim +$ gdcmdump 012345.002.050.dcm +\endverbatim + +\verbatim +\&... +(0009,0010) LO [GEMS_IDEN_01] # 12,1 Private Creator +(0009,1001) LO [GE_GENESIS_FF ] # 14,1 Full fidelity +(0009,1002) SH [MRCV] # 4,1 Suite id +(0009,1004) SH [SIGNA ] # 6,1 Product id +(0009,1027) SL 985968524 # 4,1 Image actual date +(0009,1030) SH [19356UMR2 ] # 10,1 Service id +(0009,1031) SH [999 ] # 4,1 Mobile location number +(0009,10e3) UI [1.2.840.113619.1.1.4.1762386977] # 32,1 Equipment UID +(0009,10e6) SH [08] # 2,1 Genesis Version - now +(0009,10e7) UL 2757786872 # 4,1 Exam Record checksum +(0009,10e9) SL 985968523 # 4,1 Actual series data time stamp +\&... +(0019,0000) UL 1208 # 4,1 Generic Group Length +(0019,0010) LO [GEMS_ACQU_01] # 12,1 Private Creator +(0019,100f) DS [424.399994] # 10,1 Horiz. Frame of ref. +(0019,1011) SS 0 # 2,1 Series contrast +\&... +(0019,10e0) DS [0.000000] # 8,1 User data 24 {# DTI Diffusion Dir., release 10.0 & above} +(0019,10e2) DS [0.000000] # 8,1 Velocity Encode Scale +(0019,10f2) SS 0 # 2,1 Fast phases +(0019,10f9) DS [98] # 2,1 Transmit gain +\&... +(0021,0000) UL 372 # 4,1 Generic Group Length +(0021,0010) LO [GEMS_RELA_01] # 12,1 Private Creator +(0021,1003) SS 0 # 2,1 Series from which Prescribed +\&... +\endverbatim + +\subsection siemens_csa SIEMENS CSA Header + +Using this option it is possible to dump as a readable text what is contained +in the private attribute as found in typical SIEMENS MR DICOM file. + +Eg.: + +\verbatim +$ gdcmdump --csa MR_SIEMENS_forceLoad29-1010_29-1020.dcm +\endverbatim + +\verbatim +(0029,0010)siemens csa header +Image shadow data (0029,xx10) + +0 - 'EchoLinePosition' VM 1, VR IS, SyngoDT 6, NoOfItems 6, Data '64 ' +1 - 'EchoColumnPosition' VM 1, VR IS, SyngoDT 6, NoOfItems 6, Data '64 ' +2 - 'EchoPartitionPosition' VM 1, VR IS, SyngoDT 6, NoOfItems 6, Data '32 ' +3 - 'UsedChannelMask' VM 1, VR UL, SyngoDT 9, NoOfItems 6, Data '255 ' +4 - 'Actual3DImaPartNumber' VM 1, VR IS, SyngoDT 6, NoOfItems 0, Data +5 - 'ICE_Dims' VM 1, VR LO, SyngoDT 19, NoOfItems 6, Data 'X_1_1_1_1_1_1_31_1_1_1_1_19' +6 - 'B_value' VM 1, VR IS, SyngoDT 6, NoOfItems 6, Data '0 ' +7 - 'Filter1' VM 1, VR IS, SyngoDT 6, NoOfItems 0, Data +8 - 'Filter2' VM 1, VR IS, SyngoDT 6, NoOfItems 0, Data +\&... +\endverbatim + +\subsection gems_pdb GEMS Protocol Data Block + +Using this option it is possible to dump as a readable text what is contained +in the private attribute as found in typical GEMS MR DICOM file. + +Protocol Data Block : 0025,xx1b,GEMS_SERS_01 + +\verbatim +$ gdcmdump --pdb GE_MR_0025xx1bProtocolDataBlock.dcm +\endverbatim + +\verbatim +ENTRY "Head First" +POSITION "Supine" +ANREF "NA" +COIL "HEAD" +PLANE "OBLIQUE" +SEDESCFLAG "1" +SEDESC "AX FSE T2" +IMODE "2D" +PSEQ "FSE-XL" +IOPT "FC, EDR, TRF, Fast" +PLUG "22" +FILTCHOICE "None" +BWRT "-1" +TRICKSIMG "1" +TAG_SPACE "7" +TAG_TYPE "None" +\&... +\endverbatim + +\subsection elscint_pi ELSCINT Protocol Information + +Using this option it is possible to dump as a readable text what is contained +in the private attribute as found in typical ELSCINT CT DICOM file. + +ELSCINT Protocol Information: (01f7,26,ELSCINT1) + +\verbatim +$ gdcmdump --elscint ELSCINT1_ProtocolInformation.dcm +\endverbatim + +\verbatim +ELSCINT1 Dumping info from tag (01f7,26,elscint1) +ELSCINT1/Item name: [] + ApprovedStep [yes] + RefSurview [1\0] + STD-first-img-pos [11.5] + current-step [yes] + ntimed-steps [0] + orig-n-slices [390] + protocol-file [Head_Multi_1032_usr.proc] + protocol-name [FACE-TRAUMA/Head/Hx] + protocol-path [/usr/diamond.root/spr/] + protocol-step [1] + protocol-version [2.51] + +ELSCINT1/Item name: [doseright] + ACS [n/a] + ACS-bed-position [0] + ACS-calc-mas [0] + ACS-iq-parameter [0] + ACS-learn-allowed [no] + ACS-water-radius [-1.000000] + ACS-water-radius-scan [-1] +\&... +\endverbatim + +\subsection vepro_pi VEPRO Protocol Information + +Using this option it is possible to dump as a readable text what is contained +in the private attribute as found in typical VEPRO CT DICOM file. + +ELSCINT Protocol Information: (0055,20,VEPRO VIM 5.0 DATA) + +\verbatim +$ gdcmdump --vepro VEPRO_ProtocolInformation.dcm +\endverbatim + +\verbatim +VIMDATA2: (0055,20,VEPRO VIM 5.0 DATA) + ID: VIM + Version: 5.0 + UserName: + UserAdress1: Name of Institution + UserAdress2: Street of Institution + UserAdress3: City of Institution + UserAdress4: + UserAdress5: + RecDate: 20101001 + RecTime: 211321 + RecPlace: + RecSource: DICOM Distributor + DF1: P-09/10-41808 + DF2: Sultana Razia + DF3: 19411001 + DF4: F + DF5: + DF6: + DF7: + DF8: CT Scan Brain without Contrast + DF9: 10/10-0034873 + DF10: 10/10-00348 + DF11: + DF12: + DF13: + DF14: Head 0.5 + DF15: 4 + DF16: + DF17: + DF18: + DF19: + DF20: + StudyUID: 1.2.392.200036.9116.2.6.1.48.1214228007.1285934880.206831 + SeriesUID: 1.2.392.200036.9116.2.6.1.48.1214228007.1285935201.938653 + Modality: CT +\endverbatim + +\subsection pms_mr_sds Philips Private MR Series Data Storage (1.3.46.670589.11.0.0.12.2) + +Using this option it is possible to dump as a readable text what is contained +in the private attribute as found in typical Philips Private MR Series Data Storage file. + +PMS Series Data Storage (2005,32,Philips MR Imaging DD 002) + +\verbatim +$ gdcmdump --sds PMS_SeriesDataStorage.dcm +\endverbatim + +\verbatim +\&... +PMS/Item name: [PDF_CONTROL_GEN_PARS/IEEE_PDF/Y ] +\&... +PMS/Item name: [PDF_CONTROL_PREP_PARS /IEEE_PDF/Y ] +\&... +PMS/Item name: [PDF_CONTROL_RECON_PARS/IEEE_PDF/Y ] +\&... +PMS/Item name: [PDF_CONTROL_SCAN_PARS /IEEE_PDF/Y ] +\&... +PMS/Item name: [PDF_EXAM_PARS /IEEE_PDF/Y ] +\&... +PMS/Item name: [PDF_HARDWARE_PARS /IEEE_PDF/Y ] +\&... +PMS/Item name: [PDF_PREP_PARS /IEEE_PDF/Y ] +\&... +PMS/Item name: [PDF_SPT_PARS/IEEE_PDF/Y ] + SP_scan_resol [256\256] # 2 + SP_pda_profiles [0\0] # 2 + SP_filter [324074] # 1 + SP_analyse_with_iqt [0] # 1 + SP_main_system_type [3] # 1 + SP_gradient_system [6] # 1 + SP_coil_type [2\2\0\0\0\0\0\0\0\0\0\0\0\0\0\0] # 16 + SP_coil_id [2\34\0\0\0\0\0\0\0\0\0\0\0\0\0\0] # 16 + SP_coil_part [0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0] # 16 + SP_act_q [0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0] # 16 + SP_act_coil_freq [0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0] # 16 + SP_coil_m_pos [255\255\255\0\0\0\0\0\0\0\0\0\0\0\0\255] # 16 + SP_coil_t_pos [255\128\255\0\0\0\0\0\0\0\0\0\0\0\0\255] # 16 + SP_surface_coil_con [0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0] # 16 + SP_proton_freq [127801349] # 1 + SP_tm_result [2\2\2\2\2\2\2\2\2\2\2\2\2\2\2\2] # 16 + SP_f0_result [0] # 1 + SP_as_result [0] # 1 + SP_po_result [0] # 1 + SP_rg_result [0] # 1 + SP_dc_result [0] # 1 + SP_ph_result [0] # 1 +\&... +\endverbatim + +\subsection asn1 Encapsulated ASN1 Structure + +This option is mainly used for dumping the ASN1 structure of the encrypted +Attribute (0040,0520) + +\verbatim +$ gdcmdump encrypted.dcm +\endverbatim + +\verbatim +\&... +(0400,0500) SQ # u/l,1 Encrypted Attributes Sequence + (fffe,e000) na (Item with undefined length) + (0400,0510) UI [1.2.840.10008.1.2] # 18,1 Encrypted Content Transfer Syntax UID + (0400,0520) OB 30\\82\\03\\ba\\06\\09\\2a\\86\\48\\55\\04\\08\\13 # 958,1 Encrypted Content + (fffe,e00d) +(fffe,e0dd) +\&... +\endverbatim + +\verbatim +$ gdcmdump --asn1 encrypted.dcm +\endverbatim + +\verbatim + 0:d=0 hl=4 l= 954 cons: SEQUENCE + 4:d=1 hl=2 l= 9 prim: OBJECT :pkcs7-envelopedData + 15:d=1 hl=4 l= 939 cons: cont [ 0 ] + 19:d=2 hl=4 l= 935 cons: SEQUENCE + 23:d=3 hl=2 l= 1 prim: INTEGER :00 + 26:d=3 hl=4 l= 366 cons: SET + 30:d=4 hl=4 l= 362 cons: SEQUENCE + 34:d=5 hl=2 l= 1 prim: INTEGER :00 + 37:d=5 hl=2 l= 82 cons: SEQUENCE + 39:d=6 hl=2 l= 69 cons: SEQUENCE + 41:d=7 hl=2 l= 11 cons: SET + 43:d=8 hl=2 l= 9 cons: SEQUENCE + 45:d=9 hl=2 l= 3 prim: OBJECT :countryName + 50:d=9 hl=2 l= 2 prim: PRINTABLESTRING :AU + 54:d=7 hl=2 l= 19 cons: SET + 56:d=8 hl=2 l= 17 cons: SEQUENCE + 58:d=9 hl=2 l= 3 prim: OBJECT :stateOrProvinceName + 63:d=9 hl=2 l= 10 prim: PRINTABLESTRING :Some-State + 75:d=7 hl=2 l= 33 cons: SET + 77:d=8 hl=2 l= 31 cons: SEQUENCE + 79:d=9 hl=2 l= 3 prim: OBJECT :organizationName + 84:d=9 hl=2 l= 24 prim: PRINTABLESTRING :Internet Widgits Pty Ltd + 110:d=6 hl=2 l= 9 prim: INTEGER :AC966D88787A51B4 + 121:d=5 hl=2 l= 13 cons: SEQUENCE + 123:d=6 hl=2 l= 9 prim: OBJECT :rsaEncryption + 134:d=6 hl=2 l= 0 prim: NULL + 136:d=5 hl=4 l= 256 prim: OCTET STRING [HEX DUMP]:822368070285AD756C962ECB973514B291F946... + 396:d=3 hl=4 l= 558 cons: SEQUENCE + 400:d=4 hl=2 l= 9 prim: OBJECT :pkcs7-data + 411:d=4 hl=2 l= 29 cons: SEQUENCE + 413:d=5 hl=2 l= 9 prim: OBJECT :aes-256-cbc + 424:d=5 hl=2 l= 16 prim: OCTET STRING [HEX DUMP]:3B49AFE71749F2BFF1519EBAEA95A393 + 442:d=4 hl=4 l= 512 prim: cont [ 0 ] +\endverbatim + + +\section see_also SEE ALSO + +gdcmdump(1), gdcmraw(1), gdcmanon(1) + +\section copyright COPYRIGHT + +Copyright (c) 2006-2011 Mathieu Malaterre + +*/ diff --git a/gdcm/Utilities/doxygen/man/gdcmgendir.man b/gdcm/Utilities/doxygen/man/gdcmgendir.man new file mode 100644 index 0000000..18e17f4 --- /dev/null +++ b/gdcm/Utilities/doxygen/man/gdcmgendir.man @@ -0,0 +1,92 @@ +/*! + +\page gdcmgendir Tool to generate a DICOMDIR file from a File-Set. + +\section synopsis SYNOPSIS + +\verbatim +gdcmgendir [options] file-in file-out +\endverbatim + +\section description DESCRIPTION + + +\section parameters PARAMETERS + +\verbatim +file-in DICOM input filename + +file-out DICOM output filename +\endverbatim + +\section options OPTIONS + +\subsection params Parameters +\verbatim +\endverbatim + +\subsection options Options +\verbatim + -i --input DICOM filename or directory + -o --output DICOM filename or directory + -r --recursive recursive. + --descriptor descriptor. + --root-uid Root UID. +\endverbatim + +\subsection general_options General Options +\verbatim + -h --help + print this help text and exit + + -v --version + print version information and exit + + -V --verbose + verbose mode (warning+error). + + -W --warning + warning mode, print warning information + + -E --error + error mode, print error information + + -D --debug + debug mode, print debug information +\endverbatim + +\subsection environment_variable environment variable +\verbatim + GDCM_ROOT_UID Root UID +\endverbatim + +\section usage Typical usage + +\section note NOTE +One may have to run some preliminary steps in order to get gdcmgendir to +generate the DICOMDIR file. Namely two steps: +\li Batch renaming of the DICOM filename into something compatible with ISO 9660 filename convention +\li Convert all DICOM file into the Explicit VR Little Endian Uncompressed (1.2.840.10008.1.2.1) + +Step 1. can be solved in a numerous way. Eg. on UNIX environment this could +either be solved using the mkisofs command line tool. Filenames should not +contains any extension since the VR CS does not allow for the '.' character. +Only upper case, digit 0-9, the space ' ' and the underscore '_' character are +valid in VR CS, with a maximum of 8 bytes. Another simple tool that can be +handy is 'rename' in conjunction with 'basename'. + +Step 2. can simply be achieved using the gdcmconv command line tool: + +\verbatim + $ for i in `ls IMG*`; do gdcmconv --raw --force $i /tmp/out/$i; done +\endverbatim + +\section see_also SEE ALSO + +gdcmconv(1), gdcmanon(1), rename(1), mkisofs(1) + +\section copyright COPYRIGHT + +Copyright (c) 2006-2011 Mathieu Malaterre + +*/ diff --git a/gdcm/Utilities/doxygen/man/gdcmimg.man b/gdcm/Utilities/doxygen/man/gdcmimg.man new file mode 100644 index 0000000..e21d413 --- /dev/null +++ b/gdcm/Utilities/doxygen/man/gdcmimg.man @@ -0,0 +1,287 @@ +/*! + +\page gdcmimg Manipulate DICOM image file. + +gdcmimg is a low level tool to allow de-/encapsulation from/to DICOM image. +This tool does not understand Transfer Syntax conversion. It will encapsulate +the raw data as-is. This has some impact in some cases, see special warnings +below. + +It is important to note that gdcmimg can only encapsulate proper input file, +for instance JPG and or JP2 are accepted since an associated DICOM Transfer +Syntax can be found. However input such as TIFF and/or PNG are not, since DICOM +does not support those. See instead a tool such as gdcm2vtk. + +\section synopsis SYNOPSIS + +\verbatim +gdcmimg [options] file-in file-out +\endverbatim + +\section description DESCRIPTION + +The \b gdcmimg command line tool can be used in two fashions: +\li 1. Converting a recognized file format into its encapsulated DICOM counterpart, +\li 2. Anonymizing a rectangular portion of a DICOM file. + +\section parameters PARAMETERS + +\verbatim +file-in input filename (non-DICOM) + +file-out DICOM output filename +\endverbatim + +\section options OPTIONS + +\subsection parameters parameters +\verbatim + -i --input Input filename + -o --output Output filename +\endverbatim + +\subsection options options +\verbatim + --endian %s Endianness (LSB/MSB). + -d --depth %d Depth (Either 8/16/32 or BitsAllocated eg. 12 when known). + --sign %s Pixel sign (0/1). + --spp %d Sample Per Pixel (1/3). + -s --size %d,%d Size. + -C --sop-class-uid SOP Class UID (name or value). + -T --study-uid Study UID. + -S --series-uid Series UID. + --root-uid Root UID. +\endverbatim + +\subsection fill_options fill options +\verbatim + -R --region %d,%d Region. + -F --fill %d Fill with pixel value specified. +\endverbatim + +\subsection general_options general options +\verbatim + -h --help + print this help text and exit + + -v --version + print version information and exit + + -V --verbose + verbose mode (warning+error). + + -W --warning + warning mode, print warning information + + -E --error + error mode, print error information + + -D --debug + debug mode, print debug information +\endverbatim + +\subsection environment_variable environment variable +\verbatim + GDCM_ROOT_UID Root UID +\endverbatim + +\section supported Supported File Format (appropriate file extension) gdcmimg +will base it's conversion process based on the file extension. Follows the list +of recognized file extension. When no extension is found, DICOM file is +assumed. + +input format +\verbatim + * RAW (raw, rawl, gray, rgb) + * RLE (rle) + * PNM (pgm, pnm, ppm) + * JPEG-LS (jls) + * JPEG 2000 (jp2, j2k, j2c, jpx, jpc) + * JPEG (jpg, jpeg, ljpg, ljpeg) + * DICOM () +\endverbatim + +output format: +\verbatim + * PGM (pgm, pnm, ppm) + * DICOM () +\endverbatim + +For RAW file format, you should take special care of the --endian option. +For the (old) JPEG file format, both the lossy and lossless format are +supported, user should pay attention to the --sign option. +For file format such as RLE or RAW, user is expected to fill in information +required to find the dimension and type of input data as there is no other way +to find this information. For all other file format, the properties are derived +from the file format itself. + +PNM file are supposed to be big endian (important for depth > 8) + +\section usage Typical usage +\subsection blank_out Remove a rectangular part of the image + +To fill the region [0,100]x[0,100] of a DICOM image simply do: + +\verbatim +$ gdcmimg --fill 0 --region 0,100,0,100 -i input.dcm -o output_black.dcm +\endverbatim + +Warning: if the Pixel Data is compressed, the image is first decompressed so +that pixel can be set to 0, but it is not re-compressed. + +\subsection convert_raw Convert RAW to DICOM + +Recognized extension is .raw, .rawl, .gray or .rgb (case insensitive) + +\verbatim +$ gdcmimg --size 512,512 --depth 16 -i input.raw -o output.dcm +\endverbatim + +the image will be a Secondary Capture. + +When the input is 3 component, one need to specify explicitly the Samples Per +Pixel: + +\verbatim +$ gdcmimg --size 512,512 --spp 3 input_rgb.raw output_rgb.dcm +\endverbatim + +When the filename contains .rgb as file extension output is automatically +recognized as RGB no need to specify --spp + +\verbatim +$ gdcmimg --size 512,512 input.rgb output_rgb.dcm +\endverbatim + +You can use the \b dd cmd line to skip any header you would like to discard, +for instance, if you would like to skip the first 108 bytes, simply do: + +\verbatim +$ dd skip=108 bs=1 if=input.raw of=output.raw +\endverbatim + +.raw and .rawl extension are equivalent. You need to explicitly specify the +endianess manually: + +\verbatim +$ gdcmimg --endian MSB --size 512,512 --depth 16 -i input.raw -o output.dcm +\endverbatim + +or + +\verbatim +$ gdcmimg --endian LSB --size 512,512 --depth 16 -i input.raw -o output.dcm +\endverbatim + +\subsection pnm Convert PGM/PNM/PPM to DICOM + +Recognized extensions are .pgm, .pnm, .ppm (case insensitive) + +\verbatim +$ gdcmimg -i input.pgm -o output.dcm +\endverbatim + +the image will be a Secondary Capture + +\subsection rle Convert RLE to DICOM + +Recognized extension is .rle (case insensitive) + +\verbatim +$ gdcmimg --size 512,512 --depth 16 -i input.rle -o output.dcm +\endverbatim + +the image will be a Secondary Capture +\subsection jpeg Convert JPEG to DICOM + +Recognized extensions are .jpg, .jpeg, .ljpg, .ljpeg (case insensitive) + +\verbatim +$ gdcmimg -i input.ljpeg -o output.dcm +\endverbatim + +the image will be a Secondary Capture + +\subsection j2k Convert J2K to DICOM + +Recognized extensions are .j2k, .jp2, .jpc, jpx, j2c (case insensitive) + +\verbatim +$ gdcmimg -i input.j2k -o output.dcm +\endverbatim + +the image will be a Secondary Capture. + +All Pixel informations (Bits Stored/Allocated...) will be derived from the +image itself, and not from the command line options. + +\subsection sopclassuid Specifying a SOP Class UID + +Instead of the default Secondary Capture Image Storage, one may want to +specify, say VL Photographic Image Storage. + +\verbatim +$ gdcmimg --sop-class-uid 1.2.840.10008.5.1.4.1.1.77.1.4 input.jpg output.dcm +\endverbatim + +\section multiple_files Multiple Files + +gdcmimg handle nicely a set of files (for instance jpeg): + +\verbatim +$ gdcmimg 1.jpg 2.jpg 3.jpg 4.jpg output.dcm +\endverbatim + +\section start_offset Start Offset + +In some case, one may want to create a 2D slice from an arbitrary volume (e.g +3D). In which case --offset becomes handy: + +\verbatim +$ gdcmimg --offset 4954104330 --size 1673,1673 Input3D_1673_1673_1775.raw slice_1770.dcm +\endverbatim + +\section warning Warning + +There are a couple of issues with gdcmimg implementation: + +For RAW file, one should pay attention that when using --endian MSB the Pixel +Data will be encapsulated as is (not touched by gdcmimg). Therefore the only +possible transfer syntax available is Implicit VR Big Endian DLX (G.E Private). +GDCM does handle this private Transfer Syntax. So if you need to convert this +Transfer Syntax to another one (and allow Pixel Data manipulation), you can +use: + +\verbatim +$ gdcmconv --raw --force input_big_endian_dlx.raw -o output_implicit_vr_little_endian.dcm +\endverbatim + +For JFIF file and JP2 file (with header) the header is copied into the Pixel +Data element which is illegal for JP2. +Use gdcmconv to properly re-encode a JP2/JFIF file into J2K/JPG. + +\verbatim +$ gdcmimg input.jp2 output_jp2.dcm +$ gdcmconv --j2k --force output_jp2.dcm output_j2k.dcm +\endverbatim + +For RLE file, no check is done for crossing the row boundary. It is recommended +to use gdcmconv --rle to re-encode into a proper RLE file in case of doubt. + +Of course if the compression is not ok with your setup, you can always +de-encapsulated the DICOM file (typically JPEG) to a non-encapsulated form, +using gdcmconv: + +\verbatim +$ gdcmconv --raw input_jpeg.dcm output_raw.dcm +\endverbatim + +\section see_also SEE ALSO + +gdcmdump(1), gdcm2vtk(1), gdcmraw(1), convert(1), dd(1) + +\section copyright COPYRIGHT + +Copyright (c) 2006-2011 Mathieu Malaterre + +*/ diff --git a/gdcm/Utilities/doxygen/man/gdcminfo.man b/gdcm/Utilities/doxygen/man/gdcminfo.man new file mode 100644 index 0000000..6408fb6 --- /dev/null +++ b/gdcm/Utilities/doxygen/man/gdcminfo.man @@ -0,0 +1,164 @@ +/*! + +\page gdcminfo Display meta info about the input DICOM file. + +\section synopsis SYNOPSIS + +\verbatim +gdcminfo [options] file-in +\endverbatim + +\section description DESCRIPTION + +The \b gdcminfo command line program takes as input a DICOM file, or a +directory and process it to extract meta- information about the DICOM file +processed. + +\section parameters PARAMETERS + +\verbatim +file-in DICOM input filename +\endverbatim + +\section options OPTIONS + +\subsection options options +\verbatim + -r --recursive recursive. + -d --check-deflated check if file is proper deflated syntax. + --resources-path Resources path. + --md5sum Compute md5sum of Pixel Data attribute value. + --check-compression check the encapsulated stream compression (lossless/lossy). +\endverbatim + +\subsection general_options general options +\verbatim + -h --help + print this help text and exit + + -v --version + print version information and exit + + -V --verbose + verbose mode (warning+error). + + -W --warning + warning mode, print warning information + + -E --error + error mode, print error information + + -D --debug + debug mode, print debug information +\endverbatim + +\subsection environment_variable environment variable + + GDCM_RESOURCES_PATH path pointing to resources files (Part3.xml, ...) + +\section simple_usage Simple usage + +\subsection gdcmdata gdcmData +Using data from gdcmData: + +\verbatim +$ gdcminfo gdcmData/012345.002.050.dcm +\endverbatim + +\verbatim +MediaStorage is 1.2.840.10008.5.1.4.1.1.4 [MR Image Storage] +NumberOfDimensions: 2 +Dimensions: (256,256) +Origin: (-85,21.6,108.7) +Spacing: (0.664062,0.664062,1.5) +DirectionCosines: (1,0,0,0,0,-1) +Rescale Intercept/Slope: (0,1) +SamplesPerPixel :1 +BitsAllocated :16 +BitsStored :16 +HighBit :15 +PixelRepresentation:1 +Orientation Label: CORONAL +\endverbatim + +\subsection dclunie Davie Clunie datasets: + +Using data from David Clunie datasets: + +\verbatim +$ gdcminfo BRTUM001.dcm +\endverbatim + +\verbatim +MediaStorage is 1.2.840.10008.5.1.4.1.1.4.1 [Enhanced MR Image Storage] +NumberOfDimensions: 3 +Dimensions: (256,256,15) +Origin: (40,-105,105) +Spacing: (0.820312,0.820312,6) +DirectionCosines: (0,1,0,0,0,-1) +Rescale Intercept/Slope: (0,1) +SamplesPerPixel :1 +BitsAllocated :16 +BitsStored :16 +HighBit :15 +PixelRepresentation:1 +Orientation Label: SAGITTAL +\endverbatim + +\subsection md5sum Checking the md5sum of the Pixel Data + +After compressing a DICOM file (see gdcmconv) using a lossless compression +algorithm, it is fairly easy to compare the two files for differences at DICOM +attribute level. However one operation is slightly easier to do: how to make +sure the compression was actually lossless ? In this case one could use the +--md5sum operation. + +Take an uncompressed DICOM image file: + +\verbatim +$ gdcminfo --md5sum SIEMENS_ImageLocationUN.dcm +\endverbatim + +The tool return: 0621954acd5815e0b4f7b65fcc6506b1 + +Now compress this file: + +\verbatim +$ gdcmconv --jpegls SIEMENS_ImageLocationUN.dcm lossless_compressed.dcm +\endverbatim + +and then check again the md5sum: + +\verbatim +$ gdcminfo --md5sum lossless_compressed.dcm +\endverbatim + +The tool return: 0621954acd5815e0b4f7b65fcc6506b1 + +\subsection checking_lossless Checking if Pixel Data is lossless + +In some environment one wish to check whether or not the DICOM file is +lossless. It is fairly easy to do that in most cases. Only in two occasion this +is not clear from the sole DICOM Attribute. When the Transfer Syntax is JPEG +2000 Image Compression (1.2.840.10008.1.2.4.91) and when the Transfer Syntax is +JPEG-LS Lossy (Near-Lossless) Image Compression (1.2.840.10008.1.2.4.81). + +In this case, the only solution is to open the Pixel Data element, read the +specific JPEG header and check whether or not the JPEG transformation was +lossless or not: + +\verbatim +$ gdcminfo --check-compression gdcmData/MAROTECH_CT_JP2Lossy.dcm +\endverbatim + +The tool returns: "Encapsulated Stream was found to be: lossy" + +\section see_also SEE ALSO + +gdcmdump(1), gdcmraw(1), gdcmconv(1) + +\section copyright COPYRIGHT + +Copyright (c) 2006-2011 Mathieu Malaterre + +*/ diff --git a/gdcm/Utilities/doxygen/man/gdcmpap3.man b/gdcm/Utilities/doxygen/man/gdcmpap3.man new file mode 100644 index 0000000..5a8869b --- /dev/null +++ b/gdcm/Utilities/doxygen/man/gdcmpap3.man @@ -0,0 +1,93 @@ +/*! + +\page gdcmpap3 Tool to convert PAPYRUS 3.0 to DICOM. + +\section synopsis SYNOPSIS + +\verbatim +gdcmconv [options] file-in file-out +\endverbatim + +\section description DESCRIPTION + +The \b gdcmconv command line program takes as input a PAPYRUS 3.0 file (file-in) and +process it to generate an output (pseudo) DICOM file (file-out). +The command line option dictate the type of operation(s) gdcmconv will use to +generate the output file. + +\section parameters PARAMETERS + +\verbatim +file-in DICOM input filename + +file-out DICOM output filename +\endverbatim + +\section options OPTIONS + +\subsection parameters parameters +\verbatim + -i --input DICOM filename + -o --output DICOM filename +\endverbatim + +\subsection options options +\verbatim + -S --split Split multiframes PAPYRUS 3.0 into multiples DICOM files + --decomp-pap3 Use PAPYRUS 3.0 for decompressing (can be combined with --split). + --check-iop Check that the Image Orientation (Patient) Attribute is ok (see --split). +\endverbatim + +\subsection general_options general options +\verbatim + -h --help + print this help text and exit + + -v --version + print version information and exit + + -V --verbose + verbose mode (warning+error). + + -W --warning + warning mode, print warning information + + -E --error + error mode, print error information + + -D --debug + debug mode, print debug information +\endverbatim + +\subsection environment_variable environment variable +\verbatim + GDCM_ROOT_UID Root UID +\endverbatim + +\section simple_usage Simple usage +\b gdcmconv is a great tool to convert broken PAPYRUS 3.0 implementation into +properly parsable DICOM file. Usage is simply: + +\verbatim +$ gdcmconv input.pa3 output.dcm +\endverbatim + +or if you prefer being explicit: + +\verbatim +$ gdcmconv -i input.pa3 -o output.dcm +\endverbatim + +Even though gdcmpap3 can overwrite directly on the same file (input.pa3 = +output.dcm), it is recommended that user should first convert into a different +file to make sure the bug is properly handled by GDCM. + +\section see_also SEE ALSO + +gdcmdump(1), gdcmconv(1), gdcminfo(1) + +\section copyright COPYRIGHT + +Copyright (c) 2006-2011 Mathieu Malaterre + +*/ diff --git a/gdcm/Utilities/doxygen/man/gdcmpdf.man b/gdcm/Utilities/doxygen/man/gdcmpdf.man new file mode 100644 index 0000000..221e672 --- /dev/null +++ b/gdcm/Utilities/doxygen/man/gdcmpdf.man @@ -0,0 +1,149 @@ +/*! + +\page gdcmpdf Tool to convert PDF to PDF/DICOM. + +\section synopsis SYNOPSIS + +\verbatim +gdcmpdf [options] file-in file-out +\endverbatim + +\section description DESCRIPTION + +The \b gdcmpdf tool convert a PDF file (any PDF version) into an encapsulated PDF/DICOM file. +By default it will try to read the PDF meta information stored in the PDF and convert this +information to some specific DICOM fields (see below). However it may fails (eg. wrong +password on encrypted PDF file) in which case empty value are used. + +\section parameters PARAMETERS + +\verbatim +file-in PDF input filename + +file-out DICOM output filename +\endverbatim + +\section options OPTIONS + +\subsection general_options general options +\verbatim + -h --help + print this help text and exit + + -v --version + print version information and exit + + -V --verbose + verbose mode (warning+error). + + -W --warning + warning mode, print warning information + + -E --error + error mode, print error information + + -D --debug + debug mode, print debug information +\endverbatim + +\section usage_example Usage Example + +\verbatim +$ wget http://gdcm.sourceforge.net/gdcm.pdf +$ gdcmpdf gdcm.pdf gdcm.dcm +\endverbatim + +To re-extract the encapsulated PDF file: + +\verbatim + $ gdcmraw -i gdcm.dcm -t 42,11 -o gdcm.dcm.pdf + $ diff gdcm.pdf gdcm.dcm.pdf +\endverbatim + +\section pdf_mapping PDF Info Mapping + +Here is how the PDF info is mapped to DICOM information (typical pdfinfo output): + +\verbatim +Title: GDCM Reference Manual +Subject: Grassroots DICOM API reference +Keywords: GDCM,DICOM,JPEG,Lossless JPEG,JPEG-LS,J2K,JPEG 2000,RLE +Author: Mathieu Malaterre and co. +Creator: LaTeX with hyperref package +Producer: pdfeTeX-1.21a +CreationDate: Tue Apr 28 15:34:26 2009 +Tagged: no +Pages: 1188 +Encrypted: no +Page size: 612 x 792 pts (letter) +File size: 13756841 bytes +Optimized: yes +PDF version: 1.4 +\endverbatim + +Converted to DICOM this leads to: + +\verbatim +# Dicom-Data-Set +# Used TransferSyntax: Little Endian Explicit +(0008,0005) CS [ISO_IR 100] # 10, 1 SpecificCharacterSet +(0008,0012) DA [20090428] # 8, 1 InstanceCreationDate +(0008,0013) TM [182550.302631] # 14, 1 InstanceCreationTime +(0008,0016) UI =EncapsulatedPDFStorage # 30, 1 SOPClassUID +(0008,0018) UI [1.2.826.0.1.3680043.2.1143.776842935192792959289022034349197114] # 64, 1 SOPInstanceUID +(0008,0020) DA [20090428] # 8, 1 StudyDate +(0008,0023) DA [20090428] # 8, 1 ContentDate +(0008,002a) DT [20090428153437.000000] # 22, 1 AcquisitionDateTime +(0008,0030) TM [182550.302160] # 14, 1 StudyTime +(0008,0033) TM [153426.000000] # 14, 1 ContentTime +(0008,0050) SH (no value available) # 0, 0 AccessionNumber +(0008,0060) CS [OT] # 2, 1 Modality +(0008,0064) CS [WSD] # 4, 1 ConversionType +(0008,0070) LO [LaTeX with hyperref package] # 28, 1 Manufacturer +(0008,0090) PN (no value available) # 0, 0 ReferringPhysiciansName +(0010,0010) PN [Mathieu Malaterre and co.] # 26, 1 PatientsName +(0010,0020) LO (no value available) # 0, 0 PatientID +(0010,0030) DA (no value available) # 0, 0 PatientsBirthDate +(0010,0040) CS (no value available) # 0, 0 PatientsSex +(0018,1020) LO [pdfeTeX-1.21a] # 14, 1 SoftwareVersions +(0020,000d) UI [1.2.826.0.1.3680043.2.1143.1868121832223417351654232480755123133] # 64, 1 StudyInstanceUID +(0020,000e) UI [1.2.826.0.1.3680043.2.1143.1330099150825746617507846107663964311] # 64, 1 SeriesInstanceUID +(0020,0010) SH (no value available) # 0, 0 StudyID +(0020,0011) IS [1] # 2, 1 SeriesNumber +(0020,0013) IS [1] # 2, 1 InstanceNumber +(0028,0301) CS [YES] # 4, 1 BurnedInAnnotation +(0040,a043) SQ (Sequence with explicit length #=0) # 0, 1 ConceptNameCodeSequence +(fffe,e0dd) na (SequenceDelimitationItem for re-encod.) # 0, 0 SequenceDelimitationItem +(0042,0010) ST [GDCM Reference Manual] # 22, 1 DocumentTitle +(0042,0011) OB 25\\50\\44\\46\\2d\\31\\2e\\34\\0a\\25\\e7\\f3\\cf\\d3\\0a\\33\\32\\30\\37\\37\\20\\30... # 13756842, 1 EncapsulatedDocument +(0042,0012) LO [application/pdf] # 16, 1 MIMETypeOfEncapsulatedDocument +\endverbatim + +\verbatim +$ stat gdcm.pdf + File: `gdcm.pdf' + Size: 13756841 Blocks: 26912 IO Block: 4096 regular file +Device: fe01h/65025d Inode: 2675750 Links: 1 +Access: (0644/-rw-r--r--) Uid: ( 1002/mmalaterre) Gid: ( 1002/mmalaterre) +Access: 2009-04-28 16:05:00.000000000 +0200 +Modify: 2009-04-28 15:34:37.000000000 +0200 +Change: 2009-04-28 16:05:00.000000000 +0200 +\endverbatim + + +Explanation for the different Date/Time mappings: + +\li Study Date/Time, Instance Creation Date/Time are both equal to the current time gdcmpdf tool was run, +\li Acquisition Date Time is set to the Modify Time of the actual PDF file, +\li Content Date/Time are set from the actual PDF header info: CreationDate. + + +\section see_also SEE ALSO + +gdcmconv(1), gdcmraw(1), pdfinfo(1) + +\section copyright COPYRIGHT + +Copyright (c) 2006-2011 Mathieu Malaterre + +*/ diff --git a/gdcm/Utilities/doxygen/man/gdcmraw.man b/gdcm/Utilities/doxygen/man/gdcmraw.man new file mode 100644 index 0000000..cee03e0 --- /dev/null +++ b/gdcm/Utilities/doxygen/man/gdcmraw.man @@ -0,0 +1,213 @@ +/*! + +\page gdcmraw Extract Data Element Value Field. + +\section synopsis SYNOPSIS + +\verbatim +gdcmraw [options] file-in file-out +\endverbatim + +\section description DESCRIPTION + +The \b gdcmraw tool is mostly used for development purpose. It is used to +extract a specific binary field from a DICOM DataSet. + +\section parameters PARAMETERS + +\verbatim +file-in DICOM input filename + +file-out output filename +\endverbatim + +\section options OPTIONS + +\subsection parameters parameters +\verbatim + -i --input Input filename + -o --output Output filename + -t --tag Specify tag to extract value from. +\endverbatim + +\subsection options options +\verbatim + -S --split-frags Split fragments into multiple files. + -p --pattern Specify trailing file pattern (see split-frags). + -P --pixel-data Pixel Data trailing 0. +\endverbatim + +\subsection general_options general options +\verbatim + -h --help + print this help text and exit + + -v --version + print version information and exit + + -V --verbose + verbose mode (warning+error). + + -W --warning + warning mode, print warning information + + -E --error + error mode, print error information + + -D --debug + debug mode, print debug information +\endverbatim + +\section usage Typical usage + +\subsection copy_attribute Copy Attribute Value to file + +This will extract the value at Tag (0025,101b): + +\verbatim +$ gdcmraw -i GE_MR_0025xx1bProtocolDataBlock.dcm -t 25,101b -o pdb.raw +\endverbatim + +\subsection extract_pixeldata Extract Pixel Data + +If you do not specify any tag, the Pixel Data element is the default one. So for instance to grab the Pixel Data from an image: + +\verbatim +$ gdcmraw -i test.acr -o test.raw +\endverbatim + +You can then for example compute the md5sum of this pixel data (very useful): + +\verbatim +$ md5sum test.raw +f845c8f283d39a0204c325654493ba53 test.raw +\endverbatim + +\subsection encapsulated_syntax Encapsulated Syntax + +When the Pixel Data is encapsulated, multiple fragments can be used to store a single slice image: + +\verbatim +$ gdcmdump D_CLUNIE_CT1_J2KR.dcm +\endverbatim + +\verbatim +\&... +(7fe0,0010) OB # u/l,1 Pixel Data + (fffe,e000) ?? [] # 0,1 Item + (fffe,e000) ?? ff\\4f\\ff\\51\\00\\29\\00\\00\\00\\00\\02\\00\\00\\00\\02\\00\\00\\00\\00\\00\\00\\00\\00\\00\\00\\00\\02\\00\\00\\00\\02\\00 # 65536,1 Item + (fffe,e000) ?? 2c\\b7\\ee\\68\\de\\e3\\93\\2d\\b3\\b8\\ba\\90\\7b\\42\\3e\\f8\\42\\16\\64\\88\\46\\30\\37\\d4\\50\\95\\9b\\b6\\a5\\c7\\38\\9b # 65536,1 Item + (fffe,e000) ?? 48\\3c\\03\\e8\\c4\\3f\\44\\e1\\8a\\5c\\73\\3b\\02\\0a\\ad\\a5\\8f\\e4\\0c\\81\\76\\a2\\d7\\1b\\7f\\b7\\cd\\bc\\30\\c6\\6a\\6a # 43308,1 Item +(fffe,e0dd) 0 +\endverbatim + +In order to create a J2K image out of it, we need to extract each fragments and concatenate them: + +\verbatim +$ gdcmraw -i D_CLUNIE_CT1_J2KR.dcm -o D_CLUNIE_CT1_J2KR.j2k +\endverbatim + +This is a valid J2K file, using the Kakadu software package: + +\verbatim +$ kdu_expand -i D_CLUNIE_CT1_J2KR.j2k -o D_CLUNIE_CT1_J2KR.tiff -record D_CLUNIE_CT1_J2KR.txt +\endverbatim + +\verbatim +$ cat D_CLUNIE_CT1_J2KR.txt +\endverbatim + +\verbatim +Sprofile=PROFILE2 +Scap=no +Sextensions=0 +Ssize={512,512} +Sorigin={0,0} +Stiles={512,512} +Stile_origin={0,0} +Scomponents=1 +Ssigned=yes +Sprecision=16 +Ssampling={1,1} +Sdims={512,512} +Cycc=no +Cmct=0 +Clayers=1 +Cuse_sop=no +Cuse_eph=no +Corder=LRCP +Calign_blk_last={no,no} +Clevels=5 +Cads=0 +Cdfs=0 +Cdecomp=B(-:-:-) +Creversible=yes +Ckernels=W5X3 +Catk=0 +Cuse_precincts=no +Cblk={64,64} +Cmodes=0 +Qguard=1 +Qabs_ranges=18,19,19,20,19,19,20,19,19,20,19,19,20,19,19,20 + +>> New attributes for tile 0: +\endverbatim + +\subsection extract_fragments Extract fragments as single file + +Sometimes each fragments is in fact a single slice, so we would not need to concatenate them: + + +\verbatim +$ gdcmdump 00191113.dcm +\endverbatim + +\verbatim +\&... +(7fe0,0010) OB # u/l,1 Pixel Data + (fffe,e000) ?? 00\\00\\00\\00\\6b\\38\\01\\00\\10\\77\\02\\00\\37\\b6\\03\\00\\a7\\f4\\04\\00 # 20,1 Item + (fffe,e000) ?? ff\\d8\\ff\\c3\\00\\0b\\08\\02\\00\\02\\00\\01\\00\\11\\00\\ff\\c4\\00\\1b\\00\\01\\01\\01\\01\\01\\01\\01\\01\\00\\00\\00\\00 # 79970,1 Item + (fffe,e000) ?? ff\\d8\\ff\\c3\\00\\0b\\08\\02\\00\\02\\00\\01\\00\\11\\00\\ff\\c4\\00\\1b\\00\\01\\01\\01\\01\\01\\01\\01\\01\\00\\00\\00\\00 # 81564,1 Item + (fffe,e000) ?? ff\\d8\\ff\\c3\\00\\0b\\08\\02\\00\\02\\00\\01\\00\\11\\00\\ff\\c4\\00\\1b\\00\\01\\01\\01\\01\\01\\01\\01\\01\\00\\00\\00\\00 # 81694,1 Item + (fffe,e000) ?? ff\\d8\\ff\\c3\\00\\0b\\08\\02\\00\\02\\00\\01\\00\\11\\00\\ff\\c4\\00\\1b\\00\\01\\01\\01\\01\\01\\01\\01\\01\\00\\00\\00\\00 # 81511 (81512),1 Item +(fffe,e0dd) 0 +\endverbatim + +Let's try to extract those 4 individual Lossless jpeg individually: + +\verbatim +$ gdcmraw --split-frags -i 00191113.dcm -o jpeg --pattern %02d.ljpeg +\endverbatim + +This will output 4 files: + +\verbatim +-rw-r--r-- 1 mathieu mathieu 81512 2008-08-08 22:10 jpeg03.ljpeg +-rw-r--r-- 1 mathieu mathieu 81694 2008-08-08 22:10 jpeg02.ljpeg +-rw-r--r-- 1 mathieu mathieu 81564 2008-08-08 22:10 jpeg01.ljpeg +-rw-r--r-- 1 mathieu mathieu 79970 2008-08-08 22:10 jpeg00.ljpeg +\endverbatim + +\section footnote Footnote about JPEG files + +It is a common misunderstanding to interchange 'JPEG 8bits lossy' with simply +JPEG file. The JPEG specification is much broader than simply the common lossy +8bits file (as found on internet). + +You can have: + +\li JPEG Lossy 8bits +\li JPEG Lossy 12bits +\li JPEG Lossless 2-16bits + +Those are what is defined in ITU-T T.81, ISO/IEC IS 10918-1. + +\section see_also SEE ALSO + +gdcmdump(1), gdcmraw(1) + +\section copyright COPYRIGHT + +Copyright (c) 2006-2011 Mathieu Malaterre + +*/ diff --git a/gdcm/Utilities/doxygen/man/gdcmscanner.man b/gdcm/Utilities/doxygen/man/gdcmscanner.man new file mode 100644 index 0000000..2678dd9 --- /dev/null +++ b/gdcm/Utilities/doxygen/man/gdcmscanner.man @@ -0,0 +1,79 @@ +/*! + +\page gdcmscanner Scan a directory containing DICOM files. + +\section synopsis SYNOPSIS + +\verbatim +gdcmscanner [options] directory +\endverbatim + +\section description DESCRIPTION + +The \b gdcmscanner is a command line tool to quickly extract value from a set +of DICOM attribute in a DICOM File-Set. + +\subsection parameters parameters +\verbatim + -d --dir DICOM directory + -t --tag %d,%d DICOM tag(s) to look for +\endverbatim + +\subsection options options +\verbatim + -p --print Print output. + -r --recursive Recusively descend directory. +\endverbatim + +\subsection general_options general options +\verbatim + -h --help + print this help text and exit + + -v --version + print version information and exit + + -V --verbose + verbose mode (warning+error). + + -W --warning + warning mode, print warning information + + -E --error + error mode, print error information + + -D --debug + debug mode, print debug information +\endverbatim + +\section usage Typical usage +\section simple_usage Simple usage +In order to display all the value for Patient Name (0010,0010) in the directory +name \b gdcmData, simply do: + +\verbatim +$ gdcmscanner -t 10,10 -d gdcmData -p +\endverbatim + +\section complex_usage Complex usage + +Because gdcmscanner does not support progress, you have to wait until all files +are traversed to see any results. This is quite cumbersome, on UNIX this can +be worked around with the following trick: + +\verbatim +$ find gdcmData -type d -exec gdcmscanner -t 10,10 -d {} -p ';' +\endverbatim + +So all directory are locally traversed (no child directory are recursively +traversed), which means results comes out much faster. + +\section see_also SEE ALSO + +gdcmdump(1), gdcmraw(1) + +\section copyright COPYRIGHT + +Copyright (c) 2006-2011 Mathieu Malaterre + +*/ diff --git a/gdcm/Utilities/doxygen/man/gdcmscu.man b/gdcm/Utilities/doxygen/man/gdcmscu.man new file mode 100644 index 0000000..82140c9 --- /dev/null +++ b/gdcm/Utilities/doxygen/man/gdcmscu.man @@ -0,0 +1,341 @@ +/*! + +\page gdcmscu Tool to execute a DICOM Query/Retrieve operation + +\section synopsis SYNOPSIS + +\verbatim +gdcmscu [OPTION]...[OPERATION]...HOSTNAME...[PORT]... +\endverbatim +Execute a DICOM Q/R operation to HOSTNAME, using port PORT (104 when not specified) + +\section description DESCRIPTION + +The \b gdcmscu command line program is the tool to execute DICOM Query/Retrieve operation. +It supports: +\li C-ECHO (SCU) +\li C-FIND (SCU) +\li C-STORE (SCU) +\li C-MOVE (SCU/SCP) +C-MOVE operation are executed using two different ports (one for the SCU and one for the SCP). + +\section parameters PARAMETERS + +\section options OPTIONS + +\subsection options options +\verbatim + -H --hostname %s Hostname. + -p --port %d Port number. + --aetitle %s Set calling AE Title. + --call %s Set called AE Title. +\endverbatim + +\subsection mode_options mode options +\verbatim + --echo C-ECHO (default when none). + --store C-STORE. + --find C-FIND. + --move C-MOVE. +\endverbatim + +\subsection cstore_options C-STORE options +\verbatim + -i --input %s DICOM filename + -r --recursive recursively process (sub-)directories + --store-query %s Store constructed query in file +\endverbatim + +\subsection cfind_options C-FIND/C-MOVE options +\verbatim + --patientroot C-FIND Patient Root Model. + --studyroot C-FIND Study Root Model. + + --patient C-FIND Query on Patient Info (cannot be used with --studyroot). + --study C-FIND Query on Study Info. + --series C-FIND Query on Series Info. + --image C-FIND Query on Image Info. + --key %d,%d[=%s] 0123,4567=VALUE for specifying search criteria (wildcard allowed) + With --key, leave blank (ie, --key 10,20="" or --key 10,20) to retrieve values +\endverbatim + +\subsection cmove_options C-MOVE options +\verbatim + -o --output %s DICOM filename / directory + --port-scp %d Port for incoming associations + --key %d,%d[=%s 0123,4567=VALUE for specifying search criteria (wildcard not allowed) + Note that C-MOVE supports the same queries as C-FIND, but no wildcards are allowed +\endverbatim + +\subsection general_options general options +\verbatim + -h --help + print this help text and exit + + -v --version + print version information and exit + + -V --verbose + verbose mode (warning+error). + + -W --warning + warning mode, print warning information + + -E --error + error mode, print error information + + -D --debug + debug mode, print debug information + + -L --log-file + specify a filename where to write logs + + --queryhelp + print query help +\endverbatim + +\subsection environment_variable environment variable +\verbatim + GDCM_ROOT_UID Root UID +\endverbatim + +\section cecho_usage C-ECHO usage + +\b gdcmscu is a great tool to test if a DICOM server is up. For example to send +a C-ECHO to server dicom.example.com using port 104, use: + +\verbatim +$ gdcmscu dicom.example.com +\endverbatim + +or if you prefer being explicit: + +\verbatim +$ gdcmscu --echo dicom.example.com 104 +\endverbatim + +Using basic security your DICOM server might require that you set the +appropriate called AE-TITLE + +\verbatim +$ gdcmscu --echo dicom.example.com 11112 --call SERVSCP +\endverbatim + +If you want to specifiy your own AE-TITLE (default is GDCMSCU), simply use: + +\verbatim +$ gdcmscu --echo dicom.example.com 11112 --call SERVSCP --aetitle MYSCU +\endverbatim + +For example you could test on the DICOM server provided by DICOMObject team: + +\verbatim +$ gdcmscu www.dicomserver.co.uk 11112 +\endverbatim + +\section cstore_usage C-STORE usage + +C-STORE is the operation that allow sending a DICOM file to a remote DICOM +server. For instance to send a file called myfile.dcm + +\verbatim +$ gdcmscu --store dicom.example.com 104 myfile.dcm +\endverbatim + +or if you prefer being explicit: + +\verbatim +$ gdcmscu --store dicom.example.com 104 -i myfile.dcm +\endverbatim + +You can even send multiple files using the same association: + +\verbatim +$ gdcmscu --store dicom.example.com 104 myfile1.dcm myfile2.dcm myfile3.dcm ... +\endverbatim + +\section cfind_usage C-FIND usage + +\b gdcmscu also allow querying a DICOM server. This is the C-FIND operation, +for example to find all DICOM Instance where PatientsName match a particular +pattern, usage is simply: + +\verbatim +$ gdcmscu --find --patient dicom.example.com 11112 --patientroot --key 10,10,"A*" +\endverbatim + +We also support a DCMTK compatible convention: + +\verbatim +$ gdcmscu --find --patient dicom.example.com 11112 --patientroot --key 10,10="A*" +\endverbatim + +When an attribute is set without a value it will be part of the output result: + +\verbatim +$ gdcmscu --find --patient dicom.example.com 11112 --call MI2B2 --patientroot -k 10,10="A*" -k 10,20 +\endverbatim + +\section cmove_usage C-MOVE usage + +C-MOVE is the operation to retrieve a DICOM instance from a remote DICOM +server. Most of the time, it is a subsequent operation after a C-FIND query. +To retrieve a DICOM instance where PatientID is ABCD1234, simply execute: + +\verbatim +$ gdcmscu --move --patient --aetitle ACME1 --call ACME_STORE dicom.example.com 5678 --patientroot -k 10,20="ABCD1234" --port-scp 1234 +\endverbatim + +WARNING For this operation to work you need information from the DICOM server +you are communicating with. Only the DICOM server you are sending a C-MOVE +query will be responsible for sending back incoming associations (the actual +C-STORE SCP). +Therefore you need to make sure that you mapping of (AE-TITLE,PortNumber) is +properly set on the DICOM server side as well as the port for incoming +association (--port-scp). + +\b gdcmscu does not currently support external C-STORE association (C-STORE +request sent to an external SCP application). + +\section patientroot_notes patientroot notes + +The flag --patientroot is just simply a wrapper around the syntax --key 8,52=PATIENT +For instance one would write using DCMTK syntax: + +\verbatim +$ findscu --patient dicom.example.com 11112 --key 8,52=PATIENT --key 10,10="F*" +\endverbatim + +This would become using GDCM syntax: + +\verbatim +$ gdcmscu --find --patient dicom.example.com 11112 --patientroot --key 10,10="F*" +\endverbatim + +\section debugging Debugging + +This is sometime difficult to investigate why a connection to a remote DICOM server +cannot be done. Some recommendations follows: + +Always try to do a simple C-ECHO at first. If you cannot get the C-ECHO to work +none of the other operations will work + +Before trying to a C-MOVE operation, make sure you can execute the C-FIND equivalent +query first. + +When doing a C-MOVE operation you really need to communicate with the PACS +admin as the C-MOVE operation is different from the other lower level operation +such as HTTP/GET. When doing a C-MOVE, the server will communicate back using +another channel (could be different port) using it's internal database to map +an AE-TITLE back to the destination IP. + +Indeed the C-MOVE operation by design does not always use your incoming IP +address to send back the resulting dataset. Instead it uses a mapping of +AE-TITLE to IP address to send back any results. So pay particular attention to +the spelling of your AE-TITLE and your incoming port (which may be different +from the port to connect to the server). + +\section gdcmscu_portwarnings Port Warning + +Watch out that port ranging [1-1024] are reserved for admin and not easily +accessible unless granted special privileges. Therefore the default 104 DICOM +port might not be accessible to all your users. + +\section gdcmscu_ctorewarnings C-STORE Warnings + +When constructing a C-STORE operation, gdcmscu will always use the Media +Storage SOP Class UID as found in the file to be sent. For encapsulated DICOM +file (eg. RLE Lossless) the receiving SCP server might not support this +compression and will legitimately refuse the C-STORE operation. In this case +users have to manually convert to a non-compressed form this particular file: + +\verbatim +$ gdcmconv --raw compressed.dcm non_compressed.dcm +\endverbatim + +\section gdcmscu_cmovewarnings C-MOVE Warnings + +At the moment \b gdcmscu only supports non-compressed transfer syntax. It will +always request DataSet using Implicit VR Little Endian Transfer Syntax during a +C-MOVE operation (both incoming and outgoing associations). This make gdcmscu +--move equivalent to DCMTK movescu syntax: + +\verbatim +$ movescu -xi +xi ... +\endverbatim + +\section gdcmscu_cfind_image C-FIND IMAGE level (Composite Object Instance) + +One should pay attention that gdcmscu --find and findscu are not completely +equivalent. Using gdcmscu --find, all Unique Keys will be added automatically. +One can therefore execute something like this: + +\verbatim +$ gdcmscu --find --patientroot --image --key 8,18=1.2.3.4.5.6 dicom.example.com 11112 +\endverbatim + +instead of the more explicit form + +\verbatim +$ gdcmscu --find --patientroot --image --key 8,18=1.2.3.4.5.6 dicom.example.com 11112 --key 10,20 --key 20,d --key 20,e +\endverbatim + +This would also be equivalent to: + +\verbatim +$ findscu --patient --key 8,52=IMAGE --key 8,18=1.2.3.4.5.6 dicom.example.com 11112 --key 10,20 --key 20,d --key 20,e +\endverbatim + +\section gdcmscu_storing Storing the Query + +It is also possible to store the query: + +\verbatim +gdcmscu --find --patient --patientroot dicom.example.com 11112 --key 10,20="*" --key 10,10 --store-query query.dcm +\endverbatim + +One can then check the DataSet values send for the query: + +\verbatim +$ gdcmdump query.dcm +# Dicom-File-Format + +# Dicom-Meta-Information-Header +# Used TransferSyntax: + +# Dicom-Data-Set +# Used TransferSyntax: 1.2.840.10008.1.2 +(0008,0005) ?? (CS) [ISO_IR 192] # 10,1-n Specific Character Set +(0008,0052) ?? (CS) [PATIENT ] # 8,1 Query/Retrieve Level +(0010,0010) ?? (PN) (no value) # 0,1 Patient's Name +(0010,0020) ?? (LO) [* ] # 2,1 Patient ID +\endverbatim + +The Specific Character Set was set to "ISO_IR 192" as the locale encoding of +the system was found automatically by gdcmscu to be UTF-8. + +This means that the following command line will properly setup the Query with +the appropriate Charset to be executed correctly: + +\verbatim +$ gdcmscu --find --patient --patientroot dicom.example.com 11112 --key 10,10="*Jérôme*" +\endverbatim + +The query is always executed on the server side (SCP), some implementations +does not support string matching with different Character Set. + +\section public_servers DICOM Public Servers + +An up to date list of DICOM Public Servers can be found at: + +http://www.dclunie.com/medical-image-faq/html/part8.html#DICOMPublicServers + +\section see_also SEE ALSO + +gdcmconv(1) + +\section copyright COPYRIGHT + +Copyright Insight Software Consortium + +*/ diff --git a/gdcm/Utilities/doxygen/man/gdcmtar.man b/gdcm/Utilities/doxygen/man/gdcmtar.man new file mode 100644 index 0000000..c508cea --- /dev/null +++ b/gdcm/Utilities/doxygen/man/gdcmtar.man @@ -0,0 +1,137 @@ +/*! + +\page gdcmtar Concatenate/Extract DICOM files. + +\section synopsis SYNOPSIS + +\verbatim +gdcmtar [options] file-in file-out +\endverbatim + +\section description DESCRIPTION + +The \b gdcmtar is a command line tool used to tar/untar multi-frames images +(including SIEMENS MOSAIC file) + +\section parameters PARAMETERS + +\verbatim +file-in DICOM input filename + +file-out DICOM output filename +\endverbatim + +\section options OPTIONS + +\subsection options options +\verbatim + --enhance enhance (default) + -U --unenhance unenhance + -M --mosaic Split SIEMENS Mosaic image into multiple frames. + -p --pattern Specify trailing file pattern. + --root-uid Root UID. +\endverbatim + +\subsection general_options general options +\verbatim + -h --help + print this help text and exit + + -v --version + print version information and exit + + -V --verbose + verbose mode (warning+error). + + -W --warning + warning mode, print warning information + + -E --error + error mode, print error information + + -D --debug + debug mode, print debug information +\endverbatim + +\subsection environment_variable environment variable +\verbatim + GDCM_ROOT_UID Root UID +\endverbatim + +\section usage Typical usage +\subsection mosaic SIEMENS Mosaic + +\verbatim +$ gdcminfo MR-sonata-3D-as-Tile.dcm +\endverbatim + +\verbatim +MediaStorage is 1.2.840.10008.5.1.4.1.1.4 [MR Image Storage] +TransferSyntax is 1.2.840.10008.1.2.1 [Explicit VR Little Endian] +NumberOfDimensions: 2 +Dimensions: (384,384,1) +\&... +\endverbatim + +\verbatim +$ gdcmtar --mosaic -i MR-sonata-3D-as-Tile.dcm -o mosaic --pattern %03d.dcm +\endverbatim + +Will output: + +\verbatim +-rw-r--r-- 1 mathieu mathieu 72882 2009-08-10 11:14 mosaic000.dcm +-rw-r--r-- 1 mathieu mathieu 72886 2009-08-10 11:14 mosaic001.dcm +-rw-r--r-- 1 mathieu mathieu 72886 2009-08-10 11:14 mosaic002.dcm +-rw-r--r-- 1 mathieu mathieu 72886 2009-08-10 11:14 mosaic003.dcm +-rw-r--r-- 1 mathieu mathieu 72886 2009-08-10 11:14 mosaic004.dcm +-rw-r--r-- 1 mathieu mathieu 72886 2009-08-10 11:14 mosaic005.dcm +-rw-r--r-- 1 mathieu mathieu 72884 2009-08-10 11:14 mosaic006.dcm +-rw-r--r-- 1 mathieu mathieu 72882 2009-08-10 11:14 mosaic007.dcm +-rw-r--r-- 1 mathieu mathieu 72884 2009-08-10 11:14 mosaic008.dcm +-rw-r--r-- 1 mathieu mathieu 72884 2009-08-10 11:14 mosaic009.dcm +-rw-r--r-- 1 mathieu mathieu 72884 2009-08-10 11:14 mosaic010.dcm +-rw-r--r-- 1 mathieu mathieu 72884 2009-08-10 11:14 mosaic011.dcm +-rw-r--r-- 1 mathieu mathieu 72884 2009-08-10 11:14 mosaic012.dcm +-rw-r--r-- 1 mathieu mathieu 72884 2009-08-10 11:14 mosaic013.dcm +-rw-r--r-- 1 mathieu mathieu 72882 2009-08-10 11:14 mosaic014.dcm +-rw-r--r-- 1 mathieu mathieu 72884 2009-08-10 11:14 mosaic015.dcm +-rw-r--r-- 1 mathieu mathieu 72882 2009-08-10 11:14 mosaic016.dcm +-rw-r--r-- 1 mathieu mathieu 72884 2009-08-10 11:14 mosaic017.dcm +-rw-r--r-- 1 mathieu mathieu 72884 2009-08-10 11:14 mosaic018.dcm +-rw-r--r-- 1 mathieu mathieu 72884 2009-08-10 11:14 mosaic019.dcm +-rw-r--r-- 1 mathieu mathieu 72884 2009-08-10 11:14 mosaic020.dcm +-rw-r--r-- 1 mathieu mathieu 72884 2009-08-10 11:14 mosaic021.dcm +-rw-r--r-- 1 mathieu mathieu 72884 2009-08-10 11:14 mosaic022.dcm +-rw-r--r-- 1 mathieu mathieu 72884 2009-08-10 11:14 mosaic023.dcm +-rw-r--r-- 1 mathieu mathieu 72884 2009-08-10 11:14 mosaic024.dcm +-rw-r--r-- 1 mathieu mathieu 72884 2009-08-10 11:14 mosaic025.dcm +-rw-r--r-- 1 mathieu mathieu 72884 2009-08-10 11:14 mosaic026.dcm +-rw-r--r-- 1 mathieu mathieu 72884 2009-08-10 11:14 mosaic027.dcm +-rw-r--r-- 1 mathieu mathieu 72884 2009-08-10 11:14 mosaic028.dcm +-rw-r--r-- 1 mathieu mathieu 72884 2009-08-10 11:14 mosaic029.dcm +-rw-r--r-- 1 mathieu mathieu 72882 2009-08-10 11:14 mosaic030.dcm +\endverbatim + +\verbatim +$ gdcminfo mosaic000.dcm +\endverbatim + +\verbatim +MediaStorage is 1.2.840.10008.5.1.4.1.1.4 [MR Image Storage] +TransferSyntax is 1.2.840.10008.1.2.1 [Explicit VR Little Endian] +NumberOfDimensions: 2 +Dimensions: (64,64,1) +\&... +\endverbatim + + +\section see_also SEE ALSO + +gdcmdump(1), gdcmraw(1), gdcminfo(1) + +\section copyright COPYRIGHT + +Copyright (c) 2006-2011 Mathieu Malaterre + +*/ diff --git a/gdcm/Utilities/doxygen/man/gdcmviewer.man b/gdcm/Utilities/doxygen/man/gdcmviewer.man new file mode 100644 index 0000000..5a1caa4 --- /dev/null +++ b/gdcm/Utilities/doxygen/man/gdcmviewer.man @@ -0,0 +1,88 @@ +/*! + +\page gdcmviewer Simple DICOM viewer. + +\section synopsis SYNOPSIS + +\verbatim +gdcmviewer [options] file-in +\endverbatim + +\section description DESCRIPTION + +The \b gdcmviewer is a simple tool that show how to use vtkGDCMImageReader. +The class that use gdcm to make a layer to VTK. \b gdcmviewer is basically only +just a wrapper around VTK/GDCM. + +This tool is meant for testing integration of GDCM in VTK. You should see it as +a demo tool. It does compile with VTK ranging from 4.2 to 5.10, but only with +VTK 5.2 (or above) can play with the widgets (as described below). + +\section parameters PARAMETERS + +\verbatim +file-in DICOM input filename +\endverbatim + +\section options OPTIONS + +\subsection options options +\verbatim + --force-rescale force rescale (advanced users) + --force-spacing force spacing (advanced users) + -r --recursive Recusively descend directory +\endverbatim + +\subsection general_options general options +\verbatim + -h --help + print this help text and exit + + -v --version + print version information and exit + + -V --verbose + verbose mode (warning+error). + + -W --warning + warning mode, print warning information + + -E --error + error mode, print error information + + -D --debug + debug mode, print debug information +\endverbatim + +\section usage Typical usage +\section simple_usage Simple usage + +For now gdcmviewer should be started from a command line prompt. The next +argument should be the name of the DICOM file you wish to read. For instance: + +\verbatim +$ gdcmviewer -V 012345.002.050.dcm +\endverbatim + +gdcmviewer will try to read your file, and then print the vtk information +associated with this file. Basically what kind of image you are looking at. + +\li ScalarType is the DICOM Real World Value type +\li Dimensions is the dimension of the image +\li Spacing is the spacing of the image +\li NumberOfScalarComponents should be 1 for grayscale & PALETTE COLOR and 3 for RGB, YBR data. + +\section wiki_link Wiki Link + +The wiki page, with color pictures can be found at: +http://gdcm.sourceforge.net/wiki/index.php/Gdcmviewer + +\section see_also SEE ALSO + +gdcmdump(1), gdcm2vtk(1) + +\section copyright COPYRIGHT + +Copyright (c) 2006-2011 Mathieu Malaterre + +*/ diff --git a/gdcm/Utilities/doxygen/man/gdcmxml.man b/gdcm/Utilities/doxygen/man/gdcmxml.man new file mode 100644 index 0000000..7aee053 --- /dev/null +++ b/gdcm/Utilities/doxygen/man/gdcmxml.man @@ -0,0 +1,77 @@ +/*! + +\page gdcmxml provides a tool to convert a DICOM file into a XML infoset and vice-versa. + +\section synopsis SYNOPSIS + +\verbatim +gdcmxml [options] file-in[DICOM or XML] file-out[XML or DICOM] +\endverbatim + +\section description DESCRIPTION + +The \b gdcmxml command line program converts a DICOM file (DataSet) into an XML +file (according to the Native DICOM Model) or vice-versa. For those familiar +with DCMTK, this provides binary capabilities (i.e. functionality of both +dcm2xml and xml2dcm). + +The XML infoset which is from the DICOM file gdcmXMLPrintet Class. This is in +strict compliance with the Native DICOM Model as given in Supp 118. + +\section parameters PARAMETERS + +\verbatim +file-in DICOM or XML input filename ( cannot be absent) + +file-out output filename (can be absent) +\endverbatim + +\section options OPTIONS + +\subsection parameters parameters +\verbatim + -i --input DICOM filename + -o --output DICOM filename +\endverbatim + +\subsection options_dicom2xml Options for DICOM to XML: +\verbatim + -B --loadBulkData Loads bulk data into a binary file named "UUID" (by default UUID are written). +\endverbatim + +\subsection options_xml2dicom Options for XML to DICOM: +\verbatim + -B --loadBulkData Loads bulk data from a binary file named as the "UUID" in XML file (by default UUID are written). + -T --TransferSyntax Loads transfer syntax from file (default is LittleEndianImplicit) +\endverbatim + +\subsection general_options general options +\verbatim + -h --help + print this help text and exit + + -v --version + print version information and exit + + -V --verbose + verbose mode (warning+error). + + -W --warning + warning mode, print warning information + + -E --error + error mode, print error information + + -D --debug + debug mode, print debug information +\endverbatim + +\section see_also SEE ALSO + +gdcmdump(1), gdcmconv(1) + +\section copyright COPYRIGHT + +Copyright (c) 2006-2011 Mathieu Malaterre + +*/ diff --git a/gdcm/Utilities/doxygen/patchtex.cmake b/gdcm/Utilities/doxygen/patchtex.cmake new file mode 100644 index 0000000..6cfff4a --- /dev/null +++ b/gdcm/Utilities/doxygen/patchtex.cmake @@ -0,0 +1,10 @@ +project(toto) + +file(READ ${CMAKE_CURRENT_SOURCE_DIR}/refman.tex refman_file) +string(REPLACE "]{hyperref}" +"]{hyperref}\\\\hypersetup{pdftitle={GDCM Reference Guide},pdfkeywords={DICOM},baseurl={http:\\/\\/gdcm.sourceforge.net}}\\\\hyperbaseurl{http:\\/\\/gdcm.sourceforge.net}" +patched_refman_file +${refman_file} +) + +file(WRITE ${CMAKE_CURRENT_SOURCE_DIR}/patched.tex ${patched_refman_file}) diff --git a/gdcm/Utilities/doxygen/vtk/CMakeLists.txt b/gdcm/Utilities/doxygen/vtk/CMakeLists.txt new file mode 100644 index 0000000..83a9fbd --- /dev/null +++ b/gdcm/Utilities/doxygen/vtk/CMakeLists.txt @@ -0,0 +1,122 @@ +# +# Build the documentation +# +include (Documentation) + +if (BUILD_DOCUMENTATION) +find_package(VTK REQUIRED) +mark_as_advanced(VTK_DIR) + + set(VTKGDCM_FINAL_PATH ${GDCM_BINARY_DIR}/Utilities/doxygen/html) + set (INCLUDE_QT_DOCUMENTATION OFF CACHE BOOL "Specify if Qt documentation should be linked to.") + mark_as_advanced(INCLUDE_QT_DOCUMENTATION) + if (INCLUDE_QT_DOCUMENTATION) + set(QT_DOC_DIR CACHE FILEPATH "Path to the directory containing Qt html documentation.") + find_program (DOXYTAG + doxytag + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\doxygen_is1;Inno Setup: App Path]/bin" + /Applications/Doxygen.app/Contents/Resources + /Applications/Doxygen.app/Contents/MacOS + ) + mark_as_advanced(DOXYTAG QT_DOC_DIR) + set (QT_TAG_FILE "${CMAKE_CURRENT_BINARY_DIR}/Qt.tag") + endif () + set(BUILD_DOXYGEN ON) + set(DOCUMENTATION_DOWNLOAD_VTK_TAGFILE ON) + set(DOCUMENTATION_HTML_TARZ ON) + set(DOXYGEN_PROJECT_NAME "vtkgdcm") + if(VTK_SOURCE_DIR) + message(${VTK_SOURCE_DIR}) + #set(DOXYGEN_SOURCE_DIR "${vtkgdcm_SOURCE_DIR}/VTK/Utilities/Doxygen") + set(DOXYGEN_SOURCE_DIR "${VTK_SOURCE_DIR}/Utilities/Doxygen") + else() + # sudo apt-get install vtk-doc + set(DOXYGEN_SOURCE_DIR "/usr/share/doc/vtk-doc/html/") + endif() + set(DOXYGEN_PROJECT_SOURCE_DIR "${vtkgdcm_SOURCE_DIR}") + set(VTK_DOXYGEN_HOME "${vtkgdcm_SOURCE_DIR}/VTK/Utilities/Doxygen") + set(DOXYGEN_CVSWEB_CHECKOUT "http://public.kitware.com/cgi-bin/cvsweb.cgi/~checkout~/vtkgdcm/") + set(DOXYGEN_CVSWEB_CHECKOUT_SUFFIX "?cvsroot=vtkgdcm") + set(DOXYGEN_SOURCE_LOCATIONS_DIR "${vtkgdcm_SOURCE_DIR}") + set(DOXYGEN_SOURCE_LOCATIONS + "\"${vtkgdcm_SOURCE_DIR}\" \\ + \"${vtkgdcm_SOURCE_DIR}/Utilities/Xdmf2/vtk\" \\ + \"${vtkgdcm_SOURCE_DIR}/Utilities/VTKPythonWrapping/Executable\" \\ + \"${vtkgdcm_SOURCE_DIR}/Utilities/VTKClientServer\" \\ + \"${vtkgdcm_SOURCE_DIR}/Qt/Chart\" \\ + \"${vtkgdcm_SOURCE_DIR}/Qt/Components\" \\ + \"${vtkgdcm_SOURCE_DIR}/Qt/Core\" \\ + \"${vtkgdcm_SOURCE_DIR}/Qt/Python\" \\ + \"${vtkgdcm_SOURCE_DIR}/Qt/Widgets\" \\ + \"${vtkgdcm_SOURCE_DIR}/Qt/Testing\" \\ + \"${vtkgdcm_SOURCE_DIR}/Applications/Client\" \\ + \"${vtkgdcm_SOURCE_DIR}/Applications/OverView\" \\ + \"${vtkgdcm_SOURCE_DIR}/Applications/OverView/Core\" \\ + \"${vtkgdcm_SOURCE_DIR}/Common/KWCommon\" \\ + \"${vtkgdcm_SOURCE_DIR}/Servers/Common\" \\ + \"${vtkgdcm_SOURCE_DIR}/Servers/Filters\" \\ + \"${vtkgdcm_SOURCE_DIR}/Servers/ServerManager\"") + set(DOXYGEN_BINARY_LOCATIONS_DIR "${vtkgdcm_BINARY_DIR}") + set(DOXYGEN_BINARY_LOCATIONS + "") + set(DOXYGEN_PARSED_INPUT_DIRS + " \"${CMAKE_CURRENT_BINARY_DIR}/dox\" \\ + \"${CMAKE_CURRENT_BINARY_DIR}/dox/Utilities/Xdmf2/vtk\" \\ + \"${CMAKE_CURRENT_BINARY_DIR}/dox/Utilities/VTKPythonWrapping/Executable\" \\ + \"${vtkgdcm_SOURCE_DIR}/Utilities/VTKClientServer\" \\ + \"${vtkgdcm_SOURCE_DIR}/Qt/Chart\" \\ + \"${vtkgdcm_SOURCE_DIR}/Qt/Components\" \\ + \"${vtkgdcm_SOURCE_DIR}/Qt/Core\" \\ + \"${vtkgdcm_SOURCE_DIR}/Qt/Python\" \\ + \"${vtkgdcm_SOURCE_DIR}/Qt/Widgets\" \\ + \"${vtkgdcm_SOURCE_DIR}/Qt/Testing\" \\ + \"${vtkgdcm_SOURCE_DIR}/Applications/Client\" \\ + \"${vtkgdcm_SOURCE_DIR}/Applications/OverView\" \\ + \"${vtkgdcm_SOURCE_DIR}/Applications/OverView/Core\" \\ + \"${CMAKE_CURRENT_BINARY_DIR}/dox/Qt/Core\" \\ + \"${CMAKE_CURRENT_BINARY_DIR}/dox/Common/KWCommon\" \\ + \"${CMAKE_CURRENT_BINARY_DIR}/dox/Servers/Common\" \\ + \"${CMAKE_CURRENT_BINARY_DIR}/dox/Servers/Filters\" \\ + \"${CMAKE_CURRENT_BINARY_DIR}/dox/Servers/ServerManager\"") + + + set(DOXYGEN_IGNORE_PREFIX "vtkPV vtkSM vtk pq") + + # + # Configure the script and the doxyfile, then add target + # + if(NOT DOT_PATH) + get_filename_component(DOT_PATH ${DOT} PATH) + endif() + + set(TAGFILES "\"${CMAKE_CURRENT_BINARY_DIR}/vtkNightlyDoc.tag=http://www.vtk.org/doc/nightly/html\"") + if(INCLUDE_QT_DOCUMENTATION) + set (TAGFILES "${TAGFILES} \"${QT_TAG_FILE}=http://doc.trolltech.com/4.2\"") + endif() + + configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/doxyfile.in + ${CMAKE_CURRENT_BINARY_DIR}/doxyfile @ONLY ) + + configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/doc_makeall.sh.in + ${CMAKE_CURRENT_BINARY_DIR}/doc_makeall.sh @ONLY ) + + add_custom_target(${DOXYGEN_PROJECT_NAME}DoxygenDoc + #ALL + ${BASH} + ${CMAKE_CURRENT_BINARY_DIR}/doc_makeall.sh) + + add_dependencies( + ${DOXYGEN_PROJECT_NAME}DoxygenDoc + GDCMDoxygenPDF + ) + + if(INCLUDE_QT_DOCUMENTATION) + add_custom_target(QtDoxygenTags + COMMAND ${DOXYTAG} -t ${QT_TAG_FILE} ${QT_DOC_DIR}) + add_dependencies(${DOXYGEN_PROJECT_NAME}DoxygenDoc + QtDoxygenTags) + endif() + +endif () diff --git a/gdcm/Utilities/doxygen/vtk/doc_makeall.sh.in b/gdcm/Utilities/doxygen/vtk/doc_makeall.sh.in new file mode 100644 index 0000000..a9f2451 --- /dev/null +++ b/gdcm/Utilities/doxygen/vtk/doc_makeall.sh.in @@ -0,0 +1,318 @@ +# ------------------------------------------------------------------------- +# Doxygen documentation batch +# modified by S. Barre (Time-stamp: <2005-06-17 15:12:59 barre> +# ------------------------------------------------------------------------- + +# Path to several tools (_PROG to avoid the typical GZIP env var pb) +# Example: +# DOXYGEN_PROG=@DOXYGEN@ (INCLUDE(FindDoxygen.cmake)) +# GZIP_PROG=@GZIP@ (INCLUDE(FindCygwin.cmake)) +# HHC_PROG=@HTML_HELP_COMPILER@ (INCLUDE(FindHTMLHelp.cmake)) +# MV_PROG=@MV@ (INCLUDE(FindCygwin.cmake)) +# PERL_PROG=@PERL@ (INCLUDE(FindPerl.cmake)) +# RM_PROG=@RM@ (INCLUDE(FindCygwin.cmake)) +# TAR_PROG=@TAR@ (INCLUDE(FindCygwin.cmake)) +# WGET_PROG=@WGET@ (INCLUDE(FindWget.cmake)) +# +export DOXYGEN_PROG="@DOXYGEN@" # Doxygen +export GZIP_PROG="@GZIP@" # gzip (Unix-like 'gzip compressor') +export GNUPLOT_PROG="@GNUPLOT@" # gnuplot (data plotting program) +export HHC_PROG="@HTML_HELP_COMPILER@" # HTML Help Compiler +export MV_PROG="@MV@" # mv (Unix-like 'move/rename files') +export CP_PROG="@CP@" # mv (Unix-like 'move/rename files') +export PERL_PROG="@PERL@" # Perl +export RM_PROG="@RM@" # rm (Unix-like 'remove files') +export TAR_PROG="@TAR@" # tar (Unix-like 'archiver') +export WGET_PROG="@WGET@" # wget (remote file retrieval) + +# PROJECT_NAME: +# Documentation/project name. Used in some of the resulting file names and +# xrefs to uniquify two or more projects linked together through their +# Doxygen's tag files. Mandatory for each documentation set. +# Note: might be the same as the doxyfile's PROJECT_NAME +# Example: +# PROJECT_NAME=VTK +# +export PROJECT_NAME=@DOXYGEN_PROJECT_NAME@ + +# PATH_TO_VTK_DOX_SCRIPTS: +# Path to the directory holding the Perl scripts used to produce the VTK doc +# in Doxygen format. You need the VTK source files or a local copy of +# these scripts. +# Example: +# PATH_TO_VTK_DOX_SCRIPTS=@CMAKE_CURRENT_SOURCE_DIR@ +# +export PATH_TO_VTK_DOX_SCRIPTS="@DOXYGEN_SOURCE_DIR@" + +export PATH_TO_VTKGDCM_FINAL_PATH="@VTKGDCM_FINAL_PATH@" + +# SOURCE_DIR: +# Source directory. The top directory of the source files. +# Example: +# SOURCE_DIR=@DOXYGEN_PROJECT_SOURCE_DIR@ +# +export SOURCE_DIR="@DOXYGEN_PROJECT_SOURCE_DIR@" + +# REL_PATH_TO_TOP: +# Relative path from the top directory of the source files to the directory +# (or top directory) holding the files to document. Useful if several parts +# of the same source directory should be documented separately. +# Example: +# REL_PATH_TO_TOP=. +# REL_PATH_TO_TOP=framework/src +# +export REL_PATH_TO_TOP=. + +# INTERMEDIATE_DOX_DIR: +# Directory where the intermediate Doxygen files should be stored (mainly +# these headers files converted from the VTK format to the Doxygen format). +# This directory is erased at the end of this script, unless you comment +# the corresponding line. +# DOXTEMP might be used to simplify the syntax. +# Example: +# DOXTEMP=DOXTEMP=@CMAKE_CURRENT_BINARY_DIR@ +# INTERMEDIATE_DOX_DIR=$DOXTEMP/dox +# +export DOXTEMP="@CMAKE_CURRENT_BINARY_DIR@" +export INTERMEDIATE_DOX_DIR="$DOXTEMP/dox" + +# CVSWEB_CHECKOUT, CVSWEB_CHECKOUT_SUFFIX: +# URL to the CVSWeb of the project, in checkout mode (i.e. appending a file +# name to this URL will retrieve the contents of the file). In the same way +# CVSWEB_CHECKOUT_SUFFIX is appended to the result. +# Example: +# CVSWEB_CHECKOUT=http://public.kitware.com/cgi-bin/cvsweb.cgi/~checkout~/VTK +# CVSWEB_CHECKOUT_SUFFIX=?cvsroot=CMake +# +export CVSWEB_CHECKOUT="@DOXYGEN_CVSWEB_CHECKOUT@" +export CVSWEB_CHECKOUT_SUFFIX="@DOXYGEN_CVSWEB_CHECKOUT_SUFFIX@" + +# DOXYFILE: +# Path to the Doxygen configuration file (i.e. doxyfile). +# Example: +# DOXYFILE=$DOXTEMP/doxyfile +# +export DOXYFILE="$DOXTEMP/doxyfile" + +# OUTPUT_DIRECTORY ALLOW_ERASE_OUTPUT_DIRECTORY: +# Path to the Doxygen output directory (where the resulting doc is stored). +# Note: should be the same as your doxyfile's OUTPUT_DIRECTORY +# If ON, allows the output directory to be erased when some advanced output +# file have been produced (HTML Help, or TAR archive for example). +# Example: +# OUTPUT_DIRECTORY=$DOXTEMP/doc +# ALLOW_ERASE_OUTPUT_DIRECTORY=ON +# +export OUTPUT_DIRECTORY="$DOXTEMP/doc" +export ALLOW_ERASE_OUTPUT_DIRECTORY=ON + +# COMPILE_HTML_HELP RESULTING_HTML_HELP_FILE: +# Compile the CHM (Compressed HTML) HTML Help file, name of the resulting +# file. If set to ON and name is non-empty these options will actually +# trigger the HTML-Help compiler to create the CHM. The resulting +# file (usually index.chm) will be renamed to this name. +# Note: if ON, the whole $OUTPUT_DIRECTORY will be erased at the end of +# this script, since this file is considered to be one of the +# advanced final output, unless ALLOW_ERASE_OUTPUT_DIRECTORY is OFF +# Note: your doxyfile should be configured to enable HTML Help creation +# (using GENERATE_HTML = YES, GENERATE_HTMLHELP = YES) +# Example: +# COMPILE_HTML_HELP=ON +# COMPILE_HTML_HELP=@DOCUMENTATION_HTML_HELP@ +# RESULTING_HTML_HELP_FILE=$DOXTEMP/vtk4.chm +# +export COMPILE_HTML_HELP=@DOCUMENTATION_HTML_HELP@ +export RESULTING_HTML_HELP_FILE="$DOXTEMP/$PROJECT_NAME.chm" + +# CREATE_HTML_TARZ_ARCHIVE RESULTING_HTML_TARZ_ARCHIVE_FILE: +# Create a compressed (gzip) tar archive of the html directory (located +# under the OUTPUT_DIRECTORY), and name of the resulting archive file. +# Note: your doxyfile should be configured to enable HTML creation +# (using GENERATE_HTML = YES) +# Example: +# CREATE_HTML_TARZ_ARCHIVE=ON +# CREATE_HTML_TARZ_ARCHIVE=@DOCUMENTATION_HTML_TARZ@ +# RESULTING_HTML_TARZ_ARCHIVE_FILE=$DOXTEMP/vtk4-html.tar.gz +# +export CREATE_HTML_TARZ_ARCHIVE=@DOCUMENTATION_HTML_TARZ@ +export RESULTING_HTML_TARZ_ARCHIVE_FILE="$DOXTEMP/$PROJECT_NAME-html.tar.gz" + +# DOWNLOAD_VTK_TAGFILE VTK_TAGFILE VTK_TAGFILE_REMOTE_DIR VTK_TAGFILE_DEST_DIR: +# Download the VTK tag file, name, remote location and destination dir of this +# tag file. If set to ON, the tag file is retrieved from its remote location +# using wget and stored in the destination dir. +# The tag file is expected to be compressed using gzip, but DO NOT include +# the .gz extension in VTK_TAGFILE. +# Note: your doxyfile must be tailored to make use-of or create this tag file. +# (using TAGFILES = vtk4-nightly.tag=http://www.vtk.org/doc/nightly/html +# or GENERATE_TAGFILE = "@FOO_BINARY_DIR@/Utilities/Doxygen/vtk4.tag") +# Example: +# DOWNLOAD_VTK_TAGFILE=OFF +# VTK_TAGFILE=vtk4-nightly.tag +# VTK_TAGFILE_REMOTE_DIR=http://www.vtk.org/doc/nightly/html +# VTK_TAGFILE_DEST_DIR=$DOXTEMP +# +export DOWNLOAD_VTK_TAGFILE=@DOCUMENTATION_DOWNLOAD_VTK_TAGFILE@ +export VTK_TAGFILE=vtkNightlyDoc.tag +export VTK_TAGFILE_REMOTE_DIR="http://www.vtk.org/files/nightly" +export VTK_TAGFILE_DEST_DIR="$DOXTEMP" + +echoexit() +{ + echo "$1" + exit 1 +} + +cd "${DOXTEMP}" || echoexit "Cannot find Doxygen output directory: ${DOXTEMP}" + +# ---------------------------------------------------------------------------- +# Convert the VTK headers to the Doxygen format. +echo "Convert the VTK headers to the Doxygen format." +if test "x$PERL_PROG" != "xNOTFOUND" ; then + $PERL_PROG "$PATH_TO_VTK_DOX_SCRIPTS/doc_header2doxygen.pl" \ + --to "$INTERMEDIATE_DOX_DIR" \ + --relativeto "@DOXYGEN_SOURCE_LOCATIONS_DIR@" \ + @DOXYGEN_SOURCE_LOCATIONS@ || echoexit "Problem converting VTK headers" + if test "x@DOXYGEN_BINARY_LOCATIONS_DIR@" != "x"; then + $PERL_PROG "$PATH_TO_VTK_DOX_SCRIPTS/doc_header2doxygen.pl" \ + --to "$INTERMEDIATE_DOX_DIR" \ + --relativeto "@DOXYGEN_BINARY_LOCATIONS_DIR@" \ + @DOXYGEN_BINARY_LOCATIONS@ || echoexit "Problem converting VTK headers" + fi +fi +echo "Convert the VTK headers to the Doxygen format - done" + +# ---------------------------------------------------------------------------- +# Build the full-text index. +echo "Build the full-text index." +if test "x$PERL_PROG" != "xNOTFOUND" ; then + $PERL_PROG "$PATH_TO_VTK_DOX_SCRIPTS/doc_index.pl" \ + --project "$PROJECT_NAME" \ + --stop "$PATH_TO_VTK_DOX_SCRIPTS/doc_index.stop" \ + --store "doc_""$PROJECT_NAME""_index.dox" \ + --to "$INTERMEDIATE_DOX_DIR" \ + @DOXYGEN_SOURCE_LOCATIONS@ \ + @DOXYGEN_BINARY_LOCATIONS@ || echoexit "Problem building full-text index" +fi +echo "Build the full-text index - done" + +# # ---------------------------------------------------------------------------- +# # Generate the 'Class to Demos' page cross-linking each class to these +# # demos that use that class. + +# if test "x$PERL_PROG" != "xNOTFOUND" ; then +# $PERL_PROG $PATH_TO_VTK_DOX_SCRIPTS/doc_class2example.pl \ +# --datamatch "\W((VTK|ParaView)_DATA_ROOT|(VTK|MedVIP)Data|(vtk)?GetDataRoot|ExpandDataFileName)\W" \ +# --dataicon "paper-clip.gif" \ +# --dirmatch "^demos$" \ +# --label "Demos" \ +# --project "$PROJECT_NAME" \ +# --store "doc_""$PROJECT_NAME""_class2demos.dox" \ +# --title "Class To Demos" \ +# --to "$INTERMEDIATE_DOX_DIR" \ +# --unique "d" \ +# "$SOURCE_DIR/framework/demos" +# fi + +# ---------------------------------------------------------------------------- +# Retrieve the (gziped) VTK 4 tag file and decompress it + +if test "x$DOWNLOAD_VTK_TAGFILE" == "xON" ; then + if test "x$VTK_TAGFILE" != "x" ; then + if test "x$WGET_PROG" != "xNOTFOUND" ; then + $WGET_PROG -nd -nH \ + "$VTK_TAGFILE_REMOTE_DIR/$VTK_TAGFILE.gz" \ + -O "$VTK_TAGFILE_DEST_DIR/$VTK_TAGFILE.gz" + if test "x$GZIP_PROG" != "xNOTFOUND" ; then + $GZIP_PROG -f -d "$VTK_TAGFILE_DEST_DIR/$VTK_TAGFILE.gz" + fi + fi + fi +fi + +# ---------------------------------------------------------------------------- +# Create the Doxygen doc. + +if test "x$DOXYGEN_PROG" != "xNOTFOUND" ; then + + if test "x$RM_PROG" != "xNOTFOUND" ; then + $RM_PROG -fr "$OUTPUT_DIRECTORY" + fi + + $DOXYGEN_PROG "$DOXYFILE" || echoexit "Problem running doxygen" +fi + +# ---------------------------------------------------------------------------- +# Clean the HTML pages to remove the path to the intermediate Doxygen dir. + +if test "x$PERL_PROG" != "xNOTFOUND" ; then + $PERL_PROG "$PATH_TO_VTK_DOX_SCRIPTS/doc_rmpath.pl" \ + --to "$INTERMEDIATE_DOX_DIR" \ + --html "$OUTPUT_DIRECTORY/html" || echoexit "Problem cleaning HTML pages" +fi + +# ---------------------------------------------------------------------------- +# Create the CHM HTML HELP doc. + +if test "x$COMPILE_HTML_HELP" == "xON" ; then + if test "x$RESULTING_HTML_HELP_FILE" != "x" ; then + cd "$OUTPUT_DIRECTORY/html" + if test "x$HHC_PROG" != "xNOTFOUND" ; then + $HHC_PROG index.hhp || echoexit "Problem generating CHM" + if test "x$MV_PROG" != "xNOTFOUND" ; then + $MV_PROG -f index.chm "$RESULTING_HTML_HELP_FILE" + fi + fi + fi +fi + +# ---------------------------------------------------------------------------- +# Create the compressed tar archive. + +if test "x$CREATE_HTML_TARZ_ARCHIVE" == "xON" ; then + if test "x$RESULTING_HTML_TARZ_ARCHIVE_FILE" != "x" ; then + cd "$OUTPUT_DIRECTORY" + if test "x$TAR_PROG" != "xNOTFOUND" ; then + if test "x$RM_PROG" != "xNOTFOUND" ; then + $RM_PROG -f html.tar + fi + $TAR_PROG -cf html.tar html + if test "x$GZIP_PROG" != "xNOTFOUND" ; then + if test "x$RM_PROG" != "xNOTFOUND" ; then + $RM_PROG -f html.tar.gz + fi + $GZIP_PROG html.tar + $MV_PROG -f html.tar.gz "$RESULTING_HTML_TARZ_ARCHIVE_FILE" + fi + fi + fi +fi + +# ---------------------------------------------------------------------------- +# Let's overwrite any *vtk* file produce by our custom vtk/doxygen tool +# on top of the existing doxygen one. + +if test "x$CP_PROG" != "xNOTFOUND" ; then + $CP_PROG "$OUTPUT_DIRECTORY/html/"*vtk* "$PATH_TO_VTKGDCM_FINAL_PATH" +fi + +# ---------------------------------------------------------------------------- +# Clean-up. + +if test "x$RM_PROG" != "xNOTFOUND" ; then + $RM_PROG -fr "$INTERMEDIATE_DOX_DIR" + + if test "x$DOWNLOAD_VTK_TAGFILE" == "xON" ; then + if test "x$VTK_TAGFILE" != "x" ; then + $RM_PROG -f "$VTK_TAGFILE_DEST_DIR/$VTK_TAGFILE" + fi + fi + + if test "x$COMPILE_HTML_HELP" == "xON" ; then + if test "x$RESULTING_HTML_HELP_FILE" != "x" ; then + if test "x$ALLOW_ERASE_OUTPUT_DIRECTORY" == "xON" ; then + $RM_PROG -fr "$OUTPUT_DIRECTORY" + fi + fi + fi +fi diff --git a/gdcm/Utilities/doxygen/vtk/doxyfile.in b/gdcm/Utilities/doxygen/vtk/doxyfile.in new file mode 100644 index 0000000..20c47da --- /dev/null +++ b/gdcm/Utilities/doxygen/vtk/doxyfile.in @@ -0,0 +1,157 @@ +# ------------------------------------------------------------------------- +# doxyfile for generic project +# modified by S. Barre (Time-stamp: <2005-11-07 11:45:05 barre> +# ------------------------------------------------------------------------- + +PROJECT_NAME = @DOXYGEN_PROJECT_NAME@ + +FULL_PATH_NAMES = YES +WARN_IF_UNDOCUMENTED = NO + +GENERATE_TREEVIEW = NO +GENERATE_TODOLIST = YES +GENERATE_BUGLIST = YES +GENERATE_HTML = YES +GENERATE_HTMLHELP = YES +GENERATE_LATEX = NO +GENERATE_MAN = NO +GENERATE_RTF = NO +GENERATE_TAGFILE = "@CMAKE_CURRENT_BINARY_DIR@/@DOXYGEN_PROJECT_NAME@.tag" + +PDF_HYPERLINKS = YES + +HAVE_DOT = YES +#HAVE_DOT = NO +DOT_PATH = "@DOT_PATH@" +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +TEMPLATE_RELATIONS = YES +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CLASS_DIAGRAMS = YES +GENERATE_LEGEND = YES +GRAPHICAL_HIERARCHY = NO # would be too large for vtkObject + +ALLEXTERNALS = NO + +IMAGE_PATH = "@CMAKE_CURRENT_SOURCE_DIR@" + +OUTPUT_DIRECTORY = "@CMAKE_CURRENT_BINARY_DIR@/doc" + +INPUT = \ + "@CMAKE_CURRENT_BINARY_DIR@/dox/doc_@DOXYGEN_PROJECT_NAME@_index.dox" \ + @DOXYGEN_PARSED_INPUT_DIRS@ + +#TAGFILES = "@CMAKE_CURRENT_BINARY_DIR@/vtkNightlyDoc.tag=http://www.vtk.org/doc/nightly/html" +TAGFILES = @TAGFILES@ + +EXTRACT_ALL = YES +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = YES +EXTRACT_LOCAL_CLASSES = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = YES +ALWAYS_DETAILED_SEC = NO +SOURCE_BROWSER = YES +INLINE_SOURCES = NO +CASE_SENSE_NAMES = YES +VERBATIM_HEADERS = NO +SHOW_INCLUDE_FILES = YES +JAVADOC_AUTOBRIEF = YES +SORT_MEMBER_DOCS = NO +DISTRIBUTE_GROUP_DOC = YES +TAB_SIZE = 3 +DETAILS_AT_TOP = YES +SHORT_NAMES = @DOXYGEN_SHORT_NAMES@ +# PAPER_TYPE = letter + +FILE_PATTERNS = *.h +RECURSIVE = NO +EXCLUDE = Common/vtkSetGet.h +EXCLUDE_PATTERNS = + +HTML_ALIGN_MEMBERS = YES +ALPHABETICAL_INDEX = YES +COLS_IN_ALPHA_INDEX = 3 +IGNORE_PREFIX = @DOXYGEN_IGNORE_PREFIX@ + +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = YES +SEARCH_INCLUDES = YES +INCLUDE_PATH = +EXPAND_ONLY_PREDEF = YES +PREDEFINED = "vtkSetMacro(name,type)= \ + virtual void Set##name (type);" \ + "vtkGetMacro(name,type)= \ + virtual type Get##name ();" \ + "vtkSetStringMacro(name)= \ + virtual void Set##name (const char*);" \ + "vtkGetStringMacro(name)= \ + virtual char* Get##name ();" \ + "vtkSetClampMacro(name,type,min,max)= \ + virtual void Set##name (type);" \ + "vtkSetObjectMacro(name,type)= \ + virtual void Set##name (type*);" \ + "vtkGetObjectMacro(name,type)= \ + virtual type *Get##name ();" \ + "vtkBooleanMacro(name,type)= \ + virtual void name##On (); \ + virtual void name##Off ();" \ + "vtkSetVector2Macro(name,type)= \ + virtual void Set##name (type, type); \ + void Set##name (type [2]);" \ + "vtkGetVector2Macro(name,type)= \ + virtual type *Get##name (); \ + virtual void Get##name (type &, type &); \ + virtual void Get##name (type [2]);" \ + "vtkSetVector3Macro(name,type)= \ + virtual void Set##name (type, type, type); \ + virtual void Set##name (type [3]);" \ + "vtkGetVector3Macro(name,type)= \ + virtual type *Get##name (); \ + virtual void Get##name (type &, type &, type &); \ + virtual void Get##name (type [3]);" \ + "vtkSetVector4Macro(name,type)= \ + virtual void Set##name (type, type, type, type); \ + virtual void Set##name (type [4]);" \ + "vtkGetVector4Macro(name,type)= \ + virtual type *Get##name (); \ + virtual void Get##name (type &, type &, type &, type &); \ + virtual void Get##name (type [4]);" \ + "vtkSetVector6Macro(name,type)= \ + virtual void Set##name (type, type, type, type, \ + type, type); \ + virtual void Set##name (type [6]);" \ + "vtkGetVector6Macro(name,type)= \ + virtual type *Get##name (); \ + virtual void Get##name (type &, type &, type &, \ + type &, type &, type &); \ + virtual void Get##name (type [6]);" \ + "vtkSetVectorMacro(name,type,count)= \ + virtual void Set##name(type data[]);" \ + "vtkGetVectorMacro(name,type,count)= \ + virtual type *Get##name (); \ + virtual void Get##name(type data[##count]);" \ + "vtkWorldCoordinateMacro(name)= \ + virtual vtkCoordinate *Get##name##Coordinate (); \ + virtual void Set##name(float x[3]); \ + virtual void Set##name(float x, float y, float z); \ + virtual float *Get##name();" \ + "vtkViewportCoordinateMacro(name)= \ + virtual vtkCoordinate *Get##name##Coordinate (); \ + virtual void Set##name(float x[2]); \ + virtual void Set##name(float x, float y); \ + virtual float *Get##name();" \ + "vtkTypeMacro(thisClass,superclass)= \ + typedef superclass Superclass; \ + virtual const char *GetClassName(); \ + static int IsTypeOf(const char *type); \ + virtual int IsA(const char *type); \ + static thisClass* SafeDownCast(vtkObject *o);" \ + "vtkTypeRevisionMacro(thisClass,superclass)= \ + typedef superclass Superclass; \ + virtual const char *GetClassName(); \ + static int IsTypeOf(const char *type); \ + virtual int IsA(const char *type); \ + static thisClass* SafeDownCast(vtkObject *o);" \ + "VTK_LEGACY(x)= x" diff --git a/gdcm/Utilities/gdcm_charls.h b/gdcm/Utilities/gdcm_charls.h new file mode 100644 index 0000000..c8f2c54 --- /dev/null +++ b/gdcm/Utilities/gdcm_charls.h @@ -0,0 +1,39 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCM_CHARLS_H +#define GDCM_CHARLS_H + +/* Use the charls library configured for gdcm. */ +#include "gdcmTypes.h" +#ifdef GDCM_USE_SYSTEM_CHARLS +// It is expected that 1.0 API is used (JlsParameters instead of JlsParamaters) +# include +# include +# include +# include +# include +# include +# include +#else +#include "gdcmcharls/header.h" +#include "gdcmcharls/interface.h" +#include "gdcmcharls/util.h" +#include "gdcmcharls/defaulttraits.h" +#include "gdcmcharls/losslesstraits.h" +#include "gdcmcharls/colortransform.h" +#include "gdcmcharls/streams.h" +#include "gdcmcharls/processline.h" +#endif + +#endif diff --git a/gdcm/Utilities/gdcm_expat.h b/gdcm/Utilities/gdcm_expat.h new file mode 100644 index 0000000..8d23e18 --- /dev/null +++ b/gdcm/Utilities/gdcm_expat.h @@ -0,0 +1,25 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCM_EXPAT_H +#define GDCM_EXPAT_H + +/* Use the expat library configured for gdcm. */ +#include "gdcmTypes.h" +#ifdef GDCM_USE_SYSTEM_EXPAT +# include +#else +# include +#endif + +#endif diff --git a/gdcm/Utilities/gdcm_ljpeg12.h b/gdcm/Utilities/gdcm_ljpeg12.h new file mode 100644 index 0000000..5703ce2 --- /dev/null +++ b/gdcm/Utilities/gdcm_ljpeg12.h @@ -0,0 +1,34 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCM_LJPEG12_H +#define GDCM_LJPEG12_H + +/* Use the ljpeg library configured for gdcm. */ +#include "gdcmTypes.h" + +#ifdef GDCM_USE_SYSTEM_LJPEG +extern "C" { +# include +# include +# include +} +#else +extern "C" { +#include "gdcmjpeg/12/jinclude.h" +#include "gdcmjpeg/12/jpeglib.h" +#include "gdcmjpeg/12/jerror.h" +} +#endif + +#endif diff --git a/gdcm/Utilities/gdcm_ljpeg16.h b/gdcm/Utilities/gdcm_ljpeg16.h new file mode 100644 index 0000000..1db5fd6 --- /dev/null +++ b/gdcm/Utilities/gdcm_ljpeg16.h @@ -0,0 +1,34 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCM_LJPEG16_H +#define GDCM_LJPEG16_H + +/* Use the ljpeg library configured for gdcm. */ +#include "gdcmTypes.h" + +#ifdef GDCM_USE_SYSTEM_LJPEG +extern "C" { +# include +# include +# include +} +#else +extern "C" { +#include "gdcmjpeg/16/jinclude.h" +#include "gdcmjpeg/16/jpeglib.h" +#include "gdcmjpeg/16/jerror.h" +} +#endif + +#endif diff --git a/gdcm/Utilities/gdcm_ljpeg8.h b/gdcm/Utilities/gdcm_ljpeg8.h new file mode 100644 index 0000000..2810f0f --- /dev/null +++ b/gdcm/Utilities/gdcm_ljpeg8.h @@ -0,0 +1,34 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCM_LJPEG8_H +#define GDCM_LJPEG8_H + +/* Use the ljpeg library configured for gdcm. */ +#include "gdcmTypes.h" + +#ifdef GDCM_USE_SYSTEM_LJPEG +extern "C" { +# include +# include +# include +} +#else +extern "C" { +#include "gdcmjpeg/8/jinclude.h" +#include "gdcmjpeg/8/jpeglib.h" +#include "gdcmjpeg/8/jerror.h" +} +#endif + +#endif diff --git a/gdcm/Utilities/gdcm_md5.h b/gdcm/Utilities/gdcm_md5.h new file mode 100644 index 0000000..0f15f88 --- /dev/null +++ b/gdcm/Utilities/gdcm_md5.h @@ -0,0 +1,25 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCM_MD5_H +#define GDCM_MD5_H + +/* Use the md5 library configured for gdcm. */ +#include "gdcmTypes.h" +#ifdef GDCM_USE_SYSTEM_MD5 +# include +#else +# include +#endif + +#endif diff --git a/gdcm/Utilities/gdcm_openjpeg.h b/gdcm/Utilities/gdcm_openjpeg.h new file mode 100644 index 0000000..4c96910 --- /dev/null +++ b/gdcm/Utilities/gdcm_openjpeg.h @@ -0,0 +1,41 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCM_OPENJPEG_H +#define GDCM_OPENJPEG_H + +/* Use the openjpeg library configured for gdcm. */ +#include "gdcmTypes.h" +#ifdef GDCM_USE_SYSTEM_OPENJPEG +#include +// MM: +// See openjpeg issue #3: +// http://code.google.com/p/openjpeg/issues/detail?id=3 +//#include +//#include + +// Instead duplicate header (I know this is bad) +extern "C" { +#include "gdcm_j2k.h" +#include "gdcm_jp2.h" +} + +#else +extern "C" { +#include +#include +#include +} +#endif + +#endif diff --git a/gdcm/Utilities/gdcm_openjpeg2.h b/gdcm/Utilities/gdcm_openjpeg2.h new file mode 100644 index 0000000..79830dc --- /dev/null +++ b/gdcm/Utilities/gdcm_openjpeg2.h @@ -0,0 +1,41 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCM_OPENJPEG2_H +#define GDCM_OPENJPEG2_H + +/* Use the openjpeg library configured for gdcm. */ +#include "gdcmTypes.h" +#ifdef GDCM_USE_SYSTEM_OPENJPEG +#include +// MM: +// See openjpeg issue #3: +// http://code.google.com/p/openjpeg/issues/detail?id=3 +//#include +//#include + +// Instead duplicate header (I know this is bad) +extern "C" { +//#include "gdcm_j2k.h" +//#include "gdcm_jp2.h" +} + +#else +extern "C" { +#include +#include +#include +} +#endif + +#endif diff --git a/gdcm/Utilities/gdcm_uuid.h b/gdcm/Utilities/gdcm_uuid.h new file mode 100644 index 0000000..053c967 --- /dev/null +++ b/gdcm/Utilities/gdcm_uuid.h @@ -0,0 +1,25 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCM_UUID_H +#define GDCM_UUID_H + +/* Use the uuid library configured for gdcm. */ +#include "gdcmTypes.h" +#ifdef GDCM_USE_SYSTEM_UUID +# include +#else +# include +#endif + +#endif diff --git a/gdcm/Utilities/gdcm_zlib.h b/gdcm/Utilities/gdcm_zlib.h new file mode 100644 index 0000000..8cd617b --- /dev/null +++ b/gdcm/Utilities/gdcm_zlib.h @@ -0,0 +1,27 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCM_ZLIB_H +#define GDCM_ZLIB_H + +/* Use the zlib library configured for gdcm. */ +#include "gdcmTypes.h" +#ifdef GDCM_USE_SYSTEM_ZLIB +// $ dpkg -S /usr/include/zlib.h +// zlib1g-dev: /usr/include/zlib.h +# include +#else +# include +#endif + +#endif diff --git a/gdcm/Utilities/gdcmcharls/.NoDartCoverage b/gdcm/Utilities/gdcmcharls/.NoDartCoverage new file mode 100644 index 0000000..3c99729 --- /dev/null +++ b/gdcm/Utilities/gdcmcharls/.NoDartCoverage @@ -0,0 +1 @@ +# do not do coverage in this directory diff --git a/gdcm/Utilities/gdcmcharls/CMakeLists.txt b/gdcm/Utilities/gdcmcharls/CMakeLists.txt new file mode 100644 index 0000000..0cb9b5a --- /dev/null +++ b/gdcm/Utilities/gdcmcharls/CMakeLists.txt @@ -0,0 +1,92 @@ +cmake_minimum_required(VERSION 2.8.9) + +if(NOT CHARLS_NAMESPACE) + set(CHARLS_NAMESPACE "CHARLS") + set(CHARLS_STANDALONE 1) +endif() +# In all cases: +string(TOLOWER ${CHARLS_NAMESPACE} CHARLS_LIBRARY_NAME) + +project(${CHARLS_NAMESPACE} CXX) + +#----------------------------------------------------------------------------- +# CHARLS version number +set(CHARLS_MAJOR_VERSION 1) +set(CHARLS_MINOR_VERSION 0) +set(CHARLS_BUILD_VERSION 0) +set(CHARLS_VERSION + "${CHARLS_MAJOR_VERSION}.${CHARLS_MINOR_VERSION}.${CHARLS_BUILD_VERSION}") + +#----------------------------------------------------------------------------- +#set (EXECUTABLE_OUTPUT_PATH ${CHARLS_BINARY_DIR}/bin CACHE PATH "Single output directory for building all executables.") +#set (LIBRARY_OUTPUT_PATH ${CHARLS_BINARY_DIR}/bin CACHE PATH "Single output directory for building all libraries.") +#mark_as_advanced(LIBRARY_OUTPUT_PATH EXECUTABLE_OUTPUT_PATH) + +if(NOT CHARLS_INSTALL_BIN_DIR) + set(CHARLS_INSTALL_BIN_DIR "bin") +endif() +if(NOT CHARLS_INSTALL_LIB_DIR) + set(CHARLS_INSTALL_LIB_DIR "lib") +endif() +if(NOT CHARLS_INSTALL_INCLUDE_DIR) + set(CHARLS_INSTALL_INCLUDE_DIR "include") +endif() + +#set(MANGLE_PREFIX ${JPEGLS_LIBRARY_NAME}) +#configure_file(${CMAKE_CURRENT_SOURCE_DIR}/jpegls_mangle.h.in +# ${CMAKE_CURRENT_BINARY_DIR}/jpegls_mangle.h +# @ONLY ) + + + +# When user specify build type do not override settings: +if(NOT CMAKE_BUILD_TYPE) + # The following compiler option are only meant for GCC: + if(CMAKE_COMPILER_IS_GNUCC) + #set(CMAKE_CXX_FLAGS "-Wall -O3 -g" ) + endif() +endif() + +#option(charls_BUILD_SHARED_LIBS "Build CharLS with shared libraries." OFF) +#set(BUILD_SHARED_LIBS ${charls_BUILD_SHARED_LIBS}) + +if(WIN32) + if(BUILD_SHARED_LIBS) + add_definitions(-DCHARLS_SHARED) + endif() +endif() + +add_library(${CHARLS_LIBRARY_NAME} header.cpp interface.cpp jpegls.cpp + stdafx.cpp + ) +set_target_properties(${CHARLS_LIBRARY_NAME} PROPERTIES ${GDCM_LIBRARY_PROPERTIES} LINK_INTERFACE_LIBRARIES "") + +# Install library +if(NOT CHARLS_INSTALL_NO_LIBRARIES) + # Runtime + install(TARGETS ${CHARLS_LIBRARY_NAME} + EXPORT ${GDCM_TARGETS_NAME} + RUNTIME DESTINATION ${CHARLS_INSTALL_BIN_DIR} COMPONENT Applications + LIBRARY DESTINATION ${CHARLS_INSTALL_LIB_DIR} COMPONENT Libraries ${NAMELINK_SKIP} + ARCHIVE DESTINATION ${CHARLS_INSTALL_LIB_DIR} COMPONENT DebugDevel + ) + #Development + if(NAMELINK_ONLY) + install(TARGETS ${CHARLS_LIBRARY_NAME} + EXPORT ${GDCM_TARGETS_NAME} + LIBRARY DESTINATION ${CHARLS_INSTALL_LIB_DIR} COMPONENT DebugDevel ${NAMELINK_ONLY} + ) + endif() +endif() + +if(NOT CHARLS_INSTALL_NO_DEVELOPMENT) + file(GLOB header_files "*.h") + install(FILES ${header_files} + DESTINATION ${CHARLS_INSTALL_INCLUDE_DIR} COMPONENT Headers + ) +endif() +#add_executable(charlstest test/test.cpp test/time.cpp) +#target_link_libraries (charlstest CharLS) + +#include(CTest) +#add_test(charlstest charlstest) diff --git a/gdcm/Utilities/gdcmcharls/License.txt b/gdcm/Utilities/gdcmcharls/License.txt new file mode 100644 index 0000000..6b7036e --- /dev/null +++ b/gdcm/Utilities/gdcmcharls/License.txt @@ -0,0 +1,27 @@ +Copyright (c) 2007-2010, Jan de Vaan +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of my employer, nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/gdcm/Utilities/gdcmcharls/README.GDCM.txt b/gdcm/Utilities/gdcmcharls/README.GDCM.txt new file mode 100644 index 0000000..5226fda --- /dev/null +++ b/gdcm/Utilities/gdcmcharls/README.GDCM.txt @@ -0,0 +1,28 @@ +This directory contains a subset of the CharLS project (http://charls.codeplex.com/) + +It was retrieved on Wed Sep 23 18:30:14 CEST 2009 +URL: +http://charls.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=32643 +This is the 1.0 Beta Release + +Project Description +An optimized implementation of the JPEG-LS standard for lossless and near-lossless image compression. JPEG-LS is a low-complexity standard that matches JPEG 2000 compression ratios. In terms of speed, CharLS outperforms open source and commercial JPEG LS implementations. + +About JPEG-LS +JPEG-LS (ISO-14495-1/ITU-T.87) is a standard derived from the Hewlett Packard LOCO algorithm. JPEG LS has low complexity (meaning fast compression) and high compression ratios, similar to JPEG 2000. JPEG-LS is more similar to the old Lossless JPEG than to JPEG 2000, but interestingly the two different techniques result in vastly different performance characteristics. +Wikipedia on lossless JPEG and JPEG-LS: http://en.wikipedia.org/wiki/Lossless_JPEG + +Legal +The code in this project is available through a BSD style license, allowing use of the code in commercial closed source applications if you wish. All the code in this project is written from scratch, and not based on other JPEG-LS implementations. + + +We only include enough of distribution to build the charls library. + + +Modifications +------------- + +- remove tests/* subdirs +- remove *.vcproj/*.sln M$ Visual Studio specific files (use cmake in all cases) +- apply dos2unix to all files +- remove trailing comma (,) in enum {} diff --git a/gdcm/Utilities/gdcmcharls/colortransform.h b/gdcm/Utilities/gdcmcharls/colortransform.h new file mode 100644 index 0000000..548e993 --- /dev/null +++ b/gdcm/Utilities/gdcmcharls/colortransform.h @@ -0,0 +1,180 @@ +// +// (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. +// +#ifndef CHARLS_COLORTRANSFORM +#define CHARLS_COLORTRANSFORM + +// +// This file defines simple classes that define (lossless) color transforms. +// They are invoked in processline.h to convert between decoded values and the internal line buffers. +// Color transforms work best for computer generated images. +// + +template +struct TransformNoneImpl +{ + typedef sample SAMPLE; + + inlinehint Triplet operator() (int v1, int v2, int v3) + { return Triplet(v1, v2, v3); } +}; + + +template +struct TransformNone : public TransformNoneImpl +{ + typedef struct TransformNoneImpl INVERSE; +}; + + + +template +struct TransformHp1 +{ + enum { RANGE = 1 << sizeof(sample)*8 }; + typedef sample SAMPLE; + + struct INVERSE + { + INVERSE(const TransformHp1&) {}; + + inlinehint Triplet operator() (int v1, int v2, int v3) + { return Triplet(v1 + v2 - RANGE/2, v2, v3 + v2 - RANGE/2); } + }; + + inlinehint Triplet operator() (int R, int G, int B) + { + Triplet hp1; + hp1.v2 = SAMPLE(G); + hp1.v1 = SAMPLE(R - G + RANGE/2); + hp1.v3 = SAMPLE(B - G + RANGE/2); + return hp1; + } +}; + + + + + +template +struct TransformHp2 +{ + enum { RANGE = 1 << sizeof(sample)*8 }; + typedef sample SAMPLE; + + struct INVERSE + { + INVERSE(const TransformHp2&) {}; + + inlinehint Triplet operator() (int v1, int v2, int v3) + { + Triplet rgb; + rgb.R = SAMPLE(v1 + v2 - RANGE/2); // new R + rgb.G = SAMPLE(v2); // new G + rgb.B = SAMPLE(v3 + ((rgb.R + rgb.G) >> 1) - RANGE/2); // new B + return rgb; + } + }; + + inlinehint Triplet operator() (int R, int G, int B) + { + return Triplet(R - G + RANGE/2, G, B - ((R+G )>>1) - RANGE/2); + } + + +}; + + + +template +struct TransformHp3 +{ + enum { RANGE = 1 << sizeof(sample)*8 }; + typedef sample SAMPLE; + + struct INVERSE + { + INVERSE(const TransformHp3&) {}; + + inlinehint Triplet operator() (int v1, int v2, int v3) + { + int G = v1 - ((v3 + v2)>>2) + RANGE/4; + Triplet rgb; + rgb.R = SAMPLE(v3 + G - RANGE/2); // new R + rgb.G = SAMPLE(G); // new G + rgb.B = SAMPLE(v2 + G - RANGE/2); // new B + return rgb; + } + }; + + inlinehint Triplet operator() (int R, int G, int B) + { + Triplet hp3; + hp3.v2 = SAMPLE(B - G + RANGE/2); + hp3.v3 = SAMPLE(R - G + RANGE/2); + hp3.v1 = SAMPLE(G + ((hp3.v2 + hp3.v3)>>2)) - RANGE/4; + return hp3; + } +}; + + +// Transform class that shifts bits towards the high bit when bitcount is not 8 or 16 +// needed to make the HP color transforms work correctly. + +template +struct TransformShifted +{ + typedef typename TRANSFORM::SAMPLE SAMPLE; + + struct INVERSE + { + INVERSE(const TransformShifted& transform) : + _shift(transform._shift), + _inverseTransform(transform._colortransform) + {} + + inlinehint Triplet operator() (int v1, int v2, int v3) + { + Triplet result = _inverseTransform(v1 << _shift, v2 << _shift, v3 << _shift); + + return Triplet(result.R >> _shift, result.G >> _shift, result.B >> _shift); + } + + inlinehint Quad operator() (int v1, int v2, int v3, int v4) + { + Triplet result = _inverseTransform(v1 << _shift, v2 << _shift, v3 << _shift); + + return Quad(result.R >> _shift, result.G >> _shift, result.B >> _shift, v4); + } + + int _shift; + typename TRANSFORM::INVERSE _inverseTransform; + }; + + + TransformShifted(int shift) : + _shift(shift) + { + } + + inlinehint Triplet operator() (int R, int G, int B) + { + Triplet result = _colortransform(R << _shift, G << _shift, B << _shift); + + return Triplet(result.R >> _shift, result.G >> _shift, result.B >> _shift); + } + + inlinehint Quad operator() (int R, int G, int B, int A) + { + Triplet result = _colortransform(R << _shift, G << _shift, B << _shift); + + return Quad(result.R >> _shift, result.G >> _shift, result.B >> _shift, A); + } + + int _shift; + TRANSFORM _colortransform; +}; + + + +#endif diff --git a/gdcm/Utilities/gdcmcharls/config.h b/gdcm/Utilities/gdcmcharls/config.h new file mode 100644 index 0000000..ce7b42b --- /dev/null +++ b/gdcm/Utilities/gdcmcharls/config.h @@ -0,0 +1,66 @@ +// +// (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. +// + + +#ifndef CHARLS_CONFIG +#define CHARLS_CONFIG + +#ifdef NDEBUG +# ifndef ASSERT +# define ASSERT(t) { } +# endif +#else +#include +#define ASSERT(t) assert(t) +#endif + +#if defined(_WIN32) +#ifdef _MSC_VER +#pragma warning (disable:4512) +#endif + +#endif + +#ifdef __GNUC__ +#include +#else +typedef long long int64_t; +typedef unsigned long long uint64_t; +#endif + +// Typedef used by Charls for the default integral type. +// charls will work correctly with 64 or 32 bit. +typedef long LONG; + +enum constants +{ + LONG_BITCOUNT = sizeof(LONG)*8 +}; + + +typedef unsigned char BYTE; +typedef unsigned short USHORT; + +#undef NEAR + +#ifndef inlinehint +# ifdef _MSC_VER +# ifdef NDEBUG +# define inlinehint __forceinline +# else +# define inlinehint +# endif +# elif defined(__GNUC__) && (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ > 0) +# define inlinehint inline +# else +# define inlinehint inline +# endif +#endif + +#if defined(i386) || defined(__i386__) || defined(_M_IX86) || defined(__amd64__) || defined(_M_X64) +#define ARCH_HAS_UNALIGNED_MEM_ACCESS /* TODO define this symbol for more architectures */ +#endif + +#endif + diff --git a/gdcm/Utilities/gdcmcharls/context.h b/gdcm/Utilities/gdcmcharls/context.h new file mode 100644 index 0000000..dd797e7 --- /dev/null +++ b/gdcm/Utilities/gdcmcharls/context.h @@ -0,0 +1,122 @@ +// +// (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. +// + + +#ifndef CHARLS_CONTEXT +#define CHARLS_CONTEXT + + +// +// JlsContext: a JPEG-LS context with it's current statistics. +// +struct JlsContext +{ +public: + JlsContext() + {} + + JlsContext(LONG a) : + A(a), + B(0), + C(0), + N(1) + { + } + + LONG A; + LONG B; + short C; + short N; + + inlinehint LONG GetErrorCorrection(LONG k) const + { + if (k != 0) + return 0; + + return BitWiseSign(2 * B + N - 1); + } + + + inlinehint void UpdateVariables(LONG errorValue, LONG NEAR, LONG NRESET) + { + ASSERT(N != 0); + + // For performance work on copies of A,B,N (compiler will use registers). + int b = B + errorValue * (2 * NEAR + 1); + int a = A + abs(errorValue); + int n = N; + + ASSERT(a < 65536 * 256); + ASSERT(abs(b) < 65536 * 256); + + if (n == NRESET) + { + a = a >> 1; + b = b >> 1; + n = n >> 1; + } + + n = n + 1; + + if (b + n <= 0) + { + b = b + n; + if (b <= -n) + { + b = -n + 1; + } + C = _tableC[C - 1]; + } + else if (b > 0) + { + b = b - n; + if (b > 0) + { + b = 0; + } + C = _tableC[C + 1]; + } + A = a; + B = b; + N = (short)n; + ASSERT(N != 0); + } + + + + inlinehint LONG GetGolomb() const + { + LONG Ntest = N; + LONG Atest = A; + LONG k = 0; + for(; (Ntest << k) < Atest; k++) + { + ASSERT(k <= 32); + }; + return k; + } + + static signed char* CreateTableC() + { + static std::vector rgtableC; + + rgtableC.reserve(256 + 2); + + rgtableC.push_back(-128); + for (int i = -128; i < 128; i++) + { + rgtableC.push_back(char(i)); + } + rgtableC.push_back(127); + + signed char* pZero = &rgtableC[128 + 1]; + ASSERT(pZero[0] == 0); + return pZero; + } +private: + + static signed char* _tableC; +}; + +#endif diff --git a/gdcm/Utilities/gdcmcharls/contextrunmode.h b/gdcm/Utilities/gdcmcharls/contextrunmode.h new file mode 100644 index 0000000..0eac1e0 --- /dev/null +++ b/gdcm/Utilities/gdcmcharls/contextrunmode.h @@ -0,0 +1,101 @@ +// +// (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. +// + + +#ifndef CHARLS_CONTEXTRUNMODE +#define CHARLS_CONTEXTRUNMODE + +// Implements statistical modelling for the run mode context. +// Computes model dependent parameters like the golomb code lengths + +struct CContextRunMode +{ + CContextRunMode(LONG a, LONG nRItype, LONG nReset) : + A(a), + N(1), + Nn(0), + _nRItype(nRItype), + _nReset((BYTE)nReset) + { + } + + LONG A; + BYTE N; + BYTE Nn; + LONG _nRItype; + BYTE _nReset; + + CContextRunMode() + {} + + + inlinehint LONG GetGolomb() const + { + LONG Ntest = N; + LONG TEMP = A + (N >> 1) * _nRItype; + LONG k = 0; + for(; Ntest < TEMP; k++) + { + Ntest <<= 1; + ASSERT(k <= 32); + }; + return k; + } + + + void UpdateVariables(LONG Errval, LONG EMErrval) + { + if (Errval < 0) + { + Nn = Nn + 1; + } + A = A + ((EMErrval + 1 - _nRItype) >> 1); + if (N == _nReset) + { + A = A >> 1; + N = N >> 1; + Nn = Nn >> 1; + } + N = N + 1; + } + + inlinehint LONG ComputeErrVal(LONG temp, LONG k) + { + bool map = temp & 1; + + LONG errvalabs = (temp + map) / 2; + + if ((k != 0 || (2 * Nn >= N)) == map) + { + ASSERT(map == ComputeMap(-errvalabs, k)); + return -errvalabs; + } + + ASSERT(map == ComputeMap(errvalabs, k)); + return errvalabs; + } + + + bool ComputeMap(LONG Errval, LONG k) const + { + if ((k == 0) && (Errval > 0) && (2 * Nn < N)) + return 1; + + else if ((Errval < 0) && (2 * Nn >= N)) + return 1; + + else if ((Errval < 0) && (k != 0)) + return 1; + + return 0; + } + + + inlinehint LONG ComputeMapNegativeE(LONG k) const + { + return k != 0 || (2 * Nn >= N ); + } +}; + +#endif diff --git a/gdcm/Utilities/gdcmcharls/decoderstrategy.h b/gdcm/Utilities/gdcmcharls/decoderstrategy.h new file mode 100644 index 0000000..0481782 --- /dev/null +++ b/gdcm/Utilities/gdcmcharls/decoderstrategy.h @@ -0,0 +1,285 @@ +// +// (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. +// + +#ifndef CHARLS_DECODERSTATEGY +#define CHARLS_DECODERSTATEGY + +#include "streams.h" +#include "processline.h" +#include "config.h" +#include "util.h" + +// Implements encoding to stream of bits. In encoding mode JpegLsCodec inherits from EncoderStrategy + + + +class DecoderStrategy +{ +public: + DecoderStrategy(const JlsParameters& info) : + _info(info), + _processLine(0), + _readCache(0), + _validBits(0), + _position(0) + { + } + + virtual ~DecoderStrategy() + { + } + + virtual void SetPresets(const JlsCustomParameters& presets) = 0; + virtual size_t DecodeScan(void* outputData, const JlsRect& size, const void* compressedData, size_t byteCount, bool bCheck) = 0; + + void Init(BYTE* compressedBytes, size_t byteCount) + { + _validBits = 0; + _readCache = 0; + _position = compressedBytes; + _endPosition = compressedBytes + byteCount; + _nextFFPosition = FindNextFF(); + MakeValid(); + } + + inlinehint void Skip(LONG length) + { + _validBits -= length; + _readCache = _readCache << length; + } + + + void OnLineBegin(LONG /*cpixel*/, void* /*ptypeBuffer*/, LONG /*pixelStride*/) + {} + + + void OnLineEnd(LONG pixelCount, const void* ptypeBuffer, LONG pixelStride) + { + _processLine->NewLineDecoded(ptypeBuffer, pixelCount, pixelStride); + } + + void EndScan() + { + if ((*_position) != 0xFF) + { + ReadBit(); + + if ((*_position) != 0xFF) + throw JlsException(TooMuchCompressedData); + } + + if (_readCache != 0) + throw JlsException(TooMuchCompressedData); + } + + + inlinehint bool OptimizedRead() + { + // Easy & fast: if there is no 0xFF byte in sight, we can read without bitstuffing + if (_position < _nextFFPosition - (sizeof(bufType)-1)) + { + _readCache |= FromBigEndian::Read(_position) >> _validBits; + int bytesToRead = (bufferbits - _validBits) >> 3; + _position += bytesToRead; + _validBits += bytesToRead * 8; + ASSERT(_validBits >= bufferbits - 8); + return true; + } + return false; + } + + typedef size_t bufType; + + enum { + bufferbits = sizeof( bufType ) * 8 + }; + + void MakeValid() + { + ASSERT(_validBits <=bufferbits - 8); + + if (OptimizedRead()) + return; + + do + { + if (_position >= _endPosition) + { + if (_validBits <= 0) + throw JlsException(InvalidCompressedData); + + return; + } + + bufType valnew = _position[0]; + + if (valnew == 0xFF) + { + // JPEG bitstream rule: no FF may be followed by 0x80 or higher + if (_position == _endPosition - 1 || (_position[1] & 0x80) != 0) + { + if (_validBits <= 0) + throw JlsException(InvalidCompressedData); + + return; + } + } + + _readCache |= valnew << (bufferbits - 8 - _validBits); + _position += 1; + _validBits += 8; + + if (valnew == 0xFF) + { + _validBits--; + } + } + while (_validBits < bufferbits - 8); + + _nextFFPosition = FindNextFF(); + return; + + } + + + BYTE* FindNextFF() + { + BYTE* pbyteNextFF = _position; + + while (pbyteNextFF < _endPosition) + { + if (*pbyteNextFF == 0xFF) + { + break; + } + pbyteNextFF++; + } + + + return pbyteNextFF; + } + + + BYTE* GetCurBytePos() const + { + LONG validBits = _validBits; + BYTE* compressedBytes = _position; + + for (;;) + { + LONG cbitLast = compressedBytes[-1] == 0xFF ? 7 : 8; + + if (validBits < cbitLast ) + return compressedBytes; + + validBits -= cbitLast; + compressedBytes--; + } + } + + + inlinehint LONG ReadValue(LONG length) + { + if (_validBits < length) + { + MakeValid(); + if (_validBits < length) + throw JlsException(InvalidCompressedData); + } + + ASSERT(length != 0 && length <= _validBits); + ASSERT(length < 32); + LONG result = LONG(_readCache >> (bufferbits - length)); + Skip(length); + return result; + } + + + inlinehint LONG PeekByte() + { + if (_validBits < 8) + { + MakeValid(); + } + + return _readCache >> (bufferbits - 8); + } + + + + inlinehint bool ReadBit() + { + if (_validBits <= 0) + { + MakeValid(); + } + + bool bSet = (_readCache & (bufType(1) << (bufferbits - 1))) != 0; + Skip(1); + return bSet; + } + + + + inlinehint LONG Peek0Bits() + { + if (_validBits < 16) + { + MakeValid(); + } + bufType valTest = _readCache; + + for (LONG count = 0; count < 16; count++) + { + if ((valTest & (bufType(1) << (bufferbits - 1))) != 0) + return count; + + valTest <<= 1; + } + return -1; + } + + + + inlinehint LONG ReadHighbits() + { + LONG count = Peek0Bits(); + if (count >= 0) + { + Skip(count + 1); + return count; + } + Skip(15); + + for (LONG highbits = 15; ; highbits++) + { + if (ReadBit()) + return highbits; + } + } + + + LONG ReadLongValue(LONG length) + { + if (length <= 24) + return ReadValue(length); + + return (ReadValue(length - 24) << 24) + ReadValue(24); + } + +protected: + JlsParameters _info; + std::auto_ptr _processLine; + +private: + // decoding + bufType _readCache; + LONG _validBits; + BYTE* _position; + BYTE* _nextFFPosition; + BYTE* _endPosition; +}; + + +#endif diff --git a/gdcm/Utilities/gdcmcharls/defaulttraits.h b/gdcm/Utilities/gdcmcharls/defaulttraits.h new file mode 100644 index 0000000..5032f7d --- /dev/null +++ b/gdcm/Utilities/gdcmcharls/defaulttraits.h @@ -0,0 +1,126 @@ +// +// (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. +// + + +#ifndef CHARLS_DEFAULTTRAITS +#define CHARLS_DEFAULTTRAITS + +// Default traits that support all JPEG LS parameters: custom limit, near, maxval (not power of 2) + +// This traits class is used to initialize a coder/decoder. +// The coder/decoder also delegates some functions to the traits class. +// This is to allow the traits class to replace the default implementation here with optimized specific implementations. +// This is done for lossless coding/decoding: see losslesstraits.h + +template +struct DefaultTraitsT +{ +public: + typedef sample SAMPLE; + typedef pixel PIXEL; + + LONG MAXVAL; + LONG RANGE; + LONG NEAR; + LONG qbpp; + LONG bpp; + LONG LIMIT; + LONG RESET; + + DefaultTraitsT(const DefaultTraitsT& src) : + MAXVAL(src.MAXVAL), + RANGE(src.RANGE), + NEAR(src.NEAR), + qbpp(src.qbpp), + bpp(src.bpp), + LIMIT(src.LIMIT), + RESET(src.RESET) + { + } + + DefaultTraitsT(LONG max, LONG jls_near) + { + NEAR = jls_near; + MAXVAL = max; + RANGE = (MAXVAL + 2 * NEAR )/(2 * NEAR + 1) + 1; + bpp = log_2(max); + LIMIT = 2 * (bpp + MAX(8,bpp)); + qbpp = log_2(RANGE); + RESET = BASIC_RESET; + } + + + inlinehint LONG ComputeErrVal(LONG e) const + { + LONG q = Quantize(e); + return ModRange(q); + } + + inlinehint SAMPLE ComputeReconstructedSample(LONG Px, LONG ErrVal) + { + return FixReconstructedValue(Px + DeQuantize(ErrVal)); + } + + inlinehint bool IsNear(LONG lhs, LONG rhs) const + { return abs(lhs-rhs) <=NEAR; } + + bool IsNear(Triplet lhs, Triplet rhs) const + { + return abs(lhs.v1-rhs.v1) <=NEAR && + abs(lhs.v2-rhs.v2) <=NEAR && + abs(lhs.v3-rhs.v3) <=NEAR; + } + + inlinehint LONG CorrectPrediction(LONG Pxc) const + { + if ((Pxc & MAXVAL) == Pxc) + return Pxc; + + return (~(Pxc >> (LONG_BITCOUNT-1))) & MAXVAL; + } + + inlinehint LONG ModRange(LONG Errval) const + { + ASSERT(abs(Errval) <= RANGE); + if (Errval < 0) + Errval = Errval + RANGE; + + if (Errval >= ((RANGE + 1) / 2)) + Errval = Errval - RANGE; + + ASSERT(abs(Errval) <= RANGE/2); + + return Errval; + } + + +private: + LONG Quantize(LONG Errval) const + { + if (Errval > 0) + return (Errval + NEAR) / (2 * NEAR + 1); + else + return - (NEAR - Errval) / (2 * NEAR + 1); + } + + + inlinehint LONG DeQuantize(LONG Errval) const + { + return Errval * (2 * NEAR + 1); + } + + inlinehint SAMPLE FixReconstructedValue(LONG val) const + { + if (val < -NEAR) + val = val + RANGE*(2*NEAR+1); + else if (val > MAXVAL + NEAR) + val = val - RANGE*(2*NEAR+1); + + return SAMPLE(CorrectPrediction(val)); + } + +}; + + +#endif diff --git a/gdcm/Utilities/gdcmcharls/encoderstrategy.h b/gdcm/Utilities/gdcmcharls/encoderstrategy.h new file mode 100644 index 0000000..f2426db --- /dev/null +++ b/gdcm/Utilities/gdcmcharls/encoderstrategy.h @@ -0,0 +1,161 @@ +// +// (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. +// + +#ifndef CHARLS_ENCODERSTRATEGY +#define CHARLS_ENCODERSTRATEGY + +#include "processline.h" +#include "decoderstrategy.h" + +// Implements encoding to stream of bits. In encoding mode JpegLsCodec inherits from EncoderStrategy + +class EncoderStrategy +{ + +public: + explicit EncoderStrategy(const JlsParameters& info) : + _qdecoder(0), + _info(info), + _processLine(0), + valcurrent(0), + bitpos(0), + _isFFWritten(false), + _bytesWritten(0) + + { + } + + virtual ~EncoderStrategy() + { + } + + LONG PeekByte(); + + void OnLineBegin(LONG cpixel, void* ptypeBuffer, LONG pixelStride) + { + _processLine->NewLineRequested(ptypeBuffer, cpixel, pixelStride); + } + + void OnLineEnd(LONG /*cpixel*/, void* /*ptypeBuffer*/, LONG /*pixelStride*/) { } + + virtual void SetPresets(const JlsCustomParameters& presets) = 0; + + virtual size_t EncodeScan(const void* pvoid, void* pvoidOut, size_t byteCount, void* pvoidCompare) = 0; + +protected: + + void Init(BYTE* compressedBytes, size_t byteCount) + { + bitpos = 32; + valcurrent = 0; + _position = compressedBytes; + _compressedLength = byteCount; + } + + + void AppendToBitStream(LONG value, LONG length) + { + ASSERT(length < 32 && length >= 0); + + ASSERT((_qdecoder.get() == NULL) || (length == 0 && value == 0) ||( _qdecoder->ReadLongValue(length) == value)); + +#ifndef NDEBUG + if (length < 32) + { + int mask = (1 << (length)) - 1; + ASSERT((value | mask) == mask); + } +#endif + + bitpos -= length; + if (bitpos >= 0) + { + valcurrent = valcurrent | (value << bitpos); + return; + } + valcurrent |= value >> -bitpos; + + Flush(); + + ASSERT(bitpos >=0); + valcurrent |= value << bitpos; + + } + + void EndScan() + { + Flush(); + + // if a 0xff was written, Flush() will force one unset bit anyway + if (_isFFWritten) + AppendToBitStream(0, (bitpos - 1) % 8); + else + AppendToBitStream(0, bitpos % 8); + + Flush(); + ASSERT(bitpos == 0x20); + } + + void Flush() + { + for (LONG i = 0; i < 4; ++i) + { + if (bitpos >= 32) + break; + + if (_isFFWritten) + { + // insert highmost bit + *_position = BYTE(valcurrent >> 25); + valcurrent = valcurrent << 7; + bitpos += 7; + _isFFWritten = false; + } + else + { + *_position = BYTE(valcurrent >> 24); + valcurrent = valcurrent << 8; + bitpos += 8; + _isFFWritten = *_position == 0xFF; + } + + _position++; + _compressedLength--; + _bytesWritten++; + + } + + } + + size_t GetLength() + { + return _bytesWritten - (bitpos -32)/8; + } + + + inlinehint void AppendOnesToBitStream(LONG length) + { + AppendToBitStream((1 << length) - 1, length); + } + + + std::auto_ptr _qdecoder; + +protected: + JlsParameters _info; + std::auto_ptr _processLine; +private: + + unsigned int valcurrent; + LONG bitpos; + size_t _compressedLength; + + // encoding + BYTE* _position; + bool _isFFWritten; + size_t _bytesWritten; + +}; + +#endif diff --git a/gdcm/Utilities/gdcmcharls/header.cpp b/gdcm/Utilities/gdcmcharls/header.cpp new file mode 100644 index 0000000..92026a3 --- /dev/null +++ b/gdcm/Utilities/gdcmcharls/header.cpp @@ -0,0 +1,627 @@ +// +// (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. +// + +#include "config.h" +#include "util.h" +#include "header.h" +#include "streams.h" +#include "decoderstrategy.h" +#include "encoderstrategy.h" +#include + + +// JFIF\0 +BYTE jfifID[] = {'J','F','I','F','\0'}; + + +bool IsDefault(const JlsCustomParameters* pcustom) +{ + if (pcustom->MAXVAL != 0) + return false; + + if (pcustom->T1 != 0) + return false; + + if (pcustom->T2 != 0) + return false; + + if (pcustom->T3 != 0) + return false; + + if (pcustom->RESET != 0) + return false; + + return true; +} + + +LONG CLAMP(LONG i, LONG j, LONG MAXVAL) +{ + if (i > MAXVAL || i < j) + return j; + + return i; +} + + +JlsCustomParameters ComputeDefault(LONG MAXVAL, LONG NEAR) +{ + JlsCustomParameters preset = JlsCustomParameters(); + + LONG FACTOR = (MIN(MAXVAL, 4095) + 128)/256; + + preset.T1 = CLAMP(FACTOR * (BASIC_T1 - 2) + 2 + 3*NEAR, NEAR + 1, MAXVAL); + preset.T2 = CLAMP(FACTOR * (BASIC_T2 - 3) + 3 + 5*NEAR, preset.T1, MAXVAL); + preset.T3 = CLAMP(FACTOR * (BASIC_T3 - 4) + 4 + 7*NEAR, preset.T2, MAXVAL); + preset.MAXVAL = MAXVAL; + preset.RESET = BASIC_RESET; + return preset; +} + + +JLS_ERROR CheckParameterCoherent(const JlsParameters* pparams) +{ + if (pparams->bitspersample < 6 || pparams->bitspersample > 16) + return ParameterValueNotSupported; + + if (pparams->ilv < 0 || pparams->ilv > 2) + throw JlsException(InvalidCompressedData); + + if (pparams->bitspersample < 6 || pparams->bitspersample > 16) + return ParameterValueNotSupported; + + switch (pparams->components) + { + case 4: return pparams->ilv == ILV_SAMPLE ? ParameterValueNotSupported : OK; + case 3: return OK; + case 1: return pparams->ilv != ILV_NONE ? ParameterValueNotSupported : OK; + case 0: return InvalidJlsParameters; + + default: return pparams->ilv != ILV_NONE ? ParameterValueNotSupported : OK; + } +} + +// +// JpegMarkerSegment +// +class JpegMarkerSegment : public JpegSegment +{ +public: + JpegMarkerSegment(BYTE marker, std::vector vecbyte) + { + _marker = marker; + std::swap(_vecbyte, vecbyte); + } + + virtual void Write(JLSOutputStream* pstream) + { + pstream->WriteByte(0xFF); + pstream->WriteByte(_marker); + pstream->WriteWord(USHORT(_vecbyte.size() + 2)); + pstream->WriteBytes(_vecbyte); + } + + BYTE _marker; + std::vector _vecbyte; +}; + + +// +// push_back() +// +void push_back(std::vector& vec, USHORT value) +{ + vec.push_back(BYTE(value / 0x100)); + vec.push_back(BYTE(value % 0x100)); +} + + +// +// CreateMarkerStartOfFrame() +// +JpegSegment* CreateMarkerStartOfFrame(Size size, LONG bitsPerSample, LONG ccomp) +{ + + std::vector vec; + vec.push_back(static_cast(bitsPerSample)); + push_back(vec, static_cast(size.cy)); + push_back(vec, static_cast(size.cx)); + + // components + vec.push_back(static_cast(ccomp)); + for (BYTE component = 0; component < ccomp; component++) + { + // rescaling + vec.push_back(component + 1); + vec.push_back(0x11); + //"Tq1" reserved, 0 + vec.push_back(0); + } + + return new JpegMarkerSegment(JPEG_SOF, vec); +} + + + + +// +// ctor() +// +JLSOutputStream::JLSOutputStream() : + _bCompare(false), + _pdata(NULL), + _cbyteOffset(0), + _cbyteLength(0), + _icompLast(0) +{ +} + + + +// +// dtor() +// +JLSOutputStream::~JLSOutputStream() +{ + for (size_t i = 0; i < _segments.size(); ++i) + { + delete _segments[i]; + } + _segments.empty(); +} + + + + +// +// Init() +// +void JLSOutputStream::Init(Size size, LONG bitsPerSample, LONG ccomp) +{ + _segments.push_back(CreateMarkerStartOfFrame(size, bitsPerSample, ccomp)); +} + + +void JLSOutputStream::AddColorTransform(int i) +{ + std::vector rgbyteXform; + rgbyteXform.push_back('m'); + rgbyteXform.push_back('r'); + rgbyteXform.push_back('f'); + rgbyteXform.push_back('x'); + rgbyteXform.push_back((BYTE)i); + + _segments.push_back(new JpegMarkerSegment(JPEG_APP8, rgbyteXform)); +} + + +// +// Write() +// +size_t JLSOutputStream::Write(BYTE* pdata, size_t cbyteLength) +{ + _pdata = pdata; + _cbyteLength = cbyteLength; + + WriteByte(0xFF); + WriteByte(JPEG_SOI); + + for (size_t i = 0; i < _segments.size(); ++i) + { + _segments[i]->Write(this); + } + + //_bCompare = false; + + WriteByte(0xFF); + WriteByte(JPEG_EOI); + + return _cbyteOffset; +} + + + +JLSInputStream::JLSInputStream(const BYTE* pdata, size_t cbyteLength) : + _pdata(pdata), + _cbyteOffset(0), + _cbyteLength(cbyteLength), + _bCompare(false), + _info(), + _rect() +{ +} + +// +// Read() +// +void JLSInputStream::Read(void* pvoid, size_t cbyteAvailable) +{ + ReadHeader(); + + JLS_ERROR error = CheckParameterCoherent(&_info); + if (error != OK) + throw JlsException(error); + + ReadPixels(pvoid, cbyteAvailable); +} + + + + + +// +// ReadPixels() +// +void JLSInputStream::ReadPixels(void* pvoid, size_t cbyteAvailable) +{ + + if (_rect.Width <= 0) + { + _rect.Width = _info.width; + _rect.Height = _info.height; + } + + int64_t cbytePlane = (int64_t)(_rect.Width) * _rect.Height * ((_info.bitspersample + 7)/8); + + if (int64_t(cbyteAvailable) < cbytePlane * _info.components) + throw JlsException(UncompressedBufferTooSmall); + + int scancount = _info.ilv == ILV_NONE ? _info.components : 1; + + BYTE* pbyte = (BYTE*)pvoid; + for (LONG scan = 0; scan < scancount; ++scan) + { + ReadScan(pbyte); + pbyte += cbytePlane; + } +} + +// ReadNBytes() +// +void JLSInputStream::ReadNBytes(std::vector& dst, int byteCount) +{ + for (int i = 0; i < byteCount; ++i) + { + dst.push_back((char)ReadByte()); + } +} + + +// +// ReadHeader() +// +void JLSInputStream::ReadHeader() +{ + if (ReadByte() != 0xFF) + throw JlsException(InvalidCompressedData); + + if (ReadByte() != JPEG_SOI) + throw JlsException(InvalidCompressedData); + + for (;;) + { + if (ReadByte() != 0xFF) + throw JlsException(InvalidCompressedData); + + BYTE marker = (BYTE)ReadByte(); + + size_t cbyteStart = _cbyteOffset; + LONG cbyteMarker = ReadWord(); + + switch (marker) + { + case JPEG_SOS: ReadStartOfScan(); break; + case JPEG_SOF: ReadStartOfFrame(); break; + case JPEG_COM: ReadComment(); break; + case JPEG_LSE: ReadPresetParameters(); break; + case JPEG_APP0: ReadJfif(); break; + case JPEG_APP7: ReadColorSpace(); break; + case JPEG_APP8: ReadColorXForm(); break; + // Other tags not supported (among which DNL DRI) + default: throw JlsException(ImageTypeNotSupported); + } + + if (marker == JPEG_SOS) + { + _cbyteOffset = cbyteStart - 2; + return; + } + _cbyteOffset = cbyteStart + cbyteMarker; + } +} + + +JpegMarkerSegment* EncodeStartOfScan(const JlsParameters* pparams, LONG icomponent) +{ + BYTE itable = 0; + + std::vector rgbyte; + + if (icomponent < 0) + { + rgbyte.push_back((BYTE)pparams->components); + for (LONG icomponent_ = 0; icomponent_ < pparams->components; ++icomponent_ ) + { + rgbyte.push_back(BYTE(icomponent_ + 1)); + rgbyte.push_back(itable); + } + } + else + { + rgbyte.push_back(1); + rgbyte.push_back((BYTE)icomponent); + rgbyte.push_back(itable); + } + + rgbyte.push_back(BYTE(pparams->allowedlossyerror)); + rgbyte.push_back(BYTE(pparams->ilv)); + rgbyte.push_back(0); // transform + + return new JpegMarkerSegment(JPEG_SOS, rgbyte); +} + + + +JpegMarkerSegment* CreateLSE(const JlsCustomParameters* pcustom) +{ + std::vector rgbyte; + + rgbyte.push_back(1); + push_back(rgbyte, (USHORT)pcustom->MAXVAL); + push_back(rgbyte, (USHORT)pcustom->T1); + push_back(rgbyte, (USHORT)pcustom->T2); + push_back(rgbyte, (USHORT)pcustom->T3); + push_back(rgbyte, (USHORT)pcustom->RESET); + + return new JpegMarkerSegment(JPEG_LSE, rgbyte); +} + +// +// ReadPresetParameters() +// +void JLSInputStream::ReadPresetParameters() +{ + LONG type = ReadByte(); + + + switch (type) + { + case 1: + { + _info.custom.MAXVAL = ReadWord(); + _info.custom.T1 = ReadWord(); + _info.custom.T2 = ReadWord(); + _info.custom.T3 = ReadWord(); + _info.custom.RESET = ReadWord(); + return; + } + } + + +} + + +// +// ReadStartOfScan() +// +void JLSInputStream::ReadStartOfScan() +{ + LONG ccomp = ReadByte(); + for (LONG i = 0; i < ccomp; ++i) + { + ReadByte(); + ReadByte(); + } + _info.allowedlossyerror = ReadByte(); + _info.ilv = interleavemode(ReadByte()); + + if(_info.bytesperline == 0) + { + int width = _rect.Width != 0 ? _rect.Width : _info.width; + int components = _info.ilv == ILV_NONE ? 1 : _info.components; + _info.bytesperline = components * width * ((_info.bitspersample + 7)/8); + } +} + + +// +// ReadComment() +// +void JLSInputStream::ReadComment() +{} + + +// +// ReadJfif() +// +void JLSInputStream::ReadJfif() +{ + for(int i = 0; i < (int)sizeof(jfifID); i++) + { + if(jfifID[i] != ReadByte()) + return; + } + _info.jfif.Ver = ReadWord(); + + // DPI or DPcm + _info.jfif.units = ReadByte(); + _info.jfif.XDensity = ReadWord(); + _info.jfif.YDensity = ReadWord(); + + // thumbnail + _info.jfif.Xthumb = ReadByte(); + _info.jfif.Ythumb = ReadByte(); + if(_info.jfif.Xthumb > 0 && _info.jfif.pdataThumbnail) + { + std::vector tempbuff((char*)_info.jfif.pdataThumbnail, (char*)_info.jfif.pdataThumbnail+3*_info.jfif.Xthumb*_info.jfif.Ythumb); + ReadNBytes(tempbuff, 3*_info.jfif.Xthumb*_info.jfif.Ythumb); + } +} + +// +// CreateJFIF() +// +JpegMarkerSegment* CreateJFIF(const JfifParameters* jfif) +{ + std::vector rgbyte; + for(int i = 0; i < (int)sizeof(jfifID); i++) + { + rgbyte.push_back(jfifID[i]); + } + + push_back(rgbyte, (USHORT)jfif->Ver); + + rgbyte.push_back(jfif->units); + push_back(rgbyte, (USHORT)jfif->XDensity); + push_back(rgbyte, (USHORT)jfif->YDensity); + + // thumbnail + rgbyte.push_back((BYTE)jfif->Xthumb); + rgbyte.push_back((BYTE)jfif->Ythumb); + if(jfif->Xthumb > 0) + { + if(jfif->pdataThumbnail) + throw JlsException(InvalidJlsParameters); + + rgbyte.insert(rgbyte.end(), (BYTE*)jfif->pdataThumbnail, (BYTE*)jfif->pdataThumbnail+3*jfif->Xthumb*jfif->Ythumb + ); + } + + return new JpegMarkerSegment(JPEG_APP0, rgbyte); +} + + +// +// ReadStartOfFrame() +// +void JLSInputStream::ReadStartOfFrame() +{ + _info.bitspersample = ReadByte(); + int cline = ReadWord(); + int ccol = ReadWord(); + _info.width = ccol; + _info.height = cline; + _info.components= ReadByte(); +} + + +// +// ReadByte() +// +BYTE JLSInputStream::ReadByte() +{ + if (_cbyteOffset >= _cbyteLength) + throw JlsException(InvalidCompressedData); + + return _pdata[_cbyteOffset++]; +} + + +// +// ReadWord() +// +int JLSInputStream::ReadWord() +{ + int i = ReadByte() * 256; + return i + ReadByte(); +} + + +void JLSInputStream::ReadScan(void* pvout) +{ + std::auto_ptr qcodec = JlsCodecFactory().GetCodec(_info, _info.custom); + + _cbyteOffset += qcodec->DecodeScan(pvout, _rect, _pdata + _cbyteOffset, _cbyteLength - _cbyteOffset, _bCompare); +} + + +class JpegImageDataSegment: public JpegSegment +{ +public: + JpegImageDataSegment(const void* pvoidRaw, const JlsParameters& info, LONG icompStart, int ccompScan) : + _ccompScan(ccompScan), + _icompStart(icompStart), + _pvoidRaw(pvoidRaw), + _info(info) + { + } + + void Write(JLSOutputStream* pstream) + { + JlsParameters info = _info; + info.components = _ccompScan; + std::auto_ptr qcodec =JlsCodecFactory().GetCodec(info, _info.custom); + size_t cbyteWritten = qcodec->EncodeScan((BYTE*)_pvoidRaw, pstream->GetPos(), pstream->GetLength(), pstream->_bCompare ? pstream->GetPos() : NULL); + pstream->Seek(cbyteWritten); + } + + + int _ccompScan; + LONG _icompStart; + const void* _pvoidRaw; + JlsParameters _info; +}; + + +void JLSOutputStream::AddScan(const void* compareData, const JlsParameters* pparams) +{ + if (pparams->jfif.Ver) + { + _segments.push_back(CreateJFIF(&pparams->jfif)); + } + if (!IsDefault(&pparams->custom)) + { + _segments.push_back(CreateLSE(&pparams->custom)); + } + else if (pparams->bitspersample > 12) + { + JlsCustomParameters preset = ComputeDefault((1 << pparams->bitspersample) - 1, pparams->allowedlossyerror); + _segments.push_back(CreateLSE(&preset)); + } + + _icompLast += 1; + _segments.push_back(EncodeStartOfScan(pparams,pparams->ilv == ILV_NONE ? _icompLast : -1)); + + //Size size = Size(pparams->width, pparams->height); + int ccomp = pparams->ilv == ILV_NONE ? 1 : pparams->components; + _segments.push_back(new JpegImageDataSegment(compareData, *pparams, _icompLast, ccomp)); +} + + +// +// ReadColorSpace() +// +void JLSInputStream::ReadColorSpace() +{} + + + +// +// ReadColorXForm() +// +void JLSInputStream::ReadColorXForm() +{ + std::vector sourceTag; + ReadNBytes(sourceTag, 4); + + if(strncmp(&sourceTag[0],"mrfx", 4) != 0) + return; + + int xform = ReadByte(); + switch(xform) + { + case COLORXFORM_NONE: + case COLORXFORM_HP1: + case COLORXFORM_HP2: + case COLORXFORM_HP3: + _info.colorTransform = xform; + return; + case COLORXFORM_RGB_AS_YUV_LOSSY: + case COLORXFORM_MATRIX: + throw JlsException(ImageTypeNotSupported); + default: + throw JlsException(InvalidCompressedData); + } +} + diff --git a/gdcm/Utilities/gdcmcharls/header.h b/gdcm/Utilities/gdcmcharls/header.h new file mode 100644 index 0000000..034325c --- /dev/null +++ b/gdcm/Utilities/gdcmcharls/header.h @@ -0,0 +1,62 @@ +// +// (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. +// + + +#ifndef CHARLS_HEADER +#define CHARLS_HEADER + +#include "streams.h" + +#define JPEG_SOI 0xD8 +#define JPEG_EOI 0xD9 +#define JPEG_SOS 0xDA + +#define JPEG_SOF 0xF7 +#define JPEG_LSE 0xF8 +#define JPEG_DNL 0xDC +#define JPEG_DRI 0xDD +#define JPEG_RSTm 0xD0 +#define JPEG_COM 0xFE +#define JPEG_APP0 0xE0 // JFIF +#define JPEG_APP7 0xE7 // colorspace +#define JPEG_APP8 0xE8 // colorXForm + + + +// Default bin sizes for JPEG-LS statistical modeling. Can be overriden at compression time, however this is rarely done. +const int BASIC_T1 = 3; +const int BASIC_T2 = 7; +const int BASIC_T3 = 21; + +const LONG BASIC_RESET = 64; + +class JLSOutputStream; + + +template +class JlsCodecFactory +{ +public: + std::auto_ptr GetCodec(const JlsParameters& info, const JlsCustomParameters&); +private: + STRATEGY* GetCodecImpl(const JlsParameters& info); +}; + +JLS_ERROR CheckParameterCoherent(const JlsParameters* pparams); + +JlsCustomParameters ComputeDefault(LONG MAXVAL, LONG NEAR); + +// +// JpegSegment +// +class JpegSegment +{ +protected: + JpegSegment() {} +public: + virtual ~JpegSegment() {} + virtual void Write(JLSOutputStream* pstream) = 0; +}; + +#endif diff --git a/gdcm/Utilities/gdcmcharls/interface.cpp b/gdcm/Utilities/gdcmcharls/interface.cpp new file mode 100644 index 0000000..ca4e1e9 --- /dev/null +++ b/gdcm/Utilities/gdcmcharls/interface.cpp @@ -0,0 +1,206 @@ +// +// (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. +// + + +//implement correct linkage for win32 dlls +//#if defined(_WIN32) +//#define CHARLS_IMEXPORT(returntype) __declspec(dllexport) returntype __stdcall +//#endif + +#include "config.h" +#include "util.h" +#include "interface.h" +#include "header.h" + + +JLS_ERROR CheckInput(const void* compressedData, size_t compressedLength, const void* uncompressedData, size_t uncompressedLength, const JlsParameters* pparams) +{ + if (pparams == NULL) + return InvalidJlsParameters; + + if (compressedLength == 0) + return InvalidJlsParameters; + + if (compressedData == NULL) + return InvalidJlsParameters; + + if (uncompressedData == NULL) + return InvalidJlsParameters; + + if (pparams->width < 1 || pparams->width > 65535) + return ParameterValueNotSupported; + + if (pparams->height < 1 || pparams->height > 65535) + return ParameterValueNotSupported; + + int bytesperline = pparams->bytesperline < 0 ? -pparams->bytesperline : pparams->bytesperline; + + if (uncompressedLength < size_t(bytesperline * pparams->height)) + return InvalidJlsParameters; + + return CheckParameterCoherent(pparams); +} + + + +extern "C" +{ + +CHARLS_IMEXPORT(JLS_ERROR) JpegLsEncode(void* compressedData, size_t compressedLength, size_t* pcbyteWritten, const void* uncompressedData, size_t uncompressedLength, struct JlsParameters* pparams) +{ + JlsParameters info = *pparams; + if(info.bytesperline == 0) + { + info.bytesperline = info.width * ((info.bitspersample + 7)/8); + if (info.ilv != ILV_NONE) + { + info.bytesperline *= info.components; + } + } + + JLS_ERROR parameterError = CheckInput(compressedData, compressedLength, uncompressedData, uncompressedLength, &info); + + if (parameterError != OK) + return parameterError; + + if (pcbyteWritten == NULL) + return InvalidJlsParameters; + + Size size = Size(info.width, info.height); + JLSOutputStream stream; + + stream.Init(size, info.bitspersample, info.components); + + if (info.colorTransform != 0) + { + stream.AddColorTransform(info.colorTransform); + } + + if (info.ilv == ILV_NONE) + { + LONG cbyteComp = size.cx*size.cy*((info.bitspersample +7)/8); + for (LONG component = 0; component < info.components; ++component) + { + const BYTE* compareData = static_cast(uncompressedData) + component*cbyteComp; + stream.AddScan(compareData, &info); + } + } + else + { + stream.AddScan(uncompressedData, &info); + } + + + stream.Write((BYTE*)compressedData, compressedLength); + + *pcbyteWritten = stream.GetBytesWritten(); + return OK; +} + +CHARLS_IMEXPORT(JLS_ERROR) JpegLsDecode(void* uncompressedData, size_t uncompressedLength, const void* compressedData, size_t compressedLength, JlsParameters* info) +{ + JLSInputStream reader((BYTE*)compressedData, compressedLength); + + if(info != NULL) + { + reader.SetInfo(info); + } + + try + { + reader.Read(uncompressedData, uncompressedLength); + return OK; + } + catch (JlsException& e) + { + return e._error; + } +} + + +CHARLS_IMEXPORT(JLS_ERROR) JpegLsDecodeRect(void* uncompressedData, size_t uncompressedLength, const void* compressedData, size_t compressedLength, JlsRect roi, JlsParameters* info) +{ + JLSInputStream reader((BYTE*)compressedData, compressedLength); + + if(info != NULL) + { + reader.SetInfo(info); + } + + reader.SetRect(roi); + + try + { + reader.Read(uncompressedData, uncompressedLength); + return OK; + } + catch (JlsException& e) + { + return e._error; + } +} + + +CHARLS_IMEXPORT(JLS_ERROR) JpegLsVerifyEncode(const void* uncompressedData, size_t uncompressedLength, const void* compressedData, size_t compressedLength) +{ + JlsParameters info = JlsParameters(); + + JLS_ERROR error = JpegLsReadHeader(compressedData, compressedLength, &info); + if (error != OK) + return error; + + error = CheckInput(compressedData, compressedLength, uncompressedData, uncompressedLength, &info); + + if (error != OK) + return error; + + Size size = Size(info.width, info.height); + + JLSOutputStream stream; + + stream.Init(size, info.bitspersample, info.components); + + if (info.ilv == ILV_NONE) + { + LONG cbyteComp = size.cx*size.cy*((info.bitspersample +7)/8); + for (LONG component = 0; component < info.components; ++component) + { + const BYTE* compareData = static_cast(uncompressedData) + component*cbyteComp; + stream.AddScan(compareData, &info); + } + } + else + { + stream.AddScan(uncompressedData, &info); + } + + std::vector rgbyteCompressed(compressedLength + 16); + + memcpy(&rgbyteCompressed[0], compressedData, compressedLength); + + stream.EnableCompare(true); + stream.Write(&rgbyteCompressed[0], compressedLength); + + return OK; +} + + +CHARLS_IMEXPORT(JLS_ERROR) JpegLsReadHeader(const void* compressedData, size_t compressedLength, JlsParameters* pparams) +{ + try + { + JLSInputStream reader((BYTE*)compressedData, compressedLength); + reader.ReadHeader(); + JlsParameters info = reader.GetMetadata(); + *pparams = info; + return OK; + } + catch (JlsException& e) + { + return e._error; + } + +} + +} diff --git a/gdcm/Utilities/gdcmcharls/interface.h b/gdcm/Utilities/gdcmcharls/interface.h new file mode 100644 index 0000000..680a7c0 --- /dev/null +++ b/gdcm/Utilities/gdcmcharls/interface.h @@ -0,0 +1,52 @@ +// +// (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. +// + + +#ifndef JLS_INTERFACE +#define JLS_INTERFACE + +#include "publictypes.h" + +#if defined(_WIN32) && defined(CHARLS_SHARED) +#ifdef gdcmcharls_EXPORTS +#define CHARLS_IMEXPORT(returntype) __declspec(dllexport) returntype __stdcall +#else +#define CHARLS_IMEXPORT(returntype) __declspec(dllimport) returntype __stdcall +#endif +#else +#if __GNUC__ >= 4 +#define CHARLS_IMEXPORT(returntype) __attribute__ ((visibility ("default"))) returntype +#else +#define CHARLS_IMEXPORT(returntype) returntype +#endif +#endif /* _WIN32 */ + + +#ifdef __cplusplus +extern "C" +{ +#endif + CHARLS_IMEXPORT(enum JLS_ERROR) JpegLsEncode(void* compressedData, size_t compressedLength, size_t* pcbyteWritten, + const void* uncompressedData, size_t uncompressedLength, struct JlsParameters* pparams); + + CHARLS_IMEXPORT(enum JLS_ERROR) JpegLsDecode(void* uncompressedData, size_t uncompressedLength, + const void* compressedData, size_t compressedLength, + struct JlsParameters* info); + + + CHARLS_IMEXPORT(enum JLS_ERROR) JpegLsDecodeRect(void* uncompressedData, size_t uncompressedLength, + const void* compressedData, size_t compressedLength, + struct JlsRect rect, struct JlsParameters* info); + + CHARLS_IMEXPORT(enum JLS_ERROR) JpegLsReadHeader(const void* compressedData, size_t compressedLength, + struct JlsParameters* pparams); + + CHARLS_IMEXPORT(enum JLS_ERROR) JpegLsVerifyEncode(const void* uncompressedData, size_t uncompressedLength, + const void* compressedData, size_t compressedLength); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/gdcm/Utilities/gdcmcharls/jpegls.cpp b/gdcm/Utilities/gdcmcharls/jpegls.cpp new file mode 100644 index 0000000..6a6bcf4 --- /dev/null +++ b/gdcm/Utilities/gdcmcharls/jpegls.cpp @@ -0,0 +1,172 @@ +// +// (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. +// + +#include "config.h" +#include "util.h" +#include "streams.h" +#include "header.h" + + +#include + +#include +#include +#include + +#include "decoderstrategy.h" +#include "encoderstrategy.h" +#include "context.h" +#include "contextrunmode.h" +#include "lookuptable.h" + + +signed char* JlsContext::_tableC = CreateTableC(); + +// As defined in the JPEG-LS standard + +// used to determine how large runs should be encoded at a time. +const int J[32] = {0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 9, 10, 11, 12, 13, 14, 15}; + + + +#include "losslesstraits.h" +#include "defaulttraits.h" + +#include "scan.h" + +signed char QuantizeGratientOrg(const JlsCustomParameters& preset, LONG NEAR, LONG Di) +{ + if (Di <= -preset.T3) return -4; + if (Di <= -preset.T2) return -3; + if (Di <= -preset.T1) return -2; + if (Di < -NEAR) return -1; + if (Di <= NEAR) return 0; + if (Di < preset.T1) return 1; + if (Di < preset.T2) return 2; + if (Di < preset.T3) return 3; + + return 4; +} + + + +std::vector CreateQLutLossless(LONG cbit) +{ + JlsCustomParameters preset = ComputeDefault((1 << cbit) - 1, 0); + LONG range = preset.MAXVAL + 1; + + std::vector lut(range * 2); + + for (LONG diff = -range; diff < range; diff++) + { + lut[range + diff] = QuantizeGratientOrg(preset, 0,diff); + } + return lut; +} + +// Lookup tables to replace code with lookup tables. +// To avoid threading issues, all tables are created when the program is loaded. + + +// Lookup table: decode symbols that are smaller or equal to 8 bit (16 tables for each value of k) +CTable decodingTables[16] = { InitTable(0), InitTable(1), InitTable(2), InitTable(3), + InitTable(4), InitTable(5), InitTable(6), InitTable(7), + InitTable(8), InitTable(9), InitTable(10), InitTable(11), + InitTable(12), InitTable(13), InitTable(14),InitTable(15) }; + + +// Lookup tables: sample differences to bin indexes. +std::vector rgquant8Ll = CreateQLutLossless(8); +std::vector rgquant10Ll = CreateQLutLossless(10); +std::vector rgquant12Ll = CreateQLutLossless(12); +std::vector rgquant16Ll = CreateQLutLossless(16); + + + + +template +std::auto_ptr JlsCodecFactory::GetCodec(const JlsParameters& info, const JlsCustomParameters& presets) +{ + STRATEGY* pstrategy = NULL; + if (presets.RESET != 0 && presets.RESET != BASIC_RESET) + { + DefaultTraitsT traits((1 << info.bitspersample) - 1, info.allowedlossyerror); + traits.MAXVAL = presets.MAXVAL; + traits.RESET = presets.RESET; + pstrategy = new JlsCodec, STRATEGY>(traits, info); + } + else + { + pstrategy = GetCodecImpl(info); + } + + if (pstrategy != NULL) + { + pstrategy->SetPresets(presets); + } + return std::auto_ptr(pstrategy); +} + + + +template +STRATEGY* CreateCodec(const TRAITS& t, const STRATEGY*,const JlsParameters& info) +{ + return new JlsCodec(t, info); +} + + +template +STRATEGY* JlsCodecFactory::GetCodecImpl(const JlsParameters& info) +{ + STRATEGY* s = 0; + + if (info.ilv == ILV_SAMPLE && info.components != 3) + return NULL; + +#ifndef DISABLE_SPECIALIZATIONS + + // optimized lossless versions common formats + if (info.allowedlossyerror == 0) + { + if (info.ilv == ILV_SAMPLE) + { + if (info.bitspersample == 8) + return CreateCodec(LosslessTraitsT,8>(), s, info); + } + else + { + switch (info.bitspersample) + { + case 8: return CreateCodec(LosslessTraitsT(), s, info); + case 12: return CreateCodec(LosslessTraitsT(), s, info); + case 16: return CreateCodec(LosslessTraitsT(), s, info); + } + } + } + +#endif + + int maxval = (1 << info.bitspersample) - 1; + + if (info.bitspersample <= 8) + { + if (info.ilv == ILV_SAMPLE) + return CreateCodec(DefaultTraitsT >(maxval, info.allowedlossyerror), s, info); + + return CreateCodec(DefaultTraitsT((1 << info.bitspersample) - 1, info.allowedlossyerror), s, info); + } + else if (info.bitspersample <= 16) + { + if (info.ilv == ILV_SAMPLE) + return CreateCodec(DefaultTraitsT >(maxval, info.allowedlossyerror), s, info); + + return CreateCodec(DefaultTraitsT(maxval, info.allowedlossyerror), s, info); + } + return NULL; +} + + +template class JlsCodecFactory; +template class JlsCodecFactory; diff --git a/gdcm/Utilities/gdcmcharls/lookuptable.h b/gdcm/Utilities/gdcmcharls/lookuptable.h new file mode 100644 index 0000000..b37d104 --- /dev/null +++ b/gdcm/Utilities/gdcmcharls/lookuptable.h @@ -0,0 +1,69 @@ +// +// (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. +// + + +#ifndef CHARLS_LOOKUPTABLE +#define CHARLS_LOOKUPTABLE + +// Tables for fast decoding of short Golomb Codes. + +struct Code +{ + Code() + { + } + + Code(LONG value, LONG length) : + _value(value), + _length(length) + { + } + + LONG GetValue() const + { return _value; } + LONG GetLength() const + { return _length; } + + LONG _value; + LONG _length; +}; + + + +class CTable +{ +public: + + enum { cbit = 8 } ; + + CTable() + { + ::memset(rgtype, 0, sizeof(rgtype)); + } + + void AddEntry(BYTE bvalue, Code c); + + inlinehint const Code& Get(LONG value) + { return rgtype[value]; } +private: + Code rgtype[1 << cbit]; +}; + + +// +// AddEntry +// +void CTable::AddEntry(BYTE bvalue, Code c) +{ + LONG length = c.GetLength(); + ASSERT(length <= cbit); + + for (LONG i = 0; i < LONG(1) << (cbit - length); ++i) + { + ASSERT(rgtype[(bvalue << (cbit - length)) + i].GetLength() == 0); + rgtype[(bvalue << (cbit - length)) + i] = c; + } +} + +#endif diff --git a/gdcm/Utilities/gdcmcharls/losslesstraits.h b/gdcm/Utilities/gdcmcharls/losslesstraits.h new file mode 100644 index 0000000..712fe95 --- /dev/null +++ b/gdcm/Utilities/gdcmcharls/losslesstraits.h @@ -0,0 +1,120 @@ +// +// (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. +// + + + +#ifndef CHARLS_LOSSLESSTRAITS +#define CHARLS_LOSSLESSTRAITS + +#include "header.h" + +// +// optimized trait classes for lossless compression of 8 bit color and 8/16 bit monochrome images. +// This class is assumes MAXVAL correspond to a whole number of bits, and no custom RESET value is set when encoding. +// The point of this is to have the most optimized code for the most common and most demanding scenario. + +template +struct LosslessTraitsImplT +{ + typedef sample SAMPLE; + enum { + NEAR = 0, + bpp = bitsperpixel, + qbpp = bitsperpixel, + RANGE = (1 << bpp), + MAXVAL= (1 << bpp) - 1, + LIMIT = 2 * (bitsperpixel + MAX(8,bitsperpixel)), + RESET = BASIC_RESET + }; + + static inlinehint LONG ComputeErrVal(LONG d) + { return ModRange(d); } + + static inlinehint bool IsNear(LONG lhs, LONG rhs) + { return lhs == rhs; } + + static inlinehint LONG ModRange(LONG Errval) + { + return LONG(Errval << (LONG_BITCOUNT - bpp)) >> (LONG_BITCOUNT - bpp); + } + + static inlinehint SAMPLE ComputeReconstructedSample(LONG Px, LONG ErrVal) + { + return SAMPLE(MAXVAL & (Px + ErrVal)); + } + + static inlinehint LONG CorrectPrediction(LONG Pxc) + { + if ((Pxc & MAXVAL) == Pxc) + return Pxc; + + return (~(Pxc >> (LONG_BITCOUNT-1))) & MAXVAL; + } + +}; + +template +struct LosslessTraitsT : public LosslessTraitsImplT +{ + typedef SAMPLE PIXEL; +}; + + + +template<> +struct LosslessTraitsT : public LosslessTraitsImplT +{ + typedef SAMPLE PIXEL; + + static inlinehint signed char ModRange(LONG Errval) + { return (signed char)Errval; } + + static inlinehint LONG ComputeErrVal(LONG d) + { return (signed char)(d); } + + static inlinehint BYTE ComputeReconstructedSample(LONG Px, LONG ErrVal) + { return BYTE(Px + ErrVal); } + +}; + + + +template<> +struct LosslessTraitsT : public LosslessTraitsImplT +{ + typedef SAMPLE PIXEL; + + static inlinehint short ModRange(LONG Errval) + { return short(Errval); } + + static inlinehint LONG ComputeErrVal(LONG d) + { return short(d); } + + static inlinehint SAMPLE ComputeReconstructedSample(LONG Px, LONG ErrVal) + { return SAMPLE(Px + ErrVal); } + +}; + + + + +template +struct LosslessTraitsT,bpp> : public LosslessTraitsImplT +{ + typedef Triplet PIXEL; + + static inlinehint bool IsNear(LONG lhs, LONG rhs) + { return lhs == rhs; } + + static inlinehint bool IsNear(PIXEL lhs, PIXEL rhs) + { return lhs == rhs; } + + + static inlinehint SAMPLE ComputeReconstructedSample(LONG Px, LONG ErrVal) + { return SAMPLE(Px + ErrVal); } + + +}; + +#endif diff --git a/gdcm/Utilities/gdcmcharls/processline.h b/gdcm/Utilities/gdcmcharls/processline.h new file mode 100644 index 0000000..e9b7e6f --- /dev/null +++ b/gdcm/Utilities/gdcmcharls/processline.h @@ -0,0 +1,225 @@ +// +// (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. +// +#ifndef CHARLS_PROCESSLINE +#define CHARLS_PROCESSLINE + +#include "colortransform.h" + +// +// This file defines the ProcessLine base class, its derivitives and helper functions. +// During coding/decoding, CharLS process one line at a time. The different Processline implementations +// convert the uncompressed format to and from the internal format for encoding. +// Conversions include color transforms, line interleaved vs sample interleaved, masking out unused bits, +// accounting for line padding etc. +// This mechanism could be used to encode/decode images as they are received. +// + +class ProcessLine +{ +public: + virtual ~ProcessLine() {} + virtual void NewLineDecoded(const void* pSrc, int pixelCount, int bytesperline) = 0; + virtual void NewLineRequested(void* pSrc, int pixelCount, int bytesperline) = 0; +}; + + +class PostProcesSingleComponent : public ProcessLine +{ +public: + PostProcesSingleComponent(void* pbyteOutput, const JlsParameters& info, int bytesPerPixel) : + _pbyteOutput((BYTE*)pbyteOutput), + _bytesPerPixel(bytesPerPixel), + _bytesPerLine(info.bytesperline) + { + } + + void NewLineRequested(void* pDst, int pixelCount, int /*byteStride*/) + { + ::memcpy(pDst, _pbyteOutput, pixelCount * _bytesPerPixel); + _pbyteOutput += _bytesPerLine; + } + + void NewLineDecoded(const void* pSrc, int pixelCount, int /*byteStride*/) + { + ::memcpy(_pbyteOutput, pSrc, pixelCount * _bytesPerPixel); + _pbyteOutput += _bytesPerLine; + } + +private: + BYTE* _pbyteOutput; + int _bytesPerPixel; + int _bytesPerLine; +}; + + +template +void TransformLineToQuad(const SAMPLE* ptypeInput, LONG pixelStrideIn, Quad* pbyteBuffer, LONG pixelStride, TRANSFORM& transform) +{ + int cpixel = MIN(pixelStride, pixelStrideIn); + Quad* ptypeBuffer = (Quad*)pbyteBuffer; + + for (int x = 0; x < cpixel; ++x) + { + Quad pixel(transform(ptypeInput[x], ptypeInput[x + pixelStrideIn], ptypeInput[x + 2*pixelStrideIn]),ptypeInput[x + 3*pixelStrideIn]) ; + + ptypeBuffer[x] = pixel; + } +} + + +template +void TransformQuadToLine(const Quad* pbyteInput, LONG pixelStrideIn, SAMPLE* ptypeBuffer, LONG pixelStride, TRANSFORM& transform) +{ + int cpixel = MIN(pixelStride, pixelStrideIn); + const Quad* ptypeBufferIn = (Quad*)pbyteInput; + + for (int x = 0; x < cpixel; ++x) + { + Quad color = ptypeBufferIn[x]; + Quad colorTranformed(transform(color.v1, color.v2, color.v3), color.v4); + + ptypeBuffer[x] = colorTranformed.v1; + ptypeBuffer[x + pixelStride] = colorTranformed.v2; + ptypeBuffer[x + 2 *pixelStride] = colorTranformed.v3; + ptypeBuffer[x + 3 *pixelStride] = colorTranformed.v4; + } +} + + +template +void TransformRgbToBgr(SAMPLE* pDest, int samplesPerPixel, int pixelCount) +{ + for (int i = 0; i < pixelCount; ++i) + { + std::swap(pDest[0], pDest[2]); + pDest += samplesPerPixel; + } +} + + +template +void TransformLine(Triplet* pDest, const Triplet* pSrc, int pixelCount, TRANSFORM& transform) +{ + for (int i = 0; i < pixelCount; ++i) + { + pDest[i] = transform(pSrc[i].v1, pSrc[i].v2, pSrc[i].v3); + } +} + + +template +void TransformLineToTriplet(const SAMPLE* ptypeInput, LONG pixelStrideIn, Triplet* pbyteBuffer, LONG pixelStride, TRANSFORM& transform) +{ + int cpixel = MIN(pixelStride, pixelStrideIn); + Triplet* ptypeBuffer = (Triplet*)pbyteBuffer; + + for (int x = 0; x < cpixel; ++x) + { + ptypeBuffer[x] = transform(ptypeInput[x], ptypeInput[x + pixelStrideIn], ptypeInput[x + 2*pixelStrideIn]); + } +} + + +template +void TransformTripletToLine(const Triplet* pbyteInput, LONG pixelStrideIn, SAMPLE* ptypeBuffer, LONG pixelStride, TRANSFORM& transform) +{ + int cpixel = MIN(pixelStride, pixelStrideIn); + const Triplet* ptypeBufferIn = (Triplet*)pbyteInput; + + for (int x = 0; x < cpixel; ++x) + { + Triplet color = ptypeBufferIn[x]; + Triplet colorTranformed = transform(color.v1, color.v2, color.v3); + + ptypeBuffer[x] = colorTranformed.v1; + ptypeBuffer[x + pixelStride] = colorTranformed.v2; + ptypeBuffer[x + 2 *pixelStride] = colorTranformed.v3; + } +} + + +template +class ProcessTransformed : public ProcessLine +{ + typedef typename TRANSFORM::SAMPLE SAMPLE; + + ProcessTransformed(const ProcessTransformed&); +public: + ProcessTransformed(void* pbyteOutput, const JlsParameters& info, TRANSFORM transform) : + _pbyteOutput((BYTE*)pbyteOutput), + _info(info), + _templine(info.width * info.components), + _transform(transform), + _inverseTransform(transform) + { +// ASSERT(_info.components == sizeof(TRIPLET)/sizeof(TRIPLET::SAMPLE)); + } + + + void NewLineRequested(void* pDst, int pixelCount, int stride) + { + SAMPLE* pLine = (SAMPLE*)_pbyteOutput; + if (_info.outputBgr) + { + pLine = &_templine[0]; + memcpy(pLine, _pbyteOutput, sizeof(Triplet)*pixelCount); + TransformRgbToBgr(pLine, _info.components, pixelCount); + } + + if (_info.components == 3) + { + if (_info.ilv == ILV_SAMPLE) + { + TransformLine((Triplet*)pDst, (const Triplet*)pLine, pixelCount, _transform); + } + else + { + TransformTripletToLine((const Triplet*)pLine, pixelCount, (SAMPLE*)pDst, stride, _transform); + } + } + else if (_info.components == 4 && _info.ilv == ILV_LINE) + { + TransformQuadToLine((const Quad*)pLine, pixelCount, (SAMPLE*)pDst, stride, _transform); + } + _pbyteOutput += _info.bytesperline; + } + + + void NewLineDecoded(const void* pSrc, int pixelCount, int byteStride) + { + if (_info.components == 3) + { + if (_info.ilv == ILV_SAMPLE) + { + TransformLine((Triplet*)_pbyteOutput, (const Triplet*)pSrc, pixelCount, _inverseTransform); + } + else + { + TransformLineToTriplet((const SAMPLE*)pSrc, byteStride, (Triplet*)_pbyteOutput, pixelCount, _inverseTransform); + } + } + else if (_info.components == 4 && _info.ilv == ILV_LINE) + { + TransformLineToQuad((const SAMPLE*)pSrc, byteStride, (Quad*)_pbyteOutput, pixelCount, _inverseTransform); + } + + if (_info.outputBgr) + { + TransformRgbToBgr(_pbyteOutput, _info.components, pixelCount); + } + _pbyteOutput += _info.bytesperline; + } + + +private: + BYTE* _pbyteOutput; + const JlsParameters& _info; + std::vector _templine; + TRANSFORM _transform; + typename TRANSFORM::INVERSE _inverseTransform; +}; + + + +#endif diff --git a/gdcm/Utilities/gdcmcharls/publictypes.h b/gdcm/Utilities/gdcmcharls/publictypes.h new file mode 100644 index 0000000..612738c --- /dev/null +++ b/gdcm/Utilities/gdcmcharls/publictypes.h @@ -0,0 +1,76 @@ +// +// (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. +// +#ifndef CHARLS_PUBLICTYPES +#define CHARLS_PUBLICTYPES + +#include "config.h" + +enum JLS_ERROR +{ + OK = 0, + InvalidJlsParameters, + ParameterValueNotSupported, + UncompressedBufferTooSmall, + CompressedBufferTooSmall, + InvalidCompressedData, + TooMuchCompressedData, + ImageTypeNotSupported, + UnsupportedBitDepthForTransform, + UnsupportedColorTransform +}; + + +enum interleavemode +{ + ILV_NONE = 0, + ILV_LINE = 1, + ILV_SAMPLE = 2 +}; + + +struct JlsCustomParameters +{ + int MAXVAL; + int T1; + int T2; + int T3; + int RESET; +}; + + +struct JlsRect +{ + int X, Y; + int Width, Height; +}; + + +struct JfifParameters +{ + int Ver; + char units; + int XDensity; + int YDensity; + short Xthumb; + short Ythumb; + void* pdataThumbnail; // user must set buffer which size is Xthumb*Ythumb*3(RGB) before JpegLsDecode() +}; + + +struct JlsParameters +{ + int width; + int height; + int bitspersample; + int bytesperline; // for [source (at encoding)][decoded (at decoding)] pixel image in user buffer + int components; + int allowedlossyerror; + enum interleavemode ilv; + int colorTransform; + char outputBgr; + struct JlsCustomParameters custom; + struct JfifParameters jfif; +}; + +#endif diff --git a/gdcm/Utilities/gdcmcharls/scan.h b/gdcm/Utilities/gdcmcharls/scan.h new file mode 100644 index 0000000..b083c4b --- /dev/null +++ b/gdcm/Utilities/gdcmcharls/scan.h @@ -0,0 +1,865 @@ +// +// (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. +// + +#ifndef CHARLS_SCAN +#define CHARLS_SCAN + +#include "lookuptable.h" + +// This file contains the code for handling a "scan". Usually an image is encoded as a single scan. + + +#ifdef _MSC_VER +#pragma warning (disable: 4127) +#endif + + +extern CTable decodingTables[16]; +extern std::vector rgquant8Ll; +extern std::vector rgquant10Ll; +extern std::vector rgquant12Ll; +extern std::vector rgquant16Ll; +// +// Apply +// +inlinehint LONG ApplySign(LONG i, LONG sign) +{ return (sign ^ i) - sign; } + + + +// Two alternatives for GetPredictedValue() (second is slightly faster due to reduced branching) + +#if 0 + +inlinehint LONG GetPredictedValue(LONG Ra, LONG Rb, LONG Rc) +{ + if (Ra < Rb) + { + if (Rc < Ra) + return Rb; + + if (Rc > Rb) + return Ra; + } + else + { + if (Rc < Rb) + return Ra; + + if (Rc > Ra) + return Rb; + } + + return Ra + Rb - Rc; +} + +#else + +inlinehint LONG GetPredictedValue(LONG Ra, LONG Rb, LONG Rc) +{ + // sign trick reduces the number of if statements (branches) + LONG sgn = BitWiseSign(Rb - Ra); + + // is Ra between Rc and Rb? + if ((sgn ^ (Rc - Ra)) < 0) + { + return Rb; + } + else if ((sgn ^ (Rb - Rc)) < 0) + { + return Ra; + } + + // default case, valid if Rc element of [Ra,Rb] + return Ra + Rb - Rc; +} + +#endif + +inlinehint LONG UnMapErrVal(LONG mappedError) +{ + //LONG sign = ~((mappedError & 1) - 1); + LONG sign = LONG(mappedError << (LONG_BITCOUNT-1)) >> (LONG_BITCOUNT-1); + return sign ^ (mappedError >> 1); +} + + + +inlinehint LONG GetMappedErrVal(LONG Errval) +{ + LONG mappedError = (Errval >> (LONG_BITCOUNT-2)) ^ (2 * Errval); + return mappedError; +} + + + +inlinehint LONG ComputeContextID(LONG Q1, LONG Q2, LONG Q3) +{ return (Q1*9 + Q2)*9 + Q3; } + + +// +// +// +template +class JlsCodec : public STRATEGY +{ +public: + typedef typename TRAITS::PIXEL PIXEL; + typedef typename TRAITS::SAMPLE SAMPLE; + +public: + + JlsCodec(const TRAITS& inTraits, const JlsParameters& info) : STRATEGY(info), + traits(inTraits), + _rect(), + _width(0), + T1(0), + T2(0), + T3(0), + _RUNindex(0), + _pquant(0), + _bCompare(0) + + { + if (Info().ilv == ILV_NONE) + { + Info().components = 1; + } + } + + + void SetPresets(const JlsCustomParameters& presets) + { + JlsCustomParameters presetDefault = ComputeDefault(traits.MAXVAL, traits.NEAR); + + InitParams(presets.T1 != 0 ? presets.T1 : presetDefault.T1, + presets.T2 != 0 ? presets.T2 : presetDefault.T2, + presets.T3 != 0 ? presets.T3 : presetDefault.T3, + presets.RESET != 0 ? presets.RESET : presetDefault.RESET); + } + + + bool IsInterleaved() + { + if (Info().ilv == ILV_NONE) + return false; + + if (Info().components == 1) + return false; + + return true; + } + + JlsParameters& Info() { return STRATEGY::_info; } + + signed char QuantizeGratientOrg(LONG Di); + inlinehint LONG QuantizeGratient(LONG Di) + { + ASSERT(QuantizeGratientOrg(Di) == *(_pquant + Di)); + return *(_pquant + Di); + } + + void InitQuantizationLUT(); + + LONG DecodeValue(LONG k, LONG limit, LONG qbpp); + inlinehint void EncodeMappedValue(LONG k, LONG mappedError, LONG limit); + + void IncrementRunIndex() + { _RUNindex = MIN(31,_RUNindex + 1); } + void DecrementRunIndex() + { _RUNindex = MAX(0,_RUNindex - 1); } + + LONG DecodeRIError(CContextRunMode& ctx); + Triplet DecodeRIPixel(Triplet Ra, Triplet Rb); + SAMPLE DecodeRIPixel(LONG Ra, LONG Rb); + LONG DecodeRunPixels(PIXEL Ra, PIXEL* ptype, LONG cpixelMac); + LONG DoRunMode(LONG index, DecoderStrategy*); + + void EncodeRIError(CContextRunMode& ctx, LONG Errval); + SAMPLE EncodeRIPixel(LONG x, LONG Ra, LONG Rb); + Triplet EncodeRIPixel(Triplet x, Triplet Ra, Triplet Rb); + void EncodeRunPixels(LONG runLength, bool bEndofline); + LONG DoRunMode(LONG index, EncoderStrategy*); + + inlinehint SAMPLE DoRegular(LONG Qs, LONG, LONG pred, DecoderStrategy*); + inlinehint SAMPLE DoRegular(LONG Qs, LONG x, LONG pred, EncoderStrategy*); + + void DoLine(SAMPLE* pdummy); + void DoLine(Triplet* pdummy); + void DoScan(BYTE* compressedBytes, size_t compressedLength); + +public: + ProcessLine* CreateProcess(void* pvoidOut); + void InitDefault(); + void InitParams(LONG t1, LONG t2, LONG t3, LONG nReset); + + size_t EncodeScan(const void* rawData, void* pvoidOut, size_t compressedLength, void* pvoidCompare); + size_t DecodeScan(void* rawData, const JlsRect& size, const void* compressedData, size_t compressedLength, bool bCompare); + +protected: + // codec parameters + TRAITS traits; + JlsRect _rect; + int _width; + LONG T1; + LONG T2; + LONG T3; + + // compression context + JlsContext _contexts[365]; + CContextRunMode _contextRunmode[2]; + LONG _RUNindex; + PIXEL* _previousLine; // previous line ptr + PIXEL* _currentLine; // current line ptr + + + // quantization lookup table + signed char* _pquant; + std::vector _rgquant; + + // debugging + bool _bCompare; +}; + + +// Encode/decode a single sample. Performancewise the #1 important functions + +template +typename TRAITS::SAMPLE JlsCodec::DoRegular(LONG Qs, LONG, LONG pred, DecoderStrategy*) +{ + LONG sign = BitWiseSign(Qs); + JlsContext& ctx = _contexts[ApplySign(Qs, sign)]; + LONG k = ctx.GetGolomb(); + LONG Px = traits.CorrectPrediction(pred + ApplySign(ctx.C, sign)); + + LONG ErrVal; + const Code& code = decodingTables[k].Get(STRATEGY::PeekByte()); + if (code.GetLength() != 0) + { + STRATEGY::Skip(code.GetLength()); + ErrVal = code.GetValue(); + ASSERT(abs(ErrVal) < 65535); + } + else + { + ErrVal = UnMapErrVal(DecodeValue(k, traits.LIMIT, traits.qbpp)); + if (abs(ErrVal) > 65535) + throw JlsException(InvalidCompressedData); + } + ErrVal = ErrVal ^ ((traits.NEAR == 0) ? ctx.GetErrorCorrection(k) : 0); + ctx.UpdateVariables(ErrVal, traits.NEAR, traits.RESET); + ErrVal = ApplySign(ErrVal, sign); + return traits.ComputeReconstructedSample(Px, ErrVal); +} + + +template +typename TRAITS::SAMPLE JlsCodec::DoRegular(LONG Qs, LONG x, LONG pred, EncoderStrategy*) +{ + LONG sign = BitWiseSign(Qs); + JlsContext& ctx = _contexts[ApplySign(Qs, sign)]; + LONG k = ctx.GetGolomb(); + LONG Px = traits.CorrectPrediction(pred + ApplySign(ctx.C, sign)); + + LONG ErrVal = traits.ComputeErrVal(ApplySign(x - Px, sign)); + + EncodeMappedValue(k, GetMappedErrVal(ctx.GetErrorCorrection(k | traits.NEAR) ^ ErrVal), traits.LIMIT); + ctx.UpdateVariables(ErrVal, traits.NEAR, traits.RESET); + ASSERT(traits.IsNear(traits.ComputeReconstructedSample(Px, ApplySign(ErrVal, sign)), x)); + return static_cast(traits.ComputeReconstructedSample(Px, ApplySign(ErrVal, sign))); +} + + +// Functions to build tables used to decode short golomb codes. + +inlinehint std::pair CreateEncodedValue(LONG k, LONG mappedError) +{ + LONG highbits = mappedError >> k; + return std::make_pair(highbits + k + 1, (LONG(1) << k) | (mappedError & ((LONG(1) << k) - 1))); +} + + +CTable InitTable(LONG k) +{ + CTable table; + for (short nerr = 0; ; nerr++) + { + // Q is not used when k != 0 + LONG merrval = GetMappedErrVal(nerr);//, k, -1); + std::pair paircode = CreateEncodedValue(k, merrval); + if (paircode.first > CTable::cbit) + break; + + Code code = Code( nerr, short(paircode.first) ); + table.AddEntry(BYTE(paircode.second), code); + } + + for (short nerr = -1; ; nerr--) + { + // Q is not used when k != 0 + LONG merrval = GetMappedErrVal(nerr);//, k, -1); + std::pair paircode = CreateEncodedValue(k, merrval); + if (paircode.first > CTable::cbit) + break; + + Code code = Code(nerr, short(paircode.first)); + table.AddEntry(BYTE(paircode.second), code); + } + + return table; +} + + +// Encoding/decoding of golomb codes + +template +LONG JlsCodec::DecodeValue(LONG k, LONG limit, LONG qbpp) +{ + LONG highbits = STRATEGY::ReadHighbits(); + + if (highbits >= limit - (qbpp + 1)) + return STRATEGY::ReadValue(qbpp) + 1; + + if (k == 0) + return highbits; + + return (highbits << k) + STRATEGY::ReadValue(k); +} + + + +template +inlinehint void JlsCodec::EncodeMappedValue(LONG k, LONG mappedError, LONG limit) +{ + LONG highbits = mappedError >> k; + + if (highbits < limit - traits.qbpp - 1) + { + if (highbits + 1 > 31) + { + STRATEGY::AppendToBitStream(0, highbits / 2); + highbits = highbits - highbits / 2; + } + STRATEGY::AppendToBitStream(1, highbits + 1); + STRATEGY::AppendToBitStream((mappedError & ((1 << k) - 1)), k); + return; + } + + if (limit - traits.qbpp > 31) + { + STRATEGY::AppendToBitStream(0, 31); + STRATEGY::AppendToBitStream(1, limit - traits.qbpp - 31); + } + else + { + STRATEGY::AppendToBitStream(1, limit - traits.qbpp); + } + STRATEGY::AppendToBitStream((mappedError - 1) & ((1 << traits.qbpp) - 1), traits.qbpp); +} + + +// Sets up a lookup table to "Quantize" sample difference. + +template +void JlsCodec::InitQuantizationLUT() +{ + // for lossless mode with default parameters, we have precomputed te luts for bitcounts 8,10,12 and 16 + if (traits.NEAR == 0 && traits.MAXVAL == (1 << traits.bpp) - 1) + { + JlsCustomParameters presets = ComputeDefault(traits.MAXVAL, traits.NEAR); + if (presets.T1 == T1 && presets.T2 == T2 && presets.T3 == T3) + { + if (traits.bpp == 8) + { + _pquant = &rgquant8Ll[rgquant8Ll.size() / 2 ]; + return; + } + if (traits.bpp == 10) + { + _pquant = &rgquant10Ll[rgquant10Ll.size() / 2 ]; + return; + } + if (traits.bpp == 12) + { + _pquant = &rgquant12Ll[rgquant12Ll.size() / 2 ]; + return; + } + if (traits.bpp == 16) + { + _pquant = &rgquant16Ll[rgquant16Ll.size() / 2 ]; + return; + } + } + } + + LONG RANGE = 1 << traits.bpp; + + _rgquant.resize(RANGE * 2); + + _pquant = &_rgquant[RANGE]; + for (LONG i = -RANGE; i < RANGE; ++i) + { + _pquant[i] = QuantizeGratientOrg(i); + } +} + + +template +signed char JlsCodec::QuantizeGratientOrg(LONG Di) +{ + if (Di <= -T3) return -4; + if (Di <= -T2) return -3; + if (Di <= -T1) return -2; + if (Di < -traits.NEAR) return -1; + if (Di <= traits.NEAR) return 0; + if (Di < T1) return 1; + if (Di < T2) return 2; + if (Di < T3) return 3; + + return 4; +} + + + +// RI = Run interruption: functions that handle the sample terminating a run. + +template +LONG JlsCodec::DecodeRIError(CContextRunMode& ctx) +{ + LONG k = ctx.GetGolomb(); + LONG EMErrval = DecodeValue(k, traits.LIMIT - J[_RUNindex]-1, traits.qbpp); + LONG Errval = ctx.ComputeErrVal(EMErrval + ctx._nRItype, k); + ctx.UpdateVariables(Errval, EMErrval); + return Errval; +} + + + +template +void JlsCodec::EncodeRIError(CContextRunMode& ctx, LONG Errval) +{ + LONG k = ctx.GetGolomb(); + bool map = ctx.ComputeMap(Errval, k); + LONG EMErrval = 2 * abs(Errval) - ctx._nRItype - map; + + ASSERT(Errval == ctx.ComputeErrVal(EMErrval + ctx._nRItype, k)); + EncodeMappedValue(k, EMErrval, traits.LIMIT-J[_RUNindex]-1); + ctx.UpdateVariables(Errval, EMErrval); +} + + +template +Triplet JlsCodec::DecodeRIPixel(Triplet Ra, Triplet Rb) +{ + LONG Errval1 = DecodeRIError(_contextRunmode[0]); + LONG Errval2 = DecodeRIError(_contextRunmode[0]); + LONG Errval3 = DecodeRIError(_contextRunmode[0]); + + return Triplet(traits.ComputeReconstructedSample(Rb.v1, Errval1 * Sign(Rb.v1 - Ra.v1)), + traits.ComputeReconstructedSample(Rb.v2, Errval2 * Sign(Rb.v2 - Ra.v2)), + traits.ComputeReconstructedSample(Rb.v3, Errval3 * Sign(Rb.v3 - Ra.v3))); +} + + + +template +Triplet JlsCodec::EncodeRIPixel(Triplet x, Triplet Ra, Triplet Rb) +{ + LONG errval1 = traits.ComputeErrVal(Sign(Rb.v1 - Ra.v1) * (x.v1 - Rb.v1)); + EncodeRIError(_contextRunmode[0], errval1); + + LONG errval2 = traits.ComputeErrVal(Sign(Rb.v2 - Ra.v2) * (x.v2 - Rb.v2)); + EncodeRIError(_contextRunmode[0], errval2); + + LONG errval3 = traits.ComputeErrVal(Sign(Rb.v3 - Ra.v3) * (x.v3 - Rb.v3)); + EncodeRIError(_contextRunmode[0], errval3); + + + return Triplet(traits.ComputeReconstructedSample(Rb.v1, errval1 * Sign(Rb.v1 - Ra.v1)), + traits.ComputeReconstructedSample(Rb.v2, errval2 * Sign(Rb.v2 - Ra.v2)), + traits.ComputeReconstructedSample(Rb.v3, errval3 * Sign(Rb.v3 - Ra.v3))); +} + + + +template +typename TRAITS::SAMPLE JlsCodec::DecodeRIPixel(LONG Ra, LONG Rb) +{ + if (abs(Ra - Rb) <= traits.NEAR) + { + LONG ErrVal = DecodeRIError(_contextRunmode[1]); + return static_cast(traits.ComputeReconstructedSample(Ra, ErrVal)); + } + else + { + LONG ErrVal = DecodeRIError(_contextRunmode[0]); + return static_cast(traits.ComputeReconstructedSample(Rb, ErrVal * Sign(Rb - Ra))); + } +} + + +template +typename TRAITS::SAMPLE JlsCodec::EncodeRIPixel(LONG x, LONG Ra, LONG Rb) +{ + if (abs(Ra - Rb) <= traits.NEAR) + { + LONG ErrVal = traits.ComputeErrVal(x - Ra); + EncodeRIError(_contextRunmode[1], ErrVal); + return static_cast(traits.ComputeReconstructedSample(Ra, ErrVal)); + } + else + { + LONG ErrVal = traits.ComputeErrVal((x - Rb) * Sign(Rb - Ra)); + EncodeRIError(_contextRunmode[0], ErrVal); + return static_cast(traits.ComputeReconstructedSample(Rb, ErrVal * Sign(Rb - Ra))); + } +} + + +// RunMode: Functions that handle run-length encoding + +template +void JlsCodec::EncodeRunPixels(LONG runLength, bool endOfLine) +{ + while (runLength >= LONG(1 << J[_RUNindex])) + { + STRATEGY::AppendOnesToBitStream(1); + runLength = runLength - LONG(1 << J[_RUNindex]); + IncrementRunIndex(); + } + + if (endOfLine) + { + if (runLength != 0) + { + STRATEGY::AppendOnesToBitStream(1); + } + } + else + { + STRATEGY::AppendToBitStream(runLength, J[_RUNindex] + 1); // leading 0 + actual remaining length + } +} + + +template +LONG JlsCodec::DecodeRunPixels(PIXEL Ra, PIXEL* startPos, LONG cpixelMac) +{ + LONG index = 0; + while (STRATEGY::ReadBit()) + { + int count = MIN(1 << J[_RUNindex], int(cpixelMac - index)); + index += count; + ASSERT(index <= cpixelMac); + + if (count == (1 << J[_RUNindex])) + { + IncrementRunIndex(); + } + + if (index == cpixelMac) + break; + } + + + if (index != cpixelMac) + { + // incomplete run + index += (J[_RUNindex] > 0) ? STRATEGY::ReadValue(J[_RUNindex]) : 0; + } + + if (index > cpixelMac) + throw JlsException(InvalidCompressedData); + + for (LONG i = 0; i < index; ++i) + { + startPos[i] = Ra; + } + + return index; +} + +template +LONG JlsCodec::DoRunMode(LONG index, EncoderStrategy*) +{ + LONG ctypeRem = _width - index; + PIXEL* ptypeCurX = _currentLine + index; + PIXEL* ptypePrevX = _previousLine + index; + + PIXEL Ra = ptypeCurX[-1]; + + LONG runLength = 0; + + while (traits.IsNear(ptypeCurX[runLength],Ra)) + { + ptypeCurX[runLength] = Ra; + runLength++; + + if (runLength == ctypeRem) + break; + } + + EncodeRunPixels(runLength, runLength == ctypeRem); + + if (runLength == ctypeRem) + return runLength; + + ptypeCurX[runLength] = EncodeRIPixel(ptypeCurX[runLength], Ra, ptypePrevX[runLength]); + DecrementRunIndex(); + return runLength + 1; +} + + +template +LONG JlsCodec::DoRunMode(LONG startIndex, DecoderStrategy*) +{ + PIXEL Ra = _currentLine[startIndex-1]; + + LONG runLength = DecodeRunPixels(Ra, _currentLine + startIndex, _width - startIndex); + LONG endIndex = startIndex + runLength; + + if (endIndex == _width) + return endIndex - startIndex; + + // run interruption + PIXEL Rb = _previousLine[endIndex]; + _currentLine[endIndex] = DecodeRIPixel(Ra, Rb); + DecrementRunIndex(); + return endIndex - startIndex + 1; +} + + +// DoLine: Encodes/Decodes a scanline of samples + +template +void JlsCodec::DoLine(SAMPLE*) +{ + LONG index = 0; + LONG Rb = _previousLine[index-1]; + LONG Rd = _previousLine[index]; + + while(index < _width) + { + LONG Ra = _currentLine[index -1]; + LONG Rc = Rb; + Rb = Rd; + Rd = _previousLine[index + 1]; + + LONG Qs = ComputeContextID(QuantizeGratient(Rd - Rb), QuantizeGratient(Rb - Rc), QuantizeGratient(Rc - Ra)); + + if (Qs != 0) + { + _currentLine[index] = DoRegular(Qs, _currentLine[index], GetPredictedValue(Ra, Rb, Rc), (STRATEGY*)(NULL)); + index++; + } + else + { + index += DoRunMode(index, (STRATEGY*)(NULL)); + Rb = _previousLine[index-1]; + Rd = _previousLine[index]; + } + } +} + + +// DoLine: Encodes/Decodes a scanline of triplets in ILV_SAMPLE mode + +template +void JlsCodec::DoLine(Triplet*) +{ + LONG index = 0; + while(index < _width) + { + Triplet Ra = _currentLine[index -1]; + Triplet Rc = _previousLine[index-1]; + Triplet Rb = _previousLine[index]; + Triplet Rd = _previousLine[index + 1]; + + LONG Qs1 = ComputeContextID(QuantizeGratient(Rd.v1 - Rb.v1), QuantizeGratient(Rb.v1 - Rc.v1), QuantizeGratient(Rc.v1 - Ra.v1)); + LONG Qs2 = ComputeContextID(QuantizeGratient(Rd.v2 - Rb.v2), QuantizeGratient(Rb.v2 - Rc.v2), QuantizeGratient(Rc.v2 - Ra.v2)); + LONG Qs3 = ComputeContextID(QuantizeGratient(Rd.v3 - Rb.v3), QuantizeGratient(Rb.v3 - Rc.v3), QuantizeGratient(Rc.v3 - Ra.v3)); + + + if (Qs1 == 0 && Qs2 == 0 && Qs3 == 0) + { + index += DoRunMode(index, (STRATEGY*)(NULL)); + } + else + { + Triplet Rx; + Rx.v1 = DoRegular(Qs1, _currentLine[index].v1, GetPredictedValue(Ra.v1, Rb.v1, Rc.v1), (STRATEGY*)(NULL)); + Rx.v2 = DoRegular(Qs2, _currentLine[index].v2, GetPredictedValue(Ra.v2, Rb.v2, Rc.v2), (STRATEGY*)(NULL)); + Rx.v3 = DoRegular(Qs3, _currentLine[index].v3, GetPredictedValue(Ra.v3, Rb.v3, Rc.v3), (STRATEGY*)(NULL)); + _currentLine[index] = Rx; + index++; + } + } +} + + +// DoScan: Encodes or decodes a scan. +// In ILV_SAMPLE mode, multiple components are handled in DoLine +// In ILV_LINE mode, a call do DoLine is made for every component +// In ILV_NONE mode, DoScan is called for each component + +template +void JlsCodec::DoScan(BYTE* compressedBytes, size_t compressedLength) +{ + _width = Info().width; + + STRATEGY::Init(compressedBytes, compressedLength); + + LONG pixelstride = _width + 4; + int components = Info().ilv == ILV_LINE ? Info().components : 1; + + std::vector vectmp(2 * components * pixelstride); + std::vector rgRUNindex(components); + + for (LONG line = 0; line < Info().height; ++line) + { + _previousLine = &vectmp[1]; + _currentLine = &vectmp[1 + components * pixelstride]; + if ((line & 1) == 1) + { + std::swap(_previousLine, _currentLine); + } + + STRATEGY::OnLineBegin(_width, _currentLine, pixelstride); + + for (int component = 0; component < components; ++component) + { + _RUNindex = rgRUNindex[component]; + + // initialize edge pixels used for prediction + _previousLine[_width] = _previousLine[_width - 1]; + _currentLine[-1] = _previousLine[0]; + DoLine((PIXEL*) NULL); // dummy arg for overload resolution + + rgRUNindex[component] = _RUNindex; + _previousLine += pixelstride; + _currentLine += pixelstride; + } + + if (_rect.Y <= line && line < _rect.Y + _rect.Height) + { + STRATEGY::OnLineEnd(_rect.Width, _currentLine + _rect.X - (components * pixelstride), pixelstride); + } + } + + STRATEGY::EndScan(); +} + + +// Factory function for ProcessLine objects to copy/transform unencoded pixels to/from our scanline buffers. + +template +ProcessLine* JlsCodec::CreateProcess(void* pvoidOut) +{ + if (!IsInterleaved()) + return new PostProcesSingleComponent(pvoidOut, Info(), sizeof(typename TRAITS::PIXEL)); + + if (Info().colorTransform == 0) + return new ProcessTransformed >(pvoidOut, Info(), TransformNone()); + + if (Info().bitspersample == sizeof(SAMPLE)*8) + { + switch(Info().colorTransform) + { + case COLORXFORM_HP1 : return new ProcessTransformed >(pvoidOut, Info(), TransformHp1()); break; + case COLORXFORM_HP2 : return new ProcessTransformed >(pvoidOut, Info(), TransformHp2()); break; + case COLORXFORM_HP3 : return new ProcessTransformed >(pvoidOut, Info(), TransformHp3()); break; + default: throw JlsException(UnsupportedColorTransform); + } + } + else if (Info().bitspersample > 8) + { + int shift = 16 - Info().bitspersample; + switch(Info().colorTransform) + { + case COLORXFORM_HP1 : return new ProcessTransformed > >(pvoidOut, Info(), TransformShifted >(shift)); break; + case COLORXFORM_HP2 : return new ProcessTransformed > >(pvoidOut, Info(), TransformShifted >(shift)); break; + case COLORXFORM_HP3 : return new ProcessTransformed > >(pvoidOut, Info(), TransformShifted >(shift)); break; + default: throw JlsException(UnsupportedColorTransform); + } + } + throw JlsException(UnsupportedBitDepthForTransform); +} + + + +// Setup codec for encoding and calls DoScan + +template +size_t JlsCodec::EncodeScan(const void* rawData, void* compressedData, size_t compressedLength, void* pvoidCompare) +{ + STRATEGY::_processLine = std::auto_ptr(CreateProcess(const_cast(rawData))); + + BYTE* compressedBytes = static_cast(compressedData); + + if (pvoidCompare != NULL) + { + STRATEGY::_qdecoder = std::auto_ptr(new JlsCodec(traits, Info())); + STRATEGY::_qdecoder->Init((BYTE*)pvoidCompare, compressedLength); + } + + DoScan(compressedBytes, compressedLength); + + return STRATEGY::GetLength(); + +} + +// Setup codec for decoding and calls DoScan + +template +size_t JlsCodec::DecodeScan(void* rawData, const JlsRect& rect, const void* compressedData, size_t compressedLength, bool bCompare) +{ + STRATEGY::_processLine = std::auto_ptr(CreateProcess(rawData)); + + BYTE* compressedBytes = const_cast(static_cast(compressedData)); + _bCompare = bCompare; + + BYTE rgbyte[20]; + + size_t readBytes = 0; + ::memcpy(rgbyte, compressedBytes, 4); + readBytes += 4; + + size_t cbyteScanheader = rgbyte[3] - 2; + + if (cbyteScanheader > sizeof(rgbyte)) + throw JlsException(InvalidCompressedData); + + ::memcpy(rgbyte, compressedBytes, cbyteScanheader); + readBytes += cbyteScanheader; + + _rect = rect; + + DoScan(compressedBytes + readBytes, compressedLength - readBytes); + + return STRATEGY::GetCurBytePos() - compressedBytes; +} + +// Initialize the codec data structures. Depends on JPEG-LS parameters like T1-T3. + +template +void JlsCodec::InitParams(LONG t1, LONG t2, LONG t3, LONG nReset) +{ + T1 = t1; + T2 = t2; + T3 = t3; + + InitQuantizationLUT(); + + LONG A = MAX(2, (traits.RANGE + 32)/64); + for (unsigned int Q = 0; Q < sizeof(_contexts) / sizeof(_contexts[0]); ++Q) + { + _contexts[Q] = JlsContext(A); + } + + _contextRunmode[0] = CContextRunMode(MAX(2, (traits.RANGE + 32)/64), 0, nReset); + _contextRunmode[1] = CContextRunMode(MAX(2, (traits.RANGE + 32)/64), 1, nReset); + _RUNindex = 0; +} + +#endif diff --git a/gdcm/Utilities/gdcmcharls/stdafx.cpp b/gdcm/Utilities/gdcmcharls/stdafx.cpp new file mode 100644 index 0000000..e69de29 diff --git a/gdcm/Utilities/gdcmcharls/streams.h b/gdcm/Utilities/gdcmcharls/streams.h new file mode 100644 index 0000000..ee8dbd3 --- /dev/null +++ b/gdcm/Utilities/gdcmcharls/streams.h @@ -0,0 +1,156 @@ +// +// (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. +// +#ifndef CHARLS_STREAMS +#define CHARLS_STREAMS + +#include +#include +#include "util.h" + + + +// This file defines JPEG-LS streams: The header and the actual pixel data. Header markers have fixed length, the pixeldata not. + + + +class JpegSegment; + +enum JPEGLS_ColorXForm +{ + // default (RGB) + COLORXFORM_NONE = 0, + + // Color transforms as defined by HP + COLORXFORM_HP1, + COLORXFORM_HP2, + COLORXFORM_HP3, + + // Defined by HP but not supported by CharLS + COLORXFORM_RGB_AS_YUV_LOSSY, + COLORXFORM_MATRIX +}; + +// +// JLSOutputStream: minimal implementation to write JPEG header streams +// +class JLSOutputStream +{ + friend class JpegMarkerSegment; + friend class JpegImageDataSegment; + +public: + JLSOutputStream(); + virtual ~JLSOutputStream(); + + void Init(Size size, LONG bitsPerSample, LONG ccomp); + void AddScan(const void* compareData, const JlsParameters* pparams); + void AddLSE(const JlsCustomParameters* pcustom); + void AddColorTransform(int i); + size_t GetBytesWritten() + { return _cbyteOffset; } + + size_t GetLength() + { return _cbyteLength - _cbyteOffset; } + + size_t Write(BYTE* pdata, size_t cbyteLength); + + void EnableCompare(bool bCompare) + { _bCompare = bCompare; } +private: + BYTE* GetPos() const + { return _pdata + _cbyteOffset; } + + void WriteByte(BYTE val) + { + ASSERT(!_bCompare || _pdata[_cbyteOffset] == val); + + _pdata[_cbyteOffset++] = val; + } + + void WriteBytes(const std::vector& rgbyte) + { + for (size_t i = 0; i < rgbyte.size(); ++i) + { + WriteByte(rgbyte[i]); + } + } + + void WriteWord(USHORT val) + { + WriteByte(BYTE(val / 0x100)); + WriteByte(BYTE(val % 0x100)); + } + + + void Seek(size_t byteCount) + { _cbyteOffset += byteCount; } + + bool _bCompare; + +private: + BYTE* _pdata; + size_t _cbyteOffset; + size_t _cbyteLength; + LONG _icompLast; + std::vector _segments; +}; + + +// +// JLSInputStream: minimal implementation to read JPEG header streams +// +class JLSInputStream +{ +public: + JLSInputStream(const BYTE* pdata, size_t cbyteLength); + + size_t GetBytesRead() + { return _cbyteOffset; } + + const JlsParameters& GetMetadata() const + { return _info; } + + const JlsCustomParameters& GetCustomPreset() const + { return _info.custom; } + + void Read(void* pvoid, size_t cbyteAvailable); + void ReadHeader(); + + void EnableCompare(bool bCompare) + { _bCompare = bCompare; } + + void SetInfo(JlsParameters* info) { _info = *info; } + + void SetRect(JlsRect rect) { _rect = rect; } + +private: + void ReadPixels(void* pvoid, size_t cbyteAvailable); + void ReadScan(void*); + void ReadStartOfScan(); + void ReadPresetParameters(); + void ReadComment(); + void ReadStartOfFrame(); + BYTE ReadByte(); + int ReadWord(); + void ReadNBytes(std::vector& dst, int byteCount); + + // JFIF + void ReadJfif(); + // Color Transform Application Markers & Code Stream (HP extension) + void ReadColorSpace(); + void ReadColorXForm(); + +private: + const BYTE* _pdata; + size_t _cbyteOffset; + size_t _cbyteLength; + bool _bCompare; + JlsParameters _info; + JlsRect _rect; +}; + + + + +#endif diff --git a/gdcm/Utilities/gdcmcharls/util.h b/gdcm/Utilities/gdcmcharls/util.h new file mode 100644 index 0000000..892cc47 --- /dev/null +++ b/gdcm/Utilities/gdcmcharls/util.h @@ -0,0 +1,148 @@ +// +// (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. +// + + +#ifndef CHARLS_UTIL +#define CHARLS_UTIL + +#include +#include +#include "publictypes.h" + + +#ifndef MAX +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) +#endif + +#ifndef MIN +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#endif + + +inline LONG log_2(LONG n) +{ + LONG x = 0; + while (n > (LONG(1) << x)) + { + ++x; + } + return x; + +} + +struct Size +{ + Size(LONG width, LONG height) : + cx(width), + cy(height) + {} + LONG cx; + LONG cy; +}; + + + +inline LONG Sign(LONG n) + { return (n >> (LONG_BITCOUNT-1)) | 1;} + +inline LONG BitWiseSign(LONG i) + { return i >> (LONG_BITCOUNT-1); } + + +template +struct Triplet +{ + Triplet() : + v1(0), + v2(0), + v3(0) + {} + + Triplet(LONG x1, LONG x2, LONG x3) : + v1((SAMPLE)x1), + v2((SAMPLE)x2), + v3((SAMPLE)x3) + {} + + union + { + SAMPLE v1; + SAMPLE R; + }; + union + { + SAMPLE v2; + SAMPLE G; + }; + union + { + SAMPLE v3; + SAMPLE B; + }; +}; + +inline bool operator==(const Triplet& lhs, const Triplet& rhs) + { return lhs.v1 == rhs.v1 && lhs.v2 == rhs.v2 && lhs.v3 == rhs.v3; } + +inline bool operator!=(const Triplet& lhs, const Triplet& rhs) + { return !(lhs == rhs); } + + +template +struct Quad : public Triplet +{ + Quad() : + v4(0) + {} + + Quad(Triplet triplet, LONG alpha) : Triplet(triplet), A((sample)alpha) + {} + + union + { + sample v4; + sample A; + }; +}; + + + +template +struct FromBigEndian +{ +}; + +template <> +struct FromBigEndian<4> +{ + inlinehint static unsigned int Read(BYTE* pbyte) + { + return (pbyte[0] << 24) + (pbyte[1] << 16) + (pbyte[2] << 8) + (pbyte[3] << 0); + } +}; + + + +template <> +struct FromBigEndian<8> +{ + inlinehint static uint64_t Read(BYTE* pbyte) + { + return (uint64_t(pbyte[0]) << 56) + (uint64_t(pbyte[1]) << 48) + (uint64_t(pbyte[2]) << 40) + (uint64_t(pbyte[3]) << 32) + + (uint64_t(pbyte[4]) << 24) + (uint64_t(pbyte[5]) << 16) + (uint64_t(pbyte[6]) << 8) + (uint64_t(pbyte[7]) << 0); + } +}; + + +class JlsException +{ +public: + JlsException(JLS_ERROR error) : _error(error) + { } + + JLS_ERROR _error; +}; + + +#endif diff --git a/gdcm/Utilities/gdcmexpat/.NoDartCoverage b/gdcm/Utilities/gdcmexpat/.NoDartCoverage new file mode 100644 index 0000000..3c99729 --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/.NoDartCoverage @@ -0,0 +1 @@ +# do not do coverage in this directory diff --git a/gdcm/Utilities/gdcmexpat/CMakeLists.txt b/gdcm/Utilities/gdcmexpat/CMakeLists.txt new file mode 100644 index 0000000..80f7dd5 --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/CMakeLists.txt @@ -0,0 +1,49 @@ +cmake_minimum_required(VERSION 2.8.9) + +if(NOT EXPAT_NAMESPACE) + set(EXPAT_NAMESPACE "EXPAT") + set(EXPAT_STANDALONE 1) +endif() +# In all cases: +string(TOLOWER ${EXPAT_NAMESPACE} EXPAT_LIBRARY_NAME) + +project(${EXPAT_NAMESPACE} C) + +set(EXPAT_MAJOR_VERSION 2) +set(EXPAT_MINOR_VERSION 0) +set(EXPAT_BUILD_VERSION 0) +set(EXPAT_VERSION + "${EXPAT_MAJOR_VERSION}.${EXPAT_MINOR_VERSION}.${EXPAT_BUILD_VERSION}") + +set(EXPAT_LIBRARY_PROPERTIES ${EXPAT_LIBRARY_PROPERTIES} + VERSION "${EXPAT_VERSION}" + SOVERSION "${EXPAT_MAJOR_VERSION}.${EXPAT_MINOR_VERSION}" +) + +# Do full dependency headers. +include_regular_expression("^.*$") + +#if(WIN32) +# if(BUILD_SHARED_LIBS) +# set(EXPATDLL 1) +# else() +# set (EXPATSTATIC 1) +# endif() +#endif() + +#----------------------------------------------------------------------------- +include (${CMAKE_ROOT}/Modules/CheckIncludeFile.cmake) +# FIXME not the right way of doing it: +CHECK_INCLUDE_FILE("string.h" HAVE_MEMMOVE) + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/expat_config.h.in + ${CMAKE_CURRENT_BINARY_DIR}/expat_config.h) +set(MANGLE_PREFIX ${EXPAT_LIBRARY_NAME}) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/expat_mangle.h.in + ${CMAKE_CURRENT_BINARY_DIR}/expat_mangle.h + @ONLY ) + +# for expat_config.h +include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR}) +subdirs(lib) + diff --git a/gdcm/Utilities/gdcmexpat/COPYING b/gdcm/Utilities/gdcmexpat/COPYING new file mode 100644 index 0000000..dcb4506 --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/COPYING @@ -0,0 +1,22 @@ +Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd + and Clark Cooper +Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006 Expat maintainers. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/gdcm/Utilities/gdcmexpat/Changes b/gdcm/Utilities/gdcmexpat/Changes new file mode 100644 index 0000000..6381866 --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/Changes @@ -0,0 +1,148 @@ +Release 2.0.0 Wed Jan 11 2006 + - We no longer use the "check" library for C unit testing; we + always use the (partial) internal implementation of the API. + - Report XML_NS setting via XML_GetFeatureList(). + - Fixed headers for use from C++. + - XML_GetCurrentLineNumber() and XML_GetCurrentColumnNumber() + now return unsigned integers. + - Added XML_LARGE_SIZE switch to enable 64-bit integers for + byte indexes and line/column numbers. + - Updated to use libtool 1.5.22 (the most recent). + - Added support for AmigaOS. + - Some mostly minor bug fixes. SF issues include: 1006708, + 1021776, 1023646, 1114960, 1156398, 1221160, 1271642. + +Release 1.95.8 Fri Jul 23 2004 + - Major new feature: suspend/resume. Handlers can now request + that a parse be suspended for later resumption or aborted + altogether. See "Temporarily Stopping Parsing" in the + documentation for more details. + - Some mostly minor bug fixes, but compilation should no + longer generate warnings on most platforms. SF issues + include: 827319, 840173, 846309, 888329, 896188, 923913, + 928113, 961698, 985192. + +Release 1.95.7 Mon Oct 20 2003 + - Fixed enum XML_Status issue (reported on SourceForge many + times), so compilers that are properly picky will be happy. + - Introduced an XMLCALL macro to control the calling + convention used by the Expat API; this macro should be used + to annotate prototypes and definitions of callback + implementations in code compiled with a calling convention + other than the default convention for the host platform. + - Improved ability to build without the configure-generated + expat_config.h header. This is useful for applications + which embed Expat rather than linking in the library. + - Fixed a variety of bugs: see SF issues 458907, 609603, + 676844, 679754, 692878, 692964, 695401, 699323, 699487, + 820946. + - Improved hash table lookups. + - Added more regression tests and improved documentation. + +Release 1.95.6 Tue Jan 28 2003 + - Added XML_FreeContentModel(). + - Added XML_MemMalloc(), XML_MemRealloc(), XML_MemFree(). + - Fixed a variety of bugs: see SF issues 615606, 616863, + 618199, 653180, 673791. + - Enhanced the regression test suite. + - Man page improvements: includes SF issue 632146. + +Release 1.95.5 Fri Sep 6 2002 + - Added XML_UseForeignDTD() for improved SAX2 support. + - Added XML_GetFeatureList(). + - Defined XML_Bool type and the values XML_TRUE and XML_FALSE. + - Use an incomplete struct instead of a void* for the parser + (may not retain). + - Fixed UTF-8 decoding bug that caused legal UTF-8 to be rejected. + - Finally fixed bug where default handler would report DTD + events that were already handled by another handler. + Initial patch contributed by Darryl Miles. + - Removed unnecessary DllMain() function that caused static + linking into a DLL to be difficult. + - Added VC++ projects for building static libraries. + - Reduced line-length for all source code and headers to be + no longer than 80 characters, to help with AS/400 support. + - Reduced memory copying during parsing (SF patch #600964). + - Fixed a variety of bugs: see SF issues 580793, 434664, + 483514, 580503, 581069, 584041, 584183, 584832, 585537, + 596555, 596678, 598352, 598944, 599715, 600479, 600971. + +Release 1.95.4 Fri Jul 12 2002 + - Added support for VMS, contributed by Craig Berry. See + vms/README.vms for more information. + - Added Mac OS (classic) support, with a makefile for MPW, + contributed by Thomas Wegner and Daryle Walker. + - Added Borland C++ Builder 5 / BCC 5.5 support, contributed + by Patrick McConnell (SF patch #538032). + - Fixed a variety of bugs: see SF issues 441449, 563184, + 564342, 566334, 566901, 569461, 570263, 575168, 579196. + - Made skippedEntityHandler conform to SAX2 (see source comment) + - Re-implemented WFC: Entity Declared from XML 1.0 spec and + added a new error "entity declared in parameter entity": + see SF bug report 569461 and SF patch 578161 + - Re-implemented section 5.1 from XML 1.0 spec: + see SF bug report 570263 and SF patch 578161 + +Release 1.95.3 Mon Jun 3 2002 + - Added a project to the MSVC workspace to create a wchar_t + version of the library; the DLLs are named libexpatw.dll. + - Changed the name of the Windows DLLs from expat.dll to + libexpat.dll; this fixes SF bug #432456. + - Added the XML_ParserReset() API function. + - Fixed XML_SetReturnNSTriplet() to work for element names. + - Made the XML_UNICODE builds usable (thanks, Karl!). + - Allow xmlwf to read from standard input. + - Install a man page for xmlwf on Unix systems. + - Fixed many bugs; see SF bug reports 231864, 461380, 464837, + 466885, 469226, 477667, 484419, 487840, 494749, 496505, + 547350. Other bugs which we can't test as easily may also + have been fixed, especially in the area of build support. + +Release 1.95.2 Fri Jul 27 2001 + - More changes to make MSVC happy with the build; add a single + workspace to support both the library and xmlwf application. + - Added a Windows installer for Windows users; includes + xmlwf.exe. + - Added compile-time constants that can be used to determine the + Expat version + - Removed a lot of GNU-specific dependencies to aide portability + among the various Unix flavors. + - Fix the UTF-8 BOM bug. + - Cleaned up warning messages for several compilers. + - Added the -Wall, -Wstrict-prototypes options for GCC. + +Release 1.95.1 Sun Oct 22 15:11:36 EDT 2000 + - Changes to get expat to build under Microsoft compiler + - Removed all aborts and instead return an UNEXPECTED_STATE error. + - Fixed a bug where a stray '%' in an entity value would cause an + abort. + - Defined XML_SetEndNamespaceDeclHandler. Thanks to Darryl Miles for + finding this oversight. + - Changed default patterns in lib/Makefile.in to fit non-GNU makes + Thanks to robin@unrated.net for reporting and providing an + account to test on. + - The reference had the wrong label for XML_SetStartNamespaceDecl. + Reported by an anonymous user. + +Release 1.95.0 Fri Sep 29 2000 + - XML_ParserCreate_MM + Allows you to set a memory management suite to replace the + standard malloc,realloc, and free. + - XML_SetReturnNSTriplet + If you turn this feature on when namespace processing is in + effect, then qualified, prefixed element and attribute names + are returned as "uri|name|prefix" where '|' is whatever + separator character is used in namespace processing. + - Merged in features from perl-expat + o XML_SetElementDeclHandler + o XML_SetAttlistDeclHandler + o XML_SetXmlDeclHandler + o XML_SetEntityDeclHandler + o StartDoctypeDeclHandler takes 3 additional parameters: + sysid, pubid, has_internal_subset + o Many paired handler setters (like XML_SetElementHandler) + now have corresponding individual handler setters + o XML_GetInputContext for getting the input context of + the current parse position. + - Added reference material + - Packaged into a distribution that builds a sharable library diff --git a/gdcm/Utilities/gdcmexpat/README b/gdcm/Utilities/gdcmexpat/README new file mode 100644 index 0000000..585bcc1 --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/README @@ -0,0 +1,118 @@ + + Expat, Release 2.0.0 + +This is Expat, a C library for parsing XML, written by James Clark. +Expat is a stream-oriented XML parser. This means that you register +handlers with the parser before starting the parse. These handlers +are called when the parser discovers the associated structures in the +document being parsed. A start tag is an example of the kind of +structures for which you may register handlers. + +Windows users should use the expat_win32bin package, which includes +both precompiled libraries and executables, and source code for +developers. + +Expat is free software. You may copy, distribute, and modify it under +the terms of the License contained in the file COPYING distributed +with this package. This license is the same as the MIT/X Consortium +license. + +Versions of Expat that have an odd minor version (the middle number in +the release above), are development releases and should be considered +as beta software. Releases with even minor version numbers are +intended to be production grade software. + +If you are building Expat from a check-out from the CVS repository, +you need to run a script that generates the configure script using the +GNU autoconf and libtool tools. To do this, you need to have +autoconf 2.52 or newer and libtool 1.4 or newer. Run the script like +this: + + ./buildconf.sh + +Once this has been done, follow the same instructions as for building +from a source distribution. + +To build Expat from a source distribution, you first run the +configuration shell script in the top level distribution directory: + + ./configure + +There are many options which you may provide to configure (which you +can discover by running configure with the --help option). But the +one of most interest is the one that sets the installation directory. +By default, the configure script will set things up to install +libexpat into /usr/local/lib, expat.h into /usr/local/include, and +xmlwf into /usr/local/bin. If, for example, you'd prefer to install +into /home/me/mystuff/lib, /home/me/mystuff/include, and +/home/me/mystuff/bin, you can tell configure about that with: + + ./configure --prefix=/home/me/mystuff + +Another interesting option is to enable 64-bit integer support for +line and column numbers and the over-all byte index: + + ./configure CPPFLAGS=-DXML_LARGE_SIZE + +After running the configure script, the "make" command will build +things and "make install" will install things into their proper +location. Have a look at the "Makefile" to learn about additional +"make" options. Note that you need to have write permission into +the directories into which things will be installed. + +If you are interested in building Expat to provide document +information in UTF-16 rather than the default UTF-8, follow these +instructions: + + 1. For UTF-16 output as unsigned short (and version/error + strings as char), run: + + ./configure CPPFLAGS=-DXML_UNICODE + + For UTF-16 output as wchar_t (incl. version/error strings), + run: + + ./configure CFLAGS="-g -O2 -fshort-wchar" \ + CPPFLAGS=-DXML_UNICODE_WCHAR_T + + 2. Edit the MakeFile, changing: + + LIBRARY = libexpat.la + + to: + + LIBRARY = libexpatw.la + + (Note the additional "w" in the library name.) + + 3. Run "make buildlib" (which builds the library only). + + 4. Run "make installlib" (which installs the library only). + +Note for Solaris users: The "ar" command is usually located in +"/usr/ccs/bin", which is not in the default PATH. You will need to +add this to your path for the "make" command, and probably also switch +to GNU make (the "make" found in /usr/ccs/bin does not seem to work +properly -- appearantly it does not understand .PHONY directives). If +you're using ksh or bash, use this command to build: + + PATH=/usr/ccs/bin:$PATH make + +When using Expat with a project using autoconf for configuration, you +can use the probing macro in conftools/expat.m4 to determine how to +include Expat. See the comments at the top of that file for more +information. + +A reference manual is available in the file doc/reference.html in this +distribution. + +The homepage for this project is http://www.libexpat.org/. There +are links there to connect you to the bug reports page. If you need +to report a bug when you don't have access to a browser, you may also +send a bug report by email to expat-bugs@mail.libexpat.org. + +Discussion related to the direction of future expat development takes +place on expat-discuss@mail.libexpat.org. Archives of this list and +other Expat-related lists may be found at: + + http://mail.libexpat.org/mailman/listinfo/ diff --git a/gdcm/Utilities/gdcmexpat/doc/reference.html b/gdcm/Utilities/gdcmexpat/doc/reference.html new file mode 100644 index 0000000..e812c7d --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/doc/reference.html @@ -0,0 +1,2334 @@ + + + + + + Expat XML Parser + + + + + + + + + + + + + + +
(Expat logo)
Release 2.0.0
+
+ +

Expat is a library, written in C, for parsing XML documents. It's +the underlying XML parser for the open source Mozilla project, Perl's +XML::Parser, Python's xml.parsers.expat, and +other open-source XML parsers.

+ +

This library is the creation of James Clark, who's also given us +groff (an nroff look-alike), Jade (an implemention of ISO's DSSSL +stylesheet language for SGML), XP (a Java XML parser package), XT (a +Java XSL engine). James was also the technical lead on the XML +Working Group at W3C that produced the XML specification.

+ +

This is free software, licensed under the MIT/X Consortium license. You may download it +from the Expat home page. +

+ +

The bulk of this document was originally commissioned as an article +by XML.com. They graciously allowed +Clark Cooper to retain copyright and to distribute it with Expat. +This version has been substantially extended to include documentation +on features which have been added since the original article was +published, and additional information on using the original +interface.

+ +
+

Table of Contents

+ + +
+

Overview

+ +

Expat is a stream-oriented parser. You register callback (or +handler) functions with the parser and then start feeding it the +document. As the parser recognizes parts of the document, it will +call the appropriate handler for that part (if you've registered one.) +The document is fed to the parser in pieces, so you can start parsing +before you have all the document. This also allows you to parse really +huge documents that won't fit into memory.

+ +

Expat can be intimidating due to the many kinds of handlers and +options you can set. But you only need to learn four functions in +order to do 90% of what you'll want to do with it:

+ +
+ +
XML_ParserCreate
+
Create a new parser object.
+ +
XML_SetElementHandler
+
Set handlers for start and end tags.
+ +
XML_SetCharacterDataHandler
+
Set handler for text.
+ +
XML_Parse
+
Pass a buffer full of document to the parser
+
+ +

These functions and others are described in the reference part of this document. The reference +section also describes in detail the parameters passed to the +different types of handlers.

+ +

Let's look at a very simple example program that only uses 3 of the +above functions (it doesn't need to set a character handler.) The +program outline.c prints an +element outline, indenting child elements to distinguish them from the +parent element that contains them. The start handler does all the +work. It prints two indenting spaces for every level of ancestor +elements, then it prints the element and attribute +information. Finally it increments the global Depth +variable.

+ +
+int Depth;
+
+void XMLCALL
+start(void *data, const char *el, const char **attr) {
+  int i;
+
+  for (i = 0; i < Depth; i++)
+    printf("  ");
+
+  printf("%s", el);
+
+  for (i = 0; attr[i]; i += 2) {
+    printf(" %s='%s'", attr[i], attr[i + 1]);
+  }
+
+  printf("\n");
+  Depth++;
+}  /* End of start handler */
+
+ +

The end tag simply does the bookkeeping work of decrementing +Depth.

+
+void XMLCALL
+end(void *data, const char *el) {
+  Depth--;
+}  /* End of end handler */
+
+ +

Note the XMLCALL annotation used for the callbacks. +This is used to ensure that the Expat and the callbacks are using the +same calling convention in case the compiler options used for Expat +itself and the client code are different. Expat tries not to care +what the default calling convention is, though it may require that it +be compiled with a default convention of "cdecl" on some platforms. +For code which uses Expat, however, the calling convention is +specified by the XMLCALL annotation on most platforms; +callbacks should be defined using this annotation.

+ +

The XMLCALL annotation was added in Expat 1.95.7, but +existing working Expat applications don't need to add it (since they +are already using the "cdecl" calling convention, or they wouldn't be +working). The annotation is only needed if the default calling +convention may be something other than "cdecl". To use the annotation +safely with older versions of Expat, you can conditionally define it +after including Expat's header file:

+ +
+#include <expat.h>
+
+#ifndef XMLCALL
+#if defined(_MSC_EXTENSIONS) && !defined(__BEOS__) && !defined(__CYGWIN__)
+#define XMLCALL __cdecl
+#elif defined(__GNUC__)
+#define XMLCALL __attribute__((cdecl))
+#else
+#define XMLCALL
+#endif
+#endif
+
+ +

After creating the parser, the main program just has the job of +shoveling the document to the parser so that it can do its work.

+ +
+

Building and Installing Expat

+ +

The Expat distribution comes as a compressed (with GNU gzip) tar +file. You may download the latest version from Source Forge. After +unpacking this, cd into the directory. Then follow either the Win32 +directions or Unix directions below.

+ +

Building under Win32

+ +

If you're using the GNU compiler under cygwin, follow the Unix +directions in the next section. Otherwise if you have Microsoft's +Developer Studio installed, then from Windows Explorer double-click on +"expat.dsp" in the lib directory and build and install in the usual +manner.

+ +

Alternatively, you may download the Win32 binary package that +contains the "expat.h" include file and a pre-built DLL.

+ +

Building under Unix (or GNU)

+ +

First you'll need to run the configure shell script in order to +configure the Makefiles and headers for your system.

+ +

If you're happy with all the defaults that configure picks for you, +and you have permission on your system to install into /usr/local, you +can install Expat with this sequence of commands:

+ +
+./configure
+make
+make install
+
+ +

There are some options that you can provide to this script, but the +only one we'll mention here is the --prefix option. You +can find out all the options available by running configure with just +the --help option.

+ +

By default, the configure script sets things up so that the library +gets installed in /usr/local/lib and the associated +header file in /usr/local/include. But if you were to +give the option, --prefix=/home/me/mystuff, then the +library and header would get installed in +/home/me/mystuff/lib and +/home/me/mystuff/include respectively.

+ +

Configuring Expat Using the Pre-Processor

+ +

Expat's feature set can be configured using a small number of +pre-processor definitions. The definition of this symbols does not +affect the set of entry points for Expat, only the behavior of the API +and the definition of character types in the case of +XML_UNICODE_WCHAR_T. The symbols are:

+ +
+
XML_DTD
+
Include support for using and reporting DTD-based content. If +this is defined, default attribute values from an external DTD subset +are reported and attribute value normalization occurs based on the +type of attributes defined in the external subset. Without +this, Expat has a smaller memory footprint and can be faster, but will +not load external entities or process conditional sections. This does +not affect the set of functions available in the API.
+ +
XML_NS
+
When defined, support for the Namespaces in XML +specification is included.
+ +
XML_UNICODE
+
When defined, character data reported to the application is +encoded in UTF-16 using wide characters of the type +XML_Char. This is implied if +XML_UNICODE_WCHAR_T is defined.
+ +
XML_UNICODE_WCHAR_T
+
If defined, causes the XML_Char character type to be +defined using the wchar_t type; otherwise, unsigned +short is used. Defining this implies +XML_UNICODE.
+ +
XML_LARGE_SIZE
+
If defined, causes the XML_Size and XML_Index +integer types to be at least 64 bits in size. This is intended to support +processing of very large input streams, where the return values of +XML_GetCurrentByteIndex, +XML_GetCurrentLineNumber and +XML_GetCurrentColumnNumber +could overflow. It may not be supported by all compilers, and is turned +off by default.
+ +
XML_CONTEXT_BYTES
+
The number of input bytes of markup context which the parser will +ensure are available for reporting via XML_GetInputContext. This is +normally set to 1024, and must be set to a positive interger. If this +is not defined, the input context will not be available and XML_GetInputContext will +always report NULL. Without this, Expat has a smaller memory +footprint and can be faster.
+ +
XML_STATIC
+
On Windows, this should be set if Expat is going to be linked +statically with the code that calls it; this is required to get all +the right MSVC magic annotations correct. This is ignored on other +platforms.
+
+ +
+

Using Expat

+ +

Compiling and Linking Against Expat

+ +

Unless you installed Expat in a location not expected by your +compiler and linker, all you have to do to use Expat in your programs +is to include the Expat header (#include <expat.h>) +in your files that make calls to it and to tell the linker that it +needs to link against the Expat library. On Unix systems, this would +usually be done with the -lexpat argument. Otherwise, +you'll need to tell the compiler where to look for the Expat header +and the linker where to find the Expat library. You may also need to +take steps to tell the operating system where to find this libary at +run time.

+ +

On a Unix-based system, here's what a Makefile might look like when +Expat is installed in a standard location:

+ +
+CC=cc
+LDFLAGS=
+LIBS= -lexpat
+xmlapp: xmlapp.o
+        $(CC) $(LDFLAGS) -o xmlapp xmlapp.o $(LIBS)
+
+ +

If you installed Expat in, say, /home/me/mystuff, then +the Makefile would look like this:

+ +
+CC=cc
+CFLAGS= -I/home/me/mystuff/include
+LDFLAGS=
+LIBS= -L/home/me/mystuff/lib -lexpat
+xmlapp: xmlapp.o
+        $(CC) $(LDFLAGS) -o xmlapp xmlapp.o $(LIBS)
+
+ +

You'd also have to set the environment variable +LD_LIBRARY_PATH to /home/me/mystuff/lib (or +to ${LD_LIBRARY_PATH}:/home/me/mystuff/lib if +LD_LIBRARY_PATH already has some directories in it) in order to run +your application.

+ +

Expat Basics

+ +

As we saw in the example in the overview, the first step in parsing +an XML document with Expat is to create a parser object. There are three functions in the Expat API for creating a +parser object. However, only two of these (XML_ParserCreate and XML_ParserCreateNS) can be used for +constructing a parser for a top-level document. The object returned +by these functions is an opaque pointer (i.e. "expat.h" declares it as +void *) to data with further internal structure. In order to free the +memory associated with this object you must call XML_ParserFree. Note that if you have +provided any user data that gets stored in the +parser, then your application is responsible for freeing it prior to +calling XML_ParserFree.

+ +

The objects returned by the parser creation functions are good for +parsing only one XML document or external parsed entity. If your +application needs to parse many XML documents, then it needs to create +a parser object for each one. The best way to deal with this is to +create a higher level object that contains all the default +initialization you want for your parser objects.

+ +

Walking through a document hierarchy with a stream oriented parser +will require a good stack mechanism in order to keep track of current +context. For instance, to answer the simple question, "What element +does this text belong to?" requires a stack, since the parser may have +descended into other elements that are children of the current one and +has encountered this text on the way out.

+ +

The things you're likely to want to keep on a stack are the +currently opened element and it's attributes. You push this +information onto the stack in the start handler and you pop it off in +the end handler.

+ +

For some tasks, it is sufficient to just keep information on what +the depth of the stack is (or would be if you had one.) The outline +program shown above presents one example. Another such task would be +skipping over a complete element. When you see the start tag for the +element you want to skip, you set a skip flag and record the depth at +which the element started. When the end tag handler encounters the +same depth, the skipped element has ended and the flag may be +cleared. If you follow the convention that the root element starts at +1, then you can use the same variable for skip flag and skip +depth.

+ +
+void
+init_info(Parseinfo *info) {
+  info->skip = 0;
+  info->depth = 1;
+  /* Other initializations here */
+}  /* End of init_info */
+
+void XMLCALL
+rawstart(void *data, const char *el, const char **attr) {
+  Parseinfo *inf = (Parseinfo *) data;
+
+  if (! inf->skip) {
+    if (should_skip(inf, el, attr)) {
+      inf->skip = inf->depth;
+    }
+    else
+      start(inf, el, attr);     /* This does rest of start handling */
+  }
+
+  inf->depth++;
+}  /* End of rawstart */
+
+void XMLCALL
+rawend(void *data, const char *el) {
+  Parseinfo *inf = (Parseinfo *) data;
+
+  inf->depth--;
+
+  if (! inf->skip)
+    end(inf, el);              /* This does rest of end handling */
+
+  if (inf->skip == inf->depth)
+    inf->skip = 0;
+}  /* End rawend */
+
+ +

Notice in the above example the difference in how depth is +manipulated in the start and end handlers. The end tag handler should +be the mirror image of the start tag handler. This is necessary to +properly model containment. Since, in the start tag handler, we +incremented depth after the main body of start tag code, then +in the end handler, we need to manipulate it before the main +body. If we'd decided to increment it first thing in the start +handler, then we'd have had to decrement it last thing in the end +handler.

+ +

Communicating between handlers

+ +

In order to be able to pass information between different handlers +without using globals, you'll need to define a data structure to hold +the shared variables. You can then tell Expat (with the XML_SetUserData function) to pass a +pointer to this structure to the handlers. This is the first +argument received by most handlers. In the reference section, an argument to a callback function is named +userData and have type void * if the user +data is passed; it will have the type XML_Parser if the +parser itself is passed. When the parser is passed, the user data may +be retrieved using XML_GetUserData.

+ +

One common case where multiple calls to a single handler may need +to communicate using an application data structure is the case when +content passed to the character data handler (set by XML_SetCharacterDataHandler) needs to be accumulated. A +common first-time mistake with any of the event-oriented interfaces to +an XML parser is to expect all the text contained in an element to be +reported by a single call to the character data handler. Expat, like +many other XML parsers, reports such data as a sequence of calls; +there's no way to know when the end of the sequence is reached until a +different callback is made. A buffer referenced by the user data +structure proves both an effective and convenient place to accumulate +character data.

+ + + + +

XML Version

+ +

Expat is an XML 1.0 parser, and as such never complains based on +the value of the version pseudo-attribute in the XML +declaration, if present.

+ +

If an application needs to check the version number (to support +alternate processing), it should use the XML_SetXmlDeclHandler function to +set a handler that uses the information in the XML declaration to +determine what to do. This example shows how to check that only a +version number of "1.0" is accepted:

+ +
+static int wrong_version;
+static XML_Parser parser;
+
+static void XMLCALL
+xmldecl_handler(void            *userData,
+                const XML_Char  *version,
+                const XML_Char  *encoding,
+                int              standalone)
+{
+  static const XML_Char Version_1_0[] = {'1', '.', '0', 0};
+
+  int i;
+
+  for (i = 0; i < (sizeof(Version_1_0) / sizeof(Version_1_0[0])); ++i) {
+    if (version[i] != Version_1_0[i]) {
+      wrong_version = 1;
+      /* also clear all other handlers: */
+      XML_SetCharacterDataHandler(parser, NULL);
+      ...
+      return;
+    }
+  }
+  ...
+}
+
+ +

Namespace Processing

+ +

When the parser is created using the XML_ParserCreateNS, function, Expat +performs namespace processing. Under namespace processing, Expat +consumes xmlns and xmlns:... attributes, +which declare namespaces for the scope of the element in which they +occur. This means that your start handler will not see these +attributes. Your application can still be informed of these +declarations by setting namespace declaration handlers with XML_SetNamespaceDeclHandler.

+ +

Element type and attribute names that belong to a given namespace +are passed to the appropriate handler in expanded form. By default +this expanded form is a concatenation of the namespace URI, the +separator character (which is the 2nd argument to XML_ParserCreateNS), and the local +name (i.e. the part after the colon). Names with undeclared prefixes +are not well-formed when namespace processing is enabled, and will +trigger an error. Unprefixed attribute names are never expanded, +and unprefixed element names are only expanded when they are in the +scope of a default namespace.

+ +

However if XML_SetReturnNSTriplet has been called with a non-zero +do_nst parameter, then the expanded form for names with +an explicit prefix is a concatenation of: URI, separator, local name, +separator, prefix.

+ +

You can set handlers for the start of a namespace declaration and +for the end of a scope of a declaration with the XML_SetNamespaceDeclHandler +function. The StartNamespaceDeclHandler is called prior to the start +tag handler and the EndNamespaceDeclHandler is called after the +corresponding end tag that ends the namespace's scope. The namespace +start handler gets passed the prefix and URI for the namespace. For a +default namespace declaration (xmlns='...'), the prefix will be null. +The URI will be null for the case where the default namespace is being +unset. The namespace end handler just gets the prefix for the closing +scope.

+ +

These handlers are called for each declaration. So if, for +instance, a start tag had three namespace declarations, then the +StartNamespaceDeclHandler would be called three times before the start +tag handler is called, once for each declaration.

+ +

Character Encodings

+ +

While XML is based on Unicode, and every XML processor is required +to recognized UTF-8 and UTF-16 (1 and 2 byte encodings of Unicode), +other encodings may be declared in XML documents or entities. For the +main document, an XML declaration may contain an encoding +declaration:

+
+<?xml version="1.0" encoding="ISO-8859-2"?>
+
+ +

External parsed entities may begin with a text declaration, which +looks like an XML declaration with just an encoding declaration:

+
+<?xml encoding="Big5"?>
+
+ +

With Expat, you may also specify an encoding at the time of +creating a parser. This is useful when the encoding information may +come from a source outside the document itself (like a higher level +protocol.)

+ +

There are four built-in encodings +in Expat:

+
    +
  • UTF-8
  • +
  • UTF-16
  • +
  • ISO-8859-1
  • +
  • US-ASCII
  • +
+ +

Anything else discovered in an encoding declaration or in the +protocol encoding specified in the parser constructor, triggers a call +to the UnknownEncodingHandler. This handler gets passed +the encoding name and a pointer to an XML_Encoding data +structure. Your handler must fill in this structure and return +XML_STATUS_OK if it knows how to deal with the +encoding. Otherwise the handler should return +XML_STATUS_ERROR. The handler also gets passed a pointer +to an optional application data structure that you may indicate when +you set the handler.

+ +

Expat places restrictions on character encodings that it can +support by filling in the XML_Encoding structure. +include file:

+
    +
  1. Every ASCII character that can appear in a well-formed XML document +must be represented by a single byte, and that byte must correspond to +it's ASCII encoding (except for the characters $@\^'{}~)
  2. +
  3. Characters must be encoded in 4 bytes or less.
  4. +
  5. All characters encoded must have Unicode scalar values less than or +equal to 65535 (0xFFFF)This does not apply to the built-in support +for UTF-16 and UTF-8
  6. +
  7. No character may be encoded by more that one distinct sequence of +bytes
  8. +
+ +

XML_Encoding contains an array of integers that +correspond to the 1st byte of an encoding sequence. If the value in +the array for a byte is zero or positive, then the byte is a single +byte encoding that encodes the Unicode scalar value contained in the +array. A -1 in this array indicates a malformed byte. If the value is +-2, -3, or -4, then the byte is the beginning of a 2, 3, or 4 byte +sequence respectively. Multi-byte sequences are sent to the convert +function pointed at in the XML_Encoding structure. This +function should return the Unicode scalar value for the sequence or -1 +if the sequence is malformed.

+ +

One pitfall that novice Expat users are likely to fall into is that +although Expat may accept input in various encodings, the strings that +it passes to the handlers are always encoded in UTF-8 or UTF-16 +(depending on how Expat was compiled). Your application is responsible +for any translation of these strings into other encodings.

+ +

Handling External Entity References

+ +

Expat does not read or parse external entities directly. Note that +any external DTD is a special case of an external entity. If you've +set no ExternalEntityRefHandler, then external entity +references are silently ignored. Otherwise, it calls your handler with +the information needed to read and parse the external entity.

+ +

Your handler isn't actually responsible for parsing the entity, but +it is responsible for creating a subsidiary parser with XML_ExternalEntityParserCreate that will do the job. This +returns an instance of XML_Parser that has handlers and +other data structures initialized from the parent parser. You may then +use XML_Parse or XML_ParseBuffer calls against this +parser. Since external entities my refer to other external entities, +your handler should be prepared to be called recursively.

+ +

Parsing DTDs

+ +

In order to parse parameter entities, before starting the parse, +you must call XML_SetParamEntityParsing with one of the following +arguments:

+
+
XML_PARAM_ENTITY_PARSING_NEVER
+
Don't parse parameter entities or the external subset
+
XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE
+
Parse parameter entites and the external subset unless +standalone was set to "yes" in the XML declaration.
+
XML_PARAM_ENTITY_PARSING_ALWAYS
+
Always parse parameter entities and the external subset
+
+ +

In order to read an external DTD, you also have to set an external +entity reference handler as described above.

+ +

Temporarily Stopping Parsing

+ +

Expat 1.95.8 introduces a new feature: its now possible to stop +parsing temporarily from within a handler function, even if more data +has already been passed into the parser. Applications for this +include

+ +
    +
  • Supporting the XInclude specification.
  • + +
  • Delaying further processing until additional information is + available from some other source.
  • + +
  • Adjusting processor load as task priorities shift within an + application.
  • + +
  • Stopping parsing completely (simply free or reset the parser + instead of resuming in the outer parsing loop). This can be useful + if a application-domain error is found in the XML being parsed or if + the result of the parse is determined not to be useful after + all.
  • +
+ +

To take advantage of this feature, the main parsing loop of an +application needs to support this specifically. It cannot be +supported with a parsing loop compatible with Expat 1.95.7 or +earlier (though existing loops will continue to work without +supporting the stop/resume feature).

+ +

An application that uses this feature for a single parser will have +the rough structure (in pseudo-code):

+ +
+fd = open_input()
+p = create_parser()
+
+if parse_xml(p, fd) {
+  /* suspended */
+
+  int suspended = 1;
+
+  while (suspended) {
+    do_something_else()
+    if ready_to_resume() {
+      suspended = continue_parsing(p, fd);
+    }
+  }
+}
+
+ +

An application that may resume any of several parsers based on +input (either from the XML being parsed or some other source) will +certainly have more interesting control structures.

+ +

This C function could be used for the parse_xml +function mentioned in the pseudo-code above:

+ +
+#define BUFF_SIZE 10240
+
+/* Parse a document from the open file descriptor 'fd' until the parse
+   is complete (the document has been completely parsed, or there's
+   been an error), or the parse is stopped.  Return non-zero when
+   the parse is merely suspended.
+*/
+int
+parse_xml(XML_Parser p, int fd)
+{
+  for (;;) {
+    int last_chunk;
+    int bytes_read;
+    enum XML_Status status;
+
+    void *buff = XML_GetBuffer(p, BUFF_SIZE);
+    if (buff == NULL) {
+      /* handle error... */
+      return 0;
+    }
+    bytes_read = read(fd, buff, BUFF_SIZE);
+    if (bytes_read < 0) {
+      /* handle error... */
+      return 0;
+    }
+    status = XML_ParseBuffer(p, bytes_read, bytes_read == 0);
+    switch (status) {
+      case XML_STATUS_ERROR:
+        /* handle error... */
+        return 0;
+      case XML_STATUS_SUSPENDED:
+        return 1;
+    }
+    if (bytes_read == 0)
+      return 0;
+  }
+}
+
+ +

The corresponding continue_parsing function is +somewhat simpler, since it only need deal with the return code from +XML_ResumeParser; it can +delegate the input handling to the parse_xml +function:

+ +
+/* Continue parsing a document which had been suspended.  The 'p' and
+   'fd' arguments are the same as passed to parse_xml().  Return
+   non-zero when the parse is suspended.
+*/
+int
+continue_parsing(XML_Parser p, int fd)
+{
+  enum XML_Status status = XML_ResumeParser(p);
+  switch (status) {
+    case XML_STATUS_ERROR:
+      /* handle error... */
+      return 0;
+    case XML_ERROR_NOT_SUSPENDED:
+      /* handle error... */
+      return 0;.
+    case XML_STATUS_SUSPENDED:
+      return 1;
+  }
+  return parse_xml(p, fd);
+}
+
+ +

Now that we've seen what a mess the top-level parsing loop can +become, what have we gained? Very simply, we can now use the XML_StopParser function to stop +parsing, without having to go to great lengths to avoid additional +processing that we're expecting to ignore. As a bonus, we get to stop +parsing temporarily, and come back to it when we're +ready.

+ +

To stop parsing from a handler function, use the XML_StopParser function. This function +takes two arguments; the parser being stopped and a flag indicating +whether the parse can be resumed in the future.

+ + + + +
+ + +

Expat Reference

+ +

Parser Creation

+ +
+XML_Parser XMLCALL
+XML_ParserCreate(const XML_Char *encoding);
+
+
+Construct a new parser. If encoding is non-null, it specifies a +character encoding to use for the document. This overrides the document +encoding declaration. There are four built-in encodings: +
    +
  • US-ASCII
  • +
  • UTF-8
  • +
  • UTF-16
  • +
  • ISO-8859-1
  • +
+Any other value will invoke a call to the UnknownEncodingHandler. +
+ +
+XML_Parser XMLCALL
+XML_ParserCreateNS(const XML_Char *encoding,
+                   XML_Char sep);
+
+
+Constructs a new parser that has namespace processing in effect. Namespace +expanded element names and attribute names are returned as a concatenation +of the namespace URI, sep, and the local part of the name. This +means that you should pick a character for sep that can't be +part of a legal URI. There is a special case when sep is the null +character '\0': the namespace URI and the local part will be +concatenated without any separator - this is intended to support RDF processors. +It is a programming error to use the null separator with +namespace triplets.
+ +
+XML_Parser XMLCALL
+XML_ParserCreate_MM(const XML_Char *encoding,
+                    const XML_Memory_Handling_Suite *ms,
+		    const XML_Char *sep);
+
+
+typedef struct {
+  void *(XMLCALL *malloc_fcn)(size_t size);
+  void *(XMLCALL *realloc_fcn)(void *ptr, size_t size);
+  void (XMLCALL *free_fcn)(void *ptr);
+} XML_Memory_Handling_Suite;
+
+
+

Construct a new parser using the suite of memory handling functions +specified in ms. If ms is NULL, then use the +standard set of memory management functions. If sep is +non NULL, then namespace processing is enabled in the created parser +and the character pointed at by sep is used as the separator between +the namespace URI and the local part of the name.

+
+ +
+XML_Parser XMLCALL
+XML_ExternalEntityParserCreate(XML_Parser p,
+                               const XML_Char *context,
+                               const XML_Char *encoding);
+
+
+Construct a new XML_Parser object for parsing an external +general entity. Context is the context argument passed in a call to a +ExternalEntityRefHandler. Other state information such as handlers, +user data, namespace processing is inherited from the parser passed as +the 1st argument. So you shouldn't need to call any of the behavior +changing functions on this parser (unless you want it to act +differently than the parent parser). +
+ +
+void XMLCALL
+XML_ParserFree(XML_Parser p);
+
+
+Free memory used by the parser. Your application is responsible for +freeing any memory associated with user data. +
+ +
+XML_Bool XMLCALL
+XML_ParserReset(XML_Parser p,
+                const XML_Char *encoding);
+
+
+Clean up the memory structures maintained by the parser so that it may +be used again. After this has been called, parser is +ready to start parsing a new document. All handlers are cleared from +the parser, except for the unknownEncodingHandler. The parser's external +state is re-initialized except for the values of ns and ns_triplets. +This function may not be used on a parser created using XML_ExternalEntityParserCreate; it will return XML_FALSE in that case. Returns +XML_TRUE on success. Your application is responsible for +dealing with any memory associated with user data. +
+ +

Parsing

+ +

To state the obvious: the three parsing functions XML_Parse, +XML_ParseBuffer and +XML_GetBuffer must not be called from within a handler +unless they operate on a separate parser instance, that is, one that +did not call the handler. For example, it is OK to call the parsing +functions from within an XML_ExternalEntityRefHandler, +if they apply to the parser created by +XML_ExternalEntityParserCreate.

+ +

Note: the len argument passed to these functions +should be considerably less than the maximum value for an integer, +as it could create an integer overflow situation if the added +lengths of a buffer and the unprocessed portion of the previous buffer +exceed the maximum integer value. Input data at the end of a buffer +will remain unprocessed if it is part of an XML token for which the +end is not part of that buffer.

+ +
+enum XML_Status XMLCALL
+XML_Parse(XML_Parser p,
+          const char *s,
+          int len,
+          int isFinal);
+
+
+enum XML_Status {
+  XML_STATUS_ERROR = 0,
+  XML_STATUS_OK = 1
+};
+
+
+Parse some more of the document. The string s is a buffer +containing part (or perhaps all) of the document. The number of bytes of s +that are part of the document is indicated by len. This means +that s doesn't have to be null terminated. It also means that +if len is larger than the number of bytes in the block of +memory that s points at, then a memory fault is likely. The +isFinal parameter informs the parser that this is the last +piece of the document. Frequently, the last piece is empty (i.e. +len is zero.) +If a parse error occurred, it returns XML_STATUS_ERROR. +Otherwise it returns XML_STATUS_OK value. +
+ +
+enum XML_Status XMLCALL
+XML_ParseBuffer(XML_Parser p,
+                int len,
+                int isFinal);
+
+
+This is just like XML_Parse, +except in this case Expat provides the buffer. By obtaining the +buffer from Expat with the XML_GetBuffer function, the application can avoid double +copying of the input. +
+ +
+void * XMLCALL
+XML_GetBuffer(XML_Parser p,
+              int len);
+
+
+Obtain a buffer of size len to read a piece of the document +into. A NULL value is returned if Expat can't allocate enough memory for +this buffer. This has to be called prior to every call to +XML_ParseBuffer. A +typical use would look like this: + +
+for (;;) {
+  int bytes_read;
+  void *buff = XML_GetBuffer(p, BUFF_SIZE);
+  if (buff == NULL) {
+    /* handle error */
+  }
+
+  bytes_read = read(docfd, buff, BUFF_SIZE);
+  if (bytes_read < 0) {
+    /* handle error */
+  }
+
+  if (! XML_ParseBuffer(p, bytes_read, bytes_read == 0)) {
+    /* handle parse error */
+  }
+
+  if (bytes_read == 0)
+    break;
+}
+
+
+ +
+enum XML_Status XMLCALL
+XML_StopParser(XML_Parser p,
+               XML_Bool resumable);
+
+
+ +

Stops parsing, causing XML_Parse or XML_ParseBuffer to return. Must be called from within a +call-back handler, except when aborting (when resumable +is XML_FALSE) an already suspended parser. Some +call-backs may still follow because they would otherwise get +lost, including +

    +
  • the end element handler for empty elements when stopped in the + start element handler,
  • +
  • end namespace declaration handler when stopped in the end + element handler,
  • +
+and possibly others.

+ +

This can be called from most handlers, including DTD related +call-backs, except when parsing an external parameter entity and +resumable is XML_TRUE. Returns +XML_STATUS_OK when successful, +XML_STATUS_ERROR otherwise. The possible error codes +are:

+
+
XML_ERROR_SUSPENDED
+
when suspending an already suspended parser.
+
XML_ERROR_FINISHED
+
when the parser has already finished.
+
XML_ERROR_SUSPEND_PE
+
when suspending while parsing an external PE.
+
+ +

Since the stop/resume feature requires application support in the +outer parsing loop, it is an error to call this function for a parser +not being handled appropriately; see Temporarily Stopping Parsing for more information.

+ +

When resumable is XML_TRUE then parsing +is suspended, that is, XML_Parse and XML_ParseBuffer return XML_STATUS_SUSPENDED. +Otherwise, parsing is aborted, that is, XML_Parse and XML_ParseBuffer return +XML_STATUS_ERROR with error code +XML_ERROR_ABORTED.

+ +

Note: +This will be applied to the current parser instance only, that is, if +there is a parent parser then it will continue parsing when the +external entity reference handler returns. It is up to the +implementation of that handler to call XML_StopParser on the parent parser +(recursively), if one wants to stop parsing altogether.

+ +

When suspended, parsing can be resumed by calling XML_ResumeParser.

+ +

New in Expat 1.95.8.

+
+ +
+enum XML_Status XMLCALL
+XML_ResumeParser(XML_Parser p);
+
+
+

Resumes parsing after it has been suspended with XML_StopParser. Must not be called from +within a handler call-back. Returns same status codes as XML_Parse or XML_ParseBuffer. An additional error +code, XML_ERROR_NOT_SUSPENDED, will be returned if the +parser was not currently suspended.

+ +

Note: +This must be called on the most deeply nested child parser instance +first, and on its parent parser only after the child parser has +finished, to be applied recursively until the document entity's parser +is restarted. That is, the parent parser will not resume by itself +and it is up to the application to call XML_ResumeParser on it at the +appropriate moment.

+ +

New in Expat 1.95.8.

+
+ +
+void XMLCALL
+XML_GetParsingStatus(XML_Parser p,
+                     XML_ParsingStatus *status);
+
+
+enum XML_Parsing {
+  XML_INITIALIZED,
+  XML_PARSING,
+  XML_FINISHED,
+  XML_SUSPENDED
+};
+
+typedef struct {
+  enum XML_Parsing parsing;
+  XML_Bool finalBuffer;
+} XML_ParsingStatus;
+
+
+

Returns status of parser with respect to being initialized, +parsing, finished, or suspended, and whether the final buffer is being +processed. The status parameter must not be +NULL.

+ +

New in Expat 1.95.8.

+
+ + +

Handler Setting

+ +

Although handlers are typically set prior to parsing and left alone, an +application may choose to set or change the handler for a parsing event +while the parse is in progress. For instance, your application may choose +to ignore all text not descended from a para element. One +way it could do this is to set the character handler when a para start tag +is seen, and unset it for the corresponding end tag.

+ +

A handler may be unset by providing a NULL pointer to the +appropriate handler setter. None of the handler setting functions have +a return value.

+ +

Your handlers will be receiving strings in arrays of type +XML_Char. This type is conditionally defined in expat.h as +either char, wchar_t or unsigned short. +The former implies UTF-8 encoding, the latter two imply UTF-16 encoding. +Note that you'll receive them in this form independent of the original +encoding of the document.

+ +
+
+void XMLCALL
+XML_SetStartElementHandler(XML_Parser p,
+                           XML_StartElementHandler start);
+
+
+typedef void
+(XMLCALL *XML_StartElementHandler)(void *userData,
+                                   const XML_Char *name,
+                                   const XML_Char **atts);
+
+

Set handler for start (and empty) tags. Attributes are passed to the start +handler as a pointer to a vector of char pointers. Each attribute seen in +a start (or empty) tag occupies 2 consecutive places in this vector: the +attribute name followed by the attribute value. These pairs are terminated +by a null pointer.

+

Note that an empty tag generates a call to both start and end handlers +(in that order).

+
+ +
+
+void XMLCALL
+XML_SetEndElementHandler(XML_Parser p,
+                         XML_EndElementHandler);
+
+
+typedef void
+(XMLCALL *XML_EndElementHandler)(void *userData,
+                                 const XML_Char *name);
+
+

Set handler for end (and empty) tags. As noted above, an empty tag +generates a call to both start and end handlers.

+
+ +
+
+void XMLCALL
+XML_SetElementHandler(XML_Parser p,
+                      XML_StartElementHandler start,
+                      XML_EndElementHandler end);
+
+

Set handlers for start and end tags with one call.

+
+ +
+
+void XMLCALL
+XML_SetCharacterDataHandler(XML_Parser p,
+                            XML_CharacterDataHandler charhndl)
+
+
+typedef void
+(XMLCALL *XML_CharacterDataHandler)(void *userData,
+                                    const XML_Char *s,
+                                    int len);
+
+

Set a text handler. The string your handler receives +is NOT nul-terminated. You have to use the length argument +to deal with the end of the string. A single block of contiguous text +free of markup may still result in a sequence of calls to this handler. +In other words, if you're searching for a pattern in the text, it may +be split across calls to this handler.

+
+ +
+
+void XMLCALL
+XML_SetProcessingInstructionHandler(XML_Parser p,
+                                    XML_ProcessingInstructionHandler proc)
+
+
+typedef void
+(XMLCALL *XML_ProcessingInstructionHandler)(void *userData,
+                                            const XML_Char *target,
+                                            const XML_Char *data);
+
+
+

Set a handler for processing instructions. The target is the first word +in the processing instruction. The data is the rest of the characters in +it after skipping all whitespace after the initial word.

+
+ +
+
+void XMLCALL
+XML_SetCommentHandler(XML_Parser p,
+                      XML_CommentHandler cmnt)
+
+
+typedef void
+(XMLCALL *XML_CommentHandler)(void *userData,
+                              const XML_Char *data);
+
+

Set a handler for comments. The data is all text inside the comment +delimiters.

+
+ +
+
+void XMLCALL
+XML_SetStartCdataSectionHandler(XML_Parser p,
+                                XML_StartCdataSectionHandler start);
+
+
+typedef void
+(XMLCALL *XML_StartCdataSectionHandler)(void *userData);
+
+

Set a handler that gets called at the beginning of a CDATA section.

+
+ +
+
+void XMLCALL
+XML_SetEndCdataSectionHandler(XML_Parser p,
+                              XML_EndCdataSectionHandler end);
+
+
+typedef void
+(XMLCALL *XML_EndCdataSectionHandler)(void *userData);
+
+

Set a handler that gets called at the end of a CDATA section.

+
+ +
+
+void XMLCALL
+XML_SetCdataSectionHandler(XML_Parser p,
+                           XML_StartCdataSectionHandler start,
+                           XML_EndCdataSectionHandler end)
+
+

Sets both CDATA section handlers with one call.

+
+ +
+
+void XMLCALL
+XML_SetDefaultHandler(XML_Parser p,
+                      XML_DefaultHandler hndl)
+
+
+typedef void
+(XMLCALL *XML_DefaultHandler)(void *userData,
+                              const XML_Char *s,
+                              int len);
+
+ +

Sets a handler for any characters in the document which wouldn't +otherwise be handled. This includes both data for which no handlers +can be set (like some kinds of DTD declarations) and data which could +be reported but which currently has no handler set. The characters +are passed exactly as they were present in the XML document except +that they will be encoded in UTF-8 or UTF-16. Line boundaries are not +normalized. Note that a byte order mark character is not passed to the +default handler. There are no guarantees about how characters are +divided between calls to the default handler: for example, a comment +might be split between multiple calls. Setting the handler with +this call has the side effect of turning off expansion of references +to internally defined general entities. Instead these references are +passed to the default handler.

+ +

See also XML_DefaultCurrent.

+
+ +
+
+void XMLCALL
+XML_SetDefaultHandlerExpand(XML_Parser p,
+                            XML_DefaultHandler hndl)
+
+
+typedef void
+(XMLCALL *XML_DefaultHandler)(void *userData,
+                              const XML_Char *s,
+                              int len);
+
+

This sets a default handler, but doesn't inhibit the expansion of +internal entity references. The entity reference will not be passed +to the default handler.

+ +

See also XML_DefaultCurrent.

+
+ +
+
+void XMLCALL
+XML_SetExternalEntityRefHandler(XML_Parser p,
+                                XML_ExternalEntityRefHandler hndl)
+
+
+typedef int
+(XMLCALL *XML_ExternalEntityRefHandler)(XML_Parser p,
+                                        const XML_Char *context,
+                                        const XML_Char *base,
+                                        const XML_Char *systemId,
+                                        const XML_Char *publicId);
+
+

Set an external entity reference handler. This handler is also +called for processing an external DTD subset if parameter entity parsing +is in effect. (See +XML_SetParamEntityParsing.)

+ +

The context parameter specifies the parsing context in +the format expected by the context argument to XML_ExternalEntityParserCreate. code is +valid only until the handler returns, so if the referenced entity is +to be parsed later, it must be copied. context is NULL +only when the entity is a parameter entity, which is how one can +differentiate between general and parameter entities.

+ +

The base parameter is the base to use for relative +system identifiers. It is set by XML_SetBase and may be NULL. The +publicId parameter is the public id given in the entity +declaration and may be NULL. systemId is the system +identifier specified in the entity declaration and is never NULL.

+ +

There are a couple of ways in which this handler differs from +others. First, this handler returns a status indicator (an +integer). XML_STATUS_OK should be returned for successful +handling of the external entity reference. Returning +XML_STATUS_ERROR indicates failure, and causes the +calling parser to return an +XML_ERROR_EXTERNAL_ENTITY_HANDLING error.

+ +

Second, instead of having the user data as its first argument, it +receives the parser that encountered the entity reference. This, along +with the context parameter, may be used as arguments to a call to +XML_ExternalEntityParserCreate. Using the returned +parser, the body of the external entity can be recursively parsed.

+ +

Since this handler may be called recursively, it should not be saving +information into global or static variables.

+
+ +
+void XMLCALL
+XML_SetExternalEntityRefHandlerArg(XML_Parser p,
+                                   void *arg)
+
+
+

Set the argument passed to the ExternalEntityRefHandler. If +arg is not NULL, it is the new value passed to the +handler set using XML_SetExternalEntityRefHandler; if arg is +NULL, the argument passed to the handler function will be the parser +object itself.

+ +

Note: +The type of arg and the type of the first argument to the +ExternalEntityRefHandler do not match. This function takes a +void * to be passed to the handler, while the handler +accepts an XML_Parser. This is a historical accident, +but will not be corrected before Expat 2.0 (at the earliest) to avoid +causing compiler warnings for code that's known to work with this +API. It is the responsibility of the application code to know the +actual type of the argument passed to the handler and to manage it +properly.

+
+ +
+
+void XMLCALL
+XML_SetSkippedEntityHandler(XML_Parser p,
+                            XML_SkippedEntityHandler handler)
+
+
+typedef void
+(XMLCALL *XML_SkippedEntityHandler)(void *userData,
+                                    const XML_Char *entityName,
+                                    int is_parameter_entity);
+
+

Set a skipped entity handler. This is called in two situations:

+
    +
  1. An entity reference is encountered for which no declaration + has been read and this is not an error.
  2. +
  3. An internal entity reference is read, but not expanded, because + XML_SetDefaultHandler + has been called.
  4. +
+

The is_parameter_entity argument will be non-zero for +a parameter entity and zero for a general entity.

Note: skipped +parameter entities in declarations and skipped general entities in +attribute values cannot be reported, because the event would be out of +sync with the reporting of the declarations or attribute values

+
+ +
+
+void XMLCALL
+XML_SetUnknownEncodingHandler(XML_Parser p,
+                              XML_UnknownEncodingHandler enchandler,
+			      void *encodingHandlerData)
+
+
+typedef int
+(XMLCALL *XML_UnknownEncodingHandler)(void *encodingHandlerData,
+                                      const XML_Char *name,
+                                      XML_Encoding *info);
+
+typedef struct {
+  int map[256];
+  void *data;
+  int (XMLCALL *convert)(void *data, const char *s);
+  void (XMLCALL *release)(void *data);
+} XML_Encoding;
+
+

Set a handler to deal with encodings other than the built in set. This should be done before +XML_Parse or XML_ParseBuffer have been called on the +given parser.

If the handler knows how to deal with an encoding +with the given name, it should fill in the info data +structure and return XML_STATUS_OK. Otherwise it +should return XML_STATUS_ERROR. The handler will be called +at most once per parsed (external) entity. The optional application +data pointer encodingHandlerData will be passed back to +the handler.

+ +

The map array contains information for every possible possible leading +byte in a byte sequence. If the corresponding value is >= 0, then it's +a single byte sequence and the byte encodes that Unicode value. If the +value is -1, then that byte is invalid as the initial byte in a sequence. +If the value is -n, where n is an integer > 1, then n is the number of +bytes in the sequence and the actual conversion is accomplished by a +call to the function pointed at by convert. This function may return -1 +if the sequence itself is invalid. The convert pointer may be null if +there are only single byte codes. The data parameter passed to the convert +function is the data pointer from XML_Encoding. The +string s is NOT nul-terminated and points at the sequence of +bytes to be converted.

+ +

The function pointed at by release is called by the +parser when it is finished with the encoding. It may be NULL.

+
+ +
+
+void XMLCALL
+XML_SetStartNamespaceDeclHandler(XML_Parser p,
+			         XML_StartNamespaceDeclHandler start);
+
+
+typedef void
+(XMLCALL *XML_StartNamespaceDeclHandler)(void *userData,
+                                         const XML_Char *prefix,
+                                         const XML_Char *uri);
+
+

Set a handler to be called when a namespace is declared. Namespace +declarations occur inside start tags. But the namespace declaration start +handler is called before the start tag handler for each namespace declared +in that start tag.

+
+ +
+
+void XMLCALL
+XML_SetEndNamespaceDeclHandler(XML_Parser p,
+			       XML_EndNamespaceDeclHandler end);
+
+
+typedef void
+(XMLCALL *XML_EndNamespaceDeclHandler)(void *userData,
+                                       const XML_Char *prefix);
+
+

Set a handler to be called when leaving the scope of a namespace +declaration. This will be called, for each namespace declaration, +after the handler for the end tag of the element in which the +namespace was declared.

+
+ +
+
+void XMLCALL
+XML_SetNamespaceDeclHandler(XML_Parser p,
+                            XML_StartNamespaceDeclHandler start,
+                            XML_EndNamespaceDeclHandler end)
+
+

Sets both namespace declaration handlers with a single call.

+
+ +
+
+void XMLCALL
+XML_SetXmlDeclHandler(XML_Parser p,
+		      XML_XmlDeclHandler xmldecl);
+
+
+typedef void
+(XMLCALL *XML_XmlDeclHandler)(void            *userData,
+                              const XML_Char  *version,
+                              const XML_Char  *encoding,
+                              int             standalone);
+
+

Sets a handler that is called for XML declarations and also for +text declarations discovered in external entities. The way to +distinguish is that the version parameter will be NULL +for text declarations. The encoding parameter may be NULL +for an XML declaration. The standalone argument will +contain -1, 0, or 1 indicating respectively that there was no +standalone parameter in the declaration, that it was given as no, or +that it was given as yes.

+
+ +
+
+void XMLCALL
+XML_SetStartDoctypeDeclHandler(XML_Parser p,
+			       XML_StartDoctypeDeclHandler start);
+
+
+typedef void
+(XMLCALL *XML_StartDoctypeDeclHandler)(void           *userData,
+                                       const XML_Char *doctypeName,
+                                       const XML_Char *sysid,
+                                       const XML_Char *pubid,
+                                       int            has_internal_subset);
+
+

Set a handler that is called at the start of a DOCTYPE declaration, +before any external or internal subset is parsed. Both sysid +and pubid may be NULL. The has_internal_subset +will be non-zero if the DOCTYPE declaration has an internal subset.

+
+ +
+
+void XMLCALL
+XML_SetEndDoctypeDeclHandler(XML_Parser p,
+			     XML_EndDoctypeDeclHandler end);
+
+
+typedef void
+(XMLCALL *XML_EndDoctypeDeclHandler)(void *userData);
+
+

Set a handler that is called at the end of a DOCTYPE declaration, +after parsing any external subset.

+
+ +
+
+void XMLCALL
+XML_SetDoctypeDeclHandler(XML_Parser p,
+			  XML_StartDoctypeDeclHandler start,
+			  XML_EndDoctypeDeclHandler end);
+
+

Set both doctype handlers with one call.

+
+ +
+
+void XMLCALL
+XML_SetElementDeclHandler(XML_Parser p,
+			  XML_ElementDeclHandler eldecl);
+
+
+typedef void
+(XMLCALL *XML_ElementDeclHandler)(void *userData,
+                                  const XML_Char *name,
+                                  XML_Content *model);
+
+
+enum XML_Content_Type {
+  XML_CTYPE_EMPTY = 1,
+  XML_CTYPE_ANY,
+  XML_CTYPE_MIXED,
+  XML_CTYPE_NAME,
+  XML_CTYPE_CHOICE,
+  XML_CTYPE_SEQ
+};
+
+enum XML_Content_Quant {
+  XML_CQUANT_NONE,
+  XML_CQUANT_OPT,
+  XML_CQUANT_REP,
+  XML_CQUANT_PLUS
+};
+
+typedef struct XML_cp XML_Content;
+
+struct XML_cp {
+  enum XML_Content_Type		type;
+  enum XML_Content_Quant	quant;
+  const XML_Char *		name;
+  unsigned int			numchildren;
+  XML_Content *			children;
+};
+
+

Sets a handler for element declarations in a DTD. The handler gets +called with the name of the element in the declaration and a pointer +to a structure that contains the element model. It is the +application's responsibility to free this data structure using +XML_FreeContentModel.

+ +

The model argument is the root of a tree of +XML_Content nodes. If type equals +XML_CTYPE_EMPTY or XML_CTYPE_ANY, then +quant will be XML_CQUANT_NONE, and the other +fields will be zero or NULL. If type is +XML_CTYPE_MIXED, then quant will be +XML_CQUANT_NONE or XML_CQUANT_REP and +numchildren will contain the number of elements that are +allowed to be mixed in and children points to an array of +XML_Content structures that will all have type +XML_CTYPE_NAME with no quantification. Only the root node can be type +XML_CTYPE_EMPTY, XML_CTYPE_ANY, or +XML_CTYPE_MIXED.

+ +

For type XML_CTYPE_NAME, the name field +points to the name and the numchildren and +children fields will be zero and NULL. The +quant field will indicate any quantifiers placed on the +name.

+ +

Types XML_CTYPE_CHOICE and XML_CTYPE_SEQ +indicate a choice or sequence respectively. The +numchildren field indicates how many nodes in the choice +or sequence and children points to the nodes.

+
+ +
+
+void XMLCALL
+XML_SetAttlistDeclHandler(XML_Parser p,
+                          XML_AttlistDeclHandler attdecl);
+
+
+typedef void
+(XMLCALL *XML_AttlistDeclHandler)(void           *userData,
+                                  const XML_Char *elname,
+                                  const XML_Char *attname,
+                                  const XML_Char *att_type,
+                                  const XML_Char *dflt,
+                                  int            isrequired);
+
+

Set a handler for attlist declarations in the DTD. This handler is +called for each attribute. So a single attlist declaration +with multiple attributes declared will generate multiple calls to this +handler. The elname parameter returns the name of the +element for which the attribute is being declared. The attribute name +is in the attname parameter. The attribute type is in the +att_type parameter. It is the string representing the +type in the declaration with whitespace removed.

+ +

The dflt parameter holds the default value. It will be +NULL in the case of "#IMPLIED" or "#REQUIRED" attributes. You can +distinguish these two cases by checking the isrequired +parameter, which will be true in the case of "#REQUIRED" attributes. +Attributes which are "#FIXED" will have also have a true +isrequired, but they will have the non-NULL fixed value +in the dflt parameter.

+
+ +
+
+void XMLCALL
+XML_SetEntityDeclHandler(XML_Parser p,
+			 XML_EntityDeclHandler handler);
+
+
+typedef void
+(XMLCALL *XML_EntityDeclHandler)(void           *userData,
+                                 const XML_Char *entityName,
+                                 int            is_parameter_entity,
+                                 const XML_Char *value,
+                                 int            value_length, 
+                                 const XML_Char *base,
+                                 const XML_Char *systemId,
+                                 const XML_Char *publicId,
+                                 const XML_Char *notationName);
+
+

Sets a handler that will be called for all entity declarations. +The is_parameter_entity argument will be non-zero in the +case of parameter entities and zero otherwise.

+ +

For internal entities (<!ENTITY foo "bar">), +value will be non-NULL and systemId, +publicId, and notationName will all be NULL. +The value string is not NULL terminated; the length is +provided in the value_length parameter. Do not use +value_length to test for internal entities, since it is +legal to have zero-length values. Instead check for whether or not +value is NULL.

The notationName +argument will have a non-NULL value only for unparsed entity +declarations.

+
+ +
+
+void XMLCALL
+XML_SetUnparsedEntityDeclHandler(XML_Parser p,
+                                 XML_UnparsedEntityDeclHandler h)
+
+
+typedef void
+(XMLCALL *XML_UnparsedEntityDeclHandler)(void *userData,
+                                         const XML_Char *entityName, 
+                                         const XML_Char *base,
+                                         const XML_Char *systemId,
+                                         const XML_Char *publicId,
+                                         const XML_Char *notationName);
+
+

Set a handler that receives declarations of unparsed entities. These +are entity declarations that have a notation (NDATA) field:

+ +
+<!ENTITY logo SYSTEM "images/logo.gif" NDATA gif>
+
+

This handler is obsolete and is provided for backwards +compatibility. Use instead XML_SetEntityDeclHandler.

+
+ +
+
+void XMLCALL
+XML_SetNotationDeclHandler(XML_Parser p,
+                           XML_NotationDeclHandler h)
+
+
+typedef void
+(XMLCALL *XML_NotationDeclHandler)(void *userData, 
+                                   const XML_Char *notationName,
+                                   const XML_Char *base,
+                                   const XML_Char *systemId,
+                                   const XML_Char *publicId);
+
+

Set a handler that receives notation declarations.

+
+ +
+
+void XMLCALL
+XML_SetNotStandaloneHandler(XML_Parser p,
+                            XML_NotStandaloneHandler h)
+
+
+typedef int 
+(XMLCALL *XML_NotStandaloneHandler)(void *userData);
+
+

Set a handler that is called if the document is not "standalone". +This happens when there is an external subset or a reference to a +parameter entity, but does not have standalone set to "yes" in an XML +declaration. If this handler returns XML_STATUS_ERROR, +then the parser will throw an XML_ERROR_NOT_STANDALONE +error.

+
+ +

Parse position and error reporting functions

+ +

These are the functions you'll want to call when the parse +functions return XML_STATUS_ERROR (a parse error has +occurred), although the position reporting functions are useful outside +of errors. The position reported is the byte position (in the original +document or entity encoding) of the first of the sequence of +characters that generated the current event (or the error that caused +the parse functions to return XML_STATUS_ERROR.) The +exceptions are callbacks trigged by declarations in the document +prologue, in which case they exact position reported is somewhere in the +relevant markup, but not necessarily as meaningful as for other +events.

+ +

The position reporting functions are accurate only outside of the +DTD. In other words, they usually return bogus information when +called from within a DTD declaration handler.

+ +
+enum XML_Error XMLCALL
+XML_GetErrorCode(XML_Parser p);
+
+
+Return what type of error has occurred. +
+ +
+const XML_LChar * XMLCALL
+XML_ErrorString(enum XML_Error code);
+
+
+Return a string describing the error corresponding to code. +The code should be one of the enums that can be returned from +XML_GetErrorCode. +
+ +
+XML_Index XMLCALL
+XML_GetCurrentByteIndex(XML_Parser p);
+
+
+Return the byte offset of the position. This always corresponds to +the values returned by XML_GetCurrentLineNumber and XML_GetCurrentColumnNumber. +
+ +
+XML_Size XMLCALL
+XML_GetCurrentLineNumber(XML_Parser p);
+
+
+Return the line number of the position. The first line is reported as +1. +
+ +
+XML_Size XMLCALL
+XML_GetCurrentColumnNumber(XML_Parser p);
+
+
+Return the offset, from the beginning of the current line, of +the position. +
+ +
+int XMLCALL
+XML_GetCurrentByteCount(XML_Parser p);
+
+
+Return the number of bytes in the current event. Returns +0 if the event is inside a reference to an internal +entity and for the end-tag event for empty element tags (the later can +be used to distinguish empty-element tags from empty elements using +separate start and end tags). +
+ +
+const char * XMLCALL
+XML_GetInputContext(XML_Parser p,
+                    int *offset,
+                    int *size);
+
+
+ +

Returns the parser's input buffer, sets the integer pointed at by +offset to the offset within this buffer of the current +parse position, and set the integer pointed at by size to +the size of the returned buffer.

+ +

This should only be called from within a handler during an active +parse and the returned buffer should only be referred to from within +the handler that made the call. This input buffer contains the +untranslated bytes of the input.

+ +

Only a limited amount of context is kept, so if the event +triggering a call spans over a very large amount of input, the actual +parse position may be before the beginning of the buffer.

+ +

If XML_CONTEXT_BYTES is not defined, this will always +return NULL.

+
+ +

Miscellaneous functions

+ +

The functions in this section either obtain state information from +the parser or can be used to dynamicly set parser options.

+ +
+void XMLCALL
+XML_SetUserData(XML_Parser p,
+                void *userData);
+
+
+This sets the user data pointer that gets passed to handlers. It +overwrites any previous value for this pointer. Note that the +application is responsible for freeing the memory associated with +userData when it is finished with the parser. So if you +call this when there's already a pointer there, and you haven't freed +the memory associated with it, then you've probably just leaked +memory. +
+ +
+void * XMLCALL
+XML_GetUserData(XML_Parser p);
+
+
+This returns the user data pointer that gets passed to handlers. +It is actually implemented as a macro. +
+ +
+void XMLCALL
+XML_UseParserAsHandlerArg(XML_Parser p);
+
+
+After this is called, handlers receive the parser in their +userData arguments. The user data can still be obtained +using the XML_GetUserData function. +
+ +
+enum XML_Status XMLCALL
+XML_SetBase(XML_Parser p,
+            const XML_Char *base);
+
+
+Set the base to be used for resolving relative URIs in system +identifiers. The return value is XML_STATUS_ERROR if +there's no memory to store base, otherwise it's +XML_STATUS_OK. +
+ +
+const XML_Char * XMLCALL
+XML_GetBase(XML_Parser p);
+
+
+Return the base for resolving relative URIs. +
+ +
+int XMLCALL
+XML_GetSpecifiedAttributeCount(XML_Parser p);
+
+
+When attributes are reported to the start handler in the atts vector, +attributes that were explicitly set in the element occur before any +attributes that receive their value from default information in an +ATTLIST declaration. This function returns the number of attributes +that were explicitly set times two, thus giving the offset in the +atts array passed to the start tag handler of the first +attribute set due to defaults. It supplies information for the last +call to a start handler. If called inside a start handler, then that +means the current call. +
+ +
+int XMLCALL
+XML_GetIdAttributeIndex(XML_Parser p);
+
+
+Returns the index of the ID attribute passed in the atts array in the +last call to XML_StartElementHandler, or -1 if there is no ID +attribute. If called inside a start handler, then that means the +current call. +
+ +
+enum XML_Status XMLCALL
+XML_SetEncoding(XML_Parser p,
+                const XML_Char *encoding);
+
+
+Set the encoding to be used by the parser. It is equivalent to +passing a non-null encoding argument to the parser creation functions. +It must not be called after XML_Parse or XML_ParseBuffer have been called on the given parser. +Returns XML_STATUS_OK on success or +XML_STATUS_ERROR on error. +
+ +
+int XMLCALL
+XML_SetParamEntityParsing(XML_Parser p,
+                          enum XML_ParamEntityParsing code);
+
+
+This enables parsing of parameter entities, including the external +parameter entity that is the external DTD subset, according to +code. +The choices for code are: +
    +
  • XML_PARAM_ENTITY_PARSING_NEVER
  • +
  • XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE
  • +
  • XML_PARAM_ENTITY_PARSING_ALWAYS
  • +
+
+ +
+enum XML_Error XMLCALL
+XML_UseForeignDTD(XML_Parser parser, XML_Bool useDTD);
+
+
+

This function allows an application to provide an external subset +for the document type declaration for documents which do not specify +an external subset of their own. For documents which specify an +external subset in their DOCTYPE declaration, the application-provided +subset will be ignored. If the document does not contain a DOCTYPE +declaration at all and useDTD is true, the +application-provided subset will be parsed, but the +startDoctypeDeclHandler and +endDoctypeDeclHandler functions, if set, will not be +called. The setting of parameter entity parsing, controlled using +XML_SetParamEntityParsing, will be honored.

+ +

The application-provided external subset is read by calling the +external entity reference handler set via XML_SetExternalEntityRefHandler with both +publicId and systemId set to NULL.

+ +

If this function is called after parsing has begun, it returns +XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING and ignores +useDTD. If called when Expat has been compiled without +DTD support, it returns +XML_ERROR_FEATURE_REQUIRES_XML_DTD. Otherwise, it +returns XML_ERROR_NONE.

+ +

Note: For the purpose of checking WFC: Entity Declared, passing +useDTD == XML_TRUE will make the parser behave as if +the document had a DTD with an external subset. This holds true even if +the external entity reference handler returns without action.

+
+ +
+void XMLCALL
+XML_SetReturnNSTriplet(XML_Parser parser,
+                       int        do_nst);
+
+
+

+This function only has an effect when using a parser created with +XML_ParserCreateNS, +i.e. when namespace processing is in effect. The do_nst +sets whether or not prefixes are returned with names qualified with a +namespace prefix. If this function is called with do_nst +non-zero, then afterwards namespace qualified names (that is qualified +with a prefix as opposed to belonging to a default namespace) are +returned as a triplet with the three parts separated by the namespace +separator specified when the parser was created. The order of +returned parts is URI, local name, and prefix.

If +do_nst is zero, then namespaces are reported in the +default manner, URI then local_name separated by the namespace +separator.

+
+ +
+void XMLCALL
+XML_DefaultCurrent(XML_Parser parser);
+
+
+This can be called within a handler for a start element, end element, +processing instruction or character data. It causes the corresponding +markup to be passed to the default handler set by XML_SetDefaultHandler or +XML_SetDefaultHandlerExpand. It does nothing if there is +not a default handler. +
+ +
+XML_LChar * XMLCALL
+XML_ExpatVersion();
+
+
+Return the library version as a string (e.g. "expat_1.95.1"). +
+ +
+struct XML_Expat_Version XMLCALL
+XML_ExpatVersionInfo();
+
+
+typedef struct {
+  int major;
+  int minor;
+  int micro;
+} XML_Expat_Version;
+
+
+Return the library version information as a structure. +Some macros are also defined that support compile-time tests of the +library version: +
    +
  • XML_MAJOR_VERSION
  • +
  • XML_MINOR_VERSION
  • +
  • XML_MICRO_VERSION
  • +
+Testing these constants is currently the best way to determine if +particular parts of the Expat API are available. +
+ +
+const XML_Feature * XMLCALL
+XML_GetFeatureList();
+
+
+enum XML_FeatureEnum {
+  XML_FEATURE_END = 0,
+  XML_FEATURE_UNICODE,
+  XML_FEATURE_UNICODE_WCHAR_T,
+  XML_FEATURE_DTD,
+  XML_FEATURE_CONTEXT_BYTES,
+  XML_FEATURE_MIN_SIZE,
+  XML_FEATURE_SIZEOF_XML_CHAR,
+  XML_FEATURE_SIZEOF_XML_LCHAR
+};
+
+typedef struct {
+  enum XML_FeatureEnum  feature;
+  XML_LChar            *name;
+  long int              value;
+} XML_Feature;
+
+
+

Returns a list of "feature" records, providing details on how +Expat was configured at compile time. Most applications should not +need to worry about this, but this information is otherwise not +available from Expat. This function allows code that does need to +check these features to do so at runtime.

+ +

The return value is an array of XML_Feature, +terminated by a record with a feature of +XML_FEATURE_END and name of NULL, +identifying the feature-test macros Expat was compiled with. Since an +application that requires this kind of information needs to determine +the type of character the name points to, records for the +XML_FEATURE_SIZEOF_XML_CHAR and +XML_FEATURE_SIZEOF_XML_LCHAR will be located at the +beginning of the list, followed by XML_FEATURE_UNICODE +and XML_FEATURE_UNICODE_WCHAR_T, if they are present at +all.

+ +

Some features have an associated value. If there isn't an +associated value, the value field is set to 0. At this +time, the following features have been defined to have values:

+ +
+
XML_FEATURE_SIZEOF_XML_CHAR
+
The number of bytes occupied by one XML_Char + character.
+
XML_FEATURE_SIZEOF_XML_LCHAR
+
The number of bytes occupied by one XML_LChar + character.
+
XML_FEATURE_CONTEXT_BYTES
+
The maximum number of characters of context which can be + reported by XML_GetInputContext.
+
+
+ +
+void XMLCALL
+XML_FreeContentModel(XML_Parser parser, XML_Content *model);
+
+
+Function to deallocate the model argument passed to the +XML_ElementDeclHandler callback set using XML_ElementDeclHandler. +This function should not be used for any other purpose. +
+ +

The following functions allow external code to share the memory +allocator an XML_Parser has been configured to use. This +is especially useful for third-party libraries that interact with a +parser object created by application code, or heavily layered +applications. This can be essential when using dynamically loaded +libraries which use different C standard libraries (this can happen on +Windows, at least).

+ +
+void * XMLCALL
+XML_MemMalloc(XML_Parser parser, size_t size);
+
+
+Allocate size bytes of memory using the allocator the +parser object has been configured to use. Returns a +pointer to the memory or NULL on failure. Memory allocated in this +way must be freed using XML_MemFree. +
+ +
+void * XMLCALL
+XML_MemRealloc(XML_Parser parser, void *ptr, size_t size);
+
+
+Allocate size bytes of memory using the allocator the +parser object has been configured to use. +ptr must point to a block of memory allocated by XML_MemMalloc or +XML_MemRealloc, or be NULL. This function tries to +expand the block pointed to by ptr if possible. Returns +a pointer to the memory or NULL on failure. On success, the original +block has either been expanded or freed. On failure, the original +block has not been freed; the caller is responsible for freeing the +original block. Memory allocated in this way must be freed using +XML_MemFree. +
+ +
+void XMLCALL
+XML_MemFree(XML_Parser parser, void *ptr);
+
+
+Free a block of memory pointed to by ptr. The block must +have been allocated by XML_MemMalloc or XML_MemRealloc, or be NULL. +
+ +
+

Valid XHTML 1.0!

+
+ + diff --git a/gdcm/Utilities/gdcmexpat/doc/style.css b/gdcm/Utilities/gdcmexpat/doc/style.css new file mode 100644 index 0000000..69df30b --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/doc/style.css @@ -0,0 +1,101 @@ +body { + background-color: white; + border: 0px; + margin: 0px; + padding: 0px; +} + +.corner { + width: 200px; + height: 80px; + text-align: center; +} + +.banner { + background-color: rgb(110,139,61); + color: rgb(255,236,176); + padding-left: 2em; +} + +.banner h1 { + font-size: 200%; +} + +.content { + padding: 0em 2em 1em 2em; +} + +.releaseno { + background-color: rgb(110,139,61); + color: rgb(255,236,176); + padding-bottom: 0.3em; + padding-top: 0.5em; + text-align: center; + font-weight: bold; +} + +.noborder { + border-width: 0px; +} + +.eg { + padding-left: 1em; + padding-top: .5em; + padding-bottom: .5em; + border: solid thin; + margin: 1em 0; + background-color: tan; + margin-left: 2em; + margin-right: 10%; +} + +.pseudocode { + padding-left: 1em; + padding-top: .5em; + padding-bottom: .5em; + border: solid thin; + margin: 1em 0; + background-color: rgb(250,220,180); + margin-left: 2em; + margin-right: 10%; +} + +.handler { + width: 100%; + border-top-width: thin; + margin-bottom: 1em; +} + +.handler p { + margin-left: 2em; +} + +.setter { + font-weight: bold; +} + +.signature { + color: navy; +} + +.fcndec { + width: 100%; + border-top-width: thin; + font-weight: bold; +} + +.fcndef { + margin-left: 2em; + margin-bottom: 2em; +} + +dd { + margin-bottom: 2em; +} + +.cpp-symbols dt { + font-family: monospace; +} +.cpp-symbols dd { + margin-bottom: 1em; +} diff --git a/gdcm/Utilities/gdcmexpat/doc/xmlwf.1 b/gdcm/Utilities/gdcmexpat/doc/xmlwf.1 new file mode 100644 index 0000000..907d6c3 --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/doc/xmlwf.1 @@ -0,0 +1,251 @@ +.\" This manpage has been automatically generated by docbook2man +.\" from a DocBook document. This tool can be found at: +.\" +.\" Please send any bug reports, improvements, comments, patches, +.\" etc. to Steve Cheng . +.TH "XMLWF" "1" "24 January 2003" "" "" +.SH NAME +xmlwf \- Determines if an XML document is well-formed +.SH SYNOPSIS + +\fBxmlwf\fR [ \fB-s\fR] [ \fB-n\fR] [ \fB-p\fR] [ \fB-x\fR] [ \fB-e \fIencoding\fB\fR] [ \fB-w\fR] [ \fB-d \fIoutput-dir\fB\fR] [ \fB-c\fR] [ \fB-m\fR] [ \fB-r\fR] [ \fB-t\fR] [ \fB-v\fR] [ \fBfile ...\fR] + +.SH "DESCRIPTION" +.PP +\fBxmlwf\fR uses the Expat library to +determine if an XML document is well-formed. It is +non-validating. +.PP +If you do not specify any files on the command-line, and you +have a recent version of \fBxmlwf\fR, the +input file will be read from standard input. +.SH "WELL-FORMED DOCUMENTS" +.PP +A well-formed document must adhere to the +following rules: +.TP 0.2i +\(bu +The file begins with an XML declaration. For instance, +. +\fBNOTE:\fR +\fBxmlwf\fR does not currently +check for a valid XML declaration. +.TP 0.2i +\(bu +Every start tag is either empty () +or has a corresponding end tag. +.TP 0.2i +\(bu +There is exactly one root element. This element must contain +all other elements in the document. Only comments, white +space, and processing instructions may come after the close +of the root element. +.TP 0.2i +\(bu +All elements nest properly. +.TP 0.2i +\(bu +All attribute values are enclosed in quotes (either single +or double). +.PP +If the document has a DTD, and it strictly complies with that +DTD, then the document is also considered \fBvalid\fR. +\fBxmlwf\fR is a non-validating parser -- +it does not check the DTD. However, it does support +external entities (see the \fB-x\fR option). +.SH "OPTIONS" +.PP +When an option includes an argument, you may specify the argument either +separately ("\fB-d\fR output") or concatenated with the +option ("\fB-d\fRoutput"). \fBxmlwf\fR +supports both. +.TP +\fB-c\fR +If the input file is well-formed and \fBxmlwf\fR +doesn't encounter any errors, the input file is simply copied to +the output directory unchanged. +This implies no namespaces (turns off \fB-n\fR) and +requires \fB-d\fR to specify an output file. +.TP +\fB-d output-dir\fR +Specifies a directory to contain transformed +representations of the input files. +By default, \fB-d\fR outputs a canonical representation +(described below). +You can select different output formats using \fB-c\fR +and \fB-m\fR. + +The output filenames will +be exactly the same as the input filenames or "STDIN" if the input is +coming from standard input. Therefore, you must be careful that the +output file does not go into the same directory as the input +file. Otherwise, \fBxmlwf\fR will delete the +input file before it generates the output file (just like running +cat < file > file in most shells). + +Two structurally equivalent XML documents have a byte-for-byte +identical canonical XML representation. +Note that ignorable white space is considered significant and +is treated equivalently to data. +More on canonical XML can be found at +http://www.jclark.com/xml/canonxml.html . +.TP +\fB-e encoding\fR +Specifies the character encoding for the document, overriding +any document encoding declaration. \fBxmlwf\fR +supports four built-in encodings: +US-ASCII, +UTF-8, +UTF-16, and +ISO-8859-1. +Also see the \fB-w\fR option. +.TP +\fB-m\fR +Outputs some strange sort of XML file that completely +describes the the input file, including character postitions. +Requires \fB-d\fR to specify an output file. +.TP +\fB-n\fR +Turns on namespace processing. (describe namespaces) +\fB-c\fR disables namespaces. +.TP +\fB-p\fR +Tells xmlwf to process external DTDs and parameter +entities. + +Normally \fBxmlwf\fR never parses parameter +entities. \fB-p\fR tells it to always parse them. +\fB-p\fR implies \fB-x\fR. +.TP +\fB-r\fR +Normally \fBxmlwf\fR memory-maps the XML file +before parsing; this can result in faster parsing on many +platforms. +\fB-r\fR turns off memory-mapping and uses normal file +IO calls instead. +Of course, memory-mapping is automatically turned off +when reading from standard input. + +Use of memory-mapping can cause some platforms to report +substantially higher memory usage for +\fBxmlwf\fR, but this appears to be a matter of +the operating system reporting memory in a strange way; there is +not a leak in \fBxmlwf\fR. +.TP +\fB-s\fR +Prints an error if the document is not standalone. +A document is standalone if it has no external subset and no +references to parameter entities. +.TP +\fB-t\fR +Turns on timings. This tells Expat to parse the entire file, +but not perform any processing. +This gives a fairly accurate idea of the raw speed of Expat itself +without client overhead. +\fB-t\fR turns off most of the output options +(\fB-d\fR, \fB-m\fR, \fB-c\fR, +\&...). +.TP +\fB-v\fR +Prints the version of the Expat library being used, including some +information on the compile-time configuration of the library, and +then exits. +.TP +\fB-w\fR +Enables support for Windows code pages. +Normally, \fBxmlwf\fR will throw an error if it +runs across an encoding that it is not equipped to handle itself. With +\fB-w\fR, xmlwf will try to use a Windows code +page. See also \fB-e\fR. +.TP +\fB-x\fR +Turns on parsing external entities. + +Non-validating parsers are not required to resolve external +entities, or even expand entities at all. +Expat always expands internal entities (?), +but external entity parsing must be enabled explicitly. + +External entities are simply entities that obtain their +data from outside the XML file currently being parsed. + +This is an example of an internal entity: + +.nf + +.fi + +And here are some examples of external entities: + +.nf + (parsed) + (unparsed) +.fi +.TP +\fB--\fR +(Two hyphens.) +Terminates the list of options. This is only needed if a filename +starts with a hyphen. For example: + +.nf +xmlwf -- -myfile.xml +.fi + +will run \fBxmlwf\fR on the file +\fI-myfile.xml\fR. +.PP +Older versions of \fBxmlwf\fR do not support +reading from standard input. +.SH "OUTPUT" +.PP +If an input file is not well-formed, +\fBxmlwf\fR prints a single line describing +the problem to standard output. If a file is well formed, +\fBxmlwf\fR outputs nothing. +Note that the result code is \fBnot\fR set. +.SH "BUGS" +.PP +According to the W3C standard, an XML file without a +declaration at the beginning is not considered well-formed. +However, \fBxmlwf\fR allows this to pass. +.PP +\fBxmlwf\fR returns a 0 - noerr result, +even if the file is not well-formed. There is no good way for +a program to use \fBxmlwf\fR to quickly +check a file -- it must parse \fBxmlwf\fR's +standard output. +.PP +The errors should go to standard error, not standard output. +.PP +There should be a way to get \fB-d\fR to send its +output to standard output rather than forcing the user to send +it to a file. +.PP +I have no idea why anyone would want to use the +\fB-d\fR, \fB-c\fR, and +\fB-m\fR options. If someone could explain it to +me, I'd like to add this information to this manpage. +.SH "ALTERNATIVES" +.PP +Here are some XML validators on the web: + +.nf +http://www.hcrc.ed.ac.uk/~richard/xml-check.html +http://www.stg.brown.edu/service/xmlvalid/ +http://www.scripting.com/frontier5/xml/code/xmlValidator.html +http://www.xml.com/pub/a/tools/ruwf/check.html +.fi +.SH "SEE ALSO" +.PP + +.nf +The Expat home page: http://www.libexpat.org/ +The W3 XML specification: http://www.w3.org/TR/REC-xml +.fi +.SH "AUTHOR" +.PP +This manual page was written by Scott Bronson for +the Debian GNU/Linux system (but may be used by others). Permission is +granted to copy, distribute and/or modify this document under +the terms of the GNU Free Documentation +License, Version 1.1. diff --git a/gdcm/Utilities/gdcmexpat/doc/xmlwf.sgml b/gdcm/Utilities/gdcmexpat/doc/xmlwf.sgml new file mode 100644 index 0000000..139c95e --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/doc/xmlwf.sgml @@ -0,0 +1,473 @@ + manpage.1'. You may view + the manual page with: `docbook-to-man manpage.sgml | nroff -man | + less'. A typical entry in a Makefile or Makefile.am is: + +manpage.1: manpage.sgml + docbook-to-man $< > $@ + --> + + + Scott"> + Bronson"> + + December 5, 2001"> + + 1"> + bronson@rinspin.com"> + + XMLWF"> + + + Debian GNU/Linux"> + GNU"> +]> + + + +
+ &dhemail; +
+ + &dhfirstname; + &dhsurname; + + + 2001 + &dhusername; + + &dhdate; +
+ + &dhucpackage; + + &dhsection; + + + &dhpackage; + + Determines if an XML document is well-formed + + + + &dhpackage; + + + + + + + + + + + + + + + + + + file ... + + + + + DESCRIPTION + + + &dhpackage; uses the Expat library to + determine if an XML document is well-formed. It is + non-validating. + + + + If you do not specify any files on the command-line, and you + have a recent version of &dhpackage;, the + input file will be read from standard input. + + + + + + WELL-FORMED DOCUMENTS + + + A well-formed document must adhere to the + following rules: + + + + + The file begins with an XML declaration. For instance, + <?xml version="1.0" standalone="yes"?>. + NOTE: + &dhpackage; does not currently + check for a valid XML declaration. + + + Every start tag is either empty (<tag/>) + or has a corresponding end tag. + + + There is exactly one root element. This element must contain + all other elements in the document. Only comments, white + space, and processing instructions may come after the close + of the root element. + + + All elements nest properly. + + + All attribute values are enclosed in quotes (either single + or double). + + + + + If the document has a DTD, and it strictly complies with that + DTD, then the document is also considered valid. + &dhpackage; is a non-validating parser -- + it does not check the DTD. However, it does support + external entities (see the option). + + + + + OPTIONS + + +When an option includes an argument, you may specify the argument either +separately (" output") or concatenated with the +option ("output"). &dhpackage; +supports both. + + + + + + + + + If the input file is well-formed and &dhpackage; + doesn't encounter any errors, the input file is simply copied to + the output directory unchanged. + This implies no namespaces (turns off ) and + requires to specify an output file. + + + + + + + + + Specifies a directory to contain transformed + representations of the input files. + By default, outputs a canonical representation + (described below). + You can select different output formats using + and . + + + The output filenames will + be exactly the same as the input filenames or "STDIN" if the input is + coming from standard input. Therefore, you must be careful that the + output file does not go into the same directory as the input + file. Otherwise, &dhpackage; will delete the + input file before it generates the output file (just like running + cat < file > file in most shells). + + + Two structurally equivalent XML documents have a byte-for-byte + identical canonical XML representation. + Note that ignorable white space is considered significant and + is treated equivalently to data. + More on canonical XML can be found at + http://www.jclark.com/xml/canonxml.html . + + + + + + + + + Specifies the character encoding for the document, overriding + any document encoding declaration. &dhpackage; + supports four built-in encodings: + US-ASCII, + UTF-8, + UTF-16, and + ISO-8859-1. + Also see the option. + + + + + + + + + Outputs some strange sort of XML file that completely + describes the the input file, including character postitions. + Requires to specify an output file. + + + + + + + + + Turns on namespace processing. (describe namespaces) + disables namespaces. + + + + + + + + + Tells xmlwf to process external DTDs and parameter + entities. + + + Normally &dhpackage; never parses parameter + entities. tells it to always parse them. + implies . + + + + + + + + + Normally &dhpackage; memory-maps the XML file + before parsing; this can result in faster parsing on many + platforms. + turns off memory-mapping and uses normal file + IO calls instead. + Of course, memory-mapping is automatically turned off + when reading from standard input. + + + Use of memory-mapping can cause some platforms to report + substantially higher memory usage for + &dhpackage;, but this appears to be a matter of + the operating system reporting memory in a strange way; there is + not a leak in &dhpackage;. + + + + + + + + + Prints an error if the document is not standalone. + A document is standalone if it has no external subset and no + references to parameter entities. + + + + + + + + + Turns on timings. This tells Expat to parse the entire file, + but not perform any processing. + This gives a fairly accurate idea of the raw speed of Expat itself + without client overhead. + turns off most of the output options + (, , , + ...). + + + + + + + + + Prints the version of the Expat library being used, including some + information on the compile-time configuration of the library, and + then exits. + + + + + + + + + Enables support for Windows code pages. + Normally, &dhpackage; will throw an error if it + runs across an encoding that it is not equipped to handle itself. With + , &dhpackage; will try to use a Windows code + page. See also . + + + + + + + + + Turns on parsing external entities. + + + Non-validating parsers are not required to resolve external + entities, or even expand entities at all. + Expat always expands internal entities (?), + but external entity parsing must be enabled explicitly. + + + External entities are simply entities that obtain their + data from outside the XML file currently being parsed. + + + This is an example of an internal entity: + +<!ENTITY vers '1.0.2'> + + + + And here are some examples of external entities: + + +<!ENTITY header SYSTEM "header-&vers;.xml"> (parsed) +<!ENTITY logo SYSTEM "logo.png" PNG> (unparsed) + + + + + + + + + + + (Two hyphens.) + Terminates the list of options. This is only needed if a filename + starts with a hyphen. For example: + + +&dhpackage; -- -myfile.xml + + + will run &dhpackage; on the file + -myfile.xml. + + + + + + + Older versions of &dhpackage; do not support + reading from standard input. + + + + + OUTPUT + + If an input file is not well-formed, + &dhpackage; prints a single line describing + the problem to standard output. If a file is well formed, + &dhpackage; outputs nothing. + Note that the result code is not set. + + + + + BUGS + + According to the W3C standard, an XML file without a + declaration at the beginning is not considered well-formed. + However, &dhpackage; allows this to pass. + + + &dhpackage; returns a 0 - noerr result, + even if the file is not well-formed. There is no good way for + a program to use &dhpackage; to quickly + check a file -- it must parse &dhpackage;'s + standard output. + + + The errors should go to standard error, not standard output. + + + There should be a way to get to send its + output to standard output rather than forcing the user to send + it to a file. + + + I have no idea why anyone would want to use the + , , and + options. If someone could explain it to + me, I'd like to add this information to this manpage. + + + + + ALTERNATIVES + + Here are some XML validators on the web: + + +http://www.hcrc.ed.ac.uk/~richard/xml-check.html +http://www.stg.brown.edu/service/xmlvalid/ +http://www.scripting.com/frontier5/xml/code/xmlValidator.html +http://www.xml.com/pub/a/tools/ruwf/check.html + + + + + + + SEE ALSO + + + +The Expat home page: http://www.libexpat.org/ +The W3 XML specification: http://www.w3.org/TR/REC-xml + + + + + + + AUTHOR + + This manual page was written by &dhusername; &dhemail; for + the &debian; system (but may be used by others). Permission is + granted to copy, distribute and/or modify this document under + the terms of the GNU Free Documentation + License, Version 1.1. + + +
+ + diff --git a/gdcm/Utilities/gdcmexpat/examples/elements.c b/gdcm/Utilities/gdcmexpat/examples/elements.c new file mode 100644 index 0000000..421a1ce --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/examples/elements.c @@ -0,0 +1,67 @@ +/* This is simple demonstration of how to use expat. This program + reads an XML document from standard input and writes a line with + the name of each element to standard output indenting child + elements by one tab stop more than their parent element. + It must be used with Expat compiled for UTF-8 output. +*/ + +#include +#include "expat.h" + +#ifdef XML_LARGE_SIZE +#if defined(XML_USE_MSC_EXTENSIONS) && _MSC_VER < 1400 +#define XML_FMT_INT_MOD "I64" +#else +#define XML_FMT_INT_MOD "ll" +#endif +#else +#define XML_FMT_INT_MOD "l" +#endif + +static void XMLCALL +startElement(void *userData, const char *name, const char **atts) +{ + int i; + int *depthPtr = (int *)userData; + for (i = 0; i < *depthPtr; i++) + putchar('\t'); + puts(name); + *depthPtr += 1; +} + +static void XMLCALL +endElement(void *userData, const char *name) +{ + int *depthPtr = (int *)userData; + *depthPtr -= 1; +} + +#ifdef AMIGA_SHARED_LIB +#include +int +amiga_main(int argc, char *argv[]) +#else +int +main(int argc, char *argv[]) +#endif +{ + char buf[BUFSIZ]; + XML_Parser parser = XML_ParserCreate(NULL); + int done; + int depth = 0; + XML_SetUserData(parser, &depth); + XML_SetElementHandler(parser, startElement, endElement); + do { + size_t len = fread(buf, 1, sizeof(buf), stdin); + done = len < sizeof(buf); + if (XML_Parse(parser, buf, len, done) == XML_STATUS_ERROR) { + fprintf(stderr, + "%s at line %" XML_FMT_INT_MOD "u\n", + XML_ErrorString(XML_GetErrorCode(parser)), + XML_GetCurrentLineNumber(parser)); + return 1; + } + } while (!done); + XML_ParserFree(parser); + return 0; +} diff --git a/gdcm/Utilities/gdcmexpat/examples/outline.c b/gdcm/Utilities/gdcmexpat/examples/outline.c new file mode 100644 index 0000000..807ddb8 --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/examples/outline.c @@ -0,0 +1,107 @@ +/***************************************************************** + * outline.c + * + * Copyright 1999, Clark Cooper + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the license contained in the + * COPYING file that comes with the expat distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Read an XML document from standard input and print an element + * outline on standard output. + * Must be used with Expat compiled for UTF-8 output. + */ + + +#include +#include + +#ifdef XML_LARGE_SIZE +#if defined(XML_USE_MSC_EXTENSIONS) && _MSC_VER < 1400 +#define XML_FMT_INT_MOD "I64" +#else +#define XML_FMT_INT_MOD "ll" +#endif +#else +#define XML_FMT_INT_MOD "l" +#endif + +#define BUFFSIZE 8192 + +char Buff[BUFFSIZE]; + +int Depth; + +static void XMLCALL +start(void *data, const char *el, const char **attr) +{ + int i; + + for (i = 0; i < Depth; i++) + printf(" "); + + printf("%s", el); + + for (i = 0; attr[i]; i += 2) { + printf(" %s='%s'", attr[i], attr[i + 1]); + } + + printf("\n"); + Depth++; +} + +static void XMLCALL +end(void *data, const char *el) +{ + Depth--; +} + +#ifdef AMIGA_SHARED_LIB +#include +int +amiga_main(int argc, char *argv[]) +#else +int +main(int argc, char *argv[]) +#endif +{ + XML_Parser p = XML_ParserCreate(NULL); + if (! p) { + fprintf(stderr, "Couldn't allocate memory for parser\n"); + exit(-1); + } + + XML_SetElementHandler(p, start, end); + + for (;;) { + int done; + int len; + + len = fread(Buff, 1, BUFFSIZE, stdin); + if (ferror(stdin)) { + fprintf(stderr, "Read error\n"); + exit(-1); + } + done = feof(stdin); + + if (XML_Parse(p, Buff, len, done) == XML_STATUS_ERROR) { + fprintf(stderr, "Parse error at line %" XML_FMT_INT_MOD "u:\n%s\n", + XML_GetCurrentLineNumber(p), + XML_ErrorString(XML_GetErrorCode(p))); + exit(-1); + } + + if (done) + break; + } + return 0; +} diff --git a/gdcm/Utilities/gdcmexpat/expat_config.h.in b/gdcm/Utilities/gdcmexpat/expat_config.h.in new file mode 100644 index 0000000..f54d24c --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/expat_config.h.in @@ -0,0 +1,92 @@ +/* expat_config.h.in. Generated from configure.in by autoheader. */ + +/* 1234 = LIL_ENDIAN, 4321 = BIGENDIAN */ +#undef BYTEORDER + +/* Define to 1 if you have the `bcopy' function. */ +#undef HAVE_BCOPY + +/* Define to 1 if you have the header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_FCNTL_H + +/* Define to 1 if you have the `getpagesize' function. */ +#undef HAVE_GETPAGESIZE + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the `memmove' function. */ +#cmakedefine HAVE_MEMMOVE + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have a working `mmap' system call. */ +#undef HAVE_MMAP + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* whether byteorder is bigendian */ +#undef WORDS_BIGENDIAN + +/* Define to specify how much context to retain around the current parse + point. */ +#undef XML_CONTEXT_BYTES + +/* Define to make parameter entity parsing functionality available. */ +#undef XML_DTD + +/* Define to make XML Namespaces functionality available. */ +#undef XML_NS + +/* Define to __FUNCTION__ or "" if `__func__' does not conform to ANSI C. */ +#undef __func__ + +/* Define to empty if `const' does not conform to ANSI C. */ +#undef const + +/* Define to `long' if does not define. */ +#undef off_t + +/* Define to `unsigned' if does not define. */ +#undef size_t diff --git a/gdcm/Utilities/gdcmexpat/expat_mangle.h.in b/gdcm/Utilities/gdcmexpat/expat_mangle.h.in new file mode 100644 index 0000000..8c4edef --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/expat_mangle.h.in @@ -0,0 +1,89 @@ +/* This file was generated by CMake http://www.cmake.org */ + +#ifndef @MANGLE_PREFIX@_mangle_h +#define @MANGLE_PREFIX@_mangle_h + +/* + * This header file mangles all symbols exported from the expat library. + * It is included in all files while building the expat library. Due to + * namespace pollution, no expat headers should be included in .h files in + * GDCM. + * + * The following command was used to obtain the symbol list: + * + * nm lib@MANGLE_PREFIX@.a |grep " [TR] " + */ + +#define asParser @MANGLE_PREFIX@_asParser +#define XML_DefaultCurrent @MANGLE_PREFIX@_XML_DefaultCurrent +#define XML_ErrorString @MANGLE_PREFIX@_XML_ErrorString +#define XML_ExpatVersion @MANGLE_PREFIX@_XML_ExpatVersion +#define XML_ExpatVersionInfo @MANGLE_PREFIX@_XML_ExpatVersionInfo +#define XML_ExternalEntityParserCreate @MANGLE_PREFIX@_XML_ExternalEntityParserCreate +#define XML_GetBase @MANGLE_PREFIX@_XML_GetBase +#define XML_GetBuffer @MANGLE_PREFIX@_XML_GetBuffer +#define XML_GetCurrentByteCount @MANGLE_PREFIX@_XML_GetCurrentByteCount +#define XML_GetCurrentByteIndex @MANGLE_PREFIX@_XML_GetCurrentByteIndex +#define XML_GetCurrentColumnNumber @MANGLE_PREFIX@_XML_GetCurrentColumnNumber +#define XML_GetCurrentLineNumber @MANGLE_PREFIX@_XML_GetCurrentLineNumber +#define XML_GetErrorCode @MANGLE_PREFIX@_XML_GetErrorCode +#define XML_GetIdAttributeIndex @MANGLE_PREFIX@_XML_GetIdAttributeIndex +#define XML_GetInputContext @MANGLE_PREFIX@_XML_GetInputContext +#define XML_GetSpecifiedAttributeCount @MANGLE_PREFIX@_XML_GetSpecifiedAttributeCount +#define XML_Parse @MANGLE_PREFIX@_XML_Parse +#define XML_ParseBuffer @MANGLE_PREFIX@_XML_ParseBuffer +#define XML_ParserCreate @MANGLE_PREFIX@_XML_ParserCreate +#define XML_ParserCreateNS @MANGLE_PREFIX@_XML_ParserCreateNS +#define XML_ParserCreate_MM @MANGLE_PREFIX@_XML_ParserCreate_MM +#define XML_ParserFree @MANGLE_PREFIX@_XML_ParserFree +#define XML_SetAttlistDeclHandler @MANGLE_PREFIX@_XML_SetAttlistDeclHandler +#define XML_SetBase @MANGLE_PREFIX@_XML_SetBase +#define XML_SetCdataSectionHandler @MANGLE_PREFIX@_XML_SetCdataSectionHandler +#define XML_SetCharacterDataHandler @MANGLE_PREFIX@_XML_SetCharacterDataHandler +#define XML_SetCommentHandler @MANGLE_PREFIX@_XML_SetCommentHandler +#define XML_SetDefaultHandler @MANGLE_PREFIX@_XML_SetDefaultHandler +#define XML_SetDefaultHandlerExpand @MANGLE_PREFIX@_XML_SetDefaultHandlerExpand +#define XML_SetDoctypeDeclHandler @MANGLE_PREFIX@_XML_SetDoctypeDeclHandler +#define XML_SetElementDeclHandler @MANGLE_PREFIX@_XML_SetElementDeclHandler +#define XML_SetElementHandler @MANGLE_PREFIX@_XML_SetElementHandler +#define XML_SetEncoding @MANGLE_PREFIX@_XML_SetEncoding +#define XML_SetEndCdataSectionHandler @MANGLE_PREFIX@_XML_SetEndCdataSectionHandler +#define XML_SetEndDoctypeDeclHandler @MANGLE_PREFIX@_XML_SetEndDoctypeDeclHandler +#define XML_SetEndElementHandler @MANGLE_PREFIX@_XML_SetEndElementHandler +#define XML_SetEndNamespaceDeclHandler @MANGLE_PREFIX@_XML_SetEndNamespaceDeclHandler +#define XML_SetEntityDeclHandler @MANGLE_PREFIX@_XML_SetEntityDeclHandler +#define XML_SetExternalEntityRefHandler @MANGLE_PREFIX@_XML_SetExternalEntityRefHandler +#define XML_SetExternalEntityRefHandlerArg @MANGLE_PREFIX@_XML_SetExternalEntityRefHandlerArg +#define XML_SetNamespaceDeclHandler @MANGLE_PREFIX@_XML_SetNamespaceDeclHandler +#define XML_SetNotStandaloneHandler @MANGLE_PREFIX@_XML_SetNotStandaloneHandler +#define XML_SetNotationDeclHandler @MANGLE_PREFIX@_XML_SetNotationDeclHandler +#define XML_SetParamEntityParsing @MANGLE_PREFIX@_XML_SetParamEntityParsing +#define XML_SetProcessingInstructionHandler @MANGLE_PREFIX@_XML_SetProcessingInstructionHandler +#define XML_SetReturnNSTriplet @MANGLE_PREFIX@_XML_SetReturnNSTriplet +#define XML_SetStartCdataSectionHandler @MANGLE_PREFIX@_XML_SetStartCdataSectionHandler +#define XML_SetStartDoctypeDeclHandler @MANGLE_PREFIX@_XML_SetStartDoctypeDeclHandler +#define XML_SetStartElementHandler @MANGLE_PREFIX@_XML_SetStartElementHandler +#define XML_SetStartNamespaceDeclHandler @MANGLE_PREFIX@_XML_SetStartNamespaceDeclHandler +#define XML_SetUnknownEncodingHandler @MANGLE_PREFIX@_XML_SetUnknownEncodingHandler +#define XML_SetUnparsedEntityDeclHandler @MANGLE_PREFIX@_XML_SetUnparsedEntityDeclHandler +#define XML_SetUserData @MANGLE_PREFIX@_XML_SetUserData +#define XML_SetXmlDeclHandler @MANGLE_PREFIX@_XML_SetXmlDeclHandler +#define XML_UseParserAsHandlerArg @MANGLE_PREFIX@_XML_UseParserAsHandlerArg +#define XmlGetUtf16InternalEncoding @MANGLE_PREFIX@_XmlGetUtf16InternalEncoding +#define XmlGetUtf16InternalEncodingNS @MANGLE_PREFIX@_XmlGetUtf16InternalEncodingNS +#define XmlGetUtf8InternalEncoding @MANGLE_PREFIX@_XmlGetUtf8InternalEncoding +#define XmlGetUtf8InternalEncodingNS @MANGLE_PREFIX@_XmlGetUtf8InternalEncodingNS +#define XmlInitEncoding @MANGLE_PREFIX@_XmlInitEncoding +#define XmlInitEncodingNS @MANGLE_PREFIX@_XmlInitEncodingNS +#define XmlInitUnknownEncoding @MANGLE_PREFIX@_XmlInitUnknownEncoding +#define XmlInitUnknownEncodingNS @MANGLE_PREFIX@_XmlInitUnknownEncodingNS +#define XmlParseXmlDecl @MANGLE_PREFIX@_XmlParseXmlDecl +#define XmlParseXmlDeclNS @MANGLE_PREFIX@_XmlParseXmlDeclNS +#define XmlSizeOfUnknownEncoding @MANGLE_PREFIX@_XmlSizeOfUnknownEncoding +#define XmlUtf16Encode @MANGLE_PREFIX@_XmlUtf16Encode +#define XmlUtf8Encode @MANGLE_PREFIX@_XmlUtf8Encode +#define XmlPrologStateInit @MANGLE_PREFIX@_XmlPrologStateInit +#define XmlPrologStateInitExternalEntity @MANGLE_PREFIX@_XmlPrologStateInitExternalEntity + +#endif + diff --git a/gdcm/Utilities/gdcmexpat/lib/CMakeLists.txt b/gdcm/Utilities/gdcmexpat/lib/CMakeLists.txt new file mode 100644 index 0000000..08e6a5f --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/lib/CMakeLists.txt @@ -0,0 +1,18 @@ + +set(EXPAT_SRCS + xmlparse.c + xmltok.c + xmlrole.c +) + +add_library(${EXPAT_LIBRARY_NAME} ${EXPAT_SRCS}) +set_target_properties(${EXPAT_LIBRARY_NAME} PROPERTIES ${EXPAT_LIBRARY_PROPERTIES}) +if(NOT EXPAT_INSTALL_NO_LIBRARIES) + install(TARGETS ${EXPAT_LIBRARY_NAME} + EXPORT ${GDCM_TARGETS_NAME} + RUNTIME DESTINATION ${EXPAT_INSTALL_BIN_DIR} COMPONENT Applications + LIBRARY DESTINATION ${EXPAT_INSTALL_LIB_DIR} COMPONENT Libraries + ARCHIVE DESTINATION ${EXPAT_INSTALL_LIB_DIR} COMPONENT DebugDevel + ${CPACK_NAMELINK_TYPE} + ) +endif() diff --git a/gdcm/Utilities/gdcmexpat/lib/ascii.h b/gdcm/Utilities/gdcmexpat/lib/ascii.h new file mode 100644 index 0000000..337e5bb --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/lib/ascii.h @@ -0,0 +1,85 @@ +/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +#define ASCII_A 0x41 +#define ASCII_B 0x42 +#define ASCII_C 0x43 +#define ASCII_D 0x44 +#define ASCII_E 0x45 +#define ASCII_F 0x46 +#define ASCII_G 0x47 +#define ASCII_H 0x48 +#define ASCII_I 0x49 +#define ASCII_J 0x4A +#define ASCII_K 0x4B +#define ASCII_L 0x4C +#define ASCII_M 0x4D +#define ASCII_N 0x4E +#define ASCII_O 0x4F +#define ASCII_P 0x50 +#define ASCII_Q 0x51 +#define ASCII_R 0x52 +#define ASCII_S 0x53 +#define ASCII_T 0x54 +#define ASCII_U 0x55 +#define ASCII_V 0x56 +#define ASCII_W 0x57 +#define ASCII_X 0x58 +#define ASCII_Y 0x59 +#define ASCII_Z 0x5A + +#define ASCII_a 0x61 +#define ASCII_b 0x62 +#define ASCII_c 0x63 +#define ASCII_d 0x64 +#define ASCII_e 0x65 +#define ASCII_f 0x66 +#define ASCII_g 0x67 +#define ASCII_h 0x68 +#define ASCII_i 0x69 +#define ASCII_j 0x6A +#define ASCII_k 0x6B +#define ASCII_l 0x6C +#define ASCII_m 0x6D +#define ASCII_n 0x6E +#define ASCII_o 0x6F +#define ASCII_p 0x70 +#define ASCII_q 0x71 +#define ASCII_r 0x72 +#define ASCII_s 0x73 +#define ASCII_t 0x74 +#define ASCII_u 0x75 +#define ASCII_v 0x76 +#define ASCII_w 0x77 +#define ASCII_x 0x78 +#define ASCII_y 0x79 +#define ASCII_z 0x7A + +#define ASCII_0 0x30 +#define ASCII_1 0x31 +#define ASCII_2 0x32 +#define ASCII_3 0x33 +#define ASCII_4 0x34 +#define ASCII_5 0x35 +#define ASCII_6 0x36 +#define ASCII_7 0x37 +#define ASCII_8 0x38 +#define ASCII_9 0x39 + +#define ASCII_TAB 0x09 +#define ASCII_SPACE 0x20 +#define ASCII_EXCL 0x21 +#define ASCII_QUOT 0x22 +#define ASCII_AMP 0x26 +#define ASCII_APOS 0x27 +#define ASCII_MINUS 0x2D +#define ASCII_PERIOD 0x2E +#define ASCII_COLON 0x3A +#define ASCII_SEMI 0x3B +#define ASCII_LT 0x3C +#define ASCII_EQUALS 0x3D +#define ASCII_GT 0x3E +#define ASCII_LSQB 0x5B +#define ASCII_RSQB 0x5D +#define ASCII_UNDERSCORE 0x5F diff --git a/gdcm/Utilities/gdcmexpat/lib/asciitab.h b/gdcm/Utilities/gdcmexpat/lib/asciitab.h new file mode 100644 index 0000000..79a15c2 --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/lib/asciitab.h @@ -0,0 +1,36 @@ +/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +/* 0x00 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x04 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x08 */ BT_NONXML, BT_S, BT_LF, BT_NONXML, +/* 0x0C */ BT_NONXML, BT_CR, BT_NONXML, BT_NONXML, +/* 0x10 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x14 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x18 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x1C */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x20 */ BT_S, BT_EXCL, BT_QUOT, BT_NUM, +/* 0x24 */ BT_OTHER, BT_PERCNT, BT_AMP, BT_APOS, +/* 0x28 */ BT_LPAR, BT_RPAR, BT_AST, BT_PLUS, +/* 0x2C */ BT_COMMA, BT_MINUS, BT_NAME, BT_SOL, +/* 0x30 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT, +/* 0x34 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT, +/* 0x38 */ BT_DIGIT, BT_DIGIT, BT_COLON, BT_SEMI, +/* 0x3C */ BT_LT, BT_EQUALS, BT_GT, BT_QUEST, +/* 0x40 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX, +/* 0x44 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT, +/* 0x48 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x4C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x50 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x54 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x58 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_LSQB, +/* 0x5C */ BT_OTHER, BT_RSQB, BT_OTHER, BT_NMSTRT, +/* 0x60 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX, +/* 0x64 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT, +/* 0x68 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x6C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x70 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x74 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x78 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER, +/* 0x7C */ BT_VERBAR, BT_OTHER, BT_OTHER, BT_OTHER, diff --git a/gdcm/Utilities/gdcmexpat/lib/expat.h b/gdcm/Utilities/gdcmexpat/lib/expat.h new file mode 100644 index 0000000..cf113ee --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/lib/expat.h @@ -0,0 +1,1013 @@ +/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +#ifndef Expat_INCLUDED +#define Expat_INCLUDED 1 + +#ifdef __VMS +/* 0 1 2 3 0 1 2 3 + 1234567890123456789012345678901 1234567890123456789012345678901 */ +#define XML_SetProcessingInstructionHandler XML_SetProcessingInstrHandler +#define XML_SetUnparsedEntityDeclHandler XML_SetUnparsedEntDeclHandler +#define XML_SetStartNamespaceDeclHandler XML_SetStartNamespcDeclHandler +#define XML_SetExternalEntityRefHandlerArg XML_SetExternalEntRefHandlerArg +#endif + +#include +#include "expat_external.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct XML_ParserStruct; +typedef struct XML_ParserStruct *XML_Parser; + +/* Should this be defined using stdbool.h when C99 is available? */ +typedef unsigned char XML_Bool; +#define XML_TRUE ((XML_Bool) 1) +#define XML_FALSE ((XML_Bool) 0) + +/* The XML_Status enum gives the possible return values for several + API functions. The preprocessor #defines are included so this + stanza can be added to code that still needs to support older + versions of Expat 1.95.x: + + #ifndef XML_STATUS_OK + #define XML_STATUS_OK 1 + #define XML_STATUS_ERROR 0 + #endif + + Otherwise, the #define hackery is quite ugly and would have been + dropped. +*/ +enum XML_Status { + XML_STATUS_ERROR = 0, +#define XML_STATUS_ERROR XML_STATUS_ERROR + XML_STATUS_OK = 1, +#define XML_STATUS_OK XML_STATUS_OK + XML_STATUS_SUSPENDED = 2 +#define XML_STATUS_SUSPENDED XML_STATUS_SUSPENDED +}; + +enum XML_Error { + XML_ERROR_NONE, + XML_ERROR_NO_MEMORY, + XML_ERROR_SYNTAX, + XML_ERROR_NO_ELEMENTS, + XML_ERROR_INVALID_TOKEN, + XML_ERROR_UNCLOSED_TOKEN, + XML_ERROR_PARTIAL_CHAR, + XML_ERROR_TAG_MISMATCH, + XML_ERROR_DUPLICATE_ATTRIBUTE, + XML_ERROR_JUNK_AFTER_DOC_ELEMENT, + XML_ERROR_PARAM_ENTITY_REF, + XML_ERROR_UNDEFINED_ENTITY, + XML_ERROR_RECURSIVE_ENTITY_REF, + XML_ERROR_ASYNC_ENTITY, + XML_ERROR_BAD_CHAR_REF, + XML_ERROR_BINARY_ENTITY_REF, + XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF, + XML_ERROR_MISPLACED_XML_PI, + XML_ERROR_UNKNOWN_ENCODING, + XML_ERROR_INCORRECT_ENCODING, + XML_ERROR_UNCLOSED_CDATA_SECTION, + XML_ERROR_EXTERNAL_ENTITY_HANDLING, + XML_ERROR_NOT_STANDALONE, + XML_ERROR_UNEXPECTED_STATE, + XML_ERROR_ENTITY_DECLARED_IN_PE, + XML_ERROR_FEATURE_REQUIRES_XML_DTD, + XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING, + /* Added in 1.95.7. */ + XML_ERROR_UNBOUND_PREFIX, + /* Added in 1.95.8. */ + XML_ERROR_UNDECLARING_PREFIX, + XML_ERROR_INCOMPLETE_PE, + XML_ERROR_XML_DECL, + XML_ERROR_TEXT_DECL, + XML_ERROR_PUBLICID, + XML_ERROR_SUSPENDED, + XML_ERROR_NOT_SUSPENDED, + XML_ERROR_ABORTED, + XML_ERROR_FINISHED, + XML_ERROR_SUSPEND_PE, + /* Added in 2.0. */ + XML_ERROR_RESERVED_PREFIX_XML, + XML_ERROR_RESERVED_PREFIX_XMLNS, + XML_ERROR_RESERVED_NAMESPACE_URI +}; + +enum XML_Content_Type { + XML_CTYPE_EMPTY = 1, + XML_CTYPE_ANY, + XML_CTYPE_MIXED, + XML_CTYPE_NAME, + XML_CTYPE_CHOICE, + XML_CTYPE_SEQ +}; + +enum XML_Content_Quant { + XML_CQUANT_NONE, + XML_CQUANT_OPT, + XML_CQUANT_REP, + XML_CQUANT_PLUS +}; + +/* If type == XML_CTYPE_EMPTY or XML_CTYPE_ANY, then quant will be + XML_CQUANT_NONE, and the other fields will be zero or NULL. + If type == XML_CTYPE_MIXED, then quant will be NONE or REP and + numchildren will contain number of elements that may be mixed in + and children point to an array of XML_Content cells that will be + all of XML_CTYPE_NAME type with no quantification. + + If type == XML_CTYPE_NAME, then the name points to the name, and + the numchildren field will be zero and children will be NULL. The + quant fields indicates any quantifiers placed on the name. + + CHOICE and SEQ will have name NULL, the number of children in + numchildren and children will point, recursively, to an array + of XML_Content cells. + + The EMPTY, ANY, and MIXED types will only occur at top level. +*/ + +typedef struct XML_cp XML_Content; + +struct XML_cp { + enum XML_Content_Type type; + enum XML_Content_Quant quant; + XML_Char * name; + unsigned int numchildren; + XML_Content * children; +}; + + +/* This is called for an element declaration. See above for + description of the model argument. It's the caller's responsibility + to free model when finished with it. +*/ +typedef void (XMLCALL *XML_ElementDeclHandler) (void *userData, + const XML_Char *name, + XML_Content *model); + +XMLPARSEAPI(void) +XML_SetElementDeclHandler(XML_Parser parser, + XML_ElementDeclHandler eldecl); + +/* The Attlist declaration handler is called for *each* attribute. So + a single Attlist declaration with multiple attributes declared will + generate multiple calls to this handler. The "default" parameter + may be NULL in the case of the "#IMPLIED" or "#REQUIRED" + keyword. The "isrequired" parameter will be true and the default + value will be NULL in the case of "#REQUIRED". If "isrequired" is + true and default is non-NULL, then this is a "#FIXED" default. +*/ +typedef void (XMLCALL *XML_AttlistDeclHandler) ( + void *userData, + const XML_Char *elname, + const XML_Char *attname, + const XML_Char *att_type, + const XML_Char *dflt, + int isrequired); + +XMLPARSEAPI(void) +XML_SetAttlistDeclHandler(XML_Parser parser, + XML_AttlistDeclHandler attdecl); + +/* The XML declaration handler is called for *both* XML declarations + and text declarations. The way to distinguish is that the version + parameter will be NULL for text declarations. The encoding + parameter may be NULL for XML declarations. The standalone + parameter will be -1, 0, or 1 indicating respectively that there + was no standalone parameter in the declaration, that it was given + as no, or that it was given as yes. +*/ +typedef void (XMLCALL *XML_XmlDeclHandler) (void *userData, + const XML_Char *version, + const XML_Char *encoding, + int standalone); + +XMLPARSEAPI(void) +XML_SetXmlDeclHandler(XML_Parser parser, + XML_XmlDeclHandler xmldecl); + + +typedef struct { + void *(*malloc_fcn)(size_t size); + void *(*realloc_fcn)(void *ptr, size_t size); + void (*free_fcn)(void *ptr); +} XML_Memory_Handling_Suite; + +/* Constructs a new parser; encoding is the encoding specified by the + external protocol or NULL if there is none specified. +*/ +XMLPARSEAPI(XML_Parser) +XML_ParserCreate(const XML_Char *encoding); + +/* Constructs a new parser and namespace processor. Element type + names and attribute names that belong to a namespace will be + expanded; unprefixed attribute names are never expanded; unprefixed + element type names are expanded only if there is a default + namespace. The expanded name is the concatenation of the namespace + URI, the namespace separator character, and the local part of the + name. If the namespace separator is '\0' then the namespace URI + and the local part will be concatenated without any separator. + It is a programming error to use the separator '\0' with namespace + triplets (see XML_SetReturnNSTriplet). +*/ +XMLPARSEAPI(XML_Parser) +XML_ParserCreateNS(const XML_Char *encoding, XML_Char namespaceSeparator); + + +/* Constructs a new parser using the memory management suite referred to + by memsuite. If memsuite is NULL, then use the standard library memory + suite. If namespaceSeparator is non-NULL it creates a parser with + namespace processing as described above. The character pointed at + will serve as the namespace separator. + + All further memory operations used for the created parser will come from + the given suite. +*/ +XMLPARSEAPI(XML_Parser) +XML_ParserCreate_MM(const XML_Char *encoding, + const XML_Memory_Handling_Suite *memsuite, + const XML_Char *namespaceSeparator); + +/* Prepare a parser object to be re-used. This is particularly + valuable when memory allocation overhead is disproportionatly high, + such as when a large number of small documnents need to be parsed. + All handlers are cleared from the parser, except for the + unknownEncodingHandler. The parser's external state is re-initialized + except for the values of ns and ns_triplets. + + Added in Expat 1.95.3. +*/ +XMLPARSEAPI(XML_Bool) +XML_ParserReset(XML_Parser parser, const XML_Char *encoding); + +/* atts is array of name/value pairs, terminated by 0; + names and values are 0 terminated. +*/ +typedef void (XMLCALL *XML_StartElementHandler) (void *userData, + const XML_Char *name, + const XML_Char **atts); + +typedef void (XMLCALL *XML_EndElementHandler) (void *userData, + const XML_Char *name); + + +/* s is not 0 terminated. */ +typedef void (XMLCALL *XML_CharacterDataHandler) (void *userData, + const XML_Char *s, + int len); + +/* target and data are 0 terminated */ +typedef void (XMLCALL *XML_ProcessingInstructionHandler) ( + void *userData, + const XML_Char *target, + const XML_Char *data); + +/* data is 0 terminated */ +typedef void (XMLCALL *XML_CommentHandler) (void *userData, + const XML_Char *data); + +typedef void (XMLCALL *XML_StartCdataSectionHandler) (void *userData); +typedef void (XMLCALL *XML_EndCdataSectionHandler) (void *userData); + +/* This is called for any characters in the XML document for which + there is no applicable handler. This includes both characters that + are part of markup which is of a kind that is not reported + (comments, markup declarations), or characters that are part of a + construct which could be reported but for which no handler has been + supplied. The characters are passed exactly as they were in the XML + document except that they will be encoded in UTF-8 or UTF-16. + Line boundaries are not normalized. Note that a byte order mark + character is not passed to the default handler. There are no + guarantees about how characters are divided between calls to the + default handler: for example, a comment might be split between + multiple calls. +*/ +typedef void (XMLCALL *XML_DefaultHandler) (void *userData, + const XML_Char *s, + int len); + +/* This is called for the start of the DOCTYPE declaration, before + any DTD or internal subset is parsed. +*/ +typedef void (XMLCALL *XML_StartDoctypeDeclHandler) ( + void *userData, + const XML_Char *doctypeName, + const XML_Char *sysid, + const XML_Char *pubid, + int has_internal_subset); + +/* This is called for the start of the DOCTYPE declaration when the + closing > is encountered, but after processing any external + subset. +*/ +typedef void (XMLCALL *XML_EndDoctypeDeclHandler)(void *userData); + +/* This is called for entity declarations. The is_parameter_entity + argument will be non-zero if the entity is a parameter entity, zero + otherwise. + + For internal entities (), value will + be non-NULL and systemId, publicID, and notationName will be NULL. + The value string is NOT nul-terminated; the length is provided in + the value_length argument. Since it is legal to have zero-length + values, do not use this argument to test for internal entities. + + For external entities, value will be NULL and systemId will be + non-NULL. The publicId argument will be NULL unless a public + identifier was provided. The notationName argument will have a + non-NULL value only for unparsed entity declarations. + + Note that is_parameter_entity can't be changed to XML_Bool, since + that would break binary compatibility. +*/ +typedef void (XMLCALL *XML_EntityDeclHandler) ( + void *userData, + const XML_Char *entityName, + int is_parameter_entity, + const XML_Char *value, + int value_length, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId, + const XML_Char *notationName); + +XMLPARSEAPI(void) +XML_SetEntityDeclHandler(XML_Parser parser, + XML_EntityDeclHandler handler); + +/* OBSOLETE -- OBSOLETE -- OBSOLETE + This handler has been superceded by the EntityDeclHandler above. + It is provided here for backward compatibility. + + This is called for a declaration of an unparsed (NDATA) entity. + The base argument is whatever was set by XML_SetBase. The + entityName, systemId and notationName arguments will never be + NULL. The other arguments may be. +*/ +typedef void (XMLCALL *XML_UnparsedEntityDeclHandler) ( + void *userData, + const XML_Char *entityName, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId, + const XML_Char *notationName); + +/* This is called for a declaration of notation. The base argument is + whatever was set by XML_SetBase. The notationName will never be + NULL. The other arguments can be. +*/ +typedef void (XMLCALL *XML_NotationDeclHandler) ( + void *userData, + const XML_Char *notationName, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId); + +/* When namespace processing is enabled, these are called once for + each namespace declaration. The call to the start and end element + handlers occur between the calls to the start and end namespace + declaration handlers. For an xmlns attribute, prefix will be + NULL. For an xmlns="" attribute, uri will be NULL. +*/ +typedef void (XMLCALL *XML_StartNamespaceDeclHandler) ( + void *userData, + const XML_Char *prefix, + const XML_Char *uri); + +typedef void (XMLCALL *XML_EndNamespaceDeclHandler) ( + void *userData, + const XML_Char *prefix); + +/* This is called if the document is not standalone, that is, it has an + external subset or a reference to a parameter entity, but does not + have standalone="yes". If this handler returns XML_STATUS_ERROR, + then processing will not continue, and the parser will return a + XML_ERROR_NOT_STANDALONE error. + If parameter entity parsing is enabled, then in addition to the + conditions above this handler will only be called if the referenced + entity was actually read. +*/ +typedef int (XMLCALL *XML_NotStandaloneHandler) (void *userData); + +/* This is called for a reference to an external parsed general + entity. The referenced entity is not automatically parsed. The + application can parse it immediately or later using + XML_ExternalEntityParserCreate. + + The parser argument is the parser parsing the entity containing the + reference; it can be passed as the parser argument to + XML_ExternalEntityParserCreate. The systemId argument is the + system identifier as specified in the entity declaration; it will + not be NULL. + + The base argument is the system identifier that should be used as + the base for resolving systemId if systemId was relative; this is + set by XML_SetBase; it may be NULL. + + The publicId argument is the public identifier as specified in the + entity declaration, or NULL if none was specified; the whitespace + in the public identifier will have been normalized as required by + the XML spec. + + The context argument specifies the parsing context in the format + expected by the context argument to XML_ExternalEntityParserCreate; + context is valid only until the handler returns, so if the + referenced entity is to be parsed later, it must be copied. + context is NULL only when the entity is a parameter entity. + + The handler should return XML_STATUS_ERROR if processing should not + continue because of a fatal error in the handling of the external + entity. In this case the calling parser will return an + XML_ERROR_EXTERNAL_ENTITY_HANDLING error. + + Note that unlike other handlers the first argument is the parser, + not userData. +*/ +typedef int (XMLCALL *XML_ExternalEntityRefHandler) ( + XML_Parser parser, + const XML_Char *context, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId); + +/* This is called in two situations: + 1) An entity reference is encountered for which no declaration + has been read *and* this is not an error. + 2) An internal entity reference is read, but not expanded, because + XML_SetDefaultHandler has been called. + Note: skipped parameter entities in declarations and skipped general + entities in attribute values cannot be reported, because + the event would be out of sync with the reporting of the + declarations or attribute values +*/ +typedef void (XMLCALL *XML_SkippedEntityHandler) ( + void *userData, + const XML_Char *entityName, + int is_parameter_entity); + +/* This structure is filled in by the XML_UnknownEncodingHandler to + provide information to the parser about encodings that are unknown + to the parser. + + The map[b] member gives information about byte sequences whose + first byte is b. + + If map[b] is c where c is >= 0, then b by itself encodes the + Unicode scalar value c. + + If map[b] is -1, then the byte sequence is malformed. + + If map[b] is -n, where n >= 2, then b is the first byte of an + n-byte sequence that encodes a single Unicode scalar value. + + The data member will be passed as the first argument to the convert + function. + + The convert function is used to convert multibyte sequences; s will + point to a n-byte sequence where map[(unsigned char)*s] == -n. The + convert function must return the Unicode scalar value represented + by this byte sequence or -1 if the byte sequence is malformed. + + The convert function may be NULL if the encoding is a single-byte + encoding, that is if map[b] >= -1 for all bytes b. + + When the parser is finished with the encoding, then if release is + not NULL, it will call release passing it the data member; once + release has been called, the convert function will not be called + again. + + Expat places certain restrictions on the encodings that are supported + using this mechanism. + + 1. Every ASCII character that can appear in a well-formed XML document, + other than the characters + + $@\^`{}~ + + must be represented by a single byte, and that byte must be the + same byte that represents that character in ASCII. + + 2. No character may require more than 4 bytes to encode. + + 3. All characters encoded must have Unicode scalar values <= + 0xFFFF, (i.e., characters that would be encoded by surrogates in + UTF-16 are not allowed). Note that this restriction doesn't + apply to the built-in support for UTF-8 and UTF-16. + + 4. No Unicode character may be encoded by more than one distinct + sequence of bytes. +*/ +typedef struct { + int map[256]; + void *data; + int (XMLCALL *convert)(void *data, const char *s); + void (XMLCALL *release)(void *data); +} XML_Encoding; + +/* This is called for an encoding that is unknown to the parser. + + The encodingHandlerData argument is that which was passed as the + second argument to XML_SetUnknownEncodingHandler. + + The name argument gives the name of the encoding as specified in + the encoding declaration. + + If the callback can provide information about the encoding, it must + fill in the XML_Encoding structure, and return XML_STATUS_OK. + Otherwise it must return XML_STATUS_ERROR. + + If info does not describe a suitable encoding, then the parser will + return an XML_UNKNOWN_ENCODING error. +*/ +typedef int (XMLCALL *XML_UnknownEncodingHandler) ( + void *encodingHandlerData, + const XML_Char *name, + XML_Encoding *info); + +XMLPARSEAPI(void) +XML_SetElementHandler(XML_Parser parser, + XML_StartElementHandler start, + XML_EndElementHandler end); + +XMLPARSEAPI(void) +XML_SetStartElementHandler(XML_Parser parser, + XML_StartElementHandler handler); + +XMLPARSEAPI(void) +XML_SetEndElementHandler(XML_Parser parser, + XML_EndElementHandler handler); + +XMLPARSEAPI(void) +XML_SetCharacterDataHandler(XML_Parser parser, + XML_CharacterDataHandler handler); + +XMLPARSEAPI(void) +XML_SetProcessingInstructionHandler(XML_Parser parser, + XML_ProcessingInstructionHandler handler); +XMLPARSEAPI(void) +XML_SetCommentHandler(XML_Parser parser, + XML_CommentHandler handler); + +XMLPARSEAPI(void) +XML_SetCdataSectionHandler(XML_Parser parser, + XML_StartCdataSectionHandler start, + XML_EndCdataSectionHandler end); + +XMLPARSEAPI(void) +XML_SetStartCdataSectionHandler(XML_Parser parser, + XML_StartCdataSectionHandler start); + +XMLPARSEAPI(void) +XML_SetEndCdataSectionHandler(XML_Parser parser, + XML_EndCdataSectionHandler end); + +/* This sets the default handler and also inhibits expansion of + internal entities. These entity references will be passed to the + default handler, or to the skipped entity handler, if one is set. +*/ +XMLPARSEAPI(void) +XML_SetDefaultHandler(XML_Parser parser, + XML_DefaultHandler handler); + +/* This sets the default handler but does not inhibit expansion of + internal entities. The entity reference will not be passed to the + default handler. +*/ +XMLPARSEAPI(void) +XML_SetDefaultHandlerExpand(XML_Parser parser, + XML_DefaultHandler handler); + +XMLPARSEAPI(void) +XML_SetDoctypeDeclHandler(XML_Parser parser, + XML_StartDoctypeDeclHandler start, + XML_EndDoctypeDeclHandler end); + +XMLPARSEAPI(void) +XML_SetStartDoctypeDeclHandler(XML_Parser parser, + XML_StartDoctypeDeclHandler start); + +XMLPARSEAPI(void) +XML_SetEndDoctypeDeclHandler(XML_Parser parser, + XML_EndDoctypeDeclHandler end); + +XMLPARSEAPI(void) +XML_SetUnparsedEntityDeclHandler(XML_Parser parser, + XML_UnparsedEntityDeclHandler handler); + +XMLPARSEAPI(void) +XML_SetNotationDeclHandler(XML_Parser parser, + XML_NotationDeclHandler handler); + +XMLPARSEAPI(void) +XML_SetNamespaceDeclHandler(XML_Parser parser, + XML_StartNamespaceDeclHandler start, + XML_EndNamespaceDeclHandler end); + +XMLPARSEAPI(void) +XML_SetStartNamespaceDeclHandler(XML_Parser parser, + XML_StartNamespaceDeclHandler start); + +XMLPARSEAPI(void) +XML_SetEndNamespaceDeclHandler(XML_Parser parser, + XML_EndNamespaceDeclHandler end); + +XMLPARSEAPI(void) +XML_SetNotStandaloneHandler(XML_Parser parser, + XML_NotStandaloneHandler handler); + +XMLPARSEAPI(void) +XML_SetExternalEntityRefHandler(XML_Parser parser, + XML_ExternalEntityRefHandler handler); + +/* If a non-NULL value for arg is specified here, then it will be + passed as the first argument to the external entity ref handler + instead of the parser object. +*/ +XMLPARSEAPI(void) +XML_SetExternalEntityRefHandlerArg(XML_Parser parser, + void *arg); + +XMLPARSEAPI(void) +XML_SetSkippedEntityHandler(XML_Parser parser, + XML_SkippedEntityHandler handler); + +XMLPARSEAPI(void) +XML_SetUnknownEncodingHandler(XML_Parser parser, + XML_UnknownEncodingHandler handler, + void *encodingHandlerData); + +/* This can be called within a handler for a start element, end + element, processing instruction or character data. It causes the + corresponding markup to be passed to the default handler. +*/ +XMLPARSEAPI(void) +XML_DefaultCurrent(XML_Parser parser); + +/* If do_nst is non-zero, and namespace processing is in effect, and + a name has a prefix (i.e. an explicit namespace qualifier) then + that name is returned as a triplet in a single string separated by + the separator character specified when the parser was created: URI + + sep + local_name + sep + prefix. + + If do_nst is zero, then namespace information is returned in the + default manner (URI + sep + local_name) whether or not the name + has a prefix. + + Note: Calling XML_SetReturnNSTriplet after XML_Parse or + XML_ParseBuffer has no effect. +*/ + +XMLPARSEAPI(void) +XML_SetReturnNSTriplet(XML_Parser parser, int do_nst); + +/* This value is passed as the userData argument to callbacks. */ +XMLPARSEAPI(void) +XML_SetUserData(XML_Parser parser, void *userData); + +/* Returns the last value set by XML_SetUserData or NULL. */ +#define XML_GetUserData(parser) (*(void **)(parser)) + +/* This is equivalent to supplying an encoding argument to + XML_ParserCreate. On success XML_SetEncoding returns non-zero, + zero otherwise. + Note: Calling XML_SetEncoding after XML_Parse or XML_ParseBuffer + has no effect and returns XML_STATUS_ERROR. +*/ +XMLPARSEAPI(enum XML_Status) +XML_SetEncoding(XML_Parser parser, const XML_Char *encoding); + +/* If this function is called, then the parser will be passed as the + first argument to callbacks instead of userData. The userData will + still be accessible using XML_GetUserData. +*/ +XMLPARSEAPI(void) +XML_UseParserAsHandlerArg(XML_Parser parser); + +/* If useDTD == XML_TRUE is passed to this function, then the parser + will assume that there is an external subset, even if none is + specified in the document. In such a case the parser will call the + externalEntityRefHandler with a value of NULL for the systemId + argument (the publicId and context arguments will be NULL as well). + Note: For the purpose of checking WFC: Entity Declared, passing + useDTD == XML_TRUE will make the parser behave as if the document + had a DTD with an external subset. + Note: If this function is called, then this must be done before + the first call to XML_Parse or XML_ParseBuffer, since it will + have no effect after that. Returns + XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING. + Note: If the document does not have a DOCTYPE declaration at all, + then startDoctypeDeclHandler and endDoctypeDeclHandler will not + be called, despite an external subset being parsed. + Note: If XML_DTD is not defined when Expat is compiled, returns + XML_ERROR_FEATURE_REQUIRES_XML_DTD. +*/ +XMLPARSEAPI(enum XML_Error) +XML_UseForeignDTD(XML_Parser parser, XML_Bool useDTD); + + +/* Sets the base to be used for resolving relative URIs in system + identifiers in declarations. Resolving relative identifiers is + left to the application: this value will be passed through as the + base argument to the XML_ExternalEntityRefHandler, + XML_NotationDeclHandler and XML_UnparsedEntityDeclHandler. The base + argument will be copied. Returns XML_STATUS_ERROR if out of memory, + XML_STATUS_OK otherwise. +*/ +XMLPARSEAPI(enum XML_Status) +XML_SetBase(XML_Parser parser, const XML_Char *base); + +XMLPARSEAPI(const XML_Char *) +XML_GetBase(XML_Parser parser); + +/* Returns the number of the attribute/value pairs passed in last call + to the XML_StartElementHandler that were specified in the start-tag + rather than defaulted. Each attribute/value pair counts as 2; thus + this correspondds to an index into the atts array passed to the + XML_StartElementHandler. +*/ +XMLPARSEAPI(int) +XML_GetSpecifiedAttributeCount(XML_Parser parser); + +/* Returns the index of the ID attribute passed in the last call to + XML_StartElementHandler, or -1 if there is no ID attribute. Each + attribute/value pair counts as 2; thus this correspondds to an + index into the atts array passed to the XML_StartElementHandler. +*/ +XMLPARSEAPI(int) +XML_GetIdAttributeIndex(XML_Parser parser); + +/* Parses some input. Returns XML_STATUS_ERROR if a fatal error is + detected. The last call to XML_Parse must have isFinal true; len + may be zero for this call (or any other). + + Though the return values for these functions has always been + described as a Boolean value, the implementation, at least for the + 1.95.x series, has always returned exactly one of the XML_Status + values. +*/ +XMLPARSEAPI(enum XML_Status) +XML_Parse(XML_Parser parser, const char *s, int len, int isFinal); + +XMLPARSEAPI(void *) +XML_GetBuffer(XML_Parser parser, int len); + +XMLPARSEAPI(enum XML_Status) +XML_ParseBuffer(XML_Parser parser, int len, int isFinal); + +/* Stops parsing, causing XML_Parse() or XML_ParseBuffer() to return. + Must be called from within a call-back handler, except when aborting + (resumable = 0) an already suspended parser. Some call-backs may + still follow because they would otherwise get lost. Examples: + - endElementHandler() for empty elements when stopped in + startElementHandler(), + - endNameSpaceDeclHandler() when stopped in endElementHandler(), + and possibly others. + + Can be called from most handlers, including DTD related call-backs, + except when parsing an external parameter entity and resumable != 0. + Returns XML_STATUS_OK when successful, XML_STATUS_ERROR otherwise. + Possible error codes: + - XML_ERROR_SUSPENDED: when suspending an already suspended parser. + - XML_ERROR_FINISHED: when the parser has already finished. + - XML_ERROR_SUSPEND_PE: when suspending while parsing an external PE. + + When resumable != 0 (true) then parsing is suspended, that is, + XML_Parse() and XML_ParseBuffer() return XML_STATUS_SUSPENDED. + Otherwise, parsing is aborted, that is, XML_Parse() and XML_ParseBuffer() + return XML_STATUS_ERROR with error code XML_ERROR_ABORTED. + + *Note*: + This will be applied to the current parser instance only, that is, if + there is a parent parser then it will continue parsing when the + externalEntityRefHandler() returns. It is up to the implementation of + the externalEntityRefHandler() to call XML_StopParser() on the parent + parser (recursively), if one wants to stop parsing altogether. + + When suspended, parsing can be resumed by calling XML_ResumeParser(). +*/ +XMLPARSEAPI(enum XML_Status) +XML_StopParser(XML_Parser parser, XML_Bool resumable); + +/* Resumes parsing after it has been suspended with XML_StopParser(). + Must not be called from within a handler call-back. Returns same + status codes as XML_Parse() or XML_ParseBuffer(). + Additional error code XML_ERROR_NOT_SUSPENDED possible. + + *Note*: + This must be called on the most deeply nested child parser instance + first, and on its parent parser only after the child parser has finished, + to be applied recursively until the document entity's parser is restarted. + That is, the parent parser will not resume by itself and it is up to the + application to call XML_ResumeParser() on it at the appropriate moment. +*/ +XMLPARSEAPI(enum XML_Status) +XML_ResumeParser(XML_Parser parser); + +enum XML_Parsing { + XML_INITIALIZED, + XML_PARSING, + XML_FINISHED, + XML_SUSPENDED +}; + +typedef struct { + enum XML_Parsing parsing; + XML_Bool finalBuffer; +} XML_ParsingStatus; + +/* Returns status of parser with respect to being initialized, parsing, + finished, or suspended and processing the final buffer. + XXX XML_Parse() and XML_ParseBuffer() should return XML_ParsingStatus, + XXX with XML_FINISHED_OK or XML_FINISHED_ERROR replacing XML_FINISHED +*/ +XMLPARSEAPI(void) +XML_GetParsingStatus(XML_Parser parser, XML_ParsingStatus *status); + +/* Creates an XML_Parser object that can parse an external general + entity; context is a '\0'-terminated string specifying the parse + context; encoding is a '\0'-terminated string giving the name of + the externally specified encoding, or NULL if there is no + externally specified encoding. The context string consists of a + sequence of tokens separated by formfeeds (\f); a token consisting + of a name specifies that the general entity of the name is open; a + token of the form prefix=uri specifies the namespace for a + particular prefix; a token of the form =uri specifies the default + namespace. This can be called at any point after the first call to + an ExternalEntityRefHandler so longer as the parser has not yet + been freed. The new parser is completely independent and may + safely be used in a separate thread. The handlers and userData are + initialized from the parser argument. Returns NULL if out of memory. + Otherwise returns a new XML_Parser object. +*/ +XMLPARSEAPI(XML_Parser) +XML_ExternalEntityParserCreate(XML_Parser parser, + const XML_Char *context, + const XML_Char *encoding); + +enum XML_ParamEntityParsing { + XML_PARAM_ENTITY_PARSING_NEVER, + XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE, + XML_PARAM_ENTITY_PARSING_ALWAYS +}; + +/* Controls parsing of parameter entities (including the external DTD + subset). If parsing of parameter entities is enabled, then + references to external parameter entities (including the external + DTD subset) will be passed to the handler set with + XML_SetExternalEntityRefHandler. The context passed will be 0. + + Unlike external general entities, external parameter entities can + only be parsed synchronously. If the external parameter entity is + to be parsed, it must be parsed during the call to the external + entity ref handler: the complete sequence of + XML_ExternalEntityParserCreate, XML_Parse/XML_ParseBuffer and + XML_ParserFree calls must be made during this call. After + XML_ExternalEntityParserCreate has been called to create the parser + for the external parameter entity (context must be 0 for this + call), it is illegal to make any calls on the old parser until + XML_ParserFree has been called on the newly created parser. + If the library has been compiled without support for parameter + entity parsing (ie without XML_DTD being defined), then + XML_SetParamEntityParsing will return 0 if parsing of parameter + entities is requested; otherwise it will return non-zero. + Note: If XML_SetParamEntityParsing is called after XML_Parse or + XML_ParseBuffer, then it has no effect and will always return 0. +*/ +XMLPARSEAPI(int) +XML_SetParamEntityParsing(XML_Parser parser, + enum XML_ParamEntityParsing parsing); + +/* If XML_Parse or XML_ParseBuffer have returned XML_STATUS_ERROR, then + XML_GetErrorCode returns information about the error. +*/ +XMLPARSEAPI(enum XML_Error) +XML_GetErrorCode(XML_Parser parser); + +/* These functions return information about the current parse + location. They may be called from any callback called to report + some parse event; in this case the location is the location of the + first of the sequence of characters that generated the event. When + called from callbacks generated by declarations in the document + prologue, the location identified isn't as neatly defined, but will + be within the relevant markup. When called outside of the callback + functions, the position indicated will be just past the last parse + event (regardless of whether there was an associated callback). + + They may also be called after returning from a call to XML_Parse + or XML_ParseBuffer. If the return value is XML_STATUS_ERROR then + the location is the location of the character at which the error + was detected; otherwise the location is the location of the last + parse event, as described above. +*/ +XMLPARSEAPI(XML_Size) XML_GetCurrentLineNumber(XML_Parser parser); +XMLPARSEAPI(XML_Size) XML_GetCurrentColumnNumber(XML_Parser parser); +XMLPARSEAPI(XML_Index) XML_GetCurrentByteIndex(XML_Parser parser); + +/* Return the number of bytes in the current event. + Returns 0 if the event is in an internal entity. +*/ +XMLPARSEAPI(int) +XML_GetCurrentByteCount(XML_Parser parser); + +/* If XML_CONTEXT_BYTES is defined, returns the input buffer, sets + the integer pointed to by offset to the offset within this buffer + of the current parse position, and sets the integer pointed to by size + to the size of this buffer (the number of input bytes). Otherwise + returns a NULL pointer. Also returns a NULL pointer if a parse isn't + active. + + NOTE: The character pointer returned should not be used outside + the handler that makes the call. +*/ +XMLPARSEAPI(const char *) +XML_GetInputContext(XML_Parser parser, + int *offset, + int *size); + +/* For backwards compatibility with previous versions. */ +#define XML_GetErrorLineNumber XML_GetCurrentLineNumber +#define XML_GetErrorColumnNumber XML_GetCurrentColumnNumber +#define XML_GetErrorByteIndex XML_GetCurrentByteIndex + +/* Frees the content model passed to the element declaration handler */ +XMLPARSEAPI(void) +XML_FreeContentModel(XML_Parser parser, XML_Content *model); + +/* Exposing the memory handling functions used in Expat */ +XMLPARSEAPI(void *) +XML_MemMalloc(XML_Parser parser, size_t size); + +XMLPARSEAPI(void *) +XML_MemRealloc(XML_Parser parser, void *ptr, size_t size); + +XMLPARSEAPI(void) +XML_MemFree(XML_Parser parser, void *ptr); + +/* Frees memory used by the parser. */ +XMLPARSEAPI(void) +XML_ParserFree(XML_Parser parser); + +/* Returns a string describing the error. */ +XMLPARSEAPI(const XML_LChar *) +XML_ErrorString(enum XML_Error code); + +/* Return a string containing the version number of this expat */ +XMLPARSEAPI(const XML_LChar *) +XML_ExpatVersion(void); + +typedef struct { + int major; + int minor; + int micro; +} XML_Expat_Version; + +/* Return an XML_Expat_Version structure containing numeric version + number information for this version of expat. +*/ +XMLPARSEAPI(XML_Expat_Version) +XML_ExpatVersionInfo(void); + +/* Added in Expat 1.95.5. */ +enum XML_FeatureEnum { + XML_FEATURE_END = 0, + XML_FEATURE_UNICODE, + XML_FEATURE_UNICODE_WCHAR_T, + XML_FEATURE_DTD, + XML_FEATURE_CONTEXT_BYTES, + XML_FEATURE_MIN_SIZE, + XML_FEATURE_SIZEOF_XML_CHAR, + XML_FEATURE_SIZEOF_XML_LCHAR, + XML_FEATURE_NS + /* Additional features must be added to the end of this enum. */ +}; + +typedef struct { + enum XML_FeatureEnum feature; + const XML_LChar *name; + long int value; +} XML_Feature; + +XMLPARSEAPI(const XML_Feature *) +XML_GetFeatureList(void); + + +/* Expat follows the GNU/Linux convention of odd number minor version for + beta/development releases and even number minor version for stable + releases. Micro is bumped with each release, and set to 0 with each + change to major or minor version. +*/ +#define XML_MAJOR_VERSION 2 +#define XML_MINOR_VERSION 0 +#define XML_MICRO_VERSION 0 + +#ifdef __cplusplus +} +#endif + +#endif /* not Expat_INCLUDED */ diff --git a/gdcm/Utilities/gdcmexpat/lib/expat_external.h b/gdcm/Utilities/gdcmexpat/lib/expat_external.h new file mode 100644 index 0000000..c400090 --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/lib/expat_external.h @@ -0,0 +1,122 @@ +/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +#ifndef Expat_External_INCLUDED +#define Expat_External_INCLUDED 1 + +/* External API definitions */ + +#if defined(_MSC_EXTENSIONS) && !defined(__BEOS__) && !defined(__CYGWIN__) +#define XML_USE_MSC_EXTENSIONS 1 +#endif + +/* Expat tries very hard to make the API boundary very specifically + defined. There are two macros defined to control this boundary; + each of these can be defined before including this header to + achieve some different behavior, but doing so it not recommended or + tested frequently. + + XMLCALL - The calling convention to use for all calls across the + "library boundary." This will default to cdecl, and + try really hard to tell the compiler that's what we + want. + + XMLIMPORT - Whatever magic is needed to note that a function is + to be imported from a dynamically loaded library + (.dll, .so, or .sl, depending on your platform). + + The XMLCALL macro was added in Expat 1.95.7. The only one which is + expected to be directly useful in client code is XMLCALL. + + Note that on at least some Unix versions, the Expat library must be + compiled with the cdecl calling convention as the default since + system headers may assume the cdecl convention. +*/ +#ifndef XMLCALL +#if defined(XML_USE_MSC_EXTENSIONS) +#define XMLCALL __cdecl +#elif defined(__GNUC__) && defined(__i386) +#define XMLCALL __attribute__((cdecl)) +#else +/* For any platform which uses this definition and supports more than + one calling convention, we need to extend this definition to + declare the convention used on that platform, if it's possible to + do so. + + If this is the case for your platform, please file a bug report + with information on how to identify your platform via the C + pre-processor and how to specify the same calling convention as the + platform's malloc() implementation. +*/ +#define XMLCALL +#endif +#endif /* not defined XMLCALL */ + + +#if !defined(XML_STATIC) && !defined(XMLIMPORT) +/* using Expat from an application */ + +#ifdef XML_USE_MSC_EXTENSIONS +#ifdef gdcmexpat_EXPORTS +#define XMLIMPORT __declspec(dllexport) +#else +#ifndef XML_BUILDING_EXPAT +#define XMLIMPORT __declspec(dllimport) +#endif +#endif +#else +#if __GNUC__ >= 4 +#define XMLIMPORT __attribute__ ((visibility ("default"))) +#endif +#endif +#endif /* not defined XML_STATIC */ + + +/* If we didn't define it above, define it away: */ +#ifndef XMLIMPORT +#define XMLIMPORT +#endif + + +#define XMLPARSEAPI(type) XMLIMPORT type XMLCALL + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef XML_UNICODE_WCHAR_T +#define XML_UNICODE +#endif + +#ifdef XML_UNICODE /* Information is UTF-16 encoded. */ +#ifdef XML_UNICODE_WCHAR_T +typedef wchar_t XML_Char; +typedef wchar_t XML_LChar; +#else +typedef unsigned short XML_Char; +typedef char XML_LChar; +#endif /* XML_UNICODE_WCHAR_T */ +#else /* Information is UTF-8 encoded. */ +typedef char XML_Char; +typedef char XML_LChar; +#endif /* XML_UNICODE */ + +#ifdef XML_LARGE_SIZE /* Use large integers for file/stream positions. */ +#if defined(XML_USE_MSC_EXTENSIONS) && _MSC_VER < 1400 +typedef __int64 XML_Index; +typedef unsigned __int64 XML_Size; +#else +typedef long long XML_Index; +typedef unsigned long long XML_Size; +#endif +#else +typedef long XML_Index; +typedef unsigned long XML_Size; +#endif /* XML_LARGE_SIZE */ + +#ifdef __cplusplus +} +#endif + +#endif /* not Expat_External_INCLUDED */ diff --git a/gdcm/Utilities/gdcmexpat/lib/iasciitab.h b/gdcm/Utilities/gdcmexpat/lib/iasciitab.h new file mode 100644 index 0000000..24a1d5c --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/lib/iasciitab.h @@ -0,0 +1,37 @@ +/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +/* Like asciitab.h, except that 0xD has code BT_S rather than BT_CR */ +/* 0x00 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x04 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x08 */ BT_NONXML, BT_S, BT_LF, BT_NONXML, +/* 0x0C */ BT_NONXML, BT_S, BT_NONXML, BT_NONXML, +/* 0x10 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x14 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x18 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x1C */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x20 */ BT_S, BT_EXCL, BT_QUOT, BT_NUM, +/* 0x24 */ BT_OTHER, BT_PERCNT, BT_AMP, BT_APOS, +/* 0x28 */ BT_LPAR, BT_RPAR, BT_AST, BT_PLUS, +/* 0x2C */ BT_COMMA, BT_MINUS, BT_NAME, BT_SOL, +/* 0x30 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT, +/* 0x34 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT, +/* 0x38 */ BT_DIGIT, BT_DIGIT, BT_COLON, BT_SEMI, +/* 0x3C */ BT_LT, BT_EQUALS, BT_GT, BT_QUEST, +/* 0x40 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX, +/* 0x44 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT, +/* 0x48 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x4C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x50 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x54 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x58 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_LSQB, +/* 0x5C */ BT_OTHER, BT_RSQB, BT_OTHER, BT_NMSTRT, +/* 0x60 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX, +/* 0x64 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT, +/* 0x68 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x6C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x70 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x74 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x78 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER, +/* 0x7C */ BT_VERBAR, BT_OTHER, BT_OTHER, BT_OTHER, diff --git a/gdcm/Utilities/gdcmexpat/lib/internal.h b/gdcm/Utilities/gdcmexpat/lib/internal.h new file mode 100644 index 0000000..ff056c6 --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/lib/internal.h @@ -0,0 +1,73 @@ +/* internal.h + + Internal definitions used by Expat. This is not needed to compile + client code. + + The following calling convention macros are defined for frequently + called functions: + + FASTCALL - Used for those internal functions that have a simple + body and a low number of arguments and local variables. + + PTRCALL - Used for functions called though function pointers. + + PTRFASTCALL - Like PTRCALL, but for low number of arguments. + + inline - Used for selected internal functions for which inlining + may improve performance on some platforms. + + Note: Use of these macros is based on judgement, not hard rules, + and therefore subject to change. +*/ + +#if defined(__GNUC__) && defined(__i386__) +/* We'll use this version by default only where we know it helps. + + regparm() generates warnings on Solaris boxes. See SF bug #692878. + + Instability reported with egcs on a RedHat Linux 7.3. + Let's comment out: + #define FASTCALL __attribute__((stdcall, regparm(3))) + and let's try this: +*/ +#define FASTCALL __attribute__((regparm(3))) +#define PTRFASTCALL __attribute__((regparm(3))) +#endif + +/* Using __fastcall seems to have an unexpected negative effect under + MS VC++, especially for function pointers, so we won't use it for + now on that platform. It may be reconsidered for a future release + if it can be made more effective. + Likely reason: __fastcall on Windows is like stdcall, therefore + the compiler cannot perform stack optimizations for call clusters. +*/ + +/* Make sure all of these are defined if they aren't already. */ + +#ifndef FASTCALL +#define FASTCALL +#endif + +#ifndef PTRCALL +#define PTRCALL +#endif + +#ifndef PTRFASTCALL +#define PTRFASTCALL +#endif + +#ifndef XML_MIN_SIZE +#if !defined(__cplusplus) && !defined(inline) +#ifdef __GNUC__ +#define inline __inline +#endif /* __GNUC__ */ +#endif +#endif /* XML_MIN_SIZE */ + +#ifdef __cplusplus +#define inline inline +#else +#ifndef inline +#define inline +#endif +#endif diff --git a/gdcm/Utilities/gdcmexpat/lib/latin1tab.h b/gdcm/Utilities/gdcmexpat/lib/latin1tab.h new file mode 100644 index 0000000..53c25d7 --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/lib/latin1tab.h @@ -0,0 +1,36 @@ +/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +/* 0x80 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0x84 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0x88 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0x8C */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0x90 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0x94 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0x98 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0x9C */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0xA0 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0xA4 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0xA8 */ BT_OTHER, BT_OTHER, BT_NMSTRT, BT_OTHER, +/* 0xAC */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0xB0 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0xB4 */ BT_OTHER, BT_NMSTRT, BT_OTHER, BT_NAME, +/* 0xB8 */ BT_OTHER, BT_OTHER, BT_NMSTRT, BT_OTHER, +/* 0xBC */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0xC0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xC4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xC8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xCC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xD0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xD4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER, +/* 0xD8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xDC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xE0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xE4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xE8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xEC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xF0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xF4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER, +/* 0xF8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xFC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, diff --git a/gdcm/Utilities/gdcmexpat/lib/nametab.h b/gdcm/Utilities/gdcmexpat/lib/nametab.h new file mode 100644 index 0000000..b05e62c --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/lib/nametab.h @@ -0,0 +1,150 @@ +static const unsigned namingBitmap[] = { +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, +0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, +0x00000000, 0x04000000, 0x87FFFFFE, 0x07FFFFFE, +0x00000000, 0x00000000, 0xFF7FFFFF, 0xFF7FFFFF, +0xFFFFFFFF, 0x7FF3FFFF, 0xFFFFFDFE, 0x7FFFFFFF, +0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFE00F, 0xFC31FFFF, +0x00FFFFFF, 0x00000000, 0xFFFF0000, 0xFFFFFFFF, +0xFFFFFFFF, 0xF80001FF, 0x00000003, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0xFFFFD740, 0xFFFFFFFB, 0x547F7FFF, 0x000FFFFD, +0xFFFFDFFE, 0xFFFFFFFF, 0xDFFEFFFF, 0xFFFFFFFF, +0xFFFF0003, 0xFFFFFFFF, 0xFFFF199F, 0x033FCFFF, +0x00000000, 0xFFFE0000, 0x027FFFFF, 0xFFFFFFFE, +0x0000007F, 0x00000000, 0xFFFF0000, 0x000707FF, +0x00000000, 0x07FFFFFE, 0x000007FE, 0xFFFE0000, +0xFFFFFFFF, 0x7CFFFFFF, 0x002F7FFF, 0x00000060, +0xFFFFFFE0, 0x23FFFFFF, 0xFF000000, 0x00000003, +0xFFF99FE0, 0x03C5FDFF, 0xB0000000, 0x00030003, +0xFFF987E0, 0x036DFDFF, 0x5E000000, 0x001C0000, +0xFFFBAFE0, 0x23EDFDFF, 0x00000000, 0x00000001, +0xFFF99FE0, 0x23CDFDFF, 0xB0000000, 0x00000003, +0xD63DC7E0, 0x03BFC718, 0x00000000, 0x00000000, +0xFFFDDFE0, 0x03EFFDFF, 0x00000000, 0x00000003, +0xFFFDDFE0, 0x03EFFDFF, 0x40000000, 0x00000003, +0xFFFDDFE0, 0x03FFFDFF, 0x00000000, 0x00000003, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0xFFFFFFFE, 0x000D7FFF, 0x0000003F, 0x00000000, +0xFEF02596, 0x200D6CAE, 0x0000001F, 0x00000000, +0x00000000, 0x00000000, 0xFFFFFEFF, 0x000003FF, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0xFFFFFFFF, 0xFFFF003F, 0x007FFFFF, +0x0007DAED, 0x50000000, 0x82315001, 0x002C62AB, +0x40000000, 0xF580C900, 0x00000007, 0x02010800, +0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, +0x0FFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x03FFFFFF, +0x3F3FFFFF, 0xFFFFFFFF, 0xAAFF3F3F, 0x3FFFFFFF, +0xFFFFFFFF, 0x5FDFFFFF, 0x0FCF1FDC, 0x1FDC1FFF, +0x00000000, 0x00004C40, 0x00000000, 0x00000000, +0x00000007, 0x00000000, 0x00000000, 0x00000000, +0x00000080, 0x000003FE, 0xFFFFFFFE, 0xFFFFFFFF, +0x001FFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0x07FFFFFF, +0xFFFFFFE0, 0x00001FFF, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, +0xFFFFFFFF, 0x0000003F, 0x00000000, 0x00000000, +0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, +0xFFFFFFFF, 0x0000000F, 0x00000000, 0x00000000, +0x00000000, 0x07FF6000, 0x87FFFFFE, 0x07FFFFFE, +0x00000000, 0x00800000, 0xFF7FFFFF, 0xFF7FFFFF, +0x00FFFFFF, 0x00000000, 0xFFFF0000, 0xFFFFFFFF, +0xFFFFFFFF, 0xF80001FF, 0x00030003, 0x00000000, +0xFFFFFFFF, 0xFFFFFFFF, 0x0000003F, 0x00000003, +0xFFFFD7C0, 0xFFFFFFFB, 0x547F7FFF, 0x000FFFFD, +0xFFFFDFFE, 0xFFFFFFFF, 0xDFFEFFFF, 0xFFFFFFFF, +0xFFFF007B, 0xFFFFFFFF, 0xFFFF199F, 0x033FCFFF, +0x00000000, 0xFFFE0000, 0x027FFFFF, 0xFFFFFFFE, +0xFFFE007F, 0xBBFFFFFB, 0xFFFF0016, 0x000707FF, +0x00000000, 0x07FFFFFE, 0x0007FFFF, 0xFFFF03FF, +0xFFFFFFFF, 0x7CFFFFFF, 0xFFEF7FFF, 0x03FF3DFF, +0xFFFFFFEE, 0xF3FFFFFF, 0xFF1E3FFF, 0x0000FFCF, +0xFFF99FEE, 0xD3C5FDFF, 0xB080399F, 0x0003FFCF, +0xFFF987E4, 0xD36DFDFF, 0x5E003987, 0x001FFFC0, +0xFFFBAFEE, 0xF3EDFDFF, 0x00003BBF, 0x0000FFC1, +0xFFF99FEE, 0xF3CDFDFF, 0xB0C0398F, 0x0000FFC3, +0xD63DC7EC, 0xC3BFC718, 0x00803DC7, 0x0000FF80, +0xFFFDDFEE, 0xC3EFFDFF, 0x00603DDF, 0x0000FFC3, +0xFFFDDFEC, 0xC3EFFDFF, 0x40603DDF, 0x0000FFC3, +0xFFFDDFEC, 0xC3FFFDFF, 0x00803DCF, 0x0000FFC3, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0xFFFFFFFE, 0x07FF7FFF, 0x03FF7FFF, 0x00000000, +0xFEF02596, 0x3BFF6CAE, 0x03FF3F5F, 0x00000000, +0x03000000, 0xC2A003FF, 0xFFFFFEFF, 0xFFFE03FF, +0xFEBF0FDF, 0x02FE3FFF, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x1FFF0000, 0x00000002, +0x000000A0, 0x003EFFFE, 0xFFFFFFFE, 0xFFFFFFFF, +0x661FFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0x77FFFFFF, +}; +static const unsigned char nmstrtPages[] = { +0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00, +0x00, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, +0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x13, +0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x15, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x17, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x18, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; +static const unsigned char namePages[] = { +0x19, 0x03, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x00, +0x00, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, +0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x13, +0x26, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x27, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x17, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x18, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; diff --git a/gdcm/Utilities/gdcmexpat/lib/utf8tab.h b/gdcm/Utilities/gdcmexpat/lib/utf8tab.h new file mode 100644 index 0000000..7bb3e77 --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/lib/utf8tab.h @@ -0,0 +1,37 @@ +/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + + +/* 0x80 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0x84 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0x88 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0x8C */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0x90 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0x94 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0x98 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0x9C */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xA0 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xA4 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xA8 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xAC */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xB0 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xB4 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xB8 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xBC */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xC0 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, +/* 0xC4 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, +/* 0xC8 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, +/* 0xCC */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, +/* 0xD0 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, +/* 0xD4 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, +/* 0xD8 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, +/* 0xDC */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, +/* 0xE0 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3, +/* 0xE4 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3, +/* 0xE8 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3, +/* 0xEC */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3, +/* 0xF0 */ BT_LEAD4, BT_LEAD4, BT_LEAD4, BT_LEAD4, +/* 0xF4 */ BT_LEAD4, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0xF8 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0xFC */ BT_NONXML, BT_NONXML, BT_MALFORM, BT_MALFORM, diff --git a/gdcm/Utilities/gdcmexpat/lib/xmlparse.c b/gdcm/Utilities/gdcmexpat/lib/xmlparse.c new file mode 100644 index 0000000..a569f2d --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/lib/xmlparse.c @@ -0,0 +1,6257 @@ +/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +#include +#include /* memset(), memcpy() */ +#include + +#define XML_BUILDING_EXPAT 1 + +#include "expat_config.h" + +#include "expat.h" + +#ifdef XML_UNICODE +#define XML_ENCODE_MAX XML_UTF16_ENCODE_MAX +#define XmlConvert XmlUtf16Convert +#define XmlGetInternalEncoding XmlGetUtf16InternalEncoding +#define XmlGetInternalEncodingNS XmlGetUtf16InternalEncodingNS +#define XmlEncode XmlUtf16Encode +#define MUST_CONVERT(enc, s) (!(enc)->isUtf16 || (((unsigned long)s) & 1)) +typedef unsigned short ICHAR; +#else +#define XML_ENCODE_MAX XML_UTF8_ENCODE_MAX +#define XmlConvert XmlUtf8Convert +#define XmlGetInternalEncoding XmlGetUtf8InternalEncoding +#define XmlGetInternalEncodingNS XmlGetUtf8InternalEncodingNS +#define XmlEncode XmlUtf8Encode +#define MUST_CONVERT(enc, s) (!(enc)->isUtf8) +typedef char ICHAR; +#endif + + +#ifndef XML_NS + +#define XmlInitEncodingNS XmlInitEncoding +#define XmlInitUnknownEncodingNS XmlInitUnknownEncoding +#undef XmlGetInternalEncodingNS +#define XmlGetInternalEncodingNS XmlGetInternalEncoding +#define XmlParseXmlDeclNS XmlParseXmlDecl + +#endif + +#ifdef XML_UNICODE + +#ifdef XML_UNICODE_WCHAR_T +#define XML_T(x) (const wchar_t)x +#define XML_L(x) L ## x +#else +#define XML_T(x) (const unsigned short)x +#define XML_L(x) x +#endif + +#else + +#define XML_T(x) x +#define XML_L(x) x + +#endif + +/* Round up n to be a multiple of sz, where sz is a power of 2. */ +#define ROUND_UP(n, sz) (((n) + ((sz) - 1)) & ~((sz) - 1)) + +/* Handle the case where memmove() doesn't exist. */ +#ifndef HAVE_MEMMOVE +#ifdef HAVE_BCOPY +#define memmove(d,s,l) bcopy((s),(d),(l)) +#else +#error memmove does not exist on this platform, nor is a substitute available +#endif /* HAVE_BCOPY */ +#endif /* HAVE_MEMMOVE */ + +#include "internal.h" +#include "xmltok.h" +#include "xmlrole.h" + +typedef const XML_Char *KEY; + +typedef struct { + KEY name; +} NAMED; + +typedef struct { + NAMED **v; + unsigned char power; + size_t size; + size_t used; + const XML_Memory_Handling_Suite *mem; +} HASH_TABLE; + +/* Basic character hash algorithm, taken from Python's string hash: + h = h * 1000003 ^ character, the constant being a prime number. + +*/ +#ifdef XML_UNICODE +#define CHAR_HASH(h, c) \ + (((h) * 0xF4243) ^ (unsigned short)(c)) +#else +#define CHAR_HASH(h, c) \ + (((h) * 0xF4243) ^ (unsigned char)(c)) +#endif + +/* For probing (after a collision) we need a step size relative prime + to the hash table size, which is a power of 2. We use double-hashing, + since we can calculate a second hash value cheaply by taking those bits + of the first hash value that were discarded (masked out) when the table + index was calculated: index = hash & mask, where mask = table->size - 1. + We limit the maximum step size to table->size / 4 (mask >> 2) and make + it odd, since odd numbers are always relative prime to a power of 2. +*/ +#define SECOND_HASH(hash, mask, power) \ + ((((hash) & ~(mask)) >> ((power) - 1)) & ((mask) >> 2)) +#define PROBE_STEP(hash, mask, power) \ + ((unsigned char)((SECOND_HASH(hash, mask, power)) | 1)) + +typedef struct { + NAMED **p; + NAMED **end; +} HASH_TABLE_ITER; + +#define INIT_TAG_BUF_SIZE 32 /* must be a multiple of sizeof(XML_Char) */ +#define INIT_DATA_BUF_SIZE 1024 +#define INIT_ATTS_SIZE 16 +#define INIT_ATTS_VERSION 0xFFFFFFFF +#define INIT_BLOCK_SIZE 1024 +#define INIT_BUFFER_SIZE 1024 + +#define EXPAND_SPARE 24 + +typedef struct binding { + struct prefix *prefix; + struct binding *nextTagBinding; + struct binding *prevPrefixBinding; + const struct attribute_id *attId; + XML_Char *uri; + int uriLen; + int uriAlloc; +} BINDING; + +typedef struct prefix { + const XML_Char *name; + BINDING *binding; +} PREFIX; + +typedef struct { + const XML_Char *str; + const XML_Char *localPart; + const XML_Char *prefix; + int strLen; + int uriLen; + int prefixLen; +} TAG_NAME; + +/* TAG represents an open element. + The name of the element is stored in both the document and API + encodings. The memory buffer 'buf' is a separately-allocated + memory area which stores the name. During the XML_Parse()/ + XMLParseBuffer() when the element is open, the memory for the 'raw' + version of the name (in the document encoding) is shared with the + document buffer. If the element is open across calls to + XML_Parse()/XML_ParseBuffer(), the buffer is re-allocated to + contain the 'raw' name as well. + + A parser re-uses these structures, maintaining a list of allocated + TAG objects in a free list. +*/ +typedef struct tag { + struct tag *parent; /* parent of this element */ + const char *rawName; /* tagName in the original encoding */ + int rawNameLength; + TAG_NAME name; /* tagName in the API encoding */ + char *buf; /* buffer for name components */ + char *bufEnd; /* end of the buffer */ + BINDING *bindings; +} TAG; + +typedef struct { + const XML_Char *name; + const XML_Char *textPtr; + int textLen; /* length in XML_Chars */ + int processed; /* # of processed bytes - when suspended */ + const XML_Char *systemId; + const XML_Char *base; + const XML_Char *publicId; + const XML_Char *notation; + XML_Bool open; + XML_Bool is_param; + XML_Bool is_internal; /* true if declared in internal subset outside PE */ +} ENTITY; + +typedef struct { + enum XML_Content_Type type; + enum XML_Content_Quant quant; + const XML_Char * name; + int firstchild; + int lastchild; + int childcnt; + int nextsib; +} CONTENT_SCAFFOLD; + +#define INIT_SCAFFOLD_ELEMENTS 32 + +typedef struct block { + struct block *next; + int size; + XML_Char s[1]; +} BLOCK; + +typedef struct { + BLOCK *blocks; + BLOCK *freeBlocks; + const XML_Char *end; + XML_Char *ptr; + XML_Char *start; + const XML_Memory_Handling_Suite *mem; +} STRING_POOL; + +/* The XML_Char before the name is used to determine whether + an attribute has been specified. */ +typedef struct attribute_id { + XML_Char *name; + PREFIX *prefix; + XML_Bool maybeTokenized; + XML_Bool xmlns; +} ATTRIBUTE_ID; + +typedef struct { + const ATTRIBUTE_ID *id; + XML_Bool isCdata; + const XML_Char *value; +} DEFAULT_ATTRIBUTE; + +typedef struct { + unsigned long version; + unsigned long hash; + const XML_Char *uriName; +} NS_ATT; + +typedef struct { + const XML_Char *name; + PREFIX *prefix; + const ATTRIBUTE_ID *idAtt; + int nDefaultAtts; + int allocDefaultAtts; + DEFAULT_ATTRIBUTE *defaultAtts; +} ELEMENT_TYPE; + +typedef struct { + HASH_TABLE generalEntities; + HASH_TABLE elementTypes; + HASH_TABLE attributeIds; + HASH_TABLE prefixes; + STRING_POOL pool; + STRING_POOL entityValuePool; + /* false once a parameter entity reference has been skipped */ + XML_Bool keepProcessing; + /* true once an internal or external PE reference has been encountered; + this includes the reference to an external subset */ + XML_Bool hasParamEntityRefs; + XML_Bool standalone; +#ifdef XML_DTD + /* indicates if external PE has been read */ + XML_Bool paramEntityRead; + HASH_TABLE paramEntities; +#endif /* XML_DTD */ + PREFIX defaultPrefix; + /* === scaffolding for building content model === */ + XML_Bool in_eldecl; + CONTENT_SCAFFOLD *scaffold; + unsigned contentStringLen; + unsigned scaffSize; + unsigned scaffCount; + int scaffLevel; + int *scaffIndex; +} DTD; + +typedef struct open_internal_entity { + const char *internalEventPtr; + const char *internalEventEndPtr; + struct open_internal_entity *next; + ENTITY *entity; + int startTagLevel; + XML_Bool betweenDecl; /* WFC: PE Between Declarations */ +} OPEN_INTERNAL_ENTITY; + +typedef enum XML_Error PTRCALL Processor(XML_Parser parser, + const char *start, + const char *end, + const char **endPtr); + +static Processor prologProcessor; +static Processor prologInitProcessor; +static Processor contentProcessor; +static Processor cdataSectionProcessor; +#ifdef XML_DTD +static Processor ignoreSectionProcessor; +static Processor externalParEntProcessor; +static Processor externalParEntInitProcessor; +static Processor entityValueProcessor; +static Processor entityValueInitProcessor; +#endif /* XML_DTD */ +static Processor epilogProcessor; +static Processor errorProcessor; +static Processor externalEntityInitProcessor; +static Processor externalEntityInitProcessor2; +static Processor externalEntityInitProcessor3; +static Processor externalEntityContentProcessor; +static Processor internalEntityProcessor; + +static enum XML_Error +handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName); +static enum XML_Error +processXmlDecl(XML_Parser parser, int isGeneralTextEntity, + const char *s, const char *next); +static enum XML_Error +initializeEncoding(XML_Parser parser); +static enum XML_Error +doProlog(XML_Parser parser, const ENCODING *enc, const char *s, + const char *end, int tok, const char *next, const char **nextPtr, + XML_Bool haveMore); +static enum XML_Error +processInternalEntity(XML_Parser parser, ENTITY *entity, + XML_Bool betweenDecl); +static enum XML_Error +doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, + const char *start, const char *end, const char **endPtr, + XML_Bool haveMore); +static enum XML_Error +doCdataSection(XML_Parser parser, const ENCODING *, const char **startPtr, + const char *end, const char **nextPtr, XML_Bool haveMore); +#ifdef XML_DTD +static enum XML_Error +doIgnoreSection(XML_Parser parser, const ENCODING *, const char **startPtr, + const char *end, const char **nextPtr, XML_Bool haveMore); +#endif /* XML_DTD */ + +static enum XML_Error +storeAtts(XML_Parser parser, const ENCODING *, const char *s, + TAG_NAME *tagNamePtr, BINDING **bindingsPtr); +static enum XML_Error +addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId, + const XML_Char *uri, BINDING **bindingsPtr); +static int +defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *, XML_Bool isCdata, + XML_Bool isId, const XML_Char *dfltValue, XML_Parser parser); +static enum XML_Error +storeAttributeValue(XML_Parser parser, const ENCODING *, XML_Bool isCdata, + const char *, const char *, STRING_POOL *); +static enum XML_Error +appendAttributeValue(XML_Parser parser, const ENCODING *, XML_Bool isCdata, + const char *, const char *, STRING_POOL *); +static ATTRIBUTE_ID * +getAttributeId(XML_Parser parser, const ENCODING *enc, const char *start, + const char *end); +static int +setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *); +static enum XML_Error +storeEntityValue(XML_Parser parser, const ENCODING *enc, const char *start, + const char *end); +static int +reportProcessingInstruction(XML_Parser parser, const ENCODING *enc, + const char *start, const char *end); +static int +reportComment(XML_Parser parser, const ENCODING *enc, const char *start, + const char *end); +static void +reportDefault(XML_Parser parser, const ENCODING *enc, const char *start, + const char *end); + +static const XML_Char * getContext(XML_Parser parser); +static XML_Bool +setContext(XML_Parser parser, const XML_Char *context); + +static void FASTCALL normalizePublicId(XML_Char *s); + +static DTD * dtdCreate(const XML_Memory_Handling_Suite *ms); +/* do not call if parentParser != NULL */ +static void dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms); +static void +dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms); +static int +dtdCopy(DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms); +static int +copyEntityTable(HASH_TABLE *, STRING_POOL *, const HASH_TABLE *); + +static NAMED * +lookup(HASH_TABLE *table, KEY name, size_t createSize); +static void FASTCALL +hashTableInit(HASH_TABLE *, const XML_Memory_Handling_Suite *ms); +static void FASTCALL hashTableClear(HASH_TABLE *); +static void FASTCALL hashTableDestroy(HASH_TABLE *); +static void FASTCALL +hashTableIterInit(HASH_TABLE_ITER *, const HASH_TABLE *); +static NAMED * FASTCALL hashTableIterNext(HASH_TABLE_ITER *); + +static void FASTCALL +poolInit(STRING_POOL *, const XML_Memory_Handling_Suite *ms); +static void FASTCALL poolClear(STRING_POOL *); +static void FASTCALL poolDestroy(STRING_POOL *); +static XML_Char * +poolAppend(STRING_POOL *pool, const ENCODING *enc, + const char *ptr, const char *end); +static XML_Char * +poolStoreString(STRING_POOL *pool, const ENCODING *enc, + const char *ptr, const char *end); +static XML_Bool FASTCALL poolGrow(STRING_POOL *pool); +static const XML_Char * FASTCALL +poolCopyString(STRING_POOL *pool, const XML_Char *s); +static const XML_Char * +poolCopyStringN(STRING_POOL *pool, const XML_Char *s, int n); +static const XML_Char * FASTCALL +poolAppendString(STRING_POOL *pool, const XML_Char *s); + +static int FASTCALL nextScaffoldPart(XML_Parser parser); +static XML_Content * build_model(XML_Parser parser); +static ELEMENT_TYPE * +getElementType(XML_Parser parser, const ENCODING *enc, + const char *ptr, const char *end); + +static XML_Parser +parserCreate(const XML_Char *encodingName, + const XML_Memory_Handling_Suite *memsuite, + const XML_Char *nameSep, + DTD *dtd); +static void +parserInit(XML_Parser parser, const XML_Char *encodingName); + +#define poolStart(pool) ((pool)->start) +#define poolEnd(pool) ((pool)->ptr) +#define poolLength(pool) ((pool)->ptr - (pool)->start) +#define poolChop(pool) ((void)--(pool->ptr)) +#define poolLastChar(pool) (((pool)->ptr)[-1]) +#define poolDiscard(pool) ((pool)->ptr = (pool)->start) +#define poolFinish(pool) ((pool)->start = (pool)->ptr) +#define poolAppendChar(pool, c) \ + (((pool)->ptr == (pool)->end && !poolGrow(pool)) \ + ? 0 \ + : ((*((pool)->ptr)++ = c), 1)) + +struct XML_ParserStruct { + /* The first member must be userData so that the XML_GetUserData + macro works. */ + void *m_userData; + void *m_handlerArg; + char *m_buffer; + const XML_Memory_Handling_Suite m_mem; + /* first character to be parsed */ + const char *m_bufferPtr; + /* past last character to be parsed */ + char *m_bufferEnd; + /* allocated end of buffer */ + const char *m_bufferLim; + XML_Index m_parseEndByteIndex; + const char *m_parseEndPtr; + XML_Char *m_dataBuf; + XML_Char *m_dataBufEnd; + XML_StartElementHandler m_startElementHandler; + XML_EndElementHandler m_endElementHandler; + XML_CharacterDataHandler m_characterDataHandler; + XML_ProcessingInstructionHandler m_processingInstructionHandler; + XML_CommentHandler m_commentHandler; + XML_StartCdataSectionHandler m_startCdataSectionHandler; + XML_EndCdataSectionHandler m_endCdataSectionHandler; + XML_DefaultHandler m_defaultHandler; + XML_StartDoctypeDeclHandler m_startDoctypeDeclHandler; + XML_EndDoctypeDeclHandler m_endDoctypeDeclHandler; + XML_UnparsedEntityDeclHandler m_unparsedEntityDeclHandler; + XML_NotationDeclHandler m_notationDeclHandler; + XML_StartNamespaceDeclHandler m_startNamespaceDeclHandler; + XML_EndNamespaceDeclHandler m_endNamespaceDeclHandler; + XML_NotStandaloneHandler m_notStandaloneHandler; + XML_ExternalEntityRefHandler m_externalEntityRefHandler; + XML_Parser m_externalEntityRefHandlerArg; + XML_SkippedEntityHandler m_skippedEntityHandler; + XML_UnknownEncodingHandler m_unknownEncodingHandler; + XML_ElementDeclHandler m_elementDeclHandler; + XML_AttlistDeclHandler m_attlistDeclHandler; + XML_EntityDeclHandler m_entityDeclHandler; + XML_XmlDeclHandler m_xmlDeclHandler; + const ENCODING *m_encoding; + INIT_ENCODING m_initEncoding; + const ENCODING *m_internalEncoding; + const XML_Char *m_protocolEncodingName; + XML_Bool m_ns; + XML_Bool m_ns_triplets; + void *m_unknownEncodingMem; + void *m_unknownEncodingData; + void *m_unknownEncodingHandlerData; + void (XMLCALL *m_unknownEncodingRelease)(void *); + PROLOG_STATE m_prologState; + Processor *m_processor; + enum XML_Error m_errorCode; + const char *m_eventPtr; + const char *m_eventEndPtr; + const char *m_positionPtr; + OPEN_INTERNAL_ENTITY *m_openInternalEntities; + OPEN_INTERNAL_ENTITY *m_freeInternalEntities; + XML_Bool m_defaultExpandInternalEntities; + int m_tagLevel; + ENTITY *m_declEntity; + const XML_Char *m_doctypeName; + const XML_Char *m_doctypeSysid; + const XML_Char *m_doctypePubid; + const XML_Char *m_declAttributeType; + const XML_Char *m_declNotationName; + const XML_Char *m_declNotationPublicId; + ELEMENT_TYPE *m_declElementType; + ATTRIBUTE_ID *m_declAttributeId; + XML_Bool m_declAttributeIsCdata; + XML_Bool m_declAttributeIsId; + DTD *m_dtd; + const XML_Char *m_curBase; + TAG *m_tagStack; + TAG *m_freeTagList; + BINDING *m_inheritedBindings; + BINDING *m_freeBindingList; + int m_attsSize; + int m_nSpecifiedAtts; + int m_idAttIndex; + ATTRIBUTE *m_atts; + NS_ATT *m_nsAtts; + unsigned long m_nsAttsVersion; + unsigned char m_nsAttsPower; + POSITION m_position; + STRING_POOL m_tempPool; + STRING_POOL m_temp2Pool; + char *m_groupConnector; + unsigned int m_groupSize; + XML_Char m_namespaceSeparator; + XML_Parser m_parentParser; + XML_ParsingStatus m_parsingStatus; +#ifdef XML_DTD + XML_Bool m_isParamEntity; + XML_Bool m_useForeignDTD; + enum XML_ParamEntityParsing m_paramEntityParsing; +#endif +}; + +#define MALLOC(s) (parser->m_mem.malloc_fcn((s))) +#define REALLOC(p,s) (parser->m_mem.realloc_fcn((p),(s))) +#define FREE(p) (parser->m_mem.free_fcn((p))) + +#define userData (parser->m_userData) +#define handlerArg (parser->m_handlerArg) +#define startElementHandler (parser->m_startElementHandler) +#define endElementHandler (parser->m_endElementHandler) +#define characterDataHandler (parser->m_characterDataHandler) +#define processingInstructionHandler \ + (parser->m_processingInstructionHandler) +#define commentHandler (parser->m_commentHandler) +#define startCdataSectionHandler \ + (parser->m_startCdataSectionHandler) +#define endCdataSectionHandler (parser->m_endCdataSectionHandler) +#define defaultHandler (parser->m_defaultHandler) +#define startDoctypeDeclHandler (parser->m_startDoctypeDeclHandler) +#define endDoctypeDeclHandler (parser->m_endDoctypeDeclHandler) +#define unparsedEntityDeclHandler \ + (parser->m_unparsedEntityDeclHandler) +#define notationDeclHandler (parser->m_notationDeclHandler) +#define startNamespaceDeclHandler \ + (parser->m_startNamespaceDeclHandler) +#define endNamespaceDeclHandler (parser->m_endNamespaceDeclHandler) +#define notStandaloneHandler (parser->m_notStandaloneHandler) +#define externalEntityRefHandler \ + (parser->m_externalEntityRefHandler) +#define externalEntityRefHandlerArg \ + (parser->m_externalEntityRefHandlerArg) +#define internalEntityRefHandler \ + (parser->m_internalEntityRefHandler) +#define skippedEntityHandler (parser->m_skippedEntityHandler) +#define unknownEncodingHandler (parser->m_unknownEncodingHandler) +#define elementDeclHandler (parser->m_elementDeclHandler) +#define attlistDeclHandler (parser->m_attlistDeclHandler) +#define entityDeclHandler (parser->m_entityDeclHandler) +#define xmlDeclHandler (parser->m_xmlDeclHandler) +#define encoding (parser->m_encoding) +#define initEncoding (parser->m_initEncoding) +#define internalEncoding (parser->m_internalEncoding) +#define unknownEncodingMem (parser->m_unknownEncodingMem) +#define unknownEncodingData (parser->m_unknownEncodingData) +#define unknownEncodingHandlerData \ + (parser->m_unknownEncodingHandlerData) +#define unknownEncodingRelease (parser->m_unknownEncodingRelease) +#define protocolEncodingName (parser->m_protocolEncodingName) +#define ns (parser->m_ns) +#define ns_triplets (parser->m_ns_triplets) +#define prologState (parser->m_prologState) +#define processor (parser->m_processor) +#define errorCode (parser->m_errorCode) +#define eventPtr (parser->m_eventPtr) +#define eventEndPtr (parser->m_eventEndPtr) +#define positionPtr (parser->m_positionPtr) +#define position (parser->m_position) +#define openInternalEntities (parser->m_openInternalEntities) +#define freeInternalEntities (parser->m_freeInternalEntities) +#define defaultExpandInternalEntities \ + (parser->m_defaultExpandInternalEntities) +#define tagLevel (parser->m_tagLevel) +#define buffer (parser->m_buffer) +#define bufferPtr (parser->m_bufferPtr) +#define bufferEnd (parser->m_bufferEnd) +#define parseEndByteIndex (parser->m_parseEndByteIndex) +#define parseEndPtr (parser->m_parseEndPtr) +#define bufferLim (parser->m_bufferLim) +#define dataBuf (parser->m_dataBuf) +#define dataBufEnd (parser->m_dataBufEnd) +#define _dtd (parser->m_dtd) +#define curBase (parser->m_curBase) +#define declEntity (parser->m_declEntity) +#define doctypeName (parser->m_doctypeName) +#define doctypeSysid (parser->m_doctypeSysid) +#define doctypePubid (parser->m_doctypePubid) +#define declAttributeType (parser->m_declAttributeType) +#define declNotationName (parser->m_declNotationName) +#define declNotationPublicId (parser->m_declNotationPublicId) +#define declElementType (parser->m_declElementType) +#define declAttributeId (parser->m_declAttributeId) +#define declAttributeIsCdata (parser->m_declAttributeIsCdata) +#define declAttributeIsId (parser->m_declAttributeIsId) +#define freeTagList (parser->m_freeTagList) +#define freeBindingList (parser->m_freeBindingList) +#define inheritedBindings (parser->m_inheritedBindings) +#define tagStack (parser->m_tagStack) +#define atts (parser->m_atts) +#define attsSize (parser->m_attsSize) +#define nSpecifiedAtts (parser->m_nSpecifiedAtts) +#define idAttIndex (parser->m_idAttIndex) +#define nsAtts (parser->m_nsAtts) +#define nsAttsVersion (parser->m_nsAttsVersion) +#define nsAttsPower (parser->m_nsAttsPower) +#define tempPool (parser->m_tempPool) +#define temp2Pool (parser->m_temp2Pool) +#define groupConnector (parser->m_groupConnector) +#define groupSize (parser->m_groupSize) +#define namespaceSeparator (parser->m_namespaceSeparator) +#define parentParser (parser->m_parentParser) +#define ps_parsing (parser->m_parsingStatus.parsing) +#define ps_finalBuffer (parser->m_parsingStatus.finalBuffer) +#ifdef XML_DTD +#define isParamEntity (parser->m_isParamEntity) +#define useForeignDTD (parser->m_useForeignDTD) +#define paramEntityParsing (parser->m_paramEntityParsing) +#endif /* XML_DTD */ + +XML_Parser XMLCALL +XML_ParserCreate(const XML_Char *encodingName) +{ + return XML_ParserCreate_MM(encodingName, NULL, NULL); +} + +XML_Parser XMLCALL +XML_ParserCreateNS(const XML_Char *encodingName, XML_Char nsSep) +{ + XML_Char tmp[2]; + *tmp = nsSep; + return XML_ParserCreate_MM(encodingName, NULL, tmp); +} + +static const XML_Char implicitContext[] = { + 'x', 'm', 'l', '=', 'h', 't', 't', 'p', ':', '/', '/', + 'w', 'w', 'w', '.', 'w', '3', '.', 'o', 'r', 'g', '/', + 'X', 'M', 'L', '/', '1', '9', '9', '8', '/', + 'n', 'a', 'm', 'e', 's', 'p', 'a', 'c', 'e', '\0' +}; + +XML_Parser XMLCALL +XML_ParserCreate_MM(const XML_Char *encodingName, + const XML_Memory_Handling_Suite *memsuite, + const XML_Char *nameSep) +{ + XML_Parser parser = parserCreate(encodingName, memsuite, nameSep, NULL); + if (parser != NULL && ns) { + /* implicit context only set for root parser, since child + parsers (i.e. external entity parsers) will inherit it + */ + if (!setContext(parser, implicitContext)) { + XML_ParserFree(parser); + return NULL; + } + } + return parser; +} + +static XML_Parser +parserCreate(const XML_Char *encodingName, + const XML_Memory_Handling_Suite *memsuite, + const XML_Char *nameSep, + DTD *dtd) +{ + XML_Parser parser; + + if (memsuite) { + XML_Memory_Handling_Suite *mtemp; + parser = (XML_Parser) + memsuite->malloc_fcn(sizeof(struct XML_ParserStruct)); + if (parser != NULL) { + mtemp = (XML_Memory_Handling_Suite *)&(parser->m_mem); + mtemp->malloc_fcn = memsuite->malloc_fcn; + mtemp->realloc_fcn = memsuite->realloc_fcn; + mtemp->free_fcn = memsuite->free_fcn; + } + } + else { + XML_Memory_Handling_Suite *mtemp; + parser = (XML_Parser)malloc(sizeof(struct XML_ParserStruct)); + if (parser != NULL) { + mtemp = (XML_Memory_Handling_Suite *)&(parser->m_mem); + mtemp->malloc_fcn = malloc; + mtemp->realloc_fcn = realloc; + mtemp->free_fcn = free; + } + } + + if (!parser) + return parser; + + buffer = NULL; + bufferLim = NULL; + + attsSize = INIT_ATTS_SIZE; + atts = (ATTRIBUTE *)MALLOC(attsSize * sizeof(ATTRIBUTE)); + if (atts == NULL) { + FREE(parser); + return NULL; + } + dataBuf = (XML_Char *)MALLOC(INIT_DATA_BUF_SIZE * sizeof(XML_Char)); + if (dataBuf == NULL) { + FREE(atts); + FREE(parser); + return NULL; + } + dataBufEnd = dataBuf + INIT_DATA_BUF_SIZE; + + if (dtd) + _dtd = dtd; + else { + _dtd = dtdCreate(&parser->m_mem); + if (_dtd == NULL) { + FREE(dataBuf); + FREE(atts); + FREE(parser); + return NULL; + } + } + + freeBindingList = NULL; + freeTagList = NULL; + freeInternalEntities = NULL; + + groupSize = 0; + groupConnector = NULL; + + unknownEncodingHandler = NULL; + unknownEncodingHandlerData = NULL; + + namespaceSeparator = '!'; + ns = XML_FALSE; + ns_triplets = XML_FALSE; + + nsAtts = NULL; + nsAttsVersion = 0; + nsAttsPower = 0; + + poolInit(&tempPool, &(parser->m_mem)); + poolInit(&temp2Pool, &(parser->m_mem)); + parserInit(parser, encodingName); + + if (encodingName && !protocolEncodingName) { + XML_ParserFree(parser); + return NULL; + } + + if (nameSep) { + ns = XML_TRUE; + internalEncoding = XmlGetInternalEncodingNS(); + namespaceSeparator = *nameSep; + } + else { + internalEncoding = XmlGetInternalEncoding(); + } + + return parser; +} + +static void +parserInit(XML_Parser parser, const XML_Char *encodingName) +{ + processor = prologInitProcessor; + XmlPrologStateInit(&prologState); + protocolEncodingName = (encodingName != NULL + ? poolCopyString(&tempPool, encodingName) + : NULL); + curBase = NULL; + XmlInitEncoding(&initEncoding, &encoding, 0); + userData = NULL; + handlerArg = NULL; + startElementHandler = NULL; + endElementHandler = NULL; + characterDataHandler = NULL; + processingInstructionHandler = NULL; + commentHandler = NULL; + startCdataSectionHandler = NULL; + endCdataSectionHandler = NULL; + defaultHandler = NULL; + startDoctypeDeclHandler = NULL; + endDoctypeDeclHandler = NULL; + unparsedEntityDeclHandler = NULL; + notationDeclHandler = NULL; + startNamespaceDeclHandler = NULL; + endNamespaceDeclHandler = NULL; + notStandaloneHandler = NULL; + externalEntityRefHandler = NULL; + externalEntityRefHandlerArg = parser; + skippedEntityHandler = NULL; + elementDeclHandler = NULL; + attlistDeclHandler = NULL; + entityDeclHandler = NULL; + xmlDeclHandler = NULL; + bufferPtr = buffer; + bufferEnd = buffer; + parseEndByteIndex = 0; + parseEndPtr = NULL; + declElementType = NULL; + declAttributeId = NULL; + declEntity = NULL; + doctypeName = NULL; + doctypeSysid = NULL; + doctypePubid = NULL; + declAttributeType = NULL; + declNotationName = NULL; + declNotationPublicId = NULL; + declAttributeIsCdata = XML_FALSE; + declAttributeIsId = XML_FALSE; + memset(&position, 0, sizeof(POSITION)); + errorCode = XML_ERROR_NONE; + eventPtr = NULL; + eventEndPtr = NULL; + positionPtr = NULL; + openInternalEntities = NULL; + defaultExpandInternalEntities = XML_TRUE; + tagLevel = 0; + tagStack = NULL; + inheritedBindings = NULL; + nSpecifiedAtts = 0; + unknownEncodingMem = NULL; + unknownEncodingRelease = NULL; + unknownEncodingData = NULL; + parentParser = NULL; + ps_parsing = XML_INITIALIZED; +#ifdef XML_DTD + isParamEntity = XML_FALSE; + useForeignDTD = XML_FALSE; + paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER; +#endif +} + +/* moves list of bindings to freeBindingList */ +static void FASTCALL +moveToFreeBindingList(XML_Parser parser, BINDING *bindings) +{ + while (bindings) { + BINDING *b = bindings; + bindings = bindings->nextTagBinding; + b->nextTagBinding = freeBindingList; + freeBindingList = b; + } +} + +XML_Bool XMLCALL +XML_ParserReset(XML_Parser parser, const XML_Char *encodingName) +{ + TAG *tStk; + OPEN_INTERNAL_ENTITY *openEntityList; + if (parentParser) + return XML_FALSE; + /* move tagStack to freeTagList */ + tStk = tagStack; + while (tStk) { + TAG *tag = tStk; + tStk = tStk->parent; + tag->parent = freeTagList; + moveToFreeBindingList(parser, tag->bindings); + tag->bindings = NULL; + freeTagList = tag; + } + /* move openInternalEntities to freeInternalEntities */ + openEntityList = openInternalEntities; + while (openEntityList) { + OPEN_INTERNAL_ENTITY *openEntity = openEntityList; + openEntityList = openEntity->next; + openEntity->next = freeInternalEntities; + freeInternalEntities = openEntity; + } + moveToFreeBindingList(parser, inheritedBindings); + FREE(unknownEncodingMem); + if (unknownEncodingRelease) + unknownEncodingRelease(unknownEncodingData); + poolClear(&tempPool); + poolClear(&temp2Pool); + parserInit(parser, encodingName); + dtdReset(_dtd, &parser->m_mem); + return setContext(parser, implicitContext); +} + +enum XML_Status XMLCALL +XML_SetEncoding(XML_Parser parser, const XML_Char *encodingName) +{ + /* Block after XML_Parse()/XML_ParseBuffer() has been called. + XXX There's no way for the caller to determine which of the + XXX possible error cases caused the XML_STATUS_ERROR return. + */ + if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED) + return XML_STATUS_ERROR; + if (encodingName == NULL) + protocolEncodingName = NULL; + else { + protocolEncodingName = poolCopyString(&tempPool, encodingName); + if (!protocolEncodingName) + return XML_STATUS_ERROR; + } + return XML_STATUS_OK; +} + +XML_Parser XMLCALL +XML_ExternalEntityParserCreate(XML_Parser oldParser, + const XML_Char *context, + const XML_Char *encodingName) +{ + XML_Parser parser = oldParser; + DTD *newDtd = NULL; + DTD *oldDtd = _dtd; + XML_StartElementHandler oldStartElementHandler = startElementHandler; + XML_EndElementHandler oldEndElementHandler = endElementHandler; + XML_CharacterDataHandler oldCharacterDataHandler = characterDataHandler; + XML_ProcessingInstructionHandler oldProcessingInstructionHandler + = processingInstructionHandler; + XML_CommentHandler oldCommentHandler = commentHandler; + XML_StartCdataSectionHandler oldStartCdataSectionHandler + = startCdataSectionHandler; + XML_EndCdataSectionHandler oldEndCdataSectionHandler + = endCdataSectionHandler; + XML_DefaultHandler oldDefaultHandler = defaultHandler; + XML_UnparsedEntityDeclHandler oldUnparsedEntityDeclHandler + = unparsedEntityDeclHandler; + XML_NotationDeclHandler oldNotationDeclHandler = notationDeclHandler; + XML_StartNamespaceDeclHandler oldStartNamespaceDeclHandler + = startNamespaceDeclHandler; + XML_EndNamespaceDeclHandler oldEndNamespaceDeclHandler + = endNamespaceDeclHandler; + XML_NotStandaloneHandler oldNotStandaloneHandler = notStandaloneHandler; + XML_ExternalEntityRefHandler oldExternalEntityRefHandler + = externalEntityRefHandler; + XML_SkippedEntityHandler oldSkippedEntityHandler = skippedEntityHandler; + XML_UnknownEncodingHandler oldUnknownEncodingHandler + = unknownEncodingHandler; + XML_ElementDeclHandler oldElementDeclHandler = elementDeclHandler; + XML_AttlistDeclHandler oldAttlistDeclHandler = attlistDeclHandler; + XML_EntityDeclHandler oldEntityDeclHandler = entityDeclHandler; + XML_XmlDeclHandler oldXmlDeclHandler = xmlDeclHandler; + ELEMENT_TYPE * oldDeclElementType = declElementType; + + void *oldUserData = userData; + void *oldHandlerArg = handlerArg; + XML_Bool oldDefaultExpandInternalEntities = defaultExpandInternalEntities; + XML_Parser oldExternalEntityRefHandlerArg = externalEntityRefHandlerArg; +#ifdef XML_DTD + enum XML_ParamEntityParsing oldParamEntityParsing = paramEntityParsing; + int oldInEntityValue = prologState.inEntityValue; +#endif + XML_Bool oldns_triplets = ns_triplets; + +#ifdef XML_DTD + if (!context) + newDtd = oldDtd; +#endif /* XML_DTD */ + + /* Note that the magical uses of the pre-processor to make field + access look more like C++ require that `parser' be overwritten + here. This makes this function more painful to follow than it + would be otherwise. + */ + if (ns) { + XML_Char tmp[2]; + *tmp = namespaceSeparator; + parser = parserCreate(encodingName, &parser->m_mem, tmp, newDtd); + } + else { + parser = parserCreate(encodingName, &parser->m_mem, NULL, newDtd); + } + + if (!parser) + return NULL; + + startElementHandler = oldStartElementHandler; + endElementHandler = oldEndElementHandler; + characterDataHandler = oldCharacterDataHandler; + processingInstructionHandler = oldProcessingInstructionHandler; + commentHandler = oldCommentHandler; + startCdataSectionHandler = oldStartCdataSectionHandler; + endCdataSectionHandler = oldEndCdataSectionHandler; + defaultHandler = oldDefaultHandler; + unparsedEntityDeclHandler = oldUnparsedEntityDeclHandler; + notationDeclHandler = oldNotationDeclHandler; + startNamespaceDeclHandler = oldStartNamespaceDeclHandler; + endNamespaceDeclHandler = oldEndNamespaceDeclHandler; + notStandaloneHandler = oldNotStandaloneHandler; + externalEntityRefHandler = oldExternalEntityRefHandler; + skippedEntityHandler = oldSkippedEntityHandler; + unknownEncodingHandler = oldUnknownEncodingHandler; + elementDeclHandler = oldElementDeclHandler; + attlistDeclHandler = oldAttlistDeclHandler; + entityDeclHandler = oldEntityDeclHandler; + xmlDeclHandler = oldXmlDeclHandler; + declElementType = oldDeclElementType; + userData = oldUserData; + if (oldUserData == oldHandlerArg) + handlerArg = userData; + else + handlerArg = parser; + if (oldExternalEntityRefHandlerArg != oldParser) + externalEntityRefHandlerArg = oldExternalEntityRefHandlerArg; + defaultExpandInternalEntities = oldDefaultExpandInternalEntities; + ns_triplets = oldns_triplets; + parentParser = oldParser; +#ifdef XML_DTD + paramEntityParsing = oldParamEntityParsing; + prologState.inEntityValue = oldInEntityValue; + if (context) { +#endif /* XML_DTD */ + if (!dtdCopy(_dtd, oldDtd, &parser->m_mem) + || !setContext(parser, context)) { + XML_ParserFree(parser); + return NULL; + } + processor = externalEntityInitProcessor; +#ifdef XML_DTD + } + else { + /* The DTD instance referenced by _dtd is shared between the document's + root parser and external PE parsers, therefore one does not need to + call setContext. In addition, one also *must* not call setContext, + because this would overwrite existing prefix->binding pointers in + _dtd with ones that get destroyed with the external PE parser. + This would leave those prefixes with dangling pointers. + */ + isParamEntity = XML_TRUE; + XmlPrologStateInitExternalEntity(&prologState); + processor = externalParEntInitProcessor; + } +#endif /* XML_DTD */ + return parser; +} + +static void FASTCALL +destroyBindings(BINDING *bindings, XML_Parser parser) +{ + for (;;) { + BINDING *b = bindings; + if (!b) + break; + bindings = b->nextTagBinding; + FREE(b->uri); + FREE(b); + } +} + +void XMLCALL +XML_ParserFree(XML_Parser parser) +{ + TAG *tagList; + OPEN_INTERNAL_ENTITY *entityList; + if (parser == NULL) + return; + /* free tagStack and freeTagList */ + tagList = tagStack; + for (;;) { + TAG *p; + if (tagList == NULL) { + if (freeTagList == NULL) + break; + tagList = freeTagList; + freeTagList = NULL; + } + p = tagList; + tagList = tagList->parent; + FREE(p->buf); + destroyBindings(p->bindings, parser); + FREE(p); + } + /* free openInternalEntities and freeInternalEntities */ + entityList = openInternalEntities; + for (;;) { + OPEN_INTERNAL_ENTITY *openEntity; + if (entityList == NULL) { + if (freeInternalEntities == NULL) + break; + entityList = freeInternalEntities; + freeInternalEntities = NULL; + } + openEntity = entityList; + entityList = entityList->next; + FREE(openEntity); + } + + destroyBindings(freeBindingList, parser); + destroyBindings(inheritedBindings, parser); + poolDestroy(&tempPool); + poolDestroy(&temp2Pool); +#ifdef XML_DTD + /* external parameter entity parsers share the DTD structure + parser->m_dtd with the root parser, so we must not destroy it + */ + if (!isParamEntity && _dtd) +#else + if (_dtd) +#endif /* XML_DTD */ + dtdDestroy(_dtd, (XML_Bool)!parentParser, &parser->m_mem); + FREE((void *)atts); + FREE(groupConnector); + FREE(buffer); + FREE(dataBuf); + FREE(nsAtts); + FREE(unknownEncodingMem); + if (unknownEncodingRelease) + unknownEncodingRelease(unknownEncodingData); + FREE(parser); +} + +void XMLCALL +XML_UseParserAsHandlerArg(XML_Parser parser) +{ + handlerArg = parser; +} + +enum XML_Error XMLCALL +XML_UseForeignDTD(XML_Parser parser, XML_Bool useDTD) +{ +#ifdef XML_DTD + /* block after XML_Parse()/XML_ParseBuffer() has been called */ + if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED) + return XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING; + useForeignDTD = useDTD; + return XML_ERROR_NONE; +#else + return XML_ERROR_FEATURE_REQUIRES_XML_DTD; +#endif +} + +void XMLCALL +XML_SetReturnNSTriplet(XML_Parser parser, int do_nst) +{ + /* block after XML_Parse()/XML_ParseBuffer() has been called */ + if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED) + return; + ns_triplets = do_nst ? XML_TRUE : XML_FALSE; +} + +void XMLCALL +XML_SetUserData(XML_Parser parser, void *p) +{ + if (handlerArg == userData) + handlerArg = userData = p; + else + userData = p; +} + +enum XML_Status XMLCALL +XML_SetBase(XML_Parser parser, const XML_Char *p) +{ + if (p) { + p = poolCopyString(&_dtd->pool, p); + if (!p) + return XML_STATUS_ERROR; + curBase = p; + } + else + curBase = NULL; + return XML_STATUS_OK; +} + +const XML_Char * XMLCALL +XML_GetBase(XML_Parser parser) +{ + return curBase; +} + +int XMLCALL +XML_GetSpecifiedAttributeCount(XML_Parser parser) +{ + return nSpecifiedAtts; +} + +int XMLCALL +XML_GetIdAttributeIndex(XML_Parser parser) +{ + return idAttIndex; +} + +void XMLCALL +XML_SetElementHandler(XML_Parser parser, + XML_StartElementHandler start, + XML_EndElementHandler end) +{ + startElementHandler = start; + endElementHandler = end; +} + +void XMLCALL +XML_SetStartElementHandler(XML_Parser parser, + XML_StartElementHandler start) { + startElementHandler = start; +} + +void XMLCALL +XML_SetEndElementHandler(XML_Parser parser, + XML_EndElementHandler end) { + endElementHandler = end; +} + +void XMLCALL +XML_SetCharacterDataHandler(XML_Parser parser, + XML_CharacterDataHandler handler) +{ + characterDataHandler = handler; +} + +void XMLCALL +XML_SetProcessingInstructionHandler(XML_Parser parser, + XML_ProcessingInstructionHandler handler) +{ + processingInstructionHandler = handler; +} + +void XMLCALL +XML_SetCommentHandler(XML_Parser parser, + XML_CommentHandler handler) +{ + commentHandler = handler; +} + +void XMLCALL +XML_SetCdataSectionHandler(XML_Parser parser, + XML_StartCdataSectionHandler start, + XML_EndCdataSectionHandler end) +{ + startCdataSectionHandler = start; + endCdataSectionHandler = end; +} + +void XMLCALL +XML_SetStartCdataSectionHandler(XML_Parser parser, + XML_StartCdataSectionHandler start) { + startCdataSectionHandler = start; +} + +void XMLCALL +XML_SetEndCdataSectionHandler(XML_Parser parser, + XML_EndCdataSectionHandler end) { + endCdataSectionHandler = end; +} + +void XMLCALL +XML_SetDefaultHandler(XML_Parser parser, + XML_DefaultHandler handler) +{ + defaultHandler = handler; + defaultExpandInternalEntities = XML_FALSE; +} + +void XMLCALL +XML_SetDefaultHandlerExpand(XML_Parser parser, + XML_DefaultHandler handler) +{ + defaultHandler = handler; + defaultExpandInternalEntities = XML_TRUE; +} + +void XMLCALL +XML_SetDoctypeDeclHandler(XML_Parser parser, + XML_StartDoctypeDeclHandler start, + XML_EndDoctypeDeclHandler end) +{ + startDoctypeDeclHandler = start; + endDoctypeDeclHandler = end; +} + +void XMLCALL +XML_SetStartDoctypeDeclHandler(XML_Parser parser, + XML_StartDoctypeDeclHandler start) { + startDoctypeDeclHandler = start; +} + +void XMLCALL +XML_SetEndDoctypeDeclHandler(XML_Parser parser, + XML_EndDoctypeDeclHandler end) { + endDoctypeDeclHandler = end; +} + +void XMLCALL +XML_SetUnparsedEntityDeclHandler(XML_Parser parser, + XML_UnparsedEntityDeclHandler handler) +{ + unparsedEntityDeclHandler = handler; +} + +void XMLCALL +XML_SetNotationDeclHandler(XML_Parser parser, + XML_NotationDeclHandler handler) +{ + notationDeclHandler = handler; +} + +void XMLCALL +XML_SetNamespaceDeclHandler(XML_Parser parser, + XML_StartNamespaceDeclHandler start, + XML_EndNamespaceDeclHandler end) +{ + startNamespaceDeclHandler = start; + endNamespaceDeclHandler = end; +} + +void XMLCALL +XML_SetStartNamespaceDeclHandler(XML_Parser parser, + XML_StartNamespaceDeclHandler start) { + startNamespaceDeclHandler = start; +} + +void XMLCALL +XML_SetEndNamespaceDeclHandler(XML_Parser parser, + XML_EndNamespaceDeclHandler end) { + endNamespaceDeclHandler = end; +} + +void XMLCALL +XML_SetNotStandaloneHandler(XML_Parser parser, + XML_NotStandaloneHandler handler) +{ + notStandaloneHandler = handler; +} + +void XMLCALL +XML_SetExternalEntityRefHandler(XML_Parser parser, + XML_ExternalEntityRefHandler handler) +{ + externalEntityRefHandler = handler; +} + +void XMLCALL +XML_SetExternalEntityRefHandlerArg(XML_Parser parser, void *arg) +{ + if (arg) + externalEntityRefHandlerArg = (XML_Parser)arg; + else + externalEntityRefHandlerArg = parser; +} + +void XMLCALL +XML_SetSkippedEntityHandler(XML_Parser parser, + XML_SkippedEntityHandler handler) +{ + skippedEntityHandler = handler; +} + +void XMLCALL +XML_SetUnknownEncodingHandler(XML_Parser parser, + XML_UnknownEncodingHandler handler, + void *data) +{ + unknownEncodingHandler = handler; + unknownEncodingHandlerData = data; +} + +void XMLCALL +XML_SetElementDeclHandler(XML_Parser parser, + XML_ElementDeclHandler eldecl) +{ + elementDeclHandler = eldecl; +} + +void XMLCALL +XML_SetAttlistDeclHandler(XML_Parser parser, + XML_AttlistDeclHandler attdecl) +{ + attlistDeclHandler = attdecl; +} + +void XMLCALL +XML_SetEntityDeclHandler(XML_Parser parser, + XML_EntityDeclHandler handler) +{ + entityDeclHandler = handler; +} + +void XMLCALL +XML_SetXmlDeclHandler(XML_Parser parser, + XML_XmlDeclHandler handler) { + xmlDeclHandler = handler; +} + +int XMLCALL +XML_SetParamEntityParsing(XML_Parser parser, + enum XML_ParamEntityParsing peParsing) +{ + /* block after XML_Parse()/XML_ParseBuffer() has been called */ + if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED) + return 0; +#ifdef XML_DTD + paramEntityParsing = peParsing; + return 1; +#else + return peParsing == XML_PARAM_ENTITY_PARSING_NEVER; +#endif +} + +enum XML_Status XMLCALL +XML_Parse(XML_Parser parser, const char *s, int len, int isFinal) +{ + switch (ps_parsing) { + case XML_SUSPENDED: + errorCode = XML_ERROR_SUSPENDED; + return XML_STATUS_ERROR; + case XML_FINISHED: + errorCode = XML_ERROR_FINISHED; + return XML_STATUS_ERROR; + default: + ps_parsing = XML_PARSING; + } + + if (len == 0) { + ps_finalBuffer = (XML_Bool)isFinal; + if (!isFinal) + return XML_STATUS_OK; + positionPtr = bufferPtr; + parseEndPtr = bufferEnd; + + /* If data are left over from last buffer, and we now know that these + data are the final chunk of input, then we have to check them again + to detect errors based on that fact. + */ + errorCode = processor(parser, bufferPtr, parseEndPtr, &bufferPtr); + + if (errorCode == XML_ERROR_NONE) { + switch (ps_parsing) { + case XML_SUSPENDED: + XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position); + positionPtr = bufferPtr; + return XML_STATUS_SUSPENDED; + case XML_INITIALIZED: + case XML_PARSING: + ps_parsing = XML_FINISHED; + /* fall through */ + default: + return XML_STATUS_OK; + } + } + eventEndPtr = eventPtr; + processor = errorProcessor; + return XML_STATUS_ERROR; + } +#ifndef XML_CONTEXT_BYTES + else if (bufferPtr == bufferEnd) { + const char *end; + int nLeftOver; + enum XML_Status result; + parseEndByteIndex += len; + positionPtr = s; + ps_finalBuffer = (XML_Bool)isFinal; + + errorCode = processor(parser, s, parseEndPtr = s + len, &end); + + if (errorCode != XML_ERROR_NONE) { + eventEndPtr = eventPtr; + processor = errorProcessor; + return XML_STATUS_ERROR; + } + else { + switch (ps_parsing) { + case XML_SUSPENDED: + result = XML_STATUS_SUSPENDED; + break; + case XML_INITIALIZED: + case XML_PARSING: + case XML_FINISHED://to avoid warning that this case isn't handled + result = XML_STATUS_OK; + if (isFinal) { + ps_parsing = XML_FINISHED; + return result; + } + } + } + + XmlUpdatePosition(encoding, positionPtr, end, &position); + nLeftOver = s + len - end; + if (nLeftOver) { + if (buffer == NULL || nLeftOver > bufferLim - buffer) { + /* FIXME avoid integer overflow */ + char *temp; + temp = (buffer == NULL + ? (char *)MALLOC(len * 2) + : (char *)REALLOC(buffer, len * 2)); + if (temp == NULL) { + errorCode = XML_ERROR_NO_MEMORY; + return XML_STATUS_ERROR; + } + buffer = temp; + if (!buffer) { + errorCode = XML_ERROR_NO_MEMORY; + eventPtr = eventEndPtr = NULL; + processor = errorProcessor; + return XML_STATUS_ERROR; + } + bufferLim = buffer + len * 2; + } + memcpy(buffer, end, nLeftOver); + } + bufferPtr = buffer; + bufferEnd = buffer + nLeftOver; + positionPtr = bufferPtr; + parseEndPtr = bufferEnd; + eventPtr = bufferPtr; + eventEndPtr = bufferPtr; + return result; + } +#endif /* not defined XML_CONTEXT_BYTES */ + else { + void *buff = XML_GetBuffer(parser, len); + if (buff == NULL) + return XML_STATUS_ERROR; + else { + memcpy(buff, s, len); + return XML_ParseBuffer(parser, len, isFinal); + } + } +} + +enum XML_Status XMLCALL +XML_ParseBuffer(XML_Parser parser, int len, int isFinal) +{ + const char *start; + enum XML_Status result = XML_STATUS_OK; + + switch (ps_parsing) { + case XML_SUSPENDED: + errorCode = XML_ERROR_SUSPENDED; + return XML_STATUS_ERROR; + case XML_FINISHED: + errorCode = XML_ERROR_FINISHED; + return XML_STATUS_ERROR; + default: + ps_parsing = XML_PARSING; + } + + start = bufferPtr; + positionPtr = start; + bufferEnd += len; + parseEndPtr = bufferEnd; + parseEndByteIndex += len; + ps_finalBuffer = (XML_Bool)isFinal; + + errorCode = processor(parser, start, parseEndPtr, &bufferPtr); + + if (errorCode != XML_ERROR_NONE) { + eventEndPtr = eventPtr; + processor = errorProcessor; + return XML_STATUS_ERROR; + } + else { + switch (ps_parsing) { + case XML_SUSPENDED: + result = XML_STATUS_SUSPENDED; + break; + case XML_INITIALIZED: + case XML_PARSING: + if (isFinal) { + ps_parsing = XML_FINISHED; + return result; + } + default: ; /* should not happen */ + } + } + + XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position); + positionPtr = bufferPtr; + return result; +} + +void * XMLCALL +XML_GetBuffer(XML_Parser parser, int len) +{ + switch (ps_parsing) { + case XML_SUSPENDED: + errorCode = XML_ERROR_SUSPENDED; + return NULL; + case XML_FINISHED: + errorCode = XML_ERROR_FINISHED; + return NULL; + default: ; + } + + if (len > bufferLim - bufferEnd) { + /* FIXME avoid integer overflow */ + int neededSize = len + (int)(bufferEnd - bufferPtr); +#ifdef XML_CONTEXT_BYTES + int keep = (int)(bufferPtr - buffer); + + if (keep > XML_CONTEXT_BYTES) + keep = XML_CONTEXT_BYTES; + neededSize += keep; +#endif /* defined XML_CONTEXT_BYTES */ + if (neededSize <= bufferLim - buffer) { +#ifdef XML_CONTEXT_BYTES + if (keep < bufferPtr - buffer) { + int offset = (int)(bufferPtr - buffer) - keep; + memmove(buffer, &buffer[offset], bufferEnd - bufferPtr + keep); + bufferEnd -= offset; + bufferPtr -= offset; + } +#else + memmove(buffer, bufferPtr, bufferEnd - bufferPtr); + bufferEnd = buffer + (bufferEnd - bufferPtr); + bufferPtr = buffer; +#endif /* not defined XML_CONTEXT_BYTES */ + } + else { + char *newBuf; + int bufferSize = (int)(bufferLim - bufferPtr); + if (bufferSize == 0) + bufferSize = INIT_BUFFER_SIZE; + do { + bufferSize *= 2; + } while (bufferSize < neededSize); + newBuf = (char *)MALLOC(bufferSize); + if (newBuf == 0) { + errorCode = XML_ERROR_NO_MEMORY; + return NULL; + } + bufferLim = newBuf + bufferSize; +#ifdef XML_CONTEXT_BYTES + if (bufferPtr) { + int keep = (int)(bufferPtr - buffer); + if (keep > XML_CONTEXT_BYTES) + keep = XML_CONTEXT_BYTES; + memcpy(newBuf, &bufferPtr[-keep], bufferEnd - bufferPtr + keep); + FREE(buffer); + buffer = newBuf; + bufferEnd = buffer + (bufferEnd - bufferPtr) + keep; + bufferPtr = buffer + keep; + } + else { + bufferEnd = newBuf + (bufferEnd - bufferPtr); + bufferPtr = buffer = newBuf; + } +#else + if (bufferPtr) { + memcpy(newBuf, bufferPtr, bufferEnd - bufferPtr); + FREE(buffer); + } + bufferEnd = newBuf + (bufferEnd - bufferPtr); + bufferPtr = buffer = newBuf; +#endif /* not defined XML_CONTEXT_BYTES */ + } + } + return bufferEnd; +} + +enum XML_Status XMLCALL +XML_StopParser(XML_Parser parser, XML_Bool resumable) +{ + switch (ps_parsing) { + case XML_SUSPENDED: + if (resumable) { + errorCode = XML_ERROR_SUSPENDED; + return XML_STATUS_ERROR; + } + ps_parsing = XML_FINISHED; + break; + case XML_FINISHED: + errorCode = XML_ERROR_FINISHED; + return XML_STATUS_ERROR; + default: + if (resumable) { +#ifdef XML_DTD + if (isParamEntity) { + errorCode = XML_ERROR_SUSPEND_PE; + return XML_STATUS_ERROR; + } +#endif + ps_parsing = XML_SUSPENDED; + } + else + ps_parsing = XML_FINISHED; + } + return XML_STATUS_OK; +} + +enum XML_Status XMLCALL +XML_ResumeParser(XML_Parser parser) +{ + enum XML_Status result = XML_STATUS_OK; + + if (ps_parsing != XML_SUSPENDED) { + errorCode = XML_ERROR_NOT_SUSPENDED; + return XML_STATUS_ERROR; + } + ps_parsing = XML_PARSING; + + errorCode = processor(parser, bufferPtr, parseEndPtr, &bufferPtr); + + if (errorCode != XML_ERROR_NONE) { + eventEndPtr = eventPtr; + processor = errorProcessor; + return XML_STATUS_ERROR; + } + else { + switch (ps_parsing) { + case XML_SUSPENDED: + result = XML_STATUS_SUSPENDED; + break; + case XML_INITIALIZED: + case XML_PARSING: + if (ps_finalBuffer) { + ps_parsing = XML_FINISHED; + return result; + } + default: ; + } + } + + XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position); + positionPtr = bufferPtr; + return result; +} + +void XMLCALL +XML_GetParsingStatus(XML_Parser parser, XML_ParsingStatus *status) +{ + assert(status != NULL); + *status = parser->m_parsingStatus; +} + +enum XML_Error XMLCALL +XML_GetErrorCode(XML_Parser parser) +{ + return errorCode; +} + +XML_Index XMLCALL +XML_GetCurrentByteIndex(XML_Parser parser) +{ + if (eventPtr) + return parseEndByteIndex - (parseEndPtr - eventPtr); + return -1; +} + +int XMLCALL +XML_GetCurrentByteCount(XML_Parser parser) +{ + if (eventEndPtr && eventPtr) + return (int)(eventEndPtr - eventPtr); + return 0; +} + +const char * XMLCALL +XML_GetInputContext(XML_Parser parser, int *offset, int *size) +{ +#ifdef XML_CONTEXT_BYTES + if (eventPtr && buffer) { + *offset = (int)(eventPtr - buffer); + *size = (int)(bufferEnd - buffer); + return buffer; + } +#endif /* defined XML_CONTEXT_BYTES */ + return (char *) 0; +} + +XML_Size XMLCALL +XML_GetCurrentLineNumber(XML_Parser parser) +{ + if (eventPtr && eventPtr >= positionPtr) { + XmlUpdatePosition(encoding, positionPtr, eventPtr, &position); + positionPtr = eventPtr; + } + return position.lineNumber + 1; +} + +XML_Size XMLCALL +XML_GetCurrentColumnNumber(XML_Parser parser) +{ + if (eventPtr && eventPtr >= positionPtr) { + XmlUpdatePosition(encoding, positionPtr, eventPtr, &position); + positionPtr = eventPtr; + } + return position.columnNumber; +} + +void XMLCALL +XML_FreeContentModel(XML_Parser parser, XML_Content *model) +{ + FREE(model); +} + +void * XMLCALL +XML_MemMalloc(XML_Parser parser, size_t size) +{ + return MALLOC(size); +} + +void * XMLCALL +XML_MemRealloc(XML_Parser parser, void *ptr, size_t size) +{ + return REALLOC(ptr, size); +} + +void XMLCALL +XML_MemFree(XML_Parser parser, void *ptr) +{ + FREE(ptr); +} + +void XMLCALL +XML_DefaultCurrent(XML_Parser parser) +{ + if (defaultHandler) { + if (openInternalEntities) + reportDefault(parser, + internalEncoding, + openInternalEntities->internalEventPtr, + openInternalEntities->internalEventEndPtr); + else + reportDefault(parser, encoding, eventPtr, eventEndPtr); + } +} + +const XML_LChar * XMLCALL +XML_ErrorString(enum XML_Error code) +{ + static const XML_LChar* const message[] = { + 0, + XML_L("out of memory"), + XML_L("syntax error"), + XML_L("no element found"), + XML_L("not well-formed (invalid token)"), + XML_L("unclosed token"), + XML_L("partial character"), + XML_L("mismatched tag"), + XML_L("duplicate attribute"), + XML_L("junk after document element"), + XML_L("illegal parameter entity reference"), + XML_L("undefined entity"), + XML_L("recursive entity reference"), + XML_L("asynchronous entity"), + XML_L("reference to invalid character number"), + XML_L("reference to binary entity"), + XML_L("reference to external entity in attribute"), + XML_L("XML or text declaration not at start of entity"), + XML_L("unknown encoding"), + XML_L("encoding specified in XML declaration is incorrect"), + XML_L("unclosed CDATA section"), + XML_L("error in processing external entity reference"), + XML_L("document is not standalone"), + XML_L("unexpected parser state - please send a bug report"), + XML_L("entity declared in parameter entity"), + XML_L("requested feature requires XML_DTD support in Expat"), + XML_L("cannot change setting once parsing has begun"), + XML_L("unbound prefix"), + XML_L("must not undeclare prefix"), + XML_L("incomplete markup in parameter entity"), + XML_L("XML declaration not well-formed"), + XML_L("text declaration not well-formed"), + XML_L("illegal character(s) in public id"), + XML_L("parser suspended"), + XML_L("parser not suspended"), + XML_L("parsing aborted"), + XML_L("parsing finished"), + XML_L("cannot suspend in external parameter entity"), + XML_L("reserved prefix (xml) must not be undeclared or bound to another namespace name"), + XML_L("reserved prefix (xmlns) must not be declared or undeclared"), + XML_L("prefix must not be bound to one of the reserved namespace names") + }; + if (code > 0 && code < sizeof(message)/sizeof(message[0])) + return message[code]; + return NULL; +} + +const XML_LChar * XMLCALL +XML_ExpatVersion(void) { + + /* V1 is used to string-ize the version number. However, it would + string-ize the actual version macro *names* unless we get them + substituted before being passed to V1. CPP is defined to expand + a macro, then rescan for more expansions. Thus, we use V2 to expand + the version macros, then CPP will expand the resulting V1() macro + with the correct numerals. */ + /* ### I'm assuming cpp is portable in this respect... */ + +#define V1(a,b,c) XML_L(#a)XML_L(".")XML_L(#b)XML_L(".")XML_L(#c) +#define V2(a,b,c) XML_L("expat_")V1(a,b,c) + + return V2(XML_MAJOR_VERSION, XML_MINOR_VERSION, XML_MICRO_VERSION); + +#undef V1 +#undef V2 +} + +XML_Expat_Version XMLCALL +XML_ExpatVersionInfo(void) +{ + XML_Expat_Version version; + + version.major = XML_MAJOR_VERSION; + version.minor = XML_MINOR_VERSION; + version.micro = XML_MICRO_VERSION; + + return version; +} + +const XML_Feature * XMLCALL +XML_GetFeatureList(void) +{ + static const XML_Feature features[] = { + {XML_FEATURE_SIZEOF_XML_CHAR, XML_L("sizeof(XML_Char)"), + sizeof(XML_Char)}, + {XML_FEATURE_SIZEOF_XML_LCHAR, XML_L("sizeof(XML_LChar)"), + sizeof(XML_LChar)}, +#ifdef XML_UNICODE + {XML_FEATURE_UNICODE, XML_L("XML_UNICODE"), 0}, +#endif +#ifdef XML_UNICODE_WCHAR_T + {XML_FEATURE_UNICODE_WCHAR_T, XML_L("XML_UNICODE_WCHAR_T"), 0}, +#endif +#ifdef XML_DTD + {XML_FEATURE_DTD, XML_L("XML_DTD"), 0}, +#endif +#ifdef XML_CONTEXT_BYTES + {XML_FEATURE_CONTEXT_BYTES, XML_L("XML_CONTEXT_BYTES"), + XML_CONTEXT_BYTES}, +#endif +#ifdef XML_MIN_SIZE + {XML_FEATURE_MIN_SIZE, XML_L("XML_MIN_SIZE"), 0}, +#endif +#ifdef XML_NS + {XML_FEATURE_NS, XML_L("XML_NS"), 0}, +#endif + {XML_FEATURE_END, NULL, 0} + }; + + return features; +} + +/* Initially tag->rawName always points into the parse buffer; + for those TAG instances opened while the current parse buffer was + processed, and not yet closed, we need to store tag->rawName in a more + permanent location, since the parse buffer is about to be discarded. +*/ +static XML_Bool +storeRawNames(XML_Parser parser) +{ + TAG *tag = tagStack; + while (tag) { + int bufSize; + int nameLen = sizeof(XML_Char) * (tag->name.strLen + 1); + char *rawNameBuf = tag->buf + nameLen; + /* Stop if already stored. Since tagStack is a stack, we can stop + at the first entry that has already been copied; everything + below it in the stack is already been accounted for in a + previous call to this function. + */ + if (tag->rawName == rawNameBuf) + break; + /* For re-use purposes we need to ensure that the + size of tag->buf is a multiple of sizeof(XML_Char). + */ + bufSize = nameLen + ROUND_UP(tag->rawNameLength, sizeof(XML_Char)); + if (bufSize > tag->bufEnd - tag->buf) { + char *temp = (char *)REALLOC(tag->buf, bufSize); + if (temp == NULL) + return XML_FALSE; + /* if tag->name.str points to tag->buf (only when namespace + processing is off) then we have to update it + */ + if (tag->name.str == (XML_Char *)tag->buf) + tag->name.str = (XML_Char *)temp; + /* if tag->name.localPart is set (when namespace processing is on) + then update it as well, since it will always point into tag->buf + */ + if (tag->name.localPart) + tag->name.localPart = (XML_Char *)temp + (tag->name.localPart - + (XML_Char *)tag->buf); + tag->buf = temp; + tag->bufEnd = temp + bufSize; + rawNameBuf = temp + nameLen; + } + memcpy(rawNameBuf, tag->rawName, tag->rawNameLength); + tag->rawName = rawNameBuf; + tag = tag->parent; + } + return XML_TRUE; +} + +static enum XML_Error PTRCALL +contentProcessor(XML_Parser parser, + const char *start, + const char *end, + const char **endPtr) +{ + enum XML_Error result = doContent(parser, 0, encoding, start, end, + endPtr, (XML_Bool)!ps_finalBuffer); + if (result == XML_ERROR_NONE) { + if (!storeRawNames(parser)) + return XML_ERROR_NO_MEMORY; + } + return result; +} + +static enum XML_Error PTRCALL +externalEntityInitProcessor(XML_Parser parser, + const char *start, + const char *end, + const char **endPtr) +{ + enum XML_Error result = initializeEncoding(parser); + if (result != XML_ERROR_NONE) + return result; + processor = externalEntityInitProcessor2; + return externalEntityInitProcessor2(parser, start, end, endPtr); +} + +static enum XML_Error PTRCALL +externalEntityInitProcessor2(XML_Parser parser, + const char *start, + const char *end, + const char **endPtr) +{ + const char *next = start; /* XmlContentTok doesn't always set the last arg */ + int tok = XmlContentTok(encoding, start, end, &next); + switch (tok) { + case XML_TOK_BOM: + /* If we are at the end of the buffer, this would cause the next stage, + i.e. externalEntityInitProcessor3, to pass control directly to + doContent (by detecting XML_TOK_NONE) without processing any xml text + declaration - causing the error XML_ERROR_MISPLACED_XML_PI in doContent. + */ + if (next == end && !ps_finalBuffer) { + *endPtr = next; + return XML_ERROR_NONE; + } + start = next; + break; + case XML_TOK_PARTIAL: + if (!ps_finalBuffer) { + *endPtr = start; + return XML_ERROR_NONE; + } + eventPtr = start; + return XML_ERROR_UNCLOSED_TOKEN; + case XML_TOK_PARTIAL_CHAR: + if (!ps_finalBuffer) { + *endPtr = start; + return XML_ERROR_NONE; + } + eventPtr = start; + return XML_ERROR_PARTIAL_CHAR; + } + processor = externalEntityInitProcessor3; + return externalEntityInitProcessor3(parser, start, end, endPtr); +} + +static enum XML_Error PTRCALL +externalEntityInitProcessor3(XML_Parser parser, + const char *start, + const char *end, + const char **endPtr) +{ + int tok; + const char *next = start; /* XmlContentTok doesn't always set the last arg */ + eventPtr = start; + tok = XmlContentTok(encoding, start, end, &next); + eventEndPtr = next; + + switch (tok) { + case XML_TOK_XML_DECL: + { + enum XML_Error result; + result = processXmlDecl(parser, 1, start, next); + if (result != XML_ERROR_NONE) + return result; + switch (ps_parsing) { + case XML_SUSPENDED: + *endPtr = next; + return XML_ERROR_NONE; + case XML_FINISHED: + return XML_ERROR_ABORTED; + default: + start = next; + } + } + break; + case XML_TOK_PARTIAL: + if (!ps_finalBuffer) { + *endPtr = start; + return XML_ERROR_NONE; + } + return XML_ERROR_UNCLOSED_TOKEN; + case XML_TOK_PARTIAL_CHAR: + if (!ps_finalBuffer) { + *endPtr = start; + return XML_ERROR_NONE; + } + return XML_ERROR_PARTIAL_CHAR; + } + processor = externalEntityContentProcessor; + tagLevel = 1; + return externalEntityContentProcessor(parser, start, end, endPtr); +} + +static enum XML_Error PTRCALL +externalEntityContentProcessor(XML_Parser parser, + const char *start, + const char *end, + const char **endPtr) +{ + enum XML_Error result = doContent(parser, 1, encoding, start, end, + endPtr, (XML_Bool)!ps_finalBuffer); + if (result == XML_ERROR_NONE) { + if (!storeRawNames(parser)) + return XML_ERROR_NO_MEMORY; + } + return result; +} + +static enum XML_Error +doContent(XML_Parser parser, + int startTagLevel, + const ENCODING *enc, + const char *s, + const char *end, + const char **nextPtr, + XML_Bool haveMore) +{ + /* save one level of indirection */ + DTD * const dtd = _dtd; + + const char **eventPP; + const char **eventEndPP; + if (enc == encoding) { + eventPP = &eventPtr; + eventEndPP = &eventEndPtr; + } + else { + eventPP = &(openInternalEntities->internalEventPtr); + eventEndPP = &(openInternalEntities->internalEventEndPtr); + } + *eventPP = s; + + for (;;) { + const char *next = s; /* XmlContentTok doesn't always set the last arg */ + int tok = XmlContentTok(enc, s, end, &next); + *eventEndPP = next; + switch (tok) { + case XML_TOK_TRAILING_CR: + if (haveMore) { + *nextPtr = s; + return XML_ERROR_NONE; + } + *eventEndPP = end; + if (characterDataHandler) { + XML_Char c = 0xA; + characterDataHandler(handlerArg, &c, 1); + } + else if (defaultHandler) + reportDefault(parser, enc, s, end); + /* We are at the end of the final buffer, should we check for + XML_SUSPENDED, XML_FINISHED? + */ + if (startTagLevel == 0) + return XML_ERROR_NO_ELEMENTS; + if (tagLevel != startTagLevel) + return XML_ERROR_ASYNC_ENTITY; + *nextPtr = end; + return XML_ERROR_NONE; + case XML_TOK_NONE: + if (haveMore) { + *nextPtr = s; + return XML_ERROR_NONE; + } + if (startTagLevel > 0) { + if (tagLevel != startTagLevel) + return XML_ERROR_ASYNC_ENTITY; + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_NO_ELEMENTS; + case XML_TOK_INVALID: + *eventPP = next; + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_PARTIAL: + if (haveMore) { + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_UNCLOSED_TOKEN; + case XML_TOK_PARTIAL_CHAR: + if (haveMore) { + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_PARTIAL_CHAR; + case XML_TOK_ENTITY_REF: + { + const XML_Char *name; + ENTITY *entity; + XML_Char ch = (XML_Char) XmlPredefinedEntityName(enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (ch) { + if (characterDataHandler) + characterDataHandler(handlerArg, &ch, 1); + else if (defaultHandler) + reportDefault(parser, enc, s, next); + break; + } + name = poolStoreString(&dtd->pool, enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (!name) + return XML_ERROR_NO_MEMORY; + entity = (ENTITY *)lookup(&dtd->generalEntities, name, 0); + poolDiscard(&dtd->pool); + /* First, determine if a check for an existing declaration is needed; + if yes, check that the entity exists, and that it is internal, + otherwise call the skipped entity or default handler. + */ + if (!dtd->hasParamEntityRefs || dtd->standalone) { + if (!entity) + return XML_ERROR_UNDEFINED_ENTITY; + else if (!entity->is_internal) + return XML_ERROR_ENTITY_DECLARED_IN_PE; + } + else if (!entity) { + if (skippedEntityHandler) + skippedEntityHandler(handlerArg, name, 0); + else if (defaultHandler) + reportDefault(parser, enc, s, next); + break; + } + if (entity->open) + return XML_ERROR_RECURSIVE_ENTITY_REF; + if (entity->notation) + return XML_ERROR_BINARY_ENTITY_REF; + if (entity->textPtr) { + enum XML_Error result; + if (!defaultExpandInternalEntities) { + if (skippedEntityHandler) + skippedEntityHandler(handlerArg, entity->name, 0); + else if (defaultHandler) + reportDefault(parser, enc, s, next); + break; + } + result = processInternalEntity(parser, entity, XML_FALSE); + if (result != XML_ERROR_NONE) + return result; + } + else if (externalEntityRefHandler) { + const XML_Char *context; + entity->open = XML_TRUE; + context = getContext(parser); + entity->open = XML_FALSE; + if (!context) + return XML_ERROR_NO_MEMORY; + if (!externalEntityRefHandler(externalEntityRefHandlerArg, + context, + entity->base, + entity->systemId, + entity->publicId)) + return XML_ERROR_EXTERNAL_ENTITY_HANDLING; + poolDiscard(&tempPool); + } + else if (defaultHandler) + reportDefault(parser, enc, s, next); + break; + } + case XML_TOK_START_TAG_NO_ATTS: + /* fall through */ + case XML_TOK_START_TAG_WITH_ATTS: + { + TAG *tag; + enum XML_Error result; + XML_Char *toPtr; + if (freeTagList) { + tag = freeTagList; + freeTagList = freeTagList->parent; + } + else { + tag = (TAG *)MALLOC(sizeof(TAG)); + if (!tag) + return XML_ERROR_NO_MEMORY; + tag->buf = (char *)MALLOC(INIT_TAG_BUF_SIZE); + if (!tag->buf) { + FREE(tag); + return XML_ERROR_NO_MEMORY; + } + tag->bufEnd = tag->buf + INIT_TAG_BUF_SIZE; + } + tag->bindings = NULL; + tag->parent = tagStack; + tagStack = tag; + tag->name.localPart = NULL; + tag->name.prefix = NULL; + tag->rawName = s + enc->minBytesPerChar; + tag->rawNameLength = XmlNameLength(enc, tag->rawName); + ++tagLevel; + { + const char *rawNameEnd = tag->rawName + tag->rawNameLength; + const char *fromPtr = tag->rawName; + toPtr = (XML_Char *)tag->buf; + for (;;) { + int bufSize; + int convLen; + XmlConvert(enc, + &fromPtr, rawNameEnd, + (ICHAR **)&toPtr, (ICHAR *)tag->bufEnd - 1); + convLen = (int)(toPtr - (XML_Char *)tag->buf); + if (fromPtr == rawNameEnd) { + tag->name.strLen = convLen; + break; + } + bufSize = (int)(tag->bufEnd - tag->buf) << 1; + { + char *temp = (char *)REALLOC(tag->buf, bufSize); + if (temp == NULL) + return XML_ERROR_NO_MEMORY; + tag->buf = temp; + tag->bufEnd = temp + bufSize; + toPtr = (XML_Char *)temp + convLen; + } + } + } + tag->name.str = (XML_Char *)tag->buf; + *toPtr = XML_T('\0'); + result = storeAtts(parser, enc, s, &(tag->name), &(tag->bindings)); + if (result) + return result; + if (startElementHandler) + startElementHandler(handlerArg, tag->name.str, + (const XML_Char **)atts); + else if (defaultHandler) + reportDefault(parser, enc, s, next); + poolClear(&tempPool); + break; + } + case XML_TOK_EMPTY_ELEMENT_NO_ATTS: + /* fall through */ + case XML_TOK_EMPTY_ELEMENT_WITH_ATTS: + { + const char *rawName = s + enc->minBytesPerChar; + enum XML_Error result; + BINDING *bindings = NULL; + XML_Bool noElmHandlers = XML_TRUE; + TAG_NAME name; + name.str = poolStoreString(&tempPool, enc, rawName, + rawName + XmlNameLength(enc, rawName)); + if (!name.str) + return XML_ERROR_NO_MEMORY; + poolFinish(&tempPool); + result = storeAtts(parser, enc, s, &name, &bindings); + if (result) + return result; + poolFinish(&tempPool); + if (startElementHandler) { + startElementHandler(handlerArg, name.str, (const XML_Char **)atts); + noElmHandlers = XML_FALSE; + } + if (endElementHandler) { + if (startElementHandler) + *eventPP = *eventEndPP; + endElementHandler(handlerArg, name.str); + noElmHandlers = XML_FALSE; + } + if (noElmHandlers && defaultHandler) + reportDefault(parser, enc, s, next); + poolClear(&tempPool); + while (bindings) { + BINDING *b = bindings; + if (endNamespaceDeclHandler) + endNamespaceDeclHandler(handlerArg, b->prefix->name); + bindings = bindings->nextTagBinding; + b->nextTagBinding = freeBindingList; + freeBindingList = b; + b->prefix->binding = b->prevPrefixBinding; + } + } + if (tagLevel == 0) + return epilogProcessor(parser, next, end, nextPtr); + break; + case XML_TOK_END_TAG: + if (tagLevel == startTagLevel) + return XML_ERROR_ASYNC_ENTITY; + else { + int len; + const char *rawName; + TAG *tag = tagStack; + tagStack = tag->parent; + tag->parent = freeTagList; + freeTagList = tag; + rawName = s + enc->minBytesPerChar*2; + len = XmlNameLength(enc, rawName); + if (len != tag->rawNameLength + || memcmp(tag->rawName, rawName, len) != 0) { + *eventPP = rawName; + return XML_ERROR_TAG_MISMATCH; + } + --tagLevel; + if (endElementHandler) { + const XML_Char *localPart; + const XML_Char *prefix; + XML_Char *uri; + localPart = tag->name.localPart; + if (ns && localPart) { + /* localPart and prefix may have been overwritten in + tag->name.str, since this points to the binding->uri + buffer which gets re-used; so we have to add them again + */ + uri = (XML_Char *)tag->name.str + tag->name.uriLen; + /* don't need to check for space - already done in storeAtts() */ + while (*localPart) *uri++ = *localPart++; + prefix = (XML_Char *)tag->name.prefix; + if (ns_triplets && prefix) { + *uri++ = namespaceSeparator; + while (*prefix) *uri++ = *prefix++; + } + *uri = XML_T('\0'); + } + endElementHandler(handlerArg, tag->name.str); + } + else if (defaultHandler) + reportDefault(parser, enc, s, next); + while (tag->bindings) { + BINDING *b = tag->bindings; + if (endNamespaceDeclHandler) + endNamespaceDeclHandler(handlerArg, b->prefix->name); + tag->bindings = tag->bindings->nextTagBinding; + b->nextTagBinding = freeBindingList; + freeBindingList = b; + b->prefix->binding = b->prevPrefixBinding; + } + if (tagLevel == 0) + return epilogProcessor(parser, next, end, nextPtr); + } + break; + case XML_TOK_CHAR_REF: + { + int n = XmlCharRefNumber(enc, s); + if (n < 0) + return XML_ERROR_BAD_CHAR_REF; + if (characterDataHandler) { + XML_Char buf[XML_ENCODE_MAX]; + characterDataHandler(handlerArg, buf, XmlEncode(n, (ICHAR *)buf)); + } + else if (defaultHandler) + reportDefault(parser, enc, s, next); + } + break; + case XML_TOK_XML_DECL: + return XML_ERROR_MISPLACED_XML_PI; + case XML_TOK_DATA_NEWLINE: + if (characterDataHandler) { + XML_Char c = 0xA; + characterDataHandler(handlerArg, &c, 1); + } + else if (defaultHandler) + reportDefault(parser, enc, s, next); + break; + case XML_TOK_CDATA_SECT_OPEN: + { + enum XML_Error result; + if (startCdataSectionHandler) + startCdataSectionHandler(handlerArg); +#if 0 + /* Suppose you doing a transformation on a document that involves + changing only the character data. You set up a defaultHandler + and a characterDataHandler. The defaultHandler simply copies + characters through. The characterDataHandler does the + transformation and writes the characters out escaping them as + necessary. This case will fail to work if we leave out the + following two lines (because & and < inside CDATA sections will + be incorrectly escaped). + + However, now we have a start/endCdataSectionHandler, so it seems + easier to let the user deal with this. + */ + else if (characterDataHandler) + characterDataHandler(handlerArg, dataBuf, 0); +#endif + else if (defaultHandler) + reportDefault(parser, enc, s, next); + result = doCdataSection(parser, enc, &next, end, nextPtr, haveMore); + if (result != XML_ERROR_NONE) + return result; + else if (!next) { + processor = cdataSectionProcessor; + return result; + } + } + break; + case XML_TOK_TRAILING_RSQB: + if (haveMore) { + *nextPtr = s; + return XML_ERROR_NONE; + } + if (characterDataHandler) { + if (MUST_CONVERT(enc, s)) { + ICHAR *dataPtr = (ICHAR *)dataBuf; + XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)dataBufEnd); + characterDataHandler(handlerArg, dataBuf, + (int)(dataPtr - (ICHAR *)dataBuf)); + } + else + characterDataHandler(handlerArg, + (XML_Char *)s, + (int)((XML_Char *)end - (XML_Char *)s)); + } + else if (defaultHandler) + reportDefault(parser, enc, s, end); + /* We are at the end of the final buffer, should we check for + XML_SUSPENDED, XML_FINISHED? + */ + if (startTagLevel == 0) { + *eventPP = end; + return XML_ERROR_NO_ELEMENTS; + } + if (tagLevel != startTagLevel) { + *eventPP = end; + return XML_ERROR_ASYNC_ENTITY; + } + *nextPtr = end; + return XML_ERROR_NONE; + case XML_TOK_DATA_CHARS: + if (characterDataHandler) { + if (MUST_CONVERT(enc, s)) { + for (;;) { + ICHAR *dataPtr = (ICHAR *)dataBuf; + XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)dataBufEnd); + *eventEndPP = s; + characterDataHandler(handlerArg, dataBuf, + (int)(dataPtr - (ICHAR *)dataBuf)); + if (s == next) + break; + *eventPP = s; + } + } + else + characterDataHandler(handlerArg, + (XML_Char *)s, + (int)((XML_Char *)next - (XML_Char *)s)); + } + else if (defaultHandler) + reportDefault(parser, enc, s, next); + break; + case XML_TOK_PI: + if (!reportProcessingInstruction(parser, enc, s, next)) + return XML_ERROR_NO_MEMORY; + break; + case XML_TOK_COMMENT: + if (!reportComment(parser, enc, s, next)) + return XML_ERROR_NO_MEMORY; + break; + default: + if (defaultHandler) + reportDefault(parser, enc, s, next); + break; + } + *eventPP = s = next; + switch (ps_parsing) { + case XML_SUSPENDED: + *nextPtr = next; + return XML_ERROR_NONE; + case XML_FINISHED: + return XML_ERROR_ABORTED; + default: ; + } + } + /* not reached */ +} + +/* Precondition: all arguments must be non-NULL; + Purpose: + - normalize attributes + - check attributes for well-formedness + - generate namespace aware attribute names (URI, prefix) + - build list of attributes for startElementHandler + - default attributes + - process namespace declarations (check and report them) + - generate namespace aware element name (URI, prefix) +*/ +static enum XML_Error +storeAtts(XML_Parser parser, const ENCODING *enc, + const char *attStr, TAG_NAME *tagNamePtr, + BINDING **bindingsPtr) +{ + DTD * const dtd = _dtd; /* save one level of indirection */ + ELEMENT_TYPE *elementType; + int nDefaultAtts; + const XML_Char **appAtts; /* the attribute list for the application */ + int attIndex = 0; + int prefixLen; + int i; + int n; + XML_Char *uri; + int nPrefixes = 0; + BINDING *binding; + const XML_Char *localPart; + + /* lookup the element type name */ + elementType = (ELEMENT_TYPE *)lookup(&dtd->elementTypes, tagNamePtr->str,0); + if (!elementType) { + const XML_Char *name = poolCopyString(&dtd->pool, tagNamePtr->str); + if (!name) + return XML_ERROR_NO_MEMORY; + elementType = (ELEMENT_TYPE *)lookup(&dtd->elementTypes, name, + sizeof(ELEMENT_TYPE)); + if (!elementType) + return XML_ERROR_NO_MEMORY; + if (ns && !setElementTypePrefix(parser, elementType)) + return XML_ERROR_NO_MEMORY; + } + nDefaultAtts = elementType->nDefaultAtts; + + /* get the attributes from the tokenizer */ + n = XmlGetAttributes(enc, attStr, attsSize, atts); + if (n + nDefaultAtts > attsSize) { + int oldAttsSize = attsSize; + ATTRIBUTE *temp; + attsSize = n + nDefaultAtts + INIT_ATTS_SIZE; + temp = (ATTRIBUTE *)REALLOC((void *)atts, attsSize * sizeof(ATTRIBUTE)); + if (temp == NULL) + return XML_ERROR_NO_MEMORY; + atts = temp; + if (n > oldAttsSize) + XmlGetAttributes(enc, attStr, n, atts); + } + + appAtts = (const XML_Char **)atts; + for (i = 0; i < n; i++) { + /* add the name and value to the attribute list */ + ATTRIBUTE_ID *attId = getAttributeId(parser, enc, atts[i].name, + atts[i].name + + XmlNameLength(enc, atts[i].name)); + if (!attId) + return XML_ERROR_NO_MEMORY; + /* Detect duplicate attributes by their QNames. This does not work when + namespace processing is turned on and different prefixes for the same + namespace are used. For this case we have a check further down. + */ + if ((attId->name)[-1]) { + if (enc == encoding) + eventPtr = atts[i].name; + return XML_ERROR_DUPLICATE_ATTRIBUTE; + } + (attId->name)[-1] = 1; + appAtts[attIndex++] = attId->name; + if (!atts[i].normalized) { + enum XML_Error result; + XML_Bool isCdata = XML_TRUE; + + /* figure out whether declared as other than CDATA */ + if (attId->maybeTokenized) { + int j; + for (j = 0; j < nDefaultAtts; j++) { + if (attId == elementType->defaultAtts[j].id) { + isCdata = elementType->defaultAtts[j].isCdata; + break; + } + } + } + + /* normalize the attribute value */ + result = storeAttributeValue(parser, enc, isCdata, + atts[i].valuePtr, atts[i].valueEnd, + &tempPool); + if (result) + return result; + appAtts[attIndex] = poolStart(&tempPool); + poolFinish(&tempPool); + } + else { + /* the value did not need normalizing */ + appAtts[attIndex] = poolStoreString(&tempPool, enc, atts[i].valuePtr, + atts[i].valueEnd); + if (appAtts[attIndex] == 0) + return XML_ERROR_NO_MEMORY; + poolFinish(&tempPool); + } + /* handle prefixed attribute names */ + if (attId->prefix) { + if (attId->xmlns) { + /* deal with namespace declarations here */ + enum XML_Error result = addBinding(parser, attId->prefix, attId, + appAtts[attIndex], bindingsPtr); + if (result) + return result; + --attIndex; + } + else { + /* deal with other prefixed names later */ + attIndex++; + nPrefixes++; + (attId->name)[-1] = 2; + } + } + else + attIndex++; + } + + /* set-up for XML_GetSpecifiedAttributeCount and XML_GetIdAttributeIndex */ + nSpecifiedAtts = attIndex; + if (elementType->idAtt && (elementType->idAtt->name)[-1]) { + for (i = 0; i < attIndex; i += 2) + if (appAtts[i] == elementType->idAtt->name) { + idAttIndex = i; + break; + } + } + else + idAttIndex = -1; + + /* do attribute defaulting */ + for (i = 0; i < nDefaultAtts; i++) { + const DEFAULT_ATTRIBUTE *da = elementType->defaultAtts + i; + if (!(da->id->name)[-1] && da->value) { + if (da->id->prefix) { + if (da->id->xmlns) { + enum XML_Error result = addBinding(parser, da->id->prefix, da->id, + da->value, bindingsPtr); + if (result) + return result; + } + else { + (da->id->name)[-1] = 2; + nPrefixes++; + appAtts[attIndex++] = da->id->name; + appAtts[attIndex++] = da->value; + } + } + else { + (da->id->name)[-1] = 1; + appAtts[attIndex++] = da->id->name; + appAtts[attIndex++] = da->value; + } + } + } + appAtts[attIndex] = 0; + + /* expand prefixed attribute names, check for duplicates, + and clear flags that say whether attributes were specified */ + i = 0; + if (nPrefixes) { + int j; /* hash table index */ + unsigned long version = nsAttsVersion; + int nsAttsSize = (int)1 << nsAttsPower; + /* size of hash table must be at least 2 * (# of prefixed attributes) */ + if ((nPrefixes << 1) >> nsAttsPower) { /* true for nsAttsPower = 0 */ + NS_ATT *temp; + /* hash table size must also be a power of 2 and >= 8 */ + while (nPrefixes >> nsAttsPower++); + if (nsAttsPower < 3) + nsAttsPower = 3; + nsAttsSize = (int)1 << nsAttsPower; + temp = (NS_ATT *)REALLOC(nsAtts, nsAttsSize * sizeof(NS_ATT)); + if (!temp) + return XML_ERROR_NO_MEMORY; + nsAtts = temp; + version = 0; /* force re-initialization of nsAtts hash table */ + } + /* using a version flag saves us from initializing nsAtts every time */ + if (!version) { /* initialize version flags when version wraps around */ + version = INIT_ATTS_VERSION; + for (j = nsAttsSize; j != 0; ) + nsAtts[--j].version = version; + } + nsAttsVersion = --version; + + /* expand prefixed names and check for duplicates */ + for (; i < attIndex; i += 2) { + const XML_Char *s = appAtts[i]; + if (s[-1] == 2) { /* prefixed */ + ATTRIBUTE_ID *id; + const BINDING *b; + unsigned long uriHash = 0; + ((XML_Char *)s)[-1] = 0; /* clear flag */ + id = (ATTRIBUTE_ID *)lookup(&dtd->attributeIds, s, 0); + b = id->prefix->binding; + if (!b) + return XML_ERROR_UNBOUND_PREFIX; + + /* as we expand the name we also calculate its hash value */ + for (j = 0; j < b->uriLen; j++) { + const XML_Char c = b->uri[j]; + if (!poolAppendChar(&tempPool, c)) + return XML_ERROR_NO_MEMORY; + uriHash = CHAR_HASH(uriHash, c); + } + while (*s++ != XML_T(':')) + ; + do { /* copies null terminator */ + const XML_Char c = *s; + if (!poolAppendChar(&tempPool, *s)) + return XML_ERROR_NO_MEMORY; + uriHash = CHAR_HASH(uriHash, c); + } while (*s++); + + { /* Check hash table for duplicate of expanded name (uriName). + Derived from code in lookup(HASH_TABLE *table, ...). + */ + unsigned char step = 0; + unsigned long mask = nsAttsSize - 1; + j = uriHash & mask; /* index into hash table */ + while (nsAtts[j].version == version) { + /* for speed we compare stored hash values first */ + if (uriHash == nsAtts[j].hash) { + const XML_Char *s1 = poolStart(&tempPool); + const XML_Char *s2 = nsAtts[j].uriName; + /* s1 is null terminated, but not s2 */ + for (; *s1 == *s2 && *s1 != 0; s1++, s2++); + if (*s1 == 0) + return XML_ERROR_DUPLICATE_ATTRIBUTE; + } + if (!step) + step = PROBE_STEP(uriHash, mask, nsAttsPower); + j < step ? (j += nsAttsSize - step) : (j -= step); + } + } + + if (ns_triplets) { /* append namespace separator and prefix */ + tempPool.ptr[-1] = namespaceSeparator; + s = b->prefix->name; + do { + if (!poolAppendChar(&tempPool, *s)) + return XML_ERROR_NO_MEMORY; + } while (*s++); + } + + /* store expanded name in attribute list */ + s = poolStart(&tempPool); + poolFinish(&tempPool); + appAtts[i] = s; + + /* fill empty slot with new version, uriName and hash value */ + nsAtts[j].version = version; + nsAtts[j].hash = uriHash; + nsAtts[j].uriName = s; + + if (!--nPrefixes) { + i += 2; + break; + } + } + else /* not prefixed */ + ((XML_Char *)s)[-1] = 0; /* clear flag */ + } + } + /* clear flags for the remaining attributes */ + for (; i < attIndex; i += 2) + ((XML_Char *)(appAtts[i]))[-1] = 0; + for (binding = *bindingsPtr; binding; binding = binding->nextTagBinding) + binding->attId->name[-1] = 0; + + if (!ns) + return XML_ERROR_NONE; + + /* expand the element type name */ + if (elementType->prefix) { + binding = elementType->prefix->binding; + if (!binding) + return XML_ERROR_UNBOUND_PREFIX; + localPart = tagNamePtr->str; + while (*localPart++ != XML_T(':')) + ; + } + else if (dtd->defaultPrefix.binding) { + binding = dtd->defaultPrefix.binding; + localPart = tagNamePtr->str; + } + else + return XML_ERROR_NONE; + prefixLen = 0; + if (ns_triplets && binding->prefix->name) { + for (; binding->prefix->name[prefixLen++];) + ; /* prefixLen includes null terminator */ + } + tagNamePtr->localPart = localPart; + tagNamePtr->uriLen = binding->uriLen; + tagNamePtr->prefix = binding->prefix->name; + tagNamePtr->prefixLen = prefixLen; + for (i = 0; localPart[i++];) + ; /* i includes null terminator */ + n = i + binding->uriLen + prefixLen; + if (n > binding->uriAlloc) { + TAG *p; + uri = (XML_Char *)MALLOC((n + EXPAND_SPARE) * sizeof(XML_Char)); + if (!uri) + return XML_ERROR_NO_MEMORY; + binding->uriAlloc = n + EXPAND_SPARE; + memcpy(uri, binding->uri, binding->uriLen * sizeof(XML_Char)); + for (p = tagStack; p; p = p->parent) + if (p->name.str == binding->uri) + p->name.str = uri; + FREE(binding->uri); + binding->uri = uri; + } + /* if namespaceSeparator != '\0' then uri includes it already */ + uri = binding->uri + binding->uriLen; + memcpy(uri, localPart, i * sizeof(XML_Char)); + /* we always have a namespace separator between localPart and prefix */ + if (prefixLen) { + uri += i - 1; + *uri = namespaceSeparator; /* replace null terminator */ + memcpy(uri + 1, binding->prefix->name, prefixLen * sizeof(XML_Char)); + } + tagNamePtr->str = binding->uri; + return XML_ERROR_NONE; +} + +/* addBinding() overwrites the value of prefix->binding without checking. + Therefore one must keep track of the old value outside of addBinding(). +*/ +static enum XML_Error +addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId, + const XML_Char *uri, BINDING **bindingsPtr) +{ + static const XML_Char xmlNamespace[] = { + 'h', 't', 't', 'p', ':', '/', '/', + 'w', 'w', 'w', '.', 'w', '3', '.', 'o', 'r', 'g', '/', + 'X', 'M', 'L', '/', '1', '9', '9', '8', '/', + 'n', 'a', 'm', 'e', 's', 'p', 'a', 'c', 'e', '\0' + }; + static const int xmlLen = + (int)sizeof(xmlNamespace)/sizeof(XML_Char) - 1; + static const XML_Char xmlnsNamespace[] = { + 'h', 't', 't', 'p', ':', '/', '/', + 'w', 'w', 'w', '.', 'w', '3', '.', 'o', 'r', 'g', '/', + '2', '0', '0', '0', '/', 'x', 'm', 'l', 'n', 's', '/', '\0' + }; + static const int xmlnsLen = + (int)sizeof(xmlnsNamespace)/sizeof(XML_Char) - 1; + + XML_Bool mustBeXML = XML_FALSE; + XML_Bool isXML = XML_TRUE; + XML_Bool isXMLNS = XML_TRUE; + + BINDING *b; + int len; + + /* empty URI is only valid for default namespace per XML NS 1.0 (not 1.1) */ + if (*uri == XML_T('\0') && prefix->name) + return XML_ERROR_UNDECLARING_PREFIX; + + if (prefix->name + && prefix->name[0] == XML_T('x') + && prefix->name[1] == XML_T('m') + && prefix->name[2] == XML_T('l')) { + + /* Not allowed to bind xmlns */ + if (prefix->name[3] == XML_T('n') + && prefix->name[4] == XML_T('s') + && prefix->name[5] == XML_T('\0')) + return XML_ERROR_RESERVED_PREFIX_XMLNS; + + if (prefix->name[3] == XML_T('\0')) + mustBeXML = XML_TRUE; + } + + for (len = 0; uri[len]; len++) { + if (isXML && (len > xmlLen || uri[len] != xmlNamespace[len])) + isXML = XML_FALSE; + + if (!mustBeXML && isXMLNS + && (len > xmlnsLen || uri[len] != xmlnsNamespace[len])) + isXMLNS = XML_FALSE; + } + isXML = isXML && len == xmlLen; + isXMLNS = isXMLNS && len == xmlnsLen; + + if (mustBeXML != isXML) + return mustBeXML ? XML_ERROR_RESERVED_PREFIX_XML + : XML_ERROR_RESERVED_NAMESPACE_URI; + + if (isXMLNS) + return XML_ERROR_RESERVED_NAMESPACE_URI; + + if (namespaceSeparator) + len++; + if (freeBindingList) { + b = freeBindingList; + if (len > b->uriAlloc) { + XML_Char *temp = (XML_Char *)REALLOC(b->uri, + sizeof(XML_Char) * (len + EXPAND_SPARE)); + if (temp == NULL) + return XML_ERROR_NO_MEMORY; + b->uri = temp; + b->uriAlloc = len + EXPAND_SPARE; + } + freeBindingList = b->nextTagBinding; + } + else { + b = (BINDING *)MALLOC(sizeof(BINDING)); + if (!b) + return XML_ERROR_NO_MEMORY; + b->uri = (XML_Char *)MALLOC(sizeof(XML_Char) * (len + EXPAND_SPARE)); + if (!b->uri) { + FREE(b); + return XML_ERROR_NO_MEMORY; + } + b->uriAlloc = len + EXPAND_SPARE; + } + b->uriLen = len; + memcpy(b->uri, uri, len * sizeof(XML_Char)); + if (namespaceSeparator) + b->uri[len - 1] = namespaceSeparator; + b->prefix = prefix; + b->attId = attId; + b->prevPrefixBinding = prefix->binding; + /* NULL binding when default namespace undeclared */ + if (*uri == XML_T('\0') && prefix == &_dtd->defaultPrefix) + prefix->binding = NULL; + else + prefix->binding = b; + b->nextTagBinding = *bindingsPtr; + *bindingsPtr = b; + /* if attId == NULL then we are not starting a namespace scope */ + if (attId && startNamespaceDeclHandler) + startNamespaceDeclHandler(handlerArg, prefix->name, + prefix->binding ? uri : 0); + return XML_ERROR_NONE; +} + +/* The idea here is to avoid using stack for each CDATA section when + the whole file is parsed with one call. +*/ +static enum XML_Error PTRCALL +cdataSectionProcessor(XML_Parser parser, + const char *start, + const char *end, + const char **endPtr) +{ + enum XML_Error result = doCdataSection(parser, encoding, &start, end, + endPtr, (XML_Bool)!ps_finalBuffer); + if (result != XML_ERROR_NONE) + return result; + if (start) { + if (parentParser) { /* we are parsing an external entity */ + processor = externalEntityContentProcessor; + return externalEntityContentProcessor(parser, start, end, endPtr); + } + else { + processor = contentProcessor; + return contentProcessor(parser, start, end, endPtr); + } + } + return result; +} + +/* startPtr gets set to non-null if the section is closed, and to null if + the section is not yet closed. +*/ +static enum XML_Error +doCdataSection(XML_Parser parser, + const ENCODING *enc, + const char **startPtr, + const char *end, + const char **nextPtr, + XML_Bool haveMore) +{ + const char *s = *startPtr; + const char **eventPP; + const char **eventEndPP; + if (enc == encoding) { + eventPP = &eventPtr; + *eventPP = s; + eventEndPP = &eventEndPtr; + } + else { + eventPP = &(openInternalEntities->internalEventPtr); + eventEndPP = &(openInternalEntities->internalEventEndPtr); + } + *eventPP = s; + *startPtr = NULL; + + for (;;) { + const char *next; + int tok = XmlCdataSectionTok(enc, s, end, &next); + *eventEndPP = next; + switch (tok) { + case XML_TOK_CDATA_SECT_CLOSE: + if (endCdataSectionHandler) + endCdataSectionHandler(handlerArg); +#if 0 + /* see comment under XML_TOK_CDATA_SECT_OPEN */ + else if (characterDataHandler) + characterDataHandler(handlerArg, dataBuf, 0); +#endif + else if (defaultHandler) + reportDefault(parser, enc, s, next); + *startPtr = next; + *nextPtr = next; + if (ps_parsing == XML_FINISHED) + return XML_ERROR_ABORTED; + else + return XML_ERROR_NONE; + case XML_TOK_DATA_NEWLINE: + if (characterDataHandler) { + XML_Char c = 0xA; + characterDataHandler(handlerArg, &c, 1); + } + else if (defaultHandler) + reportDefault(parser, enc, s, next); + break; + case XML_TOK_DATA_CHARS: + if (characterDataHandler) { + if (MUST_CONVERT(enc, s)) { + for (;;) { + ICHAR *dataPtr = (ICHAR *)dataBuf; + XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)dataBufEnd); + *eventEndPP = next; + characterDataHandler(handlerArg, dataBuf, + (int)(dataPtr - (ICHAR *)dataBuf)); + if (s == next) + break; + *eventPP = s; + } + } + else + characterDataHandler(handlerArg, + (XML_Char *)s, + (int)((XML_Char *)next - (XML_Char *)s)); + } + else if (defaultHandler) + reportDefault(parser, enc, s, next); + break; + case XML_TOK_INVALID: + *eventPP = next; + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_PARTIAL_CHAR: + if (haveMore) { + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_PARTIAL_CHAR; + case XML_TOK_PARTIAL: + case XML_TOK_NONE: + if (haveMore) { + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_UNCLOSED_CDATA_SECTION; + default: + *eventPP = next; + return XML_ERROR_UNEXPECTED_STATE; + } + + *eventPP = s = next; + switch (ps_parsing) { + case XML_SUSPENDED: + *nextPtr = next; + return XML_ERROR_NONE; + case XML_FINISHED: + return XML_ERROR_ABORTED; + default: ; + } + } + /* not reached */ +} + +#ifdef XML_DTD + +/* The idea here is to avoid using stack for each IGNORE section when + the whole file is parsed with one call. +*/ +static enum XML_Error PTRCALL +ignoreSectionProcessor(XML_Parser parser, + const char *start, + const char *end, + const char **endPtr) +{ + enum XML_Error result = doIgnoreSection(parser, encoding, &start, end, + endPtr, (XML_Bool)!ps_finalBuffer); + if (result != XML_ERROR_NONE) + return result; + if (start) { + processor = prologProcessor; + return prologProcessor(parser, start, end, endPtr); + } + return result; +} + +/* startPtr gets set to non-null is the section is closed, and to null + if the section is not yet closed. +*/ +static enum XML_Error +doIgnoreSection(XML_Parser parser, + const ENCODING *enc, + const char **startPtr, + const char *end, + const char **nextPtr, + XML_Bool haveMore) +{ + const char *next; + int tok; + const char *s = *startPtr; + const char **eventPP; + const char **eventEndPP; + if (enc == encoding) { + eventPP = &eventPtr; + *eventPP = s; + eventEndPP = &eventEndPtr; + } + else { + eventPP = &(openInternalEntities->internalEventPtr); + eventEndPP = &(openInternalEntities->internalEventEndPtr); + } + *eventPP = s; + *startPtr = NULL; + tok = XmlIgnoreSectionTok(enc, s, end, &next); + *eventEndPP = next; + switch (tok) { + case XML_TOK_IGNORE_SECT: + if (defaultHandler) + reportDefault(parser, enc, s, next); + *startPtr = next; + *nextPtr = next; + if (ps_parsing == XML_FINISHED) + return XML_ERROR_ABORTED; + else + return XML_ERROR_NONE; + case XML_TOK_INVALID: + *eventPP = next; + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_PARTIAL_CHAR: + if (haveMore) { + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_PARTIAL_CHAR; + case XML_TOK_PARTIAL: + case XML_TOK_NONE: + if (haveMore) { + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_SYNTAX; /* XML_ERROR_UNCLOSED_IGNORE_SECTION */ + default: + *eventPP = next; + return XML_ERROR_UNEXPECTED_STATE; + } + /* not reached */ +} + +#endif /* XML_DTD */ + +static enum XML_Error +initializeEncoding(XML_Parser parser) +{ + const char *s; +#ifdef XML_UNICODE + char encodingBuf[128]; + if (!protocolEncodingName) + s = NULL; + else { + int i; + for (i = 0; protocolEncodingName[i]; i++) { + if (i == sizeof(encodingBuf) - 1 + || (protocolEncodingName[i] & ~0x7f) != 0) { + encodingBuf[0] = '\0'; + break; + } + encodingBuf[i] = (char)protocolEncodingName[i]; + } + encodingBuf[i] = '\0'; + s = encodingBuf; + } +#else + s = protocolEncodingName; +#endif + if ((ns ? XmlInitEncodingNS : XmlInitEncoding)(&initEncoding, &encoding, s)) + return XML_ERROR_NONE; + return handleUnknownEncoding(parser, protocolEncodingName); +} + +static enum XML_Error +processXmlDecl(XML_Parser parser, int isGeneralTextEntity, + const char *s, const char *next) +{ + const char *encodingName = NULL; + const XML_Char *storedEncName = NULL; + const ENCODING *newEncoding = NULL; + const char *version = NULL; + const char *versionend; + const XML_Char *storedversion = NULL; + int standalone = -1; + if (!(ns + ? XmlParseXmlDeclNS + : XmlParseXmlDecl)(isGeneralTextEntity, + encoding, + s, + next, + &eventPtr, + &version, + &versionend, + &encodingName, + &newEncoding, + &standalone)) { + if (isGeneralTextEntity) + return XML_ERROR_TEXT_DECL; + else + return XML_ERROR_XML_DECL; + } + if (!isGeneralTextEntity && standalone == 1) { + _dtd->standalone = XML_TRUE; +#ifdef XML_DTD + if (paramEntityParsing == XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE) + paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER; +#endif /* XML_DTD */ + } + if (xmlDeclHandler) { + if (encodingName != NULL) { + storedEncName = poolStoreString(&temp2Pool, + encoding, + encodingName, + encodingName + + XmlNameLength(encoding, encodingName)); + if (!storedEncName) + return XML_ERROR_NO_MEMORY; + poolFinish(&temp2Pool); + } + if (version) { + storedversion = poolStoreString(&temp2Pool, + encoding, + version, + versionend - encoding->minBytesPerChar); + if (!storedversion) + return XML_ERROR_NO_MEMORY; + } + xmlDeclHandler(handlerArg, storedversion, storedEncName, standalone); + } + else if (defaultHandler) + reportDefault(parser, encoding, s, next); + if (protocolEncodingName == NULL) { + if (newEncoding) { + if (newEncoding->minBytesPerChar != encoding->minBytesPerChar) { + eventPtr = encodingName; + return XML_ERROR_INCORRECT_ENCODING; + } + encoding = newEncoding; + } + else if (encodingName) { + enum XML_Error result; + if (!storedEncName) { + storedEncName = poolStoreString( + &temp2Pool, encoding, encodingName, + encodingName + XmlNameLength(encoding, encodingName)); + if (!storedEncName) + return XML_ERROR_NO_MEMORY; + } + result = handleUnknownEncoding(parser, storedEncName); + poolClear(&temp2Pool); + if (result == XML_ERROR_UNKNOWN_ENCODING) + eventPtr = encodingName; + return result; + } + } + + if (storedEncName || storedversion) + poolClear(&temp2Pool); + + return XML_ERROR_NONE; +} + +static enum XML_Error +handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName) +{ + if (unknownEncodingHandler) { + XML_Encoding info; + int i; + for (i = 0; i < 256; i++) + info.map[i] = -1; + info.convert = NULL; + info.data = NULL; + info.release = NULL; + if (unknownEncodingHandler(unknownEncodingHandlerData, encodingName, + &info)) { + ENCODING *enc; + unknownEncodingMem = MALLOC(XmlSizeOfUnknownEncoding()); + if (!unknownEncodingMem) { + if (info.release) + info.release(info.data); + return XML_ERROR_NO_MEMORY; + } + enc = (ns + ? XmlInitUnknownEncodingNS + : XmlInitUnknownEncoding)(unknownEncodingMem, + info.map, + info.convert, + info.data); + if (enc) { + unknownEncodingData = info.data; + unknownEncodingRelease = info.release; + encoding = enc; + return XML_ERROR_NONE; + } + } + if (info.release != NULL) + info.release(info.data); + } + return XML_ERROR_UNKNOWN_ENCODING; +} + +static enum XML_Error PTRCALL +prologInitProcessor(XML_Parser parser, + const char *s, + const char *end, + const char **nextPtr) +{ + enum XML_Error result = initializeEncoding(parser); + if (result != XML_ERROR_NONE) + return result; + processor = prologProcessor; + return prologProcessor(parser, s, end, nextPtr); +} + +#ifdef XML_DTD + +static enum XML_Error PTRCALL +externalParEntInitProcessor(XML_Parser parser, + const char *s, + const char *end, + const char **nextPtr) +{ + enum XML_Error result = initializeEncoding(parser); + if (result != XML_ERROR_NONE) + return result; + + /* we know now that XML_Parse(Buffer) has been called, + so we consider the external parameter entity read */ + _dtd->paramEntityRead = XML_TRUE; + + if (prologState.inEntityValue) { + processor = entityValueInitProcessor; + return entityValueInitProcessor(parser, s, end, nextPtr); + } + else { + processor = externalParEntProcessor; + return externalParEntProcessor(parser, s, end, nextPtr); + } +} + +static enum XML_Error PTRCALL +entityValueInitProcessor(XML_Parser parser, + const char *s, + const char *end, + const char **nextPtr) +{ + int tok; + const char *start = s; + const char *next = start; + eventPtr = start; + + for (;;) { + tok = XmlPrologTok(encoding, start, end, &next); + eventEndPtr = next; + if (tok <= 0) { + if (!ps_finalBuffer && tok != XML_TOK_INVALID) { + *nextPtr = s; + return XML_ERROR_NONE; + } + switch (tok) { + case XML_TOK_INVALID: + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_PARTIAL: + return XML_ERROR_UNCLOSED_TOKEN; + case XML_TOK_PARTIAL_CHAR: + return XML_ERROR_PARTIAL_CHAR; + case XML_TOK_NONE: /* start == end */ + default: + break; + } + /* found end of entity value - can store it now */ + return storeEntityValue(parser, encoding, s, end); + } + else if (tok == XML_TOK_XML_DECL) { + enum XML_Error result; + result = processXmlDecl(parser, 0, start, next); + if (result != XML_ERROR_NONE) + return result; + switch (ps_parsing) { + case XML_SUSPENDED: + *nextPtr = next; + return XML_ERROR_NONE; + case XML_FINISHED: + return XML_ERROR_ABORTED; + default: + *nextPtr = next; + } + /* stop scanning for text declaration - we found one */ + processor = entityValueProcessor; + return entityValueProcessor(parser, next, end, nextPtr); + } + /* If we are at the end of the buffer, this would cause XmlPrologTok to + return XML_TOK_NONE on the next call, which would then cause the + function to exit with *nextPtr set to s - that is what we want for other + tokens, but not for the BOM - we would rather like to skip it; + then, when this routine is entered the next time, XmlPrologTok will + return XML_TOK_INVALID, since the BOM is still in the buffer + */ + else if (tok == XML_TOK_BOM && next == end && !ps_finalBuffer) { + *nextPtr = next; + return XML_ERROR_NONE; + } + start = next; + eventPtr = start; + } +} + +static enum XML_Error PTRCALL +externalParEntProcessor(XML_Parser parser, + const char *s, + const char *end, + const char **nextPtr) +{ + const char *next = s; + int tok; + + tok = XmlPrologTok(encoding, s, end, &next); + if (tok <= 0) { + if (!ps_finalBuffer && tok != XML_TOK_INVALID) { + *nextPtr = s; + return XML_ERROR_NONE; + } + switch (tok) { + case XML_TOK_INVALID: + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_PARTIAL: + return XML_ERROR_UNCLOSED_TOKEN; + case XML_TOK_PARTIAL_CHAR: + return XML_ERROR_PARTIAL_CHAR; + case XML_TOK_NONE: /* start == end */ + default: + break; + } + } + /* This would cause the next stage, i.e. doProlog to be passed XML_TOK_BOM. + However, when parsing an external subset, doProlog will not accept a BOM + as valid, and report a syntax error, so we have to skip the BOM + */ + else if (tok == XML_TOK_BOM) { + s = next; + tok = XmlPrologTok(encoding, s, end, &next); + } + + processor = prologProcessor; + return doProlog(parser, encoding, s, end, tok, next, + nextPtr, (XML_Bool)!ps_finalBuffer); +} + +static enum XML_Error PTRCALL +entityValueProcessor(XML_Parser parser, + const char *s, + const char *end, + const char **nextPtr) +{ + const char *start = s; + const char *next = s; + const ENCODING *enc = encoding; + int tok; + + for (;;) { + tok = XmlPrologTok(enc, start, end, &next); + if (tok <= 0) { + if (!ps_finalBuffer && tok != XML_TOK_INVALID) { + *nextPtr = s; + return XML_ERROR_NONE; + } + switch (tok) { + case XML_TOK_INVALID: + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_PARTIAL: + return XML_ERROR_UNCLOSED_TOKEN; + case XML_TOK_PARTIAL_CHAR: + return XML_ERROR_PARTIAL_CHAR; + case XML_TOK_NONE: /* start == end */ + default: + break; + } + /* found end of entity value - can store it now */ + return storeEntityValue(parser, enc, s, end); + } + start = next; + } +} + +#endif /* XML_DTD */ + +static enum XML_Error PTRCALL +prologProcessor(XML_Parser parser, + const char *s, + const char *end, + const char **nextPtr) +{ + const char *next = s; + int tok = XmlPrologTok(encoding, s, end, &next); + return doProlog(parser, encoding, s, end, tok, next, + nextPtr, (XML_Bool)!ps_finalBuffer); +} + +static enum XML_Error +doProlog(XML_Parser parser, + const ENCODING *enc, + const char *s, + const char *end, + int tok, + const char *next, + const char **nextPtr, + XML_Bool haveMore) +{ +#ifdef XML_DTD + static const XML_Char externalSubsetName[] = { '#' , '\0' }; +#endif /* XML_DTD */ + static const XML_Char atypeCDATA[] = { 'C', 'D', 'A', 'T', 'A', '\0' }; + static const XML_Char atypeID[] = { 'I', 'D', '\0' }; + static const XML_Char atypeIDREF[] = { 'I', 'D', 'R', 'E', 'F', '\0' }; + static const XML_Char atypeIDREFS[] = { 'I', 'D', 'R', 'E', 'F', 'S', '\0' }; + static const XML_Char atypeENTITY[] = { 'E', 'N', 'T', 'I', 'T', 'Y', '\0' }; + static const XML_Char atypeENTITIES[] = + { 'E', 'N', 'T', 'I', 'T', 'I', 'E', 'S', '\0' }; + static const XML_Char atypeNMTOKEN[] = { + 'N', 'M', 'T', 'O', 'K', 'E', 'N', '\0' }; + static const XML_Char atypeNMTOKENS[] = { + 'N', 'M', 'T', 'O', 'K', 'E', 'N', 'S', '\0' }; + static const XML_Char notationPrefix[] = { + 'N', 'O', 'T', 'A', 'T', 'I', 'O', 'N', '(', '\0' }; + static const XML_Char enumValueSep[] = { '|', '\0' }; + static const XML_Char enumValueStart[] = { '(', '\0' }; + + /* save one level of indirection */ + DTD * const dtd = _dtd; + + const char **eventPP; + const char **eventEndPP; + enum XML_Content_Quant quant; + + if (enc == encoding) { + eventPP = &eventPtr; + eventEndPP = &eventEndPtr; + } + else { + eventPP = &(openInternalEntities->internalEventPtr); + eventEndPP = &(openInternalEntities->internalEventEndPtr); + } + + for (;;) { + int role; + XML_Bool handleDefault = XML_TRUE; + *eventPP = s; + *eventEndPP = next; + if (tok <= 0) { + if (haveMore && tok != XML_TOK_INVALID) { + *nextPtr = s; + return XML_ERROR_NONE; + } + switch (tok) { + case XML_TOK_INVALID: + *eventPP = next; + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_PARTIAL: + return XML_ERROR_UNCLOSED_TOKEN; + case XML_TOK_PARTIAL_CHAR: + return XML_ERROR_PARTIAL_CHAR; + case XML_TOK_NONE: +#ifdef XML_DTD + /* for internal PE NOT referenced between declarations */ + if (enc != encoding && !openInternalEntities->betweenDecl) { + *nextPtr = s; + return XML_ERROR_NONE; + } + /* WFC: PE Between Declarations - must check that PE contains + complete markup, not only for external PEs, but also for + internal PEs if the reference occurs between declarations. + */ + if (isParamEntity || enc != encoding) { + if (XmlTokenRole(&prologState, XML_TOK_NONE, end, end, enc) + == XML_ROLE_ERROR) + return XML_ERROR_INCOMPLETE_PE; + *nextPtr = s; + return XML_ERROR_NONE; + } +#endif /* XML_DTD */ + return XML_ERROR_NO_ELEMENTS; + default: + tok = -tok; + next = end; + break; + } + } + role = XmlTokenRole(&prologState, tok, s, next, enc); + switch (role) { + case XML_ROLE_XML_DECL: + { + enum XML_Error result = processXmlDecl(parser, 0, s, next); + if (result != XML_ERROR_NONE) + return result; + enc = encoding; + handleDefault = XML_FALSE; + } + break; + case XML_ROLE_DOCTYPE_NAME: + if (startDoctypeDeclHandler) { + doctypeName = poolStoreString(&tempPool, enc, s, next); + if (!doctypeName) + return XML_ERROR_NO_MEMORY; + poolFinish(&tempPool); + doctypePubid = NULL; + handleDefault = XML_FALSE; + } + doctypeSysid = NULL; /* always initialize to NULL */ + break; + case XML_ROLE_DOCTYPE_INTERNAL_SUBSET: + if (startDoctypeDeclHandler) { + startDoctypeDeclHandler(handlerArg, doctypeName, doctypeSysid, + doctypePubid, 1); + doctypeName = NULL; + poolClear(&tempPool); + handleDefault = XML_FALSE; + } + break; +#ifdef XML_DTD + case XML_ROLE_TEXT_DECL: + { + enum XML_Error result = processXmlDecl(parser, 1, s, next); + if (result != XML_ERROR_NONE) + return result; + enc = encoding; + handleDefault = XML_FALSE; + } + break; +#endif /* XML_DTD */ + case XML_ROLE_DOCTYPE_PUBLIC_ID: +#ifdef XML_DTD + useForeignDTD = XML_FALSE; + declEntity = (ENTITY *)lookup(&dtd->paramEntities, + externalSubsetName, + sizeof(ENTITY)); + if (!declEntity) + return XML_ERROR_NO_MEMORY; +#endif /* XML_DTD */ + dtd->hasParamEntityRefs = XML_TRUE; + if (startDoctypeDeclHandler) { + if (!XmlIsPublicId(enc, s, next, eventPP)) + return XML_ERROR_PUBLICID; + doctypePubid = poolStoreString(&tempPool, enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (!doctypePubid) + return XML_ERROR_NO_MEMORY; + normalizePublicId((XML_Char *)doctypePubid); + poolFinish(&tempPool); + handleDefault = XML_FALSE; + goto alreadyChecked; + } + /* fall through */ + case XML_ROLE_ENTITY_PUBLIC_ID: + if (!XmlIsPublicId(enc, s, next, eventPP)) + return XML_ERROR_PUBLICID; + alreadyChecked: + if (dtd->keepProcessing && declEntity) { + XML_Char *tem = poolStoreString(&dtd->pool, + enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (!tem) + return XML_ERROR_NO_MEMORY; + normalizePublicId(tem); + declEntity->publicId = tem; + poolFinish(&dtd->pool); + if (entityDeclHandler) + handleDefault = XML_FALSE; + } + break; + case XML_ROLE_DOCTYPE_CLOSE: + if (doctypeName) { + startDoctypeDeclHandler(handlerArg, doctypeName, + doctypeSysid, doctypePubid, 0); + poolClear(&tempPool); + handleDefault = XML_FALSE; + } + /* doctypeSysid will be non-NULL in the case of a previous + XML_ROLE_DOCTYPE_SYSTEM_ID, even if startDoctypeDeclHandler + was not set, indicating an external subset + */ +#ifdef XML_DTD + if (doctypeSysid || useForeignDTD) { + XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs; + dtd->hasParamEntityRefs = XML_TRUE; + if (paramEntityParsing && externalEntityRefHandler) { + ENTITY *entity = (ENTITY *)lookup(&dtd->paramEntities, + externalSubsetName, + sizeof(ENTITY)); + if (!entity) + return XML_ERROR_NO_MEMORY; + if (useForeignDTD) + entity->base = curBase; + dtd->paramEntityRead = XML_FALSE; + if (!externalEntityRefHandler(externalEntityRefHandlerArg, + 0, + entity->base, + entity->systemId, + entity->publicId)) + return XML_ERROR_EXTERNAL_ENTITY_HANDLING; + if (dtd->paramEntityRead) { + if (!dtd->standalone && + notStandaloneHandler && + !notStandaloneHandler(handlerArg)) + return XML_ERROR_NOT_STANDALONE; + } + /* if we didn't read the foreign DTD then this means that there + is no external subset and we must reset dtd->hasParamEntityRefs + */ + else if (!doctypeSysid) + dtd->hasParamEntityRefs = hadParamEntityRefs; + /* end of DTD - no need to update dtd->keepProcessing */ + } + useForeignDTD = XML_FALSE; + } +#endif /* XML_DTD */ + if (endDoctypeDeclHandler) { + endDoctypeDeclHandler(handlerArg); + handleDefault = XML_FALSE; + } + break; + case XML_ROLE_INSTANCE_START: +#ifdef XML_DTD + /* if there is no DOCTYPE declaration then now is the + last chance to read the foreign DTD + */ + if (useForeignDTD) { + XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs; + dtd->hasParamEntityRefs = XML_TRUE; + if (paramEntityParsing && externalEntityRefHandler) { + ENTITY *entity = (ENTITY *)lookup(&dtd->paramEntities, + externalSubsetName, + sizeof(ENTITY)); + if (!entity) + return XML_ERROR_NO_MEMORY; + entity->base = curBase; + dtd->paramEntityRead = XML_FALSE; + if (!externalEntityRefHandler(externalEntityRefHandlerArg, + 0, + entity->base, + entity->systemId, + entity->publicId)) + return XML_ERROR_EXTERNAL_ENTITY_HANDLING; + if (dtd->paramEntityRead) { + if (!dtd->standalone && + notStandaloneHandler && + !notStandaloneHandler(handlerArg)) + return XML_ERROR_NOT_STANDALONE; + } + /* if we didn't read the foreign DTD then this means that there + is no external subset and we must reset dtd->hasParamEntityRefs + */ + else + dtd->hasParamEntityRefs = hadParamEntityRefs; + /* end of DTD - no need to update dtd->keepProcessing */ + } + } +#endif /* XML_DTD */ + processor = contentProcessor; + return contentProcessor(parser, s, end, nextPtr); + case XML_ROLE_ATTLIST_ELEMENT_NAME: + declElementType = getElementType(parser, enc, s, next); + if (!declElementType) + return XML_ERROR_NO_MEMORY; + goto checkAttListDeclHandler; + case XML_ROLE_ATTRIBUTE_NAME: + declAttributeId = getAttributeId(parser, enc, s, next); + if (!declAttributeId) + return XML_ERROR_NO_MEMORY; + declAttributeIsCdata = XML_FALSE; + declAttributeType = NULL; + declAttributeIsId = XML_FALSE; + goto checkAttListDeclHandler; + case XML_ROLE_ATTRIBUTE_TYPE_CDATA: + declAttributeIsCdata = XML_TRUE; + declAttributeType = atypeCDATA; + goto checkAttListDeclHandler; + case XML_ROLE_ATTRIBUTE_TYPE_ID: + declAttributeIsId = XML_TRUE; + declAttributeType = atypeID; + goto checkAttListDeclHandler; + case XML_ROLE_ATTRIBUTE_TYPE_IDREF: + declAttributeType = atypeIDREF; + goto checkAttListDeclHandler; + case XML_ROLE_ATTRIBUTE_TYPE_IDREFS: + declAttributeType = atypeIDREFS; + goto checkAttListDeclHandler; + case XML_ROLE_ATTRIBUTE_TYPE_ENTITY: + declAttributeType = atypeENTITY; + goto checkAttListDeclHandler; + case XML_ROLE_ATTRIBUTE_TYPE_ENTITIES: + declAttributeType = atypeENTITIES; + goto checkAttListDeclHandler; + case XML_ROLE_ATTRIBUTE_TYPE_NMTOKEN: + declAttributeType = atypeNMTOKEN; + goto checkAttListDeclHandler; + case XML_ROLE_ATTRIBUTE_TYPE_NMTOKENS: + declAttributeType = atypeNMTOKENS; + checkAttListDeclHandler: + if (dtd->keepProcessing && attlistDeclHandler) + handleDefault = XML_FALSE; + break; + case XML_ROLE_ATTRIBUTE_ENUM_VALUE: + case XML_ROLE_ATTRIBUTE_NOTATION_VALUE: + if (dtd->keepProcessing && attlistDeclHandler) { + const XML_Char *prefix; + if (declAttributeType) { + prefix = enumValueSep; + } + else { + prefix = (role == XML_ROLE_ATTRIBUTE_NOTATION_VALUE + ? notationPrefix + : enumValueStart); + } + if (!poolAppendString(&tempPool, prefix)) + return XML_ERROR_NO_MEMORY; + if (!poolAppend(&tempPool, enc, s, next)) + return XML_ERROR_NO_MEMORY; + declAttributeType = tempPool.start; + handleDefault = XML_FALSE; + } + break; + case XML_ROLE_IMPLIED_ATTRIBUTE_VALUE: + case XML_ROLE_REQUIRED_ATTRIBUTE_VALUE: + if (dtd->keepProcessing) { + if (!defineAttribute(declElementType, declAttributeId, + declAttributeIsCdata, declAttributeIsId, + 0, parser)) + return XML_ERROR_NO_MEMORY; + if (attlistDeclHandler && declAttributeType) { + if (*declAttributeType == XML_T('(') + || (*declAttributeType == XML_T('N') + && declAttributeType[1] == XML_T('O'))) { + /* Enumerated or Notation type */ + if (!poolAppendChar(&tempPool, XML_T(')')) + || !poolAppendChar(&tempPool, XML_T('\0'))) + return XML_ERROR_NO_MEMORY; + declAttributeType = tempPool.start; + poolFinish(&tempPool); + } + *eventEndPP = s; + attlistDeclHandler(handlerArg, declElementType->name, + declAttributeId->name, declAttributeType, + 0, role == XML_ROLE_REQUIRED_ATTRIBUTE_VALUE); + poolClear(&tempPool); + handleDefault = XML_FALSE; + } + } + break; + case XML_ROLE_DEFAULT_ATTRIBUTE_VALUE: + case XML_ROLE_FIXED_ATTRIBUTE_VALUE: + if (dtd->keepProcessing) { + const XML_Char *attVal; + enum XML_Error result = + storeAttributeValue(parser, enc, declAttributeIsCdata, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar, + &dtd->pool); + if (result) + return result; + attVal = poolStart(&dtd->pool); + poolFinish(&dtd->pool); + /* ID attributes aren't allowed to have a default */ + if (!defineAttribute(declElementType, declAttributeId, + declAttributeIsCdata, XML_FALSE, attVal, parser)) + return XML_ERROR_NO_MEMORY; + if (attlistDeclHandler && declAttributeType) { + if (*declAttributeType == XML_T('(') + || (*declAttributeType == XML_T('N') + && declAttributeType[1] == XML_T('O'))) { + /* Enumerated or Notation type */ + if (!poolAppendChar(&tempPool, XML_T(')')) + || !poolAppendChar(&tempPool, XML_T('\0'))) + return XML_ERROR_NO_MEMORY; + declAttributeType = tempPool.start; + poolFinish(&tempPool); + } + *eventEndPP = s; + attlistDeclHandler(handlerArg, declElementType->name, + declAttributeId->name, declAttributeType, + attVal, + role == XML_ROLE_FIXED_ATTRIBUTE_VALUE); + poolClear(&tempPool); + handleDefault = XML_FALSE; + } + } + break; + case XML_ROLE_ENTITY_VALUE: + if (dtd->keepProcessing) { + enum XML_Error result = storeEntityValue(parser, enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (declEntity) { + declEntity->textPtr = poolStart(&dtd->entityValuePool); + declEntity->textLen = (int)(poolLength(&dtd->entityValuePool)); + poolFinish(&dtd->entityValuePool); + if (entityDeclHandler) { + *eventEndPP = s; + entityDeclHandler(handlerArg, + declEntity->name, + declEntity->is_param, + declEntity->textPtr, + declEntity->textLen, + curBase, 0, 0, 0); + handleDefault = XML_FALSE; + } + } + else + poolDiscard(&dtd->entityValuePool); + if (result != XML_ERROR_NONE) + return result; + } + break; + case XML_ROLE_DOCTYPE_SYSTEM_ID: +#ifdef XML_DTD + useForeignDTD = XML_FALSE; +#endif /* XML_DTD */ + dtd->hasParamEntityRefs = XML_TRUE; + if (startDoctypeDeclHandler) { + doctypeSysid = poolStoreString(&tempPool, enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (doctypeSysid == NULL) + return XML_ERROR_NO_MEMORY; + poolFinish(&tempPool); + handleDefault = XML_FALSE; + } +#ifdef XML_DTD + else + /* use externalSubsetName to make doctypeSysid non-NULL + for the case where no startDoctypeDeclHandler is set */ + doctypeSysid = externalSubsetName; +#endif /* XML_DTD */ + if (!dtd->standalone +#ifdef XML_DTD + && !paramEntityParsing +#endif /* XML_DTD */ + && notStandaloneHandler + && !notStandaloneHandler(handlerArg)) + return XML_ERROR_NOT_STANDALONE; +#ifndef XML_DTD + break; +#else /* XML_DTD */ + if (!declEntity) { + declEntity = (ENTITY *)lookup(&dtd->paramEntities, + externalSubsetName, + sizeof(ENTITY)); + if (!declEntity) + return XML_ERROR_NO_MEMORY; + declEntity->publicId = NULL; + } + /* fall through */ +#endif /* XML_DTD */ + case XML_ROLE_ENTITY_SYSTEM_ID: + if (dtd->keepProcessing && declEntity) { + declEntity->systemId = poolStoreString(&dtd->pool, enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (!declEntity->systemId) + return XML_ERROR_NO_MEMORY; + declEntity->base = curBase; + poolFinish(&dtd->pool); + if (entityDeclHandler) + handleDefault = XML_FALSE; + } + break; + case XML_ROLE_ENTITY_COMPLETE: + if (dtd->keepProcessing && declEntity && entityDeclHandler) { + *eventEndPP = s; + entityDeclHandler(handlerArg, + declEntity->name, + declEntity->is_param, + 0,0, + declEntity->base, + declEntity->systemId, + declEntity->publicId, + 0); + handleDefault = XML_FALSE; + } + break; + case XML_ROLE_ENTITY_NOTATION_NAME: + if (dtd->keepProcessing && declEntity) { + declEntity->notation = poolStoreString(&dtd->pool, enc, s, next); + if (!declEntity->notation) + return XML_ERROR_NO_MEMORY; + poolFinish(&dtd->pool); + if (unparsedEntityDeclHandler) { + *eventEndPP = s; + unparsedEntityDeclHandler(handlerArg, + declEntity->name, + declEntity->base, + declEntity->systemId, + declEntity->publicId, + declEntity->notation); + handleDefault = XML_FALSE; + } + else if (entityDeclHandler) { + *eventEndPP = s; + entityDeclHandler(handlerArg, + declEntity->name, + 0,0,0, + declEntity->base, + declEntity->systemId, + declEntity->publicId, + declEntity->notation); + handleDefault = XML_FALSE; + } + } + break; + case XML_ROLE_GENERAL_ENTITY_NAME: + { + if (XmlPredefinedEntityName(enc, s, next)) { + declEntity = NULL; + break; + } + if (dtd->keepProcessing) { + const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next); + if (!name) + return XML_ERROR_NO_MEMORY; + declEntity = (ENTITY *)lookup(&dtd->generalEntities, name, + sizeof(ENTITY)); + if (!declEntity) + return XML_ERROR_NO_MEMORY; + if (declEntity->name != name) { + poolDiscard(&dtd->pool); + declEntity = NULL; + } + else { + poolFinish(&dtd->pool); + declEntity->publicId = NULL; + declEntity->is_param = XML_FALSE; + /* if we have a parent parser or are reading an internal parameter + entity, then the entity declaration is not considered "internal" + */ + declEntity->is_internal = !(parentParser || openInternalEntities); + if (entityDeclHandler) + handleDefault = XML_FALSE; + } + } + else { + poolDiscard(&dtd->pool); + declEntity = NULL; + } + } + break; + case XML_ROLE_PARAM_ENTITY_NAME: +#ifdef XML_DTD + if (dtd->keepProcessing) { + const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next); + if (!name) + return XML_ERROR_NO_MEMORY; + declEntity = (ENTITY *)lookup(&dtd->paramEntities, + name, sizeof(ENTITY)); + if (!declEntity) + return XML_ERROR_NO_MEMORY; + if (declEntity->name != name) { + poolDiscard(&dtd->pool); + declEntity = NULL; + } + else { + poolFinish(&dtd->pool); + declEntity->publicId = NULL; + declEntity->is_param = XML_TRUE; + /* if we have a parent parser or are reading an internal parameter + entity, then the entity declaration is not considered "internal" + */ + declEntity->is_internal = !(parentParser || openInternalEntities); + if (entityDeclHandler) + handleDefault = XML_FALSE; + } + } + else { + poolDiscard(&dtd->pool); + declEntity = NULL; + } +#else /* not XML_DTD */ + declEntity = NULL; +#endif /* XML_DTD */ + break; + case XML_ROLE_NOTATION_NAME: + declNotationPublicId = NULL; + declNotationName = NULL; + if (notationDeclHandler) { + declNotationName = poolStoreString(&tempPool, enc, s, next); + if (!declNotationName) + return XML_ERROR_NO_MEMORY; + poolFinish(&tempPool); + handleDefault = XML_FALSE; + } + break; + case XML_ROLE_NOTATION_PUBLIC_ID: + if (!XmlIsPublicId(enc, s, next, eventPP)) + return XML_ERROR_PUBLICID; + if (declNotationName) { /* means notationDeclHandler != NULL */ + XML_Char *tem = poolStoreString(&tempPool, + enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (!tem) + return XML_ERROR_NO_MEMORY; + normalizePublicId(tem); + declNotationPublicId = tem; + poolFinish(&tempPool); + handleDefault = XML_FALSE; + } + break; + case XML_ROLE_NOTATION_SYSTEM_ID: + if (declNotationName && notationDeclHandler) { + const XML_Char *systemId + = poolStoreString(&tempPool, enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (!systemId) + return XML_ERROR_NO_MEMORY; + *eventEndPP = s; + notationDeclHandler(handlerArg, + declNotationName, + curBase, + systemId, + declNotationPublicId); + handleDefault = XML_FALSE; + } + poolClear(&tempPool); + break; + case XML_ROLE_NOTATION_NO_SYSTEM_ID: + if (declNotationPublicId && notationDeclHandler) { + *eventEndPP = s; + notationDeclHandler(handlerArg, + declNotationName, + curBase, + 0, + declNotationPublicId); + handleDefault = XML_FALSE; + } + poolClear(&tempPool); + break; + case XML_ROLE_ERROR: + switch (tok) { + case XML_TOK_PARAM_ENTITY_REF: + /* PE references in internal subset are + not allowed within declarations. */ + return XML_ERROR_PARAM_ENTITY_REF; + case XML_TOK_XML_DECL: + return XML_ERROR_MISPLACED_XML_PI; + default: + return XML_ERROR_SYNTAX; + } +#ifdef XML_DTD + case XML_ROLE_IGNORE_SECT: + { + enum XML_Error result; + if (defaultHandler) + reportDefault(parser, enc, s, next); + handleDefault = XML_FALSE; + result = doIgnoreSection(parser, enc, &next, end, nextPtr, haveMore); + if (result != XML_ERROR_NONE) + return result; + else if (!next) { + processor = ignoreSectionProcessor; + return result; + } + } + break; +#endif /* XML_DTD */ + case XML_ROLE_GROUP_OPEN: + if (prologState.level >= groupSize) { + if (groupSize) { + char *temp = (char *)REALLOC(groupConnector, groupSize *= 2); + if (temp == NULL) + return XML_ERROR_NO_MEMORY; + groupConnector = temp; + if (dtd->scaffIndex) { + int *temp = (int *)REALLOC(dtd->scaffIndex, + groupSize * sizeof(int)); + if (temp == NULL) + return XML_ERROR_NO_MEMORY; + dtd->scaffIndex = temp; + } + } + else { + groupConnector = (char *)MALLOC(groupSize = 32); + if (!groupConnector) + return XML_ERROR_NO_MEMORY; + } + } + groupConnector[prologState.level] = 0; + if (dtd->in_eldecl) { + int myindex = nextScaffoldPart(parser); + if (myindex < 0) + return XML_ERROR_NO_MEMORY; + dtd->scaffIndex[dtd->scaffLevel] = myindex; + dtd->scaffLevel++; + dtd->scaffold[myindex].type = XML_CTYPE_SEQ; + if (elementDeclHandler) + handleDefault = XML_FALSE; + } + break; + case XML_ROLE_GROUP_SEQUENCE: + if (groupConnector[prologState.level] == '|') + return XML_ERROR_SYNTAX; + groupConnector[prologState.level] = ','; + if (dtd->in_eldecl && elementDeclHandler) + handleDefault = XML_FALSE; + break; + case XML_ROLE_GROUP_CHOICE: + if (groupConnector[prologState.level] == ',') + return XML_ERROR_SYNTAX; + if (dtd->in_eldecl + && !groupConnector[prologState.level] + && (dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]].type + != XML_CTYPE_MIXED) + ) { + dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]].type + = XML_CTYPE_CHOICE; + if (elementDeclHandler) + handleDefault = XML_FALSE; + } + groupConnector[prologState.level] = '|'; + break; + case XML_ROLE_PARAM_ENTITY_REF: +#ifdef XML_DTD + case XML_ROLE_INNER_PARAM_ENTITY_REF: + dtd->hasParamEntityRefs = XML_TRUE; + if (!paramEntityParsing) + dtd->keepProcessing = dtd->standalone; + else { + const XML_Char *name; + ENTITY *entity; + name = poolStoreString(&dtd->pool, enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (!name) + return XML_ERROR_NO_MEMORY; + entity = (ENTITY *)lookup(&dtd->paramEntities, name, 0); + poolDiscard(&dtd->pool); + /* first, determine if a check for an existing declaration is needed; + if yes, check that the entity exists, and that it is internal, + otherwise call the skipped entity handler + */ + if (prologState.documentEntity && + (dtd->standalone + ? !openInternalEntities + : !dtd->hasParamEntityRefs)) { + if (!entity) + return XML_ERROR_UNDEFINED_ENTITY; + else if (!entity->is_internal) + return XML_ERROR_ENTITY_DECLARED_IN_PE; + } + else if (!entity) { + dtd->keepProcessing = dtd->standalone; + /* cannot report skipped entities in declarations */ + if ((role == XML_ROLE_PARAM_ENTITY_REF) && skippedEntityHandler) { + skippedEntityHandler(handlerArg, name, 1); + handleDefault = XML_FALSE; + } + break; + } + if (entity->open) + return XML_ERROR_RECURSIVE_ENTITY_REF; + if (entity->textPtr) { + enum XML_Error result; + XML_Bool betweenDecl = + (role == XML_ROLE_PARAM_ENTITY_REF ? XML_TRUE : XML_FALSE); + result = processInternalEntity(parser, entity, betweenDecl); + if (result != XML_ERROR_NONE) + return result; + handleDefault = XML_FALSE; + break; + } + if (externalEntityRefHandler) { + dtd->paramEntityRead = XML_FALSE; + entity->open = XML_TRUE; + if (!externalEntityRefHandler(externalEntityRefHandlerArg, + 0, + entity->base, + entity->systemId, + entity->publicId)) { + entity->open = XML_FALSE; + return XML_ERROR_EXTERNAL_ENTITY_HANDLING; + } + entity->open = XML_FALSE; + handleDefault = XML_FALSE; + if (!dtd->paramEntityRead) { + dtd->keepProcessing = dtd->standalone; + break; + } + } + else { + dtd->keepProcessing = dtd->standalone; + break; + } + } +#endif /* XML_DTD */ + if (!dtd->standalone && + notStandaloneHandler && + !notStandaloneHandler(handlerArg)) + return XML_ERROR_NOT_STANDALONE; + break; + + /* Element declaration stuff */ + + case XML_ROLE_ELEMENT_NAME: + if (elementDeclHandler) { + declElementType = getElementType(parser, enc, s, next); + if (!declElementType) + return XML_ERROR_NO_MEMORY; + dtd->scaffLevel = 0; + dtd->scaffCount = 0; + dtd->in_eldecl = XML_TRUE; + handleDefault = XML_FALSE; + } + break; + + case XML_ROLE_CONTENT_ANY: + case XML_ROLE_CONTENT_EMPTY: + if (dtd->in_eldecl) { + if (elementDeclHandler) { + XML_Content * content = (XML_Content *) MALLOC(sizeof(XML_Content)); + if (!content) + return XML_ERROR_NO_MEMORY; + content->quant = XML_CQUANT_NONE; + content->name = NULL; + content->numchildren = 0; + content->children = NULL; + content->type = ((role == XML_ROLE_CONTENT_ANY) ? + XML_CTYPE_ANY : + XML_CTYPE_EMPTY); + *eventEndPP = s; + elementDeclHandler(handlerArg, declElementType->name, content); + handleDefault = XML_FALSE; + } + dtd->in_eldecl = XML_FALSE; + } + break; + + case XML_ROLE_CONTENT_PCDATA: + if (dtd->in_eldecl) { + dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]].type + = XML_CTYPE_MIXED; + if (elementDeclHandler) + handleDefault = XML_FALSE; + } + break; + + case XML_ROLE_CONTENT_ELEMENT: + quant = XML_CQUANT_NONE; + goto elementContent; + case XML_ROLE_CONTENT_ELEMENT_OPT: + quant = XML_CQUANT_OPT; + goto elementContent; + case XML_ROLE_CONTENT_ELEMENT_REP: + quant = XML_CQUANT_REP; + goto elementContent; + case XML_ROLE_CONTENT_ELEMENT_PLUS: + quant = XML_CQUANT_PLUS; + elementContent: + if (dtd->in_eldecl) { + ELEMENT_TYPE *el; + const XML_Char *name; + int nameLen; + const char *nxt = (quant == XML_CQUANT_NONE + ? next + : next - enc->minBytesPerChar); + int myindex = nextScaffoldPart(parser); + if (myindex < 0) + return XML_ERROR_NO_MEMORY; + dtd->scaffold[myindex].type = XML_CTYPE_NAME; + dtd->scaffold[myindex].quant = quant; + el = getElementType(parser, enc, s, nxt); + if (!el) + return XML_ERROR_NO_MEMORY; + name = el->name; + dtd->scaffold[myindex].name = name; + nameLen = 0; + for (; name[nameLen++]; ); + dtd->contentStringLen += nameLen; + if (elementDeclHandler) + handleDefault = XML_FALSE; + } + break; + + case XML_ROLE_GROUP_CLOSE: + quant = XML_CQUANT_NONE; + goto closeGroup; + case XML_ROLE_GROUP_CLOSE_OPT: + quant = XML_CQUANT_OPT; + goto closeGroup; + case XML_ROLE_GROUP_CLOSE_REP: + quant = XML_CQUANT_REP; + goto closeGroup; + case XML_ROLE_GROUP_CLOSE_PLUS: + quant = XML_CQUANT_PLUS; + closeGroup: + if (dtd->in_eldecl) { + if (elementDeclHandler) + handleDefault = XML_FALSE; + dtd->scaffLevel--; + dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel]].quant = quant; + if (dtd->scaffLevel == 0) { + if (!handleDefault) { + XML_Content *model = build_model(parser); + if (!model) + return XML_ERROR_NO_MEMORY; + *eventEndPP = s; + elementDeclHandler(handlerArg, declElementType->name, model); + } + dtd->in_eldecl = XML_FALSE; + dtd->contentStringLen = 0; + } + } + break; + /* End element declaration stuff */ + + case XML_ROLE_PI: + if (!reportProcessingInstruction(parser, enc, s, next)) + return XML_ERROR_NO_MEMORY; + handleDefault = XML_FALSE; + break; + case XML_ROLE_COMMENT: + if (!reportComment(parser, enc, s, next)) + return XML_ERROR_NO_MEMORY; + handleDefault = XML_FALSE; + break; + case XML_ROLE_NONE: + switch (tok) { + case XML_TOK_BOM: + handleDefault = XML_FALSE; + break; + } + break; + case XML_ROLE_DOCTYPE_NONE: + if (startDoctypeDeclHandler) + handleDefault = XML_FALSE; + break; + case XML_ROLE_ENTITY_NONE: + if (dtd->keepProcessing && entityDeclHandler) + handleDefault = XML_FALSE; + break; + case XML_ROLE_NOTATION_NONE: + if (notationDeclHandler) + handleDefault = XML_FALSE; + break; + case XML_ROLE_ATTLIST_NONE: + if (dtd->keepProcessing && attlistDeclHandler) + handleDefault = XML_FALSE; + break; + case XML_ROLE_ELEMENT_NONE: + if (elementDeclHandler) + handleDefault = XML_FALSE; + break; + } /* end of big switch */ + + if (handleDefault && defaultHandler) + reportDefault(parser, enc, s, next); + + switch (ps_parsing) { + case XML_SUSPENDED: + *nextPtr = next; + return XML_ERROR_NONE; + case XML_FINISHED: + return XML_ERROR_ABORTED; + default: + s = next; + tok = XmlPrologTok(enc, s, end, &next); + } + } + /* not reached */ +} + +static enum XML_Error PTRCALL +epilogProcessor(XML_Parser parser, + const char *s, + const char *end, + const char **nextPtr) +{ + processor = epilogProcessor; + eventPtr = s; + for (;;) { + const char *next = NULL; + int tok = XmlPrologTok(encoding, s, end, &next); + eventEndPtr = next; + switch (tok) { + /* report partial linebreak - it might be the last token */ + case -XML_TOK_PROLOG_S: + if (defaultHandler) { + reportDefault(parser, encoding, s, next); + if (ps_parsing == XML_FINISHED) + return XML_ERROR_ABORTED; + } + *nextPtr = next; + return XML_ERROR_NONE; + case XML_TOK_NONE: + *nextPtr = s; + return XML_ERROR_NONE; + case XML_TOK_PROLOG_S: + if (defaultHandler) + reportDefault(parser, encoding, s, next); + break; + case XML_TOK_PI: + if (!reportProcessingInstruction(parser, encoding, s, next)) + return XML_ERROR_NO_MEMORY; + break; + case XML_TOK_COMMENT: + if (!reportComment(parser, encoding, s, next)) + return XML_ERROR_NO_MEMORY; + break; + case XML_TOK_INVALID: + eventPtr = next; + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_PARTIAL: + if (!ps_finalBuffer) { + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_UNCLOSED_TOKEN; + case XML_TOK_PARTIAL_CHAR: + if (!ps_finalBuffer) { + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_PARTIAL_CHAR; + default: + return XML_ERROR_JUNK_AFTER_DOC_ELEMENT; + } + eventPtr = s = next; + switch (ps_parsing) { + case XML_SUSPENDED: + *nextPtr = next; + return XML_ERROR_NONE; + case XML_FINISHED: + return XML_ERROR_ABORTED; + default: ; + } + } +} + +static enum XML_Error +processInternalEntity(XML_Parser parser, ENTITY *entity, + XML_Bool betweenDecl) +{ + const char *textStart, *textEnd; + const char *next; + enum XML_Error result; + OPEN_INTERNAL_ENTITY *openEntity; + + if (freeInternalEntities) { + openEntity = freeInternalEntities; + freeInternalEntities = openEntity->next; + } + else { + openEntity = (OPEN_INTERNAL_ENTITY *)MALLOC(sizeof(OPEN_INTERNAL_ENTITY)); + if (!openEntity) + return XML_ERROR_NO_MEMORY; + } + entity->open = XML_TRUE; + entity->processed = 0; + openEntity->next = openInternalEntities; + openInternalEntities = openEntity; + openEntity->entity = entity; + openEntity->startTagLevel = tagLevel; + openEntity->betweenDecl = betweenDecl; + openEntity->internalEventPtr = NULL; + openEntity->internalEventEndPtr = NULL; + textStart = (char *)entity->textPtr; + textEnd = (char *)(entity->textPtr + entity->textLen); + +#ifdef XML_DTD + if (entity->is_param) { + int tok = XmlPrologTok(internalEncoding, textStart, textEnd, &next); + result = doProlog(parser, internalEncoding, textStart, textEnd, tok, + next, &next, XML_FALSE); + } + else +#endif /* XML_DTD */ + result = doContent(parser, tagLevel, internalEncoding, textStart, + textEnd, &next, XML_FALSE); + + if (result == XML_ERROR_NONE) { + if (textEnd != next && ps_parsing == XML_SUSPENDED) { + entity->processed = (int)(next - textStart); + processor = internalEntityProcessor; + } + else { + entity->open = XML_FALSE; + openInternalEntities = openEntity->next; + /* put openEntity back in list of free instances */ + openEntity->next = freeInternalEntities; + freeInternalEntities = openEntity; + } + } + return result; +} + +static enum XML_Error PTRCALL +internalEntityProcessor(XML_Parser parser, + const char *s, + const char *end, + const char **nextPtr) +{ + ENTITY *entity; + const char *textStart, *textEnd; + const char *next; + enum XML_Error result; + OPEN_INTERNAL_ENTITY *openEntity = openInternalEntities; + if (!openEntity) + return XML_ERROR_UNEXPECTED_STATE; + + entity = openEntity->entity; + textStart = ((char *)entity->textPtr) + entity->processed; + textEnd = (char *)(entity->textPtr + entity->textLen); + +#ifdef XML_DTD + if (entity->is_param) { + int tok = XmlPrologTok(internalEncoding, textStart, textEnd, &next); + result = doProlog(parser, internalEncoding, textStart, textEnd, tok, + next, &next, XML_FALSE); + } + else +#endif /* XML_DTD */ + result = doContent(parser, openEntity->startTagLevel, internalEncoding, + textStart, textEnd, &next, XML_FALSE); + + if (result != XML_ERROR_NONE) + return result; + else if (textEnd != next && ps_parsing == XML_SUSPENDED) { + entity->processed = (int)(next - (char *)entity->textPtr); + return result; + } + else { + entity->open = XML_FALSE; + openInternalEntities = openEntity->next; + /* put openEntity back in list of free instances */ + openEntity->next = freeInternalEntities; + freeInternalEntities = openEntity; + } + +#ifdef XML_DTD + if (entity->is_param) { + int tok; + processor = prologProcessor; + tok = XmlPrologTok(encoding, s, end, &next); + return doProlog(parser, encoding, s, end, tok, next, nextPtr, + (XML_Bool)!ps_finalBuffer); + } + else +#endif /* XML_DTD */ + { + processor = contentProcessor; + /* see externalEntityContentProcessor vs contentProcessor */ + return doContent(parser, parentParser ? 1 : 0, encoding, s, end, + nextPtr, (XML_Bool)!ps_finalBuffer); + } +} + +static enum XML_Error PTRCALL +errorProcessor(XML_Parser parser, + const char *s, + const char *end, + const char **nextPtr) +{ + return errorCode; +} + +static enum XML_Error +storeAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata, + const char *ptr, const char *end, + STRING_POOL *pool) +{ + enum XML_Error result = appendAttributeValue(parser, enc, isCdata, ptr, + end, pool); + if (result) + return result; + if (!isCdata && poolLength(pool) && poolLastChar(pool) == 0x20) + poolChop(pool); + if (!poolAppendChar(pool, XML_T('\0'))) + return XML_ERROR_NO_MEMORY; + return XML_ERROR_NONE; +} + +static enum XML_Error +appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata, + const char *ptr, const char *end, + STRING_POOL *pool) +{ + DTD * const dtd = _dtd; /* save one level of indirection */ + for (;;) { + const char *next; + int tok = XmlAttributeValueTok(enc, ptr, end, &next); + switch (tok) { + case XML_TOK_NONE: + return XML_ERROR_NONE; + case XML_TOK_INVALID: + if (enc == encoding) + eventPtr = next; + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_PARTIAL: + if (enc == encoding) + eventPtr = ptr; + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_CHAR_REF: + { + XML_Char buf[XML_ENCODE_MAX]; + int i; + int n = XmlCharRefNumber(enc, ptr); + if (n < 0) { + if (enc == encoding) + eventPtr = ptr; + return XML_ERROR_BAD_CHAR_REF; + } + if (!isCdata + && n == 0x20 /* space */ + && (poolLength(pool) == 0 || poolLastChar(pool) == 0x20)) + break; + n = XmlEncode(n, (ICHAR *)buf); + if (!n) { + if (enc == encoding) + eventPtr = ptr; + return XML_ERROR_BAD_CHAR_REF; + } + for (i = 0; i < n; i++) { + if (!poolAppendChar(pool, buf[i])) + return XML_ERROR_NO_MEMORY; + } + } + break; + case XML_TOK_DATA_CHARS: + if (!poolAppend(pool, enc, ptr, next)) + return XML_ERROR_NO_MEMORY; + break; + case XML_TOK_TRAILING_CR: + next = ptr + enc->minBytesPerChar; + /* fall through */ + case XML_TOK_ATTRIBUTE_VALUE_S: + case XML_TOK_DATA_NEWLINE: + if (!isCdata && (poolLength(pool) == 0 || poolLastChar(pool) == 0x20)) + break; + if (!poolAppendChar(pool, 0x20)) + return XML_ERROR_NO_MEMORY; + break; + case XML_TOK_ENTITY_REF: + { + const XML_Char *name; + ENTITY *entity; + char checkEntityDecl; + XML_Char ch = (XML_Char) XmlPredefinedEntityName(enc, + ptr + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (ch) { + if (!poolAppendChar(pool, ch)) + return XML_ERROR_NO_MEMORY; + break; + } + name = poolStoreString(&temp2Pool, enc, + ptr + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (!name) + return XML_ERROR_NO_MEMORY; + entity = (ENTITY *)lookup(&dtd->generalEntities, name, 0); + poolDiscard(&temp2Pool); + /* First, determine if a check for an existing declaration is needed; + if yes, check that the entity exists, and that it is internal. + */ + if (pool == &dtd->pool) /* are we called from prolog? */ + checkEntityDecl = +#ifdef XML_DTD + prologState.documentEntity && +#endif /* XML_DTD */ + (dtd->standalone + ? !openInternalEntities + : !dtd->hasParamEntityRefs); + else /* if (pool == &tempPool): we are called from content */ + checkEntityDecl = !dtd->hasParamEntityRefs || dtd->standalone; + if (checkEntityDecl) { + if (!entity) + return XML_ERROR_UNDEFINED_ENTITY; + else if (!entity->is_internal) + return XML_ERROR_ENTITY_DECLARED_IN_PE; + } + else if (!entity) { + /* Cannot report skipped entity here - see comments on + skippedEntityHandler. + if (skippedEntityHandler) + skippedEntityHandler(handlerArg, name, 0); + */ + /* Cannot call the default handler because this would be + out of sync with the call to the startElementHandler. + if ((pool == &tempPool) && defaultHandler) + reportDefault(parser, enc, ptr, next); + */ + break; + } + if (entity->open) { + if (enc == encoding) + eventPtr = ptr; + return XML_ERROR_RECURSIVE_ENTITY_REF; + } + if (entity->notation) { + if (enc == encoding) + eventPtr = ptr; + return XML_ERROR_BINARY_ENTITY_REF; + } + if (!entity->textPtr) { + if (enc == encoding) + eventPtr = ptr; + return XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF; + } + else { + enum XML_Error result; + const XML_Char *textEnd = entity->textPtr + entity->textLen; + entity->open = XML_TRUE; + result = appendAttributeValue(parser, internalEncoding, isCdata, + (char *)entity->textPtr, + (char *)textEnd, pool); + entity->open = XML_FALSE; + if (result) + return result; + } + } + break; + default: + if (enc == encoding) + eventPtr = ptr; + return XML_ERROR_UNEXPECTED_STATE; + } + ptr = next; + } + /* not reached */ +} + +static enum XML_Error +storeEntityValue(XML_Parser parser, + const ENCODING *enc, + const char *entityTextPtr, + const char *entityTextEnd) +{ + DTD * const dtd = _dtd; /* save one level of indirection */ + STRING_POOL *pool = &(dtd->entityValuePool); + enum XML_Error result = XML_ERROR_NONE; +#ifdef XML_DTD + int oldInEntityValue = prologState.inEntityValue; + prologState.inEntityValue = 1; +#endif /* XML_DTD */ + /* never return Null for the value argument in EntityDeclHandler, + since this would indicate an external entity; therefore we + have to make sure that entityValuePool.start is not null */ + if (!pool->blocks) { + if (!poolGrow(pool)) + return XML_ERROR_NO_MEMORY; + } + + for (;;) { + const char *next; + int tok = XmlEntityValueTok(enc, entityTextPtr, entityTextEnd, &next); + switch (tok) { + case XML_TOK_PARAM_ENTITY_REF: +#ifdef XML_DTD + if (isParamEntity || enc != encoding) { + const XML_Char *name; + ENTITY *entity; + name = poolStoreString(&tempPool, enc, + entityTextPtr + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (!name) { + result = XML_ERROR_NO_MEMORY; + goto endEntityValue; + } + entity = (ENTITY *)lookup(&dtd->paramEntities, name, 0); + poolDiscard(&tempPool); + if (!entity) { + /* not a well-formedness error - see XML 1.0: WFC Entity Declared */ + /* cannot report skipped entity here - see comments on + skippedEntityHandler + if (skippedEntityHandler) + skippedEntityHandler(handlerArg, name, 0); + */ + dtd->keepProcessing = dtd->standalone; + goto endEntityValue; + } + if (entity->open) { + if (enc == encoding) + eventPtr = entityTextPtr; + result = XML_ERROR_RECURSIVE_ENTITY_REF; + goto endEntityValue; + } + if (entity->systemId) { + if (externalEntityRefHandler) { + dtd->paramEntityRead = XML_FALSE; + entity->open = XML_TRUE; + if (!externalEntityRefHandler(externalEntityRefHandlerArg, + 0, + entity->base, + entity->systemId, + entity->publicId)) { + entity->open = XML_FALSE; + result = XML_ERROR_EXTERNAL_ENTITY_HANDLING; + goto endEntityValue; + } + entity->open = XML_FALSE; + if (!dtd->paramEntityRead) + dtd->keepProcessing = dtd->standalone; + } + else + dtd->keepProcessing = dtd->standalone; + } + else { + entity->open = XML_TRUE; + result = storeEntityValue(parser, + internalEncoding, + (char *)entity->textPtr, + (char *)(entity->textPtr + + entity->textLen)); + entity->open = XML_FALSE; + if (result) + goto endEntityValue; + } + break; + } +#endif /* XML_DTD */ + /* In the internal subset, PE references are not legal + within markup declarations, e.g entity values in this case. */ + eventPtr = entityTextPtr; + result = XML_ERROR_PARAM_ENTITY_REF; + goto endEntityValue; + case XML_TOK_NONE: + result = XML_ERROR_NONE; + goto endEntityValue; + case XML_TOK_ENTITY_REF: + case XML_TOK_DATA_CHARS: + if (!poolAppend(pool, enc, entityTextPtr, next)) { + result = XML_ERROR_NO_MEMORY; + goto endEntityValue; + } + break; + case XML_TOK_TRAILING_CR: + next = entityTextPtr + enc->minBytesPerChar; + /* fall through */ + case XML_TOK_DATA_NEWLINE: + if (pool->end == pool->ptr && !poolGrow(pool)) { + result = XML_ERROR_NO_MEMORY; + goto endEntityValue; + } + *(pool->ptr)++ = 0xA; + break; + case XML_TOK_CHAR_REF: + { + XML_Char buf[XML_ENCODE_MAX]; + int i; + int n = XmlCharRefNumber(enc, entityTextPtr); + if (n < 0) { + if (enc == encoding) + eventPtr = entityTextPtr; + result = XML_ERROR_BAD_CHAR_REF; + goto endEntityValue; + } + n = XmlEncode(n, (ICHAR *)buf); + if (!n) { + if (enc == encoding) + eventPtr = entityTextPtr; + result = XML_ERROR_BAD_CHAR_REF; + goto endEntityValue; + } + for (i = 0; i < n; i++) { + if (pool->end == pool->ptr && !poolGrow(pool)) { + result = XML_ERROR_NO_MEMORY; + goto endEntityValue; + } + *(pool->ptr)++ = buf[i]; + } + } + break; + case XML_TOK_PARTIAL: + if (enc == encoding) + eventPtr = entityTextPtr; + result = XML_ERROR_INVALID_TOKEN; + goto endEntityValue; + case XML_TOK_INVALID: + if (enc == encoding) + eventPtr = next; + result = XML_ERROR_INVALID_TOKEN; + goto endEntityValue; + default: + if (enc == encoding) + eventPtr = entityTextPtr; + result = XML_ERROR_UNEXPECTED_STATE; + goto endEntityValue; + } + entityTextPtr = next; + } +endEntityValue: +#ifdef XML_DTD + prologState.inEntityValue = oldInEntityValue; +#endif /* XML_DTD */ + return result; +} + +static void FASTCALL +normalizeLines(XML_Char *s) +{ + XML_Char *p; + for (;; s++) { + if (*s == XML_T('\0')) + return; + if (*s == 0xD) + break; + } + p = s; + do { + if (*s == 0xD) { + *p++ = 0xA; + if (*++s == 0xA) + s++; + } + else + *p++ = *s++; + } while (*s); + *p = XML_T('\0'); +} + +static int +reportProcessingInstruction(XML_Parser parser, const ENCODING *enc, + const char *start, const char *end) +{ + const XML_Char *target; + XML_Char *data; + const char *tem; + if (!processingInstructionHandler) { + if (defaultHandler) + reportDefault(parser, enc, start, end); + return 1; + } + start += enc->minBytesPerChar * 2; + tem = start + XmlNameLength(enc, start); + target = poolStoreString(&tempPool, enc, start, tem); + if (!target) + return 0; + poolFinish(&tempPool); + data = poolStoreString(&tempPool, enc, + XmlSkipS(enc, tem), + end - enc->minBytesPerChar*2); + if (!data) + return 0; + normalizeLines(data); + processingInstructionHandler(handlerArg, target, data); + poolClear(&tempPool); + return 1; +} + +static int +reportComment(XML_Parser parser, const ENCODING *enc, + const char *start, const char *end) +{ + XML_Char *data; + if (!commentHandler) { + if (defaultHandler) + reportDefault(parser, enc, start, end); + return 1; + } + data = poolStoreString(&tempPool, + enc, + start + enc->minBytesPerChar * 4, + end - enc->minBytesPerChar * 3); + if (!data) + return 0; + normalizeLines(data); + commentHandler(handlerArg, data); + poolClear(&tempPool); + return 1; +} + +static void +reportDefault(XML_Parser parser, const ENCODING *enc, + const char *s, const char *end) +{ + if (MUST_CONVERT(enc, s)) { + const char **eventPP; + const char **eventEndPP; + if (enc == encoding) { + eventPP = &eventPtr; + eventEndPP = &eventEndPtr; + } + else { + eventPP = &(openInternalEntities->internalEventPtr); + eventEndPP = &(openInternalEntities->internalEventEndPtr); + } + do { + ICHAR *dataPtr = (ICHAR *)dataBuf; + XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)dataBufEnd); + *eventEndPP = s; + defaultHandler(handlerArg, dataBuf, (int)(dataPtr - (ICHAR *)dataBuf)); + *eventPP = s; + } while (s != end); + } + else + defaultHandler(handlerArg, (XML_Char *)s, (int)((XML_Char *)end - (XML_Char *)s)); +} + + +static int +defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId, XML_Bool isCdata, + XML_Bool isId, const XML_Char *value, XML_Parser parser) +{ + DEFAULT_ATTRIBUTE *att; + if (value || isId) { + /* The handling of default attributes gets messed up if we have + a default which duplicates a non-default. */ + int i; + for (i = 0; i < type->nDefaultAtts; i++) + if (attId == type->defaultAtts[i].id) + return 1; + if (isId && !type->idAtt && !attId->xmlns) + type->idAtt = attId; + } + if (type->nDefaultAtts == type->allocDefaultAtts) { + if (type->allocDefaultAtts == 0) { + type->allocDefaultAtts = 8; + type->defaultAtts = (DEFAULT_ATTRIBUTE *)MALLOC(type->allocDefaultAtts + * sizeof(DEFAULT_ATTRIBUTE)); + if (!type->defaultAtts) + return 0; + } + else { + DEFAULT_ATTRIBUTE *temp; + int count = type->allocDefaultAtts * 2; + temp = (DEFAULT_ATTRIBUTE *) + REALLOC(type->defaultAtts, (count * sizeof(DEFAULT_ATTRIBUTE))); + if (temp == NULL) + return 0; + type->allocDefaultAtts = count; + type->defaultAtts = temp; + } + } + att = type->defaultAtts + type->nDefaultAtts; + att->id = attId; + att->value = value; + att->isCdata = isCdata; + if (!isCdata) + attId->maybeTokenized = XML_TRUE; + type->nDefaultAtts += 1; + return 1; +} + +static int +setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *elementType) +{ + DTD * const dtd = _dtd; /* save one level of indirection */ + const XML_Char *name; + for (name = elementType->name; *name; name++) { + if (*name == XML_T(':')) { + PREFIX *prefix; + const XML_Char *s; + for (s = elementType->name; s != name; s++) { + if (!poolAppendChar(&dtd->pool, *s)) + return 0; + } + if (!poolAppendChar(&dtd->pool, XML_T('\0'))) + return 0; + prefix = (PREFIX *)lookup(&dtd->prefixes, poolStart(&dtd->pool), + sizeof(PREFIX)); + if (!prefix) + return 0; + if (prefix->name == poolStart(&dtd->pool)) + poolFinish(&dtd->pool); + else + poolDiscard(&dtd->pool); + elementType->prefix = prefix; + + } + } + return 1; +} + +static ATTRIBUTE_ID * +getAttributeId(XML_Parser parser, const ENCODING *enc, + const char *start, const char *end) +{ + DTD * const dtd = _dtd; /* save one level of indirection */ + ATTRIBUTE_ID *id; + const XML_Char *name; + if (!poolAppendChar(&dtd->pool, XML_T('\0'))) + return NULL; + name = poolStoreString(&dtd->pool, enc, start, end); + if (!name) + return NULL; + /* skip quotation mark - its storage will be re-used (like in name[-1]) */ + ++name; + id = (ATTRIBUTE_ID *)lookup(&dtd->attributeIds, name, sizeof(ATTRIBUTE_ID)); + if (!id) + return NULL; + if (id->name != name) + poolDiscard(&dtd->pool); + else { + poolFinish(&dtd->pool); + if (!ns) + ; + else if (name[0] == XML_T('x') + && name[1] == XML_T('m') + && name[2] == XML_T('l') + && name[3] == XML_T('n') + && name[4] == XML_T('s') + && (name[5] == XML_T('\0') || name[5] == XML_T(':'))) { + if (name[5] == XML_T('\0')) + id->prefix = &dtd->defaultPrefix; + else + id->prefix = (PREFIX *)lookup(&dtd->prefixes, name + 6, sizeof(PREFIX)); + id->xmlns = XML_TRUE; + } + else { + int i; + for (i = 0; name[i]; i++) { + /* attributes without prefix are *not* in the default namespace */ + if (name[i] == XML_T(':')) { + int j; + for (j = 0; j < i; j++) { + if (!poolAppendChar(&dtd->pool, name[j])) + return NULL; + } + if (!poolAppendChar(&dtd->pool, XML_T('\0'))) + return NULL; + id->prefix = (PREFIX *)lookup(&dtd->prefixes, poolStart(&dtd->pool), + sizeof(PREFIX)); + if (id->prefix->name == poolStart(&dtd->pool)) + poolFinish(&dtd->pool); + else + poolDiscard(&dtd->pool); + break; + } + } + } + } + return id; +} + +#define CONTEXT_SEP XML_T('\f') + +static const XML_Char * +getContext(XML_Parser parser) +{ + DTD * const dtd = _dtd; /* save one level of indirection */ + HASH_TABLE_ITER iter; + XML_Bool needSep = XML_FALSE; + + if (dtd->defaultPrefix.binding) { + int i; + int len; + if (!poolAppendChar(&tempPool, XML_T('='))) + return NULL; + len = dtd->defaultPrefix.binding->uriLen; + if (namespaceSeparator) + len--; + for (i = 0; i < len; i++) + if (!poolAppendChar(&tempPool, dtd->defaultPrefix.binding->uri[i])) + return NULL; + needSep = XML_TRUE; + } + + hashTableIterInit(&iter, &(dtd->prefixes)); + for (;;) { + int i; + int len; + const XML_Char *s; + PREFIX *prefix = (PREFIX *)hashTableIterNext(&iter); + if (!prefix) + break; + if (!prefix->binding) + continue; + if (needSep && !poolAppendChar(&tempPool, CONTEXT_SEP)) + return NULL; + for (s = prefix->name; *s; s++) + if (!poolAppendChar(&tempPool, *s)) + return NULL; + if (!poolAppendChar(&tempPool, XML_T('='))) + return NULL; + len = prefix->binding->uriLen; + if (namespaceSeparator) + len--; + for (i = 0; i < len; i++) + if (!poolAppendChar(&tempPool, prefix->binding->uri[i])) + return NULL; + needSep = XML_TRUE; + } + + + hashTableIterInit(&iter, &(dtd->generalEntities)); + for (;;) { + const XML_Char *s; + ENTITY *e = (ENTITY *)hashTableIterNext(&iter); + if (!e) + break; + if (!e->open) + continue; + if (needSep && !poolAppendChar(&tempPool, CONTEXT_SEP)) + return NULL; + for (s = e->name; *s; s++) + if (!poolAppendChar(&tempPool, *s)) + return 0; + needSep = XML_TRUE; + } + + if (!poolAppendChar(&tempPool, XML_T('\0'))) + return NULL; + return tempPool.start; +} + +static XML_Bool +setContext(XML_Parser parser, const XML_Char *context) +{ + DTD * const dtd = _dtd; /* save one level of indirection */ + const XML_Char *s = context; + + while (*context != XML_T('\0')) { + if (*s == CONTEXT_SEP || *s == XML_T('\0')) { + ENTITY *e; + if (!poolAppendChar(&tempPool, XML_T('\0'))) + return XML_FALSE; + e = (ENTITY *)lookup(&dtd->generalEntities, poolStart(&tempPool), 0); + if (e) + e->open = XML_TRUE; + if (*s != XML_T('\0')) + s++; + context = s; + poolDiscard(&tempPool); + } + else if (*s == XML_T('=')) { + PREFIX *prefix; + if (poolLength(&tempPool) == 0) + prefix = &dtd->defaultPrefix; + else { + if (!poolAppendChar(&tempPool, XML_T('\0'))) + return XML_FALSE; + prefix = (PREFIX *)lookup(&dtd->prefixes, poolStart(&tempPool), + sizeof(PREFIX)); + if (!prefix) + return XML_FALSE; + if (prefix->name == poolStart(&tempPool)) { + prefix->name = poolCopyString(&dtd->pool, prefix->name); + if (!prefix->name) + return XML_FALSE; + } + poolDiscard(&tempPool); + } + for (context = s + 1; + *context != CONTEXT_SEP && *context != XML_T('\0'); + context++) + if (!poolAppendChar(&tempPool, *context)) + return XML_FALSE; + if (!poolAppendChar(&tempPool, XML_T('\0'))) + return XML_FALSE; + if (addBinding(parser, prefix, NULL, poolStart(&tempPool), + &inheritedBindings) != XML_ERROR_NONE) + return XML_FALSE; + poolDiscard(&tempPool); + if (*context != XML_T('\0')) + ++context; + s = context; + } + else { + if (!poolAppendChar(&tempPool, *s)) + return XML_FALSE; + s++; + } + } + return XML_TRUE; +} + +static void FASTCALL +normalizePublicId(XML_Char *publicId) +{ + XML_Char *p = publicId; + XML_Char *s; + for (s = publicId; *s; s++) { + switch (*s) { + case 0x20: + case 0xD: + case 0xA: + if (p != publicId && p[-1] != 0x20) + *p++ = 0x20; + break; + default: + *p++ = *s; + } + } + if (p != publicId && p[-1] == 0x20) + --p; + *p = XML_T('\0'); +} + +static DTD * +dtdCreate(const XML_Memory_Handling_Suite *ms) +{ + DTD *p = (DTD *)ms->malloc_fcn(sizeof(DTD)); + if (p == NULL) + return p; + poolInit(&(p->pool), ms); + poolInit(&(p->entityValuePool), ms); + hashTableInit(&(p->generalEntities), ms); + hashTableInit(&(p->elementTypes), ms); + hashTableInit(&(p->attributeIds), ms); + hashTableInit(&(p->prefixes), ms); +#ifdef XML_DTD + p->paramEntityRead = XML_FALSE; + hashTableInit(&(p->paramEntities), ms); +#endif /* XML_DTD */ + p->defaultPrefix.name = NULL; + p->defaultPrefix.binding = NULL; + + p->in_eldecl = XML_FALSE; + p->scaffIndex = NULL; + p->scaffold = NULL; + p->scaffLevel = 0; + p->scaffSize = 0; + p->scaffCount = 0; + p->contentStringLen = 0; + + p->keepProcessing = XML_TRUE; + p->hasParamEntityRefs = XML_FALSE; + p->standalone = XML_FALSE; + return p; +} + +static void +dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms) +{ + HASH_TABLE_ITER iter; + hashTableIterInit(&iter, &(p->elementTypes)); + for (;;) { + ELEMENT_TYPE *e = (ELEMENT_TYPE *)hashTableIterNext(&iter); + if (!e) + break; + if (e->allocDefaultAtts != 0) + ms->free_fcn(e->defaultAtts); + } + hashTableClear(&(p->generalEntities)); +#ifdef XML_DTD + p->paramEntityRead = XML_FALSE; + hashTableClear(&(p->paramEntities)); +#endif /* XML_DTD */ + hashTableClear(&(p->elementTypes)); + hashTableClear(&(p->attributeIds)); + hashTableClear(&(p->prefixes)); + poolClear(&(p->pool)); + poolClear(&(p->entityValuePool)); + p->defaultPrefix.name = NULL; + p->defaultPrefix.binding = NULL; + + p->in_eldecl = XML_FALSE; + + ms->free_fcn(p->scaffIndex); + p->scaffIndex = NULL; + ms->free_fcn(p->scaffold); + p->scaffold = NULL; + + p->scaffLevel = 0; + p->scaffSize = 0; + p->scaffCount = 0; + p->contentStringLen = 0; + + p->keepProcessing = XML_TRUE; + p->hasParamEntityRefs = XML_FALSE; + p->standalone = XML_FALSE; +} + +static void +dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms) +{ + HASH_TABLE_ITER iter; + hashTableIterInit(&iter, &(p->elementTypes)); + for (;;) { + ELEMENT_TYPE *e = (ELEMENT_TYPE *)hashTableIterNext(&iter); + if (!e) + break; + if (e->allocDefaultAtts != 0) + ms->free_fcn(e->defaultAtts); + } + hashTableDestroy(&(p->generalEntities)); +#ifdef XML_DTD + hashTableDestroy(&(p->paramEntities)); +#endif /* XML_DTD */ + hashTableDestroy(&(p->elementTypes)); + hashTableDestroy(&(p->attributeIds)); + hashTableDestroy(&(p->prefixes)); + poolDestroy(&(p->pool)); + poolDestroy(&(p->entityValuePool)); + if (isDocEntity) { + ms->free_fcn(p->scaffIndex); + ms->free_fcn(p->scaffold); + } + ms->free_fcn(p); +} + +/* Do a deep copy of the DTD. Return 0 for out of memory, non-zero otherwise. + The new DTD has already been initialized. +*/ +static int +dtdCopy(DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms) +{ + HASH_TABLE_ITER iter; + + /* Copy the prefix table. */ + + hashTableIterInit(&iter, &(oldDtd->prefixes)); + for (;;) { + const XML_Char *name; + const PREFIX *oldP = (PREFIX *)hashTableIterNext(&iter); + if (!oldP) + break; + name = poolCopyString(&(newDtd->pool), oldP->name); + if (!name) + return 0; + if (!lookup(&(newDtd->prefixes), name, sizeof(PREFIX))) + return 0; + } + + hashTableIterInit(&iter, &(oldDtd->attributeIds)); + + /* Copy the attribute id table. */ + + for (;;) { + ATTRIBUTE_ID *newA; + const XML_Char *name; + const ATTRIBUTE_ID *oldA = (ATTRIBUTE_ID *)hashTableIterNext(&iter); + + if (!oldA) + break; + /* Remember to allocate the scratch byte before the name. */ + if (!poolAppendChar(&(newDtd->pool), XML_T('\0'))) + return 0; + name = poolCopyString(&(newDtd->pool), oldA->name); + if (!name) + return 0; + ++name; + newA = (ATTRIBUTE_ID *)lookup(&(newDtd->attributeIds), name, + sizeof(ATTRIBUTE_ID)); + if (!newA) + return 0; + newA->maybeTokenized = oldA->maybeTokenized; + if (oldA->prefix) { + newA->xmlns = oldA->xmlns; + if (oldA->prefix == &oldDtd->defaultPrefix) + newA->prefix = &newDtd->defaultPrefix; + else + newA->prefix = (PREFIX *)lookup(&(newDtd->prefixes), + oldA->prefix->name, 0); + } + } + + /* Copy the element type table. */ + + hashTableIterInit(&iter, &(oldDtd->elementTypes)); + + for (;;) { + int i; + ELEMENT_TYPE *newE; + const XML_Char *name; + const ELEMENT_TYPE *oldE = (ELEMENT_TYPE *)hashTableIterNext(&iter); + if (!oldE) + break; + name = poolCopyString(&(newDtd->pool), oldE->name); + if (!name) + return 0; + newE = (ELEMENT_TYPE *)lookup(&(newDtd->elementTypes), name, + sizeof(ELEMENT_TYPE)); + if (!newE) + return 0; + if (oldE->nDefaultAtts) { + newE->defaultAtts = (DEFAULT_ATTRIBUTE *) + ms->malloc_fcn(oldE->nDefaultAtts * sizeof(DEFAULT_ATTRIBUTE)); + if (!newE->defaultAtts) { + ms->free_fcn(newE); + return 0; + } + } + if (oldE->idAtt) + newE->idAtt = (ATTRIBUTE_ID *) + lookup(&(newDtd->attributeIds), oldE->idAtt->name, 0); + newE->allocDefaultAtts = newE->nDefaultAtts = oldE->nDefaultAtts; + if (oldE->prefix) + newE->prefix = (PREFIX *)lookup(&(newDtd->prefixes), + oldE->prefix->name, 0); + for (i = 0; i < newE->nDefaultAtts; i++) { + newE->defaultAtts[i].id = (ATTRIBUTE_ID *) + lookup(&(newDtd->attributeIds), oldE->defaultAtts[i].id->name, 0); + newE->defaultAtts[i].isCdata = oldE->defaultAtts[i].isCdata; + if (oldE->defaultAtts[i].value) { + newE->defaultAtts[i].value + = poolCopyString(&(newDtd->pool), oldE->defaultAtts[i].value); + if (!newE->defaultAtts[i].value) + return 0; + } + else + newE->defaultAtts[i].value = NULL; + } + } + + /* Copy the entity tables. */ + if (!copyEntityTable(&(newDtd->generalEntities), + &(newDtd->pool), + &(oldDtd->generalEntities))) + return 0; + +#ifdef XML_DTD + if (!copyEntityTable(&(newDtd->paramEntities), + &(newDtd->pool), + &(oldDtd->paramEntities))) + return 0; + newDtd->paramEntityRead = oldDtd->paramEntityRead; +#endif /* XML_DTD */ + + newDtd->keepProcessing = oldDtd->keepProcessing; + newDtd->hasParamEntityRefs = oldDtd->hasParamEntityRefs; + newDtd->standalone = oldDtd->standalone; + + /* Don't want deep copying for scaffolding */ + newDtd->in_eldecl = oldDtd->in_eldecl; + newDtd->scaffold = oldDtd->scaffold; + newDtd->contentStringLen = oldDtd->contentStringLen; + newDtd->scaffSize = oldDtd->scaffSize; + newDtd->scaffLevel = oldDtd->scaffLevel; + newDtd->scaffIndex = oldDtd->scaffIndex; + + return 1; +} /* End dtdCopy */ + +static int +copyEntityTable(HASH_TABLE *newTable, + STRING_POOL *newPool, + const HASH_TABLE *oldTable) +{ + HASH_TABLE_ITER iter; + const XML_Char *cachedOldBase = NULL; + const XML_Char *cachedNewBase = NULL; + + hashTableIterInit(&iter, oldTable); + + for (;;) { + ENTITY *newE; + const XML_Char *name; + const ENTITY *oldE = (ENTITY *)hashTableIterNext(&iter); + if (!oldE) + break; + name = poolCopyString(newPool, oldE->name); + if (!name) + return 0; + newE = (ENTITY *)lookup(newTable, name, sizeof(ENTITY)); + if (!newE) + return 0; + if (oldE->systemId) { + const XML_Char *tem = poolCopyString(newPool, oldE->systemId); + if (!tem) + return 0; + newE->systemId = tem; + if (oldE->base) { + if (oldE->base == cachedOldBase) + newE->base = cachedNewBase; + else { + cachedOldBase = oldE->base; + tem = poolCopyString(newPool, cachedOldBase); + if (!tem) + return 0; + cachedNewBase = newE->base = tem; + } + } + if (oldE->publicId) { + tem = poolCopyString(newPool, oldE->publicId); + if (!tem) + return 0; + newE->publicId = tem; + } + } + else { + const XML_Char *tem = poolCopyStringN(newPool, oldE->textPtr, + oldE->textLen); + if (!tem) + return 0; + newE->textPtr = tem; + newE->textLen = oldE->textLen; + } + if (oldE->notation) { + const XML_Char *tem = poolCopyString(newPool, oldE->notation); + if (!tem) + return 0; + newE->notation = tem; + } + newE->is_param = oldE->is_param; + newE->is_internal = oldE->is_internal; + } + return 1; +} + +#define INIT_POWER 6 + +static XML_Bool FASTCALL +keyeq(KEY s1, KEY s2) +{ + for (; *s1 == *s2; s1++, s2++) + if (*s1 == 0) + return XML_TRUE; + return XML_FALSE; +} + +static unsigned long FASTCALL +hash(KEY s) +{ + unsigned long h = 0; + while (*s) + h = CHAR_HASH(h, *s++); + return h; +} + +static NAMED * +lookup(HASH_TABLE *table, KEY name, size_t createSize) +{ + size_t i; + if (table->size == 0) { + size_t tsize; + if (!createSize) + return NULL; + table->power = INIT_POWER; + /* table->size is a power of 2 */ + table->size = (size_t)1 << INIT_POWER; + tsize = table->size * sizeof(NAMED *); + table->v = (NAMED **)table->mem->malloc_fcn(tsize); + if (!table->v) { + table->size = 0; + return NULL; + } + memset(table->v, 0, tsize); + i = hash(name) & ((unsigned long)table->size - 1); + } + else { + unsigned long h = hash(name); + unsigned long mask = (unsigned long)table->size - 1; + unsigned char step = 0; + i = h & mask; + while (table->v[i]) { + if (keyeq(name, table->v[i]->name)) + return table->v[i]; + if (!step) + step = PROBE_STEP(h, mask, table->power); + i < step ? (i += table->size - step) : (i -= step); + } + if (!createSize) + return NULL; + + /* check for overflow (table is half full) */ + if (table->used >> (table->power - 1)) { + unsigned char newPower = table->power + 1; + size_t newSize = (size_t)1 << newPower; + unsigned long newMask = (unsigned long)newSize - 1; + size_t tsize = newSize * sizeof(NAMED *); + NAMED **newV = (NAMED **)table->mem->malloc_fcn(tsize); + if (!newV) + return NULL; + memset(newV, 0, tsize); + for (i = 0; i < table->size; i++) + if (table->v[i]) { + unsigned long newHash = hash(table->v[i]->name); + size_t j = newHash & newMask; + step = 0; + while (newV[j]) { + if (!step) + step = PROBE_STEP(newHash, newMask, newPower); + j < step ? (j += newSize - step) : (j -= step); + } + newV[j] = table->v[i]; + } + table->mem->free_fcn(table->v); + table->v = newV; + table->power = newPower; + table->size = newSize; + i = h & newMask; + step = 0; + while (table->v[i]) { + if (!step) + step = PROBE_STEP(h, newMask, newPower); + i < step ? (i += newSize - step) : (i -= step); + } + } + } + table->v[i] = (NAMED *)table->mem->malloc_fcn(createSize); + if (!table->v[i]) + return NULL; + memset(table->v[i], 0, createSize); + table->v[i]->name = name; + (table->used)++; + return table->v[i]; +} + +static void FASTCALL +hashTableClear(HASH_TABLE *table) +{ + size_t i; + for (i = 0; i < table->size; i++) { + table->mem->free_fcn(table->v[i]); + table->v[i] = NULL; + } + table->used = 0; +} + +static void FASTCALL +hashTableDestroy(HASH_TABLE *table) +{ + size_t i; + for (i = 0; i < table->size; i++) + table->mem->free_fcn(table->v[i]); + table->mem->free_fcn(table->v); +} + +static void FASTCALL +hashTableInit(HASH_TABLE *p, const XML_Memory_Handling_Suite *ms) +{ + p->power = 0; + p->size = 0; + p->used = 0; + p->v = NULL; + p->mem = ms; +} + +static void FASTCALL +hashTableIterInit(HASH_TABLE_ITER *iter, const HASH_TABLE *table) +{ + iter->p = table->v; + iter->end = iter->p + table->size; +} + +static NAMED * FASTCALL +hashTableIterNext(HASH_TABLE_ITER *iter) +{ + while (iter->p != iter->end) { + NAMED *tem = *(iter->p)++; + if (tem) + return tem; + } + return NULL; +} + +static void FASTCALL +poolInit(STRING_POOL *pool, const XML_Memory_Handling_Suite *ms) +{ + pool->blocks = NULL; + pool->freeBlocks = NULL; + pool->start = NULL; + pool->ptr = NULL; + pool->end = NULL; + pool->mem = ms; +} + +static void FASTCALL +poolClear(STRING_POOL *pool) +{ + if (!pool->freeBlocks) + pool->freeBlocks = pool->blocks; + else { + BLOCK *p = pool->blocks; + while (p) { + BLOCK *tem = p->next; + p->next = pool->freeBlocks; + pool->freeBlocks = p; + p = tem; + } + } + pool->blocks = NULL; + pool->start = NULL; + pool->ptr = NULL; + pool->end = NULL; +} + +static void FASTCALL +poolDestroy(STRING_POOL *pool) +{ + BLOCK *p = pool->blocks; + while (p) { + BLOCK *tem = p->next; + pool->mem->free_fcn(p); + p = tem; + } + p = pool->freeBlocks; + while (p) { + BLOCK *tem = p->next; + pool->mem->free_fcn(p); + p = tem; + } +} + +static XML_Char * +poolAppend(STRING_POOL *pool, const ENCODING *enc, + const char *ptr, const char *end) +{ + if (!pool->ptr && !poolGrow(pool)) + return NULL; + for (;;) { + XmlConvert(enc, &ptr, end, (ICHAR **)&(pool->ptr), (ICHAR *)pool->end); + if (ptr == end) + break; + if (!poolGrow(pool)) + return NULL; + } + return pool->start; +} + +static const XML_Char * FASTCALL +poolCopyString(STRING_POOL *pool, const XML_Char *s) +{ + do { + if (!poolAppendChar(pool, *s)) + return NULL; + } while (*s++); + s = pool->start; + poolFinish(pool); + return s; +} + +static const XML_Char * +poolCopyStringN(STRING_POOL *pool, const XML_Char *s, int n) +{ + if (!pool->ptr && !poolGrow(pool)) + return NULL; + for (; n > 0; --n, s++) { + if (!poolAppendChar(pool, *s)) + return NULL; + } + s = pool->start; + poolFinish(pool); + return s; +} + +static const XML_Char * FASTCALL +poolAppendString(STRING_POOL *pool, const XML_Char *s) +{ + while (*s) { + if (!poolAppendChar(pool, *s)) + return NULL; + s++; + } + return pool->start; +} + +static XML_Char * +poolStoreString(STRING_POOL *pool, const ENCODING *enc, + const char *ptr, const char *end) +{ + if (!poolAppend(pool, enc, ptr, end)) + return NULL; + if (pool->ptr == pool->end && !poolGrow(pool)) + return NULL; + *(pool->ptr)++ = 0; + return pool->start; +} + +static XML_Bool FASTCALL +poolGrow(STRING_POOL *pool) +{ + if (pool->freeBlocks) { + if (pool->start == 0) { + pool->blocks = pool->freeBlocks; + pool->freeBlocks = pool->freeBlocks->next; + pool->blocks->next = NULL; + pool->start = pool->blocks->s; + pool->end = pool->start + pool->blocks->size; + pool->ptr = pool->start; + return XML_TRUE; + } + if (pool->end - pool->start < pool->freeBlocks->size) { + BLOCK *tem = pool->freeBlocks->next; + pool->freeBlocks->next = pool->blocks; + pool->blocks = pool->freeBlocks; + pool->freeBlocks = tem; + memcpy(pool->blocks->s, pool->start, + (pool->end - pool->start) * sizeof(XML_Char)); + pool->ptr = pool->blocks->s + (pool->ptr - pool->start); + pool->start = pool->blocks->s; + pool->end = pool->start + pool->blocks->size; + return XML_TRUE; + } + } + if (pool->blocks && pool->start == pool->blocks->s) { + int blockSize = (int)(pool->end - pool->start)*2; + pool->blocks = (BLOCK *) + pool->mem->realloc_fcn(pool->blocks, + (offsetof(BLOCK, s) + + blockSize * sizeof(XML_Char))); + if (pool->blocks == NULL) + return XML_FALSE; + pool->blocks->size = blockSize; + pool->ptr = pool->blocks->s + (pool->ptr - pool->start); + pool->start = pool->blocks->s; + pool->end = pool->start + blockSize; + } + else { + BLOCK *tem; + int blockSize = (int)(pool->end - pool->start); + if (blockSize < INIT_BLOCK_SIZE) + blockSize = INIT_BLOCK_SIZE; + else + blockSize *= 2; + tem = (BLOCK *)pool->mem->malloc_fcn(offsetof(BLOCK, s) + + blockSize * sizeof(XML_Char)); + if (!tem) + return XML_FALSE; + tem->size = blockSize; + tem->next = pool->blocks; + pool->blocks = tem; + if (pool->ptr != pool->start) + memcpy(tem->s, pool->start, + (pool->ptr - pool->start) * sizeof(XML_Char)); + pool->ptr = tem->s + (pool->ptr - pool->start); + pool->start = tem->s; + pool->end = tem->s + blockSize; + } + return XML_TRUE; +} + +static int FASTCALL +nextScaffoldPart(XML_Parser parser) +{ + DTD * const dtd = _dtd; /* save one level of indirection */ + CONTENT_SCAFFOLD * me; + int next; + + if (!dtd->scaffIndex) { + dtd->scaffIndex = (int *)MALLOC(groupSize * sizeof(int)); + if (!dtd->scaffIndex) + return -1; + dtd->scaffIndex[0] = 0; + } + + if (dtd->scaffCount >= dtd->scaffSize) { + CONTENT_SCAFFOLD *temp; + if (dtd->scaffold) { + temp = (CONTENT_SCAFFOLD *) + REALLOC(dtd->scaffold, dtd->scaffSize * 2 * sizeof(CONTENT_SCAFFOLD)); + if (temp == NULL) + return -1; + dtd->scaffSize *= 2; + } + else { + temp = (CONTENT_SCAFFOLD *)MALLOC(INIT_SCAFFOLD_ELEMENTS + * sizeof(CONTENT_SCAFFOLD)); + if (temp == NULL) + return -1; + dtd->scaffSize = INIT_SCAFFOLD_ELEMENTS; + } + dtd->scaffold = temp; + } + next = dtd->scaffCount++; + me = &dtd->scaffold[next]; + if (dtd->scaffLevel) { + CONTENT_SCAFFOLD *parent = &dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel-1]]; + if (parent->lastchild) { + dtd->scaffold[parent->lastchild].nextsib = next; + } + if (!parent->childcnt) + parent->firstchild = next; + parent->lastchild = next; + parent->childcnt++; + } + me->firstchild = me->lastchild = me->childcnt = me->nextsib = 0; + return next; +} + +static void +build_node(XML_Parser parser, + int src_node, + XML_Content *dest, + XML_Content **contpos, + XML_Char **strpos) +{ + DTD * const dtd = _dtd; /* save one level of indirection */ + dest->type = dtd->scaffold[src_node].type; + dest->quant = dtd->scaffold[src_node].quant; + if (dest->type == XML_CTYPE_NAME) { + const XML_Char *src; + dest->name = *strpos; + src = dtd->scaffold[src_node].name; + for (;;) { + *(*strpos)++ = *src; + if (!*src) + break; + src++; + } + dest->numchildren = 0; + dest->children = NULL; + } + else { + unsigned int i; + int cn; + dest->numchildren = dtd->scaffold[src_node].childcnt; + dest->children = *contpos; + *contpos += dest->numchildren; + for (i = 0, cn = dtd->scaffold[src_node].firstchild; + i < dest->numchildren; + i++, cn = dtd->scaffold[cn].nextsib) { + build_node(parser, cn, &(dest->children[i]), contpos, strpos); + } + dest->name = NULL; + } +} + +static XML_Content * +build_model (XML_Parser parser) +{ + DTD * const dtd = _dtd; /* save one level of indirection */ + XML_Content *ret; + XML_Content *cpos; + XML_Char * str; + int allocsize = (dtd->scaffCount * sizeof(XML_Content) + + (dtd->contentStringLen * sizeof(XML_Char))); + + ret = (XML_Content *)MALLOC(allocsize); + if (!ret) + return NULL; + + str = (XML_Char *) (&ret[dtd->scaffCount]); + cpos = &ret[1]; + + build_node(parser, 0, ret, &cpos, &str); + return ret; +} + +static ELEMENT_TYPE * +getElementType(XML_Parser parser, + const ENCODING *enc, + const char *ptr, + const char *end) +{ + DTD * const dtd = _dtd; /* save one level of indirection */ + const XML_Char *name = poolStoreString(&dtd->pool, enc, ptr, end); + ELEMENT_TYPE *ret; + + if (!name) + return NULL; + ret = (ELEMENT_TYPE *) lookup(&dtd->elementTypes, name, sizeof(ELEMENT_TYPE)); + if (!ret) + return NULL; + if (ret->name != name) + poolDiscard(&dtd->pool); + else { + poolFinish(&dtd->pool); + if (!setElementTypePrefix(parser, ret)) + return NULL; + } + return ret; +} diff --git a/gdcm/Utilities/gdcmexpat/lib/xmlrole.c b/gdcm/Utilities/gdcmexpat/lib/xmlrole.c new file mode 100644 index 0000000..3782f1e --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/lib/xmlrole.c @@ -0,0 +1,1330 @@ +/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +#include + +#ifdef COMPILED_FROM_DSP +#include "winconfig.h" +#elif defined(MACOS_CLASSIC) +#include "macconfig.h" +#elif defined(__amigaos4__) +#include "amigaconfig.h" +#else +#ifdef HAVE_EXPAT_CONFIG_H +#include +#endif +#endif /* ndef COMPILED_FROM_DSP */ + +#include "expat_external.h" +#include "internal.h" +#include "xmlrole.h" +#include "ascii.h" + +/* Doesn't check: + + that ,| are not mixed in a model group + content of literals + +*/ + +static const char KW_ANY[] = { + ASCII_A, ASCII_N, ASCII_Y, '\0' }; +static const char KW_ATTLIST[] = { + ASCII_A, ASCII_T, ASCII_T, ASCII_L, ASCII_I, ASCII_S, ASCII_T, '\0' }; +static const char KW_CDATA[] = { + ASCII_C, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' }; +static const char KW_DOCTYPE[] = { + ASCII_D, ASCII_O, ASCII_C, ASCII_T, ASCII_Y, ASCII_P, ASCII_E, '\0' }; +static const char KW_ELEMENT[] = { + ASCII_E, ASCII_L, ASCII_E, ASCII_M, ASCII_E, ASCII_N, ASCII_T, '\0' }; +static const char KW_EMPTY[] = { + ASCII_E, ASCII_M, ASCII_P, ASCII_T, ASCII_Y, '\0' }; +static const char KW_ENTITIES[] = { + ASCII_E, ASCII_N, ASCII_T, ASCII_I, ASCII_T, ASCII_I, ASCII_E, ASCII_S, + '\0' }; +static const char KW_ENTITY[] = { + ASCII_E, ASCII_N, ASCII_T, ASCII_I, ASCII_T, ASCII_Y, '\0' }; +static const char KW_FIXED[] = { + ASCII_F, ASCII_I, ASCII_X, ASCII_E, ASCII_D, '\0' }; +static const char KW_ID[] = { + ASCII_I, ASCII_D, '\0' }; +static const char KW_IDREF[] = { + ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, '\0' }; +static const char KW_IDREFS[] = { + ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, ASCII_S, '\0' }; +static const char KW_IGNORE[] = { + ASCII_I, ASCII_G, ASCII_N, ASCII_O, ASCII_R, ASCII_E, '\0' }; +static const char KW_IMPLIED[] = { + ASCII_I, ASCII_M, ASCII_P, ASCII_L, ASCII_I, ASCII_E, ASCII_D, '\0' }; +static const char KW_INCLUDE[] = { + ASCII_I, ASCII_N, ASCII_C, ASCII_L, ASCII_U, ASCII_D, ASCII_E, '\0' }; +static const char KW_NDATA[] = { + ASCII_N, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' }; +static const char KW_NMTOKEN[] = { + ASCII_N, ASCII_M, ASCII_T, ASCII_O, ASCII_K, ASCII_E, ASCII_N, '\0' }; +static const char KW_NMTOKENS[] = { + ASCII_N, ASCII_M, ASCII_T, ASCII_O, ASCII_K, ASCII_E, ASCII_N, ASCII_S, + '\0' }; +static const char KW_NOTATION[] = + { ASCII_N, ASCII_O, ASCII_T, ASCII_A, ASCII_T, ASCII_I, ASCII_O, ASCII_N, + '\0' }; +static const char KW_PCDATA[] = { + ASCII_P, ASCII_C, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' }; +static const char KW_PUBLIC[] = { + ASCII_P, ASCII_U, ASCII_B, ASCII_L, ASCII_I, ASCII_C, '\0' }; +static const char KW_REQUIRED[] = { + ASCII_R, ASCII_E, ASCII_Q, ASCII_U, ASCII_I, ASCII_R, ASCII_E, ASCII_D, + '\0' }; +static const char KW_SYSTEM[] = { + ASCII_S, ASCII_Y, ASCII_S, ASCII_T, ASCII_E, ASCII_M, '\0' }; + +#ifndef MIN_BYTES_PER_CHAR +#define MIN_BYTES_PER_CHAR(enc) ((enc)->minBytesPerChar) +#endif + +#ifdef XML_DTD +#define setTopLevel(state) \ + ((state)->handler = ((state)->documentEntity \ + ? internalSubset \ + : externalSubset1)) +#else /* not XML_DTD */ +#define setTopLevel(state) ((state)->handler = internalSubset) +#endif /* not XML_DTD */ + +typedef int PTRCALL PROLOG_HANDLER(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc); + +static PROLOG_HANDLER + prolog0, prolog1, prolog2, + doctype0, doctype1, doctype2, doctype3, doctype4, doctype5, + internalSubset, + entity0, entity1, entity2, entity3, entity4, entity5, entity6, + entity7, entity8, entity9, entity10, + notation0, notation1, notation2, notation3, notation4, + attlist0, attlist1, attlist2, attlist3, attlist4, attlist5, attlist6, + attlist7, attlist8, attlist9, + element0, element1, element2, element3, element4, element5, element6, + element7, +#ifdef XML_DTD + externalSubset0, externalSubset1, + condSect0, condSect1, condSect2, +#endif /* XML_DTD */ + declClose, + error; + +static int FASTCALL common(PROLOG_STATE *state, int tok); + +static int PTRCALL +prolog0(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + state->handler = prolog1; + return XML_ROLE_NONE; + case XML_TOK_XML_DECL: + state->handler = prolog1; + return XML_ROLE_XML_DECL; + case XML_TOK_PI: + state->handler = prolog1; + return XML_ROLE_PI; + case XML_TOK_COMMENT: + state->handler = prolog1; + return XML_ROLE_COMMENT; + case XML_TOK_BOM: + return XML_ROLE_NONE; + case XML_TOK_DECL_OPEN: + if (!XmlNameMatchesAscii(enc, + ptr + 2 * MIN_BYTES_PER_CHAR(enc), + end, + KW_DOCTYPE)) + break; + state->handler = doctype0; + return XML_ROLE_DOCTYPE_NONE; + case XML_TOK_INSTANCE_START: + state->handler = error; + return XML_ROLE_INSTANCE_START; + } + return common(state, tok); +} + +static int PTRCALL +prolog1(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_PI: + return XML_ROLE_PI; + case XML_TOK_COMMENT: + return XML_ROLE_COMMENT; + case XML_TOK_BOM: + return XML_ROLE_NONE; + case XML_TOK_DECL_OPEN: + if (!XmlNameMatchesAscii(enc, + ptr + 2 * MIN_BYTES_PER_CHAR(enc), + end, + KW_DOCTYPE)) + break; + state->handler = doctype0; + return XML_ROLE_DOCTYPE_NONE; + case XML_TOK_INSTANCE_START: + state->handler = error; + return XML_ROLE_INSTANCE_START; + } + return common(state, tok); +} + +static int PTRCALL +prolog2(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_PI: + return XML_ROLE_PI; + case XML_TOK_COMMENT: + return XML_ROLE_COMMENT; + case XML_TOK_INSTANCE_START: + state->handler = error; + return XML_ROLE_INSTANCE_START; + } + return common(state, tok); +} + +static int PTRCALL +doctype0(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_DOCTYPE_NONE; + case XML_TOK_NAME: + case XML_TOK_PREFIXED_NAME: + state->handler = doctype1; + return XML_ROLE_DOCTYPE_NAME; + } + return common(state, tok); +} + +static int PTRCALL +doctype1(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_DOCTYPE_NONE; + case XML_TOK_OPEN_BRACKET: + state->handler = internalSubset; + return XML_ROLE_DOCTYPE_INTERNAL_SUBSET; + case XML_TOK_DECL_CLOSE: + state->handler = prolog2; + return XML_ROLE_DOCTYPE_CLOSE; + case XML_TOK_NAME: + if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) { + state->handler = doctype3; + return XML_ROLE_DOCTYPE_NONE; + } + if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) { + state->handler = doctype2; + return XML_ROLE_DOCTYPE_NONE; + } + break; + } + return common(state, tok); +} + +static int PTRCALL +doctype2(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_DOCTYPE_NONE; + case XML_TOK_LITERAL: + state->handler = doctype3; + return XML_ROLE_DOCTYPE_PUBLIC_ID; + } + return common(state, tok); +} + +static int PTRCALL +doctype3(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_DOCTYPE_NONE; + case XML_TOK_LITERAL: + state->handler = doctype4; + return XML_ROLE_DOCTYPE_SYSTEM_ID; + } + return common(state, tok); +} + +static int PTRCALL +doctype4(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_DOCTYPE_NONE; + case XML_TOK_OPEN_BRACKET: + state->handler = internalSubset; + return XML_ROLE_DOCTYPE_INTERNAL_SUBSET; + case XML_TOK_DECL_CLOSE: + state->handler = prolog2; + return XML_ROLE_DOCTYPE_CLOSE; + } + return common(state, tok); +} + +static int PTRCALL +doctype5(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_DOCTYPE_NONE; + case XML_TOK_DECL_CLOSE: + state->handler = prolog2; + return XML_ROLE_DOCTYPE_CLOSE; + } + return common(state, tok); +} + +static int PTRCALL +internalSubset(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_DECL_OPEN: + if (XmlNameMatchesAscii(enc, + ptr + 2 * MIN_BYTES_PER_CHAR(enc), + end, + KW_ENTITY)) { + state->handler = entity0; + return XML_ROLE_ENTITY_NONE; + } + if (XmlNameMatchesAscii(enc, + ptr + 2 * MIN_BYTES_PER_CHAR(enc), + end, + KW_ATTLIST)) { + state->handler = attlist0; + return XML_ROLE_ATTLIST_NONE; + } + if (XmlNameMatchesAscii(enc, + ptr + 2 * MIN_BYTES_PER_CHAR(enc), + end, + KW_ELEMENT)) { + state->handler = element0; + return XML_ROLE_ELEMENT_NONE; + } + if (XmlNameMatchesAscii(enc, + ptr + 2 * MIN_BYTES_PER_CHAR(enc), + end, + KW_NOTATION)) { + state->handler = notation0; + return XML_ROLE_NOTATION_NONE; + } + break; + case XML_TOK_PI: + return XML_ROLE_PI; + case XML_TOK_COMMENT: + return XML_ROLE_COMMENT; + case XML_TOK_PARAM_ENTITY_REF: + return XML_ROLE_PARAM_ENTITY_REF; + case XML_TOK_CLOSE_BRACKET: + state->handler = doctype5; + return XML_ROLE_DOCTYPE_NONE; + case XML_TOK_NONE: + return XML_ROLE_NONE; + } + return common(state, tok); +} + +#ifdef XML_DTD + +static int PTRCALL +externalSubset0(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + state->handler = externalSubset1; + if (tok == XML_TOK_XML_DECL) + return XML_ROLE_TEXT_DECL; + return externalSubset1(state, tok, ptr, end, enc); +} + +static int PTRCALL +externalSubset1(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_COND_SECT_OPEN: + state->handler = condSect0; + return XML_ROLE_NONE; + case XML_TOK_COND_SECT_CLOSE: + if (state->includeLevel == 0) + break; + state->includeLevel -= 1; + return XML_ROLE_NONE; + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_CLOSE_BRACKET: + break; + case XML_TOK_NONE: + if (state->includeLevel) + break; + return XML_ROLE_NONE; + default: + return internalSubset(state, tok, ptr, end, enc); + } + return common(state, tok); +} + +#endif /* XML_DTD */ + +static int PTRCALL +entity0(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ENTITY_NONE; + case XML_TOK_PERCENT: + state->handler = entity1; + return XML_ROLE_ENTITY_NONE; + case XML_TOK_NAME: + state->handler = entity2; + return XML_ROLE_GENERAL_ENTITY_NAME; + } + return common(state, tok); +} + +static int PTRCALL +entity1(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ENTITY_NONE; + case XML_TOK_NAME: + state->handler = entity7; + return XML_ROLE_PARAM_ENTITY_NAME; + } + return common(state, tok); +} + +static int PTRCALL +entity2(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ENTITY_NONE; + case XML_TOK_NAME: + if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) { + state->handler = entity4; + return XML_ROLE_ENTITY_NONE; + } + if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) { + state->handler = entity3; + return XML_ROLE_ENTITY_NONE; + } + break; + case XML_TOK_LITERAL: + state->handler = declClose; + state->role_none = XML_ROLE_ENTITY_NONE; + return XML_ROLE_ENTITY_VALUE; + } + return common(state, tok); +} + +static int PTRCALL +entity3(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ENTITY_NONE; + case XML_TOK_LITERAL: + state->handler = entity4; + return XML_ROLE_ENTITY_PUBLIC_ID; + } + return common(state, tok); +} + +static int PTRCALL +entity4(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ENTITY_NONE; + case XML_TOK_LITERAL: + state->handler = entity5; + return XML_ROLE_ENTITY_SYSTEM_ID; + } + return common(state, tok); +} + +static int PTRCALL +entity5(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ENTITY_NONE; + case XML_TOK_DECL_CLOSE: + setTopLevel(state); + return XML_ROLE_ENTITY_COMPLETE; + case XML_TOK_NAME: + if (XmlNameMatchesAscii(enc, ptr, end, KW_NDATA)) { + state->handler = entity6; + return XML_ROLE_ENTITY_NONE; + } + break; + } + return common(state, tok); +} + +static int PTRCALL +entity6(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ENTITY_NONE; + case XML_TOK_NAME: + state->handler = declClose; + state->role_none = XML_ROLE_ENTITY_NONE; + return XML_ROLE_ENTITY_NOTATION_NAME; + } + return common(state, tok); +} + +static int PTRCALL +entity7(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ENTITY_NONE; + case XML_TOK_NAME: + if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) { + state->handler = entity9; + return XML_ROLE_ENTITY_NONE; + } + if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) { + state->handler = entity8; + return XML_ROLE_ENTITY_NONE; + } + break; + case XML_TOK_LITERAL: + state->handler = declClose; + state->role_none = XML_ROLE_ENTITY_NONE; + return XML_ROLE_ENTITY_VALUE; + } + return common(state, tok); +} + +static int PTRCALL +entity8(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ENTITY_NONE; + case XML_TOK_LITERAL: + state->handler = entity9; + return XML_ROLE_ENTITY_PUBLIC_ID; + } + return common(state, tok); +} + +static int PTRCALL +entity9(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ENTITY_NONE; + case XML_TOK_LITERAL: + state->handler = entity10; + return XML_ROLE_ENTITY_SYSTEM_ID; + } + return common(state, tok); +} + +static int PTRCALL +entity10(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ENTITY_NONE; + case XML_TOK_DECL_CLOSE: + setTopLevel(state); + return XML_ROLE_ENTITY_COMPLETE; + } + return common(state, tok); +} + +static int PTRCALL +notation0(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NOTATION_NONE; + case XML_TOK_NAME: + state->handler = notation1; + return XML_ROLE_NOTATION_NAME; + } + return common(state, tok); +} + +static int PTRCALL +notation1(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NOTATION_NONE; + case XML_TOK_NAME: + if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) { + state->handler = notation3; + return XML_ROLE_NOTATION_NONE; + } + if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) { + state->handler = notation2; + return XML_ROLE_NOTATION_NONE; + } + break; + } + return common(state, tok); +} + +static int PTRCALL +notation2(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NOTATION_NONE; + case XML_TOK_LITERAL: + state->handler = notation4; + return XML_ROLE_NOTATION_PUBLIC_ID; + } + return common(state, tok); +} + +static int PTRCALL +notation3(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NOTATION_NONE; + case XML_TOK_LITERAL: + state->handler = declClose; + state->role_none = XML_ROLE_NOTATION_NONE; + return XML_ROLE_NOTATION_SYSTEM_ID; + } + return common(state, tok); +} + +static int PTRCALL +notation4(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NOTATION_NONE; + case XML_TOK_LITERAL: + state->handler = declClose; + state->role_none = XML_ROLE_NOTATION_NONE; + return XML_ROLE_NOTATION_SYSTEM_ID; + case XML_TOK_DECL_CLOSE: + setTopLevel(state); + return XML_ROLE_NOTATION_NO_SYSTEM_ID; + } + return common(state, tok); +} + +static int PTRCALL +attlist0(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_NAME: + case XML_TOK_PREFIXED_NAME: + state->handler = attlist1; + return XML_ROLE_ATTLIST_ELEMENT_NAME; + } + return common(state, tok); +} + +static int PTRCALL +attlist1(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_DECL_CLOSE: + setTopLevel(state); + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_NAME: + case XML_TOK_PREFIXED_NAME: + state->handler = attlist2; + return XML_ROLE_ATTRIBUTE_NAME; + } + return common(state, tok); +} + +static int PTRCALL +attlist2(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_NAME: + { + static const char * const types[] = { + KW_CDATA, + KW_ID, + KW_IDREF, + KW_IDREFS, + KW_ENTITY, + KW_ENTITIES, + KW_NMTOKEN, + KW_NMTOKENS, + }; + int i; + for (i = 0; i < (int)(sizeof(types)/sizeof(types[0])); i++) + if (XmlNameMatchesAscii(enc, ptr, end, types[i])) { + state->handler = attlist8; + return XML_ROLE_ATTRIBUTE_TYPE_CDATA + i; + } + } + if (XmlNameMatchesAscii(enc, ptr, end, KW_NOTATION)) { + state->handler = attlist5; + return XML_ROLE_ATTLIST_NONE; + } + break; + case XML_TOK_OPEN_PAREN: + state->handler = attlist3; + return XML_ROLE_ATTLIST_NONE; + } + return common(state, tok); +} + +static int PTRCALL +attlist3(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_NMTOKEN: + case XML_TOK_NAME: + case XML_TOK_PREFIXED_NAME: + state->handler = attlist4; + return XML_ROLE_ATTRIBUTE_ENUM_VALUE; + } + return common(state, tok); +} + +static int PTRCALL +attlist4(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_CLOSE_PAREN: + state->handler = attlist8; + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_OR: + state->handler = attlist3; + return XML_ROLE_ATTLIST_NONE; + } + return common(state, tok); +} + +static int PTRCALL +attlist5(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_OPEN_PAREN: + state->handler = attlist6; + return XML_ROLE_ATTLIST_NONE; + } + return common(state, tok); +} + +static int PTRCALL +attlist6(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_NAME: + state->handler = attlist7; + return XML_ROLE_ATTRIBUTE_NOTATION_VALUE; + } + return common(state, tok); +} + +static int PTRCALL +attlist7(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_CLOSE_PAREN: + state->handler = attlist8; + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_OR: + state->handler = attlist6; + return XML_ROLE_ATTLIST_NONE; + } + return common(state, tok); +} + +/* default value */ +static int PTRCALL +attlist8(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_POUND_NAME: + if (XmlNameMatchesAscii(enc, + ptr + MIN_BYTES_PER_CHAR(enc), + end, + KW_IMPLIED)) { + state->handler = attlist1; + return XML_ROLE_IMPLIED_ATTRIBUTE_VALUE; + } + if (XmlNameMatchesAscii(enc, + ptr + MIN_BYTES_PER_CHAR(enc), + end, + KW_REQUIRED)) { + state->handler = attlist1; + return XML_ROLE_REQUIRED_ATTRIBUTE_VALUE; + } + if (XmlNameMatchesAscii(enc, + ptr + MIN_BYTES_PER_CHAR(enc), + end, + KW_FIXED)) { + state->handler = attlist9; + return XML_ROLE_ATTLIST_NONE; + } + break; + case XML_TOK_LITERAL: + state->handler = attlist1; + return XML_ROLE_DEFAULT_ATTRIBUTE_VALUE; + } + return common(state, tok); +} + +static int PTRCALL +attlist9(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_LITERAL: + state->handler = attlist1; + return XML_ROLE_FIXED_ATTRIBUTE_VALUE; + } + return common(state, tok); +} + +static int PTRCALL +element0(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ELEMENT_NONE; + case XML_TOK_NAME: + case XML_TOK_PREFIXED_NAME: + state->handler = element1; + return XML_ROLE_ELEMENT_NAME; + } + return common(state, tok); +} + +static int PTRCALL +element1(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ELEMENT_NONE; + case XML_TOK_NAME: + if (XmlNameMatchesAscii(enc, ptr, end, KW_EMPTY)) { + state->handler = declClose; + state->role_none = XML_ROLE_ELEMENT_NONE; + return XML_ROLE_CONTENT_EMPTY; + } + if (XmlNameMatchesAscii(enc, ptr, end, KW_ANY)) { + state->handler = declClose; + state->role_none = XML_ROLE_ELEMENT_NONE; + return XML_ROLE_CONTENT_ANY; + } + break; + case XML_TOK_OPEN_PAREN: + state->handler = element2; + state->level = 1; + return XML_ROLE_GROUP_OPEN; + } + return common(state, tok); +} + +static int PTRCALL +element2(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ELEMENT_NONE; + case XML_TOK_POUND_NAME: + if (XmlNameMatchesAscii(enc, + ptr + MIN_BYTES_PER_CHAR(enc), + end, + KW_PCDATA)) { + state->handler = element3; + return XML_ROLE_CONTENT_PCDATA; + } + break; + case XML_TOK_OPEN_PAREN: + state->level = 2; + state->handler = element6; + return XML_ROLE_GROUP_OPEN; + case XML_TOK_NAME: + case XML_TOK_PREFIXED_NAME: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT; + case XML_TOK_NAME_QUESTION: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT_OPT; + case XML_TOK_NAME_ASTERISK: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT_REP; + case XML_TOK_NAME_PLUS: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT_PLUS; + } + return common(state, tok); +} + +static int PTRCALL +element3(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ELEMENT_NONE; + case XML_TOK_CLOSE_PAREN: + state->handler = declClose; + state->role_none = XML_ROLE_ELEMENT_NONE; + return XML_ROLE_GROUP_CLOSE; + case XML_TOK_CLOSE_PAREN_ASTERISK: + state->handler = declClose; + state->role_none = XML_ROLE_ELEMENT_NONE; + return XML_ROLE_GROUP_CLOSE_REP; + case XML_TOK_OR: + state->handler = element4; + return XML_ROLE_ELEMENT_NONE; + } + return common(state, tok); +} + +static int PTRCALL +element4(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ELEMENT_NONE; + case XML_TOK_NAME: + case XML_TOK_PREFIXED_NAME: + state->handler = element5; + return XML_ROLE_CONTENT_ELEMENT; + } + return common(state, tok); +} + +static int PTRCALL +element5(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ELEMENT_NONE; + case XML_TOK_CLOSE_PAREN_ASTERISK: + state->handler = declClose; + state->role_none = XML_ROLE_ELEMENT_NONE; + return XML_ROLE_GROUP_CLOSE_REP; + case XML_TOK_OR: + state->handler = element4; + return XML_ROLE_ELEMENT_NONE; + } + return common(state, tok); +} + +static int PTRCALL +element6(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ELEMENT_NONE; + case XML_TOK_OPEN_PAREN: + state->level += 1; + return XML_ROLE_GROUP_OPEN; + case XML_TOK_NAME: + case XML_TOK_PREFIXED_NAME: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT; + case XML_TOK_NAME_QUESTION: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT_OPT; + case XML_TOK_NAME_ASTERISK: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT_REP; + case XML_TOK_NAME_PLUS: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT_PLUS; + } + return common(state, tok); +} + +static int PTRCALL +element7(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ELEMENT_NONE; + case XML_TOK_CLOSE_PAREN: + state->level -= 1; + if (state->level == 0) { + state->handler = declClose; + state->role_none = XML_ROLE_ELEMENT_NONE; + } + return XML_ROLE_GROUP_CLOSE; + case XML_TOK_CLOSE_PAREN_ASTERISK: + state->level -= 1; + if (state->level == 0) { + state->handler = declClose; + state->role_none = XML_ROLE_ELEMENT_NONE; + } + return XML_ROLE_GROUP_CLOSE_REP; + case XML_TOK_CLOSE_PAREN_QUESTION: + state->level -= 1; + if (state->level == 0) { + state->handler = declClose; + state->role_none = XML_ROLE_ELEMENT_NONE; + } + return XML_ROLE_GROUP_CLOSE_OPT; + case XML_TOK_CLOSE_PAREN_PLUS: + state->level -= 1; + if (state->level == 0) { + state->handler = declClose; + state->role_none = XML_ROLE_ELEMENT_NONE; + } + return XML_ROLE_GROUP_CLOSE_PLUS; + case XML_TOK_COMMA: + state->handler = element6; + return XML_ROLE_GROUP_SEQUENCE; + case XML_TOK_OR: + state->handler = element6; + return XML_ROLE_GROUP_CHOICE; + } + return common(state, tok); +} + +#ifdef XML_DTD + +static int PTRCALL +condSect0(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_NAME: + if (XmlNameMatchesAscii(enc, ptr, end, KW_INCLUDE)) { + state->handler = condSect1; + return XML_ROLE_NONE; + } + if (XmlNameMatchesAscii(enc, ptr, end, KW_IGNORE)) { + state->handler = condSect2; + return XML_ROLE_NONE; + } + break; + } + return common(state, tok); +} + +static int PTRCALL +condSect1(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_OPEN_BRACKET: + state->handler = externalSubset1; + state->includeLevel += 1; + return XML_ROLE_NONE; + } + return common(state, tok); +} + +static int PTRCALL +condSect2(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_OPEN_BRACKET: + state->handler = externalSubset1; + return XML_ROLE_IGNORE_SECT; + } + return common(state, tok); +} + +#endif /* XML_DTD */ + +static int PTRCALL +declClose(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return state->role_none; + case XML_TOK_DECL_CLOSE: + setTopLevel(state); + return state->role_none; + } + return common(state, tok); +} + +static int PTRCALL +error(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + return XML_ROLE_NONE; +} + +static int FASTCALL +common(PROLOG_STATE *state, int tok) +{ +#ifdef XML_DTD + if (!state->documentEntity && tok == XML_TOK_PARAM_ENTITY_REF) + return XML_ROLE_INNER_PARAM_ENTITY_REF; +#endif + state->handler = error; + return XML_ROLE_ERROR; +} + +void +XmlPrologStateInit(PROLOG_STATE *state) +{ + state->handler = prolog0; +#ifdef XML_DTD + state->documentEntity = 1; + state->includeLevel = 0; + state->inEntityValue = 0; +#endif /* XML_DTD */ +} + +#ifdef XML_DTD + +void +XmlPrologStateInitExternalEntity(PROLOG_STATE *state) +{ + state->handler = externalSubset0; + state->documentEntity = 0; + state->includeLevel = 0; +} + +#endif /* XML_DTD */ diff --git a/gdcm/Utilities/gdcmexpat/lib/xmlrole.h b/gdcm/Utilities/gdcmexpat/lib/xmlrole.h new file mode 100644 index 0000000..4dd9f06 --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/lib/xmlrole.h @@ -0,0 +1,114 @@ +/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +#ifndef XmlRole_INCLUDED +#define XmlRole_INCLUDED 1 + +#ifdef __VMS +/* 0 1 2 3 0 1 2 3 + 1234567890123456789012345678901 1234567890123456789012345678901 */ +#define XmlPrologStateInitExternalEntity XmlPrologStateInitExternalEnt +#endif + +#include "xmltok.h" + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + XML_ROLE_ERROR = -1, + XML_ROLE_NONE = 0, + XML_ROLE_XML_DECL, + XML_ROLE_INSTANCE_START, + XML_ROLE_DOCTYPE_NONE, + XML_ROLE_DOCTYPE_NAME, + XML_ROLE_DOCTYPE_SYSTEM_ID, + XML_ROLE_DOCTYPE_PUBLIC_ID, + XML_ROLE_DOCTYPE_INTERNAL_SUBSET, + XML_ROLE_DOCTYPE_CLOSE, + XML_ROLE_GENERAL_ENTITY_NAME, + XML_ROLE_PARAM_ENTITY_NAME, + XML_ROLE_ENTITY_NONE, + XML_ROLE_ENTITY_VALUE, + XML_ROLE_ENTITY_SYSTEM_ID, + XML_ROLE_ENTITY_PUBLIC_ID, + XML_ROLE_ENTITY_COMPLETE, + XML_ROLE_ENTITY_NOTATION_NAME, + XML_ROLE_NOTATION_NONE, + XML_ROLE_NOTATION_NAME, + XML_ROLE_NOTATION_SYSTEM_ID, + XML_ROLE_NOTATION_NO_SYSTEM_ID, + XML_ROLE_NOTATION_PUBLIC_ID, + XML_ROLE_ATTRIBUTE_NAME, + XML_ROLE_ATTRIBUTE_TYPE_CDATA, + XML_ROLE_ATTRIBUTE_TYPE_ID, + XML_ROLE_ATTRIBUTE_TYPE_IDREF, + XML_ROLE_ATTRIBUTE_TYPE_IDREFS, + XML_ROLE_ATTRIBUTE_TYPE_ENTITY, + XML_ROLE_ATTRIBUTE_TYPE_ENTITIES, + XML_ROLE_ATTRIBUTE_TYPE_NMTOKEN, + XML_ROLE_ATTRIBUTE_TYPE_NMTOKENS, + XML_ROLE_ATTRIBUTE_ENUM_VALUE, + XML_ROLE_ATTRIBUTE_NOTATION_VALUE, + XML_ROLE_ATTLIST_NONE, + XML_ROLE_ATTLIST_ELEMENT_NAME, + XML_ROLE_IMPLIED_ATTRIBUTE_VALUE, + XML_ROLE_REQUIRED_ATTRIBUTE_VALUE, + XML_ROLE_DEFAULT_ATTRIBUTE_VALUE, + XML_ROLE_FIXED_ATTRIBUTE_VALUE, + XML_ROLE_ELEMENT_NONE, + XML_ROLE_ELEMENT_NAME, + XML_ROLE_CONTENT_ANY, + XML_ROLE_CONTENT_EMPTY, + XML_ROLE_CONTENT_PCDATA, + XML_ROLE_GROUP_OPEN, + XML_ROLE_GROUP_CLOSE, + XML_ROLE_GROUP_CLOSE_REP, + XML_ROLE_GROUP_CLOSE_OPT, + XML_ROLE_GROUP_CLOSE_PLUS, + XML_ROLE_GROUP_CHOICE, + XML_ROLE_GROUP_SEQUENCE, + XML_ROLE_CONTENT_ELEMENT, + XML_ROLE_CONTENT_ELEMENT_REP, + XML_ROLE_CONTENT_ELEMENT_OPT, + XML_ROLE_CONTENT_ELEMENT_PLUS, + XML_ROLE_PI, + XML_ROLE_COMMENT, +#ifdef XML_DTD + XML_ROLE_TEXT_DECL, + XML_ROLE_IGNORE_SECT, + XML_ROLE_INNER_PARAM_ENTITY_REF, +#endif /* XML_DTD */ + XML_ROLE_PARAM_ENTITY_REF +}; + +typedef struct prolog_state { + int (PTRCALL *handler) (struct prolog_state *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc); + unsigned level; + int role_none; +#ifdef XML_DTD + unsigned includeLevel; + int documentEntity; + int inEntityValue; +#endif /* XML_DTD */ +} PROLOG_STATE; + +void XmlPrologStateInit(PROLOG_STATE *); +#ifdef XML_DTD +void XmlPrologStateInitExternalEntity(PROLOG_STATE *); +#endif /* XML_DTD */ + +#define XmlTokenRole(state, tok, ptr, end, enc) \ + (((state)->handler)(state, tok, ptr, end, enc)) + +#ifdef __cplusplus +} +#endif + +#endif /* not XmlRole_INCLUDED */ diff --git a/gdcm/Utilities/gdcmexpat/lib/xmltok.c b/gdcm/Utilities/gdcmexpat/lib/xmltok.c new file mode 100644 index 0000000..26cee4d --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/lib/xmltok.c @@ -0,0 +1,1639 @@ +/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +#include + +#ifdef COMPILED_FROM_DSP +#include "winconfig.h" +#elif defined(MACOS_CLASSIC) +#include "macconfig.h" +#elif defined(__amigaos4__) +#include "amigaconfig.h" +#else +#ifdef HAVE_EXPAT_CONFIG_H +#include +#endif +#endif /* ndef COMPILED_FROM_DSP */ + +#include "expat_external.h" +#include "internal.h" +#include "xmltok.h" +#include "nametab.h" + +#ifdef XML_DTD +#define IGNORE_SECTION_TOK_VTABLE , PREFIX(ignoreSectionTok) +#else +#define IGNORE_SECTION_TOK_VTABLE /* as nothing */ +#endif + +#define VTABLE1 \ + { PREFIX(prologTok), PREFIX(contentTok), \ + PREFIX(cdataSectionTok) IGNORE_SECTION_TOK_VTABLE }, \ + { PREFIX(attributeValueTok), PREFIX(entityValueTok) }, \ + PREFIX(sameName), \ + PREFIX(nameMatchesAscii), \ + PREFIX(nameLength), \ + PREFIX(skipS), \ + PREFIX(getAtts), \ + PREFIX(charRefNumber), \ + PREFIX(predefinedEntityName), \ + PREFIX(updatePosition), \ + PREFIX(isPublicId) + +#define VTABLE VTABLE1, PREFIX(toUtf8), PREFIX(toUtf16) + +#define UCS2_GET_NAMING(pages, hi, lo) \ + (namingBitmap[(pages[hi] << 3) + ((lo) >> 5)] & (1 << ((lo) & 0x1F))) + +/* A 2 byte UTF-8 representation splits the characters 11 bits between + the bottom 5 and 6 bits of the bytes. We need 8 bits to index into + pages, 3 bits to add to that index and 5 bits to generate the mask. +*/ +#define UTF8_GET_NAMING2(pages, byte) \ + (namingBitmap[((pages)[(((byte)[0]) >> 2) & 7] << 3) \ + + ((((byte)[0]) & 3) << 1) \ + + ((((byte)[1]) >> 5) & 1)] \ + & (1 << (((byte)[1]) & 0x1F))) + +/* A 3 byte UTF-8 representation splits the characters 16 bits between + the bottom 4, 6 and 6 bits of the bytes. We need 8 bits to index + into pages, 3 bits to add to that index and 5 bits to generate the + mask. +*/ +#define UTF8_GET_NAMING3(pages, byte) \ + (namingBitmap[((pages)[((((byte)[0]) & 0xF) << 4) \ + + ((((byte)[1]) >> 2) & 0xF)] \ + << 3) \ + + ((((byte)[1]) & 3) << 1) \ + + ((((byte)[2]) >> 5) & 1)] \ + & (1 << (((byte)[2]) & 0x1F))) + +#define UTF8_GET_NAMING(pages, p, n) \ + ((n) == 2 \ + ? UTF8_GET_NAMING2(pages, (const unsigned char *)(p)) \ + : ((n) == 3 \ + ? UTF8_GET_NAMING3(pages, (const unsigned char *)(p)) \ + : 0)) + +/* Detection of invalid UTF-8 sequences is based on Table 3.1B + of Unicode 3.2: http://www.unicode.org/unicode/reports/tr28/ + with the additional restriction of not allowing the Unicode + code points 0xFFFF and 0xFFFE (sequences EF,BF,BF and EF,BF,BE). + Implementation details: + (A & 0x80) == 0 means A < 0x80 + and + (A & 0xC0) == 0xC0 means A > 0xBF +*/ + +#define UTF8_INVALID2(p) \ + ((*p) < 0xC2 || ((p)[1] & 0x80) == 0 || ((p)[1] & 0xC0) == 0xC0) + +#define UTF8_INVALID3(p) \ + (((p)[2] & 0x80) == 0 \ + || \ + ((*p) == 0xEF && (p)[1] == 0xBF \ + ? \ + (p)[2] > 0xBD \ + : \ + ((p)[2] & 0xC0) == 0xC0) \ + || \ + ((*p) == 0xE0 \ + ? \ + (p)[1] < 0xA0 || ((p)[1] & 0xC0) == 0xC0 \ + : \ + ((p)[1] & 0x80) == 0 \ + || \ + ((*p) == 0xED ? (p)[1] > 0x9F : ((p)[1] & 0xC0) == 0xC0))) + +#define UTF8_INVALID4(p) \ + (((p)[3] & 0x80) == 0 || ((p)[3] & 0xC0) == 0xC0 \ + || \ + ((p)[2] & 0x80) == 0 || ((p)[2] & 0xC0) == 0xC0 \ + || \ + ((*p) == 0xF0 \ + ? \ + (p)[1] < 0x90 || ((p)[1] & 0xC0) == 0xC0 \ + : \ + ((p)[1] & 0x80) == 0 \ + || \ + ((*p) == 0xF4 ? (p)[1] > 0x8F : ((p)[1] & 0xC0) == 0xC0))) + +static int PTRFASTCALL +isNever(const ENCODING *enc, const char *p) +{ + return 0; +} + +static int PTRFASTCALL +utf8_isName2(const ENCODING *enc, const char *p) +{ + return UTF8_GET_NAMING2(namePages, (const unsigned char *)p); +} + +static int PTRFASTCALL +utf8_isName3(const ENCODING *enc, const char *p) +{ + return UTF8_GET_NAMING3(namePages, (const unsigned char *)p); +} + +#define utf8_isName4 isNever + +static int PTRFASTCALL +utf8_isNmstrt2(const ENCODING *enc, const char *p) +{ + return UTF8_GET_NAMING2(nmstrtPages, (const unsigned char *)p); +} + +static int PTRFASTCALL +utf8_isNmstrt3(const ENCODING *enc, const char *p) +{ + return UTF8_GET_NAMING3(nmstrtPages, (const unsigned char *)p); +} + +#define utf8_isNmstrt4 isNever + +static int PTRFASTCALL +utf8_isInvalid2(const ENCODING *enc, const char *p) +{ + return UTF8_INVALID2((const unsigned char *)p); +} + +static int PTRFASTCALL +utf8_isInvalid3(const ENCODING *enc, const char *p) +{ + return UTF8_INVALID3((const unsigned char *)p); +} + +static int PTRFASTCALL +utf8_isInvalid4(const ENCODING *enc, const char *p) +{ + return UTF8_INVALID4((const unsigned char *)p); +} + +struct normal_encoding { + ENCODING enc; + unsigned char type[256]; +#ifdef XML_MIN_SIZE + int (PTRFASTCALL *byteType)(const ENCODING *, const char *); + int (PTRFASTCALL *isNameMin)(const ENCODING *, const char *); + int (PTRFASTCALL *isNmstrtMin)(const ENCODING *, const char *); + int (PTRFASTCALL *byteToAscii)(const ENCODING *, const char *); + int (PTRCALL *charMatches)(const ENCODING *, const char *, int); +#endif /* XML_MIN_SIZE */ + int (PTRFASTCALL *isName2)(const ENCODING *, const char *); + int (PTRFASTCALL *isName3)(const ENCODING *, const char *); + int (PTRFASTCALL *isName4)(const ENCODING *, const char *); + int (PTRFASTCALL *isNmstrt2)(const ENCODING *, const char *); + int (PTRFASTCALL *isNmstrt3)(const ENCODING *, const char *); + int (PTRFASTCALL *isNmstrt4)(const ENCODING *, const char *); + int (PTRFASTCALL *isInvalid2)(const ENCODING *, const char *); + int (PTRFASTCALL *isInvalid3)(const ENCODING *, const char *); + int (PTRFASTCALL *isInvalid4)(const ENCODING *, const char *); +}; + +#define AS_NORMAL_ENCODING(enc) ((const struct normal_encoding *) (enc)) + +#ifdef XML_MIN_SIZE + +#define STANDARD_VTABLE(E) \ + E ## byteType, \ + E ## isNameMin, \ + E ## isNmstrtMin, \ + E ## byteToAscii, \ + E ## charMatches, + +#else + +#define STANDARD_VTABLE(E) /* as nothing */ + +#endif + +#define NORMAL_VTABLE(E) \ + E ## isName2, \ + E ## isName3, \ + E ## isName4, \ + E ## isNmstrt2, \ + E ## isNmstrt3, \ + E ## isNmstrt4, \ + E ## isInvalid2, \ + E ## isInvalid3, \ + E ## isInvalid4 + +static int FASTCALL checkCharRefNumber(int); + +#include "xmltok_impl.h" +#include "ascii.h" + +#ifdef XML_MIN_SIZE +#define sb_isNameMin isNever +#define sb_isNmstrtMin isNever +#endif + +#ifdef XML_MIN_SIZE +#define MINBPC(enc) ((enc)->minBytesPerChar) +#else +/* minimum bytes per character */ +#define MINBPC(enc) 1 +#endif + +#define SB_BYTE_TYPE(enc, p) \ + (((struct normal_encoding *)(enc))->type[(unsigned char)*(p)]) + +#ifdef XML_MIN_SIZE +static int PTRFASTCALL +sb_byteType(const ENCODING *enc, const char *p) +{ + return SB_BYTE_TYPE(enc, p); +} +#define BYTE_TYPE(enc, p) \ + (AS_NORMAL_ENCODING(enc)->byteType(enc, p)) +#else +#define BYTE_TYPE(enc, p) SB_BYTE_TYPE(enc, p) +#endif + +#ifdef XML_MIN_SIZE +#define BYTE_TO_ASCII(enc, p) \ + (AS_NORMAL_ENCODING(enc)->byteToAscii(enc, p)) +static int PTRFASTCALL +sb_byteToAscii(const ENCODING *enc, const char *p) +{ + return *p; +} +#else +#define BYTE_TO_ASCII(enc, p) (*(p)) +#endif + +#define IS_NAME_CHAR(enc, p, n) \ + (AS_NORMAL_ENCODING(enc)->isName ## n(enc, p)) +#define IS_NMSTRT_CHAR(enc, p, n) \ + (AS_NORMAL_ENCODING(enc)->isNmstrt ## n(enc, p)) +#define IS_INVALID_CHAR(enc, p, n) \ + (AS_NORMAL_ENCODING(enc)->isInvalid ## n(enc, p)) + +#ifdef XML_MIN_SIZE +#define IS_NAME_CHAR_MINBPC(enc, p) \ + (AS_NORMAL_ENCODING(enc)->isNameMin(enc, p)) +#define IS_NMSTRT_CHAR_MINBPC(enc, p) \ + (AS_NORMAL_ENCODING(enc)->isNmstrtMin(enc, p)) +#else +#define IS_NAME_CHAR_MINBPC(enc, p) (0) +#define IS_NMSTRT_CHAR_MINBPC(enc, p) (0) +#endif + +#ifdef XML_MIN_SIZE +#define CHAR_MATCHES(enc, p, c) \ + (AS_NORMAL_ENCODING(enc)->charMatches(enc, p, c)) +static int PTRCALL +sb_charMatches(const ENCODING *enc, const char *p, int c) +{ + return *p == c; +} +#else +/* c is an ASCII character */ +#define CHAR_MATCHES(enc, p, c) (*(p) == c) +#endif + +#define PREFIX(ident) normal_ ## ident +#include "xmltok_impl.c" + +#undef MINBPC +#undef BYTE_TYPE +#undef BYTE_TO_ASCII +#undef CHAR_MATCHES +#undef IS_NAME_CHAR +#undef IS_NAME_CHAR_MINBPC +#undef IS_NMSTRT_CHAR +#undef IS_NMSTRT_CHAR_MINBPC +#undef IS_INVALID_CHAR + +enum { /* UTF8_cvalN is value of masked first byte of N byte sequence */ + UTF8_cval1 = 0x00, + UTF8_cval2 = 0xc0, + UTF8_cval3 = 0xe0, + UTF8_cval4 = 0xf0 +}; + +static void PTRCALL +utf8_toUtf8(const ENCODING *enc, + const char **fromP, const char *fromLim, + char **toP, const char *toLim) +{ + char *to; + const char *from; + if (fromLim - *fromP > toLim - *toP) { + /* Avoid copying partial characters. */ + for (fromLim = *fromP + (toLim - *toP); fromLim > *fromP; fromLim--) + if (((unsigned char)fromLim[-1] & 0xc0) != 0x80) + break; + } + for (to = *toP, from = *fromP; from != fromLim; from++, to++) + *to = *from; + *fromP = from; + *toP = to; +} + +static void PTRCALL +utf8_toUtf16(const ENCODING *enc, + const char **fromP, const char *fromLim, + unsigned short **toP, const unsigned short *toLim) +{ + unsigned short *to = *toP; + const char *from = *fromP; + while (from != fromLim && to != toLim) { + switch (((struct normal_encoding *)enc)->type[(unsigned char)*from]) { + case BT_LEAD2: + *to++ = (unsigned short)(((from[0] & 0x1f) << 6) | (from[1] & 0x3f)); + from += 2; + break; + case BT_LEAD3: + *to++ = (unsigned short)(((from[0] & 0xf) << 12) + | ((from[1] & 0x3f) << 6) | (from[2] & 0x3f)); + from += 3; + break; + case BT_LEAD4: + { + unsigned long n; + if (to + 1 == toLim) + goto after; + n = ((from[0] & 0x7) << 18) | ((from[1] & 0x3f) << 12) + | ((from[2] & 0x3f) << 6) | (from[3] & 0x3f); + n -= 0x10000; + to[0] = (unsigned short)((n >> 10) | 0xD800); + to[1] = (unsigned short)((n & 0x3FF) | 0xDC00); + to += 2; + from += 4; + } + break; + default: + *to++ = *from++; + break; + } + } +after: + *fromP = from; + *toP = to; +} + +#ifdef XML_NS +static const struct normal_encoding utf8_encoding_ns = { + { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 }, + { +#include "asciitab.h" +#include "utf8tab.h" + }, + STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_) +}; +#endif + +static const struct normal_encoding utf8_encoding = { + { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 }, + { +#define BT_COLON BT_NMSTRT +#include "asciitab.h" +#undef BT_COLON +#include "utf8tab.h" + }, + STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_) +}; + +#ifdef XML_NS + +static const struct normal_encoding internal_utf8_encoding_ns = { + { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 }, + { +#include "iasciitab.h" +#include "utf8tab.h" + }, + STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_) +}; + +#endif + +static const struct normal_encoding internal_utf8_encoding = { + { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 }, + { +#define BT_COLON BT_NMSTRT +#include "iasciitab.h" +#undef BT_COLON +#include "utf8tab.h" + }, + STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_) +}; + +static void PTRCALL +latin1_toUtf8(const ENCODING *enc, + const char **fromP, const char *fromLim, + char **toP, const char *toLim) +{ + for (;;) { + unsigned char c; + if (*fromP == fromLim) + break; + c = (unsigned char)**fromP; + if (c & 0x80) { + if (toLim - *toP < 2) + break; + *(*toP)++ = (char)((c >> 6) | UTF8_cval2); + *(*toP)++ = (char)((c & 0x3f) | 0x80); + (*fromP)++; + } + else { + if (*toP == toLim) + break; + *(*toP)++ = *(*fromP)++; + } + } +} + +static void PTRCALL +latin1_toUtf16(const ENCODING *enc, + const char **fromP, const char *fromLim, + unsigned short **toP, const unsigned short *toLim) +{ + while (*fromP != fromLim && *toP != toLim) + *(*toP)++ = (unsigned char)*(*fromP)++; +} + +#ifdef XML_NS + +static const struct normal_encoding latin1_encoding_ns = { + { VTABLE1, latin1_toUtf8, latin1_toUtf16, 1, 0, 0 }, + { +#include "asciitab.h" +#include "latin1tab.h" + }, + STANDARD_VTABLE(sb_) +}; + +#endif + +static const struct normal_encoding latin1_encoding = { + { VTABLE1, latin1_toUtf8, latin1_toUtf16, 1, 0, 0 }, + { +#define BT_COLON BT_NMSTRT +#include "asciitab.h" +#undef BT_COLON +#include "latin1tab.h" + }, + STANDARD_VTABLE(sb_) +}; + +static void PTRCALL +ascii_toUtf8(const ENCODING *enc, + const char **fromP, const char *fromLim, + char **toP, const char *toLim) +{ + while (*fromP != fromLim && *toP != toLim) + *(*toP)++ = *(*fromP)++; +} + +#ifdef XML_NS + +static const struct normal_encoding ascii_encoding_ns = { + { VTABLE1, ascii_toUtf8, latin1_toUtf16, 1, 1, 0 }, + { +#include "asciitab.h" +/* BT_NONXML == 0 */ + }, + STANDARD_VTABLE(sb_) +}; + +#endif + +static const struct normal_encoding ascii_encoding = { + { VTABLE1, ascii_toUtf8, latin1_toUtf16, 1, 1, 0 }, + { +#define BT_COLON BT_NMSTRT +#include "asciitab.h" +#undef BT_COLON +/* BT_NONXML == 0 */ + }, + STANDARD_VTABLE(sb_) +}; + +static int PTRFASTCALL +unicode_byte_type(char hi, char lo) +{ + switch ((unsigned char)hi) { + case 0xD8: case 0xD9: case 0xDA: case 0xDB: + return BT_LEAD4; + case 0xDC: case 0xDD: case 0xDE: case 0xDF: + return BT_TRAIL; + case 0xFF: + switch ((unsigned char)lo) { + case 0xFF: + case 0xFE: + return BT_NONXML; + } + break; + } + return BT_NONASCII; +} + +#define DEFINE_UTF16_TO_UTF8(E) \ +static void PTRCALL \ +E ## toUtf8(const ENCODING *enc, \ + const char **fromP, const char *fromLim, \ + char **toP, const char *toLim) \ +{ \ + const char *from; \ + for (from = *fromP; from != fromLim; from += 2) { \ + int plane; \ + unsigned char lo2; \ + unsigned char lo = GET_LO(from); \ + unsigned char hi = GET_HI(from); \ + switch (hi) { \ + case 0: \ + if (lo < 0x80) { \ + if (*toP == toLim) { \ + *fromP = from; \ + return; \ + } \ + *(*toP)++ = lo; \ + break; \ + } \ + /* fall through */ \ + case 0x1: case 0x2: case 0x3: \ + case 0x4: case 0x5: case 0x6: case 0x7: \ + if (toLim - *toP < 2) { \ + *fromP = from; \ + return; \ + } \ + *(*toP)++ = ((lo >> 6) | (hi << 2) | UTF8_cval2); \ + *(*toP)++ = ((lo & 0x3f) | 0x80); \ + break; \ + default: \ + if (toLim - *toP < 3) { \ + *fromP = from; \ + return; \ + } \ + /* 16 bits divided 4, 6, 6 amongst 3 bytes */ \ + *(*toP)++ = ((hi >> 4) | UTF8_cval3); \ + *(*toP)++ = (((hi & 0xf) << 2) | (lo >> 6) | 0x80); \ + *(*toP)++ = ((lo & 0x3f) | 0x80); \ + break; \ + case 0xD8: case 0xD9: case 0xDA: case 0xDB: \ + if (toLim - *toP < 4) { \ + *fromP = from; \ + return; \ + } \ + plane = (((hi & 0x3) << 2) | ((lo >> 6) & 0x3)) + 1; \ + *(*toP)++ = ((plane >> 2) | UTF8_cval4); \ + *(*toP)++ = (((lo >> 2) & 0xF) | ((plane & 0x3) << 4) | 0x80); \ + from += 2; \ + lo2 = GET_LO(from); \ + *(*toP)++ = (((lo & 0x3) << 4) \ + | ((GET_HI(from) & 0x3) << 2) \ + | (lo2 >> 6) \ + | 0x80); \ + *(*toP)++ = ((lo2 & 0x3f) | 0x80); \ + break; \ + } \ + } \ + *fromP = from; \ +} + +#define DEFINE_UTF16_TO_UTF16(E) \ +static void PTRCALL \ +E ## toUtf16(const ENCODING *enc, \ + const char **fromP, const char *fromLim, \ + unsigned short **toP, const unsigned short *toLim) \ +{ \ + /* Avoid copying first half only of surrogate */ \ + if (fromLim - *fromP > ((toLim - *toP) << 1) \ + && (GET_HI(fromLim - 2) & 0xF8) == 0xD8) \ + fromLim -= 2; \ + for (; *fromP != fromLim && *toP != toLim; *fromP += 2) \ + *(*toP)++ = (GET_HI(*fromP) << 8) | GET_LO(*fromP); \ +} + +#define SET2(ptr, ch) \ + (((ptr)[0] = ((ch) & 0xff)), ((ptr)[1] = ((ch) >> 8))) +#define GET_LO(ptr) ((unsigned char)(ptr)[0]) +#define GET_HI(ptr) ((unsigned char)(ptr)[1]) + +DEFINE_UTF16_TO_UTF8(little2_) +DEFINE_UTF16_TO_UTF16(little2_) + +#undef SET2 +#undef GET_LO +#undef GET_HI + +#define SET2(ptr, ch) \ + (((ptr)[0] = ((ch) >> 8)), ((ptr)[1] = ((ch) & 0xFF))) +#define GET_LO(ptr) ((unsigned char)(ptr)[1]) +#define GET_HI(ptr) ((unsigned char)(ptr)[0]) + +DEFINE_UTF16_TO_UTF8(big2_) +DEFINE_UTF16_TO_UTF16(big2_) + +#undef SET2 +#undef GET_LO +#undef GET_HI + +#define LITTLE2_BYTE_TYPE(enc, p) \ + ((p)[1] == 0 \ + ? ((struct normal_encoding *)(enc))->type[(unsigned char)*(p)] \ + : unicode_byte_type((p)[1], (p)[0])) +#define LITTLE2_BYTE_TO_ASCII(enc, p) ((p)[1] == 0 ? (p)[0] : -1) +#define LITTLE2_CHAR_MATCHES(enc, p, c) ((p)[1] == 0 && (p)[0] == c) +#define LITTLE2_IS_NAME_CHAR_MINBPC(enc, p) \ + UCS2_GET_NAMING(namePages, (unsigned char)p[1], (unsigned char)p[0]) +#define LITTLE2_IS_NMSTRT_CHAR_MINBPC(enc, p) \ + UCS2_GET_NAMING(nmstrtPages, (unsigned char)p[1], (unsigned char)p[0]) + +#ifdef XML_MIN_SIZE + +static int PTRFASTCALL +little2_byteType(const ENCODING *enc, const char *p) +{ + return LITTLE2_BYTE_TYPE(enc, p); +} + +static int PTRFASTCALL +little2_byteToAscii(const ENCODING *enc, const char *p) +{ + return LITTLE2_BYTE_TO_ASCII(enc, p); +} + +static int PTRCALL +little2_charMatches(const ENCODING *enc, const char *p, int c) +{ + return LITTLE2_CHAR_MATCHES(enc, p, c); +} + +static int PTRFASTCALL +little2_isNameMin(const ENCODING *enc, const char *p) +{ + return LITTLE2_IS_NAME_CHAR_MINBPC(enc, p); +} + +static int PTRFASTCALL +little2_isNmstrtMin(const ENCODING *enc, const char *p) +{ + return LITTLE2_IS_NMSTRT_CHAR_MINBPC(enc, p); +} + +#undef VTABLE +#define VTABLE VTABLE1, little2_toUtf8, little2_toUtf16 + +#else /* not XML_MIN_SIZE */ + +#undef PREFIX +#define PREFIX(ident) little2_ ## ident +#define MINBPC(enc) 2 +/* CHAR_MATCHES is guaranteed to have MINBPC bytes available. */ +#define BYTE_TYPE(enc, p) LITTLE2_BYTE_TYPE(enc, p) +#define BYTE_TO_ASCII(enc, p) LITTLE2_BYTE_TO_ASCII(enc, p) +#define CHAR_MATCHES(enc, p, c) LITTLE2_CHAR_MATCHES(enc, p, c) +#define IS_NAME_CHAR(enc, p, n) 0 +#define IS_NAME_CHAR_MINBPC(enc, p) LITTLE2_IS_NAME_CHAR_MINBPC(enc, p) +#define IS_NMSTRT_CHAR(enc, p, n) (0) +#define IS_NMSTRT_CHAR_MINBPC(enc, p) LITTLE2_IS_NMSTRT_CHAR_MINBPC(enc, p) + +#include "xmltok_impl.c" + +#undef MINBPC +#undef BYTE_TYPE +#undef BYTE_TO_ASCII +#undef CHAR_MATCHES +#undef IS_NAME_CHAR +#undef IS_NAME_CHAR_MINBPC +#undef IS_NMSTRT_CHAR +#undef IS_NMSTRT_CHAR_MINBPC +#undef IS_INVALID_CHAR + +#endif /* not XML_MIN_SIZE */ + +#ifdef XML_NS + +static const struct normal_encoding little2_encoding_ns = { + { VTABLE, 2, 0, +#if BYTEORDER == 1234 + 1 +#else + 0 +#endif + }, + { +#include "asciitab.h" +#include "latin1tab.h" + }, + STANDARD_VTABLE(little2_) +}; + +#endif + +static const struct normal_encoding little2_encoding = { + { VTABLE, 2, 0, +#if BYTEORDER == 1234 + 1 +#else + 0 +#endif + }, + { +#define BT_COLON BT_NMSTRT +#include "asciitab.h" +#undef BT_COLON +#include "latin1tab.h" + }, + STANDARD_VTABLE(little2_) +}; + +#if BYTEORDER != 4321 + +#ifdef XML_NS + +static const struct normal_encoding internal_little2_encoding_ns = { + { VTABLE, 2, 0, 1 }, + { +#include "iasciitab.h" +#include "latin1tab.h" + }, + STANDARD_VTABLE(little2_) +}; + +#endif + +static const struct normal_encoding internal_little2_encoding = { + { VTABLE, 2, 0, 1 }, + { +#define BT_COLON BT_NMSTRT +#include "iasciitab.h" +#undef BT_COLON +#include "latin1tab.h" + }, + STANDARD_VTABLE(little2_) +}; + +#endif + + +#define BIG2_BYTE_TYPE(enc, p) \ + ((p)[0] == 0 \ + ? ((struct normal_encoding *)(enc))->type[(unsigned char)(p)[1]] \ + : unicode_byte_type((p)[0], (p)[1])) +#define BIG2_BYTE_TO_ASCII(enc, p) ((p)[0] == 0 ? (p)[1] : -1) +#define BIG2_CHAR_MATCHES(enc, p, c) ((p)[0] == 0 && (p)[1] == c) +#define BIG2_IS_NAME_CHAR_MINBPC(enc, p) \ + UCS2_GET_NAMING(namePages, (unsigned char)p[0], (unsigned char)p[1]) +#define BIG2_IS_NMSTRT_CHAR_MINBPC(enc, p) \ + UCS2_GET_NAMING(nmstrtPages, (unsigned char)p[0], (unsigned char)p[1]) + +#ifdef XML_MIN_SIZE + +static int PTRFASTCALL +big2_byteType(const ENCODING *enc, const char *p) +{ + return BIG2_BYTE_TYPE(enc, p); +} + +static int PTRFASTCALL +big2_byteToAscii(const ENCODING *enc, const char *p) +{ + return BIG2_BYTE_TO_ASCII(enc, p); +} + +static int PTRCALL +big2_charMatches(const ENCODING *enc, const char *p, int c) +{ + return BIG2_CHAR_MATCHES(enc, p, c); +} + +static int PTRFASTCALL +big2_isNameMin(const ENCODING *enc, const char *p) +{ + return BIG2_IS_NAME_CHAR_MINBPC(enc, p); +} + +static int PTRFASTCALL +big2_isNmstrtMin(const ENCODING *enc, const char *p) +{ + return BIG2_IS_NMSTRT_CHAR_MINBPC(enc, p); +} + +#undef VTABLE +#define VTABLE VTABLE1, big2_toUtf8, big2_toUtf16 + +#else /* not XML_MIN_SIZE */ + +#undef PREFIX +#define PREFIX(ident) big2_ ## ident +#define MINBPC(enc) 2 +/* CHAR_MATCHES is guaranteed to have MINBPC bytes available. */ +#define BYTE_TYPE(enc, p) BIG2_BYTE_TYPE(enc, p) +#define BYTE_TO_ASCII(enc, p) BIG2_BYTE_TO_ASCII(enc, p) +#define CHAR_MATCHES(enc, p, c) BIG2_CHAR_MATCHES(enc, p, c) +#define IS_NAME_CHAR(enc, p, n) 0 +#define IS_NAME_CHAR_MINBPC(enc, p) BIG2_IS_NAME_CHAR_MINBPC(enc, p) +#define IS_NMSTRT_CHAR(enc, p, n) (0) +#define IS_NMSTRT_CHAR_MINBPC(enc, p) BIG2_IS_NMSTRT_CHAR_MINBPC(enc, p) + +#include "xmltok_impl.c" + +#undef MINBPC +#undef BYTE_TYPE +#undef BYTE_TO_ASCII +#undef CHAR_MATCHES +#undef IS_NAME_CHAR +#undef IS_NAME_CHAR_MINBPC +#undef IS_NMSTRT_CHAR +#undef IS_NMSTRT_CHAR_MINBPC +#undef IS_INVALID_CHAR + +#endif /* not XML_MIN_SIZE */ + +#ifdef XML_NS + +static const struct normal_encoding big2_encoding_ns = { + { VTABLE, 2, 0, +#if BYTEORDER == 4321 + 1 +#else + 0 +#endif + }, + { +#include "asciitab.h" +#include "latin1tab.h" + }, + STANDARD_VTABLE(big2_) +}; + +#endif + +static const struct normal_encoding big2_encoding = { + { VTABLE, 2, 0, +#if BYTEORDER == 4321 + 1 +#else + 0 +#endif + }, + { +#define BT_COLON BT_NMSTRT +#include "asciitab.h" +#undef BT_COLON +#include "latin1tab.h" + }, + STANDARD_VTABLE(big2_) +}; + +#if BYTEORDER != 1234 + +#ifdef XML_NS + +static const struct normal_encoding internal_big2_encoding_ns = { + { VTABLE, 2, 0, 1 }, + { +#include "iasciitab.h" +#include "latin1tab.h" + }, + STANDARD_VTABLE(big2_) +}; + +#endif + +static const struct normal_encoding internal_big2_encoding = { + { VTABLE, 2, 0, 1 }, + { +#define BT_COLON BT_NMSTRT +#include "iasciitab.h" +#undef BT_COLON +#include "latin1tab.h" + }, + STANDARD_VTABLE(big2_) +}; + +#endif + +#undef PREFIX + +static int FASTCALL +streqci(const char *s1, const char *s2) +{ + for (;;) { + char c1 = *s1++; + char c2 = *s2++; + if (ASCII_a <= c1 && c1 <= ASCII_z) + c1 += ASCII_A - ASCII_a; + if (ASCII_a <= c2 && c2 <= ASCII_z) + c2 += ASCII_A - ASCII_a; + if (c1 != c2) + return 0; + if (!c1) + break; + } + return 1; +} + +static void PTRCALL +initUpdatePosition(const ENCODING *enc, const char *ptr, + const char *end, POSITION *pos) +{ + normal_updatePosition(&utf8_encoding.enc, ptr, end, pos); +} + +static int +toAscii(const ENCODING *enc, const char *ptr, const char *end) +{ + char buf[1]; + char *p = buf; + XmlUtf8Convert(enc, &ptr, end, &p, p + 1); + if (p == buf) + return -1; + else + return buf[0]; +} + +static int FASTCALL +isSpace(int c) +{ + switch (c) { + case 0x20: + case 0xD: + case 0xA: + case 0x9: + return 1; + } + return 0; +} + +/* Return 1 if there's just optional white space or there's an S + followed by name=val. +*/ +static int +parsePseudoAttribute(const ENCODING *enc, + const char *ptr, + const char *end, + const char **namePtr, + const char **nameEndPtr, + const char **valPtr, + const char **nextTokPtr) +{ + int c; + char open; + if (ptr == end) { + *namePtr = NULL; + return 1; + } + if (!isSpace(toAscii(enc, ptr, end))) { + *nextTokPtr = ptr; + return 0; + } + do { + ptr += enc->minBytesPerChar; + } while (isSpace(toAscii(enc, ptr, end))); + if (ptr == end) { + *namePtr = NULL; + return 1; + } + *namePtr = ptr; + for (;;) { + c = toAscii(enc, ptr, end); + if (c == -1) { + *nextTokPtr = ptr; + return 0; + } + if (c == ASCII_EQUALS) { + *nameEndPtr = ptr; + break; + } + if (isSpace(c)) { + *nameEndPtr = ptr; + do { + ptr += enc->minBytesPerChar; + } while (isSpace(c = toAscii(enc, ptr, end))); + if (c != ASCII_EQUALS) { + *nextTokPtr = ptr; + return 0; + } + break; + } + ptr += enc->minBytesPerChar; + } + if (ptr == *namePtr) { + *nextTokPtr = ptr; + return 0; + } + ptr += enc->minBytesPerChar; + c = toAscii(enc, ptr, end); + while (isSpace(c)) { + ptr += enc->minBytesPerChar; + c = toAscii(enc, ptr, end); + } + if (c != ASCII_QUOT && c != ASCII_APOS) { + *nextTokPtr = ptr; + return 0; + } + open = (char)c; + ptr += enc->minBytesPerChar; + *valPtr = ptr; + for (;; ptr += enc->minBytesPerChar) { + c = toAscii(enc, ptr, end); + if (c == open) + break; + if (!(ASCII_a <= c && c <= ASCII_z) + && !(ASCII_A <= c && c <= ASCII_Z) + && !(ASCII_0 <= c && c <= ASCII_9) + && c != ASCII_PERIOD + && c != ASCII_MINUS + && c != ASCII_UNDERSCORE) { + *nextTokPtr = ptr; + return 0; + } + } + *nextTokPtr = ptr + enc->minBytesPerChar; + return 1; +} + +static const char KW_version[] = { + ASCII_v, ASCII_e, ASCII_r, ASCII_s, ASCII_i, ASCII_o, ASCII_n, '\0' +}; + +static const char KW_encoding[] = { + ASCII_e, ASCII_n, ASCII_c, ASCII_o, ASCII_d, ASCII_i, ASCII_n, ASCII_g, '\0' +}; + +static const char KW_standalone[] = { + ASCII_s, ASCII_t, ASCII_a, ASCII_n, ASCII_d, ASCII_a, ASCII_l, ASCII_o, + ASCII_n, ASCII_e, '\0' +}; + +static const char KW_yes[] = { + ASCII_y, ASCII_e, ASCII_s, '\0' +}; + +static const char KW_no[] = { + ASCII_n, ASCII_o, '\0' +}; + +static int +doParseXmlDecl(const ENCODING *(*encodingFinder)(const ENCODING *, + const char *, + const char *), + int isGeneralTextEntity, + const ENCODING *enc, + const char *ptr, + const char *end, + const char **badPtr, + const char **versionPtr, + const char **versionEndPtr, + const char **encodingName, + const ENCODING **encoding, + int *standalone) +{ + const char *val = NULL; + const char *name = NULL; + const char *nameEnd = NULL; + ptr += 5 * enc->minBytesPerChar; + end -= 2 * enc->minBytesPerChar; + if (!parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr) + || !name) { + *badPtr = ptr; + return 0; + } + if (!XmlNameMatchesAscii(enc, name, nameEnd, KW_version)) { + if (!isGeneralTextEntity) { + *badPtr = name; + return 0; + } + } + else { + if (versionPtr) + *versionPtr = val; + if (versionEndPtr) + *versionEndPtr = ptr; + if (!parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr)) { + *badPtr = ptr; + return 0; + } + if (!name) { + if (isGeneralTextEntity) { + /* a TextDecl must have an EncodingDecl */ + *badPtr = ptr; + return 0; + } + return 1; + } + } + if (XmlNameMatchesAscii(enc, name, nameEnd, KW_encoding)) { + int c = toAscii(enc, val, end); + if (!(ASCII_a <= c && c <= ASCII_z) && !(ASCII_A <= c && c <= ASCII_Z)) { + *badPtr = val; + return 0; + } + if (encodingName) + *encodingName = val; + if (encoding) + *encoding = encodingFinder(enc, val, ptr - enc->minBytesPerChar); + if (!parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr)) { + *badPtr = ptr; + return 0; + } + if (!name) + return 1; + } + if (!XmlNameMatchesAscii(enc, name, nameEnd, KW_standalone) + || isGeneralTextEntity) { + *badPtr = name; + return 0; + } + if (XmlNameMatchesAscii(enc, val, ptr - enc->minBytesPerChar, KW_yes)) { + if (standalone) + *standalone = 1; + } + else if (XmlNameMatchesAscii(enc, val, ptr - enc->minBytesPerChar, KW_no)) { + if (standalone) + *standalone = 0; + } + else { + *badPtr = val; + return 0; + } + while (isSpace(toAscii(enc, ptr, end))) + ptr += enc->minBytesPerChar; + if (ptr != end) { + *badPtr = ptr; + return 0; + } + return 1; +} + +static int FASTCALL +checkCharRefNumber(int result) +{ + switch (result >> 8) { + case 0xD8: case 0xD9: case 0xDA: case 0xDB: + case 0xDC: case 0xDD: case 0xDE: case 0xDF: + return -1; + case 0: + if (latin1_encoding.type[result] == BT_NONXML) + return -1; + break; + case 0xFF: + if (result == 0xFFFE || result == 0xFFFF) + return -1; + break; + } + return result; +} + +int FASTCALL +XmlUtf8Encode(int c, char *buf) +{ + enum { + /* minN is minimum legal resulting value for N byte sequence */ + min2 = 0x80, + min3 = 0x800, + min4 = 0x10000 + }; + + if (c < 0) + return 0; + if (c < min2) { + buf[0] = (char)(c | UTF8_cval1); + return 1; + } + if (c < min3) { + buf[0] = (char)((c >> 6) | UTF8_cval2); + buf[1] = (char)((c & 0x3f) | 0x80); + return 2; + } + if (c < min4) { + buf[0] = (char)((c >> 12) | UTF8_cval3); + buf[1] = (char)(((c >> 6) & 0x3f) | 0x80); + buf[2] = (char)((c & 0x3f) | 0x80); + return 3; + } + if (c < 0x110000) { + buf[0] = (char)((c >> 18) | UTF8_cval4); + buf[1] = (char)(((c >> 12) & 0x3f) | 0x80); + buf[2] = (char)(((c >> 6) & 0x3f) | 0x80); + buf[3] = (char)((c & 0x3f) | 0x80); + return 4; + } + return 0; +} + +int FASTCALL +XmlUtf16Encode(int charNum, unsigned short *buf) +{ + if (charNum < 0) + return 0; + if (charNum < 0x10000) { + buf[0] = (unsigned short)charNum; + return 1; + } + if (charNum < 0x110000) { + charNum -= 0x10000; + buf[0] = (unsigned short)((charNum >> 10) + 0xD800); + buf[1] = (unsigned short)((charNum & 0x3FF) + 0xDC00); + return 2; + } + return 0; +} + +struct unknown_encoding { + struct normal_encoding normal; + CONVERTER convert; + void *userData; + unsigned short utf16[256]; + char utf8[256][4]; +}; + +#define AS_UNKNOWN_ENCODING(enc) ((const struct unknown_encoding *) (enc)) + +int +XmlSizeOfUnknownEncoding(void) +{ + return sizeof(struct unknown_encoding); +} + +static int PTRFASTCALL +unknown_isName(const ENCODING *enc, const char *p) +{ + const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc); + int c = uenc->convert(uenc->userData, p); + if (c & ~0xFFFF) + return 0; + return UCS2_GET_NAMING(namePages, c >> 8, c & 0xFF); +} + +static int PTRFASTCALL +unknown_isNmstrt(const ENCODING *enc, const char *p) +{ + const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc); + int c = uenc->convert(uenc->userData, p); + if (c & ~0xFFFF) + return 0; + return UCS2_GET_NAMING(nmstrtPages, c >> 8, c & 0xFF); +} + +static int PTRFASTCALL +unknown_isInvalid(const ENCODING *enc, const char *p) +{ + const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc); + int c = uenc->convert(uenc->userData, p); + return (c & ~0xFFFF) || checkCharRefNumber(c) < 0; +} + +static void PTRCALL +unknown_toUtf8(const ENCODING *enc, + const char **fromP, const char *fromLim, + char **toP, const char *toLim) +{ + const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc); + char buf[XML_UTF8_ENCODE_MAX]; + for (;;) { + const char *utf8; + int n; + if (*fromP == fromLim) + break; + utf8 = uenc->utf8[(unsigned char)**fromP]; + n = *utf8++; + if (n == 0) { + int c = uenc->convert(uenc->userData, *fromP); + n = XmlUtf8Encode(c, buf); + if (n > toLim - *toP) + break; + utf8 = buf; + *fromP += (AS_NORMAL_ENCODING(enc)->type[(unsigned char)**fromP] + - (BT_LEAD2 - 2)); + } + else { + if (n > toLim - *toP) + break; + (*fromP)++; + } + do { + *(*toP)++ = *utf8++; + } while (--n != 0); + } +} + +static void PTRCALL +unknown_toUtf16(const ENCODING *enc, + const char **fromP, const char *fromLim, + unsigned short **toP, const unsigned short *toLim) +{ + const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc); + while (*fromP != fromLim && *toP != toLim) { + unsigned short c = uenc->utf16[(unsigned char)**fromP]; + if (c == 0) { + c = (unsigned short) + uenc->convert(uenc->userData, *fromP); + *fromP += (AS_NORMAL_ENCODING(enc)->type[(unsigned char)**fromP] + - (BT_LEAD2 - 2)); + } + else + (*fromP)++; + *(*toP)++ = c; + } +} + +ENCODING * +XmlInitUnknownEncoding(void *mem, + int *table, + CONVERTER convert, + void *userData) +{ + int i; + struct unknown_encoding *e = (struct unknown_encoding *)mem; + for (i = 0; i < (int)sizeof(struct normal_encoding); i++) + ((char *)mem)[i] = ((char *)&latin1_encoding)[i]; + for (i = 0; i < 128; i++) + if (latin1_encoding.type[i] != BT_OTHER + && latin1_encoding.type[i] != BT_NONXML + && table[i] != i) + return 0; + for (i = 0; i < 256; i++) { + int c = table[i]; + if (c == -1) { + e->normal.type[i] = BT_MALFORM; + /* This shouldn't really get used. */ + e->utf16[i] = 0xFFFF; + e->utf8[i][0] = 1; + e->utf8[i][1] = 0; + } + else if (c < 0) { + if (c < -4) + return 0; + e->normal.type[i] = (unsigned char)(BT_LEAD2 - (c + 2)); + e->utf8[i][0] = 0; + e->utf16[i] = 0; + } + else if (c < 0x80) { + if (latin1_encoding.type[c] != BT_OTHER + && latin1_encoding.type[c] != BT_NONXML + && c != i) + return 0; + e->normal.type[i] = latin1_encoding.type[c]; + e->utf8[i][0] = 1; + e->utf8[i][1] = (char)c; + e->utf16[i] = (unsigned short)(c == 0 ? 0xFFFF : c); + } + else if (checkCharRefNumber(c) < 0) { + e->normal.type[i] = BT_NONXML; + /* This shouldn't really get used. */ + e->utf16[i] = 0xFFFF; + e->utf8[i][0] = 1; + e->utf8[i][1] = 0; + } + else { + if (c > 0xFFFF) + return 0; + if (UCS2_GET_NAMING(nmstrtPages, c >> 8, c & 0xff)) + e->normal.type[i] = BT_NMSTRT; + else if (UCS2_GET_NAMING(namePages, c >> 8, c & 0xff)) + e->normal.type[i] = BT_NAME; + else + e->normal.type[i] = BT_OTHER; + e->utf8[i][0] = (char)XmlUtf8Encode(c, e->utf8[i] + 1); + e->utf16[i] = (unsigned short)c; + } + } + e->userData = userData; + e->convert = convert; + if (convert) { + e->normal.isName2 = unknown_isName; + e->normal.isName3 = unknown_isName; + e->normal.isName4 = unknown_isName; + e->normal.isNmstrt2 = unknown_isNmstrt; + e->normal.isNmstrt3 = unknown_isNmstrt; + e->normal.isNmstrt4 = unknown_isNmstrt; + e->normal.isInvalid2 = unknown_isInvalid; + e->normal.isInvalid3 = unknown_isInvalid; + e->normal.isInvalid4 = unknown_isInvalid; + } + e->normal.enc.utf8Convert = unknown_toUtf8; + e->normal.enc.utf16Convert = unknown_toUtf16; + return &(e->normal.enc); +} + +/* If this enumeration is changed, getEncodingIndex and encodings +must also be changed. */ +enum { + UNKNOWN_ENC = -1, + ISO_8859_1_ENC = 0, + US_ASCII_ENC, + UTF_8_ENC, + UTF_16_ENC, + UTF_16BE_ENC, + UTF_16LE_ENC, + /* must match encodingNames up to here */ + NO_ENC +}; + +static const char KW_ISO_8859_1[] = { + ASCII_I, ASCII_S, ASCII_O, ASCII_MINUS, ASCII_8, ASCII_8, ASCII_5, ASCII_9, + ASCII_MINUS, ASCII_1, '\0' +}; +static const char KW_US_ASCII[] = { + ASCII_U, ASCII_S, ASCII_MINUS, ASCII_A, ASCII_S, ASCII_C, ASCII_I, ASCII_I, + '\0' +}; +static const char KW_UTF_8[] = { + ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_8, '\0' +}; +static const char KW_UTF_16[] = { + ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_1, ASCII_6, '\0' +}; +static const char KW_UTF_16BE[] = { + ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_1, ASCII_6, ASCII_B, ASCII_E, + '\0' +}; +static const char KW_UTF_16LE[] = { + ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_1, ASCII_6, ASCII_L, ASCII_E, + '\0' +}; + +static int FASTCALL +getEncodingIndex(const char *name) +{ + static const char * const encodingNames[] = { + KW_ISO_8859_1, + KW_US_ASCII, + KW_UTF_8, + KW_UTF_16, + KW_UTF_16BE, + KW_UTF_16LE, + }; + int i; + if (name == NULL) + return NO_ENC; + for (i = 0; i < (int)(sizeof(encodingNames)/sizeof(encodingNames[0])); i++) + if (streqci(name, encodingNames[i])) + return i; + return UNKNOWN_ENC; +} + +/* For binary compatibility, we store the index of the encoding + specified at initialization in the isUtf16 member. +*/ + +#define INIT_ENC_INDEX(enc) ((int)(enc)->initEnc.isUtf16) +#define SET_INIT_ENC_INDEX(enc, i) ((enc)->initEnc.isUtf16 = (char)i) + +/* This is what detects the encoding. encodingTable maps from + encoding indices to encodings; INIT_ENC_INDEX(enc) is the index of + the external (protocol) specified encoding; state is + XML_CONTENT_STATE if we're parsing an external text entity, and + XML_PROLOG_STATE otherwise. +*/ + + +static int +initScan(const ENCODING * const *encodingTable, + const INIT_ENCODING *enc, + int state, + const char *ptr, + const char *end, + const char **nextTokPtr) +{ + const ENCODING **encPtr; + + if (ptr == end) + return XML_TOK_NONE; + encPtr = enc->encPtr; + if (ptr + 1 == end) { + /* only a single byte available for auto-detection */ +#ifndef XML_DTD /* FIXME */ + /* a well-formed document entity must have more than one byte */ + if (state != XML_CONTENT_STATE) + return XML_TOK_PARTIAL; +#endif + /* so we're parsing an external text entity... */ + /* if UTF-16 was externally specified, then we need at least 2 bytes */ + switch (INIT_ENC_INDEX(enc)) { + case UTF_16_ENC: + case UTF_16LE_ENC: + case UTF_16BE_ENC: + return XML_TOK_PARTIAL; + } + switch ((unsigned char)*ptr) { + case 0xFE: + case 0xFF: + case 0xEF: /* possibly first byte of UTF-8 BOM */ + if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC + && state == XML_CONTENT_STATE) + break; + /* fall through */ + case 0x00: + case 0x3C: + return XML_TOK_PARTIAL; + } + } + else { + switch (((unsigned char)ptr[0] << 8) | (unsigned char)ptr[1]) { + case 0xFEFF: + if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC + && state == XML_CONTENT_STATE) + break; + *nextTokPtr = ptr + 2; + *encPtr = encodingTable[UTF_16BE_ENC]; + return XML_TOK_BOM; + /* 00 3C is handled in the default case */ + case 0x3C00: + if ((INIT_ENC_INDEX(enc) == UTF_16BE_ENC + || INIT_ENC_INDEX(enc) == UTF_16_ENC) + && state == XML_CONTENT_STATE) + break; + *encPtr = encodingTable[UTF_16LE_ENC]; + return XmlTok(*encPtr, state, ptr, end, nextTokPtr); + case 0xFFFE: + if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC + && state == XML_CONTENT_STATE) + break; + *nextTokPtr = ptr + 2; + *encPtr = encodingTable[UTF_16LE_ENC]; + return XML_TOK_BOM; + case 0xEFBB: + /* Maybe a UTF-8 BOM (EF BB BF) */ + /* If there's an explicitly specified (external) encoding + of ISO-8859-1 or some flavour of UTF-16 + and this is an external text entity, + don't look for the BOM, + because it might be a legal data. + */ + if (state == XML_CONTENT_STATE) { + int e = INIT_ENC_INDEX(enc); + if (e == ISO_8859_1_ENC || e == UTF_16BE_ENC + || e == UTF_16LE_ENC || e == UTF_16_ENC) + break; + } + if (ptr + 2 == end) + return XML_TOK_PARTIAL; + if ((unsigned char)ptr[2] == 0xBF) { + *nextTokPtr = ptr + 3; + *encPtr = encodingTable[UTF_8_ENC]; + return XML_TOK_BOM; + } + break; + default: + if (ptr[0] == '\0') { + /* 0 isn't a legal data character. Furthermore a document + entity can only start with ASCII characters. So the only + way this can fail to be big-endian UTF-16 if it it's an + external parsed general entity that's labelled as + UTF-16LE. + */ + if (state == XML_CONTENT_STATE && INIT_ENC_INDEX(enc) == UTF_16LE_ENC) + break; + *encPtr = encodingTable[UTF_16BE_ENC]; + return XmlTok(*encPtr, state, ptr, end, nextTokPtr); + } + else if (ptr[1] == '\0') { + /* We could recover here in the case: + - parsing an external entity + - second byte is 0 + - no externally specified encoding + - no encoding declaration + by assuming UTF-16LE. But we don't, because this would mean when + presented just with a single byte, we couldn't reliably determine + whether we needed further bytes. + */ + if (state == XML_CONTENT_STATE) + break; + *encPtr = encodingTable[UTF_16LE_ENC]; + return XmlTok(*encPtr, state, ptr, end, nextTokPtr); + } + break; + } + } + *encPtr = encodingTable[INIT_ENC_INDEX(enc)]; + return XmlTok(*encPtr, state, ptr, end, nextTokPtr); +} + + +#define NS(x) x +#define ns(x) x +#include "xmltok_ns.c" +#undef NS +#undef ns + +#ifdef XML_NS + +#define NS(x) x ## NS +#define ns(x) x ## _ns + +#include "xmltok_ns.c" + +#undef NS +#undef ns + +ENCODING * +XmlInitUnknownEncodingNS(void *mem, + int *table, + CONVERTER convert, + void *userData) +{ + ENCODING *enc = XmlInitUnknownEncoding(mem, table, convert, userData); + if (enc) + ((struct normal_encoding *)enc)->type[ASCII_COLON] = BT_COLON; + return enc; +} + +#endif /* XML_NS */ diff --git a/gdcm/Utilities/gdcmexpat/lib/xmltok.h b/gdcm/Utilities/gdcmexpat/lib/xmltok.h new file mode 100644 index 0000000..ca867aa --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/lib/xmltok.h @@ -0,0 +1,316 @@ +/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +#ifndef XmlTok_INCLUDED +#define XmlTok_INCLUDED 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* The following token may be returned by XmlContentTok */ +#define XML_TOK_TRAILING_RSQB -5 /* ] or ]] at the end of the scan; might be + start of illegal ]]> sequence */ +/* The following tokens may be returned by both XmlPrologTok and + XmlContentTok. +*/ +#define XML_TOK_NONE -4 /* The string to be scanned is empty */ +#define XML_TOK_TRAILING_CR -3 /* A CR at the end of the scan; + might be part of CRLF sequence */ +#define XML_TOK_PARTIAL_CHAR -2 /* only part of a multibyte sequence */ +#define XML_TOK_PARTIAL -1 /* only part of a token */ +#define XML_TOK_INVALID 0 + +/* The following tokens are returned by XmlContentTok; some are also + returned by XmlAttributeValueTok, XmlEntityTok, XmlCdataSectionTok. +*/ +#define XML_TOK_START_TAG_WITH_ATTS 1 +#define XML_TOK_START_TAG_NO_ATTS 2 +#define XML_TOK_EMPTY_ELEMENT_WITH_ATTS 3 /* empty element tag */ +#define XML_TOK_EMPTY_ELEMENT_NO_ATTS 4 +#define XML_TOK_END_TAG 5 +#define XML_TOK_DATA_CHARS 6 +#define XML_TOK_DATA_NEWLINE 7 +#define XML_TOK_CDATA_SECT_OPEN 8 +#define XML_TOK_ENTITY_REF 9 +#define XML_TOK_CHAR_REF 10 /* numeric character reference */ + +/* The following tokens may be returned by both XmlPrologTok and + XmlContentTok. +*/ +#define XML_TOK_PI 11 /* processing instruction */ +#define XML_TOK_XML_DECL 12 /* XML decl or text decl */ +#define XML_TOK_COMMENT 13 +#define XML_TOK_BOM 14 /* Byte order mark */ + +/* The following tokens are returned only by XmlPrologTok */ +#define XML_TOK_PROLOG_S 15 +#define XML_TOK_DECL_OPEN 16 /* */ +#define XML_TOK_NAME 18 +#define XML_TOK_NMTOKEN 19 +#define XML_TOK_POUND_NAME 20 /* #name */ +#define XML_TOK_OR 21 /* | */ +#define XML_TOK_PERCENT 22 +#define XML_TOK_OPEN_PAREN 23 +#define XML_TOK_CLOSE_PAREN 24 +#define XML_TOK_OPEN_BRACKET 25 +#define XML_TOK_CLOSE_BRACKET 26 +#define XML_TOK_LITERAL 27 +#define XML_TOK_PARAM_ENTITY_REF 28 +#define XML_TOK_INSTANCE_START 29 + +/* The following occur only in element type declarations */ +#define XML_TOK_NAME_QUESTION 30 /* name? */ +#define XML_TOK_NAME_ASTERISK 31 /* name* */ +#define XML_TOK_NAME_PLUS 32 /* name+ */ +#define XML_TOK_COND_SECT_OPEN 33 /* */ +#define XML_TOK_CLOSE_PAREN_QUESTION 35 /* )? */ +#define XML_TOK_CLOSE_PAREN_ASTERISK 36 /* )* */ +#define XML_TOK_CLOSE_PAREN_PLUS 37 /* )+ */ +#define XML_TOK_COMMA 38 + +/* The following token is returned only by XmlAttributeValueTok */ +#define XML_TOK_ATTRIBUTE_VALUE_S 39 + +/* The following token is returned only by XmlCdataSectionTok */ +#define XML_TOK_CDATA_SECT_CLOSE 40 + +/* With namespace processing this is returned by XmlPrologTok for a + name with a colon. +*/ +#define XML_TOK_PREFIXED_NAME 41 + +#ifdef XML_DTD +#define XML_TOK_IGNORE_SECT 42 +#endif /* XML_DTD */ + +#ifdef XML_DTD +#define XML_N_STATES 4 +#else /* not XML_DTD */ +#define XML_N_STATES 3 +#endif /* not XML_DTD */ + +#define XML_PROLOG_STATE 0 +#define XML_CONTENT_STATE 1 +#define XML_CDATA_SECTION_STATE 2 +#ifdef XML_DTD +#define XML_IGNORE_SECTION_STATE 3 +#endif /* XML_DTD */ + +#define XML_N_LITERAL_TYPES 2 +#define XML_ATTRIBUTE_VALUE_LITERAL 0 +#define XML_ENTITY_VALUE_LITERAL 1 + +/* The size of the buffer passed to XmlUtf8Encode must be at least this. */ +#define XML_UTF8_ENCODE_MAX 4 +/* The size of the buffer passed to XmlUtf16Encode must be at least this. */ +#define XML_UTF16_ENCODE_MAX 2 + +typedef struct position { + /* first line and first column are 0 not 1 */ + XML_Size lineNumber; + XML_Size columnNumber; +} POSITION; + +typedef struct { + const char *name; + const char *valuePtr; + const char *valueEnd; + char normalized; +} ATTRIBUTE; + +struct encoding; +typedef struct encoding ENCODING; + +typedef int (PTRCALL *SCANNER)(const ENCODING *, + const char *, + const char *, + const char **); + +struct encoding { + SCANNER scanners[XML_N_STATES]; + SCANNER literalScanners[XML_N_LITERAL_TYPES]; + int (PTRCALL *sameName)(const ENCODING *, + const char *, + const char *); + int (PTRCALL *nameMatchesAscii)(const ENCODING *, + const char *, + const char *, + const char *); + int (PTRFASTCALL *nameLength)(const ENCODING *, const char *); + const char *(PTRFASTCALL *skipS)(const ENCODING *, const char *); + int (PTRCALL *getAtts)(const ENCODING *enc, + const char *ptr, + int attsMax, + ATTRIBUTE *atts); + int (PTRFASTCALL *charRefNumber)(const ENCODING *enc, const char *ptr); + int (PTRCALL *predefinedEntityName)(const ENCODING *, + const char *, + const char *); + void (PTRCALL *updatePosition)(const ENCODING *, + const char *ptr, + const char *end, + POSITION *); + int (PTRCALL *isPublicId)(const ENCODING *enc, + const char *ptr, + const char *end, + const char **badPtr); + void (PTRCALL *utf8Convert)(const ENCODING *enc, + const char **fromP, + const char *fromLim, + char **toP, + const char *toLim); + void (PTRCALL *utf16Convert)(const ENCODING *enc, + const char **fromP, + const char *fromLim, + unsigned short **toP, + const unsigned short *toLim); + int minBytesPerChar; + char isUtf8; + char isUtf16; +}; + +/* Scan the string starting at ptr until the end of the next complete + token, but do not scan past eptr. Return an integer giving the + type of token. + + Return XML_TOK_NONE when ptr == eptr; nextTokPtr will not be set. + + Return XML_TOK_PARTIAL when the string does not contain a complete + token; nextTokPtr will not be set. + + Return XML_TOK_INVALID when the string does not start a valid + token; nextTokPtr will be set to point to the character which made + the token invalid. + + Otherwise the string starts with a valid token; nextTokPtr will be + set to point to the character following the end of that token. + + Each data character counts as a single token, but adjacent data + characters may be returned together. Similarly for characters in + the prolog outside literals, comments and processing instructions. +*/ + + +#define XmlTok(enc, state, ptr, end, nextTokPtr) \ + (((enc)->scanners[state])(enc, ptr, end, nextTokPtr)) + +#define XmlPrologTok(enc, ptr, end, nextTokPtr) \ + XmlTok(enc, XML_PROLOG_STATE, ptr, end, nextTokPtr) + +#define XmlContentTok(enc, ptr, end, nextTokPtr) \ + XmlTok(enc, XML_CONTENT_STATE, ptr, end, nextTokPtr) + +#define XmlCdataSectionTok(enc, ptr, end, nextTokPtr) \ + XmlTok(enc, XML_CDATA_SECTION_STATE, ptr, end, nextTokPtr) + +#ifdef XML_DTD + +#define XmlIgnoreSectionTok(enc, ptr, end, nextTokPtr) \ + XmlTok(enc, XML_IGNORE_SECTION_STATE, ptr, end, nextTokPtr) + +#endif /* XML_DTD */ + +/* This is used for performing a 2nd-level tokenization on the content + of a literal that has already been returned by XmlTok. +*/ +#define XmlLiteralTok(enc, literalType, ptr, end, nextTokPtr) \ + (((enc)->literalScanners[literalType])(enc, ptr, end, nextTokPtr)) + +#define XmlAttributeValueTok(enc, ptr, end, nextTokPtr) \ + XmlLiteralTok(enc, XML_ATTRIBUTE_VALUE_LITERAL, ptr, end, nextTokPtr) + +#define XmlEntityValueTok(enc, ptr, end, nextTokPtr) \ + XmlLiteralTok(enc, XML_ENTITY_VALUE_LITERAL, ptr, end, nextTokPtr) + +#define XmlSameName(enc, ptr1, ptr2) (((enc)->sameName)(enc, ptr1, ptr2)) + +#define XmlNameMatchesAscii(enc, ptr1, end1, ptr2) \ + (((enc)->nameMatchesAscii)(enc, ptr1, end1, ptr2)) + +#define XmlNameLength(enc, ptr) \ + (((enc)->nameLength)(enc, ptr)) + +#define XmlSkipS(enc, ptr) \ + (((enc)->skipS)(enc, ptr)) + +#define XmlGetAttributes(enc, ptr, attsMax, atts) \ + (((enc)->getAtts)(enc, ptr, attsMax, atts)) + +#define XmlCharRefNumber(enc, ptr) \ + (((enc)->charRefNumber)(enc, ptr)) + +#define XmlPredefinedEntityName(enc, ptr, end) \ + (((enc)->predefinedEntityName)(enc, ptr, end)) + +#define XmlUpdatePosition(enc, ptr, end, pos) \ + (((enc)->updatePosition)(enc, ptr, end, pos)) + +#define XmlIsPublicId(enc, ptr, end, badPtr) \ + (((enc)->isPublicId)(enc, ptr, end, badPtr)) + +#define XmlUtf8Convert(enc, fromP, fromLim, toP, toLim) \ + (((enc)->utf8Convert)(enc, fromP, fromLim, toP, toLim)) + +#define XmlUtf16Convert(enc, fromP, fromLim, toP, toLim) \ + (((enc)->utf16Convert)(enc, fromP, fromLim, toP, toLim)) + +typedef struct { + ENCODING initEnc; + const ENCODING **encPtr; +} INIT_ENCODING; + +int XmlParseXmlDecl(int isGeneralTextEntity, + const ENCODING *enc, + const char *ptr, + const char *end, + const char **badPtr, + const char **versionPtr, + const char **versionEndPtr, + const char **encodingNamePtr, + const ENCODING **namedEncodingPtr, + int *standalonePtr); + +int XmlInitEncoding(INIT_ENCODING *, const ENCODING **, const char *name); +const ENCODING *XmlGetUtf8InternalEncoding(void); +const ENCODING *XmlGetUtf16InternalEncoding(void); +int FASTCALL XmlUtf8Encode(int charNumber, char *buf); +int FASTCALL XmlUtf16Encode(int charNumber, unsigned short *buf); +int XmlSizeOfUnknownEncoding(void); + + +typedef int (XMLCALL *CONVERTER) (void *userData, const char *p); + +ENCODING * +XmlInitUnknownEncoding(void *mem, + int *table, + CONVERTER convert, + void *userData); + +int XmlParseXmlDeclNS(int isGeneralTextEntity, + const ENCODING *enc, + const char *ptr, + const char *end, + const char **badPtr, + const char **versionPtr, + const char **versionEndPtr, + const char **encodingNamePtr, + const ENCODING **namedEncodingPtr, + int *standalonePtr); + +int XmlInitEncodingNS(INIT_ENCODING *, const ENCODING **, const char *name); +const ENCODING *XmlGetUtf8InternalEncodingNS(void); +const ENCODING *XmlGetUtf16InternalEncodingNS(void); +ENCODING * +XmlInitUnknownEncodingNS(void *mem, + int *table, + CONVERTER convert, + void *userData); +#ifdef __cplusplus +} +#endif + +#endif /* not XmlTok_INCLUDED */ diff --git a/gdcm/Utilities/gdcmexpat/lib/xmltok_impl.c b/gdcm/Utilities/gdcmexpat/lib/xmltok_impl.c new file mode 100644 index 0000000..0ee57ab --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/lib/xmltok_impl.c @@ -0,0 +1,1779 @@ +/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +#ifndef IS_INVALID_CHAR +#define IS_INVALID_CHAR(enc, ptr, n) (0) +#endif + +#define INVALID_LEAD_CASE(n, ptr, nextTokPtr) \ + case BT_LEAD ## n: \ + if (end - ptr < n) \ + return XML_TOK_PARTIAL_CHAR; \ + if (IS_INVALID_CHAR(enc, ptr, n)) { \ + *(nextTokPtr) = (ptr); \ + return XML_TOK_INVALID; \ + } \ + ptr += n; \ + break; + +#define INVALID_CASES(ptr, nextTokPtr) \ + INVALID_LEAD_CASE(2, ptr, nextTokPtr) \ + INVALID_LEAD_CASE(3, ptr, nextTokPtr) \ + INVALID_LEAD_CASE(4, ptr, nextTokPtr) \ + case BT_NONXML: \ + case BT_MALFORM: \ + case BT_TRAIL: \ + *(nextTokPtr) = (ptr); \ + return XML_TOK_INVALID; + +#define CHECK_NAME_CASE(n, enc, ptr, end, nextTokPtr) \ + case BT_LEAD ## n: \ + if (end - ptr < n) \ + return XML_TOK_PARTIAL_CHAR; \ + if (!IS_NAME_CHAR(enc, ptr, n)) { \ + *nextTokPtr = ptr; \ + return XML_TOK_INVALID; \ + } \ + ptr += n; \ + break; + +#define CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) \ + case BT_NONASCII: \ + if (!IS_NAME_CHAR_MINBPC(enc, ptr)) { \ + *nextTokPtr = ptr; \ + return XML_TOK_INVALID; \ + } \ + case BT_NMSTRT: \ + case BT_HEX: \ + case BT_DIGIT: \ + case BT_NAME: \ + case BT_MINUS: \ + ptr += MINBPC(enc); \ + break; \ + CHECK_NAME_CASE(2, enc, ptr, end, nextTokPtr) \ + CHECK_NAME_CASE(3, enc, ptr, end, nextTokPtr) \ + CHECK_NAME_CASE(4, enc, ptr, end, nextTokPtr) + +#define CHECK_NMSTRT_CASE(n, enc, ptr, end, nextTokPtr) \ + case BT_LEAD ## n: \ + if (end - ptr < n) \ + return XML_TOK_PARTIAL_CHAR; \ + if (!IS_NMSTRT_CHAR(enc, ptr, n)) { \ + *nextTokPtr = ptr; \ + return XML_TOK_INVALID; \ + } \ + ptr += n; \ + break; + +#define CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) \ + case BT_NONASCII: \ + if (!IS_NMSTRT_CHAR_MINBPC(enc, ptr)) { \ + *nextTokPtr = ptr; \ + return XML_TOK_INVALID; \ + } \ + case BT_NMSTRT: \ + case BT_HEX: \ + ptr += MINBPC(enc); \ + break; \ + CHECK_NMSTRT_CASE(2, enc, ptr, end, nextTokPtr) \ + CHECK_NMSTRT_CASE(3, enc, ptr, end, nextTokPtr) \ + CHECK_NMSTRT_CASE(4, enc, ptr, end, nextTokPtr) + +#ifndef PREFIX +#define PREFIX(ident) ident +#endif + +/* ptr points to character following " */ + switch (BYTE_TYPE(enc, ptr + MINBPC(enc))) { + case BT_S: case BT_CR: case BT_LF: case BT_PERCNT: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + /* fall through */ + case BT_S: case BT_CR: case BT_LF: + *nextTokPtr = ptr; + return XML_TOK_DECL_OPEN; + case BT_NMSTRT: + case BT_HEX: + ptr += MINBPC(enc); + break; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + return XML_TOK_PARTIAL; +} + +static int PTRCALL +PREFIX(checkPiTarget)(const ENCODING *enc, const char *ptr, + const char *end, int *tokPtr) +{ + int upper = 0; + *tokPtr = XML_TOK_PI; + if (end - ptr != MINBPC(enc)*3) + return 1; + switch (BYTE_TO_ASCII(enc, ptr)) { + case ASCII_x: + break; + case ASCII_X: + upper = 1; + break; + default: + return 1; + } + ptr += MINBPC(enc); + switch (BYTE_TO_ASCII(enc, ptr)) { + case ASCII_m: + break; + case ASCII_M: + upper = 1; + break; + default: + return 1; + } + ptr += MINBPC(enc); + switch (BYTE_TO_ASCII(enc, ptr)) { + case ASCII_l: + break; + case ASCII_L: + upper = 1; + break; + default: + return 1; + } + if (upper) + return 0; + *tokPtr = XML_TOK_XML_DECL; + return 1; +} + +/* ptr points to character following " 1) { + size_t n = end - ptr; + if (n & (MINBPC(enc) - 1)) { + n &= ~(MINBPC(enc) - 1); + if (n == 0) + return XML_TOK_PARTIAL; + end = ptr + n; + } + } + switch (BYTE_TYPE(enc, ptr)) { + case BT_RSQB: + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_PARTIAL; + if (!CHAR_MATCHES(enc, ptr, ASCII_RSQB)) + break; + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_PARTIAL; + if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) { + ptr -= MINBPC(enc); + break; + } + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_CDATA_SECT_CLOSE; + case BT_CR: + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_PARTIAL; + if (BYTE_TYPE(enc, ptr) == BT_LF) + ptr += MINBPC(enc); + *nextTokPtr = ptr; + return XML_TOK_DATA_NEWLINE; + case BT_LF: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_DATA_NEWLINE; + INVALID_CASES(ptr, nextTokPtr) + default: + ptr += MINBPC(enc); + break; + } + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { +#define LEAD_CASE(n) \ + case BT_LEAD ## n: \ + if (end - ptr < n || IS_INVALID_CHAR(enc, ptr, n)) { \ + *nextTokPtr = ptr; \ + return XML_TOK_DATA_CHARS; \ + } \ + ptr += n; \ + break; + LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) +#undef LEAD_CASE + case BT_NONXML: + case BT_MALFORM: + case BT_TRAIL: + case BT_CR: + case BT_LF: + case BT_RSQB: + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + default: + ptr += MINBPC(enc); + break; + } + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; +} + +/* ptr points to character following " 1) { + size_t n = end - ptr; + if (n & (MINBPC(enc) - 1)) { + n &= ~(MINBPC(enc) - 1); + if (n == 0) + return XML_TOK_PARTIAL; + end = ptr + n; + } + } + switch (BYTE_TYPE(enc, ptr)) { + case BT_LT: + return PREFIX(scanLt)(enc, ptr + MINBPC(enc), end, nextTokPtr); + case BT_AMP: + return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr); + case BT_CR: + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_TRAILING_CR; + if (BYTE_TYPE(enc, ptr) == BT_LF) + ptr += MINBPC(enc); + *nextTokPtr = ptr; + return XML_TOK_DATA_NEWLINE; + case BT_LF: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_DATA_NEWLINE; + case BT_RSQB: + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_TRAILING_RSQB; + if (!CHAR_MATCHES(enc, ptr, ASCII_RSQB)) + break; + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_TRAILING_RSQB; + if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) { + ptr -= MINBPC(enc); + break; + } + *nextTokPtr = ptr; + return XML_TOK_INVALID; + INVALID_CASES(ptr, nextTokPtr) + default: + ptr += MINBPC(enc); + break; + } + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { +#define LEAD_CASE(n) \ + case BT_LEAD ## n: \ + if (end - ptr < n || IS_INVALID_CHAR(enc, ptr, n)) { \ + *nextTokPtr = ptr; \ + return XML_TOK_DATA_CHARS; \ + } \ + ptr += n; \ + break; + LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) +#undef LEAD_CASE + case BT_RSQB: + if (ptr + MINBPC(enc) != end) { + if (!CHAR_MATCHES(enc, ptr + MINBPC(enc), ASCII_RSQB)) { + ptr += MINBPC(enc); + break; + } + if (ptr + 2*MINBPC(enc) != end) { + if (!CHAR_MATCHES(enc, ptr + 2*MINBPC(enc), ASCII_GT)) { + ptr += MINBPC(enc); + break; + } + *nextTokPtr = ptr + 2*MINBPC(enc); + return XML_TOK_INVALID; + } + } + /* fall through */ + case BT_AMP: + case BT_LT: + case BT_NONXML: + case BT_MALFORM: + case BT_TRAIL: + case BT_CR: + case BT_LF: + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + default: + ptr += MINBPC(enc); + break; + } + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; +} + +/* ptr points to character following "%" */ + +static int PTRCALL +PREFIX(scanPercent)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + if (ptr == end) + return -XML_TOK_PERCENT; + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) + case BT_S: case BT_LF: case BT_CR: case BT_PERCNT: + *nextTokPtr = ptr; + return XML_TOK_PERCENT; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) + case BT_SEMI: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_PARAM_ENTITY_REF; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + return XML_TOK_PARTIAL; +} + +static int PTRCALL +PREFIX(scanPoundName)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + if (ptr == end) + return XML_TOK_PARTIAL; + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) + case BT_CR: case BT_LF: case BT_S: + case BT_RPAR: case BT_GT: case BT_PERCNT: case BT_VERBAR: + *nextTokPtr = ptr; + return XML_TOK_POUND_NAME; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + return -XML_TOK_POUND_NAME; +} + +static int PTRCALL +PREFIX(scanLit)(int open, const ENCODING *enc, + const char *ptr, const char *end, + const char **nextTokPtr) +{ + while (ptr != end) { + int t = BYTE_TYPE(enc, ptr); + switch (t) { + INVALID_CASES(ptr, nextTokPtr) + case BT_QUOT: + case BT_APOS: + ptr += MINBPC(enc); + if (t != open) + break; + if (ptr == end) + return -XML_TOK_LITERAL; + *nextTokPtr = ptr; + switch (BYTE_TYPE(enc, ptr)) { + case BT_S: case BT_CR: case BT_LF: + case BT_GT: case BT_PERCNT: case BT_LSQB: + return XML_TOK_LITERAL; + default: + return XML_TOK_INVALID; + } + default: + ptr += MINBPC(enc); + break; + } + } + return XML_TOK_PARTIAL; +} + +static int PTRCALL +PREFIX(prologTok)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + int tok; + if (ptr == end) + return XML_TOK_NONE; + if (MINBPC(enc) > 1) { + size_t n = end - ptr; + if (n & (MINBPC(enc) - 1)) { + n &= ~(MINBPC(enc) - 1); + if (n == 0) + return XML_TOK_PARTIAL; + end = ptr + n; + } + } + switch (BYTE_TYPE(enc, ptr)) { + case BT_QUOT: + return PREFIX(scanLit)(BT_QUOT, enc, ptr + MINBPC(enc), end, nextTokPtr); + case BT_APOS: + return PREFIX(scanLit)(BT_APOS, enc, ptr + MINBPC(enc), end, nextTokPtr); + case BT_LT: + { + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_PARTIAL; + switch (BYTE_TYPE(enc, ptr)) { + case BT_EXCL: + return PREFIX(scanDecl)(enc, ptr + MINBPC(enc), end, nextTokPtr); + case BT_QUEST: + return PREFIX(scanPi)(enc, ptr + MINBPC(enc), end, nextTokPtr); + case BT_NMSTRT: + case BT_HEX: + case BT_NONASCII: + case BT_LEAD2: + case BT_LEAD3: + case BT_LEAD4: + *nextTokPtr = ptr - MINBPC(enc); + return XML_TOK_INSTANCE_START; + } + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + case BT_CR: + if (ptr + MINBPC(enc) == end) { + *nextTokPtr = end; + /* indicate that this might be part of a CR/LF pair */ + return -XML_TOK_PROLOG_S; + } + /* fall through */ + case BT_S: case BT_LF: + for (;;) { + ptr += MINBPC(enc); + if (ptr == end) + break; + switch (BYTE_TYPE(enc, ptr)) { + case BT_S: case BT_LF: + break; + case BT_CR: + /* don't split CR/LF pair */ + if (ptr + MINBPC(enc) != end) + break; + /* fall through */ + default: + *nextTokPtr = ptr; + return XML_TOK_PROLOG_S; + } + } + *nextTokPtr = ptr; + return XML_TOK_PROLOG_S; + case BT_PERCNT: + return PREFIX(scanPercent)(enc, ptr + MINBPC(enc), end, nextTokPtr); + case BT_COMMA: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_COMMA; + case BT_LSQB: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_OPEN_BRACKET; + case BT_RSQB: + ptr += MINBPC(enc); + if (ptr == end) + return -XML_TOK_CLOSE_BRACKET; + if (CHAR_MATCHES(enc, ptr, ASCII_RSQB)) { + if (ptr + MINBPC(enc) == end) + return XML_TOK_PARTIAL; + if (CHAR_MATCHES(enc, ptr + MINBPC(enc), ASCII_GT)) { + *nextTokPtr = ptr + 2*MINBPC(enc); + return XML_TOK_COND_SECT_CLOSE; + } + } + *nextTokPtr = ptr; + return XML_TOK_CLOSE_BRACKET; + case BT_LPAR: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_OPEN_PAREN; + case BT_RPAR: + ptr += MINBPC(enc); + if (ptr == end) + return -XML_TOK_CLOSE_PAREN; + switch (BYTE_TYPE(enc, ptr)) { + case BT_AST: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_CLOSE_PAREN_ASTERISK; + case BT_QUEST: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_CLOSE_PAREN_QUESTION; + case BT_PLUS: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_CLOSE_PAREN_PLUS; + case BT_CR: case BT_LF: case BT_S: + case BT_GT: case BT_COMMA: case BT_VERBAR: + case BT_RPAR: + *nextTokPtr = ptr; + return XML_TOK_CLOSE_PAREN; + } + *nextTokPtr = ptr; + return XML_TOK_INVALID; + case BT_VERBAR: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_OR; + case BT_GT: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_DECL_CLOSE; + case BT_NUM: + return PREFIX(scanPoundName)(enc, ptr + MINBPC(enc), end, nextTokPtr); +#define LEAD_CASE(n) \ + case BT_LEAD ## n: \ + if (end - ptr < n) \ + return XML_TOK_PARTIAL_CHAR; \ + if (IS_NMSTRT_CHAR(enc, ptr, n)) { \ + ptr += n; \ + tok = XML_TOK_NAME; \ + break; \ + } \ + if (IS_NAME_CHAR(enc, ptr, n)) { \ + ptr += n; \ + tok = XML_TOK_NMTOKEN; \ + break; \ + } \ + *nextTokPtr = ptr; \ + return XML_TOK_INVALID; + LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) +#undef LEAD_CASE + case BT_NMSTRT: + case BT_HEX: + tok = XML_TOK_NAME; + ptr += MINBPC(enc); + break; + case BT_DIGIT: + case BT_NAME: + case BT_MINUS: +#ifdef XML_NS + case BT_COLON: +#endif + tok = XML_TOK_NMTOKEN; + ptr += MINBPC(enc); + break; + case BT_NONASCII: + if (IS_NMSTRT_CHAR_MINBPC(enc, ptr)) { + ptr += MINBPC(enc); + tok = XML_TOK_NAME; + break; + } + if (IS_NAME_CHAR_MINBPC(enc, ptr)) { + ptr += MINBPC(enc); + tok = XML_TOK_NMTOKEN; + break; + } + /* fall through */ + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) + case BT_GT: case BT_RPAR: case BT_COMMA: + case BT_VERBAR: case BT_LSQB: case BT_PERCNT: + case BT_S: case BT_CR: case BT_LF: + *nextTokPtr = ptr; + return tok; +#ifdef XML_NS + case BT_COLON: + ptr += MINBPC(enc); + switch (tok) { + case XML_TOK_NAME: + if (ptr == end) + return XML_TOK_PARTIAL; + tok = XML_TOK_PREFIXED_NAME; + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) + default: + tok = XML_TOK_NMTOKEN; + break; + } + break; + case XML_TOK_PREFIXED_NAME: + tok = XML_TOK_NMTOKEN; + break; + } + break; +#endif + case BT_PLUS: + if (tok == XML_TOK_NMTOKEN) { + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_NAME_PLUS; + case BT_AST: + if (tok == XML_TOK_NMTOKEN) { + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_NAME_ASTERISK; + case BT_QUEST: + if (tok == XML_TOK_NMTOKEN) { + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_NAME_QUESTION; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + return -tok; +} + +static int PTRCALL +PREFIX(attributeValueTok)(const ENCODING *enc, const char *ptr, + const char *end, const char **nextTokPtr) +{ + const char *start; + if (ptr == end) + return XML_TOK_NONE; + start = ptr; + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { +#define LEAD_CASE(n) \ + case BT_LEAD ## n: ptr += n; break; + LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) +#undef LEAD_CASE + case BT_AMP: + if (ptr == start) + return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr); + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + case BT_LT: + /* this is for inside entity references */ + *nextTokPtr = ptr; + return XML_TOK_INVALID; + case BT_LF: + if (ptr == start) { + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_DATA_NEWLINE; + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + case BT_CR: + if (ptr == start) { + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_TRAILING_CR; + if (BYTE_TYPE(enc, ptr) == BT_LF) + ptr += MINBPC(enc); + *nextTokPtr = ptr; + return XML_TOK_DATA_NEWLINE; + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + case BT_S: + if (ptr == start) { + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_ATTRIBUTE_VALUE_S; + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + default: + ptr += MINBPC(enc); + break; + } + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; +} + +static int PTRCALL +PREFIX(entityValueTok)(const ENCODING *enc, const char *ptr, + const char *end, const char **nextTokPtr) +{ + const char *start; + if (ptr == end) + return XML_TOK_NONE; + start = ptr; + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { +#define LEAD_CASE(n) \ + case BT_LEAD ## n: ptr += n; break; + LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) +#undef LEAD_CASE + case BT_AMP: + if (ptr == start) + return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr); + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + case BT_PERCNT: + if (ptr == start) { + int tok = PREFIX(scanPercent)(enc, ptr + MINBPC(enc), + end, nextTokPtr); + return (tok == XML_TOK_PERCENT) ? XML_TOK_INVALID : tok; + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + case BT_LF: + if (ptr == start) { + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_DATA_NEWLINE; + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + case BT_CR: + if (ptr == start) { + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_TRAILING_CR; + if (BYTE_TYPE(enc, ptr) == BT_LF) + ptr += MINBPC(enc); + *nextTokPtr = ptr; + return XML_TOK_DATA_NEWLINE; + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + default: + ptr += MINBPC(enc); + break; + } + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; +} + +#ifdef XML_DTD + +static int PTRCALL +PREFIX(ignoreSectionTok)(const ENCODING *enc, const char *ptr, + const char *end, const char **nextTokPtr) +{ + int level = 0; + if (MINBPC(enc) > 1) { + size_t n = end - ptr; + if (n & (MINBPC(enc) - 1)) { + n &= ~(MINBPC(enc) - 1); + end = ptr + n; + } + } + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { + INVALID_CASES(ptr, nextTokPtr) + case BT_LT: + if ((ptr += MINBPC(enc)) == end) + return XML_TOK_PARTIAL; + if (CHAR_MATCHES(enc, ptr, ASCII_EXCL)) { + if ((ptr += MINBPC(enc)) == end) + return XML_TOK_PARTIAL; + if (CHAR_MATCHES(enc, ptr, ASCII_LSQB)) { + ++level; + ptr += MINBPC(enc); + } + } + break; + case BT_RSQB: + if ((ptr += MINBPC(enc)) == end) + return XML_TOK_PARTIAL; + if (CHAR_MATCHES(enc, ptr, ASCII_RSQB)) { + if ((ptr += MINBPC(enc)) == end) + return XML_TOK_PARTIAL; + if (CHAR_MATCHES(enc, ptr, ASCII_GT)) { + ptr += MINBPC(enc); + if (level == 0) { + *nextTokPtr = ptr; + return XML_TOK_IGNORE_SECT; + } + --level; + } + } + break; + default: + ptr += MINBPC(enc); + break; + } + } + return XML_TOK_PARTIAL; +} + +#endif /* XML_DTD */ + +static int PTRCALL +PREFIX(isPublicId)(const ENCODING *enc, const char *ptr, const char *end, + const char **badPtr) +{ + ptr += MINBPC(enc); + end -= MINBPC(enc); + for (; ptr != end; ptr += MINBPC(enc)) { + switch (BYTE_TYPE(enc, ptr)) { + case BT_DIGIT: + case BT_HEX: + case BT_MINUS: + case BT_APOS: + case BT_LPAR: + case BT_RPAR: + case BT_PLUS: + case BT_COMMA: + case BT_SOL: + case BT_EQUALS: + case BT_QUEST: + case BT_CR: + case BT_LF: + case BT_SEMI: + case BT_EXCL: + case BT_AST: + case BT_PERCNT: + case BT_NUM: +#ifdef XML_NS + case BT_COLON: +#endif + break; + case BT_S: + if (CHAR_MATCHES(enc, ptr, ASCII_TAB)) { + *badPtr = ptr; + return 0; + } + break; + case BT_NAME: + case BT_NMSTRT: + if (!(BYTE_TO_ASCII(enc, ptr) & ~0x7f)) + break; + default: + switch (BYTE_TO_ASCII(enc, ptr)) { + case 0x24: /* $ */ + case 0x40: /* @ */ + break; + default: + *badPtr = ptr; + return 0; + } + break; + } + } + return 1; +} + +/* This must only be called for a well-formed start-tag or empty + element tag. Returns the number of attributes. Pointers to the + first attsMax attributes are stored in atts. +*/ + +static int PTRCALL +PREFIX(getAtts)(const ENCODING *enc, const char *ptr, + int attsMax, ATTRIBUTE *atts) +{ + enum { other, inName, inValue } state = inName; + int nAtts = 0; + int open = 0; /* defined when state == inValue; + initialization just to shut up compilers */ + + for (ptr += MINBPC(enc);; ptr += MINBPC(enc)) { + switch (BYTE_TYPE(enc, ptr)) { +#define START_NAME \ + if (state == other) { \ + if (nAtts < attsMax) { \ + atts[nAtts].name = ptr; \ + atts[nAtts].normalized = 1; \ + } \ + state = inName; \ + } +#define LEAD_CASE(n) \ + case BT_LEAD ## n: START_NAME ptr += (n - MINBPC(enc)); break; + LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) +#undef LEAD_CASE + case BT_NONASCII: + case BT_NMSTRT: + case BT_HEX: + START_NAME + break; +#undef START_NAME + case BT_QUOT: + if (state != inValue) { + if (nAtts < attsMax) + atts[nAtts].valuePtr = ptr + MINBPC(enc); + state = inValue; + open = BT_QUOT; + } + else if (open == BT_QUOT) { + state = other; + if (nAtts < attsMax) + atts[nAtts].valueEnd = ptr; + nAtts++; + } + break; + case BT_APOS: + if (state != inValue) { + if (nAtts < attsMax) + atts[nAtts].valuePtr = ptr + MINBPC(enc); + state = inValue; + open = BT_APOS; + } + else if (open == BT_APOS) { + state = other; + if (nAtts < attsMax) + atts[nAtts].valueEnd = ptr; + nAtts++; + } + break; + case BT_AMP: + if (nAtts < attsMax) + atts[nAtts].normalized = 0; + break; + case BT_S: + if (state == inName) + state = other; + else if (state == inValue + && nAtts < attsMax + && atts[nAtts].normalized + && (ptr == atts[nAtts].valuePtr + || BYTE_TO_ASCII(enc, ptr) != ASCII_SPACE + || BYTE_TO_ASCII(enc, ptr + MINBPC(enc)) == ASCII_SPACE + || BYTE_TYPE(enc, ptr + MINBPC(enc)) == open)) + atts[nAtts].normalized = 0; + break; + case BT_CR: case BT_LF: + /* This case ensures that the first attribute name is counted + Apart from that we could just change state on the quote. */ + if (state == inName) + state = other; + else if (state == inValue && nAtts < attsMax) + atts[nAtts].normalized = 0; + break; + case BT_GT: + case BT_SOL: + if (state != inValue) + return nAtts; + break; + default: + break; + } + } + /* not reached */ +} + +static int PTRFASTCALL +PREFIX(charRefNumber)(const ENCODING *enc, const char *ptr) +{ + int result = 0; + /* skip &# */ + ptr += 2*MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_x)) { + for (ptr += MINBPC(enc); + !CHAR_MATCHES(enc, ptr, ASCII_SEMI); + ptr += MINBPC(enc)) { + int c = BYTE_TO_ASCII(enc, ptr); + switch (c) { + case ASCII_0: case ASCII_1: case ASCII_2: case ASCII_3: case ASCII_4: + case ASCII_5: case ASCII_6: case ASCII_7: case ASCII_8: case ASCII_9: + result <<= 4; + result |= (c - ASCII_0); + break; + case ASCII_A: case ASCII_B: case ASCII_C: + case ASCII_D: case ASCII_E: case ASCII_F: + result <<= 4; + result += 10 + (c - ASCII_A); + break; + case ASCII_a: case ASCII_b: case ASCII_c: + case ASCII_d: case ASCII_e: case ASCII_f: + result <<= 4; + result += 10 + (c - ASCII_a); + break; + } + if (result >= 0x110000) + return -1; + } + } + else { + for (; !CHAR_MATCHES(enc, ptr, ASCII_SEMI); ptr += MINBPC(enc)) { + int c = BYTE_TO_ASCII(enc, ptr); + result *= 10; + result += (c - ASCII_0); + if (result >= 0x110000) + return -1; + } + } + return checkCharRefNumber(result); +} + +static int PTRCALL +PREFIX(predefinedEntityName)(const ENCODING *enc, const char *ptr, + const char *end) +{ + switch ((end - ptr)/MINBPC(enc)) { + case 2: + if (CHAR_MATCHES(enc, ptr + MINBPC(enc), ASCII_t)) { + switch (BYTE_TO_ASCII(enc, ptr)) { + case ASCII_l: + return ASCII_LT; + case ASCII_g: + return ASCII_GT; + } + } + break; + case 3: + if (CHAR_MATCHES(enc, ptr, ASCII_a)) { + ptr += MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_m)) { + ptr += MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_p)) + return ASCII_AMP; + } + } + break; + case 4: + switch (BYTE_TO_ASCII(enc, ptr)) { + case ASCII_q: + ptr += MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_u)) { + ptr += MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_o)) { + ptr += MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_t)) + return ASCII_QUOT; + } + } + break; + case ASCII_a: + ptr += MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_p)) { + ptr += MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_o)) { + ptr += MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_s)) + return ASCII_APOS; + } + } + break; + } + } + return 0; +} + +static int PTRCALL +PREFIX(sameName)(const ENCODING *enc, const char *ptr1, const char *ptr2) +{ + for (;;) { + switch (BYTE_TYPE(enc, ptr1)) { +#define LEAD_CASE(n) \ + case BT_LEAD ## n: \ + if (*ptr1++ != *ptr2++) \ + return 0; + LEAD_CASE(4) LEAD_CASE(3) LEAD_CASE(2) +#undef LEAD_CASE + /* fall through */ + if (*ptr1++ != *ptr2++) + return 0; + break; + case BT_NONASCII: + case BT_NMSTRT: +#ifdef XML_NS + case BT_COLON: +#endif + case BT_HEX: + case BT_DIGIT: + case BT_NAME: + case BT_MINUS: + if (*ptr2++ != *ptr1++) + return 0; + if (MINBPC(enc) > 1) { + if (*ptr2++ != *ptr1++) + return 0; + if (MINBPC(enc) > 2) { + if (*ptr2++ != *ptr1++) + return 0; + if (MINBPC(enc) > 3) { + if (*ptr2++ != *ptr1++) + return 0; + } + } + } + break; + default: + if (MINBPC(enc) == 1 && *ptr1 == *ptr2) + return 1; + switch (BYTE_TYPE(enc, ptr2)) { + case BT_LEAD2: + case BT_LEAD3: + case BT_LEAD4: + case BT_NONASCII: + case BT_NMSTRT: +#ifdef XML_NS + case BT_COLON: +#endif + case BT_HEX: + case BT_DIGIT: + case BT_NAME: + case BT_MINUS: + return 0; + default: + return 1; + } + } + } + /* not reached */ +} + +static int PTRCALL +PREFIX(nameMatchesAscii)(const ENCODING *enc, const char *ptr1, + const char *end1, const char *ptr2) +{ + for (; *ptr2; ptr1 += MINBPC(enc), ptr2++) { + if (ptr1 == end1) + return 0; + if (!CHAR_MATCHES(enc, ptr1, *ptr2)) + return 0; + } + return ptr1 == end1; +} + +static int PTRFASTCALL +PREFIX(nameLength)(const ENCODING *enc, const char *ptr) +{ + const char *start = ptr; + for (;;) { + switch (BYTE_TYPE(enc, ptr)) { +#define LEAD_CASE(n) \ + case BT_LEAD ## n: ptr += n; break; + LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) +#undef LEAD_CASE + case BT_NONASCII: + case BT_NMSTRT: +#ifdef XML_NS + case BT_COLON: +#endif + case BT_HEX: + case BT_DIGIT: + case BT_NAME: + case BT_MINUS: + ptr += MINBPC(enc); + break; + default: + return (int)(ptr - start); + } + } +} + +static const char * PTRFASTCALL +PREFIX(skipS)(const ENCODING *enc, const char *ptr) +{ + for (;;) { + switch (BYTE_TYPE(enc, ptr)) { + case BT_LF: + case BT_CR: + case BT_S: + ptr += MINBPC(enc); + break; + default: + return ptr; + } + } +} + +static void PTRCALL +PREFIX(updatePosition)(const ENCODING *enc, + const char *ptr, + const char *end, + POSITION *pos) +{ + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { +#define LEAD_CASE(n) \ + case BT_LEAD ## n: \ + ptr += n; \ + break; + LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) +#undef LEAD_CASE + case BT_LF: + pos->columnNumber = (XML_Size)-1; + pos->lineNumber++; + ptr += MINBPC(enc); + break; + case BT_CR: + pos->lineNumber++; + ptr += MINBPC(enc); + if (ptr != end && BYTE_TYPE(enc, ptr) == BT_LF) + ptr += MINBPC(enc); + pos->columnNumber = (XML_Size)-1; + break; + default: + ptr += MINBPC(enc); + break; + } + pos->columnNumber++; + } +} + +#undef DO_LEAD_CASE +#undef MULTIBYTE_CASES +#undef INVALID_CASES +#undef CHECK_NAME_CASE +#undef CHECK_NAME_CASES +#undef CHECK_NMSTRT_CASE +#undef CHECK_NMSTRT_CASES + diff --git a/gdcm/Utilities/gdcmexpat/lib/xmltok_impl.h b/gdcm/Utilities/gdcmexpat/lib/xmltok_impl.h new file mode 100644 index 0000000..da0ea60 --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/lib/xmltok_impl.h @@ -0,0 +1,46 @@ +/* +Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd +See the file COPYING for copying permission. +*/ + +enum { + BT_NONXML, + BT_MALFORM, + BT_LT, + BT_AMP, + BT_RSQB, + BT_LEAD2, + BT_LEAD3, + BT_LEAD4, + BT_TRAIL, + BT_CR, + BT_LF, + BT_GT, + BT_QUOT, + BT_APOS, + BT_EQUALS, + BT_QUEST, + BT_EXCL, + BT_SOL, + BT_SEMI, + BT_NUM, + BT_LSQB, + BT_S, + BT_NMSTRT, + BT_COLON, + BT_HEX, + BT_DIGIT, + BT_NAME, + BT_MINUS, + BT_OTHER, /* known not to be a name or name start character */ + BT_NONASCII, /* might be a name or name start character */ + BT_PERCNT, + BT_LPAR, + BT_RPAR, + BT_AST, + BT_PLUS, + BT_COMMA, + BT_VERBAR +}; + +#include diff --git a/gdcm/Utilities/gdcmexpat/lib/xmltok_ns.c b/gdcm/Utilities/gdcmexpat/lib/xmltok_ns.c new file mode 100644 index 0000000..d2f8938 --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/lib/xmltok_ns.c @@ -0,0 +1,106 @@ +const ENCODING * +NS(XmlGetUtf8InternalEncoding)(void) +{ + return &ns(internal_utf8_encoding).enc; +} + +const ENCODING * +NS(XmlGetUtf16InternalEncoding)(void) +{ +#if BYTEORDER == 1234 + return &ns(internal_little2_encoding).enc; +#elif BYTEORDER == 4321 + return &ns(internal_big2_encoding).enc; +#else + const short n = 1; + return (*(const char *)&n + ? &ns(internal_little2_encoding).enc + : &ns(internal_big2_encoding).enc); +#endif +} + +static const ENCODING * const NS(encodings)[] = { + &ns(latin1_encoding).enc, + &ns(ascii_encoding).enc, + &ns(utf8_encoding).enc, + &ns(big2_encoding).enc, + &ns(big2_encoding).enc, + &ns(little2_encoding).enc, + &ns(utf8_encoding).enc /* NO_ENC */ +}; + +static int PTRCALL +NS(initScanProlog)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + return initScan(NS(encodings), (const INIT_ENCODING *)enc, + XML_PROLOG_STATE, ptr, end, nextTokPtr); +} + +static int PTRCALL +NS(initScanContent)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + return initScan(NS(encodings), (const INIT_ENCODING *)enc, + XML_CONTENT_STATE, ptr, end, nextTokPtr); +} + +int +NS(XmlInitEncoding)(INIT_ENCODING *p, const ENCODING **encPtr, + const char *name) +{ + int i = getEncodingIndex(name); + if (i == UNKNOWN_ENC) + return 0; + SET_INIT_ENC_INDEX(p, i); + p->initEnc.scanners[XML_PROLOG_STATE] = NS(initScanProlog); + p->initEnc.scanners[XML_CONTENT_STATE] = NS(initScanContent); + p->initEnc.updatePosition = initUpdatePosition; + p->encPtr = encPtr; + *encPtr = &(p->initEnc); + return 1; +} + +static const ENCODING * +NS(findEncoding)(const ENCODING *enc, const char *ptr, const char *end) +{ +#define ENCODING_MAX 128 + char buf[ENCODING_MAX]; + char *p = buf; + int i; + XmlUtf8Convert(enc, &ptr, end, &p, p + ENCODING_MAX - 1); + if (ptr != end) + return 0; + *p = 0; + if (streqci(buf, KW_UTF_16) && enc->minBytesPerChar == 2) + return enc; + i = getEncodingIndex(buf); + if (i == UNKNOWN_ENC) + return 0; + return NS(encodings)[i]; +} + +int +NS(XmlParseXmlDecl)(int isGeneralTextEntity, + const ENCODING *enc, + const char *ptr, + const char *end, + const char **badPtr, + const char **versionPtr, + const char **versionEndPtr, + const char **encodingName, + const ENCODING **encoding, + int *standalone) +{ + return doParseXmlDecl(NS(findEncoding), + isGeneralTextEntity, + enc, + ptr, + end, + badPtr, + versionPtr, + versionEndPtr, + encodingName, + encoding, + standalone); +} diff --git a/gdcm/Utilities/gdcmexpat/tests/README.txt b/gdcm/Utilities/gdcmexpat/tests/README.txt new file mode 100644 index 0000000..33a47c3 --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/tests/README.txt @@ -0,0 +1,14 @@ +This directory contains the (fledgling) test suite for Expat. The +tests provide general unit testing and regression coverage. The tests +are not expected to be useful examples of Expat usage; see the +examples/ directory for that. + +The Expat tests use a partial internal implementation of the "Check" +unit testing framework for C. More information on Check can be found at: + + http://check.sourceforge.net/ + +Expat must be built and installed before "make check" can be executed. + +Since both Check and this test suite are young, it can all change in a +later version. diff --git a/gdcm/Utilities/gdcmexpat/tests/benchmark/README.txt b/gdcm/Utilities/gdcmexpat/tests/benchmark/README.txt new file mode 100644 index 0000000..7f9cca0 --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/tests/benchmark/README.txt @@ -0,0 +1,16 @@ +Use this benchmark command line utility as follows: + + benchmark [-n] <# iterations> + +The command line arguments are: + + -n ... optional; if supplied, namespace processing is turned on + ... name/path of test xml file + ... size of processing buffer; + the file is parsed in chunks of this size + <# iterations> ... how often will the file be parsed + +Returns: + + The time (in seconds) it takes to parse the test file, + averaged over the number of iterations. \ No newline at end of file diff --git a/gdcm/Utilities/gdcmexpat/tests/benchmark/benchmark.c b/gdcm/Utilities/gdcmexpat/tests/benchmark/benchmark.c new file mode 100644 index 0000000..86266a0 --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/tests/benchmark/benchmark.c @@ -0,0 +1,114 @@ +#include +#include +#include +#include +#include "expat.h" + +#ifdef XML_LARGE_SIZE +#define XML_FMT_INT_MOD "ll" +#else +#define XML_FMT_INT_MOD "l" +#endif + +static void +usage(const char *prog, int rc) +{ + fprintf(stderr, + "usage: %s [-n] filename bufferSize nr_of_loops\n", prog); + exit(rc); +} + +#ifdef AMIGA_SHARED_LIB +#include +int +amiga_main(int argc, char *argv[]) +#else +int main (int argc, char *argv[]) +#endif +{ + XML_Parser parser; + char *XMLBuf, *XMLBufEnd, *XMLBufPtr; + FILE *fd; + struct stat fileAttr; + int nrOfLoops, bufferSize, fileSize, i, isFinal; + int j = 0, ns = 0; + clock_t tstart, tend; + double cpuTime = 0.0; + + if (argc > 1) { + if (argv[1][0] == '-') { + if (argv[1][1] == 'n' && argv[1][2] == '\0') { + ns = 1; + j = 1; + } + else + usage(argv[0], 1); + } + } + + if (argc != j + 4) + usage(argv[0], 1); + + if (stat (argv[j + 1], &fileAttr) != 0) { + fprintf (stderr, "could not access file '%s'\n", argv[j + 1]); + return 2; + } + + fd = fopen (argv[j + 1], "r"); + if (!fd) { + fprintf (stderr, "could not open file '%s'\n", argv[j + 1]); + exit(2); + } + + bufferSize = atoi (argv[j + 2]); + nrOfLoops = atoi (argv[j + 3]); + if (bufferSize <= 0 || nrOfLoops <= 0) { + fprintf (stderr, + "buffer size and nr of loops must be greater than zero.\n"); + exit(3); + } + + XMLBuf = malloc (fileAttr.st_size); + fileSize = fread (XMLBuf, sizeof (char), fileAttr.st_size, fd); + fclose (fd); + + i = 0; + XMLBufEnd = XMLBuf + fileSize; + while (i < nrOfLoops) { + XMLBufPtr = XMLBuf; + isFinal = 0; + if (ns) + parser = XML_ParserCreateNS(NULL, '!'); + else + parser = XML_ParserCreate(NULL); + tstart = clock(); + do { + int parseBufferSize = XMLBufEnd - XMLBufPtr; + if (parseBufferSize <= bufferSize) + isFinal = 1; + else + parseBufferSize = bufferSize; + if (!XML_Parse (parser, XMLBufPtr, parseBufferSize, isFinal)) { + fprintf (stderr, "error '%s' at line %" XML_FMT_INT_MOD \ + "u character %" XML_FMT_INT_MOD "u\n", + XML_ErrorString (XML_GetErrorCode (parser)), + XML_GetCurrentLineNumber (parser), + XML_GetCurrentColumnNumber (parser)); + free (XMLBuf); + XML_ParserFree (parser); + exit (4); + } + XMLBufPtr += bufferSize; + } while (!isFinal); + tend = clock(); + cpuTime += ((double) (tend - tstart)) / CLOCKS_PER_SEC; + XML_ParserFree (parser); + i++; + } + + free (XMLBuf); + + printf ("%d loops, with buffer size %d. Average time per loop: %f\n", + nrOfLoops, bufferSize, cpuTime / (double) nrOfLoops); + return 0; +} diff --git a/gdcm/Utilities/gdcmexpat/tests/chardata.c b/gdcm/Utilities/gdcmexpat/tests/chardata.c new file mode 100644 index 0000000..5fb0299 --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/tests/chardata.c @@ -0,0 +1,131 @@ +/* Copyright (c) 1998-2003 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. + + chardata.c +*/ + +#ifdef HAVE_EXPAT_CONFIG_H +#include +#endif +#ifdef HAVE_CHECK_H +#include +#else +#include "minicheck.h" +#endif + +#include +#include +#include + +#include "chardata.h" + + +static int +xmlstrlen(const XML_Char *s) +{ + int len = 0; + assert(s != NULL); + while (s[len] != 0) + ++len; + return len; +} + + +void +CharData_Init(CharData *storage) +{ + assert(storage != NULL); + storage->count = -1; +} + +void +CharData_AppendString(CharData *storage, const char *s) +{ + int maxchars = sizeof(storage->data) / sizeof(storage->data[0]); + int len; + + assert(s != NULL); + len = strlen(s); + if (storage->count < 0) + storage->count = 0; + if ((len + storage->count) > maxchars) { + len = (maxchars - storage->count); + } + if (len + storage->count < sizeof(storage->data)) { + memcpy(storage->data + storage->count, s, len); + storage->count += len; + } +} + +void +CharData_AppendXMLChars(CharData *storage, const XML_Char *s, int len) +{ + int maxchars; + + assert(storage != NULL); + assert(s != NULL); + maxchars = sizeof(storage->data) / sizeof(storage->data[0]); + if (storage->count < 0) + storage->count = 0; + if (len < 0) + len = xmlstrlen(s); + if ((len + storage->count) > maxchars) { + len = (maxchars - storage->count); + } + if (len + storage->count < sizeof(storage->data)) { + memcpy(storage->data + storage->count, s, + len * sizeof(storage->data[0])); + storage->count += len; + } +} + +int +CharData_CheckString(CharData *storage, const char *expected) +{ + char buffer[1280]; + int len; + int count; + + assert(storage != NULL); + assert(expected != NULL); + count = (storage->count < 0) ? 0 : storage->count; + len = strlen(expected); + if (len != count) { + if (sizeof(XML_Char) == 1) + sprintf(buffer, "wrong number of data characters:" + " got %d, expected %d:\n%s", count, len, storage->data); + else + sprintf(buffer, + "wrong number of data characters: got %d, expected %d", + count, len); + fail(buffer); + return 0; + } + if (memcmp(expected, storage->data, len) != 0) { + fail("got bad data bytes"); + return 0; + } + return 1; +} + +int +CharData_CheckXMLChars(CharData *storage, const XML_Char *expected) +{ + char buffer[1024]; + int len = xmlstrlen(expected); + int count; + + assert(storage != NULL); + count = (storage->count < 0) ? 0 : storage->count; + if (len != count) { + sprintf(buffer, "wrong number of data characters: got %d, expected %d", + count, len); + fail(buffer); + return 0; + } + if (memcmp(expected, storage->data, len * sizeof(storage->data[0])) != 0) { + fail("got bad data bytes"); + return 0; + } + return 1; +} diff --git a/gdcm/Utilities/gdcmexpat/tests/chardata.h b/gdcm/Utilities/gdcmexpat/tests/chardata.h new file mode 100644 index 0000000..e8dc4ce --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/tests/chardata.h @@ -0,0 +1,40 @@ +/* chardata.h + + Interface to some helper routines used to accumulate and check text + and attribute content. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef XML_CHARDATA_H +#define XML_CHARDATA_H 1 + +#ifndef XML_VERSION +#include "expat.h" /* need XML_Char */ +#endif + + +typedef struct { + int count; /* # of chars, < 0 if not set */ + XML_Char data[1024]; +} CharData; + + +void CharData_Init(CharData *storage); + +void CharData_AppendString(CharData *storage, const char *s); + +void CharData_AppendXMLChars(CharData *storage, const XML_Char *s, int len); + +int CharData_CheckString(CharData *storage, const char *s); + +int CharData_CheckXMLChars(CharData *storage, const XML_Char *s); + + +#endif /* XML_CHARDATA_H */ + +#ifdef __cplusplus +} +#endif diff --git a/gdcm/Utilities/gdcmexpat/tests/minicheck.c b/gdcm/Utilities/gdcmexpat/tests/minicheck.c new file mode 100644 index 0000000..25fbf85 --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/tests/minicheck.c @@ -0,0 +1,182 @@ +/* Miniature re-implementation of the "check" library. + * + * This is intended to support just enough of check to run the Expat + * tests. This interface is based entirely on the portion of the + * check library being used. + */ + +#include +#include +#include +#include + +#include "minicheck.h" + +Suite * +suite_create(char *name) +{ + Suite *suite = (Suite *) calloc(1, sizeof(Suite)); + if (suite != NULL) { + suite->name = name; + } + return suite; +} + +TCase * +tcase_create(char *name) +{ + TCase *tc = (TCase *) calloc(1, sizeof(TCase)); + if (tc != NULL) { + tc->name = name; + } + return tc; +} + +void +suite_add_tcase(Suite *suite, TCase *tc) +{ + assert(suite != NULL); + assert(tc != NULL); + assert(tc->next_tcase == NULL); + + tc->next_tcase = suite->tests; + suite->tests = tc; +} + +void +tcase_add_checked_fixture(TCase *tc, + tcase_setup_function setup, + tcase_teardown_function teardown) +{ + assert(tc != NULL); + tc->setup = setup; + tc->teardown = teardown; +} + +void +tcase_add_test(TCase *tc, tcase_test_function test) +{ + assert(tc != NULL); + if (tc->allocated == tc->ntests) { + int nalloc = tc->allocated + 100; + size_t new_size = sizeof(tcase_test_function) * nalloc; + tcase_test_function *new_tests = realloc(tc->tests, new_size); + assert(new_tests != NULL); + if (new_tests != tc->tests) { + free(tc->tests); + tc->tests = new_tests; + } + tc->allocated = nalloc; + } + tc->tests[tc->ntests] = test; + tc->ntests++; +} + +SRunner * +srunner_create(Suite *suite) +{ + SRunner *runner = calloc(1, sizeof(SRunner)); + if (runner != NULL) { + runner->suite = suite; + } + return runner; +} + +void +srunner_set_fork_status(SRunner *runner, int status) +{ + /* We ignore this. */ +} + +static jmp_buf env; + +static char const *_check_current_function = NULL; +static int _check_current_lineno = -1; +static char const *_check_current_filename = NULL; + +void +_check_set_test_info(char const *function, char const *filename, int lineno) +{ + _check_current_function = function; + _check_current_lineno = lineno; + _check_current_filename = filename; +} + + +static void +add_failure(SRunner *runner, int verbosity) +{ + runner->nfailures++; + if (verbosity >= CK_VERBOSE) { + printf("%s:%d: %s\n", _check_current_filename, + _check_current_lineno, _check_current_function); + } +} + +void +srunner_run_all(SRunner *runner, int verbosity) +{ + Suite *suite; + TCase *tc; + assert(runner != NULL); + suite = runner->suite; + tc = suite->tests; + while (tc != NULL) { + int i; + for (i = 0; i < tc->ntests; ++i) { + runner->nchecks++; + + if (tc->setup != NULL) { + /* setup */ + if (setjmp(env)) { + add_failure(runner, verbosity); + continue; + } + tc->setup(); + } + /* test */ + if (setjmp(env)) { + add_failure(runner, verbosity); + continue; + } + (tc->tests[i])(); + + /* teardown */ + if (tc->teardown != NULL) { + if (setjmp(env)) { + add_failure(runner, verbosity); + continue; + } + tc->teardown(); + } + } + tc = tc->next_tcase; + } + if (verbosity) { + int passed = runner->nchecks - runner->nfailures; + double percentage = ((double) passed) / runner->nchecks; + int display = (int) (percentage * 100); + printf("%d%%: Checks: %d, Failed: %d\n", + display, runner->nchecks, runner->nfailures); + } +} + +void +_fail_unless(int condition, const char *file, int line, char *msg) +{ + longjmp(env, 1); +} + +int +srunner_ntests_failed(SRunner *runner) +{ + assert(runner != NULL); + return runner->nfailures; +} + +void +srunner_free(SRunner *runner) +{ + free(runner->suite); + free(runner); +} diff --git a/gdcm/Utilities/gdcmexpat/tests/minicheck.h b/gdcm/Utilities/gdcmexpat/tests/minicheck.h new file mode 100644 index 0000000..c8a1d5e --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/tests/minicheck.h @@ -0,0 +1,84 @@ +/* Miniature re-implementation of the "check" library. + * + * This is intended to support just enough of check to run the Expat + * tests. This interface is based entirely on the portion of the + * check library being used. + * + * This is *source* compatible, but not necessary *link* compatible. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#define CK_NOFORK 0 +#define CK_FORK 1 + +#define CK_SILENT 0 +#define CK_NORMAL 1 +#define CK_VERBOSE 2 + +#define START_TEST(testname) static void testname(void) { \ + _check_set_test_info(__func__, __FILE__, __LINE__); \ + { +#define END_TEST } } + +#define fail(msg) _fail_unless(0, __FILE__, __LINE__, msg) + +typedef void (*tcase_setup_function)(void); +typedef void (*tcase_teardown_function)(void); +typedef void (*tcase_test_function)(void); + +typedef struct SRunner SRunner; +typedef struct Suite Suite; +typedef struct TCase TCase; + +struct SRunner { + Suite *suite; + int forking; + int nchecks; + int nfailures; +}; + +struct Suite { + char *name; + TCase *tests; +}; + +struct TCase { + char *name; + tcase_setup_function setup; + tcase_teardown_function teardown; + tcase_test_function *tests; + int ntests; + int allocated; + TCase *next_tcase; +}; + + +/* Internal helper. */ +void _check_set_test_info(char const *function, + char const *filename, int lineno); + + +/* + * Prototypes for the actual implementation. + */ + +void _fail_unless(int condition, const char *file, int line, char *msg); +Suite *suite_create(char *name); +TCase *tcase_create(char *name); +void suite_add_tcase(Suite *suite, TCase *tc); +void tcase_add_checked_fixture(TCase *, + tcase_setup_function, + tcase_teardown_function); +void tcase_add_test(TCase *tc, tcase_test_function test); +SRunner *srunner_create(Suite *suite); +void srunner_set_fork_status(SRunner *runner, int forking); +void srunner_run_all(SRunner *runner, int verbosity); +int srunner_ntests_failed(SRunner *runner); +void srunner_free(SRunner *runner); + +#ifdef __cplusplus +} +#endif diff --git a/gdcm/Utilities/gdcmexpat/tests/runtests.c b/gdcm/Utilities/gdcmexpat/tests/runtests.c new file mode 100644 index 0000000..088fe6f --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/tests/runtests.c @@ -0,0 +1,1450 @@ +/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. + + runtest.c : run the Expat test suite +*/ + +#ifdef HAVE_EXPAT_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "expat.h" +#include "chardata.h" +#include "minicheck.h" + +#ifdef AMIGA_SHARED_LIB +#include +#endif + +#ifdef XML_LARGE_SIZE +#define XML_FMT_INT_MOD "ll" +#else +#define XML_FMT_INT_MOD "l" +#endif + +static XML_Parser parser; + + +static void +basic_setup(void) +{ + parser = XML_ParserCreate(NULL); + if (parser == NULL) + fail("Parser not created."); +} + +static void +basic_teardown(void) +{ + if (parser != NULL) + XML_ParserFree(parser); +} + +/* Generate a failure using the parser state to create an error message; + this should be used when the parser reports an error we weren't + expecting. +*/ +static void +_xml_failure(XML_Parser parser, const char *file, int line) +{ + char buffer[1024]; + sprintf(buffer, + "\n %s (line %" XML_FMT_INT_MOD "u, offset %"\ + XML_FMT_INT_MOD "u)\n reported from %s, line %d", + XML_ErrorString(XML_GetErrorCode(parser)), + XML_GetCurrentLineNumber(parser), + XML_GetCurrentColumnNumber(parser), + file, line); + _fail_unless(0, file, line, buffer); +} + +#define xml_failure(parser) _xml_failure((parser), __FILE__, __LINE__) + +static void +_expect_failure(char *text, enum XML_Error errorCode, char *errorMessage, + char *file, int lineno) +{ + if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_OK) + /* Hackish use of _fail_unless() macro, but let's us report + the right filename and line number. */ + _fail_unless(0, file, lineno, errorMessage); + if (XML_GetErrorCode(parser) != errorCode) + _xml_failure(parser, file, lineno); +} + +#define expect_failure(text, errorCode, errorMessage) \ + _expect_failure((text), (errorCode), (errorMessage), \ + __FILE__, __LINE__) + +/* Dummy handlers for when we need to set a handler to tickle a bug, + but it doesn't need to do anything. +*/ + +static void XMLCALL +dummy_start_doctype_handler(void *userData, + const XML_Char *doctypeName, + const XML_Char *sysid, + const XML_Char *pubid, + int has_internal_subset) +{} + +static void XMLCALL +dummy_end_doctype_handler(void *userData) +{} + +static void XMLCALL +dummy_entity_decl_handler(void *userData, + const XML_Char *entityName, + int is_parameter_entity, + const XML_Char *value, + int value_length, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId, + const XML_Char *notationName) +{} + +static void XMLCALL +dummy_notation_decl_handler(void *userData, + const XML_Char *notationName, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId) +{} + +static void XMLCALL +dummy_element_decl_handler(void *userData, + const XML_Char *name, + XML_Content *model) +{} + +static void XMLCALL +dummy_attlist_decl_handler(void *userData, + const XML_Char *elname, + const XML_Char *attname, + const XML_Char *att_type, + const XML_Char *dflt, + int isrequired) +{} + +static void XMLCALL +dummy_comment_handler(void *userData, const XML_Char *data) +{} + +static void XMLCALL +dummy_pi_handler(void *userData, const XML_Char *target, const XML_Char *data) +{} + +static void XMLCALL +dummy_start_element(void *userData, + const XML_Char *name, const XML_Char **atts) +{} + + +/* + * Character & encoding tests. + */ + +START_TEST(test_nul_byte) +{ + char text[] = "\0"; + + /* test that a NUL byte (in US-ASCII data) is an error */ + if (XML_Parse(parser, text, sizeof(text) - 1, XML_TRUE) == XML_STATUS_OK) + fail("Parser did not report error on NUL-byte."); + if (XML_GetErrorCode(parser) != XML_ERROR_INVALID_TOKEN) + xml_failure(parser); +} +END_TEST + + +START_TEST(test_u0000_char) +{ + /* test that a NUL byte (in US-ASCII data) is an error */ + expect_failure("", + XML_ERROR_BAD_CHAR_REF, + "Parser did not report error on NUL-byte."); +} +END_TEST + +START_TEST(test_bom_utf8) +{ + /* This test is really just making sure we don't core on a UTF-8 BOM. */ + char *text = "\357\273\277"; + + if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR) + xml_failure(parser); +} +END_TEST + +START_TEST(test_bom_utf16_be) +{ + char text[] = "\376\377\0<\0e\0/\0>"; + + if (XML_Parse(parser, text, sizeof(text)-1, XML_TRUE) == XML_STATUS_ERROR) + xml_failure(parser); +} +END_TEST + +START_TEST(test_bom_utf16_le) +{ + char text[] = "\377\376<\0e\0/\0>\0"; + + if (XML_Parse(parser, text, sizeof(text)-1, XML_TRUE) == XML_STATUS_ERROR) + xml_failure(parser); +} +END_TEST + +static void XMLCALL +accumulate_characters(void *userData, const XML_Char *s, int len) +{ + CharData_AppendXMLChars((CharData *)userData, s, len); +} + +static void XMLCALL +accumulate_attribute(void *userData, const XML_Char *name, + const XML_Char **atts) +{ + CharData *storage = (CharData *)userData; + if (storage->count < 0 && atts != NULL && atts[0] != NULL) { + /* "accumulate" the value of the first attribute we see */ + CharData_AppendXMLChars(storage, atts[1], -1); + } +} + + +static void +_run_character_check(XML_Char *text, XML_Char *expected, + const char *file, int line) +{ + CharData storage; + + CharData_Init(&storage); + XML_SetUserData(parser, &storage); + XML_SetCharacterDataHandler(parser, accumulate_characters); + if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR) + _xml_failure(parser, file, line); + CharData_CheckXMLChars(&storage, expected); +} + +#define run_character_check(text, expected) \ + _run_character_check(text, expected, __FILE__, __LINE__) + +static void +_run_attribute_check(XML_Char *text, XML_Char *expected, + const char *file, int line) +{ + CharData storage; + + CharData_Init(&storage); + XML_SetUserData(parser, &storage); + XML_SetStartElementHandler(parser, accumulate_attribute); + if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR) + _xml_failure(parser, file, line); + CharData_CheckXMLChars(&storage, expected); +} + +#define run_attribute_check(text, expected) \ + _run_attribute_check(text, expected, __FILE__, __LINE__) + +/* Regression test for SF bug #491986. */ +START_TEST(test_danish_latin1) +{ + char *text = + "\n" + "J\xF8rgen \xE6\xF8\xE5\xC6\xD8\xC5"; + run_character_check(text, + "J\xC3\xB8rgen \xC3\xA6\xC3\xB8\xC3\xA5\xC3\x86\xC3\x98\xC3\x85"); +} +END_TEST + + +/* Regression test for SF bug #514281. */ +START_TEST(test_french_charref_hexidecimal) +{ + char *text = + "\n" + "éèàçêÈ"; + run_character_check(text, + "\xC3\xA9\xC3\xA8\xC3\xA0\xC3\xA7\xC3\xAA\xC3\x88"); +} +END_TEST + +START_TEST(test_french_charref_decimal) +{ + char *text = + "\n" + "éèàçêÈ"; + run_character_check(text, + "\xC3\xA9\xC3\xA8\xC3\xA0\xC3\xA7\xC3\xAA\xC3\x88"); +} +END_TEST + +START_TEST(test_french_latin1) +{ + char *text = + "\n" + "\xE9\xE8\xE0\xE7\xEa\xC8"; + run_character_check(text, + "\xC3\xA9\xC3\xA8\xC3\xA0\xC3\xA7\xC3\xAA\xC3\x88"); +} +END_TEST + +START_TEST(test_french_utf8) +{ + char *text = + "\n" + "\xC3\xA9"; + run_character_check(text, "\xC3\xA9"); +} +END_TEST + +/* Regression test for SF bug #600479. + XXX There should be a test that exercises all legal XML Unicode + characters as PCDATA and attribute value content, and XML Name + characters as part of element and attribute names. +*/ +START_TEST(test_utf8_false_rejection) +{ + char *text = "\xEF\xBA\xBF"; + run_character_check(text, "\xEF\xBA\xBF"); +} +END_TEST + +/* Regression test for SF bug #477667. + This test assures that any 8-bit character followed by a 7-bit + character will not be mistakenly interpreted as a valid UTF-8 + sequence. +*/ +START_TEST(test_illegal_utf8) +{ + char text[100]; + int i; + + for (i = 128; i <= 255; ++i) { + sprintf(text, "%ccd", i); + if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_OK) { + sprintf(text, + "expected token error for '%c' (ordinal %d) in UTF-8 text", + i, i); + fail(text); + } + else if (XML_GetErrorCode(parser) != XML_ERROR_INVALID_TOKEN) + xml_failure(parser); + /* Reset the parser since we use the same parser repeatedly. */ + XML_ParserReset(parser, NULL); + } +} +END_TEST + +START_TEST(test_utf16) +{ + /* + some text + */ + char text[] = + "\000<\000?\000x\000m\000\154\000 \000v\000e\000r\000s\000i\000o" + "\000n\000=\000'\0001\000.\000\060\000'\000 \000e\000n\000c\000o" + "\000d\000i\000n\000g\000=\000'\000U\000T\000F\000-\0001\000\066" + "\000'\000?\000>\000\n" + "\000<\000d\000o\000c\000 \000a\000=\000'\0001\0002\0003\000'" + "\000>\000s\000o\000m\000e\000 \000t\000e\000x\000t\000<\000/" + "\000d\000o\000c\000>"; + if (XML_Parse(parser, text, sizeof(text)-1, XML_TRUE) == XML_STATUS_ERROR) + xml_failure(parser); +} +END_TEST + +START_TEST(test_utf16_le_epilog_newline) +{ + int first_chunk_bytes = 17; + char text[] = + "\xFF\xFE" /* BOM */ + "<\000e\000/\000>\000" /* document element */ + "\r\000\n\000\r\000\n\000"; /* epilog */ + + if (first_chunk_bytes >= sizeof(text) - 1) + fail("bad value of first_chunk_bytes"); + if ( XML_Parse(parser, text, first_chunk_bytes, XML_FALSE) + == XML_STATUS_ERROR) + xml_failure(parser); + else { + enum XML_Status rc; + rc = XML_Parse(parser, text + first_chunk_bytes, + sizeof(text) - first_chunk_bytes - 1, XML_TRUE); + if (rc == XML_STATUS_ERROR) + xml_failure(parser); + } +} +END_TEST + +/* Regression test for SF bug #481609, #774028. */ +START_TEST(test_latin1_umlauts) +{ + char *text = + "\n" + "\xE4 \xF6 \xFC ä ö ü ä ö ü >"; + char *utf8 = + "\xC3\xA4 \xC3\xB6 \xC3\xBC " + "\xC3\xA4 \xC3\xB6 \xC3\xBC " + "\xC3\xA4 \xC3\xB6 \xC3\xBC >"; + run_character_check(text, utf8); + XML_ParserReset(parser, NULL); + run_attribute_check(text, utf8); +} +END_TEST + +/* Regression test #1 for SF bug #653180. */ +START_TEST(test_line_number_after_parse) +{ + char *text = + "\n" + "\n" + "\n"; + XML_Size lineno; + + if (XML_Parse(parser, text, strlen(text), XML_FALSE) == XML_STATUS_ERROR) + xml_failure(parser); + lineno = XML_GetCurrentLineNumber(parser); + if (lineno != 4) { + char buffer[100]; + sprintf(buffer, + "expected 4 lines, saw %" XML_FMT_INT_MOD "u", lineno); + fail(buffer); + } +} +END_TEST + +/* Regression test #2 for SF bug #653180. */ +START_TEST(test_column_number_after_parse) +{ + char *text = ""; + XML_Size colno; + + if (XML_Parse(parser, text, strlen(text), XML_FALSE) == XML_STATUS_ERROR) + xml_failure(parser); + colno = XML_GetCurrentColumnNumber(parser); + if (colno != 11) { + char buffer[100]; + sprintf(buffer, + "expected 11 columns, saw %" XML_FMT_INT_MOD "u", colno); + fail(buffer); + } +} +END_TEST + +static void XMLCALL +start_element_event_handler2(void *userData, const XML_Char *name, + const XML_Char **attr) +{ + CharData *storage = (CharData *) userData; + char buffer[100]; + + sprintf(buffer, + "<%s> at col:%" XML_FMT_INT_MOD "u line:%"\ + XML_FMT_INT_MOD "u\n", name, + XML_GetCurrentColumnNumber(parser), + XML_GetCurrentLineNumber(parser)); + CharData_AppendString(storage, buffer); +} + +static void XMLCALL +end_element_event_handler2(void *userData, const XML_Char *name) +{ + CharData *storage = (CharData *) userData; + char buffer[100]; + + sprintf(buffer, + " at col:%" XML_FMT_INT_MOD "u line:%"\ + XML_FMT_INT_MOD "u\n", name, + XML_GetCurrentColumnNumber(parser), + XML_GetCurrentLineNumber(parser)); + CharData_AppendString(storage, buffer); +} + +/* Regression test #3 for SF bug #653180. */ +START_TEST(test_line_and_column_numbers_inside_handlers) +{ + char *text = + "\n" /* Unix end-of-line */ + " \r\n" /* Windows end-of-line */ + " \r" /* Mac OS end-of-line */ + " \n" + " \n" + " \n" + " \n" + ""; + char *expected = + " at col:0 line:1\n" + " at col:2 line:2\n" + " at col:4 line:3\n" + " at col:8 line:3\n" + " at col:2 line:4\n" + " at col:2 line:5\n" + " at col:4 line:6\n" + " at col:8 line:6\n" + " at col:2 line:7\n" + " at col:0 line:8\n"; + CharData storage; + + CharData_Init(&storage); + XML_SetUserData(parser, &storage); + XML_SetStartElementHandler(parser, start_element_event_handler2); + XML_SetEndElementHandler(parser, end_element_event_handler2); + if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR) + xml_failure(parser); + + CharData_CheckString(&storage, expected); +} +END_TEST + +/* Regression test #4 for SF bug #653180. */ +START_TEST(test_line_number_after_error) +{ + char *text = + "\n" + " \n" + " "; /* missing */ + XML_Size lineno; + if (XML_Parse(parser, text, strlen(text), XML_FALSE) != XML_STATUS_ERROR) + fail("Expected a parse error"); + + lineno = XML_GetCurrentLineNumber(parser); + if (lineno != 3) { + char buffer[100]; + sprintf(buffer, "expected 3 lines, saw %" XML_FMT_INT_MOD "u", lineno); + fail(buffer); + } +} +END_TEST + +/* Regression test #5 for SF bug #653180. */ +START_TEST(test_column_number_after_error) +{ + char *text = + "\n" + " \n" + " "; /* missing */ + XML_Size colno; + if (XML_Parse(parser, text, strlen(text), XML_FALSE) != XML_STATUS_ERROR) + fail("Expected a parse error"); + + colno = XML_GetCurrentColumnNumber(parser); + if (colno != 4) { + char buffer[100]; + sprintf(buffer, + "expected 4 columns, saw %" XML_FMT_INT_MOD "u", colno); + fail(buffer); + } +} +END_TEST + +/* Regression test for SF bug #478332. */ +START_TEST(test_really_long_lines) +{ + /* This parses an input line longer than INIT_DATA_BUF_SIZE + characters long (defined to be 1024 in xmlparse.c). We take a + really cheesy approach to building the input buffer, because + this avoids writing bugs in buffer-filling code. + */ + char *text = + "" + /* 64 chars */ + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" + /* until we have at least 1024 characters on the line: */ + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" + ""; + if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR) + xml_failure(parser); +} +END_TEST + + +/* + * Element event tests. + */ + +static void XMLCALL +end_element_event_handler(void *userData, const XML_Char *name) +{ + CharData *storage = (CharData *) userData; + CharData_AppendString(storage, "/"); + CharData_AppendXMLChars(storage, name, -1); +} + +START_TEST(test_end_element_events) +{ + char *text = ""; + char *expected = "/c/b/f/d/a"; + CharData storage; + + CharData_Init(&storage); + XML_SetUserData(parser, &storage); + XML_SetEndElementHandler(parser, end_element_event_handler); + if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR) + xml_failure(parser); + CharData_CheckString(&storage, expected); +} +END_TEST + + +/* + * Attribute tests. + */ + +/* Helpers used by the following test; this checks any "attr" and "refs" + attributes to make sure whitespace has been normalized. + + Return true if whitespace has been normalized in a string, using + the rules for attribute value normalization. The 'is_cdata' flag + is needed since CDATA attributes don't need to have multiple + whitespace characters collapsed to a single space, while other + attribute data types do. (Section 3.3.3 of the recommendation.) +*/ +static int +is_whitespace_normalized(const XML_Char *s, int is_cdata) +{ + int blanks = 0; + int at_start = 1; + while (*s) { + if (*s == ' ') + ++blanks; + else if (*s == '\t' || *s == '\n' || *s == '\r') + return 0; + else { + if (at_start) { + at_start = 0; + if (blanks && !is_cdata) + /* illegal leading blanks */ + return 0; + } + else if (blanks > 1 && !is_cdata) + return 0; + blanks = 0; + } + ++s; + } + if (blanks && !is_cdata) + return 0; + return 1; +} + +/* Check the attribute whitespace checker: */ +static void +testhelper_is_whitespace_normalized(void) +{ + assert(is_whitespace_normalized("abc", 0)); + assert(is_whitespace_normalized("abc", 1)); + assert(is_whitespace_normalized("abc def ghi", 0)); + assert(is_whitespace_normalized("abc def ghi", 1)); + assert(!is_whitespace_normalized(" abc def ghi", 0)); + assert(is_whitespace_normalized(" abc def ghi", 1)); + assert(!is_whitespace_normalized("abc def ghi", 0)); + assert(is_whitespace_normalized("abc def ghi", 1)); + assert(!is_whitespace_normalized("abc def ghi ", 0)); + assert(is_whitespace_normalized("abc def ghi ", 1)); + assert(!is_whitespace_normalized(" ", 0)); + assert(is_whitespace_normalized(" ", 1)); + assert(!is_whitespace_normalized("\t", 0)); + assert(!is_whitespace_normalized("\t", 1)); + assert(!is_whitespace_normalized("\n", 0)); + assert(!is_whitespace_normalized("\n", 1)); + assert(!is_whitespace_normalized("\r", 0)); + assert(!is_whitespace_normalized("\r", 1)); + assert(!is_whitespace_normalized("abc\t def", 1)); +} + +static void XMLCALL +check_attr_contains_normalized_whitespace(void *userData, + const XML_Char *name, + const XML_Char **atts) +{ + int i; + for (i = 0; atts[i] != NULL; i += 2) { + const XML_Char *attrname = atts[i]; + const XML_Char *value = atts[i + 1]; + if (strcmp("attr", attrname) == 0 + || strcmp("ents", attrname) == 0 + || strcmp("refs", attrname) == 0) { + if (!is_whitespace_normalized(value, 0)) { + char buffer[256]; + sprintf(buffer, "attribute value not normalized: %s='%s'", + attrname, value); + fail(buffer); + } + } + } +} + +START_TEST(test_attr_whitespace_normalization) +{ + char *text = + "\n" + "]>\n" + "\n" + " \n" + " \n" + ""; + + XML_SetStartElementHandler(parser, + check_attr_contains_normalized_whitespace); + if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR) + xml_failure(parser); +} +END_TEST + + +/* + * XML declaration tests. + */ + +START_TEST(test_xmldecl_misplaced) +{ + expect_failure("\n" + "\n" + "", + XML_ERROR_MISPLACED_XML_PI, + "failed to report misplaced XML declaration"); +} +END_TEST + +/* Regression test for SF bug #584832. */ +static int XMLCALL +UnknownEncodingHandler(void *data,const XML_Char *encoding,XML_Encoding *info) +{ + if (strcmp(encoding,"unsupported-encoding") == 0) { + int i; + for (i = 0; i < 256; ++i) + info->map[i] = i; + info->data = NULL; + info->convert = NULL; + info->release = NULL; + return XML_STATUS_OK; + } + return XML_STATUS_ERROR; +} + +START_TEST(test_unknown_encoding_internal_entity) +{ + char *text = + "\n" + "]>\n" + ""; + + XML_SetUnknownEncodingHandler(parser, UnknownEncodingHandler, NULL); + if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR) + xml_failure(parser); +} +END_TEST + +/* Regression test for SF bug #620106. */ +static int XMLCALL +external_entity_loader_set_encoding(XML_Parser parser, + const XML_Char *context, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId) +{ + /* This text says it's an unsupported encoding, but it's really + UTF-8, which we tell Expat using XML_SetEncoding(). + */ + char *text = + "" + "\xC3\xA9"; + XML_Parser extparser; + + extparser = XML_ExternalEntityParserCreate(parser, context, NULL); + if (extparser == NULL) + fail("Could not create external entity parser."); + if (!XML_SetEncoding(extparser, "utf-8")) + fail("XML_SetEncoding() ignored for external entity"); + if ( XML_Parse(extparser, text, strlen(text), XML_TRUE) + == XML_STATUS_ERROR) { + xml_failure(parser); + return 0; + } + return 1; +} + +START_TEST(test_ext_entity_set_encoding) +{ + char *text = + "\n" + "]>\n" + "&en;"; + + XML_SetExternalEntityRefHandler(parser, + external_entity_loader_set_encoding); + run_character_check(text, "\xC3\xA9"); +} +END_TEST + +/* Test that no error is reported for unknown entities if we don't + read an external subset. This was fixed in Expat 1.95.5. +*/ +START_TEST(test_wfc_undeclared_entity_unread_external_subset) { + char *text = + "\n" + "&entity;"; + + if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR) + xml_failure(parser); +} +END_TEST + +/* Test that an error is reported for unknown entities if we don't + have an external subset. +*/ +START_TEST(test_wfc_undeclared_entity_no_external_subset) { + expect_failure("&entity;", + XML_ERROR_UNDEFINED_ENTITY, + "Parser did not report undefined entity w/out a DTD."); +} +END_TEST + +/* Test that an error is reported for unknown entities if we don't + read an external subset, but have been declared standalone. +*/ +START_TEST(test_wfc_undeclared_entity_standalone) { + char *text = + "\n" + "\n" + "&entity;"; + + expect_failure(text, + XML_ERROR_UNDEFINED_ENTITY, + "Parser did not report undefined entity (standalone)."); +} +END_TEST + +static int XMLCALL +external_entity_loader(XML_Parser parser, + const XML_Char *context, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId) +{ + char *text = (char *)XML_GetUserData(parser); + XML_Parser extparser; + + extparser = XML_ExternalEntityParserCreate(parser, context, NULL); + if (extparser == NULL) + fail("Could not create external entity parser."); + if ( XML_Parse(extparser, text, strlen(text), XML_TRUE) + == XML_STATUS_ERROR) { + xml_failure(parser); + return XML_STATUS_ERROR; + } + return XML_STATUS_OK; +} + +/* Test that an error is reported for unknown entities if we have read + an external subset, and standalone is true. +*/ +START_TEST(test_wfc_undeclared_entity_with_external_subset_standalone) { + char *text = + "\n" + "\n" + "&entity;"; + char *foo_text = + ""; + + XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS); + XML_SetUserData(parser, foo_text); + XML_SetExternalEntityRefHandler(parser, external_entity_loader); + expect_failure(text, + XML_ERROR_UNDEFINED_ENTITY, + "Parser did not report undefined entity (external DTD)."); +} +END_TEST + +/* Test that no error is reported for unknown entities if we have read + an external subset, and standalone is false. +*/ +START_TEST(test_wfc_undeclared_entity_with_external_subset) { + char *text = + "\n" + "\n" + "&entity;"; + char *foo_text = + ""; + + XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS); + XML_SetUserData(parser, foo_text); + XML_SetExternalEntityRefHandler(parser, external_entity_loader); + if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR) + xml_failure(parser); +} +END_TEST + +START_TEST(test_wfc_no_recursive_entity_refs) +{ + char *text = + "\n" + "]>\n" + "&entity;"; + + expect_failure(text, + XML_ERROR_RECURSIVE_ENTITY_REF, + "Parser did not report recursive entity reference."); +} +END_TEST + +/* Regression test for SF bug #483514. */ +START_TEST(test_dtd_default_handling) +{ + char *text = + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "]>"; + + XML_SetDefaultHandler(parser, accumulate_characters); + XML_SetDoctypeDeclHandler(parser, + dummy_start_doctype_handler, + dummy_end_doctype_handler); + XML_SetEntityDeclHandler(parser, dummy_entity_decl_handler); + XML_SetNotationDeclHandler(parser, dummy_notation_decl_handler); + XML_SetElementDeclHandler(parser, dummy_element_decl_handler); + XML_SetAttlistDeclHandler(parser, dummy_attlist_decl_handler); + XML_SetProcessingInstructionHandler(parser, dummy_pi_handler); + XML_SetCommentHandler(parser, dummy_comment_handler); + run_character_check(text, "\n\n\n\n\n\n\n"); +} +END_TEST + +/* See related SF bug #673791. + When namespace processing is enabled, setting the namespace URI for + a prefix is not allowed; this test ensures that it *is* allowed + when namespace processing is not enabled. + (See Namespaces in XML, section 2.) +*/ +START_TEST(test_empty_ns_without_namespaces) +{ + char *text = + "\n" + " \n" + ""; + + if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR) + xml_failure(parser); +} +END_TEST + +/* Regression test for SF bug #824420. + Checks that an xmlns:prefix attribute set in an attribute's default + value isn't misinterpreted. +*/ +START_TEST(test_ns_in_attribute_default_without_namespaces) +{ + char *text = + "\n" + " ]>\n" + ""; + + if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR) + xml_failure(parser); +} +END_TEST + + +/* + * Namespaces tests. + */ + +static void +namespace_setup(void) +{ + parser = XML_ParserCreateNS(NULL, ' '); + if (parser == NULL) + fail("Parser not created."); +} + +static void +namespace_teardown(void) +{ + basic_teardown(); +} + +/* Check that an element name and attribute name match the expected values. + The expected values are passed as an array reference of string pointers + provided as the userData argument; the first is the expected + element name, and the second is the expected attribute name. +*/ +static void XMLCALL +triplet_start_checker(void *userData, const XML_Char *name, + const XML_Char **atts) +{ + char **elemstr = (char **)userData; + char buffer[1024]; + if (strcmp(elemstr[0], name) != 0) { + sprintf(buffer, "unexpected start string: '%s'", name); + fail(buffer); + } + if (strcmp(elemstr[1], atts[0]) != 0) { + sprintf(buffer, "unexpected attribute string: '%s'", atts[0]); + fail(buffer); + } +} + +/* Check that the element name passed to the end-element handler matches + the expected value. The expected value is passed as the first element + in an array of strings passed as the userData argument. +*/ +static void XMLCALL +triplet_end_checker(void *userData, const XML_Char *name) +{ + char **elemstr = (char **)userData; + if (strcmp(elemstr[0], name) != 0) { + char buffer[1024]; + sprintf(buffer, "unexpected end string: '%s'", name); + fail(buffer); + } +} + +START_TEST(test_return_ns_triplet) +{ + char *text = + ""; + char *elemstr[] = { + "http://expat.sf.net/ e foo", + "http://expat.sf.net/ a bar" + }; + XML_SetReturnNSTriplet(parser, XML_TRUE); + XML_SetUserData(parser, elemstr); + XML_SetElementHandler(parser, triplet_start_checker, triplet_end_checker); + if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR) + xml_failure(parser); +} +END_TEST + +static void XMLCALL +overwrite_start_checker(void *userData, const XML_Char *name, + const XML_Char **atts) +{ + CharData *storage = (CharData *) userData; + CharData_AppendString(storage, "start "); + CharData_AppendXMLChars(storage, name, -1); + while (*atts != NULL) { + CharData_AppendString(storage, "\nattribute "); + CharData_AppendXMLChars(storage, *atts, -1); + atts += 2; + } + CharData_AppendString(storage, "\n"); +} + +static void XMLCALL +overwrite_end_checker(void *userData, const XML_Char *name) +{ + CharData *storage = (CharData *) userData; + CharData_AppendString(storage, "end "); + CharData_AppendXMLChars(storage, name, -1); + CharData_AppendString(storage, "\n"); +} + +static void +run_ns_tagname_overwrite_test(char *text, char *result) +{ + CharData storage; + CharData_Init(&storage); + XML_SetUserData(parser, &storage); + XML_SetElementHandler(parser, + overwrite_start_checker, overwrite_end_checker); + if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR) + xml_failure(parser); + CharData_CheckString(&storage, result); +} + +/* Regression test for SF bug #566334. */ +START_TEST(test_ns_tagname_overwrite) +{ + char *text = + "\n" + " \n" + " \n" + ""; + char *result = + "start http://xml.libexpat.org/ e\n" + "start http://xml.libexpat.org/ f\n" + "attribute http://xml.libexpat.org/ attr\n" + "end http://xml.libexpat.org/ f\n" + "start http://xml.libexpat.org/ g\n" + "attribute http://xml.libexpat.org/ attr2\n" + "end http://xml.libexpat.org/ g\n" + "end http://xml.libexpat.org/ e\n"; + run_ns_tagname_overwrite_test(text, result); +} +END_TEST + +/* Regression test for SF bug #566334. */ +START_TEST(test_ns_tagname_overwrite_triplet) +{ + char *text = + "\n" + " \n" + " \n" + ""; + char *result = + "start http://xml.libexpat.org/ e n\n" + "start http://xml.libexpat.org/ f n\n" + "attribute http://xml.libexpat.org/ attr n\n" + "end http://xml.libexpat.org/ f n\n" + "start http://xml.libexpat.org/ g n\n" + "attribute http://xml.libexpat.org/ attr2 n\n" + "end http://xml.libexpat.org/ g n\n" + "end http://xml.libexpat.org/ e n\n"; + XML_SetReturnNSTriplet(parser, XML_TRUE); + run_ns_tagname_overwrite_test(text, result); +} +END_TEST + + +/* Regression test for SF bug #620343. */ +static void XMLCALL +start_element_fail(void *userData, + const XML_Char *name, const XML_Char **atts) +{ + /* We should never get here. */ + fail("should never reach start_element_fail()"); +} + +static void XMLCALL +start_ns_clearing_start_element(void *userData, + const XML_Char *prefix, + const XML_Char *uri) +{ + XML_SetStartElementHandler((XML_Parser) userData, NULL); +} + +START_TEST(test_start_ns_clears_start_element) +{ + /* This needs to use separate start/end tags; using the empty tag + syntax doesn't cause the problematic path through Expat to be + taken. + */ + char *text = ""; + + XML_SetStartElementHandler(parser, start_element_fail); + XML_SetStartNamespaceDeclHandler(parser, start_ns_clearing_start_element); + XML_UseParserAsHandlerArg(parser); + if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR) + xml_failure(parser); +} +END_TEST + +/* Regression test for SF bug #616863. */ +static int XMLCALL +external_entity_handler(XML_Parser parser, + const XML_Char *context, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId) +{ + int callno = 1 + (int)XML_GetUserData(parser); + char *text; + XML_Parser p2; + + if (callno == 1) + text = ("\n" + "\n" + "\n"); + else + text = ("" + ""); + + XML_SetUserData(parser, (void *) callno); + p2 = XML_ExternalEntityParserCreate(parser, context, NULL); + if (XML_Parse(p2, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR) { + xml_failure(p2); + return 0; + } + XML_ParserFree(p2); + return 1; +} + +START_TEST(test_default_ns_from_ext_subset_and_ext_ge) +{ + char *text = + "\n" + "\n" + "]>\n" + "\n" + "&en;\n" + ""; + + XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS); + XML_SetExternalEntityRefHandler(parser, external_entity_handler); + /* We actually need to set this handler to tickle this bug. */ + XML_SetStartElementHandler(parser, dummy_start_element); + XML_SetUserData(parser, NULL); + if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR) + xml_failure(parser); +} +END_TEST + +/* Regression test #1 for SF bug #673791. */ +START_TEST(test_ns_prefix_with_empty_uri_1) +{ + char *text = + "\n" + " \n" + ""; + + expect_failure(text, + XML_ERROR_UNDECLARING_PREFIX, + "Did not report re-setting namespace" + " URI with prefix to ''."); +} +END_TEST + +/* Regression test #2 for SF bug #673791. */ +START_TEST(test_ns_prefix_with_empty_uri_2) +{ + char *text = + "\n" + ""; + + expect_failure(text, + XML_ERROR_UNDECLARING_PREFIX, + "Did not report setting namespace URI with prefix to ''."); +} +END_TEST + +/* Regression test #3 for SF bug #673791. */ +START_TEST(test_ns_prefix_with_empty_uri_3) +{ + char *text = + "\n" + " \n" + "]>\n" + ""; + + expect_failure(text, + XML_ERROR_UNDECLARING_PREFIX, + "Didn't report attr default setting NS w/ prefix to ''."); +} +END_TEST + +/* Regression test #4 for SF bug #673791. */ +START_TEST(test_ns_prefix_with_empty_uri_4) +{ + char *text = + "\n" + " \n" + "]>\n" + ""; + /* Packaged info expected by the end element handler; + the weird structuring lets us re-use the triplet_end_checker() + function also used for another test. */ + char *elemstr[] = { + "http://xml.libexpat.org/ doc prefix" + }; + XML_SetReturnNSTriplet(parser, XML_TRUE); + XML_SetUserData(parser, elemstr); + XML_SetEndElementHandler(parser, triplet_end_checker); + if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR) + xml_failure(parser); +} +END_TEST + +START_TEST(test_ns_default_with_empty_uri) +{ + char *text = + "\n" + " \n" + ""; + if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR) + xml_failure(parser); +} +END_TEST + +/* Regression test for SF bug #692964: two prefixes for one namespace. */ +START_TEST(test_ns_duplicate_attrs_diff_prefixes) +{ + char *text = + ""; + expect_failure(text, + XML_ERROR_DUPLICATE_ATTRIBUTE, + "did not report multiple attributes with same URI+name"); +} +END_TEST + +/* Regression test for SF bug #695401: unbound prefix. */ +START_TEST(test_ns_unbound_prefix_on_attribute) +{ + char *text = ""; + expect_failure(text, + XML_ERROR_UNBOUND_PREFIX, + "did not report unbound prefix on attribute"); +} +END_TEST + +/* Regression test for SF bug #695401: unbound prefix. */ +START_TEST(test_ns_unbound_prefix_on_element) +{ + char *text = ""; + expect_failure(text, + XML_ERROR_UNBOUND_PREFIX, + "did not report unbound prefix on element"); +} +END_TEST + +static Suite * +make_suite(void) +{ + Suite *s = suite_create("basic"); + TCase *tc_basic = tcase_create("basic tests"); + TCase *tc_namespace = tcase_create("XML namespaces"); + + suite_add_tcase(s, tc_basic); + tcase_add_checked_fixture(tc_basic, basic_setup, basic_teardown); + tcase_add_test(tc_basic, test_nul_byte); + tcase_add_test(tc_basic, test_u0000_char); + tcase_add_test(tc_basic, test_bom_utf8); + tcase_add_test(tc_basic, test_bom_utf16_be); + tcase_add_test(tc_basic, test_bom_utf16_le); + tcase_add_test(tc_basic, test_illegal_utf8); + tcase_add_test(tc_basic, test_utf16); + tcase_add_test(tc_basic, test_utf16_le_epilog_newline); + tcase_add_test(tc_basic, test_latin1_umlauts); + /* Regression test for SF bug #491986. */ + tcase_add_test(tc_basic, test_danish_latin1); + /* Regression test for SF bug #514281. */ + tcase_add_test(tc_basic, test_french_charref_hexidecimal); + tcase_add_test(tc_basic, test_french_charref_decimal); + tcase_add_test(tc_basic, test_french_latin1); + tcase_add_test(tc_basic, test_french_utf8); + tcase_add_test(tc_basic, test_utf8_false_rejection); + tcase_add_test(tc_basic, test_line_number_after_parse); + tcase_add_test(tc_basic, test_column_number_after_parse); + tcase_add_test(tc_basic, test_line_and_column_numbers_inside_handlers); + tcase_add_test(tc_basic, test_line_number_after_error); + tcase_add_test(tc_basic, test_column_number_after_error); + tcase_add_test(tc_basic, test_really_long_lines); + tcase_add_test(tc_basic, test_end_element_events); + tcase_add_test(tc_basic, test_attr_whitespace_normalization); + tcase_add_test(tc_basic, test_xmldecl_misplaced); + tcase_add_test(tc_basic, test_unknown_encoding_internal_entity); + tcase_add_test(tc_basic, + test_wfc_undeclared_entity_unread_external_subset); + tcase_add_test(tc_basic, test_wfc_undeclared_entity_no_external_subset); + tcase_add_test(tc_basic, test_wfc_undeclared_entity_standalone); + tcase_add_test(tc_basic, test_wfc_undeclared_entity_with_external_subset); + tcase_add_test(tc_basic, + test_wfc_undeclared_entity_with_external_subset_standalone); + tcase_add_test(tc_basic, test_wfc_no_recursive_entity_refs); + tcase_add_test(tc_basic, test_ext_entity_set_encoding); + tcase_add_test(tc_basic, test_dtd_default_handling); + tcase_add_test(tc_basic, test_empty_ns_without_namespaces); + tcase_add_test(tc_basic, test_ns_in_attribute_default_without_namespaces); + + suite_add_tcase(s, tc_namespace); + tcase_add_checked_fixture(tc_namespace, + namespace_setup, namespace_teardown); + tcase_add_test(tc_namespace, test_return_ns_triplet); + tcase_add_test(tc_namespace, test_ns_tagname_overwrite); + tcase_add_test(tc_namespace, test_ns_tagname_overwrite_triplet); + tcase_add_test(tc_namespace, test_start_ns_clears_start_element); + tcase_add_test(tc_namespace, test_default_ns_from_ext_subset_and_ext_ge); + tcase_add_test(tc_namespace, test_ns_prefix_with_empty_uri_1); + tcase_add_test(tc_namespace, test_ns_prefix_with_empty_uri_2); + tcase_add_test(tc_namespace, test_ns_prefix_with_empty_uri_3); + tcase_add_test(tc_namespace, test_ns_prefix_with_empty_uri_4); + tcase_add_test(tc_namespace, test_ns_default_with_empty_uri); + tcase_add_test(tc_namespace, test_ns_duplicate_attrs_diff_prefixes); + tcase_add_test(tc_namespace, test_ns_unbound_prefix_on_attribute); + tcase_add_test(tc_namespace, test_ns_unbound_prefix_on_element); + + return s; +} + + +#ifdef AMIGA_SHARED_LIB +int +amiga_main(int argc, char *argv[]) +#else +int +main(int argc, char *argv[]) +#endif +{ + int i, nf; + int forking = 0, forking_set = 0; + int verbosity = CK_NORMAL; + Suite *s = make_suite(); + SRunner *sr = srunner_create(s); + + /* run the tests for internal helper functions */ + testhelper_is_whitespace_normalized(); + + for (i = 1; i < argc; ++i) { + char *opt = argv[i]; + if (strcmp(opt, "-v") == 0 || strcmp(opt, "--verbose") == 0) + verbosity = CK_VERBOSE; + else if (strcmp(opt, "-q") == 0 || strcmp(opt, "--quiet") == 0) + verbosity = CK_SILENT; + else if (strcmp(opt, "-f") == 0 || strcmp(opt, "--fork") == 0) { + forking = 1; + forking_set = 1; + } + else if (strcmp(opt, "-n") == 0 || strcmp(opt, "--no-fork") == 0) { + forking = 0; + forking_set = 1; + } + else { + fprintf(stderr, "runtests: unknown option '%s'\n", opt); + return 2; + } + } + if (forking_set) + srunner_set_fork_status(sr, forking ? CK_FORK : CK_NOFORK); + if (verbosity != CK_SILENT) + printf("Expat version: %s\n", XML_ExpatVersion()); + srunner_run_all(sr, verbosity); + nf = srunner_ntests_failed(sr); + srunner_free(sr); + + return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/gdcm/Utilities/gdcmexpat/tests/runtestspp.cpp b/gdcm/Utilities/gdcmexpat/tests/runtestspp.cpp new file mode 100644 index 0000000..c35dc58 --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/tests/runtestspp.cpp @@ -0,0 +1,6 @@ +// C++ compilation harness for the test suite. +// +// This is used to ensure the Expat headers can be included from C++ +// and have everything work as expected. +// +#include "runtests.c" diff --git a/gdcm/Utilities/gdcmexpat/tests/xmltest.sh b/gdcm/Utilities/gdcmexpat/tests/xmltest.sh new file mode 100644 index 0000000..725441e --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/tests/xmltest.sh @@ -0,0 +1,141 @@ +#! /bin/sh + +# EXPAT TEST SCRIPT FOR W3C XML TEST SUITE + +# This script can be used to exercise Expat against the +# w3c.org xml test suite, available from +# http://www.w3.org/XML/Test/xmlts20020606.zip. + +# To run this script, first set XMLWF so that xmlwf can be +# found, then set the output directory with OUTPUT. + +# The script lists all test cases where Expat shows a discrepancy +# from the expected result. Test cases where only the canonical +# output differs are prefixed with "Output differs:", and a diff file +# is generated in the appropriate subdirectory under $OUTPUT. + +# If there are output files provided, the script will use +# output from xmlwf and compare the desired output against it. +# However, one has to take into account that the canonical output +# produced by xmlwf conforms to an older definition of canonical XML +# and does not generate notation declarations. + +MYDIR="`dirname \"$0\"`" +cd "$MYDIR" +MYDIR="`pwd`" +XMLWF="`dirname \"$MYDIR\"`/xmlwf/xmlwf" +# XMLWF=/usr/local/bin/xmlwf +TS="$MYDIR/XML-Test-Suite" +# OUTPUT must terminate with the directory separator. +OUTPUT="$TS/out/" +# OUTPUT=/home/tmp/xml-testsuite-out/ + + +# RunXmlwfNotWF file reldir +# reldir includes trailing slash +RunXmlwfNotWF() { + file="$1" + reldir="$2" + $XMLWF -p "$file" > outfile || return $? + read outdata < outfile + if test "$outdata" = "" ; then + echo "Expected well-formed: $reldir$file" + return 1 + else + return 0 + fi +} + +# RunXmlwfWF file reldir +# reldir includes trailing slash +RunXmlwfWF() { + file="$1" + reldir="$2" + $XMLWF -p -d "$OUTPUT$reldir" "$file" > outfile || return $? + read outdata < outfile + if test "$outdata" = "" ; then + if [ -f "out/$file" ] ; then + diff "$OUTPUT$reldir$file" "out/$file" > outfile + if [ -s outfile ] ; then + cp outfile "$OUTPUT$reldir$file.diff" + echo "Output differs: $reldir$file" + return 1 + fi + fi + return 0 + else + echo "In $reldir: $outdata" + return 1 + fi +} + +SUCCESS=0 +ERROR=0 + +UpdateStatus() { + if [ "$1" -eq 0 ] ; then + SUCCESS=`expr $SUCCESS + 1` + else + ERROR=`expr $ERROR + 1` + fi +} + +########################## +# well-formed test cases # +########################## + +cd "$TS/xmlconf" +for xmldir in ibm/valid/P* \ + ibm/invalid/P* \ + xmltest/valid/ext-sa \ + xmltest/valid/not-sa \ + xmltest/invalid \ + xmltest/invalid/not-sa \ + xmltest/valid/sa \ + sun/valid \ + sun/invalid ; do + cd "$TS/xmlconf/$xmldir" + mkdir -p "$OUTPUT$xmldir" + for xmlfile in *.xml ; do + RunXmlwfWF "$xmlfile" "$xmldir/" + UpdateStatus $? + done + rm outfile +done + +cd "$TS/xmlconf/oasis" +mkdir -p "$OUTPUT"oasis +for xmlfile in *pass*.xml ; do + RunXmlwfWF "$xmlfile" "oasis/" + UpdateStatus $? +done +rm outfile + +############################## +# not well-formed test cases # +############################## + +cd "$TS/xmlconf" +for xmldir in ibm/not-wf/P* \ + ibm/not-wf/misc \ + xmltest/not-wf/ext-sa \ + xmltest/not-wf/not-sa \ + xmltest/not-wf/sa \ + sun/not-wf ; do + cd "$TS/xmlconf/$xmldir" + for xmlfile in *.xml ; do + RunXmlwfNotWF "$xmlfile" "$xmldir/" + UpdateStatus $? + done + rm outfile +done + +cd "$TS/xmlconf/oasis" +for xmlfile in *fail*.xml ; do + RunXmlwfNotWF "$xmlfile" "oasis/" + UpdateStatus $? +done +rm outfile + +echo "Passed: $SUCCESS" +echo "Failed: $ERROR" diff --git a/gdcm/Utilities/gdcmexpat/xmlwf/codepage.c b/gdcm/Utilities/gdcmexpat/xmlwf/codepage.c new file mode 100644 index 0000000..e610c7c --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/xmlwf/codepage.c @@ -0,0 +1,68 @@ +/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +#include "codepage.h" + +#ifdef WIN32 +#define STRICT 1 +#define WIN32_LEAN_AND_MEAN 1 + +#include + +int +codepageMap(int cp, int *map) +{ + int i; + CPINFO info; + if (!GetCPInfo(cp, &info) || info.MaxCharSize > 2) + return 0; + for (i = 0; i < 256; i++) + map[i] = -1; + if (info.MaxCharSize > 1) { + for (i = 0; i < MAX_LEADBYTES; i+=2) { + int j, lim; + if (info.LeadByte[i] == 0 && info.LeadByte[i + 1] == 0) + break; + lim = info.LeadByte[i + 1]; + for (j = info.LeadByte[i]; j <= lim; j++) + map[j] = -2; + } + } + for (i = 0; i < 256; i++) { + if (map[i] == -1) { + char c = (char)i; + unsigned short n; + if (MultiByteToWideChar(cp, MB_PRECOMPOSED|MB_ERR_INVALID_CHARS, + &c, 1, &n, 1) == 1) + map[i] = n; + } + } + return 1; +} + +int +codepageConvert(int cp, const char *p) +{ + unsigned short c; + if (MultiByteToWideChar(cp, MB_PRECOMPOSED|MB_ERR_INVALID_CHARS, + p, 2, &c, 1) == 1) + return c; + return -1; +} + +#else /* not WIN32 */ + +int +codepageMap(int cp, int *map) +{ + return 0; +} + +int +codepageConvert(int cp, const char *p) +{ + return -1; +} + +#endif /* not WIN32 */ diff --git a/gdcm/Utilities/gdcmexpat/xmlwf/codepage.h b/gdcm/Utilities/gdcmexpat/xmlwf/codepage.h new file mode 100644 index 0000000..6a4df68 --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/xmlwf/codepage.h @@ -0,0 +1,6 @@ +/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +int codepageMap(int cp, int *map); +int codepageConvert(int cp, const char *p); diff --git a/gdcm/Utilities/gdcmexpat/xmlwf/ct.c b/gdcm/Utilities/gdcmexpat/xmlwf/ct.c new file mode 100644 index 0000000..95903a3 --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/xmlwf/ct.c @@ -0,0 +1,147 @@ +#define CHARSET_MAX 41 + +static const char * +getTok(const char **pp) +{ + enum { inAtom, inString, init, inComment }; + int state = init; + const char *tokStart = 0; + for (;;) { + switch (**pp) { + case '\0': + return 0; + case ' ': + case '\r': + case '\t': + case '\n': + if (state == inAtom) + return tokStart; + break; + case '(': + if (state == inAtom) + return tokStart; + if (state != inString) + state++; + break; + case ')': + if (state > init) + --state; + else if (state != inString) + return 0; + break; + case ';': + case '/': + case '=': + if (state == inAtom) + return tokStart; + if (state == init) + return (*pp)++; + break; + case '\\': + ++*pp; + if (**pp == '\0') + return 0; + break; + case '"': + switch (state) { + case inString: + ++*pp; + return tokStart; + case inAtom: + return tokStart; + case init: + tokStart = *pp; + state = inString; + break; + } + break; + default: + if (state == init) { + tokStart = *pp; + state = inAtom; + } + break; + } + ++*pp; + } + /* not reached */ +} + +/* key must be lowercase ASCII */ + +static int +matchkey(const char *start, const char *end, const char *key) +{ + if (!start) + return 0; + for (; start != end; start++, key++) + if (*start != *key && *start != 'A' + (*key - 'a')) + return 0; + return *key == '\0'; +} + +void +getXMLCharset(const char *buf, char *charset) +{ + const char *next, *p; + + charset[0] = '\0'; + next = buf; + p = getTok(&next); + if (matchkey(p, next, "text")) + strcpy(charset, "us-ascii"); + else if (!matchkey(p, next, "application")) + return; + p = getTok(&next); + if (!p || *p != '/') + return; + p = getTok(&next); + if (matchkey(p, next, "xml")) + isXml = 1; + p = getTok(&next); + while (p) { + if (*p == ';') { + p = getTok(&next); + if (matchkey(p, next, "charset")) { + p = getTok(&next); + if (p && *p == '=') { + p = getTok(&next); + if (p) { + char *s = charset; + if (*p == '"') { + while (++p != next - 1) { + if (*p == '\\') + ++p; + if (s == charset + CHARSET_MAX - 1) { + charset[0] = '\0'; + break; + } + *s++ = *p; + } + *s++ = '\0'; + } + else { + if (next - p > CHARSET_MAX - 1) + break; + while (p != next) + *s++ = *p++; + *s = 0; + break; + } + } + } + } + } + else + p = getTok(&next); + } +} + +int +main(int argc, char **argv) +{ + char buf[CHARSET_MAX]; + getXMLCharset(argv[1], buf); + printf("charset = \"%s\"\n", buf); + return 0; +} diff --git a/gdcm/Utilities/gdcmexpat/xmlwf/filemap.h b/gdcm/Utilities/gdcmexpat/xmlwf/filemap.h new file mode 100644 index 0000000..814edec --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/xmlwf/filemap.h @@ -0,0 +1,17 @@ +/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +#include + +#ifdef XML_UNICODE +int filemap(const wchar_t *name, + void (*processor)(const void *, size_t, + const wchar_t *, void *arg), + void *arg); +#else +int filemap(const char *name, + void (*processor)(const void *, size_t, + const char *, void *arg), + void *arg); +#endif diff --git a/gdcm/Utilities/gdcmexpat/xmlwf/readfilemap.c b/gdcm/Utilities/gdcmexpat/xmlwf/readfilemap.c new file mode 100644 index 0000000..42b5e03 --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/xmlwf/readfilemap.c @@ -0,0 +1,82 @@ +/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +#include +#include +#include +#include +#include + +#ifdef __BEOS__ +#include +#endif + +#ifndef S_ISREG +#ifndef S_IFREG +#define S_IFREG _S_IFREG +#endif +#ifndef S_IFMT +#define S_IFMT _S_IFMT +#endif +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#endif /* not S_ISREG */ + +#ifndef O_BINARY +#ifdef _O_BINARY +#define O_BINARY _O_BINARY +#else +#define O_BINARY 0 +#endif +#endif + +#include "filemap.h" + +int +filemap(const char *name, + void (*processor)(const void *, size_t, const char *, void *arg), + void *arg) +{ + size_t nbytes; + int fd; + int n; + struct stat sb; + void *p; + + fd = open(name, O_RDONLY|O_BINARY); + if (fd < 0) { + perror(name); + return 0; + } + if (fstat(fd, &sb) < 0) { + perror(name); + return 0; + } + if (!S_ISREG(sb.st_mode)) { + fprintf(stderr, "%s: not a regular file\n", name); + return 0; + } + nbytes = sb.st_size; + p = malloc(nbytes); + if (!p) { + fprintf(stderr, "%s: out of memory\n", name); + return 0; + } + n = read(fd, p, nbytes); + if (n < 0) { + perror(name); + free(p); + close(fd); + return 0; + } + if (n != nbytes) { + fprintf(stderr, "%s: read unexpected number of bytes\n", name); + free(p); + close(fd); + return 0; + } + processor(p, nbytes, name, arg); + free(p); + close(fd); + return 1; +} diff --git a/gdcm/Utilities/gdcmexpat/xmlwf/unixfilemap.c b/gdcm/Utilities/gdcmexpat/xmlwf/unixfilemap.c new file mode 100644 index 0000000..22048c8 --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/xmlwf/unixfilemap.c @@ -0,0 +1,58 @@ +/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef MAP_FILE +#define MAP_FILE 0 +#endif + +#include "filemap.h" + +int +filemap(const char *name, + void (*processor)(const void *, size_t, const char *, void *arg), + void *arg) +{ + int fd; + size_t nbytes; + struct stat sb; + void *p; + + fd = open(name, O_RDONLY); + if (fd < 0) { + perror(name); + return 0; + } + if (fstat(fd, &sb) < 0) { + perror(name); + close(fd); + return 0; + } + if (!S_ISREG(sb.st_mode)) { + close(fd); + fprintf(stderr, "%s: not a regular file\n", name); + return 0; + } + + nbytes = sb.st_size; + p = (void *)mmap((caddr_t)0, (size_t)nbytes, PROT_READ, + MAP_FILE|MAP_PRIVATE, fd, (off_t)0); + if (p == (void *)-1) { + perror(name); + close(fd); + return 0; + } + processor(p, nbytes, name, arg); + munmap((caddr_t)p, nbytes); + close(fd); + return 1; +} diff --git a/gdcm/Utilities/gdcmexpat/xmlwf/win32filemap.c b/gdcm/Utilities/gdcmexpat/xmlwf/win32filemap.c new file mode 100644 index 0000000..41dc35b --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/xmlwf/win32filemap.c @@ -0,0 +1,96 @@ +/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +#define STRICT 1 +#define WIN32_LEAN_AND_MEAN 1 + +#ifdef XML_UNICODE_WCHAR_T +#ifndef XML_UNICODE +#define XML_UNICODE +#endif +#endif + +#ifdef XML_UNICODE +#define UNICODE +#define _UNICODE +#endif /* XML_UNICODE */ +#include +#include +#include +#include "filemap.h" + +static void win32perror(const TCHAR *); + +int +filemap(const TCHAR *name, + void (*processor)(const void *, size_t, const TCHAR *, void *arg), + void *arg) +{ + HANDLE f; + HANDLE m; + DWORD size; + DWORD sizeHi; + void *p; + + f = CreateFile(name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, + FILE_FLAG_SEQUENTIAL_SCAN, NULL); + if (f == INVALID_HANDLE_VALUE) { + win32perror(name); + return 0; + } + size = GetFileSize(f, &sizeHi); + if (size == (DWORD)-1) { + win32perror(name); + return 0; + } + if (sizeHi) { + _ftprintf(stderr, _T("%s: bigger than 2Gb\n"), name); + return 0; + } + /* CreateFileMapping barfs on zero length files */ + if (size == 0) { + static const char c = '\0'; + processor(&c, 0, name, arg); + CloseHandle(f); + return 1; + } + m = CreateFileMapping(f, NULL, PAGE_READONLY, 0, 0, NULL); + if (m == NULL) { + win32perror(name); + CloseHandle(f); + return 0; + } + p = MapViewOfFile(m, FILE_MAP_READ, 0, 0, 0); + if (p == NULL) { + win32perror(name); + CloseHandle(m); + CloseHandle(f); + return 0; + } + processor(p, size, name, arg); + UnmapViewOfFile(p); + CloseHandle(m); + CloseHandle(f); + return 1; +} + +static void +win32perror(const TCHAR *s) +{ + LPVOID buf; + if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER + | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &buf, + 0, + NULL)) { + _ftprintf(stderr, _T("%s: %s"), s, buf); + fflush(stderr); + LocalFree(buf); + } + else + _ftprintf(stderr, _T("%s: unknown Windows error\n"), s); +} diff --git a/gdcm/Utilities/gdcmexpat/xmlwf/xmlfile.c b/gdcm/Utilities/gdcmexpat/xmlwf/xmlfile.c new file mode 100644 index 0000000..88bb396 --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/xmlwf/xmlfile.c @@ -0,0 +1,241 @@ +/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +#include +#include +#include +#include +#include + +#ifdef COMPILED_FROM_DSP +#include "winconfig.h" +#elif defined(MACOS_CLASSIC) +#include "macconfig.h" +#elif defined(__amigaos4__) +#include "amigaconfig.h" +#elif defined(HAVE_EXPAT_CONFIG_H) +#include +#endif /* ndef COMPILED_FROM_DSP */ + +#include "expat.h" +#include "xmlfile.h" +#include "xmltchar.h" +#include "filemap.h" + +#ifdef _MSC_VER +#include +#endif + +#ifdef AMIGA_SHARED_LIB +#include +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifndef O_BINARY +#ifdef _O_BINARY +#define O_BINARY _O_BINARY +#else +#define O_BINARY 0 +#endif +#endif + +#ifdef _DEBUG +#define READ_SIZE 16 +#else +#define READ_SIZE (1024*8) +#endif + + +typedef struct { + XML_Parser parser; + int *retPtr; +} PROCESS_ARGS; + +static void +reportError(XML_Parser parser, const XML_Char *filename) +{ + enum XML_Error code = XML_GetErrorCode(parser); + const XML_Char *message = XML_ErrorString(code); + if (message) + ftprintf(stdout, T("%s:%" XML_FMT_INT_MOD "u:%" XML_FMT_INT_MOD "u: %s\n"), + filename, + XML_GetErrorLineNumber(parser), + XML_GetErrorColumnNumber(parser), + message); + else + ftprintf(stderr, T("%s: (unknown message %d)\n"), filename, code); +} + +static void +processFile(const void *data, size_t size, + const XML_Char *filename, void *args) +{ + XML_Parser parser = ((PROCESS_ARGS *)args)->parser; + int *retPtr = ((PROCESS_ARGS *)args)->retPtr; + if (XML_Parse(parser, (const char *)data, size, 1) == XML_STATUS_ERROR) { + reportError(parser, filename); + *retPtr = 0; + } + else + *retPtr = 1; +} + +#ifdef WIN32 + +static int +isAsciiLetter(XML_Char c) +{ + return (T('a') <= c && c <= T('z')) || (T('A') <= c && c <= T('Z')); +} + +#endif /* WIN32 */ + +static const XML_Char * +resolveSystemId(const XML_Char *base, const XML_Char *systemId, + XML_Char **toFree) +{ + XML_Char *s; + *toFree = 0; + if (!base + || *systemId == T('/') +#ifdef WIN32 + || *systemId == T('\\') + || (isAsciiLetter(systemId[0]) && systemId[1] == T(':')) +#endif + ) + return systemId; + *toFree = (XML_Char *)malloc((tcslen(base) + tcslen(systemId) + 2) + * sizeof(XML_Char)); + if (!*toFree) + return systemId; + tcscpy(*toFree, base); + s = *toFree; + if (tcsrchr(s, T('/'))) + s = tcsrchr(s, T('/')) + 1; +#ifdef WIN32 + if (tcsrchr(s, T('\\'))) + s = tcsrchr(s, T('\\')) + 1; +#endif + tcscpy(s, systemId); + return *toFree; +} + +static int +externalEntityRefFilemap(XML_Parser parser, + const XML_Char *context, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId) +{ + int result; + XML_Char *s; + const XML_Char *filename; + XML_Parser entParser = XML_ExternalEntityParserCreate(parser, context, 0); + PROCESS_ARGS args; + args.retPtr = &result; + args.parser = entParser; + filename = resolveSystemId(base, systemId, &s); + XML_SetBase(entParser, filename); + if (!filemap(filename, processFile, &args)) + result = 0; + free(s); + XML_ParserFree(entParser); + return result; +} + +static int +processStream(const XML_Char *filename, XML_Parser parser) +{ + /* passing NULL for filename means read intput from stdin */ + int fd = 0; /* 0 is the fileno for stdin */ + + if (filename != NULL) { + fd = topen(filename, O_BINARY|O_RDONLY); + if (fd < 0) { + tperror(filename); + return 0; + } + } + for (;;) { + int nread; + char *buf = (char *)XML_GetBuffer(parser, READ_SIZE); + if (!buf) { + if (filename != NULL) + close(fd); + ftprintf(stderr, T("%s: out of memory\n"), + filename != NULL ? filename : "xmlwf"); + return 0; + } + nread = read(fd, buf, READ_SIZE); + if (nread < 0) { + tperror(filename != NULL ? filename : "STDIN"); + if (filename != NULL) + close(fd); + return 0; + } + if (XML_ParseBuffer(parser, nread, nread == 0) == XML_STATUS_ERROR) { + reportError(parser, filename != NULL ? filename : "STDIN"); + if (filename != NULL) + close(fd); + return 0; + } + if (nread == 0) { + if (filename != NULL) + close(fd); + break;; + } + } + return 1; +} + +static int +externalEntityRefStream(XML_Parser parser, + const XML_Char *context, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId) +{ + XML_Char *s; + const XML_Char *filename; + int ret; + XML_Parser entParser = XML_ExternalEntityParserCreate(parser, context, 0); + filename = resolveSystemId(base, systemId, &s); + XML_SetBase(entParser, filename); + ret = processStream(filename, entParser); + free(s); + XML_ParserFree(entParser); + return ret; +} + +int +XML_ProcessFile(XML_Parser parser, + const XML_Char *filename, + unsigned flags) +{ + int result; + + if (!XML_SetBase(parser, filename)) { + ftprintf(stderr, T("%s: out of memory"), filename); + exit(1); + } + + if (flags & XML_EXTERNAL_ENTITIES) + XML_SetExternalEntityRefHandler(parser, + (flags & XML_MAP_FILE) + ? externalEntityRefFilemap + : externalEntityRefStream); + if (flags & XML_MAP_FILE) { + PROCESS_ARGS args; + args.retPtr = &result; + args.parser = parser; + if (!filemap(filename, processFile, &args)) + result = 0; + } + else + result = processStream(filename, parser); + return result; +} diff --git a/gdcm/Utilities/gdcmexpat/xmlwf/xmlfile.h b/gdcm/Utilities/gdcmexpat/xmlwf/xmlfile.h new file mode 100644 index 0000000..d093ecc --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/xmlwf/xmlfile.h @@ -0,0 +1,20 @@ +/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +#define XML_MAP_FILE 01 +#define XML_EXTERNAL_ENTITIES 02 + +#ifdef XML_LARGE_SIZE +#if defined(XML_USE_MSC_EXTENSIONS) && _MSC_VER < 1400 +#define XML_FMT_INT_MOD "I64" +#else +#define XML_FMT_INT_MOD "ll" +#endif +#else +#define XML_FMT_INT_MOD "l" +#endif + +extern int XML_ProcessFile(XML_Parser parser, + const XML_Char *filename, + unsigned flags); diff --git a/gdcm/Utilities/gdcmexpat/xmlwf/xmlmime.c b/gdcm/Utilities/gdcmexpat/xmlwf/xmlmime.c new file mode 100644 index 0000000..56a0e7f --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/xmlwf/xmlmime.c @@ -0,0 +1,163 @@ +#include +#include "xmlmime.h" + +static const char * +getTok(const char **pp) +{ + /* inComment means one level of nesting; inComment+1 means two levels etc */ + enum { inAtom, inString, init, inComment }; + int state = init; + const char *tokStart = 0; + for (;;) { + switch (**pp) { + case '\0': + if (state == inAtom) + return tokStart; + return 0; + case ' ': + case '\r': + case '\t': + case '\n': + if (state == inAtom) + return tokStart; + break; + case '(': + if (state == inAtom) + return tokStart; + if (state != inString) + state++; + break; + case ')': + if (state > init) + --state; + else if (state != inString) + return 0; + break; + case ';': + case '/': + case '=': + if (state == inAtom) + return tokStart; + if (state == init) + return (*pp)++; + break; + case '\\': + ++*pp; + if (**pp == '\0') + return 0; + break; + case '"': + switch (state) { + case inString: + ++*pp; + return tokStart; + case inAtom: + return tokStart; + case init: + tokStart = *pp; + state = inString; + break; + } + break; + default: + if (state == init) { + tokStart = *pp; + state = inAtom; + } + break; + } + ++*pp; + } + /* not reached */ +} + +/* key must be lowercase ASCII */ + +static int +matchkey(const char *start, const char *end, const char *key) +{ + if (!start) + return 0; + for (; start != end; start++, key++) + if (*start != *key && *start != 'A' + (*key - 'a')) + return 0; + return *key == '\0'; +} + +void +getXMLCharset(const char *buf, char *charset) +{ + const char *next, *p; + + charset[0] = '\0'; + next = buf; + p = getTok(&next); + if (matchkey(p, next, "text")) + strcpy(charset, "us-ascii"); + else if (!matchkey(p, next, "application")) + return; + p = getTok(&next); + if (!p || *p != '/') + return; + p = getTok(&next); +#if 0 + if (!matchkey(p, next, "xml") && charset[0] == '\0') + return; +#endif + p = getTok(&next); + while (p) { + if (*p == ';') { + p = getTok(&next); + if (matchkey(p, next, "charset")) { + p = getTok(&next); + if (p && *p == '=') { + p = getTok(&next); + if (p) { + char *s = charset; + if (*p == '"') { + while (++p != next - 1) { + if (*p == '\\') + ++p; + if (s == charset + CHARSET_MAX - 1) { + charset[0] = '\0'; + break; + } + *s++ = *p; + } + *s++ = '\0'; + } + else { + if (next - p > CHARSET_MAX - 1) + break; + while (p != next) + *s++ = *p++; + *s = 0; + break; + } + } + } + break; + } + } + else + p = getTok(&next); + } +} + +#ifdef TEST + +#include + +int +main(int argc, char *argv[]) +{ + char buf[CHARSET_MAX]; + if (argc <= 1) + return 1; + printf("%s\n", argv[1]); + getXMLCharset(argv[1], buf); + printf("charset=\"%s\"\n", buf); + return 0; +} + +#endif /* TEST */ diff --git a/gdcm/Utilities/gdcmexpat/xmlwf/xmlmime.h b/gdcm/Utilities/gdcmexpat/xmlwf/xmlmime.h new file mode 100644 index 0000000..bf0356d --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/xmlwf/xmlmime.h @@ -0,0 +1,19 @@ +#ifdef __cplusplus +extern "C" { +#endif + +/* Registered charset names are at most 40 characters long. */ + +#define CHARSET_MAX 41 + +/* Figure out the charset to use from the ContentType. + buf contains the body of the header field (the part after "Content-Type:"). + charset gets the charset to use. It must be at least CHARSET_MAX chars + long. charset will be empty if the default charset should be used. +*/ + +void getXMLCharset(const char *buf, char *charset); + +#ifdef __cplusplus +} +#endif diff --git a/gdcm/Utilities/gdcmexpat/xmlwf/xmltchar.h b/gdcm/Utilities/gdcmexpat/xmlwf/xmltchar.h new file mode 100644 index 0000000..1088575 --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/xmlwf/xmltchar.h @@ -0,0 +1,36 @@ +#ifdef XML_UNICODE +#ifndef XML_UNICODE_WCHAR_T +#error xmlwf requires a 16-bit Unicode-compatible wchar_t +#endif +#define T(x) L ## x +#define ftprintf fwprintf +#define tfopen _wfopen +#define fputts fputws +#define puttc putwc +#define tcscmp wcscmp +#define tcscpy wcscpy +#define tcscat wcscat +#define tcschr wcschr +#define tcsrchr wcsrchr +#define tcslen wcslen +#define tperror _wperror +#define topen _wopen +#define tmain wmain +#define tremove _wremove +#else /* not XML_UNICODE */ +#define T(x) x +#define ftprintf fprintf +#define tfopen fopen +#define fputts fputs +#define puttc putc +#define tcscmp strcmp +#define tcscpy strcpy +#define tcscat strcat +#define tcschr strchr +#define tcsrchr strrchr +#define tcslen strlen +#define tperror perror +#define topen open +#define tmain main +#define tremove remove +#endif /* not XML_UNICODE */ diff --git a/gdcm/Utilities/gdcmexpat/xmlwf/xmlurl.h b/gdcm/Utilities/gdcmexpat/xmlwf/xmlurl.h new file mode 100644 index 0000000..d329913 --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/xmlwf/xmlurl.h @@ -0,0 +1,13 @@ +#ifdef __cplusplus +extern "C" { +#endif + +int XML_URLInit(); +void XML_URLUninit(); +int XML_ProcessURL(XML_Parser parser, + const XML_Char *url, + unsigned flags); + +#ifdef __cplusplus +} +#endif diff --git a/gdcm/Utilities/gdcmexpat/xmlwf/xmlwf.c b/gdcm/Utilities/gdcmexpat/xmlwf/xmlwf.c new file mode 100644 index 0000000..2de9b92 --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/xmlwf/xmlwf.c @@ -0,0 +1,853 @@ +/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +#include +#include +#include +#include + +#include "expat.h" +#include "codepage.h" +#include "xmlfile.h" +#include "xmltchar.h" + +#ifdef _MSC_VER +#include +#endif + +#ifdef AMIGA_SHARED_LIB +#include +#endif + +/* This ensures proper sorting. */ + +#define NSSEP T('\001') + +static void XMLCALL +characterData(void *userData, const XML_Char *s, int len) +{ + FILE *fp = (FILE *)userData; + for (; len > 0; --len, ++s) { + switch (*s) { + case T('&'): + fputts(T("&"), fp); + break; + case T('<'): + fputts(T("<"), fp); + break; + case T('>'): + fputts(T(">"), fp); + break; +#ifdef W3C14N + case 13: + fputts(T(" "), fp); + break; +#else + case T('"'): + fputts(T("""), fp); + break; + case 9: + case 10: + case 13: + ftprintf(fp, T("&#%d;"), *s); + break; +#endif + default: + puttc(*s, fp); + break; + } + } +} + +static void +attributeValue(FILE *fp, const XML_Char *s) +{ + puttc(T('='), fp); + puttc(T('"'), fp); + for (;;) { + switch (*s) { + case 0: + case NSSEP: + puttc(T('"'), fp); + return; + case T('&'): + fputts(T("&"), fp); + break; + case T('<'): + fputts(T("<"), fp); + break; + case T('"'): + fputts(T("""), fp); + break; +#ifdef W3C14N + case 9: + fputts(T(" "), fp); + break; + case 10: + fputts(T(" "), fp); + break; + case 13: + fputts(T(" "), fp); + break; +#else + case T('>'): + fputts(T(">"), fp); + break; + case 9: + case 10: + case 13: + ftprintf(fp, T("&#%d;"), *s); + break; +#endif + default: + puttc(*s, fp); + break; + } + s++; + } +} + +/* Lexicographically comparing UTF-8 encoded attribute values, +is equivalent to lexicographically comparing based on the character number. */ + +static int +attcmp(const void *att1, const void *att2) +{ + return tcscmp(*(const XML_Char **)att1, *(const XML_Char **)att2); +} + +static void XMLCALL +startElement(void *userData, const XML_Char *name, const XML_Char **atts) +{ + int nAtts; + const XML_Char **p; + FILE *fp = (FILE *)userData; + puttc(T('<'), fp); + fputts(name, fp); + + p = atts; + while (*p) + ++p; + nAtts = (p - atts) >> 1; + if (nAtts > 1) + qsort((void *)atts, nAtts, sizeof(XML_Char *) * 2, attcmp); + while (*atts) { + puttc(T(' '), fp); + fputts(*atts++, fp); + attributeValue(fp, *atts); + atts++; + } + puttc(T('>'), fp); +} + +static void XMLCALL +endElement(void *userData, const XML_Char *name) +{ + FILE *fp = (FILE *)userData; + puttc(T('<'), fp); + puttc(T('/'), fp); + fputts(name, fp); + puttc(T('>'), fp); +} + +static int +nsattcmp(const void *p1, const void *p2) +{ + const XML_Char *att1 = *(const XML_Char **)p1; + const XML_Char *att2 = *(const XML_Char **)p2; + int sep1 = (tcsrchr(att1, NSSEP) != 0); + int sep2 = (tcsrchr(att1, NSSEP) != 0); + if (sep1 != sep2) + return sep1 - sep2; + return tcscmp(att1, att2); +} + +static void XMLCALL +startElementNS(void *userData, const XML_Char *name, const XML_Char **atts) +{ + int nAtts; + int nsi; + const XML_Char **p; + FILE *fp = (FILE *)userData; + const XML_Char *sep; + puttc(T('<'), fp); + + sep = tcsrchr(name, NSSEP); + if (sep) { + fputts(T("n1:"), fp); + fputts(sep + 1, fp); + fputts(T(" xmlns:n1"), fp); + attributeValue(fp, name); + nsi = 2; + } + else { + fputts(name, fp); + nsi = 1; + } + + p = atts; + while (*p) + ++p; + nAtts = (p - atts) >> 1; + if (nAtts > 1) + qsort((void *)atts, nAtts, sizeof(XML_Char *) * 2, nsattcmp); + while (*atts) { + name = *atts++; + sep = tcsrchr(name, NSSEP); + puttc(T(' '), fp); + if (sep) { + ftprintf(fp, T("n%d:"), nsi); + fputts(sep + 1, fp); + } + else + fputts(name, fp); + attributeValue(fp, *atts); + if (sep) { + ftprintf(fp, T(" xmlns:n%d"), nsi++); + attributeValue(fp, name); + } + atts++; + } + puttc(T('>'), fp); +} + +static void XMLCALL +endElementNS(void *userData, const XML_Char *name) +{ + FILE *fp = (FILE *)userData; + const XML_Char *sep; + puttc(T('<'), fp); + puttc(T('/'), fp); + sep = tcsrchr(name, NSSEP); + if (sep) { + fputts(T("n1:"), fp); + fputts(sep + 1, fp); + } + else + fputts(name, fp); + puttc(T('>'), fp); +} + +#ifndef W3C14N + +static void XMLCALL +processingInstruction(void *userData, const XML_Char *target, + const XML_Char *data) +{ + FILE *fp = (FILE *)userData; + puttc(T('<'), fp); + puttc(T('?'), fp); + fputts(target, fp); + puttc(T(' '), fp); + fputts(data, fp); + puttc(T('?'), fp); + puttc(T('>'), fp); +} + +#endif /* not W3C14N */ + +static void XMLCALL +defaultCharacterData(void *userData, const XML_Char *s, int len) +{ + XML_DefaultCurrent((XML_Parser) userData); +} + +static void XMLCALL +defaultStartElement(void *userData, const XML_Char *name, + const XML_Char **atts) +{ + XML_DefaultCurrent((XML_Parser) userData); +} + +static void XMLCALL +defaultEndElement(void *userData, const XML_Char *name) +{ + XML_DefaultCurrent((XML_Parser) userData); +} + +static void XMLCALL +defaultProcessingInstruction(void *userData, const XML_Char *target, + const XML_Char *data) +{ + XML_DefaultCurrent((XML_Parser) userData); +} + +static void XMLCALL +nopCharacterData(void *userData, const XML_Char *s, int len) +{ +} + +static void XMLCALL +nopStartElement(void *userData, const XML_Char *name, const XML_Char **atts) +{ +} + +static void XMLCALL +nopEndElement(void *userData, const XML_Char *name) +{ +} + +static void XMLCALL +nopProcessingInstruction(void *userData, const XML_Char *target, + const XML_Char *data) +{ +} + +static void XMLCALL +markup(void *userData, const XML_Char *s, int len) +{ + FILE *fp = (FILE *)XML_GetUserData((XML_Parser) userData); + for (; len > 0; --len, ++s) + puttc(*s, fp); +} + +static void +metaLocation(XML_Parser parser) +{ + const XML_Char *uri = XML_GetBase(parser); + if (uri) + ftprintf((FILE *)XML_GetUserData(parser), T(" uri=\"%s\""), uri); + ftprintf((FILE *)XML_GetUserData(parser), + T(" byte=\"%" XML_FMT_INT_MOD "d\" nbytes=\"%d\" \ + line=\"%" XML_FMT_INT_MOD "u\" col=\"%" XML_FMT_INT_MOD "u\""), + XML_GetCurrentByteIndex(parser), + XML_GetCurrentByteCount(parser), + XML_GetCurrentLineNumber(parser), + XML_GetCurrentColumnNumber(parser)); +} + +static void +metaStartDocument(void *userData) +{ + fputts(T("\n"), (FILE *)XML_GetUserData((XML_Parser) userData)); +} + +static void +metaEndDocument(void *userData) +{ + fputts(T("\n"), (FILE *)XML_GetUserData((XML_Parser) userData)); +} + +static void XMLCALL +metaStartElement(void *userData, const XML_Char *name, + const XML_Char **atts) +{ + XML_Parser parser = (XML_Parser) userData; + FILE *fp = (FILE *)XML_GetUserData(parser); + const XML_Char **specifiedAttsEnd + = atts + XML_GetSpecifiedAttributeCount(parser); + const XML_Char **idAttPtr; + int idAttIndex = XML_GetIdAttributeIndex(parser); + if (idAttIndex < 0) + idAttPtr = 0; + else + idAttPtr = atts + idAttIndex; + + ftprintf(fp, T("\n"), fp); + do { + ftprintf(fp, T("= specifiedAttsEnd) + fputts(T("\" defaulted=\"yes\"/>\n"), fp); + else if (atts == idAttPtr) + fputts(T("\" id=\"yes\"/>\n"), fp); + else + fputts(T("\"/>\n"), fp); + } while (*(atts += 2)); + fputts(T("\n"), fp); + } + else + fputts(T("/>\n"), fp); +} + +static void XMLCALL +metaEndElement(void *userData, const XML_Char *name) +{ + XML_Parser parser = (XML_Parser) userData; + FILE *fp = (FILE *)XML_GetUserData(parser); + ftprintf(fp, T("\n"), fp); +} + +static void XMLCALL +metaProcessingInstruction(void *userData, const XML_Char *target, + const XML_Char *data) +{ + XML_Parser parser = (XML_Parser) userData; + FILE *fp = (FILE *)XML_GetUserData(parser); + ftprintf(fp, T("\n"), fp); +} + +static void XMLCALL +metaComment(void *userData, const XML_Char *data) +{ + XML_Parser parser = (XML_Parser) userData; + FILE *fp = (FILE *)XML_GetUserData(parser); + fputts(T("\n"), fp); +} + +static void XMLCALL +metaStartCdataSection(void *userData) +{ + XML_Parser parser = (XML_Parser) userData; + FILE *fp = (FILE *)XML_GetUserData(parser); + fputts(T("\n"), fp); +} + +static void XMLCALL +metaEndCdataSection(void *userData) +{ + XML_Parser parser = (XML_Parser) userData; + FILE *fp = (FILE *)XML_GetUserData(parser); + fputts(T("\n"), fp); +} + +static void XMLCALL +metaCharacterData(void *userData, const XML_Char *s, int len) +{ + XML_Parser parser = (XML_Parser) userData; + FILE *fp = (FILE *)XML_GetUserData(parser); + fputts(T("\n"), fp); +} + +static void XMLCALL +metaStartDoctypeDecl(void *userData, + const XML_Char *doctypeName, + const XML_Char *sysid, + const XML_Char *pubid, + int has_internal_subset) +{ + XML_Parser parser = (XML_Parser) userData; + FILE *fp = (FILE *)XML_GetUserData(parser); + ftprintf(fp, T("\n"), fp); +} + +static void XMLCALL +metaEndDoctypeDecl(void *userData) +{ + XML_Parser parser = (XML_Parser) userData; + FILE *fp = (FILE *)XML_GetUserData(parser); + fputts(T("\n"), fp); +} + +static void XMLCALL +metaNotationDecl(void *userData, + const XML_Char *notationName, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId) +{ + XML_Parser parser = (XML_Parser) userData; + FILE *fp = (FILE *)XML_GetUserData(parser); + ftprintf(fp, T("\n"), fp); +} + + +static void XMLCALL +metaEntityDecl(void *userData, + const XML_Char *entityName, + int is_param, + const XML_Char *value, + int value_length, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId, + const XML_Char *notationName) +{ + XML_Parser parser = (XML_Parser) userData; + FILE *fp = (FILE *)XML_GetUserData(parser); + + if (value) { + ftprintf(fp, T("'), fp); + characterData(fp, value, value_length); + fputts(T("\n"), fp); + } + else if (notationName) { + ftprintf(fp, T("\n"), fp); + } + else { + ftprintf(fp, T("\n"), fp); + } +} + +static void XMLCALL +metaStartNamespaceDecl(void *userData, + const XML_Char *prefix, + const XML_Char *uri) +{ + XML_Parser parser = (XML_Parser) userData; + FILE *fp = (FILE *)XML_GetUserData(parser); + fputts(T("\n"), fp); + } + else + fputts(T("/>\n"), fp); +} + +static void XMLCALL +metaEndNamespaceDecl(void *userData, const XML_Char *prefix) +{ + XML_Parser parser = (XML_Parser) userData; + FILE *fp = (FILE *)XML_GetUserData(parser); + if (!prefix) + fputts(T("\n"), fp); + else + ftprintf(fp, T("\n"), prefix); +} + +static int XMLCALL +unknownEncodingConvert(void *data, const char *p) +{ + return codepageConvert(*(int *)data, p); +} + +static int XMLCALL +unknownEncoding(void *userData, const XML_Char *name, XML_Encoding *info) +{ + int cp; + static const XML_Char prefixL[] = T("windows-"); + static const XML_Char prefixU[] = T("WINDOWS-"); + int i; + + for (i = 0; prefixU[i]; i++) + if (name[i] != prefixU[i] && name[i] != prefixL[i]) + return 0; + + cp = 0; + for (; name[i]; i++) { + static const XML_Char digits[] = T("0123456789"); + const XML_Char *s = tcschr(digits, name[i]); + if (!s) + return 0; + cp *= 10; + cp += s - digits; + if (cp >= 0x10000) + return 0; + } + if (!codepageMap(cp, info->map)) + return 0; + info->convert = unknownEncodingConvert; + /* We could just cast the code page integer to a void *, + and avoid the use of release. */ + info->release = free; + info->data = malloc(sizeof(int)); + if (!info->data) + return 0; + *(int *)info->data = cp; + return 1; +} + +static int XMLCALL +notStandalone(void *userData) +{ + return 0; +} + +static void +showVersion(XML_Char *prog) +{ + XML_Char *s = prog; + XML_Char ch; + const XML_Feature *features = XML_GetFeatureList(); + while ((ch = *s) != 0) { + if (ch == '/' +#ifdef WIN32 + || ch == '\\' +#endif + ) + prog = s + 1; + ++s; + } + ftprintf(stdout, T("%s using %s\n"), prog, XML_ExpatVersion()); + if (features != NULL && features[0].feature != XML_FEATURE_END) { + int i = 1; + ftprintf(stdout, T("%s"), features[0].name); + if (features[0].value) + ftprintf(stdout, T("=%ld"), features[0].value); + while (features[i].feature != XML_FEATURE_END) { + ftprintf(stdout, T(", %s"), features[i].name); + if (features[i].value) + ftprintf(stdout, T("=%ld"), features[i].value); + ++i; + } + ftprintf(stdout, T("\n")); + } +} + +static void +usage(const XML_Char *prog, int rc) +{ + ftprintf(stderr, + T("usage: %s [-n] [-p] [-r] [-s] [-w] [-x] [-d output-dir] " + "[-e encoding] file ...\n"), prog); + exit(rc); +} + +#ifdef AMIGA_SHARED_LIB +int +amiga_main(int argc, char *argv[]) +#else +int +tmain(int argc, XML_Char **argv) +#endif +{ + int i, j; + const XML_Char *outputDir = NULL; + const XML_Char *encoding = NULL; + unsigned processFlags = XML_MAP_FILE; + int windowsCodePages = 0; + int outputType = 0; + int useNamespaces = 0; + int requireStandalone = 0; + enum XML_ParamEntityParsing paramEntityParsing = + XML_PARAM_ENTITY_PARSING_NEVER; + int useStdin = 0; + +#ifdef _MSC_VER + _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF|_CRTDBG_LEAK_CHECK_DF); +#endif + + i = 1; + j = 0; + while (i < argc) { + if (j == 0) { + if (argv[i][0] != T('-')) + break; + if (argv[i][1] == T('-') && argv[i][2] == T('\0')) { + i++; + break; + } + j++; + } + switch (argv[i][j]) { + case T('r'): + processFlags &= ~XML_MAP_FILE; + j++; + break; + case T('s'): + requireStandalone = 1; + j++; + break; + case T('n'): + useNamespaces = 1; + j++; + break; + case T('p'): + paramEntityParsing = XML_PARAM_ENTITY_PARSING_ALWAYS; + /* fall through */ + case T('x'): + processFlags |= XML_EXTERNAL_ENTITIES; + j++; + break; + case T('w'): + windowsCodePages = 1; + j++; + break; + case T('m'): + outputType = 'm'; + j++; + break; + case T('c'): + outputType = 'c'; + useNamespaces = 0; + j++; + break; + case T('t'): + outputType = 't'; + j++; + break; + case T('d'): + if (argv[i][j + 1] == T('\0')) { + if (++i == argc) + usage(argv[0], 2); + outputDir = argv[i]; + } + else + outputDir = argv[i] + j + 1; + i++; + j = 0; + break; + case T('e'): + if (argv[i][j + 1] == T('\0')) { + if (++i == argc) + usage(argv[0], 2); + encoding = argv[i]; + } + else + encoding = argv[i] + j + 1; + i++; + j = 0; + break; + case T('h'): + usage(argv[0], 0); + return 0; + case T('v'): + showVersion(argv[0]); + return 0; + case T('\0'): + if (j > 1) { + i++; + j = 0; + break; + } + /* fall through */ + default: + usage(argv[0], 2); + } + } + if (i == argc) { + useStdin = 1; + processFlags &= ~XML_MAP_FILE; + i--; + } + for (; i < argc; i++) { + FILE *fp = 0; + XML_Char *outName = 0; + int result; + XML_Parser parser; + if (useNamespaces) + parser = XML_ParserCreateNS(encoding, NSSEP); + else + parser = XML_ParserCreate(encoding); + if (requireStandalone) + XML_SetNotStandaloneHandler(parser, notStandalone); + XML_SetParamEntityParsing(parser, paramEntityParsing); + if (outputType == 't') { + /* This is for doing timings; this gives a more realistic estimate of + the parsing time. */ + outputDir = 0; + XML_SetElementHandler(parser, nopStartElement, nopEndElement); + XML_SetCharacterDataHandler(parser, nopCharacterData); + XML_SetProcessingInstructionHandler(parser, nopProcessingInstruction); + } + else if (outputDir) { + const XML_Char *file = useStdin ? T("STDIN") : argv[i]; + if (tcsrchr(file, T('/'))) + file = tcsrchr(file, T('/')) + 1; +#ifdef WIN32 + if (tcsrchr(file, T('\\'))) + file = tcsrchr(file, T('\\')) + 1; +#endif + outName = (XML_Char *)malloc((tcslen(outputDir) + tcslen(file) + 2) + * sizeof(XML_Char)); + tcscpy(outName, outputDir); + tcscat(outName, T("/")); + tcscat(outName, file); + fp = tfopen(outName, T("wb")); + if (!fp) { + tperror(outName); + exit(1); + } + setvbuf(fp, NULL, _IOFBF, 16384); +#ifdef XML_UNICODE + puttc(0xFEFF, fp); +#endif + XML_SetUserData(parser, fp); + switch (outputType) { + case 'm': + XML_UseParserAsHandlerArg(parser); + XML_SetElementHandler(parser, metaStartElement, metaEndElement); + XML_SetProcessingInstructionHandler(parser, metaProcessingInstruction); + XML_SetCommentHandler(parser, metaComment); + XML_SetCdataSectionHandler(parser, metaStartCdataSection, + metaEndCdataSection); + XML_SetCharacterDataHandler(parser, metaCharacterData); + XML_SetDoctypeDeclHandler(parser, metaStartDoctypeDecl, + metaEndDoctypeDecl); + XML_SetEntityDeclHandler(parser, metaEntityDecl); + XML_SetNotationDeclHandler(parser, metaNotationDecl); + XML_SetNamespaceDeclHandler(parser, metaStartNamespaceDecl, + metaEndNamespaceDecl); + metaStartDocument(parser); + break; + case 'c': + XML_UseParserAsHandlerArg(parser); + XML_SetDefaultHandler(parser, markup); + XML_SetElementHandler(parser, defaultStartElement, defaultEndElement); + XML_SetCharacterDataHandler(parser, defaultCharacterData); + XML_SetProcessingInstructionHandler(parser, + defaultProcessingInstruction); + break; + default: + if (useNamespaces) + XML_SetElementHandler(parser, startElementNS, endElementNS); + else + XML_SetElementHandler(parser, startElement, endElement); + XML_SetCharacterDataHandler(parser, characterData); +#ifndef W3C14N + XML_SetProcessingInstructionHandler(parser, processingInstruction); +#endif /* not W3C14N */ + break; + } + } + if (windowsCodePages) + XML_SetUnknownEncodingHandler(parser, unknownEncoding, 0); + result = XML_ProcessFile(parser, useStdin ? NULL : argv[i], processFlags); + if (outputDir) { + if (outputType == 'm') + metaEndDocument(parser); + fclose(fp); + if (!result) + tremove(outName); + free(outName); + } + XML_ParserFree(parser); + } + return 0; +} diff --git a/gdcm/Utilities/gdcmexpat/xmlwf/xmlwin32url.cxx b/gdcm/Utilities/gdcmexpat/xmlwf/xmlwin32url.cxx new file mode 100644 index 0000000..bbfcce2 --- /dev/null +++ b/gdcm/Utilities/gdcmexpat/xmlwf/xmlwin32url.cxx @@ -0,0 +1,395 @@ +#include "expat.h" +#ifdef XML_UNICODE +#define UNICODE +#endif +#include +#include +#include +#include +#include +#include "xmlurl.h" +#include "xmlmime.h" + +static int +processURL(XML_Parser parser, IMoniker *baseMoniker, const XML_Char *url); + +typedef void (*StopHandler)(void *, HRESULT); + +class Callback : public IBindStatusCallback { +public: + // IUnknown methods + STDMETHODIMP QueryInterface(REFIID,void **); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + // IBindStatusCallback methods + STDMETHODIMP OnStartBinding(DWORD, IBinding *); + STDMETHODIMP GetPriority(LONG *); + STDMETHODIMP OnLowResource(DWORD); + STDMETHODIMP OnProgress(ULONG, ULONG, ULONG, LPCWSTR); + STDMETHODIMP OnStopBinding(HRESULT, LPCWSTR); + STDMETHODIMP GetBindInfo(DWORD *, BINDINFO *); + STDMETHODIMP OnDataAvailable(DWORD, DWORD, FORMATETC *, STGMEDIUM *); + STDMETHODIMP OnObjectAvailable(REFIID, IUnknown *); + Callback(XML_Parser, IMoniker *, StopHandler, void *); + ~Callback(); + int externalEntityRef(const XML_Char *context, + const XML_Char *systemId, const XML_Char *publicId); +private: + XML_Parser parser_; + IMoniker *baseMoniker_; + DWORD totalRead_; + ULONG ref_; + IBinding *pBinding_; + StopHandler stopHandler_; + void *stopArg_; +}; + +STDMETHODIMP_(ULONG) +Callback::AddRef() +{ + return ref_++; +} + +STDMETHODIMP_(ULONG) +Callback::Release() +{ + if (--ref_ == 0) { + delete this; + return 0; + } + return ref_; +} + +STDMETHODIMP +Callback::QueryInterface(REFIID riid, void** ppv) +{ + if (IsEqualGUID(riid, IID_IUnknown)) + *ppv = (IUnknown *)this; + else if (IsEqualGUID(riid, IID_IBindStatusCallback)) + *ppv = (IBindStatusCallback *)this; + else + return E_NOINTERFACE; + ((LPUNKNOWN)*ppv)->AddRef(); + return S_OK; +} + +STDMETHODIMP +Callback::OnStartBinding(DWORD, IBinding* pBinding) +{ + pBinding_ = pBinding; + pBinding->AddRef(); + return S_OK; +} + +STDMETHODIMP +Callback::GetPriority(LONG *) +{ + return E_NOTIMPL; +} + +STDMETHODIMP +Callback::OnLowResource(DWORD) +{ + return E_NOTIMPL; +} + +STDMETHODIMP +Callback::OnProgress(ULONG, ULONG, ULONG, LPCWSTR) +{ + return S_OK; +} + +STDMETHODIMP +Callback::OnStopBinding(HRESULT hr, LPCWSTR szError) +{ + if (pBinding_) { + pBinding_->Release(); + pBinding_ = 0; + } + if (baseMoniker_) { + baseMoniker_->Release(); + baseMoniker_ = 0; + } + stopHandler_(stopArg_, hr); + return S_OK; +} + +STDMETHODIMP +Callback::GetBindInfo(DWORD* pgrfBINDF, BINDINFO* pbindinfo) +{ + *pgrfBINDF = BINDF_ASYNCHRONOUS; + return S_OK; +} + +static void +reportError(XML_Parser parser) +{ + int code = XML_GetErrorCode(parser); + const XML_Char *message = XML_ErrorString(code); + if (message) + _ftprintf(stderr, _T("%s:%d:%ld: %s\n"), + XML_GetBase(parser), + XML_GetErrorLineNumber(parser), + XML_GetErrorColumnNumber(parser), + message); + else + _ftprintf(stderr, _T("%s: (unknown message %d)\n"), + XML_GetBase(parser), code); +} + +STDMETHODIMP +Callback::OnDataAvailable(DWORD grfBSCF, + DWORD dwSize, + FORMATETC *pfmtetc, + STGMEDIUM* pstgmed) +{ + if (grfBSCF & BSCF_FIRSTDATANOTIFICATION) { + IWinInetHttpInfo *hp; + HRESULT hr = pBinding_->QueryInterface(IID_IWinInetHttpInfo, + (void **)&hp); + if (SUCCEEDED(hr)) { + char contentType[1024]; + DWORD bufSize = sizeof(contentType); + DWORD flags = 0; + contentType[0] = 0; + hr = hp->QueryInfo(HTTP_QUERY_CONTENT_TYPE, contentType, + &bufSize, 0, NULL); + if (SUCCEEDED(hr)) { + char charset[CHARSET_MAX]; + getXMLCharset(contentType, charset); + if (charset[0]) { +#ifdef XML_UNICODE + XML_Char wcharset[CHARSET_MAX]; + XML_Char *p1 = wcharset; + const char *p2 = charset; + while ((*p1++ = (unsigned char)*p2++) != 0) + ; + XML_SetEncoding(parser_, wcharset); +#else + XML_SetEncoding(parser_, charset); +#endif + } + } + hp->Release(); + } + } + if (!parser_) + return E_ABORT; + if (pstgmed->tymed == TYMED_ISTREAM) { + while (totalRead_ < dwSize) { +#define READ_MAX (64*1024) + DWORD nToRead = dwSize - totalRead_; + if (nToRead > READ_MAX) + nToRead = READ_MAX; + void *buf = XML_GetBuffer(parser_, nToRead); + if (!buf) { + _ftprintf(stderr, _T("out of memory\n")); + return E_ABORT; + } + DWORD nRead; + HRESULT hr = pstgmed->pstm->Read(buf, nToRead, &nRead); + if (SUCCEEDED(hr)) { + totalRead_ += nRead; + if (!XML_ParseBuffer(parser_, + nRead, + (grfBSCF & BSCF_LASTDATANOTIFICATION) != 0 + && totalRead_ == dwSize)) { + reportError(parser_); + return E_ABORT; + } + } + } + } + return S_OK; +} + +STDMETHODIMP +Callback::OnObjectAvailable(REFIID, IUnknown *) +{ + return S_OK; +} + +int +Callback::externalEntityRef(const XML_Char *context, + const XML_Char *systemId, + const XML_Char *publicId) +{ + XML_Parser entParser = XML_ExternalEntityParserCreate(parser_, context, 0); + XML_SetBase(entParser, systemId); + int ret = processURL(entParser, baseMoniker_, systemId); + XML_ParserFree(entParser); + return ret; +} + +Callback::Callback(XML_Parser parser, IMoniker *baseMoniker, + StopHandler stopHandler, void *stopArg) +: parser_(parser), + baseMoniker_(baseMoniker), + ref_(0), + pBinding_(0), + totalRead_(0), + stopHandler_(stopHandler), + stopArg_(stopArg) +{ + if (baseMoniker_) + baseMoniker_->AddRef(); +} + +Callback::~Callback() +{ + if (pBinding_) + pBinding_->Release(); + if (baseMoniker_) + baseMoniker_->Release(); +} + +static int +externalEntityRef(void *arg, + const XML_Char *context, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId) +{ + return ((Callback *)arg)->externalEntityRef(context, systemId, publicId); +} + + +static HRESULT +openStream(XML_Parser parser, + IMoniker *baseMoniker, + const XML_Char *uri, + StopHandler stopHandler, void *stopArg) +{ + if (!XML_SetBase(parser, uri)) + return E_OUTOFMEMORY; + HRESULT hr; + IMoniker *m; +#ifdef XML_UNICODE + hr = CreateURLMoniker(0, uri, &m); +#else + LPWSTR uriw = new wchar_t[strlen(uri) + 1]; + for (int i = 0;; i++) { + uriw[i] = uri[i]; + if (uriw[i] == 0) + break; + } + hr = CreateURLMoniker(baseMoniker, uriw, &m); + delete [] uriw; +#endif + if (FAILED(hr)) + return hr; + IBindStatusCallback *cb = new Callback(parser, m, stopHandler, stopArg); + XML_SetExternalEntityRefHandler(parser, externalEntityRef); + XML_SetExternalEntityRefHandlerArg(parser, cb); + cb->AddRef(); + IBindCtx *b; + if (FAILED(hr = CreateAsyncBindCtx(0, cb, 0, &b))) { + cb->Release(); + m->Release(); + return hr; + } + cb->Release(); + IStream *pStream; + hr = m->BindToStorage(b, 0, IID_IStream, (void **)&pStream); + if (SUCCEEDED(hr)) { + if (pStream) + pStream->Release(); + } + if (hr == MK_S_ASYNCHRONOUS) + hr = S_OK; + m->Release(); + b->Release(); + return hr; +} + +struct QuitInfo { + const XML_Char *url; + HRESULT hr; + int stop; +}; + +static void +winPerror(const XML_Char *url, HRESULT hr) +{ + LPVOID buf; + if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER + | FORMAT_MESSAGE_FROM_HMODULE, + GetModuleHandleA("urlmon.dll"), + hr, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &buf, + 0, + NULL) + || FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER + | FORMAT_MESSAGE_FROM_SYSTEM, + 0, + hr, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &buf, + 0, + NULL)) { + /* The system error messages seem to end with a newline. */ + _ftprintf(stderr, _T("%s: %s"), url, buf); + fflush(stderr); + LocalFree(buf); + } + else + _ftprintf(stderr, _T("%s: error %x\n"), url, hr); +} + +static void +threadQuit(void *p, HRESULT hr) +{ + QuitInfo *qi = (QuitInfo *)p; + qi->hr = hr; + qi->stop = 1; +} + +extern "C" +int +XML_URLInit(void) +{ + return SUCCEEDED(CoInitialize(0)); +} + +extern "C" +void +XML_URLUninit(void) +{ + CoUninitialize(); +} + +static int +processURL(XML_Parser parser, IMoniker *baseMoniker, + const XML_Char *url) +{ + QuitInfo qi; + qi.stop = 0; + qi.url = url; + + XML_SetBase(parser, url); + HRESULT hr = openStream(parser, baseMoniker, url, threadQuit, &qi); + if (FAILED(hr)) { + winPerror(url, hr); + return 0; + } + else if (FAILED(qi.hr)) { + winPerror(url, qi.hr); + return 0; + } + MSG msg; + while (!qi.stop && GetMessage (&msg, NULL, 0, 0)) { + TranslateMessage (&msg); + DispatchMessage (&msg); + } + return 1; +} + +extern "C" +int +XML_ProcessURL(XML_Parser parser, + const XML_Char *url, + unsigned flags) +{ + return processURL(parser, 0, url); +} diff --git a/gdcm/Utilities/gdcmjpeg/.NoDartCoverage b/gdcm/Utilities/gdcmjpeg/.NoDartCoverage new file mode 100644 index 0000000..3c99729 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/.NoDartCoverage @@ -0,0 +1 @@ +# do not do coverage in this directory diff --git a/gdcm/Utilities/gdcmjpeg/12/CMakeLists.txt b/gdcm/Utilities/gdcmjpeg/12/CMakeLists.txt new file mode 100644 index 0000000..58c8b74 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/12/CMakeLists.txt @@ -0,0 +1,28 @@ +# JPEG 12 bits project + +include_directories(BEFORE + ${CMAKE_CURRENT_BINARY_DIR} + ${ITKJPEG_SOURCE_DIR}) +add_library(${JPEG_LIBRARY_NAME}12 ${JPEG_SOURCES}) +set_target_properties(${JPEG_LIBRARY_NAME}12 PROPERTIES ${JPEG_LIBRARY_PROPERTIES}) +if(NOT JPEG_INSTALL_NO_LIBRARIES) + install(TARGETS ${JPEG_LIBRARY_NAME}12 + EXPORT ${GDCM_TARGETS_NAME} + RUNTIME DESTINATION ${JPEG_INSTALL_BIN_DIR} COMPONENT Applications + LIBRARY DESTINATION ${JPEG_INSTALL_LIB_DIR} COMPONENT Libraries ${NAMELINK_SKIP} + ARCHIVE DESTINATION ${JPEG_INSTALL_LIB_DIR} COMPONENT DebugDevel + ) + if(NAMELINK_ONLY) + install(TARGETS ${JPEG_LIBRARY_NAME}12 + EXPORT ${GDCM_TARGETS_NAME} + LIBRARY DESTINATION ${JPEG_INSTALL_LIB_DIR} COMPONENT DebugDevel ${NAMELINK_ONLY} + ) + endif() +endif() + +if(NOT JPEG_INSTALL_NO_DEVELOPMENT) + file(GLOB header_files "${CMAKE_CURRENT_BINARY_DIR}/*.h") + install(FILES ${header_files} + DESTINATION ${JPEG_INSTALL_INCLUDE_DIR}/12 COMPONENT DebugDevel + ) +endif() diff --git a/gdcm/Utilities/gdcmjpeg/16/CMakeLists.txt b/gdcm/Utilities/gdcmjpeg/16/CMakeLists.txt new file mode 100644 index 0000000..2127eea --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/16/CMakeLists.txt @@ -0,0 +1,28 @@ +# JPEG 16 bits project + +include_directories(BEFORE + ${CMAKE_CURRENT_BINARY_DIR} + ${ITKJPEG_SOURCE_DIR}) +add_library(${JPEG_LIBRARY_NAME}16 ${JPEG_SOURCES}) +set_target_properties(${JPEG_LIBRARY_NAME}16 PROPERTIES ${JPEG_LIBRARY_PROPERTIES}) +if(NOT JPEG_INSTALL_NO_LIBRARIES) + install(TARGETS ${JPEG_LIBRARY_NAME}16 + EXPORT ${GDCM_TARGETS_NAME} + RUNTIME DESTINATION ${JPEG_INSTALL_BIN_DIR} COMPONENT Applications + LIBRARY DESTINATION ${JPEG_INSTALL_LIB_DIR} COMPONENT Libraries ${NAMELINK_SKIP} + ARCHIVE DESTINATION ${JPEG_INSTALL_LIB_DIR} COMPONENT DebugDevel + ) + if(NAMELINK_ONLY) + install(TARGETS ${JPEG_LIBRARY_NAME}16 + EXPORT ${GDCM_TARGETS_NAME} + LIBRARY DESTINATION ${JPEG_INSTALL_LIB_DIR} COMPONENT DebugDevel ${NAMELINK_ONLY} + ) + endif() +endif() + +if(NOT JPEG_INSTALL_NO_DEVELOPMENT) + file(GLOB header_files "${CMAKE_CURRENT_BINARY_DIR}/*.h") + install(FILES ${header_files} + DESTINATION ${JPEG_INSTALL_INCLUDE_DIR}/16 COMPONENT DebugDevel + ) +endif() diff --git a/gdcm/Utilities/gdcmjpeg/8/CMakeLists.txt b/gdcm/Utilities/gdcmjpeg/8/CMakeLists.txt new file mode 100644 index 0000000..4669543 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/8/CMakeLists.txt @@ -0,0 +1,28 @@ +# JPEG 8 bits project + +include_directories(BEFORE + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}) +add_library(${JPEG_LIBRARY_NAME}8 ${JPEG_SOURCES}) +set_target_properties(${JPEG_LIBRARY_NAME}8 PROPERTIES ${JPEG_LIBRARY_PROPERTIES}) +if(NOT JPEG_INSTALL_NO_LIBRARIES) + install(TARGETS ${JPEG_LIBRARY_NAME}8 + EXPORT ${GDCM_TARGETS_NAME} + RUNTIME DESTINATION ${JPEG_INSTALL_BIN_DIR} COMPONENT Applications + LIBRARY DESTINATION ${JPEG_INSTALL_LIB_DIR} COMPONENT Libraries ${NAMELINK_SKIP} + ARCHIVE DESTINATION ${JPEG_INSTALL_LIB_DIR} COMPONENT DebugDevel + ) + if(NAMELINK_ONLY) + install(TARGETS ${JPEG_LIBRARY_NAME}8 + EXPORT ${GDCM_TARGETS_NAME} + LIBRARY DESTINATION ${JPEG_INSTALL_LIB_DIR} COMPONENT DebugDevel ${NAMELINK_ONLY} + ) + endif() +endif() + +if(NOT JPEG_INSTALL_NO_DEVELOPMENT) + file(GLOB header_files "${CMAKE_CURRENT_BINARY_DIR}/*.h") + install(FILES ${header_files} + DESTINATION ${JPEG_INSTALL_INCLUDE_DIR}/8 COMPONENT DebugDevel + ) +endif() diff --git a/gdcm/Utilities/gdcmjpeg/CMakeLists.txt b/gdcm/Utilities/gdcmjpeg/CMakeLists.txt new file mode 100644 index 0000000..2e77d35 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/CMakeLists.txt @@ -0,0 +1,176 @@ +cmake_minimum_required(VERSION 2.8.9) + +if(NOT JPEG_NAMESPACE) + set(JPEG_NAMESPACE "JPEG") + set(JPEG_STANDALONE 1) + set(JPEG_INSTALL_BIN_DIR bin) + set(JPEG_INSTALL_LIB_DIR lib) + set(JPEG_INSTALL_INCLUDE_DIR include/ljpeg-62) + option(JPEG_BUILD_SHARED_LIBS "Build IJG/JPEG with shared libraries." OFF) + set(BUILD_SHARED_LIBS ${JPEG_BUILD_SHARED_LIBS}) +endif() +# In all cases: +string(TOLOWER ${JPEG_NAMESPACE} JPEG_LIBRARY_NAME) + + +project(${JPEG_NAMESPACE} C) + +# Do full dependency headers. +include_regular_expression("^.*$") + +# let advanced user the option to define JPEG_API_VERSION: +if(NOT DEFINED JPEG_API_VERSION) + set(JPEG_API_VERSION "${GDCM_MAJOR_VERSION}.${GDCM_MINOR_VERSION}") +endif() +set(JPEG_LIBRARY_PROPERTIES ${JPEG_LIBRARY_PROPERTIES} + VERSION "${GDCM_VERSION}" + SOVERSION "${JPEG_API_VERSION}" +) + + +# memmgr back ends: compile only one of these into a working library +# (For now, let's use the mode that requires the image fit into memory. +# This is the recommended mode for Win32 anyway.) +set(systemdependent_SRCS jmemnobs.c) + +# library object files common to compression and decompression +set(common_SRCS +jcomapi.c jutils.c jerror.c jmemmgr.c +#jmemsrc.c +) + +# compression library object files +set(compression_SRCS +jcapimin.c jcapistd.c jctrans.c jcparam.c jcinit.c +jcmaster.c jcmarker.c jcmainct.c jcprepct.c jccoefct.c jccolor.c +jcsample.c jchuff.c jcphuff.c jcdctmgr.c jfdctfst.c jfdctflt.c +jdatadst.c +) + +# Lossy (DCT) codec: +set(comp_lossy_SRCS +jfdctint.c +jclossy.c + +# lossless +jclossls.c + +#jdarith.c +jcodec.c +jcscale.c +jcshuff.c +jclhuff.c +jcpred.c +jcdiffct.c +) + +# decompression library object files +set(decompression_SRCS +jdapimin.c jdapistd.c jdtrans.c jdmaster.c +jdinput.c jdmarker.c jdhuff.c jdphuff.c jdmainct.c jdcoefct.c +jdpostct.c jddctmgr.c jidctfst.c jidctflt.c jidctint.c jidctred.c +jdsample.c jdcolor.c jquant1.c jquant2.c jdmerge.c +jdatasrc.c +) + +set(decomp_lossy_SRCS + jdlossls.c jdlossy.c + #jcarith.c +jdlhuff.c +jddiffct.c +jdpred.c +jdscale.c +jdshuff.c +) + +set(JPEG_HEADER_FILES + jchuff.h + jdct.h + jdhuff.h + jerror.h + jinclude.h + jmemsys.h + jmorecfg.h + jpegint.h + jpeglib.h + jversion.h + jlossy.h + jlossls.h + ) + +set(JPEG_SOURCES) +foreach(src + ${systemdependent_SRCS} + ${common_SRCS} + ${compression_SRCS} + ${decompression_SRCS} + ${comp_lossy_SRCS} + ${decomp_lossy_SRCS} + ) + set(JPEG_SOURCES ${JPEG_SOURCES} + "${CMAKE_CURRENT_SOURCE_DIR}/${src}") +endforeach() + +if (WIN32) + if (BUILD_SHARED_LIBS) + set(JPEGDLL 1) + else () + set(JPEGSTATIC 1) + endif () +endif () + +# By default support DICOMObjects bug, if this is a speed penalty for you +# you should consider disabling it +set(SUPPORT_DICOMOBJECTS_BUG ON) + +# Generate three libraries: jpeg 8bits, 12bits and 16bits +# using only one source directory + +#----------------------------------------------------------------------------- +include (${CMAKE_ROOT}/Modules/CheckIncludeFile.cmake) +CHECK_INCLUDE_FILE("stddef.h" HAVE_STDDEF_H) +CHECK_INCLUDE_FILE("stdlib.h" HAVE_STDLIB_H) + +include_directories(${CMAKE_CURRENT_BINARY_DIR}) +# Particular case jpegcmake.h needs to be specified either 8, 12 or 16 bits: +# also configure the name mangling +foreach(bits 8 12 16) + set(CMAKE_BITS_IN_JSAMPLE ${bits}) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/jpegcmake.h.in + ${CMAKE_CURRENT_BINARY_DIR}/${bits}/jpegcmake.h + @ONLY) + set(MANGLE_PREFIX ${JPEG_LIBRARY_NAME}${bits}) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/mangle_jpeg.h.in + ${CMAKE_CURRENT_BINARY_DIR}/${bits}/mangle_jpeg${bits}bits.h + @ONLY) + + + # FIXME FIXME FIXME + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/jmorecfg.h + ${CMAKE_CURRENT_BINARY_DIR}/${bits}/jmorecfg.h + COPYONLY) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/jconfig.h + ${CMAKE_CURRENT_BINARY_DIR}/${bits}/jconfig.h + COPYONLY) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/jpeglib.h + ${CMAKE_CURRENT_BINARY_DIR}/${bits}/jpeglib.h + COPYONLY) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/jerror.h + ${CMAKE_CURRENT_BINARY_DIR}/${bits}/jerror.h + COPYONLY) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/jinclude.h + ${CMAKE_CURRENT_BINARY_DIR}/${bits}/jinclude.h + COPYONLY) +endforeach() + +# I could not get the depencencies in CMake to work properly so instead +# have multiple directory for each target that will ensure proper recompilation +# of the objects files +subdirs(8 12 16) + +if(NOT JPEG_INSTALL_NO_DEVELOPMENT) + file(GLOB header_files "*.h") + install(FILES ${header_files} + DESTINATION ${JPEG_INSTALL_INCLUDE_DIR} COMPONENT Headers + ) +endif() diff --git a/gdcm/Utilities/gdcmjpeg/COPYRIGHT.dcmtk b/gdcm/Utilities/gdcmjpeg/COPYRIGHT.dcmtk new file mode 100644 index 0000000..e63ec12 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/COPYRIGHT.dcmtk @@ -0,0 +1,257 @@ + +COPYRIGHT + +Unless otherwise specified, the DCMTK software package has the +following copyright: + +/* + * Copyright (C) 1994-2004, OFFIS + * + * This software and supporting documentation were developed by + * + * Kuratorium OFFIS e.V. + * Healthcare Information and Communication Systems + * Escherweg 2 + * D-26121 Oldenburg, Germany + * + * THIS SOFTWARE IS MADE AVAILABLE, AS IS, AND OFFIS MAKES NO WARRANTY + * REGARDING THE SOFTWARE, ITS PERFORMANCE, ITS MERCHANTABILITY OR + * FITNESS FOR ANY PARTICULAR USE, FREEDOM FROM ANY COMPUTER DISEASES OR + * ITS CONFORMITY TO ANY SPECIFICATION. THE ENTIRE RISK AS TO QUALITY AND + * PERFORMANCE OF THE SOFTWARE IS WITH THE USER. + * + * Copyright of the software and supporting documentation is, unless + * otherwise stated, owned by OFFIS, and free access is hereby granted as + * a license to use this software, copy this software and prepare + * derivative works based upon this software. However, any distribution + * of this software source code or supporting documentation or derivative + * works (source code and supporting documentation) must include the + * three paragraphs of this copyright notice. + * + */ + +Some portions of the DCMTK software package are derived from earlier +versions of this software with the following copyright, and can be +identifed by the following copyright notice located in each source file: + +/* + * Copyright (C) 1993/1994, OFFIS, Oldenburg University and CERIUM + * + * This software and supporting documentation were + * developed by + * + * Institut OFFIS + * Bereich Kommunikationssysteme + * Westerstr. 10-12 + * 26121 Oldenburg, Germany + * + * Fachbereich Informatik + * Abteilung Prozessinformatik + * Carl von Ossietzky Universitaet Oldenburg + * Ammerlaender Heerstr. 114-118 + * 26111 Oldenburg, Germany + * + * CERIUM + * Laboratoire SIM + * Faculte de Medecine + * 2 Avenue du Pr. Leon Bernard + * 35043 Rennes Cedex, France + * + * for CEN/TC251/WG4 as a contribution to the Radiological + * Society of North America (RSNA) 1993 Digital Imaging and + * Communications in Medicine (DICOM) Demonstration. + * + * THIS SOFTWARE IS MADE AVAILABLE, AS IS, AND NEITHER OFFIS, + * OLDENBURG UNIVERSITY NOR CERIUM MAKE ANY WARRANTY REGARDING + * THE SOFTWARE, ITS PERFORMANCE, ITS MERCHANTABILITY OR + * FITNESS FOR ANY PARTICULAR USE, FREEDOM FROM ANY COMPUTER + * DISEASES OR ITS CONFORMITY TO ANY SPECIFICATION. THE + * ENTIRE RISK AS TO QUALITY AND PERFORMANCE OF THE SOFTWARE + * IS WITH THE USER. + * + * Copyright of the software and supporting documentation + * is, unless otherwise stated, jointly owned by OFFIS, + * Oldenburg University and CERIUM and free access is hereby + * granted as a license to use this software, copy this + * software and prepare derivative works based upon this + * software. However, any distribution of this software + * source code or supporting documentation or derivative + * works (source code and supporting documentation) must + * include the three paragraphs of this copyright notice. + * + */ + +Some other parts of this software within the dcmtk/dcmnet +sub-package related to the DICOM Upper Layer Protocol are +derived from software developed for the RSNA'93 DICOM +demonstration and kindly made available to us by the Mallinckrodt +Institute of Radiology. Such software can be identifed by the +following copyright notice located in each affected source file: + +/* + * Copyright (C) 1993, RSNA and Washington University + * + * The software and supporting documentation for the Radiological + * Society of North America (RSNA) 1993 Digital Imaging and + * Communications in Medicine (DICOM) Demonstration were developed + * at the + * Electronic Radiology Laboratory + * Mallinckrodt Institute of Radiology + * Washington University School of Medicine + * 510 S. Kingshighway Blvd. + * St. Louis, MO 63110 + * as part of the 1993 DICOM Central Test Node project for, and + * under contract with, the Radiological Society of North America. + * + * THIS SOFTWARE IS MADE AVAILABLE, AS IS, AND NEITHER RSNA NOR + * WASHINGTON UNIVERSITY MAKE ANY WARRANTY ABOUT THE SOFTWARE, ITS + * PERFORMANCE, ITS MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR + * USE, FREEDOM FROM ANY COMPUTER DISEASES OR ITS CONFORMITY TO ANY + * SPECIFICATION. THE ENTIRE RISK AS TO QUALITY AND PERFORMANCE OF + * THE SOFTWARE IS WITH THE USER. + * + * Copyright of the software and supporting documentation is + * jointly owned by RSNA and Washington University, and free access + * is hereby granted as a license to use this software, copy this + * software and prepare derivative works based upon this software. + * However, any distribution of this software source code or + * supporting documentation or derivative works (source code and + * supporting documentation) must include the three paragraphs of + * the copyright notice. + */ + +The dcmjpeg sub-package includes an adapted version of the Independent JPEG +Group Toolkit Version 6b, which is contained in dcmjpeg/libijg8, +dcmjpeg/libijg12 and dcmjpeg/libijg16. This toolkit is covered by the +following copyright. The original README file for the Independent JPEG +Group Toolkit is located in dcmjpeg/docs/ijg_readme.txt. + +/* + * The authors make NO WARRANTY or representation, either express or implied, + * with respect to this software, its quality, accuracy, merchantability, or + * fitness for a particular purpose. This software is provided "AS IS", and you, + * its user, assume the entire risk as to its quality and accuracy. + * + * This software is copyright (C) 1991-1998, Thomas G. Lane. + * All Rights Reserved except as specified below. + * + * Permission is hereby granted to use, copy, modify, and distribute this + * software (or portions thereof) for any purpose, without fee, subject to these + * conditions: + * (1) If any part of the source code for this software is distributed, then this + * README file must be included, with this copyright and no-warranty notice + * unaltered; and any additions, deletions, or changes to the original files + * must be clearly indicated in accompanying documentation. + * (2) If only executable code is distributed, then the accompanying + * documentation must state that "this software is based in part on the work of + * the Independent JPEG Group". + * (3) Permission for use of this software is granted only if the user accepts + * full responsibility for any undesirable consequences; the authors accept + * NO LIABILITY for damages of any kind. + * + * These conditions apply to any software derived from or based on the IJG code, + * not just to the unmodified library. If you use our work, you ought to + * acknowledge us. + * + * Permission is NOT granted for the use of any IJG author's name or company name + * in advertising or publicity relating to this software or products derived from + * it. This software may be referred to only as "the Independent JPEG Group's + * software". + * + * We specifically permit and encourage the use of this software as the basis of + * commercial products, provided that all warranty or liability claims are + * assumed by the product vendor. + */ + + +The color quantization code in module dcmimage (dcmquant and the related +classes) is derived from code written by Jef Poskanzer for the NetPBM +toolkit which has the following copyright: + +/* + * Copyright (C) 1989, 1991 by Jef Poskanzer. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. This software is provided "as is" without express or + * implied warranty. + */ + + +The code for the OFStandard::strlcpy and OFStandard::strlcat helper +functions in ofstd/libsrc/ofstd.cc has been derived from the BSD +implementation of strlcpy() and strlcat() and which carries the +following copyright notice: + +/* + * Copyright (c) 1998 Todd C. Miller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +The code for the OFStandard::atof helper function in +ofstd/libsrc/ofstd.cc has been derived from an implementation which +carries the following copyright notice: + +/* + * Copyright 1988 Regents of the University of California + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appear in all copies. The + * University of California makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * + * The code for OFStandard::ftoa has been derived + * from an implementation which carries the following copyright notice: + * + * Copyright (c) 1988 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +The "Base64" encoder/decoder in ofstd/libsrc/ofstd.cc has been derived +from an implementation which carries the following copyright notice: + +/* + * Copyright (c) 1999, Bob Withers - bwit(at)pobox.com + * + * This code may be freely used for any purpose, either personal or commercial, + * provided the authors copyright notice remains intact. + */ diff --git a/gdcm/Utilities/gdcmjpeg/Jfif.txt b/gdcm/Utilities/gdcmjpeg/Jfif.txt new file mode 100644 index 0000000..8132a10 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/Jfif.txt @@ -0,0 +1,331 @@ +JPEG File Interchange Format +Version 1.02 + + +September 1, 1992 + + + + + + + + + + Eric Hamilton + C-Cube Microsystems + 1778 McCarthy Blvd. + Milpitas, CA 95035 + + +1 408 944-6300 + Fax: +1 408 944-6314 + E-mail: eric@c3.pla.ca.us + + + + +JPEG File Interchange Format +Version 1.02 + +Why a File Interchange Format + +JPEG File Interchange Format is a minimal file format which enables JPEG bitstreams to +be exchanged between a wide variety of platforms and applications. This minimal format +does not include any of the advanced features found in the TIFF JPEG specification or any +application specific file format. Nor should it, for the only purpose of this simplified +format is to allow the exchange of JPEG compressed images. + +JPEG File Interchange Format features + +o Uses JPEG compression +o Uses JPEG interchange format compressed image representation +o PC or Mac or Unix workstation compatible +o Standard color space: one or three components. For three components, YCbCr + (CCIR 601-256 levels) +o APP0 marker used to specify Units, X pixel density, Y pixel density, thumbnail +o APP0 marker also used to specify JFIF extensions +o APP0 marker also used to specify application-specific information + +JPEG Compression + +Although any JPEG process is supported by the syntax of the JPEG File Interchange Format +(JFIF) it is strongly recommended that the JPEG baseline process be used for the purposes +of file interchange. This ensures maximum compatibility with all applications supporting +JPEG. JFIF conforms to the JPEG Draft International Standard (ISO DIS 10918-1). + +The JPEG File Interchange Format is entirely compatible with the standard JPEG +interchange format; the only additional requirement is the mandatory presence of the +APP0 marker right after the SOI marker. Note that JPEG interchange format requires (as +does JFIF) that all table specifications used in the encoding process be coded in the +bitstream prior to their use. + +Compatible across platforms + +The JPEG File Interchange Format is compatible across platforms: for example, it does not +use any resource forks, supported by the Macintosh but not by PCs or workstations. + + +Standard color space + +The color space to be used is YCbCr as defined by CCIR 601 (256 levels). The RGB +components calculated by linear conversion from YCbCr shall not be gamma corrected +(gamma = 1.0). If only one component is used, that component shall be Y. + +APP0 marker used to identify JPEG FIF + +The APP0 marker is used to identify a JPEG FIF file. The JPEG FIF APP0 marker is +mandatory right after the SOI marker. + +The JFIF APP0 marker is identified by a zero terminated string: "JFIF". The APP0 can be +used for any other purpose by the application provided it can be distinguished from the +JFIF APP0. + +The JFIF APP0 marker provides information which is missing from the JPEG stream: +version number, X and Y pixel density (dots per inch or dots per cm), pixel aspect ratio +(derived from X and Y pixel density), thumbnail. + +APP0 marker used to specify JFIF extensions + +Additional APP0 marker segment(s) can optionally be used to specify JFIF extensions. If +used, these segment(s) must immediately follow the JFIF APP0 marker. Decoders should +skip any unsupported JFIF extension segments and continue decoding. + +The JFIF extension APP0 marker is identified by a zero terminated string: "JFXX". The +JFIF extension APP0 marker segment contains a 1-byte code which identifies the extension. +This version, version 1.02, has only one extension defined: an extension for defining +thumbnails stored in formats other than 24-bit RGB. + +APP0 marker used for application-specific information + +Additional APP0 marker segments can be used to hold application-specific information +which does not affect the decodability or displayability of the JFIF file. Application- +specific APP0 marker segments must appear after the JFIF APP0 and any JFXX APP0 +segments. Decoders should skip any unrecognized application-specific APP0 segments. + +Application-specific APP0 marker segments are identified by a zero terminated string +which identifies the application (not "JFIF" or "JFXX"). This string should be an +organization name or company trademark. Generic strings such as dog, cat, tree, etc. +should not be used. + + + +Conversion to and from RGB + +Y, Cb, and Cr are converted from R, G, and B as defined in CCIR Recommendation 601 +but are normalized so as to occupy the full 256 levels of a 8-bit binary encoding. More +precisely: + +Y = 256 * E'y +Cb = 256 * [ E'Cb ] + 128 +Cr = 256 * [ E'Cr ] + 128 + +where the E'y, E'Cb and E'Cb are defined as in CCIR 601. Since values of E'y have a +range of 0 to 1.0 and those for E'Cb and E'Cr have a range of -0.5 to +0.5, Y, Cb, and Cr +must be clamped to 255 when they are maximum value. + +RGB to YCbCr Conversion + +YCbCr (256 levels) can be computed directly from 8-bit RGB as follows: + +Y = 0.299 R + 0.587 G + 0.114 B +Cb = - 0.1687 R - 0.3313 G + 0.5 B + 128 +Cr = 0.5 R - 0.4187 G - 0.0813 B + 128 + +NOTE - Not all image file formats store image samples in the order R0, G0, +B0, ... Rn, Gn, Bn. Be sure to verify the sample order before converting an +RGB file to JFIF. + + +YCbCr to RGB Conversion + +RGB can be computed directly from YCbCr (256 levels) as follows: + +R = Y + 1.402 (Cr-128) +G = Y - 0.34414 (Cb-128) - 0.71414 (Cr-128) +B = Y + 1.772 (Cb-128) + + +Image Orientation + +In JFIF files, the image orientation is always top-down. This means that the first image +samples encoded in a JFIF file are located in the upper left hand corner of the image and +encoding proceeds from left to right and top to bottom. Top-down orientation is used for +both the full resolution image and the thumbnail image. + +The process of converting an image file having bottom-up orientation to JFIF must include +inverting the order of all image lines before JPEG encoding + + +Spatial Relationship of Components + +Specification of the spatial positioning of pixel samples within components relative to the +samples of other components is necessary for proper image post processing and accurate +image presentation. In JFIF files, the position of the pixels in subsampled components are +defined with respect to the highest resolution component. Since components must be +sampled orthogonally (along rows and columns), the spatial position of the samples in a +given subsampled component may be determined by specifying the horizontal and vertical +offsets of the first sample, i.e. the sample in the upper left corner, with respect to the +highest resolution component. + +The horizontal and vertical offsets of the first sample in a subsampled component, +Xoffseti[0,0] and Yoffseti[0,0], is defined to be + +Xoffseti[0,0] = ( Nsamplesref / Nsamplesi ) / 2 - 0.5 +Yoffseti[0,0] = ( Nlinesref / Nlinesi ) / 2 - 0.5 + +where +Nsamplesref is the number of samples per line in the largest component, +Nsamplesi is the number of samples per line in the ith component, +Nlinesref is the number of lines in the largest component, +Nlinesi is the number of lines in the ith component. + +Proper subsampling of components incorporates an anti-aliasing filter which reduces the +spectral bandwidth of the full resolution components. Subsampling can easily be +accomplished using a symmetrical digital filter with an even number of taps (coefficients). +A commonly used filter for 2:1 subsampling utilizes two taps (1/2,1/2). + +NOTE - This definition is compatible with industry standards such as Postcript +Level 2 and QuickTime. This defintition is not compatible with the conventions +used by CCIR Recommendation 601-1 and other digital video formats. For these +formats, pre-processing of the chrominance components is necessary prior to +compression in order to ensure accurate reconstruction of the compressed image. + + +JPEG File Interchange Format Specification + +The syntax of a JFIF file conforms to the syntax for interchange format defined in Annex B +of ISO DIS 10918-1. In addition, a JFIF file uses APP0 marker segments and constrains +certain parameters in the frame header as defined below. + + X'FF', SOI + X'FF', APP0, length, identifier, version, units, Xdensity, Ydensity, Xthumbnail, + Ythumbnail, (RGB)n + length (2 bytes) Total APP0 field byte count, including the byte + count value (2 bytes), but excluding the APP0 + marker itself + identifier (5 bytes) = X'4A', X'46', X'49', X'46', X'00' + This zero terminated string ("JFIF") uniquely + identifies this APP0 marker. This string shall + have zero parity (bit 7=0). + version (2 bytes) = X'0102' + The most significant byte is used for major + revisions, the least significant byte for minor + revisions. Version 1.02 is the current released + revision. + units (1 byte) Units for the X and Y densities. + units = 0: no units, X and Y specify the pixel + aspect ratio + units = 1: X and Y are dots per inch + units = 2: X and Y are dots per cm + Xdensity (2 bytes) Horizontal pixel density + Ydensity (2 bytes) Vertical pixel density + Xthumbnail (1 byte) Thumbnail horizontal pixel count + Ythumbnail (1 byte) Thumbnail vertical pixel count + (RGB)n (3n bytes) Packed (24-bit) RGB values for the thumbnail + pixels, n = Xthumbnail * Ythumbnail + [ Optional JFIF extension APP0 marker segment(s) - see below ] + o + o + o + X'FF', SOFn, length, frame parameters + Number of components Nf = 1 or 3 + 1st component C1 = 1 = Y component + 2nd component C2 = 2 = Cb component + 3rd component C3 = 3 = Cr component + o + o + o + X'FF', EOI + +JFIF Extension APP0 Marker Segment + +Immediately following the JFIF APP0 marker segment may be a JFIF extension APP0 +marker. This JFIF extension APP0 marker segment may only be present for JFIF versions +1.02 and above. The syntax of the JFIF extension APP0 marker segment is: + + X'FF', APP0, length, identifier, extension_code, extension_data + length (2 bytes) Total APP0 field byte count, including the byte + count value (2 bytes), but excluding the APP0 + marker itself + identifier (5 bytes) = X'4A', X'46', X'58', X'58', X'00' + This zero terminated string ("JFXX") uniquely + identifies this APP0 marker. This string shall + have zero parity (bit 7=0). + extension_code (1 byte) = Code which identifies the extension. In this + version, the following extensions are defined: + = X'10' Thumbnail coded using JPEG + = X'11' Thumbnail stored using 1 byte/pixel + = X'13' Thumbnail stored using 3 bytes/pixel + extension_data (variable) = The specification of the remainder of the JFIF + extension APP0 marker segment varies with the + extension. See below for a specification of + extension_data for each extension. + +JFIF Extension: Thumbnail coded using JPEG + +This extension supports thumbnails compressed using JPEG. The compressed thumbnail +immediately follows the extension_code (X'10') in the extension_data field and the length +of the compressed data must be included in the JFIF extension APP0 marker length field. + +The syntax of the extension_data field conforms to the syntax for interchange format defined +in Annex B of ISO DIS 10918-1. However, no "JFIF" or "JFXX" marker segments shall +be present. As in the full resolution image of the JFIF file, the syntax of extension_data +constrains parameters in the frame header as defined below: + + X'FF', SOI + o + o + o + X'FF', SOFn, length, frame parameters + Number of components Nf = 1 or 3 + 1st component C1 = 1 = Y component + 2nd component C2 = 2 = Cb component + 3rd component C3 = 3 = Cr component + o + o + o + X'FF', EOI + + + +JFIF Extension: Thumbnail stored using one byte per pixel + +This extension supports thumbnails stored using one byte per pixel and a color palette in +the extension_data field. The syntax of extension_data is: + + Xthumbnail (1 byte) Thumbnail horizontal pixel count + Ythumbnail (1 byte) Thumbnail vertical pixel count + palette (768 bytes) 24-bit RGB pixel values for the color palette. + The RGB values define the colors represented by + each value of an 8-bit binary encoding (0 - 255). + (pixel)n (n bytes) 8-bit values for the thumbnail pixels + n = Xthumbnail * Ythumbnail + +JFIF Extension: Thumbnail stored using three bytes per pixel + +This extension supports thumbnails stored using three bytes per pixel in the extension_data +field. The syntax of extension_data is: + + Xthumbnail (1 byte) Thumbnail horizontal pixel count + Ythumbnail (1 byte) Thumbnail vertical pixel count + (RGB)n (3n bytes) Packed (24-bit) RGB values for the thumbnail + pixels, n = Xthumbnail * Ythumbnail + +Useful tips + +o you can identify a JFIF file by looking for the following sequence: X'FF', SOI, X'FF', +APP0, <2 bytes to be skipped>, "JFIF", X'00'. + +o if you use APP0 elsewhere, be sure not to have the strings "JFIF" or "JFXX" right after +the APP0 marker. + +o if you do not want to include a thumbnail, just program Xthumbnail = Ythumbnail = 0. + +o be sure to check the version number in the special APP0 field. In general, if the major +version number of the JFIF file matches that supported by the decoder, the file will be +decodable. + +o if you only want to specify a pixel aspect ratio, put 0 for the units field in the special +APP0 field. Xdensity and Ydensity can then be programmed for the desired aspect ratio. +Xdensity = 1, Ydensity = 1 will program a 1:1 aspect ratio. Xdensity and Ydensity should +always be non-zero. diff --git a/gdcm/Utilities/gdcmjpeg/README b/gdcm/Utilities/gdcmjpeg/README new file mode 100644 index 0000000..2423594 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/README @@ -0,0 +1,385 @@ +The Independent JPEG Group's JPEG software +========================================== + +README for release 6b of 27-Mar-1998 +==================================== + +This distribution contains the sixth public release of the Independent JPEG +Group's free JPEG software. You are welcome to redistribute this software and +to use it for any purpose, subject to the conditions under LEGAL ISSUES, below. + +Serious users of this software (particularly those incorporating it into +larger programs) should contact IJG at jpeg-info@uunet.uu.net to be added to +our electronic mailing list. Mailing list members are notified of updates +and have a chance to participate in technical discussions, etc. + +This software is the work of Tom Lane, Philip Gladstone, Jim Boucher, +Lee Crocker, Julian Minguillon, Luis Ortiz, George Phillips, Davide Rossi, +Guido Vollbeding, Ge' Weijers, and other members of the Independent JPEG +Group. + +IJG is not affiliated with the official ISO JPEG standards committee. + + +DOCUMENTATION ROADMAP +===================== + +This file contains the following sections: + +OVERVIEW General description of JPEG and the IJG software. +LEGAL ISSUES Copyright, lack of warranty, terms of distribution. +REFERENCES Where to learn more about JPEG. +ARCHIVE LOCATIONS Where to find newer versions of this software. +RELATED SOFTWARE Other stuff you should get. +FILE FORMAT WARS Software *not* to get. +TO DO Plans for future IJG releases. + +Other documentation files in the distribution are: + +User documentation: + install.doc How to configure and install the IJG software. + usage.doc Usage instructions for cjpeg, djpeg, jpegtran, + rdjpgcom, and wrjpgcom. + *.1 Unix-style man pages for programs (same info as usage.doc). + wizard.doc Advanced usage instructions for JPEG wizards only. + change.log Version-to-version change highlights. +Programmer and internal documentation: + libjpeg.doc How to use the JPEG library in your own programs. + example.c Sample code for calling the JPEG library. + structure.doc Overview of the JPEG library's internal structure. + filelist.doc Road map of IJG files. + coderules.doc Coding style rules --- please read if you contribute code. + +Please read at least the files install.doc and usage.doc. Useful information +can also be found in the JPEG FAQ (Frequently Asked Questions) article. See +ARCHIVE LOCATIONS below to find out where to obtain the FAQ article. + +If you want to understand how the JPEG code works, we suggest reading one or +more of the REFERENCES, then looking at the documentation files (in roughly +the order listed) before diving into the code. + + +OVERVIEW +======== + +This package contains C software to implement JPEG image compression and +decompression. JPEG (pronounced "jay-peg") is a standardized compression +method for full-color and gray-scale images. JPEG is intended for compressing +"real-world" scenes; line drawings, cartoons and other non-realistic images +are not its strong suit. JPEG is lossy, meaning that the output image is not +exactly identical to the input image. Hence you must not use JPEG if you +have to have identical output bits. However, on typical photographic images, +very good compression levels can be obtained with no visible change, and +remarkably high compression levels are possible if you can tolerate a +low-quality image. For more details, see the references, or just experiment +with various compression settings. + +This software implements JPEG baseline, extended-sequential, progressive +and lossless compression processes. Provision is made for supporting all +variants of these processes, although some uncommon parameter settings aren't +implemented yet. For legal reasons, we are not distributing code for the +arithmetic-coding variants of JPEG; see LEGAL ISSUES. We have made no +provision for supporting the hierarchical processes defined in the standard. + +We provide a set of library routines for reading and writing JPEG image files, +plus two sample applications "cjpeg" and "djpeg", which use the library to +perform conversion between JPEG and some other popular image file formats. +The library is intended to be reused in other applications. + +In order to support file conversion and viewing software, we have included +considerable functionality beyond the bare JPEG coding/decoding capability; +for example, the color quantization modules are not strictly part of JPEG +decoding, but they are essential for output to colormapped file formats or +colormapped displays. These extra functions can be compiled out of the +library if not required for a particular application. We have also included +"jpegtran", a utility for lossless transcoding between different JPEG +processes, and "rdjpgcom" and "wrjpgcom", two simple applications for +inserting and extracting textual comments in JFIF files. + +The emphasis in designing this software has been on achieving portability and +flexibility, while also making it fast enough to be useful. In particular, +the software is not intended to be read as a tutorial on JPEG. (See the +REFERENCES section for introductory material.) Rather, it is intended to +be reliable, portable, industrial-strength code. We do not claim to have +achieved that goal in every aspect of the software, but we strive for it. + +We welcome the use of this software as a component of commercial products. +No royalty is required, but we do ask for an acknowledgement in product +documentation, as described under LEGAL ISSUES. + + +LEGAL ISSUES +============ + +In plain English: + +1. We don't promise that this software works. (But if you find any bugs, + please let us know!) +2. You can use this software for whatever you want. You don't have to pay us. +3. You may not pretend that you wrote this software. If you use it in a + program, you must acknowledge somewhere in your documentation that + you've used the IJG code. + +In legalese: + +The authors make NO WARRANTY or representation, either express or implied, +with respect to this software, its quality, accuracy, merchantability, or +fitness for a particular purpose. This software is provided "AS IS", and you, +its user, assume the entire risk as to its quality and accuracy. + +This software is copyright (C) 1991-1998, Thomas G. Lane. +All Rights Reserved except as specified below. + +Permission is hereby granted to use, copy, modify, and distribute this +software (or portions thereof) for any purpose, without fee, subject to these +conditions: +(1) If any part of the source code for this software is distributed, then this +README file must be included, with this copyright and no-warranty notice +unaltered; and any additions, deletions, or changes to the original files +must be clearly indicated in accompanying documentation. +(2) If only executable code is distributed, then the accompanying +documentation must state that "this software is based in part on the work of +the Independent JPEG Group". +(3) Permission for use of this software is granted only if the user accepts +full responsibility for any undesirable consequences; the authors accept +NO LIABILITY for damages of any kind. + +These conditions apply to any software derived from or based on the IJG code, +not just to the unmodified library. If you use our work, you ought to +acknowledge us. + +Permission is NOT granted for the use of any IJG author's name or company name +in advertising or publicity relating to this software or products derived from +it. This software may be referred to only as "the Independent JPEG Group's +software". + +We specifically permit and encourage the use of this software as the basis of +commercial products, provided that all warranty or liability claims are +assumed by the product vendor. + + +ansi2knr.c is included in this distribution by permission of L. Peter Deutsch, +sole proprietor of its copyright holder, Aladdin Enterprises of Menlo Park, CA. +ansi2knr.c is NOT covered by the above copyright and conditions, but instead +by the usual distribution terms of the Free Software Foundation; principally, +that you must include source code if you redistribute it. (See the file +ansi2knr.c for full details.) However, since ansi2knr.c is not needed as part +of any program generated from the IJG code, this does not limit you more than +the foregoing paragraphs do. + +The Unix configuration script "configure" was produced with GNU Autoconf. +It is copyright by the Free Software Foundation but is freely distributable. +The same holds for its supporting scripts (config.guess, config.sub, +ltconfig, ltmain.sh). Another support script, install-sh, is copyright +by M.I.T. but is also freely distributable. + +It appears that the arithmetic coding option of the JPEG spec is covered by +patents owned by IBM, AT&T, and Mitsubishi. Hence arithmetic coding cannot +legally be used without obtaining one or more licenses. For this reason, +support for arithmetic coding has been removed from the free JPEG software. +(Since arithmetic coding provides only a marginal gain over the unpatented +Huffman mode, it is unlikely that very many implementations will support it.) +So far as we are aware, there are no patent restrictions on the remaining +code. + +The IJG distribution formerly included code to read and write GIF files. +To avoid entanglement with the Unisys LZW patent, GIF reading support has +been removed altogether, and the GIF writer has been simplified to produce +"uncompressed GIFs". This technique does not use the LZW algorithm; the +resulting GIF files are larger than usual, but are readable by all standard +GIF decoders. + +We are required to state that + "The Graphics Interchange Format(c) is the Copyright property of + CompuServe Incorporated. GIF(sm) is a Service Mark property of + CompuServe Incorporated." + + +REFERENCES +========== + +We highly recommend reading one or more of these references before trying to +understand the innards of the JPEG software. + +The best short technical introduction to the JPEG compression algorithm is + Wallace, Gregory K. "The JPEG Still Picture Compression Standard", + Communications of the ACM, April 1991 (vol. 34 no. 4), pp. 30-44. +(Adjacent articles in that issue discuss MPEG motion picture compression, +applications of JPEG, and related topics.) If you don't have the CACM issue +handy, a PostScript file containing a revised version of Wallace's article is +available at ftp://ftp.uu.net/graphics/jpeg/wallace.ps.gz. The file (actually +a preprint for an article that appeared in IEEE Trans. Consumer Electronics) +omits the sample images that appeared in CACM, but it includes corrections +and some added material. Note: the Wallace article is copyright ACM and IEEE, +and it may not be used for commercial purposes. + +A somewhat less technical, more leisurely introduction to JPEG can be found in +"The Data Compression Book" by Mark Nelson and Jean-loup Gailly, published by +M&T Books (New York), 2nd ed. 1996, ISBN 1-55851-434-1. This book provides +good explanations and example C code for a multitude of compression methods +including JPEG. It is an excellent source if you are comfortable reading C +code but don't know much about data compression in general. The book's JPEG +sample code is far from industrial-strength, but when you are ready to look +at a full implementation, you've got one here... + +The best full description of JPEG is the textbook "JPEG Still Image Data +Compression Standard" by William B. Pennebaker and Joan L. Mitchell, published +by Van Nostrand Reinhold, 1993, ISBN 0-442-01272-1. Price US$59.95, 638 pp. +The book includes the complete text of the ISO JPEG standards (DIS 10918-1 +and draft DIS 10918-2). This is by far the most complete exposition of JPEG +in existence, and we highly recommend it. + +The JPEG standard itself is not available electronically; you must order a +paper copy through ISO or ITU. (Unless you feel a need to own a certified +official copy, we recommend buying the Pennebaker and Mitchell book instead; +it's much cheaper and includes a great deal of useful explanatory material.) +In the USA, copies of the standard may be ordered from ANSI Sales at (212) +642-4900, or from Global Engineering Documents at (800) 854-7179. (ANSI +doesn't take credit card orders, but Global does.) It's not cheap: as of +1992, ANSI was charging $95 for Part 1 and $47 for Part 2, plus 7% +shipping/handling. The standard is divided into two parts, Part 1 being the +actual specification, while Part 2 covers compliance testing methods. Part 1 +is titled "Digital Compression and Coding of Continuous-tone Still Images, +Part 1: Requirements and guidelines" and has document numbers ISO/IEC IS +10918-1, ITU-T T.81. Part 2 is titled "Digital Compression and Coding of +Continuous-tone Still Images, Part 2: Compliance testing" and has document +numbers ISO/IEC IS 10918-2, ITU-T T.83. + +Some extensions to the original JPEG standard are defined in JPEG Part 3, +a newer ISO standard numbered ISO/IEC IS 10918-3 and ITU-T T.84. IJG +currently does not support any Part 3 extensions. + +The JPEG standard does not specify all details of an interchangeable file +format. For the omitted details we follow the "JFIF" conventions, revision +1.02. A copy of the JFIF spec is available from: + Literature Department + C-Cube Microsystems, Inc. + 1778 McCarthy Blvd. + Milpitas, CA 95035 + phone (408) 944-6300, fax (408) 944-6314 +A PostScript version of this document is available by FTP at +ftp://ftp.uu.net/graphics/jpeg/jfif.ps.gz. There is also a plain text +version at ftp://ftp.uu.net/graphics/jpeg/jfif.txt.gz, but it is missing +the figures. + +The TIFF 6.0 file format specification can be obtained by FTP from +ftp://ftp.sgi.com/graphics/tiff/TIFF6.ps.gz. The JPEG incorporation scheme +found in the TIFF 6.0 spec of 3-June-92 has a number of serious problems. +IJG does not recommend use of the TIFF 6.0 design (TIFF Compression tag 6). +Instead, we recommend the JPEG design proposed by TIFF Technical Note #2 +(Compression tag 7). Copies of this Note can be obtained from ftp.sgi.com or +from ftp://ftp.uu.net/graphics/jpeg/. It is expected that the next revision +of the TIFF spec will replace the 6.0 JPEG design with the Note's design. +Although IJG's own code does not support TIFF/JPEG, the free libtiff library +uses our library to implement TIFF/JPEG per the Note. libtiff is available +from ftp://ftp.sgi.com/graphics/tiff/. + + +ARCHIVE LOCATIONS +================= + +The "official" archive site for this software is ftp.uu.net (Internet +address 192.48.96.9). The most recent released version can always be found +there in directory graphics/jpeg. This particular version will be archived +as ftp://ftp.uu.net/graphics/jpeg/jpegsrc.v6b.tar.gz. If you don't have +direct Internet access, UUNET's archives are also available via UUCP; contact +help@uunet.uu.net for information on retrieving files that way. + +Numerous Internet sites maintain copies of the UUNET files. However, only +ftp.uu.net is guaranteed to have the latest official version. + +You can also obtain this software in DOS-compatible "zip" archive format from +the SimTel archives (ftp://ftp.simtel.net/pub/simtelnet/msdos/graphics/), or +on CompuServe in the Graphics Support forum (GO CIS:GRAPHSUP), library 12 +"JPEG Tools". Again, these versions may sometimes lag behind the ftp.uu.net +release. + +The JPEG FAQ (Frequently Asked Questions) article is a useful source of +general information about JPEG. It is updated constantly and therefore is +not included in this distribution. The FAQ is posted every two weeks to +Usenet newsgroups comp.graphics.misc, news.answers, and other groups. +It is available on the World Wide Web at http://www.faqs.org/faqs/jpeg-faq/ +and other news.answers archive sites, including the official news.answers +archive at rtfm.mit.edu: ftp://rtfm.mit.edu/pub/usenet/news.answers/jpeg-faq/. +If you don't have Web or FTP access, send e-mail to mail-server@rtfm.mit.edu +with body + send usenet/news.answers/jpeg-faq/part1 + send usenet/news.answers/jpeg-faq/part2 + + +RELATED SOFTWARE +================ + +Numerous viewing and image manipulation programs now support JPEG. (Quite a +few of them use this library to do so.) The JPEG FAQ described above lists +some of the more popular free and shareware viewers, and tells where to +obtain them on Internet. + +If you are on a Unix machine, we highly recommend Jef Poskanzer's free +PBMPLUS software, which provides many useful operations on PPM-format image +files. In particular, it can convert PPM images to and from a wide range of +other formats, thus making cjpeg/djpeg considerably more useful. The latest +version is distributed by the NetPBM group, and is available from numerous +sites, notably ftp://wuarchive.wustl.edu/graphics/graphics/packages/NetPBM/. +Unfortunately PBMPLUS/NETPBM is not nearly as portable as the IJG software is; +you are likely to have difficulty making it work on any non-Unix machine. + +A different free JPEG implementation, written by the PVRG group at Stanford, +is available from ftp://havefun.stanford.edu/pub/jpeg/. This program +is designed for research and experimentation rather than production use; +it is slower, harder to use, and less portable than the IJG code, but it +is easier to read and modify. Also, the PVRG code supports lossless JPEG, +which we do not. (On the other hand, it doesn't do progressive JPEG.) + + +FILE FORMAT WARS +================ + +Some JPEG programs produce files that are not compatible with our library. +The root of the problem is that the ISO JPEG committee failed to specify a +concrete file format. Some vendors "filled in the blanks" on their own, +creating proprietary formats that no one else could read. (For example, none +of the early commercial JPEG implementations for the Macintosh were able to +exchange compressed files.) + +The file format we have adopted is called JFIF (see REFERENCES). This format +has been agreed to by a number of major commercial JPEG vendors, and it has +become the de facto standard. JFIF is a minimal or "low end" representation. +We recommend the use of TIFF/JPEG (TIFF revision 6.0 as modified by TIFF +Technical Note #2) for "high end" applications that need to record a lot of +additional data about an image. TIFF/JPEG is fairly new and not yet widely +supported, unfortunately. + +The upcoming JPEG Part 3 standard defines a file format called SPIFF. +SPIFF is interoperable with JFIF, in the sense that most JFIF decoders should +be able to read the most common variant of SPIFF. SPIFF has some technical +advantages over JFIF, but its major claim to fame is simply that it is an +official standard rather than an informal one. At this point it is unclear +whether SPIFF will supersede JFIF or whether JFIF will remain the de-facto +standard. IJG intends to support SPIFF once the standard is frozen, but we +have not decided whether it should become our default output format or not. +(In any case, our decoder will remain capable of reading JFIF indefinitely.) + +Various proprietary file formats incorporating JPEG compression also exist. +We have little or no sympathy for the existence of these formats. Indeed, +one of the original reasons for developing this free software was to help +force convergence on common, open format standards for JPEG files. Don't +use a proprietary file format! + + +TO DO +===== + +The major thrust for v7 will probably be improvement of visual quality. +The current method for scaling the quantization tables is known not to be +very good at low Q values. We also intend to investigate block boundary +smoothing, "poor man's variable quantization", and other means of improving +quality-vs-file-size performance without sacrificing compatibility. + +In future versions, we are considering supporting some of the upcoming JPEG +Part 3 extensions --- principally, variable quantization and the SPIFF file +format. + +As always, speeding things up is of great interest. + +Please send bug reports, offers of help, etc. to jpeg-info@uunet.uu.net. diff --git a/gdcm/Utilities/gdcmjpeg/README.GDCM.txt b/gdcm/Utilities/gdcmjpeg/README.GDCM.txt new file mode 100644 index 0000000..7e19b07 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/README.GDCM.txt @@ -0,0 +1,83 @@ +This directory contains a subset of the Independent JPEG Group's (IJG) libjpeg +version 6b. We only include enough of distribution to build libjpeg. We do +not include the standard executables that come with libjpeg (cjpeg, djpeg, +etc.). Furthermore, the standard libjpeg build process is replaced with a CMake +build process. + +We'd like to thank the IJG for distributing a public JPEG IO library. + +We'd like to also thank the dcmtk crew for releasing their toolkit under such a +nice license that allow us to patch ijg properly to handle all sort of jpeg +compression found in the DICOM implementation. The copyright can be found in +COPYRIGHT.dcmtk. + +Modifications +------------- + +1. +jconfig.h is usually generated by the build process. For this distribution, we +ship a version of jconfig.h.in to be used across several platforms. It's +purpose is also to allow generation of both 8bits, 12bits and 16bits lib. + + + +2. +jmorecfg.h was modified so that we can modify it automatically at build time to +either generate a 8bits jpeg lib, 12bits jpeg library or 16bits jpeg library: + +Index: jmorecfg.h +=================================================================== +RCS file: /cvs/public/gdcm/src/jpeg/libijg8/jmorecfg.h,v +retrieving revision 1.4 +diff -u -3 -p -r1.4 jmorecfg.h +--- jmorecfg.h 31 Oct 2003 14:59:50 -0000 1.4 ++++ jmorecfg.h 7 Oct 2004 02:30:40 -0000 +@@ -19,7 +19,8 @@ + * We do not support run-time selection of data precision, sorry. + */ + +-#define BITS_IN_JSAMPLE 8 /* use 8 or 12 */ ++//#define BITS_IN_JSAMPLE 8 /* use 8 or 12 */ ++#define BITS_IN_JSAMPLE @GDCM_BITS_IN_JSAMPLE@ + + /* + * Maximum number of components (color channels) allowed in JPEG image. + + + + +3. +To further allow us to have to different copy of the 8, 12 and 16 bits jpeg +library we had to mangle the name. Fur this purpose two new file were added to +the library: gdcm_mangle_8bits.h, gdcm_mangle_12bits.h and +gdcm_mangle_16bits.h. +Those file were generated using: + + nm libgdcmijpeg8.a | grep " [R|T] " | colrm 1 11 | sort + + +4. +In order to read lossless images, we had to apply the ls-patch to jpeg-6b. So I started from scratch: + +tar xvfz /tmp/jpegsrc.v6b.tar.gz (1) +patch < /tmp/ljpeg-6b.patch (2) +patch -p0 < arithmetic-without-arith-option-full.patch (3) +patch -p0 < warnings10-14.patch (4) +patch -p0 < previous-gdcm.patch (5) +----------------------------------------------------------- += The subdir src/jpeg/libijg + +(now I also need to apply the redhat patch for cplusplus lib) + +(1) http://www.ijg.org/files/jpegsrc.v6b.tar.gz +(2) http://www.oceana.com/ftp/ljpeg/ljpeg-patch.v6b.tar.gz +(3), (4) and (5) http://www.creatis.insa-lyon.fr/~malaterre/jpeg/ + +(3) Was made with a carefull inspection of dcmtk code (see convert.sh at the same spot as the patch) +(4) Is basically just compilation of the lib with -W -Wall -Werror +(5) This contains some configuration copy/paste from VTK, and the 'well known' 12 bits Philips MRI DICOM patch + + + +NOTE for later: +(shoud we disable getenv just as dcmtk ? there is a ijg flag for that NO_ENV or something similar diff --git a/gdcm/Utilities/gdcmjpeg/change.log b/gdcm/Utilities/gdcmjpeg/change.log new file mode 100644 index 0000000..74102c0 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/change.log @@ -0,0 +1,217 @@ +CHANGE LOG for Independent JPEG Group's JPEG software + + +Version 6b 27-Mar-1998 +----------------------- + +jpegtran has new features for lossless image transformations (rotation +and flipping) as well as "lossless" reduction to grayscale. + +jpegtran now copies comments by default; it has a -copy switch to enable +copying all APPn blocks as well, or to suppress comments. (Formerly it +always suppressed comments and APPn blocks.) jpegtran now also preserves +JFIF version and resolution information. + +New decompressor library feature: COM and APPn markers found in the input +file can be saved in memory for later use by the application. (Before, +you had to code this up yourself with a custom marker processor.) + +There is an unused field "void * client_data" now in compress and decompress +parameter structs; this may be useful in some applications. + +JFIF version number information is now saved by the decoder and accepted by +the encoder. jpegtran uses this to copy the source file's version number, +to ensure "jpegtran -copy all" won't create bogus files that contain JFXX +extensions but claim to be version 1.01. Applications that generate their +own JFXX extension markers also (finally) have a supported way to cause the +encoder to emit JFIF version number 1.02. + +djpeg's trace mode reports JFIF 1.02 thumbnail images as such, rather +than as unknown APP0 markers. + +In -verbose mode, djpeg and rdjpgcom will try to print the contents of +APP12 markers as text. Some digital cameras store useful text information +in APP12 markers. + +Handling of truncated data streams is more robust: blocks beyond the one in +which the error occurs will be output as uniform gray, or left unchanged +if decoding a progressive JPEG. The appearance no longer depends on the +Huffman tables being used. + +Huffman tables are checked for validity much more carefully than before. + +To avoid the Unisys LZW patent, djpeg's GIF output capability has been +changed to produce "uncompressed GIFs", and cjpeg's GIF input capability +has been removed altogether. We're not happy about it either, but there +seems to be no good alternative. + +The configure script now supports building libjpeg as a shared library +on many flavors of Unix (all the ones that GNU libtool knows how to +build shared libraries for). Use "./configure --enable-shared" to +try this out. + +New jconfig file and makefiles for Microsoft Visual C++ and Developer Studio. +Also, a jconfig file and a build script for Metrowerks CodeWarrior +on Apple Macintosh. makefile.dj has been updated for DJGPP v2, and there +are miscellaneous other minor improvements in the makefiles. + +jmemmac.c now knows how to create temporary files following Mac System 7 +conventions. + +djpeg's -map switch is now able to read raw-format PPM files reliably. + +cjpeg -progressive -restart no longer generates any unnecessary DRI markers. + +Multiple calls to jpeg_simple_progression for a single JPEG object +no longer leak memory. + + +Version 6a 7-Feb-96 +-------------------- + +Library initialization sequence modified to detect version mismatches +and struct field packing mismatches between library and calling application. +This change requires applications to be recompiled, but does not require +any application source code change. + +All routine declarations changed to the style "GLOBAL(type) name ...", +that is, GLOBAL, LOCAL, METHODDEF, EXTERN are now macros taking the +routine's return type as an argument. This makes it possible to add +Microsoft-style linkage keywords to all the routines by changing just +these macros. Note that any application code that was using these macros +will have to be changed. + +DCT coefficient quantization tables are now stored in normal array order +rather than zigzag order. Application code that calls jpeg_add_quant_table, +or otherwise manipulates quantization tables directly, will need to be +changed. If you need to make such code work with either older or newer +versions of the library, a test like "#if JPEG_LIB_VERSION >= 61" is +recommended. + +djpeg's trace capability now dumps DQT tables in natural order, not zigzag +order. This allows the trace output to be made into a "-qtables" file +more easily. + +New system-dependent memory manager module for use on Apple Macintosh. + +Fix bug in cjpeg's -smooth option: last one or two scanlines would be +duplicates of the prior line unless the image height mod 16 was 1 or 2. + +Repair minor problems in VMS, BCC, MC6 makefiles. + +New configure script based on latest GNU Autoconf. + +Correct the list of include files needed by MetroWerks C for ccommand(). + +Numerous small documentation updates. + + +Version 6 2-Aug-95 +------------------- + +Progressive JPEG support: library can read and write full progressive JPEG +files. A "buffered image" mode supports incremental decoding for on-the-fly +display of progressive images. Simply recompiling an existing IJG-v5-based +decoder with v6 should allow it to read progressive files, though of course +without any special progressive display. + +New "jpegtran" application performs lossless transcoding between different +JPEG formats; primarily, it can be used to convert baseline to progressive +JPEG and vice versa. In support of jpegtran, the library now allows lossless +reading and writing of JPEG files as DCT coefficient arrays. This ability +may be of use in other applications. + +Notes for programmers: +* We changed jpeg_start_decompress() to be able to suspend; this makes all +decoding modes available to suspending-input applications. However, +existing applications that use suspending input will need to be changed +to check the return value from jpeg_start_decompress(). You don't need to +do anything if you don't use a suspending data source. +* We changed the interface to the virtual array routines: access_virt_array +routines now take a count of the number of rows to access this time. The +last parameter to request_virt_array routines is now interpreted as the +maximum number of rows that may be accessed at once, but not necessarily +the height of every access. + + +Version 5b 15-Mar-95 +--------------------- + +Correct bugs with grayscale images having v_samp_factor > 1. + +jpeg_write_raw_data() now supports output suspension. + +Correct bugs in "configure" script for case of compiling in +a directory other than the one containing the source files. + +Repair bug in jquant1.c: sometimes didn't use as many colors as it could. + +Borland C makefile and jconfig file work under either MS-DOS or OS/2. + +Miscellaneous improvements to documentation. + + +Version 5a 7-Dec-94 +-------------------- + +Changed color conversion roundoff behavior so that grayscale values are +represented exactly. (This causes test image files to change.) + +Make ordered dither use 16x16 instead of 4x4 pattern for a small quality +improvement. + +New configure script based on latest GNU Autoconf. +Fix configure script to handle CFLAGS correctly. +Rename *.auto files to *.cfg, so that configure script still works if +file names have been truncated for DOS. + +Fix bug in rdbmp.c: didn't allow for extra data between header and image. + +Modify rdppm.c/wrppm.c to handle 2-byte raw PPM/PGM formats for 12-bit data. + +Fix several bugs in rdrle.c. + +NEED_SHORT_EXTERNAL_NAMES option was broken. + +Revise jerror.h/jerror.c for more flexibility in message table. + +Repair oversight in jmemname.c NO_MKTEMP case: file could be there +but unreadable. + + +Version 5 24-Sep-94 +-------------------- + +Version 5 represents a nearly complete redesign and rewrite of the IJG +software. Major user-visible changes include: + * Automatic configuration simplifies installation for most Unix systems. + * A range of speed vs. image quality tradeoffs are supported. + This includes resizing of an image during decompression: scaling down + by a factor of 1/2, 1/4, or 1/8 is handled very efficiently. + * New programs rdjpgcom and wrjpgcom allow insertion and extraction + of text comments in a JPEG file. + +The application programmer's interface to the library has changed completely. +Notable improvements include: + * We have eliminated the use of callback routines for handling the + uncompressed image data. The application now sees the library as a + set of routines that it calls to read or write image data on a + scanline-by-scanline basis. + * The application image data is represented in a conventional interleaved- + pixel format, rather than as a separate array for each color channel. + This can save a copying step in many programs. + * The handling of compressed data has been cleaned up: the application can + supply routines to source or sink the compressed data. It is possible to + suspend processing on source/sink buffer overrun, although this is not + supported in all operating modes. + * All static state has been eliminated from the library, so that multiple + instances of compression or decompression can be active concurrently. + * JPEG abbreviated datastream formats are supported, ie, quantization and + Huffman tables can be stored separately from the image data. + * And not only that, but the documentation of the library has improved + considerably! + + +The last widely used release before the version 5 rewrite was version 4A of +18-Feb-93. Change logs before that point have been discarded, since they +are not of much interest after the rewrite. diff --git a/gdcm/Utilities/gdcmjpeg/dcmtk.sh b/gdcm/Utilities/gdcmjpeg/dcmtk.sh new file mode 100644 index 0000000..da2271f --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/dcmtk.sh @@ -0,0 +1,20 @@ +# Script to patch dcmtk in order to compare gdcm version against it +sed -i -e 's/IJG_INT32/INT32/g' *.c *.h +sed -i -e's/jinclude[8|12|16]/jinclude/g' *.c +sed -i -e's/jpeglib[8|12|16]/jpeglib/g' *.c +sed -i -e's/jlossy[8|12|16]/jlossy/g' *.c +sed -i -e's/jmemsys[8|12|16]/jmemsys/g' *.c +sed -i -e's/jdct[8|12|16]/jdct/g' *.c +sed -i -e's/jversion[8|12|16]/jversion/g' *.c +sed -i -e's/jerror[8|12|16]/jerror/g' *.c +sed -i -e's/jdhuff[8|12|16]/jdhuff/g' *.c +sed -i -e's/jlossls[8|12|16]/jlossls/g' *.c +sed -i -e's/jchuff[8|12|16]/jchuff/g' *.c +sed -i -e's/jconfig[8|12|16]/jconfig/g' *.h +sed -i -e's/jmorecfg[8|12|16]/jmorecfg/g' *.h +sed -i -e's/jpegint[8|12|16]/jpegint/g' *.h +sed -i -e's/jerror[8|12|16]/jerror/g' *.h +sed -i -e's/mymain/main/g' *.c +rename 's/8\.h$/\.h/' *.h +rename 's/12\.h$/\.h/' *.h +rename 's/16\.h$/\.h/' *.h diff --git a/gdcm/Utilities/gdcmjpeg/example.c b/gdcm/Utilities/gdcmjpeg/example.c new file mode 100644 index 0000000..71f98ff --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/example.c @@ -0,0 +1,433 @@ +/* + * example.c + * + * This file illustrates how to use the IJG code as a subroutine library + * to read or write JPEG image files. You should look at this code in + * conjunction with the documentation file libjpeg.doc. + * + * This code will not do anything useful as-is, but it may be helpful as a + * skeleton for constructing routines that call the JPEG library. + * + * We present these routines in the same coding style used in the JPEG code + * (ANSI function definitions, etc); but you are of course free to code your + * routines in a different style if you prefer. + */ + +#include + +/* + * Include file for users of JPEG library. + * You will need to have included system headers that define at least + * the typedefs FILE and size_t before you can include jpeglib.h. + * (stdio.h is sufficient on ANSI-conforming systems.) + * You may also wish to include "jerror.h". + */ + +#include "jpeglib.h" + +/* + * is used for the optional error recovery mechanism shown in + * the second part of the example. + */ + +#include + + + +/******************** JPEG COMPRESSION SAMPLE INTERFACE *******************/ + +/* This half of the example shows how to feed data into the JPEG compressor. + * We present a minimal version that does not worry about refinements such + * as error recovery (the JPEG code will just exit() if it gets an error). + */ + + +/* + * IMAGE DATA FORMATS: + * + * The standard input image format is a rectangular array of pixels, with + * each pixel having the same number of "component" values (color channels). + * Each pixel row is an array of JSAMPLEs (which typically are unsigned chars). + * If you are working with color data, then the color values for each pixel + * must be adjacent in the row; for example, R,G,B,R,G,B,R,G,B,... for 24-bit + * RGB color. + * + * For this example, we'll assume that this data structure matches the way + * our application has stored the image in memory, so we can just pass a + * pointer to our image buffer. In particular, let's say that the image is + * RGB color and is described by: + */ + +extern JSAMPLE * image_buffer; /* Points to large array of R,G,B-order data */ +extern int image_height; /* Number of rows in image */ +extern int image_width; /* Number of columns in image */ + + +/* + * Sample routine for JPEG compression. We assume that the target file name + * and a compression quality factor are passed in. + */ + +GLOBAL(void) +write_JPEG_file (char * filename, int quality) +{ + /* This struct contains the JPEG compression parameters and pointers to + * working space (which is allocated as needed by the JPEG library). + * It is possible to have several such structures, representing multiple + * compression/decompression processes, in existence at once. We refer + * to any one struct (and its associated working data) as a "JPEG object". + */ + struct jpeg_compress_struct cinfo; + /* This struct represents a JPEG error handler. It is declared separately + * because applications often want to supply a specialized error handler + * (see the second half of this file for an example). But here we just + * take the easy way out and use the standard error handler, which will + * print a message on stderr and call exit() if compression fails. + * Note that this struct must live as long as the main JPEG parameter + * struct, to avoid dangling-pointer problems. + */ + struct jpeg_error_mgr jerr; + /* More stuff */ + FILE * outfile; /* target file */ + JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ + int row_stride; /* physical row width in image buffer */ + + /* Step 1: allocate and initialize JPEG compression object */ + + /* We have to set up the error handler first, in case the initialization + * step fails. (Unlikely, but it could happen if you are out of memory.) + * This routine fills in the contents of struct jerr, and returns jerr's + * address which we place into the link field in cinfo. + */ + cinfo.err = jpeg_std_error(&jerr); + /* Now we can initialize the JPEG compression object. */ + jpeg_create_compress(&cinfo); + + /* Step 2: specify data destination (eg, a file) */ + /* Note: steps 2 and 3 can be done in either order. */ + + /* Here we use the library-supplied code to send compressed data to a + * stdio stream. You can also write your own code to do something else. + * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that + * requires it in order to write binary files. + */ + if ((outfile = fopen(filename, "wb")) == NULL) { + fprintf(stderr, "can't open %s\n", filename); + exit(1); + } + jpeg_stdio_dest(&cinfo, outfile); + + /* Step 3: set parameters for compression */ + + /* First we supply a description of the input image. + * Four fields of the cinfo struct must be filled in: + */ + cinfo.image_width = image_width; /* image width and height, in pixels */ + cinfo.image_height = image_height; + cinfo.input_components = 3; /* # of color components per pixel */ + cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ + /* Now use the library's routine to set default compression parameters. + * (You must set at least cinfo.in_color_space before calling this, + * since the defaults depend on the source color space.) + */ + jpeg_set_defaults(&cinfo); + /* Now you can set any non-default parameters you wish to. + * Here we just illustrate the use of quality (quantization table) scaling: + */ + jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */); + + /* Step 4: Start compressor */ + + /* TRUE ensures that we will write a complete interchange-JPEG file. + * Pass TRUE unless you are very sure of what you're doing. + */ + jpeg_start_compress(&cinfo, TRUE); + + /* Step 5: while (scan lines remain to be written) */ + /* jpeg_write_scanlines(...); */ + + /* Here we use the library's state variable cinfo.next_scanline as the + * loop counter, so that we don't have to keep track ourselves. + * To keep things simple, we pass one scanline per call; you can pass + * more if you wish, though. + */ + row_stride = image_width * 3; /* JSAMPLEs per row in image_buffer */ + + while (cinfo.next_scanline < cinfo.image_height) { + /* jpeg_write_scanlines expects an array of pointers to scanlines. + * Here the array is only one element long, but you could pass + * more than one scanline at a time if that's more convenient. + */ + row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride]; + (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); + } + + /* Step 6: Finish compression */ + + jpeg_finish_compress(&cinfo); + /* After finish_compress, we can close the output file. */ + fclose(outfile); + + /* Step 7: release JPEG compression object */ + + /* This is an important step since it will release a good deal of memory. */ + jpeg_destroy_compress(&cinfo); + + /* And we're done! */ +} + + +/* + * SOME FINE POINTS: + * + * In the above loop, we ignored the return value of jpeg_write_scanlines, + * which is the number of scanlines actually written. We could get away + * with this because we were only relying on the value of cinfo.next_scanline, + * which will be incremented correctly. If you maintain additional loop + * variables then you should be careful to increment them properly. + * Actually, for output to a stdio stream you needn't worry, because + * then jpeg_write_scanlines will write all the lines passed (or else exit + * with a fatal error). Partial writes can only occur if you use a data + * destination module that can demand suspension of the compressor. + * (If you don't know what that's for, you don't need it.) + * + * If the compressor requires full-image buffers (for entropy-coding + * optimization or a multi-scan JPEG file), it will create temporary + * files for anything that doesn't fit within the maximum-memory setting. + * (Note that temp files are NOT needed if you use the default parameters.) + * On some systems you may need to set up a signal handler to ensure that + * temporary files are deleted if the program is interrupted. See libjpeg.doc. + * + * Scanlines MUST be supplied in top-to-bottom order if you want your JPEG + * files to be compatible with everyone else's. If you cannot readily read + * your data in that order, you'll need an intermediate array to hold the + * image. See rdtarga.c or rdbmp.c for examples of handling bottom-to-top + * source data using the JPEG code's internal virtual-array mechanisms. + */ + + + +/******************** JPEG DECOMPRESSION SAMPLE INTERFACE *******************/ + +/* This half of the example shows how to read data from the JPEG decompressor. + * It's a bit more refined than the above, in that we show: + * (a) how to modify the JPEG library's standard error-reporting behavior; + * (b) how to allocate workspace using the library's memory manager. + * + * Just to make this example a little different from the first one, we'll + * assume that we do not intend to put the whole image into an in-memory + * buffer, but to send it line-by-line someplace else. We need a one- + * scanline-high JSAMPLE array as a work buffer, and we will let the JPEG + * memory manager allocate it for us. This approach is actually quite useful + * because we don't need to remember to deallocate the buffer separately: it + * will go away automatically when the JPEG object is cleaned up. + */ + + +/* + * ERROR HANDLING: + * + * The JPEG library's standard error handler (jerror.c) is divided into + * several "methods" which you can override individually. This lets you + * adjust the behavior without duplicating a lot of code, which you might + * have to update with each future release. + * + * Our example here shows how to override the "error_exit" method so that + * control is returned to the library's caller when a fatal error occurs, + * rather than calling exit() as the standard error_exit method does. + * + * We use C's setjmp/longjmp facility to return control. This means that the + * routine which calls the JPEG library must first execute a setjmp() call to + * establish the return point. We want the replacement error_exit to do a + * longjmp(). But we need to make the setjmp buffer accessible to the + * error_exit routine. To do this, we make a private extension of the + * standard JPEG error handler object. (If we were using C++, we'd say we + * were making a subclass of the regular error handler.) + * + * Here's the extended error handler struct: + */ + +struct my_error_mgr { + struct jpeg_error_mgr pub; /* "public" fields */ + + jmp_buf setjmp_buffer; /* for return to caller */ +}; + +typedef struct my_error_mgr * my_error_ptr; + +/* + * Here's the routine that will replace the standard error_exit method: + */ + +METHODDEF(void) +my_error_exit (j_common_ptr cinfo) +{ + /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */ + my_error_ptr myerr = (my_error_ptr) cinfo->err; + + /* Always display the message. */ + /* We could postpone this until after returning, if we chose. */ + (*cinfo->err->output_message) (cinfo); + + /* Return control to the setjmp point */ + longjmp(myerr->setjmp_buffer, 1); +} + + +/* + * Sample routine for JPEG decompression. We assume that the source file name + * is passed in. We want to return 1 on success, 0 on error. + */ + + +GLOBAL(int) +read_JPEG_file (char * filename) +{ + /* This struct contains the JPEG decompression parameters and pointers to + * working space (which is allocated as needed by the JPEG library). + */ + struct jpeg_decompress_struct cinfo; + /* We use our private extension JPEG error handler. + * Note that this struct must live as long as the main JPEG parameter + * struct, to avoid dangling-pointer problems. + */ + struct my_error_mgr jerr; + /* More stuff */ + FILE * infile; /* source file */ + JSAMPARRAY buffer; /* Output row buffer */ + int row_stride; /* physical row width in output buffer */ + + /* In this example we want to open the input file before doing anything else, + * so that the setjmp() error recovery below can assume the file is open. + * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that + * requires it in order to read binary files. + */ + + if ((infile = fopen(filename, "rb")) == NULL) { + fprintf(stderr, "can't open %s\n", filename); + return 0; + } + + /* Step 1: allocate and initialize JPEG decompression object */ + + /* We set up the normal JPEG error routines, then override error_exit. */ + cinfo.err = jpeg_std_error(&jerr.pub); + jerr.pub.error_exit = my_error_exit; + /* Establish the setjmp return context for my_error_exit to use. */ + if (setjmp(jerr.setjmp_buffer)) { + /* If we get here, the JPEG code has signaled an error. + * We need to clean up the JPEG object, close the input file, and return. + */ + jpeg_destroy_decompress(&cinfo); + fclose(infile); + return 0; + } + /* Now we can initialize the JPEG decompression object. */ + jpeg_create_decompress(&cinfo); + + /* Step 2: specify data source (eg, a file) */ + + jpeg_stdio_src(&cinfo, infile); + + /* Step 3: read file parameters with jpeg_read_header() */ + + (void) jpeg_read_header(&cinfo, TRUE); + /* We can ignore the return value from jpeg_read_header since + * (a) suspension is not possible with the stdio data source, and + * (b) we passed TRUE to reject a tables-only JPEG file as an error. + * See libjpeg.doc for more info. + */ + + /* Step 4: set parameters for decompression */ + + /* In this example, we don't need to change any of the defaults set by + * jpeg_read_header(), so we do nothing here. + */ + + /* Step 5: Start decompressor */ + + (void) jpeg_start_decompress(&cinfo); + /* We can ignore the return value since suspension is not possible + * with the stdio data source. + */ + + /* We may need to do some setup of our own at this point before reading + * the data. After jpeg_start_decompress() we have the correct scaled + * output image dimensions available, as well as the output colormap + * if we asked for color quantization. + * In this example, we need to make an output work buffer of the right size. + */ + /* JSAMPLEs per row in output buffer */ + row_stride = cinfo.output_width * cinfo.output_components; + /* Make a one-row-high sample array that will go away when done with image */ + buffer = (*cinfo.mem->alloc_sarray) + ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); + + /* Step 6: while (scan lines remain to be read) */ + /* jpeg_read_scanlines(...); */ + + /* Here we use the library's state variable cinfo.output_scanline as the + * loop counter, so that we don't have to keep track ourselves. + */ + while (cinfo.output_scanline < cinfo.output_height) { + /* jpeg_read_scanlines expects an array of pointers to scanlines. + * Here the array is only one element long, but you could ask for + * more than one scanline at a time if that's more convenient. + */ + (void) jpeg_read_scanlines(&cinfo, buffer, 1); + /* Assume put_scanline_someplace wants a pointer and sample count. */ + put_scanline_someplace(buffer[0], row_stride); + } + + /* Step 7: Finish decompression */ + + (void) jpeg_finish_decompress(&cinfo); + /* We can ignore the return value since suspension is not possible + * with the stdio data source. + */ + + /* Step 8: Release JPEG decompression object */ + + /* This is an important step since it will release a good deal of memory. */ + jpeg_destroy_decompress(&cinfo); + + /* After finish_decompress, we can close the input file. + * Here we postpone it until after no more JPEG errors are possible, + * so as to simplify the setjmp error logic above. (Actually, I don't + * think that jpeg_destroy can do an error exit, but why assume anything...) + */ + fclose(infile); + + /* At this point you may want to check to see whether any corrupt-data + * warnings occurred (test whether jerr.pub.num_warnings is nonzero). + */ + + /* And we're done! */ + return 1; +} + + +/* + * SOME FINE POINTS: + * + * In the above code, we ignored the return value of jpeg_read_scanlines, + * which is the number of scanlines actually read. We could get away with + * this because we asked for only one line at a time and we weren't using + * a suspending data source. See libjpeg.doc for more info. + * + * We cheated a bit by calling alloc_sarray() after jpeg_start_decompress(); + * we should have done it beforehand to ensure that the space would be + * counted against the JPEG max_memory setting. In some systems the above + * code would risk an out-of-memory error. However, in general we don't + * know the output image dimensions before jpeg_start_decompress(), unless we + * call jpeg_calc_output_dimensions(). See libjpeg.doc for more about this. + * + * Scanlines are returned in the same order as they appear in the JPEG file, + * which is standardly top-to-bottom. If you must emit data bottom-to-top, + * you can use one of the virtual arrays provided by the JPEG memory manager + * to invert the data. See wrbmp.c for an example. + * + * As with compression, some operating modes may require temporary files. + * On some systems you may need to set up a signal handler to ensure that + * temporary files are deleted if the program is interrupted. See libjpeg.doc. + */ diff --git a/gdcm/Utilities/gdcmjpeg/filelist.doc b/gdcm/Utilities/gdcmjpeg/filelist.doc new file mode 100644 index 0000000..9ba88e0 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/filelist.doc @@ -0,0 +1,239 @@ +IJG JPEG LIBRARY: FILE LIST + +Copyright (C) 1994-1997, Thomas G. Lane. +This file is part of the Independent JPEG Group's software. +For conditions of distribution and use, see the accompanying README file. + + +Here is a road map to the files in the IJG JPEG distribution. The +distribution includes the JPEG library proper, plus two application +programs ("cjpeg" and "djpeg") which use the library to convert JPEG +files to and from some other popular image formats. A third application +"jpegtran" uses the library to do lossless conversion between different +variants of JPEG. There are also two stand-alone applications, +"rdjpgcom" and "wrjpgcom". + + +THE JPEG LIBRARY +================ + +Include files: + +jpeglib.h JPEG library's exported data and function declarations. +jconfig.h Configuration declarations. Note: this file is not present + in the distribution; it is generated during installation. +jmorecfg.h Additional configuration declarations; need not be changed + for a standard installation. +jerror.h Declares JPEG library's error and trace message codes. +jinclude.h Central include file used by all IJG .c files to reference + system include files. +jpegint.h JPEG library's internal data structures. +jlossls.h JPEG library's lossless codec data structures. +jlossy.h JPEG library's lossy codec structures. +jchuff.h Private declarations for Huffman encoder modules. +jdhuff.h Private declarations for Huffman decoder modules. +jdct.h Private declarations for forward & reverse DCT subsystems. +jmemsys.h Private declarations for memory management subsystem. +jversion.h Version information. + +Applications using the library should include jpeglib.h (which in turn +includes jconfig.h and jmorecfg.h). Optionally, jerror.h may be included +if the application needs to reference individual JPEG error codes. The +other include files are intended for internal use and would not normally +be included by an application program. (cjpeg/djpeg/etc do use jinclude.h, +since its function is to improve portability of the whole IJG distribution. +Most other applications will directly include the system include files they +want, and hence won't need jinclude.h.) + + +C source code files: + +These files contain most of the functions intended to be called directly by +an application program: + +jcapimin.c Application program interface: core routines for compression. +jcapistd.c Application program interface: standard compression. +jdapimin.c Application program interface: core routines for decompression. +jdapistd.c Application program interface: standard decompression. +jcomapi.c Application program interface routines common to compression + and decompression. +jcparam.c Compression parameter setting helper routines. +jctrans.c API and library routines for transcoding compression. +jdtrans.c API and library routines for transcoding decompression. + +Compression side of the library: + +jcinit.c Initialization: determines which other modules to use. +jcmaster.c Master control: setup and inter-pass sequencing logic. +jcmainct.c Main buffer controller (preprocessor => JPEG compressor). +jchuff.c Codec-independent Huffman entropy encoding routines. +jcprepct.c Preprocessor buffer controller. +jccolor.c Color space conversion. +jcsample.c Downsampling. +jcmarker.c JPEG marker writing. +jdatadst.c Data destination manager for stdio output. + +Lossy (DCT) codec: + +jlossy.c Lossy compressor proper. +jccoefct.c Buffer controller for DCT coefficient buffer. +jcdctmgr.c DCT manager (DCT implementation selection & control). +jfdctint.c Forward DCT using slow-but-accurate integer method. +jfdctfst.c Forward DCT using faster, less accurate integer method. +jfdctflt.c Forward DCT using floating-point arithmetic. +jcshuff.c Huffman entropy coding for sequential JPEG. +jcphuff.c Huffman entropy coding for progressive JPEG. + +Lossless (spatial) codec: + +jclossls.c Lossless compressor proper. +jcdiffct.c Buffer controller for difference buffer. +jcscale.c Point transformation. +jcpred.c Sample predictor and differencer. +jclhuff.c Huffman entropy encoding for lossless JPEG. + +Decompression side of the library: + +jdmaster.c Master control: determines which other modules to use. +jdinput.c Input controller: controls input processing modules. +jdmainct.c Main buffer controller (JPEG decompressor => postprocessor). +jdhuff.c Codec-independent Huffman entropy decoding routines. +jdpostct.c Postprocessor buffer controller. +jdmarker.c JPEG marker reading. +jdsample.c Upsampling. +jdcolor.c Color space conversion. +jdmerge.c Merged upsampling/color conversion (faster, lower quality). +jquant1.c One-pass color quantization using a fixed-spacing colormap. +jquant2.c Two-pass color quantization using a custom-generated colormap. + Also handles one-pass quantization to an externally given map. +jdatasrc.c Data source manager for stdio input. + +Lossy (DCT) codec: + +jdlossy.c Lossy decompressor proper. +jdcoefct.c Buffer controller for DCT coefficient buffer. +jdshuff.c Huffman entropy decoding for sequential JPEG. +jdphuff.c Huffman entropy decoding for progressive JPEG. +jddctmgr.c IDCT manager (IDCT implementation selection & control). +jidctint.c Inverse DCT using slow-but-accurate integer method. +jidctfst.c Inverse DCT using faster, less accurate integer method. +jidctflt.c Inverse DCT using floating-point arithmetic. +jidctred.c Inverse DCTs with reduced-size outputs. + +Lossless (spatial) codec: + +jdlossls.c Lossless decompressor proper. +jddiffct.c Buffer controller for difference buffers. +jdlhuff.c Huffman entropy decoding for lossless JPEG. +jdpred.c Sample predictor and undifferencer. +jdscale.c Point transformation, sample size scaling. + +Support files for both compression and decompression: + +jerror.c Standard error handling routines (application replaceable). +jmemmgr.c System-independent (more or less) memory management code. +jcodec.c Codec-independent utility routines. +jutils.c Miscellaneous utility routines. + +jmemmgr.c relies on a system-dependent memory management module. The IJG +distribution includes the following implementations of the system-dependent +module: + +jmemnobs.c "No backing store": assumes adequate virtual memory exists. +jmemansi.c Makes temporary files with ANSI-standard routine tmpfile(). +jmemname.c Makes temporary files with program-generated file names. +jmemdos.c Custom implementation for MS-DOS (16-bit environment only): + can use extended and expanded memory as well as temp files. +jmemmac.c Custom implementation for Apple Macintosh. + +Exactly one of the system-dependent modules should be configured into an +installed JPEG library (see install.doc for hints about which one to use). +On unusual systems you may find it worthwhile to make a special +system-dependent memory manager. + + +Non-C source code files: + +jmemdosa.asm 80x86 assembly code support for jmemdos.c; used only in + MS-DOS-specific configurations of the JPEG library. + + +CJPEG/DJPEG/JPEGTRAN +==================== + +Include files: + +cdjpeg.h Declarations shared by cjpeg/djpeg/jpegtran modules. +cderror.h Additional error and trace message codes for cjpeg et al. +transupp.h Declarations for jpegtran support routines in transupp.c. + +C source code files: + +cjpeg.c Main program for cjpeg. +djpeg.c Main program for djpeg. +jpegtran.c Main program for jpegtran. +cdjpeg.c Utility routines used by all three programs. +rdcolmap.c Code to read a colormap file for djpeg's "-map" switch. +rdswitch.c Code to process some of cjpeg's more complex switches. + Also used by jpegtran. +transupp.c Support code for jpegtran: lossless image manipulations. + +Image file reader modules for cjpeg: + +rdbmp.c BMP file input. +rdgif.c GIF file input (now just a stub). +rdppm.c PPM/PGM file input. +rdrle.c Utah RLE file input. +rdtarga.c Targa file input. + +Image file writer modules for djpeg: + +wrbmp.c BMP file output. +wrgif.c GIF file output (a mere shadow of its former self). +wrppm.c PPM/PGM file output. +wrrle.c Utah RLE file output. +wrtarga.c Targa file output. + + +RDJPGCOM/WRJPGCOM +================= + +C source code files: + +rdjpgcom.c Stand-alone rdjpgcom application. +wrjpgcom.c Stand-alone wrjpgcom application. + +These programs do not depend on the IJG library. They do use +jconfig.h and jinclude.h, only to improve portability. + + +ADDITIONAL FILES +================ + +Documentation (see README for a guide to the documentation files): + +README Master documentation file. +*.doc Other documentation files. +*.1 Documentation in Unix man page format. +change.log Version-to-version change highlights. +example.c Sample code for calling JPEG library. + +Configuration/installation files and programs (see install.doc for more info): + +configure Unix shell script to perform automatic configuration. +ltconfig Support scripts for configure (from GNU libtool). +ltmain.sh +config.guess +config.sub +install-sh Install shell script for those Unix systems lacking one. +ckconfig.c Program to generate jconfig.h on non-Unix systems. +jconfig.doc Template for making jconfig.h by hand. +makefile.* Sample makefiles for particular systems. +jconfig.* Sample jconfig.h for particular systems. +ansi2knr.c De-ANSIfier for pre-ANSI C compilers (courtesy of + L. Peter Deutsch and Aladdin Enterprises). + +Test files (see install.doc for test procedure): + +test*.* Source and comparison files for confidence test. + These are binary image files, NOT text files. diff --git a/gdcm/Utilities/gdcmjpeg/install.doc b/gdcm/Utilities/gdcmjpeg/install.doc new file mode 100644 index 0000000..ab62cbe --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/install.doc @@ -0,0 +1,1063 @@ +INSTALLATION INSTRUCTIONS for the Independent JPEG Group's JPEG software + +Copyright (C) 1991-1998, Thomas G. Lane. +This file is part of the Independent JPEG Group's software. +For conditions of distribution and use, see the accompanying README file. + + +This file explains how to configure and install the IJG software. We have +tried to make this software extremely portable and flexible, so that it can be +adapted to almost any environment. The downside of this decision is that the +installation process is complicated. We have provided shortcuts to simplify +the task on common systems. But in any case, you will need at least a little +familiarity with C programming and program build procedures for your system. + +If you are only using this software as part of a larger program, the larger +program's installation procedure may take care of configuring the IJG code. +For example, Ghostscript's installation script will configure the IJG code. +You don't need to read this file if you just want to compile Ghostscript. + +If you are on a Unix machine, you may not need to read this file at all. +Try doing + ./configure + make + make test +If that doesn't complain, do + make install +(better do "make -n install" first to see if the makefile will put the files +where you want them). Read further if you run into snags or want to customize +the code for your system. + + +TABLE OF CONTENTS +----------------- + +Before you start +Configuring the software: + using the automatic "configure" script + using one of the supplied jconfig and makefile files + by hand +Building the software +Testing the software +Installing the software +Optional stuff +Optimization +Hints for specific systems + + +BEFORE YOU START +================ + +Before installing the software you must unpack the distributed source code. +Since you are reading this file, you have probably already succeeded in this +task. However, there is a potential for error if you needed to convert the +files to the local standard text file format (for example, if you are on +MS-DOS you may have converted LF end-of-line to CR/LF). You must apply +such conversion to all the files EXCEPT those whose names begin with "test". +The test files contain binary data; if you change them in any way then the +self-test will give bad results. + +Please check the last section of this file to see if there are hints for the +specific machine or compiler you are using. + + +CONFIGURING THE SOFTWARE +======================== + +To configure the IJG code for your system, you need to create two files: + * jconfig.h: contains values for system-dependent #define symbols. + * Makefile: controls the compilation process. +(On a non-Unix machine, you may create "project files" or some other +substitute for a Makefile. jconfig.h is needed in any environment.) + +We provide three different ways to generate these files: + * On a Unix system, you can just run the "configure" script. + * We provide sample jconfig files and makefiles for popular machines; + if your machine matches one of the samples, just copy the right sample + files to jconfig.h and Makefile. + * If all else fails, read the instructions below and make your own files. + + +Configuring the software using the automatic "configure" script +--------------------------------------------------------------- + +If you are on a Unix machine, you can just type + ./configure +and let the configure script construct appropriate configuration files. +If you're using "csh" on an old version of System V, you might need to type + sh configure +instead to prevent csh from trying to execute configure itself. +Expect configure to run for a few minutes, particularly on slower machines; +it works by compiling a series of test programs. + +Configure was created with GNU Autoconf and it follows the usual conventions +for GNU configure scripts. It makes a few assumptions that you may want to +override. You can do this by providing optional switches to configure: + +* If you want to build libjpeg as a shared library, say + ./configure --enable-shared +To get both shared and static libraries, say + ./configure --enable-shared --enable-static +Note that these switches invoke GNU libtool to take care of system-dependent +shared library building methods. If things don't work this way, please try +running configure without either switch; that should build a static library +without using libtool. If that works, your problem is probably with libtool +not with the IJG code. libtool is fairly new and doesn't support all flavors +of Unix yet. (You might be able to find a newer version of libtool than the +one included with libjpeg; see ftp.gnu.org. Report libtool problems to +bug-libtool@gnu.org.) + +* Configure will use gcc (GNU C compiler) if it's available, otherwise cc. +To force a particular compiler to be selected, use the CC option, for example + ./configure CC='cc' +The same method can be used to include any unusual compiler switches. +For example, on HP-UX you probably want to say + ./configure CC='cc -Aa' +to get HP's compiler to run in ANSI mode. + +* The default CFLAGS setting is "-O" for non-gcc compilers, "-O2" for gcc. +You can override this by saying, for example, + ./configure CFLAGS='-g' +if you want to compile with debugging support. + +* Configure will set up the makefile so that "make install" will install files +into /usr/local/bin, /usr/local/man, etc. You can specify an installation +prefix other than "/usr/local" by giving configure the option "--prefix=PATH". + +* If you don't have a lot of swap space, you may need to enable the IJG +software's internal virtual memory mechanism. To do this, give the option +"--enable-maxmem=N" where N is the default maxmemory limit in megabytes. +This is discussed in more detail under "Selecting a memory manager", below. +You probably don't need to worry about this on reasonably-sized Unix machines, +unless you plan to process very large images. + +Configure has some other features that are useful if you are cross-compiling +or working in a network of multiple machine types; but if you need those +features, you probably already know how to use them. + + +Configuring the software using one of the supplied jconfig and makefile files +----------------------------------------------------------------------------- + +If you have one of these systems, you can just use the provided configuration +files: + +Makefile jconfig file System and/or compiler + +makefile.manx jconfig.manx Amiga, Manx Aztec C +makefile.sas jconfig.sas Amiga, SAS C +makeproj.mac jconfig.mac Apple Macintosh, Metrowerks CodeWarrior +mak*jpeg.st jconfig.st Atari ST/STE/TT, Pure C or Turbo C +makefile.bcc jconfig.bcc MS-DOS or OS/2, Borland C +makefile.dj jconfig.dj MS-DOS, DJGPP (Delorie's port of GNU C) +makefile.mc6 jconfig.mc6 MS-DOS, Microsoft C (16-bit only) +makefile.wat jconfig.wat MS-DOS, OS/2, or Windows NT, Watcom C +makefile.vc jconfig.vc Windows NT/95, MS Visual C++ +make*.ds jconfig.vc Windows NT/95, MS Developer Studio +makefile.mms jconfig.vms Digital VMS, with MMS software +makefile.vms jconfig.vms Digital VMS, without MMS software + +Copy the proper jconfig file to jconfig.h and the makefile to Makefile (or +whatever your system uses as the standard makefile name). For more info see +the appropriate system-specific hints section near the end of this file. + + +Configuring the software by hand +-------------------------------- + +First, generate a jconfig.h file. If you are moderately familiar with C, +the comments in jconfig.doc should be enough information to do this; just +copy jconfig.doc to jconfig.h and edit it appropriately. Otherwise, you may +prefer to use the ckconfig.c program. You will need to compile and execute +ckconfig.c by hand --- we hope you know at least enough to do that. +ckconfig.c may not compile the first try (in fact, the whole idea is for it +to fail if anything is going to). If you get compile errors, fix them by +editing ckconfig.c according to the directions given in ckconfig.c. Once +you get it to run, it will write a suitable jconfig.h file, and will also +print out some advice about which makefile to use. + +You may also want to look at the canned jconfig files, if there is one for a +system similar to yours. + +Second, select a makefile and copy it to Makefile (or whatever your system +uses as the standard makefile name). The most generic makefiles we provide +are + makefile.ansi: if your C compiler supports function prototypes + makefile.unix: if not. +(You have function prototypes if ckconfig.c put "#define HAVE_PROTOTYPES" +in jconfig.h.) You may want to start from one of the other makefiles if +there is one for a system similar to yours. + +Look over the selected Makefile and adjust options as needed. In particular +you may want to change the CC and CFLAGS definitions. For instance, if you +are using GCC, set CC=gcc. If you had to use any compiler switches to get +ckconfig.c to work, make sure the same switches are in CFLAGS. + +If you are on a system that doesn't use makefiles, you'll need to set up +project files (or whatever you do use) to compile all the source files and +link them into executable files cjpeg, djpeg, jpegtran, rdjpgcom, and wrjpgcom. +See the file lists in any of the makefiles to find out which files go into +each program. Note that the provided makefiles all make a "library" file +libjpeg first, but you don't have to do that if you don't want to; the file +lists identify which source files are actually needed for compression, +decompression, or both. As a last resort, you can make a batch script that +just compiles everything and links it all together; makefile.vms is an example +of this (it's for VMS systems that have no make-like utility). + +Here are comments about some specific configuration decisions you'll +need to make: + +Command line style +------------------ + +These programs can use a Unix-like command line style which supports +redirection and piping, like this: + cjpeg inputfile >outputfile + cjpeg outputfile + source program | cjpeg >outputfile +The simpler "two file" command line style is just + cjpeg inputfile outputfile +You may prefer the two-file style, particularly if you don't have pipes. + +You MUST use two-file style on any system that doesn't cope well with binary +data fed through stdin/stdout; this is true for some MS-DOS compilers, for +example. If you're not on a Unix system, it's safest to assume you need +two-file style. (But if your compiler provides either the Posix-standard +fdopen() library routine or a Microsoft-compatible setmode() routine, you +can safely use the Unix command line style, by defining USE_FDOPEN or +USE_SETMODE respectively.) + +To use the two-file style, make jconfig.h say "#define TWO_FILE_COMMANDLINE". + +Selecting a memory manager +-------------------------- + +The IJG code is capable of working on images that are too big to fit in main +memory; data is swapped out to temporary files as necessary. However, the +code to do this is rather system-dependent. We provide five different +memory managers: + +* jmemansi.c This version uses the ANSI-standard library routine tmpfile(), + which not all non-ANSI systems have. On some systems + tmpfile() may put the temporary file in a non-optimal + location; if you don't like what it does, use jmemname.c. + +* jmemname.c This version creates named temporary files. For anything + except a Unix machine, you'll need to configure the + select_file_name() routine appropriately; see the comments + near the head of jmemname.c. If you use this version, define + NEED_SIGNAL_CATCHER in jconfig.h to make sure the temp files + are removed if the program is aborted. + +* jmemnobs.c (That stands for No Backing Store :-).) This will compile on + almost any system, but it assumes you have enough main memory + or virtual memory to hold the biggest images you work with. + +* jmemdos.c This should be used with most 16-bit MS-DOS compilers. + See the system-specific notes about MS-DOS for more info. + IMPORTANT: if you use this, define USE_MSDOS_MEMMGR in + jconfig.h, and include the assembly file jmemdosa.asm in the + programs. The supplied makefiles and jconfig files for + 16-bit MS-DOS compilers already do both. + +* jmemmac.c Custom version for Apple Macintosh; see the system-specific + notes for Macintosh for more info. + +To use a particular memory manager, change the SYSDEPMEM variable in your +makefile to equal the corresponding object file name (for example, jmemansi.o +or jmemansi.obj for jmemansi.c). + +If you have plenty of (real or virtual) main memory, just use jmemnobs.c. +"Plenty" means about ten bytes for every pixel in the largest images +you plan to process, so a lot of systems don't meet this criterion. +If yours doesn't, try jmemansi.c first. If that doesn't compile, you'll have +to use jmemname.c; be sure to adjust select_file_name() for local conditions. +You may also need to change unlink() to remove() in close_backing_store(). + +Except with jmemnobs.c or jmemmac.c, you need to adjust the DEFAULT_MAX_MEM +setting to a reasonable value for your system (either by adding a #define for +DEFAULT_MAX_MEM to jconfig.h, or by adding a -D switch to the Makefile). +This value limits the amount of data space the program will attempt to +allocate. Code and static data space isn't counted, so the actual memory +needs for cjpeg or djpeg are typically 100 to 150Kb more than the max-memory +setting. Larger max-memory settings reduce the amount of I/O needed to +process a large image, but too large a value can result in "insufficient +memory" failures. On most Unix machines (and other systems with virtual +memory), just set DEFAULT_MAX_MEM to several million and forget it. At the +other end of the spectrum, for MS-DOS machines you probably can't go much +above 300K to 400K. (On MS-DOS the value refers to conventional memory only. +Extended/expanded memory is handled separately by jmemdos.c.) + + +BUILDING THE SOFTWARE +===================== + +Now you should be able to compile the software. Just say "make" (or +whatever's necessary to start the compilation). Have a cup of coffee. + +Here are some things that could go wrong: + +If your compiler complains about undefined structures, you should be able to +shut it up by putting "#define INCOMPLETE_TYPES_BROKEN" in jconfig.h. + +If you have trouble with missing system include files or inclusion of the +wrong ones, read jinclude.h. This shouldn't happen if you used configure +or ckconfig.c to set up jconfig.h. + +There are a fair number of routines that do not use all of their parameters; +some compilers will issue warnings about this, which you can ignore. There +are also a few configuration checks that may give "unreachable code" warnings. +Any other warning deserves investigation. + +If you don't have a getenv() library routine, define NO_GETENV. + +Also see the system-specific hints, below. + + +TESTING THE SOFTWARE +==================== + +As a quick test of functionality we've included a small sample image in +several forms: + testorig.jpg Starting point for the djpeg tests. + testimg.ppm The output of djpeg testorig.jpg + testimg.bmp The output of djpeg -bmp -colors 256 testorig.jpg + testimg.jpg The output of cjpeg testimg.ppm + testprog.jpg Progressive-mode equivalent of testorig.jpg. + testimgp.jpg The output of cjpeg -progressive -optimize testimg.ppm +(The first- and second-generation .jpg files aren't identical since JPEG is +lossy.) If you can generate duplicates of the testimg* files then you +probably have working programs. + +With most of the makefiles, "make test" will perform the necessary +comparisons. + +If you're using a makefile that doesn't provide the test option, run djpeg +and cjpeg by hand and compare the output files to testimg* with whatever +binary file comparison tool you have. The files should be bit-for-bit +identical. + +If the programs complain "MAX_ALLOC_CHUNK is wrong, please fix", then you +need to reduce MAX_ALLOC_CHUNK to a value that fits in type size_t. +Try adding "#define MAX_ALLOC_CHUNK 65520L" to jconfig.h. A less likely +configuration error is "ALIGN_TYPE is wrong, please fix": defining ALIGN_TYPE +as long should take care of that one. + +If the cjpeg test run fails with "Missing Huffman code table entry", it's a +good bet that you needed to define RIGHT_SHIFT_IS_UNSIGNED. Go back to the +configuration step and run ckconfig.c. (This is a good plan for any other +test failure, too.) + +If you are using Unix (one-file) command line style on a non-Unix system, +it's a good idea to check that binary I/O through stdin/stdout actually +works. You should get the same results from "djpeg out.ppm" +as from "djpeg -outfile out.ppm testorig.jpg". Note that the makefiles all +use the latter style and therefore do not exercise stdin/stdout! If this +check fails, try recompiling with USE_SETMODE or USE_FDOPEN defined. +If it still doesn't work, better use two-file style. + +If you chose a memory manager other than jmemnobs.c, you should test that +temporary-file usage works. Try "djpeg -bmp -colors 256 -max 0 testorig.jpg" +and make sure its output matches testimg.bmp. If you have any really large +images handy, try compressing them with -optimize and/or decompressing with +-colors 256 to make sure your DEFAULT_MAX_MEM setting is not too large. + +NOTE: this is far from an exhaustive test of the JPEG software; some modules, +such as 1-pass color quantization, are not exercised at all. It's just a +quick test to give you some confidence that you haven't missed something +major. + + +INSTALLING THE SOFTWARE +======================= + +Once you're done with the above steps, you can install the software by +copying the executable files (cjpeg, djpeg, jpegtran, rdjpgcom, and wrjpgcom) +to wherever you normally install programs. On Unix systems, you'll also want +to put the man pages (cjpeg.1, djpeg.1, jpegtran.1, rdjpgcom.1, wrjpgcom.1) +in the man-page directory. The pre-fab makefiles don't support this step +since there's such a wide variety of installation procedures on different +systems. + +If you generated a Makefile with the "configure" script, you can just say + make install +to install the programs and their man pages into the standard places. +(You'll probably need to be root to do this.) We recommend first saying + make -n install +to see where configure thought the files should go. You may need to edit +the Makefile, particularly if your system's conventions for man page +filenames don't match what configure expects. + +If you want to install the IJG library itself, for use in compiling other +programs besides ours, then you need to put the four include files + jpeglib.h jerror.h jconfig.h jmorecfg.h +into your include-file directory, and put the library file libjpeg.a +(extension may vary depending on system) wherever library files go. +If you generated a Makefile with "configure", it will do what it thinks +is the right thing if you say + make install-lib + + +OPTIONAL STUFF +============== + +Progress monitor: + +If you like, you can #define PROGRESS_REPORT (in jconfig.h) to enable display +of percent-done progress reports. The routine provided in cdjpeg.c merely +prints percentages to stderr, but you can customize it to do something +fancier. + +Utah RLE file format support: + +We distribute the software with support for RLE image files (Utah Raster +Toolkit format) disabled, because the RLE support won't compile without the +Utah library. If you have URT version 3.1 or later, you can enable RLE +support as follows: + 1. #define RLE_SUPPORTED in jconfig.h. + 2. Add a -I option to CFLAGS in the Makefile for the directory + containing the URT .h files (typically the "include" + subdirectory of the URT distribution). + 3. Add -L... -lrle to LDLIBS in the Makefile, where ... specifies + the directory containing the URT "librle.a" file (typically the + "lib" subdirectory of the URT distribution). + +Support for 12-bit-deep pixel data: + +The JPEG standard allows either 8-bit or 12-bit data precision. (For color, +this means 8 or 12 bits per channel, of course.) If you need to work with +deeper than 8-bit data, you can compile the IJG code for 12-bit operation. +To do so: + 1. In jmorecfg.h, define BITS_IN_JSAMPLE as 12 rather than 8. + 2. In jconfig.h, undefine BMP_SUPPORTED, RLE_SUPPORTED, and TARGA_SUPPORTED, + because the code for those formats doesn't handle 12-bit data and won't + even compile. (The PPM code does work, as explained below. The GIF + code works too; it scales 8-bit GIF data to and from 12-bit depth + automatically.) + 3. Compile. Don't expect "make test" to pass, since the supplied test + files are for 8-bit data. + +Currently, 12-bit support does not work on 16-bit-int machines. + +Note that a 12-bit version will not read 8-bit JPEG files, nor vice versa; +so you'll want to keep around a regular 8-bit compilation as well. +(Run-time selection of data depth, to allow a single copy that does both, +is possible but would probably slow things down considerably; it's very low +on our to-do list.) + +The PPM reader (rdppm.c) can read 12-bit data from either text-format or +binary-format PPM and PGM files. Binary-format PPM/PGM files which have a +maxval greater than 255 are assumed to use 2 bytes per sample, LSB first +(little-endian order). As of early 1995, 2-byte binary format is not +officially supported by the PBMPLUS library, but it is expected that a +future release of PBMPLUS will support it. Note that the PPM reader will +read files of any maxval regardless of the BITS_IN_JSAMPLE setting; incoming +data is automatically rescaled to either maxval=255 or maxval=4095 as +appropriate for the cjpeg bit depth. + +The PPM writer (wrppm.c) will normally write 2-byte binary PPM or PGM +format, maxval 4095, when compiled with BITS_IN_JSAMPLE=12. Since this +format is not yet widely supported, you can disable it by compiling wrppm.c +with PPM_NORAWWORD defined; then the data is scaled down to 8 bits to make a +standard 1-byte/sample PPM or PGM file. (Yes, this means still another copy +of djpeg to keep around. But hopefully you won't need it for very long. +Poskanzer's supposed to get that new PBMPLUS release out Real Soon Now.) + +Of course, if you are working with 12-bit data, you probably have it stored +in some other, nonstandard format. In that case you'll probably want to +write your own I/O modules to read and write your format. + +Note that a 12-bit version of cjpeg always runs in "-optimize" mode, in +order to generate valid Huffman tables. This is necessary because our +default Huffman tables only cover 8-bit data. + +Removing code: + +If you need to make a smaller version of the JPEG software, some optional +functions can be removed at compile time. See the xxx_SUPPORTED #defines in +jconfig.h and jmorecfg.h. If at all possible, we recommend that you leave in +decoder support for all valid JPEG files, to ensure that you can read anyone's +output. Taking out support for image file formats that you don't use is the +most painless way to make the programs smaller. Another possibility is to +remove some of the DCT methods: in particular, the "IFAST" method may not be +enough faster than the others to be worth keeping on your machine. (If you +do remove ISLOW or IFAST, be sure to redefine JDCT_DEFAULT or JDCT_FASTEST +to a supported method, by adding a #define in jconfig.h.) + + +OPTIMIZATION +============ + +Unless you own a Cray, you'll probably be interested in making the JPEG +software go as fast as possible. This section covers some machine-dependent +optimizations you may want to try. We suggest that before trying any of +this, you first get the basic installation to pass the self-test step. +Repeat the self-test after any optimization to make sure that you haven't +broken anything. + +The integer DCT routines perform a lot of multiplications. These +multiplications must yield 32-bit results, but none of their input values +are more than 16 bits wide. On many machines, notably the 680x0 and 80x86 +CPUs, a 16x16=>32 bit multiply instruction is faster than a full 32x32=>32 +bit multiply. Unfortunately there is no portable way to specify such a +multiplication in C, but some compilers can generate one when you use the +right combination of casts. See the MULTIPLYxxx macro definitions in +jdct.h. If your compiler makes "int" be 32 bits and "short" be 16 bits, +defining SHORTxSHORT_32 is fairly likely to work. When experimenting with +alternate definitions, be sure to test not only whether the code still works +(use the self-test), but also whether it is actually faster --- on some +compilers, alternate definitions may compute the right answer, yet be slower +than the default. Timing cjpeg on a large PGM (grayscale) input file is the +best way to check this, as the DCT will be the largest fraction of the runtime +in that mode. (Note: some of the distributed compiler-specific jconfig files +already contain #define switches to select appropriate MULTIPLYxxx +definitions.) + +If your machine has sufficiently fast floating point hardware, you may find +that the float DCT method is faster than the integer DCT methods, even +after tweaking the integer multiply macros. In that case you may want to +make the float DCT be the default method. (The only objection to this is +that float DCT results may vary slightly across machines.) To do that, add +"#define JDCT_DEFAULT JDCT_FLOAT" to jconfig.h. Even if you don't change +the default, you should redefine JDCT_FASTEST, which is the method selected +by djpeg's -fast switch. Don't forget to update the documentation files +(usage.doc and/or cjpeg.1, djpeg.1) to agree with what you've done. + +If access to "short" arrays is slow on your machine, it may be a win to +define type JCOEF as int rather than short. This will cost a good deal of +memory though, particularly in some multi-pass modes, so don't do it unless +you have memory to burn and short is REALLY slow. + +If your compiler can compile function calls in-line, make sure the INLINE +macro in jmorecfg.h is defined as the keyword that marks a function +inline-able. Some compilers have a switch that tells the compiler to inline +any function it thinks is profitable (e.g., -finline-functions for gcc). +Enabling such a switch is likely to make the compiled code bigger but faster. + +In general, it's worth trying the maximum optimization level of your compiler, +and experimenting with any optional optimizations such as loop unrolling. +(Unfortunately, far too many compilers have optimizer bugs ... be prepared to +back off if the code fails self-test.) If you do any experimentation along +these lines, please report the optimal settings to jpeg-info@uunet.uu.net so +we can mention them in future releases. Be sure to specify your machine and +compiler version. + + +HINTS FOR SPECIFIC SYSTEMS +========================== + +We welcome reports on changes needed for systems not mentioned here. Submit +'em to jpeg-info@uunet.uu.net. Also, if configure or ckconfig.c is wrong +about how to configure the JPEG software for your system, please let us know. + + +Acorn RISC OS: + +(Thanks to Simon Middleton for these hints on compiling with Desktop C.) +After renaming the files according to Acorn conventions, take a copy of +makefile.ansi, change all occurrences of 'libjpeg.a' to 'libjpeg.o' and +change these definitions as indicated: + +CFLAGS= -throwback -IC: -Wn +LDLIBS=C:o.Stubs +SYSDEPMEM=jmemansi.o +LN=Link +AR=LibFile -c -o + +Also add a new line '.c.o:; $(cc) $< $(cflags) -c -o $@'. Remove the +lines '$(RM) libjpeg.o' and '$(AR2) libjpeg.o' and the 'jconfig.h' +dependency section. + +Copy jconfig.doc to jconfig.h. Edit jconfig.h to define TWO_FILE_COMMANDLINE +and CHAR_IS_UNSIGNED. + +Run the makefile using !AMU not !Make. If you want to use the 'clean' and +'test' makefile entries then you will have to fiddle with the syntax a bit +and rename the test files. + + +Amiga: + +SAS C 6.50 reportedly is too buggy to compile the IJG code properly. +A patch to update to 6.51 is available from SAS or AmiNet FTP sites. + +The supplied config files are set up to use jmemname.c as the memory +manager, with temporary files being created on the device named by +"JPEGTMP:". + + +Atari ST/STE/TT: + +Copy the project files makcjpeg.st, makdjpeg.st, maktjpeg.st, and makljpeg.st +to cjpeg.prj, djpeg.prj, jpegtran.prj, and libjpeg.prj respectively. The +project files should work as-is with Pure C. For Turbo C, change library +filenames "pc..." to "tc..." in each project file. Note that libjpeg.prj +selects jmemansi.c as the recommended memory manager. You'll probably want to +adjust the DEFAULT_MAX_MEM setting --- you want it to be a couple hundred K +less than your normal free memory. Put "#define DEFAULT_MAX_MEM nnnn" into +jconfig.h to do this. + +To use the 68881/68882 coprocessor for the floating point DCT, add the +compiler option "-8" to the project files and replace pcfltlib.lib with +pc881lib.lib in cjpeg.prj and djpeg.prj. Or if you don't have a +coprocessor, you may prefer to remove the float DCT code by undefining +DCT_FLOAT_SUPPORTED in jmorecfg.h (since without a coprocessor, the float +code will be too slow to be useful). In that case, you can delete +pcfltlib.lib from the project files. + +Note that you must make libjpeg.lib before making cjpeg.ttp, djpeg.ttp, +or jpegtran.ttp. You'll have to perform the self-test by hand. + +We haven't bothered to include project files for rdjpgcom and wrjpgcom. +Those source files should just be compiled by themselves; they don't +depend on the JPEG library. + +There is a bug in some older versions of the Turbo C library which causes the +space used by temporary files created with "tmpfile()" not to be freed after +an abnormal program exit. If you check your disk afterwards, you will find +cluster chains that are allocated but not used by a file. This should not +happen in cjpeg/djpeg/jpegtran, since we enable a signal catcher to explicitly +close temp files before exiting. But if you use the JPEG library with your +own code, be sure to supply a signal catcher, or else use a different +system-dependent memory manager. + + +Cray: + +Should you be so fortunate as to be running JPEG on a Cray YMP, there is a +compiler bug in old versions of Cray's Standard C (prior to 3.1). If you +still have an old compiler, you'll need to insert a line reading +"#pragma novector" just before the loop + for (i = 1; i <= (int) htbl->bits[l]; i++) + huffsize[p++] = (char) l; +in fix_huff_tbl (in V5beta1, line 204 of jchuff.c and line 176 of jdhuff.c). +[This bug may or may not still occur with the current IJG code, but it's +probably a dead issue anyway...] + + +HP-UX: + +If you have HP-UX 7.05 or later with the "software development" C compiler, +you should run the compiler in ANSI mode. If using the configure script, +say + ./configure CC='cc -Aa' +(or -Ae if you prefer). If configuring by hand, use makefile.ansi and add +"-Aa" to the CFLAGS line in the makefile. + +If you have a pre-7.05 system, or if you are using the non-ANSI C compiler +delivered with a minimum HP-UX system, then you must use makefile.unix +(and do NOT add -Aa); or just run configure without the CC option. + +On HP 9000 series 800 machines, the HP C compiler is buggy in revisions prior +to A.08.07. If you get complaints about "not a typedef name", you'll have to +use makefile.unix, or run configure without the CC option. + + +Macintosh, generic comments: + +The supplied user-interface files (cjpeg.c, djpeg.c, etc) are set up to +provide a Unix-style command line interface. You can use this interface on +the Mac by means of the ccommand() library routine provided by Metrowerks +CodeWarrior or Think C. This is only appropriate for testing the library, +however; to make a user-friendly equivalent of cjpeg/djpeg you'd really want +to develop a Mac-style user interface. There isn't a complete example +available at the moment, but there are some helpful starting points: +1. Sam Bushell's free "To JPEG" applet provides drag-and-drop conversion to +JPEG under System 7 and later. This only illustrates how to use the +compression half of the library, but it does a very nice job of that part. +The CodeWarrior source code is available from http://www.pobox.com/~jsam. +2. Jim Brunner prepared a Mac-style user interface for both compression and +decompression. Unfortunately, it hasn't been updated since IJG v4, and +the library's API has changed considerably since then. Still it may be of +some help, particularly as a guide to compiling the IJG code under Think C. +Jim's code is available from the Info-Mac archives, at sumex-aim.stanford.edu +or mirrors thereof; see file /info-mac/dev/src/jpeg-convert-c.hqx. + +jmemmac.c is the recommended memory manager back end for Macintosh. It uses +NewPtr/DisposePtr instead of malloc/free, and has a Mac-specific +implementation of jpeg_mem_available(). It also creates temporary files that +follow Mac conventions. (That part of the code relies on System-7-or-later OS +functions. See the comments in jmemmac.c if you need to run it on System 6.) +NOTE that USE_MAC_MEMMGR must be defined in jconfig.h to use jmemmac.c. + +You can also use jmemnobs.c, if you don't care about handling images larger +than available memory. If you use any memory manager back end other than +jmemmac.c, we recommend replacing "malloc" and "free" by "NewPtr" and +"DisposePtr", because Mac C libraries often have peculiar implementations of +malloc/free. (For instance, free() may not return the freed space to the +Mac Memory Manager. This is undesirable for the IJG code because jmemmgr.c +already clumps space requests.) + + +Macintosh, Metrowerks CodeWarrior: + +The Unix-command-line-style interface can be used by defining USE_CCOMMAND. +You'll also need to define TWO_FILE_COMMANDLINE to avoid stdin/stdout. +This means that when using the cjpeg/djpeg programs, you'll have to type the +input and output file names in the "Arguments" text-edit box, rather than +using the file radio buttons. (Perhaps USE_FDOPEN or USE_SETMODE would +eliminate the problem, but I haven't heard from anyone who's tried it.) + +On 680x0 Macs, Metrowerks defines type "double" as a 10-byte IEEE extended +float. jmemmgr.c won't like this: it wants sizeof(ALIGN_TYPE) to be a power +of 2. Add "#define ALIGN_TYPE long" to jconfig.h to eliminate the complaint. + +The supplied configuration file jconfig.mac can be used for your jconfig.h; +it includes all the recommended symbol definitions. If you have AppleScript +installed, you can run the supplied script makeproj.mac to create CodeWarrior +project files for the library and the testbed applications, then build the +library and applications. (Thanks to Dan Sears and Don Agro for this nifty +hack, which saves us from trying to maintain CodeWarrior project files as part +of the IJG distribution...) + + +Macintosh, Think C: + +The documentation in Jim Brunner's "JPEG Convert" source code (see above) +includes detailed build instructions for Think C; it's probably somewhat +out of date for the current release, but may be helpful. + +If you want to build the minimal command line version, proceed as follows. +You'll have to prepare project files for the programs; we don't include any +in the distribution since they are not text files. Use the file lists in +any of the supplied makefiles as a guide. Also add the ANSI and Unix C +libraries in a separate segment. You may need to divide the JPEG files into +more than one segment; we recommend dividing compression and decompression +modules. Define USE_CCOMMAND in jconfig.h so that the ccommand() routine is +called. You must also define TWO_FILE_COMMANDLINE because stdin/stdout +don't handle binary data correctly. + +On 680x0 Macs, Think C defines type "double" as a 12-byte IEEE extended float. +jmemmgr.c won't like this: it wants sizeof(ALIGN_TYPE) to be a power of 2. +Add "#define ALIGN_TYPE long" to jconfig.h to eliminate the complaint. + +jconfig.mac should work as a jconfig.h configuration file for Think C, +but the makeproj.mac AppleScript script is specific to CodeWarrior. Sorry. + + +MIPS R3000: + +MIPS's cc version 1.31 has a rather nasty optimization bug. Don't use -O +if you have that compiler version. (Use "cc -V" to check the version.) +Note that the R3000 chip is found in workstations from DEC and others. + + +MS-DOS, generic comments for 16-bit compilers: + +The IJG code is designed to work well in 80x86 "small" or "medium" memory +models (i.e., data pointers are 16 bits unless explicitly declared "far"; +code pointers can be either size). You may be able to use small model to +compile cjpeg or djpeg by itself, but you will probably have to use medium +model for any larger application. This won't make much difference in +performance. You *will* take a noticeable performance hit if you use a +large-data memory model, and you should avoid "huge" model if at all +possible. Be sure that NEED_FAR_POINTERS is defined in jconfig.h if you use +a small-data memory model; be sure it is NOT defined if you use a large-data +model. (The supplied makefiles and jconfig files for Borland and Microsoft C +compile in medium model and define NEED_FAR_POINTERS.) + +The DOS-specific memory manager, jmemdos.c, should be used if possible. +It needs some assembly-code routines which are in jmemdosa.asm; make sure +your makefile assembles that file and includes it in the library. If you +don't have a suitable assembler, you can get pre-assembled object files for +jmemdosa by FTP from ftp.uu.net:/graphics/jpeg/jdosaobj.zip. (DOS-oriented +distributions of the IJG source code often include these object files.) + +When using jmemdos.c, jconfig.h must define USE_MSDOS_MEMMGR and must set +MAX_ALLOC_CHUNK to less than 64K (65520L is a typical value). If your +C library's far-heap malloc() can't allocate blocks that large, reduce +MAX_ALLOC_CHUNK to whatever it can handle. + +If you can't use jmemdos.c for some reason --- for example, because you +don't have an assembler to assemble jmemdosa.asm --- you'll have to fall +back to jmemansi.c or jmemname.c. You'll probably still need to set +MAX_ALLOC_CHUNK in jconfig.h, because most DOS C libraries won't malloc() +more than 64K at a time. IMPORTANT: if you use jmemansi.c or jmemname.c, +you will have to compile in a large-data memory model in order to get the +right stdio library. Too bad. + +wrjpgcom needs to be compiled in large model, because it malloc()s a 64KB +work area to hold the comment text. If your C library's malloc can't +handle that, reduce MAX_COM_LENGTH as necessary in wrjpgcom.c. + +Most MS-DOS compilers treat stdin/stdout as text files, so you must use +two-file command line style. But if your compiler has either fdopen() or +setmode(), you can use one-file style if you like. To do this, define +USE_SETMODE or USE_FDOPEN so that stdin/stdout will be set to binary mode. +(USE_SETMODE seems to work with more DOS compilers than USE_FDOPEN.) You +should test that I/O through stdin/stdout produces the same results as I/O +to explicitly named files... the "make test" procedures in the supplied +makefiles do NOT use stdin/stdout. + + +MS-DOS, generic comments for 32-bit compilers: + +None of the above comments about memory models apply if you are using a +32-bit flat-memory-space environment, such as DJGPP or Watcom C. (And you +should use one if you have it, as performance will be much better than +8086-compatible code!) For flat-memory-space compilers, do NOT define +NEED_FAR_POINTERS, and do NOT use jmemdos.c. Use jmemnobs.c if the +environment supplies adequate virtual memory, otherwise use jmemansi.c or +jmemname.c. + +You'll still need to be careful about binary I/O through stdin/stdout. +See the last paragraph of the previous section. + + +MS-DOS, Borland C: + +Be sure to convert all the source files to DOS text format (CR/LF newlines). +Although Borland C will often work OK with unmodified Unix (LF newlines) +source files, sometimes it will give bogus compile errors. +"Illegal character '#'" is the most common such error. (This is true with +Borland C 3.1, but perhaps is fixed in newer releases.) + +If you want one-file command line style, just undefine TWO_FILE_COMMANDLINE. +jconfig.bcc already includes #define USE_SETMODE to make this work. +(fdopen does not work correctly.) + + +MS-DOS, Microsoft C: + +makefile.mc6 works with Microsoft C, DOS Visual C++, etc. It should only +be used if you want to build a 16-bit (small or medium memory model) program. + +If you want one-file command line style, just undefine TWO_FILE_COMMANDLINE. +jconfig.mc6 already includes #define USE_SETMODE to make this work. +(fdopen does not work correctly.) + +Note that this makefile assumes that the working copy of itself is called +"makefile". If you want to call it something else, say "makefile.mak", +be sure to adjust the dependency line that reads "$(RFILE) : makefile". +Otherwise the make will fail because it doesn't know how to create "makefile". +Worse, some releases of Microsoft's make utilities give an incorrect error +message in this situation. + +Old versions of MS C fail with an "out of macro expansion space" error +because they can't cope with the macro TRACEMS8 (defined in jerror.h). +If this happens to you, the easiest solution is to change TRACEMS8 to +expand to nothing. You'll lose the ability to dump out JPEG coefficient +tables with djpeg -debug -debug, but at least you can compile. + +Original MS C 6.0 is very buggy; it compiles incorrect code unless you turn +off optimization entirely (remove -O from CFLAGS). 6.00A is better, but it +still generates bad code if you enable loop optimizations (-Ol or -Ox). + +MS C 8.0 crashes when compiling jquant1.c with optimization switch /Oo ... +which is on by default. To work around this bug, compile that one file +with /Oo-. + + +Microsoft Windows (all versions), generic comments: + +Some Windows system include files define typedef boolean as "unsigned char". +The IJG code also defines typedef boolean, but we make it "int" by default. +This doesn't affect the IJG programs because we don't import those Windows +include files. But if you use the JPEG library in your own program, and some +of your program's files import one definition of boolean while some import the +other, you can get all sorts of mysterious problems. A good preventive step +is to make the IJG library use "unsigned char" for boolean. To do that, +add something like this to your jconfig.h file: + /* Define "boolean" as unsigned char, not int, per Windows custom */ + #ifndef __RPCNDR_H__ /* don't conflict if rpcndr.h already read */ + typedef unsigned char boolean; + #endif + #define HAVE_BOOLEAN /* prevent jmorecfg.h from redefining it */ +(This is already in jconfig.vc, by the way.) + +windef.h contains the declarations + #define far + #define FAR far +Since jmorecfg.h tries to define FAR as empty, you may get a compiler +warning if you include both jpeglib.h and windef.h (which windows.h +includes). To suppress the warning, you can put "#ifndef FAR"/"#endif" +around the line "#define FAR" in jmorecfg.h. + +When using the library in a Windows application, you will almost certainly +want to modify or replace the error handler module jerror.c, since our +default error handler does a couple of inappropriate things: + 1. it tries to write error and warning messages on stderr; + 2. in event of a fatal error, it exits by calling exit(). + +A simple stopgap solution for problem 1 is to replace the line + fprintf(stderr, "%s\n", buffer); +(in output_message in jerror.c) with + MessageBox(GetActiveWindow(),buffer,"JPEG Error",MB_OK|MB_ICONERROR); +It's highly recommended that you at least do that much, since otherwise +error messages will disappear into nowhere. (Beginning with IJG v6b, this +code is already present in jerror.c; just define USE_WINDOWS_MESSAGEBOX in +jconfig.h to enable it.) + +The proper solution for problem 2 is to return control to your calling +application after a library error. This can be done with the setjmp/longjmp +technique discussed in libjpeg.doc and illustrated in example.c. (NOTE: +some older Windows C compilers provide versions of setjmp/longjmp that +don't actually work under Windows. You may need to use the Windows system +functions Catch and Throw instead.) + +The recommended memory manager under Windows is jmemnobs.c; in other words, +let Windows do any virtual memory management needed. You should NOT use +jmemdos.c nor jmemdosa.asm under Windows. + +For Windows 3.1, we recommend compiling in medium or large memory model; +for newer Windows versions, use a 32-bit flat memory model. (See the MS-DOS +sections above for more info about memory models.) In the 16-bit memory +models only, you'll need to put + #define MAX_ALLOC_CHUNK 65520L /* Maximum request to malloc() */ +into jconfig.h to limit allocation chunks to 64Kb. (Without that, you'd +have to use huge memory model, which slows things down unnecessarily.) +jmemnobs.c works without modification in large or flat memory models, but to +use medium model, you need to modify its jpeg_get_large and jpeg_free_large +routines to allocate far memory. In any case, you might like to replace +its calls to malloc and free with direct calls on Windows memory allocation +functions. + +You may also want to modify jdatasrc.c and jdatadst.c to use Windows file +operations rather than fread/fwrite. This is only necessary if your C +compiler doesn't provide a competent implementation of C stdio functions. + +You might want to tweak the RGB_xxx macros in jmorecfg.h so that the library +will accept or deliver color pixels in BGR sample order, not RGB; BGR order +is usually more convenient under Windows. Note that this change will break +the sample applications cjpeg/djpeg, but the library itself works fine. + + +Many people want to convert the IJG library into a DLL. This is reasonably +straightforward, but watch out for the following: + + 1. Don't try to compile as a DLL in small or medium memory model; use +large model, or even better, 32-bit flat model. Many places in the IJG code +assume the address of a local variable is an ordinary (not FAR) pointer; +that isn't true in a medium-model DLL. + + 2. Microsoft C cannot pass file pointers between applications and DLLs. +(See Microsoft Knowledge Base, PSS ID Number Q50336.) So jdatasrc.c and +jdatadst.c don't work if you open a file in your application and then pass +the pointer to the DLL. One workaround is to make jdatasrc.c/jdatadst.c +part of your main application rather than part of the DLL. + + 3. You'll probably need to modify the macros GLOBAL() and EXTERN() to +attach suitable linkage keywords to the exported routine names. Similarly, +you'll want to modify METHODDEF() and JMETHOD() to ensure function pointers +are declared in a way that lets application routines be called back through +the function pointers. These macros are in jmorecfg.h. Typical definitions +for a 16-bit DLL are: + #define GLOBAL(type) type _far _pascal _loadds _export + #define EXTERN(type) extern type _far _pascal _loadds + #define METHODDEF(type) static type _far _pascal + #define JMETHOD(type,methodname,arglist) \ + type (_far _pascal *methodname) arglist +For a 32-bit DLL you may want something like + #define GLOBAL(type) __declspec(dllexport) type + #define EXTERN(type) extern __declspec(dllexport) type +Although not all the GLOBAL routines are actually intended to be called by +the application, the performance cost of making them all DLL entry points is +negligible. + +The unmodified IJG library presents a very C-specific application interface, +so the resulting DLL is only usable from C or C++ applications. There has +been some talk of writing wrapper code that would present a simpler interface +usable from other languages, such as Visual Basic. This is on our to-do list +but hasn't been very high priority --- any volunteers out there? + + +Microsoft Windows, Borland C: + +The provided jconfig.bcc should work OK in a 32-bit Windows environment, +but you'll need to tweak it in a 16-bit environment (you'd need to define +NEED_FAR_POINTERS and MAX_ALLOC_CHUNK). Beware that makefile.bcc will need +alteration if you want to use it for Windows --- in particular, you should +use jmemnobs.c not jmemdos.c under Windows. + +Borland C++ 4.5 fails with an internal compiler error when trying to compile +jdmerge.c in 32-bit mode. If enough people complain, perhaps Borland will fix +it. In the meantime, the simplest known workaround is to add a redundant +definition of the variable range_limit in h2v1_merged_upsample(), at the head +of the block that handles odd image width (about line 268 in v6 jdmerge.c): + /* If image width is odd, do the last output column separately */ + if (cinfo->output_width & 1) { + register JSAMPLE * range_limit = cinfo->sample_range_limit; /* ADD THIS */ + cb = GETJSAMPLE(*inptr1); +Pretty bizarre, especially since the very similar routine h2v2_merged_upsample +doesn't trigger the bug. +Recent reports suggest that this bug does not occur with "bcc32a" (the +Pentium-optimized version of the compiler). + +Another report from a user of Borland C 4.5 was that incorrect code (leading +to a color shift in processed images) was produced if any of the following +optimization switch combinations were used: + -Ot -Og + -Ot -Op + -Ot -Om +So try backing off on optimization if you see such a problem. (Are there +several different releases all numbered "4.5"??) + + +Microsoft Windows, Microsoft Visual C++: + +jconfig.vc should work OK with any Microsoft compiler for a 32-bit memory +model. makefile.vc is intended for command-line use. (If you are using +the Developer Studio environment, you may prefer the DevStudio project +files; see below.) + +Some users feel that it's easier to call the library from C++ code if you +force VC++ to treat the library as C++ code, which you can do by renaming +all the *.c files to *.cpp (and adjusting the makefile to match). This +avoids the need to put extern "C" { ... } around #include "jpeglib.h" in +your C++ application. + + +Microsoft Windows, Microsoft Developer Studio: + +We include makefiles that should work as project files in DevStudio 4.2 or +later. There is a library makefile that builds the IJG library as a static +Win32 library, and an application makefile that builds the sample applications +as Win32 console applications. (Even if you only want the library, we +recommend building the applications so that you can run the self-test.) + +To use: +1. Copy jconfig.vc to jconfig.h, makelib.ds to jpeg.mak, and + makeapps.ds to apps.mak. (Note that the renaming is critical!) +2. Click on the .mak files to construct project workspaces. + (If you are using DevStudio more recent than 4.2, you'll probably + get a message saying that the makefiles are being updated.) +3. Build the library project, then the applications project. +4. Move the application .exe files from `app`\Release to an + appropriate location on your path. +5. To perform the self-test, execute the command line + NMAKE /f makefile.vc test + + +OS/2, Borland C++: + +Watch out for optimization bugs in older Borland compilers; you may need +to back off the optimization switch settings. See the comments in +makefile.bcc. + + +SGI: + +On some SGI systems, you may need to set "AR2= ar -ts" in the Makefile. +If you are using configure, you can do this by saying + ./configure RANLIB='ar -ts' +This change is not needed on all SGIs. Use it only if the make fails at the +stage of linking the completed programs. + +On the MIPS R4000 architecture (Indy, etc.), the compiler option "-mips2" +reportedly speeds up the float DCT method substantially, enough to make it +faster than the default int method (but still slower than the fast int +method). If you use -mips2, you may want to alter the default DCT method to +be float. To do this, put "#define JDCT_DEFAULT JDCT_FLOAT" in jconfig.h. + + +VMS: + +On an Alpha/VMS system with MMS, be sure to use the "/Marco=Alpha=1" +qualifier with MMS when building the JPEG package. + +VAX/VMS v5.5-1 may have problems with the test step of the build procedure +reporting differences when it compares the original and test images. If the +error points to the last block of the files, it is most likely bogus and may +be safely ignored. It seems to be because the files are Stream_LF and +Backup/Compare has difficulty with the (presumably) null padded files. +This problem was not observed on VAX/VMS v6.1 or AXP/VMS v6.1. diff --git a/gdcm/Utilities/gdcmjpeg/jcapimin.c b/gdcm/Utilities/gdcmjpeg/jcapimin.c new file mode 100644 index 0000000..3053a69 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jcapimin.c @@ -0,0 +1,280 @@ +/* + * jcapimin.c + * + * Copyright (C) 1994-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains application interface code for the compression half + * of the JPEG library. These are the "minimum" API routines that may be + * needed in either the normal full-compression case or the transcoding-only + * case. + * + * Most of the routines intended to be called directly by an application + * are in this file or in jcapistd.c. But also see jcparam.c for + * parameter-setup helper routines, jcomapi.c for routines shared by + * compression and decompression, and jctrans.c for the transcoding case. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * Initialization of a JPEG compression object. + * The error manager must already be set up (in case memory manager fails). + */ + +GLOBAL(void) +jpeg_CreateCompress (j_compress_ptr cinfo, int version, size_t structsize) +{ + int i; + + /* Guard against version mismatches between library and caller. */ + cinfo->mem = NULL; /* so jpeg_destroy knows mem mgr not called */ + if (version != JPEG_LIB_VERSION) + ERREXIT2(cinfo, JERR_BAD_LIB_VERSION, JPEG_LIB_VERSION, version); + if (structsize != SIZEOF(struct jpeg_compress_struct)) + ERREXIT2(cinfo, JERR_BAD_STRUCT_SIZE, + (int) SIZEOF(struct jpeg_compress_struct), (int) structsize); + + /* For debugging purposes, we zero the whole master structure. + * But the application has already set the err pointer, and may have set + * client_data, so we have to save and restore those fields. + * Note: if application hasn't set client_data, tools like Purify may + * complain here. + */ + { + struct jpeg_error_mgr * err = cinfo->err; + void * client_data = cinfo->client_data; /* ignore Purify complaint here */ + MEMZERO(cinfo, SIZEOF(struct jpeg_compress_struct)); + cinfo->err = err; + cinfo->client_data = client_data; + } + cinfo->is_decompressor = FALSE; + + /* Initialize a memory manager instance for this object */ + jinit_memory_mgr((j_common_ptr) cinfo); + + /* Zero out pointers to permanent structures. */ + cinfo->progress = NULL; + cinfo->dest = NULL; + + cinfo->comp_info = NULL; + + for (i = 0; i < NUM_QUANT_TBLS; i++) + cinfo->quant_tbl_ptrs[i] = NULL; + + for (i = 0; i < NUM_HUFF_TBLS; i++) { + cinfo->dc_huff_tbl_ptrs[i] = NULL; + cinfo->ac_huff_tbl_ptrs[i] = NULL; + } + + cinfo->script_space = NULL; + + cinfo->input_gamma = 1.0; /* in case application forgets */ + + /* OK, I'm ready */ + cinfo->global_state = CSTATE_START; +} + + +/* + * Destruction of a JPEG compression object + */ + +GLOBAL(void) +jpeg_destroy_compress (j_compress_ptr cinfo) +{ + jpeg_destroy((j_common_ptr) cinfo); /* use common routine */ +} + + +/* + * Abort processing of a JPEG compression operation, + * but don't destroy the object itself. + */ + +GLOBAL(void) +jpeg_abort_compress (j_compress_ptr cinfo) +{ + jpeg_abort((j_common_ptr) cinfo); /* use common routine */ +} + + +/* + * Forcibly suppress or un-suppress all quantization and Huffman tables. + * Marks all currently defined tables as already written (if suppress) + * or not written (if !suppress). This will control whether they get emitted + * by a subsequent jpeg_start_compress call. + * + * This routine is exported for use by applications that want to produce + * abbreviated JPEG datastreams. It logically belongs in jcparam.c, but + * since it is called by jpeg_start_compress, we put it here --- otherwise + * jcparam.o would be linked whether the application used it or not. + */ + +GLOBAL(void) +jpeg_suppress_tables (j_compress_ptr cinfo, boolean suppress) +{ + int i; + JQUANT_TBL * qtbl; + JHUFF_TBL * htbl; + + for (i = 0; i < NUM_QUANT_TBLS; i++) { + if ((qtbl = cinfo->quant_tbl_ptrs[i]) != NULL) + qtbl->sent_table = suppress; + } + + for (i = 0; i < NUM_HUFF_TBLS; i++) { + if ((htbl = cinfo->dc_huff_tbl_ptrs[i]) != NULL) + htbl->sent_table = suppress; + if ((htbl = cinfo->ac_huff_tbl_ptrs[i]) != NULL) + htbl->sent_table = suppress; + } +} + + +/* + * Finish JPEG compression. + * + * If a multipass operating mode was selected, this may do a great deal of + * work including most of the actual output. + */ + +GLOBAL(void) +jpeg_finish_compress (j_compress_ptr cinfo) +{ + JDIMENSION iMCU_row; + + if (cinfo->global_state == CSTATE_SCANNING || + cinfo->global_state == CSTATE_RAW_OK) { + /* Terminate first pass */ + if (cinfo->next_scanline < cinfo->image_height) + ERREXIT(cinfo, JERR_TOO_LITTLE_DATA); + (*cinfo->master->finish_pass) (cinfo); + } else if (cinfo->global_state != CSTATE_WRCOEFS) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + /* Perform any remaining passes */ + while (! cinfo->master->is_last_pass) { + (*cinfo->master->prepare_for_pass) (cinfo); + for (iMCU_row = 0; iMCU_row < cinfo->total_iMCU_rows; iMCU_row++) { + if (cinfo->progress != NULL) { + cinfo->progress->pass_counter = (long) iMCU_row; + cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows; + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + } + /* We bypass the main controller and invoke coef controller directly; + * all work is being done from the coefficient buffer. + */ + if (! (*cinfo->codec->compress_data) (cinfo, (JSAMPIMAGE) NULL)) + ERREXIT(cinfo, JERR_CANT_SUSPEND); + } + (*cinfo->master->finish_pass) (cinfo); + } + /* Write EOI, do final cleanup */ + (*cinfo->marker->write_file_trailer) (cinfo); + (*cinfo->dest->term_destination) (cinfo); + /* We can use jpeg_abort to release memory and reset global_state */ + jpeg_abort((j_common_ptr) cinfo); +} + + +/* + * Write a special marker. + * This is only recommended for writing COM or APPn markers. + * Must be called after jpeg_start_compress() and before + * first call to jpeg_write_scanlines() or jpeg_write_raw_data(). + */ + +GLOBAL(void) +jpeg_write_marker (j_compress_ptr cinfo, int marker, + const JOCTET *dataptr, unsigned int datalen) +{ + JMETHOD(void, write_marker_byte, (j_compress_ptr info, int val)); + + if (cinfo->next_scanline != 0 || + (cinfo->global_state != CSTATE_SCANNING && + cinfo->global_state != CSTATE_RAW_OK && + cinfo->global_state != CSTATE_WRCOEFS)) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + (*cinfo->marker->write_marker_header) (cinfo, marker, datalen); + write_marker_byte = cinfo->marker->write_marker_byte; /* copy for speed */ + while (datalen--) { + (*write_marker_byte) (cinfo, *dataptr); + dataptr++; + } +} + +/* Same, but piecemeal. */ + +GLOBAL(void) +jpeg_write_m_header (j_compress_ptr cinfo, int marker, unsigned int datalen) +{ + if (cinfo->next_scanline != 0 || + (cinfo->global_state != CSTATE_SCANNING && + cinfo->global_state != CSTATE_RAW_OK && + cinfo->global_state != CSTATE_WRCOEFS)) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + (*cinfo->marker->write_marker_header) (cinfo, marker, datalen); +} + +GLOBAL(void) +jpeg_write_m_byte (j_compress_ptr cinfo, int val) +{ + (*cinfo->marker->write_marker_byte) (cinfo, val); +} + + +/* + * Alternate compression function: just write an abbreviated table file. + * Before calling this, all parameters and a data destination must be set up. + * + * To produce a pair of files containing abbreviated tables and abbreviated + * image data, one would proceed as follows: + * + * initialize JPEG object + * set JPEG parameters + * set destination to table file + * jpeg_write_tables(cinfo); + * set destination to image file + * jpeg_start_compress(cinfo, FALSE); + * write data... + * jpeg_finish_compress(cinfo); + * + * jpeg_write_tables has the side effect of marking all tables written + * (same as jpeg_suppress_tables(..., TRUE)). Thus a subsequent start_compress + * will not re-emit the tables unless it is passed write_all_tables=TRUE. + */ + +GLOBAL(void) +jpeg_write_tables (j_compress_ptr cinfo) +{ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + /* (Re)initialize error mgr and destination modules */ + (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo); + (*cinfo->dest->init_destination) (cinfo); + /* Initialize the marker writer ... bit of a crock to do it here. */ + jinit_marker_writer(cinfo); + /* Write them tables! */ + (*cinfo->marker->write_tables_only) (cinfo); + /* And clean up. */ + (*cinfo->dest->term_destination) (cinfo); + /* + * In library releases up through v6a, we called jpeg_abort() here to free + * any working memory allocated by the destination manager and marker + * writer. Some applications had a problem with that: they allocated space + * of their own from the library memory manager, and didn't want it to go + * away during write_tables. So now we do nothing. This will cause a + * memory leak if an app calls write_tables repeatedly without doing a full + * compression cycle or otherwise resetting the JPEG object. However, that + * seems less bad than unexpectedly freeing memory in the normal case. + * An app that prefers the old behavior can call jpeg_abort for itself after + * each call to jpeg_write_tables(). + */ +} diff --git a/gdcm/Utilities/gdcmjpeg/jcapistd.c b/gdcm/Utilities/gdcmjpeg/jcapistd.c new file mode 100644 index 0000000..ee2a849 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jcapistd.c @@ -0,0 +1,161 @@ +/* + * jcapistd.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains application interface code for the compression half + * of the JPEG library. These are the "standard" API routines that are + * used in the normal full-compression case. They are not used by a + * transcoding-only application. Note that if an application links in + * jpeg_start_compress, it will end up linking in the entire compressor. + * We thus must separate this file from jcapimin.c to avoid linking the + * whole compression library into a transcoder. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * Compression initialization. + * Before calling this, all parameters and a data destination must be set up. + * + * We require a write_all_tables parameter as a failsafe check when writing + * multiple datastreams from the same compression object. Since prior runs + * will have left all the tables marked sent_table=TRUE, a subsequent run + * would emit an abbreviated stream (no tables) by default. This may be what + * is wanted, but for safety's sake it should not be the default behavior: + * programmers should have to make a deliberate choice to emit abbreviated + * images. Therefore the documentation and examples should encourage people + * to pass write_all_tables=TRUE; then it will take active thought to do the + * wrong thing. + */ + +GLOBAL(void) +jpeg_start_compress (j_compress_ptr cinfo, boolean write_all_tables) +{ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + if (write_all_tables) + jpeg_suppress_tables(cinfo, FALSE); /* mark all tables to be written */ + + /* (Re)initialize error mgr and destination modules */ + (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo); + (*cinfo->dest->init_destination) (cinfo); + /* Perform master selection of active modules */ + jinit_compress_master(cinfo); + /* Set up for the first pass */ + (*cinfo->master->prepare_for_pass) (cinfo); + /* Ready for application to drive first pass through jpeg_write_scanlines + * or jpeg_write_raw_data. + */ + cinfo->next_scanline = 0; + cinfo->global_state = (cinfo->raw_data_in ? CSTATE_RAW_OK : CSTATE_SCANNING); +} + + +/* + * Write some scanlines of data to the JPEG compressor. + * + * The return value will be the number of lines actually written. + * This should be less than the supplied num_lines only in case that + * the data destination module has requested suspension of the compressor, + * or if more than image_height scanlines are passed in. + * + * Note: we warn about excess calls to jpeg_write_scanlines() since + * this likely signals an application programmer error. However, + * excess scanlines passed in the last valid call are *silently* ignored, + * so that the application need not adjust num_lines for end-of-image + * when using a multiple-scanline buffer. + */ + +GLOBAL(JDIMENSION) +jpeg_write_scanlines (j_compress_ptr cinfo, JSAMPARRAY scanlines, + JDIMENSION num_lines) +{ + JDIMENSION row_ctr, rows_left; + + if (cinfo->global_state != CSTATE_SCANNING) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + if (cinfo->next_scanline >= cinfo->image_height) + WARNMS(cinfo, JWRN_TOO_MUCH_DATA); + + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) { + cinfo->progress->pass_counter = (long) cinfo->next_scanline; + cinfo->progress->pass_limit = (long) cinfo->image_height; + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + } + + /* Give master control module another chance if this is first call to + * jpeg_write_scanlines. This lets output of the frame/scan headers be + * delayed so that application can write COM, etc, markers between + * jpeg_start_compress and jpeg_write_scanlines. + */ + if (cinfo->master->call_pass_startup) + (*cinfo->master->pass_startup) (cinfo); + + /* Ignore any extra scanlines at bottom of image. */ + rows_left = cinfo->image_height - cinfo->next_scanline; + if (num_lines > rows_left) + num_lines = rows_left; + + row_ctr = 0; + (*cinfo->main->process_data) (cinfo, scanlines, &row_ctr, num_lines); + cinfo->next_scanline += row_ctr; + return row_ctr; +} + + +/* + * Alternate entry point to write raw data. + * Processes exactly one iMCU row per call, unless suspended. + */ + +GLOBAL(JDIMENSION) +jpeg_write_raw_data (j_compress_ptr cinfo, JSAMPIMAGE data, + JDIMENSION num_lines) +{ + JDIMENSION lines_per_iMCU_row; + + if (cinfo->global_state != CSTATE_RAW_OK) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + if (cinfo->next_scanline >= cinfo->image_height) { + WARNMS(cinfo, JWRN_TOO_MUCH_DATA); + return 0; + } + + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) { + cinfo->progress->pass_counter = (long) cinfo->next_scanline; + cinfo->progress->pass_limit = (long) cinfo->image_height; + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + } + + /* Give master control module another chance if this is first call to + * jpeg_write_raw_data. This lets output of the frame/scan headers be + * delayed so that application can write COM, etc, markers between + * jpeg_start_compress and jpeg_write_raw_data. + */ + if (cinfo->master->call_pass_startup) + (*cinfo->master->pass_startup) (cinfo); + + /* Verify that at least one iMCU row has been passed. */ + lines_per_iMCU_row = cinfo->max_v_samp_factor * cinfo->data_unit; + if (num_lines < lines_per_iMCU_row) + ERREXIT(cinfo, JERR_BUFFER_SIZE); + + /* Directly compress the row. */ + if (! (*cinfo->codec->compress_data) (cinfo, data)) { + /* If compressor did not consume the whole row, suspend processing. */ + return 0; + } + + /* OK, we processed one iMCU row. */ + cinfo->next_scanline += lines_per_iMCU_row; + return lines_per_iMCU_row; +} diff --git a/gdcm/Utilities/gdcmjpeg/jccoefct.c b/gdcm/Utilities/gdcmjpeg/jccoefct.c new file mode 100644 index 0000000..cad73c8 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jccoefct.c @@ -0,0 +1,455 @@ +/* + * jccoefct.c + * + * Copyright (C) 1994-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the coefficient buffer controller for compression. + * This controller is the top level of the JPEG compressor proper. + * The coefficient buffer lies between forward-DCT and entropy encoding steps. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jlossy.h" /* Private declarations for lossy codec */ + + +/* We use a full-image coefficient buffer when doing Huffman optimization, + * and also for writing multiple-scan JPEG files. In all cases, the DCT + * step is run during the first pass, and subsequent passes need only read + * the buffered coefficients. + */ +#ifdef ENTROPY_OPT_SUPPORTED +#define FULL_COEF_BUFFER_SUPPORTED +#else +#ifdef C_MULTISCAN_FILES_SUPPORTED +#define FULL_COEF_BUFFER_SUPPORTED +#endif +#endif + + +/* Private buffer controller object */ + +typedef struct { + JDIMENSION iMCU_row_num; /* iMCU row # within image */ + JDIMENSION mcu_ctr; /* counts MCUs processed in current row */ + int MCU_vert_offset; /* counts MCU rows within iMCU row */ + int MCU_rows_per_iMCU_row; /* number of such rows needed */ + + /* For single-pass compression, it's sufficient to buffer just one MCU + * (although this may prove a bit slow in practice). We allocate a + * workspace of C_MAX_DATA_UNITS_IN_MCU coefficient blocks, and reuse it for + * each MCU constructed and sent. (On 80x86, the workspace is FAR even + * though it's not really very big; this is to keep the module interfaces + * unchanged when a large coefficient buffer is necessary.) + * In multi-pass modes, this array points to the current MCU's blocks + * within the virtual arrays. + */ + JBLOCKROW MCU_buffer[C_MAX_DATA_UNITS_IN_MCU]; + + /* In multi-pass modes, we need a virtual block array for each component. */ + jvirt_barray_ptr whole_image[MAX_COMPONENTS]; +} c_coef_controller; + +typedef c_coef_controller * c_coef_ptr; + + +/* Forward declarations */ +METHODDEF(boolean) compress_data + JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf)); +#ifdef FULL_COEF_BUFFER_SUPPORTED +METHODDEF(boolean) compress_first_pass + JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf)); +METHODDEF(boolean) compress_output + JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf)); +#endif + + +LOCAL(void) +start_iMCU_row (j_compress_ptr cinfo) +/* Reset within-iMCU-row counters for a new row */ +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + c_coef_ptr coef = (c_coef_ptr) lossyc->coef_private; + + /* In an interleaved scan, an MCU row is the same as an iMCU row. + * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows. + * But at the bottom of the image, process only what's left. + */ + if (cinfo->comps_in_scan > 1) { + coef->MCU_rows_per_iMCU_row = 1; + } else { + if (coef->iMCU_row_num < (cinfo->total_iMCU_rows-1)) + coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor; + else + coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height; + } + + coef->mcu_ctr = 0; + coef->MCU_vert_offset = 0; +} + + +/* + * Initialize for a processing pass. + */ + +METHODDEF(void) +start_pass_coef (j_compress_ptr cinfo, J_BUF_MODE pass_mode) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + c_coef_ptr coef = (c_coef_ptr) lossyc->coef_private; + + coef->iMCU_row_num = 0; + start_iMCU_row(cinfo); + + switch (pass_mode) { + case JBUF_PASS_THRU: + if (coef->whole_image[0] != NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + lossyc->pub.compress_data = compress_data; + break; +#ifdef FULL_COEF_BUFFER_SUPPORTED + case JBUF_SAVE_AND_PASS: + if (coef->whole_image[0] == NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + lossyc->pub.compress_data = compress_first_pass; + break; + case JBUF_CRANK_DEST: + if (coef->whole_image[0] == NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + lossyc->pub.compress_data = compress_output; + break; +#endif + default: + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + break; + } +} + + +/* + * Process some data in the single-pass case. + * We process the equivalent of one fully interleaved MCU row ("iMCU" row) + * per call, ie, v_samp_factor block rows for each component in the image. + * Returns TRUE if the iMCU row is completed, FALSE if suspended. + * + * NB: input_buf contains a plane for each component in image, + * which we index according to the component's SOF position. + */ + +METHODDEF(boolean) +compress_data (j_compress_ptr cinfo, JSAMPIMAGE input_buf) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + c_coef_ptr coef = (c_coef_ptr) lossyc->coef_private; + JDIMENSION MCU_col_num; /* index of current MCU within row */ + JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1; + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + int blkn, bi, ci, yindex, yoffset, blockcnt; + JDIMENSION ypos, xpos; + jpeg_component_info *compptr; + + /* Loop to write as much as one whole iMCU row */ + for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row; + yoffset++) { + for (MCU_col_num = coef->mcu_ctr; MCU_col_num <= last_MCU_col; + MCU_col_num++) { + /* Determine where data comes from in input_buf and do the DCT thing. + * Each call on forward_DCT processes a horizontal row of DCT blocks + * as wide as an MCU; we rely on having allocated the MCU_buffer[] blocks + * sequentially. Dummy blocks at the right or bottom edge are filled in + * specially. The data in them does not matter for image reconstruction, + * so we fill them with values that will encode to the smallest amount of + * data, viz: all zeroes in the AC entries, DC entries equal to previous + * block's DC value. (Thanks to Thomas Kinsman for this idea.) + */ + blkn = 0; + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + blockcnt = (MCU_col_num < last_MCU_col) ? compptr->MCU_width + : compptr->last_col_width; + xpos = MCU_col_num * compptr->MCU_sample_width; + ypos = yoffset * DCTSIZE; /* ypos == (yoffset+yindex) * DCTSIZE */ + for (yindex = 0; yindex < compptr->MCU_height; yindex++) { + if (coef->iMCU_row_num < last_iMCU_row || + yoffset+yindex < compptr->last_row_height) { + (*lossyc->fdct_forward_DCT) (cinfo, compptr, + input_buf[compptr->component_index], + coef->MCU_buffer[blkn], + ypos, xpos, (JDIMENSION) blockcnt); + if (blockcnt < compptr->MCU_width) { + /* Create some dummy blocks at the right edge of the image. */ + jzero_far((void FAR *) coef->MCU_buffer[blkn + blockcnt], + (compptr->MCU_width - blockcnt) * SIZEOF(JBLOCK)); + for (bi = blockcnt; bi < compptr->MCU_width; bi++) { + coef->MCU_buffer[blkn+bi][0][0] = coef->MCU_buffer[blkn+bi-1][0][0]; + } + } + } else { + /* Create a row of dummy blocks at the bottom of the image. */ + jzero_far((void FAR *) coef->MCU_buffer[blkn], + compptr->MCU_width * SIZEOF(JBLOCK)); + for (bi = 0; bi < compptr->MCU_width; bi++) { + coef->MCU_buffer[blkn+bi][0][0] = coef->MCU_buffer[blkn-1][0][0]; + } + } + blkn += compptr->MCU_width; + ypos += DCTSIZE; + } + } + /* Try to write the MCU. In event of a suspension failure, we will + * re-DCT the MCU on restart (a bit inefficient, could be fixed...) + */ + if (! (*lossyc->entropy_encode_mcu) (cinfo, coef->MCU_buffer)) { + /* Suspension forced; update state counters and exit */ + coef->MCU_vert_offset = yoffset; + coef->mcu_ctr = MCU_col_num; + return FALSE; + } + } + /* Completed an MCU row, but perhaps not an iMCU row */ + coef->mcu_ctr = 0; + } + /* Completed the iMCU row, advance counters for next one */ + coef->iMCU_row_num++; + start_iMCU_row(cinfo); + return TRUE; +} + + +#ifdef FULL_COEF_BUFFER_SUPPORTED + +/* + * Process some data in the first pass of a multi-pass case. + * We process the equivalent of one fully interleaved MCU row ("iMCU" row) + * per call, ie, v_samp_factor block rows for each component in the image. + * This amount of data is read from the source buffer, DCT'd and quantized, + * and saved into the virtual arrays. We also generate suitable dummy blocks + * as needed at the right and lower edges. (The dummy blocks are constructed + * in the virtual arrays, which have been padded appropriately.) This makes + * it possible for subsequent passes not to worry about real vs. dummy blocks. + * + * We must also emit the data to the entropy encoder. This is conveniently + * done by calling compress_output() after we've loaded the current strip + * of the virtual arrays. + * + * NB: input_buf contains a plane for each component in image. All + * components are DCT'd and loaded into the virtual arrays in this pass. + * However, it may be that only a subset of the components are emitted to + * the entropy encoder during this first pass; be careful about looking + * at the scan-dependent variables (MCU dimensions, etc). + */ + +METHODDEF(boolean) +compress_first_pass (j_compress_ptr cinfo, JSAMPIMAGE input_buf) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + c_coef_ptr coef = (c_coef_ptr) lossyc->coef_private; + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + JDIMENSION blocks_across, MCUs_across, MCUindex; + int bi, ci, h_samp_factor, block_row, block_rows, ndummy; + JCOEF lastDC; + jpeg_component_info *compptr; + JBLOCKARRAY buffer; + JBLOCKROW thisblockrow, lastblockrow; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Align the virtual buffer for this component. */ + buffer = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef->whole_image[ci], + coef->iMCU_row_num * compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, TRUE); + /* Count non-dummy DCT block rows in this iMCU row. */ + if (coef->iMCU_row_num < last_iMCU_row) + block_rows = compptr->v_samp_factor; + else { + /* NB: can't use last_row_height here, since may not be set! */ + block_rows = (int) (compptr->height_in_data_units % compptr->v_samp_factor); + if (block_rows == 0) block_rows = compptr->v_samp_factor; + } + blocks_across = compptr->width_in_data_units; + h_samp_factor = compptr->h_samp_factor; + /* Count number of dummy blocks to be added at the right margin. */ + ndummy = (int) (blocks_across % h_samp_factor); + if (ndummy > 0) + ndummy = h_samp_factor - ndummy; + /* Perform DCT for all non-dummy blocks in this iMCU row. Each call + * on forward_DCT processes a complete horizontal row of DCT blocks. + */ + for (block_row = 0; block_row < block_rows; block_row++) { + thisblockrow = buffer[block_row]; + (*lossyc->fdct_forward_DCT) (cinfo, compptr, + input_buf[ci], thisblockrow, + (JDIMENSION) (block_row * DCTSIZE), + (JDIMENSION) 0, blocks_across); + if (ndummy > 0) { + /* Create dummy blocks at the right edge of the image. */ + thisblockrow += blocks_across; /* => first dummy block */ + jzero_far((void FAR *) thisblockrow, ndummy * SIZEOF(JBLOCK)); + lastDC = thisblockrow[-1][0]; + for (bi = 0; bi < ndummy; bi++) { + thisblockrow[bi][0] = lastDC; + } + } + } + /* If at end of image, create dummy block rows as needed. + * The tricky part here is that within each MCU, we want the DC values + * of the dummy blocks to match the last real block's DC value. + * This squeezes a few more bytes out of the resulting file... + */ + if (coef->iMCU_row_num == last_iMCU_row) { + blocks_across += ndummy; /* include lower right corner */ + MCUs_across = blocks_across / h_samp_factor; + for (block_row = block_rows; block_row < compptr->v_samp_factor; + block_row++) { + thisblockrow = buffer[block_row]; + lastblockrow = buffer[block_row-1]; + jzero_far((void FAR *) thisblockrow, + (size_t) (blocks_across * SIZEOF(JBLOCK))); + for (MCUindex = 0; MCUindex < MCUs_across; MCUindex++) { + lastDC = lastblockrow[h_samp_factor-1][0]; + for (bi = 0; bi < h_samp_factor; bi++) { + thisblockrow[bi][0] = lastDC; + } + thisblockrow += h_samp_factor; /* advance to next MCU in row */ + lastblockrow += h_samp_factor; + } + } + } + } + /* NB: compress_output will increment iMCU_row_num if successful. + * A suspension return will result in redoing all the work above next time. + */ + + /* Emit data to the entropy encoder, sharing code with subsequent passes */ + return compress_output(cinfo, input_buf); +} + + +/* + * Process some data in subsequent passes of a multi-pass case. + * We process the equivalent of one fully interleaved MCU row ("iMCU" row) + * per call, ie, v_samp_factor block rows for each component in the scan. + * The data is obtained from the virtual arrays and fed to the entropy coder. + * Returns TRUE if the iMCU row is completed, FALSE if suspended. + * + * NB: input_buf is ignored; it is likely to be a NULL pointer. + */ + +METHODDEF(boolean) +compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + c_coef_ptr coef = (c_coef_ptr) lossyc->coef_private; + JDIMENSION MCU_col_num; /* index of current MCU within row */ + int blkn, ci, xindex, yindex, yoffset; + JDIMENSION start_col; + JBLOCKARRAY buffer[MAX_COMPS_IN_SCAN]; + JBLOCKROW buffer_ptr; + jpeg_component_info *compptr; + (void)input_buf; + + /* Align the virtual buffers for the components used in this scan. + * NB: during first pass, this is safe only because the buffers will + * already be aligned properly, so jmemmgr.c won't need to do any I/O. + */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + buffer[ci] = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef->whole_image[compptr->component_index], + coef->iMCU_row_num * compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } + + /* Loop to process one whole iMCU row */ + for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row; + yoffset++) { + for (MCU_col_num = coef->mcu_ctr; MCU_col_num < cinfo->MCUs_per_row; + MCU_col_num++) { + /* Construct list of pointers to DCT blocks belonging to this MCU */ + blkn = 0; /* index of current DCT block within MCU */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + start_col = MCU_col_num * compptr->MCU_width; + for (yindex = 0; yindex < compptr->MCU_height; yindex++) { + buffer_ptr = buffer[ci][yindex+yoffset] + start_col; + for (xindex = 0; xindex < compptr->MCU_width; xindex++) { + coef->MCU_buffer[blkn++] = buffer_ptr++; + } + } + } + /* Try to write the MCU. */ + if (! (*lossyc->entropy_encode_mcu) (cinfo, coef->MCU_buffer)) { + /* Suspension forced; update state counters and exit */ + coef->MCU_vert_offset = yoffset; + coef->mcu_ctr = MCU_col_num; + return FALSE; + } + } + /* Completed an MCU row, but perhaps not an iMCU row */ + coef->mcu_ctr = 0; + } + /* Completed the iMCU row, advance counters for next one */ + coef->iMCU_row_num++; + start_iMCU_row(cinfo); + return TRUE; +} + +#endif /* FULL_COEF_BUFFER_SUPPORTED */ + + +/* + * Initialize coefficient buffer controller. + */ + +GLOBAL(void) +jinit_c_coef_controller (j_compress_ptr cinfo, boolean need_full_buffer) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + c_coef_ptr coef; + + coef = (c_coef_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(c_coef_controller)); + lossyc->coef_private = (struct jpeg_c_coef_controller *) coef; + lossyc->coef_start_pass = start_pass_coef; + + /* Create the coefficient buffer. */ + if (need_full_buffer) { +#ifdef FULL_COEF_BUFFER_SUPPORTED + /* Allocate a full-image virtual array for each component, */ + /* padded to a multiple of samp_factor DCT blocks in each direction. */ + int ci; + jpeg_component_info *compptr; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + coef->whole_image[ci] = (*cinfo->mem->request_virt_barray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, + (JDIMENSION) jround_up((long) compptr->width_in_data_units, + (long) compptr->h_samp_factor), + (JDIMENSION) jround_up((long) compptr->height_in_data_units, + (long) compptr->v_samp_factor), + (JDIMENSION) compptr->v_samp_factor); + } +#else + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); +#endif + } else { + /* We only need a single-MCU buffer. */ + JBLOCKROW buffer; + int i; + + buffer = (JBLOCKROW) + (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE, + C_MAX_DATA_UNITS_IN_MCU * SIZEOF(JBLOCK)); + for (i = 0; i < C_MAX_DATA_UNITS_IN_MCU; i++) { + coef->MCU_buffer[i] = buffer + i; + } + coef->whole_image[0] = NULL; /* flag for no virtual arrays */ + } +} diff --git a/gdcm/Utilities/gdcmjpeg/jccolor.c b/gdcm/Utilities/gdcmjpeg/jccolor.c new file mode 100644 index 0000000..a0afd61 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jccolor.c @@ -0,0 +1,460 @@ +/* + * jccolor.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains input colorspace conversion routines. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Private subobject */ + +typedef struct { + struct jpeg_color_converter pub; /* public fields */ + + /* Private state for RGB->YCC conversion */ + INT32 * rgb_ycc_tab; /* => table for RGB to YCbCr conversion */ +} my_color_converter; + +typedef my_color_converter * my_cconvert_ptr; + + +/**************** RGB -> YCbCr conversion: most common case **************/ + +/* + * YCbCr is defined per CCIR 601-1, except that Cb and Cr are + * normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5. + * The conversion equations to be implemented are therefore + * Y = 0.29900 * R + 0.58700 * G + 0.11400 * B + * Cb = -0.16874 * R - 0.33126 * G + 0.50000 * B + CENTERJSAMPLE + * Cr = 0.50000 * R - 0.41869 * G - 0.08131 * B + CENTERJSAMPLE + * (These numbers are derived from TIFF 6.0 section 21, dated 3-June-92.) + * Note: older versions of the IJG code used a zero offset of MAXJSAMPLE/2, + * rather than CENTERJSAMPLE, for Cb and Cr. This gave equal positive and + * negative swings for Cb/Cr, but meant that grayscale values (Cb=Cr=0) + * were not represented exactly. Now we sacrifice exact representation of + * maximum red and maximum blue in order to get exact grayscales. + * + * To avoid floating-point arithmetic, we represent the fractional constants + * as integers scaled up by 2^16 (about 4 digits precision); we have to divide + * the products by 2^16, with appropriate rounding, to get the correct answer. + * + * For even more speed, we avoid doing any multiplications in the inner loop + * by precalculating the constants times R,G,B for all possible values. + * For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table); + * for 12-bit samples it is still acceptable. It's not very reasonable for + * 16-bit samples, but if you want lossless storage you shouldn't be changing + * colorspace anyway. + * The CENTERJSAMPLE offsets and the rounding fudge-factor of 0.5 are included + * in the tables to save adding them separately in the inner loop. + */ + +#define SCALEBITS 16 /* speediest right-shift on some machines */ +#define CBCR_OFFSET ((INT32) CENTERJSAMPLE << SCALEBITS) +#define ONE_HALF ((INT32) 1 << (SCALEBITS-1)) +#define FIX(x) ((INT32) ((x) * (1L< Y section */ +#define G_Y_OFF (1*(MAXJSAMPLE+1)) /* offset to G => Y section */ +#define B_Y_OFF (2*(MAXJSAMPLE+1)) /* etc. */ +#define R_CB_OFF (3*(MAXJSAMPLE+1)) +#define G_CB_OFF (4*(MAXJSAMPLE+1)) +#define B_CB_OFF (5*(MAXJSAMPLE+1)) +#define R_CR_OFF B_CB_OFF /* B=>Cb, R=>Cr are the same */ +#define G_CR_OFF (6*(MAXJSAMPLE+1)) +#define B_CR_OFF (7*(MAXJSAMPLE+1)) +#define TABLE_SIZE (8*(MAXJSAMPLE+1)) + + +/* + * Initialize for RGB->YCC colorspace conversion. + */ + +METHODDEF(void) +rgb_ycc_start (j_compress_ptr cinfo) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + INT32 * rgb_ycc_tab; + INT32 i; + + /* Allocate and fill in the conversion tables. */ + cconvert->rgb_ycc_tab = rgb_ycc_tab = (INT32 *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (TABLE_SIZE * SIZEOF(INT32))); + + for (i = 0; i <= MAXJSAMPLE; i++) { + rgb_ycc_tab[i+R_Y_OFF] = FIX(0.29900) * i; + rgb_ycc_tab[i+G_Y_OFF] = FIX(0.58700) * i; + rgb_ycc_tab[i+B_Y_OFF] = FIX(0.11400) * i + ONE_HALF; + rgb_ycc_tab[i+R_CB_OFF] = (-FIX(0.16874)) * i; + rgb_ycc_tab[i+G_CB_OFF] = (-FIX(0.33126)) * i; + /* We use a rounding fudge-factor of 0.5-epsilon for Cb and Cr. + * This ensures that the maximum output will round to MAXJSAMPLE + * not MAXJSAMPLE+1, and thus that we don't have to range-limit. + */ + rgb_ycc_tab[i+B_CB_OFF] = FIX(0.50000) * i + CBCR_OFFSET + ONE_HALF-1; +/* B=>Cb and R=>Cr tables are the same + rgb_ycc_tab[i+R_CR_OFF] = FIX(0.50000) * i + CBCR_OFFSET + ONE_HALF-1; +*/ + rgb_ycc_tab[i+G_CR_OFF] = (-FIX(0.41869)) * i; + rgb_ycc_tab[i+B_CR_OFF] = (-FIX(0.08131)) * i; + } +} + + +/* + * Convert some rows of samples to the JPEG colorspace. + * + * Note that we change from the application's interleaved-pixel format + * to our internal noninterleaved, one-plane-per-component format. + * The input buffer is therefore three times as wide as the output buffer. + * + * A starting row offset is provided only for the output buffer. The caller + * can easily adjust the passed input_buf value to accommodate any row + * offset required on that side. + */ + +METHODDEF(void) +rgb_ycc_convert (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + register int r, g, b; + register INT32 * ctab = cconvert->rgb_ycc_tab; + register JSAMPROW inptr; + register JSAMPROW outptr0, outptr1, outptr2; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->image_width; + + while (--num_rows >= 0) { + inptr = *input_buf++; + outptr0 = output_buf[0][output_row]; + outptr1 = output_buf[1][output_row]; + outptr2 = output_buf[2][output_row]; + output_row++; + for (col = 0; col < num_cols; col++) { + r = GETJSAMPLE(inptr[RGB_RED]); + g = GETJSAMPLE(inptr[RGB_GREEN]); + b = GETJSAMPLE(inptr[RGB_BLUE]); + inptr += RGB_PIXELSIZE; + /* If the inputs are 0..MAXJSAMPLE, the outputs of these equations + * must be too; we do not need an explicit range-limiting operation. + * Hence the value being shifted is never negative, and we don't + * need the general RIGHT_SHIFT macro. + */ + /* Y */ + outptr0[col] = (JSAMPLE) + ((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF]) + >> SCALEBITS); + /* Cb */ + outptr1[col] = (JSAMPLE) + ((ctab[r+R_CB_OFF] + ctab[g+G_CB_OFF] + ctab[b+B_CB_OFF]) + >> SCALEBITS); + /* Cr */ + outptr2[col] = (JSAMPLE) + ((ctab[r+R_CR_OFF] + ctab[g+G_CR_OFF] + ctab[b+B_CR_OFF]) + >> SCALEBITS); + } + } +} + + +/**************** Cases other than RGB -> YCbCr **************/ + + +/* + * Convert some rows of samples to the JPEG colorspace. + * This version handles RGB->grayscale conversion, which is the same + * as the RGB->Y portion of RGB->YCbCr. + * We assume rgb_ycc_start has been called (we only use the Y tables). + */ + +METHODDEF(void) +rgb_gray_convert (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + register int r, g, b; + register INT32 * ctab = cconvert->rgb_ycc_tab; + register JSAMPROW inptr; + register JSAMPROW outptr; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->image_width; + + while (--num_rows >= 0) { + inptr = *input_buf++; + outptr = output_buf[0][output_row]; + output_row++; + for (col = 0; col < num_cols; col++) { + r = GETJSAMPLE(inptr[RGB_RED]); + g = GETJSAMPLE(inptr[RGB_GREEN]); + b = GETJSAMPLE(inptr[RGB_BLUE]); + inptr += RGB_PIXELSIZE; + /* Y */ + outptr[col] = (JSAMPLE) + ((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF]) + >> SCALEBITS); + } + } +} + + +/* + * Convert some rows of samples to the JPEG colorspace. + * This version handles Adobe-style CMYK->YCCK conversion, + * where we convert R=1-C, G=1-M, and B=1-Y to YCbCr using the same + * conversion as above, while passing K (black) unchanged. + * We assume rgb_ycc_start has been called. + */ + +METHODDEF(void) +cmyk_ycck_convert (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + register int r, g, b; + register INT32 * ctab = cconvert->rgb_ycc_tab; + register JSAMPROW inptr; + register JSAMPROW outptr0, outptr1, outptr2, outptr3; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->image_width; + + while (--num_rows >= 0) { + inptr = *input_buf++; + outptr0 = output_buf[0][output_row]; + outptr1 = output_buf[1][output_row]; + outptr2 = output_buf[2][output_row]; + outptr3 = output_buf[3][output_row]; + output_row++; + for (col = 0; col < num_cols; col++) { + r = MAXJSAMPLE - GETJSAMPLE(inptr[0]); + g = MAXJSAMPLE - GETJSAMPLE(inptr[1]); + b = MAXJSAMPLE - GETJSAMPLE(inptr[2]); + /* K passes through as-is */ + outptr3[col] = inptr[3]; /* don't need GETJSAMPLE here */ + inptr += 4; + /* If the inputs are 0..MAXJSAMPLE, the outputs of these equations + * must be too; we do not need an explicit range-limiting operation. + * Hence the value being shifted is never negative, and we don't + * need the general RIGHT_SHIFT macro. + */ + /* Y */ + outptr0[col] = (JSAMPLE) + ((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF]) + >> SCALEBITS); + /* Cb */ + outptr1[col] = (JSAMPLE) + ((ctab[r+R_CB_OFF] + ctab[g+G_CB_OFF] + ctab[b+B_CB_OFF]) + >> SCALEBITS); + /* Cr */ + outptr2[col] = (JSAMPLE) + ((ctab[r+R_CR_OFF] + ctab[g+G_CR_OFF] + ctab[b+B_CR_OFF]) + >> SCALEBITS); + } + } +} + + +/* + * Convert some rows of samples to the JPEG colorspace. + * This version handles grayscale output with no conversion. + * The source can be either plain grayscale or YCbCr (since Y == gray). + */ + +METHODDEF(void) +grayscale_convert (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows) +{ + register JSAMPROW inptr; + register JSAMPROW outptr; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->image_width; + int instride = cinfo->input_components; + + while (--num_rows >= 0) { + inptr = *input_buf++; + outptr = output_buf[0][output_row]; + output_row++; + for (col = 0; col < num_cols; col++) { + outptr[col] = inptr[0]; /* don't need GETJSAMPLE() here */ + inptr += instride; + } + } +} + + +/* + * Convert some rows of samples to the JPEG colorspace. + * This version handles multi-component colorspaces without conversion. + * We assume input_components == num_components. + */ + +METHODDEF(void) +null_convert (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows) +{ + register JSAMPROW inptr; + register JSAMPROW outptr; + register JDIMENSION col; + register int ci; + int nc = cinfo->num_components; + JDIMENSION num_cols = cinfo->image_width; + + while (--num_rows >= 0) { + /* It seems fastest to make a separate pass for each component. */ + for (ci = 0; ci < nc; ci++) { + inptr = *input_buf; + outptr = output_buf[ci][output_row]; + for (col = 0; col < num_cols; col++) { + outptr[col] = inptr[ci]; /* don't need GETJSAMPLE() here */ + inptr += nc; + } + } + input_buf++; + output_row++; + } +} + + +/* + * Empty method for start_pass. + */ + +METHODDEF(void) +null_method (j_compress_ptr cinfo) +{ + (void)cinfo; + /* no work needed */ +} + + +/* + * Module initialization routine for input colorspace conversion. + */ + +GLOBAL(void) +jinit_color_converter (j_compress_ptr cinfo) +{ + my_cconvert_ptr cconvert; + + cconvert = (my_cconvert_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_color_converter)); + cinfo->cconvert = (struct jpeg_color_converter *) cconvert; + /* set start_pass to null method until we find out differently */ + cconvert->pub.start_pass = null_method; + + /* Make sure input_components agrees with in_color_space */ + switch (cinfo->in_color_space) { + case JCS_GRAYSCALE: + if (cinfo->input_components != 1) + ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE); + break; + + case JCS_RGB: +#if RGB_PIXELSIZE != 3 + if (cinfo->input_components != RGB_PIXELSIZE) + ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE); + break; +#endif /* else share code with YCbCr */ + + case JCS_YCbCr: + if (cinfo->input_components != 3) + ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE); + break; + + case JCS_CMYK: + case JCS_YCCK: + if (cinfo->input_components != 4) + ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE); + break; + + default: /* JCS_UNKNOWN can be anything */ + if (cinfo->input_components < 1) + ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE); + break; + } + + /* Check num_components, set conversion method based on requested space */ + switch (cinfo->jpeg_color_space) { + case JCS_GRAYSCALE: + if (cinfo->num_components != 1) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + if (cinfo->in_color_space == JCS_GRAYSCALE) + cconvert->pub.color_convert = grayscale_convert; + else if (cinfo->in_color_space == JCS_RGB) { + cconvert->pub.start_pass = rgb_ycc_start; + cconvert->pub.color_convert = rgb_gray_convert; + } else if (cinfo->in_color_space == JCS_YCbCr) + cconvert->pub.color_convert = grayscale_convert; + else + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + + case JCS_RGB: + if (cinfo->num_components != 3) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + if (cinfo->in_color_space == JCS_RGB && RGB_PIXELSIZE == 3) + cconvert->pub.color_convert = null_convert; + else + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + + case JCS_YCbCr: + if (cinfo->num_components != 3) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + if (cinfo->in_color_space == JCS_RGB) { + cconvert->pub.start_pass = rgb_ycc_start; + cconvert->pub.color_convert = rgb_ycc_convert; + } else if (cinfo->in_color_space == JCS_YCbCr) + cconvert->pub.color_convert = null_convert; + else + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + + case JCS_CMYK: + if (cinfo->num_components != 4) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + if (cinfo->in_color_space == JCS_CMYK) + cconvert->pub.color_convert = null_convert; + else + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + + case JCS_YCCK: + if (cinfo->num_components != 4) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + if (cinfo->in_color_space == JCS_CMYK) { + cconvert->pub.start_pass = rgb_ycc_start; + cconvert->pub.color_convert = cmyk_ycck_convert; + } else if (cinfo->in_color_space == JCS_YCCK) + cconvert->pub.color_convert = null_convert; + else + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + + default: /* allow null conversion of JCS_UNKNOWN */ + if (cinfo->jpeg_color_space != cinfo->in_color_space || + cinfo->num_components != cinfo->input_components) + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + cconvert->pub.color_convert = null_convert; + break; + } +} diff --git a/gdcm/Utilities/gdcmjpeg/jcdctmgr.c b/gdcm/Utilities/gdcmjpeg/jcdctmgr.c new file mode 100644 index 0000000..5b21799 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jcdctmgr.c @@ -0,0 +1,390 @@ +/* + * jcdctmgr.c + * + * Copyright (C) 1994-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the forward-DCT management logic. + * This code selects a particular DCT implementation to be used, + * and it performs related housekeeping chores including coefficient + * quantization. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jlossy.h" /* Private declarations for lossy codec */ +#include "jdct.h" /* Private declarations for DCT subsystem */ + + +/* Private subobject for this module */ + +typedef struct { + /* Pointer to the DCT routine actually in use */ + forward_DCT_method_ptr do_dct; + + /* The actual post-DCT divisors --- not identical to the quant table + * entries, because of scaling (especially for an unnormalized DCT). + * Each table is given in normal array order. + */ + DCTELEM * divisors[NUM_QUANT_TBLS]; + +#ifdef DCT_FLOAT_SUPPORTED + /* Same as above for the floating-point case. */ + float_DCT_method_ptr do_float_dct; + FAST_FLOAT * float_divisors[NUM_QUANT_TBLS]; +#endif +} fdct_controller; + +typedef fdct_controller * fdct_ptr; + + +/* + * Initialize for a processing pass. + * Verify that all referenced Q-tables are present, and set up + * the divisor table for each one. + * In the current implementation, DCT of all components is done during + * the first pass, even if only some components will be output in the + * first scan. Hence all components should be examined here. + */ + +METHODDEF(void) +start_pass_fdctmgr (j_compress_ptr cinfo) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + fdct_ptr fdct = (fdct_ptr) lossyc->fdct_private; + int ci, qtblno, i; + jpeg_component_info *compptr; + JQUANT_TBL * qtbl; + DCTELEM * dtbl; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + qtblno = compptr->quant_tbl_no; + /* Make sure specified quantization table is present */ + if (qtblno < 0 || qtblno >= NUM_QUANT_TBLS || + cinfo->quant_tbl_ptrs[qtblno] == NULL) + ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, qtblno); + qtbl = cinfo->quant_tbl_ptrs[qtblno]; + /* Compute divisors for this quant table */ + /* We may do this more than once for same table, but it's not a big deal */ + switch (cinfo->dct_method) { +#ifdef DCT_ISLOW_SUPPORTED + case JDCT_ISLOW: + /* For LL&M IDCT method, divisors are equal to raw quantization + * coefficients multiplied by 8 (to counteract scaling). + */ + if (fdct->divisors[qtblno] == NULL) { + fdct->divisors[qtblno] = (DCTELEM *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + DCTSIZE2 * SIZEOF(DCTELEM)); + } + dtbl = fdct->divisors[qtblno]; + for (i = 0; i < DCTSIZE2; i++) { + dtbl[i] = ((DCTELEM) qtbl->quantval[i]) << 3; + } + break; +#endif +#ifdef DCT_IFAST_SUPPORTED + case JDCT_IFAST: + { + /* For AA&N IDCT method, divisors are equal to quantization + * coefficients scaled by scalefactor[row]*scalefactor[col], where + * scalefactor[0] = 1 + * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7 + * We apply a further scale factor of 8. + */ +#define CONST_BITS 14 + static const INT16 aanscales[DCTSIZE2] = { + /* precomputed values scaled up by 14 bits */ + 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, + 22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270, + 21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906, + 19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315, + 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, + 12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552, + 8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446, + 4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247 + }; + SHIFT_TEMPS + + if (fdct->divisors[qtblno] == NULL) { + fdct->divisors[qtblno] = (DCTELEM *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + DCTSIZE2 * SIZEOF(DCTELEM)); + } + dtbl = fdct->divisors[qtblno]; + for (i = 0; i < DCTSIZE2; i++) { + dtbl[i] = (DCTELEM) + DESCALE(MULTIPLY16V16((INT32) qtbl->quantval[i], + (INT32) aanscales[i]), + CONST_BITS-3); + } + } + break; +#endif +#ifdef DCT_FLOAT_SUPPORTED + case JDCT_FLOAT: + { + /* For float AA&N IDCT method, divisors are equal to quantization + * coefficients scaled by scalefactor[row]*scalefactor[col], where + * scalefactor[0] = 1 + * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7 + * We apply a further scale factor of 8. + * What's actually stored is 1/divisor so that the inner loop can + * use a multiplication rather than a division. + */ + FAST_FLOAT * fdtbl; + int row, col; + static const double aanscalefactor[DCTSIZE] = { + 1.0, 1.387039845, 1.306562965, 1.175875602, + 1.0, 0.785694958, 0.541196100, 0.275899379 + }; + + if (fdct->float_divisors[qtblno] == NULL) { + fdct->float_divisors[qtblno] = (FAST_FLOAT *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + DCTSIZE2 * SIZEOF(FAST_FLOAT)); + } + fdtbl = fdct->float_divisors[qtblno]; + i = 0; + for (row = 0; row < DCTSIZE; row++) { + for (col = 0; col < DCTSIZE; col++) { + fdtbl[i] = (FAST_FLOAT) + (1.0 / (((double) qtbl->quantval[i] * + aanscalefactor[row] * aanscalefactor[col] * 8.0))); + i++; + } + } + } + break; +#endif + default: + ERREXIT(cinfo, JERR_NOT_COMPILED); + break; + } + } +} + + +/* + * Perform forward DCT on one or more blocks of a component. + * + * The input samples are taken from the sample_data[] array starting at + * position start_row/start_col, and moving to the right for any additional + * blocks. The quantized coefficients are returned in coef_blocks[]. + */ + +METHODDEF(void) +forward_DCT (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY sample_data, JBLOCKROW coef_blocks, + JDIMENSION start_row, JDIMENSION start_col, + JDIMENSION num_blocks) +/* This version is used for integer DCT implementations. */ +{ + /* This routine is heavily used, so it's worth coding it tightly. */ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + fdct_ptr fdct = (fdct_ptr) lossyc->fdct_private; + forward_DCT_method_ptr do_dct = fdct->do_dct; + DCTELEM * divisors = fdct->divisors[compptr->quant_tbl_no]; + DCTELEM workspace[DCTSIZE2]; /* work area for FDCT subroutine */ + JDIMENSION bi; + + sample_data += start_row; /* fold in the vertical offset once */ + + for (bi = 0; bi < num_blocks; bi++, start_col += DCTSIZE) { + /* Load data into workspace, applying unsigned->signed conversion */ + { register DCTELEM *workspaceptr; + register JSAMPROW elemptr; + register int elemr; + + workspaceptr = workspace; + for (elemr = 0; elemr < DCTSIZE; elemr++) { + elemptr = sample_data[elemr] + start_col; +#if DCTSIZE == 8 /* unroll the inner loop */ + *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; +#else + { register int elemc; + for (elemc = DCTSIZE; elemc > 0; elemc--) { + *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + } + } +#endif + } + } + + /* Perform the DCT */ + (*do_dct) (workspace); + + /* Quantize/descale the coefficients, and store into coef_blocks[] */ + { register DCTELEM temp, qval; + register int i; + register JCOEFPTR output_ptr = coef_blocks[bi]; + + for (i = 0; i < DCTSIZE2; i++) { + qval = divisors[i]; + temp = workspace[i]; + /* Divide the coefficient value by qval, ensuring proper rounding. + * Since C does not specify the direction of rounding for negative + * quotients, we have to force the dividend positive for portability. + * + * In most files, at least half of the output values will be zero + * (at default quantization settings, more like three-quarters...) + * so we should ensure that this case is fast. On many machines, + * a comparison is enough cheaper than a divide to make a special test + * a win. Since both inputs will be nonnegative, we need only test + * for a < b to discover whether a/b is 0. + * If your machine's division is fast enough, define FAST_DIVIDE. + */ +#ifdef FAST_DIVIDE +#define DIVIDE_BY(a,b) a /= b +#else +#define DIVIDE_BY(a,b) if (a >= b) a /= b; else a = 0 +#endif + if (temp < 0) { + temp = -temp; + temp += qval>>1; /* for rounding */ + DIVIDE_BY(temp, qval); + temp = -temp; + } else { + temp += qval>>1; /* for rounding */ + DIVIDE_BY(temp, qval); + } + output_ptr[i] = (JCOEF) temp; + } + } + } +} + + +#ifdef DCT_FLOAT_SUPPORTED + +METHODDEF(void) +forward_DCT_float (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY sample_data, JBLOCKROW coef_blocks, + JDIMENSION start_row, JDIMENSION start_col, + JDIMENSION num_blocks) +/* This version is used for floating-point DCT implementations. */ +{ + /* This routine is heavily used, so it's worth coding it tightly. */ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + fdct_ptr fdct = (fdct_ptr) lossyc->fdct_private; + float_DCT_method_ptr do_dct = fdct->do_float_dct; + FAST_FLOAT * divisors = fdct->float_divisors[compptr->quant_tbl_no]; + FAST_FLOAT workspace[DCTSIZE2]; /* work area for FDCT subroutine */ + JDIMENSION bi; + + sample_data += start_row; /* fold in the vertical offset once */ + + for (bi = 0; bi < num_blocks; bi++, start_col += DCTSIZE) { + /* Load data into workspace, applying unsigned->signed conversion */ + { register FAST_FLOAT *workspaceptr; + register JSAMPROW elemptr; + register int elemr; + + workspaceptr = workspace; + for (elemr = 0; elemr < DCTSIZE; elemr++) { + elemptr = sample_data[elemr] + start_col; +#if DCTSIZE == 8 /* unroll the inner loop */ + *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); + *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); + *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); + *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); + *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); + *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); + *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); + *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); +#else + { register int elemc; + for (elemc = DCTSIZE; elemc > 0; elemc--) { + *workspaceptr++ = (FAST_FLOAT) + (GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); + } + } +#endif + } + } + + /* Perform the DCT */ + (*do_dct) (workspace); + + /* Quantize/descale the coefficients, and store into coef_blocks[] */ + { register FAST_FLOAT temp; + register int i; + register JCOEFPTR output_ptr = coef_blocks[bi]; + + for (i = 0; i < DCTSIZE2; i++) { + /* Apply the quantization and scaling factor */ + temp = workspace[i] * divisors[i]; + /* Round to nearest integer. + * Since C does not specify the direction of rounding for negative + * quotients, we have to force the dividend positive for portability. + * The maximum coefficient size is +-16K (for 12-bit data), so this + * code should work for either 16-bit or 32-bit ints. + */ + output_ptr[i] = (JCOEF) ((int) (temp + (FAST_FLOAT) 16384.5) - 16384); + } + } + } +} + +#endif /* DCT_FLOAT_SUPPORTED */ + + +/* + * Initialize FDCT manager. + */ + +GLOBAL(void) +jinit_forward_dct (j_compress_ptr cinfo) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + fdct_ptr fdct; + int i; + + fdct = (fdct_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(fdct_controller)); + lossyc->fdct_private = (struct jpeg_forward_dct *) fdct; + lossyc->fdct_start_pass = start_pass_fdctmgr; + + switch (cinfo->dct_method) { +#ifdef DCT_ISLOW_SUPPORTED + case JDCT_ISLOW: + lossyc->fdct_forward_DCT = forward_DCT; + fdct->do_dct = jpeg_fdct_islow; + break; +#endif +#ifdef DCT_IFAST_SUPPORTED + case JDCT_IFAST: + lossyc->fdct_forward_DCT = forward_DCT; + fdct->do_dct = jpeg_fdct_ifast; + break; +#endif +#ifdef DCT_FLOAT_SUPPORTED + case JDCT_FLOAT: + lossyc->fdct_forward_DCT = forward_DCT_float; + fdct->do_float_dct = jpeg_fdct_float; + break; +#endif + default: + ERREXIT(cinfo, JERR_NOT_COMPILED); + break; + } + + /* Mark divisor tables unallocated */ + for (i = 0; i < NUM_QUANT_TBLS; i++) { + fdct->divisors[i] = NULL; +#ifdef DCT_FLOAT_SUPPORTED + fdct->float_divisors[i] = NULL; +#endif + } +} diff --git a/gdcm/Utilities/gdcmjpeg/jcdiffct.c b/gdcm/Utilities/gdcmjpeg/jcdiffct.c new file mode 100644 index 0000000..d395342 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jcdiffct.c @@ -0,0 +1,410 @@ +/* + * jcdiffct.c + * + * Copyright (C) 1994-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the difference buffer controller for compression. + * This controller is the top level of the lossless JPEG compressor proper. + * The difference buffer lies between prediction/differencing and entropy + * encoding. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jlossls.h" /* Private declarations for lossless codec */ + + +#ifdef C_LOSSLESS_SUPPORTED + +/* We use a full-image sample buffer when doing Huffman optimization, + * and also for writing multiple-scan JPEG files. In all cases, the + * full-image buffer is filled during the first pass, and the scaling, + * prediction and differencing steps are run during subsequent passes. + */ +#ifdef ENTROPY_OPT_SUPPORTED +#define FULL_SAMP_BUFFER_SUPPORTED +#else +#ifdef C_MULTISCAN_FILES_SUPPORTED +#define FULL_SAMP_BUFFER_SUPPORTED +#endif +#endif + + +/* Private buffer controller object */ + +typedef struct { + JDIMENSION iMCU_row_num; /* iMCU row # within image */ + JDIMENSION mcu_ctr; /* counts MCUs processed in current row */ + int MCU_vert_offset; /* counts MCU rows within iMCU row */ + int MCU_rows_per_iMCU_row; /* number of such rows needed */ + + JSAMPROW cur_row[MAX_COMPONENTS]; /* row of point transformed samples */ + JSAMPROW prev_row[MAX_COMPONENTS]; /* previous row of Pt'd samples */ + JDIFFARRAY diff_buf[MAX_COMPONENTS]; /* iMCU row of differences */ + + /* In multi-pass modes, we need a virtual sample array for each component. */ + jvirt_sarray_ptr whole_image[MAX_COMPONENTS]; +} c_diff_controller; + +typedef c_diff_controller * c_diff_ptr; + + +/* Forward declarations */ +METHODDEF(boolean) compress_data + JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf)); +#ifdef FULL_SAMP_BUFFER_SUPPORTED +METHODDEF(boolean) compress_first_pass + JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf)); +METHODDEF(boolean) compress_output + JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf)); +#endif + + +LOCAL(void) +start_iMCU_row (j_compress_ptr cinfo) +/* Reset within-iMCU-row counters for a new row */ +{ + j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; + c_diff_ptr diff = (c_diff_ptr) losslsc->diff_private; + + /* In an interleaved scan, an MCU row is the same as an iMCU row. + * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows. + * But at the bottom of the image, process only what's left. + */ + if (cinfo->comps_in_scan > 1) { + diff->MCU_rows_per_iMCU_row = 1; + } else { + if (diff->iMCU_row_num < (cinfo->total_iMCU_rows-1)) + diff->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor; + else + diff->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height; + } + + diff->mcu_ctr = 0; + diff->MCU_vert_offset = 0; +} + + +/* + * Initialize for a processing pass. + */ + +METHODDEF(void) +start_pass_diff (j_compress_ptr cinfo, J_BUF_MODE pass_mode) +{ + j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; + c_diff_ptr diff = (c_diff_ptr) losslsc->diff_private; + + diff->iMCU_row_num = 0; + start_iMCU_row(cinfo); + + switch (pass_mode) { + case JBUF_PASS_THRU: + if (diff->whole_image[0] != NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + losslsc->pub.compress_data = compress_data; + break; +#ifdef FULL_SAMP_BUFFER_SUPPORTED + case JBUF_SAVE_AND_PASS: + if (diff->whole_image[0] == NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + losslsc->pub.compress_data = compress_first_pass; + break; + case JBUF_CRANK_DEST: + if (diff->whole_image[0] == NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + losslsc->pub.compress_data = compress_output; + break; +#endif + default: + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + break; + } +} + + +#define SWAP_ROWS(rowa,rowb) {JSAMPROW temp; temp=rowa; rowa=rowb; rowb=temp;} + +/* + * Process some data in the single-pass case. + * We process the equivalent of one fully interleaved MCU row ("iMCU" row) + * per call, ie, v_samp_factor rows for each component in the image. + * Returns TRUE if the iMCU row is completed, FALSE if suspended. + * + * NB: input_buf contains a plane for each component in image, + * which we index according to the component's SOF position. + */ + +METHODDEF(boolean) +compress_data (j_compress_ptr cinfo, JSAMPIMAGE input_buf) +{ + j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; + c_diff_ptr diff = (c_diff_ptr) losslsc->diff_private; + JDIMENSION MCU_col_num; /* index of current MCU within row */ + JDIMENSION MCU_count; /* number of MCUs encoded */ + /* JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1; */ + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + int comp, ci, yoffset, samp_row, samp_rows, samps_across; + jpeg_component_info *compptr; + + /* Loop to write as much as one whole iMCU row */ + for (yoffset = diff->MCU_vert_offset; yoffset < diff->MCU_rows_per_iMCU_row; + yoffset++) { + + MCU_col_num = diff->mcu_ctr; + + /* Scale and predict each scanline of the MCU-row separately. + * + * Note: We only do this if we are at the start of a MCU-row, ie, + * we don't want to reprocess a row suspended by the output. + */ + if (MCU_col_num == 0) { + for (comp = 0; comp < cinfo->comps_in_scan; comp++) { + compptr = cinfo->cur_comp_info[comp]; + ci = compptr->component_index; + if (diff->iMCU_row_num < last_iMCU_row) + samp_rows = compptr->v_samp_factor; + else { + /* NB: can't use last_row_height here, since may not be set! */ + samp_rows = (int) (compptr->height_in_data_units % compptr->v_samp_factor); + if (samp_rows == 0) samp_rows = compptr->v_samp_factor; + else { + /* Fill dummy difference rows at the bottom edge with zeros, which + * will encode to the smallest amount of data. + */ + for (samp_row = samp_rows; samp_row < compptr->v_samp_factor; + samp_row++) + MEMZERO(diff->diff_buf[ci][samp_row], + jround_up((long) compptr->width_in_data_units, + (long) compptr->h_samp_factor) * SIZEOF(JDIFF)); + } + } + samps_across = compptr->width_in_data_units; + + for (samp_row = 0; samp_row < samp_rows; samp_row++) { + (*losslsc->scaler_scale) (cinfo, + input_buf[ci][samp_row], + diff->cur_row[ci], samps_across); + (*losslsc->predict_difference[ci]) (cinfo, ci, + diff->cur_row[ci], + diff->prev_row[ci], + diff->diff_buf[ci][samp_row], + samps_across); + SWAP_ROWS(diff->cur_row[ci], diff->prev_row[ci]); + } + } + } + + /* Try to write the MCU-row (or remaining portion of suspended MCU-row). */ + MCU_count = + (*losslsc->entropy_encode_mcus) (cinfo, + diff->diff_buf, yoffset, MCU_col_num, + cinfo->MCUs_per_row - MCU_col_num); + if (MCU_count != cinfo->MCUs_per_row - MCU_col_num) { + /* Suspension forced; update state counters and exit */ + diff->MCU_vert_offset = yoffset; + diff->mcu_ctr += MCU_col_num; + return FALSE; + } + + /* Completed an MCU row, but perhaps not an iMCU row */ + diff->mcu_ctr = 0; + } + + /* Completed the iMCU row, advance counters for next one */ + diff->iMCU_row_num++; + start_iMCU_row(cinfo); + return TRUE; +} + + +#ifdef FULL_SAMP_BUFFER_SUPPORTED + +/* + * Process some data in the first pass of a multi-pass case. + * We process the equivalent of one fully interleaved MCU row ("iMCU" row) + * per call, ie, v_samp_factor rows for each component in the image. + * This amount of data is read from the source buffer and saved into the + * virtual arrays. + * + * We must also emit the data to the compressor. This is conveniently + * done by calling compress_output() after we've loaded the current strip + * of the virtual arrays. + * + * NB: input_buf contains a plane for each component in image. All components + * are loaded into the virtual arrays in this pass. However, it may be that + * only a subset of the components are emitted to the compressor during + * this first pass; be careful about looking at the scan-dependent variables + * (MCU dimensions, etc). + */ + +METHODDEF(boolean) +compress_first_pass (j_compress_ptr cinfo, JSAMPIMAGE input_buf) +{ + j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; + c_diff_ptr diff = (c_diff_ptr) losslsc->diff_private; + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + JDIMENSION samps_across; + int ci, samp_row, samp_rows; + JSAMPARRAY buffer[MAX_COMPONENTS]; + jpeg_component_info *compptr; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Align the virtual buffers for this component. */ + buffer[ci] = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, diff->whole_image[ci], + diff->iMCU_row_num * compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, TRUE); + + /* Count non-dummy sample rows in this iMCU row. */ + if (diff->iMCU_row_num < last_iMCU_row) + samp_rows = compptr->v_samp_factor; + else { + /* NB: can't use last_row_height here, since may not be set! */ + samp_rows = (int) (compptr->height_in_data_units % compptr->v_samp_factor); + if (samp_rows == 0) samp_rows = compptr->v_samp_factor; + } + samps_across = compptr->width_in_data_units; + + /* Perform point transform scaling and prediction/differencing for all + * non-dummy rows in this iMCU row. Each call on these functions + * process a complete row of samples. + */ + for (samp_row = 0; samp_row < samp_rows; samp_row++) { + MEMCOPY(buffer[ci][samp_row], input_buf[ci][samp_row], + samps_across * SIZEOF(JSAMPLE)); + } + } + + /* NB: compress_output will increment iMCU_row_num if successful. + * A suspension return will result in redoing all the work above next time. + */ + + /* Emit data to the compressor, sharing code with subsequent passes */ + return compress_output(cinfo, input_buf); +} + + +/* + * Process some data in subsequent passes of a multi-pass case. + * We process the equivalent of one fully interleaved MCU row ("iMCU" row) + * per call, ie, v_samp_factor rows for each component in the scan. + * The data is obtained from the virtual arrays and fed to the compressor. + * Returns TRUE if the iMCU row is completed, FALSE if suspended. + * + * NB: input_buf is ignored; it is likely to be a NULL pointer. + */ + +METHODDEF(boolean) +compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf) +{ + j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; + c_diff_ptr diff = (c_diff_ptr) losslsc->diff_private; + /* JDIMENSION MCU_col_num; */ /* index of current MCU within row */ + /* JDIMENSION MCU_count; */ /* number of MCUs encoded */ + int comp, ci /* , yoffset */ ; + JSAMPARRAY buffer[MAX_COMPONENTS]; + jpeg_component_info *compptr; + (void)input_buf; + + /* Align the virtual buffers for the components used in this scan. + * NB: during first pass, this is safe only because the buffers will + * already be aligned properly, so jmemmgr.c won't need to do any I/O. + */ + for (comp = 0; comp < cinfo->comps_in_scan; comp++) { + compptr = cinfo->cur_comp_info[comp]; + ci = compptr->component_index; + buffer[ci] = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, diff->whole_image[ci], + diff->iMCU_row_num * compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } + + return compress_data(cinfo, buffer); +} + +#endif /* FULL_SAMP_BUFFER_SUPPORTED */ + + +/* + * Initialize difference buffer controller. + */ + +GLOBAL(void) +jinit_c_diff_controller (j_compress_ptr cinfo, boolean need_full_buffer) +{ + j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; + c_diff_ptr diff; + int ci, row; + jpeg_component_info *compptr; + + diff = (c_diff_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(c_diff_controller)); + losslsc->diff_private = (void *) diff; + losslsc->diff_start_pass = start_pass_diff; + + /* Create the prediction row buffers. */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + diff->cur_row[ci] = *(*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) jround_up((long) compptr->width_in_data_units, + (long) compptr->h_samp_factor), + (JDIMENSION) 1); + diff->prev_row[ci] = *(*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) jround_up((long) compptr->width_in_data_units, + (long) compptr->h_samp_factor), + (JDIMENSION) 1); + } + + /* Create the difference buffer. */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + diff->diff_buf[ci] = (*cinfo->mem->alloc_darray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) jround_up((long) compptr->width_in_data_units, + (long) compptr->h_samp_factor), + (JDIMENSION) compptr->v_samp_factor); + /* Prefill difference rows with zeros. We do this because only actual + * data is placed in the buffers during prediction/differencing, leaving + * any dummy differences at the right edge as zeros, which will encode + * to the smallest amount of data. + */ + for (row = 0; row < compptr->v_samp_factor; row++) + MEMZERO(diff->diff_buf[ci][row], + jround_up((long) compptr->width_in_data_units, + (long) compptr->h_samp_factor) * SIZEOF(JDIFF)); + } + + /* Create the sample buffer. */ + if (need_full_buffer) { +#ifdef FULL_SAMP_BUFFER_SUPPORTED + /* Allocate a full-image virtual array for each component, */ + /* padded to a multiple of samp_factor differences in each direction. */ + int ci; + jpeg_component_info *compptr; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + diff->whole_image[ci] = (*cinfo->mem->request_virt_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, + (JDIMENSION) jround_up((long) compptr->width_in_data_units, + (long) compptr->h_samp_factor), + (JDIMENSION) jround_up((long) compptr->height_in_data_units, + (long) compptr->v_samp_factor), + (JDIMENSION) compptr->v_samp_factor); + } +#else + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); +#endif + } else + diff->whole_image[0] = NULL; /* flag for no virtual arrays */ +} + +#endif /* C_LOSSLESS_SUPPORTED */ diff --git a/gdcm/Utilities/gdcmjpeg/jchuff.c b/gdcm/Utilities/gdcmjpeg/jchuff.c new file mode 100644 index 0000000..439b123 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jchuff.c @@ -0,0 +1,274 @@ +/* + * jchuff.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains Huffman entropy decoding routines which are shared + * by the sequential, progressive and lossless decoders. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jchuff.h" /* Declarations shared with jc*huff.c */ + + +/* + * Compute the derived values for a Huffman table. + * This routine also performs some validation checks on the table. + */ + +GLOBAL(void) +jpeg_make_c_derived_tbl (j_compress_ptr cinfo, boolean isDC, int tblno, + c_derived_tbl ** pdtbl) +{ + JHUFF_TBL *htbl; + c_derived_tbl *dtbl; + int p, i, l, lastp, si, maxsymbol; + char huffsize[257]; + unsigned int huffcode[257]; + unsigned int code; + + /* Note that huffsize[] and huffcode[] are filled in code-length order, + * paralleling the order of the symbols themselves in htbl->huffval[]. + */ + + /* Find the input Huffman table */ + if (tblno < 0 || tblno >= NUM_HUFF_TBLS) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tblno); + htbl = + isDC ? cinfo->dc_huff_tbl_ptrs[tblno] : cinfo->ac_huff_tbl_ptrs[tblno]; + if (htbl == NULL) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tblno); + + /* Allocate a workspace if we haven't already done so. */ + if (*pdtbl == NULL) + *pdtbl = (c_derived_tbl *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(c_derived_tbl)); + dtbl = *pdtbl; + + /* Figure C.1: make table of Huffman code length for each symbol */ + + p = 0; + for (l = 1; l <= 16; l++) { + i = (int) htbl->bits[l]; + if (i < 0 || p + i > 256) /* protect against table overrun */ + ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); + while (i--) + huffsize[p++] = (char) l; + } + huffsize[p] = 0; + lastp = p; + + /* Figure C.2: generate the codes themselves */ + /* We also validate that the counts represent a legal Huffman code tree. */ + + code = 0; + si = huffsize[0]; + p = 0; + while (huffsize[p]) { + while (((int) huffsize[p]) == si) { + huffcode[p++] = code; + code++; + } + /* code is now 1 more than the last code used for codelength si; but + * it must still fit in si bits, since no code is allowed to be all ones. + * BUG FIX 2001-09-03: Comparison must be >, not >= + */ + if (((INT32) code) > (((INT32) 1) << si)) + ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); + code <<= 1; + si++; + } + + /* Figure C.3: generate encoding tables */ + /* These are code and size indexed by symbol value */ + + /* Set all codeless symbols to have code length 0; + * this lets us detect duplicate VAL entries here, and later + * allows emit_bits to detect any attempt to emit such symbols. + */ + MEMZERO(dtbl->ehufsi, SIZEOF(dtbl->ehufsi)); + + /* This is also a convenient place to check for out-of-range + * and duplicated VAL entries. We allow 0..255 for AC symbols + * but only 0..16 for DC. (We could constrain them further + * based on data depth and mode, but this seems enough.) + */ + maxsymbol = isDC ? 16 : 255; + + for (p = 0; p < lastp; p++) { + i = htbl->huffval[p]; + if (i < 0 || i > maxsymbol || dtbl->ehufsi[i]) + ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); + dtbl->ehufco[i] = huffcode[p]; + dtbl->ehufsi[i] = huffsize[p]; + } +} + + +/* + * Generate the best Huffman code table for the given counts, fill htbl. + * + * The JPEG standard requires that no symbol be assigned a codeword of all + * one bits (so that padding bits added at the end of a compressed segment + * can't look like a valid code). Because of the canonical ordering of + * codewords, this just means that there must be an unused slot in the + * longest codeword length category. Section K.2 of the JPEG spec suggests + * reserving such a slot by pretending that symbol 256 is a valid symbol + * with count 1. In theory that's not optimal; giving it count zero but + * including it in the symbol set anyway should give a better Huffman code. + * But the theoretically better code actually seems to come out worse in + * practice, because it produces more all-ones bytes (which incur stuffed + * zero bytes in the final file). In any case the difference is tiny. + * + * The JPEG standard requires Huffman codes to be no more than 16 bits long. + * If some symbols have a very small but nonzero probability, the Huffman tree + * must be adjusted to meet the code length restriction. We currently use + * the adjustment method suggested in JPEG section K.2. This method is *not* + * optimal; it may not choose the best possible limited-length code. But + * typically only very-low-frequency symbols will be given less-than-optimal + * lengths, so the code is almost optimal. Experimental comparisons against + * an optimal limited-length-code algorithm indicate that the difference is + * microscopic --- usually less than a hundredth of a percent of total size. + * So the extra complexity of an optimal algorithm doesn't seem worthwhile. + */ + +GLOBAL(void) +jpeg_gen_optimal_table (j_compress_ptr cinfo, JHUFF_TBL * htbl, long freq[]) +{ +#define MAX_CLEN 32 /* assumed maximum initial code length */ + UINT8 bits[MAX_CLEN+1]; /* bits[k] = # of symbols with code length k */ + int codesize[257]; /* codesize[k] = code length of symbol k */ + int others[257]; /* next symbol in current branch of tree */ + int c1, c2; + int p, i, j; + long v; + + /* This algorithm is explained in section K.2 of the JPEG standard */ + + MEMZERO(bits, SIZEOF(bits)); + MEMZERO(codesize, SIZEOF(codesize)); + for (i = 0; i < 257; i++) + others[i] = -1; /* init links to empty */ + + freq[256] = 1; /* make sure 256 has a nonzero count */ + /* Including the pseudo-symbol 256 in the Huffman procedure guarantees + * that no real symbol is given code-value of all ones, because 256 + * will be placed last in the largest codeword category. + */ + + /* Huffman's basic algorithm to assign optimal code lengths to symbols */ + + for (;;) { + /* Find the smallest nonzero frequency, set c1 = its symbol */ + /* In case of ties, take the larger symbol number */ + c1 = -1; + v = 1000000000L; + for (i = 0; i <= 256; i++) { + if (freq[i] && freq[i] <= v) { + v = freq[i]; + c1 = i; + } + } + + /* Find the next smallest nonzero frequency, set c2 = its symbol */ + /* In case of ties, take the larger symbol number */ + c2 = -1; + v = 1000000000L; + for (i = 0; i <= 256; i++) { + if (freq[i] && freq[i] <= v && i != c1) { + v = freq[i]; + c2 = i; + } + } + + /* Done if we've merged everything into one frequency */ + if (c2 < 0) + break; + + /* Else merge the two counts/trees */ + freq[c1] += freq[c2]; + freq[c2] = 0; + + /* Increment the codesize of everything in c1's tree branch */ + codesize[c1]++; + while (others[c1] >= 0) { + c1 = others[c1]; + codesize[c1]++; + } + + others[c1] = c2; /* chain c2 onto c1's tree branch */ + + /* Increment the codesize of everything in c2's tree branch */ + codesize[c2]++; + while (others[c2] >= 0) { + c2 = others[c2]; + codesize[c2]++; + } + } + + /* Now count the number of symbols of each code length */ + for (i = 0; i <= 256; i++) { + if (codesize[i]) { + /* The JPEG standard seems to think that this can't happen, */ + /* but I'm paranoid... */ + if (codesize[i] > MAX_CLEN) + ERREXIT(cinfo, JERR_HUFF_CLEN_OVERFLOW); + + bits[codesize[i]]++; + } + } + + /* JPEG doesn't allow symbols with code lengths over 16 bits, so if the pure + * Huffman procedure assigned any such lengths, we must adjust the coding. + * Here is what the JPEG spec says about how this next bit works: + * Since symbols are paired for the longest Huffman code, the symbols are + * removed from this length category two at a time. The prefix for the pair + * (which is one bit shorter) is allocated to one of the pair; then, + * skipping the BITS entry for that prefix length, a code word from the next + * shortest nonzero BITS entry is converted into a prefix for two code words + * one bit longer. + */ + + for (i = MAX_CLEN; i > 16; i--) { + while (bits[i] > 0) { + j = i - 2; /* find length of new prefix to be used */ + while (bits[j] == 0) + j--; + + bits[i] -= 2; /* remove two symbols */ + bits[i-1]++; /* one goes in this length */ + bits[j+1] += 2; /* two new symbols in this length */ + bits[j]--; /* symbol of this length is now a prefix */ + } + } + + /* Remove the count for the pseudo-symbol 256 from the largest codelength */ + while (bits[i] == 0) /* find largest codelength still in use */ + i--; + bits[i]--; + + /* Return final symbol counts (only for lengths 0..16) */ + MEMCOPY(htbl->bits, bits, SIZEOF(htbl->bits)); + + /* Return a list of the symbols sorted by code length */ + /* It's not real clear to me why we don't need to consider the codelength + * changes made above, but the JPEG spec seems to think this works. + */ + p = 0; + for (i = 1; i <= MAX_CLEN; i++) { + for (j = 0; j <= 255; j++) { + if (codesize[j] == i) { + htbl->huffval[p] = (UINT8) j; + p++; + } + } + } + + /* Set sent_table FALSE so updated table will be written to JPEG file. */ + htbl->sent_table = FALSE; +} diff --git a/gdcm/Utilities/gdcmjpeg/jchuff.h b/gdcm/Utilities/gdcmjpeg/jchuff.h new file mode 100644 index 0000000..6b0570e --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jchuff.h @@ -0,0 +1,54 @@ +/* + * jchuff.h + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains declarations for Huffman entropy encoding routines + * that are shared between the sequential encoder (jchuff.c) and the + * progressive encoder (jcphuff.c). No other modules need to see these. + */ + +/* The legal range of a DCT coefficient is + * -1024 .. +1023 for 8-bit data; + * -16384 .. +16383 for 12-bit data. + * Hence the magnitude should always fit in 10 or 14 bits respectively. + */ + +#if BITS_IN_JSAMPLE == 8 +#define MAX_COEF_BITS 10 +#else +#define MAX_COEF_BITS 14 +#endif + +/* The legal range of a spatial difference is + * -32767 .. +32768. + * Hence the magnitude should always fit in 16 bits. + */ + +#define MAX_DIFF_BITS 16 + +/* Derived data constructed for each Huffman table */ + +typedef struct { + unsigned int ehufco[256]; /* code for each symbol */ + char ehufsi[256]; /* length of code for each symbol */ + /* If no code has been allocated for a symbol S, ehufsi[S] contains 0 */ +} c_derived_tbl; + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_make_c_derived_tbl jMkCDerived +#define jpeg_gen_optimal_table jGenOptTbl +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + +/* Expand a Huffman table definition into the derived format */ +EXTERN(void) jpeg_make_c_derived_tbl + JPP((j_compress_ptr cinfo, boolean isDC, int tblno, + c_derived_tbl ** pdtbl)); + +/* Generate an optimal table definition given the specified counts */ +EXTERN(void) jpeg_gen_optimal_table + JPP((j_compress_ptr cinfo, JHUFF_TBL * htbl, long freq[])); diff --git a/gdcm/Utilities/gdcmjpeg/jcinit.c b/gdcm/Utilities/gdcmjpeg/jcinit.c new file mode 100644 index 0000000..b485a8e --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jcinit.c @@ -0,0 +1,57 @@ +/* + * jcinit.c + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains initialization logic for the JPEG compressor. + * This routine is in charge of selecting the modules to be executed and + * making an initialization call to each one. + * + * Logically, this code belongs in jcmaster.c. It's split out because + * linking this routine implies linking the entire compression library. + * For a transcoding-only application, we want to be able to use jcmaster.c + * without linking in the whole library. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * Master selection of compression modules. + * This is done once at the start of processing an image. We determine + * which modules will be used and give them appropriate initialization calls. + */ + +GLOBAL(void) +jinit_compress_master (j_compress_ptr cinfo) +{ + /* Initialize master control (includes parameter checking/processing) */ + jinit_c_master_control(cinfo, FALSE /* full compression */); + + /* Initialize compression codec */ + jinit_c_codec(cinfo); + + /* Preprocessing */ + if (! cinfo->raw_data_in) { + jinit_color_converter(cinfo); + jinit_downsampler(cinfo); + jinit_c_prep_controller(cinfo, FALSE /* never need full buffer here */); + } + + jinit_c_main_controller(cinfo, FALSE /* never need full buffer here */); + + jinit_marker_writer(cinfo); + + /* We can now tell the memory manager to allocate virtual arrays. */ + (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo); + + /* Write the datastream header (SOI) immediately. + * Frame and scan headers are postponed till later. + * This lets application insert special markers after the SOI. + */ + (*cinfo->marker->write_file_header) (cinfo); +} diff --git a/gdcm/Utilities/gdcmjpeg/jclhuff.c b/gdcm/Utilities/gdcmjpeg/jclhuff.c new file mode 100644 index 0000000..cbcc23d --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jclhuff.c @@ -0,0 +1,602 @@ +/* + * jclhuff.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains Huffman entropy encoding routines for lossless JPEG. + * + * Much of the complexity here has to do with supporting output suspension. + * If the data destination module demands suspension, we want to be able to + * back up to the start of the current MCU. To do this, we copy state + * variables into local working storage, and update them back to the + * permanent JPEG objects only upon successful completion of an MCU. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jlossls.h" /* Private declarations for lossless codec */ +#include "jchuff.h" /* Declarations shared with jc*huff.c */ + + +/* Expanded entropy encoder object for Huffman encoding. + * + * The savable_state subrecord contains fields that change within an MCU, + * but must not be updated permanently until we complete the MCU. + */ + +typedef struct { + INT32 put_buffer; /* current bit-accumulation buffer */ + int put_bits; /* # of bits now in it */ +} savable_state; + +/* This macro is to work around compilers with missing or broken + * structure assignment. You'll need to fix this code if you have + * such a compiler and you change MAX_COMPS_IN_SCAN. + */ + +#ifndef NO_STRUCT_ASSIGN +#define ASSIGN_STATE(dest,src) ((dest) = (src)) +#else +#define ASSIGN_STATE(dest,src) \ + ((dest).put_buffer = (src).put_buffer, \ + (dest).put_bits = (src).put_bits) +#endif + + +typedef struct { + int ci, yoffset, MCU_width; +} lhe_input_ptr_info; + + +typedef struct { + savable_state saved; /* Bit buffer at start of MCU */ + + /* These fields are NOT loaded into local working state. */ + unsigned int restarts_to_go; /* MCUs left in this restart interval */ + int next_restart_num; /* next restart number to write (0-7) */ + + /* Pointers to derived tables (these workspaces have image lifespan) */ + c_derived_tbl * derived_tbls[NUM_HUFF_TBLS]; + + /* Pointers to derived tables to be used for each data unit within an MCU */ + c_derived_tbl * cur_tbls[C_MAX_DATA_UNITS_IN_MCU]; + +#ifdef ENTROPY_OPT_SUPPORTED /* Statistics tables for optimization */ + long * count_ptrs[NUM_HUFF_TBLS]; + + /* Pointers to stats tables to be used for each data unit within an MCU */ + long * cur_counts[C_MAX_DATA_UNITS_IN_MCU]; +#endif + + /* Pointers to the proper input difference row for each group of data units + * within an MCU. For each component, there are Vi groups of Hi data units. + */ + JDIFFROW input_ptr[C_MAX_DATA_UNITS_IN_MCU]; + + /* Number of input pointers in use for the current MCU. This is the sum + * of all Vi in the MCU. + */ + int num_input_ptrs; + + /* Information used for positioning the input pointers within the input + * difference rows. + */ + lhe_input_ptr_info input_ptr_info[C_MAX_DATA_UNITS_IN_MCU]; + + /* Index of the proper input pointer for each data unit within an MCU */ + int input_ptr_index[C_MAX_DATA_UNITS_IN_MCU]; + +} lhuff_entropy_encoder; + +typedef lhuff_entropy_encoder * lhuff_entropy_ptr; + +/* Working state while writing an MCU. + * This struct contains all the fields that are needed by subroutines. + */ + +typedef struct { + JOCTET * next_output_byte; /* => next byte to write in buffer */ + size_t free_in_buffer; /* # of byte spaces remaining in buffer */ + savable_state cur; /* Current bit buffer & DC state */ + j_compress_ptr cinfo; /* dump_buffer needs access to this */ +} working_state; + + +/* Forward declarations */ +METHODDEF(JDIMENSION) encode_mcus_huff (j_compress_ptr cinfo, + JDIFFIMAGE diff_buf, + JDIMENSION MCU_row_num, + JDIMENSION MCU_col_num, + JDIMENSION nMCU); +METHODDEF(void) finish_pass_huff JPP((j_compress_ptr cinfo)); +#ifdef ENTROPY_OPT_SUPPORTED +METHODDEF(JDIMENSION) encode_mcus_gather (j_compress_ptr cinfo, + JDIFFIMAGE diff_buf, + JDIMENSION MCU_row_num, + JDIMENSION MCU_col_num, + JDIMENSION nMCU); +METHODDEF(void) finish_pass_gather JPP((j_compress_ptr cinfo)); +#endif + + +/* + * Initialize for a Huffman-compressed scan. + * If gather_statistics is TRUE, we do not output anything during the scan, + * just count the Huffman symbols used and generate Huffman code tables. + */ + +METHODDEF(void) +start_pass_huff (j_compress_ptr cinfo, boolean gather_statistics) +{ + j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; + lhuff_entropy_ptr entropy = (lhuff_entropy_ptr) losslsc->entropy_private; + int ci, dctbl, sampn, ptrn, yoffset, xoffset; + jpeg_component_info * compptr; + + if (gather_statistics) { +#ifdef ENTROPY_OPT_SUPPORTED + losslsc->entropy_encode_mcus = encode_mcus_gather; + losslsc->pub.entropy_finish_pass = finish_pass_gather; +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else { + losslsc->entropy_encode_mcus = encode_mcus_huff; + losslsc->pub.entropy_finish_pass = finish_pass_huff; + } + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + dctbl = compptr->dc_tbl_no; + if (gather_statistics) { +#ifdef ENTROPY_OPT_SUPPORTED + /* Check for invalid table indexes */ + /* (make_c_derived_tbl does this in the other path) */ + if (dctbl < 0 || dctbl >= NUM_HUFF_TBLS) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, dctbl); + /* Allocate and zero the statistics tables */ + /* Note that jpeg_gen_optimal_table expects 257 entries in each table! */ + if (entropy->count_ptrs[dctbl] == NULL) + entropy->count_ptrs[dctbl] = (long *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + 257 * SIZEOF(long)); + MEMZERO(entropy->count_ptrs[dctbl], 257 * SIZEOF(long)); +#endif + } else { + /* Compute derived values for Huffman tables */ + /* We may do this more than once for a table, but it's not expensive */ + jpeg_make_c_derived_tbl(cinfo, TRUE, dctbl, + & entropy->derived_tbls[dctbl]); + } + } + + /* Precalculate encoding info for each sample in an MCU of this scan */ + for (sampn = 0, ptrn = 0; sampn < cinfo->data_units_in_MCU;) { + compptr = cinfo->cur_comp_info[cinfo->MCU_membership[sampn]]; + ci = compptr->component_index; + /* ci = cinfo->MCU_membership[sampn]; + compptr = cinfo->cur_comp_info[ci];*/ + for (yoffset = 0; yoffset < compptr->MCU_height; yoffset++, ptrn++) { + /* Precalculate the setup info for each input pointer */ + entropy->input_ptr_info[ptrn].ci = ci; + entropy->input_ptr_info[ptrn].yoffset = yoffset; + entropy->input_ptr_info[ptrn].MCU_width = compptr->MCU_width; + for (xoffset = 0; xoffset < compptr->MCU_width; xoffset++, sampn++) { + /* Precalculate the input pointer index for each sample */ + entropy->input_ptr_index[sampn] = ptrn; + /* Precalculate which tables to use for each sample */ + entropy->cur_tbls[sampn] = entropy->derived_tbls[compptr->dc_tbl_no]; + entropy->cur_counts[sampn] = entropy->count_ptrs[compptr->dc_tbl_no]; + } + } + } + entropy->num_input_ptrs = ptrn; + + /* Initialize bit buffer to empty */ + entropy->saved.put_buffer = 0; + entropy->saved.put_bits = 0; + + /* Initialize restart stuff */ + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num = 0; +} + + +/* Outputting bytes to the file */ + +/* Emit a byte, taking 'action' if must suspend. */ +#define emit_byte(state,val,action) \ + { *(state)->next_output_byte++ = (JOCTET) (val); \ + if (--(state)->free_in_buffer == 0) \ + if (! dump_buffer(state)) \ + { action; } } + + +LOCAL(boolean) +dump_buffer (working_state * state) +/* Empty the output buffer; return TRUE if successful, FALSE if must suspend */ +{ + struct jpeg_destination_mgr * dest = state->cinfo->dest; + + if (! (*dest->empty_output_buffer) (state->cinfo)) + return FALSE; + /* After a successful buffer dump, must reset buffer pointers */ + state->next_output_byte = dest->next_output_byte; + state->free_in_buffer = dest->free_in_buffer; + return TRUE; +} + + +/* Outputting bits to the file */ + +/* Only the right 24 bits of put_buffer are used; the valid bits are + * left-justified in this part. At most 16 bits can be passed to emit_bits + * in one call, and we never retain more than 7 bits in put_buffer + * between calls, so 24 bits are sufficient. + */ + +INLINE +LOCAL(boolean) +emit_bits (working_state * state, unsigned int code, int size) +/* Emit some bits; return TRUE if successful, FALSE if must suspend */ +{ + /* This routine is heavily used, so it's worth coding tightly. */ + register INT32 put_buffer = (INT32) code; + register int put_bits = state->cur.put_bits; + + /* if size is 0, caller used an invalid Huffman table entry */ + if (size == 0) + ERREXIT(state->cinfo, JERR_HUFF_MISSING_CODE); + + put_buffer &= (((INT32) 1)<cur.put_buffer; /* and merge with old buffer contents */ + + while (put_bits >= 8) { + int c = (int) ((put_buffer >> 16) & 0xFF); + + emit_byte(state, c, return FALSE); + if (c == 0xFF) { /* need to stuff a zero byte? */ + emit_byte(state, 0, return FALSE); + } + put_buffer <<= 8; + put_bits -= 8; + } + + state->cur.put_buffer = put_buffer; /* update state variables */ + state->cur.put_bits = put_bits; + + return TRUE; +} + + +LOCAL(boolean) +flush_bits (working_state * state) +{ + if (! emit_bits(state, 0x7F, 7)) /* fill any partial byte with ones */ + return FALSE; + state->cur.put_buffer = 0; /* and reset bit-buffer to empty */ + state->cur.put_bits = 0; + return TRUE; +} + + +/* + * Emit a restart marker & resynchronize predictions. + */ + +LOCAL(boolean) +emit_restart (working_state * state, int restart_num) +{ + /* int ci; */ + + if (! flush_bits(state)) + return FALSE; + + emit_byte(state, 0xFF, return FALSE); + emit_byte(state, JPEG_RST0 + restart_num, return FALSE); + + /* The restart counter is not updated until we successfully write the MCU. */ + + return TRUE; +} + + +/* + * Encode and output one nMCU's worth of Huffman-compressed differences. + */ + +METHODDEF(JDIMENSION) +encode_mcus_huff (j_compress_ptr cinfo, JDIFFIMAGE diff_buf, + JDIMENSION MCU_row_num, JDIMENSION MCU_col_num, + JDIMENSION nMCU) +{ + j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; + lhuff_entropy_ptr entropy = (lhuff_entropy_ptr) losslsc->entropy_private; + working_state state; + unsigned int mcu_num; + int sampn, ci, yoffset, MCU_width, ptrn; + /* jpeg_component_info * compptr; */ + + /* Load up working state */ + state.next_output_byte = cinfo->dest->next_output_byte; + state.free_in_buffer = cinfo->dest->free_in_buffer; + ASSIGN_STATE(state.cur, entropy->saved); + state.cinfo = cinfo; + + /* Emit restart marker if needed */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + if (! emit_restart(&state, entropy->next_restart_num)) + return 0; + } + + /* Set input pointer locations based on MCU_col_num */ + for (ptrn = 0; ptrn < entropy->num_input_ptrs; ptrn++) { + ci = entropy->input_ptr_info[ptrn].ci; + yoffset = entropy->input_ptr_info[ptrn].yoffset; + MCU_width = entropy->input_ptr_info[ptrn].MCU_width; + entropy->input_ptr[ptrn] = + diff_buf[ci][MCU_row_num + yoffset] + (MCU_col_num * MCU_width); + } + + for (mcu_num = 0; mcu_num < nMCU; mcu_num++) { + + /* Inner loop handles the samples in the MCU */ + for (sampn = 0; sampn < cinfo->data_units_in_MCU; sampn++) { + register int temp, temp2 /* , temp3 */ ; + register int nbits; + c_derived_tbl *dctbl = entropy->cur_tbls[sampn]; + + /* Encode the difference per section H.1.2.2 */ + + /* Input the sample difference */ + temp = *entropy->input_ptr[entropy->input_ptr_index[sampn]]++; + + if (temp & 0x8000) { /* instead of temp < 0 */ + temp = (-temp) & 0x7FFF; /* absolute value, mod 2^16 */ + if (temp == 0) /* special case: magnitude = 32768 */ + temp2 = temp = 0x8000; + temp2 = ~ temp; /* one's complement of magnitude */ + } else { + temp &= 0x7FFF; /* abs value mod 2^16 */ + temp2 = temp; /* magnitude */ + } + + /* Find the number of bits needed for the magnitude of the difference */ + nbits = 0; + while (temp) { + nbits++; + temp >>= 1; + } + /* Check for out-of-range difference values. + */ + if (nbits > MAX_DIFF_BITS) + ERREXIT(cinfo, JERR_BAD_DIFF); + + /* Emit the Huffman-coded symbol for the number of bits */ + if (! emit_bits(&state, dctbl->ehufco[nbits], dctbl->ehufsi[nbits])) + return mcu_num; + + /* Emit that number of bits of the value, if positive, */ + /* or the complement of its magnitude, if negative. */ + if (nbits && /* emit_bits rejects calls with size 0 */ + nbits != 16) /* special case: no bits should be emitted */ + if (! emit_bits(&state, (unsigned int) temp2, nbits)) + return mcu_num; + } + + /* Completed MCU, so update state */ + cinfo->dest->next_output_byte = state.next_output_byte; + cinfo->dest->free_in_buffer = state.free_in_buffer; + ASSIGN_STATE(entropy->saved, state.cur); + + /* Update restart-interval state too */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num++; + entropy->next_restart_num &= 7; + } + entropy->restarts_to_go--; + } + + } + + return nMCU; +} + + +/* + * Finish up at the end of a Huffman-compressed scan. + */ + +METHODDEF(void) +finish_pass_huff (j_compress_ptr cinfo) +{ + j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; + lhuff_entropy_ptr entropy = (lhuff_entropy_ptr) losslsc->entropy_private; + working_state state; + + /* Load up working state ... flush_bits needs it */ + state.next_output_byte = cinfo->dest->next_output_byte; + state.free_in_buffer = cinfo->dest->free_in_buffer; + ASSIGN_STATE(state.cur, entropy->saved); + state.cinfo = cinfo; + + /* Flush out the last data */ + if (! flush_bits(&state)) + ERREXIT(cinfo, JERR_CANT_SUSPEND); + + /* Update state */ + cinfo->dest->next_output_byte = state.next_output_byte; + cinfo->dest->free_in_buffer = state.free_in_buffer; + ASSIGN_STATE(entropy->saved, state.cur); +} + + +/* + * Huffman coding optimization. + * + * We first scan the supplied data and count the number of uses of each symbol + * that is to be Huffman-coded. (This process MUST agree with the code above.) + * Then we build a Huffman coding tree for the observed counts. + * Symbols which are not needed at all for the particular image are not + * assigned any code, which saves space in the DHT marker as well as in + * the compressed data. + */ + +#ifdef ENTROPY_OPT_SUPPORTED + +/* + * Trial-encode one nMCU's worth of Huffman-compressed differences. + * No data is actually output, so no suspension return is possible. + */ + +METHODDEF(JDIMENSION) +encode_mcus_gather (j_compress_ptr cinfo, JDIFFIMAGE diff_buf, + JDIMENSION MCU_row_num, JDIMENSION MCU_col_num, + JDIMENSION nMCU) +{ + j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; + lhuff_entropy_ptr entropy = (lhuff_entropy_ptr) losslsc->entropy_private; + unsigned int mcu_num; + int sampn, ci, yoffset, MCU_width, ptrn; + /* jpeg_component_info * compptr; */ + + /* Take care of restart intervals if needed */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + /* Update restart state */ + entropy->restarts_to_go = cinfo->restart_interval; + } + entropy->restarts_to_go--; + } + + /* Set input pointer locations based on MCU_col_num */ + for (ptrn = 0; ptrn < entropy->num_input_ptrs; ptrn++) { + ci = entropy->input_ptr_info[ptrn].ci; + yoffset = entropy->input_ptr_info[ptrn].yoffset; + MCU_width = entropy->input_ptr_info[ptrn].MCU_width; + entropy->input_ptr[ptrn] = + diff_buf[ci][MCU_row_num + yoffset] + (MCU_col_num * MCU_width); + } + + for (mcu_num = 0; mcu_num < nMCU; mcu_num++) { + + /* Inner loop handles the samples in the MCU */ + for (sampn = 0; sampn < cinfo->data_units_in_MCU; sampn++) { + register int temp; + register int nbits; + /* c_derived_tbl *dctbl = entropy->cur_tbls[sampn]; */ + long * counts = entropy->cur_counts[sampn]; + + /* Encode the difference per section H.1.2.2 */ + + /* Input the sample difference */ + temp = *entropy->input_ptr[entropy->input_ptr_index[sampn]]++; + + if (temp & 0x8000) { /* instead of temp < 0 */ + temp = (-temp) & 0x7FFF; /* absolute value, mod 2^16 */ + if (temp == 0) /* special case: magnitude = 32768 */ + temp = 0x8000; + } else + temp &= 0x7FFF; /* abs value mod 2^16 */ + + /* Find the number of bits needed for the magnitude of the difference */ + nbits = 0; + while (temp) { + nbits++; + temp >>= 1; + } + /* Check for out-of-range difference values. + */ + if (nbits > MAX_DIFF_BITS) + ERREXIT(cinfo, JERR_BAD_DIFF); + + /* Count the Huffman symbol for the number of bits */ + counts[nbits]++; + } + } + + return nMCU; +} + + +/* + * Finish up a statistics-gathering pass and create the new Huffman tables. + */ + +METHODDEF(void) +finish_pass_gather (j_compress_ptr cinfo) +{ + j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; + lhuff_entropy_ptr entropy = (lhuff_entropy_ptr) losslsc->entropy_private; + int ci, dctbl; + jpeg_component_info * compptr; + JHUFF_TBL **htblptr; + boolean did_dc[NUM_HUFF_TBLS]; + + /* It's important not to apply jpeg_gen_optimal_table more than once + * per table, because it clobbers the input frequency counts! + */ + MEMZERO(did_dc, SIZEOF(did_dc)); + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + dctbl = compptr->dc_tbl_no; + if (! did_dc[dctbl]) { + htblptr = & cinfo->dc_huff_tbl_ptrs[dctbl]; + if (*htblptr == NULL) + *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo); + jpeg_gen_optimal_table(cinfo, *htblptr, entropy->count_ptrs[dctbl]); + did_dc[dctbl] = TRUE; + } + } +} + + +#endif /* ENTROPY_OPT_SUPPORTED */ + + +METHODDEF(boolean) +need_optimization_pass (j_compress_ptr cinfo) +{ + (void)cinfo; + return TRUE; +} + + +/* + * Module initialization routine for Huffman entropy encoding. + */ + +GLOBAL(void) +jinit_lhuff_encoder (j_compress_ptr cinfo) +{ + j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; + lhuff_entropy_ptr entropy; + int i; + + entropy = (lhuff_entropy_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(lhuff_entropy_encoder)); + losslsc->entropy_private = (struct jpeg_entropy_encoder *) entropy; + losslsc->pub.entropy_start_pass = start_pass_huff; + losslsc->pub.need_optimization_pass = need_optimization_pass; + + /* Mark tables unallocated */ + for (i = 0; i < NUM_HUFF_TBLS; i++) { + entropy->derived_tbls[i] = NULL; +#ifdef ENTROPY_OPT_SUPPORTED + entropy->count_ptrs[i] = NULL; +#endif + } +} diff --git a/gdcm/Utilities/gdcmjpeg/jclossls.c b/gdcm/Utilities/gdcmjpeg/jclossls.c new file mode 100644 index 0000000..b00d1fb --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jclossls.c @@ -0,0 +1,82 @@ +/* + * jclossls.c + * + * Copyright (C) 1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the control logic for the lossless JPEG compressor. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jlossls.h" + + +#ifdef C_LOSSLESS_SUPPORTED + +/* + * Initialize for a processing pass. + */ + +METHODDEF(void) +start_pass (j_compress_ptr cinfo, J_BUF_MODE pass_mode) +{ + j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; + + (*losslsc->scaler_start_pass) (cinfo); + (*losslsc->predict_start_pass) (cinfo); + (*losslsc->diff_start_pass) (cinfo, pass_mode); +} + + +/* + * Initialize the lossless compression codec. + * This is called only once, during master selection. + */ + +GLOBAL(void) +jinit_lossless_c_codec(j_compress_ptr cinfo) +{ + j_lossless_c_ptr losslsc; + + /* Create subobject in permanent pool */ + losslsc = (j_lossless_c_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + SIZEOF(jpeg_lossless_c_codec)); + cinfo->codec = (struct jpeg_c_codec *) losslsc; + + /* Initialize sub-modules */ + + /* Scaler */ + jinit_c_scaler(cinfo); + + /* Differencer */ + jinit_differencer(cinfo); + + /* Entropy encoding: either Huffman or arithmetic coding. */ + if (cinfo->arith_code) { +#ifdef WITH_ARITHMETIC_PATCH + jinit_arith_encoder(cinfo); +#else + ERREXIT(cinfo, JERR_ARITH_NOTIMPL); +#endif + } else { + jinit_lhuff_encoder(cinfo); + } + + /* Need a full-image difference buffer in any multi-pass mode. */ + jinit_c_diff_controller(cinfo, + (boolean) (cinfo->num_scans > 1 || + cinfo->optimize_coding)); + + /* Initialize method pointers. + * + * Note: entropy_start_pass and entropy_finish_pass are assigned in + * jclhuff.c and compress_data is assigned in jcdiffct.c. + */ + losslsc->pub.start_pass = start_pass; +} + +#endif /* C_LOSSLESS_SUPPORTED */ diff --git a/gdcm/Utilities/gdcmjpeg/jclossy.c b/gdcm/Utilities/gdcmjpeg/jclossy.c new file mode 100644 index 0000000..70661b3 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jclossy.c @@ -0,0 +1,80 @@ +/* + * jclossy.c + * + * Copyright (C) 1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the control logic for the lossy JPEG compressor. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jlossy.h" + + +/* + * Initialize for a processing pass. + */ + +METHODDEF(void) +start_pass (j_compress_ptr cinfo, J_BUF_MODE pass_mode) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + + (*lossyc->fdct_start_pass) (cinfo); + (*lossyc->coef_start_pass) (cinfo, pass_mode); +} + + +/* + * Initialize the lossy compression codec. + * This is called only once, during master selection. + */ + +GLOBAL(void) +jinit_lossy_c_codec (j_compress_ptr cinfo) +{ + j_lossy_c_ptr lossyc; + + /* Create subobject in permanent pool */ + lossyc = (j_lossy_c_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + SIZEOF(jpeg_lossy_c_codec)); + cinfo->codec = (struct jpeg_c_codec *) lossyc; + + /* Initialize sub-modules */ + + /* Forward DCT */ + jinit_forward_dct(cinfo); + /* Entropy encoding: either Huffman or arithmetic coding. */ + if (cinfo->arith_code) { +#ifdef WITH_ARITHMETIC_PATCH + jinit_arith_encoder(cinfo); +#else + ERREXIT(cinfo, JERR_ARITH_NOTIMPL); +#endif + } else { + if (cinfo->process == JPROC_PROGRESSIVE) { +#ifdef C_PROGRESSIVE_SUPPORTED + jinit_phuff_encoder(cinfo); +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else + jinit_shuff_encoder(cinfo); + } + + /* Need a full-image coefficient buffer in any multi-pass mode. */ + jinit_c_coef_controller(cinfo, + (boolean) (cinfo->num_scans > 1 || + cinfo->optimize_coding)); + + /* Initialize method pointers. + * + * Note: entropy_start_pass and entropy_finish_pass are assigned in + * jcshuff.c or jcphuff.c and compress_data is assigned in jccoefct.c. + */ + lossyc->pub.start_pass = start_pass; +} diff --git a/gdcm/Utilities/gdcmjpeg/jcmainct.c b/gdcm/Utilities/gdcmjpeg/jcmainct.c new file mode 100644 index 0000000..2e2d2e1 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jcmainct.c @@ -0,0 +1,296 @@ +/* + * jcmainct.c + * + * Copyright (C) 1994-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the main buffer controller for compression. + * The main buffer lies between the pre-processor and the JPEG + * compressor proper; it holds downsampled data in the JPEG colorspace. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Note: currently, there is no operating mode in which a full-image buffer + * is needed at this step. If there were, that mode could not be used with + * "raw data" input, since this module is bypassed in that case. However, + * we've left the code here for possible use in special applications. + */ +#undef FULL_MAIN_BUFFER_SUPPORTED + + +/* Private buffer controller object */ + +typedef struct { + struct jpeg_c_main_controller pub; /* public fields */ + + JDIMENSION cur_iMCU_row; /* number of current iMCU row */ + JDIMENSION rowgroup_ctr; /* counts row groups received in iMCU row */ + boolean suspended; /* remember if we suspended output */ + J_BUF_MODE pass_mode; /* current operating mode */ + + /* If using just a strip buffer, this points to the entire set of buffers + * (we allocate one for each component). In the full-image case, this + * points to the currently accessible strips of the virtual arrays. + */ + JSAMPARRAY buffer[MAX_COMPONENTS]; + +#ifdef FULL_MAIN_BUFFER_SUPPORTED + /* If using full-image storage, this array holds pointers to virtual-array + * control blocks for each component. Unused if not full-image storage. + */ + jvirt_sarray_ptr whole_image[MAX_COMPONENTS]; +#endif +} my_main_controller; + +typedef my_main_controller * my_main_ptr; + + +/* Forward declarations */ +METHODDEF(void) process_data_simple_main + JPP((j_compress_ptr cinfo, JSAMPARRAY input_buf, + JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail)); +#ifdef FULL_MAIN_BUFFER_SUPPORTED +METHODDEF(void) process_data_buffer_main + JPP((j_compress_ptr cinfo, JSAMPARRAY input_buf, + JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail)); +#endif + + +/* + * Initialize for a processing pass. + */ + +METHODDEF(void) +start_pass_main (j_compress_ptr cinfo, J_BUF_MODE pass_mode) +{ + my_main_ptr mainPtr = (my_main_ptr) cinfo->main; + + /* Do nothing in raw-data mode. */ + if (cinfo->raw_data_in) + return; + + mainPtr->cur_iMCU_row = 0; /* initialize counters */ + mainPtr->rowgroup_ctr = 0; + mainPtr->suspended = FALSE; + mainPtr->pass_mode = pass_mode; /* save mode for use by process_data */ + + switch (pass_mode) { + case JBUF_PASS_THRU: +#ifdef FULL_MAIN_BUFFER_SUPPORTED + if (mainPtr->whole_image[0] != NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); +#endif + mainPtr->pub.process_data = process_data_simple_main; + break; +#ifdef FULL_MAIN_BUFFER_SUPPORTED + case JBUF_SAVE_SOURCE: + case JBUF_CRANK_DEST: + case JBUF_SAVE_AND_PASS: + if (mainPtr->whole_image[0] == NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + mainPtr->pub.process_data = process_data_buffer_main; + break; +#endif + default: + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + break; + } +} + + +/* + * Process some data. + * This routine handles the simple pass-through mode, + * where we have only a strip buffer. + */ + +METHODDEF(void) +process_data_simple_main (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail) +{ + my_main_ptr mainPtr = (my_main_ptr) cinfo->main; + JDIMENSION data_unit = (JDIMENSION)(cinfo->data_unit); + + while (mainPtr->cur_iMCU_row < cinfo->total_iMCU_rows) { + /* Read input data if we haven't filled the main buffer yet */ + if (mainPtr->rowgroup_ctr < data_unit) + (*cinfo->prep->pre_process_data) (cinfo, + input_buf, in_row_ctr, in_rows_avail, + mainPtr->buffer, &mainPtr->rowgroup_ctr, + (JDIMENSION) data_unit); + + /* If we don't have a full iMCU row buffered, return to application for + * more data. Note that preprocessor will always pad to fill the iMCU row + * at the bottom of the image. + */ + if (mainPtr->rowgroup_ctr != data_unit) + return; + + /* Send the completed row to the compressor */ + if (! (*cinfo->codec->compress_data) (cinfo, mainPtr->buffer)) { + /* If compressor did not consume the whole row, then we must need to + * suspend processing and return to the application. In this situation + * we pretend we didn't yet consume the last input row; otherwise, if + * it happened to be the last row of the image, the application would + * think we were done. + */ + if (! mainPtr->suspended) { + (*in_row_ctr)--; + mainPtr->suspended = TRUE; + } + return; + } + /* We did finish the row. Undo our little suspension hack if a previous + * call suspended; then mark the main buffer empty. + */ + if (mainPtr->suspended) { + (*in_row_ctr)++; + mainPtr->suspended = FALSE; + } + mainPtr->rowgroup_ctr = 0; + mainPtr->cur_iMCU_row++; + } +} + + +#ifdef FULL_MAIN_BUFFER_SUPPORTED + +/* + * Process some data. + * This routine handles all of the modes that use a full-size buffer. + */ + +METHODDEF(void) +process_data_buffer_main (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail) +{ + my_main_ptr mainPtr = (my_main_ptr) cinfo->main; + int ci; + jpeg_component_info *compptr; + boolean writing = (mainPtr->pass_mode != JBUF_CRANK_DEST); + JDIMENSION data_unit = (JDIMENSION)(cinfo->data_unit); + + while (mainPtr->cur_iMCU_row < cinfo->total_iMCU_rows) { + /* Realign the virtual buffers if at the start of an iMCU row. */ + if (mainPtr->rowgroup_ctr == 0) { + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + mainPtr->buffer[ci] = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, mainPtr->whole_image[ci], + mainPtr->cur_iMCU_row * (compptr->v_samp_factor * data_unit), + (JDIMENSION) (compptr->v_samp_factor * data_unit), writing); + } + /* In a read pass, pretend we just read some source data. */ + if (! writing) { + *in_row_ctr += cinfo->max_v_samp_factor * data_unit; + mainPtr->rowgroup_ctr = data_unit; + } + } + + /* If a write pass, read input data until the current iMCU row is full. */ + /* Note: preprocessor will pad if necessary to fill the last iMCU row. */ + if (writing) { + (*cinfo->prep->pre_process_data) (cinfo, + input_buf, in_row_ctr, in_rows_avail, + mainPtr->buffer, &mainPtr->rowgroup_ctr, + (JDIMENSION) data_unit); + /* Return to application if we need more data to fill the iMCU row. */ + if (mainPtr->rowgroup_ctr < data_unit) + return; + } + + /* Emit data, unless this is a sink-only pass. */ + if (mainPtr->pass_mode != JBUF_SAVE_SOURCE) { + if (! (*cinfo->codec->compress_data) (cinfo, mainPtr->buffer)) { + /* If compressor did not consume the whole row, then we must need to + * suspend processing and return to the application. In this situation + * we pretend we didn't yet consume the last input row; otherwise, if + * it happened to be the last row of the image, the application would + * think we were done. + */ + if (! mainPtr->suspended) { + (*in_row_ctr)--; + mainPtr->suspended = TRUE; + } + return; + } + /* We did finish the row. Undo our little suspension hack if a previous + * call suspended; then mark the main buffer empty. + */ + if (mainPtr->suspended) { + (*in_row_ctr)++; + mainPtr->suspended = FALSE; + } + } + + /* If get here, we are done with this iMCU row. Mark buffer empty. */ + mainPtr->rowgroup_ctr = 0; + mainPtr->cur_iMCU_row++; + } +} + +#endif /* FULL_MAIN_BUFFER_SUPPORTED */ + + +/* + * Initialize main buffer controller. + */ + +GLOBAL(void) +jinit_c_main_controller (j_compress_ptr cinfo, boolean need_full_buffer) +{ + my_main_ptr mainPtr; + int ci; + jpeg_component_info *compptr; + int data_unit = cinfo->data_unit; + + mainPtr = (my_main_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_main_controller)); + cinfo->main = (struct jpeg_c_main_controller *) mainPtr; + mainPtr->pub.start_pass = start_pass_main; + + /* We don't need to create a buffer in raw-data mode. */ + if (cinfo->raw_data_in) + return; + + /* Create the buffer. It holds downsampled data, so each component + * may be of a different size. + */ + if (need_full_buffer) { +#ifdef FULL_MAIN_BUFFER_SUPPORTED + /* Allocate a full-image virtual array for each component */ + /* Note we pad the bottom to a multiple of the iMCU height */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + mainPtr->whole_image[ci] = (*cinfo->mem->request_virt_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, + compptr->width_in_data_units * data_unit, + (JDIMENSION) jround_up((long) compptr->height_in_data_units, + (long) compptr->v_samp_factor) * data_unit, + (JDIMENSION) (compptr->v_samp_factor * data_unit)); + } +#else + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); +#endif + } else { +#ifdef FULL_MAIN_BUFFER_SUPPORTED + mainPtr->whole_image[0] = NULL; /* flag for no virtual arrays */ +#endif + /* Allocate a strip buffer for each component */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + mainPtr->buffer[ci] = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + compptr->width_in_data_units * data_unit, + (JDIMENSION) (compptr->v_samp_factor * data_unit)); + } + } +} diff --git a/gdcm/Utilities/gdcmjpeg/jcmarker.c b/gdcm/Utilities/gdcmjpeg/jcmarker.c new file mode 100644 index 0000000..979bd85 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jcmarker.c @@ -0,0 +1,682 @@ +/* + * jcmarker.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to write JPEG datastream markers. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +typedef enum { /* JPEG marker codes */ + M_SOF0 = 0xc0, + M_SOF1 = 0xc1, + M_SOF2 = 0xc2, + M_SOF3 = 0xc3, + + M_SOF5 = 0xc5, + M_SOF6 = 0xc6, + M_SOF7 = 0xc7, + + M_JPG = 0xc8, + M_SOF9 = 0xc9, + M_SOF10 = 0xca, + M_SOF11 = 0xcb, + + M_SOF13 = 0xcd, + M_SOF14 = 0xce, + M_SOF15 = 0xcf, + + M_DHT = 0xc4, + + M_DAC = 0xcc, + + M_RST0 = 0xd0, + M_RST1 = 0xd1, + M_RST2 = 0xd2, + M_RST3 = 0xd3, + M_RST4 = 0xd4, + M_RST5 = 0xd5, + M_RST6 = 0xd6, + M_RST7 = 0xd7, + + M_SOI = 0xd8, + M_EOI = 0xd9, + M_SOS = 0xda, + M_DQT = 0xdb, + M_DNL = 0xdc, + M_DRI = 0xdd, + M_DHP = 0xde, + M_EXP = 0xdf, + + M_APP0 = 0xe0, + M_APP1 = 0xe1, + M_APP2 = 0xe2, + M_APP3 = 0xe3, + M_APP4 = 0xe4, + M_APP5 = 0xe5, + M_APP6 = 0xe6, + M_APP7 = 0xe7, + M_APP8 = 0xe8, + M_APP9 = 0xe9, + M_APP10 = 0xea, + M_APP11 = 0xeb, + M_APP12 = 0xec, + M_APP13 = 0xed, + M_APP14 = 0xee, + M_APP15 = 0xef, + + M_JPG0 = 0xf0, + M_JPG13 = 0xfd, + M_COM = 0xfe, + + M_TEM = 0x01, + + M_ERROR = 0x100 +} JPEG_MARKER; + + +/* Private state */ + +typedef struct { + struct jpeg_marker_writer pub; /* public fields */ + + unsigned int last_restart_interval; /* last DRI value emitted; 0 after SOI */ +} my_marker_writer; + +typedef my_marker_writer * my_marker_ptr; + + +/* + * Basic output routines. + * + * Note that we do not support suspension while writing a marker. + * Therefore, an application using suspension must ensure that there is + * enough buffer space for the initial markers (typ. 600-700 bytes) before + * calling jpeg_start_compress, and enough space to write the trailing EOI + * (a few bytes) before calling jpeg_finish_compress. Multipass compression + * modes are not supported at all with suspension, so those two are the only + * points where markers will be written. + */ + +LOCAL(void) +emit_byte (j_compress_ptr cinfo, int val) +/* Emit a byte */ +{ + struct jpeg_destination_mgr * dest = cinfo->dest; + + *(dest->next_output_byte)++ = (JOCTET) val; + if (--dest->free_in_buffer == 0) { + if (! (*dest->empty_output_buffer) (cinfo)) + ERREXIT(cinfo, JERR_CANT_SUSPEND); + } +} + + +LOCAL(void) +emit_marker (j_compress_ptr cinfo, JPEG_MARKER mark) +/* Emit a marker code */ +{ + emit_byte(cinfo, 0xFF); + emit_byte(cinfo, (int) mark); +} + + +LOCAL(void) +emit_2bytes (j_compress_ptr cinfo, int value) +/* Emit a 2-byte integer; these are always MSB first in JPEG files */ +{ + emit_byte(cinfo, (value >> 8) & 0xFF); + emit_byte(cinfo, value & 0xFF); +} + + +/* + * Routines to write specific marker types. + */ + +LOCAL(int) +emit_dqt (j_compress_ptr cinfo, int index) +/* Emit a DQT marker */ +/* Returns the precision used (0 = 8bits, 1 = 16bits) for baseline checking */ +{ + JQUANT_TBL * qtbl = cinfo->quant_tbl_ptrs[index]; + int prec; + int i; + + if (qtbl == NULL) + ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, index); + + prec = 0; + for (i = 0; i < DCTSIZE2; i++) { + if (qtbl->quantval[i] > 255) + prec = 1; + } + + if (! qtbl->sent_table) { + emit_marker(cinfo, M_DQT); + + emit_2bytes(cinfo, prec ? DCTSIZE2*2 + 1 + 2 : DCTSIZE2 + 1 + 2); + + emit_byte(cinfo, index + (prec<<4)); + + for (i = 0; i < DCTSIZE2; i++) { + /* The table entries must be emitted in zigzag order. */ + unsigned int qval = qtbl->quantval[jpeg_natural_order[i]]; + if (prec) + emit_byte(cinfo, (int) (qval >> 8)); + emit_byte(cinfo, (int) (qval & 0xFF)); + } + + qtbl->sent_table = TRUE; + } + + return prec; +} + + +LOCAL(void) +emit_dht (j_compress_ptr cinfo, int index, boolean is_ac) +/* Emit a DHT marker */ +{ + JHUFF_TBL * htbl; + int length, i; + + if (is_ac) { + htbl = cinfo->ac_huff_tbl_ptrs[index]; + index += 0x10; /* output index has AC bit set */ + } else { + htbl = cinfo->dc_huff_tbl_ptrs[index]; + } + + if (htbl == NULL) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, index); + + if (! htbl->sent_table) { + emit_marker(cinfo, M_DHT); + + length = 0; + for (i = 1; i <= 16; i++) + length += htbl->bits[i]; + + emit_2bytes(cinfo, length + 2 + 1 + 16); + emit_byte(cinfo, index); + + for (i = 1; i <= 16; i++) + emit_byte(cinfo, htbl->bits[i]); + + for (i = 0; i < length; i++) + emit_byte(cinfo, htbl->huffval[i]); + + htbl->sent_table = TRUE; + } +} + + +LOCAL(void) +emit_dac (j_compress_ptr cinfo) +/* Emit a DAC marker */ +/* Since the useful info is so small, we want to emit all the tables in */ +/* one DAC marker. Therefore this routine does its own scan of the table. */ +{ +#ifdef C_ARITH_CODING_SUPPORTED + char dc_in_use[NUM_ARITH_TBLS]; + char ac_in_use[NUM_ARITH_TBLS]; + int length, i; + jpeg_component_info *compptr; + + for (i = 0; i < NUM_ARITH_TBLS; i++) + dc_in_use[i] = ac_in_use[i] = 0; + + for (i = 0; i < cinfo->comps_in_scan; i++) { + compptr = cinfo->cur_comp_info[i]; + dc_in_use[compptr->dc_tbl_no] = 1; + ac_in_use[compptr->ac_tbl_no] = 1; + } + + length = 0; + for (i = 0; i < NUM_ARITH_TBLS; i++) + length += dc_in_use[i] + ac_in_use[i]; + + emit_marker(cinfo, M_DAC); + + emit_2bytes(cinfo, length*2 + 2); + + for (i = 0; i < NUM_ARITH_TBLS; i++) { + if (dc_in_use[i]) { + emit_byte(cinfo, i); + emit_byte(cinfo, cinfo->arith_dc_L[i] + (cinfo->arith_dc_U[i]<<4)); + } + if (ac_in_use[i]) { + emit_byte(cinfo, i + 0x10); + emit_byte(cinfo, cinfo->arith_ac_K[i]); + } + } +#else + (void)cinfo; +#endif /* C_ARITH_CODING_SUPPORTED */ +} + + +LOCAL(void) +emit_dri (j_compress_ptr cinfo) +/* Emit a DRI marker */ +{ + emit_marker(cinfo, M_DRI); + + emit_2bytes(cinfo, 4); /* fixed length */ + + emit_2bytes(cinfo, (int) cinfo->restart_interval); +} + + +LOCAL(void) +emit_sof (j_compress_ptr cinfo, JPEG_MARKER code) +/* Emit a SOF marker */ +{ + int ci; + jpeg_component_info *compptr; + + emit_marker(cinfo, code); + + emit_2bytes(cinfo, 3 * cinfo->num_components + 2 + 5 + 1); /* length */ + + /* Make sure image isn't bigger than SOF field can handle */ + if ((long) cinfo->image_height > 65535L || + (long) cinfo->image_width > 65535L) + ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) 65535); + + emit_byte(cinfo, cinfo->data_precision); + emit_2bytes(cinfo, (int) cinfo->image_height); + emit_2bytes(cinfo, (int) cinfo->image_width); + + emit_byte(cinfo, cinfo->num_components); + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + emit_byte(cinfo, compptr->component_id); + emit_byte(cinfo, (compptr->h_samp_factor << 4) + compptr->v_samp_factor); + emit_byte(cinfo, compptr->quant_tbl_no); + } +} + + +LOCAL(void) +emit_sos (j_compress_ptr cinfo) +/* Emit a SOS marker */ +{ + int i, td, ta; + jpeg_component_info *compptr; + + emit_marker(cinfo, M_SOS); + + emit_2bytes(cinfo, 2 * cinfo->comps_in_scan + 2 + 1 + 3); /* length */ + + emit_byte(cinfo, cinfo->comps_in_scan); + + for (i = 0; i < cinfo->comps_in_scan; i++) { + compptr = cinfo->cur_comp_info[i]; + emit_byte(cinfo, compptr->component_id); + td = compptr->dc_tbl_no; + ta = compptr->ac_tbl_no; + if (cinfo->process == JPROC_PROGRESSIVE) { + /* Progressive mode: only DC or only AC tables are used in one scan; + * furthermore, Huffman coding of DC refinement uses no table at all. + * We emit 0 for unused field(s); this is recommended by the P&M text + * but does not seem to be specified in the standard. + */ + if (cinfo->Ss == 0) { + ta = 0; /* DC scan */ + if (cinfo->Ah != 0 && !cinfo->arith_code) + td = 0; /* no DC table either */ + } else { + td = 0; /* AC scan */ + } + } + emit_byte(cinfo, (td << 4) + ta); + } + + emit_byte(cinfo, cinfo->Ss); + emit_byte(cinfo, cinfo->Se); + emit_byte(cinfo, (cinfo->Ah << 4) + cinfo->Al); +} + + +LOCAL(void) +emit_jfif_app0 (j_compress_ptr cinfo) +/* Emit a JFIF-compliant APP0 marker */ +{ + /* + * Length of APP0 block (2 bytes) + * Block ID (4 bytes - ASCII "JFIF") + * Zero byte (1 byte to terminate the ID string) + * Version Major, Minor (2 bytes - major first) + * Units (1 byte - 0x00 = none, 0x01 = inch, 0x02 = cm) + * Xdpu (2 bytes - dots per unit horizontal) + * Ydpu (2 bytes - dots per unit vertical) + * Thumbnail X size (1 byte) + * Thumbnail Y size (1 byte) + */ + + emit_marker(cinfo, M_APP0); + + emit_2bytes(cinfo, 2 + 4 + 1 + 2 + 1 + 2 + 2 + 1 + 1); /* length */ + + emit_byte(cinfo, 0x4A); /* Identifier: ASCII "JFIF" */ + emit_byte(cinfo, 0x46); + emit_byte(cinfo, 0x49); + emit_byte(cinfo, 0x46); + emit_byte(cinfo, 0); + emit_byte(cinfo, cinfo->JFIF_major_version); /* Version fields */ + emit_byte(cinfo, cinfo->JFIF_minor_version); + emit_byte(cinfo, cinfo->density_unit); /* Pixel size information */ + emit_2bytes(cinfo, (int) cinfo->X_density); + emit_2bytes(cinfo, (int) cinfo->Y_density); + emit_byte(cinfo, 0); /* No thumbnail image */ + emit_byte(cinfo, 0); +} + + +LOCAL(void) +emit_adobe_app14 (j_compress_ptr cinfo) +/* Emit an Adobe APP14 marker */ +{ + /* + * Length of APP14 block (2 bytes) + * Block ID (5 bytes - ASCII "Adobe") + * Version Number (2 bytes - currently 100) + * Flags0 (2 bytes - currently 0) + * Flags1 (2 bytes - currently 0) + * Color transform (1 byte) + * + * Although Adobe TN 5116 mentions Version = 101, all the Adobe files + * now in circulation seem to use Version = 100, so that's what we write. + * + * We write the color transform byte as 1 if the JPEG color space is + * YCbCr, 2 if it's YCCK, 0 otherwise. Adobe's definition has to do with + * whether the encoder performed a transformation, which is pretty useless. + */ + + emit_marker(cinfo, M_APP14); + + emit_2bytes(cinfo, 2 + 5 + 2 + 2 + 2 + 1); /* length */ + + emit_byte(cinfo, 0x41); /* Identifier: ASCII "Adobe" */ + emit_byte(cinfo, 0x64); + emit_byte(cinfo, 0x6F); + emit_byte(cinfo, 0x62); + emit_byte(cinfo, 0x65); + emit_2bytes(cinfo, 100); /* Version */ + emit_2bytes(cinfo, 0); /* Flags0 */ + emit_2bytes(cinfo, 0); /* Flags1 */ + switch (cinfo->jpeg_color_space) { + case JCS_YCbCr: + emit_byte(cinfo, 1); /* Color transform = 1 */ + break; + case JCS_YCCK: + emit_byte(cinfo, 2); /* Color transform = 2 */ + break; + default: + emit_byte(cinfo, 0); /* Color transform = 0 */ + break; + } +} + + +/* + * These routines allow writing an arbitrary marker with parameters. + * The only intended use is to emit COM or APPn markers after calling + * write_file_header and before calling write_frame_header. + * Other uses are not guaranteed to produce desirable results. + * Counting the parameter bytes properly is the caller's responsibility. + */ + +METHODDEF(void) +write_marker_header (j_compress_ptr cinfo, int marker, unsigned int datalen) +/* Emit an arbitrary marker header */ +{ + if (datalen > (unsigned int) 65533) /* safety check */ + ERREXIT(cinfo, JERR_BAD_LENGTH); + + emit_marker(cinfo, (JPEG_MARKER) marker); + + emit_2bytes(cinfo, (int) (datalen + 2)); /* total length */ +} + +METHODDEF(void) +write_marker_byte (j_compress_ptr cinfo, int val) +/* Emit one byte of marker parameters following write_marker_header */ +{ + emit_byte(cinfo, val); +} + + +/* + * Write datastream header. + * This consists of an SOI and optional APPn markers. + * We recommend use of the JFIF marker, but not the Adobe marker, + * when using YCbCr or grayscale data. The JFIF marker should NOT + * be used for any other JPEG colorspace. The Adobe marker is helpful + * to distinguish RGB, CMYK, and YCCK colorspaces. + * Note that an application can write additional header markers after + * jpeg_start_compress returns. + */ + +METHODDEF(void) +write_file_header (j_compress_ptr cinfo) +{ + my_marker_ptr marker = (my_marker_ptr) cinfo->marker; + + emit_marker(cinfo, M_SOI); /* first the SOI */ + + /* SOI is defined to reset restart interval to 0 */ + marker->last_restart_interval = 0; + + if (cinfo->write_JFIF_header) /* next an optional JFIF APP0 */ + emit_jfif_app0(cinfo); + if (cinfo->write_Adobe_marker) /* next an optional Adobe APP14 */ + emit_adobe_app14(cinfo); +} + + +/* + * Write frame header. + * This consists of DQT and SOFn markers. + * Note that we do not emit the SOF until we have emitted the DQT(s). + * This avoids compatibility problems with incorrect implementations that + * try to error-check the quant table numbers as soon as they see the SOF. + */ + +METHODDEF(void) +write_frame_header (j_compress_ptr cinfo) +{ + int ci, prec; + boolean is_baseline; + jpeg_component_info *compptr; + + prec = 0; + if (cinfo->process != JPROC_LOSSLESS) { + /* Emit DQT for each quantization table. + * Note that emit_dqt() suppresses any duplicate tables. + */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + prec += emit_dqt(cinfo, compptr->quant_tbl_no); + } + /* now prec is nonzero iff there are any 16-bit quant tables. */ + } + + /* Check for a non-baseline specification. + * Note we assume that Huffman table numbers won't be changed later. + */ + if (cinfo->arith_code || cinfo->process != JPROC_SEQUENTIAL || + cinfo->data_precision != 8) { + is_baseline = FALSE; + } else { + is_baseline = TRUE; + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + if (compptr->dc_tbl_no > 1 || compptr->ac_tbl_no > 1) + is_baseline = FALSE; + } + if (prec && is_baseline) { + is_baseline = FALSE; + /* If it's baseline except for quantizer size, warn the user */ + TRACEMS(cinfo, 0, JTRC_16BIT_TABLES); + } + } + + /* Emit the proper SOF marker */ + if (cinfo->arith_code) { +#ifdef WITH_ARITHMETIC_PATCH + if (cinfo->process == JPROC_PROGRESSIVE) + emit_sof(cinfo, M_SOF10); /* SOF code for progressive arithmetic */ + else if (cinfo->process == JPROC_LOSSLESS) + emit_sof(cinfo, M_SOF11); /* SOF code for lossless arithmetic */ + else + emit_sof(cinfo, M_SOF9); /* SOF code for sequential arithmetic */ +#else + emit_sof(cinfo, M_SOF9); /* SOF code for arithmetic coding */ +#endif + } else { + if (cinfo->process == JPROC_PROGRESSIVE) + emit_sof(cinfo, M_SOF2); /* SOF code for progressive Huffman */ + else if (cinfo->process == JPROC_LOSSLESS) + emit_sof(cinfo, M_SOF3); /* SOF code for lossless Huffman */ + else if (is_baseline) + emit_sof(cinfo, M_SOF0); /* SOF code for baseline implementation */ + else + emit_sof(cinfo, M_SOF1); /* SOF code for non-baseline Huffman file */ + } +} + + +/* + * Write scan header. + * This consists of DHT or DAC markers, optional DRI, and SOS. + * Compressed data will be written following the SOS. + */ + +METHODDEF(void) +write_scan_header (j_compress_ptr cinfo) +{ + my_marker_ptr marker = (my_marker_ptr) cinfo->marker; + int i; + jpeg_component_info *compptr; + + if (cinfo->arith_code) { + /* Emit arith conditioning info. We may have some duplication + * if the file has multiple scans, but it's so small it's hardly + * worth worrying about. + */ + emit_dac(cinfo); + } else { + /* Emit Huffman tables. + * Note that emit_dht() suppresses any duplicate tables. + */ + for (i = 0; i < cinfo->comps_in_scan; i++) { + compptr = cinfo->cur_comp_info[i]; + if (cinfo->process == JPROC_PROGRESSIVE) { + /* Progressive mode: only DC or only AC tables are used in one scan */ + if (cinfo->Ss == 0) { + if (cinfo->Ah == 0) /* DC needs no table for refinement scan */ + emit_dht(cinfo, compptr->dc_tbl_no, FALSE); + } else { + emit_dht(cinfo, compptr->ac_tbl_no, TRUE); + } + } else if (cinfo->process == JPROC_LOSSLESS) { + /* Lossless mode: only DC tables are used */ + emit_dht(cinfo, compptr->dc_tbl_no, FALSE); + } else { + /* Sequential mode: need both DC and AC tables */ + emit_dht(cinfo, compptr->dc_tbl_no, FALSE); + emit_dht(cinfo, compptr->ac_tbl_no, TRUE); + } + } + } + + /* Emit DRI if required --- note that DRI value could change for each scan. + * We avoid wasting space with unnecessary DRIs, however. + */ + if (cinfo->restart_interval != marker->last_restart_interval) { + emit_dri(cinfo); + marker->last_restart_interval = cinfo->restart_interval; + } + + emit_sos(cinfo); +} + + +/* + * Write datastream trailer. + */ + +METHODDEF(void) +write_file_trailer (j_compress_ptr cinfo) +{ + emit_marker(cinfo, M_EOI); +} + + +/* + * Write an abbreviated table-specification datastream. + * This consists of SOI, DQT and DHT tables, and EOI. + * Any table that is defined and not marked sent_table = TRUE will be + * emitted. Note that all tables will be marked sent_table = TRUE at exit. + */ + +METHODDEF(void) +write_tables_only (j_compress_ptr cinfo) +{ + int i; + + emit_marker(cinfo, M_SOI); + + for (i = 0; i < NUM_QUANT_TBLS; i++) { + if (cinfo->quant_tbl_ptrs[i] != NULL) + (void) emit_dqt(cinfo, i); + } + + if (! cinfo->arith_code) { + for (i = 0; i < NUM_HUFF_TBLS; i++) { + if (cinfo->dc_huff_tbl_ptrs[i] != NULL) + emit_dht(cinfo, i, FALSE); + if (cinfo->ac_huff_tbl_ptrs[i] != NULL) + emit_dht(cinfo, i, TRUE); + } + } + + emit_marker(cinfo, M_EOI); +} + + +/* + * Initialize the marker writer module. + */ + +GLOBAL(void) +jinit_marker_writer (j_compress_ptr cinfo) +{ + my_marker_ptr marker; + + /* Create the subobject */ + marker = (my_marker_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_marker_writer)); + cinfo->marker = (struct jpeg_marker_writer *) marker; + /* Initialize method pointers */ + marker->pub.write_file_header = write_file_header; + marker->pub.write_frame_header = write_frame_header; + marker->pub.write_scan_header = write_scan_header; + marker->pub.write_file_trailer = write_file_trailer; + marker->pub.write_tables_only = write_tables_only; + marker->pub.write_marker_header = write_marker_header; + marker->pub.write_marker_byte = write_marker_byte; + /* Initialize private state */ + marker->last_restart_interval = 0; +} diff --git a/gdcm/Utilities/gdcmjpeg/jcmaster.c b/gdcm/Utilities/gdcmjpeg/jcmaster.c new file mode 100644 index 0000000..656f9a0 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jcmaster.c @@ -0,0 +1,657 @@ +/* + * jcmaster.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains master control logic for the JPEG compressor. + * These routines are concerned with parameter validation, initial setup, + * and inter-pass control (determining the number of passes and the work + * to be done in each pass). + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jlossy.h" /* Private declarations for lossy codec */ + + +/* Private state */ + +typedef enum { + main_pass, /* input data, also do first output step */ + huff_opt_pass, /* Huffman code optimization pass */ + output_pass /* data output pass */ +} c_pass_type; + +typedef struct { + struct jpeg_comp_master pub; /* public fields */ + + c_pass_type pass_type; /* the type of the current pass */ + + int pass_number; /* # of passes completed */ + int total_passes; /* total # of passes needed */ + + int scan_number; /* current index in scan_info[] */ +} my_comp_master; + +typedef my_comp_master * my_master_ptr; + + +/* + * Support routines that do various essential calculations. + */ + +LOCAL(void) +initial_setup (j_compress_ptr cinfo) +/* Do computations that are needed before master selection phase */ +{ + int ci; + jpeg_component_info *compptr; + long samplesperrow; + JDIMENSION jd_samplesperrow; + int data_unit = cinfo->data_unit; + + /* Sanity check on image dimensions */ + if (cinfo->image_height <= 0 || cinfo->image_width <= 0 + || cinfo->num_components <= 0 || cinfo->input_components <= 0) + ERREXIT(cinfo, JERR_EMPTY_IMAGE); + + /* Make sure image isn't bigger than I can handle */ + if ((long) cinfo->image_height > (long) JPEG_MAX_DIMENSION || + (long) cinfo->image_width > (long) JPEG_MAX_DIMENSION) + ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) JPEG_MAX_DIMENSION); + + /* Width of an input scanline must be representable as JDIMENSION. */ + samplesperrow = (long) cinfo->image_width * (long) cinfo->input_components; + jd_samplesperrow = (JDIMENSION) samplesperrow; + if ((long) jd_samplesperrow != samplesperrow) + ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); + + /* For now, precision must match compiled-in value... */ + if (cinfo->data_precision != BITS_IN_JSAMPLE) + ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision); + + /* Check that number of components won't exceed internal array sizes */ + if (cinfo->num_components > MAX_COMPONENTS) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components, + MAX_COMPONENTS); + + /* Compute maximum sampling factors; check factor validity */ + cinfo->max_h_samp_factor = 1; + cinfo->max_v_samp_factor = 1; + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + if (compptr->h_samp_factor<=0 || compptr->h_samp_factor>MAX_SAMP_FACTOR || + compptr->v_samp_factor<=0 || compptr->v_samp_factor>MAX_SAMP_FACTOR) + ERREXIT(cinfo, JERR_BAD_SAMPLING); + cinfo->max_h_samp_factor = MAX(cinfo->max_h_samp_factor, + compptr->h_samp_factor); + cinfo->max_v_samp_factor = MAX(cinfo->max_v_samp_factor, + compptr->v_samp_factor); + } + + /* Compute dimensions of components */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Fill in the correct component_index value; don't rely on application */ + compptr->component_index = ci; + /* For compression, we never do any codec-based processing. */ + compptr->codec_data_unit = data_unit; + /* Size in data units */ + compptr->width_in_data_units = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor, + (long) (cinfo->max_h_samp_factor * data_unit)); + compptr->height_in_data_units = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor, + (long) (cinfo->max_v_samp_factor * data_unit)); + /* Size in samples */ + compptr->downsampled_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor, + (long) cinfo->max_h_samp_factor); + compptr->downsampled_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor, + (long) cinfo->max_v_samp_factor); + /* Mark component needed (this flag isn't actually used for compression) */ + compptr->component_needed = TRUE; + } + + /* Compute number of fully interleaved MCU rows (number of times that + * main controller will call coefficient controller). + */ + cinfo->total_iMCU_rows = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height, + (long) (cinfo->max_v_samp_factor*data_unit)); +} + +#ifdef C_MULTISCAN_FILES_SUPPORTED +#define NEED_SCAN_SCRIPT +#else +#ifdef C_LOSSLESS_SUPPORTED +#define NEED_SCAN_SCRIPT +#endif +#endif + +#ifdef NEED_SCAN_SCRIPT + +LOCAL(void) +validate_script (j_compress_ptr cinfo) +/* Verify that the scan script in cinfo->scan_info[] is valid; also + * determine whether it uses progressive JPEG, and set cinfo->process. + */ +{ + const jpeg_scan_info * scanptr; + int scanno, ncomps, ci, coefi, thisi; + int Ss, Se, Ah, Al; + boolean component_sent[MAX_COMPONENTS]; +#ifdef C_PROGRESSIVE_SUPPORTED + int * last_bitpos_ptr; + int last_bitpos[MAX_COMPONENTS][DCTSIZE2]; + /* -1 until that coefficient has been seen; then last Al for it */ +#endif + + if (cinfo->num_scans <= 0) + ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, 0); + +#ifndef C_MULTISCAN_FILES_SUPPORTED + if (cinfo->num_scans > 1) + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + + scanptr = cinfo->scan_info; + if (cinfo->lossless) { +#ifdef C_LOSSLESS_SUPPORTED + cinfo->process = JPROC_LOSSLESS; + for (ci = 0; ci < cinfo->num_components; ci++) + component_sent[ci] = FALSE; +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } + /* For sequential JPEG, all scans must have Ss=0, Se=DCTSIZE2-1; + * for progressive JPEG, no scan can have this. + */ + else if (scanptr->Ss != 0 || scanptr->Se != DCTSIZE2-1) { +#ifdef C_PROGRESSIVE_SUPPORTED + cinfo->process = JPROC_PROGRESSIVE; + last_bitpos_ptr = & last_bitpos[0][0]; + for (ci = 0; ci < cinfo->num_components; ci++) + for (coefi = 0; coefi < DCTSIZE2; coefi++) + *last_bitpos_ptr++ = -1; +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else { + cinfo->process = JPROC_SEQUENTIAL; + for (ci = 0; ci < cinfo->num_components; ci++) + component_sent[ci] = FALSE; + } + + for (scanno = 1; scanno <= cinfo->num_scans; scanptr++, scanno++) { + /* Validate component indexes */ + ncomps = scanptr->comps_in_scan; + if (ncomps <= 0 || ncomps > MAX_COMPS_IN_SCAN) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, ncomps, MAX_COMPS_IN_SCAN); + for (ci = 0; ci < ncomps; ci++) { + thisi = scanptr->component_index[ci]; + if (thisi < 0 || thisi >= cinfo->num_components) + ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno); + /* Components must appear in SOF order within each scan */ + if (ci > 0 && thisi <= scanptr->component_index[ci-1]) + ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno); + } + /* Validate progression parameters */ + Ss = scanptr->Ss; + Se = scanptr->Se; + Ah = scanptr->Ah; + Al = scanptr->Al; + if (cinfo->process == JPROC_LOSSLESS) { +#ifdef C_LOSSLESS_SUPPORTED + /* The JPEG spec simply gives the range 0..15 for Al (Pt), but that + * seems wrong: the upper bound ought to depend on data precision. + * Perhaps they really meant 0..N-1 for N-bit precision, which is what + * we allow here. + */ + if (Ss < 1 || Ss > 7 || /* predictor selector */ + Se != 0 || Ah != 0 || + Al < 0 || Al >= cinfo->data_precision) /* point transform */ + ERREXIT1(cinfo, JERR_BAD_LOSSLESS_SCRIPT, scanno); + /* Make sure components are not sent twice */ + for (ci = 0; ci < ncomps; ci++) { + thisi = scanptr->component_index[ci]; + if (component_sent[thisi]) + ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno); + component_sent[thisi] = TRUE; + } +#endif + } else if (cinfo->process == JPROC_PROGRESSIVE) { +#ifdef C_PROGRESSIVE_SUPPORTED + /* The JPEG spec simply gives the ranges 0..13 for Ah and Al, but that + * seems wrong: the upper bound ought to depend on data precision. + * Perhaps they really meant 0..N+1 for N-bit precision. + * Here we allow 0..10 for 8-bit data; Al larger than 10 results in + * out-of-range reconstructed DC values during the first DC scan, + * which might cause problems for some decoders. + */ +#if BITS_IN_JSAMPLE == 8 +#define MAX_AH_AL 10 +#else +#define MAX_AH_AL 13 +#endif + if (Ss < 0 || Ss >= DCTSIZE2 || Se < Ss || Se >= DCTSIZE2 || + Ah < 0 || Ah > MAX_AH_AL || Al < 0 || Al > MAX_AH_AL) + ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); + if (Ss == 0) { + if (Se != 0) /* DC and AC together not OK */ + ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); + } else { + if (ncomps != 1) /* AC scans must be for only one component */ + ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); + } + for (ci = 0; ci < ncomps; ci++) { + last_bitpos_ptr = & last_bitpos[scanptr->component_index[ci]][0]; + if (Ss != 0 && last_bitpos_ptr[0] < 0) /* AC without prior DC scan */ + ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); + for (coefi = Ss; coefi <= Se; coefi++) { + if (last_bitpos_ptr[coefi] < 0) { + /* first scan of this coefficient */ + if (Ah != 0) + ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); + } else { + /* not first scan */ + if (Ah != last_bitpos_ptr[coefi] || Al != Ah-1) + ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); + } + last_bitpos_ptr[coefi] = Al; + } + } +#endif + } else { + /* For sequential JPEG, all progression parameters must be these: */ + if (Ss != 0 || Se != DCTSIZE2-1 || Ah != 0 || Al != 0) + ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); + /* Make sure components are not sent twice */ + for (ci = 0; ci < ncomps; ci++) { + thisi = scanptr->component_index[ci]; + if (component_sent[thisi]) + ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno); + component_sent[thisi] = TRUE; + } + } + } + + /* Now verify that everything got sent. */ + if (cinfo->process == JPROC_PROGRESSIVE) { +#ifdef C_PROGRESSIVE_SUPPORTED + /* For progressive mode, we only check that at least some DC data + * got sent for each component; the spec does not require that all bits + * of all coefficients be transmitted. Would it be wiser to enforce + * transmission of all coefficient bits?? + */ + for (ci = 0; ci < cinfo->num_components; ci++) { + if (last_bitpos[ci][0] < 0) + ERREXIT(cinfo, JERR_MISSING_DATA); + } +#endif + } else { + for (ci = 0; ci < cinfo->num_components; ci++) { + if (! component_sent[ci]) + ERREXIT(cinfo, JERR_MISSING_DATA); + } + } +} + +#endif /* NEED_SCAN_SCRIPT */ + + +LOCAL(void) +select_scan_parameters (j_compress_ptr cinfo) +/* Set up the scan parameters for the current scan */ +{ + int ci; + +#ifdef NEED_SCAN_SCRIPT + if (cinfo->scan_info != NULL) { + /* Prepare for current scan --- the script is already validated */ + my_master_ptr master = (my_master_ptr) cinfo->master; + const jpeg_scan_info * scanptr = cinfo->scan_info + master->scan_number; + + cinfo->comps_in_scan = scanptr->comps_in_scan; + for (ci = 0; ci < scanptr->comps_in_scan; ci++) { + cinfo->cur_comp_info[ci] = + &cinfo->comp_info[scanptr->component_index[ci]]; + } + cinfo->Ss = scanptr->Ss; + cinfo->Se = scanptr->Se; + cinfo->Ah = scanptr->Ah; + cinfo->Al = scanptr->Al; + } else +#endif + { + /* Prepare for single sequential-JPEG scan containing all components */ + if (cinfo->num_components > MAX_COMPS_IN_SCAN) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components, + MAX_COMPS_IN_SCAN); + cinfo->comps_in_scan = cinfo->num_components; + for (ci = 0; ci < cinfo->num_components; ci++) { + cinfo->cur_comp_info[ci] = &cinfo->comp_info[ci]; + } + if (cinfo->lossless) { +#ifdef C_LOSSLESS_SUPPORTED + /* If we fall through to here, the user specified lossless, but did not + * provide a scan script. + */ + ERREXIT(cinfo, JERR_NO_LOSSLESS_SCRIPT); +#endif + } else { + cinfo->process = JPROC_SEQUENTIAL; + cinfo->Ss = 0; + cinfo->Se = DCTSIZE2-1; + cinfo->Ah = 0; + cinfo->Al = 0; + } + } +} + + +LOCAL(void) +per_scan_setup (j_compress_ptr cinfo) +/* Do computations that are needed before processing a JPEG scan */ +/* cinfo->comps_in_scan and cinfo->cur_comp_info[] are already set */ +{ + int ci, mcublks, tmp; + jpeg_component_info *compptr; + int data_unit = cinfo->data_unit; + + if (cinfo->comps_in_scan == 1) { + + /* Noninterleaved (single-component) scan */ + compptr = cinfo->cur_comp_info[0]; + + /* Overall image size in MCUs */ + cinfo->MCUs_per_row = compptr->width_in_data_units; + cinfo->MCU_rows_in_scan = compptr->height_in_data_units; + + /* For noninterleaved scan, always one block per MCU */ + compptr->MCU_width = 1; + compptr->MCU_height = 1; + compptr->MCU_data_units = 1; + compptr->MCU_sample_width = data_unit; + compptr->last_col_width = 1; + /* For noninterleaved scans, it is convenient to define last_row_height + * as the number of block rows present in the last iMCU row. + */ + tmp = (int) (compptr->height_in_data_units % compptr->v_samp_factor); + if (tmp == 0) tmp = compptr->v_samp_factor; + compptr->last_row_height = tmp; + + /* Prepare array describing MCU composition */ + cinfo->data_units_in_MCU = 1; + cinfo->MCU_membership[0] = 0; + + } else { + + /* Interleaved (multi-component) scan */ + if (cinfo->comps_in_scan <= 0 || cinfo->comps_in_scan > MAX_COMPS_IN_SCAN) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->comps_in_scan, + MAX_COMPS_IN_SCAN); + + /* Overall image size in MCUs */ + cinfo->MCUs_per_row = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width, + (long) (cinfo->max_h_samp_factor*data_unit)); + cinfo->MCU_rows_in_scan = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height, + (long) (cinfo->max_v_samp_factor*data_unit)); + + cinfo->data_units_in_MCU = 0; + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* Sampling factors give # of blocks of component in each MCU */ + compptr->MCU_width = compptr->h_samp_factor; + compptr->MCU_height = compptr->v_samp_factor; + compptr->MCU_data_units = compptr->MCU_width * compptr->MCU_height; + compptr->MCU_sample_width = compptr->MCU_width * data_unit; + /* Figure number of non-dummy blocks in last MCU column & row */ + tmp = (int) (compptr->width_in_data_units % compptr->MCU_width); + if (tmp == 0) tmp = compptr->MCU_width; + compptr->last_col_width = tmp; + tmp = (int) (compptr->height_in_data_units % compptr->MCU_height); + if (tmp == 0) tmp = compptr->MCU_height; + compptr->last_row_height = tmp; + /* Prepare array describing MCU composition */ + mcublks = compptr->MCU_data_units; + if (cinfo->data_units_in_MCU + mcublks > C_MAX_DATA_UNITS_IN_MCU) + ERREXIT(cinfo, JERR_BAD_MCU_SIZE); + while (mcublks-- > 0) { + cinfo->MCU_membership[cinfo->data_units_in_MCU++] = ci; + } + } + + } + + /* Convert restart specified in rows to actual MCU count. */ + /* Note that count must fit in 16 bits, so we provide limiting. */ + if (cinfo->restart_in_rows > 0) { + long nominal = (long) cinfo->restart_in_rows * (long) cinfo->MCUs_per_row; + cinfo->restart_interval = (unsigned int) MIN(nominal, 65535L); + } +} + + +/* + * Per-pass setup. + * This is called at the beginning of each pass. We determine which modules + * will be active during this pass and give them appropriate start_pass calls. + * We also set is_last_pass to indicate whether any more passes will be + * required. + */ + +METHODDEF(void) +prepare_for_pass (j_compress_ptr cinfo) +{ + /* j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; */ + my_master_ptr master = (my_master_ptr) cinfo->master; + + switch (master->pass_type) { + case main_pass: + /* Initial pass: will collect input data, and do either Huffman + * optimization or data output for the first scan. + */ + select_scan_parameters(cinfo); + per_scan_setup(cinfo); + if (! cinfo->raw_data_in) { + (*cinfo->cconvert->start_pass) (cinfo); + (*cinfo->downsample->start_pass) (cinfo); + (*cinfo->prep->start_pass) (cinfo, JBUF_PASS_THRU); + } + (*cinfo->codec->entropy_start_pass) (cinfo, cinfo->optimize_coding); + (*cinfo->codec->start_pass) (cinfo, + (master->total_passes > 1 ? + JBUF_SAVE_AND_PASS : JBUF_PASS_THRU)); + (*cinfo->main->start_pass) (cinfo, JBUF_PASS_THRU); + if (cinfo->optimize_coding) { + /* No immediate data output; postpone writing frame/scan headers */ + master->pub.call_pass_startup = FALSE; + } else { + /* Will write frame/scan headers at first jpeg_write_scanlines call */ + master->pub.call_pass_startup = TRUE; + } + break; +#ifdef ENTROPY_OPT_SUPPORTED + case huff_opt_pass: + /* Do Huffman optimization for a scan after the first one. */ + select_scan_parameters(cinfo); + per_scan_setup(cinfo); +#ifdef WITH_ARITHMETIC_PATCH + if ((*cinfo->codec->need_optimization_pass) (cinfo)) { +#else + if ((*cinfo->codec->need_optimization_pass) (cinfo) || cinfo->arith_code) { +#endif + (*cinfo->codec->entropy_start_pass) (cinfo, TRUE); + (*cinfo->codec->start_pass) (cinfo, JBUF_CRANK_DEST); + master->pub.call_pass_startup = FALSE; + break; + } + /* Special case: Huffman DC refinement scans need no Huffman table + * and therefore we can skip the optimization pass for them. + */ + master->pass_type = output_pass; + master->pass_number++; + /*FALLTHROUGH*/ +#endif + case output_pass: + /* Do a data-output pass. */ + /* We need not repeat per-scan setup if prior optimization pass did it. */ + if (! cinfo->optimize_coding) { + select_scan_parameters(cinfo); + per_scan_setup(cinfo); + } + (*cinfo->codec->entropy_start_pass) (cinfo, FALSE); + (*cinfo->codec->start_pass) (cinfo, JBUF_CRANK_DEST); + /* We emit frame/scan headers now */ + if (master->scan_number == 0) + (*cinfo->marker->write_frame_header) (cinfo); + (*cinfo->marker->write_scan_header) (cinfo); + master->pub.call_pass_startup = FALSE; + break; + default: + ERREXIT(cinfo, JERR_NOT_COMPILED); + } + + master->pub.is_last_pass = (master->pass_number == master->total_passes-1); + + /* Set up progress monitor's pass info if present */ + if (cinfo->progress != NULL) { + cinfo->progress->completed_passes = master->pass_number; + cinfo->progress->total_passes = master->total_passes; + } +} + + +/* + * Special start-of-pass hook. + * This is called by jpeg_write_scanlines if call_pass_startup is TRUE. + * In single-pass processing, we need this hook because we don't want to + * write frame/scan headers during jpeg_start_compress; we want to let the + * application write COM markers etc. between jpeg_start_compress and the + * jpeg_write_scanlines loop. + * In multi-pass processing, this routine is not used. + */ + +METHODDEF(void) +pass_startup (j_compress_ptr cinfo) +{ + cinfo->master->call_pass_startup = FALSE; /* reset flag so call only once */ + + (*cinfo->marker->write_frame_header) (cinfo); + (*cinfo->marker->write_scan_header) (cinfo); +} + + +/* + * Finish up at end of pass. + */ + +METHODDEF(void) +finish_pass_master (j_compress_ptr cinfo) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + my_master_ptr master = (my_master_ptr) cinfo->master; + + /* The entropy coder always needs an end-of-pass call, + * either to analyze statistics or to flush its output buffer. + */ + (*lossyc->pub.entropy_finish_pass) (cinfo); + + /* Update state for next pass */ + switch (master->pass_type) { + case main_pass: + /* next pass is either output of scan 0 (after optimization) + * or output of scan 1 (if no optimization). + */ + master->pass_type = output_pass; + if (! cinfo->optimize_coding) + master->scan_number++; + break; + case huff_opt_pass: + /* next pass is always output of current scan */ + master->pass_type = output_pass; + break; + case output_pass: + /* next pass is either optimization or output of next scan */ + if (cinfo->optimize_coding) + master->pass_type = huff_opt_pass; + master->scan_number++; + break; + } + + master->pass_number++; +} + + +/* + * Initialize master compression control. + */ + +GLOBAL(void) +jinit_c_master_control (j_compress_ptr cinfo, boolean transcode_only) +{ + my_master_ptr master; + + master = (my_master_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_comp_master)); + cinfo->master = (struct jpeg_comp_master *) master; + master->pub.prepare_for_pass = prepare_for_pass; + master->pub.pass_startup = pass_startup; + master->pub.finish_pass = finish_pass_master; + master->pub.is_last_pass = FALSE; + + cinfo->data_unit = cinfo->lossless ? 1 : DCTSIZE; + + /* Validate parameters, determine derived values */ + initial_setup(cinfo); + + if (cinfo->scan_info != NULL) { +#ifdef NEED_SCAN_SCRIPT + validate_script(cinfo); +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else { + cinfo->process = JPROC_SEQUENTIAL; + cinfo->num_scans = 1; + } + +#ifdef WITH_ARITHMETIC_PATCH + if ((cinfo->arith_code == 0) && + (cinfo->process == JPROC_PROGRESSIVE || /* TEMPORARY HACK ??? */ + cinfo->process == JPROC_LOSSLESS)) +#else + if (cinfo->process == JPROC_PROGRESSIVE || /* TEMPORARY HACK ??? */ + cinfo->process == JPROC_LOSSLESS) +#endif + cinfo->optimize_coding = TRUE; /* assume default tables no good for + * progressive mode or lossless mode */ + + /* Initialize my private state */ + if (transcode_only) { + /* no main pass in transcoding */ + if (cinfo->optimize_coding) + master->pass_type = huff_opt_pass; + else + master->pass_type = output_pass; + } else { + /* for normal compression, first pass is always this type: */ + master->pass_type = main_pass; + } + master->scan_number = 0; + master->pass_number = 0; + if (cinfo->optimize_coding) + master->total_passes = cinfo->num_scans * 2; + else + master->total_passes = cinfo->num_scans; +} diff --git a/gdcm/Utilities/gdcmjpeg/jcodec.c b/gdcm/Utilities/gdcmjpeg/jcodec.c new file mode 100644 index 0000000..9529caa --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jcodec.c @@ -0,0 +1,53 @@ +/* + * jcodec.c + * + * Copyright (C) 1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains utility functions for the JPEG codec(s). + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jlossy.h" +#include "jlossls.h" + + +/* + * Initialize the compression codec. + * This is called only once, during master selection. + */ + +GLOBAL(void) +jinit_c_codec (j_compress_ptr cinfo) +{ + if (cinfo->process == JPROC_LOSSLESS) { +#ifdef C_LOSSLESS_SUPPORTED + jinit_lossless_c_codec(cinfo); +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else + jinit_lossy_c_codec(cinfo); +} + + +/* + * Initialize the decompression codec. + * This is called only once, during master selection. + */ + +GLOBAL(void) +jinit_d_codec (j_decompress_ptr cinfo) +{ + if (cinfo->process == JPROC_LOSSLESS) { +#ifdef D_LOSSLESS_SUPPORTED + jinit_lossless_d_codec(cinfo); +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else + jinit_lossy_d_codec(cinfo); +} diff --git a/gdcm/Utilities/gdcmjpeg/jcomapi.c b/gdcm/Utilities/gdcmjpeg/jcomapi.c new file mode 100644 index 0000000..9b1fa75 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jcomapi.c @@ -0,0 +1,106 @@ +/* + * jcomapi.c + * + * Copyright (C) 1994-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains application interface routines that are used for both + * compression and decompression. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * Abort processing of a JPEG compression or decompression operation, + * but don't destroy the object itself. + * + * For this, we merely clean up all the nonpermanent memory pools. + * Note that temp files (virtual arrays) are not allowed to belong to + * the permanent pool, so we will be able to close all temp files here. + * Closing a data source or destination, if necessary, is the application's + * responsibility. + */ + +GLOBAL(void) +jpeg_abort (j_common_ptr cinfo) +{ + int pool; + + /* Do nothing if called on a not-initialized or destroyed JPEG object. */ + if (cinfo->mem == NULL) + return; + + /* Releasing pools in reverse order might help avoid fragmentation + * with some (brain-damaged) malloc libraries. + */ + for (pool = JPOOL_NUMPOOLS-1; pool > JPOOL_PERMANENT; pool--) { + (*cinfo->mem->free_pool) (cinfo, pool); + } + + /* Reset overall state for possible reuse of object */ + if (cinfo->is_decompressor) { + cinfo->global_state = DSTATE_START; + /* Try to keep application from accessing now-deleted marker list. + * A bit kludgy to do it here, but this is the most central place. + */ + ((j_decompress_ptr) cinfo)->marker_list = NULL; + } else { + cinfo->global_state = CSTATE_START; + } +} + + +/* + * Destruction of a JPEG object. + * + * Everything gets deallocated except the master jpeg_compress_struct itself + * and the error manager struct. Both of these are supplied by the application + * and must be freed, if necessary, by the application. (Often they are on + * the stack and so don't need to be freed anyway.) + * Closing a data source or destination, if necessary, is the application's + * responsibility. + */ + +GLOBAL(void) +jpeg_destroy (j_common_ptr cinfo) +{ + /* We need only tell the memory manager to release everything. */ + /* NB: mem pointer is NULL if memory mgr failed to initialize. */ + if (cinfo->mem != NULL) + (*cinfo->mem->self_destruct) (cinfo); + cinfo->mem = NULL; /* be safe if jpeg_destroy is called twice */ + cinfo->global_state = 0; /* mark it destroyed */ +} + + +/* + * Convenience routines for allocating quantization and Huffman tables. + * (Would jutils.c be a more reasonable place to put these?) + */ + +GLOBAL(JQUANT_TBL *) +jpeg_alloc_quant_table (j_common_ptr cinfo) +{ + JQUANT_TBL *tbl; + + tbl = (JQUANT_TBL *) + (*cinfo->mem->alloc_small) (cinfo, JPOOL_PERMANENT, SIZEOF(JQUANT_TBL)); + tbl->sent_table = FALSE; /* make sure this is false in any new table */ + return tbl; +} + + +GLOBAL(JHUFF_TBL *) +jpeg_alloc_huff_table (j_common_ptr cinfo) +{ + JHUFF_TBL *tbl; + + tbl = (JHUFF_TBL *) + (*cinfo->mem->alloc_small) (cinfo, JPOOL_PERMANENT, SIZEOF(JHUFF_TBL)); + tbl->sent_table = FALSE; /* make sure this is false in any new table */ + return tbl; +} diff --git a/gdcm/Utilities/gdcmjpeg/jconfig.doc b/gdcm/Utilities/gdcmjpeg/jconfig.doc new file mode 100644 index 0000000..c18d1c0 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jconfig.doc @@ -0,0 +1,155 @@ +/* + * jconfig.doc + * + * Copyright (C) 1991-1994, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file documents the configuration options that are required to + * customize the JPEG software for a particular system. + * + * The actual configuration options for a particular installation are stored + * in jconfig.h. On many machines, jconfig.h can be generated automatically + * or copied from one of the "canned" jconfig files that we supply. But if + * you need to generate a jconfig.h file by hand, this file tells you how. + * + * DO NOT EDIT THIS FILE --- IT WON'T ACCOMPLISH ANYTHING. + * EDIT A COPY NAMED JCONFIG.H. + */ + + +/* + * These symbols indicate the properties of your machine or compiler. + * #define the symbol if yes, #undef it if no. + */ + +/* Does your compiler support function prototypes? + * (If not, you also need to use ansi2knr, see install.doc) + */ +#define HAVE_PROTOTYPES + +/* Does your compiler support the declaration "unsigned char" ? + * How about "unsigned short" ? + */ +#define HAVE_UNSIGNED_CHAR +#define HAVE_UNSIGNED_SHORT + +/* Define "void" as "char" if your compiler doesn't know about type void. + * NOTE: be sure to define void such that "void *" represents the most general + * pointer type, e.g., that returned by malloc(). + */ +/* #define void char */ + +/* Define "const" as empty if your compiler doesn't know the "const" keyword. + */ +/* #define const */ + +/* Define this if an ordinary "char" type is unsigned. + * If you're not sure, leaving it undefined will work at some cost in speed. + * If you defined HAVE_UNSIGNED_CHAR then the speed difference is minimal. + */ +#undef CHAR_IS_UNSIGNED + +/* Define this if your system has an ANSI-conforming file. + */ +#define HAVE_STDDEF_H + +/* Define this if your system has an ANSI-conforming file. + */ +#define HAVE_STDLIB_H + +/* Define this if your system does not have an ANSI/SysV , + * but does have a BSD-style . + */ +#undef NEED_BSD_STRINGS + +/* Define this if your system does not provide typedef size_t in any of the + * ANSI-standard places (stddef.h, stdlib.h, or stdio.h), but places it in + * instead. + */ +#undef NEED_SYS_TYPES_H + +/* For 80x86 machines, you need to define NEED_FAR_POINTERS, + * unless you are using a large-data memory model or 80386 flat-memory mode. + * On less brain-damaged CPUs this symbol must not be defined. + * (Defining this symbol causes large data structures to be referenced through + * "far" pointers and to be allocated with a special version of malloc.) + */ +#undef NEED_FAR_POINTERS + +/* Define this if your linker needs global names to be unique in less + * than the first 15 characters. + */ +#undef NEED_SHORT_EXTERNAL_NAMES + +/* Although a real ANSI C compiler can deal perfectly well with pointers to + * unspecified structures (see "incomplete types" in the spec), a few pre-ANSI + * and pseudo-ANSI compilers get confused. To keep one of these bozos happy, + * define INCOMPLETE_TYPES_BROKEN. This is not recommended unless you + * actually get "missing structure definition" warnings or errors while + * compiling the JPEG code. + */ +#undef INCOMPLETE_TYPES_BROKEN + + +/* + * The following options affect code selection within the JPEG library, + * but they don't need to be visible to applications using the library. + * To minimize application namespace pollution, the symbols won't be + * defined unless JPEG_INTERNALS has been defined. + */ + +#ifdef JPEG_INTERNALS + +/* Define this if your compiler implements ">>" on signed values as a logical + * (unsigned) shift; leave it undefined if ">>" is a signed (arithmetic) shift, + * which is the normal and rational definition. + */ +#undef RIGHT_SHIFT_IS_UNSIGNED + + +#endif /* JPEG_INTERNALS */ + + +/* + * The remaining options do not affect the JPEG library proper, + * but only the sample applications cjpeg/djpeg (see cjpeg.c, djpeg.c). + * Other applications can ignore these. + */ + +#ifdef JPEG_CJPEG_DJPEG + +/* These defines indicate which image (non-JPEG) file formats are allowed. */ + +#define BMP_SUPPORTED /* BMP image file format */ +#define GIF_SUPPORTED /* GIF image file format */ +#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */ +#undef RLE_SUPPORTED /* Utah RLE image file format */ +#define TARGA_SUPPORTED /* Targa image file format */ + +/* Define this if you want to name both input and output files on the command + * line, rather than using stdout and optionally stdin. You MUST do this if + * your system can't cope with binary I/O to stdin/stdout. See comments at + * head of cjpeg.c or djpeg.c. + */ +#undef TWO_FILE_COMMANDLINE + +/* Define this if your system needs explicit cleanup of temporary files. + * This is crucial under MS-DOS, where the temporary "files" may be areas + * of extended memory; on most other systems it's not as important. + */ +#undef NEED_SIGNAL_CATCHER + +/* By default, we open image files with fopen(...,"rb") or fopen(...,"wb"). + * This is necessary on systems that distinguish text files from binary files, + * and is harmless on most systems that don't. If you have one of the rare + * systems that complains about the "b" spec, define this symbol. + */ +#undef DONT_USE_B_MODE + +/* Define this if you want percent-done progress reports from cjpeg/djpeg. + */ +#undef PROGRESS_REPORT + + +#endif /* JPEG_CJPEG_DJPEG */ diff --git a/gdcm/Utilities/gdcmjpeg/jconfig.h b/gdcm/Utilities/gdcmjpeg/jconfig.h new file mode 100644 index 0000000..6a27ca3 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jconfig.h @@ -0,0 +1,58 @@ +/* jconfig.h --- source file edited by configure script */ +/* see jconfig.doc for explanations */ + +#undef HAVE_PROTOTYPES +#undef HAVE_UNSIGNED_CHAR +#undef HAVE_UNSIGNED_SHORT +#undef void +#undef const +#undef CHAR_IS_UNSIGNED +#undef HAVE_STDDEF_H +#undef HAVE_STDLIB_H +#undef NEED_BSD_STRINGS +#undef NEED_SYS_TYPES_H +#undef NEED_FAR_POINTERS +#undef NEED_SHORT_EXTERNAL_NAMES +/* Define this if you get warnings about undefined structures. */ +#undef INCOMPLETE_TYPES_BROKEN + + +#if defined(_WIN32) && !(defined(__CYGWIN__) || defined(__MINGW32__)) +/* Define "boolean" as unsigned char, not int, per Windows custom */ +/* don't conflict if rpcndr.h already read; Note that the w32api headers + used by Cygwin and Mingw do not define "boolean", so jmorecfg.h + handles it later. */ +#ifndef __RPCNDR_H__ +typedef unsigned char boolean; +#endif +#define HAVE_BOOLEAN /* prevent jmorecfg.h from redefining it */ +#endif + +#ifdef JPEG_INTERNALS + +#undef RIGHT_SHIFT_IS_UNSIGNED +#undef INLINE +/* These are for configuring the JPEG memory manager. */ +#undef DEFAULT_MAX_MEM +#undef NO_MKTEMP + +#endif /* JPEG_INTERNALS */ + +#ifdef JPEG_CJPEG_DJPEG + +#define BMP_SUPPORTED /* BMP image file format */ +#define GIF_SUPPORTED /* GIF image file format */ +#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */ +#undef RLE_SUPPORTED /* Utah RLE image file format */ +#define TARGA_SUPPORTED /* Targa image file format */ + +#undef TWO_FILE_COMMANDLINE +#undef NEED_SIGNAL_CATCHER +#undef DONT_USE_B_MODE + +/* Define this if you want percent-done progress reports from cjpeg/djpeg. */ +#undef PROGRESS_REPORT + +#endif /* JPEG_CJPEG_DJPEG */ + +#include "jpegcmake.h" diff --git a/gdcm/Utilities/gdcmjpeg/jcparam.c b/gdcm/Utilities/gdcmjpeg/jcparam.c new file mode 100644 index 0000000..8c85c7b --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jcparam.c @@ -0,0 +1,687 @@ +/* + * jcparam.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains optional default-setting code for the JPEG compressor. + * Applications do not have to use this file, but those that don't use it + * must know a lot more about the innards of the JPEG code. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * Quantization table setup routines + */ + +GLOBAL(void) +jpeg_add_quant_table (j_compress_ptr cinfo, int which_tbl, + const unsigned int *basic_table, + int scale_factor, boolean force_baseline) +/* Define a quantization table equal to the basic_table times + * a scale factor (given as a percentage). + * If force_baseline is TRUE, the computed quantization table entries + * are limited to 1..255 for JPEG baseline compatibility. + */ +{ + JQUANT_TBL ** qtblptr; + int i; + long temp; + + /* Safety check to ensure start_compress not called yet. */ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + if (which_tbl < 0 || which_tbl >= NUM_QUANT_TBLS) + ERREXIT1(cinfo, JERR_DQT_INDEX, which_tbl); + + qtblptr = & cinfo->quant_tbl_ptrs[which_tbl]; + + if (*qtblptr == NULL) + *qtblptr = jpeg_alloc_quant_table((j_common_ptr) cinfo); + + for (i = 0; i < DCTSIZE2; i++) { + temp = ((long) basic_table[i] * scale_factor + 50L) / 100L; + /* limit the values to the valid range */ + if (temp <= 0L) temp = 1L; + if (temp > 32767L) temp = 32767L; /* max quantizer needed for 12 bits */ + if (force_baseline && temp > 255L) + temp = 255L; /* limit to baseline range if requested */ + (*qtblptr)->quantval[i] = (UINT16) temp; + } + + /* Initialize sent_table FALSE so table will be written to JPEG file. */ + (*qtblptr)->sent_table = FALSE; +} + + +GLOBAL(void) +jpeg_set_linear_quality (j_compress_ptr cinfo, int scale_factor, + boolean force_baseline) +/* Set or change the 'quality' (quantization) setting, using default tables + * and a straight percentage-scaling quality scale. In most cases it's better + * to use jpeg_set_quality (below); this entry point is provided for + * applications that insist on a linear percentage scaling. + */ +{ + /* These are the sample quantization tables given in JPEG spec section K.1. + * The spec says that the values given produce "good" quality, and + * when divided by 2, "very good" quality. + */ + static const unsigned int std_luminance_quant_tbl[DCTSIZE2] = { + 16, 11, 10, 16, 24, 40, 51, 61, + 12, 12, 14, 19, 26, 58, 60, 55, + 14, 13, 16, 24, 40, 57, 69, 56, + 14, 17, 22, 29, 51, 87, 80, 62, + 18, 22, 37, 56, 68, 109, 103, 77, + 24, 35, 55, 64, 81, 104, 113, 92, + 49, 64, 78, 87, 103, 121, 120, 101, + 72, 92, 95, 98, 112, 100, 103, 99 + }; + static const unsigned int std_chrominance_quant_tbl[DCTSIZE2] = { + 17, 18, 24, 47, 99, 99, 99, 99, + 18, 21, 26, 66, 99, 99, 99, 99, + 24, 26, 56, 99, 99, 99, 99, 99, + 47, 66, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99 + }; + + /* Set up two quantization tables using the specified scaling */ + jpeg_add_quant_table(cinfo, 0, std_luminance_quant_tbl, + scale_factor, force_baseline); + jpeg_add_quant_table(cinfo, 1, std_chrominance_quant_tbl, + scale_factor, force_baseline); +} + + +GLOBAL(int) +jpeg_quality_scaling (int quality) +/* Convert a user-specified quality rating to a percentage scaling factor + * for an underlying quantization table, using our recommended scaling curve. + * The input 'quality' factor should be 0 (terrible) to 100 (very good). + */ +{ + /* Safety limit on quality factor. Convert 0 to 1 to avoid zero divide. */ + if (quality <= 0) quality = 1; + if (quality > 100) quality = 100; + + /* The basic table is used as-is (scaling 100) for a quality of 50. + * Qualities 50..100 are converted to scaling percentage 200 - 2*Q; + * note that at Q=100 the scaling is 0, which will cause jpeg_add_quant_table + * to make all the table entries 1 (hence, minimum quantization loss). + * Qualities 1..50 are converted to scaling percentage 5000/Q. + */ + if (quality < 50) + quality = 5000 / quality; + else + quality = 200 - quality*2; + + return quality; +} + + +GLOBAL(void) +jpeg_set_quality (j_compress_ptr cinfo, int quality, boolean force_baseline) +/* Set or change the 'quality' (quantization) setting, using default tables. + * This is the standard quality-adjusting entry point for typical user + * interfaces; only those who want detailed control over quantization tables + * would use the preceding three routines directly. + */ +{ + /* Convert user 0-100 rating to percentage scaling */ + quality = jpeg_quality_scaling(quality); + + /* Set up standard quality tables */ + jpeg_set_linear_quality(cinfo, quality, force_baseline); +} + + +/* + * Huffman table setup routines + */ + +LOCAL(void) +add_huff_table (j_compress_ptr cinfo, + JHUFF_TBL **htblptr, const UINT8 *bits, const UINT8 *val) +/* Define a Huffman table */ +{ + int nsymbols, len; + + if (*htblptr == NULL) + *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo); + + /* Copy the number-of-symbols-of-each-code-length counts */ + MEMCOPY((*htblptr)->bits, bits, SIZEOF((*htblptr)->bits)); + + /* Validate the counts. We do this here mainly so we can copy the right + * number of symbols from the val[] array, without risking marching off + * the end of memory. jchuff.c will do a more thorough test later. + */ + nsymbols = 0; + for (len = 1; len <= 16; len++) + nsymbols += bits[len]; + if (nsymbols < 1 || nsymbols > 256) + ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); + + MEMCOPY((*htblptr)->huffval, val, nsymbols * SIZEOF(UINT8)); + + /* Initialize sent_table FALSE so table will be written to JPEG file. */ + (*htblptr)->sent_table = FALSE; +} + + +LOCAL(void) +std_huff_tables (j_compress_ptr cinfo) +/* Set up the standard Huffman tables (cf. JPEG standard section K.3) */ +/* IMPORTANT: these are only valid for 8-bit data precision! */ +{ + static const UINT8 bits_dc_luminance[17] = + { /* 0-base */ 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 }; + static const UINT8 val_dc_luminance[] = + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; + + static const UINT8 bits_dc_chrominance[17] = + { /* 0-base */ 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 }; + static const UINT8 val_dc_chrominance[] = + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; + + static const UINT8 bits_ac_luminance[17] = + { /* 0-base */ 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d }; + static const UINT8 val_ac_luminance[] = + { 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, + 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, + 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, + 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, + 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, + 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, + 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, + 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, + 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, + 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, + 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, + 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, + 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, + 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, + 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, + 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, + 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa }; + + static const UINT8 bits_ac_chrominance[17] = + { /* 0-base */ 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77 }; + static const UINT8 val_ac_chrominance[] = + { 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, + 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, + 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, + 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, + 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, + 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, + 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, + 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, + 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, + 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, + 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, + 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, + 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, + 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, + 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, + 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, + 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, + 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa }; + + add_huff_table(cinfo, &cinfo->dc_huff_tbl_ptrs[0], + bits_dc_luminance, val_dc_luminance); + add_huff_table(cinfo, &cinfo->ac_huff_tbl_ptrs[0], + bits_ac_luminance, val_ac_luminance); + add_huff_table(cinfo, &cinfo->dc_huff_tbl_ptrs[1], + bits_dc_chrominance, val_dc_chrominance); + add_huff_table(cinfo, &cinfo->ac_huff_tbl_ptrs[1], + bits_ac_chrominance, val_ac_chrominance); +} + + +/* + * Default parameter setup for compression. + * + * Applications that don't choose to use this routine must do their + * own setup of all these parameters. Alternately, you can call this + * to establish defaults and then alter parameters selectively. This + * is the recommended approach since, if we add any new parameters, + * your code will still work (they'll be set to reasonable defaults). + */ + +GLOBAL(void) +jpeg_set_defaults (j_compress_ptr cinfo) +{ + int i; + + /* Safety check to ensure start_compress not called yet. */ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + /* Allocate comp_info array large enough for maximum component count. + * Array is made permanent in case application wants to compress + * multiple images at same param settings. + */ + if (cinfo->comp_info == NULL) + cinfo->comp_info = (jpeg_component_info *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + MAX_COMPONENTS * SIZEOF(jpeg_component_info)); + + /* Initialize everything not dependent on the color space */ + + cinfo->lossless = FALSE; + cinfo->data_precision = BITS_IN_JSAMPLE; + /* Set up two quantization tables using default quality of 75 */ + jpeg_set_quality(cinfo, 75, TRUE); + /* Set up two Huffman tables */ + std_huff_tables(cinfo); + + /* Initialize default arithmetic coding conditioning */ + for (i = 0; i < NUM_ARITH_TBLS; i++) { + cinfo->arith_dc_L[i] = 0; + cinfo->arith_dc_U[i] = 1; + cinfo->arith_ac_K[i] = 5; + } + + /* Default is no multiple-scan output */ + cinfo->scan_info = NULL; + cinfo->num_scans = 0; + + /* Expect normal source image, not raw downsampled data */ + cinfo->raw_data_in = FALSE; + + /* Use Huffman coding, not arithmetic coding, by default */ + cinfo->arith_code = FALSE; + + /* By default, don't do extra passes to optimize entropy coding */ + cinfo->optimize_coding = FALSE; + /* The standard Huffman tables are only valid for 8-bit data precision. + * If the precision is higher, force optimization on so that usable + * tables will be computed. This test can be removed if default tables + * are supplied that are valid for the desired precision. + */ + if (cinfo->data_precision > 8) + cinfo->optimize_coding = TRUE; + + /* By default, use the simpler non-cosited sampling alignment */ + cinfo->CCIR601_sampling = FALSE; + + /* No input smoothing */ + cinfo->smoothing_factor = 0; + + /* DCT algorithm preference */ + cinfo->dct_method = JDCT_DEFAULT; + + /* No restart markers */ + cinfo->restart_interval = 0; + cinfo->restart_in_rows = 0; + + /* Fill in default JFIF marker parameters. Note that whether the marker + * will actually be written is determined by jpeg_set_colorspace. + * + * By default, the library emits JFIF version code 1.01. + * An application that wants to emit JFIF 1.02 extension markers should set + * JFIF_minor_version to 2. We could probably get away with just defaulting + * to 1.02, but there may still be some decoders in use that will complain + * about that; saying 1.01 should minimize compatibility problems. + */ + cinfo->JFIF_major_version = 1; /* Default JFIF version = 1.01 */ + cinfo->JFIF_minor_version = 1; + cinfo->density_unit = 0; /* Pixel size is unknown by default */ + cinfo->X_density = 1; /* Pixel aspect ratio is square by default */ + cinfo->Y_density = 1; + + /* Choose JPEG colorspace based on input space, set defaults accordingly */ + + jpeg_default_colorspace(cinfo); +} + + +/* + * Select an appropriate JPEG colorspace for in_color_space. + */ + +GLOBAL(void) +jpeg_default_colorspace (j_compress_ptr cinfo) +{ + if (cinfo->lossless) + jpeg_set_colorspace(cinfo, cinfo->in_color_space); + else { /* lossy */ + switch (cinfo->in_color_space) { + case JCS_GRAYSCALE: + jpeg_set_colorspace(cinfo, JCS_GRAYSCALE); + break; + case JCS_RGB: + jpeg_set_colorspace(cinfo, JCS_YCbCr); + break; + case JCS_YCbCr: + jpeg_set_colorspace(cinfo, JCS_YCbCr); + break; + case JCS_CMYK: + jpeg_set_colorspace(cinfo, JCS_CMYK); /* By default, no translation */ + break; + case JCS_YCCK: + jpeg_set_colorspace(cinfo, JCS_YCCK); + break; + case JCS_UNKNOWN: + jpeg_set_colorspace(cinfo, JCS_UNKNOWN); + break; + default: + ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE); + } + } +} + + +/* + * Set the JPEG colorspace, and choose colorspace-dependent default values. + */ + +GLOBAL(void) +jpeg_set_colorspace (j_compress_ptr cinfo, J_COLOR_SPACE colorspace) +{ + jpeg_component_info * compptr; + int ci; + +#define SET_COMP(index,id,hsamp,vsamp,quant,dctbl,actbl) \ + (compptr = &cinfo->comp_info[index], \ + compptr->component_id = (id), \ + compptr->h_samp_factor = (hsamp), \ + compptr->v_samp_factor = (vsamp), \ + compptr->quant_tbl_no = (quant), \ + compptr->dc_tbl_no = (dctbl), \ + compptr->ac_tbl_no = (actbl) ) + + /* Safety check to ensure start_compress not called yet. */ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + /* For all colorspaces, we use Q and Huff tables 0 for luminance components, + * tables 1 for chrominance components. + */ + + cinfo->jpeg_color_space = colorspace; + + cinfo->write_JFIF_header = FALSE; /* No marker for non-JFIF colorspaces */ + cinfo->write_Adobe_marker = FALSE; /* write no Adobe marker by default */ + + switch (colorspace) { + case JCS_GRAYSCALE: + cinfo->write_JFIF_header = TRUE; /* Write a JFIF marker */ + cinfo->num_components = 1; + /* JFIF specifies component ID 1 */ + SET_COMP(0, 1, 1,1, 0, 0,0); + break; + case JCS_RGB: + cinfo->write_Adobe_marker = TRUE; /* write Adobe marker to flag RGB */ + cinfo->num_components = 3; + SET_COMP(0, 0x52 /* 'R' */, 1,1, 0, 0,0); + SET_COMP(1, 0x47 /* 'G' */, 1,1, 0, 0,0); + SET_COMP(2, 0x42 /* 'B' */, 1,1, 0, 0,0); + break; + case JCS_YCbCr: + cinfo->write_JFIF_header = TRUE; /* Write a JFIF marker */ + cinfo->num_components = 3; + /* JFIF specifies component IDs 1,2,3 */ + if (cinfo->lossless) { + SET_COMP(0, 1, 1,1, 0, 0,0); + SET_COMP(1, 2, 1,1, 1, 1,1); + SET_COMP(2, 3, 1,1, 1, 1,1); + } else { /* lossy */ + /* We default to 2x2 subsamples of chrominance */ + SET_COMP(0, 1, 2,2, 0, 0,0); + SET_COMP(1, 2, 1,1, 1, 1,1); + SET_COMP(2, 3, 1,1, 1, 1,1); + } + break; + case JCS_CMYK: + cinfo->write_Adobe_marker = TRUE; /* write Adobe marker to flag CMYK */ + cinfo->num_components = 4; + SET_COMP(0, 0x43 /* 'C' */, 1,1, 0, 0,0); + SET_COMP(1, 0x4D /* 'M' */, 1,1, 0, 0,0); + SET_COMP(2, 0x59 /* 'Y' */, 1,1, 0, 0,0); + SET_COMP(3, 0x4B /* 'K' */, 1,1, 0, 0,0); + break; + case JCS_YCCK: + cinfo->write_Adobe_marker = TRUE; /* write Adobe marker to flag YCCK */ + cinfo->num_components = 4; + if (cinfo->lossless) { + SET_COMP(0, 1, 1,1, 0, 0,0); + SET_COMP(1, 2, 1,1, 1, 1,1); + SET_COMP(2, 3, 1,1, 1, 1,1); + SET_COMP(3, 4, 1,1, 0, 0,0); + } else { /* lossy */ + SET_COMP(0, 1, 2,2, 0, 0,0); + SET_COMP(1, 2, 1,1, 1, 1,1); + SET_COMP(2, 3, 1,1, 1, 1,1); + SET_COMP(3, 4, 2,2, 0, 0,0); + } + break; + case JCS_UNKNOWN: + cinfo->num_components = cinfo->input_components; + if (cinfo->num_components < 1 || cinfo->num_components > MAX_COMPONENTS) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components, + MAX_COMPONENTS); + for (ci = 0; ci < cinfo->num_components; ci++) { + SET_COMP(ci, ci, 1,1, 0, 0,0); + } + break; + default: + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + } +} + + +#ifdef C_PROGRESSIVE_SUPPORTED + +LOCAL(jpeg_scan_info *) +fill_scans (jpeg_scan_info * scanptr, int ncomps, + int Ss, int Se, int Ah, int Al) +/* Support routine: generate one scan for each component */ +{ + int ci; + + for (ci = 0; ci < ncomps; ci++) { + scanptr->comps_in_scan = 1; + scanptr->component_index[0] = ci; + scanptr->Ss = Ss; + scanptr->Se = Se; + scanptr->Ah = Ah; + scanptr->Al = Al; + scanptr++; + } + return scanptr; +} + + +LOCAL(jpeg_scan_info *) +fill_a_scan (jpeg_scan_info * scanptr, int ci, + int Ss, int Se, int Ah, int Al) +/* Support routine: generate one scan for specified component */ +{ + scanptr->comps_in_scan = 1; + scanptr->component_index[0] = ci; + scanptr->Ss = Ss; + scanptr->Se = Se; + scanptr->Ah = Ah; + scanptr->Al = Al; + scanptr++; + return scanptr; +} + +LOCAL(jpeg_scan_info *) +fill_dc_scans (jpeg_scan_info * scanptr, int ncomps, int Ah, int Al) +/* Support routine: generate interleaved DC scan if possible, else N scans */ +{ + int ci; + + if (ncomps <= MAX_COMPS_IN_SCAN) { + /* Single interleaved DC scan */ + scanptr->comps_in_scan = ncomps; + for (ci = 0; ci < ncomps; ci++) + scanptr->component_index[ci] = ci; + scanptr->Ss = scanptr->Se = 0; + scanptr->Ah = Ah; + scanptr->Al = Al; + scanptr++; + } else { + /* Noninterleaved DC scan for each component */ + scanptr = fill_scans(scanptr, ncomps, 0, 0, Ah, Al); + } + return scanptr; +} + + +/* + * Create a recommended progressive-JPEG script. + * cinfo->num_components and cinfo->jpeg_color_space must be correct. + */ + +GLOBAL(void) +jpeg_simple_progression (j_compress_ptr cinfo) +{ + int ncomps = cinfo->num_components; + int nscans; + jpeg_scan_info * scanptr; + + /* Safety check to ensure start_compress not called yet. */ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + /* Figure space needed for script. Calculation must match code below! */ + if (ncomps == 3 && cinfo->jpeg_color_space == JCS_YCbCr) { + /* Custom script for YCbCr color images. */ + nscans = 10; + } else { + /* All-purpose script for other color spaces. */ + if (ncomps > MAX_COMPS_IN_SCAN) + nscans = 6 * ncomps; /* 2 DC + 4 AC scans per component */ + else + nscans = 2 + 4 * ncomps; /* 2 DC scans; 4 AC scans per component */ + } + + /* Allocate space for script. + * We need to put it in the permanent pool in case the application performs + * multiple compressions without changing the settings. To avoid a memory + * leak if jpeg_simple_progression is called repeatedly for the same JPEG + * object, we try to re-use previously allocated space, and we allocate + * enough space to handle YCbCr even if initially asked for grayscale. + */ + if (cinfo->script_space == NULL || cinfo->script_space_size < nscans) { + cinfo->script_space_size = MAX(nscans, 10); + cinfo->script_space = (jpeg_scan_info *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + cinfo->script_space_size * SIZEOF(jpeg_scan_info)); + } + scanptr = cinfo->script_space; + cinfo->scan_info = scanptr; + cinfo->num_scans = nscans; + + if (ncomps == 3 && cinfo->jpeg_color_space == JCS_YCbCr) { + /* Custom script for YCbCr color images. */ + /* Initial DC scan */ + scanptr = fill_dc_scans(scanptr, ncomps, 0, 1); + /* Initial AC scan: get some luma data out in a hurry */ + scanptr = fill_a_scan(scanptr, 0, 1, 5, 0, 2); + /* Chroma data is too small to be worth expending many scans on */ + scanptr = fill_a_scan(scanptr, 2, 1, 63, 0, 1); + scanptr = fill_a_scan(scanptr, 1, 1, 63, 0, 1); + /* Complete spectral selection for luma AC */ + scanptr = fill_a_scan(scanptr, 0, 6, 63, 0, 2); + /* Refine next bit of luma AC */ + scanptr = fill_a_scan(scanptr, 0, 1, 63, 2, 1); + /* Finish DC successive approximation */ + scanptr = fill_dc_scans(scanptr, ncomps, 1, 0); + /* Finish AC successive approximation */ + scanptr = fill_a_scan(scanptr, 2, 1, 63, 1, 0); + scanptr = fill_a_scan(scanptr, 1, 1, 63, 1, 0); + /* Luma bottom bit comes last since it's usually largest scan */ + scanptr = fill_a_scan(scanptr, 0, 1, 63, 1, 0); + } else { + /* All-purpose script for other color spaces. */ + /* Successive approximation first pass */ + scanptr = fill_dc_scans(scanptr, ncomps, 0, 1); + scanptr = fill_scans(scanptr, ncomps, 1, 5, 0, 2); + scanptr = fill_scans(scanptr, ncomps, 6, 63, 0, 2); + /* Successive approximation second pass */ + scanptr = fill_scans(scanptr, ncomps, 1, 63, 2, 1); + /* Successive approximation final pass */ + scanptr = fill_dc_scans(scanptr, ncomps, 1, 0); + scanptr = fill_scans(scanptr, ncomps, 1, 63, 1, 0); + } +} + +#endif /* C_PROGRESSIVE_SUPPORTED */ + + +#ifdef C_LOSSLESS_SUPPORTED + +/* + * Create a single-entry lossless-JPEG script containing all components. + * cinfo->num_components must be correct. + */ + +GLOBAL(void) +jpeg_simple_lossless (j_compress_ptr cinfo, int predictor, int point_transform) +{ + int ncomps = cinfo->num_components; + int nscans = 1; + int ci; + jpeg_scan_info * scanptr; + + /* Safety check to ensure start_compress not called yet. */ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + cinfo->lossless = TRUE; + + /* Set jpeg_color_space. */ + jpeg_default_colorspace(cinfo); + + /* Check to ensure that all components will fit in one scan. */ + if (cinfo->num_components > MAX_COMPS_IN_SCAN) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components, + MAX_COMPS_IN_SCAN); + + /* Allocate space for script. + * We need to put it in the permanent pool in case the application performs + * multiple compressions without changing the settings. To avoid a memory + * leak if jpeg_simple_lossless is called repeatedly for the same JPEG + * object, we try to re-use previously allocated space. + */ + if (cinfo->script_space == NULL || cinfo->script_space_size < nscans) { + cinfo->script_space_size = nscans; + cinfo->script_space = (jpeg_scan_info *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + cinfo->script_space_size * SIZEOF(jpeg_scan_info)); + } + scanptr = cinfo->script_space; + cinfo->scan_info = scanptr; + cinfo->num_scans = nscans; + + /* Fill the script. */ + scanptr->comps_in_scan = ncomps; + for (ci = 0; ci < ncomps; ci++) + scanptr->component_index[ci] = ci; + scanptr->Ss = predictor; + scanptr->Se = 0; + scanptr->Ah = 0; + scanptr->Al = point_transform; +} + +#endif /* C_LOSSLESS_SUPPORTED */ diff --git a/gdcm/Utilities/gdcmjpeg/jcphuff.c b/gdcm/Utilities/gdcmjpeg/jcphuff.c new file mode 100644 index 0000000..39c641a --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jcphuff.c @@ -0,0 +1,848 @@ +/* + * jcphuff.c + * + * Copyright (C) 1995-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains Huffman entropy encoding routines for progressive JPEG. + * + * We do not support output suspension in this module, since the library + * currently does not allow multiple-scan files to be written with output + * suspension. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jlossy.h" /* Private declarations for lossy codec */ +#include "jchuff.h" /* Declarations shared with jc*huff.c */ + +#ifdef C_PROGRESSIVE_SUPPORTED + +/* Expanded entropy encoder object for progressive Huffman encoding. */ + +typedef struct { + /* Mode flag: TRUE for optimization, FALSE for actual data output */ + boolean gather_statistics; + + /* Bit-level coding status. + * next_output_byte/free_in_buffer are local copies of cinfo->dest fields. + */ + JOCTET * next_output_byte; /* => next byte to write in buffer */ + size_t free_in_buffer; /* # of byte spaces remaining in buffer */ + INT32 put_buffer; /* current bit-accumulation buffer */ + int put_bits; /* # of bits now in it */ + j_compress_ptr cinfo; /* link to cinfo (needed for dump_buffer) */ + + /* Coding status for DC components */ + int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */ + + /* Coding status for AC components */ + int ac_tbl_no; /* the table number of the single component */ + unsigned int EOBRUN; /* run length of EOBs */ + unsigned int BE; /* # of buffered correction bits before MCU */ + char * bit_buffer; /* buffer for correction bits (1 per char) */ + /* packing correction bits tightly would save some space but cost time... */ + + unsigned int restarts_to_go; /* MCUs left in this restart interval */ + int next_restart_num; /* next restart number to write (0-7) */ + + /* Pointers to derived tables (these workspaces have image lifespan). + * Since any one scan codes only DC or only AC, we only need one set + * of tables, not one for DC and one for AC. + */ + c_derived_tbl * derived_tbls[NUM_HUFF_TBLS]; + + /* Statistics tables for optimization; again, one set is enough */ + long * count_ptrs[NUM_HUFF_TBLS]; +} phuff_entropy_encoder; + +typedef phuff_entropy_encoder * phuff_entropy_ptr; + +/* MAX_CORR_BITS is the number of bits the AC refinement correction-bit + * buffer can hold. Larger sizes may slightly improve compression, but + * 1000 is already well into the realm of overkill. + * The minimum safe size is 64 bits. + */ + +#define MAX_CORR_BITS 1000 /* Max # of correction bits I can buffer */ + +/* IRIGHT_SHIFT is like RIGHT_SHIFT, but works on int rather than INT32. + * We assume that int right shift is unsigned if INT32 right shift is, + * which should be safe. + */ + +#ifdef RIGHT_SHIFT_IS_UNSIGNED +#define ISHIFT_TEMPS int ishift_temp; +#define IRIGHT_SHIFT(x,shft) \ + ((ishift_temp = (x)) < 0 ? \ + (ishift_temp >> (shft)) | ((~0) << (16-(shft))) : \ + (ishift_temp >> (shft))) +#else +#define ISHIFT_TEMPS +#define IRIGHT_SHIFT(x,shft) ((x) >> (shft)) +#endif + +/* Forward declarations */ +METHODDEF(boolean) encode_mcu_DC_first JPP((j_compress_ptr cinfo, + JBLOCKROW *MCU_data)); +METHODDEF(boolean) encode_mcu_AC_first JPP((j_compress_ptr cinfo, + JBLOCKROW *MCU_data)); +METHODDEF(boolean) encode_mcu_DC_refine JPP((j_compress_ptr cinfo, + JBLOCKROW *MCU_data)); +METHODDEF(boolean) encode_mcu_AC_refine JPP((j_compress_ptr cinfo, + JBLOCKROW *MCU_data)); +METHODDEF(void) finish_pass_phuff JPP((j_compress_ptr cinfo)); +METHODDEF(void) finish_pass_gather_phuff JPP((j_compress_ptr cinfo)); + + +/* + * Initialize for a Huffman-compressed scan using progressive JPEG. + */ + +METHODDEF(void) +start_pass_phuff (j_compress_ptr cinfo, boolean gather_statistics) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + phuff_entropy_ptr entropy = (phuff_entropy_ptr) lossyc->entropy_private; + boolean is_DC_band; + int ci, tbl; + jpeg_component_info * compptr; + + entropy->cinfo = cinfo; + entropy->gather_statistics = gather_statistics; + + is_DC_band = (cinfo->Ss == 0); + + /* We assume jcmaster.c already validated the scan parameters. */ + + /* Select execution routines */ + if (cinfo->Ah == 0) { + if (is_DC_band) + lossyc->entropy_encode_mcu = encode_mcu_DC_first; + else + lossyc->entropy_encode_mcu = encode_mcu_AC_first; + } else { + if (is_DC_band) + lossyc->entropy_encode_mcu = encode_mcu_DC_refine; + else { + lossyc->entropy_encode_mcu = encode_mcu_AC_refine; + /* AC refinement needs a correction bit buffer */ + if (entropy->bit_buffer == NULL) + entropy->bit_buffer = (char *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + MAX_CORR_BITS * SIZEOF(char)); + } + } + if (gather_statistics) + lossyc->pub.entropy_finish_pass = finish_pass_gather_phuff; + else + lossyc->pub.entropy_finish_pass = finish_pass_phuff; + + /* Only DC coefficients may be interleaved, so cinfo->comps_in_scan = 1 + * for AC coefficients. + */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* Initialize DC predictions to 0 */ + entropy->last_dc_val[ci] = 0; + /* Get table index */ + if (is_DC_band) { + if (cinfo->Ah != 0) /* DC refinement needs no table */ + continue; + tbl = compptr->dc_tbl_no; + } else { + entropy->ac_tbl_no = tbl = compptr->ac_tbl_no; + } + if (gather_statistics) { + /* Check for invalid table index */ + /* (make_c_derived_tbl does this in the other path) */ + if (tbl < 0 || tbl >= NUM_HUFF_TBLS) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tbl); + /* Allocate and zero the statistics tables */ + /* Note that jpeg_gen_optimal_table expects 257 entries in each table! */ + if (entropy->count_ptrs[tbl] == NULL) + entropy->count_ptrs[tbl] = (long *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + 257 * SIZEOF(long)); + MEMZERO(entropy->count_ptrs[tbl], 257 * SIZEOF(long)); + } else { + /* Compute derived values for Huffman table */ + /* We may do this more than once for a table, but it's not expensive */ + jpeg_make_c_derived_tbl(cinfo, is_DC_band, tbl, + & entropy->derived_tbls[tbl]); + } + } + + /* Initialize AC stuff */ + entropy->EOBRUN = 0; + entropy->BE = 0; + + /* Initialize bit buffer to empty */ + entropy->put_buffer = 0; + entropy->put_bits = 0; + + /* Initialize restart stuff */ + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num = 0; +} + + +/* Outputting bytes to the file. + * NB: these must be called only when actually outputting, + * that is, entropy->gather_statistics == FALSE. + */ + +/* Emit a byte */ +#define emit_byte(entropy,val) \ + { *(entropy)->next_output_byte++ = (JOCTET) (val); \ + if (--(entropy)->free_in_buffer == 0) \ + dump_buffer(entropy); } + + +LOCAL(void) +dump_buffer (phuff_entropy_ptr entropy) +/* Empty the output buffer; we do not support suspension in this module. */ +{ + struct jpeg_destination_mgr * dest = entropy->cinfo->dest; + + if (! (*dest->empty_output_buffer) (entropy->cinfo)) + ERREXIT(entropy->cinfo, JERR_CANT_SUSPEND); + /* After a successful buffer dump, must reset buffer pointers */ + entropy->next_output_byte = dest->next_output_byte; + entropy->free_in_buffer = dest->free_in_buffer; +} + + +/* Outputting bits to the file */ + +/* Only the right 24 bits of put_buffer are used; the valid bits are + * left-justified in this part. At most 16 bits can be passed to emit_bits + * in one call, and we never retain more than 7 bits in put_buffer + * between calls, so 24 bits are sufficient. + */ + +INLINE +LOCAL(void) +emit_bits (phuff_entropy_ptr entropy, unsigned int code, int size) +/* Emit some bits, unless we are in gather mode */ +{ + /* This routine is heavily used, so it's worth coding tightly. */ + register INT32 put_buffer = (INT32) code; + register int put_bits = entropy->put_bits; + + /* if size is 0, caller used an invalid Huffman table entry */ + if (size == 0) + ERREXIT(entropy->cinfo, JERR_HUFF_MISSING_CODE); + + if (entropy->gather_statistics) + return; /* do nothing if we're only getting stats */ + + put_buffer &= (((INT32) 1)<put_buffer; /* and merge with old buffer contents */ + + while (put_bits >= 8) { + int c = (int) ((put_buffer >> 16) & 0xFF); + + emit_byte(entropy, c); + if (c == 0xFF) { /* need to stuff a zero byte? */ + emit_byte(entropy, 0); + } + put_buffer <<= 8; + put_bits -= 8; + } + + entropy->put_buffer = put_buffer; /* update variables */ + entropy->put_bits = put_bits; +} + + +LOCAL(void) +flush_bits (phuff_entropy_ptr entropy) +{ + emit_bits(entropy, 0x7F, 7); /* fill any partial byte with ones */ + entropy->put_buffer = 0; /* and reset bit-buffer to empty */ + entropy->put_bits = 0; +} + + +/* + * Emit (or just count) a Huffman symbol. + */ + +INLINE +LOCAL(void) +emit_symbol (phuff_entropy_ptr entropy, int tbl_no, int symbol) +{ + if (entropy->gather_statistics) + entropy->count_ptrs[tbl_no][symbol]++; + else { + c_derived_tbl * tbl = entropy->derived_tbls[tbl_no]; + emit_bits(entropy, tbl->ehufco[symbol], tbl->ehufsi[symbol]); + } +} + + +/* + * Emit bits from a correction bit buffer. + */ + +LOCAL(void) +emit_buffered_bits (phuff_entropy_ptr entropy, char * bufstart, + unsigned int nbits) +{ + if (entropy->gather_statistics) + return; /* no real work */ + + while (nbits > 0) { + emit_bits(entropy, (unsigned int) (*bufstart), 1); + bufstart++; + nbits--; + } +} + + +/* + * Emit any pending EOBRUN symbol. + */ + +LOCAL(void) +emit_eobrun (phuff_entropy_ptr entropy) +{ + register int temp, nbits; + + if (entropy->EOBRUN > 0) { /* if there is any pending EOBRUN */ + temp = entropy->EOBRUN; + nbits = 0; + while ((temp >>= 1)) + nbits++; + /* safety check: shouldn't happen given limited correction-bit buffer */ + if (nbits > 14) + ERREXIT(entropy->cinfo, JERR_HUFF_MISSING_CODE); + + emit_symbol(entropy, entropy->ac_tbl_no, nbits << 4); + if (nbits) + emit_bits(entropy, entropy->EOBRUN, nbits); + + entropy->EOBRUN = 0; + + /* Emit any buffered correction bits */ + emit_buffered_bits(entropy, entropy->bit_buffer, entropy->BE); + entropy->BE = 0; + } +} + + +/* + * Emit a restart marker & resynchronize predictions. + */ + +LOCAL(void) +emit_restart (phuff_entropy_ptr entropy, int restart_num) +{ + int ci; + + emit_eobrun(entropy); + + if (! entropy->gather_statistics) { + flush_bits(entropy); + emit_byte(entropy, 0xFF); + emit_byte(entropy, JPEG_RST0 + restart_num); + } + + if (entropy->cinfo->Ss == 0) { + /* Re-initialize DC predictions to 0 */ + for (ci = 0; ci < entropy->cinfo->comps_in_scan; ci++) + entropy->last_dc_val[ci] = 0; + } else { + /* Re-initialize all AC-related fields to 0 */ + entropy->EOBRUN = 0; + entropy->BE = 0; + } +} + + +/* + * MCU encoding for DC initial scan (either spectral selection, + * or first pass of successive approximation). + */ + +METHODDEF(boolean) +encode_mcu_DC_first (j_compress_ptr cinfo, JBLOCKROW *MCU_data) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + phuff_entropy_ptr entropy = (phuff_entropy_ptr) lossyc->entropy_private; + register int temp, temp2; + register int nbits; + int blkn, ci; + int Al = cinfo->Al; + JBLOCKROW block; + jpeg_component_info * compptr; + ISHIFT_TEMPS + + entropy->next_output_byte = cinfo->dest->next_output_byte; + entropy->free_in_buffer = cinfo->dest->free_in_buffer; + + /* Emit restart marker if needed */ + if (cinfo->restart_interval) + if (entropy->restarts_to_go == 0) + emit_restart(entropy, entropy->next_restart_num); + + /* Encode the MCU data blocks */ + for (blkn = 0; blkn < cinfo->data_units_in_MCU; blkn++) { + block = MCU_data[blkn]; + ci = cinfo->MCU_membership[blkn]; + compptr = cinfo->cur_comp_info[ci]; + + /* Compute the DC value after the required point transform by Al. + * This is simply an arithmetic right shift. + */ + temp2 = IRIGHT_SHIFT((int) ((*block)[0]), Al); + + /* DC differences are figured on the point-transformed values. */ + temp = temp2 - entropy->last_dc_val[ci]; + entropy->last_dc_val[ci] = temp2; + + /* Encode the DC coefficient difference per section G.1.2.1 */ + temp2 = temp; + if (temp < 0) { + temp = -temp; /* temp is abs value of input */ + /* For a negative input, want temp2 = bitwise complement of abs(input) */ + /* This code assumes we are on a two's complement machine */ + temp2--; + } + + /* Find the number of bits needed for the magnitude of the coefficient */ + nbits = 0; + while (temp) { + nbits++; + temp >>= 1; + } + /* Check for out-of-range coefficient values. + * Since we're encoding a difference, the range limit is twice as much. + */ + if (nbits > MAX_COEF_BITS+1) + ERREXIT(cinfo, JERR_BAD_DCT_COEF); + + /* Count/emit the Huffman-coded symbol for the number of bits */ + emit_symbol(entropy, compptr->dc_tbl_no, nbits); + + /* Emit that number of bits of the value, if positive, */ + /* or the complement of its magnitude, if negative. */ + if (nbits) /* emit_bits rejects calls with size 0 */ + emit_bits(entropy, (unsigned int) temp2, nbits); + } + + cinfo->dest->next_output_byte = entropy->next_output_byte; + cinfo->dest->free_in_buffer = entropy->free_in_buffer; + + /* Update restart-interval state too */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num++; + entropy->next_restart_num &= 7; + } + entropy->restarts_to_go--; + } + + return TRUE; +} + + +/* + * MCU encoding for AC initial scan (either spectral selection, + * or first pass of successive approximation). + */ + +METHODDEF(boolean) +encode_mcu_AC_first (j_compress_ptr cinfo, JBLOCKROW *MCU_data) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + phuff_entropy_ptr entropy = (phuff_entropy_ptr) lossyc->entropy_private; + register int temp, temp2; + register int nbits; + register int r, k; + int Se = cinfo->Se; + int Al = cinfo->Al; + JBLOCKROW block; + + entropy->next_output_byte = cinfo->dest->next_output_byte; + entropy->free_in_buffer = cinfo->dest->free_in_buffer; + + /* Emit restart marker if needed */ + if (cinfo->restart_interval) + if (entropy->restarts_to_go == 0) + emit_restart(entropy, entropy->next_restart_num); + + /* Encode the MCU data block */ + block = MCU_data[0]; + + /* Encode the AC coefficients per section G.1.2.2, fig. G.3 */ + + r = 0; /* r = run length of zeros */ + + for (k = cinfo->Ss; k <= Se; k++) { + if ((temp = (*block)[jpeg_natural_order[k]]) == 0) { + r++; + continue; + } + /* We must apply the point transform by Al. For AC coefficients this + * is an integer division with rounding towards 0. To do this portably + * in C, we shift after obtaining the absolute value; so the code is + * interwoven with finding the abs value (temp) and output bits (temp2). + */ + if (temp < 0) { + temp = -temp; /* temp is abs value of input */ + temp >>= Al; /* apply the point transform */ + /* For a negative coef, want temp2 = bitwise complement of abs(coef) */ + temp2 = ~temp; + } else { + temp >>= Al; /* apply the point transform */ + temp2 = temp; + } + /* Watch out for case that nonzero coef is zero after point transform */ + if (temp == 0) { + r++; + continue; + } + + /* Emit any pending EOBRUN */ + if (entropy->EOBRUN > 0) + emit_eobrun(entropy); + /* if run length > 15, must emit special run-length-16 codes (0xF0) */ + while (r > 15) { + emit_symbol(entropy, entropy->ac_tbl_no, 0xF0); + r -= 16; + } + + /* Find the number of bits needed for the magnitude of the coefficient */ + nbits = 1; /* there must be at least one 1 bit */ + while ((temp >>= 1)) + nbits++; + /* Check for out-of-range coefficient values */ + if (nbits > MAX_COEF_BITS) + ERREXIT(cinfo, JERR_BAD_DCT_COEF); + + /* Count/emit Huffman symbol for run length / number of bits */ + emit_symbol(entropy, entropy->ac_tbl_no, (r << 4) + nbits); + + /* Emit that number of bits of the value, if positive, */ + /* or the complement of its magnitude, if negative. */ + emit_bits(entropy, (unsigned int) temp2, nbits); + + r = 0; /* reset zero run length */ + } + + if (r > 0) { /* If there are trailing zeroes, */ + entropy->EOBRUN++; /* count an EOB */ + if (entropy->EOBRUN == 0x7FFF) + emit_eobrun(entropy); /* force it out to avoid overflow */ + } + + cinfo->dest->next_output_byte = entropy->next_output_byte; + cinfo->dest->free_in_buffer = entropy->free_in_buffer; + + /* Update restart-interval state too */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num++; + entropy->next_restart_num &= 7; + } + entropy->restarts_to_go--; + } + + return TRUE; +} + + +/* + * MCU encoding for DC successive approximation refinement scan. + * Note: we assume such scans can be multi-component, although the spec + * is not very clear on the point. + */ + +METHODDEF(boolean) +encode_mcu_DC_refine (j_compress_ptr cinfo, JBLOCKROW *MCU_data) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + phuff_entropy_ptr entropy = (phuff_entropy_ptr) lossyc->entropy_private; + register int temp; + int blkn; + int Al = cinfo->Al; + JBLOCKROW block; + + entropy->next_output_byte = cinfo->dest->next_output_byte; + entropy->free_in_buffer = cinfo->dest->free_in_buffer; + + /* Emit restart marker if needed */ + if (cinfo->restart_interval) + if (entropy->restarts_to_go == 0) + emit_restart(entropy, entropy->next_restart_num); + + /* Encode the MCU data blocks */ + for (blkn = 0; blkn < cinfo->data_units_in_MCU; blkn++) { + block = MCU_data[blkn]; + + /* We simply emit the Al'th bit of the DC coefficient value. */ + temp = (*block)[0]; + emit_bits(entropy, (unsigned int) (temp >> Al), 1); + } + + cinfo->dest->next_output_byte = entropy->next_output_byte; + cinfo->dest->free_in_buffer = entropy->free_in_buffer; + + /* Update restart-interval state too */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num++; + entropy->next_restart_num &= 7; + } + entropy->restarts_to_go--; + } + + return TRUE; +} + + +/* + * MCU encoding for AC successive approximation refinement scan. + */ + +METHODDEF(boolean) +encode_mcu_AC_refine (j_compress_ptr cinfo, JBLOCKROW *MCU_data) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + phuff_entropy_ptr entropy = (phuff_entropy_ptr) lossyc->entropy_private; + register int temp; + register int r, k; + int EOB; + char *BR_buffer; + unsigned int BR; + int Se = cinfo->Se; + int Al = cinfo->Al; + JBLOCKROW block; + int absvalues[DCTSIZE2]; + + entropy->next_output_byte = cinfo->dest->next_output_byte; + entropy->free_in_buffer = cinfo->dest->free_in_buffer; + + /* Emit restart marker if needed */ + if (cinfo->restart_interval) + if (entropy->restarts_to_go == 0) + emit_restart(entropy, entropy->next_restart_num); + + /* Encode the MCU data block */ + block = MCU_data[0]; + + /* It is convenient to make a pre-pass to determine the transformed + * coefficients' absolute values and the EOB position. + */ + EOB = 0; + for (k = cinfo->Ss; k <= Se; k++) { + temp = (*block)[jpeg_natural_order[k]]; + /* We must apply the point transform by Al. For AC coefficients this + * is an integer division with rounding towards 0. To do this portably + * in C, we shift after obtaining the absolute value. + */ + if (temp < 0) + temp = -temp; /* temp is abs value of input */ + temp >>= Al; /* apply the point transform */ + absvalues[k] = temp; /* save abs value for main pass */ + if (temp == 1) + EOB = k; /* EOB = index of last newly-nonzero coef */ + } + + /* Encode the AC coefficients per section G.1.2.3, fig. G.7 */ + + r = 0; /* r = run length of zeros */ + BR = 0; /* BR = count of buffered bits added now */ + BR_buffer = entropy->bit_buffer + entropy->BE; /* Append bits to buffer */ + + for (k = cinfo->Ss; k <= Se; k++) { + if ((temp = absvalues[k]) == 0) { + r++; + continue; + } + + /* Emit any required ZRLs, but not if they can be folded into EOB */ + while (r > 15 && k <= EOB) { + /* emit any pending EOBRUN and the BE correction bits */ + emit_eobrun(entropy); + /* Emit ZRL */ + emit_symbol(entropy, entropy->ac_tbl_no, 0xF0); + r -= 16; + /* Emit buffered correction bits that must be associated with ZRL */ + emit_buffered_bits(entropy, BR_buffer, BR); + BR_buffer = entropy->bit_buffer; /* BE bits are gone now */ + BR = 0; + } + + /* If the coef was previously nonzero, it only needs a correction bit. + * NOTE: a straight translation of the spec's figure G.7 would suggest + * that we also need to test r > 15. But if r > 15, we can only get here + * if k > EOB, which implies that this coefficient is not 1. + */ + if (temp > 1) { + /* The correction bit is the next bit of the absolute value. */ + BR_buffer[BR++] = (char) (temp & 1); + continue; + } + + /* Emit any pending EOBRUN and the BE correction bits */ + emit_eobrun(entropy); + + /* Count/emit Huffman symbol for run length / number of bits */ + emit_symbol(entropy, entropy->ac_tbl_no, (r << 4) + 1); + + /* Emit output bit for newly-nonzero coef */ + temp = ((*block)[jpeg_natural_order[k]] < 0) ? 0 : 1; + emit_bits(entropy, (unsigned int) temp, 1); + + /* Emit buffered correction bits that must be associated with this code */ + emit_buffered_bits(entropy, BR_buffer, BR); + BR_buffer = entropy->bit_buffer; /* BE bits are gone now */ + BR = 0; + r = 0; /* reset zero run length */ + } + + if (r > 0 || BR > 0) { /* If there are trailing zeroes, */ + entropy->EOBRUN++; /* count an EOB */ + entropy->BE += BR; /* concat my correction bits to older ones */ + /* We force out the EOB if we risk either: + * 1. overflow of the EOB counter; + * 2. overflow of the correction bit buffer during the next MCU. + */ + if (entropy->EOBRUN == 0x7FFF || entropy->BE > (MAX_CORR_BITS-DCTSIZE2+1)) + emit_eobrun(entropy); + } + + cinfo->dest->next_output_byte = entropy->next_output_byte; + cinfo->dest->free_in_buffer = entropy->free_in_buffer; + + /* Update restart-interval state too */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num++; + entropy->next_restart_num &= 7; + } + entropy->restarts_to_go--; + } + + return TRUE; +} + + +/* + * Finish up at the end of a Huffman-compressed progressive scan. + */ + +METHODDEF(void) +finish_pass_phuff (j_compress_ptr cinfo) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + phuff_entropy_ptr entropy = (phuff_entropy_ptr) lossyc->entropy_private; + + entropy->next_output_byte = cinfo->dest->next_output_byte; + entropy->free_in_buffer = cinfo->dest->free_in_buffer; + + /* Flush out any buffered data */ + emit_eobrun(entropy); + flush_bits(entropy); + + cinfo->dest->next_output_byte = entropy->next_output_byte; + cinfo->dest->free_in_buffer = entropy->free_in_buffer; +} + + +/* + * Finish up a statistics-gathering pass and create the new Huffman tables. + */ + +METHODDEF(void) +finish_pass_gather_phuff (j_compress_ptr cinfo) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + phuff_entropy_ptr entropy = (phuff_entropy_ptr) lossyc->entropy_private; + boolean is_DC_band; + int ci, tbl; + jpeg_component_info * compptr; + JHUFF_TBL **htblptr; + boolean did[NUM_HUFF_TBLS]; + + /* Flush out buffered data (all we care about is counting the EOB symbol) */ + emit_eobrun(entropy); + + is_DC_band = (cinfo->Ss == 0); + + /* It's important not to apply jpeg_gen_optimal_table more than once + * per table, because it clobbers the input frequency counts! + */ + MEMZERO(did, SIZEOF(did)); + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + if (is_DC_band) { + if (cinfo->Ah != 0) /* DC refinement needs no table */ + continue; + tbl = compptr->dc_tbl_no; + } else { + tbl = compptr->ac_tbl_no; + } + if (! did[tbl]) { + if (is_DC_band) + htblptr = & cinfo->dc_huff_tbl_ptrs[tbl]; + else + htblptr = & cinfo->ac_huff_tbl_ptrs[tbl]; + if (*htblptr == NULL) + *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo); + jpeg_gen_optimal_table(cinfo, *htblptr, entropy->count_ptrs[tbl]); + did[tbl] = TRUE; + } + } +} + + +METHODDEF(boolean) +need_optimization_pass (j_compress_ptr cinfo) +{ + return (cinfo->Ss != 0 || cinfo->Ah == 0); +} + + +/* + * Module initialization routine for progressive Huffman entropy encoding. + */ + +GLOBAL(void) +jinit_phuff_encoder (j_compress_ptr cinfo) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + phuff_entropy_ptr entropy; + int i; + + entropy = (phuff_entropy_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(phuff_entropy_encoder)); + lossyc->entropy_private = (struct jpeg_entropy_encoder *) entropy; + lossyc->pub.entropy_start_pass = start_pass_phuff; + lossyc->pub.need_optimization_pass = need_optimization_pass; + + /* Mark tables unallocated */ + for (i = 0; i < NUM_HUFF_TBLS; i++) { + entropy->derived_tbls[i] = NULL; + entropy->count_ptrs[i] = NULL; + } + entropy->bit_buffer = NULL; /* needed only in AC refinement scan */ +} + +#endif /* C_PROGRESSIVE_SUPPORTED */ diff --git a/gdcm/Utilities/gdcmjpeg/jcpred.c b/gdcm/Utilities/gdcmjpeg/jcpred.c new file mode 100644 index 0000000..318e207 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jcpred.c @@ -0,0 +1,300 @@ +/* + * jcpred.c + * + * Copyright (C) 1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains sample differencing for lossless JPEG. + * + * In order to avoid paying the performance penalty of having to check the + * predictor being used and the row being processed for each call of the + * undifferencer, and to promote optimization, we have separate differencing + * functions for each case. + * + * We are able to avoid duplicating source code by implementing the predictors + * and differencers as macros. Each of the differencing functions are + * simply wrappers around a DIFFERENCE macro with the appropriate PREDICTOR + * macro passed as an argument. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jlossls.h" /* Private declarations for lossless codec */ + + +#ifdef C_LOSSLESS_SUPPORTED + +/* Private predictor object */ + +typedef struct { + /* MCU-rows left in the restart interval for each component */ + unsigned int restart_rows_to_go[MAX_COMPONENTS]; +} c_predictor; + +typedef c_predictor * c_pred_ptr; + +/* Forward declarations */ +LOCAL(void) reset_predictor + JPP((j_compress_ptr cinfo, int ci)); +METHODDEF(void) start_pass + JPP((j_compress_ptr cinfo)); + + +/* Predictor for the first column of the first row: 2^(P-Pt-1) */ +#define INITIAL_PREDICTORx (1 << (cinfo->data_precision - cinfo->Al - 1)) + +/* Predictor for the first column of the remaining rows: Rb */ +#define INITIAL_PREDICTOR2 GETJSAMPLE(prev_row[0]) + + +/* + * 1-Dimensional differencer routine. + * + * This macro implements the 1-D horizontal predictor (1). INITIAL_PREDICTOR + * is used as the special case predictor for the first column, which must be + * either INITIAL_PREDICTOR2 or INITIAL_PREDICTORx. The remaining samples + * use PREDICTOR1. + */ + +#define DIFFERENCE_1D(INITIAL_PREDICTOR) \ + j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; \ + c_pred_ptr pred = (c_pred_ptr) losslsc->pred_private; \ + boolean restart = FALSE; \ + unsigned int xindex; \ + int samp, Ra; \ + \ + samp = GETJSAMPLE(input_buf[0]); \ + diff_buf[0] = samp - INITIAL_PREDICTOR; \ + \ + for (xindex = 1; xindex < width; xindex++) { \ + Ra = samp; \ + samp = GETJSAMPLE(input_buf[xindex]); \ + diff_buf[xindex] = samp - PREDICTOR1; \ + } \ + \ + /* Account for restart interval (no-op if not using restarts) */ \ + if (cinfo->restart_interval) { \ + if (--(pred->restart_rows_to_go[ci]) == 0) { \ + reset_predictor(cinfo, ci); \ + restart = TRUE; \ + } \ + } + + +/* + * 2-Dimensional differencer routine. + * + * This macro implements the 2-D horizontal predictors (#2-7). PREDICTOR2 is + * used as the special case predictor for the first column. The remaining + * samples use PREDICTOR, which is a function of Ra, Rb, Rc. + * + * Because prev_row and output_buf may point to the same storage area (in an + * interleaved image with Vi=1, for example), we must take care to buffer Rb/Rc + * before writing the current reconstructed sample value into output_buf. + */ + +#define DIFFERENCE_2D(PREDICTOR) \ + j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; \ + c_pred_ptr pred = (c_pred_ptr) losslsc->pred_private; \ + unsigned int xindex; \ + int samp, Ra, Rb, Rc; \ + \ + Rb = GETJSAMPLE(prev_row[0]); \ + samp = GETJSAMPLE(input_buf[0]); \ + diff_buf[0] = samp - PREDICTOR2; \ + \ + for (xindex = 1; xindex < width; xindex++) { \ + Rc = Rb; \ + Rb = GETJSAMPLE(prev_row[xindex]); \ + Ra = samp; \ + samp = GETJSAMPLE(input_buf[xindex]); \ + diff_buf[xindex] = samp - PREDICTOR; \ + } \ + \ + /* Account for restart interval (no-op if not using restarts) */ \ + if (cinfo->restart_interval) { \ + if (--pred->restart_rows_to_go[ci] == 0) \ + reset_predictor(cinfo, ci); \ + } + + +/* + * Differencers for the all rows but the first in a scan or restart interval. + * The first sample in the row is differenced using the vertical + * predictor (2). The rest of the samples are differenced using the + * predictor specified in the scan header. + */ + +METHODDEF(void) +jpeg_difference1(j_compress_ptr cinfo, int ci, + JSAMPROW input_buf, JSAMPROW prev_row, + JDIFFROW diff_buf, JDIMENSION width) +{ + DIFFERENCE_1D(INITIAL_PREDICTOR2); +} + +METHODDEF(void) +jpeg_difference2(j_compress_ptr cinfo, int ci, + JSAMPROW input_buf, JSAMPROW prev_row, + JDIFFROW diff_buf, JDIMENSION width) +{ + DIFFERENCE_2D(PREDICTOR2); +} + +METHODDEF(void) +jpeg_difference3(j_compress_ptr cinfo, int ci, + JSAMPROW input_buf, JSAMPROW prev_row, + JDIFFROW diff_buf, JDIMENSION width) +{ + DIFFERENCE_2D(PREDICTOR3); +} + +METHODDEF(void) +jpeg_difference4(j_compress_ptr cinfo, int ci, + JSAMPROW input_buf, JSAMPROW prev_row, + JDIFFROW diff_buf, JDIMENSION width) +{ + DIFFERENCE_2D(PREDICTOR4); +} + +METHODDEF(void) +jpeg_difference5(j_compress_ptr cinfo, int ci, + JSAMPROW input_buf, JSAMPROW prev_row, + JDIFFROW diff_buf, JDIMENSION width) +{ + SHIFT_TEMPS + DIFFERENCE_2D(PREDICTOR5); +} + +METHODDEF(void) +jpeg_difference6(j_compress_ptr cinfo, int ci, + JSAMPROW input_buf, JSAMPROW prev_row, + JDIFFROW diff_buf, JDIMENSION width) +{ + SHIFT_TEMPS + DIFFERENCE_2D(PREDICTOR6); +} + +METHODDEF(void) +jpeg_difference7(j_compress_ptr cinfo, int ci, + JSAMPROW input_buf, JSAMPROW prev_row, + JDIFFROW diff_buf, JDIMENSION width) +{ + SHIFT_TEMPS + DIFFERENCE_2D(PREDICTOR7); +} + + +/* + * Differencer for the first row in a scan or restart interval. The first + * sample in the row is differenced using the special predictor constant + * x=2^(P-Pt-1). The rest of the samples are differenced using the + * 1-D horizontal predictor (1). + */ + +METHODDEF(void) +jpeg_difference_first_row(j_compress_ptr cinfo, int ci, + JSAMPROW input_buf, JSAMPROW prev_row, + JDIFFROW diff_buf, JDIMENSION width) +{ + DIFFERENCE_1D(INITIAL_PREDICTORx); + (void)prev_row; + + /* + * Now that we have differenced the first row, we want to use the + * differencer which corresponds to the predictor specified in the + * scan header. + * + * Note that we don't to do this if we have just reset the predictor + * for a new restart interval. + */ + if (!restart) { + switch (cinfo->Ss) { + case 1: + losslsc->predict_difference[ci] = jpeg_difference1; + break; + case 2: + losslsc->predict_difference[ci] = jpeg_difference2; + break; + case 3: + losslsc->predict_difference[ci] = jpeg_difference3; + break; + case 4: + losslsc->predict_difference[ci] = jpeg_difference4; + break; + case 5: + losslsc->predict_difference[ci] = jpeg_difference5; + break; + case 6: + losslsc->predict_difference[ci] = jpeg_difference6; + break; + case 7: + losslsc->predict_difference[ci] = jpeg_difference7; + break; + } + } +} + +/* + * Reset predictor at the start of a pass or restart interval. + */ + +LOCAL(void) +reset_predictor (j_compress_ptr cinfo, int ci) +{ + j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; + c_pred_ptr pred = (c_pred_ptr) losslsc->pred_private; + + /* Initialize restart counter */ + pred->restart_rows_to_go[ci] = + cinfo->restart_interval / cinfo->MCUs_per_row; + + /* Set difference function to first row function */ + losslsc->predict_difference[ci] = jpeg_difference_first_row; +} + + +/* + * Initialize for an input processing pass. + */ + +METHODDEF(void) +start_pass (j_compress_ptr cinfo) +{ + /* j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; */ + /* c_pred_ptr pred = (c_pred_ptr) losslsc->pred_private; */ + int ci; + + /* Check that the restart interval is an integer multiple of the number + * of MCU in an MCU-row. + */ + if (cinfo->restart_interval % cinfo->MCUs_per_row != 0) + ERREXIT2(cinfo, JERR_BAD_RESTART, + cinfo->restart_interval, cinfo->MCUs_per_row); + + /* Set predictors for start of pass */ + for (ci = 0; ci < cinfo->num_components; ci++) + reset_predictor(cinfo, ci); +} + + +/* + * Module initialization routine for the differencer. + */ + +GLOBAL(void) +jinit_differencer (j_compress_ptr cinfo) +{ + j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; + c_pred_ptr pred; + + pred = (c_pred_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(c_predictor)); + losslsc->pred_private = (void *) pred; + losslsc->predict_start_pass = start_pass; +} + +#endif /* C_LOSSLESS_SUPPORTED */ diff --git a/gdcm/Utilities/gdcmjpeg/jcprepct.c b/gdcm/Utilities/gdcmjpeg/jcprepct.c new file mode 100644 index 0000000..1885481 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jcprepct.c @@ -0,0 +1,354 @@ +/* + * jcprepct.c + * + * Copyright (C) 1994-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the compression preprocessing controller. + * This controller manages the color conversion, downsampling, + * and edge expansion steps. + * + * Most of the complexity here is associated with buffering input rows + * as required by the downsampler. See the comments at the head of + * jcsample.c for the downsampler's needs. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* At present, jcsample.c can request context rows only for smoothing. + * In the future, we might also need context rows for CCIR601 sampling + * or other more-complex downsampling procedures. The code to support + * context rows should be compiled only if needed. + */ +#ifdef INPUT_SMOOTHING_SUPPORTED +#define CONTEXT_ROWS_SUPPORTED +#endif + + +/* + * For the simple (no-context-row) case, we just need to buffer one + * row group's worth of pixels for the downsampling step. At the bottom of + * the image, we pad to a full row group by replicating the last pixel row. + * The downsampler's last output row is then replicated if needed to pad + * out to a full iMCU row. + * + * When providing context rows, we must buffer three row groups' worth of + * pixels. Three row groups are physically allocated, but the row pointer + * arrays are made five row groups high, with the extra pointers above and + * below "wrapping around" to point to the last and first real row groups. + * This allows the downsampler to access the proper context rows. + * At the top and bottom of the image, we create dummy context rows by + * copying the first or last real pixel row. This copying could be avoided + * by pointer hacking as is done in jdmainct.c, but it doesn't seem worth the + * trouble on the compression side. + */ + + +/* Private buffer controller object */ + +typedef struct { + struct jpeg_c_prep_controller pub; /* public fields */ + + /* Downsampling input buffer. This buffer holds color-converted data + * until we have enough to do a downsample step. + */ + JSAMPARRAY color_buf[MAX_COMPONENTS]; + + JDIMENSION rows_to_go; /* counts rows remaining in source image */ + int next_buf_row; /* index of next row to store in color_buf */ + +#ifdef CONTEXT_ROWS_SUPPORTED /* only needed for context case */ + int this_row_group; /* starting row index of group to process */ + int next_buf_stop; /* downsample when we reach this index */ +#endif +} my_prep_controller; + +typedef my_prep_controller * my_prep_ptr; + + +/* + * Initialize for a processing pass. + */ + +METHODDEF(void) +start_pass_prep (j_compress_ptr cinfo, J_BUF_MODE pass_mode) +{ + my_prep_ptr prep = (my_prep_ptr) cinfo->prep; + + if (pass_mode != JBUF_PASS_THRU) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + + /* Initialize total-height counter for detecting bottom of image */ + prep->rows_to_go = cinfo->image_height; + /* Mark the conversion buffer empty */ + prep->next_buf_row = 0; +#ifdef CONTEXT_ROWS_SUPPORTED + /* Preset additional state variables for context mode. + * These aren't used in non-context mode, so we needn't test which mode. + */ + prep->this_row_group = 0; + /* Set next_buf_stop to stop after two row groups have been read in. */ + prep->next_buf_stop = 2 * cinfo->max_v_samp_factor; +#endif +} + + +/* + * Expand an image vertically from height input_rows to height output_rows, + * by duplicating the bottom row. + */ + +LOCAL(void) +expand_bottom_edge (JSAMPARRAY image_data, JDIMENSION num_cols, + int input_rows, int output_rows) +{ + register int row; + + for (row = input_rows; row < output_rows; row++) { + jcopy_sample_rows(image_data, input_rows-1, image_data, row, + 1, num_cols); + } +} + + +/* + * Process some data in the simple no-context case. + * + * Preprocessor output data is counted in "row groups". A row group + * is defined to be v_samp_factor sample rows of each component. + * Downsampling will produce this much data from each max_v_samp_factor + * input rows. + */ + +METHODDEF(void) +pre_process_data (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail, + JSAMPIMAGE output_buf, JDIMENSION *out_row_group_ctr, + JDIMENSION out_row_groups_avail) +{ + my_prep_ptr prep = (my_prep_ptr) cinfo->prep; + int numrows, ci; + JDIMENSION inrows; + jpeg_component_info * compptr; + + while (*in_row_ctr < in_rows_avail && + *out_row_group_ctr < out_row_groups_avail) { + /* Do color conversion to fill the conversion buffer. */ + inrows = in_rows_avail - *in_row_ctr; + numrows = cinfo->max_v_samp_factor - prep->next_buf_row; + numrows = (int) MIN((JDIMENSION) numrows, inrows); + (*cinfo->cconvert->color_convert) (cinfo, input_buf + *in_row_ctr, + prep->color_buf, + (JDIMENSION) prep->next_buf_row, + numrows); + *in_row_ctr += numrows; + prep->next_buf_row += numrows; + prep->rows_to_go -= numrows; + /* If at bottom of image, pad to fill the conversion buffer. */ + if (prep->rows_to_go == 0 && + prep->next_buf_row < cinfo->max_v_samp_factor) { + for (ci = 0; ci < cinfo->num_components; ci++) { + expand_bottom_edge(prep->color_buf[ci], cinfo->image_width, + prep->next_buf_row, cinfo->max_v_samp_factor); + } + prep->next_buf_row = cinfo->max_v_samp_factor; + } + /* If we've filled the conversion buffer, empty it. */ + if (prep->next_buf_row == cinfo->max_v_samp_factor) { + (*cinfo->downsample->downsample) (cinfo, + prep->color_buf, (JDIMENSION) 0, + output_buf, *out_row_group_ctr); + prep->next_buf_row = 0; + (*out_row_group_ctr)++; + } + /* If at bottom of image, pad the output to a full iMCU height. + * Note we assume the caller is providing a one-iMCU-height output buffer! + */ + if (prep->rows_to_go == 0 && + *out_row_group_ctr < out_row_groups_avail) { + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + expand_bottom_edge(output_buf[ci], + compptr->width_in_data_units * cinfo->data_unit, + (int) (*out_row_group_ctr * compptr->v_samp_factor), + (int) (out_row_groups_avail * compptr->v_samp_factor)); + } + *out_row_group_ctr = out_row_groups_avail; + break; /* can exit outer loop without test */ + } + } +} + + +#ifdef CONTEXT_ROWS_SUPPORTED + +/* + * Process some data in the context case. + */ + +METHODDEF(void) +pre_process_context (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail, + JSAMPIMAGE output_buf, JDIMENSION *out_row_group_ctr, + JDIMENSION out_row_groups_avail) +{ + my_prep_ptr prep = (my_prep_ptr) cinfo->prep; + int numrows, ci; + int buf_height = cinfo->max_v_samp_factor * 3; + JDIMENSION inrows; + + while (*out_row_group_ctr < out_row_groups_avail) { + if (*in_row_ctr < in_rows_avail) { + /* Do color conversion to fill the conversion buffer. */ + inrows = in_rows_avail - *in_row_ctr; + numrows = prep->next_buf_stop - prep->next_buf_row; + numrows = (int) MIN((JDIMENSION) numrows, inrows); + (*cinfo->cconvert->color_convert) (cinfo, input_buf + *in_row_ctr, + prep->color_buf, + (JDIMENSION) prep->next_buf_row, + numrows); + /* Pad at top of image, if first time through */ + if (prep->rows_to_go == cinfo->image_height) { + for (ci = 0; ci < cinfo->num_components; ci++) { + int row; + for (row = 1; row <= cinfo->max_v_samp_factor; row++) { + jcopy_sample_rows(prep->color_buf[ci], 0, + prep->color_buf[ci], -row, + 1, cinfo->image_width); + } + } + } + *in_row_ctr += numrows; + prep->next_buf_row += numrows; + prep->rows_to_go -= numrows; + } else { + /* Return for more data, unless we are at the bottom of the image. */ + if (prep->rows_to_go != 0) + break; + /* When at bottom of image, pad to fill the conversion buffer. */ + if (prep->next_buf_row < prep->next_buf_stop) { + for (ci = 0; ci < cinfo->num_components; ci++) { + expand_bottom_edge(prep->color_buf[ci], cinfo->image_width, + prep->next_buf_row, prep->next_buf_stop); + } + prep->next_buf_row = prep->next_buf_stop; + } + } + /* If we've gotten enough data, downsample a row group. */ + if (prep->next_buf_row == prep->next_buf_stop) { + (*cinfo->downsample->downsample) (cinfo, + prep->color_buf, + (JDIMENSION) prep->this_row_group, + output_buf, *out_row_group_ctr); + (*out_row_group_ctr)++; + /* Advance pointers with wraparound as necessary. */ + prep->this_row_group += cinfo->max_v_samp_factor; + if (prep->this_row_group >= buf_height) + prep->this_row_group = 0; + if (prep->next_buf_row >= buf_height) + prep->next_buf_row = 0; + prep->next_buf_stop = prep->next_buf_row + cinfo->max_v_samp_factor; + } + } +} + + +/* + * Create the wrapped-around downsampling input buffer needed for context mode. + */ + +LOCAL(void) +create_context_buffer (j_compress_ptr cinfo) +{ + my_prep_ptr prep = (my_prep_ptr) cinfo->prep; + int rgroup_height = cinfo->max_v_samp_factor; + int ci, i; + jpeg_component_info * compptr; + JSAMPARRAY true_buffer, fake_buffer; + + /* Grab enough space for fake row pointers for all the components; + * we need five row groups' worth of pointers for each component. + */ + fake_buffer = (JSAMPARRAY) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (cinfo->num_components * 5 * rgroup_height) * + SIZEOF(JSAMPROW)); + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Allocate the actual buffer space (3 row groups) for this component. + * We make the buffer wide enough to allow the downsampler to edge-expand + * horizontally within the buffer, if it so chooses. + */ + true_buffer = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) (((long) compptr->width_in_data_units * cinfo->data_unit * + cinfo->max_h_samp_factor) / compptr->h_samp_factor), + (JDIMENSION) (3 * rgroup_height)); + /* Copy true buffer row pointers into the middle of the fake row array */ + MEMCOPY(fake_buffer + rgroup_height, true_buffer, + 3 * rgroup_height * SIZEOF(JSAMPROW)); + /* Fill in the above and below wraparound pointers */ + for (i = 0; i < rgroup_height; i++) { + fake_buffer[i] = true_buffer[2 * rgroup_height + i]; + fake_buffer[4 * rgroup_height + i] = true_buffer[i]; + } + prep->color_buf[ci] = fake_buffer + rgroup_height; + fake_buffer += 5 * rgroup_height; /* point to space for next component */ + } +} + +#endif /* CONTEXT_ROWS_SUPPORTED */ + + +/* + * Initialize preprocessing controller. + */ + +GLOBAL(void) +jinit_c_prep_controller (j_compress_ptr cinfo, boolean need_full_buffer) +{ + my_prep_ptr prep; + int ci; + jpeg_component_info * compptr; + + if (need_full_buffer) /* safety check */ + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + + prep = (my_prep_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_prep_controller)); + cinfo->prep = (struct jpeg_c_prep_controller *) prep; + prep->pub.start_pass = start_pass_prep; + + /* Allocate the color conversion buffer. + * We make the buffer wide enough to allow the downsampler to edge-expand + * horizontally within the buffer, if it so chooses. + */ + if (cinfo->downsample->need_context_rows) { + /* Set up to provide context rows */ +#ifdef CONTEXT_ROWS_SUPPORTED + prep->pub.pre_process_data = pre_process_context; + create_context_buffer(cinfo); +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else { + /* No context, just make it tall enough for one row group */ + prep->pub.pre_process_data = pre_process_data; + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + prep->color_buf[ci] = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) (((long) compptr->width_in_data_units * cinfo->data_unit * + cinfo->max_h_samp_factor) / compptr->h_samp_factor), + (JDIMENSION) cinfo->max_v_samp_factor); + } + } +} diff --git a/gdcm/Utilities/gdcmjpeg/jcsample.c b/gdcm/Utilities/gdcmjpeg/jcsample.c new file mode 100644 index 0000000..5b5fb79 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jcsample.c @@ -0,0 +1,520 @@ +/* + * jcsample.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains downsampling routines. + * + * Downsampling input data is counted in "row groups". A row group + * is defined to be max_v_samp_factor pixel rows of each component, + * from which the downsampler produces v_samp_factor sample rows. + * A single row group is processed in each call to the downsampler module. + * + * The downsampler is responsible for edge-expansion of its output data + * to fill an integral number of DCT blocks horizontally. The source buffer + * may be modified if it is helpful for this purpose (the source buffer is + * allocated wide enough to correspond to the desired output width). + * The caller (the prep controller) is responsible for vertical padding. + * + * The downsampler may request "context rows" by setting need_context_rows + * during startup. In this case, the input arrays will contain at least + * one row group's worth of pixels above and below the passed-in data; + * the caller will create dummy rows at image top and bottom by replicating + * the first or last real pixel row. + * + * An excellent reference for image resampling is + * Digital Image Warping, George Wolberg, 1990. + * Pub. by IEEE Computer Society Press, Los Alamitos, CA. ISBN 0-8186-8944-7. + * + * The downsampling algorithm used here is a simple average of the source + * pixels covered by the output pixel. The hi-falutin sampling literature + * refers to this as a "box filter". In general the characteristics of a box + * filter are not very good, but for the specific cases we normally use (1:1 + * and 2:1 ratios) the box is equivalent to a "triangle filter" which is not + * nearly so bad. If you intend to use other sampling ratios, you'd be well + * advised to improve this code. + * + * A simple input-smoothing capability is provided. This is mainly intended + * for cleaning up color-dithered GIF input files (if you find it inadequate, + * we suggest using an external filtering program such as pnmconvol). When + * enabled, each input pixel P is replaced by a weighted sum of itself and its + * eight neighbors. P's weight is 1-8*SF and each neighbor's weight is SF, + * where SF = (smoothing_factor / 1024). + * Currently, smoothing is only supported for 2h2v sampling factors. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Pointer to routine to downsample a single component */ +typedef JMETHOD(void, downsample1_ptr, + (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY output_data)); + +/* Private subobject */ + +typedef struct { + struct jpeg_downsampler pub; /* public fields */ + + /* Downsampling method pointers, one per component */ + downsample1_ptr methods[MAX_COMPONENTS]; +} my_downsampler; + +typedef my_downsampler * my_downsample_ptr; + + +/* + * Initialize for a downsampling pass. + */ + +METHODDEF(void) +start_pass_downsample (j_compress_ptr cinfo) +{ + (void)cinfo; + /* no work for now */ +} + + +/* + * Expand a component horizontally from width input_cols to width output_cols, + * by duplicating the rightmost samples. + */ + +LOCAL(void) +expand_right_edge (JSAMPARRAY image_data, int num_rows, + JDIMENSION input_cols, JDIMENSION output_cols) +{ + register JSAMPROW ptr; + register JSAMPLE pixval; + register int count; + int row; + int numcols = (int) (output_cols - input_cols); + + if (numcols > 0) { + for (row = 0; row < num_rows; row++) { + ptr = image_data[row] + input_cols; + pixval = ptr[-1]; /* don't need GETJSAMPLE() here */ + for (count = numcols; count > 0; count--) + *ptr++ = pixval; + } + } +} + + +/* + * Do downsampling for a whole row group (all components). + * + * In this version we simply downsample each component independently. + */ + +METHODDEF(void) +sep_downsample (j_compress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION in_row_index, + JSAMPIMAGE output_buf, JDIMENSION out_row_group_index) +{ + my_downsample_ptr downsample = (my_downsample_ptr) cinfo->downsample; + int ci; + jpeg_component_info * compptr; + JSAMPARRAY in_ptr, out_ptr; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + in_ptr = input_buf[ci] + in_row_index; + out_ptr = output_buf[ci] + (out_row_group_index * compptr->v_samp_factor); + (*downsample->methods[ci]) (cinfo, compptr, in_ptr, out_ptr); + } +} + + +/* + * Downsample pixel values of a single component. + * One row group is processed per call. + * This version handles arbitrary integral sampling ratios, without smoothing. + * Note that this version is not actually used for customary sampling ratios. + */ + +METHODDEF(void) +int_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY output_data) +{ + int inrow, outrow, h_expand, v_expand, numpix, numpix2, h, v; + JDIMENSION outcol, outcol_h; /* outcol_h == outcol*h_expand */ + JDIMENSION output_cols = compptr->width_in_data_units * cinfo->data_unit; + JSAMPROW inptr, outptr; + INT32 outvalue; + + h_expand = cinfo->max_h_samp_factor / compptr->h_samp_factor; + v_expand = cinfo->max_v_samp_factor / compptr->v_samp_factor; + numpix = h_expand * v_expand; + numpix2 = numpix/2; + + /* Expand input data enough to let all the output samples be generated + * by the standard loop. Special-casing padded output would be more + * efficient. + */ + expand_right_edge(input_data, cinfo->max_v_samp_factor, + cinfo->image_width, output_cols * h_expand); + + inrow = 0; + for (outrow = 0; outrow < compptr->v_samp_factor; outrow++) { + outptr = output_data[outrow]; + for (outcol = 0, outcol_h = 0; outcol < output_cols; + outcol++, outcol_h += h_expand) { + outvalue = 0; + for (v = 0; v < v_expand; v++) { + inptr = input_data[inrow+v] + outcol_h; + for (h = 0; h < h_expand; h++) { + outvalue += (INT32) GETJSAMPLE(*inptr++); + } + } + *outptr++ = (JSAMPLE) ((outvalue + numpix2) / numpix); + } + inrow += v_expand; + } +} + + +/* + * Downsample pixel values of a single component. + * This version handles the special case of a full-size component, + * without smoothing. + */ + +METHODDEF(void) +fullsize_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY output_data) +{ + /* Copy the data */ + jcopy_sample_rows(input_data, 0, output_data, 0, + cinfo->max_v_samp_factor, cinfo->image_width); + /* Edge-expand */ + expand_right_edge(output_data, cinfo->max_v_samp_factor, + cinfo->image_width, compptr->width_in_data_units * cinfo->data_unit); +} + + +/* + * Downsample pixel values of a single component. + * This version handles the common case of 2:1 horizontal and 1:1 vertical, + * without smoothing. + * + * A note about the "bias" calculations: when rounding fractional values to + * integer, we do not want to always round 0.5 up to the next integer. + * If we did that, we'd introduce a noticeable bias towards larger values. + * Instead, this code is arranged so that 0.5 will be rounded up or down at + * alternate pixel locations (a simple ordered dither pattern). + */ + +METHODDEF(void) +h2v1_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY output_data) +{ + int outrow; + JDIMENSION outcol; + JDIMENSION output_cols = compptr->width_in_data_units * cinfo->data_unit; + register JSAMPROW inptr, outptr; + register int bias; + + /* Expand input data enough to let all the output samples be generated + * by the standard loop. Special-casing padded output would be more + * efficient. + */ + expand_right_edge(input_data, cinfo->max_v_samp_factor, + cinfo->image_width, output_cols * 2); + + for (outrow = 0; outrow < compptr->v_samp_factor; outrow++) { + outptr = output_data[outrow]; + inptr = input_data[outrow]; + bias = 0; /* bias = 0,1,0,1,... for successive samples */ + for (outcol = 0; outcol < output_cols; outcol++) { + *outptr++ = (JSAMPLE) ((GETJSAMPLE(*inptr) + GETJSAMPLE(inptr[1]) + + bias) >> 1); + bias ^= 1; /* 0=>1, 1=>0 */ + inptr += 2; + } + } +} + + +/* + * Downsample pixel values of a single component. + * This version handles the standard case of 2:1 horizontal and 2:1 vertical, + * without smoothing. + */ + +METHODDEF(void) +h2v2_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY output_data) +{ + int inrow, outrow; + JDIMENSION outcol; + JDIMENSION output_cols = compptr->width_in_data_units * cinfo->data_unit; + register JSAMPROW inptr0, inptr1, outptr; + register int bias; + + /* Expand input data enough to let all the output samples be generated + * by the standard loop. Special-casing padded output would be more + * efficient. + */ + expand_right_edge(input_data, cinfo->max_v_samp_factor, + cinfo->image_width, output_cols * 2); + + inrow = 0; + for (outrow = 0; outrow < compptr->v_samp_factor; outrow++) { + outptr = output_data[outrow]; + inptr0 = input_data[inrow]; + inptr1 = input_data[inrow+1]; + bias = 1; /* bias = 1,2,1,2,... for successive samples */ + for (outcol = 0; outcol < output_cols; outcol++) { + *outptr++ = (JSAMPLE) ((GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) + + GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]) + + bias) >> 2); + bias ^= 3; /* 1=>2, 2=>1 */ + inptr0 += 2; inptr1 += 2; + } + inrow += 2; + } +} + + +#ifdef INPUT_SMOOTHING_SUPPORTED + +/* + * Downsample pixel values of a single component. + * This version handles the standard case of 2:1 horizontal and 2:1 vertical, + * with smoothing. One row of context is required. + */ + +METHODDEF(void) +h2v2_smooth_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY output_data) +{ + int inrow, outrow; + JDIMENSION colctr; + JDIMENSION output_cols = compptr->width_in_data_units * cinfo->data_unit; + register JSAMPROW inptr0, inptr1, above_ptr, below_ptr, outptr; + INT32 membersum, neighsum, memberscale, neighscale; + + /* Expand input data enough to let all the output samples be generated + * by the standard loop. Special-casing padded output would be more + * efficient. + */ + expand_right_edge(input_data - 1, cinfo->max_v_samp_factor + 2, + cinfo->image_width, output_cols * 2); + + /* We don't bother to form the individual "smoothed" input pixel values; + * we can directly compute the output which is the average of the four + * smoothed values. Each of the four member pixels contributes a fraction + * (1-8*SF) to its own smoothed image and a fraction SF to each of the three + * other smoothed pixels, therefore a total fraction (1-5*SF)/4 to the final + * output. The four corner-adjacent neighbor pixels contribute a fraction + * SF to just one smoothed pixel, or SF/4 to the final output; while the + * eight edge-adjacent neighbors contribute SF to each of two smoothed + * pixels, or SF/2 overall. In order to use integer arithmetic, these + * factors are scaled by 2^16 = 65536. + * Also recall that SF = smoothing_factor / 1024. + */ + + memberscale = 16384 - cinfo->smoothing_factor * 80; /* scaled (1-5*SF)/4 */ + neighscale = cinfo->smoothing_factor * 16; /* scaled SF/4 */ + + inrow = 0; + for (outrow = 0; outrow < compptr->v_samp_factor; outrow++) { + outptr = output_data[outrow]; + inptr0 = input_data[inrow]; + inptr1 = input_data[inrow+1]; + above_ptr = input_data[inrow-1]; + below_ptr = input_data[inrow+2]; + + /* Special case for first column: pretend column -1 is same as column 0 */ + membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) + + GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]); + neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) + + GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) + + GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[2]) + + GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[2]); + neighsum += neighsum; + neighsum += GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[2]) + + GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[2]); + membersum = membersum * memberscale + neighsum * neighscale; + *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16); + inptr0 += 2; inptr1 += 2; above_ptr += 2; below_ptr += 2; + + for (colctr = output_cols - 2; colctr > 0; colctr--) { + /* sum of pixels directly mapped to this output element */ + membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) + + GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]); + /* sum of edge-neighbor pixels */ + neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) + + GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) + + GETJSAMPLE(inptr0[-1]) + GETJSAMPLE(inptr0[2]) + + GETJSAMPLE(inptr1[-1]) + GETJSAMPLE(inptr1[2]); + /* The edge-neighbors count twice as much as corner-neighbors */ + neighsum += neighsum; + /* Add in the corner-neighbors */ + neighsum += GETJSAMPLE(above_ptr[-1]) + GETJSAMPLE(above_ptr[2]) + + GETJSAMPLE(below_ptr[-1]) + GETJSAMPLE(below_ptr[2]); + /* form final output scaled up by 2^16 */ + membersum = membersum * memberscale + neighsum * neighscale; + /* round, descale and output it */ + *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16); + inptr0 += 2; inptr1 += 2; above_ptr += 2; below_ptr += 2; + } + + /* Special case for last column */ + membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) + + GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]); + neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) + + GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) + + GETJSAMPLE(inptr0[-1]) + GETJSAMPLE(inptr0[1]) + + GETJSAMPLE(inptr1[-1]) + GETJSAMPLE(inptr1[1]); + neighsum += neighsum; + neighsum += GETJSAMPLE(above_ptr[-1]) + GETJSAMPLE(above_ptr[1]) + + GETJSAMPLE(below_ptr[-1]) + GETJSAMPLE(below_ptr[1]); + membersum = membersum * memberscale + neighsum * neighscale; + *outptr = (JSAMPLE) ((membersum + 32768) >> 16); + + inrow += 2; + } +} + + +/* + * Downsample pixel values of a single component. + * This version handles the special case of a full-size component, + * with smoothing. One row of context is required. + */ + +METHODDEF(void) +fullsize_smooth_downsample (j_compress_ptr cinfo, jpeg_component_info *compptr, + JSAMPARRAY input_data, JSAMPARRAY output_data) +{ + int outrow; + JDIMENSION colctr; + JDIMENSION output_cols = compptr->width_in_data_units * cinfo->data_unit; + register JSAMPROW inptr, above_ptr, below_ptr, outptr; + INT32 membersum, neighsum, memberscale, neighscale; + int colsum, lastcolsum, nextcolsum; + + /* Expand input data enough to let all the output samples be generated + * by the standard loop. Special-casing padded output would be more + * efficient. + */ + expand_right_edge(input_data - 1, cinfo->max_v_samp_factor + 2, + cinfo->image_width, output_cols); + + /* Each of the eight neighbor pixels contributes a fraction SF to the + * smoothed pixel, while the main pixel contributes (1-8*SF). In order + * to use integer arithmetic, these factors are multiplied by 2^16 = 65536. + * Also recall that SF = smoothing_factor / 1024. + */ + + memberscale = 65536L - cinfo->smoothing_factor * 512L; /* scaled 1-8*SF */ + neighscale = cinfo->smoothing_factor * 64; /* scaled SF */ + + for (outrow = 0; outrow < compptr->v_samp_factor; outrow++) { + outptr = output_data[outrow]; + inptr = input_data[outrow]; + above_ptr = input_data[outrow-1]; + below_ptr = input_data[outrow+1]; + + /* Special case for first column */ + colsum = GETJSAMPLE(*above_ptr++) + GETJSAMPLE(*below_ptr++) + + GETJSAMPLE(*inptr); + membersum = GETJSAMPLE(*inptr++); + nextcolsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(*below_ptr) + + GETJSAMPLE(*inptr); + neighsum = colsum + (colsum - membersum) + nextcolsum; + membersum = membersum * memberscale + neighsum * neighscale; + *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16); + lastcolsum = colsum; colsum = nextcolsum; + + for (colctr = output_cols - 2; colctr > 0; colctr--) { + membersum = GETJSAMPLE(*inptr++); + above_ptr++; below_ptr++; + nextcolsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(*below_ptr) + + GETJSAMPLE(*inptr); + neighsum = lastcolsum + (colsum - membersum) + nextcolsum; + membersum = membersum * memberscale + neighsum * neighscale; + *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16); + lastcolsum = colsum; colsum = nextcolsum; + } + + /* Special case for last column */ + membersum = GETJSAMPLE(*inptr); + neighsum = lastcolsum + (colsum - membersum) + colsum; + membersum = membersum * memberscale + neighsum * neighscale; + *outptr = (JSAMPLE) ((membersum + 32768) >> 16); + + } +} + +#endif /* INPUT_SMOOTHING_SUPPORTED */ + + +/* + * Module initialization routine for downsampling. + * Note that we must select a routine for each component. + */ + +GLOBAL(void) +jinit_downsampler (j_compress_ptr cinfo) +{ + my_downsample_ptr downsample; + int ci; + jpeg_component_info * compptr; + boolean smoothok = TRUE; + + downsample = (my_downsample_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_downsampler)); + cinfo->downsample = (struct jpeg_downsampler *) downsample; + downsample->pub.start_pass = start_pass_downsample; + downsample->pub.downsample = sep_downsample; + downsample->pub.need_context_rows = FALSE; + + if (cinfo->CCIR601_sampling) + ERREXIT(cinfo, JERR_CCIR601_NOTIMPL); + + /* Verify we can handle the sampling factors, and set up method pointers */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + if (compptr->h_samp_factor == cinfo->max_h_samp_factor && + compptr->v_samp_factor == cinfo->max_v_samp_factor) { +#ifdef INPUT_SMOOTHING_SUPPORTED + if (cinfo->smoothing_factor) { + downsample->methods[ci] = fullsize_smooth_downsample; + downsample->pub.need_context_rows = TRUE; + } else +#endif + downsample->methods[ci] = fullsize_downsample; + } else if (compptr->h_samp_factor * 2 == cinfo->max_h_samp_factor && + compptr->v_samp_factor == cinfo->max_v_samp_factor) { + smoothok = FALSE; + downsample->methods[ci] = h2v1_downsample; + } else if (compptr->h_samp_factor * 2 == cinfo->max_h_samp_factor && + compptr->v_samp_factor * 2 == cinfo->max_v_samp_factor) { +#ifdef INPUT_SMOOTHING_SUPPORTED + if (cinfo->smoothing_factor) { + downsample->methods[ci] = h2v2_smooth_downsample; + downsample->pub.need_context_rows = TRUE; + } else +#endif + downsample->methods[ci] = h2v2_downsample; + } else if ((cinfo->max_h_samp_factor % compptr->h_samp_factor) == 0 && + (cinfo->max_v_samp_factor % compptr->v_samp_factor) == 0) { + smoothok = FALSE; + downsample->methods[ci] = int_downsample; + } else + ERREXIT(cinfo, JERR_FRACT_SAMPLE_NOTIMPL); + } + +#ifdef INPUT_SMOOTHING_SUPPORTED + if (cinfo->smoothing_factor && !smoothok) + TRACEMS(cinfo, 0, JTRC_SMOOTH_NOTIMPL); +#endif +} diff --git a/gdcm/Utilities/gdcmjpeg/jcscale.c b/gdcm/Utilities/gdcmjpeg/jcscale.c new file mode 100644 index 0000000..f0539af --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jcscale.c @@ -0,0 +1,64 @@ +/* + * jcscale.c + * + * Copyright (C) 1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains sample downscaling by 2^Pt for lossless JPEG. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jlossls.h" /* Private declarations for lossless codec */ + + +#ifdef C_LOSSLESS_SUPPORTED + +METHODDEF(void) +simple_downscale(j_compress_ptr cinfo, + JSAMPROW input_buf, JSAMPROW output_buf, JDIMENSION width) +{ + /* j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; */ + unsigned int xindex; + SHIFT_TEMPS + + for (xindex = 0; xindex < width; xindex++) + output_buf[xindex] = (JSAMPLE) RIGHT_SHIFT(GETJSAMPLE(input_buf[xindex]), + cinfo->Al); +} + + +METHODDEF(void) +noscale(j_compress_ptr cinfo, + JSAMPROW input_buf, JSAMPROW output_buf, JDIMENSION width) +{ + (void)cinfo; + MEMCOPY(output_buf, input_buf, width * SIZEOF(JSAMPLE)); + return; +} + + +METHODDEF(void) +scaler_start_pass (j_compress_ptr cinfo) +{ + j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; + + /* Set scaler function based on Pt */ + if (cinfo->Al) + losslsc->scaler_scale = simple_downscale; + else + losslsc->scaler_scale = noscale; +} + + +GLOBAL(void) +jinit_c_scaler (j_compress_ptr cinfo) +{ + j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; + + losslsc->scaler_start_pass = scaler_start_pass; +} + +#endif /* C_LOSSLESS_SUPPORTED */ diff --git a/gdcm/Utilities/gdcmjpeg/jcshuff.c b/gdcm/Utilities/gdcmjpeg/jcshuff.c new file mode 100644 index 0000000..330c7c6 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jcshuff.c @@ -0,0 +1,662 @@ +/* + * jcshuff.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains Huffman entropy encoding routines for sequential JPEG. + * + * Much of the complexity here has to do with supporting output suspension. + * If the data destination module demands suspension, we want to be able to + * back up to the start of the current MCU. To do this, we copy state + * variables into local working storage, and update them back to the + * permanent JPEG objects only upon successful completion of an MCU. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jlossy.h" /* Private declarations for lossy codec */ +#include "jchuff.h" /* Declarations shared with jc*huff.c */ + + +/* Expanded entropy encoder object for Huffman encoding. + * + * The savable_state subrecord contains fields that change within an MCU, + * but must not be updated permanently until we complete the MCU. + */ + +typedef struct { + INT32 put_buffer; /* current bit-accumulation buffer */ + int put_bits; /* # of bits now in it */ + int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */ +} savable_state; + +/* This macro is to work around compilers with missing or broken + * structure assignment. You'll need to fix this code if you have + * such a compiler and you change MAX_COMPS_IN_SCAN. + */ + +#ifndef NO_STRUCT_ASSIGN +#define ASSIGN_STATE(dest,src) ((dest) = (src)) +#else +#if MAX_COMPS_IN_SCAN == 4 +#define ASSIGN_STATE(dest,src) \ + ((dest).put_buffer = (src).put_buffer, \ + (dest).put_bits = (src).put_bits, \ + (dest).last_dc_val[0] = (src).last_dc_val[0], \ + (dest).last_dc_val[1] = (src).last_dc_val[1], \ + (dest).last_dc_val[2] = (src).last_dc_val[2], \ + (dest).last_dc_val[3] = (src).last_dc_val[3]) +#endif +#endif + + +typedef struct { + savable_state saved; /* Bit buffer & DC state at start of MCU */ + + /* These fields are NOT loaded into local working state. */ + unsigned int restarts_to_go; /* MCUs left in this restart interval */ + int next_restart_num; /* next restart number to write (0-7) */ + + /* Pointers to derived tables (these workspaces have image lifespan) */ + c_derived_tbl * dc_derived_tbls[NUM_HUFF_TBLS]; + c_derived_tbl * ac_derived_tbls[NUM_HUFF_TBLS]; + +#ifdef ENTROPY_OPT_SUPPORTED /* Statistics tables for optimization */ + long * dc_count_ptrs[NUM_HUFF_TBLS]; + long * ac_count_ptrs[NUM_HUFF_TBLS]; +#endif +} shuff_entropy_encoder; + +typedef shuff_entropy_encoder * shuff_entropy_ptr; + +/* Working state while writing an MCU. + * This struct contains all the fields that are needed by subroutines. + */ + +typedef struct { + JOCTET * next_output_byte; /* => next byte to write in buffer */ + size_t free_in_buffer; /* # of byte spaces remaining in buffer */ + savable_state cur; /* Current bit buffer & DC state */ + j_compress_ptr cinfo; /* dump_buffer needs access to this */ +} working_state; + + +/* Forward declarations */ +METHODDEF(boolean) encode_mcu_huff JPP((j_compress_ptr cinfo, + JBLOCKROW *MCU_data)); +METHODDEF(void) finish_pass_huff JPP((j_compress_ptr cinfo)); +#ifdef ENTROPY_OPT_SUPPORTED +METHODDEF(boolean) encode_mcu_gather JPP((j_compress_ptr cinfo, + JBLOCKROW *MCU_data)); +METHODDEF(void) finish_pass_gather JPP((j_compress_ptr cinfo)); +#endif + + +/* + * Initialize for a Huffman-compressed scan. + * If gather_statistics is TRUE, we do not output anything during the scan, + * just count the Huffman symbols used and generate Huffman code tables. + */ + +METHODDEF(void) +start_pass_huff (j_compress_ptr cinfo, boolean gather_statistics) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + shuff_entropy_ptr entropy = (shuff_entropy_ptr) lossyc->entropy_private; + int ci, dctbl, actbl; + jpeg_component_info * compptr; + + if (gather_statistics) { +#ifdef ENTROPY_OPT_SUPPORTED + lossyc->entropy_encode_mcu = encode_mcu_gather; + lossyc->pub.entropy_finish_pass = finish_pass_gather; +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else { + lossyc->entropy_encode_mcu = encode_mcu_huff; + lossyc->pub.entropy_finish_pass = finish_pass_huff; + } + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + dctbl = compptr->dc_tbl_no; + actbl = compptr->ac_tbl_no; + if (gather_statistics) { +#ifdef ENTROPY_OPT_SUPPORTED + /* Check for invalid table indexes */ + /* (make_c_derived_tbl does this in the other path) */ + if (dctbl < 0 || dctbl >= NUM_HUFF_TBLS) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, dctbl); + if (actbl < 0 || actbl >= NUM_HUFF_TBLS) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, actbl); + /* Allocate and zero the statistics tables */ + /* Note that jpeg_gen_optimal_table expects 257 entries in each table! */ + if (entropy->dc_count_ptrs[dctbl] == NULL) + entropy->dc_count_ptrs[dctbl] = (long *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + 257 * SIZEOF(long)); + MEMZERO(entropy->dc_count_ptrs[dctbl], 257 * SIZEOF(long)); + if (entropy->ac_count_ptrs[actbl] == NULL) + entropy->ac_count_ptrs[actbl] = (long *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + 257 * SIZEOF(long)); + MEMZERO(entropy->ac_count_ptrs[actbl], 257 * SIZEOF(long)); +#endif + } else { + /* Compute derived values for Huffman tables */ + /* We may do this more than once for a table, but it's not expensive */ + jpeg_make_c_derived_tbl(cinfo, TRUE, dctbl, + & entropy->dc_derived_tbls[dctbl]); + jpeg_make_c_derived_tbl(cinfo, FALSE, actbl, + & entropy->ac_derived_tbls[actbl]); + } + /* Initialize DC predictions to 0 */ + entropy->saved.last_dc_val[ci] = 0; + } + + /* Initialize bit buffer to empty */ + entropy->saved.put_buffer = 0; + entropy->saved.put_bits = 0; + + /* Initialize restart stuff */ + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num = 0; +} + + +/* Outputting bytes to the file */ + +/* Emit a byte, taking 'action' if must suspend. */ +#define emit_byte(state,val,action) \ + { *(state)->next_output_byte++ = (JOCTET) (val); \ + if (--(state)->free_in_buffer == 0) \ + if (! dump_buffer(state)) \ + { action; } } + + +LOCAL(boolean) +dump_buffer (working_state * state) +/* Empty the output buffer; return TRUE if successful, FALSE if must suspend */ +{ + struct jpeg_destination_mgr * dest = state->cinfo->dest; + + if (! (*dest->empty_output_buffer) (state->cinfo)) + return FALSE; + /* After a successful buffer dump, must reset buffer pointers */ + state->next_output_byte = dest->next_output_byte; + state->free_in_buffer = dest->free_in_buffer; + return TRUE; +} + + +/* Outputting bits to the file */ + +/* Only the right 24 bits of put_buffer are used; the valid bits are + * left-justified in this part. At most 16 bits can be passed to emit_bits + * in one call, and we never retain more than 7 bits in put_buffer + * between calls, so 24 bits are sufficient. + */ + +INLINE +LOCAL(boolean) +emit_bits (working_state * state, unsigned int code, int size) +/* Emit some bits; return TRUE if successful, FALSE if must suspend */ +{ + /* This routine is heavily used, so it's worth coding tightly. */ + register INT32 put_buffer = (INT32) code; + register int put_bits = state->cur.put_bits; + + /* if size is 0, caller used an invalid Huffman table entry */ + if (size == 0) + ERREXIT(state->cinfo, JERR_HUFF_MISSING_CODE); + + put_buffer &= (((INT32) 1)<cur.put_buffer; /* and merge with old buffer contents */ + + while (put_bits >= 8) { + int c = (int) ((put_buffer >> 16) & 0xFF); + + emit_byte(state, c, return FALSE); + if (c == 0xFF) { /* need to stuff a zero byte? */ + emit_byte(state, 0, return FALSE); + } + put_buffer <<= 8; + put_bits -= 8; + } + + state->cur.put_buffer = put_buffer; /* update state variables */ + state->cur.put_bits = put_bits; + + return TRUE; +} + + +LOCAL(boolean) +flush_bits (working_state * state) +{ + if (! emit_bits(state, 0x7F, 7)) /* fill any partial byte with ones */ + return FALSE; + state->cur.put_buffer = 0; /* and reset bit-buffer to empty */ + state->cur.put_bits = 0; + return TRUE; +} + + +/* Encode a single block's worth of coefficients */ + +LOCAL(boolean) +encode_one_block (working_state * state, JCOEFPTR block, int last_dc_val, + c_derived_tbl *dctbl, c_derived_tbl *actbl) +{ + register int temp, temp2; + register int nbits; + register int k, r, i; + + /* Encode the DC coefficient difference per section F.1.2.1 */ + + temp = temp2 = block[0] - last_dc_val; + + if (temp < 0) { + temp = -temp; /* temp is abs value of input */ + /* For a negative input, want temp2 = bitwise complement of abs(input) */ + /* This code assumes we are on a two's complement machine */ + temp2--; + } + + /* Find the number of bits needed for the magnitude of the coefficient */ + nbits = 0; + while (temp) { + nbits++; + temp >>= 1; + } + /* Check for out-of-range coefficient values. + * Since we're encoding a difference, the range limit is twice as much. + */ + if (nbits > MAX_COEF_BITS+1) + ERREXIT(state->cinfo, JERR_BAD_DCT_COEF); + + /* Emit the Huffman-coded symbol for the number of bits */ + if (! emit_bits(state, dctbl->ehufco[nbits], dctbl->ehufsi[nbits])) + return FALSE; + + /* Emit that number of bits of the value, if positive, */ + /* or the complement of its magnitude, if negative. */ + if (nbits) /* emit_bits rejects calls with size 0 */ + if (! emit_bits(state, (unsigned int) temp2, nbits)) + return FALSE; + + /* Encode the AC coefficients per section F.1.2.2 */ + + r = 0; /* r = run length of zeros */ + + for (k = 1; k < DCTSIZE2; k++) { + if ((temp = block[jpeg_natural_order[k]]) == 0) { + r++; + } else { + /* if run length > 15, must emit special run-length-16 codes (0xF0) */ + while (r > 15) { + if (! emit_bits(state, actbl->ehufco[0xF0], actbl->ehufsi[0xF0])) + return FALSE; + r -= 16; + } + + temp2 = temp; + if (temp < 0) { + temp = -temp; /* temp is abs value of input */ + /* This code assumes we are on a two's complement machine */ + temp2--; + } + + /* Find the number of bits needed for the magnitude of the coefficient */ + nbits = 1; /* there must be at least one 1 bit */ + while ((temp >>= 1)) + nbits++; + /* Check for out-of-range coefficient values */ + if (nbits > MAX_COEF_BITS) + ERREXIT(state->cinfo, JERR_BAD_DCT_COEF); + + /* Emit Huffman symbol for run length / number of bits */ + i = (r << 4) + nbits; + if (! emit_bits(state, actbl->ehufco[i], actbl->ehufsi[i])) + return FALSE; + + /* Emit that number of bits of the value, if positive, */ + /* or the complement of its magnitude, if negative. */ + if (! emit_bits(state, (unsigned int) temp2, nbits)) + return FALSE; + + r = 0; + } + } + + /* If the last coef(s) were zero, emit an end-of-block code */ + if (r > 0) + if (! emit_bits(state, actbl->ehufco[0], actbl->ehufsi[0])) + return FALSE; + + return TRUE; +} + + +/* + * Emit a restart marker & resynchronize predictions. + */ + +LOCAL(boolean) +emit_restart (working_state * state, int restart_num) +{ + int ci; + + if (! flush_bits(state)) + return FALSE; + + emit_byte(state, 0xFF, return FALSE); + emit_byte(state, JPEG_RST0 + restart_num, return FALSE); + + /* Re-initialize DC predictions to 0 */ + for (ci = 0; ci < state->cinfo->comps_in_scan; ci++) + state->cur.last_dc_val[ci] = 0; + + /* The restart counter is not updated until we successfully write the MCU. */ + + return TRUE; +} + + +/* + * Encode and output one MCU's worth of Huffman-compressed coefficients. + */ + +METHODDEF(boolean) +encode_mcu_huff (j_compress_ptr cinfo, JBLOCKROW *MCU_data) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + shuff_entropy_ptr entropy = (shuff_entropy_ptr) lossyc->entropy_private; + working_state state; + int blkn, ci; + jpeg_component_info * compptr; + + /* Load up working state */ + state.next_output_byte = cinfo->dest->next_output_byte; + state.free_in_buffer = cinfo->dest->free_in_buffer; + ASSIGN_STATE(state.cur, entropy->saved); + state.cinfo = cinfo; + + /* Emit restart marker if needed */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + if (! emit_restart(&state, entropy->next_restart_num)) + return FALSE; + } + + /* Encode the MCU data blocks */ + for (blkn = 0; blkn < cinfo->data_units_in_MCU; blkn++) { + ci = cinfo->MCU_membership[blkn]; + compptr = cinfo->cur_comp_info[ci]; + if (! encode_one_block(&state, + MCU_data[blkn][0], state.cur.last_dc_val[ci], + entropy->dc_derived_tbls[compptr->dc_tbl_no], + entropy->ac_derived_tbls[compptr->ac_tbl_no])) + return FALSE; + /* Update last_dc_val */ + state.cur.last_dc_val[ci] = MCU_data[blkn][0][0]; + } + + /* Completed MCU, so update state */ + cinfo->dest->next_output_byte = state.next_output_byte; + cinfo->dest->free_in_buffer = state.free_in_buffer; + ASSIGN_STATE(entropy->saved, state.cur); + + /* Update restart-interval state too */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num++; + entropy->next_restart_num &= 7; + } + entropy->restarts_to_go--; + } + + return TRUE; +} + + +/* + * Finish up at the end of a Huffman-compressed scan. + */ + +METHODDEF(void) +finish_pass_huff (j_compress_ptr cinfo) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + shuff_entropy_ptr entropy = (shuff_entropy_ptr) lossyc->entropy_private; + working_state state; + + /* Load up working state ... flush_bits needs it */ + state.next_output_byte = cinfo->dest->next_output_byte; + state.free_in_buffer = cinfo->dest->free_in_buffer; + ASSIGN_STATE(state.cur, entropy->saved); + state.cinfo = cinfo; + + /* Flush out the last data */ + if (! flush_bits(&state)) + ERREXIT(cinfo, JERR_CANT_SUSPEND); + + /* Update state */ + cinfo->dest->next_output_byte = state.next_output_byte; + cinfo->dest->free_in_buffer = state.free_in_buffer; + ASSIGN_STATE(entropy->saved, state.cur); +} + + +/* + * Huffman coding optimization. + * + * We first scan the supplied data and count the number of uses of each symbol + * that is to be Huffman-coded. (This process MUST agree with the code above.) + * Then we build a Huffman coding tree for the observed counts. + * Symbols which are not needed at all for the particular image are not + * assigned any code, which saves space in the DHT marker as well as in + * the compressed data. + */ + +#ifdef ENTROPY_OPT_SUPPORTED + + +/* Process a single block's worth of coefficients */ + +LOCAL(void) +htest_one_block (j_compress_ptr cinfo, JCOEFPTR block, int last_dc_val, + long dc_counts[], long ac_counts[]) +{ + register int temp; + register int nbits; + register int k, r; + + /* Encode the DC coefficient difference per section F.1.2.1 */ + + temp = block[0] - last_dc_val; + if (temp < 0) + temp = -temp; + + /* Find the number of bits needed for the magnitude of the coefficient */ + nbits = 0; + while (temp) { + nbits++; + temp >>= 1; + } + /* Check for out-of-range coefficient values. + * Since we're encoding a difference, the range limit is twice as much. + */ + if (nbits > MAX_COEF_BITS+1) + ERREXIT(cinfo, JERR_BAD_DCT_COEF); + + /* Count the Huffman symbol for the number of bits */ + dc_counts[nbits]++; + + /* Encode the AC coefficients per section F.1.2.2 */ + + r = 0; /* r = run length of zeros */ + + for (k = 1; k < DCTSIZE2; k++) { + if ((temp = block[jpeg_natural_order[k]]) == 0) { + r++; + } else { + /* if run length > 15, must emit special run-length-16 codes (0xF0) */ + while (r > 15) { + ac_counts[0xF0]++; + r -= 16; + } + + /* Find the number of bits needed for the magnitude of the coefficient */ + if (temp < 0) + temp = -temp; + + /* Find the number of bits needed for the magnitude of the coefficient */ + nbits = 1; /* there must be at least one 1 bit */ + while ((temp >>= 1)) + nbits++; + /* Check for out-of-range coefficient values */ + if (nbits > MAX_COEF_BITS) + ERREXIT(cinfo, JERR_BAD_DCT_COEF); + + /* Count Huffman symbol for run length / number of bits */ + ac_counts[(r << 4) + nbits]++; + + r = 0; + } + } + + /* If the last coef(s) were zero, emit an end-of-block code */ + if (r > 0) + ac_counts[0]++; +} + + +/* + * Trial-encode one MCU's worth of Huffman-compressed coefficients. + * No data is actually output, so no suspension return is possible. + */ + +METHODDEF(boolean) +encode_mcu_gather (j_compress_ptr cinfo, JBLOCKROW *MCU_data) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + shuff_entropy_ptr entropy = (shuff_entropy_ptr) lossyc->entropy_private; + int blkn, ci; + jpeg_component_info * compptr; + + /* Take care of restart intervals if needed */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + /* Re-initialize DC predictions to 0 */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) + entropy->saved.last_dc_val[ci] = 0; + /* Update restart state */ + entropy->restarts_to_go = cinfo->restart_interval; + } + entropy->restarts_to_go--; + } + + for (blkn = 0; blkn < cinfo->data_units_in_MCU; blkn++) { + ci = cinfo->MCU_membership[blkn]; + compptr = cinfo->cur_comp_info[ci]; + htest_one_block(cinfo, MCU_data[blkn][0], entropy->saved.last_dc_val[ci], + entropy->dc_count_ptrs[compptr->dc_tbl_no], + entropy->ac_count_ptrs[compptr->ac_tbl_no]); + entropy->saved.last_dc_val[ci] = MCU_data[blkn][0][0]; + } + + return TRUE; +} + + +/* + * Finish up a statistics-gathering pass and create the new Huffman tables. + */ + +METHODDEF(void) +finish_pass_gather (j_compress_ptr cinfo) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + shuff_entropy_ptr entropy = (shuff_entropy_ptr) lossyc->entropy_private; + int ci, dctbl, actbl; + jpeg_component_info * compptr; + JHUFF_TBL **htblptr; + boolean did_dc[NUM_HUFF_TBLS]; + boolean did_ac[NUM_HUFF_TBLS]; + + /* It's important not to apply jpeg_gen_optimal_table more than once + * per table, because it clobbers the input frequency counts! + */ + MEMZERO(did_dc, SIZEOF(did_dc)); + MEMZERO(did_ac, SIZEOF(did_ac)); + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + dctbl = compptr->dc_tbl_no; + actbl = compptr->ac_tbl_no; + if (! did_dc[dctbl]) { + htblptr = & cinfo->dc_huff_tbl_ptrs[dctbl]; + if (*htblptr == NULL) + *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo); + jpeg_gen_optimal_table(cinfo, *htblptr, entropy->dc_count_ptrs[dctbl]); + did_dc[dctbl] = TRUE; + } + if (! did_ac[actbl]) { + htblptr = & cinfo->ac_huff_tbl_ptrs[actbl]; + if (*htblptr == NULL) + *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo); + jpeg_gen_optimal_table(cinfo, *htblptr, entropy->ac_count_ptrs[actbl]); + did_ac[actbl] = TRUE; + } + } +} + + +#endif /* ENTROPY_OPT_SUPPORTED */ + + +METHODDEF(boolean) +need_optimization_pass (j_compress_ptr cinfo) +{ + (void)cinfo; + return TRUE; +} + + +/* + * Module initialization routine for Huffman entropy encoding. + */ + +GLOBAL(void) +jinit_shuff_encoder (j_compress_ptr cinfo) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + shuff_entropy_ptr entropy; + int i; + + entropy = (shuff_entropy_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(shuff_entropy_encoder)); + lossyc->entropy_private = (struct jpeg_entropy_encoder *) entropy; + lossyc->pub.entropy_start_pass = start_pass_huff; + lossyc->pub.need_optimization_pass = need_optimization_pass; + + /* Mark tables unallocated */ + for (i = 0; i < NUM_HUFF_TBLS; i++) { + entropy->dc_derived_tbls[i] = entropy->ac_derived_tbls[i] = NULL; +#ifdef ENTROPY_OPT_SUPPORTED + entropy->dc_count_ptrs[i] = entropy->ac_count_ptrs[i] = NULL; +#endif + } +} diff --git a/gdcm/Utilities/gdcmjpeg/jctrans.c b/gdcm/Utilities/gdcmjpeg/jctrans.c new file mode 100644 index 0000000..2eda76f --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jctrans.c @@ -0,0 +1,425 @@ +/* + * jctrans.c + * + * Copyright (C) 1995-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains library routines for transcoding compression, + * that is, writing raw DCT coefficient arrays to an output JPEG file. + * The routines in jcapimin.c will also be needed by a transcoder. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jlossy.h" /* Private declarations for lossy codec */ + + +/* Forward declarations */ +LOCAL(void) transencode_master_selection + JPP((j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays)); +LOCAL(void) transencode_codec + JPP((j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays)); +LOCAL(void) transencode_coef_controller + JPP((j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays)); + + +/* + * Compression initialization for writing raw-coefficient data. + * Before calling this, all parameters and a data destination must be set up. + * Call jpeg_finish_compress() to actually write the data. + * + * The number of passed virtual arrays must match cinfo->num_components. + * Note that the virtual arrays need not be filled or even realized at + * the time write_coefficients is called; indeed, if the virtual arrays + * were requested from this compression object's memory manager, they + * typically will be realized during this routine and filled afterwards. + */ + +GLOBAL(void) +jpeg_write_coefficients (j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays) +{ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + /* Mark all tables to be written */ + jpeg_suppress_tables(cinfo, FALSE); + /* (Re)initialize error mgr and destination modules */ + (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo); + (*cinfo->dest->init_destination) (cinfo); + /* Perform master selection of active modules */ + transencode_master_selection(cinfo, coef_arrays); + /* Wait for jpeg_finish_compress() call */ + cinfo->next_scanline = 0; /* so jpeg_write_marker works */ + cinfo->global_state = CSTATE_WRCOEFS; +} + + +/* + * Initialize the compression object with default parameters, + * then copy from the source object all parameters needed for lossless + * transcoding. Parameters that can be varied without loss (such as + * scan script and Huffman optimization) are left in their default states. + */ + +GLOBAL(void) +jpeg_copy_critical_parameters (j_decompress_ptr srcinfo, + j_compress_ptr dstinfo) +{ + JQUANT_TBL ** qtblptr; + jpeg_component_info *incomp, *outcomp; + JQUANT_TBL *c_quant, *slot_quant; + int tblno, ci, coefi; + + /* Safety check to ensure start_compress not called yet. */ + if (dstinfo->global_state != CSTATE_START) + ERREXIT1(dstinfo, JERR_BAD_STATE, dstinfo->global_state); + /* Copy fundamental image dimensions */ + dstinfo->image_width = srcinfo->image_width; + dstinfo->image_height = srcinfo->image_height; + dstinfo->input_components = srcinfo->num_components; + dstinfo->in_color_space = srcinfo->jpeg_color_space; + /* Initialize all parameters to default values */ + jpeg_set_defaults(dstinfo); + /* jpeg_set_defaults may choose wrong colorspace, eg YCbCr if input is RGB. + * Fix it to get the right header markers for the image colorspace. + */ + jpeg_set_colorspace(dstinfo, srcinfo->jpeg_color_space); + dstinfo->data_precision = srcinfo->data_precision; + dstinfo->CCIR601_sampling = srcinfo->CCIR601_sampling; + /* Copy the source's quantization tables. */ + for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) { + if (srcinfo->quant_tbl_ptrs[tblno] != NULL) { + qtblptr = & dstinfo->quant_tbl_ptrs[tblno]; + if (*qtblptr == NULL) + *qtblptr = jpeg_alloc_quant_table((j_common_ptr) dstinfo); + MEMCOPY((*qtblptr)->quantval, + srcinfo->quant_tbl_ptrs[tblno]->quantval, + SIZEOF((*qtblptr)->quantval)); + (*qtblptr)->sent_table = FALSE; + } + } + /* Copy the source's per-component info. + * Note we assume jpeg_set_defaults has allocated the dest comp_info array. + */ + dstinfo->num_components = srcinfo->num_components; + if (dstinfo->num_components < 1 || dstinfo->num_components > MAX_COMPONENTS) + ERREXIT2(dstinfo, JERR_COMPONENT_COUNT, dstinfo->num_components, + MAX_COMPONENTS); + for (ci = 0, incomp = srcinfo->comp_info, outcomp = dstinfo->comp_info; + ci < dstinfo->num_components; ci++, incomp++, outcomp++) { + outcomp->component_id = incomp->component_id; + outcomp->h_samp_factor = incomp->h_samp_factor; + outcomp->v_samp_factor = incomp->v_samp_factor; + outcomp->quant_tbl_no = incomp->quant_tbl_no; + /* Make sure saved quantization table for component matches the qtable + * slot. If not, the input file re-used this qtable slot. + * IJG encoder currently cannot duplicate this. + */ + tblno = outcomp->quant_tbl_no; + if (tblno < 0 || tblno >= NUM_QUANT_TBLS || + srcinfo->quant_tbl_ptrs[tblno] == NULL) + ERREXIT1(dstinfo, JERR_NO_QUANT_TABLE, tblno); + slot_quant = srcinfo->quant_tbl_ptrs[tblno]; + c_quant = incomp->quant_table; + if (c_quant != NULL) { + for (coefi = 0; coefi < DCTSIZE2; coefi++) { + if (c_quant->quantval[coefi] != slot_quant->quantval[coefi]) + ERREXIT1(dstinfo, JERR_MISMATCHED_QUANT_TABLE, tblno); + } + } + /* Note: we do not copy the source's Huffman table assignments; + * instead we rely on jpeg_set_colorspace to have made a suitable choice. + */ + } + /* Also copy JFIF version and resolution information, if available. + * Strictly speaking this isn't "critical" info, but it's nearly + * always appropriate to copy it if available. In particular, + * if the application chooses to copy JFIF 1.02 extension markers from + * the source file, we need to copy the version to make sure we don't + * emit a file that has 1.02 extensions but a claimed version of 1.01. + * We will *not*, however, copy version info from mislabeled "2.01" files. + */ + if (srcinfo->saw_JFIF_marker) { + if (srcinfo->JFIF_major_version == 1) { + dstinfo->JFIF_major_version = srcinfo->JFIF_major_version; + dstinfo->JFIF_minor_version = srcinfo->JFIF_minor_version; + } + dstinfo->density_unit = srcinfo->density_unit; + dstinfo->X_density = srcinfo->X_density; + dstinfo->Y_density = srcinfo->Y_density; + } +} + + +/* + * Master selection of compression modules for transcoding. + * This substitutes for jcinit.c's initialization of the full compressor. + */ + +LOCAL(void) +transencode_master_selection (j_compress_ptr cinfo, + jvirt_barray_ptr * coef_arrays) +{ + cinfo->data_unit = DCTSIZE; + /* Although we don't actually use input_components for transcoding, + * jcmaster.c's initial_setup will complain if input_components is 0. + */ + cinfo->input_components = 1; + /* Initialize master control (includes parameter checking/processing) */ + jinit_c_master_control(cinfo, TRUE /* transcode only */); + + /* We need a special compression codec. */ + transencode_codec(cinfo, coef_arrays); + + jinit_marker_writer(cinfo); + + /* We can now tell the memory manager to allocate virtual arrays. */ + (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo); + + /* Write the datastream header (SOI, JFIF) immediately. + * Frame and scan headers are postponed till later. + * This lets application insert special markers after the SOI. + */ + (*cinfo->marker->write_file_header) (cinfo); +} + + +/* + * The rest of this file is a special implementation of the coefficient + * buffer controller. This is similar to jccoefct.c, but it handles only + * output from presupplied virtual arrays. Furthermore, we generate any + * dummy padding blocks on-the-fly rather than expecting them to be present + * in the arrays. + */ + +/* Private buffer controller object */ + +typedef struct { + JDIMENSION iMCU_row_num; /* iMCU row # within image */ + JDIMENSION mcu_ctr; /* counts MCUs processed in current row */ + int MCU_vert_offset; /* counts MCU rows within iMCU row */ + int MCU_rows_per_iMCU_row; /* number of such rows needed */ + + /* Virtual block array for each component. */ + jvirt_barray_ptr * whole_image; + + /* Workspace for constructing dummy blocks at right/bottom edges. */ + JBLOCKROW dummy_buffer[C_MAX_DATA_UNITS_IN_MCU]; +} c_coef_controller; + +typedef c_coef_controller * c_coef_ptr; + + +LOCAL(void) +start_iMCU_row (j_compress_ptr cinfo) +/* Reset within-iMCU-row counters for a new row */ +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + c_coef_ptr coef = (c_coef_ptr) lossyc->coef_private; + + /* In an interleaved scan, an MCU row is the same as an iMCU row. + * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows. + * But at the bottom of the image, process only what's left. + */ + if (cinfo->comps_in_scan > 1) { + coef->MCU_rows_per_iMCU_row = 1; + } else { + if (coef->iMCU_row_num < (cinfo->total_iMCU_rows-1)) + coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor; + else + coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height; + } + + coef->mcu_ctr = 0; + coef->MCU_vert_offset = 0; +} + + +/* + * Initialize for a processing pass. + */ + +METHODDEF(void) +start_pass_coef (j_compress_ptr cinfo, J_BUF_MODE pass_mode) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + c_coef_ptr coef = (c_coef_ptr) lossyc->coef_private; + + if (pass_mode != JBUF_CRANK_DEST) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + + coef->iMCU_row_num = 0; + start_iMCU_row(cinfo); +} + + +/* + * Process some data. + * We process the equivalent of one fully interleaved MCU row ("iMCU" row) + * per call, ie, v_samp_factor block rows for each component in the scan. + * The data is obtained from the virtual arrays and fed to the entropy coder. + * Returns TRUE if the iMCU row is completed, FALSE if suspended. + * + * NB: input_buf is ignored; it is likely to be a NULL pointer. + */ + +METHODDEF(boolean) +compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + c_coef_ptr coef = (c_coef_ptr) lossyc->coef_private; + JDIMENSION MCU_col_num; /* index of current MCU within row */ + JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1; + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + int blkn, ci, xindex, yindex, yoffset, blockcnt; + JDIMENSION start_col; + JBLOCKARRAY buffer[MAX_COMPS_IN_SCAN]; + JBLOCKROW MCU_buffer[C_MAX_DATA_UNITS_IN_MCU]; + JBLOCKROW buffer_ptr; + jpeg_component_info *compptr; + (void)input_buf; + + /* Align the virtual buffers for the components used in this scan. */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + buffer[ci] = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef->whole_image[compptr->component_index], + coef->iMCU_row_num * compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } + + /* Loop to process one whole iMCU row */ + for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row; + yoffset++) { + for (MCU_col_num = coef->mcu_ctr; MCU_col_num < cinfo->MCUs_per_row; + MCU_col_num++) { + /* Construct list of pointers to DCT blocks belonging to this MCU */ + blkn = 0; /* index of current DCT block within MCU */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + start_col = MCU_col_num * compptr->MCU_width; + blockcnt = (MCU_col_num < last_MCU_col) ? compptr->MCU_width + : compptr->last_col_width; + for (yindex = 0; yindex < compptr->MCU_height; yindex++) { + if (coef->iMCU_row_num < last_iMCU_row || + yindex+yoffset < compptr->last_row_height) { + /* Fill in pointers to real blocks in this row */ + buffer_ptr = buffer[ci][yindex+yoffset] + start_col; + for (xindex = 0; xindex < blockcnt; xindex++) + MCU_buffer[blkn++] = buffer_ptr++; + } else { + /* At bottom of image, need a whole row of dummy blocks */ + xindex = 0; + } + /* Fill in any dummy blocks needed in this row. + * Dummy blocks are filled in the same way as in jccoefct.c: + * all zeroes in the AC entries, DC entries equal to previous + * block's DC value. The init routine has already zeroed the + * AC entries, so we need only set the DC entries correctly. + */ + for (; xindex < compptr->MCU_width; xindex++) { + MCU_buffer[blkn] = coef->dummy_buffer[blkn]; + MCU_buffer[blkn][0][0] = MCU_buffer[blkn-1][0][0]; + blkn++; + } + } + } + /* Try to write the MCU. */ + if (! (*lossyc->entropy_encode_mcu) (cinfo, MCU_buffer)) { + /* Suspension forced; update state counters and exit */ + coef->MCU_vert_offset = yoffset; + coef->mcu_ctr = MCU_col_num; + return FALSE; + } + } + /* Completed an MCU row, but perhaps not an iMCU row */ + coef->mcu_ctr = 0; + } + /* Completed the iMCU row, advance counters for next one */ + coef->iMCU_row_num++; + start_iMCU_row(cinfo); + return TRUE; +} + + +/* + * Initialize coefficient buffer controller. + * + * Each passed coefficient array must be the right size for that + * coefficient: width_in_data_units wide and height_in_data_units high, + * with unitheight at least v_samp_factor. + */ + +LOCAL(void) +transencode_coef_controller (j_compress_ptr cinfo, + jvirt_barray_ptr * coef_arrays) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + c_coef_ptr coef; + JBLOCKROW buffer; + int i; + + coef = (c_coef_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(c_coef_controller)); + lossyc->coef_private = (struct jpeg_c_coef_controller *) coef; + + /* Save pointer to virtual arrays */ + coef->whole_image = coef_arrays; + + /* Allocate and pre-zero space for dummy DCT blocks. */ + buffer = (JBLOCKROW) + (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE, + C_MAX_DATA_UNITS_IN_MCU * SIZEOF(JBLOCK)); + jzero_far((void FAR *) buffer, C_MAX_DATA_UNITS_IN_MCU * SIZEOF(JBLOCK)); + for (i = 0; i < C_MAX_DATA_UNITS_IN_MCU; i++) { + coef->dummy_buffer[i] = buffer + i; + } +} + + +/* + * Initialize the transencoer codec. + * This is called only once, during master selection. + */ + +LOCAL(void) +transencode_codec (j_compress_ptr cinfo, + jvirt_barray_ptr * coef_arrays) +{ + j_lossy_c_ptr lossyc; + + /* Create subobject in permanent pool */ + lossyc = (j_lossy_c_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + SIZEOF(jpeg_lossy_c_codec)); + cinfo->codec = (struct jpeg_c_codec *) lossyc; + + /* Initialize sub-modules */ + + /* Entropy encoding: either Huffman or arithmetic coding. */ + if (cinfo->arith_code) { +#ifdef WITH_ARITHMETIC_PATCH + jinit_arith_encoder(cinfo); +#else + ERREXIT(cinfo, JERR_ARITH_NOTIMPL); +#endif + } else { + if (cinfo->process == JPROC_PROGRESSIVE) { +#ifdef C_PROGRESSIVE_SUPPORTED + jinit_phuff_encoder(cinfo); +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else + jinit_shuff_encoder(cinfo); + } + + /* We need a special coefficient buffer controller. */ + transencode_coef_controller(cinfo, coef_arrays); + + /* Initialize method pointers */ + lossyc->pub.start_pass = start_pass_coef; + lossyc->pub.compress_data = compress_output; +} diff --git a/gdcm/Utilities/gdcmjpeg/jdapimin.c b/gdcm/Utilities/gdcmjpeg/jdapimin.c new file mode 100644 index 0000000..a412027 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jdapimin.c @@ -0,0 +1,401 @@ +/* + * jdapimin.c + * + * Copyright (C) 1994-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains application interface code for the decompression half + * of the JPEG library. These are the "minimum" API routines that may be + * needed in either the normal full-decompression case or the + * transcoding-only case. + * + * Most of the routines intended to be called directly by an application + * are in this file or in jdapistd.c. But also see jcomapi.c for routines + * shared by compression and decompression, and jdtrans.c for the transcoding + * case. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * Initialization of a JPEG decompression object. + * The error manager must already be set up (in case memory manager fails). + */ + +GLOBAL(void) +jpeg_CreateDecompress (j_decompress_ptr cinfo, int version, size_t structsize) +{ + int i; + + /* Guard against version mismatches between library and caller. */ + cinfo->mem = NULL; /* so jpeg_destroy knows mem mgr not called */ + if (version != JPEG_LIB_VERSION) + ERREXIT2(cinfo, JERR_BAD_LIB_VERSION, JPEG_LIB_VERSION, version); + if (structsize != SIZEOF(struct jpeg_decompress_struct)) + ERREXIT2(cinfo, JERR_BAD_STRUCT_SIZE, + (int) SIZEOF(struct jpeg_decompress_struct), (int) structsize); + + /* For debugging purposes, we zero the whole master structure. + * But the application has already set the err pointer, and may have set + * client_data, so we have to save and restore those fields. + * Note: if application hasn't set client_data, tools like Purify may + * complain here. + */ + { + struct jpeg_error_mgr * err = cinfo->err; + void * client_data = cinfo->client_data; /* ignore Purify complaint here */ + MEMZERO(cinfo, SIZEOF(struct jpeg_decompress_struct)); + cinfo->err = err; + cinfo->client_data = client_data; + } + cinfo->is_decompressor = TRUE; + + /* Initialize a memory manager instance for this object */ + jinit_memory_mgr((j_common_ptr) cinfo); + + /* Zero out pointers to permanent structures. */ + cinfo->progress = NULL; + cinfo->src = NULL; + + for (i = 0; i < NUM_QUANT_TBLS; i++) + cinfo->quant_tbl_ptrs[i] = NULL; + + for (i = 0; i < NUM_HUFF_TBLS; i++) { + cinfo->dc_huff_tbl_ptrs[i] = NULL; + cinfo->ac_huff_tbl_ptrs[i] = NULL; + } + + /* Initialize marker processor so application can override methods + * for COM, APPn markers before calling jpeg_read_header. + */ + cinfo->marker_list = NULL; + jinit_marker_reader(cinfo); + + /* And initialize the overall input controller. */ + jinit_input_controller(cinfo); + + /* OK, I'm ready */ + cinfo->global_state = DSTATE_START; +} + + +/* + * Destruction of a JPEG decompression object + */ + +GLOBAL(void) +jpeg_destroy_decompress (j_decompress_ptr cinfo) +{ + jpeg_destroy((j_common_ptr) cinfo); /* use common routine */ +} + + +/* + * Abort processing of a JPEG decompression operation, + * but don't destroy the object itself. + */ + +GLOBAL(void) +jpeg_abort_decompress (j_decompress_ptr cinfo) +{ + jpeg_abort((j_common_ptr) cinfo); /* use common routine */ +} + + +/* + * Set default decompression parameters. + */ + +LOCAL(void) +default_decompress_parms (j_decompress_ptr cinfo) +{ + /* Guess the input colorspace, and set output colorspace accordingly. */ + /* (Wish JPEG committee had provided a real way to specify this...) */ + /* Note application may override our guesses. */ + switch (cinfo->num_components) { + case 1: + cinfo->jpeg_color_space = JCS_GRAYSCALE; + cinfo->out_color_space = JCS_GRAYSCALE; + break; + + case 3: + if (cinfo->saw_JFIF_marker) { + cinfo->jpeg_color_space = JCS_YCbCr; /* JFIF implies YCbCr */ + } else if (cinfo->saw_Adobe_marker) { + switch (cinfo->Adobe_transform) { + case 0: + cinfo->jpeg_color_space = JCS_RGB; + break; + case 1: + cinfo->jpeg_color_space = JCS_YCbCr; + break; + default: + WARNMS1(cinfo, JWRN_ADOBE_XFORM, cinfo->Adobe_transform); + cinfo->jpeg_color_space = JCS_YCbCr; /* assume it's YCbCr */ + break; + } + } else { + /* Saw no special markers, try to guess from the component IDs */ + int cid0 = cinfo->comp_info[0].component_id; + int cid1 = cinfo->comp_info[1].component_id; + int cid2 = cinfo->comp_info[2].component_id; + + if (cid0 == 1 && cid1 == 2 && cid2 == 3) + cinfo->jpeg_color_space = JCS_YCbCr; /* assume JFIF w/out marker */ + else if (cid0 == 82 && cid1 == 71 && cid2 == 66) + cinfo->jpeg_color_space = JCS_RGB; /* ASCII 'R', 'G', 'B' */ + else { + if (cinfo->process == JPROC_LOSSLESS) { + TRACEMS3(cinfo, 1, JTRC_UNKNOWN_LOSSLESS_IDS, cid0, cid1, cid2); + cinfo->jpeg_color_space = JCS_RGB; /* assume it's RGB */ + } + else { /* Lossy processes */ + TRACEMS3(cinfo, 1, JTRC_UNKNOWN_LOSSY_IDS, cid0, cid1, cid2); + cinfo->jpeg_color_space = JCS_YCbCr; /* assume it's YCbCr */ + } + } + } + /* Always guess RGB is proper output colorspace. */ + cinfo->out_color_space = JCS_RGB; + break; + + case 4: + if (cinfo->saw_Adobe_marker) { + switch (cinfo->Adobe_transform) { + case 0: + cinfo->jpeg_color_space = JCS_CMYK; + break; + case 2: + cinfo->jpeg_color_space = JCS_YCCK; + break; + default: + WARNMS1(cinfo, JWRN_ADOBE_XFORM, cinfo->Adobe_transform); + cinfo->jpeg_color_space = JCS_YCCK; /* assume it's YCCK */ + break; + } + } else { + /* No special markers, assume straight CMYK. */ + cinfo->jpeg_color_space = JCS_CMYK; + } + cinfo->out_color_space = JCS_CMYK; + break; + + default: + cinfo->jpeg_color_space = JCS_UNKNOWN; + cinfo->out_color_space = JCS_UNKNOWN; + break; + } + + /* Set defaults for other decompression parameters. */ + cinfo->scale_num = 1; /* 1:1 scaling */ + cinfo->scale_denom = 1; + cinfo->output_gamma = 1.0; + cinfo->buffered_image = FALSE; + cinfo->raw_data_out = FALSE; + cinfo->dct_method = JDCT_DEFAULT; + cinfo->do_fancy_upsampling = TRUE; + cinfo->do_block_smoothing = TRUE; + cinfo->quantize_colors = FALSE; + /* We set these in case application only sets quantize_colors. */ + cinfo->dither_mode = JDITHER_FS; +#ifdef QUANT_2PASS_SUPPORTED + cinfo->two_pass_quantize = TRUE; +#else + cinfo->two_pass_quantize = FALSE; +#endif + cinfo->desired_number_of_colors = 256; + cinfo->colormap = NULL; + /* Initialize for no mode change in buffered-image mode. */ + cinfo->enable_1pass_quant = FALSE; + cinfo->enable_external_quant = FALSE; + cinfo->enable_2pass_quant = FALSE; +} + + +/* + * Decompression startup: read start of JPEG datastream to see what's there. + * Need only initialize JPEG object and supply a data source before calling. + * + * This routine will read as far as the first SOS marker (ie, actual start of + * compressed data), and will save all tables and parameters in the JPEG + * object. It will also initialize the decompression parameters to default + * values, and finally return JPEG_HEADER_OK. On return, the application may + * adjust the decompression parameters and then call jpeg_start_decompress. + * (Or, if the application only wanted to determine the image parameters, + * the data need not be decompressed. In that case, call jpeg_abort or + * jpeg_destroy to release any temporary space.) + * If an abbreviated (tables only) datastream is presented, the routine will + * return JPEG_HEADER_TABLES_ONLY upon reaching EOI. The application may then + * re-use the JPEG object to read the abbreviated image datastream(s). + * It is unnecessary (but OK) to call jpeg_abort in this case. + * The JPEG_SUSPENDED return code only occurs if the data source module + * requests suspension of the decompressor. In this case the application + * should load more source data and then re-call jpeg_read_header to resume + * processing. + * If a non-suspending data source is used and require_image is TRUE, then the + * return code need not be inspected since only JPEG_HEADER_OK is possible. + * + * This routine is now just a front end to jpeg_consume_input, with some + * extra error checking. + */ + +GLOBAL(int) +jpeg_read_header (j_decompress_ptr cinfo, boolean require_image) +{ + int retcode; + + if (cinfo->global_state != DSTATE_START && + cinfo->global_state != DSTATE_INHEADER) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + retcode = jpeg_consume_input(cinfo); + + switch (retcode) { + case JPEG_REACHED_SOS: + retcode = JPEG_HEADER_OK; + break; + case JPEG_REACHED_EOI: + if (require_image) /* Complain if application wanted an image */ + ERREXIT(cinfo, JERR_NO_IMAGE); + /* Reset to start state; it would be safer to require the application to + * call jpeg_abort, but we can't change it now for compatibility reasons. + * A side effect is to free any temporary memory (there shouldn't be any). + */ + jpeg_abort((j_common_ptr) cinfo); /* sets state = DSTATE_START */ + retcode = JPEG_HEADER_TABLES_ONLY; + break; + case JPEG_SUSPENDED: + /* no work */ + break; + } + + return retcode; +} + + +/* + * Consume data in advance of what the decompressor requires. + * This can be called at any time once the decompressor object has + * been created and a data source has been set up. + * + * This routine is essentially a state machine that handles a couple + * of critical state-transition actions, namely initial setup and + * transition from header scanning to ready-for-start_decompress. + * All the actual input is done via the input controller's consume_input + * method. + */ + +GLOBAL(int) +jpeg_consume_input (j_decompress_ptr cinfo) +{ + int retcode = JPEG_SUSPENDED; + + /* NB: every possible DSTATE value should be listed in this switch */ + switch (cinfo->global_state) { + case DSTATE_START: + /* Start-of-datastream actions: reset appropriate modules */ + (*cinfo->inputctl->reset_input_controller) (cinfo); + /* Initialize application's data source module */ + (*cinfo->src->init_source) (cinfo); + cinfo->global_state = DSTATE_INHEADER; + /*FALLTHROUGH*/ + case DSTATE_INHEADER: + retcode = (*cinfo->inputctl->consume_input) (cinfo); + if (retcode == JPEG_REACHED_SOS) { /* Found SOS, prepare to decompress */ + /* Set up default parameters based on header data */ + default_decompress_parms(cinfo); + /* Set global state: ready for start_decompress */ + cinfo->global_state = DSTATE_READY; + } + break; + case DSTATE_READY: + /* Can't advance past first SOS until start_decompress is called */ + retcode = JPEG_REACHED_SOS; + break; + case DSTATE_PRELOAD: + case DSTATE_PRESCAN: + case DSTATE_SCANNING: + case DSTATE_RAW_OK: + case DSTATE_BUFIMAGE: + case DSTATE_BUFPOST: + case DSTATE_STOPPING: + retcode = (*cinfo->inputctl->consume_input) (cinfo); + break; + default: + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + } + return retcode; +} + + +/* + * Have we finished reading the input file? + */ + +GLOBAL(boolean) +jpeg_input_complete (j_decompress_ptr cinfo) +{ + /* Check for valid jpeg object */ + if (cinfo->global_state < DSTATE_START || + cinfo->global_state > DSTATE_STOPPING) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + return cinfo->inputctl->eoi_reached; +} + + +/* + * Is there more than one scan? + */ + +GLOBAL(boolean) +jpeg_has_multiple_scans (j_decompress_ptr cinfo) +{ + /* Only valid after jpeg_read_header completes */ + if (cinfo->global_state < DSTATE_READY || + cinfo->global_state > DSTATE_STOPPING) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + return cinfo->inputctl->has_multiple_scans; +} + + +/* + * Finish JPEG decompression. + * + * This will normally just verify the file trailer and release temp storage. + * + * Returns FALSE if suspended. The return value need be inspected only if + * a suspending data source is used. + */ + +GLOBAL(boolean) +jpeg_finish_decompress (j_decompress_ptr cinfo) +{ + if ((cinfo->global_state == DSTATE_SCANNING || + cinfo->global_state == DSTATE_RAW_OK) && ! cinfo->buffered_image) { + /* Terminate final pass of non-buffered mode */ + if (cinfo->output_scanline < cinfo->output_height) + ERREXIT(cinfo, JERR_TOO_LITTLE_DATA); + (*cinfo->master->finish_output_pass) (cinfo); + cinfo->global_state = DSTATE_STOPPING; + } else if (cinfo->global_state == DSTATE_BUFIMAGE) { + /* Finishing after a buffered-image operation */ + cinfo->global_state = DSTATE_STOPPING; + } else if (cinfo->global_state != DSTATE_STOPPING) { + /* STOPPING = repeat call after a suspension, anything else is error */ + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + } + /* Read until EOI */ + while (! cinfo->inputctl->eoi_reached) { + if ((*cinfo->inputctl->consume_input) (cinfo) == JPEG_SUSPENDED) + return FALSE; /* Suspend, come back later */ + } + /* Do final cleanup */ + (*cinfo->src->term_source) (cinfo); + /* We can use jpeg_abort to release memory and reset global_state */ + jpeg_abort((j_common_ptr) cinfo); + return TRUE; +} diff --git a/gdcm/Utilities/gdcmjpeg/jdapistd.c b/gdcm/Utilities/gdcmjpeg/jdapistd.c new file mode 100644 index 0000000..4cc36d7 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jdapistd.c @@ -0,0 +1,275 @@ +/* + * jdapistd.c + * + * Copyright (C) 1994-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains application interface code for the decompression half + * of the JPEG library. These are the "standard" API routines that are + * used in the normal full-decompression case. They are not used by a + * transcoding-only application. Note that if an application links in + * jpeg_start_decompress, it will end up linking in the entire decompressor. + * We thus must separate this file from jdapimin.c to avoid linking the + * whole decompression library into a transcoder. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Forward declarations */ +LOCAL(boolean) output_pass_setup JPP((j_decompress_ptr cinfo)); + + +/* + * Decompression initialization. + * jpeg_read_header must be completed before calling this. + * + * If a multipass operating mode was selected, this will do all but the + * last pass, and thus may take a great deal of time. + * + * Returns FALSE if suspended. The return value need be inspected only if + * a suspending data source is used. + */ + +GLOBAL(boolean) +jpeg_start_decompress (j_decompress_ptr cinfo) +{ + if (cinfo->global_state == DSTATE_READY) { + /* First call: initialize master control, select active modules */ + jinit_master_decompress(cinfo); + if (cinfo->buffered_image) { + /* No more work here; expecting jpeg_start_output next */ + cinfo->global_state = DSTATE_BUFIMAGE; + return TRUE; + } + cinfo->global_state = DSTATE_PRELOAD; + } + if (cinfo->global_state == DSTATE_PRELOAD) { + /* If file has multiple scans, absorb them all into the coef buffer */ + if (cinfo->inputctl->has_multiple_scans) { +#ifdef D_MULTISCAN_FILES_SUPPORTED + for (;;) { + int retcode; + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + /* Absorb some more input */ + retcode = (*cinfo->inputctl->consume_input) (cinfo); + if (retcode == JPEG_SUSPENDED) + return FALSE; + if (retcode == JPEG_REACHED_EOI) + break; + /* Advance progress counter if appropriate */ + if (cinfo->progress != NULL && + (retcode == JPEG_ROW_COMPLETED || retcode == JPEG_REACHED_SOS)) { + if (++cinfo->progress->pass_counter >= cinfo->progress->pass_limit) { + /* jdmaster underestimated number of scans; ratchet up one scan */ + cinfo->progress->pass_limit += (long) cinfo->total_iMCU_rows; + } + } + } +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif /* D_MULTISCAN_FILES_SUPPORTED */ + } + cinfo->output_scan_number = cinfo->input_scan_number; + } else if (cinfo->global_state != DSTATE_PRESCAN) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + /* Perform any dummy output passes, and set up for the final pass */ + return output_pass_setup(cinfo); +} + + +/* + * Set up for an output pass, and perform any dummy pass(es) needed. + * Common subroutine for jpeg_start_decompress and jpeg_start_output. + * Entry: global_state = DSTATE_PRESCAN only if previously suspended. + * Exit: If done, returns TRUE and sets global_state for proper output mode. + * If suspended, returns FALSE and sets global_state = DSTATE_PRESCAN. + */ + +LOCAL(boolean) +output_pass_setup (j_decompress_ptr cinfo) +{ + if (cinfo->global_state != DSTATE_PRESCAN) { + /* First call: do pass setup */ + (*cinfo->master->prepare_for_output_pass) (cinfo); + cinfo->output_scanline = 0; + cinfo->global_state = DSTATE_PRESCAN; + } + /* Loop over any required dummy passes */ + while (cinfo->master->is_dummy_pass) { +#ifdef QUANT_2PASS_SUPPORTED + /* Crank through the dummy pass */ + while (cinfo->output_scanline < cinfo->output_height) { + JDIMENSION last_scanline; + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) { + cinfo->progress->pass_counter = (long) cinfo->output_scanline; + cinfo->progress->pass_limit = (long) cinfo->output_height; + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + } + /* Process some data */ + last_scanline = cinfo->output_scanline; + (*cinfo->main->process_data) (cinfo, (JSAMPARRAY) NULL, + &cinfo->output_scanline, (JDIMENSION) 0); + if (cinfo->output_scanline == last_scanline) + return FALSE; /* No progress made, must suspend */ + } + /* Finish up dummy pass, and set up for another one */ + (*cinfo->master->finish_output_pass) (cinfo); + (*cinfo->master->prepare_for_output_pass) (cinfo); + cinfo->output_scanline = 0; +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif /* QUANT_2PASS_SUPPORTED */ + } + /* Ready for application to drive output pass through + * jpeg_read_scanlines or jpeg_read_raw_data. + */ + cinfo->global_state = cinfo->raw_data_out ? DSTATE_RAW_OK : DSTATE_SCANNING; + return TRUE; +} + + +/* + * Read some scanlines of data from the JPEG decompressor. + * + * The return value will be the number of lines actually read. + * This may be less than the number requested in several cases, + * including bottom of image, data source suspension, and operating + * modes that emit multiple scanlines at a time. + * + * Note: we warn about excess calls to jpeg_read_scanlines() since + * this likely signals an application programmer error. However, + * an oversize buffer (max_lines > scanlines remaining) is not an error. + */ + +GLOBAL(JDIMENSION) +jpeg_read_scanlines (j_decompress_ptr cinfo, JSAMPARRAY scanlines, + JDIMENSION max_lines) +{ + JDIMENSION row_ctr; + + if (cinfo->global_state != DSTATE_SCANNING) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + if (cinfo->output_scanline >= cinfo->output_height) { + WARNMS(cinfo, JWRN_TOO_MUCH_DATA); + return 0; + } + + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) { + cinfo->progress->pass_counter = (long) cinfo->output_scanline; + cinfo->progress->pass_limit = (long) cinfo->output_height; + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + } + + /* Process some data */ + row_ctr = 0; + (*cinfo->main->process_data) (cinfo, scanlines, &row_ctr, max_lines); + cinfo->output_scanline += row_ctr; + return row_ctr; +} + + +/* + * Alternate entry point to read raw data. + * Processes exactly one iMCU row per call, unless suspended. + */ + +GLOBAL(JDIMENSION) +jpeg_read_raw_data (j_decompress_ptr cinfo, JSAMPIMAGE data, + JDIMENSION max_lines) +{ + JDIMENSION lines_per_iMCU_row; + + if (cinfo->global_state != DSTATE_RAW_OK) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + if (cinfo->output_scanline >= cinfo->output_height) { + WARNMS(cinfo, JWRN_TOO_MUCH_DATA); + return 0; + } + + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) { + cinfo->progress->pass_counter = (long) cinfo->output_scanline; + cinfo->progress->pass_limit = (long) cinfo->output_height; + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + } + + /* Verify that at least one iMCU row can be returned. */ + lines_per_iMCU_row = cinfo->max_v_samp_factor * cinfo->min_codec_data_unit; + if (max_lines < lines_per_iMCU_row) + ERREXIT(cinfo, JERR_BUFFER_SIZE); + + /* Decompress directly into user's buffer. */ + if (! (*cinfo->codec->decompress_data) (cinfo, data)) + return 0; /* suspension forced, can do nothing more */ + + /* OK, we processed one iMCU row. */ + cinfo->output_scanline += lines_per_iMCU_row; + return lines_per_iMCU_row; +} + + +/* Additional entry points for buffered-image mode. */ + +#ifdef D_MULTISCAN_FILES_SUPPORTED + +/* + * Initialize for an output pass in buffered-image mode. + */ + +GLOBAL(boolean) +jpeg_start_output (j_decompress_ptr cinfo, int scan_number) +{ + if (cinfo->global_state != DSTATE_BUFIMAGE && + cinfo->global_state != DSTATE_PRESCAN) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + /* Limit scan number to valid range */ + if (scan_number <= 0) + scan_number = 1; + if (cinfo->inputctl->eoi_reached && + scan_number > cinfo->input_scan_number) + scan_number = cinfo->input_scan_number; + cinfo->output_scan_number = scan_number; + /* Perform any dummy output passes, and set up for the real pass */ + return output_pass_setup(cinfo); +} + + +/* + * Finish up after an output pass in buffered-image mode. + * + * Returns FALSE if suspended. The return value need be inspected only if + * a suspending data source is used. + */ + +GLOBAL(boolean) +jpeg_finish_output (j_decompress_ptr cinfo) +{ + if ((cinfo->global_state == DSTATE_SCANNING || + cinfo->global_state == DSTATE_RAW_OK) && cinfo->buffered_image) { + /* Terminate this pass. */ + /* We do not require the whole pass to have been completed. */ + (*cinfo->master->finish_output_pass) (cinfo); + cinfo->global_state = DSTATE_BUFPOST; + } else if (cinfo->global_state != DSTATE_BUFPOST) { + /* BUFPOST = repeat call after a suspension, anything else is error */ + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + } + /* Read markers looking for SOS or EOI */ + while (cinfo->input_scan_number <= cinfo->output_scan_number && + ! cinfo->inputctl->eoi_reached) { + if ((*cinfo->inputctl->consume_input) (cinfo) == JPEG_SUSPENDED) + return FALSE; /* Suspend, come back later */ + } + cinfo->global_state = DSTATE_BUFIMAGE; + return TRUE; +} + +#endif /* D_MULTISCAN_FILES_SUPPORTED */ diff --git a/gdcm/Utilities/gdcmjpeg/jdatadst.c b/gdcm/Utilities/gdcmjpeg/jdatadst.c new file mode 100644 index 0000000..079aad9 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jdatadst.c @@ -0,0 +1,155 @@ +/* + * jdatadst.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains compression data destination routines for the case of + * emitting JPEG data to a file (or any stdio stream). While these routines + * are sufficient for most applications, some will want to use a different + * destination manager. + * IMPORTANT: we assume that fwrite() will correctly transcribe an array of + * JOCTETs into 8-bit-wide elements on external storage. If char is wider + * than 8 bits on your machine, you may need to do some tweaking. + */ + +/* this is not a core library module, so it doesn't define JPEG_INTERNALS */ +#include "jinclude.h" +#include "jpeglib.h" +#include "jerror.h" + + +/* Expanded data destination object for stdio output */ + +/** + * \brief very low level C 'structure', used to decode jpeg file + * Should not appear in the Doxygen supplied documentation + */ +typedef struct { + struct jpeg_destination_mgr pub; /* public fields */ + + FILE * outfile; /* target stream */ + JOCTET * buffer; /* start of buffer */ +} my_destination_mgr; + +typedef my_destination_mgr * my_dest_ptr; + +#define OUTPUT_BUF_SIZE 4096 /* choose an efficiently fwrite'able size */ + + +/* + * Initialize destination --- called by jpeg_start_compress + * before any data is actually written. + */ + +METHODDEF(void) +init_destination (j_compress_ptr cinfo) +{ + my_dest_ptr dest = (my_dest_ptr) cinfo->dest; + + /* Allocate the output buffer --- it will be released when done with image */ + dest->buffer = (JOCTET *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + OUTPUT_BUF_SIZE * SIZEOF(JOCTET)); + + dest->pub.next_output_byte = dest->buffer; + dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; +} + + +/* + * Empty the output buffer --- called whenever buffer fills up. + * + * In typical applications, this should write the entire output buffer + * (ignoring the current state of next_output_byte & free_in_buffer), + * reset the pointer & count to the start of the buffer, and return TRUE + * indicating that the buffer has been dumped. + * + * In applications that need to be able to suspend compression due to output + * overrun, a FALSE return indicates that the buffer cannot be emptied now. + * In this situation, the compressor will return to its caller (possibly with + * an indication that it has not accepted all the supplied scanlines). The + * application should resume compression after it has made more room in the + * output buffer. Note that there are substantial restrictions on the use of + * suspension --- see the documentation. + * + * When suspending, the compressor will back up to a convenient restart point + * (typically the start of the current MCU). next_output_byte & free_in_buffer + * indicate where the restart point will be if the current call returns FALSE. + * Data beyond this point will be regenerated after resumption, so do not + * write it out when emptying the buffer externally. + */ + +METHODDEF(boolean) +empty_output_buffer (j_compress_ptr cinfo) +{ + my_dest_ptr dest = (my_dest_ptr) cinfo->dest; + + if (JFWRITE(dest->outfile, dest->buffer, OUTPUT_BUF_SIZE) != + (size_t) OUTPUT_BUF_SIZE) + ERREXIT(cinfo, JERR_FILE_WRITE); + + dest->pub.next_output_byte = dest->buffer; + dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; + + return TRUE; +} + + +/* + * Terminate destination --- called by jpeg_finish_compress + * after all data has been written. Usually needs to flush buffer. + * + * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding + * application must deal with any cleanup that should happen even + * for error exit. + */ + +METHODDEF(void) +term_destination (j_compress_ptr cinfo) +{ + my_dest_ptr dest = (my_dest_ptr) cinfo->dest; + size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer; + + /* Write any data remaining in the buffer */ + if (datacount > 0) { + if (JFWRITE(dest->outfile, dest->buffer, datacount) != datacount) + ERREXIT(cinfo, JERR_FILE_WRITE); + } + fflush(dest->outfile); + /* Make sure we wrote the output file OK */ + if (ferror(dest->outfile)) + ERREXIT(cinfo, JERR_FILE_WRITE); +} + + +/* + * Prepare for output to a stdio stream. + * The caller must have already opened the stream, and is responsible + * for closing it after finishing compression. + */ + +GLOBAL(void) +jpeg_stdio_dest (j_compress_ptr cinfo, FILE * outfile) +{ + my_dest_ptr dest; + + /* The destination object is made permanent so that multiple JPEG images + * can be written to the same file without re-executing jpeg_stdio_dest. + * This makes it dangerous to use this manager and a different destination + * manager serially with the same JPEG object, because their private object + * sizes may be different. Caveat programmer. + */ + if (cinfo->dest == NULL) { /* first time for this JPEG object? */ + cinfo->dest = (struct jpeg_destination_mgr *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + SIZEOF(my_destination_mgr)); + } + + dest = (my_dest_ptr) cinfo->dest; + dest->pub.init_destination = init_destination; + dest->pub.empty_output_buffer = empty_output_buffer; + dest->pub.term_destination = term_destination; + dest->outfile = outfile; +} diff --git a/gdcm/Utilities/gdcmjpeg/jdatasrc.c b/gdcm/Utilities/gdcmjpeg/jdatasrc.c new file mode 100644 index 0000000..531c90b --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jdatasrc.c @@ -0,0 +1,213 @@ +/* + * jdatasrc.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains decompression data source routines for the case of + * reading JPEG data from a file (or any stdio stream). While these routines + * are sufficient for most applications, some will want to use a different + * source manager. + * IMPORTANT: we assume that fread() will correctly transcribe an array of + * JOCTETs from 8-bit-wide elements on external storage. If char is wider + * than 8 bits on your machine, you may need to do some tweaking. + */ + +/* this is not a core library module, so it doesn't define JPEG_INTERNALS */ +#include "jinclude.h" +#include "jpeglib.h" +#include "jerror.h" + + +/* Expanded data source object for stdio input */ + +typedef struct { + struct jpeg_source_mgr pub; /* public fields */ + + FILE * infile; /* source stream */ + JOCTET * buffer; /* start of buffer */ + boolean start_of_file; /* have we gotten any data yet? */ +} my_source_mgr; + +typedef my_source_mgr * my_src_ptr; + +#define INPUT_BUF_SIZE 4096 /* choose an efficiently fread'able size */ + + +/* + * Initialize source --- called by jpeg_read_header + * before any data is actually read. + */ + +METHODDEF(void) +init_source (j_decompress_ptr cinfo) +{ + my_src_ptr src = (my_src_ptr) cinfo->src; + + /* We reset the empty-input-file flag for each image, + * but we don't clear the input buffer. + * This is correct behavior for reading a series of images from one source. + */ + src->start_of_file = TRUE; +} + + +/* + * Fill the input buffer --- called whenever buffer is emptied. + * + * In typical applications, this should read fresh data into the buffer + * (ignoring the current state of next_input_byte & bytes_in_buffer), + * reset the pointer & count to the start of the buffer, and return TRUE + * indicating that the buffer has been reloaded. It is not necessary to + * fill the buffer entirely, only to obtain at least one more byte. + * + * There is no such thing as an EOF return. If the end of the file has been + * reached, the routine has a choice of ERREXIT() or inserting fake data into + * the buffer. In most cases, generating a warning message and inserting a + * fake EOI marker is the best course of action --- this will allow the + * decompressor to output however much of the image is there. However, + * the resulting error message is misleading if the real problem is an empty + * input file, so we handle that case specially. + * + * In applications that need to be able to suspend compression due to input + * not being available yet, a FALSE return indicates that no more data can be + * obtained right now, but more may be forthcoming later. In this situation, + * the decompressor will return to its caller (with an indication of the + * number of scanlines it has read, if any). The application should resume + * decompression after it has loaded more data into the input buffer. Note + * that there are substantial restrictions on the use of suspension --- see + * the documentation. + * + * When suspending, the decompressor will back up to a convenient restart point + * (typically the start of the current MCU). next_input_byte & bytes_in_buffer + * indicate where the restart point will be if the current call returns FALSE. + * Data beyond this point must be rescanned after resumption, so move it to + * the front of the buffer rather than discarding it. + */ + +METHODDEF(boolean) +fill_input_buffer (j_decompress_ptr cinfo) +{ + my_src_ptr src = (my_src_ptr) cinfo->src; + size_t nbytes; + + nbytes = JFREAD(src->infile, src->buffer, INPUT_BUF_SIZE); + + if (nbytes <= 0) { + if (src->start_of_file) /* Treat empty input file as fatal error */ + ERREXIT(cinfo, JERR_INPUT_EMPTY); + WARNMS(cinfo, JWRN_JPEG_EOF); + /* Insert a fake EOI marker */ + src->buffer[0] = (JOCTET) 0xFF; + src->buffer[1] = (JOCTET) JPEG_EOI; + nbytes = 2; + } + + src->pub.next_input_byte = src->buffer; + src->pub.bytes_in_buffer = nbytes; + src->start_of_file = FALSE; + + return TRUE; +} + + +/* + * Skip data --- used to skip over a potentially large amount of + * uninteresting data (such as an APPn marker). + * + * Writers of suspendable-input applications must note that skip_input_data + * is not granted the right to give a suspension return. If the skip extends + * beyond the data currently in the buffer, the buffer can be marked empty so + * that the next read will cause a fill_input_buffer call that can suspend. + * Arranging for additional bytes to be discarded before reloading the input + * buffer is the application writer's problem. + */ + +METHODDEF(void) +skip_input_data (j_decompress_ptr cinfo, long num_bytes) +{ + my_src_ptr src = (my_src_ptr) cinfo->src; + + /* Just a dumb implementation for now. Could use fseek() except + * it doesn't work on pipes. Not clear that being smart is worth + * any trouble anyway --- large skips are infrequent. + */ + if (num_bytes > 0) { + while (num_bytes > (long) src->pub.bytes_in_buffer) { + num_bytes -= (long) src->pub.bytes_in_buffer; + (void) fill_input_buffer(cinfo); + /* note we assume that fill_input_buffer will never return FALSE, + * so suspension need not be handled. + */ + } + src->pub.next_input_byte += (size_t) num_bytes; + src->pub.bytes_in_buffer -= (size_t) num_bytes; + } +} + + +/* + * An additional method that can be provided by data source modules is the + * resync_to_restart method for error recovery in the presence of RST markers. + * For the moment, this source module just uses the default resync method + * provided by the JPEG library. That method assumes that no backtracking + * is possible. + */ + + +/* + * Terminate source --- called by jpeg_finish_decompress + * after all data has been read. Often a no-op. + * + * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding + * application must deal with any cleanup that should happen even + * for error exit. + */ + +METHODDEF(void) +term_source (j_decompress_ptr cinfo) +{ + (void)cinfo; + /* no work necessary here */ +} + + +/* + * Prepare for input from a stdio stream. + * The caller must have already opened the stream, and is responsible + * for closing it after finishing decompression. + */ + +GLOBAL(void) +jpeg_stdio_src (j_decompress_ptr cinfo, FILE * infile) +{ + my_src_ptr src; + + /* The source object and input buffer are made permanent so that a series + * of JPEG images can be read from the same file by calling jpeg_stdio_src + * only before the first one. (If we discarded the buffer at the end of + * one image, we'd likely lose the start of the next one.) + * This makes it unsafe to use this manager and a different source + * manager serially with the same JPEG object. Caveat programmer. + */ + if (cinfo->src == NULL) { /* first time for this JPEG object? */ + cinfo->src = (struct jpeg_source_mgr *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + SIZEOF(my_source_mgr)); + src = (my_src_ptr) cinfo->src; + src->buffer = (JOCTET *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + INPUT_BUF_SIZE * SIZEOF(JOCTET)); + } + + src = (my_src_ptr) cinfo->src; + src->pub.init_source = init_source; + src->pub.fill_input_buffer = fill_input_buffer; + src->pub.skip_input_data = skip_input_data; + src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ + src->pub.term_source = term_source; + src->infile = infile; + src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ + src->pub.next_input_byte = NULL; /* until buffer loaded */ +} diff --git a/gdcm/Utilities/gdcmjpeg/jdcoefct.c b/gdcm/Utilities/gdcmjpeg/jdcoefct.c new file mode 100644 index 0000000..2e5ec11 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jdcoefct.c @@ -0,0 +1,744 @@ +/* + * jdcoefct.c + * + * Copyright (C) 1994-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the coefficient buffer controller for decompression. + * This controller is the top level of the lossy JPEG decompressor proper. + * The coefficient buffer lies between entropy decoding and inverse-DCT steps. + * + * In buffered-image mode, this controller is the interface between + * input-oriented processing and output-oriented processing. + * Also, the input side (only) is used when reading a file for transcoding. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jlossy.h" + +/* Block smoothing is only applicable for progressive JPEG, so: */ +#ifndef D_PROGRESSIVE_SUPPORTED +#undef BLOCK_SMOOTHING_SUPPORTED +#endif + +/* Private buffer controller object */ + +typedef struct { + /* These variables keep track of the current location of the input side. */ + /* cinfo->input_iMCU_row is also used for this. */ + JDIMENSION MCU_ctr; /* counts MCUs processed in current row */ + int MCU_vert_offset; /* counts MCU rows within iMCU row */ + int MCU_rows_per_iMCU_row; /* number of such rows needed */ + + /* The output side's location is represented by cinfo->output_iMCU_row. */ + + /* In single-pass modes, it's sufficient to buffer just one MCU. + * We allocate a workspace of D_MAX_DATA_UNITS_IN_MCU coefficient blocks, + * and let the entropy decoder write into that workspace each time. + * (On 80x86, the workspace is FAR even though it's not really very big; + * this is to keep the module interfaces unchanged when a large coefficient + * buffer is necessary.) + * In multi-pass modes, this array points to the current MCU's blocks + * within the virtual arrays; it is used only by the input side. + */ + JBLOCKROW MCU_buffer[D_MAX_DATA_UNITS_IN_MCU]; + +#ifdef D_MULTISCAN_FILES_SUPPORTED + /* In multi-pass modes, we need a virtual block array for each component. */ + jvirt_barray_ptr whole_image[MAX_COMPONENTS]; +#endif + +#ifdef BLOCK_SMOOTHING_SUPPORTED + /* When doing block smoothing, we latch coefficient Al values here */ + int * coef_bits_latch; +#define SAVED_COEFS 6 /* we save coef_bits[0..5] */ +#endif +} d_coef_controller; + +typedef d_coef_controller * d_coef_ptr; + +/* Forward declarations */ +METHODDEF(int) decompress_onepass + JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf)); +#ifdef D_MULTISCAN_FILES_SUPPORTED +METHODDEF(int) decompress_data + JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf)); +#endif +#ifdef BLOCK_SMOOTHING_SUPPORTED +LOCAL(boolean) smoothing_ok JPP((j_decompress_ptr cinfo)); +METHODDEF(int) decompress_smooth_data + JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf)); +#endif + + +LOCAL(void) +start_iMCU_row (j_decompress_ptr cinfo) +/* Reset within-iMCU-row counters for a new row (input side) */ +{ + j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; + d_coef_ptr coef = (d_coef_ptr) lossyd->coef_private; + + /* In an interleaved scan, an MCU row is the same as an iMCU row. + * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows. + * But at the bottom of the image, process only what's left. + */ + if (cinfo->comps_in_scan > 1) { + coef->MCU_rows_per_iMCU_row = 1; + } else { + if (cinfo->input_iMCU_row < (cinfo->total_iMCU_rows-1)) + coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor; + else + coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height; + } + + coef->MCU_ctr = 0; + coef->MCU_vert_offset = 0; +} + + +/* + * Initialize for an input processing pass. + */ + +METHODDEF(void) +start_input_pass (j_decompress_ptr cinfo) +{ + cinfo->input_iMCU_row = 0; + start_iMCU_row(cinfo); +} + + +/* + * Initialize for an output processing pass. + */ + +METHODDEF(void) +start_output_pass (j_decompress_ptr cinfo) +{ +#ifdef BLOCK_SMOOTHING_SUPPORTED + j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; + /* d_coef_ptr coef = (d_coef_ptr) lossyd->coef_private; */ + + /* If multipass, check to see whether to use block smoothing on this pass */ + if (lossyd->coef_arrays != NULL) { + if (cinfo->do_block_smoothing && smoothing_ok(cinfo)) + lossyd->pub.decompress_data = decompress_smooth_data; + else + lossyd->pub.decompress_data = decompress_data; + } +#endif + cinfo->output_iMCU_row = 0; +} + + +/* + * Decompress and return some data in the single-pass case. + * Always attempts to emit one fully interleaved MCU row ("iMCU" row). + * Input and output must run in lockstep since we have only a one-MCU buffer. + * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED. + * + * NB: output_buf contains a plane for each component in image, + * which we index according to the component's SOF position. + */ + +METHODDEF(int) +decompress_onepass (j_decompress_ptr cinfo, JSAMPIMAGE output_buf) +{ + j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; + d_coef_ptr coef = (d_coef_ptr) lossyd->coef_private; + JDIMENSION MCU_col_num; /* index of current MCU within row */ + JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1; + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + int blkn, ci, xindex, yindex, yoffset, useful_width; + JSAMPARRAY output_ptr; + JDIMENSION start_col, output_col; + jpeg_component_info *compptr; + inverse_DCT_method_ptr inverse_DCT; + + /* Loop to process as much as one whole iMCU row */ + for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row; + yoffset++) { + for (MCU_col_num = coef->MCU_ctr; MCU_col_num <= last_MCU_col; + MCU_col_num++) { + /* Try to fetch an MCU. Entropy decoder expects buffer to be zeroed. */ + jzero_far((void FAR *) coef->MCU_buffer[0], + (size_t) (cinfo->data_units_in_MCU * SIZEOF(JBLOCK))); + if (! (*lossyd->entropy_decode_mcu) (cinfo, coef->MCU_buffer)) { + /* Suspension forced; update state counters and exit */ + coef->MCU_vert_offset = yoffset; + coef->MCU_ctr = MCU_col_num; + return JPEG_SUSPENDED; + } + /* Determine where data should go in output_buf and do the IDCT thing. + * We skip dummy blocks at the right and bottom edges (but blkn gets + * incremented past them!). Note the inner loop relies on having + * allocated the MCU_buffer[] blocks sequentially. + */ + blkn = 0; /* index of current DCT block within MCU */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* Don't bother to IDCT an uninteresting component. */ + if (! compptr->component_needed) { + blkn += compptr->MCU_data_units; + continue; + } + inverse_DCT = lossyd->inverse_DCT[compptr->component_index]; + useful_width = (MCU_col_num < last_MCU_col) ? compptr->MCU_width + : compptr->last_col_width; + output_ptr = output_buf[compptr->component_index] + + yoffset * compptr->codec_data_unit; + start_col = MCU_col_num * compptr->MCU_sample_width; + for (yindex = 0; yindex < compptr->MCU_height; yindex++) { + if (cinfo->input_iMCU_row < last_iMCU_row || + yoffset+yindex < compptr->last_row_height) { + output_col = start_col; + for (xindex = 0; xindex < useful_width; xindex++) { + (*inverse_DCT) (cinfo, compptr, + (JCOEFPTR) coef->MCU_buffer[blkn+xindex], + output_ptr, output_col); + output_col += compptr->codec_data_unit; + } + } + blkn += compptr->MCU_width; + output_ptr += compptr->codec_data_unit; + } + } + } + /* Completed an MCU row, but perhaps not an iMCU row */ + coef->MCU_ctr = 0; + } + /* Completed the iMCU row, advance counters for next one */ + cinfo->output_iMCU_row++; + if (++(cinfo->input_iMCU_row) < cinfo->total_iMCU_rows) { + start_iMCU_row(cinfo); + return JPEG_ROW_COMPLETED; + } + /* Completed the scan */ + (*cinfo->inputctl->finish_input_pass) (cinfo); + return JPEG_SCAN_COMPLETED; +} + + +/* + * Dummy consume-input routine for single-pass operation. + */ + +METHODDEF(int) +dummy_consume_data (j_decompress_ptr cinfo) +{ + (void)cinfo; + return JPEG_SUSPENDED; /* Always indicate nothing was done */ +} + + +#ifdef D_MULTISCAN_FILES_SUPPORTED + +/* + * Consume input data and store it in the full-image coefficient buffer. + * We read as much as one fully interleaved MCU row ("iMCU" row) per call, + * ie, v_samp_factor block rows for each component in the scan. + * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED. + */ + +METHODDEF(int) +consume_data (j_decompress_ptr cinfo) +{ + j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; + d_coef_ptr coef = (d_coef_ptr) lossyd->coef_private; + JDIMENSION MCU_col_num; /* index of current MCU within row */ + int blkn, ci, xindex, yindex, yoffset; + JDIMENSION start_col; + JBLOCKARRAY buffer[MAX_COMPS_IN_SCAN]; + JBLOCKROW buffer_ptr; + jpeg_component_info *compptr; + + /* Align the virtual buffers for the components used in this scan. */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + buffer[ci] = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef->whole_image[compptr->component_index], + cinfo->input_iMCU_row * compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, TRUE); + /* Note: entropy decoder expects buffer to be zeroed, + * but this is handled automatically by the memory manager + * because we requested a pre-zeroed array. + */ + } + + /* Loop to process one whole iMCU row */ + for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row; + yoffset++) { + for (MCU_col_num = coef->MCU_ctr; MCU_col_num < cinfo->MCUs_per_row; + MCU_col_num++) { + /* Construct list of pointers to DCT blocks belonging to this MCU */ + blkn = 0; /* index of current DCT block within MCU */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + start_col = MCU_col_num * compptr->MCU_width; + for (yindex = 0; yindex < compptr->MCU_height; yindex++) { + buffer_ptr = buffer[ci][yindex+yoffset] + start_col; + for (xindex = 0; xindex < compptr->MCU_width; xindex++) { + coef->MCU_buffer[blkn++] = buffer_ptr++; + } + } + } + /* Try to fetch the MCU. */ + if (! (*lossyd->entropy_decode_mcu) (cinfo, coef->MCU_buffer)) { + /* Suspension forced; update state counters and exit */ + coef->MCU_vert_offset = yoffset; + coef->MCU_ctr = MCU_col_num; + return JPEG_SUSPENDED; + } + } + /* Completed an MCU row, but perhaps not an iMCU row */ + coef->MCU_ctr = 0; + } + /* Completed the iMCU row, advance counters for next one */ + if (++(cinfo->input_iMCU_row) < cinfo->total_iMCU_rows) { + start_iMCU_row(cinfo); + return JPEG_ROW_COMPLETED; + } + /* Completed the scan */ + (*cinfo->inputctl->finish_input_pass) (cinfo); + return JPEG_SCAN_COMPLETED; +} + + +/* + * Decompress and return some data in the multi-pass case. + * Always attempts to emit one fully interleaved MCU row ("iMCU" row). + * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED. + * + * NB: output_buf contains a plane for each component in image. + */ + +METHODDEF(int) +decompress_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf) +{ + j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; + d_coef_ptr coef = (d_coef_ptr) lossyd->coef_private; + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + JDIMENSION block_num; + int ci, block_row, block_rows; + JBLOCKARRAY buffer; + JBLOCKROW buffer_ptr; + JSAMPARRAY output_ptr; + JDIMENSION output_col; + jpeg_component_info *compptr; + inverse_DCT_method_ptr inverse_DCT; + + /* Force some input to be done if we are getting ahead of the input. */ + while (cinfo->input_scan_number < cinfo->output_scan_number || + (cinfo->input_scan_number == cinfo->output_scan_number && + cinfo->input_iMCU_row <= cinfo->output_iMCU_row)) { + if ((*cinfo->inputctl->consume_input)(cinfo) == JPEG_SUSPENDED) + return JPEG_SUSPENDED; + } + + /* OK, output from the virtual arrays. */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Don't bother to IDCT an uninteresting component. */ + if (! compptr->component_needed) + continue; + /* Align the virtual buffer for this component. */ + buffer = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef->whole_image[ci], + cinfo->output_iMCU_row * compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, FALSE); + /* Count non-dummy DCT block rows in this iMCU row. */ + if (cinfo->output_iMCU_row < last_iMCU_row) + block_rows = compptr->v_samp_factor; + else { + /* NB: can't use last_row_height here; it is input-side-dependent! */ + block_rows = (int) (compptr->height_in_data_units % compptr->v_samp_factor); + if (block_rows == 0) block_rows = compptr->v_samp_factor; + } + inverse_DCT = lossyd->inverse_DCT[ci]; + output_ptr = output_buf[ci]; + /* Loop over all DCT blocks to be processed. */ + for (block_row = 0; block_row < block_rows; block_row++) { + buffer_ptr = buffer[block_row]; + output_col = 0; + for (block_num = 0; block_num < compptr->width_in_data_units; block_num++) { + (*inverse_DCT) (cinfo, compptr, (JCOEFPTR) buffer_ptr, + output_ptr, output_col); + buffer_ptr++; + output_col += compptr->codec_data_unit; + } + output_ptr += compptr->codec_data_unit; + } + } + + if (++(cinfo->output_iMCU_row) < cinfo->total_iMCU_rows) + return JPEG_ROW_COMPLETED; + return JPEG_SCAN_COMPLETED; +} + +#endif /* D_MULTISCAN_FILES_SUPPORTED */ + + +#ifdef BLOCK_SMOOTHING_SUPPORTED + +/* + * This code applies interblock smoothing as described by section K.8 + * of the JPEG standard: the first 5 AC coefficients are estimated from + * the DC values of a DCT block and its 8 neighboring blocks. + * We apply smoothing only for progressive JPEG decoding, and only if + * the coefficients it can estimate are not yet known to full precision. + */ + +/* Natural-order array positions of the first 5 zigzag-order coefficients */ +#define Q01_POS 1 +#define Q10_POS 8 +#define Q20_POS 16 +#define Q11_POS 9 +#define Q02_POS 2 + +/* + * Determine whether block smoothing is applicable and safe. + * We also latch the current states of the coef_bits[] entries for the + * AC coefficients; otherwise, if the input side of the decompressor + * advances into a new scan, we might think the coefficients are known + * more accurately than they really are. + */ + +LOCAL(boolean) +smoothing_ok (j_decompress_ptr cinfo) +{ + j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; + d_coef_ptr coef = (d_coef_ptr) lossyd->coef_private; + boolean smoothing_useful = FALSE; + int ci, coefi; + jpeg_component_info *compptr; + JQUANT_TBL * qtable; + int * coef_bits; + int * coef_bits_latch; + + if (! cinfo->process == JPROC_PROGRESSIVE || cinfo->coef_bits == NULL) + return FALSE; + + /* Allocate latch area if not already done */ + if (coef->coef_bits_latch == NULL) + coef->coef_bits_latch = (int *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + cinfo->num_components * + (SAVED_COEFS * SIZEOF(int))); + coef_bits_latch = coef->coef_bits_latch; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* All components' quantization values must already be latched. */ + if ((qtable = compptr->quant_table) == NULL) + return FALSE; + /* Verify DC & first 5 AC quantizers are nonzero to avoid zero-divide. */ + if (qtable->quantval[0] == 0 || + qtable->quantval[Q01_POS] == 0 || + qtable->quantval[Q10_POS] == 0 || + qtable->quantval[Q20_POS] == 0 || + qtable->quantval[Q11_POS] == 0 || + qtable->quantval[Q02_POS] == 0) + return FALSE; + /* DC values must be at least partly known for all components. */ + coef_bits = cinfo->coef_bits[ci]; + if (coef_bits[0] < 0) + return FALSE; + /* Block smoothing is helpful if some AC coefficients remain inaccurate. */ + for (coefi = 1; coefi <= 5; coefi++) { + coef_bits_latch[coefi] = coef_bits[coefi]; + if (coef_bits[coefi] != 0) + smoothing_useful = TRUE; + } + coef_bits_latch += SAVED_COEFS; + } + + return smoothing_useful; +} + + +/* + * Variant of decompress_data for use when doing block smoothing. + */ + +METHODDEF(int) +decompress_smooth_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf) +{ + j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; + d_coef_ptr coef = (d_coef_ptr) lossyd->coef_private; + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + JDIMENSION block_num, last_block_column; + int ci, block_row, block_rows, access_rows; + JBLOCKARRAY buffer; + JBLOCKROW buffer_ptr, prev_block_row, next_block_row; + JSAMPARRAY output_ptr; + JDIMENSION output_col; + jpeg_component_info *compptr; + inverse_DCT_method_ptr inverse_DCT; + boolean first_row, last_row; + JBLOCK workspace; + int *coef_bits; + JQUANT_TBL *quanttbl; + INT32 Q00,Q01,Q02,Q10,Q11,Q20, num; + int DC1,DC2,DC3,DC4,DC5,DC6,DC7,DC8,DC9; + int Al, pred; + + /* Force some input to be done if we are getting ahead of the input. */ + while (cinfo->input_scan_number <= cinfo->output_scan_number && + ! cinfo->inputctl->eoi_reached) { + if (cinfo->input_scan_number == cinfo->output_scan_number) { + /* If input is working on current scan, we ordinarily want it to + * have completed the current row. But if input scan is DC, + * we want it to keep one row ahead so that next block row's DC + * values are up to date. + */ + JDIMENSION delta = (cinfo->Ss == 0) ? 1 : 0; + if (cinfo->input_iMCU_row > cinfo->output_iMCU_row+delta) + break; + } + if ((*cinfo->inputctl->consume_input)(cinfo) == JPEG_SUSPENDED) + return JPEG_SUSPENDED; + } + + /* OK, output from the virtual arrays. */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Don't bother to IDCT an uninteresting component. */ + if (! compptr->component_needed) + continue; + /* Count non-dummy DCT block rows in this iMCU row. */ + if (cinfo->output_iMCU_row < last_iMCU_row) { + block_rows = compptr->v_samp_factor; + access_rows = block_rows * 2; /* this and next iMCU row */ + last_row = FALSE; + } else { + /* NB: can't use last_row_height here; it is input-side-dependent! */ + block_rows = (int) (compptr->height_in_data_units % compptr->v_samp_factor); + if (block_rows == 0) block_rows = compptr->v_samp_factor; + access_rows = block_rows; /* this iMCU row only */ + last_row = TRUE; + } + /* Align the virtual buffer for this component. */ + if (cinfo->output_iMCU_row > 0) { + access_rows += compptr->v_samp_factor; /* prior iMCU row too */ + buffer = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef->whole_image[ci], + (cinfo->output_iMCU_row - 1) * compptr->v_samp_factor, + (JDIMENSION) access_rows, FALSE); + buffer += compptr->v_samp_factor; /* point to current iMCU row */ + first_row = FALSE; + } else { + buffer = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef->whole_image[ci], + (JDIMENSION) 0, (JDIMENSION) access_rows, FALSE); + first_row = TRUE; + } + /* Fetch component-dependent info */ + coef_bits = coef->coef_bits_latch + (ci * SAVED_COEFS); + quanttbl = compptr->quant_table; + Q00 = quanttbl->quantval[0]; + Q01 = quanttbl->quantval[Q01_POS]; + Q10 = quanttbl->quantval[Q10_POS]; + Q20 = quanttbl->quantval[Q20_POS]; + Q11 = quanttbl->quantval[Q11_POS]; + Q02 = quanttbl->quantval[Q02_POS]; + inverse_DCT = lossyd->inverse_DCT[ci]; + output_ptr = output_buf[ci]; + /* Loop over all DCT blocks to be processed. */ + for (block_row = 0; block_row < block_rows; block_row++) { + buffer_ptr = buffer[block_row]; + if (first_row && block_row == 0) + prev_block_row = buffer_ptr; + else + prev_block_row = buffer[block_row-1]; + if (last_row && block_row == block_rows-1) + next_block_row = buffer_ptr; + else + next_block_row = buffer[block_row+1]; + /* We fetch the surrounding DC values using a sliding-register approach. + * Initialize all nine here so as to do the right thing on narrow pics. + */ + DC1 = DC2 = DC3 = (int) prev_block_row[0][0]; + DC4 = DC5 = DC6 = (int) buffer_ptr[0][0]; + DC7 = DC8 = DC9 = (int) next_block_row[0][0]; + output_col = 0; + last_block_column = compptr->width_in_data_units - 1; + for (block_num = 0; block_num <= last_block_column; block_num++) { + /* Fetch current DCT block into workspace so we can modify it. */ + jcopy_block_row(buffer_ptr, (JBLOCKROW) workspace, (JDIMENSION) 1); + /* Update DC values */ + if (block_num < last_block_column) { + DC3 = (int) prev_block_row[1][0]; + DC6 = (int) buffer_ptr[1][0]; + DC9 = (int) next_block_row[1][0]; + } + /* Compute coefficient estimates per K.8. + * An estimate is applied only if coefficient is still zero, + * and is not known to be fully accurate. + */ + /* AC01 */ + if ((Al=coef_bits[1]) != 0 && workspace[1] == 0) { + num = 36 * Q00 * (DC4 - DC6); + if (num >= 0) { + pred = (int) (((Q01<<7) + num) / (Q01<<8)); + if (Al > 0 && pred >= (1< 0 && pred >= (1<= 0) { + pred = (int) (((Q10<<7) + num) / (Q10<<8)); + if (Al > 0 && pred >= (1< 0 && pred >= (1<= 0) { + pred = (int) (((Q20<<7) + num) / (Q20<<8)); + if (Al > 0 && pred >= (1< 0 && pred >= (1<= 0) { + pred = (int) (((Q11<<7) + num) / (Q11<<8)); + if (Al > 0 && pred >= (1< 0 && pred >= (1<= 0) { + pred = (int) (((Q02<<7) + num) / (Q02<<8)); + if (Al > 0 && pred >= (1< 0 && pred >= (1<codec_data_unit; + } + output_ptr += compptr->codec_data_unit; + } + } + + if (++(cinfo->output_iMCU_row) < cinfo->total_iMCU_rows) + return JPEG_ROW_COMPLETED; + return JPEG_SCAN_COMPLETED; +} + +#endif /* BLOCK_SMOOTHING_SUPPORTED */ + + +/* + * Initialize coefficient buffer controller. + */ + +GLOBAL(void) +jinit_d_coef_controller (j_decompress_ptr cinfo, boolean need_full_buffer) +{ + j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; + d_coef_ptr coef; + + coef = (d_coef_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(d_coef_controller)); + lossyd->coef_private = (void *) coef; + lossyd->coef_start_input_pass = start_input_pass; + lossyd->coef_start_output_pass = start_output_pass; +#ifdef BLOCK_SMOOTHING_SUPPORTED + coef->coef_bits_latch = NULL; +#endif + + /* Create the coefficient buffer. */ + if (need_full_buffer) { +#ifdef D_MULTISCAN_FILES_SUPPORTED + /* Allocate a full-image virtual array for each component, */ + /* padded to a multiple of samp_factor DCT blocks in each direction. */ + /* Note we ask for a pre-zeroed array. */ + int ci, access_rows; + jpeg_component_info *compptr; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + access_rows = compptr->v_samp_factor; +#ifdef BLOCK_SMOOTHING_SUPPORTED + /* If block smoothing could be used, need a bigger window */ + if (cinfo->process == JPROC_PROGRESSIVE) + access_rows *= 3; +#endif + coef->whole_image[ci] = (*cinfo->mem->request_virt_barray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, TRUE, + (JDIMENSION) jround_up((long) compptr->width_in_data_units, + (long) compptr->h_samp_factor), + (JDIMENSION) jround_up((long) compptr->height_in_data_units, + (long) compptr->v_samp_factor), + (JDIMENSION) access_rows); + } + lossyd->pub.consume_data = consume_data; + lossyd->pub.decompress_data = decompress_data; + lossyd->coef_arrays = coef->whole_image; /* link to virtual arrays */ +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else { + /* We only need a single-MCU buffer. */ + JBLOCKROW buffer; + int i; + + buffer = (JBLOCKROW) + (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE, + D_MAX_DATA_UNITS_IN_MCU * SIZEOF(JBLOCK)); + for (i = 0; i < D_MAX_DATA_UNITS_IN_MCU; i++) { + coef->MCU_buffer[i] = buffer + i; + } + lossyd->pub.consume_data = dummy_consume_data; + lossyd->pub.decompress_data = decompress_onepass; + lossyd->coef_arrays = NULL; /* flag for no virtual arrays */ + } +} diff --git a/gdcm/Utilities/gdcmjpeg/jdcolor.c b/gdcm/Utilities/gdcmjpeg/jdcolor.c new file mode 100644 index 0000000..7b0aa3d --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jdcolor.c @@ -0,0 +1,414 @@ +/* + * jdcolor.c + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains output colorspace conversion routines. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Private subobject */ + +typedef struct { + struct jpeg_color_deconverter pub; /* public fields */ + + /* Private state for YCC->RGB conversion */ + int * Cr_r_tab; /* => table for Cr to R conversion */ + int * Cb_b_tab; /* => table for Cb to B conversion */ + INT32 * Cr_g_tab; /* => table for Cr to G conversion */ + INT32 * Cb_g_tab; /* => table for Cb to G conversion */ +} my_color_deconverter; + +typedef my_color_deconverter * my_cconvert_ptr; + + +/**************** YCbCr -> RGB conversion: most common case **************/ + +/* + * YCbCr is defined per CCIR 601-1, except that Cb and Cr are + * normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5. + * The conversion equations to be implemented are therefore + * R = Y + 1.40200 * Cr + * G = Y - 0.34414 * Cb - 0.71414 * Cr + * B = Y + 1.77200 * Cb + * where Cb and Cr represent the incoming values less CENTERJSAMPLE. + * (These numbers are derived from TIFF 6.0 section 21, dated 3-June-92.) + * + * To avoid floating-point arithmetic, we represent the fractional constants + * as integers scaled up by 2^16 (about 4 digits precision); we have to divide + * the products by 2^16, with appropriate rounding, to get the correct answer. + * Notice that Y, being an integral input, does not contribute any fraction + * so it need not participate in the rounding. + * + * For even more speed, we avoid doing any multiplications in the inner loop + * by precalculating the constants times Cb and Cr for all possible values. + * For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table); + * for 12-bit samples it is still acceptable. It's not very reasonable for + * 16-bit samples, but if you want lossless storage you shouldn't be changing + * colorspace anyway. + * The Cr=>R and Cb=>B values can be rounded to integers in advance; the + * values for the G calculation are left scaled up, since we must add them + * together before rounding. + */ + +#define SCALEBITS 16 /* speediest right-shift on some machines */ +#define ONE_HALF ((INT32) 1 << (SCALEBITS-1)) +#define FIX(x) ((INT32) ((x) * (1L<RGB colorspace conversion. + */ + +LOCAL(void) +build_ycc_rgb_table (j_decompress_ptr cinfo) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + int i; + INT32 x; +#if BITS_IN_JSAMPLE == 16 + /* no need for temporaries */ +#else + SHIFT_TEMPS +#endif + + cconvert->Cr_r_tab = (int *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (MAXJSAMPLE+1) * SIZEOF(int)); + cconvert->Cb_b_tab = (int *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (MAXJSAMPLE+1) * SIZEOF(int)); + cconvert->Cr_g_tab = (INT32 *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (MAXJSAMPLE+1) * SIZEOF(INT32)); + cconvert->Cb_g_tab = (INT32 *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (MAXJSAMPLE+1) * SIZEOF(INT32)); + + for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) { + /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */ + /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */ + +#if BITS_IN_JSAMPLE == 16 + /* Bug fix 2001-11-06 by Eichelberg: The integer routines below + produce an overflow when used with MAXJSAMPLE == 65535. + Use floating point calculation instead. */ + + /* Cr=>R value is nearest int to 1.40200 * x */ + cconvert->Cr_r_tab[i] = (int)(1.40200 * (double)x + 0.5); + /* Cb=>B value is nearest int to 1.77200 * x */ + cconvert->Cb_b_tab[i] = (int)(1.77200 * (double)x + 0.5); +#else + /* Cr=>R value is nearest int to 1.40200 * x */ + cconvert->Cr_r_tab[i] = (int) + RIGHT_SHIFT(FIX(1.40200) * x + ONE_HALF, SCALEBITS); + /* Cb=>B value is nearest int to 1.77200 * x */ + cconvert->Cb_b_tab[i] = (int) + RIGHT_SHIFT(FIX(1.77200) * x + ONE_HALF, SCALEBITS); +#endif + + /* Cr=>G value is scaled-up -0.71414 * x */ + cconvert->Cr_g_tab[i] = (- FIX(0.71414)) * x; + /* Cb=>G value is scaled-up -0.34414 * x */ + /* We also add in ONE_HALF so that need not do it in inner loop */ + cconvert->Cb_g_tab[i] = (- FIX(0.34414)) * x + ONE_HALF; + } +} + + +/* + * Convert some rows of samples to the output colorspace. + * + * Note that we change from noninterleaved, one-plane-per-component format + * to interleaved-pixel format. The output buffer is therefore three times + * as wide as the input buffer. + * A starting row offset is provided only for the input buffer. The caller + * can easily adjust the passed output_buf value to accommodate any row + * offset required on that side. + */ + +METHODDEF(void) +ycc_rgb_convert (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + register int y, cb, cr; + register JSAMPROW outptr; + register JSAMPROW inptr0, inptr1, inptr2; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->output_width; + /* copy these pointers into registers if possible */ + register JSAMPLE * range_limit = cinfo->sample_range_limit; + register int * Crrtab = cconvert->Cr_r_tab; + register int * Cbbtab = cconvert->Cb_b_tab; + register INT32 * Crgtab = cconvert->Cr_g_tab; + register INT32 * Cbgtab = cconvert->Cb_g_tab; + SHIFT_TEMPS + + while (--num_rows >= 0) { + inptr0 = input_buf[0][input_row]; + inptr1 = input_buf[1][input_row]; + inptr2 = input_buf[2][input_row]; + input_row++; + outptr = *output_buf++; + for (col = 0; col < num_cols; col++) { + y = GETJSAMPLE(inptr0[col]); + cb = GETJSAMPLE(inptr1[col]); + cr = GETJSAMPLE(inptr2[col]); + /* Range-limiting is essential due to noise introduced by DCT losses. */ + outptr[RGB_RED] = range_limit[y + Crrtab[cr]]; + outptr[RGB_GREEN] = range_limit[y + + ((int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], + SCALEBITS))]; + outptr[RGB_BLUE] = range_limit[y + Cbbtab[cb]]; + outptr += RGB_PIXELSIZE; + } + } +} + + +/**************** Cases other than YCbCr -> RGB **************/ + + +/* + * Color conversion for no colorspace change: just copy the data, + * converting from separate-planes to interleaved representation. + */ + +METHODDEF(void) +null_convert (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows) +{ + register JSAMPROW inptr, outptr; + register JDIMENSION count; + register int num_components = cinfo->num_components; + JDIMENSION num_cols = cinfo->output_width; + int ci; + + while (--num_rows >= 0) { + for (ci = 0; ci < num_components; ci++) { + inptr = input_buf[ci][input_row]; + outptr = output_buf[0] + ci; + for (count = num_cols; count > 0; count--) { + *outptr = *inptr++; /* needn't bother with GETJSAMPLE() here */ + outptr += num_components; + } + } + input_row++; + output_buf++; + } +} + + +/* + * Color conversion for grayscale: just copy the data. + * This also works for YCbCr -> grayscale conversion, in which + * we just copy the Y (luminance) component and ignore chrominance. + */ + +METHODDEF(void) +grayscale_convert (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows) +{ + jcopy_sample_rows(input_buf[0], (int) input_row, output_buf, 0, + num_rows, cinfo->output_width); +} + + +/* + * Convert grayscale to RGB: just duplicate the graylevel three times. + * This is provided to support applications that don't want to cope + * with grayscale as a separate case. + */ + +METHODDEF(void) +gray_rgb_convert (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows) +{ + register JSAMPROW inptr, outptr; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->output_width; + + while (--num_rows >= 0) { + inptr = input_buf[0][input_row++]; + outptr = *output_buf++; + for (col = 0; col < num_cols; col++) { + /* We can dispense with GETJSAMPLE() here */ + outptr[RGB_RED] = outptr[RGB_GREEN] = outptr[RGB_BLUE] = inptr[col]; + outptr += RGB_PIXELSIZE; + } + } +} + + +/* + * Adobe-style YCCK->CMYK conversion. + * We convert YCbCr to R=1-C, G=1-M, and B=1-Y using the same + * conversion as above, while passing K (black) unchanged. + * We assume build_ycc_rgb_table has been called. + */ + +METHODDEF(void) +ycck_cmyk_convert (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + register int y, cb, cr; + register JSAMPROW outptr; + register JSAMPROW inptr0, inptr1, inptr2, inptr3; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->output_width; + /* copy these pointers into registers if possible */ + register JSAMPLE * range_limit = cinfo->sample_range_limit; + register int * Crrtab = cconvert->Cr_r_tab; + register int * Cbbtab = cconvert->Cb_b_tab; + register INT32 * Crgtab = cconvert->Cr_g_tab; + register INT32 * Cbgtab = cconvert->Cb_g_tab; + SHIFT_TEMPS + + while (--num_rows >= 0) { + inptr0 = input_buf[0][input_row]; + inptr1 = input_buf[1][input_row]; + inptr2 = input_buf[2][input_row]; + inptr3 = input_buf[3][input_row]; + input_row++; + outptr = *output_buf++; + for (col = 0; col < num_cols; col++) { + y = GETJSAMPLE(inptr0[col]); + cb = GETJSAMPLE(inptr1[col]); + cr = GETJSAMPLE(inptr2[col]); + /* Range-limiting is essential due to noise introduced by DCT losses. */ + outptr[0] = range_limit[MAXJSAMPLE - (y + Crrtab[cr])]; /* red */ + outptr[1] = range_limit[MAXJSAMPLE - (y + /* green */ + ((int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], + SCALEBITS)))]; + outptr[2] = range_limit[MAXJSAMPLE - (y + Cbbtab[cb])]; /* blue */ + /* K passes through unchanged */ + outptr[3] = inptr3[col]; /* don't need GETJSAMPLE here */ + outptr += 4; + } + } +} + + +/* + * Empty method for start_pass. + */ + +METHODDEF(void) +start_pass_dcolor (j_decompress_ptr cinfo) +{ + (void)cinfo; + /* no work needed */ +} + + +/* + * Module initialization routine for output colorspace conversion. + */ + +GLOBAL(void) +jinit_color_deconverter (j_decompress_ptr cinfo) +{ + my_cconvert_ptr cconvert; + int ci; + + cconvert = (my_cconvert_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_color_deconverter)); + cinfo->cconvert = (struct jpeg_color_deconverter *) cconvert; + cconvert->pub.start_pass = start_pass_dcolor; + + /* Make sure num_components agrees with jpeg_color_space */ + switch (cinfo->jpeg_color_space) { + case JCS_GRAYSCALE: + if (cinfo->num_components != 1) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + break; + + case JCS_RGB: + case JCS_YCbCr: + if (cinfo->num_components != 3) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + break; + + case JCS_CMYK: + case JCS_YCCK: + if (cinfo->num_components != 4) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + break; + + default: /* JCS_UNKNOWN can be anything */ + if (cinfo->num_components < 1) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + break; + } + + /* Set out_color_components and conversion method based on requested space. + * Also clear the component_needed flags for any unused components, + * so that earlier pipeline stages can avoid useless computation. + */ + + switch (cinfo->out_color_space) { + case JCS_GRAYSCALE: + cinfo->out_color_components = 1; + if (cinfo->jpeg_color_space == JCS_GRAYSCALE || + cinfo->jpeg_color_space == JCS_YCbCr) { + cconvert->pub.color_convert = grayscale_convert; + /* For color->grayscale conversion, only the Y (0) component is needed */ + for (ci = 1; ci < cinfo->num_components; ci++) + cinfo->comp_info[ci].component_needed = FALSE; + } else + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + + case JCS_RGB: + cinfo->out_color_components = RGB_PIXELSIZE; + if (cinfo->jpeg_color_space == JCS_YCbCr) { + cconvert->pub.color_convert = ycc_rgb_convert; + build_ycc_rgb_table(cinfo); + } else if (cinfo->jpeg_color_space == JCS_GRAYSCALE) { + cconvert->pub.color_convert = gray_rgb_convert; + } else if (cinfo->jpeg_color_space == JCS_RGB && RGB_PIXELSIZE == 3) { + cconvert->pub.color_convert = null_convert; + } else + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + + case JCS_CMYK: + cinfo->out_color_components = 4; + if (cinfo->jpeg_color_space == JCS_YCCK) { + cconvert->pub.color_convert = ycck_cmyk_convert; + build_ycc_rgb_table(cinfo); + } else if (cinfo->jpeg_color_space == JCS_CMYK) { + cconvert->pub.color_convert = null_convert; + } else + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + + default: + /* Permit null conversion to same output space */ + if (cinfo->out_color_space == cinfo->jpeg_color_space) { + cinfo->out_color_components = cinfo->num_components; + cconvert->pub.color_convert = null_convert; + } else /* unsupported non-null conversion */ + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + } + + if (cinfo->quantize_colors) + cinfo->output_components = 1; /* single colormapped output component */ + else + cinfo->output_components = cinfo->out_color_components; +} diff --git a/gdcm/Utilities/gdcmjpeg/jdct.h b/gdcm/Utilities/gdcmjpeg/jdct.h new file mode 100644 index 0000000..d553da6 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jdct.h @@ -0,0 +1,176 @@ +/* + * jdct.h + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This include file contains common declarations for the forward and + * inverse DCT modules. These declarations are private to the DCT managers + * (jcdctmgr.c, jddctmgr.c) and the individual DCT algorithms. + * The individual DCT algorithms are kept in separate files to ease + * machine-dependent tuning (e.g., assembly coding). + */ + + +/* + * A forward DCT routine is given a pointer to a work area of type DCTELEM[]; + * the DCT is to be performed in-place in that buffer. Type DCTELEM is int + * for 8-bit samples, INT32 for 12-bit samples. (NOTE: Floating-point DCT + * implementations use an array of type FAST_FLOAT, instead.) + * The DCT inputs are expected to be signed (range +-CENTERJSAMPLE). + * The DCT outputs are returned scaled up by a factor of 8; they therefore + * have a range of +-8K for 8-bit data, +-128K for 12-bit data. This + * convention improves accuracy in integer implementations and saves some + * work in floating-point ones. + * Quantization of the output coefficients is done by jcdctmgr.c. + */ + +#if BITS_IN_JSAMPLE == 8 +typedef int DCTELEM; /* 16 or 32 bits is fine */ +#else +typedef INT32 DCTELEM; /* must have 32 bits */ +#endif + +typedef JMETHOD(void, forward_DCT_method_ptr, (DCTELEM * data)); +typedef JMETHOD(void, float_DCT_method_ptr, (FAST_FLOAT * data)); + + +/* + * An inverse DCT routine is given a pointer to the input JBLOCK and a pointer + * to an output sample array. The routine must dequantize the input data as + * well as perform the IDCT; for dequantization, it uses the multiplier table + * pointed to by compptr->dct_table. The output data is to be placed into the + * sample array starting at a specified column. (Any row offset needed will + * be applied to the array pointer before it is passed to the IDCT code.) + * Note that the number of samples emitted by the IDCT routine is + * DCT_scaled_size * DCT_scaled_size. + */ + +/* typedef inverse_DCT_method_ptr is declared in jpegint.h */ + +/* + * Each IDCT routine has its own ideas about the best dct_table element type. + */ + +typedef MULTIPLIER ISLOW_MULT_TYPE; /* short or int, whichever is faster */ +#if BITS_IN_JSAMPLE == 8 +typedef MULTIPLIER IFAST_MULT_TYPE; /* 16 bits is OK, use short if faster */ +#define IFAST_SCALE_BITS 2 /* fractional bits in scale factors */ +#else +typedef INT32 IFAST_MULT_TYPE; /* need 32 bits for scaled quantizers */ +#define IFAST_SCALE_BITS 13 /* fractional bits in scale factors */ +#endif +typedef FAST_FLOAT FLOAT_MULT_TYPE; /* preferred floating type */ + + +/* + * Each IDCT routine is responsible for range-limiting its results and + * converting them to unsigned form (0..MAXJSAMPLE). The raw outputs could + * be quite far out of range if the input data is corrupt, so a bulletproof + * range-limiting step is required. We use a mask-and-table-lookup method + * to do the combined operations quickly. See the comments with + * prepare_range_limit_table (in jdmaster.c) for more info. + */ + +#define IDCT_range_limit(cinfo) ((cinfo)->sample_range_limit + CENTERJSAMPLE) + +#define RANGE_MASK (MAXJSAMPLE * 4 + 3) /* 2 bits wider than legal samples */ + + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_fdct_islow jFDislow +#define jpeg_fdct_ifast jFDifast +#define jpeg_fdct_float jFDfloat +#define jpeg_idct_islow jRDislow +#define jpeg_idct_ifast jRDifast +#define jpeg_idct_float jRDfloat +#define jpeg_idct_4x4 jRD4x4 +#define jpeg_idct_2x2 jRD2x2 +#define jpeg_idct_1x1 jRD1x1 +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + +/* Extern declarations for the forward and inverse DCT routines. */ + +EXTERN(void) jpeg_fdct_islow JPP((DCTELEM * data)); +EXTERN(void) jpeg_fdct_ifast JPP((DCTELEM * data)); +EXTERN(void) jpeg_fdct_float JPP((FAST_FLOAT * data)); + +EXTERN(void) jpeg_idct_islow + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_ifast + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_float + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_4x4 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_2x2 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_1x1 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); + + +/* + * Macros for handling fixed-point arithmetic; these are used by many + * but not all of the DCT/IDCT modules. + * + * All values are expected to be of type INT32. + * Fractional constants are scaled left by CONST_BITS bits. + * CONST_BITS is defined within each module using these macros, + * and may differ from one module to the next. + */ + +#define ONE ((INT32) 1) +#define CONST_SCALE (ONE << CONST_BITS) + +/* Convert a positive real constant to an integer scaled by CONST_SCALE. + * Caution: some C compilers fail to reduce "FIX(constant)" at compile time, + * thus causing a lot of useless floating-point operations at run time. + */ + +#define FIX(x) ((INT32) ((x) * CONST_SCALE + 0.5)) + +/* Descale and correctly round an INT32 value that's scaled by N bits. + * We assume RIGHT_SHIFT rounds towards minus infinity, so adding + * the fudge factor is correct for either sign of X. + */ + +#define DESCALE(x,n) RIGHT_SHIFT((x) + (ONE << ((n)-1)), n) + +/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result. + * This macro is used only when the two inputs will actually be no more than + * 16 bits wide, so that a 16x16->32 bit multiply can be used instead of a + * full 32x32 multiply. This provides a useful speedup on many machines. + * Unfortunately there is no way to specify a 16x16->32 multiply portably + * in C, but some C compilers will do the right thing if you provide the + * correct combination of casts. + */ + +#ifdef SHORTxSHORT_32 /* may work if 'int' is 32 bits */ +#define MULTIPLY16C16(var,const) (((INT16) (var)) * ((INT16) (const))) +#endif +#ifdef SHORTxLCONST_32 /* known to work with Microsoft C 6.0 */ +#define MULTIPLY16C16(var,const) (((INT16) (var)) * ((INT32) (const))) +#endif + +#ifndef MULTIPLY16C16 /* default definition */ +#define MULTIPLY16C16(var,const) ((var) * (const)) +#endif + +/* Same except both inputs are variables. */ + +#ifdef SHORTxSHORT_32 /* may work if 'int' is 32 bits */ +#define MULTIPLY16V16(var1,var2) (((INT16) (var1)) * ((INT16) (var2))) +#endif + +#ifndef MULTIPLY16V16 /* default definition */ +#define MULTIPLY16V16(var1,var2) ((var1) * (var2)) +#endif diff --git a/gdcm/Utilities/gdcmjpeg/jddctmgr.c b/gdcm/Utilities/gdcmjpeg/jddctmgr.c new file mode 100644 index 0000000..6f6c444 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jddctmgr.c @@ -0,0 +1,270 @@ +/* + * jddctmgr.c + * + * Copyright (C) 1994-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the inverse-DCT management logic. + * This code selects a particular IDCT implementation to be used, + * and it performs related housekeeping chores. No code in this file + * is executed per IDCT step, only during output pass setup. + * + * Note that the IDCT routines are responsible for performing coefficient + * dequantization as well as the IDCT proper. This module sets up the + * dequantization multiplier table needed by the IDCT routine. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jlossy.h" /* Private declarations for lossy subsystem */ +#include "jdct.h" /* Private declarations for DCT subsystem */ + + +/* + * The decompressor input side (jdinput.c) saves away the appropriate + * quantization table for each component at the start of the first scan + * involving that component. (This is necessary in order to correctly + * decode files that reuse Q-table slots.) + * When we are ready to make an output pass, the saved Q-table is converted + * to a multiplier table that will actually be used by the IDCT routine. + * The multiplier table contents are IDCT-method-dependent. To support + * application changes in IDCT method between scans, we can remake the + * multiplier tables if necessary. + * In buffered-image mode, the first output pass may occur before any data + * has been seen for some components, and thus before their Q-tables have + * been saved away. To handle this case, multiplier tables are preset + * to zeroes; the result of the IDCT will be a neutral gray level. + */ + + +/* Private subobject for this module */ + +typedef struct { + /* This array contains the IDCT method code that each multiplier table + * is currently set up for, or -1 if it's not yet set up. + * The actual multiplier tables are pointed to by dct_table in the + * per-component comp_info structures. + */ + int cur_method[MAX_COMPONENTS]; +} idct_controller; + +typedef idct_controller * idct_ptr; + + +/* Allocated multiplier tables: big enough for any supported variant */ + +typedef union { + ISLOW_MULT_TYPE islow_array[DCTSIZE2]; +#ifdef DCT_IFAST_SUPPORTED + IFAST_MULT_TYPE ifast_array[DCTSIZE2]; +#endif +#ifdef DCT_FLOAT_SUPPORTED + FLOAT_MULT_TYPE float_array[DCTSIZE2]; +#endif +} multiplier_table; + + +/* The current scaled-IDCT routines require ISLOW-style multiplier tables, + * so be sure to compile that code if either ISLOW or SCALING is requested. + */ +#ifdef DCT_ISLOW_SUPPORTED +#define PROVIDE_ISLOW_TABLES +#else +#ifdef IDCT_SCALING_SUPPORTED +#define PROVIDE_ISLOW_TABLES +#endif +#endif + + +/* + * Prepare for an output pass. + * Here we select the proper IDCT routine for each component and build + * a matching multiplier table. + */ + +METHODDEF(void) +start_pass (j_decompress_ptr cinfo) +{ + j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; + idct_ptr idct = (idct_ptr) lossyd->idct_private; + int ci, i; + jpeg_component_info *compptr; + int method = 0; + inverse_DCT_method_ptr method_ptr = NULL; + JQUANT_TBL * qtbl; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Select the proper IDCT routine for this component's scaling */ + switch (compptr->codec_data_unit) { +#ifdef IDCT_SCALING_SUPPORTED + case 1: + method_ptr = jpeg_idct_1x1; + method = JDCT_ISLOW; /* jidctred uses islow-style table */ + break; + case 2: + method_ptr = jpeg_idct_2x2; + method = JDCT_ISLOW; /* jidctred uses islow-style table */ + break; + case 4: + method_ptr = jpeg_idct_4x4; + method = JDCT_ISLOW; /* jidctred uses islow-style table */ + break; +#endif + case DCTSIZE: + switch (cinfo->dct_method) { +#ifdef DCT_ISLOW_SUPPORTED + case JDCT_ISLOW: + method_ptr = jpeg_idct_islow; + method = JDCT_ISLOW; + break; +#endif +#ifdef DCT_IFAST_SUPPORTED + case JDCT_IFAST: + method_ptr = jpeg_idct_ifast; + method = JDCT_IFAST; + break; +#endif +#ifdef DCT_FLOAT_SUPPORTED + case JDCT_FLOAT: + method_ptr = jpeg_idct_float; + method = JDCT_FLOAT; + break; +#endif + default: + ERREXIT(cinfo, JERR_NOT_COMPILED); + break; + } + break; + default: + ERREXIT1(cinfo, JERR_BAD_DCTSIZE, compptr->codec_data_unit); + break; + } + lossyd->inverse_DCT[ci] = method_ptr; + /* Create multiplier table from quant table. + * However, we can skip this if the component is uninteresting + * or if we already built the table. Also, if no quant table + * has yet been saved for the component, we leave the + * multiplier table all-zero; we'll be reading zeroes from the + * coefficient controller's buffer anyway. + */ + if (! compptr->component_needed || idct->cur_method[ci] == method) + continue; + qtbl = compptr->quant_table; + if (qtbl == NULL) /* happens if no data yet for component */ + continue; + idct->cur_method[ci] = method; + switch (method) { +#ifdef PROVIDE_ISLOW_TABLES + case JDCT_ISLOW: + { + /* For LL&M IDCT method, multipliers are equal to raw quantization + * coefficients, but are stored as ints to ensure access efficiency. + */ + ISLOW_MULT_TYPE * ismtbl = (ISLOW_MULT_TYPE *) compptr->dct_table; + for (i = 0; i < DCTSIZE2; i++) { + ismtbl[i] = (ISLOW_MULT_TYPE) qtbl->quantval[i]; + } + } + break; +#endif +#ifdef DCT_IFAST_SUPPORTED + case JDCT_IFAST: + { + /* For AA&N IDCT method, multipliers are equal to quantization + * coefficients scaled by scalefactor[row]*scalefactor[col], where + * scalefactor[0] = 1 + * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7 + * For integer operation, the multiplier table is to be scaled by + * IFAST_SCALE_BITS. + */ + IFAST_MULT_TYPE * ifmtbl = (IFAST_MULT_TYPE *) compptr->dct_table; +#define CONST_BITS 14 + static const INT16 aanscales[DCTSIZE2] = { + /* precomputed values scaled up by 14 bits */ + 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, + 22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270, + 21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906, + 19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315, + 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, + 12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552, + 8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446, + 4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247 + }; + SHIFT_TEMPS + + for (i = 0; i < DCTSIZE2; i++) { + ifmtbl[i] = (IFAST_MULT_TYPE) + DESCALE(MULTIPLY16V16((INT32) qtbl->quantval[i], + (INT32) aanscales[i]), + CONST_BITS-IFAST_SCALE_BITS); + } + } + break; +#endif +#ifdef DCT_FLOAT_SUPPORTED + case JDCT_FLOAT: + { + /* For float AA&N IDCT method, multipliers are equal to quantization + * coefficients scaled by scalefactor[row]*scalefactor[col], where + * scalefactor[0] = 1 + * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7 + */ + FLOAT_MULT_TYPE * fmtbl = (FLOAT_MULT_TYPE *) compptr->dct_table; + int row, col; + static const double aanscalefactor[DCTSIZE] = { + 1.0, 1.387039845, 1.306562965, 1.175875602, + 1.0, 0.785694958, 0.541196100, 0.275899379 + }; + + i = 0; + for (row = 0; row < DCTSIZE; row++) { + for (col = 0; col < DCTSIZE; col++) { + fmtbl[i] = (FLOAT_MULT_TYPE) + ((double) qtbl->quantval[i] * + aanscalefactor[row] * aanscalefactor[col]); + i++; + } + } + } + break; +#endif + default: + ERREXIT(cinfo, JERR_NOT_COMPILED); + break; + } + } +} + + +/* + * Initialize IDCT manager. + */ + +GLOBAL(void) +jinit_inverse_dct (j_decompress_ptr cinfo) +{ + j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; + idct_ptr idct; + int ci; + jpeg_component_info *compptr; + + idct = (idct_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(idct_controller)); + lossyd->idct_private = (void *) idct; + lossyd->idct_start_pass = start_pass; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Allocate and pre-zero a multiplier table for each component */ + compptr->dct_table = + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(multiplier_table)); + MEMZERO(compptr->dct_table, SIZEOF(multiplier_table)); + /* Mark multiplier table not yet set up for any method */ + idct->cur_method[ci] = -1; + } +} diff --git a/gdcm/Utilities/gdcmjpeg/jddiffct.c b/gdcm/Utilities/gdcmjpeg/jddiffct.c new file mode 100644 index 0000000..713b046 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jddiffct.c @@ -0,0 +1,400 @@ +/* + * jddiffct.c + * + * Copyright (C) 1994-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the [un]difference buffer controller for decompression. + * This controller is the top level of the lossless JPEG decompressor proper. + * The difference buffer lies between the entropy decoding and + * prediction/undifferencing steps. The undifference buffer lies between the + * prediction/undifferencing and scaling steps. + * + * In buffered-image mode, this controller is the interface between + * input-oriented processing and output-oriented processing. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jlossls.h" + + +#ifdef D_LOSSLESS_SUPPORTED + +/* Private buffer controller object */ + +typedef struct { + /* These variables keep track of the current location of the input side. */ + /* cinfo->input_iMCU_row is also used for this. */ + JDIMENSION MCU_ctr; /* counts MCUs processed in current row */ + unsigned int restart_rows_to_go; /* MCU-rows left in this restart interval */ + unsigned int MCU_vert_offset; /* counts MCU rows within iMCU row */ + unsigned int MCU_rows_per_iMCU_row; /* number of such rows needed */ + + /* The output side's location is represented by cinfo->output_iMCU_row. */ + + JDIFFARRAY diff_buf[MAX_COMPONENTS]; /* iMCU row of differences */ + JDIFFARRAY undiff_buf[MAX_COMPONENTS]; /* iMCU row of undiff'd samples */ + +#ifdef D_MULTISCAN_FILES_SUPPORTED + /* In multi-pass modes, we need a virtual sample array for each component. */ + jvirt_sarray_ptr whole_image[MAX_COMPONENTS]; +#endif +} d_diff_controller; + +typedef d_diff_controller * d_diff_ptr; + +/* Forward declarations */ +METHODDEF(int) decompress_data + JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf)); +#ifdef D_MULTISCAN_FILES_SUPPORTED +METHODDEF(int) output_data + JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf)); +#endif + + +LOCAL(void) +start_iMCU_row (j_decompress_ptr cinfo) +/* Reset within-iMCU-row counters for a new row (input side) */ +{ + j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; + d_diff_ptr diff = (d_diff_ptr) losslsd->diff_private; + + /* In an interleaved scan, an MCU row is the same as an iMCU row. + * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows. + * But at the bottom of the image, process only what's left. + */ + if (cinfo->comps_in_scan > 1) { + diff->MCU_rows_per_iMCU_row = 1; + } else { + if (cinfo->input_iMCU_row < (cinfo->total_iMCU_rows-1)) + diff->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor; + else + diff->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height; + } + + diff->MCU_ctr = 0; + diff->MCU_vert_offset = 0; +} + + +/* + * Initialize for an input processing pass. + */ + +METHODDEF(void) +start_input_pass (j_decompress_ptr cinfo) +{ + j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; + d_diff_ptr diff = (d_diff_ptr) losslsd->diff_private; + + /* Check that the restart interval is an integer multiple of the number + * of MCU in an MCU-row. + */ + if (cinfo->restart_interval % cinfo->MCUs_per_row != 0) + ERREXIT2(cinfo, JERR_BAD_RESTART, + cinfo->restart_interval, cinfo->MCUs_per_row); + + /* Initialize restart counter */ + diff->restart_rows_to_go = cinfo->restart_interval / cinfo->MCUs_per_row; + + cinfo->input_iMCU_row = 0; + start_iMCU_row(cinfo); +} + + +/* + * Check for a restart marker & resynchronize decoder, undifferencer. + * Returns FALSE if must suspend. + */ + +METHODDEF(boolean) +process_restart (j_decompress_ptr cinfo) +{ + j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; + d_diff_ptr diff = (d_diff_ptr) losslsd->diff_private; + + if (! (*losslsd->entropy_process_restart) (cinfo)) + return FALSE; + + (*losslsd->predict_process_restart) (cinfo); + + /* Reset restart counter */ + diff->restart_rows_to_go = cinfo->restart_interval / cinfo->MCUs_per_row; + + return TRUE; +} + + +/* + * Initialize for an output processing pass. + */ + +METHODDEF(void) +start_output_pass (j_decompress_ptr cinfo) +{ + cinfo->output_iMCU_row = 0; +} + + +/* + * Decompress and return some data in the supplied buffer. + * Always attempts to emit one fully interleaved MCU row ("iMCU" row). + * Input and output must run in lockstep since we have only a one-MCU buffer. + * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED. + * + * NB: output_buf contains a plane for each component in image, + * which we index according to the component's SOF position. + */ + +METHODDEF(int) +decompress_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf) +{ + j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; + d_diff_ptr diff = (d_diff_ptr) losslsd->diff_private; + JDIMENSION MCU_col_num; /* index of current MCU within row */ + JDIMENSION MCU_count; /* number of MCUs decoded */ + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + int comp, ci, row, prev_row; + unsigned int yoffset; + jpeg_component_info *compptr; + + /* Loop to process as much as one whole iMCU row */ + for (yoffset = diff->MCU_vert_offset; yoffset < diff->MCU_rows_per_iMCU_row; + yoffset++) { + + /* Process restart marker if needed; may have to suspend */ + if (cinfo->restart_interval) { + if (diff->restart_rows_to_go == 0) + if (! process_restart(cinfo)) + return JPEG_SUSPENDED; + } + + MCU_col_num = diff->MCU_ctr; + /* Try to fetch an MCU-row (or remaining portion of suspended MCU-row). */ + MCU_count = + (*losslsd->entropy_decode_mcus) (cinfo, + diff->diff_buf, yoffset, MCU_col_num, + cinfo->MCUs_per_row - MCU_col_num); + if (MCU_count != cinfo->MCUs_per_row - MCU_col_num) { + /* Suspension forced; update state counters and exit */ + diff->MCU_vert_offset = yoffset; + diff->MCU_ctr += MCU_count; + return JPEG_SUSPENDED; + } + + /* Account for restart interval (no-op if not using restarts) */ + diff->restart_rows_to_go--; + + /* Completed an MCU row, but perhaps not an iMCU row */ + diff->MCU_ctr = 0; + } + + /* + * Undifference and scale each scanline of the disassembled MCU-row + * separately. We do not process dummy samples at the end of a scanline + * or dummy rows at the end of the image. + */ + for (comp = 0; comp < cinfo->comps_in_scan; comp++) { + compptr = cinfo->cur_comp_info[comp]; + ci = compptr->component_index; + for (row = 0, prev_row = compptr->v_samp_factor - 1; + row < (cinfo->input_iMCU_row == last_iMCU_row ? + compptr->last_row_height : compptr->v_samp_factor); + prev_row = row, row++) { + (*losslsd->predict_undifference[ci]) (cinfo, ci, + diff->diff_buf[ci][row], + diff->undiff_buf[ci][prev_row], + diff->undiff_buf[ci][row], + compptr->width_in_data_units); + (*losslsd->scaler_scale) (cinfo, diff->undiff_buf[ci][row], + output_buf[ci][row], + compptr->width_in_data_units); + } + } + + /* Completed the iMCU row, advance counters for next one. + * + * NB: output_data will increment output_iMCU_row. + * This counter is not needed for the single-pass case + * or the input side of the multi-pass case. + */ + if (++(cinfo->input_iMCU_row) < cinfo->total_iMCU_rows) { + start_iMCU_row(cinfo); + return JPEG_ROW_COMPLETED; + } + /* Completed the scan */ + (*cinfo->inputctl->finish_input_pass) (cinfo); + return JPEG_SCAN_COMPLETED; +} + + +/* + * Dummy consume-input routine for single-pass operation. + */ + +METHODDEF(int) +dummy_consume_data (j_decompress_ptr cinfo) +{ + (void)cinfo; + return JPEG_SUSPENDED; /* Always indicate nothing was done */ +} + + +#ifdef D_MULTISCAN_FILES_SUPPORTED + +/* + * Consume input data and store it in the full-image sample buffer. + * We read as much as one fully interleaved MCU row ("iMCU" row) per call, + * ie, v_samp_factor rows for each component in the scan. + * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED. + */ + +METHODDEF(int) +consume_data (j_decompress_ptr cinfo) +{ + j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; + d_diff_ptr diff = (d_diff_ptr) losslsd->diff_private; + /* JDIMENSION MCU_col_num; */ /* index of current MCU within row */ + /* JDIMENSION MCU_count; */ /* number of MCUs decoded */ + /* JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; */ + int comp, ci /* , yoffset, row, prev_row */; + JSAMPARRAY buffer[MAX_COMPS_IN_SCAN]; + jpeg_component_info *compptr; + + /* Align the virtual buffers for the components used in this scan. */ + for (comp = 0; comp < cinfo->comps_in_scan; comp++) { + compptr = cinfo->cur_comp_info[comp]; + ci = compptr->component_index; + buffer[ci] = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, diff->whole_image[ci], + cinfo->input_iMCU_row * compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, TRUE); + } + + return decompress_data(cinfo, buffer); +} + + +/* + * Output some data from the full-image buffer sample in the multi-pass case. + * Always attempts to emit one fully interleaved MCU row ("iMCU" row). + * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED. + * + * NB: output_buf contains a plane for each component in image. + */ + +METHODDEF(int) +output_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf) +{ + j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; + d_diff_ptr diff = (d_diff_ptr) losslsd->diff_private; + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + int ci, samp_rows, row; + JSAMPARRAY buffer; + jpeg_component_info *compptr; + + /* Force some input to be done if we are getting ahead of the input. */ + while (cinfo->input_scan_number < cinfo->output_scan_number || + (cinfo->input_scan_number == cinfo->output_scan_number && + cinfo->input_iMCU_row <= cinfo->output_iMCU_row)) { + if ((*cinfo->inputctl->consume_input)(cinfo) == JPEG_SUSPENDED) + return JPEG_SUSPENDED; + } + + /* OK, output from the virtual arrays. */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Align the virtual buffer for this component. */ + buffer = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, diff->whole_image[ci], + cinfo->output_iMCU_row * compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, FALSE); + + if (cinfo->output_iMCU_row < last_iMCU_row) + samp_rows = compptr->v_samp_factor; + else { + /* NB: can't use last_row_height here; it is input-side-dependent! */ + samp_rows = (int) (compptr->height_in_data_units % compptr->v_samp_factor); + if (samp_rows == 0) samp_rows = compptr->v_samp_factor; + } + + for (row = 0; row < samp_rows; row++) { + MEMCOPY(output_buf[ci][row], buffer[row], + compptr->width_in_data_units * SIZEOF(JSAMPLE)); + } + } + + if (++(cinfo->output_iMCU_row) < cinfo->total_iMCU_rows) + return JPEG_ROW_COMPLETED; + return JPEG_SCAN_COMPLETED; +} + +#endif /* D_MULTISCAN_FILES_SUPPORTED */ + + +/* + * Initialize difference buffer controller. + */ + +GLOBAL(void) +jinit_d_diff_controller (j_decompress_ptr cinfo, boolean need_full_buffer) +{ + j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; + d_diff_ptr diff; + int ci; + jpeg_component_info *compptr; + + diff = (d_diff_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(d_diff_controller)); + losslsd->diff_private = (void *) diff; + losslsd->diff_start_input_pass = start_input_pass; + losslsd->pub.start_output_pass = start_output_pass; + + /* Create the [un]difference buffers. */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + diff->diff_buf[ci] = (*cinfo->mem->alloc_darray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) jround_up((long) compptr->width_in_data_units, + (long) compptr->h_samp_factor), + (JDIMENSION) compptr->v_samp_factor); + diff->undiff_buf[ci] = (*cinfo->mem->alloc_darray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) jround_up((long) compptr->width_in_data_units, + (long) compptr->h_samp_factor), + (JDIMENSION) compptr->v_samp_factor); + } + + if (need_full_buffer) { +#ifdef D_MULTISCAN_FILES_SUPPORTED + /* Allocate a full-image virtual array for each component. */ + int access_rows; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + access_rows = compptr->v_samp_factor; + diff->whole_image[ci] = (*cinfo->mem->request_virt_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, + (JDIMENSION) jround_up((long) compptr->width_in_data_units, + (long) compptr->h_samp_factor), + (JDIMENSION) jround_up((long) compptr->height_in_data_units, + (long) compptr->v_samp_factor), + (JDIMENSION) access_rows); + } + losslsd->pub.consume_data = consume_data; + losslsd->pub.decompress_data = output_data; +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else { + losslsd->pub.consume_data = dummy_consume_data; + losslsd->pub.decompress_data = decompress_data; + diff->whole_image[0] = NULL; /* flag for no virtual arrays */ + } +} + +#endif /* D_LOSSLESS_SUPPORTED */ diff --git a/gdcm/Utilities/gdcmjpeg/jdhuff.c b/gdcm/Utilities/gdcmjpeg/jdhuff.c new file mode 100644 index 0000000..5c02ab5 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jdhuff.c @@ -0,0 +1,344 @@ +/* + * jdhuff.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains Huffman entropy decoding routines which are shared + * by the sequential, progressive and lossless decoders. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jlossy.h" /* Private declarations for lossy codec */ +#include "jlossls.h" /* Private declarations for lossless codec */ +#include "jdhuff.h" /* Declarations shared with jd*huff.c */ + + +/* + * Compute the derived values for a Huffman table. + * This routine also performs some validation checks on the table. + */ + +GLOBAL(void) +jpeg_make_d_derived_tbl (j_decompress_ptr cinfo, boolean isDC, int tblno, + d_derived_tbl ** pdtbl) +{ + JHUFF_TBL *htbl; + d_derived_tbl *dtbl; + int p, i, l, si, numsymbols; + int lookbits, ctr; + char huffsize[257]; + unsigned int huffcode[257]; + unsigned int code; + + /* Note that huffsize[] and huffcode[] are filled in code-length order, + * paralleling the order of the symbols themselves in htbl->huffval[]. + */ + + /* Find the input Huffman table */ + if (tblno < 0 || tblno >= NUM_HUFF_TBLS) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tblno); + htbl = + isDC ? cinfo->dc_huff_tbl_ptrs[tblno] : cinfo->ac_huff_tbl_ptrs[tblno]; + if (htbl == NULL) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tblno); + + /* Allocate a workspace if we haven't already done so. */ + if (*pdtbl == NULL) + *pdtbl = (d_derived_tbl *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(d_derived_tbl)); + dtbl = *pdtbl; + dtbl->pub = htbl; /* fill in back link */ + + /* Figure C.1: make table of Huffman code length for each symbol */ + + p = 0; + for (l = 1; l <= 16; l++) { + i = (int) htbl->bits[l]; + if (i < 0 || p + i > 256) /* protect against table overrun */ + ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); + while (i--) + huffsize[p++] = (char) l; + } + huffsize[p] = 0; + numsymbols = p; + + /* Figure C.2: generate the codes themselves */ + /* We also validate that the counts represent a legal Huffman code tree. */ + + code = 0; + si = huffsize[0]; + p = 0; + while (huffsize[p]) { + while (((int) huffsize[p]) == si) { + huffcode[p++] = code; + code++; + } + /* code is now 1 more than the last code used for codelength si; but + * it must still fit in si bits, since no code is allowed to be all ones. + * BUG FIX 2001-09-03: Comparison must be >, not >= + */ + if (((INT32) code) > (((INT32) 1) << si)) + ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); + code <<= 1; + si++; + } + + /* Figure F.15: generate decoding tables for bit-sequential decoding */ + + p = 0; + for (l = 1; l <= 16; l++) { + if (htbl->bits[l]) { + /* valoffset[l] = huffval[] index of 1st symbol of code length l, + * minus the minimum code of length l + */ + dtbl->valoffset[l] = (INT32) p - (INT32) huffcode[p]; + p += htbl->bits[l]; + dtbl->maxcode[l] = huffcode[p-1]; /* maximum code of length l */ + } else { + dtbl->maxcode[l] = -1; /* -1 if no codes of this length */ + } + } + dtbl->maxcode[17] = 0xFFFFFL; /* ensures jpeg_huff_decode terminates */ + + /* Compute lookahead tables to speed up decoding. + * First we set all the table entries to 0, indicating "too long"; + * then we iterate through the Huffman codes that are short enough and + * fill in all the entries that correspond to bit sequences starting + * with that code. + */ + + MEMZERO(dtbl->look_nbits, SIZEOF(dtbl->look_nbits)); + + p = 0; + for (l = 1; l <= HUFF_LOOKAHEAD; l++) { + for (i = 1; i <= (int) htbl->bits[l]; i++, p++) { + /* l = current code's length, p = its index in huffcode[] & huffval[]. */ + /* Generate left-justified code followed by all possible bit sequences */ + lookbits = huffcode[p] << (HUFF_LOOKAHEAD-l); + for (ctr = 1 << (HUFF_LOOKAHEAD-l); ctr > 0; ctr--) { + dtbl->look_nbits[lookbits] = l; + dtbl->look_sym[lookbits] = htbl->huffval[p]; + lookbits++; + } + } + } + + /* Validate symbols as being reasonable. + * For AC tables, we make no check, but accept all byte values 0..255. + * For DC tables, we require the symbols to be in range 0..16. + * (Tighter bounds could be applied depending on the data depth and mode, + * but this is sufficient to ensure safe decoding.) + */ + if (isDC) { + for (i = 0; i < numsymbols; i++) { + int sym = htbl->huffval[i]; +/* The following file contains a value of 17 in the huffman table, which is impossible + * according to ISO 10918-1, H.1.2.2 Huffman coding of the modulo difference + * and table H.2. + * PHILIPS_Gyroscan-12-Jpeg_Extended_Process_2_4.dcm + * MM, 2008/08/12 I am breaking backward compatibility and decide not to support this image + * anymore. In fact the decompression using another library: PVRG was giving me + * another result anyway. + * + * Steps: + * + * $ gdcmconv --raw -i PHILIPS_Gyroscan-12-Jpeg_Extended_Process_2_4.dcm -o bla.dcm + * $ gdcmraw -i bla.dcm -o bla.raw + * $ gdcmraw -i PHILIPS_Gyroscan-12-Jpeg_Extended_Process_2_4.dcm -o philips.jpg + * $ pvrgjpeg -d philips + * $ dd conv=swab if=philips.jpg.0 of=philips.raw + * $ vbindiff bla.raw philips.raw + * + * $ md5sum bla.raw philips.raw + * 4b0021efe5a675f24c82e1ff28a1e2eb bla.raw + * d93d2f78d845c7a132489aab92eadd32 philips.raw + * + * + * footnote, I get a much closer result doing: + * $ pvrgjpeg -a -y -d philips + * after that the number of diff with IJG is getting lower + * + * 0f2570f5d91ddea5bd9d3825a86eaabe philips.raw + */ + if (sym < 0 || sym > 16) + ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); + } + } +} + + +/* + * Out-of-line code for bit fetching. + * See jdhuff.h for info about usage. + * Note: current values of get_buffer and bits_left are passed as parameters, + * but are returned in the corresponding fields of the state struct. + * + * On most machines MIN_GET_BITS should be 25 to allow the full 32-bit width + * of get_buffer to be used. (On machines with wider words, an even larger + * buffer could be used.) However, on some machines 32-bit shifts are + * quite slow and take time proportional to the number of places shifted. + * (This is true with most PC compilers, for instance.) In this case it may + * be a win to set MIN_GET_BITS to the minimum value of 15. This reduces the + * average shift distance at the cost of more calls to jpeg_fill_bit_buffer. + */ + +#ifdef SLOW_SHIFT_32 +#define MIN_GET_BITS 15 /* minimum allowable value */ +#else +#define MIN_GET_BITS (BIT_BUF_SIZE-7) +#endif + + +GLOBAL(boolean) +jpeg_fill_bit_buffer (bitread_working_state * state, + register bit_buf_type get_buffer, register int bits_left, + int nbits) +/* Load up the bit buffer to a depth of at least nbits */ +{ + /* Copy heavily used state fields into locals (hopefully registers) */ + register const JOCTET * next_input_byte = state->next_input_byte; + register size_t bytes_in_buffer = state->bytes_in_buffer; + j_decompress_ptr cinfo = state->cinfo; + + /* Attempt to load at least MIN_GET_BITS bits into get_buffer. */ + /* (It is assumed that no request will be for more than that many bits.) */ + /* We fail to do so only if we hit a marker or are forced to suspend. */ + + if (cinfo->unread_marker == 0) { /* cannot advance past a marker */ + while (bits_left < MIN_GET_BITS) { + register int c; + + /* Attempt to read a byte */ + if (bytes_in_buffer == 0) { + if (! (*cinfo->src->fill_input_buffer) (cinfo)) + return FALSE; + next_input_byte = cinfo->src->next_input_byte; + bytes_in_buffer = cinfo->src->bytes_in_buffer; + } + bytes_in_buffer--; + c = GETJOCTET(*next_input_byte++); + + /* If it's 0xFF, check and discard stuffed zero byte */ + if (c == 0xFF) { + /* Loop here to discard any padding FF's on terminating marker, + * so that we can save a valid unread_marker value. NOTE: we will + * accept multiple FF's followed by a 0 as meaning a single FF data + * byte. This data pattern is not valid according to the standard. + */ + do { + if (bytes_in_buffer == 0) { + if (! (*cinfo->src->fill_input_buffer) (cinfo)) + return FALSE; + next_input_byte = cinfo->src->next_input_byte; + bytes_in_buffer = cinfo->src->bytes_in_buffer; + } + bytes_in_buffer--; + c = GETJOCTET(*next_input_byte++); + } while (c == 0xFF); + + if (c == 0) { + /* Found FF/00, which represents an FF data byte */ + c = 0xFF; + } else { + /* Oops, it's actually a marker indicating end of compressed data. + * Save the marker code for later use. + * Fine point: it might appear that we should save the marker into + * bitread working state, not straight into permanent state. But + * once we have hit a marker, we cannot need to suspend within the + * current MCU, because we will read no more bytes from the data + * source. So it is OK to update permanent state right away. + */ + cinfo->unread_marker = c; + /* See if we need to insert some fake zero bits. */ + goto no_more_bytes; + } + } + + /* OK, load c into get_buffer */ + get_buffer = (get_buffer << 8) | c; + bits_left += 8; + } /* end while */ + } else { + no_more_bytes: + /* We get here if we've read the marker that terminates the compressed + * data segment. There should be enough bits in the buffer register + * to satisfy the request; if so, no problem. + */ + if (nbits > bits_left) { + /* Uh-oh. Report corrupted data to user and stuff zeroes into + * the data stream, so that we can produce some kind of image. + * We use a nonvolatile flag to ensure that only one warning message + * appears per data segment. + */ + huffd_common_ptr huffd; + if (cinfo->process == JPROC_LOSSLESS) + huffd = (huffd_common_ptr) ((j_lossless_d_ptr) cinfo->codec)->entropy_private; + else + huffd = (huffd_common_ptr) ((j_lossy_d_ptr) cinfo->codec)->entropy_private; + if (! huffd->insufficient_data) { + WARNMS(cinfo, JWRN_HIT_MARKER); + huffd->insufficient_data = TRUE; + } + /* Fill the buffer with zero bits */ + get_buffer <<= MIN_GET_BITS - bits_left; + bits_left = MIN_GET_BITS; + } + } + + /* Unload the local registers */ + state->next_input_byte = next_input_byte; + state->bytes_in_buffer = bytes_in_buffer; + state->get_buffer = get_buffer; + state->bits_left = bits_left; + + return TRUE; +} + + +/* + * Out-of-line code for Huffman code decoding. + * See jdhuff.h for info about usage. + */ + +GLOBAL(int) +jpeg_huff_decode (bitread_working_state * state, + register bit_buf_type get_buffer, register int bits_left, + d_derived_tbl * htbl, int min_bits) +{ + register int l = min_bits; + register INT32 code; + + /* HUFF_DECODE has determined that the code is at least min_bits */ + /* bits long, so fetch that many bits in one swoop. */ + + CHECK_BIT_BUFFER(*state, l, return -1); + code = GET_BITS(l); + + /* Collect the rest of the Huffman code one bit at a time. */ + /* This is per Figure F.16 in the JPEG spec. */ + + while (code > htbl->maxcode[l]) { + code <<= 1; + CHECK_BIT_BUFFER(*state, 1, return -1); + code |= GET_BITS(1); + l++; + } + + /* Unload the local registers */ + state->get_buffer = get_buffer; + state->bits_left = bits_left; + + /* With garbage input we may reach the sentinel value l = 17. */ + + if (l > 16) { + WARNMS(state->cinfo, JWRN_HUFF_BAD_CODE); + return 0; /* fake a zero as the safest result */ + } + + return htbl->pub->huffval[ (int) (code + htbl->valoffset[l]) ]; +} diff --git a/gdcm/Utilities/gdcmjpeg/jdhuff.h b/gdcm/Utilities/gdcmjpeg/jdhuff.h new file mode 100644 index 0000000..9074656 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jdhuff.h @@ -0,0 +1,229 @@ +/* + * jdhuff.h + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains declarations for Huffman entropy decoding routines + * that are shared between the sequential decoder (jdhuff.c), the + * progressive decoder (jdphuff.c) and the lossless decoder (jdlhuff.c). + * No other modules need to see these. + */ + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_make_d_derived_tbl jMkDDerived +#define jpeg_fill_bit_buffer jFilBitBuf +#define jpeg_huff_decode jHufDecode +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* Derived data constructed for each Huffman table */ + +#define HUFF_LOOKAHEAD 8 /* # of bits of lookahead */ + +typedef struct { + /* Basic tables: (element [0] of each array is unused) */ + INT32 maxcode[18]; /* largest code of length k (-1 if none) */ + /* (maxcode[17] is a sentinel to ensure jpeg_huff_decode terminates) */ + INT32 valoffset[17]; /* huffval[] offset for codes of length k */ + /* valoffset[k] = huffval[] index of 1st symbol of code length k, less + * the smallest code of length k; so given a code of length k, the + * corresponding symbol is huffval[code + valoffset[k]] + */ + + /* Link to public Huffman table (needed only in jpeg_huff_decode) */ + JHUFF_TBL *pub; + + /* Lookahead tables: indexed by the next HUFF_LOOKAHEAD bits of + * the input data stream. If the next Huffman code is no more + * than HUFF_LOOKAHEAD bits long, we can obtain its length and + * the corresponding symbol directly from these tables. + */ + int look_nbits[1< 32 bits on your machine, and shifting/masking longs is + * reasonably fast, making bit_buf_type be long and setting BIT_BUF_SIZE + * appropriately should be a win. Unfortunately we can't define the size + * with something like #define BIT_BUF_SIZE (sizeof(bit_buf_type)*8) + * because not all machines measure sizeof in 8-bit bytes. + */ + +typedef struct { /* Bitreading state saved across MCUs */ + bit_buf_type get_buffer; /* current bit-extraction buffer */ + int bits_left; /* # of unused bits in it */ +} bitread_perm_state; + +typedef struct { /* Bitreading working state within an MCU */ + /* Current data source location */ + /* We need a copy, rather than munging the original, in case of suspension */ + const JOCTET * next_input_byte; /* => next byte to read from source */ + size_t bytes_in_buffer; /* # of bytes remaining in source buffer */ + /* Bit input buffer --- note these values are kept in register variables, + * not in this struct, inside the inner loops. + */ + bit_buf_type get_buffer; /* current bit-extraction buffer */ + int bits_left; /* # of unused bits in it */ + /* Pointer needed by jpeg_fill_bit_buffer. */ + j_decompress_ptr cinfo; /* back link to decompress master record */ +} bitread_working_state; + +/* Macros to declare and load/save bitread local variables. */ +#define BITREAD_STATE_VARS \ + register bit_buf_type get_buffer; \ + register int bits_left; \ + bitread_working_state br_state + +#define BITREAD_LOAD_STATE(cinfop,permstate) \ + br_state.cinfo = cinfop; \ + br_state.next_input_byte = cinfop->src->next_input_byte; \ + br_state.bytes_in_buffer = cinfop->src->bytes_in_buffer; \ + get_buffer = permstate.get_buffer; \ + bits_left = permstate.bits_left; + +#define BITREAD_SAVE_STATE(cinfop,permstate) \ + cinfop->src->next_input_byte = br_state.next_input_byte; \ + cinfop->src->bytes_in_buffer = br_state.bytes_in_buffer; \ + permstate.get_buffer = get_buffer; \ + permstate.bits_left = bits_left + +/* + * These macros provide the in-line portion of bit fetching. + * Use CHECK_BIT_BUFFER to ensure there are N bits in get_buffer + * before using GET_BITS, PEEK_BITS, or DROP_BITS. + * The variables get_buffer and bits_left are assumed to be locals, + * but the state struct might not be (jpeg_huff_decode needs this). + * CHECK_BIT_BUFFER(state,n,action); + * Ensure there are N bits in get_buffer; if suspend, take action. + * val = GET_BITS(n); + * Fetch next N bits. + * val = PEEK_BITS(n); + * Fetch next N bits without removing them from the buffer. + * DROP_BITS(n); + * Discard next N bits. + * The value N should be a simple variable, not an expression, because it + * is evaluated multiple times. + */ + +#define CHECK_BIT_BUFFER(state,nbits,action) \ + { if (bits_left < (nbits)) { \ + if (! jpeg_fill_bit_buffer(&(state),get_buffer,bits_left,nbits)) \ + { action; } \ + get_buffer = (state).get_buffer; bits_left = (state).bits_left; } } + +#define GET_BITS(nbits) \ + (((int) (get_buffer >> (bits_left -= (nbits)))) & ((1<<(nbits))-1)) + +#define PEEK_BITS(nbits) \ + (((int) (get_buffer >> (bits_left - (nbits)))) & ((1<<(nbits))-1)) + +#define DROP_BITS(nbits) \ + (bits_left -= (nbits)) + +/* Load up the bit buffer to a depth of at least nbits */ +EXTERN(boolean) jpeg_fill_bit_buffer + JPP((bitread_working_state * state, register bit_buf_type get_buffer, + register int bits_left, int nbits)); + + +/* + * Code for extracting next Huffman-coded symbol from input bit stream. + * Again, this is time-critical and we make the main paths be macros. + * + * We use a lookahead table to process codes of up to HUFF_LOOKAHEAD bits + * without looping. Usually, more than 95% of the Huffman codes will be 8 + * or fewer bits long. The few overlength codes are handled with a loop, + * which need not be inline code. + * + * Notes about the HUFF_DECODE macro: + * 1. Near the end of the data segment, we may fail to get enough bits + * for a lookahead. In that case, we do it the hard way. + * 2. If the lookahead table contains no entry, the next code must be + * more than HUFF_LOOKAHEAD bits long. + * 3. jpeg_huff_decode returns -1 if forced to suspend. + */ + +#define HUFF_DECODE(result,state,htbl,failaction,slowlabel) \ +{ register int nb, look; \ + if (bits_left < HUFF_LOOKAHEAD) { \ + if (! jpeg_fill_bit_buffer(&state,get_buffer,bits_left, 0)) {failaction;} \ + get_buffer = state.get_buffer; bits_left = state.bits_left; \ + if (bits_left < HUFF_LOOKAHEAD) { \ + nb = 1; goto slowlabel; \ + } \ + } \ + look = PEEK_BITS(HUFF_LOOKAHEAD); \ + if ((nb = htbl->look_nbits[look]) != 0) { \ + DROP_BITS(nb); \ + result = htbl->look_sym[look]; \ + } else { \ + nb = HUFF_LOOKAHEAD+1; \ +slowlabel: \ + if ((result=jpeg_huff_decode(&state,get_buffer,bits_left,htbl,nb)) < 0) \ + { failaction; } \ + get_buffer = state.get_buffer; bits_left = state.bits_left; \ + } \ +} + +/* Out-of-line case for Huffman code fetching */ +EXTERN(int) jpeg_huff_decode + JPP((bitread_working_state * state, register bit_buf_type get_buffer, + register int bits_left, d_derived_tbl * htbl, int min_bits)); + + +/* Common fields between sequential, progressive and lossless Huffman entropy + * decoder master structs. + */ + +#define huffd_common_fields \ + boolean insufficient_data; /* set TRUE after emmitting warning */ \ + /* These fields are loaded into local variables at start of each MCU. \ + * In case of suspension, we exit WITHOUT updating them. \ + */ \ + bitread_perm_state bitstate /* Bit buffer at start of MCU */ + +/* Routines that are to be used by any or all of the entropy decoders are + * declared to receive a pointer to this structure. There are no actual + * instances of huffd_common_struct, only of shuff_entropy_decoder, + * phuff_entropy_decoder and lhuff_entropy_decoder. + */ +struct huffd_common_struct { + huffd_common_fields; /* Fields common to all decoder struct types */ + /* Additional fields follow in an actual shuff_entropy_decoder, + * phuff_entropy_decoder or lhuff_entropy_decoder struct. All four structs + * must agree on these initial fields! (This would be a lot cleaner in C++.) + */ +}; + +typedef struct huffd_common_struct * huffd_common_ptr; diff --git a/gdcm/Utilities/gdcmjpeg/jdinput.c b/gdcm/Utilities/gdcmjpeg/jdinput.c new file mode 100644 index 0000000..a5bbe1f --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jdinput.c @@ -0,0 +1,347 @@ +/* + * jdinput.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains input control logic for the JPEG decompressor. + * These routines are concerned with controlling the decompressor's input + * processing (marker reading and coefficient/difference decoding). + * The actual input reading is done in jdmarker.c, jdhuff.c, jdphuff.c, + * and jdlhuff.c. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Private state */ + +typedef struct { + struct jpeg_input_controller pub; /* public fields */ + + boolean inheaders; /* TRUE until first SOS is reached */ +} my_input_controller; + +typedef my_input_controller * my_inputctl_ptr; + + +/* Forward declarations */ +METHODDEF(int) consume_markers JPP((j_decompress_ptr cinfo)); + + +/* + * Routines to calculate various quantities related to the size of the image. + */ + +LOCAL(void) +initial_setup (j_decompress_ptr cinfo) +/* Called once, when first SOS marker is reached */ +{ + int ci; + jpeg_component_info *compptr; + + /* Make sure image isn't bigger than I can handle */ + if ((long) cinfo->image_height > (long) JPEG_MAX_DIMENSION || + (long) cinfo->image_width > (long) JPEG_MAX_DIMENSION) + ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) JPEG_MAX_DIMENSION); + + if (cinfo->process == JPROC_LOSSLESS) { + /* If precision > compiled-in value, we must downscale */ + if (cinfo->data_precision > BITS_IN_JSAMPLE) + WARNMS2(cinfo, JWRN_MUST_DOWNSCALE, + cinfo->data_precision, BITS_IN_JSAMPLE); + } + else { /* Lossy processes */ + /* For now, precision must match compiled-in value... */ + if (cinfo->data_precision != BITS_IN_JSAMPLE) + ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision); + } + + /* Check that number of components won't exceed internal array sizes */ + if (cinfo->num_components > MAX_COMPONENTS) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components, + MAX_COMPONENTS); + + /* Compute maximum sampling factors; check factor validity */ + cinfo->max_h_samp_factor = 1; + cinfo->max_v_samp_factor = 1; + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + if (compptr->h_samp_factor<=0 || compptr->h_samp_factor>MAX_SAMP_FACTOR || + compptr->v_samp_factor<=0 || compptr->v_samp_factor>MAX_SAMP_FACTOR) + ERREXIT(cinfo, JERR_BAD_SAMPLING); + cinfo->max_h_samp_factor = MAX(cinfo->max_h_samp_factor, + compptr->h_samp_factor); + cinfo->max_v_samp_factor = MAX(cinfo->max_v_samp_factor, + compptr->v_samp_factor); + } + + /* We initialize codec_data_unit and min_codec_data_unit to data_unit. + * In the full decompressor, this will be overridden by jdmaster.c; + * but in the transcoder, jdmaster.c is not used, so we must do it here. + */ + cinfo->min_codec_data_unit = cinfo->data_unit; + + /* Compute dimensions of components */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + compptr->codec_data_unit = cinfo->data_unit; + /* Size in data units */ + compptr->width_in_data_units = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor, + (long) (cinfo->max_h_samp_factor * cinfo->data_unit)); + compptr->height_in_data_units = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor, + (long) (cinfo->max_v_samp_factor * cinfo->data_unit)); + /* downsampled_width and downsampled_height will also be overridden by + * jdmaster.c if we are doing full decompression. The transcoder library + * doesn't use these values, but the calling application might. + */ + /* Size in samples */ + compptr->downsampled_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor, + (long) cinfo->max_h_samp_factor); + compptr->downsampled_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor, + (long) cinfo->max_v_samp_factor); + /* Mark component needed, until color conversion says otherwise */ + compptr->component_needed = TRUE; + /* Mark no quantization table yet saved for component */ + compptr->quant_table = NULL; + } + + /* Compute number of fully interleaved MCU rows. */ + cinfo->total_iMCU_rows = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height, + (long) (cinfo->max_v_samp_factor*cinfo->data_unit)); + + /* Decide whether file contains multiple scans */ + if (cinfo->comps_in_scan < cinfo->num_components || + cinfo->process == JPROC_PROGRESSIVE) + cinfo->inputctl->has_multiple_scans = TRUE; + else + cinfo->inputctl->has_multiple_scans = FALSE; +} + + +LOCAL(void) +per_scan_setup (j_decompress_ptr cinfo) +/* Do computations that are needed before processing a JPEG scan */ +/* cinfo->comps_in_scan and cinfo->cur_comp_info[] were set from SOS marker */ +{ + int ci, mcublks, tmp; + jpeg_component_info *compptr; + + if (cinfo->comps_in_scan == 1) { + + /* Noninterleaved (single-component) scan */ + compptr = cinfo->cur_comp_info[0]; + + /* Overall image size in MCUs */ + cinfo->MCUs_per_row = compptr->width_in_data_units; + cinfo->MCU_rows_in_scan = compptr->height_in_data_units; + + /* For noninterleaved scan, always one data unit per MCU */ + compptr->MCU_width = 1; + compptr->MCU_height = 1; + compptr->MCU_data_units = 1; + compptr->MCU_sample_width = compptr->codec_data_unit; + compptr->last_col_width = 1; + /* For noninterleaved scans, it is convenient to define last_row_height + * as the number of data unit rows present in the last iMCU row. + */ + tmp = (int) (compptr->height_in_data_units % compptr->v_samp_factor); + if (tmp == 0) tmp = compptr->v_samp_factor; + compptr->last_row_height = tmp; + + /* Prepare array describing MCU composition */ + cinfo->data_units_in_MCU = 1; + cinfo->MCU_membership[0] = 0; + + } else { + + /* Interleaved (multi-component) scan */ + if (cinfo->comps_in_scan <= 0 || cinfo->comps_in_scan > MAX_COMPS_IN_SCAN) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->comps_in_scan, + MAX_COMPS_IN_SCAN); + + /* Overall image size in MCUs */ + cinfo->MCUs_per_row = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width, + (long) (cinfo->max_h_samp_factor*cinfo->data_unit)); + cinfo->MCU_rows_in_scan = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height, + (long) (cinfo->max_v_samp_factor*cinfo->data_unit)); + + cinfo->data_units_in_MCU = 0; + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* Sampling factors give # of data units of component in each MCU */ + compptr->MCU_width = compptr->h_samp_factor; + compptr->MCU_height = compptr->v_samp_factor; + compptr->MCU_data_units = compptr->MCU_width * compptr->MCU_height; + compptr->MCU_sample_width = compptr->MCU_width * compptr->codec_data_unit; + /* Figure number of non-dummy data units in last MCU column & row */ + tmp = (int) (compptr->width_in_data_units % compptr->MCU_width); + if (tmp == 0) tmp = compptr->MCU_width; + compptr->last_col_width = tmp; + tmp = (int) (compptr->height_in_data_units % compptr->MCU_height); + if (tmp == 0) tmp = compptr->MCU_height; + compptr->last_row_height = tmp; + /* Prepare array describing MCU composition */ + mcublks = compptr->MCU_data_units; + if (cinfo->data_units_in_MCU + mcublks > D_MAX_DATA_UNITS_IN_MCU) + ERREXIT(cinfo, JERR_BAD_MCU_SIZE); + while (mcublks-- > 0) { + cinfo->MCU_membership[cinfo->data_units_in_MCU++] = ci; + } + } + + } +} + + +/* + * Initialize the input modules to read a scan of compressed data. + * The first call to this is done by jdmaster.c after initializing + * the entire decompressor (during jpeg_start_decompress). + * Subsequent calls come from consume_markers, below. + */ + +METHODDEF(void) +start_input_pass (j_decompress_ptr cinfo) +{ + per_scan_setup(cinfo); + (*cinfo->codec->start_input_pass) (cinfo); + cinfo->inputctl->consume_input = cinfo->codec->consume_data; +} + + +/* + * Finish up after inputting a compressed-data scan. + * This is called by the coefficient controller after it's read all + * the expected data of the scan. + */ + +METHODDEF(void) +finish_input_pass (j_decompress_ptr cinfo) +{ + cinfo->inputctl->consume_input = consume_markers; +} + + +/* + * Read JPEG markers before, between, or after compressed-data scans. + * Change state as necessary when a new scan is reached. + * Return value is JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI. + * + * The consume_input method pointer points either here or to the + * coefficient controller's consume_data routine, depending on whether + * we are reading a compressed data segment or inter-segment markers. + */ + +METHODDEF(int) +consume_markers (j_decompress_ptr cinfo) +{ + my_inputctl_ptr inputctl = (my_inputctl_ptr) cinfo->inputctl; + int val; + + if (inputctl->pub.eoi_reached) /* After hitting EOI, read no further */ + return JPEG_REACHED_EOI; + + val = (*cinfo->marker->read_markers) (cinfo); + + switch (val) { + case JPEG_REACHED_SOS: /* Found SOS */ + if (inputctl->inheaders) { /* 1st SOS */ + initial_setup(cinfo); + /* + * Initialize the decompression codec. We need to do this here so that + * any codec-specific fields and function pointers are available to + * the rest of the library. + */ + jinit_d_codec(cinfo); + inputctl->inheaders = FALSE; + /* Note: start_input_pass must be called by jdmaster.c + * before any more input can be consumed. jdapimin.c is + * responsible for enforcing this sequencing. + */ + } else { /* 2nd or later SOS marker */ + if (! inputctl->pub.has_multiple_scans) + ERREXIT(cinfo, JERR_EOI_EXPECTED); /* Oops, I wasn't expecting this! */ + start_input_pass(cinfo); + } + break; + case JPEG_REACHED_EOI: /* Found EOI */ + inputctl->pub.eoi_reached = TRUE; + if (inputctl->inheaders) { /* Tables-only datastream, apparently */ + if (cinfo->marker->saw_SOF) + ERREXIT(cinfo, JERR_SOF_NO_SOS); + } else { + /* Prevent infinite loop in coef ctlr's decompress_data routine + * if user set output_scan_number larger than number of scans. + */ + if (cinfo->output_scan_number > cinfo->input_scan_number) + cinfo->output_scan_number = cinfo->input_scan_number; + } + break; + case JPEG_SUSPENDED: + break; + } + + return val; +} + + +/* + * Reset state to begin a fresh datastream. + */ + +METHODDEF(void) +reset_input_controller (j_decompress_ptr cinfo) +{ + my_inputctl_ptr inputctl = (my_inputctl_ptr) cinfo->inputctl; + + inputctl->pub.consume_input = consume_markers; + inputctl->pub.has_multiple_scans = FALSE; /* "unknown" would be better */ + inputctl->pub.eoi_reached = FALSE; + inputctl->inheaders = TRUE; + /* Reset other modules */ + (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo); + (*cinfo->marker->reset_marker_reader) (cinfo); + /* Reset progression state -- would be cleaner if entropy decoder did this */ + cinfo->coef_bits = NULL; +} + + +/* + * Initialize the input controller module. + * This is called only once, when the decompression object is created. + */ + +GLOBAL(void) +jinit_input_controller (j_decompress_ptr cinfo) +{ + my_inputctl_ptr inputctl; + + /* Create subobject in permanent pool */ + inputctl = (my_inputctl_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + SIZEOF(my_input_controller)); + cinfo->inputctl = (struct jpeg_input_controller *) inputctl; + /* Initialize method pointers */ + inputctl->pub.consume_input = consume_markers; + inputctl->pub.reset_input_controller = reset_input_controller; + inputctl->pub.start_input_pass = start_input_pass; + inputctl->pub.finish_input_pass = finish_input_pass; + /* Initialize state: can't use reset_input_controller since we don't + * want to try to reset other modules yet. + */ + inputctl->pub.has_multiple_scans = FALSE; /* "unknown" would be better */ + inputctl->pub.eoi_reached = FALSE; + inputctl->inheaders = TRUE; +} diff --git a/gdcm/Utilities/gdcmjpeg/jdlhuff.c b/gdcm/Utilities/gdcmjpeg/jdlhuff.c new file mode 100644 index 0000000..2ee9f28 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jdlhuff.c @@ -0,0 +1,291 @@ +/* + * jdlhuff.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains Huffman entropy decoding routines for lossless JPEG. + * + * Much of the complexity here has to do with supporting input suspension. + * If the data source module demands suspension, we want to be able to back + * up to the start of the current MCU. To do this, we copy state variables + * into local working storage, and update them back to the permanent + * storage only upon successful completion of an MCU. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jlossls.h" /* Private declarations for lossless codec */ +#include "jdhuff.h" /* Declarations shared with jd*huff.c */ + + +#ifdef D_LOSSLESS_SUPPORTED + +typedef struct { + int ci, yoffset, MCU_width; +} lhd_output_ptr_info; + +/* + * Private entropy decoder object for lossless Huffman decoding. + */ + +typedef struct { + huffd_common_fields; /* Fields shared with other entropy decoders */ + + /* Pointers to derived tables (these workspaces have image lifespan) */ + d_derived_tbl * derived_tbls[NUM_HUFF_TBLS]; + + /* Precalculated info set up by start_pass for use in decode_mcus: */ + + /* Pointers to derived tables to be used for each data unit within an MCU */ + d_derived_tbl * cur_tbls[D_MAX_DATA_UNITS_IN_MCU]; + + /* Pointers to the proper output difference row for each group of data units + * within an MCU. For each component, there are Vi groups of Hi data units. + */ + JDIFFROW output_ptr[D_MAX_DATA_UNITS_IN_MCU]; + + /* Number of output pointers in use for the current MCU. This is the sum + * of all Vi in the MCU. + */ + int num_output_ptrs; + + /* Information used for positioning the output pointers within the output + * difference rows. + */ + lhd_output_ptr_info output_ptr_info[D_MAX_DATA_UNITS_IN_MCU]; + + /* Index of the proper output pointer for each data unit within an MCU */ + int output_ptr_index[D_MAX_DATA_UNITS_IN_MCU]; + +} lhuff_entropy_decoder; + +typedef lhuff_entropy_decoder * lhuff_entropy_ptr; + + +/* + * Initialize for a Huffman-compressed scan. + */ + +METHODDEF(void) +start_pass_lhuff_decoder (j_decompress_ptr cinfo) +{ + j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; + lhuff_entropy_ptr entropy = (lhuff_entropy_ptr) losslsd->entropy_private; + int ci, dctbl, sampn, ptrn, yoffset, xoffset; + jpeg_component_info * compptr; + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + dctbl = compptr->dc_tbl_no; + /* Make sure requested tables are present */ + if (dctbl < 0 || dctbl >= NUM_HUFF_TBLS || + cinfo->dc_huff_tbl_ptrs[dctbl] == NULL) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, dctbl); + /* Compute derived values for Huffman tables */ + /* We may do this more than once for a table, but it's not expensive */ + jpeg_make_d_derived_tbl(cinfo, TRUE, dctbl, + & entropy->derived_tbls[dctbl]); + } + + /* Precalculate decoding info for each sample in an MCU of this scan */ + for (sampn = 0, ptrn = 0; sampn < cinfo->data_units_in_MCU;) { + compptr = cinfo->cur_comp_info[cinfo->MCU_membership[sampn]]; + ci = compptr->component_index; + for (yoffset = 0; yoffset < compptr->MCU_height; yoffset++, ptrn++) { + /* Precalculate the setup info for each output pointer */ + entropy->output_ptr_info[ptrn].ci = ci; + entropy->output_ptr_info[ptrn].yoffset = yoffset; + entropy->output_ptr_info[ptrn].MCU_width = compptr->MCU_width; + for (xoffset = 0; xoffset < compptr->MCU_width; xoffset++, sampn++) { + /* Precalculate the output pointer index for each sample */ + entropy->output_ptr_index[sampn] = ptrn; + /* Precalculate which table to use for each sample */ + entropy->cur_tbls[sampn] = entropy->derived_tbls[compptr->dc_tbl_no]; + } + } + } + entropy->num_output_ptrs = ptrn; + + /* Initialize bitread state variables */ + entropy->bitstate.bits_left = 0; + entropy->bitstate.get_buffer = 0; /* unnecessary, but keeps Purify quiet */ + entropy->insufficient_data = FALSE; +} + + +/* + * Figure F.12: extend sign bit. + * On some machines, a shift and add will be faster than a table lookup. + */ + +#ifdef AVOID_TABLES + +#define HUFF_EXTEND(x,s) ((x) < (1<<((s)-1)) ? (x) + (((-1)<<(s)) + 1) : (x)) + +#else + +#define HUFF_EXTEND(x,s) ((x) < extend_test[s] ? (x) + extend_offset[s] : (x)) + +static const int extend_test[16] = /* entry n is 2**(n-1) */ + { 0, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, + 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000 }; + +static const int extend_offset[16] = /* entry n is (-1 << n) + 1 */ + { 0, ((-1)<<1) + 1, ((-1)<<2) + 1, ((-1)<<3) + 1, ((-1)<<4) + 1, + ((-1)<<5) + 1, ((-1)<<6) + 1, ((-1)<<7) + 1, ((-1)<<8) + 1, + ((-1)<<9) + 1, ((-1)<<10) + 1, ((-1)<<11) + 1, ((-1)<<12) + 1, + ((-1)<<13) + 1, ((-1)<<14) + 1, ((-1)<<15) + 1 }; + +#endif /* AVOID_TABLES */ + + +/* + * Check for a restart marker & resynchronize decoder. + * Returns FALSE if must suspend. + */ + +METHODDEF(boolean) +process_restart (j_decompress_ptr cinfo) +{ + j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; + lhuff_entropy_ptr entropy = (lhuff_entropy_ptr) losslsd->entropy_private; + /* int ci; */ + + /* Throw away any unused bits remaining in bit buffer; */ + /* include any full bytes in next_marker's count of discarded bytes */ + cinfo->marker->discarded_bytes += entropy->bitstate.bits_left / 8; + entropy->bitstate.bits_left = 0; + + /* Advance past the RSTn marker */ + if (! (*cinfo->marker->read_restart_marker) (cinfo)) + return FALSE; + + /* Reset out-of-data flag, unless read_restart_marker left us smack up + * against a marker. In that case we will end up treating the next data + * segment as empty, and we can avoid producing bogus output pixels by + * leaving the flag set. + */ + if (cinfo->unread_marker == 0) + entropy->insufficient_data = FALSE; + + return TRUE; +} + + +/* + * Decode and return nMCU's worth of Huffman-compressed differences. + * Each MCU is also disassembled and placed accordingly in diff_buf. + * + * MCU_col_num specifies the column of the first MCU being requested within + * the MCU-row. This tells us where to position the output row pointers in + * diff_buf. + * + * Returns the number of MCUs decoded. This may be less than nMCU if data + * source requested suspension. In that case no changes have been made to + * permanent state. (Exception: some output differences may already have + * been assigned. This is harmless for this module, since we'll just + * re-assign them on the next call.) + */ + +METHODDEF(JDIMENSION) +decode_mcus (j_decompress_ptr cinfo, JDIFFIMAGE diff_buf, + JDIMENSION MCU_row_num, JDIMENSION MCU_col_num, JDIMENSION nMCU) +{ + j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; + lhuff_entropy_ptr entropy = (lhuff_entropy_ptr) losslsd->entropy_private; + unsigned int mcu_num; + int sampn, ci, yoffset, MCU_width, ptrn; + BITREAD_STATE_VARS; + + /* Set output pointer locations based on MCU_col_num */ + for (ptrn = 0; ptrn < entropy->num_output_ptrs; ptrn++) { + ci = entropy->output_ptr_info[ptrn].ci; + yoffset = entropy->output_ptr_info[ptrn].yoffset; + MCU_width = entropy->output_ptr_info[ptrn].MCU_width; + entropy->output_ptr[ptrn] = + diff_buf[ci][MCU_row_num + yoffset] + (MCU_col_num * MCU_width); + } + + /* + * If we've run out of data, zero out the buffers and return. + * By resetting the undifferencer, the output samples will be CENTERJSAMPLE. + * + * NB: We should find a way to do this without interacting with the + * undifferencer module directly. + */ + if (entropy->insufficient_data) { + for (ptrn = 0; ptrn < entropy->num_output_ptrs; ptrn++) + jzero_far((void FAR *) entropy->output_ptr[ptrn], + nMCU * entropy->output_ptr_info[ptrn].MCU_width * SIZEOF(JDIFF)); + + (*losslsd->predict_process_restart) (cinfo); + } + + else { + + /* Load up working state */ + BITREAD_LOAD_STATE(cinfo,entropy->bitstate); + + /* Outer loop handles the number of MCU requested */ + + for (mcu_num = 0; mcu_num < nMCU; mcu_num++) { + + /* Inner loop handles the samples in the MCU */ + for (sampn = 0; sampn < cinfo->data_units_in_MCU; sampn++) { + d_derived_tbl * dctbl = entropy->cur_tbls[sampn]; + register int s, r; + + /* Section H.2.2: decode the sample difference */ + HUFF_DECODE(s, br_state, dctbl, return mcu_num, label1); + if (s) { + if (s == 16) /* special case: always output 32768 */ + s = 32768; + else { /* normal case: fetch subsequent bits */ + CHECK_BIT_BUFFER(br_state, s, return mcu_num); + r = GET_BITS(s); + s = HUFF_EXTEND(r, s); + } + } + + /* Output the sample difference */ + *entropy->output_ptr[entropy->output_ptr_index[sampn]]++ = (JDIFF) s; + } + + /* Completed MCU, so update state */ + BITREAD_SAVE_STATE(cinfo,entropy->bitstate); + } + } + + return nMCU; +} + + +/* + * Module initialization routine for lossless Huffman entropy decoding. + */ + +GLOBAL(void) +jinit_lhuff_decoder (j_decompress_ptr cinfo) +{ + j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; + lhuff_entropy_ptr entropy; + int i; + + entropy = (lhuff_entropy_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(lhuff_entropy_decoder)); + losslsd->entropy_private = (void *) entropy; + losslsd->entropy_start_pass = start_pass_lhuff_decoder; + losslsd->entropy_process_restart = process_restart; + losslsd->entropy_decode_mcus = decode_mcus; + + /* Mark tables unallocated */ + for (i = 0; i < NUM_HUFF_TBLS; i++) { + entropy->derived_tbls[i] = NULL; + } +} + +#endif /* D_LOSSLESS_SUPPORTED */ diff --git a/gdcm/Utilities/gdcmjpeg/jdlossls.c b/gdcm/Utilities/gdcmjpeg/jdlossls.c new file mode 100644 index 0000000..e9de17d --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jdlossls.c @@ -0,0 +1,98 @@ +/* + * jdlossls.c + * + * Copyright (C) 1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the control logic for the lossless JPEG decompressor. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jlossls.h" + + +#ifdef D_LOSSLESS_SUPPORTED + +/* + * Compute output image dimensions and related values. + */ + +METHODDEF(void) +calc_output_dimensions (j_decompress_ptr cinfo) +{ + /* Hardwire it to "no scaling" */ + cinfo->output_width = cinfo->image_width; + cinfo->output_height = cinfo->image_height; + /* jdinput.c has already initialized codec_data_unit to 1, + * and has computed unscaled downsampled_width and downsampled_height. + */ +} + + +/* + * Initialize for an input processing pass. + */ + +METHODDEF(void) +start_input_pass (j_decompress_ptr cinfo) +{ + j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; + + (*losslsd->entropy_start_pass) (cinfo); + (*losslsd->predict_start_pass) (cinfo); + (*losslsd->scaler_start_pass) (cinfo); + (*losslsd->diff_start_input_pass) (cinfo); +} + + +/* + * Initialize the lossless decompression codec. + * This is called only once, during master selection. + */ + +GLOBAL(void) +jinit_lossless_d_codec(j_decompress_ptr cinfo) +{ + j_lossless_d_ptr losslsd; + boolean use_c_buffer; + + /* Create subobject in permanent pool */ + losslsd = (j_lossless_d_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + SIZEOF(jpeg_lossless_d_codec)); + cinfo->codec = (struct jpeg_d_codec *) losslsd; + + /* Initialize sub-modules */ + /* Entropy decoding: either Huffman or arithmetic coding. */ + if (cinfo->arith_code) { +#ifdef WITH_ARITHMETIC_PATCH + jinit_arith_decoder(cinfo); +#else + ERREXIT(cinfo, JERR_ARITH_NOTIMPL); +#endif + } else { + jinit_lhuff_decoder(cinfo); + } + + /* Undifferencer */ + jinit_undifferencer(cinfo); + + /* Scaler */ + jinit_d_scaler(cinfo); + + use_c_buffer = cinfo->inputctl->has_multiple_scans || cinfo->buffered_image; + jinit_d_diff_controller(cinfo, use_c_buffer); + + /* Initialize method pointers. + * + * Note: consume_data, start_output_pass and decompress_data are + * assigned in jddiffct.c. + */ + losslsd->pub.calc_output_dimensions = calc_output_dimensions; + losslsd->pub.start_input_pass = start_input_pass; +} + +#endif /* D_LOSSLESS_SUPPORTED */ diff --git a/gdcm/Utilities/gdcmjpeg/jdlossy.c b/gdcm/Utilities/gdcmjpeg/jdlossy.c new file mode 100644 index 0000000..738c997 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jdlossy.c @@ -0,0 +1,228 @@ +/* + * jdlossy.c + * + * Copyright (C) 1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the control logic for the lossy JPEG decompressor. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jlossy.h" + + +/* + * Compute output image dimensions and related values. + */ + +METHODDEF(void) +calc_output_dimensions (j_decompress_ptr cinfo) +{ +#ifdef IDCT_SCALING_SUPPORTED + int ci; + jpeg_component_info *compptr; + + /* Compute actual output image dimensions and DCT scaling choices. */ + if (cinfo->scale_num * 8 <= cinfo->scale_denom) { + /* Provide 1/8 scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width, 8L); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height, 8L); + cinfo->min_codec_data_unit = 1; + } else if (cinfo->scale_num * 4 <= cinfo->scale_denom) { + /* Provide 1/4 scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width, 4L); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height, 4L); + cinfo->min_codec_data_unit = 2; + } else if (cinfo->scale_num * 2 <= cinfo->scale_denom) { + /* Provide 1/2 scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width, 2L); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height, 2L); + cinfo->min_codec_data_unit = 4; + } else { + /* Provide 1/1 scaling */ + cinfo->output_width = cinfo->image_width; + cinfo->output_height = cinfo->image_height; + cinfo->min_codec_data_unit = DCTSIZE; + } + /* In selecting the actual DCT scaling for each component, we try to + * scale up the chroma components via IDCT scaling rather than upsampling. + * This saves time if the upsampler gets to use 1:1 scaling. + * Note this code assumes that the supported DCT scalings are powers of 2. + */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + int ssize = cinfo->min_codec_data_unit; + while (ssize < DCTSIZE && + (compptr->h_samp_factor * ssize * 2 <= + cinfo->max_h_samp_factor * cinfo->min_codec_data_unit) && + (compptr->v_samp_factor * ssize * 2 <= + cinfo->max_v_samp_factor * cinfo->min_codec_data_unit)) { + ssize = ssize * 2; + } + compptr->codec_data_unit = ssize; + } + + /* Recompute downsampled dimensions of components; + * application needs to know these if using raw downsampled data. + */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Size in samples, after IDCT scaling */ + compptr->downsampled_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * + (long) (compptr->h_samp_factor * compptr->codec_data_unit), + (long) (cinfo->max_h_samp_factor * DCTSIZE)); + compptr->downsampled_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * + (long) (compptr->v_samp_factor * compptr->codec_data_unit), + (long) (cinfo->max_v_samp_factor * DCTSIZE)); + } + +#else /* !IDCT_SCALING_SUPPORTED */ + + /* Hardwire it to "no scaling" */ + cinfo->output_width = cinfo->image_width; + cinfo->output_height = cinfo->image_height; + /* jdinput.c has already initialized codec_data_unit to DCTSIZE, + * and has computed unscaled downsampled_width and downsampled_height. + */ + +#endif /* IDCT_SCALING_SUPPORTED */ +} + + +/* + * Save away a copy of the Q-table referenced by each component present + * in the current scan, unless already saved during a prior scan. + * + * In a multiple-scan JPEG file, the encoder could assign different components + * the same Q-table slot number, but change table definitions between scans + * so that each component uses a different Q-table. (The IJG encoder is not + * currently capable of doing this, but other encoders might.) Since we want + * to be able to dequantize all the components at the end of the file, this + * means that we have to save away the table actually used for each component. + * We do this by copying the table at the start of the first scan containing + * the component. + * The JPEG spec prohibits the encoder from changing the contents of a Q-table + * slot between scans of a component using that slot. If the encoder does so + * anyway, this decoder will simply use the Q-table values that were current + * at the start of the first scan for the component. + * + * The decompressor output side looks only at the saved quant tables, + * not at the current Q-table slots. + */ + +LOCAL(void) +latch_quant_tables (j_decompress_ptr cinfo) +{ + int ci, qtblno; + jpeg_component_info *compptr; + JQUANT_TBL * qtbl; + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* No work if we already saved Q-table for this component */ + if (compptr->quant_table != NULL) + continue; + /* Make sure specified quantization table is present */ + qtblno = compptr->quant_tbl_no; + if (qtblno < 0 || qtblno >= NUM_QUANT_TBLS || + cinfo->quant_tbl_ptrs[qtblno] == NULL) + ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, qtblno); + /* OK, save away the quantization table */ + qtbl = (JQUANT_TBL *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(JQUANT_TBL)); + MEMCOPY(qtbl, cinfo->quant_tbl_ptrs[qtblno], SIZEOF(JQUANT_TBL)); + compptr->quant_table = qtbl; + } +} + + +/* + * Initialize for an input processing pass. + */ + +METHODDEF(void) +start_input_pass (j_decompress_ptr cinfo) +{ + j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; + + latch_quant_tables(cinfo); + (*lossyd->entropy_start_pass) (cinfo); + (*lossyd->coef_start_input_pass) (cinfo); +} + + +/* + * Initialize for an output processing pass. + */ + +METHODDEF(void) +start_output_pass (j_decompress_ptr cinfo) +{ + j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; + + (*lossyd->idct_start_pass) (cinfo); + (*lossyd->coef_start_output_pass) (cinfo); +} + +/* + * Initialize the lossy decompression codec. + * This is called only once, during master selection. + */ + +GLOBAL(void) +jinit_lossy_d_codec (j_decompress_ptr cinfo) +{ + j_lossy_d_ptr lossyd; + boolean use_c_buffer; + + /* Create subobject in permanent pool */ + lossyd = (j_lossy_d_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + SIZEOF(jpeg_lossy_d_codec)); + cinfo->codec = (struct jpeg_d_codec *) lossyd; + + /* Initialize sub-modules */ + + /* Inverse DCT */ + jinit_inverse_dct(cinfo); + /* Entropy decoding: either Huffman or arithmetic coding. */ + if (cinfo->arith_code) { +#ifdef WITH_ARITHMETIC_PATCH + jinit_arith_decoder(cinfo); +#else + ERREXIT(cinfo, JERR_ARITH_NOTIMPL); +#endif + } else { + if (cinfo->process == JPROC_PROGRESSIVE) { +#ifdef D_PROGRESSIVE_SUPPORTED + jinit_phuff_decoder(cinfo); +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else + jinit_shuff_decoder(cinfo); + } + + use_c_buffer = cinfo->inputctl->has_multiple_scans || cinfo->buffered_image; + jinit_d_coef_controller(cinfo, use_c_buffer); + + /* Initialize method pointers. + * + * Note: consume_data and decompress_data are assigned in jdcoefct.c. + */ + lossyd->pub.calc_output_dimensions = calc_output_dimensions; + lossyd->pub.start_input_pass = start_input_pass; + lossyd->pub.start_output_pass = start_output_pass; +} diff --git a/gdcm/Utilities/gdcmjpeg/jdmainct.c b/gdcm/Utilities/gdcmjpeg/jdmainct.c new file mode 100644 index 0000000..43cb09b --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jdmainct.c @@ -0,0 +1,512 @@ +/* + * jdmainct.c + * + * Copyright (C) 1994-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the main buffer controller for decompression. + * The main buffer lies between the JPEG decompressor proper and the + * post-processor; it holds downsampled data in the JPEG colorspace. + * + * Note that this code is bypassed in raw-data mode, since the application + * supplies the equivalent of the main buffer in that case. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * In the current system design, the main buffer need never be a full-image + * buffer; any full-height buffers will be found inside the coefficient or + * postprocessing controllers. Nonetheless, the main controller is not + * trivial. Its responsibility is to provide context rows for upsampling/ + * rescaling, and doing this in an efficient fashion is a bit tricky. + * + * Postprocessor input data is counted in "row groups". A row group + * is defined to be (v_samp_factor * codec_data_unit / min_codec_data_unit) + * sample rows of each component. (We require codec_data_unit values to be + * chosen such that these numbers are integers. In practice codec_data_unit + * values will likely be powers of two, so we actually have the stronger + * condition that codec_data_unit / min_codec_data_unit is an integer.) + * Upsampling will typically produce max_v_samp_factor pixel rows from each + * row group (times any additional scale factor that the upsampler is + * applying). + * + * The decompression codec will deliver data to us one iMCU row at a time; + * each iMCU row contains v_samp_factor * codec_data_unit sample rows, or + * exactly min_codec_data_unit row groups. (This amount of data corresponds + * to one row of MCUs when the image is fully interleaved.) Note that the + * number of sample rows varies across components, but the number of row + * groups does not. Some garbage sample rows may be included in the last iMCU + * row at the bottom of the image. + * + * Depending on the vertical scaling algorithm used, the upsampler may need + * access to the sample row(s) above and below its current input row group. + * The upsampler is required to set need_context_rows TRUE at global selection + * time if so. When need_context_rows is FALSE, this controller can simply + * obtain one iMCU row at a time from the coefficient controller and dole it + * out as row groups to the postprocessor. + * + * When need_context_rows is TRUE, this controller guarantees that the buffer + * passed to postprocessing contains at least one row group's worth of samples + * above and below the row group(s) being processed. Note that the context + * rows "above" the first passed row group appear at negative row offsets in + * the passed buffer. At the top and bottom of the image, the required + * context rows are manufactured by duplicating the first or last real sample + * row; this avoids having special cases in the upsampling inner loops. + * + * The amount of context is fixed at one row group just because that's a + * convenient number for this controller to work with. The existing + * upsamplers really only need one sample row of context. An upsampler + * supporting arbitrary output rescaling might wish for more than one row + * group of context when shrinking the image; tough, we don't handle that. + * (This is justified by the assumption that downsizing will be handled mostly + * by adjusting the codec_data_unit values, so that the actual scale factor at + * the upsample step needn't be much less than one.) + * + * To provide the desired context, we have to retain the last two row groups + * of one iMCU row while reading in the next iMCU row. (The last row group + * can't be processed until we have another row group for its below-context, + * and so we have to save the next-to-last group too for its above-context.) + * We could do this most simply by copying data around in our buffer, but + * that'd be very slow. We can avoid copying any data by creating a rather + * strange pointer structure. Here's how it works. We allocate a workspace + * consisting of M+2 row groups (where M = min_codec_data_unit is the number + * of row groups per iMCU row). We create two sets of redundant pointers to + * the workspace. Labeling the physical row groups 0 to M+1, the synthesized + * pointer lists look like this: + * M+1 M-1 + * master pointer --> 0 master pointer --> 0 + * 1 1 + * ... ... + * M-3 M-3 + * M-2 M + * M-1 M+1 + * M M-2 + * M+1 M-1 + * 0 0 + * We read alternate iMCU rows using each master pointer; thus the last two + * row groups of the previous iMCU row remain un-overwritten in the workspace. + * The pointer lists are set up so that the required context rows appear to + * be adjacent to the proper places when we pass the pointer lists to the + * upsampler. + * + * The above pictures describe the normal state of the pointer lists. + * At top and bottom of the image, we diddle the pointer lists to duplicate + * the first or last sample row as necessary (this is cheaper than copying + * sample rows around). + * + * This scheme breaks down if M < 2, ie, min_codec_data_unit is 1. In that + * situation each iMCU row provides only one row group so the buffering logic + * must be different (eg, we must read two iMCU rows before we can emit the + * first row group). For now, we simply do not support providing context + * rows when min_codec_data_unit is 1. That combination seems unlikely to + * be worth providing --- if someone wants a 1/8th-size preview, they probably + * want it quick and dirty, so a context-free upsampler is sufficient. + */ + + +/* Private buffer controller object */ + +typedef struct { + struct jpeg_d_main_controller pub; /* public fields */ + + /* Pointer to allocated workspace (M or M+2 row groups). */ + JSAMPARRAY buffer[MAX_COMPONENTS]; + + boolean buffer_full; /* Have we gotten an iMCU row from decoder? */ + JDIMENSION rowgroup_ctr; /* counts row groups output to postprocessor */ + + /* Remaining fields are only used in the context case. */ + + /* These are the master pointers to the funny-order pointer lists. */ + JSAMPIMAGE xbuffer[2]; /* pointers to weird pointer lists */ + + int whichptr; /* indicates which pointer set is now in use */ + int context_state; /* process_data state machine status */ + JDIMENSION rowgroups_avail; /* row groups available to postprocessor */ + JDIMENSION iMCU_row_ctr; /* counts iMCU rows to detect image top/bot */ +} my_main_controller; + +typedef my_main_controller * my_main_ptr; + +/* context_state values: */ +#define CTX_PREPARE_FOR_IMCU 0 /* need to prepare for MCU row */ +#define CTX_PROCESS_IMCU 1 /* feeding iMCU to postprocessor */ +#define CTX_POSTPONED_ROW 2 /* feeding postponed row group */ + + +/* Forward declarations */ +METHODDEF(void) process_data_simple_main + JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf, + JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)); +METHODDEF(void) process_data_context_main + JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf, + JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)); +#ifdef QUANT_2PASS_SUPPORTED +METHODDEF(void) process_data_crank_post + JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf, + JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)); +#endif + + +LOCAL(void) +alloc_funny_pointers (j_decompress_ptr cinfo) +/* Allocate space for the funny pointer lists. + * This is done only once, not once per pass. + */ +{ + my_main_ptr mainPtr = (my_main_ptr) cinfo->main; + int ci, rgroup; + int M = cinfo->min_codec_data_unit; + jpeg_component_info *compptr; + JSAMPARRAY xbuf; + + /* Get top-level space for component array pointers. + * We alloc both arrays with one call to save a few cycles. + */ + mainPtr->xbuffer[0] = (JSAMPIMAGE) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + cinfo->num_components * 2 * SIZEOF(JSAMPARRAY)); + mainPtr->xbuffer[1] = mainPtr->xbuffer[0] + cinfo->num_components; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + rgroup = (compptr->v_samp_factor * compptr->codec_data_unit) / + cinfo->min_codec_data_unit; /* height of a row group of component */ + /* Get space for pointer lists --- M+4 row groups in each list. + * We alloc both pointer lists with one call to save a few cycles. + */ + xbuf = (JSAMPARRAY) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + 2 * (rgroup * (M + 4)) * SIZEOF(JSAMPROW)); + xbuf += rgroup; /* want one row group at negative offsets */ + mainPtr->xbuffer[0][ci] = xbuf; + xbuf += rgroup * (M + 4); + mainPtr->xbuffer[1][ci] = xbuf; + } +} + + +LOCAL(void) +make_funny_pointers (j_decompress_ptr cinfo) +/* Create the funny pointer lists discussed in the comments above. + * The actual workspace is already allocated (in mainPtr->buffer), + * and the space for the pointer lists is allocated too. + * This routine just fills in the curiously ordered lists. + * This will be repeated at the beginning of each pass. + */ +{ + my_main_ptr mainPtr = (my_main_ptr) cinfo->main; + int ci, i, rgroup; + int M = cinfo->min_codec_data_unit; + jpeg_component_info *compptr; + JSAMPARRAY buf, xbuf0, xbuf1; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + rgroup = (compptr->v_samp_factor * compptr->codec_data_unit) / + cinfo->min_codec_data_unit; /* height of a row group of component */ + xbuf0 = mainPtr->xbuffer[0][ci]; + xbuf1 = mainPtr->xbuffer[1][ci]; + /* First copy the workspace pointers as-is */ + buf = mainPtr->buffer[ci]; + for (i = 0; i < rgroup * (M + 2); i++) { + xbuf0[i] = xbuf1[i] = buf[i]; + } + /* In the second list, put the last four row groups in swapped order */ + for (i = 0; i < rgroup * 2; i++) { + xbuf1[rgroup*(M-2) + i] = buf[rgroup*M + i]; + xbuf1[rgroup*M + i] = buf[rgroup*(M-2) + i]; + } + /* The wraparound pointers at top and bottom will be filled later + * (see set_wraparound_pointers, below). Initially we want the "above" + * pointers to duplicate the first actual data line. This only needs + * to happen in xbuffer[0]. + */ + for (i = 0; i < rgroup; i++) { + xbuf0[i - rgroup] = xbuf0[0]; + } + } +} + + +LOCAL(void) +set_wraparound_pointers (j_decompress_ptr cinfo) +/* Set up the "wraparound" pointers at top and bottom of the pointer lists. + * This changes the pointer list state from top-of-image to the normal state. + */ +{ + my_main_ptr mainPtr = (my_main_ptr) cinfo->main; + int ci, i, rgroup; + int M = cinfo->min_codec_data_unit; + jpeg_component_info *compptr; + JSAMPARRAY xbuf0, xbuf1; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + rgroup = (compptr->v_samp_factor * compptr->codec_data_unit) / + cinfo->min_codec_data_unit; /* height of a row group of component */ + xbuf0 = mainPtr->xbuffer[0][ci]; + xbuf1 = mainPtr->xbuffer[1][ci]; + for (i = 0; i < rgroup; i++) { + xbuf0[i - rgroup] = xbuf0[rgroup*(M+1) + i]; + xbuf1[i - rgroup] = xbuf1[rgroup*(M+1) + i]; + xbuf0[rgroup*(M+2) + i] = xbuf0[i]; + xbuf1[rgroup*(M+2) + i] = xbuf1[i]; + } + } +} + + +LOCAL(void) +set_bottom_pointers (j_decompress_ptr cinfo) +/* Change the pointer lists to duplicate the last sample row at the bottom + * of the image. whichptr indicates which xbuffer holds the final iMCU row. + * Also sets rowgroups_avail to indicate number of nondummy row groups in row. + */ +{ + my_main_ptr mainPtr = (my_main_ptr) cinfo->main; + int ci, i, rgroup, iMCUheight, rows_left; + jpeg_component_info *compptr; + JSAMPARRAY xbuf; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Count sample rows in one iMCU row and in one row group */ + iMCUheight = compptr->v_samp_factor * compptr->codec_data_unit; + rgroup = iMCUheight / cinfo->min_codec_data_unit; + /* Count nondummy sample rows remaining for this component */ + rows_left = (int) (compptr->downsampled_height % (JDIMENSION) iMCUheight); + if (rows_left == 0) rows_left = iMCUheight; + /* Count nondummy row groups. Should get same answer for each component, + * so we need only do it once. + */ + if (ci == 0) { + mainPtr->rowgroups_avail = (JDIMENSION) ((rows_left-1) / rgroup + 1); + } + /* Duplicate the last real sample row rgroup*2 times; this pads out the + * last partial rowgroup and ensures at least one full rowgroup of context. + */ + xbuf = mainPtr->xbuffer[mainPtr->whichptr][ci]; + for (i = 0; i < rgroup * 2; i++) { + xbuf[rows_left + i] = xbuf[rows_left-1]; + } + } +} + + +/* + * Initialize for a processing pass. + */ + +METHODDEF(void) +start_pass_main (j_decompress_ptr cinfo, J_BUF_MODE pass_mode) +{ + my_main_ptr mainPtr = (my_main_ptr) cinfo->main; + + switch (pass_mode) { + case JBUF_PASS_THRU: + if (cinfo->upsample->need_context_rows) { + mainPtr->pub.process_data = process_data_context_main; + make_funny_pointers(cinfo); /* Create the xbuffer[] lists */ + mainPtr->whichptr = 0; /* Read first iMCU row into xbuffer[0] */ + mainPtr->context_state = CTX_PREPARE_FOR_IMCU; + mainPtr->iMCU_row_ctr = 0; + } else { + /* Simple case with no context needed */ + mainPtr->pub.process_data = process_data_simple_main; + } + mainPtr->buffer_full = FALSE; /* Mark buffer empty */ + mainPtr->rowgroup_ctr = 0; + break; +#ifdef QUANT_2PASS_SUPPORTED + case JBUF_CRANK_DEST: + /* For last pass of 2-pass quantization, just crank the postprocessor */ + mainPtr->pub.process_data = process_data_crank_post; + break; +#endif + default: + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + break; + } +} + + +/* + * Process some data. + * This handles the simple case where no context is required. + */ + +METHODDEF(void) +process_data_simple_main (j_decompress_ptr cinfo, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +{ + my_main_ptr mainPtr = (my_main_ptr) cinfo->main; + JDIMENSION rowgroups_avail; + + /* Read input data if we haven't filled the main buffer yet */ + if (! mainPtr->buffer_full) { + if (! (*cinfo->codec->decompress_data) (cinfo, mainPtr->buffer)) + return; /* suspension forced, can do nothing more */ + mainPtr->buffer_full = TRUE; /* OK, we have an iMCU row to work with */ + } + + /* There are always min_codec_data_unit row groups in an iMCU row. */ + rowgroups_avail = (JDIMENSION) cinfo->min_codec_data_unit; + /* Note: at the bottom of the image, we may pass extra garbage row groups + * to the postprocessor. The postprocessor has to check for bottom + * of image anyway (at row resolution), so no point in us doing it too. + */ + + /* Feed the postprocessor */ + (*cinfo->post->post_process_data) (cinfo, mainPtr->buffer, + &mainPtr->rowgroup_ctr, rowgroups_avail, + output_buf, out_row_ctr, out_rows_avail); + + /* Has postprocessor consumed all the data yet? If so, mark buffer empty */ + if (mainPtr->rowgroup_ctr >= rowgroups_avail) { + mainPtr->buffer_full = FALSE; + mainPtr->rowgroup_ctr = 0; + } +} + + +/* + * Process some data. + * This handles the case where context rows must be provided. + */ + +METHODDEF(void) +process_data_context_main (j_decompress_ptr cinfo, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +{ + my_main_ptr mainPtr = (my_main_ptr) cinfo->main; + + /* Read input data if we haven't filled the main buffer yet */ + if (! mainPtr->buffer_full) { + if (! (*cinfo->codec->decompress_data) (cinfo, + mainPtr->xbuffer[mainPtr->whichptr])) + return; /* suspension forced, can do nothing more */ + mainPtr->buffer_full = TRUE; /* OK, we have an iMCU row to work with */ + mainPtr->iMCU_row_ctr++; /* count rows received */ + } + + /* Postprocessor typically will not swallow all the input data it is handed + * in one call (due to filling the output buffer first). Must be prepared + * to exit and restart. This switch lets us keep track of how far we got. + * Note that each case falls through to the next on successful completion. + */ + switch (mainPtr->context_state) { + case CTX_POSTPONED_ROW: + /* Call postprocessor using previously set pointers for postponed row */ + (*cinfo->post->post_process_data) (cinfo, mainPtr->xbuffer[mainPtr->whichptr], + &mainPtr->rowgroup_ctr, mainPtr->rowgroups_avail, + output_buf, out_row_ctr, out_rows_avail); + if (mainPtr->rowgroup_ctr < mainPtr->rowgroups_avail) + return; /* Need to suspend */ + mainPtr->context_state = CTX_PREPARE_FOR_IMCU; + if (*out_row_ctr >= out_rows_avail) + return; /* Postprocessor exactly filled output buf */ + /*FALLTHROUGH*/ + case CTX_PREPARE_FOR_IMCU: + /* Prepare to process first M-1 row groups of this iMCU row */ + mainPtr->rowgroup_ctr = 0; + mainPtr->rowgroups_avail = (JDIMENSION) (cinfo->min_codec_data_unit - 1); + /* Check for bottom of image: if so, tweak pointers to "duplicate" + * the last sample row, and adjust rowgroups_avail to ignore padding rows. + */ + if (mainPtr->iMCU_row_ctr == cinfo->total_iMCU_rows) + set_bottom_pointers(cinfo); + mainPtr->context_state = CTX_PROCESS_IMCU; + /*FALLTHROUGH*/ + case CTX_PROCESS_IMCU: + /* Call postprocessor using previously set pointers */ + (*cinfo->post->post_process_data) (cinfo, mainPtr->xbuffer[mainPtr->whichptr], + &mainPtr->rowgroup_ctr, mainPtr->rowgroups_avail, + output_buf, out_row_ctr, out_rows_avail); + if (mainPtr->rowgroup_ctr < mainPtr->rowgroups_avail) + return; /* Need to suspend */ + /* After the first iMCU, change wraparound pointers to normal state */ + if (mainPtr->iMCU_row_ctr == 1) + set_wraparound_pointers(cinfo); + /* Prepare to load new iMCU row using other xbuffer list */ + mainPtr->whichptr ^= 1; /* 0=>1 or 1=>0 */ + mainPtr->buffer_full = FALSE; + /* Still need to process last row group of this iMCU row, */ + /* which is saved at index M+1 of the other xbuffer */ + mainPtr->rowgroup_ctr = (JDIMENSION) (cinfo->min_codec_data_unit + 1); + mainPtr->rowgroups_avail = (JDIMENSION) (cinfo->min_codec_data_unit + 2); + mainPtr->context_state = CTX_POSTPONED_ROW; + } +} + + +/* + * Process some data. + * Final pass of two-pass quantization: just call the postprocessor. + * Source data will be the postprocessor controller's internal buffer. + */ + +#ifdef QUANT_2PASS_SUPPORTED + +METHODDEF(void) +process_data_crank_post (j_decompress_ptr cinfo, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +{ + (*cinfo->post->post_process_data) (cinfo, (JSAMPIMAGE) NULL, + (JDIMENSION *) NULL, (JDIMENSION) 0, + output_buf, out_row_ctr, out_rows_avail); +} + +#endif /* QUANT_2PASS_SUPPORTED */ + + +/* + * Initialize main buffer controller. + */ + +GLOBAL(void) +jinit_d_main_controller (j_decompress_ptr cinfo, boolean need_full_buffer) +{ + my_main_ptr mainPtr; + int ci, rgroup, ngroups; + jpeg_component_info *compptr; + + mainPtr = (my_main_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_main_controller)); + cinfo->main = (struct jpeg_d_main_controller *) mainPtr; + mainPtr->pub.start_pass = start_pass_main; + + if (need_full_buffer) /* shouldn't happen */ + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + + /* Allocate the workspace. + * ngroups is the number of row groups we need. + */ + if (cinfo->upsample->need_context_rows) { + if (cinfo->min_codec_data_unit < 2) /* unsupported, see comments above */ + ERREXIT(cinfo, JERR_NOTIMPL); + alloc_funny_pointers(cinfo); /* Alloc space for xbuffer[] lists */ + ngroups = cinfo->min_codec_data_unit + 2; + } else { + ngroups = cinfo->min_codec_data_unit; + } + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + rgroup = (compptr->v_samp_factor * compptr->codec_data_unit) / + cinfo->min_codec_data_unit; /* height of a row group of component */ + mainPtr->buffer[ci] = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + compptr->width_in_data_units * compptr->codec_data_unit, + (JDIMENSION) (rgroup * ngroups)); + } +} diff --git a/gdcm/Utilities/gdcmjpeg/jdmarker.c b/gdcm/Utilities/gdcmjpeg/jdmarker.c new file mode 100644 index 0000000..8cddcc0 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jdmarker.c @@ -0,0 +1,1370 @@ +/* + * jdmarker.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to decode JPEG datastream markers. + * Most of the complexity arises from our desire to support input + * suspension: if not all of the data for a marker is available, + * we must exit back to the application. On resumption, we reprocess + * the marker. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +typedef enum { /* JPEG marker codes */ + M_SOF0 = 0xc0, + M_SOF1 = 0xc1, + M_SOF2 = 0xc2, + M_SOF3 = 0xc3, + + M_SOF5 = 0xc5, + M_SOF6 = 0xc6, + M_SOF7 = 0xc7, + + M_JPG = 0xc8, + M_SOF9 = 0xc9, + M_SOF10 = 0xca, + M_SOF11 = 0xcb, + + M_SOF13 = 0xcd, + M_SOF14 = 0xce, + M_SOF15 = 0xcf, + + M_DHT = 0xc4, + + M_DAC = 0xcc, + + M_RST0 = 0xd0, + M_RST1 = 0xd1, + M_RST2 = 0xd2, + M_RST3 = 0xd3, + M_RST4 = 0xd4, + M_RST5 = 0xd5, + M_RST6 = 0xd6, + M_RST7 = 0xd7, + + M_SOI = 0xd8, + M_EOI = 0xd9, + M_SOS = 0xda, + M_DQT = 0xdb, + M_DNL = 0xdc, + M_DRI = 0xdd, + M_DHP = 0xde, + M_EXP = 0xdf, + + M_APP0 = 0xe0, + M_APP1 = 0xe1, + M_APP2 = 0xe2, + M_APP3 = 0xe3, + M_APP4 = 0xe4, + M_APP5 = 0xe5, + M_APP6 = 0xe6, + M_APP7 = 0xe7, + M_APP8 = 0xe8, + M_APP9 = 0xe9, + M_APP10 = 0xea, + M_APP11 = 0xeb, + M_APP12 = 0xec, + M_APP13 = 0xed, + M_APP14 = 0xee, + M_APP15 = 0xef, + + M_JPG0 = 0xf0, + M_JPG13 = 0xfd, + M_COM = 0xfe, + + M_TEM = 0x01, + + M_ERROR = 0x100 +} JPEG_MARKER; + + +/* Private state */ + +typedef struct { + struct jpeg_marker_reader pub; /* public fields */ + + /* Application-overridable marker processing methods */ + jpeg_marker_parser_method process_COM; + jpeg_marker_parser_method process_APPn[16]; + + /* Limit on marker data length to save for each marker type */ + unsigned int length_limit_COM; + unsigned int length_limit_APPn[16]; + + /* Status of COM/APPn marker saving */ + jpeg_saved_marker_ptr cur_marker; /* NULL if not processing a marker */ + unsigned int bytes_read; /* data bytes read so far in marker */ + /* Note: cur_marker is not linked into marker_list until it's all read. */ +} my_marker_reader; + +typedef my_marker_reader * my_marker_ptr; + + +/* + * Macros for fetching data from the data source module. + * + * At all times, cinfo->src->next_input_byte and ->bytes_in_buffer reflect + * the current restart point; we update them only when we have reached a + * suitable place to restart if a suspension occurs. + */ + +/* Declare and initialize local copies of input pointer/count */ +#define INPUT_VARS(cinfo) \ + struct jpeg_source_mgr * datasrc = (cinfo)->src; \ + const JOCTET * next_input_byte = datasrc->next_input_byte; \ + size_t bytes_in_buffer = datasrc->bytes_in_buffer + +/* Unload the local copies --- do this only at a restart boundary */ +#define INPUT_SYNC(cinfo) \ + ( datasrc->next_input_byte = next_input_byte, \ + datasrc->bytes_in_buffer = bytes_in_buffer ) + +/* Reload the local copies --- used only in MAKE_BYTE_AVAIL */ +#define INPUT_RELOAD(cinfo) \ + ( next_input_byte = datasrc->next_input_byte, \ + bytes_in_buffer = datasrc->bytes_in_buffer ) + +/* Internal macro for INPUT_BYTE and INPUT_2BYTES: make a byte available. + * Note we do *not* do INPUT_SYNC before calling fill_input_buffer, + * but we must reload the local copies after a successful fill. + */ +#define MAKE_BYTE_AVAIL(cinfo,action) \ + if (bytes_in_buffer == 0) { \ + if (! (*datasrc->fill_input_buffer) (cinfo)) \ + { action; } \ + INPUT_RELOAD(cinfo); \ + } + +/* Read a byte into variable V. + * If must suspend, take the specified action (typically "return FALSE"). + */ +#define INPUT_BYTE(cinfo,V,action) \ + MAKESTMT( MAKE_BYTE_AVAIL(cinfo,action); \ + bytes_in_buffer--; \ + V = GETJOCTET(*next_input_byte++); ) + +/* As above, but read two bytes interpreted as an unsigned 16-bit integer. + * V should be declared unsigned int or perhaps INT32. + */ +#define INPUT_2BYTES(cinfo,V,action) \ + MAKESTMT( MAKE_BYTE_AVAIL(cinfo,action); \ + bytes_in_buffer--; \ + V = ((unsigned int) GETJOCTET(*next_input_byte++)) << 8; \ + MAKE_BYTE_AVAIL(cinfo,action); \ + bytes_in_buffer--; \ + V += GETJOCTET(*next_input_byte++); ) + + +/* + * Routines to process JPEG markers. + * + * Entry condition: JPEG marker itself has been read and its code saved + * in cinfo->unread_marker; input restart point is just after the marker. + * + * Exit: if return TRUE, have read and processed any parameters, and have + * updated the restart point to point after the parameters. + * If return FALSE, was forced to suspend before reaching end of + * marker parameters; restart point has not been moved. Same routine + * will be called again after application supplies more input data. + * + * This approach to suspension assumes that all of a marker's parameters + * can fit into a single input bufferload. This should hold for "normal" + * markers. Some COM/APPn markers might have large parameter segments + * that might not fit. If we are simply dropping such a marker, we use + * skip_input_data to get past it, and thereby put the problem on the + * source manager's shoulders. If we are saving the marker's contents + * into memory, we use a slightly different convention: when forced to + * suspend, the marker processor updates the restart point to the end of + * what it's consumed (ie, the end of the buffer) before returning FALSE. + * On resumption, cinfo->unread_marker still contains the marker code, + * but the data source will point to the next chunk of marker data. + * The marker processor must retain internal state to deal with this. + * + * Note that we don't bother to avoid duplicate trace messages if a + * suspension occurs within marker parameters. Other side effects + * require more care. + */ + + +LOCAL(boolean) +get_soi (j_decompress_ptr cinfo) +/* Process an SOI marker */ +{ + int i; + + TRACEMS(cinfo, 1, JTRC_SOI); + + if (cinfo->marker->saw_SOI) + ERREXIT(cinfo, JERR_SOI_DUPLICATE); + + /* Reset all parameters that are defined to be reset by SOI */ + + for (i = 0; i < NUM_ARITH_TBLS; i++) { + cinfo->arith_dc_L[i] = 0; + cinfo->arith_dc_U[i] = 1; + cinfo->arith_ac_K[i] = 5; + } + cinfo->restart_interval = 0; + + /* Set initial assumptions for colorspace etc */ + + cinfo->jpeg_color_space = JCS_UNKNOWN; + cinfo->CCIR601_sampling = FALSE; /* Assume non-CCIR sampling??? */ + + cinfo->saw_JFIF_marker = FALSE; + cinfo->JFIF_major_version = 1; /* set default JFIF APP0 values */ + cinfo->JFIF_minor_version = 1; + cinfo->density_unit = 0; + cinfo->X_density = 1; + cinfo->Y_density = 1; + cinfo->saw_Adobe_marker = FALSE; + cinfo->Adobe_transform = 0; + + cinfo->marker->saw_SOI = TRUE; + + return TRUE; +} + + +LOCAL(boolean) +get_sof (j_decompress_ptr cinfo, J_CODEC_PROCESS process, boolean is_arith, + int data_unit) +/* Process a SOFn marker */ +{ + INT32 length; + int c, ci; + jpeg_component_info * compptr; + INPUT_VARS(cinfo); + + cinfo->data_unit = data_unit; + cinfo->process = process; + cinfo->arith_code = is_arith; + + INPUT_2BYTES(cinfo, length, return FALSE); + + INPUT_BYTE(cinfo, cinfo->data_precision, return FALSE); + INPUT_2BYTES(cinfo, cinfo->image_height, return FALSE); + INPUT_2BYTES(cinfo, cinfo->image_width, return FALSE); + INPUT_BYTE(cinfo, cinfo->num_components, return FALSE); + + length -= 8; + + TRACEMS4(cinfo, 1, JTRC_SOF, cinfo->unread_marker, + (int) cinfo->image_width, (int) cinfo->image_height, + cinfo->num_components); + + if (cinfo->marker->saw_SOF) + ERREXIT(cinfo, JERR_SOF_DUPLICATE); + + /* We don't support files in which the image height is initially specified */ + /* as 0 and is later redefined by DNL. As long as we have to check that, */ + /* might as well have a general sanity check. */ + if (cinfo->image_height <= 0 || cinfo->image_width <= 0 + || cinfo->num_components <= 0) + ERREXIT(cinfo, JERR_EMPTY_IMAGE); + + if (length != (cinfo->num_components * 3)) + ERREXIT(cinfo, JERR_BAD_LENGTH); + + if (cinfo->comp_info == NULL) /* do only once, even if suspend */ + cinfo->comp_info = (jpeg_component_info *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + cinfo->num_components * SIZEOF(jpeg_component_info)); + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + compptr->component_index = ci; + INPUT_BYTE(cinfo, compptr->component_id, return FALSE); + INPUT_BYTE(cinfo, c, return FALSE); + compptr->h_samp_factor = (c >> 4) & 15; + compptr->v_samp_factor = (c ) & 15; + INPUT_BYTE(cinfo, compptr->quant_tbl_no, return FALSE); + + TRACEMS4(cinfo, 1, JTRC_SOF_COMPONENT, + compptr->component_id, compptr->h_samp_factor, + compptr->v_samp_factor, compptr->quant_tbl_no); + } + + cinfo->marker->saw_SOF = TRUE; + + INPUT_SYNC(cinfo); + return TRUE; +} + + +LOCAL(boolean) +get_sos (j_decompress_ptr cinfo) +/* Process a SOS marker */ +{ + INT32 length; + int i, ci, n, c, cc; + jpeg_component_info * compptr; + INPUT_VARS(cinfo); + + if (! cinfo->marker->saw_SOF) + ERREXIT(cinfo, JERR_SOS_NO_SOF); + + INPUT_2BYTES(cinfo, length, return FALSE); + + INPUT_BYTE(cinfo, n, return FALSE); /* Number of components */ + + TRACEMS1(cinfo, 1, JTRC_SOS, n); + + if (length != (n * 2 + 6) || n < 1 || n > MAX_COMPS_IN_SCAN) + ERREXIT(cinfo, JERR_BAD_LENGTH); + + cinfo->comps_in_scan = n; + + /* Collect the component-spec parameters */ + + for (i = 0; i < n; i++) { + INPUT_BYTE(cinfo, cc, return FALSE); + INPUT_BYTE(cinfo, c, return FALSE); + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + if (cc == compptr->component_id) + goto id_found; + } + + ERREXIT1(cinfo, JERR_BAD_COMPONENT_ID, cc); + + id_found: + + cinfo->cur_comp_info[i] = compptr; + compptr->dc_tbl_no = (c >> 4) & 15; + compptr->ac_tbl_no = (c ) & 15; + + TRACEMS3(cinfo, 1, JTRC_SOS_COMPONENT, cc, + compptr->dc_tbl_no, compptr->ac_tbl_no); + } + + /* Collect the additional scan parameters Ss, Se, Ah/Al. */ + INPUT_BYTE(cinfo, c, return FALSE); + cinfo->Ss = c; + INPUT_BYTE(cinfo, c, return FALSE); + cinfo->Se = c; + INPUT_BYTE(cinfo, c, return FALSE); + cinfo->Ah = (c >> 4) & 15; + cinfo->Al = (c ) & 15; + + TRACEMS4(cinfo, 1, JTRC_SOS_PARAMS, cinfo->Ss, cinfo->Se, + cinfo->Ah, cinfo->Al); + + /* Prepare to scan data & restart markers */ + cinfo->marker->next_restart_num = 0; + + /* Count another SOS marker */ + cinfo->input_scan_number++; + + INPUT_SYNC(cinfo); + return TRUE; +} + + +#ifdef D_ARITH_CODING_SUPPORTED + +LOCAL(boolean) +get_dac (j_decompress_ptr cinfo) +/* Process a DAC marker */ +{ + INT32 length; + int index, val; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + + while (length > 0) { + INPUT_BYTE(cinfo, index, return FALSE); + INPUT_BYTE(cinfo, val, return FALSE); + + length -= 2; + + TRACEMS2(cinfo, 1, JTRC_DAC, index, val); + + if (index < 0 || index >= (2*NUM_ARITH_TBLS)) + ERREXIT1(cinfo, JERR_DAC_INDEX, index); + + if (index >= NUM_ARITH_TBLS) { /* define AC table */ + cinfo->arith_ac_K[index-NUM_ARITH_TBLS] = (UINT8) val; + } else { /* define DC table */ + cinfo->arith_dc_L[index] = (UINT8) (val & 0x0F); + cinfo->arith_dc_U[index] = (UINT8) (val >> 4); + if (cinfo->arith_dc_L[index] > cinfo->arith_dc_U[index]) + ERREXIT1(cinfo, JERR_DAC_VALUE, val); + } + } + + if (length != 0) + ERREXIT(cinfo, JERR_BAD_LENGTH); + + INPUT_SYNC(cinfo); + return TRUE; +} + +#else /* ! D_ARITH_CODING_SUPPORTED */ + +#define get_dac(cinfo) skip_variable(cinfo) + +#endif /* D_ARITH_CODING_SUPPORTED */ + + +LOCAL(boolean) +get_dht (j_decompress_ptr cinfo) +/* Process a DHT marker */ +{ + INT32 length; + UINT8 bits[17]; + UINT8 huffval[256]; + int i, index, count; + JHUFF_TBL **htblptr; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + + while (length > 16) { + INPUT_BYTE(cinfo, index, return FALSE); + + TRACEMS1(cinfo, 1, JTRC_DHT, index); + + bits[0] = 0; + count = 0; + for (i = 1; i <= 16; i++) { + INPUT_BYTE(cinfo, bits[i], return FALSE); + count += bits[i]; + } + + length -= 1 + 16; + + TRACEMS8(cinfo, 2, JTRC_HUFFBITS, + bits[1], bits[2], bits[3], bits[4], + bits[5], bits[6], bits[7], bits[8]); + TRACEMS8(cinfo, 2, JTRC_HUFFBITS, + bits[9], bits[10], bits[11], bits[12], + bits[13], bits[14], bits[15], bits[16]); + + /* Here we just do minimal validation of the counts to avoid walking + * off the end of our table space. jdhuff.c will check more carefully. + */ + if (count > 256 || ((INT32) count) > length) + ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); + + for (i = 0; i < count; i++) + INPUT_BYTE(cinfo, huffval[i], return FALSE); + + length -= count; + + if (index & 0x10) { /* AC table definition */ + index -= 0x10; + htblptr = &cinfo->ac_huff_tbl_ptrs[index]; + } else { /* DC table definition */ + htblptr = &cinfo->dc_huff_tbl_ptrs[index]; + } + + if (index < 0 || index >= NUM_HUFF_TBLS) + ERREXIT1(cinfo, JERR_DHT_INDEX, index); + + if (*htblptr == NULL) + *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo); + + MEMCOPY((*htblptr)->bits, bits, SIZEOF((*htblptr)->bits)); + MEMCOPY((*htblptr)->huffval, huffval, SIZEOF((*htblptr)->huffval)); + } + + if (length != 0) + ERREXIT(cinfo, JERR_BAD_LENGTH); + + INPUT_SYNC(cinfo); + return TRUE; +} + + +LOCAL(boolean) +get_dqt (j_decompress_ptr cinfo) +/* Process a DQT marker */ +{ + INT32 length; + int n, i, prec; + unsigned int tmp; + JQUANT_TBL *quant_ptr; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + + while (length > 0) { + INPUT_BYTE(cinfo, n, return FALSE); + prec = n >> 4; + n &= 0x0F; + + TRACEMS2(cinfo, 1, JTRC_DQT, n, prec); + + if (n >= NUM_QUANT_TBLS) + ERREXIT1(cinfo, JERR_DQT_INDEX, n); + + if (cinfo->quant_tbl_ptrs[n] == NULL) + cinfo->quant_tbl_ptrs[n] = jpeg_alloc_quant_table((j_common_ptr) cinfo); + quant_ptr = cinfo->quant_tbl_ptrs[n]; + + for (i = 0; i < DCTSIZE2; i++) { + if (prec) + INPUT_2BYTES(cinfo, tmp, return FALSE); + else + INPUT_BYTE(cinfo, tmp, return FALSE); + /* We convert the zigzag-order table to natural array order. */ + quant_ptr->quantval[jpeg_natural_order[i]] = (UINT16) tmp; + } + + if (cinfo->err->trace_level >= 2) { + for (i = 0; i < DCTSIZE2; i += 8) { + TRACEMS8(cinfo, 2, JTRC_QUANTVALS, + quant_ptr->quantval[i], quant_ptr->quantval[i+1], + quant_ptr->quantval[i+2], quant_ptr->quantval[i+3], + quant_ptr->quantval[i+4], quant_ptr->quantval[i+5], + quant_ptr->quantval[i+6], quant_ptr->quantval[i+7]); + } + } + + length -= DCTSIZE2+1; + if (prec) length -= DCTSIZE2; + } + + if (length != 0) + ERREXIT(cinfo, JERR_BAD_LENGTH); + + INPUT_SYNC(cinfo); + return TRUE; +} + + +LOCAL(boolean) +get_dri (j_decompress_ptr cinfo) +/* Process a DRI marker */ +{ + INT32 length; + unsigned int tmp; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + + if (length != 4) + ERREXIT(cinfo, JERR_BAD_LENGTH); + + INPUT_2BYTES(cinfo, tmp, return FALSE); + + TRACEMS1(cinfo, 1, JTRC_DRI, tmp); + + cinfo->restart_interval = tmp; + + INPUT_SYNC(cinfo); + return TRUE; +} + + +/* + * Routines for processing APPn and COM markers. + * These are either saved in memory or discarded, per application request. + * APP0 and APP14 are specially checked to see if they are + * JFIF and Adobe markers, respectively. + */ + +#define APP0_DATA_LEN 14 /* Length of interesting data in APP0 */ +#define APP14_DATA_LEN 12 /* Length of interesting data in APP14 */ +#define APPN_DATA_LEN 14 /* Must be the largest of the above!! */ + + +LOCAL(void) +examine_app0 (j_decompress_ptr cinfo, JOCTET FAR * data, + unsigned int datalen, INT32 remaining) +/* Examine first few bytes from an APP0. + * Take appropriate action if it is a JFIF marker. + * datalen is # of bytes at data[], remaining is length of rest of marker data. + */ +{ + INT32 totallen = (INT32) datalen + remaining; + + if (datalen >= APP0_DATA_LEN && + GETJOCTET(data[0]) == 0x4A && + GETJOCTET(data[1]) == 0x46 && + GETJOCTET(data[2]) == 0x49 && + GETJOCTET(data[3]) == 0x46 && + GETJOCTET(data[4]) == 0) { + /* Found JFIF APP0 marker: save info */ + cinfo->saw_JFIF_marker = TRUE; + cinfo->JFIF_major_version = GETJOCTET(data[5]); + cinfo->JFIF_minor_version = GETJOCTET(data[6]); + cinfo->density_unit = GETJOCTET(data[7]); + cinfo->X_density = (GETJOCTET(data[8]) << 8) + GETJOCTET(data[9]); + cinfo->Y_density = (GETJOCTET(data[10]) << 8) + GETJOCTET(data[11]); + /* Check version. + * Major version must be 1, anything else signals an incompatible change. + * (We used to treat this as an error, but now it's a nonfatal warning, + * because some bozo at Hijaak couldn't read the spec.) + * Minor version should be 0..2, but process anyway if newer. + */ + if (cinfo->JFIF_major_version != 1) + WARNMS2(cinfo, JWRN_JFIF_MAJOR, + cinfo->JFIF_major_version, cinfo->JFIF_minor_version); + /* Generate trace messages */ + TRACEMS5(cinfo, 1, JTRC_JFIF, + cinfo->JFIF_major_version, cinfo->JFIF_minor_version, + cinfo->X_density, cinfo->Y_density, cinfo->density_unit); + /* Validate thumbnail dimensions and issue appropriate messages */ + if (GETJOCTET(data[12]) | GETJOCTET(data[13])) + TRACEMS2(cinfo, 1, JTRC_JFIF_THUMBNAIL, + GETJOCTET(data[12]), GETJOCTET(data[13])); + totallen -= APP0_DATA_LEN; + if (totallen != + ((INT32)GETJOCTET(data[12]) * (INT32)GETJOCTET(data[13]) * (INT32) 3)) + TRACEMS1(cinfo, 1, JTRC_JFIF_BADTHUMBNAILSIZE, (int) totallen); + } else if (datalen >= 6 && + GETJOCTET(data[0]) == 0x4A && + GETJOCTET(data[1]) == 0x46 && + GETJOCTET(data[2]) == 0x58 && + GETJOCTET(data[3]) == 0x58 && + GETJOCTET(data[4]) == 0) { + /* Found JFIF "JFXX" extension APP0 marker */ + /* The library doesn't actually do anything with these, + * but we try to produce a helpful trace message. + */ + switch (GETJOCTET(data[5])) { + case 0x10: + TRACEMS1(cinfo, 1, JTRC_THUMB_JPEG, (int) totallen); + break; + case 0x11: + TRACEMS1(cinfo, 1, JTRC_THUMB_PALETTE, (int) totallen); + break; + case 0x13: + TRACEMS1(cinfo, 1, JTRC_THUMB_RGB, (int) totallen); + break; + default: + TRACEMS2(cinfo, 1, JTRC_JFIF_EXTENSION, + GETJOCTET(data[5]), (int) totallen); + break; + } + } else { + /* Start of APP0 does not match "JFIF" or "JFXX", or too short */ + TRACEMS1(cinfo, 1, JTRC_APP0, (int) totallen); + } +} + + +LOCAL(void) +examine_app14 (j_decompress_ptr cinfo, JOCTET FAR * data, + unsigned int datalen, INT32 remaining) +/* Examine first few bytes from an APP14. + * Take appropriate action if it is an Adobe marker. + * datalen is # of bytes at data[], remaining is length of rest of marker data. + */ +{ + unsigned int version, flags0, flags1, transform; + + if (datalen >= APP14_DATA_LEN && + GETJOCTET(data[0]) == 0x41 && + GETJOCTET(data[1]) == 0x64 && + GETJOCTET(data[2]) == 0x6F && + GETJOCTET(data[3]) == 0x62 && + GETJOCTET(data[4]) == 0x65) { + /* Found Adobe APP14 marker */ + version = (GETJOCTET(data[5]) << 8) + GETJOCTET(data[6]); + flags0 = (GETJOCTET(data[7]) << 8) + GETJOCTET(data[8]); + flags1 = (GETJOCTET(data[9]) << 8) + GETJOCTET(data[10]); + transform = GETJOCTET(data[11]); + TRACEMS4(cinfo, 1, JTRC_ADOBE, version, flags0, flags1, transform); + cinfo->saw_Adobe_marker = TRUE; + cinfo->Adobe_transform = (UINT8) transform; + } else { + /* Start of APP14 does not match "Adobe", or too short */ + TRACEMS1(cinfo, 1, JTRC_APP14, (int) (datalen + remaining)); + } +} + + +METHODDEF(boolean) +get_interesting_appn (j_decompress_ptr cinfo) +/* Process an APP0 or APP14 marker without saving it */ +{ + INT32 length; + JOCTET b[APPN_DATA_LEN]; + unsigned int i, numtoread; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + + /* get the interesting part of the marker data */ + if (length >= APPN_DATA_LEN) + numtoread = APPN_DATA_LEN; + else if (length > 0) + numtoread = (unsigned int) length; + else + numtoread = 0; + for (i = 0; i < numtoread; i++) + INPUT_BYTE(cinfo, b[i], return FALSE); + length -= numtoread; + + /* process it */ + switch (cinfo->unread_marker) { + case M_APP0: + examine_app0(cinfo, (JOCTET FAR *) b, numtoread, length); + break; + case M_APP14: + examine_app14(cinfo, (JOCTET FAR *) b, numtoread, length); + break; + default: + /* can't get here unless jpeg_save_markers chooses wrong processor */ + ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, cinfo->unread_marker); + break; + } + + /* skip any remaining data -- could be lots */ + INPUT_SYNC(cinfo); + if (length > 0) + (*cinfo->src->skip_input_data) (cinfo, (long) length); + + return TRUE; +} + + +#ifdef SAVE_MARKERS_SUPPORTED + +METHODDEF(boolean) +save_marker (j_decompress_ptr cinfo) +/* Save an APPn or COM marker into the marker list */ +{ + my_marker_ptr marker = (my_marker_ptr) cinfo->marker; + jpeg_saved_marker_ptr cur_marker = marker->cur_marker; + unsigned int bytes_read, data_length; + JOCTET FAR * data; + INT32 length = 0; + INPUT_VARS(cinfo); + + if (cur_marker == NULL) { + /* begin reading a marker */ + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + if (length >= 0) { /* watch out for bogus length word */ + /* figure out how much we want to save */ + unsigned int limit; + if (cinfo->unread_marker == (int) M_COM) + limit = marker->length_limit_COM; + else + limit = marker->length_limit_APPn[cinfo->unread_marker - (int) M_APP0]; + if ((unsigned int) length < limit) + limit = (unsigned int) length; + /* allocate and initialize the marker item */ + cur_marker = (jpeg_saved_marker_ptr) + (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(struct jpeg_marker_struct) + limit); + cur_marker->next = NULL; + cur_marker->marker = (UINT8) cinfo->unread_marker; + cur_marker->original_length = (unsigned int) length; + cur_marker->data_length = limit; + /* data area is just beyond the jpeg_marker_struct */ + data = cur_marker->data = (JOCTET FAR *) (cur_marker + 1); + marker->cur_marker = cur_marker; + marker->bytes_read = 0; + bytes_read = 0; + data_length = limit; + } else { + /* deal with bogus length word */ + bytes_read = data_length = 0; + data = NULL; + } + } else { + /* resume reading a marker */ + bytes_read = marker->bytes_read; + data_length = cur_marker->data_length; + data = cur_marker->data + bytes_read; + } + + while (bytes_read < data_length) { + INPUT_SYNC(cinfo); /* move the restart point to here */ + marker->bytes_read = bytes_read; + /* If there's not at least one byte in buffer, suspend */ + MAKE_BYTE_AVAIL(cinfo, return FALSE); + /* Copy bytes with reasonable rapidity */ + while (bytes_read < data_length && bytes_in_buffer > 0) { + *data++ = *next_input_byte++; + bytes_in_buffer--; + bytes_read++; + } + } + + /* Done reading what we want to read */ + if (cur_marker != NULL) { /* will be NULL if bogus length word */ + /* Add new marker to end of list */ + if (cinfo->marker_list == NULL) { + cinfo->marker_list = cur_marker; + } else { + jpeg_saved_marker_ptr prev = cinfo->marker_list; + while (prev->next != NULL) + prev = prev->next; + prev->next = cur_marker; + } + /* Reset pointer & calc remaining data length */ + data = cur_marker->data; + length = cur_marker->original_length - data_length; + } + /* Reset to initial state for next marker */ + marker->cur_marker = NULL; + + /* Process the marker if interesting; else just make a generic trace msg */ + switch (cinfo->unread_marker) { + case M_APP0: + examine_app0(cinfo, data, data_length, length); + break; + case M_APP14: + examine_app14(cinfo, data, data_length, length); + break; + default: + TRACEMS2(cinfo, 1, JTRC_MISC_MARKER, cinfo->unread_marker, + (int) (data_length + length)); + break; + } + + /* skip any remaining data -- could be lots */ + INPUT_SYNC(cinfo); /* do before skip_input_data */ + if (length > 0) + (*cinfo->src->skip_input_data) (cinfo, (long) length); + + return TRUE; +} + +#endif /* SAVE_MARKERS_SUPPORTED */ + + +METHODDEF(boolean) +skip_variable (j_decompress_ptr cinfo) +/* Skip over an unknown or uninteresting variable-length marker */ +{ + INT32 length; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + + TRACEMS2(cinfo, 1, JTRC_MISC_MARKER, cinfo->unread_marker, (int) length); + + INPUT_SYNC(cinfo); /* do before skip_input_data */ + if (length > 0) + (*cinfo->src->skip_input_data) (cinfo, (long) length); + + return TRUE; +} + + +/* + * Find the next JPEG marker, save it in cinfo->unread_marker. + * Returns FALSE if had to suspend before reaching a marker; + * in that case cinfo->unread_marker is unchanged. + * + * Note that the result might not be a valid marker code, + * but it will never be 0 or FF. + */ + +LOCAL(boolean) +next_marker (j_decompress_ptr cinfo) +{ + int c; + INPUT_VARS(cinfo); + + for (;;) { + INPUT_BYTE(cinfo, c, return FALSE); + /* Skip any non-FF bytes. + * This may look a bit inefficient, but it will not occur in a valid file. + * We sync after each discarded byte so that a suspending data source + * can discard the byte from its buffer. + */ + while (c != 0xFF) { + cinfo->marker->discarded_bytes++; + INPUT_SYNC(cinfo); + INPUT_BYTE(cinfo, c, return FALSE); + } + /* This loop swallows any duplicate FF bytes. Extra FFs are legal as + * pad bytes, so don't count them in discarded_bytes. We assume there + * will not be so many consecutive FF bytes as to overflow a suspending + * data source's input buffer. + */ + do { + INPUT_BYTE(cinfo, c, return FALSE); + } while (c == 0xFF); + if (c != 0) + break; /* found a valid marker, exit loop */ + /* Reach here if we found a stuffed-zero data sequence (FF/00). + * Discard it and loop back to try again. + */ + cinfo->marker->discarded_bytes += 2; + INPUT_SYNC(cinfo); + } + + if (cinfo->marker->discarded_bytes != 0) { + WARNMS2(cinfo, JWRN_EXTRANEOUS_DATA, cinfo->marker->discarded_bytes, c); + cinfo->marker->discarded_bytes = 0; + } + + cinfo->unread_marker = c; + + INPUT_SYNC(cinfo); + return TRUE; +} + + +LOCAL(boolean) +first_marker (j_decompress_ptr cinfo) +/* Like next_marker, but used to obtain the initial SOI marker. */ +/* For this marker, we do not allow preceding garbage or fill; otherwise, + * we might well scan an entire input file before realizing it ain't JPEG. + * If an application wants to process non-JFIF files, it must seek to the + * SOI before calling the JPEG library. + */ +{ + int c, c2; + INPUT_VARS(cinfo); + + INPUT_BYTE(cinfo, c, return FALSE); + INPUT_BYTE(cinfo, c2, return FALSE); + if (c != 0xFF || c2 != (int) M_SOI) + ERREXIT2(cinfo, JERR_NO_SOI, c, c2); + + cinfo->unread_marker = c2; + + INPUT_SYNC(cinfo); + return TRUE; +} + + +/* + * Read markers until SOS or EOI. + * + * Returns same codes as are defined for jpeg_consume_input: + * JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI. + */ + +METHODDEF(int) +read_markers (j_decompress_ptr cinfo) +{ + /* Outer loop repeats once for each marker. */ + for (;;) { + /* Collect the marker proper, unless we already did. */ + /* NB: first_marker() enforces the requirement that SOI appear first. */ + if (cinfo->unread_marker == 0) { + if (! cinfo->marker->saw_SOI) { + if (! first_marker(cinfo)) + return JPEG_SUSPENDED; + } else { + if (! next_marker(cinfo)) + return JPEG_SUSPENDED; + } + } + /* At this point cinfo->unread_marker contains the marker code and the + * input point is just past the marker proper, but before any parameters. + * A suspension will cause us to return with this state still true. + */ + switch (cinfo->unread_marker) { + case M_SOI: + if (! get_soi(cinfo)) + return JPEG_SUSPENDED; + break; + + case M_SOF0: /* Baseline */ + case M_SOF1: /* Extended sequential, Huffman */ + if (! get_sof(cinfo, JPROC_SEQUENTIAL, FALSE, DCTSIZE)) + return JPEG_SUSPENDED; + break; + + case M_SOF2: /* Progressive, Huffman */ + if (! get_sof(cinfo, JPROC_PROGRESSIVE, FALSE, DCTSIZE)) + return JPEG_SUSPENDED; + break; + + case M_SOF3: /* Lossless, Huffman */ + if (! get_sof(cinfo, JPROC_LOSSLESS, FALSE, 1)) + return JPEG_SUSPENDED; + break; + + case M_SOF9: /* Extended sequential, arithmetic */ + if (! get_sof(cinfo, JPROC_SEQUENTIAL, TRUE, DCTSIZE)) + return JPEG_SUSPENDED; + break; + + case M_SOF10: /* Progressive, arithmetic */ + if (! get_sof(cinfo, JPROC_PROGRESSIVE, TRUE, DCTSIZE)) + return JPEG_SUSPENDED; + break; + + case M_SOF11: /* Lossless, arithmetic */ + if (! get_sof(cinfo, JPROC_LOSSLESS, TRUE, 1)) + return JPEG_SUSPENDED; + break; + + /* Currently unsupported SOFn types */ + case M_SOF5: /* Differential sequential, Huffman */ + case M_SOF6: /* Differential progressive, Huffman */ + case M_SOF7: /* Differential lossless, Huffman */ + case M_JPG: /* Reserved for JPEG extensions */ + case M_SOF13: /* Differential sequential, arithmetic */ + case M_SOF14: /* Differential progressive, arithmetic */ + case M_SOF15: /* Differential lossless, arithmetic */ + ERREXIT1(cinfo, JERR_SOF_UNSUPPORTED, cinfo->unread_marker); + break; + + case M_SOS: + if (! get_sos(cinfo)) + return JPEG_SUSPENDED; + cinfo->unread_marker = 0; /* processed the marker */ + return JPEG_REACHED_SOS; + + case M_EOI: + TRACEMS(cinfo, 1, JTRC_EOI); + cinfo->unread_marker = 0; /* processed the marker */ + return JPEG_REACHED_EOI; + + case M_DAC: + if (! get_dac(cinfo)) + return JPEG_SUSPENDED; + break; + + case M_DHT: + if (! get_dht(cinfo)) + return JPEG_SUSPENDED; + break; + + case M_DQT: + if (! get_dqt(cinfo)) + return JPEG_SUSPENDED; + break; + + case M_DRI: + if (! get_dri(cinfo)) + return JPEG_SUSPENDED; + break; + + case M_APP0: + case M_APP1: + case M_APP2: + case M_APP3: + case M_APP4: + case M_APP5: + case M_APP6: + case M_APP7: + case M_APP8: + case M_APP9: + case M_APP10: + case M_APP11: + case M_APP12: + case M_APP13: + case M_APP14: + case M_APP15: + if (! (*((my_marker_ptr) cinfo->marker)->process_APPn[ + cinfo->unread_marker - (int) M_APP0]) (cinfo)) + return JPEG_SUSPENDED; + break; + + case M_COM: + if (! (*((my_marker_ptr) cinfo->marker)->process_COM) (cinfo)) + return JPEG_SUSPENDED; + break; + + case M_RST0: /* these are all parameterless */ + case M_RST1: + case M_RST2: + case M_RST3: + case M_RST4: + case M_RST5: + case M_RST6: + case M_RST7: + case M_TEM: + TRACEMS1(cinfo, 1, JTRC_PARMLESS_MARKER, cinfo->unread_marker); + break; + + case M_DNL: /* Ignore DNL ... perhaps the wrong thing */ + if (! skip_variable(cinfo)) + return JPEG_SUSPENDED; + break; + + default: /* must be DHP, EXP, JPGn, or RESn */ + /* For now, we treat the reserved markers as fatal errors since they are + * likely to be used to signal incompatible JPEG Part 3 extensions. + * Once the JPEG 3 version-number marker is well defined, this code + * ought to change! + */ + ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, cinfo->unread_marker); + break; + } + /* Successfully processed marker, so reset state variable */ + cinfo->unread_marker = 0; + } /* end loop */ +} + + +/* + * Read a restart marker, which is expected to appear next in the datastream; + * if the marker is not there, take appropriate recovery action. + * Returns FALSE if suspension is required. + * + * This is called by the entropy decoder after it has read an appropriate + * number of MCUs. cinfo->unread_marker may be nonzero if the entropy decoder + * has already read a marker from the data source. Under normal conditions + * cinfo->unread_marker will be reset to 0 before returning; if not reset, + * it holds a marker which the decoder will be unable to read past. + */ + +METHODDEF(boolean) +read_restart_marker (j_decompress_ptr cinfo) +{ + /* Obtain a marker unless we already did. */ + /* Note that next_marker will complain if it skips any data. */ + if (cinfo->unread_marker == 0) { + if (! next_marker(cinfo)) + return FALSE; + } + + if (cinfo->unread_marker == + ((int) M_RST0 + cinfo->marker->next_restart_num)) { + /* Normal case --- swallow the marker and let entropy decoder continue */ + TRACEMS1(cinfo, 3, JTRC_RST, cinfo->marker->next_restart_num); + cinfo->unread_marker = 0; + } else { + /* Uh-oh, the restart markers have been messed up. */ + /* Let the data source manager determine how to resync. */ + if (! (*cinfo->src->resync_to_restart) (cinfo, + cinfo->marker->next_restart_num)) + return FALSE; + } + + /* Update next-restart state */ + cinfo->marker->next_restart_num = (cinfo->marker->next_restart_num + 1) & 7; + + return TRUE; +} + + +/* + * This is the default resync_to_restart method for data source managers + * to use if they don't have any better approach. Some data source managers + * may be able to back up, or may have additional knowledge about the data + * which permits a more intelligent recovery strategy; such managers would + * presumably supply their own resync method. + * + * read_restart_marker calls resync_to_restart if it finds a marker other than + * the restart marker it was expecting. (This code is *not* used unless + * a nonzero restart interval has been declared.) cinfo->unread_marker is + * the marker code actually found (might be anything, except 0 or FF). + * The desired restart marker number (0..7) is passed as a parameter. + * This routine is supposed to apply whatever error recovery strategy seems + * appropriate in order to position the input stream to the next data segment. + * Note that cinfo->unread_marker is treated as a marker appearing before + * the current data-source input point; usually it should be reset to zero + * before returning. + * Returns FALSE if suspension is required. + * + * This implementation is substantially constrained by wanting to treat the + * input as a data stream; this means we can't back up. Therefore, we have + * only the following actions to work with: + * 1. Simply discard the marker and let the entropy decoder resume at next + * byte of file. + * 2. Read forward until we find another marker, discarding intervening + * data. (In theory we could look ahead within the current bufferload, + * without having to discard data if we don't find the desired marker. + * This idea is not implemented here, in part because it makes behavior + * dependent on buffer size and chance buffer-boundary positions.) + * 3. Leave the marker unread (by failing to zero cinfo->unread_marker). + * This will cause the entropy decoder to process an empty data segment, + * inserting dummy zeroes, and then we will reprocess the marker. + * + * #2 is appropriate if we think the desired marker lies ahead, while #3 is + * appropriate if the found marker is a future restart marker (indicating + * that we have missed the desired restart marker, probably because it got + * corrupted). + * We apply #2 or #3 if the found marker is a restart marker no more than + * two counts behind or ahead of the expected one. We also apply #2 if the + * found marker is not a legal JPEG marker code (it's certainly bogus data). + * If the found marker is a restart marker more than 2 counts away, we do #1 + * (too much risk that the marker is erroneous; with luck we will be able to + * resync at some future point). + * For any valid non-restart JPEG marker, we apply #3. This keeps us from + * overrunning the end of a scan. An implementation limited to single-scan + * files might find it better to apply #2 for markers other than EOI, since + * any other marker would have to be bogus data in that case. + */ + +GLOBAL(boolean) +jpeg_resync_to_restart (j_decompress_ptr cinfo, int desired) +{ + int marker = cinfo->unread_marker; + int action = 1; + + /* Always put up a warning. */ + WARNMS2(cinfo, JWRN_MUST_RESYNC, marker, desired); + + /* Outer loop handles repeated decision after scanning forward. */ + for (;;) { + if (marker < (int) M_SOF0) + action = 2; /* invalid marker */ + else if (marker < (int) M_RST0 || marker > (int) M_RST7) + action = 3; /* valid non-restart marker */ + else { + if (marker == ((int) M_RST0 + ((desired+1) & 7)) || + marker == ((int) M_RST0 + ((desired+2) & 7))) + action = 3; /* one of the next two expected restarts */ + else if (marker == ((int) M_RST0 + ((desired-1) & 7)) || + marker == ((int) M_RST0 + ((desired-2) & 7))) + action = 2; /* a prior restart, so advance */ + else + action = 1; /* desired restart or too far away */ + } + TRACEMS2(cinfo, 4, JTRC_RECOVERY_ACTION, marker, action); + switch (action) { + case 1: + /* Discard marker and let entropy decoder resume processing. */ + cinfo->unread_marker = 0; + return TRUE; + case 2: + /* Scan to the next marker, and repeat the decision loop. */ + if (! next_marker(cinfo)) + return FALSE; + marker = cinfo->unread_marker; + break; + case 3: + /* Return without advancing past this marker. */ + /* Entropy decoder will be forced to process an empty segment. */ + return TRUE; + } + } /* end loop */ +} + + +/* + * Reset marker processing state to begin a fresh datastream. + */ + +METHODDEF(void) +reset_marker_reader (j_decompress_ptr cinfo) +{ + my_marker_ptr marker = (my_marker_ptr) cinfo->marker; + + cinfo->comp_info = NULL; /* until allocated by get_sof */ + cinfo->input_scan_number = 0; /* no SOS seen yet */ + cinfo->unread_marker = 0; /* no pending marker */ + marker->pub.saw_SOI = FALSE; /* set internal state too */ + marker->pub.saw_SOF = FALSE; + marker->pub.discarded_bytes = 0; + marker->cur_marker = NULL; +} + + +/* + * Initialize the marker reader module. + * This is called only once, when the decompression object is created. + */ + +GLOBAL(void) +jinit_marker_reader (j_decompress_ptr cinfo) +{ + my_marker_ptr marker; + int i; + + /* Create subobject in permanent pool */ + marker = (my_marker_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + SIZEOF(my_marker_reader)); + cinfo->marker = (struct jpeg_marker_reader *) marker; + /* Initialize public method pointers */ + marker->pub.reset_marker_reader = reset_marker_reader; + marker->pub.read_markers = read_markers; + marker->pub.read_restart_marker = read_restart_marker; + /* Initialize COM/APPn processing. + * By default, we examine and then discard APP0 and APP14, + * but simply discard COM and all other APPn. + */ + marker->process_COM = skip_variable; + marker->length_limit_COM = 0; + for (i = 0; i < 16; i++) { + marker->process_APPn[i] = skip_variable; + marker->length_limit_APPn[i] = 0; + } + marker->process_APPn[0] = get_interesting_appn; + marker->process_APPn[14] = get_interesting_appn; + /* Reset marker processing state */ + reset_marker_reader(cinfo); +} + + +/* + * Control saving of COM and APPn markers into marker_list. + */ + +#ifdef SAVE_MARKERS_SUPPORTED + +GLOBAL(void) +jpeg_save_markers (j_decompress_ptr cinfo, int marker_code, + unsigned int length_limit) +{ + my_marker_ptr marker = (my_marker_ptr) cinfo->marker; + long maxlength; + jpeg_marker_parser_method processor; + + /* Length limit mustn't be larger than what we can allocate + * (should only be a concern in a 16-bit environment). + */ + maxlength = cinfo->mem->max_alloc_chunk - SIZEOF(struct jpeg_marker_struct); + if (((long) length_limit) > maxlength) + length_limit = (unsigned int) maxlength; + + /* Choose processor routine to use. + * APP0/APP14 have special requirements. + */ + if (length_limit) { + processor = save_marker; + /* If saving APP0/APP14, save at least enough for our internal use. */ + if (marker_code == (int) M_APP0 && length_limit < APP0_DATA_LEN) + length_limit = APP0_DATA_LEN; + else if (marker_code == (int) M_APP14 && length_limit < APP14_DATA_LEN) + length_limit = APP14_DATA_LEN; + } else { + processor = skip_variable; + /* If discarding APP0/APP14, use our regular on-the-fly processor. */ + if (marker_code == (int) M_APP0 || marker_code == (int) M_APP14) + processor = get_interesting_appn; + } + + if (marker_code == (int) M_COM) { + marker->process_COM = processor; + marker->length_limit_COM = length_limit; + } else if (marker_code >= (int) M_APP0 && marker_code <= (int) M_APP15) { + marker->process_APPn[marker_code - (int) M_APP0] = processor; + marker->length_limit_APPn[marker_code - (int) M_APP0] = length_limit; + } else + ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, marker_code); +} + +#endif /* SAVE_MARKERS_SUPPORTED */ + + +/* + * Install a special processing method for COM or APPn markers. + */ + +GLOBAL(void) +jpeg_set_marker_processor (j_decompress_ptr cinfo, int marker_code, + jpeg_marker_parser_method routine) +{ + my_marker_ptr marker = (my_marker_ptr) cinfo->marker; + + if (marker_code == (int) M_COM) + marker->process_COM = routine; + else if (marker_code >= (int) M_APP0 && marker_code <= (int) M_APP15) + marker->process_APPn[marker_code - (int) M_APP0] = routine; + else + ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, marker_code); +} diff --git a/gdcm/Utilities/gdcmjpeg/jdmaster.c b/gdcm/Utilities/gdcmjpeg/jdmaster.c new file mode 100644 index 0000000..e232416 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jdmaster.c @@ -0,0 +1,460 @@ +/* + * jdmaster.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains master control logic for the JPEG decompressor. + * These routines are concerned with selecting the modules to be executed + * and with determining the number of passes and the work to be done in each + * pass. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Private state */ + +typedef struct { + struct jpeg_decomp_master pub; /* public fields */ + + int pass_number; /* # of passes completed */ + + boolean using_merged_upsample; /* TRUE if using merged upsample/cconvert */ + + /* Saved references to initialized quantizer modules, + * in case we need to switch modes. + */ + struct jpeg_color_quantizer * quantizer_1pass; + struct jpeg_color_quantizer * quantizer_2pass; +} my_decomp_master; + +typedef my_decomp_master * my_master_ptr; + + +/* + * Determine whether merged upsample/color conversion should be used. + * CRUCIAL: this must match the actual capabilities of jdmerge.c! + */ + +LOCAL(boolean) +use_merged_upsample (j_decompress_ptr cinfo) +{ +#ifdef UPSAMPLE_MERGING_SUPPORTED + /* Merging is the equivalent of plain box-filter upsampling */ + if (cinfo->do_fancy_upsampling || cinfo->CCIR601_sampling) + return FALSE; + /* jdmerge.c only supports YCC=>RGB color conversion */ + if (cinfo->jpeg_color_space != JCS_YCbCr || cinfo->num_components != 3 || + cinfo->out_color_space != JCS_RGB || + cinfo->out_color_components != RGB_PIXELSIZE) + return FALSE; + /* and it only handles 2h1v or 2h2v sampling ratios */ + if (cinfo->comp_info[0].h_samp_factor != 2 || + cinfo->comp_info[1].h_samp_factor != 1 || + cinfo->comp_info[2].h_samp_factor != 1 || + cinfo->comp_info[0].v_samp_factor > 2 || + cinfo->comp_info[1].v_samp_factor != 1 || + cinfo->comp_info[2].v_samp_factor != 1) + return FALSE; + /* furthermore, it doesn't work if each component has been + processed differently */ + if (cinfo->comp_info[0].codec_data_unit != cinfo->min_codec_data_unit || + cinfo->comp_info[1].codec_data_unit != cinfo->min_codec_data_unit || + cinfo->comp_info[2].codec_data_unit != cinfo->min_codec_data_unit) + return FALSE; + /* ??? also need to test for upsample-time rescaling, when & if supported */ + return TRUE; /* by golly, it'll work... */ +#else + return FALSE; +#endif +} + + +/* + * Compute output image dimensions and related values. + * NOTE: this is exported for possible use by application. + * Hence it mustn't do anything that can't be done twice. + * Also note that it may be called before the master module is initialized! + */ + +GLOBAL(void) +jpeg_calc_output_dimensions (j_decompress_ptr cinfo) +/* Do computations that are needed before master selection phase */ +{ + /* Prevent application from calling me at wrong times */ + if (cinfo->global_state != DSTATE_READY) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + (*cinfo->codec->calc_output_dimensions) (cinfo); + + /* Report number of components in selected colorspace. */ + /* Probably this should be in the color conversion module... */ + switch (cinfo->out_color_space) { + case JCS_GRAYSCALE: + cinfo->out_color_components = 1; + break; + case JCS_RGB: +#if RGB_PIXELSIZE != 3 + cinfo->out_color_components = RGB_PIXELSIZE; + break; +#endif /* else share code with YCbCr */ + case JCS_YCbCr: + cinfo->out_color_components = 3; + break; + case JCS_CMYK: + case JCS_YCCK: + cinfo->out_color_components = 4; + break; + default: /* else must be same colorspace as in file */ + cinfo->out_color_components = cinfo->num_components; + break; + } + cinfo->output_components = (cinfo->quantize_colors ? 1 : + cinfo->out_color_components); + + /* See if upsampler will want to emit more than one row at a time */ + if (use_merged_upsample(cinfo)) + cinfo->rec_outbuf_height = cinfo->max_v_samp_factor; + else + cinfo->rec_outbuf_height = 1; +} + + +/* + * Several decompression processes need to range-limit values to the range + * 0..MAXJSAMPLE; the input value may fall somewhat outside this range + * due to noise introduced by quantization, roundoff error, etc. These + * processes are inner loops and need to be as fast as possible. On most + * machines, particularly CPUs with pipelines or instruction prefetch, + * a (subscript-check-less) C table lookup + * x = sample_range_limit[x]; + * is faster than explicit tests + * if (x < 0) x = 0; + * else if (x > MAXJSAMPLE) x = MAXJSAMPLE; + * These processes all use a common table prepared by the routine below. + * + * For most steps we can mathematically guarantee that the initial value + * of x is within MAXJSAMPLE+1 of the legal range, so a table running from + * -(MAXJSAMPLE+1) to 2*MAXJSAMPLE+1 is sufficient. But for the initial + * limiting step (just after the IDCT), a wildly out-of-range value is + * possible if the input data is corrupt. To avoid any chance of indexing + * off the end of memory and getting a bad-pointer trap, we perform the + * post-IDCT limiting thus: + * x = range_limit[x & MASK]; + * where MASK is 2 bits wider than legal sample data, ie 10 bits for 8-bit + * samples. Under normal circumstances this is more than enough range and + * a correct output will be generated; with bogus input data the mask will + * cause wraparound, and we will safely generate a bogus-but-in-range output. + * For the post-IDCT step, we want to convert the data from signed to unsigned + * representation by adding CENTERJSAMPLE at the same time that we limit it. + * So the post-IDCT limiting table ends up looking like this: + * CENTERJSAMPLE,CENTERJSAMPLE+1,...,MAXJSAMPLE, + * MAXJSAMPLE (repeat 2*(MAXJSAMPLE+1)-CENTERJSAMPLE times), + * 0 (repeat 2*(MAXJSAMPLE+1)-CENTERJSAMPLE times), + * 0,1,...,CENTERJSAMPLE-1 + * Negative inputs select values from the upper half of the table after + * masking. + * + * We can save some space by overlapping the start of the post-IDCT table + * with the simpler range limiting table. The post-IDCT table begins at + * sample_range_limit + CENTERJSAMPLE. + * + * Note that the table is allocated in near data space on PCs; it's small + * enough and used often enough to justify this. + */ + +LOCAL(void) +prepare_range_limit_table (j_decompress_ptr cinfo) +/* Allocate and fill in the sample_range_limit table */ +{ + JSAMPLE * table; + int i; + + table = (JSAMPLE *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (5 * (MAXJSAMPLE+1) + CENTERJSAMPLE) * SIZEOF(JSAMPLE)); + table += (MAXJSAMPLE+1); /* allow negative subscripts of simple table */ + cinfo->sample_range_limit = table; + /* First segment of "simple" table: limit[x] = 0 for x < 0 */ + MEMZERO(table - (MAXJSAMPLE+1), (MAXJSAMPLE+1) * SIZEOF(JSAMPLE)); + /* Main part of "simple" table: limit[x] = x */ + for (i = 0; i <= MAXJSAMPLE; i++) + table[i] = (JSAMPLE) i; + table += CENTERJSAMPLE; /* Point to where post-IDCT table starts */ + /* End of simple table, rest of first half of post-IDCT table */ + for (i = CENTERJSAMPLE; i < 2*(MAXJSAMPLE+1); i++) + table[i] = MAXJSAMPLE; + /* Second half of post-IDCT table */ + MEMZERO(table + (2 * (MAXJSAMPLE+1)), + (2 * (MAXJSAMPLE+1) - CENTERJSAMPLE) * SIZEOF(JSAMPLE)); + MEMCOPY(table + (4 * (MAXJSAMPLE+1) - CENTERJSAMPLE), + cinfo->sample_range_limit, CENTERJSAMPLE * SIZEOF(JSAMPLE)); +} + + +/* + * Master selection of decompression modules. + * This is done once at jpeg_start_decompress time. We determine + * which modules will be used and give them appropriate initialization calls. + * We also initialize the decompressor input side to begin consuming data. + * + * Since jpeg_read_header has finished, we know what is in the SOF + * and (first) SOS markers. We also have all the application parameter + * settings. + */ + +LOCAL(void) +master_selection (j_decompress_ptr cinfo) +{ + my_master_ptr master = (my_master_ptr) cinfo->master; + long samplesperrow; + JDIMENSION jd_samplesperrow; + + /* Initialize dimensions and other stuff */ + jpeg_calc_output_dimensions(cinfo); + prepare_range_limit_table(cinfo); + + /* Width of an output scanline must be representable as JDIMENSION. */ + samplesperrow = (long) cinfo->output_width * (long) cinfo->out_color_components; + jd_samplesperrow = (JDIMENSION) samplesperrow; + if ((long) jd_samplesperrow != samplesperrow) + ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); + + /* Initialize my private state */ + master->pass_number = 0; + master->using_merged_upsample = use_merged_upsample(cinfo); + + /* Color quantizer selection */ + master->quantizer_1pass = NULL; + master->quantizer_2pass = NULL; + /* No mode changes if not using buffered-image mode. */ + if (! cinfo->quantize_colors || ! cinfo->buffered_image) { + cinfo->enable_1pass_quant = FALSE; + cinfo->enable_external_quant = FALSE; + cinfo->enable_2pass_quant = FALSE; + } + if (cinfo->quantize_colors) { + if (cinfo->raw_data_out) + ERREXIT(cinfo, JERR_NOTIMPL); + /* 2-pass quantizer only works in 3-component color space. */ + if (cinfo->out_color_components != 3) { + cinfo->enable_1pass_quant = TRUE; + cinfo->enable_external_quant = FALSE; + cinfo->enable_2pass_quant = FALSE; + cinfo->colormap = NULL; + } else if (cinfo->colormap != NULL) { + cinfo->enable_external_quant = TRUE; + } else if (cinfo->two_pass_quantize) { + cinfo->enable_2pass_quant = TRUE; + } else { + cinfo->enable_1pass_quant = TRUE; + } + + if (cinfo->enable_1pass_quant) { +#ifdef QUANT_1PASS_SUPPORTED + jinit_1pass_quantizer(cinfo); + master->quantizer_1pass = cinfo->cquantize; +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } + + /* We use the 2-pass code to map to external colormaps. */ + if (cinfo->enable_2pass_quant || cinfo->enable_external_quant) { +#ifdef QUANT_2PASS_SUPPORTED + jinit_2pass_quantizer(cinfo); + master->quantizer_2pass = cinfo->cquantize; +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } + /* If both quantizers are initialized, the 2-pass one is left active; + * this is necessary for starting with quantization to an external map. + */ + } + + /* Post-processing: in particular, color conversion first */ + if (! cinfo->raw_data_out) { + if (master->using_merged_upsample) { +#ifdef UPSAMPLE_MERGING_SUPPORTED + jinit_merged_upsampler(cinfo); /* does color conversion too */ +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else { + jinit_color_deconverter(cinfo); + jinit_upsampler(cinfo); + } + jinit_d_post_controller(cinfo, cinfo->enable_2pass_quant); + } + + /* Initialize principal buffer controllers. */ + if (! cinfo->raw_data_out) + jinit_d_main_controller(cinfo, FALSE /* never need full buffer here */); + + /* We can now tell the memory manager to allocate virtual arrays. */ + (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo); + + /* Initialize input side of decompressor to consume first scan. */ + (*cinfo->inputctl->start_input_pass) (cinfo); + +#ifdef D_MULTISCAN_FILES_SUPPORTED + /* If jpeg_start_decompress will read the whole file, initialize + * progress monitoring appropriately. The input step is counted + * as one pass. + */ + if (cinfo->progress != NULL && ! cinfo->buffered_image && + cinfo->inputctl->has_multiple_scans) { + int nscans; + /* Estimate number of scans to set pass_limit. */ + if (cinfo->process == JPROC_PROGRESSIVE) { + /* Arbitrarily estimate 2 interleaved DC scans + 3 AC scans/component. */ + nscans = 2 + 3 * cinfo->num_components; + } else { + /* For a nonprogressive multiscan file, estimate 1 scan per component. */ + nscans = cinfo->num_components; + } + cinfo->progress->pass_counter = 0L; + cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows * nscans; + cinfo->progress->completed_passes = 0; + cinfo->progress->total_passes = (cinfo->enable_2pass_quant ? 3 : 2); + /* Count the input pass as done */ + master->pass_number++; + } +#endif /* D_MULTISCAN_FILES_SUPPORTED */ +} + + +/* + * Per-pass setup. + * This is called at the beginning of each output pass. We determine which + * modules will be active during this pass and give them appropriate + * start_pass calls. We also set is_dummy_pass to indicate whether this + * is a "real" output pass or a dummy pass for color quantization. + * (In the latter case, jdapistd.c will crank the pass to completion.) + */ + +METHODDEF(void) +prepare_for_output_pass (j_decompress_ptr cinfo) +{ + my_master_ptr master = (my_master_ptr) cinfo->master; + + if (master->pub.is_dummy_pass) { +#ifdef QUANT_2PASS_SUPPORTED + /* Final pass of 2-pass quantization */ + master->pub.is_dummy_pass = FALSE; + (*cinfo->cquantize->start_pass) (cinfo, FALSE); + (*cinfo->post->start_pass) (cinfo, JBUF_CRANK_DEST); + (*cinfo->main->start_pass) (cinfo, JBUF_CRANK_DEST); +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif /* QUANT_2PASS_SUPPORTED */ + } else { + if (cinfo->quantize_colors && cinfo->colormap == NULL) { + /* Select new quantization method */ + if (cinfo->two_pass_quantize && cinfo->enable_2pass_quant) { + cinfo->cquantize = master->quantizer_2pass; + master->pub.is_dummy_pass = TRUE; + } else if (cinfo->enable_1pass_quant) { + cinfo->cquantize = master->quantizer_1pass; + } else { + ERREXIT(cinfo, JERR_MODE_CHANGE); + } + } + (*cinfo->codec->start_output_pass) (cinfo); + if (! cinfo->raw_data_out) { + if (! master->using_merged_upsample) + (*cinfo->cconvert->start_pass) (cinfo); + (*cinfo->upsample->start_pass) (cinfo); + if (cinfo->quantize_colors) + (*cinfo->cquantize->start_pass) (cinfo, master->pub.is_dummy_pass); + (*cinfo->post->start_pass) (cinfo, + (master->pub.is_dummy_pass ? JBUF_SAVE_AND_PASS : JBUF_PASS_THRU)); + (*cinfo->main->start_pass) (cinfo, JBUF_PASS_THRU); + } + } + + /* Set up progress monitor's pass info if present */ + if (cinfo->progress != NULL) { + cinfo->progress->completed_passes = master->pass_number; + cinfo->progress->total_passes = master->pass_number + + (master->pub.is_dummy_pass ? 2 : 1); + /* In buffered-image mode, we assume one more output pass if EOI not + * yet reached, but no more passes if EOI has been reached. + */ + if (cinfo->buffered_image && ! cinfo->inputctl->eoi_reached) { + cinfo->progress->total_passes += (cinfo->enable_2pass_quant ? 2 : 1); + } + } +} + + +/* + * Finish up at end of an output pass. + */ + +METHODDEF(void) +finish_output_pass (j_decompress_ptr cinfo) +{ + my_master_ptr master = (my_master_ptr) cinfo->master; + + if (cinfo->quantize_colors) + (*cinfo->cquantize->finish_pass) (cinfo); + master->pass_number++; +} + + +#ifdef D_MULTISCAN_FILES_SUPPORTED + +/* + * Switch to a new external colormap between output passes. + */ + +GLOBAL(void) +jpeg_new_colormap (j_decompress_ptr cinfo) +{ + my_master_ptr master = (my_master_ptr) cinfo->master; + + /* Prevent application from calling me at wrong times */ + if (cinfo->global_state != DSTATE_BUFIMAGE) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + if (cinfo->quantize_colors && cinfo->enable_external_quant && + cinfo->colormap != NULL) { + /* Select 2-pass quantizer for external colormap use */ + cinfo->cquantize = master->quantizer_2pass; + /* Notify quantizer of colormap change */ + (*cinfo->cquantize->new_color_map) (cinfo); + master->pub.is_dummy_pass = FALSE; /* just in case */ + } else + ERREXIT(cinfo, JERR_MODE_CHANGE); +} + +#endif /* D_MULTISCAN_FILES_SUPPORTED */ + + +/* + * Initialize master decompression control and select active modules. + * This is performed at the start of jpeg_start_decompress. + */ + +GLOBAL(void) +jinit_master_decompress (j_decompress_ptr cinfo) +{ + my_master_ptr master; + + master = (my_master_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_decomp_master)); + cinfo->master = (struct jpeg_decomp_master *) master; + master->pub.prepare_for_output_pass = prepare_for_output_pass; + master->pub.finish_output_pass = finish_output_pass; + + master->pub.is_dummy_pass = FALSE; + + master_selection(cinfo); +} diff --git a/gdcm/Utilities/gdcmjpeg/jdmerge.c b/gdcm/Utilities/gdcmjpeg/jdmerge.c new file mode 100644 index 0000000..7a23595 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jdmerge.c @@ -0,0 +1,402 @@ +/* + * jdmerge.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains code for merged upsampling/color conversion. + * + * This file combines functions from jdsample.c and jdcolor.c; + * read those files first to understand what's going on. + * + * When the chroma components are to be upsampled by simple replication + * (ie, box filtering), we can save some work in color conversion by + * calculating all the output pixels corresponding to a pair of chroma + * samples at one time. In the conversion equations + * R = Y + K1 * Cr + * G = Y + K2 * Cb + K3 * Cr + * B = Y + K4 * Cb + * only the Y term varies among the group of pixels corresponding to a pair + * of chroma samples, so the rest of the terms can be calculated just once. + * At typical sampling ratios, this eliminates half or three-quarters of the + * multiplications needed for color conversion. + * + * This file currently provides implementations for the following cases: + * YCbCr => RGB color conversion only. + * Sampling ratios of 2h1v or 2h2v. + * No scaling needed at upsample time. + * Corner-aligned (non-CCIR601) sampling alignment. + * Other special cases could be added, but in most applications these are + * the only common cases. (For uncommon cases we fall back on the more + * general code in jdsample.c and jdcolor.c.) + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + +#ifdef UPSAMPLE_MERGING_SUPPORTED + + +/* Private subobject */ + +typedef struct { + struct jpeg_upsampler pub; /* public fields */ + + /* Pointer to routine to do actual upsampling/conversion of one row group */ + JMETHOD(void, upmethod, (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr, + JSAMPARRAY output_buf)); + + /* Private state for YCC->RGB conversion */ + int * Cr_r_tab; /* => table for Cr to R conversion */ + int * Cb_b_tab; /* => table for Cb to B conversion */ + INT32 * Cr_g_tab; /* => table for Cr to G conversion */ + INT32 * Cb_g_tab; /* => table for Cb to G conversion */ + + /* For 2:1 vertical sampling, we produce two output rows at a time. + * We need a "spare" row buffer to hold the second output row if the + * application provides just a one-row buffer; we also use the spare + * to discard the dummy last row if the image height is odd. + */ + JSAMPROW spare_row; + boolean spare_full; /* T if spare buffer is occupied */ + + JDIMENSION out_row_width; /* samples per output row */ + JDIMENSION rows_to_go; /* counts rows remaining in image */ +} my_upsampler; + +typedef my_upsampler * my_upsample_ptr; + +#define SCALEBITS 16 /* speediest right-shift on some machines */ +#define ONE_HALF ((INT32) 1 << (SCALEBITS-1)) +#define FIX(x) ((INT32) ((x) * (1L<RGB colorspace conversion. + * This is taken directly from jdcolor.c; see that file for more info. + */ + +LOCAL(void) +build_ycc_rgb_table (j_decompress_ptr cinfo) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + int i; + INT32 x; + SHIFT_TEMPS + + upsample->Cr_r_tab = (int *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (MAXJSAMPLE+1) * SIZEOF(int)); + upsample->Cb_b_tab = (int *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (MAXJSAMPLE+1) * SIZEOF(int)); + upsample->Cr_g_tab = (INT32 *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (MAXJSAMPLE+1) * SIZEOF(INT32)); + upsample->Cb_g_tab = (INT32 *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (MAXJSAMPLE+1) * SIZEOF(INT32)); + + for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) { + /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */ + /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */ + /* Cr=>R value is nearest int to 1.40200 * x */ + upsample->Cr_r_tab[i] = (int) + RIGHT_SHIFT(FIX(1.40200) * x + ONE_HALF, SCALEBITS); + /* Cb=>B value is nearest int to 1.77200 * x */ + upsample->Cb_b_tab[i] = (int) + RIGHT_SHIFT(FIX(1.77200) * x + ONE_HALF, SCALEBITS); + /* Cr=>G value is scaled-up -0.71414 * x */ + upsample->Cr_g_tab[i] = (- FIX(0.71414)) * x; + /* Cb=>G value is scaled-up -0.34414 * x */ + /* We also add in ONE_HALF so that need not do it in inner loop */ + upsample->Cb_g_tab[i] = (- FIX(0.34414)) * x + ONE_HALF; + } +} + + +/* + * Initialize for an upsampling pass. + */ + +METHODDEF(void) +start_pass_merged_upsample (j_decompress_ptr cinfo) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + + /* Mark the spare buffer empty */ + upsample->spare_full = FALSE; + /* Initialize total-height counter for detecting bottom of image */ + upsample->rows_to_go = cinfo->output_height; +} + + +/* + * Control routine to do upsampling (and color conversion). + * + * The control routine just handles the row buffering considerations. + */ + +METHODDEF(void) +merged_2v_upsample (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +/* 2:1 vertical sampling case: may need a spare row. */ +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + JSAMPROW work_ptrs[2]; + JDIMENSION num_rows; /* number of rows returned to caller */ + (void)in_row_groups_avail; + + if (upsample->spare_full) { + /* If we have a spare row saved from a previous cycle, just return it. */ + jcopy_sample_rows(& upsample->spare_row, 0, output_buf + *out_row_ctr, 0, + 1, upsample->out_row_width); + num_rows = 1; + upsample->spare_full = FALSE; + } else { + /* Figure number of rows to return to caller. */ + num_rows = 2; + /* Not more than the distance to the end of the image. */ + if (num_rows > upsample->rows_to_go) + num_rows = upsample->rows_to_go; + /* And not more than what the client can accept: */ + out_rows_avail -= *out_row_ctr; + if (num_rows > out_rows_avail) + num_rows = out_rows_avail; + /* Create output pointer array for upsampler. */ + work_ptrs[0] = output_buf[*out_row_ctr]; + if (num_rows > 1) { + work_ptrs[1] = output_buf[*out_row_ctr + 1]; + } else { + work_ptrs[1] = upsample->spare_row; + upsample->spare_full = TRUE; + } + /* Now do the upsampling. */ + (*upsample->upmethod) (cinfo, input_buf, *in_row_group_ctr, work_ptrs); + } + + /* Adjust counts */ + *out_row_ctr += num_rows; + upsample->rows_to_go -= num_rows; + /* When the buffer is emptied, declare this input row group consumed */ + if (! upsample->spare_full) + (*in_row_group_ctr)++; +} + + +METHODDEF(void) +merged_1v_upsample (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +/* 1:1 vertical sampling case: much easier, never need a spare row. */ +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + (void)in_row_groups_avail;(void)out_rows_avail; + + /* Just do the upsampling. */ + (*upsample->upmethod) (cinfo, input_buf, *in_row_group_ctr, + output_buf + *out_row_ctr); + /* Adjust counts */ + (*out_row_ctr)++; + (*in_row_group_ctr)++; +} + + +/* + * These are the routines invoked by the control routines to do + * the actual upsampling/conversion. One row group is processed per call. + * + * Note: since we may be writing directly into application-supplied buffers, + * we have to be honest about the output width; we can't assume the buffer + * has been rounded up to an even width. + */ + + +/* + * Upsample and color convert for the case of 2:1 horizontal and 1:1 vertical. + */ + +METHODDEF(void) +h2v1_merged_upsample (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr, + JSAMPARRAY output_buf) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + register int y, cred, cgreen, cblue; + int cb, cr; + register JSAMPROW outptr; + JSAMPROW inptr0, inptr1, inptr2; + JDIMENSION col; + /* copy these pointers into registers if possible */ + register JSAMPLE * range_limit = cinfo->sample_range_limit; + int * Crrtab = upsample->Cr_r_tab; + int * Cbbtab = upsample->Cb_b_tab; + INT32 * Crgtab = upsample->Cr_g_tab; + INT32 * Cbgtab = upsample->Cb_g_tab; + SHIFT_TEMPS + + inptr0 = input_buf[0][in_row_group_ctr]; + inptr1 = input_buf[1][in_row_group_ctr]; + inptr2 = input_buf[2][in_row_group_ctr]; + outptr = output_buf[0]; + /* Loop for each pair of output pixels */ + for (col = cinfo->output_width >> 1; col > 0; col--) { + /* Do the chroma part of the calculation */ + cb = GETJSAMPLE(*inptr1++); + cr = GETJSAMPLE(*inptr2++); + cred = Crrtab[cr]; + cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS); + cblue = Cbbtab[cb]; + /* Fetch 2 Y values and emit 2 pixels */ + y = GETJSAMPLE(*inptr0++); + outptr[RGB_RED] = range_limit[y + cred]; + outptr[RGB_GREEN] = range_limit[y + cgreen]; + outptr[RGB_BLUE] = range_limit[y + cblue]; + outptr += RGB_PIXELSIZE; + y = GETJSAMPLE(*inptr0++); + outptr[RGB_RED] = range_limit[y + cred]; + outptr[RGB_GREEN] = range_limit[y + cgreen]; + outptr[RGB_BLUE] = range_limit[y + cblue]; + outptr += RGB_PIXELSIZE; + } + /* If image width is odd, do the last output column separately */ + if (cinfo->output_width & 1) { + cb = GETJSAMPLE(*inptr1); + cr = GETJSAMPLE(*inptr2); + cred = Crrtab[cr]; + cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS); + cblue = Cbbtab[cb]; + y = GETJSAMPLE(*inptr0); + outptr[RGB_RED] = range_limit[y + cred]; + outptr[RGB_GREEN] = range_limit[y + cgreen]; + outptr[RGB_BLUE] = range_limit[y + cblue]; + } +} + + +/* + * Upsample and color convert for the case of 2:1 horizontal and 2:1 vertical. + */ + +METHODDEF(void) +h2v2_merged_upsample (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr, + JSAMPARRAY output_buf) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + register int y, cred, cgreen, cblue; + int cb, cr; + register JSAMPROW outptr0, outptr1; + JSAMPROW inptr00, inptr01, inptr1, inptr2; + JDIMENSION col; + /* copy these pointers into registers if possible */ + register JSAMPLE * range_limit = cinfo->sample_range_limit; + int * Crrtab = upsample->Cr_r_tab; + int * Cbbtab = upsample->Cb_b_tab; + INT32 * Crgtab = upsample->Cr_g_tab; + INT32 * Cbgtab = upsample->Cb_g_tab; + SHIFT_TEMPS + + inptr00 = input_buf[0][in_row_group_ctr*2]; + inptr01 = input_buf[0][in_row_group_ctr*2 + 1]; + inptr1 = input_buf[1][in_row_group_ctr]; + inptr2 = input_buf[2][in_row_group_ctr]; + outptr0 = output_buf[0]; + outptr1 = output_buf[1]; + /* Loop for each group of output pixels */ + for (col = cinfo->output_width >> 1; col > 0; col--) { + /* Do the chroma part of the calculation */ + cb = GETJSAMPLE(*inptr1++); + cr = GETJSAMPLE(*inptr2++); + cred = Crrtab[cr]; + cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS); + cblue = Cbbtab[cb]; + /* Fetch 4 Y values and emit 4 pixels */ + y = GETJSAMPLE(*inptr00++); + outptr0[RGB_RED] = range_limit[y + cred]; + outptr0[RGB_GREEN] = range_limit[y + cgreen]; + outptr0[RGB_BLUE] = range_limit[y + cblue]; + outptr0 += RGB_PIXELSIZE; + y = GETJSAMPLE(*inptr00++); + outptr0[RGB_RED] = range_limit[y + cred]; + outptr0[RGB_GREEN] = range_limit[y + cgreen]; + outptr0[RGB_BLUE] = range_limit[y + cblue]; + outptr0 += RGB_PIXELSIZE; + y = GETJSAMPLE(*inptr01++); + outptr1[RGB_RED] = range_limit[y + cred]; + outptr1[RGB_GREEN] = range_limit[y + cgreen]; + outptr1[RGB_BLUE] = range_limit[y + cblue]; + outptr1 += RGB_PIXELSIZE; + y = GETJSAMPLE(*inptr01++); + outptr1[RGB_RED] = range_limit[y + cred]; + outptr1[RGB_GREEN] = range_limit[y + cgreen]; + outptr1[RGB_BLUE] = range_limit[y + cblue]; + outptr1 += RGB_PIXELSIZE; + } + /* If image width is odd, do the last output column separately */ + if (cinfo->output_width & 1) { + cb = GETJSAMPLE(*inptr1); + cr = GETJSAMPLE(*inptr2); + cred = Crrtab[cr]; + cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS); + cblue = Cbbtab[cb]; + y = GETJSAMPLE(*inptr00); + outptr0[RGB_RED] = range_limit[y + cred]; + outptr0[RGB_GREEN] = range_limit[y + cgreen]; + outptr0[RGB_BLUE] = range_limit[y + cblue]; + y = GETJSAMPLE(*inptr01); + outptr1[RGB_RED] = range_limit[y + cred]; + outptr1[RGB_GREEN] = range_limit[y + cgreen]; + outptr1[RGB_BLUE] = range_limit[y + cblue]; + } +} + + +/* + * Module initialization routine for merged upsampling/color conversion. + * + * NB: this is called under the conditions determined by use_merged_upsample() + * in jdmaster.c. That routine MUST correspond to the actual capabilities + * of this module; no safety checks are made here. + */ + +GLOBAL(void) +jinit_merged_upsampler (j_decompress_ptr cinfo) +{ + my_upsample_ptr upsample; + + upsample = (my_upsample_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_upsampler)); + cinfo->upsample = (struct jpeg_upsampler *) upsample; + upsample->pub.start_pass = start_pass_merged_upsample; + upsample->pub.need_context_rows = FALSE; + + upsample->out_row_width = cinfo->output_width * cinfo->out_color_components; + + if (cinfo->max_v_samp_factor == 2) { + upsample->pub.upsample = merged_2v_upsample; + upsample->upmethod = h2v2_merged_upsample; + /* Allocate a spare row buffer */ + upsample->spare_row = (JSAMPROW) + (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (size_t) (upsample->out_row_width * SIZEOF(JSAMPLE))); + } else { + upsample->pub.upsample = merged_1v_upsample; + upsample->upmethod = h2v1_merged_upsample; + /* No spare row needed */ + upsample->spare_row = NULL; + } + + build_ycc_rgb_table(cinfo); +} + +#endif /* UPSAMPLE_MERGING_SUPPORTED */ diff --git a/gdcm/Utilities/gdcmjpeg/jdphuff.c b/gdcm/Utilities/gdcmjpeg/jdphuff.c new file mode 100644 index 0000000..a2389f8 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jdphuff.c @@ -0,0 +1,675 @@ +/* + * jdphuff.c + * + * Copyright (C) 1995-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains Huffman entropy decoding routines for progressive JPEG. + * + * Much of the complexity here has to do with supporting input suspension. + * If the data source module demands suspension, we want to be able to back + * up to the start of the current MCU. To do this, we copy state variables + * into local working storage, and update them back to the permanent + * storage only upon successful completion of an MCU. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jlossy.h" /* Private declarations for lossy subsystem */ +#include "jdhuff.h" /* Declarations shared with jd*huff.c */ + + +#ifdef D_PROGRESSIVE_SUPPORTED + +/* + * Private entropy decoder object for progressive Huffman decoding. + * + * The savable_state subrecord contains fields that change within an MCU, + * but must not be updated permanently until we complete the MCU. + */ + +typedef struct { + unsigned int EOBRUN; /* remaining EOBs in EOBRUN */ + int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */ +} savable_state; + +/* This macro is to work around compilers with missing or broken + * structure assignment. You'll need to fix this code if you have + * such a compiler and you change MAX_COMPS_IN_SCAN. + */ + +#ifndef NO_STRUCT_ASSIGN +#define ASSIGN_STATE(dest,src) ((dest) = (src)) +#else +#if MAX_COMPS_IN_SCAN == 4 +#define ASSIGN_STATE(dest,src) \ + ((dest).EOBRUN = (src).EOBRUN, \ + (dest).last_dc_val[0] = (src).last_dc_val[0], \ + (dest).last_dc_val[1] = (src).last_dc_val[1], \ + (dest).last_dc_val[2] = (src).last_dc_val[2], \ + (dest).last_dc_val[3] = (src).last_dc_val[3]) +#endif +#endif + + +typedef struct { + huffd_common_fields; /* Fields shared with other entropy decoders */ + + /* These fields are loaded into local variables at start of each MCU. + * In case of suspension, we exit WITHOUT updating them. + */ + savable_state saved; /* Other state at start of MCU */ + + /* These fields are NOT loaded into local working state. */ + unsigned int restarts_to_go; /* MCUs left in this restart interval */ + + /* Pointers to derived tables (these workspaces have image lifespan) */ + d_derived_tbl * derived_tbls[NUM_HUFF_TBLS]; + + d_derived_tbl * ac_derived_tbl; /* active table during an AC scan */ +} phuff_entropy_decoder; + +typedef phuff_entropy_decoder * phuff_entropy_ptr; + +/* Forward declarations */ +METHODDEF(boolean) decode_mcu_DC_first JPP((j_decompress_ptr cinfo, + JBLOCKROW *MCU_data)); +METHODDEF(boolean) decode_mcu_AC_first JPP((j_decompress_ptr cinfo, + JBLOCKROW *MCU_data)); +METHODDEF(boolean) decode_mcu_DC_refine JPP((j_decompress_ptr cinfo, + JBLOCKROW *MCU_data)); +METHODDEF(boolean) decode_mcu_AC_refine JPP((j_decompress_ptr cinfo, + JBLOCKROW *MCU_data)); + + +/* + * Initialize for a Huffman-compressed scan. + */ + +METHODDEF(void) +start_pass_phuff_decoder (j_decompress_ptr cinfo) +{ + j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; + phuff_entropy_ptr entropy = (phuff_entropy_ptr) lossyd->entropy_private; + boolean is_DC_band, bad; + int ci, coefi, tbl; + int *coef_bit_ptr; + jpeg_component_info * compptr; + + is_DC_band = (cinfo->Ss == 0); + + /* Validate scan parameters */ + bad = FALSE; + if (is_DC_band) { + if (cinfo->Se != 0) + bad = TRUE; + } else { + /* need not check Ss/Se < 0 since they came from unsigned bytes */ + if (cinfo->Ss > cinfo->Se || cinfo->Se >= DCTSIZE2) + bad = TRUE; + /* AC scans may have only one component */ + if (cinfo->comps_in_scan != 1) + bad = TRUE; + } + if (cinfo->Ah != 0) { + /* Successive approximation refinement scan: must have Al = Ah-1. */ + if (cinfo->Al != cinfo->Ah-1) + bad = TRUE; + } + if (cinfo->Al > 13) /* need not check for < 0 */ + bad = TRUE; + /* Arguably the maximum Al value should be less than 13 for 8-bit precision, + * but the spec doesn't say so, and we try to be liberal about what we + * accept. Note: large Al values could result in out-of-range DC + * coefficients during early scans, leading to bizarre displays due to + * overflows in the IDCT math. But we won't crash. + */ + if (bad) + ERREXIT4(cinfo, JERR_BAD_PROGRESSION, + cinfo->Ss, cinfo->Se, cinfo->Ah, cinfo->Al); + /* Update progression status, and verify that scan order is legal. + * Note that inter-scan inconsistencies are treated as warnings + * not fatal errors ... not clear if this is right way to behave. + */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + int cindex = cinfo->cur_comp_info[ci]->component_index; + coef_bit_ptr = & cinfo->coef_bits[cindex][0]; + if (!is_DC_band && coef_bit_ptr[0] < 0) /* AC without prior DC scan */ + WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, 0); + for (coefi = cinfo->Ss; coefi <= cinfo->Se; coefi++) { + int expected = (coef_bit_ptr[coefi] < 0) ? 0 : coef_bit_ptr[coefi]; + if (cinfo->Ah != expected) + WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, coefi); + coef_bit_ptr[coefi] = cinfo->Al; + } + } + + /* Select MCU decoding routine */ + if (cinfo->Ah == 0) { + if (is_DC_band) + lossyd->entropy_decode_mcu = decode_mcu_DC_first; + else + lossyd->entropy_decode_mcu = decode_mcu_AC_first; + } else { + if (is_DC_band) + lossyd->entropy_decode_mcu = decode_mcu_DC_refine; + else + lossyd->entropy_decode_mcu = decode_mcu_AC_refine; + } + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* Make sure requested tables are present, and compute derived tables. + * We may build same derived table more than once, but it's not expensive. + */ + if (is_DC_band) { + if (cinfo->Ah == 0) { /* DC refinement needs no table */ + tbl = compptr->dc_tbl_no; + jpeg_make_d_derived_tbl(cinfo, TRUE, tbl, + & entropy->derived_tbls[tbl]); + } + } else { + tbl = compptr->ac_tbl_no; + jpeg_make_d_derived_tbl(cinfo, FALSE, tbl, + & entropy->derived_tbls[tbl]); + /* remember the single active table */ + entropy->ac_derived_tbl = entropy->derived_tbls[tbl]; + } + /* Initialize DC predictions to 0 */ + entropy->saved.last_dc_val[ci] = 0; + } + + /* Initialize bitread state variables */ + entropy->bitstate.bits_left = 0; + entropy->bitstate.get_buffer = 0; /* unnecessary, but keeps Purify quiet */ + entropy->insufficient_data = FALSE; + + /* Initialize private state variables */ + entropy->saved.EOBRUN = 0; + + /* Initialize restart counter */ + entropy->restarts_to_go = cinfo->restart_interval; +} + + +/* + * Figure F.12: extend sign bit. + * On some machines, a shift and add will be faster than a table lookup. + */ + +#ifdef AVOID_TABLES + +#define HUFF_EXTEND(x,s) ((x) < (1<<((s)-1)) ? (x) + (((-1)<<(s)) + 1) : (x)) + +#else + +#define HUFF_EXTEND(x,s) ((x) < extend_test[s] ? (x) + extend_offset[s] : (x)) + +static const int extend_test[16] = /* entry n is 2**(n-1) */ + { 0, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, + 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000 }; + +static const int extend_offset[16] = /* entry n is (-1 << n) + 1 */ + { 0, ((-1)<<1) + 1, ((-1)<<2) + 1, ((-1)<<3) + 1, ((-1)<<4) + 1, + ((-1)<<5) + 1, ((-1)<<6) + 1, ((-1)<<7) + 1, ((-1)<<8) + 1, + ((-1)<<9) + 1, ((-1)<<10) + 1, ((-1)<<11) + 1, ((-1)<<12) + 1, + ((-1)<<13) + 1, ((-1)<<14) + 1, ((-1)<<15) + 1 }; + +#endif /* AVOID_TABLES */ + + +/* + * Check for a restart marker & resynchronize decoder. + * Returns FALSE if must suspend. + */ + +LOCAL(boolean) +process_restart (j_decompress_ptr cinfo) +{ + j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; + phuff_entropy_ptr entropy = (phuff_entropy_ptr) lossyd->entropy_private; + int ci; + + /* Throw away any unused bits remaining in bit buffer; */ + /* include any full bytes in next_marker's count of discarded bytes */ + cinfo->marker->discarded_bytes += entropy->bitstate.bits_left / 8; + entropy->bitstate.bits_left = 0; + + /* Advance past the RSTn marker */ + if (! (*cinfo->marker->read_restart_marker) (cinfo)) + return FALSE; + + /* Re-initialize DC predictions to 0 */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) + entropy->saved.last_dc_val[ci] = 0; + /* Re-init EOB run count, too */ + entropy->saved.EOBRUN = 0; + + /* Reset restart counter */ + entropy->restarts_to_go = cinfo->restart_interval; + + /* Reset out-of-data flag, unless read_restart_marker left us smack up + * against a marker. In that case we will end up treating the next data + * segment as empty, and we can avoid producing bogus output pixels by + * leaving the flag set. + */ + if (cinfo->unread_marker == 0) + entropy->insufficient_data = FALSE; + + return TRUE; +} + + +/* + * Huffman MCU decoding. + * Each of these routines decodes and returns one MCU's worth of + * Huffman-compressed coefficients. + * The coefficients are reordered from zigzag order into natural array order, + * but are not dequantized. + * + * The i'th block of the MCU is stored into the block pointed to by + * MCU_data[i]. WE ASSUME THIS AREA IS INITIALLY ZEROED BY THE CALLER. + * + * We return FALSE if data source requested suspension. In that case no + * changes have been made to permanent state. (Exception: some output + * coefficients may already have been assigned. This is harmless for + * spectral selection, since we'll just re-assign them on the next call. + * Successive approximation AC refinement has to be more careful, however.) + */ + +/* + * MCU decoding for DC initial scan (either spectral selection, + * or first pass of successive approximation). + */ + +METHODDEF(boolean) +decode_mcu_DC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) +{ + j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; + phuff_entropy_ptr entropy = (phuff_entropy_ptr) lossyd->entropy_private; + int Al = cinfo->Al; + register int s, r; + int blkn, ci; + JBLOCKROW block; + BITREAD_STATE_VARS; + savable_state state; + d_derived_tbl * tbl; + jpeg_component_info * compptr; + + /* Process restart marker if needed; may have to suspend */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + if (! process_restart(cinfo)) + return FALSE; + } + + /* If we've run out of data, just leave the MCU set to zeroes. + * This way, we return uniform gray for the remainder of the segment. + */ + if (! entropy->insufficient_data) { + + /* Load up working state */ + BITREAD_LOAD_STATE(cinfo,entropy->bitstate); + ASSIGN_STATE(state, entropy->saved); + + /* Outer loop handles each block in the MCU */ + + for (blkn = 0; blkn < cinfo->data_units_in_MCU; blkn++) { + block = MCU_data[blkn]; + ci = cinfo->MCU_membership[blkn]; + compptr = cinfo->cur_comp_info[ci]; + tbl = entropy->derived_tbls[compptr->dc_tbl_no]; + + /* Decode a single block's worth of coefficients */ + + /* Section F.2.2.1: decode the DC coefficient difference */ + HUFF_DECODE(s, br_state, tbl, return FALSE, label1); + if (s) { + CHECK_BIT_BUFFER(br_state, s, return FALSE); + r = GET_BITS(s); + s = HUFF_EXTEND(r, s); + } + + /* Convert DC difference to actual value, update last_dc_val */ + s += state.last_dc_val[ci]; + state.last_dc_val[ci] = s; + /* Scale and output the coefficient (assumes jpeg_natural_order[0]=0) */ + (*block)[0] = (JCOEF) (s << Al); + } + + /* Completed MCU, so update state */ + BITREAD_SAVE_STATE(cinfo,entropy->bitstate); + ASSIGN_STATE(entropy->saved, state); + } + + /* Account for restart interval (no-op if not using restarts) */ + entropy->restarts_to_go--; + + return TRUE; +} + + +/* + * MCU decoding for AC initial scan (either spectral selection, + * or first pass of successive approximation). + */ + +METHODDEF(boolean) +decode_mcu_AC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) +{ + j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; + phuff_entropy_ptr entropy = (phuff_entropy_ptr) lossyd->entropy_private; + int Se = cinfo->Se; + int Al = cinfo->Al; + register int s, k, r; + unsigned int EOBRUN; + JBLOCKROW block; + BITREAD_STATE_VARS; + d_derived_tbl * tbl; + + /* Process restart marker if needed; may have to suspend */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + if (! process_restart(cinfo)) + return FALSE; + } + + /* If we've run out of data, just leave the MCU set to zeroes. + * This way, we return uniform gray for the remainder of the segment. + */ + if (! entropy->insufficient_data) { + + /* Load up working state. + * We can avoid loading/saving bitread state if in an EOB run. + */ + EOBRUN = entropy->saved.EOBRUN; /* only part of saved state we need */ + + /* There is always only one block per MCU */ + + if (EOBRUN > 0) /* if it's a band of zeroes... */ + EOBRUN--; /* ...process it now (we do nothing) */ + else { + BITREAD_LOAD_STATE(cinfo,entropy->bitstate); + block = MCU_data[0]; + tbl = entropy->ac_derived_tbl; + + for (k = cinfo->Ss; k <= Se; k++) { + HUFF_DECODE(s, br_state, tbl, return FALSE, label2); + r = s >> 4; + s &= 15; + if (s) { + k += r; + CHECK_BIT_BUFFER(br_state, s, return FALSE); + r = GET_BITS(s); + s = HUFF_EXTEND(r, s); + /* Scale and output coefficient in natural (dezigzagged) order */ + (*block)[jpeg_natural_order[k]] = (JCOEF) (s << Al); + } else { + if (r == 15) { /* ZRL */ + k += 15; /* skip 15 zeroes in band */ + } else { /* EOBr, run length is 2^r + appended bits */ + EOBRUN = 1 << r; + if (r) { /* EOBr, r > 0 */ + CHECK_BIT_BUFFER(br_state, r, return FALSE); + r = GET_BITS(r); + EOBRUN += r; + } + EOBRUN--; /* this band is processed at this moment */ + break; /* force end-of-band */ + } + } + } + + BITREAD_SAVE_STATE(cinfo,entropy->bitstate); + } + + /* Completed MCU, so update state */ + entropy->saved.EOBRUN = EOBRUN; /* only part of saved state we need */ + } + + /* Account for restart interval (no-op if not using restarts) */ + entropy->restarts_to_go--; + + return TRUE; +} + + +/* + * MCU decoding for DC successive approximation refinement scan. + * Note: we assume such scans can be multi-component, although the spec + * is not very clear on the point. + */ + +METHODDEF(boolean) +decode_mcu_DC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) +{ + j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; + phuff_entropy_ptr entropy = (phuff_entropy_ptr) lossyd->entropy_private; + int p1 = 1 << cinfo->Al; /* 1 in the bit position being coded */ + int blkn; + JBLOCKROW block; + BITREAD_STATE_VARS; + + /* Process restart marker if needed; may have to suspend */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + if (! process_restart(cinfo)) + return FALSE; + } + + /* Not worth the cycles to check insufficient_data here, + * since we will not change the data anyway if we read zeroes. + */ + + /* Load up working state */ + BITREAD_LOAD_STATE(cinfo,entropy->bitstate); + + /* Outer loop handles each block in the MCU */ + + for (blkn = 0; blkn < cinfo->data_units_in_MCU; blkn++) { + block = MCU_data[blkn]; + + /* Encoded data is simply the next bit of the two's-complement DC value */ + CHECK_BIT_BUFFER(br_state, 1, return FALSE); + if (GET_BITS(1)) + (*block)[0] |= p1; + /* Note: since we use |=, repeating the assignment later is safe */ + } + + /* Completed MCU, so update state */ + BITREAD_SAVE_STATE(cinfo,entropy->bitstate); + + /* Account for restart interval (no-op if not using restarts) */ + entropy->restarts_to_go--; + + return TRUE; +} + + +/* + * MCU decoding for AC successive approximation refinement scan. + */ + +METHODDEF(boolean) +decode_mcu_AC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) +{ + j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; + phuff_entropy_ptr entropy = (phuff_entropy_ptr) lossyd->entropy_private; + int Se = cinfo->Se; + int p1 = 1 << cinfo->Al; /* 1 in the bit position being coded */ + int m1 = (-1) << cinfo->Al; /* -1 in the bit position being coded */ + register int s, k, r; + unsigned int EOBRUN; + JBLOCKROW block; + JCOEFPTR thiscoef; + BITREAD_STATE_VARS; + d_derived_tbl * tbl; + int num_newnz; + int newnz_pos[DCTSIZE2]; + + /* Process restart marker if needed; may have to suspend */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + if (! process_restart(cinfo)) + return FALSE; + } + + /* If we've run out of data, don't modify the MCU. + */ + if (! entropy->insufficient_data) { + + /* Load up working state */ + BITREAD_LOAD_STATE(cinfo,entropy->bitstate); + EOBRUN = entropy->saved.EOBRUN; /* only part of saved state we need */ + + /* There is always only one block per MCU */ + block = MCU_data[0]; + tbl = entropy->ac_derived_tbl; + + /* If we are forced to suspend, we must undo the assignments to any newly + * nonzero coefficients in the block, because otherwise we'd get confused + * next time about which coefficients were already nonzero. + * But we need not undo addition of bits to already-nonzero coefficients; + * instead, we can test the current bit to see if we already did it. + */ + num_newnz = 0; + + /* initialize coefficient loop counter to start of band */ + k = cinfo->Ss; + + if (EOBRUN == 0) { + for (; k <= Se; k++) { + HUFF_DECODE(s, br_state, tbl, goto undoit, label3); + r = s >> 4; + s &= 15; + if (s) { + if (s != 1) /* size of new coef should always be 1 */ + WARNMS(cinfo, JWRN_HUFF_BAD_CODE); + CHECK_BIT_BUFFER(br_state, 1, goto undoit); + if (GET_BITS(1)) + s = p1; /* newly nonzero coef is positive */ + else + s = m1; /* newly nonzero coef is negative */ + } else { + if (r != 15) { + EOBRUN = 1 << r; /* EOBr, run length is 2^r + appended bits */ + if (r) { + CHECK_BIT_BUFFER(br_state, r, goto undoit); + r = GET_BITS(r); + EOBRUN += r; + } + break; /* rest of block is handled by EOB logic */ + } + /* note s = 0 for processing ZRL */ + } + /* Advance over already-nonzero coefs and r still-zero coefs, + * appending correction bits to the nonzeroes. A correction bit is 1 + * if the absolute value of the coefficient must be increased. + */ + do { + thiscoef = *block + jpeg_natural_order[k]; + if (*thiscoef != 0) { + CHECK_BIT_BUFFER(br_state, 1, goto undoit); + if (GET_BITS(1)) { + if ((*thiscoef & p1) == 0) { /* do nothing if already set it */ + if (*thiscoef >= 0) + *thiscoef += p1; + else + *thiscoef += m1; + } + } + } else { + if (--r < 0) + break; /* reached target zero coefficient */ + } + k++; + } while (k <= Se); + if (s) { + int pos = jpeg_natural_order[k]; + /* Output newly nonzero coefficient */ + (*block)[pos] = (JCOEF) s; + /* Remember its position in case we have to suspend */ + newnz_pos[num_newnz++] = pos; + } + } + } + + if (EOBRUN > 0) { + /* Scan any remaining coefficient positions after the end-of-band + * (the last newly nonzero coefficient, if any). Append a correction + * bit to each already-nonzero coefficient. A correction bit is 1 + * if the absolute value of the coefficient must be increased. + */ + for (; k <= Se; k++) { + thiscoef = *block + jpeg_natural_order[k]; + if (*thiscoef != 0) { + CHECK_BIT_BUFFER(br_state, 1, goto undoit); + if (GET_BITS(1)) { + if ((*thiscoef & p1) == 0) { /* do nothing if already changed it */ + if (*thiscoef >= 0) + *thiscoef += p1; + else + *thiscoef += m1; + } + } + } + } + /* Count one block completed in EOB run */ + EOBRUN--; + } + + /* Completed MCU, so update state */ + BITREAD_SAVE_STATE(cinfo,entropy->bitstate); + entropy->saved.EOBRUN = EOBRUN; /* only part of saved state we need */ + } + + /* Account for restart interval (no-op if not using restarts) */ + entropy->restarts_to_go--; + + return TRUE; + +undoit: + /* Re-zero any output coefficients that we made newly nonzero */ + while (num_newnz > 0) + (*block)[newnz_pos[--num_newnz]] = 0; + + return FALSE; +} + + +/* + * Module initialization routine for progressive Huffman entropy decoding. + */ + +GLOBAL(void) +jinit_phuff_decoder (j_decompress_ptr cinfo) +{ + j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; + phuff_entropy_ptr entropy; + int *coef_bit_ptr; + int ci, i; + + entropy = (phuff_entropy_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(phuff_entropy_decoder)); + lossyd->entropy_private = (void *) entropy; + lossyd->entropy_start_pass = start_pass_phuff_decoder; + + /* Mark derived tables unallocated */ + for (i = 0; i < NUM_HUFF_TBLS; i++) { + entropy->derived_tbls[i] = NULL; + } + + /* Create progression status table */ + cinfo->coef_bits = (int (*)[DCTSIZE2]) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + cinfo->num_components*DCTSIZE2*SIZEOF(int)); + coef_bit_ptr = & cinfo->coef_bits[0][0]; + for (ci = 0; ci < cinfo->num_components; ci++) + for (i = 0; i < DCTSIZE2; i++) + *coef_bit_ptr++ = -1; +} + +#endif /* D_PROGRESSIVE_SUPPORTED */ diff --git a/gdcm/Utilities/gdcmjpeg/jdpostct.c b/gdcm/Utilities/gdcmjpeg/jdpostct.c new file mode 100644 index 0000000..760eb19 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jdpostct.c @@ -0,0 +1,292 @@ +/* + * jdpostct.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the decompression postprocessing controller. + * This controller manages the upsampling, color conversion, and color + * quantization/reduction steps; specifically, it controls the buffering + * between upsample/color conversion and color quantization/reduction. + * + * If no color quantization/reduction is required, then this module has no + * work to do, and it just hands off to the upsample/color conversion code. + * An integrated upsample/convert/quantize process would replace this module + * entirely. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Private buffer controller object */ + +typedef struct { + struct jpeg_d_post_controller pub; /* public fields */ + + /* Color quantization source buffer: this holds output data from + * the upsample/color conversion step to be passed to the quantizer. + * For two-pass color quantization, we need a full-image buffer; + * for one-pass operation, a strip buffer is sufficient. + */ + jvirt_sarray_ptr whole_image; /* virtual array, or NULL if one-pass */ + JSAMPARRAY buffer; /* strip buffer, or current strip of virtual */ + JDIMENSION strip_height; /* buffer size in rows */ + /* for two-pass mode only: */ + JDIMENSION starting_row; /* row # of first row in current strip */ + JDIMENSION next_row; /* index of next row to fill/empty in strip */ +} my_post_controller; + +typedef my_post_controller * my_post_ptr; + + +/* Forward declarations */ +METHODDEF(void) post_process_1pass + JPP((j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); +#ifdef QUANT_2PASS_SUPPORTED +METHODDEF(void) post_process_prepass + JPP((j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); +METHODDEF(void) post_process_2pass + JPP((j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); +#endif + + +/* + * Initialize for a processing pass. + */ + +METHODDEF(void) +start_pass_dpost (j_decompress_ptr cinfo, J_BUF_MODE pass_mode) +{ + my_post_ptr post = (my_post_ptr) cinfo->post; + + switch (pass_mode) { + case JBUF_PASS_THRU: + if (cinfo->quantize_colors) { + /* Single-pass processing with color quantization. */ + post->pub.post_process_data = post_process_1pass; + /* We could be doing buffered-image output before starting a 2-pass + * color quantization; in that case, jinit_d_post_controller did not + * allocate a strip buffer. Use the virtual-array buffer as workspace. + */ + if (post->buffer == NULL) { + post->buffer = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, post->whole_image, + (JDIMENSION) 0, post->strip_height, TRUE); + } + } else { + /* For single-pass processing without color quantization, + * I have no work to do; just call the upsampler directly. + */ + post->pub.post_process_data = cinfo->upsample->upsample; + } + break; +#ifdef QUANT_2PASS_SUPPORTED + case JBUF_SAVE_AND_PASS: + /* First pass of 2-pass quantization */ + if (post->whole_image == NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + post->pub.post_process_data = post_process_prepass; + break; + case JBUF_CRANK_DEST: + /* Second pass of 2-pass quantization */ + if (post->whole_image == NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + post->pub.post_process_data = post_process_2pass; + break; +#endif /* QUANT_2PASS_SUPPORTED */ + default: + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + break; + } + post->starting_row = post->next_row = 0; +} + + +/* + * Process some data in the one-pass (strip buffer) case. + * This is used for color precision reduction as well as one-pass quantization. + */ + +METHODDEF(void) +post_process_1pass (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +{ + my_post_ptr post = (my_post_ptr) cinfo->post; + JDIMENSION num_rows, max_rows; + + /* Fill the buffer, but not more than what we can dump out in one go. */ + /* Note we rely on the upsampler to detect bottom of image. */ + max_rows = out_rows_avail - *out_row_ctr; + if (max_rows > post->strip_height) + max_rows = post->strip_height; + num_rows = 0; + (*cinfo->upsample->upsample) (cinfo, + input_buf, in_row_group_ctr, in_row_groups_avail, + post->buffer, &num_rows, max_rows); + /* Quantize and emit data. */ + (*cinfo->cquantize->color_quantize) (cinfo, + post->buffer, output_buf + *out_row_ctr, (int) num_rows); + *out_row_ctr += num_rows; +} + + +#ifdef QUANT_2PASS_SUPPORTED + +/* + * Process some data in the first pass of 2-pass quantization. + */ + +METHODDEF(void) +post_process_prepass (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +{ + my_post_ptr post = (my_post_ptr) cinfo->post; + JDIMENSION old_next_row, num_rows; + (void)output_buf;(void)out_rows_avail; + + /* Reposition virtual buffer if at start of strip. */ + if (post->next_row == 0) { + post->buffer = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, post->whole_image, + post->starting_row, post->strip_height, TRUE); + } + + /* Upsample some data (up to a strip height's worth). */ + old_next_row = post->next_row; + (*cinfo->upsample->upsample) (cinfo, + input_buf, in_row_group_ctr, in_row_groups_avail, + post->buffer, &post->next_row, post->strip_height); + + /* Allow quantizer to scan new data. No data is emitted, */ + /* but we advance out_row_ctr so outer loop can tell when we're done. */ + if (post->next_row > old_next_row) { + num_rows = post->next_row - old_next_row; + (*cinfo->cquantize->color_quantize) (cinfo, post->buffer + old_next_row, + (JSAMPARRAY) NULL, (int) num_rows); + *out_row_ctr += num_rows; + } + + /* Advance if we filled the strip. */ + if (post->next_row >= post->strip_height) { + post->starting_row += post->strip_height; + post->next_row = 0; + } +} + + +/* + * Process some data in the second pass of 2-pass quantization. + */ + +METHODDEF(void) +post_process_2pass (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +{ + my_post_ptr post = (my_post_ptr) cinfo->post; + JDIMENSION num_rows, max_rows; + (void)input_buf;(void)in_row_group_ctr;(void)in_row_groups_avail; + + /* Reposition virtual buffer if at start of strip. */ + if (post->next_row == 0) { + post->buffer = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, post->whole_image, + post->starting_row, post->strip_height, FALSE); + } + + /* Determine number of rows to emit. */ + num_rows = post->strip_height - post->next_row; /* available in strip */ + max_rows = out_rows_avail - *out_row_ctr; /* available in output area */ + if (num_rows > max_rows) + num_rows = max_rows; + /* We have to check bottom of image here, can't depend on upsampler. */ + max_rows = cinfo->output_height - post->starting_row; + if (num_rows > max_rows) + num_rows = max_rows; + + /* Quantize and emit data. */ + (*cinfo->cquantize->color_quantize) (cinfo, + post->buffer + post->next_row, output_buf + *out_row_ctr, + (int) num_rows); + *out_row_ctr += num_rows; + + /* Advance if we filled the strip. */ + post->next_row += num_rows; + if (post->next_row >= post->strip_height) { + post->starting_row += post->strip_height; + post->next_row = 0; + } +} + +#endif /* QUANT_2PASS_SUPPORTED */ + + +/* + * Initialize postprocessing controller. + */ + +GLOBAL(void) +jinit_d_post_controller (j_decompress_ptr cinfo, boolean need_full_buffer) +{ + my_post_ptr post; + + post = (my_post_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_post_controller)); + cinfo->post = (struct jpeg_d_post_controller *) post; + post->pub.start_pass = start_pass_dpost; + post->whole_image = NULL; /* flag for no virtual arrays */ + post->buffer = NULL; /* flag for no strip buffer */ + + /* Create the quantization buffer, if needed */ + if (cinfo->quantize_colors) { + /* The buffer strip height is max_v_samp_factor, which is typically + * an efficient number of rows for upsampling to return. + * (In the presence of output rescaling, we might want to be smarter?) + */ + post->strip_height = (JDIMENSION) cinfo->max_v_samp_factor; + if (need_full_buffer) { + /* Two-pass color quantization: need full-image storage. */ + /* We round up the number of rows to a multiple of the strip height. */ +#ifdef QUANT_2PASS_SUPPORTED + post->whole_image = (*cinfo->mem->request_virt_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, + cinfo->output_width * cinfo->out_color_components, + (JDIMENSION) jround_up((long) cinfo->output_height, + (long) post->strip_height), + post->strip_height); +#else + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); +#endif /* QUANT_2PASS_SUPPORTED */ + } else { + /* One-pass color quantization: just make a strip buffer. */ + post->buffer = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + cinfo->output_width * cinfo->out_color_components, + post->strip_height); + } + } +} diff --git a/gdcm/Utilities/gdcmjpeg/jdpred.c b/gdcm/Utilities/gdcmjpeg/jdpred.c new file mode 100644 index 0000000..e4a6f66 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jdpred.c @@ -0,0 +1,312 @@ +/* + * jdpred.c + * + * Copyright (C) 1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains sample undifferencing (reconstruction) for lossless JPEG. + * + * In order to avoid paying the performance penalty of having to check the + * predictor being used and the row being processed for each call of the + * undifferencer, and to promote optimization, we have separate undifferencing + * functions for each case. + * + * We are able to avoid duplicating source code by implementing the predictors + * and undifferencers as macros. Each of the undifferencing functions are + * simply wrappers around an UNDIFFERENCE macro with the appropriate PREDICTOR + * macro passed as an argument. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jlossls.h" /* Private declarations for lossless codec */ + + +#ifdef D_LOSSLESS_SUPPORTED + +/* Predictor for the first column of the first row: 2^(P-Pt-1) */ +#define INITIAL_PREDICTORx (1 << (cinfo->data_precision - cinfo->Al - 1)) + +/* Predictor for the first column of the remaining rows: Rb */ +#define INITIAL_PREDICTOR2 GETJSAMPLE(prev_row[0]) + + +/* + * 1-Dimensional undifferencer routine. + * + * This macro implements the 1-D horizontal predictor (1). INITIAL_PREDICTOR + * is used as the special case predictor for the first column, which must be + * either INITIAL_PREDICTOR2 or INITIAL_PREDICTORx. The remaining samples + * use PREDICTOR1. + * + * The reconstructed sample is supposed to be calculated modulo 2^16, so we + * logically AND the result with 0xFFFF. +*/ + +#define UNDIFFERENCE_1D(INITIAL_PREDICTOR) \ + unsigned int xindex; \ + int Ra; \ + \ + Ra = (diff_buf[0] + INITIAL_PREDICTOR) & 0xFFFF; \ + undiff_buf[0] = Ra; \ + \ + for (xindex = 1; xindex < width; xindex++) { \ + Ra = (diff_buf[xindex] + PREDICTOR1) & 0xFFFF; \ + undiff_buf[xindex] = Ra; \ + } + +/* + * 2-Dimensional undifferencer routine. + * + * This macro implements the 2-D horizontal predictors (#2-7). PREDICTOR2 is + * used as the special case predictor for the first column. The remaining + * samples use PREDICTOR, which is a function of Ra, Rb, Rc. + * + * Because prev_row and output_buf may point to the same storage area (in an + * interleaved image with Vi=1, for example), we must take care to buffer Rb/Rc + * before writing the current reconstructed sample value into output_buf. + * + * The reconstructed sample is supposed to be calculated modulo 2^16, so we + * logically AND the result with 0xFFFF. + */ + +#define UNDIFFERENCE_2D_BUG(PREDICTOR) \ + Rb = GETJSAMPLE(prev_row[0]); \ + Ra = (diff_buf[0] + PREDICTOR2) & 0xFFFF; \ + undiff_buf[0] = Ra; \ + \ + for (xindex = 1; xindex < width; xindex++) { \ + Rc = Rb; \ + Rb = GETJSAMPLE(prev_row[xindex]); \ + Ra = (diff_buf[xindex] + PREDICTOR) & 0xFFFF; \ + undiff_buf[xindex] = Ra; \ + } + +#define UNDIFFERENCE_2D(PREDICTOR) \ + unsigned int xindex; \ + int Ra, Rb, Rc; \ + \ + Rb = GETJSAMPLE(prev_row[0]); \ + Ra = (diff_buf[0] + PREDICTOR2) & 0xFFFF; \ + undiff_buf[0] = Ra; \ + \ + for (xindex = 1; xindex < width; xindex++) { \ + Rc = Rb; \ + Rb = GETJSAMPLE(prev_row[xindex]); \ + Ra = (diff_buf[xindex] + PREDICTOR) & 0xFFFF; \ + undiff_buf[xindex] = Ra; \ + } + + +/* + * Undifferencers for the all rows but the first in a scan or restart interval. + * The first sample in the row is undifferenced using the vertical + * predictor (2). The rest of the samples are undifferenced using the + * predictor specified in the scan header. + */ + +METHODDEF(void) +jpeg_undifference1(j_decompress_ptr cinfo, int comp_index, + JDIFFROW diff_buf, JDIFFROW prev_row, + JDIFFROW undiff_buf, JDIMENSION width) +{ + UNDIFFERENCE_1D(INITIAL_PREDICTOR2); + (void)cinfo;(void)comp_index;(void)diff_buf;(void)prev_row;(void)undiff_buf;(void)width; +} + +METHODDEF(void) +jpeg_undifference2(j_decompress_ptr cinfo, int comp_index, + JDIFFROW diff_buf, JDIFFROW prev_row, + JDIFFROW undiff_buf, JDIMENSION width) +{ + UNDIFFERENCE_2D(PREDICTOR2); + (void)cinfo;(void)comp_index;(void)diff_buf;(void)prev_row;(void)undiff_buf;(void)width; +} + +METHODDEF(void) +jpeg_undifference3(j_decompress_ptr cinfo, int comp_index, + JDIFFROW diff_buf, JDIFFROW prev_row, + JDIFFROW undiff_buf, JDIMENSION width) +{ + UNDIFFERENCE_2D(PREDICTOR3); + (void)cinfo;(void)comp_index;(void)diff_buf;(void)prev_row;(void)undiff_buf;(void)width; +} + +METHODDEF(void) +jpeg_undifference4(j_decompress_ptr cinfo, int comp_index, + JDIFFROW diff_buf, JDIFFROW prev_row, + JDIFFROW undiff_buf, JDIMENSION width) +{ + UNDIFFERENCE_2D(PREDICTOR4); + (void)cinfo;(void)comp_index;(void)diff_buf;(void)prev_row;(void)undiff_buf;(void)width; +} + +METHODDEF(void) +jpeg_undifference5(j_decompress_ptr cinfo, int comp_index, + JDIFFROW diff_buf, JDIFFROW prev_row, + JDIFFROW undiff_buf, JDIMENSION width) +{ + SHIFT_TEMPS + UNDIFFERENCE_2D(PREDICTOR5); + (void)cinfo;(void)comp_index;(void)diff_buf;(void)prev_row;(void)undiff_buf;(void)width; +} + +#ifdef SUPPORT_DICOMOBJECTS_BUG +/* uninitialized */ +static int dicomobjectsbug = -1; /* 0 == nobug, 1 == bug */ +#endif + +METHODDEF(void) +jpeg_undifference6(j_decompress_ptr cinfo, int comp_index, + JDIFFROW diff_buf, JDIFFROW prev_row, + JDIFFROW undiff_buf, JDIMENSION width) +{ +#ifdef SUPPORT_DICOMOBJECTS_BUG + unsigned int xindex; + int Ra, Rb, Rc; + int min, max, temp; + SHIFT_TEMPS + if( dicomobjectsbug == -1 ) + { + dicomobjectsbug = 0; /* no bug by default */ + + Rb = GETJSAMPLE(prev_row[0]); + Ra = (diff_buf[0] + PREDICTOR2) & 0xFFFF; + undiff_buf[0] = Ra; + temp = min = max = undiff_buf[0]; + + for (xindex = 1; xindex < width; xindex++) { + Rc = Rb; + Rb = GETJSAMPLE(prev_row[xindex]); + Ra = (diff_buf[xindex] + PREDICTOR6) & 0xFFFF; + temp = Ra; + min = temp < min ? temp : min; + max = temp > max ? temp : max; + } + if( (max - min) > 50000) /* magic number */ + { + dicomobjectsbug = 1; + WARNMS(cinfo, JWRN_SIGNED_ARITH); + } + } + if(dicomobjectsbug) + { + UNDIFFERENCE_2D_BUG(PREDICTOR6_BUG); + } + else + { + UNDIFFERENCE_2D_BUG(PREDICTOR6); + } +#else + SHIFT_TEMPS + UNDIFFERENCE_2D(PREDICTOR6); +#endif + (void)comp_index;(void)cinfo; +} + +METHODDEF(void) +jpeg_undifference7(j_decompress_ptr cinfo, int comp_index, + JDIFFROW diff_buf, JDIFFROW prev_row, + JDIFFROW undiff_buf, JDIMENSION width) +{ + SHIFT_TEMPS + UNDIFFERENCE_2D(PREDICTOR7); + (void)cinfo;(void)comp_index;(void)diff_buf;(void)prev_row;(void)undiff_buf;(void)width; +} + + +/* + * Undifferencer for the first row in a scan or restart interval. The first + * sample in the row is undifferenced using the special predictor constant + * x=2^(P-Pt-1). The rest of the samples are undifferenced using the + * 1-D horizontal predictor (1). + */ + +METHODDEF(void) +jpeg_undifference_first_row(j_decompress_ptr cinfo, int comp_index, + JDIFFROW diff_buf, JDIFFROW prev_row, + JDIFFROW undiff_buf, JDIMENSION width) +{ + j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; + + UNDIFFERENCE_1D(INITIAL_PREDICTORx); + (void)prev_row; + + /* + * Now that we have undifferenced the first row, we want to use the + * undifferencer which corresponds to the predictor specified in the + * scan header. + */ + switch (cinfo->Ss) { + case 1: + losslsd->predict_undifference[comp_index] = jpeg_undifference1; + break; + case 2: + losslsd->predict_undifference[comp_index] = jpeg_undifference2; + break; + case 3: + losslsd->predict_undifference[comp_index] = jpeg_undifference3; + break; + case 4: + losslsd->predict_undifference[comp_index] = jpeg_undifference4; + break; + case 5: + losslsd->predict_undifference[comp_index] = jpeg_undifference5; + break; + case 6: + losslsd->predict_undifference[comp_index] = jpeg_undifference6; + break; + case 7: + losslsd->predict_undifference[comp_index] = jpeg_undifference7; + break; + } +} + + +/* + * Initialize for an input processing pass. + */ + +METHODDEF(void) +predict_start_pass (j_decompress_ptr cinfo) +{ + j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; + int ci; + + /* Check that the scan parameters Ss, Se, Ah, Al are OK for lossless JPEG. + * + * Ss is the predictor selection value (psv). Legal values for sequential + * lossless JPEG are: 1 <= psv <= 7. + * + * Se and Ah are not used and should be zero. + * + * Al specifies the point transform (Pt). Legal values are: 0 <= Pt <= 15. + */ + if (cinfo->Ss < 1 || cinfo->Ss > 7 || + cinfo->Se != 0 || cinfo->Ah != 0 || + cinfo->Al > 15) /* need not check for < 0 */ + ERREXIT4(cinfo, JERR_BAD_LOSSLESS, + cinfo->Ss, cinfo->Se, cinfo->Ah, cinfo->Al); + + /* Set undifference functions to first row function */ + for (ci = 0; ci < cinfo->num_components; ci++) + losslsd->predict_undifference[ci] = jpeg_undifference_first_row; +} + + +/* + * Module initialization routine for the undifferencer. + */ + +GLOBAL(void) +jinit_undifferencer (j_decompress_ptr cinfo) +{ + j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; + + losslsd->predict_start_pass = predict_start_pass; + losslsd->predict_process_restart = predict_start_pass; +} + +#endif /* D_LOSSLESS_SUPPORTED */ diff --git a/gdcm/Utilities/gdcmjpeg/jdsample.c b/gdcm/Utilities/gdcmjpeg/jdsample.c new file mode 100644 index 0000000..f586d57 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jdsample.c @@ -0,0 +1,483 @@ +/* + * jdsample.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains upsampling routines. + * + * Upsampling input data is counted in "row groups". A row group + * is defined to be (v_samp_factor * codec_data_unit / min_codec_data_unit) + * sample rows of each component. Upsampling will normally produce + * max_v_samp_factor pixel rows from each row group (but this could vary + * if the upsampler is applying a scale factor of its own). + * + * An excellent reference for image resampling is + * Digital Image Warping, George Wolberg, 1990. + * Pub. by IEEE Computer Society Press, Los Alamitos, CA. ISBN 0-8186-8944-7. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Pointer to routine to upsample a single component */ +typedef JMETHOD(void, upsample1_ptr, + (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)); + +/* Private subobject */ + +typedef struct { + struct jpeg_upsampler pub; /* public fields */ + + /* Color conversion buffer. When using separate upsampling and color + * conversion steps, this buffer holds one upsampled row group until it + * has been color converted and output. + * Note: we do not allocate any storage for component(s) which are full-size, + * ie do not need rescaling. The corresponding entry of color_buf[] is + * simply set to point to the input data array, thereby avoiding copying. + */ + JSAMPARRAY color_buf[MAX_COMPONENTS]; + + /* Per-component upsampling method pointers */ + upsample1_ptr methods[MAX_COMPONENTS]; + + int next_row_out; /* counts rows emitted from color_buf */ + JDIMENSION rows_to_go; /* counts rows remaining in image */ + + /* Height of an input row group for each component. */ + int rowgroup_height[MAX_COMPONENTS]; + + /* These arrays save pixel expansion factors so that int_expand need not + * recompute them each time. They are unused for other upsampling methods. + */ + UINT8 h_expand[MAX_COMPONENTS]; + UINT8 v_expand[MAX_COMPONENTS]; +} my_upsampler; + +typedef my_upsampler * my_upsample_ptr; + + +/* + * Initialize for an upsampling pass. + */ + +METHODDEF(void) +start_pass_upsample (j_decompress_ptr cinfo) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + + /* Mark the conversion buffer empty */ + upsample->next_row_out = cinfo->max_v_samp_factor; + /* Initialize total-height counter for detecting bottom of image */ + upsample->rows_to_go = cinfo->output_height; +} + + +/* + * Control routine to do upsampling (and color conversion). + * + * In this version we upsample each component independently. + * We upsample one row group into the conversion buffer, then apply + * color conversion a row at a time. + */ + +METHODDEF(void) +sep_upsample (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + int ci; + jpeg_component_info * compptr; + JDIMENSION num_rows; + (void)in_row_groups_avail; + + /* Fill the conversion buffer, if it's empty */ + if (upsample->next_row_out >= cinfo->max_v_samp_factor) { + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Invoke per-component upsample method. Notice we pass a POINTER + * to color_buf[ci], so that fullsize_upsample can change it. + */ + (*upsample->methods[ci]) (cinfo, compptr, + input_buf[ci] + (*in_row_group_ctr * upsample->rowgroup_height[ci]), + upsample->color_buf + ci); + } + upsample->next_row_out = 0; + } + + /* Color-convert and emit rows */ + + /* How many we have in the buffer: */ + num_rows = (JDIMENSION) (cinfo->max_v_samp_factor - upsample->next_row_out); + /* Not more than the distance to the end of the image. Need this test + * in case the image height is not a multiple of max_v_samp_factor: + */ + if (num_rows > upsample->rows_to_go) + num_rows = upsample->rows_to_go; + /* And not more than what the client can accept: */ + out_rows_avail -= *out_row_ctr; + if (num_rows > out_rows_avail) + num_rows = out_rows_avail; + + (*cinfo->cconvert->color_convert) (cinfo, upsample->color_buf, + (JDIMENSION) upsample->next_row_out, + output_buf + *out_row_ctr, + (int) num_rows); + + /* Adjust counts */ + *out_row_ctr += num_rows; + upsample->rows_to_go -= num_rows; + upsample->next_row_out += num_rows; + /* When the buffer is emptied, declare this input row group consumed */ + if (upsample->next_row_out >= cinfo->max_v_samp_factor) + (*in_row_group_ctr)++; +} + + +/* + * These are the routines invoked by sep_upsample to upsample pixel values + * of a single component. One row group is processed per call. + */ + + +/* + * For full-size components, we just make color_buf[ci] point at the + * input buffer, and thus avoid copying any data. Note that this is + * safe only because sep_upsample doesn't declare the input row group + * "consumed" until we are done color converting and emitting it. + */ + +METHODDEF(void) +fullsize_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) +{ + (void)cinfo;(void)compptr; + *output_data_ptr = input_data; +} + + +/* + * This is a no-op version used for "uninteresting" components. + * These components will not be referenced by color conversion. + */ + +METHODDEF(void) +noop_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) +{ + (void)cinfo;(void)compptr;(void)input_data; + *output_data_ptr = NULL; /* safety check */ +} + + +/* + * This version handles any integral sampling ratios. + * This is not used for typical JPEG files, so it need not be fast. + * Nor, for that matter, is it particularly accurate: the algorithm is + * simple replication of the input pixel onto the corresponding output + * pixels. The hi-falutin sampling literature refers to this as a + * "box filter". A box filter tends to introduce visible artifacts, + * so if you are actually going to use 3:1 or 4:1 sampling ratios + * you would be well advised to improve this code. + */ + +METHODDEF(void) +int_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + JSAMPARRAY output_data = *output_data_ptr; + register JSAMPROW inptr, outptr; + register JSAMPLE invalue; + register int h; + JSAMPROW outend; + int h_expand, v_expand; + int inrow, outrow; + + h_expand = upsample->h_expand[compptr->component_index]; + v_expand = upsample->v_expand[compptr->component_index]; + + inrow = outrow = 0; + while (outrow < cinfo->max_v_samp_factor) { + /* Generate one output row with proper horizontal expansion */ + inptr = input_data[inrow]; + outptr = output_data[outrow]; + outend = outptr + cinfo->output_width; + while (outptr < outend) { + invalue = *inptr++; /* don't need GETJSAMPLE() here */ + for (h = h_expand; h > 0; h--) { + *outptr++ = invalue; + } + } + /* Generate any additional output rows by duplicating the first one */ + if (v_expand > 1) { + jcopy_sample_rows(output_data, outrow, output_data, outrow+1, + v_expand-1, cinfo->output_width); + } + inrow++; + outrow += v_expand; + } +} + + +/* + * Fast processing for the common case of 2:1 horizontal and 1:1 vertical. + * It's still a box filter. + */ + +METHODDEF(void) +h2v1_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) +{ + JSAMPARRAY output_data = *output_data_ptr; + register JSAMPROW inptr, outptr; + register JSAMPLE invalue; + JSAMPROW outend; + int inrow; + (void)compptr; + + for (inrow = 0; inrow < cinfo->max_v_samp_factor; inrow++) { + inptr = input_data[inrow]; + outptr = output_data[inrow]; + outend = outptr + cinfo->output_width; + while (outptr < outend) { + invalue = *inptr++; /* don't need GETJSAMPLE() here */ + *outptr++ = invalue; + *outptr++ = invalue; + } + } +} + + +/* + * Fast processing for the common case of 2:1 horizontal and 2:1 vertical. + * It's still a box filter. + */ + +METHODDEF(void) +h2v2_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) +{ + JSAMPARRAY output_data = *output_data_ptr; + register JSAMPROW inptr, outptr; + register JSAMPLE invalue; + JSAMPROW outend; + int inrow, outrow; + (void)compptr; + + inrow = outrow = 0; + while (outrow < cinfo->max_v_samp_factor) { + inptr = input_data[inrow]; + outptr = output_data[outrow]; + outend = outptr + cinfo->output_width; + while (outptr < outend) { + invalue = *inptr++; /* don't need GETJSAMPLE() here */ + *outptr++ = invalue; + *outptr++ = invalue; + } + jcopy_sample_rows(output_data, outrow, output_data, outrow+1, + 1, cinfo->output_width); + inrow++; + outrow += 2; + } +} + + +/* + * Fancy processing for the common case of 2:1 horizontal and 1:1 vertical. + * + * The upsampling algorithm is linear interpolation between pixel centers, + * also known as a "triangle filter". This is a good compromise between + * speed and visual quality. The centers of the output pixels are 1/4 and 3/4 + * of the way between input pixel centers. + * + * A note about the "bias" calculations: when rounding fractional values to + * integer, we do not want to always round 0.5 up to the next integer. + * If we did that, we'd introduce a noticeable bias towards larger values. + * Instead, this code is arranged so that 0.5 will be rounded up or down at + * alternate pixel locations (a simple ordered dither pattern). + */ + +METHODDEF(void) +h2v1_fancy_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) +{ + JSAMPARRAY output_data = *output_data_ptr; + register JSAMPROW inptr, outptr; + register int invalue; + register JDIMENSION colctr; + int inrow; + + for (inrow = 0; inrow < cinfo->max_v_samp_factor; inrow++) { + inptr = input_data[inrow]; + outptr = output_data[inrow]; + /* Special case for first column */ + invalue = GETJSAMPLE(*inptr++); + *outptr++ = (JSAMPLE) invalue; + *outptr++ = (JSAMPLE) ((invalue * 3 + GETJSAMPLE(*inptr) + 2) >> 2); + + for (colctr = compptr->downsampled_width - 2; colctr > 0; colctr--) { + /* General case: 3/4 * nearer pixel + 1/4 * further pixel */ + invalue = GETJSAMPLE(*inptr++) * 3; + *outptr++ = (JSAMPLE) ((invalue + GETJSAMPLE(inptr[-2]) + 1) >> 2); + *outptr++ = (JSAMPLE) ((invalue + GETJSAMPLE(*inptr) + 2) >> 2); + } + + /* Special case for last column */ + invalue = GETJSAMPLE(*inptr); + *outptr++ = (JSAMPLE) ((invalue * 3 + GETJSAMPLE(inptr[-1]) + 1) >> 2); + *outptr++ = (JSAMPLE) invalue; + } +} + + +/* + * Fancy processing for the common case of 2:1 horizontal and 2:1 vertical. + * Again a triangle filter; see comments for h2v1 case, above. + * + * It is OK for us to reference the adjacent input rows because we demanded + * context from the main buffer controller (see initialization code). + */ + +METHODDEF(void) +h2v2_fancy_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) +{ + JSAMPARRAY output_data = *output_data_ptr; + register JSAMPROW inptr0, inptr1, outptr; +#if BITS_IN_JSAMPLE == 8 + register int thiscolsum, lastcolsum, nextcolsum; +#else + register INT32 thiscolsum, lastcolsum, nextcolsum; +#endif + register JDIMENSION colctr; + int inrow, outrow, v; + + inrow = outrow = 0; + while (outrow < cinfo->max_v_samp_factor) { + for (v = 0; v < 2; v++) { + /* inptr0 points to nearest input row, inptr1 points to next nearest */ + inptr0 = input_data[inrow]; + if (v == 0) /* next nearest is row above */ + inptr1 = input_data[inrow-1]; + else /* next nearest is row below */ + inptr1 = input_data[inrow+1]; + outptr = output_data[outrow++]; + + /* Special case for first column */ + thiscolsum = GETJSAMPLE(*inptr0++) * 3 + GETJSAMPLE(*inptr1++); + nextcolsum = GETJSAMPLE(*inptr0++) * 3 + GETJSAMPLE(*inptr1++); + *outptr++ = (JSAMPLE) ((thiscolsum * 4 + 8) >> 4); + *outptr++ = (JSAMPLE) ((thiscolsum * 3 + nextcolsum + 7) >> 4); + lastcolsum = thiscolsum; thiscolsum = nextcolsum; + + for (colctr = compptr->downsampled_width - 2; colctr > 0; colctr--) { + /* General case: 3/4 * nearer pixel + 1/4 * further pixel in each */ + /* dimension, thus 9/16, 3/16, 3/16, 1/16 overall */ + nextcolsum = GETJSAMPLE(*inptr0++) * 3 + GETJSAMPLE(*inptr1++); + *outptr++ = (JSAMPLE) ((thiscolsum * 3 + lastcolsum + 8) >> 4); + *outptr++ = (JSAMPLE) ((thiscolsum * 3 + nextcolsum + 7) >> 4); + lastcolsum = thiscolsum; thiscolsum = nextcolsum; + } + + /* Special case for last column */ + *outptr++ = (JSAMPLE) ((thiscolsum * 3 + lastcolsum + 8) >> 4); + *outptr++ = (JSAMPLE) ((thiscolsum * 4 + 7) >> 4); + } + inrow++; + } +} + + +/* + * Module initialization routine for upsampling. + */ + +GLOBAL(void) +jinit_upsampler (j_decompress_ptr cinfo) +{ + my_upsample_ptr upsample; + int ci; + jpeg_component_info * compptr; + boolean need_buffer, do_fancy; + int h_in_group, v_in_group, h_out_group, v_out_group; + + upsample = (my_upsample_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_upsampler)); + cinfo->upsample = (struct jpeg_upsampler *) upsample; + upsample->pub.start_pass = start_pass_upsample; + upsample->pub.upsample = sep_upsample; + upsample->pub.need_context_rows = FALSE; /* until we find out differently */ + + if (cinfo->CCIR601_sampling) /* this isn't supported */ + ERREXIT(cinfo, JERR_CCIR601_NOTIMPL); + + /* jdmainct.c doesn't support context rows when min_codec_data_unit = 1, + * so don't ask for it. + */ + do_fancy = cinfo->do_fancy_upsampling && cinfo->min_codec_data_unit > 1; + + /* Verify we can handle the sampling factors, select per-component methods, + * and create storage as needed. + */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Compute size of an "input group" after IDCT scaling. This many samples + * are to be converted to max_h_samp_factor * max_v_samp_factor pixels. + */ + h_in_group = (compptr->h_samp_factor * compptr->codec_data_unit) / + cinfo->min_codec_data_unit; + v_in_group = (compptr->v_samp_factor * compptr->codec_data_unit) / + cinfo->min_codec_data_unit; + h_out_group = cinfo->max_h_samp_factor; + v_out_group = cinfo->max_v_samp_factor; + upsample->rowgroup_height[ci] = v_in_group; /* save for use later */ + need_buffer = TRUE; + if (! compptr->component_needed) { + /* Don't bother to upsample an uninteresting component. */ + upsample->methods[ci] = noop_upsample; + need_buffer = FALSE; + } else if (h_in_group == h_out_group && v_in_group == v_out_group) { + /* Fullsize components can be processed without any work. */ + upsample->methods[ci] = fullsize_upsample; + need_buffer = FALSE; + } else if (h_in_group * 2 == h_out_group && + v_in_group == v_out_group) { + /* Special cases for 2h1v upsampling */ + if (do_fancy && compptr->downsampled_width > 2) + upsample->methods[ci] = h2v1_fancy_upsample; + else + upsample->methods[ci] = h2v1_upsample; + } else if (h_in_group * 2 == h_out_group && + v_in_group * 2 == v_out_group) { + /* Special cases for 2h2v upsampling */ + if (do_fancy && compptr->downsampled_width > 2) { + upsample->methods[ci] = h2v2_fancy_upsample; + upsample->pub.need_context_rows = TRUE; + } else + upsample->methods[ci] = h2v2_upsample; + } else if ((h_out_group % h_in_group) == 0 && + (v_out_group % v_in_group) == 0) { + /* Generic integral-factors upsampling method */ + upsample->methods[ci] = int_upsample; + upsample->h_expand[ci] = (UINT8) (h_out_group / h_in_group); + upsample->v_expand[ci] = (UINT8) (v_out_group / v_in_group); + } else + ERREXIT(cinfo, JERR_FRACT_SAMPLE_NOTIMPL); + if (need_buffer) { + upsample->color_buf[ci] = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) jround_up((long) cinfo->output_width, + (long) cinfo->max_h_samp_factor), + (JDIMENSION) cinfo->max_v_samp_factor); + } + } +} diff --git a/gdcm/Utilities/gdcmjpeg/jdscale.c b/gdcm/Utilities/gdcmjpeg/jdscale.c new file mode 100644 index 0000000..23390e7 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jdscale.c @@ -0,0 +1,119 @@ +/* + * jdscale.c + * + * Copyright (C) 1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains sample scaling for lossless JPEG. This is a + * combination of upscaling the undifferenced sample by 2^Pt and downscaling + * the sample to fit into JSAMPLE. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jlossls.h" /* Private declarations for lossless codec */ + + +#ifdef D_LOSSLESS_SUPPORTED + +/* + * Private scaler object for lossless decoding. + */ + +typedef struct { + int scale_factor; +} scaler; + +typedef scaler * scaler_ptr; + + +/* + * Scalers for packing sample differences into JSAMPLEs. + */ + +METHODDEF(void) +simple_upscale(j_decompress_ptr cinfo, + JDIFFROW diff_buf, JSAMPROW output_buf, + JDIMENSION width) +{ + j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; + scaler_ptr scaler = (scaler_ptr) losslsd->scaler_private; + int scale_factor = scaler->scale_factor; + unsigned int xindex; + + for (xindex = 0; xindex < width; xindex++) + output_buf[xindex] = (JSAMPLE) (diff_buf[xindex] << scale_factor); +} + +METHODDEF(void) +simple_downscale(j_decompress_ptr cinfo, + JDIFFROW diff_buf, JSAMPROW output_buf, + JDIMENSION width) +{ + j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; + scaler_ptr scaler = (scaler_ptr) losslsd->scaler_private; + int scale_factor = scaler->scale_factor; + unsigned int xindex; + SHIFT_TEMPS + + for (xindex = 0; xindex < width; xindex++) + output_buf[xindex] = (JSAMPLE) RIGHT_SHIFT(diff_buf[xindex], scale_factor); +} + +METHODDEF(void) +noscale(j_decompress_ptr cinfo, + JDIFFROW diff_buf, JSAMPROW output_buf, + JDIMENSION width) +{ + unsigned int xindex; + (void)cinfo; + + for (xindex = 0; xindex < width; xindex++) + output_buf[xindex] = (JSAMPLE) diff_buf[xindex]; +} + + +METHODDEF(void) +scaler_start_pass (j_decompress_ptr cinfo) +{ + j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; + scaler_ptr scaler = (scaler_ptr) losslsd->scaler_private; + int downscale; + + /* + * Downscale by the difference in the input vs. output precision. If the + * output precision >= input precision, then do not downscale. + */ + downscale = BITS_IN_JSAMPLE < cinfo->data_precision ? + cinfo->data_precision - BITS_IN_JSAMPLE : 0; + + scaler->scale_factor = cinfo->Al - downscale; + + /* Set scaler functions based on scale_factor (positive = left shift) */ + if (scaler->scale_factor > 0) + losslsd->scaler_scale = simple_upscale; + else if (scaler->scale_factor < 0) { + scaler->scale_factor = -scaler->scale_factor; + losslsd->scaler_scale = simple_downscale; + } + else + losslsd->scaler_scale = noscale; +} + + +GLOBAL(void) +jinit_d_scaler (j_decompress_ptr cinfo) +{ + j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; + scaler_ptr scaler; + + scaler = (scaler_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(scaler)); + losslsd->scaler_private = (void *) scaler; + losslsd->scaler_start_pass = scaler_start_pass; +} + +#endif /* D_LOSSLESS_SUPPORTED */ diff --git a/gdcm/Utilities/gdcmjpeg/jdshuff.c b/gdcm/Utilities/gdcmjpeg/jdshuff.c new file mode 100644 index 0000000..66736a2 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jdshuff.c @@ -0,0 +1,360 @@ +/* + * jdshuff.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains Huffman entropy decoding routines for sequential JPEG. + * + * Much of the complexity here has to do with supporting input suspension. + * If the data source module demands suspension, we want to be able to back + * up to the start of the current MCU. To do this, we copy state variables + * into local working storage, and update them back to the permanent + * storage only upon successful completion of an MCU. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jlossy.h" /* Private declarations for lossy codec */ +#include "jdhuff.h" /* Declarations shared with jd*huff.c */ + + +/* + * Private entropy decoder object for Huffman decoding. + * + * The savable_state subrecord contains fields that change within an MCU, + * but must not be updated permanently until we complete the MCU. + */ + +typedef struct { + int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */ +} savable_state; + +/* This macro is to work around compilers with missing or broken + * structure assignment. You'll need to fix this code if you have + * such a compiler and you change MAX_COMPS_IN_SCAN. + */ + +#ifndef NO_STRUCT_ASSIGN +#define ASSIGN_STATE(dest,src) ((dest) = (src)) +#else +#if MAX_COMPS_IN_SCAN == 4 +#define ASSIGN_STATE(dest,src) \ + ((dest).last_dc_val[0] = (src).last_dc_val[0], \ + (dest).last_dc_val[1] = (src).last_dc_val[1], \ + (dest).last_dc_val[2] = (src).last_dc_val[2], \ + (dest).last_dc_val[3] = (src).last_dc_val[3]) +#endif +#endif + + +typedef struct { + huffd_common_fields; /* Fields shared with other entropy decoders */ + + /* These fields are loaded into local variables at start of each MCU. + * In case of suspension, we exit WITHOUT updating them. + */ + savable_state saved; /* Other state at start of MCU */ + + /* These fields are NOT loaded into local working state. */ + unsigned int restarts_to_go; /* MCUs left in this restart interval */ + + /* Pointers to derived tables (these workspaces have image lifespan) */ + d_derived_tbl * dc_derived_tbls[NUM_HUFF_TBLS]; + d_derived_tbl * ac_derived_tbls[NUM_HUFF_TBLS]; + + /* Precalculated info set up by start_pass for use in decode_mcu: */ + + /* Pointers to derived tables to be used for each block within an MCU */ + d_derived_tbl * dc_cur_tbls[D_MAX_DATA_UNITS_IN_MCU]; + d_derived_tbl * ac_cur_tbls[D_MAX_DATA_UNITS_IN_MCU]; + /* Whether we care about the DC and AC coefficient values for each block */ + boolean dc_needed[D_MAX_DATA_UNITS_IN_MCU]; + boolean ac_needed[D_MAX_DATA_UNITS_IN_MCU]; +} shuff_entropy_decoder; + +typedef shuff_entropy_decoder * shuff_entropy_ptr; + + +/* + * Initialize for a Huffman-compressed scan. + */ + +METHODDEF(void) +start_pass_huff_decoder (j_decompress_ptr cinfo) +{ + j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; + shuff_entropy_ptr entropy = (shuff_entropy_ptr) lossyd->entropy_private; + int ci, blkn, dctbl, actbl; + jpeg_component_info * compptr; + + /* Check that the scan parameters Ss, Se, Ah/Al are OK for sequential JPEG. + * This ought to be an error condition, but we make it a warning because + * there are some baseline files out there with all zeroes in these bytes. + */ + if (cinfo->Ss != 0 || cinfo->Se != DCTSIZE2-1 || + cinfo->Ah != 0 || cinfo->Al != 0) + WARNMS(cinfo, JWRN_NOT_SEQUENTIAL); + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + dctbl = compptr->dc_tbl_no; + actbl = compptr->ac_tbl_no; + /* Compute derived values for Huffman tables */ + /* We may do this more than once for a table, but it's not expensive */ + jpeg_make_d_derived_tbl(cinfo, TRUE, dctbl, + & entropy->dc_derived_tbls[dctbl]); + jpeg_make_d_derived_tbl(cinfo, FALSE, actbl, + & entropy->ac_derived_tbls[actbl]); + /* Initialize DC predictions to 0 */ + entropy->saved.last_dc_val[ci] = 0; + } + + /* Precalculate decoding info for each block in an MCU of this scan */ + for (blkn = 0; blkn < cinfo->data_units_in_MCU; blkn++) { + ci = cinfo->MCU_membership[blkn]; + compptr = cinfo->cur_comp_info[ci]; + /* Precalculate which table to use for each block */ + entropy->dc_cur_tbls[blkn] = entropy->dc_derived_tbls[compptr->dc_tbl_no]; + entropy->ac_cur_tbls[blkn] = entropy->ac_derived_tbls[compptr->ac_tbl_no]; + /* Decide whether we really care about the coefficient values */ + if (compptr->component_needed) { + entropy->dc_needed[blkn] = TRUE; + /* we don't need the ACs if producing a 1/8th-size image */ + entropy->ac_needed[blkn] = (compptr->codec_data_unit > 1); + } else { + entropy->dc_needed[blkn] = entropy->ac_needed[blkn] = FALSE; + } + } + + /* Initialize bitread state variables */ + entropy->bitstate.bits_left = 0; + entropy->bitstate.get_buffer = 0; /* unnecessary, but keeps Purify quiet */ + entropy->insufficient_data = FALSE; + + /* Initialize restart counter */ + entropy->restarts_to_go = cinfo->restart_interval; +} + + +/* + * Figure F.12: extend sign bit. + * On some machines, a shift and add will be faster than a table lookup. + */ + +#ifdef AVOID_TABLES + +#define HUFF_EXTEND(x,s) ((x) < (1<<((s)-1)) ? (x) + (((-1)<<(s)) + 1) : (x)) + +#else + +#define HUFF_EXTEND(x,s) ((x) < extend_test[s] ? (x) + extend_offset[s] : (x)) + +static const int extend_test[16] = /* entry n is 2**(n-1) */ + { 0, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, + 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000 }; + +static const int extend_offset[16] = /* entry n is (-1 << n) + 1 */ + { 0, ((-1)<<1) + 1, ((-1)<<2) + 1, ((-1)<<3) + 1, ((-1)<<4) + 1, + ((-1)<<5) + 1, ((-1)<<6) + 1, ((-1)<<7) + 1, ((-1)<<8) + 1, + ((-1)<<9) + 1, ((-1)<<10) + 1, ((-1)<<11) + 1, ((-1)<<12) + 1, + ((-1)<<13) + 1, ((-1)<<14) + 1, ((-1)<<15) + 1 }; + +#endif /* AVOID_TABLES */ + + +/* + * Check for a restart marker & resynchronize decoder. + * Returns FALSE if must suspend. + */ + +LOCAL(boolean) +process_restart (j_decompress_ptr cinfo) +{ + j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; + shuff_entropy_ptr entropy = (shuff_entropy_ptr) lossyd->entropy_private; + int ci; + + /* Throw away any unused bits remaining in bit buffer; */ + /* include any full bytes in next_marker's count of discarded bytes */ + cinfo->marker->discarded_bytes += entropy->bitstate.bits_left / 8; + entropy->bitstate.bits_left = 0; + + /* Advance past the RSTn marker */ + if (! (*cinfo->marker->read_restart_marker) (cinfo)) + return FALSE; + + /* Re-initialize DC predictions to 0 */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) + entropy->saved.last_dc_val[ci] = 0; + + /* Reset restart counter */ + entropy->restarts_to_go = cinfo->restart_interval; + + /* Reset out-of-data flag, unless read_restart_marker left us smack up + * against a marker. In that case we will end up treating the next data + * segment as empty, and we can avoid producing bogus output pixels by + * leaving the flag set. + */ + if (cinfo->unread_marker == 0) + entropy->insufficient_data = FALSE; + + return TRUE; +} + + +/* + * Decode and return one MCU's worth of Huffman-compressed coefficients. + * The coefficients are reordered from zigzag order into natural array order, + * but are not dequantized. + * + * The i'th block of the MCU is stored into the block pointed to by + * MCU_data[i]. WE ASSUME THIS AREA HAS BEEN ZEROED BY THE CALLER. + * (Wholesale zeroing is usually a little faster than retail...) + * + * Returns FALSE if data source requested suspension. In that case no + * changes have been made to permanent state. (Exception: some output + * coefficients may already have been assigned. This is harmless for + * this module, since we'll just re-assign them on the next call.) + */ + +METHODDEF(boolean) +decode_mcu (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) +{ + j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; + shuff_entropy_ptr entropy = (shuff_entropy_ptr) lossyd->entropy_private; + int blkn; + BITREAD_STATE_VARS; + savable_state state; + + /* Process restart marker if needed; may have to suspend */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + if (! process_restart(cinfo)) + return FALSE; + } + + /* If we've run out of data, just leave the MCU set to zeroes. + * This way, we return uniform gray for the remainder of the segment. + */ + if (! entropy->insufficient_data) { + + /* Load up working state */ + BITREAD_LOAD_STATE(cinfo,entropy->bitstate); + ASSIGN_STATE(state, entropy->saved); + + /* Outer loop handles each block in the MCU */ + + for (blkn = 0; blkn < cinfo->data_units_in_MCU; blkn++) { + JBLOCKROW block = MCU_data[blkn]; + d_derived_tbl * dctbl = entropy->dc_cur_tbls[blkn]; + d_derived_tbl * actbl = entropy->ac_cur_tbls[blkn]; + register int s, k, r; + + /* Decode a single block's worth of coefficients */ + + /* Section F.2.2.1: decode the DC coefficient difference */ + HUFF_DECODE(s, br_state, dctbl, return FALSE, label1); + if (s) { + CHECK_BIT_BUFFER(br_state, s, return FALSE); + r = GET_BITS(s); + s = HUFF_EXTEND(r, s); + } + + if (entropy->dc_needed[blkn]) { + /* Convert DC difference to actual value, update last_dc_val */ + int ci = cinfo->MCU_membership[blkn]; + s += state.last_dc_val[ci]; + state.last_dc_val[ci] = s; + /* Output the DC coefficient (assumes jpeg_natural_order[0] = 0) */ + (*block)[0] = (JCOEF) s; + } + + if (entropy->ac_needed[blkn]) { + + /* Section F.2.2.2: decode the AC coefficients */ + /* Since zeroes are skipped, output area must be cleared beforehand */ + for (k = 1; k < DCTSIZE2; k++) { + HUFF_DECODE(s, br_state, actbl, return FALSE, label2); + + r = s >> 4; + s &= 15; + + if (s) { + k += r; + CHECK_BIT_BUFFER(br_state, s, return FALSE); + r = GET_BITS(s); + s = HUFF_EXTEND(r, s); + /* Output coefficient in natural (dezigzagged) order. + * Note: the extra entries in jpeg_natural_order[] will save us + * if k >= DCTSIZE2, which could happen if the data is corrupted. + */ + (*block)[jpeg_natural_order[k]] = (JCOEF) s; + } else { + if (r != 15) + break; + k += 15; + } + } + + } else { + + /* Section F.2.2.2: decode the AC coefficients */ + /* In this path we just discard the values */ + for (k = 1; k < DCTSIZE2; k++) { + HUFF_DECODE(s, br_state, actbl, return FALSE, label3); + + r = s >> 4; + s &= 15; + + if (s) { + k += r; + CHECK_BIT_BUFFER(br_state, s, return FALSE); + DROP_BITS(s); + } else { + if (r != 15) + break; + k += 15; + } + } + + } + } + + /* Completed MCU, so update state */ + BITREAD_SAVE_STATE(cinfo,entropy->bitstate); + ASSIGN_STATE(entropy->saved, state); + } + + /* Account for restart interval (no-op if not using restarts) */ + entropy->restarts_to_go--; + + return TRUE; +} + + +/* + * Module initialization routine for Huffman entropy decoding. + */ + +GLOBAL(void) +jinit_shuff_decoder (j_decompress_ptr cinfo) +{ + j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; + shuff_entropy_ptr entropy; + int i; + + entropy = (shuff_entropy_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(shuff_entropy_decoder)); + lossyd->entropy_private = (void *) entropy; + lossyd->entropy_start_pass = start_pass_huff_decoder; + lossyd->entropy_decode_mcu = decode_mcu; + + /* Mark tables unallocated */ + for (i = 0; i < NUM_HUFF_TBLS; i++) { + entropy->dc_derived_tbls[i] = entropy->ac_derived_tbls[i] = NULL; + } +} diff --git a/gdcm/Utilities/gdcmjpeg/jdtrans.c b/gdcm/Utilities/gdcmjpeg/jdtrans.c new file mode 100644 index 0000000..af35263 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jdtrans.c @@ -0,0 +1,138 @@ +/* + * jdtrans.c + * + * Copyright (C) 1995-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains library routines for transcoding decompression, + * that is, reading raw DCT coefficient arrays from an input JPEG file. + * The routines in jdapimin.c will also be needed by a transcoder. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jlossy.h" + + +/* Forward declarations */ +LOCAL(void) transdecode_master_selection JPP((j_decompress_ptr cinfo)); + + +/* + * Read the coefficient arrays from a JPEG file. + * jpeg_read_header must be completed before calling this. + * + * The entire image is read into a set of virtual coefficient-block arrays, + * one per component. The return value is a pointer to the array of + * virtual-array descriptors. These can be manipulated directly via the + * JPEG memory manager, or handed off to jpeg_write_coefficients(). + * To release the memory occupied by the virtual arrays, call + * jpeg_finish_decompress() when done with the data. + * + * An alternative usage is to simply obtain access to the coefficient arrays + * during a buffered-image-mode decompression operation. This is allowed + * after any jpeg_finish_output() call. The arrays can be accessed until + * jpeg_finish_decompress() is called. (Note that any call to the library + * may reposition the arrays, so don't rely on access_virt_barray() results + * to stay valid across library calls.) + * + * Returns NULL if suspended. This case need be checked only if + * a suspending data source is used. + */ + +GLOBAL(jvirt_barray_ptr *) +jpeg_read_coefficients (j_decompress_ptr cinfo) +{ + /* j_lossy_d_ptr decomp; */ + + /* Can't read coefficients from lossless streams */ + if (cinfo->process == JPROC_LOSSLESS) { + ERREXIT(cinfo, JERR_CANT_TRANSCODE); + return NULL; + } + + if (cinfo->global_state == DSTATE_READY) { + /* First call: initialize active modules */ + transdecode_master_selection(cinfo); + cinfo->global_state = DSTATE_RDCOEFS; + } + if (cinfo->global_state == DSTATE_RDCOEFS) { + /* Absorb whole file into the coef buffer */ + for (;;) { + int retcode; + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + /* Absorb some more input */ + retcode = (*cinfo->inputctl->consume_input) (cinfo); + if (retcode == JPEG_SUSPENDED) + return NULL; + if (retcode == JPEG_REACHED_EOI) + break; + /* Advance progress counter if appropriate */ + if (cinfo->progress != NULL && + (retcode == JPEG_ROW_COMPLETED || retcode == JPEG_REACHED_SOS)) { + if (++cinfo->progress->pass_counter >= cinfo->progress->pass_limit) { + /* startup underestimated number of scans; ratchet up one scan */ + cinfo->progress->pass_limit += (long) cinfo->total_iMCU_rows; + } + } + } + /* Set state so that jpeg_finish_decompress does the right thing */ + cinfo->global_state = DSTATE_STOPPING; + } + /* At this point we should be in state DSTATE_STOPPING if being used + * standalone, or in state DSTATE_BUFIMAGE if being invoked to get access + * to the coefficients during a full buffered-image-mode decompression. + */ + if ((cinfo->global_state == DSTATE_STOPPING || + cinfo->global_state == DSTATE_BUFIMAGE) && cinfo->buffered_image) { + return ((j_lossy_d_ptr) cinfo->codec)->coef_arrays; + } + /* Oops, improper usage */ + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + return NULL; /* keep compiler happy */ +} + + +/* + * Master selection of decompression modules for transcoding. + * This substitutes for jdmaster.c's initialization of the full decompressor. + */ + +LOCAL(void) +transdecode_master_selection (j_decompress_ptr cinfo) +{ + /* This is effectively a buffered-image operation. */ + cinfo->buffered_image = TRUE; + + /* Initialize decompression codec */ + jinit_d_codec(cinfo); + + /* We can now tell the memory manager to allocate virtual arrays. */ + (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo); + + /* Initialize input side of decompressor to consume first scan. */ + (*cinfo->inputctl->start_input_pass) (cinfo); + + /* Initialize progress monitoring. */ + if (cinfo->progress != NULL) { + int nscans; + /* Estimate number of scans to set pass_limit. */ + if (cinfo->process == JPROC_PROGRESSIVE) { + /* Arbitrarily estimate 2 interleaved DC scans + 3 AC scans/component. */ + nscans = 2 + 3 * cinfo->num_components; + } else if (cinfo->inputctl->has_multiple_scans) { + /* For a nonprogressive multiscan file, estimate 1 scan per component. */ + nscans = cinfo->num_components; + } else { + nscans = 1; + } + cinfo->progress->pass_counter = 0L; + cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows * nscans; + cinfo->progress->completed_passes = 0; + cinfo->progress->total_passes = 1; + } +} diff --git a/gdcm/Utilities/gdcmjpeg/jerror.c b/gdcm/Utilities/gdcmjpeg/jerror.c new file mode 100644 index 0000000..4e6e2e3 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jerror.c @@ -0,0 +1,252 @@ +/* + * jerror.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains simple error-reporting and trace-message routines. + * These are suitable for Unix-like systems and others where writing to + * stderr is the right thing to do. Many applications will want to replace + * some or all of these routines. + * + * If you define USE_WINDOWS_MESSAGEBOX in jconfig.h or in the makefile, + * you get a Windows-specific hack to display error messages in a dialog box. + * It ain't much, but it beats dropping error messages into the bit bucket, + * which is what happens to output to stderr under most Windows C compilers. + * + * These routines are used by both the compression and decompression code. + */ + +/* this is not a core library module, so it doesn't define JPEG_INTERNALS */ +#include "jinclude.h" +#include "jpeglib.h" +#include "jversion.h" +#include "jerror.h" + +#ifdef USE_WINDOWS_MESSAGEBOX +#include +#endif + +#ifndef EXIT_FAILURE /* define exit() codes if not provided */ +#define EXIT_FAILURE 1 +#endif + + +/* + * Create the message string table. + * We do this from the master message list in jerror.h by re-reading + * jerror.h with a suitable definition for macro JMESSAGE. + * The message table is made an external symbol just in case any applications + * want to refer to it directly. + */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_std_message_table jMsgTable +#endif + +#define JMESSAGE(code,string) string , + +const char * const jpeg_std_message_table[] = { +#include "jerror.h" + NULL +}; + + +/* + * Error exit handler: must not return to caller. + * + * Applications may override this if they want to get control back after + * an error. Typically one would longjmp somewhere instead of exiting. + * The setjmp buffer can be made a private field within an expanded error + * handler object. Note that the info needed to generate an error message + * is stored in the error object, so you can generate the message now or + * later, at your convenience. + * You should make sure that the JPEG object is cleaned up (with jpeg_abort + * or jpeg_destroy) at some point. + */ + +METHODDEF(void) +error_exit (j_common_ptr cinfo) +{ + /* Always display the message */ + (*cinfo->err->output_message) (cinfo); + + /* Let the memory manager delete any temp files before we die */ + jpeg_destroy(cinfo); + + exit(EXIT_FAILURE); +} + + +/* + * Actual output of an error or trace message. + * Applications may override this method to send JPEG messages somewhere + * other than stderr. + * + * On Windows, printing to stderr is generally completely useless, + * so we provide optional code to produce an error-dialog popup. + * Most Windows applications will still prefer to override this routine, + * but if they don't, it'll do something at least marginally useful. + * + * NOTE: to use the library in an environment that doesn't support the + * C stdio library, you may have to delete the call to fprintf() entirely, + * not just not use this routine. + */ + +METHODDEF(void) +output_message (j_common_ptr cinfo) +{ + char buffer[JMSG_LENGTH_MAX]; + + /* Create the message */ + (*cinfo->err->format_message) (cinfo, buffer); + +#ifdef USE_WINDOWS_MESSAGEBOX + /* Display it in a message dialog box */ + MessageBox(GetActiveWindow(), buffer, "JPEG Library Error", + MB_OK | MB_ICONERROR); +#else + /* Send it to stderr, adding a newline */ + fprintf(stderr, "%s\n", buffer); +#endif +} + + +/* + * Decide whether to emit a trace or warning message. + * msg_level is one of: + * -1: recoverable corrupt-data warning, may want to abort. + * 0: important advisory messages (always display to user). + * 1: first level of tracing detail. + * 2,3,...: successively more detailed tracing messages. + * An application might override this method if it wanted to abort on warnings + * or change the policy about which messages to display. + */ + +METHODDEF(void) +emit_message (j_common_ptr cinfo, int msg_level) +{ + struct jpeg_error_mgr * err = cinfo->err; + + if (msg_level < 0) { + /* It's a warning message. Since corrupt files may generate many warnings, + * the policy implemented here is to show only the first warning, + * unless trace_level >= 3. + */ + if (err->num_warnings == 0 || err->trace_level >= 3) + (*err->output_message) (cinfo); + /* Always count warnings in num_warnings. */ + err->num_warnings++; + } else { + /* It's a trace message. Show it if trace_level >= msg_level. */ + if (err->trace_level >= msg_level) + (*err->output_message) (cinfo); + } +} + + +/* + * Format a message string for the most recent JPEG error or message. + * The message is stored into buffer, which should be at least JMSG_LENGTH_MAX + * characters. Note that no '\n' character is added to the string. + * Few applications should need to override this method. + */ + +METHODDEF(void) +format_message (j_common_ptr cinfo, char * buffer) +{ + struct jpeg_error_mgr * err = cinfo->err; + int msg_code = err->msg_code; + const char * msgtext = NULL; + const char * msgptr; + char ch; + boolean isstring; + + /* Look up message string in proper table */ + if (msg_code > 0 && msg_code <= err->last_jpeg_message) { + msgtext = err->jpeg_message_table[msg_code]; + } else if (err->addon_message_table != NULL && + msg_code >= err->first_addon_message && + msg_code <= err->last_addon_message) { + msgtext = err->addon_message_table[msg_code - err->first_addon_message]; + } + + /* Defend against bogus message number */ + if (msgtext == NULL) { + err->msg_parm.i[0] = msg_code; + msgtext = err->jpeg_message_table[0]; + } + + /* Check for string parameter, as indicated by %s in the message text */ + isstring = FALSE; + msgptr = msgtext; + while ((ch = *msgptr++) != '\0') { + if (ch == '%') { + if (*msgptr == 's') isstring = TRUE; + break; + } + } + + /* Format the message into the passed buffer */ + if (isstring) + sprintf(buffer, msgtext, err->msg_parm.s); + else + sprintf(buffer, msgtext, + err->msg_parm.i[0], err->msg_parm.i[1], + err->msg_parm.i[2], err->msg_parm.i[3], + err->msg_parm.i[4], err->msg_parm.i[5], + err->msg_parm.i[6], err->msg_parm.i[7]); +} + + +/* + * Reset error state variables at start of a new image. + * This is called during compression startup to reset trace/error + * processing to default state, without losing any application-specific + * method pointers. An application might possibly want to override + * this method if it has additional error processing state. + */ + +METHODDEF(void) +reset_error_mgr (j_common_ptr cinfo) +{ + cinfo->err->num_warnings = 0; + /* trace_level is not reset since it is an application-supplied parameter */ + cinfo->err->msg_code = 0; /* may be useful as a flag for "no error" */ +} + + +/* + * Fill in the standard error-handling methods in a jpeg_error_mgr object. + * Typical call is: + * struct jpeg_compress_struct cinfo; + * struct jpeg_error_mgr err; + * + * cinfo.err = jpeg_std_error(&err); + * after which the application may override some of the methods. + */ + +GLOBAL(struct jpeg_error_mgr *) +jpeg_std_error (struct jpeg_error_mgr * err) +{ + err->error_exit = error_exit; + err->emit_message = emit_message; + err->output_message = output_message; + err->format_message = format_message; + err->reset_error_mgr = reset_error_mgr; + + err->trace_level = 0; /* default = no tracing */ + err->num_warnings = 0; /* no warnings emitted yet */ + err->msg_code = 0; /* may be useful as a flag for "no error" */ + + /* Initialize message table pointers */ + err->jpeg_message_table = jpeg_std_message_table; + err->last_jpeg_message = (int) JMSG_LASTMSGCODE - 1; + + err->addon_message_table = NULL; + err->first_addon_message = 0; /* for safety */ + err->last_addon_message = 0; + + return err; +} diff --git a/gdcm/Utilities/gdcmjpeg/jerror.h b/gdcm/Utilities/gdcmjpeg/jerror.h new file mode 100644 index 0000000..fa9ab36 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jerror.h @@ -0,0 +1,307 @@ +/* + * jerror.h + * + * Copyright (C) 1994-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file defines the error and message codes for the JPEG library. + * Edit this file to add new codes, or to translate the message strings to + * some other language. + * A set of error-reporting macros are defined too. Some applications using + * the JPEG library may wish to include this file to get the error codes + * and/or the macros. + */ + +/* + * To define the enum list of message codes, include this file without + * defining macro JMESSAGE. To create a message string table, include it + * again with a suitable JMESSAGE definition (see jerror.c for an example). + */ +#ifndef JMESSAGE +#ifndef JERROR_H +/* First time through, define the enum list */ +#define JMAKE_ENUM_LIST +#else +/* Repeated inclusions of this file are no-ops unless JMESSAGE is defined */ +#define JMESSAGE(code,string) +#endif /* JERROR_H */ +#endif /* JMESSAGE */ + +#ifdef JMAKE_ENUM_LIST + +typedef enum { + +#define JMESSAGE(code,string) code , + +#endif /* JMAKE_ENUM_LIST */ + +JMESSAGE(JMSG_NOMESSAGE, "Bogus message code %d") /* Must be first entry! */ + +/* For maintenance convenience, list is alphabetical by message code name */ +JMESSAGE(JERR_ARITH_NOTIMPL, + "Sorry, there are legal restrictions on arithmetic coding") +JMESSAGE(JERR_BAD_ALIGN_TYPE, "ALIGN_TYPE is wrong, please fix") +JMESSAGE(JERR_BAD_ALLOC_CHUNK, "MAX_ALLOC_CHUNK is wrong, please fix") +JMESSAGE(JERR_BAD_BUFFER_MODE, "Bogus buffer control mode") +JMESSAGE(JERR_BAD_COMPONENT_ID, "Invalid component ID %d in SOS") +JMESSAGE(JERR_BAD_DCT_COEF, "DCT coefficient out of range") +JMESSAGE(JERR_BAD_DCTSIZE, "IDCT output block size %d not supported") +JMESSAGE(JERR_BAD_DIFF, "spatial difference out of range") +JMESSAGE(JERR_BAD_HUFF_TABLE, "Bogus Huffman table definition") +JMESSAGE(JERR_BAD_IN_COLORSPACE, "Bogus input colorspace") +JMESSAGE(JERR_BAD_J_COLORSPACE, "Bogus JPEG colorspace") +JMESSAGE(JERR_BAD_LENGTH, "Bogus marker length") +JMESSAGE(JERR_BAD_LIB_VERSION, + "Wrong JPEG library version: library is %d, caller expects %d") +JMESSAGE(JERR_BAD_LOSSLESS, + "Invalid lossless parameters Ss=%d Se=%d Ah=%d Al=%d") +JMESSAGE(JERR_BAD_LOSSLESS_SCRIPT, + "Invalid lossless parameters at scan script entry %d") +JMESSAGE(JERR_BAD_MCU_SIZE, "Sampling factors too large for interleaved scan") +JMESSAGE(JERR_BAD_POOL_ID, "Invalid memory pool code %d") +JMESSAGE(JERR_BAD_PRECISION, "Unsupported JPEG data precision %d") +JMESSAGE(JERR_BAD_PROGRESSION, + "Invalid progressive parameters Ss=%d Se=%d Ah=%d Al=%d") +JMESSAGE(JERR_BAD_PROG_SCRIPT, + "Invalid progressive parameters at scan script entry %d") +JMESSAGE(JERR_BAD_RESTART, "Invalid restart interval: %d, must be an integer multiple of the number of MCUs in an MCU_row (%d)") +JMESSAGE(JERR_BAD_SAMPLING, "Bogus sampling factors") +JMESSAGE(JERR_BAD_SCAN_SCRIPT, "Invalid scan script at entry %d") +JMESSAGE(JERR_BAD_STATE, "Improper call to JPEG library in state %d") +JMESSAGE(JERR_BAD_STRUCT_SIZE, + "JPEG parameter struct mismatch: library thinks size is %u, caller expects %u") +JMESSAGE(JERR_BAD_VIRTUAL_ACCESS, "Bogus virtual array access") +JMESSAGE(JERR_BUFFER_SIZE, "Buffer passed to JPEG library is too small") +JMESSAGE(JERR_CANT_SUSPEND, "Suspension not allowed here") +JMESSAGE(JERR_CANT_TRANSCODE, + "Cannot transcode to/from lossless JPEG datastreams") +JMESSAGE(JERR_CCIR601_NOTIMPL, "CCIR601 sampling not implemented yet") +JMESSAGE(JERR_COMPONENT_COUNT, "Too many color components: %d, max %d") +JMESSAGE(JERR_CONVERSION_NOTIMPL, "Unsupported color conversion request") +JMESSAGE(JERR_DAC_INDEX, "Bogus DAC index %d") +JMESSAGE(JERR_DAC_VALUE, "Bogus DAC value 0x%x") +JMESSAGE(JERR_DHT_INDEX, "Bogus DHT index %d") +JMESSAGE(JERR_DQT_INDEX, "Bogus DQT index %d") +JMESSAGE(JERR_EMPTY_IMAGE, "Empty JPEG image (DNL not supported)") +JMESSAGE(JERR_EMS_READ, "Read from EMS failed") +JMESSAGE(JERR_EMS_WRITE, "Write to EMS failed") +JMESSAGE(JERR_EOI_EXPECTED, "Didn't expect more than one scan") +JMESSAGE(JERR_FILE_READ, "Input file read error") +JMESSAGE(JERR_FILE_WRITE, "Output file write error --- out of disk space?") +JMESSAGE(JERR_FRACT_SAMPLE_NOTIMPL, "Fractional sampling not implemented yet") +JMESSAGE(JERR_HUFF_CLEN_OVERFLOW, "Huffman code size table overflow") +JMESSAGE(JERR_HUFF_MISSING_CODE, "Missing Huffman code table entry") +JMESSAGE(JERR_IMAGE_TOO_BIG, "Maximum supported image dimension is %u pixels") +JMESSAGE(JERR_INPUT_EMPTY, "Empty input file") +JMESSAGE(JERR_INPUT_EOF, "Premature end of input file") +JMESSAGE(JERR_MISMATCHED_QUANT_TABLE, + "Cannot transcode due to multiple use of quantization table %d") +JMESSAGE(JERR_MISSING_DATA, "Scan script does not transmit all data") +JMESSAGE(JERR_MODE_CHANGE, "Invalid color quantization mode change") +JMESSAGE(JERR_NOTIMPL, "Not implemented yet") +JMESSAGE(JERR_NOT_COMPILED, "Requested feature was omitted at compile time") +JMESSAGE(JERR_NO_BACKING_STORE, "Backing store not supported") +JMESSAGE(JERR_NO_HUFF_TABLE, "Huffman table 0x%02x was not defined") +JMESSAGE(JERR_NO_IMAGE, "JPEG datastream contains no image") +JMESSAGE(JERR_NO_LOSSLESS_SCRIPT, "Lossless encoding was requested but no scan script was supplied") +JMESSAGE(JERR_NO_QUANT_TABLE, "Quantization table 0x%02x was not defined") +JMESSAGE(JERR_NO_SOI, "Not a JPEG file: starts with 0x%02x 0x%02x") +JMESSAGE(JERR_OUT_OF_MEMORY, "Insufficient memory (case %d)") +JMESSAGE(JERR_QUANT_COMPONENTS, + "Cannot quantize more than %d color components") +JMESSAGE(JERR_QUANT_FEW_COLORS, "Cannot quantize to fewer than %d colors") +JMESSAGE(JERR_QUANT_MANY_COLORS, "Cannot quantize to more than %d colors") +JMESSAGE(JERR_SOF_DUPLICATE, "Invalid JPEG file structure: two SOF markers") +JMESSAGE(JERR_SOF_NO_SOS, "Invalid JPEG file structure: missing SOS marker") +JMESSAGE(JERR_SOF_UNSUPPORTED, "Unsupported JPEG process: SOF type 0x%02x") +JMESSAGE(JERR_SOI_DUPLICATE, "Invalid JPEG file structure: two SOI markers") +JMESSAGE(JERR_SOS_NO_SOF, "Invalid JPEG file structure: SOS before SOF") +JMESSAGE(JERR_TFILE_CREATE, "Failed to create temporary file %s") +JMESSAGE(JERR_TFILE_READ, "Read failed on temporary file") +JMESSAGE(JERR_TFILE_SEEK, "Seek failed on temporary file") +JMESSAGE(JERR_TFILE_WRITE, + "Write failed on temporary file --- out of disk space?") +JMESSAGE(JERR_TOO_LITTLE_DATA, "Application transferred too few scanlines") +JMESSAGE(JERR_UNKNOWN_MARKER, "Unsupported marker type 0x%02x") +JMESSAGE(JERR_VIRTUAL_BUG, "Virtual array controller messed up") +JMESSAGE(JERR_WIDTH_OVERFLOW, "Image too wide for this implementation") +JMESSAGE(JERR_XMS_READ, "Read from XMS failed") +JMESSAGE(JERR_XMS_WRITE, "Write to XMS failed") +JMESSAGE(JMSG_COPYRIGHT, JCOPYRIGHT) +JMESSAGE(JMSG_VERSION, JVERSION) +JMESSAGE(JTRC_16BIT_TABLES, + "CAUTION: quantization tables are too coarse for baseline JPEG") +JMESSAGE(JTRC_ADOBE, + "Adobe APP14 marker: version %d, flags 0x%04x 0x%04x, transform %d") +JMESSAGE(JTRC_APP0, "Unknown APP0 marker (not JFIF), length %u") +JMESSAGE(JTRC_APP14, "Unknown APP14 marker (not Adobe), length %u") +JMESSAGE(JTRC_DAC, "Define Arithmetic Table 0x%02x: 0x%02x") +JMESSAGE(JTRC_DHT, "Define Huffman Table 0x%02x") +JMESSAGE(JTRC_DQT, "Define Quantization Table %d precision %d") +JMESSAGE(JTRC_DRI, "Define Restart Interval %u") +JMESSAGE(JTRC_EMS_CLOSE, "Freed EMS handle %u") +JMESSAGE(JTRC_EMS_OPEN, "Obtained EMS handle %u") +JMESSAGE(JTRC_EOI, "End Of Image") +JMESSAGE(JTRC_HUFFBITS, " %3d %3d %3d %3d %3d %3d %3d %3d") +JMESSAGE(JTRC_JFIF, "JFIF APP0 marker: version %d.%02d, density %dx%d %d") +JMESSAGE(JTRC_JFIF_BADTHUMBNAILSIZE, + "Warning: thumbnail image size does not match data length %u") +JMESSAGE(JTRC_JFIF_EXTENSION, + "JFIF extension marker: type 0x%02x, length %u") +JMESSAGE(JTRC_JFIF_THUMBNAIL, " with %d x %d thumbnail image") +JMESSAGE(JTRC_MISC_MARKER, "Miscellaneous marker 0x%02x, length %u") +JMESSAGE(JTRC_PARMLESS_MARKER, "Unexpected marker 0x%02x") +JMESSAGE(JTRC_QUANTVALS, " %4u %4u %4u %4u %4u %4u %4u %4u") +JMESSAGE(JTRC_QUANT_3_NCOLORS, "Quantizing to %d = %d*%d*%d colors") +JMESSAGE(JTRC_QUANT_NCOLORS, "Quantizing to %d colors") +JMESSAGE(JTRC_QUANT_SELECTED, "Selected %d colors for quantization") +JMESSAGE(JTRC_RECOVERY_ACTION, "At marker 0x%02x, recovery action %d") +JMESSAGE(JTRC_RST, "RST%d") +JMESSAGE(JTRC_SMOOTH_NOTIMPL, + "Smoothing not supported with nonstandard sampling ratios") +JMESSAGE(JTRC_SOF, "Start Of Frame 0x%02x: width=%u, height=%u, components=%d") +JMESSAGE(JTRC_SOF_COMPONENT, " Component %d: %dhx%dv q=%d") +JMESSAGE(JTRC_SOI, "Start of Image") +JMESSAGE(JTRC_SOS, "Start Of Scan: %d components") +JMESSAGE(JTRC_SOS_COMPONENT, " Component %d: dc=%d ac=%d") +JMESSAGE(JTRC_SOS_PARAMS, " Ss=%d, Se=%d, Ah=%d, Al=%d") +JMESSAGE(JTRC_TFILE_CLOSE, "Closed temporary file %s") +JMESSAGE(JTRC_TFILE_OPEN, "Opened temporary file %s") +JMESSAGE(JTRC_THUMB_JPEG, + "JFIF extension marker: JPEG-compressed thumbnail image, length %u") +JMESSAGE(JTRC_THUMB_PALETTE, + "JFIF extension marker: palette thumbnail image, length %u") +JMESSAGE(JTRC_THUMB_RGB, + "JFIF extension marker: RGB thumbnail image, length %u") +JMESSAGE(JTRC_UNKNOWN_LOSSLESS_IDS, + "Unrecognized component IDs %d %d %d, assuming RGB") +JMESSAGE(JTRC_UNKNOWN_LOSSY_IDS, + "Unrecognized component IDs %d %d %d, assuming YCbCr") +JMESSAGE(JTRC_XMS_CLOSE, "Freed XMS handle %u") +JMESSAGE(JTRC_XMS_OPEN, "Obtained XMS handle %u") +JMESSAGE(JWRN_ADOBE_XFORM, "Unknown Adobe color transform code %d") +JMESSAGE(JWRN_BOGUS_PROGRESSION, + "Inconsistent progression sequence for component %d coefficient %d") +JMESSAGE(JWRN_EXTRANEOUS_DATA, + "Corrupt JPEG data: %u extraneous bytes before marker 0x%02x") +JMESSAGE(JWRN_HIT_MARKER, "Corrupt JPEG data: premature end of data segment") +JMESSAGE(JWRN_HUFF_BAD_CODE, "Corrupt JPEG data: bad Huffman code") +JMESSAGE(JWRN_JFIF_MAJOR, "Warning: unknown JFIF revision number %d.%02d") +JMESSAGE(JWRN_JPEG_EOF, "Premature end of JPEG file") +JMESSAGE(JWRN_MUST_DOWNSCALE, + "Must downscale data from %d bits to %d") +JMESSAGE(JWRN_MUST_RESYNC, + "Corrupt JPEG data: found marker 0x%02x instead of RST%d") +JMESSAGE(JWRN_NOT_SEQUENTIAL, "Invalid SOS parameters for sequential JPEG") +JMESSAGE(JWRN_TOO_MUCH_DATA, "Application transferred too many scanlines") +/* For more information see: + * http://www.medicalconnections.co.uk/html/lossless_bug.html */ +JMESSAGE(JWRN_SIGNED_ARITH, "Corrupt JPEG data: using signed arithmetic") + +#ifdef JMAKE_ENUM_LIST + + JMSG_LASTMSGCODE +} J_MESSAGE_CODE; + +#undef JMAKE_ENUM_LIST +#endif /* JMAKE_ENUM_LIST */ + +/* Zap JMESSAGE macro so that future re-inclusions do nothing by default */ +#undef JMESSAGE + + +#ifndef JERROR_H +#define JERROR_H + +/* Macros to simplify using the error and trace message stuff */ +/* The first parameter is either type of cinfo pointer */ + +/* Fatal errors (print message and exit) */ +#define ERREXIT(cinfo,code) \ + ((cinfo)->err->msg_code = (code), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT1(cinfo,code,p1) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT2(cinfo,code,p1,p2) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT3(cinfo,code,p1,p2,p3) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (cinfo)->err->msg_parm.i[2] = (p3), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT4(cinfo,code,p1,p2,p3,p4) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (cinfo)->err->msg_parm.i[2] = (p3), \ + (cinfo)->err->msg_parm.i[3] = (p4), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXITS(cinfo,code,str) \ + ((cinfo)->err->msg_code = (code), \ + strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) + +#define MAKESTMT(stuff) do { stuff } while (0) + +/* Nonfatal errors (we can keep going, but the data is probably corrupt) */ +#define WARNMS(cinfo,code) \ + ((cinfo)->err->msg_code = (code), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1)) +#define WARNMS1(cinfo,code,p1) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1)) +#define WARNMS2(cinfo,code,p1,p2) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1)) + +/* Informational/debugging messages */ +#define TRACEMS(cinfo,lvl,code) \ + ((cinfo)->err->msg_code = (code), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) +#define TRACEMS1(cinfo,lvl,code,p1) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) +#define TRACEMS2(cinfo,lvl,code,p1,p2) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) +#define TRACEMS3(cinfo,lvl,code,p1,p2,p3) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMS4(cinfo,lvl,code,p1,p2,p3,p4) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMS5(cinfo,lvl,code,p1,p2,p3,p4,p5) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \ + _mp[4] = (p5); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMS8(cinfo,lvl,code,p1,p2,p3,p4,p5,p6,p7,p8) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \ + _mp[4] = (p5); _mp[5] = (p6); _mp[6] = (p7); _mp[7] = (p8); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMSS(cinfo,lvl,code,str) \ + ((cinfo)->err->msg_code = (code), \ + strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) + +#endif /* JERROR_H */ diff --git a/gdcm/Utilities/gdcmjpeg/jfdctflt.c b/gdcm/Utilities/gdcmjpeg/jfdctflt.c new file mode 100644 index 0000000..13c9ed1 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jfdctflt.c @@ -0,0 +1,168 @@ +/* + * jfdctflt.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a floating-point implementation of the + * forward DCT (Discrete Cosine Transform). + * + * This implementation should be more accurate than either of the integer + * DCT implementations. However, it may not give the same results on all + * machines because of differences in roundoff behavior. Speed will depend + * on the hardware's floating point capacity. + * + * A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT + * on each column. Direct algorithms are also available, but they are + * much more complex and seem not to be any faster when reduced to code. + * + * This implementation is based on Arai, Agui, and Nakajima's algorithm for + * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in + * Japanese, but the algorithm is described in the Pennebaker & Mitchell + * JPEG textbook (see REFERENCES section in file README). The following code + * is based directly on figure 4-8 in P&M. + * While an 8-point DCT cannot be done in less than 11 multiplies, it is + * possible to arrange the computation so that many of the multiplies are + * simple scalings of the final outputs. These multiplies can then be + * folded into the multiplications or divisions by the JPEG quantization + * table entries. The AA&N method leaves only 5 multiplies and 29 adds + * to be done in the DCT itself. + * The primary disadvantage of this method is that with a fixed-point + * implementation, accuracy is lost due to imprecise representation of the + * scaled quantization values. However, that problem does not arise if + * we use floating point arithmetic. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + +#ifdef DCT_FLOAT_SUPPORTED + + +/* + * This module is specialized to the case DCTSIZE = 8. + */ + +#if DCTSIZE != 8 + Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ +#endif + + +/* + * Perform the forward DCT on one block of samples. + */ + +GLOBAL(void) +jpeg_fdct_float (FAST_FLOAT * data) +{ + FAST_FLOAT tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + FAST_FLOAT tmp10, tmp11, tmp12, tmp13; + FAST_FLOAT z1, z2, z3, z4, z5, z11, z13; + FAST_FLOAT *dataptr; + int ctr; + + /* Pass 1: process rows. */ + + dataptr = data; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + tmp0 = dataptr[0] + dataptr[7]; + tmp7 = dataptr[0] - dataptr[7]; + tmp1 = dataptr[1] + dataptr[6]; + tmp6 = dataptr[1] - dataptr[6]; + tmp2 = dataptr[2] + dataptr[5]; + tmp5 = dataptr[2] - dataptr[5]; + tmp3 = dataptr[3] + dataptr[4]; + tmp4 = dataptr[3] - dataptr[4]; + + /* Even part */ + + tmp10 = tmp0 + tmp3; /* phase 2 */ + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + dataptr[0] = tmp10 + tmp11; /* phase 3 */ + dataptr[4] = tmp10 - tmp11; + + z1 = (tmp12 + tmp13) * ((FAST_FLOAT) 0.707106781); /* c4 */ + dataptr[2] = tmp13 + z1; /* phase 5 */ + dataptr[6] = tmp13 - z1; + + /* Odd part */ + + tmp10 = tmp4 + tmp5; /* phase 2 */ + tmp11 = tmp5 + tmp6; + tmp12 = tmp6 + tmp7; + + /* The rotator is modified from fig 4-8 to avoid extra negations. */ + z5 = (tmp10 - tmp12) * ((FAST_FLOAT) 0.382683433); /* c6 */ + z2 = ((FAST_FLOAT) 0.541196100) * tmp10 + z5; /* c2-c6 */ + z4 = ((FAST_FLOAT) 1.306562965) * tmp12 + z5; /* c2+c6 */ + z3 = tmp11 * ((FAST_FLOAT) 0.707106781); /* c4 */ + + z11 = tmp7 + z3; /* phase 5 */ + z13 = tmp7 - z3; + + dataptr[5] = z13 + z2; /* phase 6 */ + dataptr[3] = z13 - z2; + dataptr[1] = z11 + z4; + dataptr[7] = z11 - z4; + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. */ + + dataptr = data; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7]; + tmp7 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7]; + tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6]; + tmp6 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6]; + tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5]; + tmp5 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5]; + tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4]; + tmp4 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4]; + + /* Even part */ + + tmp10 = tmp0 + tmp3; /* phase 2 */ + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + dataptr[DCTSIZE*0] = tmp10 + tmp11; /* phase 3 */ + dataptr[DCTSIZE*4] = tmp10 - tmp11; + + z1 = (tmp12 + tmp13) * ((FAST_FLOAT) 0.707106781); /* c4 */ + dataptr[DCTSIZE*2] = tmp13 + z1; /* phase 5 */ + dataptr[DCTSIZE*6] = tmp13 - z1; + + /* Odd part */ + + tmp10 = tmp4 + tmp5; /* phase 2 */ + tmp11 = tmp5 + tmp6; + tmp12 = tmp6 + tmp7; + + /* The rotator is modified from fig 4-8 to avoid extra negations. */ + z5 = (tmp10 - tmp12) * ((FAST_FLOAT) 0.382683433); /* c6 */ + z2 = ((FAST_FLOAT) 0.541196100) * tmp10 + z5; /* c2-c6 */ + z4 = ((FAST_FLOAT) 1.306562965) * tmp12 + z5; /* c2+c6 */ + z3 = tmp11 * ((FAST_FLOAT) 0.707106781); /* c4 */ + + z11 = tmp7 + z3; /* phase 5 */ + z13 = tmp7 - z3; + + dataptr[DCTSIZE*5] = z13 + z2; /* phase 6 */ + dataptr[DCTSIZE*3] = z13 - z2; + dataptr[DCTSIZE*1] = z11 + z4; + dataptr[DCTSIZE*7] = z11 - z4; + + dataptr++; /* advance pointer to next column */ + } +} + +#endif /* DCT_FLOAT_SUPPORTED */ diff --git a/gdcm/Utilities/gdcmjpeg/jfdctfst.c b/gdcm/Utilities/gdcmjpeg/jfdctfst.c new file mode 100644 index 0000000..6c19cf9 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jfdctfst.c @@ -0,0 +1,224 @@ +/* + * jfdctfst.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a fast, not so accurate integer implementation of the + * forward DCT (Discrete Cosine Transform). + * + * A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT + * on each column. Direct algorithms are also available, but they are + * much more complex and seem not to be any faster when reduced to code. + * + * This implementation is based on Arai, Agui, and Nakajima's algorithm for + * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in + * Japanese, but the algorithm is described in the Pennebaker & Mitchell + * JPEG textbook (see REFERENCES section in file README). The following code + * is based directly on figure 4-8 in P&M. + * While an 8-point DCT cannot be done in less than 11 multiplies, it is + * possible to arrange the computation so that many of the multiplies are + * simple scalings of the final outputs. These multiplies can then be + * folded into the multiplications or divisions by the JPEG quantization + * table entries. The AA&N method leaves only 5 multiplies and 29 adds + * to be done in the DCT itself. + * The primary disadvantage of this method is that with fixed-point math, + * accuracy is lost due to imprecise representation of the scaled + * quantization values. The smaller the quantization table entry, the less + * precise the scaled value, so this implementation does worse with high- + * quality-setting files than with low-quality ones. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + +#ifdef DCT_IFAST_SUPPORTED + + +/* + * This module is specialized to the case DCTSIZE = 8. + */ + +#if DCTSIZE != 8 + Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ +#endif + + +/* Scaling decisions are generally the same as in the LL&M algorithm; + * see jfdctint.c for more details. However, we choose to descale + * (right shift) multiplication products as soon as they are formed, + * rather than carrying additional fractional bits into subsequent additions. + * This compromises accuracy slightly, but it lets us save a few shifts. + * More importantly, 16-bit arithmetic is then adequate (for 8-bit samples) + * everywhere except in the multiplications proper; this saves a good deal + * of work on 16-bit-int machines. + * + * Again to save a few shifts, the intermediate results between pass 1 and + * pass 2 are not upscaled, but are represented only to integral precision. + * + * A final compromise is to represent the multiplicative constants to only + * 8 fractional bits, rather than 13. This saves some shifting work on some + * machines, and may also reduce the cost of multiplication (since there + * are fewer one-bits in the constants). + */ + +#define CONST_BITS 8 + + +/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus + * causing a lot of useless floating-point operations at run time. + * To get around this we use the following pre-calculated constants. + * If you change CONST_BITS you may want to add appropriate values. + * (With a reasonable C compiler, you can just rely on the FIX() macro...) + */ + +#if CONST_BITS == 8 +#define FIX_0_382683433 ((INT32) 98) /* FIX(0.382683433) */ +#define FIX_0_541196100 ((INT32) 139) /* FIX(0.541196100) */ +#define FIX_0_707106781 ((INT32) 181) /* FIX(0.707106781) */ +#define FIX_1_306562965 ((INT32) 334) /* FIX(1.306562965) */ +#else +#define FIX_0_382683433 FIX(0.382683433) +#define FIX_0_541196100 FIX(0.541196100) +#define FIX_0_707106781 FIX(0.707106781) +#define FIX_1_306562965 FIX(1.306562965) +#endif + + +/* We can gain a little more speed, with a further compromise in accuracy, + * by omitting the addition in a descaling shift. This yields an incorrectly + * rounded result half the time... + */ + +#ifndef USE_ACCURATE_ROUNDING +#undef DESCALE +#define DESCALE(x,n) RIGHT_SHIFT(x, n) +#endif + + +/* Multiply a DCTELEM variable by an INT32 constant, and immediately + * descale to yield a DCTELEM result. + */ + +#define MULTIPLY(var,const) ((DCTELEM) DESCALE((var) * (const), CONST_BITS)) + + +/* + * Perform the forward DCT on one block of samples. + */ + +GLOBAL(void) +jpeg_fdct_ifast (DCTELEM * data) +{ + DCTELEM tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + DCTELEM tmp10, tmp11, tmp12, tmp13; + DCTELEM z1, z2, z3, z4, z5, z11, z13; + DCTELEM *dataptr; + int ctr; + SHIFT_TEMPS + + /* Pass 1: process rows. */ + + dataptr = data; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + tmp0 = dataptr[0] + dataptr[7]; + tmp7 = dataptr[0] - dataptr[7]; + tmp1 = dataptr[1] + dataptr[6]; + tmp6 = dataptr[1] - dataptr[6]; + tmp2 = dataptr[2] + dataptr[5]; + tmp5 = dataptr[2] - dataptr[5]; + tmp3 = dataptr[3] + dataptr[4]; + tmp4 = dataptr[3] - dataptr[4]; + + /* Even part */ + + tmp10 = tmp0 + tmp3; /* phase 2 */ + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + dataptr[0] = tmp10 + tmp11; /* phase 3 */ + dataptr[4] = tmp10 - tmp11; + + z1 = MULTIPLY(tmp12 + tmp13, FIX_0_707106781); /* c4 */ + dataptr[2] = tmp13 + z1; /* phase 5 */ + dataptr[6] = tmp13 - z1; + + /* Odd part */ + + tmp10 = tmp4 + tmp5; /* phase 2 */ + tmp11 = tmp5 + tmp6; + tmp12 = tmp6 + tmp7; + + /* The rotator is modified from fig 4-8 to avoid extra negations. */ + z5 = MULTIPLY(tmp10 - tmp12, FIX_0_382683433); /* c6 */ + z2 = MULTIPLY(tmp10, FIX_0_541196100) + z5; /* c2-c6 */ + z4 = MULTIPLY(tmp12, FIX_1_306562965) + z5; /* c2+c6 */ + z3 = MULTIPLY(tmp11, FIX_0_707106781); /* c4 */ + + z11 = tmp7 + z3; /* phase 5 */ + z13 = tmp7 - z3; + + dataptr[5] = z13 + z2; /* phase 6 */ + dataptr[3] = z13 - z2; + dataptr[1] = z11 + z4; + dataptr[7] = z11 - z4; + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. */ + + dataptr = data; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7]; + tmp7 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7]; + tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6]; + tmp6 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6]; + tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5]; + tmp5 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5]; + tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4]; + tmp4 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4]; + + /* Even part */ + + tmp10 = tmp0 + tmp3; /* phase 2 */ + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + dataptr[DCTSIZE*0] = tmp10 + tmp11; /* phase 3 */ + dataptr[DCTSIZE*4] = tmp10 - tmp11; + + z1 = MULTIPLY(tmp12 + tmp13, FIX_0_707106781); /* c4 */ + dataptr[DCTSIZE*2] = tmp13 + z1; /* phase 5 */ + dataptr[DCTSIZE*6] = tmp13 - z1; + + /* Odd part */ + + tmp10 = tmp4 + tmp5; /* phase 2 */ + tmp11 = tmp5 + tmp6; + tmp12 = tmp6 + tmp7; + + /* The rotator is modified from fig 4-8 to avoid extra negations. */ + z5 = MULTIPLY(tmp10 - tmp12, FIX_0_382683433); /* c6 */ + z2 = MULTIPLY(tmp10, FIX_0_541196100) + z5; /* c2-c6 */ + z4 = MULTIPLY(tmp12, FIX_1_306562965) + z5; /* c2+c6 */ + z3 = MULTIPLY(tmp11, FIX_0_707106781); /* c4 */ + + z11 = tmp7 + z3; /* phase 5 */ + z13 = tmp7 - z3; + + dataptr[DCTSIZE*5] = z13 + z2; /* phase 6 */ + dataptr[DCTSIZE*3] = z13 - z2; + dataptr[DCTSIZE*1] = z11 + z4; + dataptr[DCTSIZE*7] = z11 - z4; + + dataptr++; /* advance pointer to next column */ + } +} + +#endif /* DCT_IFAST_SUPPORTED */ diff --git a/gdcm/Utilities/gdcmjpeg/jfdctint.c b/gdcm/Utilities/gdcmjpeg/jfdctint.c new file mode 100644 index 0000000..c6c4a28 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jfdctint.c @@ -0,0 +1,283 @@ +/* + * jfdctint.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a slow-but-accurate integer implementation of the + * forward DCT (Discrete Cosine Transform). + * + * A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT + * on each column. Direct algorithms are also available, but they are + * much more complex and seem not to be any faster when reduced to code. + * + * This implementation is based on an algorithm described in + * C. Loeffler, A. Ligtenberg and G. Moschytz, "Practical Fast 1-D DCT + * Algorithms with 11 Multiplications", Proc. Int'l. Conf. on Acoustics, + * Speech, and Signal Processing 1989 (ICASSP '89), pp. 988-991. + * The primary algorithm described there uses 11 multiplies and 29 adds. + * We use their alternate method with 12 multiplies and 32 adds. + * The advantage of this method is that no data path contains more than one + * multiplication; this allows a very simple and accurate implementation in + * scaled fixed-point arithmetic, with a minimal number of shifts. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + +#ifdef DCT_ISLOW_SUPPORTED + + +/* + * This module is specialized to the case DCTSIZE = 8. + */ + +#if DCTSIZE != 8 + Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ +#endif + + +/* + * The poop on this scaling stuff is as follows: + * + * Each 1-D DCT step produces outputs which are a factor of sqrt(N) + * larger than the true DCT outputs. The final outputs are therefore + * a factor of N larger than desired; since N=8 this can be cured by + * a simple right shift at the end of the algorithm. The advantage of + * this arrangement is that we save two multiplications per 1-D DCT, + * because the y0 and y4 outputs need not be divided by sqrt(N). + * In the IJG code, this factor of 8 is removed by the quantization step + * (in jcdctmgr.c), NOT in this module. + * + * We have to do addition and subtraction of the integer inputs, which + * is no problem, and multiplication by fractional constants, which is + * a problem to do in integer arithmetic. We multiply all the constants + * by CONST_SCALE and convert them to integer constants (thus retaining + * CONST_BITS bits of precision in the constants). After doing a + * multiplication we have to divide the product by CONST_SCALE, with proper + * rounding, to produce the correct output. This division can be done + * cheaply as a right shift of CONST_BITS bits. We postpone shifting + * as long as possible so that partial sums can be added together with + * full fractional precision. + * + * The outputs of the first pass are scaled up by PASS1_BITS bits so that + * they are represented to better-than-integral precision. These outputs + * require BITS_IN_JSAMPLE + PASS1_BITS + 3 bits; this fits in a 16-bit word + * with the recommended scaling. (For 12-bit sample data, the intermediate + * array is INT32 anyway.) + * + * To avoid overflow of the 32-bit intermediate results in pass 2, we must + * have BITS_IN_JSAMPLE + CONST_BITS + PASS1_BITS <= 26. Error analysis + * shows that the values given below are the most effective. + */ + +#if BITS_IN_JSAMPLE == 8 +#define CONST_BITS 13 +#define PASS1_BITS 2 +#else +#define CONST_BITS 13 +#define PASS1_BITS 1 /* lose a little precision to avoid overflow */ +#endif + +/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus + * causing a lot of useless floating-point operations at run time. + * To get around this we use the following pre-calculated constants. + * If you change CONST_BITS you may want to add appropriate values. + * (With a reasonable C compiler, you can just rely on the FIX() macro...) + */ + +#if CONST_BITS == 13 +#define FIX_0_298631336 ((INT32) 2446) /* FIX(0.298631336) */ +#define FIX_0_390180644 ((INT32) 3196) /* FIX(0.390180644) */ +#define FIX_0_541196100 ((INT32) 4433) /* FIX(0.541196100) */ +#define FIX_0_765366865 ((INT32) 6270) /* FIX(0.765366865) */ +#define FIX_0_899976223 ((INT32) 7373) /* FIX(0.899976223) */ +#define FIX_1_175875602 ((INT32) 9633) /* FIX(1.175875602) */ +#define FIX_1_501321110 ((INT32) 12299) /* FIX(1.501321110) */ +#define FIX_1_847759065 ((INT32) 15137) /* FIX(1.847759065) */ +#define FIX_1_961570560 ((INT32) 16069) /* FIX(1.961570560) */ +#define FIX_2_053119869 ((INT32) 16819) /* FIX(2.053119869) */ +#define FIX_2_562915447 ((INT32) 20995) /* FIX(2.562915447) */ +#define FIX_3_072711026 ((INT32) 25172) /* FIX(3.072711026) */ +#else +#define FIX_0_298631336 FIX(0.298631336) +#define FIX_0_390180644 FIX(0.390180644) +#define FIX_0_541196100 FIX(0.541196100) +#define FIX_0_765366865 FIX(0.765366865) +#define FIX_0_899976223 FIX(0.899976223) +#define FIX_1_175875602 FIX(1.175875602) +#define FIX_1_501321110 FIX(1.501321110) +#define FIX_1_847759065 FIX(1.847759065) +#define FIX_1_961570560 FIX(1.961570560) +#define FIX_2_053119869 FIX(2.053119869) +#define FIX_2_562915447 FIX(2.562915447) +#define FIX_3_072711026 FIX(3.072711026) +#endif + + +/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result. + * For 8-bit samples with the recommended scaling, all the variable + * and constant values involved are no more than 16 bits wide, so a + * 16x16->32 bit multiply can be used instead of a full 32x32 multiply. + * For 12-bit samples, a full 32-bit multiplication will be needed. + */ + +#if BITS_IN_JSAMPLE == 8 +#define MULTIPLY(var,const) MULTIPLY16C16(var,const) +#else +#define MULTIPLY(var,const) ((var) * (const)) +#endif + + +/* + * Perform the forward DCT on one block of samples. + */ + +GLOBAL(void) +jpeg_fdct_islow (DCTELEM * data) +{ + INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + INT32 tmp10, tmp11, tmp12, tmp13; + INT32 z1, z2, z3, z4, z5; + DCTELEM *dataptr; + int ctr; + SHIFT_TEMPS + + /* Pass 1: process rows. */ + /* Note results are scaled up by sqrt(8) compared to a true DCT; */ + /* furthermore, we scale the results by 2**PASS1_BITS. */ + + dataptr = data; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + tmp0 = dataptr[0] + dataptr[7]; + tmp7 = dataptr[0] - dataptr[7]; + tmp1 = dataptr[1] + dataptr[6]; + tmp6 = dataptr[1] - dataptr[6]; + tmp2 = dataptr[2] + dataptr[5]; + tmp5 = dataptr[2] - dataptr[5]; + tmp3 = dataptr[3] + dataptr[4]; + tmp4 = dataptr[3] - dataptr[4]; + + /* Even part per LL&M figure 1 --- note that published figure is faulty; + * rotator "sqrt(2)*c1" should be "sqrt(2)*c6". + */ + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + dataptr[0] = (DCTELEM) ((tmp10 + tmp11) << PASS1_BITS); + dataptr[4] = (DCTELEM) ((tmp10 - tmp11) << PASS1_BITS); + + z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100); + dataptr[2] = (DCTELEM) DESCALE(z1 + MULTIPLY(tmp13, FIX_0_765366865), + CONST_BITS-PASS1_BITS); + dataptr[6] = (DCTELEM) DESCALE(z1 + MULTIPLY(tmp12, - FIX_1_847759065), + CONST_BITS-PASS1_BITS); + + /* Odd part per figure 8 --- note paper omits factor of sqrt(2). + * cK represents cos(K*pi/16). + * i0..i3 in the paper are tmp4..tmp7 here. + */ + + z1 = tmp4 + tmp7; + z2 = tmp5 + tmp6; + z3 = tmp4 + tmp6; + z4 = tmp5 + tmp7; + z5 = MULTIPLY(z3 + z4, FIX_1_175875602); /* sqrt(2) * c3 */ + + tmp4 = MULTIPLY(tmp4, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */ + tmp5 = MULTIPLY(tmp5, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */ + tmp6 = MULTIPLY(tmp6, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */ + tmp7 = MULTIPLY(tmp7, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */ + z1 = MULTIPLY(z1, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */ + z2 = MULTIPLY(z2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */ + z3 = MULTIPLY(z3, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */ + z4 = MULTIPLY(z4, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */ + + z3 += z5; + z4 += z5; + + dataptr[7] = (DCTELEM) DESCALE(tmp4 + z1 + z3, CONST_BITS-PASS1_BITS); + dataptr[5] = (DCTELEM) DESCALE(tmp5 + z2 + z4, CONST_BITS-PASS1_BITS); + dataptr[3] = (DCTELEM) DESCALE(tmp6 + z2 + z3, CONST_BITS-PASS1_BITS); + dataptr[1] = (DCTELEM) DESCALE(tmp7 + z1 + z4, CONST_BITS-PASS1_BITS); + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. + * We remove the PASS1_BITS scaling, but leave the results scaled up + * by an overall factor of 8. + */ + + dataptr = data; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7]; + tmp7 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7]; + tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6]; + tmp6 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6]; + tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5]; + tmp5 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5]; + tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4]; + tmp4 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4]; + + /* Even part per LL&M figure 1 --- note that published figure is faulty; + * rotator "sqrt(2)*c1" should be "sqrt(2)*c6". + */ + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + dataptr[DCTSIZE*0] = (DCTELEM) DESCALE(tmp10 + tmp11, PASS1_BITS); + dataptr[DCTSIZE*4] = (DCTELEM) DESCALE(tmp10 - tmp11, PASS1_BITS); + + z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100); + dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(z1 + MULTIPLY(tmp13, FIX_0_765366865), + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*6] = (DCTELEM) DESCALE(z1 + MULTIPLY(tmp12, - FIX_1_847759065), + CONST_BITS+PASS1_BITS); + + /* Odd part per figure 8 --- note paper omits factor of sqrt(2). + * cK represents cos(K*pi/16). + * i0..i3 in the paper are tmp4..tmp7 here. + */ + + z1 = tmp4 + tmp7; + z2 = tmp5 + tmp6; + z3 = tmp4 + tmp6; + z4 = tmp5 + tmp7; + z5 = MULTIPLY(z3 + z4, FIX_1_175875602); /* sqrt(2) * c3 */ + + tmp4 = MULTIPLY(tmp4, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */ + tmp5 = MULTIPLY(tmp5, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */ + tmp6 = MULTIPLY(tmp6, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */ + tmp7 = MULTIPLY(tmp7, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */ + z1 = MULTIPLY(z1, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */ + z2 = MULTIPLY(z2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */ + z3 = MULTIPLY(z3, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */ + z4 = MULTIPLY(z4, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */ + + z3 += z5; + z4 += z5; + + dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp4 + z1 + z3, + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp5 + z2 + z4, + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp6 + z2 + z3, + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp7 + z1 + z4, + CONST_BITS+PASS1_BITS); + + dataptr++; /* advance pointer to next column */ + } +} + +#endif /* DCT_ISLOW_SUPPORTED */ diff --git a/gdcm/Utilities/gdcmjpeg/jidctflt.c b/gdcm/Utilities/gdcmjpeg/jidctflt.c new file mode 100644 index 0000000..e3b60b2 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jidctflt.c @@ -0,0 +1,242 @@ +/* + * jidctflt.c + * + * Copyright (C) 1994-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a floating-point implementation of the + * inverse DCT (Discrete Cosine Transform). In the IJG code, this routine + * must also perform dequantization of the input coefficients. + * + * This implementation should be more accurate than either of the integer + * IDCT implementations. However, it may not give the same results on all + * machines because of differences in roundoff behavior. Speed will depend + * on the hardware's floating point capacity. + * + * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT + * on each row (or vice versa, but it's more convenient to emit a row at + * a time). Direct algorithms are also available, but they are much more + * complex and seem not to be any faster when reduced to code. + * + * This implementation is based on Arai, Agui, and Nakajima's algorithm for + * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in + * Japanese, but the algorithm is described in the Pennebaker & Mitchell + * JPEG textbook (see REFERENCES section in file README). The following code + * is based directly on figure 4-8 in P&M. + * While an 8-point DCT cannot be done in less than 11 multiplies, it is + * possible to arrange the computation so that many of the multiplies are + * simple scalings of the final outputs. These multiplies can then be + * folded into the multiplications or divisions by the JPEG quantization + * table entries. The AA&N method leaves only 5 multiplies and 29 adds + * to be done in the DCT itself. + * The primary disadvantage of this method is that with a fixed-point + * implementation, accuracy is lost due to imprecise representation of the + * scaled quantization values. However, that problem does not arise if + * we use floating point arithmetic. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + +#ifdef DCT_FLOAT_SUPPORTED + + +/* + * This module is specialized to the case DCTSIZE = 8. + */ + +#if DCTSIZE != 8 + Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ +#endif + + +/* Dequantize a coefficient by multiplying it by the multiplier-table + * entry; produce a float result. + */ + +#define DEQUANTIZE(coef,quantval) (((FAST_FLOAT) (coef)) * (quantval)) + + +/* + * Perform dequantization and inverse DCT on one block of coefficients. + */ + +GLOBAL(void) +jpeg_idct_float (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + FAST_FLOAT tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + FAST_FLOAT tmp10, tmp11, tmp12, tmp13; + FAST_FLOAT z5, z10, z11, z12, z13; + JCOEFPTR inptr; + FLOAT_MULT_TYPE * quantptr; + FAST_FLOAT * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + FAST_FLOAT workspace[DCTSIZE2]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (FLOAT_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = DCTSIZE; ctr > 0; ctr--) { + /* Due to quantization, we will usually find that many of the input + * coefficients are zero, especially the AC terms. We can exploit this + * by short-circuiting the IDCT calculation for any column in which all + * the AC terms are zero. In that case each output is equal to the + * DC coefficient (with scale factor as needed). + * With typical images and quantization tables, half or more of the + * column DCT calculations can be simplified this way. + */ + + if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 && + inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 && + inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 && + inptr[DCTSIZE*7] == 0) { + /* AC terms all zero */ + FAST_FLOAT dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + + wsptr[DCTSIZE*0] = dcval; + wsptr[DCTSIZE*1] = dcval; + wsptr[DCTSIZE*2] = dcval; + wsptr[DCTSIZE*3] = dcval; + wsptr[DCTSIZE*4] = dcval; + wsptr[DCTSIZE*5] = dcval; + wsptr[DCTSIZE*6] = dcval; + wsptr[DCTSIZE*7] = dcval; + + inptr++; /* advance pointers to next column */ + quantptr++; + wsptr++; + continue; + } + + /* Even part */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + tmp3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + tmp10 = tmp0 + tmp2; /* phase 3 */ + tmp11 = tmp0 - tmp2; + + tmp13 = tmp1 + tmp3; /* phases 5-3 */ + tmp12 = (tmp1 - tmp3) * ((FAST_FLOAT) 1.414213562) - tmp13; /* 2*c4 */ + + tmp0 = tmp10 + tmp13; /* phase 2 */ + tmp3 = tmp10 - tmp13; + tmp1 = tmp11 + tmp12; + tmp2 = tmp11 - tmp12; + + /* Odd part */ + + tmp4 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + tmp5 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + tmp6 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + tmp7 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + + z13 = tmp6 + tmp5; /* phase 6 */ + z10 = tmp6 - tmp5; + z11 = tmp4 + tmp7; + z12 = tmp4 - tmp7; + + tmp7 = z11 + z13; /* phase 5 */ + tmp11 = (z11 - z13) * ((FAST_FLOAT) 1.414213562); /* 2*c4 */ + + z5 = (z10 + z12) * ((FAST_FLOAT) 1.847759065); /* 2*c2 */ + tmp10 = ((FAST_FLOAT) 1.082392200) * z12 - z5; /* 2*(c2-c6) */ + tmp12 = ((FAST_FLOAT) -2.613125930) * z10 + z5; /* -2*(c2+c6) */ + + tmp6 = tmp12 - tmp7; /* phase 2 */ + tmp5 = tmp11 - tmp6; + tmp4 = tmp10 + tmp5; + + wsptr[DCTSIZE*0] = tmp0 + tmp7; + wsptr[DCTSIZE*7] = tmp0 - tmp7; + wsptr[DCTSIZE*1] = tmp1 + tmp6; + wsptr[DCTSIZE*6] = tmp1 - tmp6; + wsptr[DCTSIZE*2] = tmp2 + tmp5; + wsptr[DCTSIZE*5] = tmp2 - tmp5; + wsptr[DCTSIZE*4] = tmp3 + tmp4; + wsptr[DCTSIZE*3] = tmp3 - tmp4; + + inptr++; /* advance pointers to next column */ + quantptr++; + wsptr++; + } + + /* Pass 2: process rows from work array, store into output array. */ + /* Note that we must descale the results by a factor of 8 == 2**3. */ + + wsptr = workspace; + for (ctr = 0; ctr < DCTSIZE; ctr++) { + outptr = output_buf[ctr] + output_col; + /* Rows of zeroes can be exploited in the same way as we did with columns. + * However, the column calculation has created many nonzero AC terms, so + * the simplification applies less often (typically 5% to 10% of the time). + * And testing floats for zero is relatively expensive, so we don't bother. + */ + + /* Even part */ + + tmp10 = wsptr[0] + wsptr[4]; + tmp11 = wsptr[0] - wsptr[4]; + + tmp13 = wsptr[2] + wsptr[6]; + tmp12 = (wsptr[2] - wsptr[6]) * ((FAST_FLOAT) 1.414213562) - tmp13; + + tmp0 = tmp10 + tmp13; + tmp3 = tmp10 - tmp13; + tmp1 = tmp11 + tmp12; + tmp2 = tmp11 - tmp12; + + /* Odd part */ + + z13 = wsptr[5] + wsptr[3]; + z10 = wsptr[5] - wsptr[3]; + z11 = wsptr[1] + wsptr[7]; + z12 = wsptr[1] - wsptr[7]; + + tmp7 = z11 + z13; + tmp11 = (z11 - z13) * ((FAST_FLOAT) 1.414213562); + + z5 = (z10 + z12) * ((FAST_FLOAT) 1.847759065); /* 2*c2 */ + tmp10 = ((FAST_FLOAT) 1.082392200) * z12 - z5; /* 2*(c2-c6) */ + tmp12 = ((FAST_FLOAT) -2.613125930) * z10 + z5; /* -2*(c2+c6) */ + + tmp6 = tmp12 - tmp7; + tmp5 = tmp11 - tmp6; + tmp4 = tmp10 + tmp5; + + /* Final output stage: scale down by a factor of 8 and range-limit */ + + outptr[0] = range_limit[(int) DESCALE((INT32) (tmp0 + tmp7), 3) + & RANGE_MASK]; + outptr[7] = range_limit[(int) DESCALE((INT32) (tmp0 - tmp7), 3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) DESCALE((INT32) (tmp1 + tmp6), 3) + & RANGE_MASK]; + outptr[6] = range_limit[(int) DESCALE((INT32) (tmp1 - tmp6), 3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) DESCALE((INT32) (tmp2 + tmp5), 3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) DESCALE((INT32) (tmp2 - tmp5), 3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) DESCALE((INT32) (tmp3 + tmp4), 3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) DESCALE((INT32) (tmp3 - tmp4), 3) + & RANGE_MASK]; + + wsptr += DCTSIZE; /* advance pointer to next row */ + } +} + +#endif /* DCT_FLOAT_SUPPORTED */ diff --git a/gdcm/Utilities/gdcmjpeg/jidctfst.c b/gdcm/Utilities/gdcmjpeg/jidctfst.c new file mode 100644 index 0000000..0d97707 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jidctfst.c @@ -0,0 +1,368 @@ +/* + * jidctfst.c + * + * Copyright (C) 1994-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a fast, not so accurate integer implementation of the + * inverse DCT (Discrete Cosine Transform). In the IJG code, this routine + * must also perform dequantization of the input coefficients. + * + * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT + * on each row (or vice versa, but it's more convenient to emit a row at + * a time). Direct algorithms are also available, but they are much more + * complex and seem not to be any faster when reduced to code. + * + * This implementation is based on Arai, Agui, and Nakajima's algorithm for + * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in + * Japanese, but the algorithm is described in the Pennebaker & Mitchell + * JPEG textbook (see REFERENCES section in file README). The following code + * is based directly on figure 4-8 in P&M. + * While an 8-point DCT cannot be done in less than 11 multiplies, it is + * possible to arrange the computation so that many of the multiplies are + * simple scalings of the final outputs. These multiplies can then be + * folded into the multiplications or divisions by the JPEG quantization + * table entries. The AA&N method leaves only 5 multiplies and 29 adds + * to be done in the DCT itself. + * The primary disadvantage of this method is that with fixed-point math, + * accuracy is lost due to imprecise representation of the scaled + * quantization values. The smaller the quantization table entry, the less + * precise the scaled value, so this implementation does worse with high- + * quality-setting files than with low-quality ones. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + +#ifdef DCT_IFAST_SUPPORTED + + +/* + * This module is specialized to the case DCTSIZE = 8. + */ + +#if DCTSIZE != 8 + Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ +#endif + + +/* Scaling decisions are generally the same as in the LL&M algorithm; + * see jidctint.c for more details. However, we choose to descale + * (right shift) multiplication products as soon as they are formed, + * rather than carrying additional fractional bits into subsequent additions. + * This compromises accuracy slightly, but it lets us save a few shifts. + * More importantly, 16-bit arithmetic is then adequate (for 8-bit samples) + * everywhere except in the multiplications proper; this saves a good deal + * of work on 16-bit-int machines. + * + * The dequantized coefficients are not integers because the AA&N scaling + * factors have been incorporated. We represent them scaled up by PASS1_BITS, + * so that the first and second IDCT rounds have the same input scaling. + * For 8-bit JSAMPLEs, we choose IFAST_SCALE_BITS = PASS1_BITS so as to + * avoid a descaling shift; this compromises accuracy rather drastically + * for small quantization table entries, but it saves a lot of shifts. + * For 12-bit JSAMPLEs, there's no hope of using 16x16 multiplies anyway, + * so we use a much larger scaling factor to preserve accuracy. + * + * A final compromise is to represent the multiplicative constants to only + * 8 fractional bits, rather than 13. This saves some shifting work on some + * machines, and may also reduce the cost of multiplication (since there + * are fewer one-bits in the constants). + */ + +#if BITS_IN_JSAMPLE == 8 +#define CONST_BITS 8 +#define PASS1_BITS 2 +#else +#define CONST_BITS 8 +#define PASS1_BITS 1 /* lose a little precision to avoid overflow */ +#endif + +/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus + * causing a lot of useless floating-point operations at run time. + * To get around this we use the following pre-calculated constants. + * If you change CONST_BITS you may want to add appropriate values. + * (With a reasonable C compiler, you can just rely on the FIX() macro...) + */ + +#if CONST_BITS == 8 +#define FIX_1_082392200 ((INT32) 277) /* FIX(1.082392200) */ +#define FIX_1_414213562 ((INT32) 362) /* FIX(1.414213562) */ +#define FIX_1_847759065 ((INT32) 473) /* FIX(1.847759065) */ +#define FIX_2_613125930 ((INT32) 669) /* FIX(2.613125930) */ +#else +#define FIX_1_082392200 FIX(1.082392200) +#define FIX_1_414213562 FIX(1.414213562) +#define FIX_1_847759065 FIX(1.847759065) +#define FIX_2_613125930 FIX(2.613125930) +#endif + + +/* We can gain a little more speed, with a further compromise in accuracy, + * by omitting the addition in a descaling shift. This yields an incorrectly + * rounded result half the time... + */ + +#ifndef USE_ACCURATE_ROUNDING +#undef DESCALE +#define DESCALE(x,n) RIGHT_SHIFT(x, n) +#endif + + +/* Multiply a DCTELEM variable by an INT32 constant, and immediately + * descale to yield a DCTELEM result. + */ + +#define MULTIPLY(var,const) ((DCTELEM) DESCALE((var) * (const), CONST_BITS)) + + +/* Dequantize a coefficient by multiplying it by the multiplier-table + * entry; produce a DCTELEM result. For 8-bit data a 16x16->16 + * multiplication will do. For 12-bit data, the multiplier table is + * declared INT32, so a 32-bit multiply will be used. + */ + +#if BITS_IN_JSAMPLE == 8 +#define DEQUANTIZE(coef,quantval) (((IFAST_MULT_TYPE) (coef)) * (quantval)) +#else +#define DEQUANTIZE(coef,quantval) \ + DESCALE((coef)*(quantval), IFAST_SCALE_BITS-PASS1_BITS) +#endif + + +/* Like DESCALE, but applies to a DCTELEM and produces an int. + * We assume that int right shift is unsigned if INT32 right shift is. + */ + +#ifdef RIGHT_SHIFT_IS_UNSIGNED +#define ISHIFT_TEMPS DCTELEM ishift_temp; +#if BITS_IN_JSAMPLE == 8 +#define DCTELEMBITS 16 /* DCTELEM may be 16 or 32 bits */ +#else +#define DCTELEMBITS 32 /* DCTELEM must be 32 bits */ +#endif +#define IRIGHT_SHIFT(x,shft) \ + ((ishift_temp = (x)) < 0 ? \ + (ishift_temp >> (shft)) | ((~((DCTELEM) 0)) << (DCTELEMBITS-(shft))) : \ + (ishift_temp >> (shft))) +#else +#define ISHIFT_TEMPS +#define IRIGHT_SHIFT(x,shft) ((x) >> (shft)) +#endif + +#ifdef USE_ACCURATE_ROUNDING +#define IDESCALE(x,n) ((int) IRIGHT_SHIFT((x) + (1 << ((n)-1)), n)) +#else +#define IDESCALE(x,n) ((int) IRIGHT_SHIFT(x, n)) +#endif + + +/* + * Perform dequantization and inverse DCT on one block of coefficients. + */ + +GLOBAL(void) +jpeg_idct_ifast (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + DCTELEM tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + DCTELEM tmp10, tmp11, tmp12, tmp13; + DCTELEM z5, z10, z11, z12, z13; + JCOEFPTR inptr; + IFAST_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[DCTSIZE2]; /* buffers data between passes */ + SHIFT_TEMPS /* for DESCALE */ + ISHIFT_TEMPS /* for IDESCALE */ + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (IFAST_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = DCTSIZE; ctr > 0; ctr--) { + /* Due to quantization, we will usually find that many of the input + * coefficients are zero, especially the AC terms. We can exploit this + * by short-circuiting the IDCT calculation for any column in which all + * the AC terms are zero. In that case each output is equal to the + * DC coefficient (with scale factor as needed). + * With typical images and quantization tables, half or more of the + * column DCT calculations can be simplified this way. + */ + + if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 && + inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 && + inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 && + inptr[DCTSIZE*7] == 0) { + /* AC terms all zero */ + int dcval = (int) DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + + wsptr[DCTSIZE*0] = dcval; + wsptr[DCTSIZE*1] = dcval; + wsptr[DCTSIZE*2] = dcval; + wsptr[DCTSIZE*3] = dcval; + wsptr[DCTSIZE*4] = dcval; + wsptr[DCTSIZE*5] = dcval; + wsptr[DCTSIZE*6] = dcval; + wsptr[DCTSIZE*7] = dcval; + + inptr++; /* advance pointers to next column */ + quantptr++; + wsptr++; + continue; + } + + /* Even part */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + tmp3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + tmp10 = tmp0 + tmp2; /* phase 3 */ + tmp11 = tmp0 - tmp2; + + tmp13 = tmp1 + tmp3; /* phases 5-3 */ + tmp12 = MULTIPLY(tmp1 - tmp3, FIX_1_414213562) - tmp13; /* 2*c4 */ + + tmp0 = tmp10 + tmp13; /* phase 2 */ + tmp3 = tmp10 - tmp13; + tmp1 = tmp11 + tmp12; + tmp2 = tmp11 - tmp12; + + /* Odd part */ + + tmp4 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + tmp5 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + tmp6 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + tmp7 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + + z13 = tmp6 + tmp5; /* phase 6 */ + z10 = tmp6 - tmp5; + z11 = tmp4 + tmp7; + z12 = tmp4 - tmp7; + + tmp7 = z11 + z13; /* phase 5 */ + tmp11 = MULTIPLY(z11 - z13, FIX_1_414213562); /* 2*c4 */ + + z5 = MULTIPLY(z10 + z12, FIX_1_847759065); /* 2*c2 */ + tmp10 = MULTIPLY(z12, FIX_1_082392200) - z5; /* 2*(c2-c6) */ + tmp12 = MULTIPLY(z10, - FIX_2_613125930) + z5; /* -2*(c2+c6) */ + + tmp6 = tmp12 - tmp7; /* phase 2 */ + tmp5 = tmp11 - tmp6; + tmp4 = tmp10 + tmp5; + + wsptr[DCTSIZE*0] = (int) (tmp0 + tmp7); + wsptr[DCTSIZE*7] = (int) (tmp0 - tmp7); + wsptr[DCTSIZE*1] = (int) (tmp1 + tmp6); + wsptr[DCTSIZE*6] = (int) (tmp1 - tmp6); + wsptr[DCTSIZE*2] = (int) (tmp2 + tmp5); + wsptr[DCTSIZE*5] = (int) (tmp2 - tmp5); + wsptr[DCTSIZE*4] = (int) (tmp3 + tmp4); + wsptr[DCTSIZE*3] = (int) (tmp3 - tmp4); + + inptr++; /* advance pointers to next column */ + quantptr++; + wsptr++; + } + + /* Pass 2: process rows from work array, store into output array. */ + /* Note that we must descale the results by a factor of 8 == 2**3, */ + /* and also undo the PASS1_BITS scaling. */ + + wsptr = workspace; + for (ctr = 0; ctr < DCTSIZE; ctr++) { + outptr = output_buf[ctr] + output_col; + /* Rows of zeroes can be exploited in the same way as we did with columns. + * However, the column calculation has created many nonzero AC terms, so + * the simplification applies less often (typically 5% to 10% of the time). + * On machines with very fast multiplication, it's possible that the + * test takes more time than it's worth. In that case this section + * may be commented out. + */ + +#ifndef NO_ZERO_ROW_TEST + if (wsptr[1] == 0 && wsptr[2] == 0 && wsptr[3] == 0 && wsptr[4] == 0 && + wsptr[5] == 0 && wsptr[6] == 0 && wsptr[7] == 0) { + /* AC terms all zero */ + JSAMPLE dcval = range_limit[IDESCALE(wsptr[0], PASS1_BITS+3) + & RANGE_MASK]; + + outptr[0] = dcval; + outptr[1] = dcval; + outptr[2] = dcval; + outptr[3] = dcval; + outptr[4] = dcval; + outptr[5] = dcval; + outptr[6] = dcval; + outptr[7] = dcval; + + wsptr += DCTSIZE; /* advance pointer to next row */ + continue; + } +#endif + + /* Even part */ + + tmp10 = ((DCTELEM) wsptr[0] + (DCTELEM) wsptr[4]); + tmp11 = ((DCTELEM) wsptr[0] - (DCTELEM) wsptr[4]); + + tmp13 = ((DCTELEM) wsptr[2] + (DCTELEM) wsptr[6]); + tmp12 = MULTIPLY((DCTELEM) wsptr[2] - (DCTELEM) wsptr[6], FIX_1_414213562) + - tmp13; + + tmp0 = tmp10 + tmp13; + tmp3 = tmp10 - tmp13; + tmp1 = tmp11 + tmp12; + tmp2 = tmp11 - tmp12; + + /* Odd part */ + + z13 = (DCTELEM) wsptr[5] + (DCTELEM) wsptr[3]; + z10 = (DCTELEM) wsptr[5] - (DCTELEM) wsptr[3]; + z11 = (DCTELEM) wsptr[1] + (DCTELEM) wsptr[7]; + z12 = (DCTELEM) wsptr[1] - (DCTELEM) wsptr[7]; + + tmp7 = z11 + z13; /* phase 5 */ + tmp11 = MULTIPLY(z11 - z13, FIX_1_414213562); /* 2*c4 */ + + z5 = MULTIPLY(z10 + z12, FIX_1_847759065); /* 2*c2 */ + tmp10 = MULTIPLY(z12, FIX_1_082392200) - z5; /* 2*(c2-c6) */ + tmp12 = MULTIPLY(z10, - FIX_2_613125930) + z5; /* -2*(c2+c6) */ + + tmp6 = tmp12 - tmp7; /* phase 2 */ + tmp5 = tmp11 - tmp6; + tmp4 = tmp10 + tmp5; + + /* Final output stage: scale down by a factor of 8 and range-limit */ + + outptr[0] = range_limit[IDESCALE(tmp0 + tmp7, PASS1_BITS+3) + & RANGE_MASK]; + outptr[7] = range_limit[IDESCALE(tmp0 - tmp7, PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[IDESCALE(tmp1 + tmp6, PASS1_BITS+3) + & RANGE_MASK]; + outptr[6] = range_limit[IDESCALE(tmp1 - tmp6, PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[IDESCALE(tmp2 + tmp5, PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[IDESCALE(tmp2 - tmp5, PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[IDESCALE(tmp3 + tmp4, PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[IDESCALE(tmp3 - tmp4, PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += DCTSIZE; /* advance pointer to next row */ + } +} + +#endif /* DCT_IFAST_SUPPORTED */ diff --git a/gdcm/Utilities/gdcmjpeg/jidctint.c b/gdcm/Utilities/gdcmjpeg/jidctint.c new file mode 100644 index 0000000..5d76f2e --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jidctint.c @@ -0,0 +1,389 @@ +/* + * jidctint.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a slow-but-accurate integer implementation of the + * inverse DCT (Discrete Cosine Transform). In the IJG code, this routine + * must also perform dequantization of the input coefficients. + * + * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT + * on each row (or vice versa, but it's more convenient to emit a row at + * a time). Direct algorithms are also available, but they are much more + * complex and seem not to be any faster when reduced to code. + * + * This implementation is based on an algorithm described in + * C. Loeffler, A. Ligtenberg and G. Moschytz, "Practical Fast 1-D DCT + * Algorithms with 11 Multiplications", Proc. Int'l. Conf. on Acoustics, + * Speech, and Signal Processing 1989 (ICASSP '89), pp. 988-991. + * The primary algorithm described there uses 11 multiplies and 29 adds. + * We use their alternate method with 12 multiplies and 32 adds. + * The advantage of this method is that no data path contains more than one + * multiplication; this allows a very simple and accurate implementation in + * scaled fixed-point arithmetic, with a minimal number of shifts. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + +#ifdef DCT_ISLOW_SUPPORTED + + +/* + * This module is specialized to the case DCTSIZE = 8. + */ + +#if DCTSIZE != 8 + Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ +#endif + + +/* + * The poop on this scaling stuff is as follows: + * + * Each 1-D IDCT step produces outputs which are a factor of sqrt(N) + * larger than the true IDCT outputs. The final outputs are therefore + * a factor of N larger than desired; since N=8 this can be cured by + * a simple right shift at the end of the algorithm. The advantage of + * this arrangement is that we save two multiplications per 1-D IDCT, + * because the y0 and y4 inputs need not be divided by sqrt(N). + * + * We have to do addition and subtraction of the integer inputs, which + * is no problem, and multiplication by fractional constants, which is + * a problem to do in integer arithmetic. We multiply all the constants + * by CONST_SCALE and convert them to integer constants (thus retaining + * CONST_BITS bits of precision in the constants). After doing a + * multiplication we have to divide the product by CONST_SCALE, with proper + * rounding, to produce the correct output. This division can be done + * cheaply as a right shift of CONST_BITS bits. We postpone shifting + * as long as possible so that partial sums can be added together with + * full fractional precision. + * + * The outputs of the first pass are scaled up by PASS1_BITS bits so that + * they are represented to better-than-integral precision. These outputs + * require BITS_IN_JSAMPLE + PASS1_BITS + 3 bits; this fits in a 16-bit word + * with the recommended scaling. (To scale up 12-bit sample data further, an + * intermediate INT32 array would be needed.) + * + * To avoid overflow of the 32-bit intermediate results in pass 2, we must + * have BITS_IN_JSAMPLE + CONST_BITS + PASS1_BITS <= 26. Error analysis + * shows that the values given below are the most effective. + */ + +#if BITS_IN_JSAMPLE == 8 +#define CONST_BITS 13 +#define PASS1_BITS 2 +#else +#define CONST_BITS 13 +#define PASS1_BITS 1 /* lose a little precision to avoid overflow */ +#endif + +/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus + * causing a lot of useless floating-point operations at run time. + * To get around this we use the following pre-calculated constants. + * If you change CONST_BITS you may want to add appropriate values. + * (With a reasonable C compiler, you can just rely on the FIX() macro...) + */ + +#if CONST_BITS == 13 +#define FIX_0_298631336 ((INT32) 2446) /* FIX(0.298631336) */ +#define FIX_0_390180644 ((INT32) 3196) /* FIX(0.390180644) */ +#define FIX_0_541196100 ((INT32) 4433) /* FIX(0.541196100) */ +#define FIX_0_765366865 ((INT32) 6270) /* FIX(0.765366865) */ +#define FIX_0_899976223 ((INT32) 7373) /* FIX(0.899976223) */ +#define FIX_1_175875602 ((INT32) 9633) /* FIX(1.175875602) */ +#define FIX_1_501321110 ((INT32) 12299) /* FIX(1.501321110) */ +#define FIX_1_847759065 ((INT32) 15137) /* FIX(1.847759065) */ +#define FIX_1_961570560 ((INT32) 16069) /* FIX(1.961570560) */ +#define FIX_2_053119869 ((INT32) 16819) /* FIX(2.053119869) */ +#define FIX_2_562915447 ((INT32) 20995) /* FIX(2.562915447) */ +#define FIX_3_072711026 ((INT32) 25172) /* FIX(3.072711026) */ +#else +#define FIX_0_298631336 FIX(0.298631336) +#define FIX_0_390180644 FIX(0.390180644) +#define FIX_0_541196100 FIX(0.541196100) +#define FIX_0_765366865 FIX(0.765366865) +#define FIX_0_899976223 FIX(0.899976223) +#define FIX_1_175875602 FIX(1.175875602) +#define FIX_1_501321110 FIX(1.501321110) +#define FIX_1_847759065 FIX(1.847759065) +#define FIX_1_961570560 FIX(1.961570560) +#define FIX_2_053119869 FIX(2.053119869) +#define FIX_2_562915447 FIX(2.562915447) +#define FIX_3_072711026 FIX(3.072711026) +#endif + + +/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result. + * For 8-bit samples with the recommended scaling, all the variable + * and constant values involved are no more than 16 bits wide, so a + * 16x16->32 bit multiply can be used instead of a full 32x32 multiply. + * For 12-bit samples, a full 32-bit multiplication will be needed. + */ + +#if BITS_IN_JSAMPLE == 8 +#define MULTIPLY(var,const) MULTIPLY16C16(var,const) +#else +#define MULTIPLY(var,const) ((var) * (const)) +#endif + + +/* Dequantize a coefficient by multiplying it by the multiplier-table + * entry; produce an int result. In this module, both inputs and result + * are 16 bits or less, so either int or short multiply will work. + */ + +#define DEQUANTIZE(coef,quantval) (((ISLOW_MULT_TYPE) (coef)) * (quantval)) + + +/* + * Perform dequantization and inverse DCT on one block of coefficients. + */ + +GLOBAL(void) +jpeg_idct_islow (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3; + INT32 tmp10, tmp11, tmp12, tmp13; + INT32 z1, z2, z3, z4, z5; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[DCTSIZE2]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + /* Note results are scaled up by sqrt(8) compared to a true IDCT; */ + /* furthermore, we scale the results by 2**PASS1_BITS. */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = DCTSIZE; ctr > 0; ctr--) { + /* Due to quantization, we will usually find that many of the input + * coefficients are zero, especially the AC terms. We can exploit this + * by short-circuiting the IDCT calculation for any column in which all + * the AC terms are zero. In that case each output is equal to the + * DC coefficient (with scale factor as needed). + * With typical images and quantization tables, half or more of the + * column DCT calculations can be simplified this way. + */ + + if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 && + inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 && + inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 && + inptr[DCTSIZE*7] == 0) { + /* AC terms all zero */ + int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS; + + wsptr[DCTSIZE*0] = dcval; + wsptr[DCTSIZE*1] = dcval; + wsptr[DCTSIZE*2] = dcval; + wsptr[DCTSIZE*3] = dcval; + wsptr[DCTSIZE*4] = dcval; + wsptr[DCTSIZE*5] = dcval; + wsptr[DCTSIZE*6] = dcval; + wsptr[DCTSIZE*7] = dcval; + + inptr++; /* advance pointers to next column */ + quantptr++; + wsptr++; + continue; + } + + /* Even part: reverse the even part of the forward DCT. */ + /* The rotator is sqrt(2)*c(-6). */ + + z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + z1 = MULTIPLY(z2 + z3, FIX_0_541196100); + tmp2 = z1 + MULTIPLY(z3, - FIX_1_847759065); + tmp3 = z1 + MULTIPLY(z2, FIX_0_765366865); + + z2 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + z3 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + + tmp0 = (z2 + z3) << CONST_BITS; + tmp1 = (z2 - z3) << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + /* Odd part per figure 8; the matrix is unitary and hence its + * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. + */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + tmp1 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + tmp2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + tmp3 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + + z1 = tmp0 + tmp3; + z2 = tmp1 + tmp2; + z3 = tmp0 + tmp2; + z4 = tmp1 + tmp3; + z5 = MULTIPLY(z3 + z4, FIX_1_175875602); /* sqrt(2) * c3 */ + + tmp0 = MULTIPLY(tmp0, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */ + tmp1 = MULTIPLY(tmp1, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */ + tmp2 = MULTIPLY(tmp2, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */ + tmp3 = MULTIPLY(tmp3, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */ + z1 = MULTIPLY(z1, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */ + z2 = MULTIPLY(z2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */ + z3 = MULTIPLY(z3, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */ + z4 = MULTIPLY(z4, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */ + + z3 += z5; + z4 += z5; + + tmp0 += z1 + z3; + tmp1 += z2 + z4; + tmp2 += z2 + z3; + tmp3 += z1 + z4; + + /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ + + wsptr[DCTSIZE*0] = (int) DESCALE(tmp10 + tmp3, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*7] = (int) DESCALE(tmp10 - tmp3, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*1] = (int) DESCALE(tmp11 + tmp2, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*6] = (int) DESCALE(tmp11 - tmp2, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*2] = (int) DESCALE(tmp12 + tmp1, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*5] = (int) DESCALE(tmp12 - tmp1, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*3] = (int) DESCALE(tmp13 + tmp0, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*4] = (int) DESCALE(tmp13 - tmp0, CONST_BITS-PASS1_BITS); + + inptr++; /* advance pointers to next column */ + quantptr++; + wsptr++; + } + + /* Pass 2: process rows from work array, store into output array. */ + /* Note that we must descale the results by a factor of 8 == 2**3, */ + /* and also undo the PASS1_BITS scaling. */ + + wsptr = workspace; + for (ctr = 0; ctr < DCTSIZE; ctr++) { + outptr = output_buf[ctr] + output_col; + /* Rows of zeroes can be exploited in the same way as we did with columns. + * However, the column calculation has created many nonzero AC terms, so + * the simplification applies less often (typically 5% to 10% of the time). + * On machines with very fast multiplication, it's possible that the + * test takes more time than it's worth. In that case this section + * may be commented out. + */ + +#ifndef NO_ZERO_ROW_TEST + if (wsptr[1] == 0 && wsptr[2] == 0 && wsptr[3] == 0 && wsptr[4] == 0 && + wsptr[5] == 0 && wsptr[6] == 0 && wsptr[7] == 0) { + /* AC terms all zero */ + JSAMPLE dcval = range_limit[(int) DESCALE((INT32) wsptr[0], PASS1_BITS+3) + & RANGE_MASK]; + + outptr[0] = dcval; + outptr[1] = dcval; + outptr[2] = dcval; + outptr[3] = dcval; + outptr[4] = dcval; + outptr[5] = dcval; + outptr[6] = dcval; + outptr[7] = dcval; + + wsptr += DCTSIZE; /* advance pointer to next row */ + continue; + } +#endif + + /* Even part: reverse the even part of the forward DCT. */ + /* The rotator is sqrt(2)*c(-6). */ + + z2 = (INT32) wsptr[2]; + z3 = (INT32) wsptr[6]; + + z1 = MULTIPLY(z2 + z3, FIX_0_541196100); + tmp2 = z1 + MULTIPLY(z3, - FIX_1_847759065); + tmp3 = z1 + MULTIPLY(z2, FIX_0_765366865); + + tmp0 = ((INT32) wsptr[0] + (INT32) wsptr[4]) << CONST_BITS; + tmp1 = ((INT32) wsptr[0] - (INT32) wsptr[4]) << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + /* Odd part per figure 8; the matrix is unitary and hence its + * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. + */ + + tmp0 = (INT32) wsptr[7]; + tmp1 = (INT32) wsptr[5]; + tmp2 = (INT32) wsptr[3]; + tmp3 = (INT32) wsptr[1]; + + z1 = tmp0 + tmp3; + z2 = tmp1 + tmp2; + z3 = tmp0 + tmp2; + z4 = tmp1 + tmp3; + z5 = MULTIPLY(z3 + z4, FIX_1_175875602); /* sqrt(2) * c3 */ + + tmp0 = MULTIPLY(tmp0, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */ + tmp1 = MULTIPLY(tmp1, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */ + tmp2 = MULTIPLY(tmp2, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */ + tmp3 = MULTIPLY(tmp3, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */ + z1 = MULTIPLY(z1, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */ + z2 = MULTIPLY(z2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */ + z3 = MULTIPLY(z3, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */ + z4 = MULTIPLY(z4, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */ + + z3 += z5; + z4 += z5; + + tmp0 += z1 + z3; + tmp1 += z2 + z4; + tmp2 += z2 + z3; + tmp3 += z1 + z4; + + /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ + + outptr[0] = range_limit[(int) DESCALE(tmp10 + tmp3, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[7] = range_limit[(int) DESCALE(tmp10 - tmp3, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) DESCALE(tmp11 + tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[6] = range_limit[(int) DESCALE(tmp11 - tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) DESCALE(tmp12 + tmp1, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) DESCALE(tmp12 - tmp1, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) DESCALE(tmp13 + tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) DESCALE(tmp13 - tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += DCTSIZE; /* advance pointer to next row */ + } +} + +#endif /* DCT_ISLOW_SUPPORTED */ diff --git a/gdcm/Utilities/gdcmjpeg/jidctred.c b/gdcm/Utilities/gdcmjpeg/jidctred.c new file mode 100644 index 0000000..fa28750 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jidctred.c @@ -0,0 +1,398 @@ +/* + * jidctred.c + * + * Copyright (C) 1994-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains inverse-DCT routines that produce reduced-size output: + * either 4x4, 2x2, or 1x1 pixels from an 8x8 DCT block. + * + * The implementation is based on the Loeffler, Ligtenberg and Moschytz (LL&M) + * algorithm used in jidctint.c. We simply replace each 8-to-8 1-D IDCT step + * with an 8-to-4 step that produces the four averages of two adjacent outputs + * (or an 8-to-2 step producing two averages of four outputs, for 2x2 output). + * These steps were derived by computing the corresponding values at the end + * of the normal LL&M code, then simplifying as much as possible. + * + * 1x1 is trivial: just take the DC coefficient divided by 8. + * + * See jidctint.c for additional comments. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + +#ifdef IDCT_SCALING_SUPPORTED + + +/* + * This module is specialized to the case DCTSIZE = 8. + */ + +#if DCTSIZE != 8 + Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ +#endif + + +/* Scaling is the same as in jidctint.c. */ + +#if BITS_IN_JSAMPLE == 8 +#define CONST_BITS 13 +#define PASS1_BITS 2 +#else +#define CONST_BITS 13 +#define PASS1_BITS 1 /* lose a little precision to avoid overflow */ +#endif + +/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus + * causing a lot of useless floating-point operations at run time. + * To get around this we use the following pre-calculated constants. + * If you change CONST_BITS you may want to add appropriate values. + * (With a reasonable C compiler, you can just rely on the FIX() macro...) + */ + +#if CONST_BITS == 13 +#define FIX_0_211164243 ((INT32) 1730) /* FIX(0.211164243) */ +#define FIX_0_509795579 ((INT32) 4176) /* FIX(0.509795579) */ +#define FIX_0_601344887 ((INT32) 4926) /* FIX(0.601344887) */ +#define FIX_0_720959822 ((INT32) 5906) /* FIX(0.720959822) */ +#define FIX_0_765366865 ((INT32) 6270) /* FIX(0.765366865) */ +#define FIX_0_850430095 ((INT32) 6967) /* FIX(0.850430095) */ +#define FIX_0_899976223 ((INT32) 7373) /* FIX(0.899976223) */ +#define FIX_1_061594337 ((INT32) 8697) /* FIX(1.061594337) */ +#define FIX_1_272758580 ((INT32) 10426) /* FIX(1.272758580) */ +#define FIX_1_451774981 ((INT32) 11893) /* FIX(1.451774981) */ +#define FIX_1_847759065 ((INT32) 15137) /* FIX(1.847759065) */ +#define FIX_2_172734803 ((INT32) 17799) /* FIX(2.172734803) */ +#define FIX_2_562915447 ((INT32) 20995) /* FIX(2.562915447) */ +#define FIX_3_624509785 ((INT32) 29692) /* FIX(3.624509785) */ +#else +#define FIX_0_211164243 FIX(0.211164243) +#define FIX_0_509795579 FIX(0.509795579) +#define FIX_0_601344887 FIX(0.601344887) +#define FIX_0_720959822 FIX(0.720959822) +#define FIX_0_765366865 FIX(0.765366865) +#define FIX_0_850430095 FIX(0.850430095) +#define FIX_0_899976223 FIX(0.899976223) +#define FIX_1_061594337 FIX(1.061594337) +#define FIX_1_272758580 FIX(1.272758580) +#define FIX_1_451774981 FIX(1.451774981) +#define FIX_1_847759065 FIX(1.847759065) +#define FIX_2_172734803 FIX(2.172734803) +#define FIX_2_562915447 FIX(2.562915447) +#define FIX_3_624509785 FIX(3.624509785) +#endif + + +/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result. + * For 8-bit samples with the recommended scaling, all the variable + * and constant values involved are no more than 16 bits wide, so a + * 16x16->32 bit multiply can be used instead of a full 32x32 multiply. + * For 12-bit samples, a full 32-bit multiplication will be needed. + */ + +#if BITS_IN_JSAMPLE == 8 +#define MULTIPLY(var,const) MULTIPLY16C16(var,const) +#else +#define MULTIPLY(var,const) ((var) * (const)) +#endif + + +/* Dequantize a coefficient by multiplying it by the multiplier-table + * entry; produce an int result. In this module, both inputs and result + * are 16 bits or less, so either int or short multiply will work. + */ + +#define DEQUANTIZE(coef,quantval) (((ISLOW_MULT_TYPE) (coef)) * (quantval)) + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a reduced-size 4x4 output block. + */ + +GLOBAL(void) +jpeg_idct_4x4 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp0, tmp2, tmp10, tmp12; + INT32 z1, z2, z3, z4; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[DCTSIZE*4]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = DCTSIZE; ctr > 0; inptr++, quantptr++, wsptr++, ctr--) { + /* Don't bother to process column 4, because second pass won't use it */ + if (ctr == DCTSIZE-4) + continue; + if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 && + inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*5] == 0 && + inptr[DCTSIZE*6] == 0 && inptr[DCTSIZE*7] == 0) { + /* AC terms all zero; we need not examine term 4 for 4x4 output */ + int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS; + + wsptr[DCTSIZE*0] = dcval; + wsptr[DCTSIZE*1] = dcval; + wsptr[DCTSIZE*2] = dcval; + wsptr[DCTSIZE*3] = dcval; + + continue; + } + + /* Even part */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp0 <<= (CONST_BITS+1); + + z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + tmp2 = MULTIPLY(z2, FIX_1_847759065) + MULTIPLY(z3, - FIX_0_765366865); + + tmp10 = tmp0 + tmp2; + tmp12 = tmp0 - tmp2; + + /* Odd part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + z2 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + z3 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + z4 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + + tmp0 = MULTIPLY(z1, - FIX_0_211164243) /* sqrt(2) * (c3-c1) */ + + MULTIPLY(z2, FIX_1_451774981) /* sqrt(2) * (c3+c7) */ + + MULTIPLY(z3, - FIX_2_172734803) /* sqrt(2) * (-c1-c5) */ + + MULTIPLY(z4, FIX_1_061594337); /* sqrt(2) * (c5+c7) */ + + tmp2 = MULTIPLY(z1, - FIX_0_509795579) /* sqrt(2) * (c7-c5) */ + + MULTIPLY(z2, - FIX_0_601344887) /* sqrt(2) * (c5-c1) */ + + MULTIPLY(z3, FIX_0_899976223) /* sqrt(2) * (c3-c7) */ + + MULTIPLY(z4, FIX_2_562915447); /* sqrt(2) * (c1+c3) */ + + /* Final output stage */ + + wsptr[DCTSIZE*0] = (int) DESCALE(tmp10 + tmp2, CONST_BITS-PASS1_BITS+1); + wsptr[DCTSIZE*3] = (int) DESCALE(tmp10 - tmp2, CONST_BITS-PASS1_BITS+1); + wsptr[DCTSIZE*1] = (int) DESCALE(tmp12 + tmp0, CONST_BITS-PASS1_BITS+1); + wsptr[DCTSIZE*2] = (int) DESCALE(tmp12 - tmp0, CONST_BITS-PASS1_BITS+1); + } + + /* Pass 2: process 4 rows from work array, store into output array. */ + + wsptr = workspace; + for (ctr = 0; ctr < 4; ctr++) { + outptr = output_buf[ctr] + output_col; + /* It's not clear whether a zero row test is worthwhile here ... */ + +#ifndef NO_ZERO_ROW_TEST + if (wsptr[1] == 0 && wsptr[2] == 0 && wsptr[3] == 0 && + wsptr[5] == 0 && wsptr[6] == 0 && wsptr[7] == 0) { + /* AC terms all zero */ + JSAMPLE dcval = range_limit[(int) DESCALE((INT32) wsptr[0], PASS1_BITS+3) + & RANGE_MASK]; + + outptr[0] = dcval; + outptr[1] = dcval; + outptr[2] = dcval; + outptr[3] = dcval; + + wsptr += DCTSIZE; /* advance pointer to next row */ + continue; + } +#endif + + /* Even part */ + + tmp0 = ((INT32) wsptr[0]) << (CONST_BITS+1); + + tmp2 = MULTIPLY((INT32) wsptr[2], FIX_1_847759065) + + MULTIPLY((INT32) wsptr[6], - FIX_0_765366865); + + tmp10 = tmp0 + tmp2; + tmp12 = tmp0 - tmp2; + + /* Odd part */ + + z1 = (INT32) wsptr[7]; + z2 = (INT32) wsptr[5]; + z3 = (INT32) wsptr[3]; + z4 = (INT32) wsptr[1]; + + tmp0 = MULTIPLY(z1, - FIX_0_211164243) /* sqrt(2) * (c3-c1) */ + + MULTIPLY(z2, FIX_1_451774981) /* sqrt(2) * (c3+c7) */ + + MULTIPLY(z3, - FIX_2_172734803) /* sqrt(2) * (-c1-c5) */ + + MULTIPLY(z4, FIX_1_061594337); /* sqrt(2) * (c5+c7) */ + + tmp2 = MULTIPLY(z1, - FIX_0_509795579) /* sqrt(2) * (c7-c5) */ + + MULTIPLY(z2, - FIX_0_601344887) /* sqrt(2) * (c5-c1) */ + + MULTIPLY(z3, FIX_0_899976223) /* sqrt(2) * (c3-c7) */ + + MULTIPLY(z4, FIX_2_562915447); /* sqrt(2) * (c1+c3) */ + + /* Final output stage */ + + outptr[0] = range_limit[(int) DESCALE(tmp10 + tmp2, + CONST_BITS+PASS1_BITS+3+1) + & RANGE_MASK]; + outptr[3] = range_limit[(int) DESCALE(tmp10 - tmp2, + CONST_BITS+PASS1_BITS+3+1) + & RANGE_MASK]; + outptr[1] = range_limit[(int) DESCALE(tmp12 + tmp0, + CONST_BITS+PASS1_BITS+3+1) + & RANGE_MASK]; + outptr[2] = range_limit[(int) DESCALE(tmp12 - tmp0, + CONST_BITS+PASS1_BITS+3+1) + & RANGE_MASK]; + + wsptr += DCTSIZE; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a reduced-size 2x2 output block. + */ + +GLOBAL(void) +jpeg_idct_2x2 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp0, tmp10, z1; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[DCTSIZE*2]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = DCTSIZE; ctr > 0; inptr++, quantptr++, wsptr++, ctr--) { + /* Don't bother to process columns 2,4,6 */ + if (ctr == DCTSIZE-2 || ctr == DCTSIZE-4 || ctr == DCTSIZE-6) + continue; + if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*3] == 0 && + inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*7] == 0) { + /* AC terms all zero; we need not examine terms 2,4,6 for 2x2 output */ + int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS; + + wsptr[DCTSIZE*0] = dcval; + wsptr[DCTSIZE*1] = dcval; + + continue; + } + + /* Even part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp10 = z1 << (CONST_BITS+2); + + /* Odd part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + tmp0 = MULTIPLY(z1, - FIX_0_720959822); /* sqrt(2) * (c7-c5+c3-c1) */ + z1 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + tmp0 += MULTIPLY(z1, FIX_0_850430095); /* sqrt(2) * (-c1+c3+c5+c7) */ + z1 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + tmp0 += MULTIPLY(z1, - FIX_1_272758580); /* sqrt(2) * (-c1+c3-c5-c7) */ + z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + tmp0 += MULTIPLY(z1, FIX_3_624509785); /* sqrt(2) * (c1+c3+c5+c7) */ + + /* Final output stage */ + + wsptr[DCTSIZE*0] = (int) DESCALE(tmp10 + tmp0, CONST_BITS-PASS1_BITS+2); + wsptr[DCTSIZE*1] = (int) DESCALE(tmp10 - tmp0, CONST_BITS-PASS1_BITS+2); + } + + /* Pass 2: process 2 rows from work array, store into output array. */ + + wsptr = workspace; + for (ctr = 0; ctr < 2; ctr++) { + outptr = output_buf[ctr] + output_col; + /* It's not clear whether a zero row test is worthwhile here ... */ + +#ifndef NO_ZERO_ROW_TEST + if (wsptr[1] == 0 && wsptr[3] == 0 && wsptr[5] == 0 && wsptr[7] == 0) { + /* AC terms all zero */ + JSAMPLE dcval = range_limit[(int) DESCALE((INT32) wsptr[0], PASS1_BITS+3) + & RANGE_MASK]; + + outptr[0] = dcval; + outptr[1] = dcval; + + wsptr += DCTSIZE; /* advance pointer to next row */ + continue; + } +#endif + + /* Even part */ + + tmp10 = ((INT32) wsptr[0]) << (CONST_BITS+2); + + /* Odd part */ + + tmp0 = MULTIPLY((INT32) wsptr[7], - FIX_0_720959822) /* sqrt(2) * (c7-c5+c3-c1) */ + + MULTIPLY((INT32) wsptr[5], FIX_0_850430095) /* sqrt(2) * (-c1+c3+c5+c7) */ + + MULTIPLY((INT32) wsptr[3], - FIX_1_272758580) /* sqrt(2) * (-c1+c3-c5-c7) */ + + MULTIPLY((INT32) wsptr[1], FIX_3_624509785); /* sqrt(2) * (c1+c3+c5+c7) */ + + /* Final output stage */ + + outptr[0] = range_limit[(int) DESCALE(tmp10 + tmp0, + CONST_BITS+PASS1_BITS+3+2) + & RANGE_MASK]; + outptr[1] = range_limit[(int) DESCALE(tmp10 - tmp0, + CONST_BITS+PASS1_BITS+3+2) + & RANGE_MASK]; + + wsptr += DCTSIZE; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a reduced-size 1x1 output block. + */ + +GLOBAL(void) +jpeg_idct_1x1 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + int dcval; + ISLOW_MULT_TYPE * quantptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + SHIFT_TEMPS + + /* We hardly need an inverse DCT routine for this: just take the + * average pixel value, which is one-eighth of the DC coefficient. + */ + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + dcval = DEQUANTIZE(coef_block[0], quantptr[0]); + dcval = (int) DESCALE((INT32) dcval, 3); + + output_buf[0][output_col] = range_limit[dcval & RANGE_MASK]; +} + +#endif /* IDCT_SCALING_SUPPORTED */ diff --git a/gdcm/Utilities/gdcmjpeg/jinclude.h b/gdcm/Utilities/gdcmjpeg/jinclude.h new file mode 100644 index 0000000..0a4f151 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jinclude.h @@ -0,0 +1,91 @@ +/* + * jinclude.h + * + * Copyright (C) 1991-1994, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file exists to provide a single place to fix any problems with + * including the wrong system include files. (Common problems are taken + * care of by the standard jconfig symbols, but on really weird systems + * you may have to edit this file.) + * + * NOTE: this file is NOT intended to be included by applications using the + * JPEG library. Most applications need only include jpeglib.h. + */ + + +/* Include auto-config file to find out which system include files we need. */ + +#include "jconfig.h" /* auto configuration options */ +#define JCONFIG_INCLUDED /* so that jpeglib.h doesn't do it again */ + +/* + * We need the NULL macro and size_t typedef. + * On an ANSI-conforming system it is sufficient to include . + * Otherwise, we get them from or ; we may have to + * pull in as well. + * Note that the core JPEG library does not require ; + * only the default error handler and data source/destination modules do. + * But we must pull it in because of the references to FILE in jpeglib.h. + * You can remove those references if you want to compile without . + */ + +#ifdef HAVE_STDDEF_H +#include +#endif + +#ifdef HAVE_STDLIB_H +#include +#endif + +#ifdef NEED_SYS_TYPES_H +#include +#endif + +#include + +/* + * We need memory copying and zeroing functions, plus strncpy(). + * ANSI and System V implementations declare these in . + * BSD doesn't have the mem() functions, but it does have bcopy()/bzero(). + * Some systems may declare memset and memcpy in . + * + * NOTE: we assume the size parameters to these functions are of type size_t. + * Change the casts in these macros if not! + */ + +#ifdef NEED_BSD_STRINGS + +#include +#define MEMZERO(target,size) bzero((void *)(target), (size_t)(size)) +#define MEMCOPY(dest,src,size) bcopy((const void *)(src), (void *)(dest), (size_t)(size)) + +#else /* not BSD, assume ANSI/SysV string lib */ + +#include +#define MEMZERO(target,size) memset((void *)(target), 0, (size_t)(size)) +#define MEMCOPY(dest,src,size) memcpy((void *)(dest), (const void *)(src), (size_t)(size)) + +#endif + +/* + * In ANSI C, and indeed any rational implementation, size_t is also the + * type returned by sizeof(). However, it seems there are some irrational + * implementations out there, in which sizeof() returns an int even though + * size_t is defined as long or unsigned long. To ensure consistent results + * we always use this SIZEOF() macro in place of using sizeof() directly. + */ + +#define SIZEOF(object) ((size_t) sizeof(object)) + +/* + * The modules that use fread() and fwrite() always invoke them through + * these macros. On some systems you may need to twiddle the argument casts. + * CAUTION: argument order is different from underlying functions! + */ + +#define JFREAD(file,buf,sizeofbuf) \ + ((size_t) fread((void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) +#define JFWRITE(file,buf,sizeofbuf) \ + ((size_t) fwrite((const void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) diff --git a/gdcm/Utilities/gdcmjpeg/jlossls.h b/gdcm/Utilities/gdcmjpeg/jlossls.h new file mode 100644 index 0000000..9b391bd --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jlossls.h @@ -0,0 +1,152 @@ +/* + * jlossls.h + * + * Copyright (C) 1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This include file contains common declarations for the lossless JPEG + * codec modules. + */ + +#ifndef JLOSSLS_H +#define JLOSSLS_H + + +/* + * Table H.1: Predictors for lossless coding. + */ + +#define PREDICTOR1 Ra +#define PREDICTOR2 Rb +#define PREDICTOR3 Rc +#define PREDICTOR4 (int) ((INT32) Ra + (INT32) Rb - (INT32) Rc) +#define PREDICTOR5 (int) ((INT32) Ra + RIGHT_SHIFT((INT32) Rb - (INT32) Rc, 1)) +#define PREDICTOR6 (int) ((INT32) Rb + RIGHT_SHIFT((INT32) Ra - (INT32) Rc, 1)) +#define PREDICTOR6_BUG (int) ((INT16) Rb + RIGHT_SHIFT((INT16) Ra - (INT16) Rc, 1)) +#define PREDICTOR7 (int) RIGHT_SHIFT((INT32) Ra + (INT32) Rb, 1) + + +typedef JMETHOD(void, predict_difference_method_ptr, + (j_compress_ptr cinfo, int ci, + JSAMPROW input_buf, JSAMPROW prev_row, + JDIFFROW diff_buf, JDIMENSION width)); + +typedef JMETHOD(void, scaler_method_ptr, + (j_compress_ptr cinfo, int ci, + JSAMPROW input_buf, JSAMPROW output_buf, + JDIMENSION width)); + +/* Lossless-specific compression codec (compressor proper) */ +typedef struct { + struct jpeg_c_codec pub; /* public fields */ + + + /* Difference buffer control */ + JMETHOD(void, diff_start_pass, (j_compress_ptr cinfo, + J_BUF_MODE pass_mode)); + + /* Pointer to data which is private to diff controller */ + void *diff_private; + + + /* Entropy encoding */ + JMETHOD(JDIMENSION, entropy_encode_mcus, (j_compress_ptr cinfo, + JDIFFIMAGE diff_buf, + JDIMENSION MCU_row_num, + JDIMENSION MCU_col_num, + JDIMENSION nMCU)); + + /* Pointer to data which is private to entropy module */ + void *entropy_private; + + + /* Prediction, differencing */ + JMETHOD(void, predict_start_pass, (j_compress_ptr cinfo)); + + /* It is useful to allow each component to have a separate diff method. */ + predict_difference_method_ptr predict_difference[MAX_COMPONENTS]; + + /* Pointer to data which is private to predictor module */ + void *pred_private; + + /* Sample scaling */ + JMETHOD(void, scaler_start_pass, (j_compress_ptr cinfo)); + JMETHOD(void, scaler_scale, (j_compress_ptr cinfo, + JSAMPROW input_buf, JSAMPROW output_buf, + JDIMENSION width)); + + /* Pointer to data which is private to scaler module */ + void *scaler_private; + +} jpeg_lossless_c_codec; + +typedef jpeg_lossless_c_codec * j_lossless_c_ptr; + + +typedef JMETHOD(void, predict_undifference_method_ptr, + (j_decompress_ptr cinfo, int comp_index, + JDIFFROW diff_buf, JDIFFROW prev_row, + JDIFFROW undiff_buf, JDIMENSION width)); + +/* Lossless-specific decompression codec (decompressor proper) */ +typedef struct { + struct jpeg_d_codec pub; /* public fields */ + + + /* Difference buffer control */ + JMETHOD(void, diff_start_input_pass, (j_decompress_ptr cinfo)); + + /* Pointer to data which is private to diff controller */ + void *diff_private; + + + /* Entropy decoding */ + JMETHOD(void, entropy_start_pass, (j_decompress_ptr cinfo)); + JMETHOD(boolean, entropy_process_restart, (j_decompress_ptr cinfo)); + JMETHOD(JDIMENSION, entropy_decode_mcus, (j_decompress_ptr cinfo, + JDIFFIMAGE diff_buf, + JDIMENSION MCU_row_num, + JDIMENSION MCU_col_num, + JDIMENSION nMCU)); + + /* Pointer to data which is private to entropy module */ + void *entropy_private; + + + /* Prediction, undifferencing */ + JMETHOD(void, predict_start_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, predict_process_restart, (j_decompress_ptr cinfo)); + + /* It is useful to allow each component to have a separate undiff method. */ + predict_undifference_method_ptr predict_undifference[MAX_COMPONENTS]; + + /* Pointer to data which is private to predictor module */ + void *pred_private; + + /* Sample scaling */ + JMETHOD(void, scaler_start_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, scaler_scale, (j_decompress_ptr cinfo, + JDIFFROW diff_buf, JSAMPROW output_buf, + JDIMENSION width)); + + /* Pointer to data which is private to scaler module */ + void *scaler_private; + +} jpeg_lossless_d_codec; + +typedef jpeg_lossless_d_codec * j_lossless_d_ptr; + + +/* Compression module initialization routines */ +EXTERN(void) jinit_lossless_c_codec JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_lhuff_encoder JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_differencer JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_c_scaler JPP((j_compress_ptr cinfo)); +/* Decompression module initialization routines */ +EXTERN(void) jinit_lossless_d_codec JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_lhuff_decoder JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_undifferencer JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_d_scaler JPP((j_decompress_ptr cinfo)); + +#endif /* JLOSSLS_H */ diff --git a/gdcm/Utilities/gdcmjpeg/jlossy.h b/gdcm/Utilities/gdcmjpeg/jlossy.h new file mode 100644 index 0000000..83c43f0 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jlossy.h @@ -0,0 +1,120 @@ +/* + * jlossy.h + * + * Copyright (C) 1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This include file contains common declarations for the lossy (DCT-based) + * JPEG codec modules. + */ + +#ifndef JLOSSY_H +#define JLOSSY_H + + +/* Lossy-specific compression codec (compressor proper) */ +typedef struct { + struct jpeg_c_codec pub; /* public fields */ + + + /* Coefficient buffer control */ + JMETHOD(void, coef_start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); + /* JMETHOD(boolean, coef_compress_data, (j_compress_ptr cinfo, + JSAMPIMAGE input_buf));*/ + + /* Pointer to data which is private to coef module */ + void *coef_private; + + + /* Forward DCT (also controls coefficient quantization) */ + JMETHOD(void, fdct_start_pass, (j_compress_ptr cinfo)); + /* perhaps this should be an array??? */ + JMETHOD(void, fdct_forward_DCT, (j_compress_ptr cinfo, + jpeg_component_info * compptr, + JSAMPARRAY sample_data, JBLOCKROW coef_blocks, + JDIMENSION start_row, JDIMENSION start_col, + JDIMENSION num_blocks)); + + /* Pointer to data which is private to fdct module */ + void *fdct_private; + + + /* Entropy encoding */ + JMETHOD(boolean, entropy_encode_mcu, (j_compress_ptr cinfo, + JBLOCKROW *MCU_data)); + + /* Pointer to data which is private to entropy module */ + void *entropy_private; + +} jpeg_lossy_c_codec; + +typedef jpeg_lossy_c_codec * j_lossy_c_ptr; + + + +typedef JMETHOD(void, inverse_DCT_method_ptr, + (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col)); + +/* Lossy-specific decompression codec (decompressor proper) */ +typedef struct { + struct jpeg_d_codec pub; /* public fields */ + + + /* Coefficient buffer control */ + JMETHOD(void, coef_start_input_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, coef_start_output_pass, (j_decompress_ptr cinfo)); + + /* Pointer to array of coefficient virtual arrays, or NULL if none */ + jvirt_barray_ptr *coef_arrays; + + /* Pointer to data which is private to coef module */ + void *coef_private; + + + /* Entropy decoding */ + JMETHOD(void, entropy_start_pass, (j_decompress_ptr cinfo)); + JMETHOD(boolean, entropy_decode_mcu, (j_decompress_ptr cinfo, + JBLOCKROW *MCU_data)); + + /* This is here to share code between baseline and progressive decoders; */ + /* other modules probably should not use it */ + boolean entropy_insufficient_data; /* set TRUE after emitting warning */ + + /* Pointer to data which is private to entropy module */ + void *entropy_private; + + + /* Inverse DCT (also performs dequantization) */ + JMETHOD(void, idct_start_pass, (j_decompress_ptr cinfo)); + + /* It is useful to allow each component to have a separate IDCT method. */ + inverse_DCT_method_ptr inverse_DCT[MAX_COMPONENTS]; + + /* Pointer to data which is private to idct module */ + void *idct_private; + +} jpeg_lossy_d_codec; + +typedef jpeg_lossy_d_codec * j_lossy_d_ptr; + + +/* Compression module initialization routines */ +EXTERN(void) jinit_lossy_c_codec JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_c_coef_controller JPP((j_compress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_forward_dct JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_shuff_encoder JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_phuff_encoder JPP((j_compress_ptr cinfo)); + +/* Decompression module initialization routines */ +EXTERN(void) jinit_lossy_d_codec JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_d_coef_controller JPP((j_decompress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_shuff_decoder JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_phuff_decoder JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_inverse_dct JPP((j_decompress_ptr cinfo)); + +#endif /* JLOSSY_H */ diff --git a/gdcm/Utilities/gdcmjpeg/jmemmgr.c b/gdcm/Utilities/gdcmjpeg/jmemmgr.c new file mode 100644 index 0000000..63dcd94 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jmemmgr.c @@ -0,0 +1,1174 @@ +/* + * jmemmgr.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the JPEG system-independent memory management + * routines. This code is usable across a wide variety of machines; most + * of the system dependencies have been isolated in a separate file. + * The major functions provided here are: + * * pool-based allocation and freeing of memory; + * * policy decisions about how to divide available memory among the + * virtual arrays; + * * control logic for swapping virtual arrays between main memory and + * backing storage. + * The separate system-dependent file provides the actual backing-storage + * access code, and it contains the policy decision about how much total + * main memory to use. + * This file is system-dependent in the sense that some of its functions + * are unnecessary in some systems. For example, if there is enough virtual + * memory so that backing storage will never be used, much of the virtual + * array control logic could be removed. (Of course, if you have that much + * memory then you shouldn't care about a little bit of unused code...) + */ + +#define JPEG_INTERNALS +#define AM_MEMORY_MANAGER /* we define jvirt_Xarray_control structs */ +#include "jinclude.h" +#include "jpeglib.h" +#include "jmemsys.h" /* import the system-dependent declarations */ + +#ifndef NO_GETENV +#ifndef HAVE_STDLIB_H /* should declare getenv() */ +extern char * getenv JPP((const char * name)); +#endif +#endif + + +/* + * Some important notes: + * The allocation routines provided here must never return NULL. + * They should exit to error_exit if unsuccessful. + * + * It's not a good idea to try to merge the sarray, barray and darray + * routines, even though they are textually almost the same, because + * samples are usually stored as bytes while coefficients and differenced + * are shorts or ints. Thus, in machines where byte pointers have a + * different representation from word pointers, the resulting machine + * code could not be the same. + */ + + +/* + * Many machines require storage alignment: longs must start on 4-byte + * boundaries, doubles on 8-byte boundaries, etc. On such machines, malloc() + * always returns pointers that are multiples of the worst-case alignment + * requirement, and we had better do so too. + * There isn't any really portable way to determine the worst-case alignment + * requirement. This module assumes that the alignment requirement is + * multiples of sizeof(ALIGN_TYPE). + * By default, we define ALIGN_TYPE as double. This is necessary on some + * workstations (where doubles really do need 8-byte alignment) and will work + * fine on nearly everything. If your machine has lesser alignment needs, + * you can save a few bytes by making ALIGN_TYPE smaller. + * The only place I know of where this will NOT work is certain Macintosh + * 680x0 compilers that define double as a 10-byte IEEE extended float. + * Doing 10-byte alignment is counterproductive because longwords won't be + * aligned well. Put "#define ALIGN_TYPE long" in jconfig.h if you have + * such a compiler. + */ + +#ifndef ALIGN_TYPE /* so can override from jconfig.h */ +#define ALIGN_TYPE double +#endif + + +/* + * We allocate objects from "pools", where each pool is gotten with a single + * request to jpeg_get_small() or jpeg_get_large(). There is no per-object + * overhead within a pool, except for alignment padding. Each pool has a + * header with a link to the next pool of the same class. + * Small and large pool headers are identical except that the latter's + * link pointer must be FAR on 80x86 machines. + * Notice that the "real" header fields are union'ed with a dummy ALIGN_TYPE + * field. This forces the compiler to make SIZEOF(small_pool_hdr) a multiple + * of the alignment requirement of ALIGN_TYPE. + */ + +typedef union small_pool_struct * small_pool_ptr; + +typedef union small_pool_struct { + struct { + small_pool_ptr next; /* next in list of pools */ + size_t bytes_used; /* how many bytes already used within pool */ + size_t bytes_left; /* bytes still available in this pool */ + } hdr; + ALIGN_TYPE dummy; /* included in union to ensure alignment */ +} small_pool_hdr; + +typedef union large_pool_struct FAR * large_pool_ptr; + +typedef union large_pool_struct { + struct { + large_pool_ptr next; /* next in list of pools */ + size_t bytes_used; /* how many bytes already used within pool */ + size_t bytes_left; /* bytes still available in this pool */ + } hdr; + ALIGN_TYPE dummy; /* included in union to ensure alignment */ +} large_pool_hdr; + + +/* + * Here is the full definition of a memory manager object. + */ + +typedef struct { + struct jpeg_memory_mgr pub; /* public fields */ + + /* Each pool identifier (lifetime class) names a linked list of pools. */ + small_pool_ptr small_list[JPOOL_NUMPOOLS]; + large_pool_ptr large_list[JPOOL_NUMPOOLS]; + + /* Since we only have one lifetime class of virtual arrays, only one + * linked list is necessary (for each datatype). Note that the virtual + * array control blocks being linked together are actually stored somewhere + * in the small-pool list. + */ + jvirt_sarray_ptr virt_sarray_list; + jvirt_barray_ptr virt_barray_list; + + /* This counts total space obtained from jpeg_get_small/large */ + long total_space_allocated; + + /* alloc_sarray and alloc_barray set this value for use by virtual + * array routines. + */ + JDIMENSION last_rowsperchunk; /* from most recent alloc_sarray/barray */ +} my_memory_mgr; + +typedef my_memory_mgr * my_mem_ptr; + + +/* + * The control blocks for virtual arrays. + * Note that these blocks are allocated in the "small" pool area. + * System-dependent info for the associated backing store (if any) is hidden + * inside the backing_store_info struct. + */ + +struct jvirt_sarray_control { + JSAMPARRAY mem_buffer; /* => the in-memory buffer */ + JDIMENSION rows_in_array; /* total virtual array height */ + JDIMENSION samplesperrow; /* width of array (and of memory buffer) */ + JDIMENSION maxaccess; /* max rows accessed by access_virt_sarray */ + JDIMENSION rows_in_mem; /* height of memory buffer */ + JDIMENSION rowsperchunk; /* allocation chunk size in mem_buffer */ + JDIMENSION cur_start_row; /* first logical row # in the buffer */ + JDIMENSION first_undef_row; /* row # of first uninitialized row */ + boolean pre_zero; /* pre-zero mode requested? */ + boolean dirty; /* do current buffer contents need written? */ + boolean b_s_open; /* is backing-store data valid? */ + jvirt_sarray_ptr next; /* link to next virtual sarray control block */ + backing_store_info b_s_info; /* System-dependent control info */ +}; + +struct jvirt_barray_control { + JBLOCKARRAY mem_buffer; /* => the in-memory buffer */ + JDIMENSION rows_in_array; /* total virtual array height */ + JDIMENSION blocksperrow; /* width of array (and of memory buffer) */ + JDIMENSION maxaccess; /* max rows accessed by access_virt_barray */ + JDIMENSION rows_in_mem; /* height of memory buffer */ + JDIMENSION rowsperchunk; /* allocation chunk size in mem_buffer */ + JDIMENSION cur_start_row; /* first logical row # in the buffer */ + JDIMENSION first_undef_row; /* row # of first uninitialized row */ + boolean pre_zero; /* pre-zero mode requested? */ + boolean dirty; /* do current buffer contents need written? */ + boolean b_s_open; /* is backing-store data valid? */ + jvirt_barray_ptr next; /* link to next virtual barray control block */ + backing_store_info b_s_info; /* System-dependent control info */ +}; + + +#ifdef MEM_STATS /* optional extra stuff for statistics */ + +LOCAL(void) +print_mem_stats (j_common_ptr cinfo, int pool_id) +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + small_pool_ptr shdr_ptr; + large_pool_ptr lhdr_ptr; + + /* Since this is only a debugging stub, we can cheat a little by using + * fprintf directly rather than going through the trace message code. + * This is helpful because message parm array can't handle longs. + */ + fprintf(stderr, "Freeing pool %d, total space = %ld\n", + pool_id, mem->total_space_allocated); + + for (lhdr_ptr = mem->large_list[pool_id]; lhdr_ptr != NULL; + lhdr_ptr = lhdr_ptr->hdr.next) { + fprintf(stderr, " Large chunk used %ld\n", + (long) lhdr_ptr->hdr.bytes_used); + } + + for (shdr_ptr = mem->small_list[pool_id]; shdr_ptr != NULL; + shdr_ptr = shdr_ptr->hdr.next) { + fprintf(stderr, " Small chunk used %ld free %ld\n", + (long) shdr_ptr->hdr.bytes_used, + (long) shdr_ptr->hdr.bytes_left); + } +} + +#endif /* MEM_STATS */ + + +LOCAL(void) +out_of_memory (j_common_ptr cinfo, int which) +/* Report an out-of-memory error and stop execution */ +/* If we compiled MEM_STATS support, report alloc requests before dying */ +{ +#ifdef MEM_STATS + cinfo->err->trace_level = 2; /* force self_destruct to report stats */ +#endif + ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, which); +} + + +/* + * Allocation of "small" objects. + * + * For these, we use pooled storage. When a new pool must be created, + * we try to get enough space for the current request plus a "slop" factor, + * where the slop will be the amount of leftover space in the new pool. + * The speed vs. space tradeoff is largely determined by the slop values. + * A different slop value is provided for each pool class (lifetime), + * and we also distinguish the first pool of a class from later ones. + * NOTE: the values given work fairly well on both 16- and 32-bit-int + * machines, but may be too small if longs are 64 bits or more. + */ + +static const size_t first_pool_slop[JPOOL_NUMPOOLS] = +{ + 1600, /* first PERMANENT pool */ + 16000 /* first IMAGE pool */ +}; + +static const size_t extra_pool_slop[JPOOL_NUMPOOLS] = +{ + 0, /* additional PERMANENT pools */ + 5000 /* additional IMAGE pools */ +}; + +#define MIN_SLOP 50 /* greater than 0 to avoid futile looping */ + + +METHODDEF(void *) +alloc_small (j_common_ptr cinfo, int pool_id, size_t sizeofobject) +/* Allocate a "small" object */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + small_pool_ptr hdr_ptr, prev_hdr_ptr; + char * data_ptr; + size_t odd_bytes, min_request, slop; + + /* Check for unsatisfiable request (do now to ensure no overflow below) */ + if (sizeofobject > (size_t) (MAX_ALLOC_CHUNK-SIZEOF(small_pool_hdr))) + out_of_memory(cinfo, 1); /* request exceeds malloc's ability */ + + /* Round up the requested size to a multiple of SIZEOF(ALIGN_TYPE) */ + odd_bytes = sizeofobject % SIZEOF(ALIGN_TYPE); + if (odd_bytes > 0) + sizeofobject += SIZEOF(ALIGN_TYPE) - odd_bytes; + + /* See if space is available in any existing pool */ + if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS) + ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ + prev_hdr_ptr = NULL; + hdr_ptr = mem->small_list[pool_id]; + while (hdr_ptr != NULL) { + if (hdr_ptr->hdr.bytes_left >= sizeofobject) + break; /* found pool with enough space */ + prev_hdr_ptr = hdr_ptr; + hdr_ptr = hdr_ptr->hdr.next; + } + + /* Time to make a new pool? */ + if (hdr_ptr == NULL) { + /* min_request is what we need now, slop is what will be leftover */ + min_request = sizeofobject + SIZEOF(small_pool_hdr); + if (prev_hdr_ptr == NULL) /* first pool in class? */ + slop = first_pool_slop[pool_id]; + else + slop = extra_pool_slop[pool_id]; + /* Don't ask for more than MAX_ALLOC_CHUNK */ + if (slop > (size_t) (MAX_ALLOC_CHUNK-min_request)) + slop = (size_t) (MAX_ALLOC_CHUNK-min_request); + /* Try to get space, if fail reduce slop and try again */ + for (;;) { + hdr_ptr = (small_pool_ptr) jpeg_get_small(cinfo, min_request + slop); + if (hdr_ptr != NULL) + break; + slop /= 2; + if (slop < MIN_SLOP) /* give up when it gets real small */ + out_of_memory(cinfo, 2); /* jpeg_get_small failed */ + } + mem->total_space_allocated += min_request + slop; + /* Success, initialize the new pool header and add to end of list */ + hdr_ptr->hdr.next = NULL; + hdr_ptr->hdr.bytes_used = 0; + hdr_ptr->hdr.bytes_left = sizeofobject + slop; + if (prev_hdr_ptr == NULL) /* first pool in class? */ + mem->small_list[pool_id] = hdr_ptr; + else + prev_hdr_ptr->hdr.next = hdr_ptr; + } + + /* OK, allocate the object from the current pool */ + data_ptr = (char *) (hdr_ptr + 1); /* point to first data byte in pool */ + data_ptr += hdr_ptr->hdr.bytes_used; /* point to place for object */ + hdr_ptr->hdr.bytes_used += sizeofobject; + hdr_ptr->hdr.bytes_left -= sizeofobject; + + return (void *) data_ptr; +} + + +/* + * Allocation of "large" objects. + * + * The external semantics of these are the same as "small" objects, + * except that FAR pointers are used on 80x86. However the pool + * management heuristics are quite different. We assume that each + * request is large enough that it may as well be passed directly to + * jpeg_get_large; the pool management just links everything together + * so that we can free it all on demand. + * Note: the major use of "large" objects is in JSAMPARRAY and JBLOCKARRAY + * structures. The routines that create these structures (see below) + * deliberately bunch rows together to ensure a large request size. + */ + +METHODDEF(void FAR *) +alloc_large (j_common_ptr cinfo, int pool_id, size_t sizeofobject) +/* Allocate a "large" object */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + large_pool_ptr hdr_ptr; + size_t odd_bytes; + + /* Check for unsatisfiable request (do now to ensure no overflow below) */ + if (sizeofobject > (size_t) (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr))) + out_of_memory(cinfo, 3); /* request exceeds malloc's ability */ + + /* Round up the requested size to a multiple of SIZEOF(ALIGN_TYPE) */ + odd_bytes = sizeofobject % SIZEOF(ALIGN_TYPE); + if (odd_bytes > 0) + sizeofobject += SIZEOF(ALIGN_TYPE) - odd_bytes; + + /* Always make a new pool */ + if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS) + ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ + + hdr_ptr = (large_pool_ptr) jpeg_get_large(cinfo, sizeofobject + + SIZEOF(large_pool_hdr)); + if (hdr_ptr == NULL) + out_of_memory(cinfo, 4); /* jpeg_get_large failed */ + mem->total_space_allocated += sizeofobject + SIZEOF(large_pool_hdr); + + /* Success, initialize the new pool header and add to list */ + hdr_ptr->hdr.next = mem->large_list[pool_id]; + /* We maintain space counts in each pool header for statistical purposes, + * even though they are not needed for allocation. + */ + hdr_ptr->hdr.bytes_used = sizeofobject; + hdr_ptr->hdr.bytes_left = 0; + mem->large_list[pool_id] = hdr_ptr; + + return (void FAR *) (hdr_ptr + 1); /* point to first data byte in pool */ +} + + +/* + * Creation of 2-D sample arrays. + * The pointers are in near heap, the samples themselves in FAR heap. + * + * To minimize allocation overhead and to allow I/O of large contiguous + * blocks, we allocate the sample rows in groups of as many rows as possible + * without exceeding MAX_ALLOC_CHUNK total bytes per allocation request. + * NB: the virtual array control routines, later in this file, know about + * this chunking of rows. The rowsperchunk value is left in the mem manager + * object so that it can be saved away if this sarray is the workspace for + * a virtual array. + */ + +METHODDEF(JSAMPARRAY) +alloc_sarray (j_common_ptr cinfo, int pool_id, + JDIMENSION samplesperrow, JDIMENSION numrows) +/* Allocate a 2-D sample array */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + JSAMPARRAY result; + JSAMPROW workspace; + JDIMENSION rowsperchunk, currow, i; + long ltemp; + + /* Calculate max # of rows allowed in one allocation chunk */ + ltemp = (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)) / + ((long) samplesperrow * SIZEOF(JSAMPLE)); + if (ltemp <= 0) + ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); + if (ltemp < (long) numrows) + rowsperchunk = (JDIMENSION) ltemp; + else + rowsperchunk = numrows; + mem->last_rowsperchunk = rowsperchunk; + + /* Get space for row pointers (small object) */ + result = (JSAMPARRAY) alloc_small(cinfo, pool_id, + (size_t) (numrows * SIZEOF(JSAMPROW))); + + /* Get the rows themselves (large objects) */ + currow = 0; + while (currow < numrows) { + rowsperchunk = MIN(rowsperchunk, numrows - currow); + workspace = (JSAMPROW) alloc_large(cinfo, pool_id, + (size_t) ((size_t) rowsperchunk * (size_t) samplesperrow + * SIZEOF(JSAMPLE))); + for (i = rowsperchunk; i > 0; i--) { + result[currow++] = workspace; + workspace += samplesperrow; + } + } + + return result; +} + + +/* + * Creation of 2-D coefficient-block arrays. + * This is essentially the same as the code for sample arrays, above. + */ + +METHODDEF(JBLOCKARRAY) +alloc_barray (j_common_ptr cinfo, int pool_id, + JDIMENSION blocksperrow, JDIMENSION numrows) +/* Allocate a 2-D coefficient-block array */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + JBLOCKARRAY result; + JBLOCKROW workspace; + JDIMENSION rowsperchunk, currow, i; + long ltemp; + + /* Calculate max # of rows allowed in one allocation chunk */ + ltemp = (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)) / + ((long) blocksperrow * SIZEOF(JBLOCK)); + if (ltemp <= 0) + ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); + if (ltemp < (long) numrows) + rowsperchunk = (JDIMENSION) ltemp; + else + rowsperchunk = numrows; + mem->last_rowsperchunk = rowsperchunk; + + /* Get space for row pointers (small object) */ + result = (JBLOCKARRAY) alloc_small(cinfo, pool_id, + (size_t) (numrows * SIZEOF(JBLOCKROW))); + + /* Get the rows themselves (large objects) */ + currow = 0; + while (currow < numrows) { + rowsperchunk = MIN(rowsperchunk, numrows - currow); + workspace = (JBLOCKROW) alloc_large(cinfo, pool_id, + (size_t) ((size_t) rowsperchunk * (size_t) blocksperrow + * SIZEOF(JBLOCK))); + for (i = rowsperchunk; i > 0; i--) { + result[currow++] = workspace; + workspace += blocksperrow; + } + } + + return result; +} + + +#ifdef NEED_DARRAY + +/* + * Creation of 2-D difference arrays. + * This is essentially the same as the code for sample arrays, above. + */ + +METHODDEF(JDIFFARRAY) +alloc_darray (j_common_ptr cinfo, int pool_id, + JDIMENSION diffsperrow, JDIMENSION numrows) +/* Allocate a 2-D difference array */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + JDIFFARRAY result; + JDIFFROW workspace; + JDIMENSION rowsperchunk, currow, i; + long ltemp; + + /* Calculate max # of rows allowed in one allocation chunk */ + ltemp = (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)) / + ((long) diffsperrow * SIZEOF(JDIFF)); + if (ltemp <= 0) + ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); + if (ltemp < (long) numrows) + rowsperchunk = (JDIMENSION) ltemp; + else + rowsperchunk = numrows; + mem->last_rowsperchunk = rowsperchunk; + + /* Get space for row pointers (small object) */ + result = (JDIFFARRAY) alloc_small(cinfo, pool_id, + (size_t) (numrows * SIZEOF(JDIFFROW))); + + /* Get the rows themselves (large objects) */ + currow = 0; + while (currow < numrows) { + rowsperchunk = MIN(rowsperchunk, numrows - currow); + workspace = (JDIFFROW) alloc_large(cinfo, pool_id, + (size_t) ((size_t) rowsperchunk * (size_t) diffsperrow + * SIZEOF(JDIFF))); + for (i = rowsperchunk; i > 0; i--) { + result[currow++] = workspace; + workspace += diffsperrow; + } + } + + return result; +} + +#endif + + +/* + * About virtual array management: + * + * The above "normal" array routines are only used to allocate strip buffers + * (as wide as the image, but just a few rows high). Full-image-sized buffers + * are handled as "virtual" arrays. The array is still accessed a strip at a + * time, but the memory manager must save the whole array for repeated + * accesses. The intended implementation is that there is a strip buffer in + * memory (as high as is possible given the desired memory limit), plus a + * backing file that holds the rest of the array. + * + * The request_virt_array routines are told the total size of the image and + * the maximum number of rows that will be accessed at once. The in-memory + * buffer must be at least as large as the maxaccess value. + * + * The request routines create control blocks but not the in-memory buffers. + * That is postponed until realize_virt_arrays is called. At that time the + * total amount of space needed is known (approximately, anyway), so free + * memory can be divided up fairly. + * + * The access_virt_array routines are responsible for making a specific strip + * area accessible (after reading or writing the backing file, if necessary). + * Note that the access routines are told whether the caller intends to modify + * the accessed strip; during a read-only pass this saves having to rewrite + * data to disk. The access routines are also responsible for pre-zeroing + * any newly accessed rows, if pre-zeroing was requested. + * + * In current usage, the access requests are usually for nonoverlapping + * strips; that is, successive access start_row numbers differ by exactly + * num_rows = maxaccess. This means we can get good performance with simple + * buffer dump/reload logic, by making the in-memory buffer be a multiple + * of the access height; then there will never be accesses across bufferload + * boundaries. The code will still work with overlapping access requests, + * but it doesn't handle bufferload overlaps very efficiently. + */ + + +METHODDEF(jvirt_sarray_ptr) +request_virt_sarray (j_common_ptr cinfo, int pool_id, boolean pre_zero, + JDIMENSION samplesperrow, JDIMENSION numrows, + JDIMENSION maxaccess) +/* Request a virtual 2-D sample array */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + jvirt_sarray_ptr result; + + /* Only IMAGE-lifetime virtual arrays are currently supported */ + if (pool_id != JPOOL_IMAGE) + ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ + + /* get control block */ + result = (jvirt_sarray_ptr) alloc_small(cinfo, pool_id, + SIZEOF(struct jvirt_sarray_control)); + + result->mem_buffer = NULL; /* marks array not yet realized */ + result->rows_in_array = numrows; + result->samplesperrow = samplesperrow; + result->maxaccess = maxaccess; + result->pre_zero = pre_zero; + result->b_s_open = FALSE; /* no associated backing-store object */ + result->next = mem->virt_sarray_list; /* add to list of virtual arrays */ + mem->virt_sarray_list = result; + + return result; +} + + +METHODDEF(jvirt_barray_ptr) +request_virt_barray (j_common_ptr cinfo, int pool_id, boolean pre_zero, + JDIMENSION blocksperrow, JDIMENSION numrows, + JDIMENSION maxaccess) +/* Request a virtual 2-D coefficient-block array */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + jvirt_barray_ptr result; + + /* Only IMAGE-lifetime virtual arrays are currently supported */ + if (pool_id != JPOOL_IMAGE) + ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ + + /* get control block */ + result = (jvirt_barray_ptr) alloc_small(cinfo, pool_id, + SIZEOF(struct jvirt_barray_control)); + + result->mem_buffer = NULL; /* marks array not yet realized */ + result->rows_in_array = numrows; + result->blocksperrow = blocksperrow; + result->maxaccess = maxaccess; + result->pre_zero = pre_zero; + result->b_s_open = FALSE; /* no associated backing-store object */ + result->next = mem->virt_barray_list; /* add to list of virtual arrays */ + mem->virt_barray_list = result; + + return result; +} + + +METHODDEF(void) +realize_virt_arrays (j_common_ptr cinfo) +/* Allocate the in-memory buffers for any unrealized virtual arrays */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + long space_per_minheight, maximum_space, avail_mem; + long minheights, max_minheights; + jvirt_sarray_ptr sptr; + jvirt_barray_ptr bptr; + + /* Compute the minimum space needed (maxaccess rows in each buffer) + * and the maximum space needed (full image height in each buffer). + * These may be of use to the system-dependent jpeg_mem_available routine. + */ + space_per_minheight = 0; + maximum_space = 0; + for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) { + if (sptr->mem_buffer == NULL) { /* if not realized yet */ + space_per_minheight += (long) sptr->maxaccess * + (long) sptr->samplesperrow * SIZEOF(JSAMPLE); + maximum_space += (long) sptr->rows_in_array * + (long) sptr->samplesperrow * SIZEOF(JSAMPLE); + } + } + for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) { + if (bptr->mem_buffer == NULL) { /* if not realized yet */ + space_per_minheight += (long) bptr->maxaccess * + (long) bptr->blocksperrow * SIZEOF(JBLOCK); + maximum_space += (long) bptr->rows_in_array * + (long) bptr->blocksperrow * SIZEOF(JBLOCK); + } + } + + if (space_per_minheight <= 0) + return; /* no unrealized arrays, no work */ + + /* Determine amount of memory to actually use; this is system-dependent. */ + avail_mem = jpeg_mem_available(cinfo, space_per_minheight, maximum_space, + mem->total_space_allocated); + + /* If the maximum space needed is available, make all the buffers full + * height; otherwise parcel it out with the same number of minheights + * in each buffer. + */ + if (avail_mem >= maximum_space) + max_minheights = 1000000000L; + else { + max_minheights = avail_mem / space_per_minheight; + /* If there doesn't seem to be enough space, try to get the minimum + * anyway. This allows a "stub" implementation of jpeg_mem_available(). + */ + if (max_minheights <= 0) + max_minheights = 1; + } + + /* Allocate the in-memory buffers and initialize backing store as needed. */ + + for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) { + if (sptr->mem_buffer == NULL) { /* if not realized yet */ + minheights = ((long) sptr->rows_in_array - 1L) / sptr->maxaccess + 1L; + if (minheights <= max_minheights) { + /* This buffer fits in memory */ + sptr->rows_in_mem = sptr->rows_in_array; + } else { + /* It doesn't fit in memory, create backing store. */ + sptr->rows_in_mem = (JDIMENSION) (max_minheights * sptr->maxaccess); + jpeg_open_backing_store(cinfo, & sptr->b_s_info, + (long) sptr->rows_in_array * + (long) sptr->samplesperrow * + (long) SIZEOF(JSAMPLE)); + sptr->b_s_open = TRUE; + } + sptr->mem_buffer = alloc_sarray(cinfo, JPOOL_IMAGE, + sptr->samplesperrow, sptr->rows_in_mem); + sptr->rowsperchunk = mem->last_rowsperchunk; + sptr->cur_start_row = 0; + sptr->first_undef_row = 0; + sptr->dirty = FALSE; + } + } + + for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) { + if (bptr->mem_buffer == NULL) { /* if not realized yet */ + minheights = ((long) bptr->rows_in_array - 1L) / bptr->maxaccess + 1L; + if (minheights <= max_minheights) { + /* This buffer fits in memory */ + bptr->rows_in_mem = bptr->rows_in_array; + } else { + /* It doesn't fit in memory, create backing store. */ + bptr->rows_in_mem = (JDIMENSION) (max_minheights * bptr->maxaccess); + jpeg_open_backing_store(cinfo, & bptr->b_s_info, + (long) bptr->rows_in_array * + (long) bptr->blocksperrow * + (long) SIZEOF(JBLOCK)); + bptr->b_s_open = TRUE; + } + bptr->mem_buffer = alloc_barray(cinfo, JPOOL_IMAGE, + bptr->blocksperrow, bptr->rows_in_mem); + bptr->rowsperchunk = mem->last_rowsperchunk; + bptr->cur_start_row = 0; + bptr->first_undef_row = 0; + bptr->dirty = FALSE; + } + } +} + + +LOCAL(void) +do_sarray_io (j_common_ptr cinfo, jvirt_sarray_ptr ptr, boolean writing) +/* Do backing store read or write of a virtual sample array */ +{ + long bytesperrow, file_offset, byte_count, rows, thisrow, i; + + bytesperrow = (long) ptr->samplesperrow * SIZEOF(JSAMPLE); + file_offset = ptr->cur_start_row * bytesperrow; + /* Loop to read or write each allocation chunk in mem_buffer */ + for (i = 0; i < (long) ptr->rows_in_mem; i += ptr->rowsperchunk) { + /* One chunk, but check for short chunk at end of buffer */ + rows = MIN((long) ptr->rowsperchunk, (long) ptr->rows_in_mem - i); + /* Transfer no more than is currently defined */ + thisrow = (long) ptr->cur_start_row + i; + rows = MIN(rows, (long) ptr->first_undef_row - thisrow); + /* Transfer no more than fits in file */ + rows = MIN(rows, (long) ptr->rows_in_array - thisrow); + if (rows <= 0) /* this chunk might be past end of file! */ + break; + byte_count = rows * bytesperrow; + if (writing) + (*ptr->b_s_info.write_backing_store) (cinfo, & ptr->b_s_info, + (void FAR *) ptr->mem_buffer[i], + file_offset, byte_count); + else + (*ptr->b_s_info.read_backing_store) (cinfo, & ptr->b_s_info, + (void FAR *) ptr->mem_buffer[i], + file_offset, byte_count); + file_offset += byte_count; + } +} + + +LOCAL(void) +do_barray_io (j_common_ptr cinfo, jvirt_barray_ptr ptr, boolean writing) +/* Do backing store read or write of a virtual coefficient-block array */ +{ + long bytesperrow, file_offset, byte_count, rows, thisrow, i; + + bytesperrow = (long) ptr->blocksperrow * SIZEOF(JBLOCK); + file_offset = ptr->cur_start_row * bytesperrow; + /* Loop to read or write each allocation chunk in mem_buffer */ + for (i = 0; i < (long) ptr->rows_in_mem; i += ptr->rowsperchunk) { + /* One chunk, but check for short chunk at end of buffer */ + rows = MIN((long) ptr->rowsperchunk, (long) ptr->rows_in_mem - i); + /* Transfer no more than is currently defined */ + thisrow = (long) ptr->cur_start_row + i; + rows = MIN(rows, (long) ptr->first_undef_row - thisrow); + /* Transfer no more than fits in file */ + rows = MIN(rows, (long) ptr->rows_in_array - thisrow); + if (rows <= 0) /* this chunk might be past end of file! */ + break; + byte_count = rows * bytesperrow; + if (writing) + (*ptr->b_s_info.write_backing_store) (cinfo, & ptr->b_s_info, + (void FAR *) ptr->mem_buffer[i], + file_offset, byte_count); + else + (*ptr->b_s_info.read_backing_store) (cinfo, & ptr->b_s_info, + (void FAR *) ptr->mem_buffer[i], + file_offset, byte_count); + file_offset += byte_count; + } +} + + +METHODDEF(JSAMPARRAY) +access_virt_sarray (j_common_ptr cinfo, jvirt_sarray_ptr ptr, + JDIMENSION start_row, JDIMENSION num_rows, + boolean writable) +/* Access the part of a virtual sample array starting at start_row */ +/* and extending for num_rows rows. writable is true if */ +/* caller intends to modify the accessed area. */ +{ + JDIMENSION end_row = start_row + num_rows; + JDIMENSION undef_row; + + /* debugging check */ + if (end_row > ptr->rows_in_array || num_rows > ptr->maxaccess || + ptr->mem_buffer == NULL) + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + + /* Make the desired part of the virtual array accessible */ + if (start_row < ptr->cur_start_row || + end_row > ptr->cur_start_row+ptr->rows_in_mem) { + if (! ptr->b_s_open) + ERREXIT(cinfo, JERR_VIRTUAL_BUG); + /* Flush old buffer contents if necessary */ + if (ptr->dirty) { + do_sarray_io(cinfo, ptr, TRUE); + ptr->dirty = FALSE; + } + /* Decide what part of virtual array to access. + * Algorithm: if target address > current window, assume forward scan, + * load starting at target address. If target address < current window, + * assume backward scan, load so that target area is top of window. + * Note that when switching from forward write to forward read, will have + * start_row = 0, so the limiting case applies and we load from 0 anyway. + */ + if (start_row > ptr->cur_start_row) { + ptr->cur_start_row = start_row; + } else { + /* use long arithmetic here to avoid overflow & unsigned problems */ + long ltemp; + + ltemp = (long) end_row - (long) ptr->rows_in_mem; + if (ltemp < 0) + ltemp = 0; /* don't fall off front end of file */ + ptr->cur_start_row = (JDIMENSION) ltemp; + } + /* Read in the selected part of the array. + * During the initial write pass, we will do no actual read + * because the selected part is all undefined. + */ + do_sarray_io(cinfo, ptr, FALSE); + } + /* Ensure the accessed part of the array is defined; prezero if needed. + * To improve locality of access, we only prezero the part of the array + * that the caller is about to access, not the entire in-memory array. + */ + if (ptr->first_undef_row < end_row) { + if (ptr->first_undef_row < start_row) { + if (writable) /* writer skipped over a section of array */ + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + undef_row = start_row; /* but reader is allowed to read ahead */ + } else { + undef_row = ptr->first_undef_row; + } + if (writable) + ptr->first_undef_row = end_row; + if (ptr->pre_zero) { + size_t bytesperrow = (size_t) ptr->samplesperrow * SIZEOF(JSAMPLE); + undef_row -= ptr->cur_start_row; /* make indexes relative to buffer */ + end_row -= ptr->cur_start_row; + while (undef_row < end_row) { + jzero_far((void FAR *) ptr->mem_buffer[undef_row], bytesperrow); + undef_row++; + } + } else { + if (! writable) /* reader looking at undefined data */ + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + } + } + /* Flag the buffer dirty if caller will write in it */ + if (writable) + ptr->dirty = TRUE; + /* Return address of proper part of the buffer */ + return ptr->mem_buffer + (start_row - ptr->cur_start_row); +} + + +METHODDEF(JBLOCKARRAY) +access_virt_barray (j_common_ptr cinfo, jvirt_barray_ptr ptr, + JDIMENSION start_row, JDIMENSION num_rows, + boolean writable) +/* Access the part of a virtual block array starting at start_row */ +/* and extending for num_rows rows. writable is true if */ +/* caller intends to modify the accessed area. */ +{ + JDIMENSION end_row = start_row + num_rows; + JDIMENSION undef_row; + + /* debugging check */ + if (end_row > ptr->rows_in_array || num_rows > ptr->maxaccess || + ptr->mem_buffer == NULL) + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + + /* Make the desired part of the virtual array accessible */ + if (start_row < ptr->cur_start_row || + end_row > ptr->cur_start_row+ptr->rows_in_mem) { + if (! ptr->b_s_open) + ERREXIT(cinfo, JERR_VIRTUAL_BUG); + /* Flush old buffer contents if necessary */ + if (ptr->dirty) { + do_barray_io(cinfo, ptr, TRUE); + ptr->dirty = FALSE; + } + /* Decide what part of virtual array to access. + * Algorithm: if target address > current window, assume forward scan, + * load starting at target address. If target address < current window, + * assume backward scan, load so that target area is top of window. + * Note that when switching from forward write to forward read, will have + * start_row = 0, so the limiting case applies and we load from 0 anyway. + */ + if (start_row > ptr->cur_start_row) { + ptr->cur_start_row = start_row; + } else { + /* use long arithmetic here to avoid overflow & unsigned problems */ + long ltemp; + + ltemp = (long) end_row - (long) ptr->rows_in_mem; + if (ltemp < 0) + ltemp = 0; /* don't fall off front end of file */ + ptr->cur_start_row = (JDIMENSION) ltemp; + } + /* Read in the selected part of the array. + * During the initial write pass, we will do no actual read + * because the selected part is all undefined. + */ + do_barray_io(cinfo, ptr, FALSE); + } + /* Ensure the accessed part of the array is defined; prezero if needed. + * To improve locality of access, we only prezero the part of the array + * that the caller is about to access, not the entire in-memory array. + */ + if (ptr->first_undef_row < end_row) { + if (ptr->first_undef_row < start_row) { + if (writable) /* writer skipped over a section of array */ + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + undef_row = start_row; /* but reader is allowed to read ahead */ + } else { + undef_row = ptr->first_undef_row; + } + if (writable) + ptr->first_undef_row = end_row; + if (ptr->pre_zero) { + size_t bytesperrow = (size_t) ptr->blocksperrow * SIZEOF(JBLOCK); + undef_row -= ptr->cur_start_row; /* make indexes relative to buffer */ + end_row -= ptr->cur_start_row; + while (undef_row < end_row) { + jzero_far((void FAR *) ptr->mem_buffer[undef_row], bytesperrow); + undef_row++; + } + } else { + if (! writable) /* reader looking at undefined data */ + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + } + } + /* Flag the buffer dirty if caller will write in it */ + if (writable) + ptr->dirty = TRUE; + /* Return address of proper part of the buffer */ + return ptr->mem_buffer + (start_row - ptr->cur_start_row); +} + + +/* + * Release all objects belonging to a specified pool. + */ + +METHODDEF(void) +free_pool (j_common_ptr cinfo, int pool_id) +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + small_pool_ptr shdr_ptr; + large_pool_ptr lhdr_ptr; + size_t space_freed; + + if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS) + ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ + +#ifdef MEM_STATS + if (cinfo->err->trace_level > 1) + print_mem_stats(cinfo, pool_id); /* print pool's memory usage statistics */ +#endif + + /* If freeing IMAGE pool, close any virtual arrays first */ + if (pool_id == JPOOL_IMAGE) { + jvirt_sarray_ptr sptr; + jvirt_barray_ptr bptr; + + for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) { + if (sptr->b_s_open) { /* there may be no backing store */ + sptr->b_s_open = FALSE; /* prevent recursive close if error */ + (*sptr->b_s_info.close_backing_store) (cinfo, & sptr->b_s_info); + } + } + mem->virt_sarray_list = NULL; + for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) { + if (bptr->b_s_open) { /* there may be no backing store */ + bptr->b_s_open = FALSE; /* prevent recursive close if error */ + (*bptr->b_s_info.close_backing_store) (cinfo, & bptr->b_s_info); + } + } + mem->virt_barray_list = NULL; + } + + /* Release large objects */ + lhdr_ptr = mem->large_list[pool_id]; + mem->large_list[pool_id] = NULL; + + while (lhdr_ptr != NULL) { + large_pool_ptr next_lhdr_ptr = lhdr_ptr->hdr.next; + space_freed = lhdr_ptr->hdr.bytes_used + + lhdr_ptr->hdr.bytes_left + + SIZEOF(large_pool_hdr); + jpeg_free_large(cinfo, (void FAR *) lhdr_ptr, space_freed); + mem->total_space_allocated -= space_freed; + lhdr_ptr = next_lhdr_ptr; + } + + /* Release small objects */ + shdr_ptr = mem->small_list[pool_id]; + mem->small_list[pool_id] = NULL; + + while (shdr_ptr != NULL) { + small_pool_ptr next_shdr_ptr = shdr_ptr->hdr.next; + space_freed = shdr_ptr->hdr.bytes_used + + shdr_ptr->hdr.bytes_left + + SIZEOF(small_pool_hdr); + jpeg_free_small(cinfo, (void *) shdr_ptr, space_freed); + mem->total_space_allocated -= space_freed; + shdr_ptr = next_shdr_ptr; + } +} + + +/* + * Close up shop entirely. + * Note that this cannot be called unless cinfo->mem is non-NULL. + */ + +METHODDEF(void) +self_destruct (j_common_ptr cinfo) +{ + int pool; + + /* Close all backing store, release all memory. + * Releasing pools in reverse order might help avoid fragmentation + * with some (brain-damaged) malloc libraries. + */ + for (pool = JPOOL_NUMPOOLS-1; pool >= JPOOL_PERMANENT; pool--) { + free_pool(cinfo, pool); + } + + /* Release the memory manager control block too. */ + jpeg_free_small(cinfo, (void *) cinfo->mem, SIZEOF(my_memory_mgr)); + cinfo->mem = NULL; /* ensures I will be called only once */ + + jpeg_mem_term(cinfo); /* system-dependent cleanup */ +} + + +/* + * Memory manager initialization. + * When this is called, only the error manager pointer is valid in cinfo! + */ + +GLOBAL(void) +jinit_memory_mgr (j_common_ptr cinfo) +{ + my_mem_ptr mem; + long max_to_use; + int pool; + size_t test_mac; + + cinfo->mem = NULL; /* for safety if init fails */ + + /* Check for configuration errors. + * SIZEOF(ALIGN_TYPE) should be a power of 2; otherwise, it probably + * doesn't reflect any real hardware alignment requirement. + * The test is a little tricky: for X>0, X and X-1 have no one-bits + * in common if and only if X is a power of 2, ie has only one one-bit. + * Some compilers may give an "unreachable code" warning here; ignore it. + */ + if ((SIZEOF(ALIGN_TYPE) & (SIZEOF(ALIGN_TYPE)-1)) != 0) + ERREXIT(cinfo, JERR_BAD_ALIGN_TYPE); + /* MAX_ALLOC_CHUNK must be representable as type size_t, and must be + * a multiple of SIZEOF(ALIGN_TYPE). + * Again, an "unreachable code" warning may be ignored here. + * But a "constant too large" warning means you need to fix MAX_ALLOC_CHUNK. + */ + test_mac = (size_t) MAX_ALLOC_CHUNK; + if ((long) test_mac != MAX_ALLOC_CHUNK || + (MAX_ALLOC_CHUNK % SIZEOF(ALIGN_TYPE)) != 0) + ERREXIT(cinfo, JERR_BAD_ALLOC_CHUNK); + + max_to_use = jpeg_mem_init(cinfo); /* system-dependent initialization */ + + /* Attempt to allocate memory manager's control block */ + mem = (my_mem_ptr) jpeg_get_small(cinfo, SIZEOF(my_memory_mgr)); + + if (mem == NULL) { + jpeg_mem_term(cinfo); /* system-dependent cleanup */ + ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 0); + } + + /* OK, fill in the method pointers */ + mem->pub.alloc_small = alloc_small; + mem->pub.alloc_large = alloc_large; + mem->pub.alloc_sarray = alloc_sarray; + mem->pub.alloc_barray = alloc_barray; +#ifdef NEED_DARRAY + mem->pub.alloc_darray = alloc_darray; +#endif + mem->pub.request_virt_sarray = request_virt_sarray; + mem->pub.request_virt_barray = request_virt_barray; + mem->pub.realize_virt_arrays = realize_virt_arrays; + mem->pub.access_virt_sarray = access_virt_sarray; + mem->pub.access_virt_barray = access_virt_barray; + mem->pub.free_pool = free_pool; + mem->pub.self_destruct = self_destruct; + + /* Make MAX_ALLOC_CHUNK accessible to other modules */ + mem->pub.max_alloc_chunk = MAX_ALLOC_CHUNK; + + /* Initialize working state */ + mem->pub.max_memory_to_use = max_to_use; + + for (pool = JPOOL_NUMPOOLS-1; pool >= JPOOL_PERMANENT; pool--) { + mem->small_list[pool] = NULL; + mem->large_list[pool] = NULL; + } + mem->virt_sarray_list = NULL; + mem->virt_barray_list = NULL; + + mem->total_space_allocated = SIZEOF(my_memory_mgr); + + /* Declare ourselves open for business */ + cinfo->mem = & mem->pub; + + /* Check for an environment variable JPEGMEM; if found, override the + * default max_memory setting from jpeg_mem_init. Note that the + * surrounding application may again override this value. + * If your system doesn't support getenv(), define NO_GETENV to disable + * this feature. + */ +#ifndef NO_GETENV + { char * memenv; + + if ((memenv = getenv("JPEGMEM")) != NULL) { + char ch = 'x'; + + if (sscanf(memenv, "%ld%c", &max_to_use, &ch) > 0) { + if (ch == 'm' || ch == 'M') + max_to_use *= 1000L; + mem->pub.max_memory_to_use = max_to_use * 1000L; + } + } + } +#endif + +} diff --git a/gdcm/Utilities/gdcmjpeg/jmemnobs.c b/gdcm/Utilities/gdcmjpeg/jmemnobs.c new file mode 100644 index 0000000..6757d4b --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jmemnobs.c @@ -0,0 +1,117 @@ +/* + * jmemnobs.c + * + * Copyright (C) 1992-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file provides a really simple implementation of the system- + * dependent portion of the JPEG memory manager. This implementation + * assumes that no backing-store files are needed: all required space + * can be obtained from malloc(). + * This is very portable in the sense that it'll compile on almost anything, + * but you'd better have lots of main memory (or virtual memory) if you want + * to process big images. + * Note that the max_memory_to_use option is ignored by this implementation. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jmemsys.h" /* import the system-dependent declarations */ + +#ifndef HAVE_STDLIB_H /* should declare malloc(),free() */ +extern void * malloc JPP((size_t size)); +extern void free JPP((void *ptr)); +#endif + + +/* + * Memory allocation and freeing are controlled by the regular library + * routines malloc() and free(). + */ + +GLOBAL(void *) +jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject) +{ + (void)cinfo; + return (void *) malloc(sizeofobject); +} + +GLOBAL(void) +jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject) +{ + (void)cinfo;(void)sizeofobject; + free(object); +} + + +/* + * "Large" objects are treated the same as "small" ones. + * NB: although we include FAR keywords in the routine declarations, + * this file won't actually work in 80x86 small/medium model; at least, + * you probably won't be able to process useful-size images in only 64KB. + */ + +GLOBAL(void FAR *) +jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject) +{ + (void)cinfo; + return (void FAR *) malloc(sizeofobject); +} + +GLOBAL(void) +jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject) +{ + (void)cinfo;(void)sizeofobject; + free(object); +} + + +/* + * This routine computes the total memory space available for allocation. + * Here we always say, "we got all you want bud!" + */ + +GLOBAL(long) +jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed, + long max_bytes_needed, long already_allocated) +{ + (void)cinfo;(void)min_bytes_needed;(void)already_allocated; + return max_bytes_needed; +} + + +/* + * Backing store (temporary file) management. + * Since jpeg_mem_available always promised the moon, + * this should never be called and we can just error out. + */ + +GLOBAL(void) +jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info, + long total_bytes_needed) +{ + (void)info;(void)total_bytes_needed; + ERREXIT(cinfo, JERR_NO_BACKING_STORE); +} + + +/* + * These routines take care of any system-dependent initialization and + * cleanup required. Here, there isn't any. + */ + +GLOBAL(long) +jpeg_mem_init (j_common_ptr cinfo) +{ + (void)cinfo; + return 0; /* just set max_memory_to_use to 0 */ +} + +GLOBAL(void) +jpeg_mem_term (j_common_ptr cinfo) +{ + (void)cinfo; + /* no work */ +} diff --git a/gdcm/Utilities/gdcmjpeg/jmemsrc.c b/gdcm/Utilities/gdcmjpeg/jmemsrc.c new file mode 100644 index 0000000..3045bae --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jmemsrc.c @@ -0,0 +1,173 @@ +/* + * jmemsrc.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains decompression data source routines for the case of + * reading JPEG data from a memory buffer that is preloaded with the entire + * JPEG file. This would not seem especially useful at first sight, but + * a number of people have asked for it. + * This is really just a stripped-down version of jdatasrc.c. Comparison + * of this code with jdatasrc.c may be helpful in seeing how to make + * custom source managers for other purposes. + */ + +/* code was taken from: + * [How to read JPEG resource using JpegLib ?] + * http://www.smalleranimals.com/vforum/archive/index.php?t-1922.html + */ + +/* this is not a core library module, so it doesn't define JPEG_INTERNALS */ +#include "jinclude.h" +#include "jpeglib.h" +#include "jerror.h" + + +/* Expanded data source object for memory input */ + +/** + * \brief very low level C 'structure', used to decode jpeg file + * Should not appear in the Doxygen supplied documentation + */ +typedef struct { + struct jpeg_source_mgr pub; /* public fields */ + JOCTET eoi_buffer[2]; /* a place to put a dummy EOI */ +} my_source_mgr; + +typedef my_source_mgr * my_src_ptr; + + +/* + * Initialize source --- called by jpeg_read_header + * before any data is actually read. + */ + +METHODDEF(void) +init_source (j_decompress_ptr cinfo) +{ + /* No work, since jpeg_memory_src set up the buffer pointer and count. + * Indeed, if we want to read multiple JPEG images from one buffer, + * this *must* not do anything to the pointer. + */ + (void)cinfo; +} + + +/* + * Fill the input buffer --- called whenever buffer is emptied. + * + * In this application, this routine should never be called; if it is called, + * the decompressor has overrun the end of the input buffer, implying we + * supplied an incomplete or corrupt JPEG datastream. A simple error exit + * might be the most appropriate response. + * + * But what we choose to do in this code is to supply dummy EOI markers + * in order to force the decompressor to finish processing and supply + * some sort of output image, no matter how corrupted. + */ + +METHODDEF(boolean) +fill_input_buffer (j_decompress_ptr cinfo) +{ + my_src_ptr src = (my_src_ptr) cinfo->src; + + WARNMS(cinfo, JWRN_JPEG_EOF); + + /* Create a fake EOI marker */ + src->eoi_buffer[0] = (JOCTET) 0xFF; + src->eoi_buffer[1] = (JOCTET) JPEG_EOI; + src->pub.next_input_byte = src->eoi_buffer; + src->pub.bytes_in_buffer = 2; + + return TRUE; +} + + +/* + * Skip data --- used to skip over a potentially large amount of + * uninteresting data (such as an APPn marker). + * + * If we overrun the end of the buffer, we let fill_input_buffer deal with + * it. An extremely large skip could cause some time-wasting here, but + * it really isn't supposed to happen ... and the decompressor will never + * skip more than 64K anyway. + */ + +METHODDEF(void) +skip_input_data (j_decompress_ptr cinfo, long num_bytes) +{ + my_src_ptr src = (my_src_ptr) cinfo->src; + + if (num_bytes > 0) { + while (num_bytes > (long) src->pub.bytes_in_buffer) { + num_bytes -= (long) src->pub.bytes_in_buffer; + (void) fill_input_buffer(cinfo); + /* note we assume that fill_input_buffer will never return FALSE, + * so suspension need not be handled. + */ + } + src->pub.next_input_byte += (size_t) num_bytes; + src->pub.bytes_in_buffer -= (size_t) num_bytes; + } +} + + +/* + * An additional method that can be provided by data source modules is the + * resync_to_restart method for error recovery in the presence of RST markers. + * For the moment, this source module just uses the default resync method + * provided by the JPEG library. That method assumes that no backtracking + * is possible. + */ + + +/* + * Terminate source --- called by jpeg_finish_decompress + * after all data has been read. Often a no-op. + * + * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding + * application must deal with any cleanup that should happen even + * for error exit. + */ + +METHODDEF(void) +term_source (j_decompress_ptr cinfo) +{ + /* no work necessary here */ + (void)cinfo; +} + + +/* + * Prepare for input from a memory buffer. + */ + +GLOBAL(void) +jpeg_memory_src (j_decompress_ptr cinfo, const JOCTET * buffer, size_t bufsize) +{ + my_src_ptr src; + + /* The source object is made permanent so that a series of JPEG images + * can be read from a single buffer by calling jpeg_memory_src + * only before the first one. + * This makes it unsafe to use this manager and a different source + * manager serially with the same JPEG object. Caveat programmer. + */ + if (cinfo->src == NULL) { /* first time for this JPEG object? */ + cinfo->src = (struct jpeg_source_mgr *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + SIZEOF(my_source_mgr)); + } + + src = (my_src_ptr) cinfo->src; + src->pub.init_source = init_source; + src->pub.fill_input_buffer = fill_input_buffer; + src->pub.skip_input_data = skip_input_data; + src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ + src->pub.term_source = term_source; + + src->pub.next_input_byte = buffer; + src->pub.bytes_in_buffer = bufsize; +} diff --git a/gdcm/Utilities/gdcmjpeg/jmemsys.h b/gdcm/Utilities/gdcmjpeg/jmemsys.h new file mode 100644 index 0000000..2e8ee7e --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jmemsys.h @@ -0,0 +1,198 @@ +/* + * jmemsys.h + * + * Copyright (C) 1992-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This include file defines the interface between the system-independent + * and system-dependent portions of the JPEG memory manager. No other + * modules need include it. (The system-independent portion is jmemmgr.c; + * there are several different versions of the system-dependent portion.) + * + * This file works as-is for the system-dependent memory managers supplied + * in the IJG distribution. You may need to modify it if you write a + * custom memory manager. If system-dependent changes are needed in + * this file, the best method is to #ifdef them based on a configuration + * symbol supplied in jconfig.h, as we have done with USE_MSDOS_MEMMGR + * and USE_MAC_MEMMGR. + */ + + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_get_small jGetSmall +#define jpeg_free_small jFreeSmall +#define jpeg_get_large jGetLarge +#define jpeg_free_large jFreeLarge +#define jpeg_mem_available jMemAvail +#define jpeg_open_backing_store jOpenBackStore +#define jpeg_mem_init jMemInit +#define jpeg_mem_term jMemTerm +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* + * These two functions are used to allocate and release small chunks of + * memory. (Typically the total amount requested through jpeg_get_small is + * no more than 20K or so; this will be requested in chunks of a few K each.) + * Behavior should be the same as for the standard library functions malloc + * and free; in particular, jpeg_get_small must return NULL on failure. + * On most systems, these ARE malloc and free. jpeg_free_small is passed the + * size of the object being freed, just in case it's needed. + * On an 80x86 machine using small-data memory model, these manage near heap. + */ + +EXTERN(void *) jpeg_get_small JPP((j_common_ptr cinfo, size_t sizeofobject)); +EXTERN(void) jpeg_free_small JPP((j_common_ptr cinfo, void * object, + size_t sizeofobject)); + +/* + * These two functions are used to allocate and release large chunks of + * memory (up to the total free space designated by jpeg_mem_available). + * The interface is the same as above, except that on an 80x86 machine, + * far pointers are used. On most other machines these are identical to + * the jpeg_get/free_small routines; but we keep them separate anyway, + * in case a different allocation strategy is desirable for large chunks. + */ + +EXTERN(void FAR *) jpeg_get_large JPP((j_common_ptr cinfo, + size_t sizeofobject)); +EXTERN(void) jpeg_free_large JPP((j_common_ptr cinfo, void FAR * object, + size_t sizeofobject)); + +/* + * The macro MAX_ALLOC_CHUNK designates the maximum number of bytes that may + * be requested in a single call to jpeg_get_large (and jpeg_get_small for that + * matter, but that case should never come into play). This macro is needed + * to model the 64Kb-segment-size limit of far addressing on 80x86 machines. + * On those machines, we expect that jconfig.h will provide a proper value. + * On machines with 32-bit flat address spaces, any large constant may be used. + * + * NB: jmemmgr.c expects that MAX_ALLOC_CHUNK will be representable as type + * size_t and will be a multiple of sizeof(align_type). + */ + +#ifndef MAX_ALLOC_CHUNK /* may be overridden in jconfig.h */ +#define MAX_ALLOC_CHUNK 1000000000L +#endif + +/* + * This routine computes the total space still available for allocation by + * jpeg_get_large. If more space than this is needed, backing store will be + * used. NOTE: any memory already allocated must not be counted. + * + * There is a minimum space requirement, corresponding to the minimum + * feasible buffer sizes; jmemmgr.c will request that much space even if + * jpeg_mem_available returns zero. The maximum space needed, enough to hold + * all working storage in memory, is also passed in case it is useful. + * Finally, the total space already allocated is passed. If no better + * method is available, cinfo->mem->max_memory_to_use - already_allocated + * is often a suitable calculation. + * + * It is OK for jpeg_mem_available to underestimate the space available + * (that'll just lead to more backing-store access than is really necessary). + * However, an overestimate will lead to failure. Hence it's wise to subtract + * a slop factor from the true available space. 5% should be enough. + * + * On machines with lots of virtual memory, any large constant may be returned. + * Conversely, zero may be returned to always use the minimum amount of memory. + */ + +EXTERN(long) jpeg_mem_available JPP((j_common_ptr cinfo, + long min_bytes_needed, + long max_bytes_needed, + long already_allocated)); + + +/* + * This structure holds whatever state is needed to access a single + * backing-store object. The read/write/close method pointers are called + * by jmemmgr.c to manipulate the backing-store object; all other fields + * are private to the system-dependent backing store routines. + */ + +#define TEMP_NAME_LENGTH 64 /* max length of a temporary file's name */ + + +#ifdef USE_MSDOS_MEMMGR /* DOS-specific junk */ + +typedef unsigned short XMSH; /* type of extended-memory handles */ +typedef unsigned short EMSH; /* type of expanded-memory handles */ + +typedef union { + short file_handle; /* DOS file handle if it's a temp file */ + XMSH xms_handle; /* handle if it's a chunk of XMS */ + EMSH ems_handle; /* handle if it's a chunk of EMS */ +} handle_union; + +#endif /* USE_MSDOS_MEMMGR */ + +#ifdef USE_MAC_MEMMGR /* Mac-specific junk */ +#include +#endif /* USE_MAC_MEMMGR */ + + +typedef struct backing_store_struct * backing_store_ptr; + +typedef struct backing_store_struct { + /* Methods for reading/writing/closing this backing-store object */ + JMETHOD(void, read_backing_store, (j_common_ptr cinfo, + backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count)); + JMETHOD(void, write_backing_store, (j_common_ptr cinfo, + backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count)); + JMETHOD(void, close_backing_store, (j_common_ptr cinfo, + backing_store_ptr info)); + + /* Private fields for system-dependent backing-store management */ +#ifdef USE_MSDOS_MEMMGR + /* For the MS-DOS manager (jmemdos.c), we need: */ + handle_union handle; /* reference to backing-store storage object */ + char temp_name[TEMP_NAME_LENGTH]; /* name if it's a file */ +#else +#ifdef USE_MAC_MEMMGR + /* For the Mac manager (jmemmac.c), we need: */ + short temp_file; /* file reference number to temp file */ + FSSpec tempSpec; /* the FSSpec for the temp file */ + char temp_name[TEMP_NAME_LENGTH]; /* name if it's a file */ +#else + /* For a typical implementation with temp files, we need: */ + FILE * temp_file; /* stdio reference to temp file */ + char temp_name[TEMP_NAME_LENGTH]; /* name of temp file */ +#endif +#endif +} backing_store_info; + + +/* + * Initial opening of a backing-store object. This must fill in the + * read/write/close pointers in the object. The read/write routines + * may take an error exit if the specified maximum file size is exceeded. + * (If jpeg_mem_available always returns a large value, this routine can + * just take an error exit.) + */ + +EXTERN(void) jpeg_open_backing_store JPP((j_common_ptr cinfo, + backing_store_ptr info, + long total_bytes_needed)); + + +/* + * These routines take care of any system-dependent initialization and + * cleanup required. jpeg_mem_init will be called before anything is + * allocated (and, therefore, nothing in cinfo is of use except the error + * manager pointer). It should return a suitable default value for + * max_memory_to_use; this may subsequently be overridden by the surrounding + * application. (Note that max_memory_to_use is only important if + * jpeg_mem_available chooses to consult it ... no one else will.) + * jpeg_mem_term may assume that all requested memory has been freed and that + * all opened backing-store objects have been closed. + */ + +EXTERN(long) jpeg_mem_init JPP((j_common_ptr cinfo)); +EXTERN(void) jpeg_mem_term JPP((j_common_ptr cinfo)); diff --git a/gdcm/Utilities/gdcmjpeg/jmorecfg.h b/gdcm/Utilities/gdcmjpeg/jmorecfg.h new file mode 100644 index 0000000..f6b7c75 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jmorecfg.h @@ -0,0 +1,424 @@ +/* + * jmorecfg.h + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains additional configuration options that customize the + * JPEG software for special applications or support machine-dependent + * optimizations. Most users will not need to touch this file. + */ + +/* + * Define BITS_IN_JSAMPLE as either + * 8 for 8-bit sample values (the usual setting) + * 12 for 12-bit sample values + * Only 8 and 12 are legal data precisions for lossy JPEG according to the + * JPEG standard, and the IJG code does not support anything else! + * We do not support run-time selection of data precision, sorry. + */ + +/*#define BITS_IN_JSAMPLE 8*//* use 8 or 12 (or 16 only for lossless) */ +#ifndef BITS_IN_JSAMPLE +#error You need to define BITS_IN_JSAMPLE +#endif + +/* + * Maximum number of components (color channels) allowed in JPEG image. + * To meet the letter of the JPEG spec, set this to 255. However, darn + * few applications need more than 4 channels (maybe 5 for CMYK + alpha + * mask). We recommend 10 as a reasonable compromise; use 4 if you are + * really short on memory. (Each allowed component costs a hundred or so + * bytes of storage, whether actually used in an image or not.) + */ + +#define MAX_COMPONENTS 10 /* maximum number of image components */ + + +/* + * Basic data types. + * You may need to change these if you have a machine with unusual data + * type sizes; for example, "char" not 8 bits, "short" not 16 bits, + * or "long" not 32 bits. We don't care whether "int" is 16 or 32 bits, + * but it had better be at least 16. + */ + +/* Representation of a single sample (pixel element value). + * We frequently allocate large arrays of these, so it's important to keep + * them small. But if you have memory to burn and access to char or short + * arrays is very slow on your hardware, you might want to change these. + */ + +#if BITS_IN_JSAMPLE == 8 +/* JSAMPLE should be the smallest type that will hold the values 0..255. + * You can use a signed char by having GETJSAMPLE mask it with 0xFF. + */ + +#ifdef HAVE_UNSIGNED_CHAR + +typedef unsigned char JSAMPLE; +#define GETJSAMPLE(value) ((int) (value)) + +#else /* not HAVE_UNSIGNED_CHAR */ + +typedef char JSAMPLE; +#ifdef CHAR_IS_UNSIGNED +#define GETJSAMPLE(value) ((int) (value)) +#else +#define GETJSAMPLE(value) ((int) (value) & 0xFF) +#endif /* CHAR_IS_UNSIGNED */ + +#endif /* HAVE_UNSIGNED_CHAR */ + +#define MAXJSAMPLE 255 +#define CENTERJSAMPLE 128 + +#endif /* BITS_IN_JSAMPLE == 8 */ + + +#if BITS_IN_JSAMPLE == 12 +/* JSAMPLE should be the smallest type that will hold the values 0..4095. + * On nearly all machines "short" will do nicely. + */ + +typedef short JSAMPLE; +#define GETJSAMPLE(value) ((int) (value)) + +#define MAXJSAMPLE 4095 +#define CENTERJSAMPLE 2048 + +#endif /* BITS_IN_JSAMPLE == 12 */ + + +#if BITS_IN_JSAMPLE == 16 +/* JSAMPLE should be the smallest type that will hold the values 0..65535. + * You can use a signed short by having GETJSAMPLE mask it with 0xFFFF. + */ + +#ifdef HAVE_UNSIGNED_SHORT + +typedef unsigned short JSAMPLE; +#define GETJSAMPLE(value) ((int) (value)) + +#else /* not HAVE_UNSIGNED_SHORT */ + +typedef short JSAMPLE; +#ifdef SHORT_IS_UNSIGNED +#define GETJSAMPLE(value) ((int) (value)) +#else +#define GETJSAMPLE(value) ((int) (value) & 0xFFFF) +#endif /* SHORT_IS_UNSIGNED */ + +#endif /* HAVE_UNSIGNED_SHORT */ + +#define MAXJSAMPLE 65535 +#define CENTERJSAMPLE 32768 + +#endif /* BITS_IN_JSAMPLE == 16 */ + + +/* Representation of a DCT frequency coefficient. + * This should be a signed value of at least 16 bits; "short" is usually OK. + * Again, we allocate large arrays of these, but you can change to int + * if you have memory to burn and "short" is really slow. + */ + +typedef short JCOEF; + + +/* Representation of a spatial difference value. + * This should be a signed value of at least 16 bits; int is usually OK. + */ + +typedef int JDIFF; + + +/* Compressed datastreams are represented as arrays of JOCTET. + * These must be EXACTLY 8 bits wide, at least once they are written to + * external storage. Note that when using the stdio data source/destination + * managers, this is also the data type passed to fread/fwrite. + */ + +#ifdef HAVE_UNSIGNED_CHAR + +typedef unsigned char JOCTET; +#define GETJOCTET(value) (value) + +#else /* not HAVE_UNSIGNED_CHAR */ + +typedef char JOCTET; +#ifdef CHAR_IS_UNSIGNED +#define GETJOCTET(value) (value) +#else +#define GETJOCTET(value) ((value) & 0xFF) +#endif /* CHAR_IS_UNSIGNED */ + +#endif /* HAVE_UNSIGNED_CHAR */ + + +/* These typedefs are used for various table entries and so forth. + * They must be at least as wide as specified; but making them too big + * won't cost a huge amount of memory, so we don't provide special + * extraction code like we did for JSAMPLE. (In other words, these + * typedefs live at a different point on the speed/space tradeoff curve.) + */ + +/* UINT8 must hold at least the values 0..255. */ + +#ifdef HAVE_UNSIGNED_CHAR +typedef unsigned char UINT8; +#else /* not HAVE_UNSIGNED_CHAR */ +#ifdef CHAR_IS_UNSIGNED +typedef char UINT8; +#else /* not CHAR_IS_UNSIGNED */ +typedef short UINT8; +#endif /* CHAR_IS_UNSIGNED */ +#endif /* HAVE_UNSIGNED_CHAR */ + +/* UINT16 must hold at least the values 0..65535. */ + +#ifdef HAVE_UNSIGNED_SHORT +typedef unsigned short UINT16; +#else /* not HAVE_UNSIGNED_SHORT */ +typedef unsigned int UINT16; +#endif /* HAVE_UNSIGNED_SHORT */ + +/* INT16 must hold at least the values -32768..32767. */ + +#ifndef XMD_H /* X11/xmd.h correctly defines INT16 */ +typedef short INT16; +#endif + +/* INT32 must hold at least signed 32-bit values. */ +/* X11/xmd.h and basetsd.h correctly defines INT32 */ + +#if !defined(XMD_H) && !defined(_BASETSD_H_) +typedef int INT32; +#endif + +/* Datatype used for image dimensions. The JPEG standard only supports + * images up to 64K*64K due to 16-bit fields in SOF markers. Therefore + * "unsigned int" is sufficient on all machines. However, if you need to + * handle larger images and you don't mind deviating from the spec, you + * can change this datatype. + */ + +typedef unsigned int JDIMENSION; + +#define JPEG_MAX_DIMENSION 65500L /* a tad under 64K to prevent overflows */ + + +/* These macros are used in all function definitions and extern declarations. + * You could modify them if you need to change function linkage conventions; + * in particular, you'll need to do that to make the library a Windows DLL. + * Another application is to make all functions global for use with debuggers + * or code profilers that require it. + */ + +/* a function called through method pointers: */ +#define METHODDEF(type) static type +/* a function used only in its module: */ +#define LOCAL(type) static type +/* a function referenced thru EXTERNs: */ +#if defined( _WIN32 ) && defined (JPEGDLL) +#define GLOBAL(type) __declspec(dllexport) type +#else +#if __GNUC__ >= 4 +#define GLOBAL(type) __attribute__ ((visibility ("default"))) type +#else +#define GLOBAL(type) type +#endif +#endif + +/* a reference to a GLOBAL function: */ +#if defined(_WIN32) && !defined(JPEGSTATIC) +#ifdef JPEGDLL +/* Win32, building a dll */ +#define EXTERN(type) __declspec(dllexport) type +#else +/* Win32, not building a dll but using the dll */ +#define EXTERN(type) __declspec(dllimport) type +#endif +#else +/* not a Win32 system or building a static Win32 lib */ +#define EXTERN(type) extern type +#endif + + +/* This macro is used to declare a "method", that is, a function pointer. + * We want to supply prototype parameters if the compiler can cope. + * Note that the arglist parameter must be parenthesized! + * Again, you can customize this if you need special linkage keywords. + */ + +#ifdef HAVE_PROTOTYPES +#define JMETHOD(type,methodname,arglist) type (*methodname) arglist +#else +#define JMETHOD(type,methodname,arglist) type (*methodname) () +#endif + + +/* Here is the pseudo-keyword for declaring pointers that must be "far" + * on 80x86 machines. Most of the specialized coding for 80x86 is handled + * by just saying "FAR *" where such a pointer is needed. In a few places + * explicit coding is needed; see uses of the NEED_FAR_POINTERS symbol. + */ + +#ifndef FAR +#ifdef NEED_FAR_POINTERS +#define FAR far +#else +#define FAR +#endif +#endif + + +/* + * On a few systems, type boolean and/or its values FALSE, TRUE may appear + * in standard header files. Or you may have conflicts with application- + * specific header files that you want to include together with these files. + * Defining HAVE_BOOLEAN before including jpeglib.h should make it work. + */ + +#ifndef HAVE_BOOLEAN +typedef int boolean; +#endif +#ifndef FALSE /* in case these macros already exist */ +#define FALSE 0 /* values of boolean */ +#endif +#ifndef TRUE +#define TRUE 1 +#endif + + +/* + * The remaining options affect code selection within the JPEG library, + * but they don't need to be visible to most applications using the library. + * To minimize application namespace pollution, the symbols won't be + * defined unless JPEG_INTERNALS or JPEG_INTERNAL_OPTIONS has been defined. + */ + +#ifdef JPEG_INTERNALS +#define JPEG_INTERNAL_OPTIONS +#endif + +#ifdef JPEG_INTERNAL_OPTIONS + + +/* + * These defines indicate whether to include various optional functions. + * Undefining some of these symbols will produce a smaller but less capable + * library. Note that you can leave certain source files out of the + * compilation/linking process if you've #undef'd the corresponding symbols. + * (You may HAVE to do that if your compiler doesn't like null source files.) + */ + +/* Arithmetic coding is unsupported for legal reasons. Complaints to IBM. */ + +/* Capability options common to encoder and decoder: */ + +#define DCT_ISLOW_SUPPORTED /* slow but accurate integer algorithm */ +#define DCT_IFAST_SUPPORTED /* faster, less accurate integer method */ +#define DCT_FLOAT_SUPPORTED /* floating-point: accurate, fast on fast HW */ + +/* Encoder capability options: */ + +#undef C_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */ +#define C_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ +#define C_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/ +#define C_LOSSLESS_SUPPORTED /* Lossless JPEG? */ +#define ENTROPY_OPT_SUPPORTED /* Optimization of entropy coding parms? */ +/* Note: if you selected 12-bit data precision, it is dangerous to turn off + * ENTROPY_OPT_SUPPORTED. The standard Huffman tables are only good for 8-bit + * precision, so jcshuff.c normally uses entropy optimization to compute + * usable tables for higher precision. If you don't want to do optimization, + * you'll have to supply different default Huffman tables. + * The exact same statements apply for progressive and lossless JPEG: + * the default tables don't work for progressive mode or lossless mode. + * (This may get fixed, however.) + */ +#define INPUT_SMOOTHING_SUPPORTED /* Input image smoothing option? */ + +/* Decoder capability options: */ + +#undef D_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */ +#define D_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ +#define D_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/ +#define D_LOSSLESS_SUPPORTED /* Lossless JPEG? */ +#define SAVE_MARKERS_SUPPORTED /* jpeg_save_markers() needed? */ +#define BLOCK_SMOOTHING_SUPPORTED /* Block smoothing? (Progressive only) */ +#define IDCT_SCALING_SUPPORTED /* Output rescaling via IDCT? */ +#undef UPSAMPLE_SCALING_SUPPORTED /* Output rescaling at upsample stage? */ +#define UPSAMPLE_MERGING_SUPPORTED /* Fast path for sloppy upsampling? */ +#define QUANT_1PASS_SUPPORTED /* 1-pass color quantization? */ +#define QUANT_2PASS_SUPPORTED /* 2-pass color quantization? */ + +/* more capability options later, no doubt */ + + +/* + * Ordering of RGB data in scanlines passed to or from the application. + * If your application wants to deal with data in the order B,G,R, just + * change these macros. You can also deal with formats such as R,G,B,X + * (one extra byte per pixel) by changing RGB_PIXELSIZE. Note that changing + * the offsets will also change the order in which colormap data is organized. + * RESTRICTIONS: + * 1. The sample applications cjpeg,djpeg do NOT support modified RGB formats. + * 2. These macros only affect RGB<=>YCbCr color conversion, so they are not + * useful if you are using JPEG color spaces other than YCbCr or grayscale. + * 3. The color quantizer modules will not behave desirably if RGB_PIXELSIZE + * is not 3 (they don't understand about dummy color components!). So you + * can't use color quantization if you change that value. + */ + +#define RGB_RED 0 /* Offset of Red in an RGB scanline element */ +#define RGB_GREEN 1 /* Offset of Green */ +#define RGB_BLUE 2 /* Offset of Blue */ +#define RGB_PIXELSIZE 3 /* JSAMPLEs per RGB scanline element */ + + +/* Definitions for speed-related optimizations. */ + + +/* If your compiler supports inline functions, define INLINE + * as the inline keyword; otherwise define it as empty. + */ + +#ifndef INLINE +#ifdef __GNUC__ /* for instance, GNU C knows about inline */ +#define INLINE __inline__ +#endif +#ifndef INLINE +#define INLINE /* default is to define it as empty */ +#endif +#endif + + +/* On some machines (notably 68000 series) "int" is 32 bits, but multiplying + * two 16-bit shorts is faster than multiplying two ints. Define MULTIPLIER + * as short on such a machine. MULTIPLIER must be at least 16 bits wide. + */ + +#ifndef MULTIPLIER +#define MULTIPLIER int /* type for fastest integer multiply */ +#endif + + +/* FAST_FLOAT should be either float or double, whichever is done faster + * by your compiler. (Note that this type is only used in the floating point + * DCT routines, so it only matters if you've defined DCT_FLOAT_SUPPORTED.) + * Typically, float is faster in ANSI C compilers, while double is faster in + * pre-ANSI compilers (because they insist on converting to double anyway). + * The code below therefore chooses float if we have ANSI-style prototypes. + */ + +#ifndef FAST_FLOAT +#ifdef HAVE_PROTOTYPES +#define FAST_FLOAT float +#else +#define FAST_FLOAT double +#endif +#endif + +#endif /* JPEG_INTERNAL_OPTIONS */ diff --git a/gdcm/Utilities/gdcmjpeg/jpegcmake.h.in b/gdcm/Utilities/gdcmjpeg/jpegcmake.h.in new file mode 100644 index 0000000..d19bf68 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jpegcmake.h.in @@ -0,0 +1,46 @@ +/* jpegcmake.h file generated by CMake http://www.cmake.org */ + +#ifndef __jpegcmake_h +#define __jpegcmake_h + +/* See jconfig.h */ +/* For all plateforms: */ +#define HAVE_PROTOTYPES +#define HAVE_UNSIGNED_CHAR +#define HAVE_UNSIGNED_SHORT + +#cmakedefine HAVE_STDDEF_H +#cmakedefine HAVE_STDLIB_H + +/* These macros are used in all function definitions and extern declarations. + * You could modify them if you need to change function linkage conventions; + * in particular, you'll need to do that to make the library a Windows DLL. + * Another application is to make all functions global for use with debuggers + * or code profilers that require it. + */ + +#cmakedefine JPEGDLL +#cmakedefine JPEGSTATIC + +/* For more info on this bug see: + * [Broken JPEG from GE station] on comp.protocols.dicom + * and official publication at: + * http://www.medicalconnections.co.uk/html/lossless_bug.html + */ +#cmakedefine SUPPORT_DICOMOBJECTS_BUG + +#define BITS_IN_JSAMPLE @CMAKE_BITS_IN_JSAMPLE@ + +#if BITS_IN_JSAMPLE == 8 +#include "mangle_jpeg8bits.h" +#endif + +#if BITS_IN_JSAMPLE == 12 +#include "mangle_jpeg12bits.h" +#endif + +#if BITS_IN_JSAMPLE == 16 +#include "mangle_jpeg16bits.h" +#endif + +#endif /* __jpegcmake_h */ diff --git a/gdcm/Utilities/gdcmjpeg/jpegint.h b/gdcm/Utilities/gdcmjpeg/jpegint.h new file mode 100644 index 0000000..684dada --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jpegint.h @@ -0,0 +1,365 @@ +/* + * jpegint.h + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file provides common declarations for the various JPEG modules. + * These declarations are considered internal to the JPEG library; most + * applications using the library shouldn't need to include this file. + */ + + +/* Declarations for both compression & decompression */ + +typedef enum { /* Operating modes for buffer controllers */ + JBUF_PASS_THRU, /* Plain stripwise operation */ + /* Remaining modes require a full-image buffer to have been created */ + JBUF_SAVE_SOURCE, /* Run source subobject only, save output */ + JBUF_CRANK_DEST, /* Run dest subobject only, using saved data */ + JBUF_SAVE_AND_PASS /* Run both subobjects, save output */ +} J_BUF_MODE; + +/* Values of global_state field (jdapi.c has some dependencies on ordering!) */ +#define CSTATE_START 100 /* after create_compress */ +#define CSTATE_SCANNING 101 /* start_compress done, write_scanlines OK */ +#define CSTATE_RAW_OK 102 /* start_compress done, write_raw_data OK */ +#define CSTATE_WRCOEFS 103 /* jpeg_write_coefficients done */ +#define DSTATE_START 200 /* after create_decompress */ +#define DSTATE_INHEADER 201 /* reading header markers, no SOS yet */ +#define DSTATE_READY 202 /* found SOS, ready for start_decompress */ +#define DSTATE_PRELOAD 203 /* reading multiscan file in start_decompress*/ +#define DSTATE_PRESCAN 204 /* performing dummy pass for 2-pass quant */ +#define DSTATE_SCANNING 205 /* start_decompress done, read_scanlines OK */ +#define DSTATE_RAW_OK 206 /* start_decompress done, read_raw_data OK */ +#define DSTATE_BUFIMAGE 207 /* expecting jpeg_start_output */ +#define DSTATE_BUFPOST 208 /* looking for SOS/EOI in jpeg_finish_output */ +#define DSTATE_RDCOEFS 209 /* reading file in jpeg_read_coefficients */ +#define DSTATE_STOPPING 210 /* looking for EOI in jpeg_finish_decompress */ + + +/* Declarations for compression modules */ + +/* Master control module */ +struct jpeg_comp_master { + JMETHOD(void, prepare_for_pass, (j_compress_ptr cinfo)); + JMETHOD(void, pass_startup, (j_compress_ptr cinfo)); + JMETHOD(void, finish_pass, (j_compress_ptr cinfo)); + + /* State variables made visible to other modules */ + boolean call_pass_startup; /* True if pass_startup must be called */ + boolean is_last_pass; /* True during last pass */ +}; + +/* Main buffer control (downsampled-data buffer) */ +struct jpeg_c_main_controller { + JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(void, process_data, (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail)); +}; + +/* Compression preprocessing (downsampling input buffer control) */ +struct jpeg_c_prep_controller { + JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(void, pre_process_data, (j_compress_ptr cinfo, + JSAMPARRAY input_buf, + JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail, + JSAMPIMAGE output_buf, + JDIMENSION *out_row_group_ctr, + JDIMENSION out_row_groups_avail)); +}; + +/* Compression codec (compressor proper) */ +struct jpeg_c_codec { + JMETHOD(void, entropy_start_pass, (j_compress_ptr cinfo, + boolean gather_statistics)); + JMETHOD(void, entropy_finish_pass, (j_compress_ptr cinfo)); + JMETHOD(boolean, need_optimization_pass, (j_compress_ptr cinfo)); + JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(boolean, compress_data, (j_compress_ptr cinfo, + JSAMPIMAGE input_buf)); +}; + +/* Colorspace conversion */ +struct jpeg_color_converter { + JMETHOD(void, start_pass, (j_compress_ptr cinfo)); + JMETHOD(void, color_convert, (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows)); +}; + +/* Downsampling */ +struct jpeg_downsampler { + JMETHOD(void, start_pass, (j_compress_ptr cinfo)); + JMETHOD(void, downsample, (j_compress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION in_row_index, + JSAMPIMAGE output_buf, + JDIMENSION out_row_group_index)); + + boolean need_context_rows; /* TRUE if need rows above & below */ +}; + +/* Marker writing */ +struct jpeg_marker_writer { + JMETHOD(void, write_file_header, (j_compress_ptr cinfo)); + JMETHOD(void, write_frame_header, (j_compress_ptr cinfo)); + JMETHOD(void, write_scan_header, (j_compress_ptr cinfo)); + JMETHOD(void, write_file_trailer, (j_compress_ptr cinfo)); + JMETHOD(void, write_tables_only, (j_compress_ptr cinfo)); + /* These routines are exported to allow insertion of extra markers */ + /* Probably only COM and APPn markers should be written this way */ + JMETHOD(void, write_marker_header, (j_compress_ptr cinfo, int marker, + unsigned int datalen)); + JMETHOD(void, write_marker_byte, (j_compress_ptr cinfo, int val)); +}; + + +/* Declarations for decompression modules */ + +/* Master control module */ +struct jpeg_decomp_master { + JMETHOD(void, prepare_for_output_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, finish_output_pass, (j_decompress_ptr cinfo)); + + /* State variables made visible to other modules */ + boolean is_dummy_pass; /* True during 1st pass for 2-pass quant */ +}; + +/* Input control module */ +struct jpeg_input_controller { + JMETHOD(int, consume_input, (j_decompress_ptr cinfo)); + JMETHOD(void, reset_input_controller, (j_decompress_ptr cinfo)); + JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, finish_input_pass, (j_decompress_ptr cinfo)); + + /* State variables made visible to other modules */ + boolean has_multiple_scans; /* True if file has multiple scans */ + boolean eoi_reached; /* True when EOI has been consumed */ +}; + +/* Main buffer control (downsampled-data buffer) */ +struct jpeg_d_main_controller { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(void, process_data, (j_decompress_ptr cinfo, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); +}; + +/* Decompression codec (decompressor proper) */ +struct jpeg_d_codec { + JMETHOD(void, calc_output_dimensions, (j_decompress_ptr cinfo)); + JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo)); + JMETHOD(int, consume_data, (j_decompress_ptr cinfo)); + JMETHOD(void, start_output_pass, (j_decompress_ptr cinfo)); + JMETHOD(int, decompress_data, (j_decompress_ptr cinfo, + JSAMPIMAGE output_buf)); +}; + +/* Decompression postprocessing (color quantization buffer control) */ +struct jpeg_d_post_controller { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(void, post_process_data, (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, + JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, + JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); +}; + +/* Marker reading & parsing */ +struct jpeg_marker_reader { + JMETHOD(void, reset_marker_reader, (j_decompress_ptr cinfo)); + /* Read markers until SOS or EOI. + * Returns same codes as are defined for jpeg_consume_input: + * JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI. + */ + JMETHOD(int, read_markers, (j_decompress_ptr cinfo)); + /* Read a restart marker --- exported for use by entropy decoder only */ + jpeg_marker_parser_method read_restart_marker; + + /* State of marker reader --- nominally internal, but applications + * supplying COM or APPn handlers might like to know the state. + */ + boolean saw_SOI; /* found SOI? */ + boolean saw_SOF; /* found SOF? */ + int next_restart_num; /* next restart number expected (0-7) */ + unsigned int discarded_bytes; /* # of bytes skipped looking for a marker */ +}; + +/* Upsampling (note that upsampler must also call color converter) */ +struct jpeg_upsampler { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, upsample, (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, + JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, + JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); + + boolean need_context_rows; /* TRUE if need rows above & below */ +}; + +/* Colorspace conversion */ +struct jpeg_color_deconverter { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, color_convert, (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows)); +}; + +/* Color quantization or color precision reduction */ +struct jpeg_color_quantizer { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo, boolean is_pre_scan)); + JMETHOD(void, color_quantize, (j_decompress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPARRAY output_buf, + int num_rows)); + JMETHOD(void, finish_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, new_color_map, (j_decompress_ptr cinfo)); +}; + + +/* Miscellaneous useful macros */ + +#undef MAX +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#undef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) + + +/* We assume that right shift corresponds to signed division by 2 with + * rounding towards minus infinity. This is correct for typical "arithmetic + * shift" instructions that shift in copies of the sign bit. But some + * C compilers implement >> with an unsigned shift. For these machines you + * must define RIGHT_SHIFT_IS_UNSIGNED. + * RIGHT_SHIFT provides a proper signed right shift of an INT32 quantity. + * It is only applied with constant shift counts. SHIFT_TEMPS must be + * included in the variables of any routine using RIGHT_SHIFT. + */ + +#ifdef RIGHT_SHIFT_IS_UNSIGNED +#define SHIFT_TEMPS INT32 shift_temp; +#define RIGHT_SHIFT(x,shft) \ + ((shift_temp = (x)) < 0 ? \ + (shift_temp >> (shft)) | ((~((INT32) 0)) << (32-(shft))) : \ + (shift_temp >> (shft))) +#else +#define SHIFT_TEMPS +#define RIGHT_SHIFT(x,shft) ((x) >> (shft)) +#endif + + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jinit_c_codec jICCodec +#define jinit_c_diff_controller jICDiffC +#define jinit_lossy_c_codec jILossyC +#define jinit_lossless_c_codec jILosslessC +#define jinit_compress_master jICompress +#define jinit_c_master_control jICMaster +#define jinit_c_main_controller jICMainC +#define jinit_c_prep_controller jICPrepC +#define jinit_c_coef_controller jICCoefC +#define jinit_color_converter jICColor +#define jinit_downsampler jIDownsampler +#define jinit_forward_dct jIFDCT +#define jinit_shuff_encoder jISHEncoder +#define jinit_phuff_encoder jIPHEncoder +#define jinit_arith_encoder jIAEncoder +#define jinit_marker_writer jIMWriter +#define jinit_d_codec jIDCodec +#define jinit_lossy_d_codec jILossyD +#define jinit_lossless_d_codec jILosslsD +#define jinit_master_decompress jIDMaster +#define jinit_d_main_controller jIDMainC +#define jinit_d_coef_controller jIDCoefC +#define jinit_d_diff_controller jIDDiffC +#define jinit_d_post_controller jIDPostC +#define jinit_input_controller jIInCtlr +#define jinit_marker_reader jIMReader +#define jinit_shuff_decoder jISHDecoder +#define jinit_phuff_decoder jIPHDecoder +#define jinit_arith_decoder jIADecoder +#define jinit_lhuff_decoder jILHDecoder +#define jinit_undifferencer jIUndiff +#define jinit_d_scaler jIDScaler +#define jinit_inverse_dct jIIDCT +#define jinit_upsampler jIUpsampler +#define jinit_color_deconverter jIDColor +#define jinit_1pass_quantizer jI1Quant +#define jinit_2pass_quantizer jI2Quant +#define jinit_merged_upsampler jIMUpsampler +#define jinit_memory_mgr jIMemMgr +#define jdiv_round_up jDivRound +#define jround_up jRound +#define jcopy_sample_rows jCopySamples +#define jcopy_block_row jCopyBlocks +#define jzero_far jZeroFar +#define jpeg_zigzag_order jZIGTable +#define jpeg_natural_order jZAGTable +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* Compression module initialization routines */ +EXTERN(void) jinit_c_codec JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_c_diff_controller JPP((j_compress_ptr cinfo, boolean need_full_buffer)); +EXTERN(void) jinit_compress_master JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_c_master_control JPP((j_compress_ptr cinfo, + boolean transcode_only)); +EXTERN(void) jinit_c_main_controller JPP((j_compress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_c_prep_controller JPP((j_compress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_compressor JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_color_converter JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_downsampler JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_marker_writer JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_arith_encoder JPP((j_compress_ptr cinfo)); +/* Decompression module initialization routines */ +EXTERN(void) jinit_d_codec JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_d_diff_controller JPP((j_decompress_ptr cinfo, boolean need_full_buffer)); +EXTERN(void) jinit_master_decompress JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_d_main_controller JPP((j_decompress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_decompressor JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_d_post_controller JPP((j_decompress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_input_controller JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_marker_reader JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_arith_decoder JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_upsampler JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_color_deconverter JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_1pass_quantizer JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_2pass_quantizer JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_merged_upsampler JPP((j_decompress_ptr cinfo)); +/* Memory manager initialization */ +EXTERN(void) jinit_memory_mgr JPP((j_common_ptr cinfo)); + +/* Utility routines in jutils.c */ +EXTERN(long) jdiv_round_up JPP((long a, long b)); +EXTERN(long) jround_up JPP((long a, long b)); +EXTERN(void) jcopy_sample_rows JPP((JSAMPARRAY input_array, int source_row, + JSAMPARRAY output_array, int dest_row, + int num_rows, JDIMENSION num_cols)); +EXTERN(void) jcopy_block_row JPP((JBLOCKROW input_row, JBLOCKROW output_row, + JDIMENSION num_blocks)); +EXTERN(void) jzero_far JPP((void FAR * target, size_t bytestozero)); +/* Constant tables in jutils.c */ +#if 0 /* This table is not actually needed in v6a */ +extern const int jpeg_zigzag_order[]; /* natural coef order to zigzag order */ +#endif +extern const int jpeg_natural_order[]; /* zigzag coef order to natural order */ + +/* Suppress undefined-structure complaints if necessary. */ + +#ifdef INCOMPLETE_TYPES_BROKEN +#ifndef AM_MEMORY_MANAGER /* only jmemmgr.c defines these */ +struct jvirt_sarray_control { long dummy; }; +struct jvirt_barray_control { long dummy; }; +#endif +#endif /* INCOMPLETE_TYPES_BROKEN */ diff --git a/gdcm/Utilities/gdcmjpeg/jpeglib.h b/gdcm/Utilities/gdcmjpeg/jpeglib.h new file mode 100644 index 0000000..b9d0c22 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jpeglib.h @@ -0,0 +1,1131 @@ +/* + * jpeglib.h + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file defines the application interface for the JPEG library. + * Most applications using the library need only include this file, + * and perhaps jerror.h if they want to know the exact error codes. + */ + +#ifndef JPEGLIB_H +#define JPEGLIB_H + +/* + * First we include the configuration files that record how this + * installation of the JPEG library is set up. jconfig.h can be + * generated automatically for many systems. jmorecfg.h contains + * manual configuration options that most people need not worry about. + */ + +#ifndef JCONFIG_INCLUDED /* in case jinclude.h already did */ +#include "jconfig.h" /* widely used configuration options */ +#endif +#include "jmorecfg.h" /* seldom changed options */ + + +/* Version ID for the JPEG library. + * Might be useful for tests like "#if JPEG_LIB_VERSION >= 60". + */ + +#define JPEG_LIB_VERSION 62 /* Version 6b */ + + +/* Various constants determining the sizes of things. + * All of these are specified by the JPEG standard, so don't change them + * if you want to be compatible. + */ + +#define DCTSIZE 8 /* The basic DCT block is 8x8 samples */ +#define DCTSIZE2 64 /* DCTSIZE squared; # of elements in a block */ +#define NUM_QUANT_TBLS 4 /* Quantization tables are numbered 0..3 */ +#define NUM_HUFF_TBLS 4 /* Huffman tables are numbered 0..3 */ +#define NUM_ARITH_TBLS 16 /* Arith-coding tables are numbered 0..15 */ +#define MAX_COMPS_IN_SCAN 4 /* JPEG limit on # of components in one scan */ +#define MAX_SAMP_FACTOR 4 /* JPEG limit on sampling factors */ +/* Unfortunately, some bozo at Adobe saw no reason to be bound by the standard; + * the PostScript DCT filter can emit files with many more than 10 data units + * per MCU. + * If you happen to run across such a file, you can up D_MAX_DATA_UNITS_IN_MCU + * to handle it. We even let you do this from the jconfig.h file. However, + * we strongly discourage changing C_MAX_DATA_UNITS_IN_MCU; just because Adobe + * sometimes emits noncompliant files doesn't mean you should too. + */ +#define C_MAX_DATA_UNITS_IN_MCU 10 /* compressor's limit on data units/MCU */ +#ifndef D_MAX_DATA_UNITS_IN_MCU +#define D_MAX_DATA_UNITS_IN_MCU 10 /* decompressor's limit on data units/MCU */ +#endif + + +/* Data structures for images (arrays of samples and of DCT coefficients). + * On 80x86 machines, the image arrays are too big for near pointers, + * but the pointer arrays can fit in near memory. + */ + +typedef JSAMPLE FAR *JSAMPROW; /* ptr to one image row of pixel samples. */ +typedef JSAMPROW *JSAMPARRAY; /* ptr to some rows (a 2-D sample array) */ +typedef JSAMPARRAY *JSAMPIMAGE; /* a 3-D sample array: top index is color */ + +typedef JCOEF JBLOCK[DCTSIZE2]; /* one block of coefficients */ +typedef JBLOCK FAR *JBLOCKROW; /* pointer to one row of coefficient blocks */ +typedef JBLOCKROW *JBLOCKARRAY; /* a 2-D array of coefficient blocks */ +typedef JBLOCKARRAY *JBLOCKIMAGE; /* a 3-D array of coefficient blocks */ + +typedef JCOEF FAR *JCOEFPTR; /* useful in a couple of places */ + +typedef JDIFF FAR *JDIFFROW; /* pointer to one row of difference values */ +typedef JDIFFROW *JDIFFARRAY; /* ptr to some rows (a 2-D diff array) */ +typedef JDIFFARRAY *JDIFFIMAGE; /* a 3-D diff array: top index is color */ + + +/* Types for JPEG compression parameters and working tables. */ + + +/* DCT coefficient quantization tables. */ + +typedef struct { + /* This array gives the coefficient quantizers in natural array order + * (not the zigzag order in which they are stored in a JPEG DQT marker). + * CAUTION: IJG versions prior to v6a kept this array in zigzag order. + */ + UINT16 quantval[DCTSIZE2]; /* quantization step for each coefficient */ + /* This field is used only during compression. It's initialized FALSE when + * the table is created, and set TRUE when it's been output to the file. + * You could suppress output of a table by setting this to TRUE. + * (See jpeg_suppress_tables for an example.) + */ + boolean sent_table; /* TRUE when table has been output */ +} JQUANT_TBL; + + +/* Huffman coding tables. */ + +typedef struct { + /* These two fields directly represent the contents of a JPEG DHT marker */ + UINT8 bits[17]; /* bits[k] = # of symbols with codes of */ + /* length k bits; bits[0] is unused */ + UINT8 huffval[256]; /* The symbols, in order of incr code length */ + /* This field is used only during compression. It's initialized FALSE when + * the table is created, and set TRUE when it's been output to the file. + * You could suppress output of a table by setting this to TRUE. + * (See jpeg_suppress_tables for an example.) + */ + boolean sent_table; /* TRUE when table has been output */ +} JHUFF_TBL; + + +/* Basic info about one component (color channel). */ + +typedef struct { + /* These values are fixed over the whole image. */ + /* For compression, they must be supplied by parameter setup; */ + /* for decompression, they are read from the SOF marker. */ + int component_id; /* identifier for this component (0..255) */ + int component_index; /* its index in SOF or cinfo->comp_info[] */ + int h_samp_factor; /* horizontal sampling factor (1..4) */ + int v_samp_factor; /* vertical sampling factor (1..4) */ + int quant_tbl_no; /* quantization table selector (0..3) */ + /* These values may vary between scans. */ + /* For compression, they must be supplied by parameter setup; */ + /* for decompression, they are read from the SOS marker. */ + /* The decompressor output side may not use these variables. */ + int dc_tbl_no; /* DC entropy table selector (0..3) */ + int ac_tbl_no; /* AC entropy table selector (0..3) */ + + /* Remaining fields should be treated as private by applications. */ + + /* These values are computed during compression or decompression startup: */ + /* Component's size in data units. + * Any dummy data units added to complete an MCU are not counted; therefore + * these values do not depend on whether a scan is interleaved or not. + */ + JDIMENSION width_in_data_units; + JDIMENSION height_in_data_units; + /* Size of a data unit in/output by the codec (in samples). Always + * data_unit for compression. For decompression this is the size of the + * output from one data_unit, reflecting any processing performed by the + * codec. For example, in the DCT-based codec, scaling may be applied + * during the IDCT step. Values of 1,2,4,8 are likely to be supported. + * Note that different components may have different codec_data_unit sizes. + */ + int codec_data_unit; + /* The downsampled dimensions are the component's actual, unpadded number + * of samples at the main buffer (preprocessing/compression interface), thus + * downsampled_width = ceil(image_width * Hi/Hmax) + * and similarly for height. For decompression, codec-based processing is + * included (ie, IDCT scaling), so + * downsampled_width = ceil(image_width * Hi/Hmax * codec_data_unit/data_unit) + */ + JDIMENSION downsampled_width; /* actual width in samples */ + JDIMENSION downsampled_height; /* actual height in samples */ + /* This flag is used only for decompression. In cases where some of the + * components will be ignored (eg grayscale output from YCbCr image), + * we can skip most computations for the unused components. + */ + boolean component_needed; /* do we need the value of this component? */ + + /* These values are computed before starting a scan of the component. */ + /* The decompressor output side may not use these variables. */ + int MCU_width; /* number of data units per MCU, horizontally */ + int MCU_height; /* number of data units per MCU, vertically */ + int MCU_data_units; /* MCU_width * MCU_height */ + int MCU_sample_width; /* MCU width in samples, MCU_width*codec_data_unit */ + int last_col_width; /* # of non-dummy data_units across in last MCU */ + int last_row_height; /* # of non-dummy data_units down in last MCU */ + + /* Saved quantization table for component; NULL if none yet saved. + * See jdinput.c comments about the need for this information. + * This field is currently used only for decompression. + */ + JQUANT_TBL * quant_table; + + /* Private per-component storage for DCT or IDCT subsystem. */ + void * dct_table; +} jpeg_component_info; + + +/* The script for encoding a multiple-scan file is an array of these: */ + +typedef struct { + int comps_in_scan; /* number of components encoded in this scan */ + int component_index[MAX_COMPS_IN_SCAN]; /* their SOF/comp_info[] indexes */ + int Ss, Se; /* progressive JPEG spectral selection parms + lossless JPEG predictor select parm (Ss) */ + int Ah, Al; /* progressive JPEG successive approx. parms + lossless JPEG point transform parm (Al) */ +} jpeg_scan_info; + +/* The decompressor can save APPn and COM markers in a list of these: */ + +typedef struct jpeg_marker_struct FAR * jpeg_saved_marker_ptr; + +struct jpeg_marker_struct { + jpeg_saved_marker_ptr next; /* next in list, or NULL */ + UINT8 marker; /* marker code: JPEG_COM, or JPEG_APP0+n */ + unsigned int original_length; /* # bytes of data in the file */ + unsigned int data_length; /* # bytes of data saved at data[] */ + JOCTET FAR * data; /* the data contained in the marker */ + /* the marker length word is not counted in data_length or original_length */ +}; + +/* Known codec processes. */ + +typedef enum { + JPROC_SEQUENTIAL, /* baseline/extended sequential DCT */ + JPROC_PROGRESSIVE, /* progressive DCT */ + JPROC_LOSSLESS /* lossless (sequential) */ +} J_CODEC_PROCESS; + +/* Known color spaces. */ + +typedef enum { + JCS_UNKNOWN, /* error/unspecified */ + JCS_GRAYSCALE, /* monochrome */ + JCS_RGB, /* red/green/blue */ + JCS_YCbCr, /* Y/Cb/Cr (also known as YUV) */ + JCS_CMYK, /* C/M/Y/K */ + JCS_YCCK /* Y/Cb/Cr/K */ +} J_COLOR_SPACE; + +/* DCT/IDCT algorithm options. */ + +typedef enum { + JDCT_ISLOW, /* slow but accurate integer algorithm */ + JDCT_IFAST, /* faster, less accurate integer method */ + JDCT_FLOAT /* floating-point: accurate, fast on fast HW */ +} J_DCT_METHOD; + +#ifndef JDCT_DEFAULT /* may be overridden in jconfig.h */ +#define JDCT_DEFAULT JDCT_ISLOW +#endif +#ifndef JDCT_FASTEST /* may be overridden in jconfig.h */ +#define JDCT_FASTEST JDCT_IFAST +#endif + +/* Dithering options for decompression. */ + +typedef enum { + JDITHER_NONE, /* no dithering */ + JDITHER_ORDERED, /* simple ordered dither */ + JDITHER_FS /* Floyd-Steinberg error diffusion dither */ +} J_DITHER_MODE; + + +/* Common fields between JPEG compression and decompression master structs. */ + +#define jpeg_common_fields \ + struct jpeg_error_mgr * err; /* Error handler module */\ + struct jpeg_memory_mgr * mem; /* Memory manager module */\ + struct jpeg_progress_mgr * progress; /* Progress monitor, or NULL if none */\ + void * client_data; /* Available for use by application */\ + boolean is_decompressor; /* So common code can tell which is which */\ + int global_state /* For checking call sequence validity */ + +/* Routines that are to be used by both halves of the library are declared + * to receive a pointer to this structure. There are no actual instances of + * jpeg_common_struct, only of jpeg_compress_struct and jpeg_decompress_struct. + */ +struct jpeg_common_struct { + jpeg_common_fields; /* Fields common to both master struct types */ + /* Additional fields follow in an actual jpeg_compress_struct or + * jpeg_decompress_struct. All three structs must agree on these + * initial fields! (This would be a lot cleaner in C++.) + */ +}; + +typedef struct jpeg_common_struct * j_common_ptr; +typedef struct jpeg_compress_struct * j_compress_ptr; +typedef struct jpeg_decompress_struct * j_decompress_ptr; + + +/* Master record for a compression instance */ + +struct jpeg_compress_struct { + jpeg_common_fields; /* Fields shared with jpeg_decompress_struct */ + + /* Destination for compressed data */ + struct jpeg_destination_mgr * dest; + + /* Description of source image --- these fields must be filled in by + * outer application before starting compression. in_color_space must + * be correct before you can even call jpeg_set_defaults(). + */ + + JDIMENSION image_width; /* input image width */ + JDIMENSION image_height; /* input image height */ + int input_components; /* # of color components in input image */ + J_COLOR_SPACE in_color_space; /* colorspace of input image */ + + double input_gamma; /* image gamma of input image */ + + /* Compression parameters --- these fields must be set before calling + * jpeg_start_compress(). We recommend calling jpeg_set_defaults() to + * initialize everything to reasonable defaults, then changing anything + * the application specifically wants to change. That way you won't get + * burnt when new parameters are added. Also note that there are several + * helper routines to simplify changing parameters. + */ + + boolean lossless; /* TRUE=lossless encoding, FALSE=lossy */ + + int data_precision; /* bits of precision in image data */ + + int num_components; /* # of color components in JPEG image */ + J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */ + + jpeg_component_info * comp_info; + /* comp_info[i] describes component that appears i'th in SOF */ + + JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS]; + /* ptrs to coefficient quantization tables, or NULL if not defined */ + + JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; + JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; + /* ptrs to Huffman coding tables, or NULL if not defined */ + + UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ + UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ + UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ + + int num_scans; /* # of entries in scan_info array */ + const jpeg_scan_info * scan_info; /* script for multi-scan file, or NULL */ + /* The default value of scan_info is NULL, which causes a single-scan + * sequential JPEG file to be emitted. To create a multi-scan file, + * set num_scans and scan_info to point to an array of scan definitions. + */ + + boolean raw_data_in; /* TRUE=caller supplies downsampled data */ + boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ + boolean optimize_coding; /* TRUE=optimize entropy encoding parms */ + boolean CCIR601_sampling; /* TRUE=first samples are cosited */ + int smoothing_factor; /* 1..100, or 0 for no input smoothing */ + J_DCT_METHOD dct_method; /* DCT algorithm selector */ + + /* The restart interval can be specified in absolute MCUs by setting + * restart_interval, or in MCU rows by setting restart_in_rows + * (in which case the correct restart_interval will be figured + * for each scan). + */ + unsigned int restart_interval; /* MCUs per restart, or 0 for no restart */ + int restart_in_rows; /* if > 0, MCU rows per restart interval */ + + /* Parameters controlling emission of special markers. */ + + boolean write_JFIF_header; /* should a JFIF marker be written? */ + UINT8 JFIF_major_version; /* What to write for the JFIF version number */ + UINT8 JFIF_minor_version; + /* These three values are not used by the JPEG code, merely copied */ + /* into the JFIF APP0 marker. density_unit can be 0 for unknown, */ + /* 1 for dots/inch, or 2 for dots/cm. Note that the pixel aspect */ + /* ratio is defined by X_density/Y_density even when density_unit=0. */ + UINT8 density_unit; /* JFIF code for pixel size units */ + UINT16 X_density; /* Horizontal pixel density */ + UINT16 Y_density; /* Vertical pixel density */ + boolean write_Adobe_marker; /* should an Adobe marker be written? */ + + /* State variable: index of next scanline to be written to + * jpeg_write_scanlines(). Application may use this to control its + * processing loop, e.g., "while (next_scanline < image_height)". + */ + + JDIMENSION next_scanline; /* 0 .. image_height-1 */ + + /* Remaining fields are known throughout compressor, but generally + * should not be touched by a surrounding application. + */ + + /* + * These fields are computed during compression startup + */ + int data_unit; /* size of data unit in samples */ + J_CODEC_PROCESS process; /* encoding process of JPEG image */ + + int max_h_samp_factor; /* largest h_samp_factor */ + int max_v_samp_factor; /* largest v_samp_factor */ + + JDIMENSION total_iMCU_rows; /* # of iMCU rows to be input to codec */ + /* The codec receives data in units of MCU rows as defined for fully + * interleaved scans (whether the JPEG file is interleaved or not). + * There are v_samp_factor * data_unit sample rows of each component in an + * "iMCU" (interleaved MCU) row. + */ + + /* + * These fields are valid during any one scan. + * They describe the components and MCUs actually appearing in the scan. + */ + int comps_in_scan; /* # of JPEG components in this scan */ + jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; + /* *cur_comp_info[i] describes component that appears i'th in SOS */ + + JDIMENSION MCUs_per_row; /* # of MCUs across the image */ + JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ + + int data_units_in_MCU; /* # of data units per MCU */ + int MCU_membership[C_MAX_DATA_UNITS_IN_MCU]; + /* MCU_membership[i] is index in cur_comp_info of component owning */ + /* i'th block in an MCU */ + + int Ss, Se, Ah, Al; /* progressive/lossless JPEG parameters for scan */ + + /* + * Links to compression subobjects (methods and private variables of modules) + */ + struct jpeg_comp_master * master; + struct jpeg_c_main_controller * main; + struct jpeg_c_prep_controller * prep; + struct jpeg_c_codec * codec; + struct jpeg_marker_writer * marker; + struct jpeg_color_converter * cconvert; + struct jpeg_downsampler * downsample; + jpeg_scan_info * script_space; /* workspace for jpeg_simple_progression */ + int script_space_size; +}; + + +/* Master record for a decompression instance */ + +struct jpeg_decompress_struct { + jpeg_common_fields; /* Fields shared with jpeg_compress_struct */ + + /* Source of compressed data */ + struct jpeg_source_mgr * src; + + /* Basic description of image --- filled in by jpeg_read_header(). */ + /* Application may inspect these values to decide how to process image. */ + + JDIMENSION image_width; /* nominal image width (from SOF marker) */ + JDIMENSION image_height; /* nominal image height */ + int num_components; /* # of color components in JPEG image */ + J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */ + + /* Decompression processing parameters --- these fields must be set before + * calling jpeg_start_decompress(). Note that jpeg_read_header() initializes + * them to default values. + */ + + J_COLOR_SPACE out_color_space; /* colorspace for output */ + + unsigned int scale_num, scale_denom; /* fraction by which to scale image */ + + double output_gamma; /* image gamma wanted in output */ + + boolean buffered_image; /* TRUE=multiple output passes */ + boolean raw_data_out; /* TRUE=downsampled data wanted */ + + J_DCT_METHOD dct_method; /* IDCT algorithm selector */ + boolean do_fancy_upsampling; /* TRUE=apply fancy upsampling */ + boolean do_block_smoothing; /* TRUE=apply interblock smoothing */ + + boolean quantize_colors; /* TRUE=colormapped output wanted */ + /* the following are ignored if not quantize_colors: */ + J_DITHER_MODE dither_mode; /* type of color dithering to use */ + boolean two_pass_quantize; /* TRUE=use two-pass color quantization */ + int desired_number_of_colors; /* max # colors to use in created colormap */ + /* these are significant only in buffered-image mode: */ + boolean enable_1pass_quant; /* enable future use of 1-pass quantizer */ + boolean enable_external_quant;/* enable future use of external colormap */ + boolean enable_2pass_quant; /* enable future use of 2-pass quantizer */ + + /* Description of actual output image that will be returned to application. + * These fields are computed by jpeg_start_decompress(). + * You can also use jpeg_calc_output_dimensions() to determine these values + * in advance of calling jpeg_start_decompress(). + */ + + JDIMENSION output_width; /* scaled image width */ + JDIMENSION output_height; /* scaled image height */ + int out_color_components; /* # of color components in out_color_space */ + int output_components; /* # of color components returned */ + /* output_components is 1 (a colormap index) when quantizing colors; + * otherwise it equals out_color_components. + */ + int rec_outbuf_height; /* min recommended height of scanline buffer */ + /* If the buffer passed to jpeg_read_scanlines() is less than this many rows + * high, space and time will be wasted due to unnecessary data copying. + * Usually rec_outbuf_height will be 1 or 2, at most 4. + */ + + /* When quantizing colors, the output colormap is described by these fields. + * The application can supply a colormap by setting colormap non-NULL before + * calling jpeg_start_decompress; otherwise a colormap is created during + * jpeg_start_decompress or jpeg_start_output. + * The map has out_color_components rows and actual_number_of_colors columns. + */ + int actual_number_of_colors; /* number of entries in use */ + JSAMPARRAY colormap; /* The color map as a 2-D pixel array */ + + /* State variables: these variables indicate the progress of decompression. + * The application may examine these but must not modify them. + */ + + /* Row index of next scanline to be read from jpeg_read_scanlines(). + * Application may use this to control its processing loop, e.g., + * "while (output_scanline < output_height)". + */ + JDIMENSION output_scanline; /* 0 .. output_height-1 */ + + /* Current input scan number and number of iMCU rows completed in scan. + * These indicate the progress of the decompressor input side. + */ + int input_scan_number; /* Number of SOS markers seen so far */ + JDIMENSION input_iMCU_row; /* Number of iMCU rows completed */ + + /* The "output scan number" is the notional scan being displayed by the + * output side. The decompressor will not allow output scan/row number + * to get ahead of input scan/row, but it can fall arbitrarily far behind. + */ + int output_scan_number; /* Nominal scan number being displayed */ + JDIMENSION output_iMCU_row; /* Number of iMCU rows read */ + + /* Current progression status. coef_bits[c][i] indicates the precision + * with which component c's DCT coefficient i (in zigzag order) is known. + * It is -1 when no data has yet been received, otherwise it is the point + * transform (shift) value for the most recent scan of the coefficient + * (thus, 0 at completion of the progression). + * This pointer is NULL when reading a non-progressive file. + */ + int (*coef_bits)[DCTSIZE2]; /* -1 or current Al value for each coef */ + + /* Internal JPEG parameters --- the application usually need not look at + * these fields. Note that the decompressor output side may not use + * any parameters that can change between scans. + */ + + /* Quantization and Huffman tables are carried forward across input + * datastreams when processing abbreviated JPEG datastreams. + */ + + JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS]; + /* ptrs to coefficient quantization tables, or NULL if not defined */ + + JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; + JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; + /* ptrs to Huffman coding tables, or NULL if not defined */ + + /* These parameters are never carried across datastreams, since they + * are given in SOF/SOS markers or defined to be reset by SOI. + */ + + int data_precision; /* bits of precision in image data */ + + jpeg_component_info * comp_info; + /* comp_info[i] describes component that appears i'th in SOF */ + + boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ + + UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ + UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ + UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ + + unsigned int restart_interval; /* MCUs per restart interval, or 0 for no restart */ + + /* These fields record data obtained from optional markers recognized by + * the JPEG library. + */ + boolean saw_JFIF_marker; /* TRUE iff a JFIF APP0 marker was found */ + /* Data copied from JFIF marker; only valid if saw_JFIF_marker is TRUE: */ + UINT8 JFIF_major_version; /* JFIF version number */ + UINT8 JFIF_minor_version; + UINT8 density_unit; /* JFIF code for pixel size units */ + UINT16 X_density; /* Horizontal pixel density */ + UINT16 Y_density; /* Vertical pixel density */ + boolean saw_Adobe_marker; /* TRUE iff an Adobe APP14 marker was found */ + UINT8 Adobe_transform; /* Color transform code from Adobe marker */ + + boolean CCIR601_sampling; /* TRUE=first samples are cosited */ + + /* Aside from the specific data retained from APPn markers known to the + * library, the uninterpreted contents of any or all APPn and COM markers + * can be saved in a list for examination by the application. + */ + jpeg_saved_marker_ptr marker_list; /* Head of list of saved markers */ + + /* Remaining fields are known throughout decompressor, but generally + * should not be touched by a surrounding application. + */ + + /* + * These fields are computed during decompression startup + */ + int data_unit; /* size of data unit in samples */ + J_CODEC_PROCESS process; /* decoding process of JPEG image */ + + int max_h_samp_factor; /* largest h_samp_factor */ + int max_v_samp_factor; /* largest v_samp_factor */ + + int min_codec_data_unit; /* smallest codec_data_unit of any component */ + + JDIMENSION total_iMCU_rows; /* # of iMCU rows in image */ + /* The codec's input and output progress is measured in units of "iMCU" + * (interleaved MCU) rows. These are the same as MCU rows in fully + * interleaved JPEG scans, but are used whether the scan is interleaved + * or not. We define an iMCU row as v_samp_factor data_unit rows of each + * component. Therefore, the codec output contains + * v_samp_factor*codec_data_unit sample rows of a component per iMCU row. + */ + + JSAMPLE * sample_range_limit; /* table for fast range-limiting */ + + /* + * These fields are valid during any one scan. + * They describe the components and MCUs actually appearing in the scan. + * Note that the decompressor output side must not use these fields. + */ + int comps_in_scan; /* # of JPEG components in this scan */ + jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; + /* *cur_comp_info[i] describes component that appears i'th in SOS */ + + JDIMENSION MCUs_per_row; /* # of MCUs across the image */ + JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ + + int data_units_in_MCU; /* # of data _units per MCU */ + int MCU_membership[D_MAX_DATA_UNITS_IN_MCU]; + /* MCU_membership[i] is index in cur_comp_info of component owning */ + /* i'th data unit in an MCU */ + + int Ss, Se, Ah, Al; /* progressive/lossless JPEG parms for scan */ + + /* This field is shared between entropy decoder and marker parser. + * It is either zero or the code of a JPEG marker that has been + * read from the data source, but has not yet been processed. + */ + int unread_marker; + + /* + * Links to decompression subobjects (methods, private variables of modules) + */ + struct jpeg_decomp_master * master; + struct jpeg_d_main_controller * main; + struct jpeg_d_codec * codec; + struct jpeg_d_post_controller * post; + struct jpeg_input_controller * inputctl; + struct jpeg_marker_reader * marker; + struct jpeg_upsampler * upsample; + struct jpeg_color_deconverter * cconvert; + struct jpeg_color_quantizer * cquantize; +}; + + +/* "Object" declarations for JPEG modules that may be supplied or called + * directly by the surrounding application. + * As with all objects in the JPEG library, these structs only define the + * publicly visible methods and state variables of a module. Additional + * private fields may exist after the public ones. + */ + + +/* Error handler object */ + +struct jpeg_error_mgr { + /* Error exit handler: does not return to caller */ + JMETHOD(void, error_exit, (j_common_ptr cinfo)); + /* Conditionally emit a trace or warning message */ + JMETHOD(void, emit_message, (j_common_ptr cinfo, int msg_level)); + /* Routine that actually outputs a trace or error message */ + JMETHOD(void, output_message, (j_common_ptr cinfo)); + /* Format a message string for the most recent JPEG error or message */ + JMETHOD(void, format_message, (j_common_ptr cinfo, char * buffer)); +#define JMSG_LENGTH_MAX 200 /* recommended size of format_message buffer */ + /* Reset error state variables at start of a new image */ + JMETHOD(void, reset_error_mgr, (j_common_ptr cinfo)); + + /* The message ID code and any parameters are saved here. + * A message can have one string parameter or up to 8 int parameters. + */ + int msg_code; +#define JMSG_STR_PARM_MAX 80 + union { + int i[8]; + char s[JMSG_STR_PARM_MAX]; + } msg_parm; + + /* Standard state variables for error facility */ + + int trace_level; /* max msg_level that will be displayed */ + + /* For recoverable corrupt-data errors, we emit a warning message, + * but keep going unless emit_message chooses to abort. emit_message + * should count warnings in num_warnings. The surrounding application + * can check for bad data by seeing if num_warnings is nonzero at the + * end of processing. + */ + long num_warnings; /* number of corrupt-data warnings */ + + /* These fields point to the table(s) of error message strings. + * An application can change the table pointer to switch to a different + * message list (typically, to change the language in which errors are + * reported). Some applications may wish to add additional error codes + * that will be handled by the JPEG library error mechanism; the second + * table pointer is used for this purpose. + * + * First table includes all errors generated by JPEG library itself. + * Error code 0 is reserved for a "no such error string" message. + */ + const char * const * jpeg_message_table; /* Library errors */ + int last_jpeg_message; /* Table contains strings 0..last_jpeg_message */ + /* Second table can be added by application (see cjpeg/djpeg for example). + * It contains strings numbered first_addon_message..last_addon_message. + */ + const char * const * addon_message_table; /* Non-library errors */ + int first_addon_message; /* code for first string in addon table */ + int last_addon_message; /* code for last string in addon table */ +}; + + +/* Progress monitor object */ + +struct jpeg_progress_mgr { + JMETHOD(void, progress_monitor, (j_common_ptr cinfo)); + + long pass_counter; /* work units completed in this pass */ + long pass_limit; /* total number of work units in this pass */ + int completed_passes; /* passes completed so far */ + int total_passes; /* total number of passes expected */ +}; + + +/* Data destination object for compression */ + +struct jpeg_destination_mgr { + JOCTET * next_output_byte; /* => next byte to write in buffer */ + size_t free_in_buffer; /* # of byte spaces remaining in buffer */ + + JMETHOD(void, init_destination, (j_compress_ptr cinfo)); + JMETHOD(boolean, empty_output_buffer, (j_compress_ptr cinfo)); + JMETHOD(void, term_destination, (j_compress_ptr cinfo)); +}; + + +/* Data source object for decompression */ + +struct jpeg_source_mgr { + const JOCTET * next_input_byte; /* => next byte to read from buffer */ + size_t bytes_in_buffer; /* # of bytes remaining in buffer */ + + JMETHOD(void, init_source, (j_decompress_ptr cinfo)); + JMETHOD(boolean, fill_input_buffer, (j_decompress_ptr cinfo)); + JMETHOD(void, skip_input_data, (j_decompress_ptr cinfo, long num_bytes)); + JMETHOD(boolean, resync_to_restart, (j_decompress_ptr cinfo, int desired)); + JMETHOD(void, term_source, (j_decompress_ptr cinfo)); +}; + + +/* Memory manager object. + * Allocates "small" objects (a few K total), "large" objects (tens of K), + * and "really big" objects (virtual arrays with backing store if needed). + * The memory manager does not allow individual objects to be freed; rather, + * each created object is assigned to a pool, and whole pools can be freed + * at once. This is faster and more convenient than remembering exactly what + * to free, especially where malloc()/free() are not too speedy. + * NB: alloc routines never return NULL. They exit to error_exit if not + * successful. + */ + +#define JPOOL_PERMANENT 0 /* lasts until master record is destroyed */ +#define JPOOL_IMAGE 1 /* lasts until done with image/datastream */ +#define JPOOL_NUMPOOLS 2 + +typedef struct jvirt_sarray_control * jvirt_sarray_ptr; +typedef struct jvirt_barray_control * jvirt_barray_ptr; + + +#ifdef C_LOSSLESS_SUPPORTED +#define NEED_DARRAY +#else +#ifdef D_LOSSLESS_SUPPORTED +#define NEED_DARRAY +#endif +#endif + +struct jpeg_memory_mgr { + /* Method pointers */ + JMETHOD(void *, alloc_small, (j_common_ptr cinfo, int pool_id, + size_t sizeofobject)); + JMETHOD(void FAR *, alloc_large, (j_common_ptr cinfo, int pool_id, + size_t sizeofobject)); + JMETHOD(JSAMPARRAY, alloc_sarray, (j_common_ptr cinfo, int pool_id, + JDIMENSION samplesperrow, + JDIMENSION numrows)); + JMETHOD(JBLOCKARRAY, alloc_barray, (j_common_ptr cinfo, int pool_id, + JDIMENSION blocksperrow, + JDIMENSION numrows)); +#ifdef NEED_DARRAY + JMETHOD(JDIFFARRAY, alloc_darray, (j_common_ptr cinfo, int pool_id, + JDIMENSION diffsperrow, + JDIMENSION numrows)); +#endif + JMETHOD(jvirt_sarray_ptr, request_virt_sarray, (j_common_ptr cinfo, + int pool_id, + boolean pre_zero, + JDIMENSION samplesperrow, + JDIMENSION numrows, + JDIMENSION maxaccess)); + JMETHOD(jvirt_barray_ptr, request_virt_barray, (j_common_ptr cinfo, + int pool_id, + boolean pre_zero, + JDIMENSION blocksperrow, + JDIMENSION numrows, + JDIMENSION maxaccess)); + JMETHOD(void, realize_virt_arrays, (j_common_ptr cinfo)); + JMETHOD(JSAMPARRAY, access_virt_sarray, (j_common_ptr cinfo, + jvirt_sarray_ptr ptr, + JDIMENSION start_row, + JDIMENSION num_rows, + boolean writable)); + JMETHOD(JBLOCKARRAY, access_virt_barray, (j_common_ptr cinfo, + jvirt_barray_ptr ptr, + JDIMENSION start_row, + JDIMENSION num_rows, + boolean writable)); + JMETHOD(void, free_pool, (j_common_ptr cinfo, int pool_id)); + JMETHOD(void, self_destruct, (j_common_ptr cinfo)); + + /* Limit on memory allocation for this JPEG object. (Note that this is + * merely advisory, not a guaranteed maximum; it only affects the space + * used for virtual-array buffers.) May be changed by outer application + * after creating the JPEG object. + */ + long max_memory_to_use; + + /* Maximum allocation request accepted by alloc_large. */ + long max_alloc_chunk; +}; + + +/* Routine signature for application-supplied marker processing methods. + * Need not pass marker code since it is stored in cinfo->unread_marker. + */ +typedef JMETHOD(boolean, jpeg_marker_parser_method, (j_decompress_ptr cinfo)); + + +/* Declarations for routines called by application. + * The JPP macro hides prototype parameters from compilers that can't cope. + * Note JPP requires double parentheses. + */ + +#ifdef HAVE_PROTOTYPES +#define JPP(arglist) arglist +#else +#define JPP(arglist) () +#endif + + +/* Short forms of external names for systems with brain-damaged linkers. + * We shorten external names to be unique in the first six letters, which + * is good enough for all known systems. + * (If your compiler itself needs names to be unique in less than 15 + * characters, you are out of luck. Get a better compiler.) + */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_std_error jStdError +#define jpeg_CreateCompress jCreaCompress +#define jpeg_CreateDecompress jCreaDecompress +#define jpeg_destroy_compress jDestCompress +#define jpeg_destroy_decompress jDestDecompress +#define jpeg_stdio_dest jStdDest +#define jpeg_stdio_src jStdSrc +#define jpeg_set_defaults jSetDefaults +#define jpeg_set_colorspace jSetColorspace +#define jpeg_default_colorspace jDefColorspace +#define jpeg_set_quality jSetQuality +#define jpeg_set_linear_quality jSetLQuality +#define jpeg_add_quant_table jAddQuantTable +#define jpeg_quality_scaling jQualityScaling +#define jpeg_simple_lossless jSimLossless +#define jpeg_simple_progression jSimProgress +#define jpeg_suppress_tables jSuppressTables +#define jpeg_alloc_quant_table jAlcQTable +#define jpeg_alloc_huff_table jAlcHTable +#define jpeg_start_compress jStrtCompress +#define jpeg_write_scanlines jWrtScanlines +#define jpeg_finish_compress jFinCompress +#define jpeg_write_raw_data jWrtRawData +#define jpeg_write_marker jWrtMarker +#define jpeg_write_m_header jWrtMHeader +#define jpeg_write_m_byte jWrtMByte +#define jpeg_write_tables jWrtTables +#define jpeg_read_header jReadHeader +#define jpeg_start_decompress jStrtDecompress +#define jpeg_read_scanlines jReadScanlines +#define jpeg_finish_decompress jFinDecompress +#define jpeg_read_raw_data jReadRawData +#define jpeg_has_multiple_scans jHasMultScn +#define jpeg_start_output jStrtOutput +#define jpeg_finish_output jFinOutput +#define jpeg_input_complete jInComplete +#define jpeg_new_colormap jNewCMap +#define jpeg_consume_input jConsumeInput +#define jpeg_calc_output_dimensions jCalcDimensions +#define jpeg_save_markers jSaveMarkers +#define jpeg_set_marker_processor jSetMarker +#define jpeg_read_coefficients jReadCoefs +#define jpeg_write_coefficients jWrtCoefs +#define jpeg_copy_critical_parameters jCopyCrit +#define jpeg_abort_compress jAbrtCompress +#define jpeg_abort_decompress jAbrtDecompress +#define jpeg_abort jAbort +#define jpeg_destroy jDestroy +#define jpeg_resync_to_restart jResyncRestart +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* Default error-management setup */ +EXTERN(struct jpeg_error_mgr *) jpeg_std_error + JPP((struct jpeg_error_mgr * err)); + +/* Initialization of JPEG compression objects. + * jpeg_create_compress() and jpeg_create_decompress() are the exported + * names that applications should call. These expand to calls on + * jpeg_CreateCompress and jpeg_CreateDecompress with additional information + * passed for version mismatch checking. + * NB: you must set up the error-manager BEFORE calling jpeg_create_xxx. + */ +#define jpeg_create_compress(cinfo) \ + jpeg_CreateCompress((cinfo), JPEG_LIB_VERSION, \ + (size_t) sizeof(struct jpeg_compress_struct)) +#define jpeg_create_decompress(cinfo) \ + jpeg_CreateDecompress((cinfo), JPEG_LIB_VERSION, \ + (size_t) sizeof(struct jpeg_decompress_struct)) +EXTERN(void) jpeg_CreateCompress JPP((j_compress_ptr cinfo, + int version, size_t structsize)); +EXTERN(void) jpeg_CreateDecompress JPP((j_decompress_ptr cinfo, + int version, size_t structsize)); +/* Destruction of JPEG compression objects */ +EXTERN(void) jpeg_destroy_compress JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_destroy_decompress JPP((j_decompress_ptr cinfo)); + +/* Standard data source and destination managers: stdio streams. */ +/* Caller is responsible for opening the file before and closing after. */ +EXTERN(void) jpeg_stdio_dest JPP((j_compress_ptr cinfo, FILE * outfile)); +EXTERN(void) jpeg_stdio_src JPP((j_decompress_ptr cinfo, FILE * infile)); + +/* Default parameter setup for compression */ +EXTERN(void) jpeg_set_defaults JPP((j_compress_ptr cinfo)); +/* Compression parameter setup aids */ +EXTERN(void) jpeg_set_colorspace JPP((j_compress_ptr cinfo, + J_COLOR_SPACE colorspace)); +EXTERN(void) jpeg_default_colorspace JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_set_quality JPP((j_compress_ptr cinfo, int quality, + boolean force_baseline)); +EXTERN(void) jpeg_set_linear_quality JPP((j_compress_ptr cinfo, + int scale_factor, + boolean force_baseline)); +EXTERN(void) jpeg_add_quant_table JPP((j_compress_ptr cinfo, int which_tbl, + const unsigned int *basic_table, + int scale_factor, + boolean force_baseline)); +EXTERN(int) jpeg_quality_scaling JPP((int quality)); +EXTERN(void) jpeg_simple_lossless JPP((j_compress_ptr cinfo, + int predictor, int point_transform)); +EXTERN(void) jpeg_simple_progression JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_suppress_tables JPP((j_compress_ptr cinfo, + boolean suppress)); +EXTERN(JQUANT_TBL *) jpeg_alloc_quant_table JPP((j_common_ptr cinfo)); +EXTERN(JHUFF_TBL *) jpeg_alloc_huff_table JPP((j_common_ptr cinfo)); + +/* Main entry points for compression */ +EXTERN(void) jpeg_start_compress JPP((j_compress_ptr cinfo, + boolean write_all_tables)); +EXTERN(JDIMENSION) jpeg_write_scanlines JPP((j_compress_ptr cinfo, + JSAMPARRAY scanlines, + JDIMENSION num_lines)); +EXTERN(void) jpeg_finish_compress JPP((j_compress_ptr cinfo)); + +/* Replaces jpeg_write_scanlines when writing raw downsampled data. */ +EXTERN(JDIMENSION) jpeg_write_raw_data JPP((j_compress_ptr cinfo, + JSAMPIMAGE data, + JDIMENSION num_lines)); + +/* Write a special marker. See libjpeg.doc concerning safe usage. */ +EXTERN(void) jpeg_write_marker + JPP((j_compress_ptr cinfo, int marker, + const JOCTET * dataptr, unsigned int datalen)); +/* Same, but piecemeal. */ +EXTERN(void) jpeg_write_m_header + JPP((j_compress_ptr cinfo, int marker, unsigned int datalen)); +EXTERN(void) jpeg_write_m_byte + JPP((j_compress_ptr cinfo, int val)); + +/* Alternate compression function: just write an abbreviated table file */ +EXTERN(void) jpeg_write_tables JPP((j_compress_ptr cinfo)); + +/* Decompression startup: read start of JPEG datastream to see what's there */ +EXTERN(int) jpeg_read_header JPP((j_decompress_ptr cinfo, + boolean require_image)); +/* Return value is one of: */ +#define JPEG_SUSPENDED 0 /* Suspended due to lack of input data */ +#define JPEG_HEADER_OK 1 /* Found valid image datastream */ +#define JPEG_HEADER_TABLES_ONLY 2 /* Found valid table-specs-only datastream */ +/* If you pass require_image = TRUE (normal case), you need not check for + * a TABLES_ONLY return code; an abbreviated file will cause an error exit. + * JPEG_SUSPENDED is only possible if you use a data source module that can + * give a suspension return (the stdio source module doesn't). + */ + +/* Main entry points for decompression */ +EXTERN(boolean) jpeg_start_decompress JPP((j_decompress_ptr cinfo)); +EXTERN(JDIMENSION) jpeg_read_scanlines JPP((j_decompress_ptr cinfo, + JSAMPARRAY scanlines, + JDIMENSION max_lines)); +EXTERN(boolean) jpeg_finish_decompress JPP((j_decompress_ptr cinfo)); + +/* Replaces jpeg_read_scanlines when reading raw downsampled data. */ +EXTERN(JDIMENSION) jpeg_read_raw_data JPP((j_decompress_ptr cinfo, + JSAMPIMAGE data, + JDIMENSION max_lines)); + +/* Additional entry points for buffered-image mode. */ +EXTERN(boolean) jpeg_has_multiple_scans JPP((j_decompress_ptr cinfo)); +EXTERN(boolean) jpeg_start_output JPP((j_decompress_ptr cinfo, + int scan_number)); +EXTERN(boolean) jpeg_finish_output JPP((j_decompress_ptr cinfo)); +EXTERN(boolean) jpeg_input_complete JPP((j_decompress_ptr cinfo)); +EXTERN(void) jpeg_new_colormap JPP((j_decompress_ptr cinfo)); +EXTERN(int) jpeg_consume_input JPP((j_decompress_ptr cinfo)); +/* Return value is one of: */ +/* #define JPEG_SUSPENDED 0 Suspended due to lack of input data */ +#define JPEG_REACHED_SOS 1 /* Reached start of new scan */ +#define JPEG_REACHED_EOI 2 /* Reached end of image */ +#define JPEG_ROW_COMPLETED 3 /* Completed one iMCU row */ +#define JPEG_SCAN_COMPLETED 4 /* Completed last iMCU row of a scan */ + +/* Precalculate output dimensions for current decompression parameters. */ +EXTERN(void) jpeg_calc_output_dimensions JPP((j_decompress_ptr cinfo)); + +/* Control saving of COM and APPn markers into marker_list. */ +EXTERN(void) jpeg_save_markers + JPP((j_decompress_ptr cinfo, int marker_code, + unsigned int length_limit)); + +/* Install a special processing method for COM or APPn markers. */ +EXTERN(void) jpeg_set_marker_processor + JPP((j_decompress_ptr cinfo, int marker_code, + jpeg_marker_parser_method routine)); + +/* Read or write raw DCT coefficients --- useful for lossless transcoding. */ +EXTERN(jvirt_barray_ptr *) jpeg_read_coefficients JPP((j_decompress_ptr cinfo)); +EXTERN(void) jpeg_write_coefficients JPP((j_compress_ptr cinfo, + jvirt_barray_ptr * coef_arrays)); +EXTERN(void) jpeg_copy_critical_parameters JPP((j_decompress_ptr srcinfo, + j_compress_ptr dstinfo)); + +/* If you choose to abort compression or decompression before completing + * jpeg_finish_(de)compress, then you need to clean up to release memory, + * temporary files, etc. You can just call jpeg_destroy_(de)compress + * if you're done with the JPEG object, but if you want to clean it up and + * reuse it, call this: + */ +EXTERN(void) jpeg_abort_compress JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_abort_decompress JPP((j_decompress_ptr cinfo)); + +/* Generic versions of jpeg_abort and jpeg_destroy that work on either + * flavor of JPEG object. These may be more convenient in some places. + */ +EXTERN(void) jpeg_abort JPP((j_common_ptr cinfo)); +EXTERN(void) jpeg_destroy JPP((j_common_ptr cinfo)); + +/* Default restart-marker-resync procedure for use by data source modules */ +EXTERN(boolean) jpeg_resync_to_restart JPP((j_decompress_ptr cinfo, + int desired)); + + +/* These marker codes are exported since applications and data source modules + * are likely to want to use them. + */ + +#define JPEG_RST0 0xD0 /* RST0 marker code */ +#define JPEG_EOI 0xD9 /* EOI marker code */ +#define JPEG_APP0 0xE0 /* APP0 marker code */ +#define JPEG_COM 0xFE /* COM marker code */ + + +/* If we have a brain-damaged compiler that emits warnings (or worse, errors) + * for structure definitions that are never filled in, keep it quiet by + * supplying dummy definitions for the various substructures. + */ + +#ifdef INCOMPLETE_TYPES_BROKEN +#ifndef JPEG_INTERNALS /* will be defined in jpegint.h */ +struct jvirt_sarray_control { long dummy; }; +struct jvirt_barray_control { long dummy; }; +struct jpeg_comp_master { long dummy; }; +struct jpeg_c_main_controller { long dummy; }; +struct jpeg_c_prep_controller { long dummy; }; +struct jpeg_c_coef_controller { long dummy; }; +struct jpeg_marker_writer { long dummy; }; +struct jpeg_color_converter { long dummy; }; +struct jpeg_downsampler { long dummy; }; +struct jpeg_forward_dct { long dummy; }; +struct jpeg_entropy_encoder { long dummy; }; +struct jpeg_decomp_master { long dummy; }; +struct jpeg_d_main_controller { long dummy; }; +struct jpeg_d_coef_controller { long dummy; }; +struct jpeg_d_post_controller { long dummy; }; +struct jpeg_input_controller { long dummy; }; +struct jpeg_marker_reader { long dummy; }; +struct jpeg_entropy_decoder { long dummy; }; +struct jpeg_inverse_dct { long dummy; }; +struct jpeg_upsampler { long dummy; }; +struct jpeg_color_deconverter { long dummy; }; +struct jpeg_color_quantizer { long dummy; }; +#endif /* JPEG_INTERNALS */ +#endif /* INCOMPLETE_TYPES_BROKEN */ + + +/* + * The JPEG library modules define JPEG_INTERNALS before including this file. + * The internal structure declarations are read only when that is true. + * Applications using the library should not include jpegint.h, but may wish + * to include jerror.h. + */ + +#ifdef JPEG_INTERNALS +#include "jpegint.h" /* fetch private declarations */ +#include "jerror.h" /* fetch error codes too */ +#endif + +#endif /* JPEGLIB_H */ diff --git a/gdcm/Utilities/gdcmjpeg/jquant1.c b/gdcm/Utilities/gdcmjpeg/jquant1.c new file mode 100644 index 0000000..8f3d8c2 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jquant1.c @@ -0,0 +1,860 @@ +/* + * jquant1.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains 1-pass color quantization (color mapping) routines. + * These routines provide mapping to a fixed color map using equally spaced + * color values. Optional Floyd-Steinberg or ordered dithering is available. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + +#ifdef QUANT_1PASS_SUPPORTED + + +/* + * The main purpose of 1-pass quantization is to provide a fast, if not very + * high quality, colormapped output capability. A 2-pass quantizer usually + * gives better visual quality; however, for quantized grayscale output this + * quantizer is perfectly adequate. Dithering is highly recommended with this + * quantizer, though you can turn it off if you really want to. + * + * In 1-pass quantization the colormap must be chosen in advance of seeing the + * image. We use a map consisting of all combinations of Ncolors[i] color + * values for the i'th component. The Ncolors[] values are chosen so that + * their product, the total number of colors, is no more than that requested. + * (In most cases, the product will be somewhat less.) + * + * Since the colormap is orthogonal, the representative value for each color + * component can be determined without considering the other components; + * then these indexes can be combined into a colormap index by a standard + * N-dimensional-array-subscript calculation. Most of the arithmetic involved + * can be precalculated and stored in the lookup table colorindex[]. + * colorindex[i][j] maps pixel value j in component i to the nearest + * representative value (grid plane) for that component; this index is + * multiplied by the array stride for component i, so that the + * index of the colormap entry closest to a given pixel value is just + * sum( colorindex[component-number][pixel-component-value] ) + * Aside from being fast, this scheme allows for variable spacing between + * representative values with no additional lookup cost. + * + * If gamma correction has been applied in color conversion, it might be wise + * to adjust the color grid spacing so that the representative colors are + * equidistant in linear space. At this writing, gamma correction is not + * implemented by jdcolor, so nothing is done here. + */ + + +/* Declarations for ordered dithering. + * + * We use a standard 16x16 ordered dither array. The basic concept of ordered + * dithering is described in many references, for instance Dale Schumacher's + * chapter II.2 of Graphics Gems II (James Arvo, ed. Academic Press, 1991). + * In place of Schumacher's comparisons against a "threshold" value, we add a + * "dither" value to the input pixel and then round the result to the nearest + * output value. The dither value is equivalent to (0.5 - threshold) times + * the distance between output values. For ordered dithering, we assume that + * the output colors are equally spaced; if not, results will probably be + * worse, since the dither may be too much or too little at a given point. + * + * The normal calculation would be to form pixel value + dither, range-limit + * this to 0..MAXJSAMPLE, and then index into the colorindex table as usual. + * We can skip the separate range-limiting step by extending the colorindex + * table in both directions. + */ + +#define ODITHER_SIZE 16 /* dimension of dither matrix */ +/* NB: if ODITHER_SIZE is not a power of 2, ODITHER_MASK uses will break */ +#define ODITHER_CELLS (ODITHER_SIZE*ODITHER_SIZE) /* # cells in matrix */ +#define ODITHER_MASK (ODITHER_SIZE-1) /* mask for wrapping around counters */ + +typedef int ODITHER_MATRIX[ODITHER_SIZE][ODITHER_SIZE]; +typedef int (*ODITHER_MATRIX_PTR)[ODITHER_SIZE]; + +static const UINT8 base_dither_matrix[ODITHER_SIZE][ODITHER_SIZE] = { + /* Bayer's order-4 dither array. Generated by the code given in + * Stephen Hawley's article "Ordered Dithering" in Graphics Gems I. + * The values in this array must range from 0 to ODITHER_CELLS-1. + */ + { 0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255 }, + { 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 }, + { 32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223 }, + { 160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95 }, + { 8,200, 56,248, 4,196, 52,244, 11,203, 59,251, 7,199, 55,247 }, + { 136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119 }, + { 40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215 }, + { 168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87 }, + { 2,194, 50,242, 14,206, 62,254, 1,193, 49,241, 13,205, 61,253 }, + { 130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125 }, + { 34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221 }, + { 162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93 }, + { 10,202, 58,250, 6,198, 54,246, 9,201, 57,249, 5,197, 53,245 }, + { 138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117 }, + { 42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213 }, + { 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85 } +}; + + +/* Declarations for Floyd-Steinberg dithering. + * + * Errors are accumulated into the array fserrors[], at a resolution of + * 1/16th of a pixel count. The error at a given pixel is propagated + * to its not-yet-processed neighbors using the standard F-S fractions, + * ... (here) 7/16 + * 3/16 5/16 1/16 + * We work left-to-right on even rows, right-to-left on odd rows. + * + * We can get away with a single array (holding one row's worth of errors) + * by using it to store the current row's errors at pixel columns not yet + * processed, but the next row's errors at columns already processed. We + * need only a few extra variables to hold the errors immediately around the + * current column. (If we are lucky, those variables are in registers, but + * even if not, they're probably cheaper to access than array elements are.) + * + * The fserrors[] array is indexed [component#][position]. + * We provide (#columns + 2) entries per component; the extra entry at each + * end saves us from special-casing the first and last pixels. + * + * Note: on a wide image, we might not have enough room in a PC's near data + * segment to hold the error array; so it is allocated with alloc_large. + */ + +#if BITS_IN_JSAMPLE == 8 +typedef INT16 FSERROR; /* 16 bits should be enough */ +typedef int LOCFSERROR; /* use 'int' for calculation temps */ +#else +typedef INT32 FSERROR; /* may need more than 16 bits */ +typedef INT32 LOCFSERROR; /* be sure calculation temps are big enough */ +#endif + +typedef FSERROR FAR *FSERRPTR; /* pointer to error array (in FAR storage!) */ + + +/* Private subobject */ + +#define MAX_Q_COMPS 4 /* max components I can handle */ + +typedef struct { + struct jpeg_color_quantizer pub; /* public fields */ + + /* Initially allocated colormap is saved here */ + JSAMPARRAY sv_colormap; /* The color map as a 2-D pixel array */ + int sv_actual; /* number of entries in use */ + + JSAMPARRAY colorindex; /* Precomputed mapping for speed */ + /* colorindex[i][j] = index of color closest to pixel value j in component i, + * premultiplied as described above. Since colormap indexes must fit into + * JSAMPLEs, the entries of this array will too. + */ + boolean is_padded; /* is the colorindex padded for odither? */ + + int Ncolors[MAX_Q_COMPS]; /* # of values alloced to each component */ + + /* Variables for ordered dithering */ + int row_index; /* cur row's vertical index in dither matrix */ + ODITHER_MATRIX_PTR odither[MAX_Q_COMPS]; /* one dither array per component */ + + /* Variables for Floyd-Steinberg dithering */ + FSERRPTR fserrors[MAX_Q_COMPS]; /* accumulated errors */ + boolean on_odd_row; /* flag to remember which row we are on */ +} my_cquantizer; + +typedef my_cquantizer * my_cquantize_ptr; + + +/* + * Policy-making subroutines for create_colormap and create_colorindex. + * These routines determine the colormap to be used. The rest of the module + * only assumes that the colormap is orthogonal. + * + * * select_ncolors decides how to divvy up the available colors + * among the components. + * * output_value defines the set of representative values for a component. + * * largest_input_value defines the mapping from input values to + * representative values for a component. + * Note that the latter two routines may impose different policies for + * different components, though this is not currently done. + */ + + +LOCAL(int) +select_ncolors (j_decompress_ptr cinfo, int Ncolors[]) +/* Determine allocation of desired colors to components, */ +/* and fill in Ncolors[] array to indicate choice. */ +/* Return value is total number of colors (product of Ncolors[] values). */ +{ + int nc = cinfo->out_color_components; /* number of color components */ + int max_colors = cinfo->desired_number_of_colors; + int total_colors, iroot, i, j; + boolean changed; + long temp; + static const int RGB_order[3] = { RGB_GREEN, RGB_RED, RGB_BLUE }; + + /* We can allocate at least the nc'th root of max_colors per component. */ + /* Compute floor(nc'th root of max_colors). */ + iroot = 1; + do { + iroot++; + temp = iroot; /* set temp = iroot ** nc */ + for (i = 1; i < nc; i++) + temp *= iroot; + } while (temp <= (long) max_colors); /* repeat till iroot exceeds root */ + iroot--; /* now iroot = floor(root) */ + + /* Must have at least 2 color values per component */ + if (iroot < 2) + ERREXIT1(cinfo, JERR_QUANT_FEW_COLORS, (int) temp); + + /* Initialize to iroot color values for each component */ + total_colors = 1; + for (i = 0; i < nc; i++) { + Ncolors[i] = iroot; + total_colors *= iroot; + } + /* We may be able to increment the count for one or more components without + * exceeding max_colors, though we know not all can be incremented. + * Sometimes, the first component can be incremented more than once! + * (Example: for 16 colors, we start at 2*2*2, go to 3*2*2, then 4*2*2.) + * In RGB colorspace, try to increment G first, then R, then B. + */ + do { + changed = FALSE; + for (i = 0; i < nc; i++) { + j = (cinfo->out_color_space == JCS_RGB ? RGB_order[i] : i); + /* calculate new total_colors if Ncolors[j] is incremented */ + temp = total_colors / Ncolors[j]; + temp *= Ncolors[j]+1; /* done in long arith to avoid oflo */ + if (temp > (long) max_colors) + break; /* won't fit, done with this pass */ + Ncolors[j]++; /* OK, apply the increment */ + total_colors = (int) temp; + changed = TRUE; + } + } while (changed); + + return total_colors; +} + + +LOCAL(int) +output_value (j_decompress_ptr cinfo, int ci, int j, int maxj) +/* Return j'th output value, where j will range from 0 to maxj */ +/* The output values must fall in 0..MAXJSAMPLE in increasing order */ +{ + (void)cinfo;(void)ci; + /* We always provide values 0 and MAXJSAMPLE for each component; + * any additional values are equally spaced between these limits. + * (Forcing the upper and lower values to the limits ensures that + * dithering can't produce a color outside the selected gamut.) + */ + return (int) (((INT32) j * MAXJSAMPLE + maxj/2) / maxj); +} + + +LOCAL(int) +largest_input_value (j_decompress_ptr cinfo, int ci, int j, int maxj) +/* Return largest input value that should map to j'th output value */ +/* Must have largest(j=0) >= 0, and largest(j=maxj) >= MAXJSAMPLE */ +{ + (void)cinfo;(void)ci; + /* Breakpoints are halfway between values returned by output_value */ + return (int) (((INT32) (2*j + 1) * MAXJSAMPLE + maxj) / (2*maxj)); +} + + +/* + * Create the colormap. + */ + +LOCAL(void) +create_colormap (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + JSAMPARRAY colormap; /* Created colormap */ + int total_colors; /* Number of distinct output colors */ + int i,j,k, nci, blksize, blkdist, ptr, val; + + /* Select number of colors for each component */ + total_colors = select_ncolors(cinfo, cquantize->Ncolors); + + /* Report selected color counts */ + if (cinfo->out_color_components == 3) + TRACEMS4(cinfo, 1, JTRC_QUANT_3_NCOLORS, + total_colors, cquantize->Ncolors[0], + cquantize->Ncolors[1], cquantize->Ncolors[2]); + else + TRACEMS1(cinfo, 1, JTRC_QUANT_NCOLORS, total_colors); + + /* Allocate and fill in the colormap. */ + /* The colors are ordered in the map in standard row-major order, */ + /* i.e. rightmost (highest-indexed) color changes most rapidly. */ + + colormap = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) total_colors, (JDIMENSION) cinfo->out_color_components); + + /* blksize is number of adjacent repeated entries for a component */ + /* blkdist is distance between groups of identical entries for a component */ + blkdist = total_colors; + + for (i = 0; i < cinfo->out_color_components; i++) { + /* fill in colormap entries for i'th color component */ + nci = cquantize->Ncolors[i]; /* # of distinct values for this color */ + blksize = blkdist / nci; + for (j = 0; j < nci; j++) { + /* Compute j'th output value (out of nci) for component */ + val = output_value(cinfo, i, j, nci-1); + /* Fill in all colormap entries that have this value of this component */ + for (ptr = j * blksize; ptr < total_colors; ptr += blkdist) { + /* fill in blksize entries beginning at ptr */ + for (k = 0; k < blksize; k++) + colormap[i][ptr+k] = (JSAMPLE) val; + } + } + blkdist = blksize; /* blksize of this color is blkdist of next */ + } + + /* Save the colormap in private storage, + * where it will survive color quantization mode changes. + */ + cquantize->sv_colormap = colormap; + cquantize->sv_actual = total_colors; +} + + +/* + * Create the color index table. + */ + +LOCAL(void) +create_colorindex (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + JSAMPROW indexptr; + int i,j,k, nci, blksize, val, pad; + + /* For ordered dither, we pad the color index tables by MAXJSAMPLE in + * each direction (input index values can be -MAXJSAMPLE .. 2*MAXJSAMPLE). + * This is not necessary in the other dithering modes. However, we + * flag whether it was done in case user changes dithering mode. + */ + if (cinfo->dither_mode == JDITHER_ORDERED) { + pad = MAXJSAMPLE*2; + cquantize->is_padded = TRUE; + } else { + pad = 0; + cquantize->is_padded = FALSE; + } + + cquantize->colorindex = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) (MAXJSAMPLE+1 + pad), + (JDIMENSION) cinfo->out_color_components); + + /* blksize is number of adjacent repeated entries for a component */ + blksize = cquantize->sv_actual; + + for (i = 0; i < cinfo->out_color_components; i++) { + /* fill in colorindex entries for i'th color component */ + nci = cquantize->Ncolors[i]; /* # of distinct values for this color */ + blksize = blksize / nci; + + /* adjust colorindex pointers to provide padding at negative indexes. */ + if (pad) + cquantize->colorindex[i] += MAXJSAMPLE; + + /* in loop, val = index of current output value, */ + /* and k = largest j that maps to current val */ + indexptr = cquantize->colorindex[i]; + val = 0; + k = largest_input_value(cinfo, i, 0, nci-1); + for (j = 0; j <= MAXJSAMPLE; j++) { + while (j > k) /* advance val if past boundary */ + k = largest_input_value(cinfo, i, ++val, nci-1); + /* premultiply so that no multiplication needed in main processing */ + indexptr[j] = (JSAMPLE) (val * blksize); + } + /* Pad at both ends if necessary */ + if (pad) + for (j = 1; j <= MAXJSAMPLE; j++) { + indexptr[-j] = indexptr[0]; + indexptr[MAXJSAMPLE+j] = indexptr[MAXJSAMPLE]; + } + } +} + + +/* + * Create an ordered-dither array for a component having ncolors + * distinct output values. + */ + +LOCAL(ODITHER_MATRIX_PTR) +make_odither_array (j_decompress_ptr cinfo, int ncolors) +{ + ODITHER_MATRIX_PTR odither; + int j,k; + INT32 num,den; + + odither = (ODITHER_MATRIX_PTR) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(ODITHER_MATRIX)); + /* The inter-value distance for this color is MAXJSAMPLE/(ncolors-1). + * Hence the dither value for the matrix cell with fill order f + * (f=0..N-1) should be (N-1-2*f)/(2*N) * MAXJSAMPLE/(ncolors-1). + * On 16-bit-int machine, be careful to avoid overflow. + */ + den = 2 * ODITHER_CELLS * ((INT32) (ncolors - 1)); + for (j = 0; j < ODITHER_SIZE; j++) { + for (k = 0; k < ODITHER_SIZE; k++) { + num = ((INT32) (ODITHER_CELLS-1 - 2*((int)base_dither_matrix[j][k]))) + * MAXJSAMPLE; + /* Ensure round towards zero despite C's lack of consistency + * about rounding negative values in integer division... + */ + odither[j][k] = (int) (num<0 ? -((-num)/den) : num/den); + } + } + return odither; +} + + +/* + * Create the ordered-dither tables. + * Components having the same number of representative colors may + * share a dither table. + */ + +LOCAL(void) +create_odither_tables (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + ODITHER_MATRIX_PTR odither; + int i, j, nci; + + for (i = 0; i < cinfo->out_color_components; i++) { + nci = cquantize->Ncolors[i]; /* # of distinct values for this color */ + odither = NULL; /* search for matching prior component */ + for (j = 0; j < i; j++) { + if (nci == cquantize->Ncolors[j]) { + odither = cquantize->odither[j]; + break; + } + } + if (odither == NULL) /* need a new table? */ + odither = make_odither_array(cinfo, nci); + cquantize->odither[i] = odither; + } +} + + +/* + * Map some rows of pixels to the output colormapped representation. + */ + +METHODDEF(void) +color_quantize (j_decompress_ptr cinfo, JSAMPARRAY input_buf, + JSAMPARRAY output_buf, int num_rows) +/* General case, no dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + JSAMPARRAY colorindex = cquantize->colorindex; + register int pixcode, ci; + register JSAMPROW ptrin, ptrout; + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + register int nc = cinfo->out_color_components; + + for (row = 0; row < num_rows; row++) { + ptrin = input_buf[row]; + ptrout = output_buf[row]; + for (col = width; col > 0; col--) { + pixcode = 0; + for (ci = 0; ci < nc; ci++) { + pixcode += GETJSAMPLE(colorindex[ci][GETJSAMPLE(*ptrin++)]); + } + *ptrout++ = (JSAMPLE) pixcode; + } + } +} + + +METHODDEF(void) +color_quantize3 (j_decompress_ptr cinfo, JSAMPARRAY input_buf, + JSAMPARRAY output_buf, int num_rows) +/* Fast path for out_color_components==3, no dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + register int pixcode; + register JSAMPROW ptrin, ptrout; + JSAMPROW colorindex0 = cquantize->colorindex[0]; + JSAMPROW colorindex1 = cquantize->colorindex[1]; + JSAMPROW colorindex2 = cquantize->colorindex[2]; + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + + for (row = 0; row < num_rows; row++) { + ptrin = input_buf[row]; + ptrout = output_buf[row]; + for (col = width; col > 0; col--) { + pixcode = GETJSAMPLE(colorindex0[GETJSAMPLE(*ptrin++)]); + pixcode += GETJSAMPLE(colorindex1[GETJSAMPLE(*ptrin++)]); + pixcode += GETJSAMPLE(colorindex2[GETJSAMPLE(*ptrin++)]); + *ptrout++ = (JSAMPLE) pixcode; + } + } +} + + +METHODDEF(void) +quantize_ord_dither (j_decompress_ptr cinfo, JSAMPARRAY input_buf, + JSAMPARRAY output_buf, int num_rows) +/* General case, with ordered dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + register JSAMPROW input_ptr; + register JSAMPROW output_ptr; + JSAMPROW colorindex_ci; + int * dither; /* points to active row of dither matrix */ + int row_index, col_index; /* current indexes into dither matrix */ + int nc = cinfo->out_color_components; + int ci; + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + + for (row = 0; row < num_rows; row++) { + /* Initialize output values to 0 so can process components separately */ + jzero_far((void FAR *) output_buf[row], + (size_t) (width * SIZEOF(JSAMPLE))); + row_index = cquantize->row_index; + for (ci = 0; ci < nc; ci++) { + input_ptr = input_buf[row] + ci; + output_ptr = output_buf[row]; + colorindex_ci = cquantize->colorindex[ci]; + dither = cquantize->odither[ci][row_index]; + col_index = 0; + + for (col = width; col > 0; col--) { + /* Form pixel value + dither, range-limit to 0..MAXJSAMPLE, + * select output value, accumulate into output code for this pixel. + * Range-limiting need not be done explicitly, as we have extended + * the colorindex table to produce the right answers for out-of-range + * inputs. The maximum dither is +- MAXJSAMPLE; this sets the + * required amount of padding. + */ + *output_ptr += colorindex_ci[GETJSAMPLE(*input_ptr)+dither[col_index]]; + input_ptr += nc; + output_ptr++; + col_index = (col_index + 1) & ODITHER_MASK; + } + } + /* Advance row index for next row */ + row_index = (row_index + 1) & ODITHER_MASK; + cquantize->row_index = row_index; + } +} + + +METHODDEF(void) +quantize3_ord_dither (j_decompress_ptr cinfo, JSAMPARRAY input_buf, + JSAMPARRAY output_buf, int num_rows) +/* Fast path for out_color_components==3, with ordered dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + register int pixcode; + register JSAMPROW input_ptr; + register JSAMPROW output_ptr; + JSAMPROW colorindex0 = cquantize->colorindex[0]; + JSAMPROW colorindex1 = cquantize->colorindex[1]; + JSAMPROW colorindex2 = cquantize->colorindex[2]; + int * dither0; /* points to active row of dither matrix */ + int * dither1; + int * dither2; + int row_index, col_index; /* current indexes into dither matrix */ + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + + for (row = 0; row < num_rows; row++) { + row_index = cquantize->row_index; + input_ptr = input_buf[row]; + output_ptr = output_buf[row]; + dither0 = cquantize->odither[0][row_index]; + dither1 = cquantize->odither[1][row_index]; + dither2 = cquantize->odither[2][row_index]; + col_index = 0; + + for (col = width; col > 0; col--) { + pixcode = GETJSAMPLE(colorindex0[GETJSAMPLE(*input_ptr++) + + dither0[col_index]]); + pixcode += GETJSAMPLE(colorindex1[GETJSAMPLE(*input_ptr++) + + dither1[col_index]]); + pixcode += GETJSAMPLE(colorindex2[GETJSAMPLE(*input_ptr++) + + dither2[col_index]]); + *output_ptr++ = (JSAMPLE) pixcode; + col_index = (col_index + 1) & ODITHER_MASK; + } + row_index = (row_index + 1) & ODITHER_MASK; + cquantize->row_index = row_index; + } +} + + +METHODDEF(void) +quantize_fs_dither (j_decompress_ptr cinfo, JSAMPARRAY input_buf, + JSAMPARRAY output_buf, int num_rows) +/* General case, with Floyd-Steinberg dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + register LOCFSERROR cur; /* current error or pixel value */ + LOCFSERROR belowerr; /* error for pixel below cur */ + LOCFSERROR bpreverr; /* error for below/prev col */ + LOCFSERROR bnexterr; /* error for below/next col */ + LOCFSERROR delta; + register FSERRPTR errorptr; /* => fserrors[] at column before current */ + register JSAMPROW input_ptr; + register JSAMPROW output_ptr; + JSAMPROW colorindex_ci; + JSAMPROW colormap_ci; + int pixcode; + int nc = cinfo->out_color_components; + int dir; /* 1 for left-to-right, -1 for right-to-left */ + int dirnc; /* dir * nc */ + int ci; + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + JSAMPLE *range_limit = cinfo->sample_range_limit; + SHIFT_TEMPS + + for (row = 0; row < num_rows; row++) { + /* Initialize output values to 0 so can process components separately */ + jzero_far((void FAR *) output_buf[row], + (size_t) (width * SIZEOF(JSAMPLE))); + for (ci = 0; ci < nc; ci++) { + input_ptr = input_buf[row] + ci; + output_ptr = output_buf[row]; + if (cquantize->on_odd_row) { + /* work right to left in this row */ + input_ptr += (width-1) * nc; /* so point to rightmost pixel */ + output_ptr += width-1; + dir = -1; + dirnc = -nc; + errorptr = cquantize->fserrors[ci] + (width+1); /* => entry after last column */ + } else { + /* work left to right in this row */ + dir = 1; + dirnc = nc; + errorptr = cquantize->fserrors[ci]; /* => entry before first column */ + } + colorindex_ci = cquantize->colorindex[ci]; + colormap_ci = cquantize->sv_colormap[ci]; + /* Preset error values: no error propagated to first pixel from left */ + cur = 0; + /* and no error propagated to row below yet */ + belowerr = bpreverr = 0; + + for (col = width; col > 0; col--) { + /* cur holds the error propagated from the previous pixel on the + * current line. Add the error propagated from the previous line + * to form the complete error correction term for this pixel, and + * round the error term (which is expressed * 16) to an integer. + * RIGHT_SHIFT rounds towards minus infinity, so adding 8 is correct + * for either sign of the error value. + * Note: errorptr points to *previous* column's array entry. + */ + cur = RIGHT_SHIFT(cur + errorptr[dir] + 8, 4); + /* Form pixel value + error, and range-limit to 0..MAXJSAMPLE. + * The maximum error is +- MAXJSAMPLE; this sets the required size + * of the range_limit array. + */ + cur += GETJSAMPLE(*input_ptr); + cur = GETJSAMPLE(range_limit[cur]); + /* Select output value, accumulate into output code for this pixel */ + pixcode = GETJSAMPLE(colorindex_ci[cur]); + *output_ptr += (JSAMPLE) pixcode; + /* Compute actual representation error at this pixel */ + /* Note: we can do this even though we don't have the final */ + /* pixel code, because the colormap is orthogonal. */ + cur -= GETJSAMPLE(colormap_ci[pixcode]); + /* Compute error fractions to be propagated to adjacent pixels. + * Add these into the running sums, and simultaneously shift the + * next-line error sums left by 1 column. + */ + bnexterr = cur; + delta = cur * 2; + cur += delta; /* form error * 3 */ + errorptr[0] = (FSERROR) (bpreverr + cur); + cur += delta; /* form error * 5 */ + bpreverr = belowerr + cur; + belowerr = bnexterr; + cur += delta; /* form error * 7 */ + /* At this point cur contains the 7/16 error value to be propagated + * to the next pixel on the current line, and all the errors for the + * next line have been shifted over. We are therefore ready to move on. + */ + input_ptr += dirnc; /* advance input ptr to next column */ + output_ptr += dir; /* advance output ptr to next column */ + errorptr += dir; /* advance errorptr to current column */ + } + /* Post-loop cleanup: we must unload the final error value into the + * final fserrors[] entry. Note we need not unload belowerr because + * it is for the dummy column before or after the actual array. + */ + errorptr[0] = (FSERROR) bpreverr; /* unload prev err into array */ + } + cquantize->on_odd_row = (cquantize->on_odd_row ? FALSE : TRUE); + } +} + + +/* + * Allocate workspace for Floyd-Steinberg errors. + */ + +LOCAL(void) +alloc_fs_workspace (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + size_t arraysize; + int i; + + arraysize = (size_t) ((cinfo->output_width + 2) * SIZEOF(FSERROR)); + for (i = 0; i < cinfo->out_color_components; i++) { + cquantize->fserrors[i] = (FSERRPTR) + (*cinfo->mem->alloc_large)((j_common_ptr) cinfo, JPOOL_IMAGE, arraysize); + } +} + + +/* + * Initialize for one-pass color quantization. + */ + +METHODDEF(void) +start_pass_1_quant (j_decompress_ptr cinfo, boolean is_pre_scan) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + size_t arraysize; + int i; + (void)is_pre_scan; + + /* Install my colormap. */ + cinfo->colormap = cquantize->sv_colormap; + cinfo->actual_number_of_colors = cquantize->sv_actual; + + /* Initialize for desired dithering mode. */ + switch (cinfo->dither_mode) { + case JDITHER_NONE: + if (cinfo->out_color_components == 3) + cquantize->pub.color_quantize = color_quantize3; + else + cquantize->pub.color_quantize = color_quantize; + break; + case JDITHER_ORDERED: + if (cinfo->out_color_components == 3) + cquantize->pub.color_quantize = quantize3_ord_dither; + else + cquantize->pub.color_quantize = quantize_ord_dither; + cquantize->row_index = 0; /* initialize state for ordered dither */ + /* If user changed to ordered dither from another mode, + * we must recreate the color index table with padding. + * This will cost extra space, but probably isn't very likely. + */ + if (! cquantize->is_padded) + create_colorindex(cinfo); + /* Create ordered-dither tables if we didn't already. */ + if (cquantize->odither[0] == NULL) + create_odither_tables(cinfo); + break; + case JDITHER_FS: + cquantize->pub.color_quantize = quantize_fs_dither; + cquantize->on_odd_row = FALSE; /* initialize state for F-S dither */ + /* Allocate Floyd-Steinberg workspace if didn't already. */ + if (cquantize->fserrors[0] == NULL) + alloc_fs_workspace(cinfo); + /* Initialize the propagated errors to zero. */ + arraysize = (size_t) ((cinfo->output_width + 2) * SIZEOF(FSERROR)); + for (i = 0; i < cinfo->out_color_components; i++) + jzero_far((void FAR *) cquantize->fserrors[i], arraysize); + break; + default: + ERREXIT(cinfo, JERR_NOT_COMPILED); + break; + } +} + + +/* + * Finish up at the end of the pass. + */ + +METHODDEF(void) +finish_pass_1_quant (j_decompress_ptr cinfo) +{ + (void)cinfo; + /* no work in 1-pass case */ +} + + +/* + * Switch to a new external colormap between output passes. + * Shouldn't get to this module! + */ + +METHODDEF(void) +new_color_map_1_quant (j_decompress_ptr cinfo) +{ + ERREXIT(cinfo, JERR_MODE_CHANGE); +} + + +/* + * Module initialization routine for 1-pass color quantization. + */ + +GLOBAL(void) +jinit_1pass_quantizer (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize; + + cquantize = (my_cquantize_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_cquantizer)); + cinfo->cquantize = (struct jpeg_color_quantizer *) cquantize; + cquantize->pub.start_pass = start_pass_1_quant; + cquantize->pub.finish_pass = finish_pass_1_quant; + cquantize->pub.new_color_map = new_color_map_1_quant; + cquantize->fserrors[0] = NULL; /* Flag FS workspace not allocated */ + cquantize->odither[0] = NULL; /* Also flag odither arrays not allocated */ + + /* Make sure my internal arrays won't overflow */ + if (cinfo->out_color_components > MAX_Q_COMPS) + ERREXIT1(cinfo, JERR_QUANT_COMPONENTS, MAX_Q_COMPS); + /* Make sure colormap indexes can be represented by JSAMPLEs */ + if (cinfo->desired_number_of_colors > (MAXJSAMPLE+1)) + ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, MAXJSAMPLE+1); + + /* Create the colormap and color index table. */ + create_colormap(cinfo); + create_colorindex(cinfo); + + /* Allocate Floyd-Steinberg workspace now if requested. + * We do this now since it is FAR storage and may affect the memory + * manager's space calculations. If the user changes to FS dither + * mode in a later pass, we will allocate the space then, and will + * possibly overrun the max_memory_to_use setting. + */ + if (cinfo->dither_mode == JDITHER_FS) + alloc_fs_workspace(cinfo); +} + +#endif /* QUANT_1PASS_SUPPORTED */ diff --git a/gdcm/Utilities/gdcmjpeg/jquant2.c b/gdcm/Utilities/gdcmjpeg/jquant2.c new file mode 100644 index 0000000..048b1f7 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jquant2.c @@ -0,0 +1,1312 @@ +/* + * jquant2.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains 2-pass color quantization (color mapping) routines. + * These routines provide selection of a custom color map for an image, + * followed by mapping of the image to that color map, with optional + * Floyd-Steinberg dithering. + * It is also possible to use just the second pass to map to an arbitrary + * externally-given color map. + * + * Note: ordered dithering is not supported, since there isn't any fast + * way to compute intercolor distances; it's unclear that ordered dither's + * fundamental assumptions even hold with an irregularly spaced color map. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + +#ifdef QUANT_2PASS_SUPPORTED + + +/* + * This module implements the well-known Heckbert paradigm for color + * quantization. Most of the ideas used here can be traced back to + * Heckbert's seminal paper + * Heckbert, Paul. "Color Image Quantization for Frame Buffer Display", + * Proc. SIGGRAPH '82, Computer Graphics v.16 #3 (July 1982), pp 297-304. + * + * In the first pass over the image, we accumulate a histogram showing the + * usage count of each possible color. To keep the histogram to a reasonable + * size, we reduce the precision of the input; typical practice is to retain + * 5 or 6 bits per color, so that 8 or 4 different input values are counted + * in the same histogram cell. + * + * Next, the color-selection step begins with a box representing the whole + * color space, and repeatedly splits the "largest" remaining box until we + * have as many boxes as desired colors. Then the mean color in each + * remaining box becomes one of the possible output colors. + * + * The second pass over the image maps each input pixel to the closest output + * color (optionally after applying a Floyd-Steinberg dithering correction). + * This mapping is logically trivial, but making it go fast enough requires + * considerable care. + * + * Heckbert-style quantizers vary a good deal in their policies for choosing + * the "largest" box and deciding where to cut it. The particular policies + * used here have proved out well in experimental comparisons, but better ones + * may yet be found. + * + * In earlier versions of the IJG code, this module quantized in YCbCr color + * space, processing the raw upsampled data without a color conversion step. + * This allowed the color conversion math to be done only once per colormap + * entry, not once per pixel. However, that optimization precluded other + * useful optimizations (such as merging color conversion with upsampling) + * and it also interfered with desired capabilities such as quantizing to an + * externally-supplied colormap. We have therefore abandoned that approach. + * The present code works in the post-conversion color space, typically RGB. + * + * To improve the visual quality of the results, we actually work in scaled + * RGB space, giving G distances more weight than R, and R in turn more than + * B. To do everything in integer math, we must use integer scale factors. + * The 2/3/1 scale factors used here correspond loosely to the relative + * weights of the colors in the NTSC grayscale equation. + * If you want to use this code to quantize a non-RGB color space, you'll + * probably need to change these scale factors. + */ + +#define R_SCALE 2 /* scale R distances by this much */ +#define G_SCALE 3 /* scale G distances by this much */ +#define B_SCALE 1 /* and B by this much */ + +/* Relabel R/G/B as components 0/1/2, respecting the RGB ordering defined + * in jmorecfg.h. As the code stands, it will do the right thing for R,G,B + * and B,G,R orders. If you define some other weird order in jmorecfg.h, + * you'll get compile errors until you extend this logic. In that case + * you'll probably want to tweak the histogram sizes too. + */ + +#if RGB_RED == 0 +#define C0_SCALE R_SCALE +#endif +#if RGB_BLUE == 0 +#define C0_SCALE B_SCALE +#endif +#if RGB_GREEN == 1 +#define C1_SCALE G_SCALE +#endif +#if RGB_RED == 2 +#define C2_SCALE R_SCALE +#endif +#if RGB_BLUE == 2 +#define C2_SCALE B_SCALE +#endif + + +/* + * First we have the histogram data structure and routines for creating it. + * + * The number of bits of precision can be adjusted by changing these symbols. + * We recommend keeping 6 bits for G and 5 each for R and B. + * If you have plenty of memory and cycles, 6 bits all around gives marginally + * better results; if you are short of memory, 5 bits all around will save + * some space but degrade the results. + * To maintain a fully accurate histogram, we'd need to allocate a "long" + * (preferably unsigned long) for each cell. In practice this is overkill; + * we can get by with 16 bits per cell. Few of the cell counts will overflow, + * and clamping those that do overflow to the maximum value will give close- + * enough results. This reduces the recommended histogram size from 256Kb + * to 128Kb, which is a useful savings on PC-class machines. + * (In the second pass the histogram space is re-used for pixel mapping data; + * in that capacity, each cell must be able to store zero to the number of + * desired colors. 16 bits/cell is plenty for that too.) + * Since the JPEG code is intended to run in small memory model on 80x86 + * machines, we can't just allocate the histogram in one chunk. Instead + * of a true 3-D array, we use a row of pointers to 2-D arrays. Each + * pointer corresponds to a C0 value (typically 2^5 = 32 pointers) and + * each 2-D array has 2^6*2^5 = 2048 or 2^6*2^6 = 4096 entries. Note that + * on 80x86 machines, the pointer row is in near memory but the actual + * arrays are in far memory (same arrangement as we use for image arrays). + */ + +#define MAXNUMCOLORS (MAXJSAMPLE+1) /* maximum size of colormap */ + +/* These will do the right thing for either R,G,B or B,G,R color order, + * but you may not like the results for other color orders. + */ +#define HIST_C0_BITS 5 /* bits of precision in R/B histogram */ +#define HIST_C1_BITS 6 /* bits of precision in G histogram */ +#define HIST_C2_BITS 5 /* bits of precision in B/R histogram */ + +/* Number of elements along histogram axes. */ +#define HIST_C0_ELEMS (1<cquantize; + register JSAMPROW ptr; + register histptr histp; + register hist3d histogram = cquantize->histogram; + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + (void)output_buf; + + for (row = 0; row < num_rows; row++) { + ptr = input_buf[row]; + for (col = width; col > 0; col--) { + /* get pixel value and index into the histogram */ + histp = & histogram[GETJSAMPLE(ptr[0]) >> C0_SHIFT] + [GETJSAMPLE(ptr[1]) >> C1_SHIFT] + [GETJSAMPLE(ptr[2]) >> C2_SHIFT]; + /* increment, check for overflow and undo increment if so. */ + if (++(*histp) <= 0) + (*histp)--; + ptr += 3; + } + } +} + + +/* + * Next we have the really interesting routines: selection of a colormap + * given the completed histogram. + * These routines work with a list of "boxes", each representing a rectangular + * subset of the input color space (to histogram precision). + */ + +typedef struct { + /* The bounds of the box (inclusive); expressed as histogram indexes */ + int c0min, c0max; + int c1min, c1max; + int c2min, c2max; + /* The volume (actually 2-norm) of the box */ + INT32 volume; + /* The number of nonzero histogram cells within this box */ + long colorcount; +} box; + +typedef box * boxptr; + + +LOCAL(boxptr) +find_biggest_color_pop (boxptr boxlist, int numboxes) +/* Find the splittable box with the largest color population */ +/* Returns NULL if no splittable boxes remain */ +{ + register boxptr boxp; + register int i; + register long maxc = 0; + boxptr which = NULL; + + for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++) { + if (boxp->colorcount > maxc && boxp->volume > 0) { + which = boxp; + maxc = boxp->colorcount; + } + } + return which; +} + + +LOCAL(boxptr) +find_biggest_volume (boxptr boxlist, int numboxes) +/* Find the splittable box with the largest (scaled) volume */ +/* Returns NULL if no splittable boxes remain */ +{ + register boxptr boxp; + register int i; + register INT32 maxv = 0; + boxptr which = NULL; + + for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++) { + if (boxp->volume > maxv) { + which = boxp; + maxv = boxp->volume; + } + } + return which; +} + + +LOCAL(void) +update_box (j_decompress_ptr cinfo, boxptr boxp) +/* Shrink the min/max bounds of a box to enclose only nonzero elements, */ +/* and recompute its volume and population */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + histptr histp; + int c0,c1,c2; + int c0min,c0max,c1min,c1max,c2min,c2max; + INT32 dist0,dist1,dist2; + long ccount; + + c0min = boxp->c0min; c0max = boxp->c0max; + c1min = boxp->c1min; c1max = boxp->c1max; + c2min = boxp->c2min; c2max = boxp->c2max; + + if (c0max > c0min) + for (c0 = c0min; c0 <= c0max; c0++) + for (c1 = c1min; c1 <= c1max; c1++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++) + if (*histp++ != 0) { + boxp->c0min = c0min = c0; + goto have_c0min; + } + } + have_c0min: + if (c0max > c0min) + for (c0 = c0max; c0 >= c0min; c0--) + for (c1 = c1min; c1 <= c1max; c1++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++) + if (*histp++ != 0) { + boxp->c0max = c0max = c0; + goto have_c0max; + } + } + have_c0max: + if (c1max > c1min) + for (c1 = c1min; c1 <= c1max; c1++) + for (c0 = c0min; c0 <= c0max; c0++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++) + if (*histp++ != 0) { + boxp->c1min = c1min = c1; + goto have_c1min; + } + } + have_c1min: + if (c1max > c1min) + for (c1 = c1max; c1 >= c1min; c1--) + for (c0 = c0min; c0 <= c0max; c0++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++) + if (*histp++ != 0) { + boxp->c1max = c1max = c1; + goto have_c1max; + } + } + have_c1max: + if (c2max > c2min) + for (c2 = c2min; c2 <= c2max; c2++) + for (c0 = c0min; c0 <= c0max; c0++) { + histp = & histogram[c0][c1min][c2]; + for (c1 = c1min; c1 <= c1max; c1++, histp += HIST_C2_ELEMS) + if (*histp != 0) { + boxp->c2min = c2min = c2; + goto have_c2min; + } + } + have_c2min: + if (c2max > c2min) + for (c2 = c2max; c2 >= c2min; c2--) + for (c0 = c0min; c0 <= c0max; c0++) { + histp = & histogram[c0][c1min][c2]; + for (c1 = c1min; c1 <= c1max; c1++, histp += HIST_C2_ELEMS) + if (*histp != 0) { + boxp->c2max = c2max = c2; + goto have_c2max; + } + } + have_c2max: + + /* Update box volume. + * We use 2-norm rather than real volume here; this biases the method + * against making long narrow boxes, and it has the side benefit that + * a box is splittable iff norm > 0. + * Since the differences are expressed in histogram-cell units, + * we have to shift back to JSAMPLE units to get consistent distances; + * after which, we scale according to the selected distance scale factors. + */ + dist0 = ((c0max - c0min) << C0_SHIFT) * C0_SCALE; + dist1 = ((c1max - c1min) << C1_SHIFT) * C1_SCALE; + dist2 = ((c2max - c2min) << C2_SHIFT) * C2_SCALE; + boxp->volume = dist0*dist0 + dist1*dist1 + dist2*dist2; + + /* Now scan remaining volume of box and compute population */ + ccount = 0; + for (c0 = c0min; c0 <= c0max; c0++) + for (c1 = c1min; c1 <= c1max; c1++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++, histp++) + if (*histp != 0) { + ccount++; + } + } + boxp->colorcount = ccount; +} + + +LOCAL(int) +median_cut (j_decompress_ptr cinfo, boxptr boxlist, int numboxes, + int desired_colors) +/* Repeatedly select and split the largest box until we have enough boxes */ +{ + int n,lb; + int c0,c1,c2,cmax; + register boxptr b1,b2; + + while (numboxes < desired_colors) { + /* Select box to split. + * Current algorithm: by population for first half, then by volume. + */ + if (numboxes*2 <= desired_colors) { + b1 = find_biggest_color_pop(boxlist, numboxes); + } else { + b1 = find_biggest_volume(boxlist, numboxes); + } + if (b1 == NULL) /* no splittable boxes left! */ + break; + b2 = &boxlist[numboxes]; /* where new box will go */ + /* Copy the color bounds to the new box. */ + b2->c0max = b1->c0max; b2->c1max = b1->c1max; b2->c2max = b1->c2max; + b2->c0min = b1->c0min; b2->c1min = b1->c1min; b2->c2min = b1->c2min; + /* Choose which axis to split the box on. + * Current algorithm: longest scaled axis. + * See notes in update_box about scaling distances. + */ + c0 = ((b1->c0max - b1->c0min) << C0_SHIFT) * C0_SCALE; + c1 = ((b1->c1max - b1->c1min) << C1_SHIFT) * C1_SCALE; + c2 = ((b1->c2max - b1->c2min) << C2_SHIFT) * C2_SCALE; + /* We want to break any ties in favor of green, then red, blue last. + * This code does the right thing for R,G,B or B,G,R color orders only. + */ +#if RGB_RED == 0 + cmax = c1; n = 1; + if (c0 > cmax) { cmax = c0; n = 0; } + if (c2 > cmax) { n = 2; } +#else + cmax = c1; n = 1; + if (c2 > cmax) { cmax = c2; n = 2; } + if (c0 > cmax) { n = 0; } +#endif + /* Choose split point along selected axis, and update box bounds. + * Current algorithm: split at halfway point. + * (Since the box has been shrunk to minimum volume, + * any split will produce two nonempty subboxes.) + * Note that lb value is max for lower box, so must be < old max. + */ + switch (n) { + case 0: + lb = (b1->c0max + b1->c0min) / 2; + b1->c0max = lb; + b2->c0min = lb+1; + break; + case 1: + lb = (b1->c1max + b1->c1min) / 2; + b1->c1max = lb; + b2->c1min = lb+1; + break; + case 2: + lb = (b1->c2max + b1->c2min) / 2; + b1->c2max = lb; + b2->c2min = lb+1; + break; + } + /* Update stats for boxes */ + update_box(cinfo, b1); + update_box(cinfo, b2); + numboxes++; + } + return numboxes; +} + + +LOCAL(void) +compute_color (j_decompress_ptr cinfo, boxptr boxp, int icolor) +/* Compute representative color for a box, put it in colormap[icolor] */ +{ + /* Current algorithm: mean weighted by pixels (not colors) */ + /* Note it is important to get the rounding correct! */ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + histptr histp; + int c0,c1,c2; + int c0min,c0max,c1min,c1max,c2min,c2max; + long count; + long total = 0; + long c0total = 0; + long c1total = 0; + long c2total = 0; + + c0min = boxp->c0min; c0max = boxp->c0max; + c1min = boxp->c1min; c1max = boxp->c1max; + c2min = boxp->c2min; c2max = boxp->c2max; + + for (c0 = c0min; c0 <= c0max; c0++) + for (c1 = c1min; c1 <= c1max; c1++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++) { + if ((count = *histp++) != 0) { + total += count; + c0total += ((c0 << C0_SHIFT) + ((1<>1)) * count; + c1total += ((c1 << C1_SHIFT) + ((1<>1)) * count; + c2total += ((c2 << C2_SHIFT) + ((1<>1)) * count; + } + } + } + + cinfo->colormap[0][icolor] = (JSAMPLE) ((c0total + (total>>1)) / total); + cinfo->colormap[1][icolor] = (JSAMPLE) ((c1total + (total>>1)) / total); + cinfo->colormap[2][icolor] = (JSAMPLE) ((c2total + (total>>1)) / total); +} + + +LOCAL(void) +select_colors (j_decompress_ptr cinfo, int desired_colors) +/* Master routine for color selection */ +{ + boxptr boxlist; + int numboxes; + int i; + + /* Allocate workspace for box list */ + boxlist = (boxptr) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, desired_colors * SIZEOF(box)); + /* Initialize one box containing whole space */ + numboxes = 1; + boxlist[0].c0min = 0; + boxlist[0].c0max = MAXJSAMPLE >> C0_SHIFT; + boxlist[0].c1min = 0; + boxlist[0].c1max = MAXJSAMPLE >> C1_SHIFT; + boxlist[0].c2min = 0; + boxlist[0].c2max = MAXJSAMPLE >> C2_SHIFT; + /* Shrink it to actually-used volume and set its statistics */ + update_box(cinfo, & boxlist[0]); + /* Perform median-cut to produce final box list */ + numboxes = median_cut(cinfo, boxlist, numboxes, desired_colors); + /* Compute the representative color for each box, fill colormap */ + for (i = 0; i < numboxes; i++) + compute_color(cinfo, & boxlist[i], i); + cinfo->actual_number_of_colors = numboxes; + TRACEMS1(cinfo, 1, JTRC_QUANT_SELECTED, numboxes); +} + + +/* + * These routines are concerned with the time-critical task of mapping input + * colors to the nearest color in the selected colormap. + * + * We re-use the histogram space as an "inverse color map", essentially a + * cache for the results of nearest-color searches. All colors within a + * histogram cell will be mapped to the same colormap entry, namely the one + * closest to the cell's center. This may not be quite the closest entry to + * the actual input color, but it's almost as good. A zero in the cache + * indicates we haven't found the nearest color for that cell yet; the array + * is cleared to zeroes before starting the mapping pass. When we find the + * nearest color for a cell, its colormap index plus one is recorded in the + * cache for future use. The pass2 scanning routines call fill_inverse_cmap + * when they need to use an unfilled entry in the cache. + * + * Our method of efficiently finding nearest colors is based on the "locally + * sorted search" idea described by Heckbert and on the incremental distance + * calculation described by Spencer W. Thomas in chapter III.1 of Graphics + * Gems II (James Arvo, ed. Academic Press, 1991). Thomas points out that + * the distances from a given colormap entry to each cell of the histogram can + * be computed quickly using an incremental method: the differences between + * distances to adjacent cells themselves differ by a constant. This allows a + * fairly fast implementation of the "brute force" approach of computing the + * distance from every colormap entry to every histogram cell. Unfortunately, + * it needs a work array to hold the best-distance-so-far for each histogram + * cell (because the inner loop has to be over cells, not colormap entries). + * The work array elements have to be INT32s, so the work array would need + * 256Kb at our recommended precision. This is not feasible in DOS machines. + * + * To get around these problems, we apply Thomas' method to compute the + * nearest colors for only the cells within a small subbox of the histogram. + * The work array need be only as big as the subbox, so the memory usage + * problem is solved. Furthermore, we need not fill subboxes that are never + * referenced in pass2; many images use only part of the color gamut, so a + * fair amount of work is saved. An additional advantage of this + * approach is that we can apply Heckbert's locality criterion to quickly + * eliminate colormap entries that are far away from the subbox; typically + * three-fourths of the colormap entries are rejected by Heckbert's criterion, + * and we need not compute their distances to individual cells in the subbox. + * The speed of this approach is heavily influenced by the subbox size: too + * small means too much overhead, too big loses because Heckbert's criterion + * can't eliminate as many colormap entries. Empirically the best subbox + * size seems to be about 1/512th of the histogram (1/8th in each direction). + * + * Thomas' article also describes a refined method which is asymptotically + * faster than the brute-force method, but it is also far more complex and + * cannot efficiently be applied to small subboxes. It is therefore not + * useful for programs intended to be portable to DOS machines. On machines + * with plenty of memory, filling the whole histogram in one shot with Thomas' + * refined method might be faster than the present code --- but then again, + * it might not be any faster, and it's certainly more complicated. + */ + + +/* log2(histogram cells in update box) for each axis; this can be adjusted */ +#define BOX_C0_LOG (HIST_C0_BITS-3) +#define BOX_C1_LOG (HIST_C1_BITS-3) +#define BOX_C2_LOG (HIST_C2_BITS-3) + +#define BOX_C0_ELEMS (1<actual_number_of_colors; + int maxc0, maxc1, maxc2; + int centerc0, centerc1, centerc2; + int i, x, ncolors; + INT32 minmaxdist, min_dist, max_dist, tdist; + INT32 mindist[MAXNUMCOLORS]; /* min distance to colormap entry i */ + + /* Compute true coordinates of update box's upper corner and center. + * Actually we compute the coordinates of the center of the upper-corner + * histogram cell, which are the upper bounds of the volume we care about. + * Note that since ">>" rounds down, the "center" values may be closer to + * min than to max; hence comparisons to them must be "<=", not "<". + */ + maxc0 = minc0 + ((1 << BOX_C0_SHIFT) - (1 << C0_SHIFT)); + centerc0 = (minc0 + maxc0) >> 1; + maxc1 = minc1 + ((1 << BOX_C1_SHIFT) - (1 << C1_SHIFT)); + centerc1 = (minc1 + maxc1) >> 1; + maxc2 = minc2 + ((1 << BOX_C2_SHIFT) - (1 << C2_SHIFT)); + centerc2 = (minc2 + maxc2) >> 1; + + /* For each color in colormap, find: + * 1. its minimum squared-distance to any point in the update box + * (zero if color is within update box); + * 2. its maximum squared-distance to any point in the update box. + * Both of these can be found by considering only the corners of the box. + * We save the minimum distance for each color in mindist[]; + * only the smallest maximum distance is of interest. + */ + minmaxdist = 0x7FFFFFFFL; + + for (i = 0; i < numcolors; i++) { + /* We compute the squared-c0-distance term, then add in the other two. */ + x = GETJSAMPLE(cinfo->colormap[0][i]); + if (x < minc0) { + tdist = (x - minc0) * C0_SCALE; + min_dist = tdist*tdist; + tdist = (x - maxc0) * C0_SCALE; + max_dist = tdist*tdist; + } else if (x > maxc0) { + tdist = (x - maxc0) * C0_SCALE; + min_dist = tdist*tdist; + tdist = (x - minc0) * C0_SCALE; + max_dist = tdist*tdist; + } else { + /* within cell range so no contribution to min_dist */ + min_dist = 0; + if (x <= centerc0) { + tdist = (x - maxc0) * C0_SCALE; + max_dist = tdist*tdist; + } else { + tdist = (x - minc0) * C0_SCALE; + max_dist = tdist*tdist; + } + } + + x = GETJSAMPLE(cinfo->colormap[1][i]); + if (x < minc1) { + tdist = (x - minc1) * C1_SCALE; + min_dist += tdist*tdist; + tdist = (x - maxc1) * C1_SCALE; + max_dist += tdist*tdist; + } else if (x > maxc1) { + tdist = (x - maxc1) * C1_SCALE; + min_dist += tdist*tdist; + tdist = (x - minc1) * C1_SCALE; + max_dist += tdist*tdist; + } else { + /* within cell range so no contribution to min_dist */ + if (x <= centerc1) { + tdist = (x - maxc1) * C1_SCALE; + max_dist += tdist*tdist; + } else { + tdist = (x - minc1) * C1_SCALE; + max_dist += tdist*tdist; + } + } + + x = GETJSAMPLE(cinfo->colormap[2][i]); + if (x < minc2) { + tdist = (x - minc2) * C2_SCALE; + min_dist += tdist*tdist; + tdist = (x - maxc2) * C2_SCALE; + max_dist += tdist*tdist; + } else if (x > maxc2) { + tdist = (x - maxc2) * C2_SCALE; + min_dist += tdist*tdist; + tdist = (x - minc2) * C2_SCALE; + max_dist += tdist*tdist; + } else { + /* within cell range so no contribution to min_dist */ + if (x <= centerc2) { + tdist = (x - maxc2) * C2_SCALE; + max_dist += tdist*tdist; + } else { + tdist = (x - minc2) * C2_SCALE; + max_dist += tdist*tdist; + } + } + + mindist[i] = min_dist; /* save away the results */ + if (max_dist < minmaxdist) + minmaxdist = max_dist; + } + + /* Now we know that no cell in the update box is more than minmaxdist + * away from some colormap entry. Therefore, only colors that are + * within minmaxdist of some part of the box need be considered. + */ + ncolors = 0; + for (i = 0; i < numcolors; i++) { + if (mindist[i] <= minmaxdist) + colorlist[ncolors++] = (JSAMPLE) i; + } + return ncolors; +} + + +LOCAL(void) +find_best_colors (j_decompress_ptr cinfo, int minc0, int minc1, int minc2, + int numcolors, JSAMPLE colorlist[], JSAMPLE bestcolor[]) +/* Find the closest colormap entry for each cell in the update box, + * given the list of candidate colors prepared by find_nearby_colors. + * Return the indexes of the closest entries in the bestcolor[] array. + * This routine uses Thomas' incremental distance calculation method to + * find the distance from a colormap entry to successive cells in the box. + */ +{ + int ic0, ic1, ic2; + int i, icolor; + register INT32 * bptr; /* pointer into bestdist[] array */ + JSAMPLE * cptr; /* pointer into bestcolor[] array */ + INT32 dist0, dist1; /* initial distance values */ + register INT32 dist2; /* current distance in inner loop */ + INT32 xx0, xx1; /* distance increments */ + register INT32 xx2; + INT32 inc0, inc1, inc2; /* initial values for increments */ + /* This array holds the distance to the nearest-so-far color for each cell */ + INT32 bestdist[BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS]; + + /* Initialize best-distance for each cell of the update box */ + bptr = bestdist; + for (i = BOX_C0_ELEMS*BOX_C1_ELEMS*BOX_C2_ELEMS-1; i >= 0; i--) + *bptr++ = 0x7FFFFFFFL; + + /* For each color selected by find_nearby_colors, + * compute its distance to the center of each cell in the box. + * If that's less than best-so-far, update best distance and color number. + */ + + /* Nominal steps between cell centers ("x" in Thomas article) */ +#define STEP_C0 ((1 << C0_SHIFT) * C0_SCALE) +#define STEP_C1 ((1 << C1_SHIFT) * C1_SCALE) +#define STEP_C2 ((1 << C2_SHIFT) * C2_SCALE) + + for (i = 0; i < numcolors; i++) { + icolor = GETJSAMPLE(colorlist[i]); + /* Compute (square of) distance from minc0/c1/c2 to this color */ + inc0 = (minc0 - GETJSAMPLE(cinfo->colormap[0][icolor])) * C0_SCALE; + dist0 = inc0*inc0; + inc1 = (minc1 - GETJSAMPLE(cinfo->colormap[1][icolor])) * C1_SCALE; + dist0 += inc1*inc1; + inc2 = (minc2 - GETJSAMPLE(cinfo->colormap[2][icolor])) * C2_SCALE; + dist0 += inc2*inc2; + /* Form the initial difference increments */ + inc0 = inc0 * (2 * STEP_C0) + STEP_C0 * STEP_C0; + inc1 = inc1 * (2 * STEP_C1) + STEP_C1 * STEP_C1; + inc2 = inc2 * (2 * STEP_C2) + STEP_C2 * STEP_C2; + /* Now loop over all cells in box, updating distance per Thomas method */ + bptr = bestdist; + cptr = bestcolor; + xx0 = inc0; + for (ic0 = BOX_C0_ELEMS-1; ic0 >= 0; ic0--) { + dist1 = dist0; + xx1 = inc1; + for (ic1 = BOX_C1_ELEMS-1; ic1 >= 0; ic1--) { + dist2 = dist1; + xx2 = inc2; + for (ic2 = BOX_C2_ELEMS-1; ic2 >= 0; ic2--) { + if (dist2 < *bptr) { + *bptr = dist2; + *cptr = (JSAMPLE) icolor; + } + dist2 += xx2; + xx2 += 2 * STEP_C2 * STEP_C2; + bptr++; + cptr++; + } + dist1 += xx1; + xx1 += 2 * STEP_C1 * STEP_C1; + } + dist0 += xx0; + xx0 += 2 * STEP_C0 * STEP_C0; + } + } +} + + +LOCAL(void) +fill_inverse_cmap (j_decompress_ptr cinfo, int c0, int c1, int c2) +/* Fill the inverse-colormap entries in the update box that contains */ +/* histogram cell c0/c1/c2. (Only that one cell MUST be filled, but */ +/* we can fill as many others as we wish.) */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + int minc0, minc1, minc2; /* lower left corner of update box */ + int ic0, ic1, ic2; + register JSAMPLE * cptr; /* pointer into bestcolor[] array */ + register histptr cachep; /* pointer into main cache array */ + /* This array lists the candidate colormap indexes. */ + JSAMPLE colorlist[MAXNUMCOLORS]; + int numcolors; /* number of candidate colors */ + /* This array holds the actually closest colormap index for each cell. */ + JSAMPLE bestcolor[BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS]; + + /* Convert cell coordinates to update box ID */ + c0 >>= BOX_C0_LOG; + c1 >>= BOX_C1_LOG; + c2 >>= BOX_C2_LOG; + + /* Compute true coordinates of update box's origin corner. + * Actually we compute the coordinates of the center of the corner + * histogram cell, which are the lower bounds of the volume we care about. + */ + minc0 = (c0 << BOX_C0_SHIFT) + ((1 << C0_SHIFT) >> 1); + minc1 = (c1 << BOX_C1_SHIFT) + ((1 << C1_SHIFT) >> 1); + minc2 = (c2 << BOX_C2_SHIFT) + ((1 << C2_SHIFT) >> 1); + + /* Determine which colormap entries are close enough to be candidates + * for the nearest entry to some cell in the update box. + */ + numcolors = find_nearby_colors(cinfo, minc0, minc1, minc2, colorlist); + + /* Determine the actually nearest colors. */ + find_best_colors(cinfo, minc0, minc1, minc2, numcolors, colorlist, + bestcolor); + + /* Save the best color numbers (plus 1) in the main cache array */ + c0 <<= BOX_C0_LOG; /* convert ID back to base cell indexes */ + c1 <<= BOX_C1_LOG; + c2 <<= BOX_C2_LOG; + cptr = bestcolor; + for (ic0 = 0; ic0 < BOX_C0_ELEMS; ic0++) { + for (ic1 = 0; ic1 < BOX_C1_ELEMS; ic1++) { + cachep = & histogram[c0+ic0][c1+ic1][c2]; + for (ic2 = 0; ic2 < BOX_C2_ELEMS; ic2++) { + *cachep++ = (histcell) (GETJSAMPLE(*cptr++) + 1); + } + } + } +} + + +/* + * Map some rows of pixels to the output colormapped representation. + */ + +METHODDEF(void) +pass2_no_dither (j_decompress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPARRAY output_buf, int num_rows) +/* This version performs no dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + register JSAMPROW inptr, outptr; + register histptr cachep; + register int c0, c1, c2; + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + + for (row = 0; row < num_rows; row++) { + inptr = input_buf[row]; + outptr = output_buf[row]; + for (col = width; col > 0; col--) { + /* get pixel value and index into the cache */ + c0 = GETJSAMPLE(*inptr++) >> C0_SHIFT; + c1 = GETJSAMPLE(*inptr++) >> C1_SHIFT; + c2 = GETJSAMPLE(*inptr++) >> C2_SHIFT; + cachep = & histogram[c0][c1][c2]; + /* If we have not seen this color before, find nearest colormap entry */ + /* and update the cache */ + if (*cachep == 0) + fill_inverse_cmap(cinfo, c0,c1,c2); + /* Now emit the colormap index for this cell */ + *outptr++ = (JSAMPLE) (*cachep - 1); + } + } +} + + +METHODDEF(void) +pass2_fs_dither (j_decompress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPARRAY output_buf, int num_rows) +/* This version performs Floyd-Steinberg dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + register LOCFSERROR cur0, cur1, cur2; /* current error or pixel value */ + LOCFSERROR belowerr0, belowerr1, belowerr2; /* error for pixel below cur */ + LOCFSERROR bpreverr0, bpreverr1, bpreverr2; /* error for below/prev col */ + register FSERRPTR errorptr; /* => fserrors[] at column before current */ + JSAMPROW inptr; /* => current input pixel */ + JSAMPROW outptr; /* => current output pixel */ + histptr cachep; + int dir; /* +1 or -1 depending on direction */ + int dir3; /* 3*dir, for advancing inptr & errorptr */ + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + JSAMPLE *range_limit = cinfo->sample_range_limit; + int *error_limit = cquantize->error_limiter; + JSAMPROW colormap0 = cinfo->colormap[0]; + JSAMPROW colormap1 = cinfo->colormap[1]; + JSAMPROW colormap2 = cinfo->colormap[2]; + SHIFT_TEMPS + + for (row = 0; row < num_rows; row++) { + inptr = input_buf[row]; + outptr = output_buf[row]; + if (cquantize->on_odd_row) { + /* work right to left in this row */ + inptr += (width-1) * 3; /* so point to rightmost pixel */ + outptr += width-1; + dir = -1; + dir3 = -3; + errorptr = cquantize->fserrors + (width+1)*3; /* => entry after last column */ + cquantize->on_odd_row = FALSE; /* flip for next time */ + } else { + /* work left to right in this row */ + dir = 1; + dir3 = 3; + errorptr = cquantize->fserrors; /* => entry before first real column */ + cquantize->on_odd_row = TRUE; /* flip for next time */ + } + /* Preset error values: no error propagated to first pixel from left */ + cur0 = cur1 = cur2 = 0; + /* and no error propagated to row below yet */ + belowerr0 = belowerr1 = belowerr2 = 0; + bpreverr0 = bpreverr1 = bpreverr2 = 0; + + for (col = width; col > 0; col--) { + /* curN holds the error propagated from the previous pixel on the + * current line. Add the error propagated from the previous line + * to form the complete error correction term for this pixel, and + * round the error term (which is expressed * 16) to an integer. + * RIGHT_SHIFT rounds towards minus infinity, so adding 8 is correct + * for either sign of the error value. + * Note: errorptr points to *previous* column's array entry. + */ + cur0 = RIGHT_SHIFT(cur0 + errorptr[dir3+0] + 8, 4); + cur1 = RIGHT_SHIFT(cur1 + errorptr[dir3+1] + 8, 4); + cur2 = RIGHT_SHIFT(cur2 + errorptr[dir3+2] + 8, 4); + /* Limit the error using transfer function set by init_error_limit. + * See comments with init_error_limit for rationale. + */ + cur0 = error_limit[cur0]; + cur1 = error_limit[cur1]; + cur2 = error_limit[cur2]; + /* Form pixel value + error, and range-limit to 0..MAXJSAMPLE. + * The maximum error is +- MAXJSAMPLE (or less with error limiting); + * this sets the required size of the range_limit array. + */ + cur0 += GETJSAMPLE(inptr[0]); + cur1 += GETJSAMPLE(inptr[1]); + cur2 += GETJSAMPLE(inptr[2]); + cur0 = GETJSAMPLE(range_limit[cur0]); + cur1 = GETJSAMPLE(range_limit[cur1]); + cur2 = GETJSAMPLE(range_limit[cur2]); + /* Index into the cache with adjusted pixel value */ + cachep = & histogram[cur0>>C0_SHIFT][cur1>>C1_SHIFT][cur2>>C2_SHIFT]; + /* If we have not seen this color before, find nearest colormap */ + /* entry and update the cache */ + if (*cachep == 0) + fill_inverse_cmap(cinfo, cur0>>C0_SHIFT,cur1>>C1_SHIFT,cur2>>C2_SHIFT); + /* Now emit the colormap index for this cell */ + { register int pixcode = *cachep - 1; + *outptr = (JSAMPLE) pixcode; + /* Compute representation error for this pixel */ + cur0 -= GETJSAMPLE(colormap0[pixcode]); + cur1 -= GETJSAMPLE(colormap1[pixcode]); + cur2 -= GETJSAMPLE(colormap2[pixcode]); + } + /* Compute error fractions to be propagated to adjacent pixels. + * Add these into the running sums, and simultaneously shift the + * next-line error sums left by 1 column. + */ + { register LOCFSERROR bnexterr, delta; + + bnexterr = cur0; /* Process component 0 */ + delta = cur0 * 2; + cur0 += delta; /* form error * 3 */ + errorptr[0] = (FSERROR) (bpreverr0 + cur0); + cur0 += delta; /* form error * 5 */ + bpreverr0 = belowerr0 + cur0; + belowerr0 = bnexterr; + cur0 += delta; /* form error * 7 */ + bnexterr = cur1; /* Process component 1 */ + delta = cur1 * 2; + cur1 += delta; /* form error * 3 */ + errorptr[1] = (FSERROR) (bpreverr1 + cur1); + cur1 += delta; /* form error * 5 */ + bpreverr1 = belowerr1 + cur1; + belowerr1 = bnexterr; + cur1 += delta; /* form error * 7 */ + bnexterr = cur2; /* Process component 2 */ + delta = cur2 * 2; + cur2 += delta; /* form error * 3 */ + errorptr[2] = (FSERROR) (bpreverr2 + cur2); + cur2 += delta; /* form error * 5 */ + bpreverr2 = belowerr2 + cur2; + belowerr2 = bnexterr; + cur2 += delta; /* form error * 7 */ + } + /* At this point curN contains the 7/16 error value to be propagated + * to the next pixel on the current line, and all the errors for the + * next line have been shifted over. We are therefore ready to move on. + */ + inptr += dir3; /* Advance pixel pointers to next column */ + outptr += dir; + errorptr += dir3; /* advance errorptr to current column */ + } + /* Post-loop cleanup: we must unload the final error values into the + * final fserrors[] entry. Note we need not unload belowerrN because + * it is for the dummy column before or after the actual array. + */ + errorptr[0] = (FSERROR) bpreverr0; /* unload prev errs into array */ + errorptr[1] = (FSERROR) bpreverr1; + errorptr[2] = (FSERROR) bpreverr2; + } +} + + +/* + * Initialize the error-limiting transfer function (lookup table). + * The raw F-S error computation can potentially compute error values of up to + * +- MAXJSAMPLE. But we want the maximum correction applied to a pixel to be + * much less, otherwise obviously wrong pixels will be created. (Typical + * effects include weird fringes at color-area boundaries, isolated bright + * pixels in a dark area, etc.) The standard advice for avoiding this problem + * is to ensure that the "corners" of the color cube are allocated as output + * colors; then repeated errors in the same direction cannot cause cascading + * error buildup. However, that only prevents the error from getting + * completely out of hand; Aaron Giles reports that error limiting improves + * the results even with corner colors allocated. + * A simple clamping of the error values to about +- MAXJSAMPLE/8 works pretty + * well, but the smoother transfer function used below is even better. Thanks + * to Aaron Giles for this idea. + */ + +LOCAL(void) +init_error_limit (j_decompress_ptr cinfo) +/* Allocate and fill in the error_limiter table */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + int * table; + int in, out; + + table = (int *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE*2+1) * SIZEOF(int)); + table += MAXJSAMPLE; /* so can index -MAXJSAMPLE .. +MAXJSAMPLE */ + cquantize->error_limiter = table; + +#define STEPSIZE ((MAXJSAMPLE+1)/16) + /* Map errors 1:1 up to +- MAXJSAMPLE/16 */ + out = 0; + for (in = 0; in < STEPSIZE; in++, out++) { + table[in] = out; table[-in] = -out; + } + /* Map errors 1:2 up to +- 3*MAXJSAMPLE/16 */ + for (; in < STEPSIZE*3; in++, out += (in&1) ? 0 : 1) { + table[in] = out; table[-in] = -out; + } + /* Clamp the rest to final out value (which is (MAXJSAMPLE+1)/8) */ + for (; in <= MAXJSAMPLE; in++) { + table[in] = out; table[-in] = -out; + } +#undef STEPSIZE +} + + +/* + * Finish up at the end of each pass. + */ + +METHODDEF(void) +finish_pass1 (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + + /* Select the representative colors and fill in cinfo->colormap */ + cinfo->colormap = cquantize->sv_colormap; + select_colors(cinfo, cquantize->desired); + /* Force next pass to zero the color index table */ + cquantize->needs_zeroed = TRUE; +} + + +METHODDEF(void) +finish_pass2 (j_decompress_ptr cinfo) +{ + (void)cinfo; + /* no work */ +} + + +/* + * Initialize for each processing pass. + */ + +METHODDEF(void) +start_pass_2_quant (j_decompress_ptr cinfo, boolean is_pre_scan) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + int i; + + /* Only F-S dithering or no dithering is supported. */ + /* If user asks for ordered dither, give him F-S. */ + if (cinfo->dither_mode != JDITHER_NONE) + cinfo->dither_mode = JDITHER_FS; + + if (is_pre_scan) { + /* Set up method pointers */ + cquantize->pub.color_quantize = prescan_quantize; + cquantize->pub.finish_pass = finish_pass1; + cquantize->needs_zeroed = TRUE; /* Always zero histogram */ + } else { + /* Set up method pointers */ + if (cinfo->dither_mode == JDITHER_FS) + cquantize->pub.color_quantize = pass2_fs_dither; + else + cquantize->pub.color_quantize = pass2_no_dither; + cquantize->pub.finish_pass = finish_pass2; + + /* Make sure color count is acceptable */ + i = cinfo->actual_number_of_colors; + if (i < 1) + ERREXIT1(cinfo, JERR_QUANT_FEW_COLORS, 1); + if (i > MAXNUMCOLORS) + ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, MAXNUMCOLORS); + + if (cinfo->dither_mode == JDITHER_FS) { + size_t arraysize = (size_t) ((cinfo->output_width + 2) * + (3 * SIZEOF(FSERROR))); + /* Allocate Floyd-Steinberg workspace if we didn't already. */ + if (cquantize->fserrors == NULL) + cquantize->fserrors = (FSERRPTR) (*cinfo->mem->alloc_large) + ((j_common_ptr) cinfo, JPOOL_IMAGE, arraysize); + /* Initialize the propagated errors to zero. */ + jzero_far((void FAR *) cquantize->fserrors, arraysize); + /* Make the error-limit table if we didn't already. */ + if (cquantize->error_limiter == NULL) + init_error_limit(cinfo); + cquantize->on_odd_row = FALSE; + } + + } + /* Zero the histogram or inverse color map, if necessary */ + if (cquantize->needs_zeroed) { + for (i = 0; i < HIST_C0_ELEMS; i++) { + jzero_far((void FAR *) histogram[i], + HIST_C1_ELEMS*HIST_C2_ELEMS * SIZEOF(histcell)); + } + cquantize->needs_zeroed = FALSE; + } +} + + +/* + * Switch to a new external colormap between output passes. + */ + +METHODDEF(void) +new_color_map_2_quant (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + + /* Reset the inverse color map */ + cquantize->needs_zeroed = TRUE; +} + + +/* + * Module initialization routine for 2-pass color quantization. + */ + +GLOBAL(void) +jinit_2pass_quantizer (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize; + int i; + + cquantize = (my_cquantize_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_cquantizer)); + cinfo->cquantize = (struct jpeg_color_quantizer *) cquantize; + cquantize->pub.start_pass = start_pass_2_quant; + cquantize->pub.new_color_map = new_color_map_2_quant; + cquantize->fserrors = NULL; /* flag optional arrays not allocated */ + cquantize->error_limiter = NULL; + + /* Make sure jdmaster didn't give me a case I can't handle */ + if (cinfo->out_color_components != 3) + ERREXIT(cinfo, JERR_NOTIMPL); + + /* Allocate the histogram/inverse colormap storage */ + cquantize->histogram = (hist3d) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, HIST_C0_ELEMS * SIZEOF(hist2d)); + for (i = 0; i < HIST_C0_ELEMS; i++) { + cquantize->histogram[i] = (hist2d) (*cinfo->mem->alloc_large) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + HIST_C1_ELEMS*HIST_C2_ELEMS * SIZEOF(histcell)); + } + cquantize->needs_zeroed = TRUE; /* histogram is garbage now */ + + /* Allocate storage for the completed colormap, if required. + * We do this now since it is FAR storage and may affect + * the memory manager's space calculations. + */ + if (cinfo->enable_2pass_quant) { + /* Make sure color count is acceptable */ + int desired = cinfo->desired_number_of_colors; + /* Lower bound on # of colors ... somewhat arbitrary as long as > 0 */ + if (desired < 8) + ERREXIT1(cinfo, JERR_QUANT_FEW_COLORS, 8); + /* Make sure colormap indexes can be represented by JSAMPLEs */ + if (desired > MAXNUMCOLORS) + ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, MAXNUMCOLORS); + cquantize->sv_colormap = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo,JPOOL_IMAGE, (JDIMENSION) desired, (JDIMENSION) 3); + cquantize->desired = desired; + } else + cquantize->sv_colormap = NULL; + + /* Only F-S dithering or no dithering is supported. */ + /* If user asks for ordered dither, give him F-S. */ + if (cinfo->dither_mode != JDITHER_NONE) + cinfo->dither_mode = JDITHER_FS; + + /* Allocate Floyd-Steinberg workspace if necessary. + * This isn't really needed until pass 2, but again it is FAR storage. + * Although we will cope with a later change in dither_mode, + * we do not promise to honor max_memory_to_use if dither_mode changes. + */ + if (cinfo->dither_mode == JDITHER_FS) { + cquantize->fserrors = (FSERRPTR) (*cinfo->mem->alloc_large) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (size_t) ((cinfo->output_width + 2) * (3 * SIZEOF(FSERROR)))); + /* Might as well create the error-limiting table too. */ + init_error_limit(cinfo); + } +} + +#endif /* QUANT_2PASS_SUPPORTED */ diff --git a/gdcm/Utilities/gdcmjpeg/jutils.c b/gdcm/Utilities/gdcmjpeg/jutils.c new file mode 100644 index 0000000..23abeb8 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jutils.c @@ -0,0 +1,179 @@ +/* + * jutils.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains tables and miscellaneous utility routines needed + * for both compression and decompression. + * Note we prefix all global names with "j" to minimize conflicts with + * a surrounding application. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * jpeg_zigzag_order[i] is the zigzag-order position of the i'th element + * of a DCT block read in natural order (left to right, top to bottom). + */ + +#if 0 /* This table is not actually needed in v6a */ + +const int jpeg_zigzag_order[DCTSIZE2] = { + 0, 1, 5, 6, 14, 15, 27, 28, + 2, 4, 7, 13, 16, 26, 29, 42, + 3, 8, 12, 17, 25, 30, 41, 43, + 9, 11, 18, 24, 31, 40, 44, 53, + 10, 19, 23, 32, 39, 45, 52, 54, + 20, 22, 33, 38, 46, 51, 55, 60, + 21, 34, 37, 47, 50, 56, 59, 61, + 35, 36, 48, 49, 57, 58, 62, 63 +}; + +#endif + +/* + * jpeg_natural_order[i] is the natural-order position of the i'th element + * of zigzag order. + * + * When reading corrupted data, the Huffman decoders could attempt + * to reference an entry beyond the end of this array (if the decoded + * zero run length reaches past the end of the block). To prevent + * wild stores without adding an inner-loop test, we put some extra + * "63"s after the real entries. This will cause the extra coefficient + * to be stored in location 63 of the block, not somewhere random. + * The worst case would be a run-length of 15, which means we need 16 + * fake entries. + */ + +const int jpeg_natural_order[DCTSIZE2+16] = { + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63, + 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */ + 63, 63, 63, 63, 63, 63, 63, 63 +}; + + +/* + * Arithmetic utilities + */ + +GLOBAL(long) +jdiv_round_up (long a, long b) +/* Compute a/b rounded up to next integer, ie, ceil(a/b) */ +/* Assumes a >= 0, b > 0 */ +{ + return (a + b - 1L) / b; +} + + +GLOBAL(long) +jround_up (long a, long b) +/* Compute a rounded up to next multiple of b, ie, ceil(a/b)*b */ +/* Assumes a >= 0, b > 0 */ +{ + a += b - 1L; + return a - (a % b); +} + + +/* On normal machines we can apply MEMCOPY() and MEMZERO() to sample arrays + * and coefficient-block arrays. This won't work on 80x86 because the arrays + * are FAR and we're assuming a small-pointer memory model. However, some + * DOS compilers provide far-pointer versions of memcpy() and memset() even + * in the small-model libraries. These will be used if USE_FMEM is defined. + * Otherwise, the routines below do it the hard way. (The performance cost + * is not all that great, because these routines aren't very heavily used.) + */ + +#ifndef NEED_FAR_POINTERS /* normal case, same as regular macros */ +#define FMEMCOPY(dest,src,size) MEMCOPY(dest,src,size) +#define FMEMZERO(target,size) MEMZERO(target,size) +#else /* 80x86 case, define if we can */ +#ifdef USE_FMEM +#define FMEMCOPY(dest,src,size) _fmemcpy((void FAR *)(dest), (const void FAR *)(src), (size_t)(size)) +#define FMEMZERO(target,size) _fmemset((void FAR *)(target), 0, (size_t)(size)) +#endif +#endif + + +GLOBAL(void) +jcopy_sample_rows (JSAMPARRAY input_array, int source_row, + JSAMPARRAY output_array, int dest_row, + int num_rows, JDIMENSION num_cols) +/* Copy some rows of samples from one place to another. + * num_rows rows are copied from input_array[source_row++] + * to output_array[dest_row++]; these areas may overlap for duplication. + * The source and destination arrays must be at least as wide as num_cols. + */ +{ + register JSAMPROW inptr, outptr; +#ifdef FMEMCOPY + register size_t count = (size_t) (num_cols * SIZEOF(JSAMPLE)); +#else + register JDIMENSION count; +#endif + register int row; + + input_array += source_row; + output_array += dest_row; + + for (row = num_rows; row > 0; row--) { + inptr = *input_array++; + outptr = *output_array++; +#ifdef FMEMCOPY + FMEMCOPY(outptr, inptr, count); +#else + for (count = num_cols; count > 0; count--) + *outptr++ = *inptr++; /* needn't bother with GETJSAMPLE() here */ +#endif + } +} + + +GLOBAL(void) +jcopy_block_row (JBLOCKROW input_row, JBLOCKROW output_row, + JDIMENSION num_blocks) +/* Copy a row of coefficient blocks from one place to another. */ +{ +#ifdef FMEMCOPY + FMEMCOPY(output_row, input_row, num_blocks * (DCTSIZE2 * SIZEOF(JCOEF))); +#else + register JCOEFPTR inptr, outptr; + register long count; + + inptr = (JCOEFPTR) input_row; + outptr = (JCOEFPTR) output_row; + for (count = (long) num_blocks * DCTSIZE2; count > 0; count--) { + *outptr++ = *inptr++; + } +#endif +} + + +GLOBAL(void) +jzero_far (void FAR * target, size_t bytestozero) +/* Zero out a chunk of FAR memory. */ +/* This might be sample-array data, block-array data, or alloc_large data. */ +{ +#ifdef FMEMZERO + FMEMZERO(target, bytestozero); +#else + register char FAR * ptr = (char FAR *) target; + register size_t count; + + for (count = bytestozero; count > 0; count--) { + *ptr++ = 0; + } +#endif +} diff --git a/gdcm/Utilities/gdcmjpeg/jversion.h b/gdcm/Utilities/gdcmjpeg/jversion.h new file mode 100644 index 0000000..6472c58 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/jversion.h @@ -0,0 +1,14 @@ +/* + * jversion.h + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains software version identification. + */ + + +#define JVERSION "6b 27-Mar-1998" + +#define JCOPYRIGHT "Copyright (C) 1998, Thomas G. Lane" diff --git a/gdcm/Utilities/gdcmjpeg/libjpeg.doc b/gdcm/Utilities/gdcmjpeg/libjpeg.doc new file mode 100644 index 0000000..8e36c91 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/libjpeg.doc @@ -0,0 +1,3011 @@ +USING THE IJG JPEG LIBRARY + +Copyright (C) 1994-1998, Thomas G. Lane. +This file is part of the Independent JPEG Group's software. +For conditions of distribution and use, see the accompanying README file. + + +This file describes how to use the IJG JPEG library within an application +program. Read it if you want to write a program that uses the library. + +The file example.c provides heavily commented skeleton code for calling the +JPEG library. Also see jpeglib.h (the include file to be used by application +programs) for full details about data structures and function parameter lists. +The library source code, of course, is the ultimate reference. + +Note that there have been *major* changes from the application interface +presented by IJG version 4 and earlier versions. The old design had several +inherent limitations, and it had accumulated a lot of cruft as we added +features while trying to minimize application-interface changes. We have +sacrificed backward compatibility in the version 5 rewrite, but we think the +improvements justify this. + + +TABLE OF CONTENTS +----------------- + +Overview: + Functions provided by the library + Outline of typical usage +Basic library usage: + Data formats + Compression details + Decompression details + Mechanics of usage: include files, linking, etc +Advanced features: + Compression parameter selection + Decompression parameter selection + Special color spaces + Error handling + Compressed data handling (source and destination managers) + I/O suspension + Progressive JPEG support + Buffered-image mode + Abbreviated datastreams and multiple images + Special markers + Raw (downsampled) image data + Really raw data: DCT coefficients + Progress monitoring + Memory management + Memory usage + Library compile-time options + Portability considerations + Notes for MS-DOS implementors + +You should read at least the overview and basic usage sections before trying +to program with the library. The sections on advanced features can be read +if and when you need them. + + +OVERVIEW +======== + +Functions provided by the library +--------------------------------- + +The IJG JPEG library provides C code to read and write JPEG-compressed image +files. The surrounding application program receives or supplies image data a +scanline at a time, using a straightforward uncompressed image format. All +details of color conversion and other preprocessing/postprocessing can be +handled by the library. + +The library includes a substantial amount of code that is not covered by the +JPEG standard but is necessary for typical applications of JPEG. These +functions preprocess the image before JPEG compression or postprocess it after +decompression. They include colorspace conversion, downsampling/upsampling, +and color quantization. The application indirectly selects use of this code +by specifying the format in which it wishes to supply or receive image data. +For example, if colormapped output is requested, then the decompression +library automatically invokes color quantization. + +A wide range of quality vs. speed tradeoffs are possible in JPEG processing, +and even more so in decompression postprocessing. The decompression library +provides multiple implementations that cover most of the useful tradeoffs, +ranging from very-high-quality down to fast-preview operation. On the +compression side we have generally not provided low-quality choices, since +compression is normally less time-critical. It should be understood that the +low-quality modes may not meet the JPEG standard's accuracy requirements; +nonetheless, they are useful for viewers. + +A word about functions *not* provided by the library. We handle a subset of +the ISO JPEG standard; most baseline, extended-sequential, and progressive +JPEG processes are supported. (Our subset includes all features now in common +use.) Unsupported ISO options include: + * Hierarchical storage + * Arithmetic entropy coding (unsupported for legal reasons) + * DNL marker + * Nonintegral subsampling ratios +We support both 8- and 12-bit data precision, but this is a compile-time +choice rather than a run-time choice; hence it is difficult to use both +precisions in a single application. + +By itself, the library handles only interchange JPEG datastreams --- in +particular the widely used JFIF file format. The library can be used by +surrounding code to process interchange or abbreviated JPEG datastreams that +are embedded in more complex file formats. (For example, this library is +used by the free LIBTIFF library to support JPEG compression in TIFF.) + + +Outline of typical usage +------------------------ + +The rough outline of a JPEG compression operation is: + + Allocate and initialize a JPEG compression object + Specify the destination for the compressed data (eg, a file) + Set parameters for compression, including image size & colorspace + jpeg_start_compress(...); + while (scan lines remain to be written) + jpeg_write_scanlines(...); + jpeg_finish_compress(...); + Release the JPEG compression object + +A JPEG compression object holds parameters and working state for the JPEG +library. We make creation/destruction of the object separate from starting +or finishing compression of an image; the same object can be re-used for a +series of image compression operations. This makes it easy to re-use the +same parameter settings for a sequence of images. Re-use of a JPEG object +also has important implications for processing abbreviated JPEG datastreams, +as discussed later. + +The image data to be compressed is supplied to jpeg_write_scanlines() from +in-memory buffers. If the application is doing file-to-file compression, +reading image data from the source file is the application's responsibility. +The library emits compressed data by calling a "data destination manager", +which typically will write the data into a file; but the application can +provide its own destination manager to do something else. + +Similarly, the rough outline of a JPEG decompression operation is: + + Allocate and initialize a JPEG decompression object + Specify the source of the compressed data (eg, a file) + Call jpeg_read_header() to obtain image info + Set parameters for decompression + jpeg_start_decompress(...); + while (scan lines remain to be read) + jpeg_read_scanlines(...); + jpeg_finish_decompress(...); + Release the JPEG decompression object + +This is comparable to the compression outline except that reading the +datastream header is a separate step. This is helpful because information +about the image's size, colorspace, etc is available when the application +selects decompression parameters. For example, the application can choose an +output scaling ratio that will fit the image into the available screen size. + +The decompression library obtains compressed data by calling a data source +manager, which typically will read the data from a file; but other behaviors +can be obtained with a custom source manager. Decompressed data is delivered +into in-memory buffers passed to jpeg_read_scanlines(). + +It is possible to abort an incomplete compression or decompression operation +by calling jpeg_abort(); or, if you do not need to retain the JPEG object, +simply release it by calling jpeg_destroy(). + +JPEG compression and decompression objects are two separate struct types. +However, they share some common fields, and certain routines such as +jpeg_destroy() can work on either type of object. + +The JPEG library has no static variables: all state is in the compression +or decompression object. Therefore it is possible to process multiple +compression and decompression operations concurrently, using multiple JPEG +objects. + +Both compression and decompression can be done in an incremental memory-to- +memory fashion, if suitable source/destination managers are used. See the +section on "I/O suspension" for more details. + + +BASIC LIBRARY USAGE +=================== + +Data formats +------------ + +Before diving into procedural details, it is helpful to understand the +image data format that the JPEG library expects or returns. + +The standard input image format is a rectangular array of pixels, with each +pixel having the same number of "component" or "sample" values (color +channels). You must specify how many components there are and the colorspace +interpretation of the components. Most applications will use RGB data +(three components per pixel) or grayscale data (one component per pixel). +PLEASE NOTE THAT RGB DATA IS THREE SAMPLES PER PIXEL, GRAYSCALE ONLY ONE. +A remarkable number of people manage to miss this, only to find that their +programs don't work with grayscale JPEG files. + +There is no provision for colormapped input. JPEG files are always full-color +or full grayscale (or sometimes another colorspace such as CMYK). You can +feed in a colormapped image by expanding it to full-color format. However +JPEG often doesn't work very well with source data that has been colormapped, +because of dithering noise. This is discussed in more detail in the JPEG FAQ +and the other references mentioned in the README file. + +Pixels are stored by scanlines, with each scanline running from left to +right. The component values for each pixel are adjacent in the row; for +example, R,G,B,R,G,B,R,G,B,... for 24-bit RGB color. Each scanline is an +array of data type JSAMPLE --- which is typically "unsigned char", unless +you've changed jmorecfg.h. (You can also change the RGB pixel layout, say +to B,G,R order, by modifying jmorecfg.h. But see the restrictions listed in +that file before doing so.) + +A 2-D array of pixels is formed by making a list of pointers to the starts of +scanlines; so the scanlines need not be physically adjacent in memory. Even +if you process just one scanline at a time, you must make a one-element +pointer array to conform to this structure. Pointers to JSAMPLE rows are of +type JSAMPROW, and the pointer to the pointer array is of type JSAMPARRAY. + +The library accepts or supplies one or more complete scanlines per call. +It is not possible to process part of a row at a time. Scanlines are always +processed top-to-bottom. You can process an entire image in one call if you +have it all in memory, but usually it's simplest to process one scanline at +a time. + +For best results, source data values should have the precision specified by +BITS_IN_JSAMPLE (normally 8 bits). For instance, if you choose to compress +data that's only 6 bits/channel, you should left-justify each value in a +byte before passing it to the compressor. If you need to compress data +that has more than 8 bits/channel, compile with BITS_IN_JSAMPLE = 12. +(See "Library compile-time options", later.) + + +The data format returned by the decompressor is the same in all details, +except that colormapped output is supported. (Again, a JPEG file is never +colormapped. But you can ask the decompressor to perform on-the-fly color +quantization to deliver colormapped output.) If you request colormapped +output then the returned data array contains a single JSAMPLE per pixel; +its value is an index into a color map. The color map is represented as +a 2-D JSAMPARRAY in which each row holds the values of one color component, +that is, colormap[i][j] is the value of the i'th color component for pixel +value (map index) j. Note that since the colormap indexes are stored in +JSAMPLEs, the maximum number of colors is limited by the size of JSAMPLE +(ie, at most 256 colors for an 8-bit JPEG library). + + +Compression details +------------------- + +Here we revisit the JPEG compression outline given in the overview. + +1. Allocate and initialize a JPEG compression object. + +A JPEG compression object is a "struct jpeg_compress_struct". (It also has +a bunch of subsidiary structures which are allocated via malloc(), but the +application doesn't control those directly.) This struct can be just a local +variable in the calling routine, if a single routine is going to execute the +whole JPEG compression sequence. Otherwise it can be static or allocated +from malloc(). + +You will also need a structure representing a JPEG error handler. The part +of this that the library cares about is a "struct jpeg_error_mgr". If you +are providing your own error handler, you'll typically want to embed the +jpeg_error_mgr struct in a larger structure; this is discussed later under +"Error handling". For now we'll assume you are just using the default error +handler. The default error handler will print JPEG error/warning messages +on stderr, and it will call exit() if a fatal error occurs. + +You must initialize the error handler structure, store a pointer to it into +the JPEG object's "err" field, and then call jpeg_create_compress() to +initialize the rest of the JPEG object. + +Typical code for this step, if you are using the default error handler, is + + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; + ... + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_compress(&cinfo); + +jpeg_create_compress allocates a small amount of memory, so it could fail +if you are out of memory. In that case it will exit via the error handler; +that's why the error handler must be initialized first. + + +2. Specify the destination for the compressed data (eg, a file). + +As previously mentioned, the JPEG library delivers compressed data to a +"data destination" module. The library includes one data destination +module which knows how to write to a stdio stream. You can use your own +destination module if you want to do something else, as discussed later. + +If you use the standard destination module, you must open the target stdio +stream beforehand. Typical code for this step looks like: + + FILE * outfile; + ... + if ((outfile = fopen(filename, "wb")) == NULL) { + fprintf(stderr, "can't open %s\n", filename); + exit(1); + } + jpeg_stdio_dest(&cinfo, outfile); + +where the last line invokes the standard destination module. + +WARNING: it is critical that the binary compressed data be delivered to the +output file unchanged. On non-Unix systems the stdio library may perform +newline translation or otherwise corrupt binary data. To suppress this +behavior, you may need to use a "b" option to fopen (as shown above), or use +setmode() or another routine to put the stdio stream in binary mode. See +cjpeg.c and djpeg.c for code that has been found to work on many systems. + +You can select the data destination after setting other parameters (step 3), +if that's more convenient. You may not change the destination between +calling jpeg_start_compress() and jpeg_finish_compress(). + + +3. Set parameters for compression, including image size & colorspace. + +You must supply information about the source image by setting the following +fields in the JPEG object (cinfo structure): + + image_width Width of image, in pixels + image_height Height of image, in pixels + input_components Number of color channels (samples per pixel) + in_color_space Color space of source image + +The image dimensions are, hopefully, obvious. JPEG supports image dimensions +of 1 to 64K pixels in either direction. The input color space is typically +RGB or grayscale, and input_components is 3 or 1 accordingly. (See "Special +color spaces", later, for more info.) The in_color_space field must be +assigned one of the J_COLOR_SPACE enum constants, typically JCS_RGB or +JCS_GRAYSCALE. + +JPEG has a large number of compression parameters that determine how the +image is encoded. Most applications don't need or want to know about all +these parameters. You can set all the parameters to reasonable defaults by +calling jpeg_set_defaults(); then, if there are particular values you want +to change, you can do so after that. The "Compression parameter selection" +section tells about all the parameters. + +You must set in_color_space correctly before calling jpeg_set_defaults(), +because the defaults depend on the source image colorspace. However the +other three source image parameters need not be valid until you call +jpeg_start_compress(). There's no harm in calling jpeg_set_defaults() more +than once, if that happens to be convenient. + +Typical code for a 24-bit RGB source image is + + cinfo.image_width = Width; /* image width and height, in pixels */ + cinfo.image_height = Height; + cinfo.input_components = 3; /* # of color components per pixel */ + cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ + + jpeg_set_defaults(&cinfo); + /* Make optional parameter settings here */ + + +4. jpeg_start_compress(...); + +After you have established the data destination and set all the necessary +source image info and other parameters, call jpeg_start_compress() to begin +a compression cycle. This will initialize internal state, allocate working +storage, and emit the first few bytes of the JPEG datastream header. + +Typical code: + + jpeg_start_compress(&cinfo, TRUE); + +The "TRUE" parameter ensures that a complete JPEG interchange datastream +will be written. This is appropriate in most cases. If you think you might +want to use an abbreviated datastream, read the section on abbreviated +datastreams, below. + +Once you have called jpeg_start_compress(), you may not alter any JPEG +parameters or other fields of the JPEG object until you have completed +the compression cycle. + + +5. while (scan lines remain to be written) + jpeg_write_scanlines(...); + +Now write all the required image data by calling jpeg_write_scanlines() +one or more times. You can pass one or more scanlines in each call, up +to the total image height. In most applications it is convenient to pass +just one or a few scanlines at a time. The expected format for the passed +data is discussed under "Data formats", above. + +Image data should be written in top-to-bottom scanline order. The JPEG spec +contains some weasel wording about how top and bottom are application-defined +terms (a curious interpretation of the English language...) but if you want +your files to be compatible with everyone else's, you WILL use top-to-bottom +order. If the source data must be read in bottom-to-top order, you can use +the JPEG library's virtual array mechanism to invert the data efficiently. +Examples of this can be found in the sample application cjpeg. + +The library maintains a count of the number of scanlines written so far +in the next_scanline field of the JPEG object. Usually you can just use +this variable as the loop counter, so that the loop test looks like +"while (cinfo.next_scanline < cinfo.image_height)". + +Code for this step depends heavily on the way that you store the source data. +example.c shows the following code for the case of a full-size 2-D source +array containing 3-byte RGB pixels: + + JSAMPROW row_pointer[1]; /* pointer to a single row */ + int row_stride; /* physical row width in buffer */ + + row_stride = image_width * 3; /* JSAMPLEs per row in image_buffer */ + + while (cinfo.next_scanline < cinfo.image_height) { + row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride]; + jpeg_write_scanlines(&cinfo, row_pointer, 1); + } + +jpeg_write_scanlines() returns the number of scanlines actually written. +This will normally be equal to the number passed in, so you can usually +ignore the return value. It is different in just two cases: + * If you try to write more scanlines than the declared image height, + the additional scanlines are ignored. + * If you use a suspending data destination manager, output buffer overrun + will cause the compressor to return before accepting all the passed lines. + This feature is discussed under "I/O suspension", below. The normal + stdio destination manager will NOT cause this to happen. +In any case, the return value is the same as the change in the value of +next_scanline. + + +6. jpeg_finish_compress(...); + +After all the image data has been written, call jpeg_finish_compress() to +complete the compression cycle. This step is ESSENTIAL to ensure that the +last bufferload of data is written to the data destination. +jpeg_finish_compress() also releases working memory associated with the JPEG +object. + +Typical code: + + jpeg_finish_compress(&cinfo); + +If using the stdio destination manager, don't forget to close the output +stdio stream (if necessary) afterwards. + +If you have requested a multi-pass operating mode, such as Huffman code +optimization, jpeg_finish_compress() will perform the additional passes using +data buffered by the first pass. In this case jpeg_finish_compress() may take +quite a while to complete. With the default compression parameters, this will +not happen. + +It is an error to call jpeg_finish_compress() before writing the necessary +total number of scanlines. If you wish to abort compression, call +jpeg_abort() as discussed below. + +After completing a compression cycle, you may dispose of the JPEG object +as discussed next, or you may use it to compress another image. In that case +return to step 2, 3, or 4 as appropriate. If you do not change the +destination manager, the new datastream will be written to the same target. +If you do not change any JPEG parameters, the new datastream will be written +with the same parameters as before. Note that you can change the input image +dimensions freely between cycles, but if you change the input colorspace, you +should call jpeg_set_defaults() to adjust for the new colorspace; and then +you'll need to repeat all of step 3. + + +7. Release the JPEG compression object. + +When you are done with a JPEG compression object, destroy it by calling +jpeg_destroy_compress(). This will free all subsidiary memory (regardless of +the previous state of the object). Or you can call jpeg_destroy(), which +works for either compression or decompression objects --- this may be more +convenient if you are sharing code between compression and decompression +cases. (Actually, these routines are equivalent except for the declared type +of the passed pointer. To avoid gripes from ANSI C compilers, jpeg_destroy() +should be passed a j_common_ptr.) + +If you allocated the jpeg_compress_struct structure from malloc(), freeing +it is your responsibility --- jpeg_destroy() won't. Ditto for the error +handler structure. + +Typical code: + + jpeg_destroy_compress(&cinfo); + + +8. Aborting. + +If you decide to abort a compression cycle before finishing, you can clean up +in either of two ways: + +* If you don't need the JPEG object any more, just call + jpeg_destroy_compress() or jpeg_destroy() to release memory. This is + legitimate at any point after calling jpeg_create_compress() --- in fact, + it's safe even if jpeg_create_compress() fails. + +* If you want to re-use the JPEG object, call jpeg_abort_compress(), or call + jpeg_abort() which works on both compression and decompression objects. + This will return the object to an idle state, releasing any working memory. + jpeg_abort() is allowed at any time after successful object creation. + +Note that cleaning up the data destination, if required, is your +responsibility; neither of these routines will call term_destination(). +(See "Compressed data handling", below, for more about that.) + +jpeg_destroy() and jpeg_abort() are the only safe calls to make on a JPEG +object that has reported an error by calling error_exit (see "Error handling" +for more info). The internal state of such an object is likely to be out of +whack. Either of these two routines will return the object to a known state. + + +Decompression details +--------------------- + +Here we revisit the JPEG decompression outline given in the overview. + +1. Allocate and initialize a JPEG decompression object. + +This is just like initialization for compression, as discussed above, +except that the object is a "struct jpeg_decompress_struct" and you +call jpeg_create_decompress(). Error handling is exactly the same. + +Typical code: + + struct jpeg_decompress_struct cinfo; + struct jpeg_error_mgr jerr; + ... + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_decompress(&cinfo); + +(Both here and in the IJG code, we usually use variable name "cinfo" for +both compression and decompression objects.) + + +2. Specify the source of the compressed data (eg, a file). + +As previously mentioned, the JPEG library reads compressed data from a "data +source" module. The library includes one data source module which knows how +to read from a stdio stream. You can use your own source module if you want +to do something else, as discussed later. + +If you use the standard source module, you must open the source stdio stream +beforehand. Typical code for this step looks like: + + FILE * infile; + ... + if ((infile = fopen(filename, "rb")) == NULL) { + fprintf(stderr, "can't open %s\n", filename); + exit(1); + } + jpeg_stdio_src(&cinfo, infile); + +where the last line invokes the standard source module. + +WARNING: it is critical that the binary compressed data be read unchanged. +On non-Unix systems the stdio library may perform newline translation or +otherwise corrupt binary data. To suppress this behavior, you may need to use +a "b" option to fopen (as shown above), or use setmode() or another routine to +put the stdio stream in binary mode. See cjpeg.c and djpeg.c for code that +has been found to work on many systems. + +You may not change the data source between calling jpeg_read_header() and +jpeg_finish_decompress(). If you wish to read a series of JPEG images from +a single source file, you should repeat the jpeg_read_header() to +jpeg_finish_decompress() sequence without reinitializing either the JPEG +object or the data source module; this prevents buffered input data from +being discarded. + + +3. Call jpeg_read_header() to obtain image info. + +Typical code for this step is just + + jpeg_read_header(&cinfo, TRUE); + +This will read the source datastream header markers, up to the beginning +of the compressed data proper. On return, the image dimensions and other +info have been stored in the JPEG object. The application may wish to +consult this information before selecting decompression parameters. + +More complex code is necessary if + * A suspending data source is used --- in that case jpeg_read_header() + may return before it has read all the header data. See "I/O suspension", + below. The normal stdio source manager will NOT cause this to happen. + * Abbreviated JPEG files are to be processed --- see the section on + abbreviated datastreams. Standard applications that deal only in + interchange JPEG files need not be concerned with this case either. + +It is permissible to stop at this point if you just wanted to find out the +image dimensions and other header info for a JPEG file. In that case, +call jpeg_destroy() when you are done with the JPEG object, or call +jpeg_abort() to return it to an idle state before selecting a new data +source and reading another header. + + +4. Set parameters for decompression. + +jpeg_read_header() sets appropriate default decompression parameters based on +the properties of the image (in particular, its colorspace). However, you +may well want to alter these defaults before beginning the decompression. +For example, the default is to produce full color output from a color file. +If you want colormapped output you must ask for it. Other options allow the +returned image to be scaled and allow various speed/quality tradeoffs to be +selected. "Decompression parameter selection", below, gives details. + +If the defaults are appropriate, nothing need be done at this step. + +Note that all default values are set by each call to jpeg_read_header(). +If you reuse a decompression object, you cannot expect your parameter +settings to be preserved across cycles, as you can for compression. +You must set desired parameter values each time. + + +5. jpeg_start_decompress(...); + +Once the parameter values are satisfactory, call jpeg_start_decompress() to +begin decompression. This will initialize internal state, allocate working +memory, and prepare for returning data. + +Typical code is just + + jpeg_start_decompress(&cinfo); + +If you have requested a multi-pass operating mode, such as 2-pass color +quantization, jpeg_start_decompress() will do everything needed before data +output can begin. In this case jpeg_start_decompress() may take quite a while +to complete. With a single-scan (non progressive) JPEG file and default +decompression parameters, this will not happen; jpeg_start_decompress() will +return quickly. + +After this call, the final output image dimensions, including any requested +scaling, are available in the JPEG object; so is the selected colormap, if +colormapped output has been requested. Useful fields include + + output_width image width and height, as scaled + output_height + out_color_components # of color components in out_color_space + output_components # of color components returned per pixel + colormap the selected colormap, if any + actual_number_of_colors number of entries in colormap + +output_components is 1 (a colormap index) when quantizing colors; otherwise it +equals out_color_components. It is the number of JSAMPLE values that will be +emitted per pixel in the output arrays. + +Typically you will need to allocate data buffers to hold the incoming image. +You will need output_width * output_components JSAMPLEs per scanline in your +output buffer, and a total of output_height scanlines will be returned. + +Note: if you are using the JPEG library's internal memory manager to allocate +data buffers (as djpeg does), then the manager's protocol requires that you +request large buffers *before* calling jpeg_start_decompress(). This is a +little tricky since the output_XXX fields are not normally valid then. You +can make them valid by calling jpeg_calc_output_dimensions() after setting the +relevant parameters (scaling, output color space, and quantization flag). + + +6. while (scan lines remain to be read) + jpeg_read_scanlines(...); + +Now you can read the decompressed image data by calling jpeg_read_scanlines() +one or more times. At each call, you pass in the maximum number of scanlines +to be read (ie, the height of your working buffer); jpeg_read_scanlines() +will return up to that many lines. The return value is the number of lines +actually read. The format of the returned data is discussed under "Data +formats", above. Don't forget that grayscale and color JPEGs will return +different data formats! + +Image data is returned in top-to-bottom scanline order. If you must write +out the image in bottom-to-top order, you can use the JPEG library's virtual +array mechanism to invert the data efficiently. Examples of this can be +found in the sample application djpeg. + +The library maintains a count of the number of scanlines returned so far +in the output_scanline field of the JPEG object. Usually you can just use +this variable as the loop counter, so that the loop test looks like +"while (cinfo.output_scanline < cinfo.output_height)". (Note that the test +should NOT be against image_height, unless you never use scaling. The +image_height field is the height of the original unscaled image.) +The return value always equals the change in the value of output_scanline. + +If you don't use a suspending data source, it is safe to assume that +jpeg_read_scanlines() reads at least one scanline per call, until the +bottom of the image has been reached. + +If you use a buffer larger than one scanline, it is NOT safe to assume that +jpeg_read_scanlines() fills it. (The current implementation returns only a +few scanlines per call, no matter how large a buffer you pass.) So you must +always provide a loop that calls jpeg_read_scanlines() repeatedly until the +whole image has been read. + + +7. jpeg_finish_decompress(...); + +After all the image data has been read, call jpeg_finish_decompress() to +complete the decompression cycle. This causes working memory associated +with the JPEG object to be released. + +Typical code: + + jpeg_finish_decompress(&cinfo); + +If using the stdio source manager, don't forget to close the source stdio +stream if necessary. + +It is an error to call jpeg_finish_decompress() before reading the correct +total number of scanlines. If you wish to abort decompression, call +jpeg_abort() as discussed below. + +After completing a decompression cycle, you may dispose of the JPEG object as +discussed next, or you may use it to decompress another image. In that case +return to step 2 or 3 as appropriate. If you do not change the source +manager, the next image will be read from the same source. + + +8. Release the JPEG decompression object. + +When you are done with a JPEG decompression object, destroy it by calling +jpeg_destroy_decompress() or jpeg_destroy(). The previous discussion of +destroying compression objects applies here too. + +Typical code: + + jpeg_destroy_decompress(&cinfo); + + +9. Aborting. + +You can abort a decompression cycle by calling jpeg_destroy_decompress() or +jpeg_destroy() if you don't need the JPEG object any more, or +jpeg_abort_decompress() or jpeg_abort() if you want to reuse the object. +The previous discussion of aborting compression cycles applies here too. + + +Mechanics of usage: include files, linking, etc +----------------------------------------------- + +Applications using the JPEG library should include the header file jpeglib.h +to obtain declarations of data types and routines. Before including +jpeglib.h, include system headers that define at least the typedefs FILE and +size_t. On ANSI-conforming systems, including is sufficient; on +older Unix systems, you may need to define size_t. + +If the application needs to refer to individual JPEG library error codes, also +include jerror.h to define those symbols. + +jpeglib.h indirectly includes the files jconfig.h and jmorecfg.h. If you are +installing the JPEG header files in a system directory, you will want to +install all four files: jpeglib.h, jerror.h, jconfig.h, jmorecfg.h. + +The most convenient way to include the JPEG code into your executable program +is to prepare a library file ("libjpeg.a", or a corresponding name on non-Unix +machines) and reference it at your link step. If you use only half of the +library (only compression or only decompression), only that much code will be +included from the library, unless your linker is hopelessly brain-damaged. +The supplied makefiles build libjpeg.a automatically (see install.doc). + +While you can build the JPEG library as a shared library if the whim strikes +you, we don't really recommend it. The trouble with shared libraries is that +at some point you'll probably try to substitute a new version of the library +without recompiling the calling applications. That generally doesn't work +because the parameter struct declarations usually change with each new +version. In other words, the library's API is *not* guaranteed binary +compatible across versions; we only try to ensure source-code compatibility. +(In hindsight, it might have been smarter to hide the parameter structs from +applications and introduce a ton of access functions instead. Too late now, +however.) + +On some systems your application may need to set up a signal handler to ensure +that temporary files are deleted if the program is interrupted. This is most +critical if you are on MS-DOS and use the jmemdos.c memory manager back end; +it will try to grab extended memory for temp files, and that space will NOT be +freed automatically. See cjpeg.c or djpeg.c for an example signal handler. + +It may be worth pointing out that the core JPEG library does not actually +require the stdio library: only the default source/destination managers and +error handler need it. You can use the library in a stdio-less environment +if you replace those modules and use jmemnobs.c (or another memory manager of +your own devising). More info about the minimum system library requirements +may be found in jinclude.h. + + +ADVANCED FEATURES +================= + +Compression parameter selection +------------------------------- + +This section describes all the optional parameters you can set for JPEG +compression, as well as the "helper" routines provided to assist in this +task. Proper setting of some parameters requires detailed understanding +of the JPEG standard; if you don't know what a parameter is for, it's best +not to mess with it! See REFERENCES in the README file for pointers to +more info about JPEG. + +It's a good idea to call jpeg_set_defaults() first, even if you plan to set +all the parameters; that way your code is more likely to work with future JPEG +libraries that have additional parameters. For the same reason, we recommend +you use a helper routine where one is provided, in preference to twiddling +cinfo fields directly. + +The helper routines are: + +jpeg_set_defaults (j_compress_ptr cinfo) + This routine sets all JPEG parameters to reasonable defaults, using + only the input image's color space (field in_color_space, which must + already be set in cinfo). Many applications will only need to use + this routine and perhaps jpeg_set_quality(). + +jpeg_set_colorspace (j_compress_ptr cinfo, J_COLOR_SPACE colorspace) + Sets the JPEG file's colorspace (field jpeg_color_space) as specified, + and sets other color-space-dependent parameters appropriately. See + "Special color spaces", below, before using this. A large number of + parameters, including all per-component parameters, are set by this + routine; if you want to twiddle individual parameters you should call + jpeg_set_colorspace() before rather than after. + +jpeg_default_colorspace (j_compress_ptr cinfo) + Selects an appropriate JPEG colorspace based on cinfo->in_color_space, + and calls jpeg_set_colorspace(). This is actually a subroutine of + jpeg_set_defaults(). It's broken out in case you want to change + just the colorspace-dependent JPEG parameters. + +jpeg_set_quality (j_compress_ptr cinfo, int quality, boolean force_baseline) + Constructs JPEG quantization tables appropriate for the indicated + quality setting. The quality value is expressed on the 0..100 scale + recommended by IJG (cjpeg's "-quality" switch uses this routine). + Note that the exact mapping from quality values to tables may change + in future IJG releases as more is learned about DCT quantization. + If the force_baseline parameter is TRUE, then the quantization table + entries are constrained to the range 1..255 for full JPEG baseline + compatibility. In the current implementation, this only makes a + difference for quality settings below 25, and it effectively prevents + very small/low quality files from being generated. The IJG decoder + is capable of reading the non-baseline files generated at low quality + settings when force_baseline is FALSE, but other decoders may not be. + +jpeg_set_linear_quality (j_compress_ptr cinfo, int scale_factor, + boolean force_baseline) + Same as jpeg_set_quality() except that the generated tables are the + sample tables given in the JPEC spec section K.1, multiplied by the + specified scale factor (which is expressed as a percentage; thus + scale_factor = 100 reproduces the spec's tables). Note that larger + scale factors give lower quality. This entry point is useful for + conforming to the Adobe PostScript DCT conventions, but we do not + recommend linear scaling as a user-visible quality scale otherwise. + force_baseline again constrains the computed table entries to 1..255. + +int jpeg_quality_scaling (int quality) + Converts a value on the IJG-recommended quality scale to a linear + scaling percentage. Note that this routine may change or go away + in future releases --- IJG may choose to adopt a scaling method that + can't be expressed as a simple scalar multiplier, in which case the + premise of this routine collapses. Caveat user. + +jpeg_add_quant_table (j_compress_ptr cinfo, int which_tbl, + const unsigned int *basic_table, + int scale_factor, boolean force_baseline) + Allows an arbitrary quantization table to be created. which_tbl + indicates which table slot to fill. basic_table points to an array + of 64 unsigned ints given in normal array order. These values are + multiplied by scale_factor/100 and then clamped to the range 1..65535 + (or to 1..255 if force_baseline is TRUE). + CAUTION: prior to library version 6a, jpeg_add_quant_table expected + the basic table to be given in JPEG zigzag order. If you need to + write code that works with either older or newer versions of this + routine, you must check the library version number. Something like + "#if JPEG_LIB_VERSION >= 61" is the right test. + +jpeg_simple_progression (j_compress_ptr cinfo) + Generates a default scan script for writing a progressive-JPEG file. + This is the recommended method of creating a progressive file, + unless you want to make a custom scan sequence. You must ensure that + the JPEG color space is set correctly before calling this routine. + +jpeg_simple_lossless (j_compress_ptr cinfo, int predictor, int point_transform) + Generates a default scan script for writing a lossless-JPEG file. + This is the recommended method of creating a lossless file, + unless you want to make a custom scan sequence. You must ensure that + the JPEG color space is set correctly before calling this routine. + + +Compression parameters (cinfo fields) include: + +J_DCT_METHOD dct_method + Selects the algorithm used for the DCT step. Choices are: + JDCT_ISLOW: slow but accurate integer algorithm + JDCT_IFAST: faster, less accurate integer method + JDCT_FLOAT: floating-point method + JDCT_DEFAULT: default method (normally JDCT_ISLOW) + JDCT_FASTEST: fastest method (normally JDCT_IFAST) + The FLOAT method is very slightly more accurate than the ISLOW method, + but may give different results on different machines due to varying + roundoff behavior. The integer methods should give the same results + on all machines. On machines with sufficiently fast FP hardware, the + floating-point method may also be the fastest. The IFAST method is + considerably less accurate than the other two; its use is not + recommended if high quality is a concern. JDCT_DEFAULT and + JDCT_FASTEST are macros configurable by each installation. + +J_COLOR_SPACE jpeg_color_space +int num_components + The JPEG color space and corresponding number of components; see + "Special color spaces", below, for more info. We recommend using + jpeg_set_color_space() if you want to change these. + +boolean optimize_coding + TRUE causes the compressor to compute optimal Huffman coding tables + for the image. This requires an extra pass over the data and + therefore costs a good deal of space and time. The default is + FALSE, which tells the compressor to use the supplied or default + Huffman tables. In most cases optimal tables save only a few percent + of file size compared to the default tables. Note that when this is + TRUE, you need not supply Huffman tables at all, and any you do + supply will be overwritten. + +unsigned int restart_interval +int restart_in_rows + To emit restart markers in the JPEG file, set one of these nonzero. + Set restart_interval to specify the exact interval in MCU blocks. + Set restart_in_rows to specify the interval in MCU rows. (If + restart_in_rows is not 0, then restart_interval is set after the + image width in MCUs is computed.) Defaults are zero (no restarts). + One restart marker per MCU row is often a good choice. + NOTE: the overhead of restart markers is higher in grayscale JPEG + files than in color files, and MUCH higher in progressive JPEGs. + If you use restarts, you may want to use larger intervals in those + cases. + +const jpeg_scan_info * scan_info +int num_scans + By default, scan_info is NULL; this causes the compressor to write a + single-scan sequential JPEG file. If not NULL, scan_info points to + an array of scan definition records of length num_scans. The + compressor will then write a JPEG file having one scan for each scan + definition record. This is used to generate noninterleaved or + progressive JPEG files. The library checks that the scan array + defines a valid JPEG scan sequence. (jpeg_simple_progression creates + a suitable scan definition array for progressive JPEG.) This is + discussed further under "Progressive JPEG support". + +int smoothing_factor + If non-zero, the input image is smoothed; the value should be 1 for + minimal smoothing to 100 for maximum smoothing. Consult jcsample.c + for details of the smoothing algorithm. The default is zero. + +boolean write_JFIF_header + If TRUE, a JFIF APP0 marker is emitted. jpeg_set_defaults() and + jpeg_set_colorspace() set this TRUE if a JFIF-legal JPEG color space + (ie, YCbCr or grayscale) is selected, otherwise FALSE. + +UINT8 JFIF_major_version +UINT8 JFIF_minor_version + The version number to be written into the JFIF marker. + jpeg_set_defaults() initializes the version to 1.01 (major=minor=1). + You should set it to 1.02 (major=1, minor=2) if you plan to write + any JFIF 1.02 extension markers. + +UINT8 density_unit +UINT16 X_density +UINT16 Y_density + The resolution information to be written into the JFIF marker; + not used otherwise. density_unit may be 0 for unknown, + 1 for dots/inch, or 2 for dots/cm. The default values are 0,1,1 + indicating square pixels of unknown size. + +boolean write_Adobe_marker + If TRUE, an Adobe APP14 marker is emitted. jpeg_set_defaults() and + jpeg_set_colorspace() set this TRUE if JPEG color space RGB, CMYK, + or YCCK is selected, otherwise FALSE. It is generally a bad idea + to set both write_JFIF_header and write_Adobe_marker. In fact, + you probably shouldn't change the default settings at all --- the + default behavior ensures that the JPEG file's color space can be + recognized by the decoder. + +JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS] + Pointers to coefficient quantization tables, one per table slot, + or NULL if no table is defined for a slot. Usually these should + be set via one of the above helper routines; jpeg_add_quant_table() + is general enough to define any quantization table. The other + routines will set up table slot 0 for luminance quality and table + slot 1 for chrominance. + +JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS] +JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS] + Pointers to Huffman coding tables, one per table slot, or NULL if + no table is defined for a slot. Slots 0 and 1 are filled with the + JPEG sample tables by jpeg_set_defaults(). If you need to allocate + more table structures, jpeg_alloc_huff_table() may be used. + Note that optimal Huffman tables can be computed for an image + by setting optimize_coding, as discussed above; there's seldom + any need to mess with providing your own Huffman tables. + +There are some additional cinfo fields which are not documented here +because you currently can't change them; for example, you can't set +arith_code TRUE because arithmetic coding is unsupported. + + +Per-component parameters are stored in the struct cinfo.comp_info[i] for +component number i. Note that components here refer to components of the +JPEG color space, *not* the source image color space. A suitably large +comp_info[] array is allocated by jpeg_set_defaults(); if you choose not +to use that routine, it's up to you to allocate the array. + +int component_id + The one-byte identifier code to be recorded in the JPEG file for + this component. For the standard color spaces, we recommend you + leave the default values alone. + +int h_samp_factor +int v_samp_factor + Horizontal and vertical sampling factors for the component; must + be 1..4 according to the JPEG standard. Note that larger sampling + factors indicate a higher-resolution component; many people find + this behavior quite unintuitive. The default values are 2,2 for + luminance components and 1,1 for chrominance components, except + for grayscale where 1,1 is used. + +int quant_tbl_no + Quantization table number for component. The default value is + 0 for luminance components and 1 for chrominance components. + +int dc_tbl_no +int ac_tbl_no + DC and AC entropy coding table numbers. The default values are + 0 for luminance components and 1 for chrominance components. + +int component_index + Must equal the component's index in comp_info[]. (Beginning in + release v6, the compressor library will fill this in automatically; + you don't have to.) + + +Decompression parameter selection +--------------------------------- + +Decompression parameter selection is somewhat simpler than compression +parameter selection, since all of the JPEG internal parameters are +recorded in the source file and need not be supplied by the application. +(Unless you are working with abbreviated files, in which case see +"Abbreviated datastreams", below.) Decompression parameters control +the postprocessing done on the image to deliver it in a format suitable +for the application's use. Many of the parameters control speed/quality +tradeoffs, in which faster decompression may be obtained at the price of +a poorer-quality image. The defaults select the highest quality (slowest) +processing. + +The following fields in the JPEG object are set by jpeg_read_header() and +may be useful to the application in choosing decompression parameters: + +JDIMENSION image_width Width and height of image +JDIMENSION image_height +int num_components Number of color components +J_COLOR_SPACE jpeg_color_space Colorspace of image +boolean saw_JFIF_marker TRUE if a JFIF APP0 marker was seen + UINT8 JFIF_major_version Version information from JFIF marker + UINT8 JFIF_minor_version + UINT8 density_unit Resolution data from JFIF marker + UINT16 X_density + UINT16 Y_density +boolean saw_Adobe_marker TRUE if an Adobe APP14 marker was seen + UINT8 Adobe_transform Color transform code from Adobe marker + +The JPEG color space, unfortunately, is something of a guess since the JPEG +standard proper does not provide a way to record it. In practice most files +adhere to the JFIF or Adobe conventions, and the decoder will recognize these +correctly. See "Special color spaces", below, for more info. + + +The decompression parameters that determine the basic properties of the +returned image are: + +J_COLOR_SPACE out_color_space + Output color space. jpeg_read_header() sets an appropriate default + based on jpeg_color_space; typically it will be RGB or grayscale. + The application can change this field to request output in a different + colorspace. For example, set it to JCS_GRAYSCALE to get grayscale + output from a color file. (This is useful for previewing: grayscale + output is faster than full color since the color components need not + be processed.) Note that not all possible color space transforms are + currently implemented; you may need to extend jdcolor.c if you want an + unusual conversion. + +unsigned int scale_num, scale_denom + Scale the image by the fraction scale_num/scale_denom. Default is + 1/1, or no scaling. Currently, the only supported scaling ratios + are 1/1, 1/2, 1/4, and 1/8. (The library design allows for arbitrary + scaling ratios but this is not likely to be implemented any time soon.) + Smaller scaling ratios permit significantly faster decoding since + fewer pixels need be processed and a simpler IDCT method can be used. + +boolean quantize_colors + If set TRUE, colormapped output will be delivered. Default is FALSE, + meaning that full-color output will be delivered. + +The next three parameters are relevant only if quantize_colors is TRUE. + +int desired_number_of_colors + Maximum number of colors to use in generating a library-supplied color + map (the actual number of colors is returned in a different field). + Default 256. Ignored when the application supplies its own color map. + +boolean two_pass_quantize + If TRUE, an extra pass over the image is made to select a custom color + map for the image. This usually looks a lot better than the one-size- + fits-all colormap that is used otherwise. Default is TRUE. Ignored + when the application supplies its own color map. + +J_DITHER_MODE dither_mode + Selects color dithering method. Supported values are: + JDITHER_NONE no dithering: fast, very low quality + JDITHER_ORDERED ordered dither: moderate speed and quality + JDITHER_FS Floyd-Steinberg dither: slow, high quality + Default is JDITHER_FS. (At present, ordered dither is implemented + only in the single-pass, standard-colormap case. If you ask for + ordered dither when two_pass_quantize is TRUE or when you supply + an external color map, you'll get F-S dithering.) + +When quantize_colors is TRUE, the target color map is described by the next +two fields. colormap is set to NULL by jpeg_read_header(). The application +can supply a color map by setting colormap non-NULL and setting +actual_number_of_colors to the map size. Otherwise, jpeg_start_decompress() +selects a suitable color map and sets these two fields itself. +[Implementation restriction: at present, an externally supplied colormap is +only accepted for 3-component output color spaces.] + +JSAMPARRAY colormap + The color map, represented as a 2-D pixel array of out_color_components + rows and actual_number_of_colors columns. Ignored if not quantizing. + CAUTION: if the JPEG library creates its own colormap, the storage + pointed to by this field is released by jpeg_finish_decompress(). + Copy the colormap somewhere else first, if you want to save it. + +int actual_number_of_colors + The number of colors in the color map. + +Additional decompression parameters that the application may set include: + +J_DCT_METHOD dct_method + Selects the algorithm used for the DCT step. Choices are the same + as described above for compression. + +boolean do_fancy_upsampling + If TRUE, do careful upsampling of chroma components. If FALSE, + a faster but sloppier method is used. Default is TRUE. The visual + impact of the sloppier method is often very small. + +boolean do_block_smoothing + If TRUE, interblock smoothing is applied in early stages of decoding + progressive JPEG files; if FALSE, not. Default is TRUE. Early + progression stages look "fuzzy" with smoothing, "blocky" without. + In any case, block smoothing ceases to be applied after the first few + AC coefficients are known to full accuracy, so it is relevant only + when using buffered-image mode for progressive images. + +boolean enable_1pass_quant +boolean enable_external_quant +boolean enable_2pass_quant + These are significant only in buffered-image mode, which is + described in its own section below. + + +The output image dimensions are given by the following fields. These are +computed from the source image dimensions and the decompression parameters +by jpeg_start_decompress(). You can also call jpeg_calc_output_dimensions() +to obtain the values that will result from the current parameter settings. +This can be useful if you are trying to pick a scaling ratio that will get +close to a desired target size. It's also important if you are using the +JPEG library's memory manager to allocate output buffer space, because you +are supposed to request such buffers *before* jpeg_start_decompress(). + +JDIMENSION output_width Actual dimensions of output image. +JDIMENSION output_height +int out_color_components Number of color components in out_color_space. +int output_components Number of color components returned. +int rec_outbuf_height Recommended height of scanline buffer. + +When quantizing colors, output_components is 1, indicating a single color map +index per pixel. Otherwise it equals out_color_components. The output arrays +are required to be output_width * output_components JSAMPLEs wide. + +rec_outbuf_height is the recommended minimum height (in scanlines) of the +buffer passed to jpeg_read_scanlines(). If the buffer is smaller, the +library will still work, but time will be wasted due to unnecessary data +copying. In high-quality modes, rec_outbuf_height is always 1, but some +faster, lower-quality modes set it to larger values (typically 2 to 4). +If you are going to ask for a high-speed processing mode, you may as well +go to the trouble of honoring rec_outbuf_height so as to avoid data copying. +(An output buffer larger than rec_outbuf_height lines is OK, but won't +provide any material speed improvement over that height.) + + +Special color spaces +-------------------- + +The JPEG standard itself is "color blind" and doesn't specify any particular +color space. It is customary to convert color data to a luminance/chrominance +color space before compressing, since this permits greater compression. The +existing de-facto JPEG file format standards specify YCbCr or grayscale data +(JFIF), or grayscale, RGB, YCbCr, CMYK, or YCCK (Adobe). For special +applications such as multispectral images, other color spaces can be used, +but it must be understood that such files will be unportable. + +The JPEG library can handle the most common colorspace conversions (namely +RGB <=> YCbCr and CMYK <=> YCCK). It can also deal with data of an unknown +color space, passing it through without conversion. If you deal extensively +with an unusual color space, you can easily extend the library to understand +additional color spaces and perform appropriate conversions. + +For compression, the source data's color space is specified by field +in_color_space. This is transformed to the JPEG file's color space given +by jpeg_color_space. jpeg_set_defaults() chooses a reasonable JPEG color +space depending on in_color_space, but you can override this by calling +jpeg_set_colorspace(). Of course you must select a supported transformation. +jccolor.c currently supports the following transformations: + RGB => YCbCr + RGB => GRAYSCALE + YCbCr => GRAYSCALE + CMYK => YCCK +plus the null transforms: GRAYSCALE => GRAYSCALE, RGB => RGB, +YCbCr => YCbCr, CMYK => CMYK, YCCK => YCCK, and UNKNOWN => UNKNOWN. + +The de-facto file format standards (JFIF and Adobe) specify APPn markers that +indicate the color space of the JPEG file. It is important to ensure that +these are written correctly, or omitted if the JPEG file's color space is not +one of the ones supported by the de-facto standards. jpeg_set_colorspace() +will set the compression parameters to include or omit the APPn markers +properly, so long as it is told the truth about the JPEG color space. +For example, if you are writing some random 3-component color space without +conversion, don't try to fake out the library by setting in_color_space and +jpeg_color_space to JCS_YCbCr; use JCS_UNKNOWN. You may want to write an +APPn marker of your own devising to identify the colorspace --- see "Special +markers", below. + +When told that the color space is UNKNOWN, the library will default to using +luminance-quality compression parameters for all color components. You may +well want to change these parameters. See the source code for +jpeg_set_colorspace(), in jcparam.c, for details. + +For decompression, the JPEG file's color space is given in jpeg_color_space, +and this is transformed to the output color space out_color_space. +jpeg_read_header's setting of jpeg_color_space can be relied on if the file +conforms to JFIF or Adobe conventions, but otherwise it is no better than a +guess. If you know the JPEG file's color space for certain, you can override +jpeg_read_header's guess by setting jpeg_color_space. jpeg_read_header also +selects a default output color space based on (its guess of) jpeg_color_space; +set out_color_space to override this. Again, you must select a supported +transformation. jdcolor.c currently supports + YCbCr => GRAYSCALE + YCbCr => RGB + GRAYSCALE => RGB + YCCK => CMYK +as well as the null transforms. (Since GRAYSCALE=>RGB is provided, an +application can force grayscale JPEGs to look like color JPEGs if it only +wants to handle one case.) + +The two-pass color quantizer, jquant2.c, is specialized to handle RGB data +(it weights distances appropriately for RGB colors). You'll need to modify +the code if you want to use it for non-RGB output color spaces. Note that +jquant2.c is used to map to an application-supplied colormap as well as for +the normal two-pass colormap selection process. + +CAUTION: it appears that Adobe Photoshop writes inverted data in CMYK JPEG +files: 0 represents 100% ink coverage, rather than 0% ink as you'd expect. +This is arguably a bug in Photoshop, but if you need to work with Photoshop +CMYK files, you will have to deal with it in your application. We cannot +"fix" this in the library by inverting the data during the CMYK<=>YCCK +transform, because that would break other applications, notably Ghostscript. +Photoshop versions prior to 3.0 write EPS files containing JPEG-encoded CMYK +data in the same inverted-YCCK representation used in bare JPEG files, but +the surrounding PostScript code performs an inversion using the PS image +operator. I am told that Photoshop 3.0 will write uninverted YCCK in +EPS/JPEG files, and will omit the PS-level inversion. (But the data +polarity used in bare JPEG files will not change in 3.0.) In either case, +the JPEG library must not invert the data itself, or else Ghostscript would +read these EPS files incorrectly. + + +Error handling +-------------- + +When the default error handler is used, any error detected inside the JPEG +routines will cause a message to be printed on stderr, followed by exit(). +You can supply your own error handling routines to override this behavior +and to control the treatment of nonfatal warnings and trace/debug messages. +The file example.c illustrates the most common case, which is to have the +application regain control after an error rather than exiting. + +The JPEG library never writes any message directly; it always goes through +the error handling routines. Three classes of messages are recognized: + * Fatal errors: the library cannot continue. + * Warnings: the library can continue, but the data is corrupt, and a + damaged output image is likely to result. + * Trace/informational messages. These come with a trace level indicating + the importance of the message; you can control the verbosity of the + program by adjusting the maximum trace level that will be displayed. + +You may, if you wish, simply replace the entire JPEG error handling module +(jerror.c) with your own code. However, you can avoid code duplication by +only replacing some of the routines depending on the behavior you need. +This is accomplished by calling jpeg_std_error() as usual, but then overriding +some of the method pointers in the jpeg_error_mgr struct, as illustrated by +example.c. + +All of the error handling routines will receive a pointer to the JPEG object +(a j_common_ptr which points to either a jpeg_compress_struct or a +jpeg_decompress_struct; if you need to tell which, test the is_decompressor +field). This struct includes a pointer to the error manager struct in its +"err" field. Frequently, custom error handler routines will need to access +additional data which is not known to the JPEG library or the standard error +handler. The most convenient way to do this is to embed either the JPEG +object or the jpeg_error_mgr struct in a larger structure that contains +additional fields; then casting the passed pointer provides access to the +additional fields. Again, see example.c for one way to do it. (Beginning +with IJG version 6b, there is also a void pointer "client_data" in each +JPEG object, which the application can also use to find related data. +The library does not touch client_data at all.) + +The individual methods that you might wish to override are: + +error_exit (j_common_ptr cinfo) + Receives control for a fatal error. Information sufficient to + generate the error message has been stored in cinfo->err; call + output_message to display it. Control must NOT return to the caller; + generally this routine will exit() or longjmp() somewhere. + Typically you would override this routine to get rid of the exit() + default behavior. Note that if you continue processing, you should + clean up the JPEG object with jpeg_abort() or jpeg_destroy(). + +output_message (j_common_ptr cinfo) + Actual output of any JPEG message. Override this to send messages + somewhere other than stderr. Note that this method does not know + how to generate a message, only where to send it. + +format_message (j_common_ptr cinfo, char * buffer) + Constructs a readable error message string based on the error info + stored in cinfo->err. This method is called by output_message. Few + applications should need to override this method. One possible + reason for doing so is to implement dynamic switching of error message + language. + +emit_message (j_common_ptr cinfo, int msg_level) + Decide whether or not to emit a warning or trace message; if so, + calls output_message. The main reason for overriding this method + would be to abort on warnings. msg_level is -1 for warnings, + 0 and up for trace messages. + +Only error_exit() and emit_message() are called from the rest of the JPEG +library; the other two are internal to the error handler. + +The actual message texts are stored in an array of strings which is pointed to +by the field err->jpeg_message_table. The messages are numbered from 0 to +err->last_jpeg_message, and it is these code numbers that are used in the +JPEG library code. You could replace the message texts (for instance, with +messages in French or German) by changing the message table pointer. See +jerror.h for the default texts. CAUTION: this table will almost certainly +change or grow from one library version to the next. + +It may be useful for an application to add its own message texts that are +handled by the same mechanism. The error handler supports a second "add-on" +message table for this purpose. To define an addon table, set the pointer +err->addon_message_table and the message numbers err->first_addon_message and +err->last_addon_message. If you number the addon messages beginning at 1000 +or so, you won't have to worry about conflicts with the library's built-in +messages. See the sample applications cjpeg/djpeg for an example of using +addon messages (the addon messages are defined in cderror.h). + +Actual invocation of the error handler is done via macros defined in jerror.h: + ERREXITn(...) for fatal errors + WARNMSn(...) for corrupt-data warnings + TRACEMSn(...) for trace and informational messages. +These macros store the message code and any additional parameters into the +error handler struct, then invoke the error_exit() or emit_message() method. +The variants of each macro are for varying numbers of additional parameters. +The additional parameters are inserted into the generated message using +standard printf() format codes. + +See jerror.h and jerror.c for further details. + + +Compressed data handling (source and destination managers) +---------------------------------------------------------- + +The JPEG compression library sends its compressed data to a "destination +manager" module. The default destination manager just writes the data to a +stdio stream, but you can provide your own manager to do something else. +Similarly, the decompression library calls a "source manager" to obtain the +compressed data; you can provide your own source manager if you want the data +to come from somewhere other than a stdio stream. + +In both cases, compressed data is processed a bufferload at a time: the +destination or source manager provides a work buffer, and the library invokes +the manager only when the buffer is filled or emptied. (You could define a +one-character buffer to force the manager to be invoked for each byte, but +that would be rather inefficient.) The buffer's size and location are +controlled by the manager, not by the library. For example, if you desired to +decompress a JPEG datastream that was all in memory, you could just make the +buffer pointer and length point to the original data in memory. Then the +buffer-reload procedure would be invoked only if the decompressor ran off the +end of the datastream, which would indicate an erroneous datastream. + +The work buffer is defined as an array of datatype JOCTET, which is generally +"char" or "unsigned char". On a machine where char is not exactly 8 bits +wide, you must define JOCTET as a wider data type and then modify the data +source and destination modules to transcribe the work arrays into 8-bit units +on external storage. + +A data destination manager struct contains a pointer and count defining the +next byte to write in the work buffer and the remaining free space: + + JOCTET * next_output_byte; /* => next byte to write in buffer */ + size_t free_in_buffer; /* # of byte spaces remaining in buffer */ + +The library increments the pointer and decrements the count until the buffer +is filled. The manager's empty_output_buffer method must reset the pointer +and count. The manager is expected to remember the buffer's starting address +and total size in private fields not visible to the library. + +A data destination manager provides three methods: + +init_destination (j_compress_ptr cinfo) + Initialize destination. This is called by jpeg_start_compress() + before any data is actually written. It must initialize + next_output_byte and free_in_buffer. free_in_buffer must be + initialized to a positive value. + +empty_output_buffer (j_compress_ptr cinfo) + This is called whenever the buffer has filled (free_in_buffer + reaches zero). In typical applications, it should write out the + *entire* buffer (use the saved start address and buffer length; + ignore the current state of next_output_byte and free_in_buffer). + Then reset the pointer & count to the start of the buffer, and + return TRUE indicating that the buffer has been dumped. + free_in_buffer must be set to a positive value when TRUE is + returned. A FALSE return should only be used when I/O suspension is + desired (this operating mode is discussed in the next section). + +term_destination (j_compress_ptr cinfo) + Terminate destination --- called by jpeg_finish_compress() after all + data has been written. In most applications, this must flush any + data remaining in the buffer. Use either next_output_byte or + free_in_buffer to determine how much data is in the buffer. + +term_destination() is NOT called by jpeg_abort() or jpeg_destroy(). If you +want the destination manager to be cleaned up during an abort, you must do it +yourself. + +You will also need code to create a jpeg_destination_mgr struct, fill in its +method pointers, and insert a pointer to the struct into the "dest" field of +the JPEG compression object. This can be done in-line in your setup code if +you like, but it's probably cleaner to provide a separate routine similar to +the jpeg_stdio_dest() routine of the supplied destination manager. + +Decompression source managers follow a parallel design, but with some +additional frammishes. The source manager struct contains a pointer and count +defining the next byte to read from the work buffer and the number of bytes +remaining: + + const JOCTET * next_input_byte; /* => next byte to read from buffer */ + size_t bytes_in_buffer; /* # of bytes remaining in buffer */ + +The library increments the pointer and decrements the count until the buffer +is emptied. The manager's fill_input_buffer method must reset the pointer and +count. In most applications, the manager must remember the buffer's starting +address and total size in private fields not visible to the library. + +A data source manager provides five methods: + +init_source (j_decompress_ptr cinfo) + Initialize source. This is called by jpeg_read_header() before any + data is actually read. Unlike init_destination(), it may leave + bytes_in_buffer set to 0 (in which case a fill_input_buffer() call + will occur immediately). + +fill_input_buffer (j_decompress_ptr cinfo) + This is called whenever bytes_in_buffer has reached zero and more + data is wanted. In typical applications, it should read fresh data + into the buffer (ignoring the current state of next_input_byte and + bytes_in_buffer), reset the pointer & count to the start of the + buffer, and return TRUE indicating that the buffer has been reloaded. + It is not necessary to fill the buffer entirely, only to obtain at + least one more byte. bytes_in_buffer MUST be set to a positive value + if TRUE is returned. A FALSE return should only be used when I/O + suspension is desired (this mode is discussed in the next section). + +skip_input_data (j_decompress_ptr cinfo, long num_bytes) + Skip num_bytes worth of data. The buffer pointer and count should + be advanced over num_bytes input bytes, refilling the buffer as + needed. This is used to skip over a potentially large amount of + uninteresting data (such as an APPn marker). In some applications + it may be possible to optimize away the reading of the skipped data, + but it's not clear that being smart is worth much trouble; large + skips are uncommon. bytes_in_buffer may be zero on return. + A zero or negative skip count should be treated as a no-op. + +resync_to_restart (j_decompress_ptr cinfo, int desired) + This routine is called only when the decompressor has failed to find + a restart (RSTn) marker where one is expected. Its mission is to + find a suitable point for resuming decompression. For most + applications, we recommend that you just use the default resync + procedure, jpeg_resync_to_restart(). However, if you are able to back + up in the input data stream, or if you have a-priori knowledge about + the likely location of restart markers, you may be able to do better. + Read the read_restart_marker() and jpeg_resync_to_restart() routines + in jdmarker.c if you think you'd like to implement your own resync + procedure. + +term_source (j_decompress_ptr cinfo) + Terminate source --- called by jpeg_finish_decompress() after all + data has been read. Often a no-op. + +For both fill_input_buffer() and skip_input_data(), there is no such thing +as an EOF return. If the end of the file has been reached, the routine has +a choice of exiting via ERREXIT() or inserting fake data into the buffer. +In most cases, generating a warning message and inserting a fake EOI marker +is the best course of action --- this will allow the decompressor to output +however much of the image is there. In pathological cases, the decompressor +may swallow the EOI and again demand data ... just keep feeding it fake EOIs. +jdatasrc.c illustrates the recommended error recovery behavior. + +term_source() is NOT called by jpeg_abort() or jpeg_destroy(). If you want +the source manager to be cleaned up during an abort, you must do it yourself. + +You will also need code to create a jpeg_source_mgr struct, fill in its method +pointers, and insert a pointer to the struct into the "src" field of the JPEG +decompression object. This can be done in-line in your setup code if you +like, but it's probably cleaner to provide a separate routine similar to the +jpeg_stdio_src() routine of the supplied source manager. + +For more information, consult the stdio source and destination managers +in jdatasrc.c and jdatadst.c. + + +I/O suspension +-------------- + +Some applications need to use the JPEG library as an incremental memory-to- +memory filter: when the compressed data buffer is filled or emptied, they want +control to return to the outer loop, rather than expecting that the buffer can +be emptied or reloaded within the data source/destination manager subroutine. +The library supports this need by providing an "I/O suspension" mode, which we +describe in this section. + +The I/O suspension mode is not a panacea: nothing is guaranteed about the +maximum amount of time spent in any one call to the library, so it will not +eliminate response-time problems in single-threaded applications. If you +need guaranteed response time, we suggest you "bite the bullet" and implement +a real multi-tasking capability. + +To use I/O suspension, cooperation is needed between the calling application +and the data source or destination manager; you will always need a custom +source/destination manager. (Please read the previous section if you haven't +already.) The basic idea is that the empty_output_buffer() or +fill_input_buffer() routine is a no-op, merely returning FALSE to indicate +that it has done nothing. Upon seeing this, the JPEG library suspends +operation and returns to its caller. The surrounding application is +responsible for emptying or refilling the work buffer before calling the +JPEG library again. + +Compression suspension: + +For compression suspension, use an empty_output_buffer() routine that returns +FALSE; typically it will not do anything else. This will cause the +compressor to return to the caller of jpeg_write_scanlines(), with the return +value indicating that not all the supplied scanlines have been accepted. +The application must make more room in the output buffer, adjust the output +buffer pointer/count appropriately, and then call jpeg_write_scanlines() +again, pointing to the first unconsumed scanline. + +When forced to suspend, the compressor will backtrack to a convenient stopping +point (usually the start of the current MCU); it will regenerate some output +data when restarted. Therefore, although empty_output_buffer() is only +called when the buffer is filled, you should NOT write out the entire buffer +after a suspension. Write only the data up to the current position of +next_output_byte/free_in_buffer. The data beyond that point will be +regenerated after resumption. + +Because of the backtracking behavior, a good-size output buffer is essential +for efficiency; you don't want the compressor to suspend often. (In fact, an +overly small buffer could lead to infinite looping, if a single MCU required +more data than would fit in the buffer.) We recommend a buffer of at least +several Kbytes. You may want to insert explicit code to ensure that you don't +call jpeg_write_scanlines() unless there is a reasonable amount of space in +the output buffer; in other words, flush the buffer before trying to compress +more data. + +The compressor does not allow suspension while it is trying to write JPEG +markers at the beginning and end of the file. This means that: + * At the beginning of a compression operation, there must be enough free + space in the output buffer to hold the header markers (typically 600 or + so bytes). The recommended buffer size is bigger than this anyway, so + this is not a problem as long as you start with an empty buffer. However, + this restriction might catch you if you insert large special markers, such + as a JFIF thumbnail image, without flushing the buffer afterwards. + * When you call jpeg_finish_compress(), there must be enough space in the + output buffer to emit any buffered data and the final EOI marker. In the + current implementation, half a dozen bytes should suffice for this, but + for safety's sake we recommend ensuring that at least 100 bytes are free + before calling jpeg_finish_compress(). + +A more significant restriction is that jpeg_finish_compress() cannot suspend. +This means you cannot use suspension with multi-pass operating modes, namely +Huffman code optimization and multiple-scan output. Those modes write the +whole file during jpeg_finish_compress(), which will certainly result in +buffer overrun. (Note that this restriction applies only to compression, +not decompression. The decompressor supports input suspension in all of its +operating modes.) + +Decompression suspension: + +For decompression suspension, use a fill_input_buffer() routine that simply +returns FALSE (except perhaps during error recovery, as discussed below). +This will cause the decompressor to return to its caller with an indication +that suspension has occurred. This can happen at four places: + * jpeg_read_header(): will return JPEG_SUSPENDED. + * jpeg_start_decompress(): will return FALSE, rather than its usual TRUE. + * jpeg_read_scanlines(): will return the number of scanlines already + completed (possibly 0). + * jpeg_finish_decompress(): will return FALSE, rather than its usual TRUE. +The surrounding application must recognize these cases, load more data into +the input buffer, and repeat the call. In the case of jpeg_read_scanlines(), +increment the passed pointers past any scanlines successfully read. + +Just as with compression, the decompressor will typically backtrack to a +convenient restart point before suspending. When fill_input_buffer() is +called, next_input_byte/bytes_in_buffer point to the current restart point, +which is where the decompressor will backtrack to if FALSE is returned. +The data beyond that position must NOT be discarded if you suspend; it needs +to be re-read upon resumption. In most implementations, you'll need to shift +this data down to the start of your work buffer and then load more data after +it. Again, this behavior means that a several-Kbyte work buffer is essential +for decent performance; furthermore, you should load a reasonable amount of +new data before resuming decompression. (If you loaded, say, only one new +byte each time around, you could waste a LOT of cycles.) + +The skip_input_data() source manager routine requires special care in a +suspension scenario. This routine is NOT granted the ability to suspend the +decompressor; it can decrement bytes_in_buffer to zero, but no more. If the +requested skip distance exceeds the amount of data currently in the input +buffer, then skip_input_data() must set bytes_in_buffer to zero and record the +additional skip distance somewhere else. The decompressor will immediately +call fill_input_buffer(), which should return FALSE, which will cause a +suspension return. The surrounding application must then arrange to discard +the recorded number of bytes before it resumes loading the input buffer. +(Yes, this design is rather baroque, but it avoids complexity in the far more +common case where a non-suspending source manager is used.) + +If the input data has been exhausted, we recommend that you emit a warning +and insert dummy EOI markers just as a non-suspending data source manager +would do. This can be handled either in the surrounding application logic or +within fill_input_buffer(); the latter is probably more efficient. If +fill_input_buffer() knows that no more data is available, it can set the +pointer/count to point to a dummy EOI marker and then return TRUE just as +though it had read more data in a non-suspending situation. + +The decompressor does not attempt to suspend within standard JPEG markers; +instead it will backtrack to the start of the marker and reprocess the whole +marker next time. Hence the input buffer must be large enough to hold the +longest standard marker in the file. Standard JPEG markers should normally +not exceed a few hundred bytes each (DHT tables are typically the longest). +We recommend at least a 2K buffer for performance reasons, which is much +larger than any correct marker is likely to be. For robustness against +damaged marker length counts, you may wish to insert a test in your +application for the case that the input buffer is completely full and yet +the decoder has suspended without consuming any data --- otherwise, if this +situation did occur, it would lead to an endless loop. (The library can't +provide this test since it has no idea whether "the buffer is full", or +even whether there is a fixed-size input buffer.) + +The input buffer would need to be 64K to allow for arbitrary COM or APPn +markers, but these are handled specially: they are either saved into allocated +memory, or skipped over by calling skip_input_data(). In the former case, +suspension is handled correctly, and in the latter case, the problem of +buffer overrun is placed on skip_input_data's shoulders, as explained above. +Note that if you provide your own marker handling routine for large markers, +you should consider how to deal with buffer overflow. + +Multiple-buffer management: + +In some applications it is desirable to store the compressed data in a linked +list of buffer areas, so as to avoid data copying. This can be handled by +having empty_output_buffer() or fill_input_buffer() set the pointer and count +to reference the next available buffer; FALSE is returned only if no more +buffers are available. Although seemingly straightforward, there is a +pitfall in this approach: the backtrack that occurs when FALSE is returned +could back up into an earlier buffer. For example, when fill_input_buffer() +is called, the current pointer & count indicate the backtrack restart point. +Since fill_input_buffer() will set the pointer and count to refer to a new +buffer, the restart position must be saved somewhere else. Suppose a second +call to fill_input_buffer() occurs in the same library call, and no +additional input data is available, so fill_input_buffer must return FALSE. +If the JPEG library has not moved the pointer/count forward in the current +buffer, then *the correct restart point is the saved position in the prior +buffer*. Prior buffers may be discarded only after the library establishes +a restart point within a later buffer. Similar remarks apply for output into +a chain of buffers. + +The library will never attempt to backtrack over a skip_input_data() call, +so any skipped data can be permanently discarded. You still have to deal +with the case of skipping not-yet-received data, however. + +It's much simpler to use only a single buffer; when fill_input_buffer() is +called, move any unconsumed data (beyond the current pointer/count) down to +the beginning of this buffer and then load new data into the remaining buffer +space. This approach requires a little more data copying but is far easier +to get right. + + +Progressive JPEG support +------------------------ + +Progressive JPEG rearranges the stored data into a series of scans of +increasing quality. In situations where a JPEG file is transmitted across a +slow communications link, a decoder can generate a low-quality image very +quickly from the first scan, then gradually improve the displayed quality as +more scans are received. The final image after all scans are complete is +identical to that of a regular (sequential) JPEG file of the same quality +setting. Progressive JPEG files are often slightly smaller than equivalent +sequential JPEG files, but the possibility of incremental display is the main +reason for using progressive JPEG. + +The IJG encoder library generates progressive JPEG files when given a +suitable "scan script" defining how to divide the data into scans. +Creation of progressive JPEG files is otherwise transparent to the encoder. +Progressive JPEG files can also be read transparently by the decoder library. +If the decoding application simply uses the library as defined above, it +will receive a final decoded image without any indication that the file was +progressive. Of course, this approach does not allow incremental display. +To perform incremental display, an application needs to use the decoder +library's "buffered-image" mode, in which it receives a decoded image +multiple times. + +Each displayed scan requires about as much work to decode as a full JPEG +image of the same size, so the decoder must be fairly fast in relation to the +data transmission rate in order to make incremental display useful. However, +it is possible to skip displaying the image and simply add the incoming bits +to the decoder's coefficient buffer. This is fast because only Huffman +decoding need be done, not IDCT, upsampling, colorspace conversion, etc. +The IJG decoder library allows the application to switch dynamically between +displaying the image and simply absorbing the incoming bits. A properly +coded application can automatically adapt the number of display passes to +suit the time available as the image is received. Also, a final +higher-quality display cycle can be performed from the buffered data after +the end of the file is reached. + +Progressive compression: + +To create a progressive JPEG file (or a multiple-scan sequential JPEG file), +set the scan_info cinfo field to point to an array of scan descriptors, and +perform compression as usual. Instead of constructing your own scan list, +you can call the jpeg_simple_progression() helper routine to create a +recommended progression sequence; this method should be used by all +applications that don't want to get involved in the nitty-gritty of +progressive scan sequence design. (If you want to provide user control of +scan sequences, you may wish to borrow the scan script reading code found +in rdswitch.c, so that you can read scan script files just like cjpeg's.) +When scan_info is not NULL, the compression library will store DCT'd data +into a buffer array as jpeg_write_scanlines() is called, and will emit all +the requested scans during jpeg_finish_compress(). This implies that +multiple-scan output cannot be created with a suspending data destination +manager, since jpeg_finish_compress() does not support suspension. We +should also note that the compressor currently forces Huffman optimization +mode when creating a progressive JPEG file, because the default Huffman +tables are unsuitable for progressive files. + +Progressive decompression: + +When buffered-image mode is not used, the decoder library will read all of +a multi-scan file during jpeg_start_decompress(), so that it can provide a +final decoded image. (Here "multi-scan" means either progressive or +multi-scan sequential.) This makes multi-scan files transparent to the +decoding application. However, existing applications that used suspending +input with version 5 of the IJG library will need to be modified to check +for a suspension return from jpeg_start_decompress(). + +To perform incremental display, an application must use the library's +buffered-image mode. This is described in the next section. + + +Buffered-image mode +------------------- + +In buffered-image mode, the library stores the partially decoded image in a +coefficient buffer, from which it can be read out as many times as desired. +This mode is typically used for incremental display of progressive JPEG files, +but it can be used with any JPEG file. Each scan of a progressive JPEG file +adds more data (more detail) to the buffered image. The application can +display in lockstep with the source file (one display pass per input scan), +or it can allow input processing to outrun display processing. By making +input and display processing run independently, it is possible for the +application to adapt progressive display to a wide range of data transmission +rates. + +The basic control flow for buffered-image decoding is + + jpeg_create_decompress() + set data source + jpeg_read_header() + set overall decompression parameters + cinfo.buffered_image = TRUE; /* select buffered-image mode */ + jpeg_start_decompress() + for (each output pass) { + adjust output decompression parameters if required + jpeg_start_output() /* start a new output pass */ + for (all scanlines in image) { + jpeg_read_scanlines() + display scanlines + } + jpeg_finish_output() /* terminate output pass */ + } + jpeg_finish_decompress() + jpeg_destroy_decompress() + +This differs from ordinary unbuffered decoding in that there is an additional +level of looping. The application can choose how many output passes to make +and how to display each pass. + +The simplest approach to displaying progressive images is to do one display +pass for each scan appearing in the input file. In this case the outer loop +condition is typically + while (! jpeg_input_complete(&cinfo)) +and the start-output call should read + jpeg_start_output(&cinfo, cinfo.input_scan_number); +The second parameter to jpeg_start_output() indicates which scan of the input +file is to be displayed; the scans are numbered starting at 1 for this +purpose. (You can use a loop counter starting at 1 if you like, but using +the library's input scan counter is easier.) The library automatically reads +data as necessary to complete each requested scan, and jpeg_finish_output() +advances to the next scan or end-of-image marker (hence input_scan_number +will be incremented by the time control arrives back at jpeg_start_output()). +With this technique, data is read from the input file only as needed, and +input and output processing run in lockstep. + +After reading the final scan and reaching the end of the input file, the +buffered image remains available; it can be read additional times by +repeating the jpeg_start_output()/jpeg_read_scanlines()/jpeg_finish_output() +sequence. For example, a useful technique is to use fast one-pass color +quantization for display passes made while the image is arriving, followed by +a final display pass using two-pass quantization for highest quality. This +is done by changing the library parameters before the final output pass. +Changing parameters between passes is discussed in detail below. + +In general the last scan of a progressive file cannot be recognized as such +until after it is read, so a post-input display pass is the best approach if +you want special processing in the final pass. + +When done with the image, be sure to call jpeg_finish_decompress() to release +the buffered image (or just use jpeg_destroy_decompress()). + +If input data arrives faster than it can be displayed, the application can +cause the library to decode input data in advance of what's needed to produce +output. This is done by calling the routine jpeg_consume_input(). +The return value is one of the following: + JPEG_REACHED_SOS: reached an SOS marker (the start of a new scan) + JPEG_REACHED_EOI: reached the EOI marker (end of image) + JPEG_ROW_COMPLETED: completed reading one MCU row of compressed data + JPEG_SCAN_COMPLETED: completed reading last MCU row of current scan + JPEG_SUSPENDED: suspended before completing any of the above +(JPEG_SUSPENDED can occur only if a suspending data source is used.) This +routine can be called at any time after initializing the JPEG object. It +reads some additional data and returns when one of the indicated significant +events occurs. (If called after the EOI marker is reached, it will +immediately return JPEG_REACHED_EOI without attempting to read more data.) + +The library's output processing will automatically call jpeg_consume_input() +whenever the output processing overtakes the input; thus, simple lockstep +display requires no direct calls to jpeg_consume_input(). But by adding +calls to jpeg_consume_input(), you can absorb data in advance of what is +being displayed. This has two benefits: + * You can limit buildup of unprocessed data in your input buffer. + * You can eliminate extra display passes by paying attention to the + state of the library's input processing. + +The first of these benefits only requires interspersing calls to +jpeg_consume_input() with your display operations and any other processing +you may be doing. To avoid wasting cycles due to backtracking, it's best to +call jpeg_consume_input() only after a hundred or so new bytes have arrived. +This is discussed further under "I/O suspension", above. (Note: the JPEG +library currently is not thread-safe. You must not call jpeg_consume_input() +from one thread of control if a different library routine is working on the +same JPEG object in another thread.) + +When input arrives fast enough that more than one new scan is available +before you start a new output pass, you may as well skip the output pass +corresponding to the completed scan. This occurs for free if you pass +cinfo.input_scan_number as the target scan number to jpeg_start_output(). +The input_scan_number field is simply the index of the scan currently being +consumed by the input processor. You can ensure that this is up-to-date by +emptying the input buffer just before calling jpeg_start_output(): call +jpeg_consume_input() repeatedly until it returns JPEG_SUSPENDED or +JPEG_REACHED_EOI. + +The target scan number passed to jpeg_start_output() is saved in the +cinfo.output_scan_number field. The library's output processing calls +jpeg_consume_input() whenever the current input scan number and row within +that scan is less than or equal to the current output scan number and row. +Thus, input processing can "get ahead" of the output processing but is not +allowed to "fall behind". You can achieve several different effects by +manipulating this interlock rule. For example, if you pass a target scan +number greater than the current input scan number, the output processor will +wait until that scan starts to arrive before producing any output. (To avoid +an infinite loop, the target scan number is automatically reset to the last +scan number when the end of image is reached. Thus, if you specify a large +target scan number, the library will just absorb the entire input file and +then perform an output pass. This is effectively the same as what +jpeg_start_decompress() does when you don't select buffered-image mode.) +When you pass a target scan number equal to the current input scan number, +the image is displayed no faster than the current input scan arrives. The +final possibility is to pass a target scan number less than the current input +scan number; this disables the input/output interlock and causes the output +processor to simply display whatever it finds in the image buffer, without +waiting for input. (However, the library will not accept a target scan +number less than one, so you can't avoid waiting for the first scan.) + +When data is arriving faster than the output display processing can advance +through the image, jpeg_consume_input() will store data into the buffered +image beyond the point at which the output processing is reading data out +again. If the input arrives fast enough, it may "wrap around" the buffer to +the point where the input is more than one whole scan ahead of the output. +If the output processing simply proceeds through its display pass without +paying attention to the input, the effect seen on-screen is that the lower +part of the image is one or more scans better in quality than the upper part. +Then, when the next output scan is started, you have a choice of what target +scan number to use. The recommended choice is to use the current input scan +number at that time, which implies that you've skipped the output scans +corresponding to the input scans that were completed while you processed the +previous output scan. In this way, the decoder automatically adapts its +speed to the arriving data, by skipping output scans as necessary to keep up +with the arriving data. + +When using this strategy, you'll want to be sure that you perform a final +output pass after receiving all the data; otherwise your last display may not +be full quality across the whole screen. So the right outer loop logic is +something like this: + do { + absorb any waiting input by calling jpeg_consume_input() + final_pass = jpeg_input_complete(&cinfo); + adjust output decompression parameters if required + jpeg_start_output(&cinfo, cinfo.input_scan_number); + ... + jpeg_finish_output() + } while (! final_pass); +rather than quitting as soon as jpeg_input_complete() returns TRUE. This +arrangement makes it simple to use higher-quality decoding parameters +for the final pass. But if you don't want to use special parameters for +the final pass, the right loop logic is like this: + for (;;) { + absorb any waiting input by calling jpeg_consume_input() + jpeg_start_output(&cinfo, cinfo.input_scan_number); + ... + jpeg_finish_output() + if (jpeg_input_complete(&cinfo) && + cinfo.input_scan_number == cinfo.output_scan_number) + break; + } +In this case you don't need to know in advance whether an output pass is to +be the last one, so it's not necessary to have reached EOF before starting +the final output pass; rather, what you want to test is whether the output +pass was performed in sync with the final input scan. This form of the loop +will avoid an extra output pass whenever the decoder is able (or nearly able) +to keep up with the incoming data. + +When the data transmission speed is high, you might begin a display pass, +then find that much or all of the file has arrived before you can complete +the pass. (You can detect this by noting the JPEG_REACHED_EOI return code +from jpeg_consume_input(), or equivalently by testing jpeg_input_complete().) +In this situation you may wish to abort the current display pass and start a +new one using the newly arrived information. To do so, just call +jpeg_finish_output() and then start a new pass with jpeg_start_output(). + +A variant strategy is to abort and restart display if more than one complete +scan arrives during an output pass; this can be detected by noting +JPEG_REACHED_SOS returns and/or examining cinfo.input_scan_number. This +idea should be employed with caution, however, since the display process +might never get to the bottom of the image before being aborted, resulting +in the lower part of the screen being several passes worse than the upper. +In most cases it's probably best to abort an output pass only if the whole +file has arrived and you want to begin the final output pass immediately. + +When receiving data across a communication link, we recommend always using +the current input scan number for the output target scan number; if a +higher-quality final pass is to be done, it should be started (aborting any +incomplete output pass) as soon as the end of file is received. However, +many other strategies are possible. For example, the application can examine +the parameters of the current input scan and decide whether to display it or +not. If the scan contains only chroma data, one might choose not to use it +as the target scan, expecting that the scan will be small and will arrive +quickly. To skip to the next scan, call jpeg_consume_input() until it +returns JPEG_REACHED_SOS or JPEG_REACHED_EOI. Or just use the next higher +number as the target scan for jpeg_start_output(); but that method doesn't +let you inspect the next scan's parameters before deciding to display it. + + +In buffered-image mode, jpeg_start_decompress() never performs input and +thus never suspends. An application that uses input suspension with +buffered-image mode must be prepared for suspension returns from these +routines: +* jpeg_start_output() performs input only if you request 2-pass quantization + and the target scan isn't fully read yet. (This is discussed below.) +* jpeg_read_scanlines(), as always, returns the number of scanlines that it + was able to produce before suspending. +* jpeg_finish_output() will read any markers following the target scan, + up to the end of the file or the SOS marker that begins another scan. + (But it reads no input if jpeg_consume_input() has already reached the + end of the file or a SOS marker beyond the target output scan.) +* jpeg_finish_decompress() will read until the end of file, and thus can + suspend if the end hasn't already been reached (as can be tested by + calling jpeg_input_complete()). +jpeg_start_output(), jpeg_finish_output(), and jpeg_finish_decompress() +all return TRUE if they completed their tasks, FALSE if they had to suspend. +In the event of a FALSE return, the application must load more input data +and repeat the call. Applications that use non-suspending data sources need +not check the return values of these three routines. + + +It is possible to change decoding parameters between output passes in the +buffered-image mode. The decoder library currently supports only very +limited changes of parameters. ONLY THE FOLLOWING parameter changes are +allowed after jpeg_start_decompress() is called: +* dct_method can be changed before each call to jpeg_start_output(). + For example, one could use a fast DCT method for early scans, changing + to a higher quality method for the final scan. +* dither_mode can be changed before each call to jpeg_start_output(); + of course this has no impact if not using color quantization. Typically + one would use ordered dither for initial passes, then switch to + Floyd-Steinberg dither for the final pass. Caution: changing dither mode + can cause more memory to be allocated by the library. Although the amount + of memory involved is not large (a scanline or so), it may cause the + initial max_memory_to_use specification to be exceeded, which in the worst + case would result in an out-of-memory failure. +* do_block_smoothing can be changed before each call to jpeg_start_output(). + This setting is relevant only when decoding a progressive JPEG image. + During the first DC-only scan, block smoothing provides a very "fuzzy" look + instead of the very "blocky" look seen without it; which is better seems a + matter of personal taste. But block smoothing is nearly always a win + during later stages, especially when decoding a successive-approximation + image: smoothing helps to hide the slight blockiness that otherwise shows + up on smooth gradients until the lowest coefficient bits are sent. +* Color quantization mode can be changed under the rules described below. + You *cannot* change between full-color and quantized output (because that + would alter the required I/O buffer sizes), but you can change which + quantization method is used. + +When generating color-quantized output, changing quantization method is a +very useful way of switching between high-speed and high-quality display. +The library allows you to change among its three quantization methods: +1. Single-pass quantization to a fixed color cube. + Selected by cinfo.two_pass_quantize = FALSE and cinfo.colormap = NULL. +2. Single-pass quantization to an application-supplied colormap. + Selected by setting cinfo.colormap to point to the colormap (the value of + two_pass_quantize is ignored); also set cinfo.actual_number_of_colors. +3. Two-pass quantization to a colormap chosen specifically for the image. + Selected by cinfo.two_pass_quantize = TRUE and cinfo.colormap = NULL. + (This is the default setting selected by jpeg_read_header, but it is + probably NOT what you want for the first pass of progressive display!) +These methods offer successively better quality and lesser speed. However, +only the first method is available for quantizing in non-RGB color spaces. + +IMPORTANT: because the different quantizer methods have very different +working-storage requirements, the library requires you to indicate which +one(s) you intend to use before you call jpeg_start_decompress(). (If we did +not require this, the max_memory_to_use setting would be a complete fiction.) +You do this by setting one or more of these three cinfo fields to TRUE: + enable_1pass_quant Fixed color cube colormap + enable_external_quant Externally-supplied colormap + enable_2pass_quant Two-pass custom colormap +All three are initialized FALSE by jpeg_read_header(). But +jpeg_start_decompress() automatically sets TRUE the one selected by the +current two_pass_quantize and colormap settings, so you only need to set the +enable flags for any other quantization methods you plan to change to later. + +After setting the enable flags correctly at jpeg_start_decompress() time, you +can change to any enabled quantization method by setting two_pass_quantize +and colormap properly just before calling jpeg_start_output(). The following +special rules apply: +1. You must explicitly set cinfo.colormap to NULL when switching to 1-pass + or 2-pass mode from a different mode, or when you want the 2-pass + quantizer to be re-run to generate a new colormap. +2. To switch to an external colormap, or to change to a different external + colormap than was used on the prior pass, you must call + jpeg_new_colormap() after setting cinfo.colormap. +NOTE: if you want to use the same colormap as was used in the prior pass, +you should not do either of these things. This will save some nontrivial +switchover costs. +(These requirements exist because cinfo.colormap will always be non-NULL +after completing a prior output pass, since both the 1-pass and 2-pass +quantizers set it to point to their output colormaps. Thus you have to +do one of these two things to notify the library that something has changed. +Yup, it's a bit klugy, but it's necessary to do it this way for backwards +compatibility.) + +Note that in buffered-image mode, the library generates any requested colormap +during jpeg_start_output(), not during jpeg_start_decompress(). + +When using two-pass quantization, jpeg_start_output() makes a pass over the +buffered image to determine the optimum color map; it therefore may take a +significant amount of time, whereas ordinarily it does little work. The +progress monitor hook is called during this pass, if defined. It is also +important to realize that if the specified target scan number is greater than +or equal to the current input scan number, jpeg_start_output() will attempt +to consume input as it makes this pass. If you use a suspending data source, +you need to check for a FALSE return from jpeg_start_output() under these +conditions. The combination of 2-pass quantization and a not-yet-fully-read +target scan is the only case in which jpeg_start_output() will consume input. + + +Application authors who support buffered-image mode may be tempted to use it +for all JPEG images, even single-scan ones. This will work, but it is +inefficient: there is no need to create an image-sized coefficient buffer for +single-scan images. Requesting buffered-image mode for such an image wastes +memory. Worse, it can cost time on large images, since the buffered data has +to be swapped out or written to a temporary file. If you are concerned about +maximum performance on baseline JPEG files, you should use buffered-image +mode only when the incoming file actually has multiple scans. This can be +tested by calling jpeg_has_multiple_scans(), which will return a correct +result at any time after jpeg_read_header() completes. + +It is also worth noting that when you use jpeg_consume_input() to let input +processing get ahead of output processing, the resulting pattern of access to +the coefficient buffer is quite nonsequential. It's best to use the memory +manager jmemnobs.c if you can (ie, if you have enough real or virtual main +memory). If not, at least make sure that max_memory_to_use is set as high as +possible. If the JPEG memory manager has to use a temporary file, you will +probably see a lot of disk traffic and poor performance. (This could be +improved with additional work on the memory manager, but we haven't gotten +around to it yet.) + +In some applications it may be convenient to use jpeg_consume_input() for all +input processing, including reading the initial markers; that is, you may +wish to call jpeg_consume_input() instead of jpeg_read_header() during +startup. This works, but note that you must check for JPEG_REACHED_SOS and +JPEG_REACHED_EOI return codes as the equivalent of jpeg_read_header's codes. +Once the first SOS marker has been reached, you must call +jpeg_start_decompress() before jpeg_consume_input() will consume more input; +it'll just keep returning JPEG_REACHED_SOS until you do. If you read a +tables-only file this way, jpeg_consume_input() will return JPEG_REACHED_EOI +without ever returning JPEG_REACHED_SOS; be sure to check for this case. +If this happens, the decompressor will not read any more input until you call +jpeg_abort() to reset it. It is OK to call jpeg_consume_input() even when not +using buffered-image mode, but in that case it's basically a no-op after the +initial markers have been read: it will just return JPEG_SUSPENDED. + + +Abbreviated datastreams and multiple images +------------------------------------------- + +A JPEG compression or decompression object can be reused to process multiple +images. This saves a small amount of time per image by eliminating the +"create" and "destroy" operations, but that isn't the real purpose of the +feature. Rather, reuse of an object provides support for abbreviated JPEG +datastreams. Object reuse can also simplify processing a series of images in +a single input or output file. This section explains these features. + +A JPEG file normally contains several hundred bytes worth of quantization +and Huffman tables. In a situation where many images will be stored or +transmitted with identical tables, this may represent an annoying overhead. +The JPEG standard therefore permits tables to be omitted. The standard +defines three classes of JPEG datastreams: + * "Interchange" datastreams contain an image and all tables needed to decode + the image. These are the usual kind of JPEG file. + * "Abbreviated image" datastreams contain an image, but are missing some or + all of the tables needed to decode that image. + * "Abbreviated table specification" (henceforth "tables-only") datastreams + contain only table specifications. +To decode an abbreviated image, it is necessary to load the missing table(s) +into the decoder beforehand. This can be accomplished by reading a separate +tables-only file. A variant scheme uses a series of images in which the first +image is an interchange (complete) datastream, while subsequent ones are +abbreviated and rely on the tables loaded by the first image. It is assumed +that once the decoder has read a table, it will remember that table until a +new definition for the same table number is encountered. + +It is the application designer's responsibility to figure out how to associate +the correct tables with an abbreviated image. While abbreviated datastreams +can be useful in a closed environment, their use is strongly discouraged in +any situation where data exchange with other applications might be needed. +Caveat designer. + +The JPEG library provides support for reading and writing any combination of +tables-only datastreams and abbreviated images. In both compression and +decompression objects, a quantization or Huffman table will be retained for +the lifetime of the object, unless it is overwritten by a new table definition. + + +To create abbreviated image datastreams, it is only necessary to tell the +compressor not to emit some or all of the tables it is using. Each +quantization and Huffman table struct contains a boolean field "sent_table", +which normally is initialized to FALSE. For each table used by the image, the +header-writing process emits the table and sets sent_table = TRUE unless it is +already TRUE. (In normal usage, this prevents outputting the same table +definition multiple times, as would otherwise occur because the chroma +components typically share tables.) Thus, setting this field to TRUE before +calling jpeg_start_compress() will prevent the table from being written at +all. + +If you want to create a "pure" abbreviated image file containing no tables, +just call "jpeg_suppress_tables(&cinfo, TRUE)" after constructing all the +tables. If you want to emit some but not all tables, you'll need to set the +individual sent_table fields directly. + +To create an abbreviated image, you must also call jpeg_start_compress() +with a second parameter of FALSE, not TRUE. Otherwise jpeg_start_compress() +will force all the sent_table fields to FALSE. (This is a safety feature to +prevent abbreviated images from being created accidentally.) + +To create a tables-only file, perform the same parameter setup that you +normally would, but instead of calling jpeg_start_compress() and so on, call +jpeg_write_tables(&cinfo). This will write an abbreviated datastream +containing only SOI, DQT and/or DHT markers, and EOI. All the quantization +and Huffman tables that are currently defined in the compression object will +be emitted unless their sent_tables flag is already TRUE, and then all the +sent_tables flags will be set TRUE. + +A sure-fire way to create matching tables-only and abbreviated image files +is to proceed as follows: + + create JPEG compression object + set JPEG parameters + set destination to tables-only file + jpeg_write_tables(&cinfo); + set destination to image file + jpeg_start_compress(&cinfo, FALSE); + write data... + jpeg_finish_compress(&cinfo); + +Since the JPEG parameters are not altered between writing the table file and +the abbreviated image file, the same tables are sure to be used. Of course, +you can repeat the jpeg_start_compress() ... jpeg_finish_compress() sequence +many times to produce many abbreviated image files matching the table file. + +You cannot suppress output of the computed Huffman tables when Huffman +optimization is selected. (If you could, there'd be no way to decode the +image...) Generally, you don't want to set optimize_coding = TRUE when +you are trying to produce abbreviated files. + +In some cases you might want to compress an image using tables which are +not stored in the application, but are defined in an interchange or +tables-only file readable by the application. This can be done by setting up +a JPEG decompression object to read the specification file, then copying the +tables into your compression object. See jpeg_copy_critical_parameters() +for an example of copying quantization tables. + + +To read abbreviated image files, you simply need to load the proper tables +into the decompression object before trying to read the abbreviated image. +If the proper tables are stored in the application program, you can just +allocate the table structs and fill in their contents directly. For example, +to load a fixed quantization table into table slot "n": + + if (cinfo.quant_tbl_ptrs[n] == NULL) + cinfo.quant_tbl_ptrs[n] = jpeg_alloc_quant_table((j_common_ptr) &cinfo); + quant_ptr = cinfo.quant_tbl_ptrs[n]; /* quant_ptr is JQUANT_TBL* */ + for (i = 0; i < 64; i++) { + /* Qtable[] is desired quantization table, in natural array order */ + quant_ptr->quantval[i] = Qtable[i]; + } + +Code to load a fixed Huffman table is typically (for AC table "n"): + + if (cinfo.ac_huff_tbl_ptrs[n] == NULL) + cinfo.ac_huff_tbl_ptrs[n] = jpeg_alloc_huff_table((j_common_ptr) &cinfo); + huff_ptr = cinfo.ac_huff_tbl_ptrs[n]; /* huff_ptr is JHUFF_TBL* */ + for (i = 1; i <= 16; i++) { + /* counts[i] is number of Huffman codes of length i bits, i=1..16 */ + huff_ptr->bits[i] = counts[i]; + } + for (i = 0; i < 256; i++) { + /* symbols[] is the list of Huffman symbols, in code-length order */ + huff_ptr->huffval[i] = symbols[i]; + } + +(Note that trying to set cinfo.quant_tbl_ptrs[n] to point directly at a +constant JQUANT_TBL object is not safe. If the incoming file happened to +contain a quantization table definition, your master table would get +overwritten! Instead allocate a working table copy and copy the master table +into it, as illustrated above. Ditto for Huffman tables, of course.) + +You might want to read the tables from a tables-only file, rather than +hard-wiring them into your application. The jpeg_read_header() call is +sufficient to read a tables-only file. You must pass a second parameter of +FALSE to indicate that you do not require an image to be present. Thus, the +typical scenario is + + create JPEG decompression object + set source to tables-only file + jpeg_read_header(&cinfo, FALSE); + set source to abbreviated image file + jpeg_read_header(&cinfo, TRUE); + set decompression parameters + jpeg_start_decompress(&cinfo); + read data... + jpeg_finish_decompress(&cinfo); + +In some cases, you may want to read a file without knowing whether it contains +an image or just tables. In that case, pass FALSE and check the return value +from jpeg_read_header(): it will be JPEG_HEADER_OK if an image was found, +JPEG_HEADER_TABLES_ONLY if only tables were found. (A third return value, +JPEG_SUSPENDED, is possible when using a suspending data source manager.) +Note that jpeg_read_header() will not complain if you read an abbreviated +image for which you haven't loaded the missing tables; the missing-table check +occurs later, in jpeg_start_decompress(). + + +It is possible to read a series of images from a single source file by +repeating the jpeg_read_header() ... jpeg_finish_decompress() sequence, +without releasing/recreating the JPEG object or the data source module. +(If you did reinitialize, any partial bufferload left in the data source +buffer at the end of one image would be discarded, causing you to lose the +start of the next image.) When you use this method, stored tables are +automatically carried forward, so some of the images can be abbreviated images +that depend on tables from earlier images. + +If you intend to write a series of images into a single destination file, +you might want to make a specialized data destination module that doesn't +flush the output buffer at term_destination() time. This would speed things +up by some trifling amount. Of course, you'd need to remember to flush the +buffer after the last image. You can make the later images be abbreviated +ones by passing FALSE to jpeg_start_compress(). + + +Special markers +--------------- + +Some applications may need to insert or extract special data in the JPEG +datastream. The JPEG standard provides marker types "COM" (comment) and +"APP0" through "APP15" (application) to hold application-specific data. +Unfortunately, the use of these markers is not specified by the standard. +COM markers are fairly widely used to hold user-supplied text. The JFIF file +format spec uses APP0 markers with specified initial strings to hold certain +data. Adobe applications use APP14 markers beginning with the string "Adobe" +for miscellaneous data. Other APPn markers are rarely seen, but might +contain almost anything. + +If you wish to store user-supplied text, we recommend you use COM markers +and place readable 7-bit ASCII text in them. Newline conventions are not +standardized --- expect to find LF (Unix style), CR/LF (DOS style), or CR +(Mac style). A robust COM reader should be able to cope with random binary +garbage, including nulls, since some applications generate COM markers +containing non-ASCII junk. (But yours should not be one of them.) + +For program-supplied data, use an APPn marker, and be sure to begin it with an +identifying string so that you can tell whether the marker is actually yours. +It's probably best to avoid using APP0 or APP14 for any private markers. +(NOTE: the upcoming SPIFF standard will use APP8 markers; we recommend you +not use APP8 markers for any private purposes, either.) + +Keep in mind that at most 65533 bytes can be put into one marker, but you +can have as many markers as you like. + +By default, the IJG compression library will write a JFIF APP0 marker if the +selected JPEG colorspace is grayscale or YCbCr, or an Adobe APP14 marker if +the selected colorspace is RGB, CMYK, or YCCK. You can disable this, but +we don't recommend it. The decompression library will recognize JFIF and +Adobe markers and will set the JPEG colorspace properly when one is found. + + +You can write special markers immediately following the datastream header by +calling jpeg_write_marker() after jpeg_start_compress() and before the first +call to jpeg_write_scanlines(). When you do this, the markers appear after +the SOI and the JFIF APP0 and Adobe APP14 markers (if written), but before +all else. Specify the marker type parameter as "JPEG_COM" for COM or +"JPEG_APP0 + n" for APPn. (Actually, jpeg_write_marker will let you write +any marker type, but we don't recommend writing any other kinds of marker.) +For example, to write a user comment string pointed to by comment_text: + jpeg_write_marker(cinfo, JPEG_COM, comment_text, strlen(comment_text)); + +If it's not convenient to store all the marker data in memory at once, +you can instead call jpeg_write_m_header() followed by multiple calls to +jpeg_write_m_byte(). If you do it this way, it's your responsibility to +call jpeg_write_m_byte() exactly the number of times given in the length +parameter to jpeg_write_m_header(). (This method lets you empty the +output buffer partway through a marker, which might be important when +using a suspending data destination module. In any case, if you are using +a suspending destination, you should flush its buffer after inserting +any special markers. See "I/O suspension".) + +Or, if you prefer to synthesize the marker byte sequence yourself, +you can just cram it straight into the data destination module. + +If you are writing JFIF 1.02 extension markers (thumbnail images), don't +forget to set cinfo.JFIF_minor_version = 2 so that the encoder will write the +correct JFIF version number in the JFIF header marker. The library's default +is to write version 1.01, but that's wrong if you insert any 1.02 extension +markers. (We could probably get away with just defaulting to 1.02, but there +used to be broken decoders that would complain about unknown minor version +numbers. To reduce compatibility risks it's safest not to write 1.02 unless +you are actually using 1.02 extensions.) + + +When reading, two methods of handling special markers are available: +1. You can ask the library to save the contents of COM and/or APPn markers +into memory, and then examine them at your leisure afterwards. +2. You can supply your own routine to process COM and/or APPn markers +on-the-fly as they are read. +The first method is simpler to use, especially if you are using a suspending +data source; writing a marker processor that copes with input suspension is +not easy (consider what happens if the marker is longer than your available +input buffer). However, the second method conserves memory since the marker +data need not be kept around after it's been processed. + +For either method, you'd normally set up marker handling after creating a +decompression object and before calling jpeg_read_header(), because the +markers of interest will typically be near the head of the file and so will +be scanned by jpeg_read_header. Once you've established a marker handling +method, it will be used for the life of that decompression object +(potentially many datastreams), unless you change it. Marker handling is +determined separately for COM markers and for each APPn marker code. + + +To save the contents of special markers in memory, call + jpeg_save_markers(cinfo, marker_code, length_limit) +where marker_code is the marker type to save, JPEG_COM or JPEG_APP0+n. +(To arrange to save all the special marker types, you need to call this +routine 17 times, for COM and APP0-APP15.) If the incoming marker is longer +than length_limit data bytes, only length_limit bytes will be saved; this +parameter allows you to avoid chewing up memory when you only need to see the +first few bytes of a potentially large marker. If you want to save all the +data, set length_limit to 0xFFFF; that is enough since marker lengths are only +16 bits. As a special case, setting length_limit to 0 prevents that marker +type from being saved at all. (That is the default behavior, in fact.) + +After jpeg_read_header() completes, you can examine the special markers by +following the cinfo->marker_list pointer chain. All the special markers in +the file appear in this list, in order of their occurrence in the file (but +omitting any markers of types you didn't ask for). Both the original data +length and the saved data length are recorded for each list entry; the latter +will not exceed length_limit for the particular marker type. Note that these +lengths exclude the marker length word, whereas the stored representation +within the JPEG file includes it. (Hence the maximum data length is really +only 65533.) + +It is possible that additional special markers appear in the file beyond the +SOS marker at which jpeg_read_header stops; if so, the marker list will be +extended during reading of the rest of the file. This is not expected to be +common, however. If you are short on memory you may want to reset the length +limit to zero for all marker types after finishing jpeg_read_header, to +ensure that the max_memory_to_use setting cannot be exceeded due to addition +of later markers. + +The marker list remains stored until you call jpeg_finish_decompress or +jpeg_abort, at which point the memory is freed and the list is set to empty. +(jpeg_destroy also releases the storage, of course.) + +Note that the library is internally interested in APP0 and APP14 markers; +if you try to set a small nonzero length limit on these types, the library +will silently force the length up to the minimum it wants. (But you can set +a zero length limit to prevent them from being saved at all.) Also, in a +16-bit environment, the maximum length limit may be constrained to less than +65533 by malloc() limitations. It is therefore best not to assume that the +effective length limit is exactly what you set it to be. + + +If you want to supply your own marker-reading routine, you do it by calling +jpeg_set_marker_processor(). A marker processor routine must have the +signature + boolean jpeg_marker_parser_method (j_decompress_ptr cinfo) +Although the marker code is not explicitly passed, the routine can find it +in cinfo->unread_marker. At the time of call, the marker proper has been +read from the data source module. The processor routine is responsible for +reading the marker length word and the remaining parameter bytes, if any. +Return TRUE to indicate success. (FALSE should be returned only if you are +using a suspending data source and it tells you to suspend. See the standard +marker processors in jdmarker.c for appropriate coding methods if you need to +use a suspending data source.) + +If you override the default APP0 or APP14 processors, it is up to you to +recognize JFIF and Adobe markers if you want colorspace recognition to occur +properly. We recommend copying and extending the default processors if you +want to do that. (A better idea is to save these marker types for later +examination by calling jpeg_save_markers(); that method doesn't interfere +with the library's own processing of these markers.) + +jpeg_set_marker_processor() and jpeg_save_markers() are mutually exclusive +--- if you call one it overrides any previous call to the other, for the +particular marker type specified. + +A simple example of an external COM processor can be found in djpeg.c. +Also, see jpegtran.c for an example of using jpeg_save_markers. + + +Raw (downsampled) image data +---------------------------- + +Some applications need to supply already-downsampled image data to the JPEG +compressor, or to receive raw downsampled data from the decompressor. The +library supports this requirement by allowing the application to write or +read raw data, bypassing the normal preprocessing or postprocessing steps. +The interface is different from the standard one and is somewhat harder to +use. If your interest is merely in bypassing color conversion, we recommend +that you use the standard interface and simply set jpeg_color_space = +in_color_space (or jpeg_color_space = out_color_space for decompression). +The mechanism described in this section is necessary only to supply or +receive downsampled image data, in which not all components have the same +dimensions. + + +To compress raw data, you must supply the data in the colorspace to be used +in the JPEG file (please read the earlier section on Special color spaces) +and downsampled to the sampling factors specified in the JPEG parameters. +You must supply the data in the format used internally by the JPEG library, +namely a JSAMPIMAGE array. This is an array of pointers to two-dimensional +arrays, each of type JSAMPARRAY. Each 2-D array holds the values for one +color component. This structure is necessary since the components are of +different sizes. If the image dimensions are not a multiple of the MCU size, +you must also pad the data correctly (usually, this is done by replicating +the last column and/or row). The data must be padded to a multiple of a DCT +block in each component: that is, each downsampled row must contain a +multiple of 8 valid samples, and there must be a multiple of 8 sample rows +for each component. (For applications such as conversion of digital TV +images, the standard image size is usually a multiple of the DCT block size, +so that no padding need actually be done.) + +The procedure for compression of raw data is basically the same as normal +compression, except that you call jpeg_write_raw_data() in place of +jpeg_write_scanlines(). Before calling jpeg_start_compress(), you must do +the following: + * Set cinfo->raw_data_in to TRUE. (It is set FALSE by jpeg_set_defaults().) + This notifies the library that you will be supplying raw data. + * Ensure jpeg_color_space is correct --- an explicit jpeg_set_colorspace() + call is a good idea. Note that since color conversion is bypassed, + in_color_space is ignored, except that jpeg_set_defaults() uses it to + choose the default jpeg_color_space setting. + * Ensure the sampling factors, cinfo->comp_info[i].h_samp_factor and + cinfo->comp_info[i].v_samp_factor, are correct. Since these indicate the + dimensions of the data you are supplying, it's wise to set them + explicitly, rather than assuming the library's defaults are what you want. + +To pass raw data to the library, call jpeg_write_raw_data() in place of +jpeg_write_scanlines(). The two routines work similarly except that +jpeg_write_raw_data takes a JSAMPIMAGE data array rather than JSAMPARRAY. +The scanlines count passed to and returned from jpeg_write_raw_data is +measured in terms of the component with the largest v_samp_factor. + +jpeg_write_raw_data() processes one MCU row per call, which is to say +v_samp_factor*DCTSIZE sample rows of each component. The passed num_lines +value must be at least max_v_samp_factor*DCTSIZE, and the return value will +be exactly that amount (or possibly some multiple of that amount, in future +library versions). This is true even on the last call at the bottom of the +image; don't forget to pad your data as necessary. + +The required dimensions of the supplied data can be computed for each +component as + cinfo->comp_info[i].width_in_blocks*DCTSIZE samples per row + cinfo->comp_info[i].height_in_blocks*DCTSIZE rows in image +after jpeg_start_compress() has initialized those fields. If the valid data +is smaller than this, it must be padded appropriately. For some sampling +factors and image sizes, additional dummy DCT blocks are inserted to make +the image a multiple of the MCU dimensions. The library creates such dummy +blocks itself; it does not read them from your supplied data. Therefore you +need never pad by more than DCTSIZE samples. An example may help here. +Assume 2h2v downsampling of YCbCr data, that is + cinfo->comp_info[0].h_samp_factor = 2 for Y + cinfo->comp_info[0].v_samp_factor = 2 + cinfo->comp_info[1].h_samp_factor = 1 for Cb + cinfo->comp_info[1].v_samp_factor = 1 + cinfo->comp_info[2].h_samp_factor = 1 for Cr + cinfo->comp_info[2].v_samp_factor = 1 +and suppose that the nominal image dimensions (cinfo->image_width and +cinfo->image_height) are 101x101 pixels. Then jpeg_start_compress() will +compute downsampled_width = 101 and width_in_blocks = 13 for Y, +downsampled_width = 51 and width_in_blocks = 7 for Cb and Cr (and the same +for the height fields). You must pad the Y data to at least 13*8 = 104 +columns and rows, the Cb/Cr data to at least 7*8 = 56 columns and rows. The +MCU height is max_v_samp_factor = 2 DCT rows so you must pass at least 16 +scanlines on each call to jpeg_write_raw_data(), which is to say 16 actual +sample rows of Y and 8 each of Cb and Cr. A total of 7 MCU rows are needed, +so you must pass a total of 7*16 = 112 "scanlines". The last DCT block row +of Y data is dummy, so it doesn't matter what you pass for it in the data +arrays, but the scanlines count must total up to 112 so that all of the Cb +and Cr data gets passed. + +Output suspension is supported with raw-data compression: if the data +destination module suspends, jpeg_write_raw_data() will return 0. +In this case the same data rows must be passed again on the next call. + + +Decompression with raw data output implies bypassing all postprocessing: +you cannot ask for rescaling or color quantization, for instance. More +seriously, you must deal with the color space and sampling factors present in +the incoming file. If your application only handles, say, 2h1v YCbCr data, +you must check for and fail on other color spaces or other sampling factors. +The library will not convert to a different color space for you. + +To obtain raw data output, set cinfo->raw_data_out = TRUE before +jpeg_start_decompress() (it is set FALSE by jpeg_read_header()). Be sure to +verify that the color space and sampling factors are ones you can handle. +Then call jpeg_read_raw_data() in place of jpeg_read_scanlines(). The +decompression process is otherwise the same as usual. + +jpeg_read_raw_data() returns one MCU row per call, and thus you must pass a +buffer of at least max_v_samp_factor*DCTSIZE scanlines (scanline counting is +the same as for raw-data compression). The buffer you pass must be large +enough to hold the actual data plus padding to DCT-block boundaries. As with +compression, any entirely dummy DCT blocks are not processed so you need not +allocate space for them, but the total scanline count includes them. The +above example of computing buffer dimensions for raw-data compression is +equally valid for decompression. + +Input suspension is supported with raw-data decompression: if the data source +module suspends, jpeg_read_raw_data() will return 0. You can also use +buffered-image mode to read raw data in multiple passes. + + +Really raw data: DCT coefficients +--------------------------------- + +It is possible to read or write the contents of a JPEG file as raw DCT +coefficients. This facility is mainly intended for use in lossless +transcoding between different JPEG file formats. Other possible applications +include lossless cropping of a JPEG image, lossless reassembly of a +multi-strip or multi-tile TIFF/JPEG file into a single JPEG datastream, etc. + +To read the contents of a JPEG file as DCT coefficients, open the file and do +jpeg_read_header() as usual. But instead of calling jpeg_start_decompress() +and jpeg_read_scanlines(), call jpeg_read_coefficients(). This will read the +entire image into a set of virtual coefficient-block arrays, one array per +component. The return value is a pointer to an array of virtual-array +descriptors. Each virtual array can be accessed directly using the JPEG +memory manager's access_virt_barray method (see Memory management, below, +and also read structure.doc's discussion of virtual array handling). Or, +for simple transcoding to a different JPEG file format, the array list can +just be handed directly to jpeg_write_coefficients(). + +Each block in the block arrays contains quantized coefficient values in +normal array order (not JPEG zigzag order). The block arrays contain only +DCT blocks containing real data; any entirely-dummy blocks added to fill out +interleaved MCUs at the right or bottom edges of the image are discarded +during reading and are not stored in the block arrays. (The size of each +block array can be determined from the width_in_blocks and height_in_blocks +fields of the component's comp_info entry.) This is also the data format +expected by jpeg_write_coefficients(). + +When you are done using the virtual arrays, call jpeg_finish_decompress() +to release the array storage and return the decompression object to an idle +state; or just call jpeg_destroy() if you don't need to reuse the object. + +If you use a suspending data source, jpeg_read_coefficients() will return +NULL if it is forced to suspend; a non-NULL return value indicates successful +completion. You need not test for a NULL return value when using a +non-suspending data source. + +It is also possible to call jpeg_read_coefficients() to obtain access to the +decoder's coefficient arrays during a normal decode cycle in buffered-image +mode. This frammish might be useful for progressively displaying an incoming +image and then re-encoding it without loss. To do this, decode in buffered- +image mode as discussed previously, then call jpeg_read_coefficients() after +the last jpeg_finish_output() call. The arrays will be available for your use +until you call jpeg_finish_decompress(). + + +To write the contents of a JPEG file as DCT coefficients, you must provide +the DCT coefficients stored in virtual block arrays. You can either pass +block arrays read from an input JPEG file by jpeg_read_coefficients(), or +allocate virtual arrays from the JPEG compression object and fill them +yourself. In either case, jpeg_write_coefficients() is substituted for +jpeg_start_compress() and jpeg_write_scanlines(). Thus the sequence is + * Create compression object + * Set all compression parameters as necessary + * Request virtual arrays if needed + * jpeg_write_coefficients() + * jpeg_finish_compress() + * Destroy or re-use compression object +jpeg_write_coefficients() is passed a pointer to an array of virtual block +array descriptors; the number of arrays is equal to cinfo.num_components. + +The virtual arrays need only have been requested, not realized, before +jpeg_write_coefficients() is called. A side-effect of +jpeg_write_coefficients() is to realize any virtual arrays that have been +requested from the compression object's memory manager. Thus, when obtaining +the virtual arrays from the compression object, you should fill the arrays +after calling jpeg_write_coefficients(). The data is actually written out +when you call jpeg_finish_compress(); jpeg_write_coefficients() only writes +the file header. + +When writing raw DCT coefficients, it is crucial that the JPEG quantization +tables and sampling factors match the way the data was encoded, or the +resulting file will be invalid. For transcoding from an existing JPEG file, +we recommend using jpeg_copy_critical_parameters(). This routine initializes +all the compression parameters to default values (like jpeg_set_defaults()), +then copies the critical information from a source decompression object. +The decompression object should have just been used to read the entire +JPEG input file --- that is, it should be awaiting jpeg_finish_decompress(). + +jpeg_write_coefficients() marks all tables stored in the compression object +as needing to be written to the output file (thus, it acts like +jpeg_start_compress(cinfo, TRUE)). This is for safety's sake, to avoid +emitting abbreviated JPEG files by accident. If you really want to emit an +abbreviated JPEG file, call jpeg_suppress_tables(), or set the tables' +individual sent_table flags, between calling jpeg_write_coefficients() and +jpeg_finish_compress(). + + +Progress monitoring +------------------- + +Some applications may need to regain control from the JPEG library every so +often. The typical use of this feature is to produce a percent-done bar or +other progress display. (For a simple example, see cjpeg.c or djpeg.c.) +Although you do get control back frequently during the data-transferring pass +(the jpeg_read_scanlines or jpeg_write_scanlines loop), any additional passes +will occur inside jpeg_finish_compress or jpeg_start_decompress; those +routines may take a long time to execute, and you don't get control back +until they are done. + +You can define a progress-monitor routine which will be called periodically +by the library. No guarantees are made about how often this call will occur, +so we don't recommend you use it for mouse tracking or anything like that. +At present, a call will occur once per MCU row, scanline, or sample row +group, whichever unit is convenient for the current processing mode; so the +wider the image, the longer the time between calls. During the data +transferring pass, only one call occurs per call of jpeg_read_scanlines or +jpeg_write_scanlines, so don't pass a large number of scanlines at once if +you want fine resolution in the progress count. (If you really need to use +the callback mechanism for time-critical tasks like mouse tracking, you could +insert additional calls inside some of the library's inner loops.) + +To establish a progress-monitor callback, create a struct jpeg_progress_mgr, +fill in its progress_monitor field with a pointer to your callback routine, +and set cinfo->progress to point to the struct. The callback will be called +whenever cinfo->progress is non-NULL. (This pointer is set to NULL by +jpeg_create_compress or jpeg_create_decompress; the library will not change +it thereafter. So if you allocate dynamic storage for the progress struct, +make sure it will live as long as the JPEG object does. Allocating from the +JPEG memory manager with lifetime JPOOL_PERMANENT will work nicely.) You +can use the same callback routine for both compression and decompression. + +The jpeg_progress_mgr struct contains four fields which are set by the library: + long pass_counter; /* work units completed in this pass */ + long pass_limit; /* total number of work units in this pass */ + int completed_passes; /* passes completed so far */ + int total_passes; /* total number of passes expected */ +During any one pass, pass_counter increases from 0 up to (not including) +pass_limit; the step size is usually but not necessarily 1. The pass_limit +value may change from one pass to another. The expected total number of +passes is in total_passes, and the number of passes already completed is in +completed_passes. Thus the fraction of work completed may be estimated as + completed_passes + (pass_counter/pass_limit) + -------------------------------------------- + total_passes +ignoring the fact that the passes may not be equal amounts of work. + +When decompressing, pass_limit can even change within a pass, because it +depends on the number of scans in the JPEG file, which isn't always known in +advance. The computed fraction-of-work-done may jump suddenly (if the library +discovers it has overestimated the number of scans) or even decrease (in the +opposite case). It is not wise to put great faith in the work estimate. + +When using the decompressor's buffered-image mode, the progress monitor work +estimate is likely to be completely unhelpful, because the library has no way +to know how many output passes will be demanded of it. Currently, the library +sets total_passes based on the assumption that there will be one more output +pass if the input file end hasn't yet been read (jpeg_input_complete() isn't +TRUE), but no more output passes if the file end has been reached when the +output pass is started. This means that total_passes will rise as additional +output passes are requested. If you have a way of determining the input file +size, estimating progress based on the fraction of the file that's been read +will probably be more useful than using the library's value. + + +Memory management +----------------- + +This section covers some key facts about the JPEG library's built-in memory +manager. For more info, please read structure.doc's section about the memory +manager, and consult the source code if necessary. + +All memory and temporary file allocation within the library is done via the +memory manager. If necessary, you can replace the "back end" of the memory +manager to control allocation yourself (for example, if you don't want the +library to use malloc() and free() for some reason). + +Some data is allocated "permanently" and will not be freed until the JPEG +object is destroyed. Most data is allocated "per image" and is freed by +jpeg_finish_compress, jpeg_finish_decompress, or jpeg_abort. You can call the +memory manager yourself to allocate structures that will automatically be +freed at these times. Typical code for this is + ptr = (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, size); +Use JPOOL_PERMANENT to get storage that lasts as long as the JPEG object. +Use alloc_large instead of alloc_small for anything bigger than a few Kbytes. +There are also alloc_sarray and alloc_barray routines that automatically +build 2-D sample or block arrays. + +The library's minimum space requirements to process an image depend on the +image's width, but not on its height, because the library ordinarily works +with "strip" buffers that are as wide as the image but just a few rows high. +Some operating modes (eg, two-pass color quantization) require full-image +buffers. Such buffers are treated as "virtual arrays": only the current strip +need be in memory, and the rest can be swapped out to a temporary file. + +If you use the simplest memory manager back end (jmemnobs.c), then no +temporary files are used; virtual arrays are simply malloc()'d. Images bigger +than memory can be processed only if your system supports virtual memory. +The other memory manager back ends support temporary files of various flavors +and thus work in machines without virtual memory. They may also be useful on +Unix machines if you need to process images that exceed available swap space. + +When using temporary files, the library will make the in-memory buffers for +its virtual arrays just big enough to stay within a "maximum memory" setting. +Your application can set this limit by setting cinfo->mem->max_memory_to_use +after creating the JPEG object. (Of course, there is still a minimum size for +the buffers, so the max-memory setting is effective only if it is bigger than +the minimum space needed.) If you allocate any large structures yourself, you +must allocate them before jpeg_start_compress() or jpeg_start_decompress() in +order to have them counted against the max memory limit. Also keep in mind +that space allocated with alloc_small() is ignored, on the assumption that +it's too small to be worth worrying about; so a reasonable safety margin +should be left when setting max_memory_to_use. + +If you use the jmemname.c or jmemdos.c memory manager back end, it is +important to clean up the JPEG object properly to ensure that the temporary +files get deleted. (This is especially crucial with jmemdos.c, where the +"temporary files" may be extended-memory segments; if they are not freed, +DOS will require a reboot to recover the memory.) Thus, with these memory +managers, it's a good idea to provide a signal handler that will trap any +early exit from your program. The handler should call either jpeg_abort() +or jpeg_destroy() for any active JPEG objects. A handler is not needed with +jmemnobs.c, and shouldn't be necessary with jmemansi.c or jmemmac.c either, +since the C library is supposed to take care of deleting files made with +tmpfile(). + + +Memory usage +------------ + +Working memory requirements while performing compression or decompression +depend on image dimensions, image characteristics (such as colorspace and +JPEG process), and operating mode (application-selected options). + +As of v6b, the decompressor requires: + 1. About 24K in more-or-less-fixed-size data. This varies a bit depending + on operating mode and image characteristics (particularly color vs. + grayscale), but it doesn't depend on image dimensions. + 2. Strip buffers (of size proportional to the image width) for IDCT and + upsampling results. The worst case for commonly used sampling factors + is about 34 bytes * width in pixels for a color image. A grayscale image + only needs about 8 bytes per pixel column. + 3. A full-image DCT coefficient buffer is needed to decode a multi-scan JPEG + file (including progressive JPEGs), or whenever you select buffered-image + mode. This takes 2 bytes/coefficient. At typical 2x2 sampling, that's + 3 bytes per pixel for a color image. Worst case (1x1 sampling) requires + 6 bytes/pixel. For grayscale, figure 2 bytes/pixel. + 4. To perform 2-pass color quantization, the decompressor also needs a + 128K color lookup table and a full-image pixel buffer (3 bytes/pixel). +This does not count any memory allocated by the application, such as a +buffer to hold the final output image. + +The above figures are valid for 8-bit JPEG data precision and a machine with +32-bit ints. For 12-bit JPEG data, double the size of the strip buffers and +quantization pixel buffer. The "fixed-size" data will be somewhat smaller +with 16-bit ints, larger with 64-bit ints. Also, CMYK or other unusual +color spaces will require different amounts of space. + +The full-image coefficient and pixel buffers, if needed at all, do not +have to be fully RAM resident; you can have the library use temporary +files instead when the total memory usage would exceed a limit you set. +(But if your OS supports virtual memory, it's probably better to just use +jmemnobs and let the OS do the swapping.) + +The compressor's memory requirements are similar, except that it has no need +for color quantization. Also, it needs a full-image DCT coefficient buffer +if Huffman-table optimization is asked for, even if progressive mode is not +requested. + +If you need more detailed information about memory usage in a particular +situation, you can enable the MEM_STATS code in jmemmgr.c. + + +Library compile-time options +---------------------------- + +A number of compile-time options are available by modifying jmorecfg.h. + +The JPEG standard provides for both the baseline 8-bit DCT process and +a 12-bit DCT process. The IJG code supports 12-bit lossy JPEG if you define +BITS_IN_JSAMPLE as 12 rather than 8. Note that this causes JSAMPLE to be +larger than a char, so it affects the surrounding application's image data. +The sample applications cjpeg and djpeg can support 12-bit mode only for PPM +and GIF file formats; you must disable the other file formats to compile a +12-bit cjpeg or djpeg. (install.doc has more information about that.) +At present, a 12-bit library can handle *only* 12-bit images, not both +precisions. (If you need to include both 8- and 12-bit libraries in a single +application, you could probably do it by defining NEED_SHORT_EXTERNAL_NAMES +for just one of the copies. You'd have to access the 8-bit and 12-bit copies +from separate application source files. This is untested ... if you try it, +we'd like to hear whether it works!) + +Note that a 12-bit library always compresses in Huffman optimization mode, +in order to generate valid Huffman tables. This is necessary because our +default Huffman tables only cover 8-bit data. If you need to output 12-bit +files in one pass, you'll have to supply suitable default Huffman tables. +You may also want to supply your own DCT quantization tables; the existing +quality-scaling code has been developed for 8-bit use, and probably doesn't +generate especially good tables for 12-bit. + +The maximum number of components (color channels) in the image is determined +by MAX_COMPONENTS. The JPEG standard allows up to 255 components, but we +expect that few applications will need more than four or so. + +On machines with unusual data type sizes, you may be able to improve +performance or reduce memory space by tweaking the various typedefs in +jmorecfg.h. In particular, on some RISC CPUs, access to arrays of "short"s +is quite slow; consider trading memory for speed by making JCOEF, INT16, and +UINT16 be "int" or "unsigned int". UINT8 is also a candidate to become int. +You probably don't want to make JSAMPLE be int unless you have lots of memory +to burn. + +You can reduce the size of the library by compiling out various optional +functions. To do this, undefine xxx_SUPPORTED symbols as necessary. + +You can also save a few K by not having text error messages in the library; +the standard error message table occupies about 5Kb. This is particularly +reasonable for embedded applications where there's no good way to display +a message anyway. To do this, remove the creation of the message table +(jpeg_std_message_table[]) from jerror.c, and alter format_message to do +something reasonable without it. You could output the numeric value of the +message code number, for example. If you do this, you can also save a couple +more K by modifying the TRACEMSn() macros in jerror.h to expand to nothing; +you don't need trace capability anyway, right? + + +Portability considerations +-------------------------- + +The JPEG library has been written to be extremely portable; the sample +applications cjpeg and djpeg are slightly less so. This section summarizes +the design goals in this area. (If you encounter any bugs that cause the +library to be less portable than is claimed here, we'd appreciate hearing +about them.) + +The code works fine on ANSI C, C++, and pre-ANSI C compilers, using any of +the popular system include file setups, and some not-so-popular ones too. +See install.doc for configuration procedures. + +The code is not dependent on the exact sizes of the C data types. As +distributed, we make the assumptions that + char is at least 8 bits wide + short is at least 16 bits wide + int is at least 16 bits wide + long is at least 32 bits wide +(These are the minimum requirements of the ANSI C standard.) Wider types will +work fine, although memory may be used inefficiently if char is much larger +than 8 bits or short is much bigger than 16 bits. The code should work +equally well with 16- or 32-bit ints. + +In a system where these assumptions are not met, you may be able to make the +code work by modifying the typedefs in jmorecfg.h. However, you will probably +have difficulty if int is less than 16 bits wide, since references to plain +int abound in the code. + +char can be either signed or unsigned, although the code runs faster if an +unsigned char type is available. If char is wider than 8 bits, you will need +to redefine JOCTET and/or provide custom data source/destination managers so +that JOCTET represents exactly 8 bits of data on external storage. + +The JPEG library proper does not assume ASCII representation of characters. +But some of the image file I/O modules in cjpeg/djpeg do have ASCII +dependencies in file-header manipulation; so does cjpeg's select_file_type() +routine. + +The JPEG library does not rely heavily on the C library. In particular, C +stdio is used only by the data source/destination modules and the error +handler, all of which are application-replaceable. (cjpeg/djpeg are more +heavily dependent on stdio.) malloc and free are called only from the memory +manager "back end" module, so you can use a different memory allocator by +replacing that one file. + +The code generally assumes that C names must be unique in the first 15 +characters. However, global function names can be made unique in the +first 6 characters by defining NEED_SHORT_EXTERNAL_NAMES. + +More info about porting the code may be gleaned by reading jconfig.doc, +jmorecfg.h, and jinclude.h. + + +Notes for MS-DOS implementors +----------------------------- + +The IJG code is designed to work efficiently in 80x86 "small" or "medium" +memory models (i.e., data pointers are 16 bits unless explicitly declared +"far"; code pointers can be either size). You may be able to use small +model to compile cjpeg or djpeg by itself, but you will probably have to use +medium model for any larger application. This won't make much difference in +performance. You *will* take a noticeable performance hit if you use a +large-data memory model (perhaps 10%-25%), and you should avoid "huge" model +if at all possible. + +The JPEG library typically needs 2Kb-3Kb of stack space. It will also +malloc about 20K-30K of near heap space while executing (and lots of far +heap, but that doesn't count in this calculation). This figure will vary +depending on selected operating mode, and to a lesser extent on image size. +There is also about 5Kb-6Kb of constant data which will be allocated in the +near data segment (about 4Kb of this is the error message table). +Thus you have perhaps 20K available for other modules' static data and near +heap space before you need to go to a larger memory model. The C library's +static data will account for several K of this, but that still leaves a good +deal for your needs. (If you are tight on space, you could reduce the sizes +of the I/O buffers allocated by jdatasrc.c and jdatadst.c, say from 4K to +1K. Another possibility is to move the error message table to far memory; +this should be doable with only localized hacking on jerror.c.) + +About 2K of the near heap space is "permanent" memory that will not be +released until you destroy the JPEG object. This is only an issue if you +save a JPEG object between compression or decompression operations. + +Far data space may also be a tight resource when you are dealing with large +images. The most memory-intensive case is decompression with two-pass color +quantization, or single-pass quantization to an externally supplied color +map. This requires a 128Kb color lookup table plus strip buffers amounting +to about 40 bytes per column for typical sampling ratios (eg, about 25600 +bytes for a 640-pixel-wide image). You may not be able to process wide +images if you have large data structures of your own. + +Of course, all of these concerns vanish if you use a 32-bit flat-memory-model +compiler, such as DJGPP or Watcom C. We highly recommend flat model if you +can use it; the JPEG library is significantly faster in flat model. diff --git a/gdcm/Utilities/gdcmjpeg/mangle_jpeg.h.in b/gdcm/Utilities/gdcmjpeg/mangle_jpeg.h.in new file mode 100644 index 0000000..260f49a --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/mangle_jpeg.h.in @@ -0,0 +1,140 @@ +/* mangle_jpeg@CMAKE_BITS_IN_JSAMPLE@bits.h file generated by CMake http://www.cmake.org */ +#ifndef @MANGLE_PREFIX@_mangle_h +#define @MANGLE_PREFIX@_mangle_h + +/* + * This header file mangles all symbols exported from the jpeg library. + * It is included in all files while building the jpeg library. Due to + * namespace pollution, no jpeg headers should be included in .h files in + * GDCM. This also allows us to generate two jpeg library (8bits and 12bits). + * + * The following command was used to obtain the symbol list: + * + * nm lib@MANGLE_PREFIX@.a | grep " [R|T] " | colrm 1 11 | sort + */ + + +#define jcopy_block_row @MANGLE_PREFIX@_jcopy_block_row +#define jcopy_sample_rows @MANGLE_PREFIX@_jcopy_sample_rows +#define jdiv_round_up @MANGLE_PREFIX@_jdiv_round_up +#define jinit_1pass_quantizer @MANGLE_PREFIX@_jinit_1pass_quantizer +#define jinit_2pass_quantizer @MANGLE_PREFIX@_jinit_2pass_quantizer +#define jinit_arith_decoder @MANGLE_PREFIX@_jinit_arith_decoder +#define jinit_arith_encoder @MANGLE_PREFIX@_jinit_arith_encoder +#define jinit_c_codec @MANGLE_PREFIX@_jinit_c_codec +#define jinit_c_coef_controller @MANGLE_PREFIX@_jinit_c_coef_controller +#define jinit_c_diff_controller @MANGLE_PREFIX@_jinit_c_diff_controller +#define jinit_c_main_controller @MANGLE_PREFIX@_jinit_c_main_controller +#define jinit_c_master_control @MANGLE_PREFIX@_jinit_c_master_control +#define jinit_c_prep_controller @MANGLE_PREFIX@_jinit_c_prep_controller +#define jinit_c_scaler @MANGLE_PREFIX@_jinit_c_scaler +#define jinit_color_converter @MANGLE_PREFIX@_jinit_color_converter +#define jinit_color_deconverter @MANGLE_PREFIX@_jinit_color_deconverter +#define jinit_compress_master @MANGLE_PREFIX@_jinit_compress_master +#define jinit_d_codec @MANGLE_PREFIX@_jinit_d_codec +#define jinit_d_coef_controller @MANGLE_PREFIX@_jinit_d_coef_controller +#define jinit_d_diff_controller @MANGLE_PREFIX@_jinit_d_diff_controller +#define jinit_d_main_controller @MANGLE_PREFIX@_jinit_d_main_controller +#define jinit_d_post_controller @MANGLE_PREFIX@_jinit_d_post_controller +#define jinit_d_scaler @MANGLE_PREFIX@_jinit_d_scaler +#define jinit_differencer @MANGLE_PREFIX@_jinit_differencer +#define jinit_downsampler @MANGLE_PREFIX@_jinit_downsampler +#define jinit_forward_dct @MANGLE_PREFIX@_jinit_forward_dct +#define jinit_input_controller @MANGLE_PREFIX@_jinit_input_controller +#define jinit_inverse_dct @MANGLE_PREFIX@_jinit_inverse_dct +#define jinit_lhuff_decoder @MANGLE_PREFIX@_jinit_lhuff_decoder +#define jinit_lhuff_encoder @MANGLE_PREFIX@_jinit_lhuff_encoder +#define jinit_lossless_c_codec @MANGLE_PREFIX@_jinit_lossless_c_codec +#define jinit_lossless_d_codec @MANGLE_PREFIX@_jinit_lossless_d_codec +#define jinit_lossy_c_codec @MANGLE_PREFIX@_jinit_lossy_c_codec +#define jinit_lossy_d_codec @MANGLE_PREFIX@_jinit_lossy_d_codec +#define jinit_marker_reader @MANGLE_PREFIX@_jinit_marker_reader +#define jinit_marker_writer @MANGLE_PREFIX@_jinit_marker_writer +#define jinit_master_decompress @MANGLE_PREFIX@_jinit_master_decompress +#define jinit_memory_mgr @MANGLE_PREFIX@_jinit_memory_mgr +#define jinit_merged_upsampler @MANGLE_PREFIX@_jinit_merged_upsampler +#define jinit_phuff_decoder @MANGLE_PREFIX@_jinit_phuff_decoder +#define jinit_phuff_encoder @MANGLE_PREFIX@_jinit_phuff_encoder +#define jinit_shuff_decoder @MANGLE_PREFIX@_jinit_shuff_decoder +#define jinit_shuff_encoder @MANGLE_PREFIX@_jinit_shuff_encoder +#define jinit_undifferencer @MANGLE_PREFIX@_jinit_undifferencer +#define jinit_upsampler @MANGLE_PREFIX@_jinit_upsampler +#define jpeg_CreateCompress @MANGLE_PREFIX@_jpeg_CreateCompress +#define jpeg_CreateDecompress @MANGLE_PREFIX@_jpeg_CreateDecompress +#define jpeg_abort @MANGLE_PREFIX@_jpeg_abort +#define jpeg_abort_compress @MANGLE_PREFIX@_jpeg_abort_compress +#define jpeg_abort_decompress @MANGLE_PREFIX@_jpeg_abort_decompress +#define jpeg_add_quant_table @MANGLE_PREFIX@_jpeg_add_quant_table +#define jpeg_alloc_huff_table @MANGLE_PREFIX@_jpeg_alloc_huff_table +#define jpeg_alloc_quant_table @MANGLE_PREFIX@_jpeg_alloc_quant_table +#define jpeg_calc_output_dimensions @MANGLE_PREFIX@_jpeg_calc_output_dimensions +#define jpeg_consume_input @MANGLE_PREFIX@_jpeg_consume_input +#define jpeg_copy_critical_parameters @MANGLE_PREFIX@_jpeg_copy_critical_parameters +#define jpeg_default_colorspace @MANGLE_PREFIX@_jpeg_default_colorspace +#define jpeg_destroy @MANGLE_PREFIX@_jpeg_destroy +#define jpeg_destroy_compress @MANGLE_PREFIX@_jpeg_destroy_compress +#define jpeg_destroy_decompress @MANGLE_PREFIX@_jpeg_destroy_decompress +#define jpeg_fdct_float @MANGLE_PREFIX@_jpeg_fdct_float +#define jpeg_fdct_ifast @MANGLE_PREFIX@_jpeg_fdct_ifast +#define jpeg_fdct_islow @MANGLE_PREFIX@_jpeg_fdct_islow +#define jpeg_fill_bit_buffer @MANGLE_PREFIX@_jpeg_fill_bit_buffer +#define jpeg_finish_compress @MANGLE_PREFIX@_jpeg_finish_compress +#define jpeg_finish_decompress @MANGLE_PREFIX@_jpeg_finish_decompress +#define jpeg_finish_output @MANGLE_PREFIX@_jpeg_finish_output +#define jpeg_free_large @MANGLE_PREFIX@_jpeg_free_large +#define jpeg_free_small @MANGLE_PREFIX@_jpeg_free_small +#define jpeg_gen_optimal_table @MANGLE_PREFIX@_jpeg_gen_optimal_table +#define jpeg_get_large @MANGLE_PREFIX@_jpeg_get_large +#define jpeg_get_small @MANGLE_PREFIX@_jpeg_get_small +#define jpeg_has_multiple_scans @MANGLE_PREFIX@_jpeg_has_multiple_scans +#define jpeg_huff_decode @MANGLE_PREFIX@_jpeg_huff_decode +#define jpeg_idct_1x1 @MANGLE_PREFIX@_jpeg_idct_1x1 +#define jpeg_idct_2x2 @MANGLE_PREFIX@_jpeg_idct_2x2 +#define jpeg_idct_4x4 @MANGLE_PREFIX@_jpeg_idct_4x4 +#define jpeg_idct_float @MANGLE_PREFIX@_jpeg_idct_float +#define jpeg_idct_ifast @MANGLE_PREFIX@_jpeg_idct_ifast +#define jpeg_idct_islow @MANGLE_PREFIX@_jpeg_idct_islow +#define jpeg_input_complete @MANGLE_PREFIX@_jpeg_input_complete +#define jpeg_make_c_derived_tbl @MANGLE_PREFIX@_jpeg_make_c_derived_tbl +#define jpeg_make_d_derived_tbl @MANGLE_PREFIX@_jpeg_make_d_derived_tbl +#define jpeg_mem_available @MANGLE_PREFIX@_jpeg_mem_available +#define jpeg_mem_init @MANGLE_PREFIX@_jpeg_mem_init +#define jpeg_mem_term @MANGLE_PREFIX@_jpeg_mem_term +#define jpeg_natural_order @MANGLE_PREFIX@_jpeg_natural_order +#define jpeg_new_colormap @MANGLE_PREFIX@_jpeg_new_colormap +#define jpeg_open_backing_store @MANGLE_PREFIX@_jpeg_open_backing_store +#define jpeg_quality_scaling @MANGLE_PREFIX@_jpeg_quality_scaling +#define jpeg_read_coefficients @MANGLE_PREFIX@_jpeg_read_coefficients +#define jpeg_read_header @MANGLE_PREFIX@_jpeg_read_header +#define jpeg_read_raw_data @MANGLE_PREFIX@_jpeg_read_raw_data +#define jpeg_read_scanlines @MANGLE_PREFIX@_jpeg_read_scanlines +#define jpeg_resync_to_restart @MANGLE_PREFIX@_jpeg_resync_to_restart +#define jpeg_save_markers @MANGLE_PREFIX@_jpeg_save_markers +#define jpeg_set_colorspace @MANGLE_PREFIX@_jpeg_set_colorspace +#define jpeg_set_defaults @MANGLE_PREFIX@_jpeg_set_defaults +#define jpeg_set_linear_quality @MANGLE_PREFIX@_jpeg_set_linear_quality +#define jpeg_set_marker_processor @MANGLE_PREFIX@_jpeg_set_marker_processor +#define jpeg_set_quality @MANGLE_PREFIX@_jpeg_set_quality +#define jpeg_simple_lossless @MANGLE_PREFIX@_jpeg_simple_lossless +#define jpeg_simple_progression @MANGLE_PREFIX@_jpeg_simple_progression +#define jpeg_start_compress @MANGLE_PREFIX@_jpeg_start_compress +#define jpeg_start_decompress @MANGLE_PREFIX@_jpeg_start_decompress +#define jpeg_start_output @MANGLE_PREFIX@_jpeg_start_output +#define jpeg_std_error @MANGLE_PREFIX@_jpeg_std_error +#define jpeg_std_message_table @MANGLE_PREFIX@_jpeg_std_message_table +#define jpeg_stdio_dest @MANGLE_PREFIX@_jpeg_stdio_dest +#define jpeg_stdio_src @MANGLE_PREFIX@_jpeg_stdio_src +#define jpeg_suppress_tables @MANGLE_PREFIX@_jpeg_suppress_tables +#define jpeg_write_coefficients @MANGLE_PREFIX@_jpeg_write_coefficients +#define jpeg_write_m_byte @MANGLE_PREFIX@_jpeg_write_m_byte +#define jpeg_write_m_header @MANGLE_PREFIX@_jpeg_write_m_header +#define jpeg_write_marker @MANGLE_PREFIX@_jpeg_write_marker +#define jpeg_write_raw_data @MANGLE_PREFIX@_jpeg_write_raw_data +#define jpeg_write_scanlines @MANGLE_PREFIX@_jpeg_write_scanlines +#define jpeg_write_tables @MANGLE_PREFIX@_jpeg_write_tables +#define jround_up @MANGLE_PREFIX@_jround_up +#define jzero_far @MANGLE_PREFIX@_jzero_far + +#define jpeg_memory_src @MANGLE_PREFIX@_memory_src + +#endif diff --git a/gdcm/Utilities/gdcmjpeg/structure.doc b/gdcm/Utilities/gdcmjpeg/structure.doc new file mode 100644 index 0000000..3191a5b --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/structure.doc @@ -0,0 +1,1042 @@ +IJG JPEG LIBRARY: SYSTEM ARCHITECTURE + +Copyright (C) 1991-1995, Thomas G. Lane. +This file is part of the Independent JPEG Group's software. +For conditions of distribution and use, see the accompanying README file. + + +This file provides an overview of the architecture of the IJG JPEG software; +that is, the functions of the various modules in the system and the interfaces +between modules. For more precise details about any data structure or calling +convention, see the include files and comments in the source code. + +We assume that the reader is already somewhat familiar with the JPEG standard. +The README file includes references for learning about JPEG. The file +libjpeg.doc describes the library from the viewpoint of an application +programmer using the library; it's best to read that file before this one. +Also, the file coderules.doc describes the coding style conventions we use. + +In this document, JPEG-specific terminology follows the JPEG standard: + A "component" means a color channel, e.g., Red or Luminance. + A "sample" is a single component value (i.e., one number in the image data). + A "coefficient" is a frequency coefficient (a DCT transform output number). + A "block" is an 8x8 group of samples or coefficients. + A "data unit" is an abstract data type which is either a block for lossy + (DCT-based) codecs or a sample for lossless (predictive) codecs. + An "MCU" (minimum coded unit) is an interleaved set of data units of size + determined by the sampling factors, or a single data unit in a + noninterleaved scan. +We do not use the terms "pixel" and "sample" interchangeably. When we say +pixel, we mean an element of the full-size image, while a sample is an element +of the downsampled image. Thus the number of samples may vary across +components while the number of pixels does not. (This terminology is not used +rigorously throughout the code, but it is used in places where confusion would +otherwise result.) + + +*** System features *** + +The IJG distribution contains two parts: + * A subroutine library for JPEG compression and decompression. + * cjpeg/djpeg, two sample applications that use the library to transform + JFIF JPEG files to and from several other image formats. +cjpeg/djpeg are of no great intellectual complexity: they merely add a simple +command-line user interface and I/O routines for several uncompressed image +formats. This document concentrates on the library itself. + +We desire the library to be capable of supporting all JPEG baseline, extended +sequential, and progressive DCT processes, as well as the lossless (spatial) +process. Hierarchical processes are not supported. + +Within these limits, any set of compression parameters allowed by the JPEG +spec should be readable for decompression. (We can be more restrictive about +what formats we can generate.) Although the system design allows for all +parameter values, some uncommon settings are not yet implemented and may +never be; nonintegral sampling ratios are the prime example. Furthermore, +we treat 8-bit vs. 12-bit data precision as a compile-time switch, not a +run-time option, because most machines can store 8-bit pixels much more +compactly than 12-bit. + +For legal reasons, JPEG arithmetic coding is not currently supported, but +extending the library to include it would be straightforward. + +By itself, the library handles only interchange JPEG datastreams --- in +particular the widely used JFIF file format. The library can be used by +surrounding code to process interchange or abbreviated JPEG datastreams that +are embedded in more complex file formats. (For example, libtiff uses this +library to implement JPEG compression within the TIFF file format.) + +The library includes a substantial amount of code that is not covered by the +JPEG standard but is necessary for typical applications of JPEG. These +functions preprocess the image before JPEG compression or postprocess it after +decompression. They include colorspace conversion, downsampling/upsampling, +and color quantization. This code can be omitted if not needed. + +A wide range of quality vs. speed tradeoffs are possible in JPEG processing, +and even more so in decompression postprocessing. The decompression library +provides multiple implementations that cover most of the useful tradeoffs, +ranging from very-high-quality down to fast-preview operation. On the +compression side we have generally not provided low-quality choices, since +compression is normally less time-critical. It should be understood that the +low-quality modes may not meet the JPEG standard's accuracy requirements; +nonetheless, they are useful for viewers. + + +*** Portability issues *** + +Portability is an essential requirement for the library. The key portability +issues that show up at the level of system architecture are: + +1. Memory usage. We want the code to be able to run on PC-class machines +with limited memory. Images should therefore be processed sequentially (in +strips), to avoid holding the whole image in memory at once. Where a +full-image buffer is necessary, we should be able to use either virtual memory +or temporary files. + +2. Near/far pointer distinction. To run efficiently on 80x86 machines, the +code should distinguish "small" objects (kept in near data space) from +"large" ones (kept in far data space). This is an annoying restriction, but +fortunately it does not impact code quality for less brain-damaged machines, +and the source code clutter turns out to be minimal with sufficient use of +pointer typedefs. + +3. Data precision. We assume that "char" is at least 8 bits, "short" and +"int" at least 16, "long" at least 32. The code will work fine with larger +data sizes, although memory may be used inefficiently in some cases. However, +the JPEG compressed datastream must ultimately appear on external storage as a +sequence of 8-bit bytes if it is to conform to the standard. This may pose a +problem on machines where char is wider than 8 bits. The library represents +compressed data as an array of values of typedef JOCTET. If no data type +exactly 8 bits wide is available, custom data source and data destination +modules must be written to unpack and pack the chosen JOCTET datatype into +8-bit external representation. + + +*** System overview *** + +The compressor and decompressor are each divided into two main sections: +the JPEG compressor or decompressor proper, and the preprocessing or +postprocessing functions. The interface between these two sections is the +image data that the official JPEG spec regards as its input or output: this +data is in the colorspace to be used for compression, and it is downsampled +to the sampling factors to be used. The preprocessing and postprocessing +steps are responsible for converting a normal image representation to or from +this form. (Those few applications that want to deal with YCbCr downsampled +data can skip the preprocessing or postprocessing step.) + +Looking more closely, the compressor library contains the following main +elements: + + Preprocessing: + * Color space conversion (e.g., RGB to YCbCr). + * Edge expansion and downsampling. Optionally, this step can do simple + smoothing --- this is often helpful for low-quality source data. + Lossy JPEG proper: + * MCU assembly, DCT, quantization. + * Entropy coding (sequential or progressive, Huffman or arithmetic). + Lossless JPEG proper: + * Point transform. + * Prediction, differencing. + * Entropy coding (Huffman or arithmetic) + +In addition to these modules we need overall control, marker generation, +and support code (memory management & error handling). There is also a +module responsible for physically writing the output data --- typically +this is just an interface to fwrite(), but some applications may need to +do something else with the data. + +The decompressor library contains the following main elements: + + Lossy JPEG proper: + * Entropy decoding (sequential or progressive, Huffman or arithmetic). + * Dequantization, inverse DCT, MCU disassembly. + Lossless JPEG proper: + * Entropy decoding (Huffman or arithmetic). + * Prediction, undifferencing. + * Point transform, sample size scaling. + Postprocessing: + * Upsampling. Optionally, this step may be able to do more general + rescaling of the image. + * Color space conversion (e.g., YCbCr to RGB). This step may also + provide gamma adjustment [ currently it does not ]. + * Optional color quantization (e.g., reduction to 256 colors). + * Optional color precision reduction (e.g., 24-bit to 15-bit color). + [This feature is not currently implemented.] + +We also need overall control, marker parsing, and a data source module. +The support code (memory management & error handling) can be shared with +the compression half of the library. + +There may be several implementations of each of these elements, particularly +in the decompressor, where a wide range of speed/quality tradeoffs is very +useful. It must be understood that some of the best speedups involve +merging adjacent steps in the pipeline. For example, upsampling, color space +conversion, and color quantization might all be done at once when using a +low-quality ordered-dither technique. The system architecture is designed to +allow such merging where appropriate. + + +Note: it is convenient to regard edge expansion (padding to block boundaries) +as a preprocessing/postprocessing function, even though the JPEG spec includes +it in compression/decompression. We do this because downsampling/upsampling +can be simplified a little if they work on padded data: it's not necessary to +have special cases at the right and bottom edges. Therefore the interface +buffer is always an integral number of blocks wide and high, and we expect +compression preprocessing to pad the source data properly. Padding will occur +only to the next block (8-sample) boundary. In an interleaved-scan situation, +additional dummy blocks may be used to fill out MCUs, but the MCU assembly and +disassembly logic will create or discard these blocks internally. (This is +advantageous for speed reasons, since we avoid DCTing the dummy blocks. +It also permits a small reduction in file size, because the compressor can +choose dummy block contents so as to minimize their size in compressed form. +Finally, it makes the interface buffer specification independent of whether +the file is actually interleaved or not.) Applications that wish to deal +directly with the downsampled data must provide similar buffering and padding +for odd-sized images. + + +*** Poor man's object-oriented programming *** + +It should be clear by now that we have a lot of quasi-independent processing +steps, many of which have several possible behaviors. To avoid cluttering the +code with lots of switch statements, we use a simple form of object-style +programming to separate out the different possibilities. + +For example, two different color quantization algorithms could be implemented +as two separate modules that present the same external interface; at runtime, +the calling code will access the proper module indirectly through an "object". + +We can get the limited features we need while staying within portable C. +The basic tool is a function pointer. An "object" is just a struct +containing one or more function pointer fields, each of which corresponds to +a method name in real object-oriented languages. During initialization we +fill in the function pointers with references to whichever module we have +determined we need to use in this run. Then invocation of the module is done +by indirecting through a function pointer; on most machines this is no more +expensive than a switch statement, which would be the only other way of +making the required run-time choice. The really significant benefit, of +course, is keeping the source code clean and well structured. + +We can also arrange to have private storage that varies between different +implementations of the same kind of object. We do this by making all the +module-specific object structs be separately allocated entities, which will +be accessed via pointers in the master compression or decompression struct. +The "public" fields or methods for a given kind of object are specified by +a commonly known struct. But a module's initialization code can allocate +a larger struct that contains the common struct as its first member, plus +additional private fields. With appropriate pointer casting, the module's +internal functions can access these private fields. (For a simple example, +see jdatadst.c, which implements the external interface specified by struct +jpeg_destination_mgr, but adds extra fields.) + +(Of course this would all be a lot easier if we were using C++, but we are +not yet prepared to assume that everyone has a C++ compiler.) + +An important benefit of this scheme is that it is easy to provide multiple +versions of any method, each tuned to a particular case. While a lot of +precalculation might be done to select an optimal implementation of a method, +the cost per invocation is constant. For example, the upsampling step might +have a "generic" method, plus one or more "hardwired" methods for the most +popular sampling factors; the hardwired methods would be faster because they'd +use straight-line code instead of for-loops. The cost to determine which +method to use is paid only once, at startup, and the selection criteria are +hidden from the callers of the method. + +This plan differs a little bit from usual object-oriented structures, in that +only one instance of each object class will exist during execution. The +reason for having the class structure is that on different runs we may create +different instances (choose to execute different modules). You can think of +the term "method" as denoting the common interface presented by a particular +set of interchangeable functions, and "object" as denoting a group of related +methods, or the total shared interface behavior of a group of modules. + + +*** Overall control structure *** + +We previously mentioned the need for overall control logic in the compression +and decompression libraries. In IJG implementations prior to v5, overall +control was mostly provided by "pipeline control" modules, which proved to be +large, unwieldy, and hard to understand. To improve the situation, the +control logic has been subdivided into multiple modules. The control modules +consist of: + +1. Master control for module selection and initialization. This has two +responsibilities: + + 1A. Startup initialization at the beginning of image processing. + The individual processing modules to be used in this run are selected + and given initialization calls. + + 1B. Per-pass control. This determines how many passes will be performed + and calls each active processing module to configure itself + appropriately at the beginning of each pass. End-of-pass processing, + where necessary, is also invoked from the master control module. + + Method selection is partially distributed, in that a particular processing + module may contain several possible implementations of a particular method, + which it will select among when given its initialization call. The master + control code need only be concerned with decisions that affect more than + one module. + +2. Data buffering control. A separate control module exists for each + inter-processing-step data buffer. This module is responsible for + invoking the processing steps that write or read that data buffer. + +Each buffer controller sees the world as follows: + +input data => processing step A => buffer => processing step B => output data + | | | + ------------------ controller ------------------ + +The controller knows the dataflow requirements of steps A and B: how much data +they want to accept in one chunk and how much they output in one chunk. Its +function is to manage its buffer and call A and B at the proper times. + +A data buffer control module may itself be viewed as a processing step by a +higher-level control module; thus the control modules form a binary tree with +elementary processing steps at the leaves of the tree. + +The control modules are objects. A considerable amount of flexibility can +be had by replacing implementations of a control module. For example: +* Merging of adjacent steps in the pipeline is done by replacing a control + module and its pair of processing-step modules with a single processing- + step module. (Hence the possible merges are determined by the tree of + control modules.) +* In some processing modes, a given interstep buffer need only be a "strip" + buffer large enough to accommodate the desired data chunk sizes. In other + modes, a full-image buffer is needed and several passes are required. + The control module determines which kind of buffer is used and manipulates + virtual array buffers as needed. One or both processing steps may be + unaware of the multi-pass behavior. + +In theory, we might be able to make all of the data buffer controllers +interchangeable and provide just one set of implementations for all. In +practice, each one contains considerable special-case processing for its +particular job. The buffer controller concept should be regarded as an +overall system structuring principle, not as a complete description of the +task performed by any one controller. + + +*** Codec object structure *** + +As noted above, this library supports both the lossy (DCT-based) and lossless +JPEG processes. Because these processes have little in common with one another +(and their implementations share very little code), we need to provide a way to +isloate the underlying JPEG process from the rest of the library. This is +accomplished by introducing an abstract "codec object" which acts a generic +interface to the JPEG (de)compressor proper. + +Using the power of the object-oriented scheme described above, we build the +lossy and lossless modules as two separate implementations of the codec object. +Switching between lossy and lossless processes then becomes as trivial as +assigning the appropriate method pointers during initialization of the library. + + +*** Compression object structure *** + +Here is a sketch of the logical structure of the JPEG compression library: + + |-- Colorspace conversion + |-- Preprocessing controller --| + | |-- Downsampling + | +Main controller --| + | /--> Lossy codec + | / + |-- Compression codec < *OR* + \ + \--> Lossless codec + + +where the lossy codec looks like: + + |-- Forward DCT, quantize +<-- Coefficient controller --| + |-- Entropy encoding + + +and the lossless codec looks like: + + |-- Point transformation + | +<-- Difference controller --|-- Prediction, differencing + | + |-- Lossless entropy encoding + + +This sketch also describes the flow of control (subroutine calls) during +typical image data processing. Each of the components shown in the diagram is +an "object" which may have several different implementations available. One +or more source code files contain the actual implementation(s) of each object. + +The objects shown above are: + +* Main controller: buffer controller for the subsampled-data buffer, which + holds the preprocessed input data. This controller invokes preprocessing to + fill the subsampled-data buffer, and JPEG compression to empty it. There is + usually no need for a full-image buffer here; a strip buffer is adequate. + +* Preprocessing controller: buffer controller for the downsampling input data + buffer, which lies between colorspace conversion and downsampling. Note + that a unified conversion/downsampling module would probably replace this + controller entirely. + +* Colorspace conversion: converts application image data into the desired + JPEG color space; also changes the data from pixel-interleaved layout to + separate component planes. Processes one pixel row at a time. + +* Downsampling: performs reduction of chroma components as required. + Optionally may perform pixel-level smoothing as well. Processes a "row + group" at a time, where a row group is defined as Vmax pixel rows of each + component before downsampling, and Vk sample rows afterwards (remember Vk + differs across components). Some downsampling or smoothing algorithms may + require context rows above and below the current row group; the + preprocessing controller is responsible for supplying these rows via proper + buffering. The downsampler is responsible for edge expansion at the right + edge (i.e., extending each sample row to a multiple of 8 samples); but the + preprocessing controller is responsible for vertical edge expansion (i.e., + duplicating the bottom sample row as needed to make a multiple of 8 rows). + +* Coefficient controller: buffer controller for the DCT-coefficient data. + This controller handles MCU assembly, including insertion of dummy DCT + blocks when needed at the right or bottom edge. When performing + Huffman-code optimization or emitting a multiscan JPEG file, this + controller is responsible for buffering the full image. The equivalent of + one fully interleaved MCU row of subsampled data is processed per call, + even when the JPEG file is noninterleaved. + +* Forward DCT and quantization: Perform DCT, quantize, and emit coefficients. + Works on one or more DCT blocks at a time. (Note: the coefficients are now + emitted in normal array order, which the entropy encoder is expected to + convert to zigzag order as necessary. Prior versions of the IJG code did + the conversion to zigzag order within the quantization step.) + +* Entropy encoding: Perform Huffman or arithmetic entropy coding and emit the + coded data to the data destination module. Works on one MCU per call. + For progressive JPEG, the same DCT blocks are fed to the entropy coder + during each pass, and the coder must emit the appropriate subset of + coefficients. + +* Difference controller: buffer controller for the spatial difference data. + When emitting a multiscan JPEG file, this controller is responsible for + buffering the full image. The equivalent of one fully interleaved MCU row + of subsampled data is processed per call, even when the JPEG file is + noninterleaved. + +* Point transformation: Scale the data down by the point transformation + parameter. + +* Prediction and differencing: Calculate the predictor and subtract it + from the input. Works on one scanline per call. The difference + controller supplies the prior scanline which is used for prediction. + +* Lossless entropy encoding: Perform Huffman or arithmetic entropy coding and + emit the coded data to the data destination module. This module handles MCU + assembly. Works on one MCU-row per call. + +In addition to the above objects, the compression library includes these +objects: + +* Master control: determines the number of passes required, controls overall + and per-pass initialization of the other modules. + +* Marker writing: generates JPEG markers (except for RSTn, which is emitted + by the entropy encoder when needed). + +* Data destination manager: writes the output JPEG datastream to its final + destination (e.g., a file). The destination manager supplied with the + library knows how to write to a stdio stream; for other behaviors, the + surrounding application may provide its own destination manager. + +* Memory manager: allocates and releases memory, controls virtual arrays + (with backing store management, where required). + +* Error handler: performs formatting and output of error and trace messages; + determines handling of nonfatal errors. The surrounding application may + override some or all of this object's methods to change error handling. + +* Progress monitor: supports output of "percent-done" progress reports. + This object represents an optional callback to the surrounding application: + if wanted, it must be supplied by the application. + +The error handler, destination manager, and progress monitor objects are +defined as separate objects in order to simplify application-specific +customization of the JPEG library. A surrounding application may override +individual methods or supply its own all-new implementation of one of these +objects. The object interfaces for these objects are therefore treated as +part of the application interface of the library, whereas the other objects +are internal to the library. + +The error handler and memory manager are shared by JPEG compression and +decompression; the progress monitor, if used, may be shared as well. + + +*** Decompression object structure *** + +Here is a sketch of the logical structure of the JPEG decompression library: + + /--> Lossy codec + / + |-- Decompression codec < *OR* + | \ + | \--> Lossless codec +Main controller --| + | + | |-- Upsampling + |-- Postprocessing controller --| |-- Colorspace conversion + |-- Color quantization + |-- Color precision reduction + + +where the lossy codec looks like: + + |-- Entropy decoding +<-- Coefficient controller --| + |-- Dequantize, Inverse DCT + + +and the lossless codec looks like: + + |-- Lossless entropy decoding + | +<-- Difference controller --|-- Prediction, undifferencing + | + |-- Point transformation, sample size scaling + + +As before, this diagram also represents typical control flow. The objects +shown are: + +* Main controller: buffer controller for the subsampled-data buffer, which + holds the output of JPEG decompression proper. This controller's primary + task is to feed the postprocessing procedure. Some upsampling algorithms + may require context rows above and below the current row group; when this + is true, the main controller is responsible for managing its buffer so as + to make context rows available. In the current design, the main buffer is + always a strip buffer; a full-image buffer is never required. + +* Coefficient controller: buffer controller for the DCT-coefficient data. + This controller handles MCU disassembly, including deletion of any dummy + DCT blocks at the right or bottom edge. When reading a multiscan JPEG + file, this controller is responsible for buffering the full image. + (Buffering DCT coefficients, rather than samples, is necessary to support + progressive JPEG.) The equivalent of one fully interleaved MCU row of + subsampled data is processed per call, even when the source JPEG file is + noninterleaved. + +* Entropy decoding: Read coded data from the data source module and perform + Huffman or arithmetic entropy decoding. Works on one MCU per call. + For progressive JPEG decoding, the coefficient controller supplies the prior + coefficients of each MCU (initially all zeroes), which the entropy decoder + modifies in each scan. + +* Dequantization and inverse DCT: like it says. Note that the coefficients + buffered by the coefficient controller have NOT been dequantized; we + merge dequantization and inverse DCT into a single step for speed reasons. + When scaled-down output is asked for, simplified DCT algorithms may be used + that emit only 1x1, 2x2, or 4x4 samples per DCT block, not the full 8x8. + Works on one DCT block at a time. + +* Difference controller: buffer controller for the spatial difference data. + When reading a multiscan JPEG file, this controller is responsible for + buffering the full image. The equivalent of one fully interleaved MCU row + is processed per call, even when the source JPEG file is noninterleaved. + +* Lossless entropy decoding: Read coded data from the data source module and + perform Huffman or arithmetic entropy decoding. Works on one MCU-row per + call. + +* Prediction and undifferencing: Calculate the predictor and add it to the + decoded difference. Works on one scanline per call. The difference + controller supplies the prior scanline which is used for prediction. + +* Point transform and sample size scaling: Scale the data up by the point + transformation parameter and scale it down to fit into the compiled-in + sample size. + +* Postprocessing controller: buffer controller for the color quantization + input buffer, when quantization is in use. (Without quantization, this + controller just calls the upsampler.) For two-pass quantization, this + controller is responsible for buffering the full-image data. + +* Upsampling: restores chroma components to full size. (May support more + general output rescaling, too. Note that if undersized DCT outputs have + been emitted by the DCT module, this module must adjust so that properly + sized outputs are created.) Works on one row group at a time. This module + also calls the color conversion module, so its top level is effectively a + buffer controller for the upsampling->color conversion buffer. However, in + all but the highest-quality operating modes, upsampling and color + conversion are likely to be merged into a single step. + +* Colorspace conversion: convert from JPEG color space to output color space, + and change data layout from separate component planes to pixel-interleaved. + Works on one pixel row at a time. + +* Color quantization: reduce the data to colormapped form, using either an + externally specified colormap or an internally generated one. This module + is not used for full-color output. Works on one pixel row at a time; may + require two passes to generate a color map. Note that the output will + always be a single component representing colormap indexes. In the current + design, the output values are JSAMPLEs, so an 8-bit compilation cannot + quantize to more than 256 colors. This is unlikely to be a problem in + practice. + +* Color reduction: this module handles color precision reduction, e.g., + generating 15-bit color (5 bits/primary) from JPEG's 24-bit output. + Not quite clear yet how this should be handled... should we merge it with + colorspace conversion??? + +Note that some high-speed operating modes might condense the entire +postprocessing sequence to a single module (upsample, color convert, and +quantize in one step). + +In addition to the above objects, the decompression library includes these +objects: + +* Master control: determines the number of passes required, controls overall + and per-pass initialization of the other modules. This is subdivided into + input and output control: jdinput.c controls only input-side processing, + while jdmaster.c handles overall initialization and output-side control. + +* Marker reading: decodes JPEG markers (except for RSTn). + +* Data source manager: supplies the input JPEG datastream. The source + manager supplied with the library knows how to read from a stdio stream; + for other behaviors, the surrounding application may provide its own source + manager. + +* Memory manager: same as for compression library. + +* Error handler: same as for compression library. + +* Progress monitor: same as for compression library. + +As with compression, the data source manager, error handler, and progress +monitor are candidates for replacement by a surrounding application. + + +*** Decompression input and output separation *** + +To support efficient incremental display of progressive JPEG files, the +decompressor is divided into two sections that can run independently: + +1. Data input includes marker parsing, entropy decoding, and input into the + coefficient controller's DCT coefficient buffer. Note that this + processing is relatively cheap and fast. + +2. Data output reads from the DCT coefficient buffer and performs the IDCT + and all postprocessing steps. + +For a progressive JPEG file, the data input processing is allowed to get +arbitrarily far ahead of the data output processing. (This occurs only +if the application calls jpeg_consume_input(); otherwise input and output +run in lockstep, since the input section is called only when the output +section needs more data.) In this way the application can avoid making +extra display passes when data is arriving faster than the display pass +can run. Furthermore, it is possible to abort an output pass without +losing anything, since the coefficient buffer is read-only as far as the +output section is concerned. See libjpeg.doc for more detail. + +A full-image coefficient array is only created if the JPEG file has multiple +scans (or if the application specifies buffered-image mode anyway). When +reading a single-scan file, the coefficient controller normally creates only +a one-MCU buffer, so input and output processing must run in lockstep in this +case. jpeg_consume_input() is effectively a no-op in this situation. + +The main impact of dividing the decompressor in this fashion is that we must +be very careful with shared variables in the cinfo data structure. Each +variable that can change during the course of decompression must be +classified as belonging to data input or data output, and each section must +look only at its own variables. For example, the data output section may not +depend on any of the variables that describe the current scan in the JPEG +file, because these may change as the data input section advances into a new +scan. + +The progress monitor is (somewhat arbitrarily) defined to treat input of the +file as one pass when buffered-image mode is not used, and to ignore data +input work completely when buffered-image mode is used. Note that the +library has no reliable way to predict the number of passes when dealing +with a progressive JPEG file, nor can it predict the number of output passes +in buffered-image mode. So the work estimate is inherently bogus anyway. + +No comparable division is currently made in the compression library, because +there isn't any real need for it. + + +*** Data formats *** + +Arrays of pixel sample values use the following data structure: + + typedef something JSAMPLE; a pixel component value, 0..MAXJSAMPLE + typedef JSAMPLE *JSAMPROW; ptr to a row of samples + typedef JSAMPROW *JSAMPARRAY; ptr to a list of rows + typedef JSAMPARRAY *JSAMPIMAGE; ptr to a list of color-component arrays + +The basic element type JSAMPLE will typically be one of unsigned char, +(signed) char, or short. Short will be used if samples wider than 8 bits are +to be supported (this is a compile-time option). Otherwise, unsigned char is +used if possible. If the compiler only supports signed chars, then it is +necessary to mask off the value when reading. Thus, all reads of JSAMPLE +values must be coded as "GETJSAMPLE(value)", where the macro will be defined +as "((value) & 0xFF)" on signed-char machines and "((int) (value))" elsewhere. + +With these conventions, JSAMPLE values can be assumed to be >= 0. This helps +simplify correct rounding during downsampling, etc. The JPEG standard's +specification that sample values run from -128..127 is accommodated by +subtracting 128 just as the sample value is copied into the source array for +the DCT step (this will be an array of signed ints). Similarly, during +decompression the output of the IDCT step will be immediately shifted back to +0..255. (NB: different values are required when 12-bit samples are in use. +The code is written in terms of MAXJSAMPLE and CENTERJSAMPLE, which will be +defined as 255 and 128 respectively in an 8-bit implementation, and as 4095 +and 2048 in a 12-bit implementation.) + +We use a pointer per row, rather than a two-dimensional JSAMPLE array. This +choice costs only a small amount of memory and has several benefits: +* Code using the data structure doesn't need to know the allocated width of + the rows. This simplifies edge expansion/compression, since we can work + in an array that's wider than the logical picture width. +* Indexing doesn't require multiplication; this is a performance win on many + machines. +* Arrays with more than 64K total elements can be supported even on machines + where malloc() cannot allocate chunks larger than 64K. +* The rows forming a component array may be allocated at different times + without extra copying. This trick allows some speedups in smoothing steps + that need access to the previous and next rows. + +Note that each color component is stored in a separate array; we don't use the +traditional layout in which the components of a pixel are stored together. +This simplifies coding of modules that work on each component independently, +because they don't need to know how many components there are. Furthermore, +we can read or write each component to a temporary file independently, which +is helpful when dealing with noninterleaved JPEG files. + +In general, a specific sample value is accessed by code such as + GETJSAMPLE(image[colorcomponent][row][col]) +where col is measured from the image left edge, but row is measured from the +first sample row currently in memory. Either of the first two indexings can +be precomputed by copying the relevant pointer. + + +Since most image-processing applications prefer to work on images in which +the components of a pixel are stored together, the data passed to or from the +surrounding application uses the traditional convention: a single pixel is +represented by N consecutive JSAMPLE values, and an image row is an array of +(# of color components)*(image width) JSAMPLEs. One or more rows of data can +be represented by a pointer of type JSAMPARRAY in this scheme. This scheme is +converted to component-wise storage inside the JPEG library. (Applications +that want to skip JPEG preprocessing or postprocessing will have to contend +with component-wise storage.) + + +Arrays of DCT-coefficient values use the following data structure: + + typedef short JCOEF; a 16-bit signed integer + typedef JCOEF JBLOCK[DCTSIZE2]; an 8x8 block of coefficients + typedef JBLOCK *JBLOCKROW; ptr to one horizontal row of 8x8 blocks + typedef JBLOCKROW *JBLOCKARRAY; ptr to a list of such rows + typedef JBLOCKARRAY *JBLOCKIMAGE; ptr to a list of color component arrays + +The underlying type is at least a 16-bit signed integer; while "short" is big +enough on all machines of interest, on some machines it is preferable to use +"int" for speed reasons, despite the storage cost. Coefficients are grouped +into 8x8 blocks (but we always use #defines DCTSIZE and DCTSIZE2 rather than +"8" and "64"). + +The contents of a coefficient block may be in either "natural" or zigzagged +order, and may be true values or divided by the quantization coefficients, +depending on where the block is in the processing pipeline. In the current +library, coefficient blocks are kept in natural order everywhere; the entropy +codecs zigzag or dezigzag the data as it is written or read. The blocks +contain quantized coefficients everywhere outside the DCT/IDCT subsystems. +(This latter decision may need to be revisited to support variable +quantization a la JPEG Part 3.) + +Notice that the allocation unit is now a row of 8x8 blocks, corresponding to +eight rows of samples. Otherwise the structure is much the same as for +samples, and for the same reasons. + +On machines where malloc() can't handle a request bigger than 64Kb, this data +structure limits us to rows of less than 512 JBLOCKs, or a picture width of +4000+ pixels. This seems an acceptable restriction. + + +On 80x86 machines, the bottom-level pointer types (JSAMPROW and JBLOCKROW) +must be declared as "far" pointers, but the upper levels can be "near" +(implying that the pointer lists are allocated in the DS segment). +We use a #define symbol FAR, which expands to the "far" keyword when +compiling on 80x86 machines and to nothing elsewhere. + + +*** Suspendable processing *** + +In some applications it is desirable to use the JPEG library as an +incremental, memory-to-memory filter. In this situation the data source or +destination may be a limited-size buffer, and we can't rely on being able to +empty or refill the buffer at arbitrary times. Instead the application would +like to have control return from the library at buffer overflow/underrun, and +then resume compression or decompression at a later time. + +This scenario is supported for simple cases. (For anything more complex, we +recommend that the application "bite the bullet" and develop real multitasking +capability.) The libjpeg.doc file goes into more detail about the usage and +limitations of this capability; here we address the implications for library +structure. + +The essence of the problem is that the entropy codec (coder or decoder) must +be prepared to stop at arbitrary times. In turn, the controllers that call +the entropy codec must be able to stop before having produced or consumed all +the data that they normally would handle in one call. That part is reasonably +straightforward: we make the controller call interfaces include "progress +counters" which indicate the number of data chunks successfully processed, and +we require callers to test the counter rather than just assume all of the data +was processed. + +Rather than trying to restart at an arbitrary point, the current Huffman +codecs are designed to restart at the beginning of the current MCU after a +suspension due to buffer overflow/underrun. At the start of each call, the +codec's internal state is loaded from permanent storage (in the JPEG object +structures) into local variables. On successful completion of the MCU, the +permanent state is updated. (This copying is not very expensive, and may even +lead to *improved* performance if the local variables can be registerized.) +If a suspension occurs, the codec simply returns without updating the state, +thus effectively reverting to the start of the MCU. Note that this implies +leaving some data unprocessed in the source/destination buffer (ie, the +compressed partial MCU). The data source/destination module interfaces are +specified so as to make this possible. This also implies that the data buffer +must be large enough to hold a worst-case compressed MCU; a couple thousand +bytes should be enough. + +In a successive-approximation AC refinement scan, the progressive Huffman +decoder has to be able to undo assignments of newly nonzero coefficients if it +suspends before the MCU is complete, since decoding requires distinguishing +previously-zero and previously-nonzero coefficients. This is a bit tedious +but probably won't have much effect on performance. Other variants of Huffman +decoding need not worry about this, since they will just store the same values +again if forced to repeat the MCU. + +This approach would probably not work for an arithmetic codec, since its +modifiable state is quite large and couldn't be copied cheaply. Instead it +would have to suspend and resume exactly at the point of the buffer end. + +The JPEG marker reader is designed to cope with suspension at an arbitrary +point. It does so by backing up to the start of the marker parameter segment, +so the data buffer must be big enough to hold the largest marker of interest. +Again, a couple KB should be adequate. (A special "skip" convention is used +to bypass COM and APPn markers, so these can be larger than the buffer size +without causing problems; otherwise a 64K buffer would be needed in the worst +case.) + +The JPEG marker writer currently does *not* cope with suspension. I feel that +this is not necessary; it is much easier simply to require the application to +ensure there is enough buffer space before starting. (An empty 2K buffer is +more than sufficient for the header markers; and ensuring there are a dozen or +two bytes available before calling jpeg_finish_compress() will suffice for the +trailer.) This would not work for writing multi-scan JPEG files, but +we simply do not intend to support that capability with suspension. + + +*** Memory manager services *** + +The JPEG library's memory manager controls allocation and deallocation of +memory, and it manages large "virtual" data arrays on machines where the +operating system does not provide virtual memory. Note that the same +memory manager serves both compression and decompression operations. + +In all cases, allocated objects are tied to a particular compression or +decompression master record, and they will be released when that master +record is destroyed. + +The memory manager does not provide explicit deallocation of objects. +Instead, objects are created in "pools" of free storage, and a whole pool +can be freed at once. This approach helps prevent storage-leak bugs, and +it speeds up operations whenever malloc/free are slow (as they often are). +The pools can be regarded as lifetime identifiers for objects. Two +pools/lifetimes are defined: + * JPOOL_PERMANENT lasts until master record is destroyed + * JPOOL_IMAGE lasts until done with image (JPEG datastream) +Permanent lifetime is used for parameters and tables that should be carried +across from one datastream to another; this includes all application-visible +parameters. Image lifetime is used for everything else. (A third lifetime, +JPOOL_PASS = one processing pass, was originally planned. However it was +dropped as not being worthwhile. The actual usage patterns are such that the +peak memory usage would be about the same anyway; and having per-pass storage +substantially complicates the virtual memory allocation rules --- see below.) + +The memory manager deals with three kinds of object: +1. "Small" objects. Typically these require no more than 10K-20K total. +2. "Large" objects. These may require tens to hundreds of K depending on + image size. Semantically they behave the same as small objects, but we + distinguish them for two reasons: + * On MS-DOS machines, large objects are referenced by FAR pointers, + small objects by NEAR pointers. + * Pool allocation heuristics may differ for large and small objects. + Note that individual "large" objects cannot exceed the size allowed by + type size_t, which may be 64K or less on some machines. +3. "Virtual" objects. These are large 2-D arrays of JSAMPLEs or JBLOCKs + (typically large enough for the entire image being processed). The + memory manager provides stripwise access to these arrays. On machines + without virtual memory, the rest of the array may be swapped out to a + temporary file. + +(Note: JSAMPARRAY and JBLOCKARRAY data structures are a combination of large +objects for the data proper and small objects for the row pointers. For +convenience and speed, the memory manager provides single routines to create +these structures. Similarly, virtual arrays include a small control block +and a JSAMPARRAY or JBLOCKARRAY working buffer, all created with one call.) + +In the present implementation, virtual arrays are only permitted to have image +lifespan. (Permanent lifespan would not be reasonable, and pass lifespan is +not very useful since a virtual array's raison d'etre is to store data for +multiple passes through the image.) We also expect that only "small" objects +will be given permanent lifespan, though this restriction is not required by +the memory manager. + +In a non-virtual-memory machine, some performance benefit can be gained by +making the in-memory buffers for virtual arrays be as large as possible. +(For small images, the buffers might fit entirely in memory, so blind +swapping would be very wasteful.) The memory manager will adjust the height +of the buffers to fit within a prespecified maximum memory usage. In order +to do this in a reasonably optimal fashion, the manager needs to allocate all +of the virtual arrays at once. Therefore, there isn't a one-step allocation +routine for virtual arrays; instead, there is a "request" routine that simply +allocates the control block, and a "realize" routine (called just once) that +determines space allocation and creates all of the actual buffers. The +realize routine must allow for space occupied by non-virtual large objects. +(We don't bother to factor in the space needed for small objects, on the +grounds that it isn't worth the trouble.) + +To support all this, we establish the following protocol for doing business +with the memory manager: + 1. Modules must request virtual arrays (which may have only image lifespan) + during the initial setup phase, i.e., in their jinit_xxx routines. + 2. All "large" objects (including JSAMPARRAYs and JBLOCKARRAYs) must also be + allocated during initial setup. + 3. realize_virt_arrays will be called at the completion of initial setup. + The above conventions ensure that sufficient information is available + for it to choose a good size for virtual array buffers. +Small objects of any lifespan may be allocated at any time. We expect that +the total space used for small objects will be small enough to be negligible +in the realize_virt_arrays computation. + +In a virtual-memory machine, we simply pretend that the available space is +infinite, thus causing realize_virt_arrays to decide that it can allocate all +the virtual arrays as full-size in-memory buffers. The overhead of the +virtual-array access protocol is very small when no swapping occurs. + +A virtual array can be specified to be "pre-zeroed"; when this flag is set, +never-yet-written sections of the array are set to zero before being made +available to the caller. If this flag is not set, never-written sections +of the array contain garbage. (This feature exists primarily because the +equivalent logic would otherwise be needed in jdcoefct.c for progressive +JPEG mode; we may as well make it available for possible other uses.) + +The first write pass on a virtual array is required to occur in top-to-bottom +order; read passes, as well as any write passes after the first one, may +access the array in any order. This restriction exists partly to simplify +the virtual array control logic, and partly because some file systems may not +support seeking beyond the current end-of-file in a temporary file. The main +implication of this restriction is that rearrangement of rows (such as +converting top-to-bottom data order to bottom-to-top) must be handled while +reading data out of the virtual array, not while putting it in. + + +*** Memory manager internal structure *** + +To isolate system dependencies as much as possible, we have broken the +memory manager into two parts. There is a reasonably system-independent +"front end" (jmemmgr.c) and a "back end" that contains only the code +likely to change across systems. All of the memory management methods +outlined above are implemented by the front end. The back end provides +the following routines for use by the front end (none of these routines +are known to the rest of the JPEG code): + +jpeg_mem_init, jpeg_mem_term system-dependent initialization/shutdown + +jpeg_get_small, jpeg_free_small interface to malloc and free library routines + (or their equivalents) + +jpeg_get_large, jpeg_free_large interface to FAR malloc/free in MSDOS machines; + else usually the same as + jpeg_get_small/jpeg_free_small + +jpeg_mem_available estimate available memory + +jpeg_open_backing_store create a backing-store object + +read_backing_store, manipulate a backing-store object +write_backing_store, +close_backing_store + +On some systems there will be more than one type of backing-store object +(specifically, in MS-DOS a backing store file might be an area of extended +memory as well as a disk file). jpeg_open_backing_store is responsible for +choosing how to implement a given object. The read/write/close routines +are method pointers in the structure that describes a given object; this +lets them be different for different object types. + +It may be necessary to ensure that backing store objects are explicitly +released upon abnormal program termination. For example, MS-DOS won't free +extended memory by itself. To support this, we will expect the main program +or surrounding application to arrange to call self_destruct (typically via +jpeg_destroy) upon abnormal termination. This may require a SIGINT signal +handler or equivalent. We don't want to have the back end module install its +own signal handler, because that would pre-empt the surrounding application's +ability to control signal handling. + +The IJG distribution includes several memory manager back end implementations. +Usually the same back end should be suitable for all applications on a given +system, but it is possible for an application to supply its own back end at +need. + + +*** Implications of DNL marker *** + +Some JPEG files may use a DNL marker to postpone definition of the image +height (this would be useful for a fax-like scanner's output, for instance). +In these files the SOF marker claims the image height is 0, and you only +find out the true image height at the end of the first scan. + +We could read these files as follows: +1. Upon seeing zero image height, replace it by 65535 (the maximum allowed). +2. When the DNL is found, update the image height in the global image + descriptor. +This implies that control modules must avoid making copies of the image +height, and must re-test for termination after each MCU row. This would +be easy enough to do. + +In cases where image-size data structures are allocated, this approach will +result in very inefficient use of virtual memory or much-larger-than-necessary +temporary files. This seems acceptable for something that probably won't be a +mainstream usage. People might have to forgo use of memory-hogging options +(such as two-pass color quantization or noninterleaved JPEG files) if they +want efficient conversion of such files. (One could improve efficiency by +demanding a user-supplied upper bound for the height, less than 65536; in most +cases it could be much less.) + +The standard also permits the SOF marker to overestimate the image height, +with a DNL to give the true, smaller height at the end of the first scan. +This would solve the space problems if the overestimate wasn't too great. +However, it implies that you don't even know whether DNL will be used. + +This leads to a couple of very serious objections: +1. Testing for a DNL marker must occur in the inner loop of the decompressor's + Huffman decoder; this implies a speed penalty whether the feature is used + or not. +2. There is no way to hide the last-minute change in image height from an + application using the decoder. Thus *every* application using the IJG + library would suffer a complexity penalty whether it cared about DNL or + not. +We currently do not support DNL because of these problems. + +A different approach is to insist that DNL-using files be preprocessed by a +separate program that reads ahead to the DNL, then goes back and fixes the SOF +marker. This is a much simpler solution and is probably far more efficient. +Even if one wants piped input, buffering the first scan of the JPEG file needs +a lot smaller temp file than is implied by the maximum-height method. For +this approach we'd simply treat DNL as a no-op in the decompressor (at most, +check that it matches the SOF image height). + +We will not worry about making the compressor capable of outputting DNL. +Something similar to the first scheme above could be applied if anyone ever +wants to make that work. diff --git a/gdcm/Utilities/gdcmjpeg/usage.doc b/gdcm/Utilities/gdcmjpeg/usage.doc new file mode 100644 index 0000000..3d7da74 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/usage.doc @@ -0,0 +1,562 @@ +USAGE instructions for the Independent JPEG Group's JPEG software +================================================================= + +This file describes usage of the JPEG conversion programs cjpeg and djpeg, +as well as the utility programs jpegtran, rdjpgcom and wrjpgcom. (See +the other documentation files if you wish to use the JPEG library within +your own programs.) + +If you are on a Unix machine you may prefer to read the Unix-style manual +pages in files cjpeg.1, djpeg.1, jpegtran.1, rdjpgcom.1, wrjpgcom.1. + + +INTRODUCTION + +These programs implement JPEG image compression and decompression. JPEG +(pronounced "jay-peg") is a standardized compression method for full-color +and gray-scale images. JPEG is designed to handle "real-world" scenes, +for example scanned photographs. Cartoons, line drawings, and other +non-realistic images are not JPEG's strong suit; on that sort of material +you may get poor image quality and/or little compression. + +JPEG is lossy, meaning that the output image is not necessarily identical to +the input image. Hence you should not use JPEG if you have to have identical +output bits. However, on typical real-world images, very good compression +levels can be obtained with no visible change, and amazingly high compression +is possible if you can tolerate a low-quality image. You can trade off image +quality against file size by adjusting the compressor's "quality" setting. + + +GENERAL USAGE + +We provide two programs, cjpeg to compress an image file into JPEG format, +and djpeg to decompress a JPEG file back into a conventional image format. + +On Unix-like systems, you say: + cjpeg [switches] [imagefile] >jpegfile +or + djpeg [switches] [jpegfile] >imagefile +The programs read the specified input file, or standard input if none is +named. They always write to standard output (with trace/error messages to +standard error). These conventions are handy for piping images between +programs. + +On most non-Unix systems, you say: + cjpeg [switches] imagefile jpegfile +or + djpeg [switches] jpegfile imagefile +i.e., both the input and output files are named on the command line. This +style is a little more foolproof, and it loses no functionality if you don't +have pipes. (You can get this style on Unix too, if you prefer, by defining +TWO_FILE_COMMANDLINE when you compile the programs; see install.doc.) + +You can also say: + cjpeg [switches] -outfile jpegfile imagefile +or + djpeg [switches] -outfile imagefile jpegfile +This syntax works on all systems, so it is useful for scripts. + +The currently supported image file formats are: PPM (PBMPLUS color format), +PGM (PBMPLUS gray-scale format), BMP, Targa, and RLE (Utah Raster Toolkit +format). (RLE is supported only if the URT library is available.) +cjpeg recognizes the input image format automatically, with the exception +of some Targa-format files. You have to tell djpeg which format to generate. + +JPEG files are in the defacto standard JFIF file format. There are other, +less widely used JPEG-based file formats, but we don't support them. + +All switch names may be abbreviated; for example, -grayscale may be written +-gray or -gr. Most of the "basic" switches can be abbreviated to as little as +one letter. Upper and lower case are equivalent (-BMP is the same as -bmp). +British spellings are also accepted (e.g., -greyscale), though for brevity +these are not mentioned below. + + +CJPEG DETAILS + +The basic command line switches for cjpeg are: + + -quality N Scale quantization tables to adjust image quality. + Quality is 0 (worst) to 100 (best); default is 75. + (See below for more info.) + + -grayscale Create monochrome JPEG file from color input. + Be sure to use this switch when compressing a grayscale + BMP file, because cjpeg isn't bright enough to notice + whether a BMP file uses only shades of gray. By + saying -grayscale, you'll get a smaller JPEG file that + takes less time to process. + + -optimize Perform optimization of entropy encoding parameters. + Without this, default encoding parameters are used. + -optimize usually makes the JPEG file a little smaller, + but cjpeg runs somewhat slower and needs much more + memory. Image quality and speed of decompression are + unaffected by -optimize. + + -progressive Create progressive JPEG file (see below). + + -targa Input file is Targa format. Targa files that contain + an "identification" field will not be automatically + recognized by cjpeg; for such files you must specify + -targa to make cjpeg treat the input as Targa format. + For most Targa files, you won't need this switch. + +The -quality switch lets you trade off compressed file size against quality of +the reconstructed image: the higher the quality setting, the larger the JPEG +file, and the closer the output image will be to the original input. Normally +you want to use the lowest quality setting (smallest file) that decompresses +into something visually indistinguishable from the original image. For this +purpose the quality setting should be between 50 and 95; the default of 75 is +often about right. If you see defects at -quality 75, then go up 5 or 10 +counts at a time until you are happy with the output image. (The optimal +setting will vary from one image to another.) + +-quality 100 will generate a quantization table of all 1's, minimizing loss +in the quantization step (but there is still information loss in subsampling, +as well as roundoff error). This setting is mainly of interest for +experimental purposes. Quality values above about 95 are NOT recommended for +normal use; the compressed file size goes up dramatically for hardly any gain +in output image quality. + +In the other direction, quality values below 50 will produce very small files +of low image quality. Settings around 5 to 10 might be useful in preparing an +index of a large image library, for example. Try -quality 2 (or so) for some +amusing Cubist effects. (Note: quality values below about 25 generate 2-byte +quantization tables, which are considered optional in the JPEG standard. +cjpeg emits a warning message when you give such a quality value, because some +other JPEG programs may be unable to decode the resulting file. Use -baseline +if you need to ensure compatibility at low quality values.) + +The -progressive switch creates a "progressive JPEG" file. In this type of +JPEG file, the data is stored in multiple scans of increasing quality. If the +file is being transmitted over a slow communications link, the decoder can use +the first scan to display a low-quality image very quickly, and can then +improve the display with each subsequent scan. The final image is exactly +equivalent to a standard JPEG file of the same quality setting, and the total +file size is about the same --- often a little smaller. CAUTION: progressive +JPEG is not yet widely implemented, so many decoders will be unable to view a +progressive JPEG file at all. + +Switches for advanced users: + + -dct int Use integer DCT method (default). + -dct fast Use fast integer DCT (less accurate). + -dct float Use floating-point DCT method. + The float method is very slightly more accurate than + the int method, but is much slower unless your machine + has very fast floating-point hardware. Also note that + results of the floating-point method may vary slightly + across machines, while the integer methods should give + the same results everywhere. The fast integer method + is much less accurate than the other two. + + -restart N Emit a JPEG restart marker every N MCU rows, or every + N MCU blocks if "B" is attached to the number. + -restart 0 (the default) means no restart markers. + + -smooth N Smooth the input image to eliminate dithering noise. + N, ranging from 1 to 100, indicates the strength of + smoothing. 0 (the default) means no smoothing. + + -maxmemory N Set limit for amount of memory to use in processing + large images. Value is in thousands of bytes, or + millions of bytes if "M" is attached to the number. + For example, -max 4m selects 4000000 bytes. If more + space is needed, temporary files will be used. + + -verbose Enable debug printout. More -v's give more printout. + or -debug Also, version information is printed at startup. + +The -restart option inserts extra markers that allow a JPEG decoder to +resynchronize after a transmission error. Without restart markers, any damage +to a compressed file will usually ruin the image from the point of the error +to the end of the image; with restart markers, the damage is usually confined +to the portion of the image up to the next restart marker. Of course, the +restart markers occupy extra space. We recommend -restart 1 for images that +will be transmitted across unreliable networks such as Usenet. + +The -smooth option filters the input to eliminate fine-scale noise. This is +often useful when converting dithered images to JPEG: a moderate smoothing +factor of 10 to 50 gets rid of dithering patterns in the input file, resulting +in a smaller JPEG file and a better-looking image. Too large a smoothing +factor will visibly blur the image, however. + +Switches for wizards: + + -baseline Force baseline-compatible quantization tables to be + generated. This clamps quantization values to 8 bits + even at low quality settings. (This switch is poorly + named, since it does not ensure that the output is + actually baseline JPEG. For example, you can use + -baseline and -progressive together.) + + -qtables file Use the quantization tables given in the specified + text file. + + -qslots N[,...] Select which quantization table to use for each color + component. + + -sample HxV[,...] Set JPEG sampling factors for each color component. + + -scans file Use the scan script given in the specified text file. + +The "wizard" switches are intended for experimentation with JPEG. If you +don't know what you are doing, DON'T USE THEM. These switches are documented +further in the file wizard.doc. + + +DJPEG DETAILS + +The basic command line switches for djpeg are: + + -colors N Reduce image to at most N colors. This reduces the + or -quantize N number of colors used in the output image, so that it + can be displayed on a colormapped display or stored in + a colormapped file format. For example, if you have + an 8-bit display, you'd need to reduce to 256 or fewer + colors. (-colors is the recommended name, -quantize + is provided only for backwards compatibility.) + + -fast Select recommended processing options for fast, low + quality output. (The default options are chosen for + highest quality output.) Currently, this is equivalent + to "-dct fast -nosmooth -onepass -dither ordered". + + -grayscale Force gray-scale output even if JPEG file is color. + Useful for viewing on monochrome displays; also, + djpeg runs noticeably faster in this mode. + + -scale M/N Scale the output image by a factor M/N. Currently + the scale factor must be 1/1, 1/2, 1/4, or 1/8. + Scaling is handy if the image is larger than your + screen; also, djpeg runs much faster when scaling + down the output. + + -bmp Select BMP output format (Windows flavor). 8-bit + colormapped format is emitted if -colors or -grayscale + is specified, or if the JPEG file is gray-scale; + otherwise, 24-bit full-color format is emitted. + + -gif Select GIF output format. Since GIF does not support + more than 256 colors, -colors 256 is assumed (unless + you specify a smaller number of colors). If you + specify -fast, the default number of colors is 216. + + -os2 Select BMP output format (OS/2 1.x flavor). 8-bit + colormapped format is emitted if -colors or -grayscale + is specified, or if the JPEG file is gray-scale; + otherwise, 24-bit full-color format is emitted. + + -pnm Select PBMPLUS (PPM/PGM) output format (this is the + default format). PGM is emitted if the JPEG file is + gray-scale or if -grayscale is specified; otherwise + PPM is emitted. + + -rle Select RLE output format. (Requires URT library.) + + -targa Select Targa output format. Gray-scale format is + emitted if the JPEG file is gray-scale or if + -grayscale is specified; otherwise, colormapped format + is emitted if -colors is specified; otherwise, 24-bit + full-color format is emitted. + +Switches for advanced users: + + -dct int Use integer DCT method (default). + -dct fast Use fast integer DCT (less accurate). + -dct float Use floating-point DCT method. + The float method is very slightly more accurate than + the int method, but is much slower unless your machine + has very fast floating-point hardware. Also note that + results of the floating-point method may vary slightly + across machines, while the integer methods should give + the same results everywhere. The fast integer method + is much less accurate than the other two. + + -dither fs Use Floyd-Steinberg dithering in color quantization. + -dither ordered Use ordered dithering in color quantization. + -dither none Do not use dithering in color quantization. + By default, Floyd-Steinberg dithering is applied when + quantizing colors; this is slow but usually produces + the best results. Ordered dither is a compromise + between speed and quality; no dithering is fast but + usually looks awful. Note that these switches have + no effect unless color quantization is being done. + Ordered dither is only available in -onepass mode. + + -map FILE Quantize to the colors used in the specified image + file. This is useful for producing multiple files + with identical color maps, or for forcing a predefined + set of colors to be used. The FILE must be a GIF + or PPM file. This option overrides -colors and + -onepass. + + -nosmooth Use a faster, lower-quality upsampling routine. + + -onepass Use one-pass instead of two-pass color quantization. + The one-pass method is faster and needs less memory, + but it produces a lower-quality image. -onepass is + ignored unless you also say -colors N. Also, + the one-pass method is always used for gray-scale + output (the two-pass method is no improvement then). + + -maxmemory N Set limit for amount of memory to use in processing + large images. Value is in thousands of bytes, or + millions of bytes if "M" is attached to the number. + For example, -max 4m selects 4000000 bytes. If more + space is needed, temporary files will be used. + + -verbose Enable debug printout. More -v's give more printout. + or -debug Also, version information is printed at startup. + + +HINTS FOR CJPEG + +Color GIF files are not the ideal input for JPEG; JPEG is really intended for +compressing full-color (24-bit) images. In particular, don't try to convert +cartoons, line drawings, and other images that have only a few distinct +colors. GIF works great on these, JPEG does not. If you want to convert a +GIF to JPEG, you should experiment with cjpeg's -quality and -smooth options +to get a satisfactory conversion. -smooth 10 or so is often helpful. + +Avoid running an image through a series of JPEG compression/decompression +cycles. Image quality loss will accumulate; after ten or so cycles the image +may be noticeably worse than it was after one cycle. It's best to use a +lossless format while manipulating an image, then convert to JPEG format when +you are ready to file the image away. + +The -optimize option to cjpeg is worth using when you are making a "final" +version for posting or archiving. It's also a win when you are using low +quality settings to make very small JPEG files; the percentage improvement +is often a lot more than it is on larger files. (At present, -optimize +mode is always selected when generating progressive JPEG files.) + +GIF input files are no longer supported, to avoid the Unisys LZW patent. +Use a Unisys-licensed program if you need to read a GIF file. (Conversion +of GIF files to JPEG is usually a bad idea anyway.) + + +HINTS FOR DJPEG + +To get a quick preview of an image, use the -grayscale and/or -scale switches. +"-grayscale -scale 1/8" is the fastest case. + +Several options are available that trade off image quality to gain speed. +"-fast" turns on the recommended settings. + +"-dct fast" and/or "-nosmooth" gain speed at a small sacrifice in quality. +When producing a color-quantized image, "-onepass -dither ordered" is fast but +much lower quality than the default behavior. "-dither none" may give +acceptable results in two-pass mode, but is seldom tolerable in one-pass mode. + +If you are fortunate enough to have very fast floating point hardware, +"-dct float" may be even faster than "-dct fast". But on most machines +"-dct float" is slower than "-dct int"; in this case it is not worth using, +because its theoretical accuracy advantage is too small to be significant +in practice. + +Two-pass color quantization requires a good deal of memory; on MS-DOS machines +it may run out of memory even with -maxmemory 0. In that case you can still +decompress, with some loss of image quality, by specifying -onepass for +one-pass quantization. + +To avoid the Unisys LZW patent, djpeg produces uncompressed GIF files. These +are larger than they should be, but are readable by standard GIF decoders. + + +HINTS FOR BOTH PROGRAMS + +If more space is needed than will fit in the available main memory (as +determined by -maxmemory), temporary files will be used. (MS-DOS versions +will try to get extended or expanded memory first.) The temporary files are +often rather large: in typical cases they occupy three bytes per pixel, for +example 3*800*600 = 1.44Mb for an 800x600 image. If you don't have enough +free disk space, leave out -progressive and -optimize (for cjpeg) or specify +-onepass (for djpeg). + +On MS-DOS, the temporary files are created in the directory named by the TMP +or TEMP environment variable, or in the current directory if neither of those +exist. Amiga implementations put the temp files in the directory named by +JPEGTMP:, so be sure to assign JPEGTMP: to a disk partition with adequate free +space. + +The default memory usage limit (-maxmemory) is set when the software is +compiled. If you get an "insufficient memory" error, try specifying a smaller +-maxmemory value, even -maxmemory 0 to use the absolute minimum space. You +may want to recompile with a smaller default value if this happens often. + +On machines that have "environment" variables, you can define the environment +variable JPEGMEM to set the default memory limit. The value is specified as +described for the -maxmemory switch. JPEGMEM overrides the default value +specified when the program was compiled, and itself is overridden by an +explicit -maxmemory switch. + +On MS-DOS machines, -maxmemory is the amount of main (conventional) memory to +use. (Extended or expanded memory is also used if available.) Most +DOS-specific versions of this software do their own memory space estimation +and do not need you to specify -maxmemory. + + +JPEGTRAN + +jpegtran performs various useful transformations of JPEG files. +It can translate the coded representation from one variant of JPEG to another, +for example from baseline JPEG to progressive JPEG or vice versa. It can also +perform some rearrangements of the image data, for example turning an image +from landscape to portrait format by rotation. + +jpegtran works by rearranging the compressed data (DCT coefficients), without +ever fully decoding the image. Therefore, its transformations are lossless: +there is no image degradation at all, which would not be true if you used +djpeg followed by cjpeg to accomplish the same conversion. But by the same +token, jpegtran cannot perform lossy operations such as changing the image +quality. + +jpegtran uses a command line syntax similar to cjpeg or djpeg. +On Unix-like systems, you say: + jpegtran [switches] [inputfile] >outputfile +On most non-Unix systems, you say: + jpegtran [switches] inputfile outputfile +where both the input and output files are JPEG files. + +To specify the coded JPEG representation used in the output file, +jpegtran accepts a subset of the switches recognized by cjpeg: + -optimize Perform optimization of entropy encoding parameters. + -progressive Create progressive JPEG file. + -restart N Emit a JPEG restart marker every N MCU rows, or every + N MCU blocks if "B" is attached to the number. + -scans file Use the scan script given in the specified text file. +See the previous discussion of cjpeg for more details about these switches. +If you specify none of these switches, you get a plain baseline-JPEG output +file. The quality setting and so forth are determined by the input file. + +The image can be losslessly transformed by giving one of these switches: + -flip horizontal Mirror image horizontally (left-right). + -flip vertical Mirror image vertically (top-bottom). + -rotate 90 Rotate image 90 degrees clockwise. + -rotate 180 Rotate image 180 degrees. + -rotate 270 Rotate image 270 degrees clockwise (or 90 ccw). + -transpose Transpose image (across UL-to-LR axis). + -transverse Transverse transpose (across UR-to-LL axis). + +The transpose transformation has no restrictions regarding image dimensions. +The other transformations operate rather oddly if the image dimensions are not +a multiple of the iMCU size (usually 8 or 16 pixels), because they can only +transform complete blocks of DCT coefficient data in the desired way. + +jpegtran's default behavior when transforming an odd-size image is designed +to preserve exact reversibility and mathematical consistency of the +transformation set. As stated, transpose is able to flip the entire image +area. Horizontal mirroring leaves any partial iMCU column at the right edge +untouched, but is able to flip all rows of the image. Similarly, vertical +mirroring leaves any partial iMCU row at the bottom edge untouched, but is +able to flip all columns. The other transforms can be built up as sequences +of transpose and flip operations; for consistency, their actions on edge +pixels are defined to be the same as the end result of the corresponding +transpose-and-flip sequence. + +For practical use, you may prefer to discard any untransformable edge pixels +rather than having a strange-looking strip along the right and/or bottom edges +of a transformed image. To do this, add the -trim switch: + -trim Drop non-transformable edge blocks. +Obviously, a transformation with -trim is not reversible, so strictly speaking +jpegtran with this switch is not lossless. Also, the expected mathematical +equivalences between the transformations no longer hold. For example, +"-rot 270 -trim" trims only the bottom edge, but "-rot 90 -trim" followed by +"-rot 180 -trim" trims both edges. + +Another not-strictly-lossless transformation switch is: + -grayscale Force grayscale output. +This option discards the chrominance channels if the input image is YCbCr +(ie, a standard color JPEG), resulting in a grayscale JPEG file. The +luminance channel is preserved exactly, so this is a better method of reducing +to grayscale than decompression, conversion, and recompression. This switch +is particularly handy for fixing a monochrome picture that was mistakenly +encoded as a color JPEG. (In such a case, the space savings from getting rid +of the near-empty chroma channels won't be large; but the decoding time for +a grayscale JPEG is substantially less than that for a color JPEG.) + +jpegtran also recognizes these switches that control what to do with "extra" +markers, such as comment blocks: + -copy none Copy no extra markers from source file. This setting + suppresses all comments and other excess baggage + present in the source file. + -copy comments Copy only comment markers. This setting copies + comments from the source file, but discards + any other inessential data. + -copy all Copy all extra markers. This setting preserves + miscellaneous markers found in the source file, such + as JFIF thumbnails and Photoshop settings. In some + files these extra markers can be sizable. +The default behavior is -copy comments. (Note: in IJG releases v6 and v6a, +jpegtran always did the equivalent of -copy none.) + +Additional switches recognized by jpegtran are: + -outfile filename + -maxmemory N + -verbose + -debug +These work the same as in cjpeg or djpeg. + + +THE COMMENT UTILITIES + +The JPEG standard allows "comment" (COM) blocks to occur within a JPEG file. +Although the standard doesn't actually define what COM blocks are for, they +are widely used to hold user-supplied text strings. This lets you add +annotations, titles, index terms, etc to your JPEG files, and later retrieve +them as text. COM blocks do not interfere with the image stored in the JPEG +file. The maximum size of a COM block is 64K, but you can have as many of +them as you like in one JPEG file. + +We provide two utility programs to display COM block contents and add COM +blocks to a JPEG file. + +rdjpgcom searches a JPEG file and prints the contents of any COM blocks on +standard output. The command line syntax is + rdjpgcom [-verbose] [inputfilename] +The switch "-verbose" (or just "-v") causes rdjpgcom to also display the JPEG +image dimensions. If you omit the input file name from the command line, +the JPEG file is read from standard input. (This may not work on some +operating systems, if binary data can't be read from stdin.) + +wrjpgcom adds a COM block, containing text you provide, to a JPEG file. +Ordinarily, the COM block is added after any existing COM blocks, but you +can delete the old COM blocks if you wish. wrjpgcom produces a new JPEG +file; it does not modify the input file. DO NOT try to overwrite the input +file by directing wrjpgcom's output back into it; on most systems this will +just destroy your file. + +The command line syntax for wrjpgcom is similar to cjpeg's. On Unix-like +systems, it is + wrjpgcom [switches] [inputfilename] +The output file is written to standard output. The input file comes from +the named file, or from standard input if no input file is named. + +On most non-Unix systems, the syntax is + wrjpgcom [switches] inputfilename outputfilename +where both input and output file names must be given explicitly. + +wrjpgcom understands three switches: + -replace Delete any existing COM blocks from the file. + -comment "Comment text" Supply new COM text on command line. + -cfile name Read text for new COM block from named file. +(Switch names can be abbreviated.) If you have only one line of comment text +to add, you can provide it on the command line with -comment. The comment +text must be surrounded with quotes so that it is treated as a single +argument. Longer comments can be read from a text file. + +If you give neither -comment nor -cfile, then wrjpgcom will read the comment +text from standard input. (In this case an input image file name MUST be +supplied, so that the source JPEG file comes from somewhere else.) You can +enter multiple lines, up to 64KB worth. Type an end-of-file indicator +(usually control-D or control-Z) to terminate the comment text entry. + +wrjpgcom will not add a COM block if the provided comment string is empty. +Therefore -replace -comment "" can be used to delete all COM blocks from a +file. + +These utility programs do not depend on the IJG JPEG library. In +particular, the source code for rdjpgcom is intended as an illustration of +the minimum amount of code required to parse a JPEG file header correctly. diff --git a/gdcm/Utilities/gdcmjpeg/wizard.doc b/gdcm/Utilities/gdcmjpeg/wizard.doc new file mode 100644 index 0000000..54170b2 --- /dev/null +++ b/gdcm/Utilities/gdcmjpeg/wizard.doc @@ -0,0 +1,211 @@ +Advanced usage instructions for the Independent JPEG Group's JPEG software +========================================================================== + +This file describes cjpeg's "switches for wizards". + +The "wizard" switches are intended for experimentation with JPEG by persons +who are reasonably knowledgeable about the JPEG standard. If you don't know +what you are doing, DON'T USE THESE SWITCHES. You'll likely produce files +with worse image quality and/or poorer compression than you'd get from the +default settings. Furthermore, these switches must be used with caution +when making files intended for general use, because not all JPEG decoders +will support unusual JPEG parameter settings. + + +Quantization Table Adjustment +----------------------------- + +Ordinarily, cjpeg starts with a default set of tables (the same ones given +as examples in the JPEG standard) and scales them up or down according to +the -quality setting. The details of the scaling algorithm can be found in +jcparam.c. At very low quality settings, some quantization table entries +can get scaled up to values exceeding 255. Although 2-byte quantization +values are supported by the IJG software, this feature is not in baseline +JPEG and is not supported by all implementations. If you need to ensure +wide compatibility of low-quality files, you can constrain the scaled +quantization values to no more than 255 by giving the -baseline switch. +Note that use of -baseline will result in poorer quality for the same file +size, since more bits than necessary are expended on higher AC coefficients. + +You can substitute a different set of quantization values by using the +-qtables switch: + + -qtables file Use the quantization tables given in the named file. + +The specified file should be a text file containing decimal quantization +values. The file should contain one to four tables, each of 64 elements. +The tables are implicitly numbered 0,1,etc. in order of appearance. Table +entries appear in normal array order (NOT in the zigzag order in which they +will be stored in the JPEG file). + +Quantization table files are free format, in that arbitrary whitespace can +appear between numbers. Also, comments can be included: a comment starts +with '#' and extends to the end of the line. Here is an example file that +duplicates the default quantization tables: + + # Quantization tables given in JPEG spec, section K.1 + + # This is table 0 (the luminance table): + 16 11 10 16 24 40 51 61 + 12 12 14 19 26 58 60 55 + 14 13 16 24 40 57 69 56 + 14 17 22 29 51 87 80 62 + 18 22 37 56 68 109 103 77 + 24 35 55 64 81 104 113 92 + 49 64 78 87 103 121 120 101 + 72 92 95 98 112 100 103 99 + + # This is table 1 (the chrominance table): + 17 18 24 47 99 99 99 99 + 18 21 26 66 99 99 99 99 + 24 26 56 99 99 99 99 99 + 47 66 99 99 99 99 99 99 + 99 99 99 99 99 99 99 99 + 99 99 99 99 99 99 99 99 + 99 99 99 99 99 99 99 99 + 99 99 99 99 99 99 99 99 + +If the -qtables switch is used without -quality, then the specified tables +are used exactly as-is. If both -qtables and -quality are used, then the +tables taken from the file are scaled in the same fashion that the default +tables would be scaled for that quality setting. If -baseline appears, then +the quantization values are constrained to the range 1-255. + +By default, cjpeg will use quantization table 0 for luminance components and +table 1 for chrominance components. To override this choice, use the -qslots +switch: + + -qslots N[,...] Select which quantization table to use for + each color component. + +The -qslots switch specifies a quantization table number for each color +component, in the order in which the components appear in the JPEG SOF marker. +For example, to create a separate table for each of Y,Cb,Cr, you could +provide a -qtables file that defines three quantization tables and say +"-qslots 0,1,2". If -qslots gives fewer table numbers than there are color +components, then the last table number is repeated as necessary. + + +Sampling Factor Adjustment +-------------------------- + +By default, cjpeg uses 2:1 horizontal and vertical downsampling when +compressing YCbCr data, and no downsampling for all other color spaces. +You can override this default with the -sample switch: + + -sample HxV[,...] Set JPEG sampling factors for each color + component. + +The -sample switch specifies the JPEG sampling factors for each color +component, in the order in which they appear in the JPEG SOF marker. +If you specify fewer HxV pairs than there are components, the remaining +components are set to 1x1 sampling. For example, the default YCbCr setting +is equivalent to "-sample 2x2,1x1,1x1", which can be abbreviated to +"-sample 2x2". + +There are still some JPEG decoders in existence that support only 2x1 +sampling (also called 4:2:2 sampling). Compatibility with such decoders can +be achieved by specifying "-sample 2x1". This is not recommended unless +really necessary, since it increases file size and encoding/decoding time +with very little quality gain. + + +Multiple Scan / Progression Control +----------------------------------- + +By default, cjpeg emits a single-scan sequential JPEG file. The +-progressive switch generates a progressive JPEG file using a default series +of progression parameters. You can create multiple-scan sequential JPEG +files or progressive JPEG files with custom progression parameters by using +the -scans switch: + + -scans file Use the scan sequence given in the named file. + +The specified file should be a text file containing a "scan script". +The script specifies the contents and ordering of the scans to be emitted. +Each entry in the script defines one scan. A scan definition specifies +the components to be included in the scan, and for progressive JPEG it also +specifies the progression parameters Ss,Se,Ah,Al for the scan. Scan +definitions are separated by semicolons (';'). A semicolon after the last +scan definition is optional. + +Each scan definition contains one to four component indexes, optionally +followed by a colon (':') and the four progressive-JPEG parameters. The +component indexes denote which color component(s) are to be transmitted in +the scan. Components are numbered in the order in which they appear in the +JPEG SOF marker, with the first component being numbered 0. (Note that these +indexes are not the "component ID" codes assigned to the components, just +positional indexes.) + +The progression parameters for each scan are: + Ss Zigzag index of first coefficient included in scan + Se Zigzag index of last coefficient included in scan + Ah Zero for first scan of a coefficient, else Al of prior scan + Al Successive approximation low bit position for scan +If the progression parameters are omitted, the values 0,63,0,0 are used, +producing a sequential JPEG file. cjpeg automatically determines whether +the script represents a progressive or sequential file, by observing whether +Ss and Se values other than 0 and 63 appear. (The -progressive switch is +not needed to specify this; in fact, it is ignored when -scans appears.) +The scan script must meet the JPEG restrictions on progression sequences. +(cjpeg checks that the spec's requirements are obeyed.) + +Scan script files are free format, in that arbitrary whitespace can appear +between numbers and around punctuation. Also, comments can be included: a +comment starts with '#' and extends to the end of the line. For additional +legibility, commas or dashes can be placed between values. (Actually, any +single punctuation character other than ':' or ';' can be inserted.) For +example, the following two scan definitions are equivalent: + 0 1 2: 0 63 0 0; + 0,1,2 : 0-63, 0,0 ; + +Here is an example of a scan script that generates a partially interleaved +sequential JPEG file: + + 0; # Y only in first scan + 1 2; # Cb and Cr in second scan + +Here is an example of a progressive scan script using only spectral selection +(no successive approximation): + + # Interleaved DC scan for Y,Cb,Cr: + 0,1,2: 0-0, 0, 0 ; + # AC scans: + 0: 1-2, 0, 0 ; # First two Y AC coefficients + 0: 3-5, 0, 0 ; # Three more + 1: 1-63, 0, 0 ; # All AC coefficients for Cb + 2: 1-63, 0, 0 ; # All AC coefficients for Cr + 0: 6-9, 0, 0 ; # More Y coefficients + 0: 10-63, 0, 0 ; # Remaining Y coefficients + +Here is an example of a successive-approximation script. This is equivalent +to the default script used by "cjpeg -progressive" for YCbCr images: + + # Initial DC scan for Y,Cb,Cr (lowest bit not sent) + 0,1,2: 0-0, 0, 1 ; + # First AC scan: send first 5 Y AC coefficients, minus 2 lowest bits: + 0: 1-5, 0, 2 ; + # Send all Cr,Cb AC coefficients, minus lowest bit: + # (chroma data is usually too small to be worth subdividing further; + # but note we send Cr first since eye is least sensitive to Cb) + 2: 1-63, 0, 1 ; + 1: 1-63, 0, 1 ; + # Send remaining Y AC coefficients, minus 2 lowest bits: + 0: 6-63, 0, 2 ; + # Send next-to-lowest bit of all Y AC coefficients: + 0: 1-63, 2, 1 ; + # At this point we've sent all but the lowest bit of all coefficients. + # Send lowest bit of DC coefficients + 0,1,2: 0-0, 1, 0 ; + # Send lowest bit of AC coefficients + 2: 1-63, 1, 0 ; + 1: 1-63, 1, 0 ; + # Y AC lowest bit scan is last; it's usually the largest scan + 0: 1-63, 1, 0 ; + +It may be worth pointing out that this script is tuned for quality settings +of around 50 to 75. For lower quality settings, you'd probably want to use +a script with fewer stages of successive approximation (otherwise the +initial scans will be really bad). For higher quality settings, you might +want to use more stages of successive approximation (so that the initial +scans are not too large). diff --git a/gdcm/Utilities/gdcmmd5/.NoDartCoverage b/gdcm/Utilities/gdcmmd5/.NoDartCoverage new file mode 100644 index 0000000..3c99729 --- /dev/null +++ b/gdcm/Utilities/gdcmmd5/.NoDartCoverage @@ -0,0 +1 @@ +# do not do coverage in this directory diff --git a/gdcm/Utilities/gdcmmd5/CMakeLists.txt b/gdcm/Utilities/gdcmmd5/CMakeLists.txt new file mode 100644 index 0000000..13bd2da --- /dev/null +++ b/gdcm/Utilities/gdcmmd5/CMakeLists.txt @@ -0,0 +1,88 @@ +cmake_minimum_required(VERSION 2.8.9) + +if(NOT MD5_NAMESPACE) + set(MD5_NAMESPACE "MD5") + set(MD5_STANDALONE 1) +endif() +# In all cases: +string(TOLOWER ${MD5_NAMESPACE} MD5_LIBRARY_NAME) + +project(${MD5_NAMESPACE} C) + +# Do full dependency headers. +include_regular_expression("^.*$") + +set(MD5_SOURCES + md5.c + ) + +if (WIN32) + if (BUILD_SHARED_LIBS) + set(MD5DLL 1) + else () + set(MD5STATIC 1) + endif () +endif () + +# TODO +# Optimized function needs to define: +# ARCH_IS_BIG_ENDIAN +# Big endian thing: +#include (${CMAKE_ROOT}/Modules/TestBigEndian.cmake) +#TEST_BIG_ENDIAN(MD5_WORDS_BIGENDIAN) +#set_source_files_properties(${MD5_SOURCES} +# PROPERTIES COMPILE_FLAGS -DARCH_IS_BIG_ENDIAN +# ) +set(MANGLE_PREFIX ${MD5_LIBRARY_NAME}) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/md5_mangle.h.in + ${CMAKE_CURRENT_BINARY_DIR}/md5_mangle.h + @ONLY ) + +# for md5_mangle.h +include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR}) + +add_library(${MD5_LIBRARY_NAME} ${MD5_SOURCES}) + +if(GDCM_LIBRARY_PROPERTIES) + set_target_properties(${MD5_LIBRARY_NAME} PROPERTIES ${GDCM_LIBRARY_PROPERTIES}) +endif() + +if(NOT MD5_INSTALL_BIN_DIR) + set(MD5_INSTALL_BIN_DIR "bin") +endif() +if(NOT MD5_INSTALL_LIB_DIR) + set(MD5_INSTALL_LIB_DIR "lib") +endif() + +if(NOT MD5_INSTALL_NO_LIBRARIES) + install(TARGETS ${MD5_LIBRARY_NAME} + EXPORT ${GDCM_TARGETS_NAME} + RUNTIME DESTINATION ${MD5_INSTALL_BIN_DIR} COMPONENT Applications + LIBRARY DESTINATION ${MD5_INSTALL_LIB_DIR} COMPONENT Libraries + ARCHIVE DESTINATION ${MD5_INSTALL_LIB_DIR} COMPONENT DebugDevel + ${CPACK_NAMELINK_TYPE} + ) +endif() + +if(MD5_STANDALONE) + # md5main + add_executable(md5main md5main.c) + target_link_libraries(md5main ${MD5_LIBRARY_NAME}) + if(UNIX) + target_link_libraries(md5main -lm) + endif() + # md5cmp + add_executable(md5cmp md5cmp.c) + target_link_libraries(md5cmp ${MD5_LIBRARY_NAME}) + # tst2md5 + add_executable(tst2md5 tst2md5.c) + target_link_libraries(tst2md5 ${MD5_LIBRARY_NAME}) + install(TARGETS md5main md5cmp tst2md5 + RUNTIME DESTINATION ${MD5_INSTALL_BIN_DIR} COMPONENT Applications + LIBRARY DESTINATION ${MD5_INSTALL_LIB_DIR} COMPONENT Libraries + ARCHIVE DESTINATION ${MD5_INSTALL_LIB_DIR} COMPONENT DebugDevel + ${CPACK_NAMELINK_TYPE} + ) + +endif() + diff --git a/gdcm/Utilities/gdcmmd5/COPYING b/gdcm/Utilities/gdcmmd5/COPYING new file mode 100644 index 0000000..db9c049 --- /dev/null +++ b/gdcm/Utilities/gdcmmd5/COPYING @@ -0,0 +1,24 @@ +/* + Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + + */ + diff --git a/gdcm/Utilities/gdcmmd5/README b/gdcm/Utilities/gdcmmd5/README new file mode 100644 index 0000000..5e1e40b --- /dev/null +++ b/gdcm/Utilities/gdcmmd5/README @@ -0,0 +1,2 @@ +md5 lib from: +http://sourceforge.net/projects/libmd5-rfc/ diff --git a/gdcm/Utilities/gdcmmd5/md5.c b/gdcm/Utilities/gdcmmd5/md5.c new file mode 100644 index 0000000..c35d96c --- /dev/null +++ b/gdcm/Utilities/gdcmmd5/md5.c @@ -0,0 +1,381 @@ +/* + Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + + */ +/* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321, whose + text is available at + http://www.ietf.org/rfc/rfc1321.txt + The code is derived from the text of the RFC, including the test suite + (section A.5) but excluding the rest of Appendix A. It does not include + any code or documentation that is identified in the RFC as being + copyrighted. + + The original and principal author of md5.c is L. Peter Deutsch + . Other authors are noted in the change history + that follows (in reverse chronological order): + + 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order + either statically or dynamically; added missing #include + in library. + 2002-03-11 lpd Corrected argument list for main(), and added int return + type, in test program and T value program. + 2002-02-21 lpd Added missing #include in test program. + 2000-07-03 lpd Patched to eliminate warnings about "constant is + unsigned in ANSI C, signed in traditional"; made test program + self-checking. + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). + 1999-05-03 lpd Original version. + */ + +#include "md5.h" +#include + +#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ +#ifdef ARCH_IS_BIG_ENDIAN +# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) +#else +# define BYTE_ORDER 0 +#endif + +#define T_MASK ((md5_word_t)~0) +#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) +#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) +#define T3 0x242070db +#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) +#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) +#define T6 0x4787c62a +#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) +#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) +#define T9 0x698098d8 +#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) +#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) +#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) +#define T13 0x6b901122 +#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) +#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) +#define T16 0x49b40821 +#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) +#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) +#define T19 0x265e5a51 +#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) +#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) +#define T22 0x02441453 +#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) +#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) +#define T25 0x21e1cde6 +#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) +#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) +#define T28 0x455a14ed +#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) +#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) +#define T31 0x676f02d9 +#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) +#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) +#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) +#define T35 0x6d9d6122 +#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) +#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) +#define T38 0x4bdecfa9 +#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) +#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) +#define T41 0x289b7ec6 +#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) +#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) +#define T44 0x04881d05 +#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) +#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) +#define T47 0x1fa27cf8 +#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) +#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) +#define T50 0x432aff97 +#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) +#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) +#define T53 0x655b59c3 +#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) +#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) +#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) +#define T57 0x6fa87e4f +#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) +#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) +#define T60 0x4e0811a1 +#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) +#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) +#define T63 0x2ad7d2bb +#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) + + +static void +md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) +{ + md5_word_t + a = pms->abcd[0], b = pms->abcd[1], + c = pms->abcd[2], d = pms->abcd[3]; + md5_word_t t; +#if BYTE_ORDER > 0 + /* Define storage only for big-endian CPUs. */ + md5_word_t X[16]; +#else + /* Define storage for little-endian or both types of CPUs. */ + md5_word_t xbuf[16]; + const md5_word_t *X; +#endif + + { +#if BYTE_ORDER == 0 + /* + * Determine dynamically whether this is a big-endian or + * little-endian machine, since we can use a more efficient + * algorithm on the latter. + */ + static const int w = 1; + + if (*((const md5_byte_t *)&w)) /* dynamic little-endian */ +#endif +#if BYTE_ORDER <= 0 /* little-endian */ + { + /* + * On little-endian machines, we can process properly aligned + * data without copying it. + */ + if (!((data - (const md5_byte_t *)0) & 3)) { + /* data are properly aligned */ + X = (const md5_word_t *)data; + } else { + /* not aligned */ + memcpy(xbuf, data, 64); + X = xbuf; + } + } +#endif +#if BYTE_ORDER == 0 + else /* dynamic big-endian */ +#endif +#if BYTE_ORDER >= 0 /* big-endian */ + { + /* + * On big-endian machines, we must arrange the bytes in the + * right order. + */ + const md5_byte_t *xp = data; + int i; + +# if BYTE_ORDER == 0 + X = xbuf; /* (dynamic only) */ +# else +# define xbuf X /* (static only) */ +# endif + for (i = 0; i < 16; ++i, xp += 4) + xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); + } +#endif + } + +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + + /* Round 1. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ +#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + F(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 7, T1); + SET(d, a, b, c, 1, 12, T2); + SET(c, d, a, b, 2, 17, T3); + SET(b, c, d, a, 3, 22, T4); + SET(a, b, c, d, 4, 7, T5); + SET(d, a, b, c, 5, 12, T6); + SET(c, d, a, b, 6, 17, T7); + SET(b, c, d, a, 7, 22, T8); + SET(a, b, c, d, 8, 7, T9); + SET(d, a, b, c, 9, 12, T10); + SET(c, d, a, b, 10, 17, T11); + SET(b, c, d, a, 11, 22, T12); + SET(a, b, c, d, 12, 7, T13); + SET(d, a, b, c, 13, 12, T14); + SET(c, d, a, b, 14, 17, T15); + SET(b, c, d, a, 15, 22, T16); +#undef SET + + /* Round 2. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ +#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + G(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 1, 5, T17); + SET(d, a, b, c, 6, 9, T18); + SET(c, d, a, b, 11, 14, T19); + SET(b, c, d, a, 0, 20, T20); + SET(a, b, c, d, 5, 5, T21); + SET(d, a, b, c, 10, 9, T22); + SET(c, d, a, b, 15, 14, T23); + SET(b, c, d, a, 4, 20, T24); + SET(a, b, c, d, 9, 5, T25); + SET(d, a, b, c, 14, 9, T26); + SET(c, d, a, b, 3, 14, T27); + SET(b, c, d, a, 8, 20, T28); + SET(a, b, c, d, 13, 5, T29); + SET(d, a, b, c, 2, 9, T30); + SET(c, d, a, b, 7, 14, T31); + SET(b, c, d, a, 12, 20, T32); +#undef SET + + /* Round 3. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + H(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 5, 4, T33); + SET(d, a, b, c, 8, 11, T34); + SET(c, d, a, b, 11, 16, T35); + SET(b, c, d, a, 14, 23, T36); + SET(a, b, c, d, 1, 4, T37); + SET(d, a, b, c, 4, 11, T38); + SET(c, d, a, b, 7, 16, T39); + SET(b, c, d, a, 10, 23, T40); + SET(a, b, c, d, 13, 4, T41); + SET(d, a, b, c, 0, 11, T42); + SET(c, d, a, b, 3, 16, T43); + SET(b, c, d, a, 6, 23, T44); + SET(a, b, c, d, 9, 4, T45); + SET(d, a, b, c, 12, 11, T46); + SET(c, d, a, b, 15, 16, T47); + SET(b, c, d, a, 2, 23, T48); +#undef SET + + /* Round 4. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ +#define I(x, y, z) ((y) ^ ((x) | ~(z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + I(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 6, T49); + SET(d, a, b, c, 7, 10, T50); + SET(c, d, a, b, 14, 15, T51); + SET(b, c, d, a, 5, 21, T52); + SET(a, b, c, d, 12, 6, T53); + SET(d, a, b, c, 3, 10, T54); + SET(c, d, a, b, 10, 15, T55); + SET(b, c, d, a, 1, 21, T56); + SET(a, b, c, d, 8, 6, T57); + SET(d, a, b, c, 15, 10, T58); + SET(c, d, a, b, 6, 15, T59); + SET(b, c, d, a, 13, 21, T60); + SET(a, b, c, d, 4, 6, T61); + SET(d, a, b, c, 11, 10, T62); + SET(c, d, a, b, 2, 15, T63); + SET(b, c, d, a, 9, 21, T64); +#undef SET + + /* Then perform the following additions. (That is increment each + of the four registers by the value it had before this block + was started.) */ + pms->abcd[0] += a; + pms->abcd[1] += b; + pms->abcd[2] += c; + pms->abcd[3] += d; +} + +void +md5_init(md5_state_t *pms) +{ + pms->count[0] = pms->count[1] = 0; + pms->abcd[0] = 0x67452301; + pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; + pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; + pms->abcd[3] = 0x10325476; +} + +void +md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) +{ + const md5_byte_t *p = data; + int left = nbytes; + int offset = (pms->count[0] >> 3) & 63; + md5_word_t nbits = (md5_word_t)(nbytes << 3); + + if (nbytes <= 0) + return; + + /* Update the message length. */ + pms->count[1] += nbytes >> 29; + pms->count[0] += nbits; + if (pms->count[0] < nbits) + pms->count[1]++; + + /* Process an initial partial block. */ + if (offset) { + int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); + + memcpy(pms->buf + offset, p, copy); + if (offset + copy < 64) + return; + p += copy; + left -= copy; + md5_process(pms, pms->buf); + } + + /* Process full blocks. */ + for (; left >= 64; p += 64, left -= 64) + md5_process(pms, p); + + /* Process a final partial block. */ + if (left) + memcpy(pms->buf, p, left); +} + +void +md5_finish(md5_state_t *pms, md5_byte_t digest[16]) +{ + static const md5_byte_t pad[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + md5_byte_t data[8]; + int i; + + /* Save the length before padding. */ + for (i = 0; i < 8; ++i) + data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); + /* Pad to 56 bytes mod 64. */ + md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); + /* Append the length. */ + md5_append(pms, data, 8); + for (i = 0; i < 16; ++i) + digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); +} diff --git a/gdcm/Utilities/gdcmmd5/md5.h b/gdcm/Utilities/gdcmmd5/md5.h new file mode 100644 index 0000000..cc1c05e --- /dev/null +++ b/gdcm/Utilities/gdcmmd5/md5.h @@ -0,0 +1,108 @@ +/* + Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + + */ + +#include "md5_mangle.h" + +#if defined(WIN32) + #if defined(md5_EXPORTS) + #define MD5_EXPORT __declspec( dllexport ) + #else + #define MD5_EXPORT __declspec( dllimport ) + #endif +#else + #if __GNUC__ >= 4 + #define MD5_EXPORT __attribute__ ((visibility ("default"))) + #else + #define MD5_EXPORT + #endif +#endif /*defined(WIN32)*/ + +/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321, whose + text is available at + http://www.ietf.org/rfc/rfc1321.txt + The code is derived from the text of the RFC, including the test suite + (section A.5) but excluding the rest of Appendix A. It does not include + any code or documentation that is identified in the RFC as being + copyrighted. + + The original and principal author of md5.h is L. Peter Deutsch + . Other authors are noted in the change history + that follows (in reverse chronological order): + + 2002-04-13 lpd Removed support for non-ANSI compilers; removed + references to Ghostscript; clarified derivation from RFC 1321; + now handles byte order either statically or dynamically. + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); + added conditionalization for C++ compilation from Martin + Purschke . + 1999-05-03 lpd Original version. + */ + +#ifndef md5_INCLUDED +# define md5_INCLUDED + +/* + * This package supports both compile-time and run-time determination of CPU + * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be + * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is + * defined as non-zero, the code will be compiled to run only on big-endian + * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to + * run on either big- or little-endian CPUs, but will run slightly less + * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. + */ + +typedef unsigned char md5_byte_t; /* 8-bit byte */ +typedef unsigned int md5_word_t; /* 32-bit word */ + +/* Define the state of the MD5 Algorithm. */ +typedef struct md5_state_s { + md5_word_t count[2]; /* message length in bits, lsw first */ + md5_word_t abcd[4]; /* digest buffer */ + md5_byte_t buf[64]; /* accumulate block */ +} md5_state_t; + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Initialize the algorithm. */ +void MD5_EXPORT md5_init(md5_state_t *pms); + +/* Append a string to the message. */ +void MD5_EXPORT md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); + +/* Finish the message and return the digest. */ +void MD5_EXPORT md5_finish(md5_state_t *pms, md5_byte_t digest[16]); + +#ifdef __cplusplus +} /* end extern "C" */ +#endif + +#endif /* md5_INCLUDED */ diff --git a/gdcm/Utilities/gdcmmd5/md5_mangle.h.in b/gdcm/Utilities/gdcmmd5/md5_mangle.h.in new file mode 100644 index 0000000..ad3b859 --- /dev/null +++ b/gdcm/Utilities/gdcmmd5/md5_mangle.h.in @@ -0,0 +1,36 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* This file was generated by CMake http://www.cmake.org */ + +#ifndef @MANGLE_PREFIX@_mangle_h +#define @MANGLE_PREFIX@_mangle_h + +/* + * This header file mangles all symbols exported from the md5 library. + * It is included in all files while building the md5 library. Due to + * namespace pollution, no md5 headers should be included in .h files in + * GDCM. + * + * The following command was used to obtain the symbol list: + * + * nm lib@MANGLE_PREFIX@.a |grep " [TR] " + */ + +#define md5_append @MANGLE_PREFIX@_append +#define md5_finish @MANGLE_PREFIX@_finish +#define md5_init @MANGLE_PREFIX@_init + +#define md5_EXPORTS @MANGLE_PREFIX@md5_EXPORTS + +#endif diff --git a/gdcm/Utilities/gdcmmd5/md5cmp.c b/gdcm/Utilities/gdcmmd5/md5cmp.c new file mode 100644 index 0000000..51e1c9e --- /dev/null +++ b/gdcm/Utilities/gdcmmd5/md5cmp.c @@ -0,0 +1,67 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "md5.h" + +#include +#include +#include +#include + +void process_file(const char *filename, md5_byte_t *digest) +{ + int di; + size_t file_size, read; + void *buffer; + md5_state_t state; + FILE *file = fopen(filename, "rb"); + + /* go to the end */ + /*int*/ fseek(file, 0, SEEK_END); + file_size = ftell(file); + /*int*/ fseek(file, 0, SEEK_SET); + buffer = malloc(file_size); + read = fread(buffer, 1, file_size, file); + assert( read == file_size ); + + md5_init(&state); + md5_append(&state, (const md5_byte_t *)buffer, file_size); + md5_finish(&state, digest); + /*printf("MD5 (\"%s\") = ", test[i]); */ + for (di = 0; di < 16; ++di) + { + printf("%02x", digest[di]); + } + printf("\t%s\n", filename); + free(buffer); + fclose(file); +} + +int main(int argc, char *argv[]) +{ + md5_byte_t digest1[16]; + md5_byte_t digest2[16]; + if( argc < 3 ) + { + return 1; + } + + /* Do file1 */ + process_file(argv[1], digest1); + + /* Do file2 */ + process_file(argv[2], digest2); + + return memcmp(digest1, digest2, 16); +} + diff --git a/gdcm/Utilities/gdcmmd5/md5main.c b/gdcm/Utilities/gdcmmd5/md5main.c new file mode 100644 index 0000000..625a619 --- /dev/null +++ b/gdcm/Utilities/gdcmmd5/md5main.c @@ -0,0 +1,139 @@ +/* + Copyright (C) 2002 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + + */ +/* $Id: md5main.c,v 1.1 2002/04/13 19:20:28 lpd Exp $ */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321, whose + text is available at + http://www.ietf.org/rfc/rfc1321.txt + The code is derived from the text of the RFC, including the test suite + (section A.5) but excluding the rest of Appendix A. It does not include + any code or documentation that is identified in the RFC as being + copyrighted. + + The original and principal author of md5.c is L. Peter Deutsch + . Other authors are noted in the change history + that follows (in reverse chronological order): + + 2002-04-13 lpd Splits off main program into a separate file, md5main.c. + */ + +#include "md5.h" +#include +#include +#include + +/* + * This file builds an executable that performs various functions related + * to the MD5 library. Typical compilation: + * gcc -o md5main -lm md5main.c md5.c + */ +static const char *const usage = "\ +Usage:\n\ + md5main --test # run the self-test (A.5 of RFC 1321)\n\ + md5main --t-values # print the T values for the library\n\ + md5main --version # print the version of the package\n\ +"; +static const char *const version = "2002-04-13"; + +/* Run the self-test. */ +static int +do_test(void) +{ + static const char *const test[7*2] = { + "", "d41d8cd98f00b204e9800998ecf8427e", + "a", "0cc175b9c0f1b6a831c399e269772661", + "abc", "900150983cd24fb0d6963f7d28e17f72", + "message digest", "f96b697d7cb7938d525a2f31aaf161d0", + "abcdefghijklmnopqrstuvwxyz", "c3fcd3d76192e4007dfb496cca67e13b", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + "d174ab98d277d9f5a5611c2c9f419d9f", + "12345678901234567890123456789012345678901234567890123456789012345678901234567890", "57edf4a22be3c955ac49da2e2107b67a" + }; + int i; + int status = 0; + + for (i = 0; i < 7*2; i += 2) { + md5_state_t state; + md5_byte_t digest[16]; + char hex_output[16*2 + 1]; + int di; + + md5_init(&state); + md5_append(&state, (const md5_byte_t *)test[i], strlen(test[i])); + md5_finish(&state, digest); + for (di = 0; di < 16; ++di) + sprintf(hex_output + di * 2, "%02x", digest[di]); + if (strcmp(hex_output, test[i + 1])) { + printf("MD5 (\"%s\") = ", test[i]); + puts(hex_output); + printf("**** ERROR, should be: %s\n", test[i + 1]); + status = 1; + } + } + if (status == 0) + puts("md5 self-test completed successfully."); + return status; +} + +/* Print the T values. */ +static int +do_t_values(void) +{ + int i; + for (i = 1; i <= 64; ++i) { + unsigned long v = (unsigned long)(4294967296.0 * fabs(sin((double)i))); + + /* + * The following nonsense is only to avoid compiler warnings about + * "integer constant is unsigned in ANSI C, signed with -traditional". + */ + if (v >> 31) { + printf("#define T%d /* 0x%08lx */ (T_MASK ^ 0x%08lx)\n", i, + v, (unsigned long)(unsigned int)(~v)); + } else { + printf("#define T%d 0x%08lx\n", i, v); + } + } + return 0; +} + +/* Main program */ +int +main(int argc, char *argv[]) +{ + if (argc == 2) { + if (!strcmp(argv[1], "--test")) + return do_test(); + if (!strcmp(argv[1], "--t-values")) + return do_t_values(); + if (!strcmp(argv[1], "--version")) { + puts(version); + return 0; + } + } + puts(usage); + return 0; +} diff --git a/gdcm/Utilities/gdcmmd5/tst2md5.c b/gdcm/Utilities/gdcmmd5/tst2md5.c new file mode 100644 index 0000000..72f478d --- /dev/null +++ b/gdcm/Utilities/gdcmmd5/tst2md5.c @@ -0,0 +1,104 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "md5.h" + +#include +#include +#include +#include + +/* + * Compute the md5 sum of a tst file + * tst file format: + * gdcm (4 bytes) + * sizeX (4 bytes) + * sizeY (4 bytes) + * sizeZ (4 bytes) + * bytePerScalar (2 bytes) + * numComponents (2 bytes) + * image (size = sizeX*sizeY*sizeZ*bytePerScalar/8*numComponents + */ +#define MAGIC_LEN 4 +int main(int argc, char *argv[]) +{ + const char *filename; + const char magic[] = "gdcm"; + char buffer[MAGIC_LEN+1]; + int di; + md5_state_t state; + md5_byte_t digest[16]; + unsigned int size_x, size_y, size_z; + unsigned short byte_per_scalar, num_comp; + FILE *file; + size_t s, len; + void *image; + + if( argc < 2 ) + { + return 1; + } + filename = argv[1]; + file = fopen(filename, "rb"); + s = fread(buffer, 1, MAGIC_LEN, file); + /* end with 0 */ + buffer[MAGIC_LEN] = '\0'; + assert( s == MAGIC_LEN ); + assert( strcmp(magic, buffer) == 0 ); + + /* Size X */ + s = fread (&size_x, 1, 4, file); + assert( s == 4 ); + /* Size Y */ + s = fread (&size_y, 1, 4, file); + assert( s == 4 ); + /* Size Z */ + s = fread (&size_z, 1, 4, file); + assert( s == 4 ); + /* Byte Per Scalar */ + s = fread (&byte_per_scalar, 1, 2, file); + assert( s == 2 ); + assert( !(byte_per_scalar%8) ); + /* Number of Components */ + s = fread (&num_comp, 1, 2, file); + assert( s == 2 ); + /* Display header */ + printf( "/* %s %d %d %d %d %d */\n", buffer, size_x, size_y, size_z, + byte_per_scalar, num_comp ); + + /* Compute len of image */ + len = size_x*size_y*size_z* (byte_per_scalar/8)*num_comp; + /* allocate */ + image = malloc(len); + /* read image */ + s = fread(image, 1, len, file); + assert( s == len ); + + /* compute md5 */ + md5_init(&state); + md5_append(&state, (const md5_byte_t *)image, len); + md5_finish(&state, digest); + /*printf("MD5 (\"%s\") = ", test[i]); */ + printf( "{ \"" ); + for (di = 0; di < 16; ++di) + { + printf("%02x", digest[di]); + } + printf("\" , \"%s\" },\n", filename); + + free(image); + fclose(file); + + return 0; +} + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/.NoDartCoverage b/gdcm/Utilities/gdcmopenjpeg-v1/.NoDartCoverage new file mode 100644 index 0000000..3c99729 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/.NoDartCoverage @@ -0,0 +1 @@ +# do not do coverage in this directory diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/CHANGES b/gdcm/Utilities/gdcmopenjpeg-v1/CHANGES new file mode 100644 index 0000000..18a1c98 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/CHANGES @@ -0,0 +1,817 @@ +What's New for OpenJPEG + +* : fixed +- : removed +! : changed ++ : added + +January 2, 2011 +* [antonin] bug fixes to enable cmake compilation on WIN32 platform + - fixed getopt bug in jpwl/CMakeLists.txt + - added png, zlib and lcms win32 libraries to libs directory + - updated libs/libtiff library + - moved j2k_dump_{image,cp} to j2k_dump.c to remain consistent with API interface + - changed mj2 cmake compilation method: as long as mj2 binaries do not strictly use the API interface, libopenjpeg source files are directly included in mj2 executables compilation. +! [antonin] small update to xcode project + +December 14, 2010 +! [szukw000] adapted Makefile.am/Makefile.nix to build + choice: shared xor static + +December 11, 2010 +* [antonin] fixed flags when building jp3d with MinGW + +December 10, 2010 +! [szukw000] changed build choice in configure.ac/Makefile.am/Makefile.nix: + shared xor static + +December 9, 2010 +! [antonin] removed LCMS dependency in jp3d/libjp3dvm/CMakeLists.txt +! [antonin] updated xcode project +! [antonin] renamed jp3d/libjp3dvm/openjpeg.h => jp3d/libjp3dvm/openjpeg3d.h +- [antonin] removed "codec/compat/" directory +* [szukw000] updated Makefile.in +! [szukw000] removed LCMS dependencies from Makefile.am/Makefile.nix + +December 8, 2010 + (thanks to Winfried for his help) +* [antonin] changed remaining "WIN32" to "_WIN32" +! [antonin] libopenjpeg has no more dependency on LCMS lib. Everything concerning color (icc profile, conversion to rgb, etc) has been put outside libopenjpeg and is used in j2k_to_image.c and mj2_to_frames.c. +- [antonin] removed 'opj_convert{.c,.h}' ++ [antonin] added a directory 'common/' that contains 'getopt{.c,.h}' (previously in 'codec/compat'). ++ [antonin] added files 'color{.c,.h}' in 'common/' that define the code for icc profile management and sycc_to_rgb conversion ++ [antonin] added 'common/format_defs.h' that contains common definitions used in image_to_j2k, j2k_to_image, j2k_dump. + +December 5, 2010 +! [antonin] revert to previous behaviour for cmake: builds (and links) dynamically by default. Static build only if -DBUILD_SHARED_LIBS is set to OFF. +* [antonin] added a definition in getopt.h and an initial value in convert.c + +December 3, 2010 +* [antonin] workaround for name clash when building static and dynamic on WIN32 (see http://www.vtk.org/Bug/view.php?id=10190 for description) + +November 28, 2010 +* [antonin] fixed a bug in codec/convert.c that prevented to build executables with WIN32 compiler (thanks winfried) +! [antonin] changed cmake behaviour: executables are now always statically linked. When -DBUIL_SHARED_LIBS option is ON (the default), the shared versions of the libraries are also built (but executables remain linked against the static libraries). + +November 25, 2010 +* [antonin] fix compilation and DLL creation of libopenjpeg with MSYS/MinGW (from vincent.torri, see issue 47 on googlecode) + +November 22, 2010 +! [antonin] xcode : changed to native architecture build by default +* [antonin] reverted 'include "../opj_config.h"' to 'include "opj_config.h"' + +November 17, 2010 +! [antonin] install man pages by default. install CHANGES and LICENSE +! [antonin] minor changes in cmake files (from winfried) + +November 16, 2010 +! [antonin] minor changes in cmake flags + +November 15, 2010 +! [antonin] xcode project rewrite. +! [antonin] changed imagetopng() function to correctly deal with non-standard bit-depths. Add png support for win32. (from winfried) +* [antonin] minor changes in header inclusions +* [antonin] complete rewrite of opj_convert.c with correct values (from winfried) + +November 11, 2010 +- [antonin] removed call to dirent.h in jp3d; + +October 28, 2010 +* [ben.boeckel] Set the soname and soversion on the jpwl library with CMake ++ [ben.boeckel] Install jpwl binaries with CMake + +October 26, 2010 +* [ben.boeckel] Install symlinks to versioned directory headers when using CMake ++ [ben.boeckel] Set the library version on jp3d when using CMake + +October 25, 2010 +* [ben.boeckel] Fix jp3d version + +October 24, 2010 +* [antonin] Fixed doxygen data inside source code (from winfried) + +October 22, 2010 +* [ben.boeckel] Don't install jp3d and libopenjpeg headers to the same place + +October 22, 2010 +* [ben.boeckel] Install man pages when using CMake + +October 22, 2010 +! [ben.boeckel] Default to building shared libraries + +October 22, 2010 +* [antonin] Patch to support the MSVC Win 64 builds (from szekerest) + +October 22, 2010 +* [antonin] Currently the Visual Studio builds are broken in the SVN. Attached a patch to fix this issue (from szekerest) + +October 22, 2010 +* [szukw000] replaced 'cp -d' with 'cp -P' for MacOSX + +October 22, 2010 +* [szukw000] 'jpwl/Makefile.am': added CFLAGS for bin_PROGRAMS + +October 22, 2010 ++ [szukw000] added 'libopenjpeg.pc.in' +! [szukw000] changed 'configure.ac' to create 'libopenjpeg.pc' +! [szukw000] changed 'Makefile.am' to [un]install 'libopenjpeg.pc' +! [szukw000] changed 'doc/Makefile.am' : 'uninstall-hook' added + +October 20, 2010 +* [antonin] fixed help display (patch from winfried) + +October 20, 2010 +* [antonin] + fixed paths to png and tiff in CMakeLists.txt (patch from winfried) + fixed link to lcms library (patch from winfried) + +October 18, 2010 +* [antonin] fixed options and help display (patch from winfried) + +October 18, 2010 +! [szukw000] + doc/Makefile.am + doc/Makefile.nix + jp3d/Makefile.nix + jpwl/Makefile.nix + Makefile.nix + config.nix + +October 17, 2010 +! [szukw000] + configure.ac : 'enable_shared' YES by default + doc/Makefile.am : + 'all-local' and 'install-data-hook' added + 'with_doxygen' conditional added + Makefile.am : 'doc' directory no longer substituted in SUBDIRS + + to link binaries statically: '-static' added to: + codec/Makefile.am + mj2/Makefile.am + jpwl/Makefile.am + jp3d/codec/Makefile.am + + mj2/Makefile.am : 'with_libjpwl' removed + mj2/Makefile.nix : 'with_libjpwl' removed + + config.nix : 'WITH_JPWL', 'WITH_JP3D' added + doc/Makefile.nix : 'clean', 'install', 'uninstall' added + Makefile.nix : 'WITH_JPWL', 'WITH_JP3D' added + + INSTALL : topic 3) changed regarding the changes in 'config.nix' + +October 13, 2010 +! [szukw000] + configure.ac + bootstrap.sh + + 'with_libjpwl' removed from: + libopenjpeg/Makefile.am + codec/Makefile.am + codec/Makefile.nix + Makefile.nix + +October 10, 2010 +* [antonin] Patch from winfried + + 1. The jp3d/libjp3dvm/Makefile.am has been changed: + + Installing: /usr/local/TEST_CONFIG/include/openjpeg3d-1.3/ + Installing: /usr/local/TEST_CONFIG/include/openjpeg3d-1.3/openjpeg3d.h + + PREFIX/include: + + 23 openjpeg.h -> openjpeg-1.4/openjpeg.h + 27 openjpeg3d.h -> openjpeg3d-1.3/openjpeg3d.h + + 28773 openjpeg-1.4/openjpeg.h + 22158 openjpeg3d-1.3/openjpeg3d.h + + 2. The jp3d/Makefile.nix has been changed respectivly. + + 3. The mj2/Makefile.nix contained a wrong path to 'compat/' + + 4. opj_config.h.in.user contained a comment within a comment. + + 5. 'autoreconf' reported that AC_PROG_RANLIB is no longer + necessary in 'configure.ac'. + +October 08, 2010 +* [antonin] fixed a bug in mj2.c that prevented extract_j2k_from_mj2 to build properly. Patch from winfried. + +October 04, 2010 ++ [antonin] Added files to let people build openjpeg with 'configure' tools ++ [antonin] Added makefiles to let people manually build openjpeg on *nix platforms +- [antonin] Removed obsolete Makefiles +! [antonin] Renamed dirent.h to windirent.h +! [antonin] Made optional the PNG, TIFF, and LCMS support in CMake files ++ [antonin] Added opj_config* files to configure openjpeg before building it (opj_config.h generated by 'configure', cmake, or manually by the user) +! [antonin] Renamed this file from ChangeLog to CHANGES +! [antonin] Renamed 'License.txt' to 'LICENSE' +! [antonin] Updated README files ++ [antonin] Added INSTALL and LICENSE files ++ [antonin] Added man pages + +June 22, 2010 ++ [MM] Apply patch from w. szukalski (sent to list) ++ [MM] Also dump the image info as well as cp info. + +June 21, 2010 ++ [MM] Added a j2k_dump to simply dump the parameter of a J2K file + +May 26, 2010 ++ [antonin] Added CTestConfig.cmake to the root directory to incorporate the testing dashboard. ++ [antonin] MACOSX : Added a "build all" target to the XCode project file. + +April 16, 2010 +* [antonin] MACOSX : Fixed the XCode project file to link with the PNG library. Library and header should be located in /usr/local/lib/ and /usr/local/include/, respectively. Check http://ethan.tira-thompson.org/Mac_OS_X_Ports.html if it is not the case on your mac. + +April 8, 2010 +* [FOD] Fixed issue 6 on google code. Variable "pi" not freed or pointed-to in function "pi_create_encode". Thanks to Kent Mein for reporting this. +* [FOD] Fixed problem with Borland C++ Builder (Borland C do not have lrintf). Thanks Marek Mauder for this fix. +* [FOD] Fixed pi.c bug (issue 15 on google code). Thanks to Anton Lionel for catching this. +* [FOD] Fixed MJ2 codec bugs (issues 23-24 on google code). Thanks to Winfried for these patches +* [FOD] Fixed JP3D codec file format analyzer. Thanks to Kristóf Ralovich for this patch. +! [FOD] Significant optimizations of MCT, DWT, MQ and T1 modules by Peter Wimmer (thanks Peter) + +March 26, 2010 ++ [FOD] Added support for "jpc" codestreams which are equivalent to "j2c" codestreams. Thanks to Winfried for this patch +* [FOD] Added support for PNG image format [Not yet functional under WIN32]. Thanks to Winfried for this patch. See details here http://code.google.com/p/openjpeg/issues/detail?id=16 + +March 24, 2010 +* [FOD] Code improvements using 'g++-4.4.0' to trace the code. Thanks to Winfried for this patch. + +March 7, 2010 +* [FOD] Fixed small compatibility issues with win32 in codec (moved include ) + +March 5, 2010 +! [FOD] Updated makefiles for v1.4 and v2.0 ++ [FOD] First import of OPJ_Validate tool + +February 18, 2010 +* [FOD] JP3D Module. Fixed issue when computing the number of elements in an array that leads to crash (thanks Kristof). Updated JP3D makefiles. + +January 20, 2010 +! [FOD] Created a new constant in openjpeg.h to differentiate the case when the colorspace is not supported by the library and when it is not specified in the codestream. Suggested by Matteo Italia. + +November 5, 2009 +* [antonin] fixed MCT check bug in t1_getwmsedec. See http://groups.google.com/group/openjpeg/browse_thread/thread/d9d96dd4ec3e7443 for info. + +November 5, 2009 +* [antonin] fixed "tiffio" header inclusion to use user version on Win32 system only (otherwise assume its existence in system headers). + +September 10, 2009 +* [antonin] fixed minor bugs which were triggering warnings at compilation (different signedness, wrong pointer type, etc) + +September 8, 2009 +* [antonin] openjpeg.c : fixed initialization of parameters->cp_disto_alloc/fixed_quality/fixed_alloc/tcp_numlayers because they were preventing to use the -q and -f options. + +August 31, 2009 +* [antonin] JavaOpenJpegDecoder.c : fixed a signed/unsigned behaviour when returning form C to JAVA + +August 21, 2008 +* [antonin] found a bug in tcd.c that was preventing to find the correct threshold in tcd_rateallocate.c for high-precision images. Applied a temporary patch but a better solution should be found. + +August 21, 2008 +* [antonin] fixed a bug in image_to_j2k.c that was preventing the 'r' option to work properly (everything was compressed lossless regardless of the specified rate). + +August 8, 2008 +! [FOD] Modified the way raw images with more that 8bpp are read and written + +July 9, 2008 ++ [Parvatha] Added the default lossless parameter to opj_set_default_encoder_parameters in openjpeg.c. + +June 12, 2008 +* [antonin] fixed a bug in dirent.h that prevented codec on Linux Alpha Systems to compile correctly. Thanks to RobinC. + +May 22, 2008 +* [antonin] fixed a bug in j2k.c (j2k_write_sod) that allowed to get negative rates, thanks zhong1985624 for pointing this. + +May 22, 2008 +* [antonin] additional test to avoid crash due to invalid image size, patch by Christopher Layne + +May 20, 2008 +* [antonin] memory leak fixed in openjpeg.c (opj_destroy_cstr_info()), patch by Carsten Juttner + +March 12, 2008 ++ [GB] help line for the -F option in j2k_to_image + +March 4, 2008 +! [FOD] Changed Java files copyright in JavaOpenJPEG module + +February 28, 2008 +* [FOD] Fixed openjpeg.c for proper initialization of codec context structures (dinfo in opj_create_compress() + and opj_create_decompress(). Bug fix suggested by Andrey V. Kiselev +* [FOD] Clean up of opj_aligned_malloc(), to just forgo the use of posix_memalign(), + as apparently memalign() is what is working better for everyone. Patch by Callum. + +February 28, 2008 +- [FOD] Removed the J2KViewer module, which has been replaced by OPJViewer +* [FOD] Fixed the error handling of j2k_decode in jp2.c, thanks to Robin Cornelius + +February 11, 2008 +* [GB] Minor style modifications to comply with c99 compiler flag; removed Microsoft-specific "union-in-struct" syntax; Re-enabled cstr_info struct creation when -W switch is specified +! [GB] Changed a number of things in opjviewer (e.g., decoding thread does not execute GUI calls anymore), to have it running under linux --> it is better than before, but still crashes + +February 5, 2008 +! [Parvatha] In convert.c, corrected imagetobmp() conversion for grayscale. In tcd.c, corrected Rate modification in + tcd_init_encode(). Thanks to Jeremy Furtek and Jérôme Fimes. + +January 31, 2008 +! [GB] In opjviewer, unification of JPEG 2000 family handlers (*.jp2, *.mj2, *.j2k) in a single file + +January 22, 2008 +! [FOD] In image.c, changed the opj_image_create0() memory allocation from malloc() to calloc() in order + to avoid segfaults when freeing the memory allocated for the coding of bad images. + Thanks to Christopher Layne for this improvement. + +January 17, 2008 ++ [antonin] Initial commit of Xcode project directory (XCode 2.5 for macosx) + available targets : libopenjpeg (stat and dyn), image_to_j2k, j2k_to_image + +January 16, 2008 +* [antonin] fixed opj_malloc.h for macosx (bugfix provided by janpeder, thanks) + +January 11, 2008 ++ [FOD] Added missing files to JavaOpenJPEG project (files from Patrick Piscaglia) + +January 4, 2008 +* [Parvatha] Patch by Callum Lerwick. Fixed bug during encoding using tile option in tcd.c + +---------------------- +December 21, 2007 +VERSION 1.3.0 RELEASED +---------------------- + +December 21, 2007 +* [FOD] Bug fixed by David Bruken. Fixed memory allocation issue in opj_malloc.h +! [FOD] Possible errors in pi_create_encode handled + +December 19, 2007 +* [Antonin] changed variables names alpha, beta, gamma, delta in dwt.c to avoid re-declarations on Macosx +! [Parvatha] In pi.c, removed the Recursive function pi_check_next_level() and modified the code. +* [FOD] Fixed allocation problem in pi.c + +December 19, 2007 ++ [FOD] In mqc.h, changed MQC_NUMCTXS from 32 to 19 as there are only 19 possible contexts + +December 10, 2007 ++ [FOD] First import of JAVAOpenJPEG, a Java wrapper of OpenJPEG, developed by Patrick Piscaglia of Telemis (www.telemis.com). + Thank you Patrick for this new module ! + +November 29, 2007 +! [GB] Added index.h and index.c in VC6 projects; wrapped index.h in the C++ preprocessor; modified OPJViewer project and some files. + +November 14, 2007 ++ [FOD] Created the file index.c in the codec directory. This file handles the creation of index files, + at encoding and decoding. +* [FOD] Fixed bugs during the creation of the index (PCRL progression order) +* [FOD] Fixed the maximum number of resolutions a user can discard while decoding. + Added an error state in J2K_STATE (j2k.c) + +November 14, 2007 +! [FOD] - First Patch by Callum Lerwick. Instead of reinventing realloc, j2k_read_sod now just uses opj_realloc in j2k.c + - Second Patch by Callum Lerwick. This patch rearranges the largest memory allocations so they're allocated as + late as possible, and freed as soon as possible. This cuts memory usage by about half on two large test images. + - Third Patch by Callum Lerwick. The opj_tcd_cblk array is one of the largest allocations, because it + contains a bunch of static buffers. This also makes it a major source of cache thrashing. This patch allocates + the buffers from the heap, and dynamically sizes them in the decoder. I have not yet managed to dynamically size + them in the encoder, getting the decoder to do it was tricky enough... I also split opj_tcd_cblk_t into separate + encode and decode versions. A lot of fields were not used by both, so this cuts its size even further. + +* [FOD] Avoided ABI breakage + +November 13, 2007 +! [FOD] Patch by Dzonatas and Callum Lerwick. + Fp/vectorization patch which basically converts most of the irreversible decode codepath to floating point, + eliminating a few rounds of int/fp conversion, resulting in a vast performance improvement, + and an increase in accuracy. + +November 8, 2007 +! [FOD] In t1.c, small change to avoid calling twice t1_getwmsedec() + Patches from Callum Lewick: + - Basic gcc optimization flags in cmake and makefile match. + - Fixed some spelling errors in dwt.c. + +November 5, 2007 +*+ [GB] Fixed a bug which prevented JPWL from working on multi-tiled images; added some more fields in the interface info structures +(keep a list of markers, save start packet number for each tile) + +October 23, 2007 +* [GB] Improved success for the linux build; OPJViewer shows all the COM contents + +October 18, 2007 +* [FOD] Changed the ROI parameter in the image_to_j2k codec to make it correspond to the documentation (i.e. -ROI c=0,U=25) +* [FOD] Patch from Callum Lewick. Memset patch. + The main idea of the patch is that currently opj_malloc clears all allocations, which unnecessarily + dirties up the cache and eats bandwidth. This patch makes it no longer do so, and I've painstakingly determined which allocations actually need + to be cleared and changed them to use opj_calloc() instead. I previously tried to just get rid of the opj_*alloc wrappers but that + idea was nixed, so this time I'm trying it with macros. I also put in a gcc pragma that helps enforce their use. Which got messy. :) It caught a + few places they weren't used but it also revealed that the mj2 tools are not very cleanly separated from the library. It includes all the + internal headers, but it wasn't using the malloc wrappers. I figured the binaries should be "external" and have minimal knowledge of the + internals of the library. I patched them to not include opj_includes.h, and include only the internal headers they actually need. However, + they're using the opj_clock() function, which is in with the malloc wrappers. So I decided to move the malloc wrappers to their own header. + But mj2.c seems to want to be "internal", so I patched it to use the wrappers. Note that this patch changes the semantics of opj_malloc, it no longer + clears the memory it allocates. If you need it to be cleared, you must use opj_calloc instead, or memset it yourself. It is also somewhat + invasive, please test it extensively. I've been pounding on it all summer with my test suite, Second Life, and valgrind, and it checks out clean. + +October 12, 2007 +* [FOD] Changed the way the image structure is allocated when the decoding parameters include some resolutions to discard. + This should have a significant impact for the decoding of huge images when some resolutions are discarder (-r parameter) + Warning: The output image size is now reduced when discarding resolutions ! + +October 10, 2007 +* [FOD] Patch from Callum Lewick. Clean up of j2klib.h for the aligned malloc stuff. + It makes it work right with mingw, as _mm_malloc() isn't a macro, attempts to pave the way to using cmake + to check for this stuff and combines a patch from Dana Fagerstrom at Sun that makes it use memalign() on Solaris + convert.c: Changed some error comments for TIFF images + +September 27, 2007 +* [FOD] Patch from Callum Lewick. Fixed dwt.c where an alignment in buffer was problematic under x86_64. + +September 25, 2007 +* [Mathieu Malaterre] BUG: Fix previous patch from Callum Lerwick. I have no + clue what CMAKE_INSTALL_LIBDIR refers too. Bump up cmake 2.2 restriction to + cmake 2.4 because of previous patch (not backward compatible). Properly set the SOVERSION in a cross plateform way (yes WIN32 is a platform) + +September 19, 2007 +* [Parvatha] Fixed issues with generation of SOP marker. + +September 18, 2007 +* [Parvatha] Fixed issues with Reading and Writing TIF images in convert.c to avoid segmentation fault. +* [Parvatha] Fixed issues relating to using user specified rates for CINEMA option for multiple images. + +September 17, 2007 +* [FOD] Fixed issues with cstr_info when codestream has components with different number of resolutions. +! [FOD] OpenJPEG library interface modified to retain compatibility with version 1.2 + +September 12, 2007 +* [FOD] Patch from Callum Lerwick. + Fixed the library linking so it links with the soversion properly set. + Fixes up the install targets so that it interacts properly with RPM. + Install target for MJ2. Sets some necessary and useful CFLAGS if gcc is in use. +* [FOD] Updated the MJ2 codec to be compatible with the recent changes in the OpenJPEG library + +September 11, 2007 +* [GB] JPWL encoding is finalized correctly into the JP2 file format; added an additional structure in opj_codestream_info, to keep a record of the written markers + +September 8, 2007 +* [GB] Adapted the JPWL and OPJViewer code to new interface; fixed a samll bug in JPWL which created large EPBs even when null protection was specified + +September 7, 2007 ++ [FOD] Indexes can now be generated when decoding J2K codestreams. +* [Mathieu Malaterre] Upon failure, properly return error code (!=0). +* [Mathieu Malaterre] CMake: Add cmake code to do testing if user has properly setup a testimages directory + +September 6, 2007 ++ [Mathieu Malaterre] CMake: start compiling mj2, jpwl and jp3d ++ [Mathieu Malaterre] CMake: output all executable/libs into one single directory ++ [Mathieu Malaterre] CMake: start compiling index_create ++ [Mathieu Malaterre] OpenJPEG.rc update copyright year ++ [Mathieu Malaterre] CMake: add Java j2kviewer but do not compile it using cmake since cmake has too poor support for Java. Should create a custom command running ant instead. ++ [Mathieu Malaterre] CMake: Add doxygen output ++ [GB] One more field in the codestream_info struct for recording the number of packets per tile part; JPWL now distributes the EPBs in all the tile part headers ++ [Mathieu Malaterre] CMake: Add very simple tests (simply run command line with no option) +* [Mathieu Malaterre] Fix unitialized read in img_fol (we may need a smarter initialize than memset) + +September 4, 2007 ++ [GB] Added some fields in the codestream_info structure: they are used to record the position of single tile parts. + Changed also the write_index function in the codec, to reflect the presence of this new information. + +September 3, 2007 ++ [GB] Added the knowledge of JPSEC SEC and INSEC markers (you have to compile the JPWL project). Management of these markers is limited to skipping them without crashing: + no real security function at this stage. Deprecated USE_JPSEC will be removed next + +August 31, 2007 +* [GB] Fixed save capabilities in OPJViewer due to recent code upgrade + +August 30, 2007 +* [FOD] Changed the OpenJPEG library interface to enable users to access information regarding the codestream (also called codestream index). + This index is usefull for all applications requiring to have a scalable acces to the codestream (like JPIP applications, ...) + Currently, this information is only available when encoding an image. ++ [FOD] Added the information regarding the end of packet position in the index + +August 28, 2007 +* [FOD] Fixed wrong destructors called in openjpeg.c +* [FOD] Fixed bug in j2k_decode_jpt_stream + +August 24, 2007 +* [Parvatha] The end of main header is calculated after TLM and POC marker for Dcinema. + +August 21, 2007 ++ [FOD] Added support for Visual Studio 2005 +* [FOD] Robustified MJ2 codecs +* [Parvatha] Solved problems with codec reading from image file directory when filename had more than one "." in name +* [Callum Lerwick] Minor cleanup patch, that gets rid of a bunch of "old style declaration" warnings from Intel's compiler +* [Callum Lerwick] Aligned malloc using Intel's _mm_malloc(). Cleanup on the t1 memory allocation, getting rid of some leftover debug code +* [Callum Lerwick] Memory leaks fixed +* [Callum Lerwick] Reworks of t1_updateflags to get rid of the shift operation +* [Callum Lerwick] mqc_setcurctx moved to the header to allow it to be inlined into the t1. +* [Callum Lerwick] Consolidated some calls to mqc_setcurctx. +* [Callum Lerwick] Cleaned up t1_generate_luts to output the proper types. +* [Callum Lerwick] Replaced the large ctxno_mag lookup table with a small bit of inline-able branchless code +* [Callum Lerwick] Moved the orient flipping into the ctxno_zc table. + +August 20, 2007 ++ [FOD] Added support for the TGA file format in the codec + +August 08, 2007 +* [Parvatha] Fixed the DCinema filesize allocation. It now includes the SOT marker size + +August 02, 2007 ++ [GB] Added a basic saving capability to OPJViewer + +July 18, 2007 +! [FOD] Updated libtiff library version to 3.8.2 (for WIN32) +* [FOD] Updated BMP and PxM truncation when decoding J2K files with more than 8 bits + +July 17, 2007 +* [FOD] Fixed raw option for images with more than three components + +July 17, 2007 ++ [FOD] Added support for RAW images. This module has been developped by the University of Perugia team. Thanks to them ! [image_to_j2k.c j2k_to_image.c convert.c convert.h] + +July 13, 2007 +! [FOD] Modified the memory allocation for codestreams containing multiple tiles. The memory is now allocated for each tile indenpendently, + leading to an important decrease of the virtual memory needed. [j2k.c tcd.h tcd.c] +! [FOD] Modified old comments about the ability to decode mega-images and comments about the disk size necessary to do this. [image_to_j2k.c and frames_to_mj2.c] +* [FOD] Added 2000 bytes for the memory allocation in cio.c for the minimum size of headers (useful in case of very small images) [cio.c] + +July 12, 2007 +* [GB] fixed a bug in JPWL module, which prevented to exploit the full error correction capability of RS codes (e.g. it gave up at 5 errors, + even if 6 were correctable); defined a JPWL_MAXIMUM_EPB_ROOM for better customization of the maximum dimension of EPBs (the dimension + is pre-calculated on an hypothesis, if it goes beyond 65535 there will be problems, thus we give a little less than the max, let's say 65450) + +July 8, 2007 +* [ANTONIN] fixed the size of the memory allocation in cio.c (confusion between bits and bytes) + +June 21, 2007 +* [FOD] Output image color space set when decoding a JP2 file in jp2.c ++ [GB] Previous, home, and next frame buttons for exploring MJ2 files in OPJViewer + +June 18, 2007 +* [GB] Reload image doesn't crash in OPJViewer; more settings saved to registry + +June 16, 2007 ++ [GB] Possibility to disable parsing in OPJViewer; also, saves common settings to the registry + +June 15, 2007 +* [FOD] Fixed the generation of index files + + +---------------------- +MAY 4, 2007 +VERSION 1.2.0 RELEASED +---------------------- + +May 4, 2007 +* [FOD] Bugs corrected in decoding of command line (getopt.c), in the handling of 16 bit files (t1.c and tcd.c) and the calculation of elapsed time for multiple tiles parts (tcd.c and tdc.h). + +June 2, 2007 ++ [GB] OPJViewer opens now BMP, PNG, GIF, PNM, TIFF (with wxWidgets internals); added an encoder settings tab, for future integration with "save file as..." in JPEG 2000 format + +May 31, 2007 +* [FOD] Fixed the handling of 16bit TIFF files for cinema compression. Modified "convert.c" +* [FOD] Fixed the parameters used for cinema compression (9-7 transform used instead of 5-3). Modified "image_to_j2k.c" + +May 24, 2007 +* [FOD] Bug fixed by Sylvain Munaut. Change in the reading of the POC marker. Since COD/COC can be anywhere in the header, the decoder cannot always know while decoding the POC marker + the value of numlayers and numresolution. + +May 23, 2007 +! [FOD] Patch suggested by Callum Lerwick : "This makes the t1 data arrays dynamic, which greatly reduces cache thrashing. Also, some minor cleanup to prevent unnecessary casts" + +May 22, 2007 +! [FOD] Patch suggested by Callum Lerwick : "Some formatting cleanups, + so that the long function definitions and calls fit on screen. Use of prefix increment which is theoretically faster, in practice any sane compiler can optimize a postfix + increment but its best not to count on such things. Consolidation of some redundant calculations in the inner loops, which becomes very useful in the future autovectorize patch." +! [FOD] Patch suggested by Callum Lerwick : "This changes the flag code in t1 to use a flag_t type, which can then be changed to reduce RAM usage. It is now typedef to a short." +! [FOD] Patch suggested by Callum Lerwick : "This patch makes the t1 LUTs static. I actually intend this as a prelude to possibly eliminating some or all of the LUTs entirely." + +May 11, 2007 +- [FOD] JP3D library Binaries removed from SVN. +! [FOD] MJ2 codec updated from LibOpenJPEG version 0.97 to LibOpenJPEG version 1. Hence, the MJ2 codec will now take advantage of all the improvements and optimizations done on the LibOpenJPEG library. +! [FOD] Possibility to choose to apply MCT (multiple component transform) enabled, and new decoding_limit: DECODE_ALL_BUT_PACKETS (openjpeg.h) + +April 26, 2007 ++ [gdcm] Add basic steps on how to use CMake for building examples (README.cmake) + +April 25, 2007 ++ [FOD] Modification of the openjpeg.h file to avoid and ABI break with v1.1, removed the dangerous #IFDEF JPWL and added tcp_mct in cparameters. + +April 23, 2007 ++ [GB] Enable/disable image decoding in OPJViewer + +April 12,2007 +* [Parvatha] Fixed Error in tiftoimage(). Modification in convert.c. + +April 10,2007 ++ [Parvatha] Accepting "j2c" as format for Encoding and Decoding. Modification in image_to_j2k.c. +* [Parvatha] Modified imagetotif() to read images with signed data. Modification in convert.c. + +April 5, 2007 +! [FOD] fix.h optimized. Thanks a lot to Dzonatas ! +! [FOD] dwt.c optimized. Thanks a lot to Dzonatas ! +! [FOD] t1.c optimized. Thanks a lot to Callum Lerwick ! + +April 4,2007 ++ [Parvatha] Digital cinema compliance for 4K chosen by "-cinema4K" option. Modification in image_to_j2k.c. ++ [Parvatha] Bit rate limitation for each color component. Modification in image_to_j2k.c, t2.c. +* [Parvatha] Modified and tested Progression order change "-POC" option. Modification in image_to_j2k.c, j2k.c, pi.c. ++ [Parvatha] Function j2k_check_poc_val() to check for possible loss of packets in case of wrong POC declaration. Modification in j2k.c. ++ [Parvatha] Structure T2_MODE. This tells if the t2_encode_packets() is called during Threshold calculation or in Final pass. Modification in j2k.h, tcd.c + +March 30, 2007 +* [GB] OPJViewer should now work under Linux, at least with not big j2k files. Tested under Suse 10.1 64 bit. + +March 29, 2007 +* [Parvatha] Enable accepting file names with `-´ symbol .Modification getopt.c +* [Parvatha] Rsiz profile name generation to be STD_RSIZ for profiles which are not DCI compliant.Modification in image_to_j2k.c +! [Parvatha] renamed convert_progression_order to j2k_convert_progression_order. Modification j2k.c +* [Parvatha] Calculation of number of tile part in each tile in j2k_calculate_tp. Modification j2k.c +! [Parvatha] j2k_setup_encoder to set bit rate limitation for digital cinema compliance with quality option. Modification in j2k.c +* [Parvatha] Equation to check multiple tile precincts. Modification pi.c +! [Parvatha] array size generation of pi->include in pi_initialise_encode().Modification in pi.c +* [Parvatha] modification in pi_create_encode for tile part generation.Modification in pi.c ++ [Parvatha] In tcd_rateallocate a variable stable_threshold which holds the valid threshold value. + This is used to avoid error in case of a wrong threshold value in the last iteration. Modification in tcd.c. + +March 28, 2007 +* [FOD] Fixed an historical bug in t1.c that leaded to the inclusion of useless 0xFF in the codestream. Thanks to Sylvain, Pascal and Parvatha ! + +March 27, 2007 ++ [GB] Improved parsing in OPJViewer, as well some minor aesthetic modifications; support for image rendering with bit depths lower than 8 bits; + can display an arbitrary frame of an MJ2 file (only in B/W, though); can reload a file; better resizing capabilities +* [GB] Following to Hervé's suggestions, all the exit() calls, added by JPWL strict checking in t2.c and j2k.c, + have been substituted with (object free'ing + opj_evt_message(EVT_ERROR) + return) ++ [GB] Added linking to TIFF library in the JPWL VC6 workspaces + +March 23, 2007 +* [antonin] Fixed Makefile.osx and changed Readme.osx accordingly + +March 21, 2007 +* [Parvatha] Fixed j2k_prog_order_list[]. Modifications in j2k.c. +* [Parvatha] Fixed t1_decode_cblks. Modifications in t1.c. + +March 20, 2007 ++ [Parvatha] Added feature for generation of tile parts. Modifications in image_to_j2k.c, openjpeg.c, j2k.c, pi.c ++ [Parvatha] Added function j2k_write_tlm(),to generate TLM marker for a Digital cinema compliant codestream. Modifications in j2k.c. + +March 14, 2007 +* [FOD] Fixed linux makefile, with help from David Fries and Guido + +March 7, 2007 ++ [Parvatha] Added option for Digital cinema profile compliant codestream. This can be chosen by "-cinema2K" or "-cinema4K" for a 2K and 4K compliance respectively. The feature for tileparts has not been implemented in this version. Modification in image_to_j2k.c ++ [Parvatha] Added the Digital Cinema profiles (CINEMA2K and CINEMA4K) to the list of profiles recognized in the codestream SIZ marker segment. Modification in openjpeg.h,j2k.c ++ [Parvatha] Added feature for constant quality within bitrate defined in Digital cinema standards. Modification in tcd.c +! [Parvatha] Modified the method of generation of buffer length. Modification in cio.c + + +March 1, 2007 +* [FOD] Modified codec projects (*.dsp) and makefile to include the tiff library (modified codec/image_to_j2k.dsp codec/j2k_to_image.dsp and codec/makefile) ++ [GB] Zoom capability and decoder settings dialog in OPJViewer; modified JPWL library .dsp project in order to create a library with embedded JPWL functions + +February 28, 2007 ++ [Parvatha] Enabled compression of TIF image format to j2k by tifftoimage() and decompression of codestream to TIF image format using imagetotif(). Modifications in image_to_j2k.c, j2k_to_image.c, convert.c, convert.h +* [antonin] fixed a bug in context numerotation that prevented the RESET switch to work correctly : mqc_reset_enc in mqc.c +* [Fod] Corrected codec Makefile by adding the compilation of "compat/getopt.c" + +February 27, 2007 +* [Parvatha] Made get_file_format function more robust. Modifications in image_to_j2k.c, j2k_to_image.c, getopt.c, getopt.h + +February 26, 2007 ++ [Parvatha] Option to read images from a Folder whose path is specified in the Input parameters by "-ImgDir" along with output decod format specified by "-OutFor" . Modifications in image_to_j2k.c, j2k_to_image.c, getopt.c, getopt.h ++ [Parvatha] Enabling use of multi character input parameters in the codec. Modifications in image_to_j2k.c, j2k_to_image.c, getopt.c, getopt.h + +---------------------- +February 23, 2007 +VERSION 1.1.1 RELEASED +---------------------- + +February 23, 2007 +* [GB] Fixed a copy-and-paste type assignment error (bool instead of int) in the JPWL section of decoder parameters structure in openjpeg.h; minor type-casting in jpwl_lib.c. + As a result, now OPJViewer should run correctly when built against the most current SVN trunk of LibOpenJPEG.lib ++ [GB] Linux makefile for the JPWL module; newlines at end of JPWL files + +February 22, 2007 ++ [FOD] Added the OPJViewer Module (/OPJViewer), developed by Giuseppe Baruffa of the university of Perugia + +February 21, 2007 ++ [FOD] Algorithmic optimizations in t1.c, thanks to Guido J. ! + +February 19, 2007 ++ [FOD] Added OPJ_LIMIT_DECODING enabling us to limit the decoding to main header (modified openjpeg.c, openjpeg.h, j2k.c and j2k.h) + +February 13, 2007 +! [FOD] David Fries suggestions. In image_to_j2k and j2k_to_image, strncpy() functions: instead of specifying the path size macro, let the compiler read the length out of the array entry. +! [FOD] David Fries suggestions. Makefile modified. -fPIC flag used for 64-bit compilation. Move operation (rather than copy) for the dist library creation, and -p flag added. + +January 31, 2007 +! [FOD] Extra tokens at the end of #endif directive corrected in openjpeg.c, j2k.c and image_to_j2k.c -> no more warnings in linux compilation +! [FOD] Linux Makefile added for the codec + +January 30, 2007 +! [FOD] Use of OPJ_PATH_LEN (defined as 4096) to be the maximum allowed size for filenames instead of MAX_PATH which is not always defined. This caused some programs using OpenJPEG to crash. Modifications in openjpeg.h j2k_to_image.c and image_to_j2k.c +! [FOD] Correction of the syntax usage in MJ2_codec/mj2_to_frames.c + +January 23, 2007 +! [FOD] Modification in the context numbers, to reflect what has been specified in standard, in libopenjpeg/t1.h + +December 07, 2006 ++ [Giuseppe Baruffa] Antonin verified that the MacOS build suffered from a missing definition of the "min" macro; I've added this definition (properly #ifndef'ed) into both jpwl.h and rs.h + +December 05, 2006 +* [Giuseppe Baruffa] Better fix of the TPH EPBs bug in JPWL module +* [GB] Fixed the UEP bug in JPWL module; now, during a UEP specification, RS protection or CRC check can be switched off for selected range of packets, and consequently reswitched on without confusing the decoder ++ [GB] Added some lines in the help of JPWL_image_to_j2k, specifying that when using error protection on data packets, this must be paired with header protection, i.e. there cannot be packet protection without header protection + +December 04, 2006 + ++ [Francois-Olivier Devaux] New tag: version1.0 (includes codec and libopenjpeg directories) +Total update of JPWL module + - [FOD] removed directories jpwl/decoder, jpwl/encoder, jpwl/decoder_02, jpwl/encoder_02 + + [FOD] added in JPWL directory crc.h, jpwl.h, rs.h, crc.c, jpwl.c, jpwl_lib.c, rs.c, JPWL_image_to_j2k.dsp, JPWL_j2k_to_image.dsp, LibOpenJPEG_JPWL.dsp, JPWL_image_to_j2k.dsw, JPWL_j2k_to_image.dsw + ! [FOD] Modifications of libopenjpeg to integrate JPWL module (in libopenjpeg directory): j2k.c, j2k.h, openjpeg.c, openjpeg.h, opj_includes.g, t2.c + ! [FOD] Modification of codec to integrate JPWL module (in codec directory): image_to_j2k.c, j2k_to_image.c +* [FOD] Corrected incorrect fprintf() formatting in codec/convert.c +* [FOD] Code optimization usinq vsprintf() command in libopenjpeg/event.c +* [Giuseppe Baruffa] Fixed a bug in TPH EPBs parameters: now, "last in current header" information is correctly signaled + +October 31, 2006 +* [Antonin] fixed a bug in the computation of the mantissa (mu) ++ [Antonin] added the ability to specify the rate as "float" (before : integer) + +August 18, 2006 +* [Antonin] fixed a bug in j2k_to_image.c, that prevented the -l option to work correctly. + +August 4, 2006 +* [Antonin] fixed a bug in pi.c, line 473, that appeared when more than 100 precincts were generated in a resolution level. + +July 28, 2006 ++ [Antonin Descampe] added a readme in /mj2 to warn people that it only works with opj0.97 + +July 21, 2006 +* [Mathieu Malaterre] Install exe and lib and include correctly +* [Mathieu Malaterre] Fixed mem leaks and greyscale bmp +* [Mathieu Malaterre] Fix pgx name length + random memory access +! [Mathieu Malaterre] API is now const + +March 19, 2006 +* [Antonin] fixed a bug in t1.c that prevented in some cases a true lossless compression (thanks to Don Mimlitch for reporting this bug) + +February 12, 2006 +- [Herve Drolon] removed unneeded working variables in opj_tcd_t + +February 04, 2006 +* [galt] fixed a bug in codec/convert.c::imagetobmp + +February 01, 2006 +! [Herve Drolon] changed function definitions of INT and FIX modules to 'inline' ++ [Herve Drolon] added a VERSION resource to the DLL version of OpenJPEG + +January 31, 2006 +* [Mathieu Malaterre] Fix compilation using default openjpeg.dsw +* [Herve Drolon] fixed various minor warnings occuring under icc9 and bcc32 +- [Mathieu Malaterre] Remove all references to OPJ_EXPORT, no declspec in header file anymore ++ [Mathieu Malaterre] Add a def.in file which is a template for Module Definition ++ [Herve Drolon] added MSVC project and compiler directives to build a 'standard' WIN32 DLL +! [Mathieu Malaterre] Update CMake to match the new shared lib system (no more def file) + +January 27, 2006 +* [Antonin Descampe] fixed a two initialization problems in t1.c and tcd.c + +January 26, 2006 +* [Herve Drolon] fixed various minor warnings occuring under gcc +* [__david__] fixed a segfault in codec/image_to_j2k.c & codec/j2k_to_image.c +* [__david__] fixed help option in codec/j2k_to_image & codec/image_to_j2k + +January 25, 2006 +! [Mathieu Malaterre] Sync with ITK repository, also add ref to doxygen +! [Mathieu Malaterre] Add a lot of comments on the CMake build system +! [Mathieu Malaterre] Fix MINGW32 and BORLAND compilation problems. + +January 25, 2006 +* [Antonin Descampe] fixed a problem in convert.c when multiple comments ++ [Antonin Descampe] added cmake files to the project +! [Antonin Descampe] fix.c : replaced "WIN32" by "_MSC_VER" for int64 ++ [Antonin Descampe] added "OPJ_EXPORT" in openjpeg.h to generate shared lib with win32 +! [Antonin Descampe] removed all CtrlM from files + +January 24, 2006 +! [Antonin Descampe] event.c : replaced "WIN32" by "_MSC_VER" for i2a + +January 20, 2006 +* [Antonin Descampe] fixed various minor warnings with gdcm patches + +January 19, 2006 +* [Herve Drolon] fixed a bug in jp2_read_ihdr (need to allocate jp2->comps) + +January 18, 2006 +* [Herve Drolon] changed the name of j2k_realloc to opj_realloc +* [Herve Drolon] fixed a bug in opj_cio_open when saving 48-bit images (wrong buffer size calculation) + +December 8, 2005 +* [Antonin Descampe] fixed a bug when specifying a rate '-r' => no distortion info was available in the index +* [Antonin Descampe] fixed a bug in t1_getwmsedec (stepsize was divided by 8192) + +December 5, 2005 - 1.1.0 diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/CMake/CTestCustom.cmake.in b/gdcm/Utilities/gdcmopenjpeg-v1/CMake/CTestCustom.cmake.in new file mode 100644 index 0000000..9aaafcc --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/CMake/CTestCustom.cmake.in @@ -0,0 +1,21 @@ +# +# For further details regarding this file, +# see http://www.vtk.org/Wiki/CMake_Testing_With_CTest#Customizing_CTest +# + +set (CTEST_CUSTOM_MAXIMUM_NUMBER_OF_ERRORS 50) +set (CTEST_CUSTOM_MAXIMUM_NUMBER_OF_WARNINGS 50) + +set(CTEST_CUSTOM_COVERAGE_EXCLUDE + ${CTEST_CUSTOM_COVERAGE_EXCLUDE} + + # Exclude files from the Testing directories + ".*/Testing/.*" + ) + +set(CTEST_CUSTOM_WARNING_EXCEPTION + ${CTEST_CUSTOM_WARNING_EXCEPTION} + + # Suppress warning caused by intentional messages about deprecation + ".*warning,.* is deprecated" +) diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/CMake/CheckHaveGetopt.cmake b/gdcm/Utilities/gdcmopenjpeg-v1/CMake/CheckHaveGetopt.cmake new file mode 100644 index 0000000..61fca03 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/CMake/CheckHaveGetopt.cmake @@ -0,0 +1,15 @@ +# Check if getopt is present: +include (${CMAKE_ROOT}/Modules/CheckIncludeFile.cmake) +set(DONT_HAVE_GETOPT 1) +if(UNIX) #I am pretty sure only *nix sys have this anyway + CHECK_INCLUDE_FILE("getopt.h" CMAKE_HAVE_GETOPT_H) + # Seems like we need the contrary: + if(CMAKE_HAVE_GETOPT_H) + set(DONT_HAVE_GETOPT 0) + endif() +endif() + +if(DONT_HAVE_GETOPT) + add_definitions(-DDONT_HAVE_GETOPT) +endif() + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/CMake/OpenJPEGConfig.cmake.in b/gdcm/Utilities/gdcmopenjpeg-v1/CMake/OpenJPEGConfig.cmake.in new file mode 100644 index 0000000..3196844 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/CMake/OpenJPEGConfig.cmake.in @@ -0,0 +1,48 @@ +#----------------------------------------------------------------------------- +# +# OPENJPEGConfig.cmake - CMake configuration file for external projects. +# +# This file is configured by OPENJPEG and used by the UseOPENJPEG.cmake +# module to load OPENJPEG's settings for an external project. +@OPENJPEG_CONFIG_INSTALL_ONLY@ +# The OPENJPEG version number. +set(OPENJPEG_MAJOR_VERSION "@OPENJPEG_VERSION_MAJOR@") +set(OPENJPEG_MINOR_VERSION "@OPENJPEG_VERSION_MINOR@") +set(OPENJPEG_BUILD_VERSION "@OPENJPEG_VERSION_BUILD@") + +# The libraries. +set(OPENJPEG_LIBRARIES "@OPENJPEG_LIBRARIES@") + +# The CMake macros dir. +set(OPENJPEG_CMAKE_DIR "@OPENJPEG_CMAKE_DIR_CONFIG@") + +# The configuration options. +set(OPENJPEG_BUILD_SHARED_LIBS "@OPENJPEG_BUILD_SHARED_LIBS@") + +# The "use" file. +set(OPENJPEG_USE_FILE "@OPENJPEG_USE_FILE_CONFIG@") + +get_filename_component(SELF_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) +if(EXISTS ${SELF_DIR}/OpenJPEGTargets.cmake) + # This is an install tree + include(${SELF_DIR}/OpenJPEGTargets.cmake) + get_filename_component(OPENJPEG_INCLUDE_ROOT "${SELF_DIR}/../../@OPENJPEG_INSTALL_INCLUDE_DIR@" ABSOLUTE) + set(OPENJPEG_INCLUDE_DIRS ${OPENJPEG_INCLUDE_ROOT}) + +else() + if(EXISTS ${SELF_DIR}/OpenJPEGExports.cmake) + # This is a build tree + set( OPENJPEG_INCLUDE_DIRS @OPENJPEG_INCLUDE_PATH@) + + include(${SELF_DIR}/OpenJPEGExports.cmake) + + else() + message(FATAL_ERROR "ooops") + endif() +endif() + +set(OPENJPEG_USE_FILE ${SELF_DIR}/UseOPENJPEG.cmake) + +# Backward compatible part: +set(OPENJPEG_FOUND TRUE) + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/CMakeLists.txt b/gdcm/Utilities/gdcmopenjpeg-v1/CMakeLists.txt new file mode 100644 index 0000000..71ab025 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/CMakeLists.txt @@ -0,0 +1,384 @@ +# Main CMakeLists.txt to build the OpenJPEG project using CMake (www.cmake.org) +# Written by Mathieu Malaterre + +# This CMake project will by default create a library called openjpeg +# But if you want to use this project within your own (CMake) project +# you will eventually like to prefix the library to avoid linking confusion +# For this purpose you can define a CMake var: OPENJPEG_NAMESPACE to whatever you like +# e.g.: +# set(OPENJPEG_NAMESPACE "GDCMOPENJPEG") +cmake_minimum_required(VERSION 2.8.9) + +if(NOT OPENJPEG_NAMESPACE) + set(OPENJPEG_NAMESPACE "OPENJPEG") + set(OPENJPEG_STANDALONE 1) +endif() +# In all cases: +string(TOLOWER ${OPENJPEG_NAMESPACE} OPENJPEG_LIBRARY_NAME) + +project(${OPENJPEG_NAMESPACE} C) + +# Do full dependency headers. +include_regular_expression("^.*$") + +#----------------------------------------------------------------------------- +# OPENJPEG version number, useful for packaging and doxygen doc: +set(OPENJPEG_VERSION_MAJOR 1) +set(OPENJPEG_VERSION_MINOR 4) +set(OPENJPEG_VERSION_BUILD 0) +set(OPENJPEG_VERSION + "${OPENJPEG_VERSION_MAJOR}.${OPENJPEG_VERSION_MINOR}.${OPENJPEG_VERSION_BUILD}") +set(PACKAGE_VERSION + "${OPENJPEG_VERSION_MAJOR}.${OPENJPEG_VERSION_MINOR}.${OPENJPEG_VERSION_BUILD}") +# This setting of SOVERSION assumes that any API change +# will increment either the minor or major version number of openjpeg +set(OPENJPEG_LIBRARY_PROPERTIES + VERSION "${OPENJPEG_VERSION_MAJOR}.${OPENJPEG_VERSION_MINOR}.${OPENJPEG_VERSION_BUILD}" + SOVERSION "${OPENJPEG_VERSION_MAJOR}.${OPENJPEG_VERSION_MINOR}" +) +# You will also need to define a value for the following variables: +# OPENJPEG_INSTALL_BIN_DIR - binary dir (executables) +# OPENJPEG_INSTALL_LIB_DIR - library dir (libs) +# OPENJPEG_INSTALL_DATA_DIR - share dir (say, examples, data, etc) +# OPENJPEG_INSTALL_INCLUDE_DIR - include dir (headers) + + +# On Visual Studio 8 MS deprecated C. This removes all 1.276E1265 security +# warnings +if(WIN32) + if(NOT BORLAND) + if(NOT CYGWIN) + if(NOT MINGW) + if(NOT ITK_ENABLE_VISUAL_STUDIO_DEPRECATED_C_WARNINGS) + add_definitions( + -D_CRT_FAR_MAPPINGS_NO_DEPRECATE + -D_CRT_IS_WCTYPE_NO_DEPRECATE + -D_CRT_MANAGED_FP_NO_DEPRECATE + -D_CRT_NONSTDC_NO_DEPRECATE + -D_CRT_SECURE_NO_DEPRECATE + -D_CRT_SECURE_NO_DEPRECATE_GLOBALS + -D_CRT_SETERRORMODE_BEEP_SLEEP_NO_DEPRECATE + -D_CRT_TIME_FUNCTIONS_NO_DEPRECATE + -D_CRT_VCCLRIT_NO_DEPRECATE + -D_SCL_SECURE_NO_DEPRECATE + ) + endif() + endif() + endif() + endif() +endif() + + +# -------------------------------------------------------------------------- +# Install directories + +string(TOLOWER ${PROJECT_NAME} projectname) +set(subdir "${projectname}-${OPENJPEG_VERSION_MAJOR}.${OPENJPEG_VERSION_MINOR}") + +if(NOT OPENJPEG_INSTALL_BIN_DIR) + set(OPENJPEG_INSTALL_BIN_DIR "bin") +endif() + +if(NOT OPENJPEG_INSTALL_LIB_DIR) + set(OPENJPEG_INSTALL_LIB_DIR "lib") +endif() + +if(NOT OPENJPEG_INSTALL_DATA_DIR) + set(OPENJPEG_INSTALL_DATA_DIR "share/${subdir}") +endif() + +if(NOT OPENJPEG_INSTALL_INCLUDE_DIR) + set(OPENJPEG_INSTALL_INCLUDE_DIR "include/") +endif() + +if(NOT OPENJPEG_INSTALL_MAN_DIR) + set(OPENJPEG_INSTALL_MAN_DIR "share/man/") +endif() + +if(NOT OPENJPEG_INSTALL_DOC_DIR) + set(OPENJPEG_INSTALL_DOC_DIR "share/doc/${subdir}") +endif() + +if(NOT OPENJPEG_INSTALL_PACKAGE_DIR) + set(OPENJPEG_INSTALL_PACKAGE_DIR ${OPENJPEG_INSTALL_LIB_DIR}/${subdir} + CACHE INTERNAL "") +endif() + +#----------------------------------------------------------------------------- +# Test for some required system information. +include (${CMAKE_ROOT}/Modules/CMakeBackwardCompatibilityC.cmake) + +#----------------------------------------------------------------------------- +# Test for getopt being available in this system +include (${PROJECT_SOURCE_DIR}/CMake/CheckHaveGetopt.cmake ) + +#----------------------------------------------------------------------------- +# Setup file for setting custom ctest vars +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/CMake/CTestCustom.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/CTestCustom.cmake + @ONLY + ) + +#----------------------------------------------------------------------------- +# OpenJPEG build configuration options. +#option(BUILD_SHARED_LIBS "Build OpenJPEG shared library and link executables against it." ON) + +#----------------------------------------------------------------------------- + + +# configure name mangling to allow multiple libraries to coexist +# peacefully +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/openjpeg_mangle.h.in) +set(MANGLE_PREFIX ${OPENJPEG_LIBRARY_NAME}) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/openjpeg_mangle.h.in + ${CMAKE_CURRENT_BINARY_DIR}/openjpeg_mangle.h + @ONLY) +endif() + +if(NOT OPENJPEG_INSTALL_NO_DEVELOPMENT) + install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/openjpeg_mangle.h + DESTINATION ${OPENJPEG_INSTALL_INCLUDE_DIR} COMPONENT Headers + ) +endif() + +#----------------------------------------------------------------------------- +# Always build the library +include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR}) +subdirs(libopenjpeg) + +#----------------------------------------------------------------------------- +# Build CODEC executables ? +#option(OPJ_BUILD_CODEC "Build the CODEC executables" OFF) +if(OPJ_BUILD_CODEC) + subdirs(codec) +endif() + +#----------------------------------------------------------------------------- +# Build MJ2 executables ? +#option(BUILD_MJ2 "Build the MJ2 executables." OFF) +if(BUILD_MJ2) + subdirs(mj2) +endif() + +#----------------------------------------------------------------------------- +# Build JPWL executables ? +#option(BUILD_JPWL "Build the JPWL executables" OFF) +if(BUILD_JPWL) + subdirs(jpwl) +endif() + +#----------------------------------------------------------------------------- +# Build JP3D executables ? +#option(BUILD_JP3D "Build the JP3D executables" OFF) +if(BUILD_JP3D) + subdirs(jp3d) +endif() + +#----------------------------------------------------------------------------- +# Build INDEXER_JPIP executables ? +#option(BUILD_INDEXER_JPIP "Build the INDEXER_JPIP executables" OFF) +if(BUILD_INDEXER_JPIP AND NOT UNIX) + subdirs(indexer_JPIP) +endif() + +#----------------------------------------------------------------------------- +# Build DOCUMENTATION ? +#option(BUILD_DOC "Build the doxygen documentation" OFF) +if(BUILD_DOC) + subdirs(doc) +endif() + +#----------------------------------------------------------------------------- +# For openjpeg team if they ever want CDash+CMake +option(BUILD_TESTING "Build the tests." OFF) +if(BUILD_TESTING) + enable_testing() + include(CTest) +endif() + +# Adding test with dataset from: +# http://www.crc.ricoh.com/~gormish/jpeg2000conformance/ +# -> wget http://www.crc.ricoh.com/~gormish/jpeg2000conformance/j2kp4files_v1_5.zip +# http://www.jpeg.org/jpeg2000guide/testimages/testimages.html +#----------------------------------------------------------------------------- +# Adding JPEG2000_CONFORMANCE_DATA_ROOT +find_path(JPEG2000_CONFORMANCE_DATA_ROOT testimages.html + ${OPENJPEG_SOURCE_DIR}/../jpeg2000testimages + $ENV{JPEG2000_CONFORMANCE_DATA_ROOT} +) +mark_as_advanced(JPEG2000_CONFORMANCE_DATA_ROOT) + +#----------------------------------------------------------------------------- +# Compiler specific flags: +if(CMAKE_COMPILER_IS_GNUCC) + # For all builds, make sure openjpeg is std99 compliant: + # set(CMAKE_C_FLAGS "-Wall -std=c99 ${CMAKE_C_FLAGS}") # FIXME: this setting prevented us from setting a coverage build. + # Do not use ffast-math for all build, it would produce incorrect results, only set for release: + #set(CMAKE_C_FLAGS_RELEASE "-ffast-math ${CMAKE_C_FLAGS_RELEASE}") +endif() + +# install CHANGES and LICENSE +#install( +# FILES CHANGES +# LICENSE +# DESTINATION ${OPENJPEG_INSTALL_DOC_DIR}) +# +#if(UNIX OR CYGWIN) +# set(CMAKE_INCLUDE_PATH /usr/include /usr/local/include /opt/include +# /opt/local/include /usr/include/libpng /usr/include/libpng14 +# /usr/include/libpng12 /usr/local/include/libpng +# /usr/local/include/libpng14 /usr/local/include/libpng12 +# /opt/include/libpng /opt/include/libpng14 /opt/include/libpng12 +# /opt/local/include/libpng /opt/local/include/libpng14 +# /opt/local/include/libpng12 ) +# set(CMAKE_LIBRARY_PATH /usr/lib /usr/local/lib /opt/lib /opt/local/lib) +#elseif(WIN32) +# set(CMAKE_INCLUDE_PATH ${OPENJPEG_SOURCE_DIR}/libs/libtiff +# ${OPENJPEG_SOURCE_DIR}/libs/png ${OPENJPEG_SOURCE_DIR}/libs/lcms2 +# C:/WINDOWS/system32/user ) +# set(CMAKE_LIBRARY_PATH ${OPENJPEG_SOURCE_DIR}/libs/libtiff +# ${OPENJPEG_SOURCE_DIR}/libs/png ${OPENJPEG_SOURCE_DIR}/libs/lcms2 +# C:/WINDOWS/system32/user ) +#endif() +# +include (${CMAKE_ROOT}/Modules/CheckIncludeFile.cmake) +CHECK_INCLUDE_FILE("strings.h" HAVE_STRINGS_H) +CHECK_INCLUDE_FILE("inttypes.h" HAVE_INTTYPES_H) +CHECK_INCLUDE_FILE("memory.h" HAVE_MEMORY_H) +CHECK_INCLUDE_FILE("stdint.h" HAVE_STDINT_H) +CHECK_INCLUDE_FILE("stdlib.h" HAVE_STDLIB_H) +CHECK_INCLUDE_FILE("string.h" HAVE_STRING_H) +CHECK_INCLUDE_FILE("sys/stat.h" HAVE_SYS_STAT_H) +CHECK_INCLUDE_FILE("sys/types.h" HAVE_SYS_TYPES_H) +CHECK_INCLUDE_FILE("unistd.h" HAVE_UNISTD_H) + +#find_file(HAVE_STRINGS_H_FOUND strings.h) +#if(NOT HAVE_STRINGS_H_FOUND STREQUAL "HAVE_STRINGS_H_FOUND-NOTFOUND") +# find_file(HAVE_STRINGS_H strings.h) +# set(HAS_STRINGS_H 1) +#endif() +#find_file(HAVE_INTTYPES_H_FOUND inttypes.h) +#if(NOT HAVE_INTTYPES_H_FOUND STREQUAL "HAVE_INTTYPES_H_FOUND-NOTFOUND") +# find_file(HAVE_INTTYPES_H inttypes.h) +# set(HAS_INTTYPES_H 1) +#endif() +#find_file(HAVE_MEMORY_H_FOUND memory.h) +#if(NOT HAVE_MEMORY_H_FOUND STREQUAL "HAVE_MEMORY_H_FOUND-NOTFOUND") +# find_file(HAVE_MEMORY_H memory.h) +# set(HAS_MEMORY_H 1) +#endif() +#find_file(HAVE_STDINT_H_FOUND stdint.h) +#if(NOT HAVE_STDINT_H_FOUND STREQUAL "HAVE_STDINT_H_FOUND-NOTFOUND") +# find_file(HAVE_STDINT_H stdint.h) +# set(HAS_STDINT_H 1) +#endif() +#find_file(HAVE_STDLIB_H_FOUND stdlib.h) +#if(NOT HAVE_STDLIB_H_FOUND STREQUAL "HAVE_STDLIB_H_FOUND-NOTFOUND") +# find_file(HAVE_STDLIB_H stdlib.h) +# set(HAS_STDLIB_H 1) +#endif() +#find_file(HAVE_STRING_H_FOUND string.h) +#if(NOT HAVE_STRING_H_FOUND STREQUAL "HAVE_STRING_H_FOUND-NOTFOUND") +# find_file(HAVE_STRING_H string.h) +# set(HAS_STRING_H 1) +#endif() +#find_file(HAVE_SYS_STAT_H_FOUND sys/stat.h) +#if(NOT HAVE_SYS_STAT_H_FOUND STREQUAL "HAVE_SYS_STAT_H_FOUND-NOTFOUND") +# find_file(HAVE_SYS_STAT_H sys/stat.h) +# set(HAS_SYS_STAT_H 1) +#endif() +#find_file(HAVE_SYS_TYPES_H_FOUND sys/types.h) +#if(NOT HAVE_SYS_TYPES_H_FOUND STREQUAL "HAVE_SYS_TYPES_H_FOUND-NOTFOUND") +# find_file(HAVE_SYS_TYPES_H sys/types.h) +# set(HAS_SYS_TYPES_H 1) +#endif() +#find_file(HAVE_UNISTD_H_FOUND unistd.h) +#if(NOT HAVE_UNISTD_H_FOUND STREQUAL "HAVE_UNISTD_H_FOUND-NOTFOUND") +# find_file(HAVE_UNISTD_H unistd.h) +# set(HAS_UNISTD_H 1) +#endif() +# +# Does the system have png library installed ? +# +#find_package(PNG) +# +if(PNG_FOUND) + set(HAVE_PNG_H 1) + set(HAVE_LIBPNG 1) +endif() +# +# Does the system have tiff library installed ? +# +#find_package(TIFF) +# +if(TIFF_FOUND) + set(HAVE_TIFF_H 1) + set(HAVE_LIBTIFF 1) +endif() +# +# +# Does the system have lcms library installed ? +# +set(LCMS_LIB "") +#find_file(LCMS2_HEADER_FOUND lcms2.h) +# +if(LCMS2_HEADER_FOUND STREQUAL "LCMS2_HEADER_FOUND-NOTFOUND") + set(LCMS2_HEADER_FOUND "") +endif() +if(LCMS2_HEADER_FOUND) + find_path(LCMS_INCLUDE_DIR lcms2.h) + if(UNIX OR CYGWIN) + find_library(HAVE_LIBLCMS2 lcms2) + else() + find_library(HAVE_LIBLCMS2 lcms2_static.lib) + endif() + if(HAVE_LIBLCMS2 STREQUAL "HAVE_LIBLCMS2-NOTFOUND") + set(HAVE_LIBLCMS2 "") + endif() + if(HAVE_LIBLCMS2) + set(LCMS_LIB "${HAVE_LIBLCMS2}") + set(HAVE_LCMS2_LIB 1) + set(HAVE_LCMS2_H 1) + endif() +endif() +#if(NOT LCMS2_HEADER_FOUND) +# find_file(LCMS1_HEADER_FOUND lcms.h) +# if(LCMS1_HEADER_FOUND STREQUAL "LCMS1_HEADER_FOUND-NOTFOUND") +# set(LCMS1_HEADER_FOUND "") +# endif() +# if(LCMS1_HEADER_FOUND) +# find_path(LCMS_INCLUDE_DIR lcms.h) +# find_library(HAVE_LIBLCMS1 lcms) +# if(HAVE_LIBLCMS1 STREQUAL "HAVE_LIBLCMS1-NOTFOUND") +# set(HAVE_LIBLCMS1 "") +# endif() +# if(HAVE_LIBLCMS1) +# set(LCMS_LIB "${HAVE_LIBLCMS1}") +# set(HAVE_LCMS1_LIB 1) +# set(HAVE_LCMS1_H 1) +# endif() +# endif() +#endif() +# +# generate opj_config.h +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/opj_configh.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/opj_config.h" + @ONLY +) +#mark_as_advanced( HAVE_INTTYPES_H_FOUND HAVE_LIBLCMS2 HAVE_MEMORY_H +# HAVE_MEMORY_H_FOUND HAVE_STDINT_H_FOUND HAVE_STDLIB_H_FOUND +# HAVE_STRINGS_H HAVE_STRINGS_H_FOUND HAVE_STRING_H +# HAVE_STRING_H_FOUND HAVE_SYS_STAT_H HAVE_SYS_STAT_H_FOUND +# HAVE_SYS_TYPES_H_FOUND HAVE_UNISTD_H_FOUND LCMS2_HEADER_FOUND +# LCMS_INCLUDE_DIR OPJ_BUILD_CODEC ) +# install all targets referenced as OPENJPEGTargets +#install(EXPORT ${GDCM_TARGETS_NAME} DESTINATION ${OPENJPEG_INSTALL_PACKAGE_DIR}) +#configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/CMake/OpenJPEGConfig.cmake.in +# ${CMAKE_CURRENT_BINARY_DIR}/OpenJPEGConfig.cmake +# @ONLY +#) +#install( FILES ${CMAKE_CURRENT_BINARY_DIR}/OpenJPEGConfig.cmake +# DESTINATION ${OPENJPEG_INSTALL_PACKAGE_DIR} +#) diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/CTestConfig.cmake b/gdcm/Utilities/gdcmopenjpeg-v1/CTestConfig.cmake new file mode 100644 index 0000000..6d3866e --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/CTestConfig.cmake @@ -0,0 +1,7 @@ +set(CTEST_PROJECT_NAME "OPENJPEG") +set(CTEST_NIGHTLY_START_TIME "3:00:00 UTC") + +set(CTEST_DROP_METHOD "http") +set(CTEST_DROP_SITE "my.cdash.org") +set(CTEST_DROP_LOCATION "/submit.php?project=OPENJPEG") +set(CTEST_DROP_SITE_CDASH TRUE) diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/CTestCustom.cmake.in b/gdcm/Utilities/gdcmopenjpeg-v1/CTestCustom.cmake.in new file mode 100644 index 0000000..9aaafcc --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/CTestCustom.cmake.in @@ -0,0 +1,21 @@ +# +# For further details regarding this file, +# see http://www.vtk.org/Wiki/CMake_Testing_With_CTest#Customizing_CTest +# + +set (CTEST_CUSTOM_MAXIMUM_NUMBER_OF_ERRORS 50) +set (CTEST_CUSTOM_MAXIMUM_NUMBER_OF_WARNINGS 50) + +set(CTEST_CUSTOM_COVERAGE_EXCLUDE + ${CTEST_CUSTOM_COVERAGE_EXCLUDE} + + # Exclude files from the Testing directories + ".*/Testing/.*" + ) + +set(CTEST_CUSTOM_WARNING_EXCEPTION + ${CTEST_CUSTOM_WARNING_EXCEPTION} + + # Suppress warning caused by intentional messages about deprecation + ".*warning,.* is deprecated" +) diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/INSTALL b/gdcm/Utilities/gdcmopenjpeg-v1/INSTALL new file mode 100644 index 0000000..f205256 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/INSTALL @@ -0,0 +1,105 @@ + +How to build and install openjpeg binaries +========================================== + +UNIX/LINUX similar systems +-------------------------- + +1) Using configure tools + +You can simply type + ./configure [--prefix=/path] + make + +If you are root: + make install + make clean + make distclean + +else: + sudo make install + make clean + make distclean + +Binaries are located in the 'bin' directory. + +If 'configure' does not work on your system please +call './bootstrap.sh'. + +If 'configure' does not find a library or header file, +or to see available configure options, please try +'./configure --help'. + +Note: if Doxygen is found on your system, a target 'docs' +will automatically be created in 'doc/Makefile'. To build +the documentation (it will create an 'html' directory): + cd doc + make docs + +2) Using cmake (see www.cmake.org) + +Type: + cmake . + make + +If you are root: + make install + make clean + +else: + sudo make install + make clean + +Binaries are located in the 'bin' directory. + +Main available cmake flags: +* To specify the install path: '-DCMAKE_INSTALL_PREFIX=/path' +* To build the shared libraries and links the executables against it: '-DBUILD_SHARED_LIBS:bool=on' (default: 'ON') + Note: when using this option, static libraries are not built and executables are dynamically linked. +* To build the CODEC executables: '-DBUILD_CODEC:bool=on' (default: 'ON') +* To build the MJ2 executables: '-DBUILD_MJ2:bool=on' (default: 'OFF') +* To build the JPWL executables and JPWL library: '-DBUILD_JPWL:bool=on' (default: 'OFF') +* To build the JP3D executables and JP3D library: '-DBUILD_JP3D:bool=on' (default: 'OFF') +* [WIN32 ONLY] To build the INDEXER_JPIP executable: '-DBUILD_INDEXER_JPIP:bool=on' (default: 'OFF') +* To build the doxygen documentation: '-DBUILD_DOC:bool=on' (default: 'OFF') +* To enable testing (and automatic result upload to http://my.cdash.org/index.php?project=OPENJPEG): + cmake . -DBUILD_TESTING:BOOL=ON -DJPEG2000_CONFORMANCE_DATA_ROOT:PATH=/path/to/your/JPEG2000/test/files + make + make Experimental + Note : JPEG2000 test files are available here : http://www.crc.ricoh.com/~gormish/jpeg2000conformance/ + +3) Manually using Makefile.nix: +- Manually edit the config.nix file +- Manually create an opj_config.h file from opj_config.h.in.user + and edit this opj_config.h +- Then : (if 'WITH_JPWL' and/or 'WITH_JP3D' are defined in config.nix) + make -f Makefile.nix all + make -f Makefile.nix install + make -f Makefile.nix clean + make -f Makefile.nix uninstall +- If neither 'WITH_JPWL' nor 'WITH_JP3D' is defined in config.nix + and you want to clean/compile/install/uninstall JPWL/JP3D: + call the respective target in the respective directory. + +MACOSX +------ + +The same building procedures as above will soon be available for MACOSX. +The xcode project file has also to be updated. +Right now, the CMake procedure is the only one working. Please refer to instructions above. +If it does not work, try adding the following flag to the cmake command : + '-DCMAKE_OSX_ARCHITECTURES:STRING=i386' + +WINDOWS +------- + +If you're using cygwin, the same procedures as for Unix should work. Otherwise: + +1) Using cmake to generate project files + +Use the cmake procedure above with the '-G ' flag to generate the project +files for the IDE you are using. Type 'cmake --help' for available generators on your platform. + +2) Using the provided project files + +These files are obsolete and will be updated soon. diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/LICENSE b/gdcm/Utilities/gdcmopenjpeg-v1/LICENSE new file mode 100644 index 0000000..d1e5b6a --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/LICENSE @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ \ No newline at end of file diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/LibOpenJPEG.dsp b/gdcm/Utilities/gdcmopenjpeg-v1/LibOpenJPEG.dsp new file mode 100644 index 0000000..1f959bb --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/LibOpenJPEG.dsp @@ -0,0 +1,262 @@ +# Microsoft Developer Studio Project File - Name="LibOpenJPEG" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=LibOpenJPEG - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "LibOpenJPEG.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "LibOpenJPEG.mak" CFG="LibOpenJPEG - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "LibOpenJPEG - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "LibOpenJPEG - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "LibOpenJPEG - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "OPJ_STATIC" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x40c /d "NDEBUG" +# ADD RSC /l 0x40c /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=if not exist dist mkdir dist copy Release\LibOpenJPEG.lib dist copy libopenjpeg\openjpeg.h dist +# End Special Build Tool + +!ELSEIF "$(CFG)" == "LibOpenJPEG - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /D "OPJ_STATIC" /FD /GZ /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x40c /d "_DEBUG" +# ADD RSC /l 0x40c /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"Debug\LibOpenJPEGd.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=if not exist dist mkdir dist copy Debug\LibOpenJPEGd.lib dist copy libopenjpeg\openjpeg.h dist +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "LibOpenJPEG - Win32 Release" +# Name "LibOpenJPEG - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=libopenjpeg\bio.c +# End Source File +# Begin Source File + +SOURCE=libopenjpeg\cio.c +# End Source File +# Begin Source File + +SOURCE=libopenjpeg\dwt.c +# End Source File +# Begin Source File + +SOURCE=libopenjpeg\event.c +# End Source File +# Begin Source File + +SOURCE=libopenjpeg\image.c +# End Source File +# Begin Source File + +SOURCE=libopenjpeg\j2k.c +# End Source File +# Begin Source File + +SOURCE=libopenjpeg\j2k_lib.c +# End Source File +# Begin Source File + +SOURCE=libopenjpeg\jp2.c +# End Source File +# Begin Source File + +SOURCE=libopenjpeg\jpt.c +# End Source File +# Begin Source File + +SOURCE=libopenjpeg\mct.c +# End Source File +# Begin Source File + +SOURCE=libopenjpeg\mqc.c +# End Source File +# Begin Source File + +SOURCE=libopenjpeg\openjpeg.c +# End Source File +# Begin Source File + +SOURCE=libopenjpeg\pi.c +# End Source File +# Begin Source File + +SOURCE=libopenjpeg\raw.c +# End Source File +# Begin Source File + +SOURCE=libopenjpeg\t1.c +# End Source File +# Begin Source File + +SOURCE=libopenjpeg\t2.c +# End Source File +# Begin Source File + +SOURCE=libopenjpeg\tcd.c +# End Source File +# Begin Source File + +SOURCE=libopenjpeg\tgt.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=libopenjpeg\bio.h +# End Source File +# Begin Source File + +SOURCE=libopenjpeg\cio.h +# End Source File +# Begin Source File + +SOURCE=libopenjpeg\dwt.h +# End Source File +# Begin Source File + +SOURCE=libopenjpeg\event.h +# End Source File +# Begin Source File + +SOURCE=libopenjpeg\fix.h +# End Source File +# Begin Source File + +SOURCE=libopenjpeg\image.h +# End Source File +# Begin Source File + +SOURCE=libopenjpeg\int.h +# End Source File +# Begin Source File + +SOURCE=libopenjpeg\j2k.h +# End Source File +# Begin Source File + +SOURCE=libopenjpeg\j2k_lib.h +# End Source File +# Begin Source File + +SOURCE=libopenjpeg\jp2.h +# End Source File +# Begin Source File + +SOURCE=libopenjpeg\jpt.h +# End Source File +# Begin Source File + +SOURCE=libopenjpeg\mct.h +# End Source File +# Begin Source File + +SOURCE=libopenjpeg\mqc.h +# End Source File +# Begin Source File + +SOURCE=libopenjpeg\openjpeg.h +# End Source File +# Begin Source File + +SOURCE=libopenjpeg\opj_includes.h +# End Source File +# Begin Source File + +SOURCE=libopenjpeg\pi.h +# End Source File +# Begin Source File + +SOURCE=libopenjpeg\raw.h +# End Source File +# Begin Source File + +SOURCE=libopenjpeg\t1.h +# End Source File +# Begin Source File + +SOURCE=.\libopenjpeg\t1_luts.h +# End Source File +# Begin Source File + +SOURCE=libopenjpeg\t2.h +# End Source File +# Begin Source File + +SOURCE=libopenjpeg\tcd.h +# End Source File +# Begin Source File + +SOURCE=libopenjpeg\tgt.h +# End Source File +# End Group +# End Target +# End Project diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/LibOpenJPEG.dsw b/gdcm/Utilities/gdcmopenjpeg-v1/LibOpenJPEG.dsw new file mode 100644 index 0000000..97b0b90 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/LibOpenJPEG.dsw @@ -0,0 +1,41 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "DllOpenJPEG"=.\DllOpenJPEG.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "LibOpenJPEG"=.\LibOpenJPEG.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/LibOpenJPEG.sln b/gdcm/Utilities/gdcmopenjpeg-v1/LibOpenJPEG.sln new file mode 100644 index 0000000..6cf1476 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/LibOpenJPEG.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LibOpenJPEG", "LibOpenJPEG.vcproj", "{6A47DBE3-8F80-4ABE-8688-5F8DC620977C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6A47DBE3-8F80-4ABE-8688-5F8DC620977C}.Debug|Win32.ActiveCfg = Debug|Win32 + {6A47DBE3-8F80-4ABE-8688-5F8DC620977C}.Debug|Win32.Build.0 = Debug|Win32 + {6A47DBE3-8F80-4ABE-8688-5F8DC620977C}.Release|Win32.ActiveCfg = Release|Win32 + {6A47DBE3-8F80-4ABE-8688-5F8DC620977C}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/LibOpenJPEG.vcproj b/gdcm/Utilities/gdcmopenjpeg-v1/LibOpenJPEG.vcproj new file mode 100644 index 0000000..43a1c30 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/LibOpenJPEG.vcproj @@ -0,0 +1,642 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/OPJViewer.dsp b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/OPJViewer.dsp new file mode 100644 index 0000000..0776dcb --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/OPJViewer.dsp @@ -0,0 +1,290 @@ +# Microsoft Developer Studio Project File - Name="OPJViewer" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=OPJVIEWER - WIN32 RELEASE +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "OPJViewer.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "OPJViewer.mak" CFG="OPJVIEWER - WIN32 RELEASE" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "OPJViewer - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "OPJViewer - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "OPJViewer - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /G6 /MD /W3 /GX /O2 /I "$(WXWIN28)\lib\vc_lib\msw" /I "$(WXWIN28)\include" /I ".." /I "..\libopenjpeg" /I "$(MXFLIB)" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /D WINVER=0x400 /D "_MT" /D wxUSE_GUI=1 /D "wxUSE_LIBOPENJPEG" /D "OPJ_STATIC" /D "USE_JPWL" /D "USE_JPSEC" /D "OPJ_HTMLABOUT" /D "OPJ_MANYFORMATS" /D "OPJ_INICONFIG" /FR /FD /Zm200 /c +# ADD BASE RSC /l 0x410 /d "NDEBUG" +# ADD RSC /l 0x409 /i "$(WXWIN28)\include" /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib rpcrt4.lib wsock32.lib wxzlib.lib wxregex.lib wxpng.lib wxjpeg.lib wxbase28.lib wxmsw28_core.lib wxmsw28_html.lib wxmsw28_adv.lib wxmsw28_core.lib wxbase28.lib wxtiff.lib wxjpeg.lib wxpng.lib wxzlib.lib wxregex.lib wxexpat.lib LibOpenJPEG_JPWL.lib mxflib.lib /nologo /subsystem:windows /machine:I386 /nodefaultlib:"libcmt.lib" /libpath:"$(WXWIN28)\lib\vc_lib" /libpath:"..\jpwl\Release" /libpath:"$(MXFLIB)\build\msvc\Release" /IGNORE:4089 +# SUBTRACT LINK32 /pdb:none /nodefaultlib +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Desc=Update build number +PostBuild_Cmds=buildupdate.bat +# End Special Build Tool + +!ELSEIF "$(CFG)" == "OPJViewer - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "OPJViewer___Win32_Debug" +# PROP BASE Intermediate_Dir "OPJViewer___Win32_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /I "$(WXWIN28)\INCLUDE" /I "$(WXWIN28)\lib\vc_lib\msw" /I "$(WXWIN28)\include" /I ".." /I "..\libopenjpeg" /I "$(MXFLIB)" /D "_DEBUG" /D "__WXDEBUG__" /D WXDEBUG=1 /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /D WINVER=0x400 /D "_MT" /D wxUSE_GUI=1 /D "wxUSE_LIBOPENJPEG" /D "OPJ_STATIC" /D "USE_JPWL" /D "OPJ_HTMLABOUT" /D "OPJ_INICONFIG" /D "OPJ_MANYFORMATS" /D "USE_JPSEC" /FR /FD /GZ /Zm200 /c +# ADD BASE RSC /l 0x410 /d "_DEBUG" +# ADD RSC /l 0x410 /i "$(WXWIN28)\include" /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib rpcrt4.lib wsock32.lib wxzlibd.lib wxregexd.lib wxpngd.lib wxjpegd.lib wxtiffd.lib wxbase28d.lib wxmsw28d_core.lib wxmsw28d_html.lib wxmsw28d_adv.lib LibOpenJPEG_JPWLd.lib mxflib.lib /nologo /subsystem:windows /debug /machine:I386 /nodefaultlib:"libcmtd.lib" /pdbtype:sept /libpath:"$(WXWIN28)\lib\vc_lib" /libpath:"..\jpwl\Debug" /libpath:"$(MXFLIB)\build\msvc\Debug" +# SUBTRACT LINK32 /pdb:none + +!ENDIF + +# Begin Target + +# Name "OPJViewer - Win32 Release" +# Name "OPJViewer - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\source\imagjpeg2000.cpp +# End Source File +# Begin Source File + +SOURCE=.\source\imagmxf.cpp +# End Source File +# Begin Source File + +SOURCE=..\codec\index.c +# End Source File +# Begin Source File + +SOURCE=.\source\OPJAbout.cpp +# End Source File +# Begin Source File + +SOURCE=.\source\OPJDialogs.cpp +# End Source File +# Begin Source File + +SOURCE=.\source\OPJThreads.cpp +# End Source File +# Begin Source File + +SOURCE=.\source\OPJViewer.cpp +# End Source File +# Begin Source File + +SOURCE=.\source\wxj2kparser.cpp +# End Source File +# Begin Source File + +SOURCE=.\source\wxjp2parser.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\source\about_htm.h +# End Source File +# Begin Source File + +SOURCE=.\source\build.h +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=.\source\imagjpeg2000.h +# End Source File +# Begin Source File + +SOURCE=.\source\imagmxf.h +# End Source File +# Begin Source File + +SOURCE=..\codec\index.h +# End Source File +# Begin Source File + +SOURCE=.\source\OPJViewer.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\source\wx\msw\blank.cur +# End Source File +# Begin Source File + +SOURCE=.\source\wx\msw\bullseye.cur +# End Source File +# Begin Source File + +SOURCE=.\source\wx\msw\cdrom.ico +# End Source File +# Begin Source File + +SOURCE=.\source\wx\msw\computer.ico +# End Source File +# Begin Source File + +SOURCE=.\source\wx\msw\cross.cur +# End Source File +# Begin Source File + +SOURCE=.\source\wx\msw\drive.ico +# End Source File +# Begin Source File + +SOURCE=.\source\wx\msw\file1.ico +# End Source File +# Begin Source File + +SOURCE=.\source\wx\msw\floppy.ico +# End Source File +# Begin Source File + +SOURCE=.\source\wx\msw\folder1.ico +# End Source File +# Begin Source File + +SOURCE=.\source\wx\msw\folder2.ico +# End Source File +# Begin Source File + +SOURCE=.\source\wx\msw\hand.cur +# End Source File +# Begin Source File + +SOURCE=.\source\icon1.xpm +# End Source File +# Begin Source File + +SOURCE=.\source\icon2.xpm +# End Source File +# Begin Source File + +SOURCE=.\source\icon3.xpm +# End Source File +# Begin Source File + +SOURCE=.\source\icon4.xpm +# End Source File +# Begin Source File + +SOURCE=.\source\icon5.xpm +# End Source File +# Begin Source File + +SOURCE=.\source\wx\msw\magnif1.cur +# End Source File +# Begin Source File + +SOURCE=.\source\opj_logo.xpm +# End Source File +# Begin Source File + +SOURCE=.\source\OPJChild.ico +# End Source File +# Begin Source File + +SOURCE=.\source\OPJChild16.xpm +# End Source File +# Begin Source File + +SOURCE=.\source\OPJViewer.ico +# End Source File +# Begin Source File + +SOURCE=.\source\OPJViewer.rc +# End Source File +# Begin Source File + +SOURCE=.\source\OPJViewer16.xpm +# End Source File +# Begin Source File + +SOURCE=.\source\wx\msw\pbrush.cur +# End Source File +# Begin Source File + +SOURCE=.\source\wx\msw\pencil.cur +# End Source File +# Begin Source File + +SOURCE=.\source\wx\msw\pntleft.cur +# End Source File +# Begin Source File + +SOURCE=.\source\wx\msw\pntright.cur +# End Source File +# Begin Source File + +SOURCE=.\source\wx\msw\removble.ico +# End Source File +# Begin Source File + +SOURCE=.\source\wx\msw\rightarr.cur +# End Source File +# Begin Source File + +SOURCE=.\source\wx\msw\roller.cur +# End Source File +# Begin Source File + +SOURCE=.\source\wx\msw\std.ico +# End Source File +# End Group +# End Target +# End Project diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/OPJViewer.dsw b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/OPJViewer.dsw new file mode 100644 index 0000000..b74626f --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/OPJViewer.dsw @@ -0,0 +1,56 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "LibOpenJPEG_JPWL"=..\jpwl\LibOpenJPEG_JPWL.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "OPJViewer"=.\OPJViewer.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name LibOpenJPEG_JPWL + End Project Dependency +}}} + +############################################################################### + +Project: "mxflib"="..\..\..\..\mxflib-1.0.0\build\msvc\mxflib.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/OPJViewer.iss b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/OPJViewer.iss new file mode 100644 index 0000000..0cf20da --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/OPJViewer.iss @@ -0,0 +1,48 @@ +; Script generated by the Inno Setup Script Wizard. +; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! + +[Setup] +AppName=OPJViewer +AppVerName=OPJViewer 0.4 beta +AppPublisher=OpenJPEG +AppPublisherURL=http://www.openjpeg.org +AppSupportURL=http://www.openjpeg.org +AppUpdatesURL=http://www.openjpeg.org +DefaultDirName={pf}\OPJViewer +DefaultGroupName=OPJViewer +OutputDir=setup +OutputBaseFilename=OPJViewer04beta_setup +Compression=lzma +SolidCompression=true +InfoBeforeFile=source\readmebefore.txt +InfoAfterFile=source\readmeafter.txt +LicenseFile=source\license.txt +VersionInfoVersion=0.4.0.0 +VersionInfoCompany=OpenJPEG +VersionInfoDescription=JPEG 2000 viewer +ShowLanguageDialog=yes +SetupIconFile=source\OPJViewer.ico + +[Languages] +Name: english; MessagesFile: compiler:Default.isl + +[Tasks] +Name: desktopicon; Description: {cm:CreateDesktopIcon}; GroupDescription: {cm:AdditionalIcons}; Flags: unchecked + +[Files] +Source: Release\OPJViewer.exe; DestDir: {app}; Flags: ignoreversion +;Source: about\about.htm; DestDir: {app}/about; Flags: ignoreversion +;Source: about\opj_logo.png; DestDir: {app}/about; Flags: ignoreversion +; NOTE: Don't use "Flags: ignoreversion" on any shared system files + +[Icons] +Name: {group}\OPJViewer; Filename: {app}\OPJViewer.exe; WorkingDir: {app}; IconIndex: 0 +Name: {group}\{cm:UninstallProgram,OPJViewer}; Filename: {uninstallexe} +Name: {userdesktop}\OPJViewer; Filename: {app}\OPJViewer.exe; Tasks: desktopicon; WorkingDir: {app}; IconIndex: 0 + +[Run] +Filename: {app}\OPJViewer.exe; Description: {cm:LaunchProgram,OPJViewer}; Flags: nowait postinstall skipifsilent; WorkingDir: {app} + +[Registry] +Root: HKCU; Subkey: Software\OpenJPEG; ValueType: none; ValueData: 1; Flags: uninsdeletekey; Tasks: ; Languages: +Root: HKCU; Subkey: Software\OpenJPEG\OPJViewer; ValueType: none; ValueData: 1; Flags: uninsdeletekey; Tasks: ; Languages: diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/Readme.txt b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/Readme.txt new file mode 100644 index 0000000..fe104bb --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/Readme.txt @@ -0,0 +1,100 @@ +=============================================================================== + JPEG2000 Visualization Software - OPJViewer + + Version 0.4 beta +=============================================================================== + + +1. Scope +============= + +This document describes the installation and use of the OPJViewer in the framework of OpenJPEG library. + +This implementation has been developed using the OpenJPEG library as decoding engine and wxWidgets 2.8 as GUI engine. + +If you find some bugs or if you have problems using the viewer, please send an e-mail to jpwl@diei.unipg.it + +2. Installing the viewer +========================== + +There are two options available, at the moment: + +a) compile from source code +b) download a precompiled binary. + +In order to use option a), it is mandatory to have compiled and built the LibOpenJPEG_JPWL library and the wxWidgets 2.8 framework (you have to download it from http://www.wxwidgets.org/ and compile the wx* libraries). + +2.1. Compiling the source code in Windows +------------------------------------------- + +The steps required to compile the viewer under windows are: + +a) Download at least the libopenjpeg, jpwl, and opjviewer folders from the SVN trunk. +b) Open the OPJViewer.dsw workspace with Visual C++ 6 and activate the "OPJViewer - Win32 Release" configuration. +c) In the configuration settings, go to the C++ tab and modify the wxWidgets paths in order to reflect your wx* install configuration (Preprocessor -> Additional include directories): simply update each instance of the two wx paths, do not remove or add them. +d) In the configuration settings, go to the Link tab and modify the wxWidgets path in order to reflect your wx* install configuration (Input -> Additional library path): simply update the wx path. +e) In the configuration settings, go to the Resources tab and modify the wxWidgets path in order to reflect your wx* install configuration (Additional resource include directories): simply update the wx path. +f) Build! +g) Run! +h) (OPTIONAL) Prepare an installer by compiling the InnoSetup script OPJViewer.iss (you need to download InnoSetup from http://www.jrsoftware.org/isinfo.php). + +2.1.1 Additional libraries +---------------------------- + +Since we are also working on the Digital Cinema JPEG 2000, we are integrating the viewer with the MXF library, which is used to prepare the DCPs for digital movies. You can enable its linking in the code by specifying the USE_MXF preprocessor directive but, remember, the integration is at a very early stage. + +2.2. Compiling the source code in Unix-like systems +----------------------------------------------------- + +The porting is possible and under way. + + +3. General information on the viewer +==================================== + +This viewer is conceived to open and display information and image content of J2K, JP2, and MJ2 files. +The viewer application interface is divided into three main panels: +- a browsing pane; +- a viewing pane; +- a log/peek pane. + +The browsing pane will present the markers or boxes hierarchy, with position (byte number where marker/box starts and stops) and length information (i.e., inner length as signalled by marker/box and total length, with marker/box sign included), in the following form: + +filename +| +|_ #000: Marker/Box short name (Hex code) +| | +| |_ *** Marker/Box long name *** +| |_ startbyte > stopbyte, inner_length + marker/box sign length (total length) +| |_ Additional info, depending on the marker/box type +| |_ ... +| +|_ #001: Marker/Box short name (Hex code) +| | +| |_ ... +| +... + + +The viewing pane will display the decoded image contained in the JPEG 2000 file. +It should display correctly images as large as 4000x2000, provided that a couple of GB of RAM are available. Nothing is known about the display of larger sizes: let us know if you manage to get it working. + + +The log/peek pane is shared among two different subpanels: + +- the log panel will report a lot of debugging info coming out from the wx GUI as well as from the openjpeg library +- the peek pane tries to give a peek on the codestream/file portion which is currently selected in the browsing pane. It shows both hex and ascii values corresponding to the marker/box section. + + +4. Known bugs and limitations +=============================== + +4.1. Bugs +----------- + +* + +4.2. Limitations +------------------ + +* For mj2 files, rendering is only in B/W diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/about/about.htm b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/about/about.htm new file mode 100644 index 0000000..cdde977 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/about/about.htm @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + +
+

+
+OPJViewer v0.2 alpha
+A JPEG 2000 image viewer +
+
OpenJPEG
+The OpenJPEG library is an open-source JPEG 2000 codec written in C language. +In addition to the basic codec, various other features are under development, +among them the JP2 and MJ2 (Motion JPEG 2000) file formats, an indexing tool +useful for the JPIP protocol, JPWL-tools for error-resilience, ... +
+OpenJPEG is © 2002-2007 TELE - Université Catholique de Louvain
+OPJViewer is also © 2005-2007 DSPLab - Università degli studi di Perugia +
+ + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/about/opj_logo.png b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/about/opj_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..0f43840a0184278d122f52bbbc11a943b888eec4 GIT binary patch literal 6500 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 KMNUMnLSTZ7N^0N$ literal 0 HcmV?d00001 diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/buildupdate.bat b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/buildupdate.bat new file mode 100644 index 0000000..d3cfe66 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/buildupdate.bat @@ -0,0 +1,15 @@ +::== buildupdate.bat +@echo off +setLocal EnableDelayedExpansion + +for /f "tokens=2,* delims=^(^) " %%a in ('find /v "" ^< .\source\build.h') do ( +rem echo %%a +set /A M = %%a + 1 +echo Build %%a done^! +echo wxT^("!M!"^) > buildtemp283746825t347 +) + +if exist buildtemp283746825t347 move /Y buildtemp283746825t347 .\source\build.h +if exist buildtemp283746825t347 del /F /Q buildtemp283746825t347 + +::== \ No newline at end of file diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/OPJAbout.cpp b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/OPJAbout.cpp new file mode 100644 index 0000000..f988c72 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/OPJAbout.cpp @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2007, Digital Signal Processing Laboratory, Universita'  degli studi di Perugia (UPG), Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifdef USE_MXF +#include "mxflib/mxflib.h" +#endif // USE_MXF + +#include "OPJViewer.h" + +// about window for the frame +void OPJFrame::OnAbout(wxCommandEvent& WXUNUSED(event)) +{ +#ifdef OPJ_HTMLABOUT +#include "about_htm.h" +#include "opj_logo.xpm" + + wxBoxSizer *topsizer; + wxHtmlWindow *html; + wxDialog dlg(this, wxID_ANY, wxString(_("About"))); + + wxMemoryFSHandler::AddFile(wxT("opj_logo.xpm"), wxBitmap(opj_logo), wxBITMAP_TYPE_XPM); + + topsizer = new wxBoxSizer(wxVERTICAL); + + html = new wxHtmlWindow(&dlg, wxID_ANY, wxDefaultPosition, wxSize(320, 250), wxHW_SCROLLBAR_NEVER); + html->SetBorders(0); + //html->LoadPage(wxT("about/about.htm")); + //html->SetPage("Hello, world!"); + html->SetPage(htmlaboutpage); + html->SetSize(html->GetInternalRepresentation()->GetWidth(), + html->GetInternalRepresentation()->GetHeight()); + + topsizer->Add(html, 1, wxALL, 10); + + topsizer->Add(new wxStaticLine(&dlg, wxID_ANY), 0, wxEXPAND | wxLEFT | wxRIGHT, 10); + + wxButton *bu1 = new wxButton(&dlg, wxID_OK, wxT("OK")); + bu1->SetDefault(); + + topsizer->Add(bu1, 0, wxALL | wxALIGN_RIGHT, 15); + + dlg.SetSizer(topsizer); + topsizer->Fit(&dlg); + + dlg.ShowModal(); + +#else + + wxMessageBox(wxString::Format(OPJ_APPLICATION_TITLEBAR + wxT("\n\n") + wxT("Built with %s and OpenJPEG ") + wxT(OPENJPEG_VERSION) + wxT("\non ") wxT(__DATE__) wxT(", ") wxT(__TIME__) + wxT("\nRunning under %s\n\n") + OPJ_APPLICATION_COPYRIGHT, + wxVERSION_STRING, + wxGetOsDescription().c_str()), + wxT("About ") OPJ_APPLICATION_NAME, + wxOK | wxICON_INFORMATION, + this + ); + +#endif + +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/OPJChild.ico b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/OPJChild.ico new file mode 100644 index 0000000000000000000000000000000000000000..7a127189d5bd3506e6c763205e60631369603798 GIT binary patch literal 1078 zcmd5*OAf*y5PfZ3TaG|nnC`fOmvG&ya1B?z3deD2OuEK5d_pBnOw|})JD?#x6Q#k98nB$Z4$B}T)<#237tT3a3Hb2Bd+{iIWJuIj zaM1$5d|qG_K9+dohYa%_ZbAVjP5I1)nEr@Y`^%r7_gkG$eSV+ul3cu(x4WF~fbLh4 z>q?(X=W9ytb4Pz2mOai0dpa0ux|{mEkA-i2JY`xLm}&34rYCEBEnable(false); + wxPanel* mjpeg2000Settings = CreatePart3SettingsPage(m_settingsNotebook); + if (!wxGetApp().m_enabledeco) + mjpeg2000Settings->Enable(false); +#ifdef USE_JPWL + wxPanel* jpwlSettings = CreatePart11SettingsPage(m_settingsNotebook); + if (!wxGetApp().m_enabledeco) + jpwlSettings->Enable(false); +#endif // USE_JPWL + + m_settingsNotebook->AddPage(mainSettings, wxT("Display"), false); + m_settingsNotebook->AddPage(jpeg2000Settings, wxT("JPEG 2000"), false); + m_settingsNotebook->AddPage(mjpeg2000Settings, wxT("MJPEG 2000"), false); +#ifdef USE_JPWL + m_settingsNotebook->AddPage(jpwlSettings, wxT("JPWL"), false); +#endif // USE_JPWL + + LayoutDialog(); +} + +OPJDecoderDialog::~OPJDecoderDialog() +{ +} + +wxPanel* OPJDecoderDialog::CreateMainSettingsPage(wxWindow* parent) +{ + wxPanel* panel = new wxPanel(parent, wxID_ANY); + + // top sizer + wxBoxSizer *topSizer = new wxBoxSizer(wxVERTICAL); + + // sub top sizer + wxBoxSizer *subtopSizer = new wxBoxSizer(wxVERTICAL); + + // add decoding enabling check box + subtopSizer->Add( + m_enabledecoCheck = new wxCheckBox(panel, OPJDECO_ENABLEDECO, wxT("Enable decoding"), wxDefaultPosition, wxDefaultSize), + 0, wxGROW | wxALL, 5); + m_enabledecoCheck->SetValue(wxGetApp().m_enabledeco); + + // add parsing enabling check box + subtopSizer->Add( + m_enableparseCheck = new wxCheckBox(panel, OPJDECO_ENABLEPARSE, wxT("Enable parsing"), wxDefaultPosition, wxDefaultSize), + 0, wxGROW | wxALL, 5); + m_enableparseCheck->SetValue(wxGetApp().m_enableparse); + + // resize settings, column + wxString choices[] = {wxT("Don't resize"), wxT("Low quality"), wxT("High quality")}; + m_resizeBox = new wxRadioBox(panel, OPJDECO_RESMETHOD, + wxT("Resize method"), + wxDefaultPosition, wxDefaultSize, + WXSIZEOF(choices), + choices, + 1, + wxRA_SPECIFY_ROWS); + m_resizeBox->SetSelection(wxGetApp().m_resizemethod + 1); + + subtopSizer->Add(m_resizeBox, 0, wxGROW | wxALL, 5); + + topSizer->Add(subtopSizer, 1, wxGROW | wxALIGN_CENTRE | wxALL, 5); + + // assign top and fit it + panel->SetSizer(topSizer); + topSizer->Fit(panel); + + return panel; +} + +wxPanel* OPJDecoderDialog::CreatePart3SettingsPage(wxWindow* parent) +{ + wxPanel* panel = new wxPanel(parent, wxID_ANY); + + // top sizer + wxBoxSizer *topSizer = new wxBoxSizer(wxVERTICAL); + + // add some space + //topSizer->AddSpacer(5); + + // sub top sizer + wxBoxSizer *subtopSizer = new wxBoxSizer(wxVERTICAL); + + // frame settings, column + wxStaticBox* frameBox = new wxStaticBox(panel, wxID_ANY, wxT("Frame")); + wxBoxSizer* frameSizer = new wxStaticBoxSizer(frameBox, wxVERTICAL); + + // selected frame number, row + wxBoxSizer* framenumSizer = new wxBoxSizer(wxHORIZONTAL); + + // add some text + framenumSizer->Add(new wxStaticText(panel, wxID_ANY, wxT("&Displayed frame:")), + 0, wxALL | wxALIGN_CENTER_VERTICAL, 5); + + // add some horizontal space + framenumSizer->Add(5, 5, 1, wxALL, 0); + + // add the value control + framenumSizer->Add( + m_framenumCtrl = new wxSpinCtrl(panel, OPJDECO_FRAMENUM, + wxString::Format(wxT("%d"), wxGetApp().m_framenum), + wxDefaultPosition, wxSize(80, wxDefaultCoord), + wxSP_ARROW_KEYS, + 1, 100000, wxGetApp().m_framenum), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5); + + frameSizer->Add(framenumSizer, 0, wxGROW | wxALL, 5); + + subtopSizer->Add(frameSizer, 0, wxGROW | wxALL, 5); + + topSizer->Add(subtopSizer, 1, wxGROW | wxALIGN_CENTRE | wxALL, 5); + + // assign top and fit it + panel->SetSizer(topSizer); + topSizer->Fit(panel); + + return panel; +} + +wxPanel* OPJDecoderDialog::CreatePart1SettingsPage(wxWindow* parent) +{ + wxPanel* panel = new wxPanel(parent, wxID_ANY); + + // top sizer + wxBoxSizer *topSizer = new wxBoxSizer(wxVERTICAL); + + // add some space + //topSizer->AddSpacer(5); + + // sub top sizer + wxBoxSizer *subtopSizer = new wxBoxSizer(wxVERTICAL); + + // resolutions settings, column + wxStaticBox* resolutionBox = new wxStaticBox(panel, wxID_ANY, wxT("Resolutions")); + wxBoxSizer* resolutionSizer = new wxStaticBoxSizer(resolutionBox, wxVERTICAL); + + // reduce factor sizer, row + wxBoxSizer* reduceSizer = new wxBoxSizer(wxHORIZONTAL); + + // add some text + reduceSizer->Add(new wxStaticText(panel, wxID_ANY, wxT("&Reduce factor:")), + 0, wxALL | wxALIGN_CENTER_VERTICAL, 5); + + // add some horizontal space + reduceSizer->Add(5, 5, 1, wxALL, 0); + + // add the value control + reduceSizer->Add( + m_reduceCtrl = new wxSpinCtrl(panel, OPJDECO_REDUCEFACTOR, + wxString::Format(wxT("%d"), wxGetApp().m_reducefactor), + wxDefaultPosition, wxSize(80, wxDefaultCoord), + wxSP_ARROW_KEYS, + 0, 10000, wxGetApp().m_reducefactor), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5); + + resolutionSizer->Add(reduceSizer, 0, wxGROW | wxALL, 5); + + subtopSizer->Add(resolutionSizer, 0, wxGROW | wxALL, 5); + + // quality layer settings, column + wxStaticBox* layerBox = new wxStaticBox(panel, wxID_ANY, wxT("Layers")); + wxBoxSizer* layerSizer = new wxStaticBoxSizer(layerBox, wxVERTICAL); + + // quality layers sizer, row + wxBoxSizer* qualitySizer = new wxBoxSizer(wxHORIZONTAL); + + // add some text + qualitySizer->Add(new wxStaticText(panel, wxID_ANY, wxT("&Quality layers:")), + 0, wxALL | wxALIGN_CENTER_VERTICAL, 5); + + // add some horizontal space + qualitySizer->Add(5, 5, 1, wxALL, 0); + + // add the value control + qualitySizer->Add( + m_layerCtrl = new wxSpinCtrl(panel, OPJDECO_QUALITYLAYERS, + wxString::Format(wxT("%d"), wxGetApp().m_qualitylayers), + wxDefaultPosition, wxSize(80, wxDefaultCoord), + wxSP_ARROW_KEYS, + 0, 100000, wxGetApp().m_qualitylayers), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5); + + layerSizer->Add(qualitySizer, 0, wxGROW | wxALL, 5); + + subtopSizer->Add(layerSizer, 0, wxGROW | wxALL, 5); + + // component settings, column + wxStaticBox* compoBox = new wxStaticBox(panel, wxID_ANY, wxT("Components")); + wxBoxSizer* compoSizer = new wxStaticBoxSizer(compoBox, wxVERTICAL); + + // quality layers sizer, row + wxBoxSizer* numcompsSizer = new wxBoxSizer(wxHORIZONTAL); + + // add some text + numcompsSizer->Add(new wxStaticText(panel, wxID_ANY, wxT("&Component displayed:")), + 0, wxALL | wxALIGN_CENTER_VERTICAL, 5); + + // add some horizontal space + numcompsSizer->Add(5, 5, 1, wxALL, 0); + + // add the value control + numcompsSizer->Add( + m_numcompsCtrl = new wxSpinCtrl(panel, OPJDECO_NUMCOMPS, + wxString::Format(wxT("%d"), wxGetApp().m_components), + wxDefaultPosition, wxSize(80, wxDefaultCoord), + wxSP_ARROW_KEYS, + 0, 100000, wxGetApp().m_components), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5); + m_numcompsCtrl->Enable(true); + + compoSizer->Add(numcompsSizer, 0, wxGROW | wxALL, 5); + + subtopSizer->Add(compoSizer, 0, wxGROW | wxALL, 5); + + topSizer->Add(subtopSizer, 1, wxGROW | wxALIGN_CENTRE | wxALL, 5); + + // assign top and fit it + panel->SetSizer(topSizer); + topSizer->Fit(panel); + + return panel; +} + +#ifdef USE_JPWL +wxPanel* OPJDecoderDialog::CreatePart11SettingsPage(wxWindow* parent) +{ + wxPanel* panel = new wxPanel(parent, wxID_ANY); + + // top sizer + wxBoxSizer *topSizer = new wxBoxSizer(wxVERTICAL); + + // add some space + //topSizer->AddSpacer(5); + + // sub top sizer + wxBoxSizer *subtopSizer = new wxBoxSizer(wxVERTICAL); + + // add JPWL enabling check box + subtopSizer->Add( + m_enablejpwlCheck = new wxCheckBox(panel, OPJDECO_ENABLEJPWL, wxT("Enable JPWL"), wxDefaultPosition, wxDefaultSize), + 0, wxGROW | wxALL, 5); + m_enablejpwlCheck->SetValue(wxGetApp().m_enablejpwl); + + // component settings, column + wxStaticBox* compoBox = new wxStaticBox(panel, wxID_ANY, wxT("Components")); + wxBoxSizer* compoSizer = new wxStaticBoxSizer(compoBox, wxVERTICAL); + + // expected components sizer, row + wxBoxSizer* expcompsSizer = new wxBoxSizer(wxHORIZONTAL); + + // add some text + expcompsSizer->Add(new wxStaticText(panel, wxID_ANY, wxT("&Expected comps.:")), + 0, wxALL | wxALIGN_CENTER_VERTICAL, 5); + + // add some horizontal space + expcompsSizer->Add(5, 5, 1, wxALL, 0); + + // add the value control + expcompsSizer->Add( + m_expcompsCtrl = new wxSpinCtrl(panel, OPJDECO_EXPCOMPS, + wxString::Format(wxT("%d"), wxGetApp().m_expcomps), + wxDefaultPosition, wxSize(80, wxDefaultCoord), + wxSP_ARROW_KEYS, + 1, 100000, wxGetApp().m_expcomps), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5); + m_expcompsCtrl->Enable(wxGetApp().m_enablejpwl); + + compoSizer->Add(expcompsSizer, 0, wxGROW | wxALL, 5); + + subtopSizer->Add(compoSizer, 0, wxGROW | wxALL, 5); + + // tiles settings, column + wxStaticBox* tileBox = new wxStaticBox(panel, wxID_ANY, wxT("Tiles")); + wxBoxSizer* tileSizer = new wxStaticBoxSizer(tileBox, wxVERTICAL); + + // maximum tiles sizer, row + wxBoxSizer* maxtileSizer = new wxBoxSizer(wxHORIZONTAL); + + // add some text + maxtileSizer->Add(new wxStaticText(panel, wxID_ANY, wxT("&Max. no. of tiles:")), + 0, wxALL | wxALIGN_CENTER_VERTICAL, 5); + + // add some horizontal space + maxtileSizer->Add(5, 5, 1, wxALL, 0); + + // add the value control + maxtileSizer->Add( + m_maxtilesCtrl = new wxSpinCtrl(panel, OPJDECO_MAXTILES, + wxString::Format(wxT("%d"), wxGetApp().m_maxtiles), + wxDefaultPosition, wxSize(80, wxDefaultCoord), + wxSP_ARROW_KEYS, + 1, 100000, wxGetApp().m_maxtiles), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5); + m_maxtilesCtrl->Enable(wxGetApp().m_enablejpwl); + + tileSizer->Add(maxtileSizer, 0, wxGROW | wxALL, 5); + + subtopSizer->Add(tileSizer, 0, wxGROW | wxALL, 5); + + topSizer->Add(subtopSizer, 1, wxGROW | wxALIGN_CENTRE | wxALL, 5); + + // assign top and fit it + panel->SetSizer(topSizer); + topSizer->Fit(panel); + + return panel; +} + +void OPJDecoderDialog::OnEnableDeco(wxCommandEvent& event) +{ + size_t pp; + + if (event.IsChecked()) { + wxLogMessage(wxT("Decoding enabled")); + m_resizeBox->Enable(true); + // enable all tabs except ourselves + for (pp = 0; pp < m_settingsNotebook->GetPageCount(); pp++) { + if (m_settingsNotebook->GetPageText(pp) != wxT("Display")) + m_settingsNotebook->GetPage(pp)->Enable(true); + } + } else { + wxLogMessage(wxT("Decoding disabled")); + m_resizeBox->Enable(false); + // disable all tabs except ourselves + for (pp = 0; pp < m_settingsNotebook->GetPageCount(); pp++) { + if (m_settingsNotebook->GetPageText(pp) != wxT("Display")) + m_settingsNotebook->GetPage(pp)->Enable(false); + } + } + +} + +void OPJDecoderDialog::OnEnableJPWL(wxCommandEvent& event) +{ + if (event.IsChecked()) { + wxLogMessage(wxT("JPWL enabled")); + m_expcompsCtrl->Enable(true); + m_maxtilesCtrl->Enable(true); + } else { + wxLogMessage(wxT("JPWL disabled")); + m_expcompsCtrl->Enable(false); + m_maxtilesCtrl->Enable(false); + } + +} + +#endif // USE_JPWL + + + + +// ---------------------------------------------------------------------------- +// OPJEncoderDialog +// ---------------------------------------------------------------------------- + +IMPLEMENT_CLASS(OPJEncoderDialog, wxPropertySheetDialog) + +BEGIN_EVENT_TABLE(OPJEncoderDialog, wxPropertySheetDialog) + EVT_CHECKBOX(OPJENCO_ENABLECOMM, OPJEncoderDialog::OnEnableComm) + EVT_CHECKBOX(OPJENCO_ENABLEINDEX, OPJEncoderDialog::OnEnableIdx) + EVT_CHECKBOX(OPJENCO_ENABLEPOC, OPJEncoderDialog::OnEnablePoc) + EVT_RADIOBUTTON(OPJENCO_RATERADIO, OPJEncoderDialog::OnRadioQualityRate) + EVT_RADIOBUTTON(OPJENCO_QUALITYRADIO, OPJEncoderDialog::OnRadioQualityRate) +#ifdef USE_JPWL + EVT_CHECKBOX(OPJENCO_ENABLEJPWL, OPJEncoderDialog::OnEnableJPWL) + EVT_CHOICE(OPJENCO_HPROT, OPJEncoderDialog::OnHprotSelect) + EVT_CHOICE(OPJENCO_PPROT, OPJEncoderDialog::OnPprotSelect) + EVT_CHOICE(OPJENCO_SENSI, OPJEncoderDialog::OnSensiSelect) +#endif // USE_JPWL +END_EVENT_TABLE() + +OPJEncoderDialog::OPJEncoderDialog(wxWindow* win, int dialogType) +{ + SetExtraStyle(wxDIALOG_EX_CONTEXTHELP|wxWS_EX_VALIDATE_RECURSIVELY); + + Create(win, wxID_ANY, wxT("Encoder settings"), + wxDefaultPosition, wxDefaultSize, + wxDEFAULT_DIALOG_STYLE| (int) wxPlatform::IfNot(wxOS_WINDOWS_CE, wxRESIZE_BORDER) + ); + + CreateButtons(wxOK | wxCANCEL | (int)wxPlatform::IfNot(wxOS_WINDOWS_CE, wxHELP)); + + m_settingsNotebook = GetBookCtrl(); + + wxPanel* jpeg2000_1Settings = CreatePart1_1SettingsPage(m_settingsNotebook); + wxPanel* jpeg2000_2Settings = CreatePart1_2SettingsPage(m_settingsNotebook); + wxPanel* mainSettings = CreateMainSettingsPage(m_settingsNotebook); +#ifdef USE_JPWL + wxPanel* jpwlSettings = CreatePart11SettingsPage(m_settingsNotebook); +#endif // USE_JPWL + +#ifdef USE_JPWL + m_settingsNotebook->AddPage(jpwlSettings, wxT("JPWL"), false); +#endif // USE_JPWL + m_settingsNotebook->AddPage(jpeg2000_1Settings, wxT("JPEG 2000 - 1"), false); + m_settingsNotebook->AddPage(jpeg2000_2Settings, wxT("JPEG 2000 - 2"), false); + m_settingsNotebook->AddPage(mainSettings, wxT("General"), false); + + LayoutDialog(); +} + +OPJEncoderDialog::~OPJEncoderDialog() +{ +} + +wxPanel* OPJEncoderDialog::CreateMainSettingsPage(wxWindow* parent) +{ + wxPanel* panel = new wxPanel(parent, wxID_ANY); + + // top sizer + wxBoxSizer *topSizer = new wxBoxSizer(wxVERTICAL); + + // sub top sizer + wxBoxSizer *subtopSizer = new wxBoxSizer(wxVERTICAL); + + topSizer->Add(subtopSizer, 1, wxGROW | wxALIGN_CENTRE | wxALL, 5); + + // assign top and fit it + panel->SetSizer(topSizer); + topSizer->Fit(panel); + + return panel; +} + +#ifdef USE_JPWL +wxPanel* OPJEncoderDialog::CreatePart11SettingsPage(wxWindow* parent) +{ + wxPanel* panel = new wxPanel(parent, wxID_ANY); + int specno; + + // top sizer + wxBoxSizer *topSizer = new wxBoxSizer(wxVERTICAL); + + // add JPWL enabling check box + topSizer->Add( + m_enablejpwlCheck = new wxCheckBox(panel, OPJENCO_ENABLEJPWL, wxT("Enable JPWL"), + wxDefaultPosition, wxDefaultSize), + 0, wxGROW | wxALL | wxALIGN_CENTER, 5); + m_enablejpwlCheck->SetValue(wxGetApp().m_enablejpwle); + + // sub top sizer + wxFlexGridSizer *subtopSizer = new wxFlexGridSizer(2, 3, 3); + + // header settings, column + wxStaticBox* headerBox = new wxStaticBox(panel, wxID_ANY, wxT("Header protection")); + wxBoxSizer* headerSizer = new wxStaticBoxSizer(headerBox, wxVERTICAL); + + // info sizer, row + wxBoxSizer* info1Sizer = new wxBoxSizer(wxHORIZONTAL); + + // add some text + info1Sizer->Add(new wxStaticText(panel, wxID_ANY, + wxT("Type")), + 0, wxALL | wxALIGN_CENTER_VERTICAL, 1); + + // add some horizontal space + info1Sizer->Add(3, 3, 1, wxALL, 0); + + // add some text + info1Sizer->Add(new wxStaticText(panel, wxID_ANY, + wxT("Tile part")), + 0, wxALL | wxALIGN_CENTER_VERTICAL, 1); + + headerSizer->Add(info1Sizer, 0, wxGROW | wxALL, 0); + + // specify specs + wxString hprotvalues[] = {wxT("None"), wxT("Pred."), wxT("CRC16"), wxT("CRC32"), + wxT("RS37"), wxT("RS38"), wxT("RS40"), wxT("RS43"), wxT("RS45"), wxT("RS48"), + wxT("RS51"), wxT("RS53"), wxT("RS56"), wxT("RS64"), wxT("RS75"), wxT("RS80"), + wxT("RS85"), wxT("RS96"), wxT("RS112"), wxT("RS128")}; + for (specno = 0; specno < MYJPWL_MAX_NO_TILESPECS; specno++) { + + // tile+hprot sizer, row + wxBoxSizer* tilehprotSizer = new wxBoxSizer(wxHORIZONTAL); + + // add the value selection + tilehprotSizer->Add( + m_hprotChoice[specno] = new wxChoice(panel, OPJENCO_HPROT, + wxDefaultPosition, wxSize(60, wxDefaultCoord), + WXSIZEOF(hprotvalues), hprotvalues), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 1); + m_hprotChoice[specno]->SetSelection(wxGetApp().m_hprotsel[specno]); + + // add some horizontal space + tilehprotSizer->Add(3, 3, 1, wxALL, 0); + + // add the value control + tilehprotSizer->Add( + m_htileCtrl[specno] = new wxSpinCtrl(panel, OPJENCO_HTILE, + wxString::Format(wxT("%d"), wxGetApp().m_htileval[specno]), + wxDefaultPosition, wxSize(45, wxDefaultCoord), + wxSP_ARROW_KEYS, + 0, JPWL_MAXIMUM_TILES - 1, 0), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 1); + + headerSizer->Add(tilehprotSizer, 0, wxGROW | wxALL, 0); + } + + wxCommandEvent event1; + OnHprotSelect(event1); + + subtopSizer->Add(headerSizer, 0, wxGROW | wxALL, 3); + + // packet settings, column + wxStaticBox* packetBox = new wxStaticBox(panel, wxID_ANY, wxT("Packet protection")); + wxBoxSizer* packetSizer = new wxStaticBoxSizer(packetBox, wxVERTICAL); + + // info sizer, row + wxBoxSizer* info2Sizer = new wxBoxSizer(wxHORIZONTAL); + + // add some text + info2Sizer->Add(new wxStaticText(panel, wxID_ANY, + wxT("Type")), + 0, wxALL | wxALIGN_CENTER_VERTICAL, 1); + + // add some horizontal space + info2Sizer->Add(3, 3, 1, wxALL, 0); + + // add some text + info2Sizer->Add(new wxStaticText(panel, wxID_ANY, + wxT("Tile part")), + 0, wxALL | wxALIGN_CENTER_VERTICAL, 1); + + // add some horizontal space + info2Sizer->Add(3, 3, 1, wxALL, 0); + + // add some text + info2Sizer->Add(new wxStaticText(panel, wxID_ANY, + wxT("Packet")), + 0, wxALL | wxALIGN_CENTER_VERTICAL, 1); + + packetSizer->Add(info2Sizer, 0, wxGROW | wxALL, 0); + + // specify specs + wxString pprotvalues[] = {wxT("None"), wxT("Pred."), wxT("CRC16"), wxT("CRC32"), + wxT("RS37"), wxT("RS38"), wxT("RS40"), wxT("RS43"), wxT("RS45"), wxT("RS48"), + wxT("RS51"), wxT("RS53"), wxT("RS56"), wxT("RS64"), wxT("RS75"), wxT("RS80"), + wxT("RS85"), wxT("RS96"), wxT("RS112"), wxT("RS128")}; + for (specno = 0; specno < MYJPWL_MAX_NO_TILESPECS; specno++) { + + // tile+pprot sizer, row + wxBoxSizer* tilepprotSizer = new wxBoxSizer(wxHORIZONTAL); + + // add the value selection + tilepprotSizer->Add( + m_pprotChoice[specno] = new wxChoice(panel, OPJENCO_PPROT, + wxDefaultPosition, wxSize(60, wxDefaultCoord), + WXSIZEOF(pprotvalues), pprotvalues), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 1); + m_pprotChoice[specno]->SetSelection(wxGetApp().m_pprotsel[specno]); + + // add some horizontal space + tilepprotSizer->Add(3, 3, 1, wxALL, 0); + + // add the value control + tilepprotSizer->Add( + m_ptileCtrl[specno] = new wxSpinCtrl(panel, OPJENCO_PTILE, + wxString::Format(wxT("%d"), wxGetApp().m_ptileval[specno]), + wxDefaultPosition, wxSize(45, wxDefaultCoord), + wxSP_ARROW_KEYS, + 0, JPWL_MAXIMUM_TILES - 1, 0), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 1); + + // add some horizontal space + tilepprotSizer->Add(3, 3, 1, wxALL, 0); + + // add the value control + tilepprotSizer->Add( + m_ppackCtrl[specno] = new wxSpinCtrl(panel, OPJENCO_PPACK, + wxString::Format(wxT("%d"), wxGetApp().m_ppackval[specno]), + wxDefaultPosition, wxSize(50, wxDefaultCoord), + wxSP_ARROW_KEYS, + 0, 2047, 0), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 1); + + packetSizer->Add(tilepprotSizer, 0, wxGROW | wxALL, 0); + } + + wxCommandEvent event2; + OnPprotSelect(event2); + + subtopSizer->Add(packetSizer, 0, wxGROW | wxALL, 3); + + // sensitivity settings, column + wxStaticBox* sensiBox = new wxStaticBox(panel, wxID_ANY, wxT("Sensitivity")); + wxBoxSizer* sensiSizer = new wxStaticBoxSizer(sensiBox, wxVERTICAL); + + // info sizer, row + wxBoxSizer* info3Sizer = new wxBoxSizer(wxHORIZONTAL); + + // add some text + info3Sizer->Add(new wxStaticText(panel, wxID_ANY, + wxT("Type")), + 0, wxALL | wxALIGN_CENTER_VERTICAL, 1); + + // add some horizontal space + info3Sizer->Add(3, 3, 1, wxALL, 0); + + // add some text + info3Sizer->Add(new wxStaticText(panel, wxID_ANY, + wxT("Tile part")), + 0, wxALL | wxALIGN_CENTER_VERTICAL, 1); + + sensiSizer->Add(info3Sizer, 0, wxGROW | wxALL, 0); + + // specify specs + wxString sensivalues[] = {wxT("None"), wxT("RELATIVE ERROR"), wxT("MSE"), + wxT("MSE REDUCTION"), wxT("PSNR INCREMENT"), wxT("MAXERR"), wxT("TSE")}; + for (specno = 0; specno < MYJPWL_MAX_NO_TILESPECS; specno++) { + + // tile+sensi sizer, row + wxBoxSizer* tilesensiSizer = new wxBoxSizer(wxHORIZONTAL); + + // add the value selection + tilesensiSizer->Add( + m_sensiChoice[specno] = new wxChoice(panel, OPJENCO_SENSI, + wxDefaultPosition, wxSize(110, wxDefaultCoord), + WXSIZEOF(sensivalues), sensivalues), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 1); + m_sensiChoice[specno]->SetSelection(wxGetApp().m_sensisel[specno]); + + // add some horizontal space + tilesensiSizer->Add(3, 3, 1, wxALL, 0); + + // add the value control + tilesensiSizer->Add( + m_stileCtrl[specno] = new wxSpinCtrl(panel, OPJENCO_STILE, + wxString::Format(wxT("%d"), wxGetApp().m_stileval[specno]), + wxDefaultPosition, wxSize(45, wxDefaultCoord), + wxSP_ARROW_KEYS, + 0, JPWL_MAXIMUM_TILES - 1, 0), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 1); + + sensiSizer->Add(tilesensiSizer, 0, wxGROW | wxALL, 0); + } + + wxCommandEvent event3; + OnSensiSelect(event3); + + subtopSizer->Add(sensiSizer, 0, wxGROW | wxALL, 3); + + topSizer->Add(subtopSizer, 1, wxGROW | wxALIGN_CENTRE | wxALL, 5); + + // assign top and fit it + panel->SetSizer(topSizer); + topSizer->Fit(panel); + + return panel; +} +#endif // USE_JPWL + +wxPanel* OPJEncoderDialog::CreatePart1_1SettingsPage(wxWindow* parent) +{ + wxPanel* panel = new wxPanel(parent, wxID_ANY); + + // top sizer + wxBoxSizer *topSizer = new wxBoxSizer(wxVERTICAL); + + // add some space + //topSizer->AddSpacer(5); + + // sub top sizer + wxFlexGridSizer *subtopSizer = new wxFlexGridSizer(2, 3, 3); + + // image settings, column + wxStaticBox* imageBox = new wxStaticBox(panel, wxID_ANY, wxT("Image")); + wxBoxSizer* imageSizer = new wxStaticBoxSizer(imageBox, wxVERTICAL); + + // subsampling factor sizer, row + wxBoxSizer* subsSizer = new wxBoxSizer(wxHORIZONTAL); + + // add some text + subsSizer->Add(new wxStaticText(panel, wxID_ANY, wxT("&Subsampling:")), + 0, wxALL | wxALIGN_CENTER_VERTICAL, 3); + + // add some horizontal space + subsSizer->Add(3, 3, 1, wxALL, 0); + + // add the value control + subsSizer->Add( + m_subsamplingCtrl = new wxTextCtrl(panel, OPJENCO_SUBSAMPLING, + wxGetApp().m_subsampling, + wxDefaultPosition, wxSize(80, wxDefaultCoord), + wxTE_LEFT), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 3); + + imageSizer->Add(subsSizer, 0, wxGROW | wxALL, 3); + + // origin sizer, row + wxBoxSizer* imorigSizer = new wxBoxSizer(wxHORIZONTAL); + + // add some text + imorigSizer->Add(new wxStaticText(panel, wxID_ANY, wxT("&Origin:")), + 0, wxALL | wxALIGN_CENTER_VERTICAL, 3); + + // add some horizontal space + imorigSizer->Add(3, 3, 1, wxALL, 0); + + // add the value control + imorigSizer->Add( + m_originCtrl = new wxTextCtrl(panel, OPJENCO_IMORIG, + wxGetApp().m_origin, + wxDefaultPosition, wxSize(80, wxDefaultCoord), + wxTE_LEFT), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 3); + + imageSizer->Add(imorigSizer, 0, wxGROW | wxALL, 3); + + subtopSizer->Add(imageSizer, 0, wxGROW | wxALL, 3); + + // layer settings, column + wxStaticBox* layerBox = new wxStaticBox(panel, wxID_ANY, wxT("Layers/compression")); + wxBoxSizer* layerSizer = new wxStaticBoxSizer(layerBox, wxVERTICAL); + + // rate factor sizer, row + wxBoxSizer* rateSizer = new wxBoxSizer(wxHORIZONTAL); + + // add some text + /*rateSizer->Add(new wxStaticText(panel, wxID_ANY, wxT("&Rate values:")), + 0, wxALL | wxALIGN_CENTER_VERTICAL, 3);*/ + + // add the radio button + rateSizer->Add( + m_rateRadio = new wxRadioButton(panel, OPJENCO_RATERADIO, wxT("&Rate values"), + wxDefaultPosition, wxDefaultSize, + wxRB_GROUP), + 0, wxALL | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL + ); + m_rateRadio->SetValue(!(wxGetApp().m_enablequality)); + + // add some horizontal space + rateSizer->Add(3, 3, 1, wxALL, 0); + + // add the value control + rateSizer->Add( + m_rateCtrl = new wxTextCtrl(panel, OPJENCO_RATEFACTOR, + wxGetApp().m_rates, + wxDefaultPosition, wxSize(100, wxDefaultCoord), + wxTE_LEFT), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 3); + if (wxGetApp().m_enablequality == true) + m_rateCtrl->Enable(false); + + layerSizer->Add(rateSizer, 0, wxGROW | wxALL, 3); + + // quality factor sizer, row + wxBoxSizer* qualitySizer = new wxBoxSizer(wxHORIZONTAL); + + // add some text + /*qualitySizer->Add(new wxStaticText(panel, wxID_ANY, wxT("&Quality values:")), + 0, wxALL | wxALIGN_CENTER_VERTICAL, 3);*/ + + // add the radio button + qualitySizer->Add( + m_qualityRadio = new wxRadioButton(panel, OPJENCO_QUALITYRADIO, wxT("&Quality values"), + wxDefaultPosition, wxDefaultSize), + 0, wxALL | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL + ); + m_qualityRadio->SetValue(wxGetApp().m_enablequality); + + // add some horizontal space + qualitySizer->Add(3, 3, 1, wxALL, 0); + + // add the value control + qualitySizer->Add( + m_qualityCtrl = new wxTextCtrl(panel, OPJENCO_QUALITYFACTOR, + wxGetApp().m_quality, + wxDefaultPosition, wxSize(100, wxDefaultCoord), + wxTE_LEFT), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 3); + if (wxGetApp().m_enablequality == false) + m_qualityCtrl->Enable(false); + + layerSizer->Add(qualitySizer, 0, wxGROW | wxALL, 3); + + subtopSizer->Add(layerSizer, 0, wxGROW | wxALL, 3); + + // wavelet settings, column + wxStaticBox* transformBox = new wxStaticBox(panel, wxID_ANY, wxT("Transforms")); + wxBoxSizer* transformSizer = new wxStaticBoxSizer(transformBox, wxVERTICAL); + + // multiple component check box + transformSizer->Add( + m_mctCheck = new wxCheckBox(panel, OPJENCO_ENABLEMCT, wxT("Multiple component"), + wxDefaultPosition, wxDefaultSize), + 0, wxGROW | wxALL, 3); + m_mctCheck->SetValue(wxGetApp().m_multicomp); + + // irreversible wavelet check box + transformSizer->Add( + m_irrevCheck = new wxCheckBox(panel, OPJENCO_ENABLEIRREV, wxT("Irreversible wavelet"), + wxDefaultPosition, wxDefaultSize), + 0, wxGROW | wxALL, 3); + m_irrevCheck->SetValue(wxGetApp().m_irreversible); + + // resolution number sizer, row + wxBoxSizer* resnumSizer = new wxBoxSizer(wxHORIZONTAL); + + // add some text + resnumSizer->Add(new wxStaticText(panel, wxID_ANY, wxT("&Resolutions:")), + 0, wxALL | wxALIGN_CENTER_VERTICAL, 3); + + // add some horizontal space + resnumSizer->Add(3, 3, 1, wxALL, 0); + + // add the value control + resnumSizer->Add( + m_resolutionsCtrl = new wxSpinCtrl(panel, OPJENCO_RESNUMBER, + wxString::Format(wxT("%d"), wxGetApp().m_resolutions), + wxDefaultPosition, wxSize(80, wxDefaultCoord), + wxSP_ARROW_KEYS, + 1, 256, 6), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 3); + + transformSizer->Add(resnumSizer, 0, wxGROW | wxALL, 3); + + subtopSizer->Add(transformSizer, 0, wxGROW | wxALL, 3); + + // codestream settings, column + wxStaticBox* codestreamBox = new wxStaticBox(panel, wxID_ANY, wxT("Codestream")); + wxBoxSizer* codestreamSizer = new wxStaticBoxSizer(codestreamBox, wxVERTICAL); + + // codeblock sizer, row + wxBoxSizer* codeblockSizer = new wxBoxSizer(wxHORIZONTAL); + + // add some text + codeblockSizer->Add(new wxStaticText(panel, wxID_ANY, wxT("&Codeblocks size:")), + 0, wxALL | wxALIGN_CENTER_VERTICAL, 3); + + // add some horizontal space + codeblockSizer->Add(3, 3, 1, wxALL, 0); + + // add the value control + codeblockSizer->Add( + m_cbsizeCtrl = new wxTextCtrl(panel, OPJENCO_CODEBLOCKSIZE, + wxGetApp().m_cbsize, + wxDefaultPosition, wxSize(100, wxDefaultCoord), + wxTE_LEFT), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 3); + + codestreamSizer->Add(codeblockSizer, 0, wxGROW | wxALL, 3); + + // precinct sizer, row + wxBoxSizer* precinctSizer = new wxBoxSizer(wxHORIZONTAL); + + // add some text + precinctSizer->Add(new wxStaticText(panel, wxID_ANY, wxT("&Precincts size:")), + 0, wxALL | wxALIGN_CENTER_VERTICAL, 3); + + // add some horizontal space + precinctSizer->Add(3, 3, 1, wxALL, 0); + + // add the value control + precinctSizer->Add( + m_prsizeCtrl = new wxTextCtrl(panel, OPJENCO_PRECINCTSIZE, + wxGetApp().m_prsize, + wxDefaultPosition, wxSize(100, wxDefaultCoord), + wxTE_LEFT), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 3); + + codestreamSizer->Add(precinctSizer, 0, wxGROW | wxALL, 3); + + subtopSizer->Add(codestreamSizer, 0, wxGROW | wxALL, 3); + + // tile settings, column + wxStaticBox* tileBox = new wxStaticBox(panel, wxID_ANY, wxT("Tiles")); + wxBoxSizer* tileSizer = new wxStaticBoxSizer(tileBox, wxVERTICAL); + + // tile size sizer, row + wxBoxSizer* tilesizeSizer = new wxBoxSizer(wxHORIZONTAL); + + // add some text + tilesizeSizer->Add(new wxStaticText(panel, wxID_ANY, wxT("&Size:")), + 0, wxALL | wxALIGN_CENTER_VERTICAL, 3); + + // add some horizontal space + tilesizeSizer->Add(3, 3, 1, wxALL, 0); + + // add the value control + tilesizeSizer->Add( + m_tsizeCtrl = new wxTextCtrl(panel, OPJENCO_TILESIZE, + wxGetApp().m_tsize, + wxDefaultPosition, wxSize(80, wxDefaultCoord), + wxTE_LEFT), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 3); + + tileSizer->Add(tilesizeSizer, 0, wxGROW | wxALL, 3); + + // tile origin sizer, row + wxBoxSizer* tilorigSizer = new wxBoxSizer(wxHORIZONTAL); + + // add some text + tilorigSizer->Add(new wxStaticText(panel, wxID_ANY, wxT("&Origin:")), + 0, wxALL | wxALIGN_CENTER_VERTICAL, 3); + + // add some horizontal space + tilorigSizer->Add(3, 3, 1, wxALL, 0); + + // add the value control + tilorigSizer->Add( + m_toriginCtrl = new wxTextCtrl(panel, OPJENCO_TILORIG, + wxGetApp().m_torigin, + wxDefaultPosition, wxSize(80, wxDefaultCoord), + wxTE_LEFT), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 3); + + tileSizer->Add(tilorigSizer, 0, wxGROW | wxALL, 3); + + subtopSizer->Add(tileSizer, 0, wxGROW | wxALL, 3); + + // progression and profile settings, column + wxString choices[] = {wxT("LRCP"), wxT("RLCP"), wxT("RPCL"), wxT("PCRL"), wxT("CPRL"), + wxT("DCI2K24"), wxT("DCI2K48"), wxT("DCI4K")}; + progressionBox = new wxRadioBox(panel, OPJENCO_PROGRESSION, + wxT("Progression order/profile"), + wxDefaultPosition, wxDefaultSize, + WXSIZEOF(choices), + choices, + 3, + wxRA_SPECIFY_COLS); + progressionBox->SetSelection(wxGetApp().m_progression); + + subtopSizer->Add(progressionBox, 0, wxGROW | wxALL, 3); + + topSizer->Add(subtopSizer, 1, wxGROW | wxALIGN_CENTRE | wxALL, 5); + + // assign top and fit it + panel->SetSizer(topSizer); + topSizer->Fit(panel); + + return panel; +} + +wxPanel* OPJEncoderDialog::CreatePart1_2SettingsPage(wxWindow* parent) +{ + wxPanel* panel = new wxPanel(parent, wxID_ANY); + + // top sizer + wxBoxSizer *topSizer = new wxBoxSizer(wxVERTICAL); + + // add some space + //topSizer->AddSpacer(5); + + // sub top sizer + wxFlexGridSizer *subtopSizer = new wxFlexGridSizer(2, 3, 3); + + // resilience settings, column + wxStaticBox* resilBox = new wxStaticBox(panel, wxID_ANY, wxT("Error resilience")); + wxBoxSizer* resilSizer = new wxStaticBoxSizer(resilBox, wxVERTICAL); + + // resil2 sizer, row + wxBoxSizer* resil2Sizer = new wxBoxSizer(wxHORIZONTAL); + + // SOP check box + resil2Sizer->Add( + m_sopCheck = new wxCheckBox(panel, OPJENCO_ENABLESOP, wxT("SOP"), + wxDefaultPosition, wxDefaultSize), + 0, wxGROW | wxALL, 3); + m_sopCheck->SetValue(wxGetApp().m_enablesop); + + // EPH check box + resil2Sizer->Add( + m_ephCheck = new wxCheckBox(panel, OPJENCO_ENABLEEPH, wxT("EPH"), + wxDefaultPosition, wxDefaultSize), + 0, wxGROW | wxALL, 3); + m_ephCheck->SetValue(wxGetApp().m_enableeph); + + resilSizer->Add(resil2Sizer, 0, wxGROW | wxALL, 3); + + // separation + resilSizer->Add(new wxStaticLine(panel, wxID_ANY), 0, wxEXPAND | wxLEFT | wxRIGHT, 3); + + // resil3 sizer, row + wxFlexGridSizer* resil3Sizer = new wxFlexGridSizer(3, 3, 3); + + // BYPASS check box + resil3Sizer->Add( + m_enablebypassCheck = new wxCheckBox(panel, OPJENCO_ENABLEBYPASS, wxT("BYPASS"), + wxDefaultPosition, wxDefaultSize), + 0, wxGROW | wxALL, 3); + m_enablebypassCheck->SetValue(wxGetApp().m_enablebypass); + + // RESET check box + resil3Sizer->Add( + m_enableresetCheck = new wxCheckBox(panel, OPJENCO_ENABLERESET, wxT("RESET"), + wxDefaultPosition, wxDefaultSize), + 0, wxGROW | wxALL, 3); + m_enableresetCheck->SetValue(wxGetApp().m_enablereset); + + // RESTART check box + resil3Sizer->Add( + m_enablerestartCheck = new wxCheckBox(panel, OPJENCO_ENABLERESTART, wxT("RESTART"), + wxDefaultPosition, wxDefaultSize), + 0, wxGROW | wxALL, 3); + m_enablerestartCheck->SetValue(wxGetApp().m_enablerestart); + + // VSC check box + resil3Sizer->Add( + m_enablevscCheck = new wxCheckBox(panel, OPJENCO_ENABLEVSC, wxT("VSC"), + wxDefaultPosition, wxDefaultSize), + 0, wxGROW | wxALL, 3); + m_enablevscCheck->SetValue(wxGetApp().m_enablevsc); + + // ERTERM check box + resil3Sizer->Add( + m_enableertermCheck = new wxCheckBox(panel, OPJENCO_ENABLEERTERM, wxT("ERTERM"), + wxDefaultPosition, wxDefaultSize), + 0, wxGROW | wxALL, 3); + m_enableertermCheck->SetValue(wxGetApp().m_enableerterm); + + // SEGMARK check box + resil3Sizer->Add( + m_enablesegmarkCheck = new wxCheckBox(panel, OPJENCO_ENABLESEGMARK, wxT("SEGMARK"), + wxDefaultPosition, wxDefaultSize), + 0, wxGROW | wxALL, 3); + m_enablesegmarkCheck->SetValue(wxGetApp().m_enablesegmark); + + resilSizer->Add(resil3Sizer, 0, wxGROW | wxALL, 3); + + subtopSizer->Add(resilSizer, 0, wxGROW | wxALL, 3); + + // ROI settings, column + wxStaticBox* roiBox = new wxStaticBox(panel, wxID_ANY, wxT("Region Of Interest")); + wxBoxSizer* roiSizer = new wxStaticBoxSizer(roiBox, wxVERTICAL); + + // component number sizer, row + wxBoxSizer* roicompSizer = new wxBoxSizer(wxHORIZONTAL); + + // add some text + roicompSizer->Add(new wxStaticText(panel, wxID_ANY, wxT("&Component:")), + 0, wxALL | wxALIGN_CENTER_VERTICAL, 3); + + // add some horizontal space + roicompSizer->Add(3, 3, 1, wxALL, 0); + + // add the value control + roicompSizer->Add( + /*m_layerCtrl =*/ new wxSpinCtrl(panel, OPJENCO_ROICOMP, + wxT("0"), + wxDefaultPosition, wxSize(80, wxDefaultCoord), + wxSP_ARROW_KEYS, + 0, 256, 0), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 3); + + roiSizer->Add(roicompSizer, 0, wxGROW | wxALL, 3); + + // upshift sizer, row + wxBoxSizer* roishiftSizer = new wxBoxSizer(wxHORIZONTAL); + + // add some text + roishiftSizer->Add(new wxStaticText(panel, wxID_ANY, wxT("&Upshift:")), + 0, wxALL | wxALIGN_CENTER_VERTICAL, 3); + + // add some horizontal space + roishiftSizer->Add(3, 3, 1, wxALL, 0); + + // add the value control + roishiftSizer->Add( + /*m_layerCtrl =*/ new wxSpinCtrl(panel, OPJENCO_ROISHIFT, + wxT("0"), + wxDefaultPosition, wxSize(80, wxDefaultCoord), + wxSP_ARROW_KEYS, + 0, 37, 0), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 3); + + roiSizer->Add(roishiftSizer, 0, wxGROW | wxALL, 3); + + subtopSizer->Add(roiSizer, 0, wxGROW | wxALL, 3); + + // POC settings, column + wxStaticBox* pocBox = new wxStaticBox(panel, wxID_ANY, wxT("POC")); + wxBoxSizer* pocSizer = new wxStaticBoxSizer(pocBox, wxVERTICAL); + + // POC check box + pocSizer->Add( + m_enablepocCheck = new wxCheckBox(panel, OPJENCO_ENABLEPOC, wxT("Enabled (tn=rs,cs,le,re,ce,pr)"), + wxDefaultPosition, wxDefaultSize), + 0, wxGROW | wxALL, 3); + m_enablepocCheck->SetValue(wxGetApp().m_enablepoc); + + // POC sizer, row + wxBoxSizer* pocspecSizer = new wxBoxSizer(wxHORIZONTAL); + + // add some text + pocspecSizer->Add(new wxStaticText(panel, wxID_ANY, wxT("&Changes:")), + 0, wxALL | wxALIGN_TOP, 3); + + // add some horizontal space + pocspecSizer->Add(3, 3, 1, wxALL, 0); + + // add the value control + pocspecSizer->Add( + m_pocCtrl = new wxTextCtrl(panel, OPJENCO_POCSPEC, + wxGetApp().m_poc, + wxDefaultPosition, wxSize(140, 60), + wxTE_LEFT | wxTE_MULTILINE), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 3); + m_pocCtrl->Enable(wxGetApp().m_enablepoc); + + pocSizer->Add(pocspecSizer, 0, wxGROW | wxALL, 3); + + subtopSizer->Add(pocSizer, 0, wxGROW | wxALL, 3); + + // Comment settings, column + wxStaticBox* commentBox = new wxStaticBox(panel, wxID_ANY, wxT("Comment")); + wxBoxSizer* commentSizer = new wxStaticBoxSizer(commentBox, wxVERTICAL); + + // commenting check box + commentSizer->Add( + m_enablecommCheck = new wxCheckBox(panel, OPJENCO_ENABLECOMM, wxT("Enabled (empty to reset)"), + wxDefaultPosition, wxDefaultSize), + 0, wxGROW | wxALL, 3); + m_enablecommCheck->SetValue(wxGetApp().m_enablecomm); + + // add some horizontal space + commentSizer->Add(3, 3, 1, wxALL, 0); + + // add the value control + commentSizer->Add( + m_commentCtrl = new wxTextCtrl(panel, OPJENCO_COMMENTTEXT, + wxGetApp().m_comment, + wxDefaultPosition, wxSize(wxDefaultCoord, 60), + wxTE_LEFT | wxTE_MULTILINE), + 0, wxGROW | wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 3); + m_commentCtrl->Enable(wxGetApp().m_enablecomm); + + subtopSizer->Add(commentSizer, 0, wxGROW | wxALL, 3); + + // Index file settings, column + wxStaticBox* indexBox = new wxStaticBox(panel, wxID_ANY, wxT("Indexing")); + wxBoxSizer* indexSizer = new wxStaticBoxSizer(indexBox, wxVERTICAL); + + // indexing check box + indexSizer->Add( + m_enableidxCheck = new wxCheckBox(panel, OPJENCO_ENABLEINDEX, wxT("Enabled"), + wxDefaultPosition, wxDefaultSize), + 0, wxGROW | wxALL, 3); + m_enableidxCheck->SetValue(wxGetApp().m_enableidx); + + // index file sizer, row + wxBoxSizer* indexnameSizer = new wxBoxSizer(wxHORIZONTAL); + + // add some text + indexnameSizer->Add(new wxStaticText(panel, wxID_ANY, wxT("&File name:")), + 0, wxALL | wxALIGN_CENTER_VERTICAL, 3); + + // add some horizontal space + indexnameSizer->Add(3, 3, 1, wxALL, 0); + + // add the value control + indexnameSizer->Add( + m_indexCtrl = new wxTextCtrl(panel, OPJENCO_INDEXNAME, + wxGetApp().m_index, + wxDefaultPosition, wxSize(120, wxDefaultCoord), + wxTE_LEFT), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 3); + m_indexCtrl->Enable(wxGetApp().m_enableidx); + + indexSizer->Add(indexnameSizer, 0, wxGROW | wxALL, 3); + + subtopSizer->Add(indexSizer, 0, wxGROW | wxALL, 3); + + topSizer->Add(subtopSizer, 1, wxGROW | wxALIGN_CENTRE | wxALL, 5); + + // assign top and fit it + panel->SetSizer(topSizer); + topSizer->Fit(panel); + + return panel; +} + +void OPJEncoderDialog::OnEnableComm(wxCommandEvent& event) +{ + if (event.IsChecked()) { + wxLogMessage(wxT("Comment enabled")); + m_commentCtrl->Enable(true); + } else { + wxLogMessage(wxT("Comment disabled")); + m_commentCtrl->Enable(false); + } + +} + +void OPJEncoderDialog::OnEnableIdx(wxCommandEvent& event) +{ + if (event.IsChecked()) { + wxLogMessage(wxT("Index enabled")); + m_indexCtrl->Enable(true); + } else { + wxLogMessage(wxT("Index disabled")); + m_indexCtrl->Enable(false); + } + +} + +void OPJEncoderDialog::OnEnablePoc(wxCommandEvent& event) +{ + if (event.IsChecked()) { + wxLogMessage(wxT("POC enabled")); + m_pocCtrl->Enable(true); + } else { + wxLogMessage(wxT("POC disabled")); + m_pocCtrl->Enable(false); + } + +} + +void OPJEncoderDialog::OnRadioQualityRate(wxCommandEvent& event) +{ + if (event.GetId() == OPJENCO_QUALITYRADIO) { + wxLogMessage(wxT("Quality selected")); + m_rateCtrl->Enable(false); + m_qualityCtrl->Enable(true); + } else { + wxLogMessage(wxT("Rate selected")); + m_rateCtrl->Enable(true); + m_qualityCtrl->Enable(false); + } +} + +#ifdef USE_JPWL +void OPJEncoderDialog::OnEnableJPWL(wxCommandEvent& event) +{ + int specno; + + if (event.IsChecked()) { + wxLogMessage(wxT("JPWL enabled")); + for (specno = 0; specno < MYJPWL_MAX_NO_TILESPECS; specno++) { + m_hprotChoice[specno]->Enable(true); + m_htileCtrl[specno]->Enable(true); + m_pprotChoice[specno]->Enable(true); + m_ptileCtrl[specno]->Enable(true); + m_ppackCtrl[specno]->Enable(true); + m_sensiChoice[specno]->Enable(true); + m_stileCtrl[specno]->Enable(true); + } + OnHprotSelect(event); + OnPprotSelect(event); + OnSensiSelect(event); + } else { + wxLogMessage(wxT("JPWL disabled")); + for (specno = 0; specno < MYJPWL_MAX_NO_TILESPECS; specno++) { + m_hprotChoice[specno]->Enable(false); + m_htileCtrl[specno]->Enable(false); + m_pprotChoice[specno]->Enable(false); + m_ptileCtrl[specno]->Enable(false); + m_ppackCtrl[specno]->Enable(false); + m_sensiChoice[specno]->Enable(false); + m_stileCtrl[specno]->Enable(false); + } + } + +} + +void OPJEncoderDialog::OnHprotSelect(wxCommandEvent& event) +{ + int specno; + + // deactivate properly + for (specno = MYJPWL_MAX_NO_TILESPECS - 1; specno >= 0; specno--) { + if (!m_hprotChoice[specno]->GetSelection()) { + m_hprotChoice[specno]->Enable(false); + m_htileCtrl[specno]->Enable(false); + } else + break; + } + if (specno < (MYJPWL_MAX_NO_TILESPECS - 1)) { + m_hprotChoice[specno + 1]->Enable(true); + m_htileCtrl[specno + 1]->Enable(true); + } + + //wxLogMessage(wxT("hprot changed: %d"), specno); +} + +void OPJEncoderDialog::OnPprotSelect(wxCommandEvent& event) +{ + int specno; + + // deactivate properly + for (specno = MYJPWL_MAX_NO_TILESPECS - 1; specno >= 0; specno--) { + if (!m_pprotChoice[specno]->GetSelection()) { + m_pprotChoice[specno]->Enable(false); + m_ptileCtrl[specno]->Enable(false); + m_ppackCtrl[specno]->Enable(false); + } else + break; + } + if (specno < (MYJPWL_MAX_NO_TILESPECS - 1)) { + m_pprotChoice[specno + 1]->Enable(true); + m_ptileCtrl[specno + 1]->Enable(true); + m_ppackCtrl[specno + 1]->Enable(true); + } + + //wxLogMessage(wxT("pprot changed: %d"), specno); +} + +void OPJEncoderDialog::OnSensiSelect(wxCommandEvent& event) +{ + int specno; + + // deactivate properly + for (specno = MYJPWL_MAX_NO_TILESPECS - 1; specno >= 0; specno--) { + if (!m_sensiChoice[specno]->GetSelection()) { + m_sensiChoice[specno]->Enable(false); + m_stileCtrl[specno]->Enable(false); + } else + break; + } + if (specno < (MYJPWL_MAX_NO_TILESPECS - 1)) { + m_sensiChoice[specno + 1]->Enable(true); + m_stileCtrl[specno + 1]->Enable(true); + } + + //wxLogMessage(wxT("sprot changed: %d"), specno); +} + + +#endif // USE_JPWL + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/OPJThreads.cpp b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/OPJThreads.cpp new file mode 100644 index 0000000..14159ac --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/OPJThreads.cpp @@ -0,0 +1,1268 @@ +/* + * Copyright (c) 2007, Digital Signal Processing Laboratory, Universita'  degli studi di Perugia (UPG), Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "OPJViewer.h" + + +///////////////////////////////////////////////////////////////////// +// Encoding thread class +///////////////////////////////////////////////////////////////////// + +OPJEncoThread::OPJEncoThread(OPJCanvas *canvas) + : wxThread() +{ + m_count = 0; + m_canvas = canvas; +} + +void OPJEncoThread::WriteText(const wxString& text) +{ + wxString msg; + + // before doing any GUI calls we must ensure that this thread is the only + // one doing it! + +#ifndef __WXGTK__ + wxMutexGuiEnter(); +#endif // __WXGTK__ + + msg << text; + m_canvas->WriteText(msg); + +#ifndef __WXGTK__ + wxMutexGuiLeave(); +#endif // __WXGTK__ +} + +void OPJEncoThread::OnExit() +{ + wxCriticalSectionLocker locker(wxGetApp().m_enco_critsect); + + wxArrayThread& ethreads = wxGetApp().m_enco_threads; + ethreads.Remove(this); + + if (ethreads.IsEmpty() ) + { + // signal the main thread that there are no more threads left if it is + // waiting for us + if (wxGetApp().m_enco_waitingUntilAllDone) { + wxGetApp().m_enco_waitingUntilAllDone = false; + wxGetApp().m_enco_semAllDone.Post(); + } + } +} + +void *OPJEncoThread::Entry() +{ + wxString text; + + srand(GetId()); + //int m_countnum = rand() % 9; + //text.Printf(wxT("Deco thread 0x%lx started (priority = %u, time = %d)."), + // GetId(), GetPriority(), m_countnum); + text.Printf(wxT("Enco thread %d started"), m_canvas->m_childframe->m_winnumber); + WriteText(text); + + // set handler properties + wxJPEG2000Handler *jpeg2000handler = (wxJPEG2000Handler *) wxImage::FindHandler(wxBITMAP_TYPE_JPEG2000); + jpeg2000handler->m_subsampling = wxGetApp().m_subsampling; + jpeg2000handler->m_origin = wxGetApp().m_origin; + jpeg2000handler->m_rates = wxGetApp().m_rates; + jpeg2000handler->m_quality = wxGetApp().m_quality; + jpeg2000handler->m_enablequality = wxGetApp().m_enablequality; + jpeg2000handler->m_multicomp = wxGetApp().m_multicomp; + jpeg2000handler->m_irreversible = wxGetApp().m_irreversible; + jpeg2000handler->m_resolutions = wxGetApp().m_resolutions; + jpeg2000handler->m_progression = wxGetApp().m_progression; + jpeg2000handler->m_cbsize = wxGetApp().m_cbsize; + jpeg2000handler->m_prsize = wxGetApp().m_prsize; + jpeg2000handler->m_tsize = wxGetApp().m_tsize; + jpeg2000handler->m_torigin = wxGetApp().m_torigin; + jpeg2000handler->m_enablesop = wxGetApp().m_enablesop; + jpeg2000handler->m_enableeph = wxGetApp().m_enableeph; + jpeg2000handler->m_enablebypass = wxGetApp().m_enablebypass; + jpeg2000handler->m_enablerestart = wxGetApp().m_enablerestart; + jpeg2000handler->m_enablereset = wxGetApp().m_enablereset; + jpeg2000handler->m_enablesegmark = wxGetApp().m_enablesegmark; + jpeg2000handler->m_enableerterm = wxGetApp().m_enableerterm; + jpeg2000handler->m_enablevsc = wxGetApp().m_enablevsc; + jpeg2000handler->m_enableidx = wxGetApp().m_enableidx; + jpeg2000handler->m_index = m_canvas->m_savename.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR) + wxGetApp().m_index; + jpeg2000handler->m_enablecomm = wxGetApp().m_enablecomm; + jpeg2000handler->m_comment = wxGetApp().m_comment; + jpeg2000handler->m_enablepoc = wxGetApp().m_enablepoc; + jpeg2000handler->m_poc = wxGetApp().m_poc; + + // save the file + if (!m_canvas->m_image100.SaveFile(m_canvas->m_savename.GetFullPath(), (wxBitmapType) wxBITMAP_TYPE_JPEG2000)) { + WriteText(wxT("Can't save image")); + return NULL; + } + + text.Printf(wxT("Enco thread %d finished"), m_canvas->m_childframe->m_winnumber); + WriteText(text); + return NULL; +} + + +///////////////////////////////////////////////////////////////////// +// Decoding thread class +///////////////////////////////////////////////////////////////////// +OPJDecoThread::OPJDecoThread(OPJCanvas *canvas) + : wxThread() +{ + m_count = 0; + m_canvas = canvas; +} + +void OPJDecoThread::WriteText(const wxString& text) +{ + wxString msg; + + // we use a fake event and post it for inter-thread gui communication + wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, OPJFRAME_THREADLOGMSG); + event.SetInt(-1); + msg << text; + event.SetString(msg); + wxPostEvent(this->m_canvas->m_childframe->m_frame, event); + +/* + // before doing any GUI calls we must ensure that this thread is the only + // one doing it! + +#ifndef __WXGTK__ + wxMutexGuiEnter(); +#endif // __WXGTK__ + + msg << text; + m_canvas->WriteText(msg); + +#ifndef __WXGTK__ + wxMutexGuiLeave(); +#endif // __WXGTK__ +*/ +} + +void OPJDecoThread::OnExit() +{ + wxCriticalSectionLocker locker(wxGetApp().m_deco_critsect); + + wxArrayThread& dthreads = wxGetApp().m_deco_threads; + dthreads.Remove(this); + + if (dthreads.IsEmpty() ) + { + // signal the main thread that there are no more threads left if it is + // waiting for us + if (wxGetApp().m_deco_waitingUntilAllDone) { + wxGetApp().m_deco_waitingUntilAllDone = false; + wxGetApp().m_deco_semAllDone.Post(); + } + } +} + +void *OPJDecoThread::Entry() +{ + + wxString text; + + //srand(GetId()); + //int m_countnum = rand() % 9; + //text.Printf(wxT("Deco thread 0x%lx started (priority = %u, time = %d)."), + // GetId(), GetPriority(), m_countnum); + + // we have started + text.Printf(wxT("Deco thread %d started"), m_canvas->m_childframe->m_winnumber); + WriteText(text); + + // prepare dummy wximage + wxBitmap bitmap(100, 100); + wxImage image(100, 100, true); //= bitmap.ConvertToImage(); + image.Destroy(); + + // show image full name + WriteText(m_canvas->m_fname.GetFullPath()); + + // set handler properties + wxJPEG2000Handler *jpeg2000handler = (wxJPEG2000Handler *) wxImage::FindHandler(wxBITMAP_TYPE_JPEG2000); + jpeg2000handler->m_reducefactor = wxGetApp().m_reducefactor; + jpeg2000handler->m_qualitylayers = wxGetApp().m_qualitylayers; + jpeg2000handler->m_components = wxGetApp().m_components; + jpeg2000handler->m_framenum = wxGetApp().m_framenum; +#ifdef USE_JPWL + jpeg2000handler->m_enablejpwl = wxGetApp().m_enablejpwl; + jpeg2000handler->m_expcomps = wxGetApp().m_expcomps; + jpeg2000handler->m_maxtiles = wxGetApp().m_maxtiles; +#endif // USE_JPWL + +#ifdef USE_MXF + wxMXFHandler *mxfffhandler = (wxMXFHandler *) wxImage::FindHandler(wxBITMAP_TYPE_MXF); + mxfffhandler->m_reducefactor = wxGetApp().m_reducefactor; + mxfffhandler->m_qualitylayers = wxGetApp().m_qualitylayers; + mxfffhandler->m_components = wxGetApp().m_components; + mxfffhandler->m_framenum = wxGetApp().m_framenum; + mxfffhandler->m_filename = m_canvas->m_fname; +#ifdef USE_JPWL + mxfffhandler->m_enablejpwl = wxGetApp().m_enablejpwl; + mxfffhandler->m_expcomps = wxGetApp().m_expcomps; + mxfffhandler->m_maxtiles = wxGetApp().m_maxtiles; +#endif // USE_JPWL +#endif // USE_MXF + + // if decoding is enabled... + if (wxGetApp().m_enabledeco) { + + // load the file + if (!image.LoadFile(m_canvas->m_fname.GetFullPath(), wxBITMAP_TYPE_ANY, 0)) { + WriteText(wxT("Can't load image!")); + return NULL; + } + + } else { + + // display a warning + if (!image.Create(300, 5, false)) { + WriteText(wxT("Can't create image!")); + return NULL; + } + + } + + // assign 100% image + m_canvas->m_image100 = wxBitmap(image); + + // signal the frame to refresh the canvas + wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, OPJFRAME_VIEWFIT); + event.SetString(wxT("Fit me")); + event.SetInt(m_canvas->m_childframe->m_winnumber); + wxPostEvent(m_canvas->m_childframe->m_frame, event); + + // find a fit-to-width zoom + /*int zooml, wzooml, hzooml; + wxSize clientsize = m_canvas->GetClientSize(); + wzooml = (int) floor(100.0 * (double) clientsize.GetWidth() / (double) (2 * OPJ_CANVAS_BORDER + image.GetWidth())); + hzooml = (int) floor(100.0 * (double) clientsize.GetHeight() / (double) (2 * OPJ_CANVAS_BORDER + image.GetHeight())); + zooml = wxMin(100, wxMin(wzooml, hzooml));*/ + + // fit to width +#ifndef __WXGTK__ + //m_canvas->m_childframe->m_frame->Rescale(zooml, m_canvas->m_childframe); +#endif // __WXGTK__ + + //m_canvas->m_image = m_canvas->m_image100; + //m_canvas->Refresh(); + //m_canvas->SetScrollbars(20, 20, (int)(0.5 + (double) image.GetWidth() / 20.0), (int)(0.5 + (double) image.GetHeight() / 20.0)); + + //text.Printf(wxT("Deco thread 0x%lx finished."), GetId()); + text.Printf(wxT("Deco thread %d finished"), m_canvas->m_childframe->m_winnumber); + WriteText(text); + return NULL; + +} + +///////////////////////////////////////////////////////////////////// +// Parsing thread class +///////////////////////////////////////////////////////////////////// + +OPJParseThread::OPJParseThread(OPJMarkerTree *tree, wxTreeItemId parentid) + : wxThread() +{ + m_count = 0; + m_tree = tree; + m_parentid = parentid; +} + +void OPJParseThread::WriteText(const wxString& text) +{ + wxString msg; + + // we use a fake event and post it for inter-thread gui communication + wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, OPJFRAME_THREADLOGMSG); + event.SetInt(-1); + msg << text; + event.SetString(msg); + wxPostEvent(this->m_tree->m_childframe->m_frame, event); + +/* // before doing any GUI calls we must ensure that this thread is the only + // one doing it! + +#ifndef __WXGTK__ + wxMutexGuiEnter(); +#endif // __WXGTK + + msg << text; + m_tree->WriteText(msg); + +#ifndef __WXGTK__ + wxMutexGuiLeave(); +#endif // __WXGTK*/ +} + +void OPJParseThread::OnExit() +{ + wxCriticalSectionLocker locker(wxGetApp().m_parse_critsect); + + wxArrayThread& threads = wxGetApp().m_parse_threads; + threads.Remove(this); + + if (threads.IsEmpty()) { + // signal the main thread that there are no more threads left if it is + // waiting for us + if (wxGetApp().m_parse_waitingUntilAllDone) { + wxGetApp().m_parse_waitingUntilAllDone = false; + wxGetApp().m_parse_semAllDone.Post(); + } + } +} + +void *OPJParseThread::Entry() +{ + + printf("Entering\n\n"); + + wxString text; + + srand(GetId()); + int m_countnum = rand() % 9; + text.Printf(wxT("Parse thread 0x%lx started (priority = %u, time = %d)."), + GetId(), GetPriority(), m_countnum); + WriteText(text); + LoadFile(m_tree->m_fname); + text.Printf(wxT("Parse thread 0x%lx finished."), GetId()); + WriteText(text); + + + //wxLogMessage(wxT("Entering\n")); //test wxLog thread safeness + + //wxBusyCursor wait; + //wxBusyInfo wait(wxT("Decoding image ...")); + + + /*for ( m_count = 0; m_count < m_countnum; m_count++ ) + { + // check if we were asked to exit + if ( TestDestroy() ) + break; + + text.Printf(wxT("[%u] Parse thread 0x%lx here."), m_count, GetId()); + WriteText(text); + + // wxSleep() can't be called from non-GUI thread! + wxThread::Sleep(10); + }*/ + + // wxLogMessage(text); -- test wxLog thread safeness + + printf("Exiting\n\n"); + + return NULL; +} + + +/////////////////////////////////////////// +// Parsing hread and related +/////////////////////////////////////////// + +#if USE_GENERIC_TREECTRL +BEGIN_EVENT_TABLE(OPJMarkerTree, wxGenericTreeCtrl) +#else +BEGIN_EVENT_TABLE(OPJMarkerTree, wxTreeCtrl) +#endif + /*EVT_TREE_BEGIN_DRAG(TreeTest_Ctrl, OPJMarkerTree::OnBeginDrag) + EVT_TREE_BEGIN_RDRAG(TreeTest_Ctrl, OPJMarkerTree::OnBeginRDrag) + EVT_TREE_END_DRAG(TreeTest_Ctrl, OPJMarkerTree::OnEndDrag)*/ + /*EVT_TREE_BEGIN_LABEL_EDIT(TreeTest_Ctrl, OPJMarkerTree::OnBeginLabelEdit) + EVT_TREE_END_LABEL_EDIT(TreeTest_Ctrl, OPJMarkerTree::OnEndLabelEdit)*/ + /*EVT_TREE_DELETE_ITEM(TreeTest_Ctrl, OPJMarkerTree::OnDeleteItem)*/ +#if 0 // there are so many of those that logging them causes flicker + /*EVT_TREE_GET_INFO(TreeTest_Ctrl, OPJMarkerTree::OnGetInfo)*/ +#endif + /*EVT_TREE_SET_INFO(TreeTest_Ctrl, OPJMarkerTree::OnSetInfo) + EVT_TREE_ITEM_EXPANDED(TreeTest_Ctrl, OPJMarkerTree::OnItemExpanded)*/ + EVT_TREE_ITEM_EXPANDING(TreeTest_Ctrl, OPJMarkerTree::OnItemExpanding) + /*EVT_TREE_ITEM_COLLAPSED(TreeTest_Ctrl, OPJMarkerTree::OnItemCollapsed) + EVT_TREE_ITEM_COLLAPSING(TreeTest_Ctrl, OPJMarkerTree::OnItemCollapsing)*/ + + EVT_TREE_SEL_CHANGED(TreeTest_Ctrl, OPJMarkerTree::OnSelChanged) + /*EVT_TREE_SEL_CHANGING(TreeTest_Ctrl, OPJMarkerTree::OnSelChanging)*/ + /*EVT_TREE_KEY_DOWN(TreeTest_Ctrl, OPJMarkerTree::OnTreeKeyDown)*/ + /*EVT_TREE_ITEM_ACTIVATED(TreeTest_Ctrl, OPJMarkerTree::OnItemActivated)*/ + + // so many differents ways to handle right mouse button clicks... + /*EVT_CONTEXT_MENU(OPJMarkerTree::OnContextMenu)*/ + // EVT_TREE_ITEM_MENU is the preferred event for creating context menus + // on a tree control, because it includes the point of the click or item, + // meaning that no additional placement calculations are required. + EVT_TREE_ITEM_MENU(TreeTest_Ctrl, OPJMarkerTree::OnItemMenu) + /*EVT_TREE_ITEM_RIGHT_CLICK(TreeTest_Ctrl, OPJMarkerTree::OnItemRClick)*/ + + /*EVT_RIGHT_DOWN(OPJMarkerTree::OnRMouseDown) + EVT_RIGHT_UP(OPJMarkerTree::OnRMouseUp) + EVT_RIGHT_DCLICK(OPJMarkerTree::OnRMouseDClick)*/ +END_EVENT_TABLE() + +// OPJMarkerTree implementation +#if USE_GENERIC_TREECTRL +IMPLEMENT_DYNAMIC_CLASS(OPJMarkerTree, wxGenericTreeCtrl) +#else +IMPLEMENT_DYNAMIC_CLASS(OPJMarkerTree, wxTreeCtrl) +#endif + +OPJMarkerTree::OPJMarkerTree(wxWindow *parent, OPJChildFrame *subframe, wxFileName fname, wxString name, const wxWindowID id, + const wxPoint& pos, const wxSize& size, long style) + : wxTreeCtrl(parent, id, pos, size, style) +{ + m_reverseSort = false; + m_fname = fname; + + m_peektextCtrl = ((OPJFrame *) (parent->GetParent()->GetParent()))->m_textCtrlbrowse; + CreateImageList(); + + // Add some items to the tree + //AddTestItemsToTree(5, 5); + int image = wxGetApp().ShowImages() ? OPJMarkerTree::TreeCtrlIcon_Folder : -1; + wxTreeItemId rootId = AddRoot(name, + image, image, + new OPJMarkerData(name)); + + OPJParseThread *pthread = CreateParseThread(0x00, subframe); + if (pthread->Run() != wxTHREAD_NO_ERROR) + wxLogMessage(wxT("Can't start parse thread!")); + else + wxLogMessage(wxT("New parse thread started.")); + + m_childframe = subframe; +} + +void OPJMarkerTree::CreateImageList(int size) +{ + if (size == -1) { + SetImageList(NULL); + return; + } + if (size == 0) + size = m_imageSize; + else + m_imageSize = size; + + // Make an image list containing small icons + wxImageList *images = new wxImageList(size, size, true); + + // should correspond to TreeCtrlIcon_xxx enum + wxBusyCursor wait; + wxIcon icons[5]; + icons[0] = wxIcon(icon1_xpm); + icons[1] = wxIcon(icon2_xpm); + icons[2] = wxIcon(icon3_xpm); + icons[3] = wxIcon(icon4_xpm); + icons[4] = wxIcon(icon5_xpm); + + int sizeOrig = icons[0].GetWidth(); + for (size_t i = 0; i < WXSIZEOF(icons); i++) { + if (size == sizeOrig) { + images->Add(icons[i]); + } else { + images->Add(wxBitmap(wxBitmap(icons[i]).ConvertToImage().Rescale(size, size))); + } + } + + AssignImageList(images); +} + +#if USE_GENERIC_TREECTRL || !defined(__WXMSW__) +void OPJMarkerTree::CreateButtonsImageList(int size) +{ + if ( size == -1 ) { + SetButtonsImageList(NULL); + return; + } + + // Make an image list containing small icons + wxImageList *images = new wxImageList(size, size, true); + + // should correspond to TreeCtrlIcon_xxx enum + wxBusyCursor wait; + wxIcon icons[4]; + icons[0] = wxIcon(icon3_xpm); // closed + icons[1] = wxIcon(icon3_xpm); // closed, selected + icons[2] = wxIcon(icon5_xpm); // open + icons[3] = wxIcon(icon5_xpm); // open, selected + + for ( size_t i = 0; i < WXSIZEOF(icons); i++ ) { + int sizeOrig = icons[i].GetWidth(); + if ( size == sizeOrig ) { + images->Add(icons[i]); + } else { + images->Add(wxBitmap(wxBitmap(icons[i]).ConvertToImage().Rescale(size, size))); + } + } + + AssignButtonsImageList(images); +#else +void OPJMarkerTree::CreateButtonsImageList(int WXUNUSED(size)) +{ +#endif +} + +void OPJParseThread::LoadFile(wxFileName fname) +{ + wxTreeItemId rootid; + + // this is the root node + int image = wxGetApp().ShowImages() ? m_tree->TreeCtrlIcon_Folder : -1; + + if (this->m_parentid) { + // leaf of a tree + rootid = m_parentid; + m_tree->SetItemText(rootid, wxT("Parsing...")); + + } else { + + // delete the existing tree hierarchy + m_tree->DeleteAllItems(); + + // new tree + rootid = m_tree->AddRoot(wxT("Parsing..."), + image, + image, + new OPJMarkerData(fname.GetFullPath()) + ); + //m_tree->SetItemFont(rootid, *wxITALIC_FONT); + m_tree->SetItemBold(rootid); + } + + // open the file + wxFile m_file(fname.GetFullPath().c_str(), wxFile::read); + + // parsing enabled? + if (wxGetApp().m_enableparse) { + + // what is the extension? + if ((fname.GetExt() == wxT("j2k")) || (fname.GetExt() == wxT("j2c"))) { + + // parse the file + ParseJ2KFile(&m_file, 0, m_file.Length(), rootid); + + } else if ((fname.GetExt() == wxT("jp2")) || (fname.GetExt() == wxT("mj2"))) { + + // parse the file + if (this->m_parentid) { + //WriteText(wxT("Only a subsection of jp2")); + OPJMarkerData *data = (OPJMarkerData *) m_tree->GetItemData(rootid); + ParseJ2KFile(&m_file, data->m_start, data->m_length, rootid); + m_tree->Expand(rootid); + + } else { + // as usual + ParseJP2File(&m_file, 0, m_file.Length(), rootid); + } + + } else { + + // unknown extension + WriteText(wxT("Unknown file format!")); + + } + + } + + // this is the root node + if (this->m_parentid) + m_tree->SetItemText(rootid, wxT("Codestream")); + else + //m_tree->SetItemText(rootid, wxString::Format(wxT("%s (%d B)"), fname.GetFullName(), m_file.Length())); + m_tree->SetItemText(rootid, fname.GetFullName()); + + // close the file + m_file.Close(); + + WriteText(wxT("Parsing finished!")); +} + +/*int OPJMarkerTree::OnCompareItems(const wxTreeItemId& item1, + const wxTreeItemId& item2) +{ + if ( m_reverseSort ) + { + // just exchange 1st and 2nd items + return wxTreeCtrl::OnCompareItems(item2, item1); + } + else + { + return wxTreeCtrl::OnCompareItems(item1, item2); + } +}*/ + +/*void OPJMarkerTree::AddItemsRecursively(const wxTreeItemId& idParent, + size_t numChildren, + size_t depth, + size_t folder) +{ + if ( depth > 0 ) + { + bool hasChildren = depth > 1; + + wxString str; + for ( size_t n = 0; n < numChildren; n++ ) + { + // at depth 1 elements won't have any more children + if ( hasChildren ) + str.Printf(wxT("%s child %u"), wxT("Folder"), unsigned(n + 1)); + else + str.Printf(wxT("%s child %u.%u"), wxT("File"), unsigned(folder), unsigned(n + 1)); + + // here we pass to AppendItem() normal and selected item images (we + // suppose that selected image follows the normal one in the enum) + int image, imageSel; + if ( wxGetApp().ShowImages() ) + { + image = depth == 1 ? TreeCtrlIcon_File : TreeCtrlIcon_Folder; + imageSel = image + 1; + } + else + { + image = imageSel = -1; + } + wxTreeItemId id = AppendItem(idParent, str, image, imageSel, + new OPJMarkerData(str)); + + // and now we also set the expanded one (only for the folders) + if ( hasChildren && wxGetApp().ShowImages() ) + { + SetItemImage(id, TreeCtrlIcon_FolderOpened, + wxTreeItemIcon_Expanded); + } + + // remember the last child for OnEnsureVisible() + if ( !hasChildren && n == numChildren - 1 ) + { + m_lastItem = id; + } + + AddItemsRecursively(id, numChildren, depth - 1, n + 1); + } + } + //else: done! +}*/ + +/*void OPJMarkerTree::AddTestItemsToTree(size_t numChildren, + size_t depth) +{ + int image = wxGetApp().ShowImages() ? OPJMarkerTree::TreeCtrlIcon_Folder : -1; + wxTreeItemId rootId = AddRoot(wxT("Root"), + image, image, + new OPJMarkerData(wxT("Root item"))); + if ( image != -1 ) + { + SetItemImage(rootId, TreeCtrlIcon_FolderOpened, wxTreeItemIcon_Expanded); + } + + AddItemsRecursively(rootId, numChildren, depth, 0); + + // set some colours/fonts for testing + SetItemFont(rootId, *wxITALIC_FONT); + + wxTreeItemIdValue cookie; + wxTreeItemId id = GetFirstChild(rootId, cookie); + SetItemTextColour(id, *wxBLUE); + + id = GetNextChild(rootId, cookie); + id = GetNextChild(rootId, cookie); + SetItemTextColour(id, *wxRED); + SetItemBackgroundColour(id, *wxLIGHT_GREY); +}*/ + +/*void OPJMarkerTree::GetItemsRecursively(const wxTreeItemId& idParent, + wxTreeItemIdValue cookie) +{ + wxTreeItemId id; + + if ( !cookie ) + id = GetFirstChild(idParent, cookie); + else + id = GetNextChild(idParent, cookie); + + if ( !id.IsOk() ) + return; + + wxString text = GetItemText(id); + wxLogMessage(text); + + if (ItemHasChildren(id)) + GetItemsRecursively(id); + + GetItemsRecursively(idParent, cookie); +}*/ + +/*void OPJMarkerTree::DoToggleIcon(const wxTreeItemId& item) +{ + int image = (GetItemImage(item) == TreeCtrlIcon_Folder) + ? TreeCtrlIcon_File + : TreeCtrlIcon_Folder; + SetItemImage(item, image, wxTreeItemIcon_Normal); + + image = (GetItemImage(item) == TreeCtrlIcon_FolderSelected) + ? TreeCtrlIcon_FileSelected + : TreeCtrlIcon_FolderSelected; + SetItemImage(item, image, wxTreeItemIcon_Selected); +}*/ + +void OPJMarkerTree::LogEvent(const wxChar *name, const wxTreeEvent& event) +{ + wxTreeItemId item = event.GetItem(); + wxString text; + if ( item.IsOk() ) + text << wxT('"') << GetItemText(item).c_str() << wxT('"'); + else + text = wxT("invalid item"); + wxLogMessage(wxT("%s(%s)"), name, text.c_str()); +} + +OPJParseThread *OPJMarkerTree::CreateParseThread(wxTreeItemId parentid, OPJChildFrame *subframe) +{ + OPJParseThread *pthread = new OPJParseThread(this, parentid); + + if (pthread->Create() != wxTHREAD_NO_ERROR) + wxLogError(wxT("Can't create parse thread!")); + + wxCriticalSectionLocker enter(wxGetApp().m_parse_critsect); + wxGetApp().m_parse_threads.Add(pthread); + + return pthread; +} + + +/*// avoid repetition +#define TREE_EVENT_HANDLER(name) \ +void OPJMarkerTree::name(wxTreeEvent& event) \ +{ \ + LogEvent(_T(#name), event); \ + SetLastItem(wxTreeItemId()); \ + event.Skip(); \ +}*/ + +/*TREE_EVENT_HANDLER(OnBeginRDrag)*/ +/*TREE_EVENT_HANDLER(OnDeleteItem)*/ +/*TREE_EVENT_HANDLER(OnGetInfo) +TREE_EVENT_HANDLER(OnSetInfo)*/ +/*TREE_EVENT_HANDLER(OnItemExpanded) +TREE_EVENT_HANDLER(OnItemExpanding)*/ +/*TREE_EVENT_HANDLER(OnItemCollapsed)*/ +/*TREE_EVENT_HANDLER(OnSelChanged) +TREE_EVENT_HANDLER(OnSelChanging)*/ + +/*#undef TREE_EVENT_HANDLER*/ + +void OPJMarkerTree::OnItemExpanding(wxTreeEvent& event) +{ + wxTreeItemId item = event.GetItem(); + OPJMarkerData* data = (OPJMarkerData *) GetItemData(item); + wxString text; + + if (item.IsOk()) + text << wxT('"') << GetItemText(item).c_str() << wxT('"'); + else + text = wxT("invalid item"); + + if (wxStrcmp(data->GetDesc1(), wxT("INFO-CSTREAM"))) + return; + + wxLogMessage(wxT("Expanding... (%s -> %s, %s, %d, %d)"), + text.c_str(), data->GetDesc1(), data->GetDesc2(), + data->m_start, data->m_length); + + // the codestream box is being asked for expansion + wxTreeItemIdValue cookie; + if (!GetFirstChild(item, cookie).IsOk()) { + OPJParseThread *pthread = CreateParseThread(item); + if (pthread->Run() != wxTHREAD_NO_ERROR) + wxLogMessage(wxT("Can't start parse thread!")); + else + wxLogMessage(wxT("New parse thread started.")); + } +} + +void OPJMarkerTree::OnSelChanged(wxTreeEvent& event) +{ + int bunch_linesize = 16; + int bunch_numlines = 7; + + wxTreeItemId item = event.GetItem(); + OPJMarkerData* data = (OPJMarkerData *) GetItemData(item); + wxString text; + int l, c, pos = 0, pre_pos; + + m_peektextCtrl->Clear(); + + /*text << wxString::Format(wxT("Selected... (%s -> %s, %s, %d, %d)"), + text.c_str(), data->GetDesc1(), data->GetDesc2(), + data->m_start, data->m_length) << wxT("\n");*/ + + // open the file and browse a little + wxFile *fp = new wxFile(m_fname.GetFullPath().c_str(), wxFile::read); + + // go to position claimed + fp->Seek(data->m_start, wxFromStart); + + // read a bunch + int max_read = wxMin(wxFileOffset(bunch_linesize * bunch_numlines), data->m_length - data->m_start + 1); + if (data->m_desc == wxT("MARK (65380)")) { + /*wxLogMessage(data->m_desc);*/ + max_read = data->m_length - data->m_start + 1; + bunch_numlines = (int) ceil((float) max_read / (float) bunch_linesize); + } + unsigned char *buffer = new unsigned char[bunch_linesize * bunch_numlines]; + fp->Read(buffer, max_read); + + // write the file data between start and stop + pos = 0; + for (l = 0; l < bunch_numlines; l++) { + + text << wxString::Format(wxT("%010d:"), data->m_start + pos); + + pre_pos = pos; + + // add hex browsing text + for (c = 0; c < bunch_linesize; c++) { + + if (!(c % 8)) + text << wxT(" "); + + if (pos < max_read) { + text << wxString::Format(wxT("%02X "), buffer[pos]); + } else + text << wxT(" "); + pos++; + } + + text << wxT(" "); + + // add char browsing text + for (c = 0; c < bunch_linesize; c++) { + + if (pre_pos < max_read) { + if ((buffer[pre_pos] == '\n') || + (buffer[pre_pos] == '\t') || + (buffer[pre_pos] == '\0') || + (buffer[pre_pos] == 0x0D) || + (buffer[pre_pos] == 0x0B)) + buffer[pre_pos] = ' '; + text << wxString::FromAscii((char) buffer[pre_pos]) << wxT("."); + } else + text << wxT(" "); + pre_pos++; + } + + text << wxT("\n"); + + } + + // close the file + fp->Close(); + + m_peektextCtrl->WriteText(text); + + delete buffer; +} + +/*void LogKeyEvent(const wxChar *name, const wxKeyEvent& event) +{ + wxString key; + long keycode = event.GetKeyCode(); + { + switch ( keycode ) + { + case WXK_BACK: key = wxT("BACK"); break; + case WXK_TAB: key = wxT("TAB"); break; + case WXK_RETURN: key = wxT("RETURN"); break; + case WXK_ESCAPE: key = wxT("ESCAPE"); break; + case WXK_SPACE: key = wxT("SPACE"); break; + case WXK_DELETE: key = wxT("DELETE"); break; + case WXK_START: key = wxT("START"); break; + case WXK_LBUTTON: key = wxT("LBUTTON"); break; + case WXK_RBUTTON: key = wxT("RBUTTON"); break; + case WXK_CANCEL: key = wxT("CANCEL"); break; + case WXK_MBUTTON: key = wxT("MBUTTON"); break; + case WXK_CLEAR: key = wxT("CLEAR"); break; + case WXK_SHIFT: key = wxT("SHIFT"); break; + case WXK_ALT: key = wxT("ALT"); break; + case WXK_CONTROL: key = wxT("CONTROL"); break; + case WXK_MENU: key = wxT("MENU"); break; + case WXK_PAUSE: key = wxT("PAUSE"); break; + case WXK_CAPITAL: key = wxT("CAPITAL"); break; + case WXK_END: key = wxT("END"); break; + case WXK_HOME: key = wxT("HOME"); break; + case WXK_LEFT: key = wxT("LEFT"); break; + case WXK_UP: key = wxT("UP"); break; + case WXK_RIGHT: key = wxT("RIGHT"); break; + case WXK_DOWN: key = wxT("DOWN"); break; + case WXK_SELECT: key = wxT("SELECT"); break; + case WXK_PRINT: key = wxT("PRINT"); break; + case WXK_EXECUTE: key = wxT("EXECUTE"); break; + case WXK_SNAPSHOT: key = wxT("SNAPSHOT"); break; + case WXK_INSERT: key = wxT("INSERT"); break; + case WXK_HELP: key = wxT("HELP"); break; + case WXK_NUMPAD0: key = wxT("NUMPAD0"); break; + case WXK_NUMPAD1: key = wxT("NUMPAD1"); break; + case WXK_NUMPAD2: key = wxT("NUMPAD2"); break; + case WXK_NUMPAD3: key = wxT("NUMPAD3"); break; + case WXK_NUMPAD4: key = wxT("NUMPAD4"); break; + case WXK_NUMPAD5: key = wxT("NUMPAD5"); break; + case WXK_NUMPAD6: key = wxT("NUMPAD6"); break; + case WXK_NUMPAD7: key = wxT("NUMPAD7"); break; + case WXK_NUMPAD8: key = wxT("NUMPAD8"); break; + case WXK_NUMPAD9: key = wxT("NUMPAD9"); break; + case WXK_MULTIPLY: key = wxT("MULTIPLY"); break; + case WXK_ADD: key = wxT("ADD"); break; + case WXK_SEPARATOR: key = wxT("SEPARATOR"); break; + case WXK_SUBTRACT: key = wxT("SUBTRACT"); break; + case WXK_DECIMAL: key = wxT("DECIMAL"); break; + case WXK_DIVIDE: key = wxT("DIVIDE"); break; + case WXK_F1: key = wxT("F1"); break; + case WXK_F2: key = wxT("F2"); break; + case WXK_F3: key = wxT("F3"); break; + case WXK_F4: key = wxT("F4"); break; + case WXK_F5: key = wxT("F5"); break; + case WXK_F6: key = wxT("F6"); break; + case WXK_F7: key = wxT("F7"); break; + case WXK_F8: key = wxT("F8"); break; + case WXK_F9: key = wxT("F9"); break; + case WXK_F10: key = wxT("F10"); break; + case WXK_F11: key = wxT("F11"); break; + case WXK_F12: key = wxT("F12"); break; + case WXK_F13: key = wxT("F13"); break; + case WXK_F14: key = wxT("F14"); break; + case WXK_F15: key = wxT("F15"); break; + case WXK_F16: key = wxT("F16"); break; + case WXK_F17: key = wxT("F17"); break; + case WXK_F18: key = wxT("F18"); break; + case WXK_F19: key = wxT("F19"); break; + case WXK_F20: key = wxT("F20"); break; + case WXK_F21: key = wxT("F21"); break; + case WXK_F22: key = wxT("F22"); break; + case WXK_F23: key = wxT("F23"); break; + case WXK_F24: key = wxT("F24"); break; + case WXK_NUMLOCK: key = wxT("NUMLOCK"); break; + case WXK_SCROLL: key = wxT("SCROLL"); break; + case WXK_PAGEUP: key = wxT("PAGEUP"); break; + case WXK_PAGEDOWN: key = wxT("PAGEDOWN"); break; + case WXK_NUMPAD_SPACE: key = wxT("NUMPAD_SPACE"); break; + case WXK_NUMPAD_TAB: key = wxT("NUMPAD_TAB"); break; + case WXK_NUMPAD_ENTER: key = wxT("NUMPAD_ENTER"); break; + case WXK_NUMPAD_F1: key = wxT("NUMPAD_F1"); break; + case WXK_NUMPAD_F2: key = wxT("NUMPAD_F2"); break; + case WXK_NUMPAD_F3: key = wxT("NUMPAD_F3"); break; + case WXK_NUMPAD_F4: key = wxT("NUMPAD_F4"); break; + case WXK_NUMPAD_HOME: key = wxT("NUMPAD_HOME"); break; + case WXK_NUMPAD_LEFT: key = wxT("NUMPAD_LEFT"); break; + case WXK_NUMPAD_UP: key = wxT("NUMPAD_UP"); break; + case WXK_NUMPAD_RIGHT: key = wxT("NUMPAD_RIGHT"); break; + case WXK_NUMPAD_DOWN: key = wxT("NUMPAD_DOWN"); break; + case WXK_NUMPAD_PAGEUP: key = wxT("NUMPAD_PAGEUP"); break; + case WXK_NUMPAD_PAGEDOWN: key = wxT("NUMPAD_PAGEDOWN"); break; + case WXK_NUMPAD_END: key = wxT("NUMPAD_END"); break; + case WXK_NUMPAD_BEGIN: key = wxT("NUMPAD_BEGIN"); break; + case WXK_NUMPAD_INSERT: key = wxT("NUMPAD_INSERT"); break; + case WXK_NUMPAD_DELETE: key = wxT("NUMPAD_DELETE"); break; + case WXK_NUMPAD_EQUAL: key = wxT("NUMPAD_EQUAL"); break; + case WXK_NUMPAD_MULTIPLY: key = wxT("NUMPAD_MULTIPLY"); break; + case WXK_NUMPAD_ADD: key = wxT("NUMPAD_ADD"); break; + case WXK_NUMPAD_SEPARATOR: key = wxT("NUMPAD_SEPARATOR"); break; + case WXK_NUMPAD_SUBTRACT: key = wxT("NUMPAD_SUBTRACT"); break; + case WXK_NUMPAD_DECIMAL: key = wxT("NUMPAD_DECIMAL"); break; + + default: + { + if ( keycode < 128 && wxIsprint((int)keycode) ) + key.Printf(wxT("'%c'"), (char)keycode); + else if ( keycode > 0 && keycode < 27 ) + key.Printf(_("Ctrl-%c"), wxT('A') + keycode - 1); + else + key.Printf(wxT("unknown (%ld)"), keycode); + } + } + } + + wxLogMessage(wxT("%s event: %s (flags = %c%c%c%c)"), + name, + key.c_str(), + event.ControlDown() ? wxT('C') : wxT('-'), + event.AltDown() ? wxT('A') : wxT('-'), + event.ShiftDown() ? wxT('S') : wxT('-'), + event.MetaDown() ? wxT('M') : wxT('-')); +} + +void OPJMarkerTree::OnTreeKeyDown(wxTreeEvent& event) +{ + LogKeyEvent(wxT("Tree key down "), event.GetKeyEvent()); + + event.Skip(); +}*/ + +/*void OPJMarkerTree::OnBeginDrag(wxTreeEvent& event) +{ + // need to explicitly allow drag + if ( event.GetItem() != GetRootItem() ) + { + m_draggedItem = event.GetItem(); + + wxLogMessage(wxT("OnBeginDrag: started dragging %s"), + GetItemText(m_draggedItem).c_str()); + + event.Allow(); + } + else + { + wxLogMessage(wxT("OnBeginDrag: this item can't be dragged.")); + } +} + +void OPJMarkerTree::OnEndDrag(wxTreeEvent& event) +{ + wxTreeItemId itemSrc = m_draggedItem, + itemDst = event.GetItem(); + m_draggedItem = (wxTreeItemId)0l; + + // where to copy the item? + if ( itemDst.IsOk() && !ItemHasChildren(itemDst) ) + { + // copy to the parent then + itemDst = GetItemParent(itemDst); + } + + if ( !itemDst.IsOk() ) + { + wxLogMessage(wxT("OnEndDrag: can't drop here.")); + + return; + } + + wxString text = GetItemText(itemSrc); + wxLogMessage(wxT("OnEndDrag: '%s' copied to '%s'."), + text.c_str(), GetItemText(itemDst).c_str()); + + // just do append here - we could also insert it just before/after the item + // on which it was dropped, but this requires slightly more work... we also + // completely ignore the client data and icon of the old item but could + // copy them as well. + // + // Finally, we only copy one item here but we might copy the entire tree if + // we were dragging a folder. + int image = wxGetApp().ShowImages() ? TreeCtrlIcon_File : -1; + AppendItem(itemDst, text, image); +}*/ + +/*void OPJMarkerTree::OnBeginLabelEdit(wxTreeEvent& event) +{ + wxLogMessage(wxT("OnBeginLabelEdit")); + + // for testing, prevent this item's label editing + wxTreeItemId itemId = event.GetItem(); + if ( IsTestItem(itemId) ) + { + wxMessageBox(wxT("You can't edit this item.")); + + event.Veto(); + } + else if ( itemId == GetRootItem() ) + { + // test that it is possible to change the text of the item being edited + SetItemText(itemId, _T("Editing root item")); + } +} + +void OPJMarkerTree::OnEndLabelEdit(wxTreeEvent& event) +{ + wxLogMessage(wxT("OnEndLabelEdit")); + + // don't allow anything except letters in the labels + if ( !event.GetLabel().IsWord() ) + { + wxMessageBox(wxT("The new label should be a single word.")); + + event.Veto(); + } +}*/ + +/*void OPJMarkerTree::OnItemCollapsing(wxTreeEvent& event) +{ + wxLogMessage(wxT("OnItemCollapsing")); + + // for testing, prevent the user from collapsing the first child folder + wxTreeItemId itemId = event.GetItem(); + if ( IsTestItem(itemId) ) + { + wxMessageBox(wxT("You can't collapse this item.")); + + event.Veto(); + } +}*/ + +/*void OPJMarkerTree::OnItemActivated(wxTreeEvent& event) +{ + // show some info about this item + wxTreeItemId itemId = event.GetItem(); + OPJMarkerData *item = (OPJMarkerData *)GetItemData(itemId); + + if ( item != NULL ) + { + item->ShowInfo(this); + } + + wxLogMessage(wxT("OnItemActivated")); +}*/ + +void OPJMarkerTree::OnItemMenu(wxTreeEvent& event) +{ + /*wxTreeItemId itemId = event.GetItem(); + OPJMarkerData *item = itemId.IsOk() ? (OPJMarkerData *)GetItemData(itemId) + : NULL; + + wxLogMessage(wxT("OnItemMenu for item \"%s\""), item ? item->GetDesc() + : _T(""));*/ + + //wxLogMessage(wxT("EEEEEEEEEE")); + + //event.Skip(); +} + +/*void OPJMarkerTree::OnContextMenu(wxContextMenuEvent& event) +{ + wxPoint pt = event.GetPosition(); + wxTreeItemId item; + wxLogMessage(wxT("OnContextMenu at screen coords (%i, %i)"), pt.x, pt.y); + + // check if event was generated by keyboard (MSW-specific?) + if ( pt.x == -1 && pt.y == -1 ) //(this is how MSW indicates it) + { + if ( !HasFlag(wxTR_MULTIPLE) ) + item = GetSelection(); + + // attempt to guess where to show the menu + if ( item.IsOk() ) + { + // if an item was clicked, show menu to the right of it + wxRect rect; + GetBoundingRect(item, rect, true );// only the label + pt = wxPoint(rect.GetRight(), rect.GetTop()); + } + else + { + pt = wxPoint(0, 0); + } + } + else // event was generated by mouse, use supplied coords + { + pt = ScreenToClient(pt); + item = HitTest(pt); + } + + ShowMenu(item, pt); +}*/ + +/*void OPJMarkerTree::ShowMenu(wxTreeItemId id, const wxPoint& pt) +{ + wxString title; + if ( id.IsOk() ) + { + title << wxT("Menu for ") << GetItemText(id); + } + else + { + title = wxT("Menu for no particular item"); + } + +#if wxUSE_MENUS + wxMenu menu(title); + menu.Append(TreeTest_About, wxT("&About...")); + menu.AppendSeparator(); + menu.Append(TreeTest_Highlight, wxT("&Highlight item")); + menu.Append(TreeTest_Dump, wxT("&Dump")); + + PopupMenu(&menu, pt); +#endif // wxUSE_MENUS +}*/ + +/*void OPJMarkerTree::OnItemRClick(wxTreeEvent& event) +{ + wxTreeItemId itemId = event.GetItem(); + OPJMarkerData *item = itemId.IsOk() ? (OPJMarkerData *)GetItemData(itemId) + : NULL; + + wxLogMessage(wxT("Item \"%s\" right clicked"), item ? item->GetDesc() + : _T("")); + + event.Skip(); +}*/ + +/* +void OPJMarkerTree::OnRMouseDown(wxMouseEvent& event) +{ + wxLogMessage(wxT("Right mouse button down")); + + event.Skip(); +} + +void OPJMarkerTree::OnRMouseUp(wxMouseEvent& event) +{ + wxLogMessage(wxT("Right mouse button up")); + + event.Skip(); +} + +void OPJMarkerTree::OnRMouseDClick(wxMouseEvent& event) +{ + wxTreeItemId id = HitTest(event.GetPosition()); + if ( !id ) + wxLogMessage(wxT("No item under mouse")); + else + { + OPJMarkerData *item = (OPJMarkerData *)GetItemData(id); + if ( item ) + wxLogMessage(wxT("Item '%s' under mouse"), item->GetDesc()); + } + + event.Skip(); +} +*/ + +static inline const wxChar *Bool2String(bool b) +{ + return b ? wxT("") : wxT("not "); +} + +void OPJMarkerData::ShowInfo(wxTreeCtrl *tree) +{ + wxLogMessage(wxT("Item '%s': %sselected, %sexpanded, %sbold,\n") + wxT("%u children (%u immediately under this item)."), + m_desc.c_str(), + Bool2String(tree->IsSelected(GetId())), + Bool2String(tree->IsExpanded(GetId())), + Bool2String(tree->IsBold(GetId())), + unsigned(tree->GetChildrenCount(GetId())), + unsigned(tree->GetChildrenCount(GetId(), false))); +} + + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/OPJViewer.cpp b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/OPJViewer.cpp new file mode 100644 index 0000000..056a8a1 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/OPJViewer.cpp @@ -0,0 +1,1664 @@ +/* + * Copyright (c) 2007, Digital Signal Processing Laboratory, Universita' degli studi di Perugia (UPG), Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +///////////////////////////////////////////////////////////////////////////// +// Name: sashtest.cpp +// Purpose: Layout/sash sample +// Author: Julian Smart +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id: sashtest.cpp,v 1.18 2005/08/23 15:54:35 ABX Exp $ +// Copyright: (c) Julian Smart +// Licence: wxWindows license +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +// Name: treetest.cpp +// Purpose: wxTreeCtrl sample +// Author: Julian Smart +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id: treetest.cpp,v 1.110 2006/11/04 11:26:51 VZ Exp $ +// Copyright: (c) Julian Smart +// Licence: wxWindows license +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +// Name: dialogs.cpp +// Purpose: Common dialogs demo +// Author: Julian Smart +// Modified by: ABX (2004) - adjustements for conditional building + new menu +// Created: 04/01/98 +// RCS-ID: $Id: dialogs.cpp,v 1.163 2006/11/04 10:57:24 VZ Exp $ +// Copyright: (c) Julian Smart +// Licence: wxWindows license +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +// Name: thread.cpp +// Purpose: wxWidgets thread sample +// Author: Guilhem Lavaux, Vadim Zeitlin +// Modified by: +// Created: 06/16/98 +// RCS-ID: $Id: thread.cpp,v 1.26 2006/10/02 05:36:28 PC Exp $ +// Copyright: (c) 1998-2002 wxWidgets team +// Licence: wxWindows license +///////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Name: samples/image/image.cpp +// Purpose: sample showing operations with wxImage +// Author: Robert Roebling +// Modified by: +// Created: 1998 +// RCS-ID: $Id: image.cpp,v 1.120 2006/12/06 17:13:11 VZ Exp $ +// Copyright: (c) 1998-2005 Robert Roebling +// License: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +// Name: samples/console/console.cpp +// Purpose: A sample console (as opposed to GUI) program using wxWidgets +// Author: Vadim Zeitlin +// Modified by: +// Created: 04.10.99 +// RCS-ID: $Id: console.cpp,v 1.206 2006/11/12 19:55:19 VZ Exp $ +// Copyright: (c) 1999 Vadim Zeitlin +// Licence: wxWindows license +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +// Name: samples/notebook/notebook.cpp +// Purpose: a sample demonstrating notebook usage +// Author: Julian Smart +// Modified by: Dimitri Schoolwerth +// Created: 26/10/98 +// RCS-ID: $Id: notebook.cpp,v 1.49 2006/11/04 18:24:07 RR Exp $ +// Copyright: (c) 1998-2002 wxWidgets team +// License: wxWindows license +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +// Name: dialogs.cpp +// Purpose: Common dialogs demo +// Author: Julian Smart +// Modified by: ABX (2004) - adjustements for conditional building + new menu +// Created: 04/01/98 +// RCS-ID: $Id: dialogs.cpp,v 1.163 2006/11/04 10:57:24 VZ Exp $ +// Copyright: (c) Julian Smart +// Licence: wxWindows license +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +// Name: dnd.cpp +// Purpose: Drag and drop sample +// Author: Vadim Zeitlin +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id: dnd.cpp,v 1.107 2006/10/30 20:23:41 VZ Exp $ +// Copyright: +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +// Name: test.cpp +// Purpose: wxHtml testing example +///////////////////////////////////////////////////////////////////////////// + + +#include "OPJViewer.h" + +IMPLEMENT_APP(OPJViewerApp) + +// For drawing lines in a canvas +long xpos = -1; +long ypos = -1; + +int winNumber = 1; + +// Initialise this in OnInit, not statically +bool OPJViewerApp::OnInit(void) +{ + int n; +#if wxUSE_UNICODE + + wxChar **wxArgv = new wxChar *[argc + 1]; + + for (n = 0; n < argc; n++ ) { + wxMB2WXbuf warg = wxConvertMB2WX((char *) argv[n]); + wxArgv[n] = wxStrdup(warg); + } + + wxArgv[n] = NULL; + +#else // !wxUSE_UNICODE + + #define wxArgv argv + +#endif // wxUSE_UNICODE/!wxUSE_UNICODE + +#if wxUSE_CMDLINE_PARSER + + static const wxCmdLineEntryDesc cmdLineDesc[] = + { + { wxCMD_LINE_SWITCH, _T("h"), _T("help"), _T("show this help message"), + wxCMD_LINE_VAL_NONE, wxCMD_LINE_OPTION_HELP }, + + { wxCMD_LINE_PARAM, NULL, NULL, _T("input file"), + wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL | wxCMD_LINE_PARAM_MULTIPLE }, + + { wxCMD_LINE_NONE } + }; + + wxCmdLineParser parser(cmdLineDesc, argc, wxArgv); + + switch (parser.Parse()) { + case -1: + wxLogMessage(wxT("Help was given, terminating.")); + break; + + case 0: + ShowCmdLine(parser); + break; + + default: + wxLogMessage(wxT("Syntax error detected.")); + break; + } + +#endif // wxUSE_CMDLINE_PARSER + + //wxInitAllImageHandlers(); +#if wxUSE_LIBJPEG + wxImage::AddHandler( new wxJPEGHandler ); +#endif +#if wxUSE_LIBOPENJPEG + wxImage::AddHandler( new wxJPEG2000Handler ); +#endif +#if USE_MXF + wxImage::AddHandler( new wxMXFHandler ); +#endif // USE_MXF +#if OPJ_MANYFORMATS + wxImage::AddHandler( new wxBMPHandler ); + wxImage::AddHandler( new wxPNGHandler ); + wxImage::AddHandler( new wxGIFHandler ); + wxImage::AddHandler( new wxPNMHandler ); + wxImage::AddHandler( new wxTIFFHandler ); +#endif + // we use a XPM image in our HTML page + wxImage::AddHandler(new wxXPMHandler); + + // memory file system + wxFileSystem::AddHandler(new wxMemoryFSHandler); + +#ifdef OPJ_INICONFIG + //load decoding engine parameters + OPJconfig = new wxConfig(OPJ_APPLICATION, OPJ_APPLICATION_VENDOR); + + OPJconfig->Read(wxT("decode/enabledeco"), &m_enabledeco, (bool) true); + OPJconfig->Read(wxT("decode/enableparse"), &m_enableparse, (bool) true); + OPJconfig->Read(wxT("decode/resizemethod"), &m_resizemethod, (long) 0); + OPJconfig->Read(wxT("decode/xxxreducefactor"), &m_reducefactor, (long) 0); + OPJconfig->Read(wxT("decode/xxxqualitylayers"), &m_qualitylayers, (long) 0); + OPJconfig->Read(wxT("decode/xxxcomponents"), &m_components, (long) 0); + OPJconfig->Read(wxT("decode/xxxframenum"), &m_framenum, (long) 0); +#ifdef USE_JPWL + OPJconfig->Read(wxT("decode/enablejpwl"), &m_enablejpwl, (bool) true); + OPJconfig->Read(wxT("decode/expcomps"), &m_expcomps, (long) JPWL_EXPECTED_COMPONENTS); + OPJconfig->Read(wxT("decode/maxtiles"), &m_maxtiles, (long) JPWL_MAXIMUM_TILES); +#endif // USE_JPWL + + OPJconfig->Write(wxT("teststring"), wxT("This is a test value")); + OPJconfig->Write(wxT("testbool"), (bool) true); + OPJconfig->Write(wxT("testlong"), (long) 245); + + OPJconfig->Read(wxT("showtoolbar"), &m_showtoolbar, (bool) true); + OPJconfig->Read(wxT("showbrowser"), &m_showbrowser, (bool) true); + OPJconfig->Read(wxT("showpeeker"), &m_showpeeker, (bool) true); + OPJconfig->Read(wxT("browserwidth"), &m_browserwidth, (long) OPJ_BROWSER_WIDTH); + OPJconfig->Read(wxT("peekerheight"), &m_peekerheight, (long) OPJ_PEEKER_HEIGHT); + OPJconfig->Read(wxT("framewidth"), &m_framewidth, (long) OPJ_FRAME_WIDTH); + OPJconfig->Read(wxT("frameheight"), &m_frameheight, (long) OPJ_FRAME_HEIGHT); + + // load encoding engine parameters + OPJconfig->Read(wxT("encode/subsampling"), &m_subsampling, (wxString) wxT("1,1")); + OPJconfig->Read(wxT("encode/origin"), &m_origin, (wxString) wxT("0,0")); + OPJconfig->Read(wxT("encode/rates"), &m_rates, (wxString) wxT("20,10,5")); + OPJconfig->Read(wxT("encode/quality"), &m_quality, (wxString) wxT("30,35,40")); + OPJconfig->Read(wxT("encode/enablequality"), &m_enablequality, (bool) false); + OPJconfig->Read(wxT("encode/multicomp"), &m_multicomp, (bool) false); + OPJconfig->Read(wxT("encode/irreversible"), &m_irreversible, (bool) false); + OPJconfig->Read(wxT("encode/resolutions"), &m_resolutions, (int) 6); + OPJconfig->Read(wxT("encode/progression"), &m_progression, (int) 0); + OPJconfig->Read(wxT("encode/cbsize"), &m_cbsize, (wxString) wxT("32,32")); + OPJconfig->Read(wxT("encode/prsize"), &m_prsize, (wxString) wxT("[128,128],[128,128]")); + OPJconfig->Read(wxT("encode/tsize"), &m_tsize, (wxString) wxT("")); + OPJconfig->Read(wxT("encode/torigin"), &m_torigin, (wxString) wxT("0,0")); + OPJconfig->Read(wxT("encode/enablesop"), &m_enablesop, (bool) false); + OPJconfig->Read(wxT("encode/enableeph"), &m_enableeph, (bool) false); + OPJconfig->Read(wxT("encode/enablebypass"), &m_enablebypass, (bool) false); + OPJconfig->Read(wxT("encode/enablereset"), &m_enablereset, (bool) false); + OPJconfig->Read(wxT("encode/enablerestart"), &m_enablerestart, (bool) false); + OPJconfig->Read(wxT("encode/enablevsc"), &m_enablevsc, (bool) false); + OPJconfig->Read(wxT("encode/enableerterm"), &m_enableerterm, (bool) false); + OPJconfig->Read(wxT("encode/enablesegmark"), &m_enablesegmark, (bool) false); + OPJconfig->Read(wxT("encode/enablecomm"), &m_enablecomm, (bool) true); + OPJconfig->Read(wxT("encode/enablepoc"), &m_enablepoc, (bool) false); + OPJconfig->Read(wxT("encode/comment"), &m_comment, (wxString) wxT("")); + OPJconfig->Read(wxT("encode/poc"), &m_poc, (wxString) wxT("T1=0,0,1,5,3,CPRL/T1=5,0,1,6,3,CPRL")); + OPJconfig->Read(wxT("encode/enableidx"), &m_enableidx, (bool) false); + OPJconfig->Read(wxT("encode/index"), &m_index, (wxString) wxT("index.txt")); +#ifdef USE_JPWL + OPJconfig->Read(wxT("encode/enablejpwl"), &m_enablejpwle, (bool) true); + for (n = 0; n < MYJPWL_MAX_NO_TILESPECS; n++) { + OPJconfig->Read(wxT("encode/jpwl/hprotsel") + wxString::Format(wxT("%02d"), n), &m_hprotsel[n], 0); + OPJconfig->Read(wxT("encode/jpwl/htileval") + wxString::Format(wxT("%02d"), n), &m_htileval[n], 0); + OPJconfig->Read(wxT("encode/jpwl/pprotsel") + wxString::Format(wxT("%02d"), n), &m_pprotsel[n], 0); + OPJconfig->Read(wxT("encode/jpwl/ptileval") + wxString::Format(wxT("%02d"), n), &m_ptileval[n], 0); + OPJconfig->Read(wxT("encode/jpwl/ppackval") + wxString::Format(wxT("%02d"), n), &m_ppackval[n], 0); + OPJconfig->Read(wxT("encode/jpwl/sensisel") + wxString::Format(wxT("%02d"), n), &m_sensisel[n], 0); + OPJconfig->Read(wxT("encode/jpwl/stileval") + wxString::Format(wxT("%02d"), n), &m_stileval[n], 0); + } +#endif // USE_JPWL + +#else + // set decoding engine parameters + m_enabledeco = true; + m_enableparse = true; + m_resizemethod = 0; + m_reducefactor = 0; + m_qualitylayers = 0; + m_components = 0; + m_framenum = 0; +#ifdef USE_JPWL + m_enablejpwl = true; + m_expcomps = JPWL_EXPECTED_COMPONENTS; + m_maxtiles = JPWL_MAXIMUM_TILES; +#endif // USE_JPWL + m_showtoolbar = true; + m_showbrowser = true; + m_showpeeker = true; + m_browserwidth = OPJ_BROWSER_WIDTH; + m_peekerheight = OPJ_PEEKER_HEIGHT; + m_framewidth = OPJ_FRAME_WIDTH; + m_frameheight = OPJ_FRAME_HEIGHT; + + // set encoding engine parameters + m_subsampling = wxT("1,1"); + m_origin = wxT("0,0"); + m_rates = wxT("20,10,5"); + m_quality = wxT("30,35,40"); + m_enablequality = false; + m_multicomp = false; + m_irreversible = false; + m_resolutions = 6; + m_progression = 0; + m_cbsize= wxT("32,32"); + m_prsize= wxT("[128,128],[128,128]"); + m_tsize = wxT(""); + m_torigin = wxT("0,0"); + m_enablesop = false; + m_enableeph = false; + m_enablebypass = false; + m_enablereset = false; + m_enablerestart = false; + m_enablevsc = false; + m_enableerterm = false; + m_enablesegmark = false; + m_enableidx = false; + m_index = wxT("index.txt"); + m_enablecomm = true; + m_comment = wxT(""); + m_enablepoc = false; + m_poc = wxT("T1=0,0,1,5,3,CPRL/T1=5,0,1,6,3,CPRL"); +#ifdef USE_JPWL + m_enablejpwle = true; + for (n = 0; n < MYJPWL_MAX_NO_TILESPECS; n++) { + m_hprotsel[n] = 0; + m_htileval[n] = 0; + m_pprotsel[n] = 0; + m_ptileval[n] = 0; + m_sensisel[n] = 0; + m_stileval[n] = 0; + } +#endif // USE_JPWL + +#endif // OPJ_INICONFIG + + if (m_comment == wxT("")) { +#if defined __WXMSW__ + m_comment = wxT("Created by OPJViewer Win32 - OpenJPEG version "); +#elif defined __WXGTK__ + m_comment = wxT("Created by OPJViewer Lin32 - OpenJPEG version "); +#else + m_comment = wxT("Created by OPJViewer - OpenJPEG version "); +#endif + +#ifdef USE_JPWL + m_comment += wxString::Format(wxT("%s with JPWL"), (char *) opj_version()); +#else + m_comment += wxString::Format(wxT("%s"), (char *) opj_version()); +#endif + } + + // Create the main frame window + OPJFrame *frame = new OPJFrame(NULL, wxID_ANY, OPJ_APPLICATION_TITLEBAR, + wxDefaultPosition, wxSize(wxGetApp().m_framewidth, wxGetApp().m_frameheight), + wxDEFAULT_FRAME_STYLE | wxNO_FULL_REPAINT_ON_RESIZE | + wxHSCROLL | wxVSCROLL); + + // Give it an icon (this is ignored in MDI mode: uses resources) +#ifdef __WXMSW__ + frame->SetIcon(wxIcon(wxT("OPJViewer16"))); +#endif + + frame->Show(true); + + SetTopWindow(frame); + + // if there are files on the command line, open them + if (!(m_filelist.IsEmpty())) { + //wxLogMessage(wxT("Habemus files!!!")); + wxArrayString paths, filenames; + for (unsigned int f = 0; f < wxGetApp().m_filelist.GetCount(); f++) { + paths.Add(wxFileName(wxGetApp().m_filelist[f]).GetFullPath()); + filenames.Add(wxFileName(wxGetApp().m_filelist[f]).GetFullName()); + } + //wxLogMessage(paths[0]); + frame->OpenFiles(paths, filenames); + } + + return true; +} + +int OPJViewerApp::OnExit() +{ + int n; + +#ifdef OPJ_INICONFIG + OPJconfig->Write(wxT("decode/enabledeco"), m_enabledeco); + OPJconfig->Write(wxT("decode/enableparse"), m_enableparse); + OPJconfig->Write(wxT("decode/resizemethod"), m_resizemethod); + OPJconfig->Write(wxT("decode/reducefactor"), m_reducefactor); + OPJconfig->Write(wxT("decode/qualitylayers"), m_qualitylayers); + OPJconfig->Write(wxT("decode/components"), m_components); + OPJconfig->Write(wxT("decode/framenum"), m_framenum); +#ifdef USE_JPWL + OPJconfig->Write(wxT("decode/enablejpwl"), m_enablejpwl); + OPJconfig->Write(wxT("decode/expcomps"), m_expcomps); + OPJconfig->Write(wxT("decode/maxtiles"), m_maxtiles); +#endif // USE_JPWL + OPJconfig->Write(wxT("showtoolbar"), m_showtoolbar); + OPJconfig->Write(wxT("showbrowser"), m_showbrowser); + OPJconfig->Write(wxT("showpeeker"), m_showpeeker); + OPJconfig->Write(wxT("browserwidth"), m_browserwidth); + OPJconfig->Write(wxT("peekerheight"), m_peekerheight); + OPJconfig->Write(wxT("framewidth"), m_framewidth); + OPJconfig->Write(wxT("frameheight"), m_frameheight); + + OPJconfig->Write(wxT("encode/subsampling"), m_subsampling); + OPJconfig->Write(wxT("encode/origin"), m_origin); + OPJconfig->Write(wxT("encode/rates"), m_rates); + OPJconfig->Write(wxT("encode/quality"), m_quality); + OPJconfig->Write(wxT("encode/enablequality"), m_enablequality); + OPJconfig->Write(wxT("encode/multicomp"), m_multicomp); + OPJconfig->Write(wxT("encode/irreversible"), m_irreversible); + OPJconfig->Write(wxT("encode/resolutions"), m_resolutions); + OPJconfig->Write(wxT("encode/progression"), m_progression); + OPJconfig->Write(wxT("encode/cbsize"), m_cbsize); + OPJconfig->Write(wxT("encode/prsize"), m_prsize); + OPJconfig->Write(wxT("encode/tiles"), m_tsize); + OPJconfig->Write(wxT("encode/torigin"), m_torigin); + OPJconfig->Write(wxT("encode/enablesop"), m_enablesop); + OPJconfig->Write(wxT("encode/enableeph"), m_enableeph); + OPJconfig->Write(wxT("encode/enablebypass"), m_enablebypass); + OPJconfig->Write(wxT("encode/enablereset"), m_enablereset); + OPJconfig->Write(wxT("encode/enablerestart"), m_enablerestart); + OPJconfig->Write(wxT("encode/enablevsc"), m_enablevsc); + OPJconfig->Write(wxT("encode/enableerterm"), m_enableerterm); + OPJconfig->Write(wxT("encode/enablesegmark"), m_enablesegmark); + OPJconfig->Write(wxT("encode/enableidx"), m_enableidx); + OPJconfig->Write(wxT("encode/index"), m_index); + OPJconfig->Write(wxT("encode/enablecomm"), m_enablecomm); + OPJconfig->Write(wxT("encode/comment"), m_comment); + OPJconfig->Write(wxT("encode/enablepoc"), m_enablepoc); + OPJconfig->Write(wxT("encode/poc"), m_poc); +#ifdef USE_JPWL + OPJconfig->Write(wxT("encode/enablejpwl"), m_enablejpwle); + for (n = 0; n < MYJPWL_MAX_NO_TILESPECS; n++) { + OPJconfig->Write(wxT("encode/jpwl/hprotsel") + wxString::Format(wxT("%02d"), n), m_hprotsel[n]); + OPJconfig->Write(wxT("encode/jpwl/htileval") + wxString::Format(wxT("%02d"), n), m_htileval[n]); + OPJconfig->Write(wxT("encode/jpwl/pprotsel") + wxString::Format(wxT("%02d"), n), m_pprotsel[n]); + OPJconfig->Write(wxT("encode/jpwl/ptileval") + wxString::Format(wxT("%02d"), n), m_ptileval[n]); + OPJconfig->Write(wxT("encode/jpwl/ppackval") + wxString::Format(wxT("%02d"), n), m_ppackval[n]); + OPJconfig->Write(wxT("encode/jpwl/sensisel") + wxString::Format(wxT("%02d"), n), m_sensisel[n]); + OPJconfig->Write(wxT("encode/jpwl/stileval") + wxString::Format(wxT("%02d"), n), m_stileval[n]); + } +#endif // USE_JPWL + +#endif // OPJ_INICONFIG + + return 1; +} + +void OPJViewerApp::ShowCmdLine(const wxCmdLineParser& parser) +{ + wxString s = wxT("Command line parsed successfully:\nInput files: "); + + size_t count = parser.GetParamCount(); + for (size_t param = 0; param < count; param++) { + s << parser.GetParam(param) << ';'; + m_filelist.Add(parser.GetParam(param)); + } + + //wxLogMessage(s); +} + +// OPJFrame events + +// Event class for sending text messages between worker and GUI threads +BEGIN_EVENT_TABLE(OPJFrame, wxMDIParentFrame) + EVT_MENU(OPJFRAME_HELPABOUT, OPJFrame::OnAbout) + EVT_MENU(OPJFRAME_FILEOPEN, OPJFrame::OnFileOpen) + EVT_MENU(OPJFRAME_FILESAVEAS, OPJFrame::OnFileSaveAs) + EVT_MENU(OPJFRAME_MEMORYOPEN, OPJFrame::OnMemoryOpen) + EVT_SIZE(OPJFrame::OnSize) + EVT_MENU(OPJFRAME_FILEEXIT, OPJFrame::OnQuit) + EVT_MENU(OPJFRAME_FILECLOSE, OPJFrame::OnClose) + EVT_MENU(OPJFRAME_VIEWZOOM, OPJFrame::OnZoom) + EVT_MENU(OPJFRAME_VIEWFIT, OPJFrame::OnFit) + EVT_MENU(OPJFRAME_VIEWRELOAD, OPJFrame::OnReload) + EVT_MENU(OPJFRAME_VIEWPREVFRAME, OPJFrame::OnPrevFrame) + EVT_MENU(OPJFRAME_VIEWHOMEFRAME, OPJFrame::OnHomeFrame) + EVT_MENU(OPJFRAME_VIEWNEXTFRAME, OPJFrame::OnNextFrame) + EVT_MENU(OPJFRAME_VIEWLESSLAYERS, OPJFrame::OnLessLayers) + EVT_MENU(OPJFRAME_VIEWALLLAYERS, OPJFrame::OnAllLayers) + EVT_MENU(OPJFRAME_VIEWMORELAYERS, OPJFrame::OnMoreLayers) + EVT_MENU(OPJFRAME_VIEWLESSRES, OPJFrame::OnLessRes) + EVT_MENU(OPJFRAME_VIEWFULLRES, OPJFrame::OnFullRes) + EVT_MENU(OPJFRAME_VIEWMORERES, OPJFrame::OnMoreRes) + EVT_MENU(OPJFRAME_VIEWPREVCOMP, OPJFrame::OnPrevComp) + EVT_MENU(OPJFRAME_VIEWALLCOMPS, OPJFrame::OnAllComps) + EVT_MENU(OPJFRAME_VIEWNEXTCOMP, OPJFrame::OnNextComp) + EVT_MENU(OPJFRAME_FILETOGGLEB, OPJFrame::OnToggleBrowser) + EVT_MENU(OPJFRAME_FILETOGGLEP, OPJFrame::OnTogglePeeker) + EVT_MENU(OPJFRAME_FILETOGGLET, OPJFrame::OnToggleToolbar) + EVT_MENU(OPJFRAME_SETSENCO, OPJFrame::OnSetsEnco) + EVT_MENU(OPJFRAME_SETSDECO, OPJFrame::OnSetsDeco) + EVT_SASH_DRAGGED_RANGE(OPJFRAME_BROWSEWIN, OPJFRAME_LOGWIN, OPJFrame::OnSashDrag) + EVT_NOTEBOOK_PAGE_CHANGED(LEFT_NOTEBOOK_ID, OPJFrame::OnNotebook) + EVT_MENU(OPJFRAME_THREADLOGMSG, OPJFrame::OnThreadLogmsg) +END_EVENT_TABLE() + +// this is the frame constructor +OPJFrame::OPJFrame(wxWindow *parent, const wxWindowID id, const wxString& title, + const wxPoint& pos, const wxSize& size, const long style) + : wxMDIParentFrame(parent, id, title, pos, size, style) +{ + // file menu and its items + wxMenu *file_menu = new wxMenu; + + file_menu->Append(OPJFRAME_FILEOPEN, wxT("&Open\tCtrl+O")); + file_menu->SetHelpString(OPJFRAME_FILEOPEN, wxT("Open one or more files")); + + file_menu->Append(OPJFRAME_MEMORYOPEN, wxT("&Memory\tCtrl+M")); + file_menu->SetHelpString(OPJFRAME_MEMORYOPEN, wxT("Open a memory buffer")); + + file_menu->Append(OPJFRAME_FILECLOSE, wxT("&Close\tCtrl+C")); + file_menu->SetHelpString(OPJFRAME_FILECLOSE, wxT("Close current image")); + + file_menu->AppendSeparator(); + + file_menu->Append(OPJFRAME_FILESAVEAS, wxT("&Save as\tCtrl+S")); + file_menu->SetHelpString(OPJFRAME_FILESAVEAS, wxT("Save the current image")); + //file_menu->Enable(OPJFRAME_FILESAVEAS, false); + + file_menu->AppendSeparator(); + + file_menu->Append(OPJFRAME_FILETOGGLEB, wxT("Toggle &browser\tCtrl+B")); + file_menu->SetHelpString(OPJFRAME_FILETOGGLEB, wxT("Toggle the left browsing pane")); + + file_menu->Append(OPJFRAME_FILETOGGLEP, wxT("Toggle &peeker\tCtrl+P")); + file_menu->SetHelpString(OPJFRAME_FILETOGGLEP, wxT("Toggle the bottom peeking pane")); + + file_menu->Append(OPJFRAME_FILETOGGLET, wxT("Toggle &toolbar\tCtrl+T")); + file_menu->SetHelpString(OPJFRAME_FILETOGGLET, wxT("Toggle the toolbar")); + + file_menu->AppendSeparator(); + + file_menu->Append(OPJFRAME_FILEEXIT, wxT("&Exit\tCtrl+Q")); + file_menu->SetHelpString(OPJFRAME_FILEEXIT, wxT("Quit this program")); + + // view menu and its items + wxMenu *view_menu = new wxMenu; + + view_menu->Append(OPJFRAME_VIEWZOOM, wxT("&Zoom\tCtrl+Z")); + view_menu->SetHelpString(OPJFRAME_VIEWZOOM, wxT("Rescale the image")); + + view_menu->Append(OPJFRAME_VIEWFIT, wxT("Zoom to &fit\tCtrl+F")); + view_menu->SetHelpString(OPJFRAME_VIEWFIT, wxT("Fit the image in canvas")); + + view_menu->Append(OPJFRAME_VIEWRELOAD, wxT("&Reload image\tCtrl+R")); + view_menu->SetHelpString(OPJFRAME_VIEWRELOAD, wxT("Reload the current image")); + + view_menu->AppendSeparator(); + + view_menu->Append(OPJFRAME_VIEWPREVFRAME, wxT("&Prev frame\tLeft")); + view_menu->SetHelpString(OPJFRAME_VIEWPREVFRAME, wxT("View previous frame")); + + view_menu->Append(OPJFRAME_VIEWHOMEFRAME, wxT("&Start frame\tHome")); + view_menu->SetHelpString(OPJFRAME_VIEWHOMEFRAME, wxT("View starting frame")); + + view_menu->Append(OPJFRAME_VIEWNEXTFRAME, wxT("&Next frame\tRight")); + view_menu->SetHelpString(OPJFRAME_VIEWNEXTFRAME, wxT("View next frame")); + + view_menu->AppendSeparator(); + + view_menu->Append(OPJFRAME_VIEWLESSLAYERS, wxT("&Less layers\t-")); + view_menu->SetHelpString(OPJFRAME_VIEWLESSLAYERS, wxT("Remove a layer")); + + view_menu->Append(OPJFRAME_VIEWALLLAYERS, wxT("&All layers\t0")); + view_menu->SetHelpString(OPJFRAME_VIEWALLLAYERS, wxT("Show all layers")); + + view_menu->Append(OPJFRAME_VIEWMORELAYERS, wxT("&More layers\t+")); + view_menu->SetHelpString(OPJFRAME_VIEWMORELAYERS, wxT("Add a layer")); + + view_menu->AppendSeparator(); + + view_menu->Append(OPJFRAME_VIEWLESSRES, wxT("&Less resolution\t<")); + view_menu->SetHelpString(OPJFRAME_VIEWLESSRES, wxT("Reduce the resolution")); + + view_menu->Append(OPJFRAME_VIEWFULLRES, wxT("&Full resolution\tf")); + view_menu->SetHelpString(OPJFRAME_VIEWFULLRES, wxT("Full resolution")); + + view_menu->Append(OPJFRAME_VIEWMORERES, wxT("&More resolution\t>")); + view_menu->SetHelpString(OPJFRAME_VIEWMORERES, wxT("Increase the resolution")); + + view_menu->AppendSeparator(); + + view_menu->Append(OPJFRAME_VIEWPREVCOMP, wxT("&Prev component\tDown")); + view_menu->SetHelpString(OPJFRAME_VIEWPREVCOMP, wxT("View previous component")); + + view_menu->Append(OPJFRAME_VIEWALLCOMPS, wxT("&All components\ta")); + view_menu->SetHelpString(OPJFRAME_VIEWALLCOMPS, wxT("View all components")); + + view_menu->Append(OPJFRAME_VIEWNEXTCOMP, wxT("&Next component\tUp")); + view_menu->SetHelpString(OPJFRAME_VIEWNEXTCOMP, wxT("View next component")); + + + // settings menu and its items + wxMenu *sets_menu = new wxMenu; + + sets_menu->Append(OPJFRAME_SETSENCO, wxT("&Encoder\tCtrl+E")); + sets_menu->SetHelpString(OPJFRAME_SETSENCO, wxT("Encoder settings")); + + sets_menu->Append(OPJFRAME_SETSDECO, wxT("&Decoder\tCtrl+D")); + sets_menu->SetHelpString(OPJFRAME_SETSDECO, wxT("Decoder settings")); + + // help menu and its items + wxMenu *help_menu = new wxMenu; + + help_menu->Append(OPJFRAME_HELPABOUT, wxT("&About\tF1")); + help_menu->SetHelpString(OPJFRAME_HELPABOUT, wxT("Basic info on the program")); + + // the whole menubar + wxMenuBar *menu_bar = new wxMenuBar; + menu_bar->Append(file_menu, wxT("&File")); + menu_bar->Append(view_menu, wxT("&View")); + menu_bar->Append(sets_menu, wxT("&Settings")); + menu_bar->Append(help_menu, wxT("&Help")); + + // Associate the menu bar with the frame + SetMenuBar(menu_bar); + + // the status bar + CreateStatusBar(); + + // the toolbar + tool_bar = new wxToolBar(this, OPJFRAME_TOOLBAR, + wxDefaultPosition, wxDefaultSize, + wxTB_HORIZONTAL | wxNO_BORDER); + wxBitmap bmpOpen = wxArtProvider::GetBitmap(wxART_FILE_OPEN, wxART_TOOLBAR, + wxDefaultSize); + wxBitmap bmpSaveAs = wxArtProvider::GetBitmap(wxART_FILE_SAVE_AS, wxART_TOOLBAR, + wxDefaultSize); + wxBitmap bmpZoom = wxArtProvider::GetBitmap(wxART_FIND, wxART_TOOLBAR, + wxDefaultSize); + wxBitmap bmpFit = wxArtProvider::GetBitmap(wxART_FIND_AND_REPLACE, wxART_TOOLBAR, + wxDefaultSize); + wxBitmap bmpReload = wxArtProvider::GetBitmap(wxART_EXECUTABLE_FILE, wxART_TOOLBAR, + wxDefaultSize); + wxBitmap bmpDecosettings = wxArtProvider::GetBitmap(wxART_REPORT_VIEW, wxART_TOOLBAR, + wxDefaultSize); + wxBitmap bmpEncosettings = wxArtProvider::GetBitmap(wxART_LIST_VIEW, wxART_TOOLBAR, + wxDefaultSize); + wxBitmap bmpPrevframe = wxArtProvider::GetBitmap(wxART_GO_BACK, wxART_TOOLBAR, + wxDefaultSize); + wxBitmap bmpHomeframe = wxArtProvider::GetBitmap(wxART_GO_HOME, wxART_TOOLBAR, + wxDefaultSize); + wxBitmap bmpNextframe = wxArtProvider::GetBitmap(wxART_GO_FORWARD, wxART_TOOLBAR, + wxDefaultSize); + wxBitmap bmpLesslayers = bmpPrevframe; + wxBitmap bmpAlllayers = wxArtProvider::GetBitmap(wxART_GO_TO_PARENT, wxART_TOOLBAR, + wxDefaultSize); + wxBitmap bmpMorelayers = bmpNextframe; + wxBitmap bmpLessres = bmpPrevframe; + wxBitmap bmpFullres = wxArtProvider::GetBitmap(wxART_GO_TO_PARENT, wxART_TOOLBAR, + wxDefaultSize); + wxBitmap bmpMoreres = bmpNextframe; + wxBitmap bmpPrevcomp = bmpPrevframe; + wxBitmap bmpAllcomps = wxArtProvider::GetBitmap(wxART_GO_TO_PARENT, wxART_TOOLBAR, + wxDefaultSize); + wxBitmap bmpNextcomp = bmpNextframe; + + tool_bar->AddTool(OPJFRAME_FILEOPEN, bmpOpen, wxT("Open")); + tool_bar->AddTool(OPJFRAME_FILESAVEAS, bmpSaveAs, wxT("Save as ")); + //tool_bar->EnableTool(OPJFRAME_FILESAVEAS, false); + tool_bar->AddSeparator(); + tool_bar->AddTool(OPJFRAME_VIEWZOOM, bmpZoom, wxT("Zoom")); + tool_bar->AddTool(OPJFRAME_VIEWFIT, bmpFit, wxT("Zoom to fit")); + tool_bar->AddTool(OPJFRAME_VIEWRELOAD, bmpReload, wxT("Reload")); + tool_bar->AddSeparator(); + tool_bar->AddTool(OPJFRAME_SETSDECO, bmpDecosettings, wxT("Decoder settings")); + tool_bar->AddTool(OPJFRAME_SETSENCO, bmpEncosettings, wxT("Encoder settings")); + tool_bar->AddSeparator(); + tool_bar->AddTool(OPJFRAME_VIEWPREVFRAME, bmpPrevframe, wxT("Previous frame")); + tool_bar->AddTool(OPJFRAME_VIEWHOMEFRAME, bmpHomeframe, wxT("Starting frame")); + tool_bar->AddTool(OPJFRAME_VIEWNEXTFRAME, bmpNextframe, wxT("Next frame")); + tool_bar->AddSeparator(); + tool_bar->AddTool(OPJFRAME_VIEWLESSLAYERS, bmpLesslayers, wxT("Remove a layer")); + tool_bar->AddTool(OPJFRAME_VIEWALLLAYERS, bmpAlllayers, wxT("Show all layers")); + tool_bar->AddTool(OPJFRAME_VIEWMORELAYERS, bmpMorelayers, wxT("Add a layer")); + tool_bar->AddSeparator(); + tool_bar->AddTool(OPJFRAME_VIEWLESSRES, bmpLessres, wxT("Reduce the resolution")); + tool_bar->AddTool(OPJFRAME_VIEWFULLRES, bmpFullres, wxT("Full resolution")); + tool_bar->AddTool(OPJFRAME_VIEWMORERES, bmpMoreres, wxT("Increase the resolution")); + tool_bar->AddSeparator(); + tool_bar->AddTool(OPJFRAME_VIEWPREVCOMP, bmpPrevcomp, wxT("Previous component")); + tool_bar->AddTool(OPJFRAME_VIEWALLCOMPS, bmpAllcomps, wxT("All components")); + tool_bar->AddTool(OPJFRAME_VIEWNEXTCOMP, bmpNextcomp, wxT("Next component")); + tool_bar->Realize(); + + // associate the toolbar with the frame + SetToolBar(tool_bar); + + // show the toolbar? + if (!wxGetApp().m_showtoolbar) + tool_bar->Show(false); + else + tool_bar->Show(true); + + // the logging window + loggingWindow = new wxSashLayoutWindow(this, OPJFRAME_LOGWIN, + wxDefaultPosition, wxSize(400, wxGetApp().m_peekerheight), + wxNO_BORDER | wxSW_3D | wxCLIP_CHILDREN + ); + loggingWindow->SetDefaultSize(wxSize(1000, wxGetApp().m_peekerheight)); + loggingWindow->SetOrientation(wxLAYOUT_HORIZONTAL); + loggingWindow->SetAlignment(wxLAYOUT_BOTTOM); + //loggingWindow->SetBackgroundColour(wxColour(0, 0, 255)); + loggingWindow->SetSashVisible(wxSASH_TOP, true); + + // show the logging? + if (!wxGetApp().m_showpeeker) + loggingWindow->Show(false); + else + loggingWindow->Show(true); + + // create the bottom notebook + m_bookCtrlbottom = new wxNotebook(loggingWindow, BOTTOM_NOTEBOOK_ID, + wxDefaultPosition, wxDefaultSize, + wxBK_LEFT); + + // create the text control of the logger + m_textCtrl = new wxTextCtrl(m_bookCtrlbottom, wxID_ANY, wxT(""), + wxDefaultPosition, wxDefaultSize, + wxTE_MULTILINE | wxSUNKEN_BORDER | wxTE_READONLY + ); + m_textCtrl->SetValue(_T("Logging window\n")); + + // add it to the notebook + m_bookCtrlbottom->AddPage(m_textCtrl, wxT("Log")); + + // create the text control of the browser + m_textCtrlbrowse = new wxTextCtrl(m_bookCtrlbottom, wxID_ANY, wxT(""), + wxDefaultPosition, wxDefaultSize, + wxTE_MULTILINE | wxSUNKEN_BORDER | wxTE_READONLY | wxTE_RICH + ); + wxFont *browsefont = new wxFont(wxNORMAL_FONT->GetPointSize(), + wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL); + m_textCtrlbrowse->SetDefaultStyle(wxTextAttr(wxNullColour, wxNullColour, *browsefont)); + m_textCtrlbrowse->AppendText(wxT("Browsing window\n")); + + // add it the notebook + m_bookCtrlbottom->AddPage(m_textCtrlbrowse, wxT("Peek"), false); + + // the browser window + markerTreeWindow = new wxSashLayoutWindow(this, OPJFRAME_BROWSEWIN, + wxDefaultPosition, wxSize(wxGetApp().m_browserwidth, 30), + wxNO_BORDER | wxSW_3D | wxCLIP_CHILDREN + ); + markerTreeWindow->SetDefaultSize(wxSize(wxGetApp().m_browserwidth, 1000)); + markerTreeWindow->SetOrientation(wxLAYOUT_VERTICAL); + markerTreeWindow->SetAlignment(wxLAYOUT_LEFT); + //markerTreeWindow->SetBackgroundColour(wxColour(0, 255, 0)); + markerTreeWindow->SetSashVisible(wxSASH_RIGHT, true); + markerTreeWindow->SetExtraBorderSize(0); + + // create the browser notebook + m_bookCtrl = new wxNotebook(markerTreeWindow, LEFT_NOTEBOOK_ID, + wxDefaultPosition, wxDefaultSize, + wxBK_TOP); + + // show the browser? + if (!wxGetApp().m_showbrowser) + markerTreeWindow->Show(false); + else + markerTreeWindow->Show(true); + +#ifdef __WXMOTIF__ + // For some reason, we get a memcpy crash in wxLogStream::DoLogStream + // on gcc/wxMotif, if we use wxLogTextCtl. Maybe it's just gcc? + delete wxLog::SetActiveTarget(new wxLogStderr); +#else + // set our text control as the log target + wxLogTextCtrl *logWindow = new wxLogTextCtrl(m_textCtrl); + delete wxLog::SetActiveTarget(logWindow); +#endif + + // associate drop targets with the controls + SetDropTarget(new OPJDnDFile(this)); + +} + +// this is the frame destructor +OPJFrame::~OPJFrame(void) +{ + // save size settings + GetSize(&(wxGetApp().m_framewidth), &(wxGetApp().m_frameheight)); + + // delete all possible things + delete m_bookCtrl; + m_bookCtrl = NULL; + + delete markerTreeWindow; + markerTreeWindow = NULL; + + delete m_textCtrl; + m_textCtrl = NULL; + + delete m_bookCtrlbottom; + m_bookCtrlbottom = NULL; + + delete loggingWindow; + loggingWindow = NULL; +} + +void OPJFrame::OnNotebook(wxNotebookEvent& event) +{ + int sel = event.GetSelection(); + long childnum; + + m_bookCtrl->GetPageText(sel).ToLong(&childnum); + + if (m_childhash[childnum]) + m_childhash[childnum]->Activate(); + + //wxLogMessage(wxT("Selection changed (now %d --> %d)"), childnum, m_childhash[childnum]->m_winnumber); + +} + + +void OPJFrame::Resize(int number) +{ + wxSize size = GetClientSize(); +} + +void OPJFrame::OnSetsEnco(wxCommandEvent& event) +{ + int n; + + OPJEncoderDialog dialog(this, event.GetId()); + + if (dialog.ShowModal() == wxID_OK) { + + // load settings + wxGetApp().m_subsampling = dialog.m_subsamplingCtrl->GetValue(); + wxGetApp().m_origin = dialog.m_originCtrl->GetValue(); + wxGetApp().m_rates = dialog.m_rateCtrl->GetValue(); + wxGetApp().m_quality = dialog.m_qualityCtrl->GetValue(); + wxGetApp().m_enablequality = dialog.m_qualityRadio->GetValue(); + wxGetApp().m_multicomp = dialog.m_mctCheck->GetValue(); + wxGetApp().m_irreversible = dialog.m_irrevCheck->GetValue(); + wxGetApp().m_resolutions = dialog.m_resolutionsCtrl->GetValue(); + wxGetApp().m_cbsize = dialog.m_cbsizeCtrl->GetValue(); + wxGetApp().m_prsize = dialog.m_prsizeCtrl->GetValue(); + wxGetApp().m_tsize = dialog.m_tsizeCtrl->GetValue(); + wxGetApp().m_torigin = dialog.m_toriginCtrl->GetValue(); + wxGetApp().m_progression = dialog.progressionBox->GetSelection(); + wxGetApp().m_enablesop = dialog.m_sopCheck->GetValue(); + wxGetApp().m_enableeph = dialog.m_ephCheck->GetValue(); + wxGetApp().m_enablebypass = dialog.m_enablebypassCheck->GetValue(); + wxGetApp().m_enablereset = dialog.m_enableresetCheck->GetValue(); + wxGetApp().m_enablerestart = dialog.m_enablerestartCheck->GetValue(); + wxGetApp().m_enablevsc = dialog.m_enablevscCheck->GetValue(); + wxGetApp().m_enableerterm = dialog.m_enableertermCheck->GetValue(); + wxGetApp().m_enablesegmark = dialog.m_enablesegmarkCheck->GetValue(); + wxGetApp().m_enableidx = dialog.m_enableidxCheck->GetValue(); + wxGetApp().m_index = dialog.m_indexCtrl->GetValue(); + wxGetApp().m_enablecomm = dialog.m_enablecommCheck->GetValue(); + wxGetApp().m_comment = dialog.m_commentCtrl->GetValue(); + wxGetApp().m_enablepoc = dialog.m_enablepocCheck->GetValue(); + wxGetApp().m_poc = dialog.m_pocCtrl->GetValue(); +#ifdef USE_JPWL + wxGetApp().m_enablejpwle = dialog.m_enablejpwlCheck->GetValue(); + for (n = 0; n < MYJPWL_MAX_NO_TILESPECS; n++) { + wxGetApp().m_hprotsel[n] = dialog.m_hprotChoice[n]->GetSelection(); + wxGetApp().m_htileval[n] = dialog.m_htileCtrl[n]->GetValue(); + wxGetApp().m_pprotsel[n] = dialog.m_pprotChoice[n]->GetSelection(); + wxGetApp().m_ptileval[n] = dialog.m_ptileCtrl[n]->GetValue(); + wxGetApp().m_ppackval[n] = dialog.m_ppackCtrl[n]->GetValue(); + wxGetApp().m_sensisel[n] = dialog.m_sensiChoice[n]->GetSelection(); + wxGetApp().m_stileval[n] = dialog.m_stileCtrl[n]->GetValue(); + } +#endif // USE_JPWL + }; +} + +void OPJFrame::OnSetsDeco(wxCommandEvent& event) +{ + OPJDecoderDialog dialog(this, event.GetId()); + + if (dialog.ShowModal() == wxID_OK) { + + // load settings + wxGetApp().m_enabledeco = dialog.m_enabledecoCheck->GetValue(); + wxGetApp().m_enableparse = dialog.m_enableparseCheck->GetValue(); + wxGetApp().m_resizemethod = dialog.m_resizeBox->GetSelection() - 1; + wxGetApp().m_reducefactor = dialog.m_reduceCtrl->GetValue(); + wxGetApp().m_qualitylayers = dialog.m_layerCtrl->GetValue(); + wxGetApp().m_components = dialog.m_numcompsCtrl->GetValue(); + wxGetApp().m_framenum = dialog.m_framenumCtrl->GetValue(); +#ifdef USE_JPWL + wxGetApp().m_enablejpwl = dialog.m_enablejpwlCheck->GetValue(); + wxGetApp().m_expcomps = dialog.m_expcompsCtrl->GetValue(); + wxGetApp().m_maxtiles = dialog.m_maxtilesCtrl->GetValue(); +#endif // USE_JPWL + + }; +} + +void OPJFrame::OnQuit(wxCommandEvent& WXUNUSED(event)) +{ + Close(true); +} + +void OPJFrame::OnClose(wxCommandEvent& WXUNUSED(event)) +{ + // current frame + OPJChildFrame *currframe = (OPJChildFrame *) GetActiveChild(); + + if (!currframe) + return; + + wxCloseEvent e; + currframe->OnClose(e); +} + +void OPJFrame::OnFit(wxCommandEvent& event) +{ + OPJChildFrame *currchild; + wxString eventstring = event.GetString(); + + //wxLogMessage(wxT("OnFit:%d:%s"), event.GetInt(), eventstring); + + // current child + if (event.GetInt() >= 1) { + currchild = m_childhash[event.GetInt()]; + } else { + currchild = (OPJChildFrame *) GetActiveChild(); + } + + // problems + if (!currchild) + return; + + // current canvas + OPJCanvas *currcanvas = currchild->m_canvas; + + // find a fit-to-width zoom + /*int zooml, wzooml, hzooml; + wxSize clientsize = currcanvas->GetClientSize(); + wzooml = (int) ceil(100.0 * (double) (clientsize.GetWidth() - 2 * OPJ_CANVAS_BORDER) / (double) (currcanvas->m_image100.GetWidth())); + hzooml = (int) ceil(100.0 * (double) (clientsize.GetHeight() - 2 * OPJ_CANVAS_BORDER) / (double) (currcanvas->m_image100.GetHeight())); + zooml = wxMin(100, wxMin(wzooml, hzooml));*/ + + // fit to width + Rescale(-1, currchild); +} + +void OPJFrame::OnZoom(wxCommandEvent& WXUNUSED(event)) +{ + // current frame + OPJChildFrame *currframe = (OPJChildFrame *) GetActiveChild(); + + if (!currframe) + return; + + // get the preferred zoom + long zooml = wxGetNumberFromUser(wxT("Choose a scale between 5% and 300%"), + wxT("Zoom (%)"), + wxT("Image scale"), + currframe->m_canvas->m_zooml, 5, 300, NULL, wxDefaultPosition); + + // rescale current frame image if necessary + if (zooml >= 5) { + Rescale(zooml, currframe); + wxLogMessage(wxT("zoom to %d%%"), zooml); + } +} + +void OPJFrame::Rescale(int zooml, OPJChildFrame *currframe) +{ + wxImage new_image = currframe->m_canvas->m_image100.ConvertToImage(); + + // resizing enabled? + if (wxGetApp().m_resizemethod == -1) { + + zooml = 100; + + } else { + + if (zooml < 0) { + // find a fit-to-width zoom + int wzooml, hzooml; + //wxSize clientsize = currframe->m_canvas->GetClientSize(); + wxSize clientsize = currframe->m_frame->GetActiveChild()->GetClientSize(); + wzooml = (int) floor(100.0 * (double) clientsize.GetWidth() / (double) (2 * OPJ_CANVAS_BORDER + currframe->m_canvas->m_image100.GetWidth())); + hzooml = (int) floor(100.0 * (double) clientsize.GetHeight() / (double) (2 * OPJ_CANVAS_BORDER + currframe->m_canvas->m_image100.GetHeight())); + zooml = wxMin(100, wxMin(wzooml, hzooml)); + } + } + + if (zooml != 100) + new_image.Rescale((int) ((double) zooml * (double) new_image.GetWidth() / 100.0), + (int) ((double) zooml * (double) new_image.GetHeight() / 100.0), + wxGetApp().m_resizemethod ? wxIMAGE_QUALITY_HIGH : wxIMAGE_QUALITY_NORMAL); + currframe->m_canvas->m_image = wxBitmap(new_image); + currframe->m_canvas->SetScrollbars(20, + 20, + (int)(0.5 + (double) new_image.GetWidth() / 20.0), + (int)(0.5 + (double) new_image.GetHeight() / 20.0) + ); + + currframe->m_canvas->Refresh(); + + wxLogMessage(wxT("Rescale said %d%%"), zooml); + + // update zoom + currframe->m_canvas->m_zooml = zooml; +} + + +void OPJFrame::OnReload(wxCommandEvent& event) +{ + OPJChildFrame *currframe = (OPJChildFrame *) GetActiveChild(); + + if (currframe) { + OPJDecoThread *dthread = currframe->m_canvas->CreateDecoThread(); + + if (dthread->Run() != wxTHREAD_NO_ERROR) + wxLogMessage(wxT("Can't start deco thread!")); + else + wxLogMessage(wxT("New deco thread started.")); + + currframe->m_canvas->Refresh(); + + // update zoom + //currframe->m_canvas->m_zooml = zooml; + } +} + +void OPJFrame::OnPrevFrame(wxCommandEvent& event) +{ + if (--wxGetApp().m_framenum < 0) + wxGetApp().m_framenum = 0; + + wxCommandEvent e; + OnReload(e); +} + +void OPJFrame::OnHomeFrame(wxCommandEvent& event) +{ + wxGetApp().m_framenum = 0; + + wxCommandEvent e; + OnReload(e); +} + +void OPJFrame::OnNextFrame(wxCommandEvent& event) +{ + ++wxGetApp().m_framenum; + + wxCommandEvent e; + OnReload(e); +} + +void OPJFrame::OnLessLayers(wxCommandEvent& event) +{ + if (--wxGetApp().m_qualitylayers < 1) + wxGetApp().m_qualitylayers = 1; + + wxCommandEvent e; + OnReload(e); +} + +void OPJFrame::OnAllLayers(wxCommandEvent& event) +{ + wxGetApp().m_qualitylayers = 0; + + wxCommandEvent e; + OnReload(e); +} + +void OPJFrame::OnMoreLayers(wxCommandEvent& event) +{ + ++wxGetApp().m_qualitylayers; + + wxCommandEvent e; + OnReload(e); +} + +void OPJFrame::OnLessRes(wxCommandEvent& event) +{ + ++wxGetApp().m_reducefactor; + + wxCommandEvent e; + OnReload(e); +} + +void OPJFrame::OnFullRes(wxCommandEvent& event) +{ + wxGetApp().m_reducefactor = 0; + + wxCommandEvent e; + OnReload(e); +} + +void OPJFrame::OnMoreRes(wxCommandEvent& event) +{ + if (--wxGetApp().m_reducefactor < 0) + wxGetApp().m_reducefactor = 0; + + wxCommandEvent e; + OnReload(e); +} + +void OPJFrame::OnPrevComp(wxCommandEvent& event) +{ + if (--wxGetApp().m_components < 1) + wxGetApp().m_components = 1; + + wxCommandEvent e; + OnReload(e); +} + +void OPJFrame::OnAllComps(wxCommandEvent& event) +{ + wxGetApp().m_components = 0; + + wxCommandEvent e; + OnReload(e); +} + +void OPJFrame::OnNextComp(wxCommandEvent& event) +{ + ++wxGetApp().m_components; + + wxCommandEvent e; + OnReload(e); +} + +void OPJFrame::OnToggleBrowser(wxCommandEvent& WXUNUSED(event)) +{ + if (markerTreeWindow->IsShown()) + markerTreeWindow->Show(false); + else + markerTreeWindow->Show(true); + + wxLayoutAlgorithm layout; + layout.LayoutMDIFrame(this); + + wxGetApp().m_showbrowser = markerTreeWindow->IsShown(); + + // Leaves bits of itself behind sometimes + GetClientWindow()->Refresh(); +} + +void OPJFrame::OnTogglePeeker(wxCommandEvent& WXUNUSED(event)) +{ + if (loggingWindow->IsShown()) + loggingWindow->Show(false); + else + loggingWindow->Show(true); + + wxLayoutAlgorithm layout; + layout.LayoutMDIFrame(this); + + wxGetApp().m_showpeeker = loggingWindow->IsShown(); + + // Leaves bits of itself behind sometimes + GetClientWindow()->Refresh(); +} + +void OPJFrame::OnToggleToolbar(wxCommandEvent& WXUNUSED(event)) +{ + if (tool_bar->IsShown()) + tool_bar->Show(false); + else + tool_bar->Show(true); + + wxLayoutAlgorithm layout; + layout.LayoutMDIFrame(this); + + wxGetApp().m_showtoolbar = tool_bar->IsShown(); + + // Leaves bits of itself behind sometimes + GetClientWindow()->Refresh(); +} + +void OPJFrame::OnSashDrag(wxSashEvent& event) +{ + int wid, hei; + + if (event.GetDragStatus() == wxSASH_STATUS_OUT_OF_RANGE) + return; + + switch (event.GetId()) { + case OPJFRAME_BROWSEWIN: + { + markerTreeWindow->SetDefaultSize(wxSize(event.GetDragRect().width, 1000)); + break; + } + case OPJFRAME_LOGWIN: + { + loggingWindow->SetDefaultSize(wxSize(1000, event.GetDragRect().height)); + break; + } + } + + wxLayoutAlgorithm layout; + layout.LayoutMDIFrame(this); + + // Leaves bits of itself behind sometimes + GetClientWindow()->Refresh(); + + // update dimensions + markerTreeWindow->GetSize(&wid, &hei); + wxGetApp().m_browserwidth = wid; + + loggingWindow->GetSize(&wid, &hei); + wxGetApp().m_peekerheight = hei; + +} + +void OPJFrame::OnThreadLogmsg(wxCommandEvent& event) +{ +#if 1 + wxLogMessage(wxT("Frame got message from worker thread: %d"), event.GetInt()); + wxLogMessage(event.GetString()); +#else + int n = event.GetInt(); + if ( n == -1 ) + { + m_dlgProgress->Destroy(); + m_dlgProgress = (wxProgressDialog *)NULL; + + // the dialog is aborted because the event came from another thread, so + // we may need to wake up the main event loop for the dialog to be + // really closed + wxWakeUpIdle(); + } + else + { + if ( !m_dlgProgress->Update(n) ) + { + wxCriticalSectionLocker lock(m_critsectWork); + + m_cancelled = true; + } + } +#endif +} + + +// physically save the file +void OPJFrame::SaveFile(wxArrayString paths, wxArrayString filenames) +{ + size_t count = paths.GetCount(); + wxString msg, s; + + if (wxFile::Exists(paths[0].c_str())) { + + s.Printf(wxT("File %s already exists. Do you want to overwrite it?\n"), filenames[0].c_str()); + wxMessageDialog dialog3(this, s, _T("File exists"), wxYES_NO); + if (dialog3.ShowModal() == wxID_NO) + return; + } + + /*s.Printf(_T("File %d: %s (%s)\n"), (int)0, paths[0].c_str(), filenames[0].c_str()); + msg += s; + + wxMessageDialog dialog2(this, msg, _T("Selected files")); + dialog2.ShowModal();*/ + + if (!GetActiveChild()) + return; + + ((OPJChildFrame *) GetActiveChild())->m_canvas->m_savename = paths[0]; + + OPJEncoThread *ethread = ((OPJChildFrame *) GetActiveChild())->m_canvas->CreateEncoThread(); + + if (ethread->Run() != wxTHREAD_NO_ERROR) + wxLogMessage(wxT("Can't start enco thread!")); + else + wxLogMessage(wxT("New enco thread started.")); + + +} + +// physically open the files +void OPJFrame::OpenFiles(wxArrayString paths, wxArrayString filenames) +{ + + size_t count = paths.GetCount(); + for (size_t n = 0; n < count; n++) { + + wxString msg, s; + s.Printf(_T("File %d: %s (%s)\n"), (int)n, paths[n].c_str(), filenames[n].c_str()); + + msg += s; + + /*wxMessageDialog dialog2(this, msg, _T("Selected files")); + dialog2.ShowModal();*/ + + // Make another frame, containing a canvas + OPJChildFrame *subframe = new OPJChildFrame(this, + paths[n], + winNumber, + wxT("Canvas Frame"), + wxDefaultPosition, wxSize(300, 300), + wxDEFAULT_FRAME_STYLE | wxNO_FULL_REPAINT_ON_RESIZE + ); + m_childhash[winNumber] = subframe; + + // create own marker tree + m_treehash[winNumber] = new OPJMarkerTree(m_bookCtrl, subframe, paths[n], wxT("Parsing..."), TreeTest_Ctrl, + wxDefaultPosition, wxDefaultSize, + wxTR_DEFAULT_STYLE | wxSUNKEN_BORDER + ); + + m_bookCtrl->AddPage(m_treehash[winNumber], wxString::Format(wxT("%u"), winNumber), false); + + for (unsigned int p = 0; p < m_bookCtrl->GetPageCount(); p++) { + if (m_bookCtrl->GetPageText(p) == wxString::Format(wxT("%u"), winNumber)) { + m_bookCtrl->ChangeSelection(p); + break; + } + } + + winNumber++; + } +} + +void OPJFrame::OnFileOpen(wxCommandEvent& WXUNUSED(event)) +{ + wxString wildcards = +#ifdef __WXMOTIF__ + wxT("JPEG 2000 files (*.jp2,*.j2k,*.j2c,*.mj2)|*.*j*2*"); +#else +#if wxUSE_LIBOPENJPEG + wxT("JPEG 2000 files (*.jp2,*.j2k,*.j2c,*.mj2)|*.jp2;*.j2k;*.j2c;*.mj2") +#endif +#if USE_MXF + wxT("|MXF JPEG 2000 video (*.mxf)|*.mxf") +#endif // USE_MXF +#if wxUSE_LIBJPEG + wxT("|JPEG files (*.jpg)|*.jpg") +#endif +#if OPJ_MANYFORMATS + wxT("|BMP files (*.bmp)|*.bmp") + wxT("|PNG files (*.png)|*.png") + wxT("|GIF files (*.gif)|*.gif") + wxT("|PNM files (*.pnm)|*.pnm") + wxT("|TIFF files (*.tif,*.tiff)|*.tif*") +#endif + wxT("|All files|*"); +#endif + wxFileDialog dialog(this, _T("Open image file(s)"), + wxEmptyString, wxEmptyString, wildcards, + wxFD_OPEN|wxFD_MULTIPLE); + + if (dialog.ShowModal() == wxID_OK) { + wxArrayString paths, filenames; + + dialog.GetPaths(paths); + dialog.GetFilenames(filenames); + + OpenFiles(paths, filenames); + } + +} + +void OPJFrame::OnFileSaveAs(wxCommandEvent& WXUNUSED(event)) +{ + wxString wildcards = +#ifdef wxUSE_LIBOPENJPEG +#ifdef __WXMOTIF__ + wxT("JPEG 2000 codestream (*.j2k)|*.*j*2*"); +#else + wxT("JPEG 2000 codestream (*.j2k)|*.j2k") + wxT("|JPEG 2000 file format (*.jp2)|*.jp2"); +#endif +#endif + + wxFileDialog dialog(this, _T("Save image file"), + wxEmptyString, wxEmptyString, wildcards, + wxFD_SAVE); + + if (dialog.ShowModal() == wxID_OK) { + wxArrayString paths, filenames; + + dialog.GetPaths(paths); + dialog.GetFilenames(filenames); + + SaveFile(paths, filenames); + } + + +} + +void OPJFrame::OnMemoryOpen(wxCommandEvent& WXUNUSED(event)) +{ + // do nothing + return; + + wxTextEntryDialog dialog(this, wxT("Memory HEX address range: start_address-stop_address"), + wxT("Decode a memory buffer"), + wxT("0x-0x"), + wxOK | wxCANCEL | wxCENTRE, + wxDefaultPosition); + + if (dialog.ShowModal() == wxID_OK) { + + } + +} + +BEGIN_EVENT_TABLE(OPJCanvas, wxScrolledWindow) + EVT_MOUSE_EVENTS(OPJCanvas::OnEvent) + EVT_MENU(OPJCANVAS_THREADSIGNAL, OPJCanvas::OnThreadSignal) +END_EVENT_TABLE() + +// Define a constructor for my canvas +OPJCanvas::OPJCanvas(wxFileName fname, wxWindow *parent, const wxPoint& pos, const wxSize& size) + : wxScrolledWindow(parent, wxID_ANY, pos, size, + wxSUNKEN_BORDER | wxNO_FULL_REPAINT_ON_RESIZE) +{ + SetBackgroundColour(OPJ_CANVAS_COLOUR); + + m_fname = fname; + m_childframe = (OPJChildFrame *) parent; + // 100% zoom + m_zooml = 100; + + + OPJDecoThread *dthread = CreateDecoThread(); + + if (dthread->Run() != wxTHREAD_NO_ERROR) + wxLogMessage(wxT("Can't start deco thread!")); + else + wxLogMessage(wxT("New deco thread started.")); + + // 100% zoom + //m_zooml = 100; + +} + +OPJDecoThread *OPJCanvas::CreateDecoThread(void) +{ + OPJDecoThread *dthread = new OPJDecoThread(this); + + if (dthread->Create() != wxTHREAD_NO_ERROR) + wxLogError(wxT("Can't create deco thread!")); + + wxCriticalSectionLocker enter(wxGetApp().m_deco_critsect); + wxGetApp().m_deco_threads.Add(dthread); + + return dthread; +} + +OPJEncoThread *OPJCanvas::CreateEncoThread(void) +{ + OPJEncoThread *ethread = new OPJEncoThread(this); + + if (ethread->Create() != wxTHREAD_NO_ERROR) + wxLogError(wxT("Can't create enco thread!")); + + wxCriticalSectionLocker enter(wxGetApp().m_enco_critsect); + wxGetApp().m_enco_threads.Add(ethread); + + return ethread; +} + +#define activeoverlay 0 +// Define the repainting behaviour +void OPJCanvas::OnDraw(wxDC& dc) +{ + if (m_image.Ok()) { + dc.DrawBitmap(m_image, OPJ_CANVAS_BORDER, OPJ_CANVAS_BORDER); + + if (activeoverlay) { + dc.SetPen(*wxRED_PEN); + dc.SetBrush(*wxTRANSPARENT_BRUSH); + //int tw, th; + dc.DrawRectangle(OPJ_CANVAS_BORDER, OPJ_CANVAS_BORDER, + (unsigned long int) (0.5 + (double) m_zooml * (double) m_childframe->m_twidth / 100.0), + (unsigned long int) (0.5 + (double) m_zooml * (double) m_childframe->m_theight / 100.0)); + } + + } else { + dc.SetFont(*wxSWISS_FONT); + dc.SetPen(*wxBLACK_PEN); +#ifdef __WXGTK__ + dc.DrawText(_T("Decoding image, please wait... (press \"Zoom to Fit\" to show the image)"), 40, 50); +#else + dc.DrawText(_T("Decoding image, please wait..."), 40, 50); +#endif + } +} + +// This implements a tiny doodling program! Drag the mouse using +// the left button. +void OPJCanvas::OnEvent(wxMouseEvent& event) +{ +#if USE_PENCIL_ON_CANVAS + wxClientDC dc(this); + PrepareDC(dc); + + wxPoint pt(event.GetLogicalPosition(dc)); + + if ((xpos > -1) && (ypos > -1) && event.Dragging()) { + dc.SetPen(*wxRED_PEN); + dc.DrawLine(xpos, ypos, pt.x, pt.y); + } + xpos = pt.x; + ypos = pt.y; +#endif +} + +void OPJFrame::OnSize(wxSizeEvent& WXUNUSED(event)) +{ + wxLayoutAlgorithm layout; + layout.LayoutMDIFrame(this); +} + +void OPJCanvas::OnThreadSignal(wxCommandEvent& event) +{ +#if 1 + wxLogMessage(wxT("Canvas got signal from deco thread: %d"), event.GetInt()); + wxLogMessage(event.GetString()); +#else + int n = event.GetInt(); + if ( n == -1 ) + { + m_dlgProgress->Destroy(); + m_dlgProgress = (wxProgressDialog *)NULL; + + // the dialog is aborted because the event came from another thread, so + // we may need to wake up the main event loop for the dialog to be + // really closed + wxWakeUpIdle(); + } + else + { + if ( !m_dlgProgress->Update(n) ) + { + wxCriticalSectionLocker lock(m_critsectWork); + + m_cancelled = true; + } + } +#endif +} + + +// Note that OPJFRAME_FILEOPEN and OPJFRAME_HELPABOUT commands get passed +// to the parent window for processing, so no need to +// duplicate event handlers here. + +BEGIN_EVENT_TABLE(OPJChildFrame, wxMDIChildFrame) + /*EVT_MENU(SASHTEST_CHILD_QUIT, OPJChildFrame::OnQuit)*/ + EVT_CLOSE(OPJChildFrame::OnClose) + EVT_SET_FOCUS(OPJChildFrame::OnGotFocus) + EVT_KILL_FOCUS(OPJChildFrame::OnLostFocus) +END_EVENT_TABLE() + +OPJChildFrame::OPJChildFrame(OPJFrame *parent, wxFileName fname, int winnumber, const wxString& title, const wxPoint& pos, const wxSize& size, +const long style): + wxMDIChildFrame(parent, wxID_ANY, title, pos, size, style) +{ + m_frame = (OPJFrame *) parent; + m_canvas = NULL; + //my_children.Append(this); + m_fname = fname; + m_winnumber = winnumber; + SetTitle(wxString::Format(_T("%d: "), m_winnumber) + m_fname.GetFullName()); + + // Give it an icon (this is ignored in MDI mode: uses resources) +#ifdef __WXMSW__ + SetIcon(wxIcon(wxT("OPJChild16"))); +#endif + + // Give it a status line + /*CreateStatusBar();*/ + + int width, height; + GetClientSize(&width, &height); + + OPJCanvas *canvas = new OPJCanvas(fname, this, wxPoint(0, 0), wxSize(width, height)); +#if USE_PENCIL_ON_CANVAS + canvas->SetCursor(wxCursor(wxCURSOR_PENCIL)); +#endif + m_canvas = canvas; + + // Give it scrollbars + canvas->SetScrollbars(20, 20, 5, 5); + + Show(true); + Maximize(true); + + /*wxLogError(wxString::Format(wxT("Created tree %d (0x%x)"), m_winnumber, m_frame->m_treehash[m_winnumber]));*/ + +} + +OPJChildFrame::~OPJChildFrame(void) +{ + //my_children.DeleteObject(this); +} + + +void OPJChildFrame::OnClose(wxCloseEvent& event) +{ + for (unsigned int p = 0; p < m_frame->m_bookCtrl->GetPageCount(); p++) { + if (m_frame->m_bookCtrl->GetPageText(p) == wxString::Format(wxT("%u"), m_winnumber)) { + m_frame->m_bookCtrl->DeletePage(p); + break; + } + } + Destroy(); + + wxLogMessage(wxT("Closed: %d"), m_winnumber); +} + +void OPJChildFrame::OnActivate(wxActivateEvent& event) +{ + /*if (event.GetActive() && m_canvas) + m_canvas->SetFocus();*/ +} + +void OPJChildFrame::OnGotFocus(wxFocusEvent& event) +{ + // we need to check if the notebook is being destroyed or not + if (!m_frame->m_bookCtrl) + return; + + for (unsigned int p = 0; p < m_frame->m_bookCtrl->GetPageCount(); p++) { + + if (m_frame->m_bookCtrl->GetPageText(p) == wxString::Format(wxT("%u"), m_winnumber)) { + m_frame->m_bookCtrl->ChangeSelection(p); + break; + } + + } + + //wxLogMessage(wxT("Got focus: %d (%x)"), m_winnumber, event.GetWindow()); +} + +void OPJChildFrame::OnLostFocus(wxFocusEvent& event) +{ + //wxLogMessage(wxT("Lost focus: %d (%x)"), m_winnumber, event.GetWindow()); +} + + +//////////////////////////////// +// drag and drop +//////////////////////////////// + +bool OPJDnDFile::OnDropFiles(wxCoord, wxCoord, const wxArrayString& filenames) +{ + /*size_t nFiles = filenames.GetCount(); + wxString str; + str.Printf( _T("%d files dropped\n"), (int)nFiles); + for ( size_t n = 0; n < nFiles; n++ ) { + str << filenames[n] << wxT("\n"); + } + wxLogMessage(str);*/ + m_pOwner->OpenFiles(filenames, filenames); + + return true; +} + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/OPJViewer.h b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/OPJViewer.h new file mode 100644 index 0000000..15d7477 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/OPJViewer.h @@ -0,0 +1,811 @@ +/* + * Copyright (c) 2007, Digital Signal Processing Laboratory, Università degli studi di Perugia (UPG), Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +///////////////////////////////////////////////////////////////////////////// +// Name: sashtest.h +// Purpose: Layout window/sash sample +// Author: Julian Smart +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id: sashtest.h,v 1.5 2005/06/02 12:04:24 JS Exp $ +// Copyright: (c) Julian Smart +// Licence: wxWindows license +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +// Name: treectrl.h +// Purpose: wxTreeCtrl sample +// Author: Julian Smart +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id: treetest.h,v 1.50 2006/11/04 11:26:51 VZ Exp $ +// Copyright: (c) Julian Smart +// Licence: wxWindows license +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +// Name: dialogs.h +// Purpose: Common dialogs demo +// Author: Julian Smart +// Modified by: ABX (2004) - adjustementd for conditional building +// Created: 04/01/98 +// RCS-ID: $Id: dialogs.h,v 1.50 2006/10/08 14:12:59 VZ Exp $ +// Copyright: (c) Julian Smart +// Licence: wxWindows license +///////////////////////////////////////////////////////////////////////////// + +#ifndef __OPJ_VIEWER_H__ +#define __OPJ_VIEWER_H__ + +// For compilers that support precompilation, includes "wx/wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include "wx/wx.h" +#include "wx/mdi.h" +#endif + +#include "wx/toolbar.h" +#include "wx/laywin.h" +#include "wx/treectrl.h" + +#include "icon1.xpm" +#include "icon2.xpm" +#include "icon3.xpm" +#include "icon4.xpm" +#include "icon5.xpm" + +#include "wx/filedlg.h" +#include "wx/toolbar.h" +#include +#include +#include +#include +#include "wx/notebook.h" +#include + +#include "wx/propdlg.h" +#include "wx/spinctrl.h" + +#include +#include "wx/wxhtml.h" +#include "wx/statline.h" +#include + +#include + +#include "wx/toolbar.h" +#include "wx/artprov.h" + +#include "libopenjpeg/openjpeg.h" + +//#include "imagj2k.h" +//#include "imagjp2.h" +//#include "imagmj2.h" +#include "imagjpeg2000.h" +#ifdef USE_MXF +#include "imagmxf.h" +#endif // USE_MXF + +#ifdef __WXMSW__ +typedef unsigned __int64 int8byte; +#endif // __WXMSW__ + +#ifdef __WXGTK__ +typedef unsigned long long int8byte; +#endif // __WXGTK__ + +#define USE_GENERIC_TREECTRL 0 +#define USE_PENCIL_ON_CANVAS 0 + +#if USE_GENERIC_TREECTRL +#include "wx/generic/treectlg.h" +#ifndef wxTreeCtrl +#define wxTreeCtrl wxGenericTreeCtrl +#define sm_classwxTreeCtrl sm_classwxGenericTreeCtrl +#endif +#endif + +#define OPJ_APPLICATION wxT("OPJViewer") +#define OPJ_APPLICATION_NAME wxT("OpenJPEG Viewer") +#define OPJ_APPLICATION_VERSION wxT("0.4 beta") +#define OPJ_APPLICATION_TITLEBAR OPJ_APPLICATION_NAME wxT(" ") OPJ_APPLICATION_VERSION +#define OPJ_APPLICATION_COPYRIGHT wxT("(C) 2007-2008, Giuseppe Baruffa") +#define OPJ_APPLICATION_VENDOR wxT("OpenJPEG") + +#ifdef __WXMSW__ +#define OPJ_APPLICATION_PLATFORM wxT("Windows") +#endif + +#ifdef __WXGTK__ +#define OPJ_APPLICATION_PLATFORM wxT("Linux") +#endif + +#define OPJ_FRAME_WIDTH 800 +#define OPJ_FRAME_HEIGHT 600 + +#define OPJ_BROWSER_WIDTH 300 +#define OPJ_PEEKER_HEIGHT 130 + +#define OPJ_CANVAS_BORDER 10 +#define OPJ_CANVAS_COLOUR *wxWHITE + + + +#ifdef USE_JPWL + +//#define MYJPWL_MAX_NO_TILESPECS JPWL_MAX_NO_TILESPECS +#define MYJPWL_MAX_NO_TILESPECS 4 + +#endif // USE_JPWL + + +class OPJDecoThread; +class OPJEncoThread; +class OPJParseThread; +WX_DEFINE_ARRAY_PTR(wxThread *, wxArrayThread); +class OPJChildFrame; + +////////////////////////////////// +// this is our main application // +////////////////////////////////// +class OPJViewerApp: public wxApp +{ + // public methods and variables + public: + + // class constructor + OPJViewerApp() { m_showImages = true; m_showButtons = false; } + + // other methods + bool OnInit(void); + int OnExit(void); + void SetShowImages(bool show) { m_showImages = show; } + bool ShowImages() const { return m_showImages; } + void ShowCmdLine(const wxCmdLineParser& parser); + + // all the threads currently alive - as soon as the thread terminates, it's + // removed from the array + wxArrayThread m_deco_threads, m_parse_threads, m_enco_threads; + + // crit section protects access to all of the arrays below + wxCriticalSection m_deco_critsect, m_parse_critsect, m_enco_critsect; + + // semaphore used to wait for the threads to exit, see OPJFrame::OnQuit() + wxSemaphore m_deco_semAllDone, m_parse_semAllDone, m_enco_semAllDone; + + // the last exiting thread should post to m_semAllDone if this is true + // (protected by the same m_critsect) + bool m_deco_waitingUntilAllDone, m_parse_waitingUntilAllDone, m_enco_waitingUntilAllDone; + + // the list of all filenames written in the command line + wxArrayString m_filelist; + + // displaying engine parameters + int m_resizemethod; + + // decoding engine parameters + bool m_enabledeco, m_enableparse; + int m_reducefactor, m_qualitylayers, m_components, m_framenum; +#ifdef USE_JPWL + bool m_enablejpwl, m_enablejpwle; + int m_expcomps, m_maxtiles; + int m_framewidth, m_frameheight; +#endif // USE_JPWL + + // encoding engine parameters + wxString m_subsampling, m_origin, m_rates, m_comment, m_index, m_quality; + wxString m_cbsize, m_prsize, m_tsize, m_torigin, m_poc; + bool m_enablecomm, m_enableidx, m_multicomp, m_irreversible, m_enablesop, m_enableeph; + bool m_enablebypass, m_enablereset, m_enablerestart, m_enablevsc, m_enableerterm; + bool m_enablesegmark, m_enablepoc; + bool m_enablequality; + int m_resolutions, m_progression; +#ifdef USE_JPWL + int m_hprotsel[MYJPWL_MAX_NO_TILESPECS], m_pprotsel[MYJPWL_MAX_NO_TILESPECS]; + int m_htileval[MYJPWL_MAX_NO_TILESPECS], m_ptileval[MYJPWL_MAX_NO_TILESPECS], + m_ppackval[MYJPWL_MAX_NO_TILESPECS]; + int m_sensisel[MYJPWL_MAX_NO_TILESPECS], m_stileval[MYJPWL_MAX_NO_TILESPECS]; +#endif // USE_JPWL + + // some layout settings + bool m_showtoolbar, m_showbrowser, m_showpeeker; + int m_browserwidth, m_peekerheight; + + // application configuration + wxConfig *OPJconfig; + + // private methods and variables + private: + bool m_showImages, m_showButtons; + +}; + +DECLARE_APP(OPJViewerApp) + +/////////////////////////////////////////// +// this canvas is used to draw the image // +/////////////////////////////////////////// +class OPJCanvas: public wxScrolledWindow +{ + // public methods and variables + public: + + // class constructor + OPJCanvas(wxFileName fname, wxWindow *parent, const wxPoint& pos, const wxSize& size); + + virtual void OnDraw(wxDC& dc); + void OnEvent(wxMouseEvent& event); + void WriteText(const wxString& text) { +#ifndef __WXGTK__ + wxMutexGuiEnter(); +#endif //__WXGTK__ + wxLogMessage(text); +#ifndef __WXGTK__ + wxMutexGuiLeave(); +#endif //__WXGTK__ + } + + void OnThreadSignal(wxCommandEvent& event); + + OPJDecoThread *CreateDecoThread(void); + OPJEncoThread *CreateEncoThread(void); + + + OPJChildFrame *m_childframe; + + wxBitmap m_image, m_image100; + wxFileName m_fname, m_savename; + long m_zooml; + + DECLARE_EVENT_TABLE() +}; + +/////////////////////////////////////////////////// +// the data associated to each tree leaf or node // +/////////////////////////////////////////////////// +class OPJMarkerData : public wxTreeItemData +{ + // public methods and variables + public: + + // class constructor + OPJMarkerData(const wxString& desc, const wxString& fname = wxT(""), wxFileOffset start = 0, wxFileOffset length = 0) : m_desc(desc), m_filestring(fname) { m_start = start; m_length = length; } + + void ShowInfo(wxTreeCtrl *tree); + const wxChar *GetDesc1() const { return m_desc.c_str(); } + const wxChar *GetDesc2() const { return m_filestring.c_str(); } + wxFileOffset m_start, m_length; + wxString m_desc; + + // private methods and variables + private: + wxString m_filestring; +}; + + +class OPJMarkerTree : public wxTreeCtrl +{ +public: + enum + { + TreeCtrlIcon_File, + TreeCtrlIcon_FileSelected, + TreeCtrlIcon_Folder, + TreeCtrlIcon_FolderSelected, + TreeCtrlIcon_FolderOpened + }; + + OPJMarkerTree() { }; + OPJMarkerTree(wxWindow *parent, OPJChildFrame *subframe, wxFileName fname, wxString name, const wxWindowID id, + const wxPoint& pos, const wxSize& size, + long style); + virtual ~OPJMarkerTree(){}; + OPJParseThread *CreateParseThread(wxTreeItemId parentid = 0x00, OPJChildFrame *subframe = NULL); + void WriteText(const wxString& text) { wxMutexGuiEnter(); wxLogMessage(text); wxMutexGuiLeave(); } + + wxFileName m_fname; + wxTextCtrl *m_peektextCtrl; + OPJChildFrame *m_childframe; + + /*void OnBeginDrag(wxTreeEvent& event); + void OnBeginRDrag(wxTreeEvent& event); + void OnEndDrag(wxTreeEvent& event);*/ + /*void OnBeginLabelEdit(wxTreeEvent& event); + void OnEndLabelEdit(wxTreeEvent& event);*/ + /*void OnDeleteItem(wxTreeEvent& event);*/ + /*void OnContextMenu(wxContextMenuEvent& event);*/ + void OnItemMenu(wxTreeEvent& event); + /*void OnGetInfo(wxTreeEvent& event); + void OnSetInfo(wxTreeEvent& event);*/ + /*void OnItemExpanded(wxTreeEvent& event);*/ + void OnItemExpanding(wxTreeEvent& event); + /*void OnItemCollapsed(wxTreeEvent& event); + void OnItemCollapsing(wxTreeEvent& event);*/ + void OnSelChanged(wxTreeEvent& event); + /*void OnSelChanging(wxTreeEvent& event);*/ + /*void OnTreeKeyDown(wxTreeEvent& event);*/ + /*void OnItemActivated(wxTreeEvent& event);*/ + /*void OnItemRClick(wxTreeEvent& event);*/ + /*void OnRMouseDown(wxMouseEvent& event); + void OnRMouseUp(wxMouseEvent& event); + void OnRMouseDClick(wxMouseEvent& event);*/ + /*void GetItemsRecursively(const wxTreeItemId& idParent, + wxTreeItemIdValue cookie = 0);*/ + + void CreateImageList(int size = 16); + void CreateButtonsImageList(int size = 11); + + /*void AddTestItemsToTree(size_t numChildren, size_t depth);*/ + /*void DoSortChildren(const wxTreeItemId& item, bool reverse = false) + { m_reverseSort = reverse; wxTreeCtrl::SortChildren(item); }*/ + /*void DoEnsureVisible() { if (m_lastItem.IsOk()) EnsureVisible(m_lastItem); }*/ + /*void DoToggleIcon(const wxTreeItemId& item);*/ + /*void ShowMenu(wxTreeItemId id, const wxPoint& pt);*/ + + int ImageSize(void) const { return m_imageSize; } + + void SetLastItem(wxTreeItemId id) { m_lastItem = id; } + +protected: + /*virtual int OnCompareItems(const wxTreeItemId& i1, const wxTreeItemId& i2);*/ + + // is this the test item which we use in several event handlers? + /*bool IsTestItem(const wxTreeItemId& item) + { + // the test item is the first child folder + return GetItemParent(item) == GetRootItem() && !GetPrevSibling(item); + }*/ + +private: + /*void AddItemsRecursively(const wxTreeItemId& idParent, + size_t nChildren, + size_t depth, + size_t folder);*/ + + void LogEvent(const wxChar *name, const wxTreeEvent& event); + + int m_imageSize; // current size of images + bool m_reverseSort; // flag for OnCompareItems + wxTreeItemId m_lastItem, // for OnEnsureVisible() + m_draggedItem; // item being dragged right now + + // NB: due to an ugly wxMSW hack you _must_ use DECLARE_DYNAMIC_CLASS() + // if you want your overloaded OnCompareItems() to be called. + // OTOH, if you don't want it you may omit the next line - this will + // make default (alphabetical) sorting much faster under wxMSW. + DECLARE_DYNAMIC_CLASS(OPJMarkerTree) + DECLARE_EVENT_TABLE() +}; + +// this hash map stores all the trees of currently opened images, with an integer key +WX_DECLARE_HASH_MAP(int, OPJMarkerTree*, wxIntegerHash, wxIntegerEqual, OPJMarkerTreeHash); + +// this hash map stores all the children of currently opened images, with an integer key +WX_DECLARE_HASH_MAP(int, OPJChildFrame*, wxIntegerHash, wxIntegerEqual, OPJChildFrameHash); + +// Define a new frame +class OPJFrame: public wxMDIParentFrame +{ + public: + + OPJFrame(wxWindow *parent, const wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, const long style); + + ~OPJFrame(void); + void OnSize(wxSizeEvent& WXUNUSED(event)); + void OnAbout(wxCommandEvent& WXUNUSED(event)); + void OnFileOpen(wxCommandEvent& WXUNUSED(event)); + void OnFileSaveAs(wxCommandEvent& WXUNUSED(event)); + void OnMemoryOpen(wxCommandEvent& WXUNUSED(event)); + void OnQuit(wxCommandEvent& WXUNUSED(event)); + void OnClose(wxCommandEvent& WXUNUSED(event)); + void OnZoom(wxCommandEvent& WXUNUSED(event)); + void OnFit(wxCommandEvent& event); + void OnToggleBrowser(wxCommandEvent& WXUNUSED(event)); + void OnTogglePeeker(wxCommandEvent& WXUNUSED(event)); + void OnToggleToolbar(wxCommandEvent& WXUNUSED(event)); + void OnReload(wxCommandEvent& event); + void OnPrevFrame(wxCommandEvent& event); + void OnHomeFrame(wxCommandEvent& event); + void OnNextFrame(wxCommandEvent& event); + void OnLessLayers(wxCommandEvent& event); + void OnAllLayers(wxCommandEvent& event); + void OnMoreLayers(wxCommandEvent& event); + void OnLessRes(wxCommandEvent& event); + void OnFullRes(wxCommandEvent& event); + void OnMoreRes(wxCommandEvent& event); + void OnPrevComp(wxCommandEvent& event); + void OnAllComps(wxCommandEvent& event); + void OnNextComp(wxCommandEvent& event); + void OnSetsEnco(wxCommandEvent& event); + void OnSetsDeco(wxCommandEvent& event); + void OnSashDrag(wxSashEvent& event); + void OpenFiles(wxArrayString paths, wxArrayString filenames); + void SaveFile(wxArrayString paths, wxArrayString filenames); + void OnNotebook(wxNotebookEvent& event); + void Rescale(int scale, OPJChildFrame *child); + void OnThreadLogmsg(wxCommandEvent& event); + + OPJMarkerTreeHash m_treehash; + OPJChildFrameHash m_childhash; + wxSashLayoutWindow* markerTreeWindow; + wxSashLayoutWindow* loggingWindow; + wxToolBar* tool_bar; + void Resize(int number); + wxNotebook *m_bookCtrl; + wxNotebook *m_bookCtrlbottom; + wxTextCtrl *m_textCtrlbrowse; + + private: + void TogStyle(int id, long flag); + + void DoSort(bool reverse = false); + + wxPanel *m_panel; + wxTextCtrl *m_textCtrl; + + void DoSetBold(bool bold = true); + +protected: + wxSashLayoutWindow* m_topWindow; + wxSashLayoutWindow* m_leftWindow2; + +DECLARE_EVENT_TABLE() +}; + +class OPJChildFrame: public wxMDIChildFrame +{ + public: + OPJCanvas *m_canvas; + OPJChildFrame(OPJFrame *parent, wxFileName fname, int winnumber, const wxString& title, const wxPoint& pos, const wxSize& size, const long style); + ~OPJChildFrame(void); + void OnActivate(wxActivateEvent& event); + /*void OnQuit(wxCommandEvent& WXUNUSED(event));*/ + void OnClose(wxCloseEvent& event); + void OnGotFocus(wxFocusEvent& event); + void OnLostFocus(wxFocusEvent& event); + OPJFrame *m_frame; + wxFileName m_fname; + int m_winnumber; + + unsigned long m_twidth, m_theight, m_tx, m_ty; + + DECLARE_EVENT_TABLE() +}; + +// frame and main menu ids +enum { + OPJFRAME_FILEEXIT = wxID_EXIT, + OPJFRAME_HELPABOUT = wxID_ABOUT, + OPJFRAME_FILEOPEN, + OPJFRAME_MEMORYOPEN, + OPJFRAME_FILESAVEAS, + OPJFRAME_FILETOGGLEB, + OPJFRAME_FILETOGGLEP, + OPJFRAME_FILETOGGLET, + OPJFRAME_VIEWZOOM, + OPJFRAME_VIEWFIT, + OPJFRAME_VIEWRELOAD, + OPJFRAME_VIEWPREVFRAME, + OPJFRAME_VIEWHOMEFRAME, + OPJFRAME_VIEWNEXTFRAME, + OPJFRAME_VIEWLESSLAYERS, + OPJFRAME_VIEWALLLAYERS, + OPJFRAME_VIEWMORELAYERS, + OPJFRAME_VIEWLESSRES, + OPJFRAME_VIEWFULLRES, + OPJFRAME_VIEWMORERES, + OPJFRAME_VIEWPREVCOMP, + OPJFRAME_VIEWALLCOMPS, + OPJFRAME_VIEWNEXTCOMP, + OPJFRAME_FILECLOSE, + OPJFRAME_SETSENCO, + OPJFRAME_SETSDECO, + + OPJFRAME_BROWSEWIN = 10000, + OPJFRAME_LOGWIN, + OPJFRAME_TOOLBAR, + + OPJFRAME_THREADLOGMSG, + OPJCANVAS_THREADSIGNAL +}; + + +// menu and control ids +enum +{ + TreeTest_Quit = wxID_EXIT, + TreeTest_About = wxID_ABOUT, + TreeTest_TogButtons = wxID_HIGHEST, + TreeTest_TogTwist, + TreeTest_TogLines, + TreeTest_TogEdit, + TreeTest_TogHideRoot, + TreeTest_TogRootLines, + TreeTest_TogBorder, + TreeTest_TogFullHighlight, + TreeTest_SetFgColour, + TreeTest_SetBgColour, + TreeTest_ResetStyle, + TreeTest_Highlight, + TreeTest_Dump, + TreeTest_DumpSelected, + TreeTest_Count, + TreeTest_CountRec, + TreeTest_Sort, + TreeTest_SortRev, + TreeTest_SetBold, + TreeTest_ClearBold, + TreeTest_Rename, + TreeTest_Delete, + TreeTest_DeleteChildren, + TreeTest_DeleteAll, + TreeTest_Recreate, + TreeTest_ToggleImages, + TreeTest_ToggleButtons, + TreeTest_SetImageSize, + TreeTest_ToggleSel, + TreeTest_CollapseAndReset, + TreeTest_EnsureVisible, + TreeTest_AddItem, + TreeTest_InsertItem, + TreeTest_IncIndent, + TreeTest_DecIndent, + TreeTest_IncSpacing, + TreeTest_DecSpacing, + TreeTest_ToggleIcon, + TreeTest_Select, + TreeTest_Unselect, + TreeTest_SelectRoot, + TreeTest_Ctrl = 1000, + BOTTOM_NOTEBOOK_ID, + LEFT_NOTEBOOK_ID +}; + +class OPJEncoThread : public wxThread +{ +public: + OPJEncoThread(OPJCanvas *canvas); + + // thread execution starts here + virtual void *Entry(); + + // called when the thread exits - whether it terminates normally or is + // stopped with Delete() (but not when it is Kill()ed!) + virtual void OnExit(); + + // write something to the text control + void WriteText(const wxString& text); + +public: + unsigned m_count; + OPJCanvas *m_canvas; +}; + +class OPJDecoThread : public wxThread +{ +public: + OPJDecoThread(OPJCanvas *canvas); + + // thread execution starts here + virtual void *Entry(); + + // called when the thread exits - whether it terminates normally or is + // stopped with Delete() (but not when it is Kill()ed!) + virtual void OnExit(); + + // write something to the text control + void WriteText(const wxString& text); + +public: + unsigned m_count; + OPJCanvas *m_canvas; +}; + +class OPJParseThread : public wxThread +{ +public: + OPJParseThread(OPJMarkerTree *tree, wxTreeItemId parentid = 0x00); + + // thread execution starts here + virtual void *Entry(); + + // called when the thread exits - whether it terminates normally or is + // stopped with Delete() (but not when it is Kill()ed!) + virtual void OnExit(); + + // write something to the text control + void WriteText(const wxString& text); + void LoadFile(wxFileName fname); + void ParseJ2KFile(wxFile *m_file, wxFileOffset offset, wxFileOffset length, wxTreeItemId parentid); + void ParseJP2File(wxFile *fileid, wxFileOffset filepoint, wxFileOffset filelimit, wxTreeItemId parentid); + + unsigned m_count; + OPJMarkerTree *m_tree; + wxTreeItemId m_parentid; + +private: + int jpeg2000parse(wxFile *fileid, wxFileOffset filepoint, wxFileOffset filelimit, + wxTreeItemId parentid, int level, char *scansign, unsigned long int *scanpoint); + int box_handler_function(int boxtype, wxFile *fileid, wxFileOffset filepoint, wxFileOffset filelimit, + wxTreeItemId parentid, int level, char *scansign, unsigned long int *scanpoint); + +}; + + +// Drag and drop files target +class OPJDnDFile: public wxFileDropTarget +{ +public: + OPJDnDFile(OPJFrame *pOwner) { m_pOwner = pOwner; } + virtual bool OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& filenames); + +private: + OPJFrame *m_pOwner; +}; + + + +// Property sheet dialog: encoder +class OPJEncoderDialog: public wxPropertySheetDialog +{ +DECLARE_CLASS(OPJEncoderDialog) +public: + OPJEncoderDialog(wxWindow* parent, int dialogType); + ~OPJEncoderDialog(); + + wxBookCtrlBase* m_settingsNotebook; + + wxPanel* CreateMainSettingsPage(wxWindow* parent); + wxPanel* CreatePart1_1SettingsPage(wxWindow* parent); + wxPanel* CreatePart1_2SettingsPage(wxWindow* parent); +/* wxPanel* CreatePart3SettingsPage(wxWindow* parent);*/ + void OnEnableComm(wxCommandEvent& event); + void OnEnableIdx(wxCommandEvent& event); + void OnEnablePoc(wxCommandEvent& event); + void OnRadioQualityRate(wxCommandEvent& event); +#ifdef USE_JPWL + void OnEnableJPWL(wxCommandEvent& event); + wxPanel* CreatePart11SettingsPage(wxWindow* parent); + /*wxCheckBox *m_enablejpwlCheck;*/ + wxChoice *m_hprotChoice[MYJPWL_MAX_NO_TILESPECS]; + wxSpinCtrl *m_htileCtrl[MYJPWL_MAX_NO_TILESPECS]; + wxChoice *m_pprotChoice[MYJPWL_MAX_NO_TILESPECS]; + wxSpinCtrl *m_ptileCtrl[MYJPWL_MAX_NO_TILESPECS]; + wxSpinCtrl *m_ppackCtrl[MYJPWL_MAX_NO_TILESPECS]; + wxChoice *m_sensiChoice[MYJPWL_MAX_NO_TILESPECS]; + wxSpinCtrl *m_stileCtrl[MYJPWL_MAX_NO_TILESPECS]; + void OnHprotSelect(wxCommandEvent& event); + void OnPprotSelect(wxCommandEvent& event); + void OnSensiSelect(wxCommandEvent& event); +#endif // USE_JPWL + + wxTextCtrl *m_subsamplingCtrl, *m_originCtrl, *m_rateCtrl, *m_commentCtrl; + wxRadioButton *m_rateRadio, *m_qualityRadio; + wxTextCtrl *m_indexCtrl, *m_qualityCtrl, *m_cbsizeCtrl, *m_prsizeCtrl, *m_pocCtrl; + wxTextCtrl *m_tsizeCtrl, *m_toriginCtrl; + wxRadioBox *progressionBox; + wxCheckBox *m_enablecommCheck, *m_enableidxCheck, *m_mctCheck, *m_irrevCheck; + wxCheckBox *m_sopCheck, *m_ephCheck, *m_enablebypassCheck, *m_enableresetCheck, + *m_enablerestartCheck, *m_enablevscCheck, *m_enableertermCheck, *m_enablesegmarkCheck; + wxCheckBox *m_enablepocCheck, *m_enablejpwlCheck; + wxSpinCtrl *m_resolutionsCtrl; + +protected: + + enum { + OPJENCO_ENABLEJPWL = 100, + OPJENCO_RATEFACTOR, + OPJENCO_RATERADIO, + OPJENCO_QUALITYFACTOR, + OPJENCO_QUALITYRADIO, + OPJENCO_RESNUMBER, + OPJENCO_CODEBLOCKSIZE, + OPJENCO_PRECINCTSIZE, + OPJENCO_TILESIZE, + OPJENCO_PROGRESSION, + OPJENCO_SUBSAMPLING, + OPJENCO_ENABLESOP, + OPJENCO_ENABLEEPH, + OPJENCO_ENABLEBYPASS, + OPJENCO_ENABLERESET, + OPJENCO_ENABLERESTART, + OPJENCO_ENABLEVSC, + OPJENCO_ENABLEERTERM, + OPJENCO_ENABLESEGMARK, + OPJENCO_ENABLEPOC, + OPJENCO_ROICOMP, + OPJENCO_ROISHIFT, + OPJENCO_IMORIG, + OPJENCO_TILORIG, + OPJENCO_ENABLEMCT, + OPJENCO_ENABLEIRREV, + OPJENCO_ENABLEINDEX, + OPJENCO_INDEXNAME, + OPJENCO_POCSPEC, + OPJENCO_ENABLECOMM, + OPJENCO_COMMENTTEXT, + OPJENCO_HPROT, + OPJENCO_HTILE, + OPJENCO_PPROT, + OPJENCO_PTILE, + OPJENCO_PPACK, + OPJENCO_SENSI, + OPJENCO_STILE + }; + +DECLARE_EVENT_TABLE() +}; + +// Property sheet dialog: decoder +class OPJDecoderDialog: public wxPropertySheetDialog +{ +DECLARE_CLASS(OPJDecoderDialog) +public: + OPJDecoderDialog(wxWindow* parent, int dialogType); + ~OPJDecoderDialog(); + + wxBookCtrlBase* m_settingsNotebook; + wxCheckBox *m_enabledecoCheck, *m_enableparseCheck; + wxSpinCtrl *m_reduceCtrl, *m_layerCtrl, *m_numcompsCtrl; + wxRadioBox* m_resizeBox; + + void OnEnableDeco(wxCommandEvent& event); + + wxPanel* CreateMainSettingsPage(wxWindow* parent); + wxPanel* CreatePart1SettingsPage(wxWindow* parent); + wxPanel* CreatePart3SettingsPage(wxWindow* parent); +#ifdef USE_JPWL + void OnEnableJPWL(wxCommandEvent& event); + wxPanel* CreatePart11SettingsPage(wxWindow* parent); + wxSpinCtrl *m_expcompsCtrl, *m_framenumCtrl, *m_maxtilesCtrl; + wxCheckBox *m_enablejpwlCheck; +#endif // USE_JPWL + + +protected: + + enum { + OPJDECO_RESMETHOD = 100, + OPJDECO_REDUCEFACTOR, + OPJDECO_QUALITYLAYERS, + OPJDECO_NUMCOMPS, + OPJDECO_ENABLEDECO, + OPJDECO_ENABLEPARSE, + OPJDECO_ENABLEJPWL, + OPJDECO_EXPCOMPS, + OPJDECO_MAXTILES, + OPJDECO_FRAMENUM + }; + +DECLARE_EVENT_TABLE() +}; + +#endif //__OPJ_VIEWER_H__ + + + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/OPJViewer.ico b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/OPJViewer.ico new file mode 100644 index 0000000000000000000000000000000000000000..931d5e021191a3fd17610e14bec8405796abfb57 GIT binary patch literal 1078 zcmcIjy-ou$40Z|<%7QLq7U)F#6orkAmtg1vbVa(`x*)iSDNFk*hlJE3Rn03@q5~t{ zm?+=pP^p#5KqY+V*p5FtKXycnw4~iGg!JALxqvK+Yw>5)hmb8YYy*vK(PkqX%T zRKW>PRb_z@sx(alNyl1$S+A*q@o|d7zmu=U*EU8M#q*5LLB>K%_1=8kaY-~##k#u4j_eDE{ZNy=jKO#9-!Bqkov9D}%;ll|%u$NXd zn^x1+aQXT%Tu!C)GHW{Xn^s@JX*=YrT-=qHlU_M~9F^nos7&MeIrtjfPia0#>0yxG z&Ti9Z?_?*ES=i?|vG)3=&zoP5Q=!M02=(wj=Y5m(ULmysA%o?XP!0gRR+4pB yH0$f&BZBQpNj8{d>4fFdV66}}rTpIT<|bP_g#IM*jAwWc9+kU1gT25!W4{3rvE}0c literal 0 HcmV?d00001 diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/OPJViewer.rc b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/OPJViewer.rc new file mode 100644 index 0000000..82af985 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/OPJViewer.rc @@ -0,0 +1,3 @@ +OPJChild16 ICON OPJChild.ico +OPJViewer16 ICON OPJViewer.ico +#include "wx/msw/wx.rc" \ No newline at end of file diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/OPJViewer16.xpm b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/OPJViewer16.xpm new file mode 100644 index 0000000..7c65acb --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/OPJViewer16.xpm @@ -0,0 +1,26 @@ +/* XPM */ +static char *OPJViewer16[] = { +/* columns rows colors chars-per-pixel */ +"16 16 4 1", +" c black", +". c #800000", +"X c red", +"o c None", +/* pixels */ +"oooooooooooooooo", +"ooo.XXXXoooooooo", +"ooXXoo .Xooooooo", +"o..oooo .ooooooo", +"oX.oooo ooooooo", +"oX.oooo .ooooooo", +"oXXoooo .ooooooo", +"o.XXoo .oooooooo", +"oo.XXXXooooooooo", +"ooooooooo.Xo .oo", +"ooooooooo X. ooo", +"oooooooooo...ooo", +"oooooooooo XXooo", +"oooooooooo .Xooo", +"oooooooooooooooo", +"oooooooooooooooo" +}; diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/about_htm.h b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/about_htm.h new file mode 100644 index 0000000..79a859d --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/about_htm.h @@ -0,0 +1,54 @@ +wxString htmlaboutpage = wxT( +"" +"" +"" +"" +"" +"" +"" +"" +"" +"" +"" +"" +"" +"" +"" +"" +"" +"" +"" +"
" +"

" +"
" +"" +OPJ_APPLICATION " " OPJ_APPLICATION_VERSION +"
" +"A JPEG 2000 image viewer
" +"" OPJ_APPLICATION_PLATFORM " version" +"
" +"
OpenJPEG
" +"

The OpenJPEG library is an open-source JPEG 2000 codec written in C language. " +"In addition to the basic codec, various other features are under development.


" +"* Build: ") +#include "build.h" +wxT(", " __DATE__ ", " __TIME__ "
") +wxT("* " wxVERSION_STRING "
") +wxT("* OpenJPEG " OPENJPEG_VERSION " (") +#ifdef USE_JPWL +wxT("JPWL ") +#endif // USE_JPWL +#ifdef USE_JPSEC +wxT("JPSEC ") +#endif // USE_JPSEC +wxT(")
") +#ifdef USE_MXF +wxT("* MXFLib " MXFLIB_VERSION_MAJOR "." MXFLIB_VERSION_MINOR "." MXFLIB_VERSION_TWEAK " (" MXFLIB_VERSION_BUILD ")
") +#endif // USE_MXF +wxT("
" +"OpenJPEG is © 2002-2008 TELE - Universite' Catholique de Louvain
" +"OPJViewer is © 2007-2008 DSPLab - Universita' degli studi di Perugia" +"
" +"" +"" +); diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/build.h b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/build.h new file mode 100644 index 0000000..f0f072c --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/build.h @@ -0,0 +1 @@ +wxT("491") diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/icon1.xpm b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/icon1.xpm new file mode 100644 index 0000000..fbc605b --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/icon1.xpm @@ -0,0 +1,79 @@ +/* XPM */ +static char *icon1_xpm[] = { +/* columns rows colors chars-per-pixel */ +"32 32 41 1", +"> c #97C4E7", +"# c #4381AA", +"d c #FFFFFF", +"< c #71B2DE", +"+ c #538BB1", +"& c #D1E5F5", +"q c #63B3DE", +"6 c #F1F4F7", +"* c #CAE1F3", +"y c #7AC4E5", +"= c #C3DDF1", +"X c #74A1BD", +"- c #BCD9EF", +"5 c #619BC4", +"3 c #E6EAF1", +"2 c #4B8EBF", +"o c #6B97B6", +". c #4B82A8", +" c None", +"w c #54A6D8", +"1 c #71A8D1", +", c #85BBE2", +"t c #EFF6FC", +"7 c #DEEDF8", +"@ c #4388B4", +"a c #F7FBFD", +"$ c #D7E0E9", +"r c #FAFCFE", +"4 c #DAEAF7", +"e c #E9F3FA", +"0 c #76BAE2", +"% c #7FA6C0", +"s c #FDFDFE", +"O c #5896BE", +"p c #B6D5EE", +"8 c #87ABC3", +": c #A5CCEA", +"9 c #E5F0F9", +"; c #AFD1EC", +"i c #F4F9FD", +"u c #8FB0C3", +/* pixels */ +" ", +" ", +" ", +" ", +" ", +" .XXXooOO++@#$ ", +" %&*=-;:>>,<123 ", +" %4&*=-;:>>,1>56 ", +" %74&*=-;:>>1*>56 ", +" 89700qqqqwq1e*>X ", +" 8e974&*=-;:1re*>8 ", +" 8te974&*=-;11111# ", +" 8tty000qqqqqww>,+ ", +" uitte974&*=-p:>>+ ", +" uaitte974&*=-p:>O ", +" uaayyyy000qqqqp:O ", +" uraaitte974&*=-po ", +" urraaitte974&*=-o ", +" usryyyyyyy000q*=X ", +" ussrraaitte974&*X ", +" udssrraaitte974&X ", +" uddyyyyyyyyyy074% ", +" udddssrraaitte97% ", +" uddddssrraaitte9% ", +" udddddssrraaitte8 ", +" uddddddssrraaitt8 ", +" uuuuuuuuuuuuuu88u ", +" ", +" ", +" ", +" ", +" " +}; diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/icon2.xpm b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/icon2.xpm new file mode 100644 index 0000000..7ae8c92 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/icon2.xpm @@ -0,0 +1,53 @@ +/* XPM */ +static char *icon2_xpm[] = { +/* columns rows colors chars-per-pixel */ +"32 32 15 1", +". c Black", +"O c #97C4E7", +"$ c #63B3DE", +"@ c #CAE1F3", +"; c #7AC4E5", +"* c #74A1BD", +"+ c #619BC4", +"o c #4B8EBF", +" c None", +"% c #54A6D8", +"= c #FAFCFE", +"& c #E9F3FA", +"# c #76BAE2", +"X c #C00000", +"- c #87ABC3", +/* pixels */ +" ", +" ", +" ", +" ", +" ", +" ............. ", +" .XXXXXXXXXX.o. ", +" .XXXXXXXXXX.O+. ", +" .XXXXXXXXXX.@O+. ", +" .XX##$$$$%$.&@O* ", +" .XXXXXXXXXX.=&@O- ", +" .XXXXXXXXXX...... ", +" .XX;###$$$$$%%XX. ", +" .XXXXXXXXXXXXXXX. ", +" .XXXXXXXXXXXXXXX. ", +" .XX;;;;###$$$$XX. ", +" .XXXXXXXXXXXXXXX. ", +" .XXXXXXXXXXXXXXX. ", +" .XX;;;;;;;###$XX. ", +" .XXXXXXXXXXXXXXX. ", +" .XXXXXXXXXXXXXXX. ", +" .XX;;;;;;;;;;#XX. ", +" .XXXXXXXXXXXXXXX. ", +" .XXXXXXXXXXXXXXX. ", +" .XXXXXXXXXXXXXXX. ", +" .XXXXXXXXXXXXXXX. ", +" ................. ", +" ", +" ", +" ", +" ", +" " +}; diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/icon3.xpm b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/icon3.xpm new file mode 100644 index 0000000..722de6b --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/icon3.xpm @@ -0,0 +1,79 @@ +/* XPM */ +static char *icon3_xpm[] = { +/* columns rows colors chars-per-pixel */ +"32 32 41 1", +"6 c #EDF2FB", +"- c #AAC1E8", +": c #B9CDED", +"X c #295193", +", c #C6D6F0", +"a c #4A7CCE", +"u c #779DDB", +"y c #7FA2DD", +"$ c #3263B4", +"5 c #EAF0FA", +". c #2D59A3", +"o c #6E96D8", +"* c #356AC1", +"r c #F7F9FD", +"> c #BED0EE", +"3 c #E1E9F7", +"7 c #F0F5FC", +"< c #CBD9F1", +"2 c #DAE5F6", +"# c #3161B1", +" c None", +"0 c #FDFEFF", +"= c #9FB9E5", +"e c #AEC5EA", +"t c #89A9DF", +"q c #98B5E4", +"p c #5584D1", +"d c #3A70CA", +"@ c #305FAC", +"i c #5D89D3", +"1 c #D2DFF4", +"% c #3366B9", +"9 c #FAFCFE", +"8 c #F5F8FD", +"s c #4075CC", +"O c #638ED5", +"w c #90AFE2", +"& c #3467BC", +"+ c #2F5DA9", +"; c #B3C8EB", +"4 c #E5EDF9", +/* pixels */ +" ", +" ", +" ", +" ", +" ", +" ", +" ......X ", +" .oooooO+ ", +" .ooooooo. ", +" .+@@@##$%%&&&&&****. ", +" .=-;:>,<12345678900. ", +" .q=-;:>,<1234567890. ", +" .wq=-e:>,<12345678r. ", +" .twq=-e:>,<12345678. ", +" .ytwq=-e:>,<1234567. ", +" .uytwq=-e:>,<123456. ", +" .ouytwq=-e:>,<12345. ", +" .Oouytwq=-e;>,<1234. ", +" .iOouytwq=-e;>,<123. ", +" .piOouytwq=-e;>,<12. ", +" .apiOouytwq=-e;>,<1. ", +" .sapiOouytwq=-e;>,<. ", +" .dsapiOouytwq=-e;>,. ", +" ...................# ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" " +}; diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/icon4.xpm b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/icon4.xpm new file mode 100644 index 0000000..a18e1a7 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/icon4.xpm @@ -0,0 +1,43 @@ +/* XPM */ +static char *icon4_xpm[] = { +/* columns rows colors chars-per-pixel */ +"32 32 5 1", +". c Black", +"o c #8399B4", +"X c #8DA0B9", +" c None", +"O c #800000", +/* pixels */ +" ", +" ", +" ", +" ", +" ", +" ", +" ....... ", +" .XXXXXo. ", +" .XXXXXXX. ", +" .................... ", +" .OOOOOOOOOOOOOOOOOO. ", +" .OOOOOOOOOOOOOOOOOO. ", +" .OOOOOOOOOOOOOOOOOO. ", +" .OOOOOOOOOOOOOOOOOO. ", +" .OOOOOOOOOOOOOOOOOO. ", +" .OOOOOOOOOOOOOOOOOO. ", +" .OOOOOOOOOOOOOOOOOO. ", +" .OOOOOOOOOOOOOOOOOO. ", +" .OOOOOOOOOOOOOOOOOO. ", +" .OOOOOOOOOOOOOOOOOO. ", +" .OOOOOOOOOOOOOOOOOO. ", +" .OOOOOOOOOOOOOOOOOO. ", +" .OOOOOOOOOOOOOOOOOO. ", +" .................... ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" " +}; diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/icon5.xpm b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/icon5.xpm new file mode 100644 index 0000000..9f63c31 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/icon5.xpm @@ -0,0 +1,79 @@ +/* XPM */ +static char *icon5_xpm[] = { +/* columns rows colors chars-per-pixel */ +"32 32 41 1", +"0 c #AAC1E8", +"q c #B9CDED", +"X c #295193", +"e c #C6D6F0", +"a c #4A7CCE", +"& c #779DDB", +"* c #7FA2DD", +"2 c #EAF0FA", +"@ c #2D59A3", +"o c #6E96D8", +"y c #356AC1", +"d c #214279", +"w c #BED0EE", +"= c #85A7DF", +"< c #E1E9F7", +"3 c #F0F5FC", +"s c #CBD9F1", +", c #DAE5F6", +"7 c #3161B1", +" c None", +". c #274D8B", +"6 c #FDFEFF", +"i c #E7EEF9", +"9 c #9FB9E5", +"- c #89A9DF", +"8 c #98B5E4", +"$ c #5584D1", +"+ c #3569BF", +"% c #305FAC", +"O c #5D89D3", +"> c #D2DFF4", +"p c #3366B9", +"5 c #FAFCFE", +"4 c #F5F8FD", +"t c #4075CC", +"u c #638ED5", +"r c #CEDCF2", +"; c #90AFE2", +"# c #2F5DA9", +": c #B3C8EB", +"1 c #E5EDF9", +/* pixels */ +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ......X ", +" XoooooO. ", +" Xoooooo+. ", +" Xooooooo@XXXXXXXXXX# ", +" Xoooooooooooooooooo# ", +" Xoooooooooooooooooo# ", +" Xoo$################### ", +" Xoo%O&*=-;:>,<123445667 ", +" XooX890:qwer>,<123445q# ", +" Xoty;890:qwer>,<12344# ", +" Xo%u-;890:qwer>,,,,<# ", +" XX$Ouo&*-;890:qwer>s# ", +" d%a$Ouo&*-;890:qwer# ", +" d+ta$Ouo&*-;890:qwe# ", +" d..................# ", +" ", +" ", +" ", +" ", +" ", +" ", +" " +}; diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/imagjpeg2000.cpp b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/imagjpeg2000.cpp new file mode 100644 index 0000000..ee2aa74 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/imagjpeg2000.cpp @@ -0,0 +1,1464 @@ +/* + * Copyright (c) 2007, Digital Signal Processing Laboratory, Università degli studi di Perugia (UPG), Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +///////////////////////////////////////////////////////////////////////////// +// Name: imagjpeg2000.cpp +// Purpose: wxImage JPEG 2000 family file format handler +// Author: Giuseppe Baruffa - based on imagjpeg.cpp, Vaclav Slavik +// RCS-ID: $Id: imagjpeg2000.cpp,v 0.00 2008/01/31 10:58:00 MW Exp $ +// Copyright: (c) Giuseppe Baruffa +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_IMAGE && wxUSE_LIBOPENJPEG + +#include "imagjpeg2000.h" + +#ifndef WX_PRECOMP + #include "wx/log.h" + #include "wx/app.h" + #include "wx/intl.h" + #include "wx/bitmap.h" + #include "wx/module.h" +#endif + +#include "libopenjpeg/openjpeg.h" + +#include "wx/filefn.h" +#include "wx/wfstream.h" + +// ---------------------------------------------------------------------------- +// types +// ---------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// wxJPEG2000Handler +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxJPEG2000Handler,wxImageHandler) + +#if wxUSE_STREAMS + +//------------- JPEG 2000 Data Source Manager + +#define J2K_CFMT 0 +#define JP2_CFMT 1 +#define JPT_CFMT 2 +#define MJ2_CFMT 3 +#define PXM_DFMT 0 +#define PGX_DFMT 1 +#define BMP_DFMT 2 +#define YUV_DFMT 3 + +#define MAX_MESSAGE_LEN 200 + +/* check file type */ +int +jpeg2000familytype(unsigned char *hdr, int hdr_len) +{ + // check length + if (hdr_len < 24) + return -1; + + // check format + if (hdr[0] == 0x00 && + hdr[1] == 0x00 && + hdr[2] == 0x00 && + hdr[3] == 0x0C && + hdr[4] == 0x6A && + hdr[5] == 0x50 && + hdr[6] == 0x20 && + hdr[7] == 0x20 && + hdr[20] == 0x6A && + hdr[21] == 0x70 && + hdr[22] == 0x32) + // JP2 file format + return JP2_CFMT; + else if (hdr[0] == 0x00 && + hdr[1] == 0x00 && + hdr[2] == 0x00 && + hdr[3] == 0x0C && + hdr[4] == 0x6A && + hdr[5] == 0x50 && + hdr[6] == 0x20 && + hdr[7] == 0x20 && + hdr[20] == 0x6D && + hdr[21] == 0x6A && + hdr[22] == 0x70 && + hdr[23] == 0x32) + // MJ2 file format + return MJ2_CFMT; + else if (hdr[0] == 0xFF && + hdr[1] == 0x4F) + // J2K file format + return J2K_CFMT; + else + // unknown format + return -1; + +} + +/* we have to use this to avoid GUI-noGUI threads crashing */ +void printevent(const char *msg) +{ +#ifndef __WXGTK__ + wxMutexGuiEnter(); +#endif /* __WXGTK__ */ + wxLogMessage(wxT("%s"), msg); +#ifndef __WXGTK__ + wxMutexGuiLeave(); +#endif /* __WXGTK__ */ +} + +/* sample error callback expecting a FILE* client object */ +void jpeg2000_error_callback(const char *msg, void *client_data) { + char mess[MAX_MESSAGE_LEN + 20]; + int message_len = strlen(msg); + + if (message_len > MAX_MESSAGE_LEN) + message_len = MAX_MESSAGE_LEN; + + if (msg[message_len - 1] == '\n') + message_len--; + + sprintf(mess, "[ERROR] %.*s", message_len, msg); + printevent(mess); +} + +/* sample warning callback expecting a FILE* client object */ +void jpeg2000_warning_callback(const char *msg, void *client_data) { + char mess[MAX_MESSAGE_LEN + 20]; + int message_len = strlen(msg); + + if (message_len > MAX_MESSAGE_LEN) + message_len = MAX_MESSAGE_LEN; + + if (msg[message_len - 1] == '\n') + message_len--; + + sprintf(mess, "[WARNING] %.*s", message_len, msg); + printevent(mess); +} + +/* sample debug callback expecting no client object */ +void jpeg2000_info_callback(const char *msg, void *client_data) { + char mess[MAX_MESSAGE_LEN + 20]; + int message_len = strlen(msg); + + if (message_len > MAX_MESSAGE_LEN) + message_len = MAX_MESSAGE_LEN; + + if (msg[message_len - 1] == '\n') + message_len--; + + sprintf(mess, "[INFO] %.*s", message_len, msg); + printevent(mess); +} + +/* macro functions */ +/* From little endian to big endian, 2 and 4 bytes */ +#define BYTE_SWAP2(X) ((X & 0x00FF) << 8) | ((X & 0xFF00) >> 8) +#define BYTE_SWAP4(X) ((X & 0x000000FF) << 24) | ((X & 0x0000FF00) << 8) | ((X & 0x00FF0000) >> 8) | ((X & 0xFF000000) >> 24) + +#ifdef __WXGTK__ +#define BYTE_SWAP8(X) ((X & 0x00000000000000FFULL) << 56) | ((X & 0x000000000000FF00ULL) << 40) | \ + ((X & 0x0000000000FF0000ULL) << 24) | ((X & 0x00000000FF000000ULL) << 8) | \ + ((X & 0x000000FF00000000ULL) >> 8) | ((X & 0x0000FF0000000000ULL) >> 24) | \ + ((X & 0x00FF000000000000ULL) >> 40) | ((X & 0xFF00000000000000ULL) >> 56) +#else +#define BYTE_SWAP8(X) ((X & 0x00000000000000FF) << 56) | ((X & 0x000000000000FF00) << 40) | \ + ((X & 0x0000000000FF0000) << 24) | ((X & 0x00000000FF000000) << 8) | \ + ((X & 0x000000FF00000000) >> 8) | ((X & 0x0000FF0000000000) >> 24) | \ + ((X & 0x00FF000000000000) >> 40) | ((X & 0xFF00000000000000) >> 56) +#endif + +/* From codestream to int values */ +#define STREAM_TO_UINT32(C, P) (((unsigned long int) (C)[(P) + 0] << 24) + \ + ((unsigned long int) (C)[(P) + 1] << 16) + \ + ((unsigned long int) (C)[(P) + 2] << 8) + \ + ((unsigned long int) (C)[(P) + 3] << 0)) + +#define STREAM_TO_UINT16(C, P) (((unsigned long int) (C)[(P) + 0] << 8) + \ + ((unsigned long int) (C)[(P) + 1] << 0)) + +/* defines */ +#define SHORT_DESCR_LEN 32 +#define LONG_DESCR_LEN 256 + +/* enumeration for file formats */ +#define JPEG2000FILENUM 4 +typedef enum { + + JP2_FILE, + J2K_FILE, + MJ2_FILE, + UNK_FILE + +} jpeg2000filetype; + +/* enumeration for the box types */ +#define JPEG2000BOXNUM 23 +typedef enum { + + FILE_BOX, + JP_BOX, + FTYP_BOX, + JP2H_BOX, + IHDR_BOX, + COLR_BOX, + JP2C_BOX, + JP2I_BOX, + XML_BOX, + UUID_BOX, + UINF_BOX, + MOOV_BOX, + MVHD_BOX, + TRAK_BOX, + TKHD_BOX, + MDIA_BOX, + MINF_BOX, + STBL_BOX, + STSD_BOX, + MJP2_BOX, + MDAT_BOX, + ANY_BOX, + UNK_BOX + +} jpeg2000boxtype; + +/* jpeg2000 family box signatures */ +#define FILE_SIGN "" +#define JP_SIGN "jP\040\040" +#define FTYP_SIGN "ftyp" +#define JP2H_SIGN "jp2h" +#define IHDR_SIGN "ihdr" +#define COLR_SIGN "colr" +#define JP2C_SIGN "jp2c" +#define JP2I_SIGN "jp2i" +#define XML_SIGN "xml\040" +#define UUID_SIGN "uuid" +#define UINF_SIGN "uinf" +#define MOOV_SIGN "moov" +#define MVHD_SIGN "mvhd" +#define TRAK_SIGN "trak" +#define TKHD_SIGN "tkhd" +#define MDIA_SIGN "mdia" +#define MINF_SIGN "minf" +#define VMHD_SIGN "vmhd" +#define STBL_SIGN "stbl" +#define STSD_SIGN "stsd" +#define MJP2_SIGN "mjp2" +#define MDAT_SIGN "mdat" +#define ANY_SIGN "" +#define UNK_SIGN "" + +/* the box structure itself */ +struct jpeg2000boxdef { + + char value[5]; /* hexadecimal value/string*/ + char name[SHORT_DESCR_LEN]; /* short description */ + char descr[LONG_DESCR_LEN]; /* long description */ + int sbox; /* is it a superbox? */ + int req[JPEG2000FILENUM]; /* mandatory box */ + jpeg2000boxtype ins; /* contained in box... */ + +}; + +/* the possible boxes */ +struct jpeg2000boxdef jpeg2000box[] = +{ +/* sign */ {FILE_SIGN, +/* short */ "placeholder for nothing", +/* long */ "Nothing to say", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ FILE_BOX}, + +/* sign */ {JP_SIGN, +/* short */ "JPEG 2000 Signature box", +/* long */ "This box uniquely identifies the file as being part of the JPEG 2000 family of files", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ FILE_BOX}, + +/* sign */ {FTYP_SIGN, +/* short */ "File Type box", +/* long */ "This box specifies file type, version and compatibility information, including specifying if this file " + "is a conforming JP2 file or if it can be read by a conforming JP2 reader", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ FILE_BOX}, + +/* sign */ {JP2H_SIGN, +/* short */ "JP2 Header box", +/* long */ "This box contains a series of boxes that contain header-type information about the file", +/* sbox */ 1, +/* req */ {1, 1, 1}, +/* ins */ FILE_BOX}, + +/* sign */ {IHDR_SIGN, +/* short */ "Image Header box", +/* long */ "This box specifies the size of the image and other related fields", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ JP2H_BOX}, + +/* sign */ {COLR_SIGN, +/* short */ "Colour Specification box", +/* long */ "This box specifies the colourspace of the image", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ JP2H_BOX}, + +/* sign */ {JP2C_SIGN, +/* short */ "Contiguous Codestream box", +/* long */ "This box contains the codestream as defined by Annex A", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ FILE_BOX}, + +/* sign */ {JP2I_SIGN, +/* short */ "Intellectual Property box", +/* long */ "This box contains intellectual property information about the image", +/* sbox */ 0, +/* req */ {0, 0, 0}, +/* ins */ FILE_BOX}, + +/* sign */ {XML_SIGN, +/* short */ "XML box", +/* long */ "This box provides a tool by which vendors can add XML formatted information to a JP2 file", +/* sbox */ 0, +/* req */ {0, 0, 0}, +/* ins */ FILE_BOX}, + +/* sign */ {UUID_SIGN, +/* short */ "UUID box", +/* long */ "This box provides a tool by which vendors can add additional information to a file " + "without risking conflict with other vendors", +/* sbox */ 0, +/* req */ {0, 0, 0}, +/* ins */ FILE_BOX}, + +/* sign */ {UINF_SIGN, +/* short */ "UUID Info box", +/* long */ "This box provides a tool by which a vendor may provide access to additional information associated with a UUID", +/* sbox */ 0, +/* req */ {0, 0, 0}, +/* ins */ FILE_BOX}, + +/* sign */ {MOOV_SIGN, +/* short */ "Movie box", +/* long */ "This box contains the media data. In video tracks, this box would contain JPEG2000 video frames", +/* sbox */ 1, +/* req */ {1, 1, 1}, +/* ins */ FILE_BOX}, + +/* sign */ {MVHD_SIGN, +/* short */ "Movie Header box", +/* long */ "This box defines overall information which is media-independent, and relevant to the entire presentation " + "considered as a whole", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ MOOV_BOX}, + +/* sign */ {TRAK_SIGN, +/* short */ "Track box", +/* long */ "This is a container box for a single track of a presentation. A presentation may consist of one or more tracks", +/* sbox */ 1, +/* req */ {1, 1, 1}, +/* ins */ MOOV_BOX}, + +/* sign */ {TKHD_SIGN, +/* short */ "Track Header box", +/* long */ "This box specifies the characteristics of a single track. Exactly one Track Header Box is contained in a track", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ TRAK_BOX}, + +/* sign */ {MDIA_SIGN, +/* short */ "Media box", +/* long */ "The media declaration container contains all the objects which declare information about the media data " + "within a track", +/* sbox */ 1, +/* req */ {1, 1, 1}, +/* ins */ TRAK_BOX}, + +/* sign */ {MINF_SIGN, +/* short */ "Media Information box", +/* long */ "This box contains all the objects which declare characteristic information of the media in the track", +/* sbox */ 1, +/* req */ {1, 1, 1}, +/* ins */ MDIA_BOX}, + +/* sign */ {STBL_SIGN, +/* short */ "Sample Table box", +/* long */ "The sample table contains all the time and data indexing of the media samples in a track", +/* sbox */ 1, +/* req */ {1, 1, 1}, +/* ins */ MINF_BOX}, + +/* sign */ {STSD_SIGN, +/* short */ "Sample Description box", +/* long */ "The sample description table gives detailed information about the coding type used, and any initialization " + "information needed for that coding", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ MINF_BOX}, + +/* sign */ {MJP2_SIGN, +/* short */ "MJP2 Sample Description box", +/* long */ "The MJP2 sample description table gives detailed information about the coding type used, and any initialization " + "information needed for that coding", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ MINF_BOX}, + +/* sign */ {MDAT_SIGN, +/* short */ "Media Data box", +/* long */ "The meta-data for a presentation is stored in the single Movie Box which occurs at the top-level of a file", +/* sbox */ 1, +/* req */ {1, 1, 1}, +/* ins */ FILE_BOX}, + +/* sign */ {ANY_SIGN, +/* short */ "Any box", +/* long */ "All the existing boxes", +/* sbox */ 0, +/* req */ {0, 0, 0}, +/* ins */ FILE_BOX}, + +/* sign */ {UNK_SIGN, +/* short */ "Unknown Type box", +/* long */ "The signature is not recognised to be that of an existing box", +/* sbox */ 0, +/* req */ {0, 0, 0}, +/* ins */ ANY_BOX} + +}; + +/* declaration */ +int +jpeg2000_box_handler_function(jpeg2000boxtype boxtype, wxInputStream& stream, unsigned long int filepoint, + unsigned long int filelimit, int level, char *scansign, + unsigned long int *scanpoint); + +#ifdef __WXMSW__ +typedef unsigned __int64 int8byte; +#endif // __WXMSW__ + +#ifdef __WXGTK__ +typedef unsigned long long int8byte; +#endif // __WXGTK__ + +/* internal mini-search for a box signature */ +int +jpeg2000_file_parse(wxInputStream& stream, unsigned long int filepoint, unsigned long int filelimit, int level, + char *scansign, unsigned long int *scanpoint) +{ + unsigned long int LBox = 0x00000000; + char TBox[5] = "\0\0\0\0"; + int8byte XLBox = 0x0000000000000000; + unsigned long int box_length = 0; + int last_box = 0, box_num = 0; + int box_type = ANY_BOX; + unsigned char fourbytes[4]; + int box_number = 0; + + /* cycle all over the file */ + box_num = 0; + last_box = 0; + while (!last_box) { + + /* do not exceed file limit */ + if (filepoint >= filelimit) + return (0); + + /* seek on file */ + if (stream.SeekI(filepoint, wxFromStart) == wxInvalidOffset) + return (-1); + + /* read the mandatory LBox, 4 bytes */ + if (!stream.Read(fourbytes, 4)) { + wxLogError(wxT("Problem reading LBox from the file (file ended?)")); + return -1; + }; + LBox = STREAM_TO_UINT32(fourbytes, 0); + + /* read the mandatory TBox, 4 bytes */ + if (!stream.Read(TBox, 4)) { + wxLogError(wxT("Problem reading TBox from the file (file ended?)")); + return -1; + }; + + /* look if scansign is got */ + if ((scansign != NULL) && (memcmp(TBox, scansign, 4) == 0)) { + /* hack/exploit */ + // stop as soon as you find the level-th codebox + if (box_number == level) { + memcpy(scansign, " ", 4); + *scanpoint = filepoint; + return (0); + } else + box_number++; + + }; + + /* determine the box type */ + for (box_type = JP_BOX; box_type < UNK_BOX; box_type++) + if (memcmp(TBox, jpeg2000box[box_type].value, 4) == 0) + break; + + /* read the optional XLBox, 8 bytes */ + if (LBox == 1) { + + if (!stream.Read(&XLBox, 8)) { + wxLogError(wxT("Problem reading XLBox from the file (file ended?)")); + return -1; + }; + box_length = (unsigned long int) BYTE_SWAP8(XLBox); + + } else if (LBox == 0x00000000) { + + /* last box in file */ + last_box = 1; + box_length = filelimit - filepoint; + + } else + + box_length = LBox; + + + /* go deep in the box */ + jpeg2000_box_handler_function((jpeg2000boxtype) box_type, + stream, (LBox == 1) ? (filepoint + 16) : (filepoint + 8), + filepoint + box_length, level, scansign, scanpoint); + + /* if it's a superbox go inside it */ + if (jpeg2000box[box_type].sbox) + jpeg2000_file_parse(stream, (LBox == 1) ? (filepoint + 16) : (filepoint + 8), filepoint + box_length, + level, scansign, scanpoint); + + /* increment box number and filepoint*/ + box_num++; + filepoint += box_length; + + }; + + /* all good */ + return (0); +} + +// search first contiguos codestream box in an mj2 file +unsigned long int +searchjpeg2000c(wxInputStream& stream, unsigned long int fsize, int number) +{ + char scansign[] = "jp2c"; + unsigned long int scanpoint = 0L; + + wxLogMessage(wxT("Searching jp2c box... ")); + + /* do the parsing */ + if (jpeg2000_file_parse(stream, 0, fsize, number, scansign, &scanpoint) < 0) + wxLogMessage(wxT("Unrecoverable error during JPEG 2000 box parsing: stopping")); + + if (strcmp(scansign, " ")) + wxLogMessage(wxT("Box not found")); + else { + + wxLogMessage(wxString::Format(wxT("Box found at byte %d"), scanpoint)); + + }; + + return (scanpoint); +} + +// search the jp2h box in the file +unsigned long int +searchjpeg2000headerbox(wxInputStream& stream, unsigned long int fsize) +{ + char scansign[] = "jp2h"; + unsigned long int scanpoint = 0L; + + wxLogMessage(wxT("Searching jp2h box... ")); + + /* do the parsing */ + if (jpeg2000_file_parse(stream, 0, fsize, 0, scansign, &scanpoint) < 0) + wxLogMessage(wxT("Unrecoverable error during JPEG 2000 box parsing: stopping")); + + if (strcmp(scansign, " ")) + wxLogMessage(wxT("Box not found")); + else + wxLogMessage(wxString::Format(wxT("Box found at byte %d"), scanpoint)); + + return (scanpoint); +} + +/* handling functions */ +#define ITEM_PER_ROW 10 + +/* Box handler function */ +int +jpeg2000_box_handler_function(jpeg2000boxtype boxtype, wxInputStream& stream, unsigned long int filepoint, + unsigned long int filelimit, int level, + char *scansign, unsigned long int *scanpoint) +{ + switch (boxtype) { + + /* Sample Description box */ + case (STSD_BOX): + jpeg2000_file_parse(stream, filepoint + 8, filelimit, level, scansign, scanpoint); + break; + + /* MJP2 Sample Description box */ + case (MJP2_BOX): + jpeg2000_file_parse(stream, filepoint + 78, filelimit, level, scansign, scanpoint); + break; + + /* not yet implemented */ + default: + break; + + }; + + return (0); +} + +// the jP and ftyp parts of the header +#define jpeg2000headSIZE 32 +unsigned char jpeg2000head[jpeg2000headSIZE] = { + 0x00, 0x00, 0x00, 0x0C, 'j', 'P', ' ', ' ', + 0x0D, 0x0A, 0x87, 0x0A, 0x00, 0x00, 0x00, 0x14, + 'f', 't', 'y', 'p', 'j', 'p', '2', ' ', + 0x00, 0x00, 0x00, 0x00, 'j', 'p', '2', ' ' +}; + +///////////////////////////////////////////////// +///////////////////////////////////////////////// + +// load the jpeg2000 file format +bool wxJPEG2000Handler::LoadFile(wxImage *image, wxInputStream& stream, bool verbose, int index) +{ + opj_dparameters_t parameters; /* decompression parameters */ + opj_event_mgr_t event_mgr; /* event manager */ + opj_image_t *opjimage = NULL; + unsigned char *src = NULL; + unsigned char *ptr; + int file_length, jp2c_point, jp2h_point; + unsigned long int jp2hboxlen, jp2cboxlen; + opj_codestream_info_t cstr_info; /* Codestream information structure */ + unsigned char hdr[24]; + int jpfamform; + + // destroy the image + image->Destroy(); + + /* read the beginning of the file to check the type */ + if (!stream.Read(hdr, WXSIZEOF(hdr))) + return false; + if ((jpfamform = jpeg2000familytype(hdr, WXSIZEOF(hdr))) < 0) + return false; + stream.SeekI(0, wxFromStart); + + /* handle to a decompressor */ + opj_dinfo_t* dinfo = NULL; + opj_cio_t *cio = NULL; + + /* configure the event callbacks */ + memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); + event_mgr.error_handler = jpeg2000_error_callback; + event_mgr.warning_handler = jpeg2000_warning_callback; + event_mgr.info_handler = jpeg2000_info_callback; + + /* set decoding parameters to default values */ + opj_set_default_decoder_parameters(¶meters); + + /* prepare parameters */ + strncpy(parameters.infile, "", sizeof(parameters.infile) - 1); + strncpy(parameters.outfile, "", sizeof(parameters.outfile) - 1); + parameters.decod_format = jpfamform; + parameters.cod_format = BMP_DFMT; + if (m_reducefactor) + parameters.cp_reduce = m_reducefactor; + if (m_qualitylayers) + parameters.cp_layer = m_qualitylayers; + /*if (n_components) + parameters. = n_components;*/ + + /* JPWL only */ +#ifdef USE_JPWL + parameters.jpwl_exp_comps = m_expcomps; + parameters.jpwl_max_tiles = m_maxtiles; + parameters.jpwl_correct = m_enablejpwl; +#endif /* USE_JPWL */ + + /* get a decoder handle */ + if (jpfamform == JP2_CFMT || jpfamform == MJ2_CFMT) + dinfo = opj_create_decompress(CODEC_JP2); + else if (jpfamform == J2K_CFMT) + dinfo = opj_create_decompress(CODEC_J2K); + else + return false; + + /* find length of the stream */ + stream.SeekI(0, wxFromEnd); + file_length = (int) stream.TellI(); + + /* it's a movie */ + if (jpfamform == MJ2_CFMT) { + /* search for the first codestream box and the movie header box */ + jp2c_point = searchjpeg2000c(stream, file_length, m_framenum); + jp2h_point = searchjpeg2000headerbox(stream, file_length); + + // read the jp2h box and store it + stream.SeekI(jp2h_point, wxFromStart); + stream.Read(&jp2hboxlen, sizeof(unsigned long int)); + jp2hboxlen = BYTE_SWAP4(jp2hboxlen); + + // read the jp2c box and store it + stream.SeekI(jp2c_point, wxFromStart); + stream.Read(&jp2cboxlen, sizeof(unsigned long int)); + jp2cboxlen = BYTE_SWAP4(jp2cboxlen); + + // malloc memory source + src = (unsigned char *) malloc(jpeg2000headSIZE + jp2hboxlen + jp2cboxlen); + + // copy the jP and ftyp + memcpy(src, jpeg2000head, jpeg2000headSIZE); + + // copy the jp2h + stream.SeekI(jp2h_point, wxFromStart); + stream.Read(&src[jpeg2000headSIZE], jp2hboxlen); + + // copy the jp2c + stream.SeekI(jp2c_point, wxFromStart); + stream.Read(&src[jpeg2000headSIZE + jp2hboxlen], jp2cboxlen); + } else if (jpfamform == JP2_CFMT || jpfamform == J2K_CFMT) { + /* It's a plain image */ + /* get data */ + stream.SeekI(0, wxFromStart); + src = (unsigned char *) malloc(file_length); + stream.Read(src, file_length); + } else + return false; + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr); + + /* setup the decoder decoding parameters using user parameters */ + opj_setup_decoder(dinfo, ¶meters); + + /* open a byte stream */ + if (jpfamform == MJ2_CFMT) + cio = opj_cio_open((opj_common_ptr)dinfo, src, jpeg2000headSIZE + jp2hboxlen + jp2cboxlen); + else if (jpfamform == JP2_CFMT || jpfamform == J2K_CFMT) + cio = opj_cio_open((opj_common_ptr)dinfo, src, file_length); + else { + free(src); + return false; + } + + /* decode the stream and fill the image structure */ + opjimage = opj_decode_with_info(dinfo, cio, &cstr_info); + if (!opjimage) { + wxMutexGuiEnter(); + wxLogError(wxT("JPEG 2000 failed to decode image!")); + wxMutexGuiLeave(); + opj_destroy_decompress(dinfo); + opj_cio_close(cio); + free(src); + return false; + } + + /* close the byte stream */ + opj_cio_close(cio); + + /* + + - At this point, we have the structure "opjimage" that is filled with decompressed + data, as processed by the OpenJPEG decompression engine + + - We need to fill the class "image" with the proper pixel sample values + + */ + { + int shiftbpp; + int c, tempcomps; + + // check components number + if (m_components > opjimage->numcomps) + m_components = opjimage->numcomps; + + // check image depth (only on the first one, for now) + if (m_components) + shiftbpp = opjimage->comps[m_components - 1].prec - 8; + else + shiftbpp = opjimage->comps[0].prec - 8; + + // prepare image size + if (m_components) + image->Create(opjimage->comps[m_components - 1].w, opjimage->comps[m_components - 1].h, true); + else + image->Create(opjimage->comps[0].w, opjimage->comps[0].h, true); + + // access image raw data + image->SetMask(false); + ptr = image->GetData(); + + // workaround for components different from 1 or 3 + if ((opjimage->numcomps != 1) && (opjimage->numcomps != 3)) { +#ifndef __WXGTK__ + wxMutexGuiEnter(); +#endif /* __WXGTK__ */ + wxLogMessage(wxT("JPEG2000: weird number of components")); +#ifndef __WXGTK__ + wxMutexGuiLeave(); +#endif /* __WXGTK__ */ + tempcomps = 1; + } else + tempcomps = opjimage->numcomps; + + // workaround for subsampled components + for (c = 1; c < tempcomps; c++) { + if ((opjimage->comps[c].w != opjimage->comps[c - 1].w) || (opjimage->comps[c].h != opjimage->comps[c - 1].h)) { + tempcomps = 1; + break; + } + } + + // workaround for different precision components + for (c = 1; c < tempcomps; c++) { + if (opjimage->comps[c].bpp != opjimage->comps[c - 1].bpp) { + tempcomps = 1; + break; + } + } + + // only one component selected + if (m_components) + tempcomps = 1; + + // RGB color picture + if (tempcomps == 3) { + int row, col; + int *r = opjimage->comps[0].data; + int *g = opjimage->comps[1].data; + int *b = opjimage->comps[2].data; + if (shiftbpp > 0) { + for (row = 0; row < opjimage->comps[0].h; row++) { + for (col = 0; col < opjimage->comps[0].w; col++) { + + *(ptr++) = (*(r++)) >> shiftbpp; + *(ptr++) = (*(g++)) >> shiftbpp; + *(ptr++) = (*(b++)) >> shiftbpp; + + } + } + + } else if (shiftbpp < 0) { + for (row = 0; row < opjimage->comps[0].h; row++) { + for (col = 0; col < opjimage->comps[0].w; col++) { + + *(ptr++) = (*(r++)) << -shiftbpp; + *(ptr++) = (*(g++)) << -shiftbpp; + *(ptr++) = (*(b++)) << -shiftbpp; + + } + } + + } else { + for (row = 0; row < opjimage->comps[0].h; row++) { + for (col = 0; col < opjimage->comps[0].w; col++) { + + *(ptr++) = *(r++); + *(ptr++) = *(g++); + *(ptr++) = *(b++); + + } + } + } + } + + // B/W picture + if (tempcomps == 1) { + int row, col; + int selcomp; + + if (m_components) + selcomp = m_components - 1; + else + selcomp = 0; + + int *y = opjimage->comps[selcomp].data; + if (shiftbpp > 0) { + for (row = 0; row < opjimage->comps[selcomp].h; row++) { + for (col = 0; col < opjimage->comps[selcomp].w; col++) { + + *(ptr++) = (*(y)) >> shiftbpp; + *(ptr++) = (*(y)) >> shiftbpp; + *(ptr++) = (*(y++)) >> shiftbpp; + + } + } + } else if (shiftbpp < 0) { + for (row = 0; row < opjimage->comps[selcomp].h; row++) { + for (col = 0; col < opjimage->comps[selcomp].w; col++) { + + *(ptr++) = (*(y)) << -shiftbpp; + *(ptr++) = (*(y)) << -shiftbpp; + *(ptr++) = (*(y++)) << -shiftbpp; + + } + } + } else { + for (row = 0; row < opjimage->comps[selcomp].h; row++) { + for (col = 0; col < opjimage->comps[selcomp].w; col++) { + + *(ptr++) = *(y); + *(ptr++) = *(y); + *(ptr++) = *(y++); + + } + } + } + } + + + } + + wxMutexGuiEnter(); + wxLogMessage(wxT("JPEG 2000 image loaded.")); + wxMutexGuiLeave(); + + /* close openjpeg structs */ + opj_destroy_decompress(dinfo); + opj_image_destroy(opjimage); + free(src); + + if (!image->Ok()) + return false; + else + return true; + +} + +#define CINEMA_24_CS 1302083 /* Codestream length for 24fps */ +#define CINEMA_48_CS 651041 /* Codestream length for 48fps */ +#define COMP_24_CS 1041666 /* Maximum size per color component for 2K & 4K @ 24fps */ +#define COMP_48_CS 520833 /* Maximum size per color component for 2K @ 48fps */ + +// save the j2k codestream +bool wxJPEG2000Handler::SaveFile( wxImage *wimage, wxOutputStream& stream, bool verbose ) +{ + opj_cparameters_t parameters; /* compression parameters */ + opj_event_mgr_t event_mgr; /* event manager */ + opj_image_t *oimage = NULL; + opj_image_cmptparm_t *cmptparm; + opj_cio_t *cio = NULL; + opj_codestream_info_t cstr_info; + int codestream_length; + bool bSuccess; + int i; + char indexfilename[OPJ_PATH_LEN] = ""; /* index file name */ + + /* + configure the event callbacks (not required) + setting of each callback is optionnal + */ + memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); + event_mgr.error_handler = jpeg2000_error_callback; + event_mgr.warning_handler = jpeg2000_warning_callback; + event_mgr.info_handler = jpeg2000_info_callback; + + /* set encoding parameters to default values */ + opj_set_default_encoder_parameters(¶meters); + + /* load parameters */ + parameters.cp_cinema = OFF; + + /* subsampling */ + if (sscanf(m_subsampling.ToAscii(), "%d,%d", &(parameters.subsampling_dx), &(parameters.subsampling_dy)) != 2) { + wxLogError(wxT("Wrong sub-sampling encoder setting: dx,dy")); + return false; + } + + /* compression rates */ + if ((m_rates != wxT("")) && (!m_enablequality)) { + const char *s1 = m_rates.ToAscii(); + wxLogMessage(wxT("rates %s"), s1); + while (sscanf(s1, "%f", &(parameters.tcp_rates[parameters.tcp_numlayers])) == 1) { + parameters.tcp_numlayers++; + while (*s1 && *s1 != ',') { + s1++; + } + if (!*s1) + break; + s1++; + } + wxLogMessage(wxT("%d layers"), parameters.tcp_numlayers); + parameters.cp_disto_alloc = 1; + } + + /* image quality, dB */ + if ((m_quality != wxT("")) && (m_enablequality)) { + const char *s2 = m_quality.ToAscii(); + wxLogMessage(wxT("qualities %s"), s2); + while (sscanf(s2, "%f", ¶meters.tcp_distoratio[parameters.tcp_numlayers]) == 1) { + parameters.tcp_numlayers++; + while (*s2 && *s2 != ',') { + s2++; + } + if (!*s2) + break; + s2++; + } + wxLogMessage(wxT("%d layers"), parameters.tcp_numlayers); + parameters.cp_fixed_quality = 1; + } + + /* image origin */ + if (sscanf(m_origin.ToAscii(), "%d,%d", ¶meters.image_offset_x0, ¶meters.image_offset_y0) != 2) { + wxLogError(wxT("bad coordinate of the image origin: x0,y0")); + return false; + } + + /* Create comment for codestream */ + if(m_enablecomm) { + parameters.cp_comment = (char *) malloc(strlen(m_comment.ToAscii()) + 1); + if(parameters.cp_comment) { + strcpy(parameters.cp_comment, m_comment.ToAscii()); + } + } else { + parameters.cp_comment = NULL; + } + + /* indexing file */ + if (m_enableidx) { + strncpy(indexfilename, m_index.ToAscii(), OPJ_PATH_LEN); + wxLogMessage(wxT("index file is %s"), indexfilename); + } + + /* if no rate entered, lossless by default */ + if (parameters.tcp_numlayers == 0) { + parameters.tcp_rates[0] = 0; /* MOD antonin : losslessbug */ + parameters.tcp_numlayers++; + parameters.cp_disto_alloc = 1; + } + + /* irreversible transform */ + parameters.irreversible = (m_irreversible == true) ? 1 : 0; + + /* resolutions */ + parameters.numresolution = m_resolutions; + + /* codeblocks size */ + if (m_cbsize != wxT("")) { + int cblockw_init = 0, cblockh_init = 0; + sscanf(m_cbsize.ToAscii(), "%d,%d", &cblockw_init, &cblockh_init); + if (cblockw_init * cblockh_init > 4096 || cblockw_init > 1024 || cblockw_init < 4 || cblockh_init > 1024 || cblockh_init < 4) { + wxLogError(wxT("!! Size of code_block error !! Restrictions:\n width*height<=4096\n 4<=width,height<= 1024")); + return false; + } + parameters.cblockw_init = cblockw_init; + parameters.cblockh_init = cblockh_init; + } + + /* precincts size */ + if (m_prsize != wxT("")) { + char sep; + int res_spec = 0; + char *s = (char *) m_prsize.c_str(); + do { + sep = 0; + sscanf(s, "[%d,%d]%c", ¶meters.prcw_init[res_spec], ¶meters.prch_init[res_spec], &sep); + parameters.csty |= 0x01; + res_spec++; + s = strpbrk(s, "]") + 2; + } while (sep == ','); + parameters.res_spec = res_spec; + } + + /* tiles */ + if (m_tsize != wxT("")) { + sscanf(m_tsize.ToAscii(), "%d,%d", ¶meters.cp_tdx, ¶meters.cp_tdy); + parameters.tile_size_on = true; + } + + /* tile origin */ + if (sscanf(m_torigin.ToAscii(), "%d,%d", ¶meters.cp_tx0, ¶meters.cp_ty0) != 2) { + wxLogError(wxT("tile offset setting error: X0,Y0")); + return false; + } + + /* use SOP */ + if (m_enablesop) + parameters.csty |= 0x02; + + /* use EPH */ + if (m_enableeph) + parameters.csty |= 0x04; + + /* multiple component transform */ + if (m_multicomp) + parameters.tcp_mct = 1; + else + parameters.tcp_mct = 0; + + /* mode switch */ + parameters.mode = (m_enablebypass ? 1 : 0) + (m_enablereset ? 2 : 0) + + (m_enablerestart ? 4 : 0) + (m_enablevsc ? 8 : 0) + + (m_enableerterm ? 16 : 0) + (m_enablesegmark ? 32 : 0); + + /* progression order */ + switch (m_progression) { + + /* LRCP */ + case 0: + parameters.prog_order = LRCP; + break; + + /* RLCP */ + case 1: + parameters.prog_order = RLCP; + break; + + /* RPCL */ + case 2: + parameters.prog_order = RPCL; + break; + + /* PCRL */ + case 3: + parameters.prog_order = PCRL; + break; + + /* CPRL */ + case 4: + parameters.prog_order = CPRL; + break; + + /* DCI2K24 */ + case 5: + parameters.cp_cinema = CINEMA2K_24; + parameters.cp_rsiz = CINEMA2K; + break; + + /* DCI2K48 */ + case 6: + parameters.cp_cinema = CINEMA2K_48; + parameters.cp_rsiz = CINEMA2K; + break; + + /* DCI4K */ + case 7: + parameters.cp_cinema = CINEMA4K_24; + parameters.cp_rsiz = CINEMA4K; + break; + + default: + break; + } + + /* check cinema */ + if (parameters.cp_cinema) { + + /* set up */ + parameters.tile_size_on = false; + parameters.cp_tdx=1; + parameters.cp_tdy=1; + + /*Tile part*/ + parameters.tp_flag = 'C'; + parameters.tp_on = 1; + + /*Tile and Image shall be at (0,0)*/ + parameters.cp_tx0 = 0; + parameters.cp_ty0 = 0; + parameters.image_offset_x0 = 0; + parameters.image_offset_y0 = 0; + + /*Codeblock size= 32*32*/ + parameters.cblockw_init = 32; + parameters.cblockh_init = 32; + parameters.csty |= 0x01; + + /*The progression order shall be CPRL*/ + parameters.prog_order = CPRL; + + /* No ROI */ + parameters.roi_compno = -1; + + parameters.subsampling_dx = 1; + parameters.subsampling_dy = 1; + + /* 9-7 transform */ + parameters.irreversible = 1; + + } + + /* convert wx image into opj image */ + cmptparm = (opj_image_cmptparm_t*) malloc(3 * sizeof(opj_image_cmptparm_t)); + + /* initialize opj image components */ + memset(&cmptparm[0], 0, 3 * sizeof(opj_image_cmptparm_t)); + for(i = 0; i < 3; i++) { + cmptparm[i].prec = 8; + cmptparm[i].bpp = 8; + cmptparm[i].sgnd = false; + cmptparm[i].dx = parameters.subsampling_dx; + cmptparm[i].dy = parameters.subsampling_dy; + cmptparm[i].w = wimage->GetWidth(); + cmptparm[i].h = wimage->GetHeight(); + } + + /* create the image */ + oimage = opj_image_create(3, &cmptparm[0], CLRSPC_SRGB); + if(!oimage) { + if (cmptparm) + free(cmptparm); + return false; + } + + /* set image offset and reference grid */ + oimage->x0 = parameters.image_offset_x0; + oimage->y0 = parameters.image_offset_y0; + oimage->x1 = parameters.image_offset_x0 + (wimage->GetWidth() - 1) * 1 + 1; + oimage->y1 = parameters.image_offset_y0 + (wimage->GetHeight() - 1) * 1 + 1; + + /* load image data */ + unsigned char *value = wimage->GetData(); + int area = wimage->GetWidth() * wimage->GetHeight(); + for (i = 0; i < area; i++) { + oimage->comps[0].data[i] = *(value++); + oimage->comps[1].data[i] = *(value++); + oimage->comps[2].data[i] = *(value++); + } + + /* check cinema again */ + if (parameters.cp_cinema) { + int i; + float temp_rate; + opj_poc_t *POC = NULL; + + switch (parameters.cp_cinema) { + + case CINEMA2K_24: + case CINEMA2K_48: + if (parameters.numresolution > 6) { + parameters.numresolution = 6; + } + if (!((oimage->comps[0].w == 2048) | (oimage->comps[0].h == 1080))) { + wxLogWarning(wxT("Image coordinates %d x %d is not 2K compliant. JPEG Digital Cinema Profile-3 " + "(2K profile) compliance requires that at least one of coordinates match 2048 x 1080"), + oimage->comps[0].w, oimage->comps[0].h); + parameters.cp_rsiz = STD_RSIZ; + } + break; + + case CINEMA4K_24: + if (parameters.numresolution < 1) { + parameters.numresolution = 1; + } else if (parameters.numresolution > 7) { + parameters.numresolution = 7; + } + if (!((oimage->comps[0].w == 4096) | (oimage->comps[0].h == 2160))) { + wxLogWarning(wxT("Image coordinates %d x %d is not 4K compliant. JPEG Digital Cinema Profile-4" + "(4K profile) compliance requires that at least one of coordinates match 4096 x 2160"), + oimage->comps[0].w, oimage->comps[0].h); + parameters.cp_rsiz = STD_RSIZ; + } + parameters.POC[0].tile = 1; + parameters.POC[0].resno0 = 0; + parameters.POC[0].compno0 = 0; + parameters.POC[0].layno1 = 1; + parameters.POC[0].resno1 = parameters.numresolution - 1; + parameters.POC[0].compno1 = 3; + parameters.POC[0].prg1 = CPRL; + parameters.POC[1].tile = 1; + parameters.POC[1].resno0 = parameters.numresolution - 1; + parameters.POC[1].compno0 = 0; + parameters.POC[1].layno1 = 1; + parameters.POC[1].resno1 = parameters.numresolution; + parameters.POC[1].compno1 = 3; + parameters.POC[1].prg1 = CPRL; + parameters.numpocs = 2; + break; + } + + switch (parameters.cp_cinema) { + case CINEMA2K_24: + case CINEMA4K_24: + for (i = 0 ; i < parameters.tcp_numlayers; i++) { + temp_rate = 0; + if (parameters.tcp_rates[i] == 0) { + parameters.tcp_rates[0] = ((float) (oimage->numcomps * oimage->comps[0].w * oimage->comps[0].h * oimage->comps[0].prec)) / + (CINEMA_24_CS * 8 * oimage->comps[0].dx * oimage->comps[0].dy); + }else{ + temp_rate = ((float) (oimage->numcomps * oimage->comps[0].w * oimage->comps[0].h * oimage->comps[0].prec)) / + (parameters.tcp_rates[i] * 8 * oimage->comps[0].dx * oimage->comps[0].dy); + if (temp_rate > CINEMA_24_CS ) { + parameters.tcp_rates[i]= ((float) (oimage->numcomps * oimage->comps[0].w * oimage->comps[0].h * oimage->comps[0].prec)) / + (CINEMA_24_CS * 8 * oimage->comps[0].dx * oimage->comps[0].dy); + } else { + /* do nothing */ + } + } + } + parameters.max_comp_size = COMP_24_CS; + break; + + case CINEMA2K_48: + for (i = 0; i < parameters.tcp_numlayers; i++) { + temp_rate = 0 ; + if (parameters.tcp_rates[i] == 0) { + parameters.tcp_rates[0] = ((float) (oimage->numcomps * oimage->comps[0].w * oimage->comps[0].h * oimage->comps[0].prec)) / + (CINEMA_48_CS * 8 * oimage->comps[0].dx * oimage->comps[0].dy); + }else{ + temp_rate =((float) (oimage->numcomps * oimage->comps[0].w * oimage->comps[0].h * oimage->comps[0].prec)) / + (parameters.tcp_rates[i] * 8 * oimage->comps[0].dx * oimage->comps[0].dy); + if (temp_rate > CINEMA_48_CS ){ + parameters.tcp_rates[0]= ((float) (oimage->numcomps * oimage->comps[0].w * oimage->comps[0].h * oimage->comps[0].prec)) / + (CINEMA_48_CS * 8 * oimage->comps[0].dx * oimage->comps[0].dy); + }else{ + /* do nothing */ + } + } + } + parameters.max_comp_size = COMP_48_CS; + break; + } + + parameters.cp_disto_alloc = 1; + } + + /* get a J2K compressor handle */ + opj_cinfo_t* cinfo = opj_create_compress(CODEC_J2K); + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)cinfo, &event_mgr, stderr); + + /* setup the encoder parameters using the current image and user parameters */ + opj_setup_encoder(cinfo, ¶meters, oimage); + + /* open a byte stream for writing */ + /* allocate memory for all tiles */ + cio = opj_cio_open((opj_common_ptr)cinfo, NULL, 0); + + /* encode the image */ + bSuccess = opj_encode_with_info(cinfo, cio, oimage, &cstr_info); + if (!bSuccess) { + + opj_cio_close(cio); + opj_destroy_compress(cinfo); + opj_image_destroy(oimage); + if (cmptparm) + free(cmptparm); + if(parameters.cp_comment) + free(parameters.cp_comment); + if(parameters.cp_matrice) + free(parameters.cp_matrice); + +#ifndef __WXGTK__ + wxMutexGuiEnter(); +#endif /* __WXGTK__ */ + + wxLogError(wxT("failed to encode image")); + +#ifndef __WXGTK__ + wxMutexGuiLeave(); +#endif /* __WXGTK__ */ + + return false; + } + codestream_length = cio_tell(cio); + wxLogMessage(wxT("Codestream: %d bytes"), codestream_length); + + /* write the buffer to stream */ + stream.Write(cio->buffer, codestream_length); + + /* close and free the byte stream */ + opj_cio_close(cio); + + /* Write the index to disk */ + if (*indexfilename) { + if (write_index_file(&cstr_info, indexfilename)) { + wxLogError(wxT("Failed to output index file")); + } + } + + /* free remaining compression structures */ + opj_destroy_compress(cinfo); + + /* free image data */ + opj_image_destroy(oimage); + + if (cmptparm) + free(cmptparm); + if(parameters.cp_comment) + free(parameters.cp_comment); + if(parameters.cp_matrice) + free(parameters.cp_matrice); + +#ifndef __WXGTK__ + wxMutexGuiEnter(); +#endif /* __WXGTK__ */ + + wxLogMessage(wxT("J2K: Image encoded!")); + +#ifndef __WXGTK__ + wxMutexGuiLeave(); +#endif /* __WXGTK__ */ + + return true; +} + +#ifdef __VISUALC__ + #pragma warning(default:4611) +#endif /* VC++ */ + +// recognize the JPEG 2000 family starting box or the 0xFF4F JPEG 2000 SOC marker +bool wxJPEG2000Handler::DoCanRead(wxInputStream& stream) +{ + unsigned char hdr[24]; + int jpfamform; + + if ( !stream.Read(hdr, WXSIZEOF(hdr)) ) + return false; + + jpfamform = jpeg2000familytype(hdr, WXSIZEOF(hdr)); + + return ((jpfamform == JP2_CFMT) || (jpfamform == MJ2_CFMT) || (jpfamform == J2K_CFMT)); +} + +#endif // wxUSE_STREAMS + +#endif // wxUSE_LIBOPENJPEG diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/imagjpeg2000.h b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/imagjpeg2000.h new file mode 100644 index 0000000..aad1ce3 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/imagjpeg2000.h @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2007, Digital Signal Processing Laboratory, Università degli studi di Perugia (UPG), Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +///////////////////////////////////////////////////////////////////////////// +// Name: imagalljpeg2000.h +// Purpose: wxImage JPEG 2000 family file format handler +// Author: G. Baruffa - based on imagjpeg.h, Vaclav Slavik +// RCS-ID: $Id: imagalljpeg2000.h,v 0.0 2008/01/31 11:22:00 VZ Exp $ +// Copyright: (c) Giuseppe Baruffa +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_IMAGJPEG2000_H_ +#define _WX_IMAGJPEG2000_H_ + +#include "wx/defs.h" + +//----------------------------------------------------------------------------- +// wxJPEG2000Handler +//----------------------------------------------------------------------------- + +#if wxUSE_LIBOPENJPEG + +#include "wx/image.h" +#include "libopenjpeg/openjpeg.h" +#include "codec/index.h" + +#define wxBITMAP_TYPE_JPEG2000 50 + +class WXDLLEXPORT wxJPEG2000Handler: public wxImageHandler +{ +public: + inline wxJPEG2000Handler() + { + m_name = wxT("JPEG 2000 family file format"); + m_extension = wxT("mj2"); + m_type = wxBITMAP_TYPE_JPEG2000; + m_mime = wxT("image/mj2"); + + /* decoding */ + m_reducefactor = 0; + m_qualitylayers = 0; + m_components = 0; +#ifdef USE_JPWL + m_enablejpwl = true; + m_expcomps = JPWL_EXPECTED_COMPONENTS; + m_maxtiles = JPWL_MAXIMUM_TILES; +#endif // USE_JPWL + + /* encoding */ + m_subsampling = wxT("1,1"); + m_origin = wxT("0,0"); + m_rates = wxT("20,10,5"); + m_quality = wxT("30,35,40"); + m_enablequality = false; + m_multicomp = false; + m_irreversible = false; + m_resolutions = 6; + m_progression = 0; + m_cbsize = wxT("32,32"); + m_prsize = wxT("[128,128],[128,128]"); + m_tsize = wxT(""); + m_torigin = wxT("0,0"); + /*m_progression + m_resilience*/ + m_enablesop = false; + m_enableeph = false; + m_enablereset = false; + m_enablesegmark = false; + m_enablevsc = false; + m_enablerestart = false; + m_enableerterm = false; + m_enablebypass = false; + /*m_roicompo + m_roiup + m_indexfname*/ + m_enableidx = false; + m_index = wxT("index.txt"); + m_enablepoc = false; + m_poc = wxT("T1=0,0,1,5,3,CPRL/T1=5,0,1,6,3,CPRL"); + m_enablecomm = true; + +#if defined __WXMSW__ + m_comment = wxT("Created by OPJViewer Win32 - OpenJPEG version "); +#elif defined __WXGTK__ + m_comment = wxT("Created by OPJViewer Lin32 - OpenJPEG version "); +#else + m_comment = wxT("Created by OPJViewer - OpenJPEG version "); +#endif + +#ifdef USE_JPWL + m_comment += wxString::Format(wxT("%s with JPWL"), (char *) opj_version()); +#else + m_comment += wxString::Format(wxT("%s"), (char *) opj_version()); +#endif + + } + + // decoding engine parameters + int m_reducefactor, m_qualitylayers, m_components, m_framenum; +#ifdef USE_JPWL + bool m_enablejpwl; + int m_expcomps, m_maxtiles; +#endif // USE_JPWL + + // encoding engine parameters + wxString m_subsampling; + wxString m_origin; + wxString m_rates; + wxString m_quality; + bool m_enablequality; + bool m_multicomp; + bool m_irreversible; + int m_resolutions; + int m_progression; + wxString m_cbsize; + wxString m_prsize; + wxString m_tsize; + wxString m_torigin; + /*m_progression + m_resilience*/ + bool m_enablesop; + bool m_enableeph; + bool m_enablebypass; + bool m_enableerterm; + bool m_enablerestart; + bool m_enablereset; + bool m_enablesegmark; + bool m_enablevsc; + /*m_roicompo + m_roiup + m_indexfname*/ + bool m_enableidx; + wxString m_index; + bool m_enablecomm; + wxString m_comment; + bool m_enablepoc; + wxString m_poc; + +#if wxUSE_STREAMS + virtual bool LoadFile(wxImage *image, wxInputStream& stream, bool verbose=true, int index=-1); + virtual bool SaveFile(wxImage *image, wxOutputStream& stream, bool verbose=true); +protected: + virtual bool DoCanRead(wxInputStream& stream); +#endif + +private: + OPJ_PROG_ORDER give_progression(char progression[4]); + DECLARE_DYNAMIC_CLASS(wxJPEG2000Handler) +}; + +#endif // wxUSE_LIBOPENJPEG + +#endif // _WX_IMAGJPEG2000_H_ + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/imagmxf.cpp b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/imagmxf.cpp new file mode 100644 index 0000000..ccfa9f9 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/imagmxf.cpp @@ -0,0 +1,502 @@ +/* + * Copyright (c) 2007, Digital Signal Processing Laboratory, Università degli studi di Perugia (UPG), Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +///////////////////////////////////////////////////////////////////////////// +// Name: imagmxf.cpp +// Purpose: wxImage MXF (Material eXchange Format) JPEG 2000 file format handler +// Author: Giuseppe Baruffa - based on imagjpeg.cpp, Vaclav Slavik +// RCS-ID: $Id: imagmxf.cpp,v 0.00 2007/11/19 17:00:00 MW Exp $ +// Copyright: (c) Giuseppe Baruffa +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef USE_MXF + +#include "mxflib/mxflib.h" +using namespace mxflib; + +namespace +{ + //! Structure holding information about the essence in each body stream + struct EssenceInfo + { + UMIDPtr PackageID; + PackagePtr Package; + MDObjectPtr Descriptor; + }; + //! Map of EssenceInfo structures indexed by BodySID + typedef std::map EssenceInfoMap; + + //! The map of essence info for this file + EssenceInfoMap EssenceLookup; +}; + +//! Build an EssenceInfoMap for the essence in a given file +/*! \return True if al OK, else false + */ +bool BuildEssenceInfo(MXFFilePtr &File, EssenceInfoMap &EssenceLookup); + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_IMAGE && wxUSE_LIBOPENJPEG + +#include "imagmxf.h" + +#ifndef WX_PRECOMP + #include "wx/log.h" + #include "wx/app.h" + #include "wx/intl.h" + #include "wx/bitmap.h" + #include "wx/module.h" +#endif + + +#include "libopenjpeg/openjpeg.h" + + +#include "wx/filefn.h" +#include "wx/wfstream.h" + +// ---------------------------------------------------------------------------- +// types +// ---------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// wxMXFHandler +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxMXFHandler,wxImageHandler) + +#if wxUSE_STREAMS + +#include +#define MAX_MESSAGE_LEN 200 + +//------------- MXF Manager + +// Debug and error messages + +//! Display a warning message +void mxflib::warning(const char *Fmt, ...) +{ + char msg[MAX_MESSAGE_LEN]; + va_list args; + + va_start(args, Fmt); + _vsnprintf(msg, MAX_MESSAGE_LEN, Fmt, args); + va_end(args); + + int message_len = strlen(msg) - 1; + if (msg[message_len] != '\n') + message_len = MAX_MESSAGE_LEN; +#ifndef __WXGTK__ + wxMutexGuiEnter(); +#endif /* __WXGTK__ */ + wxLogMessage(wxT("[WARNING_MXF] %.*s"), message_len, msg); +#ifndef __WXGTK__ + wxMutexGuiLeave(); +#endif /* __WXGTK__ */ +} + +//! Display an error message +void mxflib::error(const char *Fmt, ...) +{ + char msg[MAX_MESSAGE_LEN]; + va_list args; + + va_start(args, Fmt); + _vsnprintf(msg, MAX_MESSAGE_LEN, Fmt, args); + va_end(args); + + int message_len = strlen(msg) - 1; + if (msg[message_len] != '\n') + message_len = MAX_MESSAGE_LEN; +#ifndef __WXGTK__ + wxMutexGuiEnter(); +#endif /* __WXGTK__ */ + wxLogMessage(wxT("[ERROR_MXF] %.*s"), message_len, msg); +#ifndef __WXGTK__ + wxMutexGuiLeave(); +#endif /* __WXGTK__ */ +} + +//! Display an error message +void mxflib::debug(const char *Fmt, ...) +{ + char msg[MAX_MESSAGE_LEN]; + va_list args; + + va_start(args, Fmt); + _vsnprintf(msg, MAX_MESSAGE_LEN, Fmt, args); + va_end(args); + + int message_len = strlen(msg) - 1; + if (msg[message_len] != '\n') + message_len = MAX_MESSAGE_LEN; +#ifndef __WXGTK__ + wxMutexGuiEnter(); +#endif /* __WXGTK__ */ + wxLogMessage(wxT("[DEBUG_MXF] %.*s"), message_len, msg); +#ifndef __WXGTK__ + wxMutexGuiLeave(); +#endif /* __WXGTK__ */ +} + + + +//------------- JPEG 2000 Data Source Manager + +#define J2K_CFMT 0 +#define JP2_CFMT 1 +#define JPT_CFMT 2 +#define MJ2_CFMT 3 +#define PXM_DFMT 0 +#define PGX_DFMT 1 +#define BMP_DFMT 2 +#define YUV_DFMT 3 + +/* sample error callback expecting a FILE* client object */ +void mxf_error_callback(const char *msg, void *client_data) { + int message_len = strlen(msg) - 1; + if (msg[message_len] != '\n') + message_len = MAX_MESSAGE_LEN; +#ifndef __WXGTK__ + wxMutexGuiEnter(); +#endif /* __WXGTK__ */ + wxLogMessage(wxT("[ERROR] %.*s"), message_len, msg); +#ifndef __WXGTK__ + wxMutexGuiLeave(); +#endif /* __WXGTK__ */ +} + +/* sample warning callback expecting a FILE* client object */ +void mxf_warning_callback(const char *msg, void *client_data) { + int message_len = strlen(msg) - 1; + if (msg[message_len] != '\n') + message_len = MAX_MESSAGE_LEN; +#ifndef __WXGTK__ + wxMutexGuiEnter(); +#endif /* __WXGTK__ */ + wxLogMessage(wxT("[WARNING] %.*s"), message_len, msg); +#ifndef __WXGTK__ + wxMutexGuiLeave(); +#endif /* __WXGTK__ */ +} + +/* sample debug callback expecting no client object */ +void mxf_info_callback(const char *msg, void *client_data) { + int message_len = strlen(msg) - 1; + if (msg[message_len] != '\n') + message_len = MAX_MESSAGE_LEN; +#ifndef __WXGTK__ + wxMutexGuiEnter(); +#endif /* __WXGTK__ */ + wxLogMessage(wxT("[INFO] %.*s"), message_len, msg); +#ifndef __WXGTK__ + wxMutexGuiLeave(); +#endif /* __WXGTK__ */ +} + + +///////////////////////////////////////////////// +///////////////////////////////////////////////// + +// load the mxf file format +bool wxMXFHandler::LoadFile(wxImage *image, wxInputStream& stream, bool verbose, int index) +{ + opj_dparameters_t parameters; /* decompression parameters */ + opj_event_mgr_t event_mgr; /* event manager */ + opj_image_t *opjimage = NULL; + unsigned char *src = NULL; + unsigned char *ptr; + int file_length, j2k_point, j2k_len; + opj_codestream_info_t cstr_info; /* Codestream information structure */ + + // simply display the version of the library + wxLogMessage(wxT("Version of MXF: %s "), wxString::FromAscii(LibraryVersion().c_str())); + //wxLogMessage(wxT("MXF file name: %s"), m_filename.GetFullPath()); + + // open MXF file + MXFFilePtr TestFile = new MXFFile; + if (! TestFile->Open(m_filename.GetFullPath().c_str(), true)) + { + wxLogError(wxT("Could not find %s"), m_filename.GetFullPath().c_str()); + return false; + } else + wxLogMessage(wxT("Found %s"), m_filename.GetFullPath().c_str()); + + // Get the size + TestFile->SeekEnd(); + wxLogMessage(wxT("Size is %d bytes"), TestFile->Tell()); + TestFile->Seek(0); + + // essence information + //BuildEssenceInfo(TestFile, EssenceLookup); + + // close MXF file + TestFile->Close(); + + return false; + + // destroy the image + image->Destroy(); + + /* handle to a decompressor */ + opj_dinfo_t* dinfo = NULL; + opj_cio_t *cio = NULL; + + /* configure the event callbacks (not required) */ + memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); + event_mgr.error_handler = mxf_error_callback; + event_mgr.warning_handler = mxf_warning_callback; + event_mgr.info_handler = mxf_info_callback; + + /* set decoding parameters to default values */ + opj_set_default_decoder_parameters(¶meters); + + /* prepare parameters */ + strncpy(parameters.infile, "", sizeof(parameters.infile)-1); + strncpy(parameters.outfile, "", sizeof(parameters.outfile)-1); + parameters.decod_format = J2K_CFMT; + parameters.cod_format = BMP_DFMT; + if (m_reducefactor) + parameters.cp_reduce = m_reducefactor; + if (m_qualitylayers) + parameters.cp_layer = m_qualitylayers; + /*if (n_components) + parameters. = n_components;*/ + + /* JPWL only */ +#ifdef USE_JPWL + parameters.jpwl_exp_comps = m_expcomps; + parameters.jpwl_max_tiles = m_maxtiles; + parameters.jpwl_correct = m_enablejpwl; +#endif /* USE_JPWL */ + + /* get a decoder handle */ + dinfo = opj_create_decompress(CODEC_J2K); + + /* find length of the stream */ + stream.SeekI(0, wxFromEnd); + file_length = (int) stream.TellI(); + + /* search for the m_framenum codestream position and length */ + //jp2c_point = searchjp2c(stream, file_length, m_framenum); + //jp2c_len = searchjp2c(stream, file_length, m_framenum); + j2k_point = 0; + j2k_len = 10; + + // malloc memory source + src = (unsigned char *) malloc(j2k_len); + + // copy the jp2c + stream.SeekI(j2k_point, wxFromStart); + stream.Read(src, j2k_len); + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr); + + /* setup the decoder decoding parameters using user parameters */ + opj_setup_decoder(dinfo, ¶meters); + + /* open a byte stream */ + cio = opj_cio_open((opj_common_ptr)dinfo, src, j2k_len); + + /* decode the stream and fill the image structure */ + opjimage = opj_decode_with_info(dinfo, cio, &cstr_info); + if (!opjimage) { + wxMutexGuiEnter(); + wxLogError(wxT("MXF: failed to decode image!")); + wxMutexGuiLeave(); + opj_destroy_decompress(dinfo); + opj_cio_close(cio); + free(src); + return false; + } + + /* close the byte stream */ + opj_cio_close(cio); + + /* common rendering method */ +#include "imagjpeg2000.cpp" + + wxMutexGuiEnter(); + wxLogMessage(wxT("MXF: image loaded.")); + wxMutexGuiLeave(); + + /* close openjpeg structs */ + opj_destroy_decompress(dinfo); + opj_image_destroy(opjimage); + free(src); + + if (!image->Ok()) + return false; + else + return true; + +} + +// save the mxf file format +bool wxMXFHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbose ) +{ + wxLogError(wxT("MXF: Couldn't save movie -> not implemented.")); + return false; +} + +#ifdef __VISUALC__ + #pragma warning(default:4611) +#endif /* VC++ */ + +// recognize the MXF JPEG 2000 starting box +bool wxMXFHandler::DoCanRead( wxInputStream& stream ) +{ + unsigned char hdr[4]; + + if ( !stream.Read(hdr, WXSIZEOF(hdr)) ) + return false; + + return (hdr[0] == 0x06 && + hdr[1] == 0x0E && + hdr[2] == 0x2B && + hdr[3] == 0x34); +} + +//! Build an EssenceInfoMap for the essence in a given file +/*! \return True if al OK, else false + */ +bool BuildEssenceInfo(MXFFilePtr &File, EssenceInfoMap &EssenceLookup) +{ + // Empty any old data + EssenceLookup.clear(); + + // Get the master metadata set (or the header if we must) + PartitionPtr MasterPartition = File->ReadMasterPartition(); + if(!MasterPartition) + { + File->Seek(0); + MasterPartition = File->ReadPartition(); + warning("File %s does not contain a cloased copy of header metadata - using the open copy in the file header\n", File->Name.c_str()); + } + + if(!MasterPartition) + { + error("Could not read header metadata from file %s\n", File->Name.c_str()); + return false; + } + + // Read and parse the metadata + MasterPartition->ReadMetadata(); + MetadataPtr HMeta = MasterPartition->ParseMetadata(); + + if(!HMeta) + { + error("Could not read header metadata from file %s\n", File->Name.c_str()); + return false; + } + + /* Scan the Essence container data sets to get PackageID to BodySID mapping */ + MDObjectPtr ECDSet = HMeta[ContentStorage_UL]; + if(ECDSet) ECDSet = ECDSet->GetLink(); + if(ECDSet) ECDSet = ECDSet[EssenceContainerDataBatch_UL]; + if(!ECDSet) + { + error("Header metadata in file %s does not contain an EssenceContainerData set\n", File->Name.c_str()); + return false; + } + + MDObject::iterator it = ECDSet->begin(); + while(it != ECDSet->end()) + { + MDObjectPtr ThisECDSet = (*it).second->GetLink(); + MDObjectPtr PackageID; + if(ThisECDSet) PackageID = ThisECDSet->Child(LinkedPackageUID_UL); + if(PackageID) + { + EssenceInfo NewEI; + NewEI.PackageID = new UMID(PackageID->PutData()->Data); + + // Inset the basic essence info - but not if this is external essence (BodySID == 0) + UInt32 BodySID = ThisECDSet->GetUInt(BodySID_UL); + if(BodySID) EssenceLookup[BodySID] = NewEI; + } + it++; + } + + /* Now find the other items for the essence lookup map */ + if(EssenceLookup.size()) + { + PackageList::iterator it = HMeta->Packages.begin(); + while(it != HMeta->Packages.end()) + { + // Only Source Packages are of interest + if((*it)->IsA(SourcePackage_UL)) + { + MDObjectPtr Descriptor = (*it)->Child(Descriptor_UL); + if(Descriptor) Descriptor = Descriptor->GetLink(); + + if(Descriptor) + { + MDObjectPtr PackageID = (*it)->Child(PackageUID_UL); + if(PackageID) + { + UMIDPtr TheID = new UMID(PackageID->PutData()->Data); + + /* Now do a lookup in the essence lookup map (it will need to be done the long way here */ + EssenceInfoMap::iterator EL_it = EssenceLookup.begin(); + while(EL_it != EssenceLookup.end()) + { + if((*((*EL_it).second.PackageID)) == (*TheID)) + { + // If found, set the missing items and stop searching + (*EL_it).second.Package = (*it); + (*EL_it).second.Descriptor = Descriptor; + break; + } + EL_it++; + } + } + } + } + + it++; + } + } + + return true; +} + + +#endif // wxUSE_STREAMS + +#endif // wxUSE_LIBOPENJPEG + +#endif // USE_MXF + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/imagmxf.h b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/imagmxf.h new file mode 100644 index 0000000..2f287bf --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/imagmxf.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2007, Digital Signal Processing Laboratory, Università degli studi di Perugia (UPG), Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +///////////////////////////////////////////////////////////////////////////// +// Name: imagmxf.h +// Purpose: wxImage MXF (Material eXchange Format) JPEG 2000 file format handler +// Author: G. Baruffa - based on imagjpeg.h, Vaclav Slavik +// RCS-ID: $Id: imagmj2.h,v 0.0 2007/11/19 17:00:00 VZ Exp $ +// Copyright: (c) Giuseppe Baruffa +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_IMAGMXF_H_ +#define _WX_IMAGMXF_H_ + +#ifdef USE_MXF + +#include "wx/defs.h" +#include "wx/filename.h" + +//----------------------------------------------------------------------------- +// wxMXFHandler +//----------------------------------------------------------------------------- + +#if wxUSE_LIBOPENJPEG + +#include "wx/image.h" +#include "libopenjpeg/openjpeg.h" + +#define wxBITMAP_TYPE_MXF 51 + +class WXDLLEXPORT wxMXFHandler: public wxImageHandler +{ +public: + inline wxMXFHandler() + { + m_name = wxT("MXF JPEG 2000 file format"); + m_extension = wxT("mxf"); + m_type = wxBITMAP_TYPE_MXF; + m_mime = wxT("image/mxf"); + + m_reducefactor = 0; + m_qualitylayers = 0; + m_components = 0; + m_filename = wxT(""); +#ifdef USE_JPWL + m_enablejpwl = true; + m_expcomps = JPWL_EXPECTED_COMPONENTS; + m_maxtiles = JPWL_MAXIMUM_TILES; +#endif // USE_JPWL + } + + // decoding engine parameters + int m_reducefactor, m_qualitylayers, m_components, m_framenum; + wxFileName m_filename; +#ifdef USE_JPWL + bool m_enablejpwl; + int m_expcomps, m_maxtiles; +#endif // USE_JPWL + +#if wxUSE_STREAMS + virtual bool LoadFile( wxImage *image, wxInputStream& stream, bool verbose=true, int index=-1 ); + virtual bool SaveFile( wxImage *image, wxOutputStream& stream, bool verbose=true ); +protected: + virtual bool DoCanRead( wxInputStream& stream ); +#endif + +private: + DECLARE_DYNAMIC_CLASS(wxMXFHandler) +}; + +#endif // wxUSE_LIBOPENJPEG + +#endif // USE_MXF + +#endif // _WX_IMAGMXF_H_ + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/license.txt b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/license.txt new file mode 100644 index 0000000..6409db4 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/license.txt @@ -0,0 +1,14 @@ +Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium +Copyright (c) 2002-2007, Professor Benoit Macq +Copyright (c) 2001-2003, David Janssens +Copyright (c) 2002-2003, Yannick Verschueren +Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe +Copyright (c) 2005, Herve Drolon, FreeImage Team +Copyright (c) 2007, Digital Signal Processing Laboratory, Università degli studi di Perugia (UPG), Italy +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditionsare met: +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/opj_logo.xpm b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/opj_logo.xpm new file mode 100644 index 0000000..c64d0a7 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/opj_logo.xpm @@ -0,0 +1,285 @@ +/* XPM */ +static char *opj_logo[] = { +/* columns rows colors chars-per-pixel */ +"90 61 218 2", +" c #BE3D12", +". c #BF461D", +"X c #AD5435", +"o c #B64925", +"O c #B54E2B", +"+ c #BC4620", +"@ c #BB4B25", +"# c #BC4E29", +"$ c #B5502F", +"% c #BD512C", +"& c #B45334", +"* c #B35638", +"= c #B45B3D", +"- c #BB5533", +"; c #BE5937", +": c #BC5C3D", +"> c #9C766A", +", c #AD5D42", +"< c #B55F41", +"1 c #BA5E40", +"2 c #A7634D", +"3 c #A76C57", +"4 c #AA6750", +"5 c #AC6B56", +"6 c #AA6E5A", +"7 c #A4705E", +"8 c #B46045", +"9 c #B1644B", +"0 c #BD6244", +"q c #B96448", +"w c #BC694D", +"e c #B36B53", +"r c #B26E58", +"t c #BB6C52", +"y c #B2725D", +"u c #BD7056", +"i c #BB745C", +"p c #A67566", +"a c #A57B6D", +"s c #AE7562", +"d c #AB7867", +"f c #AA7C6C", +"g c #A07E73", +"h c #AA7F71", +"j c #B37661", +"k c #B47863", +"l c #B27D6B", +"z c #BB7863", +"x c #BA7E69", +"c c #C73605", +"v c #C63A0B", +"b c #CB3300", +"n c #CA3807", +"m c #C93A0A", +"M c #C43E11", +"N c #C93E10", +"B c #C44115", +"V c #C3441A", +"C c #C4481E", +"Z c #CA4113", +"A c #C94519", +"S c #CB481C", +"D c #C24A23", +"F c #C24F28", +"G c #CD4D23", +"H c #C4522D", +"J c #CB532B", +"K c #C25632", +"L c #C35936", +"P c #C25C3B", +"I c #C85630", +"U c #CB5933", +"Y c #CB5E3A", +"T c #D05026", +"R c #CC613D", +"E c #C26343", +"W c #C46748", +"Q c #C1694C", +"! c #CD6744", +"~ c #CA6C4D", +"^ c #C37155", +"/ c #C4755B", +"( c #CB7356", +") c #C8765B", +"_ c #D06D4C", +"` c #D07253", +"' c #D47B5E", +"] c #C37B63", +"[ c #C27E68", +"{ c #C97F68", +"} c #A68175", +"| c #A48479", +" . c #AD8172", +".. c #AD8578", +"X. c #AB897D", +"o. c #B1806F", +"O. c #BA816F", +"+. c #B38373", +"@. c #B58778", +"#. c #B3897B", +"$. c #BA8472", +"%. c #BB8C7C", +"&. c #C2816B", +"*. c #CD846C", +"=. c #C38470", +"-. c #C38976", +";. c #C38D7B", +":. c #CC8973", +">. c #CF8F7A", +",. c #CB907D", +"<. c #D1937F", +"1. c #948E8C", +"2. c #9D8C86", +"3. c #9D8F89", +"4. c #96908E", +"5. c #9C918D", +"6. c #949392", +"7. c #9B9492", +"8. c #9D9997", +"9. c #9D9C9C", +"0. c #A38B83", +"q. c #AA8D83", +"w. c #A4918B", +"e. c #AC9087", +"r. c #AB938C", +"t. c #A49590", +"y. c #A29996", +"u. c #A19D9C", +"i. c #AA9790", +"p. c #AC9994", +"a. c #AC9E99", +"s. c #B18D81", +"d. c #B59084", +"f. c #B49389", +"g. c #BA9184", +"h. c #B89589", +"j. c #BA988D", +"k. c #B29B93", +"l. c #BC9C92", +"z. c #ACA19D", +"x. c #B1A19D", +"c. c #BCA39B", +"v. c #A3A3A3", +"b. c #ABA5A3", +"n. c #AEA9A7", +"m. c #ABABAA", +"M. c #B3A5A1", +"N. c #B3A9A6", +"B. c #B3ADAA", +"V. c #B9A6A0", +"C. c #B9AAA5", +"Z. c #BAADA9", +"A. c #B4B0AF", +"S. c #BAB0AD", +"D. c #B4B3B3", +"F. c #BAB5B3", +"G. c #BDB8B6", +"H. c #BBBBBB", +"J. c #C39384", +"K. c #C0978A", +"L. c #C2998B", +"P. c #CA9483", +"I. c #CD9A8A", +"U. c #C19D92", +"Y. c #D69B89", +"T. c #DB9680", +"R. c #C2A095", +"E. c #C4A69C", +"W. c #CCA193", +"Q. c #C8A599", +"!. c #CBA99D", +"~. c #C6AEA6", +"^. c #CCACA2", +"/. c #CBB2AB", +"(. c #C3B8B5", +"). c #C2BDBC", +"_. c #C9B9B3", +"`. c #D3ADA0", +"'. c #D3B4A9", +"]. c #DCB2A4", +"[. c #DEB6A8", +"{. c #D1BFB9", +"}. c #D9BEB5", +"|. c #C5C0BE", +" X c #CDC0BC", +".X c #D2C1BB", +"XX c #DDC3BB", +"oX c #E0C5BC", +"OX c #E0C8BF", +"+X c #C2C2C2", +"@X c #CBC4C2", +"#X c #CDC8C6", +"$X c #CCCBCB", +"%X c #D2C6C2", +"&X c #D1CECD", +"*X c #DDC8C1", +"=X c #DECFCA", +"-X c #D9D1CE", +";X c #D3D3D3", +":X c #D9D5D4", +">X c #DED9D7", +",X c #DBDBDB", +".;X0XwXwXwXwXrXwXwXrXrXrXrXtXrXtXrXrXrXwXrXrXrXrXrXrXrXrXrXrXrXwXrXrXwXrXrXrXtXtXrXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX", +"tXtXtXtXrXrXrX0X,X'.S b b P l.z.M.k.w n b b g.;X,X,X,X0X0X0X0X0XwXwXwXwXwXwXwXwXwX0X0X0XwX0X0XwXwXwXwX0X0X0X0X0X0XwXwXwXwXrXrXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX", +"tXtXtXrXrXrXwX0X:XT.m b A ] G.D.D.m.$.m b b $.$X&X.X}.XX>XOX}.oXXX c b @ 9.v.9.u., b b - 3.& b b 7 1.1.4.4.4.6.7.9.w.m b + t.v.m.p.D b b K.;X,X0XwXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX", +"tXtXtXwX0X,X$X-.b b b i D.H.G.H.J.N b b = 9.9.5 c b B 7.9.v.y.b b m f 4.O b b 3 6.6.6.g 9 4 h u.h b b - b.m.m.s.b b N ~.;X,X0XwXrXrXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX", +"tXtXtXwX0X,X;XE.G b b I z ] ] ] W n b H l 9.8.9 b b m e 6 r e b b # 0.y.< b b O 6 p 6 < # ; q.v.t b b 0 n.A.A.+.b b H _.;X,XwXwXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX", +"tXtXtXwXwX,X;X#Xf.b b b b b b b b b - a.v.v.w.@ b b v b b b b b @ b.m.v.w.M b b b b b b v ..m.n.A b n g.H.H.H.4 b b [ &X,X0XwXrXrXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX", +"tXtXtXwXwX0X:X$XZ.Q H v n b m B H E x n.m.m.q.B b v < . v N + E z m.m.m.b.e - M m v M - t k.D.m.; # - V.H.+XH.s # # K.:X,X0XwXrXrXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX", +"tXtXtXrXwXwX,X,X$X+XG.Z.Z.B.C.S.F.H.H.H.D.D.j b b q v.b.a.n.B.H.H.+X+X+XH.H.D.Z.C.Z.Z.F.H.H.+X+XH.).H.$X&X&X;X$X#X#X:X,X0XwXrXrXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX", +"tXtXtXrXrXwX0X,X;X#X+X+X+XH.H.+X+X+XH.H.H.D.e b n i n.m.D.H.H.+X#X$X$X+X+X+X+XH.H.H.H.+X+X+X$X&X&X&X$X;X;X;X:X;X:X,X,X0XwXwXrXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX", +"tXtXtXtXrXrXwXwX,X,X;X;X$X$X$X;X;X&X;X$X#X+XF b v s.H.H.+X$X&X;X;X,X,X,X;X:X;X;X;X;X;X;X:X,X,X,X0X,X0X,X0X0X0X0X0X0X0XwXwXrXtXrXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX", +"tXtXtXrXtXrXwXwX0X,X:X;X;X;X;X;X:X;X;X;X$X+XC b B k.+X+X$X$X;X,X,X0X0X0X0X0X;X,X,X,X,X,X,X,X,X0X0X0X0X0X0XwX0X0X0XwXwXrXrXrXrXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX", +"tXtXtXtXtXrXrXrXrXwXwXwX0X0X0X0X0X0X0X,X,X:X^.^.!.$X$X;X,X,X0XwXwXwXwXwXwXwXwX0X0X0X0XwXwXwXwXwXwXrXrXwXrXrXrXrXrXrXrXrXrXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX", +"tXtXtXtXtXtXrXrXrXrXwXwXwXwX0XwXwXwX0X0X,X:X;X$X&X&X;X,X,X0XwXwXwXrXrXrXrXrXwXwXwXwXwXwXwXrXrXrXwXrXrXrXrXrXrXrXrXrXrXtXrXtXtXrXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX", +"tXtXtXtXtXtXtXtXtXrXrXrXrXrXrXrXrXrXwXwXwXwX0X,X0X0X0XwXwXrXrXrXrXrXrXrXrXrXrXrXrXrXrXwXrXrXrXrXrXtXrXrXrXtXrXrXrXrXrXrXrXrXrXtXtXtXrXrXtXtXtXtXrXrXtXrXrXtXrXtXrXtXtXtXtXtXtXtXtXtX", +"tXtXtXtXtXtXtXtXrXtXtXrXtXrXrXrXrXrXrXwXwXwX0XwX0XwXwXwXrXrXrXtXtXrXrXrXrXrXrXrXrXwXrXwXrXwXwXrXrXrXrXrXrXrXrXrXrXrXrXrXrXrXrXrXrXrXtXrXrXtXtXrXrXrXrXrXrXrXrXrXrXtXtXtXtXtXtXtXtXtX", +"tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXrXrXrXwXrXrXrXrXrXrXtXrXtXrXrXrXrXrXwXwXwXwXwX0X0XwX0XwXwXwXwXwXwXwXrXwXwXwX0X0X0X0XwX0XwXwXrXrXrXwXrXwXwXwX0XwX0XwXwXwXrXrXrXrXtXtXtXtXtXtX", +"tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXrXrXrXrXrXrXrXrXtXtXrXrXtXrXrXeX7X7X9XwXwXwX5X3X3X3X2X2X2X5X0XwXwXwXwXwX8X3X3X2X2X2X2X2X3X6X6X7XwXwXwXwXwXwX7X1XXXOXOX1X8XwXwXrXrXrXtXtXtXtXtX", +"tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXrXtXtXtXrXrXrXwXT.T T :.,X,X-X` G G G G G G U _ J.-X,X,X,X[ G G G G G G G G G G _ >XwX0X,X&XI.R N b b b m ! `.5XwXrXrXtXtXtXtXtX", +"tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXrXtXtXtXrXtXrXrXrXwX0X' b b ] >X,X%XJ b b b b b b b b Q {.:X;X:Xq b b b b b b b b b b Y >X0X,X-X'.^ n b b b b b m *.1XwXwXrXtXtXtXtXtX", +"tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXrXrX0X0X%XL b b L.@X+X-.b b M L L L D b b b M V.+X(.N b b D H H H H H U U W.;X&X^.H b b n W -.-.W n b b J &XwXrXtXtXtXtXtX", +"tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXrXwXwX0X XF b b U.+X+X[ b b D z z j P v b b N U.H.S.m b m E Q t ^ ) / ) ) /.$X$X;.m b n A %.H.H.J.N b b N .XwXwXtXtXtXtXtX", +"tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXrXwXwX,X:X!.m b L N.D.m.* b b y v.v.v.v.p.n b M f.m.w b b D u.v.m.m.D.G.H.H.+X).g.b b B j.F.D.D.D.D.l.; F I /.0XwXrXtXtXtXtX", +"tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXrXrXwX,X:XU.n b E B.A.n.$ b b s v.9.v.v.r.n n M r.b.1 b b D u.v.m.m.D.D.H.H.).H.k b b # M.G.D.D.D.D.Z.t w u _.0XwXtXtXtXtXtX", +"tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXrXrXwXwX,X;X$XJ b m h b.v.i.m b M a 5.5.2.p M b c < 8.2.+ b b M o o o o # % j G.H.g.m b A M.D.D.D.B.M.M.M.M.Z.(.:X0XwXrXtXtXtXtX", +"tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXrXrXrXrXrXwX,X,X&X(.n b M 0.v.v.s b b b b b n b b c b M u.v.g M b b b b b b b b b i G.D.0 b b 8 D.D.H.G.P n b b n b U :X,XwXtXtXtXtXtX", +"tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXrXrXrXrXwX0X,X;X$XV.n b M w.v.9.< b b b b b b b b c H r 9.v.a n b * < < w w Q Q g.D.B.: b b r D.D.D.m.C b b b b b ) ;X0XwXrXtXtXtXtX", +"tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXrXrXrXrX6XP.=.K.;X#X+Xx n b D v.u.7.. b b M D . D & 2 q.b.b.v.v.< b b X 6.9.9.b.m.D.D.D.D.n.# b b f D.D.D.b.= 1 * N b n !.;X,XwXtXtXtXtXtX", +"tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXrXtXrXrXwX stopbyte, inner_length + marker/box sign length (total length) +| |_ Additional info, depending on the marker/box type +| |_ ... +| +|_ #001: Marker/Box short name (Hex code) +| | +| |_ ... +| +... + + +The viewing pane will display the decoded image contained in the JPEG 2000 file. +It should display correctly images as large as 4000x2000, provided that a couple of GB of RAM are available. Nothing is known about the display of larger sizes: let us know if you manage to get it working. + + +The log/peek pane is shared among two different subpanels: + +- the log panel will report a lot of debugging info coming out from the wx GUI as well as from the openjpeg library +- the peek pane tries to give a peek on the codestream/file portion which is currently selected in the browsing pane. It shows both hex and ascii values corresponding to the marker/box section. + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/readmebefore.txt b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/readmebefore.txt new file mode 100644 index 0000000..a59b0e8 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/readmebefore.txt @@ -0,0 +1,11 @@ +What is OpenJPEG ? +================== +The OpenJPEG library is an open-source JPEG 2000 codec written in C language. It has been developed in order to promote the use of JPEG 2000, the new still-image compression standard from the Joint Photographic Experts Group (JPEG). In addition to the basic codec, various other features are under development, among them the JP2 and MJ2 (Motion JPEG 2000) file formats, an indexing tool useful for the JPIP protocol, JPWL-tools for error-resilience, a Java-viewer for j2k-images, ... + +Who can use the library ? +========================= +Anybody. As the OpenJPEG library is released under the BSD license, anybody can use or modify the library, even for commercial applications. The only restriction is to retain the copyright in the sources or the binaries documentation. + +Who is developing the library ? +=============================== +The library is developed by the Communications and Remote Sensing Lab (TELE), in the Université Catholique de Louvain (UCL). The JPWL module is developped and maintained by the Digital Signal Processing Lab (DSPLab) of the University of Perugia, Italy (UNIPG). As our purpose is to make OpenJPEG really useful for those interested in the image compression field, any feedback/advices are obviously welcome ! We will do our best to handle them quickly. \ No newline at end of file diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/wxj2kparser.cpp b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/wxj2kparser.cpp new file mode 100644 index 0000000..844eae9 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/wxj2kparser.cpp @@ -0,0 +1,1465 @@ +/* + * Copyright (c) 2007, Digital Signal Processing Laboratory, Università degli studi di Perugia (UPG), Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "OPJViewer.h" + +/* From little endian to big endian, 2 bytes */ +#define BYTE_SWAP2(X) ((X & 0x00FF) << 8) | ((X & 0xFF00) >> 8) +#define BYTE_SWAP4(X) ((X & 0x000000FF) << 24) | ((X & 0x0000FF00) << 8) | ((X & 0x00FF0000) >> 8) | ((X & 0xFF000000) >> 24) + +/* From codestream to int values */ +#define STREAM_TO_UINT32(C, P) (((unsigned long int) (C)[(P) + 0] << 24) + \ + ((unsigned long int) (C)[(P) + 1] << 16) + \ + ((unsigned long int) (C)[(P) + 2] << 8) + \ + ((unsigned long int) (C)[(P) + 3] << 0)) + +#define STREAM_TO_UINT16(C, P) (((unsigned long int) (C)[(P) + 0] << 8) + \ + ((unsigned long int) (C)[(P) + 1] << 0)) + + +/* Markers values */ +#define J2KMARK_NUM 24 +enum { + SOC_VAL = 0xFF4F, + SOT_VAL = 0xFF90, + SOD_VAL = 0xFF93, + EOC_VAL = 0xFFD9, + SIZ_VAL = 0xFF51, + COD_VAL = 0xFF52, + COC_VAL = 0xFF53, + RGN_VAL = 0xFF5E, + QCD_VAL = 0xFF5C, + QCC_VAL = 0xFF5D, + POD_VAL = 0xFF5F, + TLM_VAL = 0xFF55, + PLM_VAL = 0xFF57, + PLT_VAL = 0xFF58, + PPM_VAL = 0xFF60, + PPT_VAL = 0xFF61, + SOP_VAL = 0xFF91, + EPH_VAL = 0xFF92, + COM_VAL = 0xFF64 +#ifdef USE_JPWL + , EPB_VAL = 0xFF66, + ESD_VAL = 0xFF67, + EPC_VAL = 0xFF68, + RED_VAL = 0xFF69 + /*, EPB_VAL = 0xFF96, + ESD_VAL = 0xFF98, + EPC_VAL = 0xFF97, + RED_VAL = 0xFF99*/ +#endif // USE_JPWL +#ifdef USE_JPSEC + , SEC_VAL = 0xFF65 +#endif // USE_JPSEC +}; + +// All the markers in one vector +unsigned short int marker_val[] = { + SOC_VAL, SOT_VAL, SOD_VAL, EOC_VAL, + SIZ_VAL, + COD_VAL, COC_VAL, RGN_VAL, QCD_VAL, QCC_VAL, POD_VAL, + TLM_VAL, PLM_VAL, PLT_VAL, PPM_VAL, PPT_VAL, + SOP_VAL, EPH_VAL, + COM_VAL +#ifdef USE_JPWL + , EPB_VAL, ESD_VAL, EPC_VAL, RED_VAL +#endif // USE_JPWL +#ifdef USE_JPSEC + , SEC_VAL +#endif // USE_JPSEC +}; + +// Marker names +char *marker_name[] = { + "SOC", "SOT", "SOD", "EOC", + "SIZ", + "COD", "COC", "RGN", "QCD", "QCC", "POD", + "TLM", "PLM", "PLT", "PPM", "PPT", + "SOP", "EPH", + "COM" +#ifdef USE_JPWL + , "EPB", "ESD", "EPC", "RED" +#endif // USE_JPWL +#ifdef USE_JPSEC + , "SEC" +#endif // USE_JPSEC +}; + +// Marker descriptions +char *marker_descr[] = { + "Start of codestream", "Start of tile-part", "Start of data", "End of codestream", + "Image and tile size", + "Coding style default", "Coding style component", "Region-of-interest", "Quantization default", + "Quantization component", "Progression order change, default", + "Tile-part lengths, main header", "Packet length, main header", "Packets length, tile-part header", + "Packed packet headers, main header", "Packed packet headers, tile-part header", + "Start of packet", "End of packet header", + "Comment and extension" +#ifdef USE_JPWL + , "Error Protection Block", "Error Sensitivity Descriptor", "Error Protection Capability", + "Residual Errors Descriptor" +#endif // USE_JPWL +#ifdef USE_JPSEC + , "Main security marker" +#endif // USE_JPSEC +}; + +void OPJParseThread::ParseJ2KFile(wxFile *m_file, wxFileOffset offset, wxFileOffset length, wxTreeItemId parentid) +{ + unsigned short int csiz = 0; + + // check if the file is opened + if (m_file->IsOpened()) + WriteText(wxT("File OK")); + else + return; + + // position at the beginning + m_file->Seek(offset, wxFromStart); + + // navigate the file + int m, inside_sod = 0, inside_sop = 0; + int nmarks = 0, maxmarks = 10000; + unsigned char onebyte[1]; + unsigned char twobytes[2], firstbyte, secondbyte; + unsigned char fourbytes[4]; + unsigned short int currmark; + unsigned short int currlen; + int lastPsot = 0, lastsotpos = 0; + + WriteText(wxT("Start search...")); + +// advancing macro +#define OPJ_ADVANCE(A) {offset += A; if (offset < length) m_file->Seek(offset, wxFromStart); else return;} + + // begin search + while ((offset < length) && (!m_file->Eof())) { + + // read one byte + if (m_file->Read(&firstbyte, 1) != 1) + break; + + // look for 0xFF + if (firstbyte == 0xFF) { + + // it is a possible marker + if (m_file->Read(&secondbyte, 1) != 1) + break; + else + currmark = (((unsigned short int) firstbyte) << 8) + (unsigned short int) secondbyte; + + } else { + + // nope, advance by one and search again + OPJ_ADVANCE(1); + continue; + } + + // search the marker + for (m = 0; m < J2KMARK_NUM; m++) { + if (currmark == marker_val[m]) + break; + } + + // marker not found + if (m == J2KMARK_NUM) { + // nope, advance by one and search again + OPJ_ADVANCE(1); + continue; + } + + // if we are inside SOD, only some markers are allowed + if (inside_sod) { + + // we are inside SOP + if (inside_sop) { + + } + + // randomly marker coincident data + if ((currmark != SOT_VAL) && + (currmark != EOC_VAL) && + (currmark != SOP_VAL) && + (currmark != EPH_VAL)) { + OPJ_ADVANCE(1); + continue; + } + + // possible SOT? + if ((currmark == SOT_VAL)) { + // too early SOT + if (offset < (lastsotpos + lastPsot)) { + OPJ_ADVANCE(1); + continue; + } + // we were not in the last tile + /*if (lastPsot != 0) { + OPJ_ADVANCE(1); + break; + }*/ + } + } + + // beyond this point, the marker MUST BE real + + // length of current marker segment + if ((currmark == SOD_VAL) || + (currmark == SOC_VAL) || + (currmark == EOC_VAL) || + (currmark == EPH_VAL)) + + // zero length markers + currlen = 0; + + else { + + // read length field + if (m_file->Read(twobytes, 2) != 2) + break; + + currlen = (((unsigned short int) twobytes[0]) << 8) + (unsigned short int) twobytes[1]; + } + + // here we pass to AppendItem() normal and selected item images (we + // suppose that selected image follows the normal one in the enum) + int image, imageSel; + image = m_tree->TreeCtrlIcon_Folder; + imageSel = image + 1; + + // append the marker + wxTreeItemId currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("%03d: "), nmarks) + + wxString::FromAscii(marker_name[m]) + + wxString::Format(wxT(" (0x%04X)"), marker_val[m]), + image, imageSel, + new OPJMarkerData(wxT("MARK") + wxString::Format(wxT(" (%d)"), marker_val[m]), + m_tree->m_fname.GetFullPath(), offset, offset + currlen + 1) + ); + + // append some info + image = m_tree->TreeCtrlIcon_File; + imageSel = image + 1; + + // marker name + wxTreeItemId subcurrid1 = m_tree->AppendItem(currid, + wxT("*** ") + wxString::FromAscii(marker_descr[m]) + wxT(" ***"), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + m_tree->SetItemFont(subcurrid1, *wxITALIC_FONT); + + // position and length + wxTreeItemId subcurrid2 = m_tree->AppendItem(currid, + wxLongLong(offset).ToString() + wxT(" > ") + wxLongLong(offset + currlen + 1).ToString() + + wxT(", ") + wxString::Format(wxT("%d + 2 (%d)"), currlen, currlen + 2), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + // give additional info on markers + switch (currmark) { + + ///////// + // SOP // + ///////// + case SOP_VAL: + { + // read packet number + if (m_file->Read(twobytes, 2) != 2) + break; + int packnum = STREAM_TO_UINT16(twobytes, 0); + + image = m_tree->TreeCtrlIcon_File; + imageSel = image + 1; + + wxTreeItemId subcurrid3 = m_tree->AppendItem(currid, + wxString::Format(wxT("Pack. no. %d"), packnum), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + inside_sop = 1; + }; + break; + +#ifdef USE_JPWL + ///////// + // RED // + ///////// + case RED_VAL: + { + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char pred = onebyte[0]; + + image = m_tree->TreeCtrlIcon_File; + imageSel = image + 1; + + wxString address[] = { + wxT("Packet addressing"), + wxT("Byte-range addressing"), + wxT("Packet-range addressing"), + wxT("Reserved") + }; + + wxTreeItemId subcurrid = m_tree->AppendItem(currid, + address[(pred & 0xC0) >> 6], + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + subcurrid = m_tree->AppendItem(currid, + wxString::Format(wxT("%d bytes range"), (((pred & 0x02) >> 1) + 1) * 2), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + subcurrid = m_tree->AppendItem(currid, + pred & 0x01 ? wxT("Errors/erasures in codestream") : wxT("Error free codestream"), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + subcurrid = m_tree->AppendItem(currid, + wxString::Format(wxT("Residual corruption level: %d"), (pred & 0x38) >> 3), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + } + break; + + ///////// + // ESD // + ///////// + case ESD_VAL: + { + unsigned short int cesd; + if (csiz < 257) { + if (m_file->Read(onebyte, 1) != 1) + break; + cesd = onebyte[0]; + } else { + if (m_file->Read(twobytes, 2) != 2) + break; + cesd = STREAM_TO_UINT16(twobytes, 0); + } + + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char pesd = onebyte[0]; + + image = m_tree->TreeCtrlIcon_File; + imageSel = image + 1; + + wxTreeItemId subcurrid = m_tree->AppendItem(currid, + pesd & 0x01 ? wxT("Comp. average") : wxString::Format(wxT("Comp. no. %d"), cesd), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + wxString meth[] = { + wxT("Relative error sensitivity"), + wxT("MSE"), + wxT("MSE reduction"), + wxT("PSNR"), + wxT("PSNR increase"), + wxT("MAXERR (absolute peak error)"), + wxT("TSE (total squared error)"), + wxT("Reserved") + }; + + subcurrid = m_tree->AppendItem(currid, + meth[(pesd & 0x38) >> 3], + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + wxString address[] = { + wxT("Packet addressing"), + wxT("Byte-range addressing"), + wxT("Packet-range addressing"), + wxT("Reserved") + }; + + subcurrid = m_tree->AppendItem(currid, + address[(pesd & 0xC0) >> 6], + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + subcurrid = m_tree->AppendItem(currid, + wxString::Format(wxT("%d bytes/value, %d bytes range"), ((pesd & 0x04) >> 2) + 1, (((pesd & 0x02) >> 1) + 1) * 2), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + } + break; + + ///////// + // EPC // + ///////// + case EPC_VAL: + { + if (m_file->Read(twobytes, 2) != 2) + break; + unsigned short int pcrc = STREAM_TO_UINT16(twobytes, 0); + + if (m_file->Read(fourbytes, 4) != 4) + break; + unsigned long int dl = STREAM_TO_UINT32(fourbytes, 0); + + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char pepc = onebyte[0]; + + image = m_tree->TreeCtrlIcon_File; + imageSel = image + 1; + + wxTreeItemId subcurrid = m_tree->AppendItem(currid, + wxString::Format(wxT("CRC-16 = 0x%x"), pcrc), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + subcurrid = m_tree->AppendItem(currid, + wxString::Format(wxT("Tot. length = %d"), dl), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + subcurrid = m_tree->AppendItem(currid, + wxString::Format(wxT("%s%s%s%s"), + pepc & 0x10 ? wxT("ESD, ") : wxT(""), + pepc & 0x20 ? wxT("RED, ") : wxT(""), + pepc & 0x40 ? wxT("EPB, ") : wxT(""), + pepc & 0x80 ? wxT("Info") : wxT("") + ), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + } + break; + + ///////// + // EPB // + ///////// + case EPB_VAL: + { + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char depb = onebyte[0]; + + if (m_file->Read(fourbytes, 4) != 4) + break; + unsigned long int ldpepb = STREAM_TO_UINT32(fourbytes, 0); + + if (m_file->Read(fourbytes, 4) != 4) + break; + unsigned long int pepb = STREAM_TO_UINT32(fourbytes, 0); + + image = m_tree->TreeCtrlIcon_File; + imageSel = image + 1; + + wxTreeItemId subcurrid = m_tree->AppendItem(currid, + wxString::Format(wxT("No. %d, %slatest, %spacked"), + depb & 0x3F, + depb & 0x40 ? wxT("") : wxT("not "), + depb & 0x80 ? wxT("") : wxT("un")), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + subcurrid = m_tree->AppendItem(currid, + wxString::Format(wxT("%d bytes protected"), ldpepb), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + if (pepb == 0x00000000) + + subcurrid = m_tree->AppendItem(currid, + wxT("Predefined codes"), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + else if ((pepb >= 0x10000000) && (pepb <= 0x1FFFFFFF)) { + + wxString text = wxT("CRC code"); + if (pepb == 0x10000000) + text << wxT(", CCITT (X25) 16 bits"); + else if (pepb == 0x10000001) + text << wxT(", Ethernet 32 bits"); + else + text << wxT(", JPWL RA"); + subcurrid = m_tree->AppendItem(currid, + text, + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + } else if ((pepb >= 0x20000000) && (pepb <= 0x2FFFFFFF)) { + + wxString text; + subcurrid = m_tree->AppendItem(currid, + wxString::Format(wxT("RS code, RS(%d, %d)"), + (pepb & 0x0000FF00) >> 8, + (pepb & 0x000000FF)), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + } else if ((pepb >= 0x30000000) && (pepb <= 0x3FFFFFFE)) + + subcurrid = m_tree->AppendItem(currid, + wxT("JPWL RA"), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + else if (pepb == 0xFFFFFFFF) + + subcurrid = m_tree->AppendItem(currid, + wxT("No method"), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + } + break; +#endif // USE_JPWL + +#ifdef USE_JPSEC + case SEC_VAL: + { + + } + break; +#endif // USE_JPSEC + + ///////// + // SIZ // + ///////// + case SIZ_VAL: + { + int c; + + if (m_file->Read(twobytes, 2) != 2) + break; + unsigned short int rsiz = STREAM_TO_UINT16(twobytes, 0); + + if (m_file->Read(fourbytes, 4) != 4) + break; + unsigned long int xsiz = STREAM_TO_UINT32(fourbytes, 0); + + if (m_file->Read(fourbytes, 4) != 4) + break; + unsigned long int ysiz = STREAM_TO_UINT32(fourbytes, 0); + + if (m_file->Read(fourbytes, 4) != 4) + break; + unsigned long int xosiz = STREAM_TO_UINT32(fourbytes, 0); + + if (m_file->Read(fourbytes, 4) != 4) + break; + unsigned long int yosiz = STREAM_TO_UINT32(fourbytes, 0); + + if (m_file->Read(fourbytes, 4) != 4) + break; + unsigned long int xtsiz = STREAM_TO_UINT32(fourbytes, 0); + this->m_tree->m_childframe->m_twidth = xtsiz; + + if (m_file->Read(fourbytes, 4) != 4) + break; + unsigned long int ytsiz = STREAM_TO_UINT32(fourbytes, 0); + this->m_tree->m_childframe->m_theight = ytsiz; + + if (m_file->Read(fourbytes, 4) != 4) + break; + unsigned long int xtosiz = STREAM_TO_UINT32(fourbytes, 0); + this->m_tree->m_childframe->m_tx = xtosiz; + + if (m_file->Read(fourbytes, 4) != 4) + break; + unsigned long int ytosiz = STREAM_TO_UINT32(fourbytes, 0); + this->m_tree->m_childframe->m_ty = ytosiz; + + if (m_file->Read(twobytes, 2) != 2) + break; + csiz = STREAM_TO_UINT16(twobytes, 0); + + bool equaldepth = true, equalsize = true; + unsigned char *ssiz = new unsigned char(csiz); + unsigned char *xrsiz = new unsigned char(csiz); + unsigned char *yrsiz = new unsigned char(csiz); + + for (c = 0; c < csiz; c++) { + + if (m_file->Read(&ssiz[c], 1) != 1) + break; + + if (c > 0) + equaldepth = equaldepth && (ssiz[c] == ssiz[c - 1]); + + if (m_file->Read(&xrsiz[c], 1) != 1) + break; + + if (m_file->Read(&yrsiz[c], 1) != 1) + break; + + if (c > 0) + equalsize = equalsize && (xrsiz[c] == xrsiz[c - 1]) && (yrsiz[c] == yrsiz[c - 1]) ; + + } + + if (equaldepth && equalsize) + wxTreeItemId subcurrid3 = m_tree->AppendItem(currid, + wxString::Format(wxT("I: %dx%d (%d, %d), %d c., %d%s bpp"), + xsiz, ysiz, + xosiz, yosiz, + csiz, ((ssiz[0] & 0x7F) + 1), + (ssiz[0] & 0x80) ? wxT("s") : wxT("u")), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + else + wxTreeItemId subcurrid3 = m_tree->AppendItem(currid, + wxString::Format(wxT("I: %dx%d (%d, %d), %d c."), + xsiz, ysiz, + xosiz, yosiz, + csiz), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + wxTreeItemId subcurrid3 = m_tree->AppendItem(currid, + wxString::Format(wxT("T: %dx%d (%d, %d)"), + xtsiz, ytsiz, + xtosiz, ytosiz), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + image = m_tree->TreeCtrlIcon_Folder; + imageSel = image + 1; + + wxTreeItemId subcurrid4 = m_tree->AppendItem(currid, + wxT("Components"), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + image = m_tree->TreeCtrlIcon_File; + imageSel = image + 1; + + for (c = 0; c < csiz; c++) { + + wxTreeItemId subcurrid5 = m_tree->AppendItem(subcurrid4, + wxString::Format(wxT("#%d: %dx%d, %d%s bpp"), + c, + xsiz/xrsiz[c], ysiz/yrsiz[c], + ((ssiz[c] & 0x7F) + 1), + (ssiz[c] & 0x80) ? wxT("s") : wxT("u")), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + } + + }; + break; + + ///////// + // SOT // + ///////// + case SOT_VAL: + { + if (m_file->Read(twobytes, 2) != 2) + break; + unsigned short int isot = STREAM_TO_UINT16(twobytes, 0); + + if (m_file->Read(fourbytes, 4) != 4) + break; + unsigned long int psot = STREAM_TO_UINT32(fourbytes, 0); + + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char tpsot = onebyte[0]; + + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char tnsot = onebyte[0]; + + wxTreeItemId subcurrid3 = m_tree->AppendItem(currid, + wxString::Format(wxT("tile %d, psot = %d, part %d of %d"), isot, psot, tpsot, tnsot), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + lastPsot = psot; + lastsotpos = offset; + inside_sod = 0; + }; + break; + + ///////// + // COC // + ///////// + case COC_VAL: + { + unsigned short int ccoc; + if (csiz < 257) { + if (m_file->Read(onebyte, 1) != 1) + break; + ccoc = onebyte[0]; + } else { + if (m_file->Read(twobytes, 2) != 2) + break; + ccoc = STREAM_TO_UINT16(twobytes, 0); + } + + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char scoc = onebyte[0]; + + wxTreeItemId subcurrid = m_tree->AppendItem(currid, + wxString::Format(wxT("Comp. no. %d"), ccoc), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + wxString text; + if (scoc & 0x01) + text << wxT("Partitioned entropy coder"); + else + text << wxT("Unpartitioned entropy coder"); + + subcurrid = m_tree->AppendItem(currid, + text, + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char decomplevs = onebyte[0]; + + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char cbswidth = onebyte[0]; + + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char cbsheight = onebyte[0]; + + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char cbstyle = onebyte[0]; + + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char transform = onebyte[0]; + + subcurrid = m_tree->AppendItem(currid, + wxString::Format(wxT("%d levels (%d resolutions)"), decomplevs, decomplevs + 1), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + if (transform & 0x01) + text = wxT("5-3 reversible wavelet"); + else + text = wxT("9-7 irreversible wavelet"); + subcurrid = m_tree->AppendItem(currid, + text, + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + subcurrid = m_tree->AppendItem(currid, + wxString::Format(wxT("Code-blocks: %dx%d"), 1 << ((cbswidth & 0x0F) + 2), 1 << ((cbsheight & 0x0F) + 2)), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + image = m_tree->TreeCtrlIcon_Folder; + imageSel = image + 1; + + wxTreeItemId subcurrid3 = m_tree->AppendItem(currid, + wxT("Coding styles"), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + image = m_tree->TreeCtrlIcon_File; + imageSel = image + 1; + + if (cbstyle & 0x01) + text = wxT("Selective arithmetic coding bypass"); + else + text = wxT("No selective arithmetic coding bypass"); + wxTreeItemId subcurrid4 = m_tree->AppendItem(subcurrid3, + text, + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + if (cbstyle & 0x02) + text = wxT("Reset context probabilities on coding pass boundaries"); + else + text = wxT("No reset of context probabilities on coding pass boundaries"); + subcurrid4 = m_tree->AppendItem(subcurrid3, + text, + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + if (cbstyle & 0x04) + text = wxT("Termination on each coding passs"); + else + text = wxT("No termination on each coding pass"); + subcurrid4 = m_tree->AppendItem(subcurrid3, + text, + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + if (cbstyle & 0x08) + text = wxT("Vertically stripe causal context"); + else + text = wxT("No vertically stripe causal context"); + subcurrid4 = m_tree->AppendItem(subcurrid3, + text, + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + if (cbstyle & 0x10) + text = wxT("Predictable termination"); + else + text = wxT("No predictable termination"); + subcurrid4 = m_tree->AppendItem(subcurrid3, + text, + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + if (cbstyle & 0x20) + text = wxT("Segmentation symbols are used"); + else + text = wxT("No segmentation symbols are used"); + subcurrid4 = m_tree->AppendItem(subcurrid3, + text, + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + } + break; + + ///////// + // COD // + ///////// + case COD_VAL: + { + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char scod = onebyte[0]; + + wxString text; + + if (scod & 0x01) + text << wxT("Partitioned entropy coder"); + else + text << wxT("Unpartitioned entropy coder"); + + wxTreeItemId subcurrid3 = m_tree->AppendItem(currid, + text, + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + text = wxT(""); + if (scod & 0x02) + text << wxT("Possible SOPs"); + else + text << wxT("No SOPs"); + + if (scod & 0x04) + text << wxT(", possible EPHs"); + else + text << wxT(", no EPHs"); + + subcurrid3 = m_tree->AppendItem(currid, + text, + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char progord = onebyte[0]; + + if (m_file->Read(twobytes, 2) != 2) + break; + unsigned short int numlayers = STREAM_TO_UINT16(twobytes, 0); + + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char mctransform = onebyte[0]; + + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char decomplevs = onebyte[0]; + + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char cbswidth = onebyte[0]; + + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char cbsheight = onebyte[0]; + + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char cbstyle = onebyte[0]; + + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char transform = onebyte[0]; + + subcurrid3 = m_tree->AppendItem(currid, + wxString::Format(wxT("%d levels (%d resolutions)"), decomplevs, decomplevs + 1), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + text = wxT(""); + switch (progord) { + case (0): + text << wxT("LRCP"); + break; + case (1): + text << wxT("RLCP"); + break; + case (2): + text << wxT("LRCP"); + break; + case (3): + text << wxT("RPCL"); + break; + case (4): + text << wxT("CPRL"); + break; + default: + text << wxT("unknown progression"); + break; + } + text << wxString::Format(wxT(", %d layers"), numlayers); + if (transform & 0x01) + text << wxT(", 5-3 rev."); + else + text << wxT(", 9-7 irr."); + subcurrid3 = m_tree->AppendItem(currid, + text, + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + subcurrid3 = m_tree->AppendItem(currid, + wxString::Format(wxT("Code-blocks: %dx%d"), 1 << ((cbswidth & 0x0F) + 2), 1 << ((cbsheight & 0x0F) + 2)), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + switch (mctransform) { + case (0): + { + text = wxT("No MCT"); + } + break; + case (1): + { + text = wxT("Reversible MCT on 0, 1, 2"); + } + break; + case (2): + { + text = wxT("Irreversible MCT on 0, 1, 2"); + } + break; + default: + { + text = wxT("Unknown"); + } + break; + }; + subcurrid3 = m_tree->AppendItem(currid, + text, + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + + image = m_tree->TreeCtrlIcon_Folder; + imageSel = image + 1; + + subcurrid3 = m_tree->AppendItem(currid, + wxT("Coding styles"), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + image = m_tree->TreeCtrlIcon_File; + imageSel = image + 1; + + if (cbstyle & 0x01) + text = wxT("Selective arithmetic coding bypass"); + else + text = wxT("No selective arithmetic coding bypass"); + wxTreeItemId subcurrid4 = m_tree->AppendItem(subcurrid3, + text, + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + if (cbstyle & 0x02) + text = wxT("Reset context probabilities on coding pass boundaries"); + else + text = wxT("No reset of context probabilities on coding pass boundaries"); + subcurrid4 = m_tree->AppendItem(subcurrid3, + text, + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + if (cbstyle & 0x04) + text = wxT("Termination on each coding passs"); + else + text = wxT("No termination on each coding pass"); + subcurrid4 = m_tree->AppendItem(subcurrid3, + text, + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + if (cbstyle & 0x08) + text = wxT("Vertically stripe causal context"); + else + text = wxT("No vertically stripe causal context"); + subcurrid4 = m_tree->AppendItem(subcurrid3, + text, + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + if (cbstyle & 0x10) + text = wxT("Predictable termination"); + else + text = wxT("No predictable termination"); + subcurrid4 = m_tree->AppendItem(subcurrid3, + text, + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + if (cbstyle & 0x20) + text = wxT("Segmentation symbols are used"); + else + text = wxT("No segmentation symbols are used"); + subcurrid4 = m_tree->AppendItem(subcurrid3, + text, + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + }; + break; + + ///////// + // QCC // + ///////// + case QCC_VAL: + { + unsigned short int cqcc; + if (csiz < 257) { + if (m_file->Read(onebyte, 1) != 1) + break; + cqcc = onebyte[0]; + } else { + if (m_file->Read(twobytes, 2) != 2) + break; + cqcc = STREAM_TO_UINT16(twobytes, 0); + } + + wxTreeItemId subcurrid = m_tree->AppendItem(currid, + wxString::Format(wxT("Comp. no. %d"), cqcc), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char sqcc = onebyte[0]; + + wxString text; + switch (sqcc & 0x1F) { + case (0): + text = wxT("No quantization"); + break; + case (1): + text = wxT("Scalar implicit"); + break; + case (2): + text = wxT("Scalar explicit"); + break; + default: + text = wxT("Unknown"); + break; + } + text << wxString::Format(wxT(", %d guard bits"), (sqcc & 0xE0) >> 5); + wxTreeItemId subcurrid3 = m_tree->AppendItem(currid, + text, + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + } + break; + + ///////// + // QCD // + ///////// + case QCD_VAL: + { + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char sqcd = onebyte[0]; + + wxString text; + switch (sqcd & 0x1F) { + case (0): + text = wxT("No quantization"); + break; + case (1): + text = wxT("Scalar implicit"); + break; + case (2): + text = wxT("Scalar explicit"); + break; + default: + text = wxT("Unknown"); + break; + } + text << wxString::Format(wxT(", %d guard bits"), (sqcd & 0xE0) >> 5); + wxTreeItemId subcurrid3 = m_tree->AppendItem(currid, + text, + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + }; + break; + + ///////// + // COM // + ///////// + case COM_VAL: + { + #define showlen 25 + char comment[showlen]; + wxString comments; + + if (m_file->Read(twobytes, 2) != 2) + break; + unsigned short int rcom = STREAM_TO_UINT16(twobytes, 0); + + wxString text; + if (rcom == 0) + text = wxT("Binary values"); + else if (rcom == 1) + text = wxT("ISO 8859-1 (latin-1) values"); + else if (rcom < 65535) + text = wxT("Reserved for registration"); + else + text = wxT("Reserved for extension"); + wxTreeItemId subcurrid3 = m_tree->AppendItem(currid, + text, + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + if (m_file->Read(comment, showlen) != showlen) + break; + comments = wxString::FromAscii(comment).Truncate(wxMin(showlen, currlen - 4)); + if ((currlen - 4) > showlen) + comments << wxT("..."); + subcurrid3 = m_tree->AppendItem(currid, + comments, + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + }; + break; + + ///////// + // TLM // + ///////// + case TLM_VAL: + { + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char ztlm = onebyte[0]; + + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char stlm = onebyte[0]; + + image = m_tree->TreeCtrlIcon_File; + imageSel = image + 1; + + wxTreeItemId subcurrid3 = m_tree->AppendItem(currid, + wxString::Format(wxT("TLM #%d"), ztlm), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + subcurrid3 = m_tree->AppendItem(currid, + wxString::Format(wxT("%d bits/index, %d bits/length"), + 8 * ((stlm & 0x30) >> 4), 16 + 16 * ((stlm & 0x40) >> 6)), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + int n, numparts; + + numparts = (currlen - 2) / ( ((stlm & 0x30) >> 4) + 2 + 2 * ((stlm & 0x40) >> 6)); + + image = m_tree->TreeCtrlIcon_Folder; + imageSel = image + 1; + + subcurrid3 = m_tree->AppendItem(currid, + wxT("Tile parts"), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + image = m_tree->TreeCtrlIcon_File; + imageSel = image + 1; + + for (n = 0; n < numparts; n++) { + + unsigned short int ttlm; + unsigned long int ptlm; + + switch (((stlm & 0x30) >> 4)) { + + case 0: + ttlm = 0; + break; + + case 1: + if (m_file->Read(onebyte, 1) != 1) + break; + ttlm = onebyte[0]; + break; + + case 2: + if (m_file->Read(twobytes, 2) != 2) + break; + ttlm = STREAM_TO_UINT16(twobytes, 0); + break; + + } + + switch (((stlm & 0x40) >> 6)) { + + case 0: + if (m_file->Read(twobytes, 2) != 2) + break; + ptlm = STREAM_TO_UINT16(twobytes, 0); + break; + + case 1: + if (m_file->Read(fourbytes, 4) != 4) + break; + ptlm = STREAM_TO_UINT32(fourbytes, 0); + break; + + } + + wxTreeItemId subcurrid4 = m_tree->AppendItem(subcurrid3, + wxString::Format(wxT("Tile %d: %d bytes"), ttlm, ptlm), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + } + + } + break; + + ///////// + // POD // + ///////// + case POD_VAL: + { + int n, numchanges; + + if (csiz < 257) + numchanges = (currlen - 2) / 7; + else + numchanges = (currlen - 2) / 9; + + for (n = 0; n < numchanges; n++) { + + image = m_tree->TreeCtrlIcon_Folder; + imageSel = image + 1; + + wxTreeItemId subcurrid3 = m_tree->AppendItem(currid, + wxString::Format(wxT("Change #%d"), n), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char rspod = onebyte[0]; + + unsigned short int cspod; + if (csiz < 257) { + if (m_file->Read(onebyte, 1) != 1) + break; + cspod = onebyte[0]; + } else { + if (m_file->Read(twobytes, 2) != 2) + break; + cspod = STREAM_TO_UINT16(twobytes, 0); + } + + if (m_file->Read(twobytes, 2) != 2) + break; + unsigned short int lyepod = STREAM_TO_UINT16(twobytes, 0); + + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char repod = onebyte[0]; + + unsigned short int cepod; + if (csiz < 257) { + if (m_file->Read(onebyte, 1) != 1) + break; + cepod = onebyte[0]; + } else { + if (m_file->Read(twobytes, 2) != 2) + break; + cepod = STREAM_TO_UINT16(twobytes, 0); + } + + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char ppod = onebyte[0]; + + image = m_tree->TreeCtrlIcon_File; + imageSel = image + 1; + + wxTreeItemId subcurrid4 = m_tree->AppendItem(subcurrid3, + wxString::Format(wxT("%d <= Resolution < %d"), rspod, repod), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + subcurrid4 = m_tree->AppendItem(subcurrid3, + wxString::Format(wxT("%d <= Component < %d"), cspod, cepod), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + subcurrid4 = m_tree->AppendItem(subcurrid3, + wxString::Format(wxT("0 <= Layer < %d"), lyepod), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + wxString text = wxT(""); + switch (ppod) { + case (0): + text << wxT("LRCP"); + break; + case (1): + text << wxT("RLCP"); + break; + case (2): + text << wxT("LRCP"); + break; + case (3): + text << wxT("RPCL"); + break; + case (4): + text << wxT("CPRL"); + break; + default: + text << wxT("unknown progression"); + break; + } + subcurrid4 = m_tree->AppendItem(subcurrid3, + text, + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + } + + } + break; + + ///////// + // SOD // + ///////// + case SOD_VAL: + { + inside_sod = 1; + }; + break; + + default: + break; + + } + + // increment number of markers + if (nmarks++ >= maxmarks) { + WriteText(wxT("Maximum amount of markers exceeded")); + break; + } + + // advance position + OPJ_ADVANCE(currlen + 2); + } + + WriteText(wxT("Search finished")); +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/wxjp2parser.cpp b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/wxjp2parser.cpp new file mode 100644 index 0000000..182def8 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/OPJViewer/source/wxjp2parser.cpp @@ -0,0 +1,1116 @@ +/* + * Copyright (c) 2007, Digital Signal Processing Laboratory, Università degli studi di Perugia (UPG), Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "OPJViewer.h" + +/* defines */ +#define SHORT_DESCR_LEN 32 +#define LONG_DESCR_LEN 256 + +/* enumeration for file formats */ +#define J2FILENUM 4 +typedef enum { + + JP2_FILE, + J2K_FILE, + MJ2_FILE, + UNK_FILE + +} j2filetype; + +/* enumeration for the box types */ +#define j22boxNUM 23 +typedef enum { + + FILE_BOX, + JP_BOX, + FTYP_BOX, + JP2H_BOX, + IHDR_BOX, + COLR_BOX, + JP2C_BOX, + JP2I_BOX, + XML_BOX, + UUID_BOX, + UINF_BOX, + MOOV_BOX, + MVHD_BOX, + TRAK_BOX, + TKHD_BOX, + MDIA_BOX, + MDHD_BOX, + HDLR_BOX, + MINF_BOX, + VMHD_BOX, + STBL_BOX, + STSD_BOX, + STSZ_BOX, + MJP2_BOX, + MDAT_BOX, + ANY_BOX, + UNK_BOX + +} j22boxtype; + +/* the box structure itself */ +struct boxdef { + + char value[5]; /* hexadecimal value/string*/ + char name[SHORT_DESCR_LEN]; /* short description */ + char descr[LONG_DESCR_LEN]; /* long description */ + int sbox; /* is it a superbox? */ + int req[J2FILENUM]; /* mandatory box */ + j22boxtype ins; /* contained in box... */ + +}; + + +/* jp2 family box signatures */ +#define FILE_SIGN "" +#define JP_SIGN "jP\040\040" +#define FTYP_SIGN "ftyp" +#define JP2H_SIGN "jp2h" +#define IHDR_SIGN "ihdr" +#define COLR_SIGN "colr" +#define JP2C_SIGN "jp2c" +#define JP2I_SIGN "jp2i" +#define XML_SIGN "xml\040" +#define UUID_SIGN "uuid" +#define UINF_SIGN "uinf" +#define MOOV_SIGN "moov" +#define MVHD_SIGN "mvhd" +#define TRAK_SIGN "trak" +#define TKHD_SIGN "tkhd" +#define MDIA_SIGN "mdia" +#define MDHD_SIGN "mdhd" +#define HDLR_SIGN "hdlr" +#define MINF_SIGN "minf" +#define VMHD_SIGN "vmhd" +#define STBL_SIGN "stbl" +#define STSD_SIGN "stsd" +#define STSZ_SIGN "stsz" +#define MJP2_SIGN "mjp2" +#define MDAT_SIGN "mdat" +#define ANY_SIGN "" +#define UNK_SIGN "" + +/* the possible boxes */ +struct boxdef j22box[] = +{ +/* sign */ {FILE_SIGN, +/* short */ "placeholder for nothing", +/* long */ "Nothing to say", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ FILE_BOX}, + +/* sign */ {JP_SIGN, +/* short */ "JPEG 2000 Signature box", +/* long */ "This box uniquely identifies the file as being part of the JPEG 2000 family of files", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ FILE_BOX}, + +/* sign */ {FTYP_SIGN, +/* short */ "File Type box", +/* long */ "This box specifies file type, version and compatibility information, including specifying if this file " + "is a conforming JP2 file or if it can be read by a conforming JP2 reader", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ FILE_BOX}, + +/* sign */ {JP2H_SIGN, +/* short */ "JP2 Header box", +/* long */ "This box contains a series of boxes that contain header-type information about the file", +/* sbox */ 1, +/* req */ {1, 1, 1}, +/* ins */ FILE_BOX}, + +/* sign */ {IHDR_SIGN, +/* short */ "Image Header box", +/* long */ "This box specifies the size of the image and other related fields", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ JP2H_BOX}, + +/* sign */ {COLR_SIGN, +/* short */ "Colour Specification box", +/* long */ "This box specifies the colourspace of the image", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ JP2H_BOX}, + +/* sign */ {JP2C_SIGN, +/* short */ "Contiguous Codestream box", +/* long */ "This box contains the codestream as defined by Annex A", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ FILE_BOX}, + +/* sign */ {JP2I_SIGN, +/* short */ "Intellectual Property box", +/* long */ "This box contains intellectual property information about the image", +/* sbox */ 0, +/* req */ {0, 0, 0}, +/* ins */ FILE_BOX}, + +/* sign */ {XML_SIGN, +/* short */ "XML box", +/* long */ "This box provides a tool by which vendors can add XML formatted information to a JP2 file", +/* sbox */ 0, +/* req */ {0, 0, 0}, +/* ins */ FILE_BOX}, + +/* sign */ {UUID_SIGN, +/* short */ "UUID box", +/* long */ "This box provides a tool by which vendors can add additional information to a file " + "without risking conflict with other vendors", +/* sbox */ 0, +/* req */ {0, 0, 0}, +/* ins */ FILE_BOX}, + +/* sign */ {UINF_SIGN, +/* short */ "UUID Info box", +/* long */ "This box provides a tool by which a vendor may provide access to additional information associated with a UUID", +/* sbox */ 0, +/* req */ {0, 0, 0}, +/* ins */ FILE_BOX}, + +/* sign */ {MOOV_SIGN, +/* short */ "Movie box", +/* long */ "This box contains the media data. In video tracks, this box would contain JPEG2000 video frames", +/* sbox */ 1, +/* req */ {1, 1, 1}, +/* ins */ FILE_BOX}, + +/* sign */ {MVHD_SIGN, +/* short */ "Movie Header box", +/* long */ "This box defines overall information which is media-independent, and relevant to the entire presentation " + "considered as a whole", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ MOOV_BOX}, + +/* sign */ {TRAK_SIGN, +/* short */ "Track box", +/* long */ "This is a container box for a single track of a presentation. A presentation may consist of one or more tracks", +/* sbox */ 1, +/* req */ {1, 1, 1}, +/* ins */ MOOV_BOX}, + +/* sign */ {TKHD_SIGN, +/* short */ "Track Header box", +/* long */ "This box specifies the characteristics of a single track. Exactly one Track Header Box is contained in a track", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ TRAK_BOX}, + +/* sign */ {MDIA_SIGN, +/* short */ "Media box", +/* long */ "The media declaration container contains all the objects which declare information about the media data " + "within a track", +/* sbox */ 1, +/* req */ {1, 1, 1}, +/* ins */ TRAK_BOX}, + +/* sign */ {MDHD_SIGN, +/* short */ "Media Header box", +/* long */ "The media header declares overall information which is media-independent, and relevant to characteristics " + "of the media in a track", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ MDIA_BOX}, + +/* sign */ {HDLR_SIGN, +/* short */ "Handler Reference box", +/* long */ "This box within a Media Box declares the process by which the media-data in the track may be presented, " + "and thus, the nature of the media in a track", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ MDIA_BOX}, + +/* sign */ {MINF_SIGN, +/* short */ "Media Information box", +/* long */ "This box contains all the objects which declare characteristic information of the media in the track", +/* sbox */ 1, +/* req */ {1, 1, 1}, +/* ins */ MDIA_BOX}, + +/* sign */ {VMHD_SIGN, +/* short */ "Video Media Header box", +/* long */ "The video media header contains general presentation information, independent of the coding, for video media", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ MINF_BOX}, + +/* sign */ {STBL_SIGN, +/* short */ "Sample Table box", +/* long */ "The sample table contains all the time and data indexing of the media samples in a track", +/* sbox */ 1, +/* req */ {1, 1, 1}, +/* ins */ MINF_BOX}, + +/* sign */ {STSD_SIGN, +/* short */ "STSD Sample Description box", +/* long */ "The sample description table gives detailed information about the coding type used, and any initialization " + "information needed for that coding", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ MINF_BOX}, + +/* sign */ {STSZ_SIGN, +/* short */ "Sample Size box", +/* long */ "This box contains the sample count and a table giving the size of each sample", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ STBL_BOX}, + +/* sign */ {MJP2_SIGN, +/* short */ "MJP2 Sample Description box", +/* long */ "The MJP2 sample description table gives detailed information about the coding type used, and any initialization " + "information needed for that coding", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ MINF_BOX}, + +/* sign */ {MDAT_SIGN, +/* short */ "Media Data box", +/* long */ "The meta-data for a presentation is stored in the single Movie Box which occurs at the top-level of a file", +/* sbox */ 1, +/* req */ {1, 1, 1}, +/* ins */ FILE_BOX}, + +/* sign */ {ANY_SIGN, +/* short */ "Any box", +/* long */ "All the existing boxes", +/* sbox */ 0, +/* req */ {0, 0, 0}, +/* ins */ FILE_BOX}, + +/* sign */ {UNK_SIGN, +/* short */ "Unknown Type box", +/* long */ "The signature is not recognised to be that of an existing box", +/* sbox */ 0, +/* req */ {0, 0, 0}, +/* ins */ ANY_BOX} + +}; + + +/* macro functions */ +/* From little endian to big endian, 2 and 4 bytes */ +#define BYTE_SWAP2(X) ((X & 0x00FF) << 8) | ((X & 0xFF00) >> 8) +#define BYTE_SWAP4(X) ((X & 0x000000FF) << 24) | ((X & 0x0000FF00) << 8) | ((X & 0x00FF0000) >> 8) | ((X & 0xFF000000) >> 24) + +#ifdef __WXGTK__ +#define BYTE_SWAP8(X) ((X & 0x00000000000000FFULL) << 56) | ((X & 0x000000000000FF00ULL) << 40) | \ + ((X & 0x0000000000FF0000ULL) << 24) | ((X & 0x00000000FF000000ULL) << 8) | \ + ((X & 0x000000FF00000000ULL) >> 8) | ((X & 0x0000FF0000000000ULL) >> 24) | \ + ((X & 0x00FF000000000000ULL) >> 40) | ((X & 0xFF00000000000000ULL) >> 56) +#else +#define BYTE_SWAP8(X) ((X & 0x00000000000000FF) << 56) | ((X & 0x000000000000FF00) << 40) | \ + ((X & 0x0000000000FF0000) << 24) | ((X & 0x00000000FF000000) << 8) | \ + ((X & 0x000000FF00000000) >> 8) | ((X & 0x0000FF0000000000) >> 24) | \ + ((X & 0x00FF000000000000) >> 40) | ((X & 0xFF00000000000000) >> 56) +#endif + +/* From codestream to int values */ +#define STREAM_TO_UINT32(C, P) (((unsigned long int) (C)[(P) + 0] << 24) + \ + ((unsigned long int) (C)[(P) + 1] << 16) + \ + ((unsigned long int) (C)[(P) + 2] << 8) + \ + ((unsigned long int) (C)[(P) + 3] << 0)) + +#define STREAM_TO_UINT16(C, P) (((unsigned long int) (C)[(P) + 0] << 8) + \ + ((unsigned long int) (C)[(P) + 1] << 0)) + +#define OPJREAD_LONG(F,L,N) { \ + if (F->Read(fourbytes, 4) < 4) { \ + wxLogMessage(wxT("Problem reading " N " from the file (file ended?)")); \ + return -1; \ + }; \ + L = STREAM_TO_UINT32(fourbytes, 0); \ + } + +/* handling functions */ +#define ITEM_PER_ROW 10 + +//#define indprint if (0) printf("%.*s", 2 * level + 9, indent), printf +char indent[] = " " + " " + " " + " "; + +void indprint(wxString printout, int level) +{ + wxLogMessage(/*wxString::Format(wxT("%.*s"), 2 * level + 9, indent) + */printout); +} + +/* Box handler function */ +int OPJParseThread::box_handler_function(int boxtype, wxFile *fileid, wxFileOffset filepoint, wxFileOffset filelimit, + wxTreeItemId parentid, int level, char *scansign, unsigned long int *scanpoint) +{ + switch ((j22boxtype) boxtype) { + + + /* JPEG 2000 Signature box */ + case (JP_BOX): { + + unsigned long int checkdata = 0; + fileid->Read(&checkdata, sizeof(unsigned long int)); + checkdata = BYTE_SWAP4(checkdata); + + // add info + wxTreeItemId currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Check data: %X -> %s"), checkdata, (checkdata == 0x0D0A870A) ? wxT("OK") : wxT("KO")), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + + }; + break; + + + /* JPEG 2000 codestream box */ + case (JP2C_BOX): { + + // add info + wxTreeItemId currid = m_tree->AppendItem(parentid, + wxString(wxT("Codestream")), + m_tree->TreeCtrlIcon_Folder, m_tree->TreeCtrlIcon_Folder + 1, + new OPJMarkerData(wxT("INFO-CSTREAM"), m_tree->m_fname.GetFullPath(), filepoint, filelimit) + ); + + m_tree->SetItemHasChildren(currid); + + // parse the file + //ParseJ2KFile(fileid, filepoint, filelimit, currid); + + }; + break; + + + + + + /* File Type box */ + case (FTYP_BOX): { + + char BR[4], CL[4]; + unsigned long int MinV, numCL, i; + fileid->Read(BR, sizeof(char) * 4); + fileid->Read(&MinV, sizeof(unsigned long int)); + MinV = BYTE_SWAP4(MinV); + numCL = (filelimit - fileid->Tell()) / 4; + + // add info + wxTreeItemId currid = m_tree->AppendItem(parentid, + wxT("Brand/Minor version: ") + + wxString::FromAscii(BR).Truncate(4) + + wxString::Format(wxT("/%d"), MinV), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Compatibility list")), + m_tree->TreeCtrlIcon_Folder, m_tree->TreeCtrlIcon_Folder + 1, + new OPJMarkerData(wxT("INFO")) + ); + + for (i = 0; i < numCL; i++) { + fileid->Read(CL, sizeof(char) * 4); + m_tree->AppendItem(currid, + wxString::FromAscii(CL).Truncate(4), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + }; + + }; + break; + + + + /* JP2 Header box */ + case (IHDR_BOX): { + + unsigned long int height, width; + unsigned short int nc; + unsigned char bpc, C, UnkC, IPR; + fileid->Read(&height, sizeof(unsigned long int)); + height = BYTE_SWAP4(height); + fileid->Read(&width, sizeof(unsigned long int)); + width = BYTE_SWAP4(width); + fileid->Read(&nc, sizeof(unsigned short int)); + nc = BYTE_SWAP2(nc); + fileid->Read(&bpc, sizeof(unsigned char)); + fileid->Read(&C, sizeof(unsigned char)); + fileid->Read(&UnkC, sizeof(unsigned char)); + fileid->Read(&IPR, sizeof(unsigned char)); + + // add info + wxTreeItemId currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Dimensions: %d x %d x %d @ %d bpc"), width, height, nc, bpc + 1), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Compression type: %d"), C), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Colourspace unknown: %d"), UnkC), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Intellectual Property Rights: %d"), IPR), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + + }; + break; + + + + /* Colour Specification box */ + case (COLR_BOX): { + + unsigned char METH, PREC, APPROX; + char methdescr[80], enumcsdescr[80]; + unsigned long int EnumCS; + fileid->Read(&METH, sizeof(unsigned char)); + switch (METH) { + case 1: + strcpy(methdescr, "Enumerated Colourspace"); + break; + case 2: + strcpy(methdescr, "Restricted ICC profile"); + break; + default: + strcpy(methdescr, "Unknown"); + break; + }; + fileid->Read(&PREC, sizeof(unsigned char)); + fileid->Read(&APPROX, sizeof(unsigned char)); + if (METH != 2) { + fileid->Read(&EnumCS, sizeof(unsigned long int)); + EnumCS = BYTE_SWAP4(EnumCS); + switch (EnumCS) { + case 16: + strcpy(enumcsdescr, "sRGB"); + break; + case 17: + strcpy(enumcsdescr, "greyscale"); + break; + case 18: + strcpy(enumcsdescr, "sYCC"); + break; + default: + strcpy(enumcsdescr, "Unknown"); + break; + }; + }; + + // add info + wxTreeItemId currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Specification method: %d ("), METH) + + wxString::FromAscii(methdescr) + + wxT(")"), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Precedence: %d"), PREC), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Colourspace approximation: %d"), APPROX), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + + if (METH != 2) + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Enumerated colourspace: %d ("), EnumCS) + + wxString::FromAscii(enumcsdescr) + + wxT(")"), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + + if (METH != 1) + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("ICC profile: there is one")), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + + + }; + break; + + + + + + + /* Movie Header Box */ + case (MVHD_BOX): { + + unsigned long int version, rate, matrix[9], next_track_ID; + unsigned short int volume; + fileid->Read(&version, sizeof(unsigned long int)); + version = BYTE_SWAP4(version); + if (version == 0) { + unsigned long int creation_time, modification_time, timescale, duration; + fileid->Read(&creation_time, sizeof(unsigned long int)); + creation_time = BYTE_SWAP4(creation_time); + fileid->Read(&modification_time, sizeof(unsigned long int)); + modification_time = BYTE_SWAP4(modification_time); + fileid->Read(×cale, sizeof(unsigned long int)); + timescale = BYTE_SWAP4(timescale); + fileid->Read(&duration, sizeof(unsigned long int)); + duration = BYTE_SWAP4(duration); + const long unix_time = creation_time - 2082844800L; + wxTreeItemId currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Creation time: %u (%.24s)"), creation_time, ctime(&unix_time)), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + const long unix_time1 = modification_time - 2082844800L; + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Modification time: %u (%.24s)"), modification_time, ctime(&unix_time1)), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Timescale: %u (%.6fs)"), timescale, 1.0 / (float) timescale), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Duration: %u (%.3fs)"), duration, (float) duration / (float) timescale), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + } else { + int8byte creation_time, modification_time, duration; + unsigned long int timescale; + fileid->Read(&creation_time, sizeof(int8byte)); + creation_time = BYTE_SWAP8(creation_time); + fileid->Read(&modification_time, sizeof(int8byte)); + modification_time = BYTE_SWAP8(modification_time); + fileid->Read(×cale, sizeof(unsigned long int)); + timescale = BYTE_SWAP4(timescale); + fileid->Read(&duration, sizeof(int8byte)); + duration = BYTE_SWAP8(duration); + wxTreeItemId currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Creation time: %u"), creation_time), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Modification time: %u"), modification_time), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Timescale: %u"), timescale), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Duration: %u"), duration), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + }; + fileid->Read(&rate, sizeof(unsigned long int)); + rate = BYTE_SWAP4(rate); + fileid->Read(&volume, sizeof(unsigned short int)); + volume = BYTE_SWAP2(volume); + fileid->Seek(6, wxFromCurrent); + fileid->Read(&matrix, sizeof(unsigned char) * 9); + fileid->Seek(4, wxFromCurrent); + fileid->Read(&next_track_ID, sizeof(unsigned long int)); + next_track_ID = BYTE_SWAP4(next_track_ID); + wxTreeItemId currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Rate: %d (%d.%d)"), rate, rate >> 16, rate & 0x0000FFFF), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Volume: %d (%d.%d)"), volume, volume >> 8, volume & 0x00FF), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Next track ID: %d"), next_track_ID), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + }; + break; + + + /* Sample Description box */ + case (STSD_BOX): { + + unsigned long int version, entry_count; + fileid->Read(&version, sizeof(unsigned long int)); + version = BYTE_SWAP4(version); + fileid->Read(&entry_count, sizeof(unsigned long int)); + entry_count = BYTE_SWAP4(entry_count); + wxTreeItemId currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Entry count: %d"), entry_count), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO"), m_tree->m_fname.GetFullPath(), filepoint, filelimit) + ); + jpeg2000parse(fileid, filepoint + 8, filelimit, parentid, level + 1, scansign, scanpoint); + }; + break; + + + /* Sample Size box */ + case (STSZ_BOX): { + + unsigned long int version, sample_size, sample_count, entry_size; + + fileid->Read(&version, sizeof(unsigned long int)); + version = BYTE_SWAP4(version); + + fileid->Read(&sample_size, sizeof(unsigned long int)); + sample_size = BYTE_SWAP4(sample_size); + + if (sample_size == 0) { + fileid->Read(&sample_count, sizeof(unsigned long int)); + sample_count = BYTE_SWAP4(sample_count); + + wxTreeItemId currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Sample count: %d"), sample_count), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO"), m_tree->m_fname.GetFullPath(), filepoint, filelimit) + ); + + currid = m_tree->AppendItem(parentid, + wxT("Entries size (bytes)"), + m_tree->TreeCtrlIcon_Folder, m_tree->TreeCtrlIcon_Folder + 1, + new OPJMarkerData(wxT("INFO"), m_tree->m_fname.GetFullPath(), filepoint, filelimit) + ); + + wxString text; + for (unsigned int s = 0; s < sample_count; s++) { + fileid->Read(&entry_size, sizeof(unsigned long int)); + entry_size = BYTE_SWAP4(entry_size); + + text << wxString::Format(wxT("%d, "), entry_size); + + if (((s % 10) == (ITEM_PER_ROW - 1)) || (s == (sample_count - 1))) { + m_tree->AppendItem(currid, + text, + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO"), m_tree->m_fname.GetFullPath(), filepoint, filelimit) + ); + text = wxT(""); + } + + } + + } + + }; + break; + + + /* Video Media Header box */ + case (VMHD_BOX): { + + unsigned long int version; + unsigned short int graphicsmode, opcolor[3]; + char graphicsdescr[100]; + + fileid->Read(&version, sizeof(unsigned long int)); + version = BYTE_SWAP4(version); + + fileid->Read(&graphicsmode, sizeof(unsigned short int)); + graphicsmode = BYTE_SWAP2(graphicsmode); + switch (graphicsmode) { + case (0x00): + strcpy(graphicsdescr, "copy"); + break; + case (0x24): + strcpy(graphicsdescr, "transparent"); + break; + case (0x0100): + strcpy(graphicsdescr, "alpha"); + break; + case (0x0101): + strcpy(graphicsdescr, "whitealpha"); + break; + case (0x0102): + strcpy(graphicsdescr, "blackalpha"); + break; + default: + strcpy(graphicsdescr, "unknown"); + break; + }; + + fileid->Read(opcolor, 3 * sizeof(unsigned short int)); + opcolor[0] = BYTE_SWAP2(opcolor[0]); + opcolor[1] = BYTE_SWAP2(opcolor[1]); + opcolor[2] = BYTE_SWAP2(opcolor[2]); + + wxTreeItemId currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Composition mode: %d (")) + + wxString::FromAscii(graphicsdescr) + + wxT(")"), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO"), m_tree->m_fname.GetFullPath(), filepoint, filelimit) + ); + + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("OP color: %d %d %d"), opcolor[0], opcolor[1], opcolor[2]), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO"), m_tree->m_fname.GetFullPath(), filepoint, filelimit) + ); + }; + break; + + + + /* MJP2 Sample Description box */ + case (MJP2_BOX): { + + unsigned short int height, width, depth; + unsigned long int horizresolution, vertresolution; + char compressor_name[32]; + fileid->Seek(24, wxFromCurrent); + fileid->Read(&width, sizeof(unsigned short int)); + width = BYTE_SWAP2(width); + fileid->Read(&height, sizeof(unsigned short int)); + height = BYTE_SWAP2(height); + fileid->Read(&horizresolution, sizeof(unsigned long int)); + horizresolution = BYTE_SWAP4(horizresolution); + fileid->Read(&vertresolution, sizeof(unsigned long int)); + vertresolution = BYTE_SWAP4(vertresolution); + fileid->Seek(6, wxFromCurrent); + fileid->Read(compressor_name, sizeof(char) * 32); + fileid->Read(&depth, sizeof(unsigned short int)); + depth = BYTE_SWAP2(depth); + wxTreeItemId currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Dimensions: %d x %d @ %d bpp"), width, height, depth), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO"), m_tree->m_fname.GetFullPath(), filepoint, filelimit) + ); + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Resolution: %d.%d x %d.%d"), horizresolution >> 16, horizresolution & 0x0000FFFF, + vertresolution >> 16, vertresolution & 0x0000FFFF), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Compressor: %.32s"), compressor_name), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + jpeg2000parse(fileid, filepoint + 78, filelimit, parentid, level + 1, scansign, scanpoint); + + }; + break; + + /* Media Header box */ + case (MDHD_BOX): { + unsigned long int version; + unsigned short int language; + fileid->Read(&version, sizeof(unsigned long int)); + version = BYTE_SWAP4(version); + if (version == 0) { + unsigned long int creation_time, modification_time, timescale, duration; + fileid->Read(&creation_time, sizeof(unsigned long int)); + creation_time = BYTE_SWAP4(creation_time); + fileid->Read(&modification_time, sizeof(unsigned long int)); + modification_time = BYTE_SWAP4(modification_time); + fileid->Read(×cale, sizeof(unsigned long int)); + timescale = BYTE_SWAP4(timescale); + fileid->Read(&duration, sizeof(unsigned long int)); + duration = BYTE_SWAP4(duration); + const long unix_time = creation_time - 2082844800L; + wxTreeItemId currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Creation time: %u (%.24s)"), creation_time, ctime(&unix_time)), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + const long unix_time1 = modification_time - 2082844800L; + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Modification time: %u (%.24s)"), modification_time, ctime(&unix_time1)), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Timescale: %u (%.6fs)"), timescale, 1.0 / (float) timescale), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Duration: %u (%.3fs)"), duration, (float) duration / (float) timescale), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + } else { + int8byte creation_time, modification_time, duration; + unsigned long int timescale; + fileid->Read(&creation_time, sizeof(int8byte)); + creation_time = BYTE_SWAP8(creation_time); + fileid->Read(&modification_time, sizeof(int8byte)); + modification_time = BYTE_SWAP8(modification_time); + fileid->Read(×cale, sizeof(unsigned long int)); + timescale = BYTE_SWAP4(timescale); + fileid->Read(&duration, sizeof(int8byte)); + duration = BYTE_SWAP8(duration); + wxTreeItemId currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Creation time: %u"), creation_time), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Modification time: %u"), modification_time), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Timescale: %u"), timescale), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Duration: %u"), duration), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + } + fileid->Read(&language, sizeof(unsigned short int)); + + wxTreeItemId currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Language: %d (%c%c%c)"), language & 0xEFFF, + 0x60 + (char) ((language >> 10) & 0x001F), 0x60 + (char) ((language >> 5) & 0x001F), 0x60 + (char) ((language >> 0) & 0x001F)), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + }; + break; + + /* Media Handler box */ + case (HDLR_BOX): { + unsigned long int version, predefined, temp[3]; + char handler[4], name[256]; + int namelen = wxMin(256, (filelimit - filepoint - 24)); + fileid->Read(&version, sizeof(unsigned long int)); + version = BYTE_SWAP4(version); + fileid->Read(&predefined, sizeof(unsigned long int)); + fileid->Read(handler, 4 * sizeof(char)); + fileid->Read(&temp, 3 * sizeof(unsigned long int)); + fileid->Read(name, namelen * sizeof(char)); + + wxTreeItemId currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Handler: %.4s"), handler), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Name: %.255s"), name), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + + } + break; + + /* not yet implemented */ + default: + break; + + }; + + return (0); +} + + +void OPJParseThread::ParseJP2File(wxFile *fileid, wxFileOffset filepoint, wxFileOffset filelimit, wxTreeItemId parentid) +{ + unsigned long int scanpoint; + + jpeg2000parse(fileid, filepoint, filelimit, parentid, 0, NULL, &scanpoint); +} + +/* the parsing function itself */ +/* + fileid = fid of the file to scan (you should open it by yourself) + filepoint = first byte where to start to scan from (usually 0) + filelimit = first byte where to stop to scan from (usually the file size) + level = set this to 0 + scansign = signature to scan for (NULL avoids search, returns " " if successful) + scanpoint = point where the scan signature lies +*/ +int OPJParseThread::jpeg2000parse(wxFile *fileid, wxFileOffset filepoint, wxFileOffset filelimit, + wxTreeItemId parentid, int level, char *scansign, unsigned long int *scanpoint) +{ + unsigned long int LBox = 0x00000000; + //int LBox_read; + char TBox[5] = "\0\0\0\0"; + //int TBox_read; + int8byte XLBox = 0x0000000000000000; + //int XLBox_read; + unsigned long int box_length = 0; + int last_box = 0, box_num = 0; + int box_type = ANY_BOX; + unsigned char /*onebyte[1], twobytes[2],*/ fourbytes[4]; + + /* cycle all over the file */ + box_num = 0; + last_box = 0; + while (!last_box) { + + /* do not exceed file limit */ + if (filepoint >= filelimit) + return (0); + + /* seek on file */ + if (fileid->Seek(filepoint, wxFromStart) == wxInvalidOffset) + return (-1); + + /* read the mandatory LBox, 4 bytes */ + if (fileid->Read(fourbytes, 4) < 4) { + WriteText(wxT("Problem reading LBox from the file (file ended?)")); + return -1; + }; + LBox = STREAM_TO_UINT32(fourbytes, 0); + + /* read the mandatory TBox, 4 bytes */ + if (fileid->Read(TBox, 4) < 4) { + WriteText(wxT("Problem reading TBox from the file (file ended?)")); + return -1; + }; + + /* look if scansign is got */ + if ((scansign != NULL) && (memcmp(TBox, scansign, 4) == 0)) { + memcpy(scansign, " ", 4); + *scanpoint = filepoint; + + /* hack/exploit */ + // stop as soon as you find the codebox + return (0); + + }; + + /* determine the box type */ + for (box_type = JP_BOX; box_type < UNK_BOX; box_type++) + if (memcmp(TBox, j22box[box_type].value, 4) == 0) + break; + + /* read the optional XLBox, 8 bytes */ + if (LBox == 1) { + + if (fileid->Read(&XLBox, 8) < 8) { + WriteText(wxT("Problem reading XLBox from the file (file ended?)")); + return -1; + }; + box_length = (unsigned long int) BYTE_SWAP8(XLBox); + + } else if (LBox == 0x00000000) { + + /* last box in file */ + last_box = 1; + box_length = filelimit - filepoint; + + } else + + box_length = LBox; + + /* show box info */ + + // append the marker + int image, imageSel; + image = m_tree->TreeCtrlIcon_Folder; + imageSel = image + 1; + wxTreeItemId currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("%03d: "), box_num) + + wxString::FromAscii(TBox) + + wxString::Format(wxT(" (0x%04X)"), + ((unsigned long int) TBox[3]) + ((unsigned long int) TBox[2] << 8) + + ((unsigned long int) TBox[1] << 16) + ((unsigned long int) TBox[0] << 24) + ), + image, imageSel, + new OPJMarkerData(wxT("BOX"), m_tree->m_fname.GetFullPath(), filepoint, filepoint + box_length) + ); + + // append some info + image = m_tree->TreeCtrlIcon_File; + imageSel = image + 1; + + // box name + wxTreeItemId subcurrid1 = m_tree->AppendItem(currid, + wxT("*** ") + wxString::FromAscii(j22box[box_type].name) + wxT(" ***"), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + m_tree->SetItemFont(subcurrid1, *wxITALIC_FONT); + + // position and length + wxTreeItemId subcurrid2 = m_tree->AppendItem(currid, + wxLongLong(filepoint).ToString() + wxT(" > ") + wxLongLong(filepoint + box_length - 1).ToString() + + wxT(", ") + wxString::Format(wxT("%d + 8 (%d)"), box_length, box_length + 8), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + /* go deep in the box */ + box_handler_function((int) box_type, fileid, (LBox == 1) ? (filepoint + 16) : (filepoint + 8), filepoint + box_length, + currid, level, scansign, scanpoint); + + /* if it's a superbox go inside it */ + if (j22box[box_type].sbox) + jpeg2000parse(fileid, (LBox == 1) ? (filepoint + 16) : (filepoint + 8), filepoint + box_length, + currid, level + 1, scansign, scanpoint); + + /* increment box number and filepoint*/ + box_num++; + filepoint += box_length; + + }; + + /* all good */ + return (0); +} + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/OPJ_Param_File_v0_1.txt b/gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/OPJ_Param_File_v0_1.txt new file mode 100644 index 0000000..c001d5f --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/OPJ_Param_File_v0_1.txt @@ -0,0 +1,100 @@ +#Version 0.1 - February 9th 2007 +#Usage: OPJ_Validate OpenJPEG_command_line +#Example: OPJ_Validate image_to_j2k.exe -i original/Bretagne1.ppm -o original/Bretagne1.j2k -r 200, 50, 10 +#Attention: don't forget the *.exe extension for the executable file, and check the paths + +image_to_j2k.exe -i original/Bretagne1.ppm -o temp/Bretagne1_0.j2k -r 200,50,10 +j2k_to_image.exe -i original/Bretagne1.j2k -o temp/Bretagne1.ppm +image_to_j2k.exe -i original/Bretagne2.ppm -o temp/Bretagne2_0.j2k -c [128,128],[128,128],[128,128] -r 100,20,2 -t 640,480 -b 32,32 +j2k_to_image.exe -i original/Bretagne2.j2k -o temp/Bretagne2.ppm -r 2 +image_to_j2k.exe -i original/Cevennes1.bmp -o temp/Cevennes1.j2k -r 10 +j2k_to_image.exe -i original/Cevennes1.j2k -o temp/Cevennes1.bmp -l 2 +image_to_j2k.exe -i original/Cevennes2.ppm -o temp/Cevennes2.jp2 -r 50 +j2k_to_image.exe -i original/Cevennes2.jp2 -o temp/Cevennes2.ppm +image_to_j2k.exe -i original/Rome.bmp -o temp/Rome.jp2 -q 30,35,50 -p LRCP -n 3 +j2k_to_image.exe -i original/Rome.jp2 -o temp/Rome.ppm +image_to_j2k.exe -i original/Bretagne1.ppm -o temp/Bretagne1_1.j2k -q 30,35,40 -n 2 +image_to_j2k.exe -i original/Bretagne1.ppm -o temp/Bretagne1_2.j2k -q 30,35,40 -b 16,16 -c [101,101] +image_to_j2k.exe -i original/Bretagne2.ppm -o temp/Bretagne2_1.j2k -t 127,127 -p PCRL +image_to_j2k.exe -i original/X_4_2K_24_185_CBR_WB_000.tif -o temp/X_4_2K_24_185_CBR_WB_000.j2k -cinema2K 24 +image_to_j2k.exe -i original/X_5_2K_24_235_CBR_STEM24_000.tif -o temp/X_5_2K_24_235_CBR_STEM24_000.j2k -cinema2K 48 +image_to_j2k.exe -i original/X_6_2K_24_FULL_CBR_CIRCLE_000.tif -o temp/X_6_2K_24_FULL_CBR_CIRCLE_000.j2k -cinema2K 24 +#à remettre +#image_to_j2k.exe -i original/X_16_4K_24_185_CBR_WB_000.tif -o temp/X_16_4K_24_185_CBR_WB_000.j2k -cinema4K +j2k_to_image.exe -i original/A_4_2K_24_185_CBR_WB_000.j2k -o temp/A_4_2K_24_185_CBR_WB_000.tif +j2k_to_image.exe -i original/B_5_2K_24_235_CBR_STEM24_000.j2k -o temp/B_5_2K_24_235_CBR_STEM24_000.tif +j2k_to_image.exe -i original/C_6_2K_24_FULL_CBR_CIRCLE_000.j2k -o temp/C_6_2K_24_FULL_CBR_CIRCLE_000.tif +#à remettre +#j2k_to_image.exe -i original/C_18_4K_24_FULL_CBR_CIRCLE_000.j2k -o temp/C_18_4K_24_FULL_CBR_CIRCLE_000.tif +j2k_to_image.exe -i original/p0_01.j2k -o temp/p0_01.tif +j2k_to_image.exe -i original/p0_02.j2k -o temp/p0_02.tif +j2k_to_image.exe -i original/p0_03.j2k -o temp/p0_03.tif +j2k_to_image.exe -i original/p0_04.j2k -o temp/p0_04.tif +#à remettre +#j2k_to_image.exe -i original/p0_07.j2k -o temp/p0_07.tif +j2k_to_image.exe -i original/p0_08.j2k -o temp/p0_08.tif +j2k_to_image.exe -i original/p0_09.j2k -o temp/p0_09.tif +j2k_to_image.exe -i original/p0_10.j2k -o temp/p0_10.tif +j2k_to_image.exe -i original/p0_11.j2k -o temp/p0_11.tif +j2k_to_image.exe -i original/p0_12.j2k -o temp/p0_12.tif +j2k_to_image.exe -i original/p0_14.j2k -o temp/p0_14.tif +j2k_to_image.exe -i original/p0_15.j2k -o temp/p0_15.tif +j2k_to_image.exe -i original/p0_16.j2k -o temp/p0_16.tif +j2k_to_image.exe -i original/p1_01.j2k -o temp/p1_01.tif +j2k_to_image.exe -i original/p1_02.j2k -o temp/p1_02.tif +j2k_to_image.exe -i original/p1_04.j2k -o temp/p1_04.tif +j2k_to_image.exe -i original/p1_05.j2k -o temp/p1_05.tif +j2k_to_image.exe -i original/p1_06.j2k -o temp/p1_06.tif +image_to_j2k.exe -i original/c0p0_01.pgx -o temp/c0p0_01.j2k +image_to_j2k.exe -i original/c0p0_02.pgx -o temp/c0p0_02.j2k +image_to_j2k.exe -i original/c0p0_03r0.pgx -o temp/c0p0_03r0.j2k +image_to_j2k.exe -i original/c0p0_03r1.pgx -o temp/c0p0_03r1.j2k +image_to_j2k.exe -i original/c0p0_04.pgx -o temp/c00_p04.j2k +image_to_j2k.exe -i original/c0p0_05.pgx -o temp/c0p0_05.j2k +image_to_j2k.exe -i original/c0p0_06.pgx -o temp/c0p0_06.j2k +image_to_j2k.exe -i original/c0p0_07.pgx -o temp/c0p0_07.j2k +image_to_j2k.exe -i original/c0p0_08.pgx -o temp/c0p0_08.j2k +image_to_j2k.exe -i original/c0p0_09.pgx -o temp/c0p0_09.j2k +image_to_j2k.exe -i original/c0p0_10.pgx -o temp/c0p0_10.j2k +image_to_j2k.exe -i original/c0p0_11.pgx -o temp/c0p0_11.j2k +image_to_j2k.exe -i original/c0p0_12.pgx -o temp/c0p0_12.j2k +image_to_j2k.exe -i original/c0p0_13.pgx -o temp/c0p0_13.j2k +image_to_j2k.exe -i original/c0p0_14.pgx -o temp/c0p0_14.j2k +image_to_j2k.exe -i original/c0p0_15r0.pgx -o temp/c0p0_15r0.j2k +image_to_j2k.exe -i original/c0p0_15r1.pgx -o temp/c0p0_15r1.j2k +image_to_j2k.exe -i original/c0p0_16.pgx -o temp/c0p0_16.j2k +image_to_j2k.exe -i original/c0p1_04r0.pgx -o temp/c0p1_04r0.j2k +image_to_j2k.exe -i original/c0p1_05.pgx -o temp/c0p1_05.j2k +image_to_j2k.exe -i original/c1p0_01_0.pgx -o temp/c1p0_01_0.j2k +image_to_j2k.exe -i original/c1p0_02_0.pgx -o temp/c1p0_02_0.j2k +image_to_j2k.exe -i original/c1p0_03_0.pgx -o temp/c1p0_03_0.j2k +image_to_j2k.exe -i original/c1p0_04_0.pgx -o temp/c1p0_04_0.j2k +image_to_j2k.exe -i original/c1p0_05_0.pgx -o temp/c1p0_05_0.j2k +image_to_j2k.exe -i original/c1p0_06_0.pgx -o temp/c1p0_06_0.j2k +image_to_j2k.exe -i original/c1p0_07_0.pgx -o temp/c1p0_07_0.j2k +image_to_j2k.exe -i original/c1p0_08_0.pgx -o temp/c1p0_08_0.j2k +image_to_j2k.exe -i original/c1p0_09_0.pgx -o temp/c1p0_09_0.j2k +image_to_j2k.exe -i original/c1p0_10_0.pgx -o temp/c1p0_10_0.j2k +image_to_j2k.exe -i original/c1p0_11_0.pgx -o temp/c1p0_11_0.j2k +image_to_j2k.exe -i original/c1p0_12_0.pgx -o temp/c1p0_12_0.j2k +image_to_j2k.exe -i original/c1p0_13_0.pgx -o temp/c1p0_13_0.j2k +image_to_j2k.exe -i original/c1p0_14_0.pgx -o temp/c1p0_14_0.j2k +image_to_j2k.exe -i original/c1p0_15_0.pgx -o temp/c1p0_15_0.j2k +image_to_j2k.exe -i original/c1p0_16_0.pgx -o temp/c1p0_16_0.j2k +image_to_j2k.exe -i original/c1p1_02_0.pgx -o temp/c1p1_02_0.j2k +image_to_j2k.exe -i original/c1p1_05_0.pgx -o temp/c1p1_05_0.j2k +image_to_j2k.exe -i original/Bretagne2.ppm -o temp/Bretagne2_2.j2k -s 2,2 -SOP +image_to_j2k.exe -i original/Bretagne2.ppm -o temp/Bretagne2_3.j2k -EPH -M 38 +image_to_j2k.exe -i original/Bretagne2.ppm -o temp/Bretagne2_4.j2k -d 150,300 -r 800 +j2k_to_image.exe -i original/Bretagne1.j2k -o temp/Bretagne1.bmp +j2k_to_image.exe -i original/Bretagne1.j2k -o temp/Bretagne1r2.bmp -r 2 +j2k_to_image.exe -i original/Bretagne1.j2k -o temp/Bretagne1.tga +j2k_to_image.exe -i original/Bretagne1.j2k -o temp/Bretagne1r2.tga -r 2 +j2k_to_image.exe -i original/Bretagne1.j2k -o temp/Bretagne1.pnm +j2k_to_image.exe -i original/Bretagne1.j2k -o temp/Bretagne1r2.pnm -r 2 +j2k_to_image.exe -i original/Bretagne1.j2k -o temp/Bretagne1r2.ppm -r 2 +j2k_to_image.exe -i original/Bretagne1.j2k -o temp/Bretagne1.raw +j2k_to_image.exe -i original/Bretagne1.j2k -o temp/Bretagne1r2.raw -r 2 +j2k_to_image.exe -i original/Bretagne1.j2k -o temp/Bretagne1.tif +j2k_to_image.exe -i original/Bretagne1.j2k -o temp/Bretagne1r2.tif -r 2 +j2k_to_image.exe -i original/p0_03.j2k -o p0_03.pgx diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/OPJ_Validate.c b/gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/OPJ_Validate.c new file mode 100644 index 0000000..c685478 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/OPJ_Validate.c @@ -0,0 +1,244 @@ +/* +* Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium +* Copyright (c) 2002-2007, Professor Benoit Macq +* Copyright (c) 2003-2007, Francois-Olivier Devaux +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef _WIN32 +#include +#endif /* _WIN32 */ +#include +#include +#include "md5.h" + +#define OPJ_Bin_Dir "OPJ_Binaries" + +int doprocess(char programme[4096],char command_line[4096]) { + +#ifdef _WIN32 + + int exit=STILL_ACTIVE; + STARTUPINFO siStartupInfo; + PROCESS_INFORMATION piProcessInfo; + + memset(&siStartupInfo, 0, sizeof(siStartupInfo)); + memset(&piProcessInfo, 0, sizeof(piProcessInfo)); + siStartupInfo.cb = sizeof(siStartupInfo); + + if(CreateProcess(programme, // Application name + command_line, // Application arguments + 0, + 0, + FALSE, + CREATE_DEFAULT_ERROR_MODE, + 0, + 0, // Working directory + &siStartupInfo, + &piProcessInfo) == FALSE) + return 1; + + exit=STILL_ACTIVE; + while(exit==STILL_ACTIVE) { + Sleep(1000); + GetExitCodeProcess(piProcessInfo.hProcess,&exit); + } + + return 0; + +#else /* !_WIN32 */ + printf("\n%s\n", command_line); + system(command_line); + return 0; + +#endif /* _WIN32 */ + +} + +char MD5_process(char *input_filename, char *md5_filename) { + MD5_CTX mdContext; + int bytes; + unsigned char data[1024]; + FILE *input_file, *md5_file; + + input_file = fopen(input_filename, "rb"); + if (!input_file) { + printf("Error opening file %s\n", input_filename); + return 1; + } + + md5_file = fopen(md5_filename, "wb"); + if (!md5_file) { + printf("Error opening file %s\n", md5_filename); + return 1; + } + + MD5Init (&mdContext); + while ((bytes = fread (data, 1, 1024, input_file)) != 0) + MD5Update (&mdContext, data, bytes); + MD5Final (&mdContext); + + fwrite(mdContext.digest,16,1,md5_file); + + fclose(input_file); + fclose(md5_file); + + return 0; +} + +char fcompare(char *input_filename, char *output_filename) { + FILE *input_file, *output_file; + unsigned char input_buffer[17], output_buffer[17]; + char comparison; + + input_file = fopen(input_filename, "rb"); + if (!input_file) { + printf("Error opening file %s\n", input_filename); + return -1; + } + + output_file = fopen(output_filename, "rb"); + if (!output_file) { + printf("Error opening file %s\n", output_filename); + return -1; + } + + fread(input_buffer,16,1,input_file); + fread(output_buffer,16,1,output_file); + fclose(input_file); + fclose(output_file); + input_buffer[16] = 0; + output_buffer[16] = 0; + + comparison = strcmp(input_buffer, output_buffer); + + if (comparison) + return 1; + return 0; +} + +int main(int argc, char* argv[]) { + FILE *param_file, *md5_file; + FILE *report_file; + char line[4096]; + char md5_filename[4096], tempmd5_filename[4096], temp[4096], report_filename[4096]; + char output_filename[4096]; + char input_cmdline[4096]; + char command_line[4096], exefile[4096]; + int task_counter = 0, word_counter; + char bin_dir[4096]; + unsigned int word_pointer; + char ch[4096]; + char comparison; + int num_failed = 0; + int num_inexistant = 0; + int num_passed = 0; + + if (argc != 3) { + printf("Error with command line. \nExpected: OPJ_Validate parameter_filename bin_directory\n Example: OPJ_Validate parameters_01.txt version1.1.a\n\n"); + return 1; + } + + param_file = fopen(argv[1],"rb"); + if (!param_file) { + printf("Error opening parameter file %s\n",argv[1]); + return 1; + } + + sprintf(bin_dir,"%s/%s",OPJ_Bin_Dir,argv[2]); + sprintf(tempmd5_filename,"temp/tempmd5.txt"); + sprintf(report_filename,"%s/report.txt",bin_dir); + report_file = fopen(report_filename, "wb"); + if (!report_file) { + printf("Unable to open report file %s", report_filename); + return 1; + } + + while (fgets(line, 4096, param_file) != NULL) { + + if (line[0] != '#' && line[0] != 0x0d) { // If not a comment line + sscanf(line, "%s", temp); + word_pointer = 0; + sprintf(input_cmdline,""); + sscanf(line+word_pointer,"%s",ch); + sprintf(exefile,"%s/%s",bin_dir,ch); + word_counter = 0; + while (sscanf(line+word_pointer,"%s",ch) > 0) { + if (word_counter == 4) + strcpy(output_filename, ch); + word_pointer += strlen(ch)+1; + sprintf(input_cmdline,"%s%s ",input_cmdline, ch); + word_counter++; + } + sprintf(md5_filename,"%s.md5",output_filename); + task_counter++; + sprintf(command_line,"%s/%s",bin_dir,input_cmdline); + printf("Task %d\nMD5 file: %s\nCommand line: \"%s\"\n",task_counter, md5_filename,command_line); + fprintf(report_file,"Task %d\n MD5 file: %s\n Command line: \"%s\"\n",task_counter, md5_filename,command_line); + + if (doprocess(exefile,command_line)) { + printf("Error executing: \"%s\" \n", command_line); + fprintf(report_file,"Task %d failed because command line is not valid.\n\n", task_counter); + } + else { + + // Check if MD5 reference exists + md5_file = fopen(md5_filename,"rb"); + if (md5_file) { + fclose(md5_file); + if (MD5_process(output_filename, tempmd5_filename)) + return 1; + + comparison = fcompare(tempmd5_filename, md5_filename); + if (comparison == -1) + return 1; + else if (comparison) { + printf("ERROR: %s and %s are different.\nThe codec seems to behave differently.\n\n", tempmd5_filename, md5_filename); + fprintf(report_file,"ERROR: %s and %s are different.\nThe codec seems to behave differently.\n\n", tempmd5_filename, md5_filename); + num_failed++; + } + else { + printf("%s and %s are the same.\nTask %d OK\n\n",tempmd5_filename, md5_filename, task_counter); + fprintf(report_file," %s and %s are the same.\nTask %d OK\n\n",tempmd5_filename, md5_filename, task_counter); + num_passed++; + } + remove(tempmd5_filename); + } + else { + if (MD5_process(output_filename, md5_filename)) + return 1; + printf("... MD5 of %s was inexistant. It has been created\n\n", output_filename); + fprintf(report_file,"MD5 of %s was inexistant. It has been created\n\n", output_filename); + num_inexistant++; + } + } + } + } + + printf("\nREPORT;\n%d tests num_passed\n%d tests num_failed\n%d MD5 were num_inexistant\n", num_passed, num_failed, num_inexistant); + fprintf(report_file,"\nREPORT;\n%d tests num_passed\n%d tests num_failed\n%d MD5 were num_inexistant\n", num_passed, num_failed, num_inexistant); + fclose(param_file); + fclose(report_file); + +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/OPJ_Validate.dsp b/gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/OPJ_Validate.dsp new file mode 100644 index 0000000..191b047 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/OPJ_Validate.dsp @@ -0,0 +1,108 @@ +# Microsoft Developer Studio Project File - Name="OPJ_Validate" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=OPJ_Validate - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "OPJ_Validate.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "OPJ_Validate.mak" CFG="OPJ_Validate - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "OPJ_Validate - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "OPJ_Validate - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "OPJ_Validate - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x80c /d "NDEBUG" +# ADD RSC /l 0x80c /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "OPJ_Validate - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /GZ /c +# ADD BASE RSC /l 0x80c /d "_DEBUG" +# ADD RSC /l 0x80c /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "OPJ_Validate - Win32 Release" +# Name "OPJ_Validate - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\md5.c +# End Source File +# Begin Source File + +SOURCE=.\OPJ_Validate.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\md5.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/OPJ_Validate.dsw b/gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/OPJ_Validate.dsw new file mode 100644 index 0000000..ca39384 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/OPJ_Validate.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "OPJ_Validate"=".\OPJ_Validate.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/OPJ_Validate_Candidate_vs_Ref.bat b/gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/OPJ_Validate_Candidate_vs_Ref.bat new file mode 100644 index 0000000..2f5e99e --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/OPJ_Validate_Candidate_vs_Ref.bat @@ -0,0 +1,8 @@ +cd temp +erase *.ppm +erase *.j2k +erase *.bmp +erase *.tif +erase *.jp2 +cd .. +OPJ_Validate.exe OPJ_Param_File_v0_1.txt testv2 diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/OPJ_Validate_Candidate_vs_Ref.sh b/gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/OPJ_Validate_Candidate_vs_Ref.sh new file mode 100644 index 0000000..edd3eaa --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/OPJ_Validate_Candidate_vs_Ref.sh @@ -0,0 +1,16 @@ +#!/bin/bash +cd temp +erase *.ppm +erase *.j2k +erase *.bmp +erase *.tif +erase *.jp2 +cd .. + +echo +echo "Type the name of the directory (inside OPJ_Binaries) " +echo "containing your executables to compared with reference, followed by [ENTER] (example: rev101):" +read compdir + +./OPJ_Validate linux_OPJ_Param_File_v0_1.txt $compdir +echo diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/OPJ_Validate_Create_Ref.bat b/gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/OPJ_Validate_Create_Ref.bat new file mode 100644 index 0000000..29c5da0 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/OPJ_Validate_Create_Ref.bat @@ -0,0 +1,4 @@ +cd temp +erase *.md5 +cd .. +OPJ_Validate.exe OPJ_Param_File_v0_1.txt rev490 diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/OPJ_Validate_Create_Ref.sh b/gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/OPJ_Validate_Create_Ref.sh new file mode 100644 index 0000000..e44e053 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/OPJ_Validate_Create_Ref.sh @@ -0,0 +1,13 @@ +#!/bin/bash +#Create Reference images and hash + +echo +echo "Type the name of the directory (inside OPJ_Binaries) " +echo "containing your reference executables, followed by [ENTER] (example: rev100):" +read refdir +cd temp +rm *.md5 +cd .. +./OPJ_Validate linux_OPJ_Param_File_v0_1.txt $refdir +echo + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/README.txt b/gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/README.txt new file mode 100644 index 0000000..c9fc79b --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/README.txt @@ -0,0 +1,46 @@ +Initialization +-------------- +Download the source images into the /original directory from http://www.openjpeg.org/OPJ_Validate_OriginalImages.7z + +Usage +----- +Usage: OPJ_Validate batch_text_file bin_directory +Example: OPJ_Validate OPJ_Param_File_v0_1.txt v1.1.a +where OPJ_Param_File_v0_1.txt is a file containing a list of compression and decompression parameters +and v1.1.a is a directory inside the directory OPJ_Binaries containing the openjpeg executables (j2k_to_image.exe and image_to_j2k.exe) + +Example with batch file: You consider revision 490 (/rev490) as stable, and would like to compare it a new version, revision 493 (rev493). + +Batch mode +---------- +1) Calculate the reference by running the "OPJ_Validate_Create_Ref rev490" file (.sh or .bat depending on your os) +2) Compare the candidate revision with ther reference by running the "OPJ_Validate_Candidate_vs_Ref rev493" file +3) The results of the comparison are given at the end of the processing. They are also available in the bin directory OPJ_Binaries/rev493/report.txt + +Manual mode +----------- +1) Put the j2k_to_image.exe and image_to_j2k.exe binaries of both revisions in the OPJ_Binaries directory (OPJ_Binaries/rev490 and OPJ_Binaries/rev493) +2) Start by initializing the validation with revision 490. + a) Modify OPJ_Validate_init.bat and set the last line to "OPJ_Validate.exe OPJ_Param_File_v0_1.txt rev490" + b) Execute OPJ_Validate_init.bat +3) Compare the reference files generated in the previous step with files generated with revision 493 + a) Modify OPJ_Validate_run.bat and set the last line to "OPJ_Validate.exe OPJ_Param_File_v0_1.txt rev493" + b) Execute OPJ_Validate_run.bat +4) Read the results in the binaries directory of revision 493 (OPJ_Binaries/rev493/report.txt) + Search for the word "ERROR:" in that file. + If this word is not present in the report, this means that both codecs of rev490 and rev493 gave the same results. + Otherwise, it means that for certain encoding/decoding parameters, the codecs behave differently. + + Example of error + Task 17 + MD5 file: temp/A_4_2K_24_185_CBR_WB_000.tif.md5 + Command line: "OPJ_Binaries/rev473/j2k_to_image.exe -i original/A_4_2K_24_185_CBR_WB_000.j2k -o temp/A_4_2K_24_185_CBR_WB_000.tif " + ERROR: temp/tempmd5.txt and temp/A_4_2K_24_185_CBR_WB_000.tif.md5 are different. + The codec seems to behave differently. + + This means that the rev490 and rev493 created two different versions of file A_4_2K_24_185_CBR_WB_000.tif with the command line given above. + An error might have been caused by switching to this new revision. + + Warning: Do not take the last line of the report.txt file into account ( Cool. All files passed the tests !) as it is a bug. Search for the word "ERROR:" to detect potential errors. +5) If no error is detected, you can commit the changes to the OpenJPEG repository + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/linux_OPJ_Param_File_v0_1.txt b/gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/linux_OPJ_Param_File_v0_1.txt new file mode 100644 index 0000000..034e4ca --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/linux_OPJ_Param_File_v0_1.txt @@ -0,0 +1,89 @@ +#OPJ Parameter file +#Version 0.1 - February 9th 2007 +#Usage: OPJ_Validate OpenJPEG_command_line +#Example: OPJ_Validate image_to_j2k.exe -i original/Bretagne1.ppm -o original/Bretagne1.j2k -r 200, 50, 10 +#Attention: don't forget the *.exe extension for the executable file, and check the paths +# +image_to_j2k -i original/Bretagne1.ppm -o temp/Bretagne1_0.j2k -r 200,50,10 +j2k_to_image -i original/Bretagne1.j2k -o temp/Bretagne1.ppm +image_to_j2k -i original/Bretagne2.ppm -o temp/Bretagne2_0.j2k -c [128,128],[128,128],[128,128] -r 100,20,2 -t 640,480 -b 32,32 +j2k_to_image -i original/Bretagne2.j2k -o temp/Bretagne2.ppm -r 2 +image_to_j2k -i original/Cevennes1.bmp -o temp/Cevennes1.j2k -r 10 +j2k_to_image -i original/Cevennes1.j2k -o temp/Cevennes1.bmp -l 2 +image_to_j2k -i original/Cevennes2.ppm -o temp/Cevennes2.jp2 -r 50 +j2k_to_image -i original/Cevennes2.jp2 -o temp/Cevennes2.ppm +image_to_j2k -i original/Rome.bmp -o temp/Rome.jp2 -q 30,35,50 -p LRCP -n 3 +j2k_to_image -i original/Rome.jp2 -o temp/Rome.ppm +image_to_j2k -i original/Bretagne1.ppm -o temp/Bretagne1_1.j2k -q 30,35,40 -n 2 +image_to_j2k -i original/Bretagne1.ppm -o temp/Bretagne1_2.j2k -q 30,35,40 -b 16,16 -c [101,101] +image_to_j2k -i original/Bretagne2.ppm -o temp/Bretagne2_1.j2k -t 127,127 -p PCRL +image_to_j2k -i original/X_4_2K_24_185_CBR_WB_000.tif -o temp/X_4_2K_24_185_CBR_WB_000.j2k -cinema2K 24 +image_to_j2k -i original/X_5_2K_24_235_CBR_STEM24_000.tif -o temp/X_5_2K_24_235_CBR_STEM24_000.j2k -cinema2K 48 +image_to_j2k -i original/X_6_2K_24_FULL_CBR_CIRCLE_000.tif -o temp/X_6_2K_24_FULL_CBR_CIRCLE_000.j2k -cinema2K 24 +#à remettre +#image_to_j2k -i original/X_16_4K_24_185_CBR_WB_000.tif -o temp/X_16_4K_24_185_CBR_WB_000.j2k -cinema4K +j2k_to_image -i original/A_4_2K_24_185_CBR_WB_000.j2k -o temp/A_4_2K_24_185_CBR_WB_000.tif +j2k_to_image -i original/B_5_2K_24_235_CBR_STEM24_000.j2k -o temp/B_5_2K_24_235_CBR_STEM24_000.tif +j2k_to_image -i original/C_6_2K_24_FULL_CBR_CIRCLE_000.j2k -o temp/C_6_2K_24_FULL_CBR_CIRCLE_000.tif +#à remettre +#j2k_to_image -i original/C_18_4K_24_FULL_CBR_CIRCLE_000.j2k -o temp/C_18_4K_24_FULL_CBR_CIRCLE_000.tif +j2k_to_image -i original/p0_01.j2k -o temp/p0_01.tif +j2k_to_image -i original/p0_02.j2k -o temp/p0_02.tif +j2k_to_image -i original/p0_03.j2k -o temp/p0_03.tif +j2k_to_image -i original/p0_04.j2k -o temp/p0_04.tif +#a remettre +#j2k_to_image -i original/p0_07.j2k -o temp/p0_07.tif +j2k_to_image -i original/p0_08.j2k -o temp/p0_08.tif +j2k_to_image -i original/p0_09.j2k -o temp/p0_09.tif +j2k_to_image -i original/p0_10.j2k -o temp/p0_10.tif +j2k_to_image -i original/p0_11.j2k -o temp/p0_11.tif +j2k_to_image -i original/p0_12.j2k -o temp/p0_12.tif +j2k_to_image -i original/p0_14.j2k -o temp/p0_14.tif +j2k_to_image -i original/p0_15.j2k -o temp/p0_15.tif +j2k_to_image -i original/p0_16.j2k -o temp/p0_16.tif +j2k_to_image -i original/p1_01.j2k -o temp/p1_01.tif +j2k_to_image -i original/p1_02.j2k -o temp/p1_02.tif +j2k_to_image -i original/p1_04.j2k -o temp/p1_04.tif +j2k_to_image -i original/p1_05.j2k -o temp/p1_05.tif +j2k_to_image -i original/p1_06.j2k -o temp/p1_06.tif +image_to_j2k -i original/c0p0_01.pgx -o temp/c0p0_01.j2k +image_to_j2k -i original/c0p0_02.pgx -o temp/c0p0_02.j2k +image_to_j2k -i original/c0p0_03r0.pgx -o temp/c0p0_03r0.j2k +image_to_j2k -i original/c0p0_03r1.pgx -o temp/c0p0_03r1.j2k +image_to_j2k -i original/c0p0_04.pgx -o temp/c00_p04.j2k +image_to_j2k -i original/c0p0_05.pgx -o temp/c0p0_05.j2k +image_to_j2k -i original/c0p0_06.pgx -o temp/c0p0_06.j2k +image_to_j2k -i original/c0p0_07.pgx -o temp/c0p0_07.j2k +image_to_j2k -i original/c0p0_08.pgx -o temp/c0p0_08.j2k +image_to_j2k -i original/c0p0_09.pgx -o temp/c0p0_09.j2k +image_to_j2k -i original/c0p0_10.pgx -o temp/c0p0_10.j2k +image_to_j2k -i original/c0p0_11.pgx -o temp/c0p0_11.j2k +image_to_j2k -i original/c0p0_12.pgx -o temp/c0p0_12.j2k +image_to_j2k -i original/c0p0_13.pgx -o temp/c0p0_13.j2k +image_to_j2k -i original/c0p0_14.pgx -o temp/c0p0_14.j2k +image_to_j2k -i original/c0p0_15r0.pgx -o temp/c0p0_15r0.j2k +image_to_j2k -i original/c0p0_15r1.pgx -o temp/c0p0_15r1.j2k +image_to_j2k -i original/c0p0_16.pgx -o temp/c0p0_16.j2k +image_to_j2k -i original/c0p1_04r0.pgx -o temp/c0p1_04r0.j2k +image_to_j2k -i original/c0p1_05.pgx -o temp/c0p1_05.j2k +image_to_j2k -i original/c1p0_01_0.pgx -o temp/c1p0_01_0.j2k +image_to_j2k -i original/c1p0_02_0.pgx -o temp/c1p0_02_0.j2k +image_to_j2k -i original/c1p0_03_0.pgx -o temp/c1p0_03_0.j2k +image_to_j2k -i original/c1p0_04_0.pgx -o temp/c1p0_04_0.j2k +image_to_j2k -i original/c1p0_05_0.pgx -o temp/c1p0_05_0.j2k +image_to_j2k -i original/c1p0_06_0.pgx -o temp/c1p0_06_0.j2k +image_to_j2k -i original/c1p0_07_0.pgx -o temp/c1p0_07_0.j2k +image_to_j2k -i original/c1p0_08_0.pgx -o temp/c1p0_08_0.j2k +image_to_j2k -i original/c1p0_09_0.pgx -o temp/c1p0_09_0.j2k +image_to_j2k -i original/c1p0_10_0.pgx -o temp/c1p0_10_0.j2k +image_to_j2k -i original/c1p0_11_0.pgx -o temp/c1p0_11_0.j2k +image_to_j2k -i original/c1p0_12_0.pgx -o temp/c1p0_12_0.j2k +image_to_j2k -i original/c1p0_13_0.pgx -o temp/c1p0_13_0.j2k +image_to_j2k -i original/c1p0_14_0.pgx -o temp/c1p0_14_0.j2k +image_to_j2k -i original/c1p0_15_0.pgx -o temp/c1p0_15_0.j2k +image_to_j2k -i original/c1p0_16_0.pgx -o temp/c1p0_16_0.j2k +image_to_j2k -i original/c1p1_02_0.pgx -o temp/c1p1_02_0.j2k +image_to_j2k -i original/c1p1_05_0.pgx -o temp/c1p1_05_0.j2k +image_to_j2k -i original/Bretagne2.ppm -o temp/Bretagne2_2.j2k -s 2,2 -SOP +image_to_j2k -i original/Bretagne2.ppm -o temp/Bretagne2_3.j2k -EPH -M 38 +image_to_j2k -i original/Bretagne2.ppm -o temp/Bretagne2_4.j2k -d 150,300 -r 800 diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/md5.c b/gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/md5.c new file mode 100644 index 0000000..263dab6 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/md5.c @@ -0,0 +1,276 @@ +/* + ********************************************************************** + ** md5.c ** + ** RSA Data Security, Inc. MD5 Message Digest Algorithm ** + ** Created: 2/17/90 RLR ** + ** Revised: 1/91 SRD,AJ,BSK,JT Reference C Version ** + ********************************************************************** + */ + +/* + ********************************************************************** + ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. ** + ** ** + ** License to copy and use this software is granted provided that ** + ** it is identified as the "RSA Data Security, Inc. MD5 Message ** + ** Digest Algorithm" in all material mentioning or referencing this ** + ** software or this function. ** + ** ** + ** License is also granted to make and use derivative works ** + ** provided that such works are identified as "derived from the RSA ** + ** Data Security, Inc. MD5 Message Digest Algorithm" in all ** + ** material mentioning or referencing the derived work. ** + ** ** + ** RSA Data Security, Inc. makes no representations concerning ** + ** either the merchantability of this software or the suitability ** + ** of this software for any particular purpose. It is provided "as ** + ** is" without express or implied warranty of any kind. ** + ** ** + ** These notices must be retained in any copies of any part of this ** + ** documentation and/or software. ** + ********************************************************************** + */ + +/* -- include the following line if the md5.h header file is separate -- */ +#include "md5.h" + +/* forward declaration */ +static void Transform (); + +static unsigned char PADDING[64] = { + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +/* F, G and H are basic MD5 functions: selection, majority, parity */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/* ROTATE_LEFT rotates x left n bits */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */ +/* Rotation is separate from addition to prevent recomputation */ +#define FF(a, b, c, d, x, s, ac) \ + {(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define GG(a, b, c, d, x, s, ac) \ + {(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define HH(a, b, c, d, x, s, ac) \ + {(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define II(a, b, c, d, x, s, ac) \ + {(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + +void MD5Init (mdContext) +MD5_CTX *mdContext; +{ + mdContext->i[0] = mdContext->i[1] = (UINT4)0; + + /* Load magic initialization constants. + */ + mdContext->buf[0] = (UINT4)0x67452301; + mdContext->buf[1] = (UINT4)0xefcdab89; + mdContext->buf[2] = (UINT4)0x98badcfe; + mdContext->buf[3] = (UINT4)0x10325476; +} + +void MD5Update (mdContext, inBuf, inLen) +MD5_CTX *mdContext; +unsigned char *inBuf; +unsigned int inLen; +{ + UINT4 in[16]; + int mdi; + unsigned int i, ii; + + /* compute number of bytes mod 64 */ + mdi = (int)((mdContext->i[0] >> 3) & 0x3F); + + /* update number of bits */ + if ((mdContext->i[0] + ((UINT4)inLen << 3)) < mdContext->i[0]) + mdContext->i[1]++; + mdContext->i[0] += ((UINT4)inLen << 3); + mdContext->i[1] += ((UINT4)inLen >> 29); + + while (inLen--) { + /* add new character to buffer, increment mdi */ + mdContext->in[mdi++] = *inBuf++; + + /* transform if necessary */ + if (mdi == 0x40) { + for (i = 0, ii = 0; i < 16; i++, ii += 4) + in[i] = (((UINT4)mdContext->in[ii+3]) << 24) | + (((UINT4)mdContext->in[ii+2]) << 16) | + (((UINT4)mdContext->in[ii+1]) << 8) | + ((UINT4)mdContext->in[ii]); + Transform (mdContext->buf, in); + mdi = 0; + } + } +} + +void MD5Final (mdContext) +MD5_CTX *mdContext; +{ + UINT4 in[16]; + int mdi; + unsigned int i, ii; + unsigned int padLen; + + /* save number of bits */ + in[14] = mdContext->i[0]; + in[15] = mdContext->i[1]; + + /* compute number of bytes mod 64 */ + mdi = (int)((mdContext->i[0] >> 3) & 0x3F); + + /* pad out to 56 mod 64 */ + padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi); + MD5Update (mdContext, PADDING, padLen); + + /* append length in bits and transform */ + for (i = 0, ii = 0; i < 14; i++, ii += 4) + in[i] = (((UINT4)mdContext->in[ii+3]) << 24) | + (((UINT4)mdContext->in[ii+2]) << 16) | + (((UINT4)mdContext->in[ii+1]) << 8) | + ((UINT4)mdContext->in[ii]); + Transform (mdContext->buf, in); + + /* store buffer in digest */ + for (i = 0, ii = 0; i < 4; i++, ii += 4) { + mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF); + mdContext->digest[ii+1] = + (unsigned char)((mdContext->buf[i] >> 8) & 0xFF); + mdContext->digest[ii+2] = + (unsigned char)((mdContext->buf[i] >> 16) & 0xFF); + mdContext->digest[ii+3] = + (unsigned char)((mdContext->buf[i] >> 24) & 0xFF); + } +} + +/* Basic MD5 step. Transform buf based on in. + */ +static void Transform (buf, in) +UINT4 *buf; +UINT4 *in; +{ + UINT4 a = buf[0], b = buf[1], c = buf[2], d = buf[3]; + + /* Round 1 */ +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 + FF ( a, b, c, d, in[ 0], S11, 3614090360); /* 1 */ + FF ( d, a, b, c, in[ 1], S12, 3905402710); /* 2 */ + FF ( c, d, a, b, in[ 2], S13, 606105819); /* 3 */ + FF ( b, c, d, a, in[ 3], S14, 3250441966); /* 4 */ + FF ( a, b, c, d, in[ 4], S11, 4118548399); /* 5 */ + FF ( d, a, b, c, in[ 5], S12, 1200080426); /* 6 */ + FF ( c, d, a, b, in[ 6], S13, 2821735955); /* 7 */ + FF ( b, c, d, a, in[ 7], S14, 4249261313); /* 8 */ + FF ( a, b, c, d, in[ 8], S11, 1770035416); /* 9 */ + FF ( d, a, b, c, in[ 9], S12, 2336552879); /* 10 */ + FF ( c, d, a, b, in[10], S13, 4294925233); /* 11 */ + FF ( b, c, d, a, in[11], S14, 2304563134); /* 12 */ + FF ( a, b, c, d, in[12], S11, 1804603682); /* 13 */ + FF ( d, a, b, c, in[13], S12, 4254626195); /* 14 */ + FF ( c, d, a, b, in[14], S13, 2792965006); /* 15 */ + FF ( b, c, d, a, in[15], S14, 1236535329); /* 16 */ + + /* Round 2 */ +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 + GG ( a, b, c, d, in[ 1], S21, 4129170786); /* 17 */ + GG ( d, a, b, c, in[ 6], S22, 3225465664); /* 18 */ + GG ( c, d, a, b, in[11], S23, 643717713); /* 19 */ + GG ( b, c, d, a, in[ 0], S24, 3921069994); /* 20 */ + GG ( a, b, c, d, in[ 5], S21, 3593408605); /* 21 */ + GG ( d, a, b, c, in[10], S22, 38016083); /* 22 */ + GG ( c, d, a, b, in[15], S23, 3634488961); /* 23 */ + GG ( b, c, d, a, in[ 4], S24, 3889429448); /* 24 */ + GG ( a, b, c, d, in[ 9], S21, 568446438); /* 25 */ + GG ( d, a, b, c, in[14], S22, 3275163606); /* 26 */ + GG ( c, d, a, b, in[ 3], S23, 4107603335); /* 27 */ + GG ( b, c, d, a, in[ 8], S24, 1163531501); /* 28 */ + GG ( a, b, c, d, in[13], S21, 2850285829); /* 29 */ + GG ( d, a, b, c, in[ 2], S22, 4243563512); /* 30 */ + GG ( c, d, a, b, in[ 7], S23, 1735328473); /* 31 */ + GG ( b, c, d, a, in[12], S24, 2368359562); /* 32 */ + + /* Round 3 */ +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 + HH ( a, b, c, d, in[ 5], S31, 4294588738); /* 33 */ + HH ( d, a, b, c, in[ 8], S32, 2272392833); /* 34 */ + HH ( c, d, a, b, in[11], S33, 1839030562); /* 35 */ + HH ( b, c, d, a, in[14], S34, 4259657740); /* 36 */ + HH ( a, b, c, d, in[ 1], S31, 2763975236); /* 37 */ + HH ( d, a, b, c, in[ 4], S32, 1272893353); /* 38 */ + HH ( c, d, a, b, in[ 7], S33, 4139469664); /* 39 */ + HH ( b, c, d, a, in[10], S34, 3200236656); /* 40 */ + HH ( a, b, c, d, in[13], S31, 681279174); /* 41 */ + HH ( d, a, b, c, in[ 0], S32, 3936430074); /* 42 */ + HH ( c, d, a, b, in[ 3], S33, 3572445317); /* 43 */ + HH ( b, c, d, a, in[ 6], S34, 76029189); /* 44 */ + HH ( a, b, c, d, in[ 9], S31, 3654602809); /* 45 */ + HH ( d, a, b, c, in[12], S32, 3873151461); /* 46 */ + HH ( c, d, a, b, in[15], S33, 530742520); /* 47 */ + HH ( b, c, d, a, in[ 2], S34, 3299628645); /* 48 */ + + /* Round 4 */ +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + II ( a, b, c, d, in[ 0], S41, 4096336452); /* 49 */ + II ( d, a, b, c, in[ 7], S42, 1126891415); /* 50 */ + II ( c, d, a, b, in[14], S43, 2878612391); /* 51 */ + II ( b, c, d, a, in[ 5], S44, 4237533241); /* 52 */ + II ( a, b, c, d, in[12], S41, 1700485571); /* 53 */ + II ( d, a, b, c, in[ 3], S42, 2399980690); /* 54 */ + II ( c, d, a, b, in[10], S43, 4293915773); /* 55 */ + II ( b, c, d, a, in[ 1], S44, 2240044497); /* 56 */ + II ( a, b, c, d, in[ 8], S41, 1873313359); /* 57 */ + II ( d, a, b, c, in[15], S42, 4264355552); /* 58 */ + II ( c, d, a, b, in[ 6], S43, 2734768916); /* 59 */ + II ( b, c, d, a, in[13], S44, 1309151649); /* 60 */ + II ( a, b, c, d, in[ 4], S41, 4149444226); /* 61 */ + II ( d, a, b, c, in[11], S42, 3174756917); /* 62 */ + II ( c, d, a, b, in[ 2], S43, 718787259); /* 63 */ + II ( b, c, d, a, in[ 9], S44, 3951481745); /* 64 */ + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +/* + ********************************************************************** + ** End of md5.c ** + ******************************* (cut) ******************************** + */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/md5.h b/gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/md5.h new file mode 100644 index 0000000..2b61fd3 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/md5.h @@ -0,0 +1,59 @@ +/* + ********************************************************************** + ** md5.h -- Header file for implementation of MD5 ** + ** RSA Data Security, Inc. MD5 Message Digest Algorithm ** + ** Created: 2/17/90 RLR ** + ** Revised: 12/27/90 SRD,AJ,BSK,JT Reference C version ** + ** Revised (for MD5): RLR 4/27/91 ** + ** -- G modified to have y&~z instead of y&z ** + ** -- FF, GG, HH modified to add in last register done ** + ** -- Access pattern: round 2 works mod 5, round 3 works mod 3 ** + ** -- distinct additive constant for each step ** + ** -- round 4 added, working mod 7 ** + ********************************************************************** + */ + +/* + ********************************************************************** + ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. ** + ** ** + ** License to copy and use this software is granted provided that ** + ** it is identified as the "RSA Data Security, Inc. MD5 Message ** + ** Digest Algorithm" in all material mentioning or referencing this ** + ** software or this function. ** + ** ** + ** License is also granted to make and use derivative works ** + ** provided that such works are identified as "derived from the RSA ** + ** Data Security, Inc. MD5 Message Digest Algorithm" in all ** + ** material mentioning or referencing the derived work. ** + ** ** + ** RSA Data Security, Inc. makes no representations concerning ** + ** either the merchantability of this software or the suitability ** + ** of this software for any particular purpose. It is provided "as ** + ** is" without express or implied warranty of any kind. ** + ** ** + ** These notices must be retained in any copies of any part of this ** + ** documentation and/or software. ** + ********************************************************************** + */ + +/* typedef a 32 bit type */ +typedef unsigned long int UINT4; + +/* Data structure for MD5 (Message Digest) computation */ +typedef struct { + UINT4 i[2]; /* number of _bits_ handled mod 2^64 */ + UINT4 buf[4]; /* scratch buffer */ + unsigned char in[64]; /* input buffer */ + unsigned char digest[16]; /* actual digest after MD5Final call */ +} MD5_CTX; + +void MD5Init (); +void MD5Update (); +void MD5Final (); + +/* + ********************************************************************** + ** End of md5.h ** + ******************************* (cut) ******************************** + */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/original/README.txt b/gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/original/README.txt new file mode 100644 index 0000000..d78d1bd --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/OPJ_Validate/original/README.txt @@ -0,0 +1 @@ +Download the source images into this directory from http://www.openjpeg.org/OPJ_Validate_OriginalImages.7z diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/OpenJPEG.rc b/gdcm/Utilities/gdcmopenjpeg-v1/OpenJPEG.rc new file mode 100644 index 0000000..4d8d18a --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/OpenJPEG.rc @@ -0,0 +1,109 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// French (France) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_FRA) +#ifdef _WIN32 +LANGUAGE LANG_FRENCH, SUBLANG_FRENCH +#pragma code_page(1252) +#endif //_WIN32 + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,1,0,0 + PRODUCTVERSION 1,1,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Comments", "The OpenJPEG library is an open-source JPEG 2000 codec. \0" + VALUE "CompanyName", "OpenJPEG\0" + VALUE "FileDescription", "OpenJPEG\0" + VALUE "FileVersion", "1, 1, 0, 0\0" + VALUE "InternalName", "OpenJPEG\0" + VALUE "LegalCopyright", "Copyright © 2002-2007, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium\0" + VALUE "LegalTrademarks", "See http://www.openjpeg.org for details\0" + VALUE "OriginalFilename", "OpenJPEG.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "OpenJPEG\0" + VALUE "ProductVersion", "1, 1, 0, 0\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + +#endif // !_MAC + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // French (France) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/README b/gdcm/Utilities/gdcmopenjpeg-v1/README new file mode 100644 index 0000000..031cf3d --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/README @@ -0,0 +1 @@ +see INSTALL for installation procedures. \ No newline at end of file diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/README.msvc b/gdcm/Utilities/gdcmopenjpeg-v1/README.msvc new file mode 100644 index 0000000..fc9ea89 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/README.msvc @@ -0,0 +1,40 @@ +How to compile the library under MS VC++ 6.0 +-------------------------------------------- + +The library comes in two versions : +- a static library that can be linked against any C/C++ program +- a Dynamic Link Library (Windows DLL) that can be used in any C/C++ program and in most interpreted languages (e.g. VB, C#, ...). + +In order to compile the library version *or* the DLL version, you will have to : + +1) Open the MSVC workspace named LibOpenJPEG.dsw +2) Set the choosen target as the active project, that means : + a) Go to the Menu 'Build -> Set Active Configuration' + b) Choose one of the following configuration : + - DllOpenJPEG - Win32 Release => creates a DLL in release mode named OpenJPEG.dll + - DllOpenJPEG - Win32 Debug => creates a DLL in debug mode named OpenJPEGd.dll + - LibOpenJPEG - Win32 Release => creates a static library in release mode named LibOpenJPEG.lib + - LibOpenJPEG - Win32 Debug => creates a static library in debug mode named LibOpenJPEGd.lib +3) Build the project : Menu -> Build -> Rebuild All + +The build process will create a directory named 'dist' that will contain all you need in order to use the library. + +Simple codec compilation +------------------------ + +Once you've built the library, you might want to test it with a basic codec. To do this, go to the codec directory and use one of the following projects to build an encoder and decoder respectively: +- image_to_j2k.dsw +- j2k_to_image.dsw + +IMPORTANT NOTE : +---------------- + +The encoder and decoder samples are configured to use the static version of the library. A link to the LibOpenJPEG static project is included in these projects so that you can build both a codec and the library in a single pass. + +However, you MUST NOTE that in order to use LibOpenJPEG as a static library in your program, you NEED to add the following compiler directive to your project : OPJ_STATIC +Look at the menu 'Project -> Settings -> C/C++ tab -> preprocessor definition' to see how this is configured. +When using OpenJPEG as a DLL, this compiler directive MUST NOT be used. + + + + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/codec/CMakeLists.txt b/gdcm/Utilities/gdcmopenjpeg-v1/codec/CMakeLists.txt new file mode 100644 index 0000000..2c1a072 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/codec/CMakeLists.txt @@ -0,0 +1,102 @@ + # Build the demo app, small examples + +# First thing define the common source: +set(common_SRCS + convert.c + index.c + ${${OPENJPEG_NAMESPACE}_SOURCE_DIR}/common/color.c +) + +# If not getopt was found then add it to the lib: +if(DONT_HAVE_GETOPT) + set(common_SRCS + ${common_SRCS} + ${OPENJPEG_SOURCE_DIR}/common/getopt.c + ) +endif() + +# Headers file are located here: +include_directories( + ${OPENJPEG_SOURCE_DIR}/libopenjpeg + ${LCMS_INCLUDE_DIR} + ${OPENJPEG_SOURCE_DIR}/common + ) +if(PNG_FOUND) + include_directories(${PNG_INCLUDE_DIR}) +endif() +if(TIFF_FOUND) + include_directories(${TIFF_INCLUDE_DIR}) +endif() + +if(WIN32) + if(BUILD_SHARED_LIBS) + add_definitions(-DOPJ_EXPORTS) + else() + add_definitions(-DOPJ_STATIC) + endif() +endif() + +# Loop over all executables: +foreach(exe j2k_to_image image_to_j2k j2k_dump) + add_executable(${exe} ${exe}.c ${common_SRCS}) + target_link_libraries(${exe} ${OPENJPEG_LIBRARY_NAME} ${LCMS_LIB}) + if(PNG_FOUND) + target_link_libraries(${exe} ${PNG_LIBRARIES}) + endif() + if(TIFF_FOUND) + target_link_libraries(${exe} ${TIFF_LIBRARIES}) + endif() + add_test(NAME ${exe} COMMAND ${EXECUTABLE_OUTPUT_PATH}/${exe}) + # calling those exe without option will make them fail always: + set_tests_properties(${exe} PROPERTIES WILL_FAIL TRUE) + # On unix you need to link to the math library: + if(UNIX) + target_link_libraries(${exe} m) + endif() + # Install exe + install(TARGETS ${exe} + EXPORT OpenJPEGTargets + DESTINATION ${OPENJPEG_INSTALL_BIN_DIR} COMPONENT Applications + ) +endforeach() + +# Install man pages +install( + FILES ../doc/man/man1/image_to_j2k.1 + ../doc/man/man1/j2k_dump.1 + ../doc/man/man1/j2k_to_image.1 + DESTINATION ${OPENJPEG_INSTALL_MAN_DIR}/man1) +# + +if(BUILD_TESTING) +# Do testing here, once we know the examples are being built: +file(GLOB_RECURSE OPENJPEG_DATA_IMAGES_GLOB + "${JPEG2000_CONFORMANCE_DATA_ROOT}/*.j2k" + "${JPEG2000_CONFORMANCE_DATA_ROOT}/*.j2c" + "${JPEG2000_CONFORMANCE_DATA_ROOT}/*.jp2" + ) + +foreach(filename ${OPENJPEG_DATA_IMAGES_GLOB}) + get_filename_component(filename_temp ${filename} NAME) + get_filename_component(filename_ext ${filename} EXT) + execute_process(COMMAND ${EXECUTABLE_OUTPUT_PATH}/j2k_dump -i ${filename} + OUTPUT_VARIABLE dump_success + OUTPUT_FILE ${CMAKE_CURRENT_BINARY_DIR}/${filename_temp}.dump + ERROR_QUIET + ) + if(dump_success) + file(READ ${CMAKE_CURRENT_BINARY_DIR}/${filename_temp}.dump numcomp_file) + string(REGEX REPLACE ".*numcomps=([0-9]+).*" "\\1" + numcomps "${numcomp_file}") + #message( "found:${output_variable} for ${filename_temp}" ) + endif() + add_test(NAME dump-${filename_temp} COMMAND ${EXECUTABLE_OUTPUT_PATH}/j2k_dump -i ${filename}) + foreach(codec_type ppm pgx bmp tif raw tga png) + add_test(NAME j2i-${filename_temp}-${codec_type} COMMAND ${EXECUTABLE_OUTPUT_PATH}/j2k_to_image -i ${filename} -o ${filename_temp}.${codec_type}) + add_test(NAME i2j-${filename_temp}-${codec_type} COMMAND ${EXECUTABLE_OUTPUT_PATH}/image_to_j2k -i ${filename_temp}.${codec_type} -o ${filename_temp}.${codec_type}${filename_ext}) + #if(UNIX) + # add_test(cmp-${filename_temp}-${codec_type} cmp ${filename} ${filename_temp}.${codec_type}${filename_ext}) + #endif() + endforeach() +endforeach() +endif() diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/codec/README b/gdcm/Utilities/gdcmopenjpeg-v1/codec/README new file mode 100644 index 0000000..8004998 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/codec/README @@ -0,0 +1,8 @@ +Simple codec compilation +------------------------ +Once you've built the library, you might want to test it with a basic codec. To do this, go to the codec directory and either use the provided Makefile or use one of the following commands to build an encoder and decoder respectively: + +gcc index.c convert.c image_to_j2k.c -o image_to_j2k -lopenjpeg -I ../libopenjpeg/ -lm -ltiff +gcc index.c convert.c j2k_to_image.c -o j2k_to_image -lopenjpeg -I ../libopenjpeg/ -lm -ltiff + +You should add '-L..' to those lines if you did not use the 'install' target when building the library. \ No newline at end of file diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/codec/convert.c b/gdcm/Utilities/gdcmopenjpeg-v1/codec/convert.c new file mode 100644 index 0000000..25e715b --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/codec/convert.c @@ -0,0 +1,2686 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2006-2007, Parvatha Elangovan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "opj_config.h" + +#include +#include +#include + +#ifdef HAVE_LIBTIFF +#ifdef _WIN32 +#include "../libs/libtiff/tiffio.h" +#else +#include +#endif /* _WIN32 */ +#endif /* HAVE_LIBTIFF */ + +#ifdef HAVE_LIBPNG +#ifdef _WIN32 +#include "../libs/png/png.h" +#else +#include +#endif /* _WIN32 */ +#endif /* HAVE_LIBPNG */ + +#include "../libopenjpeg/openjpeg.h" +#include "convert.h" + +/* + * Get logarithm of an integer and round downwards. + * + * log2(a) + */ +static int int_floorlog2(int a) { + int l; + for (l = 0; a > 1; l++) { + a >>= 1; + } + return l; +} + +/* + * Divide an integer by a power of 2 and round upwards. + * + * a divided by 2^b + */ +static int int_ceildivpow2(int a, int b) { + return (a + (1 << b) - 1) >> b; +} + +/* + * Divide an integer and round upwards. + * + * a divided by b + */ +static int int_ceildiv(int a, int b) { + return (a + b - 1) / b; +} + + +/* -->> -->> -->> -->> + + TGA IMAGE FORMAT + + <<-- <<-- <<-- <<-- */ + +// TGA header definition. +#pragma pack(push,1) // Pack structure byte aligned +typedef struct tga_header +{ + unsigned char id_length; /* Image id field length */ + unsigned char colour_map_type; /* Colour map type */ + unsigned char image_type; /* Image type */ + /* + ** Colour map specification + */ + unsigned short colour_map_index; /* First entry index */ + unsigned short colour_map_length; /* Colour map length */ + unsigned char colour_map_entry_size; /* Colour map entry size */ + /* + ** Image specification + */ + unsigned short x_origin; /* x origin of image */ + unsigned short y_origin; /* u origin of image */ + unsigned short image_width; /* Image width */ + unsigned short image_height; /* Image height */ + unsigned char pixel_depth; /* Pixel depth */ + unsigned char image_desc; /* Image descriptor */ +} tga_header; +#pragma pack(pop) // Return to normal structure packing alignment. + +int tga_readheader(FILE *fp, unsigned int *bits_per_pixel, + unsigned int *width, unsigned int *height, int *flip_image) +{ + int palette_size; + tga_header tga ; + + if (!bits_per_pixel || !width || !height || !flip_image) + return 0; + + // Read TGA header + fread((unsigned char*)&tga, sizeof(tga_header), 1, fp); + + *bits_per_pixel = tga.pixel_depth; + + *width = tga.image_width; + *height = tga.image_height ; + + // Ignore tga identifier, if present ... + if (tga.id_length) + { + unsigned char *id = (unsigned char *) malloc(tga.id_length); + fread(id, tga.id_length, 1, fp); + free(id); + } + + // Test for compressed formats ... not yet supported ... + // Note :- 9 - RLE encoded palettized. + // 10 - RLE encoded RGB. + if (tga.image_type > 8) + { + fprintf(stderr, "Sorry, compressed tga files are not currently supported.\n"); + return 0 ; + } + + *flip_image = !(tga.image_desc & 32); + + // Palettized formats are not yet supported, skip over the palette, if present ... + palette_size = tga.colour_map_length * (tga.colour_map_entry_size/8); + + if (palette_size>0) + { + fprintf(stderr, "File contains a palette - not yet supported."); + fseek(fp, palette_size, SEEK_CUR); + } + return 1; +} + +int tga_writeheader(FILE *fp, int bits_per_pixel, int width, int height, + bool flip_image) +{ + tga_header tga; + + if (!bits_per_pixel || !width || !height) + return 0; + + memset(&tga, 0, sizeof(tga_header)); + + tga.pixel_depth = bits_per_pixel; + tga.image_width = width; + tga.image_height = height; + tga.image_type = 2; // Uncompressed. + tga.image_desc = 8; // 8 bits per component. + + if (flip_image) + tga.image_desc |= 32; + + // Write TGA header + fwrite((unsigned char*)&tga, sizeof(tga_header), 1, fp); + + return 1; +} + +opj_image_t* tgatoimage(const char *filename, opj_cparameters_t *parameters) { + FILE *f; + opj_image_t *image; + unsigned int image_width, image_height, pixel_bit_depth; + unsigned int x, y; + int flip_image=0; + opj_image_cmptparm_t cmptparm[4]; /* maximum 4 components */ + int numcomps; + OPJ_COLOR_SPACE color_space; + bool mono ; + bool save_alpha; + int subsampling_dx, subsampling_dy; + int i; + + f = fopen(filename, "rb"); + if (!f) { + fprintf(stderr, "Failed to open %s for reading !!\n", filename); + return 0; + } + + if (!tga_readheader(f, &pixel_bit_depth, &image_width, &image_height, &flip_image)) + return NULL; + + // We currently only support 24 & 32 bit tga's ... + if (!((pixel_bit_depth == 24) || (pixel_bit_depth == 32))) + return NULL; + + /* initialize image components */ + memset(&cmptparm[0], 0, 4 * sizeof(opj_image_cmptparm_t)); + + mono = (pixel_bit_depth == 8) || (pixel_bit_depth == 16); // Mono with & without alpha. + save_alpha = (pixel_bit_depth == 16) || (pixel_bit_depth == 32); // Mono with alpha, or RGB with alpha + + if (mono) { + color_space = CLRSPC_GRAY; + numcomps = save_alpha ? 2 : 1; + } + else { + numcomps = save_alpha ? 4 : 3; + color_space = CLRSPC_SRGB; + } + + subsampling_dx = parameters->subsampling_dx; + subsampling_dy = parameters->subsampling_dy; + + for (i = 0; i < numcomps; i++) { + cmptparm[i].prec = 8; + cmptparm[i].bpp = 8; + cmptparm[i].sgnd = 0; + cmptparm[i].dx = subsampling_dx; + cmptparm[i].dy = subsampling_dy; + cmptparm[i].w = image_width; + cmptparm[i].h = image_height; + } + + /* create the image */ + image = opj_image_create(numcomps, &cmptparm[0], color_space); + + if (!image) + return NULL; + + /* set image offset and reference grid */ + image->x0 = parameters->image_offset_x0; + image->y0 = parameters->image_offset_y0; + image->x1 = !image->x0 ? (image_width - 1) * subsampling_dx + 1 : image->x0 + (image_width - 1) * subsampling_dx + 1; + image->y1 = !image->y0 ? (image_height - 1) * subsampling_dy + 1 : image->y0 + (image_height - 1) * subsampling_dy + 1; + + /* set image data */ + for (y=0; y < image_height; y++) + { + int index; + + if (flip_image) + index = (image_height-y-1)*image_width; + else + index = y*image_width; + + if (numcomps==3) + { + for (x=0;xcomps[0].data[index]=r; + image->comps[1].data[index]=g; + image->comps[2].data[index]=b; + index++; + } + } + else if (numcomps==4) + { + for (x=0;xcomps[0].data[index]=r; + image->comps[1].data[index]=g; + image->comps[2].data[index]=b; + image->comps[3].data[index]=a; + index++; + } + } + else { + fprintf(stderr, "Currently unsupported bit depth : %s\n", filename); + } + } + return image; +} + +int imagetotga(opj_image_t * image, const char *outfile) { + int width, height, bpp, x, y; + bool write_alpha; + int i; + unsigned int alpha_channel; + float r,g,b,a; + unsigned char value; + float scale; + FILE *fdest; + + fdest = fopen(outfile, "wb"); + if (!fdest) { + fprintf(stderr, "ERROR -> failed to open %s for writing\n", outfile); + return 1; + } + + for (i = 0; i < image->numcomps-1; i++) { + if ((image->comps[0].dx != image->comps[i+1].dx) + ||(image->comps[0].dy != image->comps[i+1].dy) + ||(image->comps[0].prec != image->comps[i+1].prec)) { + fprintf(stderr, "Unable to create a tga file with such J2K image charateristics."); + return 1; + } + } + + width = image->comps[0].w; + height = image->comps[0].h; + + // Mono with alpha, or RGB with alpha. + write_alpha = (image->numcomps==2) || (image->numcomps==4); + + // Write TGA header + bpp = write_alpha ? 32 : 24; + if (!tga_writeheader(fdest, bpp, width , height, true)) + return 1; + + alpha_channel = image->numcomps-1; + + scale = 255.0f / (float)((1<comps[0].prec)-1); + + for (y=0; y < height; y++) { + unsigned int index=y*width; + + for (x=0; x < width; x++, index++) { + r = (float)(image->comps[0].data[index]); + + if (image->numcomps>2) { + g = (float)(image->comps[1].data[index]); + b = (float)(image->comps[2].data[index]); + } + else {// Greyscale ... + g = r; + b = r; + } + + // TGA format writes BGR ... + value = (unsigned char)(b*scale); + fwrite(&value,1,1,fdest); + + value = (unsigned char)(g*scale); + fwrite(&value,1,1,fdest); + + value = (unsigned char)(r*scale); + fwrite(&value,1,1,fdest); + + if (write_alpha) { + a = (float)(image->comps[alpha_channel].data[index]); + value = (unsigned char)(a*scale); + fwrite(&value,1,1,fdest); + } + } + } + + return 0; +} + +/* -->> -->> -->> -->> + + BMP IMAGE FORMAT + + <<-- <<-- <<-- <<-- */ + +/* WORD defines a two byte word */ +typedef unsigned short int WORD; + +/* DWORD defines a four byte word */ +typedef unsigned long int DWORD; + +typedef struct { + WORD bfType; /* 'BM' for Bitmap (19776) */ + DWORD bfSize; /* Size of the file */ + WORD bfReserved1; /* Reserved : 0 */ + WORD bfReserved2; /* Reserved : 0 */ + DWORD bfOffBits; /* Offset */ +} BITMAPFILEHEADER_t; + +typedef struct { + DWORD biSize; /* Size of the structure in bytes */ + DWORD biWidth; /* Width of the image in pixels */ + DWORD biHeight; /* Heigth of the image in pixels */ + WORD biPlanes; /* 1 */ + WORD biBitCount; /* Number of color bits by pixels */ + DWORD biCompression; /* Type of encoding 0: none 1: RLE8 2: RLE4 */ + DWORD biSizeImage; /* Size of the image in bytes */ + DWORD biXpelsPerMeter; /* Horizontal (X) resolution in pixels/meter */ + DWORD biYpelsPerMeter; /* Vertical (Y) resolution in pixels/meter */ + DWORD biClrUsed; /* Number of color used in the image (0: ALL) */ + DWORD biClrImportant; /* Number of important color (0: ALL) */ +} BITMAPINFOHEADER_t; + +opj_image_t* bmptoimage(const char *filename, opj_cparameters_t *parameters) { + int subsampling_dx = parameters->subsampling_dx; + int subsampling_dy = parameters->subsampling_dy; + + int i, numcomps, w, h; + OPJ_COLOR_SPACE color_space; + opj_image_cmptparm_t cmptparm[3]; /* maximum of 3 components */ + opj_image_t * image = NULL; + + FILE *IN; + BITMAPFILEHEADER_t File_h; + BITMAPINFOHEADER_t Info_h; + unsigned char *RGB; + unsigned char *table_R, *table_G, *table_B; + unsigned int j, PAD = 0; + + int x, y, index; + int gray_scale = 1, not_end_file = 1; + + unsigned int line = 0, col = 0; + unsigned char v, v2; + DWORD W, H; + + IN = fopen(filename, "rb"); + if (!IN) { + fprintf(stderr, "Failed to open %s for reading !!\n", filename); + return 0; + } + + File_h.bfType = getc(IN); + File_h.bfType = (getc(IN) << 8) + File_h.bfType; + + if (File_h.bfType != 19778) { + fprintf(stderr,"Error, not a BMP file!\n"); + return 0; + } else { + /* FILE HEADER */ + /* ------------- */ + File_h.bfSize = getc(IN); + File_h.bfSize = (getc(IN) << 8) + File_h.bfSize; + File_h.bfSize = (getc(IN) << 16) + File_h.bfSize; + File_h.bfSize = (getc(IN) << 24) + File_h.bfSize; + + File_h.bfReserved1 = getc(IN); + File_h.bfReserved1 = (getc(IN) << 8) + File_h.bfReserved1; + + File_h.bfReserved2 = getc(IN); + File_h.bfReserved2 = (getc(IN) << 8) + File_h.bfReserved2; + + File_h.bfOffBits = getc(IN); + File_h.bfOffBits = (getc(IN) << 8) + File_h.bfOffBits; + File_h.bfOffBits = (getc(IN) << 16) + File_h.bfOffBits; + File_h.bfOffBits = (getc(IN) << 24) + File_h.bfOffBits; + + /* INFO HEADER */ + /* ------------- */ + + Info_h.biSize = getc(IN); + Info_h.biSize = (getc(IN) << 8) + Info_h.biSize; + Info_h.biSize = (getc(IN) << 16) + Info_h.biSize; + Info_h.biSize = (getc(IN) << 24) + Info_h.biSize; + + Info_h.biWidth = getc(IN); + Info_h.biWidth = (getc(IN) << 8) + Info_h.biWidth; + Info_h.biWidth = (getc(IN) << 16) + Info_h.biWidth; + Info_h.biWidth = (getc(IN) << 24) + Info_h.biWidth; + w = Info_h.biWidth; + + Info_h.biHeight = getc(IN); + Info_h.biHeight = (getc(IN) << 8) + Info_h.biHeight; + Info_h.biHeight = (getc(IN) << 16) + Info_h.biHeight; + Info_h.biHeight = (getc(IN) << 24) + Info_h.biHeight; + h = Info_h.biHeight; + + Info_h.biPlanes = getc(IN); + Info_h.biPlanes = (getc(IN) << 8) + Info_h.biPlanes; + + Info_h.biBitCount = getc(IN); + Info_h.biBitCount = (getc(IN) << 8) + Info_h.biBitCount; + + Info_h.biCompression = getc(IN); + Info_h.biCompression = (getc(IN) << 8) + Info_h.biCompression; + Info_h.biCompression = (getc(IN) << 16) + Info_h.biCompression; + Info_h.biCompression = (getc(IN) << 24) + Info_h.biCompression; + + Info_h.biSizeImage = getc(IN); + Info_h.biSizeImage = (getc(IN) << 8) + Info_h.biSizeImage; + Info_h.biSizeImage = (getc(IN) << 16) + Info_h.biSizeImage; + Info_h.biSizeImage = (getc(IN) << 24) + Info_h.biSizeImage; + + Info_h.biXpelsPerMeter = getc(IN); + Info_h.biXpelsPerMeter = (getc(IN) << 8) + Info_h.biXpelsPerMeter; + Info_h.biXpelsPerMeter = (getc(IN) << 16) + Info_h.biXpelsPerMeter; + Info_h.biXpelsPerMeter = (getc(IN) << 24) + Info_h.biXpelsPerMeter; + + Info_h.biYpelsPerMeter = getc(IN); + Info_h.biYpelsPerMeter = (getc(IN) << 8) + Info_h.biYpelsPerMeter; + Info_h.biYpelsPerMeter = (getc(IN) << 16) + Info_h.biYpelsPerMeter; + Info_h.biYpelsPerMeter = (getc(IN) << 24) + Info_h.biYpelsPerMeter; + + Info_h.biClrUsed = getc(IN); + Info_h.biClrUsed = (getc(IN) << 8) + Info_h.biClrUsed; + Info_h.biClrUsed = (getc(IN) << 16) + Info_h.biClrUsed; + Info_h.biClrUsed = (getc(IN) << 24) + Info_h.biClrUsed; + + Info_h.biClrImportant = getc(IN); + Info_h.biClrImportant = (getc(IN) << 8) + Info_h.biClrImportant; + Info_h.biClrImportant = (getc(IN) << 16) + Info_h.biClrImportant; + Info_h.biClrImportant = (getc(IN) << 24) + Info_h.biClrImportant; + + /* Read the data and store them in the OUT file */ + + if (Info_h.biBitCount == 24) { + numcomps = 3; + color_space = CLRSPC_SRGB; + /* initialize image components */ + memset(&cmptparm[0], 0, 3 * sizeof(opj_image_cmptparm_t)); + for(i = 0; i < numcomps; i++) { + cmptparm[i].prec = 8; + cmptparm[i].bpp = 8; + cmptparm[i].sgnd = 0; + cmptparm[i].dx = subsampling_dx; + cmptparm[i].dy = subsampling_dy; + cmptparm[i].w = w; + cmptparm[i].h = h; + } + /* create the image */ + image = opj_image_create(numcomps, &cmptparm[0], color_space); + if(!image) { + fclose(IN); + return NULL; + } + + /* set image offset and reference grid */ + image->x0 = parameters->image_offset_x0; + image->y0 = parameters->image_offset_y0; + image->x1 = !image->x0 ? (w - 1) * subsampling_dx + 1 : image->x0 + (w - 1) * subsampling_dx + 1; + image->y1 = !image->y0 ? (h - 1) * subsampling_dy + 1 : image->y0 + (h - 1) * subsampling_dy + 1; + + /* set image data */ + + /* Place the cursor at the beginning of the image information */ + fseek(IN, 0, SEEK_SET); + fseek(IN, File_h.bfOffBits, SEEK_SET); + + W = Info_h.biWidth; + H = Info_h.biHeight; + + /* PAD = 4 - (3 * W) % 4; */ + /* PAD = (PAD == 4) ? 0 : PAD; */ + PAD = (3 * W) % 4 ? 4 - (3 * W) % 4 : 0; + + RGB = (unsigned char *) malloc((3 * W + PAD) * H * sizeof(unsigned char)); + + fread(RGB, sizeof(unsigned char), (3 * W + PAD) * H, IN); + + index = 0; + + for(y = 0; y < (int)H; y++) { + unsigned char *scanline = RGB + (3 * W + PAD) * (H - 1 - y); + for(x = 0; x < (int)W; x++) { + unsigned char *pixel = &scanline[3 * x]; + image->comps[0].data[index] = pixel[2]; /* R */ + image->comps[1].data[index] = pixel[1]; /* G */ + image->comps[2].data[index] = pixel[0]; /* B */ + index++; + } + } + + free(RGB); + + } else if (Info_h.biBitCount == 8 && Info_h.biCompression == 0) { + table_R = (unsigned char *) malloc(256 * sizeof(unsigned char)); + table_G = (unsigned char *) malloc(256 * sizeof(unsigned char)); + table_B = (unsigned char *) malloc(256 * sizeof(unsigned char)); + + for (j = 0; j < Info_h.biClrUsed; j++) { + table_B[j] = getc(IN); + table_G[j] = getc(IN); + table_R[j] = getc(IN); + getc(IN); + if (table_R[j] != table_G[j] && table_R[j] != table_B[j] && table_G[j] != table_B[j]) + gray_scale = 0; + } + + /* Place the cursor at the beginning of the image information */ + fseek(IN, 0, SEEK_SET); + fseek(IN, File_h.bfOffBits, SEEK_SET); + + W = Info_h.biWidth; + H = Info_h.biHeight; + if (Info_h.biWidth % 2) + W++; + + numcomps = gray_scale ? 1 : 3; + color_space = gray_scale ? CLRSPC_GRAY : CLRSPC_SRGB; + /* initialize image components */ + memset(&cmptparm[0], 0, 3 * sizeof(opj_image_cmptparm_t)); + for(i = 0; i < numcomps; i++) { + cmptparm[i].prec = 8; + cmptparm[i].bpp = 8; + cmptparm[i].sgnd = 0; + cmptparm[i].dx = subsampling_dx; + cmptparm[i].dy = subsampling_dy; + cmptparm[i].w = w; + cmptparm[i].h = h; + } + /* create the image */ + image = opj_image_create(numcomps, &cmptparm[0], color_space); + if(!image) { + fclose(IN); + return NULL; + } + + /* set image offset and reference grid */ + image->x0 = parameters->image_offset_x0; + image->y0 = parameters->image_offset_y0; + image->x1 = !image->x0 ? (w - 1) * subsampling_dx + 1 : image->x0 + (w - 1) * subsampling_dx + 1; + image->y1 = !image->y0 ? (h - 1) * subsampling_dy + 1 : image->y0 + (h - 1) * subsampling_dy + 1; + + /* set image data */ + + RGB = (unsigned char *) malloc(W * H * sizeof(unsigned char)); + + fread(RGB, sizeof(unsigned char), W * H, IN); + if (gray_scale) { + index = 0; + for (j = 0; j < W * H; j++) { + if ((j % W < W - 1 && Info_h.biWidth % 2) || !(Info_h.biWidth % 2)) { + image->comps[0].data[index] = table_R[RGB[W * H - ((j) / (W) + 1) * W + (j) % (W)]]; + index++; + } + } + + } else { + index = 0; + for (j = 0; j < W * H; j++) { + if ((j % W < W - 1 && Info_h.biWidth % 2) || !(Info_h.biWidth % 2)) { + unsigned char pixel_index = RGB[W * H - ((j) / (W) + 1) * W + (j) % (W)]; + image->comps[0].data[index] = table_R[pixel_index]; + image->comps[1].data[index] = table_G[pixel_index]; + image->comps[2].data[index] = table_B[pixel_index]; + index++; + } + } + } + free(RGB); + free(table_R); + free(table_G); + free(table_B); + } else if (Info_h.biBitCount == 8 && Info_h.biCompression == 1) { + table_R = (unsigned char *) malloc(256 * sizeof(unsigned char)); + table_G = (unsigned char *) malloc(256 * sizeof(unsigned char)); + table_B = (unsigned char *) malloc(256 * sizeof(unsigned char)); + + for (j = 0; j < Info_h.biClrUsed; j++) { + table_B[j] = getc(IN); + table_G[j] = getc(IN); + table_R[j] = getc(IN); + getc(IN); + if (table_R[j] != table_G[j] && table_R[j] != table_B[j] && table_G[j] != table_B[j]) + gray_scale = 0; + } + + numcomps = gray_scale ? 1 : 3; + color_space = gray_scale ? CLRSPC_GRAY : CLRSPC_SRGB; + /* initialize image components */ + memset(&cmptparm[0], 0, 3 * sizeof(opj_image_cmptparm_t)); + for(i = 0; i < numcomps; i++) { + cmptparm[i].prec = 8; + cmptparm[i].bpp = 8; + cmptparm[i].sgnd = 0; + cmptparm[i].dx = subsampling_dx; + cmptparm[i].dy = subsampling_dy; + cmptparm[i].w = w; + cmptparm[i].h = h; + } + /* create the image */ + image = opj_image_create(numcomps, &cmptparm[0], color_space); + if(!image) { + fclose(IN); + return NULL; + } + + /* set image offset and reference grid */ + image->x0 = parameters->image_offset_x0; + image->y0 = parameters->image_offset_y0; + image->x1 = !image->x0 ? (w - 1) * subsampling_dx + 1 : image->x0 + (w - 1) * subsampling_dx + 1; + image->y1 = !image->y0 ? (h - 1) * subsampling_dy + 1 : image->y0 + (h - 1) * subsampling_dy + 1; + + /* set image data */ + + /* Place the cursor at the beginning of the image information */ + fseek(IN, 0, SEEK_SET); + fseek(IN, File_h.bfOffBits, SEEK_SET); + + RGB = (unsigned char *) malloc(Info_h.biWidth * Info_h.biHeight * sizeof(unsigned char)); + + while (not_end_file) { + v = getc(IN); + if (v) { + v2 = getc(IN); + for (i = 0; i < (int) v; i++) { + RGB[line * Info_h.biWidth + col] = v2; + col++; + } + } else { + v = getc(IN); + switch (v) { + case 0: + col = 0; + line++; + break; + case 1: + line++; + not_end_file = 0; + break; + case 2: + fprintf(stderr,"No Delta supported\n"); + opj_image_destroy(image); + fclose(IN); + return NULL; + default: + for (i = 0; i < v; i++) { + v2 = getc(IN); + RGB[line * Info_h.biWidth + col] = v2; + col++; + } + if (v % 2) + v2 = getc(IN); + break; + } + } + } + if (gray_scale) { + index = 0; + for (line = 0; line < Info_h.biHeight; line++) { + for (col = 0; col < Info_h.biWidth; col++) { + image->comps[0].data[index] = table_R[(int)RGB[(Info_h.biHeight - line - 1) * Info_h.biWidth + col]]; + index++; + } + } + } else { + index = 0; + for (line = 0; line < Info_h.biHeight; line++) { + for (col = 0; col < Info_h.biWidth; col++) { + unsigned char pixel_index = (int)RGB[(Info_h.biHeight - line - 1) * Info_h.biWidth + col]; + image->comps[0].data[index] = table_R[pixel_index]; + image->comps[1].data[index] = table_G[pixel_index]; + image->comps[2].data[index] = table_B[pixel_index]; + index++; + } + } + } + free(RGB); + free(table_R); + free(table_G); + free(table_B); + } else { + fprintf(stderr, + "Other system than 24 bits/pixels or 8 bits (no RLE coding) is not yet implemented [%d]\n", Info_h.biBitCount); + } + fclose(IN); + } + + return image; +} + +int imagetobmp(opj_image_t * image, const char *outfile) { + int w, h; + int i, pad; + FILE *fdest = NULL; + int adjustR, adjustG, adjustB; + + if (image->numcomps == 3 && image->comps[0].dx == image->comps[1].dx + && image->comps[1].dx == image->comps[2].dx + && image->comps[0].dy == image->comps[1].dy + && image->comps[1].dy == image->comps[2].dy + && image->comps[0].prec == image->comps[1].prec + && image->comps[1].prec == image->comps[2].prec) { + + /* -->> -->> -->> -->> + 24 bits color + <<-- <<-- <<-- <<-- */ + + fdest = fopen(outfile, "wb"); + if (!fdest) { + fprintf(stderr, "ERROR -> failed to open %s for writing\n", outfile); + return 1; + } + + w = image->comps[0].w; + h = image->comps[0].h; + + fprintf(fdest, "BM"); + + /* FILE HEADER */ + /* ------------- */ + fprintf(fdest, "%c%c%c%c", + (unsigned char) (h * w * 3 + 3 * h * (w % 2) + 54) & 0xff, + (unsigned char) ((h * w * 3 + 3 * h * (w % 2) + 54) >> 8) & 0xff, + (unsigned char) ((h * w * 3 + 3 * h * (w % 2) + 54) >> 16) & 0xff, + (unsigned char) ((h * w * 3 + 3 * h * (w % 2) + 54) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (0) & 0xff, ((0) >> 8) & 0xff, ((0) >> 16) & 0xff, ((0) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (54) & 0xff, ((54) >> 8) & 0xff,((54) >> 16) & 0xff, ((54) >> 24) & 0xff); + + /* INFO HEADER */ + /* ------------- */ + fprintf(fdest, "%c%c%c%c", (40) & 0xff, ((40) >> 8) & 0xff, ((40) >> 16) & 0xff, ((40) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (unsigned char) ((w) & 0xff), + (unsigned char) ((w) >> 8) & 0xff, + (unsigned char) ((w) >> 16) & 0xff, + (unsigned char) ((w) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (unsigned char) ((h) & 0xff), + (unsigned char) ((h) >> 8) & 0xff, + (unsigned char) ((h) >> 16) & 0xff, + (unsigned char) ((h) >> 24) & 0xff); + fprintf(fdest, "%c%c", (1) & 0xff, ((1) >> 8) & 0xff); + fprintf(fdest, "%c%c", (24) & 0xff, ((24) >> 8) & 0xff); + fprintf(fdest, "%c%c%c%c", (0) & 0xff, ((0) >> 8) & 0xff, ((0) >> 16) & 0xff, ((0) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (unsigned char) (3 * h * w + 3 * h * (w % 2)) & 0xff, + (unsigned char) ((h * w * 3 + 3 * h * (w % 2)) >> 8) & 0xff, + (unsigned char) ((h * w * 3 + 3 * h * (w % 2)) >> 16) & 0xff, + (unsigned char) ((h * w * 3 + 3 * h * (w % 2)) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (7834) & 0xff, ((7834) >> 8) & 0xff, ((7834) >> 16) & 0xff, ((7834) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (7834) & 0xff, ((7834) >> 8) & 0xff, ((7834) >> 16) & 0xff, ((7834) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (0) & 0xff, ((0) >> 8) & 0xff, ((0) >> 16) & 0xff, ((0) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (0) & 0xff, ((0) >> 8) & 0xff, ((0) >> 16) & 0xff, ((0) >> 24) & 0xff); + + if (image->comps[0].prec > 8) { + adjustR = image->comps[0].prec - 8; + printf("BMP CONVERSION: Truncating component 0 from %d bits to 8 bits\n", image->comps[0].prec); + } + else + adjustR = 0; + if (image->comps[1].prec > 8) { + adjustG = image->comps[1].prec - 8; + printf("BMP CONVERSION: Truncating component 1 from %d bits to 8 bits\n", image->comps[1].prec); + } + else + adjustG = 0; + if (image->comps[2].prec > 8) { + adjustB = image->comps[2].prec - 8; + printf("BMP CONVERSION: Truncating component 2 from %d bits to 8 bits\n", image->comps[2].prec); + } + else + adjustB = 0; + + for (i = 0; i < w * h; i++) { + unsigned char rc, gc, bc; + int r, g, b; + + r = image->comps[0].data[w * h - ((i) / (w) + 1) * w + (i) % (w)]; + r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0); + rc = (unsigned char) ((r >> adjustR)+((r >> (adjustR-1))%2)); + g = image->comps[1].data[w * h - ((i) / (w) + 1) * w + (i) % (w)]; + g += (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0); + gc = (unsigned char) ((g >> adjustG)+((g >> (adjustG-1))%2)); + b = image->comps[2].data[w * h - ((i) / (w) + 1) * w + (i) % (w)]; + b += (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0); + bc = (unsigned char) ((b >> adjustB)+((b >> (adjustB-1))%2)); + + fprintf(fdest, "%c%c%c", bc, gc, rc); + + if ((i + 1) % w == 0) { + for (pad = (3 * w) % 4 ? 4 - (3 * w) % 4 : 0; pad > 0; pad--) /* ADD */ + fprintf(fdest, "%c", 0); + } + } + fclose(fdest); + } else { /* Gray-scale */ + + /* -->> -->> -->> -->> + 8 bits non code (Gray scale) + <<-- <<-- <<-- <<-- */ + + fdest = fopen(outfile, "wb"); + w = image->comps[0].w; + h = image->comps[0].h; + + fprintf(fdest, "BM"); + + /* FILE HEADER */ + /* ------------- */ + fprintf(fdest, "%c%c%c%c", (unsigned char) (h * w + 54 + 1024 + h * (w % 2)) & 0xff, + (unsigned char) ((h * w + 54 + 1024 + h * (w % 2)) >> 8) & 0xff, + (unsigned char) ((h * w + 54 + 1024 + h * (w % 2)) >> 16) & 0xff, + (unsigned char) ((h * w + 54 + 1024 + w * (w % 2)) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (0) & 0xff, ((0) >> 8) & 0xff, ((0) >> 16) & 0xff, ((0) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (54 + 1024) & 0xff, ((54 + 1024) >> 8) & 0xff, + ((54 + 1024) >> 16) & 0xff, + ((54 + 1024) >> 24) & 0xff); + + /* INFO HEADER */ + /* ------------- */ + fprintf(fdest, "%c%c%c%c", (40) & 0xff, ((40) >> 8) & 0xff, ((40) >> 16) & 0xff, ((40) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (unsigned char) ((w) & 0xff), + (unsigned char) ((w) >> 8) & 0xff, + (unsigned char) ((w) >> 16) & 0xff, + (unsigned char) ((w) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (unsigned char) ((h) & 0xff), + (unsigned char) ((h) >> 8) & 0xff, + (unsigned char) ((h) >> 16) & 0xff, + (unsigned char) ((h) >> 24) & 0xff); + fprintf(fdest, "%c%c", (1) & 0xff, ((1) >> 8) & 0xff); + fprintf(fdest, "%c%c", (8) & 0xff, ((8) >> 8) & 0xff); + fprintf(fdest, "%c%c%c%c", (0) & 0xff, ((0) >> 8) & 0xff, ((0) >> 16) & 0xff, ((0) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (unsigned char) (h * w + h * (w % 2)) & 0xff, + (unsigned char) ((h * w + h * (w % 2)) >> 8) & 0xff, + (unsigned char) ((h * w + h * (w % 2)) >> 16) & 0xff, + (unsigned char) ((h * w + h * (w % 2)) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (7834) & 0xff, ((7834) >> 8) & 0xff, ((7834) >> 16) & 0xff, ((7834) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (7834) & 0xff, ((7834) >> 8) & 0xff, ((7834) >> 16) & 0xff, ((7834) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (256) & 0xff, ((256) >> 8) & 0xff, ((256) >> 16) & 0xff, ((256) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (256) & 0xff, ((256) >> 8) & 0xff, ((256) >> 16) & 0xff, ((256) >> 24) & 0xff); + + if (image->comps[0].prec > 8) { + adjustR = image->comps[0].prec - 8; + printf("BMP CONVERSION: Truncating component 0 from %d bits to 8 bits\n", image->comps[0].prec); + }else + adjustR = 0; + + for (i = 0; i < 256; i++) { + fprintf(fdest, "%c%c%c%c", i, i, i, 0); + } + + for (i = 0; i < w * h; i++) { + unsigned char rc; + int r; + + r = image->comps[0].data[w * h - ((i) / (w) + 1) * w + (i) % (w)]; + r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0); + rc = (unsigned char) ((r >> adjustR)+((r >> (adjustR-1))%2)); + + fprintf(fdest, "%c", rc); + + if ((i + 1) % w == 0) { + for (pad = w % 4 ? 4 - w % 4 : 0; pad > 0; pad--) /* ADD */ + fprintf(fdest, "%c", 0); + } + } + fclose(fdest); + } + + return 0; +} + +/* -->> -->> -->> -->> + +PGX IMAGE FORMAT + +<<-- <<-- <<-- <<-- */ + + +unsigned char readuchar(FILE * f) +{ + unsigned char c1; + fread(&c1, 1, 1, f); + return c1; +} + +unsigned short readushort(FILE * f, int bigendian) +{ + unsigned char c1, c2; + fread(&c1, 1, 1, f); + fread(&c2, 1, 1, f); + if (bigendian) + return (c1 << 8) + c2; + else + return (c2 << 8) + c1; +} + +unsigned int readuint(FILE * f, int bigendian) +{ + unsigned char c1, c2, c3, c4; + fread(&c1, 1, 1, f); + fread(&c2, 1, 1, f); + fread(&c3, 1, 1, f); + fread(&c4, 1, 1, f); + if (bigendian) + return (c1 << 24) + (c2 << 16) + (c3 << 8) + c4; + else + return (c4 << 24) + (c3 << 16) + (c2 << 8) + c1; +} + +opj_image_t* pgxtoimage(const char *filename, opj_cparameters_t *parameters) { + FILE *f = NULL; + int w, h, prec; + int i, numcomps, max; + OPJ_COLOR_SPACE color_space; + opj_image_cmptparm_t cmptparm; /* maximum of 1 component */ + opj_image_t * image = NULL; + + char endian1,endian2,sign; + char signtmp[32]; + + char temp[32]; + int bigendian; + opj_image_comp_t *comp = NULL; + + numcomps = 1; + color_space = CLRSPC_GRAY; + + memset(&cmptparm, 0, sizeof(opj_image_cmptparm_t)); + + max = 0; + + f = fopen(filename, "rb"); + if (!f) { + fprintf(stderr, "Failed to open %s for reading !\n", filename); + return NULL; + } + + fseek(f, 0, SEEK_SET); + fscanf(f, "PG%[ \t]%c%c%[ \t+-]%d%[ \t]%d%[ \t]%d",temp,&endian1,&endian2,signtmp,&prec,temp,&w,temp,&h); + + i=0; + sign='+'; + while (signtmp[i]!='\0') { + if (signtmp[i]=='-') sign='-'; + i++; + } + + fgetc(f); + if (endian1=='M' && endian2=='L') { + bigendian = 1; + } else if (endian2=='M' && endian1=='L') { + bigendian = 0; + } else { + fprintf(stderr, "Bad pgx header, please check input file\n"); + return NULL; + } + + /* initialize image component */ + + cmptparm.x0 = parameters->image_offset_x0; + cmptparm.y0 = parameters->image_offset_y0; + cmptparm.w = !cmptparm.x0 ? (w - 1) * parameters->subsampling_dx + 1 : cmptparm.x0 + (w - 1) * parameters->subsampling_dx + 1; + cmptparm.h = !cmptparm.y0 ? (h - 1) * parameters->subsampling_dy + 1 : cmptparm.y0 + (h - 1) * parameters->subsampling_dy + 1; + + if (sign == '-') { + cmptparm.sgnd = 1; + } else { + cmptparm.sgnd = 0; + } + cmptparm.prec = prec; + cmptparm.bpp = prec; + cmptparm.dx = parameters->subsampling_dx; + cmptparm.dy = parameters->subsampling_dy; + + /* create the image */ + image = opj_image_create(numcomps, &cmptparm, color_space); + if(!image) { + fclose(f); + return NULL; + } + /* set image offset and reference grid */ + image->x0 = cmptparm.x0; + image->y0 = cmptparm.x0; + image->x1 = cmptparm.w; + image->y1 = cmptparm.h; + + /* set image data */ + + comp = &image->comps[0]; + + for (i = 0; i < w * h; i++) { + int v; + if (comp->prec <= 8) { + if (!comp->sgnd) { + v = readuchar(f); + } else { + v = (char) readuchar(f); + } + } else if (comp->prec <= 16) { + if (!comp->sgnd) { + v = readushort(f, bigendian); + } else { + v = (short) readushort(f, bigendian); + } + } else { + if (!comp->sgnd) { + v = readuint(f, bigendian); + } else { + v = (int) readuint(f, bigendian); + } + } + if (v > max) + max = v; + comp->data[i] = v; + } + fclose(f); + comp->bpp = int_floorlog2(max) + 1; + + return image; +} + +int imagetopgx(opj_image_t * image, const char *outfile) { + int w, h; + int i, j, compno; + FILE *fdest = NULL; + + for (compno = 0; compno < image->numcomps; compno++) { + opj_image_comp_t *comp = &image->comps[compno]; + char bname[256]; /* buffer for name */ + char *name = bname; /* pointer */ + int nbytes = 0; + const size_t olen = strlen(outfile); + const size_t dotpos = olen - 4; + const size_t total = dotpos + 1 + 1 + 4; /* '-' + '[1-3]' + '.pgx' */ + if( outfile[dotpos] != '.' ) { + /* `pgx` was recognized but there is no dot at expected position */ + fprintf(stderr, "ERROR -> Impossible happen." ); + return 1; + } + if( total > 256 ) { + name = (char*)malloc(total+1); + } + strncpy(name, outfile, dotpos); + if (image->numcomps > 1) { + sprintf(name+dotpos, "-%d.pgx", compno); + } else { + strcpy(name+dotpos, ".pgx"); + } + fdest = fopen(name, "wb"); + if (!fdest) { + fprintf(stderr, "ERROR -> failed to open %s for writing\n", name); + return 1; + } + /* dont need name anymore */ + if( total > 256 ) { + free(name); + } + + w = image->comps[compno].w; + h = image->comps[compno].h; + + fprintf(fdest, "PG ML %c %d %d %d\n", comp->sgnd ? '-' : '+', comp->prec, w, h); + if (comp->prec <= 8) { + nbytes = 1; + } else if (comp->prec <= 16) { + nbytes = 2; + } else { + nbytes = 4; + } + for (i = 0; i < w * h; i++) { + int v = image->comps[compno].data[i]; + for (j = nbytes - 1; j >= 0; j--) { + char byte = (char) (v >> (j * 8)); + fwrite(&byte, 1, 1, fdest); + } + } + fclose(fdest); + } + + return 0; +} + +/* -->> -->> -->> -->> + +PNM IMAGE FORMAT + +<<-- <<-- <<-- <<-- */ + +opj_image_t* pnmtoimage(const char *filename, opj_cparameters_t *parameters) { + int subsampling_dx = parameters->subsampling_dx; + int subsampling_dy = parameters->subsampling_dy; + + FILE *f = NULL; + int i, compno, numcomps, w, h; + OPJ_COLOR_SPACE color_space; + opj_image_cmptparm_t cmptparm[3]; /* maximum of 3 components */ + opj_image_t * image = NULL; + char value; + + f = fopen(filename, "rb"); + if (!f) { + fprintf(stderr, "Failed to open %s for reading !!\n", filename); + return 0; + } + + if (fgetc(f) != 'P') + return 0; + value = fgetc(f); + + switch(value) { + case '2': /* greyscale image type */ + case '5': + numcomps = 1; + color_space = CLRSPC_GRAY; + break; + + case '3': /* RGB image type */ + case '6': + numcomps = 3; + color_space = CLRSPC_SRGB; + break; + + default: + fclose(f); + return NULL; + } + + fgetc(f); + + /* skip comments */ + while(fgetc(f) == '#') while(fgetc(f) != '\n'); + + fseek(f, -1, SEEK_CUR); + fscanf(f, "%d %d\n255", &w, &h); + fgetc(f); /* */ + + /* initialize image components */ + memset(&cmptparm[0], 0, 3 * sizeof(opj_image_cmptparm_t)); + for(i = 0; i < numcomps; i++) { + cmptparm[i].prec = 8; + cmptparm[i].bpp = 8; + cmptparm[i].sgnd = 0; + cmptparm[i].dx = subsampling_dx; + cmptparm[i].dy = subsampling_dy; + cmptparm[i].w = w; + cmptparm[i].h = h; + } + /* create the image */ + image = opj_image_create(numcomps, &cmptparm[0], color_space); + if(!image) { + fclose(f); + return NULL; + } + + /* set image offset and reference grid */ + image->x0 = parameters->image_offset_x0; + image->y0 = parameters->image_offset_y0; + image->x1 = parameters->image_offset_x0 + (w - 1) * subsampling_dx + 1; + image->y1 = parameters->image_offset_y0 + (h - 1) * subsampling_dy + 1; + + /* set image data */ + + if ((value == '2') || (value == '3')) { /* ASCII */ + for (i = 0; i < w * h; i++) { + for(compno = 0; compno < numcomps; compno++) { + unsigned int index = 0; + fscanf(f, "%u", &index); + /* compno : 0 = GREY, (0, 1, 2) = (R, G, B) */ + image->comps[compno].data[i] = index; + } + } + } else if ((value == '5') || (value == '6')) { /* BINARY */ + for (i = 0; i < w * h; i++) { + for(compno = 0; compno < numcomps; compno++) { + unsigned char index = 0; + fread(&index, 1, 1, f); + /* compno : 0 = GREY, (0, 1, 2) = (R, G, B) */ + image->comps[compno].data[i] = index; + } + } + } + + fclose(f); + + return image; +} + +int imagetopnm(opj_image_t * image, const char *outfile) { + int w, wr, h, hr, max; + int i, compno; + int adjustR, adjustG, adjustB, adjustX; + FILE *fdest = NULL; + char S2; + const char *tmp = outfile; + + while (*tmp) { + tmp++; + } + tmp--; + tmp--; + S2 = *tmp; + + if (image->numcomps == 3 && image->comps[0].dx == image->comps[1].dx + && image->comps[1].dx == image->comps[2].dx + && image->comps[0].dy == image->comps[1].dy + && image->comps[1].dy == image->comps[2].dy + && image->comps[0].prec == image->comps[1].prec + && image->comps[1].prec == image->comps[2].prec + && S2 !='g' && S2 !='G') { + + fdest = fopen(outfile, "wb"); + if (!fdest) { + fprintf(stderr, "ERROR -> failed to open %s for writing\n", outfile); + return 1; + } + + w = int_ceildiv(image->x1 - image->x0, image->comps[0].dx); + wr = image->comps[0].w; + + h = int_ceildiv(image->y1 - image->y0, image->comps[0].dy); + hr = image->comps[0].h; + + max = image->comps[0].prec > 8 ? 255 : (1 << image->comps[0].prec) - 1; + + image->comps[0].x0 = int_ceildivpow2(image->comps[0].x0 - int_ceildiv(image->x0, image->comps[0].dx), image->comps[0].factor); + image->comps[0].y0 = int_ceildivpow2(image->comps[0].y0 - int_ceildiv(image->y0, image->comps[0].dy), image->comps[0].factor); + + fprintf(fdest, "P6\n%d %d\n%d\n", wr, hr, max); + + if (image->comps[0].prec > 8) { + adjustR = image->comps[0].prec - 8; + printf("PNM CONVERSION: Truncating component 0 from %d bits to 8 bits\n", image->comps[0].prec); + } + else + adjustR = 0; + if (image->comps[1].prec > 8) { + adjustG = image->comps[1].prec - 8; + printf("PNM CONVERSION: Truncating component 1 from %d bits to 8 bits\n", image->comps[1].prec); + } + else + adjustG = 0; + if (image->comps[2].prec > 8) { + adjustB = image->comps[2].prec - 8; + printf("PNM CONVERSION: Truncating component 2 from %d bits to 8 bits\n", image->comps[2].prec); + } + else + adjustB = 0; + + + for (i = 0; i < wr * hr; i++) { + int r, g, b; + unsigned char rc,gc,bc; + r = image->comps[0].data[i]; + r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0); + rc = (unsigned char) ((r >> adjustR)+((r >> (adjustR-1))%2)); + + g = image->comps[1].data[i]; + g += (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0); + gc = (unsigned char) ((g >> adjustG)+((g >> (adjustG-1))%2)); + + b = image->comps[2].data[i]; + b += (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0); + bc = (unsigned char) ((b >> adjustB)+((b >> (adjustB-1))%2)); + + fprintf(fdest, "%c%c%c", rc, gc, bc); + } + fclose(fdest); + + } else { + int ncomp=(S2=='g' || S2=='G')?1:image->numcomps; + if (image->numcomps > ncomp) { + fprintf(stderr,"WARNING -> [PGM files] Only the first component\n"); + fprintf(stderr," is written to the file\n"); + } + for (compno = 0; compno < ncomp; compno++) { + char name[256]; + if (ncomp > 1) { + sprintf(name, "%d.%s", compno, outfile); + } else { + sprintf(name, "%s", outfile); + } + + fdest = fopen(name, "wb"); + if (!fdest) { + fprintf(stderr, "ERROR -> failed to open %s for writing\n", name); + return 1; + } + + w = int_ceildiv(image->x1 - image->x0, image->comps[compno].dx); + wr = image->comps[compno].w; + + h = int_ceildiv(image->y1 - image->y0, image->comps[compno].dy); + hr = image->comps[compno].h; + + max = image->comps[compno].prec > 8 ? 255 : (1 << image->comps[compno].prec) - 1; + + image->comps[compno].x0 = int_ceildivpow2(image->comps[compno].x0 - int_ceildiv(image->x0, image->comps[compno].dx), image->comps[compno].factor); + image->comps[compno].y0 = int_ceildivpow2(image->comps[compno].y0 - int_ceildiv(image->y0, image->comps[compno].dy), image->comps[compno].factor); + + fprintf(fdest, "P5\n%d %d\n%d\n", wr, hr, max); + + if (image->comps[compno].prec > 8) { + adjustX = image->comps[0].prec - 8; + printf("PNM CONVERSION: Truncating component %d from %d bits to 8 bits\n",compno, image->comps[compno].prec); + } + else + adjustX = 0; + + for (i = 0; i < wr * hr; i++) { + int l; + unsigned char lc; + l = image->comps[compno].data[i]; + l += (image->comps[compno].sgnd ? 1 << (image->comps[compno].prec - 1) : 0); + lc = (unsigned char) ((l >> adjustX)+((l >> (adjustX-1))%2)); + fprintf(fdest, "%c", lc); + } + fclose(fdest); + } + } + + return 0; +} + +#ifdef HAVE_LIBTIFF +/* -->> -->> -->> -->> + + TIFF IMAGE FORMAT + + <<-- <<-- <<-- <<-- */ + +typedef struct tiff_infoheader{ + DWORD tiWidth; // Width of Image in pixel + DWORD tiHeight; // Height of Image in pixel + DWORD tiPhoto; // Photometric + WORD tiBps; // Bits per sample + WORD tiSf; // Sample Format + WORD tiSpp; // Sample per pixel 1-bilevel,gray scale , 2- RGB + WORD tiPC; // Planar config (1-Interleaved, 2-Planarcomp) +}tiff_infoheader_t; + +int imagetotif(opj_image_t * image, const char *outfile) { + int width, height, imgsize; + int bps,index,adjust = 0; + int last_i=0; + TIFF *tif; + tdata_t buf; + tstrip_t strip; + tsize_t strip_size; + + if (image->numcomps == 3 && image->comps[0].dx == image->comps[1].dx + && image->comps[1].dx == image->comps[2].dx + && image->comps[0].dy == image->comps[1].dy + && image->comps[1].dy == image->comps[2].dy + && image->comps[0].prec == image->comps[1].prec + && image->comps[1].prec == image->comps[2].prec) { + + /* -->> -->> -->> + RGB color + <<-- <<-- <<-- */ + + tif = TIFFOpen(outfile, "wb"); + if (!tif) { + fprintf(stderr, "ERROR -> failed to open %s for writing\n", outfile); + return 1; + } + + width = image->comps[0].w; + height = image->comps[0].h; + imgsize = width * height ; + bps = image->comps[0].prec; + /* Set tags */ + TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width); + TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height); + TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3); + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bps); + TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); + TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); + TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, 1); + + /* Get a buffer for the data */ + strip_size=TIFFStripSize(tif); + buf = _TIFFmalloc(strip_size); + index=0; + adjust = image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0; + for (strip = 0; strip < TIFFNumberOfStrips(tif); strip++) { + unsigned char *dat8; + tsize_t i, ssize; + ssize = TIFFStripSize(tif); + dat8 = (unsigned char*)buf; + if (image->comps[0].prec == 8){ + for (i=0; icomps[0].data[index]; + g = image->comps[1].data[index]; + b = image->comps[2].data[index]; + if (image->comps[0].sgnd){ + r += adjust; + g += adjust; + b += adjust; + } + dat8[i+0] = r ; // R + dat8[i+1] = g ; // G + dat8[i+2] = b ; // B + index++; + last_i = i+3; + }else + break; + } + if(last_i < ssize){ + for (i=last_i; icomps[0].data[index]; + g = image->comps[1].data[index]; + b = image->comps[2].data[index]; + if (image->comps[0].sgnd){ + r += adjust; + g += adjust; + b += adjust; + } + dat8[i+0] = r ; // R + if(i+1 comps[0].prec == 12){ + for (i=0; icomps[0].data[index]; + g = image->comps[1].data[index]; + b = image->comps[2].data[index]; + r1 = image->comps[0].data[index+1]; + g1 = image->comps[1].data[index+1]; + b1 = image->comps[2].data[index+1]; + if (image->comps[0].sgnd){ + r += adjust; + g += adjust; + b += adjust; + r1 += adjust; + g1 += adjust; + b1 += adjust; + } + dat8[i+0] = (r >> 4); + dat8[i+1] = ((r & 0x0f) << 4 )|((g >> 8)& 0x0f); + dat8[i+2] = g ; + dat8[i+3] = (b >> 4); + dat8[i+4] = ((b & 0x0f) << 4 )|((r1 >> 8)& 0x0f); + dat8[i+5] = r1; + dat8[i+6] = (g1 >> 4); + dat8[i+7] = ((g1 & 0x0f)<< 4 )|((b1 >> 8)& 0x0f); + dat8[i+8] = b1; + index+=2; + last_i = i+9; + }else + break; + } + if(last_i < ssize){ + for (i= last_i; icomps[0].data[index]; + g = image->comps[1].data[index]; + b = image->comps[2].data[index]; + r1 = image->comps[0].data[index+1]; + g1 = image->comps[1].data[index+1]; + b1 = image->comps[2].data[index+1]; + if (image->comps[0].sgnd){ + r += adjust; + g += adjust; + b += adjust; + r1 += adjust; + g1 += adjust; + b1 += adjust; + } + dat8[i+0] = (r >> 4); + if(i+1 > 8)& 0x0f); else break; + if(i+2 > 4); else break; + if(i+4 > 8)& 0x0f);else break; + if(i+5 > 4); else break; + if(i+7 > 8)& 0x0f);else break; + if(i+8 comps[0].prec == 16){ + for (i=0 ; icomps[0].data[index]; + g = image->comps[1].data[index]; + b = image->comps[2].data[index]; + if (image->comps[0].sgnd){ + r += adjust; + g += adjust; + b += adjust; + } + dat8[i+0] = r;//LSB + dat8[i+1] = (r >> 8);//MSB + dat8[i+2] = g; + dat8[i+3] = (g >> 8); + dat8[i+4] = b; + dat8[i+5] = (b >> 8); + index++; + last_i = i+6; + }else + break; + } + if(last_i < ssize){ + for (i=0 ; icomps[0].data[index]; + g = image->comps[1].data[index]; + b = image->comps[2].data[index]; + if (image->comps[0].sgnd){ + r += adjust; + g += adjust; + b += adjust; + } + dat8[i+0] = r;//LSB + if(i+1 > 8);else break;//MSB + if(i+2 > 8);else break; + if(i+4 > 8);else break; + index++; + }else + break; + } + } + }else{ + fprintf(stderr,"Bits=%d, Only 8,12,16 bits implemented\n",image->comps[0].prec); + fprintf(stderr,"Aborting\n"); + return 1; + } + (void)TIFFWriteEncodedStrip(tif, strip, (void*)buf, strip_size); + } + _TIFFfree((void*)buf); + TIFFClose(tif); + }else if (image->numcomps == 1){ + /* -->> -->> -->> + Black and White + <<-- <<-- <<-- */ + + tif = TIFFOpen(outfile, "wb"); + if (!tif) { + fprintf(stderr, "ERROR -> failed to open %s for writing\n", outfile); + return 1; + } + + width = image->comps[0].w; + height = image->comps[0].h; + imgsize = width * height; + bps = image->comps[0].prec; + + /* Set tags */ + TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width); + TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height); + TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1); + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bps); + TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); + TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); + TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, 1); + + /* Get a buffer for the data */ + strip_size = TIFFStripSize(tif); + buf = _TIFFmalloc(strip_size); + index = 0; + for (strip = 0; strip < TIFFNumberOfStrips(tif); strip++) { + unsigned char *dat8; + tsize_t i; + dat8 = (unsigned char*)buf; + if (image->comps[0].prec == 8){ + for (i=0; icomps[0].data[index]; + if (image->comps[0].sgnd){ + r += adjust; + } + dat8[i+0] = r; + index++; + }else + break; + } + }else if (image->comps[0].prec == 12){ + for (i = 0; icomps[0].data[index]; + r1 = image->comps[0].data[index+1]; + if (image->comps[0].sgnd){ + r += adjust; + r1 += adjust; + } + dat8[i+0] = (r >> 4); + dat8[i+1] = ((r & 0x0f) << 4 )|((r1 >> 8)& 0x0f); + dat8[i+2] = r1 ; + index+=2; + }else + break; + } + }else if (image->comps[0].prec == 16){ + for (i=0; icomps[0].data[index]; + if (image->comps[0].sgnd){ + r += adjust; + } + dat8[i+0] = r; + dat8[i+1] = r >> 8; + index++; + }else + break; + } + }else{ + fprintf(stderr,"TIFF file creation. Bits=%d, Only 8,12,16 bits implemented\n",image->comps[0].prec); + fprintf(stderr,"Aborting\n"); + return 1; + } + (void)TIFFWriteEncodedStrip(tif, strip, (void*)buf, strip_size); + } + _TIFFfree(buf); + TIFFClose(tif); + }else{ + fprintf(stderr,"TIFF file creation. Bad color format. Only RGB & Grayscale has been implemented\n"); + fprintf(stderr,"Aborting\n"); + return 1; + } + return 0; +} + +opj_image_t* tiftoimage(const char *filename, opj_cparameters_t *parameters) +{ + int subsampling_dx = parameters->subsampling_dx; + int subsampling_dy = parameters->subsampling_dy; + TIFF *tif; + tiff_infoheader_t Info; + tdata_t buf; + tstrip_t strip; + tsize_t strip_size; + int j, numcomps, w, h,index; + OPJ_COLOR_SPACE color_space; + opj_image_cmptparm_t cmptparm[3]; + opj_image_t * image = NULL; + int imgsize = 0; + + tif = TIFFOpen(filename, "r"); + + if (!tif) { + fprintf(stderr, "Failed to open %s for reading\n", filename); + return 0; + } + + TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &Info.tiWidth); + TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &Info.tiHeight); + TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &Info.tiBps); + TIFFGetField(tif, TIFFTAG_SAMPLEFORMAT, &Info.tiSf); + TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &Info.tiSpp); + Info.tiPhoto = 0; + TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &Info.tiPhoto); + TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &Info.tiPC); + w= Info.tiWidth; + h= Info.tiHeight; + + if (Info.tiPhoto == 2) { + /* -->> -->> -->> + RGB color + <<-- <<-- <<-- */ + + numcomps = 3; + color_space = CLRSPC_SRGB; + /* initialize image components*/ + memset(&cmptparm[0], 0, 3 * sizeof(opj_image_cmptparm_t)); + for(j = 0; j < numcomps; j++) { + if (parameters->cp_cinema) { + cmptparm[j].prec = 12; + cmptparm[j].bpp = 12; + }else{ + cmptparm[j].prec = Info.tiBps; + cmptparm[j].bpp = Info.tiBps; + } + cmptparm[j].sgnd = 0; + cmptparm[j].dx = subsampling_dx; + cmptparm[j].dy = subsampling_dy; + cmptparm[j].w = w; + cmptparm[j].h = h; + } + /* create the image*/ + image = opj_image_create(numcomps, &cmptparm[0], color_space); + if(!image) { + TIFFClose(tif); + return NULL; + } + + /* set image offset and reference grid */ + image->x0 = parameters->image_offset_x0; + image->y0 = parameters->image_offset_y0; + image->x1 = !image->x0 ? (w - 1) * subsampling_dx + 1 : image->x0 + (w - 1) * subsampling_dx + 1; + image->y1 = !image->y0 ? (h - 1) * subsampling_dy + 1 : image->y0 + (h - 1) * subsampling_dy + 1; + + buf = _TIFFmalloc(TIFFStripSize(tif)); + strip_size=0; + strip_size=TIFFStripSize(tif); + index = 0; + imgsize = image->comps[0].w * image->comps[0].h ; + /* Read the Image components*/ + for (strip = 0; strip < TIFFNumberOfStrips(tif); strip++) { + unsigned char *dat8; + int i, ssize; + ssize = TIFFReadEncodedStrip(tif, strip, buf, strip_size); + dat8 = (unsigned char*)buf; + + if (Info.tiBps==12){ + for (i=0; icomps[0].data[index] = ( dat8[i+0]<<4 ) |(dat8[i+1]>>4); + image->comps[1].data[index] = ((dat8[i+1]& 0x0f)<< 8) | dat8[i+2]; + image->comps[2].data[index] = ( dat8[i+3]<<4) |(dat8[i+4]>>4); + image->comps[0].data[index+1] = ((dat8[i+4]& 0x0f)<< 8) | dat8[i+5]; + image->comps[1].data[index+1] = ( dat8[i+6] <<4) |(dat8[i+7]>>4); + image->comps[2].data[index+1] = ((dat8[i+7]& 0x0f)<< 8) | dat8[i+8]; + index+=2; + }else + break; + } + } + else if( Info.tiBps==16){ + for (i=0; icomps[0].data[index] = ( dat8[i+1] << 8 ) | dat8[i+0]; // R + image->comps[1].data[index] = ( dat8[i+3] << 8 ) | dat8[i+2]; // G + image->comps[2].data[index] = ( dat8[i+5] << 8 ) | dat8[i+4]; // B + if(parameters->cp_cinema){/* Rounding to 12 bits*/ + image->comps[0].data[index] = (image->comps[0].data[index] + 0x08) >> 4 ; + image->comps[1].data[index] = (image->comps[1].data[index] + 0x08) >> 4 ; + image->comps[2].data[index] = (image->comps[2].data[index] + 0x08) >> 4 ; + } + index++; + }else + break; + } + } + else if ( Info.tiBps==8){ + for (i=0; icomps[0].data[index] = dat8[i+0];// R + image->comps[1].data[index] = dat8[i+1];// G + image->comps[2].data[index] = dat8[i+2];// B + if(parameters->cp_cinema){/* Rounding to 12 bits*/ + image->comps[0].data[index] = image->comps[0].data[index] << 4 ; + image->comps[1].data[index] = image->comps[1].data[index] << 4 ; + image->comps[2].data[index] = image->comps[2].data[index] << 4 ; + } + index++; + }else + break; + } + } + else{ + fprintf(stderr,"TIFF file creation. Bits=%d, Only 8,12,16 bits implemented\n",Info.tiBps); + fprintf(stderr,"Aborting\n"); + return NULL; + } + } + + _TIFFfree(buf); + TIFFClose(tif); + }else if(Info.tiPhoto == 1) { + /* -->> -->> -->> + Black and White + <<-- <<-- <<-- */ + + numcomps = 1; + color_space = CLRSPC_GRAY; + /* initialize image components*/ + memset(&cmptparm[0], 0, sizeof(opj_image_cmptparm_t)); + cmptparm[0].prec = Info.tiBps; + cmptparm[0].bpp = Info.tiBps; + cmptparm[0].sgnd = 0; + cmptparm[0].dx = subsampling_dx; + cmptparm[0].dy = subsampling_dy; + cmptparm[0].w = w; + cmptparm[0].h = h; + + /* create the image*/ + image = opj_image_create(numcomps, &cmptparm[0], color_space); + if(!image) { + TIFFClose(tif); + return NULL; + } + /* set image offset and reference grid */ + image->x0 = parameters->image_offset_x0; + image->y0 = parameters->image_offset_y0; + image->x1 = !image->x0 ? (w - 1) * subsampling_dx + 1 : image->x0 + (w - 1) * subsampling_dx + 1; + image->y1 = !image->y0 ? (h - 1) * subsampling_dy + 1 : image->y0 + (h - 1) * subsampling_dy + 1; + + buf = _TIFFmalloc(TIFFStripSize(tif)); + strip_size = 0; + strip_size = TIFFStripSize(tif); + index = 0; + imgsize = image->comps[0].w * image->comps[0].h ; + /* Read the Image components*/ + for (strip = 0; strip < TIFFNumberOfStrips(tif); strip++) { + unsigned char *dat8; + int i, ssize; + ssize = TIFFReadEncodedStrip(tif, strip, buf, strip_size); + dat8 = (unsigned char*)buf; + + if (Info.tiBps==12){ + for (i=0; icomps[0].data[index] = ( dat8[i+0]<<4 ) |(dat8[i+1]>>4) ; + image->comps[0].data[index+1] = ((dat8[i+1]& 0x0f)<< 8) | dat8[i+2]; + index+=2; + }else + break; + } + } + else if( Info.tiBps==16){ + for (i=0; icomps[0].data[index] = ( dat8[i+1] << 8 ) | dat8[i+0]; + index++; + }else + break; + } + } + else if ( Info.tiBps==8){ + for (i=0; icomps[0].data[index] = dat8[i+0]; + index++; + }else + break; + } + } + else{ + fprintf(stderr,"TIFF file creation. Bits=%d, Only 8,12,16 bits implemented\n",Info.tiBps); + fprintf(stderr,"Aborting\n"); + return NULL; + } + } + + _TIFFfree(buf); + TIFFClose(tif); + }else{ + fprintf(stderr,"TIFF file creation. Bad color format. Only RGB & Grayscale has been implemented\n"); + fprintf(stderr,"Aborting\n"); + return NULL; + } + return image; +} + +#endif /* HAVE_LIBTIFF */ + +/* -->> -->> -->> -->> + + RAW IMAGE FORMAT + + <<-- <<-- <<-- <<-- */ + +opj_image_t* rawtoimage(const char *filename, opj_cparameters_t *parameters, raw_cparameters_t *raw_cp) { + int subsampling_dx = parameters->subsampling_dx; + int subsampling_dy = parameters->subsampling_dy; + + FILE *f = NULL; + int i, compno, numcomps, w, h; + OPJ_COLOR_SPACE color_space; + opj_image_cmptparm_t *cmptparm; + opj_image_t * image = NULL; + unsigned short ch; + + if((! (raw_cp->rawWidth & raw_cp->rawHeight & raw_cp->rawComp & raw_cp->rawBitDepth)) == 0) + { + fprintf(stderr,"\nError: invalid raw image parameters\n"); + fprintf(stderr,"Please use the Format option -F:\n"); + fprintf(stderr,"-F rawWidth,rawHeight,rawComp,rawBitDepth,s/u (Signed/Unsigned)\n"); + fprintf(stderr,"Example: -i lena.raw -o lena.j2k -F 512,512,3,8,u\n"); + fprintf(stderr,"Aborting\n"); + return NULL; + } + + f = fopen(filename, "rb"); + if (!f) { + fprintf(stderr, "Failed to open %s for reading !!\n", filename); + fprintf(stderr,"Aborting\n"); + return NULL; + } + numcomps = raw_cp->rawComp; + color_space = CLRSPC_SRGB; + w = raw_cp->rawWidth; + h = raw_cp->rawHeight; + cmptparm = (opj_image_cmptparm_t*) malloc(numcomps * sizeof(opj_image_cmptparm_t)); + + /* initialize image components */ + memset(&cmptparm[0], 0, numcomps * sizeof(opj_image_cmptparm_t)); + for(i = 0; i < numcomps; i++) { + cmptparm[i].prec = raw_cp->rawBitDepth; + cmptparm[i].bpp = raw_cp->rawBitDepth; + cmptparm[i].sgnd = raw_cp->rawSigned; + cmptparm[i].dx = subsampling_dx; + cmptparm[i].dy = subsampling_dy; + cmptparm[i].w = w; + cmptparm[i].h = h; + } + /* create the image */ + image = opj_image_create(numcomps, &cmptparm[0], color_space); + if(!image) { + fclose(f); + return NULL; + } + /* set image offset and reference grid */ + image->x0 = parameters->image_offset_x0; + image->y0 = parameters->image_offset_y0; + image->x1 = parameters->image_offset_x0 + (w - 1) * subsampling_dx + 1; + image->y1 = parameters->image_offset_y0 + (h - 1) * subsampling_dy + 1; + + if(raw_cp->rawBitDepth <= 8) + { + unsigned char value = 0; + for(compno = 0; compno < numcomps; compno++) { + for (i = 0; i < w * h; i++) { + if (!fread(&value, 1, 1, f)) { + fprintf(stderr,"Error reading raw file. End of file probably reached.\n"); + return NULL; + } + image->comps[compno].data[i] = raw_cp->rawSigned?(char)value:value; + } + } + } + else if(raw_cp->rawBitDepth <= 16) + { + unsigned short value; + for(compno = 0; compno < numcomps; compno++) { + for (i = 0; i < w * h; i++) { + unsigned char temp; + if (!fread(&temp, 1, 1, f)) { + fprintf(stderr,"Error reading raw file. End of file probably reached.\n"); + return NULL; + } + value = temp << 8; + if (!fread(&temp, 1, 1, f)) { + fprintf(stderr,"Error reading raw file. End of file probably reached.\n"); + return NULL; + } + value += temp; + image->comps[compno].data[i] = raw_cp->rawSigned?(short)value:value; + } + } + } + else { + fprintf(stderr,"OpenJPEG cannot encode raw components with bit depth higher than 16 bits.\n"); + return NULL; + } + + if (fread(&ch, 1, 1, f)) { + fprintf(stderr,"Warning. End of raw file not reached... processing anyway\n"); + } + fclose(f); + + return image; +} + +int imagetoraw(opj_image_t * image, const char *outfile) +{ + FILE *rawFile = NULL; + int compno; + int w, h; + int line, row; + int *ptr; + + if((image->numcomps * image->x1 * image->y1) == 0) + { + fprintf(stderr,"\nError: invalid raw image parameters\n"); + return 1; + } + + rawFile = fopen(outfile, "wb"); + if (!rawFile) { + fprintf(stderr, "Failed to open %s for writing !!\n", outfile); + return 1; + } + + fprintf(stdout,"Raw image characteristics: %d components\n", image->numcomps); + + for(compno = 0; compno < image->numcomps; compno++) + { + fprintf(stdout,"Component %d characteristics: %dx%dx%d %s\n", compno, image->comps[compno].w, + image->comps[compno].h, image->comps[compno].prec, image->comps[compno].sgnd==1 ? "signed": "unsigned"); + + w = image->comps[compno].w; + h = image->comps[compno].h; + + if(image->comps[compno].prec <= 8) + { + if(image->comps[compno].sgnd == 1) + { + signed char curr; + int mask = (1 << image->comps[compno].prec) - 1; + ptr = image->comps[compno].data; + for (line = 0; line < h; line++) { + for(row = 0; row < w; row++) { + curr = (signed char) (*ptr & mask); + fwrite(&curr, sizeof(signed char), 1, rawFile); + ptr++; + } + } + } + else if(image->comps[compno].sgnd == 0) + { + unsigned char curr; + int mask = (1 << image->comps[compno].prec) - 1; + ptr = image->comps[compno].data; + for (line = 0; line < h; line++) { + for(row = 0; row < w; row++) { + curr = (unsigned char) (*ptr & mask); + fwrite(&curr, sizeof(unsigned char), 1, rawFile); + ptr++; + } + } + } + } + else if(image->comps[compno].prec <= 16) + { + if(image->comps[compno].sgnd == 1) + { + signed short int curr; + int mask = (1 << image->comps[compno].prec) - 1; + ptr = image->comps[compno].data; + for (line = 0; line < h; line++) { + for(row = 0; row < w; row++) { + unsigned char temp; + curr = (signed short int) (*ptr & mask); + temp = (unsigned char) (curr >> 8); + fwrite(&temp, 1, 1, rawFile); + temp = (unsigned char) curr; + fwrite(&temp, 1, 1, rawFile); + ptr++; + } + } + } + else if(image->comps[compno].sgnd == 0) + { + unsigned short int curr; + int mask = (1 << image->comps[compno].prec) - 1; + ptr = image->comps[compno].data; + for (line = 0; line < h; line++) { + for(row = 0; row < w; row++) { + unsigned char temp; + curr = (unsigned short int) (*ptr & mask); + temp = (unsigned char) (curr >> 8); + fwrite(&temp, 1, 1, rawFile); + temp = (unsigned char) curr; + fwrite(&temp, 1, 1, rawFile); + ptr++; + } + } + } + } + else if (image->comps[compno].prec <= 32) + { + fprintf(stderr,"More than 16 bits per component no handled yet\n"); + return 1; + } + else + { + fprintf(stderr,"Error: invalid precision: %d\n", image->comps[compno].prec); + return 1; + } + } + fclose(rawFile); + return 0; +} + +#ifdef HAVE_LIBPNG + +#define PNG_MAGIC "\x89PNG\x0d\x0a\x1a\x0a" +#define MAGIC_SIZE 8 +/* PNG allows bits per sample: 1, 2, 4, 8, 16 */ + +opj_image_t *pngtoimage(const char *read_idf, opj_cparameters_t * params) +{ + png_structp png; + png_infop info; + double gamma, display_exponent; + int bit_depth, interlace_type,compression_type, filter_type; + int unit; + png_uint_32 resx, resy; + unsigned int i, j; + png_uint_32 width, height; + int color_type, has_alpha, is16; + unsigned char *s; + FILE *reader; + unsigned char **rows; +/* j2k: */ + opj_image_t *image; + opj_image_cmptparm_t cmptparm[4]; + int sub_dx, sub_dy; + unsigned int nr_comp; + int *r, *g, *b, *a; + unsigned char sigbuf[8]; + + if((reader = fopen(read_idf, "rb")) == NULL) + { + fprintf(stderr,"pngtoimage: can not open %s\n",read_idf); + return NULL; + } + image = NULL; png = NULL; rows = NULL; + + if(fread(sigbuf, 1, MAGIC_SIZE, reader) != MAGIC_SIZE + || memcmp(sigbuf, PNG_MAGIC, MAGIC_SIZE) != 0) + { + fprintf(stderr,"pngtoimage: %s is no valid PNG file\n",read_idf); + goto fin; + } +/* libpng-VERSION/example.c: + * PC : screen_gamma = 2.2; + * Mac: screen_gamma = 1.7 or 1.0; +*/ + display_exponent = 2.2; + + if((png = png_create_read_struct(PNG_LIBPNG_VER_STRING, + NULL, NULL, NULL)) == NULL) + goto fin; + if((info = png_create_info_struct(png)) == NULL) + goto fin; + + if(setjmp(png_jmpbuf(png))) + goto fin; + + png_init_io(png, reader); + png_set_sig_bytes(png, MAGIC_SIZE); + + png_read_info(png, info); + + if(png_get_IHDR(png, info, &width, &height, + &bit_depth, &color_type, &interlace_type, + &compression_type, &filter_type) == 0) + goto fin; + +/* png_set_expand(): + * expand paletted images to RGB, expand grayscale images of + * less than 8-bit depth to 8-bit depth, and expand tRNS chunks + * to alpha channels. +*/ + if(color_type == PNG_COLOR_TYPE_PALETTE) + png_set_expand(png); + else + if(color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) + png_set_expand(png); + + if(png_get_valid(png, info, PNG_INFO_tRNS)) + png_set_expand(png); + + is16 = (bit_depth == 16); + +/* GRAY => RGB; GRAY_ALPHA => RGBA +*/ + if(color_type == PNG_COLOR_TYPE_GRAY + || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + png_set_gray_to_rgb(png); + color_type = + (color_type == PNG_COLOR_TYPE_GRAY? PNG_COLOR_TYPE_RGB: + PNG_COLOR_TYPE_RGB_ALPHA); + } + if( !png_get_gAMA(png, info, &gamma)) + gamma = 0.45455; + + png_set_gamma(png, display_exponent, gamma); + + png_read_update_info(png, info); + + png_get_pHYs(png, info, &resx, &resy, &unit); + + color_type = png_get_color_type(png, info); + + has_alpha = (color_type == PNG_COLOR_TYPE_RGB_ALPHA); + + nr_comp = 3 + has_alpha; + + bit_depth = png_get_bit_depth(png, info); + + rows = (unsigned char**)calloc(height+1, sizeof(unsigned char*)); + for(i = 0; i < height; ++i) + rows[i] = (unsigned char*)malloc(png_get_rowbytes(png,info)); + + png_read_image(png, rows); + + memset(&cmptparm, 0, 4 * sizeof(opj_image_cmptparm_t)); + + sub_dx = params->subsampling_dx; sub_dy = params->subsampling_dy; + + for(i = 0; i < nr_comp; ++i) + { + cmptparm[i].prec = bit_depth; +/* bits_per_pixel: 8 or 16 */ + cmptparm[i].bpp = bit_depth; + cmptparm[i].sgnd = 0; + cmptparm[i].dx = sub_dx; + cmptparm[i].dy = sub_dy; + cmptparm[i].w = width; + cmptparm[i].h = height; + } + + image = opj_image_create(nr_comp, &cmptparm[0], CLRSPC_SRGB); + + if(image == NULL) goto fin; + + image->x0 = params->image_offset_x0; + image->y0 = params->image_offset_y0; + image->x1 = image->x0 + (width - 1) * sub_dx + 1 + image->x0; + image->y1 = image->y0 + (height - 1) * sub_dy + 1 + image->y0; + + r = image->comps[0].data; + g = image->comps[1].data; + b = image->comps[2].data; + a = image->comps[3].data; + + for(i = 0; i < height; ++i) + { + s = rows[i]; + + for(j = 0; j < width; ++j) + { + if(is16) + { + *r++ = s[0]<<8|s[1]; s += 2; + + *g++ = s[0]<<8|s[1]; s += 2; + + *b++ = s[0]<<8|s[1]; s += 2; + + if(has_alpha) { *a++ = s[0]<<8|s[1]; s += 2; } + + continue; + } + *r++ = *s++; *g++ = *s++; *b++ = *s++; + + if(has_alpha) *a++ = *s++; + } + } +fin: + if(rows) + { + for(i = 0; i < height; ++i) + free(rows[i]); + free(rows); + } + if(png) + png_destroy_read_struct(&png, &info, NULL); + + fclose(reader); + + return image; + +}/* pngtoimage() */ + +int imagetopng(opj_image_t * image, const char *write_idf) +{ + FILE *writer; + png_structp png; + png_infop info; + int *red, *green, *blue, *alpha; + unsigned char *row_buf, *d; + int has_alpha, width, height, nr_comp, color_type; + int adjustR, adjustG, adjustB, x, y, fails, is16, force16; + int opj_prec, prec, ushift, dshift; + unsigned short mask = 0xffff; + png_color_8 sig_bit; + + is16 = force16 = ushift = dshift = 0; fails = 1; + prec = opj_prec = image->comps[0].prec; + + if(prec > 8 && prec < 16) + { + prec = 16; force16 = 1; + } + if(prec != 1 && prec != 2 && prec != 4 && prec != 8 && prec != 16) + { + fprintf(stderr,"imagetopng: can not create %s" + "\n\twrong bit_depth %d\n", write_idf, prec); + return fails; + } + writer = fopen(write_idf, "wb"); + + if(writer == NULL) return fails; + + info = NULL; has_alpha = 0; + +/* Create and initialize the png_struct with the desired error handler + * functions. If you want to use the default stderr and longjump method, + * you can supply NULL for the last three parameters. We also check that + * the library version is compatible with the one used at compile time, + * in case we are using dynamically linked libraries. REQUIRED. +*/ + png = png_create_write_struct(PNG_LIBPNG_VER_STRING, + NULL, NULL, NULL); +/*png_voidp user_error_ptr, user_error_fn, user_warning_fn); */ + + if(png == NULL) goto fin; + +/* Allocate/initialize the image information data. REQUIRED +*/ + info = png_create_info_struct(png); + + if(info == NULL) goto fin; + +/* Set error handling. REQUIRED if you are not supplying your own + * error handling functions in the png_create_write_struct() call. +*/ + if(setjmp(png_jmpbuf(png))) goto fin; + +/* I/O initialization functions is REQUIRED +*/ + png_init_io(png, writer); + +/* Set the image information here. Width and height are up to 2^31, + * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on + * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY, + * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB, + * or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or + * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST + * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. + * REQUIRED +*/ + png_set_compression_level(png, Z_BEST_COMPRESSION); + + if(prec == 16) mask = 0xffff; + else + if(prec == 8) mask = 0x00ff; + else + if(prec == 4) mask = 0x000f; + else + if(prec == 2) mask = 0x0003; + else + if(prec == 1) mask = 0x0001; + + nr_comp = image->numcomps; + + if(nr_comp >= 3 + && image->comps[0].dx == image->comps[1].dx + && image->comps[1].dx == image->comps[2].dx + && image->comps[0].dy == image->comps[1].dy + && image->comps[1].dy == image->comps[2].dy + && image->comps[0].prec == image->comps[1].prec + && image->comps[1].prec == image->comps[2].prec) + { + int v; + + has_alpha = (nr_comp > 3); + + is16 = (prec == 16); + + width = image->comps[0].w; + height = image->comps[0].h; + + red = image->comps[0].data; + green = image->comps[1].data; + blue = image->comps[2].data; + + sig_bit.red = sig_bit.green = sig_bit.blue = prec; + + if(has_alpha) + { + sig_bit.alpha = prec; + alpha = image->comps[3].data; + color_type = PNG_COLOR_TYPE_RGB_ALPHA; + } + else + { + sig_bit.alpha = 0; alpha = NULL; + color_type = PNG_COLOR_TYPE_RGB; + } + png_set_sBIT(png, info, &sig_bit); + + png_set_IHDR(png, info, width, height, prec, + color_type, + PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + +/*=============================*/ + png_write_info(png, info); +/*=============================*/ + if(opj_prec < 8) + { + png_set_packing(png); + } + if(force16) + { + ushift = 16 - opj_prec; dshift = opj_prec - ushift; + } + adjustR = (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0); + adjustG = (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0); + adjustB = (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0); + + row_buf = (unsigned char*)malloc(width * nr_comp * 2); + + for(y = 0; y < height; ++y) + { + d = row_buf; + + for(x = 0; x < width; ++x) + { + if(is16) + { +/* Network byte order */ + v = *red + adjustR; ++red; + + if(force16) { v = (v<>dshift); } + + *d++ = (unsigned char)(v>>8); *d++ = (unsigned char)v; + + v = *green + adjustG; ++green; + + if(force16) { v = (v<>dshift); } + + *d++ = (unsigned char)(v>>8); *d++ = (unsigned char)v; + + v = *blue + adjustB; ++blue; + + if(force16) { v = (v<>dshift); } + + *d++ = (unsigned char)(v>>8); *d++ = (unsigned char)v; + + if(has_alpha) + { + v = *alpha++; + + if(force16) { v = (v<>dshift); } + + *d++ = (unsigned char)(v>>8); *d++ = (unsigned char)v; + } + continue; + } + *d++ = (unsigned char)((*red + adjustR) & mask); ++red; + *d++ = (unsigned char)((*green + adjustG) & mask); ++green; + *d++ = (unsigned char)((*blue + adjustB) & mask); ++blue; + + if(has_alpha) + { + *d++ = (unsigned char)(*alpha & mask); ++alpha; + } + } /* for(x) */ + + png_write_row(png, row_buf); + + } /* for(y) */ + free(row_buf); + + }/* nr_comp >= 3 */ + else + if(nr_comp == 1 /* GRAY */ + || ( nr_comp == 2 /* GRAY_ALPHA */ + && image->comps[0].dx == image->comps[1].dx + && image->comps[0].dy == image->comps[1].dy + && image->comps[0].prec == image->comps[1].prec)) + { + int v; + + red = image->comps[0].data; + + if(force16) + { + ushift = 16 - opj_prec; dshift = opj_prec - ushift; + } + + sig_bit.gray = prec; + sig_bit.red = sig_bit.green = sig_bit.blue = sig_bit.alpha = 0; + alpha = NULL; + color_type = PNG_COLOR_TYPE_GRAY; + + if(nr_comp == 2) + { + has_alpha = 1; sig_bit.alpha = prec; + alpha = image->comps[1].data; + color_type = PNG_COLOR_TYPE_GRAY_ALPHA; + } + width = image->comps[0].w; + height = image->comps[0].h; + + png_set_IHDR(png, info, width, height, sig_bit.gray, + color_type, + PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + + png_set_sBIT(png, info, &sig_bit); +/*=============================*/ + png_write_info(png, info); +/*=============================*/ + adjustR = (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0); + + if(opj_prec < 8) + { + png_set_packing(png); + } + + if(prec > 8) + { +/* Network byte order */ + + + row_buf = (unsigned char*) + malloc(width * nr_comp * sizeof(unsigned short)); + + for(y = 0; y < height; ++y) + { + d = row_buf; + + for(x = 0; x < width; ++x) + { + v = *red + adjustR; ++red; + + if(force16) { v = (v<>dshift); } + + *d++ = (unsigned char)(v>>8); *d++ = (unsigned char)(v & 0xff); + + if(has_alpha) + { + v = *alpha++; + + if(force16) { v = (v<>dshift); } + + *d++ = (unsigned char)(v>>8); *d++ = (unsigned char)(v & 0xff); + } + }/* for(x) */ + png_write_row(png, row_buf); + + } /* for(y) */ + free(row_buf); + } + else /* prec <= 8 */ + { + row_buf = (unsigned char*)calloc(width, nr_comp * 2); + + for(y = 0; y < height; ++y) + { + d = row_buf; + + for(x = 0; x < width; ++x) + { + *d++ = (unsigned char)((*red + adjustR) & mask); ++red; + + if(has_alpha) + { + *d++ = (unsigned char)(*alpha & mask); ++alpha; + } + }/* for(x) */ + + png_write_row(png, row_buf); + + } /* for(y) */ + free(row_buf); + } + } + else + { + fprintf(stderr,"imagetopng: can not create %s\n",write_idf); + goto fin; + } + png_write_end(png, info); + + fails = 0; + +fin: + + if(png) + { + png_destroy_write_struct(&png, &info); + } + fclose(writer); + + if(fails) remove(write_idf); + + return fails; +}/* imagetopng() */ +#endif /* HAVE_LIBPNG */ + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/codec/convert.h b/gdcm/Utilities/gdcmopenjpeg-v1/codec/convert.h new file mode 100644 index 0000000..1dc58d7 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/codec/convert.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __J2K_CONVERT_H +#define __J2K_CONVERT_H + +/**@name RAW image encoding parameters */ +/*@{*/ +typedef struct raw_cparameters { + /** width of the raw image */ + int rawWidth; + /** height of the raw image */ + int rawHeight; + /** components of the raw image */ + int rawComp; + /** bit depth of the raw image */ + int rawBitDepth; + /** signed/unsigned raw image */ + bool rawSigned; + /*@}*/ +} raw_cparameters_t; + +/* TGA conversion */ +opj_image_t* tgatoimage(const char *filename, opj_cparameters_t *parameters); +int imagetotga(opj_image_t * image, const char *outfile); + +/* BMP conversion */ +opj_image_t* bmptoimage(const char *filename, opj_cparameters_t *parameters); +int imagetobmp(opj_image_t *image, const char *outfile); + +/* TIFF conversion*/ +opj_image_t* tiftoimage(const char *filename, opj_cparameters_t *parameters); +int imagetotif(opj_image_t *image, const char *outfile); +/** +Load a single image component encoded in PGX file format +@param filename Name of the PGX file to load +@param parameters *List ?* +@return Returns a greyscale image if successful, returns NULL otherwise +*/ +opj_image_t* pgxtoimage(const char *filename, opj_cparameters_t *parameters); +int imagetopgx(opj_image_t *image, const char *outfile); + +opj_image_t* pnmtoimage(const char *filename, opj_cparameters_t *parameters); +int imagetopnm(opj_image_t *image, const char *outfile); + +/* RAW conversion */ +int imagetoraw(opj_image_t * image, const char *outfile); +opj_image_t* rawtoimage(const char *filename, opj_cparameters_t *parameters, raw_cparameters_t *raw_cp); + +/* PNG conversion*/ +extern int imagetopng(opj_image_t *image, const char *write_idf); +extern opj_image_t* pngtoimage(const char *filename, opj_cparameters_t *parameters); + +#endif /* __J2K_CONVERT_H */ + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/codec/image_to_j2k.c b/gdcm/Utilities/gdcmopenjpeg-v1/codec/image_to_j2k.c new file mode 100644 index 0000000..443d4e0 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/codec/image_to_j2k.c @@ -0,0 +1,1789 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2006-2007, Parvatha Elangovan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#ifdef _WIN32 +#include "windirent.h" +#else +#include +#endif /* _WIN32 */ + +#ifdef _WIN32 +#include +#else +#include +#define _stricmp strcasecmp +#define _strnicmp strncasecmp +#endif /* _WIN32 */ + +#include "opj_config.h" +#include "openjpeg.h" +#include "getopt.h" +#include "convert.h" +#include "index.h" + +#include "format_defs.h" + +#define CINEMA_24_CS 1302083 /*Codestream length for 24fps*/ +#define CINEMA_48_CS 651041 /*Codestream length for 48fps*/ +#define COMP_24_CS 1041666 /*Maximum size per color component for 2K & 4K @ 24fps*/ +#define COMP_48_CS 520833 /*Maximum size per color component for 2K @ 48fps*/ + +typedef struct dircnt{ + /** Buffer for holding images read from Directory*/ + char *filename_buf; + /** Pointer to the buffer*/ + char **filename; +}dircnt_t; + +typedef struct img_folder{ + /** The directory path of the folder containing input images*/ + char *imgdirpath; + /** Output format*/ + char *out_format; + /** Enable option*/ + char set_imgdir; + /** Enable Cod Format for output*/ + char set_out_format; + /** User specified rate stored in case of cinema option*/ + float *rates; +}img_fol_t; + +void encode_help_display() { + fprintf(stdout,"HELP for image_to_j2k\n----\n\n"); + fprintf(stdout,"- the -h option displays this help information on screen\n\n"); + +/* UniPG>> */ + fprintf(stdout,"List of parameters for the JPEG 2000 " +#ifdef USE_JPWL + "+ JPWL " +#endif /* USE_JPWL */ + "encoder:\n"); +/* <> */ +#ifdef USE_JPWL + fprintf(stdout," * No JPWL protection\n"); +#endif /* USE_JPWL */ +/* < \n"); + fprintf(stdout," Currently accepts PGM, PPM, PNM, PGX, PNG, BMP, TIF, RAW and TGA formats\n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-i : source file (-i source.pnm also *.pgm, *.ppm, *.pgx, *png, *.bmp, *.tif, *.raw, *.tga) \n"); + fprintf(stdout," When using this option -o must be used\n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-o : destination file (-o dest.j2k or .jp2) \n"); + fprintf(stdout,"\n"); + fprintf(stdout,"Optional Parameters:\n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-h : display the help information \n "); + fprintf(stdout,"\n"); + fprintf(stdout,"-cinema2K : Digital Cinema 2K profile compliant codestream for 2K resolution.(-cinema2k 24 or 48) \n"); + fprintf(stdout," Need to specify the frames per second for a 2K resolution. Only 24 or 48 fps is allowed\n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-cinema4K : Digital Cinema 4K profile compliant codestream for 4K resolution \n"); + fprintf(stdout," Frames per second not required. Default value is 24fps\n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-r : different compression ratios for successive layers (-r 20,10,5)\n "); + fprintf(stdout," - The rate specified for each quality level is the desired \n"); + fprintf(stdout," compression factor.\n"); + fprintf(stdout," Example: -r 20,10,1 means quality 1: compress 20x, \n"); + fprintf(stdout," quality 2: compress 10x and quality 3: compress lossless\n"); + fprintf(stdout,"\n"); + fprintf(stdout," (options -r and -q cannot be used together)\n "); + fprintf(stdout,"\n"); + + fprintf(stdout,"-q : different psnr for successive layers (-q 30,40,50) \n "); + + fprintf(stdout," (options -r and -q cannot be used together)\n "); + + fprintf(stdout,"\n"); + fprintf(stdout,"-n : number of resolutions (-n 3) \n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-b : size of code block (-b 32,32) \n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-c : size of precinct (-c 128,128) \n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-t : size of tile (-t 512,512) \n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-p : progression order (-p LRCP) [LRCP, RLCP, RPCL, PCRL, CPRL] \n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-s : subsampling factor (-s 2,2) [-s X,Y] \n"); + fprintf(stdout," Remark: subsampling bigger than 2 can produce error\n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-POC : Progression order change (-POC T1=0,0,1,5,3,CPRL/T1=5,0,1,6,3,CPRL) \n"); + fprintf(stdout," Example: T1=0,0,1,5,3,CPRL \n"); + fprintf(stdout," : Ttilenumber=Resolution num start,Component num start,Layer num end,Resolution num end,Component num end,Progression order\n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-SOP : write SOP marker before each packet \n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-EPH : write EPH marker after each header packet \n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-M : mode switch (-M 3) [1=BYPASS(LAZY) 2=RESET 4=RESTART(TERMALL)\n"); + fprintf(stdout," 8=VSC 16=ERTERM(SEGTERM) 32=SEGMARK(SEGSYM)] \n"); + fprintf(stdout," Indicate multiple modes by adding their values. \n"); + fprintf(stdout," ex: RESTART(4) + RESET(2) + SEGMARK(32) = -M 38\n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-x : create an index file *.Idx (-x index_name.Idx) \n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-ROI : c=%%d,U=%%d : quantization indices upshifted \n"); + fprintf(stdout," for component c=%%d [%%d = 0,1,2]\n"); + fprintf(stdout," with a value of U=%%d [0 <= %%d <= 37] (i.e. -ROI c=0,U=25) \n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-d : offset of the origin of the image (-d 150,300) \n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-T : offset of the origin of the tiles (-T 100,75) \n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-I : use the irreversible DWT 9-7 (-I) \n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-F : characteristics of the raw input image\n"); + fprintf(stdout," -F rawWidth,rawHeight,rawComp,rawBitDepth,s/u (Signed/Unsigned)\n"); + fprintf(stdout," Example: -i lena.raw -o lena.j2k -F 512,512,3,8,u\n"); + fprintf(stdout,"\n"); +/* UniPG>> */ +#ifdef USE_JPWL + fprintf(stdout,"-W : adoption of JPWL (Part 11) capabilities (-W params)\n"); + fprintf(stdout," The parameters can be written and repeated in any order:\n"); + fprintf(stdout," [h<=type>,s<=method>,a=,...\n"); + fprintf(stdout," ...,z=,g=,p<=type>]\n"); + fprintf(stdout,"\n"); + fprintf(stdout," h selects the header error protection (EPB): 'type' can be\n"); + fprintf(stdout," [0=none 1,absent=predefined 16=CRC-16 32=CRC-32 37-128=RS]\n"); + fprintf(stdout," if 'tilepart' is absent, it is for main and tile headers\n"); + fprintf(stdout," if 'tilepart' is present, it applies from that tile\n"); + fprintf(stdout," onwards, up to the next h<> spec, or to the last tilepart\n"); + fprintf(stdout," in the codestream (max. %d specs)\n", JPWL_MAX_NO_TILESPECS); + fprintf(stdout,"\n"); + fprintf(stdout," p selects the packet error protection (EEP/UEP with EPBs)\n"); + fprintf(stdout," to be applied to raw data: 'type' can be\n"); + fprintf(stdout," [0=none 1,absent=predefined 16=CRC-16 32=CRC-32 37-128=RS]\n"); + fprintf(stdout," if 'tilepart:pack' is absent, it is from tile 0, packet 0\n"); + fprintf(stdout," if 'tilepart:pack' is present, it applies from that tile\n"); + fprintf(stdout," and that packet onwards, up to the next packet spec\n"); + fprintf(stdout," or to the last packet in the last tilepart in the stream\n"); + fprintf(stdout," (max. %d specs)\n", JPWL_MAX_NO_PACKSPECS); + fprintf(stdout,"\n"); + fprintf(stdout," s enables sensitivity data insertion (ESD): 'method' can be\n"); + fprintf(stdout," [-1=NO ESD 0=RELATIVE ERROR 1=MSE 2=MSE REDUCTION 3=PSNR\n"); + fprintf(stdout," 4=PSNR INCREMENT 5=MAXERR 6=TSE 7=RESERVED]\n"); + fprintf(stdout," if 'tilepart' is absent, it is for main header only\n"); + fprintf(stdout," if 'tilepart' is present, it applies from that tile\n"); + fprintf(stdout," onwards, up to the next s<> spec, or to the last tilepart\n"); + fprintf(stdout," in the codestream (max. %d specs)\n", JPWL_MAX_NO_TILESPECS); + fprintf(stdout,"\n"); + fprintf(stdout," g determines the addressing mode: can be\n"); + fprintf(stdout," [0=PACKET 1=BYTE RANGE 2=PACKET RANGE]\n"); + fprintf(stdout,"\n"); + fprintf(stdout," a determines the size of data addressing: can be\n"); + fprintf(stdout," 2/4 bytes (small/large codestreams). If not set, auto-mode\n"); + fprintf(stdout,"\n"); + fprintf(stdout," z determines the size of sensitivity values: can be\n"); + fprintf(stdout," 1/2 bytes, for the transformed pseudo-floating point value\n"); + fprintf(stdout,"\n"); + fprintf(stdout," ex.:\n"); + fprintf(stdout," h,h0=64,h3=16,h5=32,p0=78,p0:24=56,p1,p3:0=0,p3:20=32,s=0,\n"); + fprintf(stdout," s0=6,s3=-1,a=0,g=1,z=1\n"); + fprintf(stdout," means\n"); + fprintf(stdout," predefined EPB in MH, rs(64,32) from TPH 0 to TPH 2,\n"); + fprintf(stdout," CRC-16 in TPH 3 and TPH 4, CRC-32 in remaining TPHs,\n"); + fprintf(stdout," UEP rs(78,32) for packets 0 to 23 of tile 0,\n"); + fprintf(stdout," UEP rs(56,32) for packs. 24 to the last of tilepart 0,\n"); + fprintf(stdout," UEP rs default for packets of tilepart 1,\n"); + fprintf(stdout," no UEP for packets 0 to 19 of tilepart 3,\n"); + fprintf(stdout," UEP CRC-32 for packs. 20 of tilepart 3 to last tilepart,\n"); + fprintf(stdout," relative sensitivity ESD for MH,\n"); + fprintf(stdout," TSE ESD from TPH 0 to TPH 2, byte range with automatic\n"); + fprintf(stdout," size of addresses and 1 byte for each sensitivity value\n"); + fprintf(stdout,"\n"); + fprintf(stdout," ex.:\n"); + fprintf(stdout," h,s,p\n"); + fprintf(stdout," means\n"); + fprintf(stdout," default protection to headers (MH and TPHs) as well as\n"); + fprintf(stdout," data packets, one ESD in MH\n"); + fprintf(stdout,"\n"); + fprintf(stdout," N.B.: use the following recommendations when specifying\n"); + fprintf(stdout," the JPWL parameters list\n"); + fprintf(stdout," - when you use UEP, always pair the 'p' option with 'h'\n"); + fprintf(stdout," \n"); +#endif /* USE_JPWL */ +/* <d_name)==0 || strcmp("..",content->d_name)==0 ) + continue; + num_images++; + } + return num_images; +} + +int load_images(dircnt_t *dirptr, char *imgdirpath){ + DIR *dir; + struct dirent* content; + int i = 0; + + /*Reading the input images from given input directory*/ + + dir= opendir(imgdirpath); + if(!dir){ + fprintf(stderr,"Could not open Folder %s\n",imgdirpath); + return 1; + }else { + fprintf(stderr,"Folder opened successfully\n"); + } + + while((content=readdir(dir))!=NULL){ + if(strcmp(".",content->d_name)==0 || strcmp("..",content->d_name)==0 ) + continue; + + strcpy(dirptr->filename[i],content->d_name); + i++; + } + return 0; +} + +int get_file_format(char *filename) { + unsigned int i; + static const char *extension[] = { + "pgx", "pnm", "pgm", "ppm", "bmp", "tif", "raw", "tga", "png", "j2k", "jp2", "j2c", "jpc" + }; + static const int format[] = { + PGX_DFMT, PXM_DFMT, PXM_DFMT, PXM_DFMT, BMP_DFMT, TIF_DFMT, RAW_DFMT, TGA_DFMT, PNG_DFMT, J2K_CFMT, JP2_CFMT, J2K_CFMT, J2K_CFMT + }; + char * ext = strrchr(filename, '.'); + if (ext == NULL) + return -1; + ext++; + for(i = 0; i < sizeof(format)/sizeof(*format); i++) { + if(_strnicmp(ext, extension[i], 3) == 0) { + return format[i]; + } + } + return -1; +} + +char * get_file_name(char *name){ + char *fname; + fname= (char*)malloc(OPJ_PATH_LEN*sizeof(char)); + fname= strtok(name,"."); + return fname; +} + +char get_next_file(int imageno,dircnt_t *dirptr,img_fol_t *img_fol, opj_cparameters_t *parameters){ + char image_filename[OPJ_PATH_LEN], infilename[OPJ_PATH_LEN],outfilename[OPJ_PATH_LEN],temp_ofname[OPJ_PATH_LEN]; + char *temp_p, temp1[OPJ_PATH_LEN]=""; + + strcpy(image_filename,dirptr->filename[imageno]); + fprintf(stderr,"File Number %d \"%s\"\n",imageno,image_filename); + parameters->decod_format = get_file_format(image_filename); + if (parameters->decod_format == -1) + return 1; + sprintf(infilename,"%s/%s",img_fol->imgdirpath,image_filename); + strncpy(parameters->infile, infilename, sizeof(infilename)); + + //Set output file + strcpy(temp_ofname,get_file_name(image_filename)); + while((temp_p = strtok(NULL,".")) != NULL){ + strcat(temp_ofname,temp1); + sprintf(temp1,".%s",temp_p); + } + if(img_fol->set_out_format==1){ + sprintf(outfilename,"%s/%s.%s",img_fol->imgdirpath,temp_ofname,img_fol->out_format); + strncpy(parameters->outfile, outfilename, sizeof(outfilename)); + } + return 0; +} + +static int initialise_4K_poc(opj_poc_t *POC, int numres){ + POC[0].tile = 1; + POC[0].resno0 = 0; + POC[0].compno0 = 0; + POC[0].layno1 = 1; + POC[0].resno1 = numres-1; + POC[0].compno1 = 3; + POC[0].prg1 = CPRL; + POC[1].tile = 1; + POC[1].resno0 = numres-1; + POC[1].compno0 = 0; + POC[1].layno1 = 1; + POC[1].resno1 = numres; + POC[1].compno1 = 3; + POC[1].prg1 = CPRL; + return 2; +} + +void cinema_parameters(opj_cparameters_t *parameters){ + parameters->tile_size_on = false; + parameters->cp_tdx=1; + parameters->cp_tdy=1; + + /*Tile part*/ + parameters->tp_flag = 'C'; + parameters->tp_on = 1; + + /*Tile and Image shall be at (0,0)*/ + parameters->cp_tx0 = 0; + parameters->cp_ty0 = 0; + parameters->image_offset_x0 = 0; + parameters->image_offset_y0 = 0; + + /*Codeblock size= 32*32*/ + parameters->cblockw_init = 32; + parameters->cblockh_init = 32; + parameters->csty |= 0x01; + + /*The progression order shall be CPRL*/ + parameters->prog_order = CPRL; + + /* No ROI */ + parameters->roi_compno = -1; + + parameters->subsampling_dx = 1; parameters->subsampling_dy = 1; + + /* 9-7 transform */ + parameters->irreversible = 1; + +} + +void cinema_setup_encoder(opj_cparameters_t *parameters,opj_image_t *image, img_fol_t *img_fol){ + int i; + float temp_rate; + + switch (parameters->cp_cinema){ + case CINEMA2K_24: + case CINEMA2K_48: + if(parameters->numresolution > 6){ + parameters->numresolution = 6; + } + if (!((image->comps[0].w == 2048) | (image->comps[0].h == 1080))){ + fprintf(stdout,"Image coordinates %d x %d is not 2K compliant.\nJPEG Digital Cinema Profile-3 " + "(2K profile) compliance requires that at least one of coordinates match 2048 x 1080\n", + image->comps[0].w,image->comps[0].h); + parameters->cp_rsiz = STD_RSIZ; + } + break; + + case CINEMA4K_24: + if(parameters->numresolution < 1){ + parameters->numresolution = 1; + }else if(parameters->numresolution > 7){ + parameters->numresolution = 7; + } + if (!((image->comps[0].w == 4096) | (image->comps[0].h == 2160))){ + fprintf(stdout,"Image coordinates %d x %d is not 4K compliant.\nJPEG Digital Cinema Profile-4" + "(4K profile) compliance requires that at least one of coordinates match 4096 x 2160\n", + image->comps[0].w,image->comps[0].h); + parameters->cp_rsiz = STD_RSIZ; + } + parameters->numpocs = initialise_4K_poc(parameters->POC,parameters->numresolution); + break; + default : + break; + } + + switch (parameters->cp_cinema){ + case CINEMA2K_24: + case CINEMA4K_24: + for(i=0 ; itcp_numlayers ; i++){ + temp_rate = 0 ; + if (img_fol->rates[i]== 0){ + parameters->tcp_rates[0]= ((float) (image->numcomps * image->comps[0].w * image->comps[0].h * image->comps[0].prec))/ + (CINEMA_24_CS * 8 * image->comps[0].dx * image->comps[0].dy); + }else{ + temp_rate =((float) (image->numcomps * image->comps[0].w * image->comps[0].h * image->comps[0].prec))/ + (img_fol->rates[i] * 8 * image->comps[0].dx * image->comps[0].dy); + if (temp_rate > CINEMA_24_CS ){ + parameters->tcp_rates[i]= ((float) (image->numcomps * image->comps[0].w * image->comps[0].h * image->comps[0].prec))/ + (CINEMA_24_CS * 8 * image->comps[0].dx * image->comps[0].dy); + }else{ + parameters->tcp_rates[i]= img_fol->rates[i]; + } + } + } + parameters->max_comp_size = COMP_24_CS; + break; + + case CINEMA2K_48: + for(i=0 ; itcp_numlayers ; i++){ + temp_rate = 0 ; + if (img_fol->rates[i]== 0){ + parameters->tcp_rates[0]= ((float) (image->numcomps * image->comps[0].w * image->comps[0].h * image->comps[0].prec))/ + (CINEMA_48_CS * 8 * image->comps[0].dx * image->comps[0].dy); + }else{ + temp_rate =((float) (image->numcomps * image->comps[0].w * image->comps[0].h * image->comps[0].prec))/ + (img_fol->rates[i] * 8 * image->comps[0].dx * image->comps[0].dy); + if (temp_rate > CINEMA_48_CS ){ + parameters->tcp_rates[0]= ((float) (image->numcomps * image->comps[0].w * image->comps[0].h * image->comps[0].prec))/ + (CINEMA_48_CS * 8 * image->comps[0].dx * image->comps[0].dy); + }else{ + parameters->tcp_rates[i]= img_fol->rates[i]; + } + } + } + parameters->max_comp_size = COMP_48_CS; + break; + default: + break; + } + parameters->cp_disto_alloc = 1; +} + +/* ------------------------------------------------------------------------------------ */ + +int parse_cmdline_encoder(int argc, char **argv, opj_cparameters_t *parameters, + img_fol_t *img_fol, raw_cparameters_t *raw_cp, char *indexfilename) { + int i, j,totlen; + option_t long_option[]={ + {"cinema2K",REQ_ARG, NULL ,'w'}, + {"cinema4K",NO_ARG, NULL ,'y'}, + {"ImgDir",REQ_ARG, NULL ,'z'}, + {"TP",REQ_ARG, NULL ,'v'}, + {"SOP",NO_ARG, NULL ,'S'}, + {"EPH",NO_ARG, NULL ,'E'}, + {"OutFor",REQ_ARG, NULL ,'O'}, + {"POC",REQ_ARG, NULL ,'P'}, + {"ROI",REQ_ARG, NULL ,'R'}, + }; + + /* parse the command line */ + const char optlist[] = "i:o:r:q:n:b:c:t:p:s:SEM:x:R:d:T:If:P:C:F:" +#ifdef USE_JPWL + "W:" +#endif /* USE_JPWL */ + "h"; + + totlen=sizeof(long_option); + img_fol->set_out_format=0; + raw_cp->rawWidth = 0; + + while (1) { + int c = getopt_long(argc, argv, optlist,long_option,totlen); + if (c == -1) + break; + switch (c) { + case 'i': /* input file */ + { + char *infile = optarg; + parameters->decod_format = get_file_format(infile); + switch(parameters->decod_format) { + case PGX_DFMT: + case PXM_DFMT: + case BMP_DFMT: + case TIF_DFMT: + case RAW_DFMT: + case TGA_DFMT: + case PNG_DFMT: + break; + default: + fprintf(stderr, + "!! Unrecognized format for infile : %s " + "[accept only *.pnm, *.pgm, *.ppm, *.pgx, *png, *.bmp, *.tif, *.raw or *.tga] !!\n\n", + infile); + return 1; + } + strncpy(parameters->infile, infile, sizeof(parameters->infile)-1); + } + break; + + /* ----------------------------------------------------- */ + + case 'o': /* output file */ + { + char *outfile = optarg; + parameters->cod_format = get_file_format(outfile); + switch(parameters->cod_format) { + case J2K_CFMT: + case JP2_CFMT: + break; + default: + fprintf(stderr, "Unknown output format image %s [only *.j2k, *.j2c or *.jp2]!! \n", outfile); + return 1; + } + strncpy(parameters->outfile, outfile, sizeof(parameters->outfile)-1); + } + break; + + /* ----------------------------------------------------- */ + case 'O': /* output format */ + { + char outformat[50]; + char *of = optarg; + sprintf(outformat,".%s",of); + img_fol->set_out_format = 1; + parameters->cod_format = get_file_format(outformat); + switch(parameters->cod_format) { + case J2K_CFMT: + case JP2_CFMT: + img_fol->out_format = optarg; + break; + default: + fprintf(stderr, "Unknown output format image [only j2k, j2c, jp2]!! \n"); + return 1; + } + } + break; + + + /* ----------------------------------------------------- */ + + + case 'r': /* rates rates/distorsion */ + { + char *s = optarg; + parameters->tcp_numlayers = 0; + while (sscanf(s, "%f", ¶meters->tcp_rates[parameters->tcp_numlayers]) == 1) { + parameters->tcp_numlayers++; + while (*s && *s != ',') { + s++; + } + if (!*s) + break; + s++; + } + parameters->cp_disto_alloc = 1; + } + break; + + /* ----------------------------------------------------- */ + + + case 'F': /* Raw image format parameters */ + { + char signo; + char *s = optarg; + if (sscanf(s, "%d,%d,%d,%d,%c", &raw_cp->rawWidth, &raw_cp->rawHeight, &raw_cp->rawComp, &raw_cp->rawBitDepth, &signo) == 5) { + if (signo == 's') { + raw_cp->rawSigned = true; + fprintf(stdout,"\nRaw file parameters: %d,%d,%d,%d Signed\n", raw_cp->rawWidth, raw_cp->rawHeight, raw_cp->rawComp, raw_cp->rawBitDepth); + } + else if (signo == 'u') { + raw_cp->rawSigned = false; + fprintf(stdout,"\nRaw file parameters: %d,%d,%d,%d Unsigned\n", raw_cp->rawWidth, raw_cp->rawHeight, raw_cp->rawComp, raw_cp->rawBitDepth); + } + else { + fprintf(stderr,"\nError: invalid raw image parameters: Unknown sign of raw file\n"); + fprintf(stderr,"Please use the Format option -F:\n"); + fprintf(stderr,"-F rawWidth,rawHeight,rawComp,rawBitDepth,s/u (Signed/Unsigned)\n"); + fprintf(stderr,"Example: -i lena.raw -o lena.j2k -F 512,512,3,8,u\n"); + fprintf(stderr,"Aborting\n"); + } + } + else { + fprintf(stderr,"\nError: invalid raw image parameters\n"); + fprintf(stderr,"Please use the Format option -F:\n"); + fprintf(stderr,"-F rawWidth,rawHeight,rawComp,rawBitDepth,s/u (Signed/Unsigned)\n"); + fprintf(stderr,"Example: -i lena.raw -o lena.j2k -F 512,512,3,8,u\n"); + fprintf(stderr,"Aborting\n"); + return 1; + } + } + break; + + /* ----------------------------------------------------- */ + + case 'q': /* add fixed_quality */ + { + char *s = optarg; + while (sscanf(s, "%f", ¶meters->tcp_distoratio[parameters->tcp_numlayers]) == 1) { + parameters->tcp_numlayers++; + while (*s && *s != ',') { + s++; + } + if (!*s) + break; + s++; + } + parameters->cp_fixed_quality = 1; + } + break; + + /* dda */ + /* ----------------------------------------------------- */ + + case 'f': /* mod fixed_quality (before : -q) */ + { + int *row = NULL, *col = NULL; + int numlayers = 0, numresolution = 0, matrix_width = 0; + + char *s = optarg; + sscanf(s, "%d", &numlayers); + s++; + if (numlayers > 9) + s++; + + parameters->tcp_numlayers = numlayers; + numresolution = parameters->numresolution; + matrix_width = numresolution * 3; + parameters->cp_matrice = (int *) malloc(numlayers * matrix_width * sizeof(int)); + s = s + 2; + + for (i = 0; i < numlayers; i++) { + row = ¶meters->cp_matrice[i * matrix_width]; + col = row; + parameters->tcp_rates[i] = 1; + sscanf(s, "%d,", &col[0]); + s += 2; + if (col[0] > 9) + s++; + col[1] = 0; + col[2] = 0; + for (j = 1; j < numresolution; j++) { + col += 3; + sscanf(s, "%d,%d,%d", &col[0], &col[1], &col[2]); + s += 6; + if (col[0] > 9) + s++; + if (col[1] > 9) + s++; + if (col[2] > 9) + s++; + } + if (i < numlayers - 1) + s++; + } + parameters->cp_fixed_alloc = 1; + } + break; + + /* ----------------------------------------------------- */ + + case 't': /* tiles */ + { + sscanf(optarg, "%d,%d", ¶meters->cp_tdx, ¶meters->cp_tdy); + parameters->tile_size_on = true; + } + break; + + /* ----------------------------------------------------- */ + + case 'n': /* resolution */ + { + sscanf(optarg, "%d", ¶meters->numresolution); + } + break; + + /* ----------------------------------------------------- */ + case 'c': /* precinct dimension */ + { + char sep; + int res_spec = 0; + + char *s = optarg; + do { + sep = 0; + sscanf(s, "[%d,%d]%c", ¶meters->prcw_init[res_spec], + ¶meters->prch_init[res_spec], &sep); + parameters->csty |= 0x01; + res_spec++; + s = strpbrk(s, "]") + 2; + } + while (sep == ','); + parameters->res_spec = res_spec; + } + break; + + /* ----------------------------------------------------- */ + + case 'b': /* code-block dimension */ + { + int cblockw_init = 0, cblockh_init = 0; + sscanf(optarg, "%d,%d", &cblockw_init, &cblockh_init); + if (cblockw_init * cblockh_init > 4096 || cblockw_init > 1024 + || cblockw_init < 4 || cblockh_init > 1024 || cblockh_init < 4) { + fprintf(stderr, + "!! Size of code_block error (option -b) !!\n\nRestriction :\n" + " * width*height<=4096\n * 4<=width,height<= 1024\n\n"); + return 1; + } + parameters->cblockw_init = cblockw_init; + parameters->cblockh_init = cblockh_init; + } + break; + + /* ----------------------------------------------------- */ + + case 'x': /* creation of index file */ + { + char *index = optarg; + strncpy(indexfilename, index, OPJ_PATH_LEN); + } + break; + + /* ----------------------------------------------------- */ + + case 'p': /* progression order */ + { + char progression[4]; + + strncpy(progression, optarg, 4); + parameters->prog_order = give_progression(progression); + if (parameters->prog_order == -1) { + fprintf(stderr, "Unrecognized progression order " + "[LRCP, RLCP, RPCL, PCRL, CPRL] !!\n"); + return 1; + } + } + break; + + /* ----------------------------------------------------- */ + + case 's': /* subsampling factor */ + { + if (sscanf(optarg, "%d,%d", ¶meters->subsampling_dx, + ¶meters->subsampling_dy) != 2) { + fprintf(stderr, "'-s' sub-sampling argument error ! [-s dx,dy]\n"); + return 1; + } + } + break; + + /* ----------------------------------------------------- */ + + case 'd': /* coordonnate of the reference grid */ + { + if (sscanf(optarg, "%d,%d", ¶meters->image_offset_x0, + ¶meters->image_offset_y0) != 2) { + fprintf(stderr, "-d 'coordonnate of the reference grid' argument " + "error !! [-d x0,y0]\n"); + return 1; + } + } + break; + + /* ----------------------------------------------------- */ + + case 'h': /* display an help description */ + encode_help_display(); + return 1; + + /* ----------------------------------------------------- */ + + case 'P': /* POC */ + { + int numpocs = 0; /* number of progression order change (POC) default 0 */ + opj_poc_t *POC = NULL; /* POC : used in case of Progression order change */ + + char *s = optarg; + POC = parameters->POC; + + while (sscanf(s, "T%d=%d,%d,%d,%d,%d,%4s", &POC[numpocs].tile, + &POC[numpocs].resno0, &POC[numpocs].compno0, + &POC[numpocs].layno1, &POC[numpocs].resno1, + &POC[numpocs].compno1, POC[numpocs].progorder) == 7) { + POC[numpocs].prg1 = give_progression(POC[numpocs].progorder); + numpocs++; + while (*s && *s != '/') { + s++; + } + if (!*s) { + break; + } + s++; + } + parameters->numpocs = numpocs; + } + break; + + /* ------------------------------------------------------ */ + + case 'S': /* SOP marker */ + { + parameters->csty |= 0x02; + } + break; + + /* ------------------------------------------------------ */ + + case 'E': /* EPH marker */ + { + parameters->csty |= 0x04; + } + break; + + /* ------------------------------------------------------ */ + + case 'M': /* Mode switch pas tous au point !! */ + { + int value = 0; + if (sscanf(optarg, "%d", &value) == 1) { + for (i = 0; i <= 5; i++) { + int cache = value & (1 << i); + if (cache) + parameters->mode |= (1 << i); + } + } + } + break; + + /* ------------------------------------------------------ */ + + case 'R': /* ROI */ + { + if (sscanf(optarg, "c=%d,U=%d", ¶meters->roi_compno, + ¶meters->roi_shift) != 2) { + fprintf(stderr, "ROI error !! [-ROI c='compno',U='shift']\n"); + return 1; + } + } + break; + + /* ------------------------------------------------------ */ + + case 'T': /* Tile offset */ + { + if (sscanf(optarg, "%d,%d", ¶meters->cp_tx0, ¶meters->cp_ty0) != 2) { + fprintf(stderr, "-T 'tile offset' argument error !! [-T X0,Y0]"); + return 1; + } + } + break; + + /* ------------------------------------------------------ */ + + case 'C': /* add a comment */ + { + parameters->cp_comment = (char*)malloc(strlen(optarg) + 1); + if(parameters->cp_comment) { + strcpy(parameters->cp_comment, optarg); + } + } + break; + + + /* ------------------------------------------------------ */ + + case 'I': /* reversible or not */ + { + parameters->irreversible = 1; + } + break; + + /* ------------------------------------------------------ */ + + case 'v': /* Tile part generation*/ + { + parameters->tp_flag = optarg[0]; + parameters->tp_on = 1; + } + break; + + /* ------------------------------------------------------ */ + + case 'z': /* Image Directory path */ + { + img_fol->imgdirpath = (char*)malloc(strlen(optarg) + 1); + strcpy(img_fol->imgdirpath,optarg); + img_fol->set_imgdir=1; + } + break; + + /* ------------------------------------------------------ */ + + case 'w': /* Digital Cinema 2K profile compliance*/ + { + int fps=0; + sscanf(optarg,"%d",&fps); + if(fps == 24){ + parameters->cp_cinema = CINEMA2K_24; + }else if(fps == 48 ){ + parameters->cp_cinema = CINEMA2K_48; + }else { + fprintf(stderr,"Incorrect value!! must be 24 or 48\n"); + return 1; + } + fprintf(stdout,"CINEMA 2K compliant codestream\n"); + parameters->cp_rsiz = CINEMA2K; + + } + break; + + /* ------------------------------------------------------ */ + + case 'y': /* Digital Cinema 4K profile compliance*/ + { + parameters->cp_cinema = CINEMA4K_24; + fprintf(stdout,"CINEMA 4K compliant codestream\n"); + parameters->cp_rsiz = CINEMA4K; + } + break; + + /* ------------------------------------------------------ */ + +/* UniPG>> */ +#ifdef USE_JPWL + /* ------------------------------------------------------ */ + + case 'W': /* JPWL capabilities switched on */ + { + char *token = NULL; + int hprot, pprot, sens, addr, size, range; + + /* we need to enable indexing */ + if (!indexfilename || !*indexfilename) { + strncpy(indexfilename, JPWL_PRIVATEINDEX_NAME, OPJ_PATH_LEN); + } + + /* search for different protection methods */ + + /* break the option in comma points and parse the result */ + token = strtok(optarg, ","); + while(token != NULL) { + + /* search header error protection method */ + if (*token == 'h') { + + static int tile = 0, tilespec = 0, lasttileno = 0; + + hprot = 1; /* predefined method */ + + if(sscanf(token, "h=%d", &hprot) == 1) { + /* Main header, specified */ + if (!((hprot == 0) || (hprot == 1) || (hprot == 16) || (hprot == 32) || + ((hprot >= 37) && (hprot <= 128)))) { + fprintf(stderr, "ERROR -> invalid main header protection method h = %d\n", hprot); + return 1; + } + parameters->jpwl_hprot_MH = hprot; + + } else if(sscanf(token, "h%d=%d", &tile, &hprot) == 2) { + /* Tile part header, specified */ + if (!((hprot == 0) || (hprot == 1) || (hprot == 16) || (hprot == 32) || + ((hprot >= 37) && (hprot <= 128)))) { + fprintf(stderr, "ERROR -> invalid tile part header protection method h = %d\n", hprot); + return 1; + } + if (tile < 0) { + fprintf(stderr, "ERROR -> invalid tile part number on protection method t = %d\n", tile); + return 1; + } + if (tilespec < JPWL_MAX_NO_TILESPECS) { + parameters->jpwl_hprot_TPH_tileno[tilespec] = lasttileno = tile; + parameters->jpwl_hprot_TPH[tilespec++] = hprot; + } + + } else if(sscanf(token, "h%d", &tile) == 1) { + /* Tile part header, unspecified */ + if (tile < 0) { + fprintf(stderr, "ERROR -> invalid tile part number on protection method t = %d\n", tile); + return 1; + } + if (tilespec < JPWL_MAX_NO_TILESPECS) { + parameters->jpwl_hprot_TPH_tileno[tilespec] = lasttileno = tile; + parameters->jpwl_hprot_TPH[tilespec++] = hprot; + } + + + } else if (!strcmp(token, "h")) { + /* Main header, unspecified */ + parameters->jpwl_hprot_MH = hprot; + + } else { + fprintf(stderr, "ERROR -> invalid protection method selection = %s\n", token); + return 1; + }; + + } + + /* search packet error protection method */ + if (*token == 'p') { + + static int pack = 0, tile = 0, packspec = 0; + + pprot = 1; /* predefined method */ + + if (sscanf(token, "p=%d", &pprot) == 1) { + /* Method for all tiles and all packets */ + if (!((pprot == 0) || (pprot == 1) || (pprot == 16) || (pprot == 32) || + ((pprot >= 37) && (pprot <= 128)))) { + fprintf(stderr, "ERROR -> invalid default packet protection method p = %d\n", pprot); + return 1; + } + parameters->jpwl_pprot_tileno[0] = 0; + parameters->jpwl_pprot_packno[0] = 0; + parameters->jpwl_pprot[0] = pprot; + + } else if (sscanf(token, "p%d=%d", &tile, &pprot) == 2) { + /* method specified from that tile on */ + if (!((pprot == 0) || (pprot == 1) || (pprot == 16) || (pprot == 32) || + ((pprot >= 37) && (pprot <= 128)))) { + fprintf(stderr, "ERROR -> invalid packet protection method p = %d\n", pprot); + return 1; + } + if (tile < 0) { + fprintf(stderr, "ERROR -> invalid tile part number on protection method p = %d\n", tile); + return 1; + } + if (packspec < JPWL_MAX_NO_PACKSPECS) { + parameters->jpwl_pprot_tileno[packspec] = tile; + parameters->jpwl_pprot_packno[packspec] = 0; + parameters->jpwl_pprot[packspec++] = pprot; + } + + } else if (sscanf(token, "p%d:%d=%d", &tile, &pack, &pprot) == 3) { + /* method fully specified from that tile and that packet on */ + if (!((pprot == 0) || (pprot == 1) || (pprot == 16) || (pprot == 32) || + ((pprot >= 37) && (pprot <= 128)))) { + fprintf(stderr, "ERROR -> invalid packet protection method p = %d\n", pprot); + return 1; + } + if (tile < 0) { + fprintf(stderr, "ERROR -> invalid tile part number on protection method p = %d\n", tile); + return 1; + } + if (pack < 0) { + fprintf(stderr, "ERROR -> invalid packet number on protection method p = %d\n", pack); + return 1; + } + if (packspec < JPWL_MAX_NO_PACKSPECS) { + parameters->jpwl_pprot_tileno[packspec] = tile; + parameters->jpwl_pprot_packno[packspec] = pack; + parameters->jpwl_pprot[packspec++] = pprot; + } + + } else if (sscanf(token, "p%d:%d", &tile, &pack) == 2) { + /* default method from that tile and that packet on */ + if (!((pprot == 0) || (pprot == 1) || (pprot == 16) || (pprot == 32) || + ((pprot >= 37) && (pprot <= 128)))) { + fprintf(stderr, "ERROR -> invalid packet protection method p = %d\n", pprot); + return 1; + } + if (tile < 0) { + fprintf(stderr, "ERROR -> invalid tile part number on protection method p = %d\n", tile); + return 1; + } + if (pack < 0) { + fprintf(stderr, "ERROR -> invalid packet number on protection method p = %d\n", pack); + return 1; + } + if (packspec < JPWL_MAX_NO_PACKSPECS) { + parameters->jpwl_pprot_tileno[packspec] = tile; + parameters->jpwl_pprot_packno[packspec] = pack; + parameters->jpwl_pprot[packspec++] = pprot; + } + + } else if (sscanf(token, "p%d", &tile) == 1) { + /* default from a tile on */ + if (tile < 0) { + fprintf(stderr, "ERROR -> invalid tile part number on protection method p = %d\n", tile); + return 1; + } + if (packspec < JPWL_MAX_NO_PACKSPECS) { + parameters->jpwl_pprot_tileno[packspec] = tile; + parameters->jpwl_pprot_packno[packspec] = 0; + parameters->jpwl_pprot[packspec++] = pprot; + } + + + } else if (!strcmp(token, "p")) { + /* all default */ + parameters->jpwl_pprot_tileno[0] = 0; + parameters->jpwl_pprot_packno[0] = 0; + parameters->jpwl_pprot[0] = pprot; + + } else { + fprintf(stderr, "ERROR -> invalid protection method selection = %s\n", token); + return 1; + }; + + } + + /* search sensitivity method */ + if (*token == 's') { + + static int tile = 0, tilespec = 0, lasttileno = 0; + + sens = 0; /* predefined: relative error */ + + if(sscanf(token, "s=%d", &sens) == 1) { + /* Main header, specified */ + if ((sens < -1) || (sens > 7)) { + fprintf(stderr, "ERROR -> invalid main header sensitivity method s = %d\n", sens); + return 1; + } + parameters->jpwl_sens_MH = sens; + + } else if(sscanf(token, "s%d=%d", &tile, &sens) == 2) { + /* Tile part header, specified */ + if ((sens < -1) || (sens > 7)) { + fprintf(stderr, "ERROR -> invalid tile part header sensitivity method s = %d\n", sens); + return 1; + } + if (tile < 0) { + fprintf(stderr, "ERROR -> invalid tile part number on sensitivity method t = %d\n", tile); + return 1; + } + if (tilespec < JPWL_MAX_NO_TILESPECS) { + parameters->jpwl_sens_TPH_tileno[tilespec] = lasttileno = tile; + parameters->jpwl_sens_TPH[tilespec++] = sens; + } + + } else if(sscanf(token, "s%d", &tile) == 1) { + /* Tile part header, unspecified */ + if (tile < 0) { + fprintf(stderr, "ERROR -> invalid tile part number on sensitivity method t = %d\n", tile); + return 1; + } + if (tilespec < JPWL_MAX_NO_TILESPECS) { + parameters->jpwl_sens_TPH_tileno[tilespec] = lasttileno = tile; + parameters->jpwl_sens_TPH[tilespec++] = hprot; + } + + } else if (!strcmp(token, "s")) { + /* Main header, unspecified */ + parameters->jpwl_sens_MH = sens; + + } else { + fprintf(stderr, "ERROR -> invalid sensitivity method selection = %s\n", token); + return 1; + }; + + parameters->jpwl_sens_size = 2; /* 2 bytes for default size */ + } + + /* search addressing size */ + if (*token == 'a') { + + + addr = 0; /* predefined: auto */ + + if(sscanf(token, "a=%d", &addr) == 1) { + /* Specified */ + if ((addr != 0) && (addr != 2) && (addr != 4)) { + fprintf(stderr, "ERROR -> invalid addressing size a = %d\n", addr); + return 1; + } + parameters->jpwl_sens_addr = addr; + + } else if (!strcmp(token, "a")) { + /* default */ + parameters->jpwl_sens_addr = addr; /* auto for default size */ + + } else { + fprintf(stderr, "ERROR -> invalid addressing selection = %s\n", token); + return 1; + }; + + } + + /* search sensitivity size */ + if (*token == 'z') { + + + size = 1; /* predefined: 1 byte */ + + if(sscanf(token, "z=%d", &size) == 1) { + /* Specified */ + if ((size != 0) && (size != 1) && (size != 2)) { + fprintf(stderr, "ERROR -> invalid sensitivity size z = %d\n", size); + return 1; + } + parameters->jpwl_sens_size = size; + + } else if (!strcmp(token, "a")) { + /* default */ + parameters->jpwl_sens_size = size; /* 1 for default size */ + + } else { + fprintf(stderr, "ERROR -> invalid size selection = %s\n", token); + return 1; + }; + + } + + /* search range method */ + if (*token == 'g') { + + + range = 0; /* predefined: 0 (packet) */ + + if(sscanf(token, "g=%d", &range) == 1) { + /* Specified */ + if ((range < 0) || (range > 3)) { + fprintf(stderr, "ERROR -> invalid sensitivity range method g = %d\n", range); + return 1; + } + parameters->jpwl_sens_range = range; + + } else if (!strcmp(token, "g")) { + /* default */ + parameters->jpwl_sens_range = range; + + } else { + fprintf(stderr, "ERROR -> invalid range selection = %s\n", token); + return 1; + }; + + } + + /* next token or bust */ + token = strtok(NULL, ","); + }; + + + /* some info */ + fprintf(stdout, "Info: JPWL capabilities enabled\n"); + parameters->jpwl_epc_on = true; + + } + break; +#endif /* USE_JPWL */ +/* < Command line not valid\n"); + return 1; + } + } + + /* check for possible errors */ + if (parameters->cp_cinema){ + if(parameters->tcp_numlayers > 1){ + parameters->cp_rsiz = STD_RSIZ; + fprintf(stdout,"Warning: DC profiles do not allow more than one quality layer. The codestream created will not be compliant with the DC profile\n"); + } + } + if(img_fol->set_imgdir == 1){ + if(!(parameters->infile[0] == 0)){ + fprintf(stderr, "Error: options -ImgDir and -i cannot be used together !!\n"); + return 1; + } + if(img_fol->set_out_format == 0){ + fprintf(stderr, "Error: When -ImgDir is used, -OutFor must be used !!\n"); + fprintf(stderr, "Only one format allowed! Valid formats are j2k and jp2!!\n"); + return 1; + } + if(!((parameters->outfile[0] == 0))){ + fprintf(stderr, "Error: options -ImgDir and -o cannot be used together !!\n"); + fprintf(stderr, "Specify OutputFormat using -OutFor !!\n"); + return 1; + } + }else{ + if((parameters->infile[0] == 0) || (parameters->outfile[0] == 0)) { + fprintf(stderr, "Example: %s -i image.ppm -o image.j2k\n",argv[0]); + fprintf(stderr, " Try: %s -h\n",argv[0]); + return 1; + } + } + + if (parameters->decod_format == RAW_DFMT && raw_cp->rawWidth == 0) { + fprintf(stderr,"\nError: invalid raw image parameters\n"); + fprintf(stderr,"Please use the Format option -F:\n"); + fprintf(stderr,"-F rawWidth,rawHeight,rawComp,rawBitDepth,s/u (Signed/Unsigned)\n"); + fprintf(stderr,"Example: -i lena.raw -o lena.j2k -F 512,512,3,8,u\n"); + fprintf(stderr,"Aborting\n"); + return 1; + } + + if ((parameters->cp_disto_alloc || parameters->cp_fixed_alloc || parameters->cp_fixed_quality) + && (!(parameters->cp_disto_alloc ^ parameters->cp_fixed_alloc ^ parameters->cp_fixed_quality))) { + fprintf(stderr, "Error: options -r -q and -f cannot be used together !!\n"); + return 1; + } /* mod fixed_quality */ + + /* if no rate entered, lossless by default */ + if (parameters->tcp_numlayers == 0) { + parameters->tcp_rates[0] = 0; /* MOD antonin : losslessbug */ + parameters->tcp_numlayers++; + parameters->cp_disto_alloc = 1; + } + + if((parameters->cp_tx0 > parameters->image_offset_x0) || (parameters->cp_ty0 > parameters->image_offset_y0)) { + fprintf(stderr, + "Error: Tile offset dimension is unnappropriate --> TX0(%d)<=IMG_X0(%d) TYO(%d)<=IMG_Y0(%d) \n", + parameters->cp_tx0, parameters->image_offset_x0, parameters->cp_ty0, parameters->image_offset_y0); + return 1; + } + + for (i = 0; i < parameters->numpocs; i++) { + if (parameters->POC[i].prg == -1) { + fprintf(stderr, + "Unrecognized progression order in option -P (POC n %d) [LRCP, RLCP, RPCL, PCRL, CPRL] !!\n", + i + 1); + } + } + + return 0; +} + +/* -------------------------------------------------------------------------- */ + +/** +sample error callback expecting a FILE* client object +*/ +void error_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[ERROR] %s", msg); +} +/** +sample warning callback expecting a FILE* client object +*/ +void warning_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[WARNING] %s", msg); +} +/** +sample debug callback expecting a FILE* client object +*/ +void info_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[INFO] %s", msg); +} + +/* -------------------------------------------------------------------------- */ + +int main(int argc, char **argv) { + bool bSuccess; + opj_cparameters_t parameters; /* compression parameters */ + img_fol_t img_fol; + opj_event_mgr_t event_mgr; /* event manager */ + opj_image_t *image = NULL; + int i,num_images; + int imageno; + dircnt_t *dirptr; + raw_cparameters_t raw_cp; + opj_codestream_info_t cstr_info; /* Codestream information structure */ + char indexfilename[OPJ_PATH_LEN]; /* index file name */ + + /* + configure the event callbacks (not required) + setting of each callback is optionnal + */ + memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); + event_mgr.error_handler = error_callback; + event_mgr.warning_handler = warning_callback; + event_mgr.info_handler = info_callback; + + /* set encoding parameters to default values */ + opj_set_default_encoder_parameters(¶meters); + + /* Initialize indexfilename and img_fol */ + *indexfilename = 0; + memset(&img_fol,0,sizeof(img_fol_t)); + + /* parse input and get user encoding parameters */ + if(parse_cmdline_encoder(argc, argv, ¶meters,&img_fol, &raw_cp, indexfilename) == 1) { + return 1; + } + + if (parameters.cp_cinema){ + img_fol.rates = (float*)malloc(parameters.tcp_numlayers * sizeof(float)); + for(i=0; i< parameters.tcp_numlayers; i++){ + img_fol.rates[i] = parameters.tcp_rates[i]; + } + cinema_parameters(¶meters); + } + + /* Create comment for codestream */ + if(parameters.cp_comment == NULL) { + const char comment[] = "Created by OpenJPEG version "; + const size_t clen = strlen(comment); + const char *version = opj_version(); +/* UniPG>> */ +#ifdef USE_JPWL + parameters.cp_comment = (char*)malloc(clen+strlen(version)+11); + sprintf(parameters.cp_comment,"%s%s with JPWL", comment, version); +#else + parameters.cp_comment = (char*)malloc(clen+strlen(version)+1); + sprintf(parameters.cp_comment,"%s%s", comment, version); +#endif +/* <filename_buf = (char*)malloc(num_images*OPJ_PATH_LEN*sizeof(char)); // Stores at max 10 image file names + dirptr->filename = (char**) malloc(num_images*sizeof(char*)); + if(!dirptr->filename_buf){ + return 0; + } + for(i=0;ifilename[i] = dirptr->filename_buf + i*OPJ_PATH_LEN; + } + } + if(load_images(dirptr,img_fol.imgdirpath)==1){ + return 0; + } + if (num_images==0){ + fprintf(stdout,"Folder is empty\n"); + return 0; + } + }else{ + num_images=1; + } + /*Encoding image one by one*/ + for(imageno=0;imagenonumcomps == 3 ? 1 : 0; + + if(parameters.cp_cinema){ + cinema_setup_encoder(¶meters,image,&img_fol); + } + + /* encode the destination image */ + /* ---------------------------- */ + + if (parameters.cod_format == J2K_CFMT) { /* J2K format output */ + int codestream_length; + opj_cio_t *cio = NULL; + FILE *f = NULL; + + /* get a J2K compressor handle */ + opj_cinfo_t* cinfo = opj_create_compress(CODEC_J2K); + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)cinfo, &event_mgr, stderr); + + /* setup the encoder parameters using the current image and user parameters */ + opj_setup_encoder(cinfo, ¶meters, image); + + /* open a byte stream for writing */ + /* allocate memory for all tiles */ + cio = opj_cio_open((opj_common_ptr)cinfo, NULL, 0); + + /* encode the image */ + if (*indexfilename) // If need to extract codestream information + bSuccess = opj_encode_with_info(cinfo, cio, image, &cstr_info); + else + bSuccess = opj_encode(cinfo, cio, image, NULL); + if (!bSuccess) { + opj_cio_close(cio); + fprintf(stderr, "failed to encode image\n"); + return 1; + } + codestream_length = cio_tell(cio); + + /* write the buffer to disk */ + f = fopen(parameters.outfile, "wb"); + if (!f) { + fprintf(stderr, "failed to open %s for writing\n", parameters.outfile); + return 1; + } + fwrite(cio->buffer, 1, codestream_length, f); + fclose(f); + + fprintf(stderr,"Generated outfile %s\n",parameters.outfile); + /* close and free the byte stream */ + opj_cio_close(cio); + + /* Write the index to disk */ + if (*indexfilename) { + bSuccess = write_index_file(&cstr_info, indexfilename); + if (bSuccess) { + fprintf(stderr, "Failed to output index file into [%s]\n", indexfilename); + } + } + + /* free remaining compression structures */ + opj_destroy_compress(cinfo); + if (*indexfilename) + opj_destroy_cstr_info(&cstr_info); + } else { /* JP2 format output */ + int codestream_length; + opj_cio_t *cio = NULL; + FILE *f = NULL; + + /* get a JP2 compressor handle */ + opj_cinfo_t* cinfo = opj_create_compress(CODEC_JP2); + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)cinfo, &event_mgr, stderr); + + /* setup the encoder parameters using the current image and using user parameters */ + opj_setup_encoder(cinfo, ¶meters, image); + + /* open a byte stream for writing */ + /* allocate memory for all tiles */ + cio = opj_cio_open((opj_common_ptr)cinfo, NULL, 0); + + /* encode the image */ + if (*indexfilename) // If need to extract codestream information + bSuccess = opj_encode_with_info(cinfo, cio, image, &cstr_info); + else + bSuccess = opj_encode(cinfo, cio, image, NULL); + if (!bSuccess) { + opj_cio_close(cio); + fprintf(stderr, "failed to encode image\n"); + return 1; + } + codestream_length = cio_tell(cio); + + /* write the buffer to disk */ + f = fopen(parameters.outfile, "wb"); + if (!f) { + fprintf(stderr, "failed to open %s for writing\n", parameters.outfile); + return 1; + } + fwrite(cio->buffer, 1, codestream_length, f); + fclose(f); + fprintf(stderr,"Generated outfile %s\n",parameters.outfile); + /* close and free the byte stream */ + opj_cio_close(cio); + + /* Write the index to disk */ + if (*indexfilename) { + bSuccess = write_index_file(&cstr_info, indexfilename); + if (bSuccess) { + fprintf(stderr, "Failed to output index file\n"); + } + } + + /* free remaining compression structures */ + opj_destroy_compress(cinfo); + if (*indexfilename) + opj_destroy_cstr_info(&cstr_info); + } + + /* free image data */ + opj_image_destroy(image); + } + + /* free user parameters structure */ + if(parameters.cp_comment) free(parameters.cp_comment); + if(parameters.cp_matrice) free(parameters.cp_matrice); + + return 0; +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/codec/image_to_j2k.dsp b/gdcm/Utilities/gdcmopenjpeg-v1/codec/image_to_j2k.dsp new file mode 100644 index 0000000..4f2cc32 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/codec/image_to_j2k.dsp @@ -0,0 +1,118 @@ +# Microsoft Developer Studio Project File - Name="image_to_j2k" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=image_to_j2k - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "image_to_j2k.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "image_to_j2k.mak" CFG="image_to_j2k - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "image_to_j2k - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "image_to_j2k - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "image_to_j2k - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "../libopenjpeg" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "OPJ_STATIC" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x40c /d "NDEBUG" +# ADD RSC /l 0x40c /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ../libs/libtiff/libtiff.lib /nologo /subsystem:console /machine:I386 /nodefaultlib:"LIBC" +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "image_to_j2k - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../libopenjpeg" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "OPJ_STATIC" /FD /GZ /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x40c /d "_DEBUG" +# ADD RSC /l 0x40c /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ../libs/libtiff/libtiff.lib /nologo /subsystem:console /debug /machine:I386 /nodefaultlib:"LIBC" /nodefaultlib:"LIBCMT" /pdbtype:sept +# SUBTRACT LINK32 /pdb:none + +!ENDIF + +# Begin Target + +# Name "image_to_j2k - Win32 Release" +# Name "image_to_j2k - Win32 Debug" +# Begin Source File + +SOURCE=.\convert.c +# End Source File +# Begin Source File + +SOURCE=.\convert.h +# End Source File +# Begin Source File + +SOURCE=.\compat\getopt.c +# End Source File +# Begin Source File + +SOURCE=.\compat\getopt.h +# End Source File +# Begin Source File + +SOURCE=.\image_to_j2k.c +# End Source File +# Begin Source File + +SOURCE=.\index.c +# End Source File +# Begin Source File + +SOURCE=.\index.h +# End Source File +# End Target +# End Project diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/codec/image_to_j2k.dsw b/gdcm/Utilities/gdcmopenjpeg-v1/codec/image_to_j2k.dsw new file mode 100644 index 0000000..5779382 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/codec/image_to_j2k.dsw @@ -0,0 +1,44 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "LibOpenJPEG"=..\LibOpenJPEG.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "image_to_j2k"=.\image_to_j2k.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name LibOpenJPEG + End Project Dependency +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/codec/image_to_j2k.sln b/gdcm/Utilities/gdcmopenjpeg-v1/codec/image_to_j2k.sln new file mode 100644 index 0000000000000000000000000000000000000000..de773c8d50dde46e6a463af8a5d1d4928eae6336 GIT binary patch literal 1506 zcmbW1$!^;)5QcNL0KJ2tTv8wuNG&aW=z&_8qDUGe2AWHOK(=UusUjL$a!K-JJ@k?K z3K`XsEjB@__@?1(-~1fv&#&L6aUqwbs?@5szRRjfb8B8VnN-$XDWajz5Fs%}G$sUL%y2X%;Pu@n z`-An_vd`t>awCebv*gS^wQR@vF*tGVmm4VBIv#xPeqt=}kWVNJhX>El<+Y57;!{m9s-re0f+<$(|~ZAxUn0+ zkft%|aOR*5NO;njv4F8NQ7omXS|v8Bs(0X%$+&qTZ(JZ??1kw_bgj;EwMcV_+kW)4 z{W?UdSjlx$rtJ)~Jgrx-7+dgC^g)n4iN&H>KVHkibAfJPwazP%i?k9uw`Ok{we~M? zI)&b#0U3ul1B3L|OMg0sSp~k=gETeN&l$ RCF1OSp1j&%*U~hOo&g;;wgmtH literal 0 HcmV?d00001 diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/codec/image_to_j2k.vcproj b/gdcm/Utilities/gdcmopenjpeg-v1/codec/image_to_j2k.vcproj new file mode 100644 index 0000000..9037235 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/codec/image_to_j2k.vcproj @@ -0,0 +1,292 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/codec/index.c b/gdcm/Utilities/gdcmopenjpeg-v1/codec/index.c new file mode 100644 index 0000000..c616fcd --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/codec/index.c @@ -0,0 +1,391 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2003-2007, Francois-Olivier Devaux + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include "openjpeg.h" +#include "index.h" + +/* ------------------------------------------------------------------------------------ */ + +/** +Write a structured index to a file +@param cstr_info Codestream information +@param index Index filename +@return Returns 0 if successful, returns 1 otherwise +*/ +int write_index_file(opj_codestream_info_t *cstr_info, char *index) { + int tileno, compno, layno, resno, precno, pack_nb, x, y; + FILE *stream = NULL; + double total_disto = 0; +/* UniPG>> */ + int tilepartno; + char disto_on, numpix_on; + +#ifdef USE_JPWL + if (!strcmp(index, JPWL_PRIVATEINDEX_NAME)) + return 0; +#endif /* USE_JPWL */ +/* <tile[0].distotile) + disto_on = 1; + else + disto_on = 0; + + if (cstr_info->tile[0].numpix) + numpix_on = 1; + else + numpix_on = 0; + + fprintf(stream, "%d %d\n", cstr_info->image_w, cstr_info->image_h); + fprintf(stream, "%d\n", cstr_info->prog); + fprintf(stream, "%d %d\n", cstr_info->tile_x, cstr_info->tile_y); + fprintf(stream, "%d %d\n", cstr_info->tw, cstr_info->th); + fprintf(stream, "%d\n", cstr_info->numcomps); + fprintf(stream, "%d\n", cstr_info->numlayers); + fprintf(stream, "%d\n", cstr_info->numdecompos[0]); /* based on component 0 */ + + for (resno = cstr_info->numdecompos[0]; resno >= 0; resno--) { + fprintf(stream, "[%d,%d] ", + (1 << cstr_info->tile[0].pdx[resno]), (1 << cstr_info->tile[0].pdx[resno])); /* based on tile 0 and component 0 */ + } + + fprintf(stream, "\n"); +/* UniPG>> */ + fprintf(stream, "%d\n", cstr_info->main_head_start); +/* <main_head_end); + fprintf(stream, "%d\n", cstr_info->codestream_size); + + fprintf(stream, "\nINFO ON TILES\n"); + fprintf(stream, "tileno start_pos end_hd end_tile nbparts"); + if (disto_on) + fprintf(stream," disto"); + if (numpix_on) + fprintf(stream," nbpix"); + if (disto_on && numpix_on) + fprintf(stream," disto/nbpix"); + fprintf(stream, "\n"); + + for (tileno = 0; tileno < cstr_info->tw * cstr_info->th; tileno++) { + fprintf(stream, "%4d %9d %9d %9d %9d", + cstr_info->tile[tileno].tileno, + cstr_info->tile[tileno].start_pos, + cstr_info->tile[tileno].end_header, + cstr_info->tile[tileno].end_pos, + cstr_info->tile[tileno].num_tps); + if (disto_on) + fprintf(stream," %9e", cstr_info->tile[tileno].distotile); + if (numpix_on) + fprintf(stream," %9d", cstr_info->tile[tileno].numpix); + if (disto_on && numpix_on) + fprintf(stream," %9e", cstr_info->tile[tileno].distotile / cstr_info->tile[tileno].numpix); + fprintf(stream, "\n"); + } + + for (tileno = 0; tileno < cstr_info->tw * cstr_info->th; tileno++) { + int start_pos, end_ph_pos, end_pos; + double disto = 0; + int max_numdecompos = 0; + pack_nb = 0; + + for (compno = 0; compno < cstr_info->numcomps; compno++) { + if (max_numdecompos < cstr_info->numdecompos[compno]) + max_numdecompos = cstr_info->numdecompos[compno]; + } + + fprintf(stream, "\nTILE %d DETAILS\n", tileno); + fprintf(stream, "part_nb tileno start_pack num_packs start_pos end_tph_pos end_pos\n"); + for (tilepartno = 0; tilepartno < cstr_info->tile[tileno].num_tps; tilepartno++) + fprintf(stream, "%4d %9d %9d %9d %9d %11d %9d\n", + tilepartno, tileno, + cstr_info->tile[tileno].tp[tilepartno].tp_start_pack, + cstr_info->tile[tileno].tp[tilepartno].tp_numpacks, + cstr_info->tile[tileno].tp[tilepartno].tp_start_pos, + cstr_info->tile[tileno].tp[tilepartno].tp_end_header, + cstr_info->tile[tileno].tp[tilepartno].tp_end_pos + ); + + if (cstr_info->prog == LRCP) { /* LRCP */ + fprintf(stream, "LRCP\npack_nb tileno layno resno compno precno start_pos end_ph_pos end_pos"); + if (disto_on) + fprintf(stream, " disto"); + fprintf(stream,"\n"); + + for (layno = 0; layno < cstr_info->numlayers; layno++) { + for (resno = 0; resno < max_numdecompos + 1; resno++) { + for (compno = 0; compno < cstr_info->numcomps; compno++) { + int prec_max; + if (resno > cstr_info->numdecompos[compno]) + break; + prec_max = cstr_info->tile[tileno].pw[resno] * cstr_info->tile[tileno].ph[resno]; + for (precno = 0; precno < prec_max; precno++) { + start_pos = cstr_info->tile[tileno].packet[pack_nb].start_pos; + end_ph_pos = cstr_info->tile[tileno].packet[pack_nb].end_ph_pos; + end_pos = cstr_info->tile[tileno].packet[pack_nb].end_pos; + disto = cstr_info->tile[tileno].packet[pack_nb].disto; + fprintf(stream, "%4d %6d %7d %5d %6d %6d %6d %6d %7d", + pack_nb, tileno, layno, resno, compno, precno, start_pos, end_ph_pos, end_pos); + if (disto_on) + fprintf(stream, " %8e", disto); + fprintf(stream, "\n"); + total_disto += disto; + pack_nb++; + } + } + } + } + } /* LRCP */ + + else if (cstr_info->prog == RLCP) { /* RLCP */ + fprintf(stream, "RLCP\npack_nb tileno resno layno compno precno start_pos end_ph_pos end_pos\n"); + if (disto_on) + fprintf(stream, " disto"); + fprintf(stream,"\n"); + + for (resno = 0; resno < max_numdecompos + 1; resno++) { + for (layno = 0; layno < cstr_info->numlayers; layno++) { + for (compno = 0; compno < cstr_info->numcomps; compno++) { + int prec_max; + if (resno > cstr_info->numdecompos[compno]) + break; + prec_max = cstr_info->tile[tileno].pw[resno] * cstr_info->tile[tileno].ph[resno]; + for (precno = 0; precno < prec_max; precno++) { + start_pos = cstr_info->tile[tileno].packet[pack_nb].start_pos; + end_ph_pos = cstr_info->tile[tileno].packet[pack_nb].end_ph_pos; + end_pos = cstr_info->tile[tileno].packet[pack_nb].end_pos; + disto = cstr_info->tile[tileno].packet[pack_nb].disto; + fprintf(stream, "%4d %6d %5d %7d %6d %6d %9d %9d %7d", + pack_nb, tileno, resno, layno, compno, precno, start_pos, end_ph_pos, end_pos); + if (disto_on) + fprintf(stream, " %8e", disto); + fprintf(stream, "\n"); + total_disto += disto; + pack_nb++; + } + } + } + } + } /* RLCP */ + + else if (cstr_info->prog == RPCL) { /* RPCL */ + + fprintf(stream, "RPCL\npack_nb tileno resno precno compno layno start_pos end_ph_pos end_pos"); + if (disto_on) + fprintf(stream, " disto"); + fprintf(stream,"\n"); + + for (resno = 0; resno < max_numdecompos + 1; resno++) { + int numprec = cstr_info->tile[tileno].pw[resno] * cstr_info->tile[tileno].ph[resno]; + for (precno = 0; precno < numprec; precno++) { + /* I suppose components have same XRsiz, YRsiz */ + int x0 = cstr_info->tile_Ox + tileno - (int)floor((float)tileno/(float)cstr_info->tw ) * cstr_info->tw * cstr_info->tile_x; + int y0 = cstr_info->tile_Ox + (int)floor( (float)tileno/(float)cstr_info->tw ) * cstr_info->tile_y; + int x1 = x0 + cstr_info->tile_x; + int y1 = y0 + cstr_info->tile_y; + for (compno = 0; compno < cstr_info->numcomps; compno++) { + int pcnx = cstr_info->tile[tileno].pw[resno]; + int pcx = (int) pow( 2, cstr_info->tile[tileno].pdx[resno] + cstr_info->numdecompos[compno] - resno ); + int pcy = (int) pow( 2, cstr_info->tile[tileno].pdy[resno] + cstr_info->numdecompos[compno] - resno ); + int precno_x = precno - (int) floor( (float)precno/(float)pcnx ) * pcnx; + int precno_y = (int) floor( (float)precno/(float)pcnx ); + if (resno > cstr_info->numdecompos[compno]) + break; + for(y = y0; y < y1; y++) { + if (precno_y*pcy == y ) { + for (x = x0; x < x1; x++) { + if (precno_x*pcx == x ) { + for (layno = 0; layno < cstr_info->numlayers; layno++) { + start_pos = cstr_info->tile[tileno].packet[pack_nb].start_pos; + end_ph_pos = cstr_info->tile[tileno].packet[pack_nb].end_ph_pos; + end_pos = cstr_info->tile[tileno].packet[pack_nb].end_pos; + disto = cstr_info->tile[tileno].packet[pack_nb].disto; + fprintf(stream, "%4d %6d %5d %6d %6d %7d %9d %9d %7d", + pack_nb, tileno, resno, precno, compno, layno, start_pos, end_ph_pos, end_pos); + if (disto_on) + fprintf(stream, " %8e", disto); + fprintf(stream, "\n"); + total_disto += disto; + pack_nb++; + } + } + }/* x = x0..x1 */ + } + } /* y = y0..y1 */ + } /* precno */ + } /* compno */ + } /* resno */ + } /* RPCL */ + + else if (cstr_info->prog == PCRL) { /* PCRL */ + /* I suppose components have same XRsiz, YRsiz */ + int x0 = cstr_info->tile_Ox + tileno - (int)floor( (float)tileno/(float)cstr_info->tw ) * cstr_info->tw * cstr_info->tile_x; + int y0 = cstr_info->tile_Ox + (int)floor( (float)tileno/(float)cstr_info->tw ) * cstr_info->tile_y; + int x1 = x0 + cstr_info->tile_x; + int y1 = y0 + cstr_info->tile_y; + + // Count the maximum number of precincts + int max_numprec = 0; + for (resno = 0; resno < max_numdecompos + 1; resno++) { + int numprec = cstr_info->tile[tileno].pw[resno] * cstr_info->tile[tileno].ph[resno]; + if (numprec > max_numprec) + max_numprec = numprec; + } + + fprintf(stream, "PCRL\npack_nb tileno precno compno resno layno start_pos end_ph_pos end_pos"); + if (disto_on) + fprintf(stream, " disto"); + fprintf(stream,"\n"); + + for (precno = 0; precno < max_numprec; precno++) { + for (compno = 0; compno < cstr_info->numcomps; compno++) { + for (resno = 0; resno < cstr_info->numdecompos[compno] + 1; resno++) { + int numprec = cstr_info->tile[tileno].pw[resno] * cstr_info->tile[tileno].ph[resno]; + int pcnx = cstr_info->tile[tileno].pw[resno]; + int pcx = (int) pow( 2, cstr_info->tile[tileno].pdx[resno] + cstr_info->numdecompos[compno] - resno ); + int pcy = (int) pow( 2, cstr_info->tile[tileno].pdy[resno] + cstr_info->numdecompos[compno] - resno ); + int precno_x = precno - (int) floor( (float)precno/(float)pcnx ) * pcnx; + int precno_y = (int) floor( (float)precno/(float)pcnx ); + if (precno >= numprec) + continue; + for(y = y0; y < y1; y++) { + if (precno_y*pcy == y ) { + for (x = x0; x < x1; x++) { + if (precno_x*pcx == x ) { + for (layno = 0; layno < cstr_info->numlayers; layno++) { + start_pos = cstr_info->tile[tileno].packet[pack_nb].start_pos; + end_ph_pos = cstr_info->tile[tileno].packet[pack_nb].end_ph_pos; + end_pos = cstr_info->tile[tileno].packet[pack_nb].end_pos; + disto = cstr_info->tile[tileno].packet[pack_nb].disto; + fprintf(stream, "%4d %6d %6d %6d %5d %7d %9d %9d %7d", + pack_nb, tileno, precno, compno, resno, layno, start_pos, end_ph_pos, end_pos); + if (disto_on) + fprintf(stream, " %8e", disto); + fprintf(stream, "\n"); + total_disto += disto; + pack_nb++; + } + } + }/* x = x0..x1 */ + } + } /* y = y0..y1 */ + } /* resno */ + } /* compno */ + } /* precno */ + } /* PCRL */ + + else { /* CPRL */ + // Count the maximum number of precincts + int max_numprec = 0; + for (resno = 0; resno < max_numdecompos + 1; resno++) { + int numprec = cstr_info->tile[tileno].pw[resno] * cstr_info->tile[tileno].ph[resno]; + if (numprec > max_numprec) + max_numprec = numprec; + } + + fprintf(stream, "CPRL\npack_nb tileno compno precno resno layno start_pos end_ph_pos end_pos"); + if (disto_on) + fprintf(stream, " disto"); + fprintf(stream,"\n"); + + for (compno = 0; compno < cstr_info->numcomps; compno++) { + /* I suppose components have same XRsiz, YRsiz */ + int x0 = cstr_info->tile_Ox + tileno - (int)floor( (float)tileno/(float)cstr_info->tw ) * cstr_info->tw * cstr_info->tile_x; + int y0 = cstr_info->tile_Ox + (int)floor( (float)tileno/(float)cstr_info->tw ) * cstr_info->tile_y; + int x1 = x0 + cstr_info->tile_x; + int y1 = y0 + cstr_info->tile_y; + + for (precno = 0; precno < max_numprec; precno++) { + for (resno = 0; resno < cstr_info->numdecompos[compno] + 1; resno++) { + int numprec = cstr_info->tile[tileno].pw[resno] * cstr_info->tile[tileno].ph[resno]; + int pcnx = cstr_info->tile[tileno].pw[resno]; + int pcx = (int) pow( 2, cstr_info->tile[tileno].pdx[resno] + cstr_info->numdecompos[compno] - resno ); + int pcy = (int) pow( 2, cstr_info->tile[tileno].pdy[resno] + cstr_info->numdecompos[compno] - resno ); + int precno_x = precno - (int) floor( (float)precno/(float)pcnx ) * pcnx; + int precno_y = (int) floor( (float)precno/(float)pcnx ); + if (precno >= numprec) + continue; + + for(y = y0; y < y1; y++) { + if (precno_y*pcy == y ) { + for (x = x0; x < x1; x++) { + if (precno_x*pcx == x ) { + for (layno = 0; layno < cstr_info->numlayers; layno++) { + start_pos = cstr_info->tile[tileno].packet[pack_nb].start_pos; + end_ph_pos = cstr_info->tile[tileno].packet[pack_nb].end_ph_pos; + end_pos = cstr_info->tile[tileno].packet[pack_nb].end_pos; + disto = cstr_info->tile[tileno].packet[pack_nb].disto; + fprintf(stream, "%4d %6d %6d %6d %5d %7d %9d %9d %7d", + pack_nb, tileno, compno, precno, resno, layno, start_pos, end_ph_pos, end_pos); + if (disto_on) + fprintf(stream, " %8e", disto); + fprintf(stream, "\n"); + total_disto += disto; + pack_nb++; + } + } + }/* x = x0..x1 */ + } + } /* y = y0..y1 */ + } /* resno */ + } /* precno */ + } /* compno */ + } /* CPRL */ + } /* tileno */ + + if (disto_on) { + fprintf(stream, "%8e\n", cstr_info->D_max); /* SE max */ + fprintf(stream, "%.8e\n", total_disto); /* SE totale */ + } +/* UniPG>> */ + /* print the markers' list */ + if (cstr_info->marknum) { + fprintf(stream, "\nMARKER LIST\n"); + fprintf(stream, "%d\n", cstr_info->marknum); + fprintf(stream, "type\tstart_pos length\n"); + for (x = 0; x < cstr_info->marknum; x++) + fprintf(stream, "%X\t%9d %9d\n", cstr_info->marker[x].type, cstr_info->marker[x].pos, cstr_info->marker[x].len); + } +/* < +#include +#include +#include + +#ifdef _WIN32 +#include "windirent.h" +#else +#include +#endif /* _WIN32 */ + +#ifdef _WIN32 +#include +#else +#include +#define _stricmp strcasecmp +#define _strnicmp strncasecmp +#endif /* _WIN32 */ + +#include "opj_config.h" +#include "openjpeg.h" +#include "../libopenjpeg/j2k.h" +#include "../libopenjpeg/jp2.h" +#include "getopt.h" +#include "convert.h" +#include "index.h" + +#include "format_defs.h" + +typedef struct dircnt{ + /** Buffer for holding images read from Directory*/ + char *filename_buf; + /** Pointer to the buffer*/ + char **filename; +}dircnt_t; + + +typedef struct img_folder{ + /** The directory path of the folder containing input images*/ + char *imgdirpath; + /** Output format*/ + const char *out_format; + /** Enable option*/ + char set_imgdir; + /** Enable Cod Format for output*/ + char set_out_format; + +}img_fol_t; + +void decode_help_display() { + fprintf(stdout,"HELP for j2k_dump\n----\n\n"); + fprintf(stdout,"- the -h option displays this help information on screen\n\n"); + +/* UniPG>> */ + fprintf(stdout,"List of parameters for the JPEG 2000 " +#ifdef USE_JPWL + "+ JPWL " +#endif /* USE_JPWL */ + "decoder:\n"); +/* <\n"); + fprintf(stdout," REQUIRED only if an Input image directory not specified\n"); + fprintf(stdout," Currently accepts J2K-files, JP2-files and JPT-files. The file type\n"); + fprintf(stdout," is identified based on its suffix.\n"); + fprintf(stdout,"\n"); +} + +/* -------------------------------------------------------------------------- */ +static void j2k_dump_image(FILE *fd, opj_image_t * img); +static void j2k_dump_cp(FILE *fd, opj_image_t * img, opj_cp_t * cp); + +int get_num_images(char *imgdirpath){ + DIR *dir; + struct dirent* content; + int num_images = 0; + + /*Reading the input images from given input directory*/ + + dir= opendir(imgdirpath); + if(!dir){ + fprintf(stderr,"Could not open Folder %s\n",imgdirpath); + return 0; + } + + while((content=readdir(dir))!=NULL){ + if(strcmp(".",content->d_name)==0 || strcmp("..",content->d_name)==0 ) + continue; + num_images++; + } + return num_images; +} + +int load_images(dircnt_t *dirptr, char *imgdirpath){ + DIR *dir; + struct dirent* content; + int i = 0; + + /*Reading the input images from given input directory*/ + + dir= opendir(imgdirpath); + if(!dir){ + fprintf(stderr,"Could not open Folder %s\n",imgdirpath); + return 1; + }else { + fprintf(stderr,"Folder opened successfully\n"); + } + + while((content=readdir(dir))!=NULL){ + if(strcmp(".",content->d_name)==0 || strcmp("..",content->d_name)==0 ) + continue; + + strcpy(dirptr->filename[i],content->d_name); + i++; + } + return 0; +} + +int get_file_format(char *filename) { + unsigned int i; + static const char *extension[] = {"pgx", "pnm", "pgm", "ppm", "bmp","tif", "raw", "tga", "png", "j2k", "jp2", "jpt", "j2c", "jpc" }; + static const int format[] = { PGX_DFMT, PXM_DFMT, PXM_DFMT, PXM_DFMT, BMP_DFMT, TIF_DFMT, RAW_DFMT, TGA_DFMT, PNG_DFMT, J2K_CFMT, JP2_CFMT, JPT_CFMT, J2K_CFMT, J2K_CFMT }; + char * ext = strrchr(filename, '.'); + if (ext == NULL) + return -1; + ext++; + if(ext) { + for(i = 0; i < sizeof(format)/sizeof(*format); i++) { + if(_strnicmp(ext, extension[i], 3) == 0) { + return format[i]; + } + } + } + + return -1; +} + +char get_next_file(int imageno,dircnt_t *dirptr,img_fol_t *img_fol, opj_dparameters_t *parameters){ + char image_filename[OPJ_PATH_LEN], infilename[OPJ_PATH_LEN],outfilename[OPJ_PATH_LEN],temp_ofname[OPJ_PATH_LEN]; + char *temp_p, temp1[OPJ_PATH_LEN]=""; + + strcpy(image_filename,dirptr->filename[imageno]); + fprintf(stderr,"File Number %d \"%s\"\n",imageno,image_filename); + parameters->decod_format = get_file_format(image_filename); + if (parameters->decod_format == -1) + return 1; + sprintf(infilename,"%s/%s",img_fol->imgdirpath,image_filename); + strncpy(parameters->infile, infilename, sizeof(infilename)); + + //Set output file + strcpy(temp_ofname,strtok(image_filename,".")); + while((temp_p = strtok(NULL,".")) != NULL){ + strcat(temp_ofname,temp1); + sprintf(temp1,".%s",temp_p); + } + if(img_fol->set_out_format==1){ + sprintf(outfilename,"%s/%s.%s",img_fol->imgdirpath,temp_ofname,img_fol->out_format); + strncpy(parameters->outfile, outfilename, sizeof(outfilename)); + } + return 0; +} + +/* -------------------------------------------------------------------------- */ +int parse_cmdline_decoder(int argc, char **argv, opj_dparameters_t *parameters,img_fol_t *img_fol, char *indexfilename) { + /* parse the command line */ + int totlen; + option_t long_option[]={ + {"ImgDir",REQ_ARG, NULL ,'y'}, + }; + + const char optlist[] = "i:h"; + totlen=sizeof(long_option); + img_fol->set_out_format = 0; + while (1) { + int c = getopt_long(argc, argv,optlist,long_option,totlen); + if (c == -1) + break; + switch (c) { + case 'i': /* input file */ + { + char *infile = optarg; + parameters->decod_format = get_file_format(infile); + switch(parameters->decod_format) { + case J2K_CFMT: + case JP2_CFMT: + case JPT_CFMT: + break; + default: + fprintf(stderr, + "!! Unrecognized format for infile : %s [accept only *.j2k, *.jp2, *.jpc or *.jpt] !!\n\n", + infile); + return 1; + } + strncpy(parameters->infile, infile, sizeof(parameters->infile)-1); + } + break; + + /* ----------------------------------------------------- */ + + case 'h': /* display an help description */ + decode_help_display(); + return 1; + + /* ------------------------------------------------------ */ + + case 'y': /* Image Directory path */ + { + img_fol->imgdirpath = (char*)malloc(strlen(optarg) + 1); + strcpy(img_fol->imgdirpath,optarg); + img_fol->set_imgdir=1; + } + break; + + /* ----------------------------------------------------- */ + + default: + fprintf(stderr,"WARNING -> this option is not valid \"-%c %s\"\n",c, optarg); + break; + } + } + + /* check for possible errors */ + if(img_fol->set_imgdir==1){ + if(!(parameters->infile[0]==0)){ + fprintf(stderr, "Error: options -ImgDir and -i cannot be used together !!\n"); + return 1; + } + if(img_fol->set_out_format == 0){ + fprintf(stderr, "Error: When -ImgDir is used, -OutFor must be used !!\n"); + fprintf(stderr, "Only one format allowed! Valid format PGM, PPM, PNM, PGX, BMP, TIF, RAW and TGA!!\n"); + return 1; + } + if(!((parameters->outfile[0] == 0))){ + fprintf(stderr, "Error: options -ImgDir and -o cannot be used together !!\n"); + return 1; + } + }else{ + if((parameters->infile[0] == 0) ) { + fprintf(stderr, "Example: %s -i image.j2k\n",argv[0]); + fprintf(stderr, " Try: %s -h\n",argv[0]); + return 1; + } + } + + return 0; +} + +/* -------------------------------------------------------------------------- */ + +/** +sample error callback expecting a FILE* client object +*/ +void error_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[ERROR] %s", msg); +} +/** +sample warning callback expecting a FILE* client object +*/ +void warning_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[WARNING] %s", msg); +} +/** +sample debug callback expecting no client object +*/ +void info_callback(const char *msg, void *client_data) { + (void)client_data; + fprintf(stdout, "[INFO] %s", msg); +} + +/* -------------------------------------------------------------------------- */ + +int main(int argc, char *argv[]) +{ + opj_dparameters_t parameters; /* decompression parameters */ + img_fol_t img_fol; + opj_event_mgr_t event_mgr; /* event manager */ + opj_image_t *image = NULL; + FILE *fsrc = NULL; + unsigned char *src = NULL; + int file_length; + int num_images; + int i,imageno; + dircnt_t *dirptr = NULL; + opj_dinfo_t* dinfo = NULL; /* handle to a decompressor */ + opj_cio_t *cio = NULL; + opj_codestream_info_t cstr_info; /* Codestream information structure */ + char indexfilename[OPJ_PATH_LEN]; /* index file name */ + + /* configure the event callbacks (not required) */ + memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); + event_mgr.error_handler = error_callback; + event_mgr.warning_handler = warning_callback; + event_mgr.info_handler = info_callback; + + /* set decoding parameters to default values */ + opj_set_default_decoder_parameters(¶meters); + + /* Initialize indexfilename and img_fol */ + *indexfilename = 0; + memset(&img_fol,0,sizeof(img_fol_t)); + + /* parse input and get user encoding parameters */ + if(parse_cmdline_decoder(argc, argv, ¶meters,&img_fol, indexfilename) == 1) { + return 1; + } + + /* Initialize reading of directory */ + if(img_fol.set_imgdir==1){ + num_images=get_num_images(img_fol.imgdirpath); + + dirptr=(dircnt_t*)malloc(sizeof(dircnt_t)); + if(dirptr){ + dirptr->filename_buf = (char*)malloc(num_images*OPJ_PATH_LEN*sizeof(char)); // Stores at max 10 image file names + dirptr->filename = (char**) malloc(num_images*sizeof(char*)); + + if(!dirptr->filename_buf){ + return 1; + } + for(i=0;ifilename[i] = dirptr->filename_buf + i*OPJ_PATH_LEN; + } + } + if(load_images(dirptr,img_fol.imgdirpath)==1){ + return 1; + } + if (num_images==0){ + fprintf(stdout,"Folder is empty\n"); + return 1; + } + }else{ + num_images=1; + } + + /*Encoding image one by one*/ + for(imageno = 0; imageno < num_images ; imageno++) + { + image = NULL; + fprintf(stderr,"\n"); + + if(img_fol.set_imgdir==1){ + if (get_next_file(imageno, dirptr,&img_fol, ¶meters)) { + fprintf(stderr,"skipping file...\n"); + continue; + } + } + + /* read the input file and put it in memory */ + /* ---------------------------------------- */ + fsrc = fopen(parameters.infile, "rb"); + if (!fsrc) { + fprintf(stderr, "ERROR -> failed to open %s for reading\n", parameters.infile); + return 1; + } + fseek(fsrc, 0, SEEK_END); + file_length = ftell(fsrc); + fseek(fsrc, 0, SEEK_SET); + src = (unsigned char *) malloc(file_length); + fread(src, 1, file_length, fsrc); + fclose(fsrc); + + /* decode the code-stream */ + /* ---------------------- */ + + switch(parameters.decod_format) { + case J2K_CFMT: + { + /* JPEG-2000 codestream */ + + /* get a decoder handle */ + dinfo = opj_create_decompress(CODEC_J2K); + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr); + + /* setup the decoder decoding parameters using user parameters */ + opj_setup_decoder(dinfo, ¶meters); + + /* open a byte stream */ + cio = opj_cio_open((opj_common_ptr)dinfo, src, file_length); + + /* decode the stream and fill the image structure */ + if (*indexfilename) // If need to extract codestream information + image = opj_decode_with_info(dinfo, cio, &cstr_info); + else + image = opj_decode(dinfo, cio); + if(!image) { + fprintf(stderr, "ERROR -> j2k_to_image: failed to decode image!\n"); + opj_destroy_decompress(dinfo); + opj_cio_close(cio); + return 1; + } + /* dump image */ + j2k_dump_image(stdout, image); + + /* dump cp */ + j2k_dump_cp(stdout, image, ((opj_j2k_t*)dinfo->j2k_handle)->cp); + + /* close the byte stream */ + opj_cio_close(cio); + + /* Write the index to disk */ + if (*indexfilename) { + char bSuccess; + bSuccess = write_index_file(&cstr_info, indexfilename); + if (bSuccess) { + fprintf(stderr, "Failed to output index file\n"); + } + } + } + break; + + case JP2_CFMT: + { + /* JPEG 2000 compressed image data */ + + /* get a decoder handle */ + dinfo = opj_create_decompress(CODEC_JP2); + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr); + + /* setup the decoder decoding parameters using the current image and user parameters */ + opj_setup_decoder(dinfo, ¶meters); + + /* open a byte stream */ + cio = opj_cio_open((opj_common_ptr)dinfo, src, file_length); + + /* decode the stream and fill the image structure */ + if (*indexfilename) // If need to extract codestream information + image = opj_decode_with_info(dinfo, cio, &cstr_info); + else + image = opj_decode(dinfo, cio); + if(!image) { + fprintf(stderr, "ERROR -> j2k_to_image: failed to decode image!\n"); + opj_destroy_decompress(dinfo); + opj_cio_close(cio); + return 1; + } + /* dump image */ + if(image->icc_profile_buf) + { + free(image->icc_profile_buf); image->icc_profile_buf = NULL; + } + j2k_dump_image(stdout, image); + + /* dump cp */ + j2k_dump_cp(stdout, image, ((opj_jp2_t*)dinfo->jp2_handle)->j2k->cp); + + /* close the byte stream */ + opj_cio_close(cio); + + /* Write the index to disk */ + if (*indexfilename) { + char bSuccess; + bSuccess = write_index_file(&cstr_info, indexfilename); + if (bSuccess) { + fprintf(stderr, "Failed to output index file\n"); + } + } + } + break; + + case JPT_CFMT: + { + /* JPEG 2000, JPIP */ + + /* get a decoder handle */ + dinfo = opj_create_decompress(CODEC_JPT); + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr); + + /* setup the decoder decoding parameters using user parameters */ + opj_setup_decoder(dinfo, ¶meters); + + /* open a byte stream */ + cio = opj_cio_open((opj_common_ptr)dinfo, src, file_length); + + /* decode the stream and fill the image structure */ + if (*indexfilename) // If need to extract codestream information + image = opj_decode_with_info(dinfo, cio, &cstr_info); + else + image = opj_decode(dinfo, cio); + if(!image) { + fprintf(stderr, "ERROR -> j2k_to_image: failed to decode image!\n"); + opj_destroy_decompress(dinfo); + opj_cio_close(cio); + return 1; + } + + /* close the byte stream */ + opj_cio_close(cio); + + /* Write the index to disk */ + if (*indexfilename) { + char bSuccess; + bSuccess = write_index_file(&cstr_info, indexfilename); + if (bSuccess) { + fprintf(stderr, "Failed to output index file\n"); + } + } + } + break; + + default: + fprintf(stderr, "skipping file..\n"); + continue; + } + + /* free the memory containing the code-stream */ + free(src); + src = NULL; + + /* free remaining structures */ + if(dinfo) { + opj_destroy_decompress(dinfo); + } + /* free codestream information structure */ + if (*indexfilename) + opj_destroy_cstr_info(&cstr_info); + /* free image data structure */ + opj_image_destroy(image); + + } + + return EXIT_SUCCESS; +} + + +static void j2k_dump_image(FILE *fd, opj_image_t * img) { + int compno; + fprintf(fd, "image {\n"); + fprintf(fd, " x0=%d, y0=%d, x1=%d, y1=%d\n", img->x0, img->y0, img->x1, img->y1); + fprintf(fd, " numcomps=%d\n", img->numcomps); + for (compno = 0; compno < img->numcomps; compno++) { + opj_image_comp_t *comp = &img->comps[compno]; + fprintf(fd, " comp %d {\n", compno); + fprintf(fd, " dx=%d, dy=%d\n", comp->dx, comp->dy); + fprintf(fd, " prec=%d\n", comp->prec); + //fprintf(fd, " bpp=%d\n", comp->bpp); + fprintf(fd, " sgnd=%d\n", comp->sgnd); + fprintf(fd, " }\n"); + } + fprintf(fd, "}\n"); +} + +static void j2k_dump_cp(FILE *fd, opj_image_t * img, opj_cp_t * cp) { + int tileno, compno, layno, bandno, resno, numbands; + fprintf(fd, "coding parameters {\n"); + fprintf(fd, " tx0=%d, ty0=%d\n", cp->tx0, cp->ty0); + fprintf(fd, " tdx=%d, tdy=%d\n", cp->tdx, cp->tdy); + fprintf(fd, " tw=%d, th=%d\n", cp->tw, cp->th); + for (tileno = 0; tileno < cp->tw * cp->th; tileno++) { + opj_tcp_t *tcp = &cp->tcps[tileno]; + fprintf(fd, " tile %d {\n", tileno); + fprintf(fd, " csty=%x\n", tcp->csty); + fprintf(fd, " prg=%d\n", tcp->prg); + fprintf(fd, " numlayers=%d\n", tcp->numlayers); + fprintf(fd, " mct=%d\n", tcp->mct); + fprintf(fd, " rates="); + for (layno = 0; layno < tcp->numlayers; layno++) { + fprintf(fd, "%.1f ", tcp->rates[layno]); + } + fprintf(fd, "\n"); + for (compno = 0; compno < img->numcomps; compno++) { + opj_tccp_t *tccp = &tcp->tccps[compno]; + fprintf(fd, " comp %d {\n", compno); + fprintf(fd, " csty=%x\n", tccp->csty); + fprintf(fd, " numresolutions=%d\n", tccp->numresolutions); + fprintf(fd, " cblkw=%d\n", tccp->cblkw); + fprintf(fd, " cblkh=%d\n", tccp->cblkh); + fprintf(fd, " cblksty=%x\n", tccp->cblksty); + fprintf(fd, " qmfbid=%d\n", tccp->qmfbid); + fprintf(fd, " qntsty=%d\n", tccp->qntsty); + fprintf(fd, " numgbits=%d\n", tccp->numgbits); + fprintf(fd, " roishift=%d\n", tccp->roishift); + fprintf(fd, " stepsizes="); + numbands = tccp->qntsty == J2K_CCP_QNTSTY_SIQNT ? 1 : tccp->numresolutions * 3 - 2; + for (bandno = 0; bandno < numbands; bandno++) { + fprintf(fd, "(%d,%d) ", tccp->stepsizes[bandno].mant, + tccp->stepsizes[bandno].expn); + } + fprintf(fd, "\n"); + + if (tccp->csty & J2K_CCP_CSTY_PRT) { + fprintf(fd, " prcw="); + for (resno = 0; resno < tccp->numresolutions; resno++) { + fprintf(fd, "%d ", tccp->prcw[resno]); + } + fprintf(fd, "\n"); + fprintf(fd, " prch="); + for (resno = 0; resno < tccp->numresolutions; resno++) { + fprintf(fd, "%d ", tccp->prch[resno]); + } + fprintf(fd, "\n"); + } + fprintf(fd, " }\n"); + } + fprintf(fd, " }\n"); + } + fprintf(fd, "}\n"); +} + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/codec/j2k_to_image.c b/gdcm/Utilities/gdcmopenjpeg-v1/codec/j2k_to_image.c new file mode 100644 index 0000000..ff6141e --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/codec/j2k_to_image.c @@ -0,0 +1,845 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2006-2007, Parvatha Elangovan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#ifdef _WIN32 +#include "windirent.h" +#else +#include +#endif /* _WIN32 */ + +#ifdef _WIN32 +#include +#else +#include +#define _stricmp strcasecmp +#define _strnicmp strncasecmp +#endif /* _WIN32 */ + +#include "opj_config.h" +#include "openjpeg.h" +#include "getopt.h" +#include "convert.h" +#include "index.h" + +#ifdef HAVE_LIBLCMS2 +#include +#endif +#ifdef HAVE_LIBLCMS1 +#include +#endif +#include "color.h" + +#include "format_defs.h" + +typedef struct dircnt{ + /** Buffer for holding images read from Directory*/ + char *filename_buf; + /** Pointer to the buffer*/ + char **filename; +}dircnt_t; + + +typedef struct img_folder{ + /** The directory path of the folder containing input images*/ + char *imgdirpath; + /** Output format*/ + const char *out_format; + /** Enable option*/ + char set_imgdir; + /** Enable Cod Format for output*/ + char set_out_format; + +}img_fol_t; + +void decode_help_display() { + fprintf(stdout,"HELP for j2k_to_image\n----\n\n"); + fprintf(stdout,"- the -h option displays this help information on screen\n\n"); + +/* UniPG>> */ + fprintf(stdout,"List of parameters for the JPEG 2000 " +#ifdef USE_JPWL + "+ JPWL " +#endif /* USE_JPWL */ + "decoder:\n"); +/* < \n"); + fprintf(stdout," Currently accepts PGM, PPM, PNM, PGX, PNG, BMP, TIF, RAW and TGA formats\n"); + fprintf(stdout," -i \n"); + fprintf(stdout," REQUIRED only if an Input image directory not specified\n"); + fprintf(stdout," Currently accepts J2K-files, JP2-files and JPT-files. The file type\n"); + fprintf(stdout," is identified based on its suffix.\n"); + fprintf(stdout," -o \n"); + fprintf(stdout," REQUIRED\n"); + fprintf(stdout," Currently accepts PGM, PPM, PNM, PGX, PNG, BMP, TIF, RAW and TGA files\n"); + fprintf(stdout," Binary data is written to the file (not ascii). If a PGX\n"); + fprintf(stdout," filename is given, there will be as many output files as there are\n"); + fprintf(stdout," components: an indice starting from 0 will then be appended to the\n"); + fprintf(stdout," output filename, just before the \"pgx\" extension. If a PGM filename\n"); + fprintf(stdout," is given and there are more than one component, only the first component\n"); + fprintf(stdout," will be written to the file.\n"); + fprintf(stdout," -r \n"); + fprintf(stdout," Set the number of highest resolution levels to be discarded. The\n"); + fprintf(stdout," image resolution is effectively divided by 2 to the power of the\n"); + fprintf(stdout," number of discarded levels. The reduce factor is limited by the\n"); + fprintf(stdout," smallest total number of decomposition levels among tiles.\n"); + fprintf(stdout," -l \n"); + fprintf(stdout," Set the maximum number of quality layers to decode. If there are\n"); + fprintf(stdout," less quality layers than the specified number, all the quality layers\n"); + fprintf(stdout," are decoded.\n"); + fprintf(stdout," -x \n"); + fprintf(stdout," Create an index file *.Idx (-x index_name.Idx) \n"); + fprintf(stdout,"\n"); +/* UniPG>> */ +#ifdef USE_JPWL + fprintf(stdout," -W \n"); + fprintf(stdout," Activates the JPWL correction capability, if the codestream complies.\n"); + fprintf(stdout," Options can be a comma separated list of tokens:\n"); + fprintf(stdout," c, c=numcomps\n"); + fprintf(stdout," numcomps is the number of expected components in the codestream\n"); + fprintf(stdout," (search of first EPB rely upon this, default is %d)\n", JPWL_EXPECTED_COMPONENTS); +#endif /* USE_JPWL */ +/* <d_name)==0 || strcmp("..",content->d_name)==0 ) + continue; + num_images++; + } + return num_images; +} + +int load_images(dircnt_t *dirptr, char *imgdirpath){ + DIR *dir; + struct dirent* content; + int i = 0; + + /*Reading the input images from given input directory*/ + + dir= opendir(imgdirpath); + if(!dir){ + fprintf(stderr,"Could not open Folder %s\n",imgdirpath); + return 1; + }else { + fprintf(stderr,"Folder opened successfully\n"); + } + + while((content=readdir(dir))!=NULL){ + if(strcmp(".",content->d_name)==0 || strcmp("..",content->d_name)==0 ) + continue; + + strcpy(dirptr->filename[i],content->d_name); + i++; + } + return 0; +} + +int get_file_format(char *filename) { + unsigned int i; + static const char *extension[] = {"pgx", "pnm", "pgm", "ppm", "bmp","tif", "raw", "tga", "png", "j2k", "jp2", "jpt", "j2c", "jpc" }; + static const int format[] = { PGX_DFMT, PXM_DFMT, PXM_DFMT, PXM_DFMT, BMP_DFMT, TIF_DFMT, RAW_DFMT, TGA_DFMT, PNG_DFMT, J2K_CFMT, JP2_CFMT, JPT_CFMT, J2K_CFMT, J2K_CFMT }; + char * ext = strrchr(filename, '.'); + if (ext == NULL) + return -1; + ext++; + if(ext) { + for(i = 0; i < sizeof(format)/sizeof(*format); i++) { + if(_strnicmp(ext, extension[i], 3) == 0) { + return format[i]; + } + } + } + + return -1; +} + +char get_next_file(int imageno,dircnt_t *dirptr,img_fol_t *img_fol, opj_dparameters_t *parameters){ + char image_filename[OPJ_PATH_LEN], infilename[OPJ_PATH_LEN],outfilename[OPJ_PATH_LEN],temp_ofname[OPJ_PATH_LEN]; + char *temp_p, temp1[OPJ_PATH_LEN]=""; + + strcpy(image_filename,dirptr->filename[imageno]); + fprintf(stderr,"File Number %d \"%s\"\n",imageno,image_filename); + parameters->decod_format = get_file_format(image_filename); + if (parameters->decod_format == -1) + return 1; + sprintf(infilename,"%s/%s",img_fol->imgdirpath,image_filename); + strncpy(parameters->infile, infilename, sizeof(infilename)); + + //Set output file + strcpy(temp_ofname,strtok(image_filename,".")); + while((temp_p = strtok(NULL,".")) != NULL){ + strcat(temp_ofname,temp1); + sprintf(temp1,".%s",temp_p); + } + if(img_fol->set_out_format==1){ + sprintf(outfilename,"%s/%s.%s",img_fol->imgdirpath,temp_ofname,img_fol->out_format); + strncpy(parameters->outfile, outfilename, sizeof(outfilename)); + } + return 0; +} + +/* -------------------------------------------------------------------------- */ +int parse_cmdline_decoder(int argc, char **argv, opj_dparameters_t *parameters,img_fol_t *img_fol, char *indexfilename) { + /* parse the command line */ + int totlen; + option_t long_option[]={ + {"ImgDir",REQ_ARG, NULL ,'y'}, + {"OutFor",REQ_ARG, NULL ,'O'}, + }; + + const char optlist[] = "i:o:r:l:x:" + +/* UniPG>> */ +#ifdef USE_JPWL + "W:" +#endif /* USE_JPWL */ +/* <set_out_format = 0; + while (1) { + int c = getopt_long(argc, argv,optlist,long_option,totlen); + if (c == -1) + break; + switch (c) { + case 'i': /* input file */ + { + char *infile = optarg; + parameters->decod_format = get_file_format(infile); + switch(parameters->decod_format) { + case J2K_CFMT: + case JP2_CFMT: + case JPT_CFMT: + break; + default: + fprintf(stderr, + "!! Unrecognized format for infile : %s [accept only *.j2k, *.jp2, *.jpc or *.jpt] !!\n\n", + infile); + return 1; + } + strncpy(parameters->infile, infile, sizeof(parameters->infile)-1); + } + break; + + /* ----------------------------------------------------- */ + + case 'o': /* output file */ + { + char *outfile = optarg; + parameters->cod_format = get_file_format(outfile); + switch(parameters->cod_format) { + case PGX_DFMT: + case PXM_DFMT: + case BMP_DFMT: + case TIF_DFMT: + case RAW_DFMT: + case TGA_DFMT: + case PNG_DFMT: + break; + default: + fprintf(stderr, "Unknown output format image %s [only *.pnm, *.pgm, *.ppm, *.pgx, *.bmp, *.tif, *.raw or *.tga]!! \n", outfile); + return 1; + } + strncpy(parameters->outfile, outfile, sizeof(parameters->outfile)-1); + } + break; + + /* ----------------------------------------------------- */ + + case 'O': /* output format */ + { + char outformat[50]; + char *of = optarg; + sprintf(outformat,".%s",of); + img_fol->set_out_format = 1; + parameters->cod_format = get_file_format(outformat); + switch(parameters->cod_format) { + case PGX_DFMT: + img_fol->out_format = "pgx"; + break; + case PXM_DFMT: + img_fol->out_format = "ppm"; + break; + case BMP_DFMT: + img_fol->out_format = "bmp"; + break; + case TIF_DFMT: + img_fol->out_format = "tif"; + break; + case RAW_DFMT: + img_fol->out_format = "raw"; + break; + case TGA_DFMT: + img_fol->out_format = "raw"; + break; + case PNG_DFMT: + img_fol->out_format = "png"; + break; + default: + fprintf(stderr, "Unknown output format image %s [only *.pnm, *.pgm, *.ppm, *.pgx, *.bmp, *.tif, *.raw or *.tga]!! \n", outformat); + return 1; + break; + } + } + break; + + /* ----------------------------------------------------- */ + + + case 'r': /* reduce option */ + { + sscanf(optarg, "%d", ¶meters->cp_reduce); + } + break; + + /* ----------------------------------------------------- */ + + + case 'l': /* layering option */ + { + sscanf(optarg, "%d", ¶meters->cp_layer); + } + break; + + /* ----------------------------------------------------- */ + + case 'h': /* display an help description */ + decode_help_display(); + return 1; + + /* ------------------------------------------------------ */ + + case 'y': /* Image Directory path */ + { + img_fol->imgdirpath = (char*)malloc(strlen(optarg) + 1); + strcpy(img_fol->imgdirpath,optarg); + img_fol->set_imgdir=1; + } + break; + /* ----------------------------------------------------- */ + case 'x': /* Creation of index file */ + { + char *index = optarg; + strncpy(indexfilename, index, OPJ_PATH_LEN); + } + break; + /* ----------------------------------------------------- */ + /* UniPG>> */ +#ifdef USE_JPWL + + case 'W': /* activate JPWL correction */ + { + char *token = NULL; + + token = strtok(optarg, ","); + while(token != NULL) { + + /* search expected number of components */ + if (*token == 'c') { + + static int compno; + + compno = JPWL_EXPECTED_COMPONENTS; /* predefined no. of components */ + + if(sscanf(token, "c=%d", &compno) == 1) { + /* Specified */ + if ((compno < 1) || (compno > 256)) { + fprintf(stderr, "ERROR -> invalid number of components c = %d\n", compno); + return 1; + } + parameters->jpwl_exp_comps = compno; + + } else if (!strcmp(token, "c")) { + /* default */ + parameters->jpwl_exp_comps = compno; /* auto for default size */ + + } else { + fprintf(stderr, "ERROR -> invalid components specified = %s\n", token); + return 1; + }; + } + + /* search maximum number of tiles */ + if (*token == 't') { + + static int tileno; + + tileno = JPWL_MAXIMUM_TILES; /* maximum no. of tiles */ + + if(sscanf(token, "t=%d", &tileno) == 1) { + /* Specified */ + if ((tileno < 1) || (tileno > JPWL_MAXIMUM_TILES)) { + fprintf(stderr, "ERROR -> invalid number of tiles t = %d\n", tileno); + return 1; + } + parameters->jpwl_max_tiles = tileno; + + } else if (!strcmp(token, "t")) { + /* default */ + parameters->jpwl_max_tiles = tileno; /* auto for default size */ + + } else { + fprintf(stderr, "ERROR -> invalid tiles specified = %s\n", token); + return 1; + }; + } + + /* next token or bust */ + token = strtok(NULL, ","); + }; + parameters->jpwl_correct = true; + fprintf(stdout, "JPWL correction capability activated\n"); + fprintf(stdout, "- expecting %d components\n", parameters->jpwl_exp_comps); + } + break; +#endif /* USE_JPWL */ +/* < this option is not valid \"-%c %s\"\n",c, optarg); + break; + } + } + + /* check for possible errors */ + if(img_fol->set_imgdir==1){ + if(!(parameters->infile[0]==0)){ + fprintf(stderr, "Error: options -ImgDir and -i cannot be used together !!\n"); + return 1; + } + if(img_fol->set_out_format == 0){ + fprintf(stderr, "Error: When -ImgDir is used, -OutFor must be used !!\n"); + fprintf(stderr, "Only one format allowed! Valid format PGM, PPM, PNM, PGX, BMP, TIF, RAW and TGA!!\n"); + return 1; + } + if(!((parameters->outfile[0] == 0))){ + fprintf(stderr, "Error: options -ImgDir and -o cannot be used together !!\n"); + return 1; + } + }else{ + if((parameters->infile[0] == 0) || (parameters->outfile[0] == 0)) { + fprintf(stderr, "Example: %s -i image.j2k -o image.pgm\n",argv[0]); + fprintf(stderr, " Try: %s -h\n",argv[0]); + return 1; + } + } + + return 0; +} + +/* -------------------------------------------------------------------------- */ + +/** +sample error callback expecting a FILE* client object +*/ +void error_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[ERROR] %s", msg); +} +/** +sample warning callback expecting a FILE* client object +*/ +void warning_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[WARNING] %s", msg); +} +/** +sample debug callback expecting no client object +*/ +void info_callback(const char *msg, void *client_data) { + (void)client_data; + fprintf(stdout, "[INFO] %s", msg); +} + +/* -------------------------------------------------------------------------- */ + +int main(int argc, char **argv) { + opj_dparameters_t parameters; /* decompression parameters */ + img_fol_t img_fol; + opj_event_mgr_t event_mgr; /* event manager */ + opj_image_t *image = NULL; + FILE *fsrc = NULL; + unsigned char *src = NULL; + int file_length; + int num_images; + int i,imageno; + dircnt_t *dirptr; + opj_dinfo_t* dinfo = NULL; /* handle to a decompressor */ + opj_cio_t *cio = NULL; + opj_codestream_info_t cstr_info; /* Codestream information structure */ + char indexfilename[OPJ_PATH_LEN]; /* index file name */ + + /* configure the event callbacks (not required) */ + memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); + event_mgr.error_handler = error_callback; + event_mgr.warning_handler = warning_callback; + event_mgr.info_handler = info_callback; + + /* set decoding parameters to default values */ + opj_set_default_decoder_parameters(¶meters); + + /* Initialize indexfilename and img_fol */ + *indexfilename = 0; + memset(&img_fol,0,sizeof(img_fol_t)); + + /* parse input and get user encoding parameters */ + if(parse_cmdline_decoder(argc, argv, ¶meters,&img_fol, indexfilename) == 1) { + return 1; + } + + /* Initialize reading of directory */ + if(img_fol.set_imgdir==1){ + num_images=get_num_images(img_fol.imgdirpath); + + dirptr=(dircnt_t*)malloc(sizeof(dircnt_t)); + if(dirptr){ + dirptr->filename_buf = (char*)malloc(num_images*OPJ_PATH_LEN*sizeof(char)); // Stores at max 10 image file names + dirptr->filename = (char**) malloc(num_images*sizeof(char*)); + + if(!dirptr->filename_buf){ + return 1; + } + for(i=0;ifilename[i] = dirptr->filename_buf + i*OPJ_PATH_LEN; + } + } + if(load_images(dirptr,img_fol.imgdirpath)==1){ + return 1; + } + if (num_images==0){ + fprintf(stdout,"Folder is empty\n"); + return 1; + } + }else{ + num_images=1; + } + + /*Encoding image one by one*/ + for(imageno = 0; imageno < num_images ; imageno++) { + image = NULL; + fprintf(stderr,"\n"); + + if(img_fol.set_imgdir==1){ + if (get_next_file(imageno, dirptr,&img_fol, ¶meters)) { + fprintf(stderr,"skipping file...\n"); + continue; + } + } + + /* read the input file and put it in memory */ + /* ---------------------------------------- */ + fsrc = fopen(parameters.infile, "rb"); + if (!fsrc) { + fprintf(stderr, "ERROR -> failed to open %s for reading\n", parameters.infile); + return 1; + } + fseek(fsrc, 0, SEEK_END); + file_length = ftell(fsrc); + fseek(fsrc, 0, SEEK_SET); + src = (unsigned char *) malloc(file_length); + fread(src, 1, file_length, fsrc); + fclose(fsrc); + + /* decode the code-stream */ + /* ---------------------- */ + + switch(parameters.decod_format) { + case J2K_CFMT: + { + /* JPEG-2000 codestream */ + + /* get a decoder handle */ + dinfo = opj_create_decompress(CODEC_J2K); + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr); + + /* setup the decoder decoding parameters using user parameters */ + opj_setup_decoder(dinfo, ¶meters); + + /* open a byte stream */ + cio = opj_cio_open((opj_common_ptr)dinfo, src, file_length); + + /* decode the stream and fill the image structure */ + if (*indexfilename) // If need to extract codestream information + image = opj_decode_with_info(dinfo, cio, &cstr_info); + else + image = opj_decode(dinfo, cio); + if(!image) { + fprintf(stderr, "ERROR -> j2k_to_image: failed to decode image!\n"); + opj_destroy_decompress(dinfo); + opj_cio_close(cio); + return 1; + } + + /* close the byte stream */ + opj_cio_close(cio); + + /* Write the index to disk */ + if (*indexfilename) { + char bSuccess; + bSuccess = write_index_file(&cstr_info, indexfilename); + if (bSuccess) { + fprintf(stderr, "Failed to output index file\n"); + } + } + } + break; + + case JP2_CFMT: + { + /* JPEG 2000 compressed image data */ + + /* get a decoder handle */ + dinfo = opj_create_decompress(CODEC_JP2); + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr); + + /* setup the decoder decoding parameters using the current image and user parameters */ + opj_setup_decoder(dinfo, ¶meters); + + /* open a byte stream */ + cio = opj_cio_open((opj_common_ptr)dinfo, src, file_length); + + /* decode the stream and fill the image structure */ + if (*indexfilename) // If need to extract codestream information + image = opj_decode_with_info(dinfo, cio, &cstr_info); + else + image = opj_decode(dinfo, cio); + if(!image) { + fprintf(stderr, "ERROR -> j2k_to_image: failed to decode image!\n"); + opj_destroy_decompress(dinfo); + opj_cio_close(cio); + return 1; + } + + /* close the byte stream */ + opj_cio_close(cio); + + /* Write the index to disk */ + if (*indexfilename) { + char bSuccess; + bSuccess = write_index_file(&cstr_info, indexfilename); + if (bSuccess) { + fprintf(stderr, "Failed to output index file\n"); + } + } + } + break; + + case JPT_CFMT: + { + /* JPEG 2000, JPIP */ + + /* get a decoder handle */ + dinfo = opj_create_decompress(CODEC_JPT); + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr); + + /* setup the decoder decoding parameters using user parameters */ + opj_setup_decoder(dinfo, ¶meters); + + /* open a byte stream */ + cio = opj_cio_open((opj_common_ptr)dinfo, src, file_length); + + /* decode the stream and fill the image structure */ + if (*indexfilename) // If need to extract codestream information + image = opj_decode_with_info(dinfo, cio, &cstr_info); + else + image = opj_decode(dinfo, cio); + if(!image) { + fprintf(stderr, "ERROR -> j2k_to_image: failed to decode image!\n"); + opj_destroy_decompress(dinfo); + opj_cio_close(cio); + return 1; + } + + /* close the byte stream */ + opj_cio_close(cio); + + /* Write the index to disk */ + if (*indexfilename) { + char bSuccess; + bSuccess = write_index_file(&cstr_info, indexfilename); + if (bSuccess) { + fprintf(stderr, "Failed to output index file\n"); + } + } + } + break; + + default: + fprintf(stderr, "skipping file..\n"); + continue; + } + + /* free the memory containing the code-stream */ + free(src); + src = NULL; + + if(image->color_space == CLRSPC_SYCC) + { + color_sycc_to_rgb(image); + } + + if(image->icc_profile_buf) + { +#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + color_apply_icc_profile(image); +#endif + + free(image->icc_profile_buf); + image->icc_profile_buf = NULL; image->icc_profile_len = 0; + } + + /* create output image */ + /* ------------------- */ + switch (parameters.cod_format) { + case PXM_DFMT: /* PNM PGM PPM */ + if (imagetopnm(image, parameters.outfile)) { + fprintf(stdout,"Outfile %s not generated\n",parameters.outfile); + } + else { + fprintf(stdout,"Generated Outfile %s\n",parameters.outfile); + } + break; + + case PGX_DFMT: /* PGX */ + if(imagetopgx(image, parameters.outfile)){ + fprintf(stdout,"Outfile %s not generated\n",parameters.outfile); + } + else { + fprintf(stdout,"Generated Outfile %s\n",parameters.outfile); + } + break; + + case BMP_DFMT: /* BMP */ + if(imagetobmp(image, parameters.outfile)){ + fprintf(stdout,"Outfile %s not generated\n",parameters.outfile); + } + else { + fprintf(stdout,"Generated Outfile %s\n",parameters.outfile); + } + break; +#ifdef HAVE_LIBTIFF + case TIF_DFMT: /* TIFF */ + if(imagetotif(image, parameters.outfile)){ + fprintf(stdout,"Outfile %s not generated\n",parameters.outfile); + } + else { + fprintf(stdout,"Generated Outfile %s\n",parameters.outfile); + } + break; +#endif /* HAVE_LIBTIFF */ + case RAW_DFMT: /* RAW */ + if(imagetoraw(image, parameters.outfile)){ + fprintf(stdout,"Error generating raw file. Outfile %s not generated\n",parameters.outfile); + } + else { + fprintf(stdout,"Successfully generated Outfile %s\n",parameters.outfile); + } + break; + + case TGA_DFMT: /* TGA */ + if(imagetotga(image, parameters.outfile)){ + fprintf(stdout,"Error generating tga file. Outfile %s not generated\n",parameters.outfile); + } + else { + fprintf(stdout,"Successfully generated Outfile %s\n",parameters.outfile); + } + break; +#ifdef HAVE_LIBPNG + case PNG_DFMT: /* PNG */ + if(imagetopng(image, parameters.outfile)){ + fprintf(stdout,"Error generating png file. Outfile %s not generated\n",parameters.outfile); + } + else { + fprintf(stdout,"Successfully generated Outfile %s\n",parameters.outfile); + } + break; +#endif /* HAVE_LIBPNG */ +/* Can happen if output file is TIFF or PNG + * and HAVE_LIBTIF or HAVE_LIBPNG is undefined +*/ + default: + fprintf(stderr,"Outfile %s not generated\n",parameters.outfile); + } + + /* free remaining structures */ + if(dinfo) { + opj_destroy_decompress(dinfo); + } + /* free codestream information structure */ + if (*indexfilename) + opj_destroy_cstr_info(&cstr_info); + /* free image data structure */ + opj_image_destroy(image); + + } + return 0; +} +//end main + + + + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/codec/j2k_to_image.dsp b/gdcm/Utilities/gdcmopenjpeg-v1/codec/j2k_to_image.dsp new file mode 100644 index 0000000..6d3ce66 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/codec/j2k_to_image.dsp @@ -0,0 +1,117 @@ +# Microsoft Developer Studio Project File - Name="j2k_to_image" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=j2k_to_image - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "j2k_to_image.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "j2k_to_image.mak" CFG="j2k_to_image - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "j2k_to_image - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "j2k_to_image - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "j2k_to_image - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "../libopenjpeg" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "OPJ_STATIC" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x40c /d "NDEBUG" +# ADD RSC /l 0x40c /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ../libs/libtiff/libtiff.lib /nologo /subsystem:console /machine:I386 /nodefaultlib:"libc" +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "j2k_to_image - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../libopenjpeg" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "OPJ_STATIC" /YX /FD /GZ /c +# ADD BASE RSC /l 0x40c /d "_DEBUG" +# ADD RSC /l 0x40c /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ../libs/libtiff/libtiff.lib /nologo /subsystem:console /debug /machine:I386 /nodefaultlib:"libc" /nodefaultlib:"libcmt" /pdbtype:sept +# SUBTRACT LINK32 /pdb:none + +!ENDIF + +# Begin Target + +# Name "j2k_to_image - Win32 Release" +# Name "j2k_to_image - Win32 Debug" +# Begin Source File + +SOURCE=.\convert.c +# End Source File +# Begin Source File + +SOURCE=.\convert.h +# End Source File +# Begin Source File + +SOURCE=.\compat\getopt.c +# End Source File +# Begin Source File + +SOURCE=.\compat\getopt.h +# End Source File +# Begin Source File + +SOURCE=.\index.c +# End Source File +# Begin Source File + +SOURCE=.\index.h +# End Source File +# Begin Source File + +SOURCE=.\j2k_to_image.c +# End Source File +# End Target +# End Project diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/codec/j2k_to_image.dsw b/gdcm/Utilities/gdcmopenjpeg-v1/codec/j2k_to_image.dsw new file mode 100644 index 0000000..d951063 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/codec/j2k_to_image.dsw @@ -0,0 +1,44 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "LibOpenJPEG"=..\LibOpenJPEG.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "j2k_to_image"=.\j2k_to_image.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name LibOpenJPEG + End Project Dependency +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/codec/j2k_to_image.sln b/gdcm/Utilities/gdcmopenjpeg-v1/codec/j2k_to_image.sln new file mode 100644 index 0000000000000000000000000000000000000000..22103f55caa4e479ba87b749e95a7ac11e4f12a2 GIT binary patch literal 1506 zcmbW1OK#gR5Qek00Np`QHYpGaq{P_Nq6_Nb6h)dEHPCJf1hPdNOcl}4BO50t>mom=E%IZq0+?vWvoLf^> z+$9hrin2NM9gI!m^sgKj;|tT673x+jt22Acg3u4+fFTx8jtGe`Vi6$-V~#_gfS0TaY7(ZrxuumAa94$yzj>`*t75Wzcy%_7Nl8MKthXNFUI`Xo4ppjVI%H z+yISQoH=L%5}vhYBw*}R + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/codec/windirent.h b/gdcm/Utilities/gdcmopenjpeg-v1/codec/windirent.h new file mode 100644 index 0000000..a788f0c --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/codec/windirent.h @@ -0,0 +1,677 @@ + +/* + * uce-dirent.h - operating system independent dirent implementation + * + * Copyright (C) 1998-2002 Toni Ronkko + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * ``Software''), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL TONI RONKKO BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * + * May 28 1998, Toni Ronkko + * + * $Id: uce-dirent.h,v 1.7 2002/05/13 10:48:35 tr Exp $ + * + * $Log: uce-dirent.h,v $ + * Revision 1.7 2002/05/13 10:48:35 tr + * embedded some source code directly to the header so that no source + * modules need to be included in the MS Visual C project using the + * interface, removed all the dependencies to other headers of the `uce' + * library so that the header can be made public + * + * Revision 1.6 2002/04/12 16:22:04 tr + * Unified Compiling Environment (UCE) replaced `std' library + * + * Revision 1.5 2001/07/20 16:33:40 tr + * moved to `std' library and re-named defines accordingly + * + * Revision 1.4 2001/07/10 16:47:18 tronkko + * revised comments + * + * Revision 1.3 2001/01/11 13:16:43 tr + * using ``uce-machine.h'' for finding out defines such as `FREEBSD' + * + * Revision 1.2 2000/10/08 16:00:41 tr + * copy of FreeBSD man page + * + * Revision 1.1 2000/07/10 05:53:16 tr + * Initial revision + * + * Revision 1.2 1998/07/19 18:29:14 tr + * Added error reporting capabilities and some asserts. + * + * Revision 1.1 1998/07/04 16:27:51 tr + * Initial revision + * + * + * MSVC 1.0 scans automatic dependencies incorrectly when your project + * contains this very header. The problem is that MSVC cannot handle + * include directives inside #if..#endif block those are never entered. + * Since this header ought to compile in many different operating systems, + * there had to be several conditional blocks that are compiled only in + * operating systems for what they were designed for. MSVC 1.0 cannot + * handle inclusion of sys/dir.h in a part that is compiled only in Apollo + * operating system. To fix the problem you need to insert DIR.H into + * SYSINCL.DAT located in MSVC\BIN directory and restart visual C++. + * Consult manuals for more informaton about the problem. + * + * Since many UNIX systems have dirent.h we assume to have one also. + * However, if your UNIX system does not have dirent.h you can download one + * for example at: http://ftp.uni-mannheim.de/ftp/GNU/dirent/dirent.tar.gz. + * You can also see if you have one of dirent.h, direct.h, dir.h, ndir.h, + * sys/dir.h and sys/ndir.h somewhere. Try defining HAVE_DIRENT_H, + * HAVE_DIRECT_H, HAVE_DIR_H, HAVE_NDIR_H, HAVE_SYS_DIR_H and + * HAVE_SYS_NDIR_H according to the files found. + */ +#ifndef DIRENT_H +#define DIRENT_H +#define DIRENT_H_INCLUDED + +/* find out platform */ +#if defined(MSDOS) /* MS-DOS */ +#elif defined(__MSDOS__) /* Turbo C/Borland */ +# define MSDOS +#elif defined(__DOS__) /* Watcom */ +# define MSDOS +#endif + +#if defined(WIN32) /* MS-Windows */ +#elif defined(__NT__) /* Watcom */ +# define WIN32 +#elif defined(_WIN32) /* Microsoft */ +# define WIN32 +#elif defined(__WIN32__) /* Borland */ +# define WIN32 +#endif + +/* + * See what kind of dirent interface we have unless autoconf has already + * determinated that. + */ +#if !defined(HAVE_DIRENT_H) && !defined(HAVE_DIRECT_H) && !defined(HAVE_SYS_DIR_H) && !defined(HAVE_NDIR_H) && !defined(HAVE_SYS_NDIR_H) && !defined(HAVE_DIR_H) +# if defined(_MSC_VER) /* Microsoft C/C++ */ + /* no dirent.h */ +# elif defined(__BORLANDC__) /* Borland C/C++ */ +# define HAVE_DIRENT_H +# define VOID_CLOSEDIR +# elif defined(__TURBOC__) /* Borland Turbo C */ + /* no dirent.h */ +# elif defined(__WATCOMC__) /* Watcom C/C++ */ +# define HAVE_DIRECT_H +# elif defined(__apollo) /* Apollo */ +# define HAVE_SYS_DIR_H +# elif defined(__hpux) /* HP-UX */ +# define HAVE_DIRENT_H +# elif (defined(__alpha) || defined(__alpha__)) && !defined(__linux__) /* Alpha OSF1 */ +# error "not implemented" +# elif defined(__sgi) /* Silicon Graphics */ +# define HAVE_DIRENT_H +# elif defined(sun) || defined(_sun) /* Sun Solaris */ +# define HAVE_DIRENT_H +# elif defined(__FreeBSD__) /* FreeBSD */ +# define HAVE_DIRENT_H +# elif defined(__linux__) /* Linux */ +# define HAVE_DIRENT_H +# elif defined(__GNUC__) /* GNU C/C++ */ +# define HAVE_DIRENT_H +# else +# error "not implemented" +# endif +#endif + +/* include proper interface headers */ +#if defined(HAVE_DIRENT_H) +# include +# ifdef FREEBSD +# define NAMLEN(dp) ((int)((dp)->d_namlen)) +# else +# define NAMLEN(dp) ((int)(strlen((dp)->d_name))) +# endif + +#elif defined(HAVE_NDIR_H) +# include +# define NAMLEN(dp) ((int)((dp)->d_namlen)) + +#elif defined(HAVE_SYS_NDIR_H) +# include +# define NAMLEN(dp) ((int)((dp)->d_namlen)) + +#elif defined(HAVE_DIRECT_H) +# include +# define NAMLEN(dp) ((int)((dp)->d_namlen)) + +#elif defined(HAVE_DIR_H) +# include +# define NAMLEN(dp) ((int)((dp)->d_namlen)) + +#elif defined(HAVE_SYS_DIR_H) +# include +# include +# ifndef dirent +# define dirent direct +# endif +# define NAMLEN(dp) ((int)((dp)->d_namlen)) + +#elif defined(MSDOS) || defined(WIN32) + + /* figure out type of underlaying directory interface to be used */ +# if defined(WIN32) +# define DIRENT_WIN32_INTERFACE +# elif defined(MSDOS) +# define DIRENT_MSDOS_INTERFACE +# else +# error "missing native dirent interface" +# endif + + /*** WIN32 specifics ***/ +# if defined(DIRENT_WIN32_INTERFACE) +# include +# if !defined(DIRENT_MAXNAMLEN) +# define DIRENT_MAXNAMLEN (MAX_PATH) +# endif + + + /*** MS-DOS specifics ***/ +# elif defined(DIRENT_MSDOS_INTERFACE) +# include + + /* Borland defines file length macros in dir.h */ +# if defined(__BORLANDC__) +# include +# if !defined(DIRENT_MAXNAMLEN) +# define DIRENT_MAXNAMLEN ((MAXFILE)+(MAXEXT)) +# endif +# if !defined(_find_t) +# define _find_t find_t +# endif + + /* Turbo C defines ffblk structure in dir.h */ +# elif defined(__TURBOC__) +# include +# if !defined(DIRENT_MAXNAMLEN) +# define DIRENT_MAXNAMLEN ((MAXFILE)+(MAXEXT)) +# endif +# define DIRENT_USE_FFBLK + + /* MSVC */ +# elif defined(_MSC_VER) +# if !defined(DIRENT_MAXNAMLEN) +# define DIRENT_MAXNAMLEN (12) +# endif + + /* Watcom */ +# elif defined(__WATCOMC__) +# if !defined(DIRENT_MAXNAMLEN) +# if defined(__OS2__) || defined(__NT__) +# define DIRENT_MAXNAMLEN (255) +# else +# define DIRENT_MAXNAMLEN (12) +# endif +# endif + +# endif +# endif + + /*** generic MS-DOS and MS-Windows stuff ***/ +# if !defined(NAME_MAX) && defined(DIRENT_MAXNAMLEN) +# define NAME_MAX DIRENT_MAXNAMLEN +# endif +# if NAME_MAX < DIRENT_MAXNAMLEN +# error "assertion failed: NAME_MAX >= DIRENT_MAXNAMLEN" +# endif + + + /* + * Substitute for real dirent structure. Note that `d_name' field is a + * true character array although we have it copied in the implementation + * dependent data. We could save some memory if we had declared `d_name' + * as a pointer refering the name within implementation dependent data. + * We have not done that since some code may rely on sizeof(d_name) to be + * something other than four. Besides, directory entries are typically so + * small that it takes virtually no time to copy them from place to place. + */ + typedef struct dirent { + char d_name[NAME_MAX + 1]; + + /*** Operating system specific part ***/ +# if defined(DIRENT_WIN32_INTERFACE) /*WIN32*/ + WIN32_FIND_DATA data; +# elif defined(DIRENT_MSDOS_INTERFACE) /*MSDOS*/ +# if defined(DIRENT_USE_FFBLK) + struct ffblk data; +# else + struct _find_t data; +# endif +# endif + } dirent; + + /* DIR substitute structure containing directory name. The name is + * essential for the operation of ``rewinndir'' function. */ + typedef struct DIR { + char *dirname; /* directory being scanned */ + dirent current; /* current entry */ + int dirent_filled; /* is current un-processed? */ + + /*** Operating system specific part ***/ +# if defined(DIRENT_WIN32_INTERFACE) + HANDLE search_handle; +# elif defined(DIRENT_MSDOS_INTERFACE) +# endif + } DIR; + +# ifdef __cplusplus +extern "C" { +# endif + +/* supply prototypes for dirent functions */ +static DIR *opendir (const char *dirname); +static struct dirent *readdir (DIR *dirp); +static int closedir (DIR *dirp); +static void rewinddir (DIR *dirp); + +/* + * Implement dirent interface as static functions so that the user does not + * need to change his project in any way to use dirent function. With this + * it is sufficient to include this very header from source modules using + * dirent functions and the functions will be pulled in automatically. + */ +#include +#include +#include +#include +#include + +/* use ffblk instead of _find_t if requested */ +#if defined(DIRENT_USE_FFBLK) +# define _A_ARCH (FA_ARCH) +# define _A_HIDDEN (FA_HIDDEN) +# define _A_NORMAL (0) +# define _A_RDONLY (FA_RDONLY) +# define _A_SUBDIR (FA_DIREC) +# define _A_SYSTEM (FA_SYSTEM) +# define _A_VOLID (FA_LABEL) +# define _dos_findnext(dest) findnext(dest) +# define _dos_findfirst(name,flags,dest) findfirst(name,dest,flags) +#endif + +static int _initdir (DIR *p); +static const char *_getdirname (const struct dirent *dp); +static void _setdirname (struct DIR *dirp); + +/* + * + * open directory stream for reading + * DIR *opendir (const char *dirname); + * + * Open named directory stream for read and return pointer to the + * internal working area that is used for retrieving individual directory + * entries. The internal working area has no fields of your interest. + * + * Returns a pointer to the internal working area or NULL in case the + * directory stream could not be opened. Global `errno' variable will set + * in case of error as follows: + * + * + * [EACESS |Permission denied. + * [EMFILE |Too many open files used by the process. + * [ENFILE |Too many open files in system. + * [ENOENT |Directory does not exist. + * [ENOMEM |Insufficient memory. + * [ENOTDIR |dirname does not refer to directory. This value is not + * reliable on MS-DOS and MS-Windows platforms. Many + * implementations return ENOENT even when the name refers to a + * file.] + *
+ *
+ */ +static DIR *opendir(const char *dirname) +{ + DIR *dirp; + assert (dirname != NULL); + + dirp = (DIR*)malloc (sizeof (struct DIR)); + if (dirp != NULL) { + char *p; + + /* allocate room for directory name */ + dirp->dirname = (char*) malloc (strlen (dirname) + 1 + strlen ("\\*.*")); + if (dirp->dirname == NULL) { + /* failed to duplicate directory name. errno set by malloc() */ + free (dirp); + return NULL; + } + /* Copy directory name while appending directory separator and "*.*". + * Directory separator is not appended if the name already ends with + * drive or directory separator. Directory separator is assumed to be + * '/' or '\' and drive separator is assumed to be ':'. */ + strcpy (dirp->dirname, dirname); + p = strchr (dirp->dirname, '\0'); + if (dirp->dirname < p && + *(p - 1) != '\\' && *(p - 1) != '/' && *(p - 1) != ':') + { + strcpy (p++, "\\"); + } +# ifdef DIRENT_WIN32_INTERFACE + strcpy (p, "*"); /*scan files with and without extension in win32*/ +# else + strcpy (p, "*.*"); /*scan files with and without extension in DOS*/ +# endif + + /* open stream */ + if (_initdir (dirp) == 0) { + /* initialization failed */ + free (dirp->dirname); + free (dirp); + return NULL; + } + } + return dirp; +} + + +/* + * + * read a directory entry + * struct dirent *readdir (DIR *dirp); + * + * Read individual directory entry and return pointer to a structure + * containing the name of the entry. Individual directory entries returned + * include normal files, sub-directories, pseudo-directories "." and ".." + * and also volume labels, hidden files and system files in MS-DOS and + * MS-Windows. You might want to use stat(2) function to determinate which + * one are you dealing with. Many dirent implementations already contain + * equivalent information in dirent structure but you cannot depend on + * this. + * + * The dirent structure contains several system dependent fields that + * generally have no interest to you. The only interesting one is char + * d_name[] that is also portable across different systems. The d_name + * field contains the name of the directory entry without leading path. + * While d_name is portable across different systems the actual storage + * capacity of d_name varies from system to system and there is no portable + * way to find out it at compile time as different systems define the + * capacity of d_name with different macros and some systems do not define + * capacity at all (besides actual declaration of the field). If you really + * need to find out storage capacity of d_name then you might want to try + * NAME_MAX macro. The NAME_MAX is defined in POSIX standard althought + * there are many MS-DOS and MS-Windows implementations those do not define + * it. There are also systems that declare d_name as "char d_name[1]" and + * then allocate suitable amount of memory at run-time. Thanks to Alain + * Decamps (Alain.Decamps@advalvas.be) for pointing it out to me. + * + * This all leads to the fact that it is difficult to allocate space + * for the directory names when the very same program is being compiled on + * number of operating systems. Therefore I suggest that you always + * allocate space for directory names dynamically. + * + * + * Returns a pointer to a structure containing name of the directory entry + * in `d_name' field or NULL if there was an error. In case of an error the + * global `errno' variable will set as follows: + * + * + * [EBADF |dir parameter refers to an invalid directory stream. This value + * is not set reliably on all implementations.] + *
+ *
+ */ +static struct dirent * +readdir (DIR *dirp) +{ + assert(dirp != NULL); + if (dirp == NULL) { + errno = EBADF; + return NULL; + } + +#if defined(DIRENT_WIN32_INTERFACE) + if (dirp->search_handle == INVALID_HANDLE_VALUE) { + /* directory stream was opened/rewound incorrectly or it ended normally */ + errno = EBADF; + return NULL; + } +#endif + + if (dirp->dirent_filled != 0) { + /* + * Directory entry has already been retrieved and there is no need to + * retrieve a new one. Directory entry will be retrieved in advance + * when the user calls readdir function for the first time. This is so + * because real dirent has separate functions for opening and reading + * the stream whereas Win32 and DOS dirents open the stream + * automatically when we retrieve the first file. Therefore, we have to + * save the first file when opening the stream and later we have to + * return the saved entry when the user tries to read the first entry. + */ + dirp->dirent_filled = 0; + } else { + /* fill in entry and return that */ +#if defined(DIRENT_WIN32_INTERFACE) + if (FindNextFile (dirp->search_handle, &dirp->current.data) == FALSE) { + /* Last file has been processed or an error occured */ + FindClose (dirp->search_handle); + dirp->search_handle = INVALID_HANDLE_VALUE; + errno = ENOENT; + return NULL; + } + +# elif defined(DIRENT_MSDOS_INTERFACE) + if (_dos_findnext (&dirp->current.data) != 0) { + /* _dos_findnext and findnext will set errno to ENOENT when no + * more entries could be retrieved. */ + return NULL; + } +# endif + + _setdirname (dirp); + assert (dirp->dirent_filled == 0); + } + return &dirp->current; +} + + +/* + * + * close directory stream. + * int closedir (DIR *dirp); + * + * Close directory stream opened by the `opendir' function. Close of + * directory stream invalidates the DIR structure as well as previously read + * dirent entry. + * + * The function typically returns 0 on success and -1 on failure but + * the function may be declared to return void on same systems. At least + * Borland C/C++ and some UNIX implementations use void as a return type. + * The dirent wrapper tries to define VOID_CLOSEDIR whenever closedir is + * known to return nothing. The very same definition is made by the GNU + * autoconf if you happen to use it. + * + * The global `errno' variable will set to EBADF in case of error. + * + */ +static int +closedir (DIR *dirp) +{ + int retcode = 0; + + /* make sure that dirp points to legal structure */ + assert (dirp != NULL); + if (dirp == NULL) { + errno = EBADF; + return -1; + } + + /* free directory name and search handles */ + if (dirp->dirname != NULL) free (dirp->dirname); + +#if defined(DIRENT_WIN32_INTERFACE) + if (dirp->search_handle != INVALID_HANDLE_VALUE) { + if (FindClose (dirp->search_handle) == FALSE) { + /* Unknown error */ + retcode = -1; + errno = EBADF; + } + } +#endif + + /* clear dirp structure to make sure that it cannot be used anymore*/ + memset (dirp, 0, sizeof (*dirp)); +# if defined(DIRENT_WIN32_INTERFACE) + dirp->search_handle = INVALID_HANDLE_VALUE; +# endif + + free (dirp); + return retcode; +} + + +/* + * + * rewind directory stream to the beginning + * void rewinddir (DIR *dirp); + * + * Rewind directory stream to the beginning so that the next call of + * readdir() returns the very first directory entry again. However, note + * that next call of readdir() may not return the same directory entry as it + * did in first time. The directory stream may have been affected by newly + * created files. + * + * Almost every dirent implementation ensure that rewinddir will update + * the directory stream to reflect any changes made to the directory entries + * since the previous ``opendir'' or ``rewinddir'' call. Keep an eye on + * this if your program depends on the feature. I know at least one dirent + * implementation where you are required to close and re-open the stream to + * see the changes. + * + * Returns nothing. If something went wrong while rewinding, you will + * notice it later when you try to retrieve the first directory entry. + */ +static void +rewinddir (DIR *dirp) +{ + /* make sure that dirp is legal */ + assert (dirp != NULL); + if (dirp == NULL) { + errno = EBADF; + return; + } + assert (dirp->dirname != NULL); + + /* close previous stream */ +#if defined(DIRENT_WIN32_INTERFACE) + if (dirp->search_handle != INVALID_HANDLE_VALUE) { + if (FindClose (dirp->search_handle) == FALSE) { + /* Unknown error */ + errno = EBADF; + } + } +#endif + + /* re-open previous stream */ + if (_initdir (dirp) == 0) { + /* initialization failed but we cannot deal with error. User will notice + * error later when she tries to retrieve first directory enty. */ + /*EMPTY*/; + } +} + + +/* + * Open native directory stream object and retrieve first file. + * Be sure to close previous stream before opening new one. + */ +static int +_initdir (DIR *dirp) +{ + assert (dirp != NULL); + assert (dirp->dirname != NULL); + dirp->dirent_filled = 0; + +# if defined(DIRENT_WIN32_INTERFACE) + /* Open stream and retrieve first file */ + dirp->search_handle = FindFirstFile (dirp->dirname, &dirp->current.data); + if (dirp->search_handle == INVALID_HANDLE_VALUE) { + /* something went wrong but we don't know what. GetLastError() could + * give us more information about the error, but then we should map + * the error code into errno. */ + errno = ENOENT; + return 0; + } + +# elif defined(DIRENT_MSDOS_INTERFACE) + if (_dos_findfirst (dirp->dirname, + _A_SUBDIR | _A_RDONLY | _A_ARCH | _A_SYSTEM | _A_HIDDEN, + &dirp->current.data) != 0) + { + /* _dos_findfirst and findfirst will set errno to ENOENT when no + * more entries could be retrieved. */ + return 0; + } +# endif + + /* initialize DIR and it's first entry */ + _setdirname (dirp); + dirp->dirent_filled = 1; + return 1; +} + + +/* + * Return implementation dependent name of the current directory entry. + */ +static const char * +_getdirname (const struct dirent *dp) +{ +#if defined(DIRENT_WIN32_INTERFACE) + return dp->data.cFileName; + +#elif defined(DIRENT_USE_FFBLK) + return dp->data.ff_name; + +#else + return dp->data.name; +#endif +} + + +/* + * Copy name of implementation dependent directory entry to the d_name field. + */ +static void +_setdirname (struct DIR *dirp) { + /* make sure that d_name is long enough */ + assert (strlen (_getdirname (&dirp->current)) <= NAME_MAX); + + strncpy (dirp->current.d_name, + _getdirname (&dirp->current), + NAME_MAX); + dirp->current.d_name[NAME_MAX] = '\0'; /*char d_name[NAME_MAX+1]*/ +} + +# ifdef __cplusplus +} +# endif +# define NAMLEN(dp) ((int)(strlen((dp)->d_name))) + +#else +# error "missing dirent interface" +#endif + + +#endif /*DIRENT_H*/ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/common/color.c b/gdcm/Utilities/gdcmopenjpeg-v1/common/color.c new file mode 100644 index 0000000..ac0921a --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/common/color.c @@ -0,0 +1,463 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#include "opj_config.h" +#include "openjpeg.h" +#include "color.h" + +#ifdef HAVE_LIBLCMS2 +#include +#endif +#ifdef HAVE_LIBLCMS1 +#include +#endif + +/*-------------------------------------------------------- +Matrix für sYCC, Amendment 1 to IEC 61966-2-1 + +Y : 0.299 0.587 0.114 :R +Cb: -0.1687 -0.3312 0.5 :G +Cr: 0.5 -0.4187 -0.0812 :B + +Inverse: + +R: 1 -3.68213e-05 1.40199 :Y +G: 1.00003 -0.344125 -0.714128 :Cb - 2^(prec - 1) +B: 0.999823 1.77204 -8.04142e-06 :Cr - 2^(prec - 1) + +-----------------------------------------------------------*/ +static void sycc_to_rgb(int offset, int upb, int y, int cb, int cr, + int *out_r, int *out_g, int *out_b) +{ + int r, g, b; + + cb -= offset; cr -= offset; + r = y + (int)(1.402 * (float)cr); + if(r < 0) r = 0; else if(r > upb) r = upb; *out_r = r; + + g = y - (int)(0.344 * (float)cb + 0.714 * (float)cr); + if(g < 0) g = 0; else if(g > upb) g = upb; *out_g = g; + + b = y + (int)(1.772 * (float)cb); + if(b < 0) b = 0; else if(b > upb) b = upb; *out_b = b; +} + +static void sycc444_to_rgb(opj_image_t *img) +{ + int *d0, *d1, *d2, *r, *g, *b; + const int *y, *cb, *cr; + int maxw, maxh, max, i, offset, upb; + + i = img->comps[0].prec; + offset = 1<<(i - 1); upb = (1<comps[0].w; maxh = img->comps[0].h; + max = maxw * maxh; + + y = img->comps[0].data; + cb = img->comps[1].data; + cr = img->comps[2].data; + + d0 = r = (int*)malloc(sizeof(int) * max); + d1 = g = (int*)malloc(sizeof(int) * max); + d2 = b = (int*)malloc(sizeof(int) * max); + + for(i = 0; i < max; ++i) + { + sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b); + + ++y; ++cb; ++cr; ++r; ++g; ++b; + } + free(img->comps[0].data); img->comps[0].data = d0; + free(img->comps[1].data); img->comps[1].data = d1; + free(img->comps[2].data); img->comps[2].data = d2; + +}/* sycc444_to_rgb() */ + +static void sycc422_to_rgb(opj_image_t *img) +{ + int *d0, *d1, *d2, *r, *g, *b; + const int *y, *cb, *cr; + int maxw, maxh, max, offset, upb; + int i, j; + + i = img->comps[0].prec; + offset = 1<<(i - 1); upb = (1<comps[0].w; maxh = img->comps[0].h; + max = maxw * maxh; + + y = img->comps[0].data; + cb = img->comps[1].data; + cr = img->comps[2].data; + + d0 = r = (int*)malloc(sizeof(int) * max); + d1 = g = (int*)malloc(sizeof(int) * max); + d2 = b = (int*)malloc(sizeof(int) * max); + + for(i=0; i < maxh; ++i) + { + for(j=0; j < maxw; j += 2) + { + sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b); + + ++y; ++r; ++g; ++b; + + sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b); + + ++y; ++r; ++g; ++b; ++cb; ++cr; + } + } + free(img->comps[0].data); img->comps[0].data = d0; + free(img->comps[1].data); img->comps[1].data = d1; + free(img->comps[2].data); img->comps[2].data = d2; + + img->comps[1].w = maxw; img->comps[1].h = maxh; + img->comps[2].w = maxw; img->comps[2].h = maxh; + img->comps[1].dx = img->comps[0].dx; + img->comps[2].dx = img->comps[0].dx; + img->comps[1].dy = img->comps[0].dy; + img->comps[2].dy = img->comps[0].dy; + +}/* sycc422_to_rgb() */ + +static void sycc420_to_rgb(opj_image_t *img) +{ + int *d0, *d1, *d2, *r, *g, *b, *nr, *ng, *nb; + const int *y, *cb, *cr, *ny; + int maxw, maxh, max, offset, upb; + int i, j; + + i = img->comps[0].prec; + offset = 1<<(i - 1); upb = (1<comps[0].w; maxh = img->comps[0].h; + max = maxw * maxh; + + y = img->comps[0].data; + cb = img->comps[1].data; + cr = img->comps[2].data; + + d0 = r = (int*)malloc(sizeof(int) * max); + d1 = g = (int*)malloc(sizeof(int) * max); + d2 = b = (int*)malloc(sizeof(int) * max); + + for(i=0; i < maxh; i += 2) + { + ny = y + maxw; + nr = r + maxw; ng = g + maxw; nb = b + maxw; + + for(j=0; j < maxw; j += 2) + { + sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b); + + ++y; ++r; ++g; ++b; + + sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b); + + ++y; ++r; ++g; ++b; + + sycc_to_rgb(offset, upb, *ny, *cb, *cr, nr, ng, nb); + + ++ny; ++nr; ++ng; ++nb; + + sycc_to_rgb(offset, upb, *ny, *cb, *cr, nr, ng, nb); + + ++ny; ++nr; ++ng; ++nb; ++cb; ++cr; + } + y += maxw; r += maxw; g += maxw; b += maxw; + } + free(img->comps[0].data); img->comps[0].data = d0; + free(img->comps[1].data); img->comps[1].data = d1; + free(img->comps[2].data); img->comps[2].data = d2; + + img->comps[1].w = maxw; img->comps[1].h = maxh; + img->comps[2].w = maxw; img->comps[2].h = maxh; + img->comps[1].dx = img->comps[0].dx; + img->comps[2].dx = img->comps[0].dx; + img->comps[1].dy = img->comps[0].dy; + img->comps[2].dy = img->comps[0].dy; + +}/* sycc420_to_rgb() */ + +void color_sycc_to_rgb(opj_image_t *img) +{ + if(img->numcomps < 3) + { + img->color_space = CLRSPC_GRAY; + return; + } + + if((img->comps[0].dx == 1) + && (img->comps[1].dx == 2) + && (img->comps[2].dx == 2) + && (img->comps[0].dy == 1) + && (img->comps[1].dy == 2) + && (img->comps[2].dy == 2))/* horizontal and vertical sub-sample */ + { + sycc420_to_rgb(img); + } + else + if((img->comps[0].dx == 1) + && (img->comps[1].dx == 2) + && (img->comps[2].dx == 2) + && (img->comps[0].dy == 1) + && (img->comps[1].dy == 1) + && (img->comps[2].dy == 1))/* horizontal sub-sample only */ + { + sycc422_to_rgb(img); + } + else + if((img->comps[0].dx == 1) + && (img->comps[1].dx == 1) + && (img->comps[2].dx == 1) + && (img->comps[0].dy == 1) + && (img->comps[1].dy == 1) + && (img->comps[2].dy == 1))/* no sub-sample */ + { + sycc444_to_rgb(img); + } + else + { + fprintf(stderr,"%s:%d:color_sycc_to_rgb\n\tCAN NOT CONVERT\n", + __FILE__,__LINE__); + return; + } + img->color_space = CLRSPC_SRGB; + +}/* color_sycc_to_rgb() */ + +#if defined(HAVE_LIBLCMS2) || defined(HAVE_LIBLCMS1) +#ifdef HAVE_LIBLCMS1 +/* Bob Friesenhahn proposed:*/ +#define cmsSigXYZData icSigXYZData +#define cmsSigLabData icSigLabData +#define cmsSigCmykData icSigCmykData +#define cmsSigYCbCrData icSigYCbCrData +#define cmsSigLuvData icSigLuvData +#define cmsSigGrayData icSigGrayData +#define cmsSigRgbData icSigRgbData +#define cmsUInt32Number DWORD + +#define cmsColorSpaceSignature icColorSpaceSignature +#define cmsGetHeaderRenderingIntent cmsTakeRenderingIntent + +#endif /* HAVE_LIBLCMS1 */ + +void color_apply_icc_profile(opj_image_t *image) +{ + cmsHPROFILE in_prof, out_prof; + cmsHTRANSFORM transform; + cmsColorSpaceSignature in_space, out_space; + cmsUInt32Number intent, in_type, out_type, nr_samples; + int *r, *g, *b; + int prec, i, max, max_w, max_h; + OPJ_COLOR_SPACE oldspace; + + in_prof = + cmsOpenProfileFromMem(image->icc_profile_buf, image->icc_profile_len); + in_space = cmsGetPCS(in_prof); + out_space = cmsGetColorSpace(in_prof); + intent = cmsGetHeaderRenderingIntent(in_prof); + + + max_w = image->comps[0].w; max_h = image->comps[0].h; + prec = image->comps[0].prec; + oldspace = image->color_space; + + if(out_space == cmsSigRgbData) /* enumCS 16 */ + { + in_type = TYPE_RGB_16; + out_type = TYPE_RGB_16; + out_prof = cmsCreate_sRGBProfile(); + image->color_space = CLRSPC_SRGB; + } + else + if(out_space == cmsSigGrayData) /* enumCS 17 */ + { + in_type = TYPE_GRAY_8; + out_type = TYPE_RGB_8; + out_prof = cmsCreate_sRGBProfile(); + image->color_space = CLRSPC_SRGB; + } + else + if(out_space == cmsSigYCbCrData) /* enumCS 18 */ + { + in_type = TYPE_YCbCr_16; + out_type = TYPE_RGB_16; + out_prof = cmsCreate_sRGBProfile(); + image->color_space = CLRSPC_SRGB; + } + else + { +#ifdef DEBUG_PROFILE +fprintf(stderr,"%s:%d: color_apply_icc_profile\n\tICC Profile has unknown " +"output colorspace(%#x)(%c%c%c%c)\n\tICC Profile ignored.\n", +__FILE__,__LINE__,out_space, +(out_space>>24) & 0xff,(out_space>>16) & 0xff, +(out_space>>8) & 0xff, out_space & 0xff); +#endif + return; + } + +#ifdef DEBUG_PROFILE +fprintf(stderr,"%s:%d:color_apply_icc_profile\n\tchannels(%d) prec(%d) w(%d) h(%d)" +"\n\tprofile: in(%p) out(%p)\n",__FILE__,__LINE__,image->numcomps,prec, +max_w,max_h, (void*)in_prof,(void*)out_prof); + +fprintf(stderr,"\trender_intent (%u)\n\t" +"color_space: in(%#x)(%c%c%c%c) out:(%#x)(%c%c%c%c)\n\t" +" type: in(%u) out:(%u)\n", +intent, +in_space, +(in_space>>24) & 0xff,(in_space>>16) & 0xff, +(in_space>>8) & 0xff, in_space & 0xff, + +out_space, +(out_space>>24) & 0xff,(out_space>>16) & 0xff, +(out_space>>8) & 0xff, out_space & 0xff, + +in_type,out_type + ); +#endif /* DEBUG_PROFILE */ + + transform = cmsCreateTransform(in_prof, in_type, + out_prof, out_type, intent, 0); + +#ifdef HAVE_LIBLCMS2 +/* Possible for: LCMS_VERSION >= 2000 :*/ + cmsCloseProfile(in_prof); + cmsCloseProfile(out_prof); +#endif + + if(transform == NULL) + { +#ifdef DEBUG_PROFILE +fprintf(stderr,"%s:%d:color_apply_icc_profile\n\tcmsCreateTransform failed. " +"ICC Profile ignored.\n",__FILE__,__LINE__); +#endif + image->color_space = oldspace; +#ifdef HAVE_LIBLCMS1 + cmsCloseProfile(in_prof); + cmsCloseProfile(out_prof); +#endif + return; + } + + if(image->numcomps > 2)/* RGB, RGBA */ + { + unsigned short *inbuf, *outbuf, *in, *out; + max = max_w * max_h; nr_samples = max * 3 * sizeof(unsigned short); + in = inbuf = (unsigned short*)malloc(nr_samples); + out = outbuf = (unsigned short*)malloc(nr_samples); + + r = image->comps[0].data; + g = image->comps[1].data; + b = image->comps[2].data; + + for(i = 0; i < max; ++i) + { + *in++ = (unsigned short)*r++; + *in++ = (unsigned short)*g++; + *in++ = (unsigned short)*b++; + } + + cmsDoTransform(transform, inbuf, outbuf, max); + + r = image->comps[0].data; + g = image->comps[1].data; + b = image->comps[2].data; + + for(i = 0; i < max; ++i) + { + *r++ = (int)*out++; + *g++ = (int)*out++; + *b++ = (int)*out++; + } + free(inbuf); free(outbuf); + } + else /* GRAY, GRAYA */ + { + unsigned char *in, *inbuf, *out, *outbuf; + + max = max_w * max_h; nr_samples = max * 3 * sizeof(unsigned char); + in = inbuf = (unsigned char*)malloc(nr_samples); + out = outbuf = (unsigned char*)malloc(nr_samples); + + image->comps = (opj_image_comp_t*) + realloc(image->comps, (image->numcomps+2)*sizeof(opj_image_comp_t)); + + if(image->numcomps == 2) + image->comps[3] = image->comps[1]; + + image->comps[1] = image->comps[0]; + image->comps[2] = image->comps[0]; + + image->comps[1].data = (int*)calloc(max, sizeof(int)); + image->comps[2].data = (int*)calloc(max, sizeof(int)); + + image->numcomps += 2; + + r = image->comps[0].data; + + for(i = 0; i < max; ++i) + { + *in++ = (unsigned char)*r++; + } + cmsDoTransform(transform, inbuf, outbuf, max); + + r = image->comps[0].data; + g = image->comps[1].data; + b = image->comps[2].data; + + for(i = 0; i < max; ++i) + { + *r++ = (int)*out++; *g++ = (int)*out++; *b++ = (int)*out++; + } + free(inbuf); free(outbuf); + + }/* if(image->numcomps */ + + cmsDeleteTransform(transform); + +#ifdef HAVE_LIBLCMS1 + cmsCloseProfile(in_prof); + cmsCloseProfile(out_prof); +#endif +}/* color_apply_icc_profile() */ + +#endif /* HAVE_LIBLCMS2 || HAVE_LIBLCMS1 */ + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/common/color.h b/gdcm/Utilities/gdcmopenjpeg-v1/common/color.h new file mode 100644 index 0000000..26117b0 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/common/color.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _OPJ_COLOR_H_ +#define _OPJ_COLOR_H_ + +extern void color_sycc_to_rgb(opj_image_t *img); +extern void color_apply_icc_profile(opj_image_t *image); + +#endif /* _OPJ_COLOR_H_ */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/common/format_defs.h b/gdcm/Utilities/gdcmopenjpeg-v1/common/format_defs.h new file mode 100644 index 0000000..d4be93b --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/common/format_defs.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _OPJ_FORMAT_DEFS_H_ +#define _OPJ_FORMAT_DEFS_H_ + +#define J2K_CFMT 0 +#define JP2_CFMT 1 +#define JPT_CFMT 2 + +#define PXM_DFMT 10 +#define PGX_DFMT 11 +#define BMP_DFMT 12 +#define YUV_DFMT 13 +#define TIF_DFMT 14 +#define RAW_DFMT 15 +#define TGA_DFMT 16 +#define PNG_DFMT 17 + +#endif /* _OPJ_FORMAT_DEFS_H_ */ \ No newline at end of file diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/common/getopt.c b/gdcm/Utilities/gdcmopenjpeg-v1/common/getopt.c new file mode 100644 index 0000000..5e444d3 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/common/getopt.c @@ -0,0 +1,261 @@ +/* + * Copyright (c) 1987, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* last review : october 29th, 2002 */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)getopt.c 8.3 (Berkeley) 4/27/95"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include + +int opterr = 1, /* if error message should be printed */ + optind = 1, /* index into parent argv vector */ + optopt, /* character checked for validity */ + optreset; /* reset getopt */ +const char *optarg; /* argument associated with option */ + +typedef struct option +{ + const char *name; + int has_arg; + int *flag; + int val; +}option_t; + +#define BADCH (int)'?' +#define BADARG (int)':' +#define EMSG "" + +/* As this class remembers its values from one Java call to the other, reset the values before each use */ +void reset_options_reading() { + opterr = 1; + optind = 1; +} + +/* + * getopt -- + * Parse argc/argv argument vector. + */ +int getopt(int nargc, char *const *nargv, const char *ostr) { +# define __progname nargv[0] + static const char *place = EMSG; /* option letter processing */ + char *oli; /* option letter list index */ + + if (optreset || !*place) { /* update scanning pointer */ + optreset = 0; + if (optind >= nargc || *(place = nargv[optind]) != '-') { + place = EMSG; + return (-1); + } + if (place[1] && *++place == '-') { /* found "--" */ + ++optind; + place = EMSG; + return (-1); + } + } /* option letter okay? */ + if ((optopt = (int) *place++) == (int) ':' || + !(oli = strchr(ostr, optopt))) { + /* + * if the user didn't specify '-' as an option, + * assume it means -1. + */ + if (optopt == (int) '-') + return (-1); + if (!*place) + ++optind; + if (opterr && *ostr != ':') { + fprintf(stderr, + "%s: illegal option -- %c\n", __progname, optopt); + return (BADCH); + } + } + if (*++oli != ':') { /* don't need argument */ + optarg = NULL; + if (!*place) + ++optind; + } else { /* need an argument */ + if (*place) /* no white space */ + optarg = place; + else if (nargc <= ++optind) { /* no arg */ + place = EMSG; + if (*ostr == ':') + return (BADARG); + if (opterr) { + fprintf(stderr, + "%s: option requires an argument -- %c\n", + __progname, optopt); + return (BADCH); + } + } else /* white space */ + optarg = nargv[optind]; + place = EMSG; + ++optind; + } + return (optopt); /* dump back option letter */ +} + + +int getopt_long(int argc, char * const argv[], const char *optstring, +struct option *longopts, int totlen) { + static int lastidx,lastofs; + char *tmp; + int i,len; + char param = 1; + +again: + if (optind >= argc || !argv[optind] || *argv[optind]!='-') + return -1; + + if (argv[optind][0]=='-' && argv[optind][1]==0) { + if(optind >= (argc - 1)){ /* no more input parameters */ + param = 0; + } + else{ /* more input parameters */ + if(argv[optind + 1][0] == '-'){ + param = 0; /* Missing parameter after '-' */ + } + else{ + param = 2; + } + } + } + + if (param == 0) { + ++optind; + return (BADCH); + } + + if (argv[optind][0]=='-') { /* long option */ + char* arg=argv[optind]+1; + const struct option* o; + o=longopts; + len=sizeof(longopts[0]); + + if (param > 1){ + arg = argv[optind+1]; + optind++; + } + else + arg = argv[optind]+1; + + if(strlen(arg)>1){ + for (i=0;iname,arg)) { /* match */ + if (o->has_arg == 0) { + if ((argv[optind+1])&&(!(argv[optind+1][0]=='-'))){ + fprintf(stderr,"%s: option does not require an argument. Ignoring %s\n",arg,argv[optind+1]); + ++optind; + } + }else{ + optarg=argv[optind+1]; + if(optarg){ + if (optarg[0] == '-'){ /* Has read next input parameter: No arg for current parameter */ + if (opterr) { + fprintf(stderr,"%s: option requires an argument\n",arg); + return (BADCH); + } + } + } + if (!optarg && o->has_arg==1) { /* no argument there */ + if (opterr) { + fprintf(stderr,"%s: option requires an argument \n",arg); + return (BADCH); + } + } + ++optind; + } + ++optind; + if (o->flag) + *(o->flag)=o->val; + else + return o->val; + return 0; + } + }//(end for)String not found in the list + fprintf(stderr,"Invalid option %s\n",arg); + ++optind; + return (BADCH); + }else{ /*Single character input parameter*/ + if (*optstring==':') return ':'; + if (lastidx!=optind) { + lastidx=optind; lastofs=0; + } + optopt=argv[optind][lastofs+1]; + if ((tmp=strchr(optstring,optopt))) {/*Found input parameter in list*/ + if (*tmp==0) { /* apparently, we looked for \0, i.e. end of argument */ + ++optind; + goto again; + } + if (tmp[1]==':') { /* argument expected */ + if (tmp[2]==':' || argv[optind][lastofs+2]) { /* "-foo", return "oo" as optarg */ + if (!*(optarg=argv[optind]+lastofs+2)) optarg=0; + goto found; + } + optarg=argv[optind+1]; + if(optarg){ + if (optarg[0] == '-'){ /* Has read next input parameter: No arg for current parameter */ + if (opterr) { + fprintf(stderr,"%s: option requires an argument\n",arg); + return (BADCH); + } + } + } + if (!optarg) { /* missing argument */ + if (opterr) { + fprintf(stderr,"%s: option requires an argument\n",arg); + return (BADCH); + } + } + ++optind; + }else {/*Argument not expected*/ + ++lastofs; + return optopt; + } +found: + ++optind; + return optopt; + } else { /* not found */ + fprintf(stderr,"Invalid option %s\n",arg); + ++optind; + return (BADCH); + }//end of not found + + }// end of single character + }//end '-' + fprintf(stderr,"Invalid option\n"); + ++optind; + return (BADCH);; +}//end function diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/common/getopt.h b/gdcm/Utilities/gdcmopenjpeg-v1/common/getopt.h new file mode 100644 index 0000000..779fe47 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/common/getopt.h @@ -0,0 +1,29 @@ +/* last review : october 29th, 2002 */ + +#ifndef _GETOPT_H_ +#define _GETOPT_H_ + +typedef struct option +{ + const char *name; + int has_arg; + int *flag; + int val; +}option_t; + +#define NO_ARG 0 +#define REQ_ARG 1 +#define OPT_ARG 2 + +extern int opterr; +extern int optind; +extern int optopt; +extern int optreset; +extern char *optarg; + +extern int getopt(int nargc, char *const *nargv, const char *ostr); +extern int getopt_long(int argc, char * const argv[], const char *optstring, + const struct option *longopts, int totlen); +extern void reset_options_reading(); + +#endif /* _GETOPT_H_ */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/doc/CMakeLists.txt b/gdcm/Utilities/gdcmopenjpeg-v1/doc/CMakeLists.txt new file mode 100644 index 0000000..23f7895 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/doc/CMakeLists.txt @@ -0,0 +1,15 @@ +find_package(Doxygen) +# +if(DOXYGEN_EXECUTABLE) +# The Doxyfile.dox is poorly defined and produce output +# in the source dir +add_custom_target(doxygen +# By default doxygen target is added to the 'all' target. Project is small +# thus running doxygen is not too time consuming + ALL + ${DOXYGEN} + ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.dox + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} +) +endif() + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/doc/Doxyfile.dox b/gdcm/Utilities/gdcmopenjpeg-v1/doc/Doxyfile.dox new file mode 100644 index 0000000..c60a4de --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/doc/Doxyfile.dox @@ -0,0 +1,234 @@ +# Doxyfile 1.4.2 + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +PROJECT_NAME = OpenJPEG +PROJECT_NUMBER = +OUTPUT_DIRECTORY = . +CREATE_SUBDIRS = NO +OUTPUT_LANGUAGE = English +USE_WINDOWS_ENCODING = YES +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = NO +STRIP_FROM_PATH = C:// +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = YES +MULTILINE_CPP_IS_BRIEF = NO +DETAILS_AT_TOP = YES +INHERIT_DOCS = YES +DISTRIBUTE_GROUP_DOC = NO +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 8 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = YES +OPTIMIZE_OUTPUT_JAVA = NO +SUBGROUPING = YES +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = YES +EXTRACT_PRIVATE = YES +EXTRACT_STATIC = YES +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = NO +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_BY_SCOPE_NAME = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_DIRECTORIES = NO +FILE_VERSION_FILTER = +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = NO +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = ../libopenjpeg \ + ../jpwl +FILE_PATTERNS = *.h \ + *.c +RECURSIVE = NO +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = * +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +VERBATIM_HEADERS = YES +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = NO +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = ./html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = NO +TREEVIEW_WIDTH = 250 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = NO +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = USE_JPWL \ + USE_JPSEC +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = YES +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = NO +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = png +DOT_PATH = +DOTFILE_DIRS = +MAX_DOT_GRAPH_WIDTH = 1024 +MAX_DOT_GRAPH_HEIGHT = 1024 +MAX_DOT_GRAPH_DEPTH = 1000 +DOT_TRANSPARENT = NO +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/doc/man/man1/image_to_j2k.1 b/gdcm/Utilities/gdcmopenjpeg-v1/doc/man/man1/image_to_j2k.1 new file mode 100644 index 0000000..331af0e --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/doc/man/man1/image_to_j2k.1 @@ -0,0 +1,222 @@ +'\" t +'\" The line above instructs most `man' programs to invoke tbl +'\" +'\" Separate paragraphs; not the same as PP which resets indent level. +.de SP +.if t .sp .5 +.if n .sp +.. +'\" +'\" Replacement em-dash for nroff (default is too short). +.ie n .ds m " - +.el .ds m \(em +'\" +'\" Placeholder macro for if longer nroff arrow is needed. +.ds RA \(-> +'\" +'\" Decimal point set slightly raised +.if t .ds d \v'-.15m'.\v'+.15m' +.if n .ds d . +'\" +'\" Enclosure macro for examples +.de EX +.SP +.nf +.ft CW +.. +.de EE +.ft R +.SP +.fi +.. +.TH image_to_j2k 1 "Version 1.4.0" "image_to_j2k" "converts to jpeg2000 files" +.P +.SH NAME +image_to_j2k - +This program reads in an image of a certain type and converts it to a +jpeg2000 file. It is part of the OpenJPEG library. +.SP +Valid input image extensions are +.B .bmp, .pgm, .pgx, .png, .pnm, .ppm, .raw, .tga, .tif \fR. For PNG resp. TIF it needs libpng resp. libtiff . +.SP +Valid output image extensions are +.B .j2k, .jp2 +.SH SYNOPSIS +.P +.B image_to_j2k -i \fRinfile.bmp \fB-o \fRoutfile.j2k +.P +.B image_to_j2k -ImgDir \fRdirectory_name \fB-OutFor \fRjp2 +.P +.B image_to_j2k -h \fRPrint a help message and exit. +.P +.R See JPWL OPTIONS for special options +.SH OPTIONS +.TP +.B \-\^b " n,n" +(Size of code block (e.g. -b 32,32). Default: 64 x 64) +.TP +.B \-\^c " n" +(Size of precinct (e.g. -c 128,128). Default: 2^15 x 2^15) +.TP +.B \-\^cinema2K " fps" +Digital Cinema 2K profile compliant codestream. Valid \fBfps\fR values are 24 or 48. +.TP +.B \-\^cinema4K +Digital Cinema 4K profile compliant codestream. Does not need an fps: default is 24 fps. +.TP +.B \-\^d " X,Y" +(Offset of image origin (e.g. -d 150,300)) +.TP +.B \-\^h +Print a help message and exit. +.TP +.B \-\^i " name" +(input file name) +.TP +.B \-\^n " n" +(Number of resolutions. Default: 6) +.TP +.B \-\^o " name" +(output file name) +.TP +.B \-\^p " name" +Progression order. \fBname\fR can be one out of:LRCP, RLCP, RPCL, PCRL, CPRL. Default: LRCP. +.TP +.B \-\^q " n" +different psnr for successive layers +.br +.B Note: \fR(options -r and -q cannot be used together) +.TP +.B \-\^r " n" +different compression ratio(s) for successive layers. The rate specified for each quality level is the desired compression factor. +.br +.B Note: \fR(options -r and -q cannot be used together) +.TP +.B \-\^s " X,Y" +sub-sampling factor (e.g. -s 2,2). Default: No sub-sampling in x or y direction. +.br +.B Remark: \fRsub-sampling bigger than 2 can produce errors. +.TP +.B \-\^t " W,H" +(Size of tile (e.g. -t 512,512) ) +.TP +.B \-\^x " name" +(Create index file and fill it. Default: no index file) +.TP +.B \-\^EPH +(Write EPH marker after each header packet. Default:no EPH) +.TP +.B \-\^F " rawWidth,rawHeight,rawComp,rawBitDepth,s_or_u" +characteristics of the raw input image +.TP +.B \-\^I +(Use the irreversible DWT 9-7. Default: Reversible DWT 5-3) +.TP +.B \-\^ImgDir " directory_name" +(directory containing input files) +.TP +.B \-\^M " n" +mode switch with values: 1, 2, 4, 8, 16, 32. Default:No mode switch activated. +.br +\fIMeaning:\fR +.br +BYPASS(1) +.br +RESET(2) +.br +RESTART(4) +.br +VSC(8) +.br +ERTERM(16) +.br +SEGMARK(32) +.br +Values can be added: RESTART(4) + RESET(2) + SEGMARK(32) = -M 38 +.TP +.B \-\^OutFor "ext" +(extension for output files) +.TP +.B \-\^POC "TtileNr=resolutionStart, componentStart, layerEnd, resolutionEnd, componentEnd, progressionOrder" +(see Examples) +.TP +.B \-\^ROI "c=n,U=n" +quantization indices upshifted for component c (0 or 1 or 2) with a value of U (>= 0 and <= 37) +.br +e.g. \fB-ROI c=0,U=25\fR +.TP +.B \-\^SOP +(Write SOP marker before each packet. Default: No SOP marker in the codestream.) +.TP +.B \-\^T "X,Y" +(Offset of the origin of the tiles (e.g. -T 100,75) ) +.TP +.B \-\^W +(see JPWL OPTIONS) +.P +.SH JPWL OPTIONS +Options usable only if the library has been compiled with \fB-DUSE_JPWL\fR +.P +.B -W h<=type>, s<=method>, a=, z=, g=, p<=type> +.P +.B h\fR selects the header error protection (EPB): \fBtype\fR can be + [0=none 1,absent=predefined 16=CRC-16 32=CRC-32 37-128=RS] + if \fBtilepart\fR is absent, it is for main and tile headers + if \fBtilepart\fR is present, it applies from that tile + onwards, up to the next h<> spec, or to the last tilepart + in the codestream (max. 16 specs) +.P +.B p \fRselects the packet error protection (EEP/UEP with EPBs) + to be applied to raw data: \fBtype\fR can be + [0=none 1,absent=predefined 16=CRC-16 32=CRC-32 37-128=RS] + if \fBtilepart:pack\fR is absent, it is from tile 0, packet 0 + if \fBtilepart:pack\fR is present, it applies from that tile + and that packet onwards, up to the next packet spec + or to the last packet in the last tilepart in the stream + (max. 16 specs) +.P +.B s \fRenables sensitivity data insertion (ESD): \fBmethod\fR can be + [-1=NO ESD 0=RELATIVE ERROR 1=MSE 2=MSE REDUCTION 3=PSNR + 4=PSNR INCREMENT 5=MAXERR 6=TSE 7=RESERVED] + if \fBtilepart\fR is absent, it is for main header only + if \fBtilepart\fR is present, it applies from that tile + onwards, up to the next s<> spec, or to the last tilepart + in the codestream (max. 16 specs) +.P +.B g \fRdetermines the addressing mode: \fBrange\fR can be + [0=PACKET 1=BYTE RANGE 2=PACKET RANGE] +.P +.B a \fRdetermines the size of data addressing: \fBaddr\fR can be + 2/4 bytes (small/large codestreams). If not set, auto-mode +.P +.B z \fRdetermines the size of sensitivity values: \fBsize\fR can be + 1/2 bytes, for the transformed pseudo-floating point value +.P +.SH EXAMPLES +.P +.B image_to_j2k -i \fRfile.bmp \fB-o \fRfile.j2k \fB-r \fR20,10,1 (compress 20x, then 10x, then lossless). +.P +.B image_to_j2k -i \fRfile.ppm \fB-o \fRfile.j2k \fB-q \fR30,40,50 +.P +.B image_to_j2k -i \fRfile.pgx \fB-o \fRfile.j2k \fB-POC \fRT1=0,0,1,5,3,CPRL +.P +.B image_to_j2k -i \fRlena.raw \fB-o \fRlena.j2k \fB-F \fR512,512,3,8,u +.P +.SH AUTHORS +Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium +.br +Copyright (c) 2002-2007, Professor Benoit Macq +.br +Copyright (c) 2001-2003, David Janssens +.br +Copyright (c) 2002-2003, Yannick Verschueren +.br +Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe +.br +Copyright (c) 2005, Herve Drolon, FreeImage Team +.br +Copyright (c) 2006-2007, Parvatha Elangovan +.P +.SH "SEE ALSO" +j2k_to_image(1) j2k_dump(1) + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/doc/man/man1/j2k_dump.1 b/gdcm/Utilities/gdcmopenjpeg-v1/doc/man/man1/j2k_dump.1 new file mode 100644 index 0000000..c45e9f4 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/doc/man/man1/j2k_dump.1 @@ -0,0 +1,62 @@ +'\" t +'\" The line above instructs most `man' programs to invoke tbl +'\" +'\" Separate paragraphs; not the same as PP which resets indent level. +.de SP +.if t .sp .5 +.if n .sp +.. +'\" +'\" Replacement em-dash for nroff (default is too short). +.ie n .ds m " - +.el .ds m \(em +'\" +'\" Placeholder macro for if longer nroff arrow is needed. +.ds RA \(-> +'\" +'\" Decimal point set slightly raised +.if t .ds d \v'-.15m'.\v'+.15m' +.if n .ds d . +'\" +'\" Enclosure macro for examples +.de EX +.SP +.nf +.ft CW +.. +.de EE +.ft R +.SP +.fi +.. +.TH j2k_dump 1 "Version 1.4.0" "j2k_dump" "dumps jpeg2000 files" +.P +.SH NAME +j2k_dump - +This program reads in a jpeg2000 image and dumps the contents to stdout. It is part of the OpenJPEG library. +.SP +Valid input image extensions are +.B .j2k, .jp2, .jpt +.SP +.SH SYNOPSIS +.P +.B j2k_dump -i \fRinfile.j2k +.P +.B j2k_dump -ImgDir \fRimages/ \fRDump all files in images/ +.P +.B j2k_dump -h \fRPrint help message and exit +.P +.SH OPTIONS +.TP +.B \-\^i "name" +(jpeg2000 input file name) +.TP +.B \-\^ImgDir "directory_name" +(directory containing jpeg2000 input files) +.P +'\".SH BUGS +.SH AUTHORS +Copyright (c) 20010, Mathieu Malaterre +.P +.SH "SEE ALSO" +image_to_j2k(1) j2k_to_image(1) diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/doc/man/man1/j2k_to_image.1 b/gdcm/Utilities/gdcmopenjpeg-v1/doc/man/man1/j2k_to_image.1 new file mode 100644 index 0000000..733a37d --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/doc/man/man1/j2k_to_image.1 @@ -0,0 +1,109 @@ +'\" t +'\" The line above instructs most `man' programs to invoke tbl +'\" +'\" Separate paragraphs; not the same as PP which resets indent level. +.de SP +.if t .sp .5 +.if n .sp +.. +'\" +'\" Replacement em-dash for nroff (default is too short). +.ie n .ds m " - +.el .ds m \(em +'\" +'\" Placeholder macro for if longer nroff arrow is needed. +.ds RA \(-> +'\" +'\" Decimal point set slightly raised +.if t .ds d \v'-.15m'.\v'+.15m' +.if n .ds d . +'\" +'\" Enclosure macro for examples +.de EX +.SP +.nf +.ft CW +.. +.de EE +.ft R +.SP +.fi +.. +.TH j2k_to_image 1 "Version 1.4.0" "j2k_to_image" "converts jpeg2000 files" +.P +.SH NAME +j2k_to_image - +This program reads in a jpeg2000 image and converts it to another +image type. It is part of the OpenJPEG library. +.SP +Valid input image extensions are +.B .j2k, .jp2, .j2c, .jpt +.SP +Valid output image extensions are +.B .bmp, .pgm, .pgx, .png, .pnm, .ppm, .raw, .tga, .tif \fR. For PNG resp. TIF it needs libpng resp. libtiff . +.SH SYNOPSIS +.P +.B j2k_to_image -i \fRinfile.j2k \fB-o \fRoutfile.png +.P +.B j2k_to_image -ImgDir \fRimages/ \fB-OutFor \fRbmp +.P +.B j2k_to_image -h \fRPrint help message and exit +.P +.R See JPWL OPTIONS for special options +.SH OPTIONS +.TP +.B \-\^i "name" +(jpeg2000 input file name) +.TP +.B \-\^l "n" +n is the maximum number of quality layers to decode. See LAYERS below) +.TP +.B \-\^o "name" +(output file name with extension) +.TP +.B \-\^r "n" +(n is the highest resolution level to be discarded. See REDUCTION below) +.TP +.B \-\^x "name" +(use name as index file and fill it) +.TP +.B \-\^ImgDir "directory_name" +(directory containing input files) +.TP +.B \-\^OutFor "ext" +(extension for output files) +.P +.SH JPWL OPTIONS +Options usable only if the library has been compiled with +.B -DUSE_JPWL +.TP +.B -W c\fR[=Nc] (Nc is the number of expected components in the codestream; default:3) +.TP +.B -W t\fR[=Nt] (Nt is the maximum number of tiles in the codestream; default:8192) +.TP +.B -W c\fR[=Nc]\fB, t\fR[=Nt] \fR(same as above) +.P +.SH REDUCTION +Set the number of highest resolution levels to be discarded. +The image resolution is effectively divided by 2 to the power of the number of discarded levels. The reduce factor is limited by the smallest total number of decomposition levels among tiles. +.SH TILES +Set the maximum number of quality layers to decode. If there are less quality layers than the specified number, all the quality layers are decoded. +.P +'\".SH BUGS +.SH AUTHORS +Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium +.br +Copyright (c) 2002-2007, Professor Benoit Macq +.br +Copyright (c) 2001-2003, David Janssens +.br +Copyright (c) 2002-2003, Yannick Verschueren +.br +Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe +.br +Copyright (c) 2005, Herve Drolon, FreeImage Team +.br +Copyright (c) 2006-2007, Parvatha Elangovan +.P +.SH "SEE ALSO" +image_to_j2k(1) j2k_dump(1) diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/doc/man/man3/libopenjpeg.3 b/gdcm/Utilities/gdcmopenjpeg-v1/doc/man/man3/libopenjpeg.3 new file mode 100644 index 0000000..071c1d5 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/doc/man/man3/libopenjpeg.3 @@ -0,0 +1,337 @@ +'\" t +'\" The line above instructs most `man' programs to invoke tbl +'\" +'\" Separate paragraphs; not the same as PP which resets indent level. +.de SP +.if t .sp .5 +.if n .sp +.. +'\" +'\" Replacement em-dash for nroff (default is too short). +.ie n .ds m " - +.el .ds m \(em +'\" +'\" Placeholder macro for if longer nroff arrow is needed. +.ds RA \(-> +'\" +'\" Decimal point set slightly raised +.if t .ds d \v'-.15m'.\v'+.15m' +.if n .ds d . +'\" +'\" Enclosure macro for examples +.de EX +.SP +.nf +.ft CW +.. +.de EE +.ft R +.SP +.fi +.. +.TH libopenjpeg 3 "Oct 2010" "Version 1.4.0" "Oct 2010" +.P +.SH NAME +libopenjpeg - +a library for reading and writing JPEG2000 image files. +.SP +.SH SYNOPSIS +.P +.B #include +.P +.SS CONVERSION FORMATS +.B PGX: imagetopgx() \fR/\fB pgxtoimage() +.P +.B PXM: imagetopnm() \fR/\fB pnmtoimage() +.P +.B BMP: imagetobmp() \fR/\fB bmptoimage() +.P +.B TIF: imagetotif() \fR/\fB tiftoimage() +.P +.B RAW: imagetoraw() \fR/\fB rawtoimage() +.P +.B TGA: imagetotga() \fR/\fB tgatoimage() +.P +.B PNG: imagetopng() \fR/\fB pngtoimage() +.P +.B YUV: imagetoyuv() \fR/\fB yuvtoimage() \fR(MJ2) +.P +.SS READ +.B opj_set_default_decoder_parameters(opj_dparameters_t *\fIparams\fB); +.P +.B opj_dinfo_t *opj_create_decompress(OPJ_CODEC_FORMAT \fIformat\fB); +.P +.B opj_event_mgr_t *opj_set_event_mgr(opj_common_ptr \fIinfo\fB, opj_event_mgr_t *\fIevent_mgr\fB, void *\fIcontext\fB); +.P +.B void opj_setup_decoder(opj_dinfo_t *\fIdinfo\fB, opj_dparameters_t * \fIparams\fB); +.P +.B opj_cio_t *opj_cio_open(opj_common_ptr \fIinfo\fB, unsigned char *\fIbuf\fB, int \fIbuf_len\fB); +.P +.B opj_image_t *opj_decode(opj_dinfo_t *\fIdinfo\fB, opj_cio_t *\fIcio\fB); +.P +.B void opj_cio_close(opj_cio_t *\fIcio\fB); +.P +.B void opj_destroy_decompress(opj_dinfo_t *\fIdinfo\fB); +.P +.B void opj_image_destroy(opj_image_t *\fIimage\fB); +.P +.SS WRITE +.B void opj_set_default_encoder_parameters(opj_cparameters_t *\fIparams\fB); +.P +/* +.B opj_image_t *FORMATtoimage(const char *\fIfname\fB, opj_cparameters_t *\fIparams\fB); +.P +*/ +.br +.B opj_cinfo_t* opj_create_compress(OPJ_CODEC_FORMAT \fIformat\fB); +.P +.B opj_event_mgr_t *opj_set_event_mgr(opj_common_ptr \fIinfo\fB, opj_event_mgr_t *\fIevent_mgr\fB, void *\fIcontext\fB); +.P +.B void opj_setup_encoder(opj_cinfo_t *\fIcinfo\fB, opj_cparameters_t *\fIparams\fB, opj_image_t *\fIimage\fB); +.P +.B opj_cio_t *opj_cio_open(opj_common_ptr \fIcinfo\fB, \fINULL\fB, \fI0\fB); +.P +.B bool opj_encode(opj_cinfo_t *\fIcinfo\fB, opj_cio_t *\fIcio\fB, opj_image_t *\fIimage\fB, char *\fIindex\fB); +.P +.B void opj_cio_close(opj_cio_t *\fIcio\fB); +.P +.B void opj_destroy_compress(opj_cinfo_t *\fIcinfo\fB); +.P +.B void opj_image_destroy(opj_image_t *\fIimage\fB); +.P +.SS GENERAL +.P +.B void opj_image_create(int \fInumcmpts\fB, opj_image_cmptparm_t *\fIcmptparms\fB, OPJ_COLOR_SPACE \fIclrspc\fB); +.P +.B int cio_tell(opj_cio_t *\fIcio\fB); +.P +.B void cio_seek(opj_cio_t *\fIcio\fB, int \fIpos\fB); +.P +.B opj_image_t *opj_decode_with_info(opj_dinfo_t *\fIdinfo\fB, opj_cio_t *\fIcio\fB, opj_codestream_info_t *\fIcstr_info\fB); +.P +.B bool opj_encode_with_info(opj_cinfo_t *\fIcinfo\fB, opj_cio_t *\fIcio\fB, opj_image_t *\fIimage\fB, opj_codestream_info_t *\fIcstr_info\fB); +.P +.B void opj_destroy_cstr_info(opj_codestream_info_t *\fIcstr_info\fB); +.P +.B const char *opj_version(\fIvoid\fB); +.P +.SH OPJ_CODEC_FORMAT +.P +.B CODEC_J2K\fR or \fBCODEC_JPT\fR or \fBCODEC_JP2 +.P +.SH OPJ_COLOR_SPACE +.P +.B CLRSPC_UNKNOWN\fR or \fBCLRSPC_UNSPECIFIED\fR or \fBCLRSPC_SRGB\fR or \fBCLRSPC_GRAY\fR or \fBCLRSPC_SYCC +.P +.SH DECOMPRESSION PARAMETERS +.p +typedef struct opj_dparameters +.br +{ + /* + Set the number of highest resolution levels to be discarded. + The image resolution is effectively divided by 2 to the power + of the number of discarded levels. + The reduce factor is limited by the smallest total number of + decomposition levels among tiles. + if != 0, then original dimension divided by 2^(reduce); + if == 0 or not used, image is decoded to the full resolution + */ + \fBint\fR cp_reduce; + /* + Set the maximum number of quality layers to decode. + If there are less quality layers than the specified number, + all the quality layers are decoded. + if != 0, then only the first "layer" layers are decoded; + if == 0 or not used, all the quality layers are decoded + */ + \fBint\fR cp_layer; + + /*command line encoder parameters (not used inside the library) */ + /* input file name */ + \fBchar\fR infile[OPJ_PATH_LEN]; + /* output file name */ + \fBchar\fR outfile[OPJ_PATH_LEN]; + /* input file format: see OPJ_CODEC_FORMAT */ + \fBint\fR decod_format; + /* output file format */ + \fBint\fR cod_format; + + /*JPWL decoding parameters */ + /* activates the JPWL correction capabilities */ + \fBbool\fR jpwl_correct; + /* expected number of components */ + \fBint\fR jpwl_exp_comps; + /* maximum number of tiles */ + \fBint\fR jpwl_max_tiles; + + /* + Specify whether the decoding should be done on the entire + codestream, or be limited to the main header + Limiting the decoding to the main header makes it possible + to extract the characteristics of the codestream + if == NO_LIMITATION, the entire codestream is decoded; + if == LIMIT_TO_MAIN_HEADER, only the main header is decoded; + */ + \fBOPJ_LIMIT_DECODING\fR cp_limit_decoding; +.br +} opj_dparameters_t; + +.SH COMPRESSION PARAMETERS +.P +typedef struct opj_cparameters +.br +{ + /* size of tile: tile_size_on = false (not in argument) + or tile_size_on = true (in argument) */ + \fBbool\fR tile_size_on; + /* XTOsiz */ + \fBint\fR cp_tx0; + /* YTOsiz */ + \fBint\fR cp_ty0; + /* XTsiz */ + \fBint\fR cp_tdx; + /* YTsiz */ + \fBint\fR cp_tdy; + /* allocation by rate/distortion */ + \fBint\fR cp_disto_alloc; + /* allocation by fixed layer */ + \fBint\fR cp_fixed_alloc; + /* add fixed_quality */ + \fBint\fR cp_fixed_quality; + /* fixed layer */ + \fBint *\fRcp_matrice; + /* comment for coding */ + \fBchar *\fRcp_comment; + /* coding style */ + \fBint\fR csty; + /* progression order: + PROG_UNKNOWN, LRCP(default), RLCP, RPCL, PCRL, CPRL */ + \fBOPJ_PROG_ORDER\fR prog_order; + /* progression order changes */ + \fBopj_poc_t\fR POC[32]; + /* number of progression order changes (POC), default: 0 */ + \fBint\fR numpocs; + /* number of layers */ + \fBint\fR tcp_numlayers; + /* rates of layers */ + \fBfloat\fR tcp_rates[100]; + /* different psnr for successive layers */ + \fBfloat\fR tcp_distoratio[100]; + /* number of resolutions */ + \fBint\fR numresolution; + /* initial code block width, default: 64 */ + \fBint\fR cblockw_init; + /* initial code block height, default: 64 */ + \fBint\fR cblockh_init; + /* mode switch (cblk_style) */ + /* 1 : use the irreversible DWT 9-7, + 0 : use lossless compression (default) */ + \fBint\fR irreversible; + /* region of interest: affected component in [0..3], + -1 means no ROI */ + \fBint\fR roi_compno; + /* region of interest: upshift value */ + \fBint\fR roi_shift; + /* number of precinct size specifications */ + \fBint\fR res_spec; + /* initial precinct width */ + \fBint\fR prcw_init[J2K_MAXRLVLS]; + /* initial precinct height */ + \fBint\fR prch_init[J2K_MAXRLVLS]; + + /*command line encoder parameters (not used inside the library) */ + /* input file name */ + \fBchar\fR infile[OPJ_PATH_LEN]; + /* output file name */ + \fBchar\fR outfile[OPJ_PATH_LEN]; + /* DEPRECATED. Index generation is now handeld with the + opj_encode_with_info() function. Set to NULL */ + \fBint\fR index_on; + /* DEPRECATED. Index generation is now handeld with the + opj_encode_with_info() function. Set to NULL */ + \fBchar\fR index[OPJ_PATH_LEN]; + /* subimage encoding: origin image offset in x direction */ + \fBint\fR image_offset_x0; + /* subimage encoding: origin image offset in y direction */ + \fBint\fR image_offset_y0; + /* subsampling value for dx */ + \fBint\fR subsampling_dx; + /* subsampling value for dy */ + \fBint\fR subsampling_dy; + /* input file format */ + \fBint\fR decod_format; + /* output file format: see OPJ_CODEC_FORMAT */ + \fBint\fR cod_format; + + /*JPWL encoding parameters */ + /* enables writing of EPC in MH, thus activating JPWL */ + \fBbool\fR jpwl_epc_on; + /* error protection method for MH (0,1,16,32,37-128) */ + \fBint\fR jpwl_hprot_MH; + /* tile number of header protection specification (>=0) */ + \fBint\fR jpwl_hprot_TPH_tileno[JPWL_MAX_NO_TILESPECS]; + /* error protection methods for TPHs (0,1,16,32,37-128) */ + \fBint\fR jpwl_hprot_TPH[JPWL_MAX_NO_TILESPECS]; + /* tile number of packet protection specification (>=0) */ + \fBint\fR jpwl_pprot_tileno[JPWL_MAX_NO_PACKSPECS]; + /* packet number of packet protection specification (>=0) */ + \fBint\fR jpwl_pprot_packno[JPWL_MAX_NO_PACKSPECS]; + /* error protection methods for packets (0,1,16,32,37-128) */ + \fBint\fR jpwl_pprot[JPWL_MAX_NO_PACKSPECS]; + /* enables writing of ESD, (0=no/1/2 bytes) */ + \fBint\fR jpwl_sens_size; + /* sensitivity addressing size (0=auto/2/4 bytes) */ + \fBint\fR jpwl_sens_addr; + /* sensitivity range (0-3) */ + \fBint\fR jpwl_sens_range; + /* sensitivity method for MH (-1=no,0-7) */ + \fBint\fR jpwl_sens_MH; + /* tile number of sensitivity specification (>=0) */ + \fBint\fR jpwl_sens_TPH_tileno[JPWL_MAX_NO_TILESPECS]; + /* sensitivity methods for TPHs (-1=no,0-7) */ + \fBint\fR jpwl_sens_TPH[JPWL_MAX_NO_TILESPECS]; + + /* Digital Cinema compliance: OFF-not compliant, + CINEMA2K_24, CINEMA2K_48, CINEMA4K_24 */ + \fBOPJ_CINEMA_MODE\fR cp_cinema; + /* Maximum rate for each component. + If == 0, component size limitation is not considered */ + \fBint\fR max_comp_size; + /* Profile name*/ + \fBOPJ_RSIZ_CAPABILITIES\fR cp_rsiz; + /* Tile part generation*/ + \fBchar\fR tp_on; + /* Flag for Tile part generation*/ + \fBchar\fR tp_flag; + /* MCT (multiple component transform) */ + \fBchar\fR tcp_mct; +.br +} opj_cparameters_t; + + +'\".SH OPTIONS +'\".SH BUGS +.SH AUTHORS +Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + +Copyright (c) 2002-2007, Professor Benoit Macq + +Copyright (c) 2001-2003, David Janssens + +Copyright (c) 2002-2003, Yannick Verschueren + +Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + +Copyright (c) 2005, Herve Drolon, FreeImage Team + +Copyright (c) 2006-2007, Parvatha Elangovan + +.P +.SH "SEE ALSO" +\fBimage_to_j2k\fR(1) \fBj2k_to_image\fR(1) \fBj2k_dump\fR(1) + +\fBJPWL_image_to_j2k\fR(1) \fBJPWL_j2k_to_image\fR(1) + +\fBextract_j2k_from_mj2\fR(1) \fBwrap_j2k_in_mj2\fR(1) +\fBframes_to_mj2\fR(1) \fBmj2_to_frames\fR(1) diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/CMakeLists.txt b/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/CMakeLists.txt new file mode 100644 index 0000000..2d8e6c4 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/CMakeLists.txt @@ -0,0 +1,5 @@ +# index_create + +add_executable(index_create +bio.c cio.c int.c pi.c t2.c tgt.c tcd.c index_create.c jpip.c jp2.c +) diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/bio.c b/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/bio.c new file mode 100644 index 0000000..2c989e5 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/bio.c @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2001-2002, David Janssens + * Copyright (c) 2003, Yannick Verschueren + * Copyright (c) 2003, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "bio.h" +#include + +static unsigned char *bio_start, *bio_end, *bio_bp; +static unsigned int bio_buf; +static int bio_ct; + +extern jmp_buf j2k_error; + +/// +/// Number of bytes written. +/// +int bio_numbytes() { + return bio_bp-bio_start; +} + +/// +/// Init decoder. +/// +/// Input buffer +/// Input buffer length +void bio_init_dec(unsigned char *bp, int len) { + bio_start=bp; + bio_end=bp+len; + bio_bp=bp; + bio_buf=0; + bio_ct=0; +} + +int bio_byteout() +{ + bio_buf = (bio_buf << 8) & 0xffff; + bio_ct = bio_buf == 0xff00 ? 7 : 8; + if (bio_bp >= bio_end) + return 1; + *bio_bp++ = bio_buf >> 8; + return 0; +} + +/// +/// Read byte. +/// +int bio_bytein() { + bio_buf=(bio_buf<<8)&0xffff; + bio_ct=bio_buf==0xff00?7:8; + if (bio_bp>=bio_end) return 1; //longjmp(j2k_error, 1); + bio_buf|=*bio_bp++; + return 0; +} + +/// +/// Read bit. +/// +int bio_getbit() { + if (bio_ct==0) { + bio_bytein(); + } + bio_ct--; + return (bio_buf>>bio_ct)&1; +} + +/// +/// Read bits. +/// +/// Number of bits to read +int bio_read(int n) { + int i, v; + v=0; + for (i=n-1; i>=0; i--) { + v+=bio_getbit()< +/// Flush bits. +/// +int bio_flush() { + bio_ct=0; + bio_byteout(); + if (bio_ct==7) { + bio_ct=0; + if ( bio_byteout()) return 1;; + } + return 0; +} + +/// +/// +int bio_inalign() { + bio_ct=0; + if ((bio_buf&0xff)==0xff) { + if( bio_bytein()) return 1; + bio_ct=0; + } + return 0; +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/bio.h b/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/bio.h new file mode 100644 index 0000000..eea6cff --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/bio.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2001-2002, David Janssens + * Copyright (c) 2003-2004, Yannick Verschueren + * Copyright (c) 2003-2004, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __BIO_H +#define __BIO_H + +int bio_numbytes(); +void bio_init_dec(unsigned char *bp, int len); +int bio_read(int n); +int bio_flush(); +int bio_inalign(); + +#endif diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/cio.c b/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/cio.c new file mode 100644 index 0000000..29f160e --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/cio.c @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2001-2002, David Janssens + * Copyright (c) 2003, Yannick Verschueren + * Copyright (c) 2003, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "cio.h" +#include + +static unsigned char *cio_start, *cio_end, *cio_bp; + +extern jmp_buf j2k_error; + +/// +/// Number of bytes written. +/// +int cio_numbytes() { + return cio_bp-cio_start; +} + +/// +/// Get position in byte stream. +/// +int cio_tell() { + return cio_bp-cio_start; +} + +/// +/// Set position in byte stream. +/// +void cio_seek(int pos) { + cio_bp=cio_start+pos; +} + +/// +/// Number of bytes left before the end of the stream. +/// +int cio_numbytesleft() { + return cio_end-cio_bp; +} + +/// +/// Get pointer to the current position in the stream. +/// +unsigned char *cio_getbp() { + return cio_bp; +} + +/// +/// Initialize byte IO. +/// +void cio_init(unsigned char *bp, int len) { + cio_start=bp; + cio_end=bp+len; + cio_bp=bp; +} + +/// +/// Write a byte. +/// +void cio_byteout(unsigned char v) { + if (cio_bp>=cio_end) longjmp(j2k_error, 1); + *cio_bp++=v; + +} + +/// +/// Read a byte. +/// +unsigned char cio_bytein() { + if (cio_bp>=cio_end) longjmp(j2k_error, 1); + return *cio_bp++; +} + +/// +/// Write a byte. +/// +//void cio_write(unsigned int v, int n) { +void cio_write(long long v, int n) { + int i; + for (i=n-1; i>=0; i--) + { + cio_byteout((unsigned char)((v>>(i<<3))&0xff)); + } +} + +/// +/// Read some bytes. +/// +/* unsigned int cio_read(int n) { */ +long long cio_read(int n) { + int i; + /*unsigned int v;*/ + long long v; + v=0; + for (i=n-1; i>=0; i--) { + v+=cio_bytein()<<(i<<3); + } + return v; +} + +/// +/// Write some bytes. +/// +void cio_skip(int n) { + cio_bp+=n; +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/cio.h b/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/cio.h new file mode 100644 index 0000000..3e29789 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/cio.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2001-2002, David Janssens + * Copyright (c) 2003-2004, Yannick Verschueren + * Copyright (c) 2003-2004, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __CIO_H +#define __CIO_H + +int cio_tell(); +void cio_seek(int pos); +int cio_numbytes(); +int cio_numbytesleft(); +unsigned char *cio_getbp(); +void cio_init(unsigned char *bp, int len); +/* void cio_write(unsigned int v, int n); */ +void cio_write(long long v, int n); +/* unsigned int cio_read(int n); */ +long long cio_read(int n); +void cio_skip(int n); + +#endif diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/fix.c b/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/fix.c new file mode 100644 index 0000000..6bf08c6 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/fix.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2001-2002, David Janssens + * Copyright (c) 2003, Yannick Verschueren + * Copyright (c) 2003, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "fix.h" + +#ifdef _WIN32 +#include + +#define int64 __int64 +#else +#define int64 long long +#endif /* _WIN32 */ + +/// +/// Multiply two fixed-precision rational numbers. +/// +int fix_mul(int a, int b) { + return (int)((int64)a*(int64)b>>13); +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/fix.h b/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/fix.h new file mode 100644 index 0000000..4b6e1b5 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/fix.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2001-2002, David Janssens + * Copyright (c) 2003, Yannick Verschueren + * Copyright (c) 2003, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __FIX_H +#define __FIX_H + +int fix_mul(int a, int b); + +#endif diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/index_create.c b/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/index_create.c new file mode 100644 index 0000000..518e70f --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/index_create.c @@ -0,0 +1,1219 @@ +/* + * Copyright (c) 2001-2002, David Janssens + * Copyright (c) 2003-2004, Yannick Verschueren + * Copyright (c) 2003-2004, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + + +#include +#include +#include +#include +#include + +#include "j2k.h" +#include "cio.h" +#include "tcd.h" +#include "int.h" +#include "jpip.h" +#include "jp2.h" + +#define J2K_MS_SOC 0xff4f +#define J2K_MS_SOT 0xff90 +#define J2K_MS_SOD 0xff93 +#define J2K_MS_EOC 0xffd9 +#define J2K_MS_SIZ 0xff51 +#define J2K_MS_COD 0xff52 +#define J2K_MS_COC 0xff53 +#define J2K_MS_RGN 0xff5e +#define J2K_MS_QCD 0xff5c +#define J2K_MS_QCC 0xff5d +#define J2K_MS_POC 0xff5f +#define J2K_MS_TLM 0xff55 +#define J2K_MS_PLM 0xff57 +#define J2K_MS_PLT 0xff58 +#define J2K_MS_PPM 0xff60 +#define J2K_MS_PPT 0xff61 +#define J2K_MS_SOP 0xff91 +#define J2K_MS_EPH 0xff92 +#define J2K_MS_CRG 0xff63 +#define J2K_MS_COM 0xff64 + +#define J2K_STATE_MHSOC 0x0001 +#define J2K_STATE_MHSIZ 0x0002 +#define J2K_STATE_MH 0x0004 +#define J2K_STATE_TPHSOT 0x0008 +#define J2K_STATE_TPH 0x0010 +#define J2K_STATE_MT 0x0020 + +#define START_NB 5 +#define INCREMENT 5 + +jmp_buf j2k_error; + +static int j2k_state; +static int j2k_curtileno; +static j2k_tcp_t j2k_default_tcp; +static unsigned char *j2k_eot; + +static j2k_image_t *j2k_img; +static j2k_cp_t *j2k_cp; + +static unsigned char **j2k_tile_data; +static int *j2k_tile_len; + +static info_image_t img; + + +void j2k_clean() { + int tileno = 0; + int compno=0, resno=0, precno=0; + + tcd_free(j2k_img, j2k_cp); + for (tileno = 0; tileno < j2k_cp->tw * j2k_cp->th; tileno++) { + info_tile_t *tile_Idx = &img.tile[tileno]; + + for (compno = 0; compno < img.Comp; compno++) + { + info_compo_t *compo_Idx = &tile_Idx->compo[compno]; + for(resno = 0; resno < img.Decomposition + 1; resno++) + { + info_reso_t *reso_Idx = &compo_Idx->reso[resno]; + for (precno = 0; precno < img.tile[tileno].pw * img.tile[tileno].ph; precno++) + { + info_prec_t *prec_Idx = &reso_Idx->prec[precno]; + free(prec_Idx->layer); + } + free(reso_Idx->prec); + } + free(compo_Idx->reso); + } + free(tile_Idx->compo); + free(tile_Idx->marker); + free(tile_Idx->tile_parts); + free(tile_Idx->marker_mul.COC); + free(tile_Idx->marker_mul.RGN); + free(tile_Idx->marker_mul.QCC); + free(tile_Idx->marker_mul.PLT); + free(tile_Idx->marker_mul.PPT); + free(tile_Idx->marker_mul.COM); +} + free(img.tile); + free(img.marker); + free(img.marker_mul.COC); + free(img.marker_mul.RGN); + free(img.marker_mul.QCC); + free(img.marker_mul.PLM); + free(img.marker_mul.PPM); + free(img.marker_mul.COM); +} + + + +void j2k_read_soc() { + j2k_state=J2K_STATE_MHSIZ; +} + + + +void j2k_read_siz() { + int len, i; + info_tile_t *tile; + + len = cio_read(2); + + /* [MHIX BOX] */ + img.marker[img.num_marker].type = J2K_MS_SIZ; + img.marker[img.num_marker].start_pos = cio_tell()-2; + img.marker[img.num_marker].len = len; + img.num_marker++; + /* [MHIX BOX] */ + + cio_read(2); /* Rsiz (capabilities) */ + j2k_img->x1 = cio_read(4); /* Xsiz */ + j2k_img->y1 = cio_read(4); /* Ysiz */ + j2k_img->x0 = cio_read(4); /* X0siz */ + j2k_img->y0 = cio_read(4); /* Y0siz */ + j2k_cp->tdx = cio_read(4); /* XTsiz */ + j2k_cp->tdy = cio_read(4); /* YTsiz */ + j2k_cp->tx0 = cio_read(4); /* XT0siz */ + j2k_cp->ty0 = cio_read(4); /* YTOsiz */ + + j2k_img->numcomps = cio_read(2); /* Csiz */ + j2k_img->comps = (j2k_comp_t*)malloc(j2k_img->numcomps * sizeof(j2k_comp_t)); + for (i = 0; i < j2k_img->numcomps; i++) { + int tmp, w, h; + tmp = cio_read(1); + j2k_img->comps[i].prec = (tmp & 0x7f) + 1; + j2k_img->comps[i].sgnd = tmp >> 7; + j2k_img->comps[i].dx = cio_read(1); + j2k_img->comps[i].dy = cio_read(1); + w = int_ceildiv(j2k_img->x1-j2k_img->x0, j2k_img->comps[i].dx); + h = int_ceildiv(j2k_img->y1-j2k_img->y0, j2k_img->comps[i].dy); + j2k_img->comps[i].data = (int*)malloc(sizeof(int) * w * h); + } + j2k_cp->tw = int_ceildiv(j2k_img->x1 - j2k_cp->tx0, j2k_cp->tdx); + j2k_cp->th = int_ceildiv(j2k_img->y1 - j2k_cp->ty0, j2k_cp->tdy); + + j2k_cp->tcps = (j2k_tcp_t*)calloc((j2k_cp->tw * j2k_cp->th), sizeof(j2k_tcp_t)); + + for (i = 0; i < j2k_cp->tw * j2k_cp->th; i++) + { + j2k_cp->tcps[i].POC = 0; + j2k_cp->tcps[i].numpocs = 0; + // j2k_cp->tcps[i].first=1; + } + + /* Initialization for PPM marker */ + j2k_cp->ppm = 0; + j2k_cp->ppm_data = NULL; + j2k_cp->ppm_previous = 0; + j2k_cp->ppm_store = 0; + + j2k_default_tcp.tccps = (j2k_tccp_t*)malloc(j2k_img->numcomps * sizeof(j2k_tccp_t)); + for (i = 0; i < j2k_cp->tw * j2k_cp->th; i++) { + j2k_cp->tcps[i].tccps = (j2k_tccp_t*)malloc(j2k_img->numcomps * sizeof(j2k_tccp_t)); + } + j2k_tile_data = (unsigned char**)calloc(j2k_cp->tw * j2k_cp->th, sizeof(char*)); + j2k_tile_len = (int*)calloc(j2k_cp->tw * j2k_cp->th, sizeof(int)); + j2k_state = J2K_STATE_MH; + + /* */ + img.Im_w = j2k_img->x1 - j2k_img->x0; + img.Im_h = j2k_img->y1 - j2k_img->y0; + img.Tile_x = j2k_cp->tdx; + img.Tile_y = j2k_cp->tdy; + img.Comp = j2k_img->numcomps; + img.tw = j2k_cp->tw; + img.th = j2k_cp->th; + img.tile = (info_tile_t*)malloc(img.tw * img.th * sizeof(info_tile_t)); + + for (i = 0; i < img.tw * img.th; i++) + { + tile = &img.tile[i]; + tile->marker = (info_marker_t*)malloc(32 * sizeof(info_marker_t)); + tile->num_marker = 0; + tile->marker_mul.num_COC = 0; + tile->marker_mul.CzCOC = START_NB; + tile->marker_mul.num_RGN = 0; + tile->marker_mul.CzRGN = START_NB; + tile->marker_mul.num_QCC = 0; + tile->marker_mul.CzQCC = START_NB; + tile->marker_mul.num_PLT = 0; + tile->marker_mul.CzPLT = START_NB; + tile->marker_mul.num_PPT = 0; + tile->marker_mul.CzPPT = START_NB; + tile->marker_mul.num_COM = 0; + tile->marker_mul.CzCOM = START_NB; + } + /* */ + + + } + +void j2k_read_com() { + int len; + info_tile_t *tile; + info_marker_t *tmp; + + len = cio_read(2); + + /* [MHIX BOX] */ + if (j2k_state == J2K_STATE_MH) + { + if (!img.marker_mul.num_COM) + img.marker_mul.COM = (info_marker_t*)malloc(img.marker_mul.CzCOM * sizeof(info_marker_t)); + if (img.marker_mul.num_COM >= img.marker_mul.CzCOM) + { + tmp = (info_marker_t*)malloc(2 * img.marker_mul.CzCOM * sizeof(info_marker_t)); + memcpy(tmp,img.marker_mul.COM,img.marker_mul.CzCOM); + img.marker_mul.CzCOM *= 2; + free(img.marker_mul.COM); + img.marker_mul.COM = tmp; + } + + img.marker_mul.COM[img.marker_mul.num_COM].type = J2K_MS_COM; + img.marker_mul.COM[img.marker_mul.num_COM].start_pos = cio_tell()-2; + img.marker_mul.COM[img.marker_mul.num_COM].len = len; + img.marker_mul.num_COM++; + } else + { + tile = &img.tile[j2k_curtileno]; + if (!tile->marker_mul.num_COM) + tile->marker_mul.COM = (info_marker_t*)calloc(START_NB, sizeof(info_marker_t)); + if (tile->marker_mul.num_COM >= tile->marker_mul.CzCOM) + { + tmp = (info_marker_t*)malloc(2 * tile->marker_mul.CzCOM * sizeof(info_marker_t)); + memcpy(tmp,tile->marker_mul.COM,tile->marker_mul.CzCOM); + tile->marker_mul.CzCOM *= 2; + free(tile->marker_mul.COM); + tile->marker_mul.COM = tmp; + } + tile->marker_mul.COM[tile->marker_mul.num_COM].type = J2K_MS_COM; + tile->marker_mul.COM[tile->marker_mul.num_COM].start_pos = cio_tell()-2; + tile->marker_mul.COM[tile->marker_mul.num_COM].len = len; + tile->marker_mul.num_COM++; + } + /* [MHIX BOX] */ + + cio_skip(len - 2); +} + + + + +void j2k_read_cox(int compno) { + int i; + j2k_tcp_t *tcp; + j2k_tccp_t *tccp; + + tcp = j2k_state == J2K_STATE_TPH ? &j2k_cp->tcps[j2k_curtileno] : &j2k_default_tcp; + tccp = &tcp->tccps[compno]; + tccp->numresolutions = cio_read(1) + 1; + + img.Decomposition = tccp->numresolutions - 1; /* */ + + tccp->cblkw = cio_read(1) + 2; + tccp->cblkh = cio_read(1) + 2; + tccp->cblksty = cio_read(1); + tccp->qmfbid = cio_read(1); + if (tccp->csty&J2K_CP_CSTY_PRT) { + for (i = 0; i < tccp->numresolutions; i++) { + int tmp = cio_read(1); + tccp->prcw[i] = tmp&0xf; + tccp->prch[i] = tmp>>4; + } + } +} + + + + +void j2k_read_cod() { + int len, i, pos; + j2k_tcp_t *tcp; + info_tile_t *tile; + + tcp = j2k_state == J2K_STATE_TPH ? &j2k_cp->tcps[j2k_curtileno] : &j2k_default_tcp; + len = cio_read(2); + + /* [MHIX BOX] */ + if (j2k_state == J2K_STATE_MH) + { + img.marker[img.num_marker].type = J2K_MS_SIZ; + img.marker[img.num_marker].start_pos = cio_tell()-2; + img.marker[img.num_marker].len = len; + img.num_marker++; + } + else + { + tile = &img.tile[j2k_curtileno]; + tile->marker[tile->num_marker].type = J2K_MS_SIZ; + tile->marker[tile->num_marker].start_pos = cio_tell()-2; + tile->marker[tile->num_marker].len = len; + tile->num_marker++; + } + /* [MHIX BOX] */ + + tcp->csty = cio_read(1); + tcp->prg = cio_read(1); + tcp->numlayers = cio_read(2); + tcp->mct = cio_read(1); + + pos = cio_tell(); + for (i = 0; i < j2k_img->numcomps; i++) { + tcp->tccps[i].csty = tcp->csty&J2K_CP_CSTY_PRT; + cio_seek(pos); + j2k_read_cox(i); + } + + /* */ + img.Prog = tcp->prg; + img.Layer = tcp->numlayers; + /* */ +} + + + + +void j2k_read_coc() { + int len, compno; + j2k_tcp_t *tcp; + info_tile_t *tile; + info_marker_t *tmp; + + tcp = j2k_state == J2K_STATE_TPH ? &j2k_cp->tcps[j2k_curtileno] : &j2k_default_tcp; + len = cio_read(2); + + /* [MHIX BOX] */ + if (j2k_state == J2K_STATE_MH) + { + if (!img.marker_mul.num_COC) + img.marker_mul.COC = (info_marker_t*)malloc(img.marker_mul.CzCOC * sizeof(info_marker_t)); + if (img.marker_mul.num_COC >= img.marker_mul.CzCOC) + { + tmp = (info_marker_t*)malloc((INCREMENT + img.marker_mul.CzCOC) * sizeof(info_marker_t)); + memcpy(tmp,img.marker_mul.COC,img.marker_mul.CzCOC); + img.marker_mul.CzCOC += INCREMENT; + free(img.marker_mul.COC); + img.marker_mul.COC = tmp; + } + img.marker_mul.COC[img.marker_mul.num_COC].type = J2K_MS_COC; + img.marker_mul.COC[img.marker_mul.num_COC].start_pos = cio_tell()-2; + img.marker_mul.COC[img.marker_mul.num_COC].len = len; + img.marker_mul.num_COC++; + } else + { + tile = &img.tile[j2k_curtileno]; + if (!tile->marker_mul.num_COC) + tile->marker_mul.COC = (info_marker_t*)malloc(tile->marker_mul.CzCOC * sizeof(info_marker_t)); + if (tile->marker_mul.num_COC >= tile->marker_mul.CzCOC) + { + tmp = (info_marker_t*)malloc((INCREMENT + tile->marker_mul.CzCOC) * sizeof(info_marker_t)); + memcpy(tmp,tile->marker_mul.COC,tile->marker_mul.CzCOC); + tile->marker_mul.CzCOC += INCREMENT; + free(tile->marker_mul.COC); + tile->marker_mul.COC = tmp; + } + tile->marker_mul.COC[tile->marker_mul.num_COC].type = J2K_MS_COC; + tile->marker_mul.COC[tile->marker_mul.num_COC].start_pos = cio_tell() - 2; + tile->marker_mul.COC[tile->marker_mul.num_COC].len = len; + tile->marker_mul.num_COC++; + } + /* [MHIX BOX] */ + + compno =cio_read(j2k_img->numcomps <= 256 ? 1 : 2); + + tcp->tccps[compno].csty = cio_read(1); + j2k_read_cox(compno); +} + + + + +void j2k_read_qcx(int compno, int len) { + int tmp; + j2k_tcp_t *tcp; + j2k_tccp_t *tccp; + int bandno, numbands; + + tcp = j2k_state == J2K_STATE_TPH ? &j2k_cp->tcps[j2k_curtileno] : &j2k_default_tcp; + tccp = &tcp->tccps[compno]; + tmp = cio_read(1); + tccp->qntsty = tmp & 0x1f; + tccp->numgbits = tmp >> 5; + numbands = tccp->qntsty == J2K_CCP_QNTSTY_SIQNT ? 1 : (tccp->qntsty == J2K_CCP_QNTSTY_NOQNT ? len - 1 : (len - 1) / 2); + for (bandno = 0; bandno < numbands; bandno++) { + int expn, mant; + if (tccp->qntsty == J2K_CCP_QNTSTY_NOQNT) { /* WHY STEPSIZES WHEN NOQNT ? */ + expn = cio_read(1) >> 3; + mant = 0; + } else { + tmp = cio_read(2); + expn = tmp >> 11; + mant = tmp & 0x7ff; + } + tccp->stepsizes[bandno].expn = expn; + tccp->stepsizes[bandno].mant = mant; + } +} + + + + +void j2k_read_qcd() { + int len, i, pos; + info_tile_t *tile; + + len = cio_read(2); + + /* [MHIX BOX] */ + if (j2k_state == J2K_STATE_MH) + { + img.marker[img.num_marker].type = J2K_MS_QCD; + img.marker[img.num_marker].start_pos = cio_tell()-2; + img.marker[img.num_marker].len = len; + img.num_marker++; + } else + { + tile = &img.tile[j2k_curtileno]; + tile->marker[tile->num_marker].type = J2K_MS_QCD; + tile->marker[tile->num_marker].start_pos = cio_tell()-2; + tile->marker[tile->num_marker].len = len; + tile->num_marker++; + } + /* [MHIX BOX] */ + + + pos=cio_tell(); + for (i = 0; i < j2k_img->numcomps; i++) { + cio_seek(pos); + j2k_read_qcx(i, len - 2); + } +} + + + + +void j2k_read_qcc() { + int len, compno; + info_tile_t *tile; + info_marker_t *tmp; + + len = cio_read(2); + /* [MHIX BOX] */ + if (j2k_state == J2K_STATE_MH) + { + if (!img.marker_mul.num_QCC) + img.marker_mul.QCC = (info_marker_t*)malloc(img.marker_mul.CzQCC * sizeof(info_marker_t)); + if (img.marker_mul.num_QCC >= img.marker_mul.CzQCC) + { + tmp = (info_marker_t*)malloc((INCREMENT + img.marker_mul.CzQCC) * sizeof(info_marker_t)); + memcpy(tmp,img.marker_mul.QCC,img.marker_mul.CzQCC); + img.marker_mul.CzQCC += INCREMENT; + free(img.marker_mul.QCC); + img.marker_mul.QCC = tmp; + } + img.marker_mul.QCC[img.marker_mul.num_QCC].type = J2K_MS_QCC; + img.marker_mul.QCC[img.marker_mul.num_QCC].start_pos = cio_tell() - 2; + img.marker_mul.QCC[img.marker_mul.num_QCC].len = len; + img.marker_mul.num_QCC++; + } else + { + tile = &img.tile[j2k_curtileno]; + if (!tile->marker_mul.num_QCC) + tile->marker_mul.QCC = (info_marker_t*)malloc(tile->marker_mul.CzQCC * sizeof(info_marker_t)); + if (tile->marker_mul.num_QCC >= tile->marker_mul.CzQCC) + { + tmp = (info_marker_t*)malloc((INCREMENT + tile->marker_mul.CzQCC) * sizeof(info_marker_t)); + memcpy(tmp,tile->marker_mul.QCC,tile->marker_mul.CzQCC); + tile->marker_mul.CzQCC += INCREMENT; + free(tile->marker_mul.QCC); + tile->marker_mul.QCC = tmp; + } + tile->marker_mul.QCC[tile->marker_mul.num_QCC].type = J2K_MS_QCC; + tile->marker_mul.QCC[tile->marker_mul.num_QCC].start_pos = cio_tell()-2; + tile->marker_mul.QCC[tile->marker_mul.num_QCC].len = len; + tile->marker_mul.num_QCC++; + } + /* [MHIX BOX] */ + + compno = cio_read(j2k_img->numcomps <= 256 ? 1 : 2); + j2k_read_qcx(compno, len - 2 - (j2k_img->numcomps <= 256 ? 1 : 2)); +} + + + + +void j2k_read_poc() { + int len, numpchgs, i, old_poc; + j2k_tcp_t *tcp; + j2k_tccp_t *tccp; + info_tile_t *tile; + + tcp = j2k_state == J2K_STATE_TPH ? &j2k_cp->tcps[j2k_curtileno] : &j2k_default_tcp; + old_poc = tcp->POC ? tcp->numpocs+1 : 0; + tcp->POC = 1; + tccp = &tcp->tccps[0]; + len = cio_read(2); + + /* [MHIX BOX] */ + if (j2k_state == J2K_STATE_MH) + { + img.marker[img.num_marker].type = J2K_MS_POC; + img.marker[img.num_marker].start_pos = cio_tell()-2; + img.marker[img.num_marker].len = len; + img.num_marker++; + } else + { + tile = &img.tile[j2k_curtileno]; + tile->marker[tile->num_marker].type = J2K_MS_POC; + tile->marker[tile->num_marker].start_pos = cio_tell()-2; + tile->marker[tile->num_marker].len = len; + tile->num_marker++; + } + /* [MHIX BOX] */ + + numpchgs = (len - 2) / (5 + 2 * (j2k_img->numcomps <= 256 ? 1 : 2)); + for (i = 0; i < numpchgs; i++) { + j2k_poc_t *poc; + poc = &tcp->pocs[i]; + poc->resno0 = cio_read(1); + poc->compno0 = cio_read(j2k_img->numcomps <= 256 ? 1 : 2); + poc->layno1 = int_min(cio_read(2), tcp->numlayers); + poc->resno1 = int_min(cio_read(1), tccp->numresolutions); + poc->compno1 = int_min(cio_read(j2k_img->numcomps <= 256 ? 1 : 2), j2k_img->numcomps); + poc->prg = cio_read(1); + } + + tcp->numpocs = numpchgs + old_poc - 1; +} + + + + +void j2k_read_crg() { + int len, i, Xcrg_i, Ycrg_i; + + len = cio_read(2); + + /* [MHIX BOX] */ + img.marker[img.num_marker].type = J2K_MS_CRG; + img.marker[img.num_marker].start_pos = cio_tell()-2; + img.marker[img.num_marker].len = len; + img.num_marker++; + /* [MHIX BOX] */ + + for (i = 0; i < j2k_img->numcomps; i++) + { + Xcrg_i = cio_read(2); + Ycrg_i = cio_read(2); + } +} + + + + +void j2k_read_tlm() { + int len, Ztlm, Stlm, ST, SP, tile_tlm, i; + long int Ttlm_i, Ptlm_i; + info_marker_t *tmp; + + len = cio_read(2); + + /* [MHIX BOX] */ + if (!img.marker_mul.num_TLM) + img.marker_mul.TLM = (info_marker_t*)malloc(img.marker_mul.CzTLM * sizeof(info_marker_t)); + if (img.marker_mul.num_TLM >= img.marker_mul.CzTLM) + { + tmp = (info_marker_t*)malloc((INCREMENT + img.marker_mul.CzTLM) * sizeof(info_marker_t)); + memcpy(tmp,img.marker_mul.TLM,img.marker_mul.CzTLM); + img.marker_mul.CzTLM += INCREMENT; + free(img.marker_mul.TLM); + img.marker_mul.TLM = tmp; + } + img.marker_mul.TLM[img.marker_mul.num_TLM].type = J2K_MS_TLM; + img.marker_mul.TLM[img.marker_mul.num_TLM].start_pos = cio_tell()-2; + img.marker_mul.TLM[img.marker_mul.num_TLM].len = len; + img.marker_mul.num_TLM++; + /* [MHIX BOX] */ + + Ztlm = cio_read(1); + Stlm = cio_read(1); + ST = ((Stlm >> 4) & 0x01) + ((Stlm >> 4) & 0x02); + SP = (Stlm >> 6) & 0x01; + tile_tlm = (len - 4) / ((SP + 1) * 2 + ST); + for (i = 0; i < tile_tlm; i++) + { + Ttlm_i = cio_read(ST); + Ptlm_i = cio_read(SP ? 4 : 2); + } +} + + + + +void j2k_read_plm() { + int len, i, Z_plm, N_plm, add, packet_len=0; + info_marker_t *tmp; + + len=cio_read(2); + + /* [MHIX BOX] */ + if (!img.marker_mul.num_PLM) + img.marker_mul.PLM = (info_marker_t*)malloc(img.marker_mul.CzPLM * sizeof(info_marker_t)); + if (img.marker_mul.num_PLM >= img.marker_mul.CzPLM) + { + tmp = (info_marker_t*)malloc((INCREMENT + img.marker_mul.CzPLM) * sizeof(info_marker_t)); + memcpy(tmp,img.marker_mul.PLM,img.marker_mul.CzPLM); + img.marker_mul.CzPLM += INCREMENT; + free(img.marker_mul.PLM); + img.marker_mul.PLM = tmp; + } + img.marker_mul.PLM[img.marker_mul.num_PLM].type = J2K_MS_PLM; + img.marker_mul.PLM[img.marker_mul.num_PLM].start_pos = cio_tell()-2; + img.marker_mul.PLM[img.marker_mul.num_PLM].len = len; + img.marker_mul.num_PLM++; + /* [MHIX BOX] */ + + Z_plm = cio_read(1); + len -= 3; + while (len > 0) + { + N_plm = cio_read(4); + len -= 4; + for (i = N_plm ; i > 0 ; i--) + { + add = cio_read(1); + len--; + packet_len = (packet_len << 7) + add; + if ((add & 0x80) == 0) + { + /* New packet */ + packet_len = 0; + } + if (len <= 0) break; + } + } +} + + + + +void j2k_read_plt() { + int len, i, Zplt, packet_len=0, add; + info_tile_t *tile; + info_marker_t *tmp; +; + len = cio_read(2); + + /* [MHIX BOX] */ + tile = &img.tile[j2k_curtileno]; + if (!tile->marker_mul.num_PLT) + tile->marker_mul.PLT = (info_marker_t*)malloc(tile->marker_mul.CzPLT * sizeof(info_marker_t)); + if (tile->marker_mul.num_PLT >= tile->marker_mul.CzPLT) + { + tmp = (info_marker_t*)malloc((INCREMENT + tile->marker_mul.CzPLT) * sizeof(info_marker_t)); + memcpy(tmp,tile->marker_mul.PLT,tile->marker_mul.CzPLT); + tile->marker_mul.CzPLT += INCREMENT; + free(tile->marker_mul.PLT); + tile->marker_mul.PLT = tmp; + } + + tile->marker_mul.PLT[tile->marker_mul.num_PLT].type = J2K_MS_PLT; + tile->marker_mul.PLT[tile->marker_mul.num_PLT].start_pos = cio_tell()-2; + tile->marker_mul.PLT[tile->marker_mul.num_PLT].len = len; + tile->marker_mul.num_PLT++; + /* [MHIX BOX] */ + + Zplt = cio_read(1); + for (i = len-3; i > 0; i--) + { + add = cio_read(1); + packet_len = (packet_len << 7) + add; + if ((add & 0x80) == 0) + { + /* New packet */ + packet_len = 0; + } + } +} + + + + +void j2k_read_ppm() { + int len, Z_ppm, i, j; + int N_ppm; + info_marker_t *tmp; + + len = cio_read(2); + + /* [MHIX BOX] */ + if (!img.marker_mul.num_PPM) + img.marker_mul.PPM = (info_marker_t*)malloc(img.marker_mul.CzPPM * sizeof(info_marker_t)); + if (img.marker_mul.num_PPM >= img.marker_mul.CzPPM) + { + tmp = (info_marker_t*)malloc((INCREMENT + img.marker_mul.CzPPM) * sizeof(info_marker_t)); + memcpy(tmp,img.marker_mul.PPM,img.marker_mul.CzPPM); + img.marker_mul.CzPPM += INCREMENT; + free(img.marker_mul.PPM); + img.marker_mul.PPM = tmp; + } + img.marker_mul.PLM[img.marker_mul.num_PPM].type = J2K_MS_PPM; + img.marker_mul.PLM[img.marker_mul.num_PPM].start_pos = cio_tell()-2; + img.marker_mul.PLM[img.marker_mul.num_PPM].len = len; + img.marker_mul.num_PPM++; + /* [MHIX BOX] */ + + j2k_cp->ppm = 1; + + Z_ppm = cio_read(1); /* Z_ppm */ + len -= 3; + while (len > 0) + { + if (j2k_cp->ppm_previous == 0) + { + N_ppm = cio_read(4); /* N_ppm */ + len -= 4; + } else + { + N_ppm = j2k_cp->ppm_previous; + } + + j = j2k_cp->ppm_store; + if (Z_ppm == 0) /* First PPM marker */ + j2k_cp->ppm_data = (unsigned char*)calloc(N_ppm, sizeof(unsigned char)); + else /* NON-first PPM marker */ + j2k_cp->ppm_data = (unsigned char*)realloc(j2k_cp->ppm_data, (N_ppm + j2k_cp->ppm_store) * sizeof(unsigned char)); + + for (i = N_ppm ; i > 0 ; i--) /* Read packet header */ + { + j2k_cp->ppm_data[j] = cio_read(1); + j++; + len--; + if (len == 0) break; /* Case of non-finished packet header in present marker but finished in next one */ + } + + j2k_cp->ppm_previous = i - 1; + j2k_cp->ppm_store = j; + } +} + + + + +void j2k_read_ppt() { + int len, Z_ppt, i, j = 0; + j2k_tcp_t *tcp; + info_tile_t *tile; + len=cio_read(2); + + /* [MHIX BOX] */ + tile = & img.tile[j2k_curtileno]; + tile->marker[tile->num_marker].type = J2K_MS_PPT; + tile->marker[tile->num_marker].start_pos = cio_tell()-2; + tile->marker[tile->num_marker].len = len; + tile->num_marker++; + /* [MHIX BOX] */ + + Z_ppt = cio_read(1); + tcp = &j2k_cp->tcps[j2k_curtileno]; + tcp->ppt = 1; + if (Z_ppt == 0) /* First PPT marker */ + { + tcp->ppt_data = (unsigned char*)calloc(len - 3, sizeof(unsigned char)); + tcp->ppt_store = 0; + } + else /* NON-first PPT marker */ + tcp->ppt_data = (unsigned char*)realloc(tcp->ppt_data, (len - 3 + tcp->ppt_store) * sizeof(unsigned char)); + + j = tcp->ppt_store; + for (i = len - 3 ; i > 0 ; i--) + { + tcp->ppt_data[j] = cio_read(1); + j++; + } + tcp->ppt_store = j; +} + + + + +void j2k_read_sot() { + int len, tileno, totlen, partno, numparts, i; + j2k_tcp_t *tcp; + j2k_tccp_t *tmp; + info_tile_t *tile; + info_tile_part_t *tilepart_tmp; + + + //fprintf(stderr,"SOT\n"); + len = cio_read(2); + tileno = cio_read(2); + /* [MHIX BOX] */ + tile = & img.tile[tileno]; + tile->marker[tile->num_marker].type = J2K_MS_SOT; + tile->marker[tile->num_marker].start_pos = cio_tell() - 4; + tile->marker[tile->num_marker].len = len; + tile->num_marker++; + /* [MHIX BOX] */ + + totlen = cio_read(4); + if (!totlen) totlen = cio_numbytesleft() + 8; + partno = cio_read(1); + numparts = cio_read(1); + + /* */ + if (tileno == 0 && partno == 0 ) + img.Main_head_end = cio_tell() - 7; /* Correction End = First byte of first SOT */ + + img.tile[tileno].num_tile = tileno; + /* */ + + tile->numparts = partno + 1; /* INDEX : Number of tile_parts for the tile */ + img.num_max_tile_parts = int_max(tile->numparts, img.num_max_tile_parts); /* INDEX : Maximum number of tile_part per tile */ + + if (partno == 0) + { + tile->tile_parts = (info_tile_part_t*)malloc(START_NB * sizeof(info_tile_part_t*)); + tile->Cztile_parts = START_NB; + } + if (partno >= tile->Cztile_parts) + { + tilepart_tmp = (info_tile_part_t*)malloc((INCREMENT + tile->Cztile_parts) * sizeof(info_tile_part_t)); + memcpy(tilepart_tmp, tile->tile_parts, tile->Cztile_parts); + tile->Cztile_parts += INCREMENT; + free(tile->tile_parts); + tile->tile_parts = tilepart_tmp; + } + + tile->tile_parts[partno].start_pos = cio_tell() - 12; /* INDEX : start_pos of the tile_part */ + tile->tile_parts[partno].length = totlen; /* INDEX : length of the tile_part */ + tile->tile_parts[partno].end_pos = totlen + cio_tell() - 12; /* INDEX : end position of the tile_part */ + + + j2k_curtileno = tileno; + j2k_eot = cio_getbp() - 12 + totlen; + j2k_state = J2K_STATE_TPH; + tcp = &j2k_cp->tcps[j2k_curtileno]; + + tile->tile_parts[numparts].num_reso_AUX = tcp->tccps[0].numresolutions; /* INDEX : AUX value for TPIX */ + + if (partno == 0) + // if (tcp->first == 1) + { + tmp = tcp->tccps; + *tcp = j2k_default_tcp; + /* Initialization PPT */ + tcp->ppt = 0; + tcp->ppt_data = NULL; + + tcp->tccps = tmp; + for (i = 0; i < j2k_img->numcomps; i++) { + tcp->tccps[i] = j2k_default_tcp.tccps[i]; + } + //j2k_cp->tcps[j2k_curtileno].first=0; + } +} + + + +void j2k_read_rgn() { + int len, compno, roisty; + j2k_tcp_t *tcp; + info_tile_t *tile; + info_marker_t *tmp; + // fprintf(stderr,"RGN\n"); + tcp = j2k_state == J2K_STATE_TPH ? &j2k_cp->tcps[j2k_curtileno] : &j2k_default_tcp; + len = cio_read(2); + + /* [MHIX BOX]*/ + if (j2k_state == J2K_STATE_MH) + { + if (!img.marker_mul.num_RGN) + img.marker_mul.RGN = (info_marker_t*)malloc(img.marker_mul.CzRGN * sizeof(info_marker_t)); + if (img.marker_mul.num_RGN >= img.marker_mul.CzRGN) + { + tmp = (info_marker_t*)malloc((INCREMENT + img.marker_mul.CzRGN) * sizeof(info_marker_t)); + memcpy(tmp,img.marker_mul.RGN, img.marker_mul.CzRGN); + img.marker_mul.CzRGN += INCREMENT; + free(img.marker_mul.RGN); + img.marker_mul.RGN = tmp; + } + img.marker_mul.RGN[img.marker_mul.num_RGN].type = J2K_MS_RGN; + img.marker_mul.RGN[img.marker_mul.num_RGN].start_pos = cio_tell() - 2; + img.marker_mul.RGN[img.marker_mul.num_RGN].len = len; + img.marker_mul.num_RGN++; + } else + { + tile = &img.tile[j2k_curtileno]; + if (!tile->marker_mul.num_RGN) + tile->marker_mul.RGN = (info_marker_t*)malloc(tile->marker_mul.CzRGN * sizeof(info_marker_t)); + if (tile->marker_mul.num_RGN >= tile->marker_mul.CzRGN) + { + tmp = (info_marker_t*)malloc((INCREMENT + tile->marker_mul.CzRGN) * sizeof(info_marker_t)); + memcpy(tmp,tile->marker_mul.RGN,tile->marker_mul.CzRGN); + tile->marker_mul.CzRGN += INCREMENT; + free(tile->marker_mul.RGN); + tile->marker_mul.RGN = tmp; + } + + tile->marker_mul.RGN[tile->marker_mul.num_RGN].type = J2K_MS_RGN; + tile->marker_mul.RGN[tile->marker_mul.num_RGN].start_pos = cio_tell() - 2; + tile->marker_mul.RGN[tile->marker_mul.num_RGN].len = len; + tile->marker_mul.num_RGN++; + } + /* [MHIX BOX] */ + + compno = cio_read(j2k_img->numcomps <= 256 ? 1 : 2); + roisty = cio_read(1); + tcp->tccps[compno].roishift = cio_read(1); +} + + + + + +void j2k_read_sod() { + int len; + unsigned char *data; + info_tile_t *tile; + info_tile_part_t *tile_part; + // fprintf(stderr,"SOD\n"); + /* [MHIX BOX] */ + tile = &img.tile[j2k_curtileno]; + tile->marker[tile->num_marker].type = J2K_MS_SOD; + tile->marker[tile->num_marker].start_pos = cio_tell(); + tile->marker[tile->num_marker].len = 0; + tile->num_marker++; + /* [MHIX BOX] */ + + tile_part = &tile->tile_parts[tile->numparts - 1]; /* INDEX : Current tilepart of a tile */ + tile_part->length_header = cio_tell() - 1 - tile_part->start_pos; /* INDEX : length of the tile-part header */ + tile_part->end_header = cio_tell() - 1; /* INDEX : end header position of the tile-part header */ + + len = int_min(j2k_eot - cio_getbp(), cio_numbytesleft()); + + j2k_tile_len[j2k_curtileno] += len; + data = (unsigned char*)realloc(j2k_tile_data[j2k_curtileno], j2k_tile_len[j2k_curtileno]); + memcpy(data, cio_getbp(), len); + j2k_tile_data[j2k_curtileno] = data; + cio_skip(len); + j2k_state = J2K_STATE_TPHSOT; +} + +void j2k_read_eoc() { + int tileno; + tcd_init(j2k_img, j2k_cp, &img); + for (tileno = 0; tilenotw * j2k_cp->th; tileno++) { + tcd_decode_tile(j2k_tile_data[tileno], j2k_tile_len[tileno], tileno, &img); + } + + j2k_state = J2K_STATE_MT; + longjmp(j2k_error, 1); +} + + + + +void j2k_read_unk() { + fprintf(stderr, "warning: unknown marker\n"); +} + + + + +int j2k_index_JPIP(char *Idx_file, char *J2K_file, int len, int version){ + FILE *dest; + unsigned char *index; + int pos_iptr, end_pos; + int len_cidx, pos_cidx; + int len_jp2c, pos_jp2c; + int len_fidx, pos_fidx; + + dest=fopen(Idx_file, "wb"); + if (!dest) { + fprintf(stderr, "Failed to open %s for reading !!\n", Idx_file); + return 0; + } + + /* INDEX MODE JPIP */ + index = (unsigned char*)malloc(len); + cio_init(index, len); + jp2_write_jp(); + jp2_write_ftyp(); + + jp2_write_jp2h(j2k_img); + jp2_write_dbtl(Idx_file); + + pos_iptr=cio_tell(); + cio_skip(24); /* IPTR further ! */ + + pos_jp2c = cio_tell(); + len_jp2c = jp2_write_jp2c(J2K_file); + + pos_cidx = cio_tell(); + len_cidx = jpip_write_cidx(pos_jp2c + 8,img, j2k_cp, version); /* Correction len_jp2C --> pos_jp2c + 8 */ + + + pos_fidx = cio_tell(); + len_fidx = jpip_write_fidx(pos_jp2c, len_jp2c, pos_cidx, len_cidx); + +end_pos = cio_tell(); + + cio_seek(pos_iptr); + jpip_write_iptr(pos_fidx,len_fidx); + cio_seek(end_pos); + + fwrite(index, 1, cio_tell(), dest); + free(index); + + fclose(dest); + return 1; +} + + + +typedef struct { + int id; + int states; + void (*handler)(); +} j2k_dec_mstabent_t; + +j2k_dec_mstabent_t j2k_dec_mstab[]={ + {J2K_MS_SOC, J2K_STATE_MHSOC, j2k_read_soc}, + {J2K_MS_SOT, J2K_STATE_MH|J2K_STATE_TPHSOT, j2k_read_sot}, + {J2K_MS_SOD, J2K_STATE_TPH, j2k_read_sod}, + {J2K_MS_EOC, J2K_STATE_TPHSOT, j2k_read_eoc}, + {J2K_MS_SIZ, J2K_STATE_MHSIZ, j2k_read_siz}, + {J2K_MS_COD, J2K_STATE_MH|J2K_STATE_TPH, j2k_read_cod}, + {J2K_MS_COC, J2K_STATE_MH|J2K_STATE_TPH, j2k_read_coc}, + {J2K_MS_RGN, J2K_STATE_MH|J2K_STATE_TPH, j2k_read_rgn}, + {J2K_MS_QCD, J2K_STATE_MH|J2K_STATE_TPH, j2k_read_qcd}, + {J2K_MS_QCC, J2K_STATE_MH|J2K_STATE_TPH, j2k_read_qcc}, + {J2K_MS_POC, J2K_STATE_MH|J2K_STATE_TPH, j2k_read_poc}, + {J2K_MS_TLM, J2K_STATE_MH, j2k_read_tlm}, + {J2K_MS_PLM, J2K_STATE_MH, j2k_read_plm}, + {J2K_MS_PLT, J2K_STATE_TPH, j2k_read_plt}, + {J2K_MS_PPM, J2K_STATE_MH, j2k_read_ppm}, + {J2K_MS_PPT, J2K_STATE_TPH, j2k_read_ppt}, + {J2K_MS_SOP, 0, 0}, + {J2K_MS_CRG, J2K_STATE_MH, j2k_read_crg}, + {J2K_MS_COM, J2K_STATE_MH|J2K_STATE_TPH, j2k_read_com}, + {0, J2K_STATE_MH|J2K_STATE_TPH, j2k_read_unk} +}; + +j2k_dec_mstabent_t *j2k_dec_mstab_lookup(int id) { + j2k_dec_mstabent_t *e; + for (e = j2k_dec_mstab; e->id != 0; e++) { + if (e->id == id) { + break; + } + } + return e; +} + +int j2k_decode(unsigned char *src, int len, j2k_image_t **image, j2k_cp_t **cp) { + if (setjmp(j2k_error)) { + if (j2k_state != J2K_STATE_MT) { + fprintf(stderr, "WARNING: incomplete bitstream\n"); + return 0; + } + return cio_numbytes(); + } + j2k_img = (j2k_image_t*)calloc(1, sizeof(j2k_image_t)); + j2k_cp = (j2k_cp_t*)calloc(1, sizeof(j2k_cp_t)); + *image = j2k_img; + *cp = j2k_cp; + j2k_state = J2K_STATE_MHSOC; + cio_init(src, len); + for (;;) { + j2k_dec_mstabent_t *e; + int id = cio_read(2); + if (id >> 8 != 0xff) { + fprintf(stderr, "%.8x: expected a marker instead of %x\n", cio_tell() - 2, id); + return 0; + } + e = j2k_dec_mstab_lookup(id); + if (!(j2k_state & e->states)) { + fprintf(stderr, "%.8x: unexpected marker %x\n", cio_tell() - 2, id); + return 0; + } + if (e->handler) { + (*e->handler)(); + } + } + +} + + +#ifdef _WIN32 +#include + +BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { + switch (ul_reason_for_call) { + case DLL_PROCESS_ATTACH: + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} +#endif /* _WIN32 */ + +int main(int argc, char **argv) +{ + FILE *src; + int totlen; + unsigned char *j2kfile; + j2k_image_t *imgg; + j2k_cp_t *cp; + int version; + + if (argc != 4) + { + fprintf(stderr,"\nUSAGE : ./index_create J2K-file JP2-file version\n\nVersion : 0, 1, 2 or 3\n 0 : [faix] 4-byte and no AUX fields\n 1 : [faix] 8-byte and no AUX fields\n 2 : [faix] 4-byte and AUX fields\n 3 : [faix] 8-byte and AUX fields\n\nReference Document : annex I from JPIP-FCD-version 2 (SC 29 N5727)\n\n"); + return 1; + } + + src=fopen(argv[1], "rb"); + if (!src) { + fprintf(stderr, "Failed to open %s for reading !!\n", argv[1]); + return 1; + } + + /* length of the codestream */ + fseek(src, 0, SEEK_END); + totlen = ftell(src); + fseek(src, 0, SEEK_SET); + + j2kfile = (unsigned char*)malloc(totlen); + fread(j2kfile, 1, totlen, src); + fclose(src); + + img.marker = (info_marker_t*)malloc(32 * sizeof(info_marker_t)); + img.num_marker = 0; + img.num_max_tile_parts = 0; + img.marker_mul.num_COC = 0; + img.marker_mul.CzCOC = START_NB; + img.marker_mul.num_RGN = 0; + img.marker_mul.CzRGN = START_NB; + img.marker_mul.num_QCC = 0; + img.marker_mul.CzQCC = START_NB; + img.marker_mul.num_TLM = 0; + img.marker_mul.CzTLM = START_NB; + img.marker_mul.num_PLM = 0; + img.marker_mul.CzPLM = START_NB; + img.marker_mul.num_PPM = 0; + img.marker_mul.CzPPM = START_NB; + img.marker_mul.num_COM = 0; + img.marker_mul.CzCOM = START_NB; + + /* decode */ + + if (!j2k_decode(j2kfile, totlen, &imgg, &cp)) { + fprintf(stderr, "Index_creator: failed to decode image!\n"); + free(j2kfile); + return 1; + } + free(j2kfile); + + // fseek(src, 0, SEEK_SET); + img.codestream_size = totlen; + sscanf(argv[3], "%d", &version); + if (version > 3) + { + fprintf(stderr,"Error : value of version unauthorized !! Value accepted : 0, 1, 2 or 3 !!\n"); + return 0; + } + + j2k_index_JPIP(argv[2], argv[1], totlen * 2 > 60000 ? totlen * 2 : 60000, version); + + j2k_clean(); + return 0; +} + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/int.c b/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/int.c new file mode 100644 index 0000000..29f778c --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/int.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2001-2002, David Janssens + * Copyright (c) 2003, Yannick Verschueren + * Copyright (c) 2003, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/// +/// Get the minimum of two integers. +/// +int int_min(int a, int b) { + return a +/// Get the maximum of two integers. +/// +int int_max(int a, int b) { + return a>b?a:b; +} + +/// +/// Clamp an integer inside an interval. +/// +int int_clamp(int a, int min, int max) { + if (amax) return max; + return a; +} + +/// +/// Get absolute value of integer. +/// +int int_abs(int a) { + return a<0?-a:a; +} + +/// +/// Divide an integer and round upwards. +/// +int int_ceildiv(int a, int b) { + return (a+b-1)/b; +} + +/// +/// Divide an integer by a power of 2 and round upwards. +/// +int int_ceildivpow2(int a, int b) { + return (a+(1<>b; +} + +/// +/// Divide an integer by a power of 2 and round downwards. +/// +int int_floordivpow2(int a, int b) { + return a>>b; +} + +/// +/// Get logarithm of an integer and round downwards. +/// +int int_floorlog2(int a) { + int l; + for (l=0; a>1; l++) { + a>>=1; + } + return l; +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/int.h b/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/int.h new file mode 100644 index 0000000..4921ff4 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/int.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2001-2002, David Janssens + * Copyright (c) 2003, Yannick Verschueren + * Copyright (c) 2003, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __INT_H +#define __INT_H + +int int_min(int a, int b); +int int_max(int a, int b); +int int_clamp(int a, int min, int max); +int int_abs(int a); +int int_ceildiv(int a, int b); +int int_ceildivpow2(int a, int b); +int int_floordivpow2(int a, int b); +int int_floorlog2(int a); + +#endif diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/j2k.h b/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/j2k.h new file mode 100644 index 0000000..6c9a3c6 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/j2k.h @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2001-2002, David Janssens + * Copyright (c) 2003-2004, Yannick Verschueren + * Copyright (c) 2003-2004, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define VERSION "0.0.8" + +#ifdef _WIN32 +#ifdef LIBJ2K_EXPORTS +#define LIBJ2K_API __declspec(dllexport) +#else +#define LIBJ2K_API __declspec(dllimport) +#endif +#else +#define LIBJ2K_API +#endif + +#ifndef __J2K_H +#define __J2K_H + +#define J2K_MAXRLVLS 33 +#define J2K_MAXBANDS (3*J2K_MAXRLVLS+1) + +#define J2K_CP_CSTY_PRT 0x01 +#define J2K_CP_CSTY_SOP 0x02 +#define J2K_CP_CSTY_EPH 0x04 +#define J2K_CCP_CSTY_PRT 0x01 +#define J2K_CCP_CBLKSTY_LAZY 0x01 +#define J2K_CCP_CBLKSTY_RESET 0x02 +#define J2K_CCP_CBLKSTY_TERMALL 0x04 +#define J2K_CCP_CBLKSTY_VSC 0x08 +#define J2K_CCP_CBLKSTY_PTERM 0x10 +#define J2K_CCP_CBLKSTY_SEGSYM 0x20 +#define J2K_CCP_QNTSTY_NOQNT 0 +#define J2K_CCP_QNTSTY_SIQNT 1 +#define J2K_CCP_QNTSTY_SEQNT 2 + +typedef struct +{ + int dx, dy; /* XRsiz, YRsiz */ + int prec; /* precision */ + int bpp; /* deapth of image in bits */ + int sgnd; /* signed */ + int *data; /* image-component data */ +} j2k_comp_t; + +typedef struct { + int version; + int x0, y0; /* XOsiz, YOsiz */ + int x1, y1; /* Xsiz, Ysiz */ + int numcomps; /* number of components */ + int index_on; /* 0 = no index || 1 = index */ + j2k_comp_t *comps; /* image-components */ +} j2k_image_t; + +typedef struct { + int expn; /* exponent */ + int mant; /* mantissa */ +} j2k_stepsize_t; + +typedef struct { + int csty; /* coding style */ + int numresolutions; /* number of resolutions */ + int cblkw; /* width of code-blocks */ + int cblkh; /* height of code-blocks */ + int cblksty; /* code-block coding style */ + int qmfbid; /* discrete wavelet transform identifier */ + int qntsty; /* quantisation style */ + j2k_stepsize_t stepsizes[J2K_MAXBANDS]; /* stepsizes used for quantisation */ + int numgbits; /* number of guard bits */ + int roishift; /* Region of Interest shift */ + int prcw[J2K_MAXRLVLS]; /* Precinct width */ + int prch[J2K_MAXRLVLS]; /* Precinct height */ +} j2k_tccp_t; + +typedef struct { + int resno0, compno0; + int layno1, resno1, compno1; + int prg; + int tile; + char progorder[4]; +} j2k_poc_t; + +typedef struct { + int csty; /* coding style */ + int prg; /* progression order */ + int numlayers; /* number of layers */ + int mct; /* multi-component transform identifier */ + int rates[100]; /* rates of layers */ + int numpocs; /* number of progression order changes */ + int POC; /* Precise if a POC marker has been used O:NO, 1:YES */ + j2k_poc_t pocs[32]; /* progression order changes */ + unsigned char *ppt_data; /* packet header store there for futur use in t2_decode_packet */ + int ppt; /* If ppt == 1 --> there was a PPT marker for the present tile */ + int ppt_store; /* Use in case of multiple marker PPT (number of info already store) */ + j2k_tccp_t *tccps; /* tile-component coding parameters */ +} j2k_tcp_t; + +typedef struct { + int tx0, ty0; /* XTOsiz, YTOsiz */ + int tdx, tdy; /* XTsiz, YTsiz */ + int tw, th; + unsigned char *ppm_data; /* packet header store there for futur use in t2_decode_packet */ + int ppm; /* If ppm == 1 --> there was a PPM marker for the present tile */ + int ppm_store; /* Use in case of multiple marker PPM (number of info already store) */ + int ppm_previous; /* Use in case of multiple marker PPM (case on non-finished previous info) */ + j2k_tcp_t *tcps; /* tile coding parameters */ +} j2k_cp_t; + + + + + +/* Packet information : Layer level */ +typedef struct { + int len; /* Length of the body of the packet */ + int len_header; /* Length of the header of the packet */ + int offset; /* Offset of the body of the packet */ + int offset_header; /* Offset of the header of the packet */ +} info_layer_t; + + +/* Access to packet information : precinct level */ +typedef struct { + info_layer_t *layer; +} info_prec_t; + + +/* Access to packet information : resolution level */ +typedef struct { + info_prec_t *prec; +} info_reso_t; + + +/* Access to packet information : component level */ +typedef struct { + info_reso_t *reso; +} info_compo_t; + + +/* Information about the marker */ +typedef struct { + int type; /* type of marker [SIZ, QCD, POC, PPM, CRG, COD] appearing only once */ + int start_pos; /* Start position of the marker */ + int len; /* Length of the marker */ +} info_marker_t; + + +/* Multiple marker in tile header */ +typedef struct{ + info_marker_t *COC; /* COC markers */ + int num_COC; /* Number of COC marker */ + int CzCOC; /* Current size of the vector COC */ + + info_marker_t *RGN; /* RGN markers */ + int num_RGN; /* Number of RGN marker */ + int CzRGN; /* Current size of the vector RGN */ + + info_marker_t *QCC; /* QCC markers */ + int num_QCC; /* Number of QCC marker */ + int CzQCC; /* Current size of the vector QCC */ + + info_marker_t *PLT; /* PLT markers */ + int num_PLT; /* Number of PLT marker */ + int CzPLT; /* Current size of the vector PLT */ + + info_marker_t *PPT; /* PPT markers */ + int num_PPT; /* Number of PPT marker */ + int CzPPT; /* Current size of the vector PPT */ + + info_marker_t *COM; /* COM markers */ + int num_COM; /* Number of COM marker */ + int CzCOM; /* Current size of the vector COC */ +} info_marker_mul_tile_t; + + +/* Information about each tile_part for a particulary tile */ +typedef struct{ + int start_pos; /* Start position of the tile_part */ + int length; /* Length of the tile_part header + body */ + int length_header; /* Length of the header */ + int end_pos; /* End position of the tile part */ + int end_header; /* End position of the tile part header */ + + int num_reso_AUX; /* Number of resolution level completed */ +} info_tile_part_t; + + +/* Information about each tile */ +typedef struct { + int num_tile; /* Number of Tile */ + int pw, ph; /* number of precinct by tile */ + int num_packet; /* number of packet in the tile */ + info_compo_t *compo; /* component [packet] */ + + info_marker_t *marker; /* information concerning markers inside image [only one apparition] */ + info_marker_mul_tile_t marker_mul; /* information concerning markers inside image [multiple apparition] */ + int num_marker; /* number of marker */ + + int numparts; /* number of tile_part for this tile */ + info_tile_part_t *tile_parts; /* Information about each tile_part */ + int Cztile_parts; /* Current size of the tile_parts vector */ +} info_tile_t; /* index struct */ + + +/* Multiple marker in main header */ +typedef struct{ + info_marker_t *COC; /* COC markers */ + int num_COC; /* Number of COC marker */ + int CzCOC; /* Current size of the vector COC */ + + info_marker_t *RGN; /* RGN markers */ + int num_RGN; /* Number of RGN marker */ + int CzRGN; /* Current size of the vector RGN */ + + info_marker_t *QCC; /* QCC markers */ + int num_QCC; /* Number of QCC marker */ + int CzQCC; /* Current size of the vector QCC */ + + info_marker_t *TLM; /* TLM markers */ + int num_TLM; /* Number of TLM marker */ + int CzTLM; /* Current size of the vector TLM */ + + info_marker_t *PLM; /* PLM markers */ + int num_PLM; /* Number of PLM marker */ + int CzPLM; /* Current size of the vector PLM */ + + info_marker_t *PPM; /* PPM markers */ + int num_PPM; /* Number of PPM marker */ + int CzPPM; /* Current size of the vector PPM */ + + info_marker_t *COM; /* COM markers */ + int num_COM; /* Number of COM marker */ + int CzCOM; /* Current size of the vector COM */ +} info_marker_mul_t; /* index struct */ + + +/* Information about image */ +typedef struct { + int Im_w, Im_h; /* Image width and Height */ + int Tile_x, Tile_y; /* Number of Tile in X and Y */ + int tw, th; + int pw, ph; /* nombre precinct in X and Y */ + int pdx, pdy; /* size of precinct in X and Y */ + + int Prog; /* progression order */ + int Comp; /* Component numbers */ + int Layer; /* number of layer */ + int Decomposition; /* number of decomposition */ + + int Main_head_end; /* Main header position */ + int codestream_size; /* codestream's size */ + + info_marker_t *marker; /* information concerning markers inside image [only one apparition] */ + info_marker_mul_t marker_mul; /* information concerning markers inside image [multiple apparition] */ + int num_marker; /* number of marker */ + + int num_packet_max; /* Maximum number of packet */ + + int num_max_tile_parts; /* Maximum number of tile-part */ + info_tile_t *tile; /* information concerning tiles inside image */ +} info_image_t; /* index struct */ + + +#endif diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/jp2.c b/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/jp2.c new file mode 100644 index 0000000..ff2d22e --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/jp2.c @@ -0,0 +1,302 @@ +/* + * Copyright (c) 2003-2004, Yannick Verschueren + * Copyright (c) 2003-2004, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + +#include "j2k.h" +#include "cio.h" +#include "tcd.h" +#include "int.h" + +#define JPIP_JPIP 0x6a706970 + +#define JP2_JP 0x6a502020 +#define JP2_FTYP 0x66747970 +#define JP2_JP2H 0x6a703268 +#define JP2_IHDR 0x69686472 +#define JP2_COLR 0x636f6c72 +#define JP2_JP2C 0x6a703263 +#define JP2_URL 0x75726c20 +#define JP2_DBTL 0x6474626c +#define JP2_BPCC 0x62706363 +#define JP2 0x6a703220 + + +void jp2_write_url(char *Idx_file) +{ + int len, lenp; + unsigned int i; + char str[256]; + + sprintf(str, "%s", Idx_file); + lenp=cio_tell(); + cio_skip(4); + cio_write(JP2_URL, 4); // DBTL + cio_write(0,1); // VERS + cio_write(0,3); // FLAG + + for (i=0; iy1-j2k_img->x0,4); // HEIGHT + cio_write(j2k_img->x1-j2k_img->x0,4); // WIDTH + cio_write(j2k_img->numcomps,2); // NC + + depth_0=j2k_img->comps[0].prec-1; + sign=j2k_img->comps[0].sgnd; + + for(i=1;inumcomps;i++) + { + depth=j2k_img->comps[i].prec-1; + sign=j2k_img->comps[i].sgnd; + if(depth_0!=depth) BPC_ok=0; + } + + if (BPC_ok) + cio_write(depth_0+(sign<<7),1); + else + cio_write(255,1); + + cio_write(7,1); // C : Always 7 + cio_write(1,1); // UnkC, colorspace unknow + cio_write(0,1); // IPR, no intellectual property + + len=cio_tell()-lenp; + cio_seek(lenp); + cio_write(len,4); // L + cio_seek(lenp+len); + + return BPC_ok; +} + +void jp2_write_bpcc(j2k_image_t *j2k_img) +{ + int len, lenp, i; + + lenp=cio_tell(); + cio_skip(4); + cio_write(JP2_BPCC, 4); // BPCC + + for(i=0;inumcomps;i++) + cio_write(j2k_img->comps[i].prec-1+(j2k_img->comps[i].sgnd<<7),1); + + len=cio_tell()-lenp; + cio_seek(lenp); + cio_write(len,4); // L + cio_seek(lenp+len); +} + +void jp2_write_colr(int BPC_ok, j2k_image_t *j2k_img) +{ + int len, lenp, meth; + + lenp=cio_tell(); + cio_skip(4); + cio_write(JP2_COLR, 4); // COLR + + if ((j2k_img->numcomps==1 || j2k_img->numcomps==3) && (BPC_ok && j2k_img->comps[0].prec==8)) + meth=1; + else + meth=2; + + cio_write(meth,1); // METH + cio_write(0,1); // PREC + cio_write(0,1); // APPROX + + if (meth==1) + cio_write(j2k_img->numcomps>1?16:17,4); // EnumCS + + if (meth==2) + cio_write(0,1); // PROFILE (??) + + len=cio_tell()-lenp; + cio_seek(lenp); + cio_write(len,4); // L + cio_seek(lenp+len); +} + +/* + * Write the JP2H box + * + * JP2 Header box + * + */ +void jp2_write_jp2h(j2k_image_t *j2k_img) +{ + int len, lenp, BPC_ok; + + lenp=cio_tell(); + cio_skip(4); + cio_write(JP2_JP2H, 4); /* JP2H */ + + BPC_ok=jp2_write_ihdr(j2k_img); + + if (!BPC_ok) + jp2_write_bpcc(j2k_img); + jp2_write_colr(BPC_ok, j2k_img); + + len=cio_tell()-lenp; + cio_seek(lenp); + cio_write(len,4); /* L */ + cio_seek(lenp+len); +} + +/* + * Write the FTYP box + * + * File type box + * + */ +void jp2_write_ftyp() +{ + int len, lenp; + + lenp=cio_tell(); + cio_skip(4); + cio_write(JP2_FTYP, 4); /* FTYP */ + + cio_write(JP2,4); /* BR */ + cio_write(0,4); /* MinV */ + cio_write(JP2,4); /* CL0 : JP2 */ + cio_write(JPIP_JPIP,4); /* CL1 : JPIP */ + + len=cio_tell()-lenp; + cio_seek(lenp); + cio_write(len,4); /* L */ + cio_seek(lenp+len); +} + +/* + * Read the FTYP box + * + * File type box + * + */ +void jp2_read_ftyp(int length) +{ + int BR, MinV, type, i; + + BR = cio_read(4); /* BR */ + MinV = cio_read(4); /* MinV */ + length-=8; + + for (i=length/4;i>0;i--) + type = cio_read(4); /* CLi : JP2, JPIP */ +} + +int jp2_write_jp2c(char *J2K_file) +{ + int len, lenp, totlen, i; + FILE *src; + char *j2kfile; + + lenp=cio_tell(); + cio_skip(4); + cio_write(JP2_JP2C, 4); // JP2C + + src=fopen(J2K_file, "rb"); + fseek(src, 0, SEEK_END); + totlen=ftell(src); + fseek(src, 0, SEEK_SET); + + j2kfile=(char*)malloc(totlen); + fread(j2kfile, 1, totlen, src); + fclose(src); + + for (i=0;i +#include +#include +#include +#include + +#include "j2k.h" +#include "cio.h" +#include "tcd.h" +#include "int.h" + +#define JPIP_CIDX 0x63696478 /* Codestream index */ +#define JPIP_CPTR 0x63707472 /* Codestream Finder Box */ +#define JPIP_MANF 0x6d616e66 /* Manifest Box */ +#define JPIP_FAIX 0x66616978 /* Fragment array Index box */ +#define JPIP_MHIX 0x6d686978 /* Main Header Index Table */ +#define JPIP_TPIX 0x74706978 /* Tile-part Index Table box */ +#define JPIP_THIX 0x74686978 /* Tile header Index Table box */ +#define JPIP_PPIX 0x70706978 /* Precinct Packet Index Table box */ +#define JPIP_PHIX 0x70686978 /* Packet Header index Table */ +#define JPIP_FIDX 0x66696478 /* File Index */ +#define JPIP_FPTR 0x66707472 /* File Finder */ +#define JPIP_PRXY 0x70727879 /* Proxy boxes */ +#define JPIP_IPTR 0x69707472 /* Index finder box */ +#define JPIP_PHLD 0x70686c64 /* Place holder */ + +#define JP2C 0x6a703263 + +//static info_marker_t marker_jpip[32], marker_local_jpip[32]; /* SIZE to precise ! */ +//static int num_marker_jpip, num_marker_local_jpip; + +/* + * Write the CPTR box + * + * Codestream finder box (box) + * + */ +void jpip_write_cptr(int offset, info_image_t img) +{ + int len, lenp; + + lenp=cio_tell(); + cio_skip(4); /* L [at the end] */ + cio_write(JPIP_CPTR,4); /* T */ + cio_write(0,2); /* DR A PRECISER !! */ + cio_write(0,2); /* CONT */ + cio_write(offset,8); /* COFF A PRECISER !! */ + cio_write(img.codestream_size,8); /* CLEN */ + len=cio_tell()-lenp; + cio_seek(lenp); + cio_write(len, 4); /* L */ + cio_seek(lenp+len); +} + +/* + * Read the CPTR box + * + * Codestream finder box (box) + * + */ +void jpip_read_cptr() +{ + int DR, CONT; + long long Coff, codestream_size; + + DR = cio_read(2); /* DR */ + CONT = cio_read(2); /* CONT */ + Coff = cio_read(8); /* COFF */ + codestream_size = cio_read(8); /* CLEN */ +} + +/* + * Write the MANF box + * + * Manifest box (box) + * + */ +void jpip_write_manf(int second, int v, info_marker_t *marker) +{ + int len, lenp, i; + lenp=cio_tell(); + cio_skip(4); /* L [at the end] */ + cio_write(JPIP_MANF,4); /* T */ + + if (second) /* Write only during the second pass */ + { + for(i=0;i= 0; i--) /* COC */ + { + cio_write(img.marker_mul.COC[i].type, 2); + cio_write(i, 2); + cio_write(img.marker_mul.COC[i].start_pos, 8); + cio_write(img.marker_mul.COC[i].len, 2); + } + + for(i = img.marker_mul.num_RGN - 1; i >= 0; i--) /* RGN */ + { + cio_write(img.marker_mul.RGN[i].type, 2); + cio_write(i, 2); + cio_write(img.marker_mul.RGN[i].start_pos, 8); + cio_write(img.marker_mul.RGN[i].len, 2); + } + + for(i = img.marker_mul.num_QCC - 1; i >= 0; i--) /* QCC */ + { + cio_write(img.marker_mul.QCC[i].type, 2); + cio_write(i, 2); + cio_write(img.marker_mul.QCC[i].start_pos, 8); + cio_write(img.marker_mul.QCC[i].len, 2); + } + + for(i = img.marker_mul.num_TLM - 1; i >= 0; i--) /* TLM */ + { + cio_write(img.marker_mul.TLM[i].type, 2); + cio_write(i, 2); + cio_write(img.marker_mul.TLM[i].start_pos, 8); + cio_write(img.marker_mul.TLM[i].len, 2); + } + + for(i = img.marker_mul.num_PLM - 1; i >= 0; i--) /* PLM */ + { + cio_write(img.marker_mul.PLM[i].type, 2); + cio_write(i, 2); + cio_write(img.marker_mul.PLM[i].start_pos, 8); + cio_write(img.marker_mul.PLM[i].len, 2); + } + + for(i = img.marker_mul.num_PPM - 1; i >= 0; i--) /* PPM */ + { + cio_write(img.marker_mul.PPM[i].type, 2); + cio_write(i, 2); + cio_write(img.marker_mul.PPM[i].start_pos, 8); + cio_write(img.marker_mul.PPM[i].len, 2); + } + + for(i = img.marker_mul.num_COM - 1; i >= 0; i--) /* COM */ + { + cio_write(img.marker_mul.COM[i].type, 2); + cio_write(i, 2); + cio_write(img.marker_mul.COM[i].start_pos, 8); + cio_write(img.marker_mul.COM[i].len, 2); + } + } + else /* TILE HEADER */ + { + tile = &img.tile[tileno]; + cio_write(tile->tile_parts[0].length_header, 8); /* TLEN */ + + for(i = 0; i < tile->num_marker; i++) /* Marker restricted to 1 apparition */ + { + cio_write(tile->marker[i].type, 2); + cio_write(0, 2); + cio_write(tile->marker[i].start_pos, 8); + cio_write(tile->marker[i].len, 2); + } + + /* Marker NOT restricted to 1 apparition */ + for(i = tile->marker_mul.num_COC - 1; i >= 0; i--) /* COC */ + { + cio_write(tile->marker_mul.COC[i].type, 2); + cio_write(i, 2); + cio_write(tile->marker_mul.COC[i].start_pos, 8); + cio_write(tile->marker_mul.COC[i].len, 2); + } + + for(i = tile->marker_mul.num_RGN - 1; i >= 0; i--) /* RGN */ + { + cio_write(tile->marker_mul.RGN[i].type, 2); + cio_write(i, 2); + cio_write(tile->marker_mul.RGN[i].start_pos, 8); + cio_write(tile->marker_mul.RGN[i].len, 2); + } + + for(i = tile->marker_mul.num_QCC - 1; i >= 0; i--) /* QCC */ + { + cio_write(tile->marker_mul.QCC[i].type, 2); + cio_write(i, 2); + cio_write(tile->marker_mul.QCC[i].start_pos, 8); + cio_write(tile->marker_mul.QCC[i].len, 2); + } + + for(i = tile->marker_mul.num_PLT - 1; i >= 0; i--) /* PLT */ + { + cio_write(tile->marker_mul.PLT[i].type,2); + cio_write(i,2); + cio_write(tile->marker_mul.PLT[i].start_pos,8); + cio_write(tile->marker_mul.PLT[i].len,2); + } + + for(i = tile->marker_mul.num_PPT - 1; i >= 0; i--) /* PPT */ + { + cio_write(tile->marker_mul.PPT[i].type, 2); + cio_write(i, 2); + cio_write(tile->marker_mul.PPT[i].start_pos, 8); + cio_write(tile->marker_mul.PPT[i].len, 2); + } + + for(i = tile->marker_mul.num_COM - 1; i >= 0; i--) /* COM */ + { + cio_write(tile->marker_mul.COM[i].type, 2); + cio_write(i, 2); + cio_write(tile->marker_mul.COM[i].start_pos, 8); + cio_write(tile->marker_mul.COM[i].len, 2); + } + } + + len=cio_tell()-lenp; + cio_seek(lenp); + cio_write(len, 4); /* L */ + cio_seek(lenp+len); + + return len; +} + +/* + * Read the MHIX box + * + * Main Header Index Table (box) + * + */ +void jpip_read_mhix(int len) +{ + int i, v, marker_type, marker_start_pos, marker_len, marker_remains; + + v = (len - 8) / 14; + + for (i=0; icompo[compno]; + int correction; + + num_packet=0; + + if(j2k_cp->tcps[tileno].csty&J2K_CP_CSTY_EPH) + correction=3; + else + correction=1; + for(resno=0;resnoreso[resno]; + for (precno=0;precnoprec[precno]; + for(layno=0;laynolayer[layno]; + cio_write(layer_Idx->offset,(version & 0x01)?8:4); /* start position */ + cio_write((layer_Idx->len_header-correction)?0:layer_Idx->len,(version & 0x01)?8:4); /* length */ + if (version & 0x02) + cio_write(0,4); /* Aux_i,j : Auxiliary value */ + num_packet++; + } + } + } + /* PADDING */ + while (num_packet < img.num_packet_max) + { + cio_write(0,(version & 0x01)?8:4); /* start position */ + cio_write(0,(version & 0x01)?8:4); /* length */ + if (version & 0x02) + cio_write(0,4); /* Aux_i,j : Auxiliary value */ + num_packet++; + } + } + + break; + + case 3: /* PHIX NOT FINISHED !! */ + cio_write(img.num_packet_max,(version & 0x01)?8:4); /* NMAX */ + cio_write(img.tw*img.th,(version & 0x01)?8:4); /* M */ + for(tileno=0;tilenocompo[compno]; + int correction; + + num_packet = 0; + if(j2k_cp->tcps[tileno].csty&J2K_CP_CSTY_EPH) + correction=3; + else + correction=1; + for(resno=0;resnoreso[resno]; + for (precno=0;precnoprec[precno]; + for(layno=0;laynolayer[layno]; + cio_write(layer_Idx->offset_header,(version & 0x01)?8:4); /* start position */ + cio_write((layer_Idx->len_header-correction)?0:layer_Idx->len_header,(version & 0x01)?8:4); /* length */ + if (version & 0x02) + cio_write(0,4); /* Aux_i,j : Auxiliary value */ + num_packet++; + } + } + } + /* PADDING */ + while (num_packettw*j2k_cp->th); + + for ( i = 0; i < 2 ; i++ ) + { + if (i) cio_seek(lenp); + + lenp = cio_tell(); + cio_skip(4); /* L [at the end] */ + cio_write(JPIP_THIX, 4); /* THIX */ + jpip_write_manf(i, j2k_cp->tw*j2k_cp->th, marker); + num_marker_local_jpip=img.Comp; + + for (tileno = 0; tileno < j2k_cp->tw*j2k_cp->th; tileno++) + { + marker[tileno].len = jpip_write_mhix(img, 1, tileno); + marker[tileno].type = JPIP_MHIX; + } + + len=cio_tell()-lenp; + cio_seek(lenp); + cio_write(len, 4); /* L */ + cio_seek(lenp+len); + } + + free(marker); + + return len; +} +/* + * Write the PPIX box + * + * Precinct Packet Index table box (superbox) + * + */ +int jpip_write_ppix(info_image_t img,j2k_cp_t *j2k_cp) +{ + int len, lenp, compno, i; + info_marker_t *marker; + int num_marker_local_jpip; + marker = (info_marker_t*)calloc(sizeof(info_marker_t), img.Comp); + + for (i=0;i<2;i++) + { + if (i) cio_seek(lenp); + + lenp=cio_tell(); + cio_skip(4); /* L [at the end] */ + cio_write(JPIP_PPIX, 4); /* PPIX */ + jpip_write_manf(i,img.Comp,marker); + num_marker_local_jpip=img.Comp; + + for (compno=0; compno +#include + + +/* */ +/* Create a packet iterator. */ +/* */ +pi_iterator_t *pi_create(j2k_image_t * img, j2k_cp_t * cp, int tileno) +{ + int p, q; + int compno, resno, pino; + int maxres = 0; + pi_iterator_t *pi; + j2k_tcp_t *tcp; + j2k_tccp_t *tccp; + + tcp = &cp->tcps[tileno]; + pi = (pi_iterator_t *) malloc((tcp->numpocs + 1) * sizeof(pi_iterator_t)); + + for (pino = 0; pino < tcp->numpocs + 1; pino++) { /* change */ + p = tileno % cp->tw; + q = tileno / cp->tw; + + pi[pino].tx0 = int_max(cp->tx0 + p * cp->tdx, img->x0); + pi[pino].ty0 = int_max(cp->ty0 + q * cp->tdy, img->y0); + pi[pino].tx1 = int_min(cp->tx0 + (p + 1) * cp->tdx, img->x1); + pi[pino].ty1 = int_min(cp->ty0 + (q + 1) * cp->tdy, img->y1); + pi[pino].numcomps = img->numcomps; + pi[pino].comps = (pi_comp_t *) malloc(img->numcomps * sizeof(pi_comp_t)); + + for (compno = 0; compno < pi->numcomps; compno++) { + int tcx0, tcy0, tcx1, tcy1; + pi_comp_t *comp = &pi[pino].comps[compno]; + tccp = &tcp->tccps[compno]; + comp->dx = img->comps[compno].dx; + comp->dy = img->comps[compno].dy; + comp->numresolutions = tccp->numresolutions; + comp->resolutions = + (pi_resolution_t *) malloc(comp->numresolutions * + sizeof(pi_resolution_t)); + tcx0 = int_ceildiv(pi->tx0, comp->dx); + tcy0 = int_ceildiv(pi->ty0, comp->dy); + tcx1 = int_ceildiv(pi->tx1, comp->dx); + tcy1 = int_ceildiv(pi->ty1, comp->dy); + if (comp->numresolutions > maxres) { + maxres = comp->numresolutions; + } + for (resno = 0; resno < comp->numresolutions; resno++) { + int levelno; + int rx0, ry0, rx1, ry1; + int px0, py0, px1, py1; + pi_resolution_t *res = &comp->resolutions[resno]; + if (tccp->csty & J2K_CCP_CSTY_PRT) { + res->pdx = tccp->prcw[resno]; + res->pdy = tccp->prch[resno]; + } else { + res->pdx = 15; + res->pdy = 15; + } + levelno = comp->numresolutions - 1 - resno; + rx0 = int_ceildivpow2(tcx0, levelno); + ry0 = int_ceildivpow2(tcy0, levelno); + rx1 = int_ceildivpow2(tcx1, levelno); + ry1 = int_ceildivpow2(tcy1, levelno); + px0 = int_floordivpow2(rx0, res->pdx) << res->pdx; + py0 = int_floordivpow2(ry0, res->pdy) << res->pdy; + px1 = int_ceildivpow2(rx1, res->pdx) << res->pdx; + py1 = int_ceildivpow2(ry1, res->pdy) << res->pdy; + res->pw = (px1 - px0) >> res->pdx; + res->ph = (py1 - py0) >> res->pdy; + } + } + + tccp = &tcp->tccps[0]; + pi[pino].step_p=1; + pi[pino].step_c=100*pi[pino].step_p; + pi[pino].step_r=img->numcomps*pi[pino].step_c; + pi[pino].step_l=maxres*pi[pino].step_r; + + if (pino==0) + pi[pino].include=(short int*)calloc(img->numcomps*maxres*tcp->numlayers*100,sizeof(short int)); + else + pi[pino].include=pi[pino-1].include; + + /*if (pino == tcp->numpocs) {*/ + if (tcp->POC == 0) { + pi[pino].first = 1; + pi[pino].poc.resno0 = 0; + pi[pino].poc.compno0 = 0; + pi[pino].poc.layno1 = tcp->numlayers; + pi[pino].poc.resno1 = maxres; + pi[pino].poc.compno1 = img->numcomps; + pi[pino].poc.prg = tcp->prg; + } else { + pi[pino].first = 1; + pi[pino].poc.resno0 = tcp->pocs[pino].resno0; + pi[pino].poc.compno0 = tcp->pocs[pino].compno0; + pi[pino].poc.layno1 = tcp->pocs[pino].layno1; + pi[pino].poc.resno1 = tcp->pocs[pino].resno1; + pi[pino].poc.compno1 = tcp->pocs[pino].compno1; + pi[pino].poc.prg = tcp->pocs[pino].prg; + } + } + return pi; +} + +/* */ +/* Get next packet in layer=resolution-component-precinct order. */ +/* */ +int pi_next_lrcp(pi_iterator_t * pi) +{ + pi_comp_t *comp; + pi_resolution_t *res; + + if (!pi->first) { + comp = &pi->comps[pi->compno]; + res = &comp->resolutions[pi->resno]; + goto skip; + } else { + pi->first = 0; + } + for (pi->layno = 0; pi->layno < pi->poc.layno1; pi->layno++) { + for (pi->resno = pi->poc.resno0; pi->resno < pi->poc.resno1; + pi->resno++) { + for (pi->compno = pi->poc.compno0; pi->compno < pi->poc.compno1; + pi->compno++) { + comp = &pi->comps[pi->compno]; + if (pi->resno >= comp->numresolutions) { + + continue; + } + res = &comp->resolutions[pi->resno]; + for (pi->precno = 0; pi->precno < res->pw * res->ph; pi->precno++) { + if (!pi->include[pi->layno * pi->step_l + pi->resno * pi->step_r + pi->compno * pi->step_c + pi->precno * pi->step_p]){ + pi->include[pi->layno * pi->step_l + pi->resno * pi->step_r + pi->compno * pi->step_c + pi->precno * pi->step_p] = 1; + return 1; + } + skip:; + } + } + } + } + return 0; +} + +/* */ +/* Get next packet in resolution-layer-component-precinct order. */ +/* */ +int pi_next_rlcp(pi_iterator_t * pi) +{ + pi_comp_t *comp; + pi_resolution_t *res; + if (!pi->first) { + comp = &pi->comps[pi->compno]; + res = &comp->resolutions[pi->resno]; + goto skip; + } else { + pi->first = 0; + } + for (pi->resno = pi->poc.resno0; pi->resno < pi->poc.resno1; pi->resno++) { + for (pi->layno = 0; pi->layno < pi->poc.layno1; pi->layno++) { + for (pi->compno = pi->poc.compno0; pi->compno < pi->poc.compno1; + pi->compno++) { + comp = &pi->comps[pi->compno]; + if (pi->resno >= comp->numresolutions) { + continue; + } + res = &comp->resolutions[pi->resno]; + for (pi->precno = 0; pi->precno < res->pw * res->ph; pi->precno++) { + if (!pi->include[pi->layno*pi->step_l+pi->resno*pi->step_r+pi->compno*pi->step_c+pi->precno*pi->step_p]){ + pi->include[pi->layno*pi->step_l+pi->resno*pi->step_r+pi->compno*pi->step_c+pi->precno*pi->step_p] = 1; + return 1; + } + skip:; + } + } + } + } + return 0; +} + +/* */ +/* Get next packet in resolution-precinct-component-layer order. */ +/* */ +int pi_next_rpcl(pi_iterator_t * pi) +{ + pi_comp_t *comp; + pi_resolution_t *res; + if (!pi->first) { + goto skip; + } else { + int compno, resno; + pi->first = 0; + pi->dx = 0; + pi->dy = 0; + for (compno = 0; compno < pi->numcomps; compno++) { + comp = &pi->comps[compno]; + for (resno = 0; resno < comp->numresolutions; resno++) { + int dx, dy; + res = &comp->resolutions[resno]; + dx = + comp->dx * (1 << (res->pdx + comp->numresolutions - 1 - resno)); + dy = + comp->dy * (1 << (res->pdy + comp->numresolutions - 1 - resno)); + pi->dx = !pi->dx ? dx : int_min(pi->dx, dx); + pi->dy = !pi->dy ? dy : int_min(pi->dy, dy); + } + } + } + for (pi->resno = pi->poc.resno0; pi->resno < pi->poc.resno1; pi->resno++) { + for (pi->y = pi->ty0; pi->y < pi->ty1; + pi->y += pi->dy - (pi->y % pi->dy)) { + for (pi->x = pi->tx0; pi->x < pi->tx1; + pi->x += pi->dx - (pi->x % pi->dx)) { + for (pi->compno = pi->poc.compno0; pi->compno < pi->poc.compno1; + pi->compno++) { + int levelno; + int trx0, try0; + int rpx, rpy; + int prci, prcj; + comp = &pi->comps[pi->compno]; + if (pi->resno >= comp->numresolutions) { + continue; + } + res = &comp->resolutions[pi->resno]; + levelno = comp->numresolutions - 1 - pi->resno; + trx0 = int_ceildiv(pi->tx0, comp->dx << levelno); + try0 = int_ceildiv(pi->ty0, comp->dy << levelno); + rpx = res->pdx + levelno; + rpy = res->pdy + levelno; + if (! + (pi->x % (comp->dx << rpx) == 0 + || (pi->x == pi->tx0 && (trx0 << levelno) % (1 << rpx)))) { + continue; + } + if (! + (pi->y % (comp->dy << rpy) == 0 + || (pi->y == pi->ty0 && (try0 << levelno) % (1 << rpx)))) { + continue; + } + prci = + int_floordivpow2(int_ceildiv(pi->x, comp->dx << levelno), + res->pdx) - int_floordivpow2(trx0, res->pdx); + prcj = + int_floordivpow2(int_ceildiv(pi->y, comp->dy << levelno), + res->pdy) - int_floordivpow2(try0, res->pdy); + pi->precno = prci + prcj * res->pw; + for (pi->layno = 0; pi->layno < pi->poc.layno1; pi->layno++) { + if (!pi->include[pi->layno*pi->step_l+pi->resno*pi->step_r+pi->compno*pi->step_c+pi->precno*pi->step_p]){ + pi->include[pi->layno*pi->step_l+pi->resno*pi->step_r+pi->compno*pi->step_c+pi->precno*pi->step_p] = 1; + return 1; + } + skip:; + } + } + } + } + } + return 0; +} + +/* */ +/* Get next packet in precinct-component-resolution-layer order. */ +/* */ +int pi_next_pcrl(pi_iterator_t * pi) +{ + pi_comp_t *comp; + pi_resolution_t *res; + if (!pi->first) { + comp = &pi->comps[pi->compno]; + goto skip; + } else { + int compno, resno; + pi->first = 0; + pi->dx = 0; + pi->dy = 0; + for (compno = 0; compno < pi->numcomps; compno++) { + comp = &pi->comps[compno]; + for (resno = 0; resno < comp->numresolutions; resno++) { + int dx, dy; + res = &comp->resolutions[resno]; + dx = + comp->dx * (1 << (res->pdx + comp->numresolutions - 1 - resno)); + dy = + comp->dy * (1 << (res->pdy + comp->numresolutions - 1 - resno)); + pi->dx = !pi->dx ? dx : int_min(pi->dx, dx); + pi->dy = !pi->dy ? dy : int_min(pi->dy, dy); + } + } + } + for (pi->y = pi->ty0; pi->y < pi->ty1; + pi->y += pi->dy - (pi->y % pi->dy)) { + for (pi->x = pi->tx0; pi->x < pi->tx1; + pi->x += pi->dx - (pi->x % pi->dx)) { + for (pi->compno = pi->poc.compno0; pi->compno < pi->poc.compno1; + pi->compno++) { + comp = &pi->comps[pi->compno]; + for (pi->resno = pi->poc.resno0; + pi->resno < int_min(pi->poc.resno1, comp->numresolutions); + pi->resno++) { + int levelno; + int trx0, try0; + int rpx, rpy; + int prci, prcj; + res = &comp->resolutions[pi->resno]; + levelno = comp->numresolutions - 1 - pi->resno; + trx0 = int_ceildiv(pi->tx0, comp->dx << levelno); + try0 = int_ceildiv(pi->ty0, comp->dy << levelno); + rpx = res->pdx + levelno; + rpy = res->pdy + levelno; + if (! + (pi->x % (comp->dx << rpx) == 0 + || (pi->x == pi->tx0 && (trx0 << levelno) % (1 << rpx)))) { + continue; + } + if (! + (pi->y % (comp->dy << rpy) == 0 + || (pi->y == pi->ty0 && (try0 << levelno) % (1 << rpx)))) { + continue; + } + prci = + int_floordivpow2(int_ceildiv(pi->x, comp->dx << levelno), + res->pdx) - int_floordivpow2(trx0, res->pdx); + prcj = + int_floordivpow2(int_ceildiv(pi->y, comp->dy << levelno), + res->pdy) - int_floordivpow2(try0, res->pdy); + pi->precno = prci + prcj * res->pw; + for (pi->layno = 0; pi->layno < pi->poc.layno1; pi->layno++) { + if (! pi->include[pi->layno*pi->step_l+pi->resno*pi->step_r+pi->compno*pi->step_c+pi->precno*pi->step_p]){ + pi->include[pi->layno*pi->step_l+pi->resno*pi->step_r+pi->compno*pi->step_c+pi->precno*pi->step_p] = 1; + return 1; + } + skip:; + } + } + } + } + } + return 0; +} + +/* */ +/* Get next packet in component-precinct-resolution-layer order. */ +/* */ +int pi_next_cprl(pi_iterator_t * pi) +{ + pi_comp_t *comp; + pi_resolution_t *res; + if (!pi->first) { + comp = &pi->comps[pi->compno]; + goto skip; + } else { + pi->first = 0; + } + for (pi->compno = pi->poc.compno0; pi->compno < pi->poc.compno1; + pi->compno++) { + int resno; + comp = &pi->comps[pi->compno]; + pi->dx = 0; + pi->dy = 0; + for (resno = 0; resno < comp->numresolutions; resno++) { + int dx, dy; + res = &comp->resolutions[resno]; + dx = comp->dx * (1 << (res->pdx + comp->numresolutions - 1 - resno)); + dy = comp->dy * (1 << (res->pdy + comp->numresolutions - 1 - resno)); + pi->dx = !pi->dx ? dx : int_min(pi->dx, dx); + pi->dy = !pi->dy ? dy : int_min(pi->dy, dy); + } + for (pi->y = pi->ty0; pi->y < pi->ty1; + pi->y += pi->dy - (pi->y % pi->dy)) { + for (pi->x = pi->tx0; pi->x < pi->tx1; + pi->x += pi->dx - (pi->x % pi->dx)) { + for (pi->resno = pi->poc.resno0; + pi->resno < int_min(pi->poc.resno1, comp->numresolutions); + pi->resno++) { + int levelno; + int trx0, try0; + int rpx, rpy; + int prci, prcj; + res = &comp->resolutions[pi->resno]; + levelno = comp->numresolutions - 1 - pi->resno; + trx0 = int_ceildiv(pi->tx0, comp->dx << levelno); + try0 = int_ceildiv(pi->ty0, comp->dy << levelno); + rpx = res->pdx + levelno; + rpy = res->pdy + levelno; + if (! + (pi->x % (comp->dx << rpx) == 0 + || (pi->x == pi->tx0 && (trx0 << levelno) % (1 << rpx)))) { + continue; + } + if (! + (pi->y % (comp->dy << rpy) == 0 + || (pi->y == pi->ty0 && (try0 << levelno) % (1 << rpx)))) { + continue; + } + prci = + int_floordivpow2(int_ceildiv(pi->x, comp->dx << levelno), + res->pdx) - int_floordivpow2(trx0, res->pdx); + prcj = + int_floordivpow2(int_ceildiv(pi->y, comp->dy << levelno), + res->pdy) - int_floordivpow2(try0, res->pdy); + pi->precno = prci + prcj * res->pw; + for (pi->layno = 0; pi->layno < pi->poc.layno1; pi->layno++) { + if (! pi->include[pi->layno*pi->step_l+pi->resno*pi->step_r+pi->compno*pi->step_c+pi->precno*pi->step_p]){ + pi->include[pi->layno*pi->step_l+pi->resno*pi->step_r+pi->compno*pi->step_c+pi->precno*pi->step_p] = 1; + return 1; + } + skip:; + } + } + } + } + } + return 0; +} + +/* */ +/* Get next packet. */ +/* */ +int pi_next(pi_iterator_t * pi) +{ + switch (pi->poc.prg) { + case 0: + return pi_next_lrcp(pi); + case 1: + return pi_next_rlcp(pi); + case 2: + return pi_next_rpcl(pi); + case 3: + return pi_next_pcrl(pi); + case 4: + return pi_next_cprl(pi); + } + return 0; +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/pi.h b/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/pi.h new file mode 100644 index 0000000..b300b9e --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/pi.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2001-2002, David Janssens + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __PI_H +#define __PI_H + +#include "j2k.h" +#include "tcd.h" + +typedef struct { + int pdx, pdy; + int pw, ph; +} pi_resolution_t; + +typedef struct { + int dx, dy; + int numresolutions; + pi_resolution_t *resolutions; +} pi_comp_t; + +typedef struct { + short int *include; + int step_l, step_r, step_c, step_p; + int compno, resno, precno, layno; /* component, resolution, precinct and layer that indentify the packet */ + int first; + j2k_poc_t poc; + int numcomps; + pi_comp_t *comps; + int tx0, ty0, tx1, ty1; + int x, y, dx, dy; +} pi_iterator_t; /* packet iterator */ + +/* + * Create a packet iterator + * img: raw image for which the packets will be listed + * cp: coding paremeters + * tileno: number that identifies the tile for which to list the packets + * return value: returns a packet iterator that points to the first packet of the tile + */ +pi_iterator_t *pi_create(j2k_image_t * img, j2k_cp_t * cp, int tileno); + +/* + * Modify the packet iterator to point to the next packet + * pi: packet iterator to modify + * return value: returns 0 if pi pointed to the last packet or else returns 1 + */ +int pi_next(pi_iterator_t * pi); + +#endif diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/t2.c b/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/t2.c new file mode 100644 index 0000000..14a44be --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/t2.c @@ -0,0 +1,389 @@ +/* + * Copyright (c) 2001-2002, David Janssens + * Copyright (c) 2003, Yannick Verschueren + * Copyright (c) 2003, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "t2.h" +#include "tcd.h" +#include "bio.h" +#include "j2k.h" +#include "pi.h" +#include "tgt.h" +#include "int.h" +#include "cio.h" +#include +#include +#include +#include + +#define RESTART 0x04 + +extern jmp_buf j2k_error; + +int t2_getcommacode() { + int n; + for (n=0; bio_read(1); n++) {} + return n; +} + +int t2_getnumpasses() +{ + int n; + if (!bio_read(1)) return 1; + if (!bio_read(1)) return 2; + if ((n=bio_read(2))!=3) return 3+n; + if ((n=bio_read(5))!=31) return 6+n; + return 37+bio_read(7); +} + +void t2_init_seg(tcd_seg_t *seg, int cblksty) { + seg->numpasses=0; + seg->len=0; + seg->maxpasses=cblksty&J2K_CCP_CBLKSTY_TERMALL?1:100; +} + +int t2_decode_packet(unsigned char *src, int len, tcd_tile_t *tile, j2k_cp_t * cp, j2k_tcp_t *tcp, int compno, int resno, int precno, int layno, info_layer_t *layer_Idx) { + int bandno, cblkno; + tcd_tilecomp_t *tilec = &tile->comps[compno]; + tcd_resolution_t *res = &tilec->resolutions[resno]; + unsigned char *c = src; + unsigned char *d = c; + int e; + int present; + + if (layno == 0) { + for (bandno = 0; bandno < res->numbands; bandno++) { + tcd_band_t *band = &res->bands[bandno]; + tcd_precinct_t *prc = &band->precincts[precno]; + tgt_reset(prc->incltree); + tgt_reset(prc->imsbtree); + for (cblkno = 0; cblkno < prc->cw * prc->ch; cblkno++) { + tcd_cblk_t *cblk = &prc->cblks[cblkno]; + cblk->numsegs = 0; + } + } + } + /* INDEX */ + layer_Idx->len_header = 0; + + /* When the marker PPT/PPM is used the packet header are store in PPT/PPM marker + This part deal with this caracteristic + step 1: Read packet header in the saved structure + step 2: (futher) return to codestream for decoding */ + if (cp->ppm == 1) /* PPM */ + { + c = cp->ppm_data; + d = c; + bio_init_dec(c, 1000); + } else + { + if (tcp->ppt == 1) /* PPT */ + { + c = tcp->ppt_data; + d = c; + bio_init_dec(c, 1000); + } else /* Normal Case */ + { + if (tcp->csty & J2K_CP_CSTY_SOP) + { + if ((*c) != 255 || (*(c+1) != 145)) {printf("Error : expected SOP marker [1]!!!\n");} + c += 6; + } + bio_init_dec(c, src + len - c); + layer_Idx->len_header = -6; + } + } + + present = bio_read(1); + + if (!present) + { + bio_inalign(); + /* Normal case */ + c += bio_numbytes(); + if (tcp->csty & J2K_CP_CSTY_EPH) + { + if ((*c) != 255 || (*(c+1) != 146)) {printf("Error : expected EPH marker [1]!!!\n");} + c += 2; + } + /* INDEX */ + layer_Idx->len_header += (c-d); + + /* PPT and PPM dealing */ + if (cp->ppm == 1) /* PPM */ + { + cp->ppm_data = c; + return 0; + } + if (tcp->ppt == 1) /* PPT */ + { + tcp->ppt_data = c; + return 0; + } + return c - src; + } + + for (bandno=0; bandnonumbands; bandno++) { + tcd_band_t *band = &res->bands[bandno]; + tcd_precinct_t *prc = &band->precincts[precno]; + for (cblkno = 0; cblkno < prc->cw * prc->ch; cblkno++) { + int included, increment, n; + tcd_cblk_t *cblk = &prc->cblks[cblkno]; + tcd_seg_t *seg; + if (!cblk->numsegs) { + included = tgt_decode(prc->incltree, cblkno, layno+1); + } else { + included = bio_read(1); + } + if (!included) { + cblk->numnewpasses = 0; + continue; + } + if (!cblk->numsegs) { + int i, numimsbs; + for (i = 0; !tgt_decode(prc->imsbtree, cblkno, i); i++) {} + numimsbs = i-1; + cblk->numbps = band->numbps - numimsbs; + cblk->numlenbits = 3; + } + cblk->numnewpasses = t2_getnumpasses(); + increment = t2_getcommacode(); + cblk->numlenbits += increment; + if (!cblk->numsegs) { + seg = &cblk->segs[0]; + t2_init_seg(seg, tcp->tccps[compno].cblksty); + } else { + seg = &cblk->segs[cblk->numsegs - 1]; + if (seg->numpasses == seg->maxpasses) { + t2_init_seg(++seg, tcp->tccps[compno].cblksty); + } + } + n = cblk->numnewpasses; + do { + seg->numnewpasses = int_min(seg->maxpasses-seg->numpasses, n); + seg->newlen = bio_read(cblk->numlenbits + int_floorlog2(seg->numnewpasses)); + n -= seg->numnewpasses; + if (n > 0) { + t2_init_seg(++seg, tcp->tccps[compno].cblksty); + } + } while (n > 0); + } + } + if(bio_inalign()) return -999; + c += bio_numbytes(); + + if (tcp->csty & J2K_CP_CSTY_EPH) { /* EPH marker */ + if ((*c) != 255 || (*(c+1) != 146)) {printf("Error : expected EPH marker [2]!!!\n"); } + c += 2; + } + + /* INDEX */ + layer_Idx->len_header += (c-d); + + /* PPT Step 2 : see above for details */ + if (cp->ppm == 1) + { + cp->ppm_data = c; /* Update pointer */ + + /* INDEX */ + layer_Idx->len_header = c-d; + + c = src; + d = c; + if (tcp->csty & J2K_CP_CSTY_SOP) + { + if ((*c) != 255 || (*(c+1) != 145)) {printf("Error : expected SOP marker [2] !!!\n"); } + c += 6; + } + bio_init_dec(c, src + len - c); + } else + { + if (tcp->ppt == 1) + { + tcp->ppt_data = c; /* Update pointer */ + /* INDEX */ + layer_Idx->len_header = c-d; + + c = src; + d = c; + if (tcp->csty & J2K_CP_CSTY_SOP) /* SOP marker */ + { + if ((*c) != 255 || (*(c+1) != 145)) {printf("Error : expected SOP marker [2] !!!\n"); } + c += 6; + } + bio_init_dec(c, src + len - c); + + } + } + + for (bandno = 0; bandno < res->numbands; bandno++) { + tcd_band_t *band = &res->bands[bandno]; + tcd_precinct_t *prc = &band->precincts[precno]; + for (cblkno = 0; cblkno < prc->cw*prc->ch; cblkno++) { + tcd_cblk_t *cblk = &prc->cblks[cblkno]; + tcd_seg_t *seg; + if (!cblk->numnewpasses) continue; + if (!cblk->numsegs) { + seg = &cblk->segs[cblk->numsegs++]; + cblk->len = 0; + } else { + seg = &cblk->segs[cblk->numsegs-1]; + if (seg->numpasses == seg->maxpasses) { + seg++; + cblk->numsegs++; + } + } + do { + if (c + seg->newlen > src + len) return -999; + memcpy(cblk->data + cblk->len, c, seg->newlen); + if (seg->numpasses == 0) { + seg->data = cblk->data + cblk->len; + } + c += seg->newlen; + cblk->len += seg->newlen; + seg->len += seg->newlen; + seg->numpasses += seg->numnewpasses; + cblk->numnewpasses -= seg->numnewpasses; + if (cblk->numnewpasses > 0) { + seg++; + cblk->numsegs++; + } + } while (cblk->numnewpasses > 0); + } + } + /* */ + e = c-d; + layer_Idx->len = e; + /* */ + + return c-src; +} + +void t2_init_info_packets(info_image_t *img, j2k_cp_t *cp) +{ + int compno, tileno, resno, precno, layno; + + for(compno = 0; compno < img->Comp; compno++) + { + for(tileno = 0; tileno < img->tw*img->th; tileno++) + { + info_tile_t *tile_Idx = &img->tile[tileno]; + info_compo_t *compo_Idx = &tile_Idx->compo[compno]; + for(resno = 0; resno < img->Decomposition + 1 ; resno++) + { + info_reso_t *reso_Idx = &compo_Idx->reso[resno]; + for (precno = 0; precno < img->tile[tileno].pw * img->tile[tileno].ph; precno++) + { + info_prec_t *prec_Idx = &reso_Idx->prec[precno]; + for(layno = 0; layno < img->Layer ; layno++) + { + info_layer_t *layer_Idx = &prec_Idx->layer[layno]; + layer_Idx->offset = 0; /* start position */ + layer_Idx->len_header = 0; /* length */ + } + } + } + } + } +} + +int t2_decode_packets(unsigned char *src, int len, j2k_image_t *img, j2k_cp_t *cp, int tileno, tcd_tile_t *tile, info_image_t *imgg) { + unsigned char *c = src; + pi_iterator_t *pi; + int pino, compno,e; + int partno; + info_tile_part_t *tile_part; + int position; + int length_read; + info_tile_t *tile_Idx; + info_compo_t *compo_Idx; + info_reso_t *reso_Idx; + info_prec_t *prec_Idx; + info_layer_t *layer_Idx; + + t2_init_info_packets(imgg, cp); /* Initialize the packets information : LEN and OFFSET to 0 */ + + tile_Idx = &imgg->tile[tileno]; + tile_Idx->num_packet = 0; + pi = pi_create(img, cp, tileno); + partno = 0; + tile_part = &tile_Idx->tile_parts[partno]; + position = tile_part->end_header + 1; + length_read = 0; + + for (pino = 0; pino <= cp->tcps[tileno].numpocs; pino++) + { + while (pi_next(&pi[pino])) + { + compo_Idx = &tile_Idx->compo[pi[pino].compno]; + reso_Idx = &compo_Idx->reso[pi[pino].resno]; + prec_Idx = &reso_Idx->prec[pi[pino].precno]; + layer_Idx = &prec_Idx->layer[pi[pino].layno]; + + layer_Idx->offset = position; + layer_Idx->offset_header = position; + + e = t2_decode_packet(c, src+len-c, tile, cp, &cp->tcps[tileno], pi[pino].compno, pi[pino].resno, pi[pino].precno, pi[pino].layno,layer_Idx); + if (e == -999) + { + break; + } else + c += e; + position += e; + + /* Update position in case of multiple tile-parts for a tile >> */ + length_read += e; + if (length_read >= (tile_part->end_pos - tile_part->end_header)) + { + partno++; + tile_part = &tile_Idx->tile_parts[partno]; + position = tile_part->end_header + 1; + length_read = 0; + } + /* << end_update */ + + tile_Idx->num_packet++; + } + + // FREE space memory taken by pi + for (compno = 0; compno < pi[pino].numcomps; compno++) + { + free(pi[pino].comps[compno].resolutions); + } + free(pi[pino].comps); + } + + free(pi[0].include); + free(pi); + + if (e==-999) + return e; + else + { + imgg->num_packet_max=int_max(imgg->num_packet_max,tile_Idx->num_packet); + return c-src; + } +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/t2.h b/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/t2.h new file mode 100644 index 0000000..f495107 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/t2.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2001-2002, David Janssens + * Copyright (c) 2003, Yannick Verschueren + * Copyright (c) 2003, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __T2_H +#define __T2_H + +#include "tcd.h" +#include "j2k.h" + +/* + * Decode the packets of a tile from a source buffer + * src: the source buffer + * len: length of the source buffer + * img: destination image + * cp: image coding parameters + * tileno: number that identifies the tile for which to decode the packets + * tile: tile for which to decode the packets + */ +int t2_decode_packets(unsigned char *src, int len, j2k_image_t *img, j2k_cp_t *cp, int tileno, tcd_tile_t *tile, info_image_t *imgg); + +#endif diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/tcd.c b/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/tcd.c new file mode 100644 index 0000000..c4045c7 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/tcd.c @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2001-2002, David Janssens + * Copyright (c) 2003, Yannick Verschueren + * Copyright (c) 2003, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "tcd.h" +#include "int.h" +#include "t2.h" +#include +#include +#include +#include +#include +#include +#include + +static tcd_image_t tcd_image; + +static j2k_image_t *tcd_img; +static j2k_cp_t *tcd_cp; + +extern jmp_buf j2k_error; + +void tcd_init(j2k_image_t *img, j2k_cp_t *cp, info_image_t *imgg) { + int tileno, compno, resno, bandno, precno, cblkno; + tcd_img=img; + tcd_cp=cp; + tcd_image.tw=cp->tw; + tcd_image.th=cp->th; + tcd_image.tiles=(tcd_tile_t*)malloc(cp->tw*cp->th*sizeof(tcd_tile_t)); + for (tileno=0; tilenotw*cp->th; tileno++) { + j2k_tcp_t *tcp=&cp->tcps[tileno]; + tcd_tile_t *tile=&tcd_image.tiles[tileno]; + // cfr p59 ISO/IEC FDIS15444-1 : 2000 (18 august 2000) + int p=tileno%cp->tw; // si numerotation matricielle .. + int q=tileno/cp->tw; // .. coordonnees de la tile (q,p) q pour ligne et p pour colonne + info_tile_t *tile_Idx=&imgg->tile[tileno]; // INDEX + + // 4 borders of the tile rescale on the image if necessary + tile->x0=int_max(cp->tx0+p*cp->tdx, img->x0); + tile->y0=int_max(cp->ty0+q*cp->tdy, img->y0); + tile->x1=int_min(cp->tx0+(p+1)*cp->tdx, img->x1); + tile->y1=int_min(cp->ty0+(q+1)*cp->tdy, img->y1); + + tile->numcomps=img->numcomps; + tile->comps=(tcd_tilecomp_t*)malloc(img->numcomps*sizeof(tcd_tilecomp_t)); + tile_Idx->compo=(info_compo_t*)malloc(img->numcomps*sizeof(info_compo_t)); // INDEX + for (compno=0; compnonumcomps; compno++) { + j2k_tccp_t *tccp=&tcp->tccps[compno]; + tcd_tilecomp_t *tilec=&tile->comps[compno]; + info_compo_t *compo_Idx=&tile_Idx->compo[compno]; // INDEX + + // border of each tile component (global) + tilec->x0=int_ceildiv(tile->x0, img->comps[compno].dx); + tilec->y0=int_ceildiv(tile->y0, img->comps[compno].dy); + tilec->x1=int_ceildiv(tile->x1, img->comps[compno].dx); + tilec->y1=int_ceildiv(tile->y1, img->comps[compno].dy); + + tilec->data=(int*)malloc(sizeof(int)*(tilec->x1-tilec->x0)*(tilec->y1-tilec->y0)); + tilec->numresolutions=tccp->numresolutions; + tilec->resolutions=(tcd_resolution_t*)malloc(tilec->numresolutions*sizeof(tcd_resolution_t)); + compo_Idx->reso=(info_reso_t*)malloc(tilec->numresolutions*sizeof(info_reso_t)); // INDEX + for (resno=0; resnonumresolutions; resno++) { + int pdx, pdy; + int levelno=tilec->numresolutions-1-resno; + int tlprcxstart, tlprcystart, brprcxend, brprcyend; + int tlcbgxstart, tlcbgystart, brcbgxend, brcbgyend; + int cbgwidthexpn, cbgheightexpn; + int cblkwidthexpn, cblkheightexpn; + tcd_resolution_t *res=&tilec->resolutions[resno]; + info_reso_t *res_Idx=&compo_Idx->reso[resno]; // INDEX + int precno_Idx; // INDEX + + // border for each resolution level (global) + res->x0=int_ceildivpow2(tilec->x0, levelno); + res->y0=int_ceildivpow2(tilec->y0, levelno); + res->x1=int_ceildivpow2(tilec->x1, levelno); + res->y1=int_ceildivpow2(tilec->y1, levelno); + + res->numbands=resno==0?1:3; + // p. 35, table A-23, ISO/IEC FDIS154444-1 : 2000 (18 august 2000) + if (tccp->csty&J2K_CCP_CSTY_PRT) { + pdx=tccp->prcw[resno]; + pdy=tccp->prch[resno]; + } else { + pdx=15; + pdy=15; + } + // p. 64, B.6, ISO/IEC FDIS15444-1 : 2000 (18 august 2000) + tlprcxstart=int_floordivpow2(res->x0, pdx)<y0, pdy)<x1, pdx)<y1, pdy)<pw=(brprcxend-tlprcxstart)>>pdx; + res->ph=(brprcyend-tlprcystart)>>pdy; + + // + imgg->tile[tileno].pw=res->pw; + imgg->tile[tileno].ph=res->ph; + + res_Idx->prec=(info_prec_t*)malloc(res->pw*res->ph*sizeof(info_prec_t)); + for (precno_Idx=0;precno_Idxpw*res->ph;precno_Idx++) + { + info_prec_t *prec_Idx = &res_Idx->prec[precno_Idx]; + prec_Idx->layer=(info_layer_t*)malloc(imgg->Layer*sizeof(info_layer_t)); + } + + imgg->pw=res->pw; // old parser version + imgg->ph=res->ph; // old parser version + imgg->pdx=1<pdy=1< + + if (resno==0) { + tlcbgxstart=tlprcxstart; + tlcbgystart=tlprcystart; + brcbgxend=brprcxend; + brcbgyend=brprcyend; + cbgwidthexpn=pdx; + cbgheightexpn=pdy; + } else { + tlcbgxstart=int_ceildivpow2(tlprcxstart, 1); + tlcbgystart=int_ceildivpow2(tlprcystart, 1); + brcbgxend=int_ceildivpow2(brprcxend, 1); + brcbgyend=int_ceildivpow2(brprcyend, 1); + cbgwidthexpn=pdx-1; + cbgheightexpn=pdy-1; + } + + cblkwidthexpn=int_min(tccp->cblkw, cbgwidthexpn); + cblkheightexpn=int_min(tccp->cblkh, cbgheightexpn); + + for (bandno=0; bandnonumbands; bandno++) { + int x0b, y0b; + tcd_band_t *band=&res->bands[bandno]; + band->bandno=resno==0?0:bandno+1; + x0b=(band->bandno==1)||(band->bandno==3)?1:0; + y0b=(band->bandno==2)||(band->bandno==3)?1:0; + + if (band->bandno==0) { + // band border (global) + band->x0=int_ceildivpow2(tilec->x0, levelno); + band->y0=int_ceildivpow2(tilec->y0, levelno); + band->x1=int_ceildivpow2(tilec->x1, levelno); + band->y1=int_ceildivpow2(tilec->y1, levelno); + } else { + // band border (global) + band->x0=int_ceildivpow2(tilec->x0-(1<y0=int_ceildivpow2(tilec->y0-(1<x1=int_ceildivpow2(tilec->x1-(1<y1=int_ceildivpow2(tilec->y1-(1<precincts=(tcd_precinct_t*)malloc(res->pw*res->ph*sizeof(tcd_precinct_t)); + + for (precno=0; precnopw*res->ph; precno++) { + int tlcblkxstart, tlcblkystart, brcblkxend, brcblkyend; + int cbgxstart=tlcbgxstart+(precno%res->pw)*(1<pw)*(1<precincts[precno]; + // precinct size (global) + prc->x0=int_max(cbgxstart, band->x0); + prc->y0=int_max(cbgystart, band->y0); + prc->x1=int_min(cbgxend, band->x1); + prc->y1=int_min(cbgyend, band->y1); + + tlcblkxstart=int_floordivpow2(prc->x0, cblkwidthexpn)<y0, cblkheightexpn)<x1, cblkwidthexpn)<y1, cblkheightexpn)<cw=(brcblkxend-tlcblkxstart)>>cblkwidthexpn; + prc->ch=(brcblkyend-tlcblkystart)>>cblkheightexpn; + + prc->cblks=(tcd_cblk_t*)malloc(prc->cw*prc->ch*sizeof(tcd_cblk_t)); + + prc->incltree=tgt_create(prc->cw, prc->ch); + prc->imsbtree=tgt_create(prc->cw, prc->ch); + + for (cblkno=0; cblknocw*prc->ch; cblkno++) { + int cblkxstart=tlcblkxstart+(cblkno%prc->cw)*(1<cw)*(1<cblks[cblkno]; + // code-block size (global) + cblk->x0=int_max(cblkxstart, prc->x0); + cblk->y0=int_max(cblkystart, prc->y0); + cblk->x1=int_min(cblkxend, prc->x1); + cblk->y1=int_min(cblkyend, prc->y1); + } + } + } + } + } + } +} + + +void tcd_free(j2k_image_t *img, j2k_cp_t *cp) { + int tileno, compno, resno, bandno, precno; + tcd_img=img; + tcd_cp=cp; + tcd_image.tw=cp->tw; + tcd_image.th=cp->th; + for (tileno=0; tilenotcps[curtileno]; + tcd_tile_t *tile=&tcd_image.tiles[tileno]; + for (compno=0; compnonumcomps; compno++) + { + tcd_tilecomp_t *tilec=&tile->comps[compno]; + for (resno=0; resnonumresolutions; resno++) + { + tcd_resolution_t *res=&tilec->resolutions[resno]; + for (bandno=0; bandnonumbands; bandno++) + { + tcd_band_t *band=&res->bands[bandno]; + for (precno=0; precnopw*res->ph; precno++) + { + tcd_precinct_t *prc=&band->precincts[precno]; + + if (prc->incltree!=NULL) + tgt_destroy(prc->incltree); + if (prc->imsbtree!=NULL) + tgt_destroy(prc->imsbtree); + free(prc->cblks); + } // for (precno + free(band->precincts); + } // for (bandno + } // for (resno + free(tilec->resolutions); + } // for (compno + free(tile->comps); + } // for (tileno + free(tcd_image.tiles); +} + + +int tcd_decode_tile(unsigned char *src, int len, int tileno, info_image_t *imgg) { + int l; + int eof=0; + tcd_tile_t *tile; + + tile = &tcd_image.tiles[tileno]; + + l = t2_decode_packets(src, len, tcd_img, tcd_cp, tileno, tile, imgg); + + if (l==-999) + { + eof=1; + fprintf(stderr, "tcd_decode: incomplete bistream\n"); + } + + if (eof) { + longjmp(j2k_error, 1); + } + + l=1; + return l; +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/tcd.h b/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/tcd.h new file mode 100644 index 0000000..9a31723 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/tcd.h @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2001-2002, David Janssens + * Copyright (c) 2003, Yannick Verschueren + * Copyright (c) 2003, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __TCD_H +#define __TCD_H + +#include "j2k.h" +#include "tgt.h" + +typedef struct { + int numpasses; + int len; + unsigned char *data; + int maxpasses; + int numnewpasses; + int newlen; +} tcd_seg_t; + +typedef struct { + int rate; + double distortiondec; +} tcd_pass_t; + +typedef struct { + int numpasses; + int len; + unsigned char *data; +} tcd_layer_t; + +typedef struct { + int x0, y0, x1, y1; + int numbps; + int numlenbits; + int len; + int numpasses; + int numnewpasses; + int numsegs; + tcd_seg_t segs[100]; + unsigned char data[8192]; + int numpassesinlayers; + tcd_layer_t layers[100]; + int totalpasses; + tcd_pass_t passes[100]; +} tcd_cblk_t; + +typedef struct { + int x0, y0, x1, y1; + int cw, ch; + tcd_cblk_t *cblks; + tgt_tree_t *incltree; + tgt_tree_t *imsbtree; +} tcd_precinct_t; + +typedef struct { + int x0, y0, x1, y1; + int bandno; + tcd_precinct_t *precincts; + int numbps; + int stepsize; +} tcd_band_t; + +typedef struct { + int x0, y0, x1, y1; + int previous_x0, previous_y0, previous_x1, previous_y1; // usefull for the DWT + int cas_col, cas_row; // usefull for the DWT + int pw, ph; + int numbands; + tcd_band_t bands[3]; +} tcd_resolution_t; + +typedef struct { + int x0, y0, x1, y1; + int previous_row, previous_col; // usefull for the DWT + int numresolutions; + tcd_resolution_t *resolutions; + int *data; +} tcd_tilecomp_t; + +typedef struct { + int x0, y0, x1, y1; + int numcomps; + //int PPT; + //int len_ppt; + tcd_tilecomp_t *comps; +} tcd_tile_t; + +typedef struct { + int tw, th; + tcd_tile_t *tiles; +} tcd_image_t; + +/* + * Initialize the tile coder/decoder + * img: raw image + * cp: coding parameters + * imgg: creation of index file + */ + +void tcd_init(j2k_image_t *img, j2k_cp_t *cp, info_image_t *imgg); + +void tcd_free(j2k_image_t *img, j2k_cp_t *cp); + +/* + * Decode a tile from a buffer into a raw image + * src: source buffer + * len: length of the source buffer + * tileno: number that identifies the tile that will be decoded + * imgg : Structure for index file + */ +int tcd_decode_tile(unsigned char *src, int len, int tileno, info_image_t *imgg); + +#endif diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/tgt.c b/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/tgt.c new file mode 100644 index 0000000..c2b4682 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/indexer_JPIP/tgt.c @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2001-2002, David Janssens + * Copyright (c) 2003, Yannick Verschueren + * Copyright (c) 2003, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "tgt.h" +#include "bio.h" +#include +#include + +/// +/// Reset tag-tree. +/// +void tgt_reset(tgt_tree_t *tree) +{ + int i; + for (i=0; inumnodes; i++) { + tree->nodes[i].value=999; + tree->nodes[i].low=0; + tree->nodes[i].known=0; + } +} + +/// +/// Create tag-tree. +/// +tgt_tree_t *tgt_create(int numleafsh, int numleafsv) +{ + int nplh[32]; + int nplv[32]; + tgt_node_t *node; + tgt_node_t *parentnode; + tgt_node_t *parentnode0; + tgt_tree_t *tree; + int i, j, k; + int numlvls; + int n; + + tree=(tgt_tree_t*)malloc(sizeof(tgt_tree_t)); + tree->numleafsh=numleafsh; + tree->numleafsv=numleafsv; + + numlvls=0; + nplh[0]=numleafsh; + nplv[0]=numleafsv; + tree->numnodes=0; + do { + n=nplh[numlvls]*nplv[numlvls]; + nplh[numlvls+1]=(nplh[numlvls]+1)/2; + nplv[numlvls+1]=(nplv[numlvls]+1)/2; + tree->numnodes+=n; + ++numlvls; + } while (n>1); + + tree->nodes=(tgt_node_t*)malloc(tree->numnodes*sizeof(tgt_node_t)); + + node=tree->nodes; + parentnode=&tree->nodes[tree->numleafsh*tree->numleafsv]; + parentnode0=parentnode; + + for (i=0; i=0) { + node->parent=parentnode; + ++node; + if (--k >= 0) { + node->parent=parentnode; + ++node; + } + ++parentnode; + } + if ((j&1)||j==nplv[i]-1) { + parentnode0=parentnode; + } else { + parentnode=parentnode0; + parentnode0+=nplh[i]; + } + } + } + node->parent=0; + + tgt_reset(tree); + + return tree; +} + +/// +/// Destroy tag-tree. +/// +void tgt_destroy(tgt_tree_t *t) { + free(t->nodes); + free(t); +} + +/// +/// Set the value of a leaf of the tag-tree. +/// +void tgt_setvalue(tgt_tree_t *tree, int leafno, int value) { + tgt_node_t *node; + node=&tree->nodes[leafno]; + while (node && node->value>value) { + node->value=value; + node=node->parent; + } +} + +/// +/// Decode the value of a leaf of the tag-tree. +/// +int tgt_decode(tgt_tree_t *tree, int leafno, int threshold) +{ + tgt_node_t *stk[31]; + tgt_node_t **stkptr; + tgt_node_t *node; + int low; + + stkptr=stk; + node=&tree->nodes[leafno]; + while (node->parent) { + *stkptr++=node; + node=node->parent; + } + + low=0; + for (;;) { + if (low>node->low) { + node->low=low; + } else { + low=node->low; + } + while (lowvalue) { + if (bio_read(1)) { + node->value=low; + } else { + ++low; + } + } + node->low=low; + if (stkptr==stk) { + break; + } + node=*--stkptr; + } + + return (node->value +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=DllOpenJPEG - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "DllOpenJPEG.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "DllOpenJPEG.mak" CFG="DllOpenJPEG - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "DllOpenJPEG - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "DllOpenJPEG - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "DllOpenJPEG - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "DLLOPENJPEG_EXPORTS" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "OPJ_EXPORTS" /FD /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x40c /d "NDEBUG" +# ADD RSC /l 0x40c /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"Release/OpenJPEG.dll" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=if not exist dist mkdir dist copy libopenjpeg\openjpeg3d.h dist copy Release\OpenJPEG.dll dist copy Release\OpenJPEG.lib dist +# End Special Build Tool + +!ELSEIF "$(CFG)" == "DllOpenJPEG - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "DLLOPENJPEG_EXPORTS" /Yu"stdafx.h" /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "OPJ_EXPORTS" /FD /GZ /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x40c /d "_DEBUG" +# ADD RSC /l 0x40c /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"Debug/OpenJPEGd.dll" /pdbtype:sept +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=if not exist dist mkdir dist copy libopenjpeg\openjpeg3d.h dist copy Debug\OpenJPEGd.dll dist copy Debug\OpenJPEGd.lib dist +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "DllOpenJPEG - Win32 Release" +# Name "DllOpenJPEG - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\libopenjpeg\bio.c +# End Source File +# Begin Source File + +SOURCE=.\libopenjpeg\cio.c +# End Source File +# Begin Source File + +SOURCE=.\libopenjpeg\dwt.c +# End Source File +# Begin Source File + +SOURCE=.\libopenjpeg\event.c +# End Source File +# Begin Source File + +SOURCE=.\libopenjpeg\image.c +# End Source File +# Begin Source File + +SOURCE=.\libopenjpeg\j2k.c +# End Source File +# Begin Source File + +SOURCE=.\libopenjpeg\j2k_lib.c +# End Source File +# Begin Source File + +SOURCE=.\libopenjpeg\jp2.c +# End Source File +# Begin Source File + +SOURCE=.\libopenjpeg\jpt.c +# End Source File +# Begin Source File + +SOURCE=.\libopenjpeg\mct.c +# End Source File +# Begin Source File + +SOURCE=.\libopenjpeg\mqc.c +# End Source File +# Begin Source File + +SOURCE=.\libopenjpeg\openjpeg.c +# End Source File +# Begin Source File + +SOURCE=.\libopenjpeg\pi.c +# End Source File +# Begin Source File + +SOURCE=.\libopenjpeg\raw.c +# End Source File +# Begin Source File + +SOURCE=.\libopenjpeg\t1.c +# End Source File +# Begin Source File + +SOURCE=.\libopenjpeg\t2.c +# End Source File +# Begin Source File + +SOURCE=.\libopenjpeg\tcd.c +# End Source File +# Begin Source File + +SOURCE=.\libopenjpeg\tgt.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\libopenjpeg\bio.h +# End Source File +# Begin Source File + +SOURCE=.\libopenjpeg\cio.h +# End Source File +# Begin Source File + +SOURCE=.\libopenjpeg\dwt.h +# End Source File +# Begin Source File + +SOURCE=.\libopenjpeg\event.h +# End Source File +# Begin Source File + +SOURCE=.\libopenjpeg\fix.h +# End Source File +# Begin Source File + +SOURCE=.\libopenjpeg\image.h +# End Source File +# Begin Source File + +SOURCE=.\libopenjpeg\int.h +# End Source File +# Begin Source File + +SOURCE=.\libopenjpeg\j2k.h +# End Source File +# Begin Source File + +SOURCE=.\libopenjpeg\j2k_lib.h +# End Source File +# Begin Source File + +SOURCE=.\libopenjpeg\jp2.h +# End Source File +# Begin Source File + +SOURCE=.\libopenjpeg\jpt.h +# End Source File +# Begin Source File + +SOURCE=.\libopenjpeg\mct.h +# End Source File +# Begin Source File + +SOURCE=.\libopenjpeg\mqc.h +# End Source File +# Begin Source File + +SOURCE=.\libopenjpeg\openjpeg3d.h +# End Source File +# Begin Source File + +SOURCE=.\libopenjpeg\opj_includes.h +# End Source File +# Begin Source File + +SOURCE=.\libopenjpeg\pi.h +# End Source File +# Begin Source File + +SOURCE=.\libopenjpeg\raw.h +# End Source File +# Begin Source File + +SOURCE=.\libopenjpeg\t1.h +# End Source File +# Begin Source File + +SOURCE=.\libopenjpeg\t2.h +# End Source File +# Begin Source File + +SOURCE=.\libopenjpeg\tcd.h +# End Source File +# Begin Source File + +SOURCE=.\libopenjpeg\tgt.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\OpenJPEG.rc +# End Source File +# End Group +# End Target +# End Project diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/DllJp3dVM.sln b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/DllJp3dVM.sln new file mode 100644 index 0000000..4561fb9 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/DllJp3dVM.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DllOpenJPEG", "DllJp3dVM.vcproj", "{790A6CE5-CE92-4A59-ADF7-54A92760BD6C}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {790A6CE5-CE92-4A59-ADF7-54A92760BD6C}.Debug.ActiveCfg = Debug|Win32 + {790A6CE5-CE92-4A59-ADF7-54A92760BD6C}.Debug.Build.0 = Debug|Win32 + {790A6CE5-CE92-4A59-ADF7-54A92760BD6C}.Release.ActiveCfg = Release|Win32 + {790A6CE5-CE92-4A59-ADF7-54A92760BD6C}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/DllJp3dVM.vcproj b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/DllJp3dVM.vcproj new file mode 100644 index 0000000..bd21fa0 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/DllJp3dVM.vcproj @@ -0,0 +1,278 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/LICENSE.txt b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/LICENSE.txt new file mode 100644 index 0000000..55207d6 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/LICENSE.txt @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, HervŽ Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * Copyright (c) 2006, Mónica Díez, Image Processing Laboratory (LPI) - University of Valladolid, Spain + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/LibJp3dVM.sln b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/LibJp3dVM.sln new file mode 100644 index 0000000..3494505 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/LibJp3dVM.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LibJp3dVM", "LibJp3dVM.vcproj", "{6F3FB035-8F4E-4794-B091-0F0A20223BE7}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {6F3FB035-8F4E-4794-B091-0F0A20223BE7}.Debug.ActiveCfg = Debug|Win32 + {6F3FB035-8F4E-4794-B091-0F0A20223BE7}.Debug.Build.0 = Debug|Win32 + {6F3FB035-8F4E-4794-B091-0F0A20223BE7}.Release.ActiveCfg = Release|Win32 + {6F3FB035-8F4E-4794-B091-0F0A20223BE7}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/LibJp3dVM.vcproj b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/LibJp3dVM.vcproj new file mode 100644 index 0000000..2e4e0c2 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/LibJp3dVM.vcproj @@ -0,0 +1,249 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/README.txt b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/README.txt new file mode 100644 index 0000000..ce04072 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/README.txt @@ -0,0 +1,285 @@ +=============================================================================== + JPEG2000 Part 10 (ISO/IEC 15444-10 JP3D) Verification Model + + Version 1.1 +=============================================================================== + + +1. Scope +================ + +This document describes the installation and the use of the JP3D VM decoder and encoder under several operating systems (Linux, Unix, Windows, ...). Version 1.1 contains a complete JPEG 2000 Part 10 encoder, as well as a decoder. +The supported functionalities are compliant with the JPEG2000 part 10 algorithm as described in the WD 6.0. +The provided encoder and the decoder are compatible also with the International standard IS 15444-1 (core coding system). +This implementation has been developped from OpenJPEG implementation of JPEG2000 standard, and for this reason it is written in C language. + +If you find some bugs or if you have problems using the encoder/decoder, please send an e-mail to jp3d@lpi.tel.uva.es + +2. Installing the code +====================================================== + +- After decompressing the zip file provided, you should find +at least the following files in the created 'jp3d_vm' directory: + + * libjp3dvm - This directory contains all library related code + * codec - This directory contains all codec related code + * tcltk - This directory contains the API scripts + * README - The file you are reading + * LICENCE - Copyright statement of the JP3D VM software + +2.1. Compiling the source code in Windows +------------------------------------------- + +This version has been compiled with Visual Studio 2003 using +the projects included in the distribution: + + * LibJp3dVM.vcproj - Creates the library with all the JP3D functionalities + * jp3d_vm_enc.vcproj - Test encoder + * jp3d_vm_dec.vcproj - Test decoder + +2.2. Compiling the source code in Unix-like systems +------------------------------------------- + +Library compilation +------------------------ +This version of the library has been tested under the following OS: +- Fedora Core + +The installation process is as simple as this : +1) Enter the 'jp3d_vm' directory +2) Build the distribution : +make +make install +3) Clean all files produced during the build process +make clean + +Codec compilation +------------------------ +Once you've built the library, you should compile the JP3D codec. + +1) Go to the 'codec' directory +2) Build the encoder and decoder programs: + +gcc convert.c volume_to_jp3d.c -o jp3d_vm_enc -I ../libjp3dvm/ -lm -ljp3dvm +gcc convert.c jp3d_to_volume.c -o jp3d_vm_dec -I ../libjp3dvm/ -lm -ljp3dvm + +Note: You should add '-L ../libjp3dvm/' to those lines if you +did not use the 'install' target (and the 'clean' target neither...). + +3. Running the JP3D VM +==================================================== + +3.1. JP3D ENCODER +==================================================== + +Required arguments +------------------------ + + * Input file(s): -i Involume [*.bin, *.pgx] + +Specifies the volume to compress. Accepted formats are *.BIN (raw binary data) or *.PGX files. +Both formats need some particular settings: + + a) BIN format. As it has no header, volume characteristics will be obtained from a .IMG file. Its location will be specified through the following argument: + -m Involumeinfo.IMG + This file shall have the following structure, with the appropiate value in each case (bit per voxel, color map, dimensions in X,Y,Z): + o Bpp %d + o Color Map %d + o Dimensions %d %d %d + + b) PGX format. Program will consider it as a volume slice. In order to denote a volume through a sequence of slices, you can define the input filename with the common pattern of the set of PGX files followed by a dash (as a wildcard character for the sequence numbers). + + * Output file: -o Outfile [*.jp3d, *j2k] + +Specifies the name of the file where the codestream will be saved. +Part 1 compliant codestream will be created when an outfile has .j2k format. + +Options +-------- + + * Rate values : -r 20,10,5 + This option offers the possibility to define the compression rate to apply. + Each value is a factor of compression (i.e. 20 : 1) and will generate a different quality layer. A lossless compression will be signified by the value 1. + NOTE : The order used to define the different levels of compression is important and must be from left to right in descending order. + + * Quality values : -q 30,35,40 + This option offers the possibility to define the quality level to achieve. Each value is a psnr, to be given in dB, and represents a quality layer. + NOTE : The order used to define the different psnr-values is important and must be from left to right in ascending order. + + + * Number of resolutions : -n 3,3,2 + This option offers the possibility to define the number of resolution levels computed for each dimension of the volume through the discret wavelet transform (DWT). Resolution in axial dimension can have a different value than in horizontal and vertical cases, but must be lower. + DEFAULT VALUE : 3,3,1 + + + * Switch modes : -M 3 + This option offers the possibility to use a mode switch during the encoding process: + o BYPASS(LAZY) [1] + o RESET [2] + o RESTART(TERMALL) [4] + o VSC [8] + o ERTERM(SEGTERM) [16] + o SEGMARK(SEGSYM) [32] + o 3D_CONTEXT [64] + For several mode switch just sum corresponding values: i.e. -M 38 => RESTART(4) + RESET(2) + SEGMARK(32) + DEFAULT VALUE: 0 + + + * Progression order : -p LRCP + This option offers the possibility to specify the progression order. Possible progression orders are : LRCP, RLCP, RPCL, PCRL and CPRL. + DEFAULT VALUE: LRCP. + + + * Code-block size : -b 32,32,32 + This option offers the possibility to define the size of the code-block. The dimension must respect the constraint defined in the JPEG-2000 standard. The maximum value autorized is 64x64x64. + DEFAULT VALUE: 64,64,64 + + + * Precinct size : -c [128,128,128],[128,128,128],... + This option offers the possibility to define the size of the precincts at each resolution. Multiple records may be supplied, in which case the first record refers to the highest resolution level and subsequent records to lower resolution levels. The last specified record is right-shifted for each remaining lower resolution levels. + NOTE : specified values must be power of 2. + DEFAULT VALUE: 2^15 x 2^15 x 2^15 + + + * Tile size : -t 512,512,512 + This option offers the possibility to divide the volume in several tiles. The three values define the width, the heigth and the depth of the tile respectivily. + DEFAULT VALUE: Volume dimensions (one tile) + + + * Subsampling factor : -s 2,2,2 + This option offers the possibility to apply a subsampling factor for X, Y and Z axis. Value higher than 2 can be a source of error ! + DEFAULT VALUE: 1,1,1 + + + * SOP marker before each packet : -SOP + This option offers the possibility to add a specific marker before each packet. It is the marker SOP (Start of packet). If the option is not used no SOP marker will be added. + + + * EPH marker after each packet header : -EPH + This option offers the possibility to add a specific marker at the head of each packet header. It is the marker EPH (End of packet Header). If the option is not used no EPH marker will be added. + + + * Offset of the volume origin : -d 150,300,10 + This option offers the possibility to move the origine of the volume in X, Y and/or Z axis. The division in tile could be modified as the anchor point for tiling will be different than the volume origin. + NOTE : the offset of the volume can not be higher than the tile dimension if the tile option is used. + DEFAULT VALUE: 0,0,0 + + + * Offset of the tile origin : -T 100,75,5 + This option offers the possibility to move the anchor point of the volume in X, Y and/or Z axis. + NOTE : the tile anchor point can not be on the volume area. + DEFAULT VALUE: 0,0,0 + + + * Display the help menu : -help + This option displays on screen the content of this page + +Additional options +---------------------------------- + + * Encoding information file: -x index_name.idx + This option offers the possibility to create a text file with some structured information generated through the encoding. The name of the file must be specified, with .idx extension. The information structure is the following: + o Volume size: + + VolW + VolH + VolD + o Progression Order: + + Prog + o Tile size: + + TileW + TileH + TileD + o Number of components: + + NumComp + o Number of layers: + + NumLayer + o Number of decompositions (=(number of resolutions - 1)): + + NumDWTx + NumDWTy + NumDWTz + o Precinct size: + + [Precinct_width(NumDWT),Precinct_height(NumDWT),Precinct_depth(NumDWT)] + + [Precinct_width(NumDWT-1),Precinct_height(NumDWT-1),Precinct_depth(NumDWT-1)] + + ... + + [Precinct_width(0),Precinct_height(0),Precinct_depth(0)] + o Main Header end position: + + MH_EndPos + o Codestream size: + + CSSize + o Tile 0 information: + + TileNum (0) + + StartPos + + TileHeader_EndPos + + EndPos + + TotalDisto (this is the sum of the distortion reductions brought by each packet belonging to this tile) + + NumPix (this is the number of pixels in the tile) + + MaxMSE (=TotalDisto/NumPix) + o Tile1 information: + + TileNum (1) + + ... + o ... + o Tile N information: + + TileNum (N) + + ... + o Packet 0 from Tile 0 information: + + PackNum (0) + + TileNum (0) + + LayerNum + + ResNum + + CompNum + + PrecNum + + StartPos + + EndPos + + Disto (distortion reduction brought by this packet) + o Packet 1 from Tile 0 information: + + PackNum (1) + + ... + o ... + o Packet M from Tile 0 information + o Packet 0 from Tile 1 information + o ... + o Packet M from Tile N information + o Maximum distortion reduction on the whole volume: + + MaxDisto + o Total distortion on the whole volume (sum of the distortion reductions from all packets in the volume): + + TotalDisto + +3.2. JP3D DECODER +==================================================== + +Required arguments +------------------------ + + * Infile : -i compressed file + Currently accepts JP3D and J2K-files. The file type is identified based on its suffix (*.jp3d, *.j2k). + + + * Outfile(s) : -o decompressed file(s) + Currently accepts BIN-files and PGX-files. Binary data is written to the file (not ascii). + If a BIN-file is defined, decoder will create automatically the volume characteristic file appending a .IMG extension to the provided output filename. + If a PGX-file is defined, decoder will understand this as a file pattern, appending corresponding indice from 0 to the number of decoded slices. + NOTE : There will be as many output files as there are components: an indice starting from 0 will then be appended to the output filename, just before the extension. + + +Options available +------------------------ + + * Reduce factor : -r 1,1,0 + Set the number of highest resolution levels to be discarded in each dimension. The decoded volume size is effectively divided by 2 to the power of the number of discarded levels. + NOTE : The reduce factor is limited by the smallest total number of decomposition levels among tiles. + + + * Layer number : -l 2 + Set the maximum number of quality layers to decode. If there are less quality layers than the specified number, all the quality layers are decoded. + + + * Performance comparisons : -O original-file + This option offers the possibility to compute some quality results for the decompressed volume, like the PSNR value achieved or the global SSIM value. Needs the original file in order to compare with the new one. + NOTE: Only valid when -r option is 0,0,0 (both original and decompressed volumes have same resolutions) + NOTE: If original file is .BIN file, the volume characteristics file shall be defined with the -m option. + (i.e. -O original-BIN-file -m original-IMG-file) + + + * Byte order (Big-endian / Little-endian) : -BE + This option offers the possibility to save the decompressed volume with a predefined byte order. + DEFAULT VALUE: Little-endian + + + * Display the help menu : -help + This option displays on screen the content of this page + + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/CMakeLists.txt b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/CMakeLists.txt new file mode 100644 index 0000000..35c6452 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/CMakeLists.txt @@ -0,0 +1,47 @@ +# Build the demo app, small examples + +# First thing define the common source: +set(common_SRCS + convert.c + ) +# Then check if getopt is present: +include (${CMAKE_ROOT}/Modules/CheckIncludeFile.cmake) +set(DONT_HAVE_GETOPT 1) +if(UNIX) #I am pretty sure only *nix sys have this anyway + CHECK_INCLUDE_FILE("getopt.h" CMAKE_HAVE_GETOPT_H) + # Seems like we need the contrary: + if(CMAKE_HAVE_GETOPT_H) + set(DONT_HAVE_GETOPT 0) + endif() +endif() + +# If not getopt was found then add it to the lib: +if(DONT_HAVE_GETOPT) + add_definitions(-DDONT_HAVE_GETOPT) + set(common_SRCS + ${common_SRCS} + getopt.c + ) +endif() + +if(WIN32) + if(BUILD_SHARED_LIBS) + add_definitions(-DOPJ_EXPORTS) + else() + add_definitions(-DOPJ_STATIC) + endif() +endif() + +# Loop over all executables: +foreach(exe jp3d_to_volume volume_to_jp3d) + add_executable(${exe} ${exe}.c ${common_SRCS}) + target_link_libraries(${exe} ${OPENJPEG_LIBRARY_NAME}_JP3D) # ${TIFF_LIBRARIES}) + # On unix you need to link to the math library: + if(UNIX) + target_link_libraries(${exe} m) + endif() + # Install exe + install_targets(/bin/ ${exe}) +endforeach() + + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/convert.c b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/convert.c new file mode 100644 index 0000000..92a8163 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/convert.c @@ -0,0 +1,997 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * Copyright (c) 2006, Mónica Díez García, Image Processing Laboratory, University of Valladolid, Spain + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include "../libjp3dvm/openjpeg3d.h" +#ifdef _WIN32 +#include "windirent.h" +#else +#include +#endif /* _WIN32 */ + + + +void dump_volume(FILE *fd, opj_volume_t * vol) { + int compno; + fprintf(fd, "volume {\n"); + fprintf(fd, " x0=%d, y0=%d, z0=%d, x1=%d, y1=%d, z1=%d\n", vol->x0, vol->y0, vol->z0,vol->x1, vol->y1, vol->z1); + fprintf(fd, " numcomps=%d\n", vol->numcomps); + for (compno = 0; compno < vol->numcomps; compno++) { + opj_volume_comp_t *comp = &vol->comps[compno]; + fprintf(fd, " comp %d {\n", compno); + fprintf(fd, " dx=%d, dy=%d, dz=%d\n", comp->dx, comp->dy, comp->dz); + fprintf(fd, " prec=%d\n", comp->prec); + fprintf(fd, " sgnd=%d\n", comp->sgnd); + fprintf(fd, " }\n"); + } + fprintf(fd, "}\n"); +} + +/* + * Get logarithm of an integer and round downwards. + * + * log2(a) + */ +static int int_floorlog2(int a) { + int l; + for (l = 0; a > 1; l++) { + a >>= 1; + } + return l; +} + +/* + * Divide an integer by a power of 2 and round upwards. + * + * a divided by 2^b + */ +static int int_ceildivpow2(int a, int b) { + return (a + (1 << b) - 1) >> b; +} + +/* + * Divide an integer and round upwards. + * + * a divided by b + */ +static int int_ceildiv(int a, int b) { + return (a + b - 1) / b; +} + + +/* -->> -->> -->> -->> + +PGX IMAGE FORMAT + +<<-- <<-- <<-- <<-- */ + + +unsigned char readuchar(FILE * f) +{ + unsigned char c1; + fread(&c1, 1, 1, f); + return c1; +} + +unsigned short readushort(FILE * f, int bigendian) +{ + unsigned char c1, c2; + fread(&c1, 1, 1, f); + fread(&c2, 1, 1, f); + if (bigendian) + return (c1 << 8) + c2; + else + return (c2 << 8) + c1; +} + +unsigned int readuint(FILE * f, int bigendian) +{ + unsigned char c1, c2, c3, c4; + fread(&c1, 1, 1, f); + fread(&c2, 1, 1, f); + fread(&c3, 1, 1, f); + fread(&c4, 1, 1, f); + if (bigendian) + return (c1 << 24) + (c2 << 16) + (c3 << 8) + c4; + else + return (c4 << 24) + (c3 << 16) + (c2 << 8) + c1; +} +/*****************************************/ +static unsigned short ShortSwap(unsigned short v) +{ + unsigned char c1, c2; + c1 = v & 0xff; + c2 = (v >> 8) & 0xff; + return (c1 << 8) + c2; +} + +static unsigned int LongSwap (unsigned int i) +{ + unsigned char b1, b2, b3, b4; + b1 = i & 255; + b2 = ( i >> 8 ) & 255; + b3 = ( i>>16 ) & 255; + b4 = ( i>>24 ) & 255; + return ((int)b1 << 24) + ((int)b2 << 16) + ((int)b3 << 8) + b4; +} +/*****************************************/ + +opj_volume_t* pgxtovolume(char *relpath, opj_cparameters_t *parameters) { + + FILE *f = NULL; + int w, h, prec; + unsigned long offset; + int i, s, numcomps, maxvalue, sliceno, slicepos, maxslice = 0; + + OPJ_COLOR_SPACE color_space; + opj_volume_cmptparm_t cmptparm; // maximum of 1 component + opj_volume_t * volume = NULL; + + char endian1,endian2,sign; + char signtmp[32]; + char temp[32]; + opj_volume_comp_t *comp = NULL; + + DIR *dirp; + struct dirent *direntp; + + char *tmp = NULL, *tmp2 = NULL, + *point = NULL, *pgx = NULL; + char tmpdirpath[MAX_PATH]; + char dirpath[MAX_PATH]; + char pattern[MAX_PATH]; + char pgxfiles[MAX_SLICES][MAX_PATH]; + int pgxslicepos[MAX_SLICES]; + char tmpno[3]; + + numcomps = 1; + color_space = CLRSPC_GRAY; + sliceno = 0; + maxvalue = 0; + memset(pgxfiles, 0, MAX_SLICES * MAX_PATH * sizeof(char)); + memset(&cmptparm, 0, sizeof(opj_volume_cmptparm_t)); + + /* Separación del caso de un único slice frente al de muchos */ + if ((tmp = strrchr(relpath,'-')) == NULL){ + //fprintf(stdout,"[INFO] A volume of only one slice....\n"); + sliceno = 1; + maxslice = 1; + strcpy(pgxfiles[0],relpath); + + } else { + //Fetch only the path + strcpy(tmpdirpath,relpath); + if ((tmp = strrchr(tmpdirpath,'/')) != NULL){ + tmp++; *tmp='\0'; + strcpy(dirpath,tmpdirpath); + } else { + strcpy(dirpath,"./"); + } + + //Fetch the pattern of the volume slices + if ((tmp = strrchr (relpath,'/')) != NULL) + tmp++; + else + tmp = relpath; + if ((tmp2 = strrchr(tmp,'-')) != NULL) + *tmp2='\0'; + else{ + fprintf(stdout, "[ERROR] tmp2 ha dado null. no ha encontrado el * %s %s",tmp,relpath); + return NULL; + } + strcpy(pattern,tmp); + + dirp = opendir( dirpath ); + if (dirp == NULL){ + fprintf(stdout, "[ERROR] Infile must be a .pgx file or a directory that contain pgx files"); + return NULL; + } + + /*Read all .pgx files of directory */ + while ( (direntp = readdir( dirp )) != NULL ) + { + /* Found a directory, but ignore . and .. */ + if(strcmp(".",direntp->d_name) == 0 || strcmp("..",direntp->d_name) == 0) + continue; + + if( ((pgx = strstr(direntp->d_name,pattern)) != NULL) && ((tmp2 = strstr(direntp->d_name,".pgx")) != NULL) ){ + + strcpy(tmp,dirpath); + tmp = strcat(tmp,direntp->d_name); + + //Obtenemos el index de la secuencia de slices + if ((tmp2 = strpbrk (direntp->d_name, "0123456789")) == NULL) + continue; + i = 0; + while (tmp2 != NULL) { + tmpno[i++] = *tmp2; + point = tmp2; + tmp2 = strpbrk (tmp2+1,"0123456789"); + }tmpno[i]='\0'; + + //Comprobamos que no estamos leyendo algo raro como pattern.jp3d + if ((point = strpbrk (point,".")) == NULL){ + break; + } + //Slicepos --> index de slice; Sliceno --> no de slices hasta el momento + slicepos = atoi(tmpno); + pgxslicepos[sliceno] = slicepos - 1; + sliceno++; + if (slicepos>maxslice) + maxslice = slicepos; + + //Colocamos el slices en su posicion correspondiente + strcpy(pgxfiles[slicepos-1],tmp); + } + } + + }/* else if pattern*.pgx */ + + if (!sliceno) { + fprintf(stdout,"[ERROR] No slices with this pattern founded !! Please check input volume name\n"); + return NULL; + } + /*if ( maxslice != sliceno) { + fprintf(stdout,"[ERROR] Slices are not sequentially numbered !! Please rename them accordingly\n"); + return NULL; + }*/ + + for (s=0;svolume_offset_x0; + cmptparm.y0 = parameters->volume_offset_y0; + cmptparm.z0 = parameters->volume_offset_z0; + cmptparm.w = !cmptparm.x0 ? (w - 1) * parameters->subsampling_dx + 1 : cmptparm.x0 + (w - 1) * parameters->subsampling_dx + 1; + cmptparm.h = !cmptparm.y0 ? (h - 1) * parameters->subsampling_dy + 1 : cmptparm.y0 + (h - 1) * parameters->subsampling_dy + 1; + cmptparm.l = !cmptparm.z0 ? (sliceno - 1) * parameters->subsampling_dz + 1 : cmptparm.z0 + (sliceno - 1) * parameters->subsampling_dz + 1; + + if (sign == '-') { + cmptparm.sgnd = 1; + } else { + cmptparm.sgnd = 0; + } + cmptparm.prec = prec; + cmptparm.bpp = prec; + cmptparm.dcoffset = parameters->dcoffset; + cmptparm.dx = parameters->subsampling_dx; + cmptparm.dy = parameters->subsampling_dy; + cmptparm.dz = parameters->subsampling_dz; + + /* create the volume */ + volume = opj_volume_create(numcomps, &cmptparm, color_space); + if(!volume) { + fclose(f); + return NULL; + } + /* set volume offset and reference grid */ + volume->x0 = cmptparm.x0; + volume->y0 = cmptparm.y0; + volume->z0 = cmptparm.z0; + volume->x1 = cmptparm.w; + volume->y1 = cmptparm.h; + volume->z1 = cmptparm.l; + + /* set volume data :only one component, that is a volume*/ + comp = &volume->comps[0]; + + }//if sliceno==1 + + offset = w * h * s; + + for (i = 0; i < w * h; i++) { + int v; + if (comp->prec <= 8) { + if (!comp->sgnd) { + v = readuchar(f); + } else { + v = (char) readuchar(f); + } + } else if (comp->prec <= 16) { + if (!comp->sgnd) { + v = readushort(f, cmptparm.bigendian); + } else { + v = (short) readushort(f, cmptparm.bigendian); + } + } else { + if (!comp->sgnd) { + v = readuint(f, cmptparm.bigendian); + } else { + v = (int) readuint(f, cmptparm.bigendian); + } + } + if (v > maxvalue) + maxvalue = v; + comp->data[i + offset] = v; + + } + fclose(f); + } // for s --> sliceno + comp->bpp = int_floorlog2(maxvalue) + 1; + if (sliceno != 1) + closedir( dirp ); + //dump_volume(stdout, volume); + return volume; +} + + +int volumetopgx(opj_volume_t * volume, char *outfile) { + int w, wr, wrr, h, hr, hrr, l, lr, lrr; + int i, j, compno, offset, sliceno; + FILE *fdest = NULL; + + for (compno = 0; compno < volume->numcomps; compno++) { + opj_volume_comp_t *comp = &volume->comps[compno]; + char name[256]; + int nbytes = 0; + char *tmp = outfile; + while (*tmp) { + tmp++; + } + while (*tmp!='.') { + tmp--; + } + *tmp='\0'; + for(sliceno = 0; sliceno < volume->z1 - volume->z0; sliceno++) { + + if (volume->numcomps > 1) { + sprintf(name, "%s%d-%d.pgx", outfile, sliceno+1, compno); + } else if ((volume->z1 - volume->z0) > 1) { + sprintf(name, "%s%d.pgx", outfile, sliceno+1); + } else { + sprintf(name, "%s.pgx", outfile); + } + + fdest = fopen(name, "wb"); + if (!fdest) { + fprintf(stdout, "[ERROR] Failed to open %s for writing \n", name); + return 1; + } + + fprintf(stdout,"[INFO] Writing in %s (%s)\n",name,volume->comps[0].bigendian ? "Bigendian" : "Little-endian"); + + w = int_ceildiv(volume->x1 - volume->x0, volume->comps[compno].dx); + wr = volume->comps[compno].w; + wrr = int_ceildivpow2(volume->comps[compno].w, volume->comps[compno].factor[0]); + + h = int_ceildiv(volume->y1 - volume->y0, volume->comps[compno].dy); + hr = volume->comps[compno].h; + hrr = int_ceildivpow2(volume->comps[compno].h, volume->comps[compno].factor[1]); + + l = int_ceildiv(volume->z1 - volume->z0, volume->comps[compno].dz); + lr = volume->comps[compno].l; + lrr = int_ceildivpow2(volume->comps[compno].l, volume->comps[compno].factor[2]); + + fprintf(fdest, "PG %c%c %c%d %d %d\n", comp->bigendian ? 'M':'L', comp->bigendian ? 'L':'M',comp->sgnd ? '-' : '+', comp->prec, wr, hr); + if (comp->prec <= 8) { + nbytes = 1; + } else if (comp->prec <= 16) { + nbytes = 2; + } else { + nbytes = 4; + } + + offset = (sliceno / lrr * l) + (sliceno % lrr); + offset = wrr * hrr * offset; + //fprintf(stdout,"%d %d %d %d\n",offset,wrr*hrr,wrr,w); + for (i = 0; i < wrr * hrr; i++) { + int v = volume->comps[0].data[(i / wrr * w) + (i % wrr) + offset]; + if (volume->comps[0].bigendian) { + for (j = nbytes - 1; j >= 0; j--) { + char byte = (char) ((v >> (j * 8)) & 0xff); + fwrite(&byte, 1, 1, fdest); + } + } else { + for (j = 0; j <= nbytes - 1; j++) { + char byte = (char) ((v >> (j * 8)) & 0xff); + fwrite(&byte, 1, 1, fdest); + } + } + } + + fclose(fdest); + }//for sliceno + }//for compno + + return 0; +} + +/* -->> -->> -->> -->> + +BIN IMAGE FORMAT + +<<-- <<-- <<-- <<-- */ + +opj_volume_t* bintovolume(char *filename, char *fileimg, opj_cparameters_t *parameters) { + int subsampling_dx = parameters->subsampling_dx; + int subsampling_dy = parameters->subsampling_dy; + int subsampling_dz = parameters->subsampling_dz; + + int i, compno, w, h, l, numcomps = 1; + int prec, max = 0; + +// char temp[32]; + char line[100]; + int bigendian; + + FILE *f = NULL; + FILE *fimg = NULL; + OPJ_COLOR_SPACE color_space; + opj_volume_cmptparm_t cmptparm; /* maximum of 1 component */ + opj_volume_t * volume = NULL; + opj_volume_comp_t *comp = NULL; + + bigendian = 0; + color_space = CLRSPC_GRAY; + + fimg = fopen(fileimg,"r"); + if (!fimg) { + fprintf(stdout, "[ERROR] Failed to open %s for reading !!\n", fileimg); + return 0; + } + + fseek(fimg, 0, SEEK_SET); + while (!feof(fimg)) { + fgets(line,100,fimg); + //fprintf(stdout,"%s %d \n",line,feof(fimg)); + if (strncmp(line,"Bpp",3) == 0){ + sscanf(line,"%*s%*[ \t]%d",&prec); + } else if (strncmp(line,"Color",5) == 0){ + sscanf(line, "%*s%*[ \t]%d",&color_space); + } else if (strncmp(line,"Dim",3) == 0){ + sscanf(line, "%*s%*[ \t]%d%*[ \t]%d%*[ \t]%d",&w,&h,&l); + } + } + //fscanf(fimg, "Bpp%[ \t]%d%[ \t\n]",temp,&prec,temp); + //fscanf(fimg, "Color Map%[ \t]%d%[ \n\t]Dimensions%[ \t]%d%[ \t]%d%[ \t]%d%[ \n\t]",temp,&color_space,temp,temp,&w,temp,&h,temp,&l,temp); + //fscanf(fimg, "Resolution(mm)%[ \t]%d%[ \t]%d%[ \t]%d%[ \n\t]",temp,&subsampling_dx,temp,&subsampling_dy,temp,&subsampling_dz,temp); + + #ifdef VERBOSE + fprintf(stdout, "[INFO] %d \t %d %d %d \t %3.2f %2.2f %2.2f \t %d \n",color_space,w,h,l,subsampling_dx,subsampling_dy,subsampling_dz,prec); + #endif + fclose(fimg); + + /* initialize volume components */ + memset(&cmptparm, 0, sizeof(opj_volume_cmptparm_t)); + + cmptparm.prec = prec; + cmptparm.bpp = prec; + cmptparm.sgnd = 0; + cmptparm.bigendian = bigendian; + cmptparm.dcoffset = parameters->dcoffset; + cmptparm.dx = subsampling_dx; + cmptparm.dy = subsampling_dy; + cmptparm.dz = subsampling_dz; + cmptparm.w = w; + cmptparm.h = h; + cmptparm.l = l; + + /* create the volume */ + volume = opj_volume_create(numcomps, &cmptparm, color_space); + if(!volume) { + fprintf(stdout,"[ERROR] Unable to create volume"); + fclose(f); + return NULL; + } + + /* set volume offset and reference grid */ + volume->x0 = parameters->volume_offset_x0; + volume->y0 = parameters->volume_offset_y0; + volume->z0 = parameters->volume_offset_z0; + volume->x1 = parameters->volume_offset_x0 + (w - 1) * subsampling_dx + 1; + volume->y1 = parameters->volume_offset_y0 + (h - 1) * subsampling_dy + 1; + volume->z1 = parameters->volume_offset_z0 + (l - 1) * subsampling_dz + 1; + + /* set volume data */ + f = fopen(filename, "rb"); + if (!f) { + fprintf(stdout, "[ERROR] Failed to open %s for reading !!\n", filename); + return 0; + } + + /* BINARY */ + for (compno = 0; compno < volume->numcomps; compno++) { + int whl = w * h * l; + /* set volume data */ + comp = &volume->comps[compno]; + + /*if (comp->prec <= 8) { + if (!comp->sgnd) { + unsigned char *data = (unsigned char *) malloc(whl * sizeof(unsigned char)); + fread(data, 1, whl, f); + for (i = 0; i < whl; i++) { + comp->data[i] = data[i]; + if (comp->data[i] > max) + max = comp->data[i]; + } + free(data); + } else { + char *data = (char *) malloc(whl); + fread(data, 1, whl, f); + for (i = 0; i < whl; i++) { + comp->data[i] = data[i]; + if (comp->data[i] > max) + max = comp->data[i]; + } + free(data); + } + } else if (comp->prec <= 16) { + if (!comp->sgnd) { + unsigned short *data = (unsigned short *) malloc(whl * sizeof(unsigned short)); + int leido = fread(data, 2, whl, f); + if (!leido) { + free(data); fclose(f); + return NULL; + } + + for (i = 0; i < whl; i++) { + if (bigendian) //(c1 << 8) + c2; + comp->data[i] = data[i]; + else{ //(c2 << 8) + c1; + comp->data[i] = ShortSwap(data[i]); + } + if (comp->data[i] > max) + max = comp->data[i]; + } + free(data); + } else { + short *data = (short *) malloc(whl); + int leido = fread(data, 2, whl, f); + if (!leido) { + free(data); fclose(f); + return NULL; + } + for (i = 0; i < whl; i++) { + if (bigendian){ //(c1 << 8) + c2; + comp->data[i] = data[i]; + }else{ //(c2 << 8) + c1; + comp->data[i] = (short) ShortSwap((unsigned short) data[i]); + } + if (comp->data[i] > max) + max = comp->data[i]; + } + free(data); + } + } else { + if (!comp->sgnd) { + unsigned int *data = (unsigned int *) malloc(whl * sizeof(unsigned int)); + int leido = fread(data, 4, whl, f); + if (!leido) { + free(data); fclose(f); + return NULL; + } for (i = 0; i < whl; i++) { + if (!bigendian) + comp->data[i] = LongSwap(data[i]); + else + comp->data[i] = data[i]; + if (comp->data[i] > max) + max = comp->data[i]; + } + free(data); + } else { + int leido = fread(comp->data, 4, whl, f); + if (!leido) { + fclose(f); + return NULL; + } + for (i = 0; i < whl; i++) { + if (!bigendian) + comp->data[i] = (int) LongSwap((unsigned int) comp->data[i]); + if (comp->data[i] > max) + max = comp->data[i]; + } + } + }*/ + + for (i = 0; i < whl; i++) { + int v; + if (comp->prec <= 8) { + if (!comp->sgnd) { + v = readuchar(f); + } else { + v = (char) readuchar(f); + } + } else if (comp->prec <= 16) { + if (!comp->sgnd) { + v = readushort(f, bigendian); + } else { + v = (short) readushort(f, bigendian); + } + } else { + if (!comp->sgnd) { + v = readuint(f, bigendian); + } else { + v = (int) readuint(f, bigendian); + } + } + if (v > max) + max = v; + comp->data[i] = v; + } + comp->bpp = int_floorlog2(max) + 1; + } + fclose(f); + return volume; +} + +int volumetobin(opj_volume_t * volume, char *outfile) { + int w, wr, wrr, h, hr, hrr, l, lr, lrr, max; + int i,j, compno, nbytes; + int offset, sliceno; + FILE *fdest = NULL; + FILE *fimgdest = NULL; +// char *imgtemp; + char name[256]; + + for (compno = 0; compno < 1; compno++) { //Only one component + + fdest = fopen(outfile, "wb"); + if (!fdest) { + fprintf(stdout, "[ERROR] Failed to open %s for writing\n", outfile); + return 1; + } + fprintf(stdout,"[INFO] Writing outfile %s (%s) \n",outfile, volume->comps[0].bigendian ? "Bigendian" : "Little-endian"); + + w = int_ceildiv(volume->x1 - volume->x0, volume->comps[compno].dx); + wr = volume->comps[compno].w; + wrr = int_ceildivpow2(volume->comps[compno].w, volume->comps[compno].factor[0]); + + h = int_ceildiv(volume->y1 - volume->y0, volume->comps[compno].dy); + hr = volume->comps[compno].h; + hrr = int_ceildivpow2(volume->comps[compno].h, volume->comps[compno].factor[1]); + + l = int_ceildiv(volume->z1 - volume->z0, volume->comps[compno].dz); + lr = volume->comps[compno].l; + lrr = int_ceildivpow2(volume->comps[compno].l, volume->comps[compno].factor[2]); + + max = (volume->comps[compno].prec <= 8) ? 255 : (1 << volume->comps[compno].prec) - 1; + + volume->comps[compno].x0 = int_ceildivpow2(volume->comps[compno].x0 - int_ceildiv(volume->x0, volume->comps[compno].dx), volume->comps[compno].factor[0]); + volume->comps[compno].y0 = int_ceildivpow2(volume->comps[compno].y0 - int_ceildiv(volume->y0, volume->comps[compno].dy), volume->comps[compno].factor[1]); + volume->comps[compno].z0 = int_ceildivpow2(volume->comps[compno].z0 - int_ceildiv(volume->z0, volume->comps[compno].dz), volume->comps[compno].factor[2]); + + if (volume->comps[0].prec <= 8) { + nbytes = 1; + } else if (volume->comps[0].prec <= 16) { + nbytes = 2; + } else { + nbytes = 4; + } + + //fprintf(stdout,"w %d wr %d wrr %d h %d hr %d hrr %d l %d lr %d lrr %d max %d nbytes %d\n Factor %d %d %d",w,wr,wrr,h,hr,hrr,l,lr,lrr,max,nbytes,volume->comps[compno].factor[0],volume->comps[compno].factor[1],volume->comps[compno].factor[2]); + + for(sliceno = 0; sliceno < lrr; sliceno++) { + offset = (sliceno / lrr * l) + (sliceno % lrr); + offset = wrr * hrr * offset; + for (i = 0; i < wrr * hrr; i++) { + int v = volume->comps[0].data[(i / wrr * w) + (i % wrr) + offset]; + if (volume->comps[0].bigendian) { + for (j = nbytes - 1; j >= 0; j--) { + char byte = (char) ((v >> (j * 8)) & 0xff); + fwrite(&byte, 1, 1, fdest); + } + } else { + for (j = 0; j <= nbytes - 1; j++) { + char byte = (char) ((v >> (j * 8)) & 0xff); + fwrite(&byte, 1, 1, fdest); + } + } + } + } + + } + + fclose(fdest); + + sprintf(name,"%s.img",outfile); + fimgdest = fopen(name, "w"); + if (!fimgdest) { + fprintf(stdout, "[ERROR] Failed to open %s for writing\n", name); + return 1; + } + fprintf(fimgdest, "Bpp\t%d\nColor Map\t2\nDimensions\t%d\t%d\t%d\nResolution(mm)\t%d\t%d\t%d\t\n", + volume->comps[0].prec,wrr,hrr,lrr,volume->comps[0].dx,volume->comps[0].dy,volume->comps[0].dz); + + fclose(fimgdest); + return 0; +} +/* -->> -->> -->> -->> + +IMG IMAGE FORMAT + +<<-- <<-- <<-- <<-- */ +opj_volume_t* imgtovolume(char *fileimg, opj_cparameters_t *parameters) { + int subsampling_dx = parameters->subsampling_dx; + int subsampling_dy = parameters->subsampling_dy; + int subsampling_dz = parameters->subsampling_dz; + + int i, compno, w, h, l, numcomps = 1; + int prec, max = 0, min = 0; + float dx, dy, dz; + char filename[100], tmpdirpath[100], dirpath[100], *tmp; + char line[100], datatype[100]; + int bigendian; + + FILE *f = NULL; + FILE *fimg = NULL; + OPJ_COLOR_SPACE color_space; + opj_volume_cmptparm_t cmptparm; /* maximum of 1 component */ + opj_volume_t * volume = NULL; + opj_volume_comp_t *comp = NULL; + + bigendian = 0; + color_space = CLRSPC_GRAY; + + fimg = fopen(fileimg,"r"); + if (!fimg) { + fprintf(stderr, "[ERROR] Failed to open %s for reading !!\n", fileimg); + return 0; + } + + //Fetch only the path + strcpy(tmpdirpath,fileimg); + if ((tmp = strrchr(tmpdirpath,'/')) != NULL){ + tmp++; *tmp='\0'; + strcpy(dirpath,tmpdirpath); + } else { + strcpy(dirpath,"./"); + } + + fseek(fimg, 0, SEEK_SET); + while (!feof(fimg)) { + fgets(line,100,fimg); + //fprintf(stdout,"%s %d \n",line,feof(fimg)); + if (strncmp(line,"Image",5) == 0){ + sscanf(line,"%*s%*[ \t]%s",datatype); + } else if (strncmp(line,"File",4) == 0){ + sscanf(line,"%*s %*s%*[ \t]%s",filename); + strcat(dirpath, filename); + strcpy(filename,dirpath); + } else if (strncmp(line,"Min",3) == 0){ + sscanf(line,"%*s %*s%*[ \t]%d%*[ \t]%d",&min,&max); + prec = int_floorlog2(max - min + 1); + } else if (strncmp(line,"Bpp",3) == 0){ + sscanf(line,"%*s%*[ \t]%d",&prec); + } else if (strncmp(line,"Color",5) == 0){ + sscanf(line, "%*s %*s%*[ \t]%d",&color_space); + } else if (strncmp(line,"Dim",3) == 0){ + sscanf(line, "%*s%*[ \t]%d%*[ \t]%d%*[ \t]%d",&w,&h,&l); + } else if (strncmp(line,"Res",3) == 0){ + sscanf(line,"%*s%*[ \t]%f%*[ \t]%f%*[ \t]%f",&dx,&dy,&dz); + } + + } + #ifdef VERBOSE + fprintf(stdout, "[INFO] %s %d \t %d %d %d \t %f %f %f \t %d %d %d \n",filename,color_space,w,h,l,dx,dy,dz,max,min,prec); + #endif + fclose(fimg); + + /* error control */ + if ( !prec || !w || !h || !l ){ + fprintf(stderr,"[ERROR] Unable to read IMG file correctly. Found some null values."); + return NULL; + } + + /* initialize volume components */ + memset(&cmptparm, 0, sizeof(opj_volume_cmptparm_t)); + + cmptparm.prec = prec; + cmptparm.bpp = prec; + cmptparm.sgnd = 0; + cmptparm.bigendian = bigendian; + cmptparm.dcoffset = parameters->dcoffset; + cmptparm.dx = subsampling_dx; + cmptparm.dy = subsampling_dy; + cmptparm.dz = subsampling_dz; + cmptparm.w = w; + cmptparm.h = h; + cmptparm.l = l; + + /* create the volume */ + volume = opj_volume_create(numcomps, &cmptparm, color_space); + if(!volume) { + fprintf(stdout,"[ERROR] Unable to create volume"); + return NULL; + } + + /* set volume offset and reference grid */ + volume->x0 = parameters->volume_offset_x0; + volume->y0 = parameters->volume_offset_y0; + volume->z0 = parameters->volume_offset_z0; + volume->x1 = parameters->volume_offset_x0 + (w - 1) * subsampling_dx + 1; + volume->y1 = parameters->volume_offset_y0 + (h - 1) * subsampling_dy + 1; + volume->z1 = parameters->volume_offset_z0 + (l - 1) * subsampling_dz + 1; + + max = 0; + /* set volume data */ + f = fopen(filename, "rb"); + if (!f) { + fprintf(stderr, "[ERROR] Failed to open %s for reading !!\n", filename); + fclose(f); + return 0; + } + + /* BINARY */ + for (compno = 0; compno < volume->numcomps; compno++) { + int whl = w * h * l; + /* set volume data */ + comp = &volume->comps[compno]; + + /*if (comp->prec <= 8) { + if (!comp->sgnd) { + unsigned char *data = (unsigned char *) malloc(whl * sizeof(unsigned char)); + fread(data, 1, whl, f); + for (i = 0; i < whl; i++) { + comp->data[i] = data[i]; + if (comp->data[i] > max) + max = comp->data[i]; + } + free(data); + } else { + char *data = (char *) malloc(whl); + fread(data, 1, whl, f); + for (i = 0; i < whl; i++) { + comp->data[i] = data[i]; + if (comp->data[i] > max) + max = comp->data[i]; + } + free(data); + } + } else if (comp->prec <= 16) { + if (!comp->sgnd) { + unsigned short *data = (unsigned short *) malloc(whl * sizeof(unsigned short)); + int leido = fread(data, 2, whl, f); + if (!leido) { + free(data); fclose(f); + return NULL; + } + + for (i = 0; i < whl; i++) { + if (bigendian) //(c1 << 8) + c2; + comp->data[i] = data[i]; + else{ //(c2 << 8) + c1; + comp->data[i] = ShortSwap(data[i]); + } + if (comp->data[i] > max) + max = comp->data[i]; + } + free(data); + } else { + short *data = (short *) malloc(whl); + int leido = fread(data, 2, whl, f); + if (!leido) { + free(data); fclose(f); + return NULL; + } + for (i = 0; i < whl; i++) { + if (bigendian){ //(c1 << 8) + c2; + comp->data[i] = data[i]; + }else{ //(c2 << 8) + c1; + comp->data[i] = (short) ShortSwap((unsigned short) data[i]); + } + if (comp->data[i] > max) + max = comp->data[i]; + } + free(data); + } + } else { + if (!comp->sgnd) { + unsigned int *data = (unsigned int *) malloc(whl * sizeof(unsigned int)); + int leido = fread(data, 4, whl, f); + if (!leido) { + free(data); fclose(f); + return NULL; + } for (i = 0; i < whl; i++) { + if (!bigendian) + comp->data[i] = LongSwap(data[i]); + else + comp->data[i] = data[i]; + if (comp->data[i] > max) + max = comp->data[i]; + } + free(data); + } else { + int leido = fread(comp->data, 4, whl, f); + if (!leido) { + fclose(f); + return NULL; + } + for (i = 0; i < whl; i++) { + if (!bigendian) + comp->data[i] = (int) LongSwap((unsigned int) comp->data[i]); + if (comp->data[i] > max) + max = comp->data[i]; + } + } + }*/ + + for (i = 0; i < whl; i++) { + int v; + if (comp->prec <= 8) { + if (!comp->sgnd) { + v = readuchar(f); + } else { + v = (char) readuchar(f); + } + } else if (comp->prec <= 16) { + if (!comp->sgnd) { + v = readushort(f, bigendian); + } else { + v = (short) readushort(f, bigendian); + } + } else { + if (!comp->sgnd) { + v = readuint(f, bigendian); + } else { + v = (int) readuint(f, bigendian); + } + } + if (v > max) + max = v; + comp->data[i] = v; + } + comp->bpp = int_floorlog2(max) + 1; + } + fclose(f); + return volume; +} + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/convert.h b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/convert.h new file mode 100644 index 0000000..95640b1 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/convert.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, HervŽ Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * Copyright (c) 2006, Mónica Díez García, Image Processing Laboratory, University of Valladolid, Spain + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __JP3D_CONVERT_H +#define __JP3D_CONVERT_H + +/** +Load a single volume component encoded in PGX file format +@param filename Name of the PGX file to load +@param parameters *List ?* +@return Returns a greyscale volume if successful, returns NULL otherwise +*/ +opj_volume_t* pgxtovolume(char *filename, opj_cparameters_t *parameters); + +int volumetopgx(opj_volume_t *volume, char *outfile); + +opj_volume_t* bintovolume(char *filename,char *fileimg, opj_cparameters_t *parameters); + +int volumetobin(opj_volume_t *volume, char *outfile); + +opj_volume_t* imgtovolume(char *fileimg, opj_cparameters_t *parameters); + +#endif /* __J2K_CONVERT_H */ + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/getopt.c b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/getopt.c new file mode 100644 index 0000000..1672d1c --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/getopt.c @@ -0,0 +1,109 @@ +/* + * Copyright (c) 1987, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* last review : october 29th, 2002 */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)getopt.c 8.3 (Berkeley) 4/27/95"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include + +int opterr = 1, /* if error message should be printed */ + optind = 1, /* index into parent argv vector */ + optopt, /* character checked for validity */ + optreset; /* reset getopt */ +char *optarg; /* argument associated with option */ + +#define BADCH (int)'?' +#define BADARG (int)':' +#define EMSG "" + +/* + * getopt -- + * Parse argc/argv argument vector. + */ +int getopt(int nargc, char *const *nargv, const char *ostr) { + + # define __progname nargv[0] /* program name */ + + static char *place = EMSG; /* option letter processing */ + char *oli; /* option letter list index */ + + if (optreset || !*place) { /* update scanning pointer */ + optreset = 0; + if (optind >= nargc || *(place = nargv[optind]) != '-') { + place = EMSG; + return (-1); + } + if (place[1] && *++place == '-') { /* found "--" */ + ++optind; + place = EMSG; + return (-1); + } + } /* option letter okay? */ + + if ((optopt = (int) *place++) == (int) ':' || !(oli = strchr(ostr, optopt))) { + /* if the user didn't specify '-' as an option, assume it means -1. */ + if (optopt == (int) '-') + return (-1); + if (!*place) + ++optind; + if (opterr && *ostr != ':') + (void) fprintf(stdout,"[ERROR] %s: illegal option -- %c\n", __progname, optopt); + return (BADCH); + } + + if (*++oli != ':') { /* don't need argument */ + optarg = NULL; + if (!*place) + ++optind; + } else { /* need an argument */ + if (*place) /* no white space */ + optarg = place; + else if (nargc <= ++optind) { /* no arg */ + place = EMSG; + if (*ostr == ':') + return (BADARG); + if (opterr) + (void) fprintf(stdout, "[ERROR] %s: option requires an argument -- %c\n", __progname, optopt); + return (BADCH); + } else /* white space */ + optarg = nargv[optind]; + place = EMSG; + ++optind; + } + return (optopt); /* dump back option letter */ +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/getopt.h b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/getopt.h new file mode 100644 index 0000000..ab9c1a7 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/getopt.h @@ -0,0 +1,14 @@ +/* last review : october 29th, 2002 */ + +#ifndef _GETOPT_H_ +#define _GETOPT_H_ + +extern int opterr; +extern int optind; +extern int optopt; +extern int optreset; +extern char *optarg; + +extern int getopt(int nargc, char *const *nargv, const char *ostr); + +#endif /* _GETOPT_H_ */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/jp3d_to_volume.c b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/jp3d_to_volume.c new file mode 100644 index 0000000..80d5b71 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/jp3d_to_volume.c @@ -0,0 +1,540 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * Copyright (c) 2006, Mónica Díez García, Image Processing Laboratory, University of Valladolid, Spain + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include + +#include "../libjp3dvm/openjpeg3d.h" +#include "getopt.h" +#include "convert.h" + +#ifdef _WIN32 +#include +#else +#define stricmp strcasecmp +#define strnicmp strncasecmp +#endif /* _WIN32 */ + +/* ----------------------------------------------------------------------- */ +static double calc_PSNR(opj_volume_t *original, opj_volume_t *decoded) +{ + int max, i, k, compno = 0, size; + double sum, total = 0; + int global = 1; + + max = (original->comps[compno].prec <= 8) ? 255 : (1 << original->comps[compno].prec) - 1; + if (global) { + size = (original->x1 - original->x0) * (original->y1 - original->y0) * (original->z1 - original->z0); + + for (compno = 0; compno < original->numcomps; compno++) { + for(sum = 0, i = 0; i < size; ++i) { + if ((decoded->comps[compno].data[i] < 0) || (decoded->comps[compno].data[i] > max)) + fprintf(stdout,"[WARNING] Data out of range during PSNR computing...\n"); + else + sum += (original->comps[compno].data[i] - decoded->comps[compno].data[i]) * (original->comps[compno].data[i] - decoded->comps[compno].data[i]); + } + } + sum /= size; + total = ((sum==0.0) ? 0.0 : 10 * log10(max * max / sum)); + } else { + size = (original->x1 - original->x0) * (original->y1 - original->y0); + + for (k = 0; k < original->z1 - original->z0; k++) { + int offset = k * size; + for (sum = 0, compno = 0; compno < original->numcomps; compno++) { + for(i = 0; i < size; ++i) { + if ((decoded->comps[compno].data[i + offset] < 0) || (decoded->comps[compno].data[i + offset] > max)) + fprintf(stdout,"[WARNING] Data out of range during PSNR computing...\n"); + else + sum += (original->comps[compno].data[i + offset] - decoded->comps[compno].data[i + offset]) * (original->comps[compno].data[i + offset] - decoded->comps[compno].data[i + offset]); + } + } + sum /= size; + total = total + ((sum==0.0) ? 0.0 : 10 * log10(max * max / sum)); + } + + } + if(total == 0) /* perfect reconstruction, PSNR should return infinity */ + return -1.0; + + return total; + //return 20 * log10((max - 1) / sqrt(sum)); +} + +static double calc_SSIM(opj_volume_t *original, opj_volume_t *decoded) +{ + int max, i, compno = 0, size, sizeM; + double sum; + double mux = 0.0, muy = 0.0, sigmax = 0.0, sigmay = 0.0, + sigmaxy = 0.0, structx = 0.0, structy = 0.0; + double lcomp,ccomp,scomp; + double C1,C2,C3; + + max = (original->comps[compno].prec <= 8) ? 255 : (1 << original->comps[compno].prec) - 1; + size = (original->x1 - original->x0) * (original->y1 - original->y0) * (original->z1 - original->z0); + + //MSSIM + +// sizeM = size / (original->z1 - original->z0); + + sizeM = size; + for(sum = 0, i = 0; i < sizeM; ++i) { + // First, the luminance of each signal is compared. + mux += original->comps[compno].data[i]; + muy += decoded->comps[compno].data[i]; + } + mux /= sizeM; + muy /= sizeM; + + //We use the standard deviation (the square root of variance) as an estimate of the signal contrast. + for(sum = 0, i = 0; i < sizeM; ++i) { + // First, the luminance of each signal is compared. + sigmax += (original->comps[compno].data[i] - mux) * (original->comps[compno].data[i] - mux); + sigmay += (decoded->comps[compno].data[i] - muy) * (decoded->comps[compno].data[i] - muy); + sigmaxy += (original->comps[compno].data[i] - mux) * (decoded->comps[compno].data[i] - muy); + } + sigmax /= sizeM - 1; + sigmay /= sizeM - 1; + sigmaxy /= sizeM - 1; + + sigmax = sqrt(sigmax); + sigmay = sqrt(sigmay); + sigmaxy = sqrt(sigmaxy); + + //Third, the signal is normalized (divided) by its own standard deviation, + //so that the two signals being compared have unit standard deviation. + + //Luminance comparison + C1 = (0.01 * max) * (0.01 * max); + lcomp = ((2 * mux * muy) + C1)/((mux*mux) + (muy*mux) + C1); + //Constrast comparison + C2 = (0.03 * max) * (0.03 * max); + ccomp = ((2 * sigmax * sigmay) + C2)/((sigmax*sigmax) + (sigmay*sigmay) + C2); + //Structure comparison + C3 = C2 / 2; + scomp = (sigmaxy + C3) / (sigmax * sigmay + C3); + //Similarity measure + + sum = lcomp * ccomp * scomp; + return sum; +} + +void decode_help_display() { + fprintf(stdout,"HELP\n----\n\n"); + fprintf(stdout,"- the -h option displays this help information on screen\n\n"); + + fprintf(stdout,"List of parameters for the JPEG 2000 encoder:\n"); + fprintf(stdout,"\n"); + fprintf(stdout," Required arguments \n"); + fprintf(stdout," ---------------------------- \n"); + fprintf(stdout," -i ( *.jp3d, *.j3d )\n"); + fprintf(stdout," Currently accepts J3D-files. The file type is identified based on its suffix.\n"); + fprintf(stdout," -o ( *.pgx, *.bin )\n"); + fprintf(stdout," Currently accepts PGX-files and BIN-files. Binary data is written to the file (not ascii). \n"); + fprintf(stdout," If a PGX filename is given, there will be as many output files as slices; \n"); + fprintf(stdout," an indice starting from 0 will then be appended to the output filename,\n"); + fprintf(stdout," just before the \"pgx\" extension.\n"); + fprintf(stdout," -m ( *.img ) \n"); + fprintf(stdout," Required only for BIN-files. Ascii data of volume characteristics is written. \n"); + fprintf(stdout,"\n"); + fprintf(stdout," Optional \n"); + fprintf(stdout," ---------------------------- \n"); + fprintf(stdout," -h \n "); + fprintf(stdout," Display the help information\n"); + fprintf(stdout," -r \n"); + fprintf(stdout," Set the number of highest resolution levels to be discarded on each dimension. \n"); + fprintf(stdout," The volume resolution is effectively divided by 2 to the power of the\n"); + fprintf(stdout," number of discarded levels. The reduce factor is limited by the\n"); + fprintf(stdout," smallest total number of decomposition levels among tiles.\n"); + fprintf(stdout," -l \n"); + fprintf(stdout," Set the maximum number of quality layers to decode. If there are\n"); + fprintf(stdout," less quality layers than the specified number, all the quality layers\n"); + fprintf(stdout," are decoded. \n"); + fprintf(stdout," -O original-file \n"); + fprintf(stdout," This option offers the possibility to compute some quality results \n"); + fprintf(stdout," for the decompressed volume, like the PSNR value achieved or the global SSIM value. \n"); + fprintf(stdout," Needs the original file in order to compare with the new one.\n"); + fprintf(stdout," NOTE: Only valid when -r option is 0,0,0 (both original and decompressed volumes have same resolutions) \n"); + fprintf(stdout," NOTE: If original file is .BIN file, the volume characteristics file shall be defined with the -m option. \n"); + fprintf(stdout," (i.e. -O original-BIN-file -m original-IMG-file) \n"); + fprintf(stdout," -BE \n"); + fprintf(stdout," Define that the recovered volume data will be saved with big endian byte order.\n"); + fprintf(stdout," By default, little endian byte order is used.\n"); + fprintf(stdout,"\n"); +} + +/* -------------------------------------------------------------------------- */ + +int get_file_format(char *filename) { + int i; + static const char *extension[] = {"pgx", "bin", "j3d", "jp3d", "j2k", "img"}; + static const int format[] = { PGX_DFMT, BIN_DFMT, J3D_CFMT, J3D_CFMT, J2K_CFMT, IMG_DFMT}; + char * ext = strrchr(filename, '.'); + if(ext) { + ext++; + for(i = 0; i < sizeof(format) / sizeof(format[0]); i++) { + if(strnicmp(ext, extension[i], 3) == 0) { + return format[i]; + } + } + } + + return -1; +} + +/* -------------------------------------------------------------------------- */ + +int parse_cmdline_decoder(int argc, char **argv, opj_dparameters_t *parameters) { + /* parse the command line */ + + while (1) { + int c = getopt(argc, argv, "i:o:O:r:l:B:m:h"); + if (c == -1) + break; + switch (c) { + case 'i': /* input file */ + { + char *infile = optarg; + parameters->decod_format = get_file_format(infile); + switch(parameters->decod_format) { + case J3D_CFMT: + case J2K_CFMT: + break; + default: + fprintf(stdout, "[ERROR] Unknown format for infile %s [only *.j3d]!! \n", infile); + return 1; + break; + } + strncpy(parameters->infile, infile, MAX_PATH); + fprintf(stdout, "[INFO] Infile: %s \n", parameters->infile); + + } + break; + + case 'm': /* img file */ + { + char *imgfile = optarg; + int imgformat = get_file_format(imgfile); + switch(imgformat) { + case IMG_DFMT: + break; + default: + fprintf(stdout, "[ERROR] Unrecognized format for imgfile : %s [accept only *.img] !!\n\n", imgfile); + return 1; + break; + } + strncpy(parameters->imgfile, imgfile, MAX_PATH); + fprintf(stdout, "[INFO] Imgfile: %s Format: %d\n", parameters->imgfile, imgformat); + } + break; + + /* ----------------------------------------------------- */ + + case 'o': /* output file */ + { + char *outfile = optarg; + parameters->cod_format = get_file_format(outfile); + switch(parameters->cod_format) { + case PGX_DFMT: + case BIN_DFMT: + break; + default: + fprintf(stdout, "[ERROR] Unrecognized format for outfile : %s [accept only *.pgx or *.bin] !!\n\n", outfile); + return 1; + break; + } + strncpy(parameters->outfile, outfile, MAX_PATH); + fprintf(stdout, "[INFO] Outfile: %s \n", parameters->outfile); + + } + break; + + /* ----------------------------------------------------- */ + + case 'O': /* Original image for PSNR computing */ + { + char *original = optarg; + parameters->orig_format = get_file_format(original); + switch(parameters->orig_format) { + case PGX_DFMT: + case BIN_DFMT: + break; + default: + fprintf(stdout, "[ERROR] Unrecognized format for original file : %s [accept only *.pgx or *.bin] !!\n\n", original); + return 1; + break; + } + strncpy(parameters->original, original, MAX_PATH); + fprintf(stdout, "[INFO] Original file: %s \n", parameters->original); + } + break; + + /* ----------------------------------------------------- */ + + case 'r': /* reduce option */ + { + //sscanf(optarg, "%d, %d, %d", ¶meters->cp_reduce[0], ¶meters->cp_reduce[1], ¶meters->cp_reduce[2]); + int aux; + aux = sscanf(optarg, "%d,%d,%d", ¶meters->cp_reduce[0], ¶meters->cp_reduce[1], ¶meters->cp_reduce[2]); + if (aux == 2) + parameters->cp_reduce[2] = 0; + else if (aux == 1) { + parameters->cp_reduce[1] = parameters->cp_reduce[0]; + parameters->cp_reduce[2] = 0; + }else if (aux == 0){ + parameters->cp_reduce[0] = 0; + parameters->cp_reduce[1] = 0; + parameters->cp_reduce[2] = 0; + } + } + break; + + /* ----------------------------------------------------- */ + + case 'l': /* layering option */ + { + sscanf(optarg, "%d", ¶meters->cp_layer); + } + break; + + /* ----------------------------------------------------- */ + + case 'B': /* BIGENDIAN vs. LITTLEENDIAN */ + { + parameters->bigendian = 1; + } + break; + + /* ----------------------------------------------------- */ + + case 'L': /* BIGENDIAN vs. LITTLEENDIAN */ + { + parameters->decod_format = LSE_CFMT; + } + break; + + /* ----------------------------------------------------- */ + + case 'h': /* display an help description */ + { + decode_help_display(); + return 1; + } + break; + + /* ----------------------------------------------------- */ + + default: + fprintf(stdout,"[WARNING] This option is not valid \"-%c %s\"\n",c, optarg); + break; + } + } + + /* check for possible errors */ + + if((parameters->infile[0] == 0) || (parameters->outfile[0] == 0)) { + fprintf(stdout,"[ERROR] At least one required argument is missing\n Check jp3d_to_volume -help for usage information\n"); + return 1; + } + + return 0; +} + +/* -------------------------------------------------------------------------- */ + +/** +sample error callback expecting a FILE* client object +*/ +void error_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[ERROR] %s", msg); +} +/** +sample warning callback expecting a FILE* client object +*/ +void warning_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[WARNING] %s", msg); +} +/** +sample debug callback expecting no client object +*/ +void info_callback(const char *msg, void *client_data) { + fprintf(stdout, "[INFO] %s", msg); +} + +/* -------------------------------------------------------------------------- */ + +int main(int argc, char **argv) { + + opj_dparameters_t parameters; /* decompression parameters */ + opj_event_mgr_t event_mgr; /* event manager */ + opj_volume_t *volume = NULL; + + opj_volume_t *original = NULL; + opj_cparameters_t cparameters; /* original parameters */ + + FILE *fsrc = NULL; + unsigned char *src = NULL; + int file_length; + int decodeok; + double psnr, ssim; + + opj_dinfo_t* dinfo = NULL; /* handle to a decompressor */ + opj_cio_t *cio = NULL; + + /* configure the event callbacks (not required) */ + memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); + event_mgr.error_handler = error_callback; + event_mgr.warning_handler = warning_callback; + event_mgr.info_handler = info_callback; + + /* set decoding parameters to default values */ + opj_set_default_decoder_parameters(¶meters); + + /* parse input and get user decoding parameters */ + strcpy(parameters.original,"NULL"); + strcpy(parameters.imgfile,"NULL"); + if(parse_cmdline_decoder(argc, argv, ¶meters) == 1) { + return 0; + } + + /* read the input file and put it in memory */ + /* ---------------------------------------- */ + fprintf(stdout, "[INFO] Loading %s file \n",parameters.decod_format==J3D_CFMT ? ".jp3d" : ".j2k"); + fsrc = fopen(parameters.infile, "rb"); + if (!fsrc) { + fprintf(stdout, "[ERROR] Failed to open %s for reading\n", parameters.infile); + return 1; + } + fseek(fsrc, 0, SEEK_END); + file_length = ftell(fsrc); + fseek(fsrc, 0, SEEK_SET); + src = (unsigned char *) malloc(file_length); + fread(src, 1, file_length, fsrc); + fclose(fsrc); + + /* decode the code-stream */ + /* ---------------------- */ + if (parameters.decod_format == J3D_CFMT || parameters.decod_format == J2K_CFMT) { + /* get a JP3D or J2K decoder handle */ + if (parameters.decod_format == J3D_CFMT) + dinfo = opj_create_decompress(CODEC_J3D); + else if (parameters.decod_format == J2K_CFMT) + dinfo = opj_create_decompress(CODEC_J2K); + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr); + + /* setup the decoder decoding parameters using user parameters */ + opj_setup_decoder(dinfo, ¶meters); + + /* open a byte stream */ + cio = opj_cio_open((opj_common_ptr)dinfo, src, file_length); + + /* decode the stream and fill the volume structure */ + volume = opj_decode(dinfo, cio); + if(!volume) { + fprintf(stdout, "[ERROR] jp3d_to_volume: failed to decode volume!\n"); + opj_destroy_decompress(dinfo); + opj_cio_close(cio); + return 1; + } + + /* close the byte stream */ + opj_cio_close(cio); + } + + /* free the memory containing the code-stream */ + free(src); + src = NULL; + + /* create output volume */ + /* ------------------- */ + + switch (parameters.cod_format) { + case PGX_DFMT: /* PGX */ + decodeok = volumetopgx(volume, parameters.outfile); + if (decodeok) + fprintf(stdout,"[ERROR] Unable to write decoded volume into pgx files\n"); + break; + + case BIN_DFMT: /* BMP */ + decodeok = volumetobin(volume, parameters.outfile); + if (decodeok) + fprintf(stdout,"[ERROR] Unable to write decoded volume into pgx files\n"); + break; + } + switch (parameters.orig_format) { + case PGX_DFMT: /* PGX */ + if (strcmp("NULL",parameters.original) != 0){ + fprintf(stdout,"Loading original file %s \n",parameters.original); + cparameters.subsampling_dx = 1; cparameters.subsampling_dy = 1; cparameters.subsampling_dz = 1; + cparameters.volume_offset_x0 = 0;cparameters.volume_offset_y0 = 0;cparameters.volume_offset_z0 = 0; + original = pgxtovolume(parameters.original,&cparameters); + } + break; + + case BIN_DFMT: /* BMP */ + if (strcmp("NULL",parameters.original) != 0 && strcmp("NULL",parameters.imgfile) != 0){ + fprintf(stdout,"Loading original file %s %s\n",parameters.original,parameters.imgfile); + cparameters.subsampling_dx = 1; cparameters.subsampling_dy = 1; cparameters.subsampling_dz = 1; + cparameters.volume_offset_x0 = 0;cparameters.volume_offset_y0 = 0;cparameters.volume_offset_z0 = 0; + original = bintovolume(parameters.original,parameters.imgfile,&cparameters); + } + break; + } + + fprintf(stdout, "[RESULT] Volume: %d x %d x %d (x %d bpv)\n ", + (volume->comps[0].w >> volume->comps[0].factor[0]), + (volume->comps[0].h >> volume->comps[0].factor[1]), + (volume->comps[0].l >> volume->comps[0].factor[2]),volume->comps[0].prec); + + if(original){ + psnr = calc_PSNR(original,volume); + ssim = calc_SSIM(original,volume); + if (psnr < 0.0) + fprintf(stdout, " PSNR: Inf , SSMI %f -- Perfect reconstruction!\n",ssim); + else + fprintf(stdout, " PSNR: %f , SSIM %f \n",psnr,ssim); + } + /* free remaining structures */ + if(dinfo) { + opj_destroy_decompress(dinfo); + } + + /* free volume data structure */ + opj_volume_destroy(volume); + + return 0; +} + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/jp3d_vm_dec.ncb b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/jp3d_vm_dec.ncb new file mode 100644 index 0000000000000000000000000000000000000000..fc66b661edfbd0af2e2a473a556b48111c086a3f GIT binary patch literal 470016 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 _P5&z}u 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 F{2x0#sNDbn literal 0 HcmV?d00001 diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/jp3d_vm_dec.sln b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/jp3d_vm_dec.sln new file mode 100644 index 0000000..5c77759 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/jp3d_vm_dec.sln @@ -0,0 +1,30 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jp3d_vm_dec", "jp3d_vm_dec.vcproj", "{E0C1B905-5B10-4C9A-AF55-2D8144D518AB}" + ProjectSection(ProjectDependencies) = postProject + {6F3FB035-8F4E-4794-B091-0F0A20223BE7} = {6F3FB035-8F4E-4794-B091-0F0A20223BE7} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LibJp3dVM", "..\LibJp3dVM.vcproj", "{6F3FB035-8F4E-4794-B091-0F0A20223BE7}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {E0C1B905-5B10-4C9A-AF55-2D8144D518AB}.Debug.ActiveCfg = Debug|Win32 + {E0C1B905-5B10-4C9A-AF55-2D8144D518AB}.Debug.Build.0 = Debug|Win32 + {E0C1B905-5B10-4C9A-AF55-2D8144D518AB}.Release.ActiveCfg = Release|Win32 + {E0C1B905-5B10-4C9A-AF55-2D8144D518AB}.Release.Build.0 = Release|Win32 + {6F3FB035-8F4E-4794-B091-0F0A20223BE7}.Debug.ActiveCfg = Debug|Win32 + {6F3FB035-8F4E-4794-B091-0F0A20223BE7}.Debug.Build.0 = Debug|Win32 + {6F3FB035-8F4E-4794-B091-0F0A20223BE7}.Release.ActiveCfg = Release|Win32 + {6F3FB035-8F4E-4794-B091-0F0A20223BE7}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/jp3d_vm_dec.suo b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/jp3d_vm_dec.suo new file mode 100644 index 0000000000000000000000000000000000000000..28c2e25584f555673a87eee32fe678e195049c10 GIT binary patch literal 13312 zcmeI2Pi)*r701VRN|U-xXqzU%q-BZYCY0FtZ)!JCx?Zo7v~l9bAt}OAwDzvub=Uh_ zcGpfqoC_Bus1PUMfYcUx0zu0K2@Wj+3DE-zLL3XU2g(JhNc;=X)_lG*``bVE?q^SmdQFUPiI zqmkafGjP^;e6l8B!Y0WxZLYAIwWmEujnAEAq+0sv%ip>5{O^9z)Iy`jcDt72Q1r~4 zISKU{a$$41S{JM8_L%0TJ(S)HG>%mbDilb5mCl)n$(U!%DHG?JHJ{--#+dx_jB8f$ z`yd)ndq8`pR{GMR+Fwd1p`;Z^m?^$5n+Z#Ok(mKwLb-| ziS&SUfM4e80RLUOKsrGCUwS}uSiJw$?mo)=_WrYtvJZp(;C}D`_y`DqkAefB9UKH5 z;6ZQ*90uy+A)Y6}5zq;`z$ZXAP<=1YKF|*az)|op7z9J$5ukRT*_S&0(0zLF$FQ`f^p}vV zMEyxJwJ+o)vuQ68%LJmaKs267d6{@NzUZmjU7_@qOg54ToQy?TVg-h+X1ouct8ahe(3*wcH1aS8zmk~f3Muj^ zokVMnqh&|P%`v(@T3w`_ zRsQ5BzSYDRsWSa5j9Wg@YMtqR>As58^eab2bSy;M}%|6|DRJXGZeU&zgcXQTzo zrz7k?`As`Pt@K6vT&_Fq_bfEi%(~=F^Pk{7lhem@b}wa-Yv}^DEY(PlKwmzYWxhuK zsnORg3De+rHkGzfOwU@4e=5%ThDyeR=sn zb3Rn_@)K>%zdY5}tQ~iU{4LVurmLv2ZWCJRF%--EI5L+(9_2GsvP9i=?7zJXKsHdR z8h!sPHp0%xf^w+~`IkKxU$yQ(#X5ZXm!33kmDKAVB#S*!m<*>PWvy3QnP*FPVk zt3S(Nk-~YYp zPVxRZARVVvT&MHj7&Dcy^CVj-UqTi$mDgZ8bvbsA*)v*B^h^&v<`6FYJAU(0d;9Sp{qfCfho+7j>VXg~9{DRZS zn{oOnKk6=KdOCLwnS%#AE#|vh#z6=@AzhNOr=A$PbZu6M_-B)Bi2S8m?Qik<-`B(P zgHwz}p0~VVr>*7hR!^cYx{5p2O8?`u{eqi#;=M^rHDaYInzvcbE>!aR3u8J^hy5+) zzr2(b`oCFjUmf&&=roaYa95t+-9~(zwa^LwJhr{O#QL6_y3rmjuMJ(yw@|k-2Ib;5 z;;{*x^S3VL6r1>aKKGAYuGQSIxfb(Jp7JJI%)j!j{+-YLC!c#KpL;i#YcrG=2nltlHp}qYf9)J9TDt(P_6p+QQG_Z$G>Ou@82fyU1b9l1JpBIjBbD1g?yz4|r(0)(8}g$CT8sS1FIP0o`7mz&I25iwh_h7Th*#=*E@2Wj z|Cr|-UtM>(oI7&%;0AXCUH435pxhC(_$n+*=|y|pq;R4xV7q9!#OErZjbVN{NZ7)m zlK_COk9s*y_wX433V;j}&`=0WM{IpYZOMQQhm6qr8VlCb+t)w9KOBl;z3tUwy^F+p zH!k3?1Ycdu!s>nh{#>nujV$=bEUo4wD^+^z*_@RsS)+p$)@Utv_4Pz6{99X{os9Yt`#+G)jta7w zTbo2F + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/jp3d_vm_enc.ncb b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/jp3d_vm_enc.ncb new file mode 100644 index 0000000000000000000000000000000000000000..7f0733b784a9544d0aa7a90ad9b21c4c654df270 GIT binary patch literal 568320 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 z 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

m(EpXjxbe}~iI9m=+M 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 literal 0 HcmV?d00001 diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/jp3d_vm_enc.sln b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/jp3d_vm_enc.sln new file mode 100644 index 0000000..02a97a8 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/jp3d_vm_enc.sln @@ -0,0 +1,35 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jp3d_vm_enc", "jp3d_vm_enc.vcproj", "{A9704A2E-3B93-4BAA-9229-02FC93D27201}" + ProjectSection(ProjectDependencies) = postProject + {6F3FB035-8F4E-4794-B091-0F0A20223BE7} = {6F3FB035-8F4E-4794-B091-0F0A20223BE7} + {6F3FB035-8F4E-4794-B091-0F0A20223BE7} = {6F3FB035-8F4E-4794-B091-0F0A20223BE7} + {6F3FB035-8F4E-4794-B091-0F0A20223BE7} = {6F3FB035-8F4E-4794-B091-0F0A20223BE7} + {6F3FB035-8F4E-4794-B091-0F0A20223BE7} = {6F3FB035-8F4E-4794-B091-0F0A20223BE7} + {6F3FB035-8F4E-4794-B091-0F0A20223BE7} = {6F3FB035-8F4E-4794-B091-0F0A20223BE7} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LibJp3dVM", "..\LibJp3dVM.vcproj", "{6F3FB035-8F4E-4794-B091-0F0A20223BE7}" + ProjectSection(ProjectDependencies) = postProject + {6F3FB035-8F4E-4794-B091-0F0A20223BE7} = {6F3FB035-8F4E-4794-B091-0F0A20223BE7} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {A9704A2E-3B93-4BAA-9229-02FC93D27201}.Debug.ActiveCfg = Debug|Win32 + {A9704A2E-3B93-4BAA-9229-02FC93D27201}.Debug.Build.0 = Debug|Win32 + {A9704A2E-3B93-4BAA-9229-02FC93D27201}.Release.ActiveCfg = Release|Win32 + {A9704A2E-3B93-4BAA-9229-02FC93D27201}.Release.Build.0 = Release|Win32 + {6F3FB035-8F4E-4794-B091-0F0A20223BE7}.Debug.ActiveCfg = Debug|Win32 + {6F3FB035-8F4E-4794-B091-0F0A20223BE7}.Debug.Build.0 = Debug|Win32 + {6F3FB035-8F4E-4794-B091-0F0A20223BE7}.Release.ActiveCfg = Release|Win32 + {6F3FB035-8F4E-4794-B091-0F0A20223BE7}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/jp3d_vm_enc.suo b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/jp3d_vm_enc.suo new file mode 100644 index 0000000000000000000000000000000000000000..702d0dd81ee6aa926631769e00fd21bde422b579 GIT binary patch literal 21504 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/volume_to_jp3d.c b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/volume_to_jp3d.c new file mode 100644 index 0000000..c9c35e7 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/volume_to_jp3d.c @@ -0,0 +1,906 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * Copyright (c) 2006, Mónica Díez García, Image Processing Laboratory, University of Valladolid, Spain + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include + +#include "../libjp3dvm/openjpeg3d.h" +#include "getopt.h" +#include "convert.h" + +#ifdef _WIN32 +#include +#else +#define stricmp strcasecmp +#define strnicmp strncasecmp +#endif /* _WIN32 */ + +/* ----------------------------------------------------------------------- */ + +void encode_help_display() { + fprintf(stdout,"List of parameters for the JPEG2000 Part 10 encoder:\n"); + fprintf(stdout,"------------\n"); + fprintf(stdout,"\n"); + fprintf(stdout,"Required Parameters (except with -h):\n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-i : source file (-i source.bin or source*.pgx) \n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-m : source characteristics file (-m imgfile.img) \n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-o : destination file (-o dest.jp3d) \n"); + fprintf(stdout,"\n"); + fprintf(stdout,"Optional Parameters:\n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-h : display the help information \n "); + fprintf(stdout,"\n"); + fprintf(stdout,"-n : number of resolutions (-n 3,3,3) \n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-I : use the irreversible transforms: ICT + DWT 9-7 (-I) \n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-C : coding algorithm (-C 2EB) [2EB, 3EB] \n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-r : different compression ratios for successive layers (-r 20,10,5)\n "); + fprintf(stdout," - The rate specified for each quality level is the desired compression factor.\n"); + fprintf(stdout," - Rate 1 means lossless compression\n"); + fprintf(stdout," (options -r and -q cannot be used together)\n "); + fprintf(stdout,"\n"); + fprintf(stdout,"-q : different psnr for successive layers (-q 30,40,50) \n "); + fprintf(stdout," (options -r and -q cannot be used together)\n "); + fprintf(stdout,"\n"); + fprintf(stdout,"-b : size of code block (-b 32,32,32) \n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-c : size of precinct (-c 128,128,128) \n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-t : size of tile (-t 512,512,512) \n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-p : progression order (-p LRCP) [LRCP, RLCP, RPCL, PCRL, CPRL] \n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-s : subsampling factor (-s 2,2,2) [-s X,Y,Z] \n"); + fprintf(stdout," - Remark: subsampling bigger than 2 can produce error\n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-SOP : write SOP marker before each packet \n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-EPH : write EPH marker after each header packet \n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-M : code-block style (-M 0) [1=BYPASS(LAZY) 2=RESET 4=RESTART(TERMALL)\n"); + fprintf(stdout," 8=VSC 16=PTERM 32=SEGSYM 64=3DCTXT] \n"); + fprintf(stdout," Indicate multiple modes by adding their values. \n"); + fprintf(stdout," ex: RESTART(4) + RESET(2) + SEGMARK(32) = -M 38\n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-D : define DC offset (-D 12) \n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-x : create an index file *.Idx (-x index_name.Idx) \n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-ROI : c=%%d,U=%%d : quantization indices upshifted \n"); + fprintf(stdout," for component c=%%d [%%d = 0,1,2]\n"); + fprintf(stdout," with a value of U=%%d [0 <= %%d <= 37] (i.e. -ROI:c=0,U=25) \n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-d : offset of the origin of the volume (-d 150,300,100) \n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-l : offset of the origin of the tiles (-l 100,75,25) \n"); + fprintf(stdout,"\n"); + fprintf(stdout,"\n"); + fprintf(stdout,"DEFAULT CODING:\n"); + fprintf(stdout,"------------\n"); + fprintf(stdout,"\n"); + fprintf(stdout," * Lossless\n"); + fprintf(stdout," * 1 tile\n"); + fprintf(stdout," * Size of precinct : 2^15 x 2^15 x 2^15 (means 1 precinct)\n"); + fprintf(stdout," * Size of code-block : 64 x 64 x 64\n"); + fprintf(stdout," * Number of resolutions in x, y and z axis: 3\n"); + fprintf(stdout," * No SOP marker in the codestream\n"); + fprintf(stdout," * No EPH marker in the codestream\n"); + fprintf(stdout," * No sub-sampling in x, y or z direction\n"); + fprintf(stdout," * No mode switch activated\n"); + fprintf(stdout," * Progression order: LRCP\n"); + fprintf(stdout," * No index file\n"); + fprintf(stdout," * No ROI upshifted\n"); + fprintf(stdout," * No offset of the origin of the volume\n"); + fprintf(stdout," * No offset of the origin of the tiles\n"); + fprintf(stdout," * Reversible DWT 5-3 on each 2D slice\n"); + fprintf(stdout," * Coding algorithm: 2D-EBCOT \n"); + fprintf(stdout,"\n"); + fprintf(stdout,"REMARKS:\n"); + fprintf(stdout,"---------\n"); + fprintf(stdout,"\n"); + fprintf(stdout,"- The markers written to the main_header are : SOC SIZ COD QCD COM.\n"); + fprintf(stdout,"- COD and QCD markers will never appear in the tile_header.\n"); + fprintf(stdout,"\n"); + fprintf(stdout,"- You need enough disk space memory (twice the original) to encode \n"); + fprintf(stdout,"the volume,i.e. for a 1.5 GB volume you need a minimum of 3GB of disk memory)\n"); + fprintf(stdout,"\n"); + fprintf(stdout,"- When loading *.pgx files, a relative path to directory is needed for input argument \n"); + fprintf(stdout," followed by the common prefix of the slices and a '*' character representing sequential numeration.\n"); + fprintf(stdout,"( -i relativepath/slices*.pgx )\n"); + fprintf(stdout,"\n"); + fprintf(stdout," - The index file has the structure below:\n"); + fprintf(stdout,"\n"); + fprintf(stdout,"\t Image_height Image_width Image_depth\n"); + fprintf(stdout,"\t Progression order: 0 (LRCP)\n"); + fprintf(stdout,"\t Tiles_size_X Tiles_size_Y Tiles_size_Z\n"); + fprintf(stdout,"\t Components_nb\n"); + fprintf(stdout,"\t Layers_nb\n"); + fprintf(stdout,"\t Decomposition_levels\n"); + fprintf(stdout,"\t [Precincts_size_X_res_Nr Precincts_size_Y_res_Nr Precincts_size_Z_res_Nr]\n\t ...\n"); + fprintf(stdout,"\t [Precincts_size_X_res_0 Precincts_size_Y_res_0 Precincts_size_Z_res_0]\n"); + fprintf(stdout,"\t Main_header_end_position\n"); + fprintf(stdout,"\t Codestream_size\n"); + fprintf(stdout,"\t Tile_0 [start_pos end_header end_pos TotalDisto NumPix MaxMSE]\n"); + fprintf(stdout,"\t ...\n"); + fprintf(stdout,"\t Tile_Nt [ '' '' '' '' '' '' ]\n"); + fprintf(stdout,"\t Tpacket_0 [Tile layer res. comp. prec. start_pos end_pos disto]\n"); + fprintf(stdout,"\t ...\n"); + fprintf(stdout,"\t Tpacket_Np ['' '' '' '' '' '' '' '' ]\n"); + fprintf(stdout,"\t MaxDisto\n"); + fprintf(stdout,"\t TotalDisto\n\n"); + fprintf(stdout,"\n"); + +} + +OPJ_PROG_ORDER give_progression(char progression[4]) { + if(strncmp(progression, "LRCP", 4) == 0) { + return LRCP; + } + if(strncmp(progression, "RLCP", 4) == 0) { + return RLCP; + } + if(strncmp(progression, "RPCL", 4) == 0) { + return RPCL; + } + if(strncmp(progression, "PCRL", 4) == 0) { + return PCRL; + } + if(strncmp(progression, "CPRL", 4) == 0) { + return CPRL; + } + + return PROG_UNKNOWN; +} + +OPJ_TRANSFORM give_transform(char transform[4]) { + if(strncmp(transform, "2DWT", 4) == 0) { + return TRF_2D_DWT; + } + if(strncmp(transform, "3DWT", 4) == 0) { + return TRF_3D_DWT; + } + return TRF_UNKNOWN; +} + +OPJ_ENTROPY_CODING give_coding(char coding[3]) { + + if(strncmp(coding, "2EB", 3) == 0) { + return ENCOD_2EB; + } + if(strncmp(coding, "3EB", 3) == 0) { + return ENCOD_3EB; + } + /*if(strncmp(coding, "2GR", 3) == 0) { + return ENCOD_2GR; + } + if(strncmp(coding, "3GR", 3) == 0) { + return ENCOD_3GR; + }*/ + + return ENCOD_UNKNOWN; +} + +int get_file_format(char *filename) { + int i; + static const char *extension[] = {"pgx", "bin", "img", "j3d", "jp3d", "j2k"}; + static const int format[] = { PGX_DFMT, BIN_DFMT, IMG_DFMT, J3D_CFMT, J3D_CFMT, J2K_CFMT}; + char * ext = strrchr(filename, '.'); + if (ext) { + ext++; + for(i = 0; i < sizeof(format)/sizeof(*format); i++) { + if(strnicmp(ext, extension[i], 3) == 0) { + return format[i]; + } + } + } + + return -1; +} + +/* ------------------------------------------------------------------------------------ */ + +int parse_cmdline_encoder(int argc, char **argv, opj_cparameters_t *parameters) { + int i, value; + + /* parse the command line */ + + while (1) { + int c = getopt(argc, argv, "i:m:o:r:q:f:t:n:c:b:x:p:s:d:hP:S:E:M:D:R:l:T:C:A:I"); + if (c == -1) + break; + switch (c) { + case 'i': /* input file */ + { + char *infile = optarg; + parameters->decod_format = get_file_format(infile); + switch(parameters->decod_format) { + case PGX_DFMT: + case BIN_DFMT: + case IMG_DFMT: + break; + default: + fprintf(stdout, "[ERROR] Unrecognized format for infile : %s [accept only *.pgx or *.bin] !!\n\n", infile); + return 1; + break; + } + strncpy(parameters->infile, infile, MAX_PATH); + fprintf(stdout, "[INFO] Infile: %s \n", parameters->infile); + + } + break; + + /* ----------------------------------------------------- */ + case 'm': /* input IMG file */ + { + char *imgfile = optarg; + int imgformat = get_file_format(imgfile); + switch(imgformat) { + case IMG_DFMT: + break; + default: + fprintf(stdout, "[ERROR] Unrecognized format for imgfile : %s [accept only *.img] !!\n\n", imgfile); + return 1; + break; + } + strncpy(parameters->imgfile, imgfile, MAX_PATH); + fprintf(stdout, "[INFO] Imgfile: %s Format: %d\n", parameters->imgfile, imgformat); + } + break; + + /* ----------------------------------------------------- */ + case 'o': /* output file */ + { + char *outfile = optarg; + parameters->cod_format = get_file_format(outfile); + switch(parameters->cod_format) { + case J3D_CFMT: + case J2K_CFMT: + case LSE_CFMT: + break; + default: + fprintf(stdout, "[ERROR] Unknown output format volume %s [only *.j2k, *.lse3d or *.jp3d]!! \n", outfile); + return 1; + break; + } + strncpy(parameters->outfile, outfile, MAX_PATH); + fprintf(stdout, "[INFO] Outfile: %s \n", parameters->outfile); + } + break; + + /* ----------------------------------------------------- */ + + case 'r': /* define compression rates for each layer */ + { + char *s = optarg; + while (sscanf(s, "%f", ¶meters->tcp_rates[parameters->tcp_numlayers]) == 1) { + parameters->tcp_numlayers++; + while (*s && *s != ',') { + s++; + } + if (!*s) + break; + s++; + } + parameters->cp_disto_alloc = 1; + } + break; + + /* ----------------------------------------------------- */ + + case 'q': /* define distorsion (PSNR) for each layer */ + { + char *s = optarg; + while (sscanf(s, "%f", ¶meters->tcp_distoratio[parameters->tcp_numlayers]) == 1) { + parameters->tcp_numlayers++; + while (*s && *s != ',') { + s++; + } + if (!*s) + break; + s++; + } + parameters->cp_fixed_quality = 1; + } + break; + + /* ----------------------------------------------------- */ + + case 'f': + { + fprintf(stdout, "/---------------------------------------------------\\\n"); + fprintf(stdout, "| Fixed layer allocation option not implemented !! |\n"); + fprintf(stdout, "\\---------------------------------------------------/\n"); + /*int *row = NULL, *col = NULL; + int numlayers = 0, matrix_width = 0; + + char *s = optarg; + sscanf(s, "%d", &numlayers); + s++; + if (numlayers > 9) + s++; + + parameters->tcp_numlayers = numlayers; + matrix_width = parameters->numresolution[0] + parameters->numresolution[1] + parameters->numresolution[2]; + parameters->cp_matrice = (int *) malloc(numlayers * matrix_width * sizeof(int)); + s = s + 2; + + for (i = 0; i < numlayers; i++) { + row = ¶meters->cp_matrice[i * matrix_width]; + col = row; + parameters->tcp_rates[i] = 1; + sscanf(s, "%d,", &col[0]); + s += 2; + if (col[0] > 9) + s++; + col[1] = 0; + col[2] = 0; + for (j = 1; j < matrix_width; j++) { + col += 3; j+=2; + sscanf(s, "%d,%d,%d", &col[0], &col[1], &col[2]); + s += 6; + if (col[0] > 9) + s++; + if (col[1] > 9) + s++; + if (col[2] > 9) + s++; + } + if (i < numlayers - 1) + s++; + } + parameters->cp_fixed_alloc = 1; */ + } + break; + + /* ----------------------------------------------------- */ + + case 't': /* tiles */ + { + if (sscanf(optarg, "%d,%d,%d", ¶meters->cp_tdx, ¶meters->cp_tdy, ¶meters->cp_tdz) !=3) { + fprintf(stdout, "[ERROR] '-t' 'dimensions of tiles' argument error ! [-t tdx,tdy,tdz]\n"); + return 1; + } + parameters->tile_size_on = true; + } + break; + + /* ----------------------------------------------------- */ + + case 'n': /* resolution */ + { + int aux; + aux = sscanf(optarg, "%d,%d,%d", ¶meters->numresolution[0], ¶meters->numresolution[1], ¶meters->numresolution[2]); + if (aux == 2) + parameters->numresolution[2] = 1; + else if (aux == 1) { + parameters->numresolution[1] = parameters->numresolution[0]; + parameters->numresolution[2] = 1; + }else if (aux == 0){ + parameters->numresolution[0] = 1; + parameters->numresolution[1] = 1; + parameters->numresolution[2] = 1; + } + } + break; + + /* ----------------------------------------------------- */ + case 'c': /* precinct dimension */ + { + char sep; + int res_spec = 0; + int aux; + char *s = optarg; + do { + sep = 0; + aux = sscanf(s, "[%d,%d,%d]%c", ¶meters->prct_init[0][res_spec], ¶meters->prct_init[1][res_spec], ¶meters->prct_init[2][res_spec], &sep); + if (sep == ',' && aux != 4) { + fprintf(stdout, "[ERROR] '-c' 'dimensions of precincts' argument error ! [-c [prcx_res0,prcy_res0,prcz_res0],...,[prcx_resN,prcy_resN,prcz_resN]]\n"); + return 1; + } + parameters->csty |= 0x01; + res_spec++; + s = strpbrk(s, "]") + 2; + } + while (sep == ','); + parameters->res_spec = res_spec; /* number of precinct size specifications */ + } + break; + + /* ----------------------------------------------------- */ + + case 'b': /* code-block dimension */ + { + int cblockw_init = 0, cblockh_init = 0, cblockl_init = 0; + if (sscanf(optarg, "%d,%d,%d", &cblockw_init, &cblockh_init, &cblockl_init) != 3) { + fprintf(stdout, "[ERROR] '-b' 'dimensions of codeblocks' argument error ! [-b cblkx,cblky,cblkz]\n"); + return 1; + } + if (cblockw_init * cblockh_init * cblockl_init > (1<<18) || cblockw_init > 1024 || cblockw_init < 4 || cblockh_init > 1024 || cblockh_init < 4 || cblockl_init > 1024 || cblockl_init < 4) { + fprintf(stdout,"[ERROR] Size of code_block error (option -b) !!\n\nRestriction :\n * width*height*length<=4096\n * 4<=width,height,length<= 1024\n\n"); + return 1; + } + parameters->cblock_init[0] = cblockw_init; + parameters->cblock_init[1] = cblockh_init; + parameters->cblock_init[2] = cblockl_init; + } + break; + + /* ----------------------------------------------------- */ + + case 'x': /* creation of index file */ + { + char *index = optarg; + strncpy(parameters->index, index, MAX_PATH); + parameters->index_on = 1; + } + break; + + /* ----------------------------------------------------- */ + + case 'p': /* progression order */ + { + char progression[4]; + + strncpy(progression, optarg, 4); + parameters->prog_order = give_progression(progression); + if (parameters->prog_order == -1) { + fprintf(stdout, "[ERROR] Unrecognized progression order [LRCP, RLCP, RPCL, PCRL, CPRL] !!\n"); + return 1; + } + } + break; + + /* ----------------------------------------------------- */ + + case 's': /* subsampling factor */ + { + if (sscanf(optarg, "%d,%d,%d", ¶meters->subsampling_dx, ¶meters->subsampling_dy, ¶meters->subsampling_dz) != 2) { + fprintf(stdout, "[ERROR] '-s' sub-sampling argument error ! [-s dx,dy,dz]\n"); + return 1; + } + } + break; + + /* ----------------------------------------------------- */ + + case 'd': /* coordonnate of the reference grid */ + { + if (sscanf(optarg, "%d,%d,%d", ¶meters->volume_offset_x0, ¶meters->volume_offset_y0, ¶meters->volume_offset_z0) != 3) { + fprintf(stdout, "[ERROR] -d 'coordonnate of the reference grid' argument error !! [-d x0,y0,z0]\n"); + return 1; + } + } + break; + + /* ----------------------------------------------------- */ + + case 'h': /* display an help description */ + { + encode_help_display(); + return 1; + } + break; + + /* ----------------------------------------------------- */ + + case 'P': /* POC */ + { + int numpocs = 0; /* number of progression order change (POC) default 0 */ + opj_poc_t *POC = NULL; /* POC : used in case of Progression order change */ + + char *s = optarg; + POC = parameters->POC; + + fprintf(stdout, "/----------------------------------\\\n"); + fprintf(stdout, "| POC option not fully tested !! |\n"); + fprintf(stdout, "\\----------------------------------/\n"); + + while (sscanf(s, "T%d=%d,%d,%d,%d,%d,%s", &POC[numpocs].tile, + &POC[numpocs].resno0, &POC[numpocs].compno0, + &POC[numpocs].layno1, &POC[numpocs].resno1, + &POC[numpocs].compno1, POC[numpocs].progorder) == 7) { + POC[numpocs].prg = give_progression(POC[numpocs].progorder); + /* POC[numpocs].tile; */ + numpocs++; + while (*s && *s != '/') { + s++; + } + if (!*s) { + break; + } + s++; + } + parameters->numpocs = numpocs; + } + break; + + /* ------------------------------------------------------ */ + + case 'S': /* SOP marker */ + { + parameters->csty |= 0x02; + } + break; + + /* ------------------------------------------------------ */ + + case 'E': /* EPH marker */ + { + parameters->csty |= 0x04; + } + break; + + /* ------------------------------------------------------ */ + + case 'M': /* Codification mode switch */ + { + fprintf(stdout, "[INFO] Mode switch option not fully tested !!\n"); + value = 0; + if (sscanf(optarg, "%d", &value) == 1) { + for (i = 0; i <= 6; i++) { + int cache = value & (1 << i); + if (cache) + parameters->mode |= (1 << i); + } + } + } + break; + + /* ------------------------------------------------------ */ + + case 'D': /* DCO */ + { + if (sscanf(optarg, "%d", ¶meters->dcoffset) != 1) { + fprintf(stdout, "[ERROR] DC offset error !! [-D %d]\n",parameters->dcoffset); + return 1; + } + } + break; + + /* ------------------------------------------------------ */ + + case 'R': /* ROI */ + { + if (sscanf(optarg, "OI:c=%d,U=%d", ¶meters->roi_compno, ¶meters->roi_shift) != 2) { + fprintf(stdout, "[ERROR] ROI error !! [-ROI:c='compno',U='shift']\n"); + return 1; + } + } + break; + + /* ------------------------------------------------------ */ + + case 'l': /* Tile offset */ + { + if (sscanf(optarg, "%d,%d,%d", ¶meters->cp_tx0, ¶meters->cp_ty0, ¶meters->cp_tz0) != 3) { + fprintf(stdout, "[ERROR] -l 'tile offset' argument error !! [-l X0,Y0,Z0]"); + return 1; + } + } + break; + + /* ------------------------------------------------------ + + case 'T': // Tranformation of original data (2D-DWT/3D-DWT/3D-RLS/2D-DWT+1D-RLS) + { + char transform[4]; + + strncpy(transform, optarg, 4); + parameters->transform_format = give_transform(transform); + if (parameters->transform_format == -1) { + fprintf(stdout, "[ERROR] -T 'Transform domain' argument error !! [-T 2DWT, 3DWT, 3RLS or 3LSE only]"); + return 1; + } + } + break; + + ------------------------------------------------------ */ + + case 'C': /* Coding of transformed data */ + { + char coding[3]; + + strncpy(coding, optarg, 3); + parameters->encoding_format = give_coding(coding); + if (parameters->encoding_format == -1) { + fprintf(stdout, "[ERROR] -C 'Coding algorithm' argument error !! [-C 2EB, 3EB, 2GR, 3GR or GRI only]"); + return 1; + } + } + break; + + /* ------------------------------------------------------ */ + + case 'I': /* reversible or not */ + { + parameters->irreversible = 1; + } + break; + + default: + fprintf(stdout, "[ERROR] This option is not valid \"-%c %s\"\n", c, optarg); + return 1; + } + } + + /* check for possible errors */ + + if((parameters->infile[0] == 0) || (parameters->outfile[0] == 0)) { + fprintf(stdout, "usage: jp3d_vm_enc -i volume-file -o jp3d-file (+ options)\n"); + return 1; + } + + if((parameters->decod_format == BIN_DFMT) && (parameters->imgfile[0] == 0)) { + fprintf(stdout, "usage: jp3d_vm_enc -i bin-volume-file -m img-file -o jp3d-file (+ options)\n"); + return 1; + } + + if((parameters->decod_format != BIN_DFMT) && (parameters->decod_format != PGX_DFMT) && (parameters->decod_format != IMG_DFMT)) { + fprintf(stdout, "usage: jp3d_vm_enc -i input-volume-file [*.bin,*.pgx,*.img] -o jp3d-file [*.jp3d,*.j2k] (+ options)\n"); + return 1; + } + if((parameters->cod_format != J3D_CFMT) && (parameters->cod_format != J2K_CFMT)) { + fprintf(stdout, "usage: jp3d_vm_enc -i input-volume-file [*.bin,*.pgx,*.img] -o jp3d-file [*.jp3d,*.j2k] (+ options)\n"); + return 1; + } + + if((parameters->encoding_format == ENCOD_2GR || parameters->encoding_format == ENCOD_3GR) && parameters->transform_format != TRF_3D_LSE && parameters->transform_format != TRF_3D_RLS) { + fprintf(stdout, "[ERROR] Entropy coding options -C [2GR,3GR] are only compatible with predictive-based transform algorithms: -T [3RLS,3LSE].\n"); + return 1; + } + if (parameters->encoding_format == ENCOD_3EB) + parameters->mode |= (1 << 6); + + if ((parameters->mode >> 6) & 1) { + parameters->encoding_format = ENCOD_3EB; + } + + if((parameters->numresolution[2] == 0 || (parameters->numresolution[1] == 0) || (parameters->numresolution[0] == 0))) { + fprintf(stdout, "[ERROR] -n 'resolution levels' argument error ! Resolutions must be greater than 1 in order to perform DWT.\n"); + return 1; + } + if (parameters->numresolution[1] != parameters->numresolution[0]) { + fprintf(stdout, "[ERROR] -n 'resolution levels' argument error ! Resolutions in X and Y axis must be the same in this implementation.\n"); + return 1; + } + + if (parameters->numresolution[2] > parameters->numresolution[0]) { + fprintf(stdout, "[ERROR] -n 'resolution levels' argument error ! Resolutions in Z axis must be lower than in X-Y axis.\n"); + return 1; + } + + if (parameters->dcoffset >= 128 && parameters->dcoffset <= -128) { + fprintf(stdout, "[ERROR] -D 'DC offset' argument error ! Value must be -128<=DCO<=128.\n"); + return 1; + } + + if(parameters->numresolution[2] != 1) { + parameters->transform_format = TRF_3D_DWT; + //fprintf(stdout, "[Warning] Resolution level in axial dim > 1 : 3D-DWT will be performed... \n"); + } else if (parameters->numresolution[2] == 1) { + parameters->transform_format = TRF_2D_DWT; + //fprintf(stdout, "[Warning] Resolution level in axial dim == 1 : 2D-DWT will be performed... \n"); + } + + if ((parameters->cod_format == J2K_CFMT) && (parameters->transform_format != TRF_2D_DWT || parameters->encoding_format != ENCOD_2EB)) { + fprintf(stdout, "[WARNING] Incompatible options -o *.j2k and defined transform or encoding algorithm. Latter will be ignored\n"); + parameters->transform_format = TRF_2D_DWT; + parameters->encoding_format = ENCOD_2EB; + } + + if ((parameters->cp_disto_alloc || parameters->cp_fixed_alloc || parameters->cp_fixed_quality) && (!(parameters->cp_disto_alloc ^ parameters->cp_fixed_quality))) { + fprintf(stdout, "[ERROR] Options -r and -q cannot be used together !!\n"); + return 1; + } /* mod fixed_quality */ + + /* if no rate entered, lossless by default */ + if (parameters->tcp_numlayers == 0) { + parameters->tcp_rates[0] = 0.0; /* MOD antonin : losslessbug */ + parameters->tcp_numlayers++; + parameters->cp_disto_alloc = 1; + } + + if((parameters->cp_tx0 > parameters->volume_offset_x0) || (parameters->cp_ty0 > parameters->volume_offset_y0) || (parameters->cp_tz0 > parameters->volume_offset_z0)) { + fprintf(stdout, "[ERROR] Tile offset dimension is unnappropriate --> TX0(%d)<=IMG_X0(%d) TYO(%d)<=IMG_Y0(%d) TZO(%d)<=IMG_Z0(%d)\n", + parameters->cp_tx0, parameters->volume_offset_x0, parameters->cp_ty0, parameters->volume_offset_y0, + parameters->cp_tz0, parameters->volume_offset_z0); + return 1; + } + + for (i = 0; i < parameters->numpocs; i++) { + if (parameters->POC[i].prg == -1) { + fprintf(stdout,"[ERROR] Unrecognized progression order in option -P (POC n %d) [LRCP, RLCP, RPCL, PCRL, CPRL] !!\n",i + 1); + } + } + return 0; +} + +/* -------------------------------------------------------------------------- */ + +/** +sample error callback expecting a FILE* client object +*/ +void error_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[ERROR] %s", msg); +} +/** +sample warning callback expecting a FILE* client object +*/ +void warning_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[WARNING] %s", msg); +} +/** +sample debug callback expecting a FILE* client object +*/ +void info_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[INFO] %s", msg); +} + +/* -------------------------------------------------------------------------- */ + +int main(int argc, char **argv) { + bool bSuccess; + bool delete_comment = true; + opj_cparameters_t parameters; /* compression parameters */ + opj_event_mgr_t event_mgr; /* event manager */ + opj_volume_t *volume = NULL; + + /* + configure the event callbacks (not required) + setting of each callback is optionnal + */ + memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); + event_mgr.error_handler = error_callback; + event_mgr.warning_handler = warning_callback; + event_mgr.info_handler = info_callback; + + /* set encoding parameters to default values */ + opj_set_default_encoder_parameters(¶meters); + + /* parse input and get user encoding parameters */ + if(parse_cmdline_encoder(argc, argv, ¶meters) == 1) { + return 0; + } + + if(parameters.cp_comment == NULL) { + parameters.cp_comment = "Created by OpenJPEG version JP3D"; + /* no need to delete parameters.cp_comment on exit */ + delete_comment = false; + } + + /* encode the destination volume */ + /* ---------------------------- */ + if (parameters.cod_format == J3D_CFMT || parameters.cod_format == J2K_CFMT) { + int codestream_length, pixels, bitsin; + opj_cio_t *cio = NULL; + FILE *f = NULL; + opj_cinfo_t* cinfo = NULL; + + /* decode the source volume */ + /* ----------------------- */ + switch (parameters.decod_format) { + case PGX_DFMT: + fprintf(stdout, "[INFO] Loading pgx file(s)\n"); + volume = pgxtovolume(parameters.infile, ¶meters); + if (!volume) { + fprintf(stdout, "[ERROR] Unable to load pgx files\n"); + return 1; + } + break; + + case BIN_DFMT: + fprintf(stdout, "[INFO] Loading bin file\n"); + volume = bintovolume(parameters.infile, parameters.imgfile, ¶meters); + if (!volume) { + fprintf(stdout, "[ERROR] Unable to load bin file\n"); + return 1; + } + break; + + case IMG_DFMT: + fprintf(stdout, "[INFO] Loading img file\n"); + volume = imgtovolume(parameters.infile, ¶meters); + if (!volume) { + fprintf(stderr, "[ERROR] Unable to load img file\n"); + return 1; + } + break; + } + + /* get a JP3D or J2K compressor handle */ + if (parameters.cod_format == J3D_CFMT) + cinfo = opj_create_compress(CODEC_J3D); + else if (parameters.cod_format == J2K_CFMT) + cinfo = opj_create_compress(CODEC_J2K); + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)cinfo, &event_mgr, stdout); + + /* setup the encoder parameters using the current volume and using user parameters */ + opj_setup_encoder(cinfo, ¶meters, volume); + + /* open a byte stream for writing */ + /* allocate memory for all tiles */ + cio = opj_cio_open((opj_common_ptr)cinfo, NULL, 0); + + /* encode the volume */ + //fprintf(stdout, "[INFO] Encode the volume\n"); + bSuccess = opj_encode(cinfo, cio, volume, parameters.index); + if (!bSuccess) { + opj_cio_close(cio); + fprintf(stdout, "[ERROR] Failed to encode volume\n"); + return 1; + } + codestream_length = cio_tell(cio); + pixels =(volume->x1 - volume->x0) * (volume->y1 - volume->y0) * (volume->z1 - volume->z0); + bitsin = pixels * volume->comps[0].prec; + fprintf(stdout, "[RESULT] Volume: %d x %d x %d (x %d bpv)\n Codestream: %d B, Ratio: %5.3f bpv, (%5.3f : 1) \n", + (volume->x1 - volume->x0),(volume->y1 - volume->y0),(volume->z1 - volume->z0),volume->comps[0].prec, + codestream_length, ((double)codestream_length * 8.0/(double)pixels), ((double)bitsin/(8.0*(double)codestream_length))); + + /* write the buffer to disk */ + f = fopen(parameters.outfile, "wb"); + if (!f) { + fprintf(stdout, "[ERROR] Failed to open %s for writing\n", parameters.outfile); + return 1; + } + fwrite(cio->buffer, 1, codestream_length, f); + fclose(f); + + /* close and free the byte stream */ + opj_cio_close(cio); + + /* free remaining compression structures */ + opj_destroy_compress(cinfo); + } else { + fprintf(stdout, "[ERROR] Cod_format != JP3d !!! \n"); + return 1; + } + + /* free user parameters structure */ + if(delete_comment) { + if(parameters.cp_comment) free(parameters.cp_comment); + } + if(parameters.cp_matrice) free(parameters.cp_matrice); + + /* free volume data */ + opj_volume_destroy(volume); + + return 0; +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/windirent.h b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/windirent.h new file mode 100644 index 0000000..a67e587 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/codec/windirent.h @@ -0,0 +1,676 @@ +/* + * uce-dirent.h - operating system independent dirent implementation + * + * Copyright (C) 1998-2002 Toni Ronkko + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * ``Software''), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL TONI RONKKO BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * + * May 28 1998, Toni Ronkko + * + * $Id: uce-dirent.h,v 1.7 2002/05/13 10:48:35 tr Exp $ + * + * $Log: uce-dirent.h,v $ + * Revision 1.7 2002/05/13 10:48:35 tr + * embedded some source code directly to the header so that no source + * modules need to be included in the MS Visual C project using the + * interface, removed all the dependencies to other headers of the `uce' + * library so that the header can be made public + * + * Revision 1.6 2002/04/12 16:22:04 tr + * Unified Compiling Environment (UCE) replaced `std' library + * + * Revision 1.5 2001/07/20 16:33:40 tr + * moved to `std' library and re-named defines accordingly + * + * Revision 1.4 2001/07/10 16:47:18 tronkko + * revised comments + * + * Revision 1.3 2001/01/11 13:16:43 tr + * using ``uce-machine.h'' for finding out defines such as `FREEBSD' + * + * Revision 1.2 2000/10/08 16:00:41 tr + * copy of FreeBSD man page + * + * Revision 1.1 2000/07/10 05:53:16 tr + * Initial revision + * + * Revision 1.2 1998/07/19 18:29:14 tr + * Added error reporting capabilities and some asserts. + * + * Revision 1.1 1998/07/04 16:27:51 tr + * Initial revision + * + * + * MSVC 1.0 scans automatic dependencies incorrectly when your project + * contains this very header. The problem is that MSVC cannot handle + * include directives inside #if..#endif block those are never entered. + * Since this header ought to compile in many different operating systems, + * there had to be several conditional blocks that are compiled only in + * operating systems for what they were designed for. MSVC 1.0 cannot + * handle inclusion of sys/dir.h in a part that is compiled only in Apollo + * operating system. To fix the problem you need to insert DIR.H into + * SYSINCL.DAT located in MSVC\BIN directory and restart visual C++. + * Consult manuals for more informaton about the problem. + * + * Since many UNIX systems have dirent.h we assume to have one also. + * However, if your UNIX system does not have dirent.h you can download one + * for example at: http://ftp.uni-mannheim.de/ftp/GNU/dirent/dirent.tar.gz. + * You can also see if you have one of dirent.h, direct.h, dir.h, ndir.h, + * sys/dir.h and sys/ndir.h somewhere. Try defining HAVE_DIRENT_H, + * HAVE_DIRECT_H, HAVE_DIR_H, HAVE_NDIR_H, HAVE_SYS_DIR_H and + * HAVE_SYS_NDIR_H according to the files found. + */ +#ifndef DIRENT_H +#define DIRENT_H +#define DIRENT_H_INCLUDED + +/* find out platform */ +#if defined(MSDOS) /* MS-DOS */ +#elif defined(__MSDOS__) /* Turbo C/Borland */ +# define MSDOS +#elif defined(__DOS__) /* Watcom */ +# define MSDOS +#endif + +#if defined(WIN32) /* MS-Windows */ +#elif defined(__NT__) /* Watcom */ +# define WIN32 +#elif defined(_WIN32) /* Microsoft */ +# define WIN32 +#elif defined(__WIN32__) /* Borland */ +# define WIN32 +#endif + +/* + * See what kind of dirent interface we have unless autoconf has already + * determinated that. + */ +#if !defined(HAVE_DIRENT_H) && !defined(HAVE_DIRECT_H) && !defined(HAVE_SYS_DIR_H) && !defined(HAVE_NDIR_H) && !defined(HAVE_SYS_NDIR_H) && !defined(HAVE_DIR_H) +# if defined(_MSC_VER) /* Microsoft C/C++ */ + /* no dirent.h */ +# elif defined(__BORLANDC__) /* Borland C/C++ */ +# define HAVE_DIRENT_H +# define VOID_CLOSEDIR +# elif defined(__TURBOC__) /* Borland Turbo C */ + /* no dirent.h */ +# elif defined(__WATCOMC__) /* Watcom C/C++ */ +# define HAVE_DIRECT_H +# elif defined(__apollo) /* Apollo */ +# define HAVE_SYS_DIR_H +# elif defined(__hpux) /* HP-UX */ +# define HAVE_DIRENT_H +# elif defined(__alpha) || defined(__alpha__) /* Alpha OSF1 */ +# error "not implemented" +# elif defined(__sgi) /* Silicon Graphics */ +# define HAVE_DIRENT_H +# elif defined(sun) || defined(_sun) /* Sun Solaris */ +# define HAVE_DIRENT_H +# elif defined(__FreeBSD__) /* FreeBSD */ +# define HAVE_DIRENT_H +# elif defined(__linux__) /* Linux */ +# define HAVE_DIRENT_H +# elif defined(__GNUC__) /* GNU C/C++ */ +# define HAVE_DIRENT_H +# else +# error "not implemented" +# endif +#endif + +/* include proper interface headers */ +#if defined(HAVE_DIRENT_H) +# include +# ifdef FREEBSD +# define NAMLEN(dp) ((int)((dp)->d_namlen)) +# else +# define NAMLEN(dp) ((int)(strlen((dp)->d_name))) +# endif + +#elif defined(HAVE_NDIR_H) +# include +# define NAMLEN(dp) ((int)((dp)->d_namlen)) + +#elif defined(HAVE_SYS_NDIR_H) +# include +# define NAMLEN(dp) ((int)((dp)->d_namlen)) + +#elif defined(HAVE_DIRECT_H) +# include +# define NAMLEN(dp) ((int)((dp)->d_namlen)) + +#elif defined(HAVE_DIR_H) +# include +# define NAMLEN(dp) ((int)((dp)->d_namlen)) + +#elif defined(HAVE_SYS_DIR_H) +# include +# include +# ifndef dirent +# define dirent direct +# endif +# define NAMLEN(dp) ((int)((dp)->d_namlen)) + +#elif defined(MSDOS) || defined(WIN32) + + /* figure out type of underlaying directory interface to be used */ +# if defined(WIN32) +# define DIRENT_WIN32_INTERFACE +# elif defined(MSDOS) +# define DIRENT_MSDOS_INTERFACE +# else +# error "missing native dirent interface" +# endif + + /*** WIN32 specifics ***/ +# if defined(DIRENT_WIN32_INTERFACE) +# include +# if !defined(DIRENT_MAXNAMLEN) +# define DIRENT_MAXNAMLEN (MAX_PATH) +# endif + + + /*** MS-DOS specifics ***/ +# elif defined(DIRENT_MSDOS_INTERFACE) +# include + + /* Borland defines file length macros in dir.h */ +# if defined(__BORLANDC__) +# include +# if !defined(DIRENT_MAXNAMLEN) +# define DIRENT_MAXNAMLEN ((MAXFILE)+(MAXEXT)) +# endif +# if !defined(_find_t) +# define _find_t find_t +# endif + + /* Turbo C defines ffblk structure in dir.h */ +# elif defined(__TURBOC__) +# include +# if !defined(DIRENT_MAXNAMLEN) +# define DIRENT_MAXNAMLEN ((MAXFILE)+(MAXEXT)) +# endif +# define DIRENT_USE_FFBLK + + /* MSVC */ +# elif defined(_MSC_VER) +# if !defined(DIRENT_MAXNAMLEN) +# define DIRENT_MAXNAMLEN (12) +# endif + + /* Watcom */ +# elif defined(__WATCOMC__) +# if !defined(DIRENT_MAXNAMLEN) +# if defined(__OS2__) || defined(__NT__) +# define DIRENT_MAXNAMLEN (255) +# else +# define DIRENT_MAXNAMLEN (12) +# endif +# endif + +# endif +# endif + + /*** generic MS-DOS and MS-Windows stuff ***/ +# if !defined(NAME_MAX) && defined(DIRENT_MAXNAMLEN) +# define NAME_MAX DIRENT_MAXNAMLEN +# endif +# if NAME_MAX < DIRENT_MAXNAMLEN +# error "assertion failed: NAME_MAX >= DIRENT_MAXNAMLEN" +# endif + + + /* + * Substitute for real dirent structure. Note that `d_name' field is a + * true character array although we have it copied in the implementation + * dependent data. We could save some memory if we had declared `d_name' + * as a pointer refering the name within implementation dependent data. + * We have not done that since some code may rely on sizeof(d_name) to be + * something other than four. Besides, directory entries are typically so + * small that it takes virtually no time to copy them from place to place. + */ + typedef struct dirent { + char d_name[NAME_MAX + 1]; + + /*** Operating system specific part ***/ +# if defined(DIRENT_WIN32_INTERFACE) /*WIN32*/ + WIN32_FIND_DATA data; +# elif defined(DIRENT_MSDOS_INTERFACE) /*MSDOS*/ +# if defined(DIRENT_USE_FFBLK) + struct ffblk data; +# else + struct _find_t data; +# endif +# endif + } dirent; + + /* DIR substitute structure containing directory name. The name is + * essential for the operation of ``rewinndir'' function. */ + typedef struct DIR { + char *dirname; /* directory being scanned */ + dirent current; /* current entry */ + int dirent_filled; /* is current un-processed? */ + + /*** Operating system specific part ***/ +# if defined(DIRENT_WIN32_INTERFACE) + HANDLE search_handle; +# elif defined(DIRENT_MSDOS_INTERFACE) +# endif + } DIR; + +# ifdef __cplusplus +extern "C" { +# endif + +/* supply prototypes for dirent functions */ +static DIR *opendir (const char *dirname); +static struct dirent *readdir (DIR *dirp); +static int closedir (DIR *dirp); +static void rewinddir (DIR *dirp); + +/* + * Implement dirent interface as static functions so that the user does not + * need to change his project in any way to use dirent function. With this + * it is sufficient to include this very header from source modules using + * dirent functions and the functions will be pulled in automatically. + */ +#include +#include +#include +#include +#include + +/* use ffblk instead of _find_t if requested */ +#if defined(DIRENT_USE_FFBLK) +# define _A_ARCH (FA_ARCH) +# define _A_HIDDEN (FA_HIDDEN) +# define _A_NORMAL (0) +# define _A_RDONLY (FA_RDONLY) +# define _A_SUBDIR (FA_DIREC) +# define _A_SYSTEM (FA_SYSTEM) +# define _A_VOLID (FA_LABEL) +# define _dos_findnext(dest) findnext(dest) +# define _dos_findfirst(name,flags,dest) findfirst(name,dest,flags) +#endif + +static int _initdir (DIR *p); +static const char *_getdirname (const struct dirent *dp); +static void _setdirname (struct DIR *dirp); + +/* + * + * open directory stream for reading + * DIR *opendir (const char *dirname); + * + * Open named directory stream for read and return pointer to the + * internal working area that is used for retrieving individual directory + * entries. The internal working area has no fields of your interest. + * + * Returns a pointer to the internal working area or NULL in case the + * directory stream could not be opened. Global `errno' variable will set + * in case of error as follows: + * + * + * [EACESS |Permission denied. + * [EMFILE |Too many open files used by the process. + * [ENFILE |Too many open files in system. + * [ENOENT |Directory does not exist. + * [ENOMEM |Insufficient memory. + * [ENOTDIR |dirname does not refer to directory. This value is not + * reliable on MS-DOS and MS-Windows platforms. Many + * implementations return ENOENT even when the name refers to a + * file.] + *
+ *
+ */ +static DIR *opendir(const char *dirname) +{ + DIR *dirp; + assert (dirname != NULL); + + dirp = (DIR*)malloc (sizeof (struct DIR)); + if (dirp != NULL) { + char *p; + + /* allocate room for directory name */ + dirp->dirname = (char*) malloc (strlen (dirname) + 1 + strlen ("\\*.*")); + if (dirp->dirname == NULL) { + /* failed to duplicate directory name. errno set by malloc() */ + free (dirp); + return NULL; + } + /* Copy directory name while appending directory separator and "*.*". + * Directory separator is not appended if the name already ends with + * drive or directory separator. Directory separator is assumed to be + * '/' or '\' and drive separator is assumed to be ':'. */ + strcpy (dirp->dirname, dirname); + p = strchr (dirp->dirname, '\0'); + if (dirp->dirname < p && + *(p - 1) != '\\' && *(p - 1) != '/' && *(p - 1) != ':') + { + strcpy (p++, "\\"); + } +# ifdef DIRENT_WIN32_INTERFACE + strcpy (p, "*"); /*scan files with and without extension in win32*/ +# else + strcpy (p, "*.*"); /*scan files with and without extension in DOS*/ +# endif + + /* open stream */ + if (_initdir (dirp) == 0) { + /* initialization failed */ + free (dirp->dirname); + free (dirp); + return NULL; + } + } + return dirp; +} + + +/* + * + * read a directory entry + * struct dirent *readdir (DIR *dirp); + * + * Read individual directory entry and return pointer to a structure + * containing the name of the entry. Individual directory entries returned + * include normal files, sub-directories, pseudo-directories "." and ".." + * and also volume labels, hidden files and system files in MS-DOS and + * MS-Windows. You might want to use stat(2) function to determinate which + * one are you dealing with. Many dirent implementations already contain + * equivalent information in dirent structure but you cannot depend on + * this. + * + * The dirent structure contains several system dependent fields that + * generally have no interest to you. The only interesting one is char + * d_name[] that is also portable across different systems. The d_name + * field contains the name of the directory entry without leading path. + * While d_name is portable across different systems the actual storage + * capacity of d_name varies from system to system and there is no portable + * way to find out it at compile time as different systems define the + * capacity of d_name with different macros and some systems do not define + * capacity at all (besides actual declaration of the field). If you really + * need to find out storage capacity of d_name then you might want to try + * NAME_MAX macro. The NAME_MAX is defined in POSIX standard althought + * there are many MS-DOS and MS-Windows implementations those do not define + * it. There are also systems that declare d_name as "char d_name[1]" and + * then allocate suitable amount of memory at run-time. Thanks to Alain + * Decamps (Alain.Decamps@advalvas.be) for pointing it out to me. + * + * This all leads to the fact that it is difficult to allocate space + * for the directory names when the very same program is being compiled on + * number of operating systems. Therefore I suggest that you always + * allocate space for directory names dynamically. + * + * + * Returns a pointer to a structure containing name of the directory entry + * in `d_name' field or NULL if there was an error. In case of an error the + * global `errno' variable will set as follows: + * + * + * [EBADF |dir parameter refers to an invalid directory stream. This value + * is not set reliably on all implementations.] + *
+ *
+ */ +static struct dirent * +readdir (DIR *dirp) +{ + assert(dirp != NULL); + if (dirp == NULL) { + errno = EBADF; + return NULL; + } + +#if defined(DIRENT_WIN32_INTERFACE) + if (dirp->search_handle == INVALID_HANDLE_VALUE) { + /* directory stream was opened/rewound incorrectly or it ended normally */ + errno = EBADF; + return NULL; + } +#endif + + if (dirp->dirent_filled != 0) { + /* + * Directory entry has already been retrieved and there is no need to + * retrieve a new one. Directory entry will be retrieved in advance + * when the user calls readdir function for the first time. This is so + * because real dirent has separate functions for opening and reading + * the stream whereas Win32 and DOS dirents open the stream + * automatically when we retrieve the first file. Therefore, we have to + * save the first file when opening the stream and later we have to + * return the saved entry when the user tries to read the first entry. + */ + dirp->dirent_filled = 0; + } else { + /* fill in entry and return that */ +#if defined(DIRENT_WIN32_INTERFACE) + if (FindNextFile (dirp->search_handle, &dirp->current.data) == FALSE) { + /* Last file has been processed or an error occured */ + FindClose (dirp->search_handle); + dirp->search_handle = INVALID_HANDLE_VALUE; + errno = ENOENT; + return NULL; + } + +# elif defined(DIRENT_MSDOS_INTERFACE) + if (_dos_findnext (&dirp->current.data) != 0) { + /* _dos_findnext and findnext will set errno to ENOENT when no + * more entries could be retrieved. */ + return NULL; + } +# endif + + _setdirname (dirp); + assert (dirp->dirent_filled == 0); + } + return &dirp->current; +} + + +/* + * + * close directory stream. + * int closedir (DIR *dirp); + * + * Close directory stream opened by the `opendir' function. Close of + * directory stream invalidates the DIR structure as well as previously read + * dirent entry. + * + * The function typically returns 0 on success and -1 on failure but + * the function may be declared to return void on same systems. At least + * Borland C/C++ and some UNIX implementations use void as a return type. + * The dirent wrapper tries to define VOID_CLOSEDIR whenever closedir is + * known to return nothing. The very same definition is made by the GNU + * autoconf if you happen to use it. + * + * The global `errno' variable will set to EBADF in case of error. + * + */ +static int +closedir (DIR *dirp) +{ + int retcode = 0; + + /* make sure that dirp points to legal structure */ + assert (dirp != NULL); + if (dirp == NULL) { + errno = EBADF; + return -1; + } + + /* free directory name and search handles */ + if (dirp->dirname != NULL) free (dirp->dirname); + +#if defined(DIRENT_WIN32_INTERFACE) + if (dirp->search_handle != INVALID_HANDLE_VALUE) { + if (FindClose (dirp->search_handle) == FALSE) { + /* Unknown error */ + retcode = -1; + errno = EBADF; + } + } +#endif + + /* clear dirp structure to make sure that it cannot be used anymore*/ + memset (dirp, 0, sizeof (*dirp)); +# if defined(DIRENT_WIN32_INTERFACE) + dirp->search_handle = INVALID_HANDLE_VALUE; +# endif + + free (dirp); + return retcode; +} + + +/* + * + * rewind directory stream to the beginning + * void rewinddir (DIR *dirp); + * + * Rewind directory stream to the beginning so that the next call of + * readdir() returns the very first directory entry again. However, note + * that next call of readdir() may not return the same directory entry as it + * did in first time. The directory stream may have been affected by newly + * created files. + * + * Almost every dirent implementation ensure that rewinddir will update + * the directory stream to reflect any changes made to the directory entries + * since the previous ``opendir'' or ``rewinddir'' call. Keep an eye on + * this if your program depends on the feature. I know at least one dirent + * implementation where you are required to close and re-open the stream to + * see the changes. + * + * Returns nothing. If something went wrong while rewinding, you will + * notice it later when you try to retrieve the first directory entry. + */ +static void +rewinddir (DIR *dirp) +{ + /* make sure that dirp is legal */ + assert (dirp != NULL); + if (dirp == NULL) { + errno = EBADF; + return; + } + assert (dirp->dirname != NULL); + + /* close previous stream */ +#if defined(DIRENT_WIN32_INTERFACE) + if (dirp->search_handle != INVALID_HANDLE_VALUE) { + if (FindClose (dirp->search_handle) == FALSE) { + /* Unknown error */ + errno = EBADF; + } + } +#endif + + /* re-open previous stream */ + if (_initdir (dirp) == 0) { + /* initialization failed but we cannot deal with error. User will notice + * error later when she tries to retrieve first directory enty. */ + /*EMPTY*/; + } +} + + +/* + * Open native directory stream object and retrieve first file. + * Be sure to close previous stream before opening new one. + */ +static int +_initdir (DIR *dirp) +{ + assert (dirp != NULL); + assert (dirp->dirname != NULL); + dirp->dirent_filled = 0; + +# if defined(DIRENT_WIN32_INTERFACE) + /* Open stream and retrieve first file */ + dirp->search_handle = FindFirstFile (dirp->dirname, &dirp->current.data); + if (dirp->search_handle == INVALID_HANDLE_VALUE) { + /* something went wrong but we don't know what. GetLastError() could + * give us more information about the error, but then we should map + * the error code into errno. */ + errno = ENOENT; + return 0; + } + +# elif defined(DIRENT_MSDOS_INTERFACE) + if (_dos_findfirst (dirp->dirname, + _A_SUBDIR | _A_RDONLY | _A_ARCH | _A_SYSTEM | _A_HIDDEN, + &dirp->current.data) != 0) + { + /* _dos_findfirst and findfirst will set errno to ENOENT when no + * more entries could be retrieved. */ + return 0; + } +# endif + + /* initialize DIR and it's first entry */ + _setdirname (dirp); + dirp->dirent_filled = 1; + return 1; +} + + +/* + * Return implementation dependent name of the current directory entry. + */ +static const char * +_getdirname (const struct dirent *dp) +{ +#if defined(DIRENT_WIN32_INTERFACE) + return dp->data.cFileName; + +#elif defined(DIRENT_USE_FFBLK) + return dp->data.ff_name; + +#else + return dp->data.name; +#endif +} + + +/* + * Copy name of implementation dependent directory entry to the d_name field. + */ +static void +_setdirname (struct DIR *dirp) { + /* make sure that d_name is long enough */ + assert (strlen (_getdirname (&dirp->current)) <= NAME_MAX); + + strncpy (dirp->current.d_name, + _getdirname (&dirp->current), + NAME_MAX); + dirp->current.d_name[NAME_MAX] = '\0'; /*char d_name[NAME_MAX+1]*/ +} + +# ifdef __cplusplus +} +# endif +# define NAMLEN(dp) ((int)(strlen((dp)->d_name))) + +#else +# error "missing dirent interface" +#endif + + +#endif /*DIRENT_H*/ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/CMakeLists.txt b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/CMakeLists.txt new file mode 100644 index 0000000..7b7541b --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/CMakeLists.txt @@ -0,0 +1,39 @@ +if(UNIX OR CYGWIN) + add_definitions(-O3) +elseif(MINGW) + add_definitions(-Os) +elseif(WIN32) + add_definitions(/Os) +endif() +# +include_regular_expression("^.*$") +# Defines the source code for the library +set(JP3DVM_SRCS +bio.c cio.c dwt.c event.c jp3d.c jp3d_lib.c mct.c mqc.c openjpeg.c pi.c raw.c t1.c t1_3d.c t2.c tcd.c tgt.c volume.c +) + +# Build the library +if(WIN32) + if(BUILD_SHARED_LIBS) + add_definitions(-DOPJ_EXPORTS) + else() + add_definitions(-DOPJ_STATIC) + endif() +endif() +add_library(${OPENJPEG_LIBRARY_NAME}_JP3D ${JP3DVM_SRCS}) +set_target_properties(${OPENJPEG_LIBRARY_NAME}_JP3D + PROPERTIES + VERSION 1.3.0 + SOVERSION 1) + +# Install library +install(TARGETS ${OPENJPEG_LIBRARY_NAME}_JP3D +DESTINATION ${OPENJPEG_INSTALL_LIB_DIR} COMPONENT Libraries +) + +# Install includes files +install(FILES openjpeg3d.h + DESTINATION ${OPENJPEG_INSTALL_INCLUDE_DIR}/openjpeg3d-1.3 +) +install(CODE + "execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink \$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${OPENJPEG_INSTALL_INCLUDE_DIR}/openjpeg3d-1.3/openjpeg3d.h \$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${OPENJPEG_INSTALL_INCLUDE_DIR}/openjpeg3d.h)") diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/bio.c b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/bio.c new file mode 100644 index 0000000..154176b --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/bio.c @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "opj_includes.h" + +/** @defgroup BIO BIO - Individual bit input-output stream */ +/*@{*/ + +/** @name Local static functions */ +/*@{*/ + +/** +Write a bit +@param bio BIO handle +@param b Bit to write (0 or 1) +*/ +static void bio_putbit(opj_bio_t *bio, int b); +/** +Read a bit +@param bio BIO handle +@return Returns the read bit +*/ +static int bio_getbit(opj_bio_t *bio); +/** +Write a byte +@param bio BIO handle +@return Returns 0 if successful, returns 1 otherwise +*/ +static int bio_byteout(opj_bio_t *bio); +/** +Read a byte +@param bio BIO handle +@return Returns 0 if successful, returns 1 otherwise +*/ +static int bio_bytein(opj_bio_t *bio); + +/*@}*/ + +/*@}*/ + + +/* +========================================================== + local functions +========================================================== +*/ + +static int bio_byteout(opj_bio_t *bio) { + bio->buf = (bio->buf << 8) & 0xffff; + bio->ct = bio->buf == 0xff00 ? 7 : 8; + if (bio->bp >= bio->end) { + return 1; + } + *bio->bp++ = bio->buf >> 8; + return 0; +} + +static int bio_bytein(opj_bio_t *bio) { + bio->buf = (bio->buf << 8) & 0xffff; + bio->ct = bio->buf == 0xff00 ? 7 : 8; + if (bio->bp >= bio->end) { + return 1; + } + bio->buf |= *bio->bp++; + return 0; +} + +static void bio_putbit(opj_bio_t *bio, int b) { + if (bio->ct == 0) { + bio_byteout(bio); + } + bio->ct--; + bio->buf |= b << bio->ct; +} + +/* MOD antonin */ +static int bio_getbit(opj_bio_t *bio) { +/* DOM */ + if (bio->ct == 0) { + bio_bytein(bio); + } + bio->ct--; + return (bio->buf >> bio->ct) & 1; +} + +/* +========================================================== + Bit Input/Output interface +========================================================== +*/ + +opj_bio_t* bio_create() { + opj_bio_t *bio = (opj_bio_t*)opj_malloc(sizeof(opj_bio_t)); + return bio; +} + +void bio_destroy(opj_bio_t *bio) { + if(bio) { + opj_free(bio); + } +} + +int bio_numbytes(opj_bio_t *bio) { + return (bio->bp - bio->start); +} + +void bio_init_enc(opj_bio_t *bio, unsigned char *bp, int len) { + bio->start = bp; + bio->end = bp + len; + bio->bp = bp; + bio->buf = 0; + bio->ct = 8; +} + +void bio_init_dec(opj_bio_t *bio, unsigned char *bp, int len) { + bio->start = bp; + bio->end = bp + len; + bio->bp = bp; + bio->buf = 0; + bio->ct = 0; +} + +void bio_write(opj_bio_t *bio, int v, int n) { + int i; + for (i = n - 1; i >= 0; i--) { + bio_putbit(bio, (v >> i) & 1); + } +} + +int bio_read(opj_bio_t *bio, int n) { + int i, v; + v = 0; + for (i = n - 1; i >= 0; i--) { + v += bio_getbit(bio) << i; + } + return v; +} + +int bio_flush(opj_bio_t *bio) { + bio->ct = 0; + if (bio_byteout(bio)) { + return 1; + } + if (bio->ct == 7) { + bio->ct = 0; + if (bio_byteout(bio)) { + return 1; + } + } + return 0; +} + +int bio_inalign(opj_bio_t *bio) { + bio->ct = 0; + if ((bio->buf & 0xff) == 0xff) { + if (bio_bytein(bio)) { + return 1; + } + bio->ct = 0; + } + return 0; +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/bio.h b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/bio.h new file mode 100644 index 0000000..179cc72 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/bio.h @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __BIO_H +#define __BIO_H +/** +@file bio.h +@brief Implementation of an individual bit input-output (BIO) + +The functions in BIO.C have for goal to realize an individual bit input - output. +*/ + +/** @defgroup BIO BIO - Individual bit input-output stream */ +/*@{*/ + +/** +Individual bit input-output stream (BIO) +*/ +typedef struct opj_bio { +/** pointer to the start of the buffer */ + unsigned char *start; +/** pointer to the end of the buffer */ + unsigned char *end; +/** pointer to the present position in the buffer */ + unsigned char *bp; +/** temporary place where each byte is read or written */ + unsigned int buf; +/** coder : number of bits free to write. decoder : number of bits read */ + int ct; +} opj_bio_t; + +/** @name Funciones generales */ +/*@{*/ +/* ----------------------------------------------------------------------- */ +/** +Create a new BIO handle +@return Returns a new BIO handle if successful, returns NULL otherwise +*/ +opj_bio_t* bio_create(); +/** +Destroy a previously created BIO handle +@param bio BIO handle to destroy +*/ +void bio_destroy(opj_bio_t *bio); +/** +Number of bytes written. +@param bio BIO handle +@return Returns the number of bytes written +*/ +int bio_numbytes(opj_bio_t *bio); +/** +Init encoder +@param bio BIO handle +@param bp Output buffer +@param len Output buffer length +*/ +void bio_init_enc(opj_bio_t *bio, unsigned char *bp, int len); +/** +Init decoder +@param bio BIO handle +@param bp Input buffer +@param len Input buffer length +*/ +void bio_init_dec(opj_bio_t *bio, unsigned char *bp, int len); +/** +Write bits +@param bio BIO handle +@param v Value of bits +@param n Number of bits to write +*/ +void bio_write(opj_bio_t *bio, int v, int n); +/** +Read bits +@param bio BIO handle +@param n Number of bits to read +@return Returns the corresponding read number +*/ +int bio_read(opj_bio_t *bio, int n); +/** +Flush bits +@param bio BIO handle +@return Returns 1 if successful, returns 0 otherwise +*/ +int bio_flush(opj_bio_t *bio); +/** +Passes the ending bits (coming from flushing) +@param bio BIO handle +@return Returns 1 if successful, returns 0 otherwise +*/ +int bio_inalign(opj_bio_t *bio); +/** +Read a bit +@param bio BIO handle +@return Returns the read bit +*/ +/* MOD antonin */ +//int bio_getbit(opj_bio_t *bio); +/* DOM */ +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __BIO_H */ + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/cio.c b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/cio.c new file mode 100644 index 0000000..d60c86d --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/cio.c @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "opj_includes.h" + +/* ----------------------------------------------------------------------- */ + +opj_cio_t* OPJ_CALLCONV opj_cio_open(opj_common_ptr cinfo, unsigned char *buffer, int length) { + opj_cp_t *cp = NULL; + opj_cio_t *cio = (opj_cio_t*)opj_malloc(sizeof(opj_cio_t)); + if(!cio) return NULL; + cio->cinfo = cinfo; + if(buffer && length) { + /* wrap a user buffer containing the encoded image */ + cio->openmode = OPJ_STREAM_READ; + cio->buffer = buffer; + cio->length = length; + } + else if(!buffer && !length && cinfo) { + /* allocate a buffer for the encoded image */ + cio->openmode = OPJ_STREAM_WRITE; + switch(cinfo->codec_format) { + case CODEC_J3D: + case CODEC_J2K: + cp = ((opj_j3d_t*)cinfo->j3d_handle)->cp; + break; + default: + opj_free(cio); + return NULL; + } + cio->length = cp->tdx * cp->tdy * cp->tdz * cp->tw * cp->th * cp->tl * 4; + cio->buffer = (unsigned char *)opj_malloc(cio->length); + if(!cio->buffer) { + opj_free(cio); + return NULL; + } + } + else { + opj_free(cio); + return NULL; + } + + /* Initialize byte IO */ + cio->start = cio->buffer; + cio->end = cio->buffer + cio->length; + cio->bp = cio->buffer; + + return cio; +} + +void OPJ_CALLCONV opj_cio_close(opj_cio_t *cio) { + if(cio) { + if(cio->openmode == OPJ_STREAM_WRITE) { + /* destroy the allocated buffer */ + opj_free(cio->buffer); + } + /* destroy the cio */ + opj_free(cio); + } +} + + +/* ----------------------------------------------------------------------- */ + +/* + * Get position in byte stream. + */ +int OPJ_CALLCONV cio_tell(opj_cio_t *cio) { + return cio->bp - cio->start; +} + +/* + * Set position in byte stream. + * + * pos : position, in number of bytes, from the beginning of the stream + */ +void OPJ_CALLCONV cio_seek(opj_cio_t *cio, int pos) { + cio->bp = cio->start + pos; +} + +/* + * Number of bytes left before the end of the stream. + */ +int cio_numbytesleft(opj_cio_t *cio) { + return cio->end - cio->bp; +} + +/* + * Get pointer to the current position in the stream. + */ +unsigned char *cio_getbp(opj_cio_t *cio) { + return cio->bp; +} + +/* + * Write a byte. + */ +bool cio_byteout(opj_cio_t *cio, unsigned char v) { + if (cio->bp >= cio->end) { + opj_event_msg(cio->cinfo, EVT_ERROR, "write error\n"); + return false; + } + *cio->bp++ = v; + return true; +} + +/* + * Read a byte. + */ +unsigned char cio_bytein(opj_cio_t *cio) { + if (cio->bp >= cio->end) { + opj_event_msg(cio->cinfo, EVT_ERROR, "read error\n"); + return 0; + } + return *cio->bp++; +} + +/* + * Write some bytes. + * + * v : value to write + * n : number of bytes to write + */ +unsigned int cio_write(opj_cio_t *cio, unsigned int v, int n) { + int i; + for (i = n - 1; i >= 0; i--) { + if( !cio_byteout(cio, (unsigned char) ((v >> (i << 3)) & 0xff)) ) + return 0; + } + return n; +} + +/* + * Read some bytes. + * + * n : number of bytes to read + * + * return : value of the n bytes read + */ +unsigned int cio_read(opj_cio_t *cio, int n) { + int i; + unsigned int v; + v = 0; + for (i = n - 1; i >= 0; i--) { + v += cio_bytein(cio) << (i << 3); + } + return v; +} + +/* + * Skip some bytes. + * + * n : number of bytes to skip + */ +void cio_skip(opj_cio_t *cio, int n) { + cio->bp += n; +} + +/* + * Write some bytes. + * + * v : value to write + * n : number of bytes to write + */ +int cio_write_int(opj_cio_t *cio, int v, int n) { + int i; + for (i = n - 1; i >= 0; i--) { + if( !cio_byteout(cio, (char) ((v >> (i << 3)) & 0xff)) ) + return 0; + } + return n; +} + +/* + * Read some bytes. + * + * n : number of bytes to read + * + * return : value of the n bytes read + */ +int cio_read_int(opj_cio_t *cio, int n) { + int i; + int v; + v = 0; + for (i = n - 1; i >= 0; i--) { + v += cio_bytein(cio) << (i << 3); + } + return v; +} + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/cio.h b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/cio.h new file mode 100644 index 0000000..415eeb0 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/cio.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __CIO_H +#define __CIO_H +/** +@file cio.h +@brief Implementation of a byte input-output process (CIO) + +The functions in CIO.C have for goal to realize a byte input / output process. +*/ + +/** @defgroup CIO CIO - byte input-output stream */ +/*@{*/ + +/** @name Funciones generales (see also openjpeg3d.h) */ +/*@{*/ +/* ----------------------------------------------------------------------- */ +/** +Number of bytes left before the end of the stream +@param cio CIO handle +@return Returns the number of bytes before the end of the stream +*/ +int cio_numbytesleft(opj_cio_t *cio); +/** +Get pointer to the current position in the stream +@param cio CIO handle +@return Returns a pointer to the current position +*/ +unsigned char *cio_getbp(opj_cio_t *cio); +/** +Write some bytes +@param cio CIO handle +@param v Value to write +@param n Number of bytes to write +@return Returns the number of bytes written or 0 if an error occured +*/ +unsigned int cio_write(opj_cio_t *cio, unsigned int v, int n); +/** +Read some bytes +@param cio CIO handle +@param n Number of bytes to read +@return Returns the value of the n bytes read +*/ +unsigned int cio_read(opj_cio_t *cio, int n); +/** +Skip some bytes +@param cio CIO handle +@param n Number of bytes to skip +*/ +void cio_skip(opj_cio_t *cio, int n); +/** +Write some bytes +@param cio CIO handle +@param v Signed integer value to write +@param n Number of bytes to write +@return Returns the number of bytes written or 0 if an error occured +*/ +int cio_write_int(opj_cio_t *cio, int v, int n); +/** +Read some bytes +@param cio CIO handle +@param n Number of bytes to read +@return Returns the value of the n bytes read +*/ +int cio_read_int(opj_cio_t *cio, int n); +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __CIO_H */ + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/dwt.c b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/dwt.c new file mode 100644 index 0000000..ff27e2b --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/dwt.c @@ -0,0 +1,1016 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * Copyrigth (c) 2006, Mónica Díez, LPI-UVA, Spain + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * NOTE: + * This is a modified version of the openjpeg dwt.c file. + * Average speed improvement compared to the original file (measured on + * my own machine, a P4 running at 3.0 GHz): + * 5x3 wavelets about 2 times faster + * 9x7 wavelets about 3 times faster + * for both, encoding and decoding. + * + * The better performance is caused by doing the 1-dimensional DWT + * within a temporary buffer where the data can be accessed sequential + * for both directions, horizontal and vertical. The 2d vertical DWT was + * the major bottleneck in the former version. + * + * I have also removed the "Add Patrick" part because it is not longer + * needed. + * + * 6/6/2005 + * -Ive (aka Reiner Wahler) + * mail: ive@lilysoft.com + */ + +#include "opj_includes.h" + +/** @defgroup DWT DWT - Implementation of a discrete wavelet transform */ +/*@{*/ + +/** @name Local static functions */ +/*@{*/ +unsigned int ops; +/** +Forward lazy transform (horizontal) +*/ +static void dwt_deinterleave_h(int *a, int *b, int dn, int sn, int cas); +/** +Forward lazy transform (vertical) +*/ +static void dwt_deinterleave_v(int *a, int *b, int dn, int sn, int x, int cas); +/** +Forward lazy transform (axial) +*/ +static void dwt_deinterleave_z(int *a, int *b, int dn, int sn, int xy, int cas); +/** +Inverse lazy transform (horizontal) +*/ +static void dwt_interleave_h(int *a, int *b, int dn, int sn, int cas); +/** +Inverse lazy transform (vertical) +*/ +static void dwt_interleave_v(int *a, int *b, int dn, int sn, int x, int cas); +/** +Inverse lazy transform (axial) +*/ +static void dwt_interleave_z(int *a, int *b, int dn, int sn, int xy, int cas); +/** +Forward 5-3 wavelet tranform in 1-D +*/ +static void dwt_encode_53(int *a, int dn, int sn, int cas); +static void dwt_encode_97(int *a, int dn, int sn, int cas); +/** +Inverse 5-3 wavelet tranform in 1-D +*/ +static void dwt_decode_53(int *a, int dn, int sn, int cas); +static void dwt_decode_97(int *a, int dn, int sn, int cas); +/** +Computing of wavelet transform L2 norms for arbitrary transforms +*/ +static double dwt_calc_wtnorms(int orient, int level[3], int dwtid[3], opj_wtfilt_t *wtfiltx, opj_wtfilt_t *wtfilty, opj_wtfilt_t *wtfiltz); +/** +Encoding of quantification stepsize +*/ +static void dwt_encode_stepsize(int stepsize, int numbps, opj_stepsize_t *bandno_stepsize); +/*@}*/ + +/*@}*/ + +#define S(i) a[(i)*2] +#define D(i) a[(1+(i)*2)] +#define S_(i) ((i)<0?S(0):((i)>=sn?S(sn-1):S(i))) +#define D_(i) ((i)<0?D(0):((i)>=dn?D(dn-1):D(i))) +/* new */ +#define SS_(i) ((i)<0?S(0):((i)>=dn?S(dn-1):S(i))) +#define DD_(i) ((i)<0?D(0):((i)>=sn?D(sn-1):D(i))) + +/*

*/ +/* This table contains the norms of the 5-3 wavelets for different bands. */ +/* */ +static double dwt_norm[10][10][10][8]; +static int flagnorm[10][10][10][8]; + +/*static const double dwt_norms[5][8][10] = { + {//ResZ=1 + {1.000, 1.500, 2.750, 5.375, 10.68, 21.34, 42.67, 85.33, 170.7, 341.3}, + {1.038, 1.592, 2.919, 5.703, 11.33, 22.64, 45.25, 90.48, 180.9}, + {1.038, 1.592, 2.919, 5.703, 11.33, 22.64, 45.25, 90.48, 180.9}, + {.7186, .9218, 1.586, 3.043, 6.019, 12.01, 24.00, 47.97, 95.93} + },{//ResZ=2 + {1.000, 1.8371, 2.750, 5.375, 10.68, 21.34, 42.67, 85.33, 170.7, 341.3}, + {1.2717, 1.592, 2.919, 5.703, 11.33, 22.64, 45.25, 90.48, 180.9}, + {1.2717, 1.592, 2.919, 5.703, 11.33, 22.64, 45.25, 90.48, 180.9}, + {.8803, .9218, 1.586, 3.043, 6.019, 12.01, 24.00, 47.97, 95.93}, + {1.2717}, + {.8803}, + {.8803}, + {.6093}, + },{ //ResZ=3 + {1.000, 1.8371, 4.5604, 5.375, 10.68, 21.34, 42.67, 85.33, 170.7, 341.3}, + {1.2717, 2.6403, 2.919, 5.703, 11.33, 22.64, 45.25, 90.48, 180.9}, + {1.2717, 2.6403, 2.919, 5.703, 11.33, 22.64, 45.25, 90.48, 180.9}, + {.8803, 1.5286, 1.586, 3.043, 6.019, 12.01, 24.00, 47.97, 95.93}, + {1.2717, 2.6403}, + {.8803, 1.5286}, + {.8803, 1.5286}, + {.6093, 0.8850}, + },{ //ResZ=4 + {1.000, 1.8371, 4.5604, 12.4614, 10.68, 21.34, 42.67, 85.33, 170.7, 341.3}, + {1.2717, 2.6403, 6.7691 , 5.703, 11.33, 22.64, 45.25, 90.48, 180.9}, + {1.2717, 2.6403, 6.7691 , 5.703, 11.33, 22.64, 45.25, 90.48, 180.9}, + {.8803, 1.5286, 3.6770 , 3.043, 6.019, 12.01, 24.00, 47.97, 95.93}, + {1.2717, 2.6403, 6.7691 }, + {.8803, 1.5286, 3.6770 }, + {.8803, 1.5286, 3.6770 }, + {.6093, 0.8850, 1.9974 }, + },{ //ResZ=5 + {1.000, 1.8371, 4.5604, 12.4614, 34.9025, 21.34, 42.67, 85.33, 170.7, 341.3}, + {1.2717, 2.6403, 6.7691 , 18.6304 , 11.33, 22.64, 45.25, 90.48, 180.9}, + {1.2717, 2.6403, 6.7691 , 18.6304, 11.33, 22.64, 45.25, 90.48, 180.9}, + {.8803, 1.5286, 3.6770 , 9.9446, 6.019, 12.01, 24.00, 47.97, 95.93}, + {1.2717, 2.6403, 6.7691, 18.6304}, + {.8803, 1.5286, 3.6770, 9.9446 }, + {.8803, 1.5286, 3.6770, 9.9446 }, + {.6093, 0.8850, 1.9974, 5.3083 }, + } +};*/ + +/* */ +/* This table contains the norms of the 9-7 wavelets for different bands. */ +/* */ +/*static const double dwt_norms_real[5][8][10] = { + {//ResZ==1 + {1.000, 1.9659, 4.1224, 8.4167, 16.9356, 33.9249, 67.8772, 135.7680, 271.5430, 543.0894}, + {1.0113, 1.9968, 4.1834, 8.5341, 17.1667, 34.3852, 68.7967, 137.6065, 275.2196}, + {1.0113, 1.9968, 4.1834, 8.5341, 17.1667, 34.3852, 68.7967, 137.6065, 275.2196}, + {0.5202, 0.9672, 2.0793, 4.3005, 8.6867, 17.4188, 34.8608, 69.7332, 139.4722} + }, { //ResZ==2 + {1.000, 2.7564, 4.1224, 8.4167, 16.9356, 33.9249, 67.8772, 135.7680, 271.5430, 543.0894}, + {1.4179, 1.9968, 4.1834, 8.5341, 17.1667, 34.3852, 68.7967, 137.6065, 275.2196}, + {1.4179, 1.9968, 4.1834, 8.5341, 17.1667, 34.3852, 68.7967, 137.6065, 275.2196}, + {0.7294, 0.9672, 2.0793, 4.3005, 8.6867, 17.4188, 34.8608, 69.7332, 139.4722}, + {1.4179}, + {0.7294}, + {0.7294}, + {0.3752} //HHH + },{ //ResZ==3 + {1.000, 2.7564, 8.3700, 8.4167, 16.9356, 33.9249, 67.8772, 135.7680, 271.5430, 543.0894}, + {1.4179, 4.0543, 4.1834, 8.5341, 17.1667, 34.3852, 68.7967, 137.6065, 275.2196}, + {1.4179, 4.0543, 4.1834, 8.5341, 17.1667, 34.3852, 68.7967, 137.6065, 275.2196}, + {0.7294, 1.9638, 2.0793, 4.3005, 8.6867, 17.4188, 34.8608, 69.7332, 139.4722}, + {1.4179, 4.0543}, + {0.7294, 1.9638}, + {0.7294, 1.9638}, + {0.3752, 0.9512} //HHH + },{ //ResZ==4 + {1.000, 2.7564, 8.3700, 24.4183, 16.9356, 33.9249, 67.8772, 135.7680, 271.5430, 543.0894}, + {1.4179, 4.0543, 12.1366, 8.5341, 17.1667, 34.3852, 68.7967, 137.6065, 275.2196}, + {1.4179, 4.0543, 12.1366, 8.5341, 17.1667, 34.3852, 68.7967, 137.6065, 275.2196}, + {0.7294, 1.9638, 6.0323, 4.3005, 8.6867, 17.4188, 34.8608, 69.7332, 139.4722}, + {1.4179, 4.0543, 12.1366}, + {0.7294, 1.9638, 6.0323}, + {0.7294, 1.9638, 6.0323}, + {0.3752, 0.9512, 2.9982} //HHH + },{ //ResZ==5 + {1.000, 2.7564, 8.3700, 24.4183, 69.6947, 33.9249, 67.8772, 135.7680, 271.5430, 543.0894}, + {1.4179, 4.0543, 12.1366, 35.1203, 17.1667, 34.3852, 68.7967, 137.6065, 275.2196}, + {1.4179, 4.0543, 12.1366, 35.1203, 17.1667, 34.3852, 68.7967, 137.6065, 275.2196}, + {0.7294, 1.9638, 6.0323, 17.6977, 8.6867, 17.4188, 34.8608, 69.7332, 139.4722}, + {1.4179, 4.0543, 12.1366, 35.1203}, + {0.7294, 1.9638, 6.0323, 17.6977}, + {0.7294, 1.9638, 6.0323, 17.6977}, + {0.3752, 0.9512, 2.9982, 8.9182} //HHH + } +};*/ + +static opj_atk_t atk_info_wt[] = { + {0, 1, J3D_ATK_WS, J3D_ATK_IRR, 0, J3D_ATK_WS, 1.230174104, 4, {0}, {0}, {0}, {1,1,1,1}, {-1.586134342059924, -0.052980118572961, 0.882911075530934, 0.443506852043971}},/* WT 9-7 IRR*/ + {1, 0, J3D_ATK_WS, J3D_ATK_REV, 0, J3D_ATK_WS, 0, 2, {0}, {1,2}, {1,2}, {1,1}, {-1,1}},/* WT 5-3 REV*/ + {2, 0, J3D_ATK_ARB, J3D_ATK_REV, 0, J3D_ATK_CON, 0, 2, {0,0}, {0,1}, {0,1}, {1,1}, {{-1},{1}}}, /* WT 2-2 REV*/ + {3, 0, J3D_ATK_ARB, J3D_ATK_REV, 1, J3D_ATK_CON, 0, 3, {0,0,-1}, {0,1,2}, {0,1,2}, {1,1,3}, {{-1},{1},{1,0,-1}}}, /* WT 2-6 REV*/ + {4, 0, J3D_ATK_ARB, J3D_ATK_REV, 1, J3D_ATK_CON, 0, 3, {0,0,-2}, {0,1,6}, {0,1,32}, {1,1,5}, {{-1},{1},{-3,22,0,-22,3}}}, /* WT 2-10 REV*/ + {5, 1, J3D_ATK_ARB, J3D_ATK_IRR, 1, J3D_ATK_WS, 1, 7, {0}, {0}, {0}, {1,1,2,1,2,1,3},{{-1},{1.58613434206},{-0.460348209828, 0.460348209828},{0.25},{0.374213867768,-0.374213867768},{-1.33613434206},{0.29306717103,0,-0.29306717103}}}, /* WT 6-10 IRR*/ + {6, 1, J3D_ATK_ARB, J3D_ATK_IRR, 0, J3D_ATK_WS, 1, 11, {0}, {0}, {0}, {1,1,2,1,2,1,2,1,2,1,5},{{-1},{0,99715069105},{-1.00573127827, 1.00573127827},{-0.27040357631},{2.20509972343, -2.20509972343},{0.08059995736}, + {-1.62682532350, 1.62682532350},{0.52040357631},{0.60404664250, -0.60404664250},{-0.82775064841},{-0.06615812964, 0.29402137720, 0, -0.29402137720, 0.06615812964}}}, /* WT 10-18 IRR*/ + {7, 1, J3D_ATK_WS, J3D_ATK_IRR, 0, J3D_ATK_WS, 1, 2, {0}, {0}, {0}, {1,1}, {-0.5, 0.25}}, /* WT 5-3 IRR*/ + {8, 0, J3D_ATK_WS, J3D_ATK_REV, 0, J3D_ATK_WS, 0, 2, {0}, {4,4}, {8,8}, {2,2}, {{-9,1},{5,-1}}} /* WT 13-7 REV*/ +}; +/* +========================================================== + local functions +========================================================== +*/ + +/* */ +/* Forward lazy transform (horizontal). */ +/* */ +static void dwt_deinterleave_h(int *a, int *b, int dn, int sn, int cas) { + int i; + for (i=0; i */ +/* Forward lazy transform (vertical). */ +/* */ +static void dwt_deinterleave_v(int *a, int *b, int dn, int sn, int x, int cas) { + int i; + for (i=0; i */ +/* Forward lazy transform (axial). */ +/* */ +static void dwt_deinterleave_z(int *a, int *b, int dn, int sn, int xy, int cas) { + int i; + for (i=0; i */ +/* Inverse lazy transform (horizontal). */ +/* */ +static void dwt_interleave_h(int *a, int *b, int dn, int sn, int cas) { + int i; + int *ai = NULL; + int *bi = NULL; + ai = a; + bi = b + cas; + for (i = 0; i < sn; i++) { + *bi = *ai; + bi += 2; + ai++; + } + ai = a + sn; + bi = b + 1 - cas; + for (i = 0; i < dn; i++) { + *bi = *ai; + bi += 2; + ai++; + } +} + +/* */ +/* Inverse lazy transform (vertical). */ +/* */ +static void dwt_interleave_v(int *a, int *b, int dn, int sn, int x, int cas) { + int i; + int *ai = NULL; + int *bi = NULL; + ai = a; + bi = b + cas; + for (i = 0; i < sn; i++) { + *bi = *ai; + bi += 2; + ai += x; + } + ai = a + (sn * x); + bi = b + 1 - cas; + for (i = 0; i < dn; i++) { + *bi = *ai; + bi += 2; + ai += x; + } +} + +/* */ +/* Inverse lazy transform (axial). */ +/* */ +static void dwt_interleave_z(int *a, int *b, int dn, int sn, int xy, int cas) { + int i; + int *ai = NULL; + int *bi = NULL; + ai = a; + bi = b + cas; + for (i = 0; i < sn; i++) { + *bi = *ai; + bi += 2; + ai += xy; + } + ai = a + (sn * xy); + bi = b + 1 - cas; + for (i = 0; i < dn; i++) { + *bi = *ai; + bi += 2; + ai += xy; + } +} + + +/* */ +/* Forward 5-3 or 9-7 wavelet tranform in 1-D. */ +/* */ +static void dwt_encode_53(int *a, int dn, int sn, int cas) { + int i; + + if (!cas) { + if ((dn > 0) || (sn > 1)) { /* NEW : CASE ONE ELEMENT */ + //for (i = 0; i < dn; i++) D(i) -= (S_(i) + S_(i + 1)) >> 1; + //for (i = 0; i < sn; i++) S(i) += (D_(i - 1) + D_(i) + 2) >> 2; + for (i = 0; i < dn; i++){ + D(i) -= (S_(i) + S_(i + 1)) >> 1; + //ops += 2; + } + for (i = 0; i < sn; i++){ + S(i) += (D_(i - 1) + D_(i) + 2) >> 2; + //ops += 3; + } + } + } else { + /*if (!sn && dn == 1) + S(0) *= 2; + else { + for (i = 0; i < dn; i++) S(i) -= (DD_(i) + DD_(i - 1)) >> 1; + for (i = 0; i < sn; i++) D(i) += (SS_(i) + SS_(i + 1) + 2) >> 2; + }*/ + if (!sn && dn == 1){ + S(0) *= 2; + //ops++; + } else { + for (i = 0; i < dn; i++){ + S(i) -= (DD_(i) + DD_(i - 1)) >> 1; + // ops += 2; + } + for (i = 0; i < sn; i++){ + D(i) += (SS_(i) + SS_(i + 1) + 2) >> 2; + // ops += 3; + } + } + } +} +static void dwt_encode_97(int *a, int dn, int sn, int cas) { + int i; + + if (!cas) { + if ((dn > 0) || (sn > 1)) { /* NEW : CASE ONE ELEMENT */ + for (i = 0; i < dn; i++) + D(i) -= fix_mul(S_(i) + S_(i + 1), 12993); + for (i = 0; i < sn; i++) + S(i) -= fix_mul(D_(i - 1) + D_(i), 434); + for (i = 0; i < dn; i++) + D(i) += fix_mul(S_(i) + S_(i + 1), 7233); + for (i = 0; i < sn; i++) + S(i) += fix_mul(D_(i - 1) + D_(i), 3633); + for (i = 0; i < dn; i++) + D(i) = fix_mul(D(i), 5038); /*5038 */ + for (i = 0; i < sn; i++) + S(i) = fix_mul(S(i), 6659); /*6660 */ + } + } else { + if ((sn > 0) || (dn > 1)) { /* NEW : CASE ONE ELEMENT */ + for (i = 0; i < dn; i++) + S(i) -= fix_mul(DD_(i) + DD_(i - 1), 12993); + for (i = 0; i < sn; i++) + D(i) -= fix_mul(SS_(i) + SS_(i + 1), 434); + for (i = 0; i < dn; i++) + S(i) += fix_mul(DD_(i) + DD_(i - 1), 7233); + for (i = 0; i < sn; i++) + D(i) += fix_mul(SS_(i) + SS_(i + 1), 3633); + for (i = 0; i < dn; i++) + S(i) = fix_mul(S(i), 5038); /*5038 */ + for (i = 0; i < sn; i++) + D(i) = fix_mul(D(i), 6659); /*6660 */ + } + } +} +/* */ +/* Inverse 5-3 or 9-7 wavelet tranform in 1-D. */ +/* */ +static void dwt_decode_53(int *a, int dn, int sn, int cas) { + int i; + if (!cas) { + if ((dn > 0) || (sn > 1)) { /* NEW : CASE ONE ELEMENT */ + for (i = 0; i < sn; i++) S(i) -= (D_(i - 1) + D_(i) + 2) >> 2; + for (i = 0; i < dn; i++) D(i) += (S_(i) + S_(i + 1)) >> 1; + } + } else { + if (!sn && dn == 1) /* NEW : CASE ONE ELEMENT */ + S(0) /= 2; + else { + for (i = 0; i < sn; i++) D(i) -= (SS_(i) + SS_(i + 1) + 2) >> 2; + for (i = 0; i < dn; i++) S(i) += (DD_(i) + DD_(i - 1)) >> 1; + } + } +} +static void dwt_decode_97(int *a, int dn, int sn, int cas) { + int i; + + if (!cas) { + if ((dn > 0) || (sn > 1)) { /* NEW : CASE ONE ELEMENT */ + for (i = 0; i < sn; i++) + S(i) = fix_mul(S(i), 10078); /* 10076 */ + for (i = 0; i < dn; i++) + D(i) = fix_mul(D(i), 13318); /* 13320 */ + for (i = 0; i < sn; i++) + S(i) -= fix_mul(D_(i - 1) + D_(i), 3633); + for (i = 0; i < dn; i++) + D(i) -= fix_mul(S_(i) + S_(i + 1), 7233); + for (i = 0; i < sn; i++) + S(i) += fix_mul(D_(i - 1) + D_(i), 434); + for (i = 0; i < dn; i++) + D(i) += fix_mul(S_(i) + S_(i + 1), 12994); /* 12993 */ + } + } else { + if ((sn > 0) || (dn > 1)) { /* NEW : CASE ONE ELEMENT */ + for (i = 0; i < sn; i++) + D(i) = fix_mul(D(i), 10078); /* 10076 */ + for (i = 0; i < dn; i++) + S(i) = fix_mul(S(i), 13318); /* 13320 */ + for (i = 0; i < sn; i++) + D(i) -= fix_mul(SS_(i) + SS_(i + 1), 3633); + for (i = 0; i < dn; i++) + S(i) -= fix_mul(DD_(i) + DD_(i - 1), 7233); + for (i = 0; i < sn; i++) + D(i) += fix_mul(SS_(i) + SS_(i + 1), 434); + for (i = 0; i < dn; i++) + S(i) += fix_mul(DD_(i) + DD_(i - 1), 12994); /* 12993 */ + } + } +} + + +/* */ +/* Get norm of arbitrary wavelet transform. */ +/* */ +static int upandconv(double *nXPS, double *LPS, int lenXPS, int lenLPS) { + /* Perform the convolution of the vectors. */ + int i,j; + double *tmp = (double *)opj_malloc(2*lenXPS * sizeof(double)); + //Upsample + memset(tmp, 0, 2*lenXPS*sizeof(double)); + for (i = 0; i < lenXPS; i++) { + *(tmp + 2*i) = *(nXPS + i); + *(nXPS + i) = 0; + } + //Convolution + for (i = 0; i < 2*lenXPS; i++) { + for (j = 0; j < lenLPS; j++) { + *(nXPS+i+j) = *(nXPS+i+j) + *(tmp + i) * *(LPS + j); + //fprintf(stdout,"*(tmp + %d) * *(LPS + %d) = %f * %f \n",i,j,*(tmp + i),*(LPS + j)); + } + } + free(tmp); + return 2*lenXPS+lenLPS-1; +} + +static double dwt_calc_wtnorms(int orient, int level[3], int dwtid[3], opj_wtfilt_t *wtfiltX, opj_wtfilt_t *wtfiltY, opj_wtfilt_t *wtfiltZ) { + int i, lenLPS, lenHPS; + double Lx = 0, Ly= 0, Hx= 0, Hy= 0, Lz= 0, Hz= 0; + double *nLPSx, *nHPSx,*nLPSy, *nHPSy,*nLPSz, *nHPSz; + int levelx, levely, levelz; + + levelx = (orient == 0) ? level[0]-1 : level[0]; + levely = (orient == 0) ? level[1]-1 : level[1]; + levelz = (orient == 0) ? level[2]-1 : level[2]; + + //X axis + lenLPS = wtfiltX->lenLPS; + lenHPS = wtfiltX->lenHPS; + for (i = 0; i < levelx; i++) { + lenLPS *= 2; + lenHPS *= 2; + lenLPS += wtfiltX->lenLPS - 1; + lenHPS += wtfiltX->lenLPS - 1; + } + nLPSx = (double *)opj_malloc(lenLPS * sizeof(double)); + nHPSx = (double *)opj_malloc(lenHPS * sizeof(double)); + + memcpy(nLPSx, wtfiltX->LPS, wtfiltX->lenLPS * sizeof(double)); + memcpy(nHPSx, wtfiltX->HPS, wtfiltX->lenHPS * sizeof(double)); + lenLPS = wtfiltX->lenLPS; + lenHPS = wtfiltX->lenHPS; + for (i = 0; i < levelx; i++) { + lenLPS = upandconv(nLPSx, wtfiltX->LPS, lenLPS, wtfiltX->lenLPS); + lenHPS = upandconv(nHPSx, wtfiltX->LPS, lenHPS, wtfiltX->lenLPS); + } + for (i = 0; i < lenLPS; i++) + Lx += nLPSx[i] * nLPSx[i]; + for (i = 0; i < lenHPS; i++) + Hx += nHPSx[i] * nHPSx[i]; + Lx = sqrt(Lx); + Hx = sqrt(Hx); + free(nLPSx); + free(nHPSx); + + //Y axis + if (dwtid[0] != dwtid[1] || level[0] != level[1]){ + lenLPS = wtfiltY->lenLPS; + lenHPS = wtfiltY->lenHPS; + for (i = 0; i < levely; i++) { + lenLPS *= 2; + lenHPS *= 2; + lenLPS += wtfiltY->lenLPS - 1; + lenHPS += wtfiltY->lenLPS - 1; + } + nLPSy = (double *)opj_malloc(lenLPS * sizeof(double)); + nHPSy = (double *)opj_malloc(lenHPS * sizeof(double)); + + memcpy(nLPSy, wtfiltY->LPS, wtfiltY->lenLPS * sizeof(double)); + memcpy(nHPSy, wtfiltY->HPS, wtfiltY->lenHPS * sizeof(double)); + lenLPS = wtfiltY->lenLPS; + lenHPS = wtfiltY->lenHPS; + for (i = 0; i < levely; i++) { + lenLPS = upandconv(nLPSy, wtfiltY->LPS, lenLPS, wtfiltY->lenLPS); + lenHPS = upandconv(nHPSy, wtfiltY->LPS, lenHPS, wtfiltY->lenLPS); + } + for (i = 0; i < lenLPS; i++) + Ly += nLPSy[i] * nLPSy[i]; + for (i = 0; i < lenHPS; i++) + Hy += nHPSy[i] * nHPSy[i]; + Ly = sqrt(Ly); + Hy = sqrt(Hy); + free(nLPSy); + free(nHPSy); + } else { + Ly = Lx; + Hy = Hx; + } + //Z axis + if (levelz >= 0) { + lenLPS = wtfiltZ->lenLPS; + lenHPS = wtfiltZ->lenHPS; + for (i = 0; i < levelz; i++) { + lenLPS *= 2; + lenHPS *= 2; + lenLPS += wtfiltZ->lenLPS - 1; + lenHPS += wtfiltZ->lenLPS - 1; + } + nLPSz = (double *)opj_malloc(lenLPS * sizeof(double)); + nHPSz = (double *)opj_malloc(lenHPS * sizeof(double)); + + memcpy(nLPSz, wtfiltZ->LPS, wtfiltZ->lenLPS * sizeof(double)); + memcpy(nHPSz, wtfiltZ->HPS, wtfiltZ->lenHPS * sizeof(double)); + lenLPS = wtfiltZ->lenLPS; + lenHPS = wtfiltZ->lenHPS; + for (i = 0; i < levelz; i++) { + lenLPS = upandconv(nLPSz, wtfiltZ->LPS, lenLPS, wtfiltZ->lenLPS); + lenHPS = upandconv(nHPSz, wtfiltZ->LPS, lenHPS, wtfiltZ->lenLPS); + } + for (i = 0; i < lenLPS; i++) + Lz += nLPSz[i] * nLPSz[i]; + for (i = 0; i < lenHPS; i++) + Hz += nHPSz[i] * nHPSz[i]; + Lz = sqrt(Lz); + Hz = sqrt(Hz); + free(nLPSz); + free(nHPSz); + } else { + Lz = 1.0; Hz = 1.0; + } + switch (orient) { + case 0: + return Lx * Ly * Lz; + case 1: + return Lx * Hy * Lz; + case 2: + return Hx * Ly * Lz; + case 3: + return Hx * Hy * Lz; + case 4: + return Lx * Ly * Hz; + case 5: + return Lx * Hy * Hz; + case 6: + return Hx * Ly * Hz; + case 7: + return Hx * Hy * Hz; + default: + return -1; + } + +} +static void dwt_getwtfilters(opj_wtfilt_t *wtfilt, int dwtid) { + if (dwtid == 0) { //DWT 9-7 + wtfilt->lenLPS = 7; wtfilt->lenHPS = 9; + wtfilt->LPS = (double *)opj_malloc(wtfilt->lenLPS * sizeof(double)); + wtfilt->HPS = (double *)opj_malloc(wtfilt->lenHPS * sizeof(double)); + wtfilt->LPS[0] = -0.091271763114; wtfilt->HPS[0] = 0.026748757411; + wtfilt->LPS[1] = -0.057543526228; wtfilt->HPS[1] = 0.016864118443; + wtfilt->LPS[2] = 0.591271763114; wtfilt->HPS[2] = -0.078223266529; + wtfilt->LPS[3] = 1.115087052457; wtfilt->HPS[3] = -0.266864118443; + wtfilt->LPS[4] = 0.591271763114; wtfilt->HPS[4] = 0.602949018236; + wtfilt->LPS[5] = -0.057543526228; wtfilt->HPS[5] = -0.266864118443; + wtfilt->LPS[6] = -0.091271763114; wtfilt->HPS[6] = -0.078223266529; + wtfilt->HPS[7] = 0.016864118443; + wtfilt->HPS[8] = 0.026748757411; + } else if (dwtid == 1) { //DWT 5-3 + wtfilt->lenLPS = 3; wtfilt->lenHPS = 5; + wtfilt->LPS = (double *)opj_malloc(wtfilt->lenLPS * sizeof(double)); + wtfilt->HPS = (double *)opj_malloc(wtfilt->lenHPS * sizeof(double)); + wtfilt->LPS[0] = 0.5; wtfilt->HPS[0] = -0.125; + wtfilt->LPS[1] = 1; wtfilt->HPS[1] = -0.25; + wtfilt->LPS[2] = 0.5; wtfilt->HPS[2] = 0.75; + wtfilt->HPS[3] = -0.25; + wtfilt->HPS[4] = -0.125; + } else { + fprintf(stdout,"[ERROR] Sorry, this wavelet hasn't been implemented so far ... Try another one :-)\n"); + exit(1); + } +} +/* */ +/* Encoding of quantization stepsize for each subband. */ +/* */ +static void dwt_encode_stepsize(int stepsize, int numbps, opj_stepsize_t *bandno_stepsize) { + int p, n; + p = int_floorlog2(stepsize) - 13; + n = 11 - int_floorlog2(stepsize); + bandno_stepsize->mant = (n < 0 ? stepsize >> -n : stepsize << n) & 0x7ff; + bandno_stepsize->expn = numbps - p; + //if J3D_CCP_QNTSTY_NOQNT --> stepsize = 8192.0 --> p = 0, n = -2 --> mant = 0; expn = (prec+gain) + //else --> bandno_stepsize = (1<<(numbps - expn)) + (1<<(numbps - expn - 11)) * Ub +} + +/* +========================================================== + DWT interface +========================================================== +*/ +/* */ +/* Forward 5-3 wavelet tranform in 3-D. */ +/* */ +void dwt_encode(opj_tcd_tilecomp_t * tilec, int dwtid[3]) { + int i, j, k; + int x, y, z; + int w, h, wh, d; + int level,levelx,levely,levelz,diff; + int *a = NULL; + int *aj = NULL; + int *bj = NULL; + int *cj = NULL; + + ops = 0; + + memset(flagnorm,0,8000*sizeof(int)); + w = tilec->x1-tilec->x0; + h = tilec->y1-tilec->y0; + d = tilec->z1-tilec->z0; + wh = w * h; + levelx = tilec->numresolution[0]-1; + levely = tilec->numresolution[1]-1; + levelz = tilec->numresolution[2]-1; + level = int_max(levelx,int_max(levely,levelz)); + diff = tilec->numresolution[0] - tilec->numresolution[2]; + + a = tilec->data; + + for (x = 0, y = 0, z = 0; (x < levelx) && (y < levely); x++, y++, z++) { + int rw; /* width of the resolution level computed */ + int rh; /* heigth of the resolution level computed */ + int rd; /* depth of the resolution level computed */ + int rw1; /* width of the resolution level once lower than computed one */ + int rh1; /* height of the resolution level once lower than computed one */ + int rd1; /* depth of the resolution level once lower than computed one */ + int cas_col; /* 0 = non inversion on horizontal filtering 1 = inversion between low-pass and high-pass filtering */ + int cas_row; /* 0 = non inversion on vertical filtering 1 = inversion between low-pass and high-pass filtering */ + int cas_axl; /* 0 = non inversion on axial filtering 1 = inversion between low-pass and high-pass filtering */ + int dn, sn; + + rw = tilec->resolutions[level - x].x1 - tilec->resolutions[level - x].x0; + rh = tilec->resolutions[level - y].y1 - tilec->resolutions[level - y].y0; + rd = tilec->resolutions[level - z].z1 - tilec->resolutions[level - z].z0; + rw1= tilec->resolutions[level - x - 1].x1 - tilec->resolutions[level - x - 1].x0; + rh1= tilec->resolutions[level - y - 1].y1 - tilec->resolutions[level - y - 1].y0; + rd1= tilec->resolutions[level - z - 1].z1 - tilec->resolutions[level - z - 1].z0; + + cas_col = tilec->resolutions[level - x].x0 % 2; /* 0 = non inversion on horizontal filtering 1 = inversion between low-pass and high-pass filtering */ + cas_row = tilec->resolutions[level - y].y0 % 2; /* 0 = non inversion on vertical filtering 1 = inversion between low-pass and high-pass filtering */ + cas_axl = tilec->resolutions[level - z].z0 % 2; + + /*fprintf(stdout," x %d y %d z %d \n",x,y,z); + fprintf(stdout," levelx %d levely %d levelz %d \n",levelx,levely,levelz); + fprintf(stdout," z1 %d z0 %d\n",tilec->resolutions[level - z].z1,tilec->resolutions[level - z].z0); + fprintf(stdout," rw %d rh %d rd %d \n rw1 %d rh1 %d rd1 %d \n",rw,rh,rd,rw1,rh1,rd1);*/ + + for (i = 0; i < rd; i++) { + + cj = a + (i * wh); + + //Horizontal + sn = rw1; + dn = rw - rw1; + bj = (int*)opj_malloc(rw * sizeof(int)); + if (dwtid[0] == 0) { + for (j = 0; j < rh; j++) { + aj = cj + j * w; + for (k = 0; k < rw; k++) bj[k] = aj[k]; + dwt_encode_97(bj, dn, sn, cas_row); + dwt_deinterleave_h(bj, aj, dn, sn, cas_row); + } + } else if (dwtid[0] == 1) { + for (j = 0; j < rh; j++) { + aj = cj + j * w; + for (k = 0; k < rw; k++) bj[k] = aj[k]; + dwt_encode_53(bj, dn, sn, cas_row); + dwt_deinterleave_h(bj, aj, dn, sn, cas_row); + } + } + opj_free(bj); + + //Vertical + sn = rh1; + dn = rh - rh1; + bj = (int*)opj_malloc(rh * sizeof(int)); + if (dwtid[1] == 0) { /*DWT 9-7*/ + for (j = 0; j < rw; j++) { + aj = cj + j; + for (k = 0; k < rh; k++) bj[k] = aj[k*w]; + dwt_encode_97(bj, dn, sn, cas_col); + dwt_deinterleave_v(bj, aj, dn, sn, w, cas_col); + } + } else if (dwtid[1] == 1) { /*DWT 5-3*/ + for (j = 0; j < rw; j++) { + aj = cj + j; + for (k = 0; k < rh; k++) bj[k] = aj[k*w]; + dwt_encode_53(bj, dn, sn, cas_col); + dwt_deinterleave_v(bj, aj, dn, sn, w, cas_col); + } + } + opj_free(bj); + } + + if (z < levelz){ + //Axial fprintf(stdout,"Axial DWT Transform %d %d %d\n",z,rd,rd1); + sn = rd1; + dn = rd - rd1; + bj = (int*)opj_malloc(rd * sizeof(int)); + if (dwtid[2] == 0) { + for (j = 0; j < (rw*rh); j++) { + aj = a + j; + for (k = 0; k < rd; k++) bj[k] = aj[k*wh]; + dwt_encode_97(bj, dn, sn, cas_axl); + dwt_deinterleave_z(bj, aj, dn, sn, wh, cas_axl); + } + } else if (dwtid[2] == 1) { + for (j = 0; j < (rw*rh); j++) { + aj = a + j; + for (k = 0; k < rd; k++) bj[k] = aj[k*wh]; + dwt_encode_53(bj, dn, sn, cas_axl); + dwt_deinterleave_z(bj, aj, dn, sn, wh, cas_axl); + } + } + opj_free(bj); + } + } + + //fprintf(stdout,"[INFO] Ops: %d \n",ops); +} + + +/* */ +/* Inverse 5-3 wavelet tranform in 3-D. */ +/* */ +void dwt_decode(opj_tcd_tilecomp_t * tilec, int stops[3], int dwtid[3]) { + int i, j, k; + int x, y, z; + int w, h, wh, d; + int level, levelx, levely, levelz, diff; + int *a = NULL; + int *aj = NULL; + int *bj = NULL; + int *cj = NULL; + + a = tilec->data; + + w = tilec->x1-tilec->x0; + h = tilec->y1-tilec->y0; + d = tilec->z1-tilec->z0; + wh = w * h; + levelx = tilec->numresolution[0]-1; + levely = tilec->numresolution[1]-1; + levelz = tilec->numresolution[2]-1; + level = int_max(levelx,int_max(levely,levelz)); + diff = tilec->numresolution[0] - tilec->numresolution[2]; + +/* General lifting framework -- DCCS-LIWT */ + for (x = level - 1, y = level - 1, z = level - 1; (x >= stops[0]) && (y >= stops[1]); x--, y--, z--) { + int rw; /* width of the resolution level computed */ + int rh; /* heigth of the resolution level computed */ + int rd; /* depth of the resolution level computed */ + int rw1; /* width of the resolution level once lower than computed one */ + int rh1; /* height of the resolution level once lower than computed one */ + int rd1; /* depth of the resolution level once lower than computed one */ + int cas_col; /* 0 = non inversion on horizontal filtering 1 = inversion between low-pass and high-pass filtering */ + int cas_row; /* 0 = non inversion on vertical filtering 1 = inversion between low-pass and high-pass filtering */ + int cas_axl; /* 0 = non inversion on axial filtering 1 = inversion between low-pass and high-pass filtering */ + int dn, sn; + + rw = tilec->resolutions[level - x].x1 - tilec->resolutions[level - x].x0; + rh = tilec->resolutions[level - y].y1 - tilec->resolutions[level - y].y0; + rd = tilec->resolutions[level - z].z1 - tilec->resolutions[level - z].z0; + rw1= tilec->resolutions[level - x - 1].x1 - tilec->resolutions[level - x - 1].x0; + rh1= tilec->resolutions[level - y - 1].y1 - tilec->resolutions[level - y - 1].y0; + rd1= tilec->resolutions[level - z - 1].z1 - tilec->resolutions[level - z - 1].z0; + + cas_col = tilec->resolutions[level - x].x0 % 2; /* 0 = non inversion on horizontal filtering 1 = inversion between low-pass and high-pass filtering */ + cas_row = tilec->resolutions[level - y].y0 % 2; /* 0 = non inversion on vertical filtering 1 = inversion between low-pass and high-pass filtering */ + cas_axl = tilec->resolutions[level - z].z0 % 2; + + /*fprintf(stdout," x %d y %d z %d \n",x,y,z); + fprintf(stdout," levelx %d levely %d levelz %d \n",levelx,levely,levelz); + fprintf(stdout," dwtid[0] %d [1] %d [2] %d \n",dwtid[0],dwtid[1],dwtid[2]); + fprintf(stdout," rw %d rh %d rd %d \n rw1 %d rh1 %d rd1 %d \n",rw,rh,rd,rw1,rh1,rd1); + fprintf(stdout,"IDWT Transform %d %d %d %d\n",level, z, rd,rd1);*/ + + if (z >= stops[2] && rd != rd1) { + //fprintf(stdout,"Axial Transform %d %d %d %d\n",levelz, z, rd,rd1); + sn = rd1; + dn = rd - rd1; + bj = (int*)opj_malloc(rd * sizeof(int)); + if (dwtid[2] == 0) { + for (j = 0; j < (rw*rh); j++) { + aj = a + j; + dwt_interleave_z(aj, bj, dn, sn, wh, cas_axl); + dwt_decode_97(bj, dn, sn, cas_axl); + for (k = 0; k < rd; k++) aj[k * wh] = bj[k]; + } + } else if (dwtid[2] == 1) { + for (j = 0; j < (rw*rh); j++) { + aj = a + j; + dwt_interleave_z(aj, bj, dn, sn, wh, cas_axl); + dwt_decode_53(bj, dn, sn, cas_axl); + for (k = 0; k < rd; k++) aj[k * wh] = bj[k]; + } + } + opj_free(bj); + } + + for (i = 0; i < rd; i++) { + //Fetch corresponding slice for doing DWT-2D + cj = tilec->data + (i * wh); + + //Vertical + sn = rh1; + dn = rh - rh1; + bj = (int*)opj_malloc(rh * sizeof(int)); + if (dwtid[1] == 0) { + for (j = 0; j < rw; j++) { + aj = cj + j; + dwt_interleave_v(aj, bj, dn, sn, w, cas_col); + dwt_decode_97(bj, dn, sn, cas_col); + for (k = 0; k < rh; k++) aj[k * w] = bj[k]; + } + } else if (dwtid[1] == 1) { + for (j = 0; j < rw; j++) { + aj = cj + j; + dwt_interleave_v(aj, bj, dn, sn, w, cas_col); + dwt_decode_53(bj, dn, sn, cas_col); + for (k = 0; k < rh; k++) aj[k * w] = bj[k]; + } + } + opj_free(bj); + + //Horizontal + sn = rw1; + dn = rw - rw1; + bj = (int*)opj_malloc(rw * sizeof(int)); + if (dwtid[0]==0) { + for (j = 0; j < rh; j++) { + aj = cj + j*w; + dwt_interleave_h(aj, bj, dn, sn, cas_row); + dwt_decode_97(bj, dn, sn, cas_row); + for (k = 0; k < rw; k++) aj[k] = bj[k]; + } + } else if (dwtid[0]==1) { + for (j = 0; j < rh; j++) { + aj = cj + j*w; + dwt_interleave_h(aj, bj, dn, sn, cas_row); + dwt_decode_53(bj, dn, sn, cas_row); + for (k = 0; k < rw; k++) aj[k] = bj[k]; + } + } + opj_free(bj); + + } + + } + +} + + +/* */ +/* Get gain of wavelet transform. */ +/* */ +int dwt_getgain(int orient, int reversible) { + if (reversible == 1) { + if (orient == 0) + return 0; + else if (orient == 1 || orient == 2 || orient == 4 ) + return 1; + else if (orient == 3 || orient == 5 || orient == 6 ) + return 2; + else + return 3; + } + //else if (reversible == 0){ + return 0; +} + +/* */ +/* Get norm of wavelet transform. */ +/* */ +double dwt_getnorm(int orient, int level[3], int dwtid[3]) { + int levelx = level[0]; + int levely = level[1]; + int levelz = (level[2] < 0) ? 0 : level[2]; + double norm; + + if (flagnorm[levelx][levely][levelz][orient] == 1) { + norm = dwt_norm[levelx][levely][levelz][orient]; + //fprintf(stdout,"[INFO] Level: %d %d %d Orient %d Dwt_norm: %f \n",level[0],level[1],level[2],orient,norm); + } else { + opj_wtfilt_t *wtfiltx =(opj_wtfilt_t *) opj_malloc(sizeof(opj_wtfilt_t)); + opj_wtfilt_t *wtfilty =(opj_wtfilt_t *) opj_malloc(sizeof(opj_wtfilt_t)); + opj_wtfilt_t *wtfiltz =(opj_wtfilt_t *) opj_malloc(sizeof(opj_wtfilt_t)); + //Fetch equivalent filters for each dimension + dwt_getwtfilters(wtfiltx, dwtid[0]); + dwt_getwtfilters(wtfilty, dwtid[1]); + dwt_getwtfilters(wtfiltz, dwtid[2]); + //Calculate the corresponding norm + norm = dwt_calc_wtnorms(orient, level, dwtid, wtfiltx, wtfilty, wtfiltz); + //Save norm in array (no recalculation) + dwt_norm[levelx][levely][levelz][orient] = norm; + flagnorm[levelx][levely][levelz][orient] = 1; + //Free reserved space + opj_free(wtfiltx->LPS); opj_free(wtfilty->LPS); opj_free(wtfiltz->LPS); + opj_free(wtfiltx->HPS); opj_free(wtfilty->HPS); opj_free(wtfiltz->HPS); + opj_free(wtfiltx); opj_free(wtfilty); opj_free(wtfiltz); + //fprintf(stdout,"[INFO] Dwtid: %d %d %d Level: %d %d %d Orient %d Norm: %f \n",dwtid[0],dwtid[1],dwtid[2],level[0],level[1],level[2],orient,norm); + } + return norm; +} +/* */ +/* Calculate explicit stepsizes for DWT. */ +/* */ +void dwt_calc_explicit_stepsizes(opj_tccp_t * tccp, int prec) { + int totnumbands, bandno, diff; + + assert(tccp->numresolution[0] >= tccp->numresolution[2]); + diff = tccp->numresolution[0] - tccp->numresolution[2]; /*if RESx=RESy != RESz */ + totnumbands = (7 * tccp->numresolution[0] - 6) - 4 * diff; /* 3-D */ + + for (bandno = 0; bandno < totnumbands; bandno++) { + double stepsize; + int resno, level[3], orient, gain; + + /* Bandno: 0 - LLL 1 - LHL + 2 - HLL 3 - HHL + 4 - LLH 5 - LHH + 6 - HLH 7 - HHH */ + + resno = (bandno == 0) ? 0 : ( (bandno <= 3 * diff) ? ((bandno - 1) / 3 + 1) : ((bandno + 4*diff - 1) / 7 + 1)); + orient = (bandno == 0) ? 0 : ( (bandno <= 3 * diff) ? ((bandno - 1) % 3 + 1) : ((bandno + 4*diff - 1) % 7 + 1)); + level[0] = tccp->numresolution[0] - 1 - resno; + level[1] = tccp->numresolution[1] - 1 - resno; + level[2] = tccp->numresolution[2] - 1 - resno; + + /* Gain: 0 - LLL 1 - LHL + 1 - HLL 2 - HHL + 1 - LLH 2 - LHH + 2 - HLH 3 - HHH */ + gain = (tccp->reversible == 0) ? 0 : ( (orient == 0) ? 0 : + ( ((orient == 1) || (orient == 2) || (orient == 4)) ? 1 : + (((orient == 3) || (orient == 5) || (orient == 6)) ? 2 : 3)) ); + + if (tccp->qntsty == J3D_CCP_QNTSTY_NOQNT) { + stepsize = 1.0; + } else { + double norm = dwt_getnorm(orient,level,tccp->dwtid); //Fetch norms if irreversible transform (by the moment only I9.7) + stepsize = (1 << (gain + 1)) / norm; + } + //fprintf(stdout,"[INFO] Bandno: %d Orient: %d Level: %d %d %d Stepsize: %f\n",bandno,orient,level[0],level[1],level[2],stepsize); + dwt_encode_stepsize((int) floor(stepsize * 8192.0), prec + gain, &tccp->stepsizes[bandno]); + } +} + + + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/dwt.h b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/dwt.h new file mode 100644 index 0000000..bd883c3 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/dwt.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * Copyrigth (c) 2006, Mónica Díez, LPI-UVA, Spain + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __DWT_H +#define __DWT_H +/** +@file dwt.h +@brief Implementation of a discrete wavelet transform (DWT) + +The functions in DWT.C have for goal to realize forward and inverse discret wavelet +transform with filter 5-3 (reversible) and filter 9-7 (irreversible). The functions in +DWT.C are used by some function in TCD.C. +*/ + +/** @defgroup DWT DWT - Implementation of a discrete wavelet transform */ +/*@{*/ + +/** +DCCS-LIWT properties +*/ + + +typedef struct opj_wtfilt { + double *LPS; + int lenLPS; + double *HPS; + int lenHPS; +} opj_wtfilt_t; +/** @name Funciones generales */ +/*@{*/ +/* ----------------------------------------------------------------------- */ +/** +Forward 5-3 wavelet tranform in 3-D. +Apply a reversible DWT transform to a component of an volume. +@param tilec Tile component information (current tile) +@param dwtid Number of identification of wavelet kernel(s) used in DWT in each direction +*/ +void dwt_encode(opj_tcd_tilecomp_t * tilec, int dwtid[3]); +/** +Inverse 5-3 wavelet tranform in 3-D. +Apply a reversible inverse DWT transform to a component of an volume. +@param tilec Tile component information (current tile) +@param stops Number of decoded resolution levels in each dimension +@param dwtid Number of identification of wavelet kernel(s) used in DWT in each dimension +*/ +void dwt_decode(opj_tcd_tilecomp_t * tilec, int stops[3], int dwtid[3]); +/* ----------------------------------------------------------------------- */ +/** +Get the gain of a subband for the reversible 3-D DWT. +@param orient Number that identifies the subband (0->LLL, 1->HLL, 2->LHL, 3->HHL, 4->LLH, 5->HLH, 6->LHH, 7->HHH) +@param reversible Wavelet transformation type +@return Returns 0 if orient = 0, returns 1 if orient = 1,2 or 4, returns 2 if orient = 3,5 or 6, returns 3 otherwise +*/ +int dwt_getgain(int orient, int reversible); +/** +Get the norm of a wavelet function of a subband at a specified level for the reversible 5-3 DWT or irreversible 9-7 in 3-D. +@param orient Band of the wavelet function +@param level Levels of the wavelet function in X,Y,Z axis +@param dwtid Wavelet transformation identifier +@return Returns the norm of the wavelet function +*/ +double dwt_getnorm(int orient, int level[3], int dwtid[3]); +/* ----------------------------------------------------------------------- */ +/** +Calcula el valor del escalón de cuantificación correspondiente a cada subbanda. +@param tccp Tile component coding parameters +@param prec Precision of data +*/ +void dwt_calc_explicit_stepsizes(opj_tccp_t * tccp, int prec); +/*@}*/ + +#endif /* __DWT_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/event.c b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/event.c new file mode 100644 index 0000000..c73eb5f --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/event.c @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "opj_includes.h" + +// ========================================================== +// Utility functions +// ========================================================== + +#ifndef _WIN32 +static char* +i2a(unsigned i, char *a, unsigned r) { + if (i/r > 0) a = i2a(i/r,a,r); + *a = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[i%r]; + return a+1; +} + +/** + Transforms integer i into an ascii string and stores the result in a; + string is encoded in the base indicated by r. + @param i Number to be converted + @param a String result + @param r Base of value; must be in the range 2 - 36 + @return Returns a +*/ +static char * +_itoa(int i, char *a, int r) { + r = ((r < 2) || (r > 36)) ? 10 : r; + if(i < 0) { + *a = '-'; + *i2a(-i, a+1, r) = 0; + } + else *i2a(i, a, r) = 0; + return a; +} + +#endif // !_WIN32 + +/* ----------------------------------------------------------------------- */ + +opj_event_mgr_t* OPJ_CALLCONV opj_set_event_mgr(opj_common_ptr cinfo, opj_event_mgr_t *event_mgr, void *context) { + if(cinfo) { + opj_event_mgr_t *previous = cinfo->event_mgr; + cinfo->event_mgr = event_mgr; + cinfo->client_data = context; + return previous; + } + + return NULL; +} + +bool opj_event_msg(opj_common_ptr cinfo, int event_type, const char *fmt, ...) { +#define MSG_SIZE 512 /* 512 bytes should be more than enough for a short message */ + opj_msg_callback msg_handler = NULL; + + opj_event_mgr_t *event_mgr = cinfo->event_mgr; + if(event_mgr != NULL) { + switch(event_type) { + case EVT_ERROR: + msg_handler = event_mgr->error_handler; + break; + case EVT_WARNING: + msg_handler = event_mgr->warning_handler; + break; + case EVT_INFO: + msg_handler = event_mgr->info_handler; + break; + default: + break; + } + if(msg_handler == NULL) { + return false; + } + } else { + return false; + } + + if ((fmt != NULL) && (event_mgr != NULL)) { + va_list arg; + int str_length, i, j; + char message[MSG_SIZE]; + memset(message, 0, MSG_SIZE); + /* initialize the optional parameter list */ + va_start(arg, fmt); + /* check the length of the format string */ + str_length = (strlen(fmt) > MSG_SIZE) ? MSG_SIZE : strlen(fmt); + /* parse the format string and put the result in 'message' */ + for (i = 0, j = 0; i < str_length; ++i) { + if (fmt[i] == '%') { + if (i + 1 < str_length) { + switch(tolower(fmt[i + 1])) { + case '%' : + message[j++] = '%'; + break; + case 'o' : /* octal numbers */ + { + char tmp[16]; + _itoa(va_arg(arg, int), tmp, 8); + strcat(message, tmp); + j += strlen(tmp); + ++i; + break; + } + case 'i' : /* decimal numbers */ + case 'd' : + { + char tmp[16]; + _itoa(va_arg(arg, int), tmp, 10); + strcat(message, tmp); + j += strlen(tmp); + ++i; + break; + } + case 'x' : /* hexadecimal numbers */ + { + char tmp[16]; + _itoa(va_arg(arg, int), tmp, 16); + strcat(message, tmp); + j += strlen(tmp); + ++i; + break; + } + case 's' : /* strings */ + { + char *tmp = va_arg(arg, char*); + strcat(message, tmp); + j += strlen(tmp); + ++i; + break; + } + case 'f' : /* floats */ + { + char tmp[16]; + double value = va_arg(arg, double); + sprintf(tmp, "%f", value); + strcat(message, tmp); + j += strlen(tmp); + ++i; + break; + } + }; + } else { + message[j++] = fmt[i]; + } + } else { + message[j++] = fmt[i]; + }; + } + /* deinitialize the optional parameter list */ + va_end(arg); + + /* output the message to the user program */ + msg_handler(message, cinfo->client_data); + } + + return true; +} + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/event.h b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/event.h new file mode 100644 index 0000000..a7a43d6 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/event.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __EVENT_H +#define __EVENT_H +/** +@file event.h +@brief Implementation of a event callback system + +The functions in EVENT.C have for goal to send output messages (errors, warnings, debug) to the user. +*/ + +#define EVT_ERROR 1 /**< Error event type */ +#define EVT_WARNING 2 /**< Warning event type */ +#define EVT_INFO 4 /**< Debug event type */ + +/** @defgroup EVENT EVENT - Implementation of a event callback system */ +/*@{*/ + +/** @name Funciones generales (see also openjpeg3d.h) */ +/*@{*/ +/* ----------------------------------------------------------------------- */ +/** +Write formatted data to a string and send the string to a user callback. +@param cinfo Codec context info +@param event_type Event type or callback to use to send the message +@param fmt Format-control string (plus optionnal arguments) +@return Returns true if successful, returns false otherwise +*/ +bool opj_event_msg(opj_common_ptr cinfo, int event_type, const char *fmt, ...); +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __EVENT_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/fix.h b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/fix.h new file mode 100644 index 0000000..f2113b5 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/fix.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __FIX_H +#define __FIX_H + +#if defined(_MSC_VER) || defined(__BORLANDC__) +#define int64 __int64 +#else +#define int64 long long +#endif + +/** +@file fix.h +@brief Implementation of operations of specific multiplication (FIX) + +The functions in FIX.H have for goal to realize specific multiplication. +*/ + +/** @defgroup FIX FIX - Implementation of operations of specific multiplication */ +/*@{*/ + +/** +Multiply two fixed-precision rational numbers. +@param a +@param b +@return Returns a * b +*/ +static int fix_mul(int a, int b) { + int64 temp = (int64) a * (int64) b >> 12; + return (int) ((temp >> 1) + (temp & 1)) ; +} + +/*@}*/ + +#endif /* __FIX_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/int.h b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/int.h new file mode 100644 index 0000000..38932d9 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/int.h @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __INT_H +#define __INT_H +/** +@file int.h +@brief Implementation of operations on integers (INT) + +The functions in INT.H have for goal to realize operations on integers. +*/ + +/** @defgroup INT INT - Implementation of operations on integers */ +/*@{*/ + +/** @name Funciones generales (see also openjpeg3d.h) */ +/*@{*/ +/* ----------------------------------------------------------------------- */ +/** +Get the minimum of two integers +@return Returns a if a < b else b +*/ +static int int_min(int a, int b) { + return a < b ? a : b; +} +/** +Get the maximum of two integers +@return Returns a if a > b else b +*/ +static int int_max(int a, int b) { + return (a > b) ? a : b; +} +/** +Clamp an integer inside an interval +@return +
    +
  • Returns a if (min < a < max) +
  • Returns max if (a > max) +
  • Returns min if (a < min) +
+*/ +static int int_clamp(int a, int min, int max) { + if (a < min) + return min; + if (a > max) + return max; + return a; +} +/** +@return Get absolute value of integer +*/ +static int int_abs(int a) { + return a < 0 ? -a : a; +} + +static double dbl_abs(double a) { + return a < 0 ? -a : a; +} +/** +Divide an integer and round upwards +@return Returns a divided by b +*/ +static int int_ceildiv(int a, int b) { + return (a + b - 1) / b; +} +/** +Divide an integer by a power of 2 and round upwards +@return Returns a divided by 2^b +*/ +static int int_ceildivpow2(int a, int b) { + return (a + (1 << b) - 1) >> b; +} +/** +Divide an integer by a power of 2 and round downwards +@return Returns a divided by 2^b +*/ +static int int_floordivpow2(int a, int b) { + return a >> b; +} +/** +Get logarithm of an integer and round downwards +@return Returns log2(a) +*/ +static int int_floorlog2(int a) { + int l; + for (l = 0; a > 1; l++) { + a >>= 1; + } + return l; +} +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/jp3d.c b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/jp3d.c new file mode 100644 index 0000000..c101830 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/jp3d.c @@ -0,0 +1,2328 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * Copyright (c) 2006, Mónica Díez García, Image Processing Laboratory, University of Valladolid, Spain + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "opj_includes.h" + +/** @defgroup J3D J3D - JPEG-2000 PART 10 codestream reader/writer */ +/*@{*/ + +/** @name Funciones locales */ +/*@{*/ + +/** +Write the SOC marker (Start Of Codestream) +@param j3d J3D handle +*/ +static void j3d_write_soc(opj_j3d_t *j3d); +/** +Read the SOC marker (Start of Codestream) +@param j3d J3D handle +*/ +static void j3d_read_soc(opj_j3d_t *j3d); +/** +Write the SIZ marker (2D volume and tile size) +@param j3d J3D handle +*/ +static void j3d_write_siz(opj_j3d_t *j3d); +/** +Read the SIZ marker (2D volume and tile size) +@param j3d J3D handle +*/ +static void j3d_read_siz(opj_j3d_t *j3d); +/** +Write the ZSI marker (3rd volume and tile size) +@param j3d J3D handle +*/ +static void j3d_write_zsi(opj_j3d_t *j3d); +/** +Read the ZSI marker (3rd volume and tile size) +@param j3d J3D handle +*/ +static void j3d_read_zsi(opj_j3d_t *j3d); +/** +Write the COM marker (comment) +@param j3d J3D handle +*/ +static void j3d_write_com(opj_j3d_t *j3d); +/** +Read the COM marker (comment) +@param j3d J3D handle +*/ +static void j3d_read_com(opj_j3d_t *j3d); +/** +Write the value concerning the specified component in the marker COD and COC +@param j3d J3D handle +@param compno Number of the component concerned by the information written +*/ +static void j3d_write_cox(opj_j3d_t *j3d, int compno); +/** +Read the value concerning the specified component in the marker COD and COC +@param j3d J3D handle +@param compno Number of the component concerned by the information read +*/ +static void j3d_read_cox(opj_j3d_t *j3d, int compno); +/** +Write the COD marker (coding style default) +@param j3d J3D handle +*/ +static void j3d_write_cod(opj_j3d_t *j3d); +/** +Read the COD marker (coding style default) +@param j3d J3D handle +*/ +static void j3d_read_cod(opj_j3d_t *j3d); +/** +Write the COC marker (coding style component) +@param j3d J3D handle +@param compno Number of the component concerned by the information written +*/ +static void j3d_write_coc(opj_j3d_t *j3d, int compno); +/** +Read the COC marker (coding style component) +@param j3d J3D handle +*/ +static void j3d_read_coc(opj_j3d_t *j3d); +/** +Write the value concerning the specified component in the marker QCD and QCC +@param j3d J3D handle +@param compno Number of the component concerned by the information written +*/ +static void j3d_write_qcx(opj_j3d_t *j3d, int compno); +/** +Read the value concerning the specified component in the marker QCD and QCC +@param j3d J3D handle +@param compno Number of the component concern by the information read +@param len Length of the information in the QCX part of the marker QCD/QCC +*/ +static void j3d_read_qcx(opj_j3d_t *j3d, int compno, int len); +/** +Write the QCD marker (quantization default) +@param j3d J3D handle +*/ +static void j3d_write_qcd(opj_j3d_t *j3d); +/** +Read the QCD marker (quantization default) +@param j3d J3D handle +*/ +static void j3d_read_qcd(opj_j3d_t *j3d); +/** +Write the QCC marker (quantization component) +@param j3d J3D handle +@param compno Number of the component concerned by the information written +*/ +static void j3d_write_qcc(opj_j3d_t *j3d, int compno); +/** +Read the QCC marker (quantization component) +@param j3d J3D handle +*/ +static void j3d_read_qcc(opj_j3d_t *j3d); +/** +Write the POC marker (progression order change) +@param j3d J3D handle +*/ +static void j3d_write_poc(opj_j3d_t *j3d); +/** +Read the POC marker (progression order change) +@param j3d J3D handle +*/ +static void j3d_read_poc(opj_j3d_t *j3d); +/** +Read the CRG marker (component registration) +@param j3d J3D handle +*/ +static void j3d_read_crg(opj_j3d_t *j3d); +/** +Read the TLM marker (tile-part lengths) +@param j3d J3D handle +*/ +static void j3d_read_tlm(opj_j3d_t *j3d); +/** +Read the PLM marker (packet length, main header) +@param j3d J3D handle +*/ +static void j3d_read_plm(opj_j3d_t *j3d); +/** +Read the PLT marker (packet length, tile-part header) +@param j3d J3D handle +*/ +static void j3d_read_plt(opj_j3d_t *j3d); +/** +Read the PPM marker (packet packet headers, main header) +@param j3d J3D handle +*/ +static void j3d_read_ppm(opj_j3d_t *j3d); +/** +Read the PPT marker (packet packet headers, tile-part header) +@param j3d J3D handle +*/ +static void j3d_read_ppt(opj_j3d_t *j3d); +/** +Write the SOT marker (start of tile-part) +@param j3d J3D handle +*/ +static void j3d_write_sot(opj_j3d_t *j3d); +/** +Read the SOT marker (start of tile-part) +@param j3d J3D handle +*/ +static void j3d_read_sot(opj_j3d_t *j3d); +/** +Write the SOD marker (start of data) +@param j3d J3D handle +@param tile_coder Pointer to a TCD handle +*/ +static void j3d_write_sod(opj_j3d_t *j3d, void *tile_coder); +/** +Read the SOD marker (start of data) +@param j3d J3D handle +*/ +static void j3d_read_sod(opj_j3d_t *j3d); +/** +Write the RGN marker (region-of-interest) +@param j3d J3D handle +@param compno Number of the component concerned by the information written +@param tileno Number of the tile concerned by the information written +*/ +static void j3d_write_rgn(opj_j3d_t *j3d, int compno, int tileno); +/** +Read the RGN marker (region-of-interest) +@param j3d J3D handle +*/ +static void j3d_read_rgn(opj_j3d_t *j3d); +/** +Write the EOC marker (end of codestream) +@param j3d J3D handle +*/ +static void j3d_write_eoc(opj_j3d_t *j3d); +/** +Read the EOC marker (end of codestream) +@param j3d J3D handle +*/ +static void j3d_read_eoc(opj_j3d_t *j3d); +/** +Read an unknown marker +@param j3d J3D handle +*/ +static void j3d_read_unk(opj_j3d_t *j3d); +/** +Write the CAP marker (extended capabilities) +@param j3d J3D handle +*/ +static void j3d_write_cap(opj_j3d_t *j3d); +/** +Read the CAP marker (extended capabilities) +@param j3d J3D handle +*/ +static void j3d_read_cap(opj_j3d_t *j3d); +/** +Write the DCO marker (Variable DC offset) +@param j3d J3D handle +*/ +static void j3d_write_dco(opj_j3d_t *j3d); +/** +Read the DCO marker (Variable DC offset) +@param j3d J3D handle +*/ +static void j3d_read_dco(opj_j3d_t *j3d); +/** +Write the ATK marker (arbitrary transformation kernel) +@param j3d J3D handle +*/ +static void j3d_write_atk(opj_j3d_t *j3d); +/** +Read the ATK marker (arbitrary transformation kernel) +@param j3d J3D handle +*/ +static void j3d_read_atk(opj_j3d_t *j3d); +/** +Write the CBD marker (component bit depth definition) +@param j3d J3D handle +*/ +static void j3d_write_cbd(opj_j3d_t *j3d); +/** +Read the CBD marker (component bit depth definition) +@param j3d J3D handle +*/ +static void j3d_read_cbd(opj_j3d_t *j3d); +/** +Write the MCT marker (multiple component transfomation definition) +@param j3d J3D handle +*/ +static void j3d_write_mct(opj_j3d_t *j3d); +/** +Read the MCT marker (multiple component transfomation definition) +@param j3d J3D handle +*/ +static void j3d_read_mct(opj_j3d_t *j3d); +/** +Write the MCC marker (multiple component transfomation collection) +@param j3d J3D handle +*/ +static void j3d_write_mcc(opj_j3d_t *j3d); +/** +Read the MCC marker (multiple component transfomation collection) +@param j3d J3D handle +*/ +static void j3d_read_mcc(opj_j3d_t *j3d); +/** +Write the MCO marker (multiple component transfomation ordering) +@param j3d J3D handle +*/ +static void j3d_write_mco(opj_j3d_t *j3d); +/** +Read the MCO marker (multiple component transfomation ordering) +@param j3d J3D handle +*/ +static void j3d_read_mco(opj_j3d_t *j3d); +/** +Write the NLT marker (non-linearity point transformation) +@param j3d J3D handle +*/ +static void j3d_write_nlt(opj_j3d_t *j3d); +/** +Read the NLT marker (non-linearity point transformation) +@param j3d J3D handle +*/ +static void j3d_read_nlt(opj_j3d_t *j3d); +/*@}*/ + +/* ----------------------------------------------------------------------- */ + +void j3d_dump_volume(FILE *fd, opj_volume_t * vol) { + int compno; + fprintf(fd, "volume {\n"); + fprintf(fd, " x0=%d, y0=%d, z0=%d, x1=%d, y1=%d, z1=%d\n", vol->x0, vol->y0, vol->z0,vol->x1, vol->y1, vol->z1); + fprintf(fd, " numcomps=%d\n", vol->numcomps); + for (compno = 0; compno < vol->numcomps; compno++) { + opj_volume_comp_t *comp = &vol->comps[compno]; + fprintf(fd, " comp %d {\n", compno); + fprintf(fd, " dx=%d, dy=%d, dz=%d\n", comp->dx, comp->dy, comp->dz); + fprintf(fd, " prec=%d\n", comp->prec); + fprintf(fd, " sgnd=%d\n", comp->sgnd); + fprintf(fd, " }\n"); + } + fprintf(fd, "}\n"); +} + +void j3d_dump_cp(FILE *fd, opj_volume_t * vol, opj_cp_t * cp) { + int tileno, compno, layno, bandno, resno, numbands; + fprintf(fd, "coding parameters {\n"); + fprintf(fd, " tx0=%d, ty0=%d, tz0=%d\n", cp->tx0, cp->ty0, cp->tz0); + fprintf(fd, " tdx=%d, tdy=%d, tdz=%d\n", cp->tdx, cp->tdy, cp->tdz); + fprintf(fd, " tw=%d, th=%d, tl=%d\n", cp->tw, cp->th, cp->tl); + fprintf(fd, " transform format: %d\n", cp->transform_format); + fprintf(fd, " encoding format: %d\n", cp->encoding_format); + for (tileno = 0; tileno < cp->tw * cp->th * cp->tl; tileno++) { + opj_tcp_t *tcp = &cp->tcps[tileno]; + fprintf(fd, " tile %d {\n", tileno); + fprintf(fd, " csty=%x\n", tcp->csty); + fprintf(fd, " prg=%d\n", tcp->prg); + fprintf(fd, " numlayers=%d\n", tcp->numlayers); + fprintf(fd, " mct=%d\n", tcp->mct); + fprintf(fd, " rates="); + for (layno = 0; layno < tcp->numlayers; layno++) { + fprintf(fd, "%f ", tcp->rates[layno]); + } + fprintf(fd, "\n"); + fprintf(fd, " first=%d\n", tcp->first); + for (compno = 0; compno < vol->numcomps; compno++) { + opj_tccp_t *tccp = &tcp->tccps[compno]; + fprintf(fd, " comp %d {\n", compno); + fprintf(fd, " csty=%x\n", tccp->csty); + fprintf(fd, " numresx=%d, numresy=%d, numresz=%d\n", tccp->numresolution[0], tccp->numresolution[1], tccp->numresolution[2]); + fprintf(fd, " cblkw=%d, cblkh=%d, cblkl=%d\n", tccp->cblk[0], tccp->cblk[1], tccp->cblk[2]); + fprintf(fd, " cblksty=%x\n", tccp->cblksty); + fprintf(fd, " qntsty=%d\n", tccp->qntsty); + fprintf(fd, " numgbits=%d\n", tccp->numgbits); + fprintf(fd, " roishift=%d\n", tccp->roishift); + fprintf(fd, " reversible=%d\n", tccp->reversible); + fprintf(fd, " dwtidx=%d dwtidy=%d dwtidz=%d\n", tccp->dwtid[0], tccp->dwtid[1], tccp->dwtid[2]); + if (tccp->atk != NULL) { + fprintf(fd, " atk.index=%d\n", tccp->atk->index); + fprintf(fd, " atk.coeff_typ=%d\n", tccp->atk->coeff_typ); + fprintf(fd, " atk.filt_cat=%d\n", tccp->atk->filt_cat); + fprintf(fd, " atk.exten=%d\n", tccp->atk->exten); + fprintf(fd, " atk.minit=%d\n", tccp->atk->minit); + fprintf(fd, " atk.wt_typ=%d\n", tccp->atk->wt_typ); + } + fprintf(fd, " stepsizes of bands="); + numbands = (tccp->qntsty == J3D_CCP_QNTSTY_SIQNT) ? 1 : + ( (cp->transform_format == TRF_2D_DWT) ? (tccp->numresolution[0] * 3 - 2) : + (tccp->numresolution[0] * 7 - 6) - 4 *(tccp->numresolution[0] - tccp->numresolution[2]) ); + for (bandno = 0; bandno < numbands; bandno++) { + fprintf(fd, "(%d,%d) ", tccp->stepsizes[bandno].mant,tccp->stepsizes[bandno].expn); + } + fprintf(fd, "\n"); + + if (tccp->csty & J3D_CCP_CSTY_PRT) { + fprintf(fd, " prcw="); + for (resno = 0; resno < tccp->numresolution[0]; resno++) { + fprintf(fd, "%d ", tccp->prctsiz[0][resno]); + } + fprintf(fd, "\n"); + fprintf(fd, " prch="); + for (resno = 0; resno < tccp->numresolution[0]; resno++) { + fprintf(fd, "%d ", tccp->prctsiz[1][resno]); + } + fprintf(fd, "\n"); + fprintf(fd, " prcl="); + for (resno = 0; resno < tccp->numresolution[0]; resno++) { + fprintf(fd, "%d ", tccp->prctsiz[2][resno]); + } + fprintf(fd, "\n"); + } + fprintf(fd, " }\n"); + } + fprintf(fd, " }\n"); + } + fprintf(fd, "}\n"); +} + +/* ----------------------------------------------------------------------- +Extended capabilities +------------------------------------------------------------------------*/ + +static void j3d_write_cap(opj_j3d_t *j3d){ + int len,lenp; + + opj_cio_t *cio = j3d->cio; + cio_write(cio, J3D_MS_CAP, 2); /* CAP */ + lenp = cio_tell(cio); + cio_skip(cio, 2); + cio_write(cio,J3D_CAP_10, 4); + len = cio_tell(cio) - lenp; + cio_seek(cio, lenp); + cio_write(cio, len, 2); /* Lsiz */ + cio_seek(cio, lenp + len); + +} +static void j3d_read_cap(opj_j3d_t *j3d){ + int len, Cap; + opj_cio_t *cio = j3d->cio; + /*cio_read(cio, 2); CAP */ + len = cio_read(cio, 2); + Cap = cio_read(cio, 4); +} +static void j3d_write_zsi(opj_j3d_t *j3d) { + int i; + int lenp, len; + + opj_cio_t *cio = j3d->cio; + opj_volume_t *volume = j3d->volume; + opj_cp_t *cp = j3d->cp; + + cio_write(cio, J3D_MS_ZSI, 2); /* ZSI */ + lenp = cio_tell(cio); + cio_skip(cio, 2); + cio_write(cio, volume->z1, 4); /* Zsiz */ + cio_write(cio, volume->z0, 4); /* Z0siz */ + cio_write(cio, cp->tdz, 4); /* ZTsiz */ + cio_write(cio, cp->tz0, 4); /* ZT0siz */ + for (i = 0; i < volume->numcomps; i++) { + cio_write(cio, volume->comps[i].dz, 1); /* ZRsiz_i */ + } + len = cio_tell(cio) - lenp; + cio_seek(cio, lenp); + cio_write(cio, len, 2); /* Lsiz */ + cio_seek(cio, lenp + len); +} + +static void j3d_read_zsi(opj_j3d_t *j3d) { + int len, i; + + opj_cio_t *cio = j3d->cio; + opj_volume_t *volume = j3d->volume; + opj_cp_t *cp = j3d->cp; + + len = cio_read(cio, 2); /* Lsiz */ + volume->z1 = cio_read(cio, 4); /* Zsiz */ + volume->z0 = cio_read(cio, 4); /* Z0siz */ + cp->tdz = cio_read(cio, 4); /* ZTsiz */ + cp->tz0 = cio_read(cio, 4); /* ZT0siz */ + for (i = 0; i < volume->numcomps; i++) { + volume->comps[i].dz = cio_read(cio, 1); /* ZRsiz_i */ + } + + //Initialization of volume + cp->tw = int_ceildiv(volume->x1 - cp->tx0, cp->tdx); + cp->th = int_ceildiv(volume->y1 - cp->ty0, cp->tdy); + cp->tl = int_ceildiv(volume->z1 - cp->tz0, cp->tdz); + cp->tcps = (opj_tcp_t *) opj_malloc(cp->tw * cp->th * cp->tl * sizeof(opj_tcp_t)); + cp->tileno = (int *) opj_malloc(cp->tw * cp->th * cp->tl * sizeof(int)); + cp->tileno_size = 0; + + for (i = 0; i < cp->tw * cp->th * cp->tl ; i++) { + cp->tcps[i].POC = 0; + cp->tcps[i].numpocs = 0; + cp->tcps[i].first = 1; + } + + /* Initialization for PPM marker (Packets header)*/ + cp->ppm = 0; + cp->ppm_data = NULL; + cp->ppm_data_first = NULL; + cp->ppm_previous = 0; + cp->ppm_store = 0; + + j3d->default_tcp->tccps = (opj_tccp_t *) opj_malloc(sizeof(opj_tccp_t) * volume->numcomps); + for (i = 0; i < cp->tw * cp->th * cp->tl ; i++) { + cp->tcps[i].tccps = (opj_tccp_t *) opj_malloc(sizeof(opj_tccp_t) * volume->numcomps); + } + j3d->tile_data = (unsigned char **) opj_malloc(cp->tw * cp->th * cp->tl * sizeof(unsigned char *)); + j3d->tile_len = (int *) opj_malloc(cp->tw * cp->th * cp->tl * sizeof(int)); + j3d->state = J3D_STATE_MH; + +} +static void j3d_write_dco(opj_j3d_t *j3d){ + int lenp, len, i; + int dcotype; + + opj_cio_t *cio = j3d->cio; + opj_volume_t *volume = j3d->volume; + opj_cp_t *cp = j3d->cp; + + dcotype = 1; /* Offsets are 16bit signed integers Table A21 15444-2 */ + cio_write(cio, J3D_MS_DCO, 2); /* DCO */ + lenp = cio_tell(cio); + cio_skip(cio, 2); + cio_write(cio, dcotype, 1); + if (dcotype == 0) { + for (i = 0; i < volume->numcomps; i++) + cio_write(cio, volume->comps[i].dcoffset, 1); /* SPdco_i */ + } else if (dcotype == 1) { + for (i = 0; i < volume->numcomps; i++){ + cio_write(cio, volume->comps[i].dcoffset, 1); /* SPdco_i */ + opj_event_msg(j3d->cinfo, EVT_INFO, "dcotype %d DCO %d \n",dcotype,volume->comps[i].dcoffset); + } + } + len = cio_tell(cio) - lenp; + cio_seek(cio, lenp); + cio_write(cio, len, 2); /* Ldco */ + cio_seek(cio, lenp + len); + +} +static void j3d_read_dco(opj_j3d_t *j3d){ + int len, i; + int dcotype; + + opj_cio_t *cio = j3d->cio; + opj_volume_t *volume = j3d->volume; + opj_cp_t *cp = j3d->cp; + + len = cio_read(cio, 2); /* Lsiz */ + dcotype = cio_read(cio, 1); //offset 8bit unsigned / 16bit signed integers + if (dcotype == 0) { + for (i = 0; i < volume->numcomps; i++) { + volume->comps[i].dcoffset = cio_read(cio, 1); + if (volume->comps[i].dcoffset > 128) + volume->comps[i].dcoffset = volume->comps[i].dcoffset - 256; + } + } else if (dcotype == 1) { + for (i = 0; i < volume->numcomps; i++) { + volume->comps[i].dcoffset = cio_read(cio, 1); + if (volume->comps[i].dcoffset > 128) + volume->comps[i].dcoffset = volume->comps[i].dcoffset - 256; + } + } + +} +static void j3d_write_atk(opj_j3d_t *j3d){ + int lenp, len, s, k; + + opj_cio_t *cio = j3d->cio; + opj_volume_t *volume = j3d->volume; + opj_atk_t *atk = j3d->cp->tcps->tccps->atk; + + cio_write(cio, J3D_MS_ATK, 2); /* ATK */ + lenp = cio_tell(cio); + cio_skip(cio, 2); + cio_write(cio, atk->index + (atk->coeff_typ << 8) + (atk->filt_cat << 11) + + (atk->wt_typ << 12) + (atk->minit << 13) + (atk->exten << 14), 2); /* Satk */ + if (atk->wt_typ == J3D_ATK_IRR) + cio_write(cio,(unsigned int) (atk->Katk * 8192.0), 1 << atk->coeff_typ); + cio_write(cio, atk->Natk, 1); + for (s = 0; s < atk->Natk; s++){ + if (atk->filt_cat == J3D_ATK_ARB) + cio_write(cio, atk->Oatk[s], 1); + if (atk->wt_typ == J3D_ATK_REV){ + cio_write(cio, atk->Eatk[s], 1); + cio_write(cio, atk->Batk[s], 1); + } + cio_write(cio, atk->LCatk[s], 1); + for (k = 0; k < atk->LCatk[s]; k++) + cio_write(cio,(unsigned int) (atk->Aatk[s][k] * 8192.0), 1 << atk->coeff_typ); + } + len = cio_tell(cio) - lenp; + cio_seek(cio, lenp); + cio_write(cio, len, 2); /* Latk */ + cio_seek(cio, lenp + len); +} +static void j3d_read_atk(opj_j3d_t *j3d){ + int len, i, Satk, k; + + opj_cio_t *cio = j3d->cio; + opj_volume_t *volume = j3d->volume; + opj_cp_t *cp = j3d->cp; + opj_atk_t *atk = cp->tcps->tccps->atk; + + len = cio_read(cio, 2); /* Latk */ + Satk = cio_read(cio, 2); + atk->index = Satk & 0x00ff; + atk->coeff_typ = Satk >> 8 & 0x0007; + atk->filt_cat = Satk >> 11 & 0x0001; + atk->wt_typ = Satk >> 12 & 0x0001; + atk->minit = Satk >> 13 & 0x0001; + atk->exten = Satk >> 14 & 0x0001; + if (atk->wt_typ == J3D_ATK_IRR) + atk->Katk = ((double) cio_read(cio, 1 << atk->coeff_typ) / 8192.0); + atk->Natk = cio_read(cio, 1); + for (i = 0; i < atk->Natk; i++) { + if (atk->filt_cat == J3D_ATK_ARB) + atk->Oatk[i] = cio_read(cio, 1); + if (atk->wt_typ == J3D_ATK_REV){ + atk->Eatk[i] = cio_read(cio, 1); + atk->Batk[i] = cio_read(cio, 1); + } + atk->LCatk[i] = cio_read(cio, 1); + for (k = 0; k < atk->LCatk[i]; k++) + atk->Aatk[i][k] = ((double) cio_read(cio, 1 << atk->coeff_typ) / 8192.0); + } +} +static void j3d_write_cbd(opj_j3d_t *j3d){ +} +static void j3d_read_cbd(opj_j3d_t *j3d){ +} +static void j3d_write_mct(opj_j3d_t *j3d){ +} +static void j3d_read_mct(opj_j3d_t *j3d){ +} +static void j3d_write_mcc(opj_j3d_t *j3d){ +} +static void j3d_read_mcc(opj_j3d_t *j3d){ +} +static void j3d_write_mco(opj_j3d_t *j3d){ +} +static void j3d_read_mco(opj_j3d_t *j3d){ +} +static void j3d_write_nlt(opj_j3d_t *j3d){ +} +static void j3d_read_nlt(opj_j3d_t *j3d){ +} +/* ----------------------------------------------------------------------- +15444-1 codestream syntax +------------------------------------------------------------------------*/ +static void j3d_write_soc(opj_j3d_t *j3d) { + opj_cio_t *cio = j3d->cio; + cio_write(cio, J3D_MS_SOC, 2); +} + +static void j3d_read_soc(opj_j3d_t *j3d) { + j3d->state = J3D_STATE_MHSIZ; +} + +static void j3d_write_siz(opj_j3d_t *j3d) { + int i; + int lenp, len; + int Rsiz; + + opj_cio_t *cio = j3d->cio; + opj_volume_t *volume = j3d->volume; + opj_cp_t *cp = j3d->cp; + + cio_write(cio, J3D_MS_SIZ, 2); /* SIZ */ + lenp = cio_tell(cio); + cio_skip(cio, 2); + //cio_write(cio, 0, 2); /* Rsiz (capabilities of 15444-1 only) */ + Rsiz = J3D_RSIZ_DCO | J3D_RSIZ_ATK; /** | J3D_RSIZ_MCT | J3D_RSIZ_NONLT (not implemented yet)*/ + cio_write(cio, Rsiz, 2); /* capabilities of WDv5.2*/ + cio_write(cio, volume->x1, 4); /* Xsiz */ + cio_write(cio, volume->y1, 4); /* Ysiz */ + cio_write(cio, volume->x0, 4); /* X0siz */ + cio_write(cio, volume->y0, 4); /* Y0siz */ + cio_write(cio, cp->tdx, 4); /* XTsiz */ + cio_write(cio, cp->tdy, 4); /* YTsiz */ + cio_write(cio, cp->tx0, 4); /* XT0siz */ + cio_write(cio, cp->ty0, 4); /* YT0siz */ + cio_write(cio, volume->numcomps, 2); /* Csiz */ + for (i = 0; i < volume->numcomps; i++) { + cio_write(cio, volume->comps[i].prec - 1 + (volume->comps[i].sgnd << 7), 1); /* Ssiz_i */ + cio_write(cio, volume->comps[i].dx, 1); /* XRsiz_i */ + cio_write(cio, volume->comps[i].dy, 1); /* YRsiz_i */ + } + len = cio_tell(cio) - lenp; + cio_seek(cio, lenp); + cio_write(cio, len, 2); /* Lsiz */ + cio_seek(cio, lenp + len); +} + +static void j3d_read_siz(opj_j3d_t *j3d) { + int len, i; + + opj_cio_t *cio = j3d->cio; + opj_volume_t *volume = j3d->volume; + opj_cp_t *cp = j3d->cp; + + len = cio_read(cio, 2); /* Lsiz */ + cp->rsiz = cio_read(cio, 2); /* Rsiz (capabilities) */ + volume->x1 = cio_read(cio, 4); /* Xsiz */ + volume->y1 = cio_read(cio, 4); /* Ysiz */ + volume->x0 = cio_read(cio, 4); /* X0siz */ + volume->y0 = cio_read(cio, 4); /* Y0siz */ + cp->tdx = cio_read(cio, 4); /* XTsiz */ + cp->tdy = cio_read(cio, 4); /* YTsiz */ + cp->tx0 = cio_read(cio, 4); /* XT0siz */ + cp->ty0 = cio_read(cio, 4); /* YT0siz */ + + volume->numcomps = cio_read(cio, 2); /* Csiz */ + volume->comps = (opj_volume_comp_t *) opj_malloc(volume->numcomps * sizeof(opj_volume_comp_t)); + for (i = 0; i < volume->numcomps; i++) { + int tmp, j; + tmp = cio_read(cio, 1); /* Ssiz_i */ + volume->comps[i].prec = (tmp & 0x7f) + 1; + volume->comps[i].sgnd = tmp >> 7; + volume->comps[i].dx = cio_read(cio, 1); /* XRsiz_i */ + volume->comps[i].dy = cio_read(cio, 1); /* YRsiz_i */ + for (j = 0; j < 3; j++) { + volume->comps[i].resno_decoded[j] = 0; /* number of resolution decoded */ + volume->comps[i].factor[j] = 0; /* reducing factor per component */ + } + } + + if (j3d->cinfo->codec_format == CODEC_J2K){ + volume->z1 = 1; + volume->z0 = 0; + volume->numslices = 1; + cp->tdz = 1; + cp->tz0 = 0; + for (i = 0; i < volume->numcomps; i++) + volume->comps[i].dz = 1; + + //Initialization of volume + cp->tw = int_ceildiv(volume->x1 - cp->tx0, cp->tdx); + cp->th = int_ceildiv(volume->y1 - cp->ty0, cp->tdy); + cp->tl = int_ceildiv(volume->z1 - cp->tz0, cp->tdz); + cp->tcps = (opj_tcp_t *) opj_malloc(cp->tw * cp->th * cp->tl * sizeof(opj_tcp_t)); + cp->tileno = (int *) opj_malloc(cp->tw * cp->th * cp->tl * sizeof(int)); + cp->tileno_size = 0; + + for (i = 0; i < cp->tw * cp->th * cp->tl ; i++) { + cp->tcps[i].POC = 0; + cp->tcps[i].numpocs = 0; + cp->tcps[i].first = 1; + } + + /* Initialization for PPM marker (Packets header)*/ + cp->ppm = 0; + cp->ppm_data = NULL; + cp->ppm_data_first = NULL; + cp->ppm_previous = 0; + cp->ppm_store = 0; + + j3d->default_tcp->tccps = (opj_tccp_t *) opj_malloc(sizeof(opj_tccp_t) * volume->numcomps); + for (i = 0; i < cp->tw * cp->th * cp->tl ; i++) { + cp->tcps[i].tccps = (opj_tccp_t *) opj_malloc(sizeof(opj_tccp_t) * volume->numcomps); + } + j3d->tile_data = (unsigned char **) opj_malloc(cp->tw * cp->th * cp->tl * sizeof(unsigned char *)); + j3d->tile_len = (int *) opj_malloc(cp->tw * cp->th * cp->tl * sizeof(int)); + j3d->state = J3D_STATE_MH; + } +} + + + +static void j3d_write_com(opj_j3d_t *j3d) { + unsigned int i; + int lenp, len; + + opj_cio_t *cio = j3d->cio; + + cio_write(cio, J3D_MS_COM, 2); + lenp = cio_tell(cio); + cio_skip(cio, 2); + //cio_write(cio, 0, 2); + cio_write(cio, j3d->cp->transform_format,1); + cio_write(cio, j3d->cp->encoding_format,1); + //opj_event_msg(j3d->cinfo, EVT_INFO, "TRF %D ENCOD %d\n",j3d->cp->transform_format,j3d->cp->encoding_format); + if (j3d->cp->comment != NULL) { + char *comment = j3d->cp->comment; + for (i = 0; i < strlen(comment); i++) { + cio_write(cio, comment[i], 1); + } + } + len = cio_tell(cio) - lenp; + cio_seek(cio, lenp); + cio_write(cio, len, 2); + cio_seek(cio, lenp + len); +} + +static void j3d_read_com(opj_j3d_t *j3d) { + int len; + opj_cio_t *cio = j3d->cio; + + len = cio_read(cio, 2); + + j3d->cp->transform_format = (OPJ_TRANSFORM) cio_read(cio, 1); + j3d->cp->encoding_format = (OPJ_ENTROPY_CODING) cio_read(cio, 1); + //opj_event_msg(j3d->cinfo, EVT_INFO, "TRF %D ENCOD %d\n",j3d->cp->transform_format,j3d->cp->encoding_format); + + cio_skip(cio, len - 4); //posible comments +} + +static void j3d_write_cox(opj_j3d_t *j3d, int compno) { + int i; + + opj_cp_t *cp = j3d->cp; + opj_tcp_t *tcp = &cp->tcps[j3d->curtileno]; + opj_tccp_t *tccp = &tcp->tccps[compno]; + opj_cio_t *cio = j3d->cio; + + cio_write(cio, tccp->numresolution[0] - 1, 1); /* SPcox (D) No of decomposition levels in x-axis*/ + if (j3d->cinfo->codec_format == CODEC_J3D) { + cio_write(cio, tccp->numresolution[1] - 1, 1); /* SPcox (E) No of decomposition levels in y-axis*/ + cio_write(cio, tccp->numresolution[2] - 1, 1); /* SPcox (F) No of decomposition levels in z-axis*/ + } + /* (cblkw - 2) + (cblkh - 2) + (cblkl - 2) <= 18*/ + cio_write(cio, tccp->cblk[0] - 2, 1); /* SPcox (G) Cblk width entre 10 y 2 (8 y 0)*/ + cio_write(cio, tccp->cblk[1] - 2, 1); /* SPcox (H) Cblk height*/ + if (j3d->cinfo->codec_format == CODEC_J3D) { + cio_write(cio, tccp->cblk[2] - 2, 1); /* SPcox (I) Cblk depth*/ + } + cio_write(cio, tccp->cblksty, 1); /* SPcox (J) Cblk style*/ + cio_write(cio, tccp->dwtid[0], 1); /* SPcox (K) WT in x-axis 15444-2 Table A10*/ + if (j3d->cinfo->codec_format == CODEC_J3D) { + cio_write(cio, tccp->dwtid[1], 1); /* SPcox (L) WT in y-axis 15444-2 Table A10*/ + cio_write(cio, tccp->dwtid[2], 1); /* SPcox (M) WT in z-axis 15444-2 Table A10*/ + } + + if (tccp->csty & J3D_CCP_CSTY_PRT) { + for (i = 0; i < tccp->numresolution[0]; i++) { + if (i < tccp->numresolution[2]) + cio_write(cio, tccp->prctsiz[0][i] + (tccp->prctsiz[1][i] << 4) + (tccp->prctsiz[2][i] << 8), 2); /* SPcox (N_i) Table A9*/ + else + if (j3d->cinfo->codec_format == CODEC_J3D) + cio_write(cio, tccp->prctsiz[0][i] + (tccp->prctsiz[1][i] << 4), 2); /* SPcox (N_i) Table A9*/ + else + cio_write(cio, tccp->prctsiz[0][i] + (tccp->prctsiz[1][i] << 4), 1); /* SPcox (N_i) Table A9*/ } + } +} + +static void j3d_read_cox(opj_j3d_t *j3d, int compno) { + int i; + + opj_cp_t *cp = j3d->cp; + opj_tcp_t *tcp = j3d->state == J3D_STATE_TPH ? &cp->tcps[j3d->curtileno] : j3d->default_tcp; + opj_tccp_t *tccp = &tcp->tccps[compno]; + opj_cio_t *cio = j3d->cio; + + tccp->numresolution[0] = cio_read(cio, 1) + 1; /* SPcox (D) No of decomposition levels in x-axis*/ + if (j3d->cinfo->codec_format == CODEC_J3D) { + tccp->numresolution[1] = cio_read(cio, 1) + 1; /* SPcox (E) No of decomposition levels in y-axis*/ + tccp->numresolution[2] = cio_read(cio, 1) + 1; /* SPcox (F) No of decomposition levels in z-axis*/ + }else if (j3d->cinfo->codec_format == CODEC_J2K) { + tccp->numresolution[1] = tccp->numresolution[0]; + tccp->numresolution[2] = 1; + } + /* check the reduce value */ + cp->reduce[0] = int_min((tccp->numresolution[0])-1, cp->reduce[0]); + cp->reduce[1] = int_min((tccp->numresolution[1])-1, cp->reduce[1]); + cp->reduce[2] = int_min((tccp->numresolution[2])-1, cp->reduce[2]); + + tccp->cblk[0] = cio_read(cio, 1) + 2; /* SPcox (G) */ + tccp->cblk[1] = cio_read(cio, 1) + 2; /* SPcox (H) */ + if (j3d->cinfo->codec_format == CODEC_J3D) + tccp->cblk[2] = cio_read(cio, 1) + 2; /* SPcox (I) */ + else + tccp->cblk[2] = tccp->cblk[0]; + + tccp->cblksty = cio_read(cio, 1); /* SPcox (J) */ + tccp->dwtid[0] = cio_read(cio, 1); /* SPcox (K) */ + if (j3d->cinfo->codec_format == CODEC_J3D) { + tccp->dwtid[1] = cio_read(cio, 1); /* SPcox (L) */ + tccp->dwtid[2] = cio_read(cio, 1); /* SPcox (M) */ + }else{ + tccp->dwtid[1] = tccp->dwtid[0]; /* SPcox (L) */ + tccp->dwtid[2] = tccp->dwtid[0]; /* SPcox (M) */ + } + tccp->reversible = (tccp->dwtid[0]>=1 && tccp->dwtid[1]>=1 && tccp->dwtid[2]>=1); //TODO: only valid for irreversible 9x7 WTs + if (tccp->csty & J3D_CP_CSTY_PRT) { + for (i = 0; i < tccp->numresolution[0]; i++) { + int tmp = cio_read(cio, 2); /* SPcox (N_i) */ + tccp->prctsiz[0][i] = tmp & 0xf; + tccp->prctsiz[1][i] = tmp >> 4; + tccp->prctsiz[2][i] = tmp >> 8; + } + } +} + +static void j3d_write_cod(opj_j3d_t *j3d) { + opj_cp_t *cp = NULL; + opj_tcp_t *tcp = NULL; + int lenp, len; + + opj_cio_t *cio = j3d->cio; + + cio_write(cio, J3D_MS_COD, 2); /* COD */ + + lenp = cio_tell(cio); + cio_skip(cio, 2); + + cp = j3d->cp; + tcp = &cp->tcps[j3d->curtileno]; + + /* Scod : Table A-4*/ + cio_write(cio, tcp->csty, 1); /* Scod : Coding style parameters */ + /* SGcod : Table A-5*/ + cio_write(cio, tcp->prg, 1); /* SGcod (A) : Progression order */ + cio_write(cio, tcp->numlayers, 2); /* SGcod (B) : No of layers */ + cio_write(cio, tcp->mct, 1); /* SGcod (C) : Multiple component transformation usage */ + /* SPcod : Table A-6*/ + j3d_write_cox(j3d, 0); + len = cio_tell(cio) - lenp; + cio_seek(cio, lenp); + cio_write(cio, len, 2); /* Lcod */ + cio_seek(cio, lenp + len); +} + +static void j3d_read_cod(opj_j3d_t *j3d) { + int len, i, pos; + + opj_cio_t *cio = j3d->cio; + opj_cp_t *cp = j3d->cp; + opj_tcp_t *tcp = j3d->state == J3D_STATE_TPH ? &cp->tcps[j3d->curtileno] : j3d->default_tcp; + opj_volume_t *volume = j3d->volume; + + /* Lcod */ + len = cio_read(cio, 2); + /* Scod : Table A-4*/ + tcp->csty = cio_read(cio, 1); + /* SGcod : Table A-5*/ + tcp->prg = (OPJ_PROG_ORDER)cio_read(cio, 1); + tcp->numlayers = cio_read(cio, 2); + tcp->mct = cio_read(cio, 1); + + pos = cio_tell(cio); + for (i = 0; i < volume->numcomps; i++) { + tcp->tccps[i].csty = tcp->csty & J3D_CP_CSTY_PRT; + cio_seek(cio, pos); + j3d_read_cox(j3d, i); + } +} + +static void j3d_write_coc(opj_j3d_t *j3d, int compno) { + int lenp, len; + + opj_cp_t *cp = j3d->cp; + opj_tcp_t *tcp = &cp->tcps[j3d->curtileno]; + opj_volume_t *volume = j3d->volume; + opj_cio_t *cio = j3d->cio; + + cio_write(cio, J3D_MS_COC, 2); /* COC */ + lenp = cio_tell(cio); + cio_skip(cio, 2); + cio_write(cio, compno, volume->numcomps <= 256 ? 1 : 2); /* Ccoc */ + cio_write(cio, tcp->tccps[compno].csty, 1); /* Scoc */ + + j3d_write_cox(j3d, compno); + + len = cio_tell(cio) - lenp; + cio_seek(cio, lenp); + cio_write(cio, len, 2); /* Lcoc */ + cio_seek(cio, lenp + len); +} + +static void j3d_read_coc(opj_j3d_t *j3d) { + int len, compno; + + opj_cp_t *cp = j3d->cp; + opj_tcp_t *tcp = j3d->state == J3D_STATE_TPH ? &cp->tcps[j3d->curtileno] : j3d->default_tcp; + opj_volume_t *volume = j3d->volume; + opj_cio_t *cio = j3d->cio; + + len = cio_read(cio, 2); /* Lcoc */ + compno = cio_read(cio, volume->numcomps <= 256 ? 1 : 2); /* Ccoc */ + tcp->tccps[compno].csty = cio_read(cio, 1); /* Scoc */ + j3d_read_cox(j3d, compno); +} + +static void j3d_write_qcx(opj_j3d_t *j3d, int compno) { + int bandno, numbands; + int expn, mant; + + opj_cp_t *cp = j3d->cp; + opj_tcp_t *tcp = &cp->tcps[j3d->curtileno]; + opj_tccp_t *tccp = &tcp->tccps[compno]; + opj_cio_t *cio = j3d->cio; + + cio_write(cio, tccp->qntsty + (tccp->numgbits << 5), 1); /* Sqcx : Table A28 de 15444-1*/ + + if (j3d->cinfo->codec_format == CODEC_J2K) + numbands = tccp->qntsty == J3D_CCP_QNTSTY_SIQNT ? 1 : tccp->numresolution[0] * 3 - 2; + else if (j3d->cinfo->codec_format == CODEC_J3D) { + int diff = tccp->numresolution[0] - tccp->numresolution[2]; + numbands = (tccp->qntsty == J3D_CCP_QNTSTY_SIQNT) ? 1 : (tccp->numresolution[0] * 7 - 6) - 4 *diff; /* SIQNT vs. SEQNT */ + } + + for (bandno = 0; bandno < numbands; bandno++) { + expn = tccp->stepsizes[bandno].expn; + mant = tccp->stepsizes[bandno].mant; + + if (tccp->qntsty == J3D_CCP_QNTSTY_NOQNT) { + cio_write(cio, expn << 3, 1); /* SPqcx_i */ + } else { + cio_write(cio, (expn << 11) + mant, 2); /* SPqcx_i */ + } + } +} + +static void j3d_read_qcx(opj_j3d_t *j3d, int compno, int len) { + int tmp; + int bandno, numbands; + + opj_cp_t *cp = j3d->cp; + opj_tcp_t *tcp = j3d->state == J3D_STATE_TPH ? &cp->tcps[j3d->curtileno] : j3d->default_tcp; + opj_tccp_t *tccp = &tcp->tccps[compno]; + opj_cio_t *cio = j3d->cio; + + tmp = cio_read(cio, 1); /* Sqcx */ + tccp->qntsty = tmp & 0x1f; + tccp->numgbits = tmp >> 5; + + /*Numbands = 1 si SIQNT + len - 1 si NOQNT + (len - 1) / 2 si SEQNT */ + numbands = tccp->qntsty == J3D_CCP_QNTSTY_SIQNT ? 1 : ((tccp->qntsty == J3D_CCP_QNTSTY_NOQNT) ? len - 1 : (len - 1) / 2); + + for (bandno = 0; bandno < numbands; bandno++) { + int expn, mant; + if (tccp->qntsty == J3D_CCP_QNTSTY_NOQNT) { + expn = cio_read(cio, 1) >> 3; /* SPqcx_i */ + mant = 0; + } else { + tmp = cio_read(cio, 2); /* SPqcx_i */ + expn = tmp >> 11; + mant = tmp & 0x7ff; + } + tccp->stepsizes[bandno].expn = expn; + tccp->stepsizes[bandno].mant = mant; + } + + /* Add Antonin : if scalar_derived -> compute other stepsizes */ + if (tccp->qntsty == J3D_CCP_QNTSTY_SIQNT) { + for (bandno = 1; bandno < J3D_MAXBANDS; bandno++) { + int numbands = (cp->transform_format==TRF_2D_DWT) ? 3 : 7; + tccp->stepsizes[bandno].expn = tccp->stepsizes[0].expn - ((bandno - 1) / numbands); + tccp->stepsizes[bandno].mant = tccp->stepsizes[0].mant; + } + } + /* ddA */ +} + +static void j3d_write_qcd(opj_j3d_t *j3d) { + int lenp, len; + + opj_cio_t *cio = j3d->cio; + + cio_write(cio, J3D_MS_QCD, 2); /* QCD */ + lenp = cio_tell(cio); + cio_skip(cio, 2); + j3d_write_qcx(j3d, 0); /* Sqcd*/ + len = cio_tell(cio) - lenp; + cio_seek(cio, lenp); + cio_write(cio, len, 2); /* Lqcd */ + cio_seek(cio, lenp + len); +} + +static void j3d_read_qcd(opj_j3d_t *j3d) { + int len, i, pos; + + opj_cio_t *cio = j3d->cio; + opj_volume_t *volume = j3d->volume; + + len = cio_read(cio, 2); /* Lqcd */ + pos = cio_tell(cio); + for (i = 0; i < volume->numcomps; i++) { + cio_seek(cio, pos); + j3d_read_qcx(j3d, i, len - 2); + } +} + +static void j3d_write_qcc(opj_j3d_t *j3d, int compno) { + int lenp, len; + + opj_cio_t *cio = j3d->cio; + + cio_write(cio, J3D_MS_QCC, 2); /* QCC */ + lenp = cio_tell(cio); + cio_skip(cio, 2); + cio_write(cio, compno, j3d->volume->numcomps <= 256 ? 1 : 2); /* Cqcc */ + j3d_write_qcx(j3d, compno); + len = cio_tell(cio) - lenp; + cio_seek(cio, lenp); + cio_write(cio, len, 2); /* Lqcc */ + cio_seek(cio, lenp + len); +} + +static void j3d_read_qcc(opj_j3d_t *j3d) { + int len, compno; + int numcomp = j3d->volume->numcomps; + opj_cio_t *cio = j3d->cio; + + len = cio_read(cio, 2); /* Lqcc */ + compno = cio_read(cio, numcomp <= 256 ? 1 : 2); /* Cqcc */ + j3d_read_qcx(j3d, compno, len - 2 - (numcomp <= 256 ? 1 : 2)); +} + +static void j3d_write_poc(opj_j3d_t *j3d) { + int len, numpchgs, i; + + int numcomps = j3d->volume->numcomps; + + opj_cp_t *cp = j3d->cp; + opj_tcp_t *tcp = &cp->tcps[j3d->curtileno]; + opj_tccp_t *tccp = &tcp->tccps[0]; + opj_cio_t *cio = j3d->cio; + + numpchgs = tcp->numpocs; + cio_write(cio, J3D_MS_POC, 2); /* POC */ + len = 2 + (5 + 2 * (numcomps <= 256 ? 1 : 2)) * numpchgs; + cio_write(cio, len, 2); /* Lpoc */ + for (i = 0; i < numpchgs; i++) { + opj_poc_t *poc = &tcp->pocs[i]; + cio_write(cio, poc->resno0, 1); /* RSpoc_i */ + cio_write(cio, poc->compno0, (numcomps <= 256 ? 1 : 2)); /* CSpoc_i */ + cio_write(cio, poc->layno1, 2); /* LYEpoc_i */ + poc->layno1 = int_min(poc->layno1, tcp->numlayers); + cio_write(cio, poc->resno1, 1); /* REpoc_i */ + poc->resno1 = int_min(poc->resno1, tccp->numresolution[0]); + cio_write(cio, poc->compno1, (numcomps <= 256 ? 1 : 2)); /* CEpoc_i */ + poc->compno1 = int_min(poc->compno1, numcomps); + cio_write(cio, poc->prg, 1); /* Ppoc_i */ + } +} + +static void j3d_read_poc(opj_j3d_t *j3d) { + int len, numpchgs, i, old_poc; + + int numcomps = j3d->volume->numcomps; + + opj_cp_t *cp = j3d->cp; + opj_tcp_t *tcp = j3d->state == J3D_STATE_TPH ? &cp->tcps[j3d->curtileno] : j3d->default_tcp; + opj_tccp_t *tccp = &tcp->tccps[0]; + opj_cio_t *cio = j3d->cio; + + old_poc = tcp->POC ? tcp->numpocs + 1 : 0; + tcp->POC = 1; + len = cio_read(cio, 2); /* Lpoc */ + numpchgs = (len - 2) / (5 + 2 * (numcomps <= 256 ? 1 : 2)); + + for (i = old_poc; i < numpchgs + old_poc; i++) { + opj_poc_t *poc; + poc = &tcp->pocs[i]; + poc->resno0 = cio_read(cio, 1); /* RSpoc_i */ + poc->compno0 = cio_read(cio, numcomps <= 256 ? 1 : 2); /* CSpoc_i */ + poc->layno1 = int_min(cio_read(cio, 2), (unsigned int) tcp->numlayers); /* LYEpoc_i */ + poc->resno1 = int_min(cio_read(cio, 1), (unsigned int) tccp->numresolution[0]); /* REpoc_i */ + poc->compno1 = int_min( + cio_read(cio, numcomps <= 256 ? 1 : 2), (unsigned int) numcomps); /* CEpoc_i */ + poc->prg = (OPJ_PROG_ORDER)cio_read(cio, 1); /* Ppoc_i */ + } + + tcp->numpocs = numpchgs + old_poc - 1; +} + +static void j3d_read_crg(opj_j3d_t *j3d) { + int len, i, Xcrg_i, Ycrg_i, Zcrg_i; + + opj_cio_t *cio = j3d->cio; + int numcomps = j3d->volume->numcomps; + + len = cio_read(cio, 2); /* Lcrg */ + for (i = 0; i < numcomps; i++) { + Xcrg_i = cio_read(cio, 2); /* Xcrg_i */ + Ycrg_i = cio_read(cio, 2); /* Ycrg_i */ + Zcrg_i = cio_read(cio, 2); /* Zcrg_i */ + } +} + +static void j3d_read_tlm(opj_j3d_t *j3d) { + int len, Ztlm, Stlm, ST, SP, tile_tlm, i; + long int Ttlm_i, Ptlm_i; + + opj_cio_t *cio = j3d->cio; + + len = cio_read(cio, 2); /* Ltlm */ + Ztlm = cio_read(cio, 1); /* Ztlm */ + Stlm = cio_read(cio, 1); /* Stlm */ + ST = ((Stlm >> 4) & 0x01) + ((Stlm >> 4) & 0x02); + SP = (Stlm >> 6) & 0x01; + tile_tlm = (len - 4) / ((SP + 1) * 2 + ST); + for (i = 0; i < tile_tlm; i++) { + Ttlm_i = cio_read(cio, ST); /* Ttlm_i */ + Ptlm_i = cio_read(cio, SP ? 4 : 2); /* Ptlm_i */ + } +} + +static void j3d_read_plm(opj_j3d_t *j3d) { + int len, i, Zplm, Nplm, add, packet_len = 0; + + opj_cio_t *cio = j3d->cio; + + len = cio_read(cio, 2); /* Lplm */ + Zplm = cio_read(cio, 1); /* Zplm */ + len -= 3; + while (len > 0) { + Nplm = cio_read(cio, 4); /* Nplm */ + len -= 4; + for (i = Nplm; i > 0; i--) { + add = cio_read(cio, 1); + len--; + packet_len = (packet_len << 7) + add; /* Iplm_ij */ + if ((add & 0x80) == 0) { + /* New packet */ + packet_len = 0; + } + if (len <= 0) + break; + } + } +} + +static void j3d_read_plt(opj_j3d_t *j3d) { + int len, i, Zplt, packet_len = 0, add; + + opj_cio_t *cio = j3d->cio; + + len = cio_read(cio, 2); /* Lplt */ + Zplt = cio_read(cio, 1); /* Zplt */ + for (i = len - 3; i > 0; i--) { + add = cio_read(cio, 1); + packet_len = (packet_len << 7) + add; /* Iplt_i */ + if ((add & 0x80) == 0) { + /* New packet */ + packet_len = 0; + } + } +} + +static void j3d_read_ppm(opj_j3d_t *j3d) { + int len, Z_ppm, i, j; + int N_ppm; + + opj_cp_t *cp = j3d->cp; + opj_cio_t *cio = j3d->cio; + + len = cio_read(cio, 2); + cp->ppm = 1; + + Z_ppm = cio_read(cio, 1); /* Z_ppm */ + len -= 3; + while (len > 0) { + if (cp->ppm_previous == 0) { + N_ppm = cio_read(cio, 4); /* N_ppm */ + len -= 4; + } else { + N_ppm = cp->ppm_previous; + } + j = cp->ppm_store; + if (Z_ppm == 0) { /* First PPM marker */ + cp->ppm_data = (unsigned char *) opj_malloc(N_ppm * sizeof(unsigned char)); + cp->ppm_data_first = cp->ppm_data; + cp->ppm_len = N_ppm; + } else { /* NON-first PPM marker */ + cp->ppm_data = (unsigned char *) opj_realloc(cp->ppm_data, (N_ppm + cp->ppm_store) * sizeof(unsigned char)); + cp->ppm_data_first = cp->ppm_data; + cp->ppm_len = N_ppm + cp->ppm_store; + } + for (i = N_ppm; i > 0; i--) { /* Read packet header */ + cp->ppm_data[j] = cio_read(cio, 1); + j++; + len--; + if (len == 0) + break; /* Case of non-finished packet header in present marker but finished in next one */ + } + cp->ppm_previous = i - 1; + cp->ppm_store = j; + } +} + +static void j3d_read_ppt(opj_j3d_t *j3d) { + int len, Z_ppt, i, j = 0; + + opj_cp_t *cp = j3d->cp; + opj_tcp_t *tcp = cp->tcps + j3d->curtileno; + opj_cio_t *cio = j3d->cio; + + len = cio_read(cio, 2); + Z_ppt = cio_read(cio, 1); + tcp->ppt = 1; + if (Z_ppt == 0) { /* First PPT marker */ + tcp->ppt_data = (unsigned char *) opj_malloc((len - 3) * sizeof(unsigned char)); + tcp->ppt_data_first = tcp->ppt_data; + tcp->ppt_store = 0; + tcp->ppt_len = len - 3; + } else { /* NON-first PPT marker */ + tcp->ppt_data = (unsigned char *) opj_realloc(tcp->ppt_data, (len - 3 + tcp->ppt_store) * sizeof(unsigned char)); + tcp->ppt_data_first = tcp->ppt_data; + tcp->ppt_len = len - 3 + tcp->ppt_store; + } + j = tcp->ppt_store; + for (i = len - 3; i > 0; i--) { + tcp->ppt_data[j] = cio_read(cio, 1); + j++; + } + tcp->ppt_store = j; +} + +static void j3d_write_sot(opj_j3d_t *j3d) { + int lenp, len; + + opj_cio_t *cio = j3d->cio; + + j3d->sot_start = cio_tell(cio); + cio_write(cio, J3D_MS_SOT, 2); /* SOT */ + lenp = cio_tell(cio); + cio_skip(cio, 2); /* Lsot (further) */ + cio_write(cio, j3d->curtileno, 2); /* Isot */ + cio_skip(cio, 4); /* Psot (further in j3d_write_sod) */ + cio_write(cio, 0, 1); /* TPsot */ + cio_write(cio, 1, 1); /* TNsot (no of tile-parts of this tile in this codestream)*/ + len = cio_tell(cio) - lenp; + cio_seek(cio, lenp); + cio_write(cio, len, 2); /* Lsot */ + cio_seek(cio, lenp + len); +} + +static void j3d_read_sot(opj_j3d_t *j3d) { + int len, tileno, totlen, partno, numparts, i; + opj_tcp_t *tcp = NULL; + char status = 0; + + opj_cp_t *cp = j3d->cp; + opj_cio_t *cio = j3d->cio; + + len = cio_read(cio, 2); + tileno = cio_read(cio, 2); + + if (cp->tileno_size == 0) { + cp->tileno[cp->tileno_size] = tileno; + cp->tileno_size++; + } else { + i = 0; + while (i < cp->tileno_size && status == 0) { + status = cp->tileno[i] == tileno ? 1 : 0; + i++; + } + if (status == 0) { + cp->tileno[cp->tileno_size] = tileno; + cp->tileno_size++; + } + } + + totlen = cio_read(cio, 4); + if (!totlen) + totlen = cio_numbytesleft(cio) + 8; + + partno = cio_read(cio, 1); + numparts = cio_read(cio, 1); + + j3d->curtileno = tileno; + j3d->eot = cio_getbp(cio) - 12 + totlen; + j3d->state = J3D_STATE_TPH; + tcp = &cp->tcps[j3d->curtileno]; + + if (tcp->first == 1) { + + /* Initialization PPT */ + opj_tccp_t *tmp = tcp->tccps; + memcpy(tcp, j3d->default_tcp, sizeof(opj_tcp_t)); + tcp->ppt = 0; + tcp->ppt_data = NULL; + tcp->ppt_data_first = NULL; + tcp->tccps = tmp; + + for (i = 0; i < j3d->volume->numcomps; i++) { + tcp->tccps[i] = j3d->default_tcp->tccps[i]; + } + cp->tcps[j3d->curtileno].first = 0; + } +} + +static void j3d_write_sod(opj_j3d_t *j3d, void *tile_coder) { + int l, layno; + int totlen; + opj_tcp_t *tcp = NULL; + opj_volume_info_t *volume_info = NULL; + + opj_tcd_t *tcd = (opj_tcd_t*)tile_coder; /* cast is needed because of conflicts in header inclusions */ + opj_cp_t *cp = j3d->cp; + opj_cio_t *cio = j3d->cio; + + cio_write(cio, J3D_MS_SOD, 2); + if (j3d->curtileno == 0) { + j3d->sod_start = cio_tell(cio) + j3d->pos_correction; + } + + /* INDEX >> */ + volume_info = j3d->volume_info; + if (volume_info && volume_info->index_on) { + volume_info->tile[j3d->curtileno].end_header = cio_tell(cio) + j3d->pos_correction - 1; + } + /* << INDEX */ + + tcp = &cp->tcps[j3d->curtileno]; + for (layno = 0; layno < tcp->numlayers; layno++) { + tcp->rates[layno] -= tcp->rates[layno] ? (j3d->sod_start / (cp->th * cp->tw * cp->tl)) : 0; + } + + if(volume_info) { + volume_info->num = 0; + } + + l = tcd_encode_tile(tcd, j3d->curtileno, cio_getbp(cio), cio_numbytesleft(cio) - 2, volume_info); + + /* Writing Psot in SOT marker */ + totlen = cio_tell(cio) + l - j3d->sot_start; + cio_seek(cio, j3d->sot_start + 6); + cio_write(cio, totlen, 4); + cio_seek(cio, j3d->sot_start + totlen); +} + +static void j3d_read_sod(opj_j3d_t *j3d) { + int len, truncate = 0, i; + unsigned char *data = NULL, *data_ptr = NULL; + + opj_cio_t *cio = j3d->cio; + int curtileno = j3d->curtileno; + + len = int_min(j3d->eot - cio_getbp(cio), cio_numbytesleft(cio) + 1); + + if (len == cio_numbytesleft(cio) + 1) { + truncate = 1; /* Case of a truncate codestream */ + } + + data = (unsigned char *) opj_malloc((j3d->tile_len[curtileno] + len) * sizeof(unsigned char)); + + for (i = 0; i < j3d->tile_len[curtileno]; i++) { + data[i] = j3d->tile_data[curtileno][i]; + } + + data_ptr = data + j3d->tile_len[curtileno]; + for (i = 0; i < len; i++) { + data_ptr[i] = cio_read(cio, 1); + } + + j3d->tile_len[curtileno] += len; + opj_free(j3d->tile_data[curtileno]); + j3d->tile_data[curtileno] = data; + + if (!truncate) { + j3d->state = J3D_STATE_TPHSOT; + } else { + j3d->state = J3D_STATE_NEOC; /* RAJOUTE !! */ + } +} + +static void j3d_write_rgn(opj_j3d_t *j3d, int compno, int tileno) { + + opj_cp_t *cp = j3d->cp; + opj_tcp_t *tcp = &cp->tcps[tileno]; + opj_cio_t *cio = j3d->cio; + int numcomps = j3d->volume->numcomps; + + cio_write(cio, J3D_MS_RGN, 2); /* RGN */ + cio_write(cio, numcomps <= 256 ? 5 : 6, 2); /* Lrgn */ + cio_write(cio, compno, numcomps <= 256 ? 1 : 2); /* Crgn */ + cio_write(cio, 0, 1); /* Srgn */ + cio_write(cio, tcp->tccps[compno].roishift, 1); /* SPrgn */ +} + +static void j3d_read_rgn(opj_j3d_t *j3d) { + int len, compno, roisty; + + opj_cp_t *cp = j3d->cp; + opj_tcp_t *tcp = j3d->state == J3D_STATE_TPH ? &cp->tcps[j3d->curtileno] : j3d->default_tcp; + opj_cio_t *cio = j3d->cio; + int numcomps = j3d->volume->numcomps; + + len = cio_read(cio, 2); /* Lrgn */ + compno = cio_read(cio, numcomps <= 256 ? 1 : 2); /* Crgn */ + roisty = cio_read(cio, 1); /* Srgn */ + tcp->tccps[compno].roishift = cio_read(cio, 1); /* SPrgn */ +} + +static void j3d_write_eoc(opj_j3d_t *j3d) { + opj_cio_t *cio = j3d->cio; + /* opj_event_msg(j3d->cinfo, "%.8x: EOC\n", cio_tell(cio) + j3d->pos_correction); */ + cio_write(cio, J3D_MS_EOC, 2); +} + +static void j3d_read_eoc(opj_j3d_t *j3d) { + int i, tileno; + +#ifndef NO_PACKETS_DECODING + opj_tcd_t *tcd = tcd_create(j3d->cinfo); + tcd_malloc_decode(tcd, j3d->volume, j3d->cp); + /*j3d_dump_volume(stdout, tcd->volume); + j3d_dump_cp(stdout, tcd->volume, tcd->cp);*/ + for (i = 0; i < j3d->cp->tileno_size; i++) { + tileno = j3d->cp->tileno[i]; + //opj_event_msg(j3d->cinfo, EVT_INFO, "tcd_decode_tile \n"); + tcd_decode_tile(tcd, j3d->tile_data[tileno], j3d->tile_len[tileno], tileno); + opj_free(j3d->tile_data[tileno]); + j3d->tile_data[tileno] = NULL; + } + tcd_free_decode(tcd); + tcd_destroy(tcd); +#else + for (i = 0; i < j3d->cp->tileno_size; i++) { + tileno = j3d->cp->tileno[i]; + opj_free(j3d->tile_data[tileno]); + j3d->tile_data[tileno] = NULL; + } +#endif + + j3d->state = J3D_STATE_MT; +} + +static void j3d_read_unk(opj_j3d_t *j3d) { + opj_event_msg(j3d->cinfo, EVT_WARNING, "Unknown marker\n"); +} + +static opj_atk_t atk_info_wt[] = { + {0, 1, J3D_ATK_WS, J3D_ATK_IRR, 0, J3D_ATK_WS, 1.230174104, 4, {0}, {0}, {0}, {1,1,1,1}, {-1.586134342059924, -0.052980118572961, 0.882911075530934, 0.443506852043971}},/* WT 9-7 IRR*/ + {1, 0, J3D_ATK_WS, J3D_ATK_REV, 0, J3D_ATK_WS, 0, 2, {0}, {1,2}, {1,2}, {1,1}, {-1.0,1.0}},/* WT 5-3 REV*/ + {2, 0, J3D_ATK_ARB, J3D_ATK_REV, 0, J3D_ATK_CON, 0, 2, {0,0}, {0,1}, {0,1}, {1,1}, {{-1.0},{1.0}}}, /* WT 2-2 REV*/ + {3, 0, J3D_ATK_ARB, J3D_ATK_REV, 1, J3D_ATK_CON, 0, 3, {0,0,-1}, {0,1,2}, {0,1,2}, {1,1,3}, {{-1.0},{1.0},{1.0,0.0,-1.0}}}, /* WT 2-6 REV*/ + {4, 0, J3D_ATK_ARB, J3D_ATK_REV, 1, J3D_ATK_CON, 0, 3, {0,0,-2}, {0,1,6}, {0,1,32}, {1,1,5}, {{-1},{1},{-3.0,22.0,0.0,-22.0,3.0}}}, /* WT 2-10 REV*/ + {5, 1, J3D_ATK_ARB, J3D_ATK_IRR, 1, J3D_ATK_WS, 1, 7, {0}, {0}, {0}, {1,1,2,1,2,1,3},{{-1},{1.58613434206},{-0.460348209828, 0.460348209828},{0.25},{0.374213867768,-0.374213867768},{-1.33613434206},{0.29306717103,0,-0.29306717103}}}, /* WT 6-10 IRR*/ + {6, 1, J3D_ATK_ARB, J3D_ATK_IRR, 0, J3D_ATK_WS, 1, 11, {0}, {0}, {0}, {1,1,2,1,2,1,2,1,2,1,5},{{-1},{0,99715069105},{-1.00573127827, 1.00573127827},{-0.27040357631},{2.20509972343, -2.20509972343},{0.08059995736}, + {-1.62682532350, 1.62682532350},{0.52040357631},{0.60404664250, -0.60404664250},{-0.82775064841},{-0.06615812964, 0.29402137720, 0, -0.29402137720, 0.06615812964}}}, /* WT 10-18 IRR*/ + {7, 1, J3D_ATK_WS, J3D_ATK_IRR, 0, J3D_ATK_WS, 1, 2, {0}, {0}, {0}, {1,1}, {-0.5, 0.25}}, /* WT 5-3 IRR*/ + {8, 0, J3D_ATK_WS, J3D_ATK_REV, 0, J3D_ATK_WS, 0, 2, {0}, {4,4}, {8,8}, {2,2}, {{-9,1},{5,-1}}} /* WT 13-7 REV*/ +}; + +typedef struct opj_dec_mstabent { + /** marker value */ + int id; + /** value of the state when the marker can appear */ + int states; + /** action linked to the marker */ + void (*handler) (opj_j3d_t *j3d); +} opj_dec_mstabent_t; + +opj_dec_mstabent_t j3d_dec_mstab[] = { + {J3D_MS_SOC, J3D_STATE_MHSOC, j3d_read_soc}, + {J3D_MS_SOT, J3D_STATE_MH | J3D_STATE_TPHSOT, j3d_read_sot}, + {J3D_MS_SOD, J3D_STATE_TPH, j3d_read_sod}, + {J3D_MS_EOC, J3D_STATE_TPHSOT, j3d_read_eoc}, + {J3D_MS_CAP, J3D_STATE_MHSIZ, j3d_read_cap}, + {J3D_MS_SIZ, J3D_STATE_MHSIZ, j3d_read_siz}, + {J3D_MS_ZSI, J3D_STATE_MHSIZ, j3d_read_zsi}, + {J3D_MS_COD, J3D_STATE_MH | J3D_STATE_TPH, j3d_read_cod}, + {J3D_MS_COC, J3D_STATE_MH | J3D_STATE_TPH, j3d_read_coc}, + {J3D_MS_RGN, J3D_STATE_MH | J3D_STATE_TPH, j3d_read_rgn}, + {J3D_MS_QCD, J3D_STATE_MH | J3D_STATE_TPH, j3d_read_qcd}, + {J3D_MS_QCC, J3D_STATE_MH | J3D_STATE_TPH, j3d_read_qcc}, + {J3D_MS_POC, J3D_STATE_MH | J3D_STATE_TPH, j3d_read_poc}, + {J3D_MS_TLM, J3D_STATE_MH, j3d_read_tlm}, + {J3D_MS_PLM, J3D_STATE_MH, j3d_read_plm}, + {J3D_MS_PLT, J3D_STATE_TPH, j3d_read_plt}, + {J3D_MS_PPM, J3D_STATE_MH, j3d_read_ppm}, + {J3D_MS_PPT, J3D_STATE_TPH, j3d_read_ppt}, + {J3D_MS_SOP, 0, 0}, + {J3D_MS_CRG, J3D_STATE_MH, j3d_read_crg}, + {J3D_MS_COM, J3D_STATE_MH | J3D_STATE_TPH, j3d_read_com}, + {J3D_MS_DCO, J3D_STATE_MH | J3D_STATE_TPH, j3d_read_dco}, + {J3D_MS_ATK, J3D_STATE_MH | J3D_STATE_TPH, j3d_read_atk}, + {0, J3D_STATE_MH | J3D_STATE_TPH, j3d_read_unk} + /*, -->must define the j3d_read functions + {J3D_MS_CBD, J3D_STATE_MH | J3D_STATE_TPH, j3d_read_cbd}, + {J3D_MS_MCT, J3D_STATE_MH | J3D_STATE_TPH, j3d_read_mct}, + {J3D_MS_MCC, J3D_STATE_MH | J3D_STATE_TPH, j3d_read_mcc}, + {J3D_MS_MCO, J3D_STATE_MH | J3D_STATE_TPH, j3d_read_mco}, + {J3D_MS_NLT, J3D_STATE_MH | J3D_STATE_TPH, j3d_read_nlt}, + {J3D_MS_VMS, J3D_STATE_MH, j3d_read_vms}, + {J3D_MS_DFS, J3D_STATE_MH, j3d_read_dfs}, + {J3D_MS_ADS, J3D_STATE_MH, j3d_read_ads}, + {J3D_MS_QPD, J3D_STATE_MH, j3d_read_qpd}, + {J3D_MS_QPC, J3D_STATE_TPH, j3d_read_qpc}*/ +}; + +/** +Read the lookup table containing all the marker, status and action +@param id Marker value +*/ +static opj_dec_mstabent_t *j3d_dec_mstab_lookup(int id) { + opj_dec_mstabent_t *e; + for (e = j3d_dec_mstab; e->id != 0; e++) { + if (e->id == id) { + break; + } + } + return e; +} + +/* ----------------------------------------------------------------------- */ +/* J3D / JPT decoder interface */ +/* ----------------------------------------------------------------------- */ + +opj_j3d_t* j3d_create_decompress(opj_common_ptr cinfo) { + opj_j3d_t *j3d = (opj_j3d_t*)opj_malloc(sizeof(opj_j3d_t)); + if(j3d) { + j3d->cinfo = cinfo; + j3d->default_tcp = (opj_tcp_t*)opj_malloc(sizeof(opj_tcp_t)); + if(!j3d->default_tcp) { + opj_free(j3d); + return NULL; + } + } + return j3d; +} + +void j3d_destroy_decompress(opj_j3d_t *j3d) { + int i = 0; + + if(j3d->tile_len != NULL) { + opj_free(j3d->tile_len); + } + if(j3d->tile_data != NULL) { + opj_free(j3d->tile_data); + } + if(j3d->default_tcp != NULL) { + opj_tcp_t *default_tcp = j3d->default_tcp; + if(default_tcp->ppt_data_first != NULL) { + opj_free(default_tcp->ppt_data_first); + } + if(j3d->default_tcp->tccps != NULL) { + opj_free(j3d->default_tcp->tccps); + } + opj_free(j3d->default_tcp); + } + if(j3d->cp != NULL) { + opj_cp_t *cp = j3d->cp; + if(cp->tcps != NULL) { + for(i = 0; i < cp->tw * cp->th * cp->tl; i++) { + if(cp->tcps[i].ppt_data_first != NULL) { + opj_free(cp->tcps[i].ppt_data_first); + } + if(cp->tcps[i].tccps != NULL) { + opj_free(cp->tcps[i].tccps); + } + } + opj_free(cp->tcps); + } + if(cp->ppm_data_first != NULL) { + opj_free(cp->ppm_data_first); + } + if(cp->tileno != NULL) { + opj_free(cp->tileno); + } + if(cp->comment != NULL) { + opj_free(cp->comment); + } + + opj_free(cp); + } + + opj_free(j3d); +} + +void j3d_setup_decoder(opj_j3d_t *j3d, opj_dparameters_t *parameters) { + if(j3d && parameters) { + /* create and initialize the coding parameters structure */ + opj_cp_t *cp = (opj_cp_t*)opj_malloc(sizeof(opj_cp_t)); + cp->reduce[0] = parameters->cp_reduce[0]; + cp->reduce[1] = parameters->cp_reduce[1]; + cp->reduce[2] = parameters->cp_reduce[2]; + cp->layer = parameters->cp_layer; + cp->bigendian = parameters->bigendian; + + + cp->encoding_format = ENCOD_2EB; + cp->transform_format = TRF_2D_DWT; + + /* keep a link to cp so that we can destroy it later in j3d_destroy_decompress */ + j3d->cp = cp; + } +} + +opj_volume_t* j3d_decode(opj_j3d_t *j3d, opj_cio_t *cio) { + opj_volume_t *volume = NULL; + + opj_common_ptr cinfo = j3d->cinfo; + + j3d->cio = cio; + + /* create an empty volume */ + volume = (opj_volume_t*)opj_malloc(sizeof(opj_volume_t)); + j3d->volume = volume; + + j3d->state = J3D_STATE_MHSOC; + + for (;;) { + opj_dec_mstabent_t *e; + int id = cio_read(cio, 2); + if (id >> 8 != 0xff) { + opj_volume_destroy(volume); + opj_event_msg(cinfo, EVT_ERROR, "%.8x: expected a marker instead of %x\n", cio_tell(cio) - 2, id); + return 0; + } + e = j3d_dec_mstab_lookup(id); + //opj_event_msg(cinfo, EVT_INFO, "MARKER %x PREVSTATE %d E->STATE %d\n",e->id,j3d->state,e->states); + if (!(j3d->state & e->states)) { + opj_volume_destroy(volume); + opj_event_msg(cinfo, EVT_ERROR, "%.8x: unexpected marker %x\n", cio_tell(cio) - 2, id); + return 0; + } + if (e->handler) { + (*e->handler)(j3d); + } + //opj_event_msg(cinfo, EVT_INFO, "POSTSTATE %d\n",j3d->state); + if (j3d->state == J3D_STATE_MT) { + break; + } + if (j3d->state == J3D_STATE_NEOC) { + break; + } + } + if (j3d->state == J3D_STATE_NEOC) { + j3d_read_eoc(j3d); + } + + if (j3d->state != J3D_STATE_MT) { + opj_event_msg(cinfo, EVT_WARNING, "Incomplete bitstream\n"); + } + + return volume; +} + +/* ----------------------------------------------------------------------- */ +/* J3D encoder interface */ +/* ----------------------------------------------------------------------- */ + +opj_j3d_t* j3d_create_compress(opj_common_ptr cinfo) { + opj_j3d_t *j3d = (opj_j3d_t*)opj_malloc(sizeof(opj_j3d_t)); + if(j3d) { + j3d->cinfo = cinfo; + } + return j3d; +} + +void j3d_destroy_compress(opj_j3d_t *j3d) { + int tileno; + + if(!j3d) return; + + if(j3d->volume_info != NULL) { + opj_volume_info_t *volume_info = j3d->volume_info; + if (volume_info->index_on && j3d->cp) { + opj_cp_t *cp = j3d->cp; + for (tileno = 0; tileno < cp->tw * cp->th; tileno++) { + opj_tile_info_t *tile_info = &volume_info->tile[tileno]; + opj_free(tile_info->thresh); + opj_free(tile_info->packet); + } + opj_free(volume_info->tile); + } + opj_free(volume_info); + } + if(j3d->cp != NULL) { + opj_cp_t *cp = j3d->cp; + + if(cp->comment) { + opj_free(cp->comment); + } + if(cp->matrice) { + opj_free(cp->matrice); + } + for (tileno = 0; tileno < cp->tw * cp->th; tileno++) { + opj_free(cp->tcps[tileno].tccps); + } + opj_free(cp->tcps); + opj_free(cp); + } + + opj_free(j3d); +} + +void j3d_setup_encoder(opj_j3d_t *j3d, opj_cparameters_t *parameters, opj_volume_t *volume) { + int i, j, tileno, numpocs_tile; + opj_cp_t *cp = NULL; + + if(!j3d || !parameters || ! volume) { + return; + } + + /* create and initialize the coding parameters structure */ + cp = (opj_cp_t*)opj_malloc(sizeof(opj_cp_t)); + + /* keep a link to cp so that we can destroy it later in j3d_destroy_compress */ + j3d->cp = cp; + + /* set default values for cp */ + cp->tw = 1; + cp->th = 1; + cp->tl = 1; + + /* copy user encoding parameters */ + cp->disto_alloc = parameters->cp_disto_alloc; + cp->fixed_alloc = parameters->cp_fixed_alloc; + cp->fixed_quality = parameters->cp_fixed_quality; + + /* transform and coding method */ + cp->transform_format = parameters->transform_format; + cp->encoding_format = parameters->encoding_format; + + /* mod fixed_quality */ + if(parameters->cp_matrice) { + size_t array_size = parameters->tcp_numlayers * 3 * parameters->numresolution[0] * sizeof(int); + cp->matrice = (int *) opj_malloc(array_size); + memcpy(cp->matrice, parameters->cp_matrice, array_size); + } + + /* creation of an index file ? */ + cp->index_on = parameters->index_on; + if(cp->index_on) { + j3d->volume_info = (opj_volume_info_t*)opj_malloc(sizeof(opj_volume_info_t)); + } + + /* tiles */ + cp->tdx = parameters->cp_tdx; + cp->tdy = parameters->cp_tdy; + cp->tdz = parameters->cp_tdz; + /* tile offset */ + cp->tx0 = parameters->cp_tx0; + cp->ty0 = parameters->cp_ty0; + cp->tz0 = parameters->cp_tz0; + /* comment string */ + if(parameters->cp_comment) { + cp->comment = (char*)opj_malloc(strlen(parameters->cp_comment) + 1); + if(cp->comment) { + strcpy(cp->comment, parameters->cp_comment); + } + } + + /*calculate other encoding parameters*/ + if (parameters->tile_size_on) { + cp->tw = int_ceildiv(volume->x1 - cp->tx0, cp->tdx); + cp->th = int_ceildiv(volume->y1 - cp->ty0, cp->tdy); + cp->tl = int_ceildiv(volume->z1 - cp->tz0, cp->tdz); + } else { + cp->tdx = volume->x1 - cp->tx0; + cp->tdy = volume->y1 - cp->ty0; + cp->tdz = volume->z1 - cp->tz0; + } + + /* initialize the multiple tiles */ + /* ---------------------------- */ + cp->tcps = (opj_tcp_t *) opj_malloc(cp->tw * cp->th * cp->tl * sizeof(opj_tcp_t)); + + for (tileno = 0; tileno < cp->tw * cp->th * cp->tl; tileno++) { + opj_tcp_t *tcp = &cp->tcps[tileno]; + tcp->numlayers = parameters->tcp_numlayers; + for (j = 0; j < tcp->numlayers; j++) { + if (cp->fixed_quality) { /* add fixed_quality */ + tcp->distoratio[j] = parameters->tcp_distoratio[j]; + } else { + tcp->rates[j] = parameters->tcp_rates[j]; + } + } + tcp->csty = parameters->csty; + tcp->prg = parameters->prog_order; + tcp->mct = volume->numcomps == 3 ? 1 : 0; + + numpocs_tile = 0; + tcp->POC = 0; + if (parameters->numpocs) { + /* initialisation of POC */ + tcp->POC = 1; + for (i = 0; i < parameters->numpocs; i++) { + if((tileno == parameters->POC[i].tile - 1) || (parameters->POC[i].tile == -1)) { + opj_poc_t *tcp_poc = &tcp->pocs[numpocs_tile]; + tcp_poc->resno0 = parameters->POC[numpocs_tile].resno0; + tcp_poc->compno0 = parameters->POC[numpocs_tile].compno0; + tcp_poc->layno1 = parameters->POC[numpocs_tile].layno1; + tcp_poc->resno1 = parameters->POC[numpocs_tile].resno1; + tcp_poc->compno1 = parameters->POC[numpocs_tile].compno1; + tcp_poc->prg = parameters->POC[numpocs_tile].prg; + tcp_poc->tile = parameters->POC[numpocs_tile].tile; + numpocs_tile++; + } + } + } + tcp->numpocs = numpocs_tile; + + tcp->tccps = (opj_tccp_t *) opj_malloc(volume->numcomps * sizeof(opj_tccp_t)); + + for (i = 0; i < volume->numcomps; i++) { + opj_tccp_t *tccp = &tcp->tccps[i]; + tccp->csty = parameters->csty & J3D_CCP_CSTY_PRT; /* 0 => standard precint || 1 => custom-defined precinct */ + tccp->numresolution[0] = parameters->numresolution[0]; + tccp->numresolution[1] = parameters->numresolution[1]; + tccp->numresolution[2] = parameters->numresolution[2]; + assert (parameters->cblock_init[0] <= T1_MAXCBLKW); + assert (parameters->cblock_init[0] >= T1_MINCBLKW); + assert (parameters->cblock_init[1] <= T1_MAXCBLKH); + assert (parameters->cblock_init[1] >= T1_MINCBLKH); + assert (parameters->cblock_init[2] <= T1_MAXCBLKD); + assert (parameters->cblock_init[2] >= T1_MINCBLKD); + tccp->cblk[0] = int_floorlog2(parameters->cblock_init[0]); + tccp->cblk[1] = int_floorlog2(parameters->cblock_init[1]); + tccp->cblk[2] = int_floorlog2(parameters->cblock_init[2]); + assert (tccp->cblk[0]+tccp->cblk[1]+tccp->cblk[1] <= T1_MAXWHD); + tccp->cblksty = parameters->mode; //Codeblock style --> Table A.19 (default 0) + + /*ATK / transform */ + tccp->reversible = parameters->irreversible ? 0 : 1; /* 0 => DWT 9-7 || 1 => DWT 5-3 */ + for (j = 0; j < 3; j++) { + tccp->dwtid[j] = parameters->irreversible ? 0 : 1; /* 0 => DWT 9-7 || 1 => DWT 5-3 */ + } + + /* Quantification: SEQNT (Scalar Expounded, value for each subband) / NOQNT (no quant)*/ + tccp->qntsty = parameters->irreversible ? J3D_CCP_QNTSTY_SEQNT : J3D_CCP_QNTSTY_NOQNT; + tccp->numgbits = 2; + if (i == parameters->roi_compno) { + tccp->roishift = parameters->roi_shift; + } else { + tccp->roishift = 0; + } + /* Custom defined precints */ + if (parameters->csty & J3D_CCP_CSTY_PRT) { + int k; + for (k = 0; k < 3; k++) { + int p = 0; + for (j = tccp->numresolution[k] - 1; j >= 0; j--) { + if (p < parameters->res_spec) {/* p < number of precinct size specifications */ + if (parameters->prct_init[k][p] < 1) { + tccp->prctsiz[k][j] = 1; + } else { + tccp->prctsiz[k][j] = int_floorlog2(parameters->prct_init[k][p]); + } + } else { + int res_spec = parameters->res_spec; + int size_prct = parameters->prct_init[k][res_spec - 1] >> (p - (res_spec - 1)); + if (size_prct < 1) { + tccp->prctsiz[k][j] = 1; + } else { + tccp->prctsiz[k][j] = int_floorlog2(size_prct); + } + } + } + p++; + } + } else { + int k; + for (k = 0; k < 3; k++) { + for (j = 0; j < tccp->numresolution[k]; j++) { + tccp->prctsiz[k][j] = 15; + } + } + } + //Calcular stepsize for each subband (if NOQNT -->stepsize = 1.0) + dwt_calc_explicit_stepsizes(tccp, volume->comps[i].prec); + } + } +} + +/** +Create an index file +@param j3d +@param cio +@param volume_info +@param index Index filename +@return Returns 1 if successful, returns 0 otherwise +*/ +static int j3d_create_index(opj_j3d_t *j3d, opj_cio_t *cio, opj_volume_info_t *volume_info, char *index) { + + int tileno, compno, layno, resno, precno, pack_nb, x, y, z; + FILE *stream = NULL; + double total_disto = 0; + + volume_info->codestream_size = cio_tell(cio) + j3d->pos_correction; /* Correction 14/4/03 suite rmq de Patrick */ + + stream = fopen(index, "w"); + if (!stream) { + opj_event_msg(j3d->cinfo, EVT_ERROR, "failed to open %s for writing\n", index); + return 0; + } + + fprintf(stream, "w %d\t h %d\t l %d\n", volume_info->volume_w, volume_info->volume_h, volume_info->volume_l); + fprintf(stream, "TRASNFORM\t%d\n", volume_info->transform_format); + fprintf(stream, "ENTROPY CODING\t%d\n", volume_info->encoding_format); + fprintf(stream, "PROG\t%d\n", volume_info->prog); + fprintf(stream, "TILE\tx %d y %d z %d\n", volume_info->tile_x, volume_info->tile_y, volume_info->tile_z); + fprintf(stream, "NOTILE\tx %d y %d z %d\n", volume_info->tw, volume_info->th, volume_info->tl); + fprintf(stream, "COMPONENTS\t%d\n", volume_info->comp); + fprintf(stream, "LAYER\t%d\n", volume_info->layer); + fprintf(stream, "RESOLUTIONS\tx %d y %d z %d\n", volume_info->decomposition[0], volume_info->decomposition[1], volume_info->decomposition[2]); + + fprintf(stream, "Precint sizes for each resolution:\n"); + for (resno = volume_info->decomposition[0]; resno >= 0; resno--) { + fprintf(stream, "Resno %d \t [%d,%d,%d] \n", resno, + (1 << volume_info->tile[0].prctsiz[0][resno]), (1 << volume_info->tile[0].prctsiz[0][resno]), (1 << volume_info->tile[0].prctsiz[2][resno])); /* based on tile 0 */ + } + fprintf(stream, "HEADER_END\t%d\n", volume_info->main_head_end); + fprintf(stream, "CODESTREAM\t%d\n", volume_info->codestream_size); + fprintf(stream, "Num_tile Start_pos End_header End_pos Distotile Nbpix Ratio\n"); + for (tileno = 0; tileno < (volume_info->tw * volume_info->th * volume_info->tl); tileno++) { + fprintf(stream, "%4d\t%9d\t%9d\t%9d\t%9e\t%9d\t%9e\n", + volume_info->tile[tileno].num_tile, + volume_info->tile[tileno].start_pos, + volume_info->tile[tileno].end_header, + volume_info->tile[tileno].end_pos, + volume_info->tile[tileno].distotile, volume_info->tile[tileno].nbpix, + volume_info->tile[tileno].distotile / volume_info->tile[tileno].nbpix); + } + + for (tileno = 0; tileno < (volume_info->tw * volume_info->th * volume_info->tl); tileno++) { + int start_pos, end_pos; + double disto = 0; + pack_nb = 0; + if (volume_info->prog == LRCP) { /* LRCP */ + fprintf(stream, "pack_nb tileno layno resno compno precno start_pos end_pos disto\n"); + for (layno = 0; layno < volume_info->layer; layno++) { + for (resno = 0; resno < volume_info->decomposition[0] + 1; resno++) { + for (compno = 0; compno < volume_info->comp; compno++) { + int prec_max = volume_info->tile[tileno].prctno[0][resno] * volume_info->tile[tileno].prctno[1][resno] * volume_info->tile[tileno].prctno[2][resno]; + for (precno = 0; precno < prec_max; precno++) { + start_pos = volume_info->tile[tileno].packet[pack_nb].start_pos; + end_pos = volume_info->tile[tileno].packet[pack_nb].end_pos; + disto = volume_info->tile[tileno].packet[pack_nb].disto; + fprintf(stream, "%4d %6d %7d %5d %6d %6d %9d %9d %8e\n",pack_nb, tileno, layno, resno, compno, precno, start_pos, end_pos, disto); + total_disto += disto; + pack_nb++; + } + } + } + } + } /* LRCP */ + else if (volume_info->prog == RLCP) { /* RLCP */ + /* + fprintf(stream, "pack_nb tileno resno layno compno precno start_pos end_pos disto"); + */ + for (resno = 0; resno < volume_info->decomposition[0] + 1; resno++) { + for (layno = 0; layno < volume_info->layer; layno++) { + for (compno = 0; compno < volume_info->comp; compno++) { + int prec_max = volume_info->tile[tileno].prctno[0][resno] * volume_info->tile[tileno].prctno[1][resno]* volume_info->tile[tileno].prctno[2][resno]; + for (precno = 0; precno < prec_max; precno++) { + start_pos = volume_info->tile[tileno].packet[pack_nb].start_pos; + end_pos = volume_info->tile[tileno].packet[pack_nb].end_pos; + disto = volume_info->tile[tileno].packet[pack_nb].disto; + fprintf(stream, "%4d %6d %5d %7d %6d %6d %9d %9d %8e\n", + pack_nb, tileno, resno, layno, compno, precno, start_pos, end_pos, disto); + total_disto += disto; + pack_nb++; + } + } + } + } + } /* RLCP */ + else if (volume_info->prog == RPCL) { /* RPCL */ + /* + fprintf(stream, "\npack_nb tileno resno precno compno layno start_pos end_pos disto\n"); + */ + for (resno = 0; resno < volume_info->decomposition[0] + 1; resno++) { + /* I suppose components have same XRsiz, YRsiz */ + //int x0 = volume_info->tile_Ox + tileno - (int)floor( (float)tileno/(float)volume_info->tw ) * volume_info->tw * volume_info->tile_x; + //int y0 = volume_info->tile_Ox + (int)floor( (float)tileno/(float)volume_info->tw ) * volume_info->tile_y; + int x0 = volume_info->tile_Ox + (int)floor( (float)tileno/(float)volume_info->tw ) * volume_info->tile_x; + int y0 = volume_info->tile_Oy + (int)floor( (float)tileno/(float)volume_info->th ) * volume_info->tile_y; + int z0 = volume_info->tile_Ox + (int)floor( (float)tileno/(float)volume_info->tl ) * volume_info->tile_z; + int x1 = x0 + volume_info->tile_x; + int y1 = y0 + volume_info->tile_y; + int z1 = z0 + volume_info->tile_z; + for(z = z0; z < z1; z++) { + for(y = y0; y < y1; y++) { + for(x = x0; x < x1; x++) { + for (compno = 0; compno < volume_info->comp; compno++) { + int prec_max = volume_info->tile[tileno].prctno[0][resno] * volume_info->tile[tileno].prctno[1][resno] * volume_info->tile[tileno].prctno[2][resno]; + for (precno = 0; precno < prec_max; precno++) { + int pcnx = volume_info->tile[tileno].prctno[0][resno]; + int pcx = (int) pow( 2, volume_info->tile[tileno].prctsiz[0][resno] + volume_info->decomposition[0] - resno ); + int pcy = (int) pow( 2, volume_info->tile[tileno].prctsiz[1][resno] + volume_info->decomposition[1] - resno ); + int pcz = (int) pow( 2, volume_info->tile[tileno].prctsiz[2][resno] + volume_info->decomposition[2] - resno ); + int precno_x = precno - (int) floor( (float)precno/(float)pcnx ) * pcnx; + int precno_y = (int) floor( (float)precno/(float)pcnx ); + if (precno_y*pcy == y ) { + if (precno_x*pcx == x ) { + for (layno = 0; layno < volume_info->layer; layno++) { + start_pos = volume_info->tile[tileno].packet[pack_nb].start_pos; + end_pos = volume_info->tile[tileno].packet[pack_nb].end_pos; + disto = volume_info->tile[tileno].packet[pack_nb].disto; + fprintf(stream, "%4d %6d %5d %6d %6d %7d %9d %9d %8e\n", + pack_nb, tileno, resno, precno, compno, layno, start_pos, end_pos, disto); + total_disto += disto; + pack_nb++; + } + } + } + } /* precno */ + } /* compno */ + } /* x = x0..x1 */ + } /* y = y0..y1 */ + } /* z = z0..z1 */ + } /* resno */ + } /* RPCL */ + else if (volume_info->prog == PCRL) { /* PCRL */ + /* I suppose components have same XRsiz, YRsiz */ + int x0 = volume_info->tile_Ox + tileno - (int)floor( (float)tileno/(float)volume_info->tw ) * volume_info->tw * volume_info->tile_x; + int y0 = volume_info->tile_Ox + (int)floor( (float)tileno/(float)volume_info->tw ) * volume_info->tile_y; + int z0 = volume_info->tile_Oz + (int)floor( (float)tileno/(float)volume_info->tw ) * volume_info->tile_z; + int x1 = x0 + volume_info->tile_x; + int y1 = y0 + volume_info->tile_y; + int z1 = z0 + volume_info->tile_z; + /* + fprintf(stream, "\npack_nb tileno precno compno resno layno start_pos end_pos disto\n"); + */ + for(z = z0; z < z1; z++) { + for(y = y0; y < y1; y++) { + for(x = x0; x < x1; x++) { + for (compno = 0; compno < volume_info->comp; compno++) { + for (resno = 0; resno < volume_info->decomposition[0] + 1; resno++) { + int prec_max = volume_info->tile[tileno].prctno[0][resno] * volume_info->tile[tileno].prctno[1][resno]; + for (precno = 0; precno < prec_max; precno++) { + int pcnx = volume_info->tile[tileno].prctno[0][resno]; + int pcx = (int) pow( 2, volume_info->tile[tileno].prctsiz[0][resno] + volume_info->decomposition[0] - resno ); + int pcy = (int) pow( 2, volume_info->tile[tileno].prctsiz[1][resno] + volume_info->decomposition[1] - resno ); + int pcz = (int) pow( 2, volume_info->tile[tileno].prctsiz[2][resno] + volume_info->decomposition[2] - resno ); + int precno_x = precno - (int) floor( (float)precno/(float)pcnx ) * pcnx; + int precno_y = (int) floor( (float)precno/(float)pcnx ); + int precno_z = (int) floor( (float)precno/(float)pcnx ); + if (precno_z*pcz == z ) { + if (precno_y*pcy == y ) { + if (precno_x*pcx == x ) { + for (layno = 0; layno < volume_info->layer; layno++) { + start_pos = volume_info->tile[tileno].packet[pack_nb].start_pos; + end_pos = volume_info->tile[tileno].packet[pack_nb].end_pos; + disto = volume_info->tile[tileno].packet[pack_nb].disto; + fprintf(stream, "%4d %6d %6d %6d %5d %7d %9d %9d %8e\n", + pack_nb, tileno, precno, compno, resno, layno, start_pos, end_pos, disto); + total_disto += disto; + pack_nb++; + } + } + } + } + } /* precno */ + } /* resno */ + } /* compno */ + } /* x = x0..x1 */ + } /* y = y0..y1 */ + } + } /* PCRL */ + else { /* CPRL */ + /* + fprintf(stream, "\npack_nb tileno compno precno resno layno start_pos end_pos disto\n"); + */ + for (compno = 0; compno < volume_info->comp; compno++) { + /* I suppose components have same XRsiz, YRsiz */ + int x0 = volume_info->tile_Ox + tileno - (int)floor( (float)tileno/(float)volume_info->tw ) * volume_info->tw * volume_info->tile_x; + int y0 = volume_info->tile_Ox + (int)floor( (float)tileno/(float)volume_info->tw ) * volume_info->tile_y; + int z0 = volume_info->tile_Oz + (int)floor( (float)tileno/(float)volume_info->tw ) * volume_info->tile_z; + int x1 = x0 + volume_info->tile_x; + int y1 = y0 + volume_info->tile_y; + int z1 = z0 + volume_info->tile_z; + for(z = z0; z < z1; z++) { + for(y = y0; y < y1; y++) { + for(x = x0; x < x1; x++) { + for (resno = 0; resno < volume_info->decomposition[0] + 1; resno++) { + int prec_max = volume_info->tile[tileno].prctno[0][resno] * volume_info->tile[tileno].prctno[1][resno] * volume_info->tile[tileno].prctno[2][resno]; + for (precno = 0; precno < prec_max; precno++) { + int pcnx = volume_info->tile[tileno].prctno[0][resno]; + int pcny = volume_info->tile[tileno].prctno[1][resno]; + int pcx = (int) pow( 2, volume_info->tile[tileno].prctsiz[0][resno] + volume_info->decomposition[0] - resno ); + int pcy = (int) pow( 2, volume_info->tile[tileno].prctsiz[1][resno] + volume_info->decomposition[1] - resno ); + int pcz = (int) pow( 2, volume_info->tile[tileno].prctsiz[2][resno] + volume_info->decomposition[2] - resno ); + int precno_x = precno - (int) floor( (float)precno/(float)pcnx ) * pcnx; + int precno_y = (int) floor( (float)precno/(float)pcnx ); + int precno_z = 0; /*???*/ + if (precno_z*pcz == z ) { + if (precno_y*pcy == y ) { + if (precno_x*pcx == x ) { + for (layno = 0; layno < volume_info->layer; layno++) { + start_pos = volume_info->tile[tileno].packet[pack_nb].start_pos; + end_pos = volume_info->tile[tileno].packet[pack_nb].end_pos; + disto = volume_info->tile[tileno].packet[pack_nb].disto; + fprintf(stream, "%4d %6d %6d %6d %5d %7d %9d %9d %8e\n", + pack_nb, tileno, compno, precno, resno, layno, start_pos, end_pos, disto); + total_disto += disto; + pack_nb++; + } + } + } + } + } /* precno */ + } /* resno */ + } /* x = x0..x1 */ + } /* y = y0..y1 */ + } /* z = z0..z1 */ + } /* comno */ + } /* CPRL */ + } /* tileno */ + + fprintf(stream, "SE_MAX\t%8e\n", volume_info->D_max); /* SE max */ + fprintf(stream, "SE_TOTAL\t%.8e\n", total_disto); /* SE totale */ + + + fclose(stream); + + return 1; +} + +bool j3d_encode(opj_j3d_t *j3d, opj_cio_t *cio, opj_volume_t *volume, char *index) { + int tileno, compno; + opj_volume_info_t *volume_info = NULL; + opj_cp_t *cp = NULL; + opj_tcd_t *tcd = NULL; /* TCD component */ + + j3d->cio = cio; + j3d->volume = volume; + cp = j3d->cp; + + /*j3d_dump_volume(stdout, volume); + j3d_dump_cp(stdout, volume, cp);*/ + + /* INDEX >> */ + volume_info = j3d->volume_info; + if (volume_info && cp->index_on) { + volume_info->index_on = cp->index_on; + volume_info->tile = (opj_tile_info_t *) opj_malloc(cp->tw * cp->th * cp->tl * sizeof(opj_tile_info_t)); + volume_info->volume_w = volume->x1 - volume->x0; + volume_info->volume_h = volume->y1 - volume->y0; + volume_info->volume_l = volume->z1 - volume->z0; + volume_info->prog = (&cp->tcps[0])->prg; + volume_info->tw = cp->tw; + volume_info->th = cp->th; + volume_info->tl = cp->tl; + volume_info->tile_x = cp->tdx; /* new version parser */ + volume_info->tile_y = cp->tdy; /* new version parser */ + volume_info->tile_z = cp->tdz; /* new version parser */ + volume_info->tile_Ox = cp->tx0; /* new version parser */ + volume_info->tile_Oy = cp->ty0; /* new version parser */ + volume_info->tile_Oz = cp->tz0; /* new version parser */ + volume_info->transform_format = cp->transform_format; + volume_info->encoding_format = cp->encoding_format; + volume_info->comp = volume->numcomps; + volume_info->layer = (&cp->tcps[0])->numlayers; + volume_info->decomposition[0] = (&cp->tcps[0])->tccps->numresolution[0] - 1; + volume_info->decomposition[1] = (&cp->tcps[0])->tccps->numresolution[1] - 1; + volume_info->decomposition[2] = (&cp->tcps[0])->tccps->numresolution[2] - 1; + volume_info->D_max = 0; /* ADD Marcela */ + } + /* << INDEX */ + + j3d_write_soc(j3d); + j3d_write_siz(j3d); + if (j3d->cinfo->codec_format == CODEC_J3D) { + j3d_write_cap(j3d); + j3d_write_zsi(j3d); + } + j3d_write_cod(j3d); + j3d_write_qcd(j3d); + for (compno = 0; compno < volume->numcomps; compno++) { + opj_tcp_t *tcp = &cp->tcps[0]; + if (tcp->tccps[compno].roishift) + j3d_write_rgn(j3d, compno, 0); + } + /*Optional 15444-2 markers*/ + if (j3d->cp->tcps->tccps[0].atk != NULL) + j3d_write_atk(j3d); + if (j3d->volume->comps[0].dcoffset != 0) + j3d_write_dco(j3d); + + if (j3d->cp->transform_format != TRF_2D_DWT || j3d->cp->encoding_format != ENCOD_2EB) + j3d_write_com(j3d); + + /* INDEX >> */ + if(volume_info && volume_info->index_on) { + volume_info->main_head_end = cio_tell(cio) - 1; + } + /* << INDEX */ + + /* create the tile encoder */ + tcd = tcd_create(j3d->cinfo); + + /* encode each tile */ + for (tileno = 0; tileno < cp->tw * cp->th * cp->tl; tileno++) { + opj_event_msg(j3d->cinfo, EVT_INFO, "tile number %d / %d\n", tileno + 1, cp->tw * cp->th * cp->tl); + + j3d->curtileno = tileno; + + /* initialisation before tile encoding */ + if (tileno == 0) { + tcd_malloc_encode(tcd, volume, cp, j3d->curtileno); + } else { + tcd_init_encode(tcd, volume, cp, j3d->curtileno); + } + + /* INDEX >> */ + if(volume_info && volume_info->index_on) { + volume_info->tile[j3d->curtileno].num_tile = j3d->curtileno; + volume_info->tile[j3d->curtileno].start_pos = cio_tell(cio) + j3d->pos_correction; + } + /* << INDEX */ + + j3d_write_sot(j3d); + + for (compno = 1; compno < volume->numcomps; compno++) { + j3d_write_coc(j3d, compno); + j3d_write_qcc(j3d, compno); + } + + if (cp->tcps[tileno].numpocs) { + j3d_write_poc(j3d); + } + j3d_write_sod(j3d, tcd); //--> tcd_encode_tile + + /* INDEX >> */ + if(volume_info && volume_info->index_on) { + volume_info->tile[j3d->curtileno].end_pos = cio_tell(cio) + j3d->pos_correction - 1; + } + /* << INDEX */ + } + + /* destroy the tile encoder */ + tcd_free_encode(tcd); + tcd_destroy(tcd); + + j3d_write_eoc(j3d); + + /* Creation of the index file */ + if(volume_info && volume_info->index_on) { + if(!j3d_create_index(j3d, cio, volume_info, index)) { + opj_event_msg(j3d->cinfo, EVT_ERROR, "failed to create index file %s\n", index); + return false; + } + } + + return true; +} + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/jp3d.h b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/jp3d.h new file mode 100644 index 0000000..dc6ba14 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/jp3d.h @@ -0,0 +1,518 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * Copyright (c) 2006, Mónica Díez García, Image Processing Laboratory, University of Valladolid, Spain + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __J3D_H +#define __J3D_H +/** +@file j3d.h +@brief The JPEG-2000 Codestream Reader/Writer (J3D) + +The functions in J3D.C have for goal to read/write the several parts of the codestream: markers and data. +*/ + +/** @defgroup J3D J3D - JPEG-2000 codestream reader/writer */ +/*@{*/ + +#define J3D_CP_CSTY_PRT 0x01 +#define J3D_CP_CSTY_SOP 0x02 +#define J3D_CP_CSTY_EPH 0x04 +#define J3D_CCP_CSTY_PRT 0x01 +/** Table A-8 */ +#define J3D_CCP_CBLKSTY_LAZY 0x01 /* Selective arithmetic coding bypass */ +#define J3D_CCP_CBLKSTY_RESET 0x02 /* Reset context probabilities on coding pass boundaries */ +#define J3D_CCP_CBLKSTY_TERMALL 0x04 /* Termination on each coding pass */ +#define J3D_CCP_CBLKSTY_VSC 0x08 /* Vertically causal context, add also hook for switching off and on 3D context models */ +#define J3D_CCP_CBLKSTY_PTERM 0x10 /* Predictable termination */ +#define J3D_CCP_CBLKSTY_SEGSYM 0x20 /* Segmentation symbols are used */ +#define J3D_CCP_CBLKSTY_3DCTXT 0x40 /* 3D context models (3D-EBCOT) vs 2D context models */ + +#define J3D_CCP_QNTSTY_NOQNT 0 /* Quantization style : no quantization */ +#define J3D_CCP_QNTSTY_SIQNT 1 /* Quantization style : scalar derived (values signalled only in LLL subband) */ +#define J3D_CCP_QNTSTY_SEQNT 2 /* Quantization style : scalar expounded (values signalled for each subband) */ + +/* ----------------------------------------------------------------------- */ + +#define J3D_MS_SOC 0xff4f /**< SOC marker value */ +#define J3D_MS_SOT 0xff90 /**< SOT marker value */ +#define J3D_MS_SOD 0xff93 /**< SOD marker value */ +#define J3D_MS_EOC 0xffd9 /**< EOC marker value */ +#define J3D_MS_CAP 0xff50 /**< CAP marker value */ +#define J3D_MS_SIZ 0xff51 /**< SIZ marker value */ +#define J3D_MS_ZSI 0xff54 /**< ZSI marker value */ +#define J3D_MS_COD 0xff52 /**< COD marker value */ +#define J3D_MS_COC 0xff53 /**< COC marker value */ +#define J3D_MS_RGN 0xff5e /**< RGN marker value */ +#define J3D_MS_QCD 0xff5c /**< QCD marker value */ +#define J3D_MS_QCC 0xff5d /**< QCC marker value */ +#define J3D_MS_POC 0xff5f /**< POC marker value */ +#define J3D_MS_TLM 0xff55 /**< TLM marker value */ +#define J3D_MS_PLM 0xff57 /**< PLM marker value */ +#define J3D_MS_PLT 0xff58 /**< PLT marker value */ +#define J3D_MS_PPM 0xff60 /**< PPM marker value */ +#define J3D_MS_PPT 0xff61 /**< PPT marker value */ +#define J3D_MS_SOP 0xff91 /**< SOP marker value */ +#define J3D_MS_EPH 0xff92 /**< EPH marker value */ +#define J3D_MS_CRG 0xff63 /**< CRG marker value */ +#define J3D_MS_COM 0xff64 /**< COM marker value */ +//15444-2 +#define J3D_MS_DCO 0xff70 /**< DCO marker value */ +#define J3D_MS_VMS 0xff71 /**< VMS marker value */ +#define J3D_MS_DFS 0xff72 /**< DFS marker value */ +#define J3D_MS_ADS 0xff73 /**< ADS marker value */ +#define J3D_MS_ATK 0xff79 /**< ATK marker value */ +#define J3D_MS_CBD 0xff78 /**< CBD marker value */ +#define J3D_MS_MCT 0xff74 /**< MCT marker value */ +#define J3D_MS_MCC 0xff75 /**< MCC marker value */ +#define J3D_MS_MCO 0xff77 /**< MCO marker value */ +#define J3D_MS_NLT 0xff76 /**< NLT marker value */ +#define J3D_MS_QPD 0xff5a /**< QPD marker value */ +#define J3D_MS_QPC 0xff5b /**< QPC marker value */ + +/* ----------------------------------------------------------------------- */ +/* Capability RSIZ parameter, extended */ +#define J3D_RSIZ_BASIC 0x0000 + +#define J3D_RSIZ_DCO 0x8001 /* Required */ +#define J3D_RSIZ_VSQNT 0x8002 +#define J3D_RSIZ_TCQNT 0x8004 +#define J3D_RSIZ_VMASK 0x8008 +#define J3D_RSIZ_SSOVL 0x8010 +#define J3D_RSIZ_ADECS 0x8020 +#define J3D_RSIZ_ATK 0x8040 /*Required*/ +#define J3D_RSIZ_SSYMK 0x8080 +#define J3D_RSIZ_MCT 0x8100 /*Not compatible with DCO*/ +#define J3D_RSIZ_NLT 0x8200 /*Required*/ +#define J3D_RSIZ_ASHAP 0x8400 +#define J3D_RSIZ_PRQNT 0x8800 + +#define J3D_CAP_10 0x00400000 +/* Arbitrary transformation kernel, 15444-2 */ +#define J3D_ATK_IRR 0 +#define J3D_ATK_REV 1 +#define J3D_ATK_ARB 0 +#define J3D_ATK_WS 1 +#define J3D_ATK_CON 0 +/* ----------------------------------------------------------------------- */ + +/** +Values that specify the status of the decoding process when decoding the main header. +These values may be combined with a | operator. +*/ +typedef enum J3D_STATUS { + /**< a SOC marker is expected */ + J3D_STATE_MHSOC = 0x0001, + /**< a SIZ marker is expected */ + J3D_STATE_MHSIZ = 0x0002, + /**< the decoding process is in the main header */ + J3D_STATE_MH = 0x0004, + /**< the decoding process is in a tile part header and expects a SOT marker */ + J3D_STATE_TPHSOT = 0x0008, + /**< the decoding process is in a tile part header */ + J3D_STATE_TPH = 0x0010, + /**< the EOC marker has just been read */ + J3D_STATE_MT = 0x0020, + /**< the decoding process must not expect a EOC marker because the codestream is truncated */ + J3D_STATE_NEOC = 0x0040 +} J3D_STATUS; + + + +/** +Arbitrary transformation kernel +*/ +typedef struct opj_atk { +/** index of wavelet kernel */ + int index; +/** Numerical type of scaling factor and lifting step parameters */ + int coeff_typ; +/** Wavelet filter category */ + int filt_cat; +/** Wavelet transformation type (REV/IRR) */ + int wt_typ; +/** Initial odd/even subsequence */ + int minit; +/** Boundary extension method (constant CON / whole-sample symmetric WS) */ + int exten; +/** Scaling factor. Only for wt_typ=IRR */ + double Katk; +/** Number of lifting steps */ + int Natk; +/** Offset for lifting step s. Only for filt_cat=ARB */ + int Oatk[256]; +/** Base 2 scaling exponent for lifting step s. Only for wt_typ=REV */ + int Eatk[256]; +/** Additive residue for lifting step s. Only for wt_typ=REV */ + int Batk[256]; +/** Number of lifting coefficients signaled for lifting step s */ + int LCatk[256]; +/** Lifting coefficient k for lifting step s */ + double Aatk[256][256]; +} opj_atk_t; + + +/** +Quantization stepsize +*/ +typedef struct opj_stepsize { +/** exponent */ + int expn; +/** mantissa */ + int mant; +} opj_stepsize_t; + +/** +Tile-component coding parameters +*/ +typedef struct opj_tccp { + /** coding style */ + int csty; + /** number of resolutions of x, y and z-axis */ + int numresolution[3]; + /** code-blocks width height & depth*/ + int cblk[3]; + /** code-block coding style */ + int cblksty; + /** 0: no ATK (only 9-7 or 5-3) 1: ATK defined WT*/ + int atk_wt[3]; + /** Arbitrary transformation kernel (15444-2)*/ + opj_atk_t *atk; + /** DWT identifier for x, y and z-axis (0:WT9-7 1:WT5-3 >1:WT-atk->index) */ + int dwtid[3]; + /** reversible/irreversible wavelet transfomation (0:irrev 1:reversible)*/ + int reversible; + /** quantisation style */ + int qntsty; + /** stepsizes used for quantization */ + opj_stepsize_t stepsizes[J3D_MAXBANDS]; + /** number of guard bits. Table A28 de 15444-1*/ + int numgbits; + /** Region Of Interest shift */ + int roishift; + /** precinct width heigth & depth*/ + int prctsiz[3][J3D_MAXRLVLS]; +} opj_tccp_t; + +/** +Tile coding parameters : coding/decoding parameters common to all tiles +(information like COD, COC in main header) +*/ +typedef struct opj_tcp { +/** 1 : first part-tile of a tile */ + int first; + /** coding style */ + int csty; + /** progression order */ + OPJ_PROG_ORDER prg; + /** number of layers */ + int numlayers; + /** multi-component transform identifier */ + int mct; + /** rates of layers */ + float rates[100]; + /** number of progression order changes */ + int numpocs; + /** indicates if a POC marker has been used O:NO, 1:YES */ + int POC; + /** progression order changes */ + opj_poc_t pocs[J3D_MAXRLVLS - 1]; + /** add fixed_quality */ + float distoratio[100]; + /** tile-component coding parameters */ + opj_tccp_t *tccps; +/** packet header store there for futur use in t2_decode_packet */ + unsigned char *ppt_data; + /** pointer remaining on the first byte of the first header if ppt is used */ + unsigned char *ppt_data_first; + /** If ppt == 1 --> there was a PPT marker for the present tile */ + int ppt; + /** used in case of multiple marker PPT (number of info already stored) */ + int ppt_store; + int ppt_len; +} opj_tcp_t; + +/** +Coding parameters +*/ +typedef struct opj_cp { +/** transform format 0: 2DWT, 1: 2D1P, 2: 3DWT, 3: 3RLS */ + OPJ_TRANSFORM transform_format; + /** entropy coding format 0: 2EB, 1: 3EB, 2: 2GR, 3: 3GR, 4: GRI*/ + OPJ_ENTROPY_CODING encoding_format; + /** allocation by rate/distortion */ + int disto_alloc; + /** allocation by fixed layer */ + int fixed_alloc; + /** add fixed_quality */ + int fixed_quality; + /** Rsiz: capabilities */ + int rsiz; + /** if != 0, then original dimension divided by 2^(reduce); if == 0 or not used, volume is decoded to the full resolution */ + int reduce[3]; + /** if != 0, then only the first "layer" layers are decoded; if == 0 or not used, all the quality layers are decoded */ + int layer; + /** 0 = no index || 1 = index */ + int index_on; + /** Big-Endian/Little-endian order */ + int bigendian; + /** XTOsiz */ + int tx0; + /** YTOsiz */ + int ty0; + /** ZTOsiz */ + int tz0; + /** XTsiz */ + int tdx; + /** YTsiz */ + int tdy; + /** ZTsiz */ + int tdz; + /** comment for coding */ + char *comment; + /** number of tiles in width, heigth and depth */ + int tw; + int th; + int tl; + /** ID number of the tiles present in the codestream */ + int *tileno; + /** size of the vector tileno */ + int tileno_size; + /** tile coding parameters */ + opj_tcp_t *tcps; + /** fixed layer */ + int *matrice; + + /** packet header store there for futur use in t2_decode_packet */ + unsigned char *ppm_data; + /** pointer remaining on the first byte of the first header if ppm is used */ + unsigned char *ppm_data_first; + /** if ppm == 1 --> there was a PPM marker for the present tile */ + int ppm; + /** use in case of multiple marker PPM (number of info already store) */ + int ppm_store; + /** use in case of multiple marker PPM (case on non-finished previous info) */ + int ppm_previous; + int ppm_len; +} opj_cp_t; + +/** +Information concerning a packet inside tile +*/ +typedef struct opj_packet_info { + /** start position */ + int start_pos; + /** end position */ + int end_pos; + /** distorsion introduced */ + double disto; +} opj_packet_info_t; + +/** +Index structure : information regarding tiles inside volume +*/ +typedef struct opj_tile_info { + /** value of thresh for each layer by tile cfr. Marcela */ + double *thresh; + /** number of tile */ + int num_tile; + /** start position */ + int start_pos; + /** end position of the header */ + int end_header; + /** end position */ + int end_pos; + /** precinct number for each resolution level (width, heigth and depth) */ + int prctno[3][J3D_MAXRLVLS]; + /** precinct size (in power of 2), in X for each resolution level */ + int prctsiz[3][J3D_MAXRLVLS]; + /** information concerning packets inside tile */ + opj_packet_info_t *packet; + + /** add fixed_quality */ + int nbpix; + /** add fixed_quality */ + double distotile; +} opj_tile_info_t; + +/** +Index structure +*/ +typedef struct opj_volume_info { + + /** transform format 0: 2DWT, 1: 2D1P, 2: 3DWT, 3: 3RLS */ + OPJ_TRANSFORM transform_format; + /** output file format 0: 2EB, 1: 3EB, 2: 2GR, 3: 3GR, 4: GRI*/ + OPJ_ENTROPY_CODING encoding_format; /** 0 = no index || 1 = index */ + int index_on; + /** 0 = wt 9-7 || 1 = wt 5-3 || >=2 wt atk defined */ + int dwtid[3]; + /** maximum distortion reduction on the whole volume (add for Marcela) */ + double D_max; + /** packet number */ + int num; + /** writing the packet in the index with t2_encode_packets */ + int index_write; + /** volume width, height and depth */ + int volume_w; + int volume_h; + int volume_l; + /** progression order */ + OPJ_PROG_ORDER prog; + /** tile size in x, y and z */ + int tile_x; + int tile_y; + int tile_z; + /** tile origin in x, y and z */ + int tile_Ox; + int tile_Oy; + int tile_Oz; + /** number of tiles in X, Y and Z */ + int tw; + int th; + int tl; + /** component numbers */ + int comp; + /** number of layer */ + int layer; + /** number of decomposition in X, Y and Z*/ + int decomposition[3]; + /** DC offset (15444-2) */ + int dcoffset; + /** main header position */ + int main_head_end; + /** codestream's size */ + int codestream_size; + /** information regarding tiles inside volume */ + opj_tile_info_t *tile; +} opj_volume_info_t; + +/** +JPEG-2000 codestream reader/writer +*/ +typedef struct opj_j3d { + /** codec context */ + opj_common_ptr cinfo; + /** locate in which part of the codestream the decoder is (main header, tile header, end) */ + int state; + /** number of the tile curently concern by coding/decoding */ + int curtileno; + /** locate the position of the end of the tile in the codestream, used to detect a truncated codestream (in j3d_read_sod) */ + unsigned char *eot; + /** locate the start position of the SOT marker of the current coded tile: */ + int sot_start; + /* after encoding the tile, a jump (in j3d_write_sod) is done to the SOT marker to store the value of its length. */ + int sod_start; + /** as the J3D-file is written in several parts during encoding, it enables to make the right correction in position return by cio_tell */ + int pos_correction; + /** array used to store the data of each tile */ + unsigned char **tile_data; + /** array used to store the length of each tile */ + int *tile_len; + + /** decompression only : store decoding parameters common to all tiles */ + opj_tcp_t *default_tcp; + /** pointer to the encoded / decoded volume */ + opj_volume_t *volume; + /** pointer to the coding parameters */ + opj_cp_t *cp; + /** helper used to write the index file */ + opj_volume_info_t *volume_info; + /** pointer to the byte i/o stream */ + opj_cio_t *cio; +} opj_j3d_t; + +/** @name Funciones generales */ +/*@{*/ +/* ----------------------------------------------------------------------- */ +/** +Creates a J3D decompression structure +@param cinfo Codec context info +@return Returns a handle to a J3D decompressor if successful, returns NULL otherwise +*/ +opj_j3d_t* j3d_create_decompress(opj_common_ptr cinfo); +/** +Destroy a J3D decompressor handle +@param j3d J3D decompressor handle to destroy +*/ +void j3d_destroy_decompress(opj_j3d_t *j3d); +/** +Setup the decoder decoding parameters using user parameters. +Decoding parameters are returned in j3d->cp. +@param j3d J3D decompressor handle +@param parameters decompression parameters +*/ +void j3d_setup_decoder(opj_j3d_t *j3d, opj_dparameters_t *parameters); +/** +Decode an volume from a JPEG-2000 codestream +@param j3d J3D decompressor handle +@param cio Input buffer stream +@return Returns a decoded volume if successful, returns NULL otherwise +*/ +opj_volume_t* j3d_decode(opj_j3d_t *j3d, opj_cio_t *cio); +/** +Decode an volume form a JPT-stream (JPEG 2000, JPIP) +@param j3d J3D decompressor handle +@param cio Input buffer stream +@return Returns a decoded volume if successful, returns NULL otherwise +*/ +opj_volume_t* j3d_decode_jpt_stream(opj_j3d_t *j3d, opj_cio_t *cio); +/** +Creates a J3D compression structure +@param cinfo Codec context info +@return Returns a handle to a J3D compressor if successful, returns NULL otherwise +*/ +opj_j3d_t* j3d_create_compress(opj_common_ptr cinfo); +/** +Destroy a J3D compressor handle +@param j3d J3D compressor handle to destroy +*/ +void j3d_destroy_compress(opj_j3d_t *j3d); +/** +Setup the encoder parameters using the current volume and using user parameters. +Coding parameters are returned in j3d->cp. +@param j3d J3D compressor handle +@param parameters compression parameters +@param volume input filled volume +*/ +void j3d_setup_encoder(opj_j3d_t *j3d, opj_cparameters_t *parameters, opj_volume_t *volume); +/** +Encode an volume into a JPEG-2000 codestream +@param j3d J3D compressor handle +@param cio Output buffer stream +@param volume Volume to encode +@param index Name of the index file if required, NULL otherwise +@return Returns true if successful, returns false otherwise +*/ +bool j3d_encode(opj_j3d_t *j3d, opj_cio_t *cio, opj_volume_t *volume, char *index); +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __J3D_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/jp3d_lib.c b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/jp3d_lib.c new file mode 100644 index 0000000..5002800 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/jp3d_lib.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef _WIN32 +#include +#else +#include +#include +#include +#endif /* _WIN32 */ +#include "opj_includes.h" + +double opj_clock() { +#ifdef _WIN32 + /* WIN32: use QueryPerformance (very accurate) */ + LARGE_INTEGER freq , t ; + /* freq is the clock speed of the CPU */ + QueryPerformanceFrequency(&freq) ; + /* cout << "freq = " << ((double) freq.QuadPart) << endl; */ + /* t is the high resolution performance counter (see MSDN) */ + QueryPerformanceCounter ( & t ) ; + return ( t.QuadPart /(double) freq.QuadPart ) ; +#else + /* Unix or Linux: use resource usage */ + struct rusage t; + double procTime; + /* (1) Get the rusage data structure at this moment (man getrusage) */ + getrusage(0,&t); + /* (2) What is the elapsed time ? - CPU time = User time + System time */ + /* (2a) Get the seconds */ + procTime = t.ru_utime.tv_sec + t.ru_stime.tv_sec; + /* (2b) More precisely! Get the microseconds part ! */ + return ( procTime + (t.ru_utime.tv_usec + t.ru_stime.tv_usec) * 1e-6 ) ; +#endif /* _WIN32 */ +} + +void* opj_malloc( size_t size ) { + void *memblock = malloc(size); + if(memblock) { + memset(memblock, 0, size); + } + return memblock; +} + +void* opj_realloc( void *memblock, size_t size ) { + return realloc(memblock, size); +} + +void opj_free( void *memblock ) { + free(memblock); +} + + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/jp3d_lib.h b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/jp3d_lib.h new file mode 100644 index 0000000..1ac7612 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/jp3d_lib.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __J3D_LIB_H +#define __J3D_LIB_H +/** +@file jp3d_lib.h +@brief Internal functions + +The functions in JP3D_LIB.C are internal utilities mainly used for memory management. +*/ + +/** @defgroup MISC MISC - Miscellaneous internal functions */ +/*@{*/ + +/** @name Funciones generales */ +/*@{*/ +/* ----------------------------------------------------------------------- */ + +/** +Difference in successive opj_clock() calls tells you the elapsed time +@return Returns time in seconds +*/ +double opj_clock(); + +/** +Allocate a memory block with elements initialized to 0 +@param size Bytes to allocate +@return Returns a void pointer to the allocated space, or NULL if there is insufficient memory available +*/ +void* opj_malloc( size_t size ); + +/** +Reallocate memory blocks. +@param memblock Pointer to previously allocated memory block +@param size New size in bytes +@return Returns a void pointer to the reallocated (and possibly moved) memory block +*/ +void* opj_realloc( void *memblock, size_t size ); + +/** +Deallocates or frees a memory block. +@param memblock Previously allocated memory block to be freed +*/ +void opj_free( void *memblock ); + +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __J3D_LIB_H */ + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/mct.c b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/mct.c new file mode 100644 index 0000000..f41c9ab --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/mct.c @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "opj_includes.h" + +/* */ +/* This table contains the norms of the basis function of the reversible MCT. */ +/* */ +static const double mct_norms[3] = { 1.732, .8292, .8292 }; + +/* */ +/* This table contains the norms of the basis function of the irreversible MCT. */ +/* */ +static const double mct_norms_real[3] = { 1.732, 1.805, 1.573 }; + +/* */ +/* Foward reversible MCT. */ +/* */ +void mct_encode(int *c0, int *c1, int *c2, int n) { + int i; + for (i = 0; i < n; i++) { + int r, g, b, y, u, v; + r = c0[i]; + g = c1[i]; + b = c2[i]; + y = (r + (g << 1) + b) >> 2; + u = b - g; + v = r - g; + c0[i] = y; + c1[i] = u; + c2[i] = v; + } +} + +/* */ +/* Inverse reversible MCT. */ +/* */ +void mct_decode(int *c0, int *c1, int *c2, int n) { + int i; + for (i = 0; i < n; i++) { + int y, u, v, r, g, b; + y = c0[i]; + u = c1[i]; + v = c2[i]; + g = y - ((u + v) >> 2); + r = v + g; + b = u + g; + c0[i] = r; + c1[i] = g; + c2[i] = b; + } +} + +/* */ +/* Get norm of basis function of reversible MCT. */ +/* */ +double mct_getnorm(int compno) { + return mct_norms[compno]; +} + +/* */ +/* Foward irreversible MCT. */ +/* */ +void mct_encode_real(int *c0, int *c1, int *c2, int n) { + int i; + for (i = 0; i < n; i++) { + int r, g, b, y, u, v; + r = c0[i]; + g = c1[i]; + b = c2[i]; + y = fix_mul(r, 2449) + fix_mul(g, 4809) + fix_mul(b, 934); + u = -fix_mul(r, 1382) - fix_mul(g, 2714) + fix_mul(b, 4096); + v = fix_mul(r, 4096) - fix_mul(g, 3430) - fix_mul(b, 666); + c0[i] = y; + c1[i] = u; + c2[i] = v; + } +} + +/* */ +/* Inverse irreversible MCT. */ +/* */ +void mct_decode_real(int *c0, int *c1, int *c2, int n) { + int i; + for (i = 0; i < n; i++) { + int y, u, v, r, g, b; + y = c0[i]; + u = c1[i]; + v = c2[i]; + r = y + fix_mul(v, 11485); + g = y - fix_mul(u, 2819) - fix_mul(v, 5850); + b = y + fix_mul(u, 14516); + c0[i] = r; + c1[i] = g; + c2[i] = b; + } +} + +/* */ +/* Get norm of basis function of irreversible MCT. */ +/* */ +double mct_getnorm_real(int compno) { + return mct_norms_real[compno]; +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/mct.h b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/mct.h new file mode 100644 index 0000000..a7dfcfb --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/mct.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MCT_H +#define __MCT_H +/** +@file mct.h +@brief Implementation of a multi-component transforms (MCT) + +The functions in MCT.C have for goal to realize reversible and irreversible multicomponent +transform. The functions in MCT.C are used by some function in TCD.C. +*/ + +/** @defgroup MCT MCT - Implementation of a multi-component transform */ +/*@{*/ + +/** @name Funciones generales */ +/*@{*/ +/* ----------------------------------------------------------------------- */ +/** +Apply a reversible multi-component transform to an image +@param c0 Samples for red component +@param c1 Samples for green component +@param c2 Samples blue component +@param n Number of samples for each component +*/ +void mct_encode(int *c0, int *c1, int *c2, int n); +/** +Apply a reversible multi-component inverse transform to an image +@param c0 Samples for luminance component +@param c1 Samples for red chrominance component +@param c2 Samples for blue chrominance component +@param n Number of samples for each component +*/ +void mct_decode(int *c0, int *c1, int *c2, int n); +/** +Get norm of the basis function used for the reversible multi-component transform +@param compno Number of the component (0->Y, 1->U, 2->V) +@return +*/ +double mct_getnorm(int compno); + +/** +Apply an irreversible multi-component transform to an image +@param c0 Samples for red component +@param c1 Samples for green component +@param c2 Samples blue component +@param n Number of samples for each component +*/ +void mct_encode_real(int *c0, int *c1, int *c2, int n); +/** +Apply an irreversible multi-component inverse transform to an image +@param c0 Samples for luminance component +@param c1 Samples for red chrominance component +@param c2 Samples for blue chrominance component +@param n Number of samples for each component +*/ +void mct_decode_real(int *c0, int *c1, int *c2, int n); +/** +Get norm of the basis function used for the irreversible multi-component transform +@param compno Number of the component (0->Y, 1->U, 2->V) +@return +*/ +double mct_getnorm_real(int compno); +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __MCT_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/mqc.c b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/mqc.c new file mode 100644 index 0000000..e2df8e3 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/mqc.c @@ -0,0 +1,548 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "opj_includes.h" + +/** @defgroup MQC MQC - Implementation of an MQ-Coder */ +/*@{*/ + +/** @name Local static functions */ +/*@{*/ + +/** +Output a byte, doing bit-stuffing if necessary. +After a 0xff byte, the next byte must be smaller than 0x90. +@param mqc MQC handle +*/ +static void mqc_byteout(opj_mqc_t *mqc); +/** +Renormalize mqc->a and mqc->c while encoding, so that mqc->a stays between 0x8000 and 0x10000 +@param mqc MQC handle +*/ +static void mqc_renorme(opj_mqc_t *mqc); +/** +Encode the most probable symbol +@param mqc MQC handle +*/ +static void mqc_codemps(opj_mqc_t *mqc); +/** +Encode the most least symbol +@param mqc MQC handle +*/ +static void mqc_codelps(opj_mqc_t *mqc); +/** +Fill mqc->c with 1's for flushing +@param mqc MQC handle +*/ +static void mqc_setbits(opj_mqc_t *mqc); +/** +Exchange MPS with LPS +@param mqc MQC handle +@return +*/ +static int mqc_mpsexchange(opj_mqc_t *mqc); +/** +Exchange LPS with MPS +@param mqc MQC handle +@return +*/ +static int mqc_lpsexchange(opj_mqc_t *mqc); +/** +Input a byte +@param mqc MQC handle +*/ +static void mqc_bytein(opj_mqc_t *mqc); +/** +Renormalize mqc->a and mqc->c while decoding +@param mqc MQC handle +*/ +static void mqc_renormd(opj_mqc_t *mqc); + +/*@}*/ + +/*@}*/ + +/* */ +/* This array defines all the possible states for a context. */ +/* */ +static opj_mqc_state_t mqc_states[47 * 2] = { + {0x5601, 0, &mqc_states[2], &mqc_states[3]}, + {0x5601, 1, &mqc_states[3], &mqc_states[2]}, + {0x3401, 0, &mqc_states[4], &mqc_states[12]}, + {0x3401, 1, &mqc_states[5], &mqc_states[13]}, + {0x1801, 0, &mqc_states[6], &mqc_states[18]}, + {0x1801, 1, &mqc_states[7], &mqc_states[19]}, + {0x0ac1, 0, &mqc_states[8], &mqc_states[24]}, + {0x0ac1, 1, &mqc_states[9], &mqc_states[25]}, + {0x0521, 0, &mqc_states[10], &mqc_states[58]}, + {0x0521, 1, &mqc_states[11], &mqc_states[59]}, + {0x0221, 0, &mqc_states[76], &mqc_states[66]}, + {0x0221, 1, &mqc_states[77], &mqc_states[67]}, + {0x5601, 0, &mqc_states[14], &mqc_states[13]}, + {0x5601, 1, &mqc_states[15], &mqc_states[12]}, + {0x5401, 0, &mqc_states[16], &mqc_states[28]}, + {0x5401, 1, &mqc_states[17], &mqc_states[29]}, + {0x4801, 0, &mqc_states[18], &mqc_states[28]}, + {0x4801, 1, &mqc_states[19], &mqc_states[29]}, + {0x3801, 0, &mqc_states[20], &mqc_states[28]}, + {0x3801, 1, &mqc_states[21], &mqc_states[29]}, + {0x3001, 0, &mqc_states[22], &mqc_states[34]}, + {0x3001, 1, &mqc_states[23], &mqc_states[35]}, + {0x2401, 0, &mqc_states[24], &mqc_states[36]}, + {0x2401, 1, &mqc_states[25], &mqc_states[37]}, + {0x1c01, 0, &mqc_states[26], &mqc_states[40]}, + {0x1c01, 1, &mqc_states[27], &mqc_states[41]}, + {0x1601, 0, &mqc_states[58], &mqc_states[42]}, + {0x1601, 1, &mqc_states[59], &mqc_states[43]}, + {0x5601, 0, &mqc_states[30], &mqc_states[29]}, + {0x5601, 1, &mqc_states[31], &mqc_states[28]}, + {0x5401, 0, &mqc_states[32], &mqc_states[28]}, + {0x5401, 1, &mqc_states[33], &mqc_states[29]}, + {0x5101, 0, &mqc_states[34], &mqc_states[30]}, + {0x5101, 1, &mqc_states[35], &mqc_states[31]}, + {0x4801, 0, &mqc_states[36], &mqc_states[32]}, + {0x4801, 1, &mqc_states[37], &mqc_states[33]}, + {0x3801, 0, &mqc_states[38], &mqc_states[34]}, + {0x3801, 1, &mqc_states[39], &mqc_states[35]}, + {0x3401, 0, &mqc_states[40], &mqc_states[36]}, + {0x3401, 1, &mqc_states[41], &mqc_states[37]}, + {0x3001, 0, &mqc_states[42], &mqc_states[38]}, + {0x3001, 1, &mqc_states[43], &mqc_states[39]}, + {0x2801, 0, &mqc_states[44], &mqc_states[38]}, + {0x2801, 1, &mqc_states[45], &mqc_states[39]}, + {0x2401, 0, &mqc_states[46], &mqc_states[40]}, + {0x2401, 1, &mqc_states[47], &mqc_states[41]}, + {0x2201, 0, &mqc_states[48], &mqc_states[42]}, + {0x2201, 1, &mqc_states[49], &mqc_states[43]}, + {0x1c01, 0, &mqc_states[50], &mqc_states[44]}, + {0x1c01, 1, &mqc_states[51], &mqc_states[45]}, + {0x1801, 0, &mqc_states[52], &mqc_states[46]}, + {0x1801, 1, &mqc_states[53], &mqc_states[47]}, + {0x1601, 0, &mqc_states[54], &mqc_states[48]}, + {0x1601, 1, &mqc_states[55], &mqc_states[49]}, + {0x1401, 0, &mqc_states[56], &mqc_states[50]}, + {0x1401, 1, &mqc_states[57], &mqc_states[51]}, + {0x1201, 0, &mqc_states[58], &mqc_states[52]}, + {0x1201, 1, &mqc_states[59], &mqc_states[53]}, + {0x1101, 0, &mqc_states[60], &mqc_states[54]}, + {0x1101, 1, &mqc_states[61], &mqc_states[55]}, + {0x0ac1, 0, &mqc_states[62], &mqc_states[56]}, + {0x0ac1, 1, &mqc_states[63], &mqc_states[57]}, + {0x09c1, 0, &mqc_states[64], &mqc_states[58]}, + {0x09c1, 1, &mqc_states[65], &mqc_states[59]}, + {0x08a1, 0, &mqc_states[66], &mqc_states[60]}, + {0x08a1, 1, &mqc_states[67], &mqc_states[61]}, + {0x0521, 0, &mqc_states[68], &mqc_states[62]}, + {0x0521, 1, &mqc_states[69], &mqc_states[63]}, + {0x0441, 0, &mqc_states[70], &mqc_states[64]}, + {0x0441, 1, &mqc_states[71], &mqc_states[65]}, + {0x02a1, 0, &mqc_states[72], &mqc_states[66]}, + {0x02a1, 1, &mqc_states[73], &mqc_states[67]}, + {0x0221, 0, &mqc_states[74], &mqc_states[68]}, + {0x0221, 1, &mqc_states[75], &mqc_states[69]}, + {0x0141, 0, &mqc_states[76], &mqc_states[70]}, + {0x0141, 1, &mqc_states[77], &mqc_states[71]}, + {0x0111, 0, &mqc_states[78], &mqc_states[72]}, + {0x0111, 1, &mqc_states[79], &mqc_states[73]}, + {0x0085, 0, &mqc_states[80], &mqc_states[74]}, + {0x0085, 1, &mqc_states[81], &mqc_states[75]}, + {0x0049, 0, &mqc_states[82], &mqc_states[76]}, + {0x0049, 1, &mqc_states[83], &mqc_states[77]}, + {0x0025, 0, &mqc_states[84], &mqc_states[78]}, + {0x0025, 1, &mqc_states[85], &mqc_states[79]}, + {0x0015, 0, &mqc_states[86], &mqc_states[80]}, + {0x0015, 1, &mqc_states[87], &mqc_states[81]}, + {0x0009, 0, &mqc_states[88], &mqc_states[82]}, + {0x0009, 1, &mqc_states[89], &mqc_states[83]}, + {0x0005, 0, &mqc_states[90], &mqc_states[84]}, + {0x0005, 1, &mqc_states[91], &mqc_states[85]}, + {0x0001, 0, &mqc_states[90], &mqc_states[86]}, + {0x0001, 1, &mqc_states[91], &mqc_states[87]}, + {0x5601, 0, &mqc_states[92], &mqc_states[92]}, + {0x5601, 1, &mqc_states[93], &mqc_states[93]}, +}; + +/* +========================================================== + local functions +========================================================== +*/ + +static void mqc_byteout(opj_mqc_t *mqc) { + if (*mqc->bp == 0xff) { + mqc->bp++; + *mqc->bp = mqc->c >> 20; + mqc->c &= 0xfffff; + mqc->ct = 7; + } else { + if ((mqc->c & 0x8000000) == 0) { /* ((mqc->c&0x8000000)==0) CHANGE */ + mqc->bp++; + *mqc->bp = mqc->c >> 19; + mqc->c &= 0x7ffff; + mqc->ct = 8; + } else { + (*mqc->bp)++; + if (*mqc->bp == 0xff) { + mqc->c &= 0x7ffffff; + mqc->bp++; + *mqc->bp = mqc->c >> 20; + mqc->c &= 0xfffff; + mqc->ct = 7; + } else { + mqc->bp++; + *mqc->bp = mqc->c >> 19; + mqc->c &= 0x7ffff; + mqc->ct = 8; + } + } + } +} + +static void mqc_renorme(opj_mqc_t *mqc) { + do { + mqc->a <<= 1; + mqc->c <<= 1; + mqc->ct--; + if (mqc->ct == 0) { + mqc_byteout(mqc); + } + } while ((mqc->a & 0x8000) == 0); +} + +static void mqc_codemps(opj_mqc_t *mqc) { + mqc->a -= (*mqc->curctx)->qeval; + if ((mqc->a & 0x8000) == 0) { + if (mqc->a < (*mqc->curctx)->qeval) { + mqc->a = (*mqc->curctx)->qeval; + } else { + mqc->c += (*mqc->curctx)->qeval; + } + *mqc->curctx = (*mqc->curctx)->nmps; + mqc_renorme(mqc); + } else { + mqc->c += (*mqc->curctx)->qeval; + } +} + +static void mqc_codelps(opj_mqc_t *mqc) { + mqc->a -= (*mqc->curctx)->qeval; + if (mqc->a < (*mqc->curctx)->qeval) { + mqc->c += (*mqc->curctx)->qeval; + } else { + mqc->a = (*mqc->curctx)->qeval; + } + *mqc->curctx = (*mqc->curctx)->nlps; + mqc_renorme(mqc); +} + +static void mqc_setbits(opj_mqc_t *mqc) { + unsigned int tempc = mqc->c + mqc->a; + mqc->c |= 0xffff; + if (mqc->c >= tempc) { + mqc->c -= 0x8000; + } +} + +static int mqc_mpsexchange(opj_mqc_t *mqc) { + int d; + if (mqc->a < (*mqc->curctx)->qeval) { + d = 1 - (*mqc->curctx)->mps; + *mqc->curctx = (*mqc->curctx)->nlps; + } else { + d = (*mqc->curctx)->mps; + *mqc->curctx = (*mqc->curctx)->nmps; + } + + return d; +} + +static int mqc_lpsexchange(opj_mqc_t *mqc) { + int d; + if (mqc->a < (*mqc->curctx)->qeval) { + mqc->a = (*mqc->curctx)->qeval; + d = (*mqc->curctx)->mps; + *mqc->curctx = (*mqc->curctx)->nmps; + } else { + mqc->a = (*mqc->curctx)->qeval; + d = 1 - (*mqc->curctx)->mps; + *mqc->curctx = (*mqc->curctx)->nlps; + } + + return d; +} + +static void mqc_bytein(opj_mqc_t *mqc) { + if (mqc->bp != mqc->end) { + unsigned int c; + if (mqc->bp + 1 != mqc->end) { + c = *(mqc->bp + 1); + } else { + c = 0xff; + } + if (*mqc->bp == 0xff) { + if (c > 0x8f) { + mqc->c += 0xff00; + mqc->ct = 8; + } else { + mqc->bp++; + mqc->c += c << 9; + mqc->ct = 7; + } + } else { + mqc->bp++; + mqc->c += c << 8; + mqc->ct = 8; + } + } else { + mqc->c += 0xff00; + mqc->ct = 8; + } +} + +static void mqc_renormd(opj_mqc_t *mqc) { + do { + if (mqc->ct == 0) { + mqc_bytein(mqc); + } + mqc->a <<= 1; + mqc->c <<= 1; + mqc->ct--; + } while (mqc->a < 0x8000); +} + +/* +========================================================== + MQ-Coder interface +========================================================== +*/ + +opj_mqc_t* mqc_create() { + opj_mqc_t *mqc = (opj_mqc_t*)opj_malloc(sizeof(opj_mqc_t)); + return mqc; +} + +void mqc_destroy(opj_mqc_t *mqc) { + if(mqc) { + opj_free(mqc); + } +} + +int mqc_numbytes(opj_mqc_t *mqc) { + return mqc->bp - mqc->start; +} + +void mqc_init_enc(opj_mqc_t *mqc, unsigned char *bp) { + mqc_setcurctx(mqc, 0); + mqc->a = 0x8000; + mqc->c = 0; + mqc->bp = bp - 1; + mqc->ct = 12; + if (*mqc->bp == 0xff) { + mqc->ct = 13; + } + mqc->start = bp; +} + +void mqc_setcurctx(opj_mqc_t *mqc, int ctxno) { + mqc->curctx = &mqc->ctxs[ctxno]; +} + +void mqc_encode(opj_mqc_t *mqc, int d) { + if ((*mqc->curctx)->mps == d) { + mqc_codemps(mqc); + } else { + mqc_codelps(mqc); + } +} + +void mqc_flush(opj_mqc_t *mqc) { + mqc_setbits(mqc); + mqc->c <<= mqc->ct; + mqc_byteout(mqc); + mqc->c <<= mqc->ct; + mqc_byteout(mqc); + + if (*mqc->bp != 0xff) { + mqc->bp++; + } +} + +void mqc_bypass_init_enc(opj_mqc_t *mqc) { + mqc->c = 0; + mqc->ct = 8; + /*if (*mqc->bp == 0xff) { + mqc->ct = 7; + } */ +} + +void mqc_bypass_enc(opj_mqc_t *mqc, int d) { + mqc->ct--; + mqc->c = mqc->c + (d << mqc->ct); + if (mqc->ct == 0) { + mqc->bp++; + *mqc->bp = mqc->c; + mqc->ct = 8; + if (*mqc->bp == 0xff) { + mqc->ct = 7; + } + mqc->c = 0; + } +} + +int mqc_bypass_flush_enc(opj_mqc_t *mqc) { + unsigned char bit_padding; + + bit_padding = 0; + + if (mqc->ct != 0) { + while (mqc->ct > 0) { + mqc->ct--; + mqc->c += bit_padding << mqc->ct; + bit_padding = (bit_padding + 1) & 0x01; + } + mqc->bp++; + *mqc->bp = mqc->c; + mqc->ct = 8; + mqc->c = 0; + } + + return 1; +} + +void mqc_reset_enc(opj_mqc_t *mqc) { + mqc_resetstates(mqc); + mqc_setstate(mqc, 18, 0, 46); + mqc_setstate(mqc, 0, 0, 3); + mqc_setstate(mqc, 1, 0, 4); +} + +void mqc_reset_enc_3(opj_mqc_t *mqc) { + mqc_resetstates(mqc); + mqc_setstate(mqc, T1_3D_CTXNO_UNI, 0, 46); + mqc_setstate(mqc, T1_3D_CTXNO_AGG, 0, 3); + mqc_setstate(mqc, T1_3D_CTXNO_ZC, 0, 4); +} + +int mqc_restart_enc(opj_mqc_t *mqc) { + int correction = 1; + + /* */ + int n = 27 - 15 - mqc->ct; + mqc->c <<= mqc->ct; + while (n > 0) { + mqc_byteout(mqc); + n -= mqc->ct; + mqc->c <<= mqc->ct; + } + mqc_byteout(mqc); + + return correction; +} + +void mqc_restart_init_enc(opj_mqc_t *mqc) { + /* */ + mqc_setcurctx(mqc, 0); + mqc->a = 0x8000; + mqc->c = 0; + mqc->ct = 12; + mqc->bp--; + if (*mqc->bp == 0xff) { + mqc->ct = 13; + } +} + +void mqc_erterm_enc(opj_mqc_t *mqc) { + int k = 11 - mqc->ct + 1; + + while (k > 0) { + mqc->c <<= mqc->ct; + mqc->ct = 0; + mqc_byteout(mqc); + k -= mqc->ct; + } + + if (*mqc->bp != 0xff) { + mqc_byteout(mqc); + } +} + +void mqc_segmark_enc(opj_mqc_t *mqc) { + int i; + mqc_setcurctx(mqc, 18); + + for (i = 1; i < 5; i++) { + mqc_encode(mqc, i % 2); + } +} + +void mqc_init_dec(opj_mqc_t *mqc, unsigned char *bp, int len) { + mqc_setcurctx(mqc, 0); + mqc->start = bp; + mqc->end = bp + len; + mqc->bp = bp; + if (len==0) mqc->c = 0xff << 16; + else mqc->c = *mqc->bp << 16; + mqc_bytein(mqc); + mqc->c <<= 7; + mqc->ct -= 7; + mqc->a = 0x8000; +} + +int mqc_decode(opj_mqc_t *mqc) { + int d; + mqc->a -= (*mqc->curctx)->qeval; + if ((mqc->c >> 16) < (*mqc->curctx)->qeval) { + d = mqc_lpsexchange(mqc); + mqc_renormd(mqc); + } else { + mqc->c -= (*mqc->curctx)->qeval << 16; + if ((mqc->a & 0x8000) == 0) { + d = mqc_mpsexchange(mqc); + mqc_renormd(mqc); + } else { + d = (*mqc->curctx)->mps; + } + } + + return d; +} + +void mqc_resetstates(opj_mqc_t *mqc) { + int i; + for (i = 0; i < MQC_NUMCTXS; i++) { + mqc->ctxs[i] = mqc_states; + } +} + +void mqc_setstate(opj_mqc_t *mqc, int ctxno, int msb, int prob) { + mqc->ctxs[ctxno] = &mqc_states[msb + (prob << 1)]; +} + + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/mqc.h b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/mqc.h new file mode 100644 index 0000000..7a6136e --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/mqc.h @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MQC_H +#define __MQC_H +/** +@file mqc.h +@brief Implementation of an MQ-Coder (MQC) + +The functions in MQC.C have for goal to realize the MQ-coder operations. The functions +in MQC.C are used by some function in T1.C. +*/ + +/** @defgroup MQC MQC - Implementation of an MQ-Coder */ +/*@{*/ + +/** +This struct defines the state of a context. +*/ +typedef struct opj_mqc_state { + /** the probability of the Least Probable Symbol (0.75->0x8000, 1.5->0xffff) */ + unsigned int qeval; + /** the Most Probable Symbol (0 or 1) */ + int mps; + /** next state if the next encoded symbol is the MPS */ + struct opj_mqc_state *nmps; + /** next state if the next encoded symbol is the LPS */ + struct opj_mqc_state *nlps; +} opj_mqc_state_t; + +#define MQC_NUMCTXS 32 + +/** +MQ coder +*/ +typedef struct opj_mqc { + unsigned int c; + unsigned int a; + unsigned int ct; + unsigned char *bp; + unsigned char *start; + unsigned char *end; + opj_mqc_state_t *ctxs[MQC_NUMCTXS]; + opj_mqc_state_t **curctx; +} opj_mqc_t; + +/** @name Exported functions */ +/*@{*/ +/* ----------------------------------------------------------------------- */ +/** +Create a new MQC handle +@return Returns a new MQC handle if successful, returns NULL otherwise +*/ +opj_mqc_t* mqc_create(); +/** +Destroy a previously created MQC handle +@param mqc MQC handle to destroy +*/ +void mqc_destroy(opj_mqc_t *mqc); +/** +Return the number of bytes written/read since initialisation +@param mqc MQC handle +@return Returns the number of bytes already encoded +*/ +int mqc_numbytes(opj_mqc_t *mqc); +/** +Reset the states of all the context of the coder/decoder +(each context is set to a state where 0 and 1 are more or less equiprobable) +@param mqc MQC handle +*/ +void mqc_resetstates(opj_mqc_t *mqc); +/** +Set the state of a particular context +@param mqc MQC handle +@param ctxno Number that identifies the context +@param msb The MSB of the new state of the context +@param prob Number that identifies the probability of the symbols for the new state of the context +*/ +void mqc_setstate(opj_mqc_t *mqc, int ctxno, int msb, int prob); +/** +Initialize the encoder +@param mqc MQC handle +@param bp Pointer to the start of the buffer where the bytes will be written +*/ +void mqc_init_enc(opj_mqc_t *mqc, unsigned char *bp); +/** +Set the current context used for coding/decoding +@param mqc MQC handle +@param ctxno Number that identifies the context +*/ +void mqc_setcurctx(opj_mqc_t *mqc, int ctxno); +/** +Encode a symbol using the MQ-coder +@param mqc MQC handle +@param d The symbol to be encoded (0 or 1) +*/ +void mqc_encode(opj_mqc_t *mqc, int d); +/** +Flush the encoder, so that all remaining data is written +@param mqc MQC handle +*/ +void mqc_flush(opj_mqc_t *mqc); +/** +BYPASS mode switch, initialization operation. +JPEG 2000 p 505. +

Not fully implemented and tested !!

+@param mqc MQC handle +*/ +void mqc_bypass_init_enc(opj_mqc_t *mqc); +/** +BYPASS mode switch, coding operation. +JPEG 2000 p 505. +

Not fully implemented and tested !!

+@param mqc MQC handle +@param d The symbol to be encoded (0 or 1) +*/ +void mqc_bypass_enc(opj_mqc_t *mqc, int d); +/** +BYPASS mode switch, flush operation +

Not fully implemented and tested !!

+@param mqc MQC handle +@return Returns 1 (always) +*/ +int mqc_bypass_flush_enc(opj_mqc_t *mqc); +/** +RESET mode switch +@param mqc MQC handle +*/ +void mqc_reset_enc(opj_mqc_t *mqc); +/** +RESET mode switch +@param mqc MQC handle +*/ +void mqc_reset_enc_3(opj_mqc_t *mqc); +/** +RESTART mode switch (TERMALL) +@param mqc MQC handle +@return Returns 1 (always) +*/ +int mqc_restart_enc(opj_mqc_t *mqc); +/** +RESTART mode switch (TERMALL) reinitialisation +@param mqc MQC handle +*/ +void mqc_restart_init_enc(opj_mqc_t *mqc); +/** +ERTERM mode switch (PTERM) +@param mqc MQC handle +*/ +void mqc_erterm_enc(opj_mqc_t *mqc); +/** +SEGMARK mode switch (SEGSYM) +@param mqc MQC handle +*/ +void mqc_segmark_enc(opj_mqc_t *mqc); +/** +Initialize the decoder +@param mqc MQC handle +@param bp Pointer to the start of the buffer from which the bytes will be read +@param len Length of the input buffer +*/ +void mqc_init_dec(opj_mqc_t *mqc, unsigned char *bp, int len); +/** +Decode a symbol +@param mqc MQC handle +@return Returns the decoded symbol (0 or 1) +*/ +int mqc_decode(opj_mqc_t *mqc); +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __MQC_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/openjpeg.c b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/openjpeg.c new file mode 100644 index 0000000..4f87db9 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/openjpeg.c @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2006, Mónica Díez García, Image Processing Laboratory, University of Valladolid, Spain + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef _WIN32 +#include +#endif /* _WIN32 */ + +#include "opj_includes.h" +#define JP3D_VERSION "1.3.0" +/* ---------------------------------------------------------------------- */ +#ifdef _WIN32 +#ifndef OPJ_STATIC +BOOL APIENTRY +DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { + switch (ul_reason_for_call) { + case DLL_PROCESS_ATTACH : + break; + case DLL_PROCESS_DETACH : + break; + case DLL_THREAD_ATTACH : + case DLL_THREAD_DETACH : + break; + } + + return TRUE; +} +#endif /* OPJ_STATIC */ +#endif /* _WIN32 */ + +/* ---------------------------------------------------------------------- */ + +const char* OPJ_CALLCONV opj_version() { + return JP3D_VERSION; +} +opj_dinfo_t* OPJ_CALLCONV opj_create_decompress(OPJ_CODEC_FORMAT format) { + opj_dinfo_t *dinfo = (opj_dinfo_t*)opj_malloc(sizeof(opj_dinfo_t)); + if(!dinfo) return NULL; + dinfo->is_decompressor = true; + switch(format) { + case CODEC_J3D: + case CODEC_J2K: + /* get a J3D decoder handle */ + dinfo->j3d_handle = (void*)j3d_create_decompress((opj_common_ptr)dinfo); + if(!dinfo->j3d_handle) { + opj_free(dinfo); + return NULL; + } + break; + default: + opj_free(dinfo); + return NULL; + } + + dinfo->codec_format = format; + + return dinfo; +} + +void OPJ_CALLCONV opj_destroy_decompress(opj_dinfo_t *dinfo) { + if(dinfo) { + /* destroy the codec */ + if(dinfo->codec_format != CODEC_UNKNOWN) { + j3d_destroy_decompress((opj_j3d_t*)dinfo->j3d_handle); + } + /* destroy the decompressor */ + opj_free(dinfo); + } +} + +void OPJ_CALLCONV opj_set_default_decoder_parameters(opj_dparameters_t *parameters) { + if(parameters) { + memset(parameters, 0, sizeof(opj_dparameters_t)); + /* default decoding parameters */ + parameters->cp_layer = 0; + parameters->cp_reduce[0] = 0; + parameters->cp_reduce[1] = 0; + parameters->cp_reduce[2] = 0; + parameters->bigendian = 0; + + parameters->decod_format = -1; + parameters->cod_format = -1; + } +} + +void OPJ_CALLCONV opj_setup_decoder(opj_dinfo_t *dinfo, opj_dparameters_t *parameters) { + if(dinfo && parameters) { + if (dinfo->codec_format != CODEC_UNKNOWN) { + j3d_setup_decoder((opj_j3d_t*)dinfo->j3d_handle, parameters); + } + } +} + +opj_volume_t* OPJ_CALLCONV opj_decode(opj_dinfo_t *dinfo, opj_cio_t *cio) { + if(dinfo && cio) { + if (dinfo->codec_format != CODEC_UNKNOWN) { + return j3d_decode((opj_j3d_t*)dinfo->j3d_handle, cio); + } + } + + return NULL; +} + +opj_cinfo_t* OPJ_CALLCONV opj_create_compress(OPJ_CODEC_FORMAT format) { + opj_cinfo_t *cinfo = (opj_cinfo_t*)opj_malloc(sizeof(opj_cinfo_t)); + if(!cinfo) return NULL; + cinfo->is_decompressor = false; + switch(format) { + case CODEC_J3D: + case CODEC_J2K: + /* get a J3D coder handle */ + cinfo->j3d_handle = (void*)j3d_create_compress((opj_common_ptr)cinfo); + if(!cinfo->j3d_handle) { + opj_free(cinfo); + return NULL; + } + break; + default: + opj_free(cinfo); + return NULL; + } + + cinfo->codec_format = format; + + return cinfo; +} + +void OPJ_CALLCONV opj_destroy_compress(opj_cinfo_t *cinfo) { + if(cinfo) { + /* destroy the codec */ + if (cinfo->codec_format != CODEC_UNKNOWN) { + j3d_destroy_compress((opj_j3d_t*)cinfo->j3d_handle); + } + /* destroy the decompressor */ + opj_free(cinfo); + } +} + +void OPJ_CALLCONV opj_set_default_encoder_parameters(opj_cparameters_t *parameters) { + if(parameters) { + memset(parameters, 0, sizeof(opj_cparameters_t)); + /* default coding parameters */ + parameters->numresolution[0] = 3; + parameters->numresolution[1] = 3; + parameters->numresolution[2] = 1; + parameters->cblock_init[0] = 64; + parameters->cblock_init[1] = 64; + parameters->cblock_init[2] = 64; + parameters->prog_order = LRCP; + parameters->roi_compno = -1; /* no ROI */ + parameters->atk_wt[0] = 1; /* 5-3 WT */ + parameters->atk_wt[1] = 1; /* 5-3 WT */ + parameters->atk_wt[2] = 1; /* 5-3 WT */ + parameters->irreversible = 0; + parameters->subsampling_dx = 1; + parameters->subsampling_dy = 1; + parameters->subsampling_dz = 1; + + parameters->decod_format = -1; + parameters->cod_format = -1; + parameters->encoding_format = ENCOD_2EB; + parameters->transform_format = TRF_2D_DWT; + } +} + +void OPJ_CALLCONV opj_setup_encoder(opj_cinfo_t *cinfo, opj_cparameters_t *parameters, opj_volume_t *volume) { + if(cinfo && parameters && volume) { + if (cinfo->codec_format != CODEC_UNKNOWN) { + j3d_setup_encoder((opj_j3d_t*)cinfo->j3d_handle, parameters, volume); + } + } +} + +bool OPJ_CALLCONV opj_encode(opj_cinfo_t *cinfo, opj_cio_t *cio, opj_volume_t *volume, char *index) { + if(cinfo && cio && volume) { + if (cinfo->codec_format != CODEC_UNKNOWN) { + return j3d_encode((opj_j3d_t*)cinfo->j3d_handle, cio, volume, index); + } + } + + return false; +} + + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/openjpeg3d.h b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/openjpeg3d.h new file mode 100644 index 0000000..bfba40d --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/openjpeg3d.h @@ -0,0 +1,713 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * Copyright (c) 2006, Mónica Díez García, Image Processing Laboratory, University of Valladolid, Spain + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef OPENJPEG_H +#define OPENJPEG_H + +/* +========================================================== + Compiler directives +========================================================== +*/ + +#if defined(OPJ_STATIC) || !(defined(WIN32) || defined(__WIN32__)) +#define OPJ_API +#define OPJ_CALLCONV +#else +#define OPJ_CALLCONV __stdcall +/* +The following ifdef block is the standard way of creating macros which make exporting +from a DLL simpler. All files within this DLL are compiled with the OPJ_EXPORTS +symbol defined on the command line. this symbol should not be defined on any project +that uses this DLL. This way any other project whose source files include this file see +OPJ_API functions as being imported from a DLL, wheras this DLL sees symbols +defined with this macro as being exported. +*/ +#ifdef OPJ_EXPORTS +#define OPJ_API __declspec(dllexport) +#else +#define OPJ_API __declspec(dllimport) +#endif /* OPJ_EXPORTS */ +#endif /* !OPJ_STATIC || !WIN32 */ + +#ifndef __cplusplus +#if defined(HAVE_STDBOOL_H) +/* +The C language implementation does correctly provide the standard header +file "stdbool.h". + */ +#include +#else +/* +The C language implementation does not provide the standard header file +"stdbool.h" as required by ISO/IEC 9899:1999. Try to compensate for this +braindamage below. +*/ +#if !defined(bool) +#define bool int +#endif +#if !defined(true) +#define true 1 +#endif +#if !defined(false) +#define false 0 +#endif +#endif +#endif /* __cplusplus */ + +/* +========================================================== + Useful constant definitions +========================================================== +*/ +#ifndef MAX_SLICES +#define MAX_SLICES 300 /**< Maximum allowed size for slices */ +#endif /* MAX_PATH */ + +#ifndef MAX_PATH +#define MAX_PATH 260 /**< Maximum allowed size for filenames */ +#endif /* MAX_PATH */ + +#define J3D_MAXRLVLS 32 /**< Number of maximum resolution level authorized */ +#define J3D_MAXBANDS (7*J3D_MAXRLVLS + 1) /**< Number of maximum sub-band linked to number of resolution level */ + +#define TINY 1.0E-20 +/* +========================================================== + enum definitions +========================================================== +*/ + +#define J2K_CFMT 0 +#define J3D_CFMT 1 +#define LSE_CFMT 2 + +#define BIN_DFMT 0 +#define PGX_DFMT 1 +#define IMG_DFMT 2 +/* ----------------------------------------------------------------------- */ + +/** Progression order */ +typedef enum PROG_ORDER { +/**< place-holder */ + PROG_UNKNOWN = -1, +/**< layer-resolution-component-precinct order */ + LRCP = 0, +/**< resolution-layer-component-precinct order */ + RLCP = 1, +/**< resolution-precinct-component-layer order */ + RPCL = 2, +/**< precinct-component-resolution-layer order */ + PCRL = 3, +/**< component-precinct-resolution-layer order */ + CPRL = 4 +} OPJ_PROG_ORDER; + +/** +Supported volume color spaces +*/ +typedef enum COLOR_SPACE { +/**< place-holder */ + CLRSPC_UNKNOWN = -1, +/**< sRGB */ + CLRSPC_SRGB = 1, +/**< grayscale */ + CLRSPC_GRAY = 2, +/**< YUV */ + CLRSPC_SYCC = 3 +} OPJ_COLOR_SPACE; + +/** +Supported codec +*/ +typedef enum CODEC_FORMAT { + /**< place-holder */ + CODEC_UNKNOWN = -1, +/**< JPEG-2000 codestream : read/write */ + CODEC_J2K = 0, +/**< JPEG-2000 Part 10 file format : read/write */ + CODEC_J3D = 1 +} OPJ_CODEC_FORMAT; + +/** +Supported entropy coding algorithms +*/ +typedef enum ENTROPY_CODING { +/**< place-holder */ + ENCOD_UNKNOWN = -1, +/**< 2D EBCOT encoding */ + ENCOD_2EB = 0, +/**< 3D EBCOT encoding */ + ENCOD_3EB = 1, +/**< Golomb-Rice coding with 2D context */ + ENCOD_2GR = 2, +/**< Golomb-Rice coding with 3D context */ + ENCOD_3GR = 3 +} OPJ_ENTROPY_CODING; + +/** +Supported transforms +*/ +typedef enum TRANSFORM { +/**< place-holder */ + TRF_UNKNOWN = -1, +/**< 2D DWT, no transform in axial dim */ + TRF_2D_DWT = 0, +/**< 3D DWT */ + TRF_3D_DWT = 1, +/**< 3D prediction*/ + TRF_3D_RLS = 2, + TRF_3D_LSE = 3 +} OPJ_TRANSFORM; +/* +========================================================== + event manager typedef definitions +========================================================== +*/ + +/** +Callback function prototype for events +@param msg Event message +@param client_data +*/ +typedef void (*opj_msg_callback) (const char *msg, void *client_data); + +/** +Message handler object +used for +
    +
  • Error messages +
  • Warning messages +
  • Debugging messages +
+*/ +typedef struct opj_event_mgr { + /** Error message callback if available, NULL otherwise */ + opj_msg_callback error_handler; + /** Warning message callback if available, NULL otherwise */ + opj_msg_callback warning_handler; + /** Debug message callback if available, NULL otherwise */ + opj_msg_callback info_handler; +} opj_event_mgr_t; + + +/* +========================================================== + codec typedef definitions +========================================================== +*/ + +/** +Progression order changes +*/ +typedef struct opj_poc { + int resno0, compno0; + int layno1, resno1, compno1; + OPJ_PROG_ORDER prg; + int tile; + char progorder[4]; +} opj_poc_t; + + +/** +Compression parameters +*/ +typedef struct opj_cparameters { +/** size of tile: tile_size_on = false (not in argument) or = true (in argument) */ + bool tile_size_on; +/** XTOsiz */ + int cp_tx0; +/** YTOsiz */ + int cp_ty0; +/** ZTOsiz */ + int cp_tz0; + +/** XTsiz */ + int cp_tdx; +/** YTsiz */ + int cp_tdy; +/** ZTsiz */ + int cp_tdz; + +/** allocation by rate/distortion */ + int cp_disto_alloc; +/** allocation by fixed layer */ + int cp_fixed_alloc; +/** add fixed_quality */ + int cp_fixed_quality; +/** fixed layer */ + int *cp_matrice; +/** number of layers */ + int tcp_numlayers; +/** rates for successive layers */ + float tcp_rates[100]; +/** psnr's for successive layers */ + float tcp_distoratio[100]; +/** comment for coding */ + char *cp_comment; +/** csty : coding style */ + int csty; +/** DC offset (DCO) */ + int dcoffset; +/** progression order (default LRCP) */ + OPJ_PROG_ORDER prog_order; +/** progression order changes */ + opj_poc_t POC[J3D_MAXRLVLS-1]; +/** number of progression order changes (POC), default to 0 */ + int numpocs; + +/** number of resolutions */ + int numresolution[3]; +/** initial code block width, height and depth, default to 64 */ + int cblock_init[3]; +/** mode switch (1=BYPASS(LAZY) 2=RESET 4=RESTART(TERMALL) 8=VSC 16=ERTERM(SEGTERM) 32=SEGMARK(SEGSYM)) */ + int mode; + +/** 1 : use the irreversible DWT 9-7, 0 : use lossless compression (default) */ + int irreversible; +/** WT from ATK, default to 0 (false), no of atk used */ + int atk_wt[3]; +/** region of interest: affected component in [0..3], -1 means no ROI */ + int roi_compno; +/** region of interest: upshift value */ + int roi_shift; + +/* number of precinct size specifications */ + int res_spec; +/** initial precinct width */ + int prct_init[3][J3D_MAXRLVLS]; + +/** transform format 0: 0: 2DWT, 1: 2D1P, 2: 3DWT, 3: 3RLS */ + OPJ_TRANSFORM transform_format; +/** output file format 0: 2EB, 1: 3EB, 2: 2GR, 3: 3GR, 4: GRI */ + OPJ_ENTROPY_CODING encoding_format; + + /**@name command line encoder parameters (not used inside the library) */ + /*@{*/ + char infile[MAX_PATH]; /** input file name */ + char outfile[MAX_PATH]; /** output file name */ + char imgfile[MAX_PATH]; /** IMG file name for BIN volumes*/ + int index_on; /** creation of an index file, default to 0 (false) */ + char index[MAX_PATH]; /** index file name */ + + int volume_offset_x0; /** subvolume encoding: origin volume offset in x, y and z direction */ + int volume_offset_y0; + int volume_offset_z0; + + int subsampling_dx; /** subsampling value for dx */ + int subsampling_dy; + int subsampling_dz; + + int decod_format; /** input file format 0: BIN, 1: PGX */ + int cod_format; /** output file format 0: JP3D */ + /*@}*/ +} opj_cparameters_t; + +/** +Decompression parameters +*/ +typedef struct opj_dparameters { +/** Set the number of highest resolution levels to be discarded. if != 0, then original dimension divided by 2^(reduce); if == 0 or not used, volume is decoded to the full resolution */ + int cp_reduce[3]; +/** Set the maximum number of quality layers to decode. if != 0, then only the first "layer" layers are decoded; if == 0 or not used, all the quality layers are decoded */ + int cp_layer; + int bigendian; + + /**@name command line encoder parameters (not used inside the library) */ + /*@{*/ +/** input file name */ + char infile[MAX_PATH]; +/** output file name */ + char outfile[MAX_PATH]; +/** IMG file name for BIN volumes*/ + char imgfile[MAX_PATH]; +/** Original file name for PSNR measures*/ + char original[MAX_PATH]; +/** input file format 0: J2K, 1: JP3D */ + int decod_format; +/** input file format 0: BIN, 1: PGM */ + int cod_format; +/** original file format 0: BIN, 1: PGM */ + int orig_format; + /*@}*/ +} opj_dparameters_t; + +/** Common fields between JPEG-2000 compression and decompression master structs. */ +#define opj_common_fields \ + opj_event_mgr_t *event_mgr; /**< pointer to the event manager */\ + void * client_data; /**< Available for use by application */\ + bool is_decompressor; /**< So common code can tell which is which */\ + OPJ_CODEC_FORMAT codec_format; /**< selected codec */\ + OPJ_ENTROPY_CODING encoding_format; /**< selected entropy coding */\ + OPJ_TRANSFORM transform_format; /**< selected transform */\ + void *j3d_handle /**< pointer to the J3D codec */ + +/* Routines that are to be used by both halves of the library are declared + * to receive a pointer to this structure. There are no actual instances of + * opj_common_struct_t, only of opj_cinfo_t and opj_dinfo_t. + */ +typedef struct opj_common_struct { + opj_common_fields; /* Fields common to both master struct types */ + /* Additional fields follow in an actual opj_cinfo_t or + * opj_dinfo_t. All three structs must agree on these + * initial fields! (This would be a lot cleaner in C++.) + */ +} opj_common_struct_t; + +typedef opj_common_struct_t * opj_common_ptr; + +/** +Compression context info +*/ +typedef struct opj_cinfo { + /** Fields shared with opj_dinfo_t */ + opj_common_fields; + /* other specific fields go here */ +} opj_cinfo_t; + +/** +Decompression context info +*/ +typedef struct opj_dinfo { + /** Fields shared with opj_cinfo_t */ + opj_common_fields; + /* other specific fields go here */ +} opj_dinfo_t; + +/* +========================================================== + I/O stream typedef definitions +========================================================== +*/ + +/* + * Stream open flags. + */ +/** The stream was opened for reading. */ +#define OPJ_STREAM_READ 0x0001 +/** The stream was opened for writing. */ +#define OPJ_STREAM_WRITE 0x0002 + +/** +Byte input-output stream (CIO) +*/ +typedef struct opj_cio { +/** codec context */ + opj_common_ptr cinfo; +/** open mode (read/write) either OPJ_STREAM_READ or OPJ_STREAM_WRITE */ + int openmode; +/** pointer to the start of the buffer */ + unsigned char *buffer; +/** buffer size in bytes */ + int length; +/** pointer to the start of the stream */ + unsigned char *start; +/** pointer to the end of the stream */ + unsigned char *end; +/** pointer to the current position */ + unsigned char *bp; +} opj_cio_t; + +/* +========================================================== + volume typedef definitions +========================================================== +*/ + +/** +Defines a single volume component +*/ +typedef struct opj_volume_comp { +/** XRsiz: horizontal separation of a sample of ith component with respect to the reference grid */ + int dx; +/** YRsiz: vertical separation of a sample of ith component with respect to the reference grid */ + int dy; +/** ZRsiz: vertical separation of a sample of ith component with respect to the reference grid */ + int dz; +/** data width */ + int w; + /** data height */ + int h; + /** data length : no of slices */ + int l; + /** x component offset compared to the whole volume */ + int x0; + /** y component offset compared to the whole volume */ + int y0; + /** z component offset compared to the whole volume */ + int z0; + /** precision */ + int prec; + /** volume depth in bits */ + int bpp; + /** DC offset (15444-2) */ + int dcoffset; + /** signed (1) / unsigned (0) */ + int sgnd; + /** BE byte order (1) / LE byte order (0) */ + int bigendian; + /** number of decoded resolution */ + int resno_decoded[3]; + /** number of division by 2 of the out volume compared to the original size of volume */ + int factor[3]; + /** volume component data */ + int *data; +} opj_volume_comp_t; + +/** +Defines volume data and characteristics +*/ +typedef struct opj_volume { +/** XOsiz: horizontal offset from the origin of the reference grid to the left side of the volume area */ + int x0; +/** YOsiz: vertical offset from the origin of the reference grid to the top side of the volume area */ + int y0; +/** ZOsiz: vertical offset from the origin of the reference grid to the top side of the volume area */ + int z0; +/** Xsiz: width of the reference grid */ + int x1; +/** Ysiz: height of the reference grid */ + int y1; +/** Zsiz: length of the reference grid */ + int z1; +/** number of components in the volume */ + int numcomps; +/** number of slices in the volume */ + int numslices; +/** color space: sRGB, Greyscale or YUV */ + OPJ_COLOR_SPACE color_space; +/** volume components */ + opj_volume_comp_t *comps; +} opj_volume_t; + +/** +Component parameters structure used by the opj_volume_create function +*/ +typedef struct opj_volume_comptparm { + /** XRsiz: horizontal separation of a sample of ith component with respect to the reference grid */ + int dx; + /** YRsiz: vertical separation of a sample of ith component with respect to the reference grid */ + int dy; + /** ZRsiz: axial separation of a sample of ith component with respect to the reference grid */ + int dz; + /** data width */ + int w; + /** data height */ + int h; + /** data length */ + int l; + /** x component offset compared to the whole volume */ + int x0; + /** y component offset compared to the whole volume */ + int y0; + /** z component offset compared to the whole volume */ + int z0; + /** precision */ + int prec; + /** volume depth in bits */ + int bpp; + /** signed (1) / unsigned (0) */ + int sgnd; + /** DC offset*/ + int dcoffset; + /** BE byte order (1) / LE byte order (0) */ + int bigendian; +} opj_volume_cmptparm_t; + +#ifdef __cplusplus +extern "C" { +#endif + + +/* +========================================================== + openjpeg version +========================================================== +*/ + +OPJ_API const char * OPJ_CALLCONV opj_version(); + +/* +========================================================== + volume functions definitions +========================================================== +*/ + +/** +Create an volume +@param numcmpts number of components +@param cmptparms components parameters +@param clrspc volume color space +@return returns a new volume structure if successful, returns NULL otherwise +*/ +OPJ_API opj_volume_t* OPJ_CALLCONV opj_volume_create(int numcmpts, opj_volume_cmptparm_t *cmptparms, OPJ_COLOR_SPACE clrspc); + +/** +Deallocate any resources associated with an volume +@param volume volume to be destroyed +*/ +OPJ_API void OPJ_CALLCONV opj_volume_destroy(opj_volume_t *volume); + +/* +========================================================== + stream functions definitions +========================================================== +*/ + +/** +Open and allocate a memory stream for read / write. +On reading, the user must provide a buffer containing encoded data. The buffer will be +wrapped by the returned CIO handle. +On writing, buffer parameters must be set to 0: a buffer will be allocated by the library +to contain encoded data. +@param cinfo Codec context info +@param buffer Reading: buffer address. Writing: NULL +@param length Reading: buffer length. Writing: 0 +@return Returns a CIO handle if successful, returns NULL otherwise +*/ +OPJ_API opj_cio_t* OPJ_CALLCONV opj_cio_open(opj_common_ptr cinfo, unsigned char *buffer, int length); + +/** +Close and free a CIO handle +@param cio CIO handle to free +*/ +OPJ_API void OPJ_CALLCONV opj_cio_close(opj_cio_t *cio); + +/** +Get position in byte stream +@param cio CIO handle +@return Returns the position in bytes +*/ +OPJ_API int OPJ_CALLCONV cio_tell(opj_cio_t *cio); +/** +Set position in byte stream +@param cio CIO handle +@param pos Position, in number of bytes, from the beginning of the stream +*/ +OPJ_API void OPJ_CALLCONV cio_seek(opj_cio_t *cio, int pos); + +/* +========================================================== + event manager functions definitions +========================================================== +*/ + +OPJ_API opj_event_mgr_t* OPJ_CALLCONV opj_set_event_mgr(opj_common_ptr cinfo, opj_event_mgr_t *event_mgr, void *context); + +/* +========================================================== + codec functions definitions +========================================================== +*/ +/** +Creates a J3D decompression structure +@param format Decoder to select +@return Returns a handle to a decompressor if successful, returns NULL otherwise +*/ +OPJ_API opj_dinfo_t* OPJ_CALLCONV opj_create_decompress(OPJ_CODEC_FORMAT format); +/** +Destroy a decompressor handle +@param dinfo decompressor handle to destroy +*/ +OPJ_API void OPJ_CALLCONV opj_destroy_decompress(opj_dinfo_t *dinfo); +/** +Set decoding parameters to default values +@param parameters Decompression parameters +*/ +OPJ_API void OPJ_CALLCONV opj_set_default_decoder_parameters(opj_dparameters_t *parameters); +/** +Setup the decoder decoding parameters using user parameters. +Decoding parameters are returned in j3d->cp. +@param dinfo decompressor handle +@param parameters decompression parameters +*/ +OPJ_API void OPJ_CALLCONV opj_setup_decoder(opj_dinfo_t *dinfo, opj_dparameters_t *parameters); +/** +Decode an volume from a JPEG-2000 codestream +@param dinfo decompressor handle +@param cio Input buffer stream +@return Returns a decoded volume if successful, returns NULL otherwise +*/ +OPJ_API opj_volume_t* OPJ_CALLCONV opj_decode(opj_dinfo_t *dinfo, opj_cio_t *cio); +/** +Creates a J3D/JP2 compression structure +@param format Coder to select +@return Returns a handle to a compressor if successful, returns NULL otherwise +*/ +OPJ_API opj_cinfo_t* OPJ_CALLCONV opj_create_compress(OPJ_CODEC_FORMAT format); +/** +Destroy a compressor handle +@param cinfo compressor handle to destroy +*/ +OPJ_API void OPJ_CALLCONV opj_destroy_compress(opj_cinfo_t *cinfo); +/** +Set encoding parameters to default values, that means : +
    +
  • Lossless +
  • 1 tile +
  • Size of precinct : 2^15 x 2^15 (means 1 precinct) +
  • Size of code-block : 64 x 64 +
  • Number of resolutions: 6 +
  • No SOP marker in the codestream +
  • No EPH marker in the codestream +
  • No sub-sampling in x or y direction +
  • No mode switch activated +
  • Progression order: LRCP +
  • No index file +
  • No ROI upshifted +
  • No offset of the origin of the volume +
  • No offset of the origin of the tiles +
  • Reversible DWT 5-3 +
+@param parameters Compression parameters +*/ +OPJ_API void OPJ_CALLCONV opj_set_default_encoder_parameters(opj_cparameters_t *parameters); +/** +Setup the encoder parameters using the current volume and using user parameters. +@param cinfo compressor handle +@param parameters compression parameters +@param volume input filled volume +*/ +OPJ_API void OPJ_CALLCONV opj_setup_encoder(opj_cinfo_t *cinfo, opj_cparameters_t *parameters, opj_volume_t *volume); +/** +Encode an volume into a JPEG-2000 codestream +@param cinfo compressor handle +@param cio Output buffer stream +@param volume Volume to encode +@param index Name of the index file if required, NULL otherwise +@return Returns true if successful, returns false otherwise +*/ +OPJ_API bool OPJ_CALLCONV opj_encode(opj_cinfo_t *cinfo, opj_cio_t *cio, opj_volume_t *volume, char *index); + +#ifdef __cplusplus +} +#endif + +#endif /* OPENJPEG_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/opj_includes.h b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/opj_includes.h new file mode 100644 index 0000000..0c70ff1 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/opj_includes.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef OPJ_INCLUDES_H +#define OPJ_INCLUDES_H + +/* + ========================================================== + Standard includes used by the library + ========================================================== +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* + ========================================================== + OpenJPEG interface + ========================================================== + */ +#include "openjpeg3d.h" + +/* + ========================================================== + OpenJPEG modules + ========================================================== +*/ + +#include "jp3d_lib.h" +#include "event.h" +#include "cio.h" + +#include "volume.h" +#include "jp3d.h" + +#include "mqc.h" +#include "raw.h" +#include "bio.h" +#include "tgt.h" +#include "tcd.h" +#include "t1.h" +#include "t1_3d.h" +#include "dwt.h" +#include "pi.h" +#include "t2.h" +#include "mct.h" +#include "int.h" +#include "fix.h" + +//#include "pred.h" +//#include "golomb.h" + +#endif /* OPJ_INCLUDES_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/pi.c b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/pi.c new file mode 100644 index 0000000..b7d8136 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/pi.c @@ -0,0 +1,630 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * Copyright (c) 2006, Mónica Díez, LPI-UVA, Spain + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "opj_includes.h" + +/** @defgroup PI PI - Implementation of a packet iterator */ +/*@{*/ + +/** @name Funciones locales */ +/*@{*/ + +/** +Get next packet in layer-resolution-component-precinct order. +@param pi packet iterator to modify +@return returns false if pi pointed to the last packet or else returns true +*/ +static bool pi_next_lrcp(opj_pi_iterator_t * pi); +/** +Get next packet in resolution-layer-component-precinct order. +@param pi packet iterator to modify +@return returns false if pi pointed to the last packet or else returns true +*/ +static bool pi_next_rlcp(opj_pi_iterator_t * pi); +/** +Get next packet in resolution-precinct-component-layer order. +@param pi packet iterator to modify +@return returns false if pi pointed to the last packet or else returns true +*/ +static bool pi_next_rpcl(opj_pi_iterator_t * pi); +/** +Get next packet in precinct-component-resolution-layer order. +@param pi packet iterator to modify +@return returns false if pi pointed to the last packet or else returns true +*/ +static bool pi_next_pcrl(opj_pi_iterator_t * pi); +/** +Get next packet in component-precinct-resolution-layer order. +@param pi packet iterator to modify +@return returns false if pi pointed to the last packet or else returns true +*/ +static bool pi_next_cprl(opj_pi_iterator_t * pi); + +/*@}*/ + +/*@}*/ + +/* +========================================================== + local functions +========================================================== +*/ + +static bool pi_next_lrcp(opj_pi_iterator_t * pi) { + opj_pi_comp_t *comp = NULL; + opj_pi_resolution_t *res = NULL; + long index = 0; + + if (!pi->first) { + comp = &pi->comps[pi->compno]; + res = &comp->resolutions[pi->resno]; + goto LABEL_SKIP; + } else { + pi->first = 0; + } + + for (pi->layno = 0; pi->layno < pi->poc.layno1; pi->layno++) { + for (pi->resno = pi->poc.resno0; pi->resno < pi->poc.resno1; pi->resno++) { + for (pi->compno = pi->poc.compno0; pi->compno < pi->poc.compno1; pi->compno++) { + comp = &pi->comps[pi->compno]; + if (pi->resno >= comp->numresolution[0]) { + continue; + } + res = &comp->resolutions[pi->resno]; + //for (pi->precno = 0; pi->precno < (res->prctno[0] * res->prctno[1]); pi->precno++) { + for (pi->precno = 0; pi->precno < (res->prctno[0] * res->prctno[1] * res->prctno[2]); pi->precno++) { + index = pi->layno * pi->step_l + + pi->resno * pi->step_r + + pi->compno * pi->step_c + + pi->precno * pi->step_p; + if (!pi->include[index]) { + pi->include[index] = 1; + return true; + } +LABEL_SKIP:; + + } + } + } + } + + return false; +} + +static bool pi_next_rlcp(opj_pi_iterator_t * pi) { + opj_pi_comp_t *comp = NULL; + opj_pi_resolution_t *res = NULL; + long index = 0; + + if (!pi->first) { + comp = &pi->comps[pi->compno]; + res = &comp->resolutions[pi->resno]; + goto LABEL_SKIP; + } else { + pi->first = 0; + } + + for (pi->resno = pi->poc.resno0; pi->resno < pi->poc.resno1; pi->resno++) { + for (pi->layno = 0; pi->layno < pi->poc.layno1; pi->layno++) { + for (pi->compno = pi->poc.compno0; pi->compno < pi->poc.compno1; pi->compno++) { + comp = &pi->comps[pi->compno]; + if (pi->resno >= comp->numresolution[0]) { + continue; + } + res = &comp->resolutions[pi->resno]; + //for (pi->precno = 0; pi->precno < (res->prctno[0] * res->prctno[1]); pi->precno++) { + for (pi->precno = 0; pi->precno < (res->prctno[0] * res->prctno[1] * res->prctno[2]); pi->precno++) { + index = pi->layno * pi->step_l + pi->resno * pi->step_r + pi->compno * pi->step_c + pi->precno * pi->step_p; + if (!pi->include[index]) { + pi->include[index] = 1; + return true; + } +LABEL_SKIP:; + } + } + } + } + + return false; +} + +static bool pi_next_rpcl(opj_pi_iterator_t * pi) { + opj_pi_comp_t *comp = NULL; + opj_pi_resolution_t *res = NULL; + long index = 0; + + if (!pi->first) { + goto LABEL_SKIP; + } else { + int compno, resno; + pi->first = 0; + pi->dx = 0; + pi->dy = 0; + for (compno = 0; compno < pi->numcomps; compno++) { + comp = &pi->comps[compno]; + for (resno = 0; resno < comp->numresolution[0]; resno++) { + int dx, dy,dz; + res = &comp->resolutions[resno]; + dx = comp->dx * (1 << (res->pdx + comp->numresolution[0] - 1 - resno)); + dy = comp->dy * (1 << (res->pdy + comp->numresolution[1] - 1 - resno)); + dz = comp->dz * (1 << (res->pdz + comp->numresolution[2] - 1 - resno)); + pi->dx = !pi->dx ? dx : int_min(pi->dx, dx); + pi->dy = !pi->dy ? dy : int_min(pi->dy, dy); + pi->dz = !pi->dz ? dz : int_min(pi->dz, dz); + } + } + } + + for (pi->resno = pi->poc.resno0; pi->resno < pi->poc.resno1; pi->resno++) { + for (pi->z = pi->tz0; pi->z < pi->tz1; pi->z += pi->dz - (pi->z % pi->dz)) { + for (pi->y = pi->ty0; pi->y < pi->ty1; pi->y += pi->dy - (pi->y % pi->dy)) { + for (pi->x = pi->tx0; pi->x < pi->tx1; pi->x += pi->dx - (pi->x % pi->dx)) { + for (pi->compno = pi->poc.compno0; pi->compno < pi->poc.compno1; pi->compno++) { + int levelnox, levelnoy, levelnoz; + int trx0, try0, trz0; + int trx1, try1, trz1; + int rpx, rpy, rpz; + int prci, prcj, prck; + comp = &pi->comps[pi->compno]; + if (pi->resno >= comp->numresolution[0]) { + continue; + } + res = &comp->resolutions[pi->resno]; + levelnox = comp->numresolution[0] - 1 - pi->resno; + levelnoy = comp->numresolution[1] - 1 - pi->resno; + levelnoz = comp->numresolution[2] - 1 - pi->resno; + trx0 = int_ceildiv(pi->tx0, comp->dx << levelnox); + try0 = int_ceildiv(pi->ty0, comp->dy << levelnoy); + trz0 = int_ceildiv(pi->tz0, comp->dz << levelnoz); + trx1 = int_ceildiv(pi->tx1, comp->dx << levelnox); + try1 = int_ceildiv(pi->ty1, comp->dy << levelnoy); + trz1 = int_ceildiv(pi->tz1, comp->dz << levelnoz); + rpx = res->pdx + levelnox; + rpy = res->pdy + levelnoy; + rpz = res->pdz + levelnoz; + if ((!(pi->x % (comp->dx << rpx) == 0) || (pi->x == pi->tx0 && (trx0 << levelnox) % (1 << rpx)))) { + continue; + } + if ((!(pi->y % (comp->dy << rpy) == 0) || (pi->y == pi->ty0 && (try0 << levelnoy) % (1 << rpx)))) { + continue; + } + if ((!(pi->z % (comp->dz << rpz) == 0) || (pi->z == pi->tz0 && (trz0 << levelnoz) % (1 << rpx)))) { + continue; + } + if ((res->prctno[0]==0)||(res->prctno[1]==0)||(res->prctno[2]==0)) continue; + + if ((trx0==trx1)||(try0==try1)||(trz0==trz1)) continue; + + prci = int_floordivpow2(int_ceildiv(pi->x, comp->dx << levelnox), res->pdx) + - int_floordivpow2(trx0, res->pdx); + prcj = int_floordivpow2(int_ceildiv(pi->y, comp->dy << levelnoy), res->pdy) + - int_floordivpow2(try0, res->pdy); + prck = int_floordivpow2(int_ceildiv(pi->z, comp->dz << levelnoz), res->pdz) + - int_floordivpow2(trz0, res->pdz); + pi->precno = prci + prcj * res->prctno[0] + prck * res->prctno[0] * res->prctno[1]; + for (pi->layno = 0; pi->layno < pi->poc.layno1; pi->layno++) { + index = pi->layno * pi->step_l + pi->resno * pi->step_r + pi->compno * pi->step_c + pi->precno * pi->step_p; + if (!pi->include[index]) { + pi->include[index] = 1; + return true; + } + LABEL_SKIP:; + } + } + } + } + } + } + + return false; +} + +static bool pi_next_pcrl(opj_pi_iterator_t * pi) { + opj_pi_comp_t *comp = NULL; + opj_pi_resolution_t *res = NULL; + long index = 0; + + if (!pi->first) { + comp = &pi->comps[pi->compno]; + goto LABEL_SKIP; + } else { + int compno, resno; + pi->first = 0; + pi->dx = 0; + pi->dy = 0; + pi->dz = 0; + for (compno = 0; compno < pi->numcomps; compno++) { + comp = &pi->comps[compno]; + for (resno = 0; resno < comp->numresolution[0]; resno++) { + int dx, dy, dz; + res = &comp->resolutions[resno]; + dx = comp->dx * (1 << (res->pdx + comp->numresolution[0] - 1 - resno)); + dy = comp->dy * (1 << (res->pdy + comp->numresolution[1] - 1 - resno)); + dz = comp->dz * (1 << (res->pdy + comp->numresolution[2] - 1 - resno)); + pi->dx = !pi->dx ? dx : int_min(pi->dx, dx); + pi->dy = !pi->dy ? dy : int_min(pi->dy, dy); + pi->dz = !pi->dz ? dz : int_min(pi->dz, dz); + } + } + } + +for (pi->z = pi->tz0; pi->z < pi->tz1; pi->z += pi->dz - (pi->z % pi->dz)) { + for (pi->y = pi->ty0; pi->y < pi->ty1; pi->y += pi->dy - (pi->y % pi->dy)) { + for (pi->x = pi->tx0; pi->x < pi->tx1; pi->x += pi->dx - (pi->x % pi->dx)) { + for (pi->compno = pi->poc.compno0; pi->compno < pi->poc.compno1; pi->compno++) { + comp = &pi->comps[pi->compno]; + for (pi->resno = pi->poc.resno0; pi->resno < int_min(pi->poc.resno1, comp->numresolution[0]); pi->resno++) { + int levelnox, levelnoy, levelnoz; + int trx0, try0, trz0; + int trx1, try1, trz1; + int rpx, rpy, rpz; + int prci, prcj, prck; + comp = &pi->comps[pi->compno]; + if (pi->resno >= comp->numresolution[0]) { + continue; + } + res = &comp->resolutions[pi->resno]; + levelnox = comp->numresolution[0] - 1 - pi->resno; + levelnoy = comp->numresolution[1] - 1 - pi->resno; + levelnoz = comp->numresolution[2] - 1 - pi->resno; + trx0 = int_ceildiv(pi->tx0, comp->dx << levelnox); + try0 = int_ceildiv(pi->ty0, comp->dy << levelnoy); + trz0 = int_ceildiv(pi->tz0, comp->dz << levelnoz); + trx1 = int_ceildiv(pi->tx1, comp->dx << levelnox); + try1 = int_ceildiv(pi->ty1, comp->dy << levelnoy); + trz1 = int_ceildiv(pi->tz1, comp->dz << levelnoz); + rpx = res->pdx + levelnox; + rpy = res->pdy + levelnoy; + rpz = res->pdz + levelnoz; + if ((!(pi->x % (comp->dx << rpx) == 0) || (pi->x == pi->tx0 && (trx0 << levelnox) % (1 << rpx)))) { + continue; + } + if ((!(pi->y % (comp->dy << rpy) == 0) || (pi->y == pi->ty0 && (try0 << levelnoy) % (1 << rpx)))) { + continue; + } + if ((!(pi->z % (comp->dz << rpz) == 0) || (pi->z == pi->tz0 && (trz0 << levelnoz) % (1 << rpx)))) { + continue; + } + if ((res->prctno[0]==0)||(res->prctno[1]==0)||(res->prctno[2]==0)) continue; + + if ((trx0==trx1)||(try0==try1)||(trz0==trz1)) continue; + + prci = int_floordivpow2(int_ceildiv(pi->x, comp->dx << levelnox), res->pdx) + - int_floordivpow2(trx0, res->pdx); + prcj = int_floordivpow2(int_ceildiv(pi->y, comp->dy << levelnoy), res->pdy) + - int_floordivpow2(try0, res->pdy); + prck = int_floordivpow2(int_ceildiv(pi->z, comp->dz << levelnoz), res->pdz) + - int_floordivpow2(trz0, res->pdz); + pi->precno = prci + prcj * res->prctno[0] + prck * res->prctno[0] * res->prctno[1]; + for (pi->layno = 0; pi->layno < pi->poc.layno1; pi->layno++) { + index = pi->layno * pi->step_l + pi->resno * pi->step_r + pi->compno * pi->step_c + pi->precno * pi->step_p; + if (!pi->include[index]) { + pi->include[index] = 1; + return true; + } +LABEL_SKIP:; + } + } + } + } + } +} + + return false; +} + +static bool pi_next_cprl(opj_pi_iterator_t * pi) { + opj_pi_comp_t *comp = NULL; + opj_pi_resolution_t *res = NULL; + long index = 0; + + if (!pi->first) { + comp = &pi->comps[pi->compno]; + goto LABEL_SKIP; + } else { + pi->first = 0; + } + + for (pi->compno = pi->poc.compno0; pi->compno < pi->poc.compno1; pi->compno++) { + int resno; + comp = &pi->comps[pi->compno]; + pi->dx = 0; + pi->dy = 0; + for (resno = 0; resno < comp->numresolution[0]; resno++) { + int dx, dy; + res = &comp->resolutions[resno]; + dx = comp->dx * (1 << (res->pdx + comp->numresolution[0] - 1 - resno)); + dy = comp->dy * (1 << (res->pdy + comp->numresolution[0] - 1 - resno)); + pi->dx = !pi->dx ? dx : int_min(pi->dx, dx); + pi->dy = !pi->dy ? dy : int_min(pi->dy, dy); + } + for (pi->z = pi->tz0; pi->z < pi->tz1; pi->z += pi->dz - (pi->z % pi->dz)) { + for (pi->y = pi->ty0; pi->y < pi->ty1; pi->y += pi->dy - (pi->y % pi->dy)) { + for (pi->x = pi->tx0; pi->x < pi->tx1; pi->x += pi->dx - (pi->x % pi->dx)) { + for (pi->resno = pi->poc.resno0; pi->resno < int_min(pi->poc.resno1, comp->numresolution[0]); pi->resno++) { + int levelnox, levelnoy, levelnoz; + int trx0, try0, trz0; + int trx1, try1, trz1; + int rpx, rpy, rpz; + int prci, prcj, prck; + comp = &pi->comps[pi->compno]; + if (pi->resno >= comp->numresolution[0]) { + continue; + } + res = &comp->resolutions[pi->resno]; + levelnox = comp->numresolution[0] - 1 - pi->resno; + levelnoy = comp->numresolution[1] - 1 - pi->resno; + levelnoz = comp->numresolution[2] - 1 - pi->resno; + trx0 = int_ceildiv(pi->tx0, comp->dx << levelnox); + try0 = int_ceildiv(pi->ty0, comp->dy << levelnoy); + trz0 = int_ceildiv(pi->tz0, comp->dz << levelnoz); + trx1 = int_ceildiv(pi->tx1, comp->dx << levelnox); + try1 = int_ceildiv(pi->ty1, comp->dy << levelnoy); + trz1 = int_ceildiv(pi->tz1, comp->dz << levelnoz); + rpx = res->pdx + levelnox; + rpy = res->pdy + levelnoy; + rpz = res->pdz + levelnoz; + if ((!(pi->x % (comp->dx << rpx) == 0) || (pi->x == pi->tx0 && (trx0 << levelnox) % (1 << rpx)))) { + continue; + } + if ((!(pi->y % (comp->dy << rpy) == 0) || (pi->y == pi->ty0 && (try0 << levelnoy) % (1 << rpx)))) { + continue; + } + if ((!(pi->z % (comp->dz << rpz) == 0) || (pi->z == pi->tz0 && (trz0 << levelnoz) % (1 << rpx)))) { + continue; + } + if ((res->prctno[0]==0)||(res->prctno[1]==0)||(res->prctno[2]==0)) continue; + + if ((trx0==trx1)||(try0==try1)||(trz0==trz1)) continue; + + prci = int_floordivpow2(int_ceildiv(pi->x, comp->dx << levelnox), res->pdx) + - int_floordivpow2(trx0, res->pdx); + prcj = int_floordivpow2(int_ceildiv(pi->y, comp->dy << levelnoy), res->pdy) + - int_floordivpow2(try0, res->pdy); + prck = int_floordivpow2(int_ceildiv(pi->z, comp->dz << levelnoz), res->pdz) + - int_floordivpow2(trz0, res->pdz); + pi->precno = prci + prcj * res->prctno[0] + prck * res->prctno[0] * res->prctno[1]; + for (pi->layno = 0; pi->layno < pi->poc.layno1; pi->layno++) { + index = pi->layno * pi->step_l + pi->resno * pi->step_r + pi->compno * pi->step_c + pi->precno * pi->step_p; + if (!pi->include[index]) { + pi->include[index] = 1; + return true; + } + LABEL_SKIP:; + } + } + } + } + } + } + + return false; +} + +/* +========================================================== + Packet iterator interface +========================================================== +*/ + +opj_pi_iterator_t *pi_create(opj_volume_t *volume, opj_cp_t *cp, int tileno) { + int p, q, r; + int compno, resno, pino; + opj_pi_iterator_t *pi = NULL; + opj_tcp_t *tcp = NULL; + opj_tccp_t *tccp = NULL; + size_t array_size; + + tcp = &cp->tcps[tileno]; + + array_size = (tcp->numpocs + 1) * sizeof(opj_pi_iterator_t); + pi = (opj_pi_iterator_t *) opj_malloc(array_size); + if(!pi) { + fprintf(stdout,"[ERROR] Malloc of opj_pi_iterator failed \n"); + return NULL; + } + + for (pino = 0; pino < tcp->numpocs + 1; pino++) { /* change */ + int maxres = 0; + int maxprec = 0; + p = tileno % cp->tw; + q = tileno / cp->tw; + r = tileno / (cp->tw * cp->th); + + pi[pino].tx0 = int_max(cp->tx0 + p * cp->tdx, volume->x0); + pi[pino].ty0 = int_max(cp->ty0 + q * cp->tdy, volume->y0); + pi[pino].tz0 = int_max(cp->tz0 + r * cp->tdz, volume->z0); + pi[pino].tx1 = int_min(cp->tx0 + (p + 1) * cp->tdx, volume->x1); + pi[pino].ty1 = int_min(cp->ty0 + (q + 1) * cp->tdy, volume->y1); + pi[pino].tz1 = int_min(cp->tz0 + (r + 1) * cp->tdz, volume->z1); + pi[pino].numcomps = volume->numcomps; + + array_size = volume->numcomps * sizeof(opj_pi_comp_t); + pi[pino].comps = (opj_pi_comp_t *) opj_malloc(array_size); + if(!pi[pino].comps) { + fprintf(stdout,"[ERROR] Malloc of opj_pi_comp failed \n"); + pi_destroy(pi, cp, tileno); + return NULL; + } + memset(pi[pino].comps, 0, array_size); + + for (compno = 0; compno < pi->numcomps; compno++) { + int tcx0, tcx1, tcy0, tcy1, tcz0, tcz1; + int i; + opj_pi_comp_t *comp = &pi[pino].comps[compno]; + tccp = &tcp->tccps[compno]; + + comp->dx = volume->comps[compno].dx; + comp->dy = volume->comps[compno].dy; + comp->dz = volume->comps[compno].dz; + for (i = 0; i < 3; i++) { + comp->numresolution[i] = tccp->numresolution[i]; + if (comp->numresolution[i] > maxres) { + maxres = comp->numresolution[i]; + } + } + array_size = comp->numresolution[0] * sizeof(opj_pi_resolution_t); + comp->resolutions = (opj_pi_resolution_t *) opj_malloc(array_size); + if(!comp->resolutions) { + fprintf(stdout,"[ERROR] Malloc of opj_pi_resolution failed \n"); + pi_destroy(pi, cp, tileno); + return NULL; + } + + tcx0 = int_ceildiv(pi->tx0, comp->dx); + tcy0 = int_ceildiv(pi->ty0, comp->dy); + tcz0 = int_ceildiv(pi->tz0, comp->dz); + tcx1 = int_ceildiv(pi->tx1, comp->dx); + tcy1 = int_ceildiv(pi->ty1, comp->dy); + tcz1 = int_ceildiv(pi->tz1, comp->dz); + + for (resno = 0; resno < comp->numresolution[0]; resno++) { + int levelnox, levelnoy, levelnoz, diff; + int rx0, ry0, rz0, rx1, ry1, rz1; + int px0, py0, pz0, px1, py1, pz1; + opj_pi_resolution_t *res = &comp->resolutions[resno]; + if (tccp->csty & J3D_CCP_CSTY_PRT) { + res->pdx = tccp->prctsiz[0][resno]; + res->pdy = tccp->prctsiz[1][resno]; + res->pdz = tccp->prctsiz[2][resno]; + } else { + res->pdx = 15; + res->pdy = 15; + res->pdz = 15; + } + levelnox = comp->numresolution[0] - 1 - resno; + levelnoy = comp->numresolution[1] - 1 - resno; + levelnoz = comp->numresolution[2] - 1 - resno; + if (levelnoz < 0) levelnoz = 0; + diff = comp->numresolution[0] - comp->numresolution[2]; + + rx0 = int_ceildivpow2(tcx0, levelnox); + ry0 = int_ceildivpow2(tcy0, levelnoy); + rz0 = int_ceildivpow2(tcz0, levelnoz); + rx1 = int_ceildivpow2(tcx1, levelnox); + ry1 = int_ceildivpow2(tcy1, levelnoy); + rz1 = int_ceildivpow2(tcz1, levelnoz); + px0 = int_floordivpow2(rx0, res->pdx) << res->pdx; + py0 = int_floordivpow2(ry0, res->pdy) << res->pdy; + pz0 = int_floordivpow2(rz0, res->pdz) << res->pdz; + px1 = int_ceildivpow2(rx1, res->pdx) << res->pdx; + py1 = int_ceildivpow2(ry1, res->pdy) << res->pdy; + pz1 = int_ceildivpow2(rz1, res->pdz) << res->pdz; + res->prctno[0] = (rx0==rx1)? 0 : ((px1 - px0) >> res->pdx); + res->prctno[1] = (ry0==ry1)? 0 : ((py1 - py0) >> res->pdy); + res->prctno[2] = (rz0==rz1)? 0 : ((pz1 - pz0) >> res->pdz); + + if (res->prctno[0]*res->prctno[1]*res->prctno[2] > maxprec) { + maxprec = res->prctno[0]*res->prctno[1]*res->prctno[2]; + } + } + } + + tccp = &tcp->tccps[0]; + pi[pino].step_p = 1; + pi[pino].step_c = maxprec * pi[pino].step_p; + pi[pino].step_r = volume->numcomps * pi[pino].step_c; + pi[pino].step_l = maxres * pi[pino].step_r; + + if (pino == 0) { + array_size = volume->numcomps * maxres * tcp->numlayers * maxprec * sizeof(short int); + pi[pino].include = (short int *) opj_malloc(array_size); + if(!pi[pino].include) { + fprintf(stdout,"[ERROR] Malloc of pi[pino].include failed \n"); + pi_destroy(pi, cp, tileno); + return NULL; + } + } + else { + pi[pino].include = pi[pino - 1].include; + } + + if (tcp->POC == 0) { + pi[pino].first = 1; + pi[pino].poc.resno0 = 0; + pi[pino].poc.compno0 = 0; + pi[pino].poc.layno1 = tcp->numlayers; + pi[pino].poc.resno1 = maxres; + pi[pino].poc.compno1 = volume->numcomps; + pi[pino].poc.prg = tcp->prg; + } else { + pi[pino].first = 1; + pi[pino].poc.resno0 = tcp->pocs[pino].resno0; + pi[pino].poc.compno0 = tcp->pocs[pino].compno0; + pi[pino].poc.layno1 = tcp->pocs[pino].layno1; + pi[pino].poc.resno1 = tcp->pocs[pino].resno1; + pi[pino].poc.compno1 = tcp->pocs[pino].compno1; + pi[pino].poc.prg = tcp->pocs[pino].prg; + } + } + + return pi; +} + +void pi_destroy(opj_pi_iterator_t *pi, opj_cp_t *cp, int tileno) { + int compno, pino; + opj_tcp_t *tcp = &cp->tcps[tileno]; + if(pi) { + for (pino = 0; pino < tcp->numpocs + 1; pino++) { + if(pi[pino].comps) { + for (compno = 0; compno < pi->numcomps; compno++) { + opj_pi_comp_t *comp = &pi[pino].comps[compno]; + if(comp->resolutions) { + opj_free(comp->resolutions); + } + } + opj_free(pi[pino].comps); + } + } + if(pi->include) { + opj_free(pi->include); + } + opj_free(pi); + } +} + +bool pi_next(opj_pi_iterator_t * pi) { + switch (pi->poc.prg) { + case LRCP: + return pi_next_lrcp(pi); + case RLCP: + return pi_next_rlcp(pi); + case RPCL: + return pi_next_rpcl(pi); + case PCRL: + return pi_next_pcrl(pi); + case CPRL: + return pi_next_cprl(pi); + } + + return false; +} + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/pi.h b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/pi.h new file mode 100644 index 0000000..92c5abc --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/pi.h @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * Copyright (c) 2006, Mónica Díez García, Image Processing Laboratory, University of Valladolid, Spain + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __PI_H +#define __PI_H +/** +@file pi.h +@brief Implementation of a packet iterator (PI) + +The functions in PI.C have for goal to realize a packet iterator that permits to get the next +packet following the progression order and change of it. The functions in PI.C are used +by some function in T2.C. +*/ + +/** @defgroup PI PI - Implementation of a packet iterator */ +/*@{*/ + +/** +Packet iterator : resolution level information +*/ +typedef struct opj_pi_resolution { +/** Size of precints in horizontal axis */ + int pdx; +/** Size of precints in vertical axis */ + int pdy; +/** Size of precints in axial axis */ + int pdz; +/** Number of precints in each axis */ + int prctno[3]; +} opj_pi_resolution_t; + +/** +Packet iterator : component information +*/ +typedef struct opj_pi_comp { +/** Size in horizontal axis */ + int dx; +/** Size in vertical axis */ + int dy; +/** Size in axial axis */ + int dz; +/** Number of resolution levels */ + int numresolution[3]; +/** Packet iterator : resolution level information */ + opj_pi_resolution_t *resolutions; +} opj_pi_comp_t; + +/** +Packet iterator +*/ +typedef struct opj_pi_iterator { +/** precise if the packet has been already used (usefull for progression order change) */ + short int *include; +/** layer step used to localize the packet in the include vector */ + int step_l; +/** resolution step used to localize the packet in the include vector */ + int step_r; +/** component step used to localize the packet in the include vector */ + int step_c; +/** precinct step used to localize the packet in the include vector */ + int step_p; +/** component that identify the packet */ + int compno; +/** resolution that identify the packet */ + int resno; +/** precinct that identify the packet */ + int precno; +/** layer that identify the packet */ + int layno; +/** 0 if the first packet */ + int first; +/** progression order change information */ + opj_poc_t poc; +/** Packet iterator : component information */ +opj_pi_comp_t *comps; + + int numcomps; + int tx0, ty0, tz0; + int tx1, ty1, tz1; + int x, y, z; + int dx, dy, dz; +} opj_pi_iterator_t; + +/** @name Funciones generales */ +/*@{*/ +/* ----------------------------------------------------------------------- */ +/** +Create a packet iterator +@param volume Raw volume for which the packets will be listed +@param cp Coding parameters +@param tileno Number that identifies the tile for which to list the packets +@return Returns a packet iterator that points to the first packet of the tile +@see pi_destroy +*/ +opj_pi_iterator_t *pi_create(opj_volume_t * volume, opj_cp_t * cp, int tileno); + +/** +Destroy a packet iterator +@param pi Previously created packet iterator +@param cp Coding parameters +@param tileno Number that identifies the tile for which the packets were listed +@see pi_create +*/ +void pi_destroy(opj_pi_iterator_t *pi, opj_cp_t *cp, int tileno); + +/** +Modify the packet iterator to point to the next packet +@param pi Packet iterator to modify +@return Returns false if pi pointed to the last packet or else returns true +*/ +bool pi_next(opj_pi_iterator_t * pi); +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __PI_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/raw.c b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/raw.c new file mode 100644 index 0000000..a008be1 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/raw.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "opj_includes.h" + +/* +========================================================== + local functions +========================================================== +*/ + + +/* +========================================================== + RAW encoding interface +========================================================== +*/ + +opj_raw_t* raw_create() { + opj_raw_t *raw = (opj_raw_t*)opj_malloc(sizeof(opj_raw_t)); + return raw; +} + +void raw_destroy(opj_raw_t *raw) { + if(raw) { + opj_free(raw); + } +} + +int raw_numbytes(opj_raw_t *raw) { + return raw->bp - raw->start; +} + +void raw_init_dec(opj_raw_t *raw, unsigned char *bp, int len) { + raw->start = bp; + raw->lenmax = len; + raw->len = 0; + raw->c = 0; + raw->ct = 0; +} + +int raw_decode(opj_raw_t *raw) { + int d; + if (raw->ct == 0) { + raw->ct = 8; + if (raw->len == raw->lenmax) { + raw->c = 0xff; + } else { + if (raw->c == 0xff) { + raw->ct = 7; + } + raw->c = *(raw->start + raw->len); + raw->len++; + } + } + raw->ct--; + d = (raw->c >> raw->ct) & 0x01; + + return d; +} + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/raw.h b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/raw.h new file mode 100644 index 0000000..de3cd56 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/raw.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __RAW_H +#define __RAW_H +/** +@file raw.h +@brief Implementation of operations for raw encoding (RAW) + +The functions in RAW.C have for goal to realize the operation of raw encoding linked +with the corresponding mode switch. +*/ + +/** @defgroup RAW RAW - Implementation of operations for raw encoding */ +/*@{*/ + +/** +RAW encoding operations +*/ +typedef struct opj_raw { +/** Temporary buffer where bits are coded or decoded */ + unsigned char c; +/** Number of bits already read or free to write */ + unsigned int ct; +/** Maximum length to decode */ + unsigned int lenmax; +/** Length decoded */ + unsigned int len; +/** Pointer to the current position in the buffer */ + unsigned char *bp; +/** Pointer to the start of the buffer */ + unsigned char *start; +/** Pointer to the end of the buffer */ + unsigned char *end; +} opj_raw_t; + +/** @name Funciones generales */ +/*@{*/ +/* ----------------------------------------------------------------------- */ +/** +Create a new RAW handle +@return Returns a new RAW handle if successful, returns NULL otherwise +*/ +opj_raw_t* raw_create(); +/** +Destroy a previously created RAW handle +@param raw RAW handle to destroy +*/ +void raw_destroy(opj_raw_t *raw); +/** +Return the number of bytes written/read since initialisation +@param raw RAW handle to destroy +@return Returns the number of bytes already encoded +*/ +int raw_numbytes(opj_raw_t *raw); +/** +Initialize the decoder +@param raw RAW handle +@param bp Pointer to the start of the buffer from which the bytes will be read +@param len Length of the input buffer +*/ +void raw_init_dec(opj_raw_t *raw, unsigned char *bp, int len); +/** +Decode a symbol using raw-decoder. Cfr p.506 TAUBMAN +@param raw RAW handle +@return Returns the decoded symbol (0 or 1) +*/ +int raw_decode(opj_raw_t *raw); +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __RAW_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/t1.c b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/t1.c new file mode 100644 index 0000000..f2a8d45 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/t1.c @@ -0,0 +1,1181 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "opj_includes.h" + +/** @defgroup T1 T1 - Implementation of the tier-1 coding */ +/*@{*/ + +/** @name Local static functions */ +/*@{*/ + +static int t1_getctxno_zc(opj_t1_t *t1, int f, int orient); +static int t1_getctxno_sc(opj_t1_t *t1, int f); +static int t1_getctxno_mag(opj_t1_t *t1, int f); +static int t1_getspb(opj_t1_t *t1, int f); +static int t1_getnmsedec_sig(opj_t1_t *t1, int x, int bitpos); +static int t1_getnmsedec_ref(opj_t1_t *t1, int x, int bitpos); +static void t1_updateflags(int *fp, int s); +/** +Encode significant pass +*/ +static void t1_enc_sigpass_step(opj_t1_t *t1, int *fp, int *dp, int orient, int bpno, int one, int *nmsedec, char type, int vsc); +/** +Decode significant pass +*/ +static void t1_dec_sigpass_step(opj_t1_t *t1, int *fp, int *dp, int orient, int oneplushalf, char type, int vsc); +/** +Encode significant pass +*/ +static void t1_enc_sigpass(opj_t1_t *t1, int w, int h, int l, int bpno, int orient, int *nmsedec, char type, int cblksty); +/** +Decode significant pass +*/ +static void t1_dec_sigpass(opj_t1_t *t1, int w, int h, int l, int bpno, int orient, char type, int cblksty); +/** +Encode refinement pass +*/ +static void t1_enc_refpass_step(opj_t1_t *t1, int *fp, int *dp, int bpno, int one, int *nmsedec, char type, int vsc); +/** +Decode refinement pass +*/ +static void t1_dec_refpass_step(opj_t1_t *t1, int *fp, int *dp, int poshalf, int neghalf, char type, int vsc); +/** +Encode refinement pass +*/ +static void t1_enc_refpass(opj_t1_t *t1, int w, int h, int l, int bpno, int *nmsedec, char type, int cblksty); +/** +Decode refinement pass +*/ +static void t1_dec_refpass(opj_t1_t *t1, int w, int h, int l, int bpno, char type, int cblksty); +/** +Encode clean-up pass +*/ +static void t1_enc_clnpass_step(opj_t1_t *t1, int *fp, int *dp, int orient, int bpno, int one, int *nmsedec, int partial, int vsc); +/** +Decode clean-up pass +*/ +static void t1_dec_clnpass_step(opj_t1_t *t1, int *fp, int *dp, int orient, int oneplushalf, int partial, int vsc); +/** +Encode clean-up pass +*/ +static void t1_enc_clnpass(opj_t1_t *t1, int w, int h, int l, int bpno, int orient, int *nmsedec, int cblksty); +/** +Decode clean-up pass +*/ +static void t1_dec_clnpass(opj_t1_t *t1, int w, int h, int l, int bpno, int orient, int cblksty); +/** +Encode 1 code-block +@param t1 T1 handle +@param cblk Code-block coding parameters +@param orient +@param compno Component number +@param level +@param dwtid +@param stepsize +@param cblksty Code-block style +@param numcomps +@param tile +*/ +static void t1_encode_cblk(opj_t1_t *t1, opj_tcd_cblk_t * cblk, int orient, int compno, int level[3], int dwtid[3], double stepsize, int cblksty, int numcomps, opj_tcd_tile_t * tile); +/** +Decode 1 code-block +@param t1 T1 handle +@param cblk Code-block coding parameters +@param orient +@param roishift Region of interest shifting value +@param cblksty Code-block style +*/ +static void t1_decode_cblk(opj_t1_t *t1, opj_tcd_cblk_t * cblk, int orient, int roishift, int cblksty); + +static int t1_init_ctxno_zc(int f, int orient); +static int t1_init_ctxno_sc(int f); +static int t1_init_ctxno_mag(int f); +static int t1_init_spb(int f); +/** +Initialize the look-up tables of the Tier-1 coder/decoder +@param t1 T1 handle +*/ +static void t1_init_luts(opj_t1_t *t1); + +/*@}*/ + +/*@}*/ + +/* ----------------------------------------------------------------------- */ + +static int t1_getctxno_zc(opj_t1_t *t1, int f, int orient) { + return t1->lut_ctxno_zc[(orient << 8) | (f & T1_SIG_OTH)]; +} + +static int t1_getctxno_sc(opj_t1_t *t1, int f) { + return t1->lut_ctxno_sc[(f & (T1_SIG_PRIM | T1_SGN)) >> 4]; +} + +static int t1_getctxno_mag(opj_t1_t *t1, int f) { + return t1->lut_ctxno_mag[(f & T1_SIG_OTH) | (((f & T1_REFINE) != 0) << 11)]; +} + +static int t1_getspb(opj_t1_t *t1, int f) { + return t1->lut_spb[(f & (T1_SIG_PRIM | T1_SGN)) >> 4]; +} + +static int t1_getnmsedec_sig(opj_t1_t *t1, int x, int bitpos) { + if (bitpos > T1_NMSEDEC_FRACBITS) { + return t1->lut_nmsedec_sig[(x >> (bitpos - T1_NMSEDEC_FRACBITS)) & ((1 << T1_NMSEDEC_BITS) - 1)]; + } + + return t1->lut_nmsedec_sig0[x & ((1 << T1_NMSEDEC_BITS) - 1)]; +} + +static int t1_getnmsedec_ref(opj_t1_t *t1, int x, int bitpos) { + if (bitpos > T1_NMSEDEC_FRACBITS) { + return t1->lut_nmsedec_ref[(x >> (bitpos - T1_NMSEDEC_FRACBITS)) & ((1 << T1_NMSEDEC_BITS) - 1)]; + } + + return t1->lut_nmsedec_ref0[x & ((1 << T1_NMSEDEC_BITS) - 1)]; +} + +static void t1_updateflags(int *fp, int s) { + int *np = fp - (T1_MAXCBLKW + 2); + int *sp = fp + (T1_MAXCBLKW + 2); + np[-1] |= T1_SIG_SE; + np[1] |= T1_SIG_SW; + sp[-1] |= T1_SIG_NE; + sp[1] |= T1_SIG_NW; + *np |= T1_SIG_S; + *sp |= T1_SIG_N; + fp[-1] |= T1_SIG_E; + fp[1] |= T1_SIG_W; + if (s) { + *np |= T1_SGN_S; + *sp |= T1_SGN_N; + fp[-1] |= T1_SGN_E; + fp[1] |= T1_SGN_W; + } +} + +static void t1_enc_sigpass_step(opj_t1_t *t1, int *fp, int *dp, int orient, int bpno, int one, int *nmsedec, char type, int vsc) { + int v, flag; + + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + flag = vsc ? ((*fp) & (~(T1_SIG_S | T1_SIG_SE | T1_SIG_SW | T1_SGN_S))) : (*fp); + if ((flag & T1_SIG_OTH) && !(flag & (T1_SIG | T1_VISIT))) { + v = int_abs(*dp) & one ? 1 : 0; + if (type == T1_TYPE_RAW) { /* BYPASS/LAZY MODE */ + mqc_setcurctx(mqc, t1_getctxno_zc(t1, flag, orient)); /* ESSAI */ + mqc_bypass_enc(mqc, v); + } else { + mqc_setcurctx(mqc, t1_getctxno_zc(t1, flag, orient)); + mqc_encode(mqc, v); + } + if (v) { + v = *dp < 0 ? 1 : 0; + *nmsedec += t1_getnmsedec_sig(t1, int_abs(*dp), bpno + T1_NMSEDEC_FRACBITS); + if (type == T1_TYPE_RAW) { /* BYPASS/LAZY MODE */ + mqc_setcurctx(mqc, t1_getctxno_sc(t1, flag)); /* ESSAI */ + mqc_bypass_enc(mqc, v); + } else { + mqc_setcurctx(mqc, t1_getctxno_sc(t1, flag)); + mqc_encode(mqc, v ^ t1_getspb(t1, flag)); + } + t1_updateflags(fp, v); + *fp |= T1_SIG; + } + *fp |= T1_VISIT; + } +} + +static void t1_dec_sigpass_step(opj_t1_t *t1, int *fp, int *dp, int orient, int oneplushalf, char type, int vsc) { + int v, flag; + + opj_raw_t *raw = t1->raw; /* RAW component */ + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + flag = vsc ? ((*fp) & (~(T1_SIG_S | T1_SIG_SE | T1_SIG_SW | T1_SGN_S))) : (*fp); + if ((flag & T1_SIG_OTH) && !(flag & (T1_SIG | T1_VISIT))) { + if (type == T1_TYPE_RAW) { + if (raw_decode(raw)) { + v = raw_decode(raw); /* ESSAI */ + *dp = v ? -oneplushalf : oneplushalf; + t1_updateflags(fp, v); + *fp |= T1_SIG; + } + } else { + mqc_setcurctx(mqc, t1_getctxno_zc(t1, flag, orient)); + if (mqc_decode(mqc)) { + mqc_setcurctx(mqc, t1_getctxno_sc(t1, flag)); + v = mqc_decode(mqc) ^ t1_getspb(t1, flag); + *dp = v ? -oneplushalf : oneplushalf; + t1_updateflags(fp, v); + *fp |= T1_SIG; + } + } + *fp |= T1_VISIT; + } +} /* VSC and BYPASS by Antonin */ + +static void t1_enc_sigpass(opj_t1_t *t1, int w, int h, int l, int bpno, int orient, int *nmsedec, char type, int cblksty) { + int i, j, k, m, one, vsc; + *nmsedec = 0; + one = 1 << (bpno + T1_NMSEDEC_FRACBITS); + for (m = 0; m < l; m++) { + for (k = 0; k < h; k += 4) { + for (i = 0; i < w; i++) { + for (j = k; j < k + 4 && j < h; j++) { + vsc = ((cblksty & J3D_CCP_CBLKSTY_VSC) && (j == k + 3 || j == h - 1)) ? 1 : 0; + t1_enc_sigpass_step(t1, &t1->flags[1 + m][1 + j][1 + i], &t1->data[m][j][i], orient, bpno, one, nmsedec, type, vsc); + } + } + } + } +} + +static void t1_dec_sigpass(opj_t1_t *t1, int w, int h, int l, int bpno, int orient, char type, int cblksty) { + int i, j, k, m, one, half, oneplushalf, vsc; + one = 1 << bpno; + half = one >> 1; + oneplushalf = one | half; + for (m = 0; m < l; m++) { + for (k = 0; k < h; k += 4) { + for (i = 0; i < w; i++) { + for (j = k; j < k + 4 && j < h; j++) { + vsc = ((cblksty & J3D_CCP_CBLKSTY_VSC) && (j == k + 3 || j == h - 1)) ? 1 : 0; + t1_dec_sigpass_step(t1, &t1->flags[1 + m][1 + j][1 + i], &t1->data[m][j][i], orient, oneplushalf, type, vsc); + } + } + } + } +} /* VSC and BYPASS by Antonin */ + +static void t1_enc_refpass_step(opj_t1_t *t1, int *fp, int *dp, int bpno, int one, int *nmsedec, char type, int vsc) { + int v, flag; + + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + flag = vsc ? ((*fp) & (~(T1_SIG_S | T1_SIG_SE | T1_SIG_SW | T1_SGN_S))) : (*fp); + if ((flag & (T1_SIG | T1_VISIT)) == T1_SIG) { + *nmsedec += t1_getnmsedec_ref(t1, int_abs(*dp), bpno + T1_NMSEDEC_FRACBITS); + v = int_abs(*dp) & one ? 1 : 0; + if (type == T1_TYPE_RAW) { /* BYPASS/LAZY MODE */ + mqc_setcurctx(mqc, t1_getctxno_mag(t1, flag)); /* ESSAI */ + mqc_bypass_enc(mqc, v); + } else { + mqc_setcurctx(mqc, t1_getctxno_mag(t1, flag)); + mqc_encode(mqc, v); + } + *fp |= T1_REFINE; + } +} + +static void t1_dec_refpass_step(opj_t1_t *t1, int *fp, int *dp, int poshalf, int neghalf, char type, int vsc) { + int v, t, flag; + + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + opj_raw_t *raw = t1->raw; /* RAW component */ + + flag = vsc ? ((*fp) & (~(T1_SIG_S | T1_SIG_SE | T1_SIG_SW | T1_SGN_S))) : (*fp); + if ((flag & (T1_SIG | T1_VISIT)) == T1_SIG) { + if (type == T1_TYPE_RAW) { + mqc_setcurctx(mqc, t1_getctxno_mag(t1, flag)); /* ESSAI */ + v = raw_decode(raw); + } else { + mqc_setcurctx(mqc, t1_getctxno_mag(t1, flag)); + v = mqc_decode(mqc); + } + t = v ? poshalf : neghalf; + *dp += *dp < 0 ? -t : t; + *fp |= T1_REFINE; + } +} /* VSC and BYPASS by Antonin */ + +static void t1_enc_refpass(opj_t1_t *t1, int w, int h, int l, int bpno, int *nmsedec, char type, int cblksty) { + int i, j, k, m, one, vsc; + *nmsedec = 0; + one = 1 << (bpno + T1_NMSEDEC_FRACBITS); + for (m = 0; m < l; m++) { + for (k = 0; k < h; k += 4) { + for (i = 0; i < w; i++) { + for (j = k; j < k + 4 && j < h; j++) { + vsc = ((cblksty & J3D_CCP_CBLKSTY_VSC) && (j == k + 3 || j == h - 1)) ? 1 : 0; + t1_enc_refpass_step(t1, &t1->flags[1 + m][1 + j][1 + i], &t1->data[m][j][i], bpno, one, nmsedec, type, vsc); + } + } + } + } +} + +static void t1_dec_refpass(opj_t1_t *t1, int w, int h, int l, int bpno, char type, int cblksty) { + int i, j, k, m, one, poshalf, neghalf; + int vsc; + one = 1 << bpno; + poshalf = one >> 1; + neghalf = bpno > 0 ? -poshalf : -1; + for (m = 0; m < l; m++) { + for (k = 0; k < h; k += 4) { + for (i = 0; i < w; i++) { + for (j = k; j < k + 4 && j < h; j++) { + vsc = ((cblksty & J3D_CCP_CBLKSTY_VSC) && (j == k + 3 || j == h - 1)) ? 1 : 0; + t1_dec_refpass_step(t1, &t1->flags[1 + m][1 + j][1 + i], &t1->data[m][j][i], poshalf, neghalf, type, vsc); + } + } + } + } +} /* VSC and BYPASS by Antonin */ + +static void t1_enc_clnpass_step(opj_t1_t *t1, int *fp, int *dp, int orient, int bpno, int one, int *nmsedec, int partial, int vsc) { + int v, flag; + + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + flag = vsc ? ((*fp) & (~(T1_SIG_S | T1_SIG_SE | T1_SIG_SW | T1_SGN_S))) : (*fp); + if (partial) { + goto LABEL_PARTIAL; + } + if (!(*fp & (T1_SIG | T1_VISIT))) { + mqc_setcurctx(mqc, t1_getctxno_zc(t1, flag, orient)); + v = int_abs(*dp) & one ? 1 : 0; + mqc_encode(mqc, v); + if (v) { +LABEL_PARTIAL: + *nmsedec += t1_getnmsedec_sig(t1, int_abs(*dp), bpno + T1_NMSEDEC_FRACBITS); + mqc_setcurctx(mqc, t1_getctxno_sc(t1, flag)); + v = *dp < 0 ? 1 : 0; + mqc_encode(mqc, v ^ t1_getspb(t1, flag)); + t1_updateflags(fp, v); + *fp |= T1_SIG; + } + } + *fp &= ~T1_VISIT; +} + +static void t1_dec_clnpass_step(opj_t1_t *t1, int *fp, int *dp, int orient, int oneplushalf, int partial, int vsc) { + int v, flag; + + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + flag = vsc ? ((*fp) & (~(T1_SIG_S | T1_SIG_SE | T1_SIG_SW | T1_SGN_S))) : (*fp); + if (partial) { + goto LABEL_PARTIAL; + } + if (!(flag & (T1_SIG | T1_VISIT))) { + mqc_setcurctx(mqc, t1_getctxno_zc(t1, flag, orient)); + if (mqc_decode(mqc)) { +LABEL_PARTIAL: + mqc_setcurctx(mqc, t1_getctxno_sc(t1, flag)); + v = mqc_decode(mqc) ^ t1_getspb(t1, flag); + *dp = v ? -oneplushalf : oneplushalf; + t1_updateflags(fp, v); + *fp |= T1_SIG; + } + } + *fp &= ~T1_VISIT; +} /* VSC and BYPASS by Antonin */ + +static void t1_enc_clnpass(opj_t1_t *t1, int w, int h, int l, int bpno, int orient, int *nmsedec, int cblksty) { + int i, j, k, m, one, agg, runlen, vsc; + + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + *nmsedec = 0; + one = 1 << (bpno + T1_NMSEDEC_FRACBITS); + for (m = 0; m < l; m++) { + for (k = 0; k < h; k += 4) { + for (i = 0; i < w; i++) { + if (k + 3 < h) { + if (cblksty & J3D_CCP_CBLKSTY_VSC) { + agg = !(t1->flags[1 + m][1 + k][1 + i] & (T1_SIG | T1_VISIT | T1_SIG_OTH) + || t1->flags[1 + m][1 + k + 1][1 + i] & (T1_SIG | T1_VISIT | T1_SIG_OTH) + || t1->flags[1 + m][1 + k + 2][1 + i] & (T1_SIG | T1_VISIT | T1_SIG_OTH) + || (t1->flags[1 + m][1 + k + 3][1 + i] + & (~(T1_SIG_S | T1_SIG_SE | T1_SIG_SW | T1_SGN_S))) & (T1_SIG | T1_VISIT | T1_SIG_OTH)); + } else { + agg = !(t1->flags[1 + m][1 + k][1 + i] & (T1_SIG | T1_VISIT | T1_SIG_OTH) + || t1->flags[1 + m][1 + k + 1][1 + i] & (T1_SIG | T1_VISIT | T1_SIG_OTH) + || t1->flags[1 + m][1 + k + 2][1 + i] & (T1_SIG | T1_VISIT | T1_SIG_OTH) + || t1->flags[1 + m][1 + k + 3][1 + i] & (T1_SIG | T1_VISIT | T1_SIG_OTH)); + } + } else { + agg = 0; + } + if (agg) { + for (runlen = 0; runlen < 4; runlen++) { + if (int_abs(t1->data[m][k + runlen][i]) & one) + break; + } + mqc_setcurctx(mqc, T1_CTXNO_AGG); + mqc_encode(mqc, runlen != 4); + if (runlen == 4) { + continue; + } + mqc_setcurctx(mqc, T1_CTXNO_UNI); + mqc_encode(mqc, runlen >> 1); + mqc_encode(mqc, runlen & 1); + } else { + runlen = 0; + } + for (j = k + runlen; j < k + 4 && j < h; j++) { + vsc = ((cblksty & J3D_CCP_CBLKSTY_VSC) && (j == k + 3 || j == h - 1)) ? 1 : 0; + t1_enc_clnpass_step(t1, &(t1->flags[1 + m][1 + j][1 + i]), &(t1->data[m][j][i]), orient, bpno, one, nmsedec, agg && (j == k + runlen), vsc); + } + } + } + } +} + +static void t1_dec_clnpass(opj_t1_t *t1, int w, int h, int l, int bpno, int orient, int cblksty) { + int i, j, k, m, one, half, oneplushalf, agg, runlen, vsc; + int segsym = cblksty & J3D_CCP_CBLKSTY_SEGSYM; + + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + one = 1 << bpno; + half = one >> 1; + oneplushalf = one | half; + for (m = 0; m < l; m++) { + for (k = 0; k < h; k += 4) { + for (i = 0; i < w; i++) { + if (k + 3 < h) { + if (cblksty & J3D_CCP_CBLKSTY_VSC) { + agg = !(t1->flags[1 + m][1 + k][1 + i] & (T1_SIG | T1_VISIT | T1_SIG_OTH) + || t1->flags[1 + m][1 + k + 1][1 + i] & (T1_SIG | T1_VISIT | T1_SIG_OTH) + || t1->flags[1 + m][1 + k + 2][1 + i] & (T1_SIG | T1_VISIT | T1_SIG_OTH) + || (t1->flags[1 + m][1 + k + 3][1 + i] + & (~(T1_SIG_S | T1_SIG_SE | T1_SIG_SW | T1_SGN_S))) & (T1_SIG | T1_VISIT | T1_SIG_OTH)); + } else { + agg = !(t1->flags[1 + m][1 + k][1 + i] & (T1_SIG | T1_VISIT | T1_SIG_OTH) + || t1->flags[1 + m][1 + k + 1][1 + i] & (T1_SIG | T1_VISIT | T1_SIG_OTH) + || t1->flags[1 + m][1 + k + 2][1 + i] & (T1_SIG | T1_VISIT | T1_SIG_OTH) + || t1->flags[1 + m][1 + k + 3][1 + i] & (T1_SIG | T1_VISIT | T1_SIG_OTH)); + } + } else { + agg = 0; + } + if (agg) { + mqc_setcurctx(mqc, T1_CTXNO_AGG); + if (!mqc_decode(mqc)) { + continue; + } + mqc_setcurctx(mqc, T1_CTXNO_UNI); + runlen = mqc_decode(mqc); + runlen = (runlen << 1) | mqc_decode(mqc); + } else { + runlen = 0; + } + for (j = k + runlen; j < k + 4 && j < h; j++) { + vsc = ((cblksty & J3D_CCP_CBLKSTY_VSC) && (j == k + 3 || j == h - 1)) ? 1 : 0; + t1_dec_clnpass_step(t1, &t1->flags[1 + m][1 + j][1 + i], &t1->data[m][j][i], orient, oneplushalf, agg && (j == k + runlen), vsc); + } + } + } + } + if (segsym) { + int v = 0; + mqc_setcurctx(mqc, T1_CTXNO_UNI); + v = mqc_decode(mqc); + v = (v << 1) | mqc_decode(mqc); + v = (v << 1) | mqc_decode(mqc); + v = (v << 1) | mqc_decode(mqc); + /* + if (v!=0xa) { + opj_event_msg(t1->cinfo, EVT_WARNING, "Bad segmentation symbol %x\n", v); + } + */ + } +} /* VSC and BYPASS by Antonin */ + + +static void t1_encode_cblk(opj_t1_t *t1, opj_tcd_cblk_t * cblk, int orient, int compno, int level[3], int dwtid[3], double stepsize, int cblksty, int numcomps, opj_tcd_tile_t * tile) { + int i, j, k; + int w, h, l; + int passno; + int bpno, passtype; + int max; + int nmsedec = 0; + double cumwmsedec = 0; + char type = T1_TYPE_MQ; + + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + w = cblk->x1 - cblk->x0; + h = cblk->y1 - cblk->y0; + l = cblk->z1 - cblk->z0; + + max = 0; + for (k = 0; k < l; k++) { + for (j = 0; j < h; j++) { + for (i = 0; i < w; i++) { + max = int_max(max, int_abs(t1->data[k][j][i])); + } + } + } + for (k = 0; k <= l; k++) { + for (j = 0; j <= h; j++) { + for (i = 0; i <= w; i++) { + t1->flags[k][j][i] = 0; + } + } + } + + cblk->numbps = max ? (int_floorlog2(max) + 1) - T1_NMSEDEC_FRACBITS : 0; + + bpno = cblk->numbps - 1; + passtype = 2; + + mqc_reset_enc(mqc); + mqc_init_enc(mqc, cblk->data); + + for (passno = 0; bpno >= 0; passno++) { + opj_tcd_pass_t *pass = &cblk->passes[passno]; + int correction = 3; + double tmpwmsedec; + type = ((bpno < (cblk->numbps - 4)) && (passtype < 2) && (cblksty & J3D_CCP_CBLKSTY_LAZY)) ? T1_TYPE_RAW : T1_TYPE_MQ; + //fprintf(stdout,"passno %d passtype %d w %d h %d l %d bpno %d orient %d type %d cblksty %d\n",passno,passtype,w,h,l,bpno,orient,type,cblksty); + + switch (passtype) { + case 0: + t1_enc_sigpass(t1, w, h, l, bpno, orient, &nmsedec, type, cblksty); + break; + case 1: + t1_enc_refpass(t1, w, h, l, bpno, &nmsedec, type, cblksty); + break; + case 2: + //fprintf(stdout,"w %d h %d l %d bpno %d orient %d \n",w,h,l,bpno,orient); + t1_enc_clnpass(t1, w, h, l, bpno, orient, &nmsedec, cblksty); + /* code switch SEGMARK (i.e. SEGSYM) */ + if (cblksty & J3D_CCP_CBLKSTY_SEGSYM) + mqc_segmark_enc(mqc); + break; + } + + /* fixed_quality */ + tmpwmsedec = t1_getwmsedec(nmsedec, compno, level, orient, bpno, stepsize, numcomps, dwtid); + cumwmsedec += tmpwmsedec; + tile->distotile += tmpwmsedec; + + /* Code switch "RESTART" (i.e. TERMALL) */ + if ((cblksty & J3D_CCP_CBLKSTY_TERMALL) && !((passtype == 2) && (bpno - 1 < 0))) { + if (type == T1_TYPE_RAW) { + mqc_flush(mqc); + correction = 1; + /* correction = mqc_bypass_flush_enc(); */ + } else { /* correction = mqc_restart_enc(); */ + mqc_flush(mqc); + correction = 1; + } + pass->term = 1; + } else { + if (((bpno < (cblk->numbps - 4) && (passtype > 0)) + || ((bpno == (cblk->numbps - 4)) && (passtype == 2))) && (cblksty & J3D_CCP_CBLKSTY_LAZY)) { + if (type == T1_TYPE_RAW) { + mqc_flush(mqc); + correction = 1; + /* correction = mqc_bypass_flush_enc(); */ + } else { /* correction = mqc_restart_enc(); */ + mqc_flush(mqc); + correction = 1; + } + pass->term = 1; + } else { + pass->term = 0; + } + } + + if (++passtype == 3) { + passtype = 0; + bpno--; + } + + if (pass->term && bpno > 0) { + type = ((bpno < (cblk->numbps - 4)) && (passtype < 2) && (cblksty & J3D_CCP_CBLKSTY_LAZY)) ? T1_TYPE_RAW : T1_TYPE_MQ; + if (type == T1_TYPE_RAW) + mqc_bypass_init_enc(mqc); + else + mqc_restart_init_enc(mqc); + } + + pass->distortiondec = cumwmsedec; + pass->rate = mqc_numbytes(mqc) + correction; /* FIXME */ + pass->len = pass->rate - (passno == 0 ? 0 : cblk->passes[passno - 1].rate); + + /* Code-switch "RESET" */ + if (cblksty & J3D_CCP_CBLKSTY_RESET) + mqc_reset_enc(mqc); + } + + /* Code switch "ERTERM" (i.e. PTERM) */ + if (cblksty & J3D_CCP_CBLKSTY_PTERM) + mqc_erterm_enc(mqc); + else /* Default coding */ if (!(cblksty & J3D_CCP_CBLKSTY_LAZY)) + mqc_flush(mqc); + + cblk->totalpasses = passno; +} + +static void t1_decode_cblk(opj_t1_t *t1, opj_tcd_cblk_t * cblk, int orient, int roishift, int cblksty) { + int i, j, k, w, h, l; + int bpno, passtype; + int segno, passno; + char type = T1_TYPE_MQ; /* BYPASS mode */ + + opj_raw_t *raw = t1->raw; /* RAW component */ + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + w = cblk->x1 - cblk->x0; + h = cblk->y1 - cblk->y0; + l = cblk->z1 - cblk->z0; + + for (k = 0; k < l; k++) { + for (j = 0; j < h; j++) { + for (i = 0; i < w; i++) { + t1->data[k][j][i] = 0; + } + } + } + + for (k = 0; k <= l; k++) { + for (j = 0; j <= h; j++) { + for (i = 0; i <= w; i++) { + t1->flags[k][j][i] = 0; + } + } + } + + bpno = roishift + cblk->numbps - 1; + passtype = 2; + + mqc_reset_enc(mqc); + + for (segno = 0; segno < cblk->numsegs; segno++) { + opj_tcd_seg_t *seg = &cblk->segs[segno]; + + /* BYPASS mode */ + type = ((bpno <= (cblk->numbps - 1) - 4) && (passtype < 2) && (cblksty & J3D_CCP_CBLKSTY_LAZY)) ? T1_TYPE_RAW : T1_TYPE_MQ; + if (type == T1_TYPE_RAW) { + raw_init_dec(raw, seg->data, seg->len); + } else { + mqc_init_dec(mqc, seg->data, seg->len); + } + + for (passno = 0; passno < seg->numpasses; passno++) { + switch (passtype) { + case 0: + t1_dec_sigpass(t1, w, h, l, bpno+1, orient, type, cblksty); + break; + case 1: + t1_dec_refpass(t1, w, h, l, bpno+1, type, cblksty); + break; + case 2: + t1_dec_clnpass(t1, w, h, l, bpno+1, orient, cblksty); + break; + } + + if ((cblksty & J3D_CCP_CBLKSTY_RESET) && type == T1_TYPE_MQ) { + mqc_reset_enc(mqc); + } + if (++passtype == 3) { + passtype = 0; + bpno--; + } + } + } +} + +static int t1_init_ctxno_zc(int f, int orient) { + int h, v, d, n, t, hv; + n = 0; + h = ((f & T1_SIG_W) != 0) + ((f & T1_SIG_E) != 0); + v = ((f & T1_SIG_N) != 0) + ((f & T1_SIG_S) != 0); + d = ((f & T1_SIG_NW) != 0) + ((f & T1_SIG_NE) != 0) + ((f & T1_SIG_SE) != 0) + ((f & T1_SIG_SW) != 0); + + switch (orient) { + case 2: + t = h; + h = v; + v = t; + case 0: + case 1: + if (!h) { + if (!v) { + if (!d) + n = 0; + else if (d == 1) + n = 1; + else + n = 2; + } else if (v == 1) { + n = 3; + } else { + n = 4; + } + } else if (h == 1) { + if (!v) { + if (!d) + n = 5; + else + n = 6; + } else { + n = 7; + } + } else + n = 8; + break; + case 3: + hv = h + v; + if (!d) { + if (!hv) { + n = 0; + } else if (hv == 1) { + n = 1; + } else { + n = 2; + } + } else if (d == 1) { + if (!hv) { + n = 3; + } else if (hv == 1) { + n = 4; + } else { + n = 5; + } + } else if (d == 2) { + if (!hv) { + n = 6; + } else { + n = 7; + } + } else { + n = 8; + } + break; + } + + return (T1_CTXNO_ZC + n); +} + +static int t1_init_ctxno_sc(int f) { + int hc, vc, n; + n = 0; + + hc = int_min(((f & (T1_SIG_E | T1_SGN_E)) == + T1_SIG_E) + ((f & (T1_SIG_W | T1_SGN_W)) == T1_SIG_W), + 1) - int_min(((f & (T1_SIG_E | T1_SGN_E)) == + (T1_SIG_E | T1_SGN_E)) + + ((f & (T1_SIG_W | T1_SGN_W)) == + (T1_SIG_W | T1_SGN_W)), 1); + + vc = int_min(((f & (T1_SIG_N | T1_SGN_N)) == + T1_SIG_N) + ((f & (T1_SIG_S | T1_SGN_S)) == T1_SIG_S), + 1) - int_min(((f & (T1_SIG_N | T1_SGN_N)) == + (T1_SIG_N | T1_SGN_N)) + + ((f & (T1_SIG_S | T1_SGN_S)) == + (T1_SIG_S | T1_SGN_S)), 1); + + if (hc < 0) { + hc = -hc; + vc = -vc; + } + if (!hc) { + if (vc == -1) + n = 1; + else if (!vc) + n = 0; + else + n = 1; + } else if (hc == 1) { + if (vc == -1) + n = 2; + else if (!vc) + n = 3; + else + n = 4; + } + + return (T1_CTXNO_SC + n); +} + +static int t1_init_ctxno_mag(int f) { + int n; + if (!(f & T1_REFINE)) + n = (f & (T1_SIG_OTH)) ? 1 : 0; + else + n = 2; + + return (T1_CTXNO_MAG + n); +} + +static int t1_init_spb(int f) { + int hc, vc, n; + + hc = int_min(((f & (T1_SIG_E | T1_SGN_E)) == + T1_SIG_E) + ((f & (T1_SIG_W | T1_SGN_W)) == T1_SIG_W), + 1) - int_min(((f & (T1_SIG_E | T1_SGN_E)) == + (T1_SIG_E | T1_SGN_E)) + + ((f & (T1_SIG_W | T1_SGN_W)) == + (T1_SIG_W | T1_SGN_W)), 1); + + vc = int_min(((f & (T1_SIG_N | T1_SGN_N)) == + T1_SIG_N) + ((f & (T1_SIG_S | T1_SGN_S)) == T1_SIG_S), + 1) - int_min(((f & (T1_SIG_N | T1_SGN_N)) == + (T1_SIG_N | T1_SGN_N)) + + ((f & (T1_SIG_S | T1_SGN_S)) == + (T1_SIG_S | T1_SGN_S)), 1); + + if (!hc && !vc) + n = 0; + else + n = (!(hc > 0 || (!hc && vc > 0))); + + return n; +} + +static void t1_init_luts(opj_t1_t *t1) { + int i, j; + double u, v, t; + for (j = 0; j < 4; j++) { + for (i = 0; i < 256; ++i) { + t1->lut_ctxno_zc[(j << 8) | i] = t1_init_ctxno_zc(i, j); + } + } + for (i = 0; i < 256; i++) { + t1->lut_ctxno_sc[i] = t1_init_ctxno_sc(i << 4); + } + for (j = 0; j < 2; j++) { + for (i = 0; i < 2048; ++i) { + t1->lut_ctxno_mag[(j << 11) + i] = t1_init_ctxno_mag((j ? T1_REFINE : 0) | i); + } + } + for (i = 0; i < 256; ++i) { + t1->lut_spb[i] = t1_init_spb(i << 4); + } + /* FIXME FIXME FIXME */ + /* fprintf(stdout,"nmsedec luts:\n"); */ + for (i = 0; i < (1 << T1_NMSEDEC_BITS); i++) { + t = i / pow(2, T1_NMSEDEC_FRACBITS); + u = t; + v = t - 1.5; + t1->lut_nmsedec_sig[i] = + int_max(0, + (int) (floor((u * u - v * v) * pow(2, T1_NMSEDEC_FRACBITS) + 0.5) / pow(2, T1_NMSEDEC_FRACBITS) * 8192.0)); + t1->lut_nmsedec_sig0[i] = + int_max(0, + (int) (floor((u * u) * pow(2, T1_NMSEDEC_FRACBITS) + 0.5) / pow(2, T1_NMSEDEC_FRACBITS) * 8192.0)); + u = t - 1.0; + if (i & (1 << (T1_NMSEDEC_BITS - 1))) { + v = t - 1.5; + } else { + v = t - 0.5; + } + t1->lut_nmsedec_ref[i] = + int_max(0, + (int) (floor((u * u - v * v) * pow(2, T1_NMSEDEC_FRACBITS) + 0.5) / pow(2, T1_NMSEDEC_FRACBITS) * 8192.0)); + t1->lut_nmsedec_ref0[i] = + int_max(0, + (int) (floor((u * u) * pow(2, T1_NMSEDEC_FRACBITS) + 0.5) / pow(2, T1_NMSEDEC_FRACBITS) * 8192.0)); + } +} + +/* ----------------------------------------------------------------------- */ + +opj_t1_t* t1_create(opj_common_ptr cinfo) { + opj_t1_t *t1 = (opj_t1_t*)opj_malloc(sizeof(opj_t1_t)); + if(t1) { + t1->cinfo = cinfo; + /* create MQC and RAW handles */ + t1->mqc = mqc_create(); + t1->raw = raw_create(); + /* initialize the look-up tables of the Tier-1 coder/decoder */ + t1_init_luts(t1); + } + return t1; +} + +void t1_destroy(opj_t1_t *t1) { + if(t1) { + /* destroy MQC and RAW handles */ + mqc_destroy(t1->mqc); + raw_destroy(t1->raw); + //opj_free(t1->data); + //opj_free(t1->flags); + opj_free(t1); + } +} + +void t1_encode_cblks(opj_t1_t *t1, opj_tcd_tile_t *tile, opj_tcp_t *tcp) { + int compno, resno, bandno, precno, cblkno; + int x, y, z, i, j, k, orient; + int n=0; + int level[3]; + FILE *fid = NULL; +// char filename[10]; + tile->distotile = 0; /* fixed_quality */ + + for (compno = 0; compno < tile->numcomps; compno++) { + opj_tcd_tilecomp_t *tilec = &tile->comps[compno]; + + for (resno = 0; resno < tilec->numresolution[0]; resno++) { + opj_tcd_resolution_t *res = &tilec->resolutions[resno]; + + /* Weighted first order entropy + sprintf(filename,"res%d.txt",resno); + if ((fid = fopen(filename,"w")) == 0){ + fprintf(stdout,"Error while opening %s\n", filename); + exit(1); + } + */ + for (bandno = 0; bandno < res->numbands; bandno++) { + opj_tcd_band_t *band = &res->bands[bandno]; + for (precno = 0; precno < res->prctno[0] * res->prctno[1] * res->prctno[2]; precno++) { + opj_tcd_precinct_t *prc = &band->precincts[precno]; + + for (cblkno = 0; cblkno < prc->cblkno[0] * prc->cblkno[1] * prc->cblkno[2]; cblkno++) { + opj_tcd_cblk_t *cblk = &prc->cblks[cblkno]; + + //fprintf(stdout,"Precno %d Cblkno %d \n",precno,cblkno); + if (band->bandno == 0) { + x = cblk->x0 - band->x0; + y = cblk->y0 - band->y0; + z = cblk->z0 - band->z0; + } else if (band->bandno == 1) { + opj_tcd_resolution_t *pres = &tilec->resolutions[resno - 1]; + x = pres->x1 - pres->x0 + cblk->x0 - band->x0; + y = cblk->y0 - band->y0; + z = cblk->z0 - band->z0; + } else if (band->bandno == 2) { + opj_tcd_resolution_t *pres = &tilec->resolutions[resno - 1]; + x = cblk->x0 - band->x0; + y = pres->y1 - pres->y0 + cblk->y0 - band->y0; + z = cblk->z0 - band->z0; + } else if (band->bandno == 3) { + opj_tcd_resolution_t *pres = &tilec->resolutions[resno - 1]; + x = pres->x1 - pres->x0 + cblk->x0 - band->x0; + y = pres->y1 - pres->y0 + cblk->y0 - band->y0; + z = cblk->z0 - band->z0; + } else if (band->bandno == 4) { + opj_tcd_resolution_t *pres = &tilec->resolutions[resno - 1]; + x = cblk->x0 - band->x0; + y = cblk->y0 - band->y0; + z = pres->z1 - pres->z0 + cblk->z0 - band->z0; + } else if (band->bandno == 5) { + opj_tcd_resolution_t *pres = &tilec->resolutions[resno - 1]; + x = pres->x1 - pres->x0 + cblk->x0 - band->x0; + y = cblk->y0 - band->y0; + z = pres->z1 - pres->z0 + cblk->z0 - band->z0; + } else if (band->bandno == 6) { + opj_tcd_resolution_t *pres = &tilec->resolutions[resno - 1]; + x = cblk->x0 - band->x0; + y = pres->y1 - pres->y0 + cblk->y0 - band->y0; + z = pres->z1 - pres->z0 + cblk->z0 - band->z0; + } else if (band->bandno == 7) { + opj_tcd_resolution_t *pres = &tilec->resolutions[resno - 1]; + x = pres->x1 - pres->x0 + cblk->x0 - band->x0; + y = pres->y1 - pres->y0 + cblk->y0 - band->y0; + z = pres->z1 - pres->z0 + cblk->z0 - band->z0; + } + + if (tcp->tccps[compno].reversible == 1) { + for (k = 0; k < cblk->z1 - cblk->z0; k++) { + for (j = 0; j < cblk->y1 - cblk->y0; j++) { + for (i = 0; i < cblk->x1 - cblk->x0; i++) { + t1->data[k][j][i] = + tilec->data[(x + i) + (y + j) * (tilec->x1 - tilec->x0) + (z + k) * (tilec->x1 - tilec->x0) * (tilec->y1 - tilec->y0)] << T1_NMSEDEC_FRACBITS; +//fprintf(fid," %d",t1->data[k][j][i]); + } + } + } + } else if (tcp->tccps[compno].reversible == 0) { + for (k = 0; k < cblk->z1 - cblk->z0; k++) { + for (j = 0; j < cblk->y1 - cblk->y0; j++) { + for (i = 0; i < cblk->x1 - cblk->x0; i++) { + t1->data[k][j][i] = fix_mul( + tilec->data[(x + i) + (y + j) * (tilec->x1 - tilec->x0) + (z + k) * (tilec->x1 - tilec->x0) * (tilec->y1 - tilec->y0)], + 8192 * 8192 / ((int) floor(band->stepsize * 8192))) >> (13 - T1_NMSEDEC_FRACBITS); + } + } + } + } + + orient = band->bandno; /* FIXME */ + if (orient == 2) { + orient = 1; + } else if (orient == 1) { + orient = 2; + } + for (i = 0; i < 3; i++) + level[i] = tilec->numresolution[i] - 1 - resno; + //fprintf(stdout,"t1_encode_cblk(t1, cblk, %d, %d, %d %d %d, %d, %f, %d, %d, tile);\n", orient, compno, level[0], level[1], level[2], tcp->tccps[compno].reversible, band->stepsize, tcp->tccps[compno].cblksty, tile->numcomps); + t1_encode_cblk(t1, cblk, orient, compno, level, tcp->tccps[compno].dwtid, band->stepsize, tcp->tccps[compno].cblksty, tile->numcomps, tile); + + } /* cblkno */ + } /* precno */ +//fprintf(fid,"\n"); + } /* bandno */ +//fclose(fid); + } /* resno */ + } /* compno */ +} + +void t1_decode_cblks(opj_t1_t *t1, opj_tcd_tile_t *tile, opj_tcp_t *tcp) { + int compno, resno, bandno, precno, cblkno; + + for (compno = 0; compno < tile->numcomps; compno++) { + opj_tcd_tilecomp_t *tilec = &tile->comps[compno]; + + for (resno = 0; resno < tilec->numresolution[0]; resno++) { + opj_tcd_resolution_t *res = &tilec->resolutions[resno]; + + for (bandno = 0; bandno < res->numbands; bandno++) { + opj_tcd_band_t *band = &res->bands[bandno]; + + for (precno = 0; precno < res->prctno[0] * res->prctno[1] * res->prctno[2]; precno++) { + opj_tcd_precinct_t *prc = &band->precincts[precno]; + + for (cblkno = 0; cblkno < prc->cblkno[0] * prc->cblkno[1] * prc->cblkno[2]; cblkno++) { + int x, y, k, i, j, z, orient; + opj_tcd_cblk_t *cblk = &prc->cblks[cblkno]; + + orient = band->bandno; /* FIXME */ + if (orient == 2) { + orient = 1; + } else if (orient == 1) { + orient = 2; + } + + t1_decode_cblk(t1, cblk, orient, tcp->tccps[compno].roishift, tcp->tccps[compno].cblksty); + + if (band->bandno == 0) { + x = cblk->x0 - band->x0; + y = cblk->y0 - band->y0; + z = cblk->z0 - band->z0; + } else if (band->bandno == 1) { + opj_tcd_resolution_t *pres = &tilec->resolutions[resno - 1]; + x = pres->x1 - pres->x0 + cblk->x0 - band->x0; + y = cblk->y0 - band->y0; + z = cblk->z0 - band->z0; + } else if (band->bandno == 2) { + opj_tcd_resolution_t *pres = &tilec->resolutions[resno - 1]; + x = cblk->x0 - band->x0; + y = pres->y1 - pres->y0 + cblk->y0 - band->y0; + z = cblk->z0 - band->z0; + } else if (band->bandno == 3) { + opj_tcd_resolution_t *pres = &tilec->resolutions[resno - 1]; + x = pres->x1 - pres->x0 + cblk->x0 - band->x0; + y = pres->y1 - pres->y0 + cblk->y0 - band->y0; + z = cblk->z0 - band->z0; + } else if (band->bandno == 4) { + opj_tcd_resolution_t *pres = &tilec->resolutions[resno - 1]; + x = cblk->x0 - band->x0; + y = cblk->y0 - band->y0; + z = pres->z1 - pres->z0 + cblk->z0 - band->z0; + } else if (band->bandno == 5) { + opj_tcd_resolution_t *pres = &tilec->resolutions[resno - 1]; + x = pres->x1 - pres->x0 + cblk->x0 - band->x0; + y = cblk->y0 - band->y0; + z = pres->z1 - pres->z0 + cblk->z0 - band->z0; + } else if (band->bandno == 6) { + opj_tcd_resolution_t *pres = &tilec->resolutions[resno - 1]; + x = cblk->x0 - band->x0; + y = pres->y1 - pres->y0 + cblk->y0 - band->y0; + z = pres->z1 - pres->z0 + cblk->z0 - band->z0; + } else if (band->bandno == 7) { + opj_tcd_resolution_t *pres = &tilec->resolutions[resno - 1]; + x = pres->x1 - pres->x0 + cblk->x0 - band->x0; + y = pres->y1 - pres->y0 + cblk->y0 - band->y0; + z = pres->z1 - pres->z0 + cblk->z0 - band->z0; + } + + if (tcp->tccps[compno].roishift) { + int thresh, val, mag; + thresh = 1 << tcp->tccps[compno].roishift; + for (k = 0; k < cblk->z1 - cblk->z0; k++) { + for (j = 0; j < cblk->y1 - cblk->y0; j++) { + for (i = 0; i < cblk->x1 - cblk->x0; i++) { + val = t1->data[k][j][i]; + mag = int_abs(val); + if (mag >= thresh) { + mag >>= tcp->tccps[compno].roishift; + t1->data[k][j][i] = val < 0 ? -mag : mag; + } + } + } + } + } + + if (tcp->tccps[compno].reversible == 1) { + for (k = 0; k < cblk->z1 - cblk->z0; k++) { + for (j = 0; j < cblk->y1 - cblk->y0; j++) { + for (i = 0; i < cblk->x1 - cblk->x0; i++) { + int tmp = t1->data[k][j][i]; + tilec->data[x + i + (y + j) * (tilec->x1 - tilec->x0) + (z + k) * (tilec->x1 - tilec->x0) * (tilec->y1 - tilec->y0)] = tmp/2; + } + } + } + } else { /* if (tcp->tccps[compno].reversible == 0) */ + for (k = 0; k < cblk->z1 - cblk->z0; k++) { + for (j = 0; j < cblk->y1 - cblk->y0; j++) { + for (i = 0; i < cblk->x1 - cblk->x0; i++) { + double tmp = (double)(t1->data[k][j][i] * band->stepsize * 4096.0); + if (t1->data[k][j][i] >> 1 == 0) { + tilec->data[x + i + (y + j) * (tilec->x1 - tilec->x0) + (z + k) * (tilec->x1 - tilec->x0) * (tilec->y1 - tilec->y0)] = 0; + } else { + int tmp2 = ((int) (floor(fabs(tmp)))) + ((int) floor(fabs(tmp*2))%2); + tilec->data[x + i + (y + j) * (tilec->x1 - tilec->x0) + (z + k) * (tilec->x1 - tilec->x0) * (tilec->y1 - tilec->y0)] = ((tmp<0)?-tmp2:tmp2); + } + } + } + } + } + } /* cblkno */ + } /* precno */ + } /* bandno */ + } /* resno */ + } /* compno */ +} + + +/** mod fixed_quality */ +double t1_getwmsedec(int nmsedec, int compno, int level[3], int orient, int bpno, double stepsize, int numcomps, int dwtid[3]) { + double w1, w2, wmsedec; + + if (dwtid[0] == 1 || dwtid[1] == 1 || dwtid[2] == 1) { + w1 = (numcomps > 1) ? mct_getnorm_real(compno) : 1; + } else { + w1 = (numcomps > 1) ? mct_getnorm(compno) : 1; + } + w2 = dwt_getnorm(orient, level, dwtid); + + //fprintf(stdout,"nmsedec %d level %d %d %d orient %d bpno %d stepsize %f \n",nmsedec ,level[0],level[1],level[2],orient,bpno,stepsize); + wmsedec = w1 * w2 * stepsize * (1 << bpno); + wmsedec *= wmsedec * nmsedec / 8192.0; + + return wmsedec; +} +/** mod fixed_quality */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/t1.h b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/t1.h new file mode 100644 index 0000000..9899757 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/t1.h @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __T1_H +#define __T1_H +/** +@file t1.h +@brief Implementation of the tier-1 coding (coding of code-block coefficients) (T1) + +The functions in T1.C have for goal to realize the tier-1 coding operation. The functions +in T1.C are used by some function in TCD.C. +*/ + +/** @defgroup T1 T1 - Implementation of the tier-1 coding */ +/*@{*/ + +/* ----------------------------------------------------------------------- */ +#define T1_NMSEDEC_BITS 7 + +#define T1_MAXCBLKW 256 /*< Maximum size of code-block (width) */ +#define T1_MAXCBLKH 256 /*< Maximum size of code-block (heigth) */ +#define T1_MAXCBLKD 256 /*< Maximum size of code-block (depth) */ +#define T1_MINCBLKW 4 /*< Minimum size of code-block (width) */ +#define T1_MINCBLKH 4 /*< Minimum size of code-block (heigth) */ +#define T1_MINCBLKD 4 /*< Minimum size of code-block (depth) */ +#define T1_MAXWHD 18 +#define T1_CBLKW 256 +#define T1_CBLKH 256 +#define T1_CBLKD 256 + +#define T1_SIG_NE 0x0001 /*< Context orientation : North-East direction */ +#define T1_SIG_SE 0x0002 /*< Context orientation : South-East direction */ +#define T1_SIG_SW 0x0004 /*< Context orientation : South-West direction */ +#define T1_SIG_NW 0x0008 /*< Context orientation : North-West direction */ +#define T1_SIG_N 0x0010 /*< Context orientation : North direction */ +#define T1_SIG_E 0x0020 /*< Context orientation : East direction */ +#define T1_SIG_S 0x0040 /*< Context orientation : South direction */ +#define T1_SIG_W 0x0080 /*< Context orientation : West direction */ +#define T1_SIG_OTH (T1_SIG_N|T1_SIG_NE|T1_SIG_E|T1_SIG_SE|T1_SIG_S|T1_SIG_SW|T1_SIG_W|T1_SIG_NW) +#define T1_SIG_PRIM (T1_SIG_N|T1_SIG_E|T1_SIG_S|T1_SIG_W) + +#define T1_SGN_N 0x0100 +#define T1_SGN_E 0x0200 +#define T1_SGN_S 0x0400 +#define T1_SGN_W 0x0800 +#define T1_SGN (T1_SGN_N|T1_SGN_E|T1_SGN_S|T1_SGN_W) + +#define T1_SIG 0x1000 +#define T1_REFINE 0x2000 +#define T1_VISIT 0x4000 + +#define T1_NUMCTXS_AGG 1 +#define T1_NUMCTXS_ZC 9 +#define T1_NUMCTXS_MAG 3 +#define T1_NUMCTXS_SC 5 +#define T1_NUMCTXS_UNI 1 + +#define T1_CTXNO_AGG 0 +#define T1_CTXNO_ZC (T1_CTXNO_AGG+T1_NUMCTXS_AGG) +#define T1_CTXNO_MAG (T1_CTXNO_ZC+T1_NUMCTXS_ZC) +#define T1_CTXNO_SC (T1_CTXNO_MAG+T1_NUMCTXS_MAG) +#define T1_CTXNO_UNI (T1_CTXNO_SC+T1_NUMCTXS_SC) +#define T1_NUMCTXS (T1_CTXNO_UNI+T1_NUMCTXS_UNI) + +#define T1_NMSEDEC_FRACBITS (T1_NMSEDEC_BITS-1) + +#define T1_TYPE_MQ 0 /*< Normal coding using entropy coder */ +#define T1_TYPE_RAW 1 /*< No encoding the information is store under raw format in codestream (mode switch RAW)*/ + +/* ----------------------------------------------------------------------- */ + +/** +Tier-1 coding (coding of code-block coefficients) +*/ +typedef struct opj_t1 { + /** codec context */ + opj_common_ptr cinfo; + + /** MQC component */ + opj_mqc_t *mqc; + /** RAW component */ + opj_raw_t *raw; + /** LUTs for context-based coding */ + int lut_ctxno_zc[1024]; + int lut_ctxno_sc[256]; + int lut_ctxno_mag[4096]; + int lut_spb[256]; + /** LUTs for decoding normalised MSE */ + int lut_nmsedec_sig[1 << T1_NMSEDEC_BITS]; + int lut_nmsedec_sig0[1 << T1_NMSEDEC_BITS]; + int lut_nmsedec_ref[1 << T1_NMSEDEC_BITS]; + int lut_nmsedec_ref0[1 << T1_NMSEDEC_BITS]; + /** Codeblock data */ + int data[T1_CBLKD][T1_CBLKH][T1_CBLKW];//int ***data; + /** Context information for each voxel in codeblock */ + int flags[T1_CBLKD + 2][T1_CBLKH + 2][T1_CBLKH + 2];//int ***flags; +} opj_t1_t; + +/** @name Exported functions */ +/*@{*/ +/* ----------------------------------------------------------------------- */ +/** +Create a new T1 handle +and initialize the look-up tables of the Tier-1 coder/decoder +@return Returns a new T1 handle if successful, returns NULL otherwise +@see t1_init_luts +*/ +opj_t1_t* t1_create(opj_common_ptr cinfo); +/** +Destroy a previously created T1 handle +@param t1 T1 handle to destroy +*/ +void t1_destroy(opj_t1_t *t1); +/** +Encode the code-blocks of a tile +@param t1 T1 handle +@param tile The tile to encode +@param tcp Tile coding parameters +*/ +void t1_encode_cblks(opj_t1_t *t1, opj_tcd_tile_t *tile, opj_tcp_t *tcp); +/** +Decode the code-blocks of a tile +@param t1 T1 handle +@param tile The tile to decode +@param tcp Tile coding parameters +*/ +void t1_decode_cblks(opj_t1_t *t1, opj_tcd_tile_t *tile, opj_tcp_t *tcp); +/** +Get weigths of MSE decoding +@param nmsedec The normalized MSE reduction +@param compno +@param level +@param orient +@param bpno +@param stepsize +@param numcomps +@param dwtid +returns MSE associated to decoding pass +*/ +double t1_getwmsedec(int nmsedec, int compno, int level[3], int orient, int bpno, double stepsize, int numcomps, int dwtid[3]); + +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __T1_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/t1_3d.c b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/t1_3d.c new file mode 100644 index 0000000..647aaa4 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/t1_3d.c @@ -0,0 +1,1230 @@ +/* + * Copyrigth (c) 2006, Mónica Díez, LPI-UVA, Spain + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "opj_includes.h" + +/** @defgroup T1_3D T1_3D - Implementation of the tier-1 coding */ +/*@{*/ + +/** @name Local static functions */ +/*@{*/ + +static int t1_3d_getctxno_zc(unsigned int f, int orient); +static int t1_3d_getctxno_sc(unsigned int f); +static int t1_3d_getctxno_mag(unsigned int f, int fsvr); +static int t1_3d_getspb(unsigned int f); +static int t1_3d_getnmsedec_sig(opj_t1_3d_t *t1, int x, int bitpos); +static int t1_3d_getnmsedec_ref(opj_t1_3d_t *t1, int x, int bitpos); +static void t1_3d_updateflags(unsigned int *fp, int s); +/** +Encode significant pass +*/ +static void t1_3d_enc_sigpass_step(opj_t1_3d_t *t1, unsigned int *fp, int *fsvr, int *dp, int orient, int bpno, int one, int *nmsedec, char type, int vsc); +/** +Decode significant pass +*/ +static void t1_3d_dec_sigpass_step(opj_t1_3d_t *t1, unsigned int *fp, int *fsvr, int *dp, int orient, int oneplushalf, char type, int vsc); +/** +Encode significant pass +*/ +static void t1_3d_enc_sigpass(opj_t1_3d_t *t1, int w, int h, int l, int bpno, int orient, int *nmsedec, char type, int cblksty); +/** +Decode significant pass +*/ +static void t1_3d_dec_sigpass(opj_t1_3d_t *t1, int w, int h, int l, int bpno, int orient, char type, int cblksty); +/** +Encode refinement pass +*/ +static void t1_3d_enc_refpass_step(opj_t1_3d_t *t1, unsigned int *fp, int *fsvr, int *dp, int bpno, int one, int *nmsedec, char type, int vsc); +/** +Decode refinement pass +*/ +static void t1_3d_dec_refpass_step(opj_t1_3d_t *t1, unsigned int *fp, int *fsvr, int *dp, int poshalf, int neghalf, char type, int vsc); +/** +Encode refinement pass +*/ +static void t1_3d_enc_refpass(opj_t1_3d_t *t1, int w, int h, int l, int bpno, int *nmsedec, char type, int cblksty); +/** +Decode refinement pass +*/ +static void t1_3d_dec_refpass(opj_t1_3d_t *t1, int w, int h, int l, int bpno, char type, int cblksty); +/** +Encode clean-up pass +*/ +static void t1_3d_enc_clnpass_step(opj_t1_3d_t *t1, unsigned int *fp, int *fsvr, int *dp, int orient, int bpno, int one, int *nmsedec, int partial, int vsc); +/** +Decode clean-up pass +*/ +static void t1_3d_dec_clnpass_step(opj_t1_3d_t *t1, unsigned int *fp, int *fsvr, int *dp, int orient, int oneplushalf, int partial, int vsc); +/** +Encode clean-up pass +*/ +static void t1_3d_enc_clnpass(opj_t1_3d_t *t1, int w, int h, int l, int bpno, int orient, int *nmsedec, int cblksty); +/** +Decode clean-up pass +*/ +static void t1_3d_dec_clnpass(opj_t1_3d_t *t1, int w, int h, int l, int bpno, int orient, int cblksty); +/** +Encode 1 code-block +@param t1 T1 handle +@param cblk Code-block coding parameters +@param orient +@param compno Component number +@param level[3] +@param dwtid[3] +@param stepsize +@param cblksty Code-block style +@param numcomps +@param tile +*/ +static void t1_3d_encode_cblk(opj_t1_3d_t *t1, opj_tcd_cblk_t * cblk, int orient, int compno, int level[3], int dwtid[3], double stepsize, int cblksty, int numcomps, opj_tcd_tile_t * tile); +/** +Decode 1 code-block +@param t1 T1 handle +@param cblk Code-block coding parameters +@param orient +@param roishift Region of interest shifting value +@param cblksty Code-block style +*/ +static void t1_3d_decode_cblk(opj_t1_3d_t *t1, opj_tcd_cblk_t * cblk, int orient, int roishift, int cblksty); +static int t1_3d_init_ctxno_zc(unsigned int f, int orient); +static int t1_3d_init_ctxno_sc(unsigned int f); +static int t1_3d_init_ctxno_mag(unsigned int f, int f2); +static int t1_3d_init_spb(unsigned int f); +/** +Initialize the look-up tables of the Tier-1 coder/decoder +@param t1 T1 handle +*/ +static void t1_3d_init_luts(opj_t1_3d_t *t1); + +/*@}*/ + +/*@}*/ + +/* ----------------------------------------------------------------------- */ + +static int t1_3d_getctxno_zc(unsigned int f, int orient) { + return t1_3d_init_ctxno_zc((f & T1_3D_SIG_OTH), orient); +} + +static int t1_3d_getctxno_sc(unsigned int f) { + return t1_3d_init_ctxno_sc((f & T1_3D_SIG_PRIM) | ((f >> 16) & T1_3D_SGN)); + //return t1->lut_ctxno_sc[((f & T1_3D_SIG_PRIM) | ((f >> 16) & T1_3D_SGN)) >> 4]; +} + +static int t1_3d_getctxno_mag(unsigned int f, int fsvr) { + return t1_3d_init_ctxno_mag((f & T1_3D_SIG_OTH), fsvr); +} + +static int t1_3d_getspb(unsigned int f) { + return t1_3d_init_spb((f & T1_3D_SIG_PRIM) | ((f >> 16) & T1_3D_SGN)); + //return t1->lut_spb[((f & T1_3D_SIG_PRIM) | ((f >> 16) & T1_3D_SGN)) >> 4]; +} + +static int t1_3d_getnmsedec_sig(opj_t1_3d_t *t1, int x, int bitpos) { + if (bitpos > T1_NMSEDEC_FRACBITS) { + return t1->lut_nmsedec_sig[(x >> (bitpos - T1_NMSEDEC_FRACBITS)) & ((1 << T1_NMSEDEC_BITS) - 1)]; + } + + return t1->lut_nmsedec_sig0[x & ((1 << T1_NMSEDEC_BITS) - 1)]; +} + +static int t1_3d_getnmsedec_ref(opj_t1_3d_t *t1, int x, int bitpos) { + if (bitpos > T1_NMSEDEC_FRACBITS) { + return t1->lut_nmsedec_ref[(x >> (bitpos - T1_NMSEDEC_FRACBITS)) & ((1 << T1_NMSEDEC_BITS) - 1)]; + } + + return t1->lut_nmsedec_ref0[x & ((1 << T1_NMSEDEC_BITS) - 1)]; +} + +static void t1_3d_updateflags(unsigned int *fp, int s) { + unsigned int *np = fp - (T1_MAXCBLKW + 2); + unsigned int *sp = fp + (T1_MAXCBLKW + 2); + + unsigned int *bwp = fp + ((T1_MAXCBLKW + 2)*(T1_MAXCBLKH +2)); + unsigned int *bnp = bwp - (T1_MAXCBLKW + 2); + unsigned int *bsp = bwp + (T1_MAXCBLKW + 2); + + unsigned int *fwp = fp - ((T1_MAXCBLKW + 2)*(T1_MAXCBLKH +2)); + unsigned int *fnp = fwp - (T1_MAXCBLKW + 2); + unsigned int *fsp = fwp + (T1_MAXCBLKW + 2); + + np[-1] |= T1_3D_SIG_SE; + np[1] |= T1_3D_SIG_SW; + sp[-1] |= T1_3D_SIG_NE; + sp[1] |= T1_3D_SIG_NW; + *np |= T1_3D_SIG_S; + *sp |= T1_3D_SIG_N; + fp[-1] |= T1_3D_SIG_E; + fp[1] |= T1_3D_SIG_W; + + *fwp |= T1_3D_SIG_FC; + *bwp |= T1_3D_SIG_BC; + + fnp[-1] |= T1_3D_SIG_FSE; + fnp[1] |= T1_3D_SIG_FSW; + fsp[-1] |= T1_3D_SIG_FNE; + fsp[1] |= T1_3D_SIG_FNW; + *fnp |= T1_3D_SIG_FS; + *fsp |= T1_3D_SIG_FN; + fwp[-1] |= T1_3D_SIG_FE; + fwp[1] |= T1_3D_SIG_FW; + + bnp[-1] |= T1_3D_SIG_BSE; + bnp[1] |= T1_3D_SIG_BSW; + bsp[-1] |= T1_3D_SIG_BNE; + bsp[1] |= T1_3D_SIG_BNW; + *bnp |= T1_3D_SIG_BS; + *bsp |= T1_3D_SIG_BN; + bwp[-1] |= T1_3D_SIG_BE; + bwp[1] |= T1_3D_SIG_BW; + + if (s) { + *np |= (T1_3D_SGN_S << 16); + *sp |= (T1_3D_SGN_N << 16); + fp[-1] |= (T1_3D_SGN_E << 16); + fp[1] |= (T1_3D_SGN_W << 16); + *fwp |= (T1_3D_SGN_F << 16); + *bwp |= (T1_3D_SGN_B << 16); + } +} + +static void t1_3d_enc_sigpass_step(opj_t1_3d_t *t1, unsigned int *fp, int *fsvr, int *dp, int orient, int bpno, int one, int *nmsedec, char type, int vsc) { + int v, flagsvr; + unsigned int flag; + + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + flag = vsc ? ((*fp) & (~(T1_3D_SIG_S | T1_3D_SIG_SE | T1_3D_SIG_SW | (T1_3D_SGN_S << 16)))) : (*fp); + flagsvr = (*fsvr); + if ((flag & T1_3D_SIG_OTH) && !(flagsvr & (T1_3D_SIG | T1_3D_VISIT))) { + v = int_abs(*dp) & one ? 1 : 0; + if (type == T1_TYPE_RAW) { /* BYPASS/LAZY MODE */ + mqc_setcurctx(mqc, t1_3d_getctxno_zc(flag, orient)); /* ESSAI */ + mqc_bypass_enc(mqc, v); + } else { + mqc_setcurctx(mqc, t1_3d_getctxno_zc(flag, orient)); + mqc_encode(mqc, v); + } + if (v) { + v = *dp < 0 ? 1 : 0; + *nmsedec += t1_3d_getnmsedec_sig(t1, int_abs(*dp), bpno + T1_NMSEDEC_FRACBITS); + if (type == T1_TYPE_RAW) { /* BYPASS/LAZY MODE */ + mqc_setcurctx(mqc, t1_3d_getctxno_sc(flag)); /* ESSAI */ + mqc_bypass_enc(mqc, v); + } else { + mqc_setcurctx(mqc, t1_3d_getctxno_sc(flag)); + mqc_encode(mqc, v ^ t1_3d_getspb(flag)); + } + t1_3d_updateflags(fp, v); + *fsvr |= T1_3D_SIG; + } + *fsvr |= T1_3D_VISIT; + } +} + +static void t1_3d_dec_sigpass_step(opj_t1_3d_t *t1, unsigned int *fp, int *fsvr, int *dp, int orient, int oneplushalf, char type, int vsc) { + int v, flagsvr; + unsigned int flag; + + opj_raw_t *raw = t1->raw; /* RAW component */ + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + flag = vsc ? ((*fp) & (~(T1_3D_SIG_S | T1_3D_SIG_SE | T1_3D_SIG_SW | (T1_3D_SGN_S << 16)))) : (*fp); + flagsvr = (*fsvr); + if ((flag & T1_3D_SIG_OTH) && !(flagsvr & (T1_3D_SIG | T1_3D_VISIT))) { + if (type == T1_TYPE_RAW) { + if (raw_decode(raw)) { + v = raw_decode(raw); /* ESSAI */ + *dp = v ? -oneplushalf : oneplushalf; + t1_3d_updateflags(fp, v); + *fsvr |= T1_3D_SIG; + } + } else { + mqc_setcurctx(mqc, t1_3d_getctxno_zc(flag, orient)); + if (mqc_decode(mqc)) { + mqc_setcurctx(mqc, t1_3d_getctxno_sc(flag)); + v = mqc_decode(mqc) ^ t1_3d_getspb(flag); + *dp = v ? -oneplushalf : oneplushalf; + t1_3d_updateflags(fp, v); + *fsvr |= T1_3D_SIG; + } + } + *fsvr |= T1_3D_VISIT; + } +} /* VSC and BYPASS by Antonin */ + +static void t1_3d_enc_sigpass(opj_t1_3d_t *t1, int w, int h, int l, int bpno, int orient, int *nmsedec, char type, int cblksty) { + int i, j, k, m, one, vsc; + *nmsedec = 0; + one = 1 << (bpno + T1_NMSEDEC_FRACBITS); + for (m = 0; m < l; m++) { + for (k = 0; k < h; k += 4) { + for (i = 0; i < w; i++) { + for (j = k; j < k + 4 && j < h; j++) { + vsc = ((cblksty & J3D_CCP_CBLKSTY_VSC) && (j == k + 3 || j == h - 1)) ? 1 : 0; + t1_3d_enc_sigpass_step(t1, &t1->flags[1 + m][1 + j][1 + i], &t1->flagSVR[1 + m][1 + j][1 + i], &t1->data[m][j][i], orient, bpno, one, nmsedec, type, vsc); + } + } + } + } +} + +static void t1_3d_dec_sigpass(opj_t1_3d_t *t1, int w, int h, int l, int bpno, int orient, char type, int cblksty) { + int i, j, k, m, one, half, oneplushalf, vsc; + one = 1 << bpno; + half = one >> 1; + oneplushalf = one | half; + for (m = 0; m < l; m++) { + for (k = 0; k < h; k += 4) { + for (i = 0; i < w; i++) { + for (j = k; j < k + 4 && j < h; j++) { + vsc = ((cblksty & J3D_CCP_CBLKSTY_VSC) && (j == k + 3 || j == h - 1)) ? 1 : 0; + t1_3d_dec_sigpass_step(t1, &t1->flags[1 + m][1 + j][1 + i], &t1->flagSVR[1 + m][1 + j][1 + i], &t1->data[m][j][i], orient, oneplushalf, type, vsc); + } + } + } + } +} /* VSC and BYPASS by Antonin */ + +static void t1_3d_enc_refpass_step(opj_t1_3d_t *t1, unsigned int *fp, int *fsvr, int *dp, int bpno, int one, int *nmsedec, char type, int vsc) { + int v, flagsvr; + unsigned int flag; + + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + flag = vsc ? ((*fp) & (~(T1_3D_SIG_S | T1_3D_SIG_SE | T1_3D_SIG_SW | (T1_3D_SGN_S << 16)))) : (*fp); + flagsvr = (*fsvr); + if ((flagsvr & (T1_3D_SIG | T1_3D_VISIT)) == T1_3D_SIG) { + *nmsedec += t1_3d_getnmsedec_ref(t1, int_abs(*dp), bpno + T1_NMSEDEC_FRACBITS); + v = int_abs(*dp) & one ? 1 : 0; + if (type == T1_TYPE_RAW) { /* BYPASS/LAZY MODE */ + mqc_setcurctx(mqc, t1_3d_getctxno_mag(flag, flagsvr)); /* ESSAI */ + mqc_bypass_enc(mqc, v); + } else { + mqc_setcurctx(mqc, t1_3d_getctxno_mag(flag, flagsvr)); + mqc_encode(mqc, v); + } + *fsvr |= T1_3D_REFINE; + } +} + +static void t1_3d_dec_refpass_step(opj_t1_3d_t *t1, unsigned int *fp, int *fsvr, int *dp, int poshalf, int neghalf, char type, int vsc) { + int v, t, flagsvr; + unsigned int flag; + + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + opj_raw_t *raw = t1->raw; /* RAW component */ + + flag = vsc ? ((*fp) & (~(T1_3D_SIG_S | T1_3D_SIG_SE | T1_3D_SIG_SW | (T1_3D_SGN_S << 16)))) : (*fp); + flagsvr = (*fsvr); + if ((flagsvr & (T1_3D_SIG | T1_3D_VISIT)) == T1_3D_SIG) { + if (type == T1_TYPE_RAW) { + mqc_setcurctx(mqc, t1_3d_getctxno_mag(flag, flagsvr)); /* ESSAI */ + v = raw_decode(raw); + } else { + mqc_setcurctx(mqc, t1_3d_getctxno_mag(flag, flagsvr)); + v = mqc_decode(mqc); + } + t = v ? poshalf : neghalf; + *dp += *dp < 0 ? -t : t; + *fsvr |= T1_3D_REFINE; + } +} /* VSC and BYPASS by Antonin */ + +static void t1_3d_enc_refpass(opj_t1_3d_t *t1, int w, int h, int l, int bpno, int *nmsedec, char type, int cblksty) { + int i, j, k, m, one, vsc; + *nmsedec = 0; + one = 1 << (bpno + T1_NMSEDEC_FRACBITS); + for (m = 0; m < l; m++){ + for (k = 0; k < h; k += 4) { + for (i = 0; i < w; i++) { + for (j = k; j < k + 4 && j < h; j++) { + vsc = ((cblksty & J3D_CCP_CBLKSTY_VSC) && (j == k + 3 || j == h - 1)) ? 1 : 0; + t1_3d_enc_refpass_step(t1, &t1->flags[1 + m][1 + j][1 + i], &t1->flagSVR[1 + m][1 + j][1 + i], &t1->data[m][j][i], bpno, one, nmsedec, type, vsc); + } + } + } + } +} + +static void t1_3d_dec_refpass(opj_t1_3d_t *t1, int w, int h, int l, int bpno, char type, int cblksty) { + int i, j, k, m, one, poshalf, neghalf; + int vsc; + one = 1 << bpno; + poshalf = one >> 1; + neghalf = bpno > 0 ? -poshalf : -1; + for (m = 0; m < l; m++) { + for (k = 0; k < h; k += 4) { + for (i = 0; i < w; i++) { + for (j = k; j < k + 4 && j < h; j++) { + vsc = ((cblksty & J3D_CCP_CBLKSTY_VSC) && (j == k + 3 || j == h - 1)) ? 1 : 0; + t1_3d_dec_refpass_step(t1, &t1->flags[1 + m][1 + j][1 + i], &t1->flagSVR[1 + m][1 + j][1 + i], &t1->data[m][j][i], poshalf, neghalf, type, vsc); + } + } + } + } +} /* VSC and BYPASS by Antonin */ + +static void t1_3d_enc_clnpass_step(opj_t1_3d_t *t1, unsigned int *fp, int *fsvr, int *dp, int orient, int bpno, int one, int *nmsedec, int partial, int vsc) { + int v, flagsvr; + unsigned int flag; + + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + flag = vsc ? ((*fp) & (~(T1_3D_SIG_S | T1_3D_SIG_SE | T1_3D_SIG_SW | (T1_3D_SGN_S << 16)))) : (*fp); + flagsvr = (*fsvr); + if (partial) { + goto LABEL_PARTIAL; + } + if (!(*fsvr & (T1_3D_SIG | T1_3D_VISIT))) { + mqc_setcurctx(mqc, t1_3d_getctxno_zc(flag, orient)); + v = int_abs(*dp) & one ? 1 : 0; + mqc_encode(mqc, v); + if (v) { +LABEL_PARTIAL: + *nmsedec += t1_3d_getnmsedec_sig(t1, int_abs(*dp), bpno + T1_NMSEDEC_FRACBITS); + mqc_setcurctx(mqc, t1_3d_getctxno_sc(flag)); + v = *dp < 0 ? 1 : 0; + mqc_encode(mqc, v ^ t1_3d_getspb(flag)); + t1_3d_updateflags(fp, v); + *fsvr |= T1_3D_SIG; + } + } + *fsvr &= ~T1_3D_VISIT; +} + +static void t1_3d_dec_clnpass_step(opj_t1_3d_t *t1, unsigned int *fp, int *fsvr, int *dp, int orient, int oneplushalf, int partial, int vsc) { + int v, flagsvr; + unsigned int flag; + + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + flag = vsc ? ((*fp) & (~(T1_3D_SIG_S | T1_3D_SIG_SE | T1_3D_SIG_SW | (T1_3D_SGN_S << 16)))) : (*fp); + flagsvr = (*fsvr); + if (partial) { + goto LABEL_PARTIAL; + } + if (!(flagsvr & (T1_3D_SIG | T1_3D_VISIT))) { + mqc_setcurctx(mqc, t1_3d_getctxno_zc(flag, orient)); + if (mqc_decode(mqc)) { +LABEL_PARTIAL: + mqc_setcurctx(mqc, t1_3d_getctxno_sc(flag)); + v = mqc_decode(mqc) ^ t1_3d_getspb(flag); + *dp = v ? -oneplushalf : oneplushalf; + t1_3d_updateflags(fp, v); + *fsvr |= T1_3D_SIG; + } + } + *fsvr &= ~T1_3D_VISIT; +} /* VSC and BYPASS by Antonin */ + +static void t1_3d_enc_clnpass(opj_t1_3d_t *t1, int w, int h, int l, int bpno, int orient, int *nmsedec, int cblksty) { + int i, j, k, m, one, agg, runlen, vsc; + + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + *nmsedec = 0; + one = 1 << (bpno + T1_NMSEDEC_FRACBITS); + for (m = 0; m < l; m++) { + for (k = 0; k < h; k += 4) { + for (i = 0; i < w; i++) { + if (k + 3 < h) { + if (cblksty & J3D_CCP_CBLKSTY_VSC) { + agg = !( ((t1->flagSVR[1 + m][1 + k][1 + i] | (T1_3D_SIG | T1_3D_VISIT)) & (t1->flags[1 + m][1 + k][1 + i] & T1_3D_SIG_OTH)) + || ((t1->flagSVR[1 + m][1 + k + 1][1 + i] | (T1_3D_SIG | T1_3D_VISIT)) & (t1->flags[1 + m][1 + k + 1][1 + i] & T1_3D_SIG_OTH)) + || ((t1->flagSVR[1 + m][1 + k + 2][1 + i] | (T1_3D_SIG | T1_3D_VISIT)) & (t1->flags[1 + m][1 + k + 2][1 + i] & T1_3D_SIG_OTH)) + || ((t1->flagSVR[1 + m][1 + k + 3][1 + i] | (T1_3D_SIG | T1_3D_VISIT)) & ((t1->flags[1 + m][1 + k + 3][1 + i] & (~(T1_3D_SIG_S | T1_3D_SIG_SE | T1_3D_SIG_SW | (T1_3D_SGN_S << 16)))) & (T1_3D_SIG_OTH))) + ); + } else { + agg = !( + ((t1->flagSVR[1 + m][1 + k][1 + i] & (T1_3D_SIG | T1_3D_VISIT)) | (t1->flags[1 + m][1 + k][1 + i] & T1_3D_SIG_OTH)) + || ((t1->flagSVR[1 + m][1 + k + 1][1 + i] & (T1_3D_SIG | T1_3D_VISIT)) | (t1->flags[1 + m][1 + k + 1][1 + i] & T1_3D_SIG_OTH)) + || ((t1->flagSVR[1 + m][1 + k + 2][1 + i] & (T1_3D_SIG | T1_3D_VISIT)) | (t1->flags[1 + m][1 + k + 2][1 + i] & T1_3D_SIG_OTH)) + || ((t1->flagSVR[1 + m][1 + k + 3][1 + i] & (T1_3D_SIG | T1_3D_VISIT)) | (t1->flags[1 + m][1 + k + 3][1 + i] & T1_3D_SIG_OTH)) + ); + } + } else { + agg = 0; + } + if (agg) { + for (runlen = 0; runlen < 4; runlen++) { + if (int_abs(t1->data[m][k + runlen][i]) & one) + break; + } + mqc_setcurctx(mqc, T1_CTXNO_AGG); + mqc_encode(mqc, runlen != 4); + if (runlen == 4) { + continue; + } + mqc_setcurctx(mqc, T1_CTXNO_UNI); + mqc_encode(mqc, runlen >> 1); + mqc_encode(mqc, runlen & 1); + } else { + runlen = 0; + } + for (j = k + runlen; j < k + 4 && j < h; j++) { + vsc = ((cblksty & J3D_CCP_CBLKSTY_VSC) && (j == k + 3 || j == h - 1)) ? 1 : 0; + t1_3d_enc_clnpass_step(t1, &t1->flags[1 + m][1 + j][1 + i], &t1->flagSVR[1 + m][1 + j][1 + i], &t1->data[m][j][i], orient, bpno, one, nmsedec, agg && (j == k + runlen), vsc); + } + } + } + } +} + +static void t1_3d_dec_clnpass(opj_t1_3d_t *t1, int w, int h, int l, int bpno, int orient, int cblksty) { + int i, j, k, m, one, half, oneplushalf, agg, runlen, vsc; + int segsym = cblksty & J3D_CCP_CBLKSTY_SEGSYM; + + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + one = 1 << bpno; + half = one >> 1; + oneplushalf = one | half; + for (m = 0; m < l; m++) { + for (k = 0; k < h; k += 4) { + for (i = 0; i < w; i++) { + if (k + 3 < h) { + if (cblksty & J3D_CCP_CBLKSTY_VSC) { + agg = !( + ((t1->flagSVR[1 + m][1 + k][1 + i] & (T1_3D_SIG | T1_3D_VISIT)) | (t1->flags[1 + m][1 + k][1 + i] & T1_3D_SIG_OTH)) + || ((t1->flagSVR[1 + m][1 + k + 1][1 + i] & (T1_3D_SIG | T1_3D_VISIT)) | (t1->flags[1 + m][1 + k + 1][1 + i] & T1_3D_SIG_OTH)) + || ((t1->flagSVR[1 + m][1 + k + 2][1 + i] & (T1_3D_SIG | T1_3D_VISIT)) | (t1->flags[1 + m][1 + k + 2][1 + i] & T1_3D_SIG_OTH)) + || ((t1->flagSVR[1 + m][1 + k + 3][1 + i] & (T1_3D_SIG | T1_3D_VISIT)) | ((t1->flags[1 + m][1 + k + 3][1 + i] & (~(T1_3D_SIG_S | T1_3D_SIG_SE | T1_3D_SIG_SW | (T1_3D_SGN_S << 16)))) & (T1_3D_SIG_OTH))) + ); + } else { + agg = !( + ((t1->flagSVR[1 + m][1 + k][1 + i] & (T1_3D_SIG | T1_3D_VISIT)) | (t1->flags[1 + m][1 + k][1 + i] & T1_3D_SIG_OTH)) + || ((t1->flagSVR[1 + m][1 + k + 1][1 + i] & (T1_3D_SIG | T1_3D_VISIT)) | (t1->flags[1 + m][1 + k + 1][1 + i] & T1_3D_SIG_OTH)) + || ((t1->flagSVR[1 + m][1 + k + 2][1 + i] & (T1_3D_SIG | T1_3D_VISIT)) | (t1->flags[1 + m][1 + k + 2][1 + i] & T1_3D_SIG_OTH)) + || ((t1->flagSVR[1 + m][1 + k + 3][1 + i] & (T1_3D_SIG | T1_3D_VISIT)) | (t1->flags[1 + m][1 + k + 3][1 + i] & T1_3D_SIG_OTH)) + ); + } + } else { + agg = 0; + } + if (agg) { + mqc_setcurctx(mqc, T1_CTXNO_AGG); + if (!mqc_decode(mqc)) { + continue; + } + mqc_setcurctx(mqc, T1_CTXNO_UNI); + runlen = mqc_decode(mqc); + runlen = (runlen << 1) | mqc_decode(mqc); + } else { + runlen = 0; + } + for (j = k + runlen; j < k + 4 && j < h; j++) { + vsc = ((cblksty & J3D_CCP_CBLKSTY_VSC) && (j == k + 3 || j == h - 1)) ? 1 : 0; + t1_3d_dec_clnpass_step(t1, &t1->flags[1 + m][1 + j][1 + i], &t1->flagSVR[1 + m][1 + j][1 + i], &t1->data[m][j][i], orient, oneplushalf, agg && (j == k + runlen), vsc); + } + } + } + } + if (segsym) { + int v = 0; + mqc_setcurctx(mqc, T1_CTXNO_UNI); + v = mqc_decode(mqc); + v = (v << 1) | mqc_decode(mqc); + v = (v << 1) | mqc_decode(mqc); + v = (v << 1) | mqc_decode(mqc); + /* + if (v!=0xa) { + opj_event_msg(t1->cinfo, EVT_WARNING, "Bad segmentation symbol %x\n", v); + } + */ + } +} /* VSC and BYPASS by Antonin */ + + +static void t1_3d_encode_cblk(opj_t1_3d_t *t1, opj_tcd_cblk_t * cblk, int orient, int compno, int level[3], int dwtid[3], double stepsize, int cblksty, int numcomps, opj_tcd_tile_t * tile) { + int i, j, k; + int w, h, l; + int passno; + int bpno, passtype; + int max; + int nmsedec = 0; + double cumwmsedec = 0; + char type = T1_TYPE_MQ; + + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + w = cblk->x1 - cblk->x0; + h = cblk->y1 - cblk->y0; + l = cblk->z1 - cblk->z0; + + max = 0; + for (k = 0; k < l; k++) { + for (j = 0; j < h; j++) { + for (i = 0; i < w; i++) { + max = int_max(max, int_abs(t1->data[k][j][i])); + } + } + } + for (k = 0; k <= l; k++) { + for (j = 0; j <= h; j++) { + for (i = 0; i <= w; i++) { + t1->flags[k][j][i] = 0; + t1->flagSVR[k][j][i] = 0; + } + } + } + + cblk->numbps = max ? (int_floorlog2(max) + 1) - T1_NMSEDEC_FRACBITS : 0; + + bpno = cblk->numbps - 1; + passtype = 2; + + mqc_reset_enc(mqc); + mqc_init_enc(mqc, cblk->data); + + for (passno = 0; bpno >= 0; passno++) { + opj_tcd_pass_t *pass = &cblk->passes[passno]; + int correction = 3; + double tmpwmsedec; + type = ((bpno < (cblk->numbps - 4)) && (passtype < 2) && (cblksty & J3D_CCP_CBLKSTY_LAZY)) ? T1_TYPE_RAW : T1_TYPE_MQ; + + switch (passtype) { + case 0: + t1_3d_enc_sigpass(t1, w, h, l, bpno, orient, &nmsedec, type, cblksty); + break; + case 1: + t1_3d_enc_refpass(t1, w, h, l, bpno, &nmsedec, type, cblksty); + break; + case 2: + t1_3d_enc_clnpass(t1, w, h, l, bpno, orient, &nmsedec, cblksty); + /* code switch SEGMARK (i.e. SEGSYM) */ + if (cblksty & J3D_CCP_CBLKSTY_SEGSYM) + mqc_segmark_enc(mqc); + break; + } + + /* fixed_quality */ + tmpwmsedec = t1_getwmsedec(nmsedec, compno, level, orient, bpno, stepsize, numcomps, dwtid); + cumwmsedec += tmpwmsedec; + tile->distotile += tmpwmsedec; + + /* Code switch "RESTART" (i.e. TERMALL) */ + if ((cblksty & J3D_CCP_CBLKSTY_TERMALL) && !((passtype == 2) && (bpno - 1 < 0))) { + if (type == T1_TYPE_RAW) { + mqc_flush(mqc); + correction = 1; + /* correction = mqc_bypass_flush_enc(); */ + } else { /* correction = mqc_restart_enc(); */ + mqc_flush(mqc); + correction = 1; + } + pass->term = 1; + } else { + if (((bpno < (cblk->numbps - 4) && (passtype > 0)) + || ((bpno == (cblk->numbps - 4)) && (passtype == 2))) && (cblksty & J3D_CCP_CBLKSTY_LAZY)) { + if (type == T1_TYPE_RAW) { + mqc_flush(mqc); + correction = 1; + } else { + mqc_flush(mqc); + correction = 1; + } + pass->term = 1; + } else { + pass->term = 0; + } + } + + if (++passtype == 3) { + passtype = 0; + bpno--; + } + + if (pass->term && bpno > 0) { + type = ((bpno < (cblk->numbps - 4)) && (passtype < 2) && (cblksty & J3D_CCP_CBLKSTY_LAZY)) ? T1_TYPE_RAW : T1_TYPE_MQ; + if (type == T1_TYPE_RAW) + mqc_bypass_init_enc(mqc); + else + mqc_restart_init_enc(mqc); + } + + pass->distortiondec = cumwmsedec; + pass->rate = mqc_numbytes(mqc) + correction; /* FIXME */ + pass->len = pass->rate - (passno == 0 ? 0 : cblk->passes[passno - 1].rate); + + /* Code-switch "RESET" */ + if (cblksty & J3D_CCP_CBLKSTY_RESET) + mqc_reset_enc(mqc); + } + + /* Code switch "ERTERM" (i.e. PTERM) */ + if (cblksty & J3D_CCP_CBLKSTY_PTERM) + mqc_erterm_enc(mqc); + else /* Default coding */ if (!(cblksty & J3D_CCP_CBLKSTY_LAZY)) + mqc_flush(mqc); + + cblk->totalpasses = passno; +} + +static void t1_3d_decode_cblk(opj_t1_3d_t *t1, opj_tcd_cblk_t * cblk, int orient, int roishift, int cblksty) { + int i, j, k; + int w, h, l; + int bpno, passtype; + int segno, passno; + char type = T1_TYPE_MQ; /* BYPASS mode */ + opj_raw_t *raw = t1->raw; /* RAW component */ + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + w = cblk->x1 - cblk->x0; + h = cblk->y1 - cblk->y0; + l = cblk->z1 - cblk->z0; + + for (k = 0; k < l; k++) { + for (j = 0; j < h; j++) { + for (i = 0; i < w; i++) { + t1->data[k][j][i] = 0; + } + } + } + + for (k = 0; k <= l; k++) { + for (j = 0; j <= h; j++) { + for (i = 0; i <= w; i++) { + t1->flags[k][j][i] = 0; + t1->flagSVR[k][j][i] = 0; + } + } + } + + + bpno = roishift + cblk->numbps - 1; + passtype = 2; + + mqc_reset_enc(mqc); + + for (segno = 0; segno < cblk->numsegs; segno++) { + opj_tcd_seg_t *seg = &cblk->segs[segno]; + + /* BYPASS mode */ + type = ((bpno <= (cblk->numbps - 1) - 4) && (passtype < 2) && (cblksty & J3D_CCP_CBLKSTY_LAZY)) ? T1_TYPE_RAW : T1_TYPE_MQ; + if (type == T1_TYPE_RAW) { + raw_init_dec(raw, seg->data, seg->len); + } else { + mqc_init_dec(mqc, seg->data, seg->len); + } + + for (passno = 0; passno < seg->numpasses; passno++) { + switch (passtype) { + case 0: + t1_3d_dec_sigpass(t1, w, h, l, bpno+1, orient, type, cblksty); + break; + case 1: + t1_3d_dec_refpass(t1, w, h, l, bpno+1, type, cblksty); + break; + case 2: + t1_3d_dec_clnpass(t1, w, h, l, bpno+1, orient, cblksty); + break; + } + + if ((cblksty & J3D_CCP_CBLKSTY_RESET) && type == T1_TYPE_MQ) { + mqc_reset_enc(mqc); + } + if (++passtype == 3) { + passtype = 0; + bpno--; + } + + } + } +} + +static int t1_3d_init_ctxno_zc(unsigned int f, int orient) { + unsigned int h, v, c; + unsigned int d2xy, d2xz, d2yz, d3; + int n; + unsigned int hvc, hc, d2, d2xy2yz, d2xy2xz; + n = 0; + h = ((f & T1_3D_SIG_W) != 0) + ((f & T1_3D_SIG_E) != 0); + v = ((f & T1_3D_SIG_N) != 0) + ((f & T1_3D_SIG_S) != 0); + c = ((f & T1_3D_SIG_FC) != 0) + ((f & T1_3D_SIG_BC) != 0); + d2xy = ((f & T1_3D_SIG_NW) != 0) + ((f & T1_3D_SIG_NE) != 0) + ((f & T1_3D_SIG_SE) != 0) + ((f & T1_3D_SIG_SW) != 0); + d2xz = ((f & T1_3D_SIG_FW) != 0) + ((f & T1_3D_SIG_BW) != 0) + ((f & T1_3D_SIG_FE) != 0) + ((f & T1_3D_SIG_BE) != 0); + d2yz = ((f & T1_3D_SIG_FN) != 0) + ((f & T1_3D_SIG_FS) != 0) + ((f & T1_3D_SIG_BN) != 0) + ((f & T1_3D_SIG_BS) != 0); + d3 = ((f & T1_3D_SIG_FNW) != 0) + ((f & T1_3D_SIG_FNE) != 0) + ((f & T1_3D_SIG_FSE) != 0) + ((f & T1_3D_SIG_FSW) != 0) + + ((f & T1_3D_SIG_BNW) != 0) + ((f & T1_3D_SIG_BNE) != 0) + ((f & T1_3D_SIG_BSE) != 0) + ((f & T1_3D_SIG_BSW) != 0); + + switch (orient) { + case 0: //LLL + case 7: //HHH + hvc = h + v + c; + d2 = d2xy + d2xz + d2yz; + if (!hvc) { + if (!d2) { + n = (!d3) ? 0 : 1; + } else if (d2 == 1) { + n = (!d3) ? 2 : 3; + } else { + n = (!d3) ? 4 : 5; + } + } else if (hvc == 1) { + if (!d2) { + n = (!d3) ? 6 : 7; + } else if (d2 == 1) { + n = (!d3) ? 8 : 9; + } else { + n = 10; + } + } else if (hvc == 2) { + if (!d2) { + n = (!d3) ? 11 : 12; + } else { + n = 13; + } + } else if (hvc == 3) { + n = 14; + } else { + n = 15; + } + break; + //LHL, HLL, LLH + case 1: + case 2: + case 4: + hc = h + c; + d2xy2yz = d2xy + d2yz; + if (!hc) { + if (!v) { + if (!d2xy) { + n = (!d2xy2yz) ? ((!d3) ? 0 : 1) : ((!d3) ? 2 : 3); + } else if (d2xy == 1) { + n = (!d2xy2yz) ? ((!d3) ? 4 : 5) : 6; + } else { //>=2 + n = 7; + } + } else { + n = (v == 1) ? 8 : 9; // =1 or =2 + } + } else if (hc == 1) { + n = (!v) ? ( (!d2xy) ? ( (!d2xy2yz) ? ( (!d3) ? 10 : 11) : (12) ) : (13) ) : (14); + } else { //if (hc >= 2) + n = 15; + } + break; + //HLH, HHL, LHH + case 3: + case 5: + case 6: + hc = h + c; + d2xy2xz = d2xy + d2xz; + if (!v) { + if (!d2xz) { + if (!hc && !d2xy2xz) { + n = (!d3) ? 0 : 1; + } else if (hc == 1) { + n = (!d2xy2xz) ? 2 : 3; + } else { //if >= 2 + n = 4; + } + } else if ( d2xz>=1 && !hc ) { + n = 5; + } else if ( hc>=1 ) { + n = (d2xz==1) ? 6 : 7; + } + } else if (v == 1) { + if (!d2xz) { + n = (!hc) ? 8 : 9; + } else if (d2xz == 1) { + n = (!hc) ? 10 : 11; + } else if (d2xz == 2) { + n = (!hc) ? 12 : 13; + } else { // if (d2xz >= 3) { + n = 14; + } + } else if (v == 2) { + n = 15; + } + break; + } + + return (T1_3D_CTXNO_ZC + n); +} + +static int t1_3d_init_ctxno_sc(unsigned int f) { + int hc, vc, cc; + int n = 0; + + hc = int_min( ( (f & (T1_3D_SIG_E | T1_3D_SGN_E)) == T1_3D_SIG_E ) + + ( (f & (T1_3D_SIG_W | T1_3D_SGN_W)) == T1_3D_SIG_W ) , 1) + - int_min( ( (f & (T1_3D_SIG_E | T1_3D_SGN_E)) == (T1_3D_SIG_E | T1_3D_SGN_E) ) + + ( (f & (T1_3D_SIG_W | T1_3D_SGN_W) ) == (T1_3D_SIG_W | T1_3D_SGN_W)), 1); + + vc = int_min(((f & (T1_3D_SIG_N | T1_3D_SGN_N)) == T1_3D_SIG_N) + + ((f & (T1_3D_SIG_S | T1_3D_SGN_S)) == T1_3D_SIG_S), 1) + - int_min(((f & (T1_3D_SIG_N | T1_3D_SGN_N)) == (T1_3D_SIG_N | T1_3D_SGN_N)) + + ((f & (T1_3D_SIG_S | T1_3D_SGN_S)) == (T1_3D_SIG_S | T1_3D_SGN_S)), 1); + + cc = int_min(((f & (T1_3D_SIG_FC | T1_3D_SGN_F)) == T1_3D_SIG_FC) + + ((f & (T1_3D_SIG_BC | T1_3D_SGN_B)) == T1_3D_SIG_BC), 1) + - int_min(((f & (T1_3D_SIG_FC | T1_3D_SGN_F)) == (T1_3D_SIG_FC | T1_3D_SGN_F)) + + ((f & (T1_3D_SIG_BC | T1_3D_SGN_B)) == (T1_3D_SIG_BC | T1_3D_SGN_B)), 1); + if (hc < 0) { + hc = -hc; + vc = -vc; + cc = -cc; + } + + if (!hc) { + if (!vc) + n = (!cc) ? 0 : 1; + else if (vc == -1) + n = (!cc) ? 1 : ( (cc>0) ? 2 : 4); + else if (vc == 1) + n = (!cc) ? 1 : ( (cc<0) ? 2 : 4); + } else if (hc == 1) { + if (!vc) + n = (!cc) ? 1 : ( (cc<0) ? 2 : 4); + else if (vc == 1) + n = (!cc) ? 4 : ( (cc>0) ? 5 : 3); + else if (vc == -1) + n = (!cc) ? 2 : 3; + } else if (hc == -1) { + if (!vc) + n = (!cc) ? 1 : ( (cc>0) ? 2 : 4); + else if (vc == 1) + n = (!cc) ? 2 : 3; + else if (vc == -1) + n = (!cc) ? 4 : ( (cc<0) ? 5 : 3); + } + + return (T1_3D_CTXNO_SC + n); +} + +static int t1_3d_init_ctxno_mag(unsigned int f, int f2) { + int n; + if (!(f2 & T1_3D_REFINE)) //First refinement for this coefficient (no previous refinement) + n = (f & (T1_3D_SIG_PRIM)) ? 1 : 0; + else + n = 2; + + return (T1_3D_CTXNO_MAG + n); +} + +static int t1_3d_init_spb(unsigned int f) { + int hc, vc, cc; + int n = 0; + + hc = int_min( ( (f & (T1_3D_SIG_E | T1_3D_SGN_E)) == T1_3D_SIG_E ) + + ( (f & (T1_3D_SIG_W | T1_3D_SGN_W)) == T1_3D_SIG_W ) , 1) + - int_min( ( (f & (T1_3D_SIG_E | T1_3D_SGN_E)) == (T1_3D_SIG_E | T1_3D_SGN_E) ) + + ( (f & (T1_3D_SIG_W | T1_3D_SGN_W) ) == (T1_3D_SIG_W | T1_3D_SGN_W)), 1); + + vc = int_min(((f & (T1_3D_SIG_N | T1_3D_SGN_N)) == T1_3D_SIG_N) + + ((f & (T1_3D_SIG_S | T1_3D_SGN_S)) == T1_3D_SIG_S), 1) + - int_min(((f & (T1_3D_SIG_N | T1_3D_SGN_N)) == (T1_3D_SIG_N | T1_3D_SGN_N)) + + ((f & (T1_3D_SIG_S | T1_3D_SGN_S)) == (T1_3D_SIG_S | T1_3D_SGN_S)), 1); + + cc = int_min(((f & (T1_3D_SIG_FC | T1_3D_SGN_F)) == T1_3D_SIG_FC) + + ((f & (T1_3D_SIG_BC | T1_3D_SGN_B)) == T1_3D_SIG_BC), 1) + - int_min(((f & (T1_3D_SIG_FC | T1_3D_SGN_F)) == (T1_3D_SIG_FC | T1_3D_SGN_F)) + + ((f & (T1_3D_SIG_BC | T1_3D_SGN_B)) == (T1_3D_SIG_BC | T1_3D_SGN_B)), 1); + + n = ((hc + vc + cc) < 0); + + return n; +} + +static void t1_3d_init_luts(opj_t1_3d_t *t1) { + int i; + double u, v, t; + /*for (j = 0; j < 4; j++) { + for (i = 0; i < 256; ++i) { + t1->lut_ctxno_zc[(j << 8) | i] = t1_3d_init_ctxno_zc(i, j); + } + } + for (i = 0; i < 4096; i++) { + t1->lut_ctxno_sc[i] = t1_3d_init_ctxno_sc(i << 4); + } + for (j = 0; j < 2; j++) { + for (i = 0; i < 2048; ++i) { + t1->lut_ctxno_mag[(j << 11) + i] = t1_3d_init_ctxno_mag((j ? T1_3D_REFINE : 0) | i); + } + } + for (i = 0; i < 4096; ++i) { + t1->lut_spb[i] = t1_3d_init_spb(i << 4); + }*/ + /* FIXME FIXME FIXME */ + for (i = 0; i < (1 << T1_NMSEDEC_BITS); i++) { + t = i / pow(2, T1_NMSEDEC_FRACBITS); + u = t; + v = t - 1.5; + t1->lut_nmsedec_sig[i] = + int_max(0, + (int) (floor((u * u - v * v) * pow(2, T1_NMSEDEC_FRACBITS) + 0.5) / pow(2, T1_NMSEDEC_FRACBITS) * 8192.0)); + t1->lut_nmsedec_sig0[i] = + int_max(0, + (int) (floor((u * u) * pow(2, T1_NMSEDEC_FRACBITS) + 0.5) / pow(2, T1_NMSEDEC_FRACBITS) * 8192.0)); + u = t - 1.0; + if (i & (1 << (T1_NMSEDEC_BITS - 1))) { + v = t - 1.5; + } else { + v = t - 0.5; + } + t1->lut_nmsedec_ref[i] = + int_max(0, + (int) (floor((u * u - v * v) * pow(2, T1_NMSEDEC_FRACBITS) + 0.5) / pow(2, T1_NMSEDEC_FRACBITS) * 8192.0)); + t1->lut_nmsedec_ref0[i] = + int_max(0, + (int) (floor((u * u) * pow(2, T1_NMSEDEC_FRACBITS) + 0.5) / pow(2, T1_NMSEDEC_FRACBITS) * 8192.0)); + } +} + +/* ----------------------------------------------------------------------- */ + +opj_t1_3d_t* t1_3d_create(opj_common_ptr cinfo) { + opj_t1_3d_t *t1 = (opj_t1_3d_t*)opj_malloc(sizeof(opj_t1_3d_t)); + if(t1) { + t1->cinfo = cinfo; + /* create MQC and RAW handles */ + t1->mqc = mqc_create(); + t1->raw = raw_create(); + /* initialize the look-up tables of the Tier-1 coder/decoder */ + t1_3d_init_luts(t1); + } + return t1; +} + +void t1_3d_destroy(opj_t1_3d_t *t1) { + if(t1) { + /* destroy MQC and RAW handles */ + mqc_destroy(t1->mqc); + raw_destroy(t1->raw); + opj_free(t1); + } +} + +void t1_3d_encode_cblks(opj_t1_3d_t *t1, opj_tcd_tile_t *tile, opj_tcp_t *tcp) { + int compno, resno, bandno, precno, cblkno; + int x, y, z, i, j, k, orient; + int level[3]; + tile->distotile = 0; /* fixed_quality */ + + for (compno = 0; compno < tile->numcomps; compno++) { + opj_tcd_tilecomp_t *tilec = &tile->comps[compno]; + + for (resno = 0; resno < tilec->numresolution[0]; resno++) { + opj_tcd_resolution_t *res = &tilec->resolutions[resno]; + + for (bandno = 0; bandno < res->numbands; bandno++) { + opj_tcd_band_t *band = &res->bands[bandno]; + + for (precno = 0; precno < res->prctno[0] * res->prctno[1] * res->prctno[2]; precno++) { + opj_tcd_precinct_t *prc = &band->precincts[precno]; + + for (cblkno = 0; cblkno < prc->cblkno[0] * prc->cblkno[1] * prc->cblkno[2]; cblkno++) { + opj_tcd_cblk_t *cblk = &prc->cblks[cblkno]; + + if (band->bandno == 0) { + x = cblk->x0 - band->x0; + y = cblk->y0 - band->y0; + z = cblk->z0 - band->z0; + } else if (band->bandno == 1) { + opj_tcd_resolution_t *pres = &tilec->resolutions[resno - 1]; + x = pres->x1 - pres->x0 + cblk->x0 - band->x0; + y = cblk->y0 - band->y0; + z = cblk->z0 - band->z0; + } else if (band->bandno == 2) { + opj_tcd_resolution_t *pres = &tilec->resolutions[resno - 1]; + x = cblk->x0 - band->x0; + y = pres->y1 - pres->y0 + cblk->y0 - band->y0; + z = cblk->z0 - band->z0; + } else if (band->bandno == 3) { + opj_tcd_resolution_t *pres = &tilec->resolutions[resno - 1]; + x = pres->x1 - pres->x0 + cblk->x0 - band->x0; + y = pres->y1 - pres->y0 + cblk->y0 - band->y0; + z = cblk->z0 - band->z0; + } else if (band->bandno == 4) { + opj_tcd_resolution_t *pres = &tilec->resolutions[resno - 1]; + x = cblk->x0 - band->x0; + y = cblk->y0 - band->y0; + z = pres->z1 - pres->z0 + cblk->z0 - band->z0; + } else if (band->bandno == 5) { + opj_tcd_resolution_t *pres = &tilec->resolutions[resno - 1]; + x = pres->x1 - pres->x0 + cblk->x0 - band->x0; + y = cblk->y0 - band->y0; + z = pres->z1 - pres->z0 + cblk->z0 - band->z0; + } else if (band->bandno == 6) { + opj_tcd_resolution_t *pres = &tilec->resolutions[resno - 1]; + x = cblk->x0 - band->x0; + y = pres->y1 - pres->y0 + cblk->y0 - band->y0; + z = pres->z1 - pres->z0 + cblk->z0 - band->z0; + } else if (band->bandno == 7) { + opj_tcd_resolution_t *pres = &tilec->resolutions[resno - 1]; + x = pres->x1 - pres->x0 + cblk->x0 - band->x0; + y = pres->y1 - pres->y0 + cblk->y0 - band->y0; + z = pres->z1 - pres->z0 + cblk->z0 - band->z0; + } + + if (tcp->tccps[compno].reversible == 1) { + for (k = 0; k < cblk->z1 - cblk->z0; k++) { + for (j = 0; j < cblk->y1 - cblk->y0; j++) { + for (i = 0; i < cblk->x1 - cblk->x0; i++) { + t1->data[k][j][i] = + tilec->data[(x + i) + (y + j) * (tilec->x1 - tilec->x0) + (z + k) * (tilec->x1 - tilec->x0) * (tilec->y1 - tilec->y0)] << T1_NMSEDEC_FRACBITS; + } + } + } + } else if (tcp->tccps[compno].reversible == 0) { + for (k = 0; k < cblk->z1 - cblk->z0; k++) { + for (j = 0; j < cblk->y1 - cblk->y0; j++) { + for (i = 0; i < cblk->x1 - cblk->x0; i++) { + t1->data[k][j][i] = fix_mul( + tilec->data[(x + i) + (y + j) * (tilec->x1 - tilec->x0) + (z + k) * (tilec->x1 - tilec->x0) * (tilec->y1 - tilec->y0)], + 8192 * 8192 / ((int) floor(band->stepsize * 8192))) >> (13 - T1_NMSEDEC_FRACBITS); + } + } + } + } + orient = band->bandno; /* FIXME */ + for (i = 0; i < 3; i++) + level[i] = tilec->numresolution[i] - 1 - resno; + + t1_3d_encode_cblk(t1, cblk, orient, compno, level, tcp->tccps[compno].dwtid, band->stepsize, tcp->tccps[compno].cblksty, tile->numcomps, tile); + + } /* cblkno */ + } /* precno */ + } /* bandno */ + } /* resno */ + } /* compno */ +} + +void t1_3d_decode_cblks(opj_t1_3d_t *t1, opj_tcd_tile_t *tile, opj_tcp_t *tcp) { + int compno, resno, bandno, precno, cblkno; + + for (compno = 0; compno < tile->numcomps; compno++) { + opj_tcd_tilecomp_t *tilec = &tile->comps[compno]; + + for (resno = 0; resno < tilec->numresolution[0]; resno++) { + opj_tcd_resolution_t *res = &tilec->resolutions[resno]; + + for (bandno = 0; bandno < res->numbands; bandno++) { + opj_tcd_band_t *band = &res->bands[bandno]; + + for (precno = 0; precno < res->prctno[0] * res->prctno[1] * res->prctno[2]; precno++) { + opj_tcd_precinct_t *prc = &band->precincts[precno]; + + for (cblkno = 0; cblkno < prc->cblkno[0] * prc->cblkno[1] * prc->cblkno[2]; cblkno++) { + int x, y, z, i, j, k, orient; + opj_tcd_cblk_t *cblk = &prc->cblks[cblkno]; + + orient = band->bandno; /* FIXME */ + + //fprintf(stdout,"[INFO] t1_3d_decode_cblk(t1, cblk, orient(%d), tcp->tccps[compno].roishift (%d), tcp->tccps[compno].cblksty (%d));\n",orient,tcp->tccps[compno].roishift, tcp->tccps[compno].cblksty); + t1_3d_decode_cblk(t1, cblk, orient, tcp->tccps[compno].roishift, tcp->tccps[compno].cblksty); + + if (band->bandno == 0) { + x = cblk->x0 - band->x0; + y = cblk->y0 - band->y0; + z = cblk->z0 - band->z0; + } else if (band->bandno == 1) { + opj_tcd_resolution_t *pres = &tilec->resolutions[resno - 1]; + x = pres->x1 - pres->x0 + cblk->x0 - band->x0; + y = cblk->y0 - band->y0; + z = cblk->z0 - band->z0; + } else if (band->bandno == 2) { + opj_tcd_resolution_t *pres = &tilec->resolutions[resno - 1]; + x = cblk->x0 - band->x0; + y = pres->y1 - pres->y0 + cblk->y0 - band->y0; + z = cblk->z0 - band->z0; + } else if (band->bandno == 3) { + opj_tcd_resolution_t *pres = &tilec->resolutions[resno - 1]; + x = pres->x1 - pres->x0 + cblk->x0 - band->x0; + y = pres->y1 - pres->y0 + cblk->y0 - band->y0; + z = cblk->z0 - band->z0; + } else if (band->bandno == 4) { + opj_tcd_resolution_t *pres = &tilec->resolutions[resno - 1]; + x = cblk->x0 - band->x0; + y = cblk->y0 - band->y0; + z = pres->z1 - pres->z0 + cblk->z0 - band->z0; + } else if (band->bandno == 5) { + opj_tcd_resolution_t *pres = &tilec->resolutions[resno - 1]; + x = pres->x1 - pres->x0 + cblk->x0 - band->x0; + y = cblk->y0 - band->y0; + z = pres->z1 - pres->z0 + cblk->z0 - band->z0; + } else if (band->bandno == 6) { + opj_tcd_resolution_t *pres = &tilec->resolutions[resno - 1]; + x = cblk->x0 - band->x0; + y = pres->y1 - pres->y0 + cblk->y0 - band->y0; + z = pres->z1 - pres->z0 + cblk->z0 - band->z0; + } else if (band->bandno == 7) { + opj_tcd_resolution_t *pres = &tilec->resolutions[resno - 1]; + x = pres->x1 - pres->x0 + cblk->x0 - band->x0; + y = pres->y1 - pres->y0 + cblk->y0 - band->y0; + z = pres->z1 - pres->z0 + cblk->z0 - band->z0; + } + + if (tcp->tccps[compno].roishift) { + int thresh, val, mag; + thresh = 1 << tcp->tccps[compno].roishift; + for (k = 0; k < cblk->z1 - cblk->z0; k++) { + for (j = 0; j < cblk->y1 - cblk->y0; j++) { + for (i = 0; i < cblk->x1 - cblk->x0; i++) { + val = t1->data[k][j][i]; + mag = int_abs(val); + if (mag >= thresh) { + mag >>= tcp->tccps[compno].roishift; + t1->data[k][j][i] = val < 0 ? -mag : mag; + } + } + } + } + } + + if (tcp->tccps[compno].reversible == 1) { + for (k = 0; k < cblk->z1 - cblk->z0; k++) { + for (j = 0; j < cblk->y1 - cblk->y0; j++) { + for (i = 0; i < cblk->x1 - cblk->x0; i++) { + int tmp = t1->data[k][j][i]; + tilec->data[x + i + (y + j) * (tilec->x1 - tilec->x0) + (z + k) * (tilec->x1 - tilec->x0) * (tilec->y1 - tilec->y0)] = tmp/2; + } + } + } + } else { /* if (tcp->tccps[compno].reversible == 0) */ + for (k = 0; k < cblk->z1 - cblk->z0; k++) { + for (j = 0; j < cblk->y1 - cblk->y0; j++) { + for (i = 0; i < cblk->x1 - cblk->x0; i++) { + double tmp = (double)(t1->data[k][j][i] * band->stepsize * 4096.0); + if (t1->data[k][j][i] >> 1 == 0) { + tilec->data[x + i + (y + j) * (tilec->x1 - tilec->x0) + (z + k) * (tilec->x1 - tilec->x0) * (tilec->y1 - tilec->y0)] = 0; + } else { + int tmp2 = ((int) (floor(fabs(tmp)))) + ((int) floor(fabs(tmp*2))%2); + tilec->data[x + i + (y + j) * (tilec->x1 - tilec->x0) + (z + k) * (tilec->x1 - tilec->x0) * (tilec->y1 - tilec->y0)] = ((tmp<0)?-tmp2:tmp2); + } + } + } + } + } + } /* cblkno */ + } /* precno */ + } /* bandno */ + } /* resno */ + } /* compno */ +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/t1_3d.h b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/t1_3d.h new file mode 100644 index 0000000..c1a5226 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/t1_3d.h @@ -0,0 +1,173 @@ +/* + * Copyrigth (c) 2006, Mónica Díez, LPI-UVA, Spain + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __T1_3D_H +#define __T1_3D_H +/** +@file t1_3d.h +@brief Implementation of the tier-1 coding (coding of code-block coefficients) (T1) + +The functions in T1_3D.C have for goal to realize the tier-1 coding operation of 3D-EBCOT. +The functions in T1_3D.C are used by some function in TCD.C. +*/ + +/** @defgroup T1_3D T1_3D - Implementation of the tier-1 coding */ +/*@{*/ + +/* ----------------------------------------------------------------------- */ + +/* Neighbourhood of 3D EBCOT (Significance context)*/ +#define T1_3D_SIG_NE 0x00000001 /*< Context orientation : North-East direction */ +#define T1_3D_SIG_SE 0x00000002 /*< Context orientation : South-East direction */ +#define T1_3D_SIG_SW 0x00000004 /*< Context orientation : South-West direction */ +#define T1_3D_SIG_NW 0x00000008 /* Context orientation : North-West direction */ +#define T1_3D_SIG_N 0x00000010 /*< Context orientation : North direction */ +#define T1_3D_SIG_E 0x00000020 /*< Context orientation : East direction */ +#define T1_3D_SIG_S 0x00000040 /*< Context orientation : South direction */ +#define T1_3D_SIG_W 0x00000080 /*< Context orientation : West direction */ +#define T1_3D_SIG_FC 0x00000100 /*< Context orientation : Forward Central direction */ +#define T1_3D_SIG_BC 0x00000200 /*< Context orientation : Backward Central direction */ +#define T1_3D_SIG_FNE 0x00000400 /*< Context orientation : Forward North-East direction */ +#define T1_3D_SIG_FSE 0x00000800 /*< Context orientation : Forward South-East direction */ +#define T1_3D_SIG_FSW 0x00001000 /*< Context orientation : Forward South-West direction */ +#define T1_3D_SIG_FNW 0x00002000 /*< Context orientation : Forward North-West direction */ +#define T1_3D_SIG_FN 0x00004000 /*< Context orientation : Forward North direction */ +#define T1_3D_SIG_FE 0x00008000 /*< Context orientation : Forward East direction */ +#define T1_3D_SIG_FS 0x00010000 /*< Context orientation : Forward South direction */ +#define T1_3D_SIG_FW 0x00020000 /*< Context orientation : Forward West direction */ +#define T1_3D_SIG_BNE 0x00040000 /*< Context orientation : Backward North-East direction */ +#define T1_3D_SIG_BSE 0x00080000 /*< Context orientation : Backward South-East direction */ +#define T1_3D_SIG_BSW 0x00100000 /*< Context orientation : Backward South-West direction */ +#define T1_3D_SIG_BNW 0x00200000 /*< Context orientation : Backward North-West direction */ +#define T1_3D_SIG_BN 0x00400000 /*< Context orientation : Backward North direction */ +#define T1_3D_SIG_BE 0x00800000 /*< Context orientation : Backward East direction */ +#define T1_3D_SIG_BS 0x01000000 /*< Context orientation : Backward South direction */ +#define T1_3D_SIG_BW 0x02000000 /*< Context orientation : Backward West direction */ +#define T1_3D_SIG_COTH (T1_3D_SIG_N|T1_3D_SIG_NE|T1_3D_SIG_E|T1_3D_SIG_SE|T1_3D_SIG_S|T1_3D_SIG_SW|T1_3D_SIG_W|T1_3D_SIG_NW) +#define T1_3D_SIG_BOTH (T1_3D_SIG_BN|T1_3D_SIG_BNE|T1_3D_SIG_BE|T1_3D_SIG_BSE|T1_3D_SIG_BS|T1_3D_SIG_BSW|T1_3D_SIG_BW|T1_3D_SIG_BNW|T1_3D_SIG_BC) +#define T1_3D_SIG_FOTH (T1_3D_SIG_FN|T1_3D_SIG_FNE|T1_3D_SIG_FE|T1_3D_SIG_FSE|T1_3D_SIG_FS|T1_3D_SIG_FSW|T1_3D_SIG_FW|T1_3D_SIG_FNW|T1_3D_SIG_FC) +#define T1_3D_SIG_OTH (T1_3D_SIG_FOTH|T1_3D_SIG_BOTH|T1_3D_SIG_COTH) +#define T1_3D_SIG_PRIM (T1_3D_SIG_N|T1_3D_SIG_E|T1_3D_SIG_S|T1_3D_SIG_W|T1_3D_SIG_FC|T1_3D_SIG_BC) + +#define T1_3D_SGN_N 0x0400 +#define T1_3D_SGN_E 0x0800 +#define T1_3D_SGN_S 0x1000 +#define T1_3D_SGN_W 0x2000 +#define T1_3D_SGN_F 0x4000 +#define T1_3D_SGN_B 0x8000 +#define T1_3D_SGN (T1_3D_SGN_N|T1_3D_SGN_E|T1_3D_SGN_S|T1_3D_SGN_W|T1_3D_SGN_F|T1_3D_SGN_B) + +#define T1_3D_SIG 0x0001 //Significance state +#define T1_3D_REFINE 0x0002 //Delayed significance +#define T1_3D_VISIT 0x0004 //First-pass membership + +#define T1_3D_NUMCTXS_AGG 1 +#define T1_3D_NUMCTXS_ZC 16 +#define T1_3D_NUMCTXS_MAG 3 +#define T1_3D_NUMCTXS_SC 6 +#define T1_3D_NUMCTXS_UNI 1 + +#define T1_3D_CTXNO_AGG 0 +#define T1_3D_CTXNO_ZC (T1_3D_CTXNO_AGG+T1_3D_NUMCTXS_AGG) //1 +#define T1_3D_CTXNO_MAG (T1_3D_CTXNO_ZC+T1_3D_NUMCTXS_ZC) //17 +#define T1_3D_CTXNO_SC (T1_3D_CTXNO_MAG+T1_3D_NUMCTXS_MAG) //20 +#define T1_3D_CTXNO_UNI (T1_3D_CTXNO_SC+T1_3D_NUMCTXS_SC) //26 +#define T1_3D_NUMCTXS (T1_3D_CTXNO_UNI+T1_3D_NUMCTXS_UNI) //27 + + +/* ----------------------------------------------------------------------- */ + +/** +Tier-1 coding (coding of code-block coefficients) +*/ +typedef struct opj_t1_3d { + /** Codec context */ + opj_common_ptr cinfo; + /** MQC component */ + opj_mqc_t *mqc; + /** RAW component */ + opj_raw_t *raw; + /** LUTs for decoding normalised MSE */ + int lut_nmsedec_sig[1 << T1_NMSEDEC_BITS]; + int lut_nmsedec_sig0[1 << T1_NMSEDEC_BITS]; + int lut_nmsedec_ref[1 << T1_NMSEDEC_BITS]; + int lut_nmsedec_ref0[1 << T1_NMSEDEC_BITS]; + /** Codeblock data */ + int data[T1_CBLKD][T1_CBLKH][T1_CBLKW]; + /** Context information for each voxel in codeblock */ + unsigned int flags[T1_CBLKD + 2][T1_CBLKH + 2][T1_CBLKH + 2]; + /** Voxel information (significance/visited/refined) */ + int flagSVR[T1_CBLKD + 2][T1_CBLKH + 2][T1_CBLKH + 2]; +} opj_t1_3d_t; + +/** @name Exported functions */ +/*@{*/ +/* ----------------------------------------------------------------------- */ +/** +Create a new T1_3D handle +and initialize the look-up tables of the Tier-1 coder/decoder +@return Returns a new T1 handle if successful, returns NULL otherwise +@see t1_init_luts +*/ +opj_t1_3d_t* t1_3d_create(opj_common_ptr cinfo); +/** +Destroy a previously created T1_3D handle +@param t1 T1_3D handle to destroy +*/ +void t1_3d_destroy(opj_t1_3d_t *t1); +/** +Encode the code-blocks of a tile +@param t1 T1_3D handle +@param tile The tile to encode +@param tcp Tile coding parameters +*/ +void t1_3d_encode_cblks(opj_t1_3d_t *t1, opj_tcd_tile_t *tile, opj_tcp_t *tcp); +/** +Decode the code-blocks of a tile +@param t1 T1_3D handle +@param tile The tile to decode +@param tcp Tile coding parameters +*/ +void t1_3d_decode_cblks(opj_t1_3d_t *t1, opj_tcd_tile_t *tile, opj_tcp_t *tcp); +/** +Get weigths of MSE decoding +@param nmsedec The normalized MSE reduction +@param compno +@param level +@param orient +@param bpno +@param reversible +@param stepsize +@param numcomps +@param dwtid +returns MSE associated to decoding pass +double t1_3d_getwmsedec(int nmsedec, int compno, int levelxy, int levelz, int orient, int bpno, int reversible, double stepsize, int numcomps, int dwtid); +*/ +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __T1_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/t2.c b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/t2.c new file mode 100644 index 0000000..cd40ba2 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/t2.c @@ -0,0 +1,675 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "opj_includes.h" + +/** @defgroup T2 T2 - Implementation of a tier-2 coding */ +/*@{*/ + +/** @name Local static functions */ +/*@{*/ + +static void t2_putcommacode(opj_bio_t *bio, int n); +static int t2_getcommacode(opj_bio_t *bio); +/** +Variable length code for signalling delta Zil (truncation point) +@param bio Bit Input/Output component +@param n delta Zil +*/ +static void t2_putnumpasses(opj_bio_t *bio, int n); +static int t2_getnumpasses(opj_bio_t *bio); +/** +Encode a packet of a tile to a destination buffer +@param tile Tile for which to write the packets +@param tcp Tile coding parameters +@param pi Packet identity +@param dest Destination buffer +@param len Length of the destination buffer +@param volume_info Structure to create an index file +@param tileno Number of the tile encoded +@param cp Coding parameters +@return Number of bytes encoded from the packet +*/ +static int t2_encode_packet(opj_tcd_tile_t *tile, opj_tcp_t *tcp, opj_pi_iterator_t *pi, unsigned char *dest, int len, opj_volume_info_t *volume_info, int tileno, opj_cp_t *cp); +/** +Initialize the segment decoder +@param seg Segment instance +@param cblksty Codeblock style +@param first Is first segment +*/ +static void t2_init_seg(opj_tcd_seg_t *seg, int cblksty, int first); +/** +Decode a packet of a tile from a source buffer +@param t2 T2 handle +@param src Source buffer +@param len Length of the source buffer +@param tile Tile for which to write the packets +@param tcp Tile coding parameters +@param pi Packet identity +@return Number of bytes decoded from the packet +*/ +int t2_decode_packet(opj_t2_t* t2, unsigned char *src, int len, opj_tcd_tile_t *tile, opj_tcp_t *tcp, opj_pi_iterator_t *pi); + +/*@}*/ + +/*@}*/ + +/* ----------------------------------------------------------------------- */ + +/* #define RESTART 0x04 */ +static void t2_putcommacode(opj_bio_t *bio, int n) { + while (--n >= 0) { + bio_write(bio, 1, 1); + } + bio_write(bio, 0, 1); +} + +static int t2_getcommacode(opj_bio_t *bio) { + int n; + for (n = 0; bio_read(bio, 1); n++) { + ; + } + return n; +} + +static void t2_putnumpasses(opj_bio_t *bio, int n) { + if (n == 1) { + bio_write(bio, 0, 1); + } else if (n == 2) { + bio_write(bio, 2, 2); + } else if (n <= 5) { + bio_write(bio, 0xc | (n - 3), 4); + } else if (n <= 36) { + bio_write(bio, 0x1e0 | (n - 6), 9); + } else if (n <= 164) { + bio_write(bio, 0xff80 | (n - 37), 16); + } +} + +static int t2_getnumpasses(opj_bio_t *bio) { + int n; + if (!bio_read(bio, 1)) + return 1; + if (!bio_read(bio, 1)) + return 2; + if ((n = bio_read(bio, 2)) != 3) + return (3 + n); + if ((n = bio_read(bio, 5)) != 31) + return (6 + n); + return (37 + bio_read(bio, 7)); +} + +static int t2_encode_packet(opj_tcd_tile_t * tile, opj_tcp_t * tcp, opj_pi_iterator_t *pi, unsigned char *dest, int len, opj_volume_info_t * volume_info, int tileno, opj_cp_t *cp) { + int bandno, cblkno; + unsigned char *sop = 0, *eph = 0; + unsigned char *c = dest; + + int compno = pi->compno; /* component value */ + int resno = pi->resno; /* resolution level value */ + int precno = pi->precno; /* precinct value */ + int layno = pi->layno; /* quality layer value */ + + opj_tcd_tilecomp_t *tilec = &tile->comps[compno]; + opj_tcd_resolution_t *res = &tilec->resolutions[resno]; + + opj_bio_t *bio = NULL; /* BIO component */ + + /* */ + if ((tcp->csty & J3D_CP_CSTY_SOP)) { + sop = (unsigned char *) opj_malloc(6 * sizeof(unsigned char)); + sop[0] = 255; + sop[1] = 145; + sop[2] = 0; + sop[3] = 4; + sop[4] = (volume_info) ? (volume_info->num % 65536) / 256 : (0 % 65536) / 256 ; + sop[5] = (volume_info) ? (volume_info->num % 65536) % 256 : (0 % 65536) % 256 ; + memcpy(c, sop, 6); + opj_free(sop); + c += 6; + } + /* */ + + if (!layno) { + for (bandno = 0; bandno < res->numbands; bandno++) { + opj_tcd_band_t *band = &res->bands[bandno]; + opj_tcd_precinct_t *prc = &band->precincts[precno]; + tgt_reset(prc->incltree); + tgt_reset(prc->imsbtree); + for (cblkno = 0; cblkno < prc->cblkno[0] * prc->cblkno[1] * prc->cblkno[2]; cblkno++) { + opj_tcd_cblk_t *cblk = &prc->cblks[cblkno]; + cblk->numpasses = 0; + tgt_setvalue(prc->imsbtree, cblkno, band->numbps - cblk->numbps); + } + } + } + + bio = bio_create(); + bio_init_enc(bio, c, len); + bio_write(bio, 1, 1); /* Empty header bit */ + + /* Writing Packet header */ + for (bandno = 0; bandno < res->numbands; bandno++) { + opj_tcd_band_t *band = &res->bands[bandno]; + opj_tcd_precinct_t *prc = &band->precincts[precno]; + for (cblkno = 0; cblkno < prc->cblkno[0] * prc->cblkno[1] * prc->cblkno[2]; cblkno++) { + opj_tcd_cblk_t *cblk = &prc->cblks[cblkno]; + opj_tcd_layer_t *layer = &cblk->layers[layno]; + if (!cblk->numpasses && layer->numpasses) { + tgt_setvalue(prc->incltree, cblkno, layno); + } + } + + for (cblkno = 0; cblkno < prc->cblkno[0] * prc->cblkno[1] * prc->cblkno[2]; cblkno++) { + opj_tcd_cblk_t *cblk = &prc->cblks[cblkno]; + opj_tcd_layer_t *layer = &cblk->layers[layno]; + int increment = 0; + int nump = 0; + int len = 0, passno; + /* cblk inclusion bits */ + if (!cblk->numpasses) { + tgt_encode(bio, prc->incltree, cblkno, layno + 1); + } else { + bio_write(bio, layer->numpasses != 0, 1); + } + /* if cblk not included, go to the next cblk */ + if (!layer->numpasses) { + continue; + } + /* if first instance of cblk --> zero bit-planes information */ + if (!cblk->numpasses) { + cblk->numlenbits = 3; + tgt_encode(bio, prc->imsbtree, cblkno, 999); + } + /* number of coding passes included */ + t2_putnumpasses(bio, layer->numpasses); + + /* computation of the increase of the length indicator and insertion in the header */ + for (passno = cblk->numpasses; passno < cblk->numpasses + layer->numpasses; passno++) { + opj_tcd_pass_t *pass = &cblk->passes[passno]; + nump++; + len += pass->len; + if (pass->term || passno == (cblk->numpasses + layer->numpasses) - 1) { + increment = int_max(increment, int_floorlog2(len) + 1 - (cblk->numlenbits + int_floorlog2(nump))); + len = 0; + nump = 0; + } + } + t2_putcommacode(bio, increment); + + /* computation of the new Length indicator */ + cblk->numlenbits += increment; + + /* insertion of the codeword segment length */ + for (passno = cblk->numpasses; passno < cblk->numpasses + layer->numpasses; passno++) { + opj_tcd_pass_t *pass = &cblk->passes[passno]; + nump++; + len += pass->len; + if (pass->term || passno == (cblk->numpasses + layer->numpasses) - 1) { + bio_write(bio, len, cblk->numlenbits + int_floorlog2(nump)); + len = 0; + nump = 0; + } + } + + } + } + + + if (bio_flush(bio)) { + return -999; /* modified to eliminate longjmp !! */ + } + + c += bio_numbytes(bio); + + bio_destroy(bio); + + /* */ + if (tcp->csty & J3D_CP_CSTY_EPH) { + eph = (unsigned char *) opj_malloc(2 * sizeof(unsigned char)); + eph[0] = 255; + eph[1] = 146; + memcpy(c, eph, 2); + opj_free(eph); + c += 2; + } + /* */ + + /* Writing the packet body */ + + for (bandno = 0; bandno < res->numbands; bandno++) { + opj_tcd_band_t *band = &res->bands[bandno]; + opj_tcd_precinct_t *prc = &band->precincts[precno]; + for (cblkno = 0; cblkno < prc->cblkno[0] * prc->cblkno[1] * prc->cblkno[2]; cblkno++) { + opj_tcd_cblk_t *cblk = &prc->cblks[cblkno]; + opj_tcd_layer_t *layer = &cblk->layers[layno]; + if (!layer->numpasses) { + continue; + } + if (c + layer->len > dest + len) { + return -999; + } + + memcpy(c, layer->data, layer->len); + cblk->numpasses += layer->numpasses; + c += layer->len; + /* ADD for index Cfr. Marcela --> delta disto by packet */ + if(volume_info && volume_info->index_write && volume_info->index_on) { + opj_tile_info_t *info_TL = &volume_info->tile[tileno]; + opj_packet_info_t *info_PK = &info_TL->packet[volume_info->num]; + info_PK->disto += layer->disto; + if (volume_info->D_max < info_PK->disto) { + volume_info->D_max = info_PK->disto; + } + } + /* */ + } + } + + return (c - dest); +} + +static void t2_init_seg(opj_tcd_seg_t * seg, int cblksty, int first) { + seg->numpasses = 0; + seg->len = 0; + if (cblksty & J3D_CCP_CBLKSTY_TERMALL) { + seg->maxpasses = 1; + } + else if (cblksty & J3D_CCP_CBLKSTY_LAZY) { + if (first) { + seg->maxpasses = 10; + } else { + seg->maxpasses = (((seg - 1)->maxpasses == 1) || ((seg - 1)->maxpasses == 10)) ? 2 : 1; + } + } else { + seg->maxpasses = 109; + } +} + +int t2_decode_packet(opj_t2_t* t2, unsigned char *src, int len, opj_tcd_tile_t *tile, opj_tcp_t *tcp, opj_pi_iterator_t *pi) { + int bandno, cblkno; + unsigned char *c = src; + + opj_cp_t *cp = t2->cp; + + int compno = pi->compno; /* component value */ + int resno = pi->resno; /* resolution level value */ + int precno = pi->precno; /* precinct value */ + int layno = pi->layno; /* quality layer value */ + + opj_tcd_tilecomp_t *tilec = &tile->comps[compno]; + opj_tcd_resolution_t *res = &tilec->resolutions[resno]; + + unsigned char *hd = NULL; + int present; + + opj_bio_t *bio = NULL; /* BIO component */ + + if (layno == 0) { + for (bandno = 0; bandno < res->numbands; bandno++) { + opj_tcd_band_t *band = &res->bands[bandno]; + opj_tcd_precinct_t *prc = &band->precincts[precno]; + + if ((band->x1-band->x0 == 0)||(band->y1-band->y0 == 0)||(band->z1-band->z0 == 0)) continue; + + tgt_reset(prc->incltree); + tgt_reset(prc->imsbtree); + for (cblkno = 0; cblkno < prc->cblkno[0] * prc->cblkno[1] * prc->cblkno[2]; cblkno++) { + opj_tcd_cblk_t *cblk = &prc->cblks[cblkno]; + cblk->numsegs = 0; + } + } + } + + /* SOP markers */ + + if (tcp->csty & J3D_CP_CSTY_SOP) { + if ((*c) != 0xff || (*(c + 1) != 0x91)) { + opj_event_msg(t2->cinfo, EVT_WARNING, "Expected SOP marker\n"); + } else { + c += 6; + } + + /** TODO : check the Nsop value */ + } + + /* + When the marker PPT/PPM is used the packet header are store in PPT/PPM marker + This part deal with this caracteristic + step 1: Read packet header in the saved structure + step 2: Return to codestream for decoding + */ + + bio = bio_create(); + + if (cp->ppm == 1) { /* PPM */ + hd = cp->ppm_data; + bio_init_dec(bio, hd, cp->ppm_len); + } else if (tcp->ppt == 1) { /* PPT */ + hd = tcp->ppt_data; + bio_init_dec(bio, hd, tcp->ppt_len); + } else { /* Normal Case */ + hd = c; + bio_init_dec(bio, hd, src+len-hd); + } + + present = bio_read(bio, 1); + + if (!present) { + bio_inalign(bio); + hd += bio_numbytes(bio); + bio_destroy(bio); + + /* EPH markers */ + + if (tcp->csty & J3D_CP_CSTY_EPH) { + if ((*hd) != 0xff || (*(hd + 1) != 0x92)) { + printf("Error : expected EPH marker\n"); + } else { + hd += 2; + } + } + + if (cp->ppm == 1) { /* PPM case */ + cp->ppm_len += cp->ppm_data-hd; + cp->ppm_data = hd; + return (c - src); + } + if (tcp->ppt == 1) { /* PPT case */ + tcp->ppt_len+=tcp->ppt_data-hd; + tcp->ppt_data = hd; + return (c - src); + } + + return (hd - src); + } + + for (bandno = 0; bandno < res->numbands; bandno++) { + opj_tcd_band_t *band = &res->bands[bandno]; + opj_tcd_precinct_t *prc = &band->precincts[precno]; + + if ((band->x1-band->x0 == 0)||(band->y1-band->y0 == 0)||(band->z1-band->z0 == 0)) continue; + + for (cblkno = 0; cblkno < prc->cblkno[0] * prc->cblkno[1] * prc->cblkno[2]; cblkno++) { + int included, increment, n; + opj_tcd_cblk_t *cblk = &prc->cblks[cblkno]; + opj_tcd_seg_t *seg = NULL; + /* if cblk not yet included before --> inclusion tagtree */ + if (!cblk->numsegs) { + included = tgt_decode(bio, prc->incltree, cblkno, layno + 1); + /* else one bit */ + } else { + included = bio_read(bio, 1); + } + /* if cblk not included */ + if (!included) { + cblk->numnewpasses = 0; + continue; + } + /* if cblk not yet included --> zero-bitplane tagtree */ + if (!cblk->numsegs) { + int i, numimsbs; + for (i = 0; !tgt_decode(bio, prc->imsbtree, cblkno, i); i++); + numimsbs = i - 1; + cblk->numbps = band->numbps - numimsbs; + cblk->numlenbits = 3; + } + /* number of coding passes */ + cblk->numnewpasses = t2_getnumpasses(bio); + increment = t2_getcommacode(bio); + /* length indicator increment */ + cblk->numlenbits += increment; + if (!cblk->numsegs) { + seg = &cblk->segs[0]; + t2_init_seg(seg, tcp->tccps[compno].cblksty, 1); + } else { + seg = &cblk->segs[cblk->numsegs - 1]; + if (seg->numpasses == seg->maxpasses) { + t2_init_seg(++seg, tcp->tccps[compno].cblksty, 0); + } + } + n = cblk->numnewpasses; + + do { + seg->numnewpasses = int_min(seg->maxpasses - seg->numpasses, n); + seg->newlen = bio_read(bio, cblk->numlenbits + int_floorlog2(seg->numnewpasses)); + n -= seg->numnewpasses; + if (n > 0) { + t2_init_seg(++seg, tcp->tccps[compno].cblksty, 0); + } + } while (n > 0); + } + } + + if (bio_inalign(bio)) { + bio_destroy(bio); + return -999; + } + + hd += bio_numbytes(bio); + bio_destroy(bio); + + /* EPH markers */ + if (tcp->csty & J3D_CP_CSTY_EPH) { + if ((*hd) != 0xff || (*(hd + 1) != 0x92)) { + opj_event_msg(t2->cinfo, EVT_ERROR, "Expected EPH marker\n"); + } else { + hd += 2; + } + } + + if (cp->ppm==1) { + cp->ppm_len+=cp->ppm_data-hd; + cp->ppm_data = hd; + } else if (tcp->ppt == 1) { + tcp->ppt_len+=tcp->ppt_data-hd; + tcp->ppt_data = hd; + } else { + c=hd; + } + + for (bandno = 0; bandno < res->numbands; bandno++) { + opj_tcd_band_t *band = &res->bands[bandno]; + opj_tcd_precinct_t *prc = &band->precincts[precno]; + + if ((band->x1-band->x0 == 0)||(band->y1-band->y0 == 0)||(band->z1-band->z0 == 0)) continue; + + for (cblkno = 0; cblkno < prc->cblkno[0] * prc->cblkno[1] * prc->cblkno[2]; cblkno++) { + opj_tcd_cblk_t *cblk = &prc->cblks[cblkno]; + opj_tcd_seg_t *seg = NULL; + if (!cblk->numnewpasses) + continue; + if (!cblk->numsegs) { + seg = &cblk->segs[0]; + cblk->numsegs++; + cblk->len = 0; + } else { + seg = &cblk->segs[cblk->numsegs - 1]; + if (seg->numpasses == seg->maxpasses) { + seg++; + cblk->numsegs++; + } + } + + do { + if (c + seg->newlen > src + len) { + return -999; + } + + memcpy(cblk->data + cblk->len, c, seg->newlen); + if (seg->numpasses == 0) { + seg->data = cblk->data + cblk->len; + } + c += seg->newlen; + cblk->len += seg->newlen; + seg->len += seg->newlen; + seg->numpasses += seg->numnewpasses; + cblk->numnewpasses -= seg->numnewpasses; + if (cblk->numnewpasses > 0) { + seg++; + cblk->numsegs++; + } + } while (cblk->numnewpasses > 0); + } + } + + return (c - src); +} + +/* ----------------------------------------------------------------------- */ + +int t2_encode_packets(opj_t2_t* t2, int tileno, opj_tcd_tile_t *tile, int maxlayers, unsigned char *dest, int len, opj_volume_info_t *volume_info) { + unsigned char *c = dest; + int e = 0; + opj_pi_iterator_t *pi = NULL; + int pino; + + opj_volume_t *volume = t2->volume; + opj_cp_t *cp = t2->cp; + + /* create a packet iterator */ + pi = pi_create(volume, cp, tileno); + if(!pi) { + fprintf(stdout,"[ERROR] Failed to create a pi structure\n"); + return -999; + } + + if(volume_info) { + volume_info->num = 0; + } + + for (pino = 0; pino <= cp->tcps[tileno].numpocs; pino++) { + while (pi_next(&pi[pino])) { + if (pi[pino].layno < maxlayers) { + e = t2_encode_packet(tile, &cp->tcps[tileno], &pi[pino], c, dest + len - c, volume_info, tileno, cp); + //opj_event_msg(t2->cinfo, EVT_INFO, " t2_encode_packet: %d bytes coded\n",e); + if (e == -999) { + break; + } else { + c += e; + } + + /* INDEX >> */ + if(volume_info && volume_info->index_on) { + if(volume_info->index_write) { + opj_tile_info_t *info_TL = &volume_info->tile[tileno]; + opj_packet_info_t *info_PK = &info_TL->packet[volume_info->num]; + if (!volume_info->num) { + info_PK->start_pos = info_TL->end_header + 1; + } else { + info_PK->start_pos = info_TL->packet[volume_info->num - 1].end_pos + 1; + } + info_PK->end_pos = info_PK->start_pos + e - 1; + } + + volume_info->num++; + } + /* << INDEX */ + } + } + } + + /* don't forget to release pi */ + pi_destroy(pi, cp, tileno); + + if (e == -999) { + return e; + } + + return (c - dest); +} + +int t2_decode_packets(opj_t2_t *t2, unsigned char *src, int len, int tileno, opj_tcd_tile_t *tile) { + unsigned char *c = src; + opj_pi_iterator_t *pi; + int pino, e = 0; + int n = 0,i; + + opj_volume_t *volume = t2->volume; + opj_cp_t *cp = t2->cp; + + /* create a packet iterator */ + pi = pi_create(volume, cp, tileno); + if(!pi) { + /* TODO: throw an error */ + return -999; + } + + for (pino = 0; pino <= cp->tcps[tileno].numpocs; pino++) { + while (pi_next(&pi[pino])) { + if ((cp->layer==0) || (cp->layer>=((pi[pino].layno)+1))) { + e = t2_decode_packet(t2, c, src + len - c, tile, &cp->tcps[tileno], &pi[pino]); + } else { + e = 0; + } + + /* progression in resolution */ + for (i = 0; i < 3; i++){ + volume->comps[pi[pino].compno].resno_decoded[i] = (e > 0) ? int_max(pi[pino].resno, volume->comps[pi[pino].compno].resno_decoded[i]) : volume->comps[pi[pino].compno].resno_decoded[i]; + } + n++; + + if (e == -999) { /* ADD */ + break; + } else { + opj_event_msg(t2->cinfo, EVT_INFO, " t2_decode_packet: %d bytes decoded\n",e); + c += e; + } + } + } + + /* don't forget to release pi */ + pi_destroy(pi, cp, tileno); + + if (e == -999) { + return e; + } + + return (c - src); +} + +/* ----------------------------------------------------------------------- */ + +opj_t2_t* t2_create(opj_common_ptr cinfo, opj_volume_t *volume, opj_cp_t *cp) { + /* create the tcd structure */ + opj_t2_t *t2 = (opj_t2_t*)opj_malloc(sizeof(opj_t2_t)); + if(!t2) return NULL; + t2->cinfo = cinfo; + t2->volume = volume; + t2->cp = cp; + + return t2; +} + +void t2_destroy(opj_t2_t *t2) { + if(t2) { + opj_free(t2); + } +} + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/t2.h b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/t2.h new file mode 100644 index 0000000..066e6b7 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/t2.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * Copyright (c) 2006, Mónica Díez García, Image Processing Laboratory, University of Valladolid, Spain + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __T2_H +#define __T2_H +/** +@file t2.h +@brief Implementation of a tier-2 coding (packetization of code-block data) (T2) + +*/ + +/** @defgroup T2 T2 - Implementation of a tier-2 coding */ +/*@{*/ + +/** +Tier-2 coding +*/ +typedef struct opj_t2 { +/** Codec context */ + opj_common_ptr cinfo; +/** Encoding: pointer to the src volume. Decoding: pointer to the dst volume. */ + opj_volume_t *volume; +/** Pointer to the volume coding parameters */ + opj_cp_t *cp; +} opj_t2_t; + +/** @name Funciones generales */ +/*@{*/ +/* ----------------------------------------------------------------------- */ + +/** +Encode the packets of a tile to a destination buffer +@param t2 T2 handle +@param tileno number of the tile encoded +@param tile the tile for which to write the packets +@param maxlayers maximum number of layers +@param dest the destination buffer +@param len the length of the destination buffer +@param volume_info structure to create an index file +@return Number of bytes written from packets +*/ +int t2_encode_packets(opj_t2_t* t2, int tileno, opj_tcd_tile_t *tile, int maxlayers, unsigned char *dest, int len, opj_volume_info_t *volume_info); + +/** +Decode the packets of a tile from a source buffer +@param t2 T2 handle +@param src the source buffer +@param len length of the source buffer +@param tileno number that identifies the tile for which to decode the packets +@param tile tile for which to decode the packets +@return Number of bytes read from packets + */ +int t2_decode_packets(opj_t2_t *t2, unsigned char *src, int len, int tileno, opj_tcd_tile_t *tile); + +/** +Create a T2 handle +@param cinfo Codec context info +@param volume Source or destination volume +@param cp Volume coding parameters +@return Returns a new T2 handle if successful, returns NULL otherwise +*/ +opj_t2_t* t2_create(opj_common_ptr cinfo, opj_volume_t *volume, opj_cp_t *cp); +/** +Destroy a T2 handle +@param t2 T2 handle to destroy +*/ +void t2_destroy(opj_t2_t *t2); + +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __T2_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/tcd.c b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/tcd.c new file mode 100644 index 0000000..f015ef0 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/tcd.c @@ -0,0 +1,1738 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * Copyright (c) 2006, Mónica Díez, LPI-UVA, Spain + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "opj_includes.h" + +void tcd_dump(FILE *fd, opj_tcd_t *tcd, opj_tcd_volume_t * vol) { + int tileno, compno, resno, bandno, precno, cblkno; + + fprintf(fd, "volume {\n"); + fprintf(fd, " tw=%d, th=%d, tl=%d, x0=%d x1=%d y0=%d y1=%d z0=%d z1=%d\n", + vol->tw, vol->th, vol->tl, tcd->volume->x0, tcd->volume->x1, tcd->volume->y0, tcd->volume->y1, tcd->volume->z0, tcd->volume->z1); + + for (tileno = 0; tileno < vol->th * vol->tw * vol->tl; tileno++) { + opj_tcd_tile_t *tile = &tcd->tcd_volume->tiles[tileno]; + fprintf(fd, " tile {\n"); + fprintf(fd, " x0=%d, y0=%d, z0=%d, x1=%d, y1=%d, z1=%d, numcomps=%d\n", + tile->x0, tile->y0, tile->z0, tile->x1, tile->y1, tile->z1, tile->numcomps); + for (compno = 0; compno < tile->numcomps; compno++) { + opj_tcd_tilecomp_t *tilec = &tile->comps[compno]; + fprintf(fd, " tilecomp %d {\n",compno); + fprintf(fd, " x0=%d, y0=%d, z0=%d, x1=%d, y1=%d, z1=%d, numresx=%d, numresy=%d, numresz=%d\n", + tilec->x0, tilec->y0, tilec->z0, tilec->x1, tilec->y1, tilec->z1, tilec->numresolution[0], tilec->numresolution[1], tilec->numresolution[2]); + for (resno = 0; resno < tilec->numresolution[0]; resno++) { + opj_tcd_resolution_t *res = &tilec->resolutions[resno]; + fprintf(fd, " res %d{\n",resno); + fprintf(fd," x0=%d, y0=%d, z0=%d, x1=%d, y1=%d, z1=%d, pw=%d, ph=%d, pl=%d, numbands=%d\n", + res->x0, res->y0, res->z0, res->x1, res->y1, res->z1, res->prctno[0], res->prctno[1], res->prctno[2], res->numbands); + for (bandno = 0; bandno < res->numbands; bandno++) { + opj_tcd_band_t *band = &res->bands[bandno]; + fprintf(fd, " band %d{\n", bandno); + fprintf(fd, " x0=%d, y0=%d, z0=%d, x1=%d, y1=%d, z1=%d, stepsize=%f, numbps=%d\n", + band->x0, band->y0, band->z0, band->x1, band->y1, band->z1, band->stepsize, band->numbps); + for (precno = 0; precno < (res->prctno[0] * res->prctno[1] * res->prctno[2]); precno++) { + opj_tcd_precinct_t *prec = &band->precincts[precno]; + fprintf(fd, " prec %d{\n",precno); + fprintf(fd, " x0=%d, y0=%d, z0=%d, x1=%d, y1=%d, z1=%d, cw=%d, ch=%d, cl=%d,\n", + prec->x0, prec->y0, prec->z0, prec->x1, prec->y1, prec->z1, prec->cblkno[0], prec->cblkno[1], prec->cblkno[2]); + for (cblkno = 0; cblkno < (prec->cblkno[0] * prec->cblkno[1] * prec->cblkno[2]); cblkno++) { + opj_tcd_cblk_t *cblk = &prec->cblks[cblkno]; + fprintf(fd, " cblk %d{\n",cblkno); + fprintf(fd, " x0=%d, y0=%d, z0=%d, x1=%d, y1=%d, z1=%d\n", cblk->x0, cblk->y0, cblk->z0, cblk->x1, cblk->y1, cblk->z1); + fprintf(fd, " }\n"); + } + fprintf(fd, " }\n"); + } + fprintf(fd, " }\n"); + } + fprintf(fd, " }\n"); + } + fprintf(fd, " }\n"); + } + fprintf(fd, " }\n"); + } + fprintf(fd, "}\n"); +} + +void tilec_dump(FILE *fd, opj_tcd_tilecomp_t *tilec) { + + int i=0,k; + int datalen; + int *a; + + fprintf(fd, " tilecomp{\n"); + fprintf(fd, " x0=%d, y0=%d, z0=%d, x1=%d, y1=%d, z1=%d, numresx=%d, numresy=%d, numresz=%d\n", + tilec->x0, tilec->y0, tilec->z0, tilec->x1, tilec->y1, tilec->z1, tilec->numresolution[0], tilec->numresolution[1], tilec->numresolution[2]); + fprintf(fd, " data {\n"); + datalen = (tilec->z1 - tilec->z0) * (tilec->y1 - tilec->y0) * (tilec->x1 - tilec->x0); + a = tilec->data; + for (k = 0; k < datalen; k++) { + if (!(k % tilec->x1)){ + fprintf(fd, "\n"); + } + if (!(k % (tilec->y1 * tilec->x1))){ + fprintf(fd, "Slice %d\n",i++); + } + fprintf(fd," %d",a[k]); + + + } + fprintf(fd, " }\n"); + /*i=0; + fprintf(fd, "Slice %d\n"); + if (tilec->prediction->prederr) { + fprintf(fd, " prederror {\n"); + a = tilec->prediction->prederr; + for (k = 0; k < datalen; k++) { + fprintf(fd," %d",*(a++)); + if (!(k % (tilec->y1 - tilec->y0) * (tilec->x1 - tilec->x0))){ + fprintf(fd, "\n");fprintf(fd, "Slice %d\n",i++); + } + if (!(k % (tilec->x1 - tilec->x0))){ + fprintf(fd, "\n"); + } + } + } + fprintf(fd, " }\n");*/ + fprintf(fd, "}\n"); +} + +/* ----------------------------------------------------------------------- */ + +/** +Create a new TCD handle +*/ +opj_tcd_t* tcd_create(opj_common_ptr cinfo) { + /* create the tcd structure */ + opj_tcd_t *tcd = (opj_tcd_t*)opj_malloc(sizeof(opj_tcd_t)); + if(!tcd) return NULL; + tcd->cinfo = cinfo; + tcd->tcd_volume = (opj_tcd_volume_t*)opj_malloc(sizeof(opj_tcd_volume_t)); + if(!tcd->tcd_volume) { + opj_free(tcd); + return NULL; + } + + return tcd; +} + +/** +Destroy a previously created TCD handle +*/ +void tcd_destroy(opj_tcd_t *tcd) { + if(tcd) { + opj_free(tcd->tcd_volume); + opj_free(tcd); + } +} + +/* ----------------------------------------------------------------------- */ +void tcd_malloc_encode(opj_tcd_t *tcd, opj_volume_t * volume, opj_cp_t * cp, int curtileno) { + int compno, resno, bandno, precno, cblkno, i, j;//, k; + + opj_tcd_tile_t *tile = NULL; /* pointer to tcd->tile */ + opj_tcd_tilecomp_t *tilec = NULL; /* pointer to tcd->tilec */ + opj_tcd_resolution_t *res = NULL; /* pointer to tcd->res */ + opj_tcd_band_t *band = NULL; /* pointer to tcd->band */ + opj_tcd_precinct_t *prc = NULL; /* pointer to tcd->prc */ + opj_tcd_cblk_t *cblk = NULL; /* pointer to tcd->cblk */ + opj_tcp_t *tcp = &cp->tcps[curtileno]; + int p,q,r; + + tcd->volume = volume; + tcd->cp = cp; + tcd->tcd_volume->tw = cp->tw; + tcd->tcd_volume->th = cp->th; + tcd->tcd_volume->tl = cp->tl; + tcd->tcd_volume->tiles = (opj_tcd_tile_t *) opj_malloc(sizeof(opj_tcd_tile_t)); + tcd->tile = tcd->tcd_volume->tiles; + tile = tcd->tile; + + + /* p61 ISO/IEC IS15444-1 : 2002 */ + /* curtileno --> raster scanned index of tiles */ + /* p,q,r --> matricial index of tiles */ + p = curtileno % cp->tw; + q = curtileno / cp->tw; + r = curtileno / (cp->tw * cp->th); /* extension to 3-D */ + + /* 4 borders of the tile rescale on the volume if necessary (B.3)*/ + tile->x0 = int_max(cp->tx0 + p * cp->tdx, volume->x0); + tile->y0 = int_max(cp->ty0 + q * cp->tdy, volume->y0); + tile->z0 = int_max(cp->tz0 + r * cp->tdz, volume->z0); + tile->x1 = int_min(cp->tx0 + (p + 1) * cp->tdx, volume->x1); + tile->y1 = int_min(cp->ty0 + (q + 1) * cp->tdy, volume->y1); + tile->z1 = int_min(cp->tz0 + (r + 1) * cp->tdz, volume->z1); + tile->numcomps = volume->numcomps; + + /* Modification of the RATE >> */ + for (j = 0; j < tcp->numlayers; j++) { + if (tcp->rates[j] <= 1) { + tcp->rates[j] = 0; + } else { + float num = (float) (tile->numcomps * (tile->x1 - tile->x0) * (tile->y1 - tile->y0) * (tile->z1 - tile->z0) * volume->comps[0].prec); + float den = (float) (8 * volume->comps[0].dx * volume->comps[0].dy * volume->comps[0].dz); + den = tcp->rates[j] * den; + tcp->rates[j] = (num + den - 1) / den; + } + /*tcp->rates[j] = tcp->rates[j] ? int_ceildiv( + tile->numcomps * (tile->x1 - tile->x0) * (tile->y1 - tile->y0) * (tile->z1 - tile->z0) * volume->comps[0].prec, + (tcp->rates[j] * 8 * volume->comps[0].dx * volume->comps[0].dy * volume->comps[0].dz)) : 0;*/ + if (tcp->rates[j]) { + if (j && tcp->rates[j] < tcp->rates[j - 1] + 10) { + tcp->rates[j] = tcp->rates[j - 1] + 20; + } else if (!j && tcp->rates[j] < 30){ + tcp->rates[j] = 30; + } + } + } + /* << Modification of the RATE */ + + tile->comps = (opj_tcd_tilecomp_t *) opj_malloc(volume->numcomps * sizeof(opj_tcd_tilecomp_t)); + for (compno = 0; compno < tile->numcomps; compno++) { + opj_tccp_t *tccp = &tcp->tccps[compno]; + int res_max; + int prevnumbands = 0; + + /* opj_tcd_tilecomp_t *tilec=&tile->comps[compno]; */ + tcd->tilec = &tile->comps[compno]; + tilec = tcd->tilec; + + /* border of each tile component (global) (B.3) */ + tilec->x0 = int_ceildiv(tile->x0, volume->comps[compno].dx); + tilec->y0 = int_ceildiv(tile->y0, volume->comps[compno].dy); + tilec->z0 = int_ceildiv(tile->z0, volume->comps[compno].dz); + tilec->x1 = int_ceildiv(tile->x1, volume->comps[compno].dx); + tilec->y1 = int_ceildiv(tile->y1, volume->comps[compno].dy); + tilec->z1 = int_ceildiv(tile->z1, volume->comps[compno].dz); + + tilec->data = (int *) opj_malloc((tilec->x1 - tilec->x0) * (tilec->y1 - tilec->y0) * (tilec->z1 - tilec->z0) * sizeof(int)); + + res_max = 0; + for (i = 0;i < 3; i++){ + tilec->numresolution[i] = tccp->numresolution[i]; + //Greater of 3 resolutions contains all information + res_max = (tilec->numresolution[i] > res_max) ? tilec->numresolution[i] : res_max; + } + + + tilec->resolutions = (opj_tcd_resolution_t *) opj_malloc(res_max * sizeof(opj_tcd_resolution_t)); + for (resno = 0; resno < res_max; resno++) { + + int pdx, pdy, pdz; + int tlprcxstart, tlprcystart, tlprczstart; + int brprcxend, brprcyend, brprczend; + int tlcbgxstart, tlcbgystart, tlcbgzstart; + int brcbgxend, brcbgyend, brcbgzend; + int cbgwidthexpn, cbgheightexpn, cbglengthexpn; + int cblkwidthexpn, cblkheightexpn, cblklengthexpn; + + int diff = tccp->numresolution[0] - tccp->numresolution[2]; + int levelnox = tilec->numresolution[0] - 1 - resno; + int levelnoy = tilec->numresolution[1] - 1 - resno; + int levelnoz = tilec->numresolution[2] - 1 - ((resno <= diff) ? 0 : (resno - diff)); + if (levelnoz < 0) levelnoz = 0; + + /* opj_tcd_resolution_t *res=&tilec->resolutions[resno]; */ + tcd->res = &tilec->resolutions[resno]; + res = tcd->res; + + /* border for each resolution level (global) (B.14)*/ + res->x0 = int_ceildivpow2(tilec->x0, levelnox); + res->y0 = int_ceildivpow2(tilec->y0, levelnoy); + res->z0 = int_ceildivpow2(tilec->z0, levelnoz); + res->x1 = int_ceildivpow2(tilec->x1, levelnox); + res->y1 = int_ceildivpow2(tilec->y1, levelnoy); + res->z1 = int_ceildivpow2(tilec->z1, levelnoz); + //if (res->z1 < 0)fprintf(stdout,"Res: %d %d/%d --> %d\n",resno,tilec->z1, levelnoz, int_ceildivpow2(tilec->z1, levelnoz)); + + res->numbands = (resno == 0) ? 1 : (resno <= diff) ? 3 : 7; /* --> 3D */ + + /* p. 30, table A-13, ISO/IEC IS154444-1 : 2002 */ + if (tccp->csty & J3D_CCP_CSTY_PRT) { + pdx = tccp->prctsiz[0][resno]; + pdy = tccp->prctsiz[1][resno]; + pdz = tccp->prctsiz[2][resno]; + } else { + pdx = 15; + pdy = 15; + pdz = 15; + } + + /* p. 66, B.16, ISO/IEC IS15444-1 : 2002 */ + tlprcxstart = int_floordivpow2(res->x0, pdx) << pdx; + tlprcystart = int_floordivpow2(res->y0, pdy) << pdy; + tlprczstart = int_floordivpow2(res->z0, pdz) << pdz; + brprcxend = int_ceildivpow2(res->x1, pdx) << pdx; + brprcyend = int_ceildivpow2(res->y1, pdy) << pdy; + brprczend = int_ceildivpow2(res->z1, pdz) << pdz; + + res->prctno[0] = (brprcxend - tlprcxstart) >> pdx; + res->prctno[1] = (brprcyend - tlprcystart) >> pdy; + res->prctno[2] = (brprczend - tlprczstart) >> pdz; + if (res->prctno[2] == 0) res->prctno[2] = 1; + + /* p. 67, B.17 & B.18, ISO/IEC IS15444-1 : 2002 */ + if (resno == 0) { + tlcbgxstart = tlprcxstart; + tlcbgystart = tlprcystart; + tlcbgzstart = tlprczstart; + brcbgxend = brprcxend; + brcbgyend = brprcyend; + brcbgzend = brprczend; + cbgwidthexpn = pdx; + cbgheightexpn = pdy; + cbglengthexpn = pdz; + } else { + tlcbgxstart = int_ceildivpow2(tlprcxstart, 1); + tlcbgystart = int_ceildivpow2(tlprcystart, 1); + tlcbgzstart = int_ceildivpow2(tlprczstart, 1); + brcbgxend = int_ceildivpow2(brprcxend, 1); + brcbgyend = int_ceildivpow2(brprcyend, 1); + brcbgzend = int_ceildivpow2(brprczend, 1); + cbgwidthexpn = pdx - 1; + cbgheightexpn = pdy - 1; + cbglengthexpn = pdz - 1; + } + + cblkwidthexpn = int_min(tccp->cblk[0], cbgwidthexpn); //6 + cblkheightexpn = int_min(tccp->cblk[1], cbgheightexpn); //6 + cblklengthexpn = int_min(tccp->cblk[2], cbglengthexpn); //6 + + res->bands = (opj_tcd_band_t *) opj_malloc(res->numbands * sizeof(opj_tcd_band_t)); + for (bandno = 0; bandno < res->numbands; bandno++) { + int x0b, y0b, z0b, i; + int gain, numbps; + opj_stepsize_t *ss = NULL; + + tcd->band = &res->bands[bandno]; + band = tcd->band; + + band->bandno = (resno == 0) ? 0 : bandno + 1; + /* Bandno: 0 - LLL 2 - LHL + 1 - HLL 3 - HHL + 4 - LLH 6 - LHH + 5 - HLH 7 - HHH */ + x0b = (band->bandno == 1) || (band->bandno == 3) || (band->bandno == 5 ) || (band->bandno == 7 ) ? 1 : 0; + y0b = (band->bandno == 2) || (band->bandno == 3) || (band->bandno == 6 ) || (band->bandno == 7 ) ? 1 : 0; + z0b = (band->bandno == 4) || (band->bandno == 5) || (band->bandno == 6 ) || (band->bandno == 7 ) ? 1 : 0; + + /* p. 65, B.15, ISO/IEC IS15444-1 : 2002 */ + if (band->bandno == 0) { + /* band border (global) */ + band->x0 = int_ceildivpow2(tilec->x0, levelnox); + band->y0 = int_ceildivpow2(tilec->y0, levelnoy); + band->z0 = int_ceildivpow2(tilec->z0, levelnoz); + band->x1 = int_ceildivpow2(tilec->x1, levelnox); + band->y1 = int_ceildivpow2(tilec->y1, levelnoy); + band->z1 = int_ceildivpow2(tilec->z1, levelnoz); + } else { + band->x0 = int_ceildivpow2(tilec->x0 - (1 << levelnox) * x0b, levelnox + 1); + band->y0 = int_ceildivpow2(tilec->y0 - (1 << levelnoy) * y0b, levelnoy + 1); + band->z0 = int_ceildivpow2(tilec->z0 - (1 << levelnoz) * z0b, (resno <= diff) ? levelnoz : levelnoz + 1); + band->x1 = int_ceildivpow2(tilec->x1 - (1 << levelnox) * x0b, levelnox + 1); + band->y1 = int_ceildivpow2(tilec->y1 - (1 << levelnoy) * y0b, levelnoy + 1); + band->z1 = int_ceildivpow2(tilec->z1 - (1 << levelnoz) * z0b, (resno <= diff) ? levelnoz : levelnoz + 1); + } + + ss = &tccp->stepsizes[(resno == 0) ? 0 : (prevnumbands + bandno + 1)]; + if (bandno == (res->numbands - 1)) + prevnumbands += (resno == 0) ? 0 : res->numbands; + gain = dwt_getgain(band->bandno,tccp->reversible); + numbps = volume->comps[compno].prec + gain; + band->stepsize = (float)((1.0 + ss->mant / 2048.0) * pow(2.0, numbps - ss->expn)); + band->numbps = ss->expn + tccp->numgbits - 1; /* WHY -1 ? */ + + band->precincts = (opj_tcd_precinct_t *) opj_malloc((res->prctno[0] * res->prctno[1] * res->prctno[2]) * sizeof(opj_tcd_precinct_t)); + + for (i = 0; i < (res->prctno[0] * res->prctno[1] * res->prctno[2]); i++) { + band->precincts[i].imsbtree = NULL; + band->precincts[i].incltree = NULL; + } + + for (precno = 0; precno < (res->prctno[0] * res->prctno[1] * res->prctno[2]); precno++) { + int tlcblkxstart, tlcblkystart, tlcblkzstart, brcblkxend, brcblkyend, brcblkzend; + int cbgxstart, cbgystart, cbgzstart, cbgxend, cbgyend, cbgzend; + + cbgxstart = tlcbgxstart + (precno % res->prctno[0]) * (1 << cbgwidthexpn); + cbgystart = tlcbgystart + ((precno % (res->prctno[0] * res->prctno[1])) / res->prctno[0]) * (1 << cbgheightexpn); + cbgzstart = tlcbgzstart + (precno / (res->prctno[0] * res->prctno[1])) * (1 << cbglengthexpn); + cbgxend = cbgxstart + (1 << cbgwidthexpn); + cbgyend = cbgystart + (1 << cbgheightexpn); + cbgzend = cbgzstart + (1 << cbglengthexpn); + + tcd->prc = &band->precincts[precno]; + prc = tcd->prc; + + /* precinct size (global) */ + prc->x0 = int_max(cbgxstart, band->x0); + prc->y0 = int_max(cbgystart, band->y0); + prc->z0 = int_max(cbgzstart, band->z0); + prc->x1 = int_min(cbgxend, band->x1); + prc->y1 = int_min(cbgyend, band->y1); + prc->z1 = int_min(cbgzend, band->z1); + + tlcblkxstart = int_floordivpow2(prc->x0, cblkwidthexpn) << cblkwidthexpn; + tlcblkystart = int_floordivpow2(prc->y0, cblkheightexpn) << cblkheightexpn; + tlcblkzstart = int_floordivpow2(prc->z0, cblklengthexpn) << cblklengthexpn; + brcblkxend = int_ceildivpow2(prc->x1, cblkwidthexpn) << cblkwidthexpn; + brcblkyend = int_ceildivpow2(prc->y1, cblkheightexpn) << cblkheightexpn; + brcblkzend = int_ceildivpow2(prc->z1, cblklengthexpn) << cblklengthexpn; + prc->cblkno[0] = (brcblkxend - tlcblkxstart) >> cblkwidthexpn; + prc->cblkno[1] = (brcblkyend - tlcblkystart) >> cblkheightexpn; + prc->cblkno[2] = (brcblkzend - tlcblkzstart) >> cblklengthexpn; + prc->cblkno[2] = (prc->cblkno[2] == 0) ? 1 : prc->cblkno[2]; + + prc->cblks = (opj_tcd_cblk_t *) opj_malloc((prc->cblkno[0] * prc->cblkno[1] * prc->cblkno[2]) * sizeof(opj_tcd_cblk_t)); + prc->incltree = tgt_create(prc->cblkno[0], prc->cblkno[1], prc->cblkno[2]); + prc->imsbtree = tgt_create(prc->cblkno[0], prc->cblkno[1], prc->cblkno[2]); + //tgt_tree_dump(stdout,prc->incltree); + for (cblkno = 0; cblkno < (prc->cblkno[0] * prc->cblkno[1] * prc->cblkno[2]); cblkno++) { + int cblkxstart = tlcblkxstart + (cblkno % prc->cblkno[0]) * (1 << cblkwidthexpn); + int cblkystart = tlcblkystart + ((cblkno % (prc->cblkno[0] * prc->cblkno[1])) / prc->cblkno[0]) * (1 << cblkheightexpn); + int cblkzstart = tlcblkzstart + (cblkno / (prc->cblkno[0] * prc->cblkno[1])) * (1 << cblklengthexpn); + int cblkxend = cblkxstart + (1 << cblkwidthexpn); + int cblkyend = cblkystart + (1 << cblkheightexpn); + int cblkzend = cblkzstart + (1 << cblklengthexpn); + int prec = ((tilec->bpp > 16) ? 3 : ((tilec->bpp > 8) ? 2 : 1)); + + tcd->cblk = &prc->cblks[cblkno]; + cblk = tcd->cblk; + + /* code-block size (global) */ + cblk->x0 = int_max(cblkxstart, prc->x0); + cblk->y0 = int_max(cblkystart, prc->y0); + cblk->z0 = int_max(cblkzstart, prc->z0); + cblk->x1 = int_min(cblkxend, prc->x1); + cblk->y1 = int_min(cblkyend, prc->y1); + cblk->z1 = int_min(cblkzend, prc->z1); + } + } + } + } + } + //tcd_dump(stdout, tcd, tcd->tcd_volume); + +} +void tcd_init_encode(opj_tcd_t *tcd, opj_volume_t * volume, opj_cp_t * cp, int curtileno) { + int compno, resno, bandno, precno, cblkno; + int j, p, q, r; + + opj_tcd_tile_t *tile = NULL; /* pointer to tcd->tile */ + opj_tcd_tilecomp_t *tilec = NULL; /* pointer to tcd->tilec */ + opj_tcd_resolution_t *res = NULL; /* pointer to tcd->res */ + opj_tcd_band_t *band = NULL; /* pointer to tcd->band */ + opj_tcd_precinct_t *prc = NULL; /* pointer to tcd->prc */ + opj_tcd_cblk_t *cblk = NULL; /* pointer to tcd->cblk */ + opj_tcp_t *tcp = &cp->tcps[curtileno]; + + tcd->tile = tcd->tcd_volume->tiles; + tile = tcd->tile; + + /* p61 ISO/IEC IS15444-1 : 2002 */ + /* curtileno --> raster scanned index of tiles */ + /* p,q,r --> matricial index of tiles */ + p = curtileno % cp->tw; + q = curtileno / cp->tw; + r = curtileno / (cp->tw * cp->th); /* extension to 3-D */ + + /* 4 borders of the tile rescale on the volume if necessary (B.3)*/ + tile->x0 = int_max(cp->tx0 + p * cp->tdx, volume->x0); + tile->y0 = int_max(cp->ty0 + q * cp->tdy, volume->y0); + tile->z0 = int_max(cp->tz0 + r * cp->tdz, volume->z0); + tile->x1 = int_min(cp->tx0 + (p + 1) * cp->tdx, volume->x1); + tile->y1 = int_min(cp->ty0 + (q + 1) * cp->tdy, volume->y1); + tile->z1 = int_min(cp->tz0 + (r + 1) * cp->tdz, volume->z1); + tile->numcomps = volume->numcomps; + + /* Modification of the RATE >> */ + for (j = 0; j < tcp->numlayers; j++) { + if (tcp->rates[j] <= 1) { + tcp->rates[j] = 0; + } else { + float num = (float) (tile->numcomps * (tile->x1 - tile->x0) * (tile->y1 - tile->y0) * (tile->z1 - tile->z0) * volume->comps[0].prec); + float den = (float) (8 * volume->comps[0].dx * volume->comps[0].dy * volume->comps[0].dz); + den = tcp->rates[j] * den; + tcp->rates[j] = (num + den - 1) / den; + } + /*tcp->rates[j] = tcp->rates[j] ? int_ceildiv( + tile->numcomps * (tile->x1 - tile->x0) * (tile->y1 - tile->y0) * (tile->z1 - tile->z0) * volume->comps[0].prec, + (tcp->rates[j] * 8 * volume->comps[0].dx * volume->comps[0].dy * volume->comps[0].dz)) : 0;*/ + if (tcp->rates[j]) { + if (j && tcp->rates[j] < tcp->rates[j - 1] + 10) { + tcp->rates[j] = tcp->rates[j - 1] + 20; + } else if (!j && tcp->rates[j] < 30){ + tcp->rates[j] = 30; + } + } + } + /* << Modification of the RATE */ + + for (compno = 0; compno < tile->numcomps; compno++) { + opj_tccp_t *tccp = &tcp->tccps[compno]; + int res_max, i; + int prevnumbands = 0; + + /* opj_tcd_tilecomp_t *tilec=&tile->comps[compno]; */ + tcd->tilec = &tile->comps[compno]; + tilec = tcd->tilec; + + /* border of each tile component (global) (B.3) */ + tilec->x0 = int_ceildiv(tile->x0, volume->comps[compno].dx); + tilec->y0 = int_ceildiv(tile->y0, volume->comps[compno].dy); + tilec->z0 = int_ceildiv(tile->z0, volume->comps[compno].dz); + tilec->x1 = int_ceildiv(tile->x1, volume->comps[compno].dx); + tilec->y1 = int_ceildiv(tile->y1, volume->comps[compno].dy); + tilec->z1 = int_ceildiv(tile->z1, volume->comps[compno].dz); + + tilec->data = (int *) opj_malloc((tilec->x1 - tilec->x0) * (tilec->y1 - tilec->y0) * (tilec->z1 - tilec->z0) * sizeof(int)); + + res_max = 0; + for (i = 0;i < 3; i++){ + tilec->numresolution[i] = tccp->numresolution[i]; + //Greater of 3 resolutions contains all information + res_max = (tilec->numresolution[i] > res_max) ? tilec->numresolution[i] : res_max; + } + + tilec->resolutions = (opj_tcd_resolution_t *) opj_malloc(res_max * sizeof(opj_tcd_resolution_t)); + for (resno = 0; resno < res_max; resno++) { + int pdx, pdy, pdz; + int tlprcxstart, tlprcystart, tlprczstart, brprcxend, brprcyend, brprczend; + int tlcbgxstart, tlcbgystart, tlcbgzstart, brcbgxend, brcbgyend, brcbgzend; + int cbgwidthexpn, cbgheightexpn, cbglengthexpn; + int cblkwidthexpn, cblkheightexpn, cblklengthexpn; + + int levelnox = tilec->numresolution[0] - 1 - resno; + int levelnoy = tilec->numresolution[1] - 1 - resno; + int diff = tccp->numresolution[0] - tccp->numresolution[2]; + int levelnoz = tilec->numresolution[2] - 1 - ((resno <= diff) ? 0 : (resno - diff)); + if (levelnoz < 0) levelnoz = 0; + + tcd->res = &tilec->resolutions[resno]; + res = tcd->res; + + /* border for each resolution level (global) (B.14)*/ + res->x0 = int_ceildivpow2(tilec->x0, levelnox); + res->y0 = int_ceildivpow2(tilec->y0, levelnoy); + res->z0 = int_ceildivpow2(tilec->z0, levelnoz); + res->x1 = int_ceildivpow2(tilec->x1, levelnox); + res->y1 = int_ceildivpow2(tilec->y1, levelnoy); + res->z1 = int_ceildivpow2(tilec->z1, levelnoz); + + // res->numbands = resno == 0 ? 1 : 3; /* --> 2D */ + res->numbands = (resno == 0) ? 1 : (resno <= diff) ? 3 : 7; /* --> 3D */ + + /* p. 30, table A-13, ISO/IEC IS154444-1 : 2002 */ + if (tccp->csty & J3D_CCP_CSTY_PRT) { + pdx = tccp->prctsiz[0][resno]; + pdy = tccp->prctsiz[1][resno]; + pdz = tccp->prctsiz[2][resno]; + } else { + pdx = 15; + pdy = 15; + pdz = 15; + } + /* p. 66, B.16, ISO/IEC IS15444-1 : 2002 */ + tlprcxstart = int_floordivpow2(res->x0, pdx) << pdx; + tlprcystart = int_floordivpow2(res->y0, pdy) << pdy; + tlprczstart = int_floordivpow2(res->z0, pdz) << pdz; + brprcxend = int_ceildivpow2(res->x1, pdx) << pdx; + brprcyend = int_ceildivpow2(res->y1, pdy) << pdy; + brprczend = int_ceildivpow2(res->z1, pdz) << pdz; + + res->prctno[0] = (brprcxend - tlprcxstart) >> pdx; + res->prctno[1] = (brprcyend - tlprcystart) >> pdy; + res->prctno[2] = (brprczend - tlprczstart) >> pdz; + if (res->prctno[2] == 0) res->prctno[2] = 1; + + /* p. 67, B.17 & B.18, ISO/IEC IS15444-1 : 2002 */ + if (resno == 0) { + tlcbgxstart = tlprcxstart; + tlcbgystart = tlprcystart; + tlcbgzstart = tlprczstart; + brcbgxend = brprcxend; + brcbgyend = brprcyend; + brcbgzend = brprczend; + cbgwidthexpn = pdx; + cbgheightexpn = pdy; + cbglengthexpn = pdz; + } else { + tlcbgxstart = int_ceildivpow2(tlprcxstart, 1); + tlcbgystart = int_ceildivpow2(tlprcystart, 1); + tlcbgzstart = int_ceildivpow2(tlprczstart, 1); + brcbgxend = int_ceildivpow2(brprcxend, 1); + brcbgyend = int_ceildivpow2(brprcyend, 1); + brcbgzend = int_ceildivpow2(brprczend, 1); + cbgwidthexpn = pdx - 1; + cbgheightexpn = pdy - 1; + cbglengthexpn = pdz - 1; + } + + cblkwidthexpn = int_min(tccp->cblk[0], cbgwidthexpn); + cblkheightexpn = int_min(tccp->cblk[1], cbgheightexpn); + cblklengthexpn = int_min(tccp->cblk[2], cbglengthexpn); + + res->bands = (opj_tcd_band_t *) opj_malloc(res->numbands * sizeof(opj_tcd_band_t)); + for (bandno = 0; bandno < res->numbands; bandno++) { + int x0b, y0b, z0b; + int gain, numbps; + opj_stepsize_t *ss = NULL; + + tcd->band = &res->bands[bandno]; + band = tcd->band; + + band->bandno = resno == 0 ? 0 : bandno + 1; + /* Bandno: 0 - LLL 2 - LHL + 1 - HLL 3 - HHL + 4 - LLH 6 - LHH + 5 - HLH 7 - HHH */ + x0b = (band->bandno == 1) || (band->bandno == 3) || (band->bandno == 5 ) || (band->bandno == 7 ) ? 1 : 0; + y0b = (band->bandno == 2) || (band->bandno == 3) || (band->bandno == 6 ) || (band->bandno == 7 ) ? 1 : 0; + z0b = (band->bandno == 4) || (band->bandno == 5) || (band->bandno == 6 ) || (band->bandno == 7 ) ? 1 : 0; + + /* p. 65, B.15, ISO/IEC IS15444-1 : 2002 */ + if (band->bandno == 0) { + /* band border (global) */ + band->x0 = int_ceildivpow2(tilec->x0, levelnox); + band->y0 = int_ceildivpow2(tilec->y0, levelnoy); + band->z0 = int_ceildivpow2(tilec->z0, levelnoz); + band->x1 = int_ceildivpow2(tilec->x1, levelnox); + band->y1 = int_ceildivpow2(tilec->y1, levelnoy); + band->z1 = int_ceildivpow2(tilec->z1, levelnoz); + } else { + band->x0 = int_ceildivpow2(tilec->x0 - (1 << levelnox) * x0b, levelnox + 1); + band->y0 = int_ceildivpow2(tilec->y0 - (1 << levelnoy) * y0b, levelnoy + 1); + band->z0 = int_ceildivpow2(tilec->z0 - (1 << levelnoz) * z0b, (resno <= diff) ? levelnoz : levelnoz + 1); + band->x1 = int_ceildivpow2(tilec->x1 - (1 << levelnox) * x0b, levelnox + 1); + band->y1 = int_ceildivpow2(tilec->y1 - (1 << levelnoy) * y0b, levelnoy + 1); + band->z1 = int_ceildivpow2(tilec->z1 - (1 << levelnoz) * z0b, (resno <= diff) ? levelnoz : levelnoz + 1); + } + + ss = &tccp->stepsizes[(resno == 0) ? 0 : (prevnumbands + bandno + 1)]; + if (bandno == (res->numbands - 1)) + prevnumbands += (resno == 0) ? 0 : res->numbands; + gain = dwt_getgain(band->bandno,tccp->reversible); + numbps = volume->comps[compno].prec + gain; + + band->stepsize = (float)((1.0 + ss->mant / 2048.0) * pow(2.0, numbps - ss->expn)); + band->numbps = ss->expn + tccp->numgbits - 1; /* WHY -1 ? */ + + for (precno = 0; precno < res->prctno[0] * res->prctno[1] * res->prctno[2]; precno++) { + int tlcblkxstart, tlcblkystart, tlcblkzstart, brcblkxend, brcblkyend, brcblkzend; + + int cbgxstart = tlcbgxstart + (precno % res->prctno[0]) * (1 << cbgwidthexpn); + int cbgystart = tlcbgystart + ((precno / (res->prctno[0] * res->prctno[1])) / res->prctno[0]) * (1 << cbgheightexpn); + int cbgzstart = tlcbgzstart + (precno / (res->prctno[0] * res->prctno[1])) * (1 << cbglengthexpn); + int cbgxend = cbgxstart + (1 << cbgwidthexpn); + int cbgyend = cbgystart + (1 << cbgheightexpn); + int cbgzend = cbgzstart + (1 << cbglengthexpn); + + /* opj_tcd_precinct_t *prc=&band->precincts[precno]; */ + tcd->prc = &band->precincts[precno]; + prc = tcd->prc; + + /* precinct size (global) */ + prc->x0 = int_max(cbgxstart, band->x0); + prc->y0 = int_max(cbgystart, band->y0); + prc->z0 = int_max(cbgzstart, band->z0); + prc->x1 = int_min(cbgxend, band->x1); + prc->y1 = int_min(cbgyend, band->y1); + prc->z1 = int_min(cbgzend, band->z1); + + tlcblkxstart = int_floordivpow2(prc->x0, cblkwidthexpn) << cblkwidthexpn; + tlcblkystart = int_floordivpow2(prc->y0, cblkheightexpn) << cblkheightexpn; + tlcblkzstart = int_floordivpow2(prc->z0, cblklengthexpn) << cblklengthexpn; + brcblkxend = int_ceildivpow2(prc->x1, cblkwidthexpn) << cblkwidthexpn; + brcblkyend = int_ceildivpow2(prc->y1, cblkheightexpn) << cblkheightexpn; + brcblkzend = int_ceildivpow2(prc->z1, cblklengthexpn) << cblklengthexpn; + prc->cblkno[0] = (brcblkxend - tlcblkxstart) >> cblkwidthexpn; + prc->cblkno[1] = (brcblkyend - tlcblkystart) >> cblkheightexpn; + prc->cblkno[2] = (brcblkzend - tlcblkzstart) >> cblklengthexpn; + prc->cblkno[2] = (prc->cblkno[2] == 0) ? 1 : prc->cblkno[2]; + + opj_free(prc->cblks); + prc->cblks = (opj_tcd_cblk_t *) opj_malloc((prc->cblkno[0] * prc->cblkno[1] * prc->cblkno[2]) * sizeof(opj_tcd_cblk_t)); + prc->incltree = tgt_create(prc->cblkno[0], prc->cblkno[1], prc->cblkno[2]); + prc->imsbtree = tgt_create(prc->cblkno[0], prc->cblkno[1], prc->cblkno[2]); + + for (cblkno = 0; cblkno < (prc->cblkno[0] * prc->cblkno[1] * prc->cblkno[2]); cblkno++) { + int cblkxstart = tlcblkxstart + (cblkno % prc->cblkno[0]) * (1 << cblkwidthexpn); + int cblkystart = tlcblkystart + ((cblkno % (prc->cblkno[0] * prc->cblkno[1])) / prc->cblkno[0]) * (1 << cblkheightexpn); + int cblkzstart = tlcblkzstart + (cblkno / (prc->cblkno[0] * prc->cblkno[1])) * (1 << cblklengthexpn); + int cblkxend = cblkxstart + (1 << cblkwidthexpn); + int cblkyend = cblkystart + (1 << cblkheightexpn); + int cblkzend = cblkzstart + (1 << cblklengthexpn); + int prec = ((tilec->bpp > 16) ? 3 : ((tilec->bpp > 8) ? 2 : 1)); + + tcd->cblk = &prc->cblks[cblkno]; + cblk = tcd->cblk; + + /* code-block size (global) */ + cblk->x0 = int_max(cblkxstart, prc->x0); + cblk->y0 = int_max(cblkystart, prc->y0); + cblk->z0 = int_max(cblkzstart, prc->z0); + cblk->x1 = int_min(cblkxend, prc->x1); + cblk->y1 = int_min(cblkyend, prc->y1); + cblk->z1 = int_min(cblkzend, prc->z1); + } + } /* precno */ + } /* bandno */ + } /* resno */ + } /* compno */ + //tcd_dump(stdout, tcd, tcd->tcd_volume); +} + + +void tcd_free_encode(opj_tcd_t *tcd) { + int tileno, compno, resno, bandno, precno; + + opj_tcd_tile_t *tile = NULL; /* pointer to tcd->tile */ +// opj_tcd_slice_t *slice = NULL; /* pointer to tcd->slice */ + opj_tcd_tilecomp_t *tilec = NULL; /* pointer to tcd->tilec */ + opj_tcd_resolution_t *res = NULL; /* pointer to tcd->res */ + opj_tcd_band_t *band = NULL; /* pointer to tcd->band */ + opj_tcd_precinct_t *prc = NULL; /* pointer to tcd->prc */ + + for (tileno = 0; tileno < 1; tileno++) { + tcd->tile = tcd->tcd_volume->tiles; + tile = tcd->tile; + + for (compno = 0; compno < tile->numcomps; compno++) { + tcd->tilec = &tile->comps[compno]; + tilec = tcd->tilec; + + for (resno = 0; resno < tilec->numresolution[0]; resno++) { + tcd->res = &tilec->resolutions[resno]; + res = tcd->res; + + for (bandno = 0; bandno < res->numbands; bandno++) { + tcd->band = &res->bands[bandno]; + band = tcd->band; + + for (precno = 0; precno < res->prctno[0] * res->prctno[1] * res->prctno[2]; precno++) { + tcd->prc = &band->precincts[precno]; + prc = tcd->prc; + + if (prc->incltree != NULL) { + tgt_destroy(prc->incltree); + prc->incltree = NULL; + } + if (prc->imsbtree != NULL) { + tgt_destroy(prc->imsbtree); + prc->imsbtree = NULL; + } + opj_free(prc->cblks); + prc->cblks = NULL; + } /* for (precno */ + opj_free(band->precincts); + band->precincts = NULL; + } /* for (bandno */ + } /* for (resno */ + opj_free(tilec->resolutions); + tilec->resolutions = NULL; + } /* for (compno */ + opj_free(tile->comps); + tile->comps = NULL; + } /* for (tileno */ + opj_free(tcd->tcd_volume->tiles); + tcd->tcd_volume->tiles = NULL; +} + +/* ----------------------------------------------------------------------- */ +void tcd_malloc_decode(opj_tcd_t *tcd, opj_volume_t * volume, opj_cp_t * cp) { + int tileno, compno, resno, bandno, precno, cblkno, res_max, + i, j, p, q, r; + unsigned int x0 = 0, y0 = 0, z0 = 0, + x1 = 0, y1 = 0, z1 = 0, + w, h, l; + + tcd->volume = volume; + tcd->cp = cp; + tcd->tcd_volume->tw = cp->tw; + tcd->tcd_volume->th = cp->th; + tcd->tcd_volume->tl = cp->tl; + tcd->tcd_volume->tiles = (opj_tcd_tile_t *) opj_malloc(cp->tw * cp->th * cp->tl * sizeof(opj_tcd_tile_t)); + + for (i = 0; i < cp->tileno_size; i++) { + opj_tcp_t *tcp = &(cp->tcps[cp->tileno[i]]); + opj_tcd_tile_t *tile = &(tcd->tcd_volume->tiles[cp->tileno[i]]); + + /* p61 ISO/IEC IS15444-1 : 2002 */ + /* curtileno --> raster scanned index of tiles */ + /* p,q,r --> matricial index of tiles */ + tileno = cp->tileno[i]; + p = tileno % cp->tw; + q = tileno / cp->tw; + r = tileno / (cp->tw * cp->th); /* extension to 3-D */ + + /* 4 borders of the tile rescale on the volume if necessary (B.3)*/ + tile->x0 = int_max(cp->tx0 + p * cp->tdx, volume->x0); + tile->y0 = int_max(cp->ty0 + q * cp->tdy, volume->y0); + tile->z0 = int_max(cp->tz0 + r * cp->tdz, volume->z0); + tile->x1 = int_min(cp->tx0 + (p + 1) * cp->tdx, volume->x1); + tile->y1 = int_min(cp->ty0 + (q + 1) * cp->tdy, volume->y1); + tile->z1 = int_min(cp->tz0 + (r + 1) * cp->tdz, volume->z1); + tile->numcomps = volume->numcomps; + + tile->comps = (opj_tcd_tilecomp_t *) opj_malloc(volume->numcomps * sizeof(opj_tcd_tilecomp_t)); + for (compno = 0; compno < tile->numcomps; compno++) { + opj_tccp_t *tccp = &tcp->tccps[compno]; + opj_tcd_tilecomp_t *tilec = &tile->comps[compno]; + int prevnumbands = 0; + + /* border of each tile component (global) */ + tilec->x0 = int_ceildiv(tile->x0, volume->comps[compno].dx); + tilec->y0 = int_ceildiv(tile->y0, volume->comps[compno].dy); + tilec->z0 = int_ceildiv(tile->z0, volume->comps[compno].dz); + tilec->x1 = int_ceildiv(tile->x1, volume->comps[compno].dx); + tilec->y1 = int_ceildiv(tile->y1, volume->comps[compno].dy); + tilec->z1 = int_ceildiv(tile->z1, volume->comps[compno].dz); + + tilec->data = (int *) opj_malloc((tilec->x1 - tilec->x0) * (tilec->y1 - tilec->y0) * (tilec->z1 - tilec->z0) * sizeof(int)); + + res_max = 0; + for (i = 0;i < 3; i++){ + tilec->numresolution[i] = tccp->numresolution[i]; + //Greater of 3 resolutions contains all information + res_max = (tilec->numresolution[i] > res_max) ? tilec->numresolution[i] : res_max; + } + + tilec->resolutions = (opj_tcd_resolution_t *) opj_malloc(res_max * sizeof(opj_tcd_resolution_t)); + + for (resno = 0; resno < res_max; resno++) { + opj_tcd_resolution_t *res = &tilec->resolutions[resno]; + int pdx, pdy, pdz; + int tlprcxstart, tlprcystart, tlprczstart, brprcxend, brprcyend, brprczend; + int tlcbgxstart, tlcbgystart, tlcbgzstart, brcbgxend, brcbgyend, brcbgzend; + int cbgwidthexpn, cbgheightexpn, cbglengthexpn; + int cblkwidthexpn, cblkheightexpn, cblklengthexpn; + int levelnox = tilec->numresolution[0] - 1 - resno; + int levelnoy = tilec->numresolution[1] - 1 - resno; + int diff = tccp->numresolution[0] - tccp->numresolution[2]; + int levelnoz = tilec->numresolution[2] - 1 - ((resno <= diff) ? 0 : (resno - diff)); + if (levelnoz < 0) levelnoz = 0; + + /* border for each resolution level (global) */ + res->x0 = int_ceildivpow2(tilec->x0, levelnox); + res->y0 = int_ceildivpow2(tilec->y0, levelnoy); + res->z0 = int_ceildivpow2(tilec->z0, levelnoz); + res->x1 = int_ceildivpow2(tilec->x1, levelnox); + res->y1 = int_ceildivpow2(tilec->y1, levelnoy); + res->z1 = int_ceildivpow2(tilec->z1, levelnoz); + res->numbands = (resno == 0) ? 1 : (resno <= diff) ? 3 : 7; /* --> 3D */ + + /* p. 30, table A-13, ISO/IEC IS154444-1 : 2002 */ + if (tccp->csty & J3D_CCP_CSTY_PRT) { + pdx = tccp->prctsiz[0][resno]; + pdy = tccp->prctsiz[1][resno]; + pdz = tccp->prctsiz[2][resno]; + } else { + pdx = 15; + pdy = 15; + pdz = 15; + } + + /* p. 66, B.16, ISO/IEC IS15444-1 : 2002 */ + tlprcxstart = int_floordivpow2(res->x0, pdx) << pdx; + tlprcystart = int_floordivpow2(res->y0, pdy) << pdy; + tlprczstart = int_floordivpow2(res->z0, pdz) << pdz; + brprcxend = int_ceildivpow2(res->x1, pdx) << pdx; + brprcyend = int_ceildivpow2(res->y1, pdy) << pdy; + brprczend = int_ceildivpow2(res->z1, pdz) << pdz; + + res->prctno[0] = (brprcxend - tlprcxstart) >> pdx; + res->prctno[1] = (brprcyend - tlprcystart) >> pdy; + res->prctno[2] = (brprczend - tlprczstart) >> pdz; + + /* p. 67, B.17 & B.18, ISO/IEC IS15444-1 : 2002 */ + if (resno == 0) { + tlcbgxstart = tlprcxstart;//0 + tlcbgystart = tlprcystart; + tlcbgzstart = tlprczstart; + brcbgxend = brprcxend;//1 + brcbgyend = brprcyend; + brcbgzend = brprczend; + cbgwidthexpn = pdx; //15 + cbgheightexpn = pdy; + cbglengthexpn = pdz; + } else { + tlcbgxstart = int_ceildivpow2(tlprcxstart, 1); + tlcbgystart = int_ceildivpow2(tlprcystart, 1); + tlcbgzstart = int_ceildivpow2(tlprczstart, 1); + brcbgxend = int_ceildivpow2(brprcxend, 1); + brcbgyend = int_ceildivpow2(brprcyend, 1); + brcbgzend = int_ceildivpow2(brprczend, 1); + cbgwidthexpn = pdx - 1; + cbgheightexpn = pdy - 1; + cbglengthexpn = pdz - 1; + } + + cblkwidthexpn = int_min(tccp->cblk[0], cbgwidthexpn); //6 + cblkheightexpn = int_min(tccp->cblk[1], cbgheightexpn); //6 + cblklengthexpn = int_min(tccp->cblk[2], cbglengthexpn); //6 + + res->bands = (opj_tcd_band_t *) opj_malloc(res->numbands * sizeof(opj_tcd_band_t)); + for (bandno = 0; bandno < res->numbands; bandno++) { + int x0b, y0b, z0b; + int gain, numbps; + opj_stepsize_t *ss = NULL; + + opj_tcd_band_t *band = &res->bands[bandno]; + band->bandno = resno == 0 ? 0 : bandno + 1; + /* Bandno: 0 - LLL 2 - LHL + 1 - HLL 3 - HHL + 4 - LLH 6 - LHH + 5 - HLH 7 - HHH */ + x0b = (band->bandno == 1) || (band->bandno == 3) || (band->bandno == 5 ) || (band->bandno == 7 ) ? 1 : 0; + y0b = (band->bandno == 2) || (band->bandno == 3) || (band->bandno == 6 ) || (band->bandno == 7 ) ? 1 : 0; + z0b = (band->bandno == 4) || (band->bandno == 5) || (band->bandno == 6 ) || (band->bandno == 7 ) ? 1 : 0; + + /* p. 65, B.15, ISO/IEC IS15444-1 : 2002 */ + if (band->bandno == 0) { + /* band border (global) */ + band->x0 = int_ceildivpow2(tilec->x0, levelnox); + band->y0 = int_ceildivpow2(tilec->y0, levelnoy); + band->z0 = int_ceildivpow2(tilec->z0, levelnoz); + band->x1 = int_ceildivpow2(tilec->x1, levelnox); + band->y1 = int_ceildivpow2(tilec->y1, levelnoy); + band->z1 = int_ceildivpow2(tilec->z1, levelnoz); + } else { + band->x0 = int_ceildivpow2(tilec->x0 - (1 << levelnox) * x0b, levelnox + 1); + band->y0 = int_ceildivpow2(tilec->y0 - (1 << levelnoy) * y0b, levelnoy + 1); + band->z0 = int_ceildivpow2(tilec->z0 - (1 << levelnoz) * z0b, (resno <= diff) ? levelnoz : levelnoz + 1); + band->x1 = int_ceildivpow2(tilec->x1 - (1 << levelnox) * x0b, levelnox + 1); + band->y1 = int_ceildivpow2(tilec->y1 - (1 << levelnoy) * y0b, levelnoy + 1); + band->z1 = int_ceildivpow2(tilec->z1 - (1 << levelnoz) * z0b, (resno <= diff) ? levelnoz : levelnoz + 1); + } + + ss = &tccp->stepsizes[(resno == 0) ? 0 : (prevnumbands + bandno + 1)]; + if (bandno == (res->numbands - 1)) + prevnumbands += (resno == 0) ? 0 : res->numbands; + gain = dwt_getgain(band->bandno,tccp->reversible); + numbps = volume->comps[compno].prec + gain; + + band->stepsize = (float)((1.0 + ss->mant / 2048.0) * pow(2.0, numbps - ss->expn)); + band->numbps = ss->expn + tccp->numgbits - 1; /* WHY -1 ? */ + + band->precincts = (opj_tcd_precinct_t *) opj_malloc(res->prctno[0] * res->prctno[1] * res->prctno[2] * sizeof(opj_tcd_precinct_t)); + + for (precno = 0; precno < res->prctno[0] * res->prctno[1] * res->prctno[2]; precno++) { + int tlcblkxstart, tlcblkystart, tlcblkzstart, brcblkxend, brcblkyend, brcblkzend; + + int cbgxstart = tlcbgxstart + (precno % res->prctno[0]) * (1 << cbgwidthexpn); + int cbgystart = tlcbgystart + (precno / res->prctno[0]) * (1 << cbgheightexpn); + int cbgzstart = tlcbgzstart + (precno / (res->prctno[0] * res->prctno[1])) * (1 << cbglengthexpn); + int cbgxend = cbgxstart + (1 << cbgwidthexpn); + int cbgyend = cbgystart + (1 << cbgheightexpn); + int cbgzend = cbgzstart + (1 << cbglengthexpn); + + opj_tcd_precinct_t *prc = &band->precincts[precno]; + /* precinct size (global) */ + prc->x0 = int_max(cbgxstart, band->x0); + prc->y0 = int_max(cbgystart, band->y0); + prc->z0 = int_max(cbgzstart, band->z0); + prc->x1 = int_min(cbgxend, band->x1); + prc->y1 = int_min(cbgyend, band->y1); + prc->z1 = int_min(cbgzend, band->z1); + + tlcblkxstart = int_floordivpow2(prc->x0, cblkwidthexpn) << cblkwidthexpn; + tlcblkystart = int_floordivpow2(prc->y0, cblkheightexpn) << cblkheightexpn; + tlcblkzstart = int_floordivpow2(prc->z0, cblklengthexpn) << cblklengthexpn; + brcblkxend = int_ceildivpow2(prc->x1, cblkwidthexpn) << cblkwidthexpn; + brcblkyend = int_ceildivpow2(prc->y1, cblkheightexpn) << cblkheightexpn; + brcblkzend = int_ceildivpow2(prc->z1, cblklengthexpn) << cblklengthexpn; + prc->cblkno[0] = (brcblkxend - tlcblkxstart) >> cblkwidthexpn; + prc->cblkno[1] = (brcblkyend - tlcblkystart) >> cblkheightexpn; + prc->cblkno[2] = (brcblkzend - tlcblkzstart) >> cblklengthexpn; + prc->cblkno[2] = (prc->cblkno[2] == 0) ? 1 : prc->cblkno[2]; + + prc->cblks = (opj_tcd_cblk_t *) opj_malloc((prc->cblkno[0] * prc->cblkno[1] * prc->cblkno[2]) * sizeof(opj_tcd_cblk_t)); + prc->incltree = tgt_create(prc->cblkno[0], prc->cblkno[1], prc->cblkno[2]); + prc->imsbtree = tgt_create(prc->cblkno[0], prc->cblkno[1], prc->cblkno[2]); + + for (cblkno = 0; cblkno < prc->cblkno[0] * prc->cblkno[1] * prc->cblkno[2]; cblkno++) { + int cblkxstart = tlcblkxstart + (cblkno % prc->cblkno[0]) * (1 << cblkwidthexpn); + int cblkystart = tlcblkystart + ((cblkno % (prc->cblkno[0] * prc->cblkno[1])) / prc->cblkno[0]) * (1 << cblkheightexpn); + int cblkzstart = tlcblkzstart + (cblkno / (prc->cblkno[0] * prc->cblkno[1])) * (1 << cblklengthexpn); + int cblkxend = cblkxstart + (1 << cblkwidthexpn); + int cblkyend = cblkystart + (1 << cblkheightexpn); + int cblkzend = cblkzstart + (1 << cblklengthexpn); + int prec = ((tilec->bpp > 16) ? 3 : ((tilec->bpp > 8) ? 2 : 1)); + /* code-block size (global) */ + opj_tcd_cblk_t *cblk = &prc->cblks[cblkno]; + + /* code-block size (global) */ + cblk->x0 = int_max(cblkxstart, prc->x0); + cblk->y0 = int_max(cblkystart, prc->y0); + cblk->z0 = int_max(cblkzstart, prc->z0); + cblk->x1 = int_min(cblkxend, prc->x1); + cblk->y1 = int_min(cblkyend, prc->y1); + cblk->z1 = int_min(cblkzend, prc->z1); + } + } /* precno */ + } /* bandno */ + } /* resno */ + } /* compno */ + } /* i = 0..cp->tileno_size */ + + //tcd_dump(stdout, tcd, tcd->tcd_volume); + + /* + Allocate place to store the decoded data = final volume + Place limited by the tile really present in the codestream + */ + + for (i = 0; i < volume->numcomps; i++) { + for (j = 0; j < cp->tileno_size; j++) { + tileno = cp->tileno[j]; + x0 = (j == 0) ? tcd->tcd_volume->tiles[tileno].comps[i].x0 : int_min(x0,(unsigned int) tcd->tcd_volume->tiles[tileno].comps[i].x0); + y0 = (j == 0) ? tcd->tcd_volume->tiles[tileno].comps[i].y0 : int_min(y0,(unsigned int) tcd->tcd_volume->tiles[tileno].comps[i].y0); + z0 = (j == 0) ? tcd->tcd_volume->tiles[tileno].comps[i].z0 : int_min(z0,(unsigned int) tcd->tcd_volume->tiles[tileno].comps[i].z0); + x1 = (j == 0) ? tcd->tcd_volume->tiles[tileno].comps[i].x1 : int_max(x1,(unsigned int) tcd->tcd_volume->tiles[tileno].comps[i].x1); + y1 = (j == 0) ? tcd->tcd_volume->tiles[tileno].comps[i].y1 : int_max(y1,(unsigned int) tcd->tcd_volume->tiles[tileno].comps[i].y1); + z1 = (j == 0) ? tcd->tcd_volume->tiles[tileno].comps[i].z1 : int_max(z1,(unsigned int) tcd->tcd_volume->tiles[tileno].comps[i].z1); + } + + w = x1 - x0; + h = y1 - y0; + l = z1 - z0; + + volume->comps[i].data = (int *) opj_malloc(w * h * l * sizeof(int)); + volume->comps[i].w = w; + volume->comps[i].h = h; + volume->comps[i].l = l; + volume->comps[i].x0 = x0; + volume->comps[i].y0 = y0; + volume->comps[i].z0 = z0; + volume->comps[i].bigendian = cp->bigendian; + } +} + +void tcd_free_decode(opj_tcd_t *tcd) { + int tileno,compno,resno,bandno,precno; + + opj_tcd_volume_t *tcd_volume = tcd->tcd_volume; + + for (tileno = 0; tileno < tcd_volume->tw * tcd_volume->th * tcd_volume->tl; tileno++) { + opj_tcd_tile_t *tile = &tcd_volume->tiles[tileno]; + for (compno = 0; compno < tile->numcomps; compno++) { + opj_tcd_tilecomp_t *tilec = &tile->comps[compno]; + for (resno = 0; resno < tilec->numresolution[0]; resno++) { + opj_tcd_resolution_t *res = &tilec->resolutions[resno]; + for (bandno = 0; bandno < res->numbands; bandno++) { + opj_tcd_band_t *band = &res->bands[bandno]; + for (precno = 0; precno < res->prctno[1] * res->prctno[0] * res->prctno[2]; precno++) { + opj_tcd_precinct_t *prec = &band->precincts[precno]; + if (prec->cblks != NULL) opj_free(prec->cblks); + if (prec->imsbtree != NULL) tgt_destroy(prec->imsbtree); + if (prec->incltree != NULL) tgt_destroy(prec->incltree); + /*for (treeno = 0; treeno < prec->numtrees; treeno++){ + if (prec->imsbtree[treeno] != NULL) tgt_destroy(prec->imsbtree[treeno]); + if (prec->incltree[treeno] != NULL) tgt_destroy(prec->incltree[treeno]); + }*/ + } + if (band->precincts != NULL) opj_free(band->precincts); + } + } + if (tilec->resolutions != NULL) opj_free(tilec->resolutions); + } + if (tile->comps != NULL) opj_free(tile->comps); + } + + if (tcd_volume->tiles != NULL) opj_free(tcd_volume->tiles); +} + + + +/* ----------------------------------------------------------------------- */ +void tcd_makelayer_fixed(opj_tcd_t *tcd, int layno, int final) { + int compno, resno, bandno, precno, cblkno; + int value; /*, matrice[tcd_tcp->numlayers][tcd_tile->comps[0].numresolution[0]][3]; */ + int matrice[10][10][3]; + int i, j, k; + + opj_cp_t *cp = tcd->cp; + opj_tcd_tile_t *tcd_tile = tcd->tcd_tile; + opj_tcp_t *tcd_tcp = tcd->tcp; + + /*matrice=(int*)opj_malloc(tcd_tcp->numlayers*tcd_tile->comps[0].numresolution[0]*3*sizeof(int)); */ + + for (compno = 0; compno < tcd_tile->numcomps; compno++) { + opj_tcd_tilecomp_t *tilec = &tcd_tile->comps[compno]; + for (i = 0; i < tcd_tcp->numlayers; i++) { + for (j = 0; j < tilec->numresolution[0]; j++) { + for (k = 0; k < 3; k++) { + matrice[i][j][k] = + (int) (cp->matrice[i * tilec->numresolution[0] * 3 + j * 3 + k] + * (float) (tcd->volume->comps[compno].prec / 16.0)); + } + } + } + + for (resno = 0; resno < tilec->numresolution[0]; resno++) { + opj_tcd_resolution_t *res = &tilec->resolutions[resno]; + for (bandno = 0; bandno < res->numbands; bandno++) { + opj_tcd_band_t *band = &res->bands[bandno]; + for (precno = 0; precno < res->prctno[0] * res->prctno[1] * res->prctno[2]; precno++) { + opj_tcd_precinct_t *prc = &band->precincts[precno]; + for (cblkno = 0; cblkno < prc->cblkno[0] * prc->cblkno[1] * prc->cblkno[2]; cblkno++) { + opj_tcd_cblk_t *cblk = &prc->cblks[cblkno]; + opj_tcd_layer_t *layer = &cblk->layers[layno]; + int n; + int imsb = tcd->volume->comps[compno].prec - cblk->numbps; /* number of bit-plan equal to zero */ + /* Correction of the matrix of coefficient to include the IMSB information */ + if (layno == 0) { + value = matrice[layno][resno][bandno]; + if (imsb >= value) { + value = 0; + } else { + value -= imsb; + } + } else { + value = matrice[layno][resno][bandno] - matrice[layno - 1][resno][bandno]; + if (imsb >= matrice[layno - 1][resno][bandno]) { + value -= (imsb - matrice[layno - 1][resno][bandno]); + if (value < 0) { + value = 0; + } + } + } + + if (layno == 0) { + cblk->numpassesinlayers = 0; + } + + n = cblk->numpassesinlayers; + if (cblk->numpassesinlayers == 0) { + if (value != 0) { + n = 3 * value - 2 + cblk->numpassesinlayers; + } else { + n = cblk->numpassesinlayers; + } + } else { + n = 3 * value + cblk->numpassesinlayers; + } + + layer->numpasses = n - cblk->numpassesinlayers; + + if (!layer->numpasses) + continue; + + if (cblk->numpassesinlayers == 0) { + layer->len = cblk->passes[n - 1].rate; + layer->data = cblk->data; + } else { + layer->len = cblk->passes[n - 1].rate - cblk->passes[cblk->numpassesinlayers - 1].rate; + layer->data = cblk->data + cblk->passes[cblk->numpassesinlayers - 1].rate; + } + if (final) + cblk->numpassesinlayers = n; + } + } + } + } + } +} + +void tcd_rateallocate_fixed(opj_tcd_t *tcd) { + int layno; + for (layno = 0; layno < tcd->tcp->numlayers; layno++) { + tcd_makelayer_fixed(tcd, layno, 1); + } +} + +void tcd_makelayer(opj_tcd_t *tcd, int layno, double thresh, int final) { + int compno, resno, bandno, precno, cblkno, passno; + + opj_tcd_tile_t *tcd_tile = tcd->tcd_tile; + + tcd_tile->distolayer[layno] = 0; /* fixed_quality */ + + for (compno = 0; compno < tcd_tile->numcomps; compno++) { + opj_tcd_tilecomp_t *tilec = &tcd_tile->comps[compno]; + for (resno = 0; resno < tilec->numresolution[0]; resno++) { + opj_tcd_resolution_t *res = &tilec->resolutions[resno]; + for (bandno = 0; bandno < res->numbands; bandno++) { + opj_tcd_band_t *band = &res->bands[bandno]; + for (precno = 0; precno < res->prctno[0] * res->prctno[1] * res->prctno[2]; precno++) { + opj_tcd_precinct_t *prc = &band->precincts[precno]; + for (cblkno = 0; cblkno < prc->cblkno[0] * prc->cblkno[1] * prc->cblkno[2]; cblkno++) { + opj_tcd_cblk_t *cblk = &prc->cblks[cblkno]; + opj_tcd_layer_t *layer = &cblk->layers[layno]; + + int n; + if (layno == 0) { + cblk->numpassesinlayers = 0; + } + n = cblk->numpassesinlayers; + for (passno = cblk->numpassesinlayers; passno < cblk->totalpasses; passno++) { + int dr; + double dd; + opj_tcd_pass_t *pass = &cblk->passes[passno]; + if (n == 0) { + dr = pass->rate; + dd = pass->distortiondec; + } else { + dr = pass->rate - cblk->passes[n - 1].rate; + dd = pass->distortiondec - cblk->passes[n - 1].distortiondec; + } + if (!dr) { + if (dd) + n = passno + 1; + continue; + } + if (dd / dr >= thresh){ + n = passno + 1; + } + } + layer->numpasses = n - cblk->numpassesinlayers; + + if (!layer->numpasses) { + layer->disto = 0; + continue; + } + if (cblk->numpassesinlayers == 0) { + layer->len = cblk->passes[n - 1].rate; + layer->data = cblk->data; + layer->disto = cblk->passes[n - 1].distortiondec; + } else { + layer->len = cblk->passes[n - 1].rate - cblk->passes[cblk->numpassesinlayers - 1].rate; + layer->data = cblk->data + cblk->passes[cblk->numpassesinlayers - 1].rate; + layer->disto = cblk->passes[n - 1].distortiondec - cblk->passes[cblk->numpassesinlayers - 1].distortiondec; + } + + tcd_tile->distolayer[layno] += layer->disto; /* fixed_quality */ + + if (final) + cblk->numpassesinlayers = n; + + // fprintf(stdout,"MakeLayer : %d %f %d %d \n",layer->len, layer->disto, layer->numpasses, n); + } + } + } + } + } +} + +bool tcd_rateallocate(opj_tcd_t *tcd, unsigned char *dest, int len, opj_volume_info_t * volume_info) { + int compno, resno, bandno, precno, cblkno, passno, layno; + double min, max; + double cumdisto[100]; /* fixed_quality */ + const double K = 1; /* 1.1; // fixed_quality */ + double maxSE = 0; + + opj_cp_t *cp = tcd->cp; + opj_tcd_tile_t *tcd_tile = tcd->tcd_tile; + opj_tcp_t *tcd_tcp = tcd->tcp; + + min = DBL_MAX; + max = 0; + + tcd_tile->nbpix = 0; /* fixed_quality */ + + for (compno = 0; compno < tcd_tile->numcomps; compno++) { + opj_tcd_tilecomp_t *tilec = &tcd_tile->comps[compno]; + tilec->nbpix = 0; + for (resno = 0; resno < tilec->numresolution[0]; resno++) { + opj_tcd_resolution_t *res = &tilec->resolutions[resno]; + for (bandno = 0; bandno < res->numbands; bandno++) { + opj_tcd_band_t *band = &res->bands[bandno]; + for (precno = 0; precno < res->prctno[0] * res->prctno[1] * res->prctno[2]; precno++) { + opj_tcd_precinct_t *prc = &band->precincts[precno]; + for (cblkno = 0; cblkno < prc->cblkno[0] * prc->cblkno[1] * prc->cblkno[2]; cblkno++) { + opj_tcd_cblk_t *cblk = &prc->cblks[cblkno]; + for (passno = 0; passno < cblk->totalpasses; passno++) { + opj_tcd_pass_t *pass = &cblk->passes[passno]; + int dr; + double dd, rdslope; + if (passno == 0) { + dr = pass->rate; + dd = pass->distortiondec; + } else { + dr = pass->rate - cblk->passes[passno - 1].rate; + dd = pass->distortiondec - cblk->passes[passno - 1].distortiondec; + } + if (dr == 0) { + continue; + } + rdslope = dd / dr; + if (rdslope < min) { + min = rdslope; + } + if (rdslope > max) { + max = rdslope; + } + + } /* passno */ + + /* fixed_quality */ + tcd_tile->nbpix += ((cblk->x1 - cblk->x0) * (cblk->y1 - cblk->y0) * (cblk->z1 - cblk->z0)); + tilec->nbpix += ((cblk->x1 - cblk->x0) * (cblk->y1 - cblk->y0) * (cblk->z1 - cblk->z0)); + } /* cbklno */ + } /* precno */ + } /* bandno */ + } /* resno */ + + maxSE += (((double)(1 << tcd->volume->comps[compno].prec) - 1.0) + * ((double)(1 << tcd->volume->comps[compno].prec) -1.0)) + * ((double)(tilec->nbpix)); + } /* compno */ + + /* add antonin index */ + if(volume_info && volume_info->index_on) { + opj_tile_info_t *info_TL = &volume_info->tile[tcd->tcd_tileno]; + info_TL->nbpix = tcd_tile->nbpix; + info_TL->distotile = tcd_tile->distotile; + info_TL->thresh = (double *) opj_malloc(tcd_tcp->numlayers * sizeof(double)); + } + /* dda */ + + for (layno = 0; layno < tcd_tcp->numlayers; layno++) { + double lo = min; + double hi = max; + int success = 0; + int maxlen = tcd_tcp->rates[layno] ? int_min(((int) tcd_tcp->rates[layno]), len) : len; + double goodthresh; + double distotarget; /* fixed_quality */ + int i = 0; + + /* fixed_quality */ + distotarget = tcd_tile->distotile - ((K * maxSE) / pow((float)10, tcd_tcp->distoratio[layno] / 10)); + + if ((tcd_tcp->rates[layno]) || (cp->disto_alloc==0)) { + opj_t2_t *t2 = t2_create(tcd->cinfo, tcd->volume, cp); + int oldl = 0, oldoldl = 0; + for (i = 0; i < 128; i++) { + double thresh = (lo + hi) / 2; + int l = 0; + double distoachieved = 0; /* fixed_quality -q */ + + tcd_makelayer(tcd, layno, thresh, 0); + + if (cp->fixed_quality) { /* fixed_quality -q */ + distoachieved = (layno == 0) ? tcd_tile->distolayer[0] : cumdisto[layno - 1] + tcd_tile->distolayer[layno]; + if (distoachieved < distotarget) { + hi = thresh; + continue; + } + lo = thresh; + } else { /* disto_alloc -r, fixed_alloc -f */ + l = t2_encode_packets(t2, tcd->tcd_tileno, tcd_tile, layno + 1, dest, maxlen, volume_info); + //fprintf(stdout, "layno %d i %d len=%d max=%d \n",layno,i,l,maxlen); + if (l == -999) { + lo = thresh; + continue; + } else if (l == oldl && oldl == oldoldl && tcd_tile->distolayer[layno] > 0.0 && i>32) + break; + hi = thresh; + oldoldl = oldl; + oldl = l; + } + success = 1; + goodthresh = thresh; + } + t2_destroy(t2); + } else { + success = 1; + goodthresh = min; + } + if (!success) { + return false; + } + + if(volume_info && volume_info->index_on) { /* Threshold for Marcela Index */ + volume_info->tile[tcd->tcd_tileno].thresh[layno] = goodthresh; + } + tcd_makelayer(tcd, layno, goodthresh, 1); + + /* fixed_quality */ + cumdisto[layno] = (layno == 0) ? tcd_tile->distolayer[0] : cumdisto[layno - 1] + tcd_tile->distolayer[layno]; + } + + return true; +} + +/* ----------------------------------------------------------------------- */ +int tcd_encode_tile(opj_tcd_t *tcd, int tileno, unsigned char *dest, int len, opj_volume_info_t * volume_info) { + int compno; + int l, i, npck = 0; + double encoding_time; + + opj_tcd_tile_t *tile = NULL; + opj_tcp_t *tcd_tcp = NULL; + opj_cp_t *cp = NULL; + + opj_tcp_t *tcp = &tcd->cp->tcps[0]; + opj_tccp_t *tccp = &tcp->tccps[0]; + opj_volume_t *volume = tcd->volume; + opj_t2_t *t2 = NULL; /* T2 component */ + + tcd->tcd_tileno = tileno; /* current encoded/decoded tile */ + + tcd->tcd_tile = tcd->tcd_volume->tiles; /* tile information */ + tile = tcd->tcd_tile; + + tcd->tcp = &tcd->cp->tcps[tileno]; /* coding/decoding params of tileno */ + tcd_tcp = tcd->tcp; + + cp = tcd->cp; /* coding parameters */ + + /* INDEX >> */ + if(volume_info && volume_info->index_on) { + opj_tcd_tilecomp_t *tilec_idx = &tile->comps[0]; /* based on component 0 */ + for (i = 0; i < tilec_idx->numresolution[0]; i++) { + opj_tcd_resolution_t *res_idx = &tilec_idx->resolutions[i]; + + volume_info->tile[tileno].prctno[0][i] = res_idx->prctno[0]; + volume_info->tile[tileno].prctno[1][i] = res_idx->prctno[1]; + volume_info->tile[tileno].prctno[2][i] = res_idx->prctno[2]; + + npck += res_idx->prctno[0] * res_idx->prctno[1] * res_idx->prctno[2]; + + volume_info->tile[tileno].prctsiz[0][i] = tccp->prctsiz[0][i]; + volume_info->tile[tileno].prctsiz[1][i] = tccp->prctsiz[1][i]; + volume_info->tile[tileno].prctsiz[2][i] = tccp->prctsiz[2][i]; + } + volume_info->tile[tileno].packet = (opj_packet_info_t *) opj_malloc(volume_info->comp * volume_info->layer * npck * sizeof(opj_packet_info_t)); + } + /* << INDEX */ + + /*---------------TILE-------------------*/ + encoding_time = opj_clock(); /* time needed to encode a tile */ + + for (compno = 0; compno < tile->numcomps; compno++) { + int x, y, z; + opj_tcd_tilecomp_t *tilec = &tile->comps[compno]; + + int adjust; + int offset_x = int_ceildiv(volume->x0, volume->comps[compno].dx); //ceil(x0 / subsampling_dx) + int offset_y = int_ceildiv(volume->y0, volume->comps[compno].dy); + int offset_z = int_ceildiv(volume->z0, volume->comps[compno].dz); + + int tw = tilec->x1 - tilec->x0; + int w = int_ceildiv(volume->x1 - volume->x0, volume->comps[compno].dx); + int th = tilec->y1 - tilec->y0; + int h = int_ceildiv(volume->y1 - volume->y0, volume->comps[compno].dy); + int tl = tilec->z1 - tilec->z0; + int l = int_ceildiv(volume->z1 - volume->z0, volume->comps[compno].dz); + + + + /* extract tile data from volume.comps[0].data to tile.comps[0].data */ + //fprintf(stdout,"[INFO] Extract tile data\n"); + if (tcd->cp->transform_format == TRF_3D_RLS || tcd->cp->transform_format == TRF_3D_LSE) { + adjust = 0; + } else { + adjust = volume->comps[compno].sgnd ? 0 : 1 << (volume->comps[compno].prec - 1); //sign=='+' --> 2^(prec-1) + if (volume->comps[compno].dcoffset != 0){ + adjust += volume->comps[compno].dcoffset; + fprintf(stdout,"[INFO] DC Offset applied: DCO = %d -> adjust = %d\n",volume->comps[compno].dcoffset,adjust); + } + } + + if (tcd_tcp->tccps[compno].reversible == 1) { //IF perfect reconstruction (DWT.5-3) + for (z = tilec->z0; z < tilec->z1; z++) { + for (y = tilec->y0; y < tilec->y1; y++) { + /* start of the src tile scanline */ + int *data = &volume->comps[compno].data[(tilec->x0 - offset_x) + (y - offset_y) * w + (z - offset_z) * w * h]; + /* start of the dst tile scanline */ + int *tile_data = &tilec->data[(y - tilec->y0) * tw + (z - tilec->z0) * tw * th]; + for (x = tilec->x0; x < tilec->x1; x++) { + *tile_data++ = *data++ - adjust; + } + } + } + } else if (tcd_tcp->tccps[compno].reversible == 0) { //IF not (DWT.9-7) + for (z = tilec->z0; z < tilec->z1; z++) { + for (y = tilec->y0; y < tilec->y1; y++) { + /* start of the src tile scanline */ + int *data = &volume->comps[compno].data[(tilec->x0 - offset_x) + (y - offset_y) * w + (z - offset_z) * w * h]; + /* start of the dst tile scanline */ + int *tile_data = &tilec->data[(y - tilec->y0) * tw + (z - tilec->z0) * tw * th]; + for (x = tilec->x0; x < tilec->x1; x++) { + *tile_data++ = (*data++ - adjust) << 13; + } + } + } + } + + } + + /*----------------MCT-------------------*/ + if (tcd_tcp->mct) { + int samples = (tile->comps[0].x1 - tile->comps[0].x0) * (tile->comps[0].y1 - tile->comps[0].y0) * (tile->comps[0].z1 - tile->comps[0].z0); + fprintf(stdout,"[INFO] Tcd_encode_tile: mct\n"); + if (tcd_tcp->tccps[0].reversible == 0) { + mct_encode_real(tile->comps[0].data, tile->comps[1].data, tile->comps[2].data, samples); + } else { + mct_encode(tile->comps[0].data, tile->comps[1].data, tile->comps[2].data, samples); + } + } + /*----------------TRANSFORM---------------------------------*/ + fprintf(stdout,"[INFO] Tcd_encode_tile: Transform\n"); + for (compno = 0; compno < tile->numcomps; compno++) { + opj_tcd_tilecomp_t *tilec = &tile->comps[compno]; + dwt_encode(tilec, tcd_tcp->tccps[compno].dwtid); + } + + /*-------------------ENTROPY CODING-----------------------------*/ + fprintf(stdout,"[INFO] Tcd_encode_tile: Entropy coding\n"); + if ((cp->encoding_format == ENCOD_2EB)||(cp->encoding_format == ENCOD_3EB)) + { + if (cp->encoding_format == ENCOD_2EB) { + opj_t1_t *t1 = NULL; + t1 = t1_create(tcd->cinfo); + t1_encode_cblks(t1, tile, tcd_tcp); + t1_destroy(t1); + } else if (cp->encoding_format == ENCOD_3EB) { + opj_t1_3d_t *t1 = NULL; + t1 = t1_3d_create(tcd->cinfo); + t1_3d_encode_cblks(t1, tile, tcd_tcp); + t1_3d_destroy(t1); + } + /*-----------RATE-ALLOCATE------------------*/ + /* INDEX */ + if(volume_info) { + volume_info->index_write = 0; + } + if (cp->disto_alloc || cp->fixed_quality) { + fprintf(stdout,"[INFO] Tcd_encode_tile: Rate-allocate\n"); + tcd_rateallocate(tcd, dest, len, volume_info); /* Normal Rate/distortion allocation */ + } else {/* fixed_alloc */ + fprintf(stdout,"[INFO] Tcd_encode_tile: Rate-allocate fixed\n"); + tcd_rateallocate_fixed(tcd); /* Fixed layer allocation */ + } + + /*--------------TIER2------------------*/ + /* INDEX */ + if(volume_info) { + volume_info->index_write = 1; + } + fprintf(stdout,"[INFO] Tcd_encode_tile: Tier - 2\n"); + t2 = t2_create(tcd->cinfo, volume, cp); + l = t2_encode_packets(t2, tileno, tile, tcd_tcp->numlayers, dest, len, volume_info); + t2_destroy(t2); + } else if ((cp->encoding_format == ENCOD_2GR)||(cp->encoding_format == ENCOD_3GR)) { + /*if(volume_info) { + volume_info->index_write = 1; + } + gr = golomb_create(tcd->cinfo, volume, cp); + l = golomb_encode(gr, tileno, tile, dest, len, volume_info); + golomb_destroy(gr);*/ + } + + + /*---------------CLEAN-------------------*/ + fprintf(stdout,"[INFO] Tcd_encode_tile: %d bytes coded\n",l); + encoding_time = opj_clock() - encoding_time; + opj_event_msg(tcd->cinfo, EVT_INFO, "- tile encoded in %f s\n", encoding_time); + + /* cleaning memory */ + for (compno = 0; compno < tile->numcomps; compno++) { + tcd->tilec = &tile->comps[compno]; + opj_free(tcd->tilec->data); + } + + if (l == -999){ + fprintf(stdout,"[ERROR] Unable to perform T2 tier. Return -999.\n"); + return 0; + } + + return l; +} + + +bool tcd_decode_tile(opj_tcd_t *tcd, unsigned char *src, int len, int tileno) { + int l, i; + int compno, eof = 0; + double tile_time, t1_time, dwt_time; + + opj_tcd_tile_t *tile = NULL; + opj_t2_t *t2 = NULL; /* T2 component */ + + tcd->tcd_tileno = tileno; + tcd->tcd_tile = &(tcd->tcd_volume->tiles[tileno]); + tcd->tcp = &(tcd->cp->tcps[tileno]); + tile = tcd->tcd_tile; + + tile_time = opj_clock(); /* time needed to decode a tile */ + opj_event_msg(tcd->cinfo, EVT_INFO, "tile %d / %d\n", tileno + 1, tcd->cp->tw * tcd->cp->th * tcd->cp->tl); + + if ((tcd->cp->encoding_format == ENCOD_2EB) || (tcd->cp->encoding_format == ENCOD_3EB)) { + /*--------------TIER2------------------*/ + t2 = t2_create(tcd->cinfo, tcd->volume, tcd->cp); + l = t2_decode_packets(t2, src, len, tileno, tile); + t2_destroy(t2); + opj_event_msg(tcd->cinfo, EVT_INFO, "Tcd_decode_tile: %d bytes decoded\n",l); + + if (l == -999) { + eof = 1; + opj_event_msg(tcd->cinfo, EVT_ERROR, "Tcd_decode_tile: incomplete bistream\n"); + } + + /*------------------TIER1-----------------*/ + opj_event_msg(tcd->cinfo, EVT_INFO, "Tcd_decode_tile: Entropy decoding %d \n",tcd->cp->encoding_format); + t1_time = opj_clock(); /* time needed to decode a tile */ + if (tcd->cp->encoding_format == ENCOD_2EB) { + opj_t1_t *t1 = NULL; /* T1 component */ + t1 = t1_create(tcd->cinfo); + t1_decode_cblks(t1, tile, tcd->tcp); + t1_destroy(t1); + }else if (tcd->cp->encoding_format == ENCOD_3EB) { + opj_t1_3d_t *t1 = NULL; /* T1 component */ + t1 = t1_3d_create(tcd->cinfo); + t1_3d_decode_cblks(t1, tile, tcd->tcp); + t1_3d_destroy(t1); + } + + t1_time = opj_clock() - t1_time; + #ifdef VERBOSE + opj_event_msg(tcd->cinfo, EVT_INFO, "- tier-1 took %f s\n", t1_time); + #endif + } else if ((tcd->cp->encoding_format == ENCOD_2GR)||(tcd->cp->encoding_format == ENCOD_3GR)) { + opj_event_msg(tcd->cinfo, EVT_INFO, "Tcd_decode_tile: Entropy decoding -- Does nothing :-D\n"); + /* + gr = golomb_create(tcd->cinfo, tcd->volume, tcd->cp); + l = golomb_decode(gr, tileno, tile, src, len); + golomb_destroy(gr); + if (l == -999) { + eof = 1; + opj_event_msg(tcd->cinfo, EVT_ERROR, "Tcd_decode_tile: incomplete bistream\n"); + } + */ + } + + /*----------------DWT---------------------*/ + fprintf(stdout,"[INFO] Tcd_decode_tile: Inverse DWT\n"); + dwt_time = opj_clock(); /* time needed to decode a tile */ + for (compno = 0; compno < tile->numcomps; compno++) { + opj_tcd_tilecomp_t *tilec = &tile->comps[compno]; + int stops[3], dwtid[3]; + + for (i = 0; i < 3; i++) { + if (tcd->cp->reduce[i] != 0) + tcd->volume->comps[compno].resno_decoded[i] = tile->comps[compno].numresolution[i] - tcd->cp->reduce[i] - 1; + stops[i] = tilec->numresolution[i] - 1 - tcd->volume->comps[compno].resno_decoded[i]; + if (stops[i] < 0) stops[i]=0; + dwtid[i] = tcd->cp->tcps->tccps[compno].dwtid[i]; + } + + dwt_decode(tilec, stops, dwtid); + + for (i = 0; i < 3; i++) { + if (tile->comps[compno].numresolution[i] > 0) { + tcd->volume->comps[compno].factor[i] = tile->comps[compno].numresolution[i] - (tcd->volume->comps[compno].resno_decoded[i] + 1); + if ( (tcd->volume->comps[compno].factor[i]) < 0 ) + tcd->volume->comps[compno].factor[i] = 0; + } + } + } + dwt_time = opj_clock() - dwt_time; + #ifdef VERBOSE + opj_event_msg(tcd->cinfo, EVT_INFO, "- dwt took %f s\n", dwt_time); + #endif + + /*----------------MCT-------------------*/ + + if (tcd->tcp->mct) { + if (tcd->tcp->tccps[0].reversible == 1) { + mct_decode(tile->comps[0].data, tile->comps[1].data, tile->comps[2].data, + (tile->comps[0].x1 - tile->comps[0].x0) * (tile->comps[0].y1 - tile->comps[0].y0) * (tile->comps[0].z1 - tile->comps[0].z0)); + } else { + mct_decode_real(tile->comps[0].data, tile->comps[1].data, tile->comps[2].data, + (tile->comps[0].x1 - tile->comps[0].x0) * (tile->comps[0].y1 - tile->comps[0].y0)* (tile->comps[0].z1 - tile->comps[0].z0)); + } + } + + /*---------------TILE-------------------*/ + + for (compno = 0; compno < tile->numcomps; compno++) { + opj_tcd_tilecomp_t *tilec = &tile->comps[compno]; + opj_tcd_resolution_t *res = &tilec->resolutions[tcd->volume->comps[compno].resno_decoded[0]]; + int adjust; + int minval = tcd->volume->comps[compno].sgnd ? -(1 << (tcd->volume->comps[compno].prec - 1)) : 0; + int maxval = tcd->volume->comps[compno].sgnd ? (1 << (tcd->volume->comps[compno].prec - 1)) - 1 : (1 << tcd->volume->comps[compno].prec) - 1; + + int tw = tilec->x1 - tilec->x0; + int w = tcd->volume->comps[compno].w; + int th = tilec->y1 - tilec->y0; + int h = tcd->volume->comps[compno].h; + + int i, j, k; + int offset_x = int_ceildivpow2(tcd->volume->comps[compno].x0, tcd->volume->comps[compno].factor[0]); + int offset_y = int_ceildivpow2(tcd->volume->comps[compno].y0, tcd->volume->comps[compno].factor[1]); + int offset_z = int_ceildivpow2(tcd->volume->comps[compno].z0, tcd->volume->comps[compno].factor[2]); + + if (tcd->cp->transform_format == TRF_3D_RLS || tcd->cp->transform_format == TRF_3D_LSE) { + adjust = 0; + } else { + adjust = tcd->volume->comps[compno].sgnd ? 0 : 1 << (tcd->volume->comps[compno].prec - 1); //sign=='+' --> 2^(prec-1) + if (tcd->volume->comps[compno].dcoffset != 0){ + adjust += tcd->volume->comps[compno].dcoffset; + fprintf(stdout,"[INFO] DC Offset applied: DCO = %d -> adjust = %d\n",tcd->volume->comps[compno].dcoffset,adjust); + } + } + + for (k = res->z0; k < res->z1; k++) { + for (j = res->y0; j < res->y1; j++) { + for (i = res->x0; i < res->x1; i++) { + int v; + float tmp = (float)((tilec->data[i - res->x0 + (j - res->y0) * tw + (k - res->z0) * tw * th]) / 8192.0); + + if (tcd->tcp->tccps[compno].reversible == 1) { + v = tilec->data[i - res->x0 + (j - res->y0) * tw + (k - res->z0) * tw * th]; + } else { + int tmp2 = ((int) (floor(fabs(tmp)))) + ((int) floor(fabs(tmp*2))%2); + v = ((tmp < 0) ? -tmp2:tmp2); + } + v += adjust; + + tcd->volume->comps[compno].data[(i - offset_x) + (j - offset_y) * w + (k - offset_z) * w * h] = int_clamp(v, minval, maxval); + } + } + } + } + + tile_time = opj_clock() - tile_time; /* time needed to decode a tile */ + opj_event_msg(tcd->cinfo, EVT_INFO, "- tile decoded in %f s\n", tile_time); + + for (compno = 0; compno < tile->numcomps; compno++) { + opj_free(tcd->tcd_volume->tiles[tileno].comps[compno].data); + tcd->tcd_volume->tiles[tileno].comps[compno].data = NULL; + } + + if (eof) { + return false; + } + + return true; +} + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/tcd.h b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/tcd.h new file mode 100644 index 0000000..0de60b8 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/tcd.h @@ -0,0 +1,334 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * Copyright (c) 2006, Mónica Díez García, Image Processing Laboratory, University of Valladolid, Spain + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __TCD_H +#define __TCD_H +/** +@file tcd.h +@brief Implementation of a tile coder/decoder (TCD) + +The functions in TCD.C have for goal to encode or decode each tile independently from +each other. The functions in TCD.C are used by some function in JP3D.C. +*/ + +/** @defgroup TCD TCD - Implementation of a tile coder/decoder */ +/*@{*/ + +/** +Tile coder/decoder: segment instance +*/ +typedef struct opj_tcd_seg { +/** Number of passes in the segment */ + int numpasses; +/** Length of information */ + int len; +/** Data */ + unsigned char *data; +/** Number of passes posible for the segment */ + int maxpasses; +/** Number of passes added to the segment */ + int numnewpasses; +/** New length after inclusion of segments */ + int newlen; +} opj_tcd_seg_t; + +/** +Tile coder/decoder: pass instance +*/ +typedef struct opj_tcd_pass { +/** Rate obtained in the pass*/ + int rate; +/** Distorsion obtained in the pass*/ + double distortiondec; + int term; +/** Length of information */ + int len; +} opj_tcd_pass_t; + +/** +Tile coder/decoder: layer instance +*/ +typedef struct opj_tcd_layer { +/** Number of passes in the layer */ + int numpasses; +/** Length of information */ + int len; +/** Distortion within layer */ + double disto; /* add for index (Cfr. Marcela) */ + unsigned char *data; /* data */ +} opj_tcd_layer_t; + +/** +Tile coder/decoder: codeblock instance +*/ +typedef struct opj_tcd_cblk { +/** Dimension of the code-blocks : left upper corner (x0, y0, z0) */ + int x0, y0, z0; +/** Dimension of the code-blocks : right low corner (x1,y1,z1) */ + int x1, y1, z1; +/** Number of bits per simbol in codeblock */ + int numbps; + int numlenbits; + int len; /* length */ +/** Number of pass already done for the code-blocks */ + int numpasses; +/** number of pass added to the code-blocks */ + int numnewpasses; +/** Number of segments */ + int numsegs; +/** Segments informations */ + opj_tcd_seg_t segs[100]; +/** Number of passes in the layer */ + int numpassesinlayers; +/** Layer information */ + opj_tcd_layer_t layers[100]; +/** Total number of passes */ + int totalpasses; +/** Information about the passes */ + opj_tcd_pass_t passes[100]; +/* Data */ + unsigned char data[524288]; + //unsigned char *data; +} opj_tcd_cblk_t; + +/** +Tile coder/decoder: precint instance +*/ +typedef struct opj_tcd_precinct { +/** Dimension of the precint : left upper corner (x0, y0, z0) */ + int x0, y0, z0; +/** Dimension of the precint : right low corner (x1,y1,z1) */ + int x1, y1, z1; +/** Number of codeblocks in precinct in width and heigth and length*/ + int cblkno[3]; +/** Information about the codeblocks */ + opj_tcd_cblk_t *cblks; +/** Inclusion tree */ + opj_tgt_tree_t *incltree; +/** Missing MSBs tree */ + opj_tgt_tree_t *imsbtree; +} opj_tcd_precinct_t; + +/** +Tile coder/decoder: subband instance +*/ +typedef struct opj_tcd_band { +/** Dimension of the subband : left upper corner (x0, y0, z0) */ + int x0, y0, z0; +/** Dimension of the subband : right low corner (x1,y1,z1) */ + int x1, y1, z1; +/** Information about the precints */ + opj_tcd_precinct_t *precincts; /* precinct information */ +/** Number of bits per symbol in band */ + int numbps; +/** Quantization stepsize associated */ + float stepsize; +/** Band orientation (O->LLL,...,7->HHH) */ + int bandno; +} opj_tcd_band_t; + +/** +Tile coder/decoder: resolution instance +*/ +typedef struct opj_tcd_resolution { +/** Dimension of the resolution level : left upper corner (x0, y0, z0) */ + int x0, y0, z0; +/** Dimension of the resolution level : right low corner (x1,y1,z1) */ + int x1, y1, z1; +/** Number of precints in each dimension for the resolution level */ + int prctno[3]; +/** Number of subbands for the resolution level */ + int numbands; +/** Subband information */ + opj_tcd_band_t *bands; +} opj_tcd_resolution_t; + +/** +Tile coder/decoder: component instance +*/ +typedef struct opj_tcd_tilecomp { +/** Dimension of the component : left upper corner (x0, y0, z0) */ + int x0, y0, z0; +/** Dimension of the component : right low corner (x1,y1,z1) */ + int x1, y1, z1; +/** Number of resolutions level if DWT transform*/ + int numresolution[3]; +/** Resolution information */ + opj_tcd_resolution_t *resolutions; +/** Data of the component */ + int *data; +/** Fixed_quality related */ + int nbpix; +/** Number of bits per voxel in component */ + int bpp; +} opj_tcd_tilecomp_t; + +/** +Tile coder/decoder: tile instance +*/ +typedef struct opj_tcd_tile { +/** Dimension of the tile : left upper corner (x0, y0, z0) */ + int x0, y0, z0; +/** Dimension of the tile : right low corner (x1,y1,z1) */ + int x1, y1, z1; +/** Number of components in tile */ + int numcomps; +/** Components information */ + opj_tcd_tilecomp_t *comps; +/** Fixed_quality related : no of bytes of data*/ + int nbpix; +/** Fixed_quality related : distortion achieved in tile */ + double distotile; +/** Fixed_quality related : distortion achieved in each layer */ + double distolayer[100]; +} opj_tcd_tile_t; + +/** +Tile coder/decoder: volume instance +*/ +typedef struct opj_tcd_volume { +/** Number of tiles in width and heigth and length */ + int tw, th, tl; +/** Tiles information */ + opj_tcd_tile_t *tiles; +} opj_tcd_volume_t; + +/** +Tile coder/decoder +*/ +typedef struct opj_tcd { +/** Codec context */ + opj_common_ptr cinfo; +/** Volume information */ + opj_volume_t *volume; +/** Coding parameters */ + opj_cp_t *cp; +/** Coding/decoding parameters common to all tiles */ + opj_tcp_t *tcp; +/** Info on each volume tile */ + opj_tcd_volume_t *tcd_volume; +/** Pointer to the current encoded/decoded tile */ + opj_tcd_tile_t *tcd_tile; +/** Current encoded/decoded tile */ + int tcd_tileno; + + /**@name working variables */ + /*@{*/ + opj_tcd_tile_t *tile; + opj_tcd_tilecomp_t *tilec; + opj_tcd_resolution_t *res; + opj_tcd_band_t *band; + opj_tcd_precinct_t *prc; + opj_tcd_cblk_t *cblk; + /*@}*/ +} opj_tcd_t; + +/** @name Funciones generales */ +/*@{*/ +/* ----------------------------------------------------------------------- */ + +/** +Dump the content of a tcd structure +*/ +void tcd_dump(FILE *fd, opj_tcd_t *tcd, opj_tcd_volume_t *img); +/** +Create a new TCD handle +@param cinfo Codec context info +@return Returns a new TCD handle if successful returns NULL otherwise +*/ +opj_tcd_t* tcd_create(opj_common_ptr cinfo); +/** +Destroy a previously created TCD handle +@param tcd TCD handle to destroy +*/ +void tcd_destroy(opj_tcd_t *tcd); +/** +Initialize the tile coder (allocate the memory) +@param tcd TCD handle +@param volume Raw volume +@param cp Coding parameters +@param curtileno Number that identifies the tile that will be encoded +*/ +void tcd_malloc_encode(opj_tcd_t *tcd, opj_volume_t * volume, opj_cp_t * cp, int curtileno); +/** +Initialize the tile coder (reuses the memory allocated by tcd_malloc_encode)(for 3D-DWT) +@param tcd TCD handle +@param volume Raw volume +@param cp Coding parameters +@param curtileno Number that identifies the tile that will be encoded +*/ +void tcd_init_encode(opj_tcd_t *tcd, opj_volume_t * volume, opj_cp_t * cp, int curtileno); +/** +Free the memory allocated for encoding +@param tcd TCD handle +*/ +void tcd_free_encode(opj_tcd_t *tcd); +/** +Initialize the tile decoder +@param tcd TCD handle +@param volume Raw volume +@param cp Coding parameters +*/ +void tcd_malloc_decode(opj_tcd_t *tcd, opj_volume_t * volume, opj_cp_t * cp); + +void tcd_makelayer_fixed(opj_tcd_t *tcd, int layno, int final); +void tcd_rateallocate_fixed(opj_tcd_t *tcd); +void tcd_makelayer(opj_tcd_t *tcd, int layno, double thresh, int final); +bool tcd_rateallocate(opj_tcd_t *tcd, unsigned char *dest, int len, opj_volume_info_t * volume_info); +/** +Encode a tile from the raw volume into a buffer +@param tcd TCD handle +@param tileno Number that identifies one of the tiles to be encoded +@param dest Destination buffer +@param len Length of destination buffer +@param volume_info Creation of index file +@return +*/ +int tcd_encode_tile(opj_tcd_t *tcd, int tileno, unsigned char *dest, int len, opj_volume_info_t * volume_info); +/** +Decode a tile from a buffer into a raw volume +@param tcd TCD handle +@param src Source buffer +@param len Length of source buffer +@param tileno Number that identifies one of the tiles to be decoded +*/ +bool tcd_decode_tile(opj_tcd_t *tcd, unsigned char *src, int len, int tileno); +/** +Free the memory allocated for decoding +@param tcd TCD handle +*/ +void tcd_free_decode(opj_tcd_t *tcd); + +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __TCD_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/tgt.c b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/tgt.c new file mode 100644 index 0000000..bb38599 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/tgt.c @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "opj_includes.h" + +/* +========================================================== + Tag-tree coder interface +========================================================== +*/ +void tgt_tree_dump (FILE *fd, opj_tgt_tree_t * tree){ + int nodesno; + + fprintf(fd, "TGT_TREE {\n"); + fprintf(fd, " numnodes: %d \n", tree->numnodes); + fprintf(fd, " numleafsh: %d, numleafsv: %d, numleafsz: %d,\n", tree->numleafsh, tree->numleafsv, tree->numleafsz); + + for (nodesno = 0; nodesno < tree->numnodes; nodesno++) { + fprintf(fd, "tgt_node %d {\n", nodesno); + fprintf(fd, " value: %d \n", tree->nodes[nodesno].value); + fprintf(fd, " low: %d \n", tree->nodes[nodesno].low); + fprintf(fd, " known: %d \n", tree->nodes[nodesno].known); + if (tree->nodes[nodesno].parent) { + fprintf(fd, " parent.value: %d \n", tree->nodes[nodesno].parent->value); + fprintf(fd, " parent.low: %d \n", tree->nodes[nodesno].parent->low); + fprintf(fd, " parent.known: %d \n", tree->nodes[nodesno].parent->known); + } + fprintf(fd, "}\n"); + + } + fprintf(fd, "}\n"); + +} + + +opj_tgt_tree_t *tgt_create(int numleafsh, int numleafsv, int numleafsz) { + + int nplh[32]; + int nplv[32]; + int nplz[32]; + opj_tgt_node_t *node = NULL; + opj_tgt_node_t *parentnode = NULL; + opj_tgt_node_t *parentnode0 = NULL; + opj_tgt_tree_t *tree = NULL; + int i, j, k, p, p0; + int numlvls; + int n, z = 0; + + tree = (opj_tgt_tree_t *) opj_malloc(sizeof(opj_tgt_tree_t)); + if(!tree) + return NULL; + tree->numleafsh = numleafsh; + tree->numleafsv = numleafsv; + tree->numleafsz = numleafsz; + + numlvls = 0; + nplh[0] = numleafsh; + nplv[0] = numleafsv; + nplz[0] = numleafsz; + tree->numnodes = 0; + do { + n = nplh[numlvls] * nplv[numlvls] * nplz[numlvls]; + nplh[numlvls + 1] = (nplh[numlvls] + 1) / 2; + nplv[numlvls + 1] = (nplv[numlvls] + 1) / 2; + nplz[numlvls + 1] = (nplz[numlvls] + 1) / 2; + tree->numnodes += n; + ++numlvls; + } while (n > 1); + + if (tree->numnodes == 0) { + opj_free(tree); + return NULL; + } + + tree->nodes = (opj_tgt_node_t *) opj_malloc(tree->numnodes * sizeof(opj_tgt_node_t)); + if(!tree->nodes) { + opj_free(tree); + return NULL; + } + + node = tree->nodes; + parentnode = &tree->nodes[tree->numleafsh * tree->numleafsv * tree->numleafsz]; + parentnode0 = parentnode; + + p = tree->numleafsh * tree->numleafsv * tree->numleafsz; + p0 = p; + n = 0; + //fprintf(stdout,"\nH %d V %d Z %d numlvls %d nodes %d\n",tree->numleafsh,tree->numleafsv,tree->numleafsz,numlvls,tree->numnodes); + for (i = 0; i < numlvls - 1; ++i) { + for (j = 0; j < nplv[i]; ++j) { + k = nplh[i]*nplz[i]; + while (--k >= 0) { + node->parent = parentnode; //fprintf(stdout,"node[%d].parent = node[%d]\n",n,p); + ++node; ++n; + if (--k >= 0 && n < p) { + node->parent = parentnode; //fprintf(stdout,"node[%d].parent = node[%d]\n",n,p); + ++node; ++n; + } + if (nplz[i] != 1){ //2D operation vs 3D operation + if (--k >= 0 && n < p) { + node->parent = parentnode; //fprintf(stdout,"node[%d].parent = node[%d]\n",n,p); + ++node; ++n; + } + if (--k >= 0 && n < p) { + node->parent = parentnode; //fprintf(stdout,"node[%d].parent = node[%d]\n",n,p); + ++node; ++n; + } + } + ++parentnode; ++p; + } + if ((j & 1) || j == nplv[i] - 1) { + parentnode0 = parentnode; p0 = p; //fprintf(stdout,"parent = node[%d] \n",p); + } else { + parentnode = parentnode0; p = p0; //fprintf(stdout,"parent = node[%d] \n",p); + parentnode0 += nplh[i]*nplz[i]; p0 += nplh[i]*nplz[i]; + } + } + } + node->parent = 0; + + + tgt_reset(tree); + + return tree; +} + +void tgt_destroy(opj_tgt_tree_t *tree) { + opj_free(tree->nodes); + opj_free(tree); +} + +void tgt_reset(opj_tgt_tree_t *tree) { + int i; + + if (NULL == tree) + return; + + for (i = 0; i < tree->numnodes; i++) { + tree->nodes[i].value = 999; + tree->nodes[i].low = 0; + tree->nodes[i].known = 0; + } +} + +void tgt_setvalue(opj_tgt_tree_t *tree, int leafno, int value) { + opj_tgt_node_t *node; + node = &tree->nodes[leafno]; + while (node && node->value > value) { + node->value = value; + node = node->parent; + } +} + +void tgt_encode(opj_bio_t *bio, opj_tgt_tree_t *tree, int leafno, int threshold) { + opj_tgt_node_t *stk[31]; + opj_tgt_node_t **stkptr; + opj_tgt_node_t *node; + int low; + + stkptr = stk; + node = &tree->nodes[leafno]; + while (node->parent) { + *stkptr++ = node; + node = node->parent; + } + + low = 0; + for (;;) { + if (low > node->low) { + node->low = low; + } else { + low = node->low; + } + + while (low < threshold) { + if (low >= node->value) { + if (!node->known) { + bio_write(bio, 1, 1); + node->known = 1; + } + break; + } + bio_write(bio, 0, 1); + ++low; + } + + node->low = low; + if (stkptr == stk) + break; + node = *--stkptr; + } +} + +int tgt_decode(opj_bio_t *bio, opj_tgt_tree_t *tree, int leafno, int threshold) { + opj_tgt_node_t *stk[31]; + opj_tgt_node_t **stkptr; + opj_tgt_node_t *node; + int low; + + stkptr = stk; + node = &tree->nodes[leafno]; + while (node->parent) { + *stkptr++ = node; + node = node->parent; + } + + low = 0; + for (;;) { + if (low > node->low) { + node->low = low; + } else { + low = node->low; + } + while (low < threshold && low < node->value) { + if (bio_read(bio, 1)) { + node->value = low; + } else { + ++low; + } + } + node->low = low; + if (stkptr == stk) { + break; + } + node = *--stkptr; + } + + return (node->value < threshold) ? 1 : 0; +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/tgt.h b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/tgt.h new file mode 100644 index 0000000..bb3a18c --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/tgt.h @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __TGT_H +#define __TGT_H +/** +@file tgt.h +@brief Implementation of a tag-tree coder (TGT) + +The functions in TGT.C have for goal to realize a tag-tree coder. The functions in TGT.C +are used by some function in T2.C. +*/ + +/** @defgroup TGT TGT - Implementation of a tag-tree coder */ +/*@{*/ + +/** +Tag node +*/ +typedef struct opj_tgt_node { +/** Node parent reference */ + struct opj_tgt_node *parent; +/** */ + int value; +/** */ + int low; +/** */ + int known; +} opj_tgt_node_t; + +/** +Tag tree +*/ +typedef struct opj_tgt_tree { +/** Number of leaves from horizontal axis */ + int numleafsh; +/** Number of leaves from vertical axis */ + int numleafsv; +/** Number of leaves from axial axis */ + int numleafsz; +/** Number of nodes */ + int numnodes; +/** Reference to each node instance */ + opj_tgt_node_t *nodes; +} opj_tgt_tree_t; + +/** @name Funciones generales */ +/*@{*/ +/* ----------------------------------------------------------------------- */ +/** +Create a tag-tree +@param numleafsh Width of the array of leafs of the tree +@param numleafsv Height of the array of leafs of the tree +@param numleafsz Depth of the array of leafs of the tree +@return Returns a new tag-tree if successful, returns NULL otherwise +*/ +opj_tgt_tree_t *tgt_create(int numleafsh, int numleafsv, int numleafsz); +/** +Destroy a tag-tree, liberating memory +@param tree Tag-tree to destroy +*/ +void tgt_destroy(opj_tgt_tree_t *tree); +/** +Reset a tag-tree (set all leaves to 0) +@param tree Tag-tree to reset +*/ +void tgt_reset(opj_tgt_tree_t *tree); +/** +Set the value of a leaf of a tag-tree +@param tree Tag-tree to modify +@param leafno Number that identifies the leaf to modify +@param value New value of the leaf +*/ +void tgt_setvalue(opj_tgt_tree_t *tree, int leafno, int value); +/** +Encode the value of a leaf of the tag-tree up to a given threshold +@param bio Pointer to a BIO handle +@param tree Tag-tree to modify +@param leafno Number that identifies the leaf to encode +@param threshold Threshold to use when encoding value of the leaf +*/ +void tgt_encode(opj_bio_t *bio, opj_tgt_tree_t *tree, int leafno, int threshold); +/** +Decode the value of a leaf of the tag-tree up to a given threshold +@param bio Pointer to a BIO handle +@param tree Tag-tree to decode +@param leafno Number that identifies the leaf to decode +@param threshold Threshold to use when decoding value of the leaf +@return Returns 1 if the node's value < threshold, returns 0 otherwise +*/ +int tgt_decode(opj_bio_t *bio, opj_tgt_tree_t *tree, int leafno, int threshold); + +/*@}*/ +/* ----------------------------------------------------------------------- */ +void tgt_tree_dump (FILE *fd, opj_tgt_tree_t * tree); + +#endif /* __TGT_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/volume.c b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/volume.c new file mode 100644 index 0000000..f85f89f --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/volume.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "opj_includes.h" + +opj_volume_t* OPJ_CALLCONV opj_volume_create(int numcmpts, opj_volume_cmptparm_t *cmptparms, OPJ_COLOR_SPACE clrspc) { + int compno; + opj_volume_t *volume = NULL; + + volume = (opj_volume_t*)opj_malloc(sizeof(opj_volume_t)); + if(volume) { + volume->color_space = clrspc; + volume->numcomps = numcmpts; + /* allocate memory for the per-component information */ + volume->comps = (opj_volume_comp_t*)opj_malloc(volume->numcomps * sizeof(opj_volume_comp_t)); + if(!volume->comps) { + opj_volume_destroy(volume); + return NULL; + } + /* create the individual volume components */ + for(compno = 0; compno < numcmpts; compno++) { + opj_volume_comp_t *comp = &volume->comps[compno]; + comp->dx = cmptparms[compno].dx; + comp->dy = cmptparms[compno].dy; + comp->dz = cmptparms[compno].dz; + comp->w = cmptparms[compno].w; + comp->h = cmptparms[compno].h; + comp->l = cmptparms[compno].l; + comp->x0 = cmptparms[compno].x0; + comp->y0 = cmptparms[compno].y0; + comp->z0 = cmptparms[compno].z0; + comp->prec = cmptparms[compno].prec; + comp->bpp = cmptparms[compno].bpp; + comp->sgnd = cmptparms[compno].sgnd; + comp->bigendian = cmptparms[compno].bigendian; + comp->dcoffset = cmptparms[compno].dcoffset; + comp->data = (int*)opj_malloc(comp->w * comp->h * comp->l * sizeof(int)); + if(!comp->data) { + fprintf(stdout,"Unable to malloc comp->data (%d x %d x %d x bytes)",comp->w,comp->h,comp->l); + opj_volume_destroy(volume); + return NULL; + } + //fprintf(stdout,"%d %d %d %d %d %d %d %d %d", comp->w,comp->h, comp->l, comp->dx, comp->dy, comp->dz, comp->prec, comp->bpp, comp->sgnd); + } + } + + return volume; +} + +void OPJ_CALLCONV opj_volume_destroy(opj_volume_t *volume) { + int i; + if(volume) { + if(volume->comps) { + /* volume components */ + for(i = 0; i < volume->numcomps; i++) { + opj_volume_comp_t *volume_comp = &volume->comps[i]; + if(volume_comp->data) { + opj_free(volume_comp->data); + } + } + opj_free(volume->comps); + } + opj_free(volume); + } +} + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/volume.h b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/volume.h new file mode 100644 index 0000000..884fab1 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/libjp3dvm/volume.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2006, Mónica Díez García, Image Processing Laboratory, University of Valladolid, Spain + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __VOLUME_H +#define __VOLUME_H +/** +@file volume.h +@brief Implementation of operations on volumes (VOLUME) + +The functions in VOLUME.C have for goal to realize operations on volumes. +*/ + +/** @defgroup VOLUME VOLUME - Implementation of operations on volumes */ +/*@{*/ + + +/*@}*/ + +#endif /* __VOLUME_H */ + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/tcltk/LPI_JP3D_VM.tcl b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/tcltk/LPI_JP3D_VM.tcl new file mode 100644 index 0000000..eb184de --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/tcltk/LPI_JP3D_VM.tcl @@ -0,0 +1,114 @@ +#!/bin/sh +# The next line is executed by /bin/sh, but not tcl \ +exec wish "$0" ${1+"$@"} + +namespace eval jp3dVM { + + variable _progress 0 + variable _afterid "" + variable _status "Compute in progress..." + variable notebook + variable mainframe + variable dataout "Process execution information" + variable status + variable prgtext + variable prgindic + + set pwd [pwd] + cd [file dirname [info script]] + variable VMDIR [pwd] + cd $pwd + + foreach script {encoder.tcl decoder.tcl} { + namespace inscope :: source $VMDIR/$script + } +} + + +proc jp3dVM::create { } { + variable notebook + variable mainframe + variable dataout + + bind all { catch {console show} } + + # Menu description + set descmenu { + "&File" {} {} 0 { + {command "E&xit" {} "Exit BWidget jp3dVM" {} -command exit} + } + "&Options" {} {} 0 { + {command "&Encode" {} "Show encoder" {} + -command {$jp3dVM::notebook raise [$jp3dVM::notebook page 0]} + } + {command "&Decode" {} "Show decoder" {} + -command {$jp3dVM::notebook raise [$jp3dVM::notebook page 1]} + } + } + "&Help" {} {} 0 { + {command "&About authors..." {} "Show info about authors" {} + -command {MessageDlg .msgdlg -parent . -title "About authors" -message " Copyright @ LPI-UVA 2006 " -type ok -icon info}} + } + } + + set mainframe [MainFrame .mainframe \ + -menu $descmenu \ + -textvariable jp3dVM::status \ + -progressvar jp3dVM::prgindic] + + $mainframe addindicator -text "JP3D Verification Model 1.0.0" + + # NoteBook creation + set frame [$mainframe getframe] + set notebook [NoteBook $frame.nb] + + set logo [frame $frame.logo] + #creo imagen logo + image create photo LPIimg -file logoLPI.gif + set logoimg [Label $logo.logoimg -image LPIimg] + + set f0 [VMEncoder::create $notebook] + set f1 [VMDecoder::create $notebook] + + set tfinfo [TitleFrame $frame.codinfo -text "Program Execution"] + set codinfo [$tfinfo getframe] + set sw [ScrolledWindow $codinfo.sw -relief sunken -borderwidth 2 -scrollbar both] + set sf [ScrollableFrame $codinfo.sf ] + $sw setwidget $sf + set subf [$sf getframe] + set labinfo [label $subf.labinfo -textvariable jp3dVM::dataout -justify left] + + pack $labinfo -side left + pack $sw + + $notebook compute_size + $notebook raise [$notebook page 0] + + pack $logoimg -side left -fill x -expand yes + pack $notebook -expand yes + pack $logo $tfinfo -side left -expand yes + pack $mainframe -fill both -expand yes + update idletasks +} + + +proc jp3dVM::main {} { + variable VMDIR + + lappend ::auto_path [file dirname $VMDIR] + namespace inscope :: package require BWidget + + option add *TitleFrame.l.font {helvetica 11 bold italic} + + wm withdraw . + wm title . "JP3D Verification Model @ LPI" + + jp3dVM::create + BWidget::place . 0 0 center + wm deiconify . + raise . + focus -force . +} + +jp3dVM::main +wm geom . [wm geom .] diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/tcltk/README b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/tcltk/README new file mode 100644 index 0000000..f4e2e35 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/tcltk/README @@ -0,0 +1,13 @@ +HOWTO USE THE TCL/TK APP IN 'jp3d/tcltk' +---------------------------------------- +1. Download the 'BWidget-1.9.2' + http://www.sourceforge.net/projects/tcllib/ + +2. Install it e.g. in '/usr/local/BWidget-1.9.2/' +3. Add the lappend command in line 4 + to jp3d/tcltk/LPI_JP3D_VM.tcl: + +#!/bin/sh +# The next line is executed by /bin/sh, but not tcl \ +exec wish "$0" ${1+"$@"} +lappend auto_path /usr/local/BWidget-1.9.2 diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/tcltk/Thumbs.db b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/tcltk/Thumbs.db new file mode 100644 index 0000000000000000000000000000000000000000..5d6ffdf99eb8ebe582a94fa45d711c3e0bb856ca GIT binary patch literal 18944 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 Be`5du literal 0 HcmV?d00001 diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/tcltk/decoder.tcl b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/tcltk/decoder.tcl new file mode 100644 index 0000000..582ef4c --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/tcltk/decoder.tcl @@ -0,0 +1,272 @@ + +namespace eval VMDecoder { + variable var + variable JP3Ddecoder "../bin/jp3d_vm_dec.exe" + #variable JP3Ddecoder "jp3d_vm_dec.exe" +} + + +proc VMDecoder::create { nb } { + variable var + + set frameD [$nb insert end VMDecoder -text "Decoder"] + set topfD [frame $frameD.topfD] + set medfD [frame $frameD.medfD] + set bottomfD [frame $frameD.bottomfD] + set srcfD [TitleFrame $topfD.srcfD -text "Source"] + set dstfD [TitleFrame $topfD.dstfD -text "Destination"] + set paramfD [TitleFrame $medfD.paramfD -text "Decoding parameters"] + set infofD [TitleFrame $medfD.infofD -text "Distortion measures"] + + set frame1 [$srcfD getframe] + _sourceD $frame1 + set frame2 [$dstfD getframe] + _destinationD $frame2 + set frame3 [$infofD getframe] + _originalD $frame3 + set frame4 [$paramfD getframe] + _paramsD $frame4 + + set butD [Button $bottomfD.butD -text "Decode!" \ + -command "VMDecoder::_decode $frame1 $frame2 $frame3" \ + -helptext "Decoding trigger button"] + set butR [Button $bottomfD.butR -text "Save info" \ + -command "VMDecoder::_save $frame3" \ + -helptext "Save information"] + + pack $srcfD $dstfD -side left -fill both -padx 10 -ipadx 5 -expand yes + pack $topfD -pady 4 -fill x + + pack $paramfD $infofD -side left -fill both -padx 10 -pady 2 -ipadx 5 -expand yes + pack $medfD -pady 4 -fill x + + pack $butD $butR -side left -padx 4 -pady 5 -expand yes + pack $bottomfD -pady 4 -fill x + +return $frameD +} + + +proc fileDialogD {w ent operation} { + + variable file + + if {$operation == "open"} { + #-----Type names---------Extension(s)--- + set types { + {"JP3D Files" {.jp3d} } + {"All files" *} + } + set file [tk_getOpenFile -filetypes $types -parent $w ] + } elseif {$operation == "original"} { + #-----Type names---------Extension(s)--- + set types { + {"BIN Raw Image Files" {.bin} } + {"PGX Raw Image Files" {.pgx} } + {"All files" *} + } + set file [tk_getOpenFile -filetypes $types -parent $w ] + } else { + #-----Type names---------Extension(s)--- + set types { + {"BIN Raw Image Files" {.bin} } + {"PGX Raw Image Files" {.pgx} } + {"All files" *} + } + set file [tk_getSaveFile -filetypes $types -parent $w -initialfile Untitled -defaultextension "*.bin"] + } + if {[string compare $file ""]} { + $ent delete 0 end + $ent insert end $file + $ent xview moveto 1 + } +} + +proc VMDecoder::_sourceD { parent } { + + variable var + + set labsrcD [LabelFrame $parent.labsrcD -text "Select compressed file: " -side top \ + -anchor w -relief flat -borderwidth 0] + set subsrcD [$labsrcD getframe] + set listD [entry $subsrcD.entrysrcD -width 40 -textvariable VMDecoder::var(sourceD)] + + set labbrw [LabelFrame $parent.labbrw -side top -anchor w -relief flat -borderwidth 0] + set subbrw [$labbrw getframe] + set butbrw [button $subbrw.butbrw -image [Bitmap::get open] \ + -relief raised -borderwidth 1 -padx 1 -pady 1 \ + -command "fileDialogD . $subsrcD.entrysrcD open"] + + pack $listD -side top + pack $butbrw -side top + pack $labsrcD $labbrw -side left -fill both -expand yes + + +} + +proc VMDecoder::_destinationD { parent } { + + variable var + + set labdstD [LabelFrame $parent.labdstD -text "Save decompressed volume file(s) as: " -side top \ + -anchor w -relief flat -borderwidth 0] + set subdstD [$labdstD getframe] + set listD [entry $subdstD.entrydstD -width 40 -textvariable VMDecoder::var(destinationD)] + + set labbrw [LabelFrame $parent.labbrw -side top -anchor w -relief flat -borderwidth 0] + set subbrw [$labbrw getframe] + set butbrw [button $subbrw.butbrw -image [Bitmap::get save] \ + -relief raised -borderwidth 1 -padx 1 -pady 1 \ + -command "fileDialogD . $subdstD.entrydstD save"] + + pack $listD -side top + pack $butbrw -side top + pack $labdstD $labbrw -side left -fill both -expand yes +} + +proc VMDecoder::_originalD { parent } { + + variable var + + set laborgD [LabelFrame $parent.laborgD -text "Select original file: " -side top \ + -anchor w -relief flat -borderwidth 0] + set suborgD [$laborgD getframe] + set listorgD [entry $suborgD.entryorgD -width 30 -textvariable VMDecoder::var(originalD)] + + set labbrw2 [LabelFrame $parent.labbrw2 -side top -anchor w -relief flat -borderwidth 0] + set subbrw2 [$labbrw2 getframe] + set butbrw2 [button $subbrw2.butbrw2 -image [Bitmap::get open] \ + -relief raised -borderwidth 1 -padx 1 -pady 1 \ + -command "fileDialogD . $suborgD.entryorgD original"] + + set infoD [Label $parent.infoD -relief sunken -textvariable VMDecoder::var(decodinfo) -justify left] + + pack $listorgD -side left -anchor n + pack $butbrw2 -side left -anchor n + pack $infoD -side bottom -anchor nw -pady 4 -ipadx 150 -ipady 20 -expand yes + pack $laborgD $labbrw2 -side left -fill both + + +} + +proc VMDecoder::_paramsD { parent } { + + variable var + + ########### DECODING ############# + set labcod [LabelFrame $parent.labcod -side top -anchor w -relief sunken -borderwidth 1] + set subcod [$labcod getframe] + + set frameres [frame $subcod.frameres -borderwidth 1] + set labres [LabelEntry $frameres.labres -label "Resolutions to discard: " -labelwidth 20 -labelanchor w \ + -textvariable VMDecoder::var(resdiscard) -editable 1 \ + -helptext "Number of highest resolution levels to be discarded on each dimension" ] + set VMDecoder::var(resdiscard) "0,0,0" + + set framelayer [frame $subcod.framelayer -borderwidth 1] + set lablayer [LabelEntry $framelayer.lablayer -label "Layers to decode: " -labelwidth 20 -labelanchor w \ + -textvariable VMDecoder::var(layer) -editable 1 \ + -helptext "Maximum number of quality layers to decode" ] + set VMDecoder::var(layer) "All" + + set framebe [frame $subcod.framebe -borderwidth 1] + set chkbe [checkbutton $framebe.chkbe -text "Write decoded file with BigEndian byte order" \ + -variable VMDecoder::var(be) -onvalue 1 -offvalue 0 ] + + pack $labres -side left -padx 2 -anchor n + pack $lablayer -side left -padx 2 -anchor n + pack $chkbe -side left -padx 2 -anchor w + pack $frameres $framelayer $framebe -side top -anchor w + + pack $subcod -anchor n + pack $labcod -side left -fill both -padx 4 -expand yes +} + + +proc VMDecoder::_decode { framesrc framedst frameinfo} { + + variable var + + set sourceD [$framesrc.labsrcD.f.entrysrcD get ] + set destinationD [$framedst.labdstD.f.entrydstD get ] + set originD [$frameinfo.laborgD.f.entryorgD get ] + set cond1 [string match *.pgx [string tolower $destinationD]] + set cond2 [string match *\**.pgx [string tolower $destinationD]] + set cond3 [string match *.bin [string tolower $destinationD]] + + #comprobamos datos son correctos + if {($cond1 == 1) && ($cond2 == 0)} { + set pgx "*.pgx" + set pattern [string range $destinationD 0 [expr [string length $destinationD]-5]] + set destinationD $pattern$img + } elseif {$sourceD == ""} { + MessageDlg .msgdlg -parent . -message "Error : Source file is not defined !" -type ok -icon error + } elseif {$destinationD == ""} { + MessageDlg .msgdlg -parent . -message "Error : Destination file is not defined !" -type ok -icon error + } else { + + #creamos datain a partir de los parametros de entrada + #set dirJP3Ddecoder [mk_relativepath $VMDecoder::JP3Ddecoder] + set dirJP3Ddecoder $VMDecoder::JP3Ddecoder + set datain [concat " $dirJP3Ddecoder -i [mk_relativepath $sourceD] "] + set datain [concat " $datain -o [mk_relativepath $destinationD] "] + if {$originD != ""} { + set datain [concat " $datain -O [mk_relativepath $originD] "] + if {$cond3 == 1} { + set img ".img" + set pattern [string range $originD 0 [expr [string length $originD]-5]] + set pattern $pattern$img + if {[file exists $pattern]} { + set datain [concat " $datain -m [mk_relativepath $pattern] "] + } else { + MessageDlg .msgdlg -parent . -message "Error : IMG file associated to original BIN volume file not found in same directory !" -type ok -icon info + } + } + } + if {$VMDecoder::var(resdiscard) != "0,0,0"} { + set datain [concat " $datain -r $VMDecoder::var(resdiscard) "] + } + if {$VMDecoder::var(layer) != "All" && $VMDecoder::var(layer) > 0} { + set datain [concat " $datain -l $VMDecoder::var(layer) "] + } + if {$VMDecoder::var(be) == 1} { + set datain [concat " $datain -BE"] + } + + set VMDecoder::var(progval) 10 + ProgressDlg .progress -parent . -title "Wait..." \ + -type infinite \ + -width 20 \ + -textvariable "Compute in progress..."\ + -variable VMDecoder::progval \ + -stop "Stop" \ + -command {destroy .progress} + + after 200 set VMDecoder::var(progval) 2 + + set fp [open "| $datain " r+] + fconfigure $fp -buffering line + set jp3dVM::dataout [concat "EXECUTED PROGRAM:\n\t$datain"] + while {-1 != [gets $fp tmp]} { + set jp3dVM::dataout [concat "$jp3dVM::dataout\n$tmp"] + } + close $fp + destroy .progress + set cond [string first "ERROR" $jp3dVM::dataout] + set cond2 [string first "PSNR" $jp3dVM::dataout] + set cond3 [string first "RESULT" $jp3dVM::dataout] + if {$cond != -1} { + MessageDlg .msgdlg -parent . -message [string range $jp3dVM::dataout [expr $cond-1] end] -type ok -icon error + } elseif {$cond3 != -1} { + if {$cond2 != -1} { + set VMDecoder::var(decodinfo) [string range $jp3dVM::dataout [expr $cond2-1] end] + } + MessageDlg .msgdlg -parent . -message [string range $jp3dVM::dataout [expr $cond3-1] end] -type ok -icon info + } + } +} + +proc VMDecoder::_save { frameinfo } { + +} + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/tcltk/encoder.tcl b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/tcltk/encoder.tcl new file mode 100644 index 0000000..dc174b7 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/tcltk/encoder.tcl @@ -0,0 +1,470 @@ + +namespace eval VMEncoder { + variable var + variable JP3Dencoder "../bin/jp3d_vm_enc.exe" +} + +proc VMEncoder::create { nb } { + + set frame [$nb insert end VMEncoder -text "Encoder"] + set topf [frame $frame.topf] + set midf [frame $frame.midf] + set bottomf [frame $frame.bottomf] + set srcf [TitleFrame $topf.srcf -text "Source"] + set dstf [TitleFrame $topf.dstf -text "Destination"] + set Tparf [TitleFrame $midf.parfT -text "Transform Parameters"] + set Cparf [TitleFrame $midf.parfC -text "Coding Parameters"] + + set frame1 [$srcf getframe] + VMEncoder::_sourceE $frame1 + + set frame2 [$dstf getframe] + VMEncoder::_destinationE $frame2 + + set frame3 [$Tparf getframe] + VMEncoder::_transformE $frame3 + + set frame4 [$Cparf getframe] + VMEncoder::_codingE $frame4 + + set butE [Button $bottomf.butE -text "Encode!" \ + -command "VMEncoder::_encode $frame1 $frame2" \ + -helptext "Encoding trigger button"] + set butR [Button $bottomf.butR -text "Restore defaults" \ + -command "VMEncoder::_reset $frame1 $frame2 $frame3 $frame4" \ + -helptext "Reset to default values"] + + pack $srcf $dstf -side left -fill y -padx 4 -expand yes + pack $topf -pady 2 -fill x + + pack $Tparf $Cparf -side left -fill both -padx 4 -expand yes + pack $midf -pady 2 -fill x + + pack $butE $butR -side left -padx 40 -pady 5 -fill y -expand yes + pack $bottomf -pady 2 -fill x + + return $frame +} + +proc VMEncoder::_sourceE { parent } { + + variable var + + set labsrc [LabelFrame $parent.labsrc -text "Select volume file to encode: " -side top \ + -anchor w -relief flat -borderwidth 0] + set subsrc [$labsrc getframe] + set list [entry $subsrc.entrysrc -width 30 -textvariable VMDecoder::var(source)] + + set labbrw [LabelFrame $parent.labbrw -side top -anchor w -relief flat -borderwidth 0] + set subbrw [$labbrw getframe] + set butbrw [button $subbrw.butbrw -image [Bitmap::get open] \ + -relief raised -borderwidth 1 -padx 1 -pady 1 \ + -command "fileDialogE . $subsrc.entrysrc open"] + + pack $list -side top + pack $butbrw -side top + pack $labsrc $labbrw -side left -fill both -expand yes +} + +proc VMEncoder::_destinationE { parent } { + + variable var + + set labdst [LabelFrame $parent.labdst -text "Save compressed volume as: " -side top \ + -anchor w -relief flat -borderwidth 0] + set subdst [$labdst getframe] + set list [entry $subdst.entrydst -width 30 -textvariable VMDecoder::var(destination)] + + set labbrw [LabelFrame $parent.labbrw -side top -anchor w -relief flat -borderwidth 0] + set subbrw [$labbrw getframe] + set butbrw [button $subbrw.butbrw -image [Bitmap::get save] \ + -relief raised -borderwidth 1 -padx 1 -pady 1 \ + -command "fileDialogE . $subdst.entrydst save"] + + pack $list -side top + pack $butbrw -side top + pack $labdst $labbrw -side left -fill both -expand yes +} + +proc VMEncoder::_codingE { parent } { + + + ########### CODING ############# + set labcod [LabelFrame $parent.labcod -side top -anchor w -relief sunken -borderwidth 1] + set subcod [$labcod getframe] + + set framerate [frame $subcod.framerate -borderwidth 1] + set labrate [LabelEntry $framerate.labrate -label "Rates: " -labelwidth 9 -labelanchor w \ + -textvariable VMEncoder::var(rate) -editable 1 \ + -helptext "Compression ratios for different layers (R1, R2, R3,...). If R=1, lossless coding" ] + set VMEncoder::var(rate) "1" + + set framecblk [frame $subcod.framecblk -borderwidth 1] + set labcblk [LabelEntry $framecblk.labcblk -label "Codeblock: " -labelwidth 9 -labelanchor w \ + -textvariable VMEncoder::var(cblksize) -editable 1 \ + -helptext "Codeblock size (X, Y, Z)" ] + set VMEncoder::var(cblksize) "64,64,64" + + set frametile [frame $subcod.frametile -borderwidth 1] + set labtile [LabelEntry $frametile.labtile -label "Tile size: " -labelwidth 9 -labelanchor w \ + -textvariable VMEncoder::var(tilesize) -editable 1 \ + -helptext "Tile size (X, Y, Z)" ] + set VMEncoder::var(tilesize) "512,512,512" + + set framesop [frame $subcod.framesop -borderwidth 1] + set chksop [checkbutton $framesop.chksop -text "Write SOP marker" \ + -variable VMEncoder::var(sop) -onvalue 1 -offvalue 0 ] + set frameeph [frame $subcod.frameeph -borderwidth 1] + set chkeph [checkbutton $frameeph.chkeph -text "Write EPH marker" \ + -variable VMEncoder::var(eph) -onvalue 1 -offvalue 0 ] + + set framepoc [frame $subcod.framepoc -borderwidth 1] + set labpoc [label $framepoc.labpoc -text "Progression order: " ] + set progorder [ComboBox $framepoc.progorder \ + -text {Choose a progression order} \ + -width 10 \ + -textvariable VMEncoder::var(progorder) \ + -values {"LRCP" "RLCP" "RPCL" "PCRL" "CPRL"} \ + -helptext "Progression order"] + set VMEncoder::var(progorder) "LRCP" + + pack $labrate -side left -padx 2 -anchor n + pack $labcblk -side left -padx 2 -anchor n + pack $labpoc $progorder -side left -padx 2 -anchor w + #pack $labtile -side left -padx 2 -anchor n + pack $chksop -side left -padx 2 -anchor w + pack $chkeph -side left -padx 2 -anchor w + ########### ENTROPY CODING ############# + set labent [LabelFrame $parent.labent -text "Entropy Coding" -side top -anchor w -relief sunken -borderwidth 1] + set subent [$labent getframe] + foreach entval {2EB 3EB} entropy {2D_EBCOT 3D_EBCOT} { + set rad [radiobutton $subent.$entval \ + -text $entropy \ + -variable VMEncoder::var(encoding) \ + -command "disableGR $entval $labcblk $progorder $labrate $chksop $chkeph" \ + -value $entval ] + pack $rad -anchor w + } + $subent.2EB select + + pack $subent -padx 2 -anchor n + + pack $framerate $framecblk $framepoc $framesop $frameeph -side top -anchor w + pack $subcod -anchor n + + pack $labent $labcod -side left -fill both -padx 4 -expand yes + + +} + +proc VMEncoder::_transformE { parent } { + + variable var + + ########### TRANSFORM ############# + set labtrf [LabelFrame $parent.labtrf -text "Transform" -side top -anchor w -relief sunken -borderwidth 1] + set subtrf [$labtrf getframe] + set labres [LabelFrame $parent.labres -side top -anchor w -relief sunken -borderwidth 1] + set subres [$labres getframe] + + ########### ATK ############# + set frameatk [frame $subres.frameatk -borderwidth 1] + set labatk [label $frameatk.labatk -text "Wavelet kernel: " -anchor w] + set atk [ComboBox $frameatk.atk \ + -textvariable VMEncoder::var(atk) \ + -width 20 \ + -text {Choose a wavelet kernel} \ + -editable false \ + -values {"R5.3" "I9.7"} ] + set VMEncoder::var(atk) "R5.3" + pack $labatk $atk -side left -anchor w + ########### RESOLUTIONS ############# + set frameres1 [frame $subres.frameres1 -borderwidth 1] + set labresolution [label $frameres1.labresol -text "Resolutions: " -anchor w ] + set frameres2 [frame $subres.frameres2 -borderwidth 1] + set labresX [label $frameres2.labresX -text " X" -anchor w ] + set labresY [label $frameres2.labresY -text " Y" -anchor w ] + set labresZ [label $frameres2.labresZ -text " Z" -anchor w ] + + + set resX [SpinBox $frameres2.spinresX \ + -range {1 6 1} -textvariable VMEncoder::var(resX) \ + -helptext "Number of resolutions in X" \ + -width 3 \ + -editable false ] + set resY [SpinBox $frameres2.spinresY \ + -range {1 6 1} -textvariable VMEncoder::var(resY) \ + -helptext "Number of resolutions in Y" \ + -width 3 \ + -editable false ] + set resZ [SpinBox $frameres2.spinresZ \ + -range {1 6 1} -textvariable VMEncoder::var(resZ) \ + -helptext "Number of resolutions in Z" \ + -width 3 \ + -editable false \ + -state disabled ] + set VMEncoder::var(resX) 3 + set VMEncoder::var(resY) 3 + set VMEncoder::var(resZ) 3 + + ########### TRF ############# + foreach trfval {2DWT 3DWT} trf {2D-DWT 3D-DWT} { + set rad [radiobutton $subtrf.$trfval -text $trf \ + -variable VMEncoder::var(transform) \ + -command "disable3RLS $trfval $atk $resX $resY $resZ"\ + -value $trfval ] + pack $rad -anchor w + } + $subtrf.2DWT select + + pack $subtrf -side left -padx 2 -pady 4 + + pack $labresolution -padx 2 -side left -anchor w + pack $labresX $resX -padx 2 -side left -anchor w + pack $labresY $resY -padx 2 -side left -anchor w + pack $labresZ $resZ -padx 2 -side left -anchor w + + pack $frameres1 -side top -fill x + pack $frameres2 $frameatk -side top -padx 2 -pady 4 -anchor n + + pack $subres -side left -padx 2 -pady 4 + pack $labtrf $labres -side left -fill both -padx 4 -expand yes +} + + +proc VMEncoder::_encode { framesrc framedst } { + + variable var + + set source [$framesrc.labsrc.f.entrysrc get ] + set destination [$framedst.labdst.f.entrydst get ] + set cond1 [string match *.pgx [string tolower $source]] + set cond2 [string match *-*.pgx [string tolower $source]] + set cond3 [string match *.bin [string tolower $source]] + + set img ".img" + set pattern [string range $source 0 [expr [string length $source]-5]] + set pattern $pattern$img + set exist [file exists $pattern] + + #comprobamos datos son correctos + if {($cond1 == 1) && ($cond2 == 0)} { + MessageDlg .msgdlg -parent . -message "Info : Really want to encode an slice instead of a volume?.\n For a group of .pgx slices, name must contain a - denoting a sequential index!" -type ok -icon info + } + + if {$source == ""} { + MessageDlg .msgdlg -parent . -message "Error : Source file is not defined !" -type ok -icon error + } elseif {$destination == ""} { + MessageDlg .msgdlg -parent . -message "Error : Destination file is not defined !" -type ok -icon error + } elseif { ($VMEncoder::var(transform) != "3RLS") && ($VMEncoder::var(atk) == "Choose a wavelet transformation kernel") } { + MessageDlg .msgdlg -parent . -title "Info" -message "Please choose a wavelet transformation kernel"\ + -type ok -icon warning + } elseif {($exist == 0) && ($cond1 == 0) && ($cond3 == 1)} { + MessageDlg .msgdlg -parent . -message "Error : IMG file associated to BIN volume file not found in same directory !" -type ok -icon info + } else { + + #creamos datain a partir de los parametros de entrada +# set dirJP3Dencoder [mk_relativepath $VMEncoder::JP3Dencoder] + set dirJP3Dencoder $VMEncoder::JP3Dencoder + set datain [concat " $dirJP3Dencoder -i [mk_relativepath $source] "] + if {$cond3 == 1} { + set datain [concat " $datain -m [mk_relativepath $pattern] "] + } + set datain [concat " $datain -o [mk_relativepath $destination] "] + if {$VMEncoder::var(encoding) != "2EB"} { + set datain [concat " $datain -C $VMEncoder::var(encoding) "] + } + if {$VMEncoder::var(transform) == "2DWT"} { + set datain [concat " $datain -n $VMEncoder::var(resX),$VMEncoder::var(resY) "] + } elseif {$VMEncoder::var(transform) == "3DWT"} { + set datain [concat " $datain -n $VMEncoder::var(resX),$VMEncoder::var(resY),$VMEncoder::var(resZ) "] + } + + set datain [concat " $datain -r $VMEncoder::var(rate) "] + + if {$VMEncoder::var(atk) == "I9.7"} { + set datain [concat " $datain -I "] + } + if {$VMEncoder::var(sop) == 1} { + set datain [concat " $datain -SOP "] + } + if {$VMEncoder::var(eph) == 1} { + set datain [concat " $datain -EPH "] + } + if {$VMEncoder::var(progorder) != "LRCP"} { + set datain [concat " $datain -p $VMEncoder::var(progorder) "] + } + if {$VMEncoder::var(cblksize) != "64,64,64"} { + set datain [concat " $datain -b $VMEncoder::var(cblksize) "] + } + + + #Making this work would be great !!! + set VMEncoder::var(progval) 10 + ProgressDlg .progress -parent . -title "Wait..." \ + -type infinite \ + -width 20 \ + -textvariable "Compute in progress..."\ + -variable VMEncoder::progval \ + -stop "Stop" \ + -command {destroy .progress} + after 200 set VMEncoder::var(progval) 2 + set fp [open "| $datain " r+] + fconfigure $fp -buffering line + set jp3dVM::dataout [concat "EXECUTED PROGRAM:\n\t$datain"] + while {-1 != [gets $fp tmp]} { + set jp3dVM::dataout [concat "$jp3dVM::dataout\n$tmp"] + } + destroy .progress + set cond [string first "ERROR" $jp3dVM::dataout] + set cond2 [string first "RESULT" $jp3dVM::dataout] + if {$cond != -1} { + MessageDlg .msgdlg -parent . -message [string range $jp3dVM::dataout [expr $cond-1] end] -type ok -icon error + } elseif {$cond2 != -1} { + MessageDlg .msgdlg -parent . -message [string range $jp3dVM::dataout [expr $cond2+7] end] -type ok -icon info + close $fp + } else { + #Must do something with this !!! [pid $fp] + close $fp + } + } +} + +proc VMEncoder::_reset { framesrc framedst frametrf framecod} { + + variable var + + #Restore defaults values + set VMEncoder::var(transform) 2DWT + set VMEncoder::var(encoding) 2EB + set VMEncoder::var(atk) "R5.3" + set VMEncoder::var(progorder) "LRCP" + set atk $frametrf.labres.f.frameatk.atk + set resX $frametrf.labres.f.frameres2.spinresX + set resY $frametrf.labres.f.frameres2.spinresY + set resZ $frametrf.labres.f.frameres2.spinresZ + disable3RLS 2DWT $atk $resX $resY $resZ + set labcblk $framecod.labcod.f.framecblk.labcblk + set progorder $framecod.labcod.f.framepoc.progorder + set labrate $framecod.labcod.f.framerate.labrate + set chksop $framecod.labcod.f.framesop.chksop + set chkeph $framecod.labcod.f.frameeph.chkeph + disableGR 3EB $labcblk $progorder $labrate $chksop $chkeph + + $framesrc.labsrc.f.entrysrc delete 0 end + $framedst.labdst.f.entrydst delete 0 end +} + +proc fileDialogE {w ent operation} { + + variable file + variable i j + + if {$operation == "open"} { + set types { + {"Source Image Files" {.pgx .bin} } + {"All files" *} + } + set file [tk_getOpenFile -filetypes $types -parent $w] + if {[string compare $file ""]} { + $ent delete 0 end + $ent insert end $file + $ent xview moveto 1 + } + } else { + set types { + {"JP3D Files" {.jp3d} } + {"JPEG2000 Files" {.j2k} } + {"All files" *} + } + set file [tk_getSaveFile -filetypes $types -parent $w \ + -initialfile Untitled -defaultextension .jp3d] + if {[string compare $file ""]} { + $ent delete 0 end + $ent insert end $file + $ent xview moveto 1 + } + } +} + +proc mk_relativepath {abspath} { + + set mydir [split [string trimleft [pwd] {/}] {/}] + set abspathcomps [split [string trimleft $abspath {/}] {/}] + + set i 0 + while {$i<[llength $mydir]} { + if {![string compare [lindex $abspathcomps $i] [lindex $mydir $i]]} { + incr i + } else { + break + } + } + set h [expr [llength $mydir]-$i] + set j [expr [llength $abspathcomps]-$i] + + if {!$h} { + set relpath "./" + } else { + set relpath "" + while { $h > 0 } { + set relpath "../$relpath" + incr h -1 + } + } + + set h [llength $abspathcomps] + while { $h > $i } { + set relpath [concat $relpath[lindex $abspathcomps [expr [llength $abspathcomps]-$j]]/] + incr h -1 + incr j -1 + } + return [string trim $relpath {/}] +} + +proc disable3RLS {flag atk resX resY resZ} { + + if {$flag == "3RLS"} { + $atk configure -state disabled + $resX configure -state disabled + $resY configure -state disabled + $resZ configure -state disabled + } elseif {$flag == "2DWT"} { + $atk configure -state normal + $resX configure -state normal + $resY configure -state normal + $resZ configure -state disabled + } elseif {$flag == "3DWT"} { + $atk configure -state normal + $resX configure -state normal + $resY configure -state normal + $resZ configure -state normal + } +} + +proc disableGR {flag labcblk progorder labrate chksop chkeph} { + + if {$flag == "2EB"} { + $labcblk configure -state normal + $progorder configure -state normal + $labrate configure -state normal + $chksop configure -state normal + $chkeph configure -state normal + set VMEncoder::var(cblksize) "64,64,64" + set VMEncoder::var(tilesize) "512,512,512" + } elseif {$flag == "3EB"} { + $labcblk configure -state normal + $progorder configure -state normal + $labrate configure -state normal + $chksop configure -state normal + $chkeph configure -state normal + set VMEncoder::var(cblksize) "64,64,64" + set VMEncoder::var(tilesize) "512,512,512" + } else { + $labcblk configure -state disabled + $progorder configure -state disabled + $labrate configure -state disabled + $chksop configure -state disabled + $chkeph configure -state disabled + } +} \ No newline at end of file diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/tcltk/logoLPI.gif b/gdcm/Utilities/gdcmopenjpeg-v1/jp3d/tcltk/logoLPI.gif new file mode 100644 index 0000000000000000000000000000000000000000..df79515057f4163e12943482993fc337eafe2002 GIT binary patch literal 5212 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 HVCw$>l!K-J literal 0 HcmV?d00001 diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jpwl/CMakeLists.txt b/gdcm/Utilities/gdcmopenjpeg-v1/jpwl/CMakeLists.txt new file mode 100644 index 0000000..13664d7 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jpwl/CMakeLists.txt @@ -0,0 +1,107 @@ +# Makefile for the main JPWL OpenJPEG codecs: JPWL_ j2k_to_image and JPWL_image_to_j2k + +add_definitions(-DUSE_JPWL) + +set(OPJ_SRCS +../libopenjpeg/bio.c +../libopenjpeg/cio.c +../libopenjpeg/dwt.c +../libopenjpeg/event.c +../libopenjpeg/image.c +../libopenjpeg/j2k.c +../libopenjpeg/j2k_lib.c +../libopenjpeg/jp2.c +../libopenjpeg/jpt.c +../libopenjpeg/mct.c +../libopenjpeg/mqc.c +../libopenjpeg/openjpeg.c +../libopenjpeg/pi.c +../libopenjpeg/raw.c +../libopenjpeg/t1.c +../libopenjpeg/t2.c +../libopenjpeg/tcd.c +../libopenjpeg/tgt.c +) +set(JPWL_SRCS crc.c jpwl.c jpwl_lib.c rs.c) + +set(common_SRCS "") +# If not getopt was found then add it to the lib: +if(DONT_HAVE_GETOPT) + set(common_SRCS ${OPENJPEG_SOURCE_DIR}/common/getopt.c) +endif() + +# Build the library +if(WIN32) + if(BUILD_SHARED_LIBS) + add_definitions(-DOPJ_EXPORTS) + else() + add_definitions(-DOPJ_STATIC) + endif() +endif() +add_library(${OPENJPEG_LIBRARY_NAME}_JPWL ${JPWL_SRCS} ${OPJ_SRCS}) +set_target_properties(${OPENJPEG_LIBRARY_NAME}_JPWL PROPERTIES ${OPENJPEG_LIBRARY_PROPERTIES}) + +# Install library +install(TARGETS ${OPENJPEG_LIBRARY_NAME}_JPWL + DESTINATION ${OPENJPEG_INSTALL_LIB_DIR} COMPONENT Libraries +) + +# Build executables + +include_directories( + ${OPENJPEG_SOURCE_DIR}/libopenjpeg + ${OPENJPEG_SOURCE_DIR}/common + ) + +if(LCMS_INCLUDE_DIR) + include_directories( ${LCMS_INCLUDE_DIR} ) +endif() +if(PNG_FOUND) + include_directories(${PNG_INCLUDE_DIR}) +endif() +if(TIFF_FOUND) + include_directories(${TIFF_INCLUDE_DIR}) +endif() + + +add_executable(JPWL_j2k_to_image +../codec/j2k_to_image.c +../codec/convert.c +../codec/index.c +${OPENJPEG_SOURCE_DIR}/common/color.c +${common_SRCS} +) + +target_link_libraries(JPWL_j2k_to_image ${OPENJPEG_LIBRARY_NAME}_JPWL ${LCMS_LIB}) +if(PNG_FOUND) + target_link_libraries(JPWL_j2k_to_image ${PNG_LIBRARIES}) +endif() +if(TIFF_FOUND) + target_link_libraries(JPWL_j2k_to_image ${TIFF_LIBRARIES}) +endif() +if(UNIX) + target_link_libraries(JPWL_j2k_to_image m) +endif() + + +add_executable(JPWL_image_to_j2k +../codec/convert.c +../codec/index.c +../codec/image_to_j2k.c +${common_SRCS} +) + +target_link_libraries(JPWL_image_to_j2k ${OPENJPEG_LIBRARY_NAME}_JPWL ${LCMS_LIB}) +if(PNG_FOUND) + target_link_libraries(JPWL_image_to_j2k ${PNG_LIBRARIES}) +endif() +if(TIFF_FOUND) + target_link_libraries(JPWL_image_to_j2k ${TIFF_LIBRARIES}) +endif() +if(UNIX) + target_link_libraries(JPWL_image_to_j2k m) +endif() + +install(TARGETS JPWL_image_to_j2k JPWL_j2k_to_image + DESTINATION ${OPENJPEG_INSTALL_BIN_DIR} COMPONENT Binaries +) diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jpwl/JPWL_image_to_j2k.dsp b/gdcm/Utilities/gdcmopenjpeg-v1/jpwl/JPWL_image_to_j2k.dsp new file mode 100644 index 0000000..91bfd49 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jpwl/JPWL_image_to_j2k.dsp @@ -0,0 +1,127 @@ +# Microsoft Developer Studio Project File - Name="JPWL_image_to_j2k" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=JPWL_image_to_j2k - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "JPWL_image_to_j2k.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "JPWL_image_to_j2k.mak" CFG="JPWL_image_to_j2k - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "JPWL_image_to_j2k - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "JPWL_image_to_j2k - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "JPWL_image_to_j2k - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "../libopenjpeg" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "OPJ_STATIC" /D "USE_JPWL" /D "USE_JPSEC" /FR /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x80c /d "NDEBUG" +# ADD RSC /l 0x80c /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib LibOpenJPEG_JPWL.lib ../libs/libtiff/libtiff.lib /nologo /subsystem:console /machine:I386 /libpath:"Release" + +!ELSEIF "$(CFG)" == "JPWL_image_to_j2k - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../libopenjpeg" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "OPJ_STATIC" /D "USE_JPWL" /D "USE_JPSEC" /FR /FD /GZ /c +# ADD BASE RSC /l 0x80c /d "_DEBUG" +# ADD RSC /l 0x80c /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib LibOpenJPEG_JPWLd.lib ../libs/libtiff/libtiff.lib /nologo /subsystem:console /debug /machine:I386 /nodefaultlib:"libcmtd.lib" /pdbtype:sept /libpath:"Debug" + +!ENDIF + +# Begin Target + +# Name "JPWL_image_to_j2k - Win32 Release" +# Name "JPWL_image_to_j2k - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\codec\convert.c +# End Source File +# Begin Source File + +SOURCE=..\codec\compat\getopt.c +# End Source File +# Begin Source File + +SOURCE=..\codec\image_to_j2k.c +# End Source File +# Begin Source File + +SOURCE=..\codec\index.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\codec\convert.h +# End Source File +# Begin Source File + +SOURCE=..\codec\compat\getopt.h +# End Source File +# Begin Source File + +SOURCE=..\codec\index.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\openjpeg.h +# End Source File +# End Group +# End Target +# End Project diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jpwl/JPWL_image_to_j2k.dsw b/gdcm/Utilities/gdcmopenjpeg-v1/jpwl/JPWL_image_to_j2k.dsw new file mode 100644 index 0000000..1b03661 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jpwl/JPWL_image_to_j2k.dsw @@ -0,0 +1,44 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "JPWL_image_to_j2k"=".\JPWL_image_to_j2k.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name LibOpenJPEG_JPWL + End Project Dependency +}}} + +############################################################################### + +Project: "LibOpenJPEG_JPWL"=".\LibOpenJPEG_JPWL.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jpwl/JPWL_j2k_to_image.dsp b/gdcm/Utilities/gdcmopenjpeg-v1/jpwl/JPWL_j2k_to_image.dsp new file mode 100644 index 0000000..15276e2 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jpwl/JPWL_j2k_to_image.dsp @@ -0,0 +1,135 @@ +# Microsoft Developer Studio Project File - Name="JPWL_j2k_to_image" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=JPWL_j2k_to_image - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "JPWL_j2k_to_image.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "JPWL_j2k_to_image.mak" CFG="JPWL_j2k_to_image - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "JPWL_j2k_to_image - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "JPWL_j2k_to_image - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "JPWL_j2k_to_image - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "../libopenjpeg" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "OPJ_STATIC" /D "USE_JPWL" /D "USE_JPSEC" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x80c /d "NDEBUG" +# ADD RSC /l 0x80c /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ../libs/libtiff/libtiff.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "JPWL_j2k_to_image - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "JPWL_j2k_to_image___Win32_Debug" +# PROP BASE Intermediate_Dir "JPWL_j2k_to_image___Win32_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../libopenjpeg" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "OPJ_STATIC" /D "USE_JPWL" /D "USE_JPSEC" /YX /FD /GZ /c +# ADD BASE RSC /l 0x80c /d "_DEBUG" +# ADD RSC /l 0x80c /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ../libs/libtiff/libtiff.lib /nologo /subsystem:console /debug /machine:I386 /nodefaultlib:"libcmtd.lib" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "JPWL_j2k_to_image - Win32 Release" +# Name "JPWL_j2k_to_image - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\codec\convert.c +# End Source File +# Begin Source File + +SOURCE=..\codec\compat\getopt.c +# End Source File +# Begin Source File + +SOURCE=..\codec\index.c +# End Source File +# Begin Source File + +SOURCE=..\codec\j2k_to_image.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\codec\convert.h +# End Source File +# Begin Source File + +SOURCE=.\crc.h +# End Source File +# Begin Source File + +SOURCE=..\codec\compat\getopt.h +# End Source File +# Begin Source File + +SOURCE=..\codec\index.h +# End Source File +# Begin Source File + +SOURCE=.\jpwl.h +# End Source File +# Begin Source File + +SOURCE=.\rs.h +# End Source File +# End Group +# End Target +# End Project diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jpwl/JPWL_j2k_to_image.dsw b/gdcm/Utilities/gdcmopenjpeg-v1/jpwl/JPWL_j2k_to_image.dsw new file mode 100644 index 0000000..bc06a72 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jpwl/JPWL_j2k_to_image.dsw @@ -0,0 +1,44 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "JPWL_j2k_to_image"=".\JPWL_j2k_to_image.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name LibOpenJPEG_JPWL + End Project Dependency +}}} + +############################################################################### + +Project: "LibOpenJPEG_JPWL"=".\LibOpenJPEG_JPWL.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jpwl/LibOpenJPEG_JPWL.dsp b/gdcm/Utilities/gdcmopenjpeg-v1/jpwl/LibOpenJPEG_JPWL.dsp new file mode 100644 index 0000000..9293c16 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jpwl/LibOpenJPEG_JPWL.dsp @@ -0,0 +1,282 @@ +# Microsoft Developer Studio Project File - Name="LibOpenJPEG_JPWL" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=LibOpenJPEG_JPWL - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "LibOpenJPEG_JPWL.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "LibOpenJPEG_JPWL.mak" CFG="LibOpenJPEG_JPWL - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "LibOpenJPEG_JPWL - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "LibOpenJPEG_JPWL - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "LibOpenJPEG_JPWL - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "LibOpenJPEG_JPWL___Win32_Release" +# PROP BASE Intermediate_Dir "LibOpenJPEG_JPWL___Win32_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "../libopenjpeg" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "OPJ_STATIC" /D "USE_JPWL" /D "USE_JPSEC" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x80c /d "NDEBUG" +# ADD RSC /l 0x80c /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "LibOpenJPEG_JPWL - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "LibOpenJPEG_JPWL___Win32_Debug" +# PROP BASE Intermediate_Dir "LibOpenJPEG_JPWL___Win32_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../libopenjpeg" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /D "OPJ_STATIC" /D "USE_JPWL" /D "USE_JPSEC" /FD /GZ /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x80c /d "_DEBUG" +# ADD RSC /l 0x80c /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"Debug\LibOpenJPEG_JPWLd.lib" + +!ENDIF + +# Begin Target + +# Name "LibOpenJPEG_JPWL - Win32 Release" +# Name "LibOpenJPEG_JPWL - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\libopenjpeg\bio.c +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\cio.c +# End Source File +# Begin Source File + +SOURCE=.\crc.c +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\dwt.c +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\event.c +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\image.c +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\j2k.c +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\j2k_lib.c +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\jp2.c +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\jpt.c +# End Source File +# Begin Source File + +SOURCE=.\jpwl.c +# End Source File +# Begin Source File + +SOURCE=.\jpwl_lib.c +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\mct.c +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\mqc.c +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\openjpeg.c +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\pi.c +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\raw.c +# End Source File +# Begin Source File + +SOURCE=.\rs.c +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\t1.c +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\t2.c +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\tcd.c +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\tgt.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\libopenjpeg\bio.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\cio.h +# End Source File +# Begin Source File + +SOURCE=.\crc.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\dwt.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\event.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\fix.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\image.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\int.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\j2k.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\j2k_lib.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\jp2.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\jpt.h +# End Source File +# Begin Source File + +SOURCE=.\jpwl.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\mct.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\mqc.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\openjpeg.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\opj_includes.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\opj_malloc.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\pi.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\raw.h +# End Source File +# Begin Source File + +SOURCE=.\rs.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\t1.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\t2.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\tcd.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\tgt.h +# End Source File +# End Group +# End Target +# End Project diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jpwl/README.txt b/gdcm/Utilities/gdcmopenjpeg-v1/jpwl/README.txt new file mode 100644 index 0000000..e289e9e --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jpwl/README.txt @@ -0,0 +1,136 @@ +=============================================================================== + JPEG2000 Part 11 (ISO/IEC 15444-11 JPWL) Software + + + + Version 20061213 +=============================================================================== + + + + + +1. Scope +============= + +This document describes the installation and use of the JPWL module in the framework of OpenJPEG library. + +This implementation has been developed from OpenJPEG implementation of JPEG2000 standard, and for this reason it is written in C language. + +If you find some bugs or if you have problems using the encoder/decoder, please send an e-mail to jpwl@diei.unipg.it + + +2. Installing the code +========================== + +The JPWL code is integrated with the standard OpenJPEG library and codecs: it is activated by setting the macro USE_JPWL to defined in the preprocessor configuration options of your preferred C compiler. + +2.1. Compiling the source code in Windows +------------------------------------------- + +The "jpwl" directory is already populated with a couple of Visual C++ 6.0 workspaces + + * JPWL_image_to_j2k.dsw - Creates the encoder with JPWL functionalities + * JPWL_j2k_to_image.dsw - Creates the decoder with JPWL functionalities + +2.2. Compiling the source code in Unix-like systems +----------------------------------------------------- + +Under linux, enter the jpwl directory and type "make clean" and "make". + + +3. Running the JPWL software +========================= + +The options available at the command line are exactly the same of the base OpenJPEG codecs. In addition, there is a "-W" switch that activates JPWL functionalities. + +3.1. JPWL Encoder +------------------- + +-W : adoption of JPWL (Part 11) capabilities (-W params) + The parameters can be written and repeated in any order: + [h<=type>,s<=method>,a=,z=,g=,... + ...,p<=type>] + + h selects the header error protection (EPB): 'type' can be + [0=none 1,absent=predefined 16=CRC-16 32=CRC-32 37-128=RS] + if 'tile' is absent, it applies to main and tile headers + if 'tile' is present, it applies from that tile + onwards, up to the next h spec, or to the last tile + in the codestream (max. 16 specs) + + p selects the packet error protection (EEP/UEP with EPBs) + to be applied to raw data: 'type' can be + [0=none 1,absent=predefined 16=CRC-16 32=CRC-32 37-128=RS] + if 'tile:pack' is absent, it starts from tile 0, packet 0 + if 'tile:pack' is present, it applies from that tile + and that packet onwards, up to the next packet spec + or to the last packet in the last tile in the codestream + (max. 16 specs) + + s enables sensitivity data insertion (ESD): 'method' can be + [-1=NO ESD 0=RELATIVE ERROR 1=MSE 2=MSE REDUCTION 3=PSNR + 4=PSNR INCREMENT 5=MAXERR 6=TSE 7=RESERVED] + if 'tile' is absent, it applies to main header only + if 'tile' is present, it applies from that tile + onwards, up to the next s spec, or to the last tile + in the codestream (max. 16 specs) + + g determines the addressing mode: can be + [0=PACKET 1=BYTE RANGE 2=PACKET RANGE] + + a determines the size of data addressing: can be + 2/4 bytes (small/large codestreams). If not set, auto-mode + + z determines the size of sensitivity values: can be + 1/2 bytes, for the transformed pseudo-floating point value + + ex.: + h,h0=64,h3=16,h5=32,p0=78,p0:24=56,p1,p3:0=0,p3:20=32,s=0,s0=6,s3=-1,a=0,g=1,z=1 + means + predefined EPB in MH, rs(64,32) from TPH 0 to TPH 2, + CRC-16 in TPH 3 and TPH 4, CRC-32 in remaining TPHs, + UEP rs(78,32) for packets 0 to 23 of tile 0, + UEP rs(56,32) for packets 24 to the last of tile 0, + UEP rs default for packets of tile 1, + no UEP for packets 0 to 19 of tile 3, + UEP CRC-32 for packets 20 of tile 3 to last tile, + relative sensitivity ESD for MH, + TSE ESD from TPH 0 to TPH 2, byte range with automatic + size of addresses and 1 byte for each sensitivity value + + ex.: + h,s,p + means + default protection to headers (MH and TPHs) as well as + data packets, one ESD in MH + + N.B.: use the following recommendations when specifying + the JPWL parameters list + - when you use UEP, always pair the 'p' option with 'h' + +3.2. JPWL Decoder +------------------- + + -W + Activates the JPWL correction capability, if the codestream complies. + Options can be a comma separated list of tokens: + c, c=numcomps + numcomps is the number of expected components in the codestream + (search of first EPB rely upon this, default is 3) + + +4. Known bugs and limitations +=============================== + +4.1. Bugs +----------- + +* It is not possible to save a JPWL encoded codestream using the wrapped file format (i.e. JP2): only raw file format (i.e. J2K) is working + +4.2. Limitations +------------------ + +* When specifying an UEP protection, you need to activate even TPH protection for those tiles where there is a protection of the packets +* RED insertion is not currently implemented at the decoder +* JPWL at entropy coding level is not implemented diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jpwl/crc.c b/gdcm/Utilities/gdcmopenjpeg-v1/jpwl/crc.c new file mode 100644 index 0000000..4a831eb --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jpwl/crc.c @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * Copyright (c) 2005-2006, Dept. of Electronic and Information Engineering, Universita' degli Studi di Perugia, Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef USE_JPWL + +#include "crc.h" + +/** +@file crc.c +@brief Functions used to compute the 16- and 32-bit CRC of byte arrays + +*/ + +/** file: CRC16.CPP + * + * CRC - Cyclic Redundancy Check (16-bit) + * + * A CRC-checksum is used to be sure, the data hasn't changed or is false. + * To create a CRC-checksum, initialise a check-variable (unsigned short), + * and set this to zero. Than call for every byte in the file (e.g.) the + * procedure updateCRC16 with this check-variable as the first parameter, + * and the byte as the second. At the end, the check-variable contains the + * CRC-checksum. + * + * implemented by Michael Neumann, 14.06.1998 + * + */ +const unsigned short CRC16_table[256] = { + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, + 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, + 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, + 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, + 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, + 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, + 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, + 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 +}; + +void updateCRC16(unsigned short *crc, unsigned char data) { + *crc = CRC16_table[(*crc >> 8) & 0xFF] ^ (*crc << 8) ^ data; +}; + + +/** file: CRC32.CPP + * + * CRC - Cyclic Redundancy Check (32-bit) + * + * A CRC-checksum is used to be sure, the data hasn't changed or is false. + * To create a CRC-checksum, initialise a check-variable (unsigned long), + * and set this to zero. Than call for every byte in the file (e.g.) the + * procedure updateCRC32 with this check-variable as the first parameter, + * and the byte as the second. At the end, the check-variable contains the + * CRC-checksum. + * + * implemented by Michael Neumann, 14.06.1998 + * + */ +const unsigned long CRC32_table[256] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + +void updateCRC32(unsigned long *crc, unsigned char data) { + *crc = CRC32_table[(unsigned char) *crc ^ data] ^ ((*crc >> 8) & 0x00FFFFFF); +}; + +#endif /* USE_JPWL */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jpwl/crc.h b/gdcm/Utilities/gdcmopenjpeg-v1/jpwl/crc.h new file mode 100644 index 0000000..2d87168 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jpwl/crc.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * Copyright (c) 2005-2006, Dept. of Electronic and Information Engineering, Universita' degli Studi di Perugia, Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef USE_JPWL + +/** +@file crc.h +@brief Functions used to compute the 16- and 32-bit CRC of byte arrays + +*/ + +#ifndef __CRC16_HEADER__ +#define __CRC16_HEADER__ + +/** file: CRC16.HPP + * + * CRC - Cyclic Redundancy Check (16-bit) + * + * A CRC-checksum is used to be sure, the data hasn't changed or is false. + * To create a CRC-checksum, initialise a check-variable (unsigned short), + * and set this to zero. Than call for every byte in the file (e.g.) the + * procedure updateCRC16 with this check-variable as the first parameter, + * and the byte as the second. At the end, the check-variable contains the + * CRC-checksum. + * + * implemented by Michael Neumann, 14.06.1998 + * + */ +void updateCRC16(unsigned short *, unsigned char); + +#endif /* __CRC16_HEADER__ */ + + +#ifndef __CRC32_HEADER__ +#define __CRC32_HEADER__ + +/** file: CRC32.HPP + * + * CRC - Cyclic Redundancy Check (32-bit) + * + * A CRC-checksum is used to be sure, the data hasn't changed or is false. + * To create a CRC-checksum, initialise a check-variable (unsigned short), + * and set this to zero. Than call for every byte in the file (e.g.) the + * procedure updateCRC32 with this check-variable as the first parameter, + * and the byte as the second. At the end, the check-variable contains the + * CRC-checksum. + * + * implemented by Michael Neumann, 14.06.1998 + * + */ +void updateCRC32(unsigned long *, unsigned char); + +#endif /* __CRC32_HEADER__ */ + + +#endif /* USE_JPWL */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jpwl/jpwl.c b/gdcm/Utilities/gdcmopenjpeg-v1/jpwl/jpwl.c new file mode 100644 index 0000000..92557c2 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jpwl/jpwl.c @@ -0,0 +1,1357 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * Copyright (c) 2005-2006, Dept. of Electronic and Information Engineering, Universita' degli Studi di Perugia, Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "../libopenjpeg/opj_includes.h" + +#ifdef USE_JPWL + +/** @defgroup JPWL JPWL - JPEG-2000 Part11 (JPWL) codestream manager */ +/*@{*/ + +/** @name Local static variables */ +/*@{*/ + +/** number of JPWL prepared markers */ +static int jwmarker_num; +/** properties of JPWL markers to insert */ +static jpwl_marker_t jwmarker[JPWL_MAX_NO_MARKERS]; + +/*@}*/ + +/*@}*/ + +/** @name Local static functions */ +/*@{*/ + +/** create an EPC marker segment +@param j2k J2K compressor handle +@param esd_on true if ESD is activated +@param red_on true if RED is activated +@param epb_on true if EPB is activated +@param info_on true if informative techniques are activated +@return returns the freshly created EPC +*/ +jpwl_epc_ms_t *jpwl_epc_create(opj_j2k_t *j2k, bool esd_on, bool red_on, bool epb_on, bool info_on); + +/*@}*/ + +/** create an EPC marker segment +@param j2k J2K compressor handle +@param comps considered component (-1=average, 0/1/2/...=component no.) +@param addrm addressing mode (0=packet, 1=byte range, 2=packet range, 3=reserved) +@param ad_size size of addresses (2/4 bytes) +@param senst sensitivity type +@param se_size sensitivity values size (1/2 bytes) +@param tileno tile where this ESD lies (-1 means MH) +@param svalnum number of sensitivity values (if 0, they will be automatically filled) +@param sensval pointer to an array of sensitivity values (if NULL, they will be automatically filled) +@return returns the freshly created ESD +*/ +jpwl_esd_ms_t *jpwl_esd_create(opj_j2k_t *j2k, int comps, unsigned char addrm, unsigned char ad_size, + unsigned char senst, int se_size, int tileno, + unsigned long int svalnum, void *sensval); + +/** this function is used to compare two JPWL markers based on +their relevant wishlist position +@param arg1 pointer to first marker +@param arg2 pointer to second marker +@return 1 if arg1>arg2, 0 if arg1=arg2, -1 if arg1pos_correction = 0; + +} + +void j2k_add_marker(opj_codestream_info_t *cstr_info, unsigned short int type, int pos, int len) { + + if (!cstr_info) + return; + + /* expand the list? */ + if ((cstr_info->marknum + 1) > cstr_info->maxmarknum) { + cstr_info->maxmarknum = 100 + (int) ((float) cstr_info->maxmarknum * 1.0F); + cstr_info->marker = opj_realloc(cstr_info->marker, cstr_info->maxmarknum); + } + + /* add the marker */ + cstr_info->marker[cstr_info->marknum].type = type; + cstr_info->marker[cstr_info->marknum].pos = pos; + cstr_info->marker[cstr_info->marknum].len = len; + cstr_info->marknum++; + +} + +void jpwl_prepare_marks(opj_j2k_t *j2k, opj_cio_t *cio, opj_image_t *image) { + + unsigned short int socsiz_len = 0; + int ciopos = cio_tell(cio), soc_pos = j2k->cstr_info->main_head_start; + unsigned char *socp = NULL; + + int tileno, acc_tpno, tpno, tilespec, hprot, sens, pprot, packspec, lastileno, packno; + + jpwl_epb_ms_t *epb_mark; + jpwl_epc_ms_t *epc_mark; + jpwl_esd_ms_t *esd_mark; + + /* find (SOC + SIZ) length */ + /* I assume SIZ is always the first marker after SOC */ + cio_seek(cio, soc_pos + 4); + socsiz_len = (unsigned short int) cio_read(cio, 2) + 4; /* add the 2 marks length itself */ + cio_seek(cio, soc_pos + 0); + socp = cio_getbp(cio); /* pointer to SOC */ + + /* + EPC MS for Main Header: if we are here it's required + */ + /* create the EPC */ + if ((epc_mark = jpwl_epc_create( + j2k, + j2k->cp->esd_on, /* is ESD present? */ + j2k->cp->red_on, /* is RED present? */ + j2k->cp->epb_on, /* is EPB present? */ + false /* are informative techniques present? */ + ))) { + + /* Add this marker to the 'insertanda' list */ + if (epc_mark) { + jwmarker[jwmarker_num].id = J2K_MS_EPC; /* its type */ + jwmarker[jwmarker_num].m.epcmark = epc_mark; /* the EPC */ + jwmarker[jwmarker_num].pos = soc_pos + socsiz_len; /* after SIZ */ + jwmarker[jwmarker_num].dpos = (double) jwmarker[jwmarker_num].pos + 0.1; /* not so first */ + jwmarker[jwmarker_num].len = epc_mark->Lepc; /* its length */ + jwmarker[jwmarker_num].len_ready = true; /* ready */ + jwmarker[jwmarker_num].pos_ready = true; /* ready */ + jwmarker[jwmarker_num].parms_ready = false; /* not ready */ + jwmarker[jwmarker_num].data_ready = true; /* ready */ + jwmarker_num++; + }; + + opj_event_msg(j2k->cinfo, EVT_INFO, + "MH EPC : setting %s%s%s\n", + j2k->cp->esd_on ? "ESD, " : "", + j2k->cp->red_on ? "RED, " : "", + j2k->cp->epb_on ? "EPB, " : "" + ); + + } else { + /* ooops, problems */ + opj_event_msg(j2k->cinfo, EVT_ERROR, "Could not create MH EPC\n"); + }; + + /* + ESD MS for Main Header + */ + /* first of all, must MH have an ESD MS? */ + if (j2k->cp->esd_on && (j2k->cp->sens_MH >= 0)) { + + /* Create the ESD */ + if ((esd_mark = jpwl_esd_create( + j2k, /* this encoder handle */ + -1, /* we are averaging over all components */ + (unsigned char) j2k->cp->sens_range, /* range method */ + (unsigned char) j2k->cp->sens_addr, /* sensitivity addressing */ + (unsigned char) j2k->cp->sens_MH, /* sensitivity method */ + j2k->cp->sens_size, /* sensitivity size */ + -1, /* this ESD is in main header */ + 0 /*j2k->cstr_info->num*/, /* number of packets in codestream */ + NULL /*sensval*/ /* pointer to sensitivity data of packets */ + ))) { + + /* Add this marker to the 'insertanda' list */ + if (jwmarker_num < JPWL_MAX_NO_MARKERS) { + jwmarker[jwmarker_num].id = J2K_MS_ESD; /* its type */ + jwmarker[jwmarker_num].m.esdmark = esd_mark; /* the EPB */ + jwmarker[jwmarker_num].pos = soc_pos + socsiz_len; /* we choose to place it after SIZ */ + jwmarker[jwmarker_num].dpos = (double) jwmarker[jwmarker_num].pos + 0.2; /* not first at all! */ + jwmarker[jwmarker_num].len = esd_mark->Lesd; /* its length */ + jwmarker[jwmarker_num].len_ready = true; /* not ready, yet */ + jwmarker[jwmarker_num].pos_ready = true; /* ready */ + jwmarker[jwmarker_num].parms_ready = true; /* not ready */ + jwmarker[jwmarker_num].data_ready = false; /* not ready */ + jwmarker_num++; + } + + opj_event_msg(j2k->cinfo, EVT_INFO, + "MH ESDs: method %d\n", + j2k->cp->sens_MH + ); + + } else { + /* ooops, problems */ + opj_event_msg(j2k->cinfo, EVT_ERROR, "Could not create MH ESD\n"); + }; + + } + + /* + ESD MSs for Tile Part Headers + */ + /* cycle through tiles */ + sens = -1; /* default spec: no ESD */ + tilespec = 0; /* first tile spec */ + acc_tpno = 0; + for (tileno = 0; tileno < j2k->cstr_info->tw * j2k->cstr_info->th; tileno++) { + + opj_event_msg(j2k->cinfo, EVT_INFO, + "Tile %d has %d tile part(s)\n", + tileno, j2k->cstr_info->tile[tileno].num_tps + ); + + /* for every tile part in the tile */ + for (tpno = 0; tpno < j2k->cstr_info->tile[tileno].num_tps; tpno++, acc_tpno++) { + + int sot_len, Psot, Psotp, mm; + unsigned long sot_pos, post_sod_pos; + + unsigned long int left_THmarks_len; + + /******* sot_pos = j2k->cstr_info->tile[tileno].start_pos; */ + sot_pos = j2k->cstr_info->tile[tileno].tp[tpno].tp_start_pos; + cio_seek(cio, sot_pos + 2); + sot_len = cio_read(cio, 2); /* SOT Len */ + cio_skip(cio, 2); + Psotp = cio_tell(cio); + Psot = cio_read(cio, 4); /* tile length */ + + /******* post_sod_pos = j2k->cstr_info->tile[tileno].end_header + 1; */ + post_sod_pos = j2k->cstr_info->tile[tileno].tp[tpno].tp_end_header + 1; + left_THmarks_len = post_sod_pos - sot_pos; + + /* add all the lengths of the markers which are len-ready and stay within SOT and SOD */ + for (mm = 0; mm < jwmarker_num; mm++) { + if ((jwmarker[mm].pos >= sot_pos) && (jwmarker[mm].pos < post_sod_pos)) { + if (jwmarker[mm].len_ready) + left_THmarks_len += jwmarker[mm].len + 2; + else { + opj_event_msg(j2k->cinfo, EVT_ERROR, "MS %x in %f is not len-ready: could not set up TH EPB\n", + jwmarker[mm].id, jwmarker[mm].dpos); + exit(1); + } + } + } + + /******* if ((tilespec < JPWL_MAX_NO_TILESPECS) && (j2k->cp->sens_TPH_tileno[tilespec] == tileno)) */ + if ((tilespec < JPWL_MAX_NO_TILESPECS) && (j2k->cp->sens_TPH_tileno[tilespec] == acc_tpno)) + /* we got a specification from this tile onwards */ + sens = j2k->cp->sens_TPH[tilespec++]; + + /* must this TPH have an ESD MS? */ + if (j2k->cp->esd_on && (sens >= 0)) { + + /* Create the ESD */ + if ((esd_mark = jpwl_esd_create( + j2k, /* this encoder handle */ + -1, /* we are averaging over all components */ + (unsigned char) j2k->cp->sens_range, /* range method */ + (unsigned char) j2k->cp->sens_addr, /* sensitivity addressing size */ + (unsigned char) sens, /* sensitivity method */ + j2k->cp->sens_size, /* sensitivity value size */ + tileno, /* this ESD is in a tile */ + 0, /* number of packets in codestream */ + NULL /* pointer to sensitivity data of packets */ + ))) { + + /* Add this marker to the 'insertanda' list */ + if (jwmarker_num < JPWL_MAX_NO_MARKERS) { + jwmarker[jwmarker_num].id = J2K_MS_ESD; /* its type */ + jwmarker[jwmarker_num].m.esdmark = esd_mark; /* the EPB */ + /****** jwmarker[jwmarker_num].pos = j2k->cstr_info->tile[tileno].start_pos + sot_len + 2; */ /* after SOT */ + jwmarker[jwmarker_num].pos = j2k->cstr_info->tile[tileno].tp[tpno].tp_start_pos + sot_len + 2; /* after SOT */ + jwmarker[jwmarker_num].dpos = (double) jwmarker[jwmarker_num].pos + 0.2; /* not first at all! */ + jwmarker[jwmarker_num].len = esd_mark->Lesd; /* its length */ + jwmarker[jwmarker_num].len_ready = true; /* ready, yet */ + jwmarker[jwmarker_num].pos_ready = true; /* ready */ + jwmarker[jwmarker_num].parms_ready = true; /* not ready */ + jwmarker[jwmarker_num].data_ready = false; /* ready */ + jwmarker_num++; + } + + /* update Psot of the tile */ + cio_seek(cio, Psotp); + cio_write(cio, Psot + esd_mark->Lesd + 2, 4); + + opj_event_msg(j2k->cinfo, EVT_INFO, + /******* "TPH ESDs: tile %02d, method %d\n", */ + "TPH ESDs: tile %02d, part %02d, method %d\n", + /******* tileno, */ + tileno, tpno, + sens + ); + + } else { + /* ooops, problems */ + /***** opj_event_msg(j2k->cinfo, EVT_ERROR, "Could not create TPH ESD #%d\n", tileno); */ + opj_event_msg(j2k->cinfo, EVT_ERROR, "Could not create TPH ESD #%d,%d\n", tileno, tpno); + }; + + } + + } + + }; + + /* + EPB MS for Main Header + */ + /* first of all, must MH have an EPB MS? */ + if (j2k->cp->epb_on && (j2k->cp->hprot_MH > 0)) { + + int mm; + + /* position of SOT */ + unsigned int sot_pos = j2k->cstr_info->main_head_end + 1; + + /* how much space is there between end of SIZ and beginning of SOT? */ + int left_MHmarks_len = sot_pos - socsiz_len; + + /* add all the lengths of the markers which are len-ready and stay within SOC and SOT */ + for (mm = 0; mm < jwmarker_num; mm++) { + if ((jwmarker[mm].pos >=0) && (jwmarker[mm].pos < sot_pos)) { + if (jwmarker[mm].len_ready) + left_MHmarks_len += jwmarker[mm].len + 2; + else { + opj_event_msg(j2k->cinfo, EVT_ERROR, "MS %x in %f is not len-ready: could not set up MH EPB\n", + jwmarker[mm].id, jwmarker[mm].dpos); + exit(1); + } + } + } + + /* Create the EPB */ + if ((epb_mark = jpwl_epb_create( + j2k, /* this encoder handle */ + true, /* is it the latest? */ + true, /* is it packed? not for now */ + -1, /* we are in main header */ + 0, /* its index is 0 (first) */ + j2k->cp->hprot_MH, /* protection type parameters of data */ + socsiz_len, /* pre-data: only SOC+SIZ */ + left_MHmarks_len /* post-data: from SOC to SOT, and all JPWL markers within */ + ))) { + + /* Add this marker to the 'insertanda' list */ + if (jwmarker_num < JPWL_MAX_NO_MARKERS) { + jwmarker[jwmarker_num].id = J2K_MS_EPB; /* its type */ + jwmarker[jwmarker_num].m.epbmark = epb_mark; /* the EPB */ + jwmarker[jwmarker_num].pos = soc_pos + socsiz_len; /* after SIZ */ + jwmarker[jwmarker_num].dpos = (double) jwmarker[jwmarker_num].pos; /* first first first! */ + jwmarker[jwmarker_num].len = epb_mark->Lepb; /* its length */ + jwmarker[jwmarker_num].len_ready = true; /* ready */ + jwmarker[jwmarker_num].pos_ready = true; /* ready */ + jwmarker[jwmarker_num].parms_ready = true; /* ready */ + jwmarker[jwmarker_num].data_ready = false; /* not ready */ + jwmarker_num++; + } + + opj_event_msg(j2k->cinfo, EVT_INFO, + "MH EPB : prot. %d\n", + j2k->cp->hprot_MH + ); + + } else { + /* ooops, problems */ + opj_event_msg(j2k->cinfo, EVT_ERROR, "Could not create MH EPB\n"); + }; + } + + /* + EPB MSs for Tile Parts + */ + /* cycle through TPHs */ + hprot = j2k->cp->hprot_MH; /* default spec */ + tilespec = 0; /* first tile spec */ + lastileno = 0; + packspec = 0; + pprot = -1; + acc_tpno = 0; + for (tileno = 0; tileno < j2k->cstr_info->tw * j2k->cstr_info->th; tileno++) { + + opj_event_msg(j2k->cinfo, EVT_INFO, + "Tile %d has %d tile part(s)\n", + tileno, j2k->cstr_info->tile[tileno].num_tps + ); + + /* for every tile part in the tile */ + for (tpno = 0; tpno < j2k->cstr_info->tile[tileno].num_tps; tpno++, acc_tpno++) { + + int sot_len, Psot, Psotp, mm, epb_index = 0, prot_len = 0; + unsigned long sot_pos, post_sod_pos; + unsigned long int left_THmarks_len/*, epbs_len = 0*/; + int startpack = 0, stoppack = j2k->cstr_info->packno; + int first_tp_pack, last_tp_pack; + jpwl_epb_ms_t *tph_epb = NULL; + + /****** sot_pos = j2k->cstr_info->tile[tileno].start_pos; */ + sot_pos = j2k->cstr_info->tile[tileno].tp[tpno].tp_start_pos; + cio_seek(cio, sot_pos + 2); + sot_len = cio_read(cio, 2); /* SOT Len */ + cio_skip(cio, 2); + Psotp = cio_tell(cio); + Psot = cio_read(cio, 4); /* tile length */ + + /* a-priori length of the data dwelling between SOT and SOD */ + /****** post_sod_pos = j2k->cstr_info->tile[tileno].end_header + 1; */ + post_sod_pos = j2k->cstr_info->tile[tileno].tp[tpno].tp_end_header + 1; + left_THmarks_len = post_sod_pos - (sot_pos + sot_len + 2); + + /* add all the lengths of the JPWL markers which are len-ready and stay within SOT and SOD */ + for (mm = 0; mm < jwmarker_num; mm++) { + if ((jwmarker[mm].pos >= sot_pos) && (jwmarker[mm].pos < post_sod_pos)) { + if (jwmarker[mm].len_ready) + left_THmarks_len += jwmarker[mm].len + 2; + else { + opj_event_msg(j2k->cinfo, EVT_ERROR, "MS %x in %f is not len-ready: could not set up TH EPB\n", + jwmarker[mm].id, jwmarker[mm].dpos); + exit(1); + } + } + } + + /****** if ((tilespec < JPWL_MAX_NO_TILESPECS) && (j2k->cp->hprot_TPH_tileno[tilespec] == tileno)) */ + if ((tilespec < JPWL_MAX_NO_TILESPECS) && (j2k->cp->hprot_TPH_tileno[tilespec] == acc_tpno)) + /* we got a specification from this tile part onwards */ + hprot = j2k->cp->hprot_TPH[tilespec++]; + + /* must this TPH have an EPB MS? */ + if (j2k->cp->epb_on && (hprot > 0)) { + + /* Create the EPB */ + if ((epb_mark = jpwl_epb_create( + j2k, /* this encoder handle */ + false, /* is it the latest? in TPH, no for now (if huge data size in TPH, we'd need more) */ + true, /* is it packed? yes for now */ + tileno, /* we are in TPH */ + epb_index++, /* its index is 0 (first) */ + hprot, /* protection type parameters of following data */ + sot_len + 2, /* pre-data length: only SOT */ + left_THmarks_len /* post-data length: from SOT end to SOD inclusive */ + ))) { + + /* Add this marker to the 'insertanda' list */ + if (jwmarker_num < JPWL_MAX_NO_MARKERS) { + jwmarker[jwmarker_num].id = J2K_MS_EPB; /* its type */ + jwmarker[jwmarker_num].m.epbmark = epb_mark; /* the EPB */ + /****** jwmarker[jwmarker_num].pos = j2k->cstr_info->tile[tileno].start_pos + sot_len + 2; */ /* after SOT */ + jwmarker[jwmarker_num].pos = j2k->cstr_info->tile[tileno].tp[tpno].tp_start_pos + sot_len + 2; /* after SOT */ + jwmarker[jwmarker_num].dpos = (double) jwmarker[jwmarker_num].pos; /* first first first! */ + jwmarker[jwmarker_num].len = epb_mark->Lepb; /* its length */ + jwmarker[jwmarker_num].len_ready = true; /* ready */ + jwmarker[jwmarker_num].pos_ready = true; /* ready */ + jwmarker[jwmarker_num].parms_ready = true; /* ready */ + jwmarker[jwmarker_num].data_ready = false; /* not ready */ + jwmarker_num++; + } + + /* update Psot of the tile */ + Psot += epb_mark->Lepb + 2; + + opj_event_msg(j2k->cinfo, EVT_INFO, + /***** "TPH EPB : tile %02d, prot. %d\n", */ + "TPH EPB : tile %02d, part %02d, prot. %d\n", + /***** tileno, */ + tileno, tpno, + hprot + ); + + /* save this TPH EPB address */ + tph_epb = epb_mark; + + } else { + /* ooops, problems */ + /****** opj_event_msg(j2k->cinfo, EVT_ERROR, "Could not create TPH EPB #%d\n", tileno); */ + opj_event_msg(j2k->cinfo, EVT_ERROR, "Could not create TPH EPB in #%d,d\n", tileno, tpno); + }; + + } + + startpack = 0; + /* EPB MSs for UEP packet data protection in Tile Parts */ + /****** for (packno = 0; packno < j2k->cstr_info->num; packno++) { */ + /*first_tp_pack = (tpno > 0) ? (first_tp_pack + j2k->cstr_info->tile[tileno].tp[tpno - 1].tp_numpacks) : 0;*/ + first_tp_pack = j2k->cstr_info->tile[tileno].tp[tpno].tp_start_pack; + last_tp_pack = first_tp_pack + j2k->cstr_info->tile[tileno].tp[tpno].tp_numpacks - 1; + for (packno = 0; packno < j2k->cstr_info->tile[tileno].tp[tpno].tp_numpacks; packno++) { + + /******** if ((packspec < JPWL_MAX_NO_PACKSPECS) && + (j2k->cp->pprot_tileno[packspec] == tileno) && (j2k->cp->pprot_packno[packspec] == packno)) { */ + if ((packspec < JPWL_MAX_NO_PACKSPECS) && + (j2k->cp->pprot_tileno[packspec] == acc_tpno) && (j2k->cp->pprot_packno[packspec] == packno)) { + + /* we got a specification from this tile and packet onwards */ + /* print the previous spec */ + if (packno > 0) { + stoppack = packno - 1; + opj_event_msg(j2k->cinfo, EVT_INFO, + /***** "UEP EPBs: tile %02d, packs. %02d-%02d (B %d-%d), prot. %d\n", */ + "UEP EPBs: tile %02d, part %02d, packs. %02d-%02d (B %d-%d), prot. %d\n", + /***** tileno, */ + tileno, tpno, + startpack, + stoppack, + /***** j2k->cstr_info->tile[tileno].packet[startpack].start_pos, */ + j2k->cstr_info->tile[tileno].packet[first_tp_pack + startpack].start_pos, + /***** j2k->cstr_info->tile[tileno].packet[stoppack].end_pos, */ + j2k->cstr_info->tile[tileno].packet[first_tp_pack + stoppack].end_pos, + pprot); + + /***** prot_len = j2k->cstr_info->tile[tileno].packet[stoppack].end_pos + 1 - + j2k->cstr_info->tile[tileno].packet[startpack].start_pos; */ + prot_len = j2k->cstr_info->tile[tileno].packet[first_tp_pack + stoppack].end_pos + 1 - + j2k->cstr_info->tile[tileno].packet[first_tp_pack + startpack].start_pos; + + /* + particular case: if this is the last header and the last packet, + then it is better to protect even the EOC marker + */ + /****** if ((tileno == ((j2k->cstr_info->tw * j2k->cstr_info->th) - 1)) && + (stoppack == (j2k->cstr_info->num - 1))) */ + if ((tileno == ((j2k->cstr_info->tw * j2k->cstr_info->th) - 1)) && + (tpno == (j2k->cstr_info->tile[tileno].num_tps - 1)) && + (stoppack == last_tp_pack)) + /* add the EOC len */ + prot_len += 2; + + /* let's add the EPBs */ + Psot += jpwl_epbs_add( + j2k, /* J2K handle */ + jwmarker, /* pointer to JPWL markers list */ + &jwmarker_num, /* pointer to the number of current markers */ + false, /* latest */ + true, /* packed */ + false, /* inside MH */ + &epb_index, /* pointer to EPB index */ + pprot, /* protection type */ + /****** (double) (j2k->cstr_info->tile[tileno].start_pos + sot_len + 2) + 0.0001, */ /* position */ + (double) (j2k->cstr_info->tile[tileno].tp[tpno].tp_start_pos + sot_len + 2) + 0.0001, /* position */ + tileno, /* number of tile */ + 0, /* length of pre-data */ + prot_len /*4000*/ /* length of post-data */ + ); + } + + startpack = packno; + pprot = j2k->cp->pprot[packspec++]; + } + + //printf("Tile %02d, pack %02d ==> %d\n", tileno, packno, pprot); + + } + + /* we are at the end: print the remaining spec */ + stoppack = packno - 1; + if (pprot >= 0) { + + opj_event_msg(j2k->cinfo, EVT_INFO, + /**** "UEP EPBs: tile %02d, packs. %02d-%02d (B %d-%d), prot. %d\n", */ + "UEP EPBs: tile %02d, part %02d, packs. %02d-%02d (B %d-%d), prot. %d\n", + /**** tileno, */ + tileno, tpno, + startpack, + stoppack, + /***** j2k->image_info->tile[tileno].packet[startpack].start_pos, + j2k->image_info->tile[tileno].packet[stoppack].end_pos, */ + j2k->cstr_info->tile[tileno].packet[first_tp_pack + startpack].start_pos, + j2k->cstr_info->tile[tileno].packet[first_tp_pack + stoppack].end_pos, + pprot); + + /***** prot_len = j2k->cstr_info->tile[tileno].packet[stoppack].end_pos + 1 - + j2k->cstr_info->tile[tileno].packet[startpack].start_pos; */ + prot_len = j2k->cstr_info->tile[tileno].packet[first_tp_pack + stoppack].end_pos + 1 - + j2k->cstr_info->tile[tileno].packet[first_tp_pack + startpack].start_pos; + + /* + particular case: if this is the last header and the last packet, + then it is better to protect even the EOC marker + */ + /***** if ((tileno == ((j2k->cstr_info->tw * j2k->cstr_info->th) - 1)) && + (stoppack == (j2k->cstr_info->num - 1))) */ + if ((tileno == ((j2k->cstr_info->tw * j2k->cstr_info->th) - 1)) && + (tpno == (j2k->cstr_info->tile[tileno].num_tps - 1)) && + (stoppack == last_tp_pack)) + /* add the EOC len */ + prot_len += 2; + + /* let's add the EPBs */ + Psot += jpwl_epbs_add( + j2k, /* J2K handle */ + jwmarker, /* pointer to JPWL markers list */ + &jwmarker_num, /* pointer to the number of current markers */ + true, /* latest */ + true, /* packed */ + false, /* inside MH */ + &epb_index, /* pointer to EPB index */ + pprot, /* protection type */ + /***** (double) (j2k->cstr_info->tile[tileno].start_pos + sot_len + 2) + 0.0001,*/ /* position */ + (double) (j2k->cstr_info->tile[tileno].tp[tpno].tp_start_pos + sot_len + 2) + 0.0001, /* position */ + tileno, /* number of tile */ + 0, /* length of pre-data */ + prot_len /*4000*/ /* length of post-data */ + ); + } + + /* we can now check if the TPH EPB was really the last one */ + if (tph_epb && (epb_index == 1)) { + /* set the TPH EPB to be the last one in current header */ + tph_epb->Depb |= (unsigned char) ((true & 0x0001) << 6); + tph_epb = NULL; + } + + /* write back Psot */ + cio_seek(cio, Psotp); + cio_write(cio, Psot, 4); + + } + + }; + + /* reset the position */ + cio_seek(cio, ciopos); + +} + +void jpwl_dump_marks(opj_j2k_t *j2k, opj_cio_t *cio, opj_image_t *image) { + + int mm; + unsigned long int old_size = j2k->cstr_info->codestream_size; + unsigned long int new_size = old_size; + int /*ciopos = cio_tell(cio),*/ soc_pos = j2k->cstr_info->main_head_start; + unsigned char *jpwl_buf, *orig_buf; + unsigned long int orig_pos; + double epbcoding_time = 0.0, esdcoding_time = 0.0; + + /* Order JPWL markers according to their wishlist position */ + qsort((void *) jwmarker, (size_t) jwmarker_num, sizeof (jpwl_marker_t), jpwl_markcomp); + + /* compute markers total size */ + for (mm = 0; mm < jwmarker_num; mm++) { + /*printf("%x, %d, %.10f, %d long\n", jwmarker[mm].id, jwmarker[mm].pos, + jwmarker[mm].dpos, jwmarker[mm].len);*/ + new_size += jwmarker[mm].len + 2; + } + + /* allocate a new buffer of proper size */ + if (!(jpwl_buf = (unsigned char *) opj_malloc((size_t) (new_size + soc_pos) * sizeof(unsigned char)))) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "Could not allocate room for JPWL codestream buffer\n"); + exit(1); + }; + + /* copy the jp2 part, if any */ + orig_buf = jpwl_buf; + memcpy(jpwl_buf, cio->buffer, soc_pos); + jpwl_buf += soc_pos; + + /* cycle through markers */ + orig_pos = soc_pos + 0; /* start from the beginning */ + cio_seek(cio, soc_pos + 0); /* rewind the original */ + for (mm = 0; mm < jwmarker_num; mm++) { + + /* + need to copy a piece of the original codestream + if there is such + */ + memcpy(jpwl_buf, cio_getbp(cio), jwmarker[mm].pos - orig_pos); + jpwl_buf += jwmarker[mm].pos - orig_pos; + orig_pos = jwmarker[mm].pos; + cio_seek(cio, orig_pos); + + /* + then write down the marker + */ + switch (jwmarker[mm].id) { + + case J2K_MS_EPB: + jpwl_epb_write(j2k, jwmarker[mm].m.epbmark, jpwl_buf); + break; + + case J2K_MS_EPC: + jpwl_epc_write(j2k, jwmarker[mm].m.epcmark, jpwl_buf); + break; + + case J2K_MS_ESD: + jpwl_esd_write(j2k, jwmarker[mm].m.esdmark, jpwl_buf); + break; + + case J2K_MS_RED: + memset(jpwl_buf, 0, jwmarker[mm].len + 2); /* placeholder */ + break; + + default: + break; + }; + + /* we update the markers struct */ + if (j2k->cstr_info) + j2k->cstr_info->marker[j2k->cstr_info->marknum - 1].pos = (jpwl_buf - orig_buf); + + /* we set the marker dpos to the new position in the JPWL codestream */ + jwmarker[mm].dpos = (double) (jpwl_buf - orig_buf); + + /* advance JPWL buffer position */ + jpwl_buf += jwmarker[mm].len + 2; + + } + + /* finish remaining original codestream */ + memcpy(jpwl_buf, cio_getbp(cio), old_size - (orig_pos - soc_pos)); + jpwl_buf += old_size - (orig_pos - soc_pos); + cio_seek(cio, soc_pos + old_size); + + /* + update info file based on added markers + */ + if (!jpwl_update_info(j2k, jwmarker, jwmarker_num)) + opj_event_msg(j2k->cinfo, EVT_ERROR, "Could not update OPJ cstr_info structure\n"); + + /* now we need to repass some markers and fill their data fields */ + + /* first of all, DL and Pcrc in EPCs */ + for (mm = 0; mm < jwmarker_num; mm++) { + + /* find the EPCs */ + if (jwmarker[mm].id == J2K_MS_EPC) { + + int epc_pos = (int) jwmarker[mm].dpos, pp; + unsigned short int mycrc = 0x0000; + + /* fix and fill the DL field */ + jwmarker[mm].m.epcmark->DL = new_size; + orig_buf[epc_pos + 6] = (unsigned char) (jwmarker[mm].m.epcmark->DL >> 24); + orig_buf[epc_pos + 7] = (unsigned char) (jwmarker[mm].m.epcmark->DL >> 16); + orig_buf[epc_pos + 8] = (unsigned char) (jwmarker[mm].m.epcmark->DL >> 8); + orig_buf[epc_pos + 9] = (unsigned char) (jwmarker[mm].m.epcmark->DL >> 0); + + /* compute the CRC field (excluding itself) */ + for (pp = 0; pp < 4; pp++) + jpwl_updateCRC16(&mycrc, orig_buf[epc_pos + pp]); + for (pp = 6; pp < (jwmarker[mm].len + 2); pp++) + jpwl_updateCRC16(&mycrc, orig_buf[epc_pos + pp]); + + /* fix and fill the CRC */ + jwmarker[mm].m.epcmark->Pcrc = mycrc; + orig_buf[epc_pos + 4] = (unsigned char) (jwmarker[mm].m.epcmark->Pcrc >> 8); + orig_buf[epc_pos + 5] = (unsigned char) (jwmarker[mm].m.epcmark->Pcrc >> 0); + + } + } + + /* then, sensitivity data in ESDs */ + esdcoding_time = opj_clock(); + for (mm = 0; mm < jwmarker_num; mm++) { + + /* find the ESDs */ + if (jwmarker[mm].id == J2K_MS_ESD) { + + /* remember that they are now in a new position (dpos) */ + int esd_pos = (int) jwmarker[mm].dpos; + + jpwl_esd_fill(j2k, jwmarker[mm].m.esdmark, &orig_buf[esd_pos]); + + } + + } + esdcoding_time = opj_clock() - esdcoding_time; + if (j2k->cp->esd_on) + opj_event_msg(j2k->cinfo, EVT_INFO, "ESDs sensitivities computed in %f s\n", esdcoding_time); + + /* finally, RS or CRC parity in EPBs */ + epbcoding_time = opj_clock(); + for (mm = 0; mm < jwmarker_num; mm++) { + + /* find the EPBs */ + if (jwmarker[mm].id == J2K_MS_EPB) { + + /* remember that they are now in a new position (dpos) */ + int nn, accum_len; + + /* let's see how many EPBs are following this one, included itself */ + /* for this to work, we suppose that the markers are correctly ordered */ + /* and, overall, that they are in packed mode inside headers */ + accum_len = 0; + for (nn = mm; (nn < jwmarker_num) && (jwmarker[nn].id == J2K_MS_EPB) && + (jwmarker[nn].pos == jwmarker[mm].pos); nn++) + accum_len += jwmarker[nn].m.epbmark->Lepb + 2; + + /* fill the current (first) EPB with post-data starting from the computed position */ + jpwl_epb_fill(j2k, jwmarker[mm].m.epbmark, &orig_buf[(int) jwmarker[mm].dpos], + &orig_buf[(int) jwmarker[mm].dpos + accum_len]); + + /* fill the remaining EPBs in the header with post-data starting from the last position */ + for (nn = mm + 1; (nn < jwmarker_num) && (jwmarker[nn].id == J2K_MS_EPB) && + (jwmarker[nn].pos == jwmarker[mm].pos); nn++) + jpwl_epb_fill(j2k, jwmarker[nn].m.epbmark, &orig_buf[(int) jwmarker[nn].dpos], NULL); + + /* skip all the processed EPBs */ + mm = nn - 1; + } + + } + epbcoding_time = opj_clock() - epbcoding_time; + if (j2k->cp->epb_on) + opj_event_msg(j2k->cinfo, EVT_INFO, "EPBs redundancy computed in %f s\n", epbcoding_time); + + /* free original cio buffer and set it to the JPWL one */ + opj_free(cio->buffer); + cio->cinfo = cio->cinfo; /* no change */ + cio->openmode = cio->openmode; /* no change */ + cio->buffer = orig_buf; + cio->length = new_size + soc_pos; + cio->start = cio->buffer; + cio->end = cio->buffer + cio->length; + cio->bp = cio->buffer; + cio_seek(cio, soc_pos + new_size); + +} + + +void j2k_read_epc(opj_j2k_t *j2k) { + unsigned long int DL, Lepcp, Pcrcp, l; + unsigned short int Lepc, Pcrc = 0x0000; + unsigned char Pepc; + opj_cio_t *cio = j2k->cio; + char *ans1; + + /* Simply read the EPC parameters */ + Lepcp = cio_tell(cio); + Lepc = cio_read(cio, 2); + Pcrcp = cio_tell(cio); + cio_skip(cio, 2); /* Pcrc */ + DL = cio_read(cio, 4); + Pepc = cio_read(cio, 1); + + /* compute Pcrc */ + cio_seek(cio, Lepcp - 2); + + /* Marker */ + jpwl_updateCRC16(&Pcrc, (unsigned char) cio_read(cio, 1)); + jpwl_updateCRC16(&Pcrc, (unsigned char) cio_read(cio, 1)); + + /* Length */ + jpwl_updateCRC16(&Pcrc, (unsigned char) cio_read(cio, 1)); + jpwl_updateCRC16(&Pcrc, (unsigned char) cio_read(cio, 1)); + + /* skip Pcrc */ + cio_skip(cio, 2); + + /* read all remaining */ + for (l = 4; l < Lepc; l++) + jpwl_updateCRC16(&Pcrc, (unsigned char) cio_read(cio, 1)); + + /* check Pcrc with the result */ + cio_seek(cio, Pcrcp); + ans1 = (Pcrc == (unsigned short int) cio_read(cio, 2)) ? "crc-ok" : "crc-ko"; + + /* now we write them to screen */ + opj_event_msg(j2k->cinfo, EVT_INFO, + "EPC(%u,%d): %s, DL=%d%s %s %s\n", + Lepcp - 2, + Lepc, + ans1, + DL, /* data length this EPC is referring to */ + (Pepc & 0x10) ? ", esd" : "", /* ESD is present */ + (Pepc & 0x20) ? ", red" : "", /* RED is present */ + (Pepc & 0x40) ? ", epb" : ""); /* EPB is present */ + + cio_seek(cio, Lepcp + Lepc); +} + +void j2k_write_epc(opj_j2k_t *j2k) { + + unsigned long int DL, Lepcp, Pcrcp, l; + unsigned short int Lepc, Pcrc; + unsigned char Pepc; + + opj_cio_t *cio = j2k->cio; + + cio_write(cio, J2K_MS_EPC, 2); /* EPC */ + Lepcp = cio_tell(cio); + cio_skip(cio, 2); + + /* CRC-16 word of the EPC */ + Pcrc = 0x0000; /* initialize */ + Pcrcp = cio_tell(cio); + cio_write(cio, Pcrc, 2); /* Pcrc placeholder*/ + + /* data length of the EPC protection domain */ + DL = 0x00000000; /* we leave this set to 0, as if the information is not available */ + cio_write(cio, DL, 4); /* DL */ + + /* jpwl capabilities */ + Pepc = 0x00; + cio_write(cio, Pepc, 1); /* Pepc */ + + /* ID section */ + /* no ID's, as of now */ + + Lepc = (unsigned short) (cio_tell(cio) - Lepcp); + cio_seek(cio, Lepcp); + cio_write(cio, Lepc, 2); /* Lepc */ + + /* compute Pcrc */ + cio_seek(cio, Lepcp - 2); + + /* Marker */ + jpwl_updateCRC16(&Pcrc, (unsigned char) cio_read(cio, 1)); + jpwl_updateCRC16(&Pcrc, (unsigned char) cio_read(cio, 1)); + + /* Length */ + jpwl_updateCRC16(&Pcrc, (unsigned char) cio_read(cio, 1)); + jpwl_updateCRC16(&Pcrc, (unsigned char) cio_read(cio, 1)); + + /* skip Pcrc */ + cio_skip(cio, 2); + + /* read all remaining */ + for (l = 4; l < Lepc; l++) + jpwl_updateCRC16(&Pcrc, (unsigned char) cio_read(cio, 1)); + + /* fill Pcrc with the result */ + cio_seek(cio, Pcrcp); + cio_write(cio, Pcrc, 2); + + cio_seek(cio, Lepcp + Lepc); + + /* marker struct update */ + j2k_add_marker(j2k->cstr_info, J2K_MS_EPC, Lepcp - 2, Lepc + 2); + +} + +void j2k_read_epb(opj_j2k_t *j2k) { + unsigned long int LDPepb, Pepb; + unsigned short int Lepb; + unsigned char Depb; + char str1[25] = ""; + bool status; + static bool first_in_tph = true; + int type, pre_len, post_len; + static unsigned char *redund = NULL; + + opj_cio_t *cio = j2k->cio; + + /* B/W = 45, RGB = 51 */ + /* SIZ SIZ_FIELDS SIZ_COMPS FOLLOWING_MARKER */ + int skipnum = 2 + 38 + 3 * j2k->cp->exp_comps + 2; + + if (j2k->cp->correct) { + + /* go back to EPB marker value */ + cio_seek(cio, cio_tell(cio) - 2); + + /* we need to understand where we are */ + if (j2k->state == J2K_STATE_MH) { + /* we are in MH */ + type = 0; /* MH */ + pre_len = skipnum; /* SOC+SIZ */ + post_len = -1; /* auto */ + + } else if ((j2k->state == J2K_STATE_TPH) && first_in_tph) { + /* we are in TPH */ + type = 1; /* TPH */ + pre_len = 12; /* SOC+SIZ */ + first_in_tph = false; + post_len = -1; /* auto */ + + } else { + /* we are elsewhere */ + type = 2; /* other */ + pre_len = 0; /* nada */ + post_len = -1; /* auto */ + + } + + /* call EPB corrector */ + /*printf("before %x, ", redund);*/ + status = jpwl_epb_correct(j2k, /* J2K decompressor handle */ + cio->bp, /* pointer to EPB in codestream buffer */ + type, /* EPB type: MH */ + pre_len, /* length of pre-data */ + post_len, /* length of post-data: -1 means auto */ + NULL, /* do everything auto */ + &redund + ); + /*printf("after %x\n", redund);*/ + + /* Read the (possibly corrected) EPB parameters */ + cio_skip(cio, 2); + Lepb = cio_read(cio, 2); + Depb = cio_read(cio, 1); + LDPepb = cio_read(cio, 4); + Pepb = cio_read(cio, 4); + + if (!status) { + + opj_event_msg(j2k->cinfo, EVT_ERROR, "JPWL correction could not be performed\n"); + + /* advance to EPB endpoint */ + cio_skip(cio, Lepb + 2); + + return; + } + + /* last in current header? */ + if (Depb & 0x40) { + redund = NULL; /* reset the pointer to L4 buffer */ + first_in_tph = true; + } + + /* advance to EPB endpoint */ + cio_skip(cio, Lepb - 11); + + } else { + + /* Simply read the EPB parameters */ + Lepb = cio_read(cio, 2); + Depb = cio_read(cio, 1); + LDPepb = cio_read(cio, 4); + Pepb = cio_read(cio, 4); + + /* What does Pepb tells us about the protection method? */ + if (((Pepb & 0xF0000000) >> 28) == 0) + sprintf(str1, "pred"); /* predefined */ + else if (((Pepb & 0xF0000000) >> 28) == 1) + sprintf(str1, "crc-%lu", 16 * ((Pepb & 0x00000001) + 1)); /* CRC mode */ + else if (((Pepb & 0xF0000000) >> 28) == 2) + sprintf(str1, "rs(%lu,32)", (Pepb & 0x0000FF00) >> 8); /* RS mode */ + else if (Pepb == 0xFFFFFFFF) + sprintf(str1, "nometh"); /* RS mode */ + else + sprintf(str1, "unknown"); /* unknown */ + + /* Now we write them to screen */ + opj_event_msg(j2k->cinfo, EVT_INFO, + "EPB(%d): (%sl, %sp, %u), %lu, %s\n", + cio_tell(cio) - 13, + (Depb & 0x40) ? "" : "n", /* latest EPB or not? */ + (Depb & 0x80) ? "" : "n", /* packed or unpacked EPB? */ + (Depb & 0x3F), /* EPB index value */ + LDPepb, /*length of the data protected by the EPB */ + str1); /* protection method */ + + cio_skip(cio, Lepb - 11); + } +} + +void j2k_write_epb(opj_j2k_t *j2k) { + unsigned long int LDPepb, Pepb, Lepbp; + unsigned short int Lepb; + unsigned char Depb; + + opj_cio_t *cio = j2k->cio; + + cio_write(cio, J2K_MS_EPB, 2); /* EPB */ + Lepbp = cio_tell(cio); + cio_skip(cio, 2); + + /* EPB style */ + Depb = 0x00; /* test */ + cio_write(cio, Depb, 1); /* Depb */ + + /* length of the data to be protected by this EPB */ + LDPepb = 0x00000000; /* test */ + cio_write(cio, LDPepb, 4); /* LDPepb */ + + /* next error correction tool */ + Pepb = 0x00000000; /* test */ + cio_write(cio, Pepb, 4); /* Pepb */ + + /* EPB data */ + /* no data, as of now */ + + Lepb = (unsigned short) (cio_tell(cio) - Lepbp); + cio_seek(cio, Lepbp); + cio_write(cio, Lepb, 2); /* Lepb */ + + cio_seek(cio, Lepbp + Lepb); + + /* marker struct update */ + j2k_add_marker(j2k->cstr_info, J2K_MS_EPB, Lepbp - 2, Lepb + 2); +} + +void j2k_read_esd(opj_j2k_t *j2k) { + unsigned short int Lesd, Cesd; + unsigned char Pesd; + + int cesdsize = (j2k->image->numcomps >= 257) ? 2 : 1; + + char str1[4][4] = {"p", "br", "pr", "res"}; + char str2[8][8] = {"res", "mse", "mse-r", "psnr", "psnr-i", "maxerr", "tse", "res"}; + + opj_cio_t *cio = j2k->cio; + + /* Simply read the ESD parameters */ + Lesd = cio_read(cio, 2); + Cesd = cio_read(cio, cesdsize); + Pesd = cio_read(cio, 1); + + /* Now we write them to screen */ + opj_event_msg(j2k->cinfo, EVT_INFO, + "ESD(%d): c%d, %s, %s, %s, %s, %s\n", + cio_tell(cio) - (5 + cesdsize), + Cesd, /* component number for this ESD */ + str1[(Pesd & (unsigned char) 0xC0) >> 6], /* addressing mode */ + str2[(Pesd & (unsigned char) 0x38) >> 3], /* sensitivity type */ + ((Pesd & (unsigned char) 0x04) >> 2) ? "2Bs" : "1Bs", + ((Pesd & (unsigned char) 0x02) >> 1) ? "4Ba" : "2Ba", + (Pesd & (unsigned char) 0x01) ? "avgc" : ""); + + cio_skip(cio, Lesd - (3 + cesdsize)); +} + +void j2k_read_red(opj_j2k_t *j2k) { + unsigned short int Lred; + unsigned char Pred; + char str1[4][4] = {"p", "br", "pr", "res"}; + + opj_cio_t *cio = j2k->cio; + + /* Simply read the RED parameters */ + Lred = cio_read(cio, 2); + Pred = cio_read(cio, 1); + + /* Now we write them to screen */ + opj_event_msg(j2k->cinfo, EVT_INFO, + "RED(%d): %s, %dc, %s, %s\n", + cio_tell(cio) - 5, + str1[(Pred & (unsigned char) 0xC0) >> 6], /* addressing mode */ + (Pred & (unsigned char) 0x38) >> 3, /* corruption level */ + ((Pred & (unsigned char) 0x02) >> 1) ? "4Ba" : "2Ba", /* address range */ + (Pred & (unsigned char) 0x01) ? "errs" : "free"); /* error free? */ + + cio_skip(cio, Lred - 3); +} + +bool jpwl_check_tile(opj_j2k_t *j2k, opj_tcd_t *tcd, int tileno) { + +#ifdef oerhgierhgvhreit4u + /* + we navigate through the tile and find possible invalid parameters: + this saves a lot of crashes!!!!! + */ + int compno, resno, precno, /*layno,*/ bandno, blockno; + int numprecincts, numblocks; + + /* this is the selected tile */ + opj_tcd_tile_t *tile = &(tcd->tcd_image->tiles[tileno]); + + /* will keep the component */ + opj_tcd_tilecomp_t *comp = NULL; + + /* will keep the resolution */ + opj_tcd_resolution_t *res; + + /* will keep the subband */ + opj_tcd_band_t *band; + + /* will keep the precinct */ + opj_tcd_precinct_t *prec; + + /* will keep the codeblock */ + opj_tcd_cblk_t *block; + + /* check all tile components */ + for (compno = 0; compno < tile->numcomps; compno++) { + comp = &(tile->comps[compno]); + + /* check all component resolutions */ + for (resno = 0; resno < comp->numresolutions; resno++) { + res = &(comp->resolutions[resno]); + numprecincts = res->pw * res->ph; + + /* check all the subbands */ + for (bandno = 0; bandno < res->numbands; bandno++) { + band = &(res->bands[bandno]); + + /* check all the precincts */ + for (precno = 0; precno < numprecincts; precno++) { + prec = &(band->precincts[precno]); + numblocks = prec->ch * prec->cw; + + /* check all the codeblocks */ + for (blockno = 0; blockno < numblocks; blockno++) { + block = &(prec->cblks[blockno]); + + /* x-origin is invalid */ + if ((block->x0 < prec->x0) || (block->x0 > prec->x1)) { + opj_event_msg(j2k->cinfo, JPWL_ASSUME ? EVT_WARNING : EVT_ERROR, + "JPWL: wrong x-cord of block origin %d => x-prec is (%d, %d)\n", + block->x0, prec->x0, prec->x1); + if (!JPWL_ASSUME || JPWL_ASSUME) + return false; + }; + } + } + } + } + } + +#endif + + return true; +} + +/*@}*/ + +#endif /* USE_JPWL */ + + +#ifdef USE_JPSEC + +/** @defgroup JPSEC JPSEC - JPEG-2000 Part 8 (JPSEC) codestream manager */ +/*@{*/ + + +/** @name Local static functions */ +/*@{*/ + +void j2k_read_sec(opj_j2k_t *j2k) { + unsigned short int Lsec; + + opj_cio_t *cio = j2k->cio; + + /* Simply read the SEC length */ + Lsec = cio_read(cio, 2); + + /* Now we write them to screen */ + opj_event_msg(j2k->cinfo, EVT_INFO, + "SEC(%d)\n", + cio_tell(cio) - 2 + ); + + cio_skip(cio, Lsec - 2); +} + +void j2k_write_sec(opj_j2k_t *j2k) { + unsigned short int Lsec = 24; + int i; + + opj_cio_t *cio = j2k->cio; + + cio_write(cio, J2K_MS_SEC, 2); /* SEC */ + cio_write(cio, Lsec, 2); + + /* write dummy data */ + for (i = 0; i < Lsec - 2; i++) + cio_write(cio, 0, 1); +} + +void j2k_read_insec(opj_j2k_t *j2k) { + unsigned short int Linsec; + + opj_cio_t *cio = j2k->cio; + + /* Simply read the INSEC length */ + Linsec = cio_read(cio, 2); + + /* Now we write them to screen */ + opj_event_msg(j2k->cinfo, EVT_INFO, + "INSEC(%d)\n", + cio_tell(cio) - 2 + ); + + cio_skip(cio, Linsec - 2); +} + + +/*@}*/ + +/*@}*/ + +#endif /* USE_JPSEC */ + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jpwl/jpwl.h b/gdcm/Utilities/gdcmopenjpeg-v1/jpwl/jpwl.h new file mode 100644 index 0000000..a96840c --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jpwl/jpwl.h @@ -0,0 +1,425 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * Copyright (c) 2005-2006, Dept. of Electronic and Information Engineering, Universita' degli Studi di Perugia, Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __JPWL_H +#define __JPWL_H + +#ifdef USE_JPWL + +#include "crc.h" +#include "rs.h" + +/** +@file jpwl.h +@brief The JPEG-2000 Part11 (JPWL) marker segments manager + +The functions in JPWL.C have for goal to read/write the markers added by JPWL. +*/ + +/** @defgroup JPWL JPWL - JPEG-2000 Part11 (JPWL) codestream manager */ +/*@{*/ + +/** +Assume a basic codestream structure, so you can resort better from uncorrected errors +*/ +#define JPWL_ASSUME true + +/** +EPB (Error Protection Block) Marker segment +*/ +typedef struct jpwl_epb_ms { + /**@name Private fields set by epb_create */ + /*@{*/ + /** is the latest in header? */ + bool latest; + /** is it in packed mode? */ + bool packed; + /** TH where this marker has been placed (-1 means MH) */ + int tileno; + /** index in current header (0-63) */ + unsigned char index; + /** error protection method [-1=absent 0=none 1=predefined 16=CRC-16 32=CRC-32 37-128=RS] */ + int hprot; + /** message word length of pre-data */ + int k_pre; + /** code word length of pre-data */ + int n_pre; + /** length of pre-data */ + int pre_len; + /** message word length of post-data */ + int k_post; + /** code word length of post-data */ + int n_post; + /** length of post-data */ + int post_len; + /*@}*/ + /**@name Marker segment fields */ + /*@{*/ + /** two bytes for the length of EPB MS, exluding the marker itself (11 to 65535 bytes) */ + unsigned short int Lepb; + /** single byte for the style */ + unsigned char Depb; + /** four bytes, from 0 to 2^31-1 */ + unsigned long int LDPepb; + /** four bytes, next error management method */ + unsigned long int Pepb; + /** EPB data, variable size */ + unsigned char *data; + /*@}*/ +} jpwl_epb_ms_t; + +/** +EPC (Error Protection Capability) Marker segment +*/ +typedef struct jpwl_epc_ms { + /** is ESD active? */ + bool esd_on; + /** is RED active? */ + bool red_on; + /** is EPB active? */ + bool epb_on; + /** are informative techniques active? */ + bool info_on; + /**@name Marker segment fields */ + /*@{*/ + /** two bytes for the length of EPC MS, exluding the marker itself (9 to 65535 bytes) */ + unsigned short int Lepc; + /** two bytes, CRC for the EPC, excluding Pcrc itself */ + unsigned short int Pcrc; + /** four bytes, the codestream length from SOC to EOC */ + unsigned long int DL; + /** one byte, signals JPWL techniques adoption */ + unsigned char Pepc; + /** EPC data, variable length */ + unsigned char *data; + /*@}*/ +} jpwl_epc_ms_t; + +/** +ESD (Error Sensitivity Descriptor) Marker segment +*/ +typedef struct jpwl_esd_ms { + /** codestream addressing mode [0=packet, 1=byte range, 2=packet range, 3=reserved] */ + unsigned char addrm; + /** size of codestream addresses [2/4 bytes] */ + unsigned char ad_size; + /** type of sensitivity + [0=relative error, 1=MSE, 2=MSE reduction, 3=PSNR, 4=PSNR increment, + 5=MAXERR (absolute peak error), 6=TSE (total squared error), 7=reserved */ + unsigned char senst; + /** size of sensitivity data (1/2 bytes) */ + unsigned char se_size; + /**@name Marker segment fields */ + /*@{*/ + /** two bytes for the length of ESD MS, exluding the marker itself (4 to 65535 bytes) */ + unsigned short int Lesd; + /** two bytes, component of error sensitivity */ + unsigned short int Cesd; + /** one byte, signals JPWL techniques adoption */ + unsigned char Pesd; + /** ESD data, variable length */ + unsigned char *data; + /*@}*/ + /**@name Fields set by esd_create (only internal use) */ + /*@{*/ + /** number of components in the image */ + int numcomps; + /** tile where this marker has been placed (-1 means MH) */ + int tileno; + /** number of sensitivity values */ + unsigned long int svalnum; + /** size of a single sensitivity pair (address+value) */ + size_t sensval_size; + /*@}*/ +} jpwl_esd_ms_t; + +/** +RED (Residual Error Descriptor) Marker segment +*/ +typedef struct jpwl_red_ms { + /** two bytes for the length of RED MS, exluding the marker itself (3 to 65535 bytes) */ + unsigned short int Lred; + /** one byte, signals JPWL techniques adoption */ + unsigned char Pred; + /** RED data, variable length */ + unsigned char *data; +} jpwl_red_ms_t; + +/** +Structure used to store JPWL markers temporary position and readyness +*/ +typedef struct jpwl_marker { + /** marker value (J2K_MS_EPC, etc.) */ + int id; + /** union keeping the pointer to the real marker struct */ + union jpwl_marks { + /** pointer to EPB marker */ + jpwl_epb_ms_t *epbmark; + /** pointer to EPC marker */ + jpwl_epc_ms_t *epcmark; + /** pointer to ESD marker */ + jpwl_esd_ms_t *esdmark; + /** pointer to RED marker */ + jpwl_red_ms_t *redmark; + } m; + /** position where the marker should go, in the pre-JPWL codestream */ + unsigned long int pos; + /** same as before, only written as a double, so we can sort it better */ + double dpos; + /** length of the marker segment (marker excluded) */ + unsigned short int len; + /** the marker length is ready or not? */ + bool len_ready; + /** the marker position is ready or not? */ + bool pos_ready; + /** the marker parameters are ready or not? */ + bool parms_ready; + /** are the written data ready or not */ + bool data_ready; +} jpwl_marker_t; + +/** +Encode according to JPWL specs +@param j2k J2K handle +@param cio codestream handle +@param image image handle +*/ +void jpwl_encode(opj_j2k_t *j2k, opj_cio_t *cio, opj_image_t *image); + +/** +Prepare the list of JPWL markers, after the Part 1 codestream +has been finalized (index struct is full) +@param j2k J2K handle +@param cio codestream handle +@param image image handle +*/ +void jpwl_prepare_marks(opj_j2k_t *j2k, opj_cio_t *cio, opj_image_t *image); + +/** +Dump the list of JPWL markers, after it has been prepared +@param j2k J2K handle +@param cio codestream handle +@param image image handle +*/ +void jpwl_dump_marks(opj_j2k_t *j2k, opj_cio_t *cio, opj_image_t *image); + +/** +Read the EPC marker (Error Protection Capability) +@param j2k J2K handle +*/ +void j2k_read_epc(opj_j2k_t *j2k); + +/** +Write the EPC marker (Error Protection Capability), BUT the DL field is always set to 0 +(this simplifies the management of EPBs and it is openly stated in the standard +as a possible value, mening that the information is not available) and the informative techniques +are not yet implemented +@param j2k J2K handle +*/ +void j2k_write_epc(opj_j2k_t *j2k); + +/** +Read the EPB marker (Error Protection Block) +@param j2k J2K handle +*/ +void j2k_read_epb(opj_j2k_t *j2k); + +/** +Write the EPB marker (Error Protection Block) +@param j2k J2K handle +*/ +void j2k_write_epb(opj_j2k_t *j2k); + +/** +Read the ESD marker (Error Sensitivity Descriptor) +@param j2k J2K handle +*/ +void j2k_read_esd(opj_j2k_t *j2k); + +/** +Read the RED marker (Residual Error Descriptor) +@param j2k J2K handle +*/ +void j2k_read_red(opj_j2k_t *j2k); + +/** create an EPB marker segment +@param j2k J2K compressor handle +@param latest it is the latest EPB in the header +@param packed EPB is in packed style +@param tileno tile number where the marker has been placed (-1 means MH) +@param idx current EPB running index +@param hprot applied protection type (-1/0,1,16,32,37-128) +@param pre_len length of pre-protected data +@param post_len length of post-protected data +@return returns the freshly created EPB +*/ +jpwl_epb_ms_t *jpwl_epb_create(opj_j2k_t *j2k, bool latest, bool packed, int tileno, int idx, int hprot, + unsigned long int pre_len, unsigned long int post_len); + +/** add a number of EPB marker segments +@param j2k J2K compressor handle +@param jwmarker pointer to the JPWL markers list +@param jwmarker_num pointer to the number of JPWL markers (gets updated) +@param latest it is the latest group of EPBs in the header +@param packed EPBs are in packed style +@param insideMH it is in the MH +@param idx pointer to the starting EPB running index (gets updated) +@param hprot applied protection type (-1/0,1,16,32,37-128) +@param place_pos place in original codestream where EPBs should go +@param tileno tile number of these EPBs +@param pre_len length of pre-protected data +@param post_len length of post-protected data +@return returns the length of all added markers +*/ +int jpwl_epbs_add(opj_j2k_t *j2k, jpwl_marker_t *jwmarker, int *jwmarker_num, + bool latest, bool packed, bool insideMH, int *idx, int hprot, + double place_pos, int tileno, + unsigned long int pre_len, unsigned long int post_len); + +/** add a number of ESD marker segments +@param j2k J2K compressor handle +@param jwmarker pointer to the JPWL markers list +@param jwmarker_num pointer to the number of JPWL markers (gets updated) +@param comps considered component (-1=average, 0/1/2/...=component no.) +@param addrm addressing mode (0=packet, 1=byte range, 2=packet range, 3=reserved) +@param ad_size size of addresses (2/4 bytes) +@param senst sensitivity type +@param se_size sensitivity values size (1/2 bytes) +@param place_pos place in original codestream where EPBs should go +@param tileno tile number of these EPBs +@return returns the length of all added markers +*/ +int jpwl_esds_add(opj_j2k_t *j2k, jpwl_marker_t *jwmarker, int *jwmarker_num, + int comps, unsigned char addrm, unsigned char ad_size, + unsigned char senst, unsigned char se_size, + double place_pos, int tileno); + +/** updates the information structure by modifying the positions and lengths +@param j2k J2K compressor handle +@param jwmarker pointer to JPWL markers list +@param jwmarker_num number of JPWL markers +@return returns true in case of success +*/ +bool jpwl_update_info(opj_j2k_t *j2k, jpwl_marker_t *jwmarker, int jwmarker_num); + + +bool jpwl_esd_fill(opj_j2k_t *j2k, jpwl_esd_ms_t *esdmark, unsigned char *buf); + +bool jpwl_epb_fill(opj_j2k_t *j2k, jpwl_epb_ms_t *epbmark, unsigned char *buf, unsigned char *post_buf); + +void j2k_add_marker(opj_codestream_info_t *cstr_info, unsigned short int type, int pos, int len); + +/** corrects the data in the JPWL codestream +@param j2k J2K compressor handle +@return true if correction is performed correctly +*/ +bool jpwl_correct(opj_j2k_t *j2k); + +/** corrects the data protected by an EPB +@param j2k J2K compressor handle +@param buffer pointer to the EPB position +@param type type of EPB: 0=MH, 1=TPH, 2=other, 3=auto +@param pre_len length of pre-data +@param post_len length of post_data +@param conn is a pointer to the length of all connected (packed) EPBs +@param L4_bufp is a pointer to the buffer pointer of redundancy data +@return returns true if correction could be succesfully performed +*/ +bool jpwl_epb_correct(opj_j2k_t *j2k, unsigned char *buffer, int type, int pre_len, int post_len, int *conn, + unsigned char **L4_bufp); + +/** check that a tile and its children have valid data +@param j2k J2K decompressor handle +@param tcd Tile decompressor handle +@param tileno number of the tile to check +*/ +bool jpwl_check_tile(opj_j2k_t *j2k, opj_tcd_t *tcd, int tileno); + +/** Macro functions for CRC computation */ + +/** +Computes the CRC-16, as stated in JPWL specs +@param CRC two bytes containing the CRC value (must be initialized with 0x0000) +@param DATA byte for which the CRC is computed; call this on every byte of the sequence +and get the CRC at the end +*/ +#define jpwl_updateCRC16(CRC, DATA) updateCRC16(CRC, DATA) + +/** +Computes the CRC-32, as stated in JPWL specs +@param CRC four bytes containing the CRC value (must be initialized with 0x00000000) +@param DATA byte for which the CRC is computed; call this on every byte of the sequence +and get the CRC at the end +*/ +#define jpwl_updateCRC32(CRC, DATA) updateCRC32(CRC, DATA) + +/** +Computes the minimum between two integers +@param a first integer to compare +@param b second integer to compare +@return returns the minimum integer between a and b +*/ +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif /* min */ + +/*@}*/ + +#endif /* USE_JPWL */ + +#ifdef USE_JPSEC + +/** @defgroup JPSEC JPSEC - JPEG-2000 Part 8 (JPSEC) codestream manager */ +/*@{*/ + +/** +Read the SEC marker (SEcured Codestream) +@param j2k J2K handle +*/ +void j2k_read_sec(opj_j2k_t *j2k); + +/** +Write the SEC marker (SEcured Codestream) +@param j2k J2K handle +*/ +void j2k_write_sec(opj_j2k_t *j2k); + +/** +Read the INSEC marker (SEcured Codestream) +@param j2k J2K handle +*/ +void j2k_read_insec(opj_j2k_t *j2k); + +/*@}*/ + +#endif /* USE_JPSEC */ + +#endif /* __JPWL_H */ + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jpwl/jpwl_lib.c b/gdcm/Utilities/gdcmopenjpeg-v1/jpwl/jpwl_lib.c new file mode 100644 index 0000000..90391b0 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jpwl/jpwl_lib.c @@ -0,0 +1,1796 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * Copyright (c) 2005-2006, Dept. of Electronic and Information Engineering, Universita' degli Studi di Perugia, Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef USE_JPWL + +#include "../libopenjpeg/opj_includes.h" +#include + +/** Minimum and maximum values for the double->pfp conversion */ +#define MIN_V1 0.0 +#define MAX_V1 17293822569102704640.0 +#define MIN_V2 0.000030517578125 +#define MAX_V2 131040.0 + +/** conversion between a double precision floating point +number and the corresponding pseudo-floating point used +to represent sensitivity values +@param V the double precision value +@param bytes the number of bytes of the representation +@return the pseudo-floating point value (cast accordingly) +*/ +unsigned short int jpwl_double_to_pfp(double V, int bytes); + +/** conversion between a pseudo-floating point used +to represent sensitivity values and the corresponding +double precision floating point number +@param em the pseudo-floating point value (cast accordingly) +@param bytes the number of bytes of the representation +@return the double precision value +*/ +double jpwl_pfp_to_double(unsigned short int em, int bytes); + + /*-------------------------------------------------------------*/ + +int jpwl_markcomp(const void *arg1, const void *arg2) +{ + /* Compare the two markers' positions */ + double diff = (((jpwl_marker_t *) arg1)->dpos - ((jpwl_marker_t *) arg2)->dpos); + + if (diff == 0.0) + return (0); + else if (diff < 0) + return (-1); + else + return (+1); +} + +int jpwl_epbs_add(opj_j2k_t *j2k, jpwl_marker_t *jwmarker, int *jwmarker_num, + bool latest, bool packed, bool insideMH, int *idx, int hprot, + double place_pos, int tileno, + unsigned long int pre_len, unsigned long int post_len) { + + jpwl_epb_ms_t *epb_mark = NULL; + + int k_pre, k_post, n_pre, n_post; + + unsigned long int L1, L2, dL4, max_postlen, epbs_len = 0; + + /* We find RS(n,k) for EPB parms and pre-data, if any */ + if (insideMH && (*idx == 0)) { + /* First EPB in MH */ + k_pre = 64; + n_pre = 160; + } else if (!insideMH && (*idx == 0)) { + /* First EPB in TH */ + k_pre = 25; + n_pre = 80; + } else { + /* Following EPBs in MH or TH */ + k_pre = 13; + n_pre = 40; + }; + + /* Find lengths, Figs. B3 and B4 */ + /* size of pre data: pre_buf(pre_len) + EPB(2) + Lepb(2) + Depb(1) + LDPepb(4) + Pepb(4) */ + L1 = pre_len + 13; + + /* size of pre-data redundancy */ + /* (redundancy per codeword) * (number of codewords, rounded up) */ + L2 = (n_pre - k_pre) * (unsigned long int) ceil((double) L1 / (double) k_pre); + + /* Find protection type for post data and its associated redundancy field length*/ + if ((hprot == 16) || (hprot == 32)) { + /* there is a CRC for post-data */ + k_post = post_len; + n_post = post_len + (hprot >> 3); + /*L3 = hprot >> 3;*/ /* 2 (CRC-16) or 4 (CRC-32) bytes */ + + } else if ((hprot >= 37) && (hprot <= 128)) { + /* there is a RS for post-data */ + k_post = 32; + n_post = hprot; + + } else { + /* Use predefined codes */ + n_post = n_pre; + k_post = k_pre; + }; + + /* Create the EPB(s) */ + while (post_len > 0) { + + /* maximum postlen in order to respect EPB size + (we use JPWL_MAXIMUM_EPB_ROOM instead of 65535 for keeping room for EPB parms)*/ + /* (message word size) * (number of containable parity words) */ + max_postlen = k_post * (unsigned long int) floor((double) JPWL_MAXIMUM_EPB_ROOM / (double) (n_post - k_post)); + + /* maximum postlen in order to respect EPB size */ + if (*idx == 0) + /* (we use (JPWL_MAXIMUM_EPB_ROOM - L2) instead of 65535 for keeping room for EPB parms + pre-data) */ + /* (message word size) * (number of containable parity words) */ + max_postlen = k_post * (unsigned long int) floor((double) (JPWL_MAXIMUM_EPB_ROOM - L2) / (double) (n_post - k_post)); + + else + /* (we use JPWL_MAXIMUM_EPB_ROOM instead of 65535 for keeping room for EPB parms) */ + /* (message word size) * (number of containable parity words) */ + max_postlen = k_post * (unsigned long int) floor((double) JPWL_MAXIMUM_EPB_ROOM / (double) (n_post - k_post)); + + /* null protection case */ + /* the max post length can be as large as the LDPepb field can host */ + if (hprot == 0) + max_postlen = INT_MAX; + + /* length to use */ + dL4 = min(max_postlen, post_len); + + if ((epb_mark = jpwl_epb_create( + j2k, /* this encoder handle */ + latest ? (dL4 < max_postlen) : false, /* is it the latest? */ + packed, /* is it packed? */ + tileno, /* we are in TPH */ + *idx, /* its index */ + hprot, /* protection type parameters of following data */ + 0, /* pre-data: nothing for now */ + dL4 /* post-data: the stub computed previously */ + ))) { + + /* Add this marker to the 'insertanda' list */ + if (*jwmarker_num < JPWL_MAX_NO_MARKERS) { + jwmarker[*jwmarker_num].id = J2K_MS_EPB; /* its type */ + jwmarker[*jwmarker_num].m.epbmark = epb_mark; /* the EPB */ + jwmarker[*jwmarker_num].pos = (int) place_pos; /* after SOT */ + jwmarker[*jwmarker_num].dpos = place_pos + 0.0000001 * (double)(*idx); /* not very first! */ + jwmarker[*jwmarker_num].len = epb_mark->Lepb; /* its length */ + jwmarker[*jwmarker_num].len_ready = true; /* ready */ + jwmarker[*jwmarker_num].pos_ready = true; /* ready */ + jwmarker[*jwmarker_num].parms_ready = true; /* ready */ + jwmarker[*jwmarker_num].data_ready = false; /* not ready */ + (*jwmarker_num)++; + } + + /* increment epb index */ + (*idx)++; + + /* decrease postlen */ + post_len -= dL4; + + /* increase the total length of EPBs */ + epbs_len += epb_mark->Lepb + 2; + + } else { + /* ooops, problems */ + opj_event_msg(j2k->cinfo, EVT_ERROR, "Could not create TPH EPB for UEP in tile %d\n", tileno); + }; + } + + return epbs_len; +} + + +jpwl_epb_ms_t *jpwl_epb_create(opj_j2k_t *j2k, bool latest, bool packed, int tileno, int idx, int hprot, + unsigned long int pre_len, unsigned long int post_len) { + + jpwl_epb_ms_t *epb = NULL; + /*unsigned short int data_len = 0;*/ + unsigned short int L2, L3; + unsigned long int L1, L4; + /*unsigned char *predata_in = NULL;*/ + + bool insideMH = (tileno == -1); + + /* Alloc space */ + if (!(epb = (jpwl_epb_ms_t *) opj_malloc((size_t) 1 * sizeof (jpwl_epb_ms_t)))) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "Could not allocate room for one EPB MS\n"); + return NULL; + }; + + /* We set RS(n,k) for EPB parms and pre-data, if any */ + if (insideMH && (idx == 0)) { + /* First EPB in MH */ + epb->k_pre = 64; + epb->n_pre = 160; + } else if (!insideMH && (idx == 0)) { + /* First EPB in TH */ + epb->k_pre = 25; + epb->n_pre = 80; + } else { + /* Following EPBs in MH or TH */ + epb->k_pre = 13; + epb->n_pre = 40; + }; + + /* Find lengths, Figs. B3 and B4 */ + /* size of pre data: pre_buf(pre_len) + EPB(2) + Lepb(2) + Depb(1) + LDPepb(4) + Pepb(4) */ + L1 = pre_len + 13; + epb->pre_len = pre_len; + + /* size of pre-data redundancy */ + /* (redundancy per codeword) * (number of codewords, rounded up) */ + L2 = (epb->n_pre - epb->k_pre) * (unsigned short int) ceil((double) L1 / (double) epb->k_pre); + + /* length of post-data */ + L4 = post_len; + epb->post_len = post_len; + + /* Find protection type for post data and its associated redundancy field length*/ + if ((hprot == 16) || (hprot == 32)) { + /* there is a CRC for post-data */ + epb->Pepb = 0x10000000 | ((unsigned long int) hprot >> 5); /* 0=CRC-16, 1=CRC-32 */ + epb->k_post = post_len; + epb->n_post = post_len + (hprot >> 3); + /*L3 = hprot >> 3;*/ /* 2 (CRC-16) or 4 (CRC-32) bytes */ + + } else if ((hprot >= 37) && (hprot <= 128)) { + /* there is a RS for post-data */ + epb->Pepb = 0x20000020 | (((unsigned long int) hprot & 0x000000FF) << 8); + epb->k_post = 32; + epb->n_post = hprot; + + } else if (hprot == 1) { + /* Use predefined codes */ + epb->Pepb = (unsigned long int) 0x00000000; + epb->n_post = epb->n_pre; + epb->k_post = epb->k_pre; + + } else if (hprot == 0) { + /* Placeholder EPB: only protects its parameters, no protection method */ + epb->Pepb = (unsigned long int) 0xFFFFFFFF; + epb->n_post = 1; + epb->k_post = 1; + + } else { + opj_event_msg(j2k->cinfo, EVT_ERROR, "Invalid protection value for EPB h = %d\n", hprot); + return NULL; + } + + epb->hprot = hprot; + + /* (redundancy per codeword) * (number of codewords, rounded up) */ + L3 = (epb->n_post - epb->k_post) * (unsigned short int) ceil((double) L4 / (double) epb->k_post); + + /* private fields */ + epb->tileno = tileno; + + /* Fill some fields of the EPB */ + + /* total length of the EPB MS (less the EPB marker itself): */ + /* Lepb(2) + Depb(1) + LDPepb(4) + Pepb(4) + pre_redundancy + post-redundancy */ + epb->Lepb = 11 + L2 + L3; + + /* EPB style */ + epb->Depb = ((packed & 0x0001) << 7) | ((latest & 0x0001) << 6) | (idx & 0x003F); + + /* length of data protected by EPB: */ + epb->LDPepb = L1 + L4; + + return epb; +} + +void jpwl_epb_write(opj_j2k_t *j2k, jpwl_epb_ms_t *epb, unsigned char *buf) { + + /* Marker */ + *(buf++) = (unsigned char) (J2K_MS_EPB >> 8); + *(buf++) = (unsigned char) (J2K_MS_EPB >> 0); + + /* Lepb */ + *(buf++) = (unsigned char) (epb->Lepb >> 8); + *(buf++) = (unsigned char) (epb->Lepb >> 0); + + /* Depb */ + *(buf++) = (unsigned char) (epb->Depb >> 0); + + /* LDPepb */ + *(buf++) = (unsigned char) (epb->LDPepb >> 24); + *(buf++) = (unsigned char) (epb->LDPepb >> 16); + *(buf++) = (unsigned char) (epb->LDPepb >> 8); + *(buf++) = (unsigned char) (epb->LDPepb >> 0); + + /* Pepb */ + *(buf++) = (unsigned char) (epb->Pepb >> 24); + *(buf++) = (unsigned char) (epb->Pepb >> 16); + *(buf++) = (unsigned char) (epb->Pepb >> 8); + *(buf++) = (unsigned char) (epb->Pepb >> 0); + + /* Data */ + /*memcpy(buf, epb->data, (size_t) epb->Lepb - 11);*/ + memset(buf, 0, (size_t) epb->Lepb - 11); + + /* update markers struct */ + j2k_add_marker(j2k->cstr_info, J2K_MS_EPB, -1, epb->Lepb + 2); + +}; + + +jpwl_epc_ms_t *jpwl_epc_create(opj_j2k_t *j2k, bool esd_on, bool red_on, bool epb_on, bool info_on) { + + jpwl_epc_ms_t *epc = NULL; + + /* Alloc space */ + if (!(epc = (jpwl_epc_ms_t *) opj_malloc((size_t) 1 * sizeof (jpwl_epc_ms_t)))) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "Could not allocate room for EPC MS\n"); + return NULL; + }; + + /* Set the EPC parameters */ + epc->esd_on = esd_on; + epc->epb_on = epb_on; + epc->red_on = red_on; + epc->info_on = info_on; + + /* Fill the EPC fields with default values */ + epc->Lepc = 9; + epc->Pcrc = 0x0000; + epc->DL = 0x00000000; + epc->Pepc = ((j2k->cp->esd_on & 0x0001) << 4) | ((j2k->cp->red_on & 0x0001) << 5) | + ((j2k->cp->epb_on & 0x0001) << 6) | ((j2k->cp->info_on & 0x0001) << 7); + + return (epc); +} + +bool jpwl_epb_fill(opj_j2k_t *j2k, jpwl_epb_ms_t *epb, unsigned char *buf, unsigned char *post_buf) { + + unsigned long int L1, L2, L3, L4; + int remaining; + unsigned long int P, NN_P; + + /* Operating buffer */ + static unsigned char codeword[NN], *parityword; + + unsigned char *L1_buf, *L2_buf; + /* these ones are static, since we need to keep memory of + the exact place from one call to the other */ + static unsigned char *L3_buf, *L4_buf; + + /* some consistency check */ + if (!buf) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "There is no operating buffer for EPBs\n"); + return false; + } + + if (!post_buf && !L4_buf) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "There is no operating buffer for EPBs data\n"); + return false; + } + + /* + * Compute parity bytes on pre-data, ALWAYS present (at least only for EPB parms) + */ + + /* Initialize RS structures */ + P = epb->n_pre - epb->k_pre; + NN_P = NN - P; + memset(codeword, 0, NN); + parityword = codeword + NN_P; + init_rs(NN_P); + + /* pre-data begins pre_len bytes before of EPB buf */ + L1_buf = buf - epb->pre_len; + L1 = epb->pre_len + 13; + + /* redundancy for pre-data begins immediately after EPB parms */ + L2_buf = buf + 13; + L2 = (epb->n_pre - epb->k_pre) * (unsigned short int) ceil((double) L1 / (double) epb->k_pre); + + /* post-data + the position of L4 buffer can be: + 1) passed as a parameter: in that case use it + 2) null: in that case use the previous (static) one + */ + if (post_buf) + L4_buf = post_buf; + L4 = epb->post_len; + + /* post-data redundancy begins immediately after pre-data redundancy */ + L3_buf = L2_buf + L2; + L3 = (epb->n_post - epb->k_post) * (unsigned short int) ceil((double) L4 / (double) epb->k_post); + + /* let's check whether EPB length is sufficient to contain all these data */ + if (epb->Lepb < (11 + L2 + L3)) + opj_event_msg(j2k->cinfo, EVT_ERROR, "There is no room in EPB data field for writing redundancy data\n"); + /*printf("Env. %d, nec. %d (%d + %d)\n", epb->Lepb - 11, L2 + L3, L2, L3);*/ + + /* Compute redundancy of pre-data message words */ + remaining = L1; + while (remaining) { + + /* copy message data into codeword buffer */ + if (remaining < epb->k_pre) { + /* the last message word is zero-padded */ + memset(codeword, 0, NN); + memcpy(codeword, L1_buf, remaining); + L1_buf += remaining; + remaining = 0; + + } else { + memcpy(codeword, L1_buf, epb->k_pre); + L1_buf += epb->k_pre; + remaining -= epb->k_pre; + + } + + /* Encode the buffer and obtain parity bytes */ + if (encode_rs(codeword, parityword)) + opj_event_msg(j2k->cinfo, EVT_WARNING, + "Possible encoding error in codeword @ position #%d\n", (L1_buf - buf) / epb->k_pre); + + /* copy parity bytes only in redundancy buffer */ + memcpy(L2_buf, parityword, P); + + /* advance parity buffer */ + L2_buf += P; + } + + /* + * Compute parity bytes on post-data, may be absent if there are no data + */ + /*printf("Hprot is %d (tileno=%d, k_pre=%d, n_pre=%d, k_post=%d, n_post=%d, pre_len=%d, post_len=%d)\n", + epb->hprot, epb->tileno, epb->k_pre, epb->n_pre, epb->k_post, epb->n_post, epb->pre_len, + epb->post_len);*/ + if (epb->hprot < 0) { + + /* there should be no EPB */ + + } else if (epb->hprot == 0) { + + /* no protection for the data */ + /* advance anyway */ + L4_buf += epb->post_len; + + } else if (epb->hprot == 16) { + + /* CRC-16 */ + unsigned short int mycrc = 0x0000; + + /* compute the CRC field (excluding itself) */ + remaining = L4; + while (remaining--) + jpwl_updateCRC16(&mycrc, *(L4_buf++)); + + /* write the CRC field */ + *(L3_buf++) = (unsigned char) (mycrc >> 8); + *(L3_buf++) = (unsigned char) (mycrc >> 0); + + } else if (epb->hprot == 32) { + + /* CRC-32 */ + unsigned long int mycrc = 0x00000000; + + /* compute the CRC field (excluding itself) */ + remaining = L4; + while (remaining--) + jpwl_updateCRC32(&mycrc, *(L4_buf++)); + + /* write the CRC field */ + *(L3_buf++) = (unsigned char) (mycrc >> 24); + *(L3_buf++) = (unsigned char) (mycrc >> 16); + *(L3_buf++) = (unsigned char) (mycrc >> 8); + *(L3_buf++) = (unsigned char) (mycrc >> 0); + + } else { + + /* RS */ + + /* Initialize RS structures */ + P = epb->n_post - epb->k_post; + NN_P = NN - P; + memset(codeword, 0, NN); + parityword = codeword + NN_P; + init_rs(NN_P); + + /* Compute redundancy of post-data message words */ + remaining = L4; + while (remaining) { + + /* copy message data into codeword buffer */ + if (remaining < epb->k_post) { + /* the last message word is zero-padded */ + memset(codeword, 0, NN); + memcpy(codeword, L4_buf, remaining); + L4_buf += remaining; + remaining = 0; + + } else { + memcpy(codeword, L4_buf, epb->k_post); + L4_buf += epb->k_post; + remaining -= epb->k_post; + + } + + /* Encode the buffer and obtain parity bytes */ + if (encode_rs(codeword, parityword)) + opj_event_msg(j2k->cinfo, EVT_WARNING, + "Possible encoding error in codeword @ position #%d\n", (L4_buf - buf) / epb->k_post); + + /* copy parity bytes only in redundancy buffer */ + memcpy(L3_buf, parityword, P); + + /* advance parity buffer */ + L3_buf += P; + } + + } + + return true; +} + + +bool jpwl_correct(opj_j2k_t *j2k) { + + opj_cio_t *cio = j2k->cio; + bool status; + static bool mh_done = false; + int mark_pos, id, len, skips, sot_pos; + unsigned long int Psot = 0; + + /* go back to marker position */ + mark_pos = cio_tell(cio) - 2; + cio_seek(cio, mark_pos); + + if ((j2k->state == J2K_STATE_MHSOC) && !mh_done) { + + int mark_val = 0, skipnum = 0; + + /* + COLOR IMAGE + first thing to do, if we are here, is to look whether + 51 (skipnum) positions ahead there is an EPB, in case of MH + */ + /* + B/W IMAGE + first thing to do, if we are here, is to look whether + 45 (skipnum) positions ahead there is an EPB, in case of MH + */ + /* SIZ SIZ_FIELDS SIZ_COMPS FOLLOWING_MARKER */ + skipnum = 2 + 38 + 3 * j2k->cp->exp_comps + 2; + if ((cio->bp + skipnum) < cio->end) { + + cio_skip(cio, skipnum); + + /* check that you are not going beyond the end of codestream */ + + /* call EPB corrector */ + status = jpwl_epb_correct(j2k, /* J2K decompressor handle */ + cio->bp, /* pointer to EPB in codestream buffer */ + 0, /* EPB type: MH */ + skipnum, /* length of pre-data */ + -1, /* length of post-data: -1 means auto */ + NULL, + NULL + ); + + /* read the marker value */ + mark_val = (*(cio->bp) << 8) | *(cio->bp + 1); + + if (status && (mark_val == J2K_MS_EPB)) { + /* we found it! */ + mh_done = true; + return true; + } + + /* Disable correction in case of missing or bad head EPB */ + /* We can't do better! */ + /* PATCHED: 2008-01-25 */ + /* MOVED UP: 2008-02-01 */ + if (!status) { + j2k->cp->correct = false; + opj_event_msg(j2k->cinfo, EVT_WARNING, "Couldn't find the MH EPB: disabling JPWL\n"); + } + + } + + } + + if (true /*(j2k->state == J2K_STATE_TPHSOT) || (j2k->state == J2K_STATE_TPH)*/) { + /* else, look if 12 positions ahead there is an EPB, in case of TPH */ + cio_seek(cio, mark_pos); + if ((cio->bp + 12) < cio->end) { + + cio_skip(cio, 12); + + /* call EPB corrector */ + status = jpwl_epb_correct(j2k, /* J2K decompressor handle */ + cio->bp, /* pointer to EPB in codestream buffer */ + 1, /* EPB type: TPH */ + 12, /* length of pre-data */ + -1, /* length of post-data: -1 means auto */ + NULL, + NULL + ); + if (status) + /* we found it! */ + return true; + } + } + + return false; + + /* for now, don't use this code */ + + /* else, look if here is an EPB, in case of other */ + if (mark_pos > 64) { + /* it cannot stay before the first MH EPB */ + cio_seek(cio, mark_pos); + cio_skip(cio, 0); + + /* call EPB corrector */ + status = jpwl_epb_correct(j2k, /* J2K decompressor handle */ + cio->bp, /* pointer to EPB in codestream buffer */ + 2, /* EPB type: TPH */ + 0, /* length of pre-data */ + -1, /* length of post-data: -1 means auto */ + NULL, + NULL + ); + if (status) + /* we found it! */ + return true; + } + + /* nope, no EPBs probably, or they are so damaged that we can give up */ + return false; + + return true; + + /* AN ATTEMPT OF PARSER */ + /* NOT USED ACTUALLY */ + + /* go to the beginning of the file */ + cio_seek(cio, 0); + + /* let's begin */ + j2k->state = J2K_STATE_MHSOC; + + /* cycle all over the markers */ + while (cio_tell(cio) < cio->length) { + + /* read the marker */ + mark_pos = cio_tell(cio); + id = cio_read(cio, 2); + + /* details */ + printf("Marker@%d: %X\n", cio_tell(cio) - 2, id); + + /* do an action in response to the read marker */ + switch (id) { + + /* short markers */ + + /* SOC */ + case J2K_MS_SOC: + j2k->state = J2K_STATE_MHSIZ; + len = 0; + skips = 0; + break; + + /* EOC */ + case J2K_MS_EOC: + j2k->state = J2K_STATE_MT; + len = 0; + skips = 0; + break; + + /* particular case of SOD */ + case J2K_MS_SOD: + len = Psot - (mark_pos - sot_pos) - 2; + skips = len; + break; + + /* long markers */ + + /* SOT */ + case J2K_MS_SOT: + j2k->state = J2K_STATE_TPH; + sot_pos = mark_pos; /* position of SOT */ + len = cio_read(cio, 2); /* read the length field */ + cio_skip(cio, 2); /* this field is unnecessary */ + Psot = cio_read(cio, 4); /* tile length */ + skips = len - 8; + break; + + /* remaining */ + case J2K_MS_SIZ: + j2k->state = J2K_STATE_MH; + /* read the length field */ + len = cio_read(cio, 2); + skips = len - 2; + break; + + /* remaining */ + default: + /* read the length field */ + len = cio_read(cio, 2); + skips = len - 2; + break; + + } + + /* skip to marker's end */ + cio_skip(cio, skips); + + } + + +} + +bool jpwl_epb_correct(opj_j2k_t *j2k, unsigned char *buffer, int type, int pre_len, int post_len, int *conn, + unsigned char **L4_bufp) { + + /* Operating buffer */ + unsigned char codeword[NN], *parityword; + + unsigned long int P, NN_P; + unsigned long int L1, L4; + int remaining, n_pre, k_pre, n_post, k_post; + + int status, tt; + + int orig_pos = cio_tell(j2k->cio); + + unsigned char *L1_buf, *L2_buf; + unsigned char *L3_buf, *L4_buf; + + unsigned long int LDPepb, Pepb; + unsigned short int Lepb; + unsigned char Depb; + char str1[25] = ""; + int myconn, errnum = 0; + bool errflag = false; + + opj_cio_t *cio = j2k->cio; + + /* check for common errors */ + if (!buffer) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "The EPB pointer is a NULL buffer\n"); + return false; + } + + /* set bignesses */ + L1 = pre_len + 13; + + /* pre-data correction */ + switch (type) { + + case 0: + /* MH EPB */ + k_pre = 64; + n_pre = 160; + break; + + case 1: + /* TPH EPB */ + k_pre = 25; + n_pre = 80; + break; + + case 2: + /* other EPBs */ + k_pre = 13; + n_pre = 40; + break; + + case 3: + /* automatic setup */ + opj_event_msg(j2k->cinfo, EVT_ERROR, "Auto. setup not yet implemented\n"); + return false; + break; + + default: + /* unknown type */ + opj_event_msg(j2k->cinfo, EVT_ERROR, "Unknown expected EPB type\n"); + return false; + break; + + } + + /* Initialize RS structures */ + P = n_pre - k_pre; + NN_P = NN - P; + tt = (int) floor((float) P / 2.0F); /* correction capability of the code */ + memset(codeword, 0, NN); + parityword = codeword + NN_P; + init_rs(NN_P); + + /* Correct pre-data message words */ + L1_buf = buffer - pre_len; + L2_buf = buffer + 13; + remaining = L1; + while (remaining) { + + /* always zero-pad codewords */ + /* (this is required, since after decoding the zeros in the long codeword + could change, and keep unchanged in subsequent calls) */ + memset(codeword, 0, NN); + + /* copy codeword buffer into message bytes */ + if (remaining < k_pre) + memcpy(codeword, L1_buf, remaining); + else + memcpy(codeword, L1_buf, k_pre); + + /* copy redundancy buffer in parity bytes */ + memcpy(parityword, L2_buf, P); + + /* Decode the buffer and possibly obtain corrected bytes */ + status = eras_dec_rs(codeword, NULL, 0); + if (status == -1) { + /*if (conn == NULL) + opj_event_msg(j2k->cinfo, EVT_WARNING, + "Possible decoding error in codeword @ position #%d\n", (L1_buf - buffer) / k_pre);*/ + errflag = true; + /* we can try to safely get out from the function: + if we are here, either this is not an EPB or the first codeword + is too damaged to be helpful */ + /*return false;*/ + + } else if (status == 0) { + /*if (conn == NULL) + opj_event_msg(j2k->cinfo, EVT_INFO, "codeword is correctly decoded\n");*/ + + } else if (status <= tt) { + /* it has corrected 0 <= errs <= tt */ + /*if (conn == NULL) + opj_event_msg(j2k->cinfo, EVT_WARNING, "%d errors corrected in codeword\n", status);*/ + errnum += status; + + } else { + /*if (conn == NULL) + opj_event_msg(j2k->cinfo, EVT_WARNING, "EPB correction capability exceeded\n"); + return false;*/ + errflag = true; + } + + + /* advance parity buffer */ + if ((status >= 0) && (status <= tt)) + /* copy back corrected parity only if all is OK */ + memcpy(L2_buf, parityword, P); + L2_buf += P; + + /* advance message buffer */ + if (remaining < k_pre) { + if ((status >= 0) && (status <= tt)) + /* copy back corrected data only if all is OK */ + memcpy(L1_buf, codeword, remaining); + L1_buf += remaining; + remaining = 0; + + } else { + if ((status >= 0) && (status <= tt)) + /* copy back corrected data only if all is OK */ + memcpy(L1_buf, codeword, k_pre); + L1_buf += k_pre; + remaining -= k_pre; + + } + } + + /* print summary */ + if (!conn) { + + /*if (errnum) + opj_event_msg(j2k->cinfo, EVT_INFO, "+ %d symbol errors corrected (Ps=%.1e)\n", errnum, + (float) errnum / ((float) n_pre * (float) L1 / (float) k_pre));*/ + if (errflag) { + /*opj_event_msg(j2k->cinfo, EVT_INFO, "+ there were unrecoverable errors\n");*/ + return false; + } + + } + + /* presumably, now, EPB parameters are correct */ + /* let's get them */ + + /* Simply read the EPB parameters */ + if (conn) + cio->bp = buffer; + cio_skip(cio, 2); /* the marker */ + Lepb = cio_read(cio, 2); + Depb = cio_read(cio, 1); + LDPepb = cio_read(cio, 4); + Pepb = cio_read(cio, 4); + + /* What does Pepb tells us about the protection method? */ + if (((Pepb & 0xF0000000) >> 28) == 0) + sprintf(str1, "pred"); /* predefined */ + else if (((Pepb & 0xF0000000) >> 28) == 1) + sprintf(str1, "crc-%lu", 16 * ((Pepb & 0x00000001) + 1)); /* CRC mode */ + else if (((Pepb & 0xF0000000) >> 28) == 2) + sprintf(str1, "rs(%lu,32)", (Pepb & 0x0000FF00) >> 8); /* RS mode */ + else if (Pepb == 0xFFFFFFFF) + sprintf(str1, "nometh"); /* RS mode */ + else + sprintf(str1, "unknown"); /* unknown */ + + /* Now we write them to screen */ + if (!conn && post_len) + opj_event_msg(j2k->cinfo, EVT_INFO, + "EPB(%d): (%sl, %sp, %u), %lu, %s\n", + cio_tell(cio) - 13, + (Depb & 0x40) ? "" : "n", /* latest EPB or not? */ + (Depb & 0x80) ? "" : "n", /* packed or unpacked EPB? */ + (Depb & 0x3F), /* EPB index value */ + LDPepb, /*length of the data protected by the EPB */ + str1); /* protection method */ + + + /* well, we need to investigate how long is the connected length of packed EPBs */ + myconn = Lepb + 2; + if ((Depb & 0x40) == 0) /* not latest in header */ + jpwl_epb_correct(j2k, /* J2K decompressor handle */ + buffer + Lepb + 2, /* pointer to next EPB in codestream buffer */ + 2, /* EPB type: should be of other type */ + 0, /* only EPB fields */ + 0, /* do not look after */ + &myconn, + NULL + ); + if (conn) + *conn += myconn; + + /*if (!conn) + printf("connected = %d\n", myconn);*/ + + /*cio_seek(j2k->cio, orig_pos); + return true;*/ + + /* post-data + the position of L4 buffer is at the end of currently connected EPBs + */ + if (!(L4_bufp)) + L4_buf = buffer + myconn; + else if (!(*L4_bufp)) + L4_buf = buffer + myconn; + else + L4_buf = *L4_bufp; + if (post_len == -1) + L4 = LDPepb - pre_len - 13; + else if (post_len == 0) + L4 = 0; + else + L4 = post_len; + + L3_buf = L2_buf; + + /* Do a further check here on the read parameters */ + if (L4 > (unsigned long) cio_numbytesleft(j2k->cio)) + /* overflow */ + return false; + + /* we are ready for decoding the remaining data */ + if (((Pepb & 0xF0000000) >> 28) == 1) { + /* CRC here */ + if ((16 * ((Pepb & 0x00000001) + 1)) == 16) { + + /* CRC-16 */ + unsigned short int mycrc = 0x0000, filecrc = 0x0000; + + /* compute the CRC field */ + remaining = L4; + while (remaining--) + jpwl_updateCRC16(&mycrc, *(L4_buf++)); + + /* read the CRC field */ + filecrc = *(L3_buf++) << 8; + filecrc |= *(L3_buf++); + + /* check the CRC field */ + if (mycrc == filecrc) { + if (conn == NULL) + opj_event_msg(j2k->cinfo, EVT_INFO, "- CRC is OK\n"); + } else { + if (conn == NULL) + opj_event_msg(j2k->cinfo, EVT_WARNING, "- CRC is KO (r=%d, c=%d)\n", filecrc, mycrc); + errflag = true; + } + } + + if ((16 * ((Pepb & 0x00000001) + 1)) == 32) { + + /* CRC-32 */ + unsigned long int mycrc = 0x00000000, filecrc = 0x00000000; + + /* compute the CRC field */ + remaining = L4; + while (remaining--) + jpwl_updateCRC32(&mycrc, *(L4_buf++)); + + /* read the CRC field */ + filecrc = *(L3_buf++) << 24; + filecrc |= *(L3_buf++) << 16; + filecrc |= *(L3_buf++) << 8; + filecrc |= *(L3_buf++); + + /* check the CRC field */ + if (mycrc == filecrc) { + if (conn == NULL) + opj_event_msg(j2k->cinfo, EVT_INFO, "- CRC is OK\n"); + } else { + if (conn == NULL) + opj_event_msg(j2k->cinfo, EVT_WARNING, "- CRC is KO (r=%d, c=%d)\n", filecrc, mycrc); + errflag = true; + } + } + + } else if (Pepb == 0xFFFFFFFF) { + /* no method */ + + /* advance without doing anything */ + remaining = L4; + while (remaining--) + L4_buf++; + + } else if ((((Pepb & 0xF0000000) >> 28) == 2) || (((Pepb & 0xF0000000) >> 28) == 0)) { + /* RS coding here */ + + if (((Pepb & 0xF0000000) >> 28) == 0) { + + k_post = k_pre; + n_post = n_pre; + + } else { + + k_post = 32; + n_post = (Pepb & 0x0000FF00) >> 8; + } + + /* Initialize RS structures */ + P = n_post - k_post; + NN_P = NN - P; + tt = (int) floor((float) P / 2.0F); /* again, correction capability */ + memset(codeword, 0, NN); + parityword = codeword + NN_P; + init_rs(NN_P); + + /* Correct post-data message words */ + /*L4_buf = buffer + Lepb + 2;*/ + L3_buf = L2_buf; + remaining = L4; + while (remaining) { + + /* always zero-pad codewords */ + /* (this is required, since after decoding the zeros in the long codeword + could change, and keep unchanged in subsequent calls) */ + memset(codeword, 0, NN); + + /* copy codeword buffer into message bytes */ + if (remaining < k_post) + memcpy(codeword, L4_buf, remaining); + else + memcpy(codeword, L4_buf, k_post); + + /* copy redundancy buffer in parity bytes */ + memcpy(parityword, L3_buf, P); + + /* Decode the buffer and possibly obtain corrected bytes */ + status = eras_dec_rs(codeword, NULL, 0); + if (status == -1) { + /*if (conn == NULL) + opj_event_msg(j2k->cinfo, EVT_WARNING, + "Possible decoding error in codeword @ position #%d\n", (L4_buf - (buffer + Lepb + 2)) / k_post);*/ + errflag = true; + + } else if (status == 0) { + /*if (conn == NULL) + opj_event_msg(j2k->cinfo, EVT_INFO, "codeword is correctly decoded\n");*/ + + } else if (status <= tt) { + /*if (conn == NULL) + opj_event_msg(j2k->cinfo, EVT_WARNING, "%d errors corrected in codeword\n", status);*/ + errnum += status; + + } else { + /*if (conn == NULL) + opj_event_msg(j2k->cinfo, EVT_WARNING, "EPB correction capability exceeded\n"); + return false;*/ + errflag = true; + } + + + /* advance parity buffer */ + if ((status >= 0) && (status <= tt)) + /* copy back corrected data only if all is OK */ + memcpy(L3_buf, parityword, P); + L3_buf += P; + + /* advance message buffer */ + if (remaining < k_post) { + if ((status >= 0) && (status <= tt)) + /* copy back corrected data only if all is OK */ + memcpy(L4_buf, codeword, remaining); + L4_buf += remaining; + remaining = 0; + + } else { + if ((status >= 0) && (status <= tt)) + /* copy back corrected data only if all is OK */ + memcpy(L4_buf, codeword, k_post); + L4_buf += k_post; + remaining -= k_post; + + } + } + } + + /* give back the L4_buf address */ + if (L4_bufp) + *L4_bufp = L4_buf; + + /* print summary */ + if (!conn) { + + if (errnum) + opj_event_msg(j2k->cinfo, EVT_INFO, "- %d symbol errors corrected (Ps=%.1e)\n", errnum, + (float) errnum / (float) LDPepb); + if (errflag) + opj_event_msg(j2k->cinfo, EVT_INFO, "- there were unrecoverable errors\n"); + + } + + cio_seek(j2k->cio, orig_pos); + + return true; +} + +void jpwl_epc_write(opj_j2k_t *j2k, jpwl_epc_ms_t *epc, unsigned char *buf) { + + /* Marker */ + *(buf++) = (unsigned char) (J2K_MS_EPC >> 8); + *(buf++) = (unsigned char) (J2K_MS_EPC >> 0); + + /* Lepc */ + *(buf++) = (unsigned char) (epc->Lepc >> 8); + *(buf++) = (unsigned char) (epc->Lepc >> 0); + + /* Pcrc */ + *(buf++) = (unsigned char) (epc->Pcrc >> 8); + *(buf++) = (unsigned char) (epc->Pcrc >> 0); + + /* DL */ + *(buf++) = (unsigned char) (epc->DL >> 24); + *(buf++) = (unsigned char) (epc->DL >> 16); + *(buf++) = (unsigned char) (epc->DL >> 8); + *(buf++) = (unsigned char) (epc->DL >> 0); + + /* Pepc */ + *(buf++) = (unsigned char) (epc->Pepc >> 0); + + /* Data */ + /*memcpy(buf, epc->data, (size_t) epc->Lepc - 9);*/ + memset(buf, 0, (size_t) epc->Lepc - 9); + + /* update markers struct */ + j2k_add_marker(j2k->cstr_info, J2K_MS_EPC, -1, epc->Lepc + 2); + +}; + +int jpwl_esds_add(opj_j2k_t *j2k, jpwl_marker_t *jwmarker, int *jwmarker_num, + int comps, unsigned char addrm, unsigned char ad_size, + unsigned char senst, unsigned char se_size, + double place_pos, int tileno) { + + return 0; +} + +jpwl_esd_ms_t *jpwl_esd_create(opj_j2k_t *j2k, int comp, unsigned char addrm, unsigned char ad_size, + unsigned char senst, unsigned char se_size, int tileno, + unsigned long int svalnum, void *sensval) { + + jpwl_esd_ms_t *esd = NULL; + + /* Alloc space */ + if (!(esd = (jpwl_esd_ms_t *) opj_malloc((size_t) 1 * sizeof (jpwl_esd_ms_t)))) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "Could not allocate room for ESD MS\n"); + return NULL; + }; + + /* if relative sensitivity, activate byte range mode */ + if (senst == 0) + addrm = 1; + + /* size of sensval's ... */ + if ((ad_size != 0) && (ad_size != 2) && (ad_size != 4)) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "Address size %d for ESD MS is forbidden\n", ad_size); + return NULL; + } + if ((se_size != 1) && (se_size != 2)) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "Sensitivity size %d for ESD MS is forbidden\n", se_size); + return NULL; + } + + /* ... depends on the addressing mode */ + switch (addrm) { + + /* packet mode */ + case (0): + ad_size = 0; /* as per the standard */ + esd->sensval_size = se_size; + break; + + /* byte range */ + case (1): + /* auto sense address size */ + if (ad_size == 0) + /* if there are more than 66% of (2^16 - 1) bytes, switch to 4 bytes + (we keep space for possible EPBs being inserted) */ + ad_size = (j2k->cstr_info->codestream_size > (1 * 65535 / 3)) ? 4 : 2; + esd->sensval_size = ad_size + ad_size + se_size; + break; + + /* packet range */ + case (2): + /* auto sense address size */ + if (ad_size == 0) + /* if there are more than 2^16 - 1 packets, switch to 4 bytes */ + ad_size = (j2k->cstr_info->packno > 65535) ? 4 : 2; + esd->sensval_size = ad_size + ad_size + se_size; + break; + + case (3): + opj_event_msg(j2k->cinfo, EVT_ERROR, "Address mode %d for ESD MS is unimplemented\n", addrm); + return NULL; + + default: + opj_event_msg(j2k->cinfo, EVT_ERROR, "Address mode %d for ESD MS is forbidden\n", addrm); + return NULL; + } + + /* set or unset sensitivity values */ + if (svalnum <= 0) { + + switch (senst) { + + /* just based on the portions of a codestream */ + case (0): + /* MH + no. of THs + no. of packets */ + svalnum = 1 + (j2k->cstr_info->tw * j2k->cstr_info->th) * (1 + j2k->cstr_info->packno); + break; + + /* all the ones that are based on the packets */ + default: + if (tileno < 0) + /* MH: all the packets and all the tiles info is written */ + svalnum = j2k->cstr_info->tw * j2k->cstr_info->th * j2k->cstr_info->packno; + else + /* TPH: only that tile info is written */ + svalnum = j2k->cstr_info->packno; + break; + + } + } + + /* fill private fields */ + esd->senst = senst; + esd->ad_size = ad_size; + esd->se_size = se_size; + esd->addrm = addrm; + esd->svalnum = svalnum; + esd->numcomps = j2k->image->numcomps; + esd->tileno = tileno; + + /* Set the ESD parameters */ + /* length, excluding data field */ + if (esd->numcomps < 257) + esd->Lesd = 4 + (unsigned short int) (esd->svalnum * esd->sensval_size); + else + esd->Lesd = 5 + (unsigned short int) (esd->svalnum * esd->sensval_size); + + /* component data field */ + if (comp >= 0) + esd->Cesd = comp; + else + /* we are averaging */ + esd->Cesd = 0; + + /* Pesd field */ + esd->Pesd = 0x00; + esd->Pesd |= (esd->addrm & 0x03) << 6; /* addressing mode */ + esd->Pesd |= (esd->senst & 0x07) << 3; /* sensitivity type */ + esd->Pesd |= ((esd->se_size >> 1) & 0x01) << 2; /* sensitivity size */ + esd->Pesd |= ((esd->ad_size >> 2) & 0x01) << 1; /* addressing size */ + esd->Pesd |= (comp < 0) ? 0x01 : 0x00; /* averaging components */ + + /* if pointer to sensval is NULL, we can fill data field by ourselves */ + if (!sensval) { + + /* old code moved to jpwl_esd_fill() */ + esd->data = NULL; + + } else { + /* we set the data field as the sensitivity values poinnter passed to the function */ + esd->data = (unsigned char *) sensval; + } + + return (esd); +} + +bool jpwl_esd_fill(opj_j2k_t *j2k, jpwl_esd_ms_t *esd, unsigned char *buf) { + + int i; + unsigned long int vv; + unsigned long int addr1 = 0L, addr2 = 0L; + double dvalue = 0.0, Omax2, tmp, TSE = 0.0, MSE, oldMSE = 0.0, PSNR, oldPSNR = 0.0; + unsigned short int pfpvalue; + unsigned long int addrmask = 0x00000000; + bool doneMH = false, doneTPH = false; + + /* sensitivity values in image info are as follows: + - for each tile, distotile is the starting distortion for that tile, sum of all components + - for each packet in a tile, disto is the distortion reduction caused by that packet to that tile + - the TSE for a single tile should be given by distotile - sum(disto) , for all components + - the MSE for a single tile is given by TSE / nbpix , for all components + - the PSNR for a single tile is given by 10*log10( Omax^2 / MSE) , for all components + (Omax is given by 2^bpp - 1 for unsigned images and by 2^(bpp - 1) - 1 for signed images + */ + + /* browse all components and find Omax */ + Omax2 = 0.0; + for (i = 0; i < j2k->image->numcomps; i++) { + tmp = pow(2.0, (double) (j2k->image->comps[i].sgnd ? + (j2k->image->comps[i].bpp - 1) : (j2k->image->comps[i].bpp))) - 1; + if (tmp > Omax2) + Omax2 = tmp; + } + Omax2 = Omax2 * Omax2; + + /* if pointer of esd->data is not null, simply write down all the values byte by byte */ + if (esd->data) { + for (i = 0; i < (int) esd->svalnum; i++) + *(buf++) = esd->data[i]; + return true; + } + + /* addressing mask */ + if (esd->ad_size == 2) + addrmask = 0x0000FFFF; /* two bytes */ + else + addrmask = 0xFFFFFFFF; /* four bytes */ + + /* set on precise point where sensitivity starts */ + if (esd->numcomps < 257) + buf += 6; + else + buf += 7; + + /* let's fill the data fields */ + for (vv = (esd->tileno < 0) ? 0 : (j2k->cstr_info->packno * esd->tileno); vv < esd->svalnum; vv++) { + + int thistile = vv / j2k->cstr_info->packno, thispacket = vv % j2k->cstr_info->packno; + + /* skip for the hack some lines below */ + if (thistile == j2k->cstr_info->tw * j2k->cstr_info->th) + break; + + /* starting tile distortion */ + if (thispacket == 0) { + TSE = j2k->cstr_info->tile[thistile].distotile; + oldMSE = TSE / j2k->cstr_info->tile[thistile].numpix; + oldPSNR = 10.0 * log10(Omax2 / oldMSE); + } + + /* TSE */ + TSE -= j2k->cstr_info->tile[thistile].packet[thispacket].disto; + + /* MSE */ + MSE = TSE / j2k->cstr_info->tile[thistile].numpix; + + /* PSNR */ + PSNR = 10.0 * log10(Omax2 / MSE); + + /* fill the address range */ + switch (esd->addrm) { + + /* packet mode */ + case (0): + /* nothing, there is none */ + break; + + /* byte range */ + case (1): + /* start address of packet */ + addr1 = (j2k->cstr_info->tile[thistile].packet[thispacket].start_pos) & addrmask; + /* end address of packet */ + addr2 = (j2k->cstr_info->tile[thistile].packet[thispacket].end_pos) & addrmask; + break; + + /* packet range */ + case (2): + /* not implemented here */ + opj_event_msg(j2k->cinfo, EVT_WARNING, "Addressing mode packet_range is not implemented\n"); + break; + + /* unknown addressing method */ + default: + /* not implemented here */ + opj_event_msg(j2k->cinfo, EVT_WARNING, "Unknown addressing mode\n"); + break; + + } + + /* hack for writing relative sensitivity of MH and TPHs */ + if ((esd->senst == 0) && (thispacket == 0)) { + + /* possible MH */ + if ((thistile == 0) && !doneMH) { + /* we have to manage MH addresses */ + addr1 = 0; /* start of MH */ + addr2 = j2k->cstr_info->main_head_end; /* end of MH */ + /* set special dvalue for this MH */ + dvalue = -10.0; + doneMH = true; /* don't come here anymore */ + vv--; /* wrap back loop counter */ + + } else if (!doneTPH) { + /* we have to manage TPH addresses */ + addr1 = j2k->cstr_info->tile[thistile].start_pos; + addr2 = j2k->cstr_info->tile[thistile].end_header; + /* set special dvalue for this TPH */ + dvalue = -1.0; + doneTPH = true; /* don't come here till the next tile */ + vv--; /* wrap back loop counter */ + } + + } else + doneTPH = false; /* reset TPH counter */ + + /* write the addresses to the buffer */ + switch (esd->ad_size) { + + case (0): + /* do nothing */ + break; + + case (2): + /* two bytes */ + *(buf++) = (unsigned char) (addr1 >> 8); + *(buf++) = (unsigned char) (addr1 >> 0); + *(buf++) = (unsigned char) (addr2 >> 8); + *(buf++) = (unsigned char) (addr2 >> 0); + break; + + case (4): + /* four bytes */ + *(buf++) = (unsigned char) (addr1 >> 24); + *(buf++) = (unsigned char) (addr1 >> 16); + *(buf++) = (unsigned char) (addr1 >> 8); + *(buf++) = (unsigned char) (addr1 >> 0); + *(buf++) = (unsigned char) (addr2 >> 24); + *(buf++) = (unsigned char) (addr2 >> 16); + *(buf++) = (unsigned char) (addr2 >> 8); + *(buf++) = (unsigned char) (addr2 >> 0); + break; + + default: + /* do nothing */ + break; + } + + + /* let's fill the value field */ + switch (esd->senst) { + + /* relative sensitivity */ + case (0): + /* we just write down the packet ordering */ + if (dvalue == -10) + /* MH */ + dvalue = MAX_V1 + 1000.0; /* this will cause pfpvalue set to 0xFFFF */ + else if (dvalue == -1) + /* TPH */ + dvalue = MAX_V1 + 1000.0; /* this will cause pfpvalue set to 0xFFFF */ + else + /* packet: first is most important, and then in decreasing order + down to the last, which counts for 1 */ + dvalue = jpwl_pfp_to_double((unsigned short) (j2k->cstr_info->packno - thispacket), esd->se_size); + break; + + /* MSE */ + case (1): + /* !!! WRONG: let's put here disto field of packets !!! */ + dvalue = MSE; + break; + + /* MSE reduction */ + case (2): + dvalue = oldMSE - MSE; + oldMSE = MSE; + break; + + /* PSNR */ + case (3): + dvalue = PSNR; + break; + + /* PSNR increase */ + case (4): + dvalue = PSNR - oldPSNR; + oldPSNR = PSNR; + break; + + /* MAXERR */ + case (5): + dvalue = 0.0; + opj_event_msg(j2k->cinfo, EVT_WARNING, "MAXERR sensitivity mode is not implemented\n"); + break; + + /* TSE */ + case (6): + dvalue = TSE; + break; + + /* reserved */ + case (7): + dvalue = 0.0; + opj_event_msg(j2k->cinfo, EVT_WARNING, "Reserved sensitivity mode is not implemented\n"); + break; + + default: + dvalue = 0.0; + break; + } + + /* compute the pseudo-floating point value */ + pfpvalue = jpwl_double_to_pfp(dvalue, esd->se_size); + + /* write the pfp value to the buffer */ + switch (esd->se_size) { + + case (1): + /* one byte */ + *(buf++) = (unsigned char) (pfpvalue >> 0); + break; + + case (2): + /* two bytes */ + *(buf++) = (unsigned char) (pfpvalue >> 8); + *(buf++) = (unsigned char) (pfpvalue >> 0); + break; + } + + } + + return true; +} + +void jpwl_esd_write(opj_j2k_t *j2k, jpwl_esd_ms_t *esd, unsigned char *buf) { + + /* Marker */ + *(buf++) = (unsigned char) (J2K_MS_ESD >> 8); + *(buf++) = (unsigned char) (J2K_MS_ESD >> 0); + + /* Lesd */ + *(buf++) = (unsigned char) (esd->Lesd >> 8); + *(buf++) = (unsigned char) (esd->Lesd >> 0); + + /* Cesd */ + if (esd->numcomps >= 257) + *(buf++) = (unsigned char) (esd->Cesd >> 8); + *(buf++) = (unsigned char) (esd->Cesd >> 0); + + /* Pesd */ + *(buf++) = (unsigned char) (esd->Pesd >> 0); + + /* Data */ + if (esd->numcomps < 257) + memset(buf, 0xAA, (size_t) esd->Lesd - 4); + /*memcpy(buf, esd->data, (size_t) esd->Lesd - 4);*/ + else + memset(buf, 0xAA, (size_t) esd->Lesd - 5); + /*memcpy(buf, esd->data, (size_t) esd->Lesd - 5);*/ + + /* update markers struct */ + j2k_add_marker(j2k->cstr_info, J2K_MS_ESD, -1, esd->Lesd + 2); + +} + +unsigned short int jpwl_double_to_pfp(double V, int bytes) { + + unsigned short int em, e, m; + + switch (bytes) { + + case (1): + + if (V < MIN_V1) { + e = 0x0000; + m = 0x0000; + } else if (V > MAX_V1) { + e = 0x000F; + m = 0x000F; + } else { + e = (unsigned short int) (floor(log(V) * 1.44269504088896) / 4.0); + m = (unsigned short int) (0.5 + (V / (pow(2.0, (double) (4 * e))))); + } + em = ((e & 0x000F) << 4) + (m & 0x000F); + break; + + case (2): + + if (V < MIN_V2) { + e = 0x0000; + m = 0x0000; + } else if (V > MAX_V2) { + e = 0x001F; + m = 0x07FF; + } else { + e = (unsigned short int) floor(log(V) * 1.44269504088896) + 15; + m = (unsigned short int) (0.5 + 2048.0 * ((V / (pow(2.0, (double) e - 15.0))) - 1.0)); + } + em = ((e & 0x001F) << 11) + (m & 0x07FF); + break; + + default: + + em = 0x0000; + break; + }; + + return em; +} + +double jpwl_pfp_to_double(unsigned short int em, int bytes) { + + double V; + + switch (bytes) { + + case 1: + V = (double) (em & 0x0F) * pow(2.0, (double) (em & 0xF0)); + break; + + case 2: + + V = pow(2.0, (double) ((em & 0xF800) >> 11) - 15.0) * (1.0 + (double) (em & 0x07FF) / 2048.0); + break; + + default: + V = 0.0; + break; + + } + + return V; + +} + +bool jpwl_update_info(opj_j2k_t *j2k, jpwl_marker_t *jwmarker, int jwmarker_num) { + + int mm; + unsigned long int addlen; + + opj_codestream_info_t *info = j2k->cstr_info; + int tileno, tpno, packno, numtiles = info->th * info->tw, numpacks = info->packno; + + if (!j2k || !jwmarker ) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "J2K handle or JPWL markers list badly allocated\n"); + return false; + } + + /* main_head_end: how many markers are there before? */ + addlen = 0; + for (mm = 0; mm < jwmarker_num; mm++) + if (jwmarker[mm].pos < (unsigned long int) info->main_head_end) + addlen += jwmarker[mm].len + 2; + info->main_head_end += addlen; + + /* codestream_size: always increment with all markers */ + addlen = 0; + for (mm = 0; mm < jwmarker_num; mm++) + addlen += jwmarker[mm].len + 2; + info->codestream_size += addlen; + + /* navigate through all the tiles */ + for (tileno = 0; tileno < numtiles; tileno++) { + + /* start_pos: increment with markers before SOT */ + addlen = 0; + for (mm = 0; mm < jwmarker_num; mm++) + if (jwmarker[mm].pos < (unsigned long int) info->tile[tileno].start_pos) + addlen += jwmarker[mm].len + 2; + info->tile[tileno].start_pos += addlen; + + /* end_header: increment with markers before of it */ + addlen = 0; + for (mm = 0; mm < jwmarker_num; mm++) + if (jwmarker[mm].pos < (unsigned long int) info->tile[tileno].end_header) + addlen += jwmarker[mm].len + 2; + info->tile[tileno].end_header += addlen; + + /* end_pos: increment with markers before the end of this tile */ + /* code is disabled, since according to JPWL no markers can be beyond TPH */ + addlen = 0; + for (mm = 0; mm < jwmarker_num; mm++) + if (jwmarker[mm].pos < (unsigned long int) info->tile[tileno].end_pos) + addlen += jwmarker[mm].len + 2; + info->tile[tileno].end_pos += addlen; + + /* navigate through all the tile parts */ + for (tpno = 0; tpno < info->tile[tileno].num_tps; tpno++) { + + /* start_pos: increment with markers before SOT */ + addlen = 0; + for (mm = 0; mm < jwmarker_num; mm++) + if (jwmarker[mm].pos < (unsigned long int) info->tile[tileno].tp[tpno].tp_start_pos) + addlen += jwmarker[mm].len + 2; + info->tile[tileno].tp[tpno].tp_start_pos += addlen; + + /* end_header: increment with markers before of it */ + addlen = 0; + for (mm = 0; mm < jwmarker_num; mm++) + if (jwmarker[mm].pos < (unsigned long int) info->tile[tileno].tp[tpno].tp_end_header) + addlen += jwmarker[mm].len + 2; + info->tile[tileno].tp[tpno].tp_end_header += addlen; + + /* end_pos: increment with markers before the end of this tile part */ + addlen = 0; + for (mm = 0; mm < jwmarker_num; mm++) + if (jwmarker[mm].pos < (unsigned long int) info->tile[tileno].tp[tpno].tp_end_pos) + addlen += jwmarker[mm].len + 2; + info->tile[tileno].tp[tpno].tp_end_pos += addlen; + + } + + /* navigate through all the packets in this tile */ + for (packno = 0; packno < numpacks; packno++) { + + /* start_pos: increment with markers before the packet */ + /* disabled for the same reason as before */ + addlen = 0; + for (mm = 0; mm < jwmarker_num; mm++) + if (jwmarker[mm].pos <= (unsigned long int) info->tile[tileno].packet[packno].start_pos) + addlen += jwmarker[mm].len + 2; + info->tile[tileno].packet[packno].start_pos += addlen; + + /* end_ph_pos: increment with markers before the packet */ + /* disabled for the same reason as before */ + /*addlen = 0; + for (mm = 0; mm < jwmarker_num; mm++) + if (jwmarker[mm].pos < (unsigned long int) info->tile[tileno].packet[packno].end_ph_pos) + addlen += jwmarker[mm].len + 2;*/ + info->tile[tileno].packet[packno].end_ph_pos += addlen; + + /* end_pos: increment if marker is before the end of packet */ + /* disabled for the same reason as before */ + /*addlen = 0; + for (mm = 0; mm < jwmarker_num; mm++) + if (jwmarker[mm].pos < (unsigned long int) info->tile[tileno].packet[packno].end_pos) + addlen += jwmarker[mm].len + 2;*/ + info->tile[tileno].packet[packno].end_pos += addlen; + + } + } + + /* reorder the markers list */ + + return true; +} + +#endif /* USE_JPWL */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jpwl/rs.c b/gdcm/Utilities/gdcmopenjpeg-v1/jpwl/rs.c new file mode 100644 index 0000000..419f083 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jpwl/rs.c @@ -0,0 +1,594 @@ + /* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * Copyright (c) 2005-2006, Dept. of Electronic and Information Engineering, Universita' degli Studi di Perugia, Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef USE_JPWL + +/** +@file rs.c +@brief Functions used to compute the Reed-Solomon parity and check of byte arrays + +*/ + +/** + * Reed-Solomon coding and decoding + * Phil Karn (karn@ka9q.ampr.org) September 1996 + * + * This file is derived from the program "new_rs_erasures.c" by Robert + * Morelos-Zaragoza (robert@spectra.eng.hawaii.edu) and Hari Thirumoorthy + * (harit@spectra.eng.hawaii.edu), Aug 1995 + * + * I've made changes to improve performance, clean up the code and make it + * easier to follow. Data is now passed to the encoding and decoding functions + * through arguments rather than in global arrays. The decode function returns + * the number of corrected symbols, or -1 if the word is uncorrectable. + * + * This code supports a symbol size from 2 bits up to 16 bits, + * implying a block size of 3 2-bit symbols (6 bits) up to 65535 + * 16-bit symbols (1,048,560 bits). The code parameters are set in rs.h. + * + * Note that if symbols larger than 8 bits are used, the type of each + * data array element switches from unsigned char to unsigned int. The + * caller must ensure that elements larger than the symbol range are + * not passed to the encoder or decoder. + * + */ +#include +#include +#include "rs.h" + +/* This defines the type used to store an element of the Galois Field + * used by the code. Make sure this is something larger than a char if + * if anything larger than GF(256) is used. + * + * Note: unsigned char will work up to GF(256) but int seems to run + * faster on the Pentium. + */ +typedef int gf; + +/* Primitive polynomials - see Lin & Costello, Appendix A, + * and Lee & Messerschmitt, p. 453. + */ +#if(MM == 2)/* Admittedly silly */ +int Pp[MM+1] = { 1, 1, 1 }; + +#elif(MM == 3) +/* 1 + x + x^3 */ +int Pp[MM+1] = { 1, 1, 0, 1 }; + +#elif(MM == 4) +/* 1 + x + x^4 */ +int Pp[MM+1] = { 1, 1, 0, 0, 1 }; + +#elif(MM == 5) +/* 1 + x^2 + x^5 */ +int Pp[MM+1] = { 1, 0, 1, 0, 0, 1 }; + +#elif(MM == 6) +/* 1 + x + x^6 */ +int Pp[MM+1] = { 1, 1, 0, 0, 0, 0, 1 }; + +#elif(MM == 7) +/* 1 + x^3 + x^7 */ +int Pp[MM+1] = { 1, 0, 0, 1, 0, 0, 0, 1 }; + +#elif(MM == 8) +/* 1+x^2+x^3+x^4+x^8 */ +int Pp[MM+1] = { 1, 0, 1, 1, 1, 0, 0, 0, 1 }; + +#elif(MM == 9) +/* 1+x^4+x^9 */ +int Pp[MM+1] = { 1, 0, 0, 0, 1, 0, 0, 0, 0, 1 }; + +#elif(MM == 10) +/* 1+x^3+x^10 */ +int Pp[MM+1] = { 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1 }; + +#elif(MM == 11) +/* 1+x^2+x^11 */ +int Pp[MM+1] = { 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; + +#elif(MM == 12) +/* 1+x+x^4+x^6+x^12 */ +int Pp[MM+1] = { 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1 }; + +#elif(MM == 13) +/* 1+x+x^3+x^4+x^13 */ +int Pp[MM+1] = { 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; + +#elif(MM == 14) +/* 1+x+x^6+x^10+x^14 */ +int Pp[MM+1] = { 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1 }; + +#elif(MM == 15) +/* 1+x+x^15 */ +int Pp[MM+1] = { 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; + +#elif(MM == 16) +/* 1+x+x^3+x^12+x^16 */ +int Pp[MM+1] = { 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1 }; + +#else +#error "MM must be in range 2-16" +#endif + +/* Alpha exponent for the first root of the generator polynomial */ +#define B0 0 /* Different from the default 1 */ + +/* index->polynomial form conversion table */ +gf Alpha_to[NN + 1]; + +/* Polynomial->index form conversion table */ +gf Index_of[NN + 1]; + +/* No legal value in index form represents zero, so + * we need a special value for this purpose + */ +#define A0 (NN) + +/* Generator polynomial g(x) + * Degree of g(x) = 2*TT + * has roots @**B0, @**(B0+1), ... ,@^(B0+2*TT-1) + */ +/*gf Gg[NN - KK + 1];*/ +gf Gg[NN - 1]; + +/* Compute x % NN, where NN is 2**MM - 1, + * without a slow divide + */ +static /*inline*/ gf +modnn(int x) +{ + while (x >= NN) { + x -= NN; + x = (x >> MM) + (x & NN); + } + return x; +} + +/*#define min(a,b) ((a) < (b) ? (a) : (b))*/ + +#define CLEAR(a,n) {\ + int ci;\ + for(ci=(n)-1;ci >=0;ci--)\ + (a)[ci] = 0;\ + } + +#define COPY(a,b,n) {\ + int ci;\ + for(ci=(n)-1;ci >=0;ci--)\ + (a)[ci] = (b)[ci];\ + } +#define COPYDOWN(a,b,n) {\ + int ci;\ + for(ci=(n)-1;ci >=0;ci--)\ + (a)[ci] = (b)[ci];\ + } + +void init_rs(int k) +{ + KK = k; + if (KK >= NN) { + printf("KK must be less than 2**MM - 1\n"); + exit(1); + } + + generate_gf(); + gen_poly(); +} + +/* generate GF(2**m) from the irreducible polynomial p(X) in p[0]..p[m] + lookup tables: index->polynomial form alpha_to[] contains j=alpha**i; + polynomial form -> index form index_of[j=alpha**i] = i + alpha=2 is the primitive element of GF(2**m) + HARI's COMMENT: (4/13/94) alpha_to[] can be used as follows: + Let @ represent the primitive element commonly called "alpha" that + is the root of the primitive polynomial p(x). Then in GF(2^m), for any + 0 <= i <= 2^m-2, + @^i = a(0) + a(1) @ + a(2) @^2 + ... + a(m-1) @^(m-1) + where the binary vector (a(0),a(1),a(2),...,a(m-1)) is the representation + of the integer "alpha_to[i]" with a(0) being the LSB and a(m-1) the MSB. Thus for + example the polynomial representation of @^5 would be given by the binary + representation of the integer "alpha_to[5]". + Similarily, index_of[] can be used as follows: + As above, let @ represent the primitive element of GF(2^m) that is + the root of the primitive polynomial p(x). In order to find the power + of @ (alpha) that has the polynomial representation + a(0) + a(1) @ + a(2) @^2 + ... + a(m-1) @^(m-1) + we consider the integer "i" whose binary representation with a(0) being LSB + and a(m-1) MSB is (a(0),a(1),...,a(m-1)) and locate the entry + "index_of[i]". Now, @^index_of[i] is that element whose polynomial + representation is (a(0),a(1),a(2),...,a(m-1)). + NOTE: + The element alpha_to[2^m-1] = 0 always signifying that the + representation of "@^infinity" = 0 is (0,0,0,...,0). + Similarily, the element index_of[0] = A0 always signifying + that the power of alpha which has the polynomial representation + (0,0,...,0) is "infinity". + +*/ + +void +generate_gf(void) +{ + register int i, mask; + + mask = 1; + Alpha_to[MM] = 0; + for (i = 0; i < MM; i++) { + Alpha_to[i] = mask; + Index_of[Alpha_to[i]] = i; + /* If Pp[i] == 1 then, term @^i occurs in poly-repr of @^MM */ + if (Pp[i] != 0) + Alpha_to[MM] ^= mask; /* Bit-wise EXOR operation */ + mask <<= 1; /* single left-shift */ + } + Index_of[Alpha_to[MM]] = MM; + /* + * Have obtained poly-repr of @^MM. Poly-repr of @^(i+1) is given by + * poly-repr of @^i shifted left one-bit and accounting for any @^MM + * term that may occur when poly-repr of @^i is shifted. + */ + mask >>= 1; + for (i = MM + 1; i < NN; i++) { + if (Alpha_to[i - 1] >= mask) + Alpha_to[i] = Alpha_to[MM] ^ ((Alpha_to[i - 1] ^ mask) << 1); + else + Alpha_to[i] = Alpha_to[i - 1] << 1; + Index_of[Alpha_to[i]] = i; + } + Index_of[0] = A0; + Alpha_to[NN] = 0; +} + + +/* + * Obtain the generator polynomial of the TT-error correcting, length + * NN=(2**MM -1) Reed Solomon code from the product of (X+@**(B0+i)), i = 0, + * ... ,(2*TT-1) + * + * Examples: + * + * If B0 = 1, TT = 1. deg(g(x)) = 2*TT = 2. + * g(x) = (x+@) (x+@**2) + * + * If B0 = 0, TT = 2. deg(g(x)) = 2*TT = 4. + * g(x) = (x+1) (x+@) (x+@**2) (x+@**3) + */ +void +gen_poly(void) +{ + register int i, j; + + Gg[0] = Alpha_to[B0]; + Gg[1] = 1; /* g(x) = (X+@**B0) initially */ + for (i = 2; i <= NN - KK; i++) { + Gg[i] = 1; + /* + * Below multiply (Gg[0]+Gg[1]*x + ... +Gg[i]x^i) by + * (@**(B0+i-1) + x) + */ + for (j = i - 1; j > 0; j--) + if (Gg[j] != 0) + Gg[j] = Gg[j - 1] ^ Alpha_to[modnn((Index_of[Gg[j]]) + B0 + i - 1)]; + else + Gg[j] = Gg[j - 1]; + /* Gg[0] can never be zero */ + Gg[0] = Alpha_to[modnn((Index_of[Gg[0]]) + B0 + i - 1)]; + } + /* convert Gg[] to index form for quicker encoding */ + for (i = 0; i <= NN - KK; i++) + Gg[i] = Index_of[Gg[i]]; +} + + +/* + * take the string of symbols in data[i], i=0..(k-1) and encode + * systematically to produce NN-KK parity symbols in bb[0]..bb[NN-KK-1] data[] + * is input and bb[] is output in polynomial form. Encoding is done by using + * a feedback shift register with appropriate connections specified by the + * elements of Gg[], which was generated above. Codeword is c(X) = + * data(X)*X**(NN-KK)+ b(X) + */ +int +encode_rs(dtype *data, dtype *bb) +{ + register int i, j; + gf feedback; + + CLEAR(bb,NN-KK); + for (i = KK - 1; i >= 0; i--) { +#if (MM != 8) + if(data[i] > NN) + return -1; /* Illegal symbol */ +#endif + feedback = Index_of[data[i] ^ bb[NN - KK - 1]]; + if (feedback != A0) { /* feedback term is non-zero */ + for (j = NN - KK - 1; j > 0; j--) + if (Gg[j] != A0) + bb[j] = bb[j - 1] ^ Alpha_to[modnn(Gg[j] + feedback)]; + else + bb[j] = bb[j - 1]; + bb[0] = Alpha_to[modnn(Gg[0] + feedback)]; + } else { /* feedback term is zero. encoder becomes a + * single-byte shifter */ + for (j = NN - KK - 1; j > 0; j--) + bb[j] = bb[j - 1]; + bb[0] = 0; + } + } + return 0; +} + +/* + * Performs ERRORS+ERASURES decoding of RS codes. If decoding is successful, + * writes the codeword into data[] itself. Otherwise data[] is unaltered. + * + * Return number of symbols corrected, or -1 if codeword is illegal + * or uncorrectable. + * + * First "no_eras" erasures are declared by the calling program. Then, the + * maximum # of errors correctable is t_after_eras = floor((NN-KK-no_eras)/2). + * If the number of channel errors is not greater than "t_after_eras" the + * transmitted codeword will be recovered. Details of algorithm can be found + * in R. Blahut's "Theory ... of Error-Correcting Codes". + */ +int +eras_dec_rs(dtype *data, int *eras_pos, int no_eras) +{ + int deg_lambda, el, deg_omega; + int i, j, r; + gf u,q,tmp,num1,num2,den,discr_r; + gf recd[NN]; + /* Err+Eras Locator poly and syndrome poly */ + /*gf lambda[NN-KK + 1], s[NN-KK + 1]; + gf b[NN-KK + 1], t[NN-KK + 1], omega[NN-KK + 1]; + gf root[NN-KK], reg[NN-KK + 1], loc[NN-KK];*/ + gf lambda[NN + 1], s[NN + 1]; + gf b[NN + 1], t[NN + 1], omega[NN + 1]; + gf root[NN], reg[NN + 1], loc[NN]; + int syn_error, count; + + /* data[] is in polynomial form, copy and convert to index form */ + for (i = NN-1; i >= 0; i--){ +#if (MM != 8) + if(data[i] > NN) + return -1; /* Illegal symbol */ +#endif + recd[i] = Index_of[data[i]]; + } + /* first form the syndromes; i.e., evaluate recd(x) at roots of g(x) + * namely @**(B0+i), i = 0, ... ,(NN-KK-1) + */ + syn_error = 0; + for (i = 1; i <= NN-KK; i++) { + tmp = 0; + for (j = 0; j < NN; j++) + if (recd[j] != A0) /* recd[j] in index form */ + tmp ^= Alpha_to[modnn(recd[j] + (B0+i-1)*j)]; + syn_error |= tmp; /* set flag if non-zero syndrome => + * error */ + /* store syndrome in index form */ + s[i] = Index_of[tmp]; + } + if (!syn_error) { + /* + * if syndrome is zero, data[] is a codeword and there are no + * errors to correct. So return data[] unmodified + */ + return 0; + } + CLEAR(&lambda[1],NN-KK); + lambda[0] = 1; + if (no_eras > 0) { + /* Init lambda to be the erasure locator polynomial */ + lambda[1] = Alpha_to[eras_pos[0]]; + for (i = 1; i < no_eras; i++) { + u = eras_pos[i]; + for (j = i+1; j > 0; j--) { + tmp = Index_of[lambda[j - 1]]; + if(tmp != A0) + lambda[j] ^= Alpha_to[modnn(u + tmp)]; + } + } +#ifdef ERASURE_DEBUG + /* find roots of the erasure location polynomial */ + for(i=1;i<=no_eras;i++) + reg[i] = Index_of[lambda[i]]; + count = 0; + for (i = 1; i <= NN; i++) { + q = 1; + for (j = 1; j <= no_eras; j++) + if (reg[j] != A0) { + reg[j] = modnn(reg[j] + j); + q ^= Alpha_to[reg[j]]; + } + if (!q) { + /* store root and error location + * number indices + */ + root[count] = i; + loc[count] = NN - i; + count++; + } + } + if (count != no_eras) { + printf("\n lambda(x) is WRONG\n"); + return -1; + } +#ifndef NO_PRINT + printf("\n Erasure positions as determined by roots of Eras Loc Poly:\n"); + for (i = 0; i < count; i++) + printf("%d ", loc[i]); + printf("\n"); +#endif +#endif + } + for(i=0;i 0; j--) + if (reg[j] != A0) { + reg[j] = modnn(reg[j] + j); + q ^= Alpha_to[reg[j]]; + } + if (!q) { + /* store root (index-form) and error location number */ + root[count] = i; + loc[count] = NN - i; + count++; + } + } + +#ifdef DEBUG + printf("\n Final error positions:\t"); + for (i = 0; i < count; i++) + printf("%d ", loc[i]); + printf("\n"); +#endif + if (deg_lambda != count) { + /* + * deg(lambda) unequal to number of roots => uncorrectable + * error detected + */ + return -1; + } + /* + * Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo + * x**(NN-KK)). in index form. Also find deg(omega). + */ + deg_omega = 0; + for (i = 0; i < NN-KK;i++){ + tmp = 0; + j = (deg_lambda < i) ? deg_lambda : i; + for(;j >= 0; j--){ + if ((s[i + 1 - j] != A0) && (lambda[j] != A0)) + tmp ^= Alpha_to[modnn(s[i + 1 - j] + lambda[j])]; + } + if(tmp != 0) + deg_omega = i; + omega[i] = Index_of[tmp]; + } + omega[NN-KK] = A0; + + /* + * Compute error values in poly-form. num1 = omega(inv(X(l))), num2 = + * inv(X(l))**(B0-1) and den = lambda_pr(inv(X(l))) all in poly-form + */ + for (j = count-1; j >=0; j--) { + num1 = 0; + for (i = deg_omega; i >= 0; i--) { + if (omega[i] != A0) + num1 ^= Alpha_to[modnn(omega[i] + i * root[j])]; + } + num2 = Alpha_to[modnn(root[j] * (B0 - 1) + NN)]; + den = 0; + + /* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */ + for (i = min(deg_lambda,NN-KK-1) & ~1; i >= 0; i -=2) { + if(lambda[i+1] != A0) + den ^= Alpha_to[modnn(lambda[i+1] + i * root[j])]; + } + if (den == 0) { +#ifdef DEBUG + printf("\n ERROR: denominator = 0\n"); +#endif + return -1; + } + /* Apply error to data */ + if (num1 != 0) { + data[loc[j]] ^= Alpha_to[modnn(Index_of[num1] + Index_of[num2] + NN - Index_of[den])]; + } + } + return count; +} + + +#endif /* USE_JPWL */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/jpwl/rs.h b/gdcm/Utilities/gdcmopenjpeg-v1/jpwl/rs.h new file mode 100644 index 0000000..6d2ed59 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/jpwl/rs.h @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * Copyright (c) 2005-2006, Dept. of Electronic and Information Engineering, Universita' degli Studi di Perugia, Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef USE_JPWL + +/** +@file rs.h +@brief Functions used to compute Reed-Solomon parity and check of byte arrays + +*/ + +#ifndef __RS_HEADER__ +#define __RS_HEADER__ + +/** Global definitions for Reed-Solomon encoder/decoder + * Phil Karn KA9Q, September 1996 + * + * The parameters MM and KK specify the Reed-Solomon code parameters. + * + * Set MM to be the size of each code symbol in bits. The Reed-Solomon + * block size will then be NN = 2**M - 1 symbols. Supported values are + * defined in rs.c. + * + * Set KK to be the number of data symbols in each block, which must be + * less than the block size. The code will then be able to correct up + * to NN-KK erasures or (NN-KK)/2 errors, or combinations thereof with + * each error counting as two erasures. + */ +#define MM 8 /* RS code over GF(2**MM) - change to suit */ +//static int KK; +int KK; + +/* Original code */ +/*#define KK 239*/ /* KK = number of information symbols */ + +#define NN ((1 << MM) - 1) + +#if (MM <= 8) +typedef unsigned char dtype; +#else +typedef unsigned int dtype; +#endif + +/** Initialization function */ +void init_rs(int); + +/** These two functions *must* be called in this order (e.g., + * by init_rs()) before any encoding/decoding + */ +void generate_gf(void); /* Generate Galois Field */ +void gen_poly(void); /* Generate generator polynomial */ + +/** Reed-Solomon encoding + * data[] is the input block, parity symbols are placed in bb[] + * bb[] may lie past the end of the data, e.g., for (255,223): + * encode_rs(&data[0],&data[223]); + */ +int encode_rs(dtype data[], dtype bb[]); + +/** Reed-Solomon erasures-and-errors decoding + * The received block goes into data[], and a list of zero-origin + * erasure positions, if any, goes in eras_pos[] with a count in no_eras. + * + * The decoder corrects the symbols in place, if possible and returns + * the number of corrected symbols. If the codeword is illegal or + * uncorrectible, the data array is unchanged and -1 is returned + */ +int eras_dec_rs(dtype data[], int eras_pos[], int no_eras); + +/** +Computes the minimum between two integers +@param a first integer to compare +@param b second integer to compare +@return returns the minimum integer between a and b +*/ +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif /* min */ + +#endif /* __RS_HEADER__ */ + + +#endif /* USE_JPWL */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg.pc.in b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg.pc.in new file mode 100644 index 0000000..e75e2bd --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: openjpeg +Description: JPEG2000 files library +URL: http://code.google.com/p/openjpeg/ +Version: @VERSION@ +Libs: -L${libdir} -lopenjpeg +Cflags: -I${includedir} diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/CMakeLists.txt b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/CMakeLists.txt new file mode 100644 index 0000000..5b7e009 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/CMakeLists.txt @@ -0,0 +1,63 @@ +include_regular_expression("^.*$") +# Defines the source code for the library +set(OPENJPEG_SRCS + bio.c + cio.c + dwt.c + event.c + image.c + j2k.c + j2k_lib.c + jp2.c + jpt.c + mct.c + mqc.c + openjpeg.c + pi.c + raw.c + t1.c + t2.c + tcd.c + tgt.c +) + +# Build the library +if(WIN32) + if(BUILD_SHARED_LIBS) + add_definitions(-DOPJ_EXPORTS) + else() + add_definitions(-DOPJ_STATIC) + endif() +endif() +add_library(${OPENJPEG_LIBRARY_NAME} ${OPENJPEG_SRCS}) +set_target_properties(${OPENJPEG_LIBRARY_NAME} PROPERTIES + ${OPENJPEG_LIBRARY_PROPERTIES} LINK_INTERFACE_LIBRARIES "") +if(UNIX) + target_link_libraries(${OPENJPEG_LIBRARY_NAME} m) +endif() + + +# Install library +if(NOT OPENJPEG_INSTALL_NO_LIBRARIES) + install(TARGETS ${OPENJPEG_LIBRARY_NAME} + EXPORT ${GDCM_TARGETS_NAME} + RUNTIME DESTINATION ${OPENJPEG_INSTALL_BIN_DIR} COMPONENT Applications + LIBRARY DESTINATION ${OPENJPEG_INSTALL_LIB_DIR} COMPONENT Libraries + ARCHIVE DESTINATION ${OPENJPEG_INSTALL_LIB_DIR} COMPONENT DebugDevel + ) +endif() + +# Install includes files +if(NOT OPENJPEG_INSTALL_NO_DEVELOPMENT) +install(FILES openjpeg.h + #DESTINATION ${OPENJPEG_INSTALL_INCLUDE_DIR}/${subdir} COMPONENT Headers + DESTINATION ${OPENJPEG_INSTALL_INCLUDE_DIR} COMPONENT Headers +) +#install(CODE +# "execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink \$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${OPENJPEG_INSTALL_INCLUDE_DIR}/${subdir}/openjpeg.h \$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${OPENJPEG_INSTALL_INCLUDE_DIR}/openjpeg.h)") + +# install man page of the library +#install( +# FILES ../doc/man/man3/libopenjpeg.3 +# DESTINATION ${OPENJPEG_INSTALL_MAN_DIR}/man3) +endif() diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/bio.c b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/bio.c new file mode 100644 index 0000000..4c02f46 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/bio.c @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "opj_includes.h" + +/** @defgroup BIO BIO - Individual bit input-output stream */ +/*@{*/ + +/** @name Local static functions */ +/*@{*/ + +/** +Write a bit +@param bio BIO handle +@param b Bit to write (0 or 1) +*/ +static void bio_putbit(opj_bio_t *bio, int b); +/** +Read a bit +@param bio BIO handle +@return Returns the read bit +*/ +static int bio_getbit(opj_bio_t *bio); +/** +Write a byte +@param bio BIO handle +@return Returns 0 if successful, returns 1 otherwise +*/ +static int bio_byteout(opj_bio_t *bio); +/** +Read a byte +@param bio BIO handle +@return Returns 0 if successful, returns 1 otherwise +*/ +static int bio_bytein(opj_bio_t *bio); + +/*@}*/ + +/*@}*/ + +/* +========================================================== + local functions +========================================================== +*/ + +static int bio_byteout(opj_bio_t *bio) { + bio->buf = (bio->buf << 8) & 0xffff; + bio->ct = bio->buf == 0xff00 ? 7 : 8; + if (bio->bp >= bio->end) { + return 1; + } + *bio->bp++ = bio->buf >> 8; + return 0; +} + +static int bio_bytein(opj_bio_t *bio) { + bio->buf = (bio->buf << 8) & 0xffff; + bio->ct = bio->buf == 0xff00 ? 7 : 8; + if (bio->bp >= bio->end) { + return 1; + } + bio->buf |= *bio->bp++; + return 0; +} + +static void bio_putbit(opj_bio_t *bio, int b) { + if (bio->ct == 0) { + bio_byteout(bio); + } + bio->ct--; + bio->buf |= b << bio->ct; +} + +static int bio_getbit(opj_bio_t *bio) { + if (bio->ct == 0) { + bio_bytein(bio); + } + bio->ct--; + return (bio->buf >> bio->ct) & 1; +} + +/* +========================================================== + Bit Input/Output interface +========================================================== +*/ + +opj_bio_t* bio_create(void) { + opj_bio_t *bio = (opj_bio_t*)opj_malloc(sizeof(opj_bio_t)); + return bio; +} + +void bio_destroy(opj_bio_t *bio) { + if(bio) { + opj_free(bio); + } +} + +int bio_numbytes(opj_bio_t *bio) { + return (bio->bp - bio->start); +} + +void bio_init_enc(opj_bio_t *bio, unsigned char *bp, int len) { + bio->start = bp; + bio->end = bp + len; + bio->bp = bp; + bio->buf = 0; + bio->ct = 8; +} + +void bio_init_dec(opj_bio_t *bio, unsigned char *bp, int len) { + bio->start = bp; + bio->end = bp + len; + bio->bp = bp; + bio->buf = 0; + bio->ct = 0; +} + +void bio_write(opj_bio_t *bio, int v, int n) { + int i; + for (i = n - 1; i >= 0; i--) { + bio_putbit(bio, (v >> i) & 1); + } +} + +int bio_read(opj_bio_t *bio, int n) { + int i, v; + v = 0; + for (i = n - 1; i >= 0; i--) { + v += bio_getbit(bio) << i; + } + return v; +} + +int bio_flush(opj_bio_t *bio) { + bio->ct = 0; + if (bio_byteout(bio)) { + return 1; + } + if (bio->ct == 7) { + bio->ct = 0; + if (bio_byteout(bio)) { + return 1; + } + } + return 0; +} + +int bio_inalign(opj_bio_t *bio) { + bio->ct = 0; + if ((bio->buf & 0xff) == 0xff) { + if (bio_bytein(bio)) { + return 1; + } + bio->ct = 0; + } + return 0; +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/bio.h b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/bio.h new file mode 100644 index 0000000..764d7cb --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/bio.h @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __BIO_H +#define __BIO_H +/** +@file bio.h +@brief Implementation of an individual bit input-output (BIO) + +The functions in BIO.C have for goal to realize an individual bit input - output. +*/ + +/** @defgroup BIO BIO - Individual bit input-output stream */ +/*@{*/ + +/** +Individual bit input-output stream (BIO) +*/ +typedef struct opj_bio { + /** pointer to the start of the buffer */ + unsigned char *start; + /** pointer to the end of the buffer */ + unsigned char *end; + /** pointer to the present position in the buffer */ + unsigned char *bp; + /** temporary place where each byte is read or written */ + unsigned int buf; + /** coder : number of bits free to write. decoder : number of bits read */ + int ct; +} opj_bio_t; + +/** @name Exported functions */ +/*@{*/ +/* ----------------------------------------------------------------------- */ +/** +Create a new BIO handle +@return Returns a new BIO handle if successful, returns NULL otherwise +*/ +opj_bio_t* bio_create(void); +/** +Destroy a previously created BIO handle +@param bio BIO handle to destroy +*/ +void bio_destroy(opj_bio_t *bio); +/** +Number of bytes written. +@param bio BIO handle +@return Returns the number of bytes written +*/ +int bio_numbytes(opj_bio_t *bio); +/** +Init encoder +@param bio BIO handle +@param bp Output buffer +@param len Output buffer length +*/ +void bio_init_enc(opj_bio_t *bio, unsigned char *bp, int len); +/** +Init decoder +@param bio BIO handle +@param bp Input buffer +@param len Input buffer length +*/ +void bio_init_dec(opj_bio_t *bio, unsigned char *bp, int len); +/** +Write bits +@param bio BIO handle +@param v Value of bits +@param n Number of bits to write +*/ +void bio_write(opj_bio_t *bio, int v, int n); +/** +Read bits +@param bio BIO handle +@param n Number of bits to read +@return Returns the corresponding read number +*/ +int bio_read(opj_bio_t *bio, int n); +/** +Flush bits +@param bio BIO handle +@return Returns 1 if successful, returns 0 otherwise +*/ +int bio_flush(opj_bio_t *bio); +/** +Passes the ending bits (coming from flushing) +@param bio BIO handle +@return Returns 1 if successful, returns 0 otherwise +*/ +int bio_inalign(opj_bio_t *bio); +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __BIO_H */ + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/cio.c b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/cio.c new file mode 100644 index 0000000..2ac262a --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/cio.c @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "opj_includes.h" + +/* ----------------------------------------------------------------------- */ + +opj_cio_t* OPJ_CALLCONV opj_cio_open(opj_common_ptr cinfo, unsigned char *buffer, int length) { + opj_cp_t *cp = NULL; + opj_cio_t *cio = (opj_cio_t*)opj_malloc(sizeof(opj_cio_t)); + if(!cio) return NULL; + cio->cinfo = cinfo; + if(buffer && length) { + /* wrap a user buffer containing the encoded image */ + cio->openmode = OPJ_STREAM_READ; + cio->buffer = buffer; + cio->length = length; + } + else if(!buffer && !length && cinfo) { + /* allocate a buffer for the encoded image */ + cio->openmode = OPJ_STREAM_WRITE; + switch(cinfo->codec_format) { + case CODEC_J2K: + cp = ((opj_j2k_t*)cinfo->j2k_handle)->cp; + break; + case CODEC_JP2: + cp = ((opj_jp2_t*)cinfo->jp2_handle)->j2k->cp; + break; + default: + opj_free(cio); + return NULL; + } + cio->length = (unsigned int) (0.1625 * cp->img_size + 2000); /* 0.1625 = 1.3/8 and 2000 bytes as a minimum for headers */ + cio->buffer = (unsigned char *)opj_malloc(cio->length); + if(!cio->buffer) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error allocating memory for compressed bitstream\n"); + opj_free(cio); + return NULL; + } + } + else { + opj_free(cio); + return NULL; + } + + /* Initialize byte IO */ + cio->start = cio->buffer; + cio->end = cio->buffer + cio->length; + cio->bp = cio->buffer; + + return cio; +} + +void OPJ_CALLCONV opj_cio_close(opj_cio_t *cio) { + if(cio) { + if(cio->openmode == OPJ_STREAM_WRITE) { + /* destroy the allocated buffer */ + opj_free(cio->buffer); + } + /* destroy the cio */ + opj_free(cio); + } +} + + +/* ----------------------------------------------------------------------- */ + +/* + * Get position in byte stream. + */ +int OPJ_CALLCONV cio_tell(opj_cio_t *cio) { + return cio->bp - cio->start; +} + +/* + * Set position in byte stream. + * + * pos : position, in number of bytes, from the beginning of the stream + */ +void OPJ_CALLCONV cio_seek(opj_cio_t *cio, int pos) { + cio->bp = cio->start + pos; +} + +/* + * Number of bytes left before the end of the stream. + */ +int cio_numbytesleft(opj_cio_t *cio) { + return cio->end - cio->bp; +} + +/* + * Get pointer to the current position in the stream. + */ +unsigned char *cio_getbp(opj_cio_t *cio) { + return cio->bp; +} + +/* + * Write a byte. + */ +bool cio_byteout(opj_cio_t *cio, unsigned char v) { + if (cio->bp >= cio->end) { + opj_event_msg(cio->cinfo, EVT_ERROR, "write error\n"); + return false; + } + *cio->bp++ = v; + return true; +} + +/* + * Read a byte. + */ +unsigned char cio_bytein(opj_cio_t *cio) { + if (cio->bp >= cio->end) { + opj_event_msg(cio->cinfo, EVT_ERROR, "read error: passed the end of the codestream (start = %d, current = %d, end = %d\n", cio->start, cio->bp, cio->end); + return 0; + } + return *cio->bp++; +} + +/* + * Write some bytes. + * + * v : value to write + * n : number of bytes to write + */ +unsigned int cio_write(opj_cio_t *cio, unsigned int v, int n) { + int i; + for (i = n - 1; i >= 0; i--) { + if( !cio_byteout(cio, (unsigned char) ((v >> (i << 3)) & 0xff)) ) + return 0; + } + return n; +} + +/* + * Read some bytes. + * + * n : number of bytes to read + * + * return : value of the n bytes read + */ +unsigned int cio_read(opj_cio_t *cio, int n) { + int i; + unsigned int v; + v = 0; + for (i = n - 1; i >= 0; i--) { + v += cio_bytein(cio) << (i << 3); + } + return v; +} + +/* + * Skip some bytes. + * + * n : number of bytes to skip + */ +void cio_skip(opj_cio_t *cio, int n) { + cio->bp += n; +} + + + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/cio.h b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/cio.h new file mode 100644 index 0000000..580bf9c --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/cio.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __CIO_H +#define __CIO_H +/** +@file cio.h +@brief Implementation of a byte input-output process (CIO) + +The functions in CIO.C have for goal to realize a byte input / output process. +*/ + +/** @defgroup CIO CIO - byte input-output stream */ +/*@{*/ + +/** @name Exported functions (see also openjpeg.h) */ +/*@{*/ +/* ----------------------------------------------------------------------- */ +/** +Number of bytes left before the end of the stream +@param cio CIO handle +@return Returns the number of bytes before the end of the stream +*/ +int cio_numbytesleft(opj_cio_t *cio); +/** +Get pointer to the current position in the stream +@param cio CIO handle +@return Returns a pointer to the current position +*/ +unsigned char *cio_getbp(opj_cio_t *cio); +/** +Write some bytes +@param cio CIO handle +@param v Value to write +@param n Number of bytes to write +@return Returns the number of bytes written or 0 if an error occured +*/ +unsigned int cio_write(opj_cio_t *cio, unsigned int v, int n); +/** +Read some bytes +@param cio CIO handle +@param n Number of bytes to read +@return Returns the value of the n bytes read +*/ +unsigned int cio_read(opj_cio_t *cio, int n); +/** +Skip some bytes +@param cio CIO handle +@param n Number of bytes to skip +*/ +void cio_skip(opj_cio_t *cio, int n); +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __CIO_H */ + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/dwt.c b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/dwt.c new file mode 100644 index 0000000..a8d579f --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/dwt.c @@ -0,0 +1,858 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2007, Jonathan Ballard + * Copyright (c) 2007, Callum Lerwick + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef __SSE__ +#include +#endif + +#include "opj_includes.h" + +/** @defgroup DWT DWT - Implementation of a discrete wavelet transform */ +/*@{*/ + +#define WS(i) v->mem[(i)*2] +#define WD(i) v->mem[(1+(i)*2)] + +/** @name Local data structures */ +/*@{*/ + +typedef struct dwt_local { + int* mem; + int dn; + int sn; + int cas; +} dwt_t; + +typedef union { + float f[4]; +} v4; + +typedef struct v4dwt_local { + v4* wavelet ; + int dn ; + int sn ; + int cas ; +} v4dwt_t ; + +static const float dwt_alpha = 1.586134342f; // 12994 +static const float dwt_beta = 0.052980118f; // 434 +static const float dwt_gamma = -0.882911075f; // -7233 +static const float dwt_delta = -0.443506852f; // -3633 + +static const float K = 1.230174105f; // 10078 +/* FIXME: What is this constant? */ +static const float c13318 = 1.625732422f; + +/*@}*/ + +/** +Virtual function type for wavelet transform in 1-D +*/ +typedef void (*DWT1DFN)(dwt_t* v); + +/** @name Local static functions */ +/*@{*/ + +/** +Forward lazy transform (horizontal) +*/ +static void dwt_deinterleave_h(int *a, int *b, int dn, int sn, int cas); +/** +Forward lazy transform (vertical) +*/ +static void dwt_deinterleave_v(int *a, int *b, int dn, int sn, int x, int cas); +/** +Inverse lazy transform (horizontal) +*/ +static void dwt_interleave_h(dwt_t* h, int *a); +/** +Inverse lazy transform (vertical) +*/ +static void dwt_interleave_v(dwt_t* v, int *a, int x); +/** +Forward 5-3 wavelet transform in 1-D +*/ +static void dwt_encode_1(int *a, int dn, int sn, int cas); +/** +Inverse 5-3 wavelet transform in 1-D +*/ +static void dwt_decode_1(dwt_t *v); +/** +Forward 9-7 wavelet transform in 1-D +*/ +static void dwt_encode_1_real(int *a, int dn, int sn, int cas); +/** +Explicit calculation of the Quantization Stepsizes +*/ +static void dwt_encode_stepsize(int stepsize, int numbps, opj_stepsize_t *bandno_stepsize); +/** +Inverse wavelet transform in 2-D. +*/ +static void dwt_decode_tile(opj_tcd_tilecomp_t* tilec, int i, DWT1DFN fn); + +/*@}*/ + +/*@}*/ + +#define S(i) a[(i)*2] +#define D(i) a[(1+(i)*2)] +#define S_(i) ((i)<0?S(0):((i)>=sn?S(sn-1):S(i))) +#define D_(i) ((i)<0?D(0):((i)>=dn?D(dn-1):D(i))) +/* new */ +#define SS_(i) ((i)<0?S(0):((i)>=dn?S(dn-1):S(i))) +#define DD_(i) ((i)<0?D(0):((i)>=sn?D(sn-1):D(i))) + +/* */ +/* This table contains the norms of the 5-3 wavelets for different bands. */ +/* */ +static const double dwt_norms[4][10] = { + {1.000, 1.500, 2.750, 5.375, 10.68, 21.34, 42.67, 85.33, 170.7, 341.3}, + {1.038, 1.592, 2.919, 5.703, 11.33, 22.64, 45.25, 90.48, 180.9}, + {1.038, 1.592, 2.919, 5.703, 11.33, 22.64, 45.25, 90.48, 180.9}, + {.7186, .9218, 1.586, 3.043, 6.019, 12.01, 24.00, 47.97, 95.93} +}; + +/* */ +/* This table contains the norms of the 9-7 wavelets for different bands. */ +/* */ +static const double dwt_norms_real[4][10] = { + {1.000, 1.965, 4.177, 8.403, 16.90, 33.84, 67.69, 135.3, 270.6, 540.9}, + {2.022, 3.989, 8.355, 17.04, 34.27, 68.63, 137.3, 274.6, 549.0}, + {2.022, 3.989, 8.355, 17.04, 34.27, 68.63, 137.3, 274.6, 549.0}, + {2.080, 3.865, 8.307, 17.18, 34.71, 69.59, 139.3, 278.6, 557.2} +}; + +/* +========================================================== + local functions +========================================================== +*/ + +/* */ +/* Forward lazy transform (horizontal). */ +/* */ +static void dwt_deinterleave_h(int *a, int *b, int dn, int sn, int cas) { + int i; + for (i=0; i */ +/* Forward lazy transform (vertical). */ +/* */ +static void dwt_deinterleave_v(int *a, int *b, int dn, int sn, int x, int cas) { + int i; + for (i=0; i */ +/* Inverse lazy transform (horizontal). */ +/* */ +static void dwt_interleave_h(dwt_t* h, int *a) { + int *ai = a; + int *bi = h->mem + h->cas; + int i = h->sn; + while( i-- ) { + *bi = *(ai++); + bi += 2; + } + ai = a + h->sn; + bi = h->mem + 1 - h->cas; + i = h->dn ; + while( i-- ) { + *bi = *(ai++); + bi += 2; + } +} + +/* */ +/* Inverse lazy transform (vertical). */ +/* */ +static void dwt_interleave_v(dwt_t* v, int *a, int x) { + int *ai = a; + int *bi = v->mem + v->cas; + int i = v->sn; + while( i-- ) { + *bi = *ai; + bi += 2; + ai += x; + } + ai = a + (v->sn * x); + bi = v->mem + 1 - v->cas; + i = v->dn ; + while( i-- ) { + *bi = *ai; + bi += 2; + ai += x; + } +} + + +/* */ +/* Forward 5-3 wavelet transform in 1-D. */ +/* */ +static void dwt_encode_1(int *a, int dn, int sn, int cas) { + int i; + + if (!cas) { + if ((dn > 0) || (sn > 1)) { /* NEW : CASE ONE ELEMENT */ + for (i = 0; i < dn; i++) D(i) -= (S_(i) + S_(i + 1)) >> 1; + for (i = 0; i < sn; i++) S(i) += (D_(i - 1) + D_(i) + 2) >> 2; + } + } else { + if (!sn && dn == 1) /* NEW : CASE ONE ELEMENT */ + S(0) *= 2; + else { + for (i = 0; i < dn; i++) S(i) -= (DD_(i) + DD_(i - 1)) >> 1; + for (i = 0; i < sn; i++) D(i) += (SS_(i) + SS_(i + 1) + 2) >> 2; + } + } +} + +/* */ +/* Inverse 5-3 wavelet transform in 1-D. */ +/* */ +static void dwt_decode_1_(int *a, int dn, int sn, int cas) { + int i; + + if (!cas) { + if ((dn > 0) || (sn > 1)) { /* NEW : CASE ONE ELEMENT */ + for (i = 0; i < sn; i++) S(i) -= (D_(i - 1) + D_(i) + 2) >> 2; + for (i = 0; i < dn; i++) D(i) += (S_(i) + S_(i + 1)) >> 1; + } + } else { + if (!sn && dn == 1) /* NEW : CASE ONE ELEMENT */ + S(0) /= 2; + else { + for (i = 0; i < sn; i++) D(i) -= (SS_(i) + SS_(i + 1) + 2) >> 2; + for (i = 0; i < dn; i++) S(i) += (DD_(i) + DD_(i - 1)) >> 1; + } + } +} + +/* */ +/* Inverse 5-3 wavelet transform in 1-D. */ +/* */ +static void dwt_decode_1(dwt_t *v) { + dwt_decode_1_(v->mem, v->dn, v->sn, v->cas); +} + +/* */ +/* Forward 9-7 wavelet transform in 1-D. */ +/* */ +static void dwt_encode_1_real(int *a, int dn, int sn, int cas) { + int i; + if (!cas) { + if ((dn > 0) || (sn > 1)) { /* NEW : CASE ONE ELEMENT */ + for (i = 0; i < dn; i++) + D(i) -= fix_mul(S_(i) + S_(i + 1), 12993); + for (i = 0; i < sn; i++) + S(i) -= fix_mul(D_(i - 1) + D_(i), 434); + for (i = 0; i < dn; i++) + D(i) += fix_mul(S_(i) + S_(i + 1), 7233); + for (i = 0; i < sn; i++) + S(i) += fix_mul(D_(i - 1) + D_(i), 3633); + for (i = 0; i < dn; i++) + D(i) = fix_mul(D(i), 5038); /*5038 */ + for (i = 0; i < sn; i++) + S(i) = fix_mul(S(i), 6659); /*6660 */ + } + } else { + if ((sn > 0) || (dn > 1)) { /* NEW : CASE ONE ELEMENT */ + for (i = 0; i < dn; i++) + S(i) -= fix_mul(DD_(i) + DD_(i - 1), 12993); + for (i = 0; i < sn; i++) + D(i) -= fix_mul(SS_(i) + SS_(i + 1), 434); + for (i = 0; i < dn; i++) + S(i) += fix_mul(DD_(i) + DD_(i - 1), 7233); + for (i = 0; i < sn; i++) + D(i) += fix_mul(SS_(i) + SS_(i + 1), 3633); + for (i = 0; i < dn; i++) + S(i) = fix_mul(S(i), 5038); /*5038 */ + for (i = 0; i < sn; i++) + D(i) = fix_mul(D(i), 6659); /*6660 */ + } + } +} + +static void dwt_encode_stepsize(int stepsize, int numbps, opj_stepsize_t *bandno_stepsize) { + int p, n; + p = int_floorlog2(stepsize) - 13; + n = 11 - int_floorlog2(stepsize); + bandno_stepsize->mant = (n < 0 ? stepsize >> -n : stepsize << n) & 0x7ff; + bandno_stepsize->expn = numbps - p; +} + +/* +========================================================== + DWT interface +========================================================== +*/ + +/* */ +/* Forward 5-3 wavelet transform in 2-D. */ +/* */ +void dwt_encode(opj_tcd_tilecomp_t * tilec) { + int i, j, k; + int *a = NULL; + int *aj = NULL; + int *bj = NULL; + int w, l; + + w = tilec->x1-tilec->x0; + l = tilec->numresolutions-1; + a = tilec->data; + + for (i = 0; i < l; i++) { + int rw; /* width of the resolution level computed */ + int rh; /* height of the resolution level computed */ + int rw1; /* width of the resolution level once lower than computed one */ + int rh1; /* height of the resolution level once lower than computed one */ + int cas_col; /* 0 = non inversion on horizontal filtering 1 = inversion between low-pass and high-pass filtering */ + int cas_row; /* 0 = non inversion on vertical filtering 1 = inversion between low-pass and high-pass filtering */ + int dn, sn; + + rw = tilec->resolutions[l - i].x1 - tilec->resolutions[l - i].x0; + rh = tilec->resolutions[l - i].y1 - tilec->resolutions[l - i].y0; + rw1= tilec->resolutions[l - i - 1].x1 - tilec->resolutions[l - i - 1].x0; + rh1= tilec->resolutions[l - i - 1].y1 - tilec->resolutions[l - i - 1].y0; + + cas_row = tilec->resolutions[l - i].x0 % 2; + cas_col = tilec->resolutions[l - i].y0 % 2; + + sn = rh1; + dn = rh - rh1; + bj = (int*)opj_malloc(rh * sizeof(int)); + for (j = 0; j < rw; j++) { + aj = a + j; + for (k = 0; k < rh; k++) bj[k] = aj[k*w]; + dwt_encode_1(bj, dn, sn, cas_col); + dwt_deinterleave_v(bj, aj, dn, sn, w, cas_col); + } + opj_free(bj); + + sn = rw1; + dn = rw - rw1; + bj = (int*)opj_malloc(rw * sizeof(int)); + for (j = 0; j < rh; j++) { + aj = a + j * w; + for (k = 0; k < rw; k++) bj[k] = aj[k]; + dwt_encode_1(bj, dn, sn, cas_row); + dwt_deinterleave_h(bj, aj, dn, sn, cas_row); + } + opj_free(bj); + } +} + + +/* */ +/* Inverse 5-3 wavelet transform in 2-D. */ +/* */ +void dwt_decode(opj_tcd_tilecomp_t* tilec, int numres) { + dwt_decode_tile(tilec, numres, &dwt_decode_1); +} + + +/* */ +/* Get gain of 5-3 wavelet transform. */ +/* */ +int dwt_getgain(int orient) { + if (orient == 0) + return 0; + if (orient == 1 || orient == 2) + return 1; + return 2; +} + +/* */ +/* Get norm of 5-3 wavelet. */ +/* */ +double dwt_getnorm(int level, int orient) { + return dwt_norms[orient][level]; +} + +/* */ +/* Forward 9-7 wavelet transform in 2-D. */ +/* */ + +void dwt_encode_real(opj_tcd_tilecomp_t * tilec) { + int i, j, k; + int *a = NULL; + int *aj = NULL; + int *bj = NULL; + int w, l; + + w = tilec->x1-tilec->x0; + l = tilec->numresolutions-1; + a = tilec->data; + + for (i = 0; i < l; i++) { + int rw; /* width of the resolution level computed */ + int rh; /* height of the resolution level computed */ + int rw1; /* width of the resolution level once lower than computed one */ + int rh1; /* height of the resolution level once lower than computed one */ + int cas_col; /* 0 = non inversion on horizontal filtering 1 = inversion between low-pass and high-pass filtering */ + int cas_row; /* 0 = non inversion on vertical filtering 1 = inversion between low-pass and high-pass filtering */ + int dn, sn; + + rw = tilec->resolutions[l - i].x1 - tilec->resolutions[l - i].x0; + rh = tilec->resolutions[l - i].y1 - tilec->resolutions[l - i].y0; + rw1= tilec->resolutions[l - i - 1].x1 - tilec->resolutions[l - i - 1].x0; + rh1= tilec->resolutions[l - i - 1].y1 - tilec->resolutions[l - i - 1].y0; + + cas_row = tilec->resolutions[l - i].x0 % 2; + cas_col = tilec->resolutions[l - i].y0 % 2; + + sn = rh1; + dn = rh - rh1; + bj = (int*)opj_malloc(rh * sizeof(int)); + for (j = 0; j < rw; j++) { + aj = a + j; + for (k = 0; k < rh; k++) bj[k] = aj[k*w]; + dwt_encode_1_real(bj, dn, sn, cas_col); + dwt_deinterleave_v(bj, aj, dn, sn, w, cas_col); + } + opj_free(bj); + + sn = rw1; + dn = rw - rw1; + bj = (int*)opj_malloc(rw * sizeof(int)); + for (j = 0; j < rh; j++) { + aj = a + j * w; + for (k = 0; k < rw; k++) bj[k] = aj[k]; + dwt_encode_1_real(bj, dn, sn, cas_row); + dwt_deinterleave_h(bj, aj, dn, sn, cas_row); + } + opj_free(bj); + } +} + + +/* */ +/* Get gain of 9-7 wavelet transform. */ +/* */ +int dwt_getgain_real(int orient) { + (void)orient; + return 0; +} + +/* */ +/* Get norm of 9-7 wavelet. */ +/* */ +double dwt_getnorm_real(int level, int orient) { + return dwt_norms_real[orient][level]; +} + +void dwt_calc_explicit_stepsizes(opj_tccp_t * tccp, int prec) { + int numbands, bandno; + numbands = 3 * tccp->numresolutions - 2; + for (bandno = 0; bandno < numbands; bandno++) { + double stepsize; + int resno, level, orient, gain; + + resno = (bandno == 0) ? 0 : ((bandno - 1) / 3 + 1); + orient = (bandno == 0) ? 0 : ((bandno - 1) % 3 + 1); + level = tccp->numresolutions - 1 - resno; + gain = (tccp->qmfbid == 0) ? 0 : ((orient == 0) ? 0 : (((orient == 1) || (orient == 2)) ? 1 : 2)); + if (tccp->qntsty == J2K_CCP_QNTSTY_NOQNT) { + stepsize = 1.0; + } else { + double norm = dwt_norms_real[orient][level]; + stepsize = (1 << (gain)) / norm; + } + dwt_encode_stepsize((int) floor(stepsize * 8192.0), prec + gain, &tccp->stepsizes[bandno]); + } +} + + +/* */ +/* Determine maximum computed resolution level for inverse wavelet transform */ +/* */ +static int dwt_decode_max_resolution(opj_tcd_resolution_t* restrict r, int i) { + int mr = 1; + int w; + while( --i ) { + r++; + if( mr < ( w = r->x1 - r->x0 ) ) + mr = w ; + if( mr < ( w = r->y1 - r->y0 ) ) + mr = w ; + } + return mr ; +} + + +/* */ +/* Inverse wavelet transform in 2-D. */ +/* */ +static void dwt_decode_tile(opj_tcd_tilecomp_t* tilec, int numres, DWT1DFN dwt_1D) { + dwt_t h; + dwt_t v; + + opj_tcd_resolution_t* tr = tilec->resolutions; + + int rw = tr->x1 - tr->x0; /* width of the resolution level computed */ + int rh = tr->y1 - tr->y0; /* height of the resolution level computed */ + + int w = tilec->x1 - tilec->x0; + + h.mem = opj_aligned_malloc(dwt_decode_max_resolution(tr, numres) * sizeof(int)); + v.mem = h.mem; + + while( --numres) { + int * restrict tiledp = tilec->data; + int j; + + ++tr; + h.sn = rw; + v.sn = rh; + + rw = tr->x1 - tr->x0; + rh = tr->y1 - tr->y0; + + h.dn = rw - h.sn; + h.cas = tr->x0 % 2; + + for(j = 0; j < rh; ++j) { + dwt_interleave_h(&h, &tiledp[j*w]); + (dwt_1D)(&h); + memcpy(&tiledp[j*w], h.mem, rw * sizeof(int)); + } + + v.dn = rh - v.sn; + v.cas = tr->y0 % 2; + + for(j = 0; j < rw; ++j){ + int k; + dwt_interleave_v(&v, &tiledp[j], w); + (dwt_1D)(&v); + for(k = 0; k < rh; ++k) { + tiledp[k * w + j] = v.mem[k]; + } + } + } + opj_aligned_free(h.mem); +} + +static void v4dwt_interleave_h(v4dwt_t* restrict w, float* restrict a, int x, int size){ + float* restrict bi = (float*) (w->wavelet + w->cas); + int count = w->sn; + int i, k; + for(k = 0; k < 2; ++k){ + if (count + 3 * x < size && ((int) a & 0x0f) == 0 && ((int) bi & 0x0f) == 0 && (x & 0x0f) == 0) { + /* Fast code path */ + for(i = 0; i < count; ++i){ + int j = i; + bi[i*8 ] = a[j]; + j += x; + bi[i*8 + 1] = a[j]; + j += x; + bi[i*8 + 2] = a[j]; + j += x; + bi[i*8 + 3] = a[j]; + } + } else { + /* Slow code path */ + for(i = 0; i < count; ++i){ + int j = i; + bi[i*8 ] = a[j]; + j += x; + if(j > size) continue; + bi[i*8 + 1] = a[j]; + j += x; + if(j > size) continue; + bi[i*8 + 2] = a[j]; + j += x; + if(j > size) continue; + bi[i*8 + 3] = a[j]; + } + } + bi = (float*) (w->wavelet + 1 - w->cas); + a += w->sn; + size -= w->sn; + count = w->dn; + } +} + +static void v4dwt_interleave_v(v4dwt_t* restrict v , float* restrict a , int x){ + v4* restrict bi = v->wavelet + v->cas; + int i; + for(i = 0; i < v->sn; ++i){ + memcpy(&bi[i*2], &a[i*x], 4 * sizeof(float)); + } + a += v->sn * x; + bi = v->wavelet + 1 - v->cas; + for(i = 0; i < v->dn; ++i){ + memcpy(&bi[i*2], &a[i*x], 4 * sizeof(float)); + } +} + +#ifdef __SSE__ + +static void v4dwt_decode_step1_sse(v4* w, int count, const __m128 c){ + __m128* restrict vw = (__m128*) w; + int i; + /* 4x unrolled loop */ + for(i = 0; i < count >> 2; ++i){ + *vw = _mm_mul_ps(*vw, c); + vw += 2; + *vw = _mm_mul_ps(*vw, c); + vw += 2; + *vw = _mm_mul_ps(*vw, c); + vw += 2; + *vw = _mm_mul_ps(*vw, c); + vw += 2; + } + count &= 3; + for(i = 0; i < count; ++i){ + *vw = _mm_mul_ps(*vw, c); + vw += 2; + } +} + +static void v4dwt_decode_step2_sse(v4* l, v4* w, int k, int m, __m128 c){ + __m128* restrict vl = (__m128*) l; + __m128* restrict vw = (__m128*) w; + int i; + __m128 tmp1, tmp2, tmp3; + tmp1 = vl[0]; + for(i = 0; i < m; ++i){ + tmp2 = vw[-1]; + tmp3 = vw[ 0]; + vw[-1] = _mm_add_ps(tmp2, _mm_mul_ps(_mm_add_ps(tmp1, tmp3), c)); + tmp1 = tmp3; + vw += 2; + } + vl = vw - 2; + if(m >= k){ + return; + } + c = _mm_add_ps(c, c); + c = _mm_mul_ps(c, vl[0]); + for(; m < k; ++m){ + __m128 tmp = vw[-1]; + vw[-1] = _mm_add_ps(tmp, c); + vw += 2; + } +} + +#else + +static void v4dwt_decode_step1(v4* w, int count, const float c){ + float* restrict fw = (float*) w; + int i; + for(i = 0; i < count; ++i){ + float tmp1 = fw[i*8 ]; + float tmp2 = fw[i*8 + 1]; + float tmp3 = fw[i*8 + 2]; + float tmp4 = fw[i*8 + 3]; + fw[i*8 ] = tmp1 * c; + fw[i*8 + 1] = tmp2 * c; + fw[i*8 + 2] = tmp3 * c; + fw[i*8 + 3] = tmp4 * c; + } +} + +static void v4dwt_decode_step2(v4* l, v4* w, int k, int m, float c){ + float* restrict fl = (float*) l; + float* restrict fw = (float*) w; + int i; + for(i = 0; i < m; ++i){ + float tmp1_1 = fl[0]; + float tmp1_2 = fl[1]; + float tmp1_3 = fl[2]; + float tmp1_4 = fl[3]; + float tmp2_1 = fw[-4]; + float tmp2_2 = fw[-3]; + float tmp2_3 = fw[-2]; + float tmp2_4 = fw[-1]; + float tmp3_1 = fw[0]; + float tmp3_2 = fw[1]; + float tmp3_3 = fw[2]; + float tmp3_4 = fw[3]; + fw[-4] = tmp2_1 + ((tmp1_1 + tmp3_1) * c); + fw[-3] = tmp2_2 + ((tmp1_2 + tmp3_2) * c); + fw[-2] = tmp2_3 + ((tmp1_3 + tmp3_3) * c); + fw[-1] = tmp2_4 + ((tmp1_4 + tmp3_4) * c); + fl = fw; + fw += 8; + } + if(m < k){ + float c1; + float c2; + float c3; + float c4; + c += c; + c1 = fl[0] * c; + c2 = fl[1] * c; + c3 = fl[2] * c; + c4 = fl[3] * c; + for(; m < k; ++m){ + float tmp1 = fw[-4]; + float tmp2 = fw[-3]; + float tmp3 = fw[-2]; + float tmp4 = fw[-1]; + fw[-4] = tmp1 + c1; + fw[-3] = tmp2 + c2; + fw[-2] = tmp3 + c3; + fw[-1] = tmp4 + c4; + fw += 8; + } + } +} + +#endif + +/* */ +/* Inverse 9-7 wavelet transform in 1-D. */ +/* */ +static void v4dwt_decode(v4dwt_t* restrict dwt){ + int a, b; + if(dwt->cas == 0) { + if(!((dwt->dn > 0) || (dwt->sn > 1))){ + return; + } + a = 0; + b = 1; + }else{ + if(!((dwt->sn > 0) || (dwt->dn > 1))) { + return; + } + a = 1; + b = 0; + } +#ifdef __SSE__ + v4dwt_decode_step1_sse(dwt->wavelet+a, dwt->sn, _mm_set1_ps(K)); + v4dwt_decode_step1_sse(dwt->wavelet+b, dwt->dn, _mm_set1_ps(c13318)); + v4dwt_decode_step2_sse(dwt->wavelet+b, dwt->wavelet+a+1, dwt->sn, int_min(dwt->sn, dwt->dn-a), _mm_set1_ps(dwt_delta)); + v4dwt_decode_step2_sse(dwt->wavelet+a, dwt->wavelet+b+1, dwt->dn, int_min(dwt->dn, dwt->sn-b), _mm_set1_ps(dwt_gamma)); + v4dwt_decode_step2_sse(dwt->wavelet+b, dwt->wavelet+a+1, dwt->sn, int_min(dwt->sn, dwt->dn-a), _mm_set1_ps(dwt_beta)); + v4dwt_decode_step2_sse(dwt->wavelet+a, dwt->wavelet+b+1, dwt->dn, int_min(dwt->dn, dwt->sn-b), _mm_set1_ps(dwt_alpha)); +#else + v4dwt_decode_step1(dwt->wavelet+a, dwt->sn, K); + v4dwt_decode_step1(dwt->wavelet+b, dwt->dn, c13318); + v4dwt_decode_step2(dwt->wavelet+b, dwt->wavelet+a+1, dwt->sn, int_min(dwt->sn, dwt->dn-a), dwt_delta); + v4dwt_decode_step2(dwt->wavelet+a, dwt->wavelet+b+1, dwt->dn, int_min(dwt->dn, dwt->sn-b), dwt_gamma); + v4dwt_decode_step2(dwt->wavelet+b, dwt->wavelet+a+1, dwt->sn, int_min(dwt->sn, dwt->dn-a), dwt_beta); + v4dwt_decode_step2(dwt->wavelet+a, dwt->wavelet+b+1, dwt->dn, int_min(dwt->dn, dwt->sn-b), dwt_alpha); +#endif +} + +/* */ +/* Inverse 9-7 wavelet transform in 2-D. */ +/* */ +void dwt_decode_real(opj_tcd_tilecomp_t* restrict tilec, int numres){ + v4dwt_t h; + v4dwt_t v; + + opj_tcd_resolution_t* res = tilec->resolutions; + + int rw = res->x1 - res->x0; /* width of the resolution level computed */ + int rh = res->y1 - res->y0; /* height of the resolution level computed */ + + int w = tilec->x1 - tilec->x0; + + h.wavelet = (v4*) opj_aligned_malloc((dwt_decode_max_resolution(res, numres)+5) * sizeof(v4)); + v.wavelet = h.wavelet; + + while( --numres) { + float * restrict aj = (float*) tilec->data; + int bufsize = (tilec->x1 - tilec->x0) * (tilec->y1 - tilec->y0); + int j; + + h.sn = rw; + v.sn = rh; + + ++res; + + rw = res->x1 - res->x0; /* width of the resolution level computed */ + rh = res->y1 - res->y0; /* height of the resolution level computed */ + + h.dn = rw - h.sn; + h.cas = res->x0 % 2; + + for(j = rh; j > 3; j -= 4){ + int k; + v4dwt_interleave_h(&h, aj, w, bufsize); + v4dwt_decode(&h); + for(k = rw; --k >= 0;){ + aj[k ] = h.wavelet[k].f[0]; + aj[k+w ] = h.wavelet[k].f[1]; + aj[k+w*2] = h.wavelet[k].f[2]; + aj[k+w*3] = h.wavelet[k].f[3]; + } + aj += w*4; + bufsize -= w*4; + } + if (rh & 0x03) { + int k; + j = rh & 0x03; + v4dwt_interleave_h(&h, aj, w, bufsize); + v4dwt_decode(&h); + for(k = rw; --k >= 0;){ + switch(j) { + case 3: aj[k+w*2] = h.wavelet[k].f[2]; + case 2: aj[k+w ] = h.wavelet[k].f[1]; + case 1: aj[k ] = h.wavelet[k].f[0]; + } + } + } + + v.dn = rh - v.sn; + v.cas = res->y0 % 2; + + aj = (float*) tilec->data; + for(j = rw; j > 3; j -= 4){ + int k; + v4dwt_interleave_v(&v, aj, w); + v4dwt_decode(&v); + for(k = 0; k < rh; ++k){ + memcpy(&aj[k*w], &v.wavelet[k], 4 * sizeof(float)); + } + aj += 4; + } + if (rw & 0x03){ + int k; + j = rw & 0x03; + v4dwt_interleave_v(&v, aj, w); + v4dwt_decode(&v); + for(k = 0; k < rh; ++k){ + memcpy(&aj[k*w], &v.wavelet[k], j * sizeof(float)); + } + } + } + + opj_aligned_free(h.wavelet); +} + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/dwt.h b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/dwt.h new file mode 100644 index 0000000..adf73e5 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/dwt.h @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __DWT_H +#define __DWT_H +/** +@file dwt.h +@brief Implementation of a discrete wavelet transform (DWT) + +The functions in DWT.C have for goal to realize forward and inverse discret wavelet +transform with filter 5-3 (reversible) and filter 9-7 (irreversible). The functions in +DWT.C are used by some function in TCD.C. +*/ + +/** @defgroup DWT DWT - Implementation of a discrete wavelet transform */ +/*@{*/ + + +/** @name Exported functions */ +/*@{*/ +/* ----------------------------------------------------------------------- */ +/** +Forward 5-3 wavelet tranform in 2-D. +Apply a reversible DWT transform to a component of an image. +@param tilec Tile component information (current tile) +*/ +void dwt_encode(opj_tcd_tilecomp_t * tilec); +/** +Inverse 5-3 wavelet tranform in 2-D. +Apply a reversible inverse DWT transform to a component of an image. +@param tilec Tile component information (current tile) +@param numres Number of resolution levels to decode +*/ +void dwt_decode(opj_tcd_tilecomp_t* tilec, int numres); +/** +Get the gain of a subband for the reversible 5-3 DWT. +@param orient Number that identifies the subband (0->LL, 1->HL, 2->LH, 3->HH) +@return Returns 0 if orient = 0, returns 1 if orient = 1 or 2, returns 2 otherwise +*/ +int dwt_getgain(int orient); +/** +Get the norm of a wavelet function of a subband at a specified level for the reversible 5-3 DWT. +@param level Level of the wavelet function +@param orient Band of the wavelet function +@return Returns the norm of the wavelet function +*/ +double dwt_getnorm(int level, int orient); +/** +Forward 9-7 wavelet transform in 2-D. +Apply an irreversible DWT transform to a component of an image. +@param tilec Tile component information (current tile) +*/ +void dwt_encode_real(opj_tcd_tilecomp_t * tilec); +/** +Inverse 9-7 wavelet transform in 2-D. +Apply an irreversible inverse DWT transform to a component of an image. +@param tilec Tile component information (current tile) +@param numres Number of resolution levels to decode +*/ +void dwt_decode_real(opj_tcd_tilecomp_t* tilec, int numres); +/** +Get the gain of a subband for the irreversible 9-7 DWT. +@param orient Number that identifies the subband (0->LL, 1->HL, 2->LH, 3->HH) +@return Returns the gain of the 9-7 wavelet transform +*/ +int dwt_getgain_real(int orient); +/** +Get the norm of a wavelet function of a subband at a specified level for the irreversible 9-7 DWT +@param level Level of the wavelet function +@param orient Band of the wavelet function +@return Returns the norm of the 9-7 wavelet +*/ +double dwt_getnorm_real(int level, int orient); +/** +Explicit calculation of the Quantization Stepsizes +@param tccp Tile-component coding parameters +@param prec Precint analyzed +*/ +void dwt_calc_explicit_stepsizes(opj_tccp_t * tccp, int prec); +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __DWT_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/event.c b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/event.c new file mode 100644 index 0000000..953a997 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/event.c @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "opj_includes.h" + +/* ========================================================== + Utility functions + ==========================================================*/ + +#ifndef _WIN32 +static char* +i2a(unsigned i, char *a, unsigned r) { + if (i/r > 0) a = i2a(i/r,a,r); + *a = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[i%r]; + return a+1; +} + +/** + Transforms integer i into an ascii string and stores the result in a; + string is encoded in the base indicated by r. + @param i Number to be converted + @param a String result + @param r Base of value; must be in the range 2 - 36 + @return Returns a +*/ +static char * +_itoa(int i, char *a, int r) { + r = ((r < 2) || (r > 36)) ? 10 : r; + if(i < 0) { + *a = '-'; + *i2a(-i, a+1, r) = 0; + } + else *i2a(i, a, r) = 0; + return a; +} + +#endif /* !_WIN32 */ + +/* ----------------------------------------------------------------------- */ + +opj_event_mgr_t* OPJ_CALLCONV opj_set_event_mgr(opj_common_ptr cinfo, opj_event_mgr_t *event_mgr, void *context) { + if(cinfo) { + opj_event_mgr_t *previous = cinfo->event_mgr; + cinfo->event_mgr = event_mgr; + cinfo->client_data = context; + return previous; + } + + return NULL; +} + +bool opj_event_msg(opj_common_ptr cinfo, int event_type, const char *fmt, ...) { +#define MSG_SIZE 512 /* 512 bytes should be more than enough for a short message */ + opj_msg_callback msg_handler = NULL; + + opj_event_mgr_t *event_mgr = cinfo->event_mgr; + if(event_mgr != NULL) { + switch(event_type) { + case EVT_ERROR: + msg_handler = event_mgr->error_handler; + break; + case EVT_WARNING: + msg_handler = event_mgr->warning_handler; + break; + case EVT_INFO: + msg_handler = event_mgr->info_handler; + break; + default: + break; + } + if(msg_handler == NULL) { + return false; + } + } else { + return false; + } + + if ((fmt != NULL) && (event_mgr != NULL)) { + va_list arg; + int str_length/*, i, j*/; /* UniPG */ + char message[MSG_SIZE]; + memset(message, 0, MSG_SIZE); + /* initialize the optional parameter list */ + va_start(arg, fmt); + /* check the length of the format string */ + str_length = (strlen(fmt) > MSG_SIZE) ? MSG_SIZE : strlen(fmt); + /* parse the format string and put the result in 'message' */ + vsprintf(message, fmt, arg); /* UniPG */ + /* deinitialize the optional parameter list */ + va_end(arg); + + /* output the message to the user program */ + msg_handler(message, cinfo->client_data); + } + + return true; +} + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/event.h b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/event.h new file mode 100644 index 0000000..11910b0 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/event.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __EVENT_H +#define __EVENT_H +/** +@file event.h +@brief Implementation of a event callback system + +The functions in EVENT.C have for goal to send output messages (errors, warnings, debug) to the user. +*/ + +#define EVT_ERROR 1 /**< Error event type */ +#define EVT_WARNING 2 /**< Warning event type */ +#define EVT_INFO 4 /**< Debug event type */ + +/** @defgroup EVENT EVENT - Implementation of a event callback system */ +/*@{*/ + +/** @name Exported functions (see also openjpeg.h) */ +/*@{*/ +/* ----------------------------------------------------------------------- */ +/** +Write formatted data to a string and send the string to a user callback. +@param cinfo Codec context info +@param event_type Event type or callback to use to send the message +@param fmt Format-control string (plus optionnal arguments) +@return Returns true if successful, returns false otherwise +*/ +bool opj_event_msg(opj_common_ptr cinfo, int event_type, const char *fmt, ...); +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __EVENT_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/fix.h b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/fix.h new file mode 100644 index 0000000..bcb2acb --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/fix.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __FIX_H +#define __FIX_H + +#if defined(_MSC_VER) || defined(__BORLANDC__) +#define int64 __int64 +#else +#define int64 long long +#endif + +/** +@file fix.h +@brief Implementation of operations of specific multiplication (FIX) + +The functions in FIX.H have for goal to realize specific multiplication. +*/ + +/** @defgroup FIX FIX - Implementation of operations of specific multiplication */ +/*@{*/ + +/** +Multiply two fixed-precision rational numbers. +@param a +@param b +@return Returns a * b +*/ +static INLINE int fix_mul(int a, int b) { + int64 temp = (int64) a * (int64) b ; + temp += temp & 4096; + return (int) (temp >> 13) ; +} + +/*@}*/ + +#endif /* __FIX_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/image.c b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/image.c new file mode 100644 index 0000000..30b7d13 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/image.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "opj_includes.h" + +opj_image_t* opj_image_create0(void) { + opj_image_t *image = (opj_image_t*)opj_calloc(1, sizeof(opj_image_t)); + return image; +} + +opj_image_t* OPJ_CALLCONV opj_image_create(int numcmpts, opj_image_cmptparm_t *cmptparms, OPJ_COLOR_SPACE clrspc) { + int compno; + opj_image_t *image = NULL; + + image = (opj_image_t*) opj_calloc(1, sizeof(opj_image_t)); + if(image) { + image->color_space = clrspc; + image->numcomps = numcmpts; + /* allocate memory for the per-component information */ + image->comps = (opj_image_comp_t*)opj_malloc(image->numcomps * sizeof(opj_image_comp_t)); + if(!image->comps) { + fprintf(stderr,"Unable to allocate memory for image.\n"); + opj_image_destroy(image); + return NULL; + } + /* create the individual image components */ + for(compno = 0; compno < numcmpts; compno++) { + opj_image_comp_t *comp = &image->comps[compno]; + comp->dx = cmptparms[compno].dx; + comp->dy = cmptparms[compno].dy; + comp->w = cmptparms[compno].w; + comp->h = cmptparms[compno].h; + comp->x0 = cmptparms[compno].x0; + comp->y0 = cmptparms[compno].y0; + comp->prec = cmptparms[compno].prec; + comp->bpp = cmptparms[compno].bpp; + comp->sgnd = cmptparms[compno].sgnd; + comp->data = (int*) opj_calloc(comp->w * comp->h, sizeof(int)); + if(!comp->data) { + fprintf(stderr,"Unable to allocate memory for image.\n"); + opj_image_destroy(image); + return NULL; + } + } + } + + return image; +} + +void OPJ_CALLCONV opj_image_destroy(opj_image_t *image) { + int i; + if(image) { + if(image->comps) { + /* image components */ + for(i = 0; i < image->numcomps; i++) { + opj_image_comp_t *image_comp = &image->comps[i]; + if(image_comp->data) { + opj_free(image_comp->data); + } + } + opj_free(image->comps); + } + opj_free(image); + } +} + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/image.h b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/image.h new file mode 100644 index 0000000..04c362e --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/image.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __IMAGE_H +#define __IMAGE_H +/** +@file image.h +@brief Implementation of operations on images (IMAGE) + +The functions in IMAGE.C have for goal to realize operations on images. +*/ + +/** @defgroup IMAGE IMAGE - Implementation of operations on images */ +/*@{*/ + +/** +Create an empty image +@todo this function should be removed +@return returns an empty image if successful, returns NULL otherwise +*/ +opj_image_t* opj_image_create0(void); + +/*@}*/ + +#endif /* __IMAGE_H */ + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/int.h b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/int.h new file mode 100644 index 0000000..4e5fe08 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/int.h @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __INT_H +#define __INT_H +/** +@file int.h +@brief Implementation of operations on integers (INT) + +The functions in INT.H have for goal to realize operations on integers. +*/ + +/** @defgroup INT INT - Implementation of operations on integers */ +/*@{*/ + +/** @name Exported functions (see also openjpeg.h) */ +/*@{*/ +/* ----------------------------------------------------------------------- */ +/** +Get the minimum of two integers +@return Returns a if a < b else b +*/ +static INLINE int int_min(int a, int b) { + return a < b ? a : b; +} +/** +Get the maximum of two integers +@return Returns a if a > b else b +*/ +static INLINE int int_max(int a, int b) { + return (a > b) ? a : b; +} +/** +Clamp an integer inside an interval +@return +
    +
  • Returns a if (min < a < max) +
  • Returns max if (a > max) +
  • Returns min if (a < min) +
+*/ +static INLINE int int_clamp(int a, int min, int max) { + if (a < min) + return min; + if (a > max) + return max; + return a; +} +/** +@return Get absolute value of integer +*/ +static INLINE int int_abs(int a) { + return a < 0 ? -a : a; +} +/** +Divide an integer and round upwards +@return Returns a divided by b +*/ +static INLINE int int_ceildiv(int a, int b) { + return (a + b - 1) / b; +} +/** +Divide an integer by a power of 2 and round upwards +@return Returns a divided by 2^b +*/ +static INLINE int int_ceildivpow2(int a, int b) { + return (a + (1 << b) - 1) >> b; +} +/** +Divide an integer by a power of 2 and round downwards +@return Returns a divided by 2^b +*/ +static INLINE int int_floordivpow2(int a, int b) { + return a >> b; +} +/** +Get logarithm of an integer and round downwards +@return Returns log2(a) +*/ +static INLINE int int_floorlog2(int a) { + int l; + for (l = 0; a > 1; l++) { + a >>= 1; + } + return l; +} +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/j2k.c b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/j2k.c new file mode 100644 index 0000000..de1c206 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/j2k.c @@ -0,0 +1,2434 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2006-2007, Parvatha Elangovan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "opj_includes.h" + +/** @defgroup J2K J2K - JPEG-2000 codestream reader/writer */ +/*@{*/ + +/** @name Local static functions */ +/*@{*/ + +/** +Write the SOC marker (Start Of Codestream) +@param j2k J2K handle +*/ +static void j2k_write_soc(opj_j2k_t *j2k); +/** +Read the SOC marker (Start of Codestream) +@param j2k J2K handle +*/ +static void j2k_read_soc(opj_j2k_t *j2k); +/** +Write the SIZ marker (image and tile size) +@param j2k J2K handle +*/ +static void j2k_write_siz(opj_j2k_t *j2k); +/** +Read the SIZ marker (image and tile size) +@param j2k J2K handle +*/ +static void j2k_read_siz(opj_j2k_t *j2k); +/** +Write the COM marker (comment) +@param j2k J2K handle +*/ +static void j2k_write_com(opj_j2k_t *j2k); +/** +Read the COM marker (comment) +@param j2k J2K handle +*/ +static void j2k_read_com(opj_j2k_t *j2k); +/** +Write the value concerning the specified component in the marker COD and COC +@param j2k J2K handle +@param compno Number of the component concerned by the information written +*/ +static void j2k_write_cox(opj_j2k_t *j2k, int compno); +/** +Read the value concerning the specified component in the marker COD and COC +@param j2k J2K handle +@param compno Number of the component concerned by the information read +*/ +static void j2k_read_cox(opj_j2k_t *j2k, int compno); +/** +Write the COD marker (coding style default) +@param j2k J2K handle +*/ +static void j2k_write_cod(opj_j2k_t *j2k); +/** +Read the COD marker (coding style default) +@param j2k J2K handle +*/ +static void j2k_read_cod(opj_j2k_t *j2k); +/** +Write the COC marker (coding style component) +@param j2k J2K handle +@param compno Number of the component concerned by the information written +*/ +static void j2k_write_coc(opj_j2k_t *j2k, int compno); +/** +Read the COC marker (coding style component) +@param j2k J2K handle +*/ +static void j2k_read_coc(opj_j2k_t *j2k); +/** +Write the value concerning the specified component in the marker QCD and QCC +@param j2k J2K handle +@param compno Number of the component concerned by the information written +*/ +static void j2k_write_qcx(opj_j2k_t *j2k, int compno); +/** +Read the value concerning the specified component in the marker QCD and QCC +@param j2k J2K handle +@param compno Number of the component concern by the information read +@param len Length of the information in the QCX part of the marker QCD/QCC +*/ +static void j2k_read_qcx(opj_j2k_t *j2k, int compno, int len); +/** +Write the QCD marker (quantization default) +@param j2k J2K handle +*/ +static void j2k_write_qcd(opj_j2k_t *j2k); +/** +Read the QCD marker (quantization default) +@param j2k J2K handle +*/ +static void j2k_read_qcd(opj_j2k_t *j2k); +/** +Write the QCC marker (quantization component) +@param j2k J2K handle +@param compno Number of the component concerned by the information written +*/ +static void j2k_write_qcc(opj_j2k_t *j2k, int compno); +/** +Read the QCC marker (quantization component) +@param j2k J2K handle +*/ +static void j2k_read_qcc(opj_j2k_t *j2k); +/** +Write the POC marker (progression order change) +@param j2k J2K handle +*/ +static void j2k_write_poc(opj_j2k_t *j2k); +/** +Read the POC marker (progression order change) +@param j2k J2K handle +*/ +static void j2k_read_poc(opj_j2k_t *j2k); +/** +Read the CRG marker (component registration) +@param j2k J2K handle +*/ +static void j2k_read_crg(opj_j2k_t *j2k); +/** +Read the TLM marker (tile-part lengths) +@param j2k J2K handle +*/ +static void j2k_read_tlm(opj_j2k_t *j2k); +/** +Read the PLM marker (packet length, main header) +@param j2k J2K handle +*/ +static void j2k_read_plm(opj_j2k_t *j2k); +/** +Read the PLT marker (packet length, tile-part header) +@param j2k J2K handle +*/ +static void j2k_read_plt(opj_j2k_t *j2k); +/** +Read the PPM marker (packet packet headers, main header) +@param j2k J2K handle +*/ +static void j2k_read_ppm(opj_j2k_t *j2k); +/** +Read the PPT marker (packet packet headers, tile-part header) +@param j2k J2K handle +*/ +static void j2k_read_ppt(opj_j2k_t *j2k); +/** +Write the TLM marker (Mainheader) +@param j2k J2K handle +*/ +static void j2k_write_tlm(opj_j2k_t *j2k); +/** +Write the SOT marker (start of tile-part) +@param j2k J2K handle +*/ +static void j2k_write_sot(opj_j2k_t *j2k); +/** +Read the SOT marker (start of tile-part) +@param j2k J2K handle +*/ +static void j2k_read_sot(opj_j2k_t *j2k); +/** +Write the SOD marker (start of data) +@param j2k J2K handle +@param tile_coder Pointer to a TCD handle +*/ +static void j2k_write_sod(opj_j2k_t *j2k, void *tile_coder); +/** +Read the SOD marker (start of data) +@param j2k J2K handle +*/ +static void j2k_read_sod(opj_j2k_t *j2k); +/** +Write the RGN marker (region-of-interest) +@param j2k J2K handle +@param compno Number of the component concerned by the information written +@param tileno Number of the tile concerned by the information written +*/ +static void j2k_write_rgn(opj_j2k_t *j2k, int compno, int tileno); +/** +Read the RGN marker (region-of-interest) +@param j2k J2K handle +*/ +static void j2k_read_rgn(opj_j2k_t *j2k); +/** +Write the EOC marker (end of codestream) +@param j2k J2K handle +*/ +static void j2k_write_eoc(opj_j2k_t *j2k); +/** +Read the EOC marker (end of codestream) +@param j2k J2K handle +*/ +static void j2k_read_eoc(opj_j2k_t *j2k); +/** +Read an unknown marker +@param j2k J2K handle +*/ +static void j2k_read_unk(opj_j2k_t *j2k); + +/*@}*/ + +/*@}*/ + +/* ----------------------------------------------------------------------- */ +typedef struct j2k_prog_order{ + OPJ_PROG_ORDER enum_prog; + char str_prog[4]; +}j2k_prog_order_t; + +j2k_prog_order_t j2k_prog_order_list[] = { + {CPRL, "CPRL"}, + {LRCP, "LRCP"}, + {PCRL, "PCRL"}, + {RLCP, "RLCP"}, + {RPCL, "RPCL"}, + {(OPJ_PROG_ORDER)-1, ""} +}; + +char *j2k_convert_progression_order(OPJ_PROG_ORDER prg_order){ + j2k_prog_order_t *po; + for(po = j2k_prog_order_list; po->enum_prog != -1; po++ ){ + if(po->enum_prog == prg_order){ + break; + } + } + return po->str_prog; +} + +/* ----------------------------------------------------------------------- */ +static int j2k_get_num_tp(opj_cp_t *cp,int pino,int tileno){ + char *prog; + int i; + int tpnum=1,tpend=0; + opj_tcp_t *tcp = &cp->tcps[tileno]; + prog = j2k_convert_progression_order(tcp->prg); + + if(cp->tp_on == 1){ + for(i=0;i<4;i++){ + if(tpend!=1){ + if( cp->tp_flag == prog[i] ){ + tpend=1;cp->tp_pos=i; + } + switch(prog[i]){ + case 'C': + tpnum= tpnum * tcp->pocs[pino].compE; + break; + case 'R': + tpnum= tpnum * tcp->pocs[pino].resE; + break; + case 'P': + tpnum= tpnum * tcp->pocs[pino].prcE; + break; + case 'L': + tpnum= tpnum * tcp->pocs[pino].layE; + break; + } + } + } + }else{ + tpnum=1; + } + return tpnum; +} + +/** mem allocation for TLM marker*/ +int j2k_calculate_tp(opj_cp_t *cp,int img_numcomp,opj_image_t *image,opj_j2k_t *j2k ){ + int pino,tileno,totnum_tp=0; + j2k->cur_totnum_tp = (int *) opj_malloc(cp->tw * cp->th * sizeof(int)); + for (tileno = 0; tileno < cp->tw * cp->th; tileno++) { + int cur_totnum_tp = 0; + opj_tcp_t *tcp = &cp->tcps[tileno]; + for(pino = 0; pino <= tcp->numpocs; pino++) { + int tp_num=0; + opj_pi_iterator_t *pi = pi_initialise_encode(image, cp, tileno,FINAL_PASS); + if(!pi) { return -1;} + tp_num = j2k_get_num_tp(cp,pino,tileno); + totnum_tp = totnum_tp + tp_num; + cur_totnum_tp = cur_totnum_tp + tp_num; + pi_destroy(pi, cp, tileno); + } + j2k->cur_totnum_tp[tileno] = cur_totnum_tp; + /* INDEX >> */ + if (j2k->cstr_info) { + j2k->cstr_info->tile[tileno].num_tps = cur_totnum_tp; + j2k->cstr_info->tile[tileno].tp = (opj_tp_info_t *) opj_malloc(cur_totnum_tp * sizeof(opj_tp_info_t)); + } + /* << INDEX */ + } + return totnum_tp; +} + +static void j2k_write_soc(opj_j2k_t *j2k) { + opj_cio_t *cio = j2k->cio; + cio_write(cio, J2K_MS_SOC, 2); + +/* UniPG>> */ +#ifdef USE_JPWL + + /* update markers struct */ + j2k_add_marker(j2k->cstr_info, J2K_MS_SOC, cio_tell(cio) - 2, 2); + +#endif /* USE_JPWL */ +/* <state = J2K_STATE_MHSIZ; + /* Index */ + if (j2k->cstr_info) { + j2k->cstr_info->main_head_start = cio_tell(j2k->cio) - 2; + j2k->cstr_info->codestream_size = cio_numbytesleft(j2k->cio) + 2 - j2k->cstr_info->main_head_start; + } +} + +static void j2k_write_siz(opj_j2k_t *j2k) { + int i; + int lenp, len; + + opj_cio_t *cio = j2k->cio; + opj_image_t *image = j2k->image; + opj_cp_t *cp = j2k->cp; + + cio_write(cio, J2K_MS_SIZ, 2); /* SIZ */ + lenp = cio_tell(cio); + cio_skip(cio, 2); + cio_write(cio, cp->rsiz, 2); /* Rsiz (capabilities) */ + cio_write(cio, image->x1, 4); /* Xsiz */ + cio_write(cio, image->y1, 4); /* Ysiz */ + cio_write(cio, image->x0, 4); /* X0siz */ + cio_write(cio, image->y0, 4); /* Y0siz */ + cio_write(cio, cp->tdx, 4); /* XTsiz */ + cio_write(cio, cp->tdy, 4); /* YTsiz */ + cio_write(cio, cp->tx0, 4); /* XT0siz */ + cio_write(cio, cp->ty0, 4); /* YT0siz */ + cio_write(cio, image->numcomps, 2); /* Csiz */ + for (i = 0; i < image->numcomps; i++) { + cio_write(cio, image->comps[i].prec - 1 + (image->comps[i].sgnd << 7), 1); /* Ssiz_i */ + cio_write(cio, image->comps[i].dx, 1); /* XRsiz_i */ + cio_write(cio, image->comps[i].dy, 1); /* YRsiz_i */ + } + len = cio_tell(cio) - lenp; + cio_seek(cio, lenp); + cio_write(cio, len, 2); /* Lsiz */ + cio_seek(cio, lenp + len); +} + +static void j2k_read_siz(opj_j2k_t *j2k) { + int len, i; + + opj_cio_t *cio = j2k->cio; + opj_image_t *image = j2k->image; + opj_cp_t *cp = j2k->cp; + + len = cio_read(cio, 2); /* Lsiz */ + cio_read(cio, 2); /* Rsiz (capabilities) */ + image->x1 = cio_read(cio, 4); /* Xsiz */ + image->y1 = cio_read(cio, 4); /* Ysiz */ + image->x0 = cio_read(cio, 4); /* X0siz */ + image->y0 = cio_read(cio, 4); /* Y0siz */ + cp->tdx = cio_read(cio, 4); /* XTsiz */ + cp->tdy = cio_read(cio, 4); /* YTsiz */ + cp->tx0 = cio_read(cio, 4); /* XT0siz */ + cp->ty0 = cio_read(cio, 4); /* YT0siz */ + + if ((image->x0<0)||(image->x1<0)||(image->y0<0)||(image->y1<0)) { + opj_event_msg(j2k->cinfo, EVT_ERROR, + "%s: invalid image size (x0:%d, x1:%d, y0:%d, y1:%d)\n", + image->x0,image->x1,image->y0,image->y1); + return; + } + + image->numcomps = cio_read(cio, 2); /* Csiz */ + +#ifdef USE_JPWL + if (j2k->cp->correct) { + /* if JPWL is on, we check whether TX errors have damaged + too much the SIZ parameters */ + if (!(image->x1 * image->y1)) { + opj_event_msg(j2k->cinfo, EVT_ERROR, + "JPWL: bad image size (%d x %d)\n", + image->x1, image->y1); + if (!JPWL_ASSUME || JPWL_ASSUME) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + return; + } + } + if (image->numcomps != ((len - 38) / 3)) { + opj_event_msg(j2k->cinfo, JPWL_ASSUME ? EVT_WARNING : EVT_ERROR, + "JPWL: Csiz is %d => space in SIZ only for %d comps.!!!\n", + image->numcomps, ((len - 38) / 3)); + if (!JPWL_ASSUME) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + return; + } + /* we try to correct */ + opj_event_msg(j2k->cinfo, EVT_WARNING, "- trying to adjust this\n"); + if (image->numcomps < ((len - 38) / 3)) { + len = 38 + 3 * image->numcomps; + opj_event_msg(j2k->cinfo, EVT_WARNING, "- setting Lsiz to %d => HYPOTHESIS!!!\n", + len); + } else { + image->numcomps = ((len - 38) / 3); + opj_event_msg(j2k->cinfo, EVT_WARNING, "- setting Csiz to %d => HYPOTHESIS!!!\n", + image->numcomps); + } + } + + /* update components number in the jpwl_exp_comps filed */ + cp->exp_comps = image->numcomps; + } +#endif /* USE_JPWL */ + + image->comps = (opj_image_comp_t*) opj_calloc(image->numcomps, sizeof(opj_image_comp_t)); + for (i = 0; i < image->numcomps; i++) { + int tmp, w, h; + tmp = cio_read(cio, 1); /* Ssiz_i */ + image->comps[i].prec = (tmp & 0x7f) + 1; + image->comps[i].sgnd = tmp >> 7; + image->comps[i].dx = cio_read(cio, 1); /* XRsiz_i */ + image->comps[i].dy = cio_read(cio, 1); /* YRsiz_i */ + +#ifdef USE_JPWL + if (j2k->cp->correct) { + /* if JPWL is on, we check whether TX errors have damaged + too much the SIZ parameters, again */ + if (!(image->comps[i].dx * image->comps[i].dy)) { + opj_event_msg(j2k->cinfo, JPWL_ASSUME ? EVT_WARNING : EVT_ERROR, + "JPWL: bad XRsiz_%d/YRsiz_%d (%d x %d)\n", + i, i, image->comps[i].dx, image->comps[i].dy); + if (!JPWL_ASSUME) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + return; + } + /* we try to correct */ + opj_event_msg(j2k->cinfo, EVT_WARNING, "- trying to adjust them\n"); + if (!image->comps[i].dx) { + image->comps[i].dx = 1; + opj_event_msg(j2k->cinfo, EVT_WARNING, "- setting XRsiz_%d to %d => HYPOTHESIS!!!\n", + i, image->comps[i].dx); + } + if (!image->comps[i].dy) { + image->comps[i].dy = 1; + opj_event_msg(j2k->cinfo, EVT_WARNING, "- setting YRsiz_%d to %d => HYPOTHESIS!!!\n", + i, image->comps[i].dy); + } + } + + } +#endif /* USE_JPWL */ + + /* TODO: unused ? */ + w = int_ceildiv(image->x1 - image->x0, image->comps[i].dx); + h = int_ceildiv(image->y1 - image->y0, image->comps[i].dy); + + image->comps[i].resno_decoded = 0; /* number of resolution decoded */ + image->comps[i].factor = cp->reduce; /* reducing factor per component */ + } + + cp->tw = int_ceildiv(image->x1 - cp->tx0, cp->tdx); + cp->th = int_ceildiv(image->y1 - cp->ty0, cp->tdy); + +#ifdef USE_JPWL + if (j2k->cp->correct) { + /* if JPWL is on, we check whether TX errors have damaged + too much the SIZ parameters */ + if ((cp->tw < 1) || (cp->th < 1) || (cp->tw > cp->max_tiles) || (cp->th > cp->max_tiles)) { + opj_event_msg(j2k->cinfo, JPWL_ASSUME ? EVT_WARNING : EVT_ERROR, + "JPWL: bad number of tiles (%d x %d)\n", + cp->tw, cp->th); + if (!JPWL_ASSUME) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + return; + } + /* we try to correct */ + opj_event_msg(j2k->cinfo, EVT_WARNING, "- trying to adjust them\n"); + if (cp->tw < 1) { + cp->tw= 1; + opj_event_msg(j2k->cinfo, EVT_WARNING, "- setting %d tiles in x => HYPOTHESIS!!!\n", + cp->tw); + } + if (cp->tw > cp->max_tiles) { + cp->tw= 1; + opj_event_msg(j2k->cinfo, EVT_WARNING, "- too large x, increase expectance of %d\n" + "- setting %d tiles in x => HYPOTHESIS!!!\n", + cp->max_tiles, cp->tw); + } + if (cp->th < 1) { + cp->th= 1; + opj_event_msg(j2k->cinfo, EVT_WARNING, "- setting %d tiles in y => HYPOTHESIS!!!\n", + cp->th); + } + if (cp->th > cp->max_tiles) { + cp->th= 1; + opj_event_msg(j2k->cinfo, EVT_WARNING, "- too large y, increase expectance of %d to continue\n", + "- setting %d tiles in y => HYPOTHESIS!!!\n", + cp->max_tiles, cp->th); + } + } + } +#endif /* USE_JPWL */ + + cp->tcps = (opj_tcp_t*) opj_calloc(cp->tw * cp->th, sizeof(opj_tcp_t)); + cp->tileno = (int*) opj_malloc(cp->tw * cp->th * sizeof(int)); + cp->tileno_size = 0; + +#ifdef USE_JPWL + if (j2k->cp->correct) { + if (!cp->tcps) { + opj_event_msg(j2k->cinfo, JPWL_ASSUME ? EVT_WARNING : EVT_ERROR, + "JPWL: could not alloc tcps field of cp\n"); + if (!JPWL_ASSUME || JPWL_ASSUME) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + return; + } + } + } +#endif /* USE_JPWL */ + + for (i = 0; i < cp->tw * cp->th; i++) { + cp->tcps[i].POC = 0; + cp->tcps[i].numpocs = 0; + cp->tcps[i].first = 1; + } + + /* Initialization for PPM marker */ + cp->ppm = 0; + cp->ppm_data = NULL; + cp->ppm_data_first = NULL; + cp->ppm_previous = 0; + cp->ppm_store = 0; + + j2k->default_tcp->tccps = (opj_tccp_t*) opj_calloc(image->numcomps, sizeof(opj_tccp_t)); + for (i = 0; i < cp->tw * cp->th; i++) { + cp->tcps[i].tccps = (opj_tccp_t*) opj_malloc(image->numcomps * sizeof(opj_tccp_t)); + } + j2k->tile_data = (unsigned char**) opj_calloc(cp->tw * cp->th, sizeof(unsigned char*)); + j2k->tile_len = (int*) opj_calloc(cp->tw * cp->th, sizeof(int)); + j2k->state = J2K_STATE_MH; + + /* Index */ + if (j2k->cstr_info) { + opj_codestream_info_t *cstr_info = j2k->cstr_info; + cstr_info->image_w = image->x1 - image->x0; + cstr_info->image_h = image->y1 - image->y0; + cstr_info->numcomps = image->numcomps; + cstr_info->tw = cp->tw; + cstr_info->th = cp->th; + cstr_info->tile_x = cp->tdx; + cstr_info->tile_y = cp->tdy; + cstr_info->tile_Ox = cp->tx0; + cstr_info->tile_Oy = cp->ty0; + cstr_info->tile = (opj_tile_info_t*) opj_calloc(cp->tw * cp->th, sizeof(opj_tile_info_t)); + } +} + +static void j2k_write_com(opj_j2k_t *j2k) { + unsigned int i; + int lenp, len; + + if(j2k->cp->comment) { + opj_cio_t *cio = j2k->cio; + char *comment = j2k->cp->comment; + + cio_write(cio, J2K_MS_COM, 2); + lenp = cio_tell(cio); + cio_skip(cio, 2); + cio_write(cio, 1, 2); /* General use (IS 8859-15:1999 (Latin) values) */ + for (i = 0; i < strlen(comment); i++) { + cio_write(cio, comment[i], 1); + } + len = cio_tell(cio) - lenp; + cio_seek(cio, lenp); + cio_write(cio, len, 2); + cio_seek(cio, lenp + len); + } +} + +static void j2k_read_com(opj_j2k_t *j2k) { + int len; + + opj_cio_t *cio = j2k->cio; + + len = cio_read(cio, 2); + cio_skip(cio, len - 2); +} + +static void j2k_write_cox(opj_j2k_t *j2k, int compno) { + int i; + + opj_cp_t *cp = j2k->cp; + opj_tcp_t *tcp = &cp->tcps[j2k->curtileno]; + opj_tccp_t *tccp = &tcp->tccps[compno]; + opj_cio_t *cio = j2k->cio; + + cio_write(cio, tccp->numresolutions - 1, 1); /* SPcox (D) */ + cio_write(cio, tccp->cblkw - 2, 1); /* SPcox (E) */ + cio_write(cio, tccp->cblkh - 2, 1); /* SPcox (F) */ + cio_write(cio, tccp->cblksty, 1); /* SPcox (G) */ + cio_write(cio, tccp->qmfbid, 1); /* SPcox (H) */ + + if (tccp->csty & J2K_CCP_CSTY_PRT) { + for (i = 0; i < tccp->numresolutions; i++) { + cio_write(cio, tccp->prcw[i] + (tccp->prch[i] << 4), 1); /* SPcox (I_i) */ + } + } +} + +static void j2k_read_cox(opj_j2k_t *j2k, int compno) { + int i; + + opj_cp_t *cp = j2k->cp; + opj_tcp_t *tcp = j2k->state == J2K_STATE_TPH ? &cp->tcps[j2k->curtileno] : j2k->default_tcp; + opj_tccp_t *tccp = &tcp->tccps[compno]; + opj_cio_t *cio = j2k->cio; + + tccp->numresolutions = cio_read(cio, 1) + 1; /* SPcox (D) */ + + // If user wants to remove more resolutions than the codestream contains, return error + if (cp->reduce >= tccp->numresolutions) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "Error decoding component %d.\nThe number of resolutions to remove is higher than the number " + "of resolutions of this component\nModify the cp_reduce parameter.\n\n", compno); + j2k->state |= J2K_STATE_ERR; + } + + tccp->cblkw = cio_read(cio, 1) + 2; /* SPcox (E) */ + tccp->cblkh = cio_read(cio, 1) + 2; /* SPcox (F) */ + tccp->cblksty = cio_read(cio, 1); /* SPcox (G) */ + tccp->qmfbid = cio_read(cio, 1); /* SPcox (H) */ + if (tccp->csty & J2K_CP_CSTY_PRT) { + for (i = 0; i < tccp->numresolutions; i++) { + int tmp = cio_read(cio, 1); /* SPcox (I_i) */ + tccp->prcw[i] = tmp & 0xf; + tccp->prch[i] = tmp >> 4; + } + } + + /* INDEX >> */ + if(j2k->cstr_info && compno == 0) { + for (i = 0; i < tccp->numresolutions; i++) { + if (tccp->csty & J2K_CP_CSTY_PRT) { + j2k->cstr_info->tile[j2k->curtileno].pdx[i] = tccp->prcw[i]; + j2k->cstr_info->tile[j2k->curtileno].pdy[i] = tccp->prch[i]; + } + else { + j2k->cstr_info->tile[j2k->curtileno].pdx[i] = 15; + j2k->cstr_info->tile[j2k->curtileno].pdx[i] = 15; + } + } + } + /* << INDEX */ +} + +static void j2k_write_cod(opj_j2k_t *j2k) { + opj_cp_t *cp = NULL; + opj_tcp_t *tcp = NULL; + int lenp, len; + + opj_cio_t *cio = j2k->cio; + + cio_write(cio, J2K_MS_COD, 2); /* COD */ + + lenp = cio_tell(cio); + cio_skip(cio, 2); + + cp = j2k->cp; + tcp = &cp->tcps[j2k->curtileno]; + + cio_write(cio, tcp->csty, 1); /* Scod */ + cio_write(cio, tcp->prg, 1); /* SGcod (A) */ + cio_write(cio, tcp->numlayers, 2); /* SGcod (B) */ + cio_write(cio, tcp->mct, 1); /* SGcod (C) */ + + j2k_write_cox(j2k, 0); + len = cio_tell(cio) - lenp; + cio_seek(cio, lenp); + cio_write(cio, len, 2); /* Lcod */ + cio_seek(cio, lenp + len); +} + +static void j2k_read_cod(opj_j2k_t *j2k) { + int len, i, pos; + + opj_cio_t *cio = j2k->cio; + opj_cp_t *cp = j2k->cp; + opj_tcp_t *tcp = j2k->state == J2K_STATE_TPH ? &cp->tcps[j2k->curtileno] : j2k->default_tcp; + opj_image_t *image = j2k->image; + + len = cio_read(cio, 2); /* Lcod */ + tcp->csty = cio_read(cio, 1); /* Scod */ + tcp->prg = (OPJ_PROG_ORDER)cio_read(cio, 1); /* SGcod (A) */ + tcp->numlayers = cio_read(cio, 2); /* SGcod (B) */ + tcp->mct = cio_read(cio, 1); /* SGcod (C) */ + + pos = cio_tell(cio); + for (i = 0; i < image->numcomps; i++) { + tcp->tccps[i].csty = tcp->csty & J2K_CP_CSTY_PRT; + cio_seek(cio, pos); + j2k_read_cox(j2k, i); + } + + /* Index */ + if (j2k->cstr_info) { + opj_codestream_info_t *cstr_info = j2k->cstr_info; + cstr_info->prog = tcp->prg; + cstr_info->numlayers = tcp->numlayers; + cstr_info->numdecompos = (int*) opj_malloc(image->numcomps * sizeof(int)); + for (i = 0; i < image->numcomps; i++) { + cstr_info->numdecompos[i] = tcp->tccps[i].numresolutions - 1; + } + } +} + +static void j2k_write_coc(opj_j2k_t *j2k, int compno) { + int lenp, len; + + opj_cp_t *cp = j2k->cp; + opj_tcp_t *tcp = &cp->tcps[j2k->curtileno]; + opj_image_t *image = j2k->image; + opj_cio_t *cio = j2k->cio; + + cio_write(cio, J2K_MS_COC, 2); /* COC */ + lenp = cio_tell(cio); + cio_skip(cio, 2); + cio_write(cio, compno, image->numcomps <= 256 ? 1 : 2); /* Ccoc */ + cio_write(cio, tcp->tccps[compno].csty, 1); /* Scoc */ + j2k_write_cox(j2k, compno); + len = cio_tell(cio) - lenp; + cio_seek(cio, lenp); + cio_write(cio, len, 2); /* Lcoc */ + cio_seek(cio, lenp + len); +} + +static void j2k_read_coc(opj_j2k_t *j2k) { + int len, compno; + + opj_cp_t *cp = j2k->cp; + opj_tcp_t *tcp = j2k->state == J2K_STATE_TPH ? &cp->tcps[j2k->curtileno] : j2k->default_tcp; + opj_image_t *image = j2k->image; + opj_cio_t *cio = j2k->cio; + + len = cio_read(cio, 2); /* Lcoc */ + compno = cio_read(cio, image->numcomps <= 256 ? 1 : 2); /* Ccoc */ + tcp->tccps[compno].csty = cio_read(cio, 1); /* Scoc */ + j2k_read_cox(j2k, compno); +} + +static void j2k_write_qcx(opj_j2k_t *j2k, int compno) { + int bandno, numbands; + int expn, mant; + + opj_cp_t *cp = j2k->cp; + opj_tcp_t *tcp = &cp->tcps[j2k->curtileno]; + opj_tccp_t *tccp = &tcp->tccps[compno]; + opj_cio_t *cio = j2k->cio; + + cio_write(cio, tccp->qntsty + (tccp->numgbits << 5), 1); /* Sqcx */ + numbands = tccp->qntsty == J2K_CCP_QNTSTY_SIQNT ? 1 : tccp->numresolutions * 3 - 2; + + for (bandno = 0; bandno < numbands; bandno++) { + expn = tccp->stepsizes[bandno].expn; + mant = tccp->stepsizes[bandno].mant; + + if (tccp->qntsty == J2K_CCP_QNTSTY_NOQNT) { + cio_write(cio, expn << 3, 1); /* SPqcx_i */ + } else { + cio_write(cio, (expn << 11) + mant, 2); /* SPqcx_i */ + } + } +} + +static void j2k_read_qcx(opj_j2k_t *j2k, int compno, int len) { + int tmp; + int bandno, numbands; + + opj_cp_t *cp = j2k->cp; + opj_tcp_t *tcp = j2k->state == J2K_STATE_TPH ? &cp->tcps[j2k->curtileno] : j2k->default_tcp; + opj_tccp_t *tccp = &tcp->tccps[compno]; + opj_cio_t *cio = j2k->cio; + + tmp = cio_read(cio, 1); /* Sqcx */ + tccp->qntsty = tmp & 0x1f; + tccp->numgbits = tmp >> 5; + numbands = (tccp->qntsty == J2K_CCP_QNTSTY_SIQNT) ? + 1 : ((tccp->qntsty == J2K_CCP_QNTSTY_NOQNT) ? len - 1 : (len - 1) / 2); + +#ifdef USE_JPWL + if (j2k->cp->correct) { + + /* if JPWL is on, we check whether there are too many subbands */ + if ((numbands < 0) || (numbands >= J2K_MAXBANDS)) { + opj_event_msg(j2k->cinfo, JPWL_ASSUME ? EVT_WARNING : EVT_ERROR, + "JPWL: bad number of subbands in Sqcx (%d)\n", + numbands); + if (!JPWL_ASSUME) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + return; + } + /* we try to correct */ + numbands = 1; + opj_event_msg(j2k->cinfo, EVT_WARNING, "- trying to adjust them\n" + "- setting number of bands to %d => HYPOTHESIS!!!\n", + numbands); + }; + + }; +#endif /* USE_JPWL */ + + for (bandno = 0; bandno < numbands; bandno++) { + int expn, mant; + if (tccp->qntsty == J2K_CCP_QNTSTY_NOQNT) { + expn = cio_read(cio, 1) >> 3; /* SPqcx_i */ + mant = 0; + } else { + tmp = cio_read(cio, 2); /* SPqcx_i */ + expn = tmp >> 11; + mant = tmp & 0x7ff; + } + tccp->stepsizes[bandno].expn = expn; + tccp->stepsizes[bandno].mant = mant; + } + + /* Add Antonin : if scalar_derived -> compute other stepsizes */ + if (tccp->qntsty == J2K_CCP_QNTSTY_SIQNT) { + for (bandno = 1; bandno < J2K_MAXBANDS; bandno++) { + tccp->stepsizes[bandno].expn = + ((tccp->stepsizes[0].expn) - ((bandno - 1) / 3) > 0) ? + (tccp->stepsizes[0].expn) - ((bandno - 1) / 3) : 0; + tccp->stepsizes[bandno].mant = tccp->stepsizes[0].mant; + } + } + /* ddA */ +} + +static void j2k_write_qcd(opj_j2k_t *j2k) { + int lenp, len; + + opj_cio_t *cio = j2k->cio; + + cio_write(cio, J2K_MS_QCD, 2); /* QCD */ + lenp = cio_tell(cio); + cio_skip(cio, 2); + j2k_write_qcx(j2k, 0); + len = cio_tell(cio) - lenp; + cio_seek(cio, lenp); + cio_write(cio, len, 2); /* Lqcd */ + cio_seek(cio, lenp + len); +} + +static void j2k_read_qcd(opj_j2k_t *j2k) { + int len, i, pos; + + opj_cio_t *cio = j2k->cio; + opj_image_t *image = j2k->image; + + len = cio_read(cio, 2); /* Lqcd */ + pos = cio_tell(cio); + for (i = 0; i < image->numcomps; i++) { + cio_seek(cio, pos); + j2k_read_qcx(j2k, i, len - 2); + } +} + +static void j2k_write_qcc(opj_j2k_t *j2k, int compno) { + int lenp, len; + + opj_cio_t *cio = j2k->cio; + + cio_write(cio, J2K_MS_QCC, 2); /* QCC */ + lenp = cio_tell(cio); + cio_skip(cio, 2); + cio_write(cio, compno, j2k->image->numcomps <= 256 ? 1 : 2); /* Cqcc */ + j2k_write_qcx(j2k, compno); + len = cio_tell(cio) - lenp; + cio_seek(cio, lenp); + cio_write(cio, len, 2); /* Lqcc */ + cio_seek(cio, lenp + len); +} + +static void j2k_read_qcc(opj_j2k_t *j2k) { + int len, compno; + int numcomp = j2k->image->numcomps; + opj_cio_t *cio = j2k->cio; + + len = cio_read(cio, 2); /* Lqcc */ + compno = cio_read(cio, numcomp <= 256 ? 1 : 2); /* Cqcc */ + +#ifdef USE_JPWL + if (j2k->cp->correct) { + + static int backup_compno = 0; + + /* compno is negative or larger than the number of components!!! */ + if ((compno < 0) || (compno >= numcomp)) { + opj_event_msg(j2k->cinfo, EVT_ERROR, + "JPWL: bad component number in QCC (%d out of a maximum of %d)\n", + compno, numcomp); + if (!JPWL_ASSUME) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + return; + } + /* we try to correct */ + compno = backup_compno % numcomp; + opj_event_msg(j2k->cinfo, EVT_WARNING, "- trying to adjust this\n" + "- setting component number to %d\n", + compno); + } + + /* keep your private count of tiles */ + backup_compno++; + }; +#endif /* USE_JPWL */ + + j2k_read_qcx(j2k, compno, len - 2 - (numcomp <= 256 ? 1 : 2)); +} + +static void j2k_write_poc(opj_j2k_t *j2k) { + int len, numpchgs, i; + + int numcomps = j2k->image->numcomps; + + opj_cp_t *cp = j2k->cp; + opj_tcp_t *tcp = &cp->tcps[j2k->curtileno]; + opj_tccp_t *tccp = &tcp->tccps[0]; + opj_cio_t *cio = j2k->cio; + + numpchgs = 1 + tcp->numpocs; + cio_write(cio, J2K_MS_POC, 2); /* POC */ + len = 2 + (5 + 2 * (numcomps <= 256 ? 1 : 2)) * numpchgs; + cio_write(cio, len, 2); /* Lpoc */ + for (i = 0; i < numpchgs; i++) { + opj_poc_t *poc = &tcp->pocs[i]; + cio_write(cio, poc->resno0, 1); /* RSpoc_i */ + cio_write(cio, poc->compno0, (numcomps <= 256 ? 1 : 2)); /* CSpoc_i */ + cio_write(cio, poc->layno1, 2); /* LYEpoc_i */ + poc->layno1 = int_min(poc->layno1, tcp->numlayers); + cio_write(cio, poc->resno1, 1); /* REpoc_i */ + poc->resno1 = int_min(poc->resno1, tccp->numresolutions); + cio_write(cio, poc->compno1, (numcomps <= 256 ? 1 : 2)); /* CEpoc_i */ + poc->compno1 = int_min(poc->compno1, numcomps); + cio_write(cio, poc->prg, 1); /* Ppoc_i */ + } +} + +static void j2k_read_poc(opj_j2k_t *j2k) { + int len, numpchgs, i, old_poc; + + int numcomps = j2k->image->numcomps; + + opj_cp_t *cp = j2k->cp; + opj_tcp_t *tcp = j2k->state == J2K_STATE_TPH ? &cp->tcps[j2k->curtileno] : j2k->default_tcp; + opj_cio_t *cio = j2k->cio; + + old_poc = tcp->POC ? tcp->numpocs + 1 : 0; + tcp->POC = 1; + len = cio_read(cio, 2); /* Lpoc */ + numpchgs = (len - 2) / (5 + 2 * (numcomps <= 256 ? 1 : 2)); + + for (i = old_poc; i < numpchgs + old_poc; i++) { + opj_poc_t *poc; + poc = &tcp->pocs[i]; + poc->resno0 = cio_read(cio, 1); /* RSpoc_i */ + poc->compno0 = cio_read(cio, numcomps <= 256 ? 1 : 2); /* CSpoc_i */ + poc->layno1 = cio_read(cio, 2); /* LYEpoc_i */ + poc->resno1 = cio_read(cio, 1); /* REpoc_i */ + poc->compno1 = int_min( + cio_read(cio, numcomps <= 256 ? 1 : 2), (unsigned int) numcomps); /* CEpoc_i */ + poc->prg = (OPJ_PROG_ORDER)cio_read(cio, 1); /* Ppoc_i */ + } + + tcp->numpocs = numpchgs + old_poc - 1; +} + +static void j2k_read_crg(opj_j2k_t *j2k) { + int len, i, Xcrg_i, Ycrg_i; + + opj_cio_t *cio = j2k->cio; + int numcomps = j2k->image->numcomps; + + len = cio_read(cio, 2); /* Lcrg */ + for (i = 0; i < numcomps; i++) { + Xcrg_i = cio_read(cio, 2); /* Xcrg_i */ + Ycrg_i = cio_read(cio, 2); /* Ycrg_i */ + } +} + +static void j2k_read_tlm(opj_j2k_t *j2k) { + int len, Ztlm, Stlm, ST, SP, tile_tlm, i; + long int Ttlm_i, Ptlm_i; + + opj_cio_t *cio = j2k->cio; + + len = cio_read(cio, 2); /* Ltlm */ + Ztlm = cio_read(cio, 1); /* Ztlm */ + Stlm = cio_read(cio, 1); /* Stlm */ + ST = ((Stlm >> 4) & 0x01) + ((Stlm >> 4) & 0x02); + SP = (Stlm >> 6) & 0x01; + tile_tlm = (len - 4) / ((SP + 1) * 2 + ST); + for (i = 0; i < tile_tlm; i++) { + Ttlm_i = cio_read(cio, ST); /* Ttlm_i */ + Ptlm_i = cio_read(cio, SP ? 4 : 2); /* Ptlm_i */ + } +} + +static void j2k_read_plm(opj_j2k_t *j2k) { + int len, i, Zplm, Nplm, add, packet_len = 0; + + opj_cio_t *cio = j2k->cio; + + len = cio_read(cio, 2); /* Lplm */ + Zplm = cio_read(cio, 1); /* Zplm */ + len -= 3; + while (len > 0) { + Nplm = cio_read(cio, 4); /* Nplm */ + len -= 4; + for (i = Nplm; i > 0; i--) { + add = cio_read(cio, 1); + len--; + packet_len = (packet_len << 7) + add; /* Iplm_ij */ + if ((add & 0x80) == 0) { + /* New packet */ + packet_len = 0; + } + if (len <= 0) + break; + } + } +} + +static void j2k_read_plt(opj_j2k_t *j2k) { + int len, i, Zplt, packet_len = 0, add; + + opj_cio_t *cio = j2k->cio; + + len = cio_read(cio, 2); /* Lplt */ + Zplt = cio_read(cio, 1); /* Zplt */ + for (i = len - 3; i > 0; i--) { + add = cio_read(cio, 1); + packet_len = (packet_len << 7) + add; /* Iplt_i */ + if ((add & 0x80) == 0) { + /* New packet */ + packet_len = 0; + } + } +} + +static void j2k_read_ppm(opj_j2k_t *j2k) { + int len, Z_ppm, i, j; + int N_ppm; + + opj_cp_t *cp = j2k->cp; + opj_cio_t *cio = j2k->cio; + + len = cio_read(cio, 2); + cp->ppm = 1; + + Z_ppm = cio_read(cio, 1); /* Z_ppm */ + len -= 3; + while (len > 0) { + if (cp->ppm_previous == 0) { + N_ppm = cio_read(cio, 4); /* N_ppm */ + len -= 4; + } else { + N_ppm = cp->ppm_previous; + } + j = cp->ppm_store; + if (Z_ppm == 0) { /* First PPM marker */ + cp->ppm_data = (unsigned char *) opj_malloc(N_ppm * sizeof(unsigned char)); + cp->ppm_data_first = cp->ppm_data; + cp->ppm_len = N_ppm; + } else { /* NON-first PPM marker */ + cp->ppm_data = (unsigned char *) opj_realloc(cp->ppm_data, (N_ppm + cp->ppm_store) * sizeof(unsigned char)); + +#ifdef USE_JPWL + /* this memory allocation check could be done even in non-JPWL cases */ + if (cp->correct) { + if (!cp->ppm_data) { + opj_event_msg(j2k->cinfo, EVT_ERROR, + "JPWL: failed memory allocation during PPM marker parsing (pos. %x)\n", + cio_tell(cio)); + if (!JPWL_ASSUME || JPWL_ASSUME) { + opj_free(cp->ppm_data); + opj_event_msg(j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + return; + } + } + } +#endif + + cp->ppm_data_first = cp->ppm_data; + cp->ppm_len = N_ppm + cp->ppm_store; + } + for (i = N_ppm; i > 0; i--) { /* Read packet header */ + cp->ppm_data[j] = cio_read(cio, 1); + j++; + len--; + if (len == 0) + break; /* Case of non-finished packet header in present marker but finished in next one */ + } + cp->ppm_previous = i - 1; + cp->ppm_store = j; + } +} + +static void j2k_read_ppt(opj_j2k_t *j2k) { + int len, Z_ppt, i, j = 0; + + opj_cp_t *cp = j2k->cp; + opj_tcp_t *tcp = cp->tcps + j2k->curtileno; + opj_cio_t *cio = j2k->cio; + + len = cio_read(cio, 2); + Z_ppt = cio_read(cio, 1); + tcp->ppt = 1; + if (Z_ppt == 0) { /* First PPT marker */ + tcp->ppt_data = (unsigned char *) opj_malloc((len - 3) * sizeof(unsigned char)); + tcp->ppt_data_first = tcp->ppt_data; + tcp->ppt_store = 0; + tcp->ppt_len = len - 3; + } else { /* NON-first PPT marker */ + tcp->ppt_data = (unsigned char *) opj_realloc(tcp->ppt_data, (len - 3 + tcp->ppt_store) * sizeof(unsigned char)); + tcp->ppt_data_first = tcp->ppt_data; + tcp->ppt_len = len - 3 + tcp->ppt_store; + } + j = tcp->ppt_store; + for (i = len - 3; i > 0; i--) { + tcp->ppt_data[j] = cio_read(cio, 1); + j++; + } + tcp->ppt_store = j; +} + +static void j2k_write_tlm(opj_j2k_t *j2k){ + int lenp; + opj_cio_t *cio = j2k->cio; + j2k->tlm_start = cio_tell(cio); + cio_write(cio, J2K_MS_TLM, 2);/* TLM */ + lenp = 4 + (5*j2k->totnum_tp); + cio_write(cio,lenp,2); /* Ltlm */ + cio_write(cio, 0,1); /* Ztlm=0*/ + cio_write(cio,80,1); /* Stlm ST=1(8bits-255 tiles max),SP=1(Ptlm=32bits) */ + cio_skip(cio,5*j2k->totnum_tp); +} + +static void j2k_write_sot(opj_j2k_t *j2k) { + int lenp, len; + + opj_cio_t *cio = j2k->cio; + + j2k->sot_start = cio_tell(cio); + cio_write(cio, J2K_MS_SOT, 2); /* SOT */ + lenp = cio_tell(cio); + cio_skip(cio, 2); /* Lsot (further) */ + cio_write(cio, j2k->curtileno, 2); /* Isot */ + cio_skip(cio, 4); /* Psot (further in j2k_write_sod) */ + cio_write(cio, j2k->cur_tp_num , 1); /* TPsot */ + cio_write(cio, j2k->cur_totnum_tp[j2k->curtileno], 1); /* TNsot */ + len = cio_tell(cio) - lenp; + cio_seek(cio, lenp); + cio_write(cio, len, 2); /* Lsot */ + cio_seek(cio, lenp + len); + + /* UniPG>> */ +#ifdef USE_JPWL + /* update markers struct */ + j2k_add_marker(j2k->cstr_info, J2K_MS_SOT, j2k->sot_start, len + 2); +#endif /* USE_JPWL */ + /* <cp; + opj_cio_t *cio = j2k->cio; + + len = cio_read(cio, 2); + tileno = cio_read(cio, 2); + +#ifdef USE_JPWL + if (j2k->cp->correct) { + + static int backup_tileno = 0; + + /* tileno is negative or larger than the number of tiles!!! */ + if ((tileno < 0) || (tileno > (cp->tw * cp->th))) { + opj_event_msg(j2k->cinfo, EVT_ERROR, + "JPWL: bad tile number (%d out of a maximum of %d)\n", + tileno, (cp->tw * cp->th)); + if (!JPWL_ASSUME) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + return; + } + /* we try to correct */ + tileno = backup_tileno; + opj_event_msg(j2k->cinfo, EVT_WARNING, "- trying to adjust this\n" + "- setting tile number to %d\n", + tileno); + } + + /* keep your private count of tiles */ + backup_tileno++; + }; +#endif /* USE_JPWL */ + + if (cp->tileno_size == 0) { + cp->tileno[cp->tileno_size] = tileno; + cp->tileno_size++; + } else { + i = 0; + while (i < cp->tileno_size && status == 0) { + status = cp->tileno[i] == tileno ? 1 : 0; + i++; + } + if (status == 0) { + cp->tileno[cp->tileno_size] = tileno; + cp->tileno_size++; + } + } + + totlen = cio_read(cio, 4); + +#ifdef USE_JPWL + if (j2k->cp->correct) { + + /* totlen is negative or larger than the bytes left!!! */ + if ((totlen < 0) || (totlen > (cio_numbytesleft(cio) + 8))) { + opj_event_msg(j2k->cinfo, EVT_ERROR, + "JPWL: bad tile byte size (%d bytes against %d bytes left)\n", + totlen, cio_numbytesleft(cio) + 8); + if (!JPWL_ASSUME) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + return; + } + /* we try to correct */ + totlen = 0; + opj_event_msg(j2k->cinfo, EVT_WARNING, "- trying to adjust this\n" + "- setting Psot to %d => assuming it is the last tile\n", + totlen); + } + + }; +#endif /* USE_JPWL */ + + if (!totlen) + totlen = cio_numbytesleft(cio) + 8; + + partno = cio_read(cio, 1); + numparts = cio_read(cio, 1); + + j2k->curtileno = tileno; + j2k->cur_tp_num = partno; + j2k->eot = cio_getbp(cio) - 12 + totlen; + j2k->state = J2K_STATE_TPH; + tcp = &cp->tcps[j2k->curtileno]; + + /* Index */ + if (j2k->cstr_info) { + if (tcp->first) { + if (tileno == 0) + j2k->cstr_info->main_head_end = cio_tell(cio) - 13; + j2k->cstr_info->tile[tileno].tileno = tileno; + j2k->cstr_info->tile[tileno].start_pos = cio_tell(cio) - 12; + j2k->cstr_info->tile[tileno].end_pos = j2k->cstr_info->tile[tileno].start_pos + totlen - 1; + j2k->cstr_info->tile[tileno].num_tps = numparts; + if (numparts) + j2k->cstr_info->tile[tileno].tp = (opj_tp_info_t *) opj_malloc(numparts * sizeof(opj_tp_info_t)); + else + j2k->cstr_info->tile[tileno].tp = (opj_tp_info_t *) opj_malloc(10 * sizeof(opj_tp_info_t)); // Fixme (10) + } + else { + j2k->cstr_info->tile[tileno].end_pos += totlen; + } + j2k->cstr_info->tile[tileno].tp[partno].tp_start_pos = cio_tell(cio) - 12; + j2k->cstr_info->tile[tileno].tp[partno].tp_end_pos = + j2k->cstr_info->tile[tileno].tp[partno].tp_start_pos + totlen - 1; + } + + if (tcp->first == 1) { + /* Initialization PPT */ + opj_tccp_t *tmp = tcp->tccps; + memcpy(tcp, j2k->default_tcp, sizeof(opj_tcp_t)); + tcp->ppt = 0; + tcp->ppt_data = NULL; + tcp->ppt_data_first = NULL; + tcp->tccps = tmp; + + for (i = 0; i < j2k->image->numcomps; i++) { + tcp->tccps[i] = j2k->default_tcp->tccps[i]; + } + cp->tcps[j2k->curtileno].first = 0; + } +} + +static void j2k_write_sod(opj_j2k_t *j2k, void *tile_coder) { + int l, layno; + int totlen; + opj_tcp_t *tcp = NULL; + opj_codestream_info_t *cstr_info = NULL; + + opj_tcd_t *tcd = (opj_tcd_t*)tile_coder; /* cast is needed because of conflicts in header inclusions */ + opj_cp_t *cp = j2k->cp; + opj_cio_t *cio = j2k->cio; + + tcd->tp_num = j2k->tp_num ; + tcd->cur_tp_num = j2k->cur_tp_num; + + cio_write(cio, J2K_MS_SOD, 2); + if (j2k->curtileno == 0) { + j2k->sod_start = cio_tell(cio) + j2k->pos_correction; + } + + /* INDEX >> */ + cstr_info = j2k->cstr_info; + if (cstr_info) { + if (!j2k->cur_tp_num ) { + cstr_info->tile[j2k->curtileno].end_header = cio_tell(cio) + j2k->pos_correction - 1; + j2k->cstr_info->tile[j2k->curtileno].tileno = j2k->curtileno; + } + else{ + if(cstr_info->tile[j2k->curtileno].packet[cstr_info->packno - 1].end_pos < cio_tell(cio)) + cstr_info->tile[j2k->curtileno].packet[cstr_info->packno].start_pos = cio_tell(cio); + } + /* UniPG>> */ +#ifdef USE_JPWL + /* update markers struct */ + j2k_add_marker(j2k->cstr_info, J2K_MS_SOD, j2k->sod_start, 2); +#endif /* USE_JPWL */ + /* <tcps[j2k->curtileno]; + for (layno = 0; layno < tcp->numlayers; layno++) { + if (tcp->rates[layno]>(j2k->sod_start / (cp->th * cp->tw))) { + tcp->rates[layno]-=(j2k->sod_start / (cp->th * cp->tw)); + } else if (tcp->rates[layno]) { + tcp->rates[layno]=1; + } + } + if(j2k->cur_tp_num == 0){ + tcd->tcd_image->tiles->packno = 0; + if(cstr_info) + cstr_info->packno = 0; + } + + l = tcd_encode_tile(tcd, j2k->curtileno, cio_getbp(cio), cio_numbytesleft(cio) - 2, cstr_info); + + /* Writing Psot in SOT marker */ + totlen = cio_tell(cio) + l - j2k->sot_start; + cio_seek(cio, j2k->sot_start + 6); + cio_write(cio, totlen, 4); + cio_seek(cio, j2k->sot_start + totlen); + /* Writing Ttlm and Ptlm in TLM marker */ + if(cp->cinema){ + cio_seek(cio, j2k->tlm_start + 6 + (5*j2k->cur_tp_num)); + cio_write(cio, j2k->curtileno, 1); + cio_write(cio, totlen, 4); + } + cio_seek(cio, j2k->sot_start + totlen); +} + +static void j2k_read_sod(opj_j2k_t *j2k) { + int len, truncate = 0, i; + unsigned char *data = NULL, *data_ptr = NULL; + + opj_cio_t *cio = j2k->cio; + int curtileno = j2k->curtileno; + + /* Index */ + if (j2k->cstr_info) { + j2k->cstr_info->tile[j2k->curtileno].tp[j2k->cur_tp_num].tp_end_header = + cio_tell(cio) + j2k->pos_correction - 1; + if (j2k->cur_tp_num == 0) + j2k->cstr_info->tile[j2k->curtileno].end_header = cio_tell(cio) + j2k->pos_correction - 1; + j2k->cstr_info->packno = 0; + } + + len = int_min(j2k->eot - cio_getbp(cio), cio_numbytesleft(cio) + 1); + + if (len == cio_numbytesleft(cio) + 1) { + truncate = 1; /* Case of a truncate codestream */ + } + + data = j2k->tile_data[curtileno]; + data = (unsigned char*) opj_realloc(data, (j2k->tile_len[curtileno] + len) * sizeof(unsigned char)); + + data_ptr = data + j2k->tile_len[curtileno]; + for (i = 0; i < len; i++) { + data_ptr[i] = cio_read(cio, 1); + } + + j2k->tile_len[curtileno] += len; + j2k->tile_data[curtileno] = data; + + if (!truncate) { + j2k->state = J2K_STATE_TPHSOT; + } else { + j2k->state = J2K_STATE_NEOC; /* RAJOUTE !! */ + } + j2k->cur_tp_num++; +} + +static void j2k_write_rgn(opj_j2k_t *j2k, int compno, int tileno) { + opj_cp_t *cp = j2k->cp; + opj_tcp_t *tcp = &cp->tcps[tileno]; + opj_cio_t *cio = j2k->cio; + int numcomps = j2k->image->numcomps; + + cio_write(cio, J2K_MS_RGN, 2); /* RGN */ + cio_write(cio, numcomps <= 256 ? 5 : 6, 2); /* Lrgn */ + cio_write(cio, compno, numcomps <= 256 ? 1 : 2); /* Crgn */ + cio_write(cio, 0, 1); /* Srgn */ + cio_write(cio, tcp->tccps[compno].roishift, 1); /* SPrgn */ +} + +static void j2k_read_rgn(opj_j2k_t *j2k) { + int len, compno, roisty; + + opj_cp_t *cp = j2k->cp; + opj_tcp_t *tcp = j2k->state == J2K_STATE_TPH ? &cp->tcps[j2k->curtileno] : j2k->default_tcp; + opj_cio_t *cio = j2k->cio; + int numcomps = j2k->image->numcomps; + + len = cio_read(cio, 2); /* Lrgn */ + compno = cio_read(cio, numcomps <= 256 ? 1 : 2); /* Crgn */ + roisty = cio_read(cio, 1); /* Srgn */ + +#ifdef USE_JPWL + if (j2k->cp->correct) { + /* totlen is negative or larger than the bytes left!!! */ + if (compno >= numcomps) { + opj_event_msg(j2k->cinfo, EVT_ERROR, + "JPWL: bad component number in RGN (%d when there are only %d)\n", + compno, numcomps); + if (!JPWL_ASSUME || JPWL_ASSUME) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + return; + } + } + }; +#endif /* USE_JPWL */ + + tcp->tccps[compno].roishift = cio_read(cio, 1); /* SPrgn */ +} + +static void j2k_write_eoc(opj_j2k_t *j2k) { + opj_cio_t *cio = j2k->cio; + /* opj_event_msg(j2k->cinfo, "%.8x: EOC\n", cio_tell(cio) + j2k->pos_correction); */ + cio_write(cio, J2K_MS_EOC, 2); + +/* UniPG>> */ +#ifdef USE_JPWL + /* update markers struct */ + j2k_add_marker(j2k->cstr_info, J2K_MS_EOC, cio_tell(cio) - 2, 2); +#endif /* USE_JPWL */ +/* <cp->limit_decoding != DECODE_ALL_BUT_PACKETS) { + opj_tcd_t *tcd = tcd_create(j2k->cinfo); + tcd_malloc_decode(tcd, j2k->image, j2k->cp); + for (i = 0; i < j2k->cp->tileno_size; i++) { + tcd_malloc_decode_tile(tcd, j2k->image, j2k->cp, i, j2k->cstr_info); + tileno = j2k->cp->tileno[i]; + success = tcd_decode_tile(tcd, j2k->tile_data[tileno], j2k->tile_len[tileno], tileno, j2k->cstr_info); + opj_free(j2k->tile_data[tileno]); + j2k->tile_data[tileno] = NULL; + tcd_free_decode_tile(tcd, i); + if (success == false) { + j2k->state |= J2K_STATE_ERR; + break; + } + } + tcd_free_decode(tcd); + tcd_destroy(tcd); + } + /* if packets should not be decoded */ + else { + for (i = 0; i < j2k->cp->tileno_size; i++) { + tileno = j2k->cp->tileno[i]; + opj_free(j2k->tile_data[tileno]); + j2k->tile_data[tileno] = NULL; + } + } + if (j2k->state & J2K_STATE_ERR) + j2k->state = J2K_STATE_MT + J2K_STATE_ERR; + else + j2k->state = J2K_STATE_MT; +} + +typedef struct opj_dec_mstabent { + /** marker value */ + int id; + /** value of the state when the marker can appear */ + int states; + /** action linked to the marker */ + void (*handler) (opj_j2k_t *j2k); +} opj_dec_mstabent_t; + +opj_dec_mstabent_t j2k_dec_mstab[] = { + {J2K_MS_SOC, J2K_STATE_MHSOC, j2k_read_soc}, + {J2K_MS_SOT, J2K_STATE_MH | J2K_STATE_TPHSOT, j2k_read_sot}, + {J2K_MS_SOD, J2K_STATE_TPH, j2k_read_sod}, + {J2K_MS_EOC, J2K_STATE_TPHSOT, j2k_read_eoc}, + {J2K_MS_SIZ, J2K_STATE_MHSIZ, j2k_read_siz}, + {J2K_MS_COD, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_cod}, + {J2K_MS_COC, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_coc}, + {J2K_MS_RGN, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_rgn}, + {J2K_MS_QCD, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_qcd}, + {J2K_MS_QCC, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_qcc}, + {J2K_MS_POC, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_poc}, + {J2K_MS_TLM, J2K_STATE_MH, j2k_read_tlm}, + {J2K_MS_PLM, J2K_STATE_MH, j2k_read_plm}, + {J2K_MS_PLT, J2K_STATE_TPH, j2k_read_plt}, + {J2K_MS_PPM, J2K_STATE_MH, j2k_read_ppm}, + {J2K_MS_PPT, J2K_STATE_TPH, j2k_read_ppt}, + {J2K_MS_SOP, 0, 0}, + {J2K_MS_CRG, J2K_STATE_MH, j2k_read_crg}, + {J2K_MS_COM, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_com}, + +#ifdef USE_JPWL + {J2K_MS_EPC, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_epc}, + {J2K_MS_EPB, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_epb}, + {J2K_MS_ESD, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_esd}, + {J2K_MS_RED, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_red}, +#endif /* USE_JPWL */ +#ifdef USE_JPSEC + {J2K_MS_SEC, J2K_STATE_MH, j2k_read_sec}, + {J2K_MS_INSEC, 0, j2k_read_insec}, +#endif /* USE_JPSEC */ + + {0, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_unk} +}; + +static void j2k_read_unk(opj_j2k_t *j2k) { + opj_event_msg(j2k->cinfo, EVT_WARNING, "Unknown marker\n"); + +#ifdef USE_JPWL + if (j2k->cp->correct) { + int m = 0, id, i; + int min_id = 0, min_dist = 17, cur_dist = 0, tmp_id; + cio_seek(j2k->cio, cio_tell(j2k->cio) - 2); + id = cio_read(j2k->cio, 2); + opj_event_msg(j2k->cinfo, EVT_ERROR, + "JPWL: really don't know this marker %x\n", + id); + if (!JPWL_ASSUME) { + opj_event_msg(j2k->cinfo, EVT_ERROR, + "- possible synch loss due to uncorrectable codestream errors => giving up\n"); + return; + } + /* OK, activate this at your own risk!!! */ + /* we look for the marker at the minimum hamming distance from this */ + while (j2k_dec_mstab[m].id) { + + /* 1's where they differ */ + tmp_id = j2k_dec_mstab[m].id ^ id; + + /* compute the hamming distance between our id and the current */ + cur_dist = 0; + for (i = 0; i < 16; i++) { + if ((tmp_id >> i) & 0x0001) { + cur_dist++; + } + } + + /* if current distance is smaller, set the minimum */ + if (cur_dist < min_dist) { + min_dist = cur_dist; + min_id = j2k_dec_mstab[m].id; + } + + /* jump to the next marker */ + m++; + } + + /* do we substitute the marker? */ + if (min_dist < JPWL_MAXIMUM_HAMMING) { + opj_event_msg(j2k->cinfo, EVT_ERROR, + "- marker %x is at distance %d from the read %x\n", + min_id, min_dist, id); + opj_event_msg(j2k->cinfo, EVT_ERROR, + "- trying to substitute in place and crossing fingers!\n"); + cio_seek(j2k->cio, cio_tell(j2k->cio) - 2); + cio_write(j2k->cio, min_id, 2); + + /* rewind */ + cio_seek(j2k->cio, cio_tell(j2k->cio) - 2); + + } + + }; +#endif /* USE_JPWL */ + +} + +/** +Read the lookup table containing all the marker, status and action +@param id Marker value +*/ +static opj_dec_mstabent_t *j2k_dec_mstab_lookup(int id) { + opj_dec_mstabent_t *e; + for (e = j2k_dec_mstab; e->id != 0; e++) { + if (e->id == id) { + break; + } + } + return e; +} + +/* ----------------------------------------------------------------------- */ +/* J2K / JPT decoder interface */ +/* ----------------------------------------------------------------------- */ + +opj_j2k_t* j2k_create_decompress(opj_common_ptr cinfo) { + opj_j2k_t *j2k = (opj_j2k_t*) opj_calloc(1, sizeof(opj_j2k_t)); + if(!j2k) + return NULL; + + j2k->default_tcp = (opj_tcp_t*) opj_calloc(1, sizeof(opj_tcp_t)); + if(!j2k->default_tcp) { + opj_free(j2k); + return NULL; + } + + j2k->cinfo = cinfo; + j2k->tile_data = NULL; + + return j2k; +} + +void j2k_destroy_decompress(opj_j2k_t *j2k) { + int i = 0; + + if(j2k->tile_len != NULL) { + opj_free(j2k->tile_len); + } + if(j2k->tile_data != NULL) { + opj_free(j2k->tile_data); + } + if(j2k->default_tcp != NULL) { + opj_tcp_t *default_tcp = j2k->default_tcp; + if(default_tcp->ppt_data_first != NULL) { + opj_free(default_tcp->ppt_data_first); + } + if(j2k->default_tcp->tccps != NULL) { + opj_free(j2k->default_tcp->tccps); + } + opj_free(j2k->default_tcp); + } + if(j2k->cp != NULL) { + opj_cp_t *cp = j2k->cp; + if(cp->tcps != NULL) { + for(i = 0; i < cp->tw * cp->th; i++) { + if(cp->tcps[i].ppt_data_first != NULL) { + opj_free(cp->tcps[i].ppt_data_first); + } + if(cp->tcps[i].tccps != NULL) { + opj_free(cp->tcps[i].tccps); + } + } + opj_free(cp->tcps); + } + if(cp->ppm_data_first != NULL) { + opj_free(cp->ppm_data_first); + } + if(cp->tileno != NULL) { + opj_free(cp->tileno); + } + if(cp->comment != NULL) { + opj_free(cp->comment); + } + + opj_free(cp); + } + opj_free(j2k); +} + +void j2k_setup_decoder(opj_j2k_t *j2k, opj_dparameters_t *parameters) { + if(j2k && parameters) { + /* create and initialize the coding parameters structure */ + opj_cp_t *cp = (opj_cp_t*) opj_calloc(1, sizeof(opj_cp_t)); + cp->reduce = parameters->cp_reduce; + cp->layer = parameters->cp_layer; + cp->limit_decoding = parameters->cp_limit_decoding; + +#ifdef USE_JPWL + cp->correct = parameters->jpwl_correct; + cp->exp_comps = parameters->jpwl_exp_comps; + cp->max_tiles = parameters->jpwl_max_tiles; +#endif /* USE_JPWL */ + + + /* keep a link to cp so that we can destroy it later in j2k_destroy_decompress */ + j2k->cp = cp; + } +} + +opj_image_t* j2k_decode(opj_j2k_t *j2k, opj_cio_t *cio, opj_codestream_info_t *cstr_info) { + opj_image_t *image = NULL; + + opj_common_ptr cinfo = j2k->cinfo; + + j2k->cio = cio; + j2k->cstr_info = cstr_info; + if (cstr_info) + memset(cstr_info, 0, sizeof(opj_codestream_info_t)); + + /* create an empty image */ + image = opj_image_create0(); + j2k->image = image; + + j2k->state = J2K_STATE_MHSOC; + + for (;;) { + opj_dec_mstabent_t *e; + int id = cio_read(cio, 2); + +#ifdef USE_JPWL + /* we try to honor JPWL correction power */ + if (j2k->cp->correct) { + + int orig_pos = cio_tell(cio); + bool status; + + /* call the corrector */ + status = jpwl_correct(j2k); + + /* go back to where you were */ + cio_seek(cio, orig_pos - 2); + + /* re-read the marker */ + id = cio_read(cio, 2); + + /* check whether it begins with ff */ + if (id >> 8 != 0xff) { + opj_event_msg(cinfo, EVT_ERROR, + "JPWL: possible bad marker %x at %d\n", + id, cio_tell(cio) - 2); + if (!JPWL_ASSUME) { + opj_image_destroy(image); + opj_event_msg(cinfo, EVT_ERROR, "JPWL: giving up\n"); + return 0; + } + /* we try to correct */ + id = id | 0xff00; + cio_seek(cio, cio_tell(cio) - 2); + cio_write(cio, id, 2); + opj_event_msg(cinfo, EVT_WARNING, "- trying to adjust this\n" + "- setting marker to %x\n", + id); + } + + } +#endif /* USE_JPWL */ + + if (id >> 8 != 0xff) { + opj_image_destroy(image); + opj_event_msg(cinfo, EVT_ERROR, "%.8x: expected a marker instead of %x\n", cio_tell(cio) - 2, id); + return 0; + } + e = j2k_dec_mstab_lookup(id); + // Check if the marker is known + if (!(j2k->state & e->states)) { + opj_image_destroy(image); + opj_event_msg(cinfo, EVT_ERROR, "%.8x: unexpected marker %x\n", cio_tell(cio) - 2, id); + return 0; + } + // Check if the decoding is limited to the main header + if (e->id == J2K_MS_SOT && j2k->cp->limit_decoding == LIMIT_TO_MAIN_HEADER) { + opj_event_msg(cinfo, EVT_INFO, "Main Header decoded.\n"); + return image; + } + + if (e->handler) { + (*e->handler)(j2k); + } + if (j2k->state & J2K_STATE_ERR) + return NULL; + + if (j2k->state == J2K_STATE_MT) { + break; + } + if (j2k->state == J2K_STATE_NEOC) { + break; + } + } + if (j2k->state == J2K_STATE_NEOC) { + j2k_read_eoc(j2k); + } + + if (j2k->state != J2K_STATE_MT) { + opj_event_msg(cinfo, EVT_WARNING, "Incomplete bitstream\n"); + } + + return image; +} + +/* +* Read a JPT-stream and decode file +* +*/ +opj_image_t* j2k_decode_jpt_stream(opj_j2k_t *j2k, opj_cio_t *cio, opj_codestream_info_t *cstr_info) { + opj_image_t *image = NULL; + opj_jpt_msg_header_t header; + int position; + + opj_common_ptr cinfo = j2k->cinfo; + + j2k->cio = cio; + + /* create an empty image */ + image = opj_image_create0(); + j2k->image = image; + + j2k->state = J2K_STATE_MHSOC; + + /* Initialize the header */ + jpt_init_msg_header(&header); + /* Read the first header of the message */ + jpt_read_msg_header(cinfo, cio, &header); + + position = cio_tell(cio); + if (header.Class_Id != 6) { /* 6 : Main header data-bin message */ + opj_image_destroy(image); + opj_event_msg(cinfo, EVT_ERROR, "[JPT-stream] : Expecting Main header first [class_Id %d] !\n", header.Class_Id); + return 0; + } + + for (;;) { + opj_dec_mstabent_t *e = NULL; + int id; + + if (!cio_numbytesleft(cio)) { + j2k_read_eoc(j2k); + return image; + } + /* data-bin read -> need to read a new header */ + if ((unsigned int) (cio_tell(cio) - position) == header.Msg_length) { + jpt_read_msg_header(cinfo, cio, &header); + position = cio_tell(cio); + if (header.Class_Id != 4) { /* 4 : Tile data-bin message */ + opj_image_destroy(image); + opj_event_msg(cinfo, EVT_ERROR, "[JPT-stream] : Expecting Tile info !\n"); + return 0; + } + } + + id = cio_read(cio, 2); + if (id >> 8 != 0xff) { + opj_image_destroy(image); + opj_event_msg(cinfo, EVT_ERROR, "%.8x: expected a marker instead of %x\n", cio_tell(cio) - 2, id); + return 0; + } + e = j2k_dec_mstab_lookup(id); + if (!(j2k->state & e->states)) { + opj_image_destroy(image); + opj_event_msg(cinfo, EVT_ERROR, "%.8x: unexpected marker %x\n", cio_tell(cio) - 2, id); + return 0; + } + if (e->handler) { + (*e->handler)(j2k); + } + if (j2k->state == J2K_STATE_MT) { + break; + } + if (j2k->state == J2K_STATE_NEOC) { + break; + } + } + if (j2k->state == J2K_STATE_NEOC) { + j2k_read_eoc(j2k); + } + + if (j2k->state != J2K_STATE_MT) { + opj_event_msg(cinfo, EVT_WARNING, "Incomplete bitstream\n"); + } + + return image; +} + +/* ----------------------------------------------------------------------- */ +/* J2K encoder interface */ +/* ----------------------------------------------------------------------- */ + +opj_j2k_t* j2k_create_compress(opj_common_ptr cinfo) { + opj_j2k_t *j2k = (opj_j2k_t*) opj_calloc(1, sizeof(opj_j2k_t)); + if(j2k) { + j2k->cinfo = cinfo; + } + return j2k; +} + +void j2k_destroy_compress(opj_j2k_t *j2k) { + int tileno; + + if(!j2k) return; + if(j2k->cp != NULL) { + opj_cp_t *cp = j2k->cp; + + if(cp->comment) { + opj_free(cp->comment); + } + if(cp->matrice) { + opj_free(cp->matrice); + } + for (tileno = 0; tileno < cp->tw * cp->th; tileno++) { + opj_free(cp->tcps[tileno].tccps); + } + opj_free(cp->tcps); + opj_free(cp); + } + + opj_free(j2k); +} + +void j2k_setup_encoder(opj_j2k_t *j2k, opj_cparameters_t *parameters, opj_image_t *image) { + int i, j, tileno, numpocs_tile; + opj_cp_t *cp = NULL; + + if(!j2k || !parameters || ! image) { + return; + } + + /* create and initialize the coding parameters structure */ + cp = (opj_cp_t*) opj_calloc(1, sizeof(opj_cp_t)); + + /* keep a link to cp so that we can destroy it later in j2k_destroy_compress */ + j2k->cp = cp; + + /* set default values for cp */ + cp->tw = 1; + cp->th = 1; + + /* + copy user encoding parameters + */ + cp->cinema = parameters->cp_cinema; + cp->max_comp_size = parameters->max_comp_size; + cp->rsiz = parameters->cp_rsiz; + cp->disto_alloc = parameters->cp_disto_alloc; + cp->fixed_alloc = parameters->cp_fixed_alloc; + cp->fixed_quality = parameters->cp_fixed_quality; + + /* mod fixed_quality */ + if(parameters->cp_matrice) { + size_t array_size = parameters->tcp_numlayers * parameters->numresolution * 3 * sizeof(int); + cp->matrice = (int *) opj_malloc(array_size); + memcpy(cp->matrice, parameters->cp_matrice, array_size); + } + + /* tiles */ + cp->tdx = parameters->cp_tdx; + cp->tdy = parameters->cp_tdy; + + /* tile offset */ + cp->tx0 = parameters->cp_tx0; + cp->ty0 = parameters->cp_ty0; + + /* comment string */ + if(parameters->cp_comment) { + cp->comment = (char*)opj_malloc(strlen(parameters->cp_comment) + 1); + if(cp->comment) { + strcpy(cp->comment, parameters->cp_comment); + } + } + + /* + calculate other encoding parameters + */ + + if (parameters->tile_size_on) { + cp->tw = int_ceildiv(image->x1 - cp->tx0, cp->tdx); + cp->th = int_ceildiv(image->y1 - cp->ty0, cp->tdy); + } else { + cp->tdx = image->x1 - cp->tx0; + cp->tdy = image->y1 - cp->ty0; + } + + if(parameters->tp_on){ + cp->tp_flag = parameters->tp_flag; + cp->tp_on = 1; + } + + cp->img_size = 0; + for(i=0;inumcomps ;i++){ + cp->img_size += (image->comps[i].w *image->comps[i].h * image->comps[i].prec); + } + + +#ifdef USE_JPWL + /* + calculate JPWL encoding parameters + */ + + if (parameters->jpwl_epc_on) { + int i; + + /* set JPWL on */ + cp->epc_on = true; + cp->info_on = false; /* no informative technique */ + + /* set EPB on */ + if ((parameters->jpwl_hprot_MH > 0) || (parameters->jpwl_hprot_TPH[0] > 0)) { + cp->epb_on = true; + + cp->hprot_MH = parameters->jpwl_hprot_MH; + for (i = 0; i < JPWL_MAX_NO_TILESPECS; i++) { + cp->hprot_TPH_tileno[i] = parameters->jpwl_hprot_TPH_tileno[i]; + cp->hprot_TPH[i] = parameters->jpwl_hprot_TPH[i]; + } + /* if tile specs are not specified, copy MH specs */ + if (cp->hprot_TPH[0] == -1) { + cp->hprot_TPH_tileno[0] = 0; + cp->hprot_TPH[0] = parameters->jpwl_hprot_MH; + } + for (i = 0; i < JPWL_MAX_NO_PACKSPECS; i++) { + cp->pprot_tileno[i] = parameters->jpwl_pprot_tileno[i]; + cp->pprot_packno[i] = parameters->jpwl_pprot_packno[i]; + cp->pprot[i] = parameters->jpwl_pprot[i]; + } + } + + /* set ESD writing */ + if ((parameters->jpwl_sens_size == 1) || (parameters->jpwl_sens_size == 2)) { + cp->esd_on = true; + + cp->sens_size = parameters->jpwl_sens_size; + cp->sens_addr = parameters->jpwl_sens_addr; + cp->sens_range = parameters->jpwl_sens_range; + + cp->sens_MH = parameters->jpwl_sens_MH; + for (i = 0; i < JPWL_MAX_NO_TILESPECS; i++) { + cp->sens_TPH_tileno[i] = parameters->jpwl_sens_TPH_tileno[i]; + cp->sens_TPH[i] = parameters->jpwl_sens_TPH[i]; + } + } + + /* always set RED writing to false: we are at the encoder */ + cp->red_on = false; + + } else { + cp->epc_on = false; + } +#endif /* USE_JPWL */ + + + /* initialize the mutiple tiles */ + /* ---------------------------- */ + cp->tcps = (opj_tcp_t*) opj_calloc(cp->tw * cp->th, sizeof(opj_tcp_t)); + + for (tileno = 0; tileno < cp->tw * cp->th; tileno++) { + opj_tcp_t *tcp = &cp->tcps[tileno]; + tcp->numlayers = parameters->tcp_numlayers; + for (j = 0; j < tcp->numlayers; j++) { + if(cp->cinema){ + if (cp->fixed_quality) { + tcp->distoratio[j] = parameters->tcp_distoratio[j]; + } + tcp->rates[j] = parameters->tcp_rates[j]; + }else{ + if (cp->fixed_quality) { /* add fixed_quality */ + tcp->distoratio[j] = parameters->tcp_distoratio[j]; + } else { + tcp->rates[j] = parameters->tcp_rates[j]; + } + } + } + tcp->csty = parameters->csty; + tcp->prg = parameters->prog_order; + tcp->mct = parameters->tcp_mct; + + numpocs_tile = 0; + tcp->POC = 0; + if (parameters->numpocs) { + /* initialisation of POC */ + tcp->POC = 1; + for (i = 0; i < parameters->numpocs; i++) { + if((tileno == parameters->POC[i].tile - 1) || (parameters->POC[i].tile == -1)) { + opj_poc_t *tcp_poc = &tcp->pocs[numpocs_tile]; + tcp_poc->resno0 = parameters->POC[numpocs_tile].resno0; + tcp_poc->compno0 = parameters->POC[numpocs_tile].compno0; + tcp_poc->layno1 = parameters->POC[numpocs_tile].layno1; + tcp_poc->resno1 = parameters->POC[numpocs_tile].resno1; + tcp_poc->compno1 = parameters->POC[numpocs_tile].compno1; + tcp_poc->prg1 = parameters->POC[numpocs_tile].prg1; + tcp_poc->tile = parameters->POC[numpocs_tile].tile; + numpocs_tile++; + } + } + tcp->numpocs = numpocs_tile -1 ; + }else{ + tcp->numpocs = 0; + } + + tcp->tccps = (opj_tccp_t*) opj_calloc(image->numcomps, sizeof(opj_tccp_t)); + + for (i = 0; i < image->numcomps; i++) { + opj_tccp_t *tccp = &tcp->tccps[i]; + tccp->csty = parameters->csty & 0x01; /* 0 => one precinct || 1 => custom precinct */ + tccp->numresolutions = parameters->numresolution; + tccp->cblkw = int_floorlog2(parameters->cblockw_init); + tccp->cblkh = int_floorlog2(parameters->cblockh_init); + tccp->cblksty = parameters->mode; + tccp->qmfbid = parameters->irreversible ? 0 : 1; + tccp->qntsty = parameters->irreversible ? J2K_CCP_QNTSTY_SEQNT : J2K_CCP_QNTSTY_NOQNT; + tccp->numgbits = 2; + if (i == parameters->roi_compno) { + tccp->roishift = parameters->roi_shift; + } else { + tccp->roishift = 0; + } + + if(parameters->cp_cinema) + { + //Precinct size for lowest frequency subband=128 + tccp->prcw[0] = 7; + tccp->prch[0] = 7; + //Precinct size at all other resolutions = 256 + for (j = 1; j < tccp->numresolutions; j++) { + tccp->prcw[j] = 8; + tccp->prch[j] = 8; + } + }else{ + if (parameters->csty & J2K_CCP_CSTY_PRT) { + int p = 0; + for (j = tccp->numresolutions - 1; j >= 0; j--) { + if (p < parameters->res_spec) { + + if (parameters->prcw_init[p] < 1) { + tccp->prcw[j] = 1; + } else { + tccp->prcw[j] = int_floorlog2(parameters->prcw_init[p]); + } + + if (parameters->prch_init[p] < 1) { + tccp->prch[j] = 1; + }else { + tccp->prch[j] = int_floorlog2(parameters->prch_init[p]); + } + + } else { + int res_spec = parameters->res_spec; + int size_prcw = parameters->prcw_init[res_spec - 1] >> (p - (res_spec - 1)); + int size_prch = parameters->prch_init[res_spec - 1] >> (p - (res_spec - 1)); + + if (size_prcw < 1) { + tccp->prcw[j] = 1; + } else { + tccp->prcw[j] = int_floorlog2(size_prcw); + } + + if (size_prch < 1) { + tccp->prch[j] = 1; + } else { + tccp->prch[j] = int_floorlog2(size_prch); + } + } + p++; + /*printf("\nsize precinct for level %d : %d,%d\n", j,tccp->prcw[j], tccp->prch[j]); */ + } //end for + } else { + for (j = 0; j < tccp->numresolutions; j++) { + tccp->prcw[j] = 15; + tccp->prch[j] = 15; + } + } + } + + dwt_calc_explicit_stepsizes(tccp, image->comps[i].prec); + } + } +} + +bool j2k_encode(opj_j2k_t *j2k, opj_cio_t *cio, opj_image_t *image, opj_codestream_info_t *cstr_info) { + int tileno, compno; + opj_cp_t *cp = NULL; + + opj_tcd_t *tcd = NULL; /* TCD component */ + + j2k->cio = cio; + j2k->image = image; + + cp = j2k->cp; + + /* INDEX >> */ + j2k->cstr_info = cstr_info; + if (cstr_info) { + int compno; + cstr_info->tile = (opj_tile_info_t *) opj_malloc(cp->tw * cp->th * sizeof(opj_tile_info_t)); + cstr_info->image_w = image->x1 - image->x0; + cstr_info->image_h = image->y1 - image->y0; + cstr_info->prog = (&cp->tcps[0])->prg; + cstr_info->tw = cp->tw; + cstr_info->th = cp->th; + cstr_info->tile_x = cp->tdx; /* new version parser */ + cstr_info->tile_y = cp->tdy; /* new version parser */ + cstr_info->tile_Ox = cp->tx0; /* new version parser */ + cstr_info->tile_Oy = cp->ty0; /* new version parser */ + cstr_info->numcomps = image->numcomps; + cstr_info->numlayers = (&cp->tcps[0])->numlayers; + cstr_info->numdecompos = (int*) opj_malloc(image->numcomps * sizeof(int)); + for (compno=0; compno < image->numcomps; compno++) { + cstr_info->numdecompos[compno] = (&cp->tcps[0])->tccps->numresolutions - 1; + } + cstr_info->D_max = 0.0; /* ADD Marcela */ + cstr_info->main_head_start = cio_tell(cio); /* position of SOC */ + cstr_info->maxmarknum = 100; + cstr_info->marker = (opj_marker_info_t *) opj_malloc(cstr_info->maxmarknum * sizeof(opj_marker_info_t)); + cstr_info->marknum = 0; + } + /* << INDEX */ + + j2k_write_soc(j2k); + j2k_write_siz(j2k); + j2k_write_cod(j2k); + j2k_write_qcd(j2k); + + if(cp->cinema){ + for (compno = 1; compno < image->numcomps; compno++) { + j2k_write_coc(j2k, compno); + j2k_write_qcc(j2k, compno); + } + } + + for (compno = 0; compno < image->numcomps; compno++) { + opj_tcp_t *tcp = &cp->tcps[0]; + if (tcp->tccps[compno].roishift) + j2k_write_rgn(j2k, compno, 0); + } + if (cp->comment != NULL) { + j2k_write_com(j2k); + } + + j2k->totnum_tp = j2k_calculate_tp(cp,image->numcomps,image,j2k); + /* TLM Marker*/ + if(cp->cinema){ + j2k_write_tlm(j2k); + if (cp->cinema == CINEMA4K_24) { + j2k_write_poc(j2k); + } + } + + /* uncomment only for testing JPSEC marker writing */ + /* j2k_write_sec(j2k); */ + + /* INDEX >> */ + if(cstr_info) { + cstr_info->main_head_end = cio_tell(cio) - 1; + } + /* << INDEX */ + /**** Main Header ENDS here ***/ + + /* create the tile encoder */ + tcd = tcd_create(j2k->cinfo); + + /* encode each tile */ + for (tileno = 0; tileno < cp->tw * cp->th; tileno++) { + int pino; + int tilepartno=0; + /* UniPG>> */ + int acc_pack_num = 0; + /* <tcps[tileno]; + opj_event_msg(j2k->cinfo, EVT_INFO, "tile number %d / %d\n", tileno + 1, cp->tw * cp->th); + + j2k->curtileno = tileno; + j2k->cur_tp_num = 0; + tcd->cur_totnum_tp = j2k->cur_totnum_tp[j2k->curtileno]; + /* initialisation before tile encoding */ + if (tileno == 0) { + tcd_malloc_encode(tcd, image, cp, j2k->curtileno); + } else { + tcd_init_encode(tcd, image, cp, j2k->curtileno); + } + + /* INDEX >> */ + if(cstr_info) { + cstr_info->tile[j2k->curtileno].start_pos = cio_tell(cio) + j2k->pos_correction; + } + /* << INDEX */ + + for(pino = 0; pino <= tcp->numpocs; pino++) { + int tot_num_tp; + tcd->cur_pino=pino; + + /*Get number of tile parts*/ + tot_num_tp = j2k_get_num_tp(cp,pino,tileno); + tcd->tp_pos = cp->tp_pos; + + for(tilepartno = 0; tilepartno < tot_num_tp ; tilepartno++){ + j2k->tp_num = tilepartno; + /* INDEX >> */ + if(cstr_info) + cstr_info->tile[j2k->curtileno].tp[j2k->cur_tp_num].tp_start_pos = + cio_tell(cio) + j2k->pos_correction; + /* << INDEX */ + j2k_write_sot(j2k); + + if(j2k->cur_tp_num == 0 && cp->cinema == 0){ + for (compno = 1; compno < image->numcomps; compno++) { + j2k_write_coc(j2k, compno); + j2k_write_qcc(j2k, compno); + } + if (cp->tcps[tileno].numpocs) { + j2k_write_poc(j2k); + } + } + + /* INDEX >> */ + if(cstr_info) + cstr_info->tile[j2k->curtileno].tp[j2k->cur_tp_num].tp_end_header = + cio_tell(cio) + j2k->pos_correction + 1; + /* << INDEX */ + + j2k_write_sod(j2k, tcd); + + /* INDEX >> */ + if(cstr_info) { + cstr_info->tile[j2k->curtileno].tp[j2k->cur_tp_num].tp_end_pos = + cio_tell(cio) + j2k->pos_correction - 1; + cstr_info->tile[j2k->curtileno].tp[j2k->cur_tp_num].tp_start_pack = + acc_pack_num; + cstr_info->tile[j2k->curtileno].tp[j2k->cur_tp_num].tp_numpacks = + cstr_info->packno - acc_pack_num; + acc_pack_num = cstr_info->packno; + } + /* << INDEX */ + + j2k->cur_tp_num++; + } + } + if(cstr_info) { + cstr_info->tile[j2k->curtileno].end_pos = cio_tell(cio) + j2k->pos_correction - 1; + } + + + /* + if (tile->PPT) { // BAD PPT !!! + FILE *PPT_file; + int i; + PPT_file=fopen("PPT","rb"); + fprintf(stderr,"%c%c%c%c",255,97,tile->len_ppt/256,tile->len_ppt%256); + for (i=0;ilen_ppt;i++) { + unsigned char elmt; + fread(&elmt, 1, 1, PPT_file); + fwrite(&elmt,1,1,f); + } + fclose(PPT_file); + unlink("PPT"); + } + */ + + } + + /* destroy the tile encoder */ + tcd_free_encode(tcd); + tcd_destroy(tcd); + + opj_free(j2k->cur_totnum_tp); + + j2k_write_eoc(j2k); + + if(cstr_info) { + cstr_info->codestream_size = cio_tell(cio) + j2k->pos_correction; + /* UniPG>> */ + /* The following adjustment is done to adjust the codestream size */ + /* if SOD is not at 0 in the buffer. Useful in case of JP2, where */ + /* the first bunch of bytes is not in the codestream */ + cstr_info->codestream_size -= cstr_info->main_head_start; + /* <epc_on) { + + /* encode according to JPWL */ + jpwl_encode(j2k, cio, image); + + } +#endif /* USE_JPWL */ + + return true; +} + + + + + + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/j2k.h b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/j2k.h new file mode 100644 index 0000000..8fc8e6d --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/j2k.h @@ -0,0 +1,446 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2006-2007, Parvatha Elangovan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __J2K_H +#define __J2K_H +/** +@file j2k.h +@brief The JPEG-2000 Codestream Reader/Writer (J2K) + +The functions in J2K.C have for goal to read/write the several parts of the codestream: markers and data. +*/ + +/** @defgroup J2K J2K - JPEG-2000 codestream reader/writer */ +/*@{*/ + +#define J2K_CP_CSTY_PRT 0x01 +#define J2K_CP_CSTY_SOP 0x02 +#define J2K_CP_CSTY_EPH 0x04 +#define J2K_CCP_CSTY_PRT 0x01 +#define J2K_CCP_CBLKSTY_LAZY 0x01 /**< Selective arithmetic coding bypass */ +#define J2K_CCP_CBLKSTY_RESET 0x02 /**< Reset context probabilities on coding pass boundaries */ +#define J2K_CCP_CBLKSTY_TERMALL 0x04 /**< Termination on each coding pass */ +#define J2K_CCP_CBLKSTY_VSC 0x08 /**< Vertically stripe causal context */ +#define J2K_CCP_CBLKSTY_PTERM 0x10 /**< Predictable termination */ +#define J2K_CCP_CBLKSTY_SEGSYM 0x20 /**< Segmentation symbols are used */ +#define J2K_CCP_QNTSTY_NOQNT 0 +#define J2K_CCP_QNTSTY_SIQNT 1 +#define J2K_CCP_QNTSTY_SEQNT 2 + +/* ----------------------------------------------------------------------- */ + +#define J2K_MS_SOC 0xff4f /**< SOC marker value */ +#define J2K_MS_SOT 0xff90 /**< SOT marker value */ +#define J2K_MS_SOD 0xff93 /**< SOD marker value */ +#define J2K_MS_EOC 0xffd9 /**< EOC marker value */ +#define J2K_MS_SIZ 0xff51 /**< SIZ marker value */ +#define J2K_MS_COD 0xff52 /**< COD marker value */ +#define J2K_MS_COC 0xff53 /**< COC marker value */ +#define J2K_MS_RGN 0xff5e /**< RGN marker value */ +#define J2K_MS_QCD 0xff5c /**< QCD marker value */ +#define J2K_MS_QCC 0xff5d /**< QCC marker value */ +#define J2K_MS_POC 0xff5f /**< POC marker value */ +#define J2K_MS_TLM 0xff55 /**< TLM marker value */ +#define J2K_MS_PLM 0xff57 /**< PLM marker value */ +#define J2K_MS_PLT 0xff58 /**< PLT marker value */ +#define J2K_MS_PPM 0xff60 /**< PPM marker value */ +#define J2K_MS_PPT 0xff61 /**< PPT marker value */ +#define J2K_MS_SOP 0xff91 /**< SOP marker value */ +#define J2K_MS_EPH 0xff92 /**< EPH marker value */ +#define J2K_MS_CRG 0xff63 /**< CRG marker value */ +#define J2K_MS_COM 0xff64 /**< COM marker value */ +/* UniPG>> */ +#ifdef USE_JPWL +#define J2K_MS_EPC 0xff68 /**< EPC marker value (Part 11: JPEG 2000 for Wireless) */ +#define J2K_MS_EPB 0xff66 /**< EPB marker value (Part 11: JPEG 2000 for Wireless) */ +#define J2K_MS_ESD 0xff67 /**< ESD marker value (Part 11: JPEG 2000 for Wireless) */ +#define J2K_MS_RED 0xff69 /**< RED marker value (Part 11: JPEG 2000 for Wireless) */ +#endif /* USE_JPWL */ +#ifdef USE_JPSEC +#define J2K_MS_SEC 0xff65 /**< SEC marker value (Part 8: Secure JPEG 2000) */ +#define J2K_MS_INSEC 0xff94 /**< INSEC marker value (Part 8: Secure JPEG 2000) */ +#endif /* USE_JPSEC */ +/* < there was a PPT marker for the present tile */ + int ppt; + /** used in case of multiple marker PPT (number of info already stored) */ + int ppt_store; + /** ppmbug1 */ + int ppt_len; + /** add fixed_quality */ + float distoratio[100]; + /** tile-component coding parameters */ + opj_tccp_t *tccps; +} opj_tcp_t; + +/** +Coding parameters +*/ +typedef struct opj_cp { + /** Digital cinema profile*/ + OPJ_CINEMA_MODE cinema; + /** Maximum rate for each component. If == 0, component size limitation is not considered */ + int max_comp_size; + /** Size of the image in bits*/ + int img_size; + /** Rsiz*/ + OPJ_RSIZ_CAPABILITIES rsiz; + /** Enabling Tile part generation*/ + char tp_on; + /** Flag determining tile part generation*/ + char tp_flag; + /** Position of tile part flag in progression order*/ + int tp_pos; + /** allocation by rate/distortion */ + int disto_alloc; + /** allocation by fixed layer */ + int fixed_alloc; + /** add fixed_quality */ + int fixed_quality; + /** if != 0, then original dimension divided by 2^(reduce); if == 0 or not used, image is decoded to the full resolution */ + int reduce; + /** if != 0, then only the first "layer" layers are decoded; if == 0 or not used, all the quality layers are decoded */ + int layer; + /** if == NO_LIMITATION, decode entire codestream; if == LIMIT_TO_MAIN_HEADER then only decode the main header */ + OPJ_LIMIT_DECODING limit_decoding; + /** XTOsiz */ + int tx0; + /** YTOsiz */ + int ty0; + /** XTsiz */ + int tdx; + /** YTsiz */ + int tdy; + /** comment for coding */ + char *comment; + /** number of tiles in width */ + int tw; + /** number of tiles in heigth */ + int th; + /** ID number of the tiles present in the codestream */ + int *tileno; + /** size of the vector tileno */ + int tileno_size; + /** packet header store there for futur use in t2_decode_packet */ + unsigned char *ppm_data; + /** pointer remaining on the first byte of the first header if ppm is used */ + unsigned char *ppm_data_first; + /** if ppm == 1 --> there was a PPM marker for the present tile */ + int ppm; + /** use in case of multiple marker PPM (number of info already store) */ + int ppm_store; + /** use in case of multiple marker PPM (case on non-finished previous info) */ + int ppm_previous; + /** ppmbug1 */ + int ppm_len; + /** tile coding parameters */ + opj_tcp_t *tcps; + /** fixed layer */ + int *matrice; +/* UniPG>> */ +#ifdef USE_JPWL + /** enables writing of EPC in MH, thus activating JPWL */ + bool epc_on; + /** enables writing of EPB, in case of activated JPWL */ + bool epb_on; + /** enables writing of ESD, in case of activated JPWL */ + bool esd_on; + /** enables writing of informative techniques of ESD, in case of activated JPWL */ + bool info_on; + /** enables writing of RED, in case of activated JPWL */ + bool red_on; + /** error protection method for MH (0,1,16,32,37-128) */ + int hprot_MH; + /** tile number of header protection specification (>=0) */ + int hprot_TPH_tileno[JPWL_MAX_NO_TILESPECS]; + /** error protection methods for TPHs (0,1,16,32,37-128) */ + int hprot_TPH[JPWL_MAX_NO_TILESPECS]; + /** tile number of packet protection specification (>=0) */ + int pprot_tileno[JPWL_MAX_NO_PACKSPECS]; + /** packet number of packet protection specification (>=0) */ + int pprot_packno[JPWL_MAX_NO_PACKSPECS]; + /** error protection methods for packets (0,1,16,32,37-128) */ + int pprot[JPWL_MAX_NO_PACKSPECS]; + /** enables writing of ESD, (0/2/4 bytes) */ + int sens_size; + /** sensitivity addressing size (0=auto/2/4 bytes) */ + int sens_addr; + /** sensitivity range (0-3) */ + int sens_range; + /** sensitivity method for MH (-1,0-7) */ + int sens_MH; + /** tile number of sensitivity specification (>=0) */ + int sens_TPH_tileno[JPWL_MAX_NO_TILESPECS]; + /** sensitivity methods for TPHs (-1,0-7) */ + int sens_TPH[JPWL_MAX_NO_TILESPECS]; + /** enables JPWL correction at the decoder */ + bool correct; + /** expected number of components at the decoder */ + int exp_comps; + /** maximum number of tiles at the decoder */ + int max_tiles; +#endif /* USE_JPWL */ +/* <cp. +@param j2k J2K decompressor handle +@param parameters decompression parameters +*/ +void j2k_setup_decoder(opj_j2k_t *j2k, opj_dparameters_t *parameters); +/** +Decode an image from a JPEG-2000 codestream +@param j2k J2K decompressor handle +@param cio Input buffer stream +@param cstr_info Codestream information structure if required, NULL otherwise +@return Returns a decoded image if successful, returns NULL otherwise +*/ +opj_image_t* j2k_decode(opj_j2k_t *j2k, opj_cio_t *cio, opj_codestream_info_t *cstr_info); +/** +Decode an image form a JPT-stream (JPEG 2000, JPIP) +@param j2k J2K decompressor handle +@param cio Input buffer stream +@param cstr_info Codestream information structure if required, NULL otherwise +@return Returns a decoded image if successful, returns NULL otherwise +*/ +opj_image_t* j2k_decode_jpt_stream(opj_j2k_t *j2k, opj_cio_t *cio, opj_codestream_info_t *cstr_info); +/** +Creates a J2K compression structure +@param cinfo Codec context info +@return Returns a handle to a J2K compressor if successful, returns NULL otherwise +*/ +opj_j2k_t* j2k_create_compress(opj_common_ptr cinfo); +/** +Destroy a J2K compressor handle +@param j2k J2K compressor handle to destroy +*/ +void j2k_destroy_compress(opj_j2k_t *j2k); +/** +Setup the encoder parameters using the current image and using user parameters. +Coding parameters are returned in j2k->cp. +@param j2k J2K compressor handle +@param parameters compression parameters +@param image input filled image +*/ +void j2k_setup_encoder(opj_j2k_t *j2k, opj_cparameters_t *parameters, opj_image_t *image); +/** +Converts an enum type progression order to string type +*/ +char *j2k_convert_progression_order(OPJ_PROG_ORDER prg_order); +/** +Encode an image into a JPEG-2000 codestream +@param j2k J2K compressor handle +@param cio Output buffer stream +@param image Image to encode +@param cstr_info Codestream information structure if required, NULL otherwise +@return Returns true if successful, returns false otherwise +*/ +bool j2k_encode(opj_j2k_t *j2k, opj_cio_t *cio, opj_image_t *image, opj_codestream_info_t *cstr_info); + +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __J2K_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/j2k_lib.c b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/j2k_lib.c new file mode 100644 index 0000000..d815f16 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/j2k_lib.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef _WIN32 +#include +#else +#include +#include +#include +#endif /* _WIN32 */ +#include "opj_includes.h" + +double opj_clock(void) { +#ifdef _WIN32 + /* _WIN32: use QueryPerformance (very accurate) */ + LARGE_INTEGER freq , t ; + /* freq is the clock speed of the CPU */ + QueryPerformanceFrequency(&freq) ; + /* cout << "freq = " << ((double) freq.QuadPart) << endl; */ + /* t is the high resolution performance counter (see MSDN) */ + QueryPerformanceCounter ( & t ) ; + return ( t.QuadPart /(double) freq.QuadPart ) ; +#else + /* Unix or Linux: use resource usage */ + struct rusage t; + double procTime; + /* (1) Get the rusage data structure at this moment (man getrusage) */ + getrusage(0,&t); + /* (2) What is the elapsed time ? - CPU time = User time + System time */ + /* (2a) Get the seconds */ + procTime = t.ru_utime.tv_sec + t.ru_stime.tv_sec; + /* (2b) More precisely! Get the microseconds part ! */ + return ( procTime + (t.ru_utime.tv_usec + t.ru_stime.tv_usec) * 1e-6 ) ; +#endif +} + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/j2k_lib.h b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/j2k_lib.h new file mode 100644 index 0000000..7df4d36 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/j2k_lib.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __J2K_LIB_H +#define __J2K_LIB_H +/** +@file j2k_lib.h +@brief Internal functions + +The functions in J2K_LIB.C are internal utilities mainly used for timing. +*/ + +/** @defgroup MISC MISC - Miscellaneous internal functions */ +/*@{*/ + +/** @name Exported functions */ +/*@{*/ +/* ----------------------------------------------------------------------- */ + +/** +Difference in successive opj_clock() calls tells you the elapsed time +@return Returns time in seconds +*/ +double opj_clock(void); + +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __J2K_LIB_H */ + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/jp2.c b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/jp2.c new file mode 100644 index 0000000..20cf2e6 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/jp2.c @@ -0,0 +1,1089 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "opj_includes.h" + +/** @defgroup JP2 JP2 - JPEG-2000 file format reader/writer */ +/*@{*/ + +/** @name Local static functions */ +/*@{*/ + +/** +Read box headers +@param cinfo Codec context info +@param cio Input stream +@param box +@return Returns true if successful, returns false otherwise +*/ +static bool jp2_read_boxhdr(opj_common_ptr cinfo, opj_cio_t *cio, opj_jp2_box_t *box); +/*static void jp2_write_url(opj_cio_t *cio, char *Idx_file);*/ +/** +Read the IHDR box - Image Header box +@param jp2 JP2 handle +@param cio Input buffer stream +@return Returns true if successful, returns false otherwise +*/ +static bool jp2_read_ihdr(opj_jp2_t *jp2, opj_cio_t *cio); +static void jp2_write_ihdr(opj_jp2_t *jp2, opj_cio_t *cio); +static void jp2_write_bpcc(opj_jp2_t *jp2, opj_cio_t *cio); +static bool jp2_read_bpcc(opj_jp2_t *jp2, opj_cio_t *cio); +static void jp2_write_colr(opj_jp2_t *jp2, opj_cio_t *cio); +/** +Write the FTYP box - File type box +@param jp2 JP2 handle +@param cio Output buffer stream +*/ +static void jp2_write_ftyp(opj_jp2_t *jp2, opj_cio_t *cio); +/** +Read the FTYP box - File type box +@param jp2 JP2 handle +@param cio Input buffer stream +@return Returns true if successful, returns false otherwise +*/ +static bool jp2_read_ftyp(opj_jp2_t *jp2, opj_cio_t *cio); +static int jp2_write_jp2c(opj_jp2_t *jp2, opj_cio_t *cio, opj_image_t *image, opj_codestream_info_t *cstr_info); +static bool jp2_read_jp2c(opj_jp2_t *jp2, opj_cio_t *cio, unsigned int *j2k_codestream_length, unsigned int *j2k_codestream_offset); +static void jp2_write_jp(opj_cio_t *cio); +/** +Read the JP box - JPEG 2000 signature +@param jp2 JP2 handle +@param cio Input buffer stream +@return Returns true if successful, returns false otherwise +*/ +static bool jp2_read_jp(opj_jp2_t *jp2, opj_cio_t *cio); +/** +Decode the structure of a JP2 file +@param jp2 JP2 handle +@param cio Input buffer stream +@param color Collector for profile, cdef and pclr data +@return Returns true if successful, returns false otherwise +*/ +static bool jp2_read_struct(opj_jp2_t *jp2, opj_cio_t *cio, + opj_jp2_color_t *color); +/** +Apply collected palette data +@param color Collector for profile, cdef and pclr data +@param image +*/ +static void jp2_apply_pclr(opj_jp2_color_t *color, opj_image_t *image); +/** +Collect palette data +@param jp2 JP2 handle +@param cio Input buffer stream +@param box +@param color Collector for profile, cdef and pclr data +@return Returns true if successful, returns false otherwise +*/ +static bool jp2_read_pclr(opj_jp2_t *jp2, opj_cio_t *cio, + opj_jp2_box_t *box, opj_jp2_color_t *color); +/** +Collect component mapping data +@param jp2 JP2 handle +@param cio Input buffer stream +@param box +@param color Collector for profile, cdef and pclr data +@return Returns true if successful, returns false otherwise +*/ +static bool jp2_read_cmap(opj_jp2_t *jp2, opj_cio_t *cio, + opj_jp2_box_t *box, opj_jp2_color_t *color); +/** +Collect colour specification data +@param jp2 JP2 handle +@param cio Input buffer stream +@param box +@param color Collector for profile, cdef and pclr data +@return Returns true if successful, returns false otherwise +*/ +static bool jp2_read_colr(opj_jp2_t *jp2, opj_cio_t *cio, + opj_jp2_box_t *box, opj_jp2_color_t *color); +/*@}*/ + +/*@}*/ + +/* ----------------------------------------------------------------------- */ + +static bool jp2_read_boxhdr(opj_common_ptr cinfo, opj_cio_t *cio, opj_jp2_box_t *box) { + box->init_pos = cio_tell(cio); + box->length = cio_read(cio, 4); + box->type = cio_read(cio, 4); + if (box->length == 1) { + if (cio_read(cio, 4) != 0) { + opj_event_msg(cinfo, EVT_ERROR, "Cannot handle box sizes higher than 2^32\n"); + return false; + } + box->length = cio_read(cio, 4); + if (box->length == 0) + box->length = cio_numbytesleft(cio) + 12; + } + else if (box->length == 0) { + box->length = cio_numbytesleft(cio) + 8; + } + + return true; +} + +#if 0 +static void jp2_write_url(opj_cio_t *cio, char *Idx_file) { + unsigned int i; + opj_jp2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio, 4); + cio_write(cio, JP2_URL, 4); /* DBTL */ + cio_write(cio, 0, 1); /* VERS */ + cio_write(cio, 0, 3); /* FLAG */ + + if(Idx_file) { + for (i = 0; i < strlen(Idx_file); i++) { + cio_write(cio, Idx_file[i], 1); + } + } + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} +#endif + +static bool jp2_read_ihdr(opj_jp2_t *jp2, opj_cio_t *cio) { + opj_jp2_box_t box; + + opj_common_ptr cinfo = jp2->cinfo; + + jp2_read_boxhdr(cinfo, cio, &box); + if (JP2_IHDR != box.type) { + opj_event_msg(cinfo, EVT_ERROR, "Expected IHDR Marker\n"); + return false; + } + + jp2->h = cio_read(cio, 4); /* HEIGHT */ + jp2->w = cio_read(cio, 4); /* WIDTH */ + jp2->numcomps = cio_read(cio, 2); /* NC */ + jp2->comps = (opj_jp2_comps_t*) opj_malloc(jp2->numcomps * sizeof(opj_jp2_comps_t)); + + jp2->bpc = cio_read(cio, 1); /* BPC */ + + jp2->C = cio_read(cio, 1); /* C */ + jp2->UnkC = cio_read(cio, 1); /* UnkC */ + jp2->IPR = cio_read(cio, 1); /* IPR */ + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cinfo, EVT_ERROR, "Error with IHDR Box\n"); + return false; + } + + return true; +} + +static void jp2_write_ihdr(opj_jp2_t *jp2, opj_cio_t *cio) { + opj_jp2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio, 4); + cio_write(cio, JP2_IHDR, 4); /* IHDR */ + + cio_write(cio, jp2->h, 4); /* HEIGHT */ + cio_write(cio, jp2->w, 4); /* WIDTH */ + cio_write(cio, jp2->numcomps, 2); /* NC */ + + cio_write(cio, jp2->bpc, 1); /* BPC */ + + cio_write(cio, jp2->C, 1); /* C : Always 7 */ + cio_write(cio, jp2->UnkC, 1); /* UnkC, colorspace unknown */ + cio_write(cio, jp2->IPR, 1); /* IPR, no intellectual property */ + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +static void jp2_write_bpcc(opj_jp2_t *jp2, opj_cio_t *cio) { + unsigned int i; + opj_jp2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio, 4); + cio_write(cio, JP2_BPCC, 4); /* BPCC */ + + for (i = 0; i < jp2->numcomps; i++) { + cio_write(cio, jp2->comps[i].bpcc, 1); + } + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + + +static bool jp2_read_bpcc(opj_jp2_t *jp2, opj_cio_t *cio) { + unsigned int i; + opj_jp2_box_t box; + + opj_common_ptr cinfo = jp2->cinfo; + + jp2_read_boxhdr(cinfo, cio, &box); + if (JP2_BPCC != box.type) { + opj_event_msg(cinfo, EVT_ERROR, "Expected BPCC Marker\n"); + return false; + } + + for (i = 0; i < jp2->numcomps; i++) { + jp2->comps[i].bpcc = cio_read(cio, 1); + } + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cinfo, EVT_ERROR, "Error with BPCC Box\n"); + return false; + } + + return true; +} + +static void jp2_write_colr(opj_jp2_t *jp2, opj_cio_t *cio) { + opj_jp2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio, 4); + cio_write(cio, JP2_COLR, 4); /* COLR */ + + cio_write(cio, jp2->meth, 1); /* METH */ + cio_write(cio, jp2->precedence, 1); /* PRECEDENCE */ + cio_write(cio, jp2->approx, 1); /* APPROX */ + + if (jp2->meth == 1) { + cio_write(cio, jp2->enumcs, 4); /* EnumCS */ + } else { + cio_write(cio, 0, 1); /* PROFILE (??) */ + } + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +static void jp2_free_pclr(opj_jp2_color_t *color) +{ + opj_free(color->jp2_pclr->channel_sign); + opj_free(color->jp2_pclr->channel_size); + opj_free(color->jp2_pclr->entries); + + if(color->jp2_pclr->cmap) opj_free(color->jp2_pclr->cmap); + + opj_free(color->jp2_pclr); color->jp2_pclr = NULL; +} + +static void free_color_data(opj_jp2_color_t *color) +{ + if(color->jp2_pclr) + { + jp2_free_pclr(color); + } + if(color->jp2_cdef) + { + if(color->jp2_cdef->info) opj_free(color->jp2_cdef->info); + opj_free(color->jp2_cdef); + } + if(color->icc_profile_buf) opj_free(color->icc_profile_buf); +} + +static void jp2_apply_pclr(opj_jp2_color_t *color, opj_image_t *image) +{ + opj_image_comp_t *old_comps, *new_comps; + unsigned char *channel_size, *channel_sign; + unsigned int *entries; + opj_jp2_cmap_comp_t *cmap; + int *src, *dst; + unsigned int j, max; + unsigned short i, nr_channels, cmp, pcol; + int k, top_k; + + channel_size = color->jp2_pclr->channel_size; + channel_sign = color->jp2_pclr->channel_sign; + entries = color->jp2_pclr->entries; + cmap = color->jp2_pclr->cmap; + nr_channels = color->jp2_pclr->nr_channels; + + old_comps = image->comps; + new_comps = (opj_image_comp_t*) + opj_malloc(nr_channels * sizeof(opj_image_comp_t)); + + for(i = 0; i < nr_channels; ++i) + { + pcol = cmap[i].pcol; cmp = cmap[i].cmp; + + new_comps[pcol] = old_comps[cmp]; + + if(cmap[i].mtyp == 0) /* Direct use */ + { + old_comps[cmp].data = NULL; continue; + } +/* Palette mapping: */ + new_comps[pcol].data = (int*) + opj_malloc(old_comps[cmp].w * old_comps[cmp].h * sizeof(int)); + new_comps[pcol].prec = channel_size[i]; + new_comps[pcol].sgnd = channel_sign[i]; + } + top_k = color->jp2_pclr->nr_entries - 1; + + for(i = 0; i < nr_channels; ++i) + { +/* Direct use: */ + if(cmap[i].mtyp == 0) continue; + +/* Palette mapping: */ + cmp = cmap[i].cmp; pcol = cmap[i].pcol; + src = old_comps[cmp].data; + dst = new_comps[pcol].data; + max = new_comps[pcol].w * new_comps[pcol].h; + + for(j = 0; j < max; ++j) + { +/* The index */ + if((k = src[j]) < 0) k = 0; else if(k > top_k) k = top_k; +/* The colour */ + dst[j] = entries[k * nr_channels + pcol]; + } + } + max = image->numcomps; + for(i = 0; i < max; ++i) + { + if(old_comps[i].data) opj_free(old_comps[i].data); + } + opj_free(old_comps); + image->comps = new_comps; + image->numcomps = nr_channels; + + jp2_free_pclr(color); + +}/* apply_pclr() */ + +static bool jp2_read_pclr(opj_jp2_t *jp2, opj_cio_t *cio, + opj_jp2_box_t *box, opj_jp2_color_t *color) +{ + opj_jp2_pclr_t *jp2_pclr; + unsigned char *channel_size, *channel_sign; + unsigned int *entries; + unsigned short nr_entries, nr_channels; + unsigned short i, j; + unsigned char uc; + +/* Part 1, I.5.3.4: 'There shall be at most one Palette box inside + * a JP2 Header box' : +*/ + if(color->jp2_pclr) return false; + + nr_entries = cio_read(cio, 2); /* NE */ + nr_channels = cio_read(cio, 1);/* NPC */ + + entries = (unsigned int*) + opj_malloc(nr_channels * nr_entries * sizeof(unsigned int)); + channel_size = (unsigned char*)opj_malloc(nr_channels); + channel_sign = (unsigned char*)opj_malloc(nr_channels); + + jp2_pclr = (opj_jp2_pclr_t*)opj_malloc(sizeof(opj_jp2_pclr_t)); + jp2_pclr->channel_sign = channel_sign; + jp2_pclr->channel_size = channel_size; + jp2_pclr->entries = entries; + jp2_pclr->nr_entries = nr_entries; + jp2_pclr->nr_channels = nr_channels; + jp2_pclr->cmap = NULL; + + color->jp2_pclr = jp2_pclr; + + for(i = 0; i < nr_channels; ++i) + { + uc = cio_read(cio, 1); /* Bi */ + channel_size[i] = (uc & 0x7f) + 1; + channel_sign[i] = (uc & 0x80)?1:0; + } + + for(j = 0; j < nr_entries; ++j) + { + for(i = 0; i < nr_channels; ++i) + { +/* Cji */ + *entries++ = cio_read(cio, channel_size[i]>>3); + } + } + + return true; +}/* jp2_read_pclr() */ + +static bool jp2_read_cmap(opj_jp2_t *jp2, opj_cio_t *cio, + opj_jp2_box_t *box, opj_jp2_color_t *color) +{ + opj_jp2_cmap_comp_t *cmap; + unsigned short i, nr_channels; + +/* Need nr_channels: */ + if(color->jp2_pclr == NULL) return false; + +/* Part 1, I.5.3.5: 'There shall be at most one Component Mapping box + * inside a JP2 Header box' : +*/ + if(color->jp2_pclr->cmap) return false; + + nr_channels = color->jp2_pclr->nr_channels; + cmap = (opj_jp2_cmap_comp_t*) + opj_malloc(nr_channels * sizeof(opj_jp2_cmap_comp_t)); + + for(i = 0; i < nr_channels; ++i) + { + cmap[i].cmp = cio_read(cio, 2); + cmap[i].mtyp = cio_read(cio, 1); + cmap[i].pcol = cio_read(cio, 1); + + } + color->jp2_pclr->cmap = cmap; + + return true; +}/* jp2_read_cmap() */ + +static void jp2_apply_cdef(opj_image_t *image, opj_jp2_color_t *color) +{ + opj_jp2_cdef_info_t *info; + int color_space; + unsigned short i, n, cn, typ, asoc, acn; + + color_space = image->color_space; + info = color->jp2_cdef->info; + n = color->jp2_cdef->n; + + for(i = 0; i < n; ++i) + { +/* WATCH: acn = asoc - 1 ! */ + if((asoc = info[i].asoc) == 0) continue; + + cn = info[i].cn; typ = info[i].typ; acn = asoc - 1; + + if(cn != acn) + { + opj_image_comp_t saved; + + memcpy(&saved, &image->comps[cn], sizeof(opj_image_comp_t)); + memcpy(&image->comps[cn], &image->comps[acn], sizeof(opj_image_comp_t)); + memcpy(&image->comps[acn], &saved, sizeof(opj_image_comp_t)); + + info[i].asoc = cn + 1; + info[acn].asoc = info[acn].cn + 1; + } + } + if(color->jp2_cdef->info) opj_free(color->jp2_cdef->info); + + opj_free(color->jp2_cdef); color->jp2_cdef = NULL; + +}/* jp2_apply_cdef() */ + +static bool jp2_read_cdef(opj_jp2_t *jp2, opj_cio_t *cio, + opj_jp2_box_t *box, opj_jp2_color_t *color) +{ + opj_jp2_cdef_info_t *info; + unsigned short i, n; + +/* Part 1, I.5.3.6: 'The shall be at most one Channel Definition box + * inside a JP2 Header box.' +*/ + if(color->jp2_cdef) return false; + + if((n = cio_read(cio, 2)) == 0) return false; /* szukw000: FIXME */ + + info = (opj_jp2_cdef_info_t*) + opj_malloc(n * sizeof(opj_jp2_cdef_info_t)); + + color->jp2_cdef = (opj_jp2_cdef_t*)opj_malloc(sizeof(opj_jp2_cdef_t)); + color->jp2_cdef->info = info; + color->jp2_cdef->n = n; + + for(i = 0; i < n; ++i) + { + info[i].cn = cio_read(cio, 2); + info[i].typ = cio_read(cio, 2); + info[i].asoc = cio_read(cio, 2); + + } + return true; +}/* jp2_read_cdef() */ + +static bool jp2_read_colr(opj_jp2_t *jp2, opj_cio_t *cio, + opj_jp2_box_t *box, opj_jp2_color_t *color) +{ + int skip_len; + opj_common_ptr cinfo; + +/* Part 1, I.5.3.3 : 'A conforming JP2 reader shall ignore all Colour + * Specification boxes after the first.' +*/ + if(color->jp2_has_colr) return false; + + cinfo = jp2->cinfo; + + jp2->meth = cio_read(cio, 1); /* METH */ + jp2->precedence = cio_read(cio, 1); /* PRECEDENCE */ + jp2->approx = cio_read(cio, 1); /* APPROX */ + + if (jp2->meth == 1) + { + jp2->enumcs = cio_read(cio, 4); /* EnumCS */ + } + else + { +/* skip PROFILE */ + skip_len = box->init_pos + box->length - cio_tell(cio); + if (skip_len < 0) + { + opj_event_msg(cinfo, EVT_ERROR, "Error with COLR box size\n"); + return false; + } + if(skip_len > 0) + { + unsigned char *start; + + start = cio_getbp(cio); + color->icc_profile_buf = (unsigned char*)opj_malloc(skip_len); + color->icc_profile_len = skip_len; + + cio_skip(cio, box->init_pos + box->length - cio_tell(cio)); + + memcpy(color->icc_profile_buf, start, skip_len); + } + } + + if (cio_tell(cio) - box->init_pos != box->length) + { + opj_event_msg(cinfo, EVT_ERROR, "Error with COLR Box\n"); + return false; + } + color->jp2_has_colr = 1; + + return true; +}/* jp2_read_colr() */ + +bool jp2_read_jp2h(opj_jp2_t *jp2, opj_cio_t *cio, opj_jp2_color_t *color) +{ + opj_jp2_box_t box; + unsigned int jp2h_end; + + opj_common_ptr cinfo = jp2->cinfo; + + jp2_read_boxhdr(cinfo, cio, &box); + do + { + if (JP2_JP2H != box.type) + { + if (box.type == JP2_JP2C) + { + opj_event_msg(cinfo, EVT_ERROR, "Expected JP2H Marker\n"); + return false; + } + cio_skip(cio, box.length - 8); + + if(cio->bp >= cio->end) return false; + + jp2_read_boxhdr(cinfo, cio, &box); + } + } while(JP2_JP2H != box.type); + + if (!jp2_read_ihdr(jp2, cio)) + return false; + jp2h_end = box.init_pos + box.length; + + if (jp2->bpc == 255) + { + if (!jp2_read_bpcc(jp2, cio)) + return false; + } + jp2_read_boxhdr(cinfo, cio, &box); + + while(cio_tell(cio) < jp2h_end) + { + if(box.type == JP2_COLR) + { + if( !jp2_read_colr(jp2, cio, &box, color)) + { + cio_seek(cio, box.init_pos + 8); + cio_skip(cio, box.length - 8); + } + jp2_read_boxhdr(cinfo, cio, &box); + continue; + } + if(box.type == JP2_CDEF) + { + if( !jp2_read_cdef(jp2, cio, &box, color)) + { + cio_seek(cio, box.init_pos + 8); + cio_skip(cio, box.length - 8); + } + jp2_read_boxhdr(cinfo, cio, &box); + continue; + } + if(box.type == JP2_PCLR) + { + if( !jp2_read_pclr(jp2, cio, &box, color)) + { + cio_seek(cio, box.init_pos + 8); + cio_skip(cio, box.length - 8); + } + jp2_read_boxhdr(cinfo, cio, &box); + continue; + } + if(box.type == JP2_CMAP) + { + if( !jp2_read_cmap(jp2, cio, &box, color)) + { + cio_seek(cio, box.init_pos + 8); + cio_skip(cio, box.length - 8); + } + jp2_read_boxhdr(cinfo, cio, &box); + continue; + } + cio_seek(cio, box.init_pos + 8); + cio_skip(cio, box.length - 8); + jp2_read_boxhdr(cinfo, cio, &box); + + }/* while(cio_tell(cio) < box_end) */ + + cio_seek(cio, jp2h_end); + +/* Part 1, I.5.3.3 : 'must contain at least one' */ + return (color->jp2_has_colr == 1); + +}/* jp2_read_jp2h() */ + +opj_image_t* jp2_decode(opj_jp2_t *jp2, opj_cio_t *cio, + opj_codestream_info_t *cstr_info) +{ + opj_common_ptr cinfo; + opj_image_t *image = NULL; + opj_jp2_color_t color; + + if(!jp2 || !cio) + { + return NULL; + } + memset(&color, 0, sizeof(opj_jp2_color_t)); + cinfo = jp2->cinfo; + +/* JP2 decoding */ + if(!jp2_read_struct(jp2, cio, &color)) + { + free_color_data(&color); + opj_event_msg(cinfo, EVT_ERROR, "Failed to decode jp2 structure\n"); + return NULL; + } + +/* J2K decoding */ + image = j2k_decode(jp2->j2k, cio, cstr_info); + + if(!image) + { + free_color_data(&color); + opj_event_msg(cinfo, EVT_ERROR, "Failed to decode J2K image\n"); + return NULL; + } + +/* Set Image Color Space */ + if (jp2->enumcs == 16) + image->color_space = CLRSPC_SRGB; + else if (jp2->enumcs == 17) + image->color_space = CLRSPC_GRAY; + else if (jp2->enumcs == 18) + image->color_space = CLRSPC_SYCC; + else + image->color_space = CLRSPC_UNKNOWN; + + if(color.jp2_cdef) + { + jp2_apply_cdef(image, &color); + } + if(color.jp2_pclr) + { +/* Part 1, I.5.3.4: Either both or none : */ + if( !color.jp2_pclr->cmap) + jp2_free_pclr(&color); + else + jp2_apply_pclr(&color, image); + } + if(color.icc_profile_buf) + { + image->icc_profile_buf = color.icc_profile_buf; + color.icc_profile_buf = NULL; + image->icc_profile_len = color.icc_profile_len; + } + return image; + +}/* jp2_decode() */ + + +void jp2_write_jp2h(opj_jp2_t *jp2, opj_cio_t *cio) { + opj_jp2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio, 4); + cio_write(cio, JP2_JP2H, 4); /* JP2H */ + + jp2_write_ihdr(jp2, cio); + + if (jp2->bpc == 255) { + jp2_write_bpcc(jp2, cio); + } + jp2_write_colr(jp2, cio); + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +static void jp2_write_ftyp(opj_jp2_t *jp2, opj_cio_t *cio) { + unsigned int i; + opj_jp2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio, 4); + cio_write(cio, JP2_FTYP, 4); /* FTYP */ + + cio_write(cio, jp2->brand, 4); /* BR */ + cio_write(cio, jp2->minversion, 4); /* MinV */ + + for (i = 0; i < jp2->numcl; i++) { + cio_write(cio, jp2->cl[i], 4); /* CL */ + } + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +static bool jp2_read_ftyp(opj_jp2_t *jp2, opj_cio_t *cio) { + int i; + opj_jp2_box_t box; + + opj_common_ptr cinfo = jp2->cinfo; + + jp2_read_boxhdr(cinfo, cio, &box); + + if (JP2_FTYP != box.type) { + opj_event_msg(cinfo, EVT_ERROR, "Expected FTYP Marker\n"); + return false; + } + + jp2->brand = cio_read(cio, 4); /* BR */ + jp2->minversion = cio_read(cio, 4); /* MinV */ + jp2->numcl = (box.length - 16) / 4; + jp2->cl = (unsigned int *) opj_malloc(jp2->numcl * sizeof(unsigned int)); + + for (i = 0; i < (int)jp2->numcl; i++) { + jp2->cl[i] = cio_read(cio, 4); /* CLi */ + } + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cinfo, EVT_ERROR, "Error with FTYP Box\n"); + return false; + } + + return true; +} + +static int jp2_write_jp2c(opj_jp2_t *jp2, opj_cio_t *cio, opj_image_t *image, opj_codestream_info_t *cstr_info) { + unsigned int j2k_codestream_offset, j2k_codestream_length; + opj_jp2_box_t box; + + opj_j2k_t *j2k = jp2->j2k; + + box.init_pos = cio_tell(cio); + cio_skip(cio, 4); + cio_write(cio, JP2_JP2C, 4); /* JP2C */ + + /* J2K encoding */ + j2k_codestream_offset = cio_tell(cio); + if(!j2k_encode(j2k, cio, image, cstr_info)) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "Failed to encode image\n"); + return 0; + } + j2k_codestream_length = cio_tell(cio) - j2k_codestream_offset; + + jp2->j2k_codestream_offset = j2k_codestream_offset; + jp2->j2k_codestream_length = j2k_codestream_length; + + box.length = 8 + jp2->j2k_codestream_length; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); + + return box.length; +} + +static bool jp2_read_jp2c(opj_jp2_t *jp2, opj_cio_t *cio, unsigned int *j2k_codestream_length, unsigned int *j2k_codestream_offset) { + opj_jp2_box_t box; + + opj_common_ptr cinfo = jp2->cinfo; + + jp2_read_boxhdr(cinfo, cio, &box); + do { + if(JP2_JP2C != box.type) { + cio_skip(cio, box.length - 8); + jp2_read_boxhdr(cinfo, cio, &box); + } + } while(JP2_JP2C != box.type); + + *j2k_codestream_offset = cio_tell(cio); + *j2k_codestream_length = box.length - 8; + + return true; +} + +static void jp2_write_jp(opj_cio_t *cio) { + opj_jp2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio, 4); + cio_write(cio, JP2_JP, 4); /* JP2 signature */ + cio_write(cio, 0x0d0a870a, 4); + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +static bool jp2_read_jp(opj_jp2_t *jp2, opj_cio_t *cio) { + opj_jp2_box_t box; + + opj_common_ptr cinfo = jp2->cinfo; + + jp2_read_boxhdr(cinfo, cio, &box); + if (JP2_JP != box.type) { + opj_event_msg(cinfo, EVT_ERROR, "Expected JP Marker\n"); + return false; + } + if (0x0d0a870a != cio_read(cio, 4)) { + opj_event_msg(cinfo, EVT_ERROR, "Error with JP Marker\n"); + return false; + } + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cinfo, EVT_ERROR, "Error with JP Box size\n"); + return false; + } + + return true; +} + + +static bool jp2_read_struct(opj_jp2_t *jp2, opj_cio_t *cio, + opj_jp2_color_t *color) { + if (!jp2_read_jp(jp2, cio)) + return false; + if (!jp2_read_ftyp(jp2, cio)) + return false; + if (!jp2_read_jp2h(jp2, cio, color)) + return false; + if (!jp2_read_jp2c(jp2, cio, &jp2->j2k_codestream_length, &jp2->j2k_codestream_offset)) + return false; + + return true; +} + +/* ----------------------------------------------------------------------- */ +/* JP2 decoder interface */ +/* ----------------------------------------------------------------------- */ + +opj_jp2_t* jp2_create_decompress(opj_common_ptr cinfo) { + opj_jp2_t *jp2 = (opj_jp2_t*) opj_calloc(1, sizeof(opj_jp2_t)); + if(jp2) { + jp2->cinfo = cinfo; + /* create the J2K codec */ + jp2->j2k = j2k_create_decompress(cinfo); + if(jp2->j2k == NULL) { + jp2_destroy_decompress(jp2); + return NULL; + } + } + return jp2; +} + +void jp2_destroy_decompress(opj_jp2_t *jp2) { + if(jp2) { + /* destroy the J2K codec */ + j2k_destroy_decompress(jp2->j2k); + + if(jp2->comps) { + opj_free(jp2->comps); + } + if(jp2->cl) { + opj_free(jp2->cl); + } + opj_free(jp2); + } +} + +void jp2_setup_decoder(opj_jp2_t *jp2, opj_dparameters_t *parameters) { + /* setup the J2K codec */ + j2k_setup_decoder(jp2->j2k, parameters); + /* further JP2 initializations go here */ +} + +/* ----------------------------------------------------------------------- */ +/* JP2 encoder interface */ +/* ----------------------------------------------------------------------- */ + +opj_jp2_t* jp2_create_compress(opj_common_ptr cinfo) { + opj_jp2_t *jp2 = (opj_jp2_t*)opj_malloc(sizeof(opj_jp2_t)); + if(jp2) { + jp2->cinfo = cinfo; + /* create the J2K codec */ + jp2->j2k = j2k_create_compress(cinfo); + if(jp2->j2k == NULL) { + jp2_destroy_compress(jp2); + return NULL; + } + } + return jp2; +} + +void jp2_destroy_compress(opj_jp2_t *jp2) { + if(jp2) { + /* destroy the J2K codec */ + j2k_destroy_compress(jp2->j2k); + + if(jp2->comps) { + opj_free(jp2->comps); + } + if(jp2->cl) { + opj_free(jp2->cl); + } + opj_free(jp2); + } +} + +void jp2_setup_encoder(opj_jp2_t *jp2, opj_cparameters_t *parameters, opj_image_t *image) { + int i; + int depth_0, sign; + + if(!jp2 || !parameters || !image) + return; + + /* setup the J2K codec */ + /* ------------------- */ + + /* Check if number of components respects standard */ + if (image->numcomps < 1 || image->numcomps > 16384) { + opj_event_msg(jp2->cinfo, EVT_ERROR, "Invalid number of components specified while setting up JP2 encoder\n"); + return; + } + + j2k_setup_encoder(jp2->j2k, parameters, image); + + /* setup the JP2 codec */ + /* ------------------- */ + + /* Profile box */ + + jp2->brand = JP2_JP2; /* BR */ + jp2->minversion = 0; /* MinV */ + jp2->numcl = 1; + jp2->cl = (unsigned int*) opj_malloc(jp2->numcl * sizeof(unsigned int)); + jp2->cl[0] = JP2_JP2; /* CL0 : JP2 */ + + /* Image Header box */ + + jp2->numcomps = image->numcomps; /* NC */ + jp2->comps = (opj_jp2_comps_t*) opj_malloc(jp2->numcomps * sizeof(opj_jp2_comps_t)); + jp2->h = image->y1 - image->y0; /* HEIGHT */ + jp2->w = image->x1 - image->x0; /* WIDTH */ + /* BPC */ + depth_0 = image->comps[0].prec - 1; + sign = image->comps[0].sgnd; + jp2->bpc = depth_0 + (sign << 7); + for (i = 1; i < image->numcomps; i++) { + int depth = image->comps[i].prec - 1; + sign = image->comps[i].sgnd; + if (depth_0 != depth) + jp2->bpc = 255; + } + jp2->C = 7; /* C : Always 7 */ + jp2->UnkC = 0; /* UnkC, colorspace specified in colr box */ + jp2->IPR = 0; /* IPR, no intellectual property */ + + /* BitsPerComponent box */ + + for (i = 0; i < image->numcomps; i++) { + jp2->comps[i].bpcc = image->comps[i].prec - 1 + (image->comps[i].sgnd << 7); + } + + /* Colour Specification box */ + + if ((image->numcomps == 1 || image->numcomps == 3) && (jp2->bpc != 255)) { + jp2->meth = 1; /* METH: Enumerated colourspace */ + } else { + jp2->meth = 2; /* METH: Restricted ICC profile */ + } + if (jp2->meth == 1) { + if (image->color_space == 1) + jp2->enumcs = 16; /* sRGB as defined by IEC 61966–2–1 */ + else if (image->color_space == 2) + jp2->enumcs = 17; /* greyscale */ + else if (image->color_space == 3) + jp2->enumcs = 18; /* YUV */ + } else { + jp2->enumcs = 0; /* PROFILE (??) */ + } + jp2->precedence = 0; /* PRECEDENCE */ + jp2->approx = 0; /* APPROX */ + +} + +bool jp2_encode(opj_jp2_t *jp2, opj_cio_t *cio, opj_image_t *image, opj_codestream_info_t *cstr_info) { + + /* JP2 encoding */ + + /* JPEG 2000 Signature box */ + jp2_write_jp(cio); + /* File Type box */ + jp2_write_ftyp(jp2, cio); + /* JP2 Header box */ + jp2_write_jp2h(jp2, cio); + + /* J2K encoding */ + + if(!jp2_write_jp2c(jp2, cio, image, cstr_info)) { + opj_event_msg(jp2->cinfo, EVT_ERROR, "Failed to encode image\n"); + return false; + } + + return true; +} + + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/jp2.h b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/jp2.h new file mode 100644 index 0000000..9ad662c --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/jp2.h @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __JP2_H +#define __JP2_H +/** +@file jp2.h +@brief The JPEG-2000 file format Reader/Writer (JP2) + +*/ + +/** @defgroup JP2 JP2 - JPEG-2000 file format reader/writer */ +/*@{*/ + +#define JPIP_JPIP 0x6a706970 + +#define JP2_JP 0x6a502020 /**< JPEG 2000 signature box */ +#define JP2_FTYP 0x66747970 /**< File type box */ +#define JP2_JP2H 0x6a703268 /**< JP2 header box */ +#define JP2_IHDR 0x69686472 /**< Image header box */ +#define JP2_COLR 0x636f6c72 /**< Colour specification box */ +#define JP2_JP2C 0x6a703263 /**< Contiguous codestream box */ +#define JP2_URL 0x75726c20 /**< URL box */ +#define JP2_DTBL 0x6474626c /**< Data Reference box */ +#define JP2_BPCC 0x62706363 /**< Bits per component box */ +#define JP2_JP2 0x6a703220 /**< File type fields */ +#define JP2_PCLR 0x70636c72 /**< Palette box */ +#define JP2_CMAP 0x636d6170 /**< Component Mapping box */ +#define JP2_CDEF 0x63646566 /**< Channel Definition box */ + +/* ----------------------------------------------------------------------- */ +/** +Channel description: channel index, type, assocation +*/ +typedef struct opj_jp2_cdef_info +{ + unsigned short cn, typ, asoc; +} opj_jp2_cdef_info_t; + +/** +Channel descriptions and number of descriptions +*/ +typedef struct opj_jp2_cdef +{ + opj_jp2_cdef_info_t *info; + unsigned short n; +} opj_jp2_cdef_t; + +/** +Component mappings: channel index, mapping type, palette index +*/ +typedef struct opj_jp2_cmap_comp +{ + unsigned short cmp; + unsigned char mtyp, pcol; +} opj_jp2_cmap_comp_t; + +/** +Palette data: table entries, palette columns +*/ +typedef struct opj_jp2_pclr +{ + unsigned int *entries; + unsigned char *channel_sign; + unsigned char *channel_size; + opj_jp2_cmap_comp_t *cmap; + unsigned short nr_entries, nr_channels; +} opj_jp2_pclr_t; + +/** +Collector for ICC profile, palette, component mapping, channel description +*/ +typedef struct opj_jp2_color +{ + unsigned char *icc_profile_buf; + int icc_profile_len; + + opj_jp2_cdef_t *jp2_cdef; + opj_jp2_pclr_t *jp2_pclr; + unsigned char jp2_has_colr; +} opj_jp2_color_t; + +/** +JP2 component +*/ +typedef struct opj_jp2_comps { + int depth; + int sgnd; + int bpcc; +} opj_jp2_comps_t; + +/** +JPEG-2000 file format reader/writer +*/ +typedef struct opj_jp2 { + /** codec context */ + opj_common_ptr cinfo; + /** handle to the J2K codec */ + opj_j2k_t *j2k; + unsigned int w; + unsigned int h; + unsigned int numcomps; + unsigned int bpc; + unsigned int C; + unsigned int UnkC; + unsigned int IPR; + unsigned int meth; + unsigned int approx; + unsigned int enumcs; + unsigned int precedence; + unsigned int brand; + unsigned int minversion; + unsigned int numcl; + unsigned int *cl; + opj_jp2_comps_t *comps; + unsigned int j2k_codestream_offset; + unsigned int j2k_codestream_length; +} opj_jp2_t; + +/** +JP2 Box +*/ +typedef struct opj_jp2_box { + int length; + int type; + int init_pos; +} opj_jp2_box_t; + +/** @name Exported functions */ +/*@{*/ +/* ----------------------------------------------------------------------- */ +/** +Write the JP2H box - JP2 Header box (used in MJ2) +@param jp2 JP2 handle +@param cio Output buffer stream +*/ +void jp2_write_jp2h(opj_jp2_t *jp2, opj_cio_t *cio); +/** +Read the JP2H box - JP2 Header box (used in MJ2) +@param jp2 JP2 handle +@param cio Input buffer stream +@param ext Collector for profile, cdef and pclr data +@return Returns true if successful, returns false otherwise +*/ +bool jp2_read_jp2h(opj_jp2_t *jp2, opj_cio_t *cio, opj_jp2_color_t *color); +/** +Creates a JP2 decompression structure +@param cinfo Codec context info +@return Returns a handle to a JP2 decompressor if successful, returns NULL otherwise +*/ +opj_jp2_t* jp2_create_decompress(opj_common_ptr cinfo); +/** +Destroy a JP2 decompressor handle +@param jp2 JP2 decompressor handle to destroy +*/ +void jp2_destroy_decompress(opj_jp2_t *jp2); +/** +Setup the decoder decoding parameters using user parameters. +Decoding parameters are returned in jp2->j2k->cp. +@param jp2 JP2 decompressor handle +@param parameters decompression parameters +*/ +void jp2_setup_decoder(opj_jp2_t *jp2, opj_dparameters_t *parameters); +/** +Decode an image from a JPEG-2000 file stream +@param jp2 JP2 decompressor handle +@param cio Input buffer stream +@param cstr_info Codestream information structure if required, NULL otherwise +@return Returns a decoded image if successful, returns NULL otherwise +*/ +opj_image_t* jp2_decode(opj_jp2_t *jp2, opj_cio_t *cio, opj_codestream_info_t *cstr_info); +/** +Creates a JP2 compression structure +@param cinfo Codec context info +@return Returns a handle to a JP2 compressor if successful, returns NULL otherwise +*/ +opj_jp2_t* jp2_create_compress(opj_common_ptr cinfo); +/** +Destroy a JP2 compressor handle +@param jp2 JP2 compressor handle to destroy +*/ +void jp2_destroy_compress(opj_jp2_t *jp2); +/** +Setup the encoder parameters using the current image and using user parameters. +Coding parameters are returned in jp2->j2k->cp. +@param jp2 JP2 compressor handle +@param parameters compression parameters +@param image input filled image +*/ +void jp2_setup_encoder(opj_jp2_t *jp2, opj_cparameters_t *parameters, opj_image_t *image); +/** +Encode an image into a JPEG-2000 file stream +@param jp2 JP2 compressor handle +@param cio Output buffer stream +@param image Image to encode +@param cstr_info Codestream information structure if required, NULL otherwise +@return Returns true if successful, returns false otherwise +*/ +bool jp2_encode(opj_jp2_t *jp2, opj_cio_t *cio, opj_image_t *image, opj_codestream_info_t *cstr_info); +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __JP2_H */ + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/jpt.c b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/jpt.c new file mode 100644 index 0000000..a2566ea --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/jpt.c @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "opj_includes.h" + +/* + * Read the information contains in VBAS [JPP/JPT stream message header] + * Store information (7 bits) in value + * + */ +unsigned int jpt_read_VBAS_info(opj_cio_t *cio, unsigned int value) { + unsigned char elmt; + + elmt = cio_read(cio, 1); + while ((elmt >> 7) == 1) { + value = (value << 7); + value |= (elmt & 0x7f); + elmt = cio_read(cio, 1); + } + value = (value << 7); + value |= (elmt & 0x7f); + + return value; +} + +/* + * Initialize the value of the message header structure + * + */ +void jpt_init_msg_header(opj_jpt_msg_header_t * header) { + header->Id = 0; /* In-class Identifier */ + header->last_byte = 0; /* Last byte information */ + header->Class_Id = 0; /* Class Identifier */ + header->CSn_Id = 0; /* CSn : index identifier */ + header->Msg_offset = 0; /* Message offset */ + header->Msg_length = 0; /* Message length */ + header->Layer_nb = 0; /* Auxiliary for JPP case */ +} + +/* + * Re-initialize the value of the message header structure + * + * Only parameters always present in message header + * + */ +void jpt_reinit_msg_header(opj_jpt_msg_header_t * header) { + header->Id = 0; /* In-class Identifier */ + header->last_byte = 0; /* Last byte information */ + header->Msg_offset = 0; /* Message offset */ + header->Msg_length = 0; /* Message length */ +} + +/* + * Read the message header for a JPP/JPT - stream + * + */ +void jpt_read_msg_header(opj_common_ptr cinfo, opj_cio_t *cio, opj_jpt_msg_header_t *header) { + unsigned char elmt, Class = 0, CSn = 0; + jpt_reinit_msg_header(header); + + /* ------------- */ + /* VBAS : Bin-ID */ + /* ------------- */ + elmt = cio_read(cio, 1); + + /* See for Class and CSn */ + switch ((elmt >> 5) & 0x03) { + case 0: + opj_event_msg(cinfo, EVT_ERROR, "Forbidden value encounter in message header !!\n"); + break; + case 1: + Class = 0; + CSn = 0; + break; + case 2: + Class = 1; + CSn = 0; + break; + case 3: + Class = 1; + CSn = 1; + break; + default: + break; + } + + /* see information on bits 'c' [p 10 : A.2.1 general, ISO/IEC FCD 15444-9] */ + if (((elmt >> 4) & 0x01) == 1) + header->last_byte = 1; + + /* In-class identifier */ + header->Id |= (elmt & 0x0f); + if ((elmt >> 7) == 1) + header->Id = jpt_read_VBAS_info(cio, header->Id); + + /* ------------ */ + /* VBAS : Class */ + /* ------------ */ + if (Class == 1) { + header->Class_Id = 0; + header->Class_Id = jpt_read_VBAS_info(cio, header->Class_Id); + } + + /* ---------- */ + /* VBAS : CSn */ + /* ---------- */ + if (CSn == 1) { + header->CSn_Id = 0; + header->CSn_Id = jpt_read_VBAS_info(cio, header->CSn_Id); + } + + /* ----------------- */ + /* VBAS : Msg_offset */ + /* ----------------- */ + header->Msg_offset = jpt_read_VBAS_info(cio, header->Msg_offset); + + /* ----------------- */ + /* VBAS : Msg_length */ + /* ----------------- */ + header->Msg_length = jpt_read_VBAS_info(cio, header->Msg_length); + + /* ---------- */ + /* VBAS : Aux */ + /* ---------- */ + if ((header->Class_Id & 0x01) == 1) { + header->Layer_nb = 0; + header->Layer_nb = jpt_read_VBAS_info(cio, header->Layer_nb); + } +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/jpt.h b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/jpt.h new file mode 100644 index 0000000..eb01f98 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/jpt.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __JPT_H +#define __JPT_H +/** +@file jpt.h +@brief JPT-stream reader (JPEG 2000, JPIP) + +JPT-stream functions are implemented in J2K.C. +*/ + +/** +Message Header JPT stream structure +*/ +typedef struct opj_jpt_msg_header { + /** In-class Identifier */ + unsigned int Id; + /** Last byte information */ + unsigned int last_byte; + /** Class Identifier */ + unsigned int Class_Id; + /** CSn : index identifier */ + unsigned int CSn_Id; + /** Message offset */ + unsigned int Msg_offset; + /** Message length */ + unsigned int Msg_length; + /** Auxiliary for JPP case */ + unsigned int Layer_nb; +} opj_jpt_msg_header_t; + +/* ----------------------------------------------------------------------- */ + +/** +Initialize the value of the message header structure +@param header Message header structure +*/ +void jpt_init_msg_header(opj_jpt_msg_header_t * header); + +/** +Read the message header for a JPP/JPT - stream +@param cinfo Codec context info +@param cio CIO handle +@param header Message header structure +*/ +void jpt_read_msg_header(opj_common_ptr cinfo, opj_cio_t *cio, opj_jpt_msg_header_t *header); + +#endif diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/mct.c b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/mct.c new file mode 100644 index 0000000..870993b --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/mct.c @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef __SSE__ +#include +#endif + +#include "opj_includes.h" + +/* */ +/* This table contains the norms of the basis function of the reversible MCT. */ +/* */ +static const double mct_norms[3] = { 1.732, .8292, .8292 }; + +/* */ +/* This table contains the norms of the basis function of the irreversible MCT. */ +/* */ +static const double mct_norms_real[3] = { 1.732, 1.805, 1.573 }; + +/* */ +/* Foward reversible MCT. */ +/* */ +void mct_encode( + int* restrict c0, + int* restrict c1, + int* restrict c2, + int n) +{ + int i; + for(i = 0; i < n; ++i) { + int r = c0[i]; + int g = c1[i]; + int b = c2[i]; + int y = (r + (g * 2) + b) >> 2; + int u = b - g; + int v = r - g; + c0[i] = y; + c1[i] = u; + c2[i] = v; + } +} + +/* */ +/* Inverse reversible MCT. */ +/* */ +void mct_decode( + int* restrict c0, + int* restrict c1, + int* restrict c2, + int n) +{ + int i; + for (i = 0; i < n; ++i) { + int y = c0[i]; + int u = c1[i]; + int v = c2[i]; + int g = y - ((u + v) >> 2); + int r = v + g; + int b = u + g; + c0[i] = r; + c1[i] = g; + c2[i] = b; + } +} + +/* */ +/* Get norm of basis function of reversible MCT. */ +/* */ +double mct_getnorm(int compno) { + return mct_norms[compno]; +} + +/* */ +/* Foward irreversible MCT. */ +/* */ +void mct_encode_real( + int* restrict c0, + int* restrict c1, + int* restrict c2, + int n) +{ + int i; + for(i = 0; i < n; ++i) { + int r = c0[i]; + int g = c1[i]; + int b = c2[i]; + int y = fix_mul(r, 2449) + fix_mul(g, 4809) + fix_mul(b, 934); + int u = -fix_mul(r, 1382) - fix_mul(g, 2714) + fix_mul(b, 4096); + int v = fix_mul(r, 4096) - fix_mul(g, 3430) - fix_mul(b, 666); + c0[i] = y; + c1[i] = u; + c2[i] = v; + } +} + +/* */ +/* Inverse irreversible MCT. */ +/* */ +void mct_decode_real( + float* restrict c0, + float* restrict c1, + float* restrict c2, + int n) +{ + int i; +#ifdef __SSE__ + __m128 vrv, vgu, vgv, vbu; + vrv = _mm_set1_ps(1.402f); + vgu = _mm_set1_ps(0.34413f); + vgv = _mm_set1_ps(0.71414f); + vbu = _mm_set1_ps(1.772f); + for (i = 0; i < (n >> 3); ++i) { + __m128 vy, vu, vv; + __m128 vr, vg, vb; + + vy = _mm_load_ps(c0); + vu = _mm_load_ps(c1); + vv = _mm_load_ps(c2); + vr = _mm_add_ps(vy, _mm_mul_ps(vv, vrv)); + vg = _mm_sub_ps(_mm_sub_ps(vy, _mm_mul_ps(vu, vgu)), _mm_mul_ps(vv, vgv)); + vb = _mm_add_ps(vy, _mm_mul_ps(vu, vbu)); + _mm_store_ps(c0, vr); + _mm_store_ps(c1, vg); + _mm_store_ps(c2, vb); + c0 += 4; + c1 += 4; + c2 += 4; + + vy = _mm_load_ps(c0); + vu = _mm_load_ps(c1); + vv = _mm_load_ps(c2); + vr = _mm_add_ps(vy, _mm_mul_ps(vv, vrv)); + vg = _mm_sub_ps(_mm_sub_ps(vy, _mm_mul_ps(vu, vgu)), _mm_mul_ps(vv, vgv)); + vb = _mm_add_ps(vy, _mm_mul_ps(vu, vbu)); + _mm_store_ps(c0, vr); + _mm_store_ps(c1, vg); + _mm_store_ps(c2, vb); + c0 += 4; + c1 += 4; + c2 += 4; + } + n &= 7; +#endif + for(i = 0; i < n; ++i) { + float y = c0[i]; + float u = c1[i]; + float v = c2[i]; + float r = y + (v * 1.402f); + float g = y - (u * 0.34413f) - (v * (0.71414f)); + float b = y + (u * 1.772f); + c0[i] = r; + c1[i] = g; + c2[i] = b; + } +} + +/* */ +/* Get norm of basis function of irreversible MCT. */ +/* */ +double mct_getnorm_real(int compno) { + return mct_norms_real[compno]; +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/mct.h b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/mct.h new file mode 100644 index 0000000..84e3f8a --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/mct.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MCT_H +#define __MCT_H +/** +@file mct.h +@brief Implementation of a multi-component transforms (MCT) + +The functions in MCT.C have for goal to realize reversible and irreversible multicomponent +transform. The functions in MCT.C are used by some function in TCD.C. +*/ + +/** @defgroup MCT MCT - Implementation of a multi-component transform */ +/*@{*/ + +/** @name Exported functions */ +/*@{*/ +/* ----------------------------------------------------------------------- */ +/** +Apply a reversible multi-component transform to an image +@param c0 Samples for red component +@param c1 Samples for green component +@param c2 Samples blue component +@param n Number of samples for each component +*/ +void mct_encode(int *c0, int *c1, int *c2, int n); +/** +Apply a reversible multi-component inverse transform to an image +@param c0 Samples for luminance component +@param c1 Samples for red chrominance component +@param c2 Samples for blue chrominance component +@param n Number of samples for each component +*/ +void mct_decode(int *c0, int *c1, int *c2, int n); +/** +Get norm of the basis function used for the reversible multi-component transform +@param compno Number of the component (0->Y, 1->U, 2->V) +@return +*/ +double mct_getnorm(int compno); + +/** +Apply an irreversible multi-component transform to an image +@param c0 Samples for red component +@param c1 Samples for green component +@param c2 Samples blue component +@param n Number of samples for each component +*/ +void mct_encode_real(int *c0, int *c1, int *c2, int n); +/** +Apply an irreversible multi-component inverse transform to an image +@param c0 Samples for luminance component +@param c1 Samples for red chrominance component +@param c2 Samples for blue chrominance component +@param n Number of samples for each component +*/ +void mct_decode_real(float* c0, float* c1, float* c2, int n); +/** +Get norm of the basis function used for the irreversible multi-component transform +@param compno Number of the component (0->Y, 1->U, 2->V) +@return +*/ +double mct_getnorm_real(int compno); +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __MCT_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/mqc.c b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/mqc.c new file mode 100644 index 0000000..5d25238 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/mqc.c @@ -0,0 +1,593 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "opj_includes.h" + +/** @defgroup MQC MQC - Implementation of an MQ-Coder */ +/*@{*/ + +/** @name Local static functions */ +/*@{*/ + +/** +Output a byte, doing bit-stuffing if necessary. +After a 0xff byte, the next byte must be smaller than 0x90. +@param mqc MQC handle +*/ +static void mqc_byteout(opj_mqc_t *mqc); +/** +Renormalize mqc->a and mqc->c while encoding, so that mqc->a stays between 0x8000 and 0x10000 +@param mqc MQC handle +*/ +static void mqc_renorme(opj_mqc_t *mqc); +/** +Encode the most probable symbol +@param mqc MQC handle +*/ +static void mqc_codemps(opj_mqc_t *mqc); +/** +Encode the most least symbol +@param mqc MQC handle +*/ +static void mqc_codelps(opj_mqc_t *mqc); +/** +Fill mqc->c with 1's for flushing +@param mqc MQC handle +*/ +static void mqc_setbits(opj_mqc_t *mqc); +/** +FIXME: documentation ??? +@param mqc MQC handle +@return +*/ +static INLINE int mqc_mpsexchange(opj_mqc_t *const mqc); +/** +FIXME: documentation ??? +@param mqc MQC handle +@return +*/ +static INLINE int mqc_lpsexchange(opj_mqc_t *const mqc); +/** +Input a byte +@param mqc MQC handle +*/ +static INLINE void mqc_bytein(opj_mqc_t *const mqc); +/** +Renormalize mqc->a and mqc->c while decoding +@param mqc MQC handle +*/ +static INLINE void mqc_renormd(opj_mqc_t *const mqc); +/*@}*/ + +/*@}*/ + +/* */ +/* This array defines all the possible states for a context. */ +/* */ +static opj_mqc_state_t mqc_states[47 * 2] = { + {0x5601, 0, &mqc_states[2], &mqc_states[3]}, + {0x5601, 1, &mqc_states[3], &mqc_states[2]}, + {0x3401, 0, &mqc_states[4], &mqc_states[12]}, + {0x3401, 1, &mqc_states[5], &mqc_states[13]}, + {0x1801, 0, &mqc_states[6], &mqc_states[18]}, + {0x1801, 1, &mqc_states[7], &mqc_states[19]}, + {0x0ac1, 0, &mqc_states[8], &mqc_states[24]}, + {0x0ac1, 1, &mqc_states[9], &mqc_states[25]}, + {0x0521, 0, &mqc_states[10], &mqc_states[58]}, + {0x0521, 1, &mqc_states[11], &mqc_states[59]}, + {0x0221, 0, &mqc_states[76], &mqc_states[66]}, + {0x0221, 1, &mqc_states[77], &mqc_states[67]}, + {0x5601, 0, &mqc_states[14], &mqc_states[13]}, + {0x5601, 1, &mqc_states[15], &mqc_states[12]}, + {0x5401, 0, &mqc_states[16], &mqc_states[28]}, + {0x5401, 1, &mqc_states[17], &mqc_states[29]}, + {0x4801, 0, &mqc_states[18], &mqc_states[28]}, + {0x4801, 1, &mqc_states[19], &mqc_states[29]}, + {0x3801, 0, &mqc_states[20], &mqc_states[28]}, + {0x3801, 1, &mqc_states[21], &mqc_states[29]}, + {0x3001, 0, &mqc_states[22], &mqc_states[34]}, + {0x3001, 1, &mqc_states[23], &mqc_states[35]}, + {0x2401, 0, &mqc_states[24], &mqc_states[36]}, + {0x2401, 1, &mqc_states[25], &mqc_states[37]}, + {0x1c01, 0, &mqc_states[26], &mqc_states[40]}, + {0x1c01, 1, &mqc_states[27], &mqc_states[41]}, + {0x1601, 0, &mqc_states[58], &mqc_states[42]}, + {0x1601, 1, &mqc_states[59], &mqc_states[43]}, + {0x5601, 0, &mqc_states[30], &mqc_states[29]}, + {0x5601, 1, &mqc_states[31], &mqc_states[28]}, + {0x5401, 0, &mqc_states[32], &mqc_states[28]}, + {0x5401, 1, &mqc_states[33], &mqc_states[29]}, + {0x5101, 0, &mqc_states[34], &mqc_states[30]}, + {0x5101, 1, &mqc_states[35], &mqc_states[31]}, + {0x4801, 0, &mqc_states[36], &mqc_states[32]}, + {0x4801, 1, &mqc_states[37], &mqc_states[33]}, + {0x3801, 0, &mqc_states[38], &mqc_states[34]}, + {0x3801, 1, &mqc_states[39], &mqc_states[35]}, + {0x3401, 0, &mqc_states[40], &mqc_states[36]}, + {0x3401, 1, &mqc_states[41], &mqc_states[37]}, + {0x3001, 0, &mqc_states[42], &mqc_states[38]}, + {0x3001, 1, &mqc_states[43], &mqc_states[39]}, + {0x2801, 0, &mqc_states[44], &mqc_states[38]}, + {0x2801, 1, &mqc_states[45], &mqc_states[39]}, + {0x2401, 0, &mqc_states[46], &mqc_states[40]}, + {0x2401, 1, &mqc_states[47], &mqc_states[41]}, + {0x2201, 0, &mqc_states[48], &mqc_states[42]}, + {0x2201, 1, &mqc_states[49], &mqc_states[43]}, + {0x1c01, 0, &mqc_states[50], &mqc_states[44]}, + {0x1c01, 1, &mqc_states[51], &mqc_states[45]}, + {0x1801, 0, &mqc_states[52], &mqc_states[46]}, + {0x1801, 1, &mqc_states[53], &mqc_states[47]}, + {0x1601, 0, &mqc_states[54], &mqc_states[48]}, + {0x1601, 1, &mqc_states[55], &mqc_states[49]}, + {0x1401, 0, &mqc_states[56], &mqc_states[50]}, + {0x1401, 1, &mqc_states[57], &mqc_states[51]}, + {0x1201, 0, &mqc_states[58], &mqc_states[52]}, + {0x1201, 1, &mqc_states[59], &mqc_states[53]}, + {0x1101, 0, &mqc_states[60], &mqc_states[54]}, + {0x1101, 1, &mqc_states[61], &mqc_states[55]}, + {0x0ac1, 0, &mqc_states[62], &mqc_states[56]}, + {0x0ac1, 1, &mqc_states[63], &mqc_states[57]}, + {0x09c1, 0, &mqc_states[64], &mqc_states[58]}, + {0x09c1, 1, &mqc_states[65], &mqc_states[59]}, + {0x08a1, 0, &mqc_states[66], &mqc_states[60]}, + {0x08a1, 1, &mqc_states[67], &mqc_states[61]}, + {0x0521, 0, &mqc_states[68], &mqc_states[62]}, + {0x0521, 1, &mqc_states[69], &mqc_states[63]}, + {0x0441, 0, &mqc_states[70], &mqc_states[64]}, + {0x0441, 1, &mqc_states[71], &mqc_states[65]}, + {0x02a1, 0, &mqc_states[72], &mqc_states[66]}, + {0x02a1, 1, &mqc_states[73], &mqc_states[67]}, + {0x0221, 0, &mqc_states[74], &mqc_states[68]}, + {0x0221, 1, &mqc_states[75], &mqc_states[69]}, + {0x0141, 0, &mqc_states[76], &mqc_states[70]}, + {0x0141, 1, &mqc_states[77], &mqc_states[71]}, + {0x0111, 0, &mqc_states[78], &mqc_states[72]}, + {0x0111, 1, &mqc_states[79], &mqc_states[73]}, + {0x0085, 0, &mqc_states[80], &mqc_states[74]}, + {0x0085, 1, &mqc_states[81], &mqc_states[75]}, + {0x0049, 0, &mqc_states[82], &mqc_states[76]}, + {0x0049, 1, &mqc_states[83], &mqc_states[77]}, + {0x0025, 0, &mqc_states[84], &mqc_states[78]}, + {0x0025, 1, &mqc_states[85], &mqc_states[79]}, + {0x0015, 0, &mqc_states[86], &mqc_states[80]}, + {0x0015, 1, &mqc_states[87], &mqc_states[81]}, + {0x0009, 0, &mqc_states[88], &mqc_states[82]}, + {0x0009, 1, &mqc_states[89], &mqc_states[83]}, + {0x0005, 0, &mqc_states[90], &mqc_states[84]}, + {0x0005, 1, &mqc_states[91], &mqc_states[85]}, + {0x0001, 0, &mqc_states[90], &mqc_states[86]}, + {0x0001, 1, &mqc_states[91], &mqc_states[87]}, + {0x5601, 0, &mqc_states[92], &mqc_states[92]}, + {0x5601, 1, &mqc_states[93], &mqc_states[93]}, +}; + +/* +========================================================== + local functions +========================================================== +*/ + +static void mqc_byteout(opj_mqc_t *mqc) { + if (*mqc->bp == 0xff) { + mqc->bp++; + *mqc->bp = mqc->c >> 20; + mqc->c &= 0xfffff; + mqc->ct = 7; + } else { + if ((mqc->c & 0x8000000) == 0) { /* ((mqc->c&0x8000000)==0) CHANGE */ + mqc->bp++; + *mqc->bp = mqc->c >> 19; + mqc->c &= 0x7ffff; + mqc->ct = 8; + } else { + (*mqc->bp)++; + if (*mqc->bp == 0xff) { + mqc->c &= 0x7ffffff; + mqc->bp++; + *mqc->bp = mqc->c >> 20; + mqc->c &= 0xfffff; + mqc->ct = 7; + } else { + mqc->bp++; + *mqc->bp = mqc->c >> 19; + mqc->c &= 0x7ffff; + mqc->ct = 8; + } + } + } +} + +static void mqc_renorme(opj_mqc_t *mqc) { + do { + mqc->a <<= 1; + mqc->c <<= 1; + mqc->ct--; + if (mqc->ct == 0) { + mqc_byteout(mqc); + } + } while ((mqc->a & 0x8000) == 0); +} + +static void mqc_codemps(opj_mqc_t *mqc) { + mqc->a -= (*mqc->curctx)->qeval; + if ((mqc->a & 0x8000) == 0) { + if (mqc->a < (*mqc->curctx)->qeval) { + mqc->a = (*mqc->curctx)->qeval; + } else { + mqc->c += (*mqc->curctx)->qeval; + } + *mqc->curctx = (*mqc->curctx)->nmps; + mqc_renorme(mqc); + } else { + mqc->c += (*mqc->curctx)->qeval; + } +} + +static void mqc_codelps(opj_mqc_t *mqc) { + mqc->a -= (*mqc->curctx)->qeval; + if (mqc->a < (*mqc->curctx)->qeval) { + mqc->c += (*mqc->curctx)->qeval; + } else { + mqc->a = (*mqc->curctx)->qeval; + } + *mqc->curctx = (*mqc->curctx)->nlps; + mqc_renorme(mqc); +} + +static void mqc_setbits(opj_mqc_t *mqc) { + unsigned int tempc = mqc->c + mqc->a; + mqc->c |= 0xffff; + if (mqc->c >= tempc) { + mqc->c -= 0x8000; + } +} + +static INLINE int mqc_mpsexchange(opj_mqc_t *const mqc) { + int d; + if (mqc->a < (*mqc->curctx)->qeval) { + d = 1 - (*mqc->curctx)->mps; + *mqc->curctx = (*mqc->curctx)->nlps; + } else { + d = (*mqc->curctx)->mps; + *mqc->curctx = (*mqc->curctx)->nmps; + } + + return d; +} + +static INLINE int mqc_lpsexchange(opj_mqc_t *const mqc) { + int d; + if (mqc->a < (*mqc->curctx)->qeval) { + mqc->a = (*mqc->curctx)->qeval; + d = (*mqc->curctx)->mps; + *mqc->curctx = (*mqc->curctx)->nmps; + } else { + mqc->a = (*mqc->curctx)->qeval; + d = 1 - (*mqc->curctx)->mps; + *mqc->curctx = (*mqc->curctx)->nlps; + } + + return d; +} + +#ifdef MQC_PERF_OPT +static INLINE void mqc_bytein(opj_mqc_t *const mqc) { + unsigned int i = *((unsigned int *) mqc->bp); + mqc->c += i & 0xffff00; + mqc->ct = i & 0x0f; + mqc->bp += (i >> 2) & 0x04; +} +#else +static void mqc_bytein(opj_mqc_t *const mqc) { + if (mqc->bp != mqc->end) { + unsigned int c; + if (mqc->bp + 1 != mqc->end) { + c = *(mqc->bp + 1); + } else { + c = 0xff; + } + if (*mqc->bp == 0xff) { + if (c > 0x8f) { + mqc->c += 0xff00; + mqc->ct = 8; + } else { + mqc->bp++; + mqc->c += c << 9; + mqc->ct = 7; + } + } else { + mqc->bp++; + mqc->c += c << 8; + mqc->ct = 8; + } + } else { + mqc->c += 0xff00; + mqc->ct = 8; + } +} +#endif + +static INLINE void mqc_renormd(opj_mqc_t *const mqc) { + do { + if (mqc->ct == 0) { + mqc_bytein(mqc); + } + mqc->a <<= 1; + mqc->c <<= 1; + mqc->ct--; + } while (mqc->a < 0x8000); +} + +/* +========================================================== + MQ-Coder interface +========================================================== +*/ + +opj_mqc_t* mqc_create(void) { + opj_mqc_t *mqc = (opj_mqc_t*)opj_malloc(sizeof(opj_mqc_t)); +#ifdef MQC_PERF_OPT + mqc->buffer = NULL; +#endif + return mqc; +} + +void mqc_destroy(opj_mqc_t *mqc) { + if(mqc) { +#ifdef MQC_PERF_OPT + if (mqc->buffer) { + opj_free(mqc->buffer); + } +#endif + opj_free(mqc); + } +} + +int mqc_numbytes(opj_mqc_t *mqc) { + return mqc->bp - mqc->start; +} + +void mqc_init_enc(opj_mqc_t *mqc, unsigned char *bp) { + mqc_setcurctx(mqc, 0); + mqc->a = 0x8000; + mqc->c = 0; + mqc->bp = bp - 1; + mqc->ct = 12; + if (*mqc->bp == 0xff) { + mqc->ct = 13; + } + mqc->start = bp; +} + +void mqc_encode(opj_mqc_t *mqc, int d) { + if ((*mqc->curctx)->mps == d) { + mqc_codemps(mqc); + } else { + mqc_codelps(mqc); + } +} + +void mqc_flush(opj_mqc_t *mqc) { + mqc_setbits(mqc); + mqc->c <<= mqc->ct; + mqc_byteout(mqc); + mqc->c <<= mqc->ct; + mqc_byteout(mqc); + + if (*mqc->bp != 0xff) { + mqc->bp++; + } +} + +void mqc_bypass_init_enc(opj_mqc_t *mqc) { + mqc->c = 0; + mqc->ct = 8; + /*if (*mqc->bp == 0xff) { + mqc->ct = 7; + } */ +} + +void mqc_bypass_enc(opj_mqc_t *mqc, int d) { + mqc->ct--; + mqc->c = mqc->c + (d << mqc->ct); + if (mqc->ct == 0) { + mqc->bp++; + *mqc->bp = mqc->c; + mqc->ct = 8; + if (*mqc->bp == 0xff) { + mqc->ct = 7; + } + mqc->c = 0; + } +} + +int mqc_bypass_flush_enc(opj_mqc_t *mqc) { + unsigned char bit_padding; + + bit_padding = 0; + + if (mqc->ct != 0) { + while (mqc->ct > 0) { + mqc->ct--; + mqc->c += bit_padding << mqc->ct; + bit_padding = (bit_padding + 1) & 0x01; + } + mqc->bp++; + *mqc->bp = mqc->c; + mqc->ct = 8; + mqc->c = 0; + } + + return 1; +} + +void mqc_reset_enc(opj_mqc_t *mqc) { + mqc_resetstates(mqc); + mqc_setstate(mqc, T1_CTXNO_UNI, 0, 46); + mqc_setstate(mqc, T1_CTXNO_AGG, 0, 3); + mqc_setstate(mqc, T1_CTXNO_ZC, 0, 4); +} + +int mqc_restart_enc(opj_mqc_t *mqc) { + int correction = 1; + + /* */ + int n = 27 - 15 - mqc->ct; + mqc->c <<= mqc->ct; + while (n > 0) { + mqc_byteout(mqc); + n -= mqc->ct; + mqc->c <<= mqc->ct; + } + mqc_byteout(mqc); + + return correction; +} + +void mqc_restart_init_enc(opj_mqc_t *mqc) { + /* */ + mqc_setcurctx(mqc, 0); + mqc->a = 0x8000; + mqc->c = 0; + mqc->ct = 12; + mqc->bp--; + if (*mqc->bp == 0xff) { + mqc->ct = 13; + } +} + +void mqc_erterm_enc(opj_mqc_t *mqc) { + int k = 11 - mqc->ct + 1; + + while (k > 0) { + mqc->c <<= mqc->ct; + mqc->ct = 0; + mqc_byteout(mqc); + k -= mqc->ct; + } + + if (*mqc->bp != 0xff) { + mqc_byteout(mqc); + } +} + +void mqc_segmark_enc(opj_mqc_t *mqc) { + int i; + mqc_setcurctx(mqc, 18); + + for (i = 1; i < 5; i++) { + mqc_encode(mqc, i % 2); + } +} + +void mqc_init_dec(opj_mqc_t *mqc, unsigned char *bp, int len) { + mqc_setcurctx(mqc, 0); + mqc->start = bp; + mqc->end = bp + len; + mqc->bp = bp; + if (len==0) mqc->c = 0xff << 16; + else mqc->c = *mqc->bp << 16; + +#ifdef MQC_PERF_OPT + { + unsigned int c; + unsigned int *ip; + unsigned char *end = mqc->end - 1; + mqc->buffer = opj_realloc(mqc->buffer, (2 * len + 1) * sizeof(unsigned int)); + ip = (unsigned int *) mqc->buffer; + + while (bp != end) { + c = *(bp + 1); + if (*bp == 0xff) { + if (c > 0x8f) { + *ip = 0x0000ff18; + } else { + bp++; + *ip = 0x00000017 | (c << 9); + } + } else { + bp++; + *ip = 0x00000018 | (c << 8); + } + ip++; + } + + /* Handle last byte of data */ + c = 0xff; + if (*bp == 0xff) { + *ip = 0x0000ff18; + } else { + bp++; + *ip = 0x00000018 | (c << 8); + } + ip++; + + *ip = 0x0000ff08; + mqc->bp = mqc->buffer; + } +#endif + mqc_bytein(mqc); + mqc->c <<= 7; + mqc->ct -= 7; + mqc->a = 0x8000; +} + +int mqc_decode(opj_mqc_t *const mqc) { + int d; + mqc->a -= (*mqc->curctx)->qeval; + if ((mqc->c >> 16) < (*mqc->curctx)->qeval) { + d = mqc_lpsexchange(mqc); + mqc_renormd(mqc); + } else { + mqc->c -= (*mqc->curctx)->qeval << 16; + if ((mqc->a & 0x8000) == 0) { + d = mqc_mpsexchange(mqc); + mqc_renormd(mqc); + } else { + d = (*mqc->curctx)->mps; + } + } + + return d; +} + +void mqc_resetstates(opj_mqc_t *mqc) { + int i; + for (i = 0; i < MQC_NUMCTXS; i++) { + mqc->ctxs[i] = mqc_states; + } +} + +void mqc_setstate(opj_mqc_t *mqc, int ctxno, int msb, int prob) { + mqc->ctxs[ctxno] = &mqc_states[msb + (prob << 1)]; +} + + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/mqc.h b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/mqc.h new file mode 100644 index 0000000..d00cd10 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/mqc.h @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MQC_H +#define __MQC_H +/** +@file mqc.h +@brief Implementation of an MQ-Coder (MQC) + +The functions in MQC.C have for goal to realize the MQ-coder operations. The functions +in MQC.C are used by some function in T1.C. +*/ + +/** @defgroup MQC MQC - Implementation of an MQ-Coder */ +/*@{*/ + +/** +This struct defines the state of a context. +*/ +typedef struct opj_mqc_state { + /** the probability of the Least Probable Symbol (0.75->0x8000, 1.5->0xffff) */ + unsigned int qeval; + /** the Most Probable Symbol (0 or 1) */ + int mps; + /** next state if the next encoded symbol is the MPS */ + struct opj_mqc_state *nmps; + /** next state if the next encoded symbol is the LPS */ + struct opj_mqc_state *nlps; +} opj_mqc_state_t; + +#define MQC_NUMCTXS 19 + +/** +MQ coder +*/ +typedef struct opj_mqc { + unsigned int c; + unsigned int a; + unsigned int ct; + unsigned char *bp; + unsigned char *start; + unsigned char *end; + opj_mqc_state_t *ctxs[MQC_NUMCTXS]; + opj_mqc_state_t **curctx; +#ifdef MQC_PERF_OPT + unsigned char *buffer; +#endif +} opj_mqc_t; + +/** @name Exported functions */ +/*@{*/ +/* ----------------------------------------------------------------------- */ +/** +Create a new MQC handle +@return Returns a new MQC handle if successful, returns NULL otherwise +*/ +opj_mqc_t* mqc_create(void); +/** +Destroy a previously created MQC handle +@param mqc MQC handle to destroy +*/ +void mqc_destroy(opj_mqc_t *mqc); +/** +Return the number of bytes written/read since initialisation +@param mqc MQC handle +@return Returns the number of bytes already encoded +*/ +int mqc_numbytes(opj_mqc_t *mqc); +/** +Reset the states of all the context of the coder/decoder +(each context is set to a state where 0 and 1 are more or less equiprobable) +@param mqc MQC handle +*/ +void mqc_resetstates(opj_mqc_t *mqc); +/** +Set the state of a particular context +@param mqc MQC handle +@param ctxno Number that identifies the context +@param msb The MSB of the new state of the context +@param prob Number that identifies the probability of the symbols for the new state of the context +*/ +void mqc_setstate(opj_mqc_t *mqc, int ctxno, int msb, int prob); +/** +Initialize the encoder +@param mqc MQC handle +@param bp Pointer to the start of the buffer where the bytes will be written +*/ +void mqc_init_enc(opj_mqc_t *mqc, unsigned char *bp); +/** +Set the current context used for coding/decoding +@param mqc MQC handle +@param ctxno Number that identifies the context +*/ +#define mqc_setcurctx(mqc, ctxno) (mqc)->curctx = &(mqc)->ctxs[(int)(ctxno)] +/** +Encode a symbol using the MQ-coder +@param mqc MQC handle +@param d The symbol to be encoded (0 or 1) +*/ +void mqc_encode(opj_mqc_t *mqc, int d); +/** +Flush the encoder, so that all remaining data is written +@param mqc MQC handle +*/ +void mqc_flush(opj_mqc_t *mqc); +/** +BYPASS mode switch, initialization operation. +JPEG 2000 p 505. +

Not fully implemented and tested !!

+@param mqc MQC handle +*/ +void mqc_bypass_init_enc(opj_mqc_t *mqc); +/** +BYPASS mode switch, coding operation. +JPEG 2000 p 505. +

Not fully implemented and tested !!

+@param mqc MQC handle +@param d The symbol to be encoded (0 or 1) +*/ +void mqc_bypass_enc(opj_mqc_t *mqc, int d); +/** +BYPASS mode switch, flush operation +

Not fully implemented and tested !!

+@param mqc MQC handle +@return Returns 1 (always) +*/ +int mqc_bypass_flush_enc(opj_mqc_t *mqc); +/** +RESET mode switch +@param mqc MQC handle +*/ +void mqc_reset_enc(opj_mqc_t *mqc); +/** +RESTART mode switch (TERMALL) +@param mqc MQC handle +@return Returns 1 (always) +*/ +int mqc_restart_enc(opj_mqc_t *mqc); +/** +RESTART mode switch (TERMALL) reinitialisation +@param mqc MQC handle +*/ +void mqc_restart_init_enc(opj_mqc_t *mqc); +/** +ERTERM mode switch (PTERM) +@param mqc MQC handle +*/ +void mqc_erterm_enc(opj_mqc_t *mqc); +/** +SEGMARK mode switch (SEGSYM) +@param mqc MQC handle +*/ +void mqc_segmark_enc(opj_mqc_t *mqc); +/** +Initialize the decoder +@param mqc MQC handle +@param bp Pointer to the start of the buffer from which the bytes will be read +@param len Length of the input buffer +*/ +void mqc_init_dec(opj_mqc_t *mqc, unsigned char *bp, int len); +/** +Decode a symbol +@param mqc MQC handle +@return Returns the decoded symbol (0 or 1) +*/ +int mqc_decode(opj_mqc_t *const mqc); +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __MQC_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/openjpeg.c b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/openjpeg.c new file mode 100644 index 0000000..6722b33 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/openjpeg.c @@ -0,0 +1,337 @@ +/* + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef _WIN32 +#include +#endif /* _WIN32 */ + +#include "opj_config.h" +#include "opj_includes.h" + +/* ---------------------------------------------------------------------- */ +#ifdef _WIN32 +#ifndef OPJ_STATIC +BOOL APIENTRY +DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { + switch (ul_reason_for_call) { + case DLL_PROCESS_ATTACH : + break; + case DLL_PROCESS_DETACH : + break; + case DLL_THREAD_ATTACH : + case DLL_THREAD_DETACH : + break; + } + + return TRUE; +} +#endif /* OPJ_STATIC */ +#endif /* _WIN32 */ + +/* ---------------------------------------------------------------------- */ + + +const char* OPJ_CALLCONV opj_version(void) { + return PACKAGE_VERSION; +} + +opj_dinfo_t* OPJ_CALLCONV opj_create_decompress(OPJ_CODEC_FORMAT format) { + opj_dinfo_t *dinfo = (opj_dinfo_t*)opj_calloc(1, sizeof(opj_dinfo_t)); + if(!dinfo) return NULL; + dinfo->is_decompressor = true; + switch(format) { + case CODEC_J2K: + case CODEC_JPT: + /* get a J2K decoder handle */ + dinfo->j2k_handle = (void*)j2k_create_decompress((opj_common_ptr)dinfo); + if(!dinfo->j2k_handle) { + opj_free(dinfo); + return NULL; + } + break; + case CODEC_JP2: + /* get a JP2 decoder handle */ + dinfo->jp2_handle = (void*)jp2_create_decompress((opj_common_ptr)dinfo); + if(!dinfo->jp2_handle) { + opj_free(dinfo); + return NULL; + } + break; + case CODEC_UNKNOWN: + default: + opj_free(dinfo); + return NULL; + } + + dinfo->codec_format = format; + + return dinfo; +} + +void OPJ_CALLCONV opj_destroy_decompress(opj_dinfo_t *dinfo) { + if(dinfo) { + /* destroy the codec */ + switch(dinfo->codec_format) { + case CODEC_J2K: + case CODEC_JPT: + j2k_destroy_decompress((opj_j2k_t*)dinfo->j2k_handle); + break; + case CODEC_JP2: + jp2_destroy_decompress((opj_jp2_t*)dinfo->jp2_handle); + break; + case CODEC_UNKNOWN: + default: + break; + } + /* destroy the decompressor */ + opj_free(dinfo); + } +} + +void OPJ_CALLCONV opj_set_default_decoder_parameters(opj_dparameters_t *parameters) { + if(parameters) { + memset(parameters, 0, sizeof(opj_dparameters_t)); + /* default decoding parameters */ + parameters->cp_layer = 0; + parameters->cp_reduce = 0; + parameters->cp_limit_decoding = NO_LIMITATION; + + parameters->decod_format = -1; + parameters->cod_format = -1; +/* UniPG>> */ +#ifdef USE_JPWL + parameters->jpwl_correct = false; + parameters->jpwl_exp_comps = JPWL_EXPECTED_COMPONENTS; + parameters->jpwl_max_tiles = JPWL_MAXIMUM_TILES; +#endif /* USE_JPWL */ +/* <codec_format) { + case CODEC_J2K: + case CODEC_JPT: + j2k_setup_decoder((opj_j2k_t*)dinfo->j2k_handle, parameters); + break; + case CODEC_JP2: + jp2_setup_decoder((opj_jp2_t*)dinfo->jp2_handle, parameters); + break; + case CODEC_UNKNOWN: + default: + break; + } + } +} + +opj_image_t* OPJ_CALLCONV opj_decode(opj_dinfo_t *dinfo, opj_cio_t *cio) { + return opj_decode_with_info(dinfo, cio, NULL); +} + +opj_image_t* OPJ_CALLCONV opj_decode_with_info(opj_dinfo_t *dinfo, opj_cio_t *cio, opj_codestream_info_t *cstr_info) { + if(dinfo && cio) { + switch(dinfo->codec_format) { + case CODEC_J2K: + return j2k_decode((opj_j2k_t*)dinfo->j2k_handle, cio, cstr_info); + case CODEC_JPT: + return j2k_decode_jpt_stream((opj_j2k_t*)dinfo->j2k_handle, cio, cstr_info); + case CODEC_JP2: + return jp2_decode((opj_jp2_t*)dinfo->jp2_handle, cio, cstr_info); + case CODEC_UNKNOWN: + default: + break; + } + } + return NULL; +} + +opj_cinfo_t* OPJ_CALLCONV opj_create_compress(OPJ_CODEC_FORMAT format) { + opj_cinfo_t *cinfo = (opj_cinfo_t*)opj_calloc(1, sizeof(opj_cinfo_t)); + if(!cinfo) return NULL; + cinfo->is_decompressor = false; + switch(format) { + case CODEC_J2K: + /* get a J2K coder handle */ + cinfo->j2k_handle = (void*)j2k_create_compress((opj_common_ptr)cinfo); + if(!cinfo->j2k_handle) { + opj_free(cinfo); + return NULL; + } + break; + case CODEC_JP2: + /* get a JP2 coder handle */ + cinfo->jp2_handle = (void*)jp2_create_compress((opj_common_ptr)cinfo); + if(!cinfo->jp2_handle) { + opj_free(cinfo); + return NULL; + } + break; + case CODEC_JPT: + case CODEC_UNKNOWN: + default: + opj_free(cinfo); + return NULL; + } + + cinfo->codec_format = format; + + return cinfo; +} + +void OPJ_CALLCONV opj_destroy_compress(opj_cinfo_t *cinfo) { + if(cinfo) { + /* destroy the codec */ + switch(cinfo->codec_format) { + case CODEC_J2K: + j2k_destroy_compress((opj_j2k_t*)cinfo->j2k_handle); + break; + case CODEC_JP2: + jp2_destroy_compress((opj_jp2_t*)cinfo->jp2_handle); + break; + case CODEC_JPT: + case CODEC_UNKNOWN: + default: + break; + } + /* destroy the decompressor */ + opj_free(cinfo); + } +} + +void OPJ_CALLCONV opj_set_default_encoder_parameters(opj_cparameters_t *parameters) { + if(parameters) { + memset(parameters, 0, sizeof(opj_cparameters_t)); + /* default coding parameters */ + parameters->cp_cinema = OFF; + parameters->max_comp_size = 0; + parameters->numresolution = 6; + parameters->cp_rsiz = STD_RSIZ; + parameters->cblockw_init = 64; + parameters->cblockh_init = 64; + parameters->prog_order = LRCP; + parameters->roi_compno = -1; /* no ROI */ + parameters->subsampling_dx = 1; + parameters->subsampling_dy = 1; + parameters->tp_on = 0; + parameters->decod_format = -1; + parameters->cod_format = -1; + parameters->tcp_rates[0] = 0; + parameters->tcp_numlayers = 0; + parameters->cp_disto_alloc = 0; + parameters->cp_fixed_alloc = 0; + parameters->cp_fixed_quality = 0; + +/* UniPG>> */ +#ifdef USE_JPWL + parameters->jpwl_epc_on = false; + parameters->jpwl_hprot_MH = -1; /* -1 means unassigned */ + { + int i; + for (i = 0; i < JPWL_MAX_NO_TILESPECS; i++) { + parameters->jpwl_hprot_TPH_tileno[i] = -1; /* unassigned */ + parameters->jpwl_hprot_TPH[i] = 0; /* absent */ + } + }; + { + int i; + for (i = 0; i < JPWL_MAX_NO_PACKSPECS; i++) { + parameters->jpwl_pprot_tileno[i] = -1; /* unassigned */ + parameters->jpwl_pprot_packno[i] = -1; /* unassigned */ + parameters->jpwl_pprot[i] = 0; /* absent */ + } + }; + parameters->jpwl_sens_size = 0; /* 0 means no ESD */ + parameters->jpwl_sens_addr = 0; /* 0 means auto */ + parameters->jpwl_sens_range = 0; /* 0 means packet */ + parameters->jpwl_sens_MH = -1; /* -1 means unassigned */ + { + int i; + for (i = 0; i < JPWL_MAX_NO_TILESPECS; i++) { + parameters->jpwl_sens_TPH_tileno[i] = -1; /* unassigned */ + parameters->jpwl_sens_TPH[i] = -1; /* absent */ + } + }; +#endif /* USE_JPWL */ +/* <codec_format) { + case CODEC_J2K: + j2k_setup_encoder((opj_j2k_t*)cinfo->j2k_handle, parameters, image); + break; + case CODEC_JP2: + jp2_setup_encoder((opj_jp2_t*)cinfo->jp2_handle, parameters, image); + break; + case CODEC_JPT: + case CODEC_UNKNOWN: + default: + break; + } + } +} + +bool OPJ_CALLCONV opj_encode(opj_cinfo_t *cinfo, opj_cio_t *cio, opj_image_t *image, char *index) { + if (index != NULL) + opj_event_msg((opj_common_ptr)cinfo, EVT_WARNING, "Set index to NULL when calling the opj_encode function.\n" + "To extract the index, use the opj_encode_with_info() function.\n" + "No index will be generated during this encoding\n"); + return opj_encode_with_info(cinfo, cio, image, NULL); +} + +bool OPJ_CALLCONV opj_encode_with_info(opj_cinfo_t *cinfo, opj_cio_t *cio, opj_image_t *image, opj_codestream_info_t *cstr_info) { + if(cinfo && cio && image) { + switch(cinfo->codec_format) { + case CODEC_J2K: + return j2k_encode((opj_j2k_t*)cinfo->j2k_handle, cio, image, cstr_info); + case CODEC_JP2: + return jp2_encode((opj_jp2_t*)cinfo->jp2_handle, cio, image, cstr_info); + case CODEC_JPT: + case CODEC_UNKNOWN: + default: + break; + } + } + return false; +} + +void OPJ_CALLCONV opj_destroy_cstr_info(opj_codestream_info_t *cstr_info) { + if (cstr_info) { + int tileno; + for (tileno = 0; tileno < cstr_info->tw * cstr_info->th; tileno++) { + opj_tile_info_t *tile_info = &cstr_info->tile[tileno]; + opj_free(tile_info->thresh); + opj_free(tile_info->packet); + opj_free(tile_info->tp); + } + opj_free(cstr_info->tile); + opj_free(cstr_info->marker); + opj_free(cstr_info->numdecompos); + } +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/openjpeg.h b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/openjpeg.h new file mode 100644 index 0000000..6b17c64 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/openjpeg.h @@ -0,0 +1,919 @@ + /* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2006-2007, Parvatha Elangovan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef OPENJPEG_H +#define OPENJPEG_H + + +/* +========================================================== + Compiler directives +========================================================== +*/ + +#if defined(OPJ_STATIC) || !defined(_WIN32) +#if __GNUC__ >= 4 +#define OPJ_API __attribute__ ((visibility ("default"))) +#else +#define OPJ_API +#endif +#define OPJ_CALLCONV +#else +#define OPJ_CALLCONV __stdcall +/* +The following ifdef block is the standard way of creating macros which make exporting +from a DLL simpler. All files within this DLL are compiled with the OPJ_EXPORTS +symbol defined on the command line. this symbol should not be defined on any project +that uses this DLL. This way any other project whose source files include this file see +OPJ_API functions as being imported from a DLL, wheras this DLL sees symbols +defined with this macro as being exported. +*/ +#if defined(OPJ_EXPORTS) || defined(DLL_EXPORT) +#define OPJ_API __declspec(dllexport) +#else +#define OPJ_API __declspec(dllimport) +#endif /* OPJ_EXPORTS */ +#endif /* !OPJ_STATIC || !_WIN32 */ + +#ifndef __cplusplus +#if defined(HAVE_STDBOOL_H) +/* +The C language implementation does correctly provide the standard header +file "stdbool.h". + */ +#include +#else +/* +The C language implementation does not provide the standard header file +"stdbool.h" as required by ISO/IEC 9899:1999. Try to compensate for this +braindamage below. +*/ +#if !defined(bool) +#define bool int +#endif +#if !defined(true) +#define true 1 +#endif +#if !defined(false) +#define false 0 +#endif +#endif +#endif /* __cplusplus */ + +/* +========================================================== + Useful constant definitions +========================================================== +*/ + +#define OPJ_PATH_LEN 4096 /**< Maximum allowed size for filenames */ + +#define J2K_MAXRLVLS 33 /**< Number of maximum resolution level authorized */ +#define J2K_MAXBANDS (3*J2K_MAXRLVLS-2) /**< Number of maximum sub-band linked to number of resolution level */ + +/* UniPG>> */ +#define JPWL_MAX_NO_TILESPECS 16 /**< Maximum number of tile parts expected by JPWL: increase at your will */ +#define JPWL_MAX_NO_PACKSPECS 16 /**< Maximum number of packet parts expected by JPWL: increase at your will */ +#define JPWL_MAX_NO_MARKERS 512 /**< Maximum number of JPWL markers: increase at your will */ +#define JPWL_PRIVATEINDEX_NAME "jpwl_index_privatefilename" /**< index file name used when JPWL is on */ +#define JPWL_EXPECTED_COMPONENTS 3 /**< Expect this number of components, so you'll find better the first EPB */ +#define JPWL_MAXIMUM_TILES 8192 /**< Expect this maximum number of tiles, to avoid some crashes */ +#define JPWL_MAXIMUM_HAMMING 2 /**< Expect this maximum number of bit errors in marker id's */ +#define JPWL_MAXIMUM_EPB_ROOM 65450 /**< Expect this maximum number of bytes for composition of EPBs */ +/* < +
  • Error messages +
  • Warning messages +
  • Debugging messages + +*/ +typedef struct opj_event_mgr { + /** Error message callback if available, NULL otherwise */ + opj_msg_callback error_handler; + /** Warning message callback if available, NULL otherwise */ + opj_msg_callback warning_handler; + /** Debug message callback if available, NULL otherwise */ + opj_msg_callback info_handler; +} opj_event_mgr_t; + + +/* +========================================================== + codec typedef definitions +========================================================== +*/ + +/** +Progression order changes +*/ +typedef struct opj_poc { + /** Resolution num start, Component num start, given by POC */ + int resno0, compno0; + /** Layer num end,Resolution num end, Component num end, given by POC */ + int layno1, resno1, compno1; + /** Layer num start,Precinct num start, Precinct num end */ + int layno0, precno0, precno1; + /** Progression order enum*/ + OPJ_PROG_ORDER prg1,prg; + /** Progression order string*/ + char progorder[5]; + /** Tile number */ + int tile; + /** Start and end values for Tile width and height*/ + int tx0,tx1,ty0,ty1; + /** Start value, initialised in pi_initialise_encode*/ + int layS, resS, compS, prcS; + /** End value, initialised in pi_initialise_encode */ + int layE, resE, compE, prcE; + /** Start and end values of Tile width and height, initialised in pi_initialise_encode*/ + int txS,txE,tyS,tyE,dx,dy; + /** Temporary values for Tile parts, initialised in pi_create_encode */ + int lay_t, res_t, comp_t, prc_t,tx0_t,ty0_t; +} opj_poc_t; + +/** +Compression parameters +*/ +typedef struct opj_cparameters { + /** size of tile: tile_size_on = false (not in argument) or = true (in argument) */ + bool tile_size_on; + /** XTOsiz */ + int cp_tx0; + /** YTOsiz */ + int cp_ty0; + /** XTsiz */ + int cp_tdx; + /** YTsiz */ + int cp_tdy; + /** allocation by rate/distortion */ + int cp_disto_alloc; + /** allocation by fixed layer */ + int cp_fixed_alloc; + /** add fixed_quality */ + int cp_fixed_quality; + /** fixed layer */ + int *cp_matrice; + /** comment for coding */ + char *cp_comment; + /** csty : coding style */ + int csty; + /** progression order (default LRCP) */ + OPJ_PROG_ORDER prog_order; + /** progression order changes */ + opj_poc_t POC[32]; + /** number of progression order changes (POC), default to 0 */ + int numpocs; + /** number of layers */ + int tcp_numlayers; + /** rates of layers */ + float tcp_rates[100]; + /** different psnr for successive layers */ + float tcp_distoratio[100]; + /** number of resolutions */ + int numresolution; + /** initial code block width, default to 64 */ + int cblockw_init; + /** initial code block height, default to 64 */ + int cblockh_init; + /** mode switch (cblk_style) */ + int mode; + /** 1 : use the irreversible DWT 9-7, 0 : use lossless compression (default) */ + int irreversible; + /** region of interest: affected component in [0..3], -1 means no ROI */ + int roi_compno; + /** region of interest: upshift value */ + int roi_shift; + /* number of precinct size specifications */ + int res_spec; + /** initial precinct width */ + int prcw_init[J2K_MAXRLVLS]; + /** initial precinct height */ + int prch_init[J2K_MAXRLVLS]; + + /**@name command line encoder parameters (not used inside the library) */ + /*@{*/ + /** input file name */ + char infile[OPJ_PATH_LEN]; + /** output file name */ + char outfile[OPJ_PATH_LEN]; + /** DEPRECATED. Index generation is now handeld with the opj_encode_with_info() function. Set to NULL */ + int index_on; + /** DEPRECATED. Index generation is now handeld with the opj_encode_with_info() function. Set to NULL */ + char index[OPJ_PATH_LEN]; + /** subimage encoding: origin image offset in x direction */ + int image_offset_x0; + /** subimage encoding: origin image offset in y direction */ + int image_offset_y0; + /** subsampling value for dx */ + int subsampling_dx; + /** subsampling value for dy */ + int subsampling_dy; + /** input file format 0: PGX, 1: PxM, 2: BMP 3:TIF*/ + int decod_format; + /** output file format 0: J2K, 1: JP2, 2: JPT */ + int cod_format; + /*@}*/ + +/* UniPG>> */ + /**@name JPWL encoding parameters */ + /*@{*/ + /** enables writing of EPC in MH, thus activating JPWL */ + bool jpwl_epc_on; + /** error protection method for MH (0,1,16,32,37-128) */ + int jpwl_hprot_MH; + /** tile number of header protection specification (>=0) */ + int jpwl_hprot_TPH_tileno[JPWL_MAX_NO_TILESPECS]; + /** error protection methods for TPHs (0,1,16,32,37-128) */ + int jpwl_hprot_TPH[JPWL_MAX_NO_TILESPECS]; + /** tile number of packet protection specification (>=0) */ + int jpwl_pprot_tileno[JPWL_MAX_NO_PACKSPECS]; + /** packet number of packet protection specification (>=0) */ + int jpwl_pprot_packno[JPWL_MAX_NO_PACKSPECS]; + /** error protection methods for packets (0,1,16,32,37-128) */ + int jpwl_pprot[JPWL_MAX_NO_PACKSPECS]; + /** enables writing of ESD, (0=no/1/2 bytes) */ + int jpwl_sens_size; + /** sensitivity addressing size (0=auto/2/4 bytes) */ + int jpwl_sens_addr; + /** sensitivity range (0-3) */ + int jpwl_sens_range; + /** sensitivity method for MH (-1=no,0-7) */ + int jpwl_sens_MH; + /** tile number of sensitivity specification (>=0) */ + int jpwl_sens_TPH_tileno[JPWL_MAX_NO_TILESPECS]; + /** sensitivity methods for TPHs (-1=no,0-7) */ + int jpwl_sens_TPH[JPWL_MAX_NO_TILESPECS]; + /*@}*/ +/* <> */ + /**@name JPWL decoding parameters */ + /*@{*/ + /** activates the JPWL correction capabilities */ + bool jpwl_correct; + /** expected number of components */ + int jpwl_exp_comps; + /** maximum number of tiles */ + int jpwl_max_tiles; + /*@}*/ +/* <> */ +/** +Marker structure +*/ +typedef struct opj_marker_info_t { + /** marker type */ + unsigned short int type; + /** position in codestream */ + int pos; + /** length, marker val included */ + int len; +} opj_marker_info_t; +/* <> */ + /** number of markers */ + int marknum; + /** list of markers */ + opj_marker_info_t *marker; + /** actual size of markers array */ + int maxmarknum; +/* <cp. +@param dinfo decompressor handle +@param parameters decompression parameters +*/ +OPJ_API void OPJ_CALLCONV opj_setup_decoder(opj_dinfo_t *dinfo, opj_dparameters_t *parameters); +/** +Decode an image from a JPEG-2000 codestream +@param dinfo decompressor handle +@param cio Input buffer stream +@return Returns a decoded image if successful, returns NULL otherwise +*/ +OPJ_API opj_image_t* OPJ_CALLCONV opj_decode(opj_dinfo_t *dinfo, opj_cio_t *cio); + +/** +Decode an image from a JPEG-2000 codestream and extract the codestream information +@param dinfo decompressor handle +@param cio Input buffer stream +@param cstr_info Codestream information structure if needed afterwards, NULL otherwise +@return Returns a decoded image if successful, returns NULL otherwise +*/ +OPJ_API opj_image_t* OPJ_CALLCONV opj_decode_with_info(opj_dinfo_t *dinfo, opj_cio_t *cio, opj_codestream_info_t *cstr_info); +/** +Creates a J2K/JP2 compression structure +@param format Coder to select +@return Returns a handle to a compressor if successful, returns NULL otherwise +*/ +OPJ_API opj_cinfo_t* OPJ_CALLCONV opj_create_compress(OPJ_CODEC_FORMAT format); +/** +Destroy a compressor handle +@param cinfo compressor handle to destroy +*/ +OPJ_API void OPJ_CALLCONV opj_destroy_compress(opj_cinfo_t *cinfo); +/** +Set encoding parameters to default values, that means : +
      +
    • Lossless +
    • 1 tile +
    • Size of precinct : 2^15 x 2^15 (means 1 precinct) +
    • Size of code-block : 64 x 64 +
    • Number of resolutions: 6 +
    • No SOP marker in the codestream +
    • No EPH marker in the codestream +
    • No sub-sampling in x or y direction +
    • No mode switch activated +
    • Progression order: LRCP +
    • No index file +
    • No ROI upshifted +
    • No offset of the origin of the image +
    • No offset of the origin of the tiles +
    • Reversible DWT 5-3 +
    +@param parameters Compression parameters +*/ +OPJ_API void OPJ_CALLCONV opj_set_default_encoder_parameters(opj_cparameters_t *parameters); +/** +Setup the encoder parameters using the current image and using user parameters. +@param cinfo Compressor handle +@param parameters Compression parameters +@param image Input filled image +*/ +OPJ_API void OPJ_CALLCONV opj_setup_encoder(opj_cinfo_t *cinfo, opj_cparameters_t *parameters, opj_image_t *image); +/** +Encode an image into a JPEG-2000 codestream +@param cinfo compressor handle +@param cio Output buffer stream +@param image Image to encode +@param index Depreacted -> Set to NULL. To extract index, used opj_encode_wci() +@return Returns true if successful, returns false otherwise +*/ +OPJ_API bool OPJ_CALLCONV opj_encode(opj_cinfo_t *cinfo, opj_cio_t *cio, opj_image_t *image, char *index); +/** +Encode an image into a JPEG-2000 codestream and extract the codestream information +@param cinfo compressor handle +@param cio Output buffer stream +@param image Image to encode +@param cstr_info Codestream information structure if needed afterwards, NULL otherwise +@return Returns true if successful, returns false otherwise +*/ +OPJ_API bool OPJ_CALLCONV opj_encode_with_info(opj_cinfo_t *cinfo, opj_cio_t *cio, opj_image_t *image, opj_codestream_info_t *cstr_info); +/** +Destroy Codestream information after compression or decompression +@param cstr_info Codestream information structure +*/ +OPJ_API void OPJ_CALLCONV opj_destroy_cstr_info(opj_codestream_info_t *cstr_info); + +#ifdef __cplusplus +} +#endif + +#endif /* OPENJPEG_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/opj_includes.h b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/opj_includes.h new file mode 100644 index 0000000..53739ab --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/opj_includes.h @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef OPJ_INCLUDES_H +#define OPJ_INCLUDES_H + +/* + ========================================================== + Standard includes used by the library + ========================================================== +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + ========================================================== + OpenJPEG interface + ========================================================== + */ +#include "openjpeg.h" + +/* + ========================================================== + OpenJPEG modules + ========================================================== +*/ + +/* Ignore GCC attributes if this is not GCC */ +#ifndef __GNUC__ + #define __attribute__(x) /* __attribute__(x) */ +#endif + +/* +The inline keyword is supported by C99 but not by C90. +Most compilers implement their own version of this keyword ... +*/ +#ifndef INLINE + #if defined(_MSC_VER) + #define INLINE __forceinline + #elif defined(__GNUC__) + #define INLINE __inline__ + #elif defined(__MWERKS__) + #define INLINE inline + #else + /* add other compilers here ... */ + #define INLINE + #endif /* defined() */ +#endif /* INLINE */ + +/* Are restricted pointers available? (C99) */ +#if (__STDC_VERSION__ != 199901L) + /* Not a C99 compiler */ + #ifdef __GNUC__ + #define restrict __restrict__ + #else + #define restrict /* restrict */ + #endif +#endif + +/* MSVC and Borland C do not have lrintf */ +#if defined(_MSC_VER) || defined(__BORLANDC__) +static INLINE long lrintf(float f){ +#ifdef _M_X64 + return (long)((f>0.0f) ? (f + 0.5f):(f -0.5f)); +#else + int i; + + _asm{ + fld f + fistp i + }; + + return i; +#endif +} +#endif + +#include "j2k_lib.h" +#include "opj_malloc.h" +#include "event.h" +#include "cio.h" + +#include "image.h" +#include "j2k.h" +#include "jp2.h" +#include "jpt.h" + +#include "mqc.h" +#include "raw.h" +#include "bio.h" +#include "tgt.h" +#include "pi.h" +#include "tcd.h" +#include "t1.h" +#include "dwt.h" +#include "t2.h" +#include "mct.h" +#include "int.h" +#include "fix.h" + +/* JPWL>> */ +#ifdef USE_JPWL +#include "../jpwl/jpwl.h" +#endif /* USE_JPWL */ +/* < + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __OPJ_MALLOC_H +#define __OPJ_MALLOC_H +/** +@file opj_malloc.h +@brief Internal functions + +The functions in opj_malloc.h are internal utilities used for memory management. +*/ + +/** @defgroup MISC MISC - Miscellaneous internal functions */ +/*@{*/ + +/** @name Exported functions */ +/*@{*/ +/* ----------------------------------------------------------------------- */ + +/** +Allocate an uninitialized memory block +@param size Bytes to allocate +@return Returns a void pointer to the allocated space, or NULL if there is insufficient memory available +*/ +#ifdef ALLOC_PERF_OPT +void * OPJ_CALLCONV opj_malloc(size_t size); +#else +#define opj_malloc(size) malloc(size) +#endif + +/** +Allocate a memory block with elements initialized to 0 +@param num Blocks to allocate +@param size Bytes per block to allocate +@return Returns a void pointer to the allocated space, or NULL if there is insufficient memory available +*/ +#ifdef ALLOC_PERF_OPT +void * OPJ_CALLCONV opj_calloc(size_t _NumOfElements, size_t _SizeOfElements); +#else +#define opj_calloc(num, size) calloc(num, size) +#endif + +/** +Allocate memory aligned to a 16 byte boundry +@param size Bytes to allocate +@return Returns a void pointer to the allocated space, or NULL if there is insufficient memory available +*/ +/* FIXME: These should be set with cmake tests, but we're currently not requiring use of cmake */ +#ifdef _WIN32 + /* Someone should tell the mingw people that their malloc.h ought to provide _mm_malloc() */ + #ifdef __GNUC__ + #include + #define HAVE_MM_MALLOC + #else /* MSVC, Intel C++ */ + #include + #ifdef _mm_malloc + #define HAVE_MM_MALLOC + #endif + #endif +#else /* Not _WIN32 */ + #if defined(__sun) + #define HAVE_MEMALIGN + /* Linux x86_64 and OSX always align allocations to 16 bytes */ + #elif !defined(__amd64__) && !defined(__APPLE__) + #define HAVE_MEMALIGN + #include + #endif +#endif + +#define opj_aligned_malloc(size) malloc(size) +#define opj_aligned_free(m) free(m) + +#ifdef HAVE_MM_MALLOC + #undef opj_aligned_malloc + #define opj_aligned_malloc(size) _mm_malloc(size, 16) + #undef opj_aligned_free + #define opj_aligned_free(m) _mm_free(m) +#endif + +#ifdef HAVE_MEMALIGN + extern void* memalign(size_t, size_t); + #undef opj_aligned_malloc + #define opj_aligned_malloc(size) memalign(16, (size)) + #undef opj_aligned_free + #define opj_aligned_free(m) free(m) +#endif + +#ifdef HAVE_POSIX_MEMALIGN + #undef opj_aligned_malloc + extern int posix_memalign(void**, size_t, size_t); + + static INLINE void* __attribute__ ((malloc)) opj_aligned_malloc(size_t size){ + void* mem = NULL; + posix_memalign(&mem, 16, size); + return mem; + } + #undef opj_aligned_free + #define opj_aligned_free(m) free(m) +#endif + +#ifdef ALLOC_PERF_OPT + #undef opj_aligned_malloc + #define opj_aligned_malloc(size) opj_malloc(size) + #undef opj_aligned_free + #define opj_aligned_free(m) opj_free(m) +#endif + +/** +Reallocate memory blocks. +@param m Pointer to previously allocated memory block +@param s New size in bytes +@return Returns a void pointer to the reallocated (and possibly moved) memory block +*/ +#ifdef ALLOC_PERF_OPT +void * OPJ_CALLCONV opj_realloc(void * m, size_t s); +#else +#define opj_realloc(m, s) realloc(m, s) +#endif + +/** +Deallocates or frees a memory block. +@param m Previously allocated memory block to be freed +*/ +#ifdef ALLOC_PERF_OPT +void OPJ_CALLCONV opj_free(void * m); +#else +#define opj_free(m) free(m) +#endif + +#ifdef __GNUC__ +#pragma GCC poison malloc calloc realloc free +#endif + +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __OPJ_MALLOC_H */ + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/pi.c b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/pi.c new file mode 100644 index 0000000..06e76af --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/pi.c @@ -0,0 +1,963 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2006-2007, Parvatha Elangovan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "opj_includes.h" + +/** @defgroup PI PI - Implementation of a packet iterator */ +/*@{*/ + +/** @name Local static functions */ +/*@{*/ + +/** +Get next packet in layer-resolution-component-precinct order. +@param pi packet iterator to modify +@return returns false if pi pointed to the last packet or else returns true +*/ +static bool pi_next_lrcp(opj_pi_iterator_t * pi); +/** +Get next packet in resolution-layer-component-precinct order. +@param pi packet iterator to modify +@return returns false if pi pointed to the last packet or else returns true +*/ +static bool pi_next_rlcp(opj_pi_iterator_t * pi); +/** +Get next packet in resolution-precinct-component-layer order. +@param pi packet iterator to modify +@return returns false if pi pointed to the last packet or else returns true +*/ +static bool pi_next_rpcl(opj_pi_iterator_t * pi); +/** +Get next packet in precinct-component-resolution-layer order. +@param pi packet iterator to modify +@return returns false if pi pointed to the last packet or else returns true +*/ +static bool pi_next_pcrl(opj_pi_iterator_t * pi); +/** +Get next packet in component-precinct-resolution-layer order. +@param pi packet iterator to modify +@return returns false if pi pointed to the last packet or else returns true +*/ +static bool pi_next_cprl(opj_pi_iterator_t * pi); + +/*@}*/ + +/*@}*/ + +/* +========================================================== + local functions +========================================================== +*/ + +static bool pi_next_lrcp(opj_pi_iterator_t * pi) { + opj_pi_comp_t *comp = NULL; + opj_pi_resolution_t *res = NULL; + long index = 0; + + if (!pi->first) { + comp = &pi->comps[pi->compno]; + res = &comp->resolutions[pi->resno]; + goto LABEL_SKIP; + } else { + pi->first = 0; + } + + for (pi->layno = pi->poc.layno0; pi->layno < pi->poc.layno1; pi->layno++) { + for (pi->resno = pi->poc.resno0; pi->resno < pi->poc.resno1; + pi->resno++) { + for (pi->compno = pi->poc.compno0; pi->compno < pi->poc.compno1; pi->compno++) { + comp = &pi->comps[pi->compno]; + if (pi->resno >= comp->numresolutions) { + continue; + } + res = &comp->resolutions[pi->resno]; + if (!pi->tp_on){ + pi->poc.precno1 = res->pw * res->ph; + } + for (pi->precno = pi->poc.precno0; pi->precno < pi->poc.precno1; pi->precno++) { + index = pi->layno * pi->step_l + pi->resno * pi->step_r + pi->compno * pi->step_c + pi->precno * pi->step_p; + if (!pi->include[index]) { + pi->include[index] = 1; + return true; + } +LABEL_SKIP:; + } + } + } + } + + return false; +} + +static bool pi_next_rlcp(opj_pi_iterator_t * pi) { + opj_pi_comp_t *comp = NULL; + opj_pi_resolution_t *res = NULL; + long index = 0; + + if (!pi->first) { + comp = &pi->comps[pi->compno]; + res = &comp->resolutions[pi->resno]; + goto LABEL_SKIP; + } else { + pi->first = 0; + } + + for (pi->resno = pi->poc.resno0; pi->resno < pi->poc.resno1; pi->resno++) { + for (pi->layno = pi->poc.layno0; pi->layno < pi->poc.layno1; pi->layno++) { + for (pi->compno = pi->poc.compno0; pi->compno < pi->poc.compno1; pi->compno++) { + comp = &pi->comps[pi->compno]; + if (pi->resno >= comp->numresolutions) { + continue; + } + res = &comp->resolutions[pi->resno]; + if(!pi->tp_on){ + pi->poc.precno1 = res->pw * res->ph; + } + for (pi->precno = pi->poc.precno0; pi->precno < pi->poc.precno1; pi->precno++) { + index = pi->layno * pi->step_l + pi->resno * pi->step_r + pi->compno * pi->step_c + pi->precno * pi->step_p; + if (!pi->include[index]) { + pi->include[index] = 1; + return true; + } +LABEL_SKIP:; + } + } + } + } + + return false; +} + +static bool pi_next_rpcl(opj_pi_iterator_t * pi) { + opj_pi_comp_t *comp = NULL; + opj_pi_resolution_t *res = NULL; + long index = 0; + + if (!pi->first) { + goto LABEL_SKIP; + } else { + int compno, resno; + pi->first = 0; + pi->dx = 0; + pi->dy = 0; + for (compno = 0; compno < pi->numcomps; compno++) { + comp = &pi->comps[compno]; + for (resno = 0; resno < comp->numresolutions; resno++) { + int dx, dy; + res = &comp->resolutions[resno]; + dx = comp->dx * (1 << (res->pdx + comp->numresolutions - 1 - resno)); + dy = comp->dy * (1 << (res->pdy + comp->numresolutions - 1 - resno)); + pi->dx = !pi->dx ? dx : int_min(pi->dx, dx); + pi->dy = !pi->dy ? dy : int_min(pi->dy, dy); + } + } + } +if (!pi->tp_on){ + pi->poc.ty0 = pi->ty0; + pi->poc.tx0 = pi->tx0; + pi->poc.ty1 = pi->ty1; + pi->poc.tx1 = pi->tx1; + } + for (pi->resno = pi->poc.resno0; pi->resno < pi->poc.resno1; pi->resno++) { + for (pi->y = pi->poc.ty0; pi->y < pi->poc.ty1; pi->y += pi->dy - (pi->y % pi->dy)) { + for (pi->x = pi->poc.tx0; pi->x < pi->poc.tx1; pi->x += pi->dx - (pi->x % pi->dx)) { + for (pi->compno = pi->poc.compno0; pi->compno < pi->poc.compno1; pi->compno++) { + int levelno; + int trx0, try0; + int trx1, try1; + int rpx, rpy; + int prci, prcj; + comp = &pi->comps[pi->compno]; + if (pi->resno >= comp->numresolutions) { + continue; + } + res = &comp->resolutions[pi->resno]; + levelno = comp->numresolutions - 1 - pi->resno; + trx0 = int_ceildiv(pi->tx0, comp->dx << levelno); + try0 = int_ceildiv(pi->ty0, comp->dy << levelno); + trx1 = int_ceildiv(pi->tx1, comp->dx << levelno); + try1 = int_ceildiv(pi->ty1, comp->dy << levelno); + rpx = res->pdx + levelno; + rpy = res->pdy + levelno; + if (!((pi->y % (comp->dy << rpy) == 0) || ((pi->y == pi->ty0) && ((try0 << levelno) % (1 << rpy))))){ + continue; + } + if (!((pi->x % (comp->dx << rpx) == 0) || ((pi->x == pi->tx0) && ((trx0 << levelno) % (1 << rpx))))){ + continue; + } + + if ((res->pw==0)||(res->ph==0)) continue; + + if ((trx0==trx1)||(try0==try1)) continue; + + prci = int_floordivpow2(int_ceildiv(pi->x, comp->dx << levelno), res->pdx) + - int_floordivpow2(trx0, res->pdx); + prcj = int_floordivpow2(int_ceildiv(pi->y, comp->dy << levelno), res->pdy) + - int_floordivpow2(try0, res->pdy); + pi->precno = prci + prcj * res->pw; + for (pi->layno = pi->poc.layno0; pi->layno < pi->poc.layno1; pi->layno++) { + index = pi->layno * pi->step_l + pi->resno * pi->step_r + pi->compno * pi->step_c + pi->precno * pi->step_p; + if (!pi->include[index]) { + pi->include[index] = 1; + return true; + } +LABEL_SKIP:; + } + } + } + } + } + + return false; +} + +static bool pi_next_pcrl(opj_pi_iterator_t * pi) { + opj_pi_comp_t *comp = NULL; + opj_pi_resolution_t *res = NULL; + long index = 0; + + if (!pi->first) { + comp = &pi->comps[pi->compno]; + goto LABEL_SKIP; + } else { + int compno, resno; + pi->first = 0; + pi->dx = 0; + pi->dy = 0; + for (compno = 0; compno < pi->numcomps; compno++) { + comp = &pi->comps[compno]; + for (resno = 0; resno < comp->numresolutions; resno++) { + int dx, dy; + res = &comp->resolutions[resno]; + dx = comp->dx * (1 << (res->pdx + comp->numresolutions - 1 - resno)); + dy = comp->dy * (1 << (res->pdy + comp->numresolutions - 1 - resno)); + pi->dx = !pi->dx ? dx : int_min(pi->dx, dx); + pi->dy = !pi->dy ? dy : int_min(pi->dy, dy); + } + } + } + if (!pi->tp_on){ + pi->poc.ty0 = pi->ty0; + pi->poc.tx0 = pi->tx0; + pi->poc.ty1 = pi->ty1; + pi->poc.tx1 = pi->tx1; + } + for (pi->y = pi->poc.ty0; pi->y < pi->poc.ty1; pi->y += pi->dy - (pi->y % pi->dy)) { + for (pi->x = pi->poc.tx0; pi->x < pi->poc.tx1; pi->x += pi->dx - (pi->x % pi->dx)) { + for (pi->compno = pi->poc.compno0; pi->compno < pi->poc.compno1; pi->compno++) { + comp = &pi->comps[pi->compno]; + for (pi->resno = pi->poc.resno0; pi->resno < int_min(pi->poc.resno1, comp->numresolutions); pi->resno++) { + int levelno; + int trx0, try0; + int trx1, try1; + int rpx, rpy; + int prci, prcj; + res = &comp->resolutions[pi->resno]; + levelno = comp->numresolutions - 1 - pi->resno; + trx0 = int_ceildiv(pi->tx0, comp->dx << levelno); + try0 = int_ceildiv(pi->ty0, comp->dy << levelno); + trx1 = int_ceildiv(pi->tx1, comp->dx << levelno); + try1 = int_ceildiv(pi->ty1, comp->dy << levelno); + rpx = res->pdx + levelno; + rpy = res->pdy + levelno; + if (!((pi->y % (comp->dy << rpy) == 0) || ((pi->y == pi->ty0) && ((try0 << levelno) % (1 << rpy))))){ + continue; + } + if (!((pi->x % (comp->dx << rpx) == 0) || ((pi->x == pi->tx0) && ((trx0 << levelno) % (1 << rpx))))){ + continue; + } + + if ((res->pw==0)||(res->ph==0)) continue; + + if ((trx0==trx1)||(try0==try1)) continue; + + prci = int_floordivpow2(int_ceildiv(pi->x, comp->dx << levelno), res->pdx) + - int_floordivpow2(trx0, res->pdx); + prcj = int_floordivpow2(int_ceildiv(pi->y, comp->dy << levelno), res->pdy) + - int_floordivpow2(try0, res->pdy); + pi->precno = prci + prcj * res->pw; + for (pi->layno = pi->poc.layno0; pi->layno < pi->poc.layno1; pi->layno++) { + index = pi->layno * pi->step_l + pi->resno * pi->step_r + pi->compno * pi->step_c + pi->precno * pi->step_p; + if (!pi->include[index]) { + pi->include[index] = 1; + return true; + } +LABEL_SKIP:; + } + } + } + } + } + + return false; +} + +static bool pi_next_cprl(opj_pi_iterator_t * pi) { + opj_pi_comp_t *comp = NULL; + opj_pi_resolution_t *res = NULL; + long index = 0; + + if (!pi->first) { + comp = &pi->comps[pi->compno]; + goto LABEL_SKIP; + } else { + pi->first = 0; + } + + for (pi->compno = pi->poc.compno0; pi->compno < pi->poc.compno1; pi->compno++) { + int resno; + comp = &pi->comps[pi->compno]; + pi->dx = 0; + pi->dy = 0; + for (resno = 0; resno < comp->numresolutions; resno++) { + int dx, dy; + res = &comp->resolutions[resno]; + dx = comp->dx * (1 << (res->pdx + comp->numresolutions - 1 - resno)); + dy = comp->dy * (1 << (res->pdy + comp->numresolutions - 1 - resno)); + pi->dx = !pi->dx ? dx : int_min(pi->dx, dx); + pi->dy = !pi->dy ? dy : int_min(pi->dy, dy); + } + if (!pi->tp_on){ + pi->poc.ty0 = pi->ty0; + pi->poc.tx0 = pi->tx0; + pi->poc.ty1 = pi->ty1; + pi->poc.tx1 = pi->tx1; + } + for (pi->y = pi->poc.ty0; pi->y < pi->poc.ty1; pi->y += pi->dy - (pi->y % pi->dy)) { + for (pi->x = pi->poc.tx0; pi->x < pi->poc.tx1; pi->x += pi->dx - (pi->x % pi->dx)) { + for (pi->resno = pi->poc.resno0; pi->resno < int_min(pi->poc.resno1, comp->numresolutions); pi->resno++) { + int levelno; + int trx0, try0; + int trx1, try1; + int rpx, rpy; + int prci, prcj; + res = &comp->resolutions[pi->resno]; + levelno = comp->numresolutions - 1 - pi->resno; + trx0 = int_ceildiv(pi->tx0, comp->dx << levelno); + try0 = int_ceildiv(pi->ty0, comp->dy << levelno); + trx1 = int_ceildiv(pi->tx1, comp->dx << levelno); + try1 = int_ceildiv(pi->ty1, comp->dy << levelno); + rpx = res->pdx + levelno; + rpy = res->pdy + levelno; + if (!((pi->y % (comp->dy << rpy) == 0) || ((pi->y == pi->ty0) && ((try0 << levelno) % (1 << rpy))))){ + continue; + } + if (!((pi->x % (comp->dx << rpx) == 0) || ((pi->x == pi->tx0) && ((trx0 << levelno) % (1 << rpx))))){ + continue; + } + + if ((res->pw==0)||(res->ph==0)) continue; + + if ((trx0==trx1)||(try0==try1)) continue; + + prci = int_floordivpow2(int_ceildiv(pi->x, comp->dx << levelno), res->pdx) + - int_floordivpow2(trx0, res->pdx); + prcj = int_floordivpow2(int_ceildiv(pi->y, comp->dy << levelno), res->pdy) + - int_floordivpow2(try0, res->pdy); + pi->precno = prci + prcj * res->pw; + for (pi->layno = pi->poc.layno0; pi->layno < pi->poc.layno1; pi->layno++) { + index = pi->layno * pi->step_l + pi->resno * pi->step_r + pi->compno * pi->step_c + pi->precno * pi->step_p; + if (!pi->include[index]) { + pi->include[index] = 1; + return true; + } +LABEL_SKIP:; + } + } + } + } + } + + return false; +} + +/* +========================================================== + Packet iterator interface +========================================================== +*/ + +opj_pi_iterator_t *pi_create_decode(opj_image_t *image, opj_cp_t *cp, int tileno) { + int p, q; + int compno, resno, pino; + opj_pi_iterator_t *pi = NULL; + opj_tcp_t *tcp = NULL; + opj_tccp_t *tccp = NULL; + + tcp = &cp->tcps[tileno]; + + pi = (opj_pi_iterator_t*) opj_calloc((tcp->numpocs + 1), sizeof(opj_pi_iterator_t)); + if(!pi) { + /* TODO: throw an error */ + return NULL; + } + + for (pino = 0; pino < tcp->numpocs + 1; pino++) { /* change */ + int maxres = 0; + int maxprec = 0; + p = tileno % cp->tw; + q = tileno / cp->tw; + + pi[pino].tx0 = int_max(cp->tx0 + p * cp->tdx, image->x0); + pi[pino].ty0 = int_max(cp->ty0 + q * cp->tdy, image->y0); + pi[pino].tx1 = int_min(cp->tx0 + (p + 1) * cp->tdx, image->x1); + pi[pino].ty1 = int_min(cp->ty0 + (q + 1) * cp->tdy, image->y1); + pi[pino].numcomps = image->numcomps; + + pi[pino].comps = (opj_pi_comp_t*) opj_calloc(image->numcomps, sizeof(opj_pi_comp_t)); + if(!pi[pino].comps) { + /* TODO: throw an error */ + pi_destroy(pi, cp, tileno); + return NULL; + } + + for (compno = 0; compno < pi->numcomps; compno++) { + int tcx0, tcy0, tcx1, tcy1; + opj_pi_comp_t *comp = &pi[pino].comps[compno]; + tccp = &tcp->tccps[compno]; + comp->dx = image->comps[compno].dx; + comp->dy = image->comps[compno].dy; + comp->numresolutions = tccp->numresolutions; + + comp->resolutions = (opj_pi_resolution_t*) opj_calloc(comp->numresolutions, sizeof(opj_pi_resolution_t)); + if(!comp->resolutions) { + /* TODO: throw an error */ + pi_destroy(pi, cp, tileno); + return NULL; + } + + tcx0 = int_ceildiv(pi->tx0, comp->dx); + tcy0 = int_ceildiv(pi->ty0, comp->dy); + tcx1 = int_ceildiv(pi->tx1, comp->dx); + tcy1 = int_ceildiv(pi->ty1, comp->dy); + if (comp->numresolutions > maxres) { + maxres = comp->numresolutions; + } + + for (resno = 0; resno < comp->numresolutions; resno++) { + int levelno; + int rx0, ry0, rx1, ry1; + int px0, py0, px1, py1; + opj_pi_resolution_t *res = &comp->resolutions[resno]; + if (tccp->csty & J2K_CCP_CSTY_PRT) { + res->pdx = tccp->prcw[resno]; + res->pdy = tccp->prch[resno]; + } else { + res->pdx = 15; + res->pdy = 15; + } + levelno = comp->numresolutions - 1 - resno; + rx0 = int_ceildivpow2(tcx0, levelno); + ry0 = int_ceildivpow2(tcy0, levelno); + rx1 = int_ceildivpow2(tcx1, levelno); + ry1 = int_ceildivpow2(tcy1, levelno); + px0 = int_floordivpow2(rx0, res->pdx) << res->pdx; + py0 = int_floordivpow2(ry0, res->pdy) << res->pdy; + px1 = int_ceildivpow2(rx1, res->pdx) << res->pdx; + py1 = int_ceildivpow2(ry1, res->pdy) << res->pdy; + res->pw = (rx0==rx1)?0:((px1 - px0) >> res->pdx); + res->ph = (ry0==ry1)?0:((py1 - py0) >> res->pdy); + + if (res->pw*res->ph > maxprec) { + maxprec = res->pw*res->ph; + } + + } + } + + tccp = &tcp->tccps[0]; + pi[pino].step_p = 1; + pi[pino].step_c = maxprec * pi[pino].step_p; + pi[pino].step_r = image->numcomps * pi[pino].step_c; + pi[pino].step_l = maxres * pi[pino].step_r; + + if (pino == 0) { + pi[pino].include = (short int*) opj_calloc(image->numcomps * maxres * tcp->numlayers * maxprec, sizeof(short int)); + if(!pi[pino].include) { + /* TODO: throw an error */ + pi_destroy(pi, cp, tileno); + return NULL; + } + } + else { + pi[pino].include = pi[pino - 1].include; + } + + if (tcp->POC == 0) { + pi[pino].first = 1; + pi[pino].poc.resno0 = 0; + pi[pino].poc.compno0 = 0; + pi[pino].poc.layno1 = tcp->numlayers; + pi[pino].poc.resno1 = maxres; + pi[pino].poc.compno1 = image->numcomps; + pi[pino].poc.prg = tcp->prg; + } else { + pi[pino].first = 1; + pi[pino].poc.resno0 = tcp->pocs[pino].resno0; + pi[pino].poc.compno0 = tcp->pocs[pino].compno0; + pi[pino].poc.layno1 = tcp->pocs[pino].layno1; + pi[pino].poc.resno1 = tcp->pocs[pino].resno1; + pi[pino].poc.compno1 = tcp->pocs[pino].compno1; + pi[pino].poc.prg = tcp->pocs[pino].prg; + } + pi[pino].poc.layno0 = 0; + pi[pino].poc.precno0 = 0; + pi[pino].poc.precno1 = maxprec; + + } + + return pi; +} + + +opj_pi_iterator_t *pi_initialise_encode(opj_image_t *image, opj_cp_t *cp, int tileno, J2K_T2_MODE t2_mode){ + int p, q, pino; + int compno, resno; + int maxres = 0; + int maxprec = 0; + opj_pi_iterator_t *pi = NULL; + opj_tcp_t *tcp = NULL; + opj_tccp_t *tccp = NULL; + + tcp = &cp->tcps[tileno]; + + pi = (opj_pi_iterator_t*) opj_calloc((tcp->numpocs + 1), sizeof(opj_pi_iterator_t)); + if(!pi) { return NULL;} + pi->tp_on = cp->tp_on; + + for(pino = 0;pino < tcp->numpocs+1 ; pino ++){ + p = tileno % cp->tw; + q = tileno / cp->tw; + + pi[pino].tx0 = int_max(cp->tx0 + p * cp->tdx, image->x0); + pi[pino].ty0 = int_max(cp->ty0 + q * cp->tdy, image->y0); + pi[pino].tx1 = int_min(cp->tx0 + (p + 1) * cp->tdx, image->x1); + pi[pino].ty1 = int_min(cp->ty0 + (q + 1) * cp->tdy, image->y1); + pi[pino].numcomps = image->numcomps; + + pi[pino].comps = (opj_pi_comp_t*) opj_calloc(image->numcomps, sizeof(opj_pi_comp_t)); + if(!pi[pino].comps) { + pi_destroy(pi, cp, tileno); + return NULL; + } + + for (compno = 0; compno < pi[pino].numcomps; compno++) { + int tcx0, tcy0, tcx1, tcy1; + opj_pi_comp_t *comp = &pi[pino].comps[compno]; + tccp = &tcp->tccps[compno]; + comp->dx = image->comps[compno].dx; + comp->dy = image->comps[compno].dy; + comp->numresolutions = tccp->numresolutions; + + comp->resolutions = (opj_pi_resolution_t*) opj_malloc(comp->numresolutions * sizeof(opj_pi_resolution_t)); + if(!comp->resolutions) { + pi_destroy(pi, cp, tileno); + return NULL; + } + + tcx0 = int_ceildiv(pi[pino].tx0, comp->dx); + tcy0 = int_ceildiv(pi[pino].ty0, comp->dy); + tcx1 = int_ceildiv(pi[pino].tx1, comp->dx); + tcy1 = int_ceildiv(pi[pino].ty1, comp->dy); + if (comp->numresolutions > maxres) { + maxres = comp->numresolutions; + } + + for (resno = 0; resno < comp->numresolutions; resno++) { + int levelno; + int rx0, ry0, rx1, ry1; + int px0, py0, px1, py1; + opj_pi_resolution_t *res = &comp->resolutions[resno]; + if (tccp->csty & J2K_CCP_CSTY_PRT) { + res->pdx = tccp->prcw[resno]; + res->pdy = tccp->prch[resno]; + } else { + res->pdx = 15; + res->pdy = 15; + } + levelno = comp->numresolutions - 1 - resno; + rx0 = int_ceildivpow2(tcx0, levelno); + ry0 = int_ceildivpow2(tcy0, levelno); + rx1 = int_ceildivpow2(tcx1, levelno); + ry1 = int_ceildivpow2(tcy1, levelno); + px0 = int_floordivpow2(rx0, res->pdx) << res->pdx; + py0 = int_floordivpow2(ry0, res->pdy) << res->pdy; + px1 = int_ceildivpow2(rx1, res->pdx) << res->pdx; + py1 = int_ceildivpow2(ry1, res->pdy) << res->pdy; + res->pw = (rx0==rx1)?0:((px1 - px0) >> res->pdx); + res->ph = (ry0==ry1)?0:((py1 - py0) >> res->pdy); + + if (res->pw*res->ph > maxprec) { + maxprec = res->pw * res->ph; + } + } + } + + tccp = &tcp->tccps[0]; + pi[pino].step_p = 1; + pi[pino].step_c = maxprec * pi[pino].step_p; + pi[pino].step_r = image->numcomps * pi[pino].step_c; + pi[pino].step_l = maxres * pi[pino].step_r; + + for (compno = 0; compno < pi->numcomps; compno++) { + opj_pi_comp_t *comp = &pi->comps[compno]; + for (resno = 0; resno < comp->numresolutions; resno++) { + int dx, dy; + opj_pi_resolution_t *res = &comp->resolutions[resno]; + dx = comp->dx * (1 << (res->pdx + comp->numresolutions - 1 - resno)); + dy = comp->dy * (1 << (res->pdy + comp->numresolutions - 1 - resno)); + pi[pino].dx = !pi->dx ? dx : int_min(pi->dx, dx); + pi[pino].dy = !pi->dy ? dy : int_min(pi->dy, dy); + } + } + + if (pino == 0) { + pi[pino].include = (short int*) opj_calloc(tcp->numlayers * pi[pino].step_l, sizeof(short int)); + if(!pi[pino].include) { + pi_destroy(pi, cp, tileno); + return NULL; + } + } + else { + pi[pino].include = pi[pino - 1].include; + } + + /* Generation of boundaries for each prog flag*/ + if(tcp->POC && ( cp->cinema || ((!cp->cinema) && (t2_mode == FINAL_PASS)))){ + tcp->pocs[pino].compS= tcp->pocs[pino].compno0; + tcp->pocs[pino].compE= tcp->pocs[pino].compno1; + tcp->pocs[pino].resS = tcp->pocs[pino].resno0; + tcp->pocs[pino].resE = tcp->pocs[pino].resno1; + tcp->pocs[pino].layE = tcp->pocs[pino].layno1; + tcp->pocs[pino].prg = tcp->pocs[pino].prg1; + if (pino > 0) + tcp->pocs[pino].layS = (tcp->pocs[pino].layE > tcp->pocs[pino - 1].layE) ? tcp->pocs[pino - 1].layE : 0; + }else { + tcp->pocs[pino].compS= 0; + tcp->pocs[pino].compE= image->numcomps; + tcp->pocs[pino].resS = 0; + tcp->pocs[pino].resE = maxres; + tcp->pocs[pino].layS = 0; + tcp->pocs[pino].layE = tcp->numlayers; + tcp->pocs[pino].prg = tcp->prg; + } + tcp->pocs[pino].prcS = 0; + tcp->pocs[pino].prcE = maxprec;; + tcp->pocs[pino].txS = pi[pino].tx0; + tcp->pocs[pino].txE = pi[pino].tx1; + tcp->pocs[pino].tyS = pi[pino].ty0; + tcp->pocs[pino].tyE = pi[pino].ty1; + tcp->pocs[pino].dx = pi[pino].dx; + tcp->pocs[pino].dy = pi[pino].dy; + } + return pi; + } + + + +void pi_destroy(opj_pi_iterator_t *pi, opj_cp_t *cp, int tileno) { + int compno, pino; + opj_tcp_t *tcp = &cp->tcps[tileno]; + if(pi) { + for (pino = 0; pino < tcp->numpocs + 1; pino++) { + if(pi[pino].comps) { + for (compno = 0; compno < pi->numcomps; compno++) { + opj_pi_comp_t *comp = &pi[pino].comps[compno]; + if(comp->resolutions) { + opj_free(comp->resolutions); + } + } + opj_free(pi[pino].comps); + } + } + if(pi->include) { + opj_free(pi->include); + } + opj_free(pi); + } +} + +bool pi_next(opj_pi_iterator_t * pi) { + switch (pi->poc.prg) { + case LRCP: + return pi_next_lrcp(pi); + case RLCP: + return pi_next_rlcp(pi); + case RPCL: + return pi_next_rpcl(pi); + case PCRL: + return pi_next_pcrl(pi); + case CPRL: + return pi_next_cprl(pi); + case PROG_UNKNOWN: + return false; + } + + return false; +} + +bool pi_create_encode( opj_pi_iterator_t *pi, opj_cp_t *cp,int tileno, int pino,int tpnum, int tppos, J2K_T2_MODE t2_mode,int cur_totnum_tp){ + char prog[4]; + int i; + int incr_top=1,resetX=0; + opj_tcp_t *tcps =&cp->tcps[tileno]; + opj_poc_t *tcp= &tcps->pocs[pino]; + + pi[pino].first = 1; + pi[pino].poc.prg = tcp->prg; + + switch(tcp->prg){ + case CPRL: strncpy(prog, "CPRL",4); + break; + case LRCP: strncpy(prog, "LRCP",4); + break; + case PCRL: strncpy(prog, "PCRL",4); + break; + case RLCP: strncpy(prog, "RLCP",4); + break; + case RPCL: strncpy(prog, "RPCL",4); + break; + case PROG_UNKNOWN: + return true; + } + + if(!(cp->tp_on && ((!cp->cinema && (t2_mode == FINAL_PASS)) || cp->cinema))){ + pi[pino].poc.resno0 = tcp->resS; + pi[pino].poc.resno1 = tcp->resE; + pi[pino].poc.compno0 = tcp->compS; + pi[pino].poc.compno1 = tcp->compE; + pi[pino].poc.layno0 = tcp->layS; + pi[pino].poc.layno1 = tcp->layE; + pi[pino].poc.precno0 = tcp->prcS; + pi[pino].poc.precno1 = tcp->prcE; + pi[pino].poc.tx0 = tcp->txS; + pi[pino].poc.ty0 = tcp->tyS; + pi[pino].poc.tx1 = tcp->txE; + pi[pino].poc.ty1 = tcp->tyE; + }else { + if( tpnum < cur_totnum_tp){ + for(i=3;i>=0;i--){ + switch(prog[i]){ + case 'C': + if (i > tppos){ + pi[pino].poc.compno0 = tcp->compS; + pi[pino].poc.compno1 = tcp->compE; + }else{ + if (tpnum == 0){ + tcp->comp_t = tcp->compS; + pi[pino].poc.compno0 = tcp->comp_t; + pi[pino].poc.compno1 = tcp->comp_t+1; + tcp->comp_t+=1; + }else{ + if (incr_top == 1){ + if(tcp->comp_t ==tcp->compE){ + tcp->comp_t = tcp->compS; + pi[pino].poc.compno0 = tcp->comp_t; + pi[pino].poc.compno1 = tcp->comp_t+1; + tcp->comp_t+=1; + incr_top=1; + }else{ + pi[pino].poc.compno0 = tcp->comp_t; + pi[pino].poc.compno1 = tcp->comp_t+1; + tcp->comp_t+=1; + incr_top=0; + } + }else{ + pi[pino].poc.compno0 = tcp->comp_t-1; + pi[pino].poc.compno1 = tcp->comp_t; + } + } + } + break; + + case 'R': + if (i > tppos){ + pi[pino].poc.resno0 = tcp->resS; + pi[pino].poc.resno1 = tcp->resE; + }else{ + if (tpnum == 0){ + tcp->res_t = tcp->resS; + pi[pino].poc.resno0 = tcp->res_t; + pi[pino].poc.resno1 = tcp->res_t+1; + tcp->res_t+=1; + }else{ + if (incr_top == 1){ + if(tcp->res_t==tcp->resE){ + tcp->res_t = tcp->resS; + pi[pino].poc.resno0 = tcp->res_t; + pi[pino].poc.resno1 = tcp->res_t+1; + tcp->res_t+=1; + incr_top=1; + }else{ + pi[pino].poc.resno0 = tcp->res_t; + pi[pino].poc.resno1 = tcp->res_t+1; + tcp->res_t+=1; + incr_top=0; + } + }else{ + pi[pino].poc.resno0 = tcp->res_t - 1; + pi[pino].poc.resno1 = tcp->res_t; + } + } + } + break; + + case 'L': + if (i > tppos){ + pi[pino].poc.layno0 = tcp->layS; + pi[pino].poc.layno1 = tcp->layE; + }else{ + if (tpnum == 0){ + tcp->lay_t = tcp->layS; + pi[pino].poc.layno0 = tcp->lay_t; + pi[pino].poc.layno1 = tcp->lay_t+1; + tcp->lay_t+=1; + }else{ + if (incr_top == 1){ + if(tcp->lay_t == tcp->layE){ + tcp->lay_t = tcp->layS; + pi[pino].poc.layno0 = tcp->lay_t; + pi[pino].poc.layno1 = tcp->lay_t+1; + tcp->lay_t+=1; + incr_top=1; + }else{ + pi[pino].poc.layno0 = tcp->lay_t; + pi[pino].poc.layno1 = tcp->lay_t+1; + tcp->lay_t+=1; + incr_top=0; + } + }else{ + pi[pino].poc.layno0 = tcp->lay_t - 1; + pi[pino].poc.layno1 = tcp->lay_t; + } + } + } + break; + + case 'P': + switch(tcp->prg){ + case LRCP: + case RLCP: + if (i > tppos){ + pi[pino].poc.precno0 = tcp->prcS; + pi[pino].poc.precno1 = tcp->prcE; + }else{ + if (tpnum == 0){ + tcp->prc_t = tcp->prcS; + pi[pino].poc.precno0 = tcp->prc_t; + pi[pino].poc.precno1 = tcp->prc_t+1; + tcp->prc_t+=1; + }else{ + if (incr_top == 1){ + if(tcp->prc_t == tcp->prcE){ + tcp->prc_t = tcp->prcS; + pi[pino].poc.precno0 = tcp->prc_t; + pi[pino].poc.precno1 = tcp->prc_t+1; + tcp->prc_t+=1; + incr_top=1; + }else{ + pi[pino].poc.precno0 = tcp->prc_t; + pi[pino].poc.precno1 = tcp->prc_t+1; + tcp->prc_t+=1; + incr_top=0; + } + }else{ + pi[pino].poc.precno0 = tcp->prc_t - 1; + pi[pino].poc.precno1 = tcp->prc_t; + } + } + } + break; + default: + if (i > tppos){ + pi[pino].poc.tx0 = tcp->txS; + pi[pino].poc.ty0 = tcp->tyS; + pi[pino].poc.tx1 = tcp->txE; + pi[pino].poc.ty1 = tcp->tyE; + }else{ + if (tpnum == 0){ + tcp->tx0_t = tcp->txS; + tcp->ty0_t = tcp->tyS; + pi[pino].poc.tx0 = tcp->tx0_t; + pi[pino].poc.tx1 = tcp->tx0_t + tcp->dx - (tcp->tx0_t % tcp->dx); + pi[pino].poc.ty0 = tcp->ty0_t; + pi[pino].poc.ty1 = tcp->ty0_t + tcp->dy - (tcp->ty0_t % tcp->dy); + tcp->tx0_t = pi[pino].poc.tx1; + tcp->ty0_t = pi[pino].poc.ty1; + }else{ + if (incr_top == 1){ + if(tcp->tx0_t >= tcp->txE){ + if(tcp->ty0_t >= tcp->tyE){ + tcp->ty0_t = tcp->tyS; + pi[pino].poc.ty0 = tcp->ty0_t; + pi[pino].poc.ty1 = tcp->ty0_t + tcp->dy - (tcp->ty0_t % tcp->dy); + tcp->ty0_t = pi[pino].poc.ty1; + incr_top=1;resetX=1; + }else{ + pi[pino].poc.ty0 = tcp->ty0_t; + pi[pino].poc.ty1 = tcp->ty0_t + tcp->dy - (tcp->ty0_t % tcp->dy); + tcp->ty0_t = pi[pino].poc.ty1; + incr_top=0;resetX=1; + } + if(resetX==1){ + tcp->tx0_t = tcp->txS; + pi[pino].poc.tx0 = tcp->tx0_t; + pi[pino].poc.tx1 = tcp->tx0_t + tcp->dx- (tcp->tx0_t % tcp->dx); + tcp->tx0_t = pi[pino].poc.tx1; + } + }else{ + pi[pino].poc.tx0 = tcp->tx0_t; + pi[pino].poc.tx1 = tcp->tx0_t + tcp->dx- (tcp->tx0_t % tcp->dx); + tcp->tx0_t = pi[pino].poc.tx1; + pi[pino].poc.ty0 = tcp->ty0_t - tcp->dy - (tcp->ty0_t % tcp->dy); + pi[pino].poc.ty1 = tcp->ty0_t ; + incr_top=0; + } + }else{ + pi[pino].poc.tx0 = tcp->tx0_t - tcp->dx - (tcp->tx0_t % tcp->dx); + pi[pino].poc.tx1 = tcp->tx0_t ; + pi[pino].poc.ty0 = tcp->ty0_t - tcp->dy - (tcp->ty0_t % tcp->dy); + pi[pino].poc.ty1 = tcp->ty0_t ; + } + } + } + break; + } + break; + } + } + } + } + return false; +} + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/pi.h b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/pi.h new file mode 100644 index 0000000..80febc5 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/pi.h @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __PI_H +#define __PI_H +/** +@file pi.h +@brief Implementation of a packet iterator (PI) + +The functions in PI.C have for goal to realize a packet iterator that permits to get the next +packet following the progression order and change of it. The functions in PI.C are used +by some function in T2.C. +*/ + +/** @defgroup PI PI - Implementation of a packet iterator */ +/*@{*/ + +/** +FIXME: documentation +*/ +typedef struct opj_pi_resolution { + int pdx, pdy; + int pw, ph; +} opj_pi_resolution_t; + +/** +FIXME: documentation +*/ +typedef struct opj_pi_comp { + int dx, dy; + /** number of resolution levels */ + int numresolutions; + opj_pi_resolution_t *resolutions; +} opj_pi_comp_t; + +/** +Packet iterator +*/ +typedef struct opj_pi_iterator { + /** Enabling Tile part generation*/ + char tp_on; + /** precise if the packet has been already used (usefull for progression order change) */ + short int *include; + /** layer step used to localize the packet in the include vector */ + int step_l; + /** resolution step used to localize the packet in the include vector */ + int step_r; + /** component step used to localize the packet in the include vector */ + int step_c; + /** precinct step used to localize the packet in the include vector */ + int step_p; + /** component that identify the packet */ + int compno; + /** resolution that identify the packet */ + int resno; + /** precinct that identify the packet */ + int precno; + /** layer that identify the packet */ + int layno; + /** 0 if the first packet */ + int first; + /** progression order change information */ + opj_poc_t poc; + /** number of components in the image */ + int numcomps; + /** Components*/ + opj_pi_comp_t *comps; + int tx0, ty0, tx1, ty1; + int x, y, dx, dy; +} opj_pi_iterator_t; + +/** @name Exported functions */ +/*@{*/ +/* ----------------------------------------------------------------------- */ +/** +Create a packet iterator for Encoder +@param image Raw image for which the packets will be listed +@param cp Coding parameters +@param tileno Number that identifies the tile for which to list the packets +@param t2_mode If == 0 In Threshold calculation ,If == 1 Final pass +@return Returns a packet iterator that points to the first packet of the tile +@see pi_destroy +*/ +opj_pi_iterator_t *pi_initialise_encode(opj_image_t *image, opj_cp_t *cp, int tileno,J2K_T2_MODE t2_mode); +/** +Modify the packet iterator for enabling tile part generation +@param pi Handle to the packet iterator generated in pi_initialise_encode +@param cp Coding parameters +@param tileno Number that identifies the tile for which to list the packets +@param pino Iterator index for pi +@param tpnum Tile part number of the current tile +@param tppos The position of the tile part flag in the progression order +@param t2_mode If == 0 In Threshold calculation ,If == 1 Final pass +@param cur_totnum_tp The total number of tile parts in the current tile +@return Returns true if an error is detected +*/ +bool pi_create_encode(opj_pi_iterator_t *pi, opj_cp_t *cp,int tileno, int pino,int tpnum, int tppos, J2K_T2_MODE t2_mode,int cur_totnum_tp); +/** +Create a packet iterator for Decoder +@param image Raw image for which the packets will be listed +@param cp Coding parameters +@param tileno Number that identifies the tile for which to list the packets +@return Returns a packet iterator that points to the first packet of the tile +@see pi_destroy +*/ +opj_pi_iterator_t *pi_create_decode(opj_image_t * image, opj_cp_t * cp, int tileno); + +/** +Destroy a packet iterator +@param pi Previously created packet iterator +@param cp Coding parameters +@param tileno Number that identifies the tile for which the packets were listed +@see pi_create +*/ +void pi_destroy(opj_pi_iterator_t *pi, opj_cp_t *cp, int tileno); + +/** +Modify the packet iterator to point to the next packet +@param pi Packet iterator to modify +@return Returns false if pi pointed to the last packet or else returns true +*/ +bool pi_next(opj_pi_iterator_t * pi); +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __PI_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/raw.c b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/raw.c new file mode 100644 index 0000000..3d231bf --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/raw.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "opj_includes.h" + +/* +========================================================== + local functions +========================================================== +*/ + + +/* +========================================================== + RAW encoding interface +========================================================== +*/ + +opj_raw_t* raw_create(void) { + opj_raw_t *raw = (opj_raw_t*)opj_malloc(sizeof(opj_raw_t)); + return raw; +} + +void raw_destroy(opj_raw_t *raw) { + if(raw) { + opj_free(raw); + } +} + +int raw_numbytes(opj_raw_t *raw) { + return raw->bp - raw->start; +} + +void raw_init_dec(opj_raw_t *raw, unsigned char *bp, int len) { + raw->start = bp; + raw->lenmax = len; + raw->len = 0; + raw->c = 0; + raw->ct = 0; +} + +int raw_decode(opj_raw_t *raw) { + int d; + if (raw->ct == 0) { + raw->ct = 8; + if (raw->len == raw->lenmax) { + raw->c = 0xff; + } else { + if (raw->c == 0xff) { + raw->ct = 7; + } + raw->c = *(raw->start + raw->len); + raw->len++; + } + } + raw->ct--; + d = (raw->c >> raw->ct) & 0x01; + + return d; +} + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/raw.h b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/raw.h new file mode 100644 index 0000000..3c4b372 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/raw.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __RAW_H +#define __RAW_H +/** +@file raw.h +@brief Implementation of operations for raw encoding (RAW) + +The functions in RAW.C have for goal to realize the operation of raw encoding linked +with the corresponding mode switch. +*/ + +/** @defgroup RAW RAW - Implementation of operations for raw encoding */ +/*@{*/ + +/** +RAW encoding operations +*/ +typedef struct opj_raw { + /** temporary buffer where bits are coded or decoded */ + unsigned char c; + /** number of bits already read or free to write */ + unsigned int ct; + /** maximum length to decode */ + unsigned int lenmax; + /** length decoded */ + unsigned int len; + /** pointer to the current position in the buffer */ + unsigned char *bp; + /** pointer to the start of the buffer */ + unsigned char *start; + /** pointer to the end of the buffer */ + unsigned char *end; +} opj_raw_t; + +/** @name Exported functions */ +/*@{*/ +/* ----------------------------------------------------------------------- */ +/** +Create a new RAW handle +@return Returns a new RAW handle if successful, returns NULL otherwise +*/ +opj_raw_t* raw_create(void); +/** +Destroy a previously created RAW handle +@param raw RAW handle to destroy +*/ +void raw_destroy(opj_raw_t *raw); +/** +Return the number of bytes written/read since initialisation +@param raw RAW handle to destroy +@return Returns the number of bytes already encoded +*/ +int raw_numbytes(opj_raw_t *raw); +/** +Initialize the decoder +@param raw RAW handle +@param bp Pointer to the start of the buffer from which the bytes will be read +@param len Length of the input buffer +*/ +void raw_init_dec(opj_raw_t *raw, unsigned char *bp, int len); +/** +Decode a symbol using raw-decoder. Cfr p.506 TAUBMAN +@param raw RAW handle +@return Returns the decoded symbol (0 or 1) +*/ +int raw_decode(opj_raw_t *raw); +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __RAW_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/t1.c b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/t1.c new file mode 100644 index 0000000..4930074 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/t1.c @@ -0,0 +1,1581 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2007, Callum Lerwick + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "opj_includes.h" +#include "t1_luts.h" + +/** @defgroup T1 T1 - Implementation of the tier-1 coding */ +/*@{*/ + +/** @name Local static functions */ +/*@{*/ + +static INLINE char t1_getctxno_zc(int f, int orient); +static char t1_getctxno_sc(int f); +static INLINE int t1_getctxno_mag(int f); +static char t1_getspb(int f); +static short t1_getnmsedec_sig(int x, int bitpos); +static short t1_getnmsedec_ref(int x, int bitpos); +static void t1_updateflags(flag_t *flagsp, int s, int stride); +/** +Encode significant pass +*/ +static void t1_enc_sigpass_step( + opj_t1_t *t1, + flag_t *flagsp, + int *datap, + int orient, + int bpno, + int one, + int *nmsedec, + char type, + int vsc); +/** +Decode significant pass +*/ +static INLINE void t1_dec_sigpass_step_raw( + opj_t1_t *t1, + flag_t *flagsp, + int *datap, + int orient, + int oneplushalf, + int vsc); +static INLINE void t1_dec_sigpass_step_mqc( + opj_t1_t *t1, + flag_t *flagsp, + int *datap, + int orient, + int oneplushalf); +static INLINE void t1_dec_sigpass_step_mqc_vsc( + opj_t1_t *t1, + flag_t *flagsp, + int *datap, + int orient, + int oneplushalf, + int vsc); +/** +Encode significant pass +*/ +static void t1_enc_sigpass( + opj_t1_t *t1, + int bpno, + int orient, + int *nmsedec, + char type, + int cblksty); +/** +Decode significant pass +*/ +static void t1_dec_sigpass_raw( + opj_t1_t *t1, + int bpno, + int orient, + int cblksty); +static void t1_dec_sigpass_mqc( + opj_t1_t *t1, + int bpno, + int orient); +static void t1_dec_sigpass_mqc_vsc( + opj_t1_t *t1, + int bpno, + int orient); +/** +Encode refinement pass +*/ +static void t1_enc_refpass_step( + opj_t1_t *t1, + flag_t *flagsp, + int *datap, + int bpno, + int one, + int *nmsedec, + char type, + int vsc); +/** +Decode refinement pass +*/ +static void INLINE t1_dec_refpass_step_raw( + opj_t1_t *t1, + flag_t *flagsp, + int *datap, + int poshalf, + int neghalf, + int vsc); +static void INLINE t1_dec_refpass_step_mqc( + opj_t1_t *t1, + flag_t *flagsp, + int *datap, + int poshalf, + int neghalf); +static void INLINE t1_dec_refpass_step_mqc_vsc( + opj_t1_t *t1, + flag_t *flagsp, + int *datap, + int poshalf, + int neghalf, + int vsc); + +/** +Encode refinement pass +*/ +static void t1_enc_refpass( + opj_t1_t *t1, + int bpno, + int *nmsedec, + char type, + int cblksty); +/** +Decode refinement pass +*/ +static void t1_dec_refpass_raw( + opj_t1_t *t1, + int bpno, + int cblksty); +static void t1_dec_refpass_mqc( + opj_t1_t *t1, + int bpno); +static void t1_dec_refpass_mqc_vsc( + opj_t1_t *t1, + int bpno); +/** +Encode clean-up pass +*/ +static void t1_enc_clnpass_step( + opj_t1_t *t1, + flag_t *flagsp, + int *datap, + int orient, + int bpno, + int one, + int *nmsedec, + int partial, + int vsc); +/** +Decode clean-up pass +*/ +static void t1_dec_clnpass_step_partial( + opj_t1_t *t1, + flag_t *flagsp, + int *datap, + int orient, + int oneplushalf); +static void t1_dec_clnpass_step( + opj_t1_t *t1, + flag_t *flagsp, + int *datap, + int orient, + int oneplushalf); +static void t1_dec_clnpass_step_vsc( + opj_t1_t *t1, + flag_t *flagsp, + int *datap, + int orient, + int oneplushalf, + int partial, + int vsc); +/** +Encode clean-up pass +*/ +static void t1_enc_clnpass( + opj_t1_t *t1, + int bpno, + int orient, + int *nmsedec, + int cblksty); +/** +Decode clean-up pass +*/ +static void t1_dec_clnpass( + opj_t1_t *t1, + int bpno, + int orient, + int cblksty); +static double t1_getwmsedec( + int nmsedec, + int compno, + int level, + int orient, + int bpno, + int qmfbid, + double stepsize, + int numcomps, + int mct); +/** +Encode 1 code-block +@param t1 T1 handle +@param cblk Code-block coding parameters +@param orient +@param compno Component number +@param level +@param qmfbid +@param stepsize +@param cblksty Code-block style +@param numcomps +@param mct +@param tile +*/ +static void t1_encode_cblk( + opj_t1_t *t1, + opj_tcd_cblk_enc_t* cblk, + int orient, + int compno, + int level, + int qmfbid, + double stepsize, + int cblksty, + int numcomps, + int mct, + opj_tcd_tile_t * tile); +/** +Decode 1 code-block +@param t1 T1 handle +@param cblk Code-block coding parameters +@param orient +@param roishift Region of interest shifting value +@param cblksty Code-block style +*/ +static void t1_decode_cblk( + opj_t1_t *t1, + opj_tcd_cblk_dec_t* cblk, + int orient, + int roishift, + int cblksty); + +/*@}*/ + +/*@}*/ + +/* ----------------------------------------------------------------------- */ + +static char t1_getctxno_zc(int f, int orient) { + return lut_ctxno_zc[(orient << 8) | (f & T1_SIG_OTH)]; +} + +static char t1_getctxno_sc(int f) { + return lut_ctxno_sc[(f & (T1_SIG_PRIM | T1_SGN)) >> 4]; +} + +static int t1_getctxno_mag(int f) { + int tmp1 = (f & T1_SIG_OTH) ? T1_CTXNO_MAG + 1 : T1_CTXNO_MAG; + int tmp2 = (f & T1_REFINE) ? T1_CTXNO_MAG + 2 : tmp1; + return (tmp2); +} + +static char t1_getspb(int f) { + return lut_spb[(f & (T1_SIG_PRIM | T1_SGN)) >> 4]; +} + +static short t1_getnmsedec_sig(int x, int bitpos) { + if (bitpos > T1_NMSEDEC_FRACBITS) { + return lut_nmsedec_sig[(x >> (bitpos - T1_NMSEDEC_FRACBITS)) & ((1 << T1_NMSEDEC_BITS) - 1)]; + } + + return lut_nmsedec_sig0[x & ((1 << T1_NMSEDEC_BITS) - 1)]; +} + +static short t1_getnmsedec_ref(int x, int bitpos) { + if (bitpos > T1_NMSEDEC_FRACBITS) { + return lut_nmsedec_ref[(x >> (bitpos - T1_NMSEDEC_FRACBITS)) & ((1 << T1_NMSEDEC_BITS) - 1)]; + } + + return lut_nmsedec_ref0[x & ((1 << T1_NMSEDEC_BITS) - 1)]; +} + +static void t1_updateflags(flag_t *flagsp, int s, int stride) { + flag_t *np = flagsp - stride; + flag_t *sp = flagsp + stride; + + static const flag_t mod[] = { + T1_SIG_S, T1_SIG_S|T1_SGN_S, + T1_SIG_E, T1_SIG_E|T1_SGN_E, + T1_SIG_W, T1_SIG_W|T1_SGN_W, + T1_SIG_N, T1_SIG_N|T1_SGN_N + }; + + np[-1] |= T1_SIG_SE; + np[0] |= mod[s]; + np[1] |= T1_SIG_SW; + + flagsp[-1] |= mod[s+2]; + flagsp[0] |= T1_SIG; + flagsp[1] |= mod[s+4]; + + sp[-1] |= T1_SIG_NE; + sp[0] |= mod[s+6]; + sp[1] |= T1_SIG_NW; +} + +static void t1_enc_sigpass_step( + opj_t1_t *t1, + flag_t *flagsp, + int *datap, + int orient, + int bpno, + int one, + int *nmsedec, + char type, + int vsc) +{ + int v, flag; + + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + flag = vsc ? ((*flagsp) & (~(T1_SIG_S | T1_SIG_SE | T1_SIG_SW | T1_SGN_S))) : (*flagsp); + if ((flag & T1_SIG_OTH) && !(flag & (T1_SIG | T1_VISIT))) { + v = int_abs(*datap) & one ? 1 : 0; + mqc_setcurctx(mqc, t1_getctxno_zc(flag, orient)); /* ESSAI */ + if (type == T1_TYPE_RAW) { /* BYPASS/LAZY MODE */ + mqc_bypass_enc(mqc, v); + } else { + mqc_encode(mqc, v); + } + if (v) { + v = *datap < 0 ? 1 : 0; + *nmsedec += t1_getnmsedec_sig(int_abs(*datap), bpno + T1_NMSEDEC_FRACBITS); + mqc_setcurctx(mqc, t1_getctxno_sc(flag)); /* ESSAI */ + if (type == T1_TYPE_RAW) { /* BYPASS/LAZY MODE */ + mqc_bypass_enc(mqc, v); + } else { + mqc_encode(mqc, v ^ t1_getspb(flag)); + } + t1_updateflags(flagsp, v, t1->flags_stride); + } + *flagsp |= T1_VISIT; + } +} + +static INLINE void t1_dec_sigpass_step_raw( + opj_t1_t *t1, + flag_t *flagsp, + int *datap, + int orient, + int oneplushalf, + int vsc) +{ + int v, flag; + + opj_raw_t *raw = t1->raw; /* RAW component */ + + flag = vsc ? ((*flagsp) & (~(T1_SIG_S | T1_SIG_SE | T1_SIG_SW | T1_SGN_S))) : (*flagsp); + if ((flag & T1_SIG_OTH) && !(flag & (T1_SIG | T1_VISIT))) { + if (raw_decode(raw)) { + v = raw_decode(raw); /* ESSAI */ + *datap = v ? -oneplushalf : oneplushalf; + t1_updateflags(flagsp, v, t1->flags_stride); + } + *flagsp |= T1_VISIT; + } +} /* VSC and BYPASS by Antonin */ + +static INLINE void t1_dec_sigpass_step_mqc( + opj_t1_t *t1, + flag_t *flagsp, + int *datap, + int orient, + int oneplushalf) +{ + int v, flag; + + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + flag = *flagsp; + if ((flag & T1_SIG_OTH) && !(flag & (T1_SIG | T1_VISIT))) { + mqc_setcurctx(mqc, t1_getctxno_zc(flag, orient)); + if (mqc_decode(mqc)) { + mqc_setcurctx(mqc, t1_getctxno_sc(flag)); + v = mqc_decode(mqc) ^ t1_getspb(flag); + *datap = v ? -oneplushalf : oneplushalf; + t1_updateflags(flagsp, v, t1->flags_stride); + } + *flagsp |= T1_VISIT; + } +} /* VSC and BYPASS by Antonin */ + +static INLINE void t1_dec_sigpass_step_mqc_vsc( + opj_t1_t *t1, + flag_t *flagsp, + int *datap, + int orient, + int oneplushalf, + int vsc) +{ + int v, flag; + + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + flag = vsc ? ((*flagsp) & (~(T1_SIG_S | T1_SIG_SE | T1_SIG_SW | T1_SGN_S))) : (*flagsp); + if ((flag & T1_SIG_OTH) && !(flag & (T1_SIG | T1_VISIT))) { + mqc_setcurctx(mqc, t1_getctxno_zc(flag, orient)); + if (mqc_decode(mqc)) { + mqc_setcurctx(mqc, t1_getctxno_sc(flag)); + v = mqc_decode(mqc) ^ t1_getspb(flag); + *datap = v ? -oneplushalf : oneplushalf; + t1_updateflags(flagsp, v, t1->flags_stride); + } + *flagsp |= T1_VISIT; + } +} /* VSC and BYPASS by Antonin */ + +static void t1_enc_sigpass( + opj_t1_t *t1, + int bpno, + int orient, + int *nmsedec, + char type, + int cblksty) +{ + int i, j, k, one, vsc; + *nmsedec = 0; + one = 1 << (bpno + T1_NMSEDEC_FRACBITS); + for (k = 0; k < t1->h; k += 4) { + for (i = 0; i < t1->w; ++i) { + for (j = k; j < k + 4 && j < t1->h; ++j) { + vsc = ((cblksty & J2K_CCP_CBLKSTY_VSC) && (j == k + 3 || j == t1->h - 1)) ? 1 : 0; + t1_enc_sigpass_step( + t1, + &t1->flags[((j+1) * t1->flags_stride) + i + 1], + &t1->data[(j * t1->w) + i], + orient, + bpno, + one, + nmsedec, + type, + vsc); + } + } + } +} + +static void t1_dec_sigpass_raw( + opj_t1_t *t1, + int bpno, + int orient, + int cblksty) +{ + int i, j, k, one, half, oneplushalf, vsc; + one = 1 << bpno; + half = one >> 1; + oneplushalf = one | half; + for (k = 0; k < t1->h; k += 4) { + for (i = 0; i < t1->w; ++i) { + for (j = k; j < k + 4 && j < t1->h; ++j) { + vsc = ((cblksty & J2K_CCP_CBLKSTY_VSC) && (j == k + 3 || j == t1->h - 1)) ? 1 : 0; + t1_dec_sigpass_step_raw( + t1, + &t1->flags[((j+1) * t1->flags_stride) + i + 1], + &t1->data[(j * t1->w) + i], + orient, + oneplushalf, + vsc); + } + } + } +} /* VSC and BYPASS by Antonin */ + +static void t1_dec_sigpass_mqc( + opj_t1_t *t1, + int bpno, + int orient) +{ + int i, j, k, one, half, oneplushalf; + int *data1 = t1->data; + flag_t *flags1 = &t1->flags[1]; + one = 1 << bpno; + half = one >> 1; + oneplushalf = one | half; + for (k = 0; k < (t1->h & ~3); k += 4) { + for (i = 0; i < t1->w; ++i) { + int *data2 = data1 + i; + flag_t *flags2 = flags1 + i; + flags2 += t1->flags_stride; + t1_dec_sigpass_step_mqc(t1, flags2, data2, orient, oneplushalf); + data2 += t1->w; + flags2 += t1->flags_stride; + t1_dec_sigpass_step_mqc(t1, flags2, data2, orient, oneplushalf); + data2 += t1->w; + flags2 += t1->flags_stride; + t1_dec_sigpass_step_mqc(t1, flags2, data2, orient, oneplushalf); + data2 += t1->w; + flags2 += t1->flags_stride; + t1_dec_sigpass_step_mqc(t1, flags2, data2, orient, oneplushalf); + data2 += t1->w; + } + data1 += t1->w << 2; + flags1 += t1->flags_stride << 2; + } + for (i = 0; i < t1->w; ++i) { + int *data2 = data1 + i; + flag_t *flags2 = flags1 + i; + for (j = k; j < t1->h; ++j) { + flags2 += t1->flags_stride; + t1_dec_sigpass_step_mqc(t1, flags2, data2, orient, oneplushalf); + data2 += t1->w; + } + } +} /* VSC and BYPASS by Antonin */ + +static void t1_dec_sigpass_mqc_vsc( + opj_t1_t *t1, + int bpno, + int orient) +{ + int i, j, k, one, half, oneplushalf, vsc; + one = 1 << bpno; + half = one >> 1; + oneplushalf = one | half; + for (k = 0; k < t1->h; k += 4) { + for (i = 0; i < t1->w; ++i) { + for (j = k; j < k + 4 && j < t1->h; ++j) { + vsc = (j == k + 3 || j == t1->h - 1) ? 1 : 0; + t1_dec_sigpass_step_mqc_vsc( + t1, + &t1->flags[((j+1) * t1->flags_stride) + i + 1], + &t1->data[(j * t1->w) + i], + orient, + oneplushalf, + vsc); + } + } + } +} /* VSC and BYPASS by Antonin */ + +static void t1_enc_refpass_step( + opj_t1_t *t1, + flag_t *flagsp, + int *datap, + int bpno, + int one, + int *nmsedec, + char type, + int vsc) +{ + int v, flag; + + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + flag = vsc ? ((*flagsp) & (~(T1_SIG_S | T1_SIG_SE | T1_SIG_SW | T1_SGN_S))) : (*flagsp); + if ((flag & (T1_SIG | T1_VISIT)) == T1_SIG) { + *nmsedec += t1_getnmsedec_ref(int_abs(*datap), bpno + T1_NMSEDEC_FRACBITS); + v = int_abs(*datap) & one ? 1 : 0; + mqc_setcurctx(mqc, t1_getctxno_mag(flag)); /* ESSAI */ + if (type == T1_TYPE_RAW) { /* BYPASS/LAZY MODE */ + mqc_bypass_enc(mqc, v); + } else { + mqc_encode(mqc, v); + } + *flagsp |= T1_REFINE; + } +} + +static INLINE void t1_dec_refpass_step_raw( + opj_t1_t *t1, + flag_t *flagsp, + int *datap, + int poshalf, + int neghalf, + int vsc) +{ + int v, t, flag; + + opj_raw_t *raw = t1->raw; /* RAW component */ + + flag = vsc ? ((*flagsp) & (~(T1_SIG_S | T1_SIG_SE | T1_SIG_SW | T1_SGN_S))) : (*flagsp); + if ((flag & (T1_SIG | T1_VISIT)) == T1_SIG) { + v = raw_decode(raw); + t = v ? poshalf : neghalf; + *datap += *datap < 0 ? -t : t; + *flagsp |= T1_REFINE; + } +} /* VSC and BYPASS by Antonin */ + +static INLINE void t1_dec_refpass_step_mqc( + opj_t1_t *t1, + flag_t *flagsp, + int *datap, + int poshalf, + int neghalf) +{ + int v, t, flag; + + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + flag = *flagsp; + if ((flag & (T1_SIG | T1_VISIT)) == T1_SIG) { + mqc_setcurctx(mqc, t1_getctxno_mag(flag)); /* ESSAI */ + v = mqc_decode(mqc); + t = v ? poshalf : neghalf; + *datap += *datap < 0 ? -t : t; + *flagsp |= T1_REFINE; + } +} /* VSC and BYPASS by Antonin */ + +static INLINE void t1_dec_refpass_step_mqc_vsc( + opj_t1_t *t1, + flag_t *flagsp, + int *datap, + int poshalf, + int neghalf, + int vsc) +{ + int v, t, flag; + + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + flag = vsc ? ((*flagsp) & (~(T1_SIG_S | T1_SIG_SE | T1_SIG_SW | T1_SGN_S))) : (*flagsp); + if ((flag & (T1_SIG | T1_VISIT)) == T1_SIG) { + mqc_setcurctx(mqc, t1_getctxno_mag(flag)); /* ESSAI */ + v = mqc_decode(mqc); + t = v ? poshalf : neghalf; + *datap += *datap < 0 ? -t : t; + *flagsp |= T1_REFINE; + } +} /* VSC and BYPASS by Antonin */ + +static void t1_enc_refpass( + opj_t1_t *t1, + int bpno, + int *nmsedec, + char type, + int cblksty) +{ + int i, j, k, one, vsc; + *nmsedec = 0; + one = 1 << (bpno + T1_NMSEDEC_FRACBITS); + for (k = 0; k < t1->h; k += 4) { + for (i = 0; i < t1->w; ++i) { + for (j = k; j < k + 4 && j < t1->h; ++j) { + vsc = ((cblksty & J2K_CCP_CBLKSTY_VSC) && (j == k + 3 || j == t1->h - 1)) ? 1 : 0; + t1_enc_refpass_step( + t1, + &t1->flags[((j+1) * t1->flags_stride) + i + 1], + &t1->data[(j * t1->w) + i], + bpno, + one, + nmsedec, + type, + vsc); + } + } + } +} + +static void t1_dec_refpass_raw( + opj_t1_t *t1, + int bpno, + int cblksty) +{ + int i, j, k, one, poshalf, neghalf; + int vsc; + one = 1 << bpno; + poshalf = one >> 1; + neghalf = bpno > 0 ? -poshalf : -1; + for (k = 0; k < t1->h; k += 4) { + for (i = 0; i < t1->w; ++i) { + for (j = k; j < k + 4 && j < t1->h; ++j) { + vsc = ((cblksty & J2K_CCP_CBLKSTY_VSC) && (j == k + 3 || j == t1->h - 1)) ? 1 : 0; + t1_dec_refpass_step_raw( + t1, + &t1->flags[((j+1) * t1->flags_stride) + i + 1], + &t1->data[(j * t1->w) + i], + poshalf, + neghalf, + vsc); + } + } + } +} /* VSC and BYPASS by Antonin */ + +static void t1_dec_refpass_mqc( + opj_t1_t *t1, + int bpno) +{ + int i, j, k, one, poshalf, neghalf; + int *data1 = t1->data; + flag_t *flags1 = &t1->flags[1]; + one = 1 << bpno; + poshalf = one >> 1; + neghalf = bpno > 0 ? -poshalf : -1; + for (k = 0; k < (t1->h & ~3); k += 4) { + for (i = 0; i < t1->w; ++i) { + int *data2 = data1 + i; + flag_t *flags2 = flags1 + i; + flags2 += t1->flags_stride; + t1_dec_refpass_step_mqc(t1, flags2, data2, poshalf, neghalf); + data2 += t1->w; + flags2 += t1->flags_stride; + t1_dec_refpass_step_mqc(t1, flags2, data2, poshalf, neghalf); + data2 += t1->w; + flags2 += t1->flags_stride; + t1_dec_refpass_step_mqc(t1, flags2, data2, poshalf, neghalf); + data2 += t1->w; + flags2 += t1->flags_stride; + t1_dec_refpass_step_mqc(t1, flags2, data2, poshalf, neghalf); + data2 += t1->w; + } + data1 += t1->w << 2; + flags1 += t1->flags_stride << 2; + } + for (i = 0; i < t1->w; ++i) { + int *data2 = data1 + i; + flag_t *flags2 = flags1 + i; + for (j = k; j < t1->h; ++j) { + flags2 += t1->flags_stride; + t1_dec_refpass_step_mqc(t1, flags2, data2, poshalf, neghalf); + data2 += t1->w; + } + } +} /* VSC and BYPASS by Antonin */ + +static void t1_dec_refpass_mqc_vsc( + opj_t1_t *t1, + int bpno) +{ + int i, j, k, one, poshalf, neghalf; + int vsc; + one = 1 << bpno; + poshalf = one >> 1; + neghalf = bpno > 0 ? -poshalf : -1; + for (k = 0; k < t1->h; k += 4) { + for (i = 0; i < t1->w; ++i) { + for (j = k; j < k + 4 && j < t1->h; ++j) { + vsc = ((j == k + 3 || j == t1->h - 1)) ? 1 : 0; + t1_dec_refpass_step_mqc_vsc( + t1, + &t1->flags[((j+1) * t1->flags_stride) + i + 1], + &t1->data[(j * t1->w) + i], + poshalf, + neghalf, + vsc); + } + } + } +} /* VSC and BYPASS by Antonin */ + +static void t1_enc_clnpass_step( + opj_t1_t *t1, + flag_t *flagsp, + int *datap, + int orient, + int bpno, + int one, + int *nmsedec, + int partial, + int vsc) +{ + int v, flag; + + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + flag = vsc ? ((*flagsp) & (~(T1_SIG_S | T1_SIG_SE | T1_SIG_SW | T1_SGN_S))) : (*flagsp); + if (partial) { + goto LABEL_PARTIAL; + } + if (!(*flagsp & (T1_SIG | T1_VISIT))) { + mqc_setcurctx(mqc, t1_getctxno_zc(flag, orient)); + v = int_abs(*datap) & one ? 1 : 0; + mqc_encode(mqc, v); + if (v) { +LABEL_PARTIAL: + *nmsedec += t1_getnmsedec_sig(int_abs(*datap), bpno + T1_NMSEDEC_FRACBITS); + mqc_setcurctx(mqc, t1_getctxno_sc(flag)); + v = *datap < 0 ? 1 : 0; + mqc_encode(mqc, v ^ t1_getspb(flag)); + t1_updateflags(flagsp, v, t1->flags_stride); + } + } + *flagsp &= ~T1_VISIT; +} + +static void t1_dec_clnpass_step_partial( + opj_t1_t *t1, + flag_t *flagsp, + int *datap, + int orient, + int oneplushalf) +{ + int v, flag; + + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + flag = *flagsp; + mqc_setcurctx(mqc, t1_getctxno_sc(flag)); + v = mqc_decode(mqc) ^ t1_getspb(flag); + *datap = v ? -oneplushalf : oneplushalf; + t1_updateflags(flagsp, v, t1->flags_stride); + *flagsp &= ~T1_VISIT; +} /* VSC and BYPASS by Antonin */ + +static void t1_dec_clnpass_step( + opj_t1_t *t1, + flag_t *flagsp, + int *datap, + int orient, + int oneplushalf) +{ + int v, flag; + + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + flag = *flagsp; + if (!(flag & (T1_SIG | T1_VISIT))) { + mqc_setcurctx(mqc, t1_getctxno_zc(flag, orient)); + if (mqc_decode(mqc)) { + mqc_setcurctx(mqc, t1_getctxno_sc(flag)); + v = mqc_decode(mqc) ^ t1_getspb(flag); + *datap = v ? -oneplushalf : oneplushalf; + t1_updateflags(flagsp, v, t1->flags_stride); + } + } + *flagsp &= ~T1_VISIT; +} /* VSC and BYPASS by Antonin */ + +static void t1_dec_clnpass_step_vsc( + opj_t1_t *t1, + flag_t *flagsp, + int *datap, + int orient, + int oneplushalf, + int partial, + int vsc) +{ + int v, flag; + + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + flag = vsc ? ((*flagsp) & (~(T1_SIG_S | T1_SIG_SE | T1_SIG_SW | T1_SGN_S))) : (*flagsp); + if (partial) { + goto LABEL_PARTIAL; + } + if (!(flag & (T1_SIG | T1_VISIT))) { + mqc_setcurctx(mqc, t1_getctxno_zc(flag, orient)); + if (mqc_decode(mqc)) { +LABEL_PARTIAL: + mqc_setcurctx(mqc, t1_getctxno_sc(flag)); + v = mqc_decode(mqc) ^ t1_getspb(flag); + *datap = v ? -oneplushalf : oneplushalf; + t1_updateflags(flagsp, v, t1->flags_stride); + } + } + *flagsp &= ~T1_VISIT; +} + +static void t1_enc_clnpass( + opj_t1_t *t1, + int bpno, + int orient, + int *nmsedec, + int cblksty) +{ + int i, j, k, one, agg, runlen, vsc; + + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + *nmsedec = 0; + one = 1 << (bpno + T1_NMSEDEC_FRACBITS); + for (k = 0; k < t1->h; k += 4) { + for (i = 0; i < t1->w; ++i) { + if (k + 3 < t1->h) { + if (cblksty & J2K_CCP_CBLKSTY_VSC) { + agg = !(MACRO_t1_flags(1 + k,1 + i) & (T1_SIG | T1_VISIT | T1_SIG_OTH) + || MACRO_t1_flags(1 + k + 1,1 + i) & (T1_SIG | T1_VISIT | T1_SIG_OTH) + || MACRO_t1_flags(1 + k + 2,1 + i) & (T1_SIG | T1_VISIT | T1_SIG_OTH) + || (MACRO_t1_flags(1 + k + 3,1 + i) + & (~(T1_SIG_S | T1_SIG_SE | T1_SIG_SW | T1_SGN_S))) & (T1_SIG | T1_VISIT | T1_SIG_OTH)); + } else { + agg = !(MACRO_t1_flags(1 + k,1 + i) & (T1_SIG | T1_VISIT | T1_SIG_OTH) + || MACRO_t1_flags(1 + k + 1,1 + i) & (T1_SIG | T1_VISIT | T1_SIG_OTH) + || MACRO_t1_flags(1 + k + 2,1 + i) & (T1_SIG | T1_VISIT | T1_SIG_OTH) + || MACRO_t1_flags(1 + k + 3,1 + i) & (T1_SIG | T1_VISIT | T1_SIG_OTH)); + } + } else { + agg = 0; + } + if (agg) { + for (runlen = 0; runlen < 4; ++runlen) { + if (int_abs(t1->data[((k + runlen)*t1->w) + i]) & one) + break; + } + mqc_setcurctx(mqc, T1_CTXNO_AGG); + mqc_encode(mqc, runlen != 4); + if (runlen == 4) { + continue; + } + mqc_setcurctx(mqc, T1_CTXNO_UNI); + mqc_encode(mqc, runlen >> 1); + mqc_encode(mqc, runlen & 1); + } else { + runlen = 0; + } + for (j = k + runlen; j < k + 4 && j < t1->h; ++j) { + vsc = ((cblksty & J2K_CCP_CBLKSTY_VSC) && (j == k + 3 || j == t1->h - 1)) ? 1 : 0; + t1_enc_clnpass_step( + t1, + &t1->flags[((j+1) * t1->flags_stride) + i + 1], + &t1->data[(j * t1->w) + i], + orient, + bpno, + one, + nmsedec, + agg && (j == k + runlen), + vsc); + } + } + } +} + +static void t1_dec_clnpass( + opj_t1_t *t1, + int bpno, + int orient, + int cblksty) +{ + int i, j, k, one, half, oneplushalf, agg, runlen, vsc; + int segsym = cblksty & J2K_CCP_CBLKSTY_SEGSYM; + + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + one = 1 << bpno; + half = one >> 1; + oneplushalf = one | half; + if (cblksty & J2K_CCP_CBLKSTY_VSC) { + for (k = 0; k < t1->h; k += 4) { + for (i = 0; i < t1->w; ++i) { + if (k + 3 < t1->h) { + agg = !(MACRO_t1_flags(1 + k,1 + i) & (T1_SIG | T1_VISIT | T1_SIG_OTH) + || MACRO_t1_flags(1 + k + 1,1 + i) & (T1_SIG | T1_VISIT | T1_SIG_OTH) + || MACRO_t1_flags(1 + k + 2,1 + i) & (T1_SIG | T1_VISIT | T1_SIG_OTH) + || (MACRO_t1_flags(1 + k + 3,1 + i) + & (~(T1_SIG_S | T1_SIG_SE | T1_SIG_SW | T1_SGN_S))) & (T1_SIG | T1_VISIT | T1_SIG_OTH)); + } else { + agg = 0; + } + if (agg) { + mqc_setcurctx(mqc, T1_CTXNO_AGG); + if (!mqc_decode(mqc)) { + continue; + } + mqc_setcurctx(mqc, T1_CTXNO_UNI); + runlen = mqc_decode(mqc); + runlen = (runlen << 1) | mqc_decode(mqc); + } else { + runlen = 0; + } + for (j = k + runlen; j < k + 4 && j < t1->h; ++j) { + vsc = (j == k + 3 || j == t1->h - 1) ? 1 : 0; + t1_dec_clnpass_step_vsc( + t1, + &t1->flags[((j+1) * t1->flags_stride) + i + 1], + &t1->data[(j * t1->w) + i], + orient, + oneplushalf, + agg && (j == k + runlen), + vsc); + } + } + } + } else { + int *data1 = t1->data; + flag_t *flags1 = &t1->flags[1]; + for (k = 0; k < (t1->h & ~3); k += 4) { + for (i = 0; i < t1->w; ++i) { + int *data2 = data1 + i; + flag_t *flags2 = flags1 + i; + agg = !(MACRO_t1_flags(1 + k,1 + i) & (T1_SIG | T1_VISIT | T1_SIG_OTH) + || MACRO_t1_flags(1 + k + 1,1 + i) & (T1_SIG | T1_VISIT | T1_SIG_OTH) + || MACRO_t1_flags(1 + k + 2,1 + i) & (T1_SIG | T1_VISIT | T1_SIG_OTH) + || MACRO_t1_flags(1 + k + 3,1 + i) & (T1_SIG | T1_VISIT | T1_SIG_OTH)); + if (agg) { + mqc_setcurctx(mqc, T1_CTXNO_AGG); + if (!mqc_decode(mqc)) { + continue; + } + mqc_setcurctx(mqc, T1_CTXNO_UNI); + runlen = mqc_decode(mqc); + runlen = (runlen << 1) | mqc_decode(mqc); + flags2 += runlen * t1->flags_stride; + data2 += runlen * t1->w; + for (j = k + runlen; j < k + 4 && j < t1->h; ++j) { + flags2 += t1->flags_stride; + if (agg && (j == k + runlen)) { + t1_dec_clnpass_step_partial(t1, flags2, data2, orient, oneplushalf); + } else { + t1_dec_clnpass_step(t1, flags2, data2, orient, oneplushalf); + } + data2 += t1->w; + } + } else { + flags2 += t1->flags_stride; + t1_dec_clnpass_step(t1, flags2, data2, orient, oneplushalf); + data2 += t1->w; + flags2 += t1->flags_stride; + t1_dec_clnpass_step(t1, flags2, data2, orient, oneplushalf); + data2 += t1->w; + flags2 += t1->flags_stride; + t1_dec_clnpass_step(t1, flags2, data2, orient, oneplushalf); + data2 += t1->w; + flags2 += t1->flags_stride; + t1_dec_clnpass_step(t1, flags2, data2, orient, oneplushalf); + data2 += t1->w; + } + } + data1 += t1->w << 2; + flags1 += t1->flags_stride << 2; + } + for (i = 0; i < t1->w; ++i) { + int *data2 = data1 + i; + flag_t *flags2 = flags1 + i; + for (j = k; j < t1->h; ++j) { + flags2 += t1->flags_stride; + t1_dec_clnpass_step(t1, flags2, data2, orient, oneplushalf); + data2 += t1->w; + } + } + } + + if (segsym) { + int v = 0; + mqc_setcurctx(mqc, T1_CTXNO_UNI); + v = mqc_decode(mqc); + v = (v << 1) | mqc_decode(mqc); + v = (v << 1) | mqc_decode(mqc); + v = (v << 1) | mqc_decode(mqc); + /* + if (v!=0xa) { + opj_event_msg(t1->cinfo, EVT_WARNING, "Bad segmentation symbol %x\n", v); + } + */ + } +} /* VSC and BYPASS by Antonin */ + + +/** mod fixed_quality */ +static double t1_getwmsedec( + int nmsedec, + int compno, + int level, + int orient, + int bpno, + int qmfbid, + double stepsize, + int numcomps, + int mct) +{ + double w1, w2, wmsedec; + if (qmfbid == 1) { + w1 = (mct && numcomps==3) ? mct_getnorm(compno) : 1.0; + w2 = dwt_getnorm(level, orient); + } else { /* if (qmfbid == 0) */ + w1 = (mct && numcomps==3) ? mct_getnorm_real(compno) : 1.0; + w2 = dwt_getnorm_real(level, orient); + } + wmsedec = w1 * w2 * stepsize * (1 << bpno); + wmsedec *= wmsedec * nmsedec / 8192.0; + + return wmsedec; +} + +static bool allocate_buffers( + opj_t1_t *t1, + int w, + int h) +{ + int datasize=w * h; + int flagssize; + + if(datasize > t1->datasize){ + opj_aligned_free(t1->data); + t1->data = (int*) opj_aligned_malloc(datasize * sizeof(int)); + if(!t1->data){ + return false; + } + t1->datasize=datasize; + } + memset(t1->data,0,datasize * sizeof(int)); + + t1->flags_stride=w+2; + flagssize=t1->flags_stride * (h+2); + + if(flagssize > t1->flagssize){ + opj_aligned_free(t1->flags); + t1->flags = (flag_t*) opj_aligned_malloc(flagssize * sizeof(flag_t)); + if(!t1->flags){ + return false; + } + t1->flagssize=flagssize; + } + memset(t1->flags,0,flagssize * sizeof(flag_t)); + + t1->w=w; + t1->h=h; + + return true; +} + +/** mod fixed_quality */ +static void t1_encode_cblk( + opj_t1_t *t1, + opj_tcd_cblk_enc_t* cblk, + int orient, + int compno, + int level, + int qmfbid, + double stepsize, + int cblksty, + int numcomps, + int mct, + opj_tcd_tile_t * tile) +{ + double cumwmsedec = 0.0; + + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + int passno, bpno, passtype; + int nmsedec = 0; + int i, max; + char type = T1_TYPE_MQ; + double tempwmsedec; + + max = 0; + for (i = 0; i < t1->w * t1->h; ++i) { + int tmp = abs(t1->data[i]); + max = int_max(max, tmp); + } + + cblk->numbps = max ? (int_floorlog2(max) + 1) - T1_NMSEDEC_FRACBITS : 0; + + bpno = cblk->numbps - 1; + passtype = 2; + + mqc_resetstates(mqc); + mqc_setstate(mqc, T1_CTXNO_UNI, 0, 46); + mqc_setstate(mqc, T1_CTXNO_AGG, 0, 3); + mqc_setstate(mqc, T1_CTXNO_ZC, 0, 4); + mqc_init_enc(mqc, cblk->data); + + for (passno = 0; bpno >= 0; ++passno) { + opj_tcd_pass_t *pass = &cblk->passes[passno]; + int correction = 3; + type = ((bpno < (cblk->numbps - 4)) && (passtype < 2) && (cblksty & J2K_CCP_CBLKSTY_LAZY)) ? T1_TYPE_RAW : T1_TYPE_MQ; + + switch (passtype) { + case 0: + t1_enc_sigpass(t1, bpno, orient, &nmsedec, type, cblksty); + break; + case 1: + t1_enc_refpass(t1, bpno, &nmsedec, type, cblksty); + break; + case 2: + t1_enc_clnpass(t1, bpno, orient, &nmsedec, cblksty); + /* code switch SEGMARK (i.e. SEGSYM) */ + if (cblksty & J2K_CCP_CBLKSTY_SEGSYM) + mqc_segmark_enc(mqc); + break; + } + + /* fixed_quality */ + tempwmsedec = t1_getwmsedec(nmsedec, compno, level, orient, bpno, qmfbid, stepsize, numcomps, mct); + cumwmsedec += tempwmsedec; + tile->distotile += tempwmsedec; + + /* Code switch "RESTART" (i.e. TERMALL) */ + if ((cblksty & J2K_CCP_CBLKSTY_TERMALL) && !((passtype == 2) && (bpno - 1 < 0))) { + if (type == T1_TYPE_RAW) { + mqc_flush(mqc); + correction = 1; + /* correction = mqc_bypass_flush_enc(); */ + } else { /* correction = mqc_restart_enc(); */ + mqc_flush(mqc); + correction = 1; + } + pass->term = 1; + } else { + if (((bpno < (cblk->numbps - 4) && (passtype > 0)) + || ((bpno == (cblk->numbps - 4)) && (passtype == 2))) && (cblksty & J2K_CCP_CBLKSTY_LAZY)) { + if (type == T1_TYPE_RAW) { + mqc_flush(mqc); + correction = 1; + /* correction = mqc_bypass_flush_enc(); */ + } else { /* correction = mqc_restart_enc(); */ + mqc_flush(mqc); + correction = 1; + } + pass->term = 1; + } else { + pass->term = 0; + } + } + + if (++passtype == 3) { + passtype = 0; + bpno--; + } + + if (pass->term && bpno > 0) { + type = ((bpno < (cblk->numbps - 4)) && (passtype < 2) && (cblksty & J2K_CCP_CBLKSTY_LAZY)) ? T1_TYPE_RAW : T1_TYPE_MQ; + if (type == T1_TYPE_RAW) + mqc_bypass_init_enc(mqc); + else + mqc_restart_init_enc(mqc); + } + + pass->distortiondec = cumwmsedec; + pass->rate = mqc_numbytes(mqc) + correction; /* FIXME */ + + /* Code-switch "RESET" */ + if (cblksty & J2K_CCP_CBLKSTY_RESET) + mqc_reset_enc(mqc); + } + + /* Code switch "ERTERM" (i.e. PTERM) */ + if (cblksty & J2K_CCP_CBLKSTY_PTERM) + mqc_erterm_enc(mqc); + else /* Default coding */ if (!(cblksty & J2K_CCP_CBLKSTY_LAZY)) + mqc_flush(mqc); + + cblk->totalpasses = passno; + + for (passno = 0; passnototalpasses; passno++) { + opj_tcd_pass_t *pass = &cblk->passes[passno]; + if (pass->rate > mqc_numbytes(mqc)) + pass->rate = mqc_numbytes(mqc); + /*Preventing generation of FF as last data byte of a pass*/ + if((pass->rate>1) && (cblk->data[pass->rate - 1] == 0xFF)){ + pass->rate--; + } + pass->len = pass->rate - (passno == 0 ? 0 : cblk->passes[passno - 1].rate); + } +} + +static void t1_decode_cblk( + opj_t1_t *t1, + opj_tcd_cblk_dec_t* cblk, + int orient, + int roishift, + int cblksty) +{ + opj_raw_t *raw = t1->raw; /* RAW component */ + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + int bpno, passtype; + int segno, passno; + char type = T1_TYPE_MQ; /* BYPASS mode */ + + if(!allocate_buffers( + t1, + cblk->x1 - cblk->x0, + cblk->y1 - cblk->y0)) + { + return; + } + + bpno = roishift + cblk->numbps - 1; + passtype = 2; + + mqc_resetstates(mqc); + mqc_setstate(mqc, T1_CTXNO_UNI, 0, 46); + mqc_setstate(mqc, T1_CTXNO_AGG, 0, 3); + mqc_setstate(mqc, T1_CTXNO_ZC, 0, 4); + + for (segno = 0; segno < cblk->numsegs; ++segno) { + opj_tcd_seg_t *seg = &cblk->segs[segno]; + + /* BYPASS mode */ + type = ((bpno <= (cblk->numbps - 1) - 4) && (passtype < 2) && (cblksty & J2K_CCP_CBLKSTY_LAZY)) ? T1_TYPE_RAW : T1_TYPE_MQ; + /* FIXME: slviewer gets here with a null pointer. Why? Partially downloaded and/or corrupt textures? */ + if(seg->data == NULL){ + continue; + } + if (type == T1_TYPE_RAW) { + raw_init_dec(raw, (*seg->data) + seg->dataindex, seg->len); + } else { + mqc_init_dec(mqc, (*seg->data) + seg->dataindex, seg->len); + } + + for (passno = 0; passno < seg->numpasses; ++passno) { + switch (passtype) { + case 0: + if (type == T1_TYPE_RAW) { + t1_dec_sigpass_raw(t1, bpno+1, orient, cblksty); + } else { + if (cblksty & J2K_CCP_CBLKSTY_VSC) { + t1_dec_sigpass_mqc_vsc(t1, bpno+1, orient); + } else { + t1_dec_sigpass_mqc(t1, bpno+1, orient); + } + } + break; + case 1: + if (type == T1_TYPE_RAW) { + t1_dec_refpass_raw(t1, bpno+1, cblksty); + } else { + if (cblksty & J2K_CCP_CBLKSTY_VSC) { + t1_dec_refpass_mqc_vsc(t1, bpno+1); + } else { + t1_dec_refpass_mqc(t1, bpno+1); + } + } + break; + case 2: + t1_dec_clnpass(t1, bpno+1, orient, cblksty); + break; + } + + if ((cblksty & J2K_CCP_CBLKSTY_RESET) && type == T1_TYPE_MQ) { + mqc_resetstates(mqc); + mqc_setstate(mqc, T1_CTXNO_UNI, 0, 46); + mqc_setstate(mqc, T1_CTXNO_AGG, 0, 3); + mqc_setstate(mqc, T1_CTXNO_ZC, 0, 4); + } + if (++passtype == 3) { + passtype = 0; + bpno--; + } + } + } +} + +/* ----------------------------------------------------------------------- */ + +opj_t1_t* t1_create(opj_common_ptr cinfo) { + opj_t1_t *t1 = (opj_t1_t*) opj_malloc(sizeof(opj_t1_t)); + if(!t1) + return NULL; + + t1->cinfo = cinfo; + /* create MQC and RAW handles */ + t1->mqc = mqc_create(); + t1->raw = raw_create(); + + t1->data=NULL; + t1->flags=NULL; + t1->datasize=0; + t1->flagssize=0; + + return t1; +} + +void t1_destroy(opj_t1_t *t1) { + if(t1) { + /* destroy MQC and RAW handles */ + mqc_destroy(t1->mqc); + raw_destroy(t1->raw); + opj_aligned_free(t1->data); + opj_aligned_free(t1->flags); + opj_free(t1); + } +} + +void t1_encode_cblks( + opj_t1_t *t1, + opj_tcd_tile_t *tile, + opj_tcp_t *tcp) +{ + int compno, resno, bandno, precno, cblkno; + + tile->distotile = 0; /* fixed_quality */ + + for (compno = 0; compno < tile->numcomps; ++compno) { + opj_tcd_tilecomp_t* tilec = &tile->comps[compno]; + opj_tccp_t* tccp = &tcp->tccps[compno]; + int tile_w = tilec->x1 - tilec->x0; + + for (resno = 0; resno < tilec->numresolutions; ++resno) { + opj_tcd_resolution_t *res = &tilec->resolutions[resno]; + + for (bandno = 0; bandno < res->numbands; ++bandno) { + opj_tcd_band_t* restrict band = &res->bands[bandno]; + + for (precno = 0; precno < res->pw * res->ph; ++precno) { + opj_tcd_precinct_t *prc = &band->precincts[precno]; + + for (cblkno = 0; cblkno < prc->cw * prc->ch; ++cblkno) { + opj_tcd_cblk_enc_t* cblk = &prc->cblks.enc[cblkno]; + int* restrict datap; + int* restrict tiledp; + int cblk_w; + int cblk_h; + int i, j; + + int x = cblk->x0 - band->x0; + int y = cblk->y0 - band->y0; + if (band->bandno & 1) { + opj_tcd_resolution_t *pres = &tilec->resolutions[resno - 1]; + x += pres->x1 - pres->x0; + } + if (band->bandno & 2) { + opj_tcd_resolution_t *pres = &tilec->resolutions[resno - 1]; + y += pres->y1 - pres->y0; + } + + if(!allocate_buffers( + t1, + cblk->x1 - cblk->x0, + cblk->y1 - cblk->y0)) + { + return; + } + + datap=t1->data; + cblk_w = t1->w; + cblk_h = t1->h; + + tiledp=&tilec->data[(y * tile_w) + x]; + if (tccp->qmfbid == 1) { + for (j = 0; j < cblk_h; ++j) { + for (i = 0; i < cblk_w; ++i) { + int tmp = tiledp[(j * tile_w) + i]; + datap[(j * cblk_w) + i] = tmp << T1_NMSEDEC_FRACBITS; + } + } + } else { /* if (tccp->qmfbid == 0) */ + for (j = 0; j < cblk_h; ++j) { + for (i = 0; i < cblk_w; ++i) { + int tmp = tiledp[(j * tile_w) + i]; + datap[(j * cblk_w) + i] = + fix_mul( + tmp, + 8192 * 8192 / ((int) floor(band->stepsize * 8192))) >> (11 - T1_NMSEDEC_FRACBITS); + } + } + } + + t1_encode_cblk( + t1, + cblk, + band->bandno, + compno, + tilec->numresolutions - 1 - resno, + tccp->qmfbid, + band->stepsize, + tccp->cblksty, + tile->numcomps, + tcp->mct, + tile); + + } /* cblkno */ + } /* precno */ + } /* bandno */ + } /* resno */ + } /* compno */ +} + +void t1_decode_cblks( + opj_t1_t* t1, + opj_tcd_tilecomp_t* tilec, + opj_tccp_t* tccp) +{ + int resno, bandno, precno, cblkno; + + int tile_w = tilec->x1 - tilec->x0; + + for (resno = 0; resno < tilec->numresolutions; ++resno) { + opj_tcd_resolution_t* res = &tilec->resolutions[resno]; + + for (bandno = 0; bandno < res->numbands; ++bandno) { + opj_tcd_band_t* restrict band = &res->bands[bandno]; + + for (precno = 0; precno < res->pw * res->ph; ++precno) { + opj_tcd_precinct_t* precinct = &band->precincts[precno]; + + for (cblkno = 0; cblkno < precinct->cw * precinct->ch; ++cblkno) { + opj_tcd_cblk_dec_t* cblk = &precinct->cblks.dec[cblkno]; + int* restrict datap; + int cblk_w, cblk_h; + int x, y; + int i, j; + + t1_decode_cblk( + t1, + cblk, + band->bandno, + tccp->roishift, + tccp->cblksty); + + x = cblk->x0 - band->x0; + y = cblk->y0 - band->y0; + if (band->bandno & 1) { + opj_tcd_resolution_t* pres = &tilec->resolutions[resno - 1]; + x += pres->x1 - pres->x0; + } + if (band->bandno & 2) { + opj_tcd_resolution_t* pres = &tilec->resolutions[resno - 1]; + y += pres->y1 - pres->y0; + } + + datap=t1->data; + cblk_w = t1->w; + cblk_h = t1->h; + + if (tccp->roishift) { + int thresh = 1 << tccp->roishift; + for (j = 0; j < cblk_h; ++j) { + for (i = 0; i < cblk_w; ++i) { + int val = datap[(j * cblk_w) + i]; + int mag = abs(val); + if (mag >= thresh) { + mag >>= tccp->roishift; + datap[(j * cblk_w) + i] = val < 0 ? -mag : mag; + } + } + } + } + + if (tccp->qmfbid == 1) { + int* restrict tiledp = &tilec->data[(y * tile_w) + x]; + for (j = 0; j < cblk_h; ++j) { + for (i = 0; i < cblk_w; ++i) { + int tmp = datap[(j * cblk_w) + i]; + ((int*)tiledp)[(j * tile_w) + i] = tmp / 2; + } + } + } else { /* if (tccp->qmfbid == 0) */ + float* restrict tiledp = (float*) &tilec->data[(y * tile_w) + x]; + for (j = 0; j < cblk_h; ++j) { + float* restrict tiledp2 = tiledp; + for (i = 0; i < cblk_w; ++i) { + float tmp = *datap * band->stepsize; + *tiledp2 = tmp; + datap++; + tiledp2++; + } + tiledp += tile_w; + } + } + opj_free(cblk->data); + opj_free(cblk->segs); + } /* cblkno */ + opj_free(precinct->cblks.dec); + } /* precno */ + } /* bandno */ + } /* resno */ +} + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/t1.h b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/t1.h new file mode 100644 index 0000000..572ec88 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/t1.h @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __T1_H +#define __T1_H +/** +@file t1.h +@brief Implementation of the tier-1 coding (coding of code-block coefficients) (T1) + +The functions in T1.C have for goal to realize the tier-1 coding operation. The functions +in T1.C are used by some function in TCD.C. +*/ + +/** @defgroup T1 T1 - Implementation of the tier-1 coding */ +/*@{*/ + +/* ----------------------------------------------------------------------- */ +#define T1_NMSEDEC_BITS 7 + +#define T1_SIG_NE 0x0001 /**< Context orientation : North-East direction */ +#define T1_SIG_SE 0x0002 /**< Context orientation : South-East direction */ +#define T1_SIG_SW 0x0004 /**< Context orientation : South-West direction */ +#define T1_SIG_NW 0x0008 /**< Context orientation : North-West direction */ +#define T1_SIG_N 0x0010 /**< Context orientation : North direction */ +#define T1_SIG_E 0x0020 /**< Context orientation : East direction */ +#define T1_SIG_S 0x0040 /**< Context orientation : South direction */ +#define T1_SIG_W 0x0080 /**< Context orientation : West direction */ +#define T1_SIG_OTH (T1_SIG_N|T1_SIG_NE|T1_SIG_E|T1_SIG_SE|T1_SIG_S|T1_SIG_SW|T1_SIG_W|T1_SIG_NW) +#define T1_SIG_PRIM (T1_SIG_N|T1_SIG_E|T1_SIG_S|T1_SIG_W) + +#define T1_SGN_N 0x0100 +#define T1_SGN_E 0x0200 +#define T1_SGN_S 0x0400 +#define T1_SGN_W 0x0800 +#define T1_SGN (T1_SGN_N|T1_SGN_E|T1_SGN_S|T1_SGN_W) + +#define T1_SIG 0x1000 +#define T1_REFINE 0x2000 +#define T1_VISIT 0x4000 + +#define T1_NUMCTXS_ZC 9 +#define T1_NUMCTXS_SC 5 +#define T1_NUMCTXS_MAG 3 +#define T1_NUMCTXS_AGG 1 +#define T1_NUMCTXS_UNI 1 + +#define T1_CTXNO_ZC 0 +#define T1_CTXNO_SC (T1_CTXNO_ZC+T1_NUMCTXS_ZC) +#define T1_CTXNO_MAG (T1_CTXNO_SC+T1_NUMCTXS_SC) +#define T1_CTXNO_AGG (T1_CTXNO_MAG+T1_NUMCTXS_MAG) +#define T1_CTXNO_UNI (T1_CTXNO_AGG+T1_NUMCTXS_AGG) +#define T1_NUMCTXS (T1_CTXNO_UNI+T1_NUMCTXS_UNI) + +#define T1_NMSEDEC_FRACBITS (T1_NMSEDEC_BITS-1) + +#define T1_TYPE_MQ 0 /**< Normal coding using entropy coder */ +#define T1_TYPE_RAW 1 /**< No encoding the information is store under raw format in codestream (mode switch RAW)*/ + +/* ----------------------------------------------------------------------- */ + +typedef short flag_t; + +/** +Tier-1 coding (coding of code-block coefficients) +*/ +typedef struct opj_t1 { + /** codec context */ + opj_common_ptr cinfo; + + /** MQC component */ + opj_mqc_t *mqc; + /** RAW component */ + opj_raw_t *raw; + + int *data; + flag_t *flags; + int w; + int h; + int datasize; + int flagssize; + int flags_stride; +} opj_t1_t; + +#define MACRO_t1_flags(x,y) t1->flags[((x)*(t1->flags_stride))+(y)] + +/** @name Exported functions */ +/*@{*/ +/* ----------------------------------------------------------------------- */ +/** +Create a new T1 handle +and initialize the look-up tables of the Tier-1 coder/decoder +@return Returns a new T1 handle if successful, returns NULL otherwise +@see t1_init_luts +*/ +opj_t1_t* t1_create(opj_common_ptr cinfo); +/** +Destroy a previously created T1 handle +@param t1 T1 handle to destroy +*/ +void t1_destroy(opj_t1_t *t1); +/** +Encode the code-blocks of a tile +@param t1 T1 handle +@param tile The tile to encode +@param tcp Tile coding parameters +*/ +void t1_encode_cblks(opj_t1_t *t1, opj_tcd_tile_t *tile, opj_tcp_t *tcp); +/** +Decode the code-blocks of a tile +@param t1 T1 handle +@param tilec The tile to decode +@param tccp Tile coding parameters +*/ +void t1_decode_cblks(opj_t1_t* t1, opj_tcd_tilecomp_t* tilec, opj_tccp_t* tccp); +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __T1_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/t1_generate_luts.c b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/t1_generate_luts.c new file mode 100644 index 0000000..3988041 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/t1_generate_luts.c @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2007, Callum Lerwick + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "opj_includes.h" +#include + +static int t1_init_ctxno_zc(int f, int orient) { + int h, v, d, n, t, hv; + n = 0; + h = ((f & T1_SIG_W) != 0) + ((f & T1_SIG_E) != 0); + v = ((f & T1_SIG_N) != 0) + ((f & T1_SIG_S) != 0); + d = ((f & T1_SIG_NW) != 0) + ((f & T1_SIG_NE) != 0) + ((f & T1_SIG_SE) != 0) + ((f & T1_SIG_SW) != 0); + + switch (orient) { + case 2: + t = h; + h = v; + v = t; + case 0: + case 1: + if (!h) { + if (!v) { + if (!d) + n = 0; + else if (d == 1) + n = 1; + else + n = 2; + } else if (v == 1) { + n = 3; + } else { + n = 4; + } + } else if (h == 1) { + if (!v) { + if (!d) + n = 5; + else + n = 6; + } else { + n = 7; + } + } else + n = 8; + break; + case 3: + hv = h + v; + if (!d) { + if (!hv) { + n = 0; + } else if (hv == 1) { + n = 1; + } else { + n = 2; + } + } else if (d == 1) { + if (!hv) { + n = 3; + } else if (hv == 1) { + n = 4; + } else { + n = 5; + } + } else if (d == 2) { + if (!hv) { + n = 6; + } else { + n = 7; + } + } else { + n = 8; + } + break; + } + + return (T1_CTXNO_ZC + n); +} + +static int t1_init_ctxno_sc(int f) { + int hc, vc, n; + n = 0; + + hc = int_min(((f & (T1_SIG_E | T1_SGN_E)) == + T1_SIG_E) + ((f & (T1_SIG_W | T1_SGN_W)) == T1_SIG_W), + 1) - int_min(((f & (T1_SIG_E | T1_SGN_E)) == + (T1_SIG_E | T1_SGN_E)) + + ((f & (T1_SIG_W | T1_SGN_W)) == + (T1_SIG_W | T1_SGN_W)), 1); + + vc = int_min(((f & (T1_SIG_N | T1_SGN_N)) == + T1_SIG_N) + ((f & (T1_SIG_S | T1_SGN_S)) == T1_SIG_S), + 1) - int_min(((f & (T1_SIG_N | T1_SGN_N)) == + (T1_SIG_N | T1_SGN_N)) + + ((f & (T1_SIG_S | T1_SGN_S)) == + (T1_SIG_S | T1_SGN_S)), 1); + + if (hc < 0) { + hc = -hc; + vc = -vc; + } + if (!hc) { + if (vc == -1) + n = 1; + else if (!vc) + n = 0; + else + n = 1; + } else if (hc == 1) { + if (vc == -1) + n = 2; + else if (!vc) + n = 3; + else + n = 4; + } + + return (T1_CTXNO_SC + n); +} + +static int t1_init_spb(int f) { + int hc, vc, n; + + hc = int_min(((f & (T1_SIG_E | T1_SGN_E)) == + T1_SIG_E) + ((f & (T1_SIG_W | T1_SGN_W)) == T1_SIG_W), + 1) - int_min(((f & (T1_SIG_E | T1_SGN_E)) == + (T1_SIG_E | T1_SGN_E)) + + ((f & (T1_SIG_W | T1_SGN_W)) == + (T1_SIG_W | T1_SGN_W)), 1); + + vc = int_min(((f & (T1_SIG_N | T1_SGN_N)) == + T1_SIG_N) + ((f & (T1_SIG_S | T1_SGN_S)) == T1_SIG_S), + 1) - int_min(((f & (T1_SIG_N | T1_SGN_N)) == + (T1_SIG_N | T1_SGN_N)) + + ((f & (T1_SIG_S | T1_SGN_S)) == + (T1_SIG_S | T1_SGN_S)), 1); + + if (!hc && !vc) + n = 0; + else + n = (!(hc > 0 || (!hc && vc > 0))); + + return n; +} + +void dump_array16(int array[],int size){ + int i; + --size; + for (i = 0; i < size; ++i) { + printf("0x%04x, ", array[i]); + if(!((i+1)&0x7)) + printf("\n "); + } + printf("0x%04x\n};\n\n", array[size]); +} + +int main(){ + int i, j; + double u, v, t; + + int lut_ctxno_zc[1024]; + int lut_nmsedec_sig[1 << T1_NMSEDEC_BITS]; + int lut_nmsedec_sig0[1 << T1_NMSEDEC_BITS]; + int lut_nmsedec_ref[1 << T1_NMSEDEC_BITS]; + int lut_nmsedec_ref0[1 << T1_NMSEDEC_BITS]; + + printf("/* This file was automatically generated by t1_generate_luts.c */\n\n"); + + // lut_ctxno_zc + for (j = 0; j < 4; ++j) { + for (i = 0; i < 256; ++i) { + int orient = j; + if (orient == 2) { + orient = 1; + } else if (orient == 1) { + orient = 2; + } + lut_ctxno_zc[(orient << 8) | i] = t1_init_ctxno_zc(i, j); + } + } + + printf("static char lut_ctxno_zc[1024] = {\n "); + for (i = 0; i < 1023; ++i) { + printf("%i, ", lut_ctxno_zc[i]); + if(!((i+1)&0x1f)) + printf("\n "); + } + printf("%i\n};\n\n", lut_ctxno_zc[1023]); + + // lut_ctxno_sc + printf("static char lut_ctxno_sc[256] = {\n "); + for (i = 0; i < 255; ++i) { + printf("0x%x, ", t1_init_ctxno_sc(i << 4)); + if(!((i+1)&0xf)) + printf("\n "); + } + printf("0x%x\n};\n\n", t1_init_ctxno_sc(255 << 4)); + + // lut_spb + printf("static char lut_spb[256] = {\n "); + for (i = 0; i < 255; ++i) { + printf("%i, ", t1_init_spb(i << 4)); + if(!((i+1)&0x1f)) + printf("\n "); + } + printf("%i\n};\n\n", t1_init_spb(255 << 4)); + + /* FIXME FIXME FIXME */ + /* fprintf(stdout,"nmsedec luts:\n"); */ + for (i = 0; i < (1 << T1_NMSEDEC_BITS); ++i) { + t = i / pow(2, T1_NMSEDEC_FRACBITS); + u = t; + v = t - 1.5; + lut_nmsedec_sig[i] = + int_max(0, + (int) (floor((u * u - v * v) * pow(2, T1_NMSEDEC_FRACBITS) + 0.5) / pow(2, T1_NMSEDEC_FRACBITS) * 8192.0)); + lut_nmsedec_sig0[i] = + int_max(0, + (int) (floor((u * u) * pow(2, T1_NMSEDEC_FRACBITS) + 0.5) / pow(2, T1_NMSEDEC_FRACBITS) * 8192.0)); + u = t - 1.0; + if (i & (1 << (T1_NMSEDEC_BITS - 1))) { + v = t - 1.5; + } else { + v = t - 0.5; + } + lut_nmsedec_ref[i] = + int_max(0, + (int) (floor((u * u - v * v) * pow(2, T1_NMSEDEC_FRACBITS) + 0.5) / pow(2, T1_NMSEDEC_FRACBITS) * 8192.0)); + lut_nmsedec_ref0[i] = + int_max(0, + (int) (floor((u * u) * pow(2, T1_NMSEDEC_FRACBITS) + 0.5) / pow(2, T1_NMSEDEC_FRACBITS) * 8192.0)); + } + + printf("static short lut_nmsedec_sig[1 << T1_NMSEDEC_BITS] = {\n "); + dump_array16(lut_nmsedec_sig, 1 << T1_NMSEDEC_BITS); + + printf("static short lut_nmsedec_sig0[1 << T1_NMSEDEC_BITS] = {\n "); + dump_array16(lut_nmsedec_sig0, 1 << T1_NMSEDEC_BITS); + + printf("static short lut_nmsedec_ref[1 << T1_NMSEDEC_BITS] = {\n "); + dump_array16(lut_nmsedec_ref, 1 << T1_NMSEDEC_BITS); + + printf("static short lut_nmsedec_ref0[1 << T1_NMSEDEC_BITS] = {\n "); + dump_array16(lut_nmsedec_ref0, 1 << T1_NMSEDEC_BITS); + + return 0; +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/t1_luts.h b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/t1_luts.h new file mode 100644 index 0000000..e5e33f6 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/t1_luts.h @@ -0,0 +1,143 @@ +/* This file was automatically generated by t1_generate_luts.c */ + +static char lut_ctxno_zc[1024] = { + 0, 1, 1, 2, 1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 0, 1, 1, 2, 1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 0, 1, 1, 2, 1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 0, 3, 3, 6, 3, 6, 6, 8, 3, 6, 6, 8, 6, 8, 8, 8, 1, 4, 4, 7, 4, 7, 7, 8, 4, 7, 7, 8, 7, 8, 8, 8, + 1, 4, 4, 7, 4, 7, 7, 8, 4, 7, 7, 8, 7, 8, 8, 8, 2, 5, 5, 7, 5, 7, 7, 8, 5, 7, 7, 8, 7, 8, 8, 8, + 1, 4, 4, 7, 4, 7, 7, 8, 4, 7, 7, 8, 7, 8, 8, 8, 2, 5, 5, 7, 5, 7, 7, 8, 5, 7, 7, 8, 7, 8, 8, 8, + 2, 5, 5, 7, 5, 7, 7, 8, 5, 7, 7, 8, 7, 8, 8, 8, 2, 5, 5, 7, 5, 7, 7, 8, 5, 7, 7, 8, 7, 8, 8, 8, + 1, 4, 4, 7, 4, 7, 7, 8, 4, 7, 7, 8, 7, 8, 8, 8, 2, 5, 5, 7, 5, 7, 7, 8, 5, 7, 7, 8, 7, 8, 8, 8, + 2, 5, 5, 7, 5, 7, 7, 8, 5, 7, 7, 8, 7, 8, 8, 8, 2, 5, 5, 7, 5, 7, 7, 8, 5, 7, 7, 8, 7, 8, 8, 8, + 2, 5, 5, 7, 5, 7, 7, 8, 5, 7, 7, 8, 7, 8, 8, 8, 2, 5, 5, 7, 5, 7, 7, 8, 5, 7, 7, 8, 7, 8, 8, 8, + 2, 5, 5, 7, 5, 7, 7, 8, 5, 7, 7, 8, 7, 8, 8, 8, 2, 5, 5, 7, 5, 7, 7, 8, 5, 7, 7, 8, 7, 8, 8, 8 +}; + +static char lut_ctxno_sc[256] = { + 0x9, 0xa, 0xc, 0xd, 0xa, 0xa, 0xd, 0xd, 0xc, 0xd, 0xc, 0xd, 0xd, 0xd, 0xd, 0xd, + 0x9, 0xa, 0xc, 0xb, 0xa, 0x9, 0xd, 0xc, 0xc, 0xb, 0xc, 0xb, 0xd, 0xc, 0xd, 0xc, + 0x9, 0xa, 0xc, 0xb, 0xa, 0xa, 0xb, 0xb, 0xc, 0xd, 0x9, 0xa, 0xd, 0xd, 0xa, 0xa, + 0x9, 0xa, 0xc, 0xd, 0xa, 0x9, 0xb, 0xc, 0xc, 0xb, 0x9, 0xa, 0xd, 0xc, 0xa, 0x9, + 0x9, 0xa, 0xc, 0xd, 0xa, 0x9, 0xb, 0xc, 0xc, 0xd, 0xc, 0xd, 0xb, 0xc, 0xb, 0xc, + 0x9, 0xa, 0xc, 0xb, 0xa, 0xa, 0xb, 0xb, 0xc, 0xb, 0xc, 0xb, 0xb, 0xb, 0xb, 0xb, + 0x9, 0xa, 0xc, 0xb, 0xa, 0x9, 0xd, 0xc, 0xc, 0xd, 0x9, 0xa, 0xb, 0xc, 0xa, 0x9, + 0x9, 0xa, 0xc, 0xd, 0xa, 0xa, 0xd, 0xd, 0xc, 0xb, 0x9, 0xa, 0xb, 0xb, 0xa, 0xa, + 0x9, 0xa, 0xc, 0xd, 0xa, 0xa, 0xd, 0xd, 0xc, 0xb, 0x9, 0xa, 0xb, 0xb, 0xa, 0xa, + 0x9, 0xa, 0xc, 0xb, 0xa, 0x9, 0xd, 0xc, 0xc, 0xd, 0x9, 0xa, 0xb, 0xc, 0xa, 0x9, + 0x9, 0xa, 0xc, 0xb, 0xa, 0xa, 0xb, 0xb, 0xc, 0xb, 0xc, 0xb, 0xb, 0xb, 0xb, 0xb, + 0x9, 0xa, 0xc, 0xd, 0xa, 0x9, 0xb, 0xc, 0xc, 0xd, 0xc, 0xd, 0xb, 0xc, 0xb, 0xc, + 0x9, 0xa, 0xc, 0xd, 0xa, 0x9, 0xb, 0xc, 0xc, 0xb, 0x9, 0xa, 0xd, 0xc, 0xa, 0x9, + 0x9, 0xa, 0xc, 0xb, 0xa, 0xa, 0xb, 0xb, 0xc, 0xd, 0x9, 0xa, 0xd, 0xd, 0xa, 0xa, + 0x9, 0xa, 0xc, 0xb, 0xa, 0x9, 0xd, 0xc, 0xc, 0xb, 0xc, 0xb, 0xd, 0xc, 0xd, 0xc, + 0x9, 0xa, 0xc, 0xd, 0xa, 0xa, 0xd, 0xd, 0xc, 0xd, 0xc, 0xd, 0xd, 0xd, 0xd, 0xd +}; + +static char lut_spb[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, + 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, + 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 +}; + +static short lut_nmsedec_sig[1 << T1_NMSEDEC_BITS] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0180, 0x0300, 0x0480, 0x0600, 0x0780, 0x0900, 0x0a80, + 0x0c00, 0x0d80, 0x0f00, 0x1080, 0x1200, 0x1380, 0x1500, 0x1680, + 0x1800, 0x1980, 0x1b00, 0x1c80, 0x1e00, 0x1f80, 0x2100, 0x2280, + 0x2400, 0x2580, 0x2700, 0x2880, 0x2a00, 0x2b80, 0x2d00, 0x2e80, + 0x3000, 0x3180, 0x3300, 0x3480, 0x3600, 0x3780, 0x3900, 0x3a80, + 0x3c00, 0x3d80, 0x3f00, 0x4080, 0x4200, 0x4380, 0x4500, 0x4680, + 0x4800, 0x4980, 0x4b00, 0x4c80, 0x4e00, 0x4f80, 0x5100, 0x5280, + 0x5400, 0x5580, 0x5700, 0x5880, 0x5a00, 0x5b80, 0x5d00, 0x5e80, + 0x6000, 0x6180, 0x6300, 0x6480, 0x6600, 0x6780, 0x6900, 0x6a80, + 0x6c00, 0x6d80, 0x6f00, 0x7080, 0x7200, 0x7380, 0x7500, 0x7680 +}; + +static short lut_nmsedec_sig0[1 << T1_NMSEDEC_BITS] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0080, 0x0080, + 0x0080, 0x0080, 0x0100, 0x0100, 0x0100, 0x0180, 0x0180, 0x0200, + 0x0200, 0x0280, 0x0280, 0x0300, 0x0300, 0x0380, 0x0400, 0x0400, + 0x0480, 0x0500, 0x0580, 0x0580, 0x0600, 0x0680, 0x0700, 0x0780, + 0x0800, 0x0880, 0x0900, 0x0980, 0x0a00, 0x0a80, 0x0b80, 0x0c00, + 0x0c80, 0x0d00, 0x0e00, 0x0e80, 0x0f00, 0x1000, 0x1080, 0x1180, + 0x1200, 0x1300, 0x1380, 0x1480, 0x1500, 0x1600, 0x1700, 0x1780, + 0x1880, 0x1980, 0x1a80, 0x1b00, 0x1c00, 0x1d00, 0x1e00, 0x1f00, + 0x2000, 0x2100, 0x2200, 0x2300, 0x2400, 0x2500, 0x2680, 0x2780, + 0x2880, 0x2980, 0x2b00, 0x2c00, 0x2d00, 0x2e80, 0x2f80, 0x3100, + 0x3200, 0x3380, 0x3480, 0x3600, 0x3700, 0x3880, 0x3a00, 0x3b00, + 0x3c80, 0x3e00, 0x3f80, 0x4080, 0x4200, 0x4380, 0x4500, 0x4680, + 0x4800, 0x4980, 0x4b00, 0x4c80, 0x4e00, 0x4f80, 0x5180, 0x5300, + 0x5480, 0x5600, 0x5800, 0x5980, 0x5b00, 0x5d00, 0x5e80, 0x6080, + 0x6200, 0x6400, 0x6580, 0x6780, 0x6900, 0x6b00, 0x6d00, 0x6e80, + 0x7080, 0x7280, 0x7480, 0x7600, 0x7800, 0x7a00, 0x7c00, 0x7e00 +}; + +static short lut_nmsedec_ref[1 << T1_NMSEDEC_BITS] = { + 0x1800, 0x1780, 0x1700, 0x1680, 0x1600, 0x1580, 0x1500, 0x1480, + 0x1400, 0x1380, 0x1300, 0x1280, 0x1200, 0x1180, 0x1100, 0x1080, + 0x1000, 0x0f80, 0x0f00, 0x0e80, 0x0e00, 0x0d80, 0x0d00, 0x0c80, + 0x0c00, 0x0b80, 0x0b00, 0x0a80, 0x0a00, 0x0980, 0x0900, 0x0880, + 0x0800, 0x0780, 0x0700, 0x0680, 0x0600, 0x0580, 0x0500, 0x0480, + 0x0400, 0x0380, 0x0300, 0x0280, 0x0200, 0x0180, 0x0100, 0x0080, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0080, 0x0100, 0x0180, 0x0200, 0x0280, 0x0300, 0x0380, + 0x0400, 0x0480, 0x0500, 0x0580, 0x0600, 0x0680, 0x0700, 0x0780, + 0x0800, 0x0880, 0x0900, 0x0980, 0x0a00, 0x0a80, 0x0b00, 0x0b80, + 0x0c00, 0x0c80, 0x0d00, 0x0d80, 0x0e00, 0x0e80, 0x0f00, 0x0f80, + 0x1000, 0x1080, 0x1100, 0x1180, 0x1200, 0x1280, 0x1300, 0x1380, + 0x1400, 0x1480, 0x1500, 0x1580, 0x1600, 0x1680, 0x1700, 0x1780 +}; + +static short lut_nmsedec_ref0[1 << T1_NMSEDEC_BITS] = { + 0x2000, 0x1f00, 0x1e00, 0x1d00, 0x1c00, 0x1b00, 0x1a80, 0x1980, + 0x1880, 0x1780, 0x1700, 0x1600, 0x1500, 0x1480, 0x1380, 0x1300, + 0x1200, 0x1180, 0x1080, 0x1000, 0x0f00, 0x0e80, 0x0e00, 0x0d00, + 0x0c80, 0x0c00, 0x0b80, 0x0a80, 0x0a00, 0x0980, 0x0900, 0x0880, + 0x0800, 0x0780, 0x0700, 0x0680, 0x0600, 0x0580, 0x0580, 0x0500, + 0x0480, 0x0400, 0x0400, 0x0380, 0x0300, 0x0300, 0x0280, 0x0280, + 0x0200, 0x0200, 0x0180, 0x0180, 0x0100, 0x0100, 0x0100, 0x0080, + 0x0080, 0x0080, 0x0080, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0080, 0x0080, + 0x0080, 0x0080, 0x0100, 0x0100, 0x0100, 0x0180, 0x0180, 0x0200, + 0x0200, 0x0280, 0x0280, 0x0300, 0x0300, 0x0380, 0x0400, 0x0400, + 0x0480, 0x0500, 0x0580, 0x0580, 0x0600, 0x0680, 0x0700, 0x0780, + 0x0800, 0x0880, 0x0900, 0x0980, 0x0a00, 0x0a80, 0x0b80, 0x0c00, + 0x0c80, 0x0d00, 0x0e00, 0x0e80, 0x0f00, 0x1000, 0x1080, 0x1180, + 0x1200, 0x1300, 0x1380, 0x1480, 0x1500, 0x1600, 0x1700, 0x1780, + 0x1880, 0x1980, 0x1a80, 0x1b00, 0x1c00, 0x1d00, 0x1e00, 0x1f00 +}; + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/t2.c b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/t2.c new file mode 100644 index 0000000..48463c9 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/t2.c @@ -0,0 +1,791 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "opj_includes.h" + +/** @defgroup T2 T2 - Implementation of a tier-2 coding */ +/*@{*/ + +/** @name Local static functions */ +/*@{*/ + +static void t2_putcommacode(opj_bio_t *bio, int n); +static int t2_getcommacode(opj_bio_t *bio); +/** +Variable length code for signalling delta Zil (truncation point) +@param bio Bit Input/Output component +@param n delta Zil +*/ +static void t2_putnumpasses(opj_bio_t *bio, int n); +static int t2_getnumpasses(opj_bio_t *bio); +/** +Encode a packet of a tile to a destination buffer +@param tile Tile for which to write the packets +@param tcp Tile coding parameters +@param pi Packet identity +@param dest Destination buffer +@param len Length of the destination buffer +@param cstr_info Codestream information structure +@param tileno Number of the tile encoded +@return +*/ +static int t2_encode_packet(opj_tcd_tile_t *tile, opj_tcp_t *tcp, opj_pi_iterator_t *pi, unsigned char *dest, int len, opj_codestream_info_t *cstr_info, int tileno); +/** +@param cblk +@param index +@param cblksty +@param first +*/ +static void t2_init_seg(opj_tcd_cblk_dec_t* cblk, int index, int cblksty, int first); +/** +Decode a packet of a tile from a source buffer +@param t2 T2 handle +@param src Source buffer +@param len Length of the source buffer +@param tile Tile for which to write the packets +@param tcp Tile coding parameters +@param pi Packet identity +@param pack_info Packet information +@return +*/ +static int t2_decode_packet(opj_t2_t* t2, unsigned char *src, int len, opj_tcd_tile_t *tile, + opj_tcp_t *tcp, opj_pi_iterator_t *pi, opj_packet_info_t *pack_info); + +/*@}*/ + +/*@}*/ + +/* ----------------------------------------------------------------------- */ + +/* #define RESTART 0x04 */ + +static void t2_putcommacode(opj_bio_t *bio, int n) { + while (--n >= 0) { + bio_write(bio, 1, 1); + } + bio_write(bio, 0, 1); +} + +static int t2_getcommacode(opj_bio_t *bio) { + int n; + for (n = 0; bio_read(bio, 1); n++) { + ; + } + return n; +} + +static void t2_putnumpasses(opj_bio_t *bio, int n) { + if (n == 1) { + bio_write(bio, 0, 1); + } else if (n == 2) { + bio_write(bio, 2, 2); + } else if (n <= 5) { + bio_write(bio, 0xc | (n - 3), 4); + } else if (n <= 36) { + bio_write(bio, 0x1e0 | (n - 6), 9); + } else if (n <= 164) { + bio_write(bio, 0xff80 | (n - 37), 16); + } +} + +static int t2_getnumpasses(opj_bio_t *bio) { + int n; + if (!bio_read(bio, 1)) + return 1; + if (!bio_read(bio, 1)) + return 2; + if ((n = bio_read(bio, 2)) != 3) + return (3 + n); + if ((n = bio_read(bio, 5)) != 31) + return (6 + n); + return (37 + bio_read(bio, 7)); +} + +static int t2_encode_packet(opj_tcd_tile_t * tile, opj_tcp_t * tcp, opj_pi_iterator_t *pi, unsigned char *dest, int length, opj_codestream_info_t *cstr_info, int tileno) { + int bandno, cblkno; + unsigned char *c = dest; + + int compno = pi->compno; /* component value */ + int resno = pi->resno; /* resolution level value */ + int precno = pi->precno; /* precinct value */ + int layno = pi->layno; /* quality layer value */ + + opj_tcd_tilecomp_t *tilec = &tile->comps[compno]; + opj_tcd_resolution_t *res = &tilec->resolutions[resno]; + + opj_bio_t *bio = NULL; /* BIO component */ + + /* */ + if (tcp->csty & J2K_CP_CSTY_SOP) { + c[0] = 255; + c[1] = 145; + c[2] = 0; + c[3] = 4; + c[4] = (tile->packno % 65536) / 256; + c[5] = (tile->packno % 65536) % 256; + c += 6; + } + /* */ + + if (!layno) { + for (bandno = 0; bandno < res->numbands; bandno++) { + opj_tcd_band_t *band = &res->bands[bandno]; + opj_tcd_precinct_t *prc = &band->precincts[precno]; + tgt_reset(prc->incltree); + tgt_reset(prc->imsbtree); + for (cblkno = 0; cblkno < prc->cw * prc->ch; cblkno++) { + opj_tcd_cblk_enc_t* cblk = &prc->cblks.enc[cblkno]; + cblk->numpasses = 0; + tgt_setvalue(prc->imsbtree, cblkno, band->numbps - cblk->numbps); + } + } + } + + bio = bio_create(); + bio_init_enc(bio, c, length); + bio_write(bio, 1, 1); /* Empty header bit */ + + /* Writing Packet header */ + for (bandno = 0; bandno < res->numbands; bandno++) { + opj_tcd_band_t *band = &res->bands[bandno]; + opj_tcd_precinct_t *prc = &band->precincts[precno]; + for (cblkno = 0; cblkno < prc->cw * prc->ch; cblkno++) { + opj_tcd_cblk_enc_t* cblk = &prc->cblks.enc[cblkno]; + opj_tcd_layer_t *layer = &cblk->layers[layno]; + if (!cblk->numpasses && layer->numpasses) { + tgt_setvalue(prc->incltree, cblkno, layno); + } + } + for (cblkno = 0; cblkno < prc->cw * prc->ch; cblkno++) { + opj_tcd_cblk_enc_t* cblk = &prc->cblks.enc[cblkno]; + opj_tcd_layer_t *layer = &cblk->layers[layno]; + int increment = 0; + int nump = 0; + int len = 0, passno; + /* cblk inclusion bits */ + if (!cblk->numpasses) { + tgt_encode(bio, prc->incltree, cblkno, layno + 1); + } else { + bio_write(bio, layer->numpasses != 0, 1); + } + /* if cblk not included, go to the next cblk */ + if (!layer->numpasses) { + continue; + } + /* if first instance of cblk --> zero bit-planes information */ + if (!cblk->numpasses) { + cblk->numlenbits = 3; + tgt_encode(bio, prc->imsbtree, cblkno, 999); + } + /* number of coding passes included */ + t2_putnumpasses(bio, layer->numpasses); + + /* computation of the increase of the length indicator and insertion in the header */ + for (passno = cblk->numpasses; passno < cblk->numpasses + layer->numpasses; passno++) { + opj_tcd_pass_t *pass = &cblk->passes[passno]; + nump++; + len += pass->len; + if (pass->term || passno == (cblk->numpasses + layer->numpasses) - 1) { + increment = int_max(increment, int_floorlog2(len) + 1 - (cblk->numlenbits + int_floorlog2(nump))); + len = 0; + nump = 0; + } + } + t2_putcommacode(bio, increment); + + /* computation of the new Length indicator */ + cblk->numlenbits += increment; + + /* insertion of the codeword segment length */ + for (passno = cblk->numpasses; passno < cblk->numpasses + layer->numpasses; passno++) { + opj_tcd_pass_t *pass = &cblk->passes[passno]; + nump++; + len += pass->len; + if (pass->term || passno == (cblk->numpasses + layer->numpasses) - 1) { + bio_write(bio, len, cblk->numlenbits + int_floorlog2(nump)); + len = 0; + nump = 0; + } + } + } + } + + if (bio_flush(bio)) { + bio_destroy(bio); + return -999; /* modified to eliminate longjmp !! */ + } + + c += bio_numbytes(bio); + bio_destroy(bio); + + /* */ + if (tcp->csty & J2K_CP_CSTY_EPH) { + c[0] = 255; + c[1] = 146; + c += 2; + } + /* */ + + /* << INDEX */ + // End of packet header position. Currently only represents the distance to start of packet + // Will be updated later by incrementing with packet start value + if(cstr_info && cstr_info->index_write) { + opj_packet_info_t *info_PK = &cstr_info->tile[tileno].packet[cstr_info->packno]; + info_PK->end_ph_pos = (int)(c - dest); + } + /* INDEX >> */ + + /* Writing the packet body */ + + for (bandno = 0; bandno < res->numbands; bandno++) { + opj_tcd_band_t *band = &res->bands[bandno]; + opj_tcd_precinct_t *prc = &band->precincts[precno]; + for (cblkno = 0; cblkno < prc->cw * prc->ch; cblkno++) { + opj_tcd_cblk_enc_t* cblk = &prc->cblks.enc[cblkno]; + opj_tcd_layer_t *layer = &cblk->layers[layno]; + if (!layer->numpasses) { + continue; + } + if (c + layer->len > dest + length) { + return -999; + } + + memcpy(c, layer->data, layer->len); + cblk->numpasses += layer->numpasses; + c += layer->len; + /* << INDEX */ + if(cstr_info && cstr_info->index_write) { + opj_packet_info_t *info_PK = &cstr_info->tile[tileno].packet[cstr_info->packno]; + info_PK->disto += layer->disto; + if (cstr_info->D_max < info_PK->disto) { + cstr_info->D_max = info_PK->disto; + } + } + /* INDEX >> */ + } + } + + return (c - dest); +} + +static void t2_init_seg(opj_tcd_cblk_dec_t* cblk, int index, int cblksty, int first) { + opj_tcd_seg_t* seg; + cblk->segs = (opj_tcd_seg_t*) opj_realloc(cblk->segs, (index + 1) * sizeof(opj_tcd_seg_t)); + seg = &cblk->segs[index]; + seg->data = NULL; + seg->dataindex = 0; + seg->numpasses = 0; + seg->len = 0; + if (cblksty & J2K_CCP_CBLKSTY_TERMALL) { + seg->maxpasses = 1; + } + else if (cblksty & J2K_CCP_CBLKSTY_LAZY) { + if (first) { + seg->maxpasses = 10; + } else { + seg->maxpasses = (((seg - 1)->maxpasses == 1) || ((seg - 1)->maxpasses == 10)) ? 2 : 1; + } + } else { + seg->maxpasses = 109; + } +} + +static int t2_decode_packet(opj_t2_t* t2, unsigned char *src, int len, opj_tcd_tile_t *tile, + opj_tcp_t *tcp, opj_pi_iterator_t *pi, opj_packet_info_t *pack_info) { + int bandno, cblkno; + unsigned char *c = src; + + opj_cp_t *cp = t2->cp; + + int compno = pi->compno; /* component value */ + int resno = pi->resno; /* resolution level value */ + int precno = pi->precno; /* precinct value */ + int layno = pi->layno; /* quality layer value */ + + opj_tcd_resolution_t* res = &tile->comps[compno].resolutions[resno]; + + unsigned char *hd = NULL; + int present; + + opj_bio_t *bio = NULL; /* BIO component */ + + if (layno == 0) { + for (bandno = 0; bandno < res->numbands; bandno++) { + opj_tcd_band_t *band = &res->bands[bandno]; + opj_tcd_precinct_t *prc = &band->precincts[precno]; + + if ((band->x1-band->x0 == 0)||(band->y1-band->y0 == 0)) continue; + + tgt_reset(prc->incltree); + tgt_reset(prc->imsbtree); + for (cblkno = 0; cblkno < prc->cw * prc->ch; cblkno++) { + opj_tcd_cblk_dec_t* cblk = &prc->cblks.dec[cblkno]; + cblk->numsegs = 0; + } + } + } + + /* SOP markers */ + + if (tcp->csty & J2K_CP_CSTY_SOP) { + if ((*c) != 0xff || (*(c + 1) != 0x91)) { + opj_event_msg(t2->cinfo, EVT_WARNING, "Expected SOP marker\n"); + } else { + c += 6; + } + + /** TODO : check the Nsop value */ + } + + /* + When the marker PPT/PPM is used the packet header are store in PPT/PPM marker + This part deal with this caracteristic + step 1: Read packet header in the saved structure + step 2: Return to codestream for decoding + */ + + bio = bio_create(); + + if (cp->ppm == 1) { /* PPM */ + hd = cp->ppm_data; + bio_init_dec(bio, hd, cp->ppm_len); + } else if (tcp->ppt == 1) { /* PPT */ + hd = tcp->ppt_data; + bio_init_dec(bio, hd, tcp->ppt_len); + } else { /* Normal Case */ + hd = c; + bio_init_dec(bio, hd, src+len-hd); + } + + present = bio_read(bio, 1); + + if (!present) { + bio_inalign(bio); + hd += bio_numbytes(bio); + bio_destroy(bio); + + /* EPH markers */ + + if (tcp->csty & J2K_CP_CSTY_EPH) { + if ((*hd) != 0xff || (*(hd + 1) != 0x92)) { + printf("Error : expected EPH marker\n"); + } else { + hd += 2; + } + } + + /* << INDEX */ + // End of packet header position. Currently only represents the distance to start of packet + // Will be updated later by incrementing with packet start value + if(pack_info) { + pack_info->end_ph_pos = (int)(c - src); + } + /* INDEX >> */ + + if (cp->ppm == 1) { /* PPM case */ + cp->ppm_len += cp->ppm_data-hd; + cp->ppm_data = hd; + return (c - src); + } + if (tcp->ppt == 1) { /* PPT case */ + tcp->ppt_len+=tcp->ppt_data-hd; + tcp->ppt_data = hd; + return (c - src); + } + + return (hd - src); + } + + for (bandno = 0; bandno < res->numbands; bandno++) { + opj_tcd_band_t *band = &res->bands[bandno]; + opj_tcd_precinct_t *prc = &band->precincts[precno]; + + if ((band->x1-band->x0 == 0)||(band->y1-band->y0 == 0)) continue; + + for (cblkno = 0; cblkno < prc->cw * prc->ch; cblkno++) { + int included, increment, n, segno; + opj_tcd_cblk_dec_t* cblk = &prc->cblks.dec[cblkno]; + /* if cblk not yet included before --> inclusion tagtree */ + if (!cblk->numsegs) { + included = tgt_decode(bio, prc->incltree, cblkno, layno + 1); + /* else one bit */ + } else { + included = bio_read(bio, 1); + } + /* if cblk not included */ + if (!included) { + cblk->numnewpasses = 0; + continue; + } + /* if cblk not yet included --> zero-bitplane tagtree */ + if (!cblk->numsegs) { + int i, numimsbs; + for (i = 0; !tgt_decode(bio, prc->imsbtree, cblkno, i); i++) { + ; + } + numimsbs = i - 1; + cblk->numbps = band->numbps - numimsbs; + cblk->numlenbits = 3; + } + /* number of coding passes */ + cblk->numnewpasses = t2_getnumpasses(bio); + increment = t2_getcommacode(bio); + /* length indicator increment */ + cblk->numlenbits += increment; + segno = 0; + if (!cblk->numsegs) { + t2_init_seg(cblk, segno, tcp->tccps[compno].cblksty, 1); + } else { + segno = cblk->numsegs - 1; + if (cblk->segs[segno].numpasses == cblk->segs[segno].maxpasses) { + ++segno; + t2_init_seg(cblk, segno, tcp->tccps[compno].cblksty, 0); + } + } + n = cblk->numnewpasses; + + do { + cblk->segs[segno].numnewpasses = int_min(cblk->segs[segno].maxpasses - cblk->segs[segno].numpasses, n); + cblk->segs[segno].newlen = bio_read(bio, cblk->numlenbits + int_floorlog2(cblk->segs[segno].numnewpasses)); + n -= cblk->segs[segno].numnewpasses; + if (n > 0) { + ++segno; + t2_init_seg(cblk, segno, tcp->tccps[compno].cblksty, 0); + } + } while (n > 0); + } + } + + if (bio_inalign(bio)) { + bio_destroy(bio); + return -999; + } + + hd += bio_numbytes(bio); + bio_destroy(bio); + + /* EPH markers */ + if (tcp->csty & J2K_CP_CSTY_EPH) { + if ((*hd) != 0xff || (*(hd + 1) != 0x92)) { + opj_event_msg(t2->cinfo, EVT_ERROR, "Expected EPH marker\n"); + return -999; + } else { + hd += 2; + } + } + + /* << INDEX */ + // End of packet header position. Currently only represents the distance to start of packet + // Will be updated later by incrementing with packet start value + if(pack_info) { + pack_info->end_ph_pos = (int)(hd - src); + } + /* INDEX >> */ + + if (cp->ppm==1) { + cp->ppm_len+=cp->ppm_data-hd; + cp->ppm_data = hd; + } else if (tcp->ppt == 1) { + tcp->ppt_len+=tcp->ppt_data-hd; + tcp->ppt_data = hd; + } else { + c=hd; + } + + for (bandno = 0; bandno < res->numbands; bandno++) { + opj_tcd_band_t *band = &res->bands[bandno]; + opj_tcd_precinct_t *prc = &band->precincts[precno]; + + if ((band->x1-band->x0 == 0)||(band->y1-band->y0 == 0)) continue; + + for (cblkno = 0; cblkno < prc->cw * prc->ch; cblkno++) { + opj_tcd_cblk_dec_t* cblk = &prc->cblks.dec[cblkno]; + opj_tcd_seg_t *seg = NULL; + if (!cblk->numnewpasses) + continue; + if (!cblk->numsegs) { + seg = &cblk->segs[0]; + cblk->numsegs++; + cblk->len = 0; + } else { + seg = &cblk->segs[cblk->numsegs - 1]; + if (seg->numpasses == seg->maxpasses) { + seg++; + cblk->numsegs++; + } + } + + do { + if (c + seg->newlen > src + len) { + return -999; + } + +#ifdef USE_JPWL + /* we need here a j2k handle to verify if making a check to + the validity of cblocks parameters is selected from user (-W) */ + + /* let's check that we are not exceeding */ + if ((cblk->len + seg->newlen) > 8192) { + opj_event_msg(t2->cinfo, EVT_WARNING, + "JPWL: segment too long (%d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n", + seg->newlen, cblkno, precno, bandno, resno, compno); + if (!JPWL_ASSUME) { + opj_event_msg(t2->cinfo, EVT_ERROR, "JPWL: giving up\n"); + return -999; + } + seg->newlen = 8192 - cblk->len; + opj_event_msg(t2->cinfo, EVT_WARNING, " - truncating segment to %d\n", seg->newlen); + break; + }; + +#endif /* USE_JPWL */ + + cblk->data = (unsigned char*) opj_realloc(cblk->data, (cblk->len + seg->newlen) * sizeof(unsigned char*)); + memcpy(cblk->data + cblk->len, c, seg->newlen); + if (seg->numpasses == 0) { + seg->data = &cblk->data; + seg->dataindex = cblk->len; + } + c += seg->newlen; + cblk->len += seg->newlen; + seg->len += seg->newlen; + seg->numpasses += seg->numnewpasses; + cblk->numnewpasses -= seg->numnewpasses; + if (cblk->numnewpasses > 0) { + seg++; + cblk->numsegs++; + } + } while (cblk->numnewpasses > 0); + } + } + + return (c - src); +} + +/* ----------------------------------------------------------------------- */ + +int t2_encode_packets(opj_t2_t* t2,int tileno, opj_tcd_tile_t *tile, int maxlayers, unsigned char *dest, int len, opj_codestream_info_t *cstr_info,int tpnum, int tppos,int pino, J2K_T2_MODE t2_mode, int cur_totnum_tp){ + unsigned char *c = dest; + int e = 0; + int compno; + opj_pi_iterator_t *pi = NULL; + int poc; + opj_image_t *image = t2->image; + opj_cp_t *cp = t2->cp; + opj_tcp_t *tcp = &cp->tcps[tileno]; + int pocno = cp->cinema == CINEMA4K_24? 2: 1; + int maxcomp = cp->max_comp_size > 0 ? image->numcomps : 1; + + pi = pi_initialise_encode(image, cp, tileno, t2_mode); + if(!pi) { + /* TODO: throw an error */ + return -999; + } + + if(t2_mode == THRESH_CALC ){ /* Calculating threshold */ + for(compno = 0; compno < maxcomp; compno++ ){ + for(poc = 0; poc < pocno ; poc++){ + int comp_len = 0; + int tpnum = compno; + if (pi_create_encode(pi, cp,tileno,poc,tpnum,tppos,t2_mode,cur_totnum_tp)) { + opj_event_msg(t2->cinfo, EVT_ERROR, "Error initializing Packet Iterator\n"); + pi_destroy(pi, cp, tileno); + return -999; + } + while (pi_next(&pi[poc])) { + if (pi[poc].layno < maxlayers) { + e = t2_encode_packet(tile, &cp->tcps[tileno], &pi[poc], c, dest + len - c, cstr_info, tileno); + comp_len = comp_len + e; + if (e == -999) { + break; + } else { + c += e; + } + } + } + if (e == -999) break; + if (cp->max_comp_size){ + if (comp_len > cp->max_comp_size){ + e = -999; + break; + } + } + } + if (e == -999) break; + } + }else{ /* t2_mode == FINAL_PASS */ + pi_create_encode(pi, cp,tileno,pino,tpnum,tppos,t2_mode,cur_totnum_tp); + while (pi_next(&pi[pino])) { + if (pi[pino].layno < maxlayers) { + e = t2_encode_packet(tile, &cp->tcps[tileno], &pi[pino], c, dest + len - c, cstr_info, tileno); + if (e == -999) { + break; + } else { + c += e; + } + /* INDEX >> */ + if(cstr_info) { + if(cstr_info->index_write) { + opj_tile_info_t *info_TL = &cstr_info->tile[tileno]; + opj_packet_info_t *info_PK = &info_TL->packet[cstr_info->packno]; + if (!cstr_info->packno) { + info_PK->start_pos = info_TL->end_header + 1; + } else { + info_PK->start_pos = ((cp->tp_on | tcp->POC)&& info_PK->start_pos) ? info_PK->start_pos : info_TL->packet[cstr_info->packno - 1].end_pos + 1; + } + info_PK->end_pos = info_PK->start_pos + e - 1; + info_PK->end_ph_pos += info_PK->start_pos - 1; // End of packet header which now only represents the distance + // to start of packet is incremented by value of start of packet + } + + cstr_info->packno++; + } + /* << INDEX */ + tile->packno++; + } + } + } + + pi_destroy(pi, cp, tileno); + + if (e == -999) { + return e; + } + + return (c - dest); +} + +int t2_decode_packets(opj_t2_t *t2, unsigned char *src, int len, int tileno, opj_tcd_tile_t *tile, opj_codestream_info_t *cstr_info) { + unsigned char *c = src; + opj_pi_iterator_t *pi; + int pino, e = 0; + int n = 0, curtp = 0; + int tp_start_packno; + + opj_image_t *image = t2->image; + opj_cp_t *cp = t2->cp; + + /* create a packet iterator */ + pi = pi_create_decode(image, cp, tileno); + if(!pi) { + /* TODO: throw an error */ + return -999; + } + + tp_start_packno = 0; + + for (pino = 0; pino <= cp->tcps[tileno].numpocs; pino++) { + while (pi_next(&pi[pino])) { + if ((cp->layer==0) || (cp->layer>=((pi[pino].layno)+1))) { + opj_packet_info_t *pack_info; + if (cstr_info) + pack_info = &cstr_info->tile[tileno].packet[cstr_info->packno]; + else + pack_info = NULL; + e = t2_decode_packet(t2, c, src + len - c, tile, &cp->tcps[tileno], &pi[pino], pack_info); + } else { + e = 0; + } + if(e == -999) return -999; + /* progression in resolution */ + image->comps[pi[pino].compno].resno_decoded = + (e > 0) ? + int_max(pi[pino].resno, image->comps[pi[pino].compno].resno_decoded) + : image->comps[pi[pino].compno].resno_decoded; + n++; + + /* INDEX >> */ + if(cstr_info) { + opj_tile_info_t *info_TL = &cstr_info->tile[tileno]; + opj_packet_info_t *info_PK = &info_TL->packet[cstr_info->packno]; + if (!cstr_info->packno) { + info_PK->start_pos = info_TL->end_header + 1; + } else if (info_TL->packet[cstr_info->packno-1].end_pos >= (int)cstr_info->tile[tileno].tp[curtp].tp_end_pos){ // New tile part + info_TL->tp[curtp].tp_numpacks = cstr_info->packno - tp_start_packno; // Number of packets in previous tile-part + tp_start_packno = cstr_info->packno; + curtp++; + info_PK->start_pos = cstr_info->tile[tileno].tp[curtp].tp_end_header+1; + } else { + info_PK->start_pos = (cp->tp_on && info_PK->start_pos) ? info_PK->start_pos : info_TL->packet[cstr_info->packno - 1].end_pos + 1; + } + info_PK->end_pos = info_PK->start_pos + e - 1; + info_PK->end_ph_pos += info_PK->start_pos - 1; // End of packet header which now only represents the distance + // to start of packet is incremented by value of start of packet + cstr_info->packno++; + } + /* << INDEX */ + + if (e == -999) { /* ADD */ + break; + } else { + c += e; + } + } + } + /* INDEX >> */ + if(cstr_info) { + cstr_info->tile[tileno].tp[curtp].tp_numpacks = cstr_info->packno - tp_start_packno; // Number of packets in last tile-part + } + /* << INDEX */ + + /* don't forget to release pi */ + pi_destroy(pi, cp, tileno); + + if (e == -999) { + return e; + } + + return (c - src); +} + +/* ----------------------------------------------------------------------- */ + +opj_t2_t* t2_create(opj_common_ptr cinfo, opj_image_t *image, opj_cp_t *cp) { + /* create the tcd structure */ + opj_t2_t *t2 = (opj_t2_t*)opj_malloc(sizeof(opj_t2_t)); + if(!t2) return NULL; + t2->cinfo = cinfo; + t2->image = image; + t2->cp = cp; + + return t2; +} + +void t2_destroy(opj_t2_t *t2) { + if(t2) { + opj_free(t2); + } +} + + + + + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/t2.h b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/t2.h new file mode 100644 index 0000000..2151ba6 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/t2.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __T2_H +#define __T2_H +/** +@file t2.h +@brief Implementation of a tier-2 coding (packetization of code-block data) (T2) + +*/ + +/** @defgroup T2 T2 - Implementation of a tier-2 coding */ +/*@{*/ + +/** +Tier-2 coding +*/ +typedef struct opj_t2 { + /** codec context */ + opj_common_ptr cinfo; + + /** Encoding: pointer to the src image. Decoding: pointer to the dst image. */ + opj_image_t *image; + /** pointer to the image coding parameters */ + opj_cp_t *cp; +} opj_t2_t; + +/** @name Exported functions */ +/*@{*/ +/* ----------------------------------------------------------------------- */ + +/** +Encode the packets of a tile to a destination buffer +@param t2 T2 handle +@param tileno number of the tile encoded +@param tile the tile for which to write the packets +@param maxlayers maximum number of layers +@param dest the destination buffer +@param len the length of the destination buffer +@param cstr_info Codestream information structure +@param tpnum Tile part number of the current tile +@param tppos The position of the tile part flag in the progression order +@param pino +@param t2_mode If == 0 In Threshold calculation ,If == 1 Final pass +@param cur_totnum_tp The total number of tile parts in the current tile +*/ +int t2_encode_packets(opj_t2_t* t2,int tileno, opj_tcd_tile_t *tile, int maxlayers, unsigned char *dest, int len, opj_codestream_info_t *cstr_info,int tpnum, int tppos,int pino,J2K_T2_MODE t2_mode,int cur_totnum_tp); +/** +Decode the packets of a tile from a source buffer +@param t2 T2 handle +@param src the source buffer +@param len length of the source buffer +@param tileno number that identifies the tile for which to decode the packets +@param tile tile for which to decode the packets +@param cstr_info Codestream information structure + */ +int t2_decode_packets(opj_t2_t *t2, unsigned char *src, int len, int tileno, opj_tcd_tile_t *tile, opj_codestream_info_t *cstr_info); + +/** +Create a T2 handle +@param cinfo Codec context info +@param image Source or destination image +@param cp Image coding parameters +@return Returns a new T2 handle if successful, returns NULL otherwise +*/ +opj_t2_t* t2_create(opj_common_ptr cinfo, opj_image_t *image, opj_cp_t *cp); +/** +Destroy a T2 handle +@param t2 T2 handle to destroy +*/ +void t2_destroy(opj_t2_t *t2); + +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __T2_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/tcd.c b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/tcd.c new file mode 100644 index 0000000..7f154f4 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/tcd.c @@ -0,0 +1,1516 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2006-2007, Parvatha Elangovan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "opj_includes.h" + +void tcd_dump(FILE *fd, opj_tcd_t *tcd, opj_tcd_image_t * img) { + int tileno, compno, resno, bandno, precno;//, cblkno; + + fprintf(fd, "image {\n"); + fprintf(fd, " tw=%d, th=%d x0=%d x1=%d y0=%d y1=%d\n", + img->tw, img->th, tcd->image->x0, tcd->image->x1, tcd->image->y0, tcd->image->y1); + + for (tileno = 0; tileno < img->th * img->tw; tileno++) { + opj_tcd_tile_t *tile = &tcd->tcd_image->tiles[tileno]; + fprintf(fd, " tile {\n"); + fprintf(fd, " x0=%d, y0=%d, x1=%d, y1=%d, numcomps=%d\n", + tile->x0, tile->y0, tile->x1, tile->y1, tile->numcomps); + for (compno = 0; compno < tile->numcomps; compno++) { + opj_tcd_tilecomp_t *tilec = &tile->comps[compno]; + fprintf(fd, " tilec {\n"); + fprintf(fd, + " x0=%d, y0=%d, x1=%d, y1=%d, numresolutions=%d\n", + tilec->x0, tilec->y0, tilec->x1, tilec->y1, tilec->numresolutions); + for (resno = 0; resno < tilec->numresolutions; resno++) { + opj_tcd_resolution_t *res = &tilec->resolutions[resno]; + fprintf(fd, "\n res {\n"); + fprintf(fd, + " x0=%d, y0=%d, x1=%d, y1=%d, pw=%d, ph=%d, numbands=%d\n", + res->x0, res->y0, res->x1, res->y1, res->pw, res->ph, res->numbands); + for (bandno = 0; bandno < res->numbands; bandno++) { + opj_tcd_band_t *band = &res->bands[bandno]; + fprintf(fd, " band {\n"); + fprintf(fd, + " x0=%d, y0=%d, x1=%d, y1=%d, stepsize=%f, numbps=%d\n", + band->x0, band->y0, band->x1, band->y1, band->stepsize, band->numbps); + for (precno = 0; precno < res->pw * res->ph; precno++) { + opj_tcd_precinct_t *prec = &band->precincts[precno]; + fprintf(fd, " prec {\n"); + fprintf(fd, + " x0=%d, y0=%d, x1=%d, y1=%d, cw=%d, ch=%d\n", + prec->x0, prec->y0, prec->x1, prec->y1, prec->cw, prec->ch); + /* + for (cblkno = 0; cblkno < prec->cw * prec->ch; cblkno++) { + opj_tcd_cblk_t *cblk = &prec->cblks[cblkno]; + fprintf(fd, " cblk {\n"); + fprintf(fd, + " x0=%d, y0=%d, x1=%d, y1=%d\n", + cblk->x0, cblk->y0, cblk->x1, cblk->y1); + fprintf(fd, " }\n"); + } + */ + fprintf(fd, " }\n"); + } + fprintf(fd, " }\n"); + } + fprintf(fd, " }\n"); + } + fprintf(fd, " }\n"); + } + fprintf(fd, " }\n"); + } + fprintf(fd, "}\n"); +} + +/* ----------------------------------------------------------------------- */ + +/** +Create a new TCD handle +*/ +opj_tcd_t* tcd_create(opj_common_ptr cinfo) { + /* create the tcd structure */ + opj_tcd_t *tcd = (opj_tcd_t*)opj_malloc(sizeof(opj_tcd_t)); + if(!tcd) return NULL; + tcd->cinfo = cinfo; + tcd->tcd_image = (opj_tcd_image_t*)opj_malloc(sizeof(opj_tcd_image_t)); + if(!tcd->tcd_image) { + opj_free(tcd); + return NULL; + } + + return tcd; +} + +/** +Destroy a previously created TCD handle +*/ +void tcd_destroy(opj_tcd_t *tcd) { + if(tcd) { + opj_free(tcd->tcd_image); + opj_free(tcd); + } +} + +/* ----------------------------------------------------------------------- */ + +void tcd_malloc_encode(opj_tcd_t *tcd, opj_image_t * image, opj_cp_t * cp, int curtileno) { + int tileno, compno, resno, bandno, precno, cblkno; + + tcd->image = image; + tcd->cp = cp; + tcd->tcd_image->tw = cp->tw; + tcd->tcd_image->th = cp->th; + tcd->tcd_image->tiles = (opj_tcd_tile_t *) opj_malloc(sizeof(opj_tcd_tile_t)); + + for (tileno = 0; tileno < 1; tileno++) { + opj_tcp_t *tcp = &cp->tcps[curtileno]; + int j; + + /* cfr p59 ISO/IEC FDIS15444-1 : 2000 (18 august 2000) */ + int p = curtileno % cp->tw; /* si numerotation matricielle .. */ + int q = curtileno / cp->tw; /* .. coordonnees de la tile (q,p) q pour ligne et p pour colonne */ + + /* opj_tcd_tile_t *tile=&tcd->tcd_image->tiles[tileno]; */ + opj_tcd_tile_t *tile = tcd->tcd_image->tiles; + + /* 4 borders of the tile rescale on the image if necessary */ + tile->x0 = int_max(cp->tx0 + p * cp->tdx, image->x0); + tile->y0 = int_max(cp->ty0 + q * cp->tdy, image->y0); + tile->x1 = int_min(cp->tx0 + (p + 1) * cp->tdx, image->x1); + tile->y1 = int_min(cp->ty0 + (q + 1) * cp->tdy, image->y1); + tile->numcomps = image->numcomps; + /* tile->PPT=image->PPT; */ + + /* Modification of the RATE >> */ + for (j = 0; j < tcp->numlayers; j++) { + tcp->rates[j] = tcp->rates[j] ? + cp->tp_on ? + (((float) (tile->numcomps + * (tile->x1 - tile->x0) + * (tile->y1 - tile->y0) + * image->comps[0].prec)) + /(tcp->rates[j] * 8 * image->comps[0].dx * image->comps[0].dy)) - (((tcd->cur_totnum_tp - 1) * 14 )/ tcp->numlayers) + : + ((float) (tile->numcomps + * (tile->x1 - tile->x0) + * (tile->y1 - tile->y0) + * image->comps[0].prec))/ + (tcp->rates[j] * 8 * image->comps[0].dx * image->comps[0].dy) + : 0; + + if (tcp->rates[j]) { + if (j && tcp->rates[j] < tcp->rates[j - 1] + 10) { + tcp->rates[j] = tcp->rates[j - 1] + 20; + } else { + if (!j && tcp->rates[j] < 30) + tcp->rates[j] = 30; + } + + if(j == (tcp->numlayers-1)){ + tcp->rates[j] = tcp->rates[j]- 2; + } + } + } + /* << Modification of the RATE */ + + tile->comps = (opj_tcd_tilecomp_t *) opj_malloc(image->numcomps * sizeof(opj_tcd_tilecomp_t)); + for (compno = 0; compno < tile->numcomps; compno++) { + opj_tccp_t *tccp = &tcp->tccps[compno]; + + opj_tcd_tilecomp_t *tilec = &tile->comps[compno]; + + /* border of each tile component (global) */ + tilec->x0 = int_ceildiv(tile->x0, image->comps[compno].dx); + tilec->y0 = int_ceildiv(tile->y0, image->comps[compno].dy); + tilec->x1 = int_ceildiv(tile->x1, image->comps[compno].dx); + tilec->y1 = int_ceildiv(tile->y1, image->comps[compno].dy); + + tilec->data = (int *) opj_aligned_malloc((tilec->x1 - tilec->x0) * (tilec->y1 - tilec->y0) * sizeof(int)); + tilec->numresolutions = tccp->numresolutions; + + tilec->resolutions = (opj_tcd_resolution_t *) opj_malloc(tilec->numresolutions * sizeof(opj_tcd_resolution_t)); + + for (resno = 0; resno < tilec->numresolutions; resno++) { + int pdx, pdy; + int levelno = tilec->numresolutions - 1 - resno; + int tlprcxstart, tlprcystart, brprcxend, brprcyend; + int tlcbgxstart, tlcbgystart, brcbgxend, brcbgyend; + int cbgwidthexpn, cbgheightexpn; + int cblkwidthexpn, cblkheightexpn; + + opj_tcd_resolution_t *res = &tilec->resolutions[resno]; + + /* border for each resolution level (global) */ + res->x0 = int_ceildivpow2(tilec->x0, levelno); + res->y0 = int_ceildivpow2(tilec->y0, levelno); + res->x1 = int_ceildivpow2(tilec->x1, levelno); + res->y1 = int_ceildivpow2(tilec->y1, levelno); + + res->numbands = resno == 0 ? 1 : 3; + /* p. 35, table A-23, ISO/IEC FDIS154444-1 : 2000 (18 august 2000) */ + if (tccp->csty & J2K_CCP_CSTY_PRT) { + pdx = tccp->prcw[resno]; + pdy = tccp->prch[resno]; + } else { + pdx = 15; + pdy = 15; + } + /* p. 64, B.6, ISO/IEC FDIS15444-1 : 2000 (18 august 2000) */ + tlprcxstart = int_floordivpow2(res->x0, pdx) << pdx; + tlprcystart = int_floordivpow2(res->y0, pdy) << pdy; + + brprcxend = int_ceildivpow2(res->x1, pdx) << pdx; + brprcyend = int_ceildivpow2(res->y1, pdy) << pdy; + + res->pw = (brprcxend - tlprcxstart) >> pdx; + res->ph = (brprcyend - tlprcystart) >> pdy; + + if (resno == 0) { + tlcbgxstart = tlprcxstart; + tlcbgystart = tlprcystart; + brcbgxend = brprcxend; + brcbgyend = brprcyend; + cbgwidthexpn = pdx; + cbgheightexpn = pdy; + } else { + tlcbgxstart = int_ceildivpow2(tlprcxstart, 1); + tlcbgystart = int_ceildivpow2(tlprcystart, 1); + brcbgxend = int_ceildivpow2(brprcxend, 1); + brcbgyend = int_ceildivpow2(brprcyend, 1); + cbgwidthexpn = pdx - 1; + cbgheightexpn = pdy - 1; + } + + cblkwidthexpn = int_min(tccp->cblkw, cbgwidthexpn); + cblkheightexpn = int_min(tccp->cblkh, cbgheightexpn); + + for (bandno = 0; bandno < res->numbands; bandno++) { + int x0b, y0b, i; + int gain, numbps; + opj_stepsize_t *ss = NULL; + + opj_tcd_band_t *band = &res->bands[bandno]; + + band->bandno = resno == 0 ? 0 : bandno + 1; + x0b = (band->bandno == 1) || (band->bandno == 3) ? 1 : 0; + y0b = (band->bandno == 2) || (band->bandno == 3) ? 1 : 0; + + if (band->bandno == 0) { + /* band border (global) */ + band->x0 = int_ceildivpow2(tilec->x0, levelno); + band->y0 = int_ceildivpow2(tilec->y0, levelno); + band->x1 = int_ceildivpow2(tilec->x1, levelno); + band->y1 = int_ceildivpow2(tilec->y1, levelno); + } else { + /* band border (global) */ + band->x0 = int_ceildivpow2(tilec->x0 - (1 << levelno) * x0b, levelno + 1); + band->y0 = int_ceildivpow2(tilec->y0 - (1 << levelno) * y0b, levelno + 1); + band->x1 = int_ceildivpow2(tilec->x1 - (1 << levelno) * x0b, levelno + 1); + band->y1 = int_ceildivpow2(tilec->y1 - (1 << levelno) * y0b, levelno + 1); + } + + ss = &tccp->stepsizes[resno == 0 ? 0 : 3 * (resno - 1) + bandno + 1]; + gain = tccp->qmfbid == 0 ? dwt_getgain_real(band->bandno) : dwt_getgain(band->bandno); + numbps = image->comps[compno].prec + gain; + + band->stepsize = (float)((1.0 + ss->mant / 2048.0) * pow(2.0, numbps - ss->expn)); + band->numbps = ss->expn + tccp->numgbits - 1; /* WHY -1 ? */ + + band->precincts = (opj_tcd_precinct_t *) opj_malloc(3 * res->pw * res->ph * sizeof(opj_tcd_precinct_t)); + + for (i = 0; i < res->pw * res->ph * 3; i++) { + band->precincts[i].imsbtree = NULL; + band->precincts[i].incltree = NULL; + } + + for (precno = 0; precno < res->pw * res->ph; precno++) { + int tlcblkxstart, tlcblkystart, brcblkxend, brcblkyend; + + int cbgxstart = tlcbgxstart + (precno % res->pw) * (1 << cbgwidthexpn); + int cbgystart = tlcbgystart + (precno / res->pw) * (1 << cbgheightexpn); + int cbgxend = cbgxstart + (1 << cbgwidthexpn); + int cbgyend = cbgystart + (1 << cbgheightexpn); + + opj_tcd_precinct_t *prc = &band->precincts[precno]; + + /* precinct size (global) */ + prc->x0 = int_max(cbgxstart, band->x0); + prc->y0 = int_max(cbgystart, band->y0); + prc->x1 = int_min(cbgxend, band->x1); + prc->y1 = int_min(cbgyend, band->y1); + + tlcblkxstart = int_floordivpow2(prc->x0, cblkwidthexpn) << cblkwidthexpn; + tlcblkystart = int_floordivpow2(prc->y0, cblkheightexpn) << cblkheightexpn; + brcblkxend = int_ceildivpow2(prc->x1, cblkwidthexpn) << cblkwidthexpn; + brcblkyend = int_ceildivpow2(prc->y1, cblkheightexpn) << cblkheightexpn; + prc->cw = (brcblkxend - tlcblkxstart) >> cblkwidthexpn; + prc->ch = (brcblkyend - tlcblkystart) >> cblkheightexpn; + + prc->cblks.enc = (opj_tcd_cblk_enc_t*) opj_calloc((prc->cw * prc->ch), sizeof(opj_tcd_cblk_enc_t)); + prc->incltree = tgt_create(prc->cw, prc->ch); + prc->imsbtree = tgt_create(prc->cw, prc->ch); + + for (cblkno = 0; cblkno < prc->cw * prc->ch; cblkno++) { + int cblkxstart = tlcblkxstart + (cblkno % prc->cw) * (1 << cblkwidthexpn); + int cblkystart = tlcblkystart + (cblkno / prc->cw) * (1 << cblkheightexpn); + int cblkxend = cblkxstart + (1 << cblkwidthexpn); + int cblkyend = cblkystart + (1 << cblkheightexpn); + + opj_tcd_cblk_enc_t* cblk = &prc->cblks.enc[cblkno]; + + /* code-block size (global) */ + cblk->x0 = int_max(cblkxstart, prc->x0); + cblk->y0 = int_max(cblkystart, prc->y0); + cblk->x1 = int_min(cblkxend, prc->x1); + cblk->y1 = int_min(cblkyend, prc->y1); + cblk->data = (unsigned char*) opj_calloc(8192+2, sizeof(unsigned char)); + /* FIXME: mqc_init_enc and mqc_byteout underrun the buffer if we don't do this. Why? */ + cblk->data += 2; + cblk->layers = (opj_tcd_layer_t*) opj_calloc(100, sizeof(opj_tcd_layer_t)); + cblk->passes = (opj_tcd_pass_t*) opj_calloc(100, sizeof(opj_tcd_pass_t)); + } + } + } + } + } + } + + /* tcd_dump(stdout, tcd, &tcd->tcd_image); */ +} + +void tcd_free_encode(opj_tcd_t *tcd) { + int tileno, compno, resno, bandno, precno, cblkno; + + for (tileno = 0; tileno < 1; tileno++) { + opj_tcd_tile_t *tile = tcd->tcd_image->tiles; + + for (compno = 0; compno < tile->numcomps; compno++) { + opj_tcd_tilecomp_t *tilec = &tile->comps[compno]; + + for (resno = 0; resno < tilec->numresolutions; resno++) { + opj_tcd_resolution_t *res = &tilec->resolutions[resno]; + + for (bandno = 0; bandno < res->numbands; bandno++) { + opj_tcd_band_t *band = &res->bands[bandno]; + + for (precno = 0; precno < res->pw * res->ph; precno++) { + opj_tcd_precinct_t *prc = &band->precincts[precno]; + + if (prc->incltree != NULL) { + tgt_destroy(prc->incltree); + prc->incltree = NULL; + } + if (prc->imsbtree != NULL) { + tgt_destroy(prc->imsbtree); + prc->imsbtree = NULL; + } + for (cblkno = 0; cblkno < prc->cw * prc->ch; cblkno++) { + opj_free(prc->cblks.enc[cblkno].data - 2); + opj_free(prc->cblks.enc[cblkno].layers); + opj_free(prc->cblks.enc[cblkno].passes); + } + opj_free(prc->cblks.enc); + } /* for (precno */ + opj_free(band->precincts); + band->precincts = NULL; + } /* for (bandno */ + } /* for (resno */ + opj_free(tilec->resolutions); + tilec->resolutions = NULL; + } /* for (compno */ + opj_free(tile->comps); + tile->comps = NULL; + } /* for (tileno */ + opj_free(tcd->tcd_image->tiles); + tcd->tcd_image->tiles = NULL; +} + +void tcd_init_encode(opj_tcd_t *tcd, opj_image_t * image, opj_cp_t * cp, int curtileno) { + int tileno, compno, resno, bandno, precno, cblkno; + + for (tileno = 0; tileno < 1; tileno++) { + opj_tcp_t *tcp = &cp->tcps[curtileno]; + int j; + /* cfr p59 ISO/IEC FDIS15444-1 : 2000 (18 august 2000) */ + int p = curtileno % cp->tw; + int q = curtileno / cp->tw; + + opj_tcd_tile_t *tile = tcd->tcd_image->tiles; + + /* 4 borders of the tile rescale on the image if necessary */ + tile->x0 = int_max(cp->tx0 + p * cp->tdx, image->x0); + tile->y0 = int_max(cp->ty0 + q * cp->tdy, image->y0); + tile->x1 = int_min(cp->tx0 + (p + 1) * cp->tdx, image->x1); + tile->y1 = int_min(cp->ty0 + (q + 1) * cp->tdy, image->y1); + + tile->numcomps = image->numcomps; + /* tile->PPT=image->PPT; */ + + /* Modification of the RATE >> */ + for (j = 0; j < tcp->numlayers; j++) { + tcp->rates[j] = tcp->rates[j] ? + cp->tp_on ? + (((float) (tile->numcomps + * (tile->x1 - tile->x0) + * (tile->y1 - tile->y0) + * image->comps[0].prec)) + /(tcp->rates[j] * 8 * image->comps[0].dx * image->comps[0].dy)) - (((tcd->cur_totnum_tp - 1) * 14 )/ tcp->numlayers) + : + ((float) (tile->numcomps + * (tile->x1 - tile->x0) + * (tile->y1 - tile->y0) + * image->comps[0].prec))/ + (tcp->rates[j] * 8 * image->comps[0].dx * image->comps[0].dy) + : 0; + + if (tcp->rates[j]) { + if (j && tcp->rates[j] < tcp->rates[j - 1] + 10) { + tcp->rates[j] = tcp->rates[j - 1] + 20; + } else { + if (!j && tcp->rates[j] < 30) + tcp->rates[j] = 30; + } + } + } + /* << Modification of the RATE */ + + /* tile->comps=(opj_tcd_tilecomp_t*)opj_realloc(tile->comps,image->numcomps*sizeof(opj_tcd_tilecomp_t)); */ + for (compno = 0; compno < tile->numcomps; compno++) { + opj_tccp_t *tccp = &tcp->tccps[compno]; + + opj_tcd_tilecomp_t *tilec = &tile->comps[compno]; + + /* border of each tile component (global) */ + tilec->x0 = int_ceildiv(tile->x0, image->comps[compno].dx); + tilec->y0 = int_ceildiv(tile->y0, image->comps[compno].dy); + tilec->x1 = int_ceildiv(tile->x1, image->comps[compno].dx); + tilec->y1 = int_ceildiv(tile->y1, image->comps[compno].dy); + + tilec->data = (int *) opj_aligned_malloc((tilec->x1 - tilec->x0) * (tilec->y1 - tilec->y0) * sizeof(int)); + tilec->numresolutions = tccp->numresolutions; + /* tilec->resolutions=(opj_tcd_resolution_t*)opj_realloc(tilec->resolutions,tilec->numresolutions*sizeof(opj_tcd_resolution_t)); */ + for (resno = 0; resno < tilec->numresolutions; resno++) { + int pdx, pdy; + + int levelno = tilec->numresolutions - 1 - resno; + int tlprcxstart, tlprcystart, brprcxend, brprcyend; + int tlcbgxstart, tlcbgystart, brcbgxend, brcbgyend; + int cbgwidthexpn, cbgheightexpn; + int cblkwidthexpn, cblkheightexpn; + + opj_tcd_resolution_t *res = &tilec->resolutions[resno]; + + /* border for each resolution level (global) */ + res->x0 = int_ceildivpow2(tilec->x0, levelno); + res->y0 = int_ceildivpow2(tilec->y0, levelno); + res->x1 = int_ceildivpow2(tilec->x1, levelno); + res->y1 = int_ceildivpow2(tilec->y1, levelno); + res->numbands = resno == 0 ? 1 : 3; + + /* p. 35, table A-23, ISO/IEC FDIS154444-1 : 2000 (18 august 2000) */ + if (tccp->csty & J2K_CCP_CSTY_PRT) { + pdx = tccp->prcw[resno]; + pdy = tccp->prch[resno]; + } else { + pdx = 15; + pdy = 15; + } + /* p. 64, B.6, ISO/IEC FDIS15444-1 : 2000 (18 august 2000) */ + tlprcxstart = int_floordivpow2(res->x0, pdx) << pdx; + tlprcystart = int_floordivpow2(res->y0, pdy) << pdy; + brprcxend = int_ceildivpow2(res->x1, pdx) << pdx; + brprcyend = int_ceildivpow2(res->y1, pdy) << pdy; + + res->pw = (brprcxend - tlprcxstart) >> pdx; + res->ph = (brprcyend - tlprcystart) >> pdy; + + if (resno == 0) { + tlcbgxstart = tlprcxstart; + tlcbgystart = tlprcystart; + brcbgxend = brprcxend; + brcbgyend = brprcyend; + cbgwidthexpn = pdx; + cbgheightexpn = pdy; + } else { + tlcbgxstart = int_ceildivpow2(tlprcxstart, 1); + tlcbgystart = int_ceildivpow2(tlprcystart, 1); + brcbgxend = int_ceildivpow2(brprcxend, 1); + brcbgyend = int_ceildivpow2(brprcyend, 1); + cbgwidthexpn = pdx - 1; + cbgheightexpn = pdy - 1; + } + + cblkwidthexpn = int_min(tccp->cblkw, cbgwidthexpn); + cblkheightexpn = int_min(tccp->cblkh, cbgheightexpn); + + for (bandno = 0; bandno < res->numbands; bandno++) { + int x0b, y0b; + int gain, numbps; + opj_stepsize_t *ss = NULL; + + opj_tcd_band_t *band = &res->bands[bandno]; + + band->bandno = resno == 0 ? 0 : bandno + 1; + x0b = (band->bandno == 1) || (band->bandno == 3) ? 1 : 0; + y0b = (band->bandno == 2) || (band->bandno == 3) ? 1 : 0; + + if (band->bandno == 0) { + /* band border */ + band->x0 = int_ceildivpow2(tilec->x0, levelno); + band->y0 = int_ceildivpow2(tilec->y0, levelno); + band->x1 = int_ceildivpow2(tilec->x1, levelno); + band->y1 = int_ceildivpow2(tilec->y1, levelno); + } else { + band->x0 = int_ceildivpow2(tilec->x0 - (1 << levelno) * x0b, levelno + 1); + band->y0 = int_ceildivpow2(tilec->y0 - (1 << levelno) * y0b, levelno + 1); + band->x1 = int_ceildivpow2(tilec->x1 - (1 << levelno) * x0b, levelno + 1); + band->y1 = int_ceildivpow2(tilec->y1 - (1 << levelno) * y0b, levelno + 1); + } + + ss = &tccp->stepsizes[resno == 0 ? 0 : 3 * (resno - 1) + bandno + 1]; + gain = tccp->qmfbid == 0 ? dwt_getgain_real(band->bandno) : dwt_getgain(band->bandno); + numbps = image->comps[compno].prec + gain; + band->stepsize = (float)((1.0 + ss->mant / 2048.0) * pow(2.0, numbps - ss->expn)); + band->numbps = ss->expn + tccp->numgbits - 1; /* WHY -1 ? */ + + for (precno = 0; precno < res->pw * res->ph; precno++) { + int tlcblkxstart, tlcblkystart, brcblkxend, brcblkyend; + + int cbgxstart = tlcbgxstart + (precno % res->pw) * (1 << cbgwidthexpn); + int cbgystart = tlcbgystart + (precno / res->pw) * (1 << cbgheightexpn); + int cbgxend = cbgxstart + (1 << cbgwidthexpn); + int cbgyend = cbgystart + (1 << cbgheightexpn); + + opj_tcd_precinct_t *prc = &band->precincts[precno]; + + /* precinct size (global) */ + prc->x0 = int_max(cbgxstart, band->x0); + prc->y0 = int_max(cbgystart, band->y0); + prc->x1 = int_min(cbgxend, band->x1); + prc->y1 = int_min(cbgyend, band->y1); + + tlcblkxstart = int_floordivpow2(prc->x0, cblkwidthexpn) << cblkwidthexpn; + tlcblkystart = int_floordivpow2(prc->y0, cblkheightexpn) << cblkheightexpn; + brcblkxend = int_ceildivpow2(prc->x1, cblkwidthexpn) << cblkwidthexpn; + brcblkyend = int_ceildivpow2(prc->y1, cblkheightexpn) << cblkheightexpn; + prc->cw = (brcblkxend - tlcblkxstart) >> cblkwidthexpn; + prc->ch = (brcblkyend - tlcblkystart) >> cblkheightexpn; + + opj_free(prc->cblks.enc); + prc->cblks.enc = (opj_tcd_cblk_enc_t*) opj_calloc(prc->cw * prc->ch, sizeof(opj_tcd_cblk_enc_t)); + + if (prc->incltree != NULL) { + tgt_destroy(prc->incltree); + } + if (prc->imsbtree != NULL) { + tgt_destroy(prc->imsbtree); + } + + prc->incltree = tgt_create(prc->cw, prc->ch); + prc->imsbtree = tgt_create(prc->cw, prc->ch); + + for (cblkno = 0; cblkno < prc->cw * prc->ch; cblkno++) { + int cblkxstart = tlcblkxstart + (cblkno % prc->cw) * (1 << cblkwidthexpn); + int cblkystart = tlcblkystart + (cblkno / prc->cw) * (1 << cblkheightexpn); + int cblkxend = cblkxstart + (1 << cblkwidthexpn); + int cblkyend = cblkystart + (1 << cblkheightexpn); + + opj_tcd_cblk_enc_t* cblk = &prc->cblks.enc[cblkno]; + + /* code-block size (global) */ + cblk->x0 = int_max(cblkxstart, prc->x0); + cblk->y0 = int_max(cblkystart, prc->y0); + cblk->x1 = int_min(cblkxend, prc->x1); + cblk->y1 = int_min(cblkyend, prc->y1); + cblk->data = (unsigned char*) opj_calloc(8192+2, sizeof(unsigned char)); + /* FIXME: mqc_init_enc and mqc_byteout underrun the buffer if we don't do this. Why? */ + cblk->data += 2; + cblk->layers = (opj_tcd_layer_t*) opj_calloc(100, sizeof(opj_tcd_layer_t)); + cblk->passes = (opj_tcd_pass_t*) opj_calloc(100, sizeof(opj_tcd_pass_t)); + } + } /* precno */ + } /* bandno */ + } /* resno */ + } /* compno */ + } /* tileno */ + + /* tcd_dump(stdout, tcd, &tcd->tcd_image); */ +} + +void tcd_malloc_decode(opj_tcd_t *tcd, opj_image_t * image, opj_cp_t * cp) { + int i, j, tileno, p, q; + unsigned int x0 = 0, y0 = 0, x1 = 0, y1 = 0, w, h; + + tcd->image = image; + tcd->tcd_image->tw = cp->tw; + tcd->tcd_image->th = cp->th; + tcd->tcd_image->tiles = (opj_tcd_tile_t *) opj_malloc(cp->tw * cp->th * sizeof(opj_tcd_tile_t)); + + /* + Allocate place to store the decoded data = final image + Place limited by the tile really present in the codestream + */ + + for (j = 0; j < cp->tileno_size; j++) { + opj_tcd_tile_t *tile; + + tileno = cp->tileno[j]; + tile = &(tcd->tcd_image->tiles[cp->tileno[tileno]]); + tile->numcomps = image->numcomps; + tile->comps = (opj_tcd_tilecomp_t*) opj_calloc(image->numcomps, sizeof(opj_tcd_tilecomp_t)); + } + + for (i = 0; i < image->numcomps; i++) { + for (j = 0; j < cp->tileno_size; j++) { + opj_tcd_tile_t *tile; + opj_tcd_tilecomp_t *tilec; + + /* cfr p59 ISO/IEC FDIS15444-1 : 2000 (18 august 2000) */ + + tileno = cp->tileno[j]; + + tile = &(tcd->tcd_image->tiles[cp->tileno[tileno]]); + tilec = &tile->comps[i]; + + p = tileno % cp->tw; /* si numerotation matricielle .. */ + q = tileno / cp->tw; /* .. coordonnees de la tile (q,p) q pour ligne et p pour colonne */ + + /* 4 borders of the tile rescale on the image if necessary */ + tile->x0 = int_max(cp->tx0 + p * cp->tdx, image->x0); + tile->y0 = int_max(cp->ty0 + q * cp->tdy, image->y0); + tile->x1 = int_min(cp->tx0 + (p + 1) * cp->tdx, image->x1); + tile->y1 = int_min(cp->ty0 + (q + 1) * cp->tdy, image->y1); + + tilec->x0 = int_ceildiv(tile->x0, image->comps[i].dx); + tilec->y0 = int_ceildiv(tile->y0, image->comps[i].dy); + tilec->x1 = int_ceildiv(tile->x1, image->comps[i].dx); + tilec->y1 = int_ceildiv(tile->y1, image->comps[i].dy); + + x0 = j == 0 ? tilec->x0 : int_min(x0, (unsigned int) tilec->x0); + y0 = j == 0 ? tilec->y0 : int_min(y0, (unsigned int) tilec->x0); + x1 = j == 0 ? tilec->x1 : int_max(x1, (unsigned int) tilec->x1); + y1 = j == 0 ? tilec->y1 : int_max(y1, (unsigned int) tilec->y1); + } + + w = int_ceildivpow2(x1 - x0, image->comps[i].factor); + h = int_ceildivpow2(y1 - y0, image->comps[i].factor); + + image->comps[i].w = w; + image->comps[i].h = h; + image->comps[i].x0 = x0; + image->comps[i].y0 = y0; + } +} + +void tcd_malloc_decode_tile(opj_tcd_t *tcd, opj_image_t * image, opj_cp_t * cp, int tileno, opj_codestream_info_t *cstr_info) { + int compno, resno, bandno, precno, cblkno; + opj_tcp_t *tcp; + opj_tcd_tile_t *tile; + + tcd->cp = cp; + + tcp = &(cp->tcps[cp->tileno[tileno]]); + tile = &(tcd->tcd_image->tiles[cp->tileno[tileno]]); + + tileno = cp->tileno[tileno]; + + for (compno = 0; compno < tile->numcomps; compno++) { + opj_tccp_t *tccp = &tcp->tccps[compno]; + opj_tcd_tilecomp_t *tilec = &tile->comps[compno]; + + /* border of each tile component (global) */ + tilec->x0 = int_ceildiv(tile->x0, image->comps[compno].dx); + tilec->y0 = int_ceildiv(tile->y0, image->comps[compno].dy); + tilec->x1 = int_ceildiv(tile->x1, image->comps[compno].dx); + tilec->y1 = int_ceildiv(tile->y1, image->comps[compno].dy); + + tilec->numresolutions = tccp->numresolutions; + tilec->resolutions = (opj_tcd_resolution_t *) opj_malloc(tilec->numresolutions * sizeof(opj_tcd_resolution_t)); + + for (resno = 0; resno < tilec->numresolutions; resno++) { + int pdx, pdy; + int levelno = tilec->numresolutions - 1 - resno; + int tlprcxstart, tlprcystart, brprcxend, brprcyend; + int tlcbgxstart, tlcbgystart, brcbgxend, brcbgyend; + int cbgwidthexpn, cbgheightexpn; + int cblkwidthexpn, cblkheightexpn; + + opj_tcd_resolution_t *res = &tilec->resolutions[resno]; + + /* border for each resolution level (global) */ + res->x0 = int_ceildivpow2(tilec->x0, levelno); + res->y0 = int_ceildivpow2(tilec->y0, levelno); + res->x1 = int_ceildivpow2(tilec->x1, levelno); + res->y1 = int_ceildivpow2(tilec->y1, levelno); + res->numbands = resno == 0 ? 1 : 3; + + /* p. 35, table A-23, ISO/IEC FDIS154444-1 : 2000 (18 august 2000) */ + if (tccp->csty & J2K_CCP_CSTY_PRT) { + pdx = tccp->prcw[resno]; + pdy = tccp->prch[resno]; + } else { + pdx = 15; + pdy = 15; + } + + /* p. 64, B.6, ISO/IEC FDIS15444-1 : 2000 (18 august 2000) */ + tlprcxstart = int_floordivpow2(res->x0, pdx) << pdx; + tlprcystart = int_floordivpow2(res->y0, pdy) << pdy; + brprcxend = int_ceildivpow2(res->x1, pdx) << pdx; + brprcyend = int_ceildivpow2(res->y1, pdy) << pdy; + + res->pw = (res->x0 == res->x1) ? 0 : ((brprcxend - tlprcxstart) >> pdx); + res->ph = (res->y0 == res->y1) ? 0 : ((brprcyend - tlprcystart) >> pdy); + + if (resno == 0) { + tlcbgxstart = tlprcxstart; + tlcbgystart = tlprcystart; + brcbgxend = brprcxend; + brcbgyend = brprcyend; + cbgwidthexpn = pdx; + cbgheightexpn = pdy; + } else { + tlcbgxstart = int_ceildivpow2(tlprcxstart, 1); + tlcbgystart = int_ceildivpow2(tlprcystart, 1); + brcbgxend = int_ceildivpow2(brprcxend, 1); + brcbgyend = int_ceildivpow2(brprcyend, 1); + cbgwidthexpn = pdx - 1; + cbgheightexpn = pdy - 1; + } + + cblkwidthexpn = int_min(tccp->cblkw, cbgwidthexpn); + cblkheightexpn = int_min(tccp->cblkh, cbgheightexpn); + + for (bandno = 0; bandno < res->numbands; bandno++) { + int x0b, y0b; + int gain, numbps; + opj_stepsize_t *ss = NULL; + + opj_tcd_band_t *band = &res->bands[bandno]; + band->bandno = resno == 0 ? 0 : bandno + 1; + x0b = (band->bandno == 1) || (band->bandno == 3) ? 1 : 0; + y0b = (band->bandno == 2) || (band->bandno == 3) ? 1 : 0; + + if (band->bandno == 0) { + /* band border (global) */ + band->x0 = int_ceildivpow2(tilec->x0, levelno); + band->y0 = int_ceildivpow2(tilec->y0, levelno); + band->x1 = int_ceildivpow2(tilec->x1, levelno); + band->y1 = int_ceildivpow2(tilec->y1, levelno); + } else { + /* band border (global) */ + band->x0 = int_ceildivpow2(tilec->x0 - (1 << levelno) * x0b, levelno + 1); + band->y0 = int_ceildivpow2(tilec->y0 - (1 << levelno) * y0b, levelno + 1); + band->x1 = int_ceildivpow2(tilec->x1 - (1 << levelno) * x0b, levelno + 1); + band->y1 = int_ceildivpow2(tilec->y1 - (1 << levelno) * y0b, levelno + 1); + } + + ss = &tccp->stepsizes[resno == 0 ? 0 : 3 * (resno - 1) + bandno + 1]; + gain = tccp->qmfbid == 0 ? dwt_getgain_real(band->bandno) : dwt_getgain(band->bandno); + numbps = image->comps[compno].prec + gain; + band->stepsize = (float)(((1.0 + ss->mant / 2048.0) * pow(2.0, numbps - ss->expn)) * 0.5); + band->numbps = ss->expn + tccp->numgbits - 1; /* WHY -1 ? */ + + band->precincts = (opj_tcd_precinct_t *) opj_malloc(res->pw * res->ph * sizeof(opj_tcd_precinct_t)); + + for (precno = 0; precno < res->pw * res->ph; precno++) { + int tlcblkxstart, tlcblkystart, brcblkxend, brcblkyend; + int cbgxstart = tlcbgxstart + (precno % res->pw) * (1 << cbgwidthexpn); + int cbgystart = tlcbgystart + (precno / res->pw) * (1 << cbgheightexpn); + int cbgxend = cbgxstart + (1 << cbgwidthexpn); + int cbgyend = cbgystart + (1 << cbgheightexpn); + + opj_tcd_precinct_t *prc = &band->precincts[precno]; + /* precinct size (global) */ + prc->x0 = int_max(cbgxstart, band->x0); + prc->y0 = int_max(cbgystart, band->y0); + prc->x1 = int_min(cbgxend, band->x1); + prc->y1 = int_min(cbgyend, band->y1); + + tlcblkxstart = int_floordivpow2(prc->x0, cblkwidthexpn) << cblkwidthexpn; + tlcblkystart = int_floordivpow2(prc->y0, cblkheightexpn) << cblkheightexpn; + brcblkxend = int_ceildivpow2(prc->x1, cblkwidthexpn) << cblkwidthexpn; + brcblkyend = int_ceildivpow2(prc->y1, cblkheightexpn) << cblkheightexpn; + prc->cw = (brcblkxend - tlcblkxstart) >> cblkwidthexpn; + prc->ch = (brcblkyend - tlcblkystart) >> cblkheightexpn; + + prc->cblks.dec = (opj_tcd_cblk_dec_t*) opj_malloc(prc->cw * prc->ch * sizeof(opj_tcd_cblk_dec_t)); + + prc->incltree = tgt_create(prc->cw, prc->ch); + prc->imsbtree = tgt_create(prc->cw, prc->ch); + + for (cblkno = 0; cblkno < prc->cw * prc->ch; cblkno++) { + int cblkxstart = tlcblkxstart + (cblkno % prc->cw) * (1 << cblkwidthexpn); + int cblkystart = tlcblkystart + (cblkno / prc->cw) * (1 << cblkheightexpn); + int cblkxend = cblkxstart + (1 << cblkwidthexpn); + int cblkyend = cblkystart + (1 << cblkheightexpn); + + opj_tcd_cblk_dec_t* cblk = &prc->cblks.dec[cblkno]; + cblk->data = NULL; + cblk->segs = NULL; + /* code-block size (global) */ + cblk->x0 = int_max(cblkxstart, prc->x0); + cblk->y0 = int_max(cblkystart, prc->y0); + cblk->x1 = int_min(cblkxend, prc->x1); + cblk->y1 = int_min(cblkyend, prc->y1); + cblk->numsegs = 0; + } + } /* precno */ + } /* bandno */ + } /* resno */ + } /* compno */ + /* tcd_dump(stdout, tcd, &tcd->tcd_image); */ +} + +void tcd_makelayer_fixed(opj_tcd_t *tcd, int layno, int final) { + int compno, resno, bandno, precno, cblkno; + int value; /*, matrice[tcd_tcp->numlayers][tcd_tile->comps[0].numresolutions][3]; */ + int matrice[10][10][3]; + int i, j, k; + + opj_cp_t *cp = tcd->cp; + opj_tcd_tile_t *tcd_tile = tcd->tcd_tile; + opj_tcp_t *tcd_tcp = tcd->tcp; + + /*matrice=(int*)opj_malloc(tcd_tcp->numlayers*tcd_tile->comps[0].numresolutions*3*sizeof(int)); */ + + for (compno = 0; compno < tcd_tile->numcomps; compno++) { + opj_tcd_tilecomp_t *tilec = &tcd_tile->comps[compno]; + for (i = 0; i < tcd_tcp->numlayers; i++) { + for (j = 0; j < tilec->numresolutions; j++) { + for (k = 0; k < 3; k++) { + matrice[i][j][k] = + (int) (cp->matrice[i * tilec->numresolutions * 3 + j * 3 + k] + * (float) (tcd->image->comps[compno].prec / 16.0)); + } + } + } + + for (resno = 0; resno < tilec->numresolutions; resno++) { + opj_tcd_resolution_t *res = &tilec->resolutions[resno]; + for (bandno = 0; bandno < res->numbands; bandno++) { + opj_tcd_band_t *band = &res->bands[bandno]; + for (precno = 0; precno < res->pw * res->ph; precno++) { + opj_tcd_precinct_t *prc = &band->precincts[precno]; + for (cblkno = 0; cblkno < prc->cw * prc->ch; cblkno++) { + opj_tcd_cblk_enc_t *cblk = &prc->cblks.enc[cblkno]; + opj_tcd_layer_t *layer = &cblk->layers[layno]; + int n; + int imsb = tcd->image->comps[compno].prec - cblk->numbps; /* number of bit-plan equal to zero */ + /* Correction of the matrix of coefficient to include the IMSB information */ + if (layno == 0) { + value = matrice[layno][resno][bandno]; + if (imsb >= value) { + value = 0; + } else { + value -= imsb; + } + } else { + value = matrice[layno][resno][bandno] - matrice[layno - 1][resno][bandno]; + if (imsb >= matrice[layno - 1][resno][bandno]) { + value -= (imsb - matrice[layno - 1][resno][bandno]); + if (value < 0) { + value = 0; + } + } + } + + if (layno == 0) { + cblk->numpassesinlayers = 0; + } + + n = cblk->numpassesinlayers; + if (cblk->numpassesinlayers == 0) { + if (value != 0) { + n = 3 * value - 2 + cblk->numpassesinlayers; + } else { + n = cblk->numpassesinlayers; + } + } else { + n = 3 * value + cblk->numpassesinlayers; + } + + layer->numpasses = n - cblk->numpassesinlayers; + + if (!layer->numpasses) + continue; + + if (cblk->numpassesinlayers == 0) { + layer->len = cblk->passes[n - 1].rate; + layer->data = cblk->data; + } else { + layer->len = cblk->passes[n - 1].rate - cblk->passes[cblk->numpassesinlayers - 1].rate; + layer->data = cblk->data + cblk->passes[cblk->numpassesinlayers - 1].rate; + } + if (final) + cblk->numpassesinlayers = n; + } + } + } + } + } +} + +void tcd_rateallocate_fixed(opj_tcd_t *tcd) { + int layno; + for (layno = 0; layno < tcd->tcp->numlayers; layno++) { + tcd_makelayer_fixed(tcd, layno, 1); + } +} + +void tcd_makelayer(opj_tcd_t *tcd, int layno, double thresh, int final) { + int compno, resno, bandno, precno, cblkno, passno; + + opj_tcd_tile_t *tcd_tile = tcd->tcd_tile; + + tcd_tile->distolayer[layno] = 0; /* fixed_quality */ + + for (compno = 0; compno < tcd_tile->numcomps; compno++) { + opj_tcd_tilecomp_t *tilec = &tcd_tile->comps[compno]; + for (resno = 0; resno < tilec->numresolutions; resno++) { + opj_tcd_resolution_t *res = &tilec->resolutions[resno]; + for (bandno = 0; bandno < res->numbands; bandno++) { + opj_tcd_band_t *band = &res->bands[bandno]; + for (precno = 0; precno < res->pw * res->ph; precno++) { + opj_tcd_precinct_t *prc = &band->precincts[precno]; + for (cblkno = 0; cblkno < prc->cw * prc->ch; cblkno++) { + opj_tcd_cblk_enc_t *cblk = &prc->cblks.enc[cblkno]; + opj_tcd_layer_t *layer = &cblk->layers[layno]; + + int n; + if (layno == 0) { + cblk->numpassesinlayers = 0; + } + n = cblk->numpassesinlayers; + for (passno = cblk->numpassesinlayers; passno < cblk->totalpasses; passno++) { + int dr; + double dd; + opj_tcd_pass_t *pass = &cblk->passes[passno]; + if (n == 0) { + dr = pass->rate; + dd = pass->distortiondec; + } else { + dr = pass->rate - cblk->passes[n - 1].rate; + dd = pass->distortiondec - cblk->passes[n - 1].distortiondec; + } + if (!dr) { + if (dd != 0) + n = passno + 1; + continue; + } + if (dd / dr >= thresh) + n = passno + 1; + } + layer->numpasses = n - cblk->numpassesinlayers; + + if (!layer->numpasses) { + layer->disto = 0; + continue; + } + if (cblk->numpassesinlayers == 0) { + layer->len = cblk->passes[n - 1].rate; + layer->data = cblk->data; + layer->disto = cblk->passes[n - 1].distortiondec; + } else { + layer->len = cblk->passes[n - 1].rate - cblk->passes[cblk->numpassesinlayers - 1].rate; + layer->data = cblk->data + cblk->passes[cblk->numpassesinlayers - 1].rate; + layer->disto = cblk->passes[n - 1].distortiondec - cblk->passes[cblk->numpassesinlayers - 1].distortiondec; + } + + tcd_tile->distolayer[layno] += layer->disto; /* fixed_quality */ + + if (final) + cblk->numpassesinlayers = n; + } + } + } + } + } +} + +bool tcd_rateallocate(opj_tcd_t *tcd, unsigned char *dest, int len, opj_codestream_info_t *cstr_info) { + int compno, resno, bandno, precno, cblkno, passno, layno; + double min, max; + double cumdisto[100]; /* fixed_quality */ + const double K = 1; /* 1.1; fixed_quality */ + double maxSE = 0; + + opj_cp_t *cp = tcd->cp; + opj_tcd_tile_t *tcd_tile = tcd->tcd_tile; + opj_tcp_t *tcd_tcp = tcd->tcp; + + min = DBL_MAX; + max = 0; + + tcd_tile->numpix = 0; /* fixed_quality */ + + for (compno = 0; compno < tcd_tile->numcomps; compno++) { + opj_tcd_tilecomp_t *tilec = &tcd_tile->comps[compno]; + tilec->numpix = 0; + + for (resno = 0; resno < tilec->numresolutions; resno++) { + opj_tcd_resolution_t *res = &tilec->resolutions[resno]; + + for (bandno = 0; bandno < res->numbands; bandno++) { + opj_tcd_band_t *band = &res->bands[bandno]; + + for (precno = 0; precno < res->pw * res->ph; precno++) { + opj_tcd_precinct_t *prc = &band->precincts[precno]; + + for (cblkno = 0; cblkno < prc->cw * prc->ch; cblkno++) { + opj_tcd_cblk_enc_t *cblk = &prc->cblks.enc[cblkno]; + + for (passno = 0; passno < cblk->totalpasses; passno++) { + opj_tcd_pass_t *pass = &cblk->passes[passno]; + int dr; + double dd, rdslope; + if (passno == 0) { + dr = pass->rate; + dd = pass->distortiondec; + } else { + dr = pass->rate - cblk->passes[passno - 1].rate; + dd = pass->distortiondec - cblk->passes[passno - 1].distortiondec; + } + if (dr == 0) { + continue; + } + rdslope = dd / dr; + if (rdslope < min) { + min = rdslope; + } + if (rdslope > max) { + max = rdslope; + } + } /* passno */ + + /* fixed_quality */ + tcd_tile->numpix += ((cblk->x1 - cblk->x0) * (cblk->y1 - cblk->y0)); + tilec->numpix += ((cblk->x1 - cblk->x0) * (cblk->y1 - cblk->y0)); + } /* cbklno */ + } /* precno */ + } /* bandno */ + } /* resno */ + + maxSE += (((double)(1 << tcd->image->comps[compno].prec) - 1.0) + * ((double)(1 << tcd->image->comps[compno].prec) -1.0)) + * ((double)(tilec->numpix)); + } /* compno */ + + /* index file */ + if(cstr_info) { + opj_tile_info_t *tile_info = &cstr_info->tile[tcd->tcd_tileno]; + tile_info->numpix = tcd_tile->numpix; + tile_info->distotile = tcd_tile->distotile; + tile_info->thresh = (double *) opj_malloc(tcd_tcp->numlayers * sizeof(double)); + } + + for (layno = 0; layno < tcd_tcp->numlayers; layno++) { + double lo = min; + double hi = max; + int success = 0; + int maxlen = tcd_tcp->rates[layno] ? int_min(((int) ceil(tcd_tcp->rates[layno])), len) : len; + double goodthresh = 0; + double stable_thresh = 0; + int i; + double distotarget; /* fixed_quality */ + + /* fixed_quality */ + distotarget = tcd_tile->distotile - ((K * maxSE) / pow((float)10, tcd_tcp->distoratio[layno] / 10)); + + /* Don't try to find an optimal threshold but rather take everything not included yet, if + -r xx,yy,zz,0 (disto_alloc == 1 and rates == 0) + -q xx,yy,zz,0 (fixed_quality == 1 and distoratio == 0) + ==> possible to have some lossy layers and the last layer for sure lossless */ + if ( ((cp->disto_alloc==1) && (tcd_tcp->rates[layno]>0)) || ((cp->fixed_quality==1) && (tcd_tcp->distoratio[layno]>0))) { + opj_t2_t *t2 = t2_create(tcd->cinfo, tcd->image, cp); + double thresh = 0; + + for (i = 0; i < 128; i++) { + int l = 0; + double distoachieved = 0; /* fixed_quality */ + thresh = (lo + hi) / 2; + + tcd_makelayer(tcd, layno, thresh, 0); + + if (cp->fixed_quality) { /* fixed_quality */ + if(cp->cinema){ + l = t2_encode_packets(t2,tcd->tcd_tileno, tcd_tile, layno + 1, dest, maxlen, cstr_info,tcd->cur_tp_num,tcd->tp_pos,tcd->cur_pino,THRESH_CALC, tcd->cur_totnum_tp); + if (l == -999) { + lo = thresh; + continue; + }else{ + distoachieved = layno == 0 ? + tcd_tile->distolayer[0] : cumdisto[layno - 1] + tcd_tile->distolayer[layno]; + if (distoachieved < distotarget) { + hi=thresh; + stable_thresh = thresh; + continue; + }else{ + lo=thresh; + } + } + }else{ + distoachieved = (layno == 0) ? + tcd_tile->distolayer[0] : (cumdisto[layno - 1] + tcd_tile->distolayer[layno]); + if (distoachieved < distotarget) { + hi = thresh; + stable_thresh = thresh; + continue; + } + lo = thresh; + } + } else { + l = t2_encode_packets(t2, tcd->tcd_tileno, tcd_tile, layno + 1, dest, maxlen, cstr_info,tcd->cur_tp_num,tcd->tp_pos,tcd->cur_pino,THRESH_CALC, tcd->cur_totnum_tp); + /* TODO: what to do with l ??? seek / tell ??? */ + /* opj_event_msg(tcd->cinfo, EVT_INFO, "rate alloc: len=%d, max=%d\n", l, maxlen); */ + if (l == -999) { + lo = thresh; + continue; + } + hi = thresh; + stable_thresh = thresh; + } + } + success = 1; + goodthresh = stable_thresh == 0? thresh : stable_thresh; + t2_destroy(t2); + } else { + success = 1; + goodthresh = min; + } + + if (!success) { + return false; + } + + if(cstr_info) { /* Threshold for Marcela Index */ + cstr_info->tile[tcd->tcd_tileno].thresh[layno] = goodthresh; + } + tcd_makelayer(tcd, layno, goodthresh, 1); + + /* fixed_quality */ + cumdisto[layno] = (layno == 0) ? tcd_tile->distolayer[0] : (cumdisto[layno - 1] + tcd_tile->distolayer[layno]); + } + + return true; +} + +int tcd_encode_tile(opj_tcd_t *tcd, int tileno, unsigned char *dest, int len, opj_codestream_info_t *cstr_info) { + int compno; + int l, i, numpacks = 0; + opj_tcd_tile_t *tile = NULL; + opj_tcp_t *tcd_tcp = NULL; + opj_cp_t *cp = NULL; + + opj_tcp_t *tcp = &tcd->cp->tcps[0]; + opj_tccp_t *tccp = &tcp->tccps[0]; + opj_image_t *image = tcd->image; + + opj_t1_t *t1 = NULL; /* T1 component */ + opj_t2_t *t2 = NULL; /* T2 component */ + + tcd->tcd_tileno = tileno; + tcd->tcd_tile = tcd->tcd_image->tiles; + tcd->tcp = &tcd->cp->tcps[tileno]; + + tile = tcd->tcd_tile; + tcd_tcp = tcd->tcp; + cp = tcd->cp; + + if(tcd->cur_tp_num == 0){ + tcd->encoding_time = opj_clock(); /* time needed to encode a tile */ + /* INDEX >> "Precinct_nb_X et Precinct_nb_Y" */ + if(cstr_info) { + opj_tcd_tilecomp_t *tilec_idx = &tile->comps[0]; /* based on component 0 */ + for (i = 0; i < tilec_idx->numresolutions; i++) { + opj_tcd_resolution_t *res_idx = &tilec_idx->resolutions[i]; + + cstr_info->tile[tileno].pw[i] = res_idx->pw; + cstr_info->tile[tileno].ph[i] = res_idx->ph; + + numpacks += res_idx->pw * res_idx->ph; + + cstr_info->tile[tileno].pdx[i] = tccp->prcw[i]; + cstr_info->tile[tileno].pdy[i] = tccp->prch[i]; + } + cstr_info->tile[tileno].packet = (opj_packet_info_t*) opj_calloc(cstr_info->numcomps * cstr_info->numlayers * numpacks, sizeof(opj_packet_info_t)); + } + /* << INDEX */ + + /*---------------TILE-------------------*/ + + for (compno = 0; compno < tile->numcomps; compno++) { + int x, y; + + int adjust = image->comps[compno].sgnd ? 0 : 1 << (image->comps[compno].prec - 1); + int offset_x = int_ceildiv(image->x0, image->comps[compno].dx); + int offset_y = int_ceildiv(image->y0, image->comps[compno].dy); + + opj_tcd_tilecomp_t *tilec = &tile->comps[compno]; + int tw = tilec->x1 - tilec->x0; + int w = int_ceildiv(image->x1 - image->x0, image->comps[compno].dx); + + /* extract tile data */ + + if (tcd_tcp->tccps[compno].qmfbid == 1) { + for (y = tilec->y0; y < tilec->y1; y++) { + /* start of the src tile scanline */ + int *data = &image->comps[compno].data[(tilec->x0 - offset_x) + (y - offset_y) * w]; + /* start of the dst tile scanline */ + int *tile_data = &tilec->data[(y - tilec->y0) * tw]; + for (x = tilec->x0; x < tilec->x1; x++) { + *tile_data++ = *data++ - adjust; + } + } + } else if (tcd_tcp->tccps[compno].qmfbid == 0) { + for (y = tilec->y0; y < tilec->y1; y++) { + /* start of the src tile scanline */ + int *data = &image->comps[compno].data[(tilec->x0 - offset_x) + (y - offset_y) * w]; + /* start of the dst tile scanline */ + int *tile_data = &tilec->data[(y - tilec->y0) * tw]; + for (x = tilec->x0; x < tilec->x1; x++) { + *tile_data++ = (*data++ - adjust) << 11; + } + + } + } + } + + /*----------------MCT-------------------*/ + if (tcd_tcp->mct) { + int samples = (tile->comps[0].x1 - tile->comps[0].x0) * (tile->comps[0].y1 - tile->comps[0].y0); + if (tcd_tcp->tccps[0].qmfbid == 0) { + mct_encode_real(tile->comps[0].data, tile->comps[1].data, tile->comps[2].data, samples); + } else { + mct_encode(tile->comps[0].data, tile->comps[1].data, tile->comps[2].data, samples); + } + } + + /*----------------DWT---------------------*/ + + for (compno = 0; compno < tile->numcomps; compno++) { + opj_tcd_tilecomp_t *tilec = &tile->comps[compno]; + if (tcd_tcp->tccps[compno].qmfbid == 1) { + dwt_encode(tilec); + } else if (tcd_tcp->tccps[compno].qmfbid == 0) { + dwt_encode_real(tilec); + } + } + + /*------------------TIER1-----------------*/ + t1 = t1_create(tcd->cinfo); + t1_encode_cblks(t1, tile, tcd_tcp); + t1_destroy(t1); + + /*-----------RATE-ALLOCATE------------------*/ + + /* INDEX */ + if(cstr_info) { + cstr_info->index_write = 0; + } + if (cp->disto_alloc || cp->fixed_quality) { /* fixed_quality */ + /* Normal Rate/distortion allocation */ + tcd_rateallocate(tcd, dest, len, cstr_info); + } else { + /* Fixed layer allocation */ + tcd_rateallocate_fixed(tcd); + } + } + /*--------------TIER2------------------*/ + + /* INDEX */ + if(cstr_info) { + cstr_info->index_write = 1; + } + + t2 = t2_create(tcd->cinfo, image, cp); + l = t2_encode_packets(t2,tileno, tile, tcd_tcp->numlayers, dest, len, cstr_info,tcd->tp_num,tcd->tp_pos,tcd->cur_pino,FINAL_PASS,tcd->cur_totnum_tp); + t2_destroy(t2); + + /*---------------CLEAN-------------------*/ + + + if(tcd->cur_tp_num == tcd->cur_totnum_tp - 1){ + tcd->encoding_time = opj_clock() - tcd->encoding_time; + opj_event_msg(tcd->cinfo, EVT_INFO, "- tile encoded in %f s\n", tcd->encoding_time); + + /* cleaning memory */ + for (compno = 0; compno < tile->numcomps; compno++) { + opj_tcd_tilecomp_t *tilec = &tile->comps[compno]; + opj_aligned_free(tilec->data); + } + } + + return l; +} + +bool tcd_decode_tile(opj_tcd_t *tcd, unsigned char *src, int len, int tileno, opj_codestream_info_t *cstr_info) { + int l; + int compno; + int eof = 0; + double tile_time, t1_time, dwt_time; + opj_tcd_tile_t *tile = NULL; + + opj_t1_t *t1 = NULL; /* T1 component */ + opj_t2_t *t2 = NULL; /* T2 component */ + + tcd->tcd_tileno = tileno; + tcd->tcd_tile = &(tcd->tcd_image->tiles[tileno]); + tcd->tcp = &(tcd->cp->tcps[tileno]); + tile = tcd->tcd_tile; + + tile_time = opj_clock(); /* time needed to decode a tile */ + opj_event_msg(tcd->cinfo, EVT_INFO, "tile %d of %d\n", tileno + 1, tcd->cp->tw * tcd->cp->th); + + /* INDEX >> */ + if(cstr_info) { + int resno, compno, numprec = 0; + for (compno = 0; compno < cstr_info->numcomps; compno++) { + opj_tcp_t *tcp = &tcd->cp->tcps[0]; + opj_tccp_t *tccp = &tcp->tccps[compno]; + opj_tcd_tilecomp_t *tilec_idx = &tile->comps[compno]; + for (resno = 0; resno < tilec_idx->numresolutions; resno++) { + opj_tcd_resolution_t *res_idx = &tilec_idx->resolutions[resno]; + cstr_info->tile[tileno].pw[resno] = res_idx->pw; + cstr_info->tile[tileno].ph[resno] = res_idx->ph; + numprec += res_idx->pw * res_idx->ph; + if (tccp->csty & J2K_CP_CSTY_PRT) { + cstr_info->tile[tileno].pdx[resno] = tccp->prcw[resno]; + cstr_info->tile[tileno].pdy[resno] = tccp->prch[resno]; + } + else { + cstr_info->tile[tileno].pdx[resno] = 15; + cstr_info->tile[tileno].pdx[resno] = 15; + } + } + } + cstr_info->tile[tileno].packet = (opj_packet_info_t *) opj_malloc(cstr_info->numlayers * numprec * sizeof(opj_packet_info_t)); + cstr_info->packno = 0; + } + /* << INDEX */ + + /*--------------TIER2------------------*/ + + t2 = t2_create(tcd->cinfo, tcd->image, tcd->cp); + l = t2_decode_packets(t2, src, len, tileno, tile, cstr_info); + t2_destroy(t2); + + if (l == -999) { + eof = 1; + opj_event_msg(tcd->cinfo, EVT_ERROR, "tcd_decode: incomplete bistream\n"); + } + + /*------------------TIER1-----------------*/ + + t1_time = opj_clock(); /* time needed to decode a tile */ + t1 = t1_create(tcd->cinfo); + for (compno = 0; compno < tile->numcomps; ++compno) { + opj_tcd_tilecomp_t* tilec = &tile->comps[compno]; + /* The +3 is headroom required by the vectorized DWT */ + tilec->data = (int*) opj_aligned_malloc((((tilec->x1 - tilec->x0) * (tilec->y1 - tilec->y0))+3) * sizeof(int)); + t1_decode_cblks(t1, tilec, &tcd->tcp->tccps[compno]); + } + t1_destroy(t1); + t1_time = opj_clock() - t1_time; + opj_event_msg(tcd->cinfo, EVT_INFO, "- tiers-1 took %f s\n", t1_time); + + /*----------------DWT---------------------*/ + + dwt_time = opj_clock(); /* time needed to decode a tile */ + for (compno = 0; compno < tile->numcomps; compno++) { + opj_tcd_tilecomp_t *tilec = &tile->comps[compno]; + int numres2decode; + + if (tcd->cp->reduce != 0) { + tcd->image->comps[compno].resno_decoded = + tile->comps[compno].numresolutions - tcd->cp->reduce - 1; + if (tcd->image->comps[compno].resno_decoded < 0) { + opj_event_msg(tcd->cinfo, EVT_ERROR, "Error decoding tile. The number of resolutions to remove [%d+1] is higher than the number " + " of resolutions in the original codestream [%d]\nModify the cp_reduce parameter.\n", tcd->cp->reduce, tile->comps[compno].numresolutions); + return false; + } + } + + numres2decode = tcd->image->comps[compno].resno_decoded + 1; + if(numres2decode > 0){ + if (tcd->tcp->tccps[compno].qmfbid == 1) { + dwt_decode(tilec, numres2decode); + } else { + dwt_decode_real(tilec, numres2decode); + } + } + } + dwt_time = opj_clock() - dwt_time; + opj_event_msg(tcd->cinfo, EVT_INFO, "- dwt took %f s\n", dwt_time); + + /*----------------MCT-------------------*/ + + if (tcd->tcp->mct) { + int n = (tile->comps[0].x1 - tile->comps[0].x0) * (tile->comps[0].y1 - tile->comps[0].y0); + if (tcd->tcp->tccps[0].qmfbid == 1) { + mct_decode( + tile->comps[0].data, + tile->comps[1].data, + tile->comps[2].data, + n); + } else { + mct_decode_real( + (float*)tile->comps[0].data, + (float*)tile->comps[1].data, + (float*)tile->comps[2].data, + n); + } + } + + /*---------------TILE-------------------*/ + + for (compno = 0; compno < tile->numcomps; ++compno) { + opj_tcd_tilecomp_t* tilec = &tile->comps[compno]; + opj_image_comp_t* imagec = &tcd->image->comps[compno]; + opj_tcd_resolution_t* res = &tilec->resolutions[imagec->resno_decoded]; + int adjust = imagec->sgnd ? 0 : 1 << (imagec->prec - 1); + int min = imagec->sgnd ? -(1 << (imagec->prec - 1)) : 0; + int max = imagec->sgnd ? (1 << (imagec->prec - 1)) - 1 : (1 << imagec->prec) - 1; + + int tw = tilec->x1 - tilec->x0; + int w = imagec->w; + + int offset_x = int_ceildivpow2(imagec->x0, imagec->factor); + int offset_y = int_ceildivpow2(imagec->y0, imagec->factor); + + int i, j; + if(!imagec->data){ + imagec->data = (int*) opj_malloc(imagec->w * imagec->h * sizeof(int)); + } + if(tcd->tcp->tccps[compno].qmfbid == 1) { + for(j = res->y0; j < res->y1; ++j) { + for(i = res->x0; i < res->x1; ++i) { + int v = tilec->data[i - res->x0 + (j - res->y0) * tw]; + v += adjust; + imagec->data[(i - offset_x) + (j - offset_y) * w] = int_clamp(v, min, max); + } + } + }else{ + for(j = res->y0; j < res->y1; ++j) { + for(i = res->x0; i < res->x1; ++i) { + float tmp = ((float*)tilec->data)[i - res->x0 + (j - res->y0) * tw]; + int v = lrintf(tmp); + v += adjust; + imagec->data[(i - offset_x) + (j - offset_y) * w] = int_clamp(v, min, max); + } + } + } + opj_aligned_free(tilec->data); + } + + tile_time = opj_clock() - tile_time; /* time needed to decode a tile */ + opj_event_msg(tcd->cinfo, EVT_INFO, "- tile decoded in %f s\n", tile_time); + + if (eof) { + return false; + } + + return true; +} + +void tcd_free_decode(opj_tcd_t *tcd) { + opj_tcd_image_t *tcd_image = tcd->tcd_image; + opj_free(tcd_image->tiles); +} + +void tcd_free_decode_tile(opj_tcd_t *tcd, int tileno) { + int compno,resno,bandno,precno; + + opj_tcd_image_t *tcd_image = tcd->tcd_image; + + opj_tcd_tile_t *tile = &tcd_image->tiles[tileno]; + for (compno = 0; compno < tile->numcomps; compno++) { + opj_tcd_tilecomp_t *tilec = &tile->comps[compno]; + for (resno = 0; resno < tilec->numresolutions; resno++) { + opj_tcd_resolution_t *res = &tilec->resolutions[resno]; + for (bandno = 0; bandno < res->numbands; bandno++) { + opj_tcd_band_t *band = &res->bands[bandno]; + for (precno = 0; precno < res->ph * res->pw; precno++) { + opj_tcd_precinct_t *prec = &band->precincts[precno]; + if (prec->imsbtree != NULL) tgt_destroy(prec->imsbtree); + if (prec->incltree != NULL) tgt_destroy(prec->incltree); + } + opj_free(band->precincts); + } + } + opj_free(tilec->resolutions); + } + opj_free(tile->comps); +} + + + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/tcd.h b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/tcd.h new file mode 100644 index 0000000..a533073 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/tcd.h @@ -0,0 +1,286 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __TCD_H +#define __TCD_H +/** +@file tcd.h +@brief Implementation of a tile coder/decoder (TCD) + +The functions in TCD.C have for goal to encode or decode each tile independently from +each other. The functions in TCD.C are used by some function in J2K.C. +*/ + +/** @defgroup TCD TCD - Implementation of a tile coder/decoder */ +/*@{*/ + +/** +FIXME: documentation +*/ +typedef struct opj_tcd_seg { + unsigned char** data; + int dataindex; + int numpasses; + int len; + int maxpasses; + int numnewpasses; + int newlen; +} opj_tcd_seg_t; + +/** +FIXME: documentation +*/ +typedef struct opj_tcd_pass { + int rate; + double distortiondec; + int term, len; +} opj_tcd_pass_t; + +/** +FIXME: documentation +*/ +typedef struct opj_tcd_layer { + int numpasses; /* Number of passes in the layer */ + int len; /* len of information */ + double disto; /* add for index (Cfr. Marcela) */ + unsigned char *data; /* data */ +} opj_tcd_layer_t; + +/** +FIXME: documentation +*/ +typedef struct opj_tcd_cblk_enc { + unsigned char* data; /* Data */ + opj_tcd_layer_t* layers; /* layer information */ + opj_tcd_pass_t* passes; /* information about the passes */ + int x0, y0, x1, y1; /* dimension of the code-blocks : left upper corner (x0, y0) right low corner (x1,y1) */ + int numbps; + int numlenbits; + int numpasses; /* number of pass already done for the code-blocks */ + int numpassesinlayers; /* number of passes in the layer */ + int totalpasses; /* total number of passes */ +} opj_tcd_cblk_enc_t; + +typedef struct opj_tcd_cblk_dec { + unsigned char* data; /* Data */ + opj_tcd_seg_t* segs; /* segments informations */ + int x0, y0, x1, y1; /* dimension of the code-blocks : left upper corner (x0, y0) right low corner (x1,y1) */ + int numbps; + int numlenbits; + int len; /* length */ + int numnewpasses; /* number of pass added to the code-blocks */ + int numsegs; /* number of segments */ +} opj_tcd_cblk_dec_t; + +/** +FIXME: documentation +*/ +typedef struct opj_tcd_precinct { + int x0, y0, x1, y1; /* dimension of the precinct : left upper corner (x0, y0) right low corner (x1,y1) */ + int cw, ch; /* number of precinct in width and heigth */ + union{ /* code-blocks informations */ + opj_tcd_cblk_enc_t* enc; + opj_tcd_cblk_dec_t* dec; + } cblks; + opj_tgt_tree_t *incltree; /* inclusion tree */ + opj_tgt_tree_t *imsbtree; /* IMSB tree */ +} opj_tcd_precinct_t; + +/** +FIXME: documentation +*/ +typedef struct opj_tcd_band { + int x0, y0, x1, y1; /* dimension of the subband : left upper corner (x0, y0) right low corner (x1,y1) */ + int bandno; + opj_tcd_precinct_t *precincts; /* precinct information */ + int numbps; + float stepsize; +} opj_tcd_band_t; + +/** +FIXME: documentation +*/ +typedef struct opj_tcd_resolution { + int x0, y0, x1, y1; /* dimension of the resolution level : left upper corner (x0, y0) right low corner (x1,y1) */ + int pw, ph; + int numbands; /* number sub-band for the resolution level */ + opj_tcd_band_t bands[3]; /* subband information */ +} opj_tcd_resolution_t; + +/** +FIXME: documentation +*/ +typedef struct opj_tcd_tilecomp { + int x0, y0, x1, y1; /* dimension of component : left upper corner (x0, y0) right low corner (x1,y1) */ + int numresolutions; /* number of resolutions level */ + opj_tcd_resolution_t *resolutions; /* resolutions information */ + int *data; /* data of the component */ + int numpix; /* add fixed_quality */ +} opj_tcd_tilecomp_t; + +/** +FIXME: documentation +*/ +typedef struct opj_tcd_tile { + int x0, y0, x1, y1; /* dimension of the tile : left upper corner (x0, y0) right low corner (x1,y1) */ + int numcomps; /* number of components in tile */ + opj_tcd_tilecomp_t *comps; /* Components information */ + int numpix; /* add fixed_quality */ + double distotile; /* add fixed_quality */ + double distolayer[100]; /* add fixed_quality */ + /** packet number */ + int packno; +} opj_tcd_tile_t; + +/** +FIXME: documentation +*/ +typedef struct opj_tcd_image { + int tw, th; /* number of tiles in width and heigth */ + opj_tcd_tile_t *tiles; /* Tiles information */ +} opj_tcd_image_t; + +/** +Tile coder/decoder +*/ +typedef struct opj_tcd { + /** Position of the tilepart flag in Progression order*/ + int tp_pos; + /** Tile part number*/ + int tp_num; + /** Current tile part number*/ + int cur_tp_num; + /** Total number of tileparts of the current tile*/ + int cur_totnum_tp; + /** Current Packet iterator number */ + int cur_pino; + /** codec context */ + opj_common_ptr cinfo; + + /** info on each image tile */ + opj_tcd_image_t *tcd_image; + /** image */ + opj_image_t *image; + /** coding parameters */ + opj_cp_t *cp; + /** pointer to the current encoded/decoded tile */ + opj_tcd_tile_t *tcd_tile; + /** coding/decoding parameters common to all tiles */ + opj_tcp_t *tcp; + /** current encoded/decoded tile */ + int tcd_tileno; + /** Time taken to encode a tile*/ + double encoding_time; +} opj_tcd_t; + +/** @name Exported functions */ +/*@{*/ +/* ----------------------------------------------------------------------- */ + +/** +Dump the content of a tcd structure +*/ +void tcd_dump(FILE *fd, opj_tcd_t *tcd, opj_tcd_image_t *img); +/** +Create a new TCD handle +@param cinfo Codec context info +@return Returns a new TCD handle if successful returns NULL otherwise +*/ +opj_tcd_t* tcd_create(opj_common_ptr cinfo); +/** +Destroy a previously created TCD handle +@param tcd TCD handle to destroy +*/ +void tcd_destroy(opj_tcd_t *tcd); +/** +Initialize the tile coder (allocate the memory) +@param tcd TCD handle +@param image Raw image +@param cp Coding parameters +@param curtileno Number that identifies the tile that will be encoded +*/ +void tcd_malloc_encode(opj_tcd_t *tcd, opj_image_t * image, opj_cp_t * cp, int curtileno); +/** +Free the memory allocated for encoding +@param tcd TCD handle +*/ +void tcd_free_encode(opj_tcd_t *tcd); +/** +Initialize the tile coder (reuses the memory allocated by tcd_malloc_encode) +@param tcd TCD handle +@param image Raw image +@param cp Coding parameters +@param curtileno Number that identifies the tile that will be encoded +*/ +void tcd_init_encode(opj_tcd_t *tcd, opj_image_t * image, opj_cp_t * cp, int curtileno); +/** +Initialize the tile decoder +@param tcd TCD handle +@param image Raw image +@param cp Coding parameters +*/ +void tcd_malloc_decode(opj_tcd_t *tcd, opj_image_t * image, opj_cp_t * cp); +void tcd_malloc_decode_tile(opj_tcd_t *tcd, opj_image_t * image, opj_cp_t * cp, int tileno, opj_codestream_info_t *cstr_info); +void tcd_makelayer_fixed(opj_tcd_t *tcd, int layno, int final); +void tcd_rateallocate_fixed(opj_tcd_t *tcd); +void tcd_makelayer(opj_tcd_t *tcd, int layno, double thresh, int final); +bool tcd_rateallocate(opj_tcd_t *tcd, unsigned char *dest, int len, opj_codestream_info_t *cstr_info); +/** +Encode a tile from the raw image into a buffer +@param tcd TCD handle +@param tileno Number that identifies one of the tiles to be encoded +@param dest Destination buffer +@param len Length of destination buffer +@param cstr_info Codestream information structure +@return +*/ +int tcd_encode_tile(opj_tcd_t *tcd, int tileno, unsigned char *dest, int len, opj_codestream_info_t *cstr_info); +/** +Decode a tile from a buffer into a raw image +@param tcd TCD handle +@param src Source buffer +@param len Length of source buffer +@param tileno Number that identifies one of the tiles to be decoded +@param cstr_info Codestream information structure +*/ +bool tcd_decode_tile(opj_tcd_t *tcd, unsigned char *src, int len, int tileno, opj_codestream_info_t *cstr_info); +/** +Free the memory allocated for decoding +@param tcd TCD handle +*/ +void tcd_free_decode(opj_tcd_t *tcd); +void tcd_free_decode_tile(opj_tcd_t *tcd, int tileno); + +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __TCD_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/tgt.c b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/tgt.c new file mode 100644 index 0000000..a5dbcd3 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/tgt.c @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "opj_includes.h" + +/* +========================================================== + Tag-tree coder interface +========================================================== +*/ + +opj_tgt_tree_t *tgt_create(int numleafsh, int numleafsv) { + int nplh[32]; + int nplv[32]; + opj_tgt_node_t *node = NULL; + opj_tgt_node_t *parentnode = NULL; + opj_tgt_node_t *parentnode0 = NULL; + opj_tgt_tree_t *tree = NULL; + int i, j, k; + int numlvls; + int n; + + tree = (opj_tgt_tree_t *) opj_malloc(sizeof(opj_tgt_tree_t)); + if(!tree) return NULL; + tree->numleafsh = numleafsh; + tree->numleafsv = numleafsv; + + numlvls = 0; + nplh[0] = numleafsh; + nplv[0] = numleafsv; + tree->numnodes = 0; + do { + n = nplh[numlvls] * nplv[numlvls]; + nplh[numlvls + 1] = (nplh[numlvls] + 1) / 2; + nplv[numlvls + 1] = (nplv[numlvls] + 1) / 2; + tree->numnodes += n; + ++numlvls; + } while (n > 1); + + /* ADD */ + if (tree->numnodes == 0) { + opj_free(tree); + return NULL; + } + + tree->nodes = (opj_tgt_node_t*) opj_calloc(tree->numnodes, sizeof(opj_tgt_node_t)); + if(!tree->nodes) { + opj_free(tree); + return NULL; + } + + node = tree->nodes; + parentnode = &tree->nodes[tree->numleafsh * tree->numleafsv]; + parentnode0 = parentnode; + + for (i = 0; i < numlvls - 1; ++i) { + for (j = 0; j < nplv[i]; ++j) { + k = nplh[i]; + while (--k >= 0) { + node->parent = parentnode; + ++node; + if (--k >= 0) { + node->parent = parentnode; + ++node; + } + ++parentnode; + } + if ((j & 1) || j == nplv[i] - 1) { + parentnode0 = parentnode; + } else { + parentnode = parentnode0; + parentnode0 += nplh[i]; + } + } + } + node->parent = 0; + + tgt_reset(tree); + + return tree; +} + +void tgt_destroy(opj_tgt_tree_t *tree) { + opj_free(tree->nodes); + opj_free(tree); +} + +void tgt_reset(opj_tgt_tree_t *tree) { + int i; + + if (NULL == tree) + return; + + for (i = 0; i < tree->numnodes; i++) { + tree->nodes[i].value = 999; + tree->nodes[i].low = 0; + tree->nodes[i].known = 0; + } +} + +void tgt_setvalue(opj_tgt_tree_t *tree, int leafno, int value) { + opj_tgt_node_t *node; + node = &tree->nodes[leafno]; + while (node && node->value > value) { + node->value = value; + node = node->parent; + } +} + +void tgt_encode(opj_bio_t *bio, opj_tgt_tree_t *tree, int leafno, int threshold) { + opj_tgt_node_t *stk[31]; + opj_tgt_node_t **stkptr; + opj_tgt_node_t *node; + int low; + + stkptr = stk; + node = &tree->nodes[leafno]; + while (node->parent) { + *stkptr++ = node; + node = node->parent; + } + + low = 0; + for (;;) { + if (low > node->low) { + node->low = low; + } else { + low = node->low; + } + + while (low < threshold) { + if (low >= node->value) { + if (!node->known) { + bio_write(bio, 1, 1); + node->known = 1; + } + break; + } + bio_write(bio, 0, 1); + ++low; + } + + node->low = low; + if (stkptr == stk) + break; + node = *--stkptr; + } +} + +int tgt_decode(opj_bio_t *bio, opj_tgt_tree_t *tree, int leafno, int threshold) { + opj_tgt_node_t *stk[31]; + opj_tgt_node_t **stkptr; + opj_tgt_node_t *node; + int low; + + stkptr = stk; + node = &tree->nodes[leafno]; + while (node->parent) { + *stkptr++ = node; + node = node->parent; + } + + low = 0; + for (;;) { + if (low > node->low) { + node->low = low; + } else { + low = node->low; + } + while (low < threshold && low < node->value) { + if (bio_read(bio, 1)) { + node->value = low; + } else { + ++low; + } + } + node->low = low; + if (stkptr == stk) { + break; + } + node = *--stkptr; + } + + return (node->value < threshold) ? 1 : 0; +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/tgt.h b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/tgt.h new file mode 100644 index 0000000..c08c8da --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libopenjpeg/tgt.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __TGT_H +#define __TGT_H +/** +@file tgt.h +@brief Implementation of a tag-tree coder (TGT) + +The functions in TGT.C have for goal to realize a tag-tree coder. The functions in TGT.C +are used by some function in T2.C. +*/ + +/** @defgroup TGT TGT - Implementation of a tag-tree coder */ +/*@{*/ + +/** +Tag node +*/ +typedef struct opj_tgt_node { + struct opj_tgt_node *parent; + int value; + int low; + int known; +} opj_tgt_node_t; + +/** +Tag tree +*/ +typedef struct opj_tgt_tree { + int numleafsh; + int numleafsv; + int numnodes; + opj_tgt_node_t *nodes; +} opj_tgt_tree_t; + +/** @name Exported functions */ +/*@{*/ +/* ----------------------------------------------------------------------- */ +/** +Create a tag-tree +@param numleafsh Width of the array of leafs of the tree +@param numleafsv Height of the array of leafs of the tree +@return Returns a new tag-tree if successful, returns NULL otherwise +*/ +opj_tgt_tree_t *tgt_create(int numleafsh, int numleafsv); +/** +Destroy a tag-tree, liberating memory +@param tree Tag-tree to destroy +*/ +void tgt_destroy(opj_tgt_tree_t *tree); +/** +Reset a tag-tree (set all leaves to 0) +@param tree Tag-tree to reset +*/ +void tgt_reset(opj_tgt_tree_t *tree); +/** +Set the value of a leaf of a tag-tree +@param tree Tag-tree to modify +@param leafno Number that identifies the leaf to modify +@param value New value of the leaf +*/ +void tgt_setvalue(opj_tgt_tree_t *tree, int leafno, int value); +/** +Encode the value of a leaf of the tag-tree up to a given threshold +@param bio Pointer to a BIO handle +@param tree Tag-tree to modify +@param leafno Number that identifies the leaf to encode +@param threshold Threshold to use when encoding value of the leaf +*/ +void tgt_encode(opj_bio_t *bio, opj_tgt_tree_t *tree, int leafno, int threshold); +/** +Decode the value of a leaf of the tag-tree up to a given threshold +@param bio Pointer to a BIO handle +@param tree Tag-tree to decode +@param leafno Number that identifies the leaf to decode +@param threshold Threshold to use when decoding value of the leaf +@return Returns 1 if the node's value < threshold, returns 0 otherwise +*/ +int tgt_decode(opj_bio_t *bio, opj_tgt_tree_t *tree, int leafno, int threshold); +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __TGT_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libs/lcms2/lcms2.h b/gdcm/Utilities/gdcmopenjpeg-v1/libs/lcms2/lcms2.h new file mode 100644 index 0000000..75a3857 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libs/lcms2/lcms2.h @@ -0,0 +1,1722 @@ +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2010 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// +// Version 2.0 +// + +#ifndef _lcms2_H + +// ********** Configuration toggles **************************************** + +// Uncomment this one if you are using big endian machines +// #define CMS_USE_BIG_ENDIAN 1 + +// Uncomment this one if your compiler/machine does NOT support the +// "long long" type. +// #define CMS_DONT_USE_INT64 1 + +// Uncomment this if your compiler doesn't work with fast floor function +// #define CMS_DONT_USE_FAST_FLOOR 1 + +// Uncomment this line if your system does not support multithreading +#define CMS_DONT_USE_PTHREADS 1 + +// Uncomment this line if you want lcms to use the black point tag in profile, +// if commented, lcms will compute the black point by its own. +// It is safer to leave it commented out +// #define CMS_USE_PROFILE_BLACK_POINT_TAG 1 + +// Uncomment this line if you are compiling as C++ and want a C++ API +// #define CMS_USE_CPP_API + +// Uncomment this line if you need strict CGATS syntax. Makes CGATS files to +// require "KEYWORD" on undefined identifiers, keep it comented out unless needed +// #define CMS_STRICT_CGATS 1 + +// ********** End of configuration toggles ****************************** + +// Needed for streams +#include + +// Needed for portability (C99 per 7.1.2) +#include +#include +#include + +#ifndef CMS_USE_CPP_API +# ifdef __cplusplus +extern "C" { +# endif +#endif + +// Version/release +#define LCMS_VERSION 2000 + +// I will give the chance of redefining basic types for compilers that are not fully C99 compliant +#ifndef CMS_BASIC_TYPES_ALREADY_DEFINED + +// Base types +typedef unsigned char cmsUInt8Number; // That is guaranteed by the C99 spec +typedef signed char cmsInt8Number; // That is guaranteed by the C99 spec + +// IEEE float storage numbers +typedef float cmsFloat32Number; +typedef double cmsFloat64Number; + +// 16-bit base types +#if (USHRT_MAX == 65535U) + typedef unsigned short cmsUInt16Number; +#elif (UINT_MAX == 65535U) + typedef unsigned int cmsUInt16Number; +#else +# error "Unable to find 16 bits unsigned type, unsupported compiler" +#endif + +#if (SHRT_MAX == 32767) + typedef short cmsInt16Number; +#elif (INT_MAX == 32767) + typedef int cmsInt16Number; +#else +# error "Unable to find 16 bits signed type, unsupported compiler" +#endif + +// 32-bit base type +#if (UINT_MAX == 4294967295U) + typedef unsigned int cmsUInt32Number; +#elif (ULONG_MAX == 4294967295U) + typedef unsigned long cmsUInt32Number; +#else +# error "Unable to find 32 bit unsigned type, unsupported compiler" +#endif + +#if (INT_MAX == +2147483647) + typedef int cmsInt32Number; +#elif (LONG_MAX == +2147483647) + typedef long cmsInt32Number; +#else +# error "Unable to find 32 bit signed type, unsupported compiler" +#endif + +// 64-bit base types +#ifndef CMS_DONT_USE_INT64 +# if (ULONG_MAX == 18446744073709551615U) + typedef unsigned long cmsUInt64Number; +# elif (ULLONG_MAX == 18446744073709551615U) + typedef unsigned long long cmsUInt64Number; +# else +# define CMS_DONT_USE_INT64 1 +# endif +# if (LONG_MAX == +9223372036854775807) + typedef long cmsInt64Number; +# elif (LLONG_MAX == +9223372036854775807) + typedef long long cmsInt64Number; +# else +# define CMS_DONT_USE_INT64 1 +# endif +#endif +#endif + +// In the case 64 bit numbers are not supported by the compiler +#ifdef CMS_DONT_USE_INT64 + typedef cmsUInt32Number cmsUInt64Number[2]; + typedef cmsInt32Number cmsInt64Number[2]; +#endif + +// Derivative types +typedef cmsUInt32Number cmsSignature; +typedef cmsUInt16Number cmsU8Fixed8Number; +typedef cmsInt32Number cmsS15Fixed16Number; +typedef cmsUInt32Number cmsU16Fixed16Number; + +// Boolean type, which will be using the native integer +typedef int cmsBool; + +// Try to detect windows +#if defined (_WIN32) || defined(_WIN64) || defined(WIN32) || defined(_WIN32_) +# define CMS_IS_WINDOWS_ 1 +#endif + +#ifdef _MSC_VER +# define CMS_IS_WINDOWS_ 1 +#endif + +#ifdef __BORLANDC__ +# define CMS_IS_WINDOWS_ 1 +#endif + +// Try to detect big endian platforms. This list can be endless, so only some checks are performed over here. +// you can pass this toggle to the compiler by using -DCMS_USE_BIG_ENDIAN or something similar + +#if defined(_HOST_BIG_ENDIAN) || defined(__BIG_ENDIAN__) || defined(WORDS_BIGENDIAN) +# define CMS_USE_BIG_ENDIAN 1 +#endif + +#if defined(__sgi__) || defined(__sgi) || defined(__powerpc__) || defined(sparc) +# define CMS_USE_BIG_ENDIAN 1 +#endif + +#if defined(__ppc__) || defined(__s390__) || defined(__s390x__) +# define CMS_USE_BIG_ENDIAN 1 +#endif + +#ifdef TARGET_CPU_PPC +# define CMS_USE_BIG_ENDIAN 1 +#endif + +#ifdef macintosh +# ifndef __LITTLE_ENDIAN__ +# define CMS_USE_BIG_ENDIAN 1 +# endif +#endif + +// Calling convention -- this is hardly platform and compiler dependent +#ifdef CMS_IS_WINDOWS_ +# if defined(CMS_DLL) || defined(CMS_DLL_BUILD) +# ifdef __BORLANDC__ +# define CMSEXPORT __stdcall _export +# define CMSAPI +# else +# define CMSEXPORT _stdcall +# ifdef CMS_DLL_BUILD +# define CMSAPI __declspec(dllexport) +# else +# define CMSAPI __declspec(dllimport) +# endif +# endif +# else +# define CMSEXPORT +# define CMSAPI +# endif +#else +# define CMSEXPORT +# define CMSAPI +#endif + +// Some common definitions +#define cmsMAX_PATH 256 + +#ifndef FALSE +# define FALSE 0 +#endif +#ifndef TRUE +# define TRUE 1 +#endif + +// D50 XYZ normalized to Y=1.0 +#define cmsD50X 0.9642 +#define cmsD50Y 1.0 +#define cmsD50Z 0.8249 + +// V4 perceptual black +#define cmsPERCEPTUAL_BLACK_X 0.00336 +#define cmsPERCEPTUAL_BLACK_Y 0.0034731 +#define cmsPERCEPTUAL_BLACK_Z 0.00287 + +// Definitions in ICC spec +#define cmsMagicNumber 0x61637370 // 'acsp' +#define lcmsSignature 0x6c636d73 // 'lcms' + + +// Base ICC type definitions +typedef enum { + cmsSigChromaticityType = 0x6368726D, // 'chrm' + cmsSigColorantOrderType = 0x636C726F, // 'clro' + cmsSigColorantTableType = 0x636C7274, // 'clrt' + cmsSigCrdInfoType = 0x63726469, // 'crdi' + cmsSigCurveType = 0x63757276, // 'curv' + cmsSigDataType = 0x64617461, // 'data' + cmsSigDateTimeType = 0x6474696D, // 'dtim' + cmsSigDeviceSettingsType = 0x64657673, // 'devs' + cmsSigLut16Type = 0x6d667432, // 'mft2' + cmsSigLut8Type = 0x6d667431, // 'mft1' + cmsSigLutAtoBType = 0x6d414220, // 'mAB ' + cmsSigLutBtoAType = 0x6d424120, // 'mBA ' + cmsSigMeasurementType = 0x6D656173, // 'meas' + cmsSigMultiLocalizedUnicodeType = 0x6D6C7563, // 'mluc' + cmsSigMultiProcessElementType = 0x6D706574, // 'mpet' + cmsSigNamedColorType = 0x6E636f6C, // 'ncol' -- DEPRECATED! + cmsSigNamedColor2Type = 0x6E636C32, // 'ncl2' + cmsSigParametricCurveType = 0x70617261, // 'para' + cmsSigProfileSequenceDescType = 0x70736571, // 'pseq' + cmsSigProfileSequenceIdType = 0x70736964, // 'psid' + cmsSigResponseCurveSet16Type = 0x72637332, // 'rcs2' + cmsSigS15Fixed16ArrayType = 0x73663332, // 'sf32' + cmsSigScreeningType = 0x7363726E, // 'scrn' + cmsSigSignatureType = 0x73696720, // 'sig ' + cmsSigTextType = 0x74657874, // 'text' + cmsSigTextDescriptionType = 0x64657363, // 'desc' + cmsSigU16Fixed16ArrayType = 0x75663332, // 'uf32' + cmsSigUcrBgType = 0x62666420, // 'bfd ' + cmsSigUInt16ArrayType = 0x75693136, // 'ui16' + cmsSigUInt32ArrayType = 0x75693332, // 'ui32' + cmsSigUInt64ArrayType = 0x75693634, // 'ui64' + cmsSigUInt8ArrayType = 0x75693038, // 'ui08' + cmsSigViewingConditionsType = 0x76696577, // 'view' + cmsSigXYZType = 0x58595A20, // 'XYZ ' + cmsSigVcgtType = 0x76636774 // 'vcgt' + +} cmsTagTypeSignature; + +// Base ICC tag definitions +typedef enum { + cmsSigAToB0Tag = 0x41324230, // 'A2B0' + cmsSigAToB1Tag = 0x41324231, // 'A2B1' + cmsSigAToB2Tag = 0x41324232, // 'A2B2' + cmsSigBlueColorantTag = 0x6258595A, // 'bXYZ' + cmsSigBlueMatrixColumnTag = 0x6258595A, // 'bXYZ' + cmsSigBlueTRCTag = 0x62545243, // 'bTRC' + cmsSigBToA0Tag = 0x42324130, // 'B2A0' + cmsSigBToA1Tag = 0x42324131, // 'B2A1' + cmsSigBToA2Tag = 0x42324132, // 'B2A2' + cmsSigCalibrationDateTimeTag = 0x63616C74, // 'calt' + cmsSigCharTargetTag = 0x74617267, // 'targ' + cmsSigChromaticAdaptationTag = 0x63686164, // 'chad' + cmsSigChromaticityTag = 0x6368726D, // 'chrm' + cmsSigColorantOrderTag = 0x636C726F, // 'clro' + cmsSigColorantTableTag = 0x636C7274, // 'clrt' + cmsSigColorantTableOutTag = 0x636C6F74, // 'clot' + cmsSigColorimetricIntentImageStateTag = 0x63696973, // 'ciis' + cmsSigCopyrightTag = 0x63707274, // 'cprt' + cmsSigCrdInfoTag = 0x63726469, // 'crdi' + cmsSigDataTag = 0x64617461, // 'data' + cmsSigDateTimeTag = 0x6474696D, // 'dtim' + cmsSigDeviceMfgDescTag = 0x646D6E64, // 'dmnd' + cmsSigDeviceModelDescTag = 0x646D6464, // 'dmdd' + cmsSigDeviceSettingsTag = 0x64657673, // 'devs' + cmsSigDToB0Tag = 0x44324230, // 'D2B0' + cmsSigDToB1Tag = 0x44324231, // 'D2B1' + cmsSigDToB2Tag = 0x44324232, // 'D2B2' + cmsSigDToB3Tag = 0x44324233, // 'D2B3' + cmsSigBToD0Tag = 0x42324430, // 'B2D0' + cmsSigBToD1Tag = 0x42324431, // 'B2D1' + cmsSigBToD2Tag = 0x42324432, // 'B2D2' + cmsSigBToD3Tag = 0x42324433, // 'B2D3' + cmsSigGamutTag = 0x67616D74, // 'gamt' + cmsSigGrayTRCTag = 0x6b545243, // 'kTRC' + cmsSigGreenColorantTag = 0x6758595A, // 'gXYZ' + cmsSigGreenMatrixColumnTag = 0x6758595A, // 'gXYZ' + cmsSigGreenTRCTag = 0x67545243, // 'gTRC' + cmsSigLuminanceTag = 0x6C756d69, // 'lumi' + cmsSigMeasurementTag = 0x6D656173, // 'meas' + cmsSigMediaBlackPointTag = 0x626B7074, // 'bkpt' + cmsSigMediaWhitePointTag = 0x77747074, // 'wtpt' + cmsSigNamedColorTag = 0x6E636f6C, // 'ncol' // Deprecated by the ICC + cmsSigNamedColor2Tag = 0x6E636C32, // 'ncl2' + cmsSigOutputResponseTag = 0x72657370, // 'resp' + cmsSigPerceptualRenderingIntentGamutTag = 0x72696730, // 'rig0' + cmsSigPreview0Tag = 0x70726530, // 'pre0' + cmsSigPreview1Tag = 0x70726531, // 'pre1' + cmsSigPreview2Tag = 0x70726532, // 'pre2' + cmsSigProfileDescriptionTag = 0x64657363, // 'desc' + cmsSigProfileSequenceDescTag = 0x70736571, // 'pseq' + cmsSigProfileSequenceIdTag = 0x70736964, // 'psid' + cmsSigPs2CRD0Tag = 0x70736430, // 'psd0' + cmsSigPs2CRD1Tag = 0x70736431, // 'psd1' + cmsSigPs2CRD2Tag = 0x70736432, // 'psd2' + cmsSigPs2CRD3Tag = 0x70736433, // 'psd3' + cmsSigPs2CSATag = 0x70733273, // 'ps2s' + cmsSigPs2RenderingIntentTag = 0x70733269, // 'ps2i' + cmsSigRedColorantTag = 0x7258595A, // 'rXYZ' + cmsSigRedMatrixColumnTag = 0x7258595A, // 'rXYZ' + cmsSigRedTRCTag = 0x72545243, // 'rTRC' + cmsSigSaturationRenderingIntentGamutTag = 0x72696732, // 'rig2' + cmsSigScreeningDescTag = 0x73637264, // 'scrd' + cmsSigScreeningTag = 0x7363726E, // 'scrn' + cmsSigTechnologyTag = 0x74656368, // 'tech' + cmsSigUcrBgTag = 0x62666420, // 'bfd ' + cmsSigViewingCondDescTag = 0x76756564, // 'vued' + cmsSigViewingConditionsTag = 0x76696577, // 'view' + cmsSigVcgtTag = 0x76636774 // 'vcgt' + +} cmsTagSignature; + + +// ICC Technology tag +typedef enum { + cmsSigDigitalCamera = 0x6463616D, // 'dcam' + cmsSigFilmScanner = 0x6673636E, // 'fscn' + cmsSigReflectiveScanner = 0x7273636E, // 'rscn' + cmsSigInkJetPrinter = 0x696A6574, // 'ijet' + cmsSigThermalWaxPrinter = 0x74776178, // 'twax' + cmsSigElectrophotographicPrinter = 0x6570686F, // 'epho' + cmsSigElectrostaticPrinter = 0x65737461, // 'esta' + cmsSigDyeSublimationPrinter = 0x64737562, // 'dsub' + cmsSigPhotographicPaperPrinter = 0x7270686F, // 'rpho' + cmsSigFilmWriter = 0x6670726E, // 'fprn' + cmsSigVideoMonitor = 0x7669646D, // 'vidm' + cmsSigVideoCamera = 0x76696463, // 'vidc' + cmsSigProjectionTelevision = 0x706A7476, // 'pjtv' + cmsSigCRTDisplay = 0x43525420, // 'CRT ' + cmsSigPMDisplay = 0x504D4420, // 'PMD ' + cmsSigAMDisplay = 0x414D4420, // 'AMD ' + cmsSigPhotoCD = 0x4B504344, // 'KPCD' + cmsSigPhotoImageSetter = 0x696D6773, // 'imgs' + cmsSigGravure = 0x67726176, // 'grav' + cmsSigOffsetLithography = 0x6F666673, // 'offs' + cmsSigSilkscreen = 0x73696C6B, // 'silk' + cmsSigFlexography = 0x666C6578, // 'flex' + cmsSigMotionPictureFilmScanner = 0x6D706673, // 'mpfs' + cmsSigMotionPictureFilmRecorder = 0x6D706672, // 'mpfr' + cmsSigDigitalMotionPictureCamera = 0x646D7063, // 'dmpc' + cmsSigDigitalCinemaProjector = 0x64636A70, // 'dcpj' + +} cmsTechnologySignature; + + +// ICC Color spaces +typedef enum { + cmsSigXYZData = 0x58595A20, // 'XYZ ' + cmsSigLabData = 0x4C616220, // 'Lab ' + cmsSigLuvData = 0x4C757620, // 'Luv ' + cmsSigYCbCrData = 0x59436272, // 'YCbr' + cmsSigYxyData = 0x59787920, // 'Yxy ' + cmsSigRgbData = 0x52474220, // 'RGB ' + cmsSigGrayData = 0x47524159, // 'GRAY' + cmsSigHsvData = 0x48535620, // 'HSV ' + cmsSigHlsData = 0x484C5320, // 'HLS ' + cmsSigCmykData = 0x434D594B, // 'CMYK' + cmsSigCmyData = 0x434D5920, // 'CMY ' + cmsSigMCH1Data = 0x4D434831, // 'MCH1' + cmsSigMCH2Data = 0x4D434832, // 'MCH2' + cmsSigMCH3Data = 0x4D434833, // 'MCH3' + cmsSigMCH4Data = 0x4D434834, // 'MCH4' + cmsSigMCH5Data = 0x4D434835, // 'MCH5' + cmsSigMCH6Data = 0x4D434836, // 'MCH6' + cmsSigMCH7Data = 0x4D434837, // 'MCH7' + cmsSigMCH8Data = 0x4D434838, // 'MCH8' + cmsSigMCH9Data = 0x4D434839, // 'MCH9' + cmsSigMCHAData = 0x4D43483A, // 'MCHA' + cmsSigMCHBData = 0x4D43483B, // 'MCHB' + cmsSigMCHCData = 0x4D43483C, // 'MCHC' + cmsSigMCHDData = 0x4D43483D, // 'MCHD' + cmsSigMCHEData = 0x4D43483E, // 'MCHE' + cmsSigMCHFData = 0x4D43483F, // 'MCHF' + cmsSigNamedData = 0x6e6d636c, // 'nmcl' + cmsSig1colorData = 0x31434C52, // '1CLR' + cmsSig2colorData = 0x32434C52, // '2CLR' + cmsSig3colorData = 0x33434C52, // '3CLR' + cmsSig4colorData = 0x34434C52, // '4CLR' + cmsSig5colorData = 0x35434C52, // '5CLR' + cmsSig6colorData = 0x36434C52, // '6CLR' + cmsSig7colorData = 0x37434C52, // '7CLR' + cmsSig8colorData = 0x38434C52, // '8CLR' + cmsSig9colorData = 0x39434C52, // '9CLR' + cmsSig10colorData = 0x41434C52, // 'ACLR' + cmsSig11colorData = 0x42434C52, // 'BCLR' + cmsSig12colorData = 0x43434C52, // 'CCLR' + cmsSig13colorData = 0x44434C52, // 'DCLR' + cmsSig14colorData = 0x45434C52, // 'ECLR' + cmsSig15colorData = 0x46434C52, // 'FCLR' + cmsSigLuvKData = 0x4C75764B // 'LuvK' + +} cmsColorSpaceSignature; + +// ICC Profile Class +typedef enum { + cmsSigInputClass = 0x73636E72, // 'scnr' + cmsSigDisplayClass = 0x6D6E7472, // 'mntr' + cmsSigOutputClass = 0x70727472, // 'prtr' + cmsSigLinkClass = 0x6C696E6B, // 'link' + cmsSigAbstractClass = 0x61627374, // 'abst' + cmsSigColorSpaceClass = 0x73706163, // 'spac' + cmsSigNamedColorClass = 0x6e6d636c, // 'nmcl' + +} cmsProfileClassSignature; + +// ICC Platforms +typedef enum { + cmsSigMacintosh = 0x4150504C, // 'APPL' + cmsSigMicrosoft = 0x4D534654, // 'MSFT' + cmsSigSolaris = 0x53554E57, // 'SUNW' + cmsSigSGI = 0x53474920, // 'SGI ' + cmsSigTaligent = 0x54474E54, // 'TGNT' + cmsSigUnices = 0x2A6E6978 // '*nix' // From argyll -- Not official + +} cmsPlatformSignature; + +// Reference gamut +#define cmsSigPerceptualReferenceMediumGamut 0x70726d67 //'prmg' + +// For cmsSigColorimetricIntentImageStateTag +#define cmsSigSceneColorimetryEstimates 0x73636F65 //'scoe' +#define cmsSigSceneAppearanceEstimates 0x73617065 //'sape' +#define cmsSigFocalPlaneColorimetryEstimates 0x66706365 //'fpce' +#define cmsSigReflectionHardcopyOriginalColorimetry 0x72686F63 //'rhoc' +#define cmsSigReflectionPrintOutputColorimetry 0x72706F63 //'rpoc' + +// Multi process elements types +typedef enum { + cmsSigCurveSetElemType = 0x63767374, //'cvst' + cmsSigMatrixElemType = 0x6D617466, //'matf' + cmsSigCLutElemType = 0x636C7574, //'clut' + + cmsSigBAcsElemType = 0x62414353, // 'bACS' + cmsSigEAcsElemType = 0x65414353, // 'eACS' + + // Custom from here, not in the ICC Spec + cmsSigXYZ2LabElemType = 0x6C327820, // 'l2x ' + cmsSigLab2XYZElemType = 0x78326C20, // 'x2l ' + cmsSigNamedColorElemType = 0x6E636C20, // 'ncl ' + cmsSigLabV2toV4 = 0x32203420, // '2 4 ' + cmsSigLabV4toV2 = 0x34203220, // '4 2 ' + + // Identities + cmsSigIdentityElemType = 0x69646E20 // 'idn ' + +} cmsStageSignature; + +// Types of CurveElements +typedef enum { + + cmsSigFormulaCurveSeg = 0x70617266, // 'parf' + cmsSigSampledCurveSeg = 0x73616D66, // 'samf' + cmsSigSegmentedCurve = 0x63757266 // 'curf' + +} cmsCurveSegSignature; + +// Used in ResponseCurveType +#define cmsSigStatusA 0x53746141 //'StaA' +#define cmsSigStatusE 0x53746145 //'StaE' +#define cmsSigStatusI 0x53746149 //'StaI' +#define cmsSigStatusT 0x53746154 //'StaT' +#define cmsSigStatusM 0x5374614D //'StaM' +#define cmsSigDN 0x444E2020 //'DN ' +#define cmsSigDNP 0x444E2050 //'DN P' +#define cmsSigDNN 0x444E4E20 //'DNN ' +#define cmsSigDNNP 0x444E4E50 //'DNNP' + +// Device attributes, currently defined values correspond to the low 4 bytes +// of the 8 byte attribute quantity +#define cmsReflective 0 +#define cmsTransparency 1 +#define cmsGlossy 0 +#define cmsMatte 2 + +// Common structures in ICC tags +typedef struct { + cmsUInt32Number len; + cmsUInt32Number flag; + cmsUInt8Number data[1]; + +} cmsICCData; + +// ICC date time +typedef struct { + cmsUInt16Number year; + cmsUInt16Number month; + cmsUInt16Number day; + cmsUInt16Number hours; + cmsUInt16Number minutes; + cmsUInt16Number seconds; + +} cmsDateTimeNumber; + +// ICC XYZ +typedef struct { + cmsS15Fixed16Number X; + cmsS15Fixed16Number Y; + cmsS15Fixed16Number Z; + +} cmsEncodedXYZNumber; + + +// Profile ID as computed by MD5 algorithm +typedef union { + cmsUInt8Number ID8[16]; + cmsUInt16Number ID16[8]; + cmsUInt32Number ID32[4]; + +} cmsProfileID; + + +// ---------------------------------------------------------------------------------------------- +// ICC profile internal base types. Strictly, shouldn't be declared in this header, but maybe +// somebody want to use this info for accessing profile header directly, so here it is. + +// Profile header -- it is 32-bit aligned, so no issues are expected on alignment +typedef struct { + cmsUInt32Number size; // Profile size in bytes + cmsSignature cmmId; // CMM for this profile + cmsUInt32Number version; // Format version number + cmsProfileClassSignature deviceClass; // Type of profile + cmsColorSpaceSignature colorSpace; // Color space of data + cmsColorSpaceSignature pcs; // PCS, XYZ or Lab only + cmsDateTimeNumber date; // Date profile was created + cmsSignature magic; // Magic Number to identify an ICC profile + cmsPlatformSignature platform; // Primary Platform + cmsUInt32Number flags; // Various bit settings + cmsSignature manufacturer; // Device manufacturer + cmsUInt32Number model; // Device model number + cmsUInt64Number attributes; // Device attributes + cmsUInt32Number renderingIntent;// Rendering intent + cmsEncodedXYZNumber illuminant; // Profile illuminant + cmsSignature creator; // Profile creator + cmsProfileID profileID; // Profile ID using MD5 + cmsInt8Number reserved[28]; // Reserved for future use + +} cmsICCHeader; + +// ICC base tag +typedef struct { + cmsTagTypeSignature sig; + cmsInt8Number reserved[4]; + +} cmsTagBase; + +// A tag entry in directory +typedef struct { + cmsTagSignature sig; // The tag signature + cmsUInt32Number offset; // Start of tag + cmsUInt32Number size; // Size in bytes + +} cmsTagEntry; + +// ---------------------------------------------------------------------------------------------- + +// Little CMS specific typedefs + +typedef void* cmsContext; // Context identifier for multithreaded environments +typedef void* cmsHANDLE ; // Generic handle +typedef void* cmsHPROFILE; // Opaque typedefs to hide internals +typedef void* cmsHTRANSFORM; + +#define cmsMAXCHANNELS 16 // Maximum number of channels in ICC profiles + +// Format of pixel is defined by one cmsUInt32Number, using bit fields as follows +// +// A O TTTTT U Y F P X S EEE CCCC BBB +// +// A: Floating point -- With this flag we can differentiate 16 bits as float and as int +// O: Optimized -- previous optimization already returns the final 8-bit value +// T: Pixeltype +// F: Flavor 0=MinIsBlack(Chocolate) 1=MinIsWhite(Vanilla) +// P: Planar? 0=Chunky, 1=Planar +// X: swap 16 bps endianess? +// S: Do swap? ie, BGR, KYMC +// E: Extra samples +// C: Channels (Samples per pixel) +// B: bytes per sample +// Y: Swap first - changes ABGR to BGRA and KCMY to CMYK + +#define FLOAT_SH(a) ((a) << 22) +#define OPTIMIZED_SH(s) ((s) << 21) +#define COLORSPACE_SH(s) ((s) << 16) +#define SWAPFIRST_SH(s) ((s) << 14) +#define FLAVOR_SH(s) ((s) << 13) +#define PLANAR_SH(p) ((p) << 12) +#define ENDIAN16_SH(e) ((e) << 11) +#define DOSWAP_SH(e) ((e) << 10) +#define EXTRA_SH(e) ((e) << 7) +#define CHANNELS_SH(c) ((c) << 3) +#define BYTES_SH(b) (b) + +// These macros unpack format specifiers into integers +#define T_FLOAT(a) (((a)>>22)&1) +#define T_OPTIMIZED(o) (((o)>>21)&1) +#define T_COLORSPACE(s) (((s)>>16)&31) +#define T_SWAPFIRST(s) (((s)>>14)&1) +#define T_FLAVOR(s) (((s)>>13)&1) +#define T_PLANAR(p) (((p)>>12)&1) +#define T_ENDIAN16(e) (((e)>>11)&1) +#define T_DOSWAP(e) (((e)>>10)&1) +#define T_EXTRA(e) (((e)>>7)&7) +#define T_CHANNELS(c) (((c)>>3)&15) +#define T_BYTES(b) ((b)&7) + + +// Pixel types +#define PT_ANY 0 // Don't check colorspace + // 1 & 2 are reserved +#define PT_GRAY 3 +#define PT_RGB 4 +#define PT_CMY 5 +#define PT_CMYK 6 +#define PT_YCbCr 7 +#define PT_YUV 8 // Lu'v' +#define PT_XYZ 9 +#define PT_Lab 10 +#define PT_YUVK 11 // Lu'v'K +#define PT_HSV 12 +#define PT_HLS 13 +#define PT_Yxy 14 + +#define PT_MCH1 15 +#define PT_MCH2 16 +#define PT_MCH3 17 +#define PT_MCH4 18 +#define PT_MCH5 19 +#define PT_MCH6 20 +#define PT_MCH7 21 +#define PT_MCH8 22 +#define PT_MCH9 23 +#define PT_MCH10 24 +#define PT_MCH11 25 +#define PT_MCH12 26 +#define PT_MCH13 27 +#define PT_MCH14 28 +#define PT_MCH15 29 + +#define PT_LabV2 30 // Identical to PT_Lab, but using the V2 old encoding + +// Some (not all!) representations + +#ifndef TYPE_RGB_8 // TYPE_RGB_8 is a very common identifier, so don't include ours + // if user has it already defined. + +#define TYPE_GRAY_8 (COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(1)) +#define TYPE_GRAY_8_REV (COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(1)|FLAVOR_SH(1)) +#define TYPE_GRAY_16 (COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(2)) +#define TYPE_GRAY_16_REV (COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(2)|FLAVOR_SH(1)) +#define TYPE_GRAY_16_SE (COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(2)|ENDIAN16_SH(1)) +#define TYPE_GRAYA_8 (COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(1)) +#define TYPE_GRAYA_16 (COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(2)) +#define TYPE_GRAYA_16_SE (COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(2)|ENDIAN16_SH(1)) +#define TYPE_GRAYA_8_PLANAR (COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(1)|PLANAR_SH(1)) +#define TYPE_GRAYA_16_PLANAR (COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(2)|PLANAR_SH(1)) + +#define TYPE_RGB_8 (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(1)) +#define TYPE_RGB_8_PLANAR (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(1)|PLANAR_SH(1)) +#define TYPE_BGR_8 (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)) +#define TYPE_BGR_8_PLANAR (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|PLANAR_SH(1)) +#define TYPE_RGB_16 (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(2)) +#define TYPE_RGB_16_PLANAR (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(2)|PLANAR_SH(1)) +#define TYPE_RGB_16_SE (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1)) +#define TYPE_BGR_16 (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)) +#define TYPE_BGR_16_PLANAR (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|PLANAR_SH(1)) +#define TYPE_BGR_16_SE (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1)) + +#define TYPE_RGBA_8 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)) +#define TYPE_RGBA_8_PLANAR (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|PLANAR_SH(1)) +#define TYPE_RGBA_16 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)) +#define TYPE_RGBA_16_PLANAR (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|PLANAR_SH(1)) +#define TYPE_RGBA_16_SE (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1)) + +#define TYPE_ARGB_8 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|SWAPFIRST_SH(1)) +#define TYPE_ARGB_16 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|SWAPFIRST_SH(1)) + +#define TYPE_ABGR_8 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)) +#define TYPE_ABGR_16 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)) +#define TYPE_ABGR_16_PLANAR (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|PLANAR_SH(1)) +#define TYPE_ABGR_16_SE (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1)) + +#define TYPE_BGRA_8 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1)) +#define TYPE_BGRA_16 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|SWAPFIRST_SH(1)) +#define TYPE_BGRA_16_SE (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1)|SWAPFIRST_SH(1)) + +#define TYPE_CMY_8 (COLORSPACE_SH(PT_CMY)|CHANNELS_SH(3)|BYTES_SH(1)) +#define TYPE_CMY_8_PLANAR (COLORSPACE_SH(PT_CMY)|CHANNELS_SH(3)|BYTES_SH(1)|PLANAR_SH(1)) +#define TYPE_CMY_16 (COLORSPACE_SH(PT_CMY)|CHANNELS_SH(3)|BYTES_SH(2)) +#define TYPE_CMY_16_PLANAR (COLORSPACE_SH(PT_CMY)|CHANNELS_SH(3)|BYTES_SH(2)|PLANAR_SH(1)) +#define TYPE_CMY_16_SE (COLORSPACE_SH(PT_CMY)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1)) + +#define TYPE_CMYK_8 (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(1)) +#define TYPE_CMYKA_8 (COLORSPACE_SH(PT_CMYK)|EXTRA_SH(1)|CHANNELS_SH(4)|BYTES_SH(1)) +#define TYPE_CMYK_8_REV (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(1)|FLAVOR_SH(1)) +#define TYPE_YUVK_8 TYPE_CMYK_8_REV +#define TYPE_CMYK_8_PLANAR (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(1)|PLANAR_SH(1)) +#define TYPE_CMYK_16 (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2)) +#define TYPE_CMYK_16_REV (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2)|FLAVOR_SH(1)) +#define TYPE_YUVK_16 TYPE_CMYK_16_REV +#define TYPE_CMYK_16_PLANAR (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2)|PLANAR_SH(1)) +#define TYPE_CMYK_16_SE (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2)|ENDIAN16_SH(1)) + +#define TYPE_KYMC_8 (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1)) +#define TYPE_KYMC_16 (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2)|DOSWAP_SH(1)) +#define TYPE_KYMC_16_SE (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1)) + +#define TYPE_KCMY_8 (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(1)|SWAPFIRST_SH(1)) +#define TYPE_KCMY_8_REV (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(1)|FLAVOR_SH(1)|SWAPFIRST_SH(1)) +#define TYPE_KCMY_16 (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2)|SWAPFIRST_SH(1)) +#define TYPE_KCMY_16_REV (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2)|FLAVOR_SH(1)|SWAPFIRST_SH(1)) +#define TYPE_KCMY_16_SE (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2)|ENDIAN16_SH(1)|SWAPFIRST_SH(1)) + +#define TYPE_CMYK5_8 (COLORSPACE_SH(PT_MCH5)|CHANNELS_SH(5)|BYTES_SH(1)) +#define TYPE_CMYK5_16 (COLORSPACE_SH(PT_MCH5)|CHANNELS_SH(5)|BYTES_SH(2)) +#define TYPE_CMYK5_16_SE (COLORSPACE_SH(PT_MCH5)|CHANNELS_SH(5)|BYTES_SH(2)|ENDIAN16_SH(1)) +#define TYPE_KYMC5_8 (COLORSPACE_SH(PT_MCH5)|CHANNELS_SH(5)|BYTES_SH(1)|DOSWAP_SH(1)) +#define TYPE_KYMC5_16 (COLORSPACE_SH(PT_MCH5)|CHANNELS_SH(5)|BYTES_SH(2)|DOSWAP_SH(1)) +#define TYPE_KYMC5_16_SE (COLORSPACE_SH(PT_MCH5)|CHANNELS_SH(5)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1)) +#define TYPE_CMYK6_8 (COLORSPACE_SH(PT_MCH6)|CHANNELS_SH(6)|BYTES_SH(1)) +#define TYPE_CMYK6_8_PLANAR (COLORSPACE_SH(PT_MCH6)|CHANNELS_SH(6)|BYTES_SH(1)|PLANAR_SH(1)) +#define TYPE_CMYK6_16 (COLORSPACE_SH(PT_MCH6)|CHANNELS_SH(6)|BYTES_SH(2)) +#define TYPE_CMYK6_16_PLANAR (COLORSPACE_SH(PT_MCH6)|CHANNELS_SH(6)|BYTES_SH(2)|PLANAR_SH(1)) +#define TYPE_CMYK6_16_SE (COLORSPACE_SH(PT_MCH6)|CHANNELS_SH(6)|BYTES_SH(2)|ENDIAN16_SH(1)) +#define TYPE_CMYK7_8 (COLORSPACE_SH(PT_MCH7)|CHANNELS_SH(7)|BYTES_SH(1)) +#define TYPE_CMYK7_16 (COLORSPACE_SH(PT_MCH7)|CHANNELS_SH(7)|BYTES_SH(2)) +#define TYPE_CMYK7_16_SE (COLORSPACE_SH(PT_MCH7)|CHANNELS_SH(7)|BYTES_SH(2)|ENDIAN16_SH(1)) +#define TYPE_KYMC7_8 (COLORSPACE_SH(PT_MCH7)|CHANNELS_SH(7)|BYTES_SH(1)|DOSWAP_SH(1)) +#define TYPE_KYMC7_16 (COLORSPACE_SH(PT_MCH7)|CHANNELS_SH(7)|BYTES_SH(2)|DOSWAP_SH(1)) +#define TYPE_KYMC7_16_SE (COLORSPACE_SH(PT_MCH7)|CHANNELS_SH(7)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1)) +#define TYPE_CMYK8_8 (COLORSPACE_SH(PT_MCH8)|CHANNELS_SH(8)|BYTES_SH(1)) +#define TYPE_CMYK8_16 (COLORSPACE_SH(PT_MCH8)|CHANNELS_SH(8)|BYTES_SH(2)) +#define TYPE_CMYK8_16_SE (COLORSPACE_SH(PT_MCH8)|CHANNELS_SH(8)|BYTES_SH(2)|ENDIAN16_SH(1)) +#define TYPE_KYMC8_8 (COLORSPACE_SH(PT_MCH8)|CHANNELS_SH(8)|BYTES_SH(1)|DOSWAP_SH(1)) +#define TYPE_KYMC8_16 (COLORSPACE_SH(PT_MCH8)|CHANNELS_SH(8)|BYTES_SH(2)|DOSWAP_SH(1)) +#define TYPE_KYMC8_16_SE (COLORSPACE_SH(PT_MCH8)|CHANNELS_SH(8)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1)) +#define TYPE_CMYK9_8 (COLORSPACE_SH(PT_MCH9)|CHANNELS_SH(9)|BYTES_SH(1)) +#define TYPE_CMYK9_16 (COLORSPACE_SH(PT_MCH9)|CHANNELS_SH(9)|BYTES_SH(2)) +#define TYPE_CMYK9_16_SE (COLORSPACE_SH(PT_MCH9)|CHANNELS_SH(9)|BYTES_SH(2)|ENDIAN16_SH(1)) +#define TYPE_KYMC9_8 (COLORSPACE_SH(PT_MCH9)|CHANNELS_SH(9)|BYTES_SH(1)|DOSWAP_SH(1)) +#define TYPE_KYMC9_16 (COLORSPACE_SH(PT_MCH9)|CHANNELS_SH(9)|BYTES_SH(2)|DOSWAP_SH(1)) +#define TYPE_KYMC9_16_SE (COLORSPACE_SH(PT_MCH9)|CHANNELS_SH(9)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1)) +#define TYPE_CMYK10_8 (COLORSPACE_SH(PT_MCH10)|CHANNELS_SH(10)|BYTES_SH(1)) +#define TYPE_CMYK10_16 (COLORSPACE_SH(PT_MCH10)|CHANNELS_SH(10)|BYTES_SH(2)) +#define TYPE_CMYK10_16_SE (COLORSPACE_SH(PT_MCH10)|CHANNELS_SH(10)|BYTES_SH(2)|ENDIAN16_SH(1)) +#define TYPE_KYMC10_8 (COLORSPACE_SH(PT_MCH10)|CHANNELS_SH(10)|BYTES_SH(1)|DOSWAP_SH(1)) +#define TYPE_KYMC10_16 (COLORSPACE_SH(PT_MCH10)|CHANNELS_SH(10)|BYTES_SH(2)|DOSWAP_SH(1)) +#define TYPE_KYMC10_16_SE (COLORSPACE_SH(PT_MCH10)|CHANNELS_SH(10)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1)) +#define TYPE_CMYK11_8 (COLORSPACE_SH(PT_MCH11)|CHANNELS_SH(11)|BYTES_SH(1)) +#define TYPE_CMYK11_16 (COLORSPACE_SH(PT_MCH11)|CHANNELS_SH(11)|BYTES_SH(2)) +#define TYPE_CMYK11_16_SE (COLORSPACE_SH(PT_MCH11)|CHANNELS_SH(11)|BYTES_SH(2)|ENDIAN16_SH(1)) +#define TYPE_KYMC11_8 (COLORSPACE_SH(PT_MCH11)|CHANNELS_SH(11)|BYTES_SH(1)|DOSWAP_SH(1)) +#define TYPE_KYMC11_16 (COLORSPACE_SH(PT_MCH11)|CHANNELS_SH(11)|BYTES_SH(2)|DOSWAP_SH(1)) +#define TYPE_KYMC11_16_SE (COLORSPACE_SH(PT_MCH11)|CHANNELS_SH(11)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1)) +#define TYPE_CMYK12_8 (COLORSPACE_SH(PT_MCH12)|CHANNELS_SH(12)|BYTES_SH(1)) +#define TYPE_CMYK12_16 (COLORSPACE_SH(PT_MCH12)|CHANNELS_SH(12)|BYTES_SH(2)) +#define TYPE_CMYK12_16_SE (COLORSPACE_SH(PT_MCH12)|CHANNELS_SH(12)|BYTES_SH(2)|ENDIAN16_SH(1)) +#define TYPE_KYMC12_8 (COLORSPACE_SH(PT_MCH12)|CHANNELS_SH(12)|BYTES_SH(1)|DOSWAP_SH(1)) +#define TYPE_KYMC12_16 (COLORSPACE_SH(PT_MCH12)|CHANNELS_SH(12)|BYTES_SH(2)|DOSWAP_SH(1)) +#define TYPE_KYMC12_16_SE (COLORSPACE_SH(PT_MCH12)|CHANNELS_SH(12)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1)) + +// Colorimetric +#define TYPE_XYZ_16 (COLORSPACE_SH(PT_XYZ)|CHANNELS_SH(3)|BYTES_SH(2)) +#define TYPE_Lab_8 (COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(1)) +#define TYPE_LabV2_8 (COLORSPACE_SH(PT_LabV2)|CHANNELS_SH(3)|BYTES_SH(1)) + +#define TYPE_ALab_8 (COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|DOSWAP_SH(1)) +#define TYPE_ALabV2_8 (COLORSPACE_SH(PT_LabV2)|CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|DOSWAP_SH(1)) +#define TYPE_Lab_16 (COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(2)) +#define TYPE_LabV2_16 (COLORSPACE_SH(PT_LabV2)|CHANNELS_SH(3)|BYTES_SH(2)) +#define TYPE_Yxy_16 (COLORSPACE_SH(PT_Yxy)|CHANNELS_SH(3)|BYTES_SH(2)) + +// YCbCr +#define TYPE_YCbCr_8 (COLORSPACE_SH(PT_YCbCr)|CHANNELS_SH(3)|BYTES_SH(1)) +#define TYPE_YCbCr_8_PLANAR (COLORSPACE_SH(PT_YCbCr)|CHANNELS_SH(3)|BYTES_SH(1)|PLANAR_SH(1)) +#define TYPE_YCbCr_16 (COLORSPACE_SH(PT_YCbCr)|CHANNELS_SH(3)|BYTES_SH(2)) +#define TYPE_YCbCr_16_PLANAR (COLORSPACE_SH(PT_YCbCr)|CHANNELS_SH(3)|BYTES_SH(2)|PLANAR_SH(1)) +#define TYPE_YCbCr_16_SE (COLORSPACE_SH(PT_YCbCr)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1)) + +// YUV +#define TYPE_YUV_8 (COLORSPACE_SH(PT_YUV)|CHANNELS_SH(3)|BYTES_SH(1)) +#define TYPE_YUV_8_PLANAR (COLORSPACE_SH(PT_YUV)|CHANNELS_SH(3)|BYTES_SH(1)|PLANAR_SH(1)) +#define TYPE_YUV_16 (COLORSPACE_SH(PT_YUV)|CHANNELS_SH(3)|BYTES_SH(2)) +#define TYPE_YUV_16_PLANAR (COLORSPACE_SH(PT_YUV)|CHANNELS_SH(3)|BYTES_SH(2)|PLANAR_SH(1)) +#define TYPE_YUV_16_SE (COLORSPACE_SH(PT_YUV)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1)) + +// HLS +#define TYPE_HLS_8 (COLORSPACE_SH(PT_HLS)|CHANNELS_SH(3)|BYTES_SH(1)) +#define TYPE_HLS_8_PLANAR (COLORSPACE_SH(PT_HLS)|CHANNELS_SH(3)|BYTES_SH(1)|PLANAR_SH(1)) +#define TYPE_HLS_16 (COLORSPACE_SH(PT_HLS)|CHANNELS_SH(3)|BYTES_SH(2)) +#define TYPE_HLS_16_PLANAR (COLORSPACE_SH(PT_HLS)|CHANNELS_SH(3)|BYTES_SH(2)|PLANAR_SH(1)) +#define TYPE_HLS_16_SE (COLORSPACE_SH(PT_HLS)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1)) + +// HSV +#define TYPE_HSV_8 (COLORSPACE_SH(PT_HSV)|CHANNELS_SH(3)|BYTES_SH(1)) +#define TYPE_HSV_8_PLANAR (COLORSPACE_SH(PT_HSV)|CHANNELS_SH(3)|BYTES_SH(1)|PLANAR_SH(1)) +#define TYPE_HSV_16 (COLORSPACE_SH(PT_HSV)|CHANNELS_SH(3)|BYTES_SH(2)) +#define TYPE_HSV_16_PLANAR (COLORSPACE_SH(PT_HSV)|CHANNELS_SH(3)|BYTES_SH(2)|PLANAR_SH(1)) +#define TYPE_HSV_16_SE (COLORSPACE_SH(PT_HSV)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1)) + +// Named color index. Only 16 bits allowed (don't check colorspace) +#define TYPE_NAMED_COLOR_INDEX (CHANNELS_SH(1)|BYTES_SH(2)) + +// Float formatters. +#define TYPE_XYZ_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_XYZ)|CHANNELS_SH(3)|BYTES_SH(4)) +#define TYPE_Lab_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(4)) +#define TYPE_GRAY_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(4)) +#define TYPE_RGB_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(4)) +#define TYPE_CMYK_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(4)) + +// Floating point formatters. +// NOTE THAT 'BYTES' FIELD IS SET TO ZERO ON DLB because 8 bytes overflows the bitfield +#define TYPE_XYZ_DBL (FLOAT_SH(1)|COLORSPACE_SH(PT_XYZ)|CHANNELS_SH(3)|BYTES_SH(0)) +#define TYPE_Lab_DBL (FLOAT_SH(1)|COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(0)) +#define TYPE_GRAY_DBL (FLOAT_SH(1)|COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(0)) +#define TYPE_RGB_DBL (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(0)) +#define TYPE_CMYK_DBL (FLOAT_SH(1)|COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(0)) + +#endif + +// Colorspaces +typedef struct { + cmsFloat64Number X; + cmsFloat64Number Y; + cmsFloat64Number Z; + + } cmsCIEXYZ; + +typedef struct { + cmsFloat64Number x; + cmsFloat64Number y; + cmsFloat64Number Y; + + } cmsCIExyY; + +typedef struct { + cmsFloat64Number L; + cmsFloat64Number a; + cmsFloat64Number b; + + } cmsCIELab; + +typedef struct { + cmsFloat64Number L; + cmsFloat64Number C; + cmsFloat64Number h; + + } cmsCIELCh; + +typedef struct { + cmsFloat64Number J; + cmsFloat64Number C; + cmsFloat64Number h; + + } cmsJCh; + +typedef struct { + cmsCIEXYZ Red; + cmsCIEXYZ Green; + cmsCIEXYZ Blue; + + } cmsCIEXYZTRIPLE; + +typedef struct { + cmsCIExyY Red; + cmsCIExyY Green; + cmsCIExyY Blue; + + } cmsCIExyYTRIPLE; + +// Illuminant types for structs below +#define cmsILLUMINANT_TYPE_UNKNOWN 0x0000000 +#define cmsILLUMINANT_TYPE_D50 0x0000001 +#define cmsILLUMINANT_TYPE_D65 0x0000002 +#define cmsILLUMINANT_TYPE_D93 0x0000003 +#define cmsILLUMINANT_TYPE_F2 0x0000004 +#define cmsILLUMINANT_TYPE_D55 0x0000005 +#define cmsILLUMINANT_TYPE_A 0x0000006 +#define cmsILLUMINANT_TYPE_E 0x0000007 +#define cmsILLUMINANT_TYPE_F8 0x0000008 + +typedef struct { + cmsUInt32Number Observer; // 0 = unknown, 1=CIE 1931, 2=CIE 1964 + cmsCIEXYZ Backing; // Value of backing + cmsUInt32Number Geometry; // 0=unknown, 1=45/0, 0/45 2=0d, d/0 + cmsFloat64Number Flare; // 0..1.0 + cmsUInt32Number IlluminantType; + + } cmsICCMeasurementConditions; + +typedef struct { + cmsCIEXYZ IlluminantXYZ; // Not the same struct as CAM02, + cmsCIEXYZ SurroundXYZ; // This is for storing the tag + cmsUInt32Number IlluminantType; // viewing condition + + } cmsICCViewingConditions; + +// Support of non-standard functions -------------------------------------------------------------------------------------- + +CMSAPI int CMSEXPORT cmsstrcasecmp(const char* s1, const char* s2); +CMSAPI long int CMSEXPORT cmsfilelength(FILE* f); + +// Plug-In registering --------------------------------------------------------------------------------------------------- + +CMSAPI cmsBool CMSEXPORT cmsPlugin(void* Plugin); +CMSAPI void CMSEXPORT cmsUnregisterPlugins(void); + +// Error logging ---------------------------------------------------------------------------------------------------------- + +// There is no error handling at all. When a function fails, it returns proper value. +// For example, all create functions does return NULL on failure. Other may return FALSE. +// It may be interesting, for the developer, to know why the function is failing. +// for that reason, lcms2 does offer a logging function. This function will get +// an ENGLISH string with some clues on what is going wrong. You can show this +// info to the end user if you wish, or just create some sort of log on disk. +// The logging function should NOT terminate the program, as this obviously can leave +// unfreed resources. It is the programmer's responsibility to check each function +// return code to make sure it didn't fail. + +#define cmsERROR_UNDEFINED 0 +#define cmsERROR_FILE 1 +#define cmsERROR_RANGE 2 +#define cmsERROR_INTERNAL 3 +#define cmsERROR_NULL 4 +#define cmsERROR_READ 5 +#define cmsERROR_SEEK 6 +#define cmsERROR_WRITE 7 +#define cmsERROR_UNKNOWN_EXTENSION 8 +#define cmsERROR_COLORSPACE_CHECK 9 +#define cmsERROR_ALREADY_DEFINED 10 +#define cmsERROR_BAD_SIGNATURE 11 +#define cmsERROR_CORRUPTION_DETECTED 12 +#define cmsERROR_NOT_SUITABLE 13 + +// Error logger is called with the ContextID when a message is raised. This gives the +// chance to know which thread is responsible of the warning and any environment associated +// with it. Non-multithreading applications may safely ignore this parameter. +// Note that under certain special circumstances, ContextID may be NULL. +typedef void (* cmsLogErrorHandlerFunction)(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *Text); + +// Allows user to set any specific logger +CMSAPI void CMSEXPORT cmsSetLogErrorHandler(cmsLogErrorHandlerFunction Fn); + +// Conversions -------------------------------------------------------------------------------------------------------------- + +// Returns pointers to constant structs +CMSAPI const cmsCIEXYZ* CMSEXPORT cmsD50_XYZ(void); +CMSAPI const cmsCIExyY* CMSEXPORT cmsD50_xyY(void); + +// Colorimetric space conversions +CMSAPI void CMSEXPORT cmsXYZ2xyY(cmsCIExyY* Dest, const cmsCIEXYZ* Source); +CMSAPI void CMSEXPORT cmsxyY2XYZ(cmsCIEXYZ* Dest, const cmsCIExyY* Source); +CMSAPI void CMSEXPORT cmsXYZ2Lab(const cmsCIEXYZ* WhitePoint, cmsCIELab* Lab, const cmsCIEXYZ* xyz); +CMSAPI void CMSEXPORT cmsLab2XYZ(const cmsCIEXYZ* WhitePoint, cmsCIEXYZ* xyz, const cmsCIELab* Lab); +CMSAPI void CMSEXPORT cmsLab2LCh(cmsCIELCh*LCh, const cmsCIELab* Lab); +CMSAPI void CMSEXPORT cmsLCh2Lab(cmsCIELab* Lab, const cmsCIELCh* LCh); + +// Encoding /Decoding on PCS +CMSAPI void CMSEXPORT cmsLabEncoded2Float(cmsCIELab* Lab, const cmsUInt16Number wLab[3]); +CMSAPI void CMSEXPORT cmsLabEncoded2FloatV2(cmsCIELab* Lab, const cmsUInt16Number wLab[3]); +CMSAPI void CMSEXPORT cmsFloat2LabEncoded(cmsUInt16Number wLab[3], const cmsCIELab* Lab); +CMSAPI void CMSEXPORT cmsFloat2LabEncodedV2(cmsUInt16Number wLab[3], const cmsCIELab* Lab); +CMSAPI void CMSEXPORT cmsXYZEncoded2Float(cmsCIEXYZ* fxyz, const cmsUInt16Number XYZ[3]); +CMSAPI void CMSEXPORT cmsFloat2XYZEncoded(cmsUInt16Number XYZ[3], const cmsCIEXYZ* fXYZ); + +// DeltaE metrics +CMSAPI cmsFloat64Number CMSEXPORT cmsDeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2); +CMSAPI cmsFloat64Number CMSEXPORT cmsCIE94DeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2); +CMSAPI cmsFloat64Number CMSEXPORT cmsBFDdeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2); +CMSAPI cmsFloat64Number CMSEXPORT cmsCMCdeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2, cmsFloat64Number l, cmsFloat64Number c); +CMSAPI cmsFloat64Number CMSEXPORT cmsCIE2000DeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2, cmsFloat64Number Kl, cmsFloat64Number Kc, cmsFloat64Number Kh); + +// Temperature <-> Chromaticity (Black body) +CMSAPI cmsBool CMSEXPORT cmsWhitePointFromTemp(cmsCIExyY* WhitePoint, cmsFloat64Number TempK); +CMSAPI cmsBool CMSEXPORT cmsTempFromWhitePoint(cmsFloat64Number* TempK, const cmsCIExyY* WhitePoint); + +// Chromatic adaptation +CMSAPI cmsBool CMSEXPORT cmsAdaptToIlluminant(cmsCIEXYZ* Result, const cmsCIEXYZ* SourceWhitePt, + const cmsCIEXYZ* Illuminant, + const cmsCIEXYZ* Value); + +// CIECAM02 --------------------------------------------------------------------------------------------------- + +// Viewing conditions. Please note those are CAM model viewing conditions, and not the ICC tag viewing +// conditions, which I'm naming cmsICCViewingConditions to make differences evident. Unfortunately, the tag +// cannot deal with surround La, Yb and D value so is basically useless to store CAM02 viewing conditions. + + +#define AVG_SURROUND 1 +#define DIM_SURROUND 2 +#define DARK_SURROUND 3 +#define CUTSHEET_SURROUND 4 + +#define D_CALCULATE (-1) + +typedef struct { + cmsCIEXYZ whitePoint; + cmsFloat64Number Yb; + cmsFloat64Number La; + int surround; + cmsFloat64Number D_value; + + } cmsViewingConditions; + +CMSAPI cmsHANDLE CMSEXPORT cmsCIECAM02Init(cmsContext ContextID, const cmsViewingConditions* pVC); +CMSAPI void CMSEXPORT cmsCIECAM02Done(cmsHANDLE hModel); +CMSAPI void CMSEXPORT cmsCIECAM02Forward(cmsHANDLE hModel, const cmsCIEXYZ* pIn, cmsJCh* pOut); +CMSAPI void CMSEXPORT cmsCIECAM02Reverse(cmsHANDLE hModel, const cmsJCh* pIn, cmsCIEXYZ* pOut); + + +// Tone curves ----------------------------------------------------------------------------------------- + +// This describes a curve segment. For a table of supported types, see the manual. User can increase the number of +// available types by using a proper plug-in. Parametric segments allow 10 parameters at most + +typedef struct { + cmsFloat32Number x0, x1; // Domain; for x0 < x <= x1 + cmsInt32Number Type; // Parametric type, Type == 0 means sampled segment. Negative values are reserved + cmsFloat64Number Params[10]; // Parameters if Type != 0 + cmsUInt32Number nGridPoints; // Number of grid points if Type == 0 + cmsFloat32Number* SampledPoints; // Points to an array of floats if Type == 0 + +} cmsCurveSegment; + +// The internal representation is none of your business. +typedef struct _cms_curve_struct cmsToneCurve; + +CMSAPI cmsToneCurve* CMSEXPORT cmsBuildSegmentedToneCurve(cmsContext ContextID, cmsInt32Number nSegments, const cmsCurveSegment Segments[]); +CMSAPI cmsToneCurve* CMSEXPORT cmsBuildParametricToneCurve(cmsContext ContextID, cmsInt32Number Type, const cmsFloat64Number Params[]); +CMSAPI cmsToneCurve* CMSEXPORT cmsBuildGamma(cmsContext ContextID, cmsFloat64Number Gamma); +CMSAPI cmsToneCurve* CMSEXPORT cmsBuildTabulatedToneCurve16(cmsContext ContextID, cmsInt32Number nEntries, const cmsUInt16Number values[]); +CMSAPI cmsToneCurve* CMSEXPORT cmsBuildTabulatedToneCurveFloat(cmsContext ContextID, cmsUInt32Number nEntries, const cmsFloat32Number values[]); +CMSAPI void CMSEXPORT cmsFreeToneCurve(cmsToneCurve* Curve); +CMSAPI void CMSEXPORT cmsFreeToneCurveTriple(cmsToneCurve* Curve[3]); +CMSAPI cmsToneCurve* CMSEXPORT cmsDupToneCurve(const cmsToneCurve* Src); +CMSAPI cmsToneCurve* CMSEXPORT cmsReverseToneCurve(const cmsToneCurve* InGamma); +CMSAPI cmsToneCurve* CMSEXPORT cmsReverseToneCurveEx(cmsInt32Number nResultSamples, const cmsToneCurve* InGamma); +CMSAPI cmsToneCurve* CMSEXPORT cmsJoinToneCurve(cmsContext ContextID, const cmsToneCurve* X, const cmsToneCurve* Y, cmsUInt32Number nPoints); +CMSAPI cmsBool CMSEXPORT cmsSmoothToneCurve(cmsToneCurve* Tab, cmsFloat64Number lambda); +CMSAPI cmsFloat32Number CMSEXPORT cmsEvalToneCurveFloat(const cmsToneCurve* Curve, cmsFloat32Number v); +CMSAPI cmsUInt16Number CMSEXPORT cmsEvalToneCurve16(const cmsToneCurve* Curve, cmsUInt16Number v); +CMSAPI cmsBool CMSEXPORT cmsIsToneCurveMultisegment(const cmsToneCurve* InGamma); +CMSAPI cmsBool CMSEXPORT cmsIsToneCurveLinear(const cmsToneCurve* Curve); +CMSAPI cmsBool CMSEXPORT cmsIsToneCurveMonotonic(const cmsToneCurve* t); +CMSAPI cmsBool CMSEXPORT cmsIsToneCurveDescending(const cmsToneCurve* t); +CMSAPI cmsInt32Number CMSEXPORT cmsGetToneCurveParametricType(const cmsToneCurve* t); +CMSAPI cmsFloat64Number CMSEXPORT cmsEstimateGamma(const cmsToneCurve* t, cmsFloat64Number Precision); + + +// Implements pipelines of multi-processing elements ------------------------------------------------------------- + +// Nothing to see here, move along +typedef struct _cmsPipeline_struct cmsPipeline; +typedef struct _cmsStage_struct cmsStage; + +// Those are hi-level pipelines +CMSAPI cmsPipeline* CMSEXPORT cmsPipelineAlloc(cmsContext ContextID, cmsUInt32Number InputChannels, cmsUInt32Number OutputChannels); +CMSAPI void CMSEXPORT cmsPipelineFree(cmsPipeline* lut); +CMSAPI cmsPipeline* CMSEXPORT cmsPipelineDup(const cmsPipeline* Orig); + +CMSAPI cmsUInt32Number CMSEXPORT cmsPipelineInputChannels(const cmsPipeline* lut); +CMSAPI cmsUInt32Number CMSEXPORT cmsPipelineOutputChannels(const cmsPipeline* lut); + +CMSAPI cmsUInt32Number CMSEXPORT cmsPipelineStageCount(const cmsPipeline* lut); +CMSAPI cmsStage* CMSEXPORT cmsPipelineGetPtrToFirstStage(const cmsPipeline* lut); +CMSAPI cmsStage* CMSEXPORT cmsPipelineGetPtrToLastStage(const cmsPipeline* lut); + +CMSAPI void CMSEXPORT cmsPipelineEval16(const cmsUInt16Number In[], cmsUInt16Number Out[], const cmsPipeline* lut); +CMSAPI void CMSEXPORT cmsPipelineEvalFloat(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsPipeline* lut); +CMSAPI cmsBool CMSEXPORT cmsPipelineEvalReverseFloat(cmsFloat32Number Target[], cmsFloat32Number Result[], cmsFloat32Number Hint[], const cmsPipeline* lut); +CMSAPI cmsBool CMSEXPORT cmsPipelineCat(cmsPipeline* l1, const cmsPipeline* l2); +CMSAPI cmsBool CMSEXPORT cmsPipelineSetSaveAs8bitsFlag(cmsPipeline* lut, cmsBool On); + +// Where to place/locate the stages in the pipeline chain +typedef enum { cmsAT_BEGIN, cmsAT_END } cmsStageLoc; + +CMSAPI void CMSEXPORT cmsPipelineInsertStage(cmsPipeline* lut, cmsStageLoc loc, cmsStage* mpe); +CMSAPI void CMSEXPORT cmsPipelineUnlinkStage(cmsPipeline* lut, cmsStageLoc loc, cmsStage** mpe); + +// This function is quite useful to analyze the structure of a Pipeline and retrieve the Stage elements +// that conform the Pipeline. It should be called with the Pipeline, the number of expected elements and +// then a list of expected types followed with a list of double pointers to Stage elements. If +// the function founds a match with current pipeline, it fills the pointers and returns TRUE +// if not, returns FALSE without touching anything. +CMSAPI cmsBool CMSEXPORT cmsPipelineCheckAndRetreiveStages(const cmsPipeline* Lut, cmsUInt32Number n, ...); + +// Matrix has double precision and CLUT has only float precision. That is because an ICC profile can encode +// matrices with far more precision that CLUTS +CMSAPI cmsStage* CMSEXPORT cmsStageAllocIdentity(cmsContext ContextID, cmsUInt32Number nChannels); +CMSAPI cmsStage* CMSEXPORT cmsStageAllocToneCurves(cmsContext ContextID, cmsUInt32Number nChannels, cmsToneCurve* const Curves[]); +CMSAPI cmsStage* CMSEXPORT cmsStageAllocMatrix(cmsContext ContextID, cmsUInt32Number Rows, cmsUInt32Number Cols, const cmsFloat64Number* Matrix, const cmsFloat64Number* Offset); + +CMSAPI cmsStage* CMSEXPORT cmsStageAllocCLut16bit(cmsContext ContextID, cmsUInt32Number nGridPoints, cmsUInt32Number inputChan, cmsUInt32Number outputChan, const cmsUInt16Number* Table); +CMSAPI cmsStage* CMSEXPORT cmsStageAllocCLutFloat(cmsContext ContextID, cmsUInt32Number nGridPoints, cmsUInt32Number inputChan, cmsUInt32Number outputChan, const cmsFloat32Number* Table); + +CMSAPI cmsStage* CMSEXPORT cmsStageAllocCLut16bitGranular(cmsContext ContextID, const cmsUInt32Number clutPoints[], cmsUInt32Number inputChan, cmsUInt32Number outputChan, const cmsUInt16Number* Table); +CMSAPI cmsStage* CMSEXPORT cmsStageAllocCLutFloatGranular(cmsContext ContextID, const cmsUInt32Number clutPoints[], cmsUInt32Number inputChan, cmsUInt32Number outputChan, const cmsFloat32Number* Table); + +CMSAPI cmsStage* CMSEXPORT cmsStageDup(cmsStage* mpe); +CMSAPI void CMSEXPORT cmsStageFree(cmsStage* mpe); +CMSAPI cmsStage* CMSEXPORT cmsStageNext(const cmsStage* mpe); + +CMSAPI cmsUInt32Number CMSEXPORT cmsStageInputChannels(const cmsStage* mpe); +CMSAPI cmsUInt32Number CMSEXPORT cmsStageOutputChannels(const cmsStage* mpe); +CMSAPI cmsStageSignature CMSEXPORT cmsStageType(const cmsStage* mpe); +CMSAPI void* CMSEXPORT cmsStageData(const cmsStage* mpe); + +// Sampling +typedef cmsInt32Number (* cmsSAMPLER16) (register const cmsUInt16Number In[], + register cmsUInt16Number Out[], + register void * Cargo); + +typedef cmsInt32Number (* cmsSAMPLERFLOAT)(register const cmsFloat32Number In[], + register cmsFloat32Number Out[], + register void * Cargo); + +// Use this flag to prevent changes being written to destination +#define SAMPLER_INSPECT 0x01000000 + +// For CLUT only +CMSAPI cmsBool CMSEXPORT cmsStageSampleCLut16bit(cmsStage* mpe, cmsSAMPLER16 Sampler, void* Cargo, cmsUInt32Number dwFlags); +CMSAPI cmsBool CMSEXPORT cmsStageSampleCLutFloat(cmsStage* mpe, cmsSAMPLERFLOAT Sampler, void* Cargo, cmsUInt32Number dwFlags); + + +// Slicers +CMSAPI cmsBool CMSEXPORT cmsSliceSpace16(cmsUInt32Number nInputs, const cmsUInt32Number clutPoints[], + cmsSAMPLER16 Sampler, void * Cargo); + +CMSAPI cmsBool CMSEXPORT cmsSliceSpaceFloat(cmsUInt32Number nInputs, const cmsUInt32Number clutPoints[], + cmsSAMPLERFLOAT Sampler, void * Cargo); + +// Multilocalized Unicode management --------------------------------------------------------------------------------------- + +typedef struct _cms_MLU_struct cmsMLU; + +#define cmsNoLanguage "\0\0" +#define cmsNoCountry "\0\0" + +CMSAPI cmsMLU* CMSEXPORT cmsMLUalloc(cmsContext ContextID, cmsUInt32Number nItems); +CMSAPI void CMSEXPORT cmsMLUfree(cmsMLU* mlu); +CMSAPI cmsMLU* CMSEXPORT cmsMLUdup(const cmsMLU* mlu); + +CMSAPI cmsBool CMSEXPORT cmsMLUsetASCII(cmsMLU* mlu, + const char LanguageCode[3], const char CountryCode[3], + const char* ASCIIString); +CMSAPI cmsBool CMSEXPORT cmsMLUsetWide(cmsMLU* mlu, + const char LanguageCode[3], const char CountryCode[3], + const wchar_t* WideString); + +CMSAPI cmsUInt32Number CMSEXPORT cmsMLUgetASCII(const cmsMLU* mlu, + const char LanguageCode[3], const char CountryCode[3], + char* Buffer, cmsUInt32Number BufferSize); + +CMSAPI cmsUInt32Number CMSEXPORT cmsMLUgetWide(const cmsMLU* mlu, + const char LanguageCode[3], const char CountryCode[3], + wchar_t* Buffer, cmsUInt32Number BufferSize); + +CMSAPI cmsBool CMSEXPORT cmsMLUgetTranslation(const cmsMLU* mlu, + const char LanguageCode[3], const char CountryCode[3], + char ObtainedLanguage[3], char ObtainedCountry[3]); + +// Undercolorremoval & black generation ------------------------------------------------------------------------------------- + +typedef struct { + cmsToneCurve* Ucr; + cmsToneCurve* Bg; + cmsMLU* Desc; + +} cmsUcrBg; + +// Screening ---------------------------------------------------------------------------------------------------------------- + +#define cmsPRINTER_DEFAULT_SCREENS 0x0001 +#define cmsFREQUENCE_UNITS_LINES_CM 0x0000 +#define cmsFREQUENCE_UNITS_LINES_INCH 0x0002 + +#define cmsSPOT_UNKNOWN 0 +#define cmsSPOT_PRINTER_DEFAULT 1 +#define cmsSPOT_ROUND 2 +#define cmsSPOT_DIAMOND 3 +#define cmsSPOT_ELLIPSE 4 +#define cmsSPOT_LINE 5 +#define cmsSPOT_SQUARE 6 +#define cmsSPOT_CROSS 7 + +typedef struct { + cmsFloat64Number Frequency; + cmsFloat64Number ScreenAngle; + cmsUInt32Number SpotShape; + +} cmsScreeningChannel; + +typedef struct { + cmsUInt32Number Flag; + cmsUInt32Number nChannels; + cmsScreeningChannel Channels[cmsMAXCHANNELS]; + +} cmsScreening; + + +// Named color ----------------------------------------------------------------------------------------------------------------- + +typedef struct _cms_NAMEDCOLORLIST_struct cmsNAMEDCOLORLIST; + +CMSAPI cmsNAMEDCOLORLIST* CMSEXPORT cmsAllocNamedColorList(cmsContext ContextID, + cmsUInt32Number n, + cmsUInt32Number ColorantCount, + const char* Prefix, const char* Suffix); + +CMSAPI void CMSEXPORT cmsFreeNamedColorList(cmsNAMEDCOLORLIST* v); +CMSAPI cmsNAMEDCOLORLIST* CMSEXPORT cmsDupNamedColorList(const cmsNAMEDCOLORLIST* v); +CMSAPI cmsBool CMSEXPORT cmsAppendNamedColor(cmsNAMEDCOLORLIST* v, const char* Name, + cmsUInt16Number PCS[3], + cmsUInt16Number Colorant[cmsMAXCHANNELS]); + +CMSAPI cmsUInt32Number CMSEXPORT cmsNamedColorCount(const cmsNAMEDCOLORLIST* v); +CMSAPI cmsInt32Number CMSEXPORT cmsNamedColorIndex(const cmsNAMEDCOLORLIST* v, const char* Name); + +CMSAPI cmsBool CMSEXPORT cmsNamedColorInfo(const cmsNAMEDCOLORLIST* NamedColorList, cmsUInt32Number nColor, + char* Name, + char* Prefix, + char* Suffix, + cmsUInt16Number* PCS, + cmsUInt16Number* Colorant); + +// Retrieve named color list from transform +CMSAPI cmsNAMEDCOLORLIST* CMSEXPORT cmsGetNamedColorList(cmsHTRANSFORM xform); + +// Profile sequence ----------------------------------------------------------------------------------------------------- + +// Profile sequence descriptor. Some fields come from profile sequence descriptor tag, others +// come from Profile Sequence Identifier Tag +typedef struct { + cmsSignature deviceMfg; + cmsSignature deviceModel; + cmsUInt64Number attributes; + cmsTechnologySignature technology; + cmsProfileID ProfileID; + cmsMLU* Manufacturer; + cmsMLU* Model; + cmsMLU* Description; + +} cmsPSEQDESC; + +typedef struct { + + cmsUInt32Number n; + cmsContext ContextID; + cmsPSEQDESC* seq; + +} cmsSEQ; + +CMSAPI cmsSEQ* CMSEXPORT cmsAllocProfileSequenceDescription(cmsContext ContextID, cmsUInt32Number n); +CMSAPI cmsSEQ* CMSEXPORT cmsDupProfileSequenceDescription(const cmsSEQ* pseq); +CMSAPI void CMSEXPORT cmsFreeProfileSequenceDescription(cmsSEQ* pseq); + +// Access to Profile data ---------------------------------------------------------------------------------------------- +CMSAPI cmsHPROFILE CMSEXPORT cmsCreateProfilePlaceholder(cmsContext ContextID); + +CMSAPI cmsContext CMSEXPORT cmsGetProfileContextID(cmsHPROFILE hProfile); +CMSAPI cmsInt32Number CMSEXPORT cmsGetTagCount(cmsHPROFILE hProfile); +CMSAPI cmsTagSignature CMSEXPORT cmsGetTagSignature(cmsHPROFILE hProfile, cmsUInt32Number n); +CMSAPI cmsBool CMSEXPORT cmsIsTag(cmsHPROFILE hProfile, cmsTagSignature sig); + +// Read and write pre-formatted data +CMSAPI void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig); +CMSAPI cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const void* data); +CMSAPI cmsBool CMSEXPORT cmsLinkTag(cmsHPROFILE hProfile, cmsTagSignature sig, cmsTagSignature dest); + +// Read and write raw data +CMSAPI cmsInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature sig, void* Buffer, cmsUInt32Number BufferSize); +CMSAPI cmsBool CMSEXPORT cmsWriteRawTag(cmsHPROFILE hProfile, cmsTagSignature sig, const void* data, cmsUInt32Number Size); + +// Access header data +CMSAPI cmsUInt32Number CMSEXPORT cmsGetHeaderFlags(cmsHPROFILE hProfile); +CMSAPI void CMSEXPORT cmsGetHeaderAttributes(cmsHPROFILE hProfile, cmsUInt64Number* Flags); +CMSAPI void CMSEXPORT cmsGetHeaderProfileID(cmsHPROFILE hProfile, cmsUInt8Number* ProfileID); +CMSAPI cmsBool CMSEXPORT cmsGetHeaderCreationDateTime(cmsHPROFILE hProfile, struct tm *Dest); +CMSAPI cmsUInt32Number CMSEXPORT cmsGetHeaderRenderingIntent(cmsHPROFILE hProfile); + +CMSAPI void CMSEXPORT cmsSetHeaderFlags(cmsHPROFILE hProfile, cmsUInt32Number Flags); +CMSAPI cmsUInt32Number CMSEXPORT cmsGetHeaderManufacturer(cmsHPROFILE hProfile); +CMSAPI void CMSEXPORT cmsSetHeaderManufacturer(cmsHPROFILE hProfile, cmsUInt32Number manufacturer); +CMSAPI cmsUInt32Number CMSEXPORT cmsGetHeaderModel(cmsHPROFILE hProfile); +CMSAPI void CMSEXPORT cmsSetHeaderModel(cmsHPROFILE hProfile, cmsUInt32Number model); +CMSAPI void CMSEXPORT cmsSetHeaderAttributes(cmsHPROFILE hProfile, cmsUInt64Number Flags); +CMSAPI void CMSEXPORT cmsSetHeaderProfileID(cmsHPROFILE hProfile, cmsUInt8Number* ProfileID); +CMSAPI void CMSEXPORT cmsSetHeaderRenderingIntent(cmsHPROFILE hProfile, cmsUInt32Number RenderingIntent); + +CMSAPI cmsColorSpaceSignature + CMSEXPORT cmsGetPCS(cmsHPROFILE hProfile); +CMSAPI void CMSEXPORT cmsSetPCS(cmsHPROFILE hProfile, cmsColorSpaceSignature pcs); +CMSAPI cmsColorSpaceSignature + CMSEXPORT cmsGetColorSpace(cmsHPROFILE hProfile); +CMSAPI void CMSEXPORT cmsSetColorSpace(cmsHPROFILE hProfile, cmsColorSpaceSignature sig); +CMSAPI cmsProfileClassSignature + CMSEXPORT cmsGetDeviceClass(cmsHPROFILE hProfile); +CMSAPI void CMSEXPORT cmsSetDeviceClass(cmsHPROFILE hProfile, cmsProfileClassSignature sig); +CMSAPI void CMSEXPORT cmsSetProfileVersion(cmsHPROFILE hProfile, cmsFloat64Number Version); +CMSAPI cmsFloat64Number CMSEXPORT cmsGetProfileVersion(cmsHPROFILE hProfile); + +CMSAPI cmsUInt32Number CMSEXPORT cmsGetEncodedICCversion(cmsHPROFILE hProfile); +CMSAPI void CMSEXPORT cmsSetEncodedICCversion(cmsHPROFILE hProfile, cmsUInt32Number Version); + +// How profiles may be used +#define LCMS_USED_AS_INPUT 0 +#define LCMS_USED_AS_OUTPUT 1 +#define LCMS_USED_AS_PROOF 2 + +CMSAPI cmsBool CMSEXPORT cmsIsIntentSupported(cmsHPROFILE hProfile, cmsUInt32Number Intent, int UsedDirection); +CMSAPI cmsBool CMSEXPORT cmsIsMatrixShaper(cmsHPROFILE hProfile); +CMSAPI cmsBool CMSEXPORT cmsIsCLUT(cmsHPROFILE hProfile, cmsUInt32Number Intent, int UsedDirection); + +// Translate form/to our notation to ICC +CMSAPI cmsColorSpaceSignature CMSEXPORT _cmsICCcolorSpace(int OurNotation); +CMSAPI int CMSEXPORT _cmsLCMScolorSpace(cmsColorSpaceSignature ProfileSpace); + +CMSAPI cmsUInt32Number CMSEXPORT cmsChannelsOf(cmsColorSpaceSignature ColorSpace); + +// Build a suitable formatter for the colorspace of this profile +CMSAPI cmsUInt32Number CMSEXPORT cmsFormatterForColorspaceOfProfile(cmsHPROFILE hProfile, cmsUInt32Number nBytes, cmsBool lIsFloat); +CMSAPI cmsUInt32Number CMSEXPORT cmsFormatterForPCSOfProfile(cmsHPROFILE hProfile, cmsUInt32Number nBytes, cmsBool lIsFloat); + + +// Localized info +typedef enum { + cmsInfoDescription = 0, + cmsInfoManufacturer = 1, + cmsInfoModel = 2, + cmsInfoCopyright = 3 +} cmsInfoType; + +CMSAPI cmsUInt32Number CMSEXPORT cmsGetProfileInfo(cmsHPROFILE hProfile, cmsInfoType Info, + const char LanguageCode[3], const char CountryCode[3], + wchar_t* Buffer, cmsUInt32Number BufferSize); + +CMSAPI cmsUInt32Number CMSEXPORT cmsGetProfileInfoASCII(cmsHPROFILE hProfile, cmsInfoType Info, + const char LanguageCode[3], const char CountryCode[3], + char* Buffer, cmsUInt32Number BufferSize); + +// IO handlers ---------------------------------------------------------------------------------------------------------- + +typedef struct _cms_io_handler cmsIOHANDLER; + +CMSAPI cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromFile(cmsContext ContextID, const char* FileName, const char* AccessMode); +CMSAPI cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromStream(cmsContext ContextID, FILE* Stream); +CMSAPI cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromMem(cmsContext ContextID, void *Buffer, cmsUInt32Number size, const char* AccessMode); +CMSAPI cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromNULL(cmsContext ContextID); +CMSAPI cmsBool CMSEXPORT cmsCloseIOhandler(cmsIOHANDLER* io); + +// MD5 message digest -------------------------------------------------------------------------------------------------- + +CMSAPI cmsBool CMSEXPORT cmsMD5computeID(cmsHPROFILE hProfile); + +// Profile high level funtions ------------------------------------------------------------------------------------------ + +CMSAPI cmsHPROFILE CMSEXPORT cmsOpenProfileFromFile(const char *ICCProfile, const char *sAccess); +CMSAPI cmsHPROFILE CMSEXPORT cmsOpenProfileFromFileTHR(cmsContext ContextID, const char *ICCProfile, const char *sAccess); +CMSAPI cmsHPROFILE CMSEXPORT cmsOpenProfileFromStream(FILE* ICCProfile, const char* sAccess); +CMSAPI cmsHPROFILE CMSEXPORT cmsOpenProfileFromStreamTHR(cmsContext ContextID, FILE* ICCProfile, const char* sAccess); +CMSAPI cmsHPROFILE CMSEXPORT cmsOpenProfileFromMem(const void * MemPtr, cmsUInt32Number dwSize); +CMSAPI cmsHPROFILE CMSEXPORT cmsOpenProfileFromMemTHR(cmsContext ContextID, const void * MemPtr, cmsUInt32Number dwSize); +CMSAPI cmsHPROFILE CMSEXPORT cmsOpenProfileFromIOhandlerTHR(cmsContext ContextID, cmsIOHANDLER* io); +CMSAPI cmsBool CMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile); + +CMSAPI cmsBool CMSEXPORT cmsSaveProfileToFile(cmsHPROFILE hProfile, const char* FileName); +CMSAPI cmsBool CMSEXPORT cmsSaveProfileToStream(cmsHPROFILE hProfile, FILE* Stream); +CMSAPI cmsBool CMSEXPORT cmsSaveProfileToMem(cmsHPROFILE hProfile, void *MemPtr, cmsUInt32Number* BytesNeeded); +CMSAPI cmsUInt32Number CMSEXPORT cmsSaveProfileToIOhandler(cmsHPROFILE hProfile, cmsIOHANDLER* io); + +// Predefined virtual profiles ------------------------------------------------------------------------------------------ + +CMSAPI cmsHPROFILE CMSEXPORT cmsCreateRGBProfileTHR(cmsContext ContextID, + const cmsCIExyY* WhitePoint, + const cmsCIExyYTRIPLE* Primaries, + cmsToneCurve* const TransferFunction[3]); + +CMSAPI cmsHPROFILE CMSEXPORT cmsCreateRGBProfile(const cmsCIExyY* WhitePoint, + const cmsCIExyYTRIPLE* Primaries, + cmsToneCurve* const TransferFunction[3]); + +CMSAPI cmsHPROFILE CMSEXPORT cmsCreateGrayProfileTHR(cmsContext ContextID, + const cmsCIExyY* WhitePoint, + const cmsToneCurve* TransferFunction); + +CMSAPI cmsHPROFILE CMSEXPORT cmsCreateGrayProfile(const cmsCIExyY* WhitePoint, + const cmsToneCurve* TransferFunction); + +CMSAPI cmsHPROFILE CMSEXPORT cmsCreateLinearizationDeviceLinkTHR(cmsContext ContextID, + cmsColorSpaceSignature ColorSpace, + cmsToneCurve* const TransferFunctions[]); + +CMSAPI cmsHPROFILE CMSEXPORT cmsCreateLinearizationDeviceLink(cmsColorSpaceSignature ColorSpace, + cmsToneCurve* const TransferFunctions[]); + +CMSAPI cmsHPROFILE CMSEXPORT cmsCreateInkLimitingDeviceLinkTHR(cmsContext ContextID, + cmsColorSpaceSignature ColorSpace, cmsFloat64Number Limit); + +CMSAPI cmsHPROFILE CMSEXPORT cmsCreateInkLimitingDeviceLink(cmsColorSpaceSignature ColorSpace, cmsFloat64Number Limit); + + +CMSAPI cmsHPROFILE CMSEXPORT cmsCreateLab2ProfileTHR(cmsContext ContextID, const cmsCIExyY* WhitePoint); +CMSAPI cmsHPROFILE CMSEXPORT cmsCreateLab2Profile(const cmsCIExyY* WhitePoint); +CMSAPI cmsHPROFILE CMSEXPORT cmsCreateLab4ProfileTHR(cmsContext ContextID, const cmsCIExyY* WhitePoint); +CMSAPI cmsHPROFILE CMSEXPORT cmsCreateLab4Profile(const cmsCIExyY* WhitePoint); + +CMSAPI cmsHPROFILE CMSEXPORT cmsCreateXYZProfileTHR(cmsContext ContextID); +CMSAPI cmsHPROFILE CMSEXPORT cmsCreateXYZProfile(void); + +CMSAPI cmsHPROFILE CMSEXPORT cmsCreate_sRGBProfileTHR(cmsContext ContextID); +CMSAPI cmsHPROFILE CMSEXPORT cmsCreate_sRGBProfile(void); + +CMSAPI cmsHPROFILE CMSEXPORT cmsCreateBCHSWabstractProfileTHR(cmsContext ContextID, + int nLUTPoints, + cmsFloat64Number Bright, + cmsFloat64Number Contrast, + cmsFloat64Number Hue, + cmsFloat64Number Saturation, + int TempSrc, + int TempDest); + +CMSAPI cmsHPROFILE CMSEXPORT cmsCreateBCHSWabstractProfile(int nLUTPoints, + cmsFloat64Number Bright, + cmsFloat64Number Contrast, + cmsFloat64Number Hue, + cmsFloat64Number Saturation, + int TempSrc, + int TempDest); + +CMSAPI cmsHPROFILE CMSEXPORT cmsCreateNULLProfileTHR(cmsContext ContextID); +CMSAPI cmsHPROFILE CMSEXPORT cmsCreateNULLProfile(void); + +// Converts a transform to a devicelink profile +CMSAPI cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat64Number Version, cmsUInt32Number dwFlags); + +// Intents ---------------------------------------------------------------------------------------------- + +// ICC Intents +#define INTENT_PERCEPTUAL 0 +#define INTENT_RELATIVE_COLORIMETRIC 1 +#define INTENT_SATURATION 2 +#define INTENT_ABSOLUTE_COLORIMETRIC 3 + +// Non-ICC intents +#define INTENT_PRESERVE_K_ONLY_PERCEPTUAL 10 +#define INTENT_PRESERVE_K_ONLY_RELATIVE_COLORIMETRIC 11 +#define INTENT_PRESERVE_K_ONLY_SATURATION 12 +#define INTENT_PRESERVE_K_PLANE_PERCEPTUAL 13 +#define INTENT_PRESERVE_K_PLANE_RELATIVE_COLORIMETRIC 14 +#define INTENT_PRESERVE_K_PLANE_SATURATION 15 + +// Call with NULL as parameters to get the intent count +CMSAPI cmsUInt32Number CMSEXPORT cmsGetSupportedIntents(cmsUInt32Number nMax, cmsUInt32Number* Codes, char** Descriptions); + +// Flags + +#define cmsFLAGS_NOCACHE 0x0040 // Inhibit 1-pixel cache +#define cmsFLAGS_NOOPTIMIZE 0x0100 // Inhibit optimizations +#define cmsFLAGS_NULLTRANSFORM 0x0200 // Don't transform anyway + + +// Proofing flags +#define cmsFLAGS_GAMUTCHECK 0x1000 // Out of Gamut alarm +#define cmsFLAGS_SOFTPROOFING 0x4000 // Do softproofing + +// Misc +#define cmsFLAGS_BLACKPOINTCOMPENSATION 0x2000 +#define cmsFLAGS_NOWHITEONWHITEFIXUP 0x0004 // Don't fix scum dot +#define cmsFLAGS_HIGHRESPRECALC 0x0400 // Use more memory to give better accurancy +#define cmsFLAGS_LOWRESPRECALC 0x0800 // Use less memory to minimize resouces + +// For devicelink creation +#define cmsFLAGS_8BITS_DEVICELINK 0x0008 // Create 8 bits devicelinks +#define cmsFLAGS_GUESSDEVICECLASS 0x0020 // Guess device class (for transform2devicelink) +#define cmsFLAGS_KEEP_SEQUENCE 0x0080 // Keep profile sequence for devicelink creation + +// Specific to a particular optimizations +#define cmsFLAGS_FORCE_CLUT 0x0002 // Force CLUT optimization +#define cmsFLAGS_CLUT_POST_LINEARIZATION 0x0001 // create postlinearization tables if possible +#define cmsFLAGS_CLUT_PRE_LINEARIZATION 0x0010 // create prelinearization tables if possible + +// Fine-tune control over number of gridpoints +#define cmsFLAGS_GRIDPOINTS(n) (((n) & 0xFF) << 16) + +// CRD special +#define cmsFLAGS_NODEFAULTRESOURCEDEF 0x01000000 + +// Transforms --------------------------------------------------------------------------------------------------- + +CMSAPI cmsHTRANSFORM CMSEXPORT cmsCreateTransformTHR(cmsContext ContextID, + cmsHPROFILE Input, + cmsUInt32Number InputFormat, + cmsHPROFILE Output, + cmsUInt32Number OutputFormat, + cmsUInt32Number Intent, + cmsUInt32Number dwFlags); + +CMSAPI cmsHTRANSFORM CMSEXPORT cmsCreateTransform(cmsHPROFILE Input, + cmsUInt32Number InputFormat, + cmsHPROFILE Output, + cmsUInt32Number OutputFormat, + cmsUInt32Number Intent, + cmsUInt32Number dwFlags); + +CMSAPI cmsHTRANSFORM CMSEXPORT cmsCreateProofingTransformTHR(cmsContext ContextID, + cmsHPROFILE Input, + cmsUInt32Number InputFormat, + cmsHPROFILE Output, + cmsUInt32Number OutputFormat, + cmsHPROFILE Proofing, + cmsUInt32Number Intent, + cmsUInt32Number ProofingIntent, + cmsUInt32Number dwFlags); + +CMSAPI cmsHTRANSFORM CMSEXPORT cmsCreateProofingTransform(cmsHPROFILE Input, + cmsUInt32Number InputFormat, + cmsHPROFILE Output, + cmsUInt32Number OutputFormat, + cmsHPROFILE Proofing, + cmsUInt32Number Intent, + cmsUInt32Number ProofingIntent, + cmsUInt32Number dwFlags); + +CMSAPI cmsHTRANSFORM CMSEXPORT cmsCreateMultiprofileTransformTHR(cmsContext ContextID, + cmsHPROFILE hProfiles[], + cmsUInt32Number nProfiles, + cmsUInt32Number InputFormat, + cmsUInt32Number OutputFormat, + cmsUInt32Number Intent, + cmsUInt32Number dwFlags); + + +CMSAPI cmsHTRANSFORM CMSEXPORT cmsCreateMultiprofileTransform(cmsHPROFILE hProfiles[], + cmsUInt32Number nProfiles, + cmsUInt32Number InputFormat, + cmsUInt32Number OutputFormat, + cmsUInt32Number Intent, + cmsUInt32Number dwFlags); + + +CMSAPI cmsHTRANSFORM CMSEXPORT cmsCreateExtendedTransform(cmsContext ContextID, + cmsUInt32Number nProfiles, cmsHPROFILE hProfiles[], + cmsBool BPC[], + cmsUInt32Number Intents[], + cmsFloat64Number AdaptationStates[], + cmsHPROFILE hGamutProfile, + cmsUInt32Number nGamutPCSposition, + cmsUInt32Number InputFormat, + cmsUInt32Number OutputFormat, + cmsUInt32Number dwFlags); + +CMSAPI void CMSEXPORT cmsDeleteTransform(cmsHTRANSFORM hTransform); + +CMSAPI void CMSEXPORT cmsDoTransform(cmsHTRANSFORM Transform, + const void * InputBuffer, + void * OutputBuffer, + cmsUInt32Number Size); + +CMSAPI void CMSEXPORT cmsSetAlarmCodes(cmsUInt16Number NewAlarm[cmsMAXCHANNELS]); +CMSAPI void CMSEXPORT cmsGetAlarmCodes(cmsUInt16Number NewAlarm[cmsMAXCHANNELS]); + +// Adaptation state for absolute colorimetric intent +CMSAPI cmsFloat64Number CMSEXPORT cmsSetAdaptationState(cmsFloat64Number d); + +CMSAPI cmsContext CMSEXPORT cmsGetTransformContextID(cmsHTRANSFORM hTransform); + + +// PostScript ColorRenderingDictionary and ColorSpaceArray ---------------------------------------------------- + +typedef enum { cmsPS_RESOURCE_CSA, cmsPS_RESOURCE_CRD } cmsPSResourceType; + +// lcms2 unified method to access postscript color resources +CMSAPI cmsUInt32Number CMSEXPORT cmsGetPostScriptColorResource(cmsContext ContextID, + cmsPSResourceType Type, + cmsHPROFILE hProfile, + cmsUInt32Number Intent, + cmsUInt32Number dwFlags, + cmsIOHANDLER* io); + +CMSAPI cmsUInt32Number CMSEXPORT cmsGetPostScriptCSA(cmsContext ContextID, cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number dwFlags, void* Buffer, cmsUInt32Number dwBufferLen); +CMSAPI cmsUInt32Number CMSEXPORT cmsGetPostScriptCRD(cmsContext ContextID, cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number dwFlags, void* Buffer, cmsUInt32Number dwBufferLen); + + +// IT8.7 / CGATS.17-200x handling ----------------------------------------------------------------------------- + +CMSAPI cmsHANDLE CMSEXPORT cmsIT8Alloc(cmsContext ContextID); +CMSAPI void CMSEXPORT cmsIT8Free(cmsHANDLE hIT8); + +// Tables +CMSAPI cmsUInt32Number CMSEXPORT cmsIT8TableCount(cmsHANDLE hIT8); +CMSAPI cmsInt32Number CMSEXPORT cmsIT8SetTable(cmsHANDLE hIT8, cmsUInt32Number nTable); + +// Persistence +CMSAPI cmsHANDLE CMSEXPORT cmsIT8LoadFromFile(cmsContext ContextID, const char* cFileName); +CMSAPI cmsHANDLE CMSEXPORT cmsIT8LoadFromMem(cmsContext ContextID, void *Ptr, cmsUInt32Number len); +// CMSAPI cmsHANDLE CMSEXPORT cmsIT8LoadFromIOhandler(cmsContext ContextID, cmsIOHANDLER* io); + +CMSAPI cmsBool CMSEXPORT cmsIT8SaveToFile(cmsHANDLE hIT8, const char* cFileName); +CMSAPI cmsBool CMSEXPORT cmsIT8SaveToMem(cmsHANDLE hIT8, void *MemPtr, cmsUInt32Number* BytesNeeded); + +// Properties +CMSAPI const char* CMSEXPORT cmsIT8GetSheetType(cmsHANDLE hIT8); +CMSAPI cmsBool CMSEXPORT cmsIT8SetSheetType(cmsHANDLE hIT8, const char* Type); + +CMSAPI cmsBool CMSEXPORT cmsIT8SetComment(cmsHANDLE hIT8, const char* cComment); + +CMSAPI cmsBool CMSEXPORT cmsIT8SetPropertyStr(cmsHANDLE hIT8, const char* cProp, const char *Str); +CMSAPI cmsBool CMSEXPORT cmsIT8SetPropertyDbl(cmsHANDLE hIT8, const char* cProp, cmsFloat64Number Val); +CMSAPI cmsBool CMSEXPORT cmsIT8SetPropertyHex(cmsHANDLE hIT8, const char* cProp, cmsUInt32Number Val); +CMSAPI cmsBool CMSEXPORT cmsIT8SetPropertyUncooked(cmsHANDLE hIT8, const char* Key, const char* Buffer); + + +CMSAPI const char* CMSEXPORT cmsIT8GetProperty(cmsHANDLE hIT8, const char* cProp); +CMSAPI cmsFloat64Number CMSEXPORT cmsIT8GetPropertyDbl(cmsHANDLE hIT8, const char* cProp); +CMSAPI cmsUInt32Number CMSEXPORT cmsIT8EnumProperties(cmsHANDLE hIT8, char ***PropertyNames); + +// Datasets +CMSAPI const char* CMSEXPORT cmsIT8GetDataRowCol(cmsHANDLE hIT8, int row, int col); +CMSAPI cmsFloat64Number CMSEXPORT cmsIT8GetDataRowColDbl(cmsHANDLE hIT8, int row, int col); + +CMSAPI cmsBool CMSEXPORT cmsIT8SetDataRowCol(cmsHANDLE hIT8, int row, int col, + const char* Val); + +CMSAPI cmsBool CMSEXPORT cmsIT8SetDataRowColDbl(cmsHANDLE hIT8, int row, int col, + cmsFloat64Number Val); + +CMSAPI const char* CMSEXPORT cmsIT8GetData(cmsHANDLE hIT8, const char* cPatch, const char* cSample); + + +CMSAPI cmsFloat64Number CMSEXPORT cmsIT8GetDataDbl(cmsHANDLE hIT8, const char* cPatch, const char* cSample); + +CMSAPI cmsBool CMSEXPORT cmsIT8SetData(cmsHANDLE hIT8, const char* cPatch, + const char* cSample, + const char *Val); + +CMSAPI cmsBool CMSEXPORT cmsIT8SetDataDbl(cmsHANDLE hIT8, const char* cPatch, + const char* cSample, + cmsFloat64Number Val); + +CMSAPI int CMSEXPORT cmsIT8FindDataFormat(cmsHANDLE hIT8, const char* cSample); +CMSAPI cmsBool CMSEXPORT cmsIT8SetDataFormat(cmsHANDLE hIT8, int n, const char *Sample); +CMSAPI int CMSEXPORT cmsIT8EnumDataFormat(cmsHANDLE hIT8, char ***SampleNames); + +CMSAPI const char* CMSEXPORT cmsIT8GetPatchName(cmsHANDLE hIT8, int nPatch, char* buffer); + +// The LABEL extension +CMSAPI int CMSEXPORT cmsIT8SetTableByLabel(cmsHANDLE hIT8, const char* cSet, const char* cField, const char* ExpectedType); + +// Formatter for double +CMSAPI void CMSEXPORT cmsIT8DefineDblFormat(cmsHANDLE hIT8, const char* Formatter); + +// Gamut boundary description routines ------------------------------------------------------------------------------ + +CMSAPI cmsHANDLE CMSEXPORT cmsGBDAlloc(cmsContext ContextID); +CMSAPI void CMSEXPORT cmsGBDFree(cmsHANDLE hGBD); +CMSAPI cmsBool CMSEXPORT cmsGDBAddPoint(cmsHANDLE hGBD, const cmsCIELab* Lab); +CMSAPI cmsBool CMSEXPORT cmsGDBCompute(cmsHANDLE hGDB, cmsUInt32Number dwFlags); +CMSAPI cmsBool CMSEXPORT cmsGDBCheckPoint(cmsHANDLE hGBD, const cmsCIELab* Lab); + +// Feature detection ---------------------------------------------------------------------------------------------- + +// Estimate the black point +CMSAPI cmsBool CMSEXPORT cmsDetectBlackPoint(cmsCIEXYZ* BlackPoint, cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number dwFlags); + +// Estimate total area coverage +CMSAPI cmsFloat64Number CMSEXPORT cmsDetectTAC(cmsHPROFILE hProfile); + + +// Poor man's gamut mapping +CMSAPI cmsBool CMSEXPORT cmsDesaturateLab(cmsCIELab* Lab, + double amax, double amin, + double bmax, double bmin); + +#ifndef CMS_USE_CPP_API +# ifdef __cplusplus + } +# endif +#endif + +#define _lcms2_H +#endif diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libs/lcms2/lcms2_plugin.h b/gdcm/Utilities/gdcmopenjpeg-v1/libs/lcms2/lcms2_plugin.h new file mode 100644 index 0000000..fd90350 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libs/lcms2/lcms2_plugin.h @@ -0,0 +1,533 @@ +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2010 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// +// This is the plug-in header file. Normal LittleCMS clients should not use it. +// It is provided for plug-in writters that may want to access the support +// functions to do low level operations. All plug-in related structures +// are defined here. Including this file forces to include the standard API too. + +#ifndef _lcms_plugin_H + +// Deal with Microsoft's attempt at deprecating C standard runtime functions +#ifdef _MSC_VER +# if (_MSC_VER >= 1400) +# ifndef _CRT_SECURE_NO_DEPRECATE +# define _CRT_SECURE_NO_DEPRECATE +# endif +# ifndef _CRT_SECURE_NO_WARNINGS +# define _CRT_SECURE_NO_WARNINGS +# endif +# endif +#endif + +#ifndef _lcms2_H +#include "lcms2.h" +#endif + +// We need some standard C functions. +#include +#include +#include +#include +#include + + +#ifndef CMS_USE_CPP_API +# ifdef __cplusplus +extern "C" { +# endif +#endif + +// Vector & Matrix operations ----------------------------------------------------------------------- + +// Axis of the matrix/array. No specific meaning at all. +#define VX 0 +#define VY 1 +#define VZ 2 + +// Vectors +typedef struct { + cmsFloat64Number n[3]; + + } cmsVEC3; + +// 3x3 Matrix +typedef struct { + cmsVEC3 v[3]; + + } cmsMAT3; + +CMSAPI void CMSEXPORT _cmsVEC3init(cmsVEC3* r, cmsFloat64Number x, cmsFloat64Number y, cmsFloat64Number z); +CMSAPI void CMSEXPORT _cmsVEC3minus(cmsVEC3* r, const cmsVEC3* a, const cmsVEC3* b); +CMSAPI void CMSEXPORT _cmsVEC3cross(cmsVEC3* r, const cmsVEC3* u, const cmsVEC3* v); +CMSAPI cmsFloat64Number CMSEXPORT _cmsVEC3dot(const cmsVEC3* u, const cmsVEC3* v); +CMSAPI cmsFloat64Number CMSEXPORT _cmsVEC3length(const cmsVEC3* a); +CMSAPI cmsFloat64Number CMSEXPORT _cmsVEC3distance(const cmsVEC3* a, const cmsVEC3* b); + +CMSAPI void CMSEXPORT _cmsMAT3identity(cmsMAT3* a); +CMSAPI cmsBool CMSEXPORT _cmsMAT3isIdentity(const cmsMAT3* a); +CMSAPI void CMSEXPORT _cmsMAT3per(cmsMAT3* r, const cmsMAT3* a, const cmsMAT3* b); +CMSAPI cmsBool CMSEXPORT _cmsMAT3inverse(const cmsMAT3* a, cmsMAT3* b); +CMSAPI cmsBool CMSEXPORT _cmsMAT3solve(cmsVEC3* x, cmsMAT3* a, cmsVEC3* b); +CMSAPI void CMSEXPORT _cmsMAT3eval(cmsVEC3* r, const cmsMAT3* a, const cmsVEC3* v); + + +// Error logging ------------------------------------------------------------------------------------- + +CMSAPI void CMSEXPORT cmsSignalError(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *ErrorText, ...); + +// Memory management ---------------------------------------------------------------------------------- + +CMSAPI void* CMSEXPORT _cmsMalloc(cmsContext ContextID, cmsUInt32Number size); +CMSAPI void* CMSEXPORT _cmsMallocZero(cmsContext ContextID, cmsUInt32Number size); +CMSAPI void* CMSEXPORT _cmsCalloc(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size); +CMSAPI void* CMSEXPORT _cmsRealloc(cmsContext ContextID, void* Ptr, cmsUInt32Number NewSize); +CMSAPI void CMSEXPORT _cmsFree(cmsContext ContextID, void* Ptr); +CMSAPI void* CMSEXPORT _cmsDupMem(cmsContext ContextID, const void* Org, cmsUInt32Number size); + +// I/O handler ---------------------------------------------------------------------------------- + +struct _cms_io_handler { + + void* stream; // Associated stream, which is implemented differently depending on media. + + cmsContext ContextID; + cmsUInt32Number UsedSpace; + char PhysicalFile[cmsMAX_PATH]; + + cmsUInt32Number (* Read)(struct _cms_io_handler* iohandler, void *Buffer, + cmsUInt32Number size, + cmsUInt32Number count); + cmsBool (* Seek)(struct _cms_io_handler* iohandler, cmsUInt32Number offset); + cmsBool (* Close)(struct _cms_io_handler* iohandler); + cmsUInt32Number (* Tell)(struct _cms_io_handler* iohandler); + cmsBool (* Write)(struct _cms_io_handler* iohandler, cmsUInt32Number size, + const void* Buffer); +}; + +// Endianess adjust functions +CMSAPI cmsUInt16Number CMSEXPORT _cmsAdjustEndianess16(cmsUInt16Number Word); +CMSAPI cmsUInt32Number CMSEXPORT _cmsAdjustEndianess32(cmsUInt32Number Value); +CMSAPI void CMSEXPORT _cmsAdjustEndianess64(cmsUInt64Number* Result, cmsUInt64Number QWord); + +// Helper IO functions +CMSAPI cmsBool CMSEXPORT _cmsReadUInt8Number(cmsIOHANDLER* io, cmsUInt8Number* n); +CMSAPI cmsBool CMSEXPORT _cmsReadUInt16Number(cmsIOHANDLER* io, cmsUInt16Number* n); +CMSAPI cmsBool CMSEXPORT _cmsReadUInt32Number(cmsIOHANDLER* io, cmsUInt32Number* n); +CMSAPI cmsBool CMSEXPORT _cmsReadFloat32Number(cmsIOHANDLER* io, cmsFloat32Number* n); +CMSAPI cmsBool CMSEXPORT _cmsReadUInt64Number(cmsIOHANDLER* io, cmsUInt64Number* n); +CMSAPI cmsBool CMSEXPORT _cmsRead15Fixed16Number(cmsIOHANDLER* io, cmsFloat64Number* n); +CMSAPI cmsBool CMSEXPORT _cmsReadXYZNumber(cmsIOHANDLER* io, cmsCIEXYZ* XYZ); +CMSAPI cmsBool CMSEXPORT _cmsReadUInt16Array(cmsIOHANDLER* io, cmsUInt32Number n, cmsUInt16Number* Array); + +CMSAPI cmsBool CMSEXPORT _cmsWriteUInt8Number(cmsIOHANDLER* io, cmsUInt8Number n); +CMSAPI cmsBool CMSEXPORT _cmsWriteUInt16Number(cmsIOHANDLER* io, cmsUInt16Number n); +CMSAPI cmsBool CMSEXPORT _cmsWriteUInt32Number(cmsIOHANDLER* io, cmsUInt32Number n); +CMSAPI cmsBool CMSEXPORT _cmsWriteFloat32Number(cmsIOHANDLER* io, cmsFloat32Number n); +CMSAPI cmsBool CMSEXPORT _cmsWriteUInt64Number(cmsIOHANDLER* io, cmsUInt64Number n); +CMSAPI cmsBool CMSEXPORT _cmsWrite15Fixed16Number(cmsIOHANDLER* io, cmsFloat64Number n); +CMSAPI cmsBool CMSEXPORT _cmsWriteXYZNumber(cmsIOHANDLER* io, const cmsCIEXYZ* XYZ); +CMSAPI cmsBool CMSEXPORT _cmsWriteUInt16Array(cmsIOHANDLER* io, cmsUInt32Number n, const cmsUInt16Number* Array); + +// ICC base tag +typedef struct { + cmsTagTypeSignature sig; + cmsInt8Number reserved[4]; + +} _cmsTagBase; + +// Type base helper functions +CMSAPI cmsTagTypeSignature CMSEXPORT _cmsReadTypeBase(cmsIOHANDLER* io); +CMSAPI cmsBool CMSEXPORT _cmsWriteTypeBase(cmsIOHANDLER* io, cmsTagTypeSignature sig); + +// Alignment functions +CMSAPI cmsBool CMSEXPORT _cmsReadAlignment(cmsIOHANDLER* io); +CMSAPI cmsBool CMSEXPORT _cmsWriteAlignment(cmsIOHANDLER* io); + +// To deal with text streams. 2K at most +CMSAPI cmsBool CMSEXPORT _cmsIOPrintf(cmsIOHANDLER* io, const char* frm, ...); + +// Fixed point helper functions +CMSAPI cmsFloat64Number CMSEXPORT _cms8Fixed8toDouble(cmsUInt16Number fixed8); +CMSAPI cmsUInt16Number CMSEXPORT _cmsDoubleTo8Fixed8(cmsFloat64Number val); + +CMSAPI cmsFloat64Number CMSEXPORT _cms15Fixed16toDouble(cmsS15Fixed16Number fix32); +CMSAPI cmsS15Fixed16Number CMSEXPORT _cmsDoubleTo15Fixed16(cmsFloat64Number v); + +// Date/time helper functions +CMSAPI void CMSEXPORT _cmsEncodeDateTimeNumber(cmsDateTimeNumber *Dest, const struct tm *Source); +CMSAPI void CMSEXPORT _cmsDecodeDateTimeNumber(const cmsDateTimeNumber *Source, struct tm *Dest); + + +//---------------------------------------------------------------------------------------------------------- + +// Plug-in foundation +#define cmsPluginMagicNumber 0x61637070 // 'acpp' + +#define cmsPluginMemHandlerSig 0x6D656D48 // 'memH' +#define cmsPluginInterpolationSig 0x696E7048 // 'inpH' +#define cmsPluginParametricCurveSig 0x70617248 // 'parH' +#define cmsPluginFormattersSig 0x66726D48 // 'frmH +#define cmsPluginTagTypeSig 0x74797048 // 'typH' +#define cmsPluginTagSig 0x74616748 // 'tagH' +#define cmsPluginRenderingIntentSig 0x696E7448 // 'intH' +#define cmsPluginMultiProcessElementSig 0x6D706548 // 'mpeH' +#define cmsPluginOptimizationSig 0x6F707448 // 'optH' + +typedef struct _cmsPluginBaseStruct { + + cmsUInt32Number Magic; // 'acpp' signature + cmsUInt32Number ExpectedVersion; // Expected version of LittleCMS + cmsUInt32Number Type; // Type of plug-in + struct _cmsPluginBaseStruct* Next; // For multiple plugin definition. NULL for end of list. + +} cmsPluginBase; + +// Maximum number of types in a plugin array +#define MAX_TYPES_IN_LCMS_PLUGIN 20 + +//---------------------------------------------------------------------------------------------------------- + +// Memory handler. Each new plug-in type replaces current behaviour +typedef struct { + + cmsPluginBase base; + + // Required + void * (* MallocPtr)(cmsContext ContextID, cmsUInt32Number size); + void (* FreePtr)(cmsContext ContextID, void *Ptr); + void * (* ReallocPtr)(cmsContext ContextID, void* Ptr, cmsUInt32Number NewSize); + + // Optional + void * (* MallocZeroPtr)(cmsContext ContextID, cmsUInt32Number size); + void * (* CallocPtr)(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size); + void * (* DupPtr)(cmsContext ContextID, const void* Org, cmsUInt32Number size); + +} cmsPluginMemHandler; + + +// ------------------------------------------------------------------------------------------------------------------ + +// Interpolation. 16 bits and floating point versions. +struct _cms_interp_struc; + +// Interpolation callbacks + +// 16 bits forward interpolation. This function performs precision-limited linear interpolation +// and is supposed to be quite fast. Implementation may be tetrahedral or trilinear, and plug-ins may +// choose to implement any other interpolation algorithm. +typedef void (* _cmsInterpFn16)(register const cmsUInt16Number Input[], + register cmsUInt16Number Output[], + register const struct _cms_interp_struc* p); + +// Floating point forward interpolation. Full precision interpolation using floats. This is not a +// time critical function. Implementation may be tetrahedral or trilinear, and plug-ins may +// choose to implement any other interpolation algorithm. +typedef void (* _cmsInterpFnFloat)(cmsFloat32Number const Input[], + cmsFloat32Number Output[], + const struct _cms_interp_struc* p); + + + +// This type holds a pointer to an interpolator that can be either 16 bits or float +typedef union { + _cmsInterpFn16 Lerp16; // Forward interpolation in 16 bits + _cmsInterpFnFloat LerpFloat; // Forward interpolation in floating point +} cmsInterpFunction; + +// Flags for interpolator selection +#define CMS_LERP_FLAGS_16BITS 0x0000 // The default +#define CMS_LERP_FLAGS_FLOAT 0x0001 // Requires different implementation +#define CMS_LERP_FLAGS_TRILINEAR 0x0100 // Hint only + + +#define MAX_INPUT_DIMENSIONS 8 + +typedef struct _cms_interp_struc { // Used on all interpolations. Supplied by lcms2 when calling the interpolation function + + cmsContext ContextID; // The calling thread + + cmsUInt32Number dwFlags; // Keep original flags + cmsUInt32Number nInputs; // != 1 only in 3D interpolation + cmsUInt32Number nOutputs; // != 1 only in 3D interpolation + + cmsUInt32Number nSamples[MAX_INPUT_DIMENSIONS]; // Valid on all kinds of tables + cmsUInt32Number Domain[MAX_INPUT_DIMENSIONS]; // Domain = nSamples - 1 + + cmsUInt32Number opta[MAX_INPUT_DIMENSIONS]; // Optimization for 3D CLUT. This is the number of nodes premultiplied for each + // dimension. For example, in 7 nodes, 7, 7^2 , 7^3, 7^4, etc. On non-regular + // Samplings may vary according of the number of nodes for each dimension. + + const void *Table; // Points to the actual interpolation table + cmsInterpFunction Interpolation; // Points to the function to do the interpolation + + } cmsInterpParams; + +// Interpolators factory +typedef cmsInterpFunction (* cmsInterpFnFactory)(cmsUInt32Number nInputChannels, cmsUInt32Number nOutputChannels, cmsUInt32Number dwFlags); + +// The plug-in +typedef struct { + cmsPluginBase base; + + // Points to a user-supplied function which implements the factory + cmsInterpFnFactory InterpolatorsFactory; + +} cmsPluginInterpolation; + +//---------------------------------------------------------------------------------------------------------- + +// Parametric curves. A negative type means same function but analytically inverted. Max. number of params is 10 + +// Evaluator callback for user-suplied parametric curves. May implement more than one type +typedef cmsFloat64Number (* cmsParametricCurveEvaluator)(cmsInt32Number Type, const cmsFloat64Number Params[10], cmsFloat64Number R); + +// Plug-in may implement an arbitrary number of parametric curves +typedef struct { + cmsPluginBase base; + + cmsUInt32Number nFunctions; // Number of supported functions + cmsUInt32Number FunctionTypes[MAX_TYPES_IN_LCMS_PLUGIN]; // The identification types + cmsUInt32Number ParameterCount[MAX_TYPES_IN_LCMS_PLUGIN]; // Number of parameters for each function + + cmsParametricCurveEvaluator Evaluator; // The evaluator + +} cmsPluginParametricCurves; +//---------------------------------------------------------------------------------------------------------- + +// Formatters. This plug-in adds new handlers, replacing them if they already exist. Formatters dealing with +// cmsFloat32Number (bps = 4) or double (bps = 0) types are requested via FormatterFloat callback. Others come across +// Formatter16 callback + +struct _cmstransform_struct; + +typedef cmsUInt8Number* (* cmsFormatter16)(register struct _cmstransform_struct* CMMcargo, + register cmsUInt16Number Values[], + register cmsUInt8Number* Buffer, + register cmsUInt32Number Stride); + +typedef cmsUInt8Number* (* cmsFormatterFloat)(struct _cmstransform_struct* CMMcargo, + cmsFloat32Number Values[], + cmsUInt8Number* Buffer, + cmsUInt32Number Stride); + +// This type holds a pointer to a formatter that can be either 16 bits or cmsFloat32Number +typedef union { + cmsFormatter16 Fmt16; + cmsFormatterFloat FmtFloat; + +} cmsFormatter; + +#define CMS_PACK_FLAGS_16BITS 0x0000 +#define CMS_PACK_FLAGS_FLOAT 0x0001 + +typedef enum { cmsFormatterInput=0, cmsFormatterOutput=1 } cmsFormatterDirection; + +typedef cmsFormatter (* cmsFormatterFactory)(cmsUInt32Number Type, // Specific type, i.e. TYPE_RGB_8 + cmsFormatterDirection Dir, + cmsUInt32Number dwFlags); // precision + +// Plug-in may implement an arbitrary number of formatters +typedef struct { + cmsPluginBase base; + cmsFormatterFactory FormattersFactory; + +} cmsPluginFormatters; + +//---------------------------------------------------------------------------------------------------------- + +// Tag type handler. Each type is free to return anything it wants, and it is up to the caller to +// know in advance what is the type contained in the tag. +typedef struct _cms_typehandler_struct { + + cmsTagTypeSignature Signature; // The signature of the type + + // Allocates and reads items + void * (* ReadPtr)(struct _cms_typehandler_struct* self, + cmsIOHANDLER* io, + cmsUInt32Number* nItems, + cmsUInt32Number SizeOfTag); + + // Writes n Items + cmsBool (* WritePtr)(struct _cms_typehandler_struct* self, + cmsIOHANDLER* io, + void* Ptr, + cmsUInt32Number nItems); + + // Duplicate an item or array of items + void* (* DupPtr)(struct _cms_typehandler_struct* self, + const void *Ptr, + cmsUInt32Number n); + + // Free all resources + void (* FreePtr)(struct _cms_typehandler_struct* self, + void *Ptr); + + // The calling thread + cmsContext ContextID; + +} cmsTagTypeHandler; + +// Each plug-in implements a single type +typedef struct { + cmsPluginBase base; + cmsTagTypeHandler Handler; + +} cmsPluginTagType; + +//---------------------------------------------------------------------------------------------------------- + +// This is the tag plugin, which identifies tags. For writing, a pointer to function is provided. +// This function should return the desired type for this tag, given the version of profile +// and the data being serialized. +typedef struct { + + cmsUInt32Number ElemCount; // If this tag needs an array, how many elements should keep + + // For reading. + cmsUInt32Number nSupportedTypes; // In how many types this tag can come (MAX_TYPES_IN_LCMS_PLUGIN maximum) + cmsTagTypeSignature SupportedTypes[MAX_TYPES_IN_LCMS_PLUGIN]; + + // For writting + cmsTagTypeSignature (* DecideType)(cmsFloat64Number ICCVersion, const void *Data); + +} cmsTagDescriptor; + +// Plug-in implements a single tag +typedef struct { + cmsPluginBase base; + + cmsTagSignature Signature; + cmsTagDescriptor Descriptor; + +} cmsPluginTag; + +//---------------------------------------------------------------------------------------------------------- + +// Custom intents. This function should join all profiles specified in the array in +// a single LUT. Any custom intent in the chain redirects to custom function. If more than +// one custom intent is found, the one located first is invoked. Usually users should use only one +// custom intent, so mixing custom intents in same multiprofile transform is not supported. + +typedef cmsPipeline* (* cmsIntentFn)( cmsContext ContextID, + cmsUInt32Number nProfiles, + cmsUInt32Number Intents[], + cmsHPROFILE hProfiles[], + cmsBool BPC[], + cmsFloat64Number AdaptationStates[], + cmsUInt32Number dwFlags); + + +// Each plug-in defines a single intent number. +typedef struct { + cmsPluginBase base; + cmsUInt32Number Intent; + cmsIntentFn Link; + char Description[256]; + +} cmsPluginRenderingIntent; + + +// The default ICC intents (perceptual, saturation, rel.col and abs.col) +CMSAPI cmsPipeline* CMSEXPORT _cmsDefaultICCintents(cmsContext ContextID, + cmsUInt32Number nProfiles, + cmsUInt32Number Intents[], + cmsHPROFILE hProfiles[], + cmsBool BPC[], + cmsFloat64Number AdaptationStates[], + cmsUInt32Number dwFlags); + + +//---------------------------------------------------------------------------------------------------------- + +// Pipelines, Multi Process Elements. + +typedef void (* _cmsStageEvalFn) (const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage* mpe); +typedef void*(* _cmsStageDupElemFn) (cmsStage* mpe); +typedef void (* _cmsStageFreeElemFn) (cmsStage* mpe); + + +// This function allocates a generic MPE +CMSAPI cmsStage* CMSEXPORT _cmsStageAllocPlaceholder(cmsContext ContextID, + cmsStageSignature Type, + cmsUInt32Number InputChannels, + cmsUInt32Number OutputChannels, + _cmsStageEvalFn EvalPtr, // Points to fn that evaluates the element (always in floating point) + _cmsStageDupElemFn DupElemPtr, // Points to a fn that duplicates the stage + _cmsStageFreeElemFn FreePtr, // Points to a fn that sets the element free + void* Data); // A generic pointer to whatever memory needed by the element +typedef struct { + cmsPluginBase base; + cmsTagTypeHandler Handler; + +} cmsPluginMultiProcessElement; + +//---------------------------------------------------------------------------------------------------------- +// Optimization. Using this plug-in, additional optimization strategies may be implemented. +// The function should return TRUE if any optimization is done on the LUT, this terminates +// the optimization search. Or FALSE if it is unable to optimize and want to give a chance +// to the rest of optimizers. + +typedef void (* _cmsOPTeval16Fn)(register const cmsUInt16Number In[], + register cmsUInt16Number Out[], + register const void* Data); + +typedef void (* _cmsOPTfreeDataFn)(cmsContext ContextID, void* Data); +typedef void* (* _cmsOPTdupDataFn)(cmsContext ContextID, const void* Data); + + +typedef cmsBool (* _cmsOPToptimizeFn)(cmsPipeline** Lut, + cmsUInt32Number Intent, + cmsUInt32Number* InputFormat, + cmsUInt32Number* OutputFormat, + cmsUInt32Number* dwFlags); + +// This function may be used to set the optional evaluator and a block of private data. If private data is being used, an optional +// duplicator and free functions should also be specified in order to duplicate the LUT construct. Use NULL to inhibit such functionality. + +CMSAPI void CMSEXPORT _cmsPipelineSetOptimizationParameters(cmsPipeline* Lut, + _cmsOPTeval16Fn Eval16, + void* PrivateData, + _cmsOPTfreeDataFn FreePrivateDataFn, + _cmsOPTdupDataFn DupPrivateDataFn); + +typedef struct { + cmsPluginBase base; + + // Optimize entry point + _cmsOPToptimizeFn OptimizePtr; + +} cmsPluginOptimization; + +//---------------------------------------------------------------------------------------------------------- + +#ifndef CMS_USE_CPP_API +# ifdef __cplusplus + } +# endif +#endif + +#define _lcms_plugin_H +#endif diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libs/lcms2/lcms2_static.lib b/gdcm/Utilities/gdcmopenjpeg-v1/libs/lcms2/lcms2_static.lib new file mode 100644 index 0000000000000000000000000000000000000000..3256a167d3a16d6533f65d01482a4a361267c63b GIT binary patch literal 1312736 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
    l% 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 literal 0 HcmV?d00001 diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libs/libtiff/libtiff.lib b/gdcm/Utilities/gdcmopenjpeg-v1/libs/libtiff/libtiff.lib new file mode 100644 index 0000000000000000000000000000000000000000..b050b61f0dec2bf7087beb8343171a9d4f0e0845 GIT binary patch literal 543310 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 */ +#define COMPRESSION_DCS 32947 /* Kodak DCS encoding */ +#define COMPRESSION_JBIG 34661 /* ISO JBIG */ +#define COMPRESSION_SGILOG 34676 /* SGI Log Luminance RLE */ +#define COMPRESSION_SGILOG24 34677 /* SGI Log 24-bit packed */ +#define COMPRESSION_JP2000 34712 /* Leadtools JPEG2000 */ +#define TIFFTAG_PHOTOMETRIC 262 /* photometric interpretation */ +#define PHOTOMETRIC_MINISWHITE 0 /* min value is white */ +#define PHOTOMETRIC_MINISBLACK 1 /* min value is black */ +#define PHOTOMETRIC_RGB 2 /* RGB color model */ +#define PHOTOMETRIC_PALETTE 3 /* color map indexed */ +#define PHOTOMETRIC_MASK 4 /* $holdout mask */ +#define PHOTOMETRIC_SEPARATED 5 /* !color separations */ +#define PHOTOMETRIC_YCBCR 6 /* !CCIR 601 */ +#define PHOTOMETRIC_CIELAB 8 /* !1976 CIE L*a*b* */ +#define PHOTOMETRIC_ICCLAB 9 /* ICC L*a*b* [Adobe TIFF Technote 4] */ +#define PHOTOMETRIC_ITULAB 10 /* ITU L*a*b* */ +#define PHOTOMETRIC_LOGL 32844 /* CIE Log2(L) */ +#define PHOTOMETRIC_LOGLUV 32845 /* CIE Log2(L) (u',v') */ +#define TIFFTAG_THRESHHOLDING 263 /* +thresholding used on data */ +#define THRESHHOLD_BILEVEL 1 /* b&w art scan */ +#define THRESHHOLD_HALFTONE 2 /* or dithered scan */ +#define THRESHHOLD_ERRORDIFFUSE 3 /* usually floyd-steinberg */ +#define TIFFTAG_CELLWIDTH 264 /* +dithering matrix width */ +#define TIFFTAG_CELLLENGTH 265 /* +dithering matrix height */ +#define TIFFTAG_FILLORDER 266 /* data order within a byte */ +#define FILLORDER_MSB2LSB 1 /* most significant -> least */ +#define FILLORDER_LSB2MSB 2 /* least significant -> most */ +#define TIFFTAG_DOCUMENTNAME 269 /* name of doc. image is from */ +#define TIFFTAG_IMAGEDESCRIPTION 270 /* info about image */ +#define TIFFTAG_MAKE 271 /* scanner manufacturer name */ +#define TIFFTAG_MODEL 272 /* scanner model name/number */ +#define TIFFTAG_STRIPOFFSETS 273 /* offsets to data strips */ +#define TIFFTAG_ORIENTATION 274 /* +image orientation */ +#define ORIENTATION_TOPLEFT 1 /* row 0 top, col 0 lhs */ +#define ORIENTATION_TOPRIGHT 2 /* row 0 top, col 0 rhs */ +#define ORIENTATION_BOTRIGHT 3 /* row 0 bottom, col 0 rhs */ +#define ORIENTATION_BOTLEFT 4 /* row 0 bottom, col 0 lhs */ +#define ORIENTATION_LEFTTOP 5 /* row 0 lhs, col 0 top */ +#define ORIENTATION_RIGHTTOP 6 /* row 0 rhs, col 0 top */ +#define ORIENTATION_RIGHTBOT 7 /* row 0 rhs, col 0 bottom */ +#define ORIENTATION_LEFTBOT 8 /* row 0 lhs, col 0 bottom */ +#define TIFFTAG_SAMPLESPERPIXEL 277 /* samples per pixel */ +#define TIFFTAG_ROWSPERSTRIP 278 /* rows per strip of data */ +#define TIFFTAG_STRIPBYTECOUNTS 279 /* bytes counts for strips */ +#define TIFFTAG_MINSAMPLEVALUE 280 /* +minimum sample value */ +#define TIFFTAG_MAXSAMPLEVALUE 281 /* +maximum sample value */ +#define TIFFTAG_XRESOLUTION 282 /* pixels/resolution in x */ +#define TIFFTAG_YRESOLUTION 283 /* pixels/resolution in y */ +#define TIFFTAG_PLANARCONFIG 284 /* storage organization */ +#define PLANARCONFIG_CONTIG 1 /* single image plane */ +#define PLANARCONFIG_SEPARATE 2 /* separate planes of data */ +#define TIFFTAG_PAGENAME 285 /* page name image is from */ +#define TIFFTAG_XPOSITION 286 /* x page offset of image lhs */ +#define TIFFTAG_YPOSITION 287 /* y page offset of image lhs */ +#define TIFFTAG_FREEOFFSETS 288 /* +byte offset to free block */ +#define TIFFTAG_FREEBYTECOUNTS 289 /* +sizes of free blocks */ +#define TIFFTAG_GRAYRESPONSEUNIT 290 /* $gray scale curve accuracy */ +#define GRAYRESPONSEUNIT_10S 1 /* tenths of a unit */ +#define GRAYRESPONSEUNIT_100S 2 /* hundredths of a unit */ +#define GRAYRESPONSEUNIT_1000S 3 /* thousandths of a unit */ +#define GRAYRESPONSEUNIT_10000S 4 /* ten-thousandths of a unit */ +#define GRAYRESPONSEUNIT_100000S 5 /* hundred-thousandths */ +#define TIFFTAG_GRAYRESPONSECURVE 291 /* $gray scale response curve */ +#define TIFFTAG_GROUP3OPTIONS 292 /* 32 flag bits */ +#define TIFFTAG_T4OPTIONS 292 /* TIFF 6.0 proper name alias */ +#define GROUP3OPT_2DENCODING 0x1 /* 2-dimensional coding */ +#define GROUP3OPT_UNCOMPRESSED 0x2 /* data not compressed */ +#define GROUP3OPT_FILLBITS 0x4 /* fill to byte boundary */ +#define TIFFTAG_GROUP4OPTIONS 293 /* 32 flag bits */ +#define TIFFTAG_T6OPTIONS 293 /* TIFF 6.0 proper name */ +#define GROUP4OPT_UNCOMPRESSED 0x2 /* data not compressed */ +#define TIFFTAG_RESOLUTIONUNIT 296 /* units of resolutions */ +#define RESUNIT_NONE 1 /* no meaningful units */ +#define RESUNIT_INCH 2 /* english */ +#define RESUNIT_CENTIMETER 3 /* metric */ +#define TIFFTAG_PAGENUMBER 297 /* page numbers of multi-page */ +#define TIFFTAG_COLORRESPONSEUNIT 300 /* $color curve accuracy */ +#define COLORRESPONSEUNIT_10S 1 /* tenths of a unit */ +#define COLORRESPONSEUNIT_100S 2 /* hundredths of a unit */ +#define COLORRESPONSEUNIT_1000S 3 /* thousandths of a unit */ +#define COLORRESPONSEUNIT_10000S 4 /* ten-thousandths of a unit */ +#define COLORRESPONSEUNIT_100000S 5 /* hundred-thousandths */ +#define TIFFTAG_TRANSFERFUNCTION 301 /* !colorimetry info */ +#define TIFFTAG_SOFTWARE 305 /* name & release */ +#define TIFFTAG_DATETIME 306 /* creation date and time */ +#define TIFFTAG_ARTIST 315 /* creator of image */ +#define TIFFTAG_HOSTCOMPUTER 316 /* machine where created */ +#define TIFFTAG_PREDICTOR 317 /* prediction scheme w/ LZW */ +#define PREDICTOR_NONE 1 /* no prediction scheme used */ +#define PREDICTOR_HORIZONTAL 2 /* horizontal differencing */ +#define PREDICTOR_FLOATINGPOINT 3 /* floating point predictor */ +#define TIFFTAG_WHITEPOINT 318 /* image white point */ +#define TIFFTAG_PRIMARYCHROMATICITIES 319 /* !primary chromaticities */ +#define TIFFTAG_COLORMAP 320 /* RGB map for pallette image */ +#define TIFFTAG_HALFTONEHINTS 321 /* !highlight+shadow info */ +#define TIFFTAG_TILEWIDTH 322 /* !tile width in pixels */ +#define TIFFTAG_TILELENGTH 323 /* !tile height in pixels */ +#define TIFFTAG_TILEOFFSETS 324 /* !offsets to data tiles */ +#define TIFFTAG_TILEBYTECOUNTS 325 /* !byte counts for tiles */ +#define TIFFTAG_BADFAXLINES 326 /* lines w/ wrong pixel count */ +#define TIFFTAG_CLEANFAXDATA 327 /* regenerated line info */ +#define CLEANFAXDATA_CLEAN 0 /* no errors detected */ +#define CLEANFAXDATA_REGENERATED 1 /* receiver regenerated lines */ +#define CLEANFAXDATA_UNCLEAN 2 /* uncorrected errors exist */ +#define TIFFTAG_CONSECUTIVEBADFAXLINES 328 /* max consecutive bad lines */ +#define TIFFTAG_SUBIFD 330 /* subimage descriptors */ +#define TIFFTAG_INKSET 332 /* !inks in separated image */ +#define INKSET_CMYK 1 /* !cyan-magenta-yellow-black color */ +#define INKSET_MULTIINK 2 /* !multi-ink or hi-fi color */ +#define TIFFTAG_INKNAMES 333 /* !ascii names of inks */ +#define TIFFTAG_NUMBEROFINKS 334 /* !number of inks */ +#define TIFFTAG_DOTRANGE 336 /* !0% and 100% dot codes */ +#define TIFFTAG_TARGETPRINTER 337 /* !separation target */ +#define TIFFTAG_EXTRASAMPLES 338 /* !info about extra samples */ +#define EXTRASAMPLE_UNSPECIFIED 0 /* !unspecified data */ +#define EXTRASAMPLE_ASSOCALPHA 1 /* !associated alpha data */ +#define EXTRASAMPLE_UNASSALPHA 2 /* !unassociated alpha data */ +#define TIFFTAG_SAMPLEFORMAT 339 /* !data sample format */ +#define SAMPLEFORMAT_UINT 1 /* !unsigned integer data */ +#define SAMPLEFORMAT_INT 2 /* !signed integer data */ +#define SAMPLEFORMAT_IEEEFP 3 /* !IEEE floating point data */ +#define SAMPLEFORMAT_VOID 4 /* !untyped data */ +#define SAMPLEFORMAT_COMPLEXINT 5 /* !complex signed int */ +#define SAMPLEFORMAT_COMPLEXIEEEFP 6 /* !complex ieee floating */ +#define TIFFTAG_SMINSAMPLEVALUE 340 /* !variable MinSampleValue */ +#define TIFFTAG_SMAXSAMPLEVALUE 341 /* !variable MaxSampleValue */ +#define TIFFTAG_CLIPPATH 343 /* %ClipPath + [Adobe TIFF technote 2] */ +#define TIFFTAG_XCLIPPATHUNITS 344 /* %XClipPathUnits + [Adobe TIFF technote 2] */ +#define TIFFTAG_YCLIPPATHUNITS 345 /* %YClipPathUnits + [Adobe TIFF technote 2] */ +#define TIFFTAG_INDEXED 346 /* %Indexed + [Adobe TIFF Technote 3] */ +#define TIFFTAG_JPEGTABLES 347 /* %JPEG table stream */ +#define TIFFTAG_OPIPROXY 351 /* %OPI Proxy [Adobe TIFF technote] */ +/* + * Tags 512-521 are obsoleted by Technical Note #2 which specifies a + * revised JPEG-in-TIFF scheme. + */ +#define TIFFTAG_JPEGPROC 512 /* !JPEG processing algorithm */ +#define JPEGPROC_BASELINE 1 /* !baseline sequential */ +#define JPEGPROC_LOSSLESS 14 /* !Huffman coded lossless */ +#define TIFFTAG_JPEGIFOFFSET 513 /* !pointer to SOI marker */ +#define TIFFTAG_JPEGIFBYTECOUNT 514 /* !JFIF stream length */ +#define TIFFTAG_JPEGRESTARTINTERVAL 515 /* !restart interval length */ +#define TIFFTAG_JPEGLOSSLESSPREDICTORS 517 /* !lossless proc predictor */ +#define TIFFTAG_JPEGPOINTTRANSFORM 518 /* !lossless point transform */ +#define TIFFTAG_JPEGQTABLES 519 /* !Q matrice offsets */ +#define TIFFTAG_JPEGDCTABLES 520 /* !DCT table offsets */ +#define TIFFTAG_JPEGACTABLES 521 /* !AC coefficient offsets */ +#define TIFFTAG_YCBCRCOEFFICIENTS 529 /* !RGB -> YCbCr transform */ +#define TIFFTAG_YCBCRSUBSAMPLING 530 /* !YCbCr subsampling factors */ +#define TIFFTAG_YCBCRPOSITIONING 531 /* !subsample positioning */ +#define YCBCRPOSITION_CENTERED 1 /* !as in PostScript Level 2 */ +#define YCBCRPOSITION_COSITED 2 /* !as in CCIR 601-1 */ +#define TIFFTAG_REFERENCEBLACKWHITE 532 /* !colorimetry info */ +#define TIFFTAG_XMLPACKET 700 /* %XML packet + [Adobe XMP Specification, + January 2004 */ +#define TIFFTAG_OPIIMAGEID 32781 /* %OPI ImageID + [Adobe TIFF technote] */ +/* tags 32952-32956 are private tags registered to Island Graphics */ +#define TIFFTAG_REFPTS 32953 /* image reference points */ +#define TIFFTAG_REGIONTACKPOINT 32954 /* region-xform tack point */ +#define TIFFTAG_REGIONWARPCORNERS 32955 /* warp quadrilateral */ +#define TIFFTAG_REGIONAFFINE 32956 /* affine transformation mat */ +/* tags 32995-32999 are private tags registered to SGI */ +#define TIFFTAG_MATTEING 32995 /* $use ExtraSamples */ +#define TIFFTAG_DATATYPE 32996 /* $use SampleFormat */ +#define TIFFTAG_IMAGEDEPTH 32997 /* z depth of image */ +#define TIFFTAG_TILEDEPTH 32998 /* z depth/data tile */ +/* tags 33300-33309 are private tags registered to Pixar */ +/* + * TIFFTAG_PIXAR_IMAGEFULLWIDTH and TIFFTAG_PIXAR_IMAGEFULLLENGTH + * are set when an image has been cropped out of a larger image. + * They reflect the size of the original uncropped image. + * The TIFFTAG_XPOSITION and TIFFTAG_YPOSITION can be used + * to determine the position of the smaller image in the larger one. + */ +#define TIFFTAG_PIXAR_IMAGEFULLWIDTH 33300 /* full image size in x */ +#define TIFFTAG_PIXAR_IMAGEFULLLENGTH 33301 /* full image size in y */ + /* Tags 33302-33306 are used to identify special image modes and data + * used by Pixar's texture formats. + */ +#define TIFFTAG_PIXAR_TEXTUREFORMAT 33302 /* texture map format */ +#define TIFFTAG_PIXAR_WRAPMODES 33303 /* s & t wrap modes */ +#define TIFFTAG_PIXAR_FOVCOT 33304 /* cotan(fov) for env. maps */ +#define TIFFTAG_PIXAR_MATRIX_WORLDTOSCREEN 33305 +#define TIFFTAG_PIXAR_MATRIX_WORLDTOCAMERA 33306 +/* tag 33405 is a private tag registered to Eastman Kodak */ +#define TIFFTAG_WRITERSERIALNUMBER 33405 /* device serial number */ +/* tag 33432 is listed in the 6.0 spec w/ unknown ownership */ +#define TIFFTAG_COPYRIGHT 33432 /* copyright string */ +/* IPTC TAG from RichTIFF specifications */ +#define TIFFTAG_RICHTIFFIPTC 33723 +/* 34016-34029 are reserved for ANSI IT8 TIFF/IT */ +#define TIFFTAG_STONITS 37439 /* Sample value to Nits */ +/* tag 34929 is a private tag registered to FedEx */ +#define TIFFTAG_FEDEX_EDR 34929 /* unknown use */ +#define TIFFTAG_INTEROPERABILITYIFD 40965 /* Pointer to Interoperability private directory */ +/* Adobe Digital Negative (DNG) format tags */ +#define TIFFTAG_DNGVERSION 50706 /* &DNG version number */ +#define TIFFTAG_DNGBACKWARDVERSION 50707 /* &DNG compatibility version */ +#define TIFFTAG_UNIQUECAMERAMODEL 50708 /* &name for the camera model */ +#define TIFFTAG_LOCALIZEDCAMERAMODEL 50709 /* &localized camera model + name */ +#define TIFFTAG_CFAPLANECOLOR 50710 /* &CFAPattern->LinearRaw space + mapping */ +#define TIFFTAG_CFALAYOUT 50711 /* &spatial layout of the CFA */ +#define TIFFTAG_LINEARIZATIONTABLE 50712 /* &lookup table description */ +#define TIFFTAG_BLACKLEVELREPEATDIM 50713 /* &repeat pattern size for + the BlackLevel tag */ +#define TIFFTAG_BLACKLEVEL 50714 /* &zero light encoding level */ +#define TIFFTAG_BLACKLEVELDELTAH 50715 /* &zero light encoding level + differences (columns) */ +#define TIFFTAG_BLACKLEVELDELTAV 50716 /* &zero light encoding level + differences (rows) */ +#define TIFFTAG_WHITELEVEL 50717 /* &fully saturated encoding + level */ +#define TIFFTAG_DEFAULTSCALE 50718 /* &default scale factors */ +#define TIFFTAG_DEFAULTCROPORIGIN 50719 /* &origin of the final image + area */ +#define TIFFTAG_DEFAULTCROPSIZE 50720 /* &size of the final image + area */ +#define TIFFTAG_COLORMATRIX1 50721 /* &XYZ->reference color space + transformation matrix 1 */ +#define TIFFTAG_COLORMATRIX2 50722 /* &XYZ->reference color space + transformation matrix 2 */ +#define TIFFTAG_CAMERACALIBRATION1 50723 /* &calibration matrix 1 */ +#define TIFFTAG_CAMERACALIBRATION2 50724 /* &calibration matrix 2 */ +#define TIFFTAG_REDUCTIONMATRIX1 50725 /* &dimensionality reduction + matrix 1 */ +#define TIFFTAG_REDUCTIONMATRIX2 50726 /* &dimensionality reduction + matrix 2 */ +#define TIFFTAG_ANALOGBALANCE 50727 /* &gain applied the stored raw + values*/ +#define TIFFTAG_ASSHOTNEUTRAL 50728 /* &selected white balance in + linear reference space */ +#define TIFFTAG_ASSHOTWHITEXY 50729 /* &selected white balance in + x-y chromaticity + coordinates */ +#define TIFFTAG_BASELINEEXPOSURE 50730 /* &how much to move the zero + point */ +#define TIFFTAG_BASELINENOISE 50731 /* &relative noise level */ +#define TIFFTAG_BASELINESHARPNESS 50732 /* &relative amount of + sharpening */ +#define TIFFTAG_BAYERGREENSPLIT 50733 /* &how closely the values of + the green pixels in the + blue/green rows track the + values of the green pixels + in the red/green rows */ +#define TIFFTAG_LINEARRESPONSELIMIT 50734 /* &non-linear encoding range */ +#define TIFFTAG_CAMERASERIALNUMBER 50735 /* &camera's serial number */ +#define TIFFTAG_LENSINFO 50736 /* info about the lens */ +#define TIFFTAG_CHROMABLURRADIUS 50737 /* &chroma blur radius */ +#define TIFFTAG_ANTIALIASSTRENGTH 50738 /* &relative strength of the + camera's anti-alias filter */ +#define TIFFTAG_SHADOWSCALE 50739 /* &used by Adobe Camera Raw */ +#define TIFFTAG_DNGPRIVATEDATA 50740 /* &manufacturer's private data */ +#define TIFFTAG_MAKERNOTESAFETY 50741 /* &whether the EXIF MakerNote + tag is safe to preserve + along with the rest of the + EXIF data */ +#define TIFFTAG_CALIBRATIONILLUMINANT1 50778 /* &illuminant 1 */ +#define TIFFTAG_CALIBRATIONILLUMINANT2 50779 /* &illuminant 2 */ +#define TIFFTAG_BESTQUALITYSCALE 50780 /* &best quality multiplier */ +#define TIFFTAG_RAWDATAUNIQUEID 50781 /* &unique identifier for + the raw image data */ +#define TIFFTAG_ORIGINALRAWFILENAME 50827 /* &file name of the original + raw file */ +#define TIFFTAG_ORIGINALRAWFILEDATA 50828 /* &contents of the original + raw file */ +#define TIFFTAG_ACTIVEAREA 50829 /* &active (non-masked) pixels + of the sensor */ +#define TIFFTAG_MASKEDAREAS 50830 /* &list of coordinates + of fully masked pixels */ +#define TIFFTAG_ASSHOTICCPROFILE 50831 /* &these two tags used to */ +#define TIFFTAG_ASSHOTPREPROFILEMATRIX 50832 /* map cameras's color space + into ICC profile space */ +#define TIFFTAG_CURRENTICCPROFILE 50833 /* & */ +#define TIFFTAG_CURRENTPREPROFILEMATRIX 50834 /* & */ +/* tag 65535 is an undefined tag used by Eastman Kodak */ +#define TIFFTAG_DCSHUESHIFTVALUES 65535 /* hue shift correction data */ + +/* + * The following are ``pseudo tags'' that can be used to control + * codec-specific functionality. These tags are not written to file. + * Note that these values start at 0xffff+1 so that they'll never + * collide with Aldus-assigned tags. + * + * If you want your private pseudo tags ``registered'' (i.e. added to + * this file), please post a bug report via the tracking system at + * http://www.remotesensing.org/libtiff/bugs.html with the appropriate + * C definitions to add. + */ +#define TIFFTAG_FAXMODE 65536 /* Group 3/4 format control */ +#define FAXMODE_CLASSIC 0x0000 /* default, include RTC */ +#define FAXMODE_NORTC 0x0001 /* no RTC at end of data */ +#define FAXMODE_NOEOL 0x0002 /* no EOL code at end of row */ +#define FAXMODE_BYTEALIGN 0x0004 /* byte align row */ +#define FAXMODE_WORDALIGN 0x0008 /* word align row */ +#define FAXMODE_CLASSF FAXMODE_NORTC /* TIFF Class F */ +#define TIFFTAG_JPEGQUALITY 65537 /* Compression quality level */ +/* Note: quality level is on the IJG 0-100 scale. Default value is 75 */ +#define TIFFTAG_JPEGCOLORMODE 65538 /* Auto RGB<=>YCbCr convert? */ +#define JPEGCOLORMODE_RAW 0x0000 /* no conversion (default) */ +#define JPEGCOLORMODE_RGB 0x0001 /* do auto conversion */ +#define TIFFTAG_JPEGTABLESMODE 65539 /* What to put in JPEGTables */ +#define JPEGTABLESMODE_QUANT 0x0001 /* include quantization tbls */ +#define JPEGTABLESMODE_HUFF 0x0002 /* include Huffman tbls */ +/* Note: default is JPEGTABLESMODE_QUANT | JPEGTABLESMODE_HUFF */ +#define TIFFTAG_FAXFILLFUNC 65540 /* G3/G4 fill function */ +#define TIFFTAG_PIXARLOGDATAFMT 65549 /* PixarLogCodec I/O data sz */ +#define PIXARLOGDATAFMT_8BIT 0 /* regular u_char samples */ +#define PIXARLOGDATAFMT_8BITABGR 1 /* ABGR-order u_chars */ +#define PIXARLOGDATAFMT_11BITLOG 2 /* 11-bit log-encoded (raw) */ +#define PIXARLOGDATAFMT_12BITPICIO 3 /* as per PICIO (1.0==2048) */ +#define PIXARLOGDATAFMT_16BIT 4 /* signed short samples */ +#define PIXARLOGDATAFMT_FLOAT 5 /* IEEE float samples */ +/* 65550-65556 are allocated to Oceana Matrix */ +#define TIFFTAG_DCSIMAGERTYPE 65550 /* imager model & filter */ +#define DCSIMAGERMODEL_M3 0 /* M3 chip (1280 x 1024) */ +#define DCSIMAGERMODEL_M5 1 /* M5 chip (1536 x 1024) */ +#define DCSIMAGERMODEL_M6 2 /* M6 chip (3072 x 2048) */ +#define DCSIMAGERFILTER_IR 0 /* infrared filter */ +#define DCSIMAGERFILTER_MONO 1 /* monochrome filter */ +#define DCSIMAGERFILTER_CFA 2 /* color filter array */ +#define DCSIMAGERFILTER_OTHER 3 /* other filter */ +#define TIFFTAG_DCSINTERPMODE 65551 /* interpolation mode */ +#define DCSINTERPMODE_NORMAL 0x0 /* whole image, default */ +#define DCSINTERPMODE_PREVIEW 0x1 /* preview of image (384x256) */ +#define TIFFTAG_DCSBALANCEARRAY 65552 /* color balance values */ +#define TIFFTAG_DCSCORRECTMATRIX 65553 /* color correction values */ +#define TIFFTAG_DCSGAMMA 65554 /* gamma value */ +#define TIFFTAG_DCSTOESHOULDERPTS 65555 /* toe & shoulder points */ +#define TIFFTAG_DCSCALIBRATIONFD 65556 /* calibration file desc */ +/* Note: quality level is on the ZLIB 1-9 scale. Default value is -1 */ +#define TIFFTAG_ZIPQUALITY 65557 /* compression quality level */ +#define TIFFTAG_PIXARLOGQUALITY 65558 /* PixarLog uses same scale */ +/* 65559 is allocated to Oceana Matrix */ +#define TIFFTAG_DCSCLIPRECTANGLE 65559 /* area of image to acquire */ +#define TIFFTAG_SGILOGDATAFMT 65560 /* SGILog user data format */ +#define SGILOGDATAFMT_FLOAT 0 /* IEEE float samples */ +#define SGILOGDATAFMT_16BIT 1 /* 16-bit samples */ +#define SGILOGDATAFMT_RAW 2 /* uninterpreted data */ +#define SGILOGDATAFMT_8BIT 3 /* 8-bit RGB monitor values */ +#define TIFFTAG_SGILOGENCODE 65561 /* SGILog data encoding control*/ +#define SGILOGENCODE_NODITHER 0 /* do not dither encoded values*/ +#define SGILOGENCODE_RANDITHER 1 /* randomly dither encd values */ + +/* + * EXIF tags + */ +#define EXIFTAG_EXPOSURETIME 33434 /* Exposure time */ +#define EXIFTAG_FNUMBER 33437 /* F number */ +#define EXIFTAG_EXPOSUREPROGRAM 34850 /* Exposure program */ +#define EXIFTAG_SPECTRALSENSITIVITY 34852 /* Spectral sensitivity */ +#define EXIFTAG_ISOSPEEDRATINGS 34855 /* ISO speed rating */ +#define EXIFTAG_OECF 34856 /* Optoelectric conversion + factor */ +#define EXIFTAG_EXIFVERSION 36864 /* Exif version */ +#define EXIFTAG_DATETIMEORIGINAL 36867 /* Date and time of original + data generation */ +#define EXIFTAG_DATETIMEDIGITIZED 36868 /* Date and time of digital + data generation */ +#define EXIFTAG_COMPONENTSCONFIGURATION 37121 /* Meaning of each component */ +#define EXIFTAG_COMPRESSEDBITSPERPIXEL 37122 /* Image compression mode */ +#define EXIFTAG_SHUTTERSPEEDVALUE 37377 /* Shutter speed */ +#define EXIFTAG_APERTUREVALUE 37378 /* Aperture */ +#define EXIFTAG_BRIGHTNESSVALUE 37379 /* Brightness */ +#define EXIFTAG_EXPOSUREBIASVALUE 37380 /* Exposure bias */ +#define EXIFTAG_MAXAPERTUREVALUE 37381 /* Maximum lens aperture */ +#define EXIFTAG_SUBJECTDISTANCE 37382 /* Subject distance */ +#define EXIFTAG_METERINGMODE 37383 /* Metering mode */ +#define EXIFTAG_LIGHTSOURCE 37384 /* Light source */ +#define EXIFTAG_FLASH 37385 /* Flash */ +#define EXIFTAG_FOCALLENGTH 37386 /* Lens focal length */ +#define EXIFTAG_SUBJECTAREA 37396 /* Subject area */ +#define EXIFTAG_MAKERNOTE 37500 /* Manufacturer notes */ +#define EXIFTAG_USERCOMMENT 37510 /* User comments */ +#define EXIFTAG_SUBSECTIME 37520 /* DateTime subseconds */ +#define EXIFTAG_SUBSECTIMEORIGINAL 37521 /* DateTimeOriginal subseconds */ +#define EXIFTAG_SUBSECTIMEDIGITIZED 37522 /* DateTimeDigitized subseconds */ +#define EXIFTAG_FLASHPIXVERSION 40960 /* Supported Flashpix version */ +#define EXIFTAG_COLORSPACE 40961 /* Color space information */ +#define EXIFTAG_PIXELXDIMENSION 40962 /* Valid image width */ +#define EXIFTAG_PIXELYDIMENSION 40963 /* Valid image height */ +#define EXIFTAG_RELATEDSOUNDFILE 40964 /* Related audio file */ +#define EXIFTAG_FLASHENERGY 41483 /* Flash energy */ +#define EXIFTAG_SPATIALFREQUENCYRESPONSE 41484 /* Spatial frequency response */ +#define EXIFTAG_FOCALPLANEXRESOLUTION 41486 /* Focal plane X resolution */ +#define EXIFTAG_FOCALPLANEYRESOLUTION 41487 /* Focal plane Y resolution */ +#define EXIFTAG_FOCALPLANERESOLUTIONUNIT 41488 /* Focal plane resolution unit */ +#define EXIFTAG_SUBJECTLOCATION 41492 /* Subject location */ +#define EXIFTAG_EXPOSUREINDEX 41493 /* Exposure index */ +#define EXIFTAG_SENSINGMETHOD 41495 /* Sensing method */ +#define EXIFTAG_FILESOURCE 41728 /* File source */ +#define EXIFTAG_SCENETYPE 41729 /* Scene type */ +#define EXIFTAG_CFAPATTERN 41730 /* CFA pattern */ +#define EXIFTAG_CUSTOMRENDERED 41985 /* Custom image processing */ +#define EXIFTAG_EXPOSUREMODE 41986 /* Exposure mode */ +#define EXIFTAG_WHITEBALANCE 41987 /* White balance */ +#define EXIFTAG_DIGITALZOOMRATIO 41988 /* Digital zoom ratio */ +#define EXIFTAG_FOCALLENGTHIN35MMFILM 41989 /* Focal length in 35 mm film */ +#define EXIFTAG_SCENECAPTURETYPE 41990 /* Scene capture type */ +#define EXIFTAG_GAINCONTROL 41991 /* Gain control */ +#define EXIFTAG_CONTRAST 41992 /* Contrast */ +#define EXIFTAG_SATURATION 41993 /* Saturation */ +#define EXIFTAG_SHARPNESS 41994 /* Sharpness */ +#define EXIFTAG_DEVICESETTINGDESCRIPTION 41995 /* Device settings description */ +#define EXIFTAG_SUBJECTDISTANCERANGE 41996 /* Subject distance range */ +#define EXIFTAG_GAINCONTROL 41991 /* Gain control */ +#define EXIFTAG_GAINCONTROL 41991 /* Gain control */ +#define EXIFTAG_IMAGEUNIQUEID 42016 /* Unique image ID */ + +#endif /* _TIFF_ */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libs/libtiff/tiffconf.h b/gdcm/Utilities/gdcmopenjpeg-v1/libs/libtiff/tiffconf.h new file mode 100644 index 0000000..7e3a710 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libs/libtiff/tiffconf.h @@ -0,0 +1,128 @@ +/* libtiff/tiffconf.h. Generated from tiffconf.h.in by configure. */ +/* + Configuration defines for installed libtiff. + This file maintained for backward compatibility. Do not use definitions + from this file in your programs. +*/ + +#ifndef _TIFFCONF_ +#define _TIFFCONF_ + +/* Signed 16-bit type */ +#define TIFF_INT16_T signed short + +/* Signed 32-bit type */ +#define TIFF_INT32_T signed int + +/* Signed 64-bit type */ +#define TIFF_INT64_T signed long long + +/* Signed 8-bit type */ +#define TIFF_INT8_T signed char + +/* Unsigned 16-bit type */ +#define TIFF_UINT16_T unsigned short + +/* Unsigned 32-bit type */ +#define TIFF_UINT32_T unsigned int + +/* Unsigned 64-bit type */ +#define TIFF_UINT64_T unsigned long long + +/* Unsigned 8-bit type */ +#define TIFF_UINT8_T unsigned char + +/* Signed size type */ +#define TIFF_SSIZE_T signed long + +/* Pointer difference type */ +#define TIFF_PTRDIFF_T ptrdiff_t + +/* Define to 1 if the system has the type `int16'. */ +/* #undef HAVE_INT16 */ + +/* Define to 1 if the system has the type `int32'. */ +/* #undef HAVE_INT32 */ + +/* Define to 1 if the system has the type `int8'. */ +/* #undef HAVE_INT8 */ + +/* Compatibility stuff. */ + +/* Define as 0 or 1 according to the floating point format suported by the + machine */ +#define HAVE_IEEEFP 1 + +/* Set the native cpu bit order (FILLORDER_LSB2MSB or FILLORDER_MSB2LSB) */ +#define HOST_FILLORDER FILLORDER_LSB2MSB + +/* Native cpu byte order: 1 if big-endian (Motorola) or 0 if little-endian + (Intel) */ +#define HOST_BIGENDIAN 0 + +/* Support CCITT Group 3 & 4 algorithms */ +#define CCITT_SUPPORT 1 + +/* Support JPEG compression (requires IJG JPEG library) */ +#define JPEG_SUPPORT 1 + +/* Support JBIG compression (requires JBIG-KIT library) */ +#define JBIG_SUPPORT 1 + +/* Support LogLuv high dynamic range encoding */ +#define LOGLUV_SUPPORT 1 + +/* Support LZW algorithm */ +#define LZW_SUPPORT 1 + +/* Support NeXT 2-bit RLE algorithm */ +#define NEXT_SUPPORT 1 + +/* Support Old JPEG compresson (read contrib/ojpeg/README first! Compilation + fails with unpatched IJG JPEG library) */ +#define OJPEG_SUPPORT 1 + +/* Support Macintosh PackBits algorithm */ +#define PACKBITS_SUPPORT 1 + +/* Support Pixar log-format algorithm (requires Zlib) */ +#define PIXARLOG_SUPPORT 1 + +/* Support ThunderScan 4-bit RLE algorithm */ +#define THUNDER_SUPPORT 1 + +/* Support Deflate compression */ +#define ZIP_SUPPORT 1 + +/* Support strip chopping (whether or not to convert single-strip uncompressed + images to mutiple strips of ~8Kb to reduce memory usage) */ +#define STRIPCHOP_DEFAULT TIFF_STRIPCHOP + +/* Enable SubIFD tag (330) support */ +#define SUBIFD_SUPPORT 1 + +/* Treat extra sample as alpha (default enabled). The RGBA interface will + treat a fourth sample with no EXTRASAMPLE_ value as being ASSOCALPHA. Many + packages produce RGBA files but don't mark the alpha properly. */ +#define DEFAULT_EXTRASAMPLE_AS_ALPHA 1 + +/* Pick up YCbCr subsampling info from the JPEG data stream to support files + lacking the tag (default enabled). */ +#define CHECK_JPEG_YCBCR_SUBSAMPLING 1 + +/* Support MS MDI magic number files as TIFF */ +#define MDI_SUPPORT 1 + +/* + * Feature support definitions. + * XXX: These macros are obsoleted. Don't use them in your apps! + * Macros stays here for backward compatibility and should be always defined. + */ +#define COLORIMETRY_SUPPORT +#define YCBCR_SUPPORT +#define CMYK_SUPPORT +#define ICC_SUPPORT +#define PHOTOSHOP_SUPPORT +#define IPTC_SUPPORT + +#endif /* _TIFFCONF_ */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libs/libtiff/tiffio.h b/gdcm/Utilities/gdcmopenjpeg-v1/libs/libtiff/tiffio.h new file mode 100644 index 0000000..af6082f --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libs/libtiff/tiffio.h @@ -0,0 +1,550 @@ +/* $Id: tiffio.h,v 1.86 2010-03-10 18:56:49 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef _TIFFIO_ +#define _TIFFIO_ + +/* + * TIFF I/O Library Definitions. + */ +#include "tiff.h" +#include "tiffvers.h" + +/* + * TIFF is defined as an incomplete type to hide the + * library's internal data structures from clients. + */ +typedef struct tiff TIFF; + +/* + * The following typedefs define the intrinsic size of + * data types used in the *exported* interfaces. These + * definitions depend on the proper definition of types + * in tiff.h. Note also that the varargs interface used + * to pass tag types and values uses the types defined in + * tiff.h directly. + * + * NB: ttag_t is unsigned int and not unsigned short because + * ANSI C requires that the type before the ellipsis be a + * promoted type (i.e. one of int, unsigned int, pointer, + * or double) and because we defined pseudo-tags that are + * outside the range of legal Aldus-assigned tags. + * NB: tsize_t is int32 and not uint32 because some functions + * return -1. + * NB: toff_t is not off_t for many reasons; TIFFs max out at + * 32-bit file offsets, and BigTIFF maxes out at 64-bit + * offsets being the most important, and to ensure use of + * a consistently unsigned type across architectures. + * Prior to libtiff 4.0, this was an unsigned 32 bit type. + */ +/* + * this is the machine addressing size type, only it's signed, so make it + * int32 on 32bit machines, int64 on 64bit machines + */ +typedef TIFF_SSIZE_T tmsize_t; +typedef uint64 toff_t; /* file offset */ +/* the following are deprecated and should be replaced by their defining + counterparts */ +typedef uint32 ttag_t; /* directory tag */ +typedef uint16 tdir_t; /* directory index */ +typedef uint16 tsample_t; /* sample number */ +typedef uint32 tstrile_t; /* strip or tile number */ +typedef tstrile_t tstrip_t; /* strip number */ +typedef tstrile_t ttile_t; /* tile number */ +typedef tmsize_t tsize_t; /* i/o size in bytes */ +typedef void* tdata_t; /* image data ref */ + +#if !defined(__WIN32__) && (defined(_WIN32) || defined(WIN32)) +#define __WIN32__ +#endif + +/* + * On windows you should define USE_WIN32_FILEIO if you are using tif_win32.c + * or AVOID_WIN32_FILEIO if you are using something else (like tif_unix.c). + * + * By default tif_unix.c is assumed. + */ + +#if defined(_WINDOWS) || defined(__WIN32__) || defined(_Windows) +# if !defined(__CYGWIN) && !defined(AVOID_WIN32_FILEIO) && !defined(USE_WIN32_FILEIO) +# define AVOID_WIN32_FILEIO +# endif +#endif + +#if defined(USE_WIN32_FILEIO) +# define VC_EXTRALEAN +# include +# ifdef __WIN32__ +DECLARE_HANDLE(thandle_t); /* Win32 file handle */ +# else +typedef HFILE thandle_t; /* client data handle */ +# endif /* __WIN32__ */ +#else +typedef void* thandle_t; /* client data handle */ +#endif /* USE_WIN32_FILEIO */ + +/* + * Flags to pass to TIFFPrintDirectory to control + * printing of data structures that are potentially + * very large. Bit-or these flags to enable printing + * multiple items. + */ +#define TIFFPRINT_NONE 0x0 /* no extra info */ +#define TIFFPRINT_STRIPS 0x1 /* strips/tiles info */ +#define TIFFPRINT_CURVES 0x2 /* color/gray response curves */ +#define TIFFPRINT_COLORMAP 0x4 /* colormap */ +#define TIFFPRINT_JPEGQTABLES 0x100 /* JPEG Q matrices */ +#define TIFFPRINT_JPEGACTABLES 0x200 /* JPEG AC tables */ +#define TIFFPRINT_JPEGDCTABLES 0x200 /* JPEG DC tables */ + +/* + * Colour conversion stuff + */ + +/* reference white */ +#define D65_X0 (95.0470F) +#define D65_Y0 (100.0F) +#define D65_Z0 (108.8827F) + +#define D50_X0 (96.4250F) +#define D50_Y0 (100.0F) +#define D50_Z0 (82.4680F) + +/* Structure for holding information about a display device. */ + +typedef unsigned char TIFFRGBValue; /* 8-bit samples */ + +typedef struct { + float d_mat[3][3]; /* XYZ -> luminance matrix */ + float d_YCR; /* Light o/p for reference white */ + float d_YCG; + float d_YCB; + uint32 d_Vrwr; /* Pixel values for ref. white */ + uint32 d_Vrwg; + uint32 d_Vrwb; + float d_Y0R; /* Residual light for black pixel */ + float d_Y0G; + float d_Y0B; + float d_gammaR; /* Gamma values for the three guns */ + float d_gammaG; + float d_gammaB; +} TIFFDisplay; + +typedef struct { /* YCbCr->RGB support */ + TIFFRGBValue* clamptab; /* range clamping table */ + int* Cr_r_tab; + int* Cb_b_tab; + int32* Cr_g_tab; + int32* Cb_g_tab; + int32* Y_tab; +} TIFFYCbCrToRGB; + +typedef struct { /* CIE Lab 1976->RGB support */ + int range; /* Size of conversion table */ +#define CIELABTORGB_TABLE_RANGE 1500 + float rstep, gstep, bstep; + float X0, Y0, Z0; /* Reference white point */ + TIFFDisplay display; + float Yr2r[CIELABTORGB_TABLE_RANGE + 1]; /* Conversion of Yr to r */ + float Yg2g[CIELABTORGB_TABLE_RANGE + 1]; /* Conversion of Yg to g */ + float Yb2b[CIELABTORGB_TABLE_RANGE + 1]; /* Conversion of Yb to b */ +} TIFFCIELabToRGB; + +/* + * RGBA-style image support. + */ +typedef struct _TIFFRGBAImage TIFFRGBAImage; +/* + * The image reading and conversion routines invoke + * ``put routines'' to copy/image/whatever tiles of + * raw image data. A default set of routines are + * provided to convert/copy raw image data to 8-bit + * packed ABGR format rasters. Applications can supply + * alternate routines that unpack the data into a + * different format or, for example, unpack the data + * and draw the unpacked raster on the display. + */ +typedef void (*tileContigRoutine) + (TIFFRGBAImage*, uint32*, uint32, uint32, uint32, uint32, int32, int32, + unsigned char*); +typedef void (*tileSeparateRoutine) + (TIFFRGBAImage*, uint32*, uint32, uint32, uint32, uint32, int32, int32, + unsigned char*, unsigned char*, unsigned char*, unsigned char*); +/* + * RGBA-reader state. + */ +struct _TIFFRGBAImage { + TIFF* tif; /* image handle */ + int stoponerr; /* stop on read error */ + int isContig; /* data is packed/separate */ + int alpha; /* type of alpha data present */ + uint32 width; /* image width */ + uint32 height; /* image height */ + uint16 bitspersample; /* image bits/sample */ + uint16 samplesperpixel; /* image samples/pixel */ + uint16 orientation; /* image orientation */ + uint16 req_orientation; /* requested orientation */ + uint16 photometric; /* image photometric interp */ + uint16* redcmap; /* colormap pallete */ + uint16* greencmap; + uint16* bluecmap; + /* get image data routine */ + int (*get)(TIFFRGBAImage*, uint32*, uint32, uint32); + /* put decoded strip/tile */ + union { + void (*any)(TIFFRGBAImage*); + tileContigRoutine contig; + tileSeparateRoutine separate; + } put; + TIFFRGBValue* Map; /* sample mapping array */ + uint32** BWmap; /* black&white map */ + uint32** PALmap; /* palette image map */ + TIFFYCbCrToRGB* ycbcr; /* YCbCr conversion state */ + TIFFCIELabToRGB* cielab; /* CIE L*a*b conversion state */ + + uint8* UaToAa; /* Unassociated alpha to associated alpha convertion LUT */ + uint8* Bitdepth16To8; /* LUT for conversion from 16bit to 8bit values */ + + int row_offset; + int col_offset; +}; + +/* + * Macros for extracting components from the + * packed ABGR form returned by TIFFReadRGBAImage. + */ +#define TIFFGetR(abgr) ((abgr) & 0xff) +#define TIFFGetG(abgr) (((abgr) >> 8) & 0xff) +#define TIFFGetB(abgr) (((abgr) >> 16) & 0xff) +#define TIFFGetA(abgr) (((abgr) >> 24) & 0xff) + +/* + * A CODEC is a software package that implements decoding, + * encoding, or decoding+encoding of a compression algorithm. + * The library provides a collection of builtin codecs. + * More codecs may be registered through calls to the library + * and/or the builtin implementations may be overridden. + */ +typedef int (*TIFFInitMethod)(TIFF*, int); +typedef struct { + char* name; + uint16 scheme; + TIFFInitMethod init; +} TIFFCodec; + +#include +#include + +/* share internal LogLuv conversion routines? */ +#ifndef LOGLUV_PUBLIC +#define LOGLUV_PUBLIC 1 +#endif + +#if !defined(__GNUC__) && !defined(__attribute__) +# define __attribute__(x) /*nothing*/ +#endif + +#if defined(c_plusplus) || defined(__cplusplus) +extern "C" { +#endif +typedef void (*TIFFErrorHandler)(const char*, const char*, va_list); +typedef void (*TIFFErrorHandlerExt)(thandle_t, const char*, const char*, va_list); +typedef tmsize_t (*TIFFReadWriteProc)(thandle_t, void*, tmsize_t); +typedef toff_t (*TIFFSeekProc)(thandle_t, toff_t, int); +typedef int (*TIFFCloseProc)(thandle_t); +typedef toff_t (*TIFFSizeProc)(thandle_t); +typedef int (*TIFFMapFileProc)(thandle_t, void** base, toff_t* size); +typedef void (*TIFFUnmapFileProc)(thandle_t, void* base, toff_t size); +typedef void (*TIFFExtendProc)(TIFF*); + +extern const char* TIFFGetVersion(void); + +extern const TIFFCodec* TIFFFindCODEC(uint16); +extern TIFFCodec* TIFFRegisterCODEC(uint16, const char*, TIFFInitMethod); +extern void TIFFUnRegisterCODEC(TIFFCodec*); +extern int TIFFIsCODECConfigured(uint16); +extern TIFFCodec* TIFFGetConfiguredCODECs(void); + +/* + * Auxiliary functions. + */ + +extern void* _TIFFmalloc(tmsize_t s); +extern void* _TIFFrealloc(void* p, tmsize_t s); +extern void _TIFFmemset(void* p, int v, tmsize_t c); +extern void _TIFFmemcpy(void* d, const void* s, tmsize_t c); +extern int _TIFFmemcmp(const void* p1, const void* p2, tmsize_t c); +extern void _TIFFfree(void* p); + +/* +** Stuff, related to tag handling and creating custom tags. +*/ +extern int TIFFGetTagListCount( TIFF * ); +extern uint32 TIFFGetTagListEntry( TIFF *, int tag_index ); + +#define TIFF_ANY TIFF_NOTYPE /* for field descriptor searching */ +#define TIFF_VARIABLE -1 /* marker for variable length tags */ +#define TIFF_SPP -2 /* marker for SamplesPerPixel tags */ +#define TIFF_VARIABLE2 -3 /* marker for uint32 var-length tags */ + +#define FIELD_CUSTOM 65 + +typedef struct _TIFFField TIFFField; +typedef struct _TIFFFieldArray TIFFFieldArray; + +extern const TIFFField* TIFFFindField(TIFF *, uint32, TIFFDataType); +extern const TIFFField* TIFFFieldWithTag(TIFF*, uint32); +extern const TIFFField* TIFFFieldWithName(TIFF*, const char *); + +typedef int (*TIFFVSetMethod)(TIFF*, uint32, va_list); +typedef int (*TIFFVGetMethod)(TIFF*, uint32, va_list); +typedef void (*TIFFPrintMethod)(TIFF*, FILE*, long); + +typedef struct { + TIFFVSetMethod vsetfield; /* tag set routine */ + TIFFVGetMethod vgetfield; /* tag get routine */ + TIFFPrintMethod printdir; /* directory print routine */ +} TIFFTagMethods; + +extern TIFFTagMethods *TIFFAccessTagMethods(TIFF *); +extern void *TIFFGetClientInfo(TIFF *, const char *); +extern void TIFFSetClientInfo(TIFF *, void *, const char *); + +extern void TIFFCleanup(TIFF* tif); +extern void TIFFClose(TIFF* tif); +extern int TIFFFlush(TIFF* tif); +extern int TIFFFlushData(TIFF* tif); +extern int TIFFGetField(TIFF* tif, uint32 tag, ...); +extern int TIFFVGetField(TIFF* tif, uint32 tag, va_list ap); +extern int TIFFGetFieldDefaulted(TIFF* tif, uint32 tag, ...); +extern int TIFFVGetFieldDefaulted(TIFF* tif, uint32 tag, va_list ap); +extern int TIFFReadDirectory(TIFF* tif); +extern int TIFFReadCustomDirectory(TIFF* tif, toff_t diroff, const TIFFFieldArray* infoarray); +extern int TIFFReadEXIFDirectory(TIFF* tif, toff_t diroff); +extern uint64 TIFFScanlineSize64(TIFF* tif); +extern tmsize_t TIFFScanlineSize(TIFF* tif); +extern uint64 TIFFRasterScanlineSize64(TIFF* tif); +extern tmsize_t TIFFRasterScanlineSize(TIFF* tif); +extern uint64 TIFFStripSize64(TIFF* tif); +extern tmsize_t TIFFStripSize(TIFF* tif); +extern uint64 TIFFRawStripSize64(TIFF* tif, uint32 strip); +extern tmsize_t TIFFRawStripSize(TIFF* tif, uint32 strip); +extern uint64 TIFFVStripSize64(TIFF* tif, uint32 nrows); +extern tmsize_t TIFFVStripSize(TIFF* tif, uint32 nrows); +extern uint64 TIFFTileRowSize64(TIFF* tif); +extern tmsize_t TIFFTileRowSize(TIFF* tif); +extern uint64 TIFFTileSize64(TIFF* tif); +extern tmsize_t TIFFTileSize(TIFF* tif); +extern uint64 TIFFVTileSize64(TIFF* tif, uint32 nrows); +extern tmsize_t TIFFVTileSize(TIFF* tif, uint32 nrows); +extern uint32 TIFFDefaultStripSize(TIFF* tif, uint32 request); +extern void TIFFDefaultTileSize(TIFF*, uint32*, uint32*); +extern int TIFFFileno(TIFF*); +extern int TIFFSetFileno(TIFF*, int); +extern thandle_t TIFFClientdata(TIFF*); +extern thandle_t TIFFSetClientdata(TIFF*, thandle_t); +extern int TIFFGetMode(TIFF*); +extern int TIFFSetMode(TIFF*, int); +extern int TIFFIsTiled(TIFF*); +extern int TIFFIsByteSwapped(TIFF*); +extern int TIFFIsUpSampled(TIFF*); +extern int TIFFIsMSB2LSB(TIFF*); +extern int TIFFIsBigEndian(TIFF*); +extern TIFFReadWriteProc TIFFGetReadProc(TIFF*); +extern TIFFReadWriteProc TIFFGetWriteProc(TIFF*); +extern TIFFSeekProc TIFFGetSeekProc(TIFF*); +extern TIFFCloseProc TIFFGetCloseProc(TIFF*); +extern TIFFSizeProc TIFFGetSizeProc(TIFF*); +extern TIFFMapFileProc TIFFGetMapFileProc(TIFF*); +extern TIFFUnmapFileProc TIFFGetUnmapFileProc(TIFF*); +extern uint32 TIFFCurrentRow(TIFF*); +extern uint16 TIFFCurrentDirectory(TIFF*); +extern uint16 TIFFNumberOfDirectories(TIFF*); +extern uint64 TIFFCurrentDirOffset(TIFF*); +extern uint32 TIFFCurrentStrip(TIFF*); +extern uint32 TIFFCurrentTile(TIFF* tif); +extern int TIFFReadBufferSetup(TIFF* tif, void* bp, tmsize_t size); +extern int TIFFWriteBufferSetup(TIFF* tif, void* bp, tmsize_t size); +extern int TIFFSetupStrips(TIFF *); +extern int TIFFWriteCheck(TIFF*, int, const char *); +extern void TIFFFreeDirectory(TIFF*); +extern int TIFFCreateDirectory(TIFF*); +extern int TIFFLastDirectory(TIFF*); +extern int TIFFSetDirectory(TIFF*, uint16); +extern int TIFFSetSubDirectory(TIFF*, uint64); +extern int TIFFUnlinkDirectory(TIFF*, uint16); +extern int TIFFSetField(TIFF*, uint32, ...); +extern int TIFFVSetField(TIFF*, uint32, va_list); +extern int TIFFUnsetField(TIFF*, uint32); +extern int TIFFWriteDirectory(TIFF *); +extern int TIFFCheckpointDirectory(TIFF *); +extern int TIFFRewriteDirectory(TIFF *); + +#if defined(c_plusplus) || defined(__cplusplus) +extern void TIFFPrintDirectory(TIFF*, FILE*, long = 0); +extern int TIFFReadScanline(TIFF* tif, void* buf, uint32 row, uint16 sample = 0); +extern int TIFFWriteScanline(TIFF* tif, void* buf, uint32 row, uint16 sample = 0); +extern int TIFFReadRGBAImage(TIFF*, uint32, uint32, uint32*, int = 0); +extern int TIFFReadRGBAImageOriented(TIFF*, uint32, uint32, uint32*, + int = ORIENTATION_BOTLEFT, int = 0); +#else +extern void TIFFPrintDirectory(TIFF*, FILE*, long); +extern int TIFFReadScanline(TIFF* tif, void* buf, uint32 row, uint16 sample); +extern int TIFFWriteScanline(TIFF* tif, void* buf, uint32 row, uint16 sample); +extern int TIFFReadRGBAImage(TIFF*, uint32, uint32, uint32*, int); +extern int TIFFReadRGBAImageOriented(TIFF*, uint32, uint32, uint32*, int, int); +#endif + +extern int TIFFReadRGBAStrip(TIFF*, uint32, uint32 * ); +extern int TIFFReadRGBATile(TIFF*, uint32, uint32, uint32 * ); +extern int TIFFRGBAImageOK(TIFF*, char [1024]); +extern int TIFFRGBAImageBegin(TIFFRGBAImage*, TIFF*, int, char [1024]); +extern int TIFFRGBAImageGet(TIFFRGBAImage*, uint32*, uint32, uint32); +extern void TIFFRGBAImageEnd(TIFFRGBAImage*); +extern TIFF* TIFFOpen(const char*, const char*); +# ifdef __WIN32__ +extern TIFF* TIFFOpenW(const wchar_t*, const char*); +# endif /* __WIN32__ */ +extern TIFF* TIFFFdOpen(int, const char*, const char*); +extern TIFF* TIFFClientOpen(const char*, const char*, + thandle_t, + TIFFReadWriteProc, TIFFReadWriteProc, + TIFFSeekProc, TIFFCloseProc, + TIFFSizeProc, + TIFFMapFileProc, TIFFUnmapFileProc); +extern const char* TIFFFileName(TIFF*); +extern const char* TIFFSetFileName(TIFF*, const char *); +extern void TIFFError(const char*, const char*, ...) __attribute__((format (printf,2,3))); +extern void TIFFErrorExt(thandle_t, const char*, const char*, ...) __attribute__((format (printf,3,4))); +extern void TIFFWarning(const char*, const char*, ...) __attribute__((format (printf,2,3))); +extern void TIFFWarningExt(thandle_t, const char*, const char*, ...) __attribute__((format (printf,3,4))); +extern TIFFErrorHandler TIFFSetErrorHandler(TIFFErrorHandler); +extern TIFFErrorHandlerExt TIFFSetErrorHandlerExt(TIFFErrorHandlerExt); +extern TIFFErrorHandler TIFFSetWarningHandler(TIFFErrorHandler); +extern TIFFErrorHandlerExt TIFFSetWarningHandlerExt(TIFFErrorHandlerExt); +extern TIFFExtendProc TIFFSetTagExtender(TIFFExtendProc); +extern uint32 TIFFComputeTile(TIFF* tif, uint32 x, uint32 y, uint32 z, uint16 s); +extern int TIFFCheckTile(TIFF* tif, uint32 x, uint32 y, uint32 z, uint16 s); +extern uint32 TIFFNumberOfTiles(TIFF*); +extern tmsize_t TIFFReadTile(TIFF* tif, void* buf, uint32 x, uint32 y, uint32 z, uint16 s); +extern tmsize_t TIFFWriteTile(TIFF* tif, void* buf, uint32 x, uint32 y, uint32 z, uint16 s); +extern uint32 TIFFComputeStrip(TIFF*, uint32, uint16); +extern uint32 TIFFNumberOfStrips(TIFF*); +extern tmsize_t TIFFReadEncodedStrip(TIFF* tif, uint32 strip, void* buf, tmsize_t size); +extern tmsize_t TIFFReadRawStrip(TIFF* tif, uint32 strip, void* buf, tmsize_t size); +extern tmsize_t TIFFReadEncodedTile(TIFF* tif, uint32 tile, void* buf, tmsize_t size); +extern tmsize_t TIFFReadRawTile(TIFF* tif, uint32 tile, void* buf, tmsize_t size); +extern tmsize_t TIFFWriteEncodedStrip(TIFF* tif, uint32 strip, void* data, tmsize_t cc); +extern tmsize_t TIFFWriteRawStrip(TIFF* tif, uint32 strip, void* data, tmsize_t cc); +extern tmsize_t TIFFWriteEncodedTile(TIFF* tif, uint32 tile, void* data, tmsize_t cc); +extern tmsize_t TIFFWriteRawTile(TIFF* tif, uint32 tile, void* data, tmsize_t cc); +extern int TIFFDataWidth(TIFFDataType); /* table of tag datatype widths */ +extern void TIFFSetWriteOffset(TIFF* tif, toff_t off); +extern void TIFFSwabShort(uint16*); +extern void TIFFSwabLong(uint32*); +extern void TIFFSwabLong8(uint64*); +extern void TIFFSwabFloat(float*); +extern void TIFFSwabDouble(double*); +extern void TIFFSwabArrayOfShort(uint16* wp, tmsize_t n); +extern void TIFFSwabArrayOfTriples(uint8* tp, tmsize_t n); +extern void TIFFSwabArrayOfLong(uint32* lp, tmsize_t n); +extern void TIFFSwabArrayOfLong8(uint64* lp, tmsize_t n); +extern void TIFFSwabArrayOfFloat(float* fp, tmsize_t n); +extern void TIFFSwabArrayOfDouble(double* dp, tmsize_t n); +extern void TIFFReverseBits(uint8* cp, tmsize_t n); +extern const unsigned char* TIFFGetBitRevTable(int); + +#ifdef LOGLUV_PUBLIC +#define U_NEU 0.210526316 +#define V_NEU 0.473684211 +#define UVSCALE 410. +extern double LogL16toY(int); +extern double LogL10toY(int); +extern void XYZtoRGB24(float*, uint8*); +extern int uv_decode(double*, double*, int); +extern void LogLuv24toXYZ(uint32, float*); +extern void LogLuv32toXYZ(uint32, float*); +#if defined(c_plusplus) || defined(__cplusplus) +extern int LogL16fromY(double, int = SGILOGENCODE_NODITHER); +extern int LogL10fromY(double, int = SGILOGENCODE_NODITHER); +extern int uv_encode(double, double, int = SGILOGENCODE_NODITHER); +extern uint32 LogLuv24fromXYZ(float*, int = SGILOGENCODE_NODITHER); +extern uint32 LogLuv32fromXYZ(float*, int = SGILOGENCODE_NODITHER); +#else +extern int LogL16fromY(double, int); +extern int LogL10fromY(double, int); +extern int uv_encode(double, double, int); +extern uint32 LogLuv24fromXYZ(float*, int); +extern uint32 LogLuv32fromXYZ(float*, int); +#endif +#endif /* LOGLUV_PUBLIC */ + +extern int TIFFCIELabToRGBInit(TIFFCIELabToRGB*, const TIFFDisplay *, float*); +extern void TIFFCIELabToXYZ(TIFFCIELabToRGB *, uint32, int32, int32, + float *, float *, float *); +extern void TIFFXYZToRGB(TIFFCIELabToRGB *, float, float, float, + uint32 *, uint32 *, uint32 *); + +extern int TIFFYCbCrToRGBInit(TIFFYCbCrToRGB*, float*, float*); +extern void TIFFYCbCrtoRGB(TIFFYCbCrToRGB *, uint32, int32, int32, + uint32 *, uint32 *, uint32 *); + +/**************************************************************************** + * O B S O L E T E D I N T E R F A C E S + * + * Don't use this stuff in your applications, it may be removed in the future + * libtiff versions. + ****************************************************************************/ +typedef struct { + ttag_t field_tag; /* field's tag */ + short field_readcount; /* read count/TIFF_VARIABLE/TIFF_SPP */ + short field_writecount; /* write count/TIFF_VARIABLE */ + TIFFDataType field_type; /* type of associated data */ + unsigned short field_bit; /* bit in fieldsset bit vector */ + unsigned char field_oktochange; /* if true, can change while writing */ + unsigned char field_passcount; /* if true, pass dir count on set */ + char *field_name; /* ASCII name */ +} TIFFFieldInfo; + +extern int TIFFMergeFieldInfo(TIFF*, const TIFFFieldInfo[], uint32); +extern const TIFFFieldInfo* TIFFFindFieldInfo(TIFF*, uint32, TIFFDataType); +extern const TIFFFieldInfo* TIFFFindFieldInfoByName(TIFF* , const char *, + TIFFDataType); + +#if defined(c_plusplus) || defined(__cplusplus) +} +#endif + +#endif /* _TIFFIO_ */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libs/libtiff/tiffio.hxx b/gdcm/Utilities/gdcmopenjpeg-v1/libs/libtiff/tiffio.hxx new file mode 100644 index 0000000..ed994f1 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libs/libtiff/tiffio.hxx @@ -0,0 +1,49 @@ +/* $Id: tiffio.hxx,v 1.3 2010-06-08 18:55:15 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef _TIFFIO_HXX_ +#define _TIFFIO_HXX_ + +/* + * TIFF I/O library definitions which provide C++ streams API. + */ + +#include +#include "tiff.h" + +extern TIFF* TIFFStreamOpen(const char*, std::ostream *); +extern TIFF* TIFFStreamOpen(const char*, std::istream *); + +#endif /* _TIFFIO_HXX_ */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c++ + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libs/libtiff/tiffvers.h b/gdcm/Utilities/gdcmopenjpeg-v1/libs/libtiff/tiffvers.h new file mode 100644 index 0000000..88ec059 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libs/libtiff/tiffvers.h @@ -0,0 +1,9 @@ +#define TIFFLIB_VERSION_STR "LIBTIFF, Version 4.0.0beta6\nCopyright (c) 1988-1996 Sam Leffler\nCopyright (c) 1991-1996 Silicon Graphics, Inc." +/* + * This define can be used in code that requires + * compilation-related definitions specific to a + * version or versions of the library. Runtime + * version checking should be done based on the + * string returned by TIFFGetVersion. + */ +#define TIFFLIB_VERSION 20100611 diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libs/png/libpng14.lib b/gdcm/Utilities/gdcmopenjpeg-v1/libs/png/libpng14.lib new file mode 100644 index 0000000000000000000000000000000000000000..6f82f34e29626678f762744a7ba62e5422484ab0 GIT binary patch literal 800554 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

    fRi%uGYLV?z+c_ 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

    lhjfoE(lQoBAO!ppQ6VD-K259Cj<((Y3 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�N-fvUH1q0MuG3`Kgic>Hkd6>Te@k# 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

    */ +/* This table contains the norms of the 5-3 wavelets for different bands. */ +/* */ +static const OPJ_FLOAT64 dwt_norms[4][10] = { + {1.000, 1.500, 2.750, 5.375, 10.68, 21.34, 42.67, 85.33, 170.7, 341.3}, + {1.038, 1.592, 2.919, 5.703, 11.33, 22.64, 45.25, 90.48, 180.9}, + {1.038, 1.592, 2.919, 5.703, 11.33, 22.64, 45.25, 90.48, 180.9}, + {.7186, .9218, 1.586, 3.043, 6.019, 12.01, 24.00, 47.97, 95.93} +}; + +/* */ +/* This table contains the norms of the 9-7 wavelets for different bands. */ +/* */ +static const OPJ_FLOAT64 dwt_norms_real[4][10] = { + {1.000, 1.965, 4.177, 8.403, 16.90, 33.84, 67.69, 135.3, 270.6, 540.9}, + {2.022, 3.989, 8.355, 17.04, 34.27, 68.63, 137.3, 274.6, 549.0}, + {2.022, 3.989, 8.355, 17.04, 34.27, 68.63, 137.3, 274.6, 549.0}, + {2.080, 3.865, 8.307, 17.18, 34.71, 69.59, 139.3, 278.6, 557.2} +}; + +/* +========================================================== + local functions +========================================================== +*/ + +/* */ +/* Forward lazy transform (horizontal). */ +/* */ +static void dwt_deinterleave_h(OPJ_INT32 *a, OPJ_INT32 *b, OPJ_INT32 dn, OPJ_INT32 sn, OPJ_INT32 cas) { + OPJ_INT32 i; + + OPJ_INT32 * l_dest = b; + OPJ_INT32 * l_src = a+cas; + for + (i=0; i */ +/* Forward lazy transform (vertical). */ +/* */ +static void dwt_deinterleave_v(OPJ_INT32 *a, OPJ_INT32 *b, OPJ_INT32 dn, OPJ_INT32 sn, OPJ_INT32 x, OPJ_INT32 cas) { + OPJ_INT32 i = sn; + OPJ_INT32 * l_dest = b; + OPJ_INT32 * l_src = a+cas; + + while + (i--) + { + *l_dest = *l_src; + l_dest += x; + l_src += 2; + /* b[i*x]=a[2*i+cas]; */ + } + l_dest = b + sn * x; + l_src = a + 1 - cas; + + i = dn; + while + (i--) + { + *l_dest = *l_src; + l_dest += x; + l_src += 2; + /*b[(sn+i)*x]=a[(2*i+1-cas)];*/ + } +} + +/* */ +/* Inverse lazy transform (horizontal). */ +/* */ +static void dwt_interleave_h(dwt_t* h, OPJ_INT32 *a) { + OPJ_INT32 *ai = a; + OPJ_INT32 *bi = h->mem + h->cas; + OPJ_INT32 i = h->sn; + while + ( i-- ) + { + *bi = *(ai++); + bi += 2; + } + ai = a + h->sn; + bi = h->mem + 1 - h->cas; + i = h->dn ; + while + ( i-- ) + { + *bi = *(ai++); + bi += 2; + } +} + +/* */ +/* Inverse lazy transform (vertical). */ +/* */ +static void dwt_interleave_v(dwt_t* v, OPJ_INT32 *a, OPJ_INT32 x) { + OPJ_INT32 *ai = a; + OPJ_INT32 *bi = v->mem + v->cas; + OPJ_INT32 i = v->sn; + while( i-- ) { + *bi = *ai; + bi += 2; + ai += x; + } + ai = a + (v->sn * x); + bi = v->mem + 1 - v->cas; + i = v->dn ; + while( i-- ) { + *bi = *ai; + bi += 2; + ai += x; + } +} + + +/* */ +/* Forward 5-3 wavelet transform in 1-D. */ +/* */ +static void dwt_encode_1(OPJ_INT32 *a, OPJ_INT32 dn, OPJ_INT32 sn, OPJ_INT32 cas) { + OPJ_INT32 i; + + if (!cas) { + if ((dn > 0) || (sn > 1)) { /* NEW : CASE ONE ELEMENT */ + for (i = 0; i < dn; i++) D(i) -= (S_(i) + S_(i + 1)) >> 1; + for (i = 0; i < sn; i++) S(i) += (D_(i - 1) + D_(i) + 2) >> 2; + } + } else { + if (!sn && dn == 1) /* NEW : CASE ONE ELEMENT */ + S(0) *= 2; + else { + for (i = 0; i < dn; i++) S(i) -= (DD_(i) + DD_(i - 1)) >> 1; + for (i = 0; i < sn; i++) D(i) += (SS_(i) + SS_(i + 1) + 2) >> 2; + } + } +} + +/* */ +/* Inverse 5-3 wavelet transform in 1-D. */ +/* */ +static void dwt_decode_1_(OPJ_INT32 *a, OPJ_INT32 dn, OPJ_INT32 sn, OPJ_INT32 cas) { + OPJ_INT32 i; + + if (!cas) { + if ((dn > 0) || (sn > 1)) { /* NEW : CASE ONE ELEMENT */ + for (i = 0; i < sn; i++) S(i) -= (D_(i - 1) + D_(i) + 2) >> 2; + for (i = 0; i < dn; i++) D(i) += (S_(i) + S_(i + 1)) >> 1; + } + } else { + if (!sn && dn == 1) /* NEW : CASE ONE ELEMENT */ + S(0) /= 2; + else { + for (i = 0; i < sn; i++) D(i) -= (SS_(i) + SS_(i + 1) + 2) >> 2; + for (i = 0; i < dn; i++) S(i) += (DD_(i) + DD_(i - 1)) >> 1; + } + } +} + +/* */ +/* Inverse 5-3 wavelet transform in 1-D. */ +/* */ +static void dwt_decode_1(dwt_t *v) { + dwt_decode_1_(v->mem, v->dn, v->sn, v->cas); +} + +/* */ +/* Forward 9-7 wavelet transform in 1-D. */ +/* */ +static void dwt_encode_1_real(OPJ_INT32 *a, OPJ_INT32 dn, OPJ_INT32 sn, OPJ_INT32 cas) { + OPJ_INT32 i; + if (!cas) { + if ((dn > 0) || (sn > 1)) { /* NEW : CASE ONE ELEMENT */ + for (i = 0; i < dn; i++) + D(i) -= fix_mul(S_(i) + S_(i + 1), 12993); + for (i = 0; i < sn; i++) + S(i) -= fix_mul(D_(i - 1) + D_(i), 434); + for (i = 0; i < dn; i++) + D(i) += fix_mul(S_(i) + S_(i + 1), 7233); + for (i = 0; i < sn; i++) + S(i) += fix_mul(D_(i - 1) + D_(i), 3633); + for (i = 0; i < dn; i++) + D(i) = fix_mul(D(i), 5038); /*5038 */ + for (i = 0; i < sn; i++) + S(i) = fix_mul(S(i), 6659); /*6660 */ + } + } else { + if ((sn > 0) || (dn > 1)) { /* NEW : CASE ONE ELEMENT */ + for (i = 0; i < dn; i++) + S(i) -= fix_mul(DD_(i) + DD_(i - 1), 12993); + for (i = 0; i < sn; i++) + D(i) -= fix_mul(SS_(i) + SS_(i + 1), 434); + for (i = 0; i < dn; i++) + S(i) += fix_mul(DD_(i) + DD_(i - 1), 7233); + for (i = 0; i < sn; i++) + D(i) += fix_mul(SS_(i) + SS_(i + 1), 3633); + for (i = 0; i < dn; i++) + S(i) = fix_mul(S(i), 5038); /*5038 */ + for (i = 0; i < sn; i++) + D(i) = fix_mul(D(i), 6659); /*6660 */ + } + } +} + +static void dwt_encode_stepsize(OPJ_INT32 stepsize, OPJ_INT32 numbps, opj_stepsize_t *bandno_stepsize) { + OPJ_INT32 p, n; + p = int_floorlog2(stepsize) - 13; + n = 11 - int_floorlog2(stepsize); + bandno_stepsize->mant = (n < 0 ? stepsize >> -n : stepsize << n) & 0x7ff; + bandno_stepsize->expn = numbps - p; +} + +/* +========================================================== + DWT interface +========================================================== +*/ + +/* */ +/* Forward 5-3 wavelet transform in 2-D. */ +/* */ +INLINE bool dwt_encode_procedure(opj_tcd_tilecomp_t * tilec,void (*p_function)(OPJ_INT32 *, OPJ_INT32,OPJ_INT32,OPJ_INT32) ) +{ + OPJ_INT32 i, j, k; + OPJ_INT32 *a = 00; + OPJ_INT32 *aj = 00; + OPJ_INT32 *bj = 00; + OPJ_INT32 w, l; + + OPJ_INT32 rw; /* width of the resolution level computed */ + OPJ_INT32 rh; /* height of the resolution level computed */ + OPJ_INT32 l_data_size; + + opj_tcd_resolution_t * l_cur_res = 0; + opj_tcd_resolution_t * l_last_res = 0; + + w = tilec->x1-tilec->x0; + l = tilec->numresolutions-1; + a = tilec->data; + + l_cur_res = tilec->resolutions + l; + l_last_res = l_cur_res - 1; + + rw = l_cur_res->x1 - l_cur_res->x0; + rh = l_cur_res->y1 - l_cur_res->y0; + + l_data_size = dwt_max_resolution( tilec->resolutions,tilec->numresolutions) * sizeof(OPJ_INT32); + bj = (OPJ_INT32*)opj_malloc(l_data_size); + if + (! bj) + { + return false; + } + i = l; + + while + (i--) + { + OPJ_INT32 rw1; /* width of the resolution level once lower than computed one */ + OPJ_INT32 rh1; /* height of the resolution level once lower than computed one */ + OPJ_INT32 cas_col; /* 0 = non inversion on horizontal filtering 1 = inversion between low-pass and high-pass filtering */ + OPJ_INT32 cas_row; /* 0 = non inversion on vertical filtering 1 = inversion between low-pass and high-pass filtering */ + OPJ_INT32 dn, sn; + + rw = l_cur_res->x1 - l_cur_res->x0; + rh = l_cur_res->y1 - l_cur_res->y0; + rw1 = l_last_res->x1 - l_last_res->x0; + rh1 = l_last_res->y1 - l_last_res->y0; + + cas_row = l_cur_res->x0 & 1; + cas_col = l_cur_res->y0 & 1; + + sn = rh1; + dn = rh - rh1; + for + (j = 0; j < rw; ++j) + { + aj = a + j; + for + (k = 0; k < rh; ++k) + { + bj[k] = aj[k*w]; + } + (*p_function) (bj, dn, sn, cas_col); + dwt_deinterleave_v(bj, aj, dn, sn, w, cas_col); + } + sn = rw1; + dn = rw - rw1; + for (j = 0; j < rh; j++) + { + aj = a + j * w; + for (k = 0; k < rw; k++) bj[k] = aj[k]; + (*p_function) (bj, dn, sn, cas_row); + dwt_deinterleave_h(bj, aj, dn, sn, cas_row); + } + l_cur_res = l_last_res; + --l_last_res; + } + opj_free(bj); + return true; +} +/* Forward 5-3 wavelet transform in 2-D. */ +/* */ +bool dwt_encode(opj_tcd_tilecomp_t * tilec) +{ + return dwt_encode_procedure(tilec,dwt_encode_1); +} + +/* */ +/* Inverse 5-3 wavelet transform in 2-D. */ +/* */ +bool dwt_decode(opj_tcd_tilecomp_t* tilec, OPJ_UINT32 numres) { + return dwt_decode_tile(tilec, numres, &dwt_decode_1); +} + + +/* */ +/* Get gain of 5-3 wavelet transform. */ +/* */ +OPJ_UINT32 dwt_getgain(OPJ_UINT32 orient) { + if (orient == 0) + return 0; + if (orient == 1 || orient == 2) + return 1; + return 2; +} + +/* */ +/* Get norm of 5-3 wavelet. */ +/* */ +OPJ_FLOAT64 dwt_getnorm(OPJ_UINT32 level, OPJ_UINT32 orient) { + return dwt_norms[orient][level]; +} + +/* */ +/* Forward 9-7 wavelet transform in 2-D. */ +/* */ +bool dwt_encode_real(opj_tcd_tilecomp_t * tilec) +{ + return dwt_encode_procedure(tilec,dwt_encode_1_real); +} + + + +/* */ +/* Get gain of 9-7 wavelet transform. */ +/* */ +OPJ_UINT32 dwt_getgain_real(OPJ_UINT32 orient) { + (void)orient; + return 0; +} + +/* */ +/* Get norm of 9-7 wavelet. */ +/* */ +OPJ_FLOAT64 dwt_getnorm_real(OPJ_UINT32 level, OPJ_UINT32 orient) { + return dwt_norms_real[orient][level]; +} + +void dwt_calc_explicit_stepsizes(opj_tccp_t * tccp, OPJ_UINT32 prec) { + OPJ_UINT32 numbands, bandno; + numbands = 3 * tccp->numresolutions - 2; + for (bandno = 0; bandno < numbands; bandno++) { + OPJ_FLOAT64 stepsize; + OPJ_UINT32 resno, level, orient, gain; + + resno = (bandno == 0) ? 0 : ((bandno - 1) / 3 + 1); + orient = (bandno == 0) ? 0 : ((bandno - 1) % 3 + 1); + level = tccp->numresolutions - 1 - resno; + gain = (tccp->qmfbid == 0) ? 0 : ((orient == 0) ? 0 : (((orient == 1) || (orient == 2)) ? 1 : 2)); + if (tccp->qntsty == J2K_CCP_QNTSTY_NOQNT) { + stepsize = 1.0; + } else { + OPJ_FLOAT64 norm = dwt_norms_real[orient][level]; + stepsize = (1 << (gain)) / norm; + } + dwt_encode_stepsize((OPJ_INT32) floor(stepsize * 8192.0), prec + gain, &tccp->stepsizes[bandno]); + } +} + + +/* */ +/* Determine maximum computed resolution level for inverse wavelet transform */ +/* */ +static OPJ_UINT32 dwt_max_resolution(opj_tcd_resolution_t* restrict r, OPJ_UINT32 i) { + OPJ_UINT32 mr = 0; + OPJ_UINT32 w; + while( --i ) { + ++r; + if( mr < ( w = r->x1 - r->x0 ) ) + mr = w ; + if( mr < ( w = r->y1 - r->y0 ) ) + mr = w ; + } + return mr ; +} + + +/* */ +/* Inverse wavelet transform in 2-D. */ +/* */ +static bool dwt_decode_tile(opj_tcd_tilecomp_t* tilec, OPJ_UINT32 numres, DWT1DFN dwt_1D) { + dwt_t h; + dwt_t v; + + opj_tcd_resolution_t* tr = tilec->resolutions; + + OPJ_UINT32 rw = tr->x1 - tr->x0; /* width of the resolution level computed */ + OPJ_UINT32 rh = tr->y1 - tr->y0; /* height of the resolution level computed */ + + OPJ_UINT32 w = tilec->x1 - tilec->x0; + + h.mem = (OPJ_INT32*) + opj_aligned_malloc(dwt_max_resolution(tr, numres) * sizeof(OPJ_INT32)); + if + (! h.mem) + { + return false; + } + + v.mem = h.mem; + + while( --numres) { + OPJ_INT32 * restrict tiledp = tilec->data; + OPJ_UINT32 j; + + ++tr; + h.sn = rw; + v.sn = rh; + + rw = tr->x1 - tr->x0; + rh = tr->y1 - tr->y0; + + h.dn = rw - h.sn; + h.cas = tr->x0 % 2; + + for(j = 0; j < rh; ++j) { + dwt_interleave_h(&h, &tiledp[j*w]); + (dwt_1D)(&h); + memcpy(&tiledp[j*w], h.mem, rw * sizeof(OPJ_INT32)); + } + + v.dn = rh - v.sn; + v.cas = tr->y0 % 2; + + for(j = 0; j < rw; ++j){ + OPJ_UINT32 k; + dwt_interleave_v(&v, &tiledp[j], w); + (dwt_1D)(&v); + for(k = 0; k < rh; ++k) { + tiledp[k * w + j] = v.mem[k]; + } + } + } + opj_aligned_free(h.mem); + return true; +} + +static void v4dwt_interleave_h(v4dwt_t* restrict w, OPJ_FLOAT32* restrict a, OPJ_INT32 x, OPJ_INT32 size){ + OPJ_FLOAT32* restrict bi = (OPJ_FLOAT32*) (w->wavelet + w->cas); + OPJ_INT32 count = w->sn; + OPJ_INT32 i, k; + for(k = 0; k < 2; ++k){ + for(i = 0; i < count; ++i){ + OPJ_INT32 j = i; + bi[i*8 ] = a[j]; + j += x; + if(j >= size) continue; + bi[i*8 + 1] = a[j]; + j += x; + if(j >= size) continue; + bi[i*8 + 2] = a[j]; + j += x; + if(j >= size) continue; + bi[i*8 + 3] = a[j]; + } + bi = (OPJ_FLOAT32*) (w->wavelet + 1 - w->cas); + a += w->sn; + size -= w->sn; + count = w->dn; + } +} + +static void v4dwt_interleave_v(v4dwt_t* restrict v , OPJ_FLOAT32* restrict a , OPJ_INT32 x){ + v4* restrict bi = v->wavelet + v->cas; + OPJ_INT32 i; + for(i = 0; i < v->sn; ++i){ + memcpy(&bi[i*2], &a[i*x], 4 * sizeof(OPJ_FLOAT32)); + } + a += v->sn * x; + bi = v->wavelet + 1 - v->cas; + for(i = 0; i < v->dn; ++i){ + memcpy(&bi[i*2], &a[i*x], 4 * sizeof(OPJ_FLOAT32)); + } +} + +#ifdef __SSE__ + +static void v4dwt_decode_step1_sse(v4* w, OPJ_INT32 count, const __m128 c){ + __m128* restrict vw = (__m128*) w; + OPJ_INT32 i; + for(i = 0; i < count; ++i){ + __m128 tmp = vw[i*2]; + vw[i*2] = tmp * c; + } +} + +static void v4dwt_decode_step2_sse(v4* l, v4* w, OPJ_INT32 k, OPJ_INT32 m, __m128 c){ + __m128* restrict vl = (__m128*) l; + __m128* restrict vw = (__m128*) w; + OPJ_INT32 i; + for(i = 0; i < m; ++i){ + __m128 tmp1 = vl[ 0]; + __m128 tmp2 = vw[-1]; + __m128 tmp3 = vw[ 0]; + vw[-1] = tmp2 + ((tmp1 + tmp3) * c); + vl = vw; + vw += 2; + } + if(m >= k){ + return; + } + c += c; + c *= vl[0]; + for(; m < k; ++m){ + __m128 tmp = vw[-1]; + vw[-1] = tmp + c; + vw += 2; + } +} + +#else + +static void v4dwt_decode_step1(v4* w, OPJ_INT32 count, const OPJ_FLOAT32 c){ + OPJ_FLOAT32* restrict fw = (OPJ_FLOAT32*) w; + OPJ_INT32 i; + for(i = 0; i < count; ++i){ + OPJ_FLOAT32 tmp1 = fw[i*8 ]; + OPJ_FLOAT32 tmp2 = fw[i*8 + 1]; + OPJ_FLOAT32 tmp3 = fw[i*8 + 2]; + OPJ_FLOAT32 tmp4 = fw[i*8 + 3]; + fw[i*8 ] = tmp1 * c; + fw[i*8 + 1] = tmp2 * c; + fw[i*8 + 2] = tmp3 * c; + fw[i*8 + 3] = tmp4 * c; + } +} + +static void v4dwt_decode_step2(v4* l, v4* w, OPJ_INT32 k, OPJ_INT32 m, OPJ_FLOAT32 c){ + OPJ_FLOAT32* restrict fl = (OPJ_FLOAT32*) l; + OPJ_FLOAT32* restrict fw = (OPJ_FLOAT32*) w; + OPJ_INT32 i; + for(i = 0; i < m; ++i){ + OPJ_FLOAT32 tmp1_1 = fl[0]; + OPJ_FLOAT32 tmp1_2 = fl[1]; + OPJ_FLOAT32 tmp1_3 = fl[2]; + OPJ_FLOAT32 tmp1_4 = fl[3]; + OPJ_FLOAT32 tmp2_1 = fw[-4]; + OPJ_FLOAT32 tmp2_2 = fw[-3]; + OPJ_FLOAT32 tmp2_3 = fw[-2]; + OPJ_FLOAT32 tmp2_4 = fw[-1]; + OPJ_FLOAT32 tmp3_1 = fw[0]; + OPJ_FLOAT32 tmp3_2 = fw[1]; + OPJ_FLOAT32 tmp3_3 = fw[2]; + OPJ_FLOAT32 tmp3_4 = fw[3]; + fw[-4] = tmp2_1 + ((tmp1_1 + tmp3_1) * c); + fw[-3] = tmp2_2 + ((tmp1_2 + tmp3_2) * c); + fw[-2] = tmp2_3 + ((tmp1_3 + tmp3_3) * c); + fw[-1] = tmp2_4 + ((tmp1_4 + tmp3_4) * c); + fl = fw; + fw += 8; + } + if(m < k){ + OPJ_FLOAT32 c1; + OPJ_FLOAT32 c2; + OPJ_FLOAT32 c3; + OPJ_FLOAT32 c4; + c += c; + c1 = fl[0] * c; + c2 = fl[1] * c; + c3 = fl[2] * c; + c4 = fl[3] * c; + for(; m < k; ++m){ + OPJ_FLOAT32 tmp1 = fw[-4]; + OPJ_FLOAT32 tmp2 = fw[-3]; + OPJ_FLOAT32 tmp3 = fw[-2]; + OPJ_FLOAT32 tmp4 = fw[-1]; + fw[-4] = tmp1 + c1; + fw[-3] = tmp2 + c2; + fw[-2] = tmp3 + c3; + fw[-1] = tmp4 + c4; + fw += 8; + } + } +} + +#endif + +/* */ +/* Inverse 9-7 wavelet transform in 1-D. */ +/* */ +static void v4dwt_decode(v4dwt_t* restrict dwt){ + OPJ_INT32 a, b; + if(dwt->cas == 0) { + if(!((dwt->dn > 0) || (dwt->sn > 1))){ + return; + } + a = 0; + b = 1; + }else{ + if(!((dwt->sn > 0) || (dwt->dn > 1))) { + return; + } + a = 1; + b = 0; + } +#ifdef __SSE__ + v4dwt_decode_step1_sse(dwt->wavelet+a, dwt->sn, _mm_set1_ps(K)); + v4dwt_decode_step1_sse(dwt->wavelet+b, dwt->dn, _mm_set1_ps(c13318)); + v4dwt_decode_step2_sse(dwt->wavelet+b, dwt->wavelet+a+1, dwt->sn, int_min(dwt->sn, dwt->dn-a), _mm_set1_ps(delta)); + v4dwt_decode_step2_sse(dwt->wavelet+a, dwt->wavelet+b+1, dwt->dn, int_min(dwt->dn, dwt->sn-b), _mm_set1_ps(dwt_gamma)); + v4dwt_decode_step2_sse(dwt->wavelet+b, dwt->wavelet+a+1, dwt->sn, int_min(dwt->sn, dwt->dn-a), _mm_set1_ps(dwt_beta)); + v4dwt_decode_step2_sse(dwt->wavelet+a, dwt->wavelet+b+1, dwt->dn, int_min(dwt->dn, dwt->sn-b), _mm_set1_ps(dwt_alpha)); +#else + v4dwt_decode_step1(dwt->wavelet+a, dwt->sn, K); + v4dwt_decode_step1(dwt->wavelet+b, dwt->dn, c13318); + v4dwt_decode_step2(dwt->wavelet+b, dwt->wavelet+a+1, dwt->sn, int_min(dwt->sn, dwt->dn-a), delta); + v4dwt_decode_step2(dwt->wavelet+a, dwt->wavelet+b+1, dwt->dn, int_min(dwt->dn, dwt->sn-b), dwt_gamma); + v4dwt_decode_step2(dwt->wavelet+b, dwt->wavelet+a+1, dwt->sn, int_min(dwt->sn, dwt->dn-a), dwt_beta); + v4dwt_decode_step2(dwt->wavelet+a, dwt->wavelet+b+1, dwt->dn, int_min(dwt->dn, dwt->sn-b), dwt_alpha); +#endif +} + +/* */ +/* Inverse 9-7 wavelet transform in 2-D. */ +/* */ +bool dwt_decode_real(opj_tcd_tilecomp_t* restrict tilec, OPJ_UINT32 numres){ + v4dwt_t h; + v4dwt_t v; + + opj_tcd_resolution_t* res = tilec->resolutions; + + OPJ_UINT32 rw = res->x1 - res->x0; /* width of the resolution level computed */ + OPJ_UINT32 rh = res->y1 - res->y0; /* height of the resolution level computed */ + + OPJ_UINT32 w = tilec->x1 - tilec->x0; + + h.wavelet = (v4*) opj_aligned_malloc((dwt_max_resolution(res, numres)+5) * sizeof(v4)); + v.wavelet = h.wavelet; + + while( --numres) { + OPJ_FLOAT32 * restrict aj = (OPJ_FLOAT32*) tilec->data; + OPJ_UINT32 bufsize = (tilec->x1 - tilec->x0) * (tilec->y1 - tilec->y0); + OPJ_INT32 j; + + h.sn = rw; + v.sn = rh; + + ++res; + + rw = res->x1 - res->x0; /* width of the resolution level computed */ + rh = res->y1 - res->y0; /* height of the resolution level computed */ + + h.dn = rw - h.sn; + h.cas = res->x0 & 1; + + for(j = rh; j > 0; j -= 4){ + v4dwt_interleave_h(&h, aj, w, bufsize); + v4dwt_decode(&h); + if(j >= 4){ + OPJ_INT32 k = rw; + while + (--k >= 0) + { + aj[k ] = h.wavelet[k].f[0]; + aj[k+w ] = h.wavelet[k].f[1]; + aj[k+w*2] = h.wavelet[k].f[2]; + aj[k+w*3] = h.wavelet[k].f[3]; + } + }else{ + OPJ_INT32 k = rw; + while + (--k >= 0) + { + switch(j) { + case 3: aj[k+w*2] = h.wavelet[k].f[2]; + case 2: aj[k+w ] = h.wavelet[k].f[1]; + case 1: aj[k ] = h.wavelet[k].f[0]; + } + } + } + aj += w*4; + bufsize -= w*4; + } + + v.dn = rh - v.sn; + v.cas = res->y0 % 2; + + aj = (OPJ_FLOAT32*) tilec->data; + for(j = rw; j > 0; j -= 4){ + v4dwt_interleave_v(&v, aj, w); + v4dwt_decode(&v); + if(j >= 4){ + OPJ_UINT32 k; + for(k = 0; k < rh; ++k){ + memcpy(&aj[k*w], &v.wavelet[k], 4 * sizeof(OPJ_FLOAT32)); + } + }else{ + OPJ_UINT32 k; + for(k = 0; k < rh; ++k){ + memcpy(&aj[k*w], &v.wavelet[k], j * sizeof(OPJ_FLOAT32)); + } + } + aj += 4; + } + } + + opj_aligned_free(h.wavelet); + return true; +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/dwt.h b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/dwt.h new file mode 100644 index 0000000..32714e4 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/dwt.h @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __DWT_H +#define __DWT_H +/** +@file dwt.h +@brief Implementation of a discrete wavelet transform (DWT) + +The functions in DWT.C have for goal to realize forward and inverse discret wavelet +transform with filter 5-3 (reversible) and filter 9-7 (irreversible). The functions in +DWT.C are used by some function in TCD.C. +*/ +#include "openjpeg.h" + +struct opj_tcd_tilecomp; +struct opj_tccp; + +/** @defgroup DWT DWT - Implementation of a discrete wavelet transform */ +/*@{*/ + + +/** @name Exported functions */ +/*@{*/ +/* ----------------------------------------------------------------------- */ +/** +Forward 5-3 wavelet tranform in 2-D. +Apply a reversible DWT transform to a component of an image. +@param tilec Tile component information (current tile) +*/ +bool dwt_encode(struct opj_tcd_tilecomp * tilec); +/** +Inverse 5-3 wavelet tranform in 2-D. +Apply a reversible inverse DWT transform to a component of an image. +@param tilec Tile component information (current tile) +@param numres Number of resolution levels to decode +*/ +bool dwt_decode(struct opj_tcd_tilecomp* tilec, OPJ_UINT32 numres); +/** +Get the gain of a subband for the reversible 5-3 DWT. +@param orient Number that identifies the subband (0->LL, 1->HL, 2->LH, 3->HH) +@return Returns 0 if orient = 0, returns 1 if orient = 1 or 2, returns 2 otherwise +*/ +OPJ_UINT32 dwt_getgain(OPJ_UINT32 orient); +/** +Get the norm of a wavelet function of a subband at a specified level for the reversible 5-3 DWT. +@param level Level of the wavelet function +@param orient Band of the wavelet function +@return Returns the norm of the wavelet function +*/ +OPJ_FLOAT64 dwt_getnorm(OPJ_UINT32 level, OPJ_UINT32 orient); +/** +Forward 9-7 wavelet transform in 2-D. +Apply an irreversible DWT transform to a component of an image. +@param tilec Tile component information (current tile) +*/ +bool dwt_encode_real(struct opj_tcd_tilecomp * tilec); +/** +Inverse 9-7 wavelet transform in 2-D. +Apply an irreversible inverse DWT transform to a component of an image. +@param tilec Tile component information (current tile) +@param numres Number of resolution levels to decode +*/ +bool dwt_decode_real(struct opj_tcd_tilecomp* tilec, OPJ_UINT32 numres); +/** +Get the gain of a subband for the irreversible 9-7 DWT. +@param orient Number that identifies the subband (0->LL, 1->HL, 2->LH, 3->HH) +@return Returns the gain of the 9-7 wavelet transform +*/ +OPJ_UINT32 dwt_getgain_real(OPJ_UINT32 orient); +/** +Get the norm of a wavelet function of a subband at a specified level for the irreversible 9-7 DWT +@param level Level of the wavelet function +@param orient Band of the wavelet function +@return Returns the norm of the 9-7 wavelet +*/ +OPJ_FLOAT64 dwt_getnorm_real(OPJ_UINT32 level, OPJ_UINT32 orient); +/** +Explicit calculation of the Quantization Stepsizes +@param tccp Tile-component coding parameters +@param prec Precint analyzed +*/ +void dwt_calc_explicit_stepsizes(struct opj_tccp * tccp, OPJ_UINT32 prec); +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __DWT_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/event.c b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/event.c new file mode 100644 index 0000000..96dcd3c --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/event.c @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "event.h" +#include "openjpeg.h" +#include "opj_includes.h" + + +/* ========================================================== + Utility functions + ==========================================================*/ + +#if !defined(_MSC_VER) && !defined(__MINGW32__) +static OPJ_CHAR* +i2a(OPJ_UINT32 i, OPJ_CHAR *a, OPJ_UINT32 r) { + if (i/r > 0) a = i2a(i/r,a,r); + *a = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[i%r]; + return a+1; +} +#endif +/* ----------------------------------------------------------------------- */ + +bool opj_event_msg(opj_event_mgr_t * p_event_mgr, OPJ_INT32 event_type, const OPJ_CHAR *fmt, ...) { +#define MSG_SIZE 512 /* 512 bytes should be more than enough for a short message */ + opj_msg_callback msg_handler = 00; + void * l_data = 00; + + + if(p_event_mgr != 00) { + switch(event_type) { + case EVT_ERROR: + msg_handler = p_event_mgr->error_handler; + l_data = p_event_mgr->m_error_data; + break; + case EVT_WARNING: + msg_handler = p_event_mgr->warning_handler; + l_data = p_event_mgr->m_warning_data; + break; + case EVT_INFO: + msg_handler = p_event_mgr->info_handler; + l_data = p_event_mgr->m_info_data; + break; + default: + break; + } + if(msg_handler == 00) { + return false; + } + } else { + return false; + } + + if ((fmt != 00) && (p_event_mgr != 00)) { + va_list arg; + OPJ_INT32 str_length/*, i, j*/; /* UniPG */ + OPJ_CHAR message[MSG_SIZE]; + memset(message, 0, MSG_SIZE); + /* initialize the optional parameter list */ + va_start(arg, fmt); + /* check the length of the format string */ + str_length = (strlen(fmt) > MSG_SIZE) ? MSG_SIZE : strlen(fmt); + /* parse the format string and put the result in 'message' */ + vsprintf(message, fmt, arg); /* UniPG */ + /* deinitialize the optional parameter list */ + va_end(arg); + + /* output the message to the user program */ + msg_handler(message, l_data); + } + + return true; +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/event.h b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/event.h new file mode 100644 index 0000000..f121a34 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/event.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __EVENT_H +#define __EVENT_H + +#include "openjpeg.h" + +/** +@file event.h +@brief Implementation of a event callback system + +The functions in EVENT.C have for goal to send output messages (errors, warnings, debug) to the user. +*/ +/** +Message handler object +used for +
      +
    • Error messages +
    • Warning messages +
    • Debugging messages +
    +*/ +typedef struct opj_event_mgr +{ + /** Data to call the event manager upon */ + void * m_error_data; + /** Data to call the event manager upon */ + void * m_warning_data; + /** Data to call the event manager upon */ + void * m_info_data; + /** Error message callback if available, NULL otherwise */ + opj_msg_callback error_handler; + /** Warning message callback if available, NULL otherwise */ + opj_msg_callback warning_handler; + /** Debug message callback if available, NULL otherwise */ + opj_msg_callback info_handler; +} opj_event_mgr_t; + +#define EVT_ERROR 1 /**< Error event type */ +#define EVT_WARNING 2 /**< Warning event type */ +#define EVT_INFO 4 /**< Debug event type */ + +/** @defgroup EVENT EVENT - Implementation of a event callback system */ +/*@{*/ + +/** @name Exported functions (see also openjpeg.h) */ +/*@{*/ +/* ----------------------------------------------------------------------- */ +/** + * Writes formatted data to a string and send the string to a user callback. + * @param p_event_mgr the event manager to display messages. + * @param event_type Event type of the message + * @param fmt Format-control string (plus optionnal arguments) + * @return Returns true if successful, returns false otherwise +*/ +bool opj_event_msg(struct opj_event_mgr * p_event_mgr, OPJ_INT32 event_type, const OPJ_CHAR *fmt, ...); +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __EVENT_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/fix.h b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/fix.h new file mode 100644 index 0000000..f4bb87f --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/fix.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __FIX_H +#define __FIX_H + +#include "openjpeg.h" +#include "opj_includes.h" + +/** +@file fix.h +@brief Implementation of operations of specific multiplication (FIX) + +The functions in FIX.H have for goal to realize specific multiplication. +*/ +/** @defgroup FIX FIX - Implementation of operations of specific multiplication */ +/*@{*/ + +/** +Multiply two fixed-precision rational numbers. +@param a +@param b +@return Returns a * b +*/ +static INLINE int fix_mul(int a, int b) { + OPJ_INT64 temp = (OPJ_INT64) a * (OPJ_INT64) b ; + temp += temp & 4096; + return (int) (temp >> 13) ; +} + +/*@}*/ + +#endif /* __FIX_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/function_list.c b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/function_list.c new file mode 100644 index 0000000..a249719 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/function_list.c @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "function_list.h" +#include "opj_includes.h" +#include "opj_malloc.h" +/** + * Default size of the validation list, if not sufficient, data will be reallocated with a double size. + */ +#define OPJ_VALIDATION_SIZE 10 + +/** + * Creates a validation list. + * + * @return the newly created validation list. + */ +opj_procedure_list_t * opj_procedure_list_create() +{ + /* memory allocation */ + opj_procedure_list_t * l_validation = (opj_procedure_list_t *) opj_malloc(sizeof(opj_procedure_list_t)); + if + (! l_validation) + { + return 00; + } + /* initialization */ + memset(l_validation,0,sizeof(opj_procedure_list_t)); + l_validation->m_nb_max_procedures = OPJ_VALIDATION_SIZE; + l_validation->m_procedures = (void**)opj_malloc( + OPJ_VALIDATION_SIZE * sizeof(opj_procedure)); + if + (! l_validation->m_procedures) + { + opj_free(l_validation); + return 00; + } + memset(l_validation->m_procedures,0,OPJ_VALIDATION_SIZE * sizeof(opj_procedure)); + return l_validation; +} + + + +/** + * Destroys a validation list. + * + * @param p_list the list to destroy. + */ +void opj_procedure_list_destroy(opj_procedure_list_t * p_list) +{ + if + (! p_list) + { + return; + } + /* initialization */ + if + (p_list->m_procedures) + { + opj_free(p_list->m_procedures); + } + opj_free(p_list); +} + +/** + * Adds a new validation procedure. + * + * @param p_validation_list the list of procedure to modify. + * @param p_procedure the procedure to add. + */ +bool opj_procedure_list_add_procedure (opj_procedure_list_t * p_validation_list, opj_procedure p_procedure) +{ + if + (p_validation_list->m_nb_max_procedures == p_validation_list->m_nb_procedures) + { + p_validation_list->m_nb_max_procedures += OPJ_VALIDATION_SIZE; + p_validation_list->m_procedures = (void**)opj_realloc( + p_validation_list->m_procedures,p_validation_list->m_nb_max_procedures * sizeof(opj_procedure)); + if + (! p_validation_list->m_procedures) + { + p_validation_list->m_nb_max_procedures = 0; + p_validation_list->m_nb_procedures = 0; + return false; + } + } + p_validation_list->m_procedures[p_validation_list->m_nb_procedures] = p_procedure; + ++p_validation_list->m_nb_procedures; + return true; +} + +/** + * Gets the number of validation procedures. + * + * @param p_validation_list the list of procedure to modify. + * + * @return the number of validation procedures. + */ +OPJ_UINT32 opj_procedure_list_get_nb_procedures (opj_procedure_list_t * p_validation_list) +{ + return p_validation_list->m_nb_procedures; +} + +/** + * Gets the pointer on the first validation procedure. This function is similar to the C++ + * iterator class to iterate through all the procedures inside the validation list. + * the caller does not take ownership of the pointer. + * + * @param p_validation_list the list of procedure to get the first procedure from. + * + * @return a pointer to the first procedure. + */ +opj_procedure* opj_procedure_list_get_first_procedure (opj_procedure_list_t * p_validation_list) +{ + return p_validation_list->m_procedures; +} + +/** + * Clears the list of validation procedures. + * + * @param p_validation_list the list of procedure to clear. + * + */ +void opj_procedure_list_clear (opj_procedure_list_t * p_validation_list) +{ + p_validation_list->m_nb_procedures = 0; +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/function_list.h b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/function_list.h new file mode 100644 index 0000000..e3e3915 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/function_list.h @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __FUNCTION_LIST_H +#define __FUNCTION_LIST_H + +/** + * @file function_list.h + * @brief Implementation of a list of procedures. + + * The functions in validation.c aims to have access to a list of procedures. +*/ + +/** @defgroup validation validation procedure*/ +/*@{*/ + +#include "openjpeg.h" +/************************************************************************************************** + ***************************************** FORWARD DECLARATION ************************************ + **************************************************************************************************/ +struct opj_jp2; + +/** + * ARGGGG, when will the template be added to the C language ??? + * in order not to have to duplicate the code in a vast number of times, use void * and downcast + * it after => UGLY but faster and easier + * TODO : make the class template in C++, use STL vector or duplicate code for each procedure type. + */ +typedef void * opj_procedure; + +/** + * A list of procedures. +*/ +typedef struct opj_procedure_list +{ + /** + * The number of validation procedures. + */ + OPJ_UINT32 m_nb_procedures; + /** + * The number of the array of validation procedures. + */ + OPJ_UINT32 m_nb_max_procedures; + /** + * The array of procedures. + */ + opj_procedure * m_procedures; + +} opj_procedure_list_t; + +/* ----------------------------------------------------------------------- */ + +/** + * Creates a validation list. + * + * @return the newly created validation list. + */ +opj_procedure_list_t * opj_procedure_list_create(); + +/** + * Destroys a validation list. + * + * @param p_list the list to destroy. + */ +void opj_procedure_list_destroy(opj_procedure_list_t * p_list); + +/** + * Adds a new validation procedure. + * + * @param p_validation_list the list of procedure to modify. + * @param p_procedure the procedure to add. + * + * @return true if the procedure could ne added. + */ +bool opj_procedure_list_add_procedure (opj_procedure_list_t * p_validation_list, opj_procedure p_procedure); + +/** + * Gets the number of validation procedures. + * + * @param p_validation_list the list of procedure to modify. + * + * @return the number of validation procedures. + */ +OPJ_UINT32 opj_procedure_list_get_nb_procedures (opj_procedure_list_t * p_validation_list); + +/** + * Gets the pointer on the first validation procedure. This function is similar to the C++ + * iterator class to iterate through all the procedures inside the validation list. + * the caller does not take ownership of the pointer. + * + * @param p_validation_list the list of procedure to get the first procedure from. + * + * @return a pointer to the first procedure. + */ +opj_procedure* opj_procedure_list_get_first_procedure (opj_procedure_list_t * p_validation_list); + + +/** + * Clears the list of validation procedures. + * + * @param p_validation_list the list of procedure to clear. + * + */ +void opj_procedure_list_clear (opj_procedure_list_t * p_validation_list); + + +#endif /* __FUNCTION_LIST_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/image.c b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/image.c new file mode 100644 index 0000000..3305f4f --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/image.c @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "image.h" +#include "openjpeg.h" +#include "opj_malloc.h" +#include "j2k.h" +#include "int.h" + +opj_image_t* opj_image_create0(void) { + opj_image_t *image = (opj_image_t*)opj_malloc(sizeof(opj_image_t)); + memset(image,0,sizeof(opj_image_t)); + return image; +} + +opj_image_t* OPJ_CALLCONV opj_image_create(OPJ_UINT32 numcmpts, opj_image_cmptparm_t *cmptparms, OPJ_COLOR_SPACE clrspc) { + OPJ_UINT32 compno; + opj_image_t *image = 00; + + image = (opj_image_t*) opj_malloc(sizeof(opj_image_t)); + if + (image) + { + memset(image,0,sizeof(opj_image_t)); + image->color_space = clrspc; + image->numcomps = numcmpts; + /* allocate memory for the per-component information */ + image->comps = (opj_image_comp_t*)opj_malloc(image->numcomps * sizeof(opj_image_comp_t)); + if + (!image->comps) + { + opj_image_destroy(image); + return 00; + } + memset(image->comps,0,image->numcomps * sizeof(opj_image_comp_t)); + /* create the individual image components */ + for(compno = 0; compno < numcmpts; compno++) { + opj_image_comp_t *comp = &image->comps[compno]; + comp->dx = cmptparms[compno].dx; + comp->dy = cmptparms[compno].dy; + comp->w = cmptparms[compno].w; + comp->h = cmptparms[compno].h; + comp->x0 = cmptparms[compno].x0; + comp->y0 = cmptparms[compno].y0; + comp->prec = cmptparms[compno].prec; + comp->sgnd = cmptparms[compno].sgnd; + comp->data = (OPJ_INT32*) opj_calloc(comp->w * comp->h, sizeof(OPJ_INT32)); + if + (!comp->data) + { + opj_image_destroy(image); + return 00; + } + } + } + return image; +} + +opj_image_t* OPJ_CALLCONV opj_image_tile_create(OPJ_UINT32 numcmpts, opj_image_cmptparm_t *cmptparms, OPJ_COLOR_SPACE clrspc) { + OPJ_UINT32 compno; + opj_image_t *image = 00; + + image = (opj_image_t*) opj_malloc(sizeof(opj_image_t)); + if + (image) + { + memset(image,0,sizeof(opj_image_t)); + image->color_space = clrspc; + image->numcomps = numcmpts; + /* allocate memory for the per-component information */ + image->comps = (opj_image_comp_t*)opj_malloc(image->numcomps * sizeof(opj_image_comp_t)); + if + (!image->comps) + { + opj_image_destroy(image); + return 00; + } + memset(image->comps,0,image->numcomps * sizeof(opj_image_comp_t)); + /* create the individual image components */ + for(compno = 0; compno < numcmpts; compno++) { + opj_image_comp_t *comp = &image->comps[compno]; + comp->dx = cmptparms[compno].dx; + comp->dy = cmptparms[compno].dy; + comp->w = cmptparms[compno].w; + comp->h = cmptparms[compno].h; + comp->x0 = cmptparms[compno].x0; + comp->y0 = cmptparms[compno].y0; + comp->prec = cmptparms[compno].prec; + comp->sgnd = cmptparms[compno].sgnd; + comp->data = 0; + } + } + return image; +} + +void OPJ_CALLCONV opj_image_destroy(opj_image_t *image) { + OPJ_UINT32 i; + if + (image) + { + if + (image->comps) + { + /* image components */ + for(i = 0; i < image->numcomps; i++) { + opj_image_comp_t *image_comp = &image->comps[i]; + if(image_comp->data) { + opj_free(image_comp->data); + } + } + opj_free(image->comps); + } + opj_free(image); + } +} + +/** + * Updates the components of the image from the coding parameters. + * + * @param p_image the image to update. + * @param p_cp the coding parameters from which to update the image. + */ +void opj_image_comp_update(opj_image_t * p_image,const opj_cp_t * p_cp) +{ + OPJ_UINT32 i, l_width, l_height; + OPJ_INT32 l_x0,l_y0,l_x1,l_y1; + OPJ_INT32 l_comp_x0,l_comp_y0,l_comp_x1,l_comp_y1; + opj_image_comp_t * l_img_comp = 00; + + l_x0 = int_max(p_cp->tx0 , p_image->x0); + l_y0 = int_max(p_cp->ty0 , p_image->y0); + l_x1 = int_min(p_cp->tx0 + p_cp->tw * p_cp->tdx, p_image->x1); + l_y1 = int_min(p_cp->ty0 + p_cp->th * p_cp->tdy, p_image->y1); + + l_img_comp = p_image->comps; + for + (i = 0; i < p_image->numcomps; ++i) + { + l_comp_x0 = int_ceildiv(l_x0, l_img_comp->dx); + l_comp_y0 = int_ceildiv(l_y0, l_img_comp->dy); + l_comp_x1 = int_ceildiv(l_x1, l_img_comp->dx); + l_comp_y1 = int_ceildiv(l_y1, l_img_comp->dy); + l_width = int_ceildivpow2(l_comp_x1 - l_comp_x0, l_img_comp->factor); + l_height = int_ceildivpow2(l_comp_y1 - l_comp_y0, l_img_comp->factor); + l_img_comp->w = l_width; + l_img_comp->h = l_height; + l_img_comp->x0 = l_x0; + l_img_comp->y0 = l_y0; + ++l_img_comp; + } +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/image.h b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/image.h new file mode 100644 index 0000000..e78df28 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/image.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __IMAGE_H +#define __IMAGE_H +/** +@file image.h +@brief Implementation of operations on images (IMAGE) + +The functions in IMAGE.C have for goal to realize operations on images. +*/ +struct opj_image; +struct opj_cp; +/** @defgroup IMAGE IMAGE - Implementation of operations on images */ +/*@{*/ + +/** +Create an empty image +@todo this function should be removed +@return returns an empty image if successful, returns NULL otherwise +*/ +struct opj_image* opj_image_create0(void); + +/** + * Updates the components of the image from the coding parameters. + * + * @param p_image the image to update. + * @param p_cp the coding parameters from which to update the image. + */ +void opj_image_comp_update(struct opj_image * p_image,const struct opj_cp * p_cp); + +/*@}*/ + +#endif /* __IMAGE_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/int.h b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/int.h new file mode 100644 index 0000000..43e576f --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/int.h @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __INT_H +#define __INT_H +/** +@file int.h +@brief Implementation of operations on integers (INT) + +The functions in INT.H have for goal to realize operations on integers. +*/ +#include "openjpeg.h" +#include "opj_includes.h" +/** @defgroup INT INT - Implementation of operations on integers */ +/*@{*/ + +/** @name Exported functions (see also openjpeg.h) */ +/*@{*/ +/* ----------------------------------------------------------------------- */ +/** +Get the minimum of two integers +@return Returns a if a < b else b +*/ +static INLINE OPJ_INT32 int_min(OPJ_INT32 a, OPJ_INT32 b) { + return a < b ? a : b; +} + +/** +Get the minimum of two integers +@return Returns a if a < b else b +*/ +static INLINE OPJ_UINT32 uint_min(OPJ_UINT32 a, OPJ_UINT32 b) { + return a < b ? a : b; +} + +/** +Get the maximum of two integers +@return Returns a if a > b else b +*/ +static INLINE OPJ_INT32 int_max(OPJ_INT32 a, OPJ_INT32 b) { + return (a > b) ? a : b; +} + +/** +Get the maximum of two integers +@return Returns a if a > b else b +*/ +static INLINE OPJ_UINT32 uint_max(OPJ_UINT32 a, OPJ_UINT32 b) { + return (a > b) ? a : b; +} +/** +Clamp an integer inside an interval +@return +
      +
    • Returns a if (min < a < max) +
    • Returns max if (a > max) +
    • Returns min if (a < min) +
    +*/ +static INLINE OPJ_INT32 int_clamp(OPJ_INT32 a, OPJ_INT32 min, OPJ_INT32 max) { + if (a < min) + return min; + if (a > max) + return max; + return a; +} +/** +@return Get absolute value of integer +*/ +static INLINE OPJ_INT32 int_abs(OPJ_INT32 a) { + return a < 0 ? -a : a; +} +/** +Divide an integer and round upwards +@return Returns a divided by b +*/ +static INLINE OPJ_INT32 int_ceildiv(OPJ_INT32 a, OPJ_INT32 b) { + return (a + b - 1) / b; +} + +/** +Divide an integer and round upwards +@return Returns a divided by b +*/ +static INLINE OPJ_UINT32 uint_ceildiv(OPJ_UINT32 a, OPJ_UINT32 b) { + return (a + b - 1) / b; +} +/** +Divide an integer by a power of 2 and round upwards +@return Returns a divided by 2^b +*/ +static INLINE OPJ_INT32 int_ceildivpow2(OPJ_INT32 a, OPJ_INT32 b) { + return (a + (1 << b) - 1) >> b; +} +/** +Divide an integer by a power of 2 and round downwards +@return Returns a divided by 2^b +*/ +static INLINE OPJ_INT32 int_floordivpow2(OPJ_INT32 a, OPJ_INT32 b) { + return a >> b; +} +/** +Get logarithm of an integer and round downwards +@return Returns log2(a) +*/ +static INLINE OPJ_INT32 int_floorlog2(OPJ_INT32 a) { + OPJ_INT32 l; + for (l = 0; a > 1; l++) { + a >>= 1; + } + return l; +} + +/** +Get logarithm of an integer and round downwards +@return Returns log2(a) +*/ +static INLINE OPJ_UINT32 uint_floorlog2(OPJ_UINT32 a) { + OPJ_UINT32 l; + for (l = 0; a > 1; ++l) + { + a >>= 1; + } + return l; +} +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/invert.c b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/invert.c new file mode 100644 index 0000000..14ce3e4 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/invert.c @@ -0,0 +1,290 @@ +/* + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "invert.h" +#include "opj_malloc.h" + + +bool opj_lupDecompose(OPJ_FLOAT32 * matrix,OPJ_UINT32 * permutations, OPJ_FLOAT32 * p_swap_area,OPJ_UINT32 n); +void opj_lupSolve(OPJ_FLOAT32 * pResult, OPJ_FLOAT32* pMatrix, OPJ_FLOAT32* pVector, OPJ_UINT32* pPermutations, OPJ_UINT32 n,OPJ_FLOAT32 * p_intermediate_data); +void opj_lupInvert (OPJ_FLOAT32 * pSrcMatrix, + OPJ_FLOAT32 * pDestMatrix, + OPJ_UINT32 n, + OPJ_UINT32 * pPermutations, + OPJ_FLOAT32 * p_src_temp, + OPJ_FLOAT32 * p_dest_temp, + OPJ_FLOAT32 * p_swap_area); + +/** + * Matrix inversion. + */ +bool opj_matrix_inversion_f(OPJ_FLOAT32 * pSrcMatrix,OPJ_FLOAT32 * pDestMatrix, OPJ_UINT32 n) +{ + OPJ_BYTE * l_data = 00; + OPJ_UINT32 l_permutation_size = n * sizeof(OPJ_UINT32); + OPJ_UINT32 l_swap_size = n * sizeof(OPJ_FLOAT32); + OPJ_UINT32 l_total_size = l_permutation_size + 3 * l_swap_size; + OPJ_UINT32 * lPermutations = 00; + OPJ_FLOAT32 * l_double_data = 00; + + l_data = (OPJ_BYTE *) opj_malloc(l_total_size); + if + (l_data == 0) + { + return false; + } + lPermutations = (OPJ_UINT32 *) l_data; + l_double_data = (OPJ_FLOAT32 *) (l_data + l_permutation_size); + memset(lPermutations,0,l_permutation_size); + + if + (! opj_lupDecompose(pSrcMatrix,lPermutations,l_double_data,n)) + { + opj_free(l_data); + return false; + } + opj_lupInvert(pSrcMatrix,pDestMatrix,n,lPermutations,l_double_data,l_double_data + n,l_double_data + 2*n); + opj_free(l_data); + return true; +} + + +/** + * LUP decomposition + */ +bool opj_lupDecompose(OPJ_FLOAT32 * matrix,OPJ_UINT32 * permutations, OPJ_FLOAT32 * p_swap_area,OPJ_UINT32 n) +{ + OPJ_UINT32 * tmpPermutations = permutations; + OPJ_UINT32 * dstPermutations; + OPJ_UINT32 k2=0,t; + OPJ_FLOAT32 temp; + OPJ_UINT32 i,j,k; + OPJ_FLOAT32 p; + OPJ_UINT32 lLastColum = n - 1; + OPJ_UINT32 lSwapSize = n * sizeof(OPJ_FLOAT32); + OPJ_FLOAT32 * lTmpMatrix = matrix; + OPJ_FLOAT32 * lColumnMatrix,* lDestMatrix; + OPJ_UINT32 offset = 1; + OPJ_UINT32 lStride = n-1; + + //initialize permutations + for + (i = 0; i < n; ++i) + { + *tmpPermutations++ = i; + } + + + + // now make a pivot with colum switch + tmpPermutations = permutations; + for + (k = 0; k < lLastColum; ++k) + { + p = 0.0; + + // take the middle element + lColumnMatrix = lTmpMatrix + k; + + // make permutation with the biggest value in the column + for + (i = k; i < n; ++i) + { + temp = ((*lColumnMatrix > 0) ? *lColumnMatrix : -(*lColumnMatrix)); + if + (temp > p) + { + p = temp; + k2 = i; + } + // next line + lColumnMatrix += n; + } + + // a whole rest of 0 -> non singular + if + (p == 0.0) + { + return false; + } + + // should we permute ? + if + (k2 != k) + { + //exchange of line + // k2 > k + dstPermutations = tmpPermutations + k2 - k; + // swap indices + t = *tmpPermutations; + *tmpPermutations = *dstPermutations; + *dstPermutations = t; + + // and swap entire line. + lColumnMatrix = lTmpMatrix + (k2 - k) * n; + memcpy(p_swap_area,lColumnMatrix,lSwapSize); + memcpy(lColumnMatrix,lTmpMatrix,lSwapSize); + memcpy(lTmpMatrix,p_swap_area,lSwapSize); + } + + // now update data in the rest of the line and line after + lDestMatrix = lTmpMatrix + k; + lColumnMatrix = lDestMatrix + n; + // take the middle element + temp = *(lDestMatrix++); + + // now compute up data (i.e. coeff up of the diagonal). + for (i = offset; i < n; ++i) + { + //lColumnMatrix; + // divide the lower column elements by the diagonal value + + // matrix[i][k] /= matrix[k][k]; + // p = matrix[i][k] + p = *lColumnMatrix / temp; + *(lColumnMatrix++) = p; + for + (j = /* k + 1 */ offset; j < n; ++j) + { + // matrix[i][j] -= matrix[i][k] * matrix[k][j]; + *(lColumnMatrix++) -= p * (*(lDestMatrix++)); + } + // come back to the k+1th element + lDestMatrix -= lStride; + // go to kth element of the next line + lColumnMatrix += k; + } + // offset is now k+2 + ++offset; + // 1 element less for stride + --lStride; + // next line + lTmpMatrix+=n; + // next permutation element + ++tmpPermutations; + } + return true; +} + + + +/** + * LUP solving + */ +void opj_lupSolve (OPJ_FLOAT32 * pResult, OPJ_FLOAT32 * pMatrix, OPJ_FLOAT32 * pVector, OPJ_UINT32* pPermutations, OPJ_UINT32 n,OPJ_FLOAT32 * p_intermediate_data) +{ + OPJ_UINT32 i,j; + OPJ_FLOAT32 sum; + OPJ_FLOAT32 u; + OPJ_UINT32 lStride = n+1; + OPJ_FLOAT32 * lCurrentPtr; + OPJ_FLOAT32 * lIntermediatePtr; + OPJ_FLOAT32 * lDestPtr; + OPJ_FLOAT32 * lTmpMatrix; + OPJ_FLOAT32 * lLineMatrix = pMatrix; + OPJ_FLOAT32 * lBeginPtr = pResult + n - 1; + OPJ_FLOAT32 * lGeneratedData; + OPJ_UINT32 * lCurrentPermutationPtr = pPermutations; + + + lIntermediatePtr = p_intermediate_data; + lGeneratedData = p_intermediate_data + n - 1; + + for + (i = 0; i < n; ++i) + { + sum = 0.0; + lCurrentPtr = p_intermediate_data; + lTmpMatrix = lLineMatrix; + for + (j = 1; j <= i; ++j) + { + // sum += matrix[i][j-1] * y[j-1]; + sum += (*(lTmpMatrix++)) * (*(lCurrentPtr++)); + } + //y[i] = pVector[pPermutations[i]] - sum; + *(lIntermediatePtr++) = pVector[*(lCurrentPermutationPtr++)] - sum; + lLineMatrix += n; + } + + // we take the last point of the matrix + lLineMatrix = pMatrix + n*n - 1; + + // and we take after the last point of the destination vector + lDestPtr = pResult + n; + + for + (i = n - 1; i != -1 ; --i) + { + sum = 0.0; + lTmpMatrix = lLineMatrix; + u = *(lTmpMatrix++); + lCurrentPtr = lDestPtr--; + for + (j = i + 1; j < n; ++j) + { + // sum += matrix[i][j] * x[j] + sum += (*(lTmpMatrix++)) * (*(lCurrentPtr++)); + } + //x[i] = (y[i] - sum) / u; + *(lBeginPtr--) = (*(lGeneratedData--) - sum) / u; + lLineMatrix -= lStride; + } +} + +/** LUP inversion (call with the result of lupDecompose) + */ +void opj_lupInvert ( + OPJ_FLOAT32 * pSrcMatrix, + OPJ_FLOAT32 * pDestMatrix, + OPJ_UINT32 n, + OPJ_UINT32 * pPermutations, + OPJ_FLOAT32 * p_src_temp, + OPJ_FLOAT32 * p_dest_temp, + OPJ_FLOAT32 * p_swap_area + ) +{ + OPJ_UINT32 j,i; + OPJ_FLOAT32 * lCurrentPtr; + OPJ_FLOAT32 * lLineMatrix = pDestMatrix; + OPJ_UINT32 lSwapSize = n * sizeof(OPJ_FLOAT32); + + for + (j = 0; j < n; ++j) + { + lCurrentPtr = lLineMatrix++; + memset(p_src_temp,0,lSwapSize); + p_src_temp[j] = 1.0; + opj_lupSolve(p_dest_temp,pSrcMatrix,p_src_temp, pPermutations, n , p_swap_area); + + for + (i = 0; i < n; ++i) + { + *(lCurrentPtr) = p_dest_temp[i]; + lCurrentPtr+=n; + } + } +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/invert.h b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/invert.h new file mode 100644 index 0000000..a6ebe72 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/invert.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __INVERT_H +#define __INVERT_H +#include "openjpeg.h" +/** + * Calculates a n x n double matrix inversion with a LUP method. Data is aligned, rows after rows (or columns after columns). + * The function does not take ownership of any memory block, data must be fred by the user. + * + * @param pSrcMatrix the matrix to invert. + * @param pDestMatrix data to store the inverted matrix. + * @return 1 if the inversion is successful, 0 if the matrix is singular. + */ +bool opj_matrix_inversion_f(OPJ_FLOAT32 * pSrcMatrix,OPJ_FLOAT32 * pDestMatrix, OPJ_UINT32 n); +#endif diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/j2k.c b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/j2k.c new file mode 100644 index 0000000..c16b210 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/j2k.c @@ -0,0 +1,9411 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2006-2007, Parvatha Elangovan + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "j2k.h" +#include "opj_malloc.h" +#include "opj_includes.h" +#include "pi.h" +#include "event.h" +#include "cio.h" +#include "int.h" +#include "tcd.h" +#include "function_list.h" +#include "invert.h" +#include "dwt.h" +#include "mct.h" +#include "image.h" + +/** @defgroup J2K J2K - JPEG-2000 codestream reader/writer */ +/*@{*/ + + +/*************************************************************************** + ********************** TYPEDEFS ******************************************* + ***************************************************************************/ +/** + * Correspondance prog order <-> string representation + */ +typedef struct j2k_prog_order +{ + OPJ_PROG_ORDER enum_prog; + OPJ_CHAR str_prog[5]; +} +j2k_prog_order_t; + +typedef struct opj_dec_memory_marker_handler +{ + /** marker value */ + OPJ_UINT32 id; + /** value of the state when the marker can appear */ + OPJ_UINT32 states; + /** action linked to the marker */ + bool (*handler) ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ); +} +opj_dec_memory_marker_handler_t; + + + +/** @name Local static functions */ +/*@{*/ +/** + * Writes a SPCod or SPCoc element, i.e. the coding style of a given component of a tile. + * + * @param p_comp_no the component number to output. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. + * +*/ +static bool j2k_write_SPCod_SPCoc( + opj_j2k_t *p_j2k, + OPJ_UINT32 p_tile_no, + OPJ_UINT32 p_comp_no, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_header_size, + struct opj_event_mgr * p_manager + ); + +/** + * Reads a SPCod or SPCoc element, i.e. the coding style of a given component of a tile. + * @param p_header_data the data contained in the COM box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the COM marker. + * @param p_manager the user event manager. +*/ +static bool j2k_read_SPCod_SPCoc( + opj_j2k_t *p_j2k, + OPJ_UINT32 compno, + OPJ_BYTE * p_header_data, + OPJ_UINT32 * p_header_size, + struct opj_event_mgr * p_manager + ); + +/** + * Gets the size taken by writting a SPCod or SPCoc for the given tile and component. + * + * @param p_tile_no the tile indix. + * @param p_comp_no the component being outputted. + * @param p_j2k the J2K codec. + * + * @return the number of bytes taken by the SPCod element. + */ +static OPJ_UINT32 j2k_get_SPCod_SPCoc_size ( + opj_j2k_t *p_j2k, + OPJ_UINT32 p_tile_no, + OPJ_UINT32 p_comp_no + ); + +/** + * Writes a SQcd or SQcc element, i.e. the quantization values of a band in the QCD or QCC. + * + * @param p_tile_no the tile to output. + * @param p_comp_no the component number to output. + * @param p_data the data buffer. + * @param p_header_size pointer to the size of the data buffer, it is changed by the function. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. + * +*/ +static bool j2k_write_SQcd_SQcc( + opj_j2k_t *p_j2k, + OPJ_UINT32 p_tile_no, + OPJ_UINT32 p_comp_no, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_header_size, + struct opj_event_mgr * p_manager + ); + +/** + * Reads a SQcd or SQcc element, i.e. the quantization values of a band in the QCD or QCC. + * + * @param p_tile_no the tile to output. + * @param p_comp_no the component number to output. + * @param p_data the data buffer. + * @param p_header_size pointer to the size of the data buffer, it is changed by the function. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. + * +*/ +static bool j2k_read_SQcd_SQcc( + opj_j2k_t *p_j2k, + OPJ_UINT32 compno, + OPJ_BYTE * p_header_data, + OPJ_UINT32 * p_header_size, + struct opj_event_mgr * p_manager + ); +/** + * Updates the Tile Length Marker. + */ +static void j2k_update_tlm ( + opj_j2k_t * p_j2k, + OPJ_UINT32 p_tile_part_size); + +/** + * Gets the size taken by writting SQcd or SQcc element, i.e. the quantization values of a band in the QCD or QCC. + * + * @param p_tile_no the tile indix. + * @param p_comp_no the component being outputted. + * @param p_j2k the J2K codec. + * + * @return the number of bytes taken by the SPCod element. + */ +static OPJ_UINT32 j2k_get_SQcd_SQcc_size ( + opj_j2k_t *p_j2k, + OPJ_UINT32 p_tile_no, + OPJ_UINT32 p_comp_no + + ); + +/** + * Copies the tile component parameters of all the component from the first tile component. + * + * @param p_j2k the J2k codec. + */ +static void j2k_copy_tile_component_parameters( + opj_j2k_t *p_j2k + ); + +/** + * Writes the SOC marker (Start Of Codestream) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ + +static bool j2k_write_soc( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); +/** + * Reads a SOC marker (Start of Codestream) + * @param p_header_data the data contained in the SOC box. + * @param jp2 the jpeg2000 file codec. + * @param p_header_size the size of the data contained in the SOC marker. + * @param p_manager the user event manager. +*/ +static bool j2k_read_soc( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); +/** + * Writes the SIZ marker (image and tile size) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static bool j2k_write_siz( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); +/** + * Writes the CBD-MCT-MCC-MCO markers (Multi components transform) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static bool j2k_write_mct_data_group( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); + +/** + * Reads a SIZ marker (image and tile size) + * @param p_header_data the data contained in the SIZ box. + * @param jp2 the jpeg2000 file codec. + * @param p_header_size the size of the data contained in the SIZ marker. + * @param p_manager the user event manager. +*/ +static bool j2k_read_siz ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ); +/** + * Writes the COM marker (comment) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static bool j2k_write_com( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); +/** + * Reads a COM marker (comments) + * @param p_header_data the data contained in the COM box. + * @param jp2 the jpeg2000 file codec. + * @param p_header_size the size of the data contained in the COM marker. + * @param p_manager the user event manager. +*/ +static bool j2k_read_com ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ); + + + +/** + * Writes the COD marker (Coding style default) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static bool j2k_write_cod( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); +/** + * Reads a COD marker (Coding Styke defaults) + * @param p_header_data the data contained in the COD box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the COD marker. + * @param p_manager the user event manager. +*/ +static bool j2k_read_cod ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ); + +/** + * Writes the COC marker (Coding style component) + * + * @param p_comp_number the index of the component to output. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static bool j2k_write_coc( + opj_j2k_t *p_j2k, + OPJ_UINT32 p_comp_number, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); + +/** + * Writes the COC marker (Coding style component) + * + * @param p_comp_no the index of the component to output. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static void j2k_write_coc_in_memory( + opj_j2k_t *p_j2k, + OPJ_UINT32 p_comp_no, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + struct opj_event_mgr * p_manager + ); +/** + * Gets the maximum size taken by a coc. + * + * @param p_j2k the jpeg2000 codec to use. + */ +static OPJ_UINT32 j2k_get_max_coc_size(opj_j2k_t *p_j2k); + +/** + * Reads a COC marker (Coding Style Component) + * @param p_header_data the data contained in the COC box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the COC marker. + * @param p_manager the user event manager. +*/ +static bool j2k_read_coc ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ); + +/** + * Writes the QCD marker (quantization default) + * + * @param p_comp_number the index of the component to output. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static bool j2k_write_qcd( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); + + +/** + * Reads a QCD marker (Quantization defaults) + * @param p_header_data the data contained in the QCD box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the QCD marker. + * @param p_manager the user event manager. +*/ +static bool j2k_read_qcd ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ); +/** + * Writes the QCC marker (quantization component) + * + * @param p_comp_no the index of the component to output. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static bool j2k_write_qcc( + opj_j2k_t *p_j2k, + OPJ_UINT32 p_comp_no, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); +/** + * Writes the QCC marker (quantization component) + * + * @param p_comp_no the index of the component to output. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static void j2k_write_qcc_in_memory( + opj_j2k_t *p_j2k, + OPJ_UINT32 p_comp_no, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + struct opj_event_mgr * p_manager + ); +/** + * Gets the maximum size taken by a qcc. + */ +static OPJ_UINT32 j2k_get_max_qcc_size (opj_j2k_t *p_j2k); + +/** + * Reads a QCC marker (Quantization component) + * @param p_header_data the data contained in the QCC box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the QCC marker. + * @param p_manager the user event manager. +*/ +static bool j2k_read_qcc( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager); +/** + * Writes the POC marker (Progression Order Change) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static bool j2k_write_poc( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); + +/** + * Writes the updated tlm. + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static bool j2k_write_updated_tlm( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); + +/** + * Writes the POC marker (Progression Order Change) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. + */ +static void j2k_write_poc_in_memory( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + struct opj_event_mgr * p_manager + ); + +/** + * Gets the maximum size taken by the writting of a POC. + */ +static OPJ_UINT32 j2k_get_max_poc_size(opj_j2k_t *p_j2k); + +/** + * Gets the maximum size taken by the toc headers of all the tile parts of any given tile. + */ +static OPJ_UINT32 j2k_get_max_toc_size (opj_j2k_t *p_j2k); + +/** + * Gets the maximum size taken by the headers of the SOT. + * + * @param p_j2k the jpeg2000 codec to use. + */ +static OPJ_UINT32 j2k_get_specific_header_sizes(opj_j2k_t *p_j2k); + +/** + * Reads a POC marker (Progression Order Change) + * + * @param p_header_data the data contained in the POC box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the POC marker. + * @param p_manager the user event manager. +*/ +static bool j2k_read_poc ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ); +/** + * Reads a CRG marker (Component registration) + * + * @param p_header_data the data contained in the TLM box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the TLM marker. + * @param p_manager the user event manager. +*/ +static bool j2k_read_crg ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ); +/** + * Reads a TLM marker (Tile Length Marker) + * + * @param p_header_data the data contained in the TLM box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the TLM marker. + * @param p_manager the user event manager. +*/ +static bool j2k_read_tlm ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ); +/** + * Reads a PLM marker (Packet length, main header marker) + * + * @param p_header_data the data contained in the TLM box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the TLM marker. + * @param p_manager the user event manager. +*/ +static bool j2k_read_plm ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ); +/** + * Reads a PLT marker (Packet length, tile-part header) + * + * @param p_header_data the data contained in the PLT box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the PLT marker. + * @param p_manager the user event manager. +*/ +static bool j2k_read_plt ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ); +/** + * Reads a PPM marker (Packed packet headers, main header) + * + * @param p_header_data the data contained in the POC box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the POC marker. + * @param p_manager the user event manager. +*/ +static bool j2k_read_ppm ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ); +/** + * Reads a PPT marker (Packed packet headers, tile-part header) + * + * @param p_header_data the data contained in the PPT box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the PPT marker. + * @param p_manager the user event manager. +*/ +static bool j2k_read_ppt ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ); +/** + * Writes the TLM marker (Tile Length Marker) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static bool j2k_write_tlm( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); +/** + * Writes the SOT marker (Start of tile-part) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static bool j2k_write_sot( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + const struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); +/** + * Reads a PPT marker (Packed packet headers, tile-part header) + * + * @param p_header_data the data contained in the PPT box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the PPT marker. + * @param p_manager the user event manager. +*/ +static bool j2k_read_sot ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ); +/** + * Writes the SOD marker (Start of data) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static bool j2k_write_sod( + opj_j2k_t *p_j2k, + struct opj_tcd * p_tile_coder, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + OPJ_UINT32 p_total_data_size, + const struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); +/** + * Reads a SOD marker (Start Of Data) + * + * @param p_header_data the data contained in the SOD box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the SOD marker. + * @param p_manager the user event manager. +*/ +static bool j2k_read_sod ( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); +/** + * Writes the RGN marker (Region Of Interest) + * + * @param p_tile_no the tile to output + * @param p_comp_no the component to output + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static bool j2k_write_rgn( + opj_j2k_t *p_j2k, + OPJ_UINT32 p_tile_no, + OPJ_UINT32 p_comp_no, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); +/** + * Reads a RGN marker (Region Of Interest) + * + * @param p_header_data the data contained in the POC box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the POC marker. + * @param p_manager the user event manager. +*/ +static bool j2k_read_rgn ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ) ; +/** + * Writes the EOC marker (End of Codestream) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static bool j2k_write_eoc( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); + +/** + * Copies the tile component parameters of all the component from the first tile component. + * + * @param p_j2k the J2k codec. + */ +static void j2k_copy_tile_quantization_parameters( + opj_j2k_t *p_j2k + ); + +/** + * Reads a EOC marker (End Of Codestream) + * + * @param p_header_data the data contained in the SOD box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the SOD marker. + * @param p_manager the user event manager. +*/ +static bool j2k_read_eoc ( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) ; + +/** + * Inits the Info + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static bool j2k_init_info( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); +/** + * Reads an unknown marker + * + * @param p_stream the stream object to read from. + * @param p_j2k the jpeg2000 codec. + * @param p_manager the user event manager. + * + * @return true if the marker could be deduced. +*/ +static bool j2k_read_unk ( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); +/** + * Ends the encoding, i.e. frees memory. + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static bool j2k_end_encoding( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); + +/** + * Writes the CBD marker (Component bit depth definition) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static bool j2k_write_cbd( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); + +/** + * Reads a CBD marker (Component bit depth definition) + * @param p_header_data the data contained in the CBD box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the CBD marker. + * @param p_manager the user event manager. +*/ +static bool j2k_read_cbd ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager); + +/** + * Writes the MCT marker (Multiple Component Transform) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static bool j2k_write_mct_record( + opj_j2k_t *p_j2k, + opj_mct_data_t * p_mct_record, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); + +/** + * Reads a MCT marker (Multiple Component Transform) + * + * @param p_header_data the data contained in the MCT box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the MCT marker. + * @param p_manager the user event manager. +*/ +static bool j2k_read_mct ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ); + +/** + * Writes the MCC marker (Multiple Component Collection) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static bool j2k_write_mcc_record( + opj_j2k_t *p_j2k, + struct opj_simple_mcc_decorrelation_data * p_mcc_record, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); + +/** + * Reads a MCC marker (Multiple Component Collection) + * + * @param p_header_data the data contained in the MCC box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the MCC marker. + * @param p_manager the user event manager. +*/ +static bool j2k_read_mcc ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ); + +/** + * Writes the MCO marker (Multiple component transformation ordering) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static bool j2k_write_mco( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); + +/** + * Reads a MCO marker (Multiple Component Transform Ordering) + * + * @param p_header_data the data contained in the MCO box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the MCO marker. + * @param p_manager the user event manager. +*/ +static bool j2k_read_mco ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ); +/** + * Writes the image components. + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static bool j2k_write_image_components( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); + +/** + * Writes regions of interests. + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static bool j2k_write_regions( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); +/** + * Writes EPC ???? + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static bool j2k_write_epc( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); + +/** + * Checks the progression order changes values. Tells of the poc given as input are valid. + * A nice message is outputted at errors. + * + * @param p_pocs the progression order changes. + * @param p_nb_pocs the number of progression order changes. + * @param p_nb_resolutions the number of resolutions. + * @param numcomps the number of components + * @param numlayers the number of layers. + * + * @return true if the pocs are valid. + */ +static bool j2k_check_poc_val( + const opj_poc_t *p_pocs, + OPJ_UINT32 p_nb_pocs, + OPJ_UINT32 p_nb_resolutions, + OPJ_UINT32 numcomps, + OPJ_UINT32 numlayers, + opj_event_mgr_t * p_manager); + +/** + * Gets the number of tile parts used for the given change of progression (if any) and the given tile. + * + * @param cp the coding parameters. + * @param pino the offset of the given poc (i.e. its position in the coding parameter). + * @param tileno the given tile. + * + * @return the number of tile parts. + */ +static OPJ_UINT32 j2k_get_num_tp( + opj_cp_t *cp, + OPJ_UINT32 pino, + OPJ_UINT32 tileno); +/** + * Calculates the total number of tile parts needed by the encoder to + * encode such an image. If not enough memory is available, then the function return false. + * + * @param p_nb_tiles pointer that will hold the number of tile parts. + * @param cp the coding parameters for the image. + * @param image the image to encode. + * @param p_j2k the p_j2k encoder. + * @param p_manager the user event manager. + * + * @return true if the function was successful, false else. + */ +static bool j2k_calculate_tp( + opj_j2k_t *p_j2k, + opj_cp_t *cp, + OPJ_UINT32 * p_nb_tiles, + opj_image_t *image, + opj_event_mgr_t * p_manager); + +static bool j2k_write_first_tile_part ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + OPJ_UINT32 p_total_data_size, + opj_stream_private_t *p_stream, + struct opj_event_mgr * p_manager + ); +static bool j2k_write_all_tile_parts( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + OPJ_UINT32 p_total_data_size, + opj_stream_private_t *p_stream, + struct opj_event_mgr * p_manager + ); + +/** + * Reads the lookup table containing all the marker, status and action, and returns the handler associated + * with the marker value. + * @param p_id Marker value to look up + * + * @return the handler associated with the id. +*/ +static const struct opj_dec_memory_marker_handler * j2k_get_marker_handler (OPJ_UINT32 p_id); + +/** + * Destroys a tile coding parameter structure. + * + * @param p_tcp the tile coding parameter to destroy. + */ +static void j2k_tcp_destroy (opj_tcp_t *p_tcp); + +static void j2k_get_tile_data (opj_tcd_t * p_tcd, OPJ_BYTE * p_data); + +/** + * Destroys a coding parameter structure. + * + * @param p_cp the coding parameter to destroy. + */ +static void j2k_cp_destroy (opj_cp_t *p_cp); + +/** + * Sets up the validation ,i.e. adds the procedures to lauch to make sure the codec parameters + * are valid. Developpers wanting to extend the library can add their own validation procedures. + */ +static void j2k_setup_encoding_validation (opj_j2k_t *p_j2k); + +/** + * Sets up the validation ,i.e. adds the procedures to lauch to make sure the codec parameters + * are valid. Developpers wanting to extend the library can add their own validation procedures. + */ +static void j2k_setup_decoding_validation (opj_j2k_t *p_j2k); + +/** + * Sets up the validation ,i.e. adds the procedures to lauch to make sure the codec parameters + * are valid. Developpers wanting to extend the library can add their own validation procedures. + */ +static void j2k_setup_end_compress (opj_j2k_t *p_j2k); + +/** + * Creates a tile-coder decoder. + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static bool j2k_create_tcd( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); + +/** + * Excutes the given procedures on the given codec. + * + * @param p_procedure_list the list of procedures to execute + * @param p_j2k the jpeg2000 codec to execute the procedures on. + * @param p_stream the stream to execute the procedures on. + * @param p_manager the user manager. + * + * @return true if all the procedures were successfully executed. + */ +static bool j2k_exec ( + opj_j2k_t * p_j2k, + opj_procedure_list_t * p_procedure_list, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager + ); +/** + * Updates the rates of the tcp. + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static bool j2k_update_rates( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); + +/** + * The default encoding validation procedure without any extension. + * + * @param p_j2k the jpeg2000 codec to validate. + * @param p_stream the input stream to validate. + * @param p_manager the user event manager. + * + * @return true if the parameters are correct. + */ +bool j2k_encoding_validation ( + opj_j2k_t * p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager + ); +/** + * The read header procedure. + */ +bool j2k_read_header_procedure( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager); + +/** + * The default decoding validation procedure without any extension. + * + * @param p_j2k the jpeg2000 codec to validate. + * @param p_stream the input stream to validate. + * @param p_manager the user event manager. + * + * @return true if the parameters are correct. + */ +bool j2k_decoding_validation ( + opj_j2k_t * p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager + ); +/** + * Reads the tiles. + */ +bool j2k_decode_tiles ( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager); + +/** + * The mct encoding validation procedure. + * + * @param p_j2k the jpeg2000 codec to validate. + * @param p_stream the input stream to validate. + * @param p_manager the user event manager. + * + * @return true if the parameters are correct. + */ +bool j2k_mct_validation ( + opj_j2k_t * p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager + ); +/** + * Builds the tcd decoder to use to decode tile. + */ +bool j2k_build_decoder ( + opj_j2k_t * p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager + ); +/** + * Builds the tcd encoder to use to encode tile. + */ +bool j2k_build_encoder ( + opj_j2k_t * p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager + ); +/** + * Copies the decoding tile parameters onto all the tile parameters. + * Creates also the tile decoder. + */ +bool j2k_copy_default_tcp_and_create_tcd( + opj_j2k_t * p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager + ); +/** + * Destroys the memory associated with the decoding of headers. + */ +bool j2k_destroy_header_memory ( + opj_j2k_t * p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager + ); + +/** + * Sets up the procedures to do on writting header. Developpers wanting to extend the library can add their own writting procedures. + */ +void j2k_setup_header_writting (opj_j2k_t *p_j2k); + +/** + * Sets up the procedures to do on reading header. Developpers wanting to extend the library can add their own reading procedures. + */ +void j2k_setup_header_reading (opj_j2k_t *p_j2k); + +/** + * Writes a tile. + * @param p_j2k the jpeg2000 codec. + * @param p_stream the stream to write data to. + * @param p_manager the user event manager. + */ +static bool j2k_post_write_tile ( + opj_j2k_t * p_j2k, + OPJ_BYTE * p_data, + OPJ_UINT32 p_data_size, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager + ); + +static bool j2k_pre_write_tile ( + opj_j2k_t * p_j2k, + OPJ_UINT32 p_tile_index, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager + ); +static bool j2k_update_image_data (opj_tcd_t * p_tcd, OPJ_BYTE * p_data); + +static bool j2k_add_mct(opj_tcp_t * p_tcp,opj_image_t * p_image, OPJ_UINT32 p_index); +/** + * Gets the offset of the header. + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +static bool j2k_get_end_header( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); + +static void j2k_read_int16_to_float (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem); +static void j2k_read_int32_to_float (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem); +static void j2k_read_float32_to_float (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem); +static void j2k_read_float64_to_float (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem); + +static void j2k_read_int16_to_int32 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem); +static void j2k_read_int32_to_int32 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem); +static void j2k_read_float32_to_int32 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem); +static void j2k_read_float64_to_int32 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem); + +static void j2k_write_float_to_int16 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem); +static void j2k_write_float_to_int32 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem); +static void j2k_write_float_to_float (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem); +static void j2k_write_float_to_float64 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem); + + + +/*@}*/ + +/*@}*/ + +/* ----------------------------------------------------------------------- */ + + + +/**************************************************************************** + ********************* CONSTANTS ******************************************** + ****************************************************************************/ + + + + +/** + * List of progression orders. + */ +const j2k_prog_order_t j2k_prog_order_list [] = +{ + {CPRL, "CPRL"}, + {LRCP, "LRCP"}, + {PCRL, "PCRL"}, + {RLCP, "RLCP"}, + {RPCL, "RPCL"}, + {(OPJ_PROG_ORDER)-1, ""} +}; + +const OPJ_UINT32 MCT_ELEMENT_SIZE [] = +{ + 2, + 4, + 4, + 8 +}; + +typedef void (* j2k_mct_function) (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem); + +const j2k_mct_function j2k_mct_read_functions_to_float [] = +{ + j2k_read_int16_to_float, + j2k_read_int32_to_float, + j2k_read_float32_to_float, + j2k_read_float64_to_float +}; + +const j2k_mct_function j2k_mct_read_functions_to_int32 [] = +{ + j2k_read_int16_to_int32, + j2k_read_int32_to_int32, + j2k_read_float32_to_int32, + j2k_read_float64_to_int32 +}; + +const j2k_mct_function j2k_mct_write_functions_from_float [] = +{ + j2k_write_float_to_int16, + j2k_write_float_to_int32, + j2k_write_float_to_float, + j2k_write_float_to_float64 +}; + + + + +/*const opj_dec_stream_marker_handler_t j2k_stream_marker_handler_tab[] = +{ + {J2K_MS_SOC, J2K_DEC_STATE_MHSOC, j2k_read_soc}, + {J2K_MS_SOD, J2K_DEC_STATE_TPH, j2k_read_sod}, + {J2K_MS_EOC, J2K_DEC_STATE_TPHSOT, j2k_read_eoc}, + {J2K_MS_SOP, 0, 0}, +#ifdef USE_JPWL + {J2K_MS_EPC, J2K_DEC_STATE_MH | J2K_DEC_STATE_TPH, j2k_read_epc}, + {J2K_MS_EPB, J2K_DEC_STATE_MH | J2K_DEC_STATE_TPH, j2k_read_epb}, + {J2K_MS_ESD, J2K_DEC_STATE_MH | J2K_DEC_STATE_TPH, j2k_read_esd}, + {J2K_MS_RED, J2K_DEC_STATE_MH | J2K_DEC_STATE_TPH, j2k_read_red}, +#endif +#ifdef USE_JPSEC + {J2K_MS_SEC, J2K_DEC_STATE_MH, j2k_read_sec}, + {J2K_MS_INSEC, 0, j2k_read_insec}, +#endif + + {0, J2K_DEC_STATE_MH | J2K_DEC_STATE_TPH, j2k_read_unk} +};*/ + +const opj_dec_memory_marker_handler_t j2k_memory_marker_handler_tab [] = +{ + {J2K_MS_SOT, J2K_DEC_STATE_MH | J2K_DEC_STATE_TPHSOT, j2k_read_sot}, + {J2K_MS_COD, J2K_DEC_STATE_MH | J2K_DEC_STATE_TPH, j2k_read_cod}, + {J2K_MS_COC, J2K_DEC_STATE_MH | J2K_DEC_STATE_TPH, j2k_read_coc}, + {J2K_MS_RGN, J2K_DEC_STATE_MH | J2K_DEC_STATE_TPH, j2k_read_rgn}, + {J2K_MS_QCD, J2K_DEC_STATE_MH | J2K_DEC_STATE_TPH, j2k_read_qcd}, + {J2K_MS_QCC, J2K_DEC_STATE_MH | J2K_DEC_STATE_TPH, j2k_read_qcc}, + {J2K_MS_POC, J2K_DEC_STATE_MH | J2K_DEC_STATE_TPH, j2k_read_poc}, + {J2K_MS_SIZ, J2K_DEC_STATE_MHSIZ , j2k_read_siz}, + {J2K_MS_TLM, J2K_DEC_STATE_MH, j2k_read_tlm}, + {J2K_MS_PLM, J2K_DEC_STATE_MH, j2k_read_plm}, + {J2K_MS_PLT, J2K_DEC_STATE_TPH, j2k_read_plt}, + {J2K_MS_PPM, J2K_DEC_STATE_MH, j2k_read_ppm}, + {J2K_MS_PPT, J2K_DEC_STATE_TPH, j2k_read_ppt}, + {J2K_MS_SOP, 0, 0}, + {J2K_MS_CRG, J2K_DEC_STATE_MH, j2k_read_crg}, + {J2K_MS_COM, J2K_DEC_STATE_MH | J2K_DEC_STATE_TPH, j2k_read_com}, + {J2K_MS_MCT, J2K_DEC_STATE_MH | J2K_DEC_STATE_TPH, j2k_read_mct}, + {J2K_MS_CBD, J2K_DEC_STATE_MH , j2k_read_cbd}, + {J2K_MS_MCC, J2K_DEC_STATE_MH | J2K_DEC_STATE_TPH, j2k_read_mcc}, + {J2K_MS_MCO, J2K_DEC_STATE_MH | J2K_DEC_STATE_TPH, j2k_read_mco}, +#ifdef USE_JPWL + {J2K_MS_EPC, J2K_DEC_STATE_MH | J2K_DEC_STATE_TPH, j2k_read_epc}, + {J2K_MS_EPB, J2K_DEC_STATE_MH | J2K_DEC_STATE_TPH, j2k_read_epb}, + {J2K_MS_ESD, J2K_DEC_STATE_MH | J2K_DEC_STATE_TPH, j2k_read_esd}, + {J2K_MS_RED, J2K_DEC_STATE_MH | J2K_DEC_STATE_TPH, j2k_read_red}, +#endif /* USE_JPWL */ +#ifdef USE_JPSEC + {J2K_MS_SEC, J2K_DEC_STATE_MH, j2k_read_sec}, + {J2K_MS_INSEC, 0, j2k_read_insec} +#endif /* USE_JPSEC */ +}; + +void j2k_read_int16_to_float (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem) +{ + OPJ_BYTE * l_src_data = (OPJ_BYTE *) p_src_data; + OPJ_FLOAT32 * l_dest_data = (OPJ_FLOAT32 *) p_dest_data; + OPJ_UINT32 i; + OPJ_UINT32 l_temp; + + for + (i=0;ienum_prog != -1; ++po ) + { + if + (po->enum_prog == p_prg_order) + { + return po->str_prog; + } + } + return po->str_prog; +} + + + + + + + +/** + * Checks the progression order changes values. Tells if the poc given as input are valid. + * + * @param p_pocs the progression order changes. + * @param p_nb_pocs the number of progression order changes. + * @param p_nb_resolutions the number of resolutions. + * @param numcomps the number of components + * @param numlayers the number of layers. + * @param p_manager the user event manager. + * + * @return true if the pocs are valid. + */ +bool j2k_check_poc_val(const opj_poc_t *p_pocs, OPJ_UINT32 p_nb_pocs, OPJ_UINT32 p_nb_resolutions, OPJ_UINT32 p_num_comps, OPJ_UINT32 p_num_layers, opj_event_mgr_t * p_manager) +{ + OPJ_UINT32* packet_array; + OPJ_UINT32 index , resno, compno, layno; + OPJ_UINT32 i; + OPJ_UINT32 step_c = 1; + OPJ_UINT32 step_r = p_num_comps * step_c; + OPJ_UINT32 step_l = p_nb_resolutions * step_r; + bool loss = false; + OPJ_UINT32 layno0 = 0; + + packet_array = (OPJ_UINT32*) opj_calloc(step_l * p_num_layers, sizeof(OPJ_UINT32)); + if + (packet_array == 00) + { + opj_event_msg(p_manager , EVT_ERROR, "Not enough memory for checking the poc values.\n"); + return false; + } + memset(packet_array,0,step_l * p_num_layers* sizeof(OPJ_UINT32)); + if + (p_nb_pocs == 0) + { + return true; + } + + index = step_r * p_pocs->resno0; + // take each resolution for each poc + for + (resno = p_pocs->resno0 ; resno < p_pocs->resno1 ; ++resno) + { + OPJ_UINT32 res_index = index + p_pocs->compno0 * step_c; + // take each comp of each resolution for each poc + for + (compno = p_pocs->compno0 ; compno < p_pocs->compno1 ; ++compno) + { + OPJ_UINT32 comp_index = res_index + layno0 * step_l; + // and finally take each layer of each res of ... + for + (layno = layno0; layno < p_pocs->layno1 ; ++layno) + { + //index = step_r * resno + step_c * compno + step_l * layno; + packet_array[comp_index] = 1; + comp_index += step_l; + } + res_index += step_c; + } + index += step_r; + } + ++p_pocs; + // iterate through all the pocs + for + (i = 1; i < p_nb_pocs ; ++i) + { + OPJ_UINT32 l_last_layno1 = (p_pocs-1)->layno1 ; + layno0 = (p_pocs->layno1 > l_last_layno1)? l_last_layno1 : 0; + index = step_r * p_pocs->resno0; + // take each resolution for each poc + for + (resno = p_pocs->resno0 ; resno < p_pocs->resno1 ; ++resno) + { + OPJ_UINT32 res_index = index + p_pocs->compno0 * step_c; + // take each comp of each resolution for each poc + for + (compno = p_pocs->compno0 ; compno < p_pocs->compno1 ; ++compno) + { + OPJ_UINT32 comp_index = res_index + layno0 * step_l; + // and finally take each layer of each res of ... + for + (layno = layno0; layno < p_pocs->layno1 ; ++layno) + { + //index = step_r * resno + step_c * compno + step_l * layno; + packet_array[comp_index] = 1; + comp_index += step_l; + } + res_index += step_c; + } + index += step_r; + } + ++p_pocs; + } + + index = 0; + for + (layno = 0; layno < p_num_layers ; ++layno) + { + for + (resno = 0; resno < p_nb_resolutions; ++resno) + { + for + (compno = 0; compno < p_num_comps; ++compno) + { + loss |= (packet_array[index]!=1); + //index = step_r * resno + step_c * compno + step_l * layno; + index += step_c; + } + } + } + if + (loss) + { + opj_event_msg(p_manager , EVT_ERROR, "Missing packets possible loss of data\n"); + } + opj_free(packet_array); + return !loss; +} + + +/* ----------------------------------------------------------------------- */ + +/** + * Gets the number of tile parts used for the given change of progression (if any) and the given tile. + * + * @param cp the coding parameters. + * @param pino the offset of the given poc (i.e. its position in the coding parameter). + * @param tileno the given tile. + * + * @return the number of tile parts. + */ +OPJ_UINT32 j2k_get_num_tp(opj_cp_t *cp,OPJ_UINT32 pino,OPJ_UINT32 tileno) +{ + const OPJ_CHAR *prog = 00; + OPJ_UINT32 i; + OPJ_UINT32 tpnum = 1; + opj_tcp_t *tcp = 00; + opj_poc_t * l_current_poc = 00; + + // preconditions only in debug + assert(tileno < (cp->tw * cp->th)); + assert(pino < (cp->tcps[tileno].numpocs + 1)); + + // get the given tile coding parameter + tcp = &cp->tcps[tileno]; + assert(tcp != 00); + l_current_poc = &(tcp->pocs[pino]); + assert(l_current_poc != 0); + + // get the progression order as a character string + prog = j2k_convert_progression_order(tcp->prg); + assert(strlen(prog) > 0); + + if + (cp->m_specific_param.m_enc.m_tp_on == 1) + { + for + (i=0;i<4;++i) + { + switch + (prog[i]) + { + // component wise + case 'C': + tpnum *= l_current_poc->compE; + break; + // resolution wise + case 'R': + tpnum *= l_current_poc->resE; + break; + // precinct wise + case 'P': + tpnum *= l_current_poc->prcE; + break; + // layer wise + case 'L': + tpnum *= l_current_poc->layE; + break; + } + // whould we split here ? + if + ( cp->m_specific_param.m_enc.m_tp_flag == prog[i] ) + { + cp->m_specific_param.m_enc.m_tp_pos=i; + break; + } + } + } + else + { + tpnum=1; + } + return tpnum; +} + +/** + * Calculates the total number of tile parts needed by the encoder to + * encode such an image. If not enough memory is available, then the function return false. + * + * @param p_nb_tiles pointer that will hold the number of tile parts. + * @param cp the coding parameters for the image. + * @param image the image to encode. + * @param p_j2k the p_j2k encoder. + * @param p_manager the user event manager. + * + * @return true if the function was successful, false else. + */ +bool j2k_calculate_tp( + opj_j2k_t *p_j2k, + opj_cp_t *cp, + OPJ_UINT32 * p_nb_tiles, + opj_image_t *image, + opj_event_mgr_t * p_manager) +{ + OPJ_UINT32 pino,tileno; + OPJ_UINT32 l_nb_tiles; + opj_tcp_t *tcp; + + // preconditions + assert(p_nb_tiles != 00); + assert(cp != 00); + assert(image != 00); + assert(p_j2k != 00); + assert(p_manager != 00); + + l_nb_tiles = cp->tw * cp->th; + * p_nb_tiles = 0; + tcp = cp->tcps; + + /* INDEX >> */ + if + (p_j2k->cstr_info) + { + opj_tile_info_t * l_info_tile_ptr = p_j2k->cstr_info->tile; + for + (tileno = 0; tileno < l_nb_tiles; ++tileno) + { + OPJ_UINT32 cur_totnum_tp = 0; + pi_update_encoding_parameters(image,cp,tileno); + for + (pino = 0; pino <= tcp->numpocs; ++pino) + { + OPJ_UINT32 tp_num = j2k_get_num_tp(cp,pino,tileno); + *p_nb_tiles = *p_nb_tiles + tp_num; + cur_totnum_tp += tp_num; + } + tcp->m_nb_tile_parts = cur_totnum_tp; + l_info_tile_ptr->tp = (opj_tp_info_t *) opj_malloc(cur_totnum_tp * sizeof(opj_tp_info_t)); + if + (l_info_tile_ptr->tp == 00) + { + return false; + } + memset(l_info_tile_ptr->tp,0,cur_totnum_tp * sizeof(opj_tp_info_t)); + l_info_tile_ptr->num_tps = cur_totnum_tp; + ++l_info_tile_ptr; + ++tcp; + } + } + else + { + for + (tileno = 0; tileno < l_nb_tiles; ++tileno) + { + OPJ_UINT32 cur_totnum_tp = 0; + pi_update_encoding_parameters(image,cp,tileno); + for + (pino = 0; pino <= tcp->numpocs; ++pino) + { + OPJ_UINT32 tp_num=0; + tp_num = j2k_get_num_tp(cp,pino,tileno); + *p_nb_tiles = *p_nb_tiles + tp_num; + cur_totnum_tp += tp_num; + } + tcp->m_nb_tile_parts = cur_totnum_tp; + ++tcp; + } + } + return true; +} + +/** + * Writes the SOC marker (Start Of Codestream) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ + +bool j2k_write_soc( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + /* 2 bytes will be written */ + OPJ_BYTE * l_start_stream = 00; + + // preconditions + assert(p_stream != 00); + assert(p_j2k != 00); + assert(p_manager != 00); + + l_start_stream = p_j2k->m_specific_param.m_encoder.m_header_tile_data; + + /* write SOC identifier */ + opj_write_bytes(l_start_stream,J2K_MS_SOC,2); + if + (opj_stream_write_data(p_stream,l_start_stream,2,p_manager) != 2) + { + return false; + } +/* UniPG>> */ +#ifdef USE_JPWL + /* update markers struct */ + j2k_add_marker(p_j2k->cstr_info, J2K_MS_SOC, p_stream_tell(p_stream) - 2, 2); +#endif /* USE_JPWL */ + return true; +/* <m_specific_param.m_decoder.m_state = J2K_DEC_STATE_MHSIZ; + /* Index */ + if + (p_j2k->cstr_info) + { + //TODO p_j2k->cstr_info->main_head_start = opj_stream_tell(p_stream) - 2; // why - 2 ? + p_j2k->cstr_info->codestream_size = 0;/*p_stream_numbytesleft(p_j2k->p_stream) + 2 - p_j2k->cstr_info->main_head_start*/; + } + return true; +} + +/** + * Writes the SIZ marker (image and tile size) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_write_siz( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 i; + OPJ_UINT32 l_size_len; + OPJ_BYTE * l_current_ptr; + opj_image_t * l_image = 00; + opj_cp_t *cp = 00; + opj_image_comp_t * l_img_comp = 00; + + // preconditions + assert(p_stream != 00); + assert(p_j2k != 00); + assert(p_manager != 00); + + l_image = p_j2k->m_image; + cp = &(p_j2k->m_cp); + l_size_len = 40 + 3 * l_image->numcomps; + l_img_comp = l_image->comps; + + if + (l_size_len > p_j2k->m_specific_param.m_encoder.m_header_tile_data_size) + { + p_j2k->m_specific_param.m_encoder.m_header_tile_data + = (OPJ_BYTE*)opj_realloc( + p_j2k->m_specific_param.m_encoder.m_header_tile_data, + l_size_len); + if + (! p_j2k->m_specific_param.m_encoder.m_header_tile_data) + { + return false; + } + p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = l_size_len; + } + + l_current_ptr = p_j2k->m_specific_param.m_encoder.m_header_tile_data; + + /* write SOC identifier */ + opj_write_bytes(l_current_ptr,J2K_MS_SIZ,2); /* SIZ */ + l_current_ptr+=2; + opj_write_bytes(l_current_ptr,l_size_len-2,2); /* L_SIZ */ + l_current_ptr+=2; + opj_write_bytes(l_current_ptr, cp->rsiz, 2); /* Rsiz (capabilities) */ + l_current_ptr+=2; + opj_write_bytes(l_current_ptr, l_image->x1, 4); /* Xsiz */ + l_current_ptr+=4; + opj_write_bytes(l_current_ptr, l_image->y1, 4); /* Ysiz */ + l_current_ptr+=4; + opj_write_bytes(l_current_ptr, l_image->x0, 4); /* X0siz */ + l_current_ptr+=4; + opj_write_bytes(l_current_ptr, l_image->y0, 4); /* Y0siz */ + l_current_ptr+=4; + opj_write_bytes(l_current_ptr, cp->tdx, 4); /* XTsiz */ + l_current_ptr+=4; + opj_write_bytes(l_current_ptr, cp->tdy, 4); /* YTsiz */ + l_current_ptr+=4; + opj_write_bytes(l_current_ptr, cp->tx0, 4); /* XT0siz */ + l_current_ptr+=4; + opj_write_bytes(l_current_ptr, cp->ty0, 4); /* YT0siz */ + l_current_ptr+=4; + opj_write_bytes(l_current_ptr, l_image->numcomps, 2); /* Csiz */ + l_current_ptr+=2; + for + (i = 0; i < l_image->numcomps; ++i) + { + // TODO here with MCT ? + opj_write_bytes(l_current_ptr, l_img_comp->prec - 1 + (l_img_comp->sgnd << 7), 1); /* Ssiz_i */ + ++l_current_ptr; + opj_write_bytes(l_current_ptr, l_img_comp->dx, 1); /* XRsiz_i */ + ++l_current_ptr; + opj_write_bytes(l_current_ptr, l_img_comp->dy, 1); /* YRsiz_i */ + ++l_current_ptr; + ++l_img_comp; + } + if + (opj_stream_write_data(p_stream,p_j2k->m_specific_param.m_encoder.m_header_tile_data,l_size_len,p_manager) != l_size_len) + { + return false; + } + return true; +} + +/** + * Reads a SIZ marker (image and tile size) + * @param p_header_data the data contained in the SIZ box. + * @param jp2 the jpeg2000 file codec. + * @param p_header_size the size of the data contained in the SIZ marker. + * @param p_manager the user event manager. +*/ +bool j2k_read_siz ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 l_size, i; + OPJ_UINT32 l_nb_comp; + OPJ_UINT32 l_nb_comp_remain; + OPJ_UINT32 l_remaining_size; + OPJ_UINT32 l_nb_tiles; + OPJ_UINT32 l_tmp; + opj_image_t *l_image = 00; + opj_cp_t *l_cp = 00; + opj_image_comp_t * l_img_comp = 00; + opj_tcp_t * l_current_tile_param = 00; + + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_header_data != 00); + + l_image = p_j2k->m_image; + l_cp = &(p_j2k->m_cp); + if + (p_header_size < 36) + { + opj_event_msg(p_manager, EVT_ERROR, "Error with SIZ marker size\n"); + return false; + } + l_remaining_size = p_header_size - 36; + + l_nb_comp = l_remaining_size / 3; + l_nb_comp_remain = l_remaining_size % 3; + if + (l_nb_comp_remain != 0) + { + opj_event_msg(p_manager, EVT_ERROR, "Error with SIZ marker size\n"); + return false; + } + l_size = p_header_size + 2; /* Lsiz */ + + opj_read_bytes(p_header_data,&l_tmp ,2); /* Rsiz (capabilities) */ + p_header_data+=2; + l_cp->rsiz = (OPJ_RSIZ_CAPABILITIES) l_tmp; + opj_read_bytes(p_header_data,(OPJ_UINT32 *) (&l_image->x1) ,4); /* Xsiz */ + p_header_data+=4; + opj_read_bytes(p_header_data,(OPJ_UINT32*) (&l_image->y1),4); /* Ysiz */ + p_header_data+=4; + opj_read_bytes(p_header_data,(OPJ_UINT32*) &l_image->x0,4); /* X0siz */ + p_header_data+=4; + opj_read_bytes(p_header_data,(OPJ_UINT32*) &l_image->y0,4); /* Y0siz */ + p_header_data+=4; + opj_read_bytes(p_header_data, (&l_cp->tdx),4); /* XTsiz */ + p_header_data+=4; + opj_read_bytes(p_header_data,&l_cp->tdy,4); /* YTsiz */ + p_header_data+=4; + opj_read_bytes(p_header_data,(OPJ_UINT32 *) (&l_cp->tx0),4); /* XT0siz */ + p_header_data+=4; + opj_read_bytes(p_header_data,(OPJ_UINT32 *) (&l_cp->ty0),4); /* YT0siz */ + p_header_data+=4; + opj_read_bytes(p_header_data,(&l_image->numcomps),2); /* Csiz */ + p_header_data+=2; + if + (l_image->numcomps != l_nb_comp) + { + opj_event_msg(p_manager, EVT_ERROR, "Error with SIZ marker size\n"); + return false; + } + +#ifdef USE_JPWL + if (p_j2k->m_cp->correct) { + /* if JPWL is on, we check whether TX errors have damaged + too much the SIZ parameters */ + if (!(image->x1 * image->y1)) { + opj_event_msg(p_j2k->cinfo, EVT_ERROR, + "JPWL: bad image size (%d x %d)\n", + image->x1, image->y1); + if (!JPWL_ASSUME || JPWL_ASSUME) { + opj_event_msg(p_j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + return; + } + } + if (image->numcomps != ((len - 38) / 3)) { + opj_event_msg(p_j2k->cinfo, JPWL_ASSUME ? EVT_WARNING : EVT_ERROR, + "JPWL: Csiz is %d => space in SIZ only for %d comps.!!!\n", + image->numcomps, ((len - 38) / 3)); + if (!JPWL_ASSUME) { + opj_event_msg(p_j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + return; + } + /* we try to correct */ + opj_event_msg(p_j2k->cinfo, EVT_WARNING, "- trying to adjust this\n"); + if (image->numcomps < ((len - 38) / 3)) { + len = 38 + 3 * image->numcomps; + opj_event_msg(p_j2k->cinfo, EVT_WARNING, "- setting Lsiz to %d => HYPOTHESIS!!!\n", + len); + } else { + image->numcomps = ((len - 38) / 3); + opj_event_msg(p_j2k->cinfo, EVT_WARNING, "- setting Csiz to %d => HYPOTHESIS!!!\n", + image->numcomps); + } + } + + /* update components number in the jpwl_exp_comps filed */ + cp->exp_comps = image->numcomps; + } +#endif /* USE_JPWL */ + + l_image->comps = (opj_image_comp_t*) opj_calloc(l_image->numcomps, sizeof(opj_image_comp_t)); + if + (l_image->comps == 00) + { + l_image->numcomps = 0; + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to take in charge SIZ marker\n"); + return false; + } + memset(l_image->comps,0,l_image->numcomps * sizeof(opj_image_comp_t)); + l_img_comp = l_image->comps; + for + (i = 0; i < l_image->numcomps; ++i) + { + OPJ_UINT32 tmp; + opj_read_bytes(p_header_data,&tmp,1); /* Ssiz_i */ + ++p_header_data; + l_img_comp->prec = (tmp & 0x7f) + 1; + l_img_comp->sgnd = tmp >> 7; + opj_read_bytes(p_header_data,&l_img_comp->dx,1); /* XRsiz_i */ + ++p_header_data; + opj_read_bytes(p_header_data,&l_img_comp->dy,1); /* YRsiz_i */ + ++p_header_data; +#ifdef USE_JPWL + if (p_j2k->m_cp->correct) { + /* if JPWL is on, we check whether TX errors have damaged + too much the SIZ parameters, again */ + if (!(image->comps[i].dx * image->comps[i].dy)) { + opj_event_msg(p_j2k->cinfo, JPWL_ASSUME ? EVT_WARNING : EVT_ERROR, + "JPWL: bad XRsiz_%d/YRsiz_%d (%d x %d)\n", + i, i, image->comps[i].dx, image->comps[i].dy); + if (!JPWL_ASSUME) { + opj_event_msg(p_j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + return; + } + /* we try to correct */ + opj_event_msg(p_j2k->cinfo, EVT_WARNING, "- trying to adjust them\n"); + if (!image->comps[i].dx) { + image->comps[i].dx = 1; + opj_event_msg(p_j2k->cinfo, EVT_WARNING, "- setting XRsiz_%d to %d => HYPOTHESIS!!!\n", + i, image->comps[i].dx); + } + if (!image->comps[i].dy) { + image->comps[i].dy = 1; + opj_event_msg(p_j2k->cinfo, EVT_WARNING, "- setting YRsiz_%d to %d => HYPOTHESIS!!!\n", + i, image->comps[i].dy); + } + } + + } +#endif /* USE_JPWL */ + l_img_comp->resno_decoded = 0; /* number of resolution decoded */ + l_img_comp->factor = l_cp->m_specific_param.m_dec.m_reduce; /* reducing factor per component */ + ++l_img_comp; + } + + l_cp->tw = int_ceildiv(l_image->x1 - l_cp->tx0, l_cp->tdx); + l_cp->th = int_ceildiv(l_image->y1 - l_cp->ty0, l_cp->tdy); + l_nb_tiles = l_cp->tw * l_cp->th; + if + (p_j2k->m_specific_param.m_decoder.m_discard_tiles) + { + p_j2k->m_specific_param.m_decoder.m_start_tile_x = (p_j2k->m_specific_param.m_decoder.m_start_tile_x - l_cp->tx0) / l_cp->tdx; + p_j2k->m_specific_param.m_decoder.m_start_tile_y = (p_j2k->m_specific_param.m_decoder.m_start_tile_y - l_cp->ty0) / l_cp->tdy; + p_j2k->m_specific_param.m_decoder.m_end_tile_x = int_ceildiv((p_j2k->m_specific_param.m_decoder.m_end_tile_x - l_cp->tx0), l_cp->tdx); + p_j2k->m_specific_param.m_decoder.m_end_tile_y = int_ceildiv((p_j2k->m_specific_param.m_decoder.m_end_tile_y - l_cp->ty0), l_cp->tdy); + } + else + { + p_j2k->m_specific_param.m_decoder.m_start_tile_x = 0; + p_j2k->m_specific_param.m_decoder.m_start_tile_y = 0; + p_j2k->m_specific_param.m_decoder.m_end_tile_x = l_cp->tw; + p_j2k->m_specific_param.m_decoder.m_end_tile_y = l_cp->th; + } + +#ifdef USE_JPWL + if (p_j2k->m_cp->correct) { + /* if JPWL is on, we check whether TX errors have damaged + too much the SIZ parameters */ + if ((cp->tw < 1) || (cp->th < 1) || (cp->tw > cp->max_tiles) || (cp->th > cp->max_tiles)) { + opj_event_msg(p_j2k->cinfo, JPWL_ASSUME ? EVT_WARNING : EVT_ERROR, + "JPWL: bad number of tiles (%d x %d)\n", + cp->tw, cp->th); + if (!JPWL_ASSUME) { + opj_event_msg(p_j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + return; + } + /* we try to correct */ + opj_event_msg(p_j2k->cinfo, EVT_WARNING, "- trying to adjust them\n"); + if (cp->tw < 1) { + cp->tw= 1; + opj_event_msg(p_j2k->cinfo, EVT_WARNING, "- setting %d tiles in x => HYPOTHESIS!!!\n", + cp->tw); + } + if (cp->tw > cp->max_tiles) { + cp->tw= 1; + opj_event_msg(p_j2k->cinfo, EVT_WARNING, "- too large x, increase expectance of %d\n" + "- setting %d tiles in x => HYPOTHESIS!!!\n", + cp->max_tiles, cp->tw); + } + if (cp->th < 1) { + cp->th= 1; + opj_event_msg(p_j2k->cinfo, EVT_WARNING, "- setting %d tiles in y => HYPOTHESIS!!!\n", + cp->th); + } + if (cp->th > cp->max_tiles) { + cp->th= 1; + opj_event_msg(p_j2k->cinfo, EVT_WARNING, "- too large y, increase expectance of %d to continue\n", + "- setting %d tiles in y => HYPOTHESIS!!!\n", + cp->max_tiles, cp->th); + } + } + } +#endif /* USE_JPWL */ + /* memory allocations */ + l_cp->tcps = (opj_tcp_t*) opj_calloc(l_nb_tiles, sizeof(opj_tcp_t)); + if + (l_cp->tcps == 00) + { + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to take in charge SIZ marker\n"); + return false; + } + memset(l_cp->tcps,0,l_nb_tiles*sizeof(opj_tcp_t)); + +#ifdef USE_JPWL + if (p_j2k->m_cp->correct) { + if (!cp->tcps) { + opj_event_msg(p_j2k->cinfo, JPWL_ASSUME ? EVT_WARNING : EVT_ERROR, + "JPWL: could not alloc tcps field of cp\n"); + if (!JPWL_ASSUME || JPWL_ASSUME) { + opj_event_msg(p_j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + return; + } + } + } +#endif /* USE_JPWL */ + + p_j2k->m_specific_param.m_decoder.m_default_tcp->tccps = (opj_tccp_t*) opj_calloc(l_image->numcomps, sizeof(opj_tccp_t)); + if + (p_j2k->m_specific_param.m_decoder.m_default_tcp->tccps == 00) + { + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to take in charge SIZ marker\n"); + return false; + } + memset(p_j2k->m_specific_param.m_decoder.m_default_tcp->tccps ,0,l_image->numcomps*sizeof(opj_tccp_t)); + + p_j2k->m_specific_param.m_decoder.m_default_tcp->m_mct_records = + (opj_mct_data_t*)opj_malloc(J2K_MCT_DEFAULT_NB_RECORDS * sizeof(opj_mct_data_t)); + if + (! p_j2k->m_specific_param.m_decoder.m_default_tcp->m_mct_records) + { + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to take in charge SIZ marker\n"); + return false; + } + memset(p_j2k->m_specific_param.m_decoder.m_default_tcp->m_mct_records,0,J2K_MCT_DEFAULT_NB_RECORDS * sizeof(opj_mct_data_t)); + p_j2k->m_specific_param.m_decoder.m_default_tcp->m_nb_max_mct_records = J2K_MCT_DEFAULT_NB_RECORDS; + + p_j2k->m_specific_param.m_decoder.m_default_tcp->m_mcc_records = + (opj_simple_mcc_decorrelation_data_t*) + opj_malloc(J2K_MCC_DEFAULT_NB_RECORDS * sizeof(opj_simple_mcc_decorrelation_data_t)); + if + (! p_j2k->m_specific_param.m_decoder.m_default_tcp->m_mcc_records) + { + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to take in charge SIZ marker\n"); + return false; + } + memset(p_j2k->m_specific_param.m_decoder.m_default_tcp->m_mcc_records,0,J2K_MCC_DEFAULT_NB_RECORDS * sizeof(opj_simple_mcc_decorrelation_data_t)); + p_j2k->m_specific_param.m_decoder.m_default_tcp->m_nb_max_mcc_records = J2K_MCC_DEFAULT_NB_RECORDS; + + /* set up default dc level shift */ + for + (i=0;inumcomps;++i) + { + if + (! l_image->comps[i].sgnd) + { + p_j2k->m_specific_param.m_decoder.m_default_tcp->tccps[i].m_dc_level_shift = 1 << (l_image->comps[i].prec - 1); + } + } + + l_current_tile_param = l_cp->tcps; + for + (i = 0; i < l_nb_tiles; ++i) + { + l_current_tile_param->tccps = (opj_tccp_t*) opj_malloc(l_image->numcomps * sizeof(opj_tccp_t)); + if + (l_current_tile_param->tccps == 00) + { + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to take in charge SIZ marker\n"); + return false; + } + memset(l_current_tile_param->tccps,0,l_image->numcomps * sizeof(opj_tccp_t)); + + ++l_current_tile_param; + + } + p_j2k->m_specific_param.m_decoder.m_state = J2K_DEC_STATE_MH; + opj_image_comp_update(l_image,l_cp); + + /* Index */ + if + (p_j2k->cstr_info) + { + opj_codestream_info_t *cstr_info = p_j2k->cstr_info; + cstr_info->image_w = l_image->x1 - l_image->x0; + cstr_info->image_h = l_image->y1 - l_image->y0; + cstr_info->numcomps = l_image->numcomps; + cstr_info->tw = l_cp->tw; + cstr_info->th = l_cp->th; + cstr_info->tile_x = l_cp->tdx; + cstr_info->tile_y = l_cp->tdy; + cstr_info->tile_Ox = l_cp->tx0; + cstr_info->tile_Oy = l_cp->ty0; + cstr_info->tile = (opj_tile_info_t*) opj_calloc(l_nb_tiles, sizeof(opj_tile_info_t)); + if + (cstr_info->tile == 00) + { + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to take in charge SIZ marker\n"); + return false; + } + memset(cstr_info->tile,0,l_nb_tiles * sizeof(opj_tile_info_t)); + } + return true; +} + +/** + * Writes the COM marker (comment) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_write_com( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 l_comment_size; + OPJ_UINT32 l_total_com_size; + const OPJ_CHAR *l_comment; + OPJ_BYTE * l_current_ptr = 00; + + // preconditions + assert(p_j2k != 00); + assert(p_stream != 00); + assert(p_manager != 00); + + l_comment = p_j2k->m_cp.comment; + l_comment_size = strlen(l_comment); + l_total_com_size = l_comment_size + 6; + + if + (l_total_com_size > p_j2k->m_specific_param.m_encoder.m_header_tile_data_size) + { + p_j2k->m_specific_param.m_encoder.m_header_tile_data + = (OPJ_BYTE*)opj_realloc( + p_j2k->m_specific_param.m_encoder.m_header_tile_data, + l_total_com_size); + if + (! p_j2k->m_specific_param.m_encoder.m_header_tile_data) + { + return false; + } + p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = l_total_com_size; + } + l_current_ptr = p_j2k->m_specific_param.m_encoder.m_header_tile_data; + opj_write_bytes(l_current_ptr,J2K_MS_COM , 2); /* COM */ + l_current_ptr+=2; + opj_write_bytes(l_current_ptr,l_total_com_size - 2 , 2); /* L_COM */ + l_current_ptr+=2; + opj_write_bytes(l_current_ptr,1 , 2); /* General use (IS 8859-15:1999 (Latin) values) */ + l_current_ptr+=2, + memcpy( l_current_ptr,l_comment,l_comment_size); + if + (opj_stream_write_data(p_stream,p_j2k->m_specific_param.m_encoder.m_header_tile_data,l_total_com_size,p_manager) != l_total_com_size) + { + return false; + } + return true; +} + +/** + * Reads a COM marker (comments) + * @param p_header_data the data contained in the COM box. + * @param jp2 the jpeg2000 file codec. + * @param p_header_size the size of the data contained in the COM marker. + * @param p_manager the user event manager. +*/ +bool j2k_read_com ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ) +{ + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_header_data != 00); + return true; +} + +/** + * Gets the size taken by writting a SPCod or SPCoc for the given tile and component. + * + * @param p_tile_no the tile indix. + * @param p_comp_no the component being outputted. + * @param p_j2k the J2K codec. + * + * @return the number of bytes taken by the SPCod element. + */ +OPJ_UINT32 j2k_get_SPCod_SPCoc_size ( + opj_j2k_t *p_j2k, + OPJ_UINT32 p_tile_no, + OPJ_UINT32 p_comp_no + ) +{ + opj_cp_t *l_cp = 00; + opj_tcp_t *l_tcp = 00; + opj_tccp_t *l_tccp = 00; + + // preconditions + assert(p_j2k != 00); + + l_cp = &(p_j2k->m_cp); + l_tcp = &l_cp->tcps[p_tile_no]; + l_tccp = &l_tcp->tccps[p_comp_no]; + + // preconditions again + assert(p_tile_no < (l_cp->tw * l_cp->th)); + assert(p_comp_no < p_j2k->m_image->numcomps); + + if + (l_tccp->csty & J2K_CCP_CSTY_PRT) + { + return 5 + l_tccp->numresolutions; + } + else + { + return 5; + } +} + + +/** + * Writes a SPCod or SPCoc element, i.e. the coding style of a given component of a tile. + * + * @param p_comp_no the component number to output. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. + * +*/ +bool j2k_write_SPCod_SPCoc( + opj_j2k_t *p_j2k, + OPJ_UINT32 p_tile_no, + OPJ_UINT32 p_comp_no, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_header_size, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 i; + opj_cp_t *l_cp = 00; + opj_tcp_t *l_tcp = 00; + opj_tccp_t *l_tccp = 00; + + // preconditions + assert(p_j2k != 00); + assert(p_header_size != 00); + assert(p_manager != 00); + assert(p_data != 00); + + l_cp = &(p_j2k->m_cp); + l_tcp = &l_cp->tcps[p_tile_no]; + l_tccp = &l_tcp->tccps[p_comp_no]; + + // preconditions again + assert(p_tile_no < (l_cp->tw * l_cp->th)); + assert(p_comp_no <(p_j2k->m_image->numcomps)); + + if + (*p_header_size < 5) + { + opj_event_msg(p_manager, EVT_ERROR, "Error writting SPCod SPCoc element\n"); + return false; + } + + opj_write_bytes(p_data,l_tccp->numresolutions - 1, 1); /* SPcoc (D) */ + ++p_data; + opj_write_bytes(p_data,l_tccp->cblkw - 2, 1); /* SPcoc (E) */ + ++p_data; + opj_write_bytes(p_data,l_tccp->cblkh - 2, 1); /* SPcoc (F) */ + ++p_data; + opj_write_bytes(p_data,l_tccp->cblksty, 1); /* SPcoc (G) */ + ++p_data; + opj_write_bytes(p_data,l_tccp->qmfbid, 1); /* SPcoc (H) */ + ++p_data; + + *p_header_size = *p_header_size - 5; + if + (l_tccp->csty & J2K_CCP_CSTY_PRT) + { + if + (*p_header_size < l_tccp->numresolutions) + { + opj_event_msg(p_manager, EVT_ERROR, "Error writting SPCod SPCoc element\n"); + return false; + } + for + (i = 0; i < l_tccp->numresolutions; ++i) + { + opj_write_bytes(p_data,l_tccp->prcw[i] + (l_tccp->prch[i] << 4), 1); /* SPcoc (I_i) */ + ++p_data; + } + *p_header_size = *p_header_size - l_tccp->numresolutions; + + } + return true; +} + + +/** + * Reads a SPCod or SPCoc element, i.e. the coding style of a given component of a tile. + * @param p_header_data the data contained in the COM box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the COM marker. + * @param p_manager the user event manager. +*/ +bool j2k_read_SPCod_SPCoc( + opj_j2k_t *p_j2k, + OPJ_UINT32 compno, + OPJ_BYTE * p_header_data, + OPJ_UINT32 * p_header_size, + struct opj_event_mgr * p_manager + ) +{ + // loop + OPJ_UINT32 i; + + opj_cp_t *l_cp = 00; + opj_tcp_t *l_tcp = 00; + opj_tccp_t *l_tccp = 00; + OPJ_BYTE * l_current_ptr = 00; + OPJ_UINT32 l_tmp; + + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_header_data != 00); + + + l_cp = &(p_j2k->m_cp); + l_tcp = p_j2k->m_specific_param.m_decoder.m_state == J2K_DEC_STATE_TPH ? &l_cp->tcps[p_j2k->m_current_tile_number] : p_j2k->m_specific_param.m_decoder.m_default_tcp; + + // precondition again + assert(compno < p_j2k->m_image->numcomps); + l_tccp = &l_tcp->tccps[compno]; + l_current_ptr = p_header_data; + + + // make sure room is sufficient + if + (* p_header_size < 5) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading SPCod SPCoc element\n"); + return false; + } + opj_read_bytes(l_current_ptr, &l_tccp->numresolutions ,1); /* SPcox (D) */ + ++l_tccp->numresolutions; /* tccp->numresolutions = read() + 1 */ + ++l_current_ptr; + + // If user wants to remove more resolutions than the codestream contains, return error + if + (l_cp->m_specific_param.m_dec.m_reduce >= l_tccp->numresolutions) + { + opj_event_msg(p_manager, EVT_ERROR, "Error decoding component %d.\nThe number of resolutions to remove is higher than the number " + "of resolutions of this component\nModify the cp_reduce parameter.\n\n", compno); + p_j2k->m_specific_param.m_decoder.m_state |= J2K_DEC_STATE_ERR; + return false; + } + + opj_read_bytes(l_current_ptr,&l_tccp->cblkw ,1); /* SPcoc (E) */ + ++l_current_ptr; + l_tccp->cblkw += 2; + + opj_read_bytes(l_current_ptr,&l_tccp->cblkh ,1); /* SPcoc (F) */ + ++l_current_ptr; + l_tccp->cblkh += 2; + + opj_read_bytes(l_current_ptr,&l_tccp->cblksty ,1); /* SPcoc (G) */ + ++l_current_ptr; + + opj_read_bytes(l_current_ptr,&l_tccp->qmfbid ,1); /* SPcoc (H) */ + ++l_current_ptr; + + * p_header_size = * p_header_size - 5; + + // use custom precinct size ? + if + (l_tccp->csty & J2K_CCP_CSTY_PRT) + { + if + (* p_header_size < l_tccp->numresolutions) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading SPCod SPCoc element\n"); + return false; + } + for + (i = 0; i < l_tccp->numresolutions; ++i) + { + opj_read_bytes(l_current_ptr,&l_tmp ,1); /* SPcoc (I_i) */ + ++l_current_ptr; + l_tccp->prcw[i] = l_tmp & 0xf; + l_tccp->prch[i] = l_tmp >> 4; + } + * p_header_size = * p_header_size - l_tccp->numresolutions; + } + else + { + /* set default size for the precinct width and height */ + for + (i = 0; i < l_tccp->numresolutions; ++i) + { + l_tccp->prcw[i] = 15; + l_tccp->prch[i] = 15; + } + } + + /* INDEX >> */ + if + (p_j2k->cstr_info && compno == 0) + { + OPJ_UINT32 l_data_size = l_tccp->numresolutions * sizeof(OPJ_UINT32); + memcpy(p_j2k->cstr_info->tile[p_j2k->m_current_tile_number].pdx,l_tccp->prcw, l_data_size); + memcpy(p_j2k->cstr_info->tile[p_j2k->m_current_tile_number].pdy,l_tccp->prch, l_data_size); + } + /* << INDEX */ + return true; +} + +/** + * Copies the tile component parameters of all the component from the first tile component. + * + * @param p_j2k the J2k codec. + */ +void j2k_copy_tile_component_parameters( + opj_j2k_t *p_j2k + ) +{ + // loop + OPJ_UINT32 i; + + opj_cp_t *l_cp = 00; + opj_tcp_t *l_tcp = 00; + opj_tccp_t *l_ref_tccp = 00; + opj_tccp_t *l_copied_tccp = 00; + OPJ_UINT32 l_prc_size; + // preconditions + assert(p_j2k != 00); + + l_cp = &(p_j2k->m_cp); + l_tcp = p_j2k->m_specific_param.m_decoder.m_state == J2K_DEC_STATE_TPH ? &l_cp->tcps[p_j2k->m_current_tile_number] : p_j2k->m_specific_param.m_decoder.m_default_tcp; + + l_ref_tccp = &l_tcp->tccps[0]; + l_copied_tccp = l_ref_tccp + 1; + l_prc_size = l_ref_tccp->numresolutions * sizeof(OPJ_UINT32); + + for + (i=1;im_image->numcomps;++i) + { + l_copied_tccp->numresolutions = l_ref_tccp->numresolutions; + l_copied_tccp->cblkw = l_ref_tccp->cblkw; + l_copied_tccp->cblkh = l_ref_tccp->cblkh; + l_copied_tccp->cblksty = l_ref_tccp->cblksty; + l_copied_tccp->qmfbid = l_ref_tccp->qmfbid; + memcpy(l_copied_tccp->prcw,l_ref_tccp->prcw,l_prc_size); + memcpy(l_copied_tccp->prch,l_ref_tccp->prch,l_prc_size); + ++l_copied_tccp; + } +} + + + +/** + * Writes the COD marker (Coding style default) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_write_cod( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + opj_cp_t *l_cp = 00; + opj_tcp_t *l_tcp = 00; + OPJ_UINT32 l_code_size,l_remaining_size; + OPJ_BYTE * l_current_data = 00; + + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + l_cp = &(p_j2k->m_cp); + l_tcp = &l_cp->tcps[p_j2k->m_current_tile_number]; + l_code_size = 9 + j2k_get_SPCod_SPCoc_size(p_j2k,p_j2k->m_current_tile_number,0); + l_remaining_size = l_code_size; + + if + (l_code_size > p_j2k->m_specific_param.m_encoder.m_header_tile_data_size) + { + p_j2k->m_specific_param.m_encoder.m_header_tile_data + = (OPJ_BYTE*)opj_realloc( + p_j2k->m_specific_param.m_encoder.m_header_tile_data, + l_code_size); + if + (! p_j2k->m_specific_param.m_encoder.m_header_tile_data) + { + return false; + } + p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = l_code_size; + } + + l_current_data = p_j2k->m_specific_param.m_encoder.m_header_tile_data; + + opj_write_bytes(l_current_data,J2K_MS_COD,2); /* COD */ + l_current_data += 2; + + opj_write_bytes(l_current_data,l_code_size-2,2); /* L_COD */ + l_current_data += 2; + + opj_write_bytes(l_current_data,l_tcp->csty,1); /* Scod */ + ++l_current_data; + + opj_write_bytes(l_current_data,l_tcp->prg,1); /* SGcod (A) */ + ++l_current_data; + + opj_write_bytes(l_current_data,l_tcp->numlayers,2); /* SGcod (B) */ + l_current_data+=2; + + opj_write_bytes(l_current_data,l_tcp->mct,1); /* SGcod (C) */ + ++l_current_data; + + l_remaining_size -= 9; + + if + (! j2k_write_SPCod_SPCoc(p_j2k,p_j2k->m_current_tile_number,0,l_current_data,&l_remaining_size,p_manager)) + { + opj_event_msg(p_manager, EVT_ERROR, "Error writting COD marker\n"); + return false; + } + if + (l_remaining_size != 0) + { + opj_event_msg(p_manager, EVT_ERROR, "Error writting COD marker\n"); + return false; + } + + if + (opj_stream_write_data(p_stream,p_j2k->m_specific_param.m_encoder.m_header_tile_data,l_code_size,p_manager) != l_code_size) + { + return false; + } + return true; +} + +/** + * Reads a COD marker (Coding Styke defaults) + * @param p_header_data the data contained in the COD box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the COD marker. + * @param p_manager the user event manager. +*/ +bool j2k_read_cod ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ) +{ + // loop + OPJ_UINT32 i; + OPJ_UINT32 l_tmp; + opj_cp_t *l_cp = 00; + opj_tcp_t *l_tcp = 00; + opj_image_t *l_image = 00; + + // preconditions + assert(p_header_data != 00); + assert(p_j2k != 00); + assert(p_manager != 00); + + l_cp = &(p_j2k->m_cp); + l_tcp = (p_j2k->m_specific_param.m_decoder.m_state == J2K_DEC_STATE_TPH) ? &l_cp->tcps[p_j2k->m_current_tile_number] : p_j2k->m_specific_param.m_decoder.m_default_tcp; + l_image = p_j2k->m_image; + + // make sure room is sufficient + if + (p_header_size < 5) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading COD marker\n"); + return false; + } + + opj_read_bytes(p_header_data,&l_tcp->csty,1); /* Scod */ + ++p_header_data; + opj_read_bytes(p_header_data,&l_tmp,1); /* SGcod (A) */ + ++p_header_data; + l_tcp->prg = (OPJ_PROG_ORDER) l_tmp; + opj_read_bytes(p_header_data,&l_tcp->numlayers,2); /* SGcod (B) */ + p_header_data+=2; + if + (l_cp->m_specific_param.m_dec.m_layer) + { + l_tcp->num_layers_to_decode = l_cp->m_specific_param.m_dec.m_layer; + } + else + { + l_tcp->num_layers_to_decode = l_tcp->numlayers; + } + + opj_read_bytes(p_header_data,&l_tcp->mct,1); /* SGcod (C) */ + ++p_header_data; + + p_header_size -= 5; + for + (i = 0; i < l_image->numcomps; ++i) + { + l_tcp->tccps[i].csty = l_tcp->csty & J2K_CCP_CSTY_PRT; + } + + if + (! j2k_read_SPCod_SPCoc(p_j2k,0,p_header_data,&p_header_size,p_manager)) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading COD marker\n"); + return false; + } + if + (p_header_size != 0) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading COD marker\n"); + return false; + } + j2k_copy_tile_component_parameters(p_j2k); + + + /* Index */ + if + (p_j2k->cstr_info) + { + opj_codestream_info_t *l_cstr_info = p_j2k->cstr_info; + l_cstr_info->prog = l_tcp->prg; + l_cstr_info->numlayers = l_tcp->numlayers; + l_cstr_info->numdecompos = (OPJ_INT32*) opj_malloc(l_image->numcomps * sizeof(OPJ_UINT32)); + for + (i = 0; i < l_image->numcomps; ++i) + { + l_cstr_info->numdecompos[i] = l_tcp->tccps[i].numresolutions - 1; + } + } + return true; +} + +/** + * Writes the COC marker (Coding style component) + * + * @param p_comp_no the index of the component to output. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_write_coc( + opj_j2k_t *p_j2k, + OPJ_UINT32 p_comp_no, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 l_coc_size,l_remaining_size; + OPJ_UINT32 l_comp_room; + + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + l_comp_room = (p_j2k->m_image->numcomps <= 256) ? 1 : 2; + + l_coc_size = 5 + l_comp_room + j2k_get_SPCod_SPCoc_size(p_j2k,p_j2k->m_current_tile_number,p_comp_no); + if + (l_coc_size > p_j2k->m_specific_param.m_encoder.m_header_tile_data_size) + { + p_j2k->m_specific_param.m_encoder.m_header_tile_data + = (OPJ_BYTE*)opj_realloc( + p_j2k->m_specific_param.m_encoder.m_header_tile_data, + l_coc_size); + if + (! p_j2k->m_specific_param.m_encoder.m_header_tile_data) + { + return false; + } + p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = l_coc_size; + } + + j2k_write_coc_in_memory(p_j2k,p_comp_no,p_j2k->m_specific_param.m_encoder.m_header_tile_data,&l_remaining_size,p_manager); + + if + (opj_stream_write_data(p_stream,p_j2k->m_specific_param.m_encoder.m_header_tile_data,l_coc_size,p_manager) != l_coc_size) + { + return false; + } + return true; +} + +/** + * Gets the maximum size taken by a coc. + * + * @param p_j2k the jpeg2000 codec to use. + */ +OPJ_UINT32 j2k_get_max_coc_size(opj_j2k_t *p_j2k) +{ + OPJ_UINT32 i,j; + OPJ_UINT32 l_nb_comp; + OPJ_UINT32 l_nb_tiles; + OPJ_UINT32 l_max = 0; + + // preconditions + + l_nb_tiles = p_j2k->m_cp.tw * p_j2k->m_cp.th ; + l_nb_comp = p_j2k->m_image->numcomps; + + for + (i=0;im_cp.tcps; + l_nb_tiles = p_j2k->m_cp.tw * p_j2k->m_cp.th ; + + for + (i=0;im_nb_tile_parts); + ++l_tcp; + } + return 12 * l_max; +} + + +/** + * Gets the maximum size taken by the headers of the SOT. + * + * @param p_j2k the jpeg2000 codec to use. + */ +OPJ_UINT32 j2k_get_specific_header_sizes(opj_j2k_t *p_j2k) +{ + OPJ_UINT32 l_nb_bytes = 0; + OPJ_UINT32 l_nb_comps; + OPJ_UINT32 l_coc_bytes,l_qcc_bytes; + + + l_nb_comps = p_j2k->m_image->numcomps - 1; + l_nb_bytes += j2k_get_max_toc_size(p_j2k); + if + (p_j2k->m_cp.m_specific_param.m_enc.m_cinema == 0) + { + l_coc_bytes = j2k_get_max_coc_size(p_j2k); + l_nb_bytes += l_nb_comps * l_coc_bytes; + l_qcc_bytes = j2k_get_max_qcc_size(p_j2k); + l_nb_bytes += l_nb_comps * l_qcc_bytes; + } + l_nb_bytes += j2k_get_max_poc_size(p_j2k); + /*** DEVELOPER CORNER, Add room for your headers ***/ + + + return l_nb_bytes; +} + + +/** + * Writes the COC marker (Coding style component) + * + * @param p_comp_no the index of the component to output. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +void j2k_write_coc_in_memory( + opj_j2k_t *p_j2k, + OPJ_UINT32 p_comp_no, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + struct opj_event_mgr * p_manager + ) +{ + opj_cp_t *l_cp = 00; + opj_tcp_t *l_tcp = 00; + OPJ_UINT32 l_coc_size,l_remaining_size; + OPJ_BYTE * l_current_data = 00; + opj_image_t *l_image = 00; + OPJ_UINT32 l_comp_room; + + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + + l_cp = &(p_j2k->m_cp); + l_tcp = &l_cp->tcps[p_j2k->m_current_tile_number]; + l_image = p_j2k->m_image; + l_comp_room = (l_image->numcomps <= 256) ? 1 : 2; + + l_coc_size = 5 + l_comp_room + j2k_get_SPCod_SPCoc_size(p_j2k,p_j2k->m_current_tile_number,p_comp_no); + l_remaining_size = l_coc_size; + + l_current_data = p_data; + + opj_write_bytes(l_current_data,J2K_MS_COC,2); /* COC */ + l_current_data += 2; + opj_write_bytes(l_current_data,l_coc_size-2,2); /* L_COC */ + l_current_data += 2; + opj_write_bytes(l_current_data,p_comp_no, l_comp_room); /* Ccoc */ + l_current_data+=l_comp_room; + opj_write_bytes(l_current_data, l_tcp->tccps[p_comp_no].csty, 1); /* Scoc */ + ++l_current_data; + l_remaining_size -= (5 + l_comp_room); + j2k_write_SPCod_SPCoc(p_j2k,p_j2k->m_current_tile_number,0,l_current_data,&l_remaining_size,p_manager); + * p_data_written = l_coc_size; +} + + +/** + * Reads a COC marker (Coding Style Component) + * @param p_header_data the data contained in the COC box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the COC marker. + * @param p_manager the user event manager. +*/ +bool j2k_read_coc ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ) +{ + opj_cp_t *l_cp = 00; + opj_tcp_t *l_tcp = 00; + opj_image_t *l_image = 00; + OPJ_UINT32 l_comp_room; + OPJ_UINT32 l_comp_no; + + // preconditions + assert(p_header_data != 00); + assert(p_j2k != 00); + assert(p_manager != 00); + + l_cp = &(p_j2k->m_cp); + l_tcp = (p_j2k->m_specific_param.m_decoder.m_state == J2K_DEC_STATE_TPH) ? &l_cp->tcps[p_j2k->m_current_tile_number] : p_j2k->m_specific_param.m_decoder.m_default_tcp; + l_image = p_j2k->m_image; + + l_comp_room = l_image->numcomps <= 256 ? 1 : 2; + // make sure room is sufficient + if + (p_header_size < l_comp_room + 1) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading COC marker\n"); + return false; + } + p_header_size -= l_comp_room + 1; + + opj_read_bytes(p_header_data,&l_comp_no,l_comp_room); /* Ccoc */ + p_header_data += l_comp_room; + if + (l_comp_no >= l_image->numcomps) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading COC marker (bad number of components)\n"); + return false; + } + opj_read_bytes(p_header_data,&l_tcp->tccps[l_comp_no].csty,1); /* Scoc */ + ++p_header_data ; + + if + (! j2k_read_SPCod_SPCoc(p_j2k,l_comp_no,p_header_data,&p_header_size,p_manager)) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading COC marker\n"); + return false; + } + if + (p_header_size != 0) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading COC marker\n"); + return false; + } + return true; +} + +/** + * Gets the size taken by writting SQcd or SQcc element, i.e. the quantization values of a band in the QCD or QCC. + * + * @param p_tile_no the tile indix. + * @param p_comp_no the component being outputted. + * @param p_j2k the J2K codec. + * + * @return the number of bytes taken by the SPCod element. + */ +OPJ_UINT32 j2k_get_SQcd_SQcc_size ( + opj_j2k_t *p_j2k, + OPJ_UINT32 p_tile_no, + OPJ_UINT32 p_comp_no + ) +{ + OPJ_UINT32 l_num_bands; + + opj_cp_t *l_cp = 00; + opj_tcp_t *l_tcp = 00; + opj_tccp_t *l_tccp = 00; + + // preconditions + assert(p_j2k != 00); + + l_cp = &(p_j2k->m_cp); + l_tcp = &l_cp->tcps[p_tile_no]; + l_tccp = &l_tcp->tccps[p_comp_no]; + + // preconditions again + assert(p_tile_no < l_cp->tw * l_cp->th); + assert(p_comp_no < p_j2k->m_image->numcomps); + + l_num_bands = (l_tccp->qntsty == J2K_CCP_QNTSTY_SIQNT) ? 1 : (l_tccp->numresolutions * 3 - 2); + + if + (l_tccp->qntsty == J2K_CCP_QNTSTY_NOQNT) + { + return 1 + l_num_bands; + } + else + { + return 1 + 2*l_num_bands; + } +} + +/** + * Writes a SQcd or SQcc element, i.e. the quantization values of a band. + * + * @param p_tile_no the tile to output. + * @param p_comp_no the component number to output. + * @param p_data the data buffer. + * @param p_header_size pointer to the size of the data buffer, it is changed by the function. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. + * +*/ +bool j2k_write_SQcd_SQcc( + opj_j2k_t *p_j2k, + OPJ_UINT32 p_tile_no, + OPJ_UINT32 p_comp_no, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_header_size, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 l_header_size; + OPJ_UINT32 l_band_no, l_num_bands; + OPJ_UINT32 l_expn,l_mant; + + opj_cp_t *l_cp = 00; + opj_tcp_t *l_tcp = 00; + opj_tccp_t *l_tccp = 00; + + // preconditions + assert(p_j2k != 00); + assert(p_header_size != 00); + assert(p_manager != 00); + assert(p_data != 00); + + l_cp = &(p_j2k->m_cp); + l_tcp = &l_cp->tcps[p_tile_no]; + l_tccp = &l_tcp->tccps[p_comp_no]; + + // preconditions again + assert(p_tile_no < l_cp->tw * l_cp->th); + assert(p_comp_no m_image->numcomps); + + l_num_bands = (l_tccp->qntsty == J2K_CCP_QNTSTY_SIQNT) ? 1 : (l_tccp->numresolutions * 3 - 2); + + if + (l_tccp->qntsty == J2K_CCP_QNTSTY_NOQNT) + { + l_header_size = 1 + l_num_bands; + if + (*p_header_size < l_header_size) + { + opj_event_msg(p_manager, EVT_ERROR, "Error writting SQcd SQcc element\n"); + return false; + } + opj_write_bytes(p_data,l_tccp->qntsty + (l_tccp->numgbits << 5), 1); /* Sqcx */ + ++p_data; + for + (l_band_no = 0; l_band_no < l_num_bands; ++l_band_no) + { + l_expn = l_tccp->stepsizes[l_band_no].expn; + opj_write_bytes(p_data, l_expn << 3, 1); /* SPqcx_i */ + ++p_data; + } + } + else + { + l_header_size = 1 + 2*l_num_bands; + if + (*p_header_size < l_header_size) + { + opj_event_msg(p_manager, EVT_ERROR, "Error writting SQcd SQcc element\n"); + return false; + } + opj_write_bytes(p_data,l_tccp->qntsty + (l_tccp->numgbits << 5), 1); /* Sqcx */ + ++p_data; + for + (l_band_no = 0; l_band_no < l_num_bands; ++l_band_no) + { + l_expn = l_tccp->stepsizes[l_band_no].expn; + l_mant = l_tccp->stepsizes[l_band_no].mant; + opj_write_bytes(p_data, (l_expn << 11) + l_mant, 2); /* SPqcx_i */ + p_data += 2; + } + } + *p_header_size = *p_header_size - l_header_size; + return true; +} + +/** + * Reads a SQcd or SQcc element, i.e. the quantization values of a band. + * + * @param p_comp_no the component being targeted. + * @param p_header_data the data contained in the COM box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the COM marker. + * @param p_manager the user event manager. +*/ +bool j2k_read_SQcd_SQcc( + opj_j2k_t *p_j2k, + OPJ_UINT32 p_comp_no, + OPJ_BYTE* p_header_data, + OPJ_UINT32 * p_header_size, + struct opj_event_mgr * p_manager + ) +{ + // loop + OPJ_UINT32 l_band_no; + opj_cp_t *l_cp = 00; + opj_tcp_t *l_tcp = 00; + opj_tccp_t *l_tccp = 00; + OPJ_BYTE * l_current_ptr = 00; + OPJ_UINT32 l_tmp; + OPJ_UINT32 l_num_band; + + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_header_data != 00); + + l_cp = &(p_j2k->m_cp); + l_tcp = p_j2k->m_specific_param.m_decoder.m_state == J2K_DEC_STATE_TPH ? &l_cp->tcps[p_j2k->m_current_tile_number] : p_j2k->m_specific_param.m_decoder.m_default_tcp; + // precondition again + assert(p_comp_no < p_j2k->m_image->numcomps); + l_tccp = &l_tcp->tccps[p_comp_no]; + l_current_ptr = p_header_data; + + if + (* p_header_size < 1) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading SQcd or SQcc element\n"); + return false; + } + * p_header_size -= 1; + + opj_read_bytes(l_current_ptr, &l_tmp ,1); /* Sqcx */ + ++l_current_ptr; + + l_tccp->qntsty = l_tmp & 0x1f; + l_tccp->numgbits = l_tmp >> 5; + if + (l_tccp->qntsty == J2K_CCP_QNTSTY_SIQNT) + { + l_num_band = 1; + } + else + { + l_num_band = (l_tccp->qntsty == J2K_CCP_QNTSTY_NOQNT) ? (*p_header_size) : (*p_header_size) / 2; + if( l_num_band > J2K_MAXBANDS ) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading CCP_QNTSTY element\n"); + return false; + } + } + +#ifdef USE_JPWL + if (p_j2k->m_cp->correct) { + + /* if JPWL is on, we check whether there are too many subbands */ + if ((numbands < 0) || (numbands >= J2K_MAXBANDS)) { + opj_event_msg(p_j2k->cinfo, JPWL_ASSUME ? EVT_WARNING : EVT_ERROR, + "JPWL: bad number of subbands in Sqcx (%d)\n", + numbands); + if (!JPWL_ASSUME) { + opj_event_msg(p_j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + return; + } + /* we try to correct */ + numbands = 1; + opj_event_msg(p_j2k->cinfo, EVT_WARNING, "- trying to adjust them\n" + "- setting number of bands to %d => HYPOTHESIS!!!\n", + numbands); + }; + + }; +#endif /* USE_JPWL */ + if + (l_tccp->qntsty == J2K_CCP_QNTSTY_NOQNT) + { + for + (l_band_no = 0; l_band_no < l_num_band; l_band_no++) + { + opj_read_bytes(l_current_ptr, &l_tmp ,1); /* SPqcx_i */ + ++l_current_ptr; + l_tccp->stepsizes[l_band_no].expn = l_tmp>>3; + l_tccp->stepsizes[l_band_no].mant = 0; + } + * p_header_size = * p_header_size - l_num_band; + } + else + { + for + (l_band_no = 0; l_band_no < l_num_band; l_band_no++) + { + opj_read_bytes(l_current_ptr, &l_tmp ,2); /* SPqcx_i */ + l_current_ptr+=2; + l_tccp->stepsizes[l_band_no].expn = l_tmp >> 11; + l_tccp->stepsizes[l_band_no].mant = l_tmp & 0x7ff; + } + * p_header_size = * p_header_size - 2*l_num_band; + } + + /* Add Antonin : if scalar_derived -> compute other stepsizes */ + if + (l_tccp->qntsty == J2K_CCP_QNTSTY_SIQNT) + { + for + (l_band_no = 1; l_band_no < J2K_MAXBANDS; l_band_no++) + { + l_tccp->stepsizes[l_band_no].expn = + ((l_tccp->stepsizes[0].expn) - ((l_band_no - 1) / 3) > 0) ? + (l_tccp->stepsizes[0].expn) - ((l_band_no - 1) / 3) : 0; + l_tccp->stepsizes[l_band_no].mant = l_tccp->stepsizes[0].mant; + } + + } + return true; +} + + + +/** + * Copies the tile component parameters of all the component from the first tile component. + * + * @param p_j2k the J2k codec. + */ +void j2k_copy_tile_quantization_parameters( + opj_j2k_t *p_j2k + ) +{ + // loop + OPJ_UINT32 i; + + opj_cp_t *l_cp = 00; + opj_tcp_t *l_tcp = 00; + opj_tccp_t *l_ref_tccp = 00; + opj_tccp_t *l_copied_tccp = 00; + OPJ_UINT32 l_size; + // preconditions + assert(p_j2k != 00); + + l_cp = &(p_j2k->m_cp); + l_tcp = p_j2k->m_specific_param.m_decoder.m_state == J2K_DEC_STATE_TPH ? &l_cp->tcps[p_j2k->m_current_tile_number] : p_j2k->m_specific_param.m_decoder.m_default_tcp; + // precondition again + l_ref_tccp = &l_tcp->tccps[0]; + l_copied_tccp = l_ref_tccp + 1; + l_size = J2K_MAXBANDS * sizeof(opj_stepsize_t); + + for + (i=1;im_image->numcomps;++i) + { + l_copied_tccp->qntsty = l_ref_tccp->qntsty; + l_copied_tccp->numgbits = l_ref_tccp->numgbits; + memcpy(l_copied_tccp->stepsizes,l_ref_tccp->stepsizes,l_size); + ++l_copied_tccp; + } +} + + + +/** + * Writes the QCD marker (quantization default) + * + * @param p_comp_number the index of the component to output. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_write_qcd( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + opj_cp_t *l_cp = 00; + opj_tcp_t *l_tcp = 00; + OPJ_UINT32 l_qcd_size,l_remaining_size; + OPJ_BYTE * l_current_data = 00; + + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + l_cp = &(p_j2k->m_cp); + l_tcp = &l_cp->tcps[p_j2k->m_current_tile_number]; + l_qcd_size = 4 + j2k_get_SQcd_SQcc_size(p_j2k,p_j2k->m_current_tile_number,0); + l_remaining_size = l_qcd_size; + + if + (l_qcd_size > p_j2k->m_specific_param.m_encoder.m_header_tile_data_size) + { + p_j2k->m_specific_param.m_encoder.m_header_tile_data + = (OPJ_BYTE*)opj_realloc( + p_j2k->m_specific_param.m_encoder.m_header_tile_data, + l_qcd_size); + if + (! p_j2k->m_specific_param.m_encoder.m_header_tile_data) + { + return false; + } + p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = l_qcd_size; + } + l_current_data = p_j2k->m_specific_param.m_encoder.m_header_tile_data; + + opj_write_bytes(l_current_data,J2K_MS_QCD,2); /* QCD */ + l_current_data += 2; + + opj_write_bytes(l_current_data,l_qcd_size-2,2); /* L_QCD */ + l_current_data += 2; + + l_remaining_size -= 4; + + if + (! j2k_write_SQcd_SQcc(p_j2k,p_j2k->m_current_tile_number,0,l_current_data,&l_remaining_size,p_manager)) + { + opj_event_msg(p_manager, EVT_ERROR, "Error writting QCD marker\n"); + return false; + } + if + (l_remaining_size != 0) + { + opj_event_msg(p_manager, EVT_ERROR, "Error writting QCD marker\n"); + return false; + } + + if + (opj_stream_write_data(p_stream, p_j2k->m_specific_param.m_encoder.m_header_tile_data,l_qcd_size,p_manager) != l_qcd_size) + { + return false; + } + return true; +} + +/** + * Reads a QCD marker (Quantization defaults) + * @param p_header_data the data contained in the QCD box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the QCD marker. + * @param p_manager the user event manager. +*/ +bool j2k_read_qcd ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ) +{ + // preconditions + assert(p_header_data != 00); + assert(p_j2k != 00); + assert(p_manager != 00); + + if + (! j2k_read_SQcd_SQcc(p_j2k,0,p_header_data,&p_header_size,p_manager)) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading QCD marker\n"); + return false; + } + if + (p_header_size != 0) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading QCD marker\n"); + return false; + } + j2k_copy_tile_quantization_parameters(p_j2k); + return true; +} + + +/** + * Writes the QCC marker (quantization component) + * + * @param p_comp_no the index of the component to output. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_write_qcc( + opj_j2k_t *p_j2k, + OPJ_UINT32 p_comp_no, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 l_qcc_size,l_remaining_size; + + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + l_qcc_size = 6 + j2k_get_SQcd_SQcc_size(p_j2k,p_j2k->m_current_tile_number,p_comp_no); + l_remaining_size = l_qcc_size; + if + (l_qcc_size > p_j2k->m_specific_param.m_encoder.m_header_tile_data_size) + { + p_j2k->m_specific_param.m_encoder.m_header_tile_data + = (OPJ_BYTE*)opj_realloc( + p_j2k->m_specific_param.m_encoder.m_header_tile_data, + l_qcc_size); + if + (! p_j2k->m_specific_param.m_encoder.m_header_tile_data) + { + return false; + } + p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = l_qcc_size; + } + j2k_write_qcc_in_memory(p_j2k,p_comp_no,p_j2k->m_specific_param.m_encoder.m_header_tile_data,&l_remaining_size,p_manager); + + if + (opj_stream_write_data(p_stream,p_j2k->m_specific_param.m_encoder.m_header_tile_data,l_qcc_size,p_manager) != l_qcc_size) + { + return false; + } + return true; +} + + +/** + * Writes the QCC marker (quantization component) + * + * @param p_comp_no the index of the component to output. + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +void j2k_write_qcc_in_memory( + opj_j2k_t *p_j2k, + OPJ_UINT32 p_comp_no, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 l_qcc_size,l_remaining_size; + OPJ_BYTE * l_current_data = 00; + + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + + l_qcc_size = 6 + j2k_get_SQcd_SQcc_size(p_j2k,p_j2k->m_current_tile_number,p_comp_no); + l_remaining_size = l_qcc_size; + + l_current_data = p_data; + + opj_write_bytes(l_current_data,J2K_MS_QCC,2); /* QCC */ + l_current_data += 2; + + if + (p_j2k->m_image->numcomps <= 256) + { + --l_qcc_size; + opj_write_bytes(l_current_data,l_qcc_size-2,2); /* L_QCC */ + l_current_data += 2; + opj_write_bytes(l_current_data, p_comp_no, 1); /* Cqcc */ + ++l_current_data; + // in the case only one byte is sufficient the last byte allocated is useless -> still do -6 for available + l_remaining_size -= 6; + } + else + { + opj_write_bytes(l_current_data,l_qcc_size-2,2); /* L_QCC */ + l_current_data += 2; + opj_write_bytes(l_current_data, p_comp_no, 2); /* Cqcc */ + l_current_data+=2; + l_remaining_size -= 6; + } + j2k_write_SQcd_SQcc(p_j2k,p_j2k->m_current_tile_number,p_comp_no,l_current_data,&l_remaining_size,p_manager); + * p_data_written = l_qcc_size; +} + +/** + * Gets the maximum size taken by a qcc. + */ +OPJ_UINT32 j2k_get_max_qcc_size (opj_j2k_t *p_j2k) +{ + return j2k_get_max_coc_size(p_j2k); +} + +/** + * Reads a QCC marker (Quantization component) + * @param p_header_data the data contained in the QCC box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the QCC marker. + * @param p_manager the user event manager. +*/ +bool j2k_read_qcc( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager) +{ + OPJ_UINT32 l_num_comp,l_comp_no; + // preconditions + assert(p_header_data != 00); + assert(p_j2k != 00); + assert(p_manager != 00); + + l_num_comp = p_j2k->m_image->numcomps; + +#ifdef USE_JPWL + if (p_j2k->m_cp->correct) { + + static OPJ_UINT32 backup_compno = 0; + + /* compno is negative or larger than the number of components!!! */ + if ((compno < 0) || (compno >= numcomp)) { + opj_event_msg(p_j2k->cinfo, EVT_ERROR, + "JPWL: bad component number in QCC (%d out of a maximum of %d)\n", + compno, numcomp); + if (!JPWL_ASSUME) { + opj_event_msg(p_j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + return; + } + /* we try to correct */ + compno = backup_compno % numcomp; + opj_event_msg(p_j2k->cinfo, EVT_WARNING, "- trying to adjust this\n" + "- setting component number to %d\n", + compno); + } + + /* keep your private count of tiles */ + backup_compno++; + }; +#endif /* USE_JPWL */ + if + (l_num_comp <= 256) + { + if + (p_header_size < 1) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading QCC marker\n"); + return false; + } + opj_read_bytes(p_header_data,&l_comp_no,1); + ++p_header_data; + --p_header_size; + } + else + { + if + (p_header_size < 2) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading QCC marker\n"); + return false; + } + opj_read_bytes(p_header_data,&l_comp_no,2); + p_header_data+=2; + p_header_size-=2; + } + if + (! j2k_read_SQcd_SQcc(p_j2k,l_comp_no,p_header_data,&p_header_size,p_manager)) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading QCC marker\n"); + return false; + } + if + (p_header_size != 0) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading QCC marker\n"); + return false; + } + return true; + +} + + +/** + * Writes the CBD marker (Component bit depth definition) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_write_cbd( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 i; + OPJ_UINT32 l_cbd_size; + OPJ_BYTE * l_current_data = 00; + opj_image_t *l_image = 00; + opj_image_comp_t * l_comp = 00; + + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + l_image = p_j2k->m_image; + l_cbd_size = 6 + p_j2k->m_image->numcomps; + + if + (l_cbd_size > p_j2k->m_specific_param.m_encoder.m_header_tile_data_size) + { + p_j2k->m_specific_param.m_encoder.m_header_tile_data + = (OPJ_BYTE*)opj_realloc( + p_j2k->m_specific_param.m_encoder.m_header_tile_data, + l_cbd_size); + if + (! p_j2k->m_specific_param.m_encoder.m_header_tile_data) + { + return false; + } + p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = l_cbd_size; + } + + l_current_data = p_j2k->m_specific_param.m_encoder.m_header_tile_data; + opj_write_bytes(l_current_data,J2K_MS_CBD,2); /* CBD */ + l_current_data += 2; + opj_write_bytes(l_current_data,l_cbd_size-2,2); /* L_CBD */ + l_current_data += 2; + opj_write_bytes(l_current_data,l_image->numcomps, 2); /* Ncbd */ + l_current_data+=2; + l_comp = l_image->comps; + for + (i=0;inumcomps;++i) + { + opj_write_bytes(l_current_data, (l_comp->sgnd << 7) | (l_comp->prec - 1), 1); /* Component bit depth */ + ++l_current_data; + ++l_comp; + } + if + (opj_stream_write_data(p_stream,p_j2k->m_specific_param.m_encoder.m_header_tile_data,l_cbd_size,p_manager) != l_cbd_size) + { + return false; + } + return true; +} + +/** + * Reads a CBD marker (Component bit depth definition) + * @param p_header_data the data contained in the CBD box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the CBD marker. + * @param p_manager the user event manager. +*/ +bool j2k_read_cbd ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager) +{ + OPJ_UINT32 l_nb_comp,l_num_comp; + OPJ_UINT32 l_comp_def; + OPJ_UINT32 i; + opj_image_comp_t * l_comp = 00; + + // preconditions + assert(p_header_data != 00); + assert(p_j2k != 00); + assert(p_manager != 00); + + l_num_comp = p_j2k->m_image->numcomps; + + if + (p_header_size != (p_j2k->m_image->numcomps + 2)) + { + opj_event_msg(p_manager, EVT_ERROR, "Crror reading CBD marker\n"); + return false; + } + opj_read_bytes(p_header_data,&l_nb_comp,2); /* Ncbd */ + p_header_data+=2; + if + (l_nb_comp != l_num_comp) + { + opj_event_msg(p_manager, EVT_ERROR, "Crror reading CBD marker\n"); + return false; + } + + l_comp = p_j2k->m_image->comps; + for + (i=0;isgnd = (l_comp_def>>7) & 1; + l_comp->prec = (l_comp_def&0x7f) + 1; + ++l_comp; + } + return true; +} + +/** + * Writes the MCC marker (Multiple Component Collection) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_write_mcc_record( + opj_j2k_t *p_j2k, + struct opj_simple_mcc_decorrelation_data * p_mcc_record, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 i; + OPJ_UINT32 l_mcc_size; + OPJ_BYTE * l_current_data = 00; + OPJ_UINT32 l_nb_bytes_for_comp; + OPJ_UINT32 l_mask; + OPJ_UINT32 l_tmcc; + + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + if + (p_mcc_record->m_nb_comps > 255 ) + { + l_nb_bytes_for_comp = 2; + l_mask = 0x8000; + } + else + { + l_nb_bytes_for_comp = 1; + l_mask = 0; + } + + l_mcc_size = p_mcc_record->m_nb_comps * 2 * l_nb_bytes_for_comp + 19; + if + (l_mcc_size > p_j2k->m_specific_param.m_encoder.m_header_tile_data_size) + { + p_j2k->m_specific_param.m_encoder.m_header_tile_data + = (OPJ_BYTE*)opj_realloc( + p_j2k->m_specific_param.m_encoder.m_header_tile_data, + l_mcc_size); + if + (! p_j2k->m_specific_param.m_encoder.m_header_tile_data) + { + return false; + } + p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = l_mcc_size; + } + l_current_data = p_j2k->m_specific_param.m_encoder.m_header_tile_data; + opj_write_bytes(l_current_data,J2K_MS_MCC,2); /* MCC */ + l_current_data += 2; + opj_write_bytes(l_current_data,l_mcc_size-2,2); /* Lmcc */ + l_current_data += 2; + + /* first marker */ + opj_write_bytes(l_current_data,0,2); /* Zmcc */ + l_current_data += 2; + opj_write_bytes(l_current_data,p_mcc_record->m_index,1); /* Imcc -> no need for other values, take the first */ + ++l_current_data; + /* only one marker atm */ + opj_write_bytes(l_current_data,0,2); /* Ymcc */ + l_current_data+=2; + opj_write_bytes(l_current_data,1,2); /* Qmcc -> number of collections -> 1 */ + l_current_data+=2; + opj_write_bytes(l_current_data,0x1,1); /* Xmcci type of component transformation -> array based decorrelation */ + ++l_current_data; + + opj_write_bytes(l_current_data,p_mcc_record->m_nb_comps | l_mask,2); /* Nmcci number of input components involved and size for each component offset = 8 bits */ + l_current_data+=2; + + for + (i=0;im_nb_comps;++i) + { + opj_write_bytes(l_current_data,i,l_nb_bytes_for_comp); /* Cmccij Component offset*/ + l_current_data+=l_nb_bytes_for_comp; + } + + opj_write_bytes(l_current_data,p_mcc_record->m_nb_comps|l_mask,2); /* Mmcci number of output components involved and size for each component offset = 8 bits */ + l_current_data+=2; + for + (i=0;im_nb_comps;++i) + { + opj_write_bytes(l_current_data,i,l_nb_bytes_for_comp); /* Wmccij Component offset*/ + l_current_data+=l_nb_bytes_for_comp; + } + l_tmcc = ((!p_mcc_record->m_is_irreversible)&1)<<16; + if + (p_mcc_record->m_decorrelation_array) + { + l_tmcc |= p_mcc_record->m_decorrelation_array->m_index; + } + if + (p_mcc_record->m_offset_array) + { + l_tmcc |= ((p_mcc_record->m_offset_array->m_index)<<8); + } + opj_write_bytes(l_current_data,l_tmcc,3); /* Tmcci : use MCT defined as number 1 and irreversible array based. */ + l_current_data+=3; + if + (opj_stream_write_data(p_stream,p_j2k->m_specific_param.m_encoder.m_header_tile_data,l_mcc_size,p_manager) != l_mcc_size) + { + return false; + } + return true; +} + + +/** + * Reads a MCC marker (Multiple Component Collection) + * + * @param p_header_data the data contained in the MCC box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the MCC marker. + * @param p_manager the user event manager. +*/ +bool j2k_read_mcc ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 i,j; + OPJ_UINT32 l_tmp; + OPJ_UINT32 l_indix; + opj_tcp_t * l_tcp; + opj_simple_mcc_decorrelation_data_t * l_mcc_record; + opj_mct_data_t * l_mct_data; + OPJ_UINT32 l_nb_collections; + OPJ_UINT32 l_nb_comps; + OPJ_UINT32 l_nb_bytes_by_comp; + + + // preconditions + assert(p_header_data != 00); + assert(p_j2k != 00); + assert(p_manager != 00); + + l_tcp = p_j2k->m_specific_param.m_decoder.m_state == J2K_DEC_STATE_TPH ? &p_j2k->m_cp.tcps[p_j2k->m_current_tile_number] : p_j2k->m_specific_param.m_decoder.m_default_tcp; + + if + (p_header_size < 2) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading MCC marker\n"); + return false; + } + + /* first marker */ + opj_read_bytes(p_header_data,&l_tmp,2); /* Zmcc */ + p_header_data += 2; + if + (l_tmp != 0) + { + opj_event_msg(p_manager, EVT_WARNING, "Cannot take in charge multiple data spanning\n"); + return true; + } + if + (p_header_size < 7) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading MCC marker\n"); + return false; + } + opj_read_bytes(p_header_data,&l_indix,1); /* Imcc -> no need for other values, take the first */ + ++p_header_data; + + l_mcc_record = l_tcp->m_mcc_records; + for + (i=0;im_nb_mcc_records;++i) + { + if + (l_mcc_record->m_index == l_indix) + { + break; + } + ++l_mcc_record; + } + /** NOT FOUND */ + if + (i == l_tcp->m_nb_mcc_records) + { + if + (l_tcp->m_nb_mcc_records == l_tcp->m_nb_max_mcc_records) + { + l_tcp->m_nb_max_mcc_records += J2K_MCC_DEFAULT_NB_RECORDS; + l_tcp->m_mcc_records = (opj_simple_mcc_decorrelation_data_t*) + opj_realloc(l_tcp->m_mcc_records,l_tcp->m_nb_max_mcc_records * sizeof(opj_simple_mcc_decorrelation_data_t)); + if + (! l_tcp->m_mcc_records) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading MCC marker\n"); + return false; + } + l_mcc_record = l_tcp->m_mcc_records + l_tcp->m_nb_mcc_records; + memset(l_mcc_record,0,(l_tcp->m_nb_max_mcc_records-l_tcp->m_nb_mcc_records) * sizeof(opj_simple_mcc_decorrelation_data_t)); + } + l_mcc_record = l_tcp->m_mcc_records + l_tcp->m_nb_mcc_records; + } + l_mcc_record->m_index = l_indix; + + /* only one marker atm */ + opj_read_bytes(p_header_data,&l_tmp,2); /* Ymcc */ + p_header_data+=2; + if + (l_tmp != 0) + { + opj_event_msg(p_manager, EVT_WARNING, "Cannot take in charge multiple data spanning\n"); + return true; + } + opj_read_bytes(p_header_data,&l_nb_collections,2); /* Qmcc -> number of collections -> 1 */ + p_header_data+=2; + if + (l_nb_collections > 1) + { + opj_event_msg(p_manager, EVT_WARNING, "Cannot take in charge multiple collections\n"); + return true; + } + p_header_size -= 7; + for + (i=0;i array based decorrelation */ + ++p_header_data; + if + (l_tmp != 1) + { + opj_event_msg(p_manager, EVT_WARNING, "Cannot take in charge collections other than array decorrelation\n"); + return true; + } + opj_read_bytes(p_header_data,&l_nb_comps,2); + p_header_data+=2; + p_header_size-=3; + l_nb_bytes_by_comp = 1 + (l_nb_comps>>15); + l_mcc_record->m_nb_comps = l_nb_comps & 0x7fff; + if + (p_header_size < (l_nb_bytes_by_comp * l_mcc_record->m_nb_comps + 2)) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading MCC marker\n"); + return false; + } + p_header_size -= (l_nb_bytes_by_comp * l_mcc_record->m_nb_comps + 2); + for + (j=0;jm_nb_comps;++j) + { + opj_read_bytes(p_header_data,&l_tmp,l_nb_bytes_by_comp); /* Cmccij Component offset*/ + p_header_data+=l_nb_bytes_by_comp; + if + (l_tmp != j) + { + opj_event_msg(p_manager, EVT_WARNING, "Cannot take in charge collections with indix shuffle\n"); + return true; + } + } + opj_read_bytes(p_header_data,&l_nb_comps,2); + p_header_data+=2; + l_nb_bytes_by_comp = 1 + (l_nb_comps>>15); + l_nb_comps &= 0x7fff; + if + (l_nb_comps != l_mcc_record->m_nb_comps) + { + opj_event_msg(p_manager, EVT_WARNING, "Cannot take in charge collections without same number of indixes\n"); + return true; + } + if + (p_header_size < (l_nb_bytes_by_comp * l_mcc_record->m_nb_comps + 3)) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading MCC marker\n"); + return false; + } + p_header_size -= (l_nb_bytes_by_comp * l_mcc_record->m_nb_comps + 3); + for + (j=0;jm_nb_comps;++j) + { + opj_read_bytes(p_header_data,&l_tmp,l_nb_bytes_by_comp); /* Wmccij Component offset*/ + p_header_data+=l_nb_bytes_by_comp; + if + (l_tmp != j) + { + opj_event_msg(p_manager, EVT_WARNING, "Cannot take in charge collections with indix shuffle\n"); + return true; + } + } + opj_read_bytes(p_header_data,&l_tmp,3); /* Wmccij Component offset*/ + p_header_data += 3; + l_mcc_record->m_is_irreversible = ! ((l_tmp>>16) & 1); + l_mcc_record->m_decorrelation_array = 00; + l_mcc_record->m_offset_array = 00; + l_indix = l_tmp & 0xff; + if + (l_indix != 0) + { + l_mct_data = l_tcp->m_mct_records; + for + (j=0;jm_nb_mct_records;++j) + { + if + (l_mct_data->m_index == l_indix) + { + l_mcc_record->m_decorrelation_array = l_mct_data; + break; + } + ++l_mct_data; + } + if + (l_mcc_record->m_decorrelation_array == 00) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading MCC marker\n"); + return false; + } + } + l_indix = (l_tmp >> 8) & 0xff; + if + (l_indix != 0) + { + l_mct_data = l_tcp->m_mct_records; + for + (j=0;jm_nb_mct_records;++j) + { + if + (l_mct_data->m_index == l_indix) + { + l_mcc_record->m_offset_array = l_mct_data; + break; + } + ++l_mct_data; + } + if + (l_mcc_record->m_offset_array == 00) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading MCC marker\n"); + return false; + } + } + } + if + (p_header_size != 0) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading MCC marker\n"); + return false; + } + ++l_tcp->m_nb_mcc_records; + return true; +} + +/** + * Writes the MCT marker (Multiple Component Transform) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_write_mct_record( + opj_j2k_t *p_j2k, + opj_mct_data_t * p_mct_record, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 l_mct_size; + OPJ_BYTE * l_current_data = 00; + OPJ_UINT32 l_tmp; + + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + l_mct_size = 10 + p_mct_record->m_data_size; + if + (l_mct_size > p_j2k->m_specific_param.m_encoder.m_header_tile_data_size) + { + p_j2k->m_specific_param.m_encoder.m_header_tile_data + = (OPJ_BYTE*)opj_realloc( + p_j2k->m_specific_param.m_encoder.m_header_tile_data, + l_mct_size); + if + (! p_j2k->m_specific_param.m_encoder.m_header_tile_data) + { + return false; + } + p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = l_mct_size; + } + + l_current_data = p_j2k->m_specific_param.m_encoder.m_header_tile_data; + + opj_write_bytes(l_current_data,J2K_MS_MCT,2); /* MCT */ + l_current_data += 2; + opj_write_bytes(l_current_data,l_mct_size-2,2); /* Lmct */ + l_current_data += 2; + opj_write_bytes(l_current_data,0,2); /* Zmct */ + l_current_data += 2; + /* only one marker atm */ + l_tmp = (p_mct_record->m_index & 0xff) | (p_mct_record->m_array_type << 8) | (p_mct_record->m_element_type << 10); + opj_write_bytes(l_current_data,l_tmp,2); + l_current_data += 2; + opj_write_bytes(l_current_data,0,2); /* Ymct */ + l_current_data+=2; + + memcpy(l_current_data,p_mct_record->m_data,p_mct_record->m_data_size); + if + (opj_stream_write_data(p_stream,p_j2k->m_specific_param.m_encoder.m_header_tile_data,l_mct_size,p_manager) != l_mct_size) + { + return false; + } + return true; +} + +/** + * Reads a MCT marker (Multiple Component Transform) + * + * @param p_header_data the data contained in the MCT box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the MCT marker. + * @param p_manager the user event manager. +*/ +bool j2k_read_mct ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 i; + opj_tcp_t *l_tcp = 00; + OPJ_UINT32 l_tmp; + OPJ_UINT32 l_indix; + opj_mct_data_t * l_mct_data; + + // preconditions + assert(p_header_data != 00); + assert(p_j2k != 00); + + l_tcp = p_j2k->m_specific_param.m_decoder.m_state == J2K_DEC_STATE_TPH ? &p_j2k->m_cp.tcps[p_j2k->m_current_tile_number] : p_j2k->m_specific_param.m_decoder.m_default_tcp; + + if + (p_header_size < 2) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading MCT marker\n"); + return false; + } + /* first marker */ + opj_read_bytes(p_header_data,&l_tmp,2); /* Zmct */ + p_header_data += 2; + if + (l_tmp != 0) + { + opj_event_msg(p_manager, EVT_WARNING, "Cannot take in charge mct data within multiple MCT records\n"); + return true; + } + if + (p_header_size <= 6) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading MCT marker\n"); + return false; + } + opj_read_bytes(p_header_data,&l_tmp,2); /* Imct -> no need for other values, take the first, type is double with decorrelation x0000 1101 0000 0000*/ + p_header_data += 2; + + l_indix = l_tmp & 0xff; + l_mct_data = l_tcp->m_mct_records; + for + (i=0;im_nb_mct_records;++i) + { + if + (l_mct_data->m_index == l_indix) + { + break; + } + ++l_mct_data; + } + /* NOT FOUND */ + if + (i == l_tcp->m_nb_mct_records) + { + if + (l_tcp->m_nb_mct_records == l_tcp->m_nb_max_mct_records) + { + l_tcp->m_nb_max_mct_records += J2K_MCT_DEFAULT_NB_RECORDS; + l_tcp->m_mct_records = (opj_mct_data_t*)opj_realloc(l_tcp->m_mct_records,l_tcp->m_nb_max_mct_records * sizeof(opj_mct_data_t)); + if + (! l_tcp->m_mct_records) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading MCT marker\n"); + return false; + } + l_mct_data = l_tcp->m_mct_records + l_tcp->m_nb_mct_records; + memset(l_mct_data ,0,(l_tcp->m_nb_max_mct_records - l_tcp->m_nb_mct_records) * sizeof(opj_mct_data_t)); + } + l_mct_data = l_tcp->m_mct_records + l_tcp->m_nb_mct_records; + } + if + (l_mct_data->m_data) + { + opj_free(l_mct_data->m_data); + l_mct_data->m_data = 00; + } + l_mct_data->m_index = l_indix; + l_mct_data->m_array_type = (J2K_MCT_ARRAY_TYPE)((l_tmp >> 8) & 3); + l_mct_data->m_element_type = (J2K_MCT_ELEMENT_TYPE)((l_tmp >> 10) & 3); + + opj_read_bytes(p_header_data,&l_tmp,2); /* Ymct */ + p_header_data+=2; + if + (l_tmp != 0) + { + opj_event_msg(p_manager, EVT_WARNING, "Cannot take in charge multiple MCT markers\n"); + return true; + } + p_header_size -= 6; + l_mct_data->m_data = (OPJ_BYTE*)opj_malloc(p_header_size); + if + (! l_mct_data->m_data) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading MCT marker\n"); + return false; + } + memcpy(l_mct_data->m_data,p_header_data,p_header_size); + l_mct_data->m_data_size = p_header_size; + ++l_tcp->m_nb_mct_records; + return true; +} + +bool j2k_setup_mct_encoding (opj_tcp_t * p_tcp,opj_image_t * p_image) +{ + OPJ_UINT32 i; + OPJ_UINT32 l_indix = 1; + opj_mct_data_t * l_mct_deco_data = 00,* l_mct_offset_data = 00; + opj_simple_mcc_decorrelation_data_t * l_mcc_data; + OPJ_UINT32 l_mct_size,l_nb_elem; + OPJ_FLOAT32 * l_data, * l_current_data; + opj_tccp_t * l_tccp; + + // preconditions + assert(p_tcp != 00); + + if + (p_tcp->mct != 2) + { + return true; + } + + if + (p_tcp->m_mct_decoding_matrix) + { + if + (p_tcp->m_nb_mct_records == p_tcp->m_nb_max_mct_records) + { + p_tcp->m_nb_max_mct_records += J2K_MCT_DEFAULT_NB_RECORDS; + p_tcp->m_mct_records = (opj_mct_data_t*)opj_realloc(p_tcp->m_mct_records,p_tcp->m_nb_max_mct_records * sizeof(opj_mct_data_t)); + if + (! p_tcp->m_mct_records) + { + return false; + } + l_mct_deco_data = p_tcp->m_mct_records + p_tcp->m_nb_mct_records; + memset(l_mct_deco_data ,0,(p_tcp->m_nb_max_mct_records - p_tcp->m_nb_mct_records) * sizeof(opj_mct_data_t)); + } + l_mct_deco_data = p_tcp->m_mct_records + p_tcp->m_nb_mct_records; + + if + (l_mct_deco_data->m_data) + { + opj_free(l_mct_deco_data->m_data); + l_mct_deco_data->m_data = 00; + } + l_mct_deco_data->m_index = l_indix++; + l_mct_deco_data->m_array_type = MCT_TYPE_DECORRELATION; + l_mct_deco_data->m_element_type = MCT_TYPE_FLOAT; + l_nb_elem = p_image->numcomps * p_image->numcomps; + l_mct_size = l_nb_elem * MCT_ELEMENT_SIZE[l_mct_deco_data->m_element_type]; + l_mct_deco_data->m_data = (OPJ_BYTE*)opj_malloc(l_mct_size ); + if + (! l_mct_deco_data->m_data) + { + return false; + } + j2k_mct_write_functions_from_float[l_mct_deco_data->m_element_type](p_tcp->m_mct_decoding_matrix,l_mct_deco_data->m_data,l_nb_elem); + l_mct_deco_data->m_data_size = l_mct_size; + ++p_tcp->m_nb_mct_records; + } + + if + (p_tcp->m_nb_mct_records == p_tcp->m_nb_max_mct_records) + { + p_tcp->m_nb_max_mct_records += J2K_MCT_DEFAULT_NB_RECORDS; + p_tcp->m_mct_records = (opj_mct_data_t*)opj_realloc(p_tcp->m_mct_records,p_tcp->m_nb_max_mct_records * sizeof(opj_mct_data_t)); + if + (! p_tcp->m_mct_records) + { + return false; + } + l_mct_offset_data = p_tcp->m_mct_records + p_tcp->m_nb_mct_records; + memset(l_mct_offset_data ,0,(p_tcp->m_nb_max_mct_records - p_tcp->m_nb_mct_records) * sizeof(opj_mct_data_t)); + if + (l_mct_deco_data) + { + l_mct_deco_data = l_mct_offset_data - 1; + } + } + l_mct_offset_data = p_tcp->m_mct_records + p_tcp->m_nb_mct_records; + if + (l_mct_offset_data->m_data) + { + opj_free(l_mct_offset_data->m_data); + l_mct_offset_data->m_data = 00; + } + + l_mct_offset_data->m_index = l_indix++; + l_mct_offset_data->m_array_type = MCT_TYPE_OFFSET; + l_mct_offset_data->m_element_type = MCT_TYPE_FLOAT; + l_nb_elem = p_image->numcomps; + l_mct_size = l_nb_elem * MCT_ELEMENT_SIZE[l_mct_offset_data->m_element_type]; + l_mct_offset_data->m_data = (OPJ_BYTE*)opj_malloc(l_mct_size ); + if + (! l_mct_offset_data->m_data) + { + return false; + } + l_data = (OPJ_FLOAT32*)opj_malloc(l_nb_elem * sizeof(OPJ_FLOAT32)); + if + (! l_data) + { + opj_free(l_mct_offset_data->m_data); + l_mct_offset_data->m_data = 00; + return false; + } + l_tccp = p_tcp->tccps; + l_current_data = l_data; + for + (i=0;im_dc_level_shift); + ++l_tccp; + } + j2k_mct_write_functions_from_float[l_mct_offset_data->m_element_type](l_data,l_mct_offset_data->m_data,l_nb_elem); + opj_free(l_data); + l_mct_offset_data->m_data_size = l_mct_size; + ++p_tcp->m_nb_mct_records; + + if + (p_tcp->m_nb_mcc_records == p_tcp->m_nb_max_mcc_records) + { + p_tcp->m_nb_max_mcc_records += J2K_MCT_DEFAULT_NB_RECORDS; + p_tcp->m_mcc_records = (opj_simple_mcc_decorrelation_data_t*) + opj_realloc(p_tcp->m_mcc_records,p_tcp->m_nb_max_mcc_records * sizeof(opj_simple_mcc_decorrelation_data_t)); + if + (! p_tcp->m_mcc_records) + { + return false; + } + l_mcc_data = p_tcp->m_mcc_records + p_tcp->m_nb_mcc_records; + memset(l_mcc_data ,0,(p_tcp->m_nb_max_mcc_records - p_tcp->m_nb_mcc_records) * sizeof(opj_simple_mcc_decorrelation_data_t)); + + } + l_mcc_data = p_tcp->m_mcc_records + p_tcp->m_nb_mcc_records; + l_mcc_data->m_decorrelation_array = l_mct_deco_data; + l_mcc_data->m_is_irreversible = 1; + l_mcc_data->m_nb_comps = p_image->numcomps; + l_mcc_data->m_index = l_indix++; + l_mcc_data->m_offset_array = l_mct_offset_data; + ++p_tcp->m_nb_mcc_records; + return true; +} + +/** + * Writes the MCO marker (Multiple component transformation ordering) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_write_mco( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + OPJ_BYTE * l_current_data = 00; + OPJ_UINT32 l_mco_size; + opj_tcp_t * l_tcp = 00; + opj_simple_mcc_decorrelation_data_t * l_mcc_record; + OPJ_UINT32 i; + + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + l_tcp =&(p_j2k->m_cp.tcps[p_j2k->m_current_tile_number]); + l_current_data = p_j2k->m_specific_param.m_encoder.m_header_tile_data; + l_mco_size = 5 + l_tcp->m_nb_mcc_records; + if + (l_mco_size > p_j2k->m_specific_param.m_encoder.m_header_tile_data_size) + { + p_j2k->m_specific_param.m_encoder.m_header_tile_data + = (OPJ_BYTE*)opj_realloc( + p_j2k->m_specific_param.m_encoder.m_header_tile_data, + l_mco_size); + if + (! p_j2k->m_specific_param.m_encoder.m_header_tile_data) + { + return false; + } + p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = l_mco_size; + } + + opj_write_bytes(l_current_data,J2K_MS_MCO,2); /* MCO */ + l_current_data += 2; + opj_write_bytes(l_current_data,l_mco_size-2,2); /* Lmco */ + l_current_data += 2; + opj_write_bytes(l_current_data,l_tcp->m_nb_mcc_records,1); /* Nmco : only one tranform stage*/ + ++l_current_data; + + l_mcc_record = l_tcp->m_mcc_records; + for + (i=0;im_nb_mcc_records;++i) + { + opj_write_bytes(l_current_data,l_mcc_record->m_index,1); /* Imco -> use the mcc indicated by 1*/ + ++l_current_data; + ++l_mcc_record; + } + + if + (opj_stream_write_data(p_stream,p_j2k->m_specific_param.m_encoder.m_header_tile_data,l_mco_size,p_manager) != l_mco_size) + { + return false; + } + return true; +} +/** + * Reads a MCO marker (Multiple Component Transform Ordering) + * + * @param p_header_data the data contained in the MCO box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the MCO marker. + * @param p_manager the user event manager. +*/ +bool j2k_read_mco ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 l_tmp, i; + OPJ_UINT32 l_nb_stages; + opj_tcp_t * l_tcp; + opj_tccp_t * l_tccp; + opj_image_t * l_image; + opj_image_comp_t * l_img_comp; + + // preconditions + assert(p_header_data != 00); + assert(p_j2k != 00); + assert(p_manager != 00); + + l_image = p_j2k->m_image; + l_tcp = p_j2k->m_specific_param.m_decoder.m_state == J2K_DEC_STATE_TPH ? &p_j2k->m_cp.tcps[p_j2k->m_current_tile_number] : p_j2k->m_specific_param.m_decoder.m_default_tcp; + if + (p_header_size < 1) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading MCO marker\n"); + return false; + } + + opj_read_bytes(p_header_data,&l_nb_stages,1); /* Nmco : only one tranform stage*/ + ++p_header_data; + if + (l_nb_stages > 1) + { + opj_event_msg(p_manager, EVT_WARNING, "Cannot take in charge multiple transformation stages.\n"); + return true; + } + if + (p_header_size != l_nb_stages + 1) + { + opj_event_msg(p_manager, EVT_WARNING, "Error reading MCO marker\n"); + return false; + } + + l_tccp = l_tcp->tccps; + l_img_comp = l_image->comps; + for + (i=0;inumcomps;++i) + { + l_tccp->m_dc_level_shift = 0; + ++l_tccp; + } + if + (l_tcp->m_mct_decoding_matrix) + { + opj_free(l_tcp->m_mct_decoding_matrix); + l_tcp->m_mct_decoding_matrix = 00; + } + + for + (i=0;im_image,l_tmp)) + { + return false; + } + } + return true; +} + +bool j2k_add_mct(opj_tcp_t * p_tcp,opj_image_t * p_image, OPJ_UINT32 p_index) +{ + OPJ_UINT32 i; + opj_simple_mcc_decorrelation_data_t * l_mcc_record; + opj_mct_data_t * l_deco_array, * l_offset_array; + OPJ_UINT32 l_data_size,l_mct_size, l_offset_size; + OPJ_UINT32 l_nb_elem; + OPJ_UINT32 * l_offset_data, * l_current_offset_data; + opj_tccp_t * l_tccp; + + + // preconditions + assert(p_tcp != 00); + + l_mcc_record = p_tcp->m_mcc_records; + for + (i=0;im_nb_mcc_records;++i) + { + if + (l_mcc_record->m_index == p_index) + { + break; + } + } + if + (i==p_tcp->m_nb_mcc_records) + { + /** element discarded **/ + return true; + } + if + (l_mcc_record->m_nb_comps != p_image->numcomps) + { + /** do not support number of comps != image */ + return true; + } + l_deco_array = l_mcc_record->m_decorrelation_array; + if + (l_deco_array) + { + l_data_size = MCT_ELEMENT_SIZE[l_deco_array->m_element_type] * p_image->numcomps * p_image->numcomps; + if + (l_deco_array->m_data_size != l_data_size) + { + return false; + } + l_nb_elem = p_image->numcomps * p_image->numcomps; + l_mct_size = l_nb_elem * sizeof(OPJ_FLOAT32); + p_tcp->m_mct_decoding_matrix = (OPJ_FLOAT32*)opj_malloc(l_mct_size); + if + (! p_tcp->m_mct_decoding_matrix ) + { + return false; + } + j2k_mct_read_functions_to_float[l_deco_array->m_element_type](l_deco_array->m_data,p_tcp->m_mct_decoding_matrix,l_nb_elem); + } + l_offset_array = l_mcc_record->m_offset_array; + if + (l_offset_array) + { + l_data_size = MCT_ELEMENT_SIZE[l_offset_array->m_element_type] * p_image->numcomps; + if + (l_offset_array->m_data_size != l_data_size) + { + return false; + } + l_nb_elem = p_image->numcomps; + l_offset_size = l_nb_elem * sizeof(OPJ_UINT32); + l_offset_data = (OPJ_UINT32*)opj_malloc(l_offset_size); + if + (! l_offset_data ) + { + return false; + } + j2k_mct_read_functions_to_int32[l_offset_array->m_element_type](l_offset_array->m_data,l_offset_data,l_nb_elem); + l_tccp = p_tcp->tccps; + l_current_offset_data = l_offset_data; + for + (i=0;inumcomps;++i) + { + l_tccp->m_dc_level_shift = *(l_current_offset_data++); + ++l_tccp; + } + opj_free(l_offset_data); + } + return true; +} + +/** + * Writes the MCT marker (Multiple Component Transform) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_write_mct_data_group( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 i; + opj_simple_mcc_decorrelation_data_t * l_mcc_record; + opj_mct_data_t * l_mct_record; + opj_tcp_t * l_tcp; + + // preconditions + assert(p_j2k != 00); + assert(p_stream != 00); + assert(p_manager != 00); + + if + (! j2k_write_cbd(p_j2k,p_stream,p_manager)) + { + return false; + } + l_tcp = &(p_j2k->m_cp.tcps[p_j2k->m_current_tile_number]); + l_mct_record = l_tcp->m_mct_records; + for + (i=0;im_nb_mct_records;++i) + { + if + (! j2k_write_mct_record(p_j2k,l_mct_record,p_stream,p_manager)) + { + return false; + } + ++l_mct_record; + } + l_mcc_record = l_tcp->m_mcc_records; + for + (i=0;im_nb_mcc_records;++i) + { + if + (! j2k_write_mcc_record(p_j2k,l_mcc_record,p_stream,p_manager)) + { + return false; + } + ++l_mcc_record; + } + if + (! j2k_write_mco(p_j2k,p_stream,p_manager)) + { + return false; + } + return true; +} + + +/** + * Writes the POC marker (Progression Order Change) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_write_poc( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 l_nb_comp; + OPJ_UINT32 l_nb_poc; + OPJ_UINT32 l_poc_size; + OPJ_UINT32 l_written_size = 0; + opj_tcp_t *l_tcp = 00; + opj_tccp_t *l_tccp = 00; + OPJ_UINT32 l_poc_room; + + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + l_tcp = &p_j2k->m_cp.tcps[p_j2k->m_current_tile_number]; + l_tccp = &l_tcp->tccps[0]; + l_nb_comp = p_j2k->m_image->numcomps; + l_nb_poc = 1 + l_tcp->numpocs; + if + (l_nb_comp <= 256) + { + l_poc_room = 1; + } + else + { + l_poc_room = 2; + } + l_poc_size = 4 + (5 + 2 * l_poc_room) * l_nb_poc; + if + (l_poc_size > p_j2k->m_specific_param.m_encoder.m_header_tile_data_size) + { + p_j2k->m_specific_param.m_encoder.m_header_tile_data + = (OPJ_BYTE*)opj_realloc( + p_j2k->m_specific_param.m_encoder.m_header_tile_data, + l_poc_size); + if + (! p_j2k->m_specific_param.m_encoder.m_header_tile_data) + { + return false; + } + p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = l_poc_size; + } + + j2k_write_poc_in_memory(p_j2k,p_j2k->m_specific_param.m_encoder.m_header_tile_data,&l_written_size,p_manager); + + if + (opj_stream_write_data(p_stream,p_j2k->m_specific_param.m_encoder.m_header_tile_data,l_poc_size,p_manager) != l_poc_size) + { + return false; + } + return true; +} + + +/** + * Writes EPC ???? + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_write_epc( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + opj_codestream_info_t * l_info = 00; + + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + l_info = p_j2k->cstr_info; + if + (l_info) + { + l_info->codestream_size = opj_stream_tell(p_stream); + /* UniPG>> */ + /* The following adjustment is done to adjust the codestream size */ + /* if SOD is not at 0 in the buffer. Useful in case of JP2, where */ + /* the first bunch of bytes is not in the codestream */ + l_info->codestream_size -= l_info->main_head_start; + /* <epc_on) { + + /* encode according to JPWL */ + jpwl_encode(p_j2k, p_stream, image); + + } +#endif /* USE_JPWL */ + return true; +} + + +/** + * Gets the maximum size taken by the writting of a POC. + */ +OPJ_UINT32 j2k_get_max_poc_size(opj_j2k_t *p_j2k) +{ + opj_tcp_t * l_tcp = 00; + OPJ_UINT32 l_nb_tiles = 0; + OPJ_UINT32 l_max_poc = 0; + OPJ_UINT32 i; + + l_tcp = p_j2k->m_cp.tcps; + l_nb_tiles = p_j2k->m_cp.th * p_j2k->m_cp.tw; + + for + (i=0;inumpocs); + ++l_tcp; + } + ++l_max_poc; + return 4 + 9 * l_max_poc; +} + + +/** + * Writes the POC marker (Progression Order Change) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +void j2k_write_poc_in_memory( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 i; + OPJ_BYTE * l_current_data = 00; + OPJ_UINT32 l_nb_comp; + OPJ_UINT32 l_nb_poc; + OPJ_UINT32 l_poc_size; + opj_image_t *l_image = 00; + opj_tcp_t *l_tcp = 00; + opj_tccp_t *l_tccp = 00; + opj_poc_t *l_current_poc = 00; + OPJ_UINT32 l_poc_room; + + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + + l_tcp = &p_j2k->m_cp.tcps[p_j2k->m_current_tile_number]; + l_tccp = &l_tcp->tccps[0]; + l_image = p_j2k->m_image; + l_nb_comp = l_image->numcomps; + l_nb_poc = 1 + l_tcp->numpocs; + if + (l_nb_comp <= 256) + { + l_poc_room = 1; + } + else + { + l_poc_room = 2; + } + l_poc_size = 4 + (5 + 2 * l_poc_room) * l_nb_poc; + + l_current_data = p_data; + + opj_write_bytes(l_current_data,J2K_MS_POC,2); /* POC */ + l_current_data += 2; + opj_write_bytes(l_current_data,l_poc_size-2,2); /* Lpoc */ + l_current_data += 2; + + l_current_poc = l_tcp->pocs; + for + (i = 0; i < l_nb_poc; ++i) + { + opj_write_bytes(l_current_data,l_current_poc->resno0,1); /* RSpoc_i */ + ++l_current_data; + opj_write_bytes(l_current_data,l_current_poc->compno0,l_poc_room); /* CSpoc_i */ + l_current_data+=l_poc_room; + opj_write_bytes(l_current_data,l_current_poc->layno1,2); /* LYEpoc_i */ + l_current_data+=2; + opj_write_bytes(l_current_data,l_current_poc->resno1,1); /* REpoc_i */ + ++l_current_data; + opj_write_bytes(l_current_data,l_current_poc->compno1,l_poc_room); /* CEpoc_i */ + l_current_data+=l_poc_room; + opj_write_bytes(l_current_data,l_current_poc->prg,1); /* Ppoc_i */ + ++l_current_data; + + /* change the value of the max layer according to the actual number of layers in the file, components and resolutions*/ + l_current_poc->layno1 = int_min(l_current_poc->layno1, l_tcp->numlayers); + l_current_poc->resno1 = int_min(l_current_poc->resno1, l_tccp->numresolutions); + l_current_poc->compno1 = int_min(l_current_poc->compno1, l_nb_comp); + ++l_current_poc; + } + * p_data_written = l_poc_size; +} + + +/** + * Reads a POC marker (Progression Order Change) + * + * @param p_header_data the data contained in the POC box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the POC marker. + * @param p_manager the user event manager. +*/ +bool j2k_read_poc ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 i; + OPJ_UINT32 l_nb_comp; + opj_image_t * l_image = 00; + OPJ_UINT32 l_old_poc_nb,l_current_poc_nb,l_current_poc_remaining; + OPJ_UINT32 l_chunk_size; + OPJ_UINT32 l_tmp; + + opj_cp_t *l_cp = 00; + opj_tcp_t *l_tcp = 00; + opj_poc_t *l_current_poc = 00; + OPJ_UINT32 l_comp_room; + + // preconditions + assert(p_header_data != 00); + assert(p_j2k != 00); + assert(p_manager != 00); + + l_image = p_j2k->m_image; + l_nb_comp = l_image->numcomps; + if + (l_nb_comp <= 256) + { + l_comp_room = 1; + } + else + { + l_comp_room = 2; + } + l_chunk_size = 5 + 2 * l_comp_room; + l_current_poc_nb = p_header_size / l_chunk_size; + l_current_poc_remaining = p_header_size % l_chunk_size; + + if + ((l_current_poc_nb <= 0) || (l_current_poc_remaining != 0)) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading POC marker\n"); + return false; + } + + l_cp = &(p_j2k->m_cp); + l_tcp = (p_j2k->m_specific_param.m_decoder.m_state == J2K_DEC_STATE_TPH) ? &l_cp->tcps[p_j2k->m_current_tile_number] : p_j2k->m_specific_param.m_decoder.m_default_tcp; + l_old_poc_nb = l_tcp->POC ? l_tcp->numpocs + 1 : 0; + l_current_poc_nb += l_old_poc_nb; + assert(l_current_poc_nb < 32); + + /* now poc is in use.*/ + l_tcp->POC = 1; + + l_current_poc = &l_tcp->pocs[l_old_poc_nb]; + for + (i = l_old_poc_nb; i < l_current_poc_nb; ++i) + { + opj_read_bytes(p_header_data,&(l_current_poc->resno0),1); /* RSpoc_i */ + ++p_header_data; + opj_read_bytes(p_header_data,&(l_current_poc->compno0),l_comp_room); /* CSpoc_i */ + p_header_data+=l_comp_room; + opj_read_bytes(p_header_data,&(l_current_poc->layno1),2); /* LYEpoc_i */ + p_header_data+=2; + opj_read_bytes(p_header_data,&(l_current_poc->resno1),1); /* REpoc_i */ + ++p_header_data; + opj_read_bytes(p_header_data,&(l_current_poc->compno1),l_comp_room); /* CEpoc_i */ + p_header_data+=l_comp_room; + opj_read_bytes(p_header_data,&l_tmp,1); /* Ppoc_i */ + ++p_header_data; + l_current_poc->prg = (OPJ_PROG_ORDER) l_tmp; + /* make sure comp is in acceptable bounds */ + l_current_poc->compno1 = uint_min(l_current_poc->compno1, l_nb_comp); + ++l_current_poc; + } + l_tcp->numpocs = l_current_poc_nb - 1; + return true; +} + +/** + * Writes the RGN marker (Region Of Interest) + * + * @param p_tile_no the tile to output + * @param p_comp_no the component to output + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_write_rgn( + opj_j2k_t *p_j2k, + OPJ_UINT32 p_tile_no, + OPJ_UINT32 p_comp_no, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + OPJ_BYTE * l_current_data = 00; + OPJ_UINT32 l_nb_comp; + OPJ_UINT32 l_rgn_size; + opj_image_t *l_image = 00; + opj_cp_t *l_cp = 00; + opj_tcp_t *l_tcp = 00; + opj_tccp_t *l_tccp = 00; + OPJ_UINT32 l_comp_room; + + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + l_cp = &(p_j2k->m_cp); + l_tcp = &l_cp->tcps[p_tile_no]; + l_tccp = &l_tcp->tccps[p_comp_no]; + + l_nb_comp = l_image->numcomps; + + if + (l_nb_comp <= 256) + { + l_comp_room = 1; + } + else + { + l_comp_room = 2; + } + l_rgn_size = 6 + l_comp_room; + + l_current_data = p_j2k->m_specific_param.m_encoder.m_header_tile_data; + + opj_write_bytes(l_current_data,J2K_MS_RGN,2); /* RGN */ + l_current_data += 2; + opj_write_bytes(l_current_data,l_rgn_size-2,2); /* Lrgn */ + l_current_data += 2; + opj_write_bytes(l_current_data,p_comp_no,l_comp_room); /* Crgn */ + l_current_data+=l_comp_room; + opj_write_bytes(l_current_data, 0,1); /* Srgn */ + ++l_current_data; + opj_write_bytes(l_current_data, l_tccp->roishift,1); /* SPrgn */ + ++l_current_data; + + if + (opj_stream_write_data(p_stream,p_j2k->m_specific_param.m_encoder.m_header_tile_data,l_rgn_size,p_manager) != l_rgn_size) + { + return false; + } + return true; +} + +/** + * Reads a RGN marker (Region Of Interest) + * + * @param p_header_data the data contained in the POC box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the POC marker. + * @param p_manager the user event manager. +*/ +bool j2k_read_rgn ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 l_nb_comp; + opj_image_t * l_image = 00; + + opj_cp_t *l_cp = 00; + opj_tcp_t *l_tcp = 00; + OPJ_UINT32 l_comp_room; + OPJ_UINT32 l_comp_no; + OPJ_UINT32 l_roi_sty; + + // preconditions + assert(p_header_data != 00); + assert(p_j2k != 00); + assert(p_manager != 00); + + l_image = p_j2k->m_image; + l_nb_comp = l_image->numcomps; + if + (l_nb_comp <= 256) + { + l_comp_room = 1; + } + else + { + l_comp_room = 2; + } + if + (p_header_size != 2 + l_comp_room) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading RGN marker\n"); + return false; + } + + l_cp = &(p_j2k->m_cp); + l_tcp = (p_j2k->m_specific_param.m_decoder.m_state == J2K_DEC_STATE_TPH) ? &l_cp->tcps[p_j2k->m_current_tile_number] : p_j2k->m_specific_param.m_decoder.m_default_tcp; + + opj_read_bytes(p_header_data,&l_comp_no,l_comp_room); /* Crgn */ + p_header_data+=l_comp_room; + opj_read_bytes(p_header_data,&l_roi_sty,1); /* Srgn */ + ++p_header_data; + +#ifdef USE_JPWL + if (p_j2k->m_cp->correct) { + /* totlen is negative or larger than the bytes left!!! */ + if (compno >= numcomps) { + opj_event_msg(p_j2k->cinfo, EVT_ERROR, + "JPWL: bad component number in RGN (%d when there are only %d)\n", + compno, numcomps); + if (!JPWL_ASSUME || JPWL_ASSUME) { + opj_event_msg(p_j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + return; + } + } + }; +#endif /* USE_JPWL */ + + opj_read_bytes(p_header_data,(OPJ_UINT32 *) (&(l_tcp->tccps[l_comp_no].roishift)),1); /* SPrgn */ + ++p_header_data; + return true; + +} + +/** + * Writes the TLM marker (Tile Length Marker) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_write_tlm( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + OPJ_BYTE * l_current_data = 00; + OPJ_UINT32 l_tlm_size; + + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + l_tlm_size = 6 + (5*p_j2k->m_specific_param.m_encoder.m_total_tile_parts); + if + (l_tlm_size > p_j2k->m_specific_param.m_encoder.m_header_tile_data_size) + { + p_j2k->m_specific_param.m_encoder.m_header_tile_data + = (OPJ_BYTE*)opj_realloc( + p_j2k->m_specific_param.m_encoder.m_header_tile_data, + l_tlm_size); + if + (! p_j2k->m_specific_param.m_encoder.m_header_tile_data) + { + return false; + } + p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = l_tlm_size; + } + l_current_data = p_j2k->m_specific_param.m_encoder.m_header_tile_data; + + /* change the way data is written to avoid seeking if possible */ + // TODO + p_j2k->m_specific_param.m_encoder.m_tlm_start = opj_stream_tell(p_stream); + + opj_write_bytes(l_current_data,J2K_MS_TLM,2); /* TLM */ + l_current_data += 2; + opj_write_bytes(l_current_data,l_tlm_size-2,2); /* Lpoc */ + l_current_data += 2; + opj_write_bytes(l_current_data,0,1); /* Ztlm=0*/ + ++l_current_data; + opj_write_bytes(l_current_data,0x50,1); /* Stlm ST=1(8bits-255 tiles max),SP=1(Ptlm=32bits) */ + ++l_current_data; + /* do nothing on the 5 * l_j2k->m_specific_param.m_encoder.m_total_tile_parts remaining data */ + + if + (opj_stream_write_data(p_stream,p_j2k->m_specific_param.m_encoder.m_header_tile_data,l_tlm_size,p_manager) != l_tlm_size) + { + return false; + } + return true; +} + +/** + * Reads a TLM marker (Tile Length Marker) + * + * @param p_header_data the data contained in the TLM box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the TLM marker. + * @param p_manager the user event manager. +*/ +bool j2k_read_tlm ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 l_Ztlm, l_Stlm, l_ST, l_SP, l_tot_num_tp, l_tot_num_tp_remaining, l_quotient, l_Ptlm_size; + // preconditions + assert(p_header_data != 00); + assert(p_j2k != 00); + assert(p_manager != 00); + + if + (p_header_size < 2) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading TLM marker\n"); + return false; + } + p_header_size -= 2; + + + opj_read_bytes(p_header_data,&l_Ztlm,1); /* Ztlm */ + ++p_header_data; + opj_read_bytes(p_header_data,&l_Stlm,1); /* Stlm */ + ++p_header_data; + + l_ST = ((l_Stlm >> 4) & 0x3); + l_SP = (l_Stlm >> 6) & 0x1; + + l_Ptlm_size = (l_SP + 1) * 2; + l_quotient = l_Ptlm_size + l_ST; + + l_tot_num_tp = p_header_size / l_quotient; + l_tot_num_tp_remaining = p_header_size % l_quotient; + if + (l_tot_num_tp_remaining != 0) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading TLM marker\n"); + return false; + } + /* Do not care of this at the moment since only local variables are set here */ + /* + for + (i = 0; i < l_tot_num_tp; ++i) + { + opj_read_bytes(p_header_data,&l_Ttlm_i,l_ST); // Ttlm_i + p_header_data += l_ST; + opj_read_bytes(p_header_data,&l_Ptlm_i,l_Ptlm_size); // Ptlm_i + p_header_data += l_Ptlm_size; + }*/ + return true; +} + +/** + * Reads a CRG marker (Component registration) + * + * @param p_header_data the data contained in the TLM box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the TLM marker. + * @param p_manager the user event manager. +*/ +bool j2k_read_crg ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 l_nb_comp; + // preconditions + assert(p_header_data != 00); + assert(p_j2k != 00); + assert(p_manager != 00); + + l_nb_comp = p_j2k->m_image->numcomps; + + if + (p_header_size != l_nb_comp *4) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading CRG marker\n"); + return false; + } + /* Do not care of this at the moment since only local variables are set here */ + /* + for + (i = 0; i < l_nb_comp; ++i) + { + opj_read_bytes(p_header_data,&l_Xcrg_i,2); // Xcrg_i + p_header_data+=2; + opj_read_bytes(p_header_data,&l_Ycrg_i,2); // Xcrg_i + p_header_data+=2; + } + */ + return true; +} + +/** + * Reads a PLM marker (Packet length, main header marker) + * + * @param p_header_data the data contained in the TLM box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the TLM marker. + * @param p_manager the user event manager. +*/ +bool j2k_read_plm ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ) +{ + // preconditions + assert(p_header_data != 00); + assert(p_j2k != 00); + assert(p_manager != 00); + + if + (p_header_size < 1) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading PLM marker\n"); + return false; + } + /* Do not care of this at the moment since only local variables are set here */ + /* + opj_read_bytes(p_header_data,&l_Zplm,1); // Zplm + ++p_header_data; + --p_header_size; + + while + (p_header_size > 0) + { + opj_read_bytes(p_header_data,&l_Nplm,1); // Nplm + ++p_header_data; + p_header_size -= (1+l_Nplm); + if + (p_header_size < 0) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading PLM marker\n"); + return false; + } + for + (i = 0; i < l_Nplm; ++i) + { + opj_read_bytes(p_header_data,&l_tmp,1); // Iplm_ij + ++p_header_data; + // take only the last seven bytes + l_packet_len |= (l_tmp & 0x7f); + if + (l_tmp & 0x80) + { + l_packet_len <<= 7; + } + else + { + // store packet length and proceed to next packet + l_packet_len = 0; + } + } + if + (l_packet_len != 0) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading PLM marker\n"); + return false; + } + } + */ + return true; +} + +/** + * Reads a PLT marker (Packet length, tile-part header) + * + * @param p_header_data the data contained in the PLT box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the PLT marker. + * @param p_manager the user event manager. +*/ +bool j2k_read_plt ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 l_Zplt, l_tmp, l_packet_len = 0, i; + + // preconditions + assert(p_header_data != 00); + assert(p_j2k != 00); + assert(p_manager != 00); + + if + (p_header_size < 1) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading PLM marker\n"); + return false; + } + + opj_read_bytes(p_header_data,&l_Zplt,1); // Zplt + ++p_header_data; + --p_header_size; + for + (i = 0; i < p_header_size; ++i) + { + opj_read_bytes(p_header_data,&l_tmp,1); // Iplm_ij + ++p_header_data; + // take only the last seven bytes + l_packet_len |= (l_tmp & 0x7f); + if + (l_tmp & 0x80) + { + l_packet_len <<= 7; + } + else + { + // store packet length and proceed to next packet + l_packet_len = 0; + } + } + if + (l_packet_len != 0) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading PLM marker\n"); + return false; + } + return true; +} + +/** + * Reads a PPM marker (Packed packet headers, main header) + * + * @param p_header_data the data contained in the POC box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the POC marker. + * @param p_manager the user event manager. +*/ +bool j2k_read_ppm ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ) +{ + + opj_cp_t *l_cp = 00; + OPJ_UINT32 l_remaining_data, l_Z_ppm, l_N_ppm; + + // preconditions + assert(p_header_data != 00); + assert(p_j2k != 00); + assert(p_manager != 00); + + if + (p_header_size < 1) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading RGN marker\n"); + return false; + } + l_cp = &(p_j2k->m_cp); + l_cp->ppm = 1; + + opj_read_bytes(p_header_data,&l_Z_ppm,1); /* Z_ppm */ + ++p_header_data; + --p_header_size; + + // first PPM marker + if + (l_Z_ppm == 0) + { + if + (p_header_size < 4) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading PPM marker\n"); + return false; + } + // read a N_ppm + opj_read_bytes(p_header_data,&l_N_ppm,4); /* N_ppm */ + p_header_data+=4; + p_header_size-=4; + /* First PPM marker */ + l_cp->ppm_len = l_N_ppm; + l_cp->ppm_data_size = 0; + l_cp->ppm_buffer = (OPJ_BYTE *) opj_malloc(l_cp->ppm_len); + l_cp->ppm_data = l_cp->ppm_buffer; + if + (l_cp->ppm_buffer == 00) + { + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory reading ppm marker\n"); + return false; + } + memset(l_cp->ppm_buffer,0,l_cp->ppm_len); + } + + while + (true) + { + if + (l_cp->ppm_data_size == l_cp->ppm_len) + { + if + (p_header_size >= 4) + { + // read a N_ppm + opj_read_bytes(p_header_data,&l_N_ppm,4); /* N_ppm */ + p_header_data+=4; + p_header_size-=4; + l_cp->ppm_len += l_N_ppm ; + l_cp->ppm_buffer = (OPJ_BYTE *) opj_realloc(l_cp->ppm_buffer, l_cp->ppm_len); + l_cp->ppm_data = l_cp->ppm_buffer; + if + (l_cp->ppm_buffer == 00) + { + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory reading ppm marker\n"); + return false; + } + memset(l_cp->ppm_buffer+l_cp->ppm_data_size,0,l_N_ppm); + } + else + { + return false; + } + } + l_remaining_data = l_cp->ppm_len - l_cp->ppm_data_size; + if + (l_remaining_data <= p_header_size) + { + /* we must store less information than available in the packet */ + memcpy(l_cp->ppm_buffer + l_cp->ppm_data_size , p_header_data , l_remaining_data); + l_cp->ppm_data_size = l_cp->ppm_len; + p_header_size -= l_remaining_data; + p_header_data += l_remaining_data; + } + else + { + memcpy(l_cp->ppm_buffer + l_cp->ppm_data_size , p_header_data , p_header_size); + l_cp->ppm_data_size += p_header_size; + p_header_data += p_header_size; + p_header_size = 0; + break; + } + } + return true; +} + +/** + * Reads a PPT marker (Packed packet headers, tile-part header) + * + * @param p_header_data the data contained in the PPT box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the PPT marker. + * @param p_manager the user event manager. +*/ +bool j2k_read_ppt ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ) +{ + + opj_cp_t *l_cp = 00; + opj_tcp_t *l_tcp = 00; + OPJ_UINT32 l_Z_ppt; + + // preconditions + assert(p_header_data != 00); + assert(p_j2k != 00); + assert(p_manager != 00); + + if + (p_header_size < 1) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading PPT marker\n"); + return false; + } + + l_cp = &(p_j2k->m_cp); + l_tcp = &(l_cp->tcps[p_j2k->m_current_tile_number]); + l_tcp->ppt = 1; + + opj_read_bytes(p_header_data,&l_Z_ppt,1); /* Z_ppt */ + ++p_header_data; + --p_header_size; + + // first PPM marker + if + (l_Z_ppt == 0) + { + /* First PPM marker */ + l_tcp->ppt_len = p_header_size; + l_tcp->ppt_data_size = 0; + l_tcp->ppt_buffer = (OPJ_BYTE *) opj_malloc(l_tcp->ppt_len); + l_tcp->ppt_data = l_tcp->ppt_buffer; + if + (l_tcp->ppt_buffer == 00) + { + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory reading PPT marker\n"); + return false; + } + memset(l_tcp->ppt_buffer,0,l_tcp->ppt_len); + } + else + { + l_tcp->ppt_len += p_header_size; + l_tcp->ppt_buffer = (OPJ_BYTE *) opj_realloc(l_tcp->ppt_buffer,l_tcp->ppt_len); + if + (l_tcp->ppt_buffer == 00) + { + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory reading PPT marker\n"); + return false; + } + l_tcp->ppt_data = l_tcp->ppt_buffer; + memset(l_tcp->ppt_buffer+l_tcp->ppt_data_size,0,p_header_size); + } + memcpy(l_tcp->ppt_buffer+l_tcp->ppt_data_size,p_header_data,p_header_size); + l_tcp->ppt_data_size += p_header_size; + return true; +} + +/** + * Writes the SOT marker (Start of tile-part) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_write_sot( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + const struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + opj_write_bytes(p_data,J2K_MS_SOT,2); /* SOT */ + p_data += 2; + + opj_write_bytes(p_data,10,2); /* Lsot */ + p_data += 2; + + opj_write_bytes(p_data, p_j2k->m_current_tile_number,2); /* Isot */ + p_data += 2; + + /* Psot */ + p_data += 4; + + opj_write_bytes(p_data, p_j2k->m_specific_param.m_encoder.m_current_tile_part_number,1); /* TPsot */ + ++p_data; + + opj_write_bytes(p_data, p_j2k->m_cp.tcps[p_j2k->m_current_tile_number].m_nb_tile_parts,1); /* TNsot */ + ++p_data; + /* UniPG>> */ +#ifdef USE_JPWL + /* update markers struct */ + j2k_add_marker(p_j2k->cstr_info, J2K_MS_SOT, p_j2k->sot_start, len + 2); +#endif /* USE_JPWL */ + + * p_data_written = 12; + return true; +} + +/** + * Reads a PPT marker (Packed packet headers, tile-part header) + * + * @param p_header_data the data contained in the PPT box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the PPT marker. + * @param p_manager the user event manager. +*/ +bool j2k_read_sot ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager + ) +{ + + opj_cp_t *l_cp = 00; + opj_tcp_t *l_tcp = 00; + OPJ_UINT32 l_tot_len, l_num_parts = 0; + OPJ_UINT32 l_current_part; + OPJ_UINT32 l_tile_x,l_tile_y; + + // preconditions + assert(p_header_data != 00); + assert(p_j2k != 00); + assert(p_manager != 00); + + if + (p_header_size != 8) + { + opj_event_msg(p_manager, EVT_ERROR, "Error reading SOT marker\n"); + return false; + } + l_cp = &(p_j2k->m_cp); + opj_read_bytes(p_header_data,&(p_j2k->m_current_tile_number),2); /* Isot */ + p_header_data+=2; + + + l_tcp = &l_cp->tcps[p_j2k->m_current_tile_number]; + l_tile_x = p_j2k->m_current_tile_number % l_cp->tw; + l_tile_y = p_j2k->m_current_tile_number / l_cp->tw; + +#ifdef USE_JPWL + if (p_j2k->m_cp->correct) { + + static int backup_tileno = 0; + + /* tileno is negative or larger than the number of tiles!!! */ + if ((tileno < 0) || (tileno > (cp->tw * cp->th))) { + opj_event_msg(p_j2k->cinfo, EVT_ERROR, + "JPWL: bad tile number (%d out of a maximum of %d)\n", + tileno, (cp->tw * cp->th)); + if (!JPWL_ASSUME) { + opj_event_msg(p_j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + return; + } + /* we try to correct */ + tileno = backup_tileno; + opj_event_msg(p_j2k->cinfo, EVT_WARNING, "- trying to adjust this\n" + "- setting tile number to %d\n", + tileno); + } + + /* keep your private count of tiles */ + backup_tileno++; + }; +#endif /* USE_JPWL */ + + /* look for the tile in the list of already processed tile (in parts). */ + /* Optimization possible here with a more complex data structure and with the removing of tiles */ + /* since the time taken by this function can only grow at the time */ + + opj_read_bytes(p_header_data,&l_tot_len,4); /* Psot */ + p_header_data+=4; + +#ifdef USE_JPWL + if (p_j2k->m_cp->correct) { + + /* totlen is negative or larger than the bytes left!!! */ + if ((totlen < 0) || (totlen > (p_stream_numbytesleft(p_stream) + 8))) { + opj_event_msg(p_j2k->cinfo, EVT_ERROR, + "JPWL: bad tile byte size (%d bytes against %d bytes left)\n", + totlen, p_stream_numbytesleft(p_stream) + 8); + if (!JPWL_ASSUME) { + opj_event_msg(p_j2k->cinfo, EVT_ERROR, "JPWL: giving up\n"); + return; + } + /* we try to correct */ + totlen = 0; + opj_event_msg(p_j2k->cinfo, EVT_WARNING, "- trying to adjust this\n" + "- setting Psot to %d => assuming it is the last tile\n", + totlen); + } + + }; +#endif /* USE_JPWL */ + + if + (!l_tot_len) + { + void* l_data = p_manager->m_error_data; + assert( l_data ); + if( l_data ) + { + OPJ_UINT32 **s = (OPJ_UINT32**)l_data; + assert( s[1] == 0 ); + if( s[1] == 0 ) + { + s[1] = &l_tot_len; + } + } + opj_event_msg(p_manager, EVT_ERROR, "Cannot read data with no size known, giving up\n"); + assert( l_tot_len != 0 ); + if( !l_tot_len ) + return false; + } + + opj_read_bytes(p_header_data,&l_current_part ,1); /* Psot */ + ++p_header_data; + + opj_read_bytes(p_header_data,&l_num_parts ,1); /* Psot */ + ++p_header_data; + + if + (l_num_parts != 0) + { + l_tcp->m_nb_tile_parts = l_num_parts; + } + if + (l_tcp->m_nb_tile_parts) + { + if + (l_tcp->m_nb_tile_parts == (l_current_part + 1)) + { + p_j2k->m_specific_param.m_decoder.m_can_decode = 1; + } + } + p_j2k->m_specific_param.m_decoder.m_sot_length = l_tot_len - 12; + p_j2k->m_specific_param.m_decoder.m_state = J2K_DEC_STATE_TPH; + p_j2k->m_specific_param.m_decoder.m_skip_data = + (l_tile_x < p_j2k->m_specific_param.m_decoder.m_start_tile_x) + || (l_tile_x >= p_j2k->m_specific_param.m_decoder.m_end_tile_x) + || (l_tile_y < p_j2k->m_specific_param.m_decoder.m_start_tile_y) + || (l_tile_y >= p_j2k->m_specific_param.m_decoder.m_end_tile_y); + /* Index */ + + /* move this onto a separate method to call before reading any SOT */ + /*if + TODO + (p_j2k->cstr_info) + { + if + (l_tcp->first) + { + if + (tileno == 0) + { + p_j2k->cstr_info->main_head_end = p_stream_tell(p_stream) - 13; + } + p_j2k->cstr_info->tile[tileno].tileno = tileno; + p_j2k->cstr_info->tile[tileno].start_pos = p_stream_tell(p_stream) - 12; + p_j2k->cstr_info->tile[tileno].end_pos = p_j2k->cstr_info->tile[tileno].start_pos + totlen - 1; + p_j2k->cstr_info->tile[tileno].num_tps = numparts; + if + (numparts) + { + p_j2k->cstr_info->tile[tileno].tp = (opj_tp_info_t *) opj_malloc(numparts * sizeof(opj_tp_info_t)); + } + else + { + p_j2k->cstr_info->tile[tileno].tp = (opj_tp_info_t *) opj_malloc(10 * sizeof(opj_tp_info_t)); // Fixme (10) + } + } + else + { + p_j2k->cstr_info->tile[tileno].end_pos += totlen; + } + p_j2k->cstr_info->tile[tileno].tp[partno].tp_start_pos = p_stream_tell(p_stream) - 12; + p_j2k->cstr_info->tile[tileno].tp[partno].tp_end_pos = + p_j2k->cstr_info->tile[tileno].tp[partno].tp_start_pos + totlen - 1; + }*/ + return true; +} + +/** + * Writes the SOD marker (Start of data) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_write_sod( + opj_j2k_t *p_j2k, + struct opj_tcd * p_tile_coder, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + OPJ_UINT32 p_total_data_size, + const struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + opj_tcp_t *l_tcp = 00; + opj_codestream_info_t *l_cstr_info = 00; + opj_cp_t *l_cp = 00; + + OPJ_UINT32 l_size_tile; + OPJ_UINT32 l_remaining_data; + + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + opj_write_bytes(p_data,J2K_MS_SOD,2); /* SOD */ + p_data += 2; + + /* make room for the EOF marker */ + l_remaining_data = p_total_data_size - 4; + + l_cp = &(p_j2k->m_cp); + l_tcp = &l_cp->tcps[p_j2k->m_current_tile_number]; + l_cstr_info = p_j2k->cstr_info; + + /* update tile coder */ + p_tile_coder->tp_num = p_j2k->m_specific_param.m_encoder.m_current_poc_tile_part_number ; + p_tile_coder->cur_tp_num = p_j2k->m_specific_param.m_encoder.m_current_tile_part_number; + l_size_tile = l_cp->th * l_cp->tw; + + /* INDEX >> */ + if + (l_cstr_info) + { + if + (!p_j2k->m_specific_param.m_encoder.m_current_tile_part_number ) + { + //TODO cstr_info->tile[p_j2k->m_current_tile_number].end_header = p_stream_tell(p_stream) + p_j2k->pos_correction - 1; + l_cstr_info->tile[p_j2k->m_current_tile_number].tileno = p_j2k->m_current_tile_number; + } + else + { + /* + TODO + if + (cstr_info->tile[p_j2k->m_current_tile_number].packet[cstr_info->packno - 1].end_pos < p_stream_tell(p_stream)) + { + cstr_info->tile[p_j2k->m_current_tile_number].packet[cstr_info->packno].start_pos = p_stream_tell(p_stream); + }*/ + + } + /* UniPG>> */ +#ifdef USE_JPWL + /* update markers struct */ + j2k_add_marker(p_j2k->cstr_info, J2K_MS_SOD, p_j2k->sod_start, 2); +#endif /* USE_JPWL */ + /* <m_specific_param.m_encoder.m_current_tile_part_number == 0) + { + p_tile_coder->tcd_image->tiles->packno = 0; + if + (l_cstr_info) + { + l_cstr_info->packno = 0; + } + } + *p_data_written = 0; + if + (! tcd_encode_tile(p_tile_coder, p_j2k->m_current_tile_number, p_data, p_data_written, l_remaining_data , l_cstr_info)) + { + opj_event_msg(p_manager, EVT_ERROR, "Cannot encode tile\n"); + return false; + } + *p_data_written += 2; + return true; +} + +/** + * Updates the Tile Length Marker. + */ +void j2k_update_tlm ( + opj_j2k_t * p_j2k, + OPJ_UINT32 p_tile_part_size + ) +{ + opj_write_bytes(p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_current,p_j2k->m_current_tile_number,1); /* PSOT */ + ++p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_current; + opj_write_bytes(p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_current,p_tile_part_size,4); /* PSOT */ + p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_current += 4; +} + + +/** + * Reads a SOD marker (Start Of Data) + * + * @param p_header_data the data contained in the SOD box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the SOD marker. + * @param p_manager the user event manager. +*/ +bool j2k_read_sod ( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 l_current_read_size; + opj_codestream_info_t * l_cstr_info = 00; + OPJ_BYTE ** l_current_data = 00; + opj_tcp_t * l_tcp = 00; + OPJ_UINT32 * l_tile_len = 00; + + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + l_tcp = &(p_j2k->m_cp.tcps[p_j2k->m_current_tile_number]); + p_j2k->m_specific_param.m_decoder.m_sot_length -= 2; + l_cstr_info = p_j2k->cstr_info; + + l_current_data = &(l_tcp->m_data); + l_tile_len = &l_tcp->m_data_size; + + if + (! *l_current_data) + { + *l_current_data = (OPJ_BYTE*) my_opj_malloc(p_j2k->m_specific_param.m_decoder.m_sot_length); + } + else + { + *l_current_data = (OPJ_BYTE*) my_opj_realloc(*l_current_data, *l_tile_len + p_j2k->m_specific_param.m_decoder.m_sot_length); + } + if + (*l_current_data == 00) + { + opj_event_msg(p_manager, EVT_ERROR, "Cannot decode tile\n"); + return false; + } + + /* Index */ + if + (l_cstr_info) + { + OPJ_SIZE_T l_current_pos = opj_stream_tell(p_stream)-1; + l_cstr_info->tile[p_j2k->m_current_tile_number].tp[p_j2k->m_specific_param.m_encoder.m_current_tile_part_number].tp_end_header = l_current_pos; + if + (p_j2k->m_specific_param.m_encoder.m_current_tile_part_number == 0) + { + l_cstr_info->tile[p_j2k->m_current_tile_number].end_header = l_current_pos; + } + l_cstr_info->packno = 0; + } + l_current_read_size = opj_stream_read_data(p_stream, *l_current_data + *l_tile_len , p_j2k->m_specific_param.m_decoder.m_sot_length,p_manager); + if + (l_current_read_size != p_j2k->m_specific_param.m_decoder.m_sot_length) + { + p_j2k->m_specific_param.m_decoder.m_state = J2K_DEC_STATE_NEOC; + } + else + { + p_j2k->m_specific_param.m_decoder.m_state = J2K_DEC_STATE_TPHSOT; + } + *l_tile_len += l_current_read_size; + return true; +} + +/** + * Writes the EOC marker (End of Codestream) + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_write_eoc( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + opj_write_bytes(p_j2k->m_specific_param.m_encoder.m_header_tile_data,J2K_MS_EOC,2); /* EOC */ + + +/* UniPG>> */ +#ifdef USE_JPWL + /* update markers struct */ + j2k_add_marker(p_j2k->cstr_info, J2K_MS_EOC, p_stream_tell(p_stream) - 2, 2); +#endif /* USE_JPWL */ + + if + (opj_stream_write_data(p_stream,p_j2k->m_specific_param.m_encoder.m_header_tile_data,2,p_manager) != 2) + { + return false; + } + if + (! opj_stream_flush(p_stream,p_manager)) + { + return false; + } + return true; +} + + +/** + * Inits the Info + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_init_info( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + opj_codestream_info_t * l_cstr_info = 00; + + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + l_cstr_info = p_j2k->cstr_info; + + if + (l_cstr_info) + { + OPJ_UINT32 compno; + l_cstr_info->tile = (opj_tile_info_t *) opj_malloc(p_j2k->m_cp.tw * p_j2k->m_cp.th * sizeof(opj_tile_info_t)); + l_cstr_info->image_w = p_j2k->m_image->x1 - p_j2k->m_image->x0; + l_cstr_info->image_h = p_j2k->m_image->y1 - p_j2k->m_image->y0; + l_cstr_info->prog = (&p_j2k->m_cp.tcps[0])->prg; + l_cstr_info->tw = p_j2k->m_cp.tw; + l_cstr_info->th = p_j2k->m_cp.th; + l_cstr_info->tile_x = p_j2k->m_cp.tdx; /* new version parser */ + l_cstr_info->tile_y = p_j2k->m_cp.tdy; /* new version parser */ + l_cstr_info->tile_Ox = p_j2k->m_cp.tx0; /* new version parser */ + l_cstr_info->tile_Oy = p_j2k->m_cp.ty0; /* new version parser */ + l_cstr_info->numcomps = p_j2k->m_image->numcomps; + l_cstr_info->numlayers = (&p_j2k->m_cp.tcps[0])->numlayers; + l_cstr_info->numdecompos = (OPJ_INT32*) opj_malloc(p_j2k->m_image->numcomps * sizeof(OPJ_INT32)); + for (compno=0; compno < p_j2k->m_image->numcomps; compno++) { + l_cstr_info->numdecompos[compno] = (&p_j2k->m_cp.tcps[0])->tccps->numresolutions - 1; + } + l_cstr_info->D_max = 0.0; /* ADD Marcela */ + l_cstr_info->main_head_start = opj_stream_tell(p_stream); /* position of SOC */ + l_cstr_info->maxmarknum = 100; + l_cstr_info->marker = (opj_marker_info_t *) opj_malloc(l_cstr_info->maxmarknum * sizeof(opj_marker_info_t)); + l_cstr_info->marknum = 0; + } + return j2k_calculate_tp(p_j2k,&(p_j2k->m_cp),&p_j2k->m_specific_param.m_encoder.m_total_tile_parts,p_j2k->m_image,p_manager); +} + +/** + * Creates a tile-coder decoder. + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_create_tcd( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + p_j2k->m_tcd = tcd_create(false); + if + (! p_j2k->m_tcd) + { + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to create Tile Coder\n"); + return false; + } + if + (! tcd_init(p_j2k->m_tcd,p_j2k->m_image,&p_j2k->m_cp)) + { + tcd_destroy(p_j2k->m_tcd); + p_j2k->m_tcd = 00; + return false; + } + return true; +} + +OPJ_FLOAT32 get_tp_stride (opj_tcp_t * p_tcp) +{ + return (OPJ_FLOAT32) ((p_tcp->m_nb_tile_parts - 1) * 14); +} + +OPJ_FLOAT32 get_default_stride (opj_tcp_t * p_tcp) +{ + return 0; +} + +/** + * Updates the rates of the tcp. + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_update_rates( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + opj_cp_t * l_cp = 00; + opj_image_t * l_image = 00; + opj_tcp_t * l_tcp = 00; + opj_image_comp_t * l_img_comp = 00; + + OPJ_UINT32 i,j,k; + OPJ_INT32 l_x0,l_y0,l_x1,l_y1; + OPJ_FLOAT32 * l_rates = 0; + OPJ_FLOAT32 l_sot_remove; + OPJ_UINT32 l_bits_empty, l_size_pixel; + OPJ_UINT32 l_tile_size = 0; + OPJ_UINT32 l_last_res; + OPJ_FLOAT32 (* l_tp_stride_func)(opj_tcp_t *) = 00; + + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + + l_cp = &(p_j2k->m_cp); + l_image = p_j2k->m_image; + l_tcp = l_cp->tcps; + + l_bits_empty = 8 * l_image->comps->dx * l_image->comps->dy; + l_size_pixel = l_image->numcomps * l_image->comps->prec; + l_sot_remove = ((OPJ_FLOAT32) opj_stream_tell(p_stream)) / (l_cp->th * l_cp->tw); + + if + (l_cp->m_specific_param.m_enc.m_tp_on) + { + l_tp_stride_func = get_tp_stride; + } + else + { + l_tp_stride_func = get_default_stride; + } + + for + (i=0;ith;++i) + { + for + (j=0;jtw;++j) + { + OPJ_FLOAT32 l_offset = ((*l_tp_stride_func)(l_tcp)) / l_tcp->numlayers; + /* 4 borders of the tile rescale on the image if necessary */ + l_x0 = int_max(l_cp->tx0 + j * l_cp->tdx, l_image->x0); + l_y0 = int_max(l_cp->ty0 + i * l_cp->tdy, l_image->y0); + l_x1 = int_min(l_cp->tx0 + (j + 1) * l_cp->tdx, l_image->x1); + l_y1 = int_min(l_cp->ty0 + (i + 1) * l_cp->tdy, l_image->y1); + l_rates = l_tcp->rates; + + /* Modification of the RATE >> */ + if + (*l_rates) + { + *l_rates = (( (float) (l_size_pixel * (l_x1 - l_x0) * (l_y1 - l_y0))) + / + ((*l_rates) * l_bits_empty) + ) + - + l_offset; + } + ++l_rates; + for + (k = 1; k < l_tcp->numlayers; ++k) + { + if + (*l_rates) + { + *l_rates = (( (OPJ_FLOAT32) (l_size_pixel * (l_x1 - l_x0) * (l_y1 - l_y0))) + / + ((*l_rates) * l_bits_empty) + ) + - + l_offset; + } + ++l_rates; + } + ++l_tcp; + } + } + + l_tcp = l_cp->tcps; + for + (i=0;ith;++i) + { + for + (j=0;jtw;++j) + { + l_rates = l_tcp->rates; + if + (*l_rates) + { + *l_rates -= l_sot_remove; + if + (*l_rates < 30) + { + *l_rates = 30; + } + } + ++l_rates; + l_last_res = l_tcp->numlayers - 1; + for + (k = 1; k < l_last_res; ++k) + { + if + (*l_rates) + { + *l_rates -= l_sot_remove; + if + (*l_rates < *(l_rates - 1) + 10) + { + *l_rates = (*(l_rates - 1)) + 20; + } + } + ++l_rates; + } + if + (*l_rates) + { + *l_rates -= (l_sot_remove + 2.f); + if + (*l_rates < *(l_rates - 1) + 10) + { + *l_rates = (*(l_rates - 1)) + 20; + } + } + ++l_tcp; + } + } + + l_img_comp = l_image->comps; + l_tile_size = 0; + for + (i=0;inumcomps;++i) + { + l_tile_size += ( uint_ceildiv(l_cp->tdx,l_img_comp->dx) + * + uint_ceildiv(l_cp->tdy,l_img_comp->dy) + * + l_img_comp->prec + ); + ++l_img_comp; + } + + l_tile_size = (OPJ_UINT32) (l_tile_size * 0.1625); /* 1.3/8 = 0.1625 */ + l_tile_size += j2k_get_specific_header_sizes(p_j2k); + + p_j2k->m_specific_param.m_encoder.m_encoded_tile_size = l_tile_size; + p_j2k->m_specific_param.m_encoder.m_encoded_tile_data = (OPJ_BYTE *) my_opj_malloc(p_j2k->m_specific_param.m_encoder.m_encoded_tile_size); + if + (p_j2k->m_specific_param.m_encoder.m_encoded_tile_data == 00) + { + return false; + } + if + (l_cp->m_specific_param.m_enc.m_cinema) + { + p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_buffer = (OPJ_BYTE *) opj_malloc(5*p_j2k->m_specific_param.m_encoder.m_total_tile_parts); + if + (! p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_buffer) + { + return false; + } + p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_current = p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_buffer; + } + return true; +} + +/** + * Reads a EOC marker (End Of Codestream) + * + * @param p_header_data the data contained in the SOD box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the SOD marker. + * @param p_manager the user event manager. +*/ +bool j2k_read_eoc ( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 i; + opj_tcd_t * l_tcd = 00; + OPJ_UINT32 l_nb_tiles; + opj_tcp_t * l_tcp = 00; + bool l_success; + + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + l_nb_tiles = p_j2k->m_cp.th * p_j2k->m_cp.tw; + l_tcp = p_j2k->m_cp.tcps; + + l_tcd = tcd_create(true); + if + (l_tcd == 00) + { + opj_event_msg(p_manager, EVT_ERROR, "Cannot decode tile, memory error\n"); + return false; + } + + + + for + (i = 0; i < l_nb_tiles; ++i) + { + if + (l_tcp->m_data) + { + if + (! tcd_init_decode_tile(l_tcd, i)) + { + tcd_destroy(l_tcd); + opj_event_msg(p_manager, EVT_ERROR, "Cannot decode tile, memory error\n"); + return false; + } + l_success = tcd_decode_tile(l_tcd, l_tcp->m_data, l_tcp->m_data_size, i, p_j2k->cstr_info); + /* cleanup */ + if + (! l_success) + { + p_j2k->m_specific_param.m_decoder.m_state |= J2K_DEC_STATE_ERR; + break; + } + } + j2k_tcp_destroy(l_tcp); + ++l_tcp; + } + tcd_destroy(l_tcd); + return true; +} + +/** + * Writes the image components. + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_write_image_components( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 compno; + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + for + (compno = 1; compno < p_j2k->m_image->numcomps; ++compno) + { + if + (! j2k_write_coc(p_j2k,compno,p_stream, p_manager)) + { + return false; + } + if + (! j2k_write_qcc(p_j2k,compno,p_stream, p_manager)) + { + return false; + } + } + return true; +} + +/** + * Writes regions of interests. + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_write_regions( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 compno; + const opj_tccp_t *l_tccp = 00; + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + l_tccp = p_j2k->m_cp.tcps->tccps; + for + (compno = 0; compno < p_j2k->m_image->numcomps; ++compno) + { + if + (l_tccp->roishift) + { + if + (! j2k_write_rgn(p_j2k,0,compno,p_stream,p_manager)) + { + return false; + } + } + ++l_tccp; + } + return true; +} +/** + * Writes the updated tlm. + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_write_updated_tlm( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 l_tlm_size; + OPJ_SIZE_T l_tlm_position, l_current_position; + + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + l_tlm_size = 5 * p_j2k->m_specific_param.m_encoder.m_total_tile_parts; + l_tlm_position = 6 + p_j2k->m_specific_param.m_encoder.m_tlm_start; + l_current_position = opj_stream_tell(p_stream); + + if + (! opj_stream_seek(p_stream,l_tlm_position,p_manager)) + { + return false; + } + if + (opj_stream_write_data(p_stream,p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_buffer,l_tlm_size,p_manager) != l_tlm_size) + { + return false; + } + if + (! opj_stream_seek(p_stream,l_current_position,p_manager)) + { + return false; + } + return true; +} + +/** + * Ends the encoding, i.e. frees memory. + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_end_encoding( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + tcd_destroy(p_j2k->m_tcd); + p_j2k->m_tcd = 00; + + if + (p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_buffer) + { + opj_free(p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_buffer); + p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_buffer = 0; + p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_current = 0; + } + if + (p_j2k->m_specific_param.m_encoder.m_encoded_tile_data) + { + opj_free(p_j2k->m_specific_param.m_encoder.m_encoded_tile_data); + p_j2k->m_specific_param.m_encoder.m_encoded_tile_data = 0; + } + p_j2k->m_specific_param.m_encoder.m_encoded_tile_size = 0; + + return true; +} + +/** + * Gets the offset of the header. + * + * @param p_stream the stream to write data to. + * @param p_j2k J2K codec. + * @param p_manager the user event manager. +*/ +bool j2k_get_end_header( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + p_j2k->cstr_info->main_head_end = opj_stream_tell(p_stream); + return true; +} + + + + +/** + * Reads an unknown marker + * + * @param p_stream the stream object to read from. + * @param p_j2k the jpeg2000 codec. + * @param p_manager the user event manager. + * + * @return true if the marker could be deduced. +*/ +bool j2k_read_unk ( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + OPJ_BYTE l_data [2]; + OPJ_UINT32 l_unknown_size; + // preconditions + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + opj_event_msg(p_manager, EVT_WARNING, "Unknown marker\n"); + +#ifdef USE_JPWL + if (p_j2k->m_cp->correct) { + OPJ_INT32 m = 0, id, i; + OPJ_INT32 min_id = 0, min_dist = 17, cur_dist = 0, tmp_id; + p_stream_seek(p_j2k->p_stream, p_stream_tell(p_j2k->p_stream) - 2); + id = p_stream_read(p_j2k->p_stream, 2); + opj_event_msg(p_j2k->cinfo, EVT_ERROR, + "JPWL: really don't know this marker %x\n", + id); + if (!JPWL_ASSUME) { + opj_event_msg(p_j2k->cinfo, EVT_ERROR, + "- possible synch loss due to uncorrectable codestream errors => giving up\n"); + return; + } + /* OK, activate this at your own risk!!! */ + /* we look for the marker at the minimum hamming distance from this */ + while (j2k_dec_mstab[m].id) { + + /* 1's where they differ */ + tmp_id = j2k_dec_mstab[m].id ^ id; + + /* compute the hamming distance between our id and the current */ + cur_dist = 0; + for (i = 0; i < 16; i++) { + if ((tmp_id >> i) & 0x0001) { + cur_dist++; + } + } + + /* if current distance is smaller, set the minimum */ + if (cur_dist < min_dist) { + min_dist = cur_dist; + min_id = j2k_dec_mstab[m].id; + } + + /* jump to the next marker */ + m++; + } + + /* do we substitute the marker? */ + if (min_dist < JPWL_MAXIMUM_HAMMING) { + opj_event_msg(p_j2k->cinfo, EVT_ERROR, + "- marker %x is at distance %d from the read %x\n", + min_id, min_dist, id); + opj_event_msg(p_j2k->cinfo, EVT_ERROR, + "- trying to substitute in place and crossing fingers!\n"); + p_stream_seek(p_j2k->p_stream, p_stream_tell(p_j2k->p_stream) - 2); + p_stream_write(p_j2k->p_stream, min_id, 2); + + /* rewind */ + p_stream_seek(p_j2k->p_stream, p_stream_tell(p_j2k->p_stream) - 2); + + } + + }; +#endif /* USE_JPWL */ + if + (opj_stream_read_data(p_stream,l_data,2,p_manager) != 2) + { + opj_event_msg(p_manager, EVT_WARNING, "Unknown marker\n"); + return false; + } + opj_read_bytes(l_data,&l_unknown_size,2); + if + (l_unknown_size < 2) + { + return false; + } + l_unknown_size-=2; + + if + (opj_stream_skip(p_stream,l_unknown_size,p_manager) != l_unknown_size) + { + return false; + } + return true; +} + +/** + * Reads the lookup table containing all the marker, status and action, and returns the handler associated + * with the marker value. + * @param p_id Marker value to look up + * + * @return the handler associated with the id. +*/ +const opj_dec_memory_marker_handler_t * j2k_get_marker_handler (OPJ_UINT32 p_id) +{ + const opj_dec_memory_marker_handler_t *e; + for + (e = j2k_memory_marker_handler_tab; e->id != 0; ++e) + { + if + (e->id == p_id) + { + break; + } + } + return e; +} + +/** + * Destroys a tile coding parameter structure. + * + * @param p_tcp the tile coding parameter to destroy. + */ +void j2k_tcp_destroy (opj_tcp_t *p_tcp) +{ + if + (p_tcp == 00) + { + return; + } + if + (p_tcp->ppt_buffer != 00) + { + opj_free(p_tcp->ppt_buffer); + p_tcp->ppt_buffer = 00; + } + if + (p_tcp->tccps != 00) + { + opj_free(p_tcp->tccps); + p_tcp->tccps = 00; + } + if + (p_tcp->m_mct_coding_matrix != 00) + { + opj_free(p_tcp->m_mct_coding_matrix); + p_tcp->m_mct_coding_matrix = 00; + } + if + (p_tcp->m_mct_decoding_matrix != 00) + { + opj_free(p_tcp->m_mct_decoding_matrix); + p_tcp->m_mct_decoding_matrix = 00; + } + if + (p_tcp->m_mcc_records) + { + opj_free(p_tcp->m_mcc_records); + p_tcp->m_mcc_records = 00; + p_tcp->m_nb_max_mcc_records = 0; + p_tcp->m_nb_mcc_records = 0; + } + if + (p_tcp->m_mct_records) + { + opj_mct_data_t * l_mct_data = p_tcp->m_mct_records; + OPJ_UINT32 i; + for + (i=0;im_nb_mct_records;++i) + { + if + (l_mct_data->m_data) + { + opj_free(l_mct_data->m_data); + l_mct_data->m_data = 00; + } + ++l_mct_data; + } + opj_free(p_tcp->m_mct_records); + p_tcp->m_mct_records = 00; + } + + if + (p_tcp->mct_norms != 00) + { + opj_free(p_tcp->mct_norms); + p_tcp->mct_norms = 00; + } + if + (p_tcp->m_data) + { + opj_free(p_tcp->m_data); + p_tcp->m_data = 00; + } +} + +/** + * Destroys a coding parameter structure. + * + * @param p_cp the coding parameter to destroy. + */ +void j2k_cp_destroy (opj_cp_t *p_cp) +{ + OPJ_UINT32 l_nb_tiles; + opj_tcp_t * l_current_tile = 00; + OPJ_UINT32 i; + + if + (p_cp == 00) + { + return; + } + if + (p_cp->tcps != 00) + { + l_current_tile = p_cp->tcps; + l_nb_tiles = p_cp->th * p_cp->tw; + + for + (i = 0; i < l_nb_tiles; ++i) + { + j2k_tcp_destroy(l_current_tile); + ++l_current_tile; + } + opj_free(p_cp->tcps); + p_cp->tcps = 00; + } + if + (p_cp->ppm_buffer != 00) + { + opj_free(p_cp->ppm_buffer); + p_cp->ppm_buffer = 00; + } + if + (p_cp->comment != 00) + { + opj_free(p_cp->comment); + p_cp->comment = 00; + } + if + (! p_cp->m_is_decoder) + { + if + (p_cp->m_specific_param.m_enc.m_matrice) + { + opj_free(p_cp->m_specific_param.m_enc.m_matrice); + p_cp->m_specific_param.m_enc.m_matrice = 00; + } + } +} + +/* ----------------------------------------------------------------------- */ +/* J2K / JPT decoder interface */ +/* ----------------------------------------------------------------------- */ +/** + * Creates a J2K decompression structure. + * + * @return a handle to a J2K decompressor if successful, NULL otherwise. +*/ +opj_j2k_t* j2k_create_decompress() +{ + opj_j2k_t *l_j2k = (opj_j2k_t*) opj_malloc(sizeof(opj_j2k_t)); + if + (!l_j2k) + { + return 00; + } + memset(l_j2k,0,sizeof(opj_j2k_t)); + l_j2k->m_is_decoder = 1; + l_j2k->m_cp.m_is_decoder = 1; + l_j2k->m_specific_param.m_decoder.m_default_tcp = (opj_tcp_t*) opj_malloc(sizeof(opj_tcp_t)); + if + (!l_j2k->m_specific_param.m_decoder.m_default_tcp) + { + opj_free(l_j2k); + return 00; + } + memset(l_j2k->m_specific_param.m_decoder.m_default_tcp,0,sizeof(opj_tcp_t)); + + l_j2k->m_specific_param.m_decoder.m_header_data = (OPJ_BYTE *) opj_malloc(J2K_DEFAULT_HEADER_SIZE); + if + (! l_j2k->m_specific_param.m_decoder.m_header_data) + { + j2k_destroy(l_j2k); + return 00; + } + l_j2k->m_specific_param.m_decoder.m_header_data_size = J2K_DEFAULT_HEADER_SIZE; + + // validation list creation + l_j2k->m_validation_list = opj_procedure_list_create(); + if + (! l_j2k->m_validation_list) + { + j2k_destroy(l_j2k); + return 00; + } + + // execution list creation + l_j2k->m_procedure_list = opj_procedure_list_create(); + if + (! l_j2k->m_procedure_list) + { + j2k_destroy(l_j2k); + return 00; + } + return l_j2k; +} + +opj_j2k_t* j2k_create_compress() +{ + opj_j2k_t *l_j2k = (opj_j2k_t*) opj_malloc(sizeof(opj_j2k_t)); + if + (!l_j2k) + { + return 00; + } + memset(l_j2k,0,sizeof(opj_j2k_t)); + l_j2k->m_is_decoder = 0; + l_j2k->m_cp.m_is_decoder = 0; + + l_j2k->m_specific_param.m_encoder.m_header_tile_data = (OPJ_BYTE *) opj_malloc(J2K_DEFAULT_HEADER_SIZE); + if + (! l_j2k->m_specific_param.m_encoder.m_header_tile_data) + { + j2k_destroy(l_j2k); + return 00; + } + l_j2k->m_specific_param.m_encoder.m_header_tile_data_size = J2K_DEFAULT_HEADER_SIZE; + + // validation list creation + l_j2k->m_validation_list = opj_procedure_list_create(); + if + (! l_j2k->m_validation_list) + { + j2k_destroy(l_j2k); + return 00; + } + + // execution list creation + l_j2k->m_procedure_list = opj_procedure_list_create(); + if + (! l_j2k->m_procedure_list) + { + j2k_destroy(l_j2k); + return 00; + } + return l_j2k; +} + + +/** + * Destroys a jpeg2000 codec. + * + * @param p_j2k the jpeg20000 structure to destroy. + */ +void j2k_destroy (opj_j2k_t *p_j2k) +{ + if + (p_j2k == 00) + { + return; + } + + if + (p_j2k->m_is_decoder) + { + if + (p_j2k->m_specific_param.m_decoder.m_default_tcp != 00) + { + j2k_tcp_destroy(p_j2k->m_specific_param.m_decoder.m_default_tcp); + opj_free(p_j2k->m_specific_param.m_decoder.m_default_tcp); + p_j2k->m_specific_param.m_decoder.m_default_tcp = 00; + } + if + (p_j2k->m_specific_param.m_decoder.m_header_data != 00) + { + opj_free(p_j2k->m_specific_param.m_decoder.m_header_data); + p_j2k->m_specific_param.m_decoder.m_header_data = 00; + p_j2k->m_specific_param.m_decoder.m_header_data_size = 0; + } + + } + else + { + if + (p_j2k->m_specific_param.m_encoder.m_encoded_tile_data) + { + opj_free(p_j2k->m_specific_param.m_encoder.m_encoded_tile_data); + p_j2k->m_specific_param.m_encoder.m_encoded_tile_data = 00; + } + if + (p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_buffer) + { + opj_free(p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_buffer); + p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_buffer = 00; + p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_current = 00; + } + if + (p_j2k->m_specific_param.m_encoder.m_header_tile_data) + { + opj_free(p_j2k->m_specific_param.m_encoder.m_header_tile_data); + p_j2k->m_specific_param.m_encoder.m_header_tile_data = 00; + p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = 0; + } + } + tcd_destroy(p_j2k->m_tcd); + + j2k_cp_destroy(&(p_j2k->m_cp)); + memset(&(p_j2k->m_cp),0,sizeof(opj_cp_t)); + + opj_procedure_list_destroy(p_j2k->m_procedure_list); + p_j2k->m_procedure_list = 00; + + opj_procedure_list_destroy(p_j2k->m_validation_list); + p_j2k->m_procedure_list = 00; + + opj_free(p_j2k); +} + +/** + * Starts a compression scheme, i.e. validates the codec parameters, writes the header. + * + * @param p_j2k the jpeg2000 codec. + * @param p_stream the stream object. + * @param p_manager the user event manager. + * + * @return true if the codec is valid. + */ +bool j2k_start_compress( + opj_j2k_t *p_j2k, + opj_stream_private_t *p_stream, + opj_image_t * p_image, + opj_event_mgr_t * p_manager) +{ + // preconditions + assert(p_j2k != 00); + assert(p_stream != 00); + assert(p_manager != 00); + p_j2k->m_image = p_image; + + + /* customization of the validation */ + j2k_setup_encoding_validation (p_j2k); + + /* validation of the parameters codec */ + if + (! j2k_exec(p_j2k,p_j2k->m_validation_list,p_stream,p_manager)) + { + return false; + } + + /* customization of the encoding */ + j2k_setup_header_writting(p_j2k); + + /* write header */ + if + (! j2k_exec (p_j2k,p_j2k->m_procedure_list,p_stream,p_manager)) + { + return false; + } + return true; +} +/** + * Sets up the procedures to do on reading header. Developpers wanting to extend the library can add their own reading procedures. + */ +void j2k_setup_header_reading (opj_j2k_t *p_j2k) +{ + // preconditions + assert(p_j2k != 00); + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(void*)j2k_read_header_procedure); + + /* DEVELOPER CORNER, add your custom procedures */ + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(void*)j2k_copy_default_tcp_and_create_tcd); + +} + +/** + * Sets up the procedures to do on decoding data. Developpers wanting to extend the library can add their own reading procedures. + */ +void j2k_setup_decoding (opj_j2k_t *p_j2k) +{ + // preconditions + assert(p_j2k != 00); + + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(void*)j2k_decode_tiles); + /* DEVELOPER CORNER, add your custom procedures */ + +} + +/** + * Sets up the procedures to do on writting header. Developpers wanting to extend the library can add their own writting procedures. + */ +void j2k_setup_header_writting (opj_j2k_t *p_j2k) +{ + // preconditions + assert(p_j2k != 00); + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(void*)j2k_init_info ); + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(void*)j2k_write_soc ); + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(void*)j2k_write_siz ); + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(void*)j2k_write_cod ); + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(void*)j2k_write_qcd ); + + + if + (p_j2k->m_cp.m_specific_param.m_enc.m_cinema) + { + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(void*)j2k_write_image_components ); + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(void*)j2k_write_tlm ); + if + (p_j2k->m_cp.m_specific_param.m_enc.m_cinema == CINEMA4K_24) + { + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(void*)j2k_write_poc ); + } + } + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(void*)j2k_write_regions); + + if + (p_j2k->m_cp.comment != 00) + { + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(void*)j2k_write_com); + } + + /* DEVELOPER CORNER, insert your custom procedures */ + if + (p_j2k->m_cp.rsiz & MCT) + { + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(void*)j2k_write_mct_data_group ); + } + /* End of Developer Corner */ + + if + (p_j2k->cstr_info) + { + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(void*)j2k_get_end_header ); + } + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(void*)j2k_create_tcd); + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(void*)j2k_update_rates); +} + +/** + * Sets up the validation ,i.e. adds the procedures to lauch to make sure the codec parameters + * are valid. Developpers wanting to extend the library can add their own validation procedures. + */ +void j2k_setup_end_compress (opj_j2k_t *p_j2k) +{ + // preconditions + assert(p_j2k != 00); + + /* DEVELOPER CORNER, insert your custom procedures */ + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(void*)j2k_write_eoc ); + if + (p_j2k->m_cp.m_specific_param.m_enc.m_cinema) + { + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(void*)j2k_write_updated_tlm); + } + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(void*)j2k_write_epc ); + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(void*)j2k_end_encoding ); + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(void*)j2k_destroy_header_memory); +} + + + +/** + * Sets up the validation ,i.e. adds the procedures to lauch to make sure the codec parameters + * are valid. Developpers wanting to extend the library can add their own validation procedures. + */ +void j2k_setup_encoding_validation (opj_j2k_t *p_j2k) +{ + // preconditions + assert(p_j2k != 00); + opj_procedure_list_add_procedure(p_j2k->m_validation_list, (void*)j2k_build_encoder); + opj_procedure_list_add_procedure(p_j2k->m_validation_list, (void*)j2k_encoding_validation); + + + /* DEVELOPER CORNER, add your custom validation procedure */ + opj_procedure_list_add_procedure(p_j2k->m_validation_list, (void*)j2k_mct_validation); +} + +/** + * Sets up the validation ,i.e. adds the procedures to lauch to make sure the codec parameters + * are valid. Developpers wanting to extend the library can add their own validation procedures. + */ +void j2k_setup_decoding_validation (opj_j2k_t *p_j2k) +{ + // preconditions + assert(p_j2k != 00); + opj_procedure_list_add_procedure(p_j2k->m_validation_list, (void*)j2k_build_decoder); + opj_procedure_list_add_procedure(p_j2k->m_validation_list, (void*)j2k_decoding_validation); + /* DEVELOPER CORNER, add your custom validation procedure */ + +} + + +/** + * Excutes the given procedures on the given codec. + * + * @param p_procedure_list the list of procedures to execute + * @param p_j2k the jpeg2000 codec to execute the procedures on. + * @param p_stream the stream to execute the procedures on. + * @param p_manager the user manager. + * + * @return true if all the procedures were successfully executed. + */ +bool j2k_exec ( + opj_j2k_t * p_j2k, + opj_procedure_list_t * p_procedure_list, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager + ) +{ + bool (** l_procedure) (opj_j2k_t * ,opj_stream_private_t *,opj_event_mgr_t *) = 00; + bool l_result = true; + OPJ_UINT32 l_nb_proc, i; + + // preconditions + assert(p_procedure_list != 00); + assert(p_j2k != 00); + assert(p_stream != 00); + assert(p_manager != 00); + + l_nb_proc = opj_procedure_list_get_nb_procedures(p_procedure_list); + l_procedure = (bool (**) (opj_j2k_t * ,opj_stream_private_t *,opj_event_mgr_t *)) opj_procedure_list_get_first_procedure(p_procedure_list); + for + (i=0;im_specific_param.m_decoder.m_state == J2K_DEC_STATE_NONE); + + /* POINTER validation */ + /* make sure a p_j2k codec is present */ + l_is_valid &= (p_j2k->m_procedure_list != 00); + /* make sure a validation list is present */ + l_is_valid &= (p_j2k->m_validation_list != 00); + + if + ((p_j2k->m_cp.tdx) < (OPJ_UINT32) (1 << p_j2k->m_cp.tcps->tccps->numresolutions)) + { + opj_event_msg(p_manager, EVT_ERROR, "Number of resolutions is too high in comparison to the size of tiles\n"); + return false; + } + if + ((p_j2k->m_cp.tdy) < (OPJ_UINT32) (1 << p_j2k->m_cp.tcps->tccps->numresolutions)) + { + opj_event_msg(p_manager, EVT_ERROR, "Number of resolutions is too high in comparison to the size of tiles\n"); + return false; + } + + /* PARAMETER VALIDATION */ + return l_is_valid; +} + +/** + * The default decoding validation procedure without any extension. + * + * @param p_j2k the jpeg2000 codec to validate. + * @param p_stream the input stream to validate. + * @param p_manager the user event manager. + * + * @return true if the parameters are correct. + */ +bool j2k_decoding_validation ( + opj_j2k_t *p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager + ) +{ + bool l_is_valid = true; + + // preconditions + assert(p_j2k != 00); + assert(p_stream != 00); + assert(p_manager != 00); + + /* STATE checking */ + /* make sure the state is at 0 */ + l_is_valid &= (p_j2k->m_specific_param.m_decoder.m_state == J2K_DEC_STATE_NONE); + + /* POINTER validation */ + /* make sure a p_j2k codec is present */ + /* make sure a procedure list is present */ + l_is_valid &= (p_j2k->m_procedure_list != 00); + /* make sure a validation list is present */ + l_is_valid &= (p_j2k->m_validation_list != 00); + + /* PARAMETER VALIDATION */ + return l_is_valid; +} + +/** + * The mct encoding validation procedure. + * + * @param p_j2k the jpeg2000 codec to validate. + * @param p_stream the input stream to validate. + * @param p_manager the user event manager. + * + * @return true if the parameters are correct. + */ +bool j2k_mct_validation ( + opj_j2k_t * p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager + ) +{ + bool l_is_valid = true; + OPJ_UINT32 i,j; + + // preconditions + assert(p_j2k != 00); + assert(p_stream != 00); + assert(p_manager != 00); + + if + ((p_j2k->m_cp.rsiz & 0x8200) == 0x8200) + { + OPJ_UINT32 l_nb_tiles = p_j2k->m_cp.th * p_j2k->m_cp.tw; + opj_tcp_t * l_tcp = p_j2k->m_cp.tcps; + for + (i=0;imct == 2) + { + opj_tccp_t * l_tccp = l_tcp->tccps; + l_is_valid &= (l_tcp->m_mct_coding_matrix != 00); + for + (j=0;jm_image->numcomps;++j) + { + l_is_valid &= ! (l_tccp->qmfbid & 1); + ++l_tccp; + } + } + ++l_tcp; + } + } + return l_is_valid; +} + +/** + * Builds the cp decoder parameters to use to decode tile. + */ +bool j2k_build_decoder ( + opj_j2k_t * p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager + ) +{ + // add here initialization of cp + // copy paste of setup_decoder + return true; +} + +/** + * Builds the cp encoder parameters to use to encode tile. + */ +bool j2k_build_encoder ( + opj_j2k_t * p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager + ) +{ + // add here initialization of cp + // copy paste of setup_encoder + return true; +} + +bool j2k_copy_default_tcp_and_create_tcd + ( + opj_j2k_t * p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager + ) +{ + opj_tcp_t * l_tcp = 00; + opj_tcp_t * l_default_tcp = 00; + OPJ_UINT32 l_nb_tiles; + OPJ_UINT32 i,j; + opj_tccp_t *l_current_tccp = 00; + OPJ_UINT32 l_tccp_size; + OPJ_UINT32 l_mct_size; + opj_image_t * l_image; + OPJ_UINT32 l_mcc_records_size,l_mct_records_size; + opj_mct_data_t * l_src_mct_rec, *l_dest_mct_rec; + opj_simple_mcc_decorrelation_data_t * l_src_mcc_rec, *l_dest_mcc_rec; + OPJ_UINT32 l_offset; + + // preconditions in debug + assert(p_j2k != 00); + assert(p_stream != 00); + assert(p_manager != 00); + + l_image = p_j2k->m_image; + l_nb_tiles = p_j2k->m_cp.th * p_j2k->m_cp.tw; + l_tcp = p_j2k->m_cp.tcps; + l_tccp_size = l_image->numcomps * sizeof(opj_tccp_t); + l_default_tcp = p_j2k->m_specific_param.m_decoder.m_default_tcp; + l_mct_size = l_image->numcomps * l_image->numcomps * sizeof(OPJ_FLOAT32); + for + (i=0;itccps; + memcpy(l_tcp,l_default_tcp, sizeof(opj_tcp_t)); + l_tcp->ppt = 0; + l_tcp->ppt_data = 00; + l_tcp->tccps = l_current_tccp; + if + (l_default_tcp->m_mct_decoding_matrix) + { + l_tcp->m_mct_decoding_matrix = (OPJ_FLOAT32*)opj_malloc(l_mct_size); + if + (! l_tcp->m_mct_decoding_matrix ) + { + return false; + } + memcpy(l_tcp->m_mct_decoding_matrix,l_default_tcp->m_mct_decoding_matrix,l_mct_size); + } + l_mct_records_size = l_default_tcp->m_nb_max_mct_records * sizeof(opj_mct_data_t); + l_tcp->m_mct_records = (opj_mct_data_t*)opj_malloc(l_mct_records_size); + if + (! l_tcp->m_mct_records) + { + return false; + } + memcpy(l_tcp->m_mct_records, l_default_tcp->m_mct_records,l_mct_records_size); + l_src_mct_rec = l_default_tcp->m_mct_records; + l_dest_mct_rec = l_tcp->m_mct_records; + for + (j=0;jm_nb_mct_records;++j) + { + if + (l_src_mct_rec->m_data) + { + l_dest_mct_rec->m_data = (OPJ_BYTE*) + opj_malloc(l_src_mct_rec->m_data_size); + if + (! l_dest_mct_rec->m_data) + { + return false; + } + memcpy(l_dest_mct_rec->m_data,l_src_mct_rec->m_data,l_src_mct_rec->m_data_size); + } + ++l_src_mct_rec; + ++l_dest_mct_rec; + } + l_mcc_records_size = l_default_tcp->m_nb_max_mcc_records * sizeof(opj_simple_mcc_decorrelation_data_t); + l_tcp->m_mcc_records = (opj_simple_mcc_decorrelation_data_t*) + opj_malloc(l_mcc_records_size); + if + (! l_tcp->m_mcc_records) + { + return false; + } + memcpy(l_tcp->m_mcc_records,l_default_tcp->m_mcc_records,l_mcc_records_size); + l_src_mcc_rec = l_default_tcp->m_mcc_records; + l_dest_mcc_rec = l_tcp->m_mcc_records; + for + (j=0;jm_nb_max_mcc_records;++j) + { + if + (l_src_mcc_rec->m_decorrelation_array) + { + l_offset = l_src_mcc_rec->m_decorrelation_array - l_default_tcp->m_mct_records; + l_dest_mcc_rec->m_decorrelation_array = l_tcp->m_mct_records + l_offset; + } + if + (l_src_mcc_rec->m_offset_array) + { + l_offset = l_src_mcc_rec->m_offset_array - l_default_tcp->m_mct_records; + l_dest_mcc_rec->m_offset_array = l_tcp->m_mct_records + l_offset; + } + ++l_src_mcc_rec; + ++l_dest_mcc_rec; + } + memcpy(l_current_tccp,l_default_tcp->tccps,l_tccp_size); + ++l_tcp; + } + p_j2k->m_tcd = tcd_create(true); + if + (! p_j2k->m_tcd ) + { + return false; + } + if + (! tcd_init(p_j2k->m_tcd, l_image, &(p_j2k->m_cp))) + { + tcd_destroy(p_j2k->m_tcd); + p_j2k->m_tcd = 00; + opj_event_msg(p_manager, EVT_ERROR, "Cannot decode tile, memory error\n"); + return false; + } + return true; +} + +/** + * Destroys the memory associated with the decoding of headers. + */ +bool j2k_destroy_header_memory ( + opj_j2k_t * p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager + ) +{ + // preconditions in debug + assert(p_j2k != 00); + assert(p_stream != 00); + assert(p_manager != 00); + + if + (p_j2k->m_specific_param.m_encoder.m_header_tile_data) + { + opj_free(p_j2k->m_specific_param.m_encoder.m_header_tile_data); + p_j2k->m_specific_param.m_encoder.m_header_tile_data = 0; + } + p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = 0; + return true; +} + +/** + * Sets up the decoder decoding parameters using user parameters. + * Decoding parameters are stored in p_j2k->m_cp. + * + * @param p_j2k J2K codec + * @param p_parameters decompression parameters + * @deprecated +*/ +void j2k_setup_decoder( + opj_j2k_t *p_j2k, + opj_dparameters_t *p_parameters + ) +{ + if + (p_j2k && p_parameters) + { + /* create and initialize the coding parameters structure */ + p_j2k->m_cp.m_specific_param.m_dec.m_reduce = p_parameters->cp_reduce; + p_j2k->m_cp.m_specific_param.m_dec.m_layer = p_parameters->cp_layer; + p_j2k->m_specific_param.m_decoder.m_discard_tiles = p_parameters->m_use_restrict_decode; + if + (p_parameters->m_use_restrict_decode) + { + p_j2k->m_specific_param.m_decoder.m_start_tile_x = p_parameters->m_decode_start_x; + p_j2k->m_specific_param.m_decoder.m_start_tile_y = p_parameters->m_decode_start_y; + p_j2k->m_specific_param.m_decoder.m_end_tile_x = p_parameters->m_decode_end_x; + p_j2k->m_specific_param.m_decoder.m_end_tile_y = p_parameters->m_decode_end_y; + } + +#ifdef USE_JPWL + cp->correct = parameters->jpwl_correct; + cp->exp_comps = parameters->jpwl_exp_comps; + cp->max_tiles = parameters->jpwl_max_tiles; +#endif /* USE_JPWL */ + } +} + +void j2k_setup_encoder(opj_j2k_t *p_j2k, opj_cparameters_t *parameters, opj_image_t *image, struct opj_event_mgr * p_manager) { + OPJ_UINT32 i, j, tileno, numpocs_tile; + opj_cp_t *cp = 00; + bool l_res; + if(!p_j2k || !parameters || ! image) { + return; + } + + /* keep a link to cp so that we can destroy it later in j2k_destroy_compress */ + cp = &(p_j2k->m_cp); + + /* set default values for cp */ + cp->tw = 1; + cp->th = 1; + + /* + copy user encoding parameters + */ + cp->m_specific_param.m_enc.m_cinema = parameters->cp_cinema; + cp->m_specific_param.m_enc.m_max_comp_size = parameters->max_comp_size; + cp->rsiz = parameters->cp_rsiz; + cp->m_specific_param.m_enc.m_disto_alloc = parameters->cp_disto_alloc; + cp->m_specific_param.m_enc.m_fixed_alloc = parameters->cp_fixed_alloc; + cp->m_specific_param.m_enc.m_fixed_quality = parameters->cp_fixed_quality; + + /* mod fixed_quality */ + if + (parameters->cp_matrice) + { + size_t array_size = parameters->tcp_numlayers * parameters->numresolution * 3 * sizeof(OPJ_INT32); + cp->m_specific_param.m_enc.m_matrice = (OPJ_INT32 *) opj_malloc(array_size); + memcpy(cp->m_specific_param.m_enc.m_matrice, parameters->cp_matrice, array_size); + } + + /* tiles */ + cp->tdx = parameters->cp_tdx; + cp->tdy = parameters->cp_tdy; + + /* tile offset */ + cp->tx0 = parameters->cp_tx0; + cp->ty0 = parameters->cp_ty0; + + /* comment string */ + if(parameters->cp_comment) { + cp->comment = (char*)opj_malloc(strlen(parameters->cp_comment) + 1); + if(cp->comment) { + strcpy(cp->comment, parameters->cp_comment); + } + } + + /* + calculate other encoding parameters + */ + + if (parameters->tile_size_on) { + cp->tw = int_ceildiv(image->x1 - cp->tx0, cp->tdx); + cp->th = int_ceildiv(image->y1 - cp->ty0, cp->tdy); + } else { + cp->tdx = image->x1 - cp->tx0; + cp->tdy = image->y1 - cp->ty0; + } + + if + (parameters->tp_on) + { + cp->m_specific_param.m_enc.m_tp_flag = parameters->tp_flag; + cp->m_specific_param.m_enc.m_tp_on = 1; + } + +#ifdef USE_JPWL + /* + calculate JPWL encoding parameters + */ + + if (parameters->jpwl_epc_on) { + OPJ_INT32 i; + + /* set JPWL on */ + cp->epc_on = true; + cp->info_on = false; /* no informative technique */ + + /* set EPB on */ + if ((parameters->jpwl_hprot_MH > 0) || (parameters->jpwl_hprot_TPH[0] > 0)) { + cp->epb_on = true; + + cp->hprot_MH = parameters->jpwl_hprot_MH; + for (i = 0; i < JPWL_MAX_NO_TILESPECS; i++) { + cp->hprot_TPH_tileno[i] = parameters->jpwl_hprot_TPH_tileno[i]; + cp->hprot_TPH[i] = parameters->jpwl_hprot_TPH[i]; + } + /* if tile specs are not specified, copy MH specs */ + if (cp->hprot_TPH[0] == -1) { + cp->hprot_TPH_tileno[0] = 0; + cp->hprot_TPH[0] = parameters->jpwl_hprot_MH; + } + for (i = 0; i < JPWL_MAX_NO_PACKSPECS; i++) { + cp->pprot_tileno[i] = parameters->jpwl_pprot_tileno[i]; + cp->pprot_packno[i] = parameters->jpwl_pprot_packno[i]; + cp->pprot[i] = parameters->jpwl_pprot[i]; + } + } + + /* set ESD writing */ + if ((parameters->jpwl_sens_size == 1) || (parameters->jpwl_sens_size == 2)) { + cp->esd_on = true; + + cp->sens_size = parameters->jpwl_sens_size; + cp->sens_addr = parameters->jpwl_sens_addr; + cp->sens_range = parameters->jpwl_sens_range; + + cp->sens_MH = parameters->jpwl_sens_MH; + for (i = 0; i < JPWL_MAX_NO_TILESPECS; i++) { + cp->sens_TPH_tileno[i] = parameters->jpwl_sens_TPH_tileno[i]; + cp->sens_TPH[i] = parameters->jpwl_sens_TPH[i]; + } + } + + /* always set RED writing to false: we are at the encoder */ + cp->red_on = false; + + } else { + cp->epc_on = false; + } +#endif /* USE_JPWL */ + + + /* initialize the mutiple tiles */ + /* ---------------------------- */ + cp->tcps = (opj_tcp_t*) opj_calloc(cp->tw * cp->th, sizeof(opj_tcp_t)); + if + (parameters->numpocs) + { + /* initialisation of POC */ + l_res = j2k_check_poc_val(parameters->POC,parameters->numpocs, parameters->numresolution, image->numcomps, parameters->tcp_numlayers, p_manager); + // TODO + } + for (tileno = 0; tileno < cp->tw * cp->th; tileno++) { + opj_tcp_t *tcp = &cp->tcps[tileno]; + tcp->numlayers = parameters->tcp_numlayers; + for (j = 0; j < tcp->numlayers; j++) { + if(cp->m_specific_param.m_enc.m_cinema){ + if (cp->m_specific_param.m_enc.m_fixed_quality) { + tcp->distoratio[j] = parameters->tcp_distoratio[j]; + } + tcp->rates[j] = parameters->tcp_rates[j]; + }else{ + if (cp->m_specific_param.m_enc.m_fixed_quality) { /* add fixed_quality */ + tcp->distoratio[j] = parameters->tcp_distoratio[j]; + } else { + tcp->rates[j] = parameters->tcp_rates[j]; + } + } + } + tcp->csty = parameters->csty; + tcp->prg = parameters->prog_order; + tcp->mct = parameters->tcp_mct; + + + + numpocs_tile = 0; + tcp->POC = 0; + if + (parameters->numpocs) + { + /* initialisation of POC */ + tcp->POC = 1; + // TODO + for (i = 0; i < (unsigned int) parameters->numpocs; i++) { + if((tileno == parameters->POC[i].tile - 1) || (parameters->POC[i].tile == -1)) { + opj_poc_t *tcp_poc = &tcp->pocs[numpocs_tile]; + tcp_poc->resno0 = parameters->POC[numpocs_tile].resno0; + tcp_poc->compno0 = parameters->POC[numpocs_tile].compno0; + tcp_poc->layno1 = parameters->POC[numpocs_tile].layno1; + tcp_poc->resno1 = parameters->POC[numpocs_tile].resno1; + tcp_poc->compno1 = parameters->POC[numpocs_tile].compno1; + tcp_poc->prg1 = parameters->POC[numpocs_tile].prg1; + tcp_poc->tile = parameters->POC[numpocs_tile].tile; + numpocs_tile++; + } + } + tcp->numpocs = numpocs_tile -1 ; + }else{ + tcp->numpocs = 0; + } + + tcp->tccps = (opj_tccp_t*) opj_calloc(image->numcomps, sizeof(opj_tccp_t)); + if + (parameters->mct_data) + { + OPJ_UINT32 lMctSize = image->numcomps * image->numcomps * sizeof(OPJ_FLOAT32); + OPJ_FLOAT32 * lTmpBuf = (OPJ_FLOAT32*)opj_malloc(lMctSize); + OPJ_INT32 * l_dc_shift = (OPJ_INT32 *) ((OPJ_BYTE *) parameters->mct_data + lMctSize); + tcp->mct = 2; + tcp->m_mct_coding_matrix = (OPJ_FLOAT32*)opj_malloc(lMctSize); + memcpy(tcp->m_mct_coding_matrix,parameters->mct_data,lMctSize); + memcpy(lTmpBuf,parameters->mct_data,lMctSize); + tcp->m_mct_decoding_matrix = (OPJ_FLOAT32*)opj_malloc(lMctSize); + assert(opj_matrix_inversion_f(lTmpBuf,(tcp->m_mct_decoding_matrix),image->numcomps)); + tcp->mct_norms = (OPJ_FLOAT64*) + opj_malloc(image->numcomps * sizeof(OPJ_FLOAT64)); + opj_calculate_norms(tcp->mct_norms,image->numcomps,tcp->m_mct_decoding_matrix); + opj_free(lTmpBuf); + for + (i = 0; i < image->numcomps; i++) + { + opj_tccp_t *tccp = &tcp->tccps[i]; + tccp->m_dc_level_shift = l_dc_shift[i]; + } + j2k_setup_mct_encoding(tcp,image); + } + else + { + for + (i = 0; i < image->numcomps; i++) + { + opj_tccp_t *tccp = &tcp->tccps[i]; + opj_image_comp_t * l_comp = &(image->comps[i]); + if + (! l_comp->sgnd) + { + tccp->m_dc_level_shift = 1 << (l_comp->prec - 1); + } + } + } + + + for (i = 0; i < image->numcomps; i++) { + opj_tccp_t *tccp = &tcp->tccps[i]; + tccp->csty = parameters->csty & 0x01; /* 0 => one precinct || 1 => custom precinct */ + tccp->numresolutions = parameters->numresolution; + tccp->cblkw = int_floorlog2(parameters->cblockw_init); + tccp->cblkh = int_floorlog2(parameters->cblockh_init); + tccp->cblksty = parameters->mode; + tccp->qmfbid = parameters->irreversible ? 0 : 1; + tccp->qntsty = parameters->irreversible ? J2K_CCP_QNTSTY_SEQNT : J2K_CCP_QNTSTY_NOQNT; + tccp->numgbits = 2; + if (i == parameters->roi_compno) { + tccp->roishift = parameters->roi_shift; + } else { + tccp->roishift = 0; + } + + if(parameters->cp_cinema) + { + //Precinct size for lowest frequency subband=128 + tccp->prcw[0] = 7; + tccp->prch[0] = 7; + //Precinct size at all other resolutions = 256 + for (j = 1; j < tccp->numresolutions; j++) { + tccp->prcw[j] = 8; + tccp->prch[j] = 8; + } + }else{ + if (parameters->csty & J2K_CCP_CSTY_PRT) { + int p = 0; + for (j = tccp->numresolutions - 1; j >= 0; j--) { + if (p < parameters->res_spec) { + + if (parameters->prcw_init[p] < 1) { + tccp->prcw[j] = 1; + } else { + tccp->prcw[j] = int_floorlog2(parameters->prcw_init[p]); + } + + if (parameters->prch_init[p] < 1) { + tccp->prch[j] = 1; + }else { + tccp->prch[j] = int_floorlog2(parameters->prch_init[p]); + } + + } else { + int res_spec = parameters->res_spec; + int size_prcw = parameters->prcw_init[res_spec - 1] >> (p - (res_spec - 1)); + int size_prch = parameters->prch_init[res_spec - 1] >> (p - (res_spec - 1)); + + if (size_prcw < 1) { + tccp->prcw[j] = 1; + } else { + tccp->prcw[j] = int_floorlog2(size_prcw); + } + + if (size_prch < 1) { + tccp->prch[j] = 1; + } else { + tccp->prch[j] = int_floorlog2(size_prch); + } + } + p++; + /*printf("\nsize precinct for level %d : %d,%d\n", j,tccp->prcw[j], tccp->prch[j]); */ + } //end for + } else { + for (j = 0; j < tccp->numresolutions; j++) { + tccp->prcw[j] = 15; + tccp->prch[j] = 15; + } + } + } + + dwt_calc_explicit_stepsizes(tccp, image->comps[i].prec); + } + } + if + (parameters->mct_data) + { + opj_free(parameters->mct_data); + parameters->mct_data = 00; + } +} + +bool j2k_write_first_tile_part ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + OPJ_UINT32 p_total_data_size, + opj_stream_private_t *p_stream, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 compno; + OPJ_UINT32 l_nb_bytes_written = 0; + OPJ_UINT32 l_current_nb_bytes_written; + OPJ_BYTE * l_begin_data = 00; + + opj_tcp_t *l_tcp = 00; + opj_tcd_t * l_tcd = 00; + opj_cp_t * l_cp = 00; + + l_tcd = p_j2k->m_tcd; + l_cp = &(p_j2k->m_cp); + l_tcp = l_cp->tcps + p_j2k->m_current_tile_number; + + l_tcd->cur_pino = 0; + /*Get number of tile parts*/ + + p_j2k->m_specific_param.m_encoder.m_current_poc_tile_part_number = 0; + /* INDEX >> */ + + /* << INDEX */ + l_current_nb_bytes_written = 0; + l_begin_data = p_data; + if + (! j2k_write_sot(p_j2k,p_data,&l_current_nb_bytes_written,p_stream,p_manager)) + { + return false; + } + l_nb_bytes_written += l_current_nb_bytes_written; + p_data += l_current_nb_bytes_written; + p_total_data_size -= l_current_nb_bytes_written; + + if + (l_cp->m_specific_param.m_enc.m_cinema == 0) + { + for + (compno = 1; compno < p_j2k->m_image->numcomps; compno++) + { + l_current_nb_bytes_written = 0; + j2k_write_coc_in_memory(p_j2k,compno,p_data,&l_current_nb_bytes_written,p_manager); + l_nb_bytes_written += l_current_nb_bytes_written; + p_data += l_current_nb_bytes_written; + p_total_data_size -= l_current_nb_bytes_written; + + l_current_nb_bytes_written = 0; + j2k_write_qcc_in_memory(p_j2k,compno,p_data,&l_current_nb_bytes_written,p_manager); + l_nb_bytes_written += l_current_nb_bytes_written; + p_data += l_current_nb_bytes_written; + p_total_data_size -= l_current_nb_bytes_written; + } + if + (l_cp->tcps[p_j2k->m_current_tile_number].numpocs) + { + l_current_nb_bytes_written = 0; + j2k_write_poc_in_memory(p_j2k,p_data,&l_current_nb_bytes_written,p_manager); + l_nb_bytes_written += l_current_nb_bytes_written; + p_data += l_current_nb_bytes_written; + p_total_data_size -= l_current_nb_bytes_written; + } + } + l_current_nb_bytes_written = 0; + if + (! j2k_write_sod(p_j2k,l_tcd,p_data,&l_current_nb_bytes_written,p_total_data_size,p_stream,p_manager)) + { + return false; + } + l_nb_bytes_written += l_current_nb_bytes_written; + * p_data_written = l_nb_bytes_written; + + /* Writing Psot in SOT marker */ + opj_write_bytes(l_begin_data + 6,l_nb_bytes_written,4); /* PSOT */ + if + (l_cp->m_specific_param.m_enc.m_cinema) + { + j2k_update_tlm(p_j2k,l_nb_bytes_written); + } + return true; +} + +bool j2k_write_all_tile_parts( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_data_written, + OPJ_UINT32 p_total_data_size, + opj_stream_private_t *p_stream, + struct opj_event_mgr * p_manager + ) +{ + OPJ_UINT32 tilepartno=0; + OPJ_UINT32 l_nb_bytes_written = 0; + OPJ_UINT32 l_current_nb_bytes_written; + OPJ_UINT32 l_part_tile_size; + OPJ_UINT32 tot_num_tp; + OPJ_UINT32 pino; + + OPJ_BYTE * l_begin_data; + opj_tcp_t *l_tcp = 00; + opj_tcd_t * l_tcd = 00; + opj_cp_t * l_cp = 00; + + + l_tcd = p_j2k->m_tcd; + l_cp = &(p_j2k->m_cp); + l_tcp = l_cp->tcps + p_j2k->m_current_tile_number; + + /*Get number of tile parts*/ + tot_num_tp = j2k_get_num_tp(l_cp,0,p_j2k->m_current_tile_number); + for + (tilepartno = 1; tilepartno < tot_num_tp ; ++tilepartno) + { + p_j2k->m_specific_param.m_encoder.m_current_poc_tile_part_number = tilepartno; + l_current_nb_bytes_written = 0; + l_part_tile_size = 0; + l_begin_data = p_data; + if + (! j2k_write_sot(p_j2k,p_data,&l_current_nb_bytes_written,p_stream,p_manager)) + { + return false; + } + l_nb_bytes_written += l_current_nb_bytes_written; + p_data += l_current_nb_bytes_written; + p_total_data_size -= l_current_nb_bytes_written; + l_part_tile_size += l_nb_bytes_written; + + l_current_nb_bytes_written = 0; + if + (! j2k_write_sod(p_j2k,l_tcd,p_data,&l_current_nb_bytes_written,p_total_data_size,p_stream,p_manager)) + { + return false; + } + p_data += l_current_nb_bytes_written; + l_nb_bytes_written += l_current_nb_bytes_written; + p_total_data_size -= l_current_nb_bytes_written; + l_part_tile_size += l_nb_bytes_written; + + /* Writing Psot in SOT marker */ + opj_write_bytes(l_begin_data + 6,l_part_tile_size,4); /* PSOT */ + + if + (l_cp->m_specific_param.m_enc.m_cinema) + { + j2k_update_tlm(p_j2k,l_part_tile_size); + } + ++p_j2k->m_specific_param.m_encoder.m_current_tile_part_number; + } + for + (pino = 1; pino <= l_tcp->numpocs; ++pino) + { + l_tcd->cur_pino = pino; + /*Get number of tile parts*/ + tot_num_tp = j2k_get_num_tp(l_cp,pino,p_j2k->m_current_tile_number); + for + (tilepartno = 0; tilepartno < tot_num_tp ; ++tilepartno) + { + p_j2k->m_specific_param.m_encoder.m_current_poc_tile_part_number = tilepartno; + l_current_nb_bytes_written = 0; + l_part_tile_size = 0; + l_begin_data = p_data; + if + (! j2k_write_sot(p_j2k,p_data,&l_current_nb_bytes_written,p_stream,p_manager)) + { + return false; + } + l_nb_bytes_written += l_current_nb_bytes_written; + p_data += l_current_nb_bytes_written; + p_total_data_size -= l_current_nb_bytes_written; + l_part_tile_size += l_current_nb_bytes_written; + + l_current_nb_bytes_written = 0; + if + (! j2k_write_sod(p_j2k,l_tcd,p_data,&l_current_nb_bytes_written,p_total_data_size,p_stream,p_manager)) + { + return false; + } + l_nb_bytes_written += l_current_nb_bytes_written; + p_data += l_current_nb_bytes_written; + p_total_data_size -= l_current_nb_bytes_written; + l_part_tile_size += l_current_nb_bytes_written; + + /* Writing Psot in SOT marker */ + opj_write_bytes(l_begin_data + 6,l_part_tile_size,4); /* PSOT */ + + if + (l_cp->m_specific_param.m_enc.m_cinema) + { + j2k_update_tlm(p_j2k,l_part_tile_size); + } + ++p_j2k->m_specific_param.m_encoder.m_current_tile_part_number; + } + } + *p_data_written = l_nb_bytes_written; + return true; +} + + +bool j2k_pre_write_tile ( + opj_j2k_t * p_j2k, + OPJ_UINT32 p_tile_index, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager + ) +{ + if + (p_tile_index != p_j2k->m_current_tile_number) + { + opj_event_msg(p_manager, EVT_ERROR, "The given tile index does not match." ); + return false; + } + + opj_event_msg(p_manager, EVT_INFO, "tile number %d / %d\n", p_j2k->m_current_tile_number + 1, p_j2k->m_cp.tw * p_j2k->m_cp.th); + + p_j2k->m_specific_param.m_encoder.m_current_tile_part_number = 0; + p_j2k->m_tcd->cur_totnum_tp = p_j2k->m_cp.tcps[p_tile_index].m_nb_tile_parts; + p_j2k->m_specific_param.m_encoder.m_current_poc_tile_part_number = 0; + /* initialisation before tile encoding */ + if + (! tcd_init_encode_tile(p_j2k->m_tcd, p_j2k->m_current_tile_number)) + { + return false; + } + return true; +} + +/** + * Writes a tile. + * @param p_j2k the jpeg2000 codec. + * @param p_stream the stream to write data to. + * @param p_manager the user event manager. + */ +bool j2k_write_tile ( + opj_j2k_t * p_j2k, + OPJ_UINT32 p_tile_index, + OPJ_BYTE * p_data, + OPJ_UINT32 p_data_size, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager + ) +{ + if + (! j2k_pre_write_tile(p_j2k,p_tile_index,p_stream,p_manager)) + { + return false; + } + return j2k_post_write_tile(p_j2k,p_data,p_data_size,p_stream,p_manager); +} + +/** + * Writes a tile. + * @param p_j2k the jpeg2000 codec. + * @param p_stream the stream to write data to. + * @param p_manager the user event manager. + */ +bool j2k_post_write_tile ( + opj_j2k_t * p_j2k, + OPJ_BYTE * p_data, + OPJ_UINT32 p_data_size, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager + ) +{ + opj_tcd_t * l_tcd = 00; + opj_cp_t * l_cp = 00; + opj_tcp_t * l_tcp = 00; + OPJ_UINT32 l_nb_bytes_written; + OPJ_BYTE * l_current_data = 00; + OPJ_UINT32 l_tile_size = 0; + OPJ_UINT32 l_available_data; + + assert(p_j2k->m_specific_param.m_encoder.m_encoded_tile_data); + + l_tcd = p_j2k->m_tcd; + l_cp = &(p_j2k->m_cp); + l_tcp = l_cp->tcps + p_j2k->m_current_tile_number; + + l_tile_size = p_j2k->m_specific_param.m_encoder.m_encoded_tile_size; + l_available_data = l_tile_size; + l_current_data = p_j2k->m_specific_param.m_encoder.m_encoded_tile_data; + if + (! tcd_copy_tile_data(l_tcd,p_data,p_data_size)) + { + opj_event_msg(p_manager, EVT_ERROR, "Size mismtach between tile data and sent data." ); + return false; + } + + l_nb_bytes_written = 0; + if + (! j2k_write_first_tile_part(p_j2k,l_current_data,&l_nb_bytes_written,l_available_data,p_stream,p_manager)) + { + return false; + } + l_current_data += l_nb_bytes_written; + l_available_data -= l_nb_bytes_written; + + l_nb_bytes_written = 0; + if + (! j2k_write_all_tile_parts(p_j2k,l_current_data,&l_nb_bytes_written,l_available_data,p_stream,p_manager)) + { + return false; + } + + l_available_data -= l_nb_bytes_written; + l_nb_bytes_written = l_tile_size - l_available_data; + + if + (opj_stream_write_data(p_stream,p_j2k->m_specific_param.m_encoder.m_encoded_tile_data,l_nb_bytes_written,p_manager) != l_nb_bytes_written) + { + return false; + } + ++p_j2k->m_current_tile_number; + return true; +} + +/** + * Reads a tile header. + * @param p_j2k the jpeg2000 codec. + * @param p_stream the stream to write data to. + * @param p_manager the user event manager. + */ +bool j2k_read_tile_header ( + opj_j2k_t * p_j2k, + OPJ_UINT32 * p_tile_index, + OPJ_UINT32 * p_data_size, + OPJ_INT32 * p_tile_x0, + OPJ_INT32 * p_tile_y0, + OPJ_INT32 * p_tile_x1, + OPJ_INT32 * p_tile_y1, + OPJ_UINT32 * p_nb_comps, + bool * p_go_on, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager + ) +{ + OPJ_UINT32 l_current_marker = J2K_MS_SOT; + OPJ_UINT32 l_marker_size; + const opj_dec_memory_marker_handler_t * l_marker_handler = 00; + opj_tcp_t * l_tcp = 00; + OPJ_UINT32 l_nb_tiles; + + // preconditions + assert(p_stream != 00); + assert(p_j2k != 00); + assert(p_manager != 00); + + if + (p_j2k->m_specific_param.m_decoder.m_state == J2K_DEC_STATE_EOC) + { + l_current_marker = J2K_MS_EOC; + } + else if + (p_j2k->m_specific_param.m_decoder.m_state != J2K_DEC_STATE_TPHSOT) + { + return false; + } + + while + (! p_j2k->m_specific_param.m_decoder.m_can_decode && l_current_marker != J2K_MS_EOC) + { + while + (l_current_marker != J2K_MS_SOD) + { + if + (opj_stream_read_data(p_stream,p_j2k->m_specific_param.m_decoder.m_header_data,2,p_manager) != 2) + { + opj_event_msg(p_manager, EVT_ERROR, "Stream too short\n"); + return false; + } + opj_read_bytes(p_j2k->m_specific_param.m_decoder.m_header_data,&l_marker_size,2); + if + (p_j2k->m_specific_param.m_decoder.m_state & J2K_DEC_STATE_TPH) + { + p_j2k->m_specific_param.m_decoder.m_sot_length -= (l_marker_size + 2); + } + l_marker_size -= 2; + + l_marker_handler = j2k_get_marker_handler(l_current_marker); + // Check if the marker is known + if + (! (p_j2k->m_specific_param.m_decoder.m_state & l_marker_handler->states) ) + { + opj_event_msg(p_manager, EVT_ERROR, "Marker is not compliant with its position\n"); + return false; + } + if + (l_marker_size > p_j2k->m_specific_param.m_decoder.m_header_data_size) + { + p_j2k->m_specific_param.m_decoder.m_header_data = (OPJ_BYTE*) + opj_realloc(p_j2k->m_specific_param.m_decoder.m_header_data,l_marker_size); + if + (p_j2k->m_specific_param.m_decoder.m_header_data == 00) + { + return false; + } + p_j2k->m_specific_param.m_decoder.m_header_data_size = l_marker_size; + + } + if + (opj_stream_read_data(p_stream,p_j2k->m_specific_param.m_decoder.m_header_data,l_marker_size,p_manager) != l_marker_size) + { + opj_event_msg(p_manager, EVT_ERROR, "Stream too short\n"); + return false; + } + if + (! (*(l_marker_handler->handler))(p_j2k,p_j2k->m_specific_param.m_decoder.m_header_data,l_marker_size,p_manager)) + { + opj_event_msg(p_manager, EVT_ERROR, "Marker is not compliant with its position\n"); + return false; + } + if + (p_j2k->m_specific_param.m_decoder.m_skip_data) + { + if + (opj_stream_skip(p_stream,p_j2k->m_specific_param.m_decoder.m_sot_length,p_manager) != p_j2k->m_specific_param.m_decoder.m_sot_length) + { + opj_event_msg(p_manager, EVT_ERROR, "Stream too short\n"); + return false; + } + l_current_marker = J2K_MS_SOD; + } + else + { + if + (opj_stream_read_data(p_stream,p_j2k->m_specific_param.m_decoder.m_header_data,2,p_manager) != 2) + { + opj_event_msg(p_manager, EVT_ERROR, "Stream too short\n"); + return false; + } + opj_read_bytes(p_j2k->m_specific_param.m_decoder.m_header_data,&l_current_marker,2); + } + } + + if + (! p_j2k->m_specific_param.m_decoder.m_skip_data) + { + if + (! j2k_read_sod(p_j2k,p_stream,p_manager)) + { + return false; + } + } + else + { + p_j2k->m_specific_param.m_decoder.m_skip_data = 0; + p_j2k->m_specific_param.m_decoder.m_can_decode = 0; + p_j2k->m_specific_param.m_decoder.m_state = J2K_DEC_STATE_TPHSOT; + if + (opj_stream_read_data(p_stream,p_j2k->m_specific_param.m_decoder.m_header_data,2,p_manager) != 2) + { + opj_event_msg(p_manager, EVT_ERROR, "Stream too short\n"); + return false; + } + opj_read_bytes(p_j2k->m_specific_param.m_decoder.m_header_data,&l_current_marker,2); + } + } + + if + (l_current_marker == J2K_MS_EOC) + { + if + (p_j2k->m_specific_param.m_decoder.m_state != J2K_DEC_STATE_EOC) + { + p_j2k->m_current_tile_number = 0; + p_j2k->m_specific_param.m_decoder.m_state = J2K_DEC_STATE_EOC; + } + } + if + ( ! p_j2k->m_specific_param.m_decoder.m_can_decode) + { + l_tcp = p_j2k->m_cp.tcps + p_j2k->m_current_tile_number; + l_nb_tiles = p_j2k->m_cp.th * p_j2k->m_cp.tw; + while + ( + (p_j2k->m_current_tile_number < l_nb_tiles) + && (l_tcp->m_data == 00) + ) + { + ++p_j2k->m_current_tile_number; + ++l_tcp; + } + if + (p_j2k->m_current_tile_number == l_nb_tiles) + { + *p_go_on = false; + return true; + } + } + if + (! tcd_init_decode_tile(p_j2k->m_tcd, p_j2k->m_current_tile_number)) + { + opj_event_msg(p_manager, EVT_ERROR, "Cannot decode tile, memory error\n"); + return false; + } + *p_tile_index = p_j2k->m_current_tile_number; + *p_go_on = true; + *p_data_size = tcd_get_decoded_tile_size(p_j2k->m_tcd); + * p_tile_x0 = p_j2k->m_tcd->tcd_image->tiles->x0; + * p_tile_y0 = p_j2k->m_tcd->tcd_image->tiles->y0; + * p_tile_x1 = p_j2k->m_tcd->tcd_image->tiles->x1; + * p_tile_y1 = p_j2k->m_tcd->tcd_image->tiles->y1; + * p_nb_comps = p_j2k->m_tcd->tcd_image->tiles->numcomps; + p_j2k->m_specific_param.m_decoder.m_state |= J2K_DEC_STATE_DATA; + return true; +} + +bool j2k_decode_tile ( + opj_j2k_t * p_j2k, + OPJ_UINT32 p_tile_index, + OPJ_BYTE * p_data, + OPJ_UINT32 p_data_size, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager + ) +{ + OPJ_UINT32 l_current_marker; + OPJ_BYTE l_data [2]; + opj_tcp_t * l_tcp; + + // preconditions + assert(p_stream != 00); + assert(p_j2k != 00); + assert(p_manager != 00); + + if + (! (p_j2k->m_specific_param.m_decoder.m_state & J2K_DEC_STATE_DATA) || p_tile_index != p_j2k->m_current_tile_number) + { + return false; + } + l_tcp = &(p_j2k->m_cp.tcps[p_tile_index]); + if + (! l_tcp->m_data) + { + j2k_tcp_destroy(&(p_j2k->m_cp.tcps[p_tile_index])); + return false; + } + if + (! tcd_decode_tile(p_j2k->m_tcd, l_tcp->m_data, l_tcp->m_data_size, p_tile_index, p_j2k->cstr_info)) + { + j2k_tcp_destroy(l_tcp); + p_j2k->m_specific_param.m_decoder.m_state |= J2K_DEC_STATE_ERR; + return false; + } + if + (! tcd_update_tile_data(p_j2k->m_tcd,p_data,p_data_size)) + { + return false; + } + j2k_tcp_destroy(l_tcp); + p_j2k->m_tcd->tcp = 0; + + p_j2k->m_specific_param.m_decoder.m_can_decode = 0; + p_j2k->m_specific_param.m_decoder.m_state &= (~J2K_DEC_STATE_DATA); + if + (p_j2k->m_specific_param.m_decoder.m_state != J2K_DEC_STATE_EOC) + { + if + (opj_stream_read_data(p_stream,l_data,2,p_manager) != 2) + { + opj_event_msg(p_manager, EVT_ERROR, "Stream too short\n"); + return false; + } + opj_read_bytes(l_data,&l_current_marker,2); + if + (l_current_marker == J2K_MS_EOC) + { + p_j2k->m_current_tile_number = 0; + p_j2k->m_specific_param.m_decoder.m_state = J2K_DEC_STATE_EOC; + } + else if + (l_current_marker != J2K_MS_SOT) + { + opj_event_msg(p_manager, EVT_ERROR, "Stream too short, expected SOT\n"); + return false; + } + } + return true; +} + + +/** + * Ends the compression procedures and possibiliy add data to be read after the + * codestream. + */ +bool j2k_end_compress(opj_j2k_t *p_j2k, struct opj_stream_private *p_stream, struct opj_event_mgr * p_manager) +{ + /* customization of the encoding */ + j2k_setup_end_compress(p_j2k); + + if + (! j2k_exec (p_j2k,p_j2k->m_procedure_list,p_stream,p_manager)) + { + return false; + } + return true; +} + +/** + * Reads a jpeg2000 codestream header structure. + * + * @param p_stream the stream to read data from. + * @param p_j2k the jpeg2000 codec. + * @param p_manager the user event manager. + * + * @return true if the box is valid. + */ +bool j2k_read_header( + opj_j2k_t *p_j2k, + struct opj_image ** p_image, + OPJ_INT32 * p_tile_x0, + OPJ_INT32 * p_tile_y0, + OPJ_UINT32 * p_tile_width, + OPJ_UINT32 * p_tile_height, + OPJ_UINT32 * p_nb_tiles_x, + OPJ_UINT32 * p_nb_tiles_y, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + // preconditions + assert(p_j2k != 00); + assert(p_stream != 00); + assert(p_manager != 00); + + *p_image = 00; + /* create an empty image */ + p_j2k->m_image = opj_image_create0(); + if + (! p_j2k->m_image) + { + return false; + } + + /* customization of the validation */ + j2k_setup_decoding_validation (p_j2k); + + /* validation of the parameters codec */ + if + (! j2k_exec(p_j2k,p_j2k->m_validation_list,p_stream,p_manager)) + { + opj_image_destroy(p_j2k->m_image); + p_j2k->m_image = 00; + return false; + } + + /* customization of the encoding */ + j2k_setup_header_reading(p_j2k); + + /* read header */ + if + (! j2k_exec (p_j2k,p_j2k->m_procedure_list,p_stream,p_manager)) + { + opj_image_destroy(p_j2k->m_image); + p_j2k->m_image = 00; + return false; + } + *p_image = p_j2k->m_image; + * p_tile_x0 = p_j2k->m_cp.tx0; + * p_tile_y0 = p_j2k->m_cp.ty0; + * p_tile_width = p_j2k->m_cp.tdx; + * p_tile_height = p_j2k->m_cp.tdy; + * p_nb_tiles_x = p_j2k->m_cp.tw; + * p_nb_tiles_y = p_j2k->m_cp.th; + return true; +} + +/** + * The read header procedure. + */ +bool j2k_read_header_procedure( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager) +{ + OPJ_UINT32 l_current_marker; + OPJ_UINT32 l_marker_size; + const opj_dec_memory_marker_handler_t * l_marker_handler = 00; + + // preconditions + assert(p_stream != 00); + assert(p_j2k != 00); + assert(p_manager != 00); + + p_j2k->m_specific_param.m_decoder.m_state = J2K_DEC_STATE_MHSOC; + + if + (! j2k_read_soc(p_j2k,p_stream,p_manager)) + { + opj_event_msg(p_manager, EVT_ERROR, "Expected a SOC marker \n"); + return false; + } + if + (opj_stream_read_data(p_stream,p_j2k->m_specific_param.m_decoder.m_header_data,2,p_manager) != 2) + { + opj_event_msg(p_manager, EVT_ERROR, "Stream too short\n"); + return false; + } + opj_read_bytes(p_j2k->m_specific_param.m_decoder.m_header_data,&l_current_marker,2); + + while + (l_current_marker != J2K_MS_SOT) + { + if + (opj_stream_read_data(p_stream,p_j2k->m_specific_param.m_decoder.m_header_data,2,p_manager) != 2) + { + opj_event_msg(p_manager, EVT_ERROR, "Stream too short\n"); + return false; + } + opj_read_bytes(p_j2k->m_specific_param.m_decoder.m_header_data,&l_marker_size,2); + l_marker_size -= 2; + /*if + (l_current_marker < 0xff00) + { + opj_event_msg(p_manager, EVT_ERROR, "%.8x: expected a marker instead of %x\n", opj_stream_tell(p_stream) - 2, l_current_marker); + return 0; + } + */ + l_marker_handler = j2k_get_marker_handler(l_current_marker); + // Check if the marker is known + if + (! (p_j2k->m_specific_param.m_decoder.m_state & l_marker_handler->states) ) + { + opj_event_msg(p_manager, EVT_ERROR, "Marker is not compliant with its position\n"); + return false; + } + if + (l_marker_size > p_j2k->m_specific_param.m_decoder.m_header_data_size) + { + p_j2k->m_specific_param.m_decoder.m_header_data = (OPJ_BYTE*) + opj_realloc(p_j2k->m_specific_param.m_decoder.m_header_data,l_marker_size); + if + (p_j2k->m_specific_param.m_decoder.m_header_data == 00) + { + return false; + } + p_j2k->m_specific_param.m_decoder.m_header_data_size = l_marker_size; + } + if + (opj_stream_read_data(p_stream,p_j2k->m_specific_param.m_decoder.m_header_data,l_marker_size,p_manager) != l_marker_size) + { + opj_event_msg(p_manager, EVT_ERROR, "Stream too short\n"); + return false; + } + if + (! (*(l_marker_handler->handler))(p_j2k,p_j2k->m_specific_param.m_decoder.m_header_data,l_marker_size,p_manager)) + { + opj_event_msg(p_manager, EVT_ERROR, "Marker is not compliant with its position\n"); + return false; + } + if + (opj_stream_read_data(p_stream,p_j2k->m_specific_param.m_decoder.m_header_data,2,p_manager) != 2) + { + opj_event_msg(p_manager, EVT_ERROR, "Stream too short\n"); + return false; + } + opj_read_bytes(p_j2k->m_specific_param.m_decoder.m_header_data,&l_current_marker,2); + } + p_j2k->m_specific_param.m_decoder.m_state = J2K_DEC_STATE_TPHSOT; + return true; +} + + + +/** + * Reads the tiles. + */ +bool j2k_decode_tiles ( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager) +{ + bool l_go_on = true; + OPJ_UINT32 l_current_tile_no; + OPJ_UINT32 l_data_size,l_max_data_size; + OPJ_INT32 l_tile_x0,l_tile_y0,l_tile_x1,l_tile_y1; + OPJ_UINT32 l_nb_comps; + OPJ_BYTE * l_current_data; + + l_current_data = (OPJ_BYTE*)opj_malloc(1000); + if + (! l_current_data) + { + return false; + } + l_max_data_size = 1000; + + while + (true) + { + if + (! j2k_read_tile_header( + p_j2k,&l_current_tile_no, + &l_data_size, + &l_tile_x0, + &l_tile_y0, + &l_tile_x1, + &l_tile_y1, + &l_nb_comps, + &l_go_on, + p_stream, + p_manager)) + { + return false; + } + if + (! l_go_on) + { + break; + } + if + (l_data_size > l_max_data_size) + { + l_current_data = (OPJ_BYTE*)opj_realloc(l_current_data,l_data_size); + if + (! l_current_data) + { + return false; + } + l_max_data_size = l_data_size; + } + if + (! j2k_decode_tile(p_j2k,l_current_tile_no,l_current_data,l_data_size,p_stream,p_manager)) + { + opj_free(l_current_data); + return false; + } + if + (! j2k_update_image_data(p_j2k->m_tcd,l_current_data)) + { + opj_free(l_current_data); + return false; + } + + } + opj_free(l_current_data); + return true; +} + + + + + + +/** + * Decodes the tiles of the stream. + */ +opj_image_t * j2k_decode( + opj_j2k_t * p_j2k, + opj_stream_private_t * p_stream, + opj_event_mgr_t * p_manager) +{ + /* customization of the encoding */ + j2k_setup_decoding(p_j2k); + + /* write header */ + if + (! j2k_exec (p_j2k,p_j2k->m_procedure_list,p_stream,p_manager)) + { + opj_image_destroy(p_j2k->m_image); + p_j2k->m_image = 00; + } + return p_j2k->m_image; +} + +/** + * Encodes all the tiles in a row. + */ +bool j2k_encode( + opj_j2k_t * p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager + ) +{ + OPJ_UINT32 i; + OPJ_UINT32 l_nb_tiles; + OPJ_UINT32 l_max_tile_size, l_current_tile_size; + OPJ_BYTE * l_current_data; + + // preconditions + assert(p_j2k != 00); + assert(p_stream != 00); + assert(p_manager != 00); + + l_current_data = (OPJ_BYTE*)opj_malloc(1000); + if + (! l_current_data) + { + return false; + } + l_max_tile_size = 1000; + + l_nb_tiles = p_j2k->m_cp.th * p_j2k->m_cp.tw; + for + (i=0;im_tcd); + if + (l_current_tile_size > l_max_tile_size) + { + l_current_data = (OPJ_BYTE*)opj_realloc(l_current_data,l_current_tile_size); + if + (! l_current_data) + { + return false; + } + l_max_tile_size = l_current_tile_size; + } + j2k_get_tile_data(p_j2k->m_tcd,l_current_data); + if + (! j2k_post_write_tile (p_j2k,l_current_data,l_current_tile_size,p_stream,p_manager)) + { + return false; + } + } + opj_free(l_current_data); + return true; +} + + + +/** + * Ends the decompression procedures and possibiliy add data to be read after the + * codestream. + */ +bool j2k_end_decompress( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager) +{ + return true; +} + + + +void j2k_get_tile_data (opj_tcd_t * p_tcd, OPJ_BYTE * p_data) +{ + OPJ_UINT32 i,j,k = 0; + OPJ_UINT32 l_width,l_height,l_stride, l_offset_x,l_offset_y, l_image_width; + opj_image_comp_t * l_img_comp = 00; + opj_tcd_tilecomp_t * l_tilec = 00; + opj_image_t * l_image = 00; + OPJ_UINT32 l_size_comp, l_remaining; + OPJ_INT32 * l_src_ptr; + l_tilec = p_tcd->tcd_image->tiles->comps; + l_image = p_tcd->image; + l_img_comp = l_image->comps; + for + (i=0;iimage->numcomps;++i) + { + l_size_comp = l_img_comp->prec >> 3; /*(/ 8)*/ + l_remaining = l_img_comp->prec & 7; /* (%8) */ + if + (l_remaining) + { + ++l_size_comp; + } + if + (l_size_comp == 3) + { + l_size_comp = 4; + } + l_width = (l_tilec->x1 - l_tilec->x0); + l_height = (l_tilec->y1 - l_tilec->y0); + l_offset_x = int_ceildiv(l_image->x0, l_img_comp->dx); + l_offset_y = int_ceildiv(l_image->y0, l_img_comp->dy); + l_image_width = int_ceildiv(l_image->x1 - l_image->x0, l_img_comp->dx); + l_stride = l_image_width - l_width; + l_src_ptr = l_img_comp->data + (l_tilec->x0 - l_offset_x) + (l_tilec->y0 - l_offset_y) * l_image_width; + + switch + (l_size_comp) + { + case 1: + { + OPJ_CHAR * l_dest_ptr = (OPJ_CHAR*) p_data; + if + (l_img_comp->sgnd) + { + for + (j=0;jsgnd) + { + for + (j=0;jtcd_image->tiles->comps; + l_image = p_tcd->image; + l_img_comp = l_image->comps; + for + (i=0;iimage->numcomps;++i) + { + if + (!l_img_comp->data) + { + l_img_comp->data = (OPJ_INT32*) opj_malloc(l_img_comp->w * l_img_comp->h * sizeof(OPJ_INT32)); + if + (! l_img_comp->data) + { + return false; + } + memset(l_img_comp->data,0,l_img_comp->w * l_img_comp->h * sizeof(OPJ_INT32)); + } + + l_size_comp = l_img_comp->prec >> 3; /*(/ 8)*/ + l_remaining = l_img_comp->prec & 7; /* (%8) */ + l_res = l_tilec->resolutions + l_img_comp->resno_decoded; + + if + (l_remaining) + { + ++l_size_comp; + } + if + (l_size_comp == 3) + { + l_size_comp = 4; + } + l_width = (l_res->x1 - l_res->x0); + l_height = (l_res->y1 - l_res->y0); + l_dest_stride = (l_img_comp->w) - l_width; + l_offset_x = int_ceildivpow2(l_img_comp->x0, l_img_comp->factor); + l_offset_y = int_ceildivpow2(l_img_comp->y0, l_img_comp->factor); + l_dest_ptr = l_img_comp->data + (l_res->x0 - l_offset_x) + (l_res->y0 - l_offset_y) * l_img_comp->w; + + switch + (l_size_comp) + { + case 1: + { + OPJ_CHAR * l_src_ptr = (OPJ_CHAR*) p_data; + if + (l_img_comp->sgnd) + { + for + (j=0;jsgnd) + { + for + (j=0;jm_cp); + + if + (p_j2k->m_specific_param.m_decoder.m_state != J2K_DEC_STATE_TPHSOT) + { + return false; + } + p_j2k->m_specific_param.m_decoder.m_start_tile_x = (p_start_x - l_cp->tx0) / l_cp->tdx; + p_j2k->m_specific_param.m_decoder.m_start_tile_y = (p_start_y - l_cp->ty0) / l_cp->tdy; + p_j2k->m_specific_param.m_decoder.m_end_tile_x = int_ceildiv((p_end_x - l_cp->tx0), l_cp->tdx); + p_j2k->m_specific_param.m_decoder.m_end_tile_y = int_ceildiv((p_end_y - l_cp->ty0), l_cp->tdy); + p_j2k->m_specific_param.m_decoder.m_discard_tiles = 1; + return true; +} + +void j2k_dump_image(FILE *fd, opj_image_t * img) { + OPJ_UINT32 compno; // to avoid signed/unsigned mismatch + fprintf(fd, "image {\n"); + fprintf(fd, " x0=%d, y0=%d, x1=%d, y1=%d\n", img->x0, img->y0, img->x1, img->y1); + fprintf(fd, " numcomps=%d\n", img->numcomps); + for (compno = 0; compno < img->numcomps; compno++) { + opj_image_comp_t *comp = &img->comps[compno]; + fprintf(fd, " comp %d {\n", compno); + fprintf(fd, " dx=%d, dy=%d\n", comp->dx, comp->dy); + fprintf(fd, " prec=%d\n", comp->prec); + //fprintf(fd, " bpp=%d\n", comp->bpp); + fprintf(fd, " sgnd=%d\n", comp->sgnd); + fprintf(fd, " }\n"); + } + fprintf(fd, "}\n"); +} + +/* +void j2k_dump_cp(FILE *fd, opj_image_t * img, opj_cp_t * cp) { + int tileno, compno, layno, bandno, resno, numbands; + fprintf(fd, "coding parameters {\n"); + fprintf(fd, " tx0=%d, ty0=%d\n", cp->tx0, cp->ty0); + fprintf(fd, " tdx=%d, tdy=%d\n", cp->tdx, cp->tdy); + fprintf(fd, " tw=%d, th=%d\n", cp->tw, cp->th); + for (tileno = 0; tileno < cp->tw * cp->th; tileno++) { + opj_tcp_t *tcp = &cp->tcps[tileno]; + fprintf(fd, " tile %d {\n", tileno); + fprintf(fd, " csty=%x\n", tcp->csty); + fprintf(fd, " prg=%d\n", tcp->prg); + fprintf(fd, " numlayers=%d\n", tcp->numlayers); + fprintf(fd, " mct=%d\n", tcp->mct); + fprintf(fd, " rates="); + for (layno = 0; layno < tcp->numlayers; layno++) { + fprintf(fd, "%.1f ", tcp->rates[layno]); + } + fprintf(fd, "\n"); + for (compno = 0; compno < img->numcomps; compno++) { + opj_tccp_t *tccp = &tcp->tccps[compno]; + fprintf(fd, " comp %d {\n", compno); + fprintf(fd, " csty=%x\n", tccp->csty); + fprintf(fd, " numresolutions=%d\n", tccp->numresolutions); + fprintf(fd, " cblkw=%d\n", tccp->cblkw); + fprintf(fd, " cblkh=%d\n", tccp->cblkh); + fprintf(fd, " cblksty=%x\n", tccp->cblksty); + fprintf(fd, " qmfbid=%d\n", tccp->qmfbid); + fprintf(fd, " qntsty=%d\n", tccp->qntsty); + fprintf(fd, " numgbits=%d\n", tccp->numgbits); + fprintf(fd, " roishift=%d\n", tccp->roishift); + fprintf(fd, " stepsizes="); + numbands = tccp->qntsty == J2K_CCP_QNTSTY_SIQNT ? 1 : tccp->numresolutions * 3 - 2; + for (bandno = 0; bandno < numbands; bandno++) { + fprintf(fd, "(%d,%d) ", tccp->stepsizes[bandno].mant, + tccp->stepsizes[bandno].expn); + } + fprintf(fd, "\n"); + + if (tccp->csty & J2K_CCP_CSTY_PRT) { + fprintf(fd, " prcw="); + for (resno = 0; resno < tccp->numresolutions; resno++) { + fprintf(fd, "%d ", tccp->prcw[resno]); + } + fprintf(fd, "\n"); + fprintf(fd, " prch="); + for (resno = 0; resno < tccp->numresolutions; resno++) { + fprintf(fd, "%d ", tccp->prch[resno]); + } + fprintf(fd, "\n"); + } + fprintf(fd, " }\n"); + } + fprintf(fd, " }\n"); + } + fprintf(fd, "}\n"); +} +*/ diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/j2k.h b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/j2k.h new file mode 100644 index 0000000..a6a9f79 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/j2k.h @@ -0,0 +1,737 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2006-2007, Parvatha Elangovan + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __J2K_H +#define __J2K_H +/** +@file j2k.h +@brief The JPEG-2000 Codestream Reader/Writer (J2K) + +The functions in J2K.C have for goal to read/write the several parts of the codestream: markers and data. +*/ + +#include "openjpeg.h" + +struct opj_dparameters; +struct opj_stream_private; +struct opj_event_mgr; +/** @defgroup J2K J2K - JPEG-2000 codestream reader/writer */ +/*@{*/ + +#define J2K_CP_CSTY_PRT 0x01 +#define J2K_CP_CSTY_SOP 0x02 +#define J2K_CP_CSTY_EPH 0x04 +#define J2K_CCP_CSTY_PRT 0x01 +#define J2K_CCP_CBLKSTY_LAZY 0x01 +#define J2K_CCP_CBLKSTY_RESET 0x02 +#define J2K_CCP_CBLKSTY_TERMALL 0x04 +#define J2K_CCP_CBLKSTY_VSC 0x08 +#define J2K_CCP_CBLKSTY_PTERM 0x10 +#define J2K_CCP_CBLKSTY_SEGSYM 0x20 +#define J2K_CCP_QNTSTY_NOQNT 0 +#define J2K_CCP_QNTSTY_SIQNT 1 +#define J2K_CCP_QNTSTY_SEQNT 2 + +/* ----------------------------------------------------------------------- */ + +#define J2K_MS_SOC 0xff4f /**< SOC marker value */ +#define J2K_MS_SOT 0xff90 /**< SOT marker value */ +#define J2K_MS_SOD 0xff93 /**< SOD marker value */ +#define J2K_MS_EOC 0xffd9 /**< EOC marker value */ +#define J2K_MS_SIZ 0xff51 /**< SIZ marker value */ +#define J2K_MS_COD 0xff52 /**< COD marker value */ +#define J2K_MS_COC 0xff53 /**< COC marker value */ +#define J2K_MS_RGN 0xff5e /**< RGN marker value */ +#define J2K_MS_QCD 0xff5c /**< QCD marker value */ +#define J2K_MS_QCC 0xff5d /**< QCC marker value */ +#define J2K_MS_POC 0xff5f /**< POC marker value */ +#define J2K_MS_TLM 0xff55 /**< TLM marker value */ +#define J2K_MS_PLM 0xff57 /**< PLM marker value */ +#define J2K_MS_PLT 0xff58 /**< PLT marker value */ +#define J2K_MS_PPM 0xff60 /**< PPM marker value */ +#define J2K_MS_PPT 0xff61 /**< PPT marker value */ +#define J2K_MS_SOP 0xff91 /**< SOP marker value */ +#define J2K_MS_EPH 0xff92 /**< EPH marker value */ +#define J2K_MS_CRG 0xff63 /**< CRG marker value */ +#define J2K_MS_COM 0xff64 /**< COM marker value */ +#define J2K_MS_CBD 0xff78 /**< CBD marker value */ +#define J2K_MS_MCC 0xff75 /**< MCC marker value */ +#define J2K_MS_MCT 0xff74 /**< MCT marker value */ +#define J2K_MS_MCO 0xff77 /**< MCO marker value */ + +/* UniPG>> */ +#ifdef USE_JPWL +#define J2K_MS_EPC 0xff68 /**< EPC marker value (Part 11: JPEG 2000 for Wireless) */ +#define J2K_MS_EPB 0xff66 /**< EPB marker value (Part 11: JPEG 2000 for Wireless) */ +#define J2K_MS_ESD 0xff67 /**< ESD marker value (Part 11: JPEG 2000 for Wireless) */ +#define J2K_MS_RED 0xff69 /**< RED marker value (Part 11: JPEG 2000 for Wireless) */ +#endif /* USE_JPWL */ +#ifdef USE_JPSEC +#define J2K_MS_SEC 0xff65 /**< SEC marker value (Part 8: Secure JPEG 2000) */ +#define J2K_MS_INSEC 0xff94 /**< INSEC marker value (Part 8: Secure JPEG 2000) */ +#endif /* USE_JPSEC */ +/* < there was a PPT marker for the present tile */ + OPJ_UINT32 ppt : 1; + /** indicates if a POC marker has been used O:NO, 1:YES */ + OPJ_UINT32 POC : 1; +} opj_tcp_t; + +typedef struct opj_encoding_param +{ + /** Digital cinema profile*/ + OPJ_CINEMA_MODE m_cinema; + /** Maximum rate for each component. If == 0, component size limitation is not considered */ + OPJ_UINT32 m_max_comp_size; + /** Position of tile part flag in progression order*/ + OPJ_INT32 m_tp_pos; + /** fixed layer */ + OPJ_INT32 *m_matrice; + /** Flag determining tile part generation*/ + OPJ_BYTE m_tp_flag; + /** allocation by rate/distortion */ + OPJ_UINT32 m_disto_alloc : 1; + /** allocation by fixed layer */ + OPJ_UINT32 m_fixed_alloc : 1; + /** add fixed_quality */ + OPJ_UINT32 m_fixed_quality : 1; + /** Enabling Tile part generation*/ + OPJ_UINT32 m_tp_on : 1; +} +opj_encoding_param_t; + +typedef struct opj_decoding_param +{ + /** if != 0, then original dimension divided by 2^(reduce); if == 0 or not used, image is decoded to the full resolution */ + OPJ_UINT32 m_reduce; + /** if != 0, then only the first "layer" layers are decoded; if == 0 or not used, all the quality layers are decoded */ + OPJ_UINT32 m_layer; +} +opj_decoding_param_t; + +/** +Coding parameters +*/ +typedef struct opj_cp +{ + /** Size of the image in bits*/ + /*int img_size;*/ + /** Rsiz*/ + OPJ_RSIZ_CAPABILITIES rsiz; + /** XTOsiz */ + OPJ_INT32 tx0; + /** YTOsiz */ + OPJ_INT32 ty0; + /** XTsiz */ + OPJ_UINT32 tdx; + /** YTsiz */ + OPJ_UINT32 tdy; + /** comment */ + OPJ_CHAR *comment; + /** number of tiles in width */ + OPJ_UINT32 tw; + /** number of tiles in heigth */ + OPJ_UINT32 th; + /** packet header storage original buffer */ + OPJ_BYTE *ppm_buffer; + /** packet header store there for futur use in t2_decode_packet */ + OPJ_BYTE *ppm_data; + /** size of the ppm_data*/ + OPJ_UINT32 ppm_len; + /** Number of bytes actually stored inside the ppm_data */ + OPJ_UINT32 ppm_data_size; + /** tile coding parameters */ + opj_tcp_t *tcps; + union + { + opj_decoding_param_t m_dec; + opj_encoding_param_t m_enc; + } + m_specific_param; + + +/* UniPG>> */ +#ifdef USE_JPWL + /** enables writing of EPC in MH, thus activating JPWL */ + bool epc_on; + /** enables writing of EPB, in case of activated JPWL */ + bool epb_on; + /** enables writing of ESD, in case of activated JPWL */ + bool esd_on; + /** enables writing of informative techniques of ESD, in case of activated JPWL */ + bool info_on; + /** enables writing of RED, in case of activated JPWL */ + bool red_on; + /** error protection method for MH (0,1,16,32,37-128) */ + int hprot_MH; + /** tile number of header protection specification (>=0) */ + int hprot_TPH_tileno[JPWL_MAX_NO_TILESPECS]; + /** error protection methods for TPHs (0,1,16,32,37-128) */ + int hprot_TPH[JPWL_MAX_NO_TILESPECS]; + /** tile number of packet protection specification (>=0) */ + int pprot_tileno[JPWL_MAX_NO_PACKSPECS]; + /** packet number of packet protection specification (>=0) */ + int pprot_packno[JPWL_MAX_NO_PACKSPECS]; + /** error protection methods for packets (0,1,16,32,37-128) */ + int pprot[JPWL_MAX_NO_PACKSPECS]; + /** enables writing of ESD, (0/2/4 bytes) */ + int sens_size; + /** sensitivity addressing size (0=auto/2/4 bytes) */ + int sens_addr; + /** sensitivity range (0-3) */ + int sens_range; + /** sensitivity method for MH (-1,0-7) */ + int sens_MH; + /** tile number of sensitivity specification (>=0) */ + int sens_TPH_tileno[JPWL_MAX_NO_TILESPECS]; + /** sensitivity methods for TPHs (-1,0-7) */ + int sens_TPH[JPWL_MAX_NO_TILESPECS]; + /** enables JPWL correction at the decoder */ + bool correct; + /** expected number of components at the decoder */ + int exp_comps; + /** maximum number of tiles at the decoder */ + int max_tiles; +#endif /* USE_JPWL */ + + /******** FLAGS *********/ + /** if ppm == 1 --> there was a PPM marker*/ + OPJ_UINT32 ppm : 1; + /** tells if the parameter is a coding or decoding one */ + OPJ_UINT32 m_is_decoder : 1; +/* <cp. + * + * @param p_j2k J2K codec + * @param p_parameters decompression parameters + * @deprecated +*/ +void j2k_setup_decoder( + opj_j2k_t *p_j2k, + struct opj_dparameters *p_parameters + ); +/** + * Reads a jpeg2000 codestream header structure. + * + * @param cio the stream to read data from. + * @param p_j2k the jpeg2000 codec. + * @param p_manager the user event manager. + * + * @return true if the box is valid. + */ +bool j2k_read_header( + opj_j2k_t *p_j2k, + struct opj_image ** p_image, + OPJ_INT32 * p_tile_x0, + OPJ_INT32 * p_tile_y0, + OPJ_UINT32 * p_tile_width, + OPJ_UINT32 * p_tile_height, + OPJ_UINT32 * p_nb_tiles_x, + OPJ_UINT32 * p_nb_tiles_y, + struct opj_stream_private *cio, + struct opj_event_mgr * p_manager + ); +/** +Decode an image from a JPEG-2000 codestream +@param j2k J2K decompressor handle +@param cio Input buffer stream +@param cstr_info Codestream information structure if required, NULL otherwise +@return Returns a decoded image if successful, returns NULL otherwise +*/ +opj_image_t* j2k_decode(opj_j2k_t *j2k, struct opj_stream_private *cio, struct opj_event_mgr * p_manager); + +/** + * Ends the decompression procedures and possibiliy add data to be read after the + * codestream. + */ +bool j2k_end_decompress(opj_j2k_t *j2k, struct opj_stream_private *cio, struct opj_event_mgr * p_manager); + +/** +Decode an image form a JPT-stream (JPEG 2000, JPIP) +@param j2k J2K decompressor handle +@param cio Input buffer stream +@param cstr_info Codestream information structure if required, NULL otherwise +@return Returns a decoded image if successful, returns NULL otherwise +*/ +opj_image_t* j2k_decode_jpt_stream(opj_j2k_t *j2k, struct opj_stream_private *cio, struct opj_codestream_info *cstr_info); + +/** +Creates a J2K compression structure +@param cinfo Codec context info +@return Returns a handle to a J2K compressor if successful, returns NULL otherwise +*/ +opj_j2k_t* j2k_create_compress(); + +/** +Setup the encoder parameters using the current image and using user parameters. +Coding parameters are returned in j2k->cp. +@param j2k J2K compressor handle +@param parameters compression parameters +@param image input filled image +*/ +void j2k_setup_encoder(opj_j2k_t *j2k, opj_cparameters_t *parameters, opj_image_t *image, struct opj_event_mgr * p_manager); + +/** + * Writes a tile. + * @param p_j2k the jpeg2000 codec. + * @param p_stream the stream to write data to. + * @param p_manager the user event manager. + */ +bool j2k_write_tile ( + opj_j2k_t * p_j2k, + OPJ_UINT32 p_tile_index, + OPJ_BYTE * p_data, + OPJ_UINT32 p_data_size, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); + +/** + * Converts an enum type progression order to string type. + * + * @param prg_order the progression order to get. + * + * @return the string representation of the gicen progression order. + */ +const char * j2k_convert_progression_order(OPJ_PROG_ORDER prg_order); + + +/** + * Encodes an image into a JPEG-2000 codestream + */ +bool j2k_encode( + opj_j2k_t * p_j2k, + struct opj_stream_private *cio, + struct opj_event_mgr * p_manager + ); +bool j2k_setup_mct_encoding (opj_tcp_t * p_tcp,opj_image_t * p_image); + +/** + * Decode tile data. + * @param p_j2k the jpeg2000 codec. + * @param p_stream the stream to write data to. + * @param p_manager the user event manager. + */ +bool j2k_decode_tile ( + opj_j2k_t * p_j2k, + OPJ_UINT32 p_tile_index, + OPJ_BYTE * p_data, + OPJ_UINT32 p_data_size, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); +/** + * Reads a tile header. + * @param p_j2k the jpeg2000 codec. + * @param p_stream the stream to write data to. + * @param p_manager the user event manager. + */ +bool j2k_read_tile_header ( + opj_j2k_t * p_j2k, + OPJ_UINT32 * p_tile_index, + OPJ_UINT32 * p_data_size, + OPJ_INT32 * p_tile_x0, + OPJ_INT32 * p_tile_y0, + OPJ_INT32 * p_tile_x1, + OPJ_INT32 * p_tile_y1, + OPJ_UINT32 * p_nb_comps, + bool * p_go_on, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); +/** + * Sets the given area to be decoded. This function should be called right after opj_read_header and before any tile header reading. + * + * @param p_j2k the jpeg2000 codec. + * @param p_start_x the left position of the rectangle to decode (in image coordinates). + * @param p_end_x the right position of the rectangle to decode (in image coordinates). + * @param p_start_y the up position of the rectangle to decode (in image coordinates). + * @param p_end_y the bottom position of the rectangle to decode (in image coordinates). + * @param p_manager the user event manager + * + * @return true if the area could be set. + */ +bool j2k_set_decode_area( + opj_j2k_t *p_j2k, + OPJ_INT32 p_start_x, + OPJ_INT32 p_start_y, + OPJ_INT32 p_end_x, + OPJ_INT32 p_end_y, + struct opj_event_mgr * p_manager + ); + +void j2k_dump_image(FILE *fd, opj_image_t * img); + +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __J2K_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/j2k_lib.c b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/j2k_lib.c new file mode 100644 index 0000000..5515bd7 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/j2k_lib.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef WIN32 +#include +#else +/*#include +#include +#include +*/ +#endif /* WIN32 */ +#include "j2k_lib.h" + + +OPJ_FLOAT64 opj_clock(void) { +#if 0 +#ifdef WIN32 + /* WIN32: use QueryPerformance (very accurate) */ + LARGE_INTEGER freq , t ; + /* freq is the clock speed of the CPU */ + QueryPerformanceFrequency(&freq) ; + /* cout << "freq = " << ((double) freq.QuadPart) << endl; */ + /* t is the high resolution performance counter (see MSDN) */ + QueryPerformanceCounter ( & t ) ; + return ( t.QuadPart /(double) freq.QuadPart ) ; +#else + /* Unix or Linux: use resource usage */ + struct rusage t; + double procTime; + /* (1) Get the rusage data structure at this moment (man getrusage) */ + getrusage(0,&t); + /* (2) What is the elapsed time ? - CPU time = User time + System time */ + /* (2a) Get the seconds */ + procTime = t.ru_utime.tv_sec + t.ru_stime.tv_sec; + /* (2b) More precisely! Get the microseconds part ! */ + return ( procTime + (t.ru_utime.tv_usec + t.ru_stime.tv_usec) * 1e-6 ) ; +#endif + +#endif + return 0; +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/j2k_lib.h b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/j2k_lib.h new file mode 100644 index 0000000..7885f99 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/j2k_lib.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __J2K_LIB_H +#define __J2K_LIB_H +/** +@file j2k_lib.h +@brief Internal functions + +The functions in J2K_LIB.C are internal utilities mainly used for timing. +*/ +#include "openjpeg.h" +/** @defgroup MISC MISC - Miscellaneous internal functions */ +/*@{*/ + +/** @name Exported functions */ +/*@{*/ +/* ----------------------------------------------------------------------- */ + +/** +Difference in successive opj_clock() calls tells you the elapsed time +@return Returns time in seconds +*/ +OPJ_FLOAT64 opj_clock(void); + +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __J2K_LIB_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/jp2.c b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/jp2.c new file mode 100644 index 0000000..523a207 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/jp2.c @@ -0,0 +1,2229 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "jp2.h" +#include "cio.h" +#include "opj_malloc.h" +#include "event.h" +#include "j2k.h" +#include "function_list.h" +#include "assert.h" + +/** @defgroup JP2 JP2 - JPEG-2000 file format reader/writer */ +/*@{*/ + +#define BOX_SIZE 1024 + + + +/** @name Local static functions */ +/*@{*/ + + + +/** + * Writes the Jpeg2000 file Header box - JP2 Header box (warning, this is a super box). + * + * @param cio the stream to write data to. + * @param jp2 the jpeg2000 file codec. + * @param p_manager user event manager. + * + * @return true if writting was successful. +*/ +bool jp2_write_jp2h( + opj_jp2_t *jp2, + struct opj_stream_private *cio, + struct opj_event_mgr * p_manager + ); + +/** + * Skips the Jpeg2000 Codestream Header box - JP2C Header box. + * + * @param cio the stream to write data to. + * @param jp2 the jpeg2000 file codec. + * @param p_manager user event manager. + * + * @return true if writting was successful. +*/ +bool jp2_skip_jp2c( + opj_jp2_t *jp2, + struct opj_stream_private *cio, + struct opj_event_mgr * p_manager + ); + +/** + * Reads the Jpeg2000 file Header box - JP2 Header box (warning, this is a super box). + * + * @param p_header_data the data contained in the file header box. + * @param jp2 the jpeg2000 file codec. + * @param p_header_size the size of the data contained in the file header box. + * @param p_manager the user event manager. + * + * @return true if the JP2 Header box was successfully reconized. +*/ +bool jp2_read_jp2h( + opj_jp2_t *jp2, + unsigned char * p_header_data, + unsigned int p_header_size, + struct opj_event_mgr * p_manager + ); + +/** + * Writes the Jpeg2000 codestream Header box - JP2C Header box. This function must be called AFTER the coding has been done. + * + * @param cio the stream to write data to. + * @param jp2 the jpeg2000 file codec. + * @param p_manager user event manager. + * + * @return true if writting was successful. +*/ +static bool jp2_write_jp2c( + opj_jp2_t *jp2, + struct opj_stream_private *cio, + struct opj_event_mgr * p_manager + ); + +/** + * Reads a box header. The box is the way data is packed inside a jpeg2000 file structure. + * + * @param cio the input stream to read data from. + * @param box the box structure to fill. + * @param p_number_bytes_read pointer to an int that will store the number of bytes read from the stream (shoul usually be 2). + * @param p_manager user event manager. + * + * @return true if the box is reconized, false otherwise +*/ +static bool jp2_read_boxhdr( + opj_jp2_box_t *box, + OPJ_UINT32 * p_number_bytes_read, + struct opj_stream_private *cio, + struct opj_event_mgr * p_manager + ); + +/** + * Reads a box header. The box is the way data is packed inside a jpeg2000 file structure. Data is read from a character string + * + * @param p_data the character string to read data from. + * @param box the box structure to fill. + * @param p_number_bytes_read pointer to an int that will store the number of bytes read from the stream (shoul usually be 2). + * @param p_box_max_size the maximum number of bytes in the box. + * + * @return true if the box is reconized, false otherwise +*/ +static bool jp2_read_boxhdr_char( + opj_jp2_box_t *box, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_number_bytes_read, + OPJ_UINT32 p_box_max_size, + struct opj_event_mgr * p_manager + ); + +/** + * Reads a jpeg2000 file signature box. + * + * @param p_header_data the data contained in the signature box. + * @param jp2 the jpeg2000 file codec. + * @param p_header_size the size of the data contained in the signature box. + * @param p_manager the user event manager. + * + * @return true if the file signature box is valid. + */ +static bool jp2_read_jp( + opj_jp2_t *jp2, + unsigned char * p_header_data, + unsigned int p_header_size, + struct opj_event_mgr * p_manager + ); + +/** + * Writes a jpeg2000 file signature box. + * + * @param cio the stream to write data to. + * @param jp2 the jpeg2000 file codec. + * @param p_manager the user event manager. + * + * @return true if writting was successful. + */ +static bool jp2_write_jp( + opj_jp2_t *jp2, + struct opj_stream_private *cio, + struct opj_event_mgr * p_manager + ); + +/** + * Writes a FTYP box - File type box + * + * @param cio the stream to write data to. + * @param jp2 the jpeg2000 file codec. + * @param p_manager the user event manager. + * + * @return true if writting was successful. + */ +static bool jp2_write_ftyp( + opj_jp2_t *jp2, + struct opj_stream_private *cio, + struct opj_event_mgr * p_manager + ); + +/** + * Reads a a FTYP box - File type box + * + * @param p_header_data the data contained in the FTYP box. + * @param jp2 the jpeg2000 file codec. + * @param p_header_size the size of the data contained in the FTYP box. + * @param p_manager the user event manager. + * + * @return true if the FTYP box is valid. + */ +static bool jp2_read_ftyp( + opj_jp2_t *jp2, + unsigned char * p_header_data, + unsigned int p_header_size, + struct opj_event_mgr * p_manager + ); + +/** + * Reads a IHDR box - Image Header box + * + * @param p_image_header_data pointer to actual data (already read from file) + * @param jp2 the jpeg2000 file codec. + * @param p_image_header_size the size of the image header + * @param p_manager the user event manager. + * + * @return true if the image header is valid, fale else. + */ +static bool jp2_read_ihdr( + opj_jp2_t *jp2, + unsigned char * p_image_header_data, + unsigned int p_image_header_size, + struct opj_event_mgr * p_manager + ); + +/** + * Writes the Image Header box - Image Header box. + * + * @param jp2 jpeg2000 file codec. + * @param p_nb_bytes_written pointer to store the nb of bytes written by the function. + * + * @return the data being copied. +*/ +static unsigned char * jp2_write_ihdr( + opj_jp2_t *jp2, + unsigned int * p_nb_bytes_written + ); + +/** + * Reads a Bit per Component box. + * + * @param p_bpc_header_data pointer to actual data (already read from file) + * @param jp2 the jpeg2000 file codec. + * @param p_bpc_header_size the size of the bpc header + * @param p_manager the user event manager. + * + * @return true if the bpc header is valid, fale else. + */ +static bool jp2_read_bpcc( + opj_jp2_t *jp2, + unsigned char * p_bpc_header_data, + unsigned int p_bpc_header_size, + struct opj_event_mgr * p_manager + ); + + +/** + * Writes the Bit per Component box. + * + * @param jp2 jpeg2000 file codec. + * @param p_nb_bytes_written pointer to store the nb of bytes written by the function. + * + * @return the data being copied. +*/ +static unsigned char * jp2_write_bpcc( + opj_jp2_t *jp2, + unsigned int * p_nb_bytes_written + ); + +/** + * Reads the Colour Specification box. + * + * @param p_colr_header_data pointer to actual data (already read from file) + * @param jp2 the jpeg2000 file codec. + * @param p_colr_header_size the size of the color header + * @param p_manager the user event manager. + * + * @return true if the bpc header is valid, fale else. +*/ +static bool jp2_read_colr( + opj_jp2_t *jp2, + unsigned char * p_colr_header_data, + unsigned int p_colr_header_size, + struct opj_event_mgr * p_manager + ); + +/** + * Writes the Colour Specification box. + * + * @param jp2 jpeg2000 file codec. + * @param p_nb_bytes_written pointer to store the nb of bytes written by the function. + * + * @return the data being copied. +*/ +static unsigned char *jp2_write_colr( + opj_jp2_t *jp2, + unsigned int * p_nb_bytes_written + ); + + +/** + * Reads a jpeg2000 file header structure. + * + * @param cio the stream to read data from. + * @param jp2 the jpeg2000 file header structure. + * @param p_manager the user event manager. + * + * @return true if the box is valid. + */ +bool jp2_read_header_procedure( + opj_jp2_t *jp2, + struct opj_stream_private *cio, + struct opj_event_mgr * p_manager + ); +/** + * Excutes the given procedures on the given codec. + * + * @param p_procedure_list the list of procedures to execute + * @param jp2 the jpeg2000 file codec to execute the procedures on. + * @param cio the stream to execute the procedures on. + * @param p_manager the user manager. + * + * @return true if all the procedures were successfully executed. + */ +static bool jp2_exec ( + opj_jp2_t * jp2, + struct opj_procedure_list * p_procedure_list, + struct opj_stream_private *cio, + struct opj_event_mgr * p_manager + ); +/** + * Finds the execution function related to the given box id. + * + * @param p_id the id of the handler to fetch. + * + * @return the given handler or NULL if it could not be found. + */ +static const opj_jp2_header_handler_t * jp2_find_handler (int p_id); + +/** + * Sets up the validation ,i.e. adds the procedures to lauch to make sure the codec parameters + * are valid. Developpers wanting to extend the library can add their own validation procedures. + */ +static void jp2_setup_encoding_validation (opj_jp2_t *jp2); + +/** + * Sets up the procedures to do on writting header. Developpers wanting to extend the library can add their own writting procedures. + */ +static void jp2_setup_header_writting (opj_jp2_t *jp2); + +/** + * The default validation procedure without any extension. + * + * @param jp2 the jpeg2000 codec to validate. + * @param cio the input stream to validate. + * @param p_manager the user event manager. + * + * @return true if the parameters are correct. + */ +bool jp2_default_validation ( + opj_jp2_t * jp2, + struct opj_stream_private *cio, + struct opj_event_mgr * p_manager + ); + +/** + * Finds the execution function related to the given box id. + * + * @param p_id the id of the handler to fetch. + * + * @return the given handler or NULL if it could not be found. + */ +static const opj_jp2_header_handler_t * jp2_find_handler ( + int p_id + ); + +/** + * Finds the image execution function related to the given box id. + * + * @param p_id the id of the handler to fetch. + * + * @return the given handler or NULL if it could not be found. + */ +static const opj_jp2_header_handler_t * jp2_img_find_handler ( + int p_id + ); + +/** + * Sets up the procedures to do on writting header after the codestream. + * Developpers wanting to extend the library can add their own writting procedures. + */ +static void jp2_setup_end_header_writting (opj_jp2_t *jp2); + +/** + * Sets up the procedures to do on reading header after the codestream. + * Developpers wanting to extend the library can add their own writting procedures. + */ +static void jp2_setup_end_header_reading (opj_jp2_t *jp2); + +/** + * Sets up the validation ,i.e. adds the procedures to lauch to make sure the codec parameters + * are valid. Developpers wanting to extend the library can add their own validation procedures. + */ +static void jp2_setup_decoding_validation (opj_jp2_t *jp2); + +/** + * Sets up the procedures to do on reading header. + * Developpers wanting to extend the library can add their own writting procedures. + */ +static void jp2_setup_header_reading (opj_jp2_t *jp2); +/*@}*/ + +/*@}*/ + +/* ----------------------------------------------------------------------- */ +const opj_jp2_header_handler_t jp2_header [] = +{ + {JP2_JP,jp2_read_jp}, + {JP2_FTYP,jp2_read_ftyp}, + {JP2_JP2H,jp2_read_jp2h} +}; + +const opj_jp2_header_handler_t jp2_img_header [] = +{ + {JP2_IHDR,jp2_read_ihdr}, + {JP2_COLR,jp2_read_colr}, + {JP2_BPCC,jp2_read_bpcc} +}; +/** + * Finds the execution function related to the given box id. + * + * @param p_id the id of the handler to fetch. + * + * @return the given handler or 00 if it could not be found. + */ +const opj_jp2_header_handler_t * jp2_find_handler ( + int p_id + ) +{ + unsigned int i, l_handler_size = sizeof(jp2_header) / sizeof(opj_jp2_header_handler_t); + for + (i=0;ijp2_state & JP2_STATE_HEADER) + { + jp2->jp2_state |= JP2_STATE_CODESTREAM; + return true; + } + else + { + opj_event_msg(p_manager, EVT_ERROR, "bad placed jpeg codestream\n"); + return false; + } + } + else if + (box.length == 0) + { + opj_event_msg(p_manager, EVT_ERROR, "Cannot handle box of undefined sizes\n"); + return false; + } + + l_current_handler = jp2_find_handler(box.type); + l_current_data_size = box.length - l_nb_bytes_read; + + if + (l_current_handler != 00) + { + if + (l_current_data_size > l_last_data_size) + { + l_current_data = (unsigned char*)opj_realloc(l_current_data,l_current_data_size); + l_last_data_size = l_current_data_size; + } + l_nb_bytes_read = opj_stream_read_data(cio,l_current_data,l_current_data_size,p_manager); + if + (l_nb_bytes_read != l_current_data_size) + { + opj_event_msg(p_manager, EVT_ERROR, "Problem with reading JPEG2000 box, stream error\n"); + return false; + } + if + (! l_current_handler->handler(jp2,l_current_data,l_current_data_size,p_manager)) + { + return false; + } + } + else + { + jp2->jp2_state |= JP2_STATE_UNKNOWN; + if + (opj_stream_skip(cio,l_current_data_size,p_manager) != l_current_data_size) + { + opj_event_msg(p_manager, EVT_ERROR, "Problem with skipping JPEG2000 box, stream error\n"); + return false; + } + } + } + return true; +} + +/** + * Reads a box header. The box is the way data is packed inside a jpeg2000 file structure. + * + * @param cio the input stream to read data from. + * @param box the box structure to fill. + * @param p_number_bytes_read pointer to an int that will store the number of bytes read from the stream (should usually be 8). + * @param p_manager user event manager. + * + * @return true if the box is reconized, false otherwise +*/ +bool jp2_read_boxhdr(opj_jp2_box_t *box, OPJ_UINT32 * p_number_bytes_read,opj_stream_private_t *cio, opj_event_mgr_t * p_manager) +{ + /* read header from file */ + unsigned char l_data_header [8]; + + // preconditions + assert(cio != 00); + assert(box != 00); + assert(p_number_bytes_read != 00); + assert(p_manager != 00); + + *p_number_bytes_read = opj_stream_read_data(cio,l_data_header,8,p_manager); + if + (*p_number_bytes_read != 8) + { + return false; + } + /* process read data */ + opj_read_bytes(l_data_header,&(box->length), 4); + opj_read_bytes(l_data_header+4,&(box->type), 4); + + // do we have a "special very large box ?" + // read then the XLBox + if + (box->length == 1) + { + OPJ_UINT32 l_xl_part_size; + OPJ_UINT32 l_nb_bytes_read = opj_stream_read_data(cio,l_data_header,8,p_manager); + if + (l_nb_bytes_read != 8) + { + if + (l_nb_bytes_read > 0) + { + *p_number_bytes_read += l_nb_bytes_read; + } + return false; + } + opj_read_bytes(l_data_header,&l_xl_part_size, 4); + if + (l_xl_part_size != 0) + { + opj_event_msg(p_manager, EVT_ERROR, "Cannot handle box sizes higher than 2^32\n"); + return false; + } + opj_read_bytes(l_data_header,&(box->length), 4); + } + return true; +} + +/** + * Reads a box header. The box is the way data is packed inside a jpeg2000 file structure. Data is read from a character string + * + * @param p_data the character string to read data from. + * @param box the box structure to fill. + * @param p_number_bytes_read pointer to an int that will store the number of bytes read from the stream (shoul usually be 2). + * @param p_box_max_size the maximum number of bytes in the box. + * + * @return true if the box is reconized, false otherwise +*/ +static bool jp2_read_boxhdr_char( + opj_jp2_box_t *box, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_number_bytes_read, + OPJ_UINT32 p_box_max_size, + opj_event_mgr_t * p_manager + ) +{ + // preconditions + assert(p_data != 00); + assert(box != 00); + assert(p_number_bytes_read != 00); + assert(p_manager != 00); + + if + (p_box_max_size < 8) + { + opj_event_msg(p_manager, EVT_ERROR, "Cannot handle box of less than 8 bytes\n"); + return false; + } + /* process read data */ + opj_read_bytes(p_data,&(box->length), 4); + p_data += 4; + opj_read_bytes(p_data,&(box->type), 4); + p_data += 4; + *p_number_bytes_read = 8; + + // do we have a "special very large box ?" + // read then the XLBox + if + (box->length == 1) + { + unsigned int l_xl_part_size; + if + (p_box_max_size < 16) + { + opj_event_msg(p_manager, EVT_ERROR, "Cannot handle XL box of less than 16 bytes\n"); + return false; + } + + opj_read_bytes(p_data,&l_xl_part_size, 4); + p_data += 4; + *p_number_bytes_read += 4; + if + (l_xl_part_size != 0) + { + opj_event_msg(p_manager, EVT_ERROR, "Cannot handle box sizes higher than 2^32\n"); + return false; + } + opj_read_bytes(p_data,&(box->length), 4); + *p_number_bytes_read += 4; + if + (box->length == 0) + { + opj_event_msg(p_manager, EVT_ERROR, "Cannot handle box of undefined sizes\n"); + return false; + } + + } + else if + (box->length == 0) + { + opj_event_msg(p_manager, EVT_ERROR, "Cannot handle box of undefined sizes\n"); + return false; + } + return true; +} + + +/** + * Reads a jpeg2000 file signature box. + * + * @param p_header_data the data contained in the signature box. + * @param jp2 the jpeg2000 file codec. + * @param p_header_size the size of the data contained in the signature box. + * @param p_manager the user event manager. + * + * @return true if the file signature box is valid. + */ +bool jp2_read_jp( + opj_jp2_t *jp2, + unsigned char * p_header_data, + unsigned int p_header_size, + opj_event_mgr_t * p_manager + ) +{ + unsigned int l_magic_number; + + // preconditions + assert(p_header_data != 00); + assert(jp2 != 00); + assert(p_manager != 00); + + if + (jp2->jp2_state != JP2_STATE_NONE) + { + opj_event_msg(p_manager, EVT_ERROR, "The signature box must be the first box in the file.\n"); + return false; + } + + + /* assure length of data is correct (4 -> magic number) */ + if + (p_header_size != 4) + { + opj_event_msg(p_manager, EVT_ERROR, "Error with JP signature Box size\n"); + return false; + } + + // rearrange data + opj_read_bytes(p_header_data,&l_magic_number,4); + if + (l_magic_number != 0x0d0a870a ) + { + opj_event_msg(p_manager, EVT_ERROR, "Error with JP Signature : bad magic number\n"); + return false; + } + jp2->jp2_state |= JP2_STATE_SIGNATURE; + return true; +} + +/** + * Reads a a FTYP box - File type box + * + * @param p_header_data the data contained in the FTYP box. + * @param jp2 the jpeg2000 file codec. + * @param p_header_size the size of the data contained in the FTYP box. + * @param p_manager the user event manager. + * + * @return true if the FTYP box is valid. + */ +bool jp2_read_ftyp( + opj_jp2_t *jp2, + unsigned char * p_header_data, + unsigned int p_header_size, + opj_event_mgr_t * p_manager + ) +{ + unsigned int i; + unsigned int l_remaining_bytes; + + // preconditions + assert(p_header_data != 00); + assert(jp2 != 00); + assert(p_manager != 00); + + if + (jp2->jp2_state != JP2_STATE_SIGNATURE) + { + opj_event_msg(p_manager, EVT_ERROR, "The ftyp box must be the second box in the file.\n"); + return false; + } + + /* assure length of data is correct */ + if + (p_header_size < 8) + { + opj_event_msg(p_manager, EVT_ERROR, "Error with FTYP signature Box size\n"); + return false; + } + + opj_read_bytes(p_header_data,&jp2->brand,4); /* BR */ + p_header_data += 4; + + opj_read_bytes(p_header_data,&jp2->minversion,4); /* MinV */ + p_header_data += 4; + + l_remaining_bytes = p_header_size - 8; + + /* the number of remaining bytes should be a multiple of 4 */ + if + ((l_remaining_bytes & 0x3) != 0) + { + opj_event_msg(p_manager, EVT_ERROR, "Error with FTYP signature Box size\n"); + return false; + } + /* div by 4 */ + jp2->numcl = l_remaining_bytes >> 2; + if + (jp2->numcl) + { + jp2->cl = (unsigned int *) opj_malloc(jp2->numcl * sizeof(unsigned int)); + if + (jp2->cl == 00) + { + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory with FTYP Box\n"); + return false; + } + memset(jp2->cl,0,jp2->numcl * sizeof(unsigned int)); + } + + + for + (i = 0; i < jp2->numcl; ++i) + { + opj_read_bytes(p_header_data,&jp2->cl[i],4); /* CLi */ + p_header_data += 4; + + } + jp2->jp2_state |= JP2_STATE_FILE_TYPE; + return true; +} + +/** + * Writes a jpeg2000 file signature box. + * + * @param cio the stream to write data to. + * @param jp2 the jpeg2000 file codec. + * @param p_manager the user event manager. + * + * @return true if writting was successful. + */ +bool jp2_write_jp ( + opj_jp2_t *jp2, + opj_stream_private_t *cio, + opj_event_mgr_t * p_manager + ) +{ + /* 12 bytes will be read */ + unsigned char l_signature_data [12]; + + // preconditions + assert(cio != 00); + assert(jp2 != 00); + assert(p_manager != 00); + + + /* write box length */ + opj_write_bytes(l_signature_data,12,4); + /* writes box type */ + opj_write_bytes(l_signature_data+4,JP2_JP,4); + /* writes magic number*/ + opj_write_bytes(l_signature_data+8,0x0d0a870a,4); + if + (opj_stream_write_data(cio,l_signature_data,12,p_manager) != 12) + { + return false; + } + return true; +} + + +/** + * Writes a FTYP box - File type box + * + * @param cio the stream to write data to. + * @param jp2 the jpeg2000 file codec. + * @param p_manager the user event manager. + * + * @return true if writting was successful. + */ +bool jp2_write_ftyp( + opj_jp2_t *jp2, + opj_stream_private_t *cio, + opj_event_mgr_t * p_manager + ) +{ + unsigned int i; + unsigned int l_ftyp_size = 16 + 4 * jp2->numcl; + unsigned char * l_ftyp_data, * l_current_data_ptr; + bool l_result; + + // preconditions + assert(cio != 00); + assert(jp2 != 00); + assert(p_manager != 00); + + l_ftyp_data = (unsigned char *) opj_malloc(l_ftyp_size); + + if + (l_ftyp_data == 00) + { + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to handle ftyp data\n"); + return false; + } + memset(l_ftyp_data,0,l_ftyp_size); + + l_current_data_ptr = l_ftyp_data; + + opj_write_bytes(l_current_data_ptr, l_ftyp_size,4); /* box size */ + l_current_data_ptr += 4; + + opj_write_bytes(l_current_data_ptr, JP2_FTYP,4); /* FTYP */ + l_current_data_ptr += 4; + + opj_write_bytes(l_current_data_ptr, jp2->brand,4); /* BR */ + l_current_data_ptr += 4; + + opj_write_bytes(l_current_data_ptr, jp2->minversion,4); /* MinV */ + l_current_data_ptr += 4; + + for + (i = 0; i < jp2->numcl; i++) + { + opj_write_bytes(l_current_data_ptr, jp2->cl[i],4); /* CL */ + } + + l_result = (opj_stream_write_data(cio,l_ftyp_data,l_ftyp_size,p_manager) == l_ftyp_size); + if + (! l_result) + { + opj_event_msg(p_manager, EVT_ERROR, "Error while writting ftyp data to stream\n"); + } + opj_free(l_ftyp_data); + return l_result; +} + +/** + * Writes the Jpeg2000 file Header box - JP2 Header box (warning, this is a super box). + * + * @param cio the stream to write data to. + * @param jp2 the jpeg2000 file codec. + * @param p_manager user event manager. + * + * @return true if writting was successful. +*/ +bool jp2_write_jp2h( + opj_jp2_t *jp2, + opj_stream_private_t *cio, + opj_event_mgr_t * p_manager + ) +{ + opj_jp2_img_header_writer_handler_t l_writers [3]; + opj_jp2_img_header_writer_handler_t * l_current_writer; + + int i, l_nb_pass; + /* size of data for super box*/ + int l_jp2h_size = 8; + bool l_result = true; + + /* to store the data of the super box */ + unsigned char l_jp2h_data [8]; + + // preconditions + assert(cio != 00); + assert(jp2 != 00); + assert(p_manager != 00); + + memset(l_writers,0,sizeof(l_writers)); + + if + (jp2->bpc == 255) + { + l_nb_pass = 3; + l_writers[0].handler = jp2_write_ihdr; + l_writers[1].handler = jp2_write_bpcc; + l_writers[2].handler = jp2_write_colr; + } + else + { + l_nb_pass = 2; + l_writers[0].handler = jp2_write_ihdr; + l_writers[1].handler = jp2_write_colr; + } + + /* write box header */ + /* write JP2H type */ + opj_write_bytes(l_jp2h_data+4,JP2_JP2H,4); + + l_current_writer = l_writers; + for + (i=0;im_data = l_current_writer->handler(jp2,&(l_current_writer->m_size)); + if + (l_current_writer->m_data == 00) + { + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to hold JP2 Header data\n"); + l_result = false; + break; + } + l_jp2h_size += l_current_writer->m_size; + ++l_current_writer; + } + + if + (! l_result) + { + l_current_writer = l_writers; + for + (i=0;im_data != 00) + { + opj_free(l_current_writer->m_data ); + } + ++l_current_writer; + } + return false; + } + + /* write super box size */ + opj_write_bytes(l_jp2h_data,l_jp2h_size,4); + + /* write super box data on stream */ + if + (opj_stream_write_data(cio,l_jp2h_data,8,p_manager) != 8) + { + opj_event_msg(p_manager, EVT_ERROR, "Stream error while writting JP2 Header box\n"); + l_result = false; + } + + if + (l_result) + { + l_current_writer = l_writers; + for + (i=0;im_data,l_current_writer->m_size,p_manager) != l_current_writer->m_size) + { + opj_event_msg(p_manager, EVT_ERROR, "Stream error while writting JP2 Header box\n"); + l_result = false; + break; + } + ++l_current_writer; + } + } + l_current_writer = l_writers; + /* cleanup */ + for + (i=0;im_data != 00) + { + opj_free(l_current_writer->m_data ); + } + ++l_current_writer; + } + return l_result; +} + +/** + * Reads the Jpeg2000 file Header box - JP2 Header box (warning, this is a super box). + * + * @param p_header_data the data contained in the file header box. + * @param jp2 the jpeg2000 file codec. + * @param p_header_size the size of the data contained in the file header box. + * @param p_manager the user event manager. + * + * @return true if the JP2 Header box was successfully reconized. +*/ +bool jp2_read_jp2h( + opj_jp2_t *jp2, + unsigned char * p_header_data, + unsigned int p_header_size, + opj_event_mgr_t * p_manager + ) +{ + unsigned int l_box_size=0, l_current_data_size = 0; + opj_jp2_box_t box; + const opj_jp2_header_handler_t * l_current_handler; + + // preconditions + assert(p_header_data != 00); + assert(jp2 != 00); + assert(p_manager != 00); + + /* make sure the box is well placed */ + if + ((jp2->jp2_state & JP2_STATE_FILE_TYPE) != JP2_STATE_FILE_TYPE ) + { + opj_event_msg(p_manager, EVT_ERROR, "The box must be the first box in the file.\n"); + return false; + } + jp2->jp2_img_state = JP2_IMG_STATE_NONE; + + /* iterate while remaining data */ + while + (p_header_size > 0) + { + if + (! jp2_read_boxhdr_char(&box,p_header_data,&l_box_size,p_header_size, p_manager)) + { + opj_event_msg(p_manager, EVT_ERROR, "Stream error while reading JP2 Header box\n"); + return false; + } + if + (box.length > p_header_size) + { + opj_event_msg(p_manager, EVT_ERROR, "Stream error while reading JP2 Header box\n"); + return false; + } + l_current_handler = jp2_img_find_handler(box.type); + + l_current_data_size = box.length - l_box_size; + p_header_data += l_box_size; + + if + (l_current_handler != 00) + { + if + (! l_current_handler->handler(jp2,p_header_data,l_current_data_size,p_manager)) + { + return false; + } + } + else + { + jp2->jp2_img_state |= JP2_IMG_STATE_UNKNOWN; + } + p_header_data += l_current_data_size; + p_header_size -= box.length; + } + jp2->jp2_state |= JP2_STATE_HEADER; + return true; +} + +/** + * Reads a IHDR box - Image Header box + * + * @param p_image_header_data pointer to actual data (already read from file) + * @param jp2 the jpeg2000 file codec. + * @param p_image_header_size the size of the image header + * @param p_image_header_max_size maximum size of the header, any size bigger than this value should result the function to output false. + * @param p_manager the user event manager. + * + * @return true if the image header is valid, fale else. + */ +bool jp2_read_ihdr( + opj_jp2_t *jp2, + unsigned char * p_image_header_data, + unsigned int p_image_header_size, + opj_event_mgr_t * p_manager + ) +{ + // preconditions + assert(p_image_header_data != 00); + assert(jp2 != 00); + assert(p_manager != 00); + + if + (p_image_header_size != 14) + { + opj_event_msg(p_manager, EVT_ERROR, "Bad image header box (bad size)\n"); + return false; + } + opj_read_bytes(p_image_header_data,&(jp2->h),4); /* HEIGHT */ + p_image_header_data += 4; + opj_read_bytes(p_image_header_data,&(jp2->w),4); /* WIDTH */ + p_image_header_data += 4; + opj_read_bytes(p_image_header_data,&(jp2->numcomps),2); /* NC */ + p_image_header_data += 2; + + /* allocate memory for components */ + jp2->comps = (opj_jp2_comps_t*) opj_malloc(jp2->numcomps * sizeof(opj_jp2_comps_t)); + if + (jp2->comps == 0) + { + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to handle image header (ihdr)\n"); + return false; + } + memset(jp2->comps,0,jp2->numcomps * sizeof(opj_jp2_comps_t)); + + opj_read_bytes(p_image_header_data,&(jp2->bpc),1); /* BPC */ + ++ p_image_header_data; + opj_read_bytes(p_image_header_data,&(jp2->C),1); /* C */ + ++ p_image_header_data; + opj_read_bytes(p_image_header_data,&(jp2->UnkC),1); /* UnkC */ + ++ p_image_header_data; + opj_read_bytes(p_image_header_data,&(jp2->IPR),1); /* IPR */ + ++ p_image_header_data; + return true; +} + +/** + * Writes the Image Header box - Image Header box. + * + * @param jp2 jpeg2000 file codec. + * @param p_nb_bytes_written pointer to store the nb of bytes written by the function. + * + * @return the data being copied. +*/ +static unsigned char * jp2_write_ihdr( + opj_jp2_t *jp2, + unsigned int * p_nb_bytes_written + ) +{ + unsigned char * l_ihdr_data,* l_current_ihdr_ptr; + + // preconditions + assert(jp2 != 00); + assert(p_nb_bytes_written != 00); + + /* default image header is 22 bytes wide */ + l_ihdr_data = (unsigned char *) opj_malloc(22); + if + (l_ihdr_data == 00) + { + return 00; + } + memset(l_ihdr_data,0,22); + + l_current_ihdr_ptr = l_ihdr_data; + + opj_write_bytes(l_current_ihdr_ptr,22,4); /* write box size */ + l_current_ihdr_ptr+=4; + opj_write_bytes(l_current_ihdr_ptr,JP2_IHDR, 4); /* IHDR */ + l_current_ihdr_ptr+=4; + opj_write_bytes(l_current_ihdr_ptr,jp2->h, 4); /* HEIGHT */ + l_current_ihdr_ptr+=4; + opj_write_bytes(l_current_ihdr_ptr, jp2->w, 4); /* WIDTH */ + l_current_ihdr_ptr+=4; + opj_write_bytes(l_current_ihdr_ptr, jp2->numcomps, 2); /* NC */ + l_current_ihdr_ptr+=2; + opj_write_bytes(l_current_ihdr_ptr, jp2->bpc, 1); /* BPC */ + ++l_current_ihdr_ptr; + opj_write_bytes(l_current_ihdr_ptr, jp2->C, 1); /* C : Always 7 */ + ++l_current_ihdr_ptr; + opj_write_bytes(l_current_ihdr_ptr, jp2->UnkC, 1); /* UnkC, colorspace unknown */ + ++l_current_ihdr_ptr; + opj_write_bytes(l_current_ihdr_ptr, jp2->IPR, 1); /* IPR, no intellectual property */ + ++l_current_ihdr_ptr; + *p_nb_bytes_written = 22; + return l_ihdr_data; +} + +/** + * Writes the Bit per Component box. + * + * @param jp2 jpeg2000 file codec. + * @param p_nb_bytes_written pointer to store the nb of bytes written by the function. + * + * @return the data being copied. +*/ +unsigned char * jp2_write_bpcc( + opj_jp2_t *jp2, + unsigned int * p_nb_bytes_written + ) +{ + unsigned int i; + /* room for 8 bytes for box and 1 byte for each component */ + int l_bpcc_size = 8 + jp2->numcomps; + unsigned char * l_bpcc_data,* l_current_bpcc_ptr; + + // preconditions + assert(jp2 != 00); + assert(p_nb_bytes_written != 00); + + l_bpcc_data = (unsigned char *) opj_malloc(l_bpcc_size); + if + (l_bpcc_data == 00) + { + return 00; + } + memset(l_bpcc_data,0,l_bpcc_size); + + l_current_bpcc_ptr = l_bpcc_data; + + opj_write_bytes(l_current_bpcc_ptr,l_bpcc_size,4); /* write box size */ + l_current_bpcc_ptr += 4; + opj_write_bytes(l_current_bpcc_ptr,JP2_BPCC,4); /* BPCC */ + l_current_bpcc_ptr += 4; + + for + (i = 0; i < jp2->numcomps; ++i) + { + opj_write_bytes(l_current_bpcc_ptr, jp2->comps[i].bpcc, 1); /* write each component information */ + ++l_current_bpcc_ptr; + } + *p_nb_bytes_written = l_bpcc_size; + return l_bpcc_data; +} + +/** + * Reads a Bit per Component box. + * + * @param p_bpc_header_data pointer to actual data (already read from file) + * @param jp2 the jpeg2000 file codec. + * @param p_bpc_header_size pointer that will hold the size of the bpc header + * @param p_bpc_header_max_size maximum size of the header, any size bigger than this value should result the function to output false. + * @param p_manager the user event manager. + * + * @return true if the bpc header is valid, fale else. + */ +bool jp2_read_bpcc( + opj_jp2_t *jp2, + unsigned char * p_bpc_header_data, + unsigned int p_bpc_header_size, + opj_event_mgr_t * p_manager + ) +{ + unsigned int i; + + // preconditions + assert(p_bpc_header_data != 00); + assert(jp2 != 00); + assert(p_manager != 00); + + // and length is relevant + if + (p_bpc_header_size != jp2->numcomps) + { + opj_event_msg(p_manager, EVT_ERROR, "Bad BPCC header box (bad size)\n"); + return false; + } + + // read info for each component + for + (i = 0; i < jp2->numcomps; ++i) + { + opj_read_bytes(p_bpc_header_data,&jp2->comps[i].bpcc ,1); /* read each BPCC component */ + ++p_bpc_header_data; + } + return true; +} + +/** + * Writes the Colour Specification box. + * + * @param jp2 jpeg2000 file codec. + * @param p_nb_bytes_written pointer to store the nb of bytes written by the function. + * + * @return the data being copied. +*/ +unsigned char *jp2_write_colr( + opj_jp2_t *jp2, + unsigned int * p_nb_bytes_written + ) +{ + /* room for 8 bytes for box 3 for common data and variable upon profile*/ + unsigned int l_colr_size = 11; + unsigned char * l_colr_data,* l_current_colr_ptr; + + // preconditions + assert(jp2 != 00); + assert(p_nb_bytes_written != 00); + + switch + (jp2->meth) + { + case 1 : + l_colr_size += 4; + break; + case 2 : + ++l_colr_size; + break; + default : + return 00; + } + + l_colr_data = (unsigned char *) opj_malloc(l_colr_size); + if + (l_colr_data == 00) + { + return 00; + } + memset(l_colr_data,0,l_colr_size); + l_current_colr_ptr = l_colr_data; + + opj_write_bytes(l_current_colr_ptr,l_colr_size,4); /* write box size */ + l_current_colr_ptr += 4; + opj_write_bytes(l_current_colr_ptr,JP2_COLR,4); /* BPCC */ + l_current_colr_ptr += 4; + + opj_write_bytes(l_current_colr_ptr, jp2->meth,1); /* METH */ + ++l_current_colr_ptr; + opj_write_bytes(l_current_colr_ptr, jp2->precedence,1); /* PRECEDENCE */ + ++l_current_colr_ptr; + opj_write_bytes(l_current_colr_ptr, jp2->approx,1); /* APPROX */ + ++l_current_colr_ptr; + + if + (jp2->meth == 1) + { + opj_write_bytes(l_current_colr_ptr, jp2->enumcs,4); /* EnumCS */ + } + else + { + opj_write_bytes(l_current_colr_ptr, 0, 1); /* PROFILE (??) */ + } + *p_nb_bytes_written = l_colr_size; + return l_colr_data; +} + +/** + * Reads the Colour Specification box. + * + * @param p_colr_header_data pointer to actual data (already read from file) + * @param jp2 the jpeg2000 file codec. + * @param p_colr_header_size pointer that will hold the size of the color header + * @param p_colr_header_max_size maximum size of the header, any size bigger than this value should result the function to output false. + * @param p_manager the user event manager. + * + * @return true if the bpc header is valid, fale else. +*/ +bool jp2_read_colr( + opj_jp2_t * jp2, + unsigned char * p_colr_header_data, + unsigned int p_colr_header_size, + opj_event_mgr_t * p_manager + ) +{ + // preconditions + assert(jp2 != 00); + assert(p_colr_header_data != 00); + assert(p_manager != 00); + + if + (p_colr_header_size < 3) + { + opj_event_msg(p_manager, EVT_ERROR, "Bad BPCC header box (bad size)\n"); + return false; + } + + opj_read_bytes(p_colr_header_data,&jp2->meth ,1); /* METH */ + ++p_colr_header_data; + + opj_read_bytes(p_colr_header_data,&jp2->precedence ,1); /* PRECEDENCE */ + ++p_colr_header_data; + + opj_read_bytes(p_colr_header_data,&jp2->approx ,1); /* APPROX */ + ++p_colr_header_data; + + + if + (jp2->meth == 1) + { + if + (p_colr_header_size != 7) + { + opj_event_msg(p_manager, EVT_ERROR, "Bad BPCC header box (bad size)\n"); + return false; + } + opj_read_bytes(p_colr_header_data,&jp2->enumcs ,4); /* EnumCS */ + } + /*else + { + // do not care with profiles. + }*/ + return true; +} + +/** + * Writes the Jpeg2000 codestream Header box - JP2C Header box. + * + * @param cio the stream to write data to. + * @param jp2 the jpeg2000 file codec. + * @param p_manager user event manager. + * + * @return true if writting was successful. +*/ +bool jp2_write_jp2c( + opj_jp2_t *jp2, + opj_stream_private_t *cio, + opj_event_mgr_t * p_manager + ) +{ + unsigned int j2k_codestream_exit; + unsigned char l_data_header [8]; + + // preconditions + assert(jp2 != 00); + assert(cio != 00); + assert(p_manager != 00); + assert(opj_stream_has_seek(cio)); + + j2k_codestream_exit = opj_stream_tell(cio); + opj_write_bytes(l_data_header,j2k_codestream_exit - jp2->j2k_codestream_offset,4); /* size of codestream */ + opj_write_bytes(l_data_header + 4,JP2_JP2C,4); /* JP2C */ + + if + (! opj_stream_seek(cio,jp2->j2k_codestream_offset,p_manager)) + { + opj_event_msg(p_manager, EVT_ERROR, "Failed to seek in the stream.\n"); + return false; + } + + if + (opj_stream_write_data(cio,l_data_header,8,p_manager) != 8) + { + opj_event_msg(p_manager, EVT_ERROR, "Failed to seek in the stream.\n"); + return false; + } + + if + (! opj_stream_seek(cio,j2k_codestream_exit,p_manager)) + { + opj_event_msg(p_manager, EVT_ERROR, "Failed to seek in the stream.\n"); + return false; + } + return true; +} + +/** + * Destroys a jpeg2000 file decompressor. + * + * @param jp2 a jpeg2000 file decompressor. + */ +void jp2_destroy(opj_jp2_t *jp2) +{ + if + (jp2) + { + /* destroy the J2K codec */ + j2k_destroy(jp2->j2k); + jp2->j2k = 00; + if + (jp2->comps) + { + opj_free(jp2->comps); + jp2->comps = 00; + } + if + (jp2->cl) + { + opj_free(jp2->cl); + jp2->cl = 00; + } + if + (jp2->m_validation_list) + { + opj_procedure_list_destroy(jp2->m_validation_list); + jp2->m_validation_list = 00; + } + if + (jp2->m_procedure_list) + { + opj_procedure_list_destroy(jp2->m_procedure_list); + jp2->m_procedure_list = 00; + } + opj_free(jp2); + } +} + + + + + +/* ----------------------------------------------------------------------- */ +/* JP2 encoder interface */ +/* ----------------------------------------------------------------------- */ + +opj_jp2_t* jp2_create(bool p_is_decoder) +{ + opj_jp2_t *jp2 = (opj_jp2_t*)opj_malloc(sizeof(opj_jp2_t)); + if + (jp2) + { + memset(jp2,0,sizeof(opj_jp2_t)); + /* create the J2K codec */ + if + (! p_is_decoder) + { + jp2->j2k = j2k_create_compress(); + } + else + { + jp2->j2k = j2k_create_decompress(); + } + if + (jp2->j2k == 00) + { + jp2_destroy(jp2); + return 00; + } + // validation list creation + jp2->m_validation_list = opj_procedure_list_create(); + if + (! jp2->m_validation_list) + { + jp2_destroy(jp2); + return 00; + } + + // execution list creation + jp2->m_procedure_list = opj_procedure_list_create(); + if + (! jp2->m_procedure_list) + { + jp2_destroy(jp2); + return 00; + } + } + return jp2; +} + +/** + * Excutes the given procedures on the given codec. + * + * @param p_procedure_list the list of procedures to execute + * @param jp2 the jpeg2000 file codec to execute the procedures on. + * @param cio the stream to execute the procedures on. + * @param p_manager the user manager. + * + * @return true if all the procedures were successfully executed. + */ +bool jp2_exec ( + opj_jp2_t * jp2, + opj_procedure_list_t * p_procedure_list, + opj_stream_private_t *cio, + opj_event_mgr_t * p_manager + ) +{ + bool (** l_procedure) (opj_jp2_t * jp2,opj_stream_private_t *,opj_event_mgr_t *) = 00; + bool l_result = true; + unsigned int l_nb_proc, i; + + // preconditions + assert(p_procedure_list != 00); + assert(jp2 != 00); + assert(cio != 00); + assert(p_manager != 00); + + l_nb_proc = opj_procedure_list_get_nb_procedures(p_procedure_list); + l_procedure = (bool (**) (opj_jp2_t * jp2,opj_stream_private_t *,opj_event_mgr_t *)) opj_procedure_list_get_first_procedure(p_procedure_list); + for + (i=0;im_validation_list,cio,p_manager)) + { + return false; + } + + /* customization of the encoding */ + jp2_setup_header_writting(jp2); + + /* write header */ + if + (! jp2_exec (jp2,jp2->m_procedure_list,cio,p_manager)) + { + return false; + } + return j2k_start_compress(jp2->j2k,cio,p_image,p_manager); +} + +/** + * Reads a jpeg2000 file header structure. + * + * @param cio the stream to read data from. + * @param jp2 the jpeg2000 file header structure. + * @param p_manager the user event manager. + * + * @return true if the box is valid. + */ +bool jp2_read_header( + opj_jp2_t *jp2, + opj_image_t ** p_image, + OPJ_INT32 * p_tile_x0, + OPJ_INT32 * p_tile_y0, + OPJ_UINT32 * p_tile_width, + OPJ_UINT32 * p_tile_height, + OPJ_UINT32 * p_nb_tiles_x, + OPJ_UINT32 * p_nb_tiles_y, + struct opj_stream_private *cio, + struct opj_event_mgr * p_manager + ) +{ + // preconditions + assert(jp2 != 00); + assert(cio != 00); + assert(p_manager != 00); + + /* customization of the validation */ + jp2_setup_decoding_validation (jp2); + + /* customization of the encoding */ + jp2_setup_header_reading(jp2); + + /* validation of the parameters codec */ + if + (! jp2_exec(jp2,jp2->m_validation_list,cio,p_manager)) + { + return false; + } + + /* read header */ + if + (! jp2_exec (jp2,jp2->m_procedure_list,cio,p_manager)) + { + return false; + } + return j2k_read_header( + jp2->j2k, + p_image, + p_tile_x0, + p_tile_y0, + p_tile_width, + p_tile_height, + p_nb_tiles_x, + p_nb_tiles_y, + cio, + p_manager); +} + +/** + * Ends the decompression procedures and possibiliy add data to be read after the + * codestream. + */ +bool jp2_end_decompress(opj_jp2_t *jp2, opj_stream_private_t *cio, opj_event_mgr_t * p_manager) +{ + // preconditions + assert(jp2 != 00); + assert(cio != 00); + assert(p_manager != 00); + + /* customization of the end encoding */ + jp2_setup_end_header_reading(jp2); + + /* write header */ + if + (! jp2_exec (jp2,jp2->m_procedure_list,cio,p_manager)) + { + return false; + } + return j2k_end_decompress(jp2->j2k, cio, p_manager); +} + + +/** + * Ends the compression procedures and possibiliy add data to be read after the + * codestream. + */ +bool jp2_end_compress(opj_jp2_t *jp2, opj_stream_private_t *cio, opj_event_mgr_t * p_manager) +{ + // preconditions + assert(jp2 != 00); + assert(cio != 00); + assert(p_manager != 00); + + /* customization of the end encoding */ + jp2_setup_end_header_writting(jp2); + + if + (! j2k_end_compress(jp2->j2k,cio,p_manager)) + { + return false; + } + /* write header */ + return jp2_exec (jp2,jp2->m_procedure_list,cio,p_manager); +} + +/** +Encode an image into a JPEG-2000 file stream +@param jp2 JP2 compressor handle +@param cio Output buffer stream +@param image Image to encode +@param cstr_info Codestream information structure if required, NULL otherwise +@return Returns true if successful, returns false otherwise +*/ +bool jp2_encode(opj_jp2_t *jp2, struct opj_stream_private *cio, struct opj_event_mgr * p_manager) +{ + return j2k_encode(jp2->j2k,cio,p_manager); +} +/** + * Writes a tile. + * @param p_j2k the jpeg2000 codec. + * @param p_stream the stream to write data to. + * @param p_manager the user event manager. + */ +bool jp2_write_tile ( + opj_jp2_t *p_jp2, + OPJ_UINT32 p_tile_index, + OPJ_BYTE * p_data, + OPJ_UINT32 p_data_size, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ) +{ + return j2k_write_tile (p_jp2->j2k,p_tile_index,p_data,p_data_size,p_stream,p_manager); +} + +/** + * Decode tile data. + * @param p_j2k the jpeg2000 codec. + * @param p_stream the stream to write data to. + * @param p_manager the user event manager. + */ +bool jp2_decode_tile ( + opj_jp2_t * p_jp2, + OPJ_UINT32 p_tile_index, + OPJ_BYTE * p_data, + OPJ_UINT32 p_data_size, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager + ) +{ + return j2k_decode_tile (p_jp2->j2k,p_tile_index,p_data,p_data_size,p_stream,p_manager); +} +/** + * Reads a tile header. + * @param p_j2k the jpeg2000 codec. + * @param p_stream the stream to write data to. + * @param p_manager the user event manager. + */ +bool jp2_read_tile_header ( + opj_jp2_t * p_jp2, + OPJ_UINT32 * p_tile_index, + OPJ_UINT32 * p_data_size, + OPJ_INT32 * p_tile_x0, + OPJ_INT32 * p_tile_y0, + OPJ_INT32 * p_tile_x1, + OPJ_INT32 * p_tile_y1, + OPJ_UINT32 * p_nb_comps, + bool * p_go_on, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager + ) +{ + return j2k_read_tile_header (p_jp2->j2k, + p_tile_index, + p_data_size, + p_tile_x0, + p_tile_y0, + p_tile_x1, + p_tile_y1, + p_nb_comps, + p_go_on, + p_stream, + p_manager); +} + +/** + * Sets up the procedures to do on writting header after the codestream. + * Developpers wanting to extend the library can add their own writting procedures. + */ +void jp2_setup_end_header_writting (opj_jp2_t *jp2) +{ + // preconditions + assert(jp2 != 00); + + opj_procedure_list_add_procedure(jp2->m_procedure_list,(void*)jp2_write_jp2c ); + /* DEVELOPER CORNER, add your custom procedures */ +} + +/** + * Sets up the procedures to do on reading header. + * Developpers wanting to extend the library can add their own writting procedures. + */ +void jp2_setup_header_reading (opj_jp2_t *jp2) +{ + // preconditions + assert(jp2 != 00); + + opj_procedure_list_add_procedure(jp2->m_procedure_list,(void*)jp2_read_header_procedure ); + /* DEVELOPER CORNER, add your custom procedures */ +} + +/** + * Sets up the procedures to do on reading header after the codestream. + * Developpers wanting to extend the library can add their own writting procedures. + */ +void jp2_setup_end_header_reading (opj_jp2_t *jp2) +{ + // preconditions + assert(jp2 != 00); + opj_procedure_list_add_procedure(jp2->m_procedure_list,(void*)jp2_read_header_procedure ); + /* DEVELOPER CORNER, add your custom procedures */ +} + + +/** + * The default validation procedure without any extension. + * + * @param jp2 the jpeg2000 codec to validate. + * @param cio the input stream to validate. + * @param p_manager the user event manager. + * + * @return true if the parameters are correct. + */ +bool jp2_default_validation ( + opj_jp2_t * jp2, + opj_stream_private_t *cio, + opj_event_mgr_t * p_manager + ) +{ + bool l_is_valid = true; + unsigned int i; + + // preconditions + assert(jp2 != 00); + assert(cio != 00); + assert(p_manager != 00); + /* JPEG2000 codec validation */ + /*TODO*/ + + /* STATE checking */ + /* make sure the state is at 0 */ + l_is_valid &= (jp2->jp2_state == JP2_STATE_NONE); + /* make sure not reading a jp2h ???? WEIRD */ + l_is_valid &= (jp2->jp2_img_state == JP2_IMG_STATE_NONE); + + /* POINTER validation */ + /* make sure a j2k codec is present */ + l_is_valid &= (jp2->j2k != 00); + /* make sure a procedure list is present */ + l_is_valid &= (jp2->m_procedure_list != 00); + /* make sure a validation list is present */ + l_is_valid &= (jp2->m_validation_list != 00); + + /* PARAMETER VALIDATION */ + /* number of components */ + l_is_valid &= (jp2->numcl > 0); + /* width */ + l_is_valid &= (jp2->h > 0); + /* height */ + l_is_valid &= (jp2->w > 0); + /* precision */ + for + (i = 0; i < jp2->numcomps; ++i) + { + l_is_valid &= (jp2->comps[i].bpcc > 0); + } + /* METH */ + l_is_valid &= ((jp2->meth > 0) && (jp2->meth < 3)); + + + + /* stream validation */ + /* back and forth is needed */ + l_is_valid &= opj_stream_has_seek(cio); + + return l_is_valid; + +} + +/** + * Sets up the validation ,i.e. adds the procedures to lauch to make sure the codec parameters + * are valid. Developpers wanting to extend the library can add their own validation procedures. + */ +void jp2_setup_encoding_validation (opj_jp2_t *jp2) +{ + // preconditions + assert(jp2 != 00); + opj_procedure_list_add_procedure(jp2->m_validation_list, (void*)jp2_default_validation); + /* DEVELOPER CORNER, add your custom validation procedure */ +} + +/** + * Sets up the validation ,i.e. adds the procedures to lauch to make sure the codec parameters + * are valid. Developpers wanting to extend the library can add their own validation procedures. + */ +void jp2_setup_decoding_validation (opj_jp2_t *jp2) +{ + // preconditions + assert(jp2 != 00); + /* DEVELOPER CORNER, add your custom validation procedure */ +} + +/** + * Sets up the procedures to do on writting header. Developpers wanting to extend the library can add their own writting procedures. + */ +void jp2_setup_header_writting (opj_jp2_t *jp2) +{ + // preconditions + assert(jp2 != 00); + opj_procedure_list_add_procedure(jp2->m_procedure_list,(void*)jp2_write_jp ); + opj_procedure_list_add_procedure(jp2->m_procedure_list,(void*)jp2_write_ftyp ); + opj_procedure_list_add_procedure(jp2->m_procedure_list,(void*)jp2_write_jp2h ); + opj_procedure_list_add_procedure(jp2->m_procedure_list,(void*)jp2_skip_jp2c ); + + /* DEVELOPER CORNER, insert your custom procedures */ + +} + + +/** + * Skips the Jpeg2000 Codestream Header box - JP2C Header box. + * + * @param cio the stream to write data to. + * @param jp2 the jpeg2000 file codec. + * @param p_manager user event manager. + * + * @return true if writting was successful. +*/ +bool jp2_skip_jp2c( + opj_jp2_t *jp2, + struct opj_stream_private *cio, + struct opj_event_mgr * p_manager + ) +{ + // preconditions + assert(jp2 != 00); + assert(cio != 00); + assert(p_manager != 00); + + jp2->j2k_codestream_offset = opj_stream_tell(cio); + if + (opj_stream_skip(cio,8,p_manager) != 8) + { + return false; + } + return true; +} + +struct opj_image * jp2_decode(opj_jp2_t *jp2, struct opj_stream_private *cio, struct opj_event_mgr * p_manager) +{ + /* J2K decoding */ + struct opj_image * image = j2k_decode(jp2->j2k, cio, p_manager); + if + (!image) + { + opj_event_msg(p_manager, EVT_ERROR, "Failed to decode J2K image\n"); + return false; + } + + /* Set Image Color Space */ + if (jp2->enumcs == 16) + image->color_space = CLRSPC_SRGB; + else if (jp2->enumcs == 17) + image->color_space = CLRSPC_GRAY; + else if (jp2->enumcs == 18) + image->color_space = CLRSPC_SYCC; + else + image->color_space = CLRSPC_UNKNOWN; + return image; +} + +void jp2_setup_encoder(opj_jp2_t *jp2, opj_cparameters_t *parameters, opj_image_t *image,opj_event_mgr_t * p_manager) +{ + unsigned int i; + int depth_0, sign; + + if(!jp2 || !parameters || !image) + return; + + /* setup the J2K codec */ + /* ------------------- */ + + /* Check if number of components respects standard */ + if (image->numcomps < 1 || image->numcomps > 16384) { + opj_event_msg(p_manager, EVT_ERROR, "Invalid number of components specified while setting up JP2 encoder\n"); + return; + } + + j2k_setup_encoder(jp2->j2k, parameters, image,p_manager); + + /* setup the JP2 codec */ + /* ------------------- */ + + /* Profile box */ + + jp2->brand = JP2_JP2; /* BR */ + jp2->minversion = 0; /* MinV */ + jp2->numcl = 1; + jp2->cl = (unsigned int*) opj_malloc(jp2->numcl * sizeof(unsigned int)); + jp2->cl[0] = JP2_JP2; /* CL0 : JP2 */ + + /* Image Header box */ + + jp2->numcomps = image->numcomps; /* NC */ + jp2->comps = (opj_jp2_comps_t*) opj_malloc(jp2->numcomps * sizeof(opj_jp2_comps_t)); + jp2->h = image->y1 - image->y0; /* HEIGHT */ + jp2->w = image->x1 - image->x0; /* WIDTH */ + /* BPC */ + depth_0 = image->comps[0].prec - 1; + sign = image->comps[0].sgnd; + jp2->bpc = depth_0 + (sign << 7); + for (i = 1; i < image->numcomps; i++) { + int depth = image->comps[i].prec - 1; + sign = image->comps[i].sgnd; + if (depth_0 != depth) + jp2->bpc = 255; + } + jp2->C = 7; /* C : Always 7 */ + jp2->UnkC = 0; /* UnkC, colorspace specified in colr box */ + jp2->IPR = 0; /* IPR, no intellectual property */ + + /* BitsPerComponent box */ + + for (i = 0; i < image->numcomps; i++) { + jp2->comps[i].bpcc = image->comps[i].prec - 1 + (image->comps[i].sgnd << 7); + } + + /* Colour Specification box */ + + if ((image->numcomps == 1 || image->numcomps == 3) && (jp2->bpc != 255)) { + jp2->meth = 1; /* METH: Enumerated colourspace */ + } else { + jp2->meth = 2; /* METH: Restricted ICC profile */ + } + if (jp2->meth == 1) { + if (image->color_space == 1) + jp2->enumcs = 16; /* sRGB as defined by IEC 61966–2–1 */ + else if (image->color_space == 2) + jp2->enumcs = 17; /* greyscale */ + else if (image->color_space == 3) + jp2->enumcs = 18; /* YUV */ + } else { + jp2->enumcs = 0; /* PROFILE (??) */ + } + jp2->precedence = 0; /* PRECEDENCE */ + jp2->approx = 0; /* APPROX */ + +} + +void jp2_setup_decoder(opj_jp2_t *jp2, opj_dparameters_t *parameters) +{ + if(!jp2 || !parameters) + return; + + /* setup the J2K codec */ + /* ------------------- */ + j2k_setup_decoder(jp2->j2k, parameters); +} +/** + * Sets the given area to be decoded. This function should be called right after opj_read_header and before any tile header reading. + * + * @param p_jp2 the jpeg2000 codec. + * @param p_end_x the right position of the rectangle to decode (in image coordinates). + * @param p_start_y the up position of the rectangle to decode (in image coordinates). + * @param p_end_y the bottom position of the rectangle to decode (in image coordinates). + * @param p_manager the user event manager + * + * @return true if the area could be set. + */ +bool jp2_set_decode_area( + opj_jp2_t *p_jp2, + OPJ_INT32 p_start_x, + OPJ_INT32 p_start_y, + OPJ_INT32 p_end_x, + OPJ_INT32 p_end_y, + struct opj_event_mgr * p_manager + ) +{ + return j2k_set_decode_area(p_jp2->j2k,p_start_x,p_start_y,p_end_x,p_end_y,p_manager); +} + +#if 0 + + + + + +static void jp2_write_url(opj_cio_t *cio, char *Idx_file) { + unsigned int i; + opj_jp2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio, 4); + cio_write(cio, JP2_URL, 4); /* DBTL */ + cio_write(cio, 0, 1); /* VERS */ + cio_write(cio, 0, 3); /* FLAG */ + + if(Idx_file) { + for (i = 0; i < strlen(Idx_file); i++) { + cio_write(cio, Idx_file[i], 1); + } + } + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} +#endif diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/jp2.h b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/jp2.h new file mode 100644 index 0000000..eee3c65 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/jp2.h @@ -0,0 +1,341 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __JP2_H +#define __JP2_H +/** +@file jp2.h +@brief The JPEG-2000 file format Reader/Writer (JP2) + +*/ +#include "openjpeg.h" + + + + +/********************************************************************************** + ********************************* FORWARD DECLARATIONS *************************** + **********************************************************************************/ +struct opj_j2k; +struct opj_procedure_list; +struct opj_event_mgr; +struct opj_stream_private; +struct opj_dparameters; +struct opj_cparameters; + +/** @defgroup JP2 JP2 - JPEG-2000 file format reader/writer */ +/*@{*/ + +#define JPIP_JPIP 0x6a706970 + +#define JP2_JP 0x6a502020 /**< JPEG 2000 signature box */ +#define JP2_FTYP 0x66747970 /**< File type box */ +#define JP2_JP2H 0x6a703268 /**< JP2 header box */ +#define JP2_IHDR 0x69686472 /**< Image header box */ +#define JP2_COLR 0x636f6c72 /**< Colour specification box */ +#define JP2_JP2C 0x6a703263 /**< Contiguous codestream box */ +#define JP2_URL 0x75726c20 /**< URL box */ +#define JP2_DBTL 0x6474626c /**< ??? */ +#define JP2_BPCC 0x62706363 /**< Bits per component box */ +#define JP2_JP2 0x6a703220 /**< File type fields */ + +/* ----------------------------------------------------------------------- */ + + +typedef enum +{ + JP2_STATE_NONE = 0x0, + JP2_STATE_SIGNATURE = 0x1, + JP2_STATE_FILE_TYPE = 0x2, + JP2_STATE_HEADER = 0x4, + JP2_STATE_CODESTREAM = 0x8, + JP2_STATE_END_CODESTREAM = 0x10, + JP2_STATE_UNKNOWN = 0x80000000 +} +JP2_STATE; + +typedef enum +{ + JP2_IMG_STATE_NONE = 0x0, + JP2_IMG_STATE_UNKNOWN = 0x80000000 +} +JP2_IMG_STATE; + +/** +JP2 component +*/ +typedef struct opj_jp2_comps +{ + unsigned int depth; + int sgnd; + unsigned int bpcc; +} +opj_jp2_comps_t; + +/** +JPEG-2000 file format reader/writer +*/ +typedef struct opj_jp2 +{ + /** handle to the J2K codec */ + struct opj_j2k *j2k; + /** list of validation procedures */ + struct opj_procedure_list * m_validation_list; + /** list of execution procedures */ + struct opj_procedure_list * m_procedure_list; + + /* width of image */ + unsigned int w; + /* height of image */ + unsigned int h; + /* number of components in the image */ + unsigned int numcomps; + unsigned int bpc; + unsigned int C; + unsigned int UnkC; + unsigned int IPR; + unsigned int meth; + unsigned int approx; + unsigned int enumcs; + unsigned int precedence; + unsigned int brand; + unsigned int minversion; + unsigned int numcl; + unsigned int *cl; + opj_jp2_comps_t *comps; + unsigned int j2k_codestream_offset; + unsigned int jp2_state; + unsigned int jp2_img_state; + +} +opj_jp2_t; + +/** +JP2 Box +*/ +typedef struct opj_jp2_box +{ + unsigned int length; + unsigned int type; +} +opj_jp2_box_t; + +typedef struct opj_jp2_header_handler +{ + /* marker value */ + int id; + /* action linked to the marker */ + bool (*handler) (opj_jp2_t *jp2,unsigned char * p_header_data, unsigned int p_header_size,struct opj_event_mgr * p_manager); +} +opj_jp2_header_handler_t; + + +typedef struct opj_jp2_img_header_writer_handler +{ + /* action to perform */ + unsigned char* (*handler) (opj_jp2_t *jp2, unsigned int * p_data_size); + /* result of the action : data */ + unsigned char * m_data; + /* size of data */ + unsigned int m_size; +} +opj_jp2_img_header_writer_handler_t; + + + + + +/** @name Exported functions */ +/*@{*/ +/* ----------------------------------------------------------------------- */ + +/** + * Creates a jpeg2000 file decompressor. + * + * @return an empty jpeg2000 file codec. + */ +opj_jp2_t* jp2_create (bool p_is_decoder); + +/** +Destroy a JP2 decompressor handle +@param jp2 JP2 decompressor handle to destroy +*/ +void jp2_destroy(opj_jp2_t *jp2); + +/** +Setup the decoder decoding parameters using user parameters. +Decoding parameters are returned in jp2->j2k->cp. +@param jp2 JP2 decompressor handle +@param parameters decompression parameters +*/ +void jp2_setup_decoder(opj_jp2_t *jp2, struct opj_dparameters *parameters); + +/** + * Decode an image from a JPEG-2000 file stream + * @param jp2 JP2 decompressor handle + * @param cio Input buffer stream + * @param cstr_info Codestream information structure if required, NULL otherwise + * @return Returns a decoded image if successful, returns NULL otherwise +*/ +struct opj_image* jp2_decode(opj_jp2_t *jp2, struct opj_stream_private *cio, struct opj_event_mgr * p_manager); +/** +Setup the encoder parameters using the current image and using user parameters. +Coding parameters are returned in jp2->j2k->cp. +@param jp2 JP2 compressor handle +@param parameters compression parameters +@param image input filled image +*/ +void jp2_setup_encoder(opj_jp2_t *jp2, struct opj_cparameters *parameters, struct opj_image *image,struct opj_event_mgr * p_manager); + +/** + * Starts a compression scheme, i.e. validates the codec parameters, writes the header. + * + * @param jp2 the jpeg2000 file codec. + * @param cio the stream object. + * + * @return true if the codec is valid. + */ +bool jp2_start_compress(opj_jp2_t *jp2, struct opj_stream_private *cio,struct opj_image * p_image,struct opj_event_mgr * p_manager); + +/** + * Ends the compression procedures and possibiliy add data to be read after the + * codestream. + */ +bool jp2_end_compress(opj_jp2_t *jp2, struct opj_stream_private *cio, struct opj_event_mgr * p_manager); + +/** +Encode an image into a JPEG-2000 file stream +@param jp2 JP2 compressor handle +@param cio Output buffer stream +@param image Image to encode +@param cstr_info Codestream information structure if required, NULL otherwise +@return Returns true if successful, returns false otherwise +*/ +bool jp2_encode(opj_jp2_t *jp2, struct opj_stream_private *cio, struct opj_event_mgr * p_manager); + +/** + * Reads a jpeg2000 file header structure. + * + * @param cio the stream to read data from. + * @param jp2 the jpeg2000 file header structure. + * @param p_manager the user event manager. + * + * @return true if the box is valid. + */ +bool jp2_read_header( + opj_jp2_t *jp2, + struct opj_image ** p_image, + OPJ_INT32 * p_tile_x0, + OPJ_INT32 * p_tile_y0, + OPJ_UINT32 * p_tile_width, + OPJ_UINT32 * p_tile_height, + OPJ_UINT32 * p_nb_tiles_x, + OPJ_UINT32 * p_nb_tiles_y, + struct opj_stream_private *cio, + struct opj_event_mgr * p_manager + ); +/** + * Ends the decompression procedures and possibiliy add data to be read after the + * codestream. + */ +bool jp2_end_decompress(opj_jp2_t *jp2, struct opj_stream_private *cio, struct opj_event_mgr * p_manager); + +/** + * Writes a tile. + * @param p_j2k the jpeg2000 codec. + * @param p_stream the stream to write data to. + * @param p_manager the user event manager. + */ +bool jp2_write_tile ( + opj_jp2_t *p_jp2, + OPJ_UINT32 p_tile_index, + OPJ_BYTE * p_data, + OPJ_UINT32 p_data_size, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); +/** + * Decode tile data. + * @param p_j2k the jpeg2000 codec. + * @param p_stream the stream to write data to. + * @param p_manager the user event manager. + */ +bool jp2_decode_tile ( + opj_jp2_t * p_jp2, + OPJ_UINT32 p_tile_index, + OPJ_BYTE * p_data, + OPJ_UINT32 p_data_size, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); +/** + * Reads a tile header. + * @param p_j2k the jpeg2000 codec. + * @param p_stream the stream to write data to. + * @param p_manager the user event manager. + */ +bool jp2_read_tile_header ( + opj_jp2_t * p_j2k, + OPJ_UINT32 * p_tile_index, + OPJ_UINT32 * p_data_size, + OPJ_INT32 * p_tile_x0, + OPJ_INT32 * p_tile_y0, + OPJ_INT32 * p_tile_x1, + OPJ_INT32 * p_tile_y1, + OPJ_UINT32 * p_nb_comps, + bool * p_go_on, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager + ); +/** + * Sets the given area to be decoded. This function should be called right after opj_read_header and before any tile header reading. + * + * @param p_jp2 the jpeg2000 codec. + * @param p_end_x the right position of the rectangle to decode (in image coordinates). + * @param p_start_y the up position of the rectangle to decode (in image coordinates). + * @param p_end_y the bottom position of the rectangle to decode (in image coordinates). + * @param p_manager the user event manager + * + * @return true if the area could be set. + */ +bool jp2_set_decode_area( + opj_jp2_t *p_jp2, + OPJ_INT32 p_start_x, + OPJ_INT32 p_start_y, + OPJ_INT32 p_end_x, + OPJ_INT32 p_end_y, + struct opj_event_mgr * p_manager + ); + +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __JP2_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/jpt.c b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/jpt.c new file mode 100644 index 0000000..0cfe44f --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/jpt.c @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "jpt.h" +#include "openjpeg.h" +#include "cio.h" +#include "event.h" +/* + * Read the information contains in VBAS [JPP/JPT stream message header] + * Store information (7 bits) in value + * @param p_cio the stream to read from. + * @param p_value the data to update + * @return the nb of bytes read or -1 if an io error occurred. + */ +bool jpt_read_VBAS_info(opj_stream_private_t * p_cio, OPJ_UINT32 * p_nb_bytes_read, OPJ_UINT32 * p_value, opj_event_mgr_t * p_manager) +{ + OPJ_BYTE l_elmt; + OPJ_UINT32 l_nb_bytes_read = 0; + + // read data till the MSB of the current byte is 1. + // concatenate 7 bits of data, last bit is finish flag + + // read data from the stream + + if + (opj_stream_read_data(p_cio,&l_elmt,1,p_manager) != 1) + { + opj_event_msg(p_manager, EVT_ERROR, "Error trying to read a byte of data.\n"); + return false; + } + ++l_nb_bytes_read; + + // is the MSB equal to 1 ? + while + (l_elmt & 0x80) + { + // concatenate 7 bits of data, last bit is finish flag + *p_value = (*p_value << 7) | (l_elmt & 0x7f); + if + (opj_stream_read_data(p_cio,&l_elmt,1,p_manager) != 1) + { + opj_event_msg(p_manager, EVT_ERROR, "Error trying to read a byte of data.\n"); + return false; + } + ++l_nb_bytes_read; + } + // concatenate 7 bits of data, last bit is finish flag + *p_value = (*p_value << 7) | (l_elmt & 0x7f); + * p_nb_bytes_read = l_nb_bytes_read; + return true; +} + +/* + * Initialize the value of the message header structure + * + */ +void jpt_init_msg_header(opj_jpt_msg_header_t * header) +{ + header->Id = 0; /* In-class Identifier */ + header->last_byte = 0; /* Last byte information */ + header->Class_Id = 0; /* Class Identifier */ + header->CSn_Id = 0; /* CSn : index identifier */ + header->Msg_offset = 0; /* Message offset */ + header->Msg_length = 0; /* Message length */ + header->Layer_nb = 0; /* Auxiliary for JPP case */ +} + +/* + * Re-initialize the value of the message header structure + * + * Only parameters always present in message header + * + */ +void jpt_reinit_msg_header(opj_jpt_msg_header_t * header) +{ + header->Id = 0; /* In-class Identifier */ + header->last_byte = 0; /* Last byte information */ + header->Msg_offset = 0; /* Message offset */ + header->Msg_length = 0; /* Message length */ +} + +/* + * Read the message header for a JPP/JPT - stream + * + */ +bool jpt_read_msg_header(opj_stream_private_t *cio, opj_jpt_msg_header_t *header, OPJ_UINT32 * p_nb_bytes_read, opj_event_mgr_t * p_manager) +{ + OPJ_BYTE elmt, Class = 0, CSn = 0; + OPJ_UINT32 l_nb_bytes_read = 0; + OPJ_UINT32 l_last_nb_bytes_read; + + + jpt_reinit_msg_header(header); + + /* ------------- */ + /* VBAS : Bin-ID */ + /* ------------- */ + if + (opj_stream_read_data(cio,&elmt,1,p_manager) != 1) + { + opj_event_msg(p_manager, EVT_ERROR, "Forbidden value encounter in message header !!\n"); + return false; + } + ++l_nb_bytes_read; + + /* See for Class and CSn */ + switch ((elmt >> 5) & 0x03) + { + case 0: + opj_event_msg(p_manager, EVT_ERROR, "Error trying to read a byte of data!!!\n"); + break; + case 1: + Class = 0; + CSn = 0; + break; + case 2: + Class = 1; + CSn = 0; + break; + case 3: + Class = 1; + CSn = 1; + break; + default: + break; + } + + /* see information on bits 'c' [p 10 : A.2.1 general, ISO/IEC FCD 15444-9] */ + if + (((elmt >> 4) & 0x01) == 1) + { + header->last_byte = 1; + } + + /* In-class identifier */ + header->Id |= (elmt & 0x0f); + if + ((elmt >> 7) == 1) + { + l_last_nb_bytes_read = 0; + if + (! jpt_read_VBAS_info(cio, &l_last_nb_bytes_read, &(header->Id), p_manager)) + { + opj_event_msg(p_manager, EVT_ERROR, "Error trying to read a byte of data!!!\n"); + return false; + } + l_nb_bytes_read += l_last_nb_bytes_read; + } + + /* ------------ */ + /* VBAS : Class */ + /* ------------ */ + if (Class == 1) + { + header->Class_Id = 0; + l_last_nb_bytes_read = 0; + if + (! jpt_read_VBAS_info(cio, &l_last_nb_bytes_read, &(header->Class_Id), p_manager)) + { + opj_event_msg(p_manager, EVT_ERROR, "Error trying to read a byte of data!!!\n"); + return false; + } + l_nb_bytes_read += l_last_nb_bytes_read; + } + + /* ---------- */ + /* VBAS : CSn */ + /* ---------- */ + if (CSn == 1) + { + header->CSn_Id = 0; + l_last_nb_bytes_read = 0; + if + (! jpt_read_VBAS_info(cio, &l_last_nb_bytes_read, &(header->CSn_Id), p_manager)) + { + opj_event_msg(p_manager, EVT_ERROR, "Error trying to read a byte of data!!!\n"); + return false; + } + l_nb_bytes_read += l_last_nb_bytes_read; + } + + /* ----------------- */ + /* VBAS : Msg_offset */ + /* ----------------- */ + l_last_nb_bytes_read = 0; + if + (! jpt_read_VBAS_info(cio, &l_last_nb_bytes_read, &(header->Msg_offset), p_manager)) + { + opj_event_msg(p_manager, EVT_ERROR, "Error trying to read a byte of data!!!\n"); + return false; + } + l_nb_bytes_read += l_last_nb_bytes_read; + + /* ----------------- */ + /* VBAS : Msg_length */ + /* ----------------- */ + l_last_nb_bytes_read = 0; + if + (! jpt_read_VBAS_info(cio, &l_last_nb_bytes_read, &(header->Msg_length), p_manager)) + { + opj_event_msg(p_manager, EVT_ERROR, "Error trying to read a byte of data!!!\n"); + return false; + } + l_nb_bytes_read += l_last_nb_bytes_read; + + /* ---------- */ + /* VBAS : Aux */ + /* ---------- */ + if ((header->Class_Id & 0x01) == 1) + { + header->Layer_nb = 0; + if + (! jpt_read_VBAS_info(cio, &l_last_nb_bytes_read, &(header->Layer_nb), p_manager)) + { + opj_event_msg(p_manager, EVT_ERROR, "Error trying to read a byte of data!!!\n"); + return false; + } + l_nb_bytes_read += l_last_nb_bytes_read; + } + * p_nb_bytes_read = l_nb_bytes_read; + return true; +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/jpt.h b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/jpt.h new file mode 100644 index 0000000..7c67cff --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/jpt.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __JPT_H +#define __JPT_H +/** +@file jpt.h +@brief JPT-stream reader (JPEG 2000, JPIP) + +JPT-stream functions are implemented in J2K.C. +*/ +#include "openjpeg.h" +struct opj_stream_private; +struct opj_event_mgr; +/** +Message Header JPT stream structure +*/ +typedef struct opj_jpt_msg_header +{ + /** In-class Identifier */ + OPJ_UINT32 Id; + /** Last byte information */ + OPJ_UINT32 last_byte; + /** Class Identifier */ + OPJ_UINT32 Class_Id; + /** CSn : index identifier */ + OPJ_UINT32 CSn_Id; + /** Message offset */ + OPJ_UINT32 Msg_offset; + /** Message length */ + OPJ_UINT32 Msg_length; + /** Auxiliary for JPP case */ + OPJ_UINT32 Layer_nb; +} opj_jpt_msg_header_t; + +/* ----------------------------------------------------------------------- */ + +/** +Initialize the value of the message header structure +@param header Message header structure +*/ +void jpt_init_msg_header(opj_jpt_msg_header_t * header); + +/** + * Read the message header for a JPP/JPT - stream + * @param p_cio stream handle + * @param header JPT Message header structure + * @param p_manager user event manager to display nice messages. +*/ +bool jpt_read_msg_header( + struct opj_stream_private * p_cio, + opj_jpt_msg_header_t * p_header, + OPJ_UINT32 * p_nb_bytes_read, + struct opj_event_mgr * p_manager); + +#endif diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/mct.c b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/mct.c new file mode 100644 index 0000000..5eadc21 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/mct.c @@ -0,0 +1,303 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mct.h" +#include "fix.h" +#include "opj_malloc.h" + +/* */ +/* This table contains the norms of the basis function of the reversible MCT. */ +/* */ +static const OPJ_FLOAT64 mct_norms[3] = { 1.732, .8292, .8292 }; + +/* */ +/* This table contains the norms of the basis function of the irreversible MCT. */ +/* */ +static const OPJ_FLOAT64 mct_norms_real[3] = { 1.732, 1.805, 1.573 }; + + + +const OPJ_FLOAT64 * get_mct_norms () +{ + return mct_norms; +} + +const OPJ_FLOAT64 * get_mct_norms_real () +{ + return mct_norms_real; +} + + + +/* */ +/* Foward reversible MCT. */ +/* */ +void mct_encode( + OPJ_INT32* restrict c0, + OPJ_INT32* restrict c1, + OPJ_INT32* restrict c2, + OPJ_UINT32 n) +{ + OPJ_UINT32 i; + for(i = 0; i < n; ++i) { + OPJ_INT32 r = c0[i]; + OPJ_INT32 g = c1[i]; + OPJ_INT32 b = c2[i]; + OPJ_INT32 y = (r + (g * 2) + b) >> 2; + OPJ_INT32 u = b - g; + OPJ_INT32 v = r - g; + c0[i] = y; + c1[i] = u; + c2[i] = v; + } +} + +/* */ +/* Inverse reversible MCT. */ +/* */ +void mct_decode( + OPJ_INT32* restrict c0, + OPJ_INT32* restrict c1, + OPJ_INT32* restrict c2, + OPJ_UINT32 n) +{ + OPJ_UINT32 i; + for (i = 0; i < n; ++i) { + OPJ_INT32 y = c0[i]; + OPJ_INT32 u = c1[i]; + OPJ_INT32 v = c2[i]; + OPJ_INT32 g = y - ((u + v) >> 2); + OPJ_INT32 r = v + g; + OPJ_INT32 b = u + g; + c0[i] = r; + c1[i] = g; + c2[i] = b; + } +} + +/* */ +/* Get norm of basis function of reversible MCT. */ +/* */ +OPJ_FLOAT64 mct_getnorm(OPJ_UINT32 compno) { + return mct_norms[compno]; +} + +/* */ +/* Foward irreversible MCT. */ +/* */ +void mct_encode_real( + OPJ_INT32* restrict c0, + OPJ_INT32* restrict c1, + OPJ_INT32* restrict c2, + OPJ_UINT32 n) +{ + OPJ_UINT32 i; + for(i = 0; i < n; ++i) { + OPJ_INT32 r = c0[i]; + OPJ_INT32 g = c1[i]; + OPJ_INT32 b = c2[i]; + OPJ_INT32 y = fix_mul(r, 2449) + fix_mul(g, 4809) + fix_mul(b, 934); + OPJ_INT32 u = -fix_mul(r, 1382) - fix_mul(g, 2714) + fix_mul(b, 4096); + OPJ_INT32 v = fix_mul(r, 4096) - fix_mul(g, 3430) - fix_mul(b, 666); + c0[i] = y; + c1[i] = u; + c2[i] = v; + } +} + +/* */ +/* Inverse irreversible MCT. */ +/* */ +void mct_decode_real( + OPJ_FLOAT32* restrict c0, + OPJ_FLOAT32* restrict c1, + OPJ_FLOAT32* restrict c2, + OPJ_UINT32 n) +{ + OPJ_UINT32 i; + for(i = 0; i < n; ++i) { + OPJ_FLOAT32 y = c0[i]; + OPJ_FLOAT32 u = c1[i]; + OPJ_FLOAT32 v = c2[i]; + OPJ_FLOAT32 r = y + (v * 1.402f); + OPJ_FLOAT32 g = y - (u * 0.34413f) - (v * (0.71414f)); + OPJ_FLOAT32 b = y + (u * 1.772f); + c0[i] = r; + c1[i] = g; + c2[i] = b; + } +} + +/* */ +/* Get norm of basis function of irreversible MCT. */ +/* */ +OPJ_FLOAT64 mct_getnorm_real(OPJ_UINT32 compno) { + return mct_norms_real[compno]; +} + +bool mct_encode_custom( + // MCT data + OPJ_BYTE * pCodingdata, + // size of components + OPJ_UINT32 n, + // components + OPJ_BYTE ** pData, + // nb of components (i.e. size of pData) + OPJ_UINT32 pNbComp, + // tells if the data is signed + OPJ_UINT32 isSigned) +{ + OPJ_FLOAT32 * lMct = (OPJ_FLOAT32 *) pCodingdata; + OPJ_UINT32 i; + OPJ_UINT32 j; + OPJ_UINT32 k; + OPJ_UINT32 lNbMatCoeff = pNbComp * pNbComp; + OPJ_INT32 * lCurrentData = 00; + OPJ_INT32 * lCurrentMatrix = 00; + OPJ_INT32 ** lData = (OPJ_INT32 **) pData; + OPJ_UINT32 lMultiplicator = 1 << 13; + OPJ_INT32 * lMctPtr; + + lCurrentData = (OPJ_INT32 *) opj_malloc((pNbComp + lNbMatCoeff) * sizeof(OPJ_INT32)); + if + (! lCurrentData) + { + return false; + } + lCurrentMatrix = lCurrentData + pNbComp; + for + (i =0;i + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MCT_H +#define __MCT_H +/** +@file mct.h +@brief Implementation of a multi-component transforms (MCT) + +The functions in MCT.C have for goal to realize reversible and irreversible multicomponent +transform. The functions in MCT.C are used by some function in TCD.C. +*/ +#include "openjpeg.h" +/** @defgroup MCT MCT - Implementation of a multi-component transform */ +/*@{*/ + +/** @name Exported functions */ +/*@{*/ +/* ----------------------------------------------------------------------- */ +/** +Apply a reversible multi-component transform to an image +@param c0 Samples for red component +@param c1 Samples for green component +@param c2 Samples blue component +@param n Number of samples for each component +*/ +void mct_encode(OPJ_INT32 *c0, OPJ_INT32 *c1, OPJ_INT32 *c2, OPJ_UINT32 n); +/** +Apply a reversible multi-component inverse transform to an image +@param c0 Samples for luminance component +@param c1 Samples for red chrominance component +@param c2 Samples for blue chrominance component +@param n Number of samples for each component +*/ +void mct_decode(OPJ_INT32 *c0, OPJ_INT32 *c1, OPJ_INT32 *c2, OPJ_UINT32 n); +/** +Get norm of the basis function used for the reversible multi-component transform +@param compno Number of the component (0->Y, 1->U, 2->V) +@return +*/ +OPJ_FLOAT64 mct_getnorm(OPJ_UINT32 compno); + +/** +Apply an irreversible multi-component transform to an image +@param c0 Samples for red component +@param c1 Samples for green component +@param c2 Samples blue component +@param n Number of samples for each component +*/ +void mct_encode_real(OPJ_INT32 *c0, OPJ_INT32 *c1, OPJ_INT32 *c2, OPJ_UINT32 n); +/** +Apply an irreversible multi-component inverse transform to an image +@param c0 Samples for luminance component +@param c1 Samples for red chrominance component +@param c2 Samples for blue chrominance component +@param n Number of samples for each component +*/ +void mct_decode_real(OPJ_FLOAT32* c0, OPJ_FLOAT32* c1, OPJ_FLOAT32* c2, OPJ_UINT32 n); +/** +Get norm of the basis function used for the irreversible multi-component transform +@param compno Number of the component (0->Y, 1->U, 2->V) +@return +*/ +OPJ_FLOAT64 mct_getnorm_real(OPJ_UINT32 compno); + +bool mct_encode_custom( + // MCT data + OPJ_BYTE * p_coding_data, + // size of components + OPJ_UINT32 n, + // components + OPJ_BYTE ** p_data, + // nb of components (i.e. size of p_data) + OPJ_UINT32 p_nb_comp, + // tells if the data is signed + OPJ_UINT32 is_signed); + +bool mct_decode_custom( + // MCT data + OPJ_BYTE * pDecodingData, + // size of components + OPJ_UINT32 n, + // components + OPJ_BYTE ** pData, + // nb of components (i.e. size of pData) + OPJ_UINT32 pNbComp, + // tells if the data is signed + OPJ_UINT32 isSigned); + +void opj_calculate_norms(OPJ_FLOAT64 * pNorms,OPJ_UINT32 p_nb_comps,OPJ_FLOAT32 * pMatrix); + +const OPJ_FLOAT64 * get_mct_norms (); +const OPJ_FLOAT64 * get_mct_norms_real (); + + +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __MCT_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/mqc.c b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/mqc.c new file mode 100644 index 0000000..5f5573d --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/mqc.c @@ -0,0 +1,542 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mqc.h" +#include "t1.h" +#include "opj_malloc.h" + +/** @defgroup MQC MQC - Implementation of an MQ-Coder */ +/*@{*/ + +/** @name Local static functions */ +/*@{*/ + +/** +Output a byte, doing bit-stuffing if necessary. +After a 0xff byte, the next byte must be smaller than 0x90. +@param mqc MQC handle +*/ +static void mqc_byteout(opj_mqc_t *mqc); +/** +Renormalize mqc->a and mqc->c while encoding, so that mqc->a stays between 0x8000 and 0x10000 +@param mqc MQC handle +*/ +static void mqc_renorme(opj_mqc_t *mqc); +/** +Encode the most probable symbol +@param mqc MQC handle +*/ +static void mqc_codemps(opj_mqc_t *mqc); +/** +Encode the most least symbol +@param mqc MQC handle +*/ +static void mqc_codelps(opj_mqc_t *mqc); +/** +Fill mqc->c with 1's for flushing +@param mqc MQC handle +*/ +static void mqc_setbits(opj_mqc_t *mqc); +/** +FIXME: documentation ??? +@param mqc MQC handle +@return +*/ +static OPJ_INT32 mqc_mpsexchange(opj_mqc_t *mqc); +/** +FIXME: documentation ??? +@param mqc MQC handle +@return +*/ +static OPJ_INT32 mqc_lpsexchange(opj_mqc_t *mqc); +/** +Input a byte +@param mqc MQC handle +*/ +static void mqc_bytein(opj_mqc_t *mqc); +/** +Renormalize mqc->a and mqc->c while decoding +@param mqc MQC handle +*/ +static void mqc_renormd(opj_mqc_t *mqc); + +/*@}*/ + +/*@}*/ + +/* */ +/* This array defines all the possible states for a context. */ +/* */ +static opj_mqc_state_t mqc_states[47 * 2] = { + {0x5601, 0, &mqc_states[2], &mqc_states[3]}, + {0x5601, 1, &mqc_states[3], &mqc_states[2]}, + {0x3401, 0, &mqc_states[4], &mqc_states[12]}, + {0x3401, 1, &mqc_states[5], &mqc_states[13]}, + {0x1801, 0, &mqc_states[6], &mqc_states[18]}, + {0x1801, 1, &mqc_states[7], &mqc_states[19]}, + {0x0ac1, 0, &mqc_states[8], &mqc_states[24]}, + {0x0ac1, 1, &mqc_states[9], &mqc_states[25]}, + {0x0521, 0, &mqc_states[10], &mqc_states[58]}, + {0x0521, 1, &mqc_states[11], &mqc_states[59]}, + {0x0221, 0, &mqc_states[76], &mqc_states[66]}, + {0x0221, 1, &mqc_states[77], &mqc_states[67]}, + {0x5601, 0, &mqc_states[14], &mqc_states[13]}, + {0x5601, 1, &mqc_states[15], &mqc_states[12]}, + {0x5401, 0, &mqc_states[16], &mqc_states[28]}, + {0x5401, 1, &mqc_states[17], &mqc_states[29]}, + {0x4801, 0, &mqc_states[18], &mqc_states[28]}, + {0x4801, 1, &mqc_states[19], &mqc_states[29]}, + {0x3801, 0, &mqc_states[20], &mqc_states[28]}, + {0x3801, 1, &mqc_states[21], &mqc_states[29]}, + {0x3001, 0, &mqc_states[22], &mqc_states[34]}, + {0x3001, 1, &mqc_states[23], &mqc_states[35]}, + {0x2401, 0, &mqc_states[24], &mqc_states[36]}, + {0x2401, 1, &mqc_states[25], &mqc_states[37]}, + {0x1c01, 0, &mqc_states[26], &mqc_states[40]}, + {0x1c01, 1, &mqc_states[27], &mqc_states[41]}, + {0x1601, 0, &mqc_states[58], &mqc_states[42]}, + {0x1601, 1, &mqc_states[59], &mqc_states[43]}, + {0x5601, 0, &mqc_states[30], &mqc_states[29]}, + {0x5601, 1, &mqc_states[31], &mqc_states[28]}, + {0x5401, 0, &mqc_states[32], &mqc_states[28]}, + {0x5401, 1, &mqc_states[33], &mqc_states[29]}, + {0x5101, 0, &mqc_states[34], &mqc_states[30]}, + {0x5101, 1, &mqc_states[35], &mqc_states[31]}, + {0x4801, 0, &mqc_states[36], &mqc_states[32]}, + {0x4801, 1, &mqc_states[37], &mqc_states[33]}, + {0x3801, 0, &mqc_states[38], &mqc_states[34]}, + {0x3801, 1, &mqc_states[39], &mqc_states[35]}, + {0x3401, 0, &mqc_states[40], &mqc_states[36]}, + {0x3401, 1, &mqc_states[41], &mqc_states[37]}, + {0x3001, 0, &mqc_states[42], &mqc_states[38]}, + {0x3001, 1, &mqc_states[43], &mqc_states[39]}, + {0x2801, 0, &mqc_states[44], &mqc_states[38]}, + {0x2801, 1, &mqc_states[45], &mqc_states[39]}, + {0x2401, 0, &mqc_states[46], &mqc_states[40]}, + {0x2401, 1, &mqc_states[47], &mqc_states[41]}, + {0x2201, 0, &mqc_states[48], &mqc_states[42]}, + {0x2201, 1, &mqc_states[49], &mqc_states[43]}, + {0x1c01, 0, &mqc_states[50], &mqc_states[44]}, + {0x1c01, 1, &mqc_states[51], &mqc_states[45]}, + {0x1801, 0, &mqc_states[52], &mqc_states[46]}, + {0x1801, 1, &mqc_states[53], &mqc_states[47]}, + {0x1601, 0, &mqc_states[54], &mqc_states[48]}, + {0x1601, 1, &mqc_states[55], &mqc_states[49]}, + {0x1401, 0, &mqc_states[56], &mqc_states[50]}, + {0x1401, 1, &mqc_states[57], &mqc_states[51]}, + {0x1201, 0, &mqc_states[58], &mqc_states[52]}, + {0x1201, 1, &mqc_states[59], &mqc_states[53]}, + {0x1101, 0, &mqc_states[60], &mqc_states[54]}, + {0x1101, 1, &mqc_states[61], &mqc_states[55]}, + {0x0ac1, 0, &mqc_states[62], &mqc_states[56]}, + {0x0ac1, 1, &mqc_states[63], &mqc_states[57]}, + {0x09c1, 0, &mqc_states[64], &mqc_states[58]}, + {0x09c1, 1, &mqc_states[65], &mqc_states[59]}, + {0x08a1, 0, &mqc_states[66], &mqc_states[60]}, + {0x08a1, 1, &mqc_states[67], &mqc_states[61]}, + {0x0521, 0, &mqc_states[68], &mqc_states[62]}, + {0x0521, 1, &mqc_states[69], &mqc_states[63]}, + {0x0441, 0, &mqc_states[70], &mqc_states[64]}, + {0x0441, 1, &mqc_states[71], &mqc_states[65]}, + {0x02a1, 0, &mqc_states[72], &mqc_states[66]}, + {0x02a1, 1, &mqc_states[73], &mqc_states[67]}, + {0x0221, 0, &mqc_states[74], &mqc_states[68]}, + {0x0221, 1, &mqc_states[75], &mqc_states[69]}, + {0x0141, 0, &mqc_states[76], &mqc_states[70]}, + {0x0141, 1, &mqc_states[77], &mqc_states[71]}, + {0x0111, 0, &mqc_states[78], &mqc_states[72]}, + {0x0111, 1, &mqc_states[79], &mqc_states[73]}, + {0x0085, 0, &mqc_states[80], &mqc_states[74]}, + {0x0085, 1, &mqc_states[81], &mqc_states[75]}, + {0x0049, 0, &mqc_states[82], &mqc_states[76]}, + {0x0049, 1, &mqc_states[83], &mqc_states[77]}, + {0x0025, 0, &mqc_states[84], &mqc_states[78]}, + {0x0025, 1, &mqc_states[85], &mqc_states[79]}, + {0x0015, 0, &mqc_states[86], &mqc_states[80]}, + {0x0015, 1, &mqc_states[87], &mqc_states[81]}, + {0x0009, 0, &mqc_states[88], &mqc_states[82]}, + {0x0009, 1, &mqc_states[89], &mqc_states[83]}, + {0x0005, 0, &mqc_states[90], &mqc_states[84]}, + {0x0005, 1, &mqc_states[91], &mqc_states[85]}, + {0x0001, 0, &mqc_states[90], &mqc_states[86]}, + {0x0001, 1, &mqc_states[91], &mqc_states[87]}, + {0x5601, 0, &mqc_states[92], &mqc_states[92]}, + {0x5601, 1, &mqc_states[93], &mqc_states[93]}, +}; + +/* +========================================================== + local functions +========================================================== +*/ + +static void mqc_byteout(opj_mqc_t *mqc) { + if (*mqc->bp == 0xff) { + mqc->bp++; + *mqc->bp = mqc->c >> 20; + mqc->c &= 0xfffff; + mqc->ct = 7; + } else { + if ((mqc->c & 0x8000000) == 0) { /* ((mqc->c&0x8000000)==0) CHANGE */ + mqc->bp++; + *mqc->bp = mqc->c >> 19; + mqc->c &= 0x7ffff; + mqc->ct = 8; + } else { + (*mqc->bp)++; + if (*mqc->bp == 0xff) { + mqc->c &= 0x7ffffff; + mqc->bp++; + *mqc->bp = mqc->c >> 20; + mqc->c &= 0xfffff; + mqc->ct = 7; + } else { + mqc->bp++; + *mqc->bp = mqc->c >> 19; + mqc->c &= 0x7ffff; + mqc->ct = 8; + } + } + } +} + +static void mqc_renorme(opj_mqc_t *mqc) { + do { + mqc->a <<= 1; + mqc->c <<= 1; + mqc->ct--; + if (mqc->ct == 0) { + mqc_byteout(mqc); + } + } while ((mqc->a & 0x8000) == 0); +} + +static void mqc_codemps(opj_mqc_t *mqc) { + mqc->a -= (*mqc->curctx)->qeval; + if ((mqc->a & 0x8000) == 0) { + if (mqc->a < (*mqc->curctx)->qeval) { + mqc->a = (*mqc->curctx)->qeval; + } else { + mqc->c += (*mqc->curctx)->qeval; + } + *mqc->curctx = (*mqc->curctx)->nmps; + mqc_renorme(mqc); + } else { + mqc->c += (*mqc->curctx)->qeval; + } +} + +static void mqc_codelps(opj_mqc_t *mqc) { + mqc->a -= (*mqc->curctx)->qeval; + if (mqc->a < (*mqc->curctx)->qeval) { + mqc->c += (*mqc->curctx)->qeval; + } else { + mqc->a = (*mqc->curctx)->qeval; + } + *mqc->curctx = (*mqc->curctx)->nlps; + mqc_renorme(mqc); +} + +static void mqc_setbits(opj_mqc_t *mqc) { + OPJ_UINT32 tempc = mqc->c + mqc->a; + mqc->c |= 0xffff; + if (mqc->c >= tempc) { + mqc->c -= 0x8000; + } +} + +static OPJ_INT32 mqc_mpsexchange(opj_mqc_t *mqc) { + OPJ_INT32 d; + if (mqc->a < (*mqc->curctx)->qeval) { + d = 1 - (*mqc->curctx)->mps; + *mqc->curctx = (*mqc->curctx)->nlps; + } else { + d = (*mqc->curctx)->mps; + *mqc->curctx = (*mqc->curctx)->nmps; + } + + return d; +} + +static OPJ_INT32 mqc_lpsexchange(opj_mqc_t *mqc) { + OPJ_INT32 d; + if (mqc->a < (*mqc->curctx)->qeval) { + mqc->a = (*mqc->curctx)->qeval; + d = (*mqc->curctx)->mps; + *mqc->curctx = (*mqc->curctx)->nmps; + } else { + mqc->a = (*mqc->curctx)->qeval; + d = 1 - (*mqc->curctx)->mps; + *mqc->curctx = (*mqc->curctx)->nlps; + } + + return d; +} + +static void mqc_bytein(opj_mqc_t *mqc) { + if (mqc->bp != mqc->end) { + OPJ_UINT32 c; + if (mqc->bp + 1 != mqc->end) { + c = *(mqc->bp + 1); + } else { + c = 0xff; + } + if (*mqc->bp == 0xff) { + if (c > 0x8f) { + mqc->c += 0xff00; + mqc->ct = 8; + } else { + mqc->bp++; + mqc->c += c << 9; + mqc->ct = 7; + } + } else { + mqc->bp++; + mqc->c += c << 8; + mqc->ct = 8; + } + } else { + mqc->c += 0xff00; + mqc->ct = 8; + } +} + +static void mqc_renormd(opj_mqc_t *mqc) { + do { + if (mqc->ct == 0) { + mqc_bytein(mqc); + } + mqc->a <<= 1; + mqc->c <<= 1; + mqc->ct--; + } while (mqc->a < 0x8000); +} + +/* +========================================================== + MQ-Coder interface +========================================================== +*/ + +opj_mqc_t* mqc_create(void) { + opj_mqc_t *mqc = (opj_mqc_t*)opj_malloc(sizeof(opj_mqc_t)); + return mqc; +} + +void mqc_destroy(opj_mqc_t *mqc) { + if + (mqc) + { + opj_free(mqc); + } +} + +OPJ_UINT32 mqc_numbytes(opj_mqc_t *mqc) { + return mqc->bp - mqc->start; +} + +void mqc_init_enc(opj_mqc_t *mqc, OPJ_BYTE *bp) { + mqc_setcurctx(mqc, 0); + mqc->a = 0x8000; + mqc->c = 0; + mqc->bp = bp - 1; + *(mqc->bp) = 0; + mqc->ct = 12; + /*if (*mqc->bp == 0xff) { + mqc->ct = 13; + }*/ + mqc->start = bp; +} + +void mqc_encode(opj_mqc_t *mqc, OPJ_UINT32 d) { + if ((*mqc->curctx)->mps == d) { + mqc_codemps(mqc); + } else { + mqc_codelps(mqc); + } +} + +void mqc_flush(opj_mqc_t *mqc) { + mqc_setbits(mqc); + mqc->c <<= mqc->ct; + mqc_byteout(mqc); + mqc->c <<= mqc->ct; + mqc_byteout(mqc); + + if (*mqc->bp != 0xff) { + mqc->bp++; + } +} + +void mqc_bypass_init_enc(opj_mqc_t *mqc) { + mqc->c = 0; + mqc->ct = 8; + /*if (*mqc->bp == 0xff) { + mqc->ct = 7; + } */ +} + +void mqc_bypass_enc(opj_mqc_t *mqc, OPJ_UINT32 d) { + mqc->ct--; + mqc->c = mqc->c + (d << mqc->ct); + if (mqc->ct == 0) { + mqc->bp++; + *mqc->bp = mqc->c; + mqc->ct = 8; + if (*mqc->bp == 0xff) { + mqc->ct = 7; + } + mqc->c = 0; + } +} + +OPJ_UINT32 mqc_bypass_flush_enc(opj_mqc_t *mqc) { + OPJ_BYTE bit_padding; + + bit_padding = 0; + + if (mqc->ct != 0) { + while (mqc->ct > 0) { + mqc->ct--; + mqc->c += bit_padding << mqc->ct; + bit_padding = (bit_padding + 1) & 0x01; + } + mqc->bp++; + *mqc->bp = mqc->c; + mqc->ct = 8; + mqc->c = 0; + } + + return 1; +} + +void mqc_reset_enc(opj_mqc_t *mqc) { + mqc_resetstates(mqc); + mqc_setstate(mqc, T1_CTXNO_UNI, 0, 46); + mqc_setstate(mqc, T1_CTXNO_AGG, 0, 3); + mqc_setstate(mqc, T1_CTXNO_ZC, 0, 4); +} + +OPJ_UINT32 mqc_restart_enc(opj_mqc_t *mqc) { + OPJ_UINT32 correction = 1; + + /* */ + OPJ_INT32 n = 27 - 15 - mqc->ct; + mqc->c <<= mqc->ct; + while (n > 0) { + mqc_byteout(mqc); + n -= mqc->ct; + mqc->c <<= mqc->ct; + } + mqc_byteout(mqc); + + return correction; +} + +void mqc_restart_init_enc(opj_mqc_t *mqc) { + /* */ + mqc_setcurctx(mqc, 0); + mqc->a = 0x8000; + mqc->c = 0; + mqc->ct = 12; + mqc->bp--; + if (*mqc->bp == 0xff) { + mqc->ct = 13; + } +} + +void mqc_erterm_enc(opj_mqc_t *mqc) { + OPJ_INT32 k = 11 - mqc->ct + 1; + + while (k > 0) { + mqc->c <<= mqc->ct; + mqc->ct = 0; + mqc_byteout(mqc); + k -= mqc->ct; + } + + if (*mqc->bp != 0xff) { + mqc_byteout(mqc); + } +} + +void mqc_segmark_enc(opj_mqc_t *mqc) { + OPJ_UINT32 i; + mqc_setcurctx(mqc, 18); + + for (i = 1; i < 5; i++) { + mqc_encode(mqc, i % 2); + } +} + +void mqc_init_dec(opj_mqc_t *mqc, OPJ_BYTE *bp, OPJ_UINT32 len) { + mqc_setcurctx(mqc, 0); + mqc->start = bp; + mqc->end = bp + len; + mqc->bp = bp; + if (len==0) mqc->c = 0xff << 16; + else mqc->c = *mqc->bp << 16; + mqc_bytein(mqc); + mqc->c <<= 7; + mqc->ct -= 7; + mqc->a = 0x8000; +} + +OPJ_UINT32 mqc_decode(opj_mqc_t *mqc) { + OPJ_INT32 d; + mqc->a -= (*mqc->curctx)->qeval; + if ((mqc->c >> 16) < (*mqc->curctx)->qeval) { + d = mqc_lpsexchange(mqc); + mqc_renormd(mqc); + } else { + mqc->c -= (*mqc->curctx)->qeval << 16; + if ((mqc->a & 0x8000) == 0) { + d = mqc_mpsexchange(mqc); + mqc_renormd(mqc); + } else { + d = (*mqc->curctx)->mps; + } + } + + return (OPJ_UINT32)d; +} + +void mqc_resetstates(opj_mqc_t *mqc) { + OPJ_UINT32 i; + for (i = 0; i < MQC_NUMCTXS; i++) { + mqc->ctxs[i] = mqc_states; + } +} + +void mqc_setstate(opj_mqc_t *mqc, OPJ_UINT32 ctxno, OPJ_UINT32 msb, OPJ_INT32 prob) { + mqc->ctxs[ctxno] = &mqc_states[msb + (prob << 1)]; +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/mqc.h b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/mqc.h new file mode 100644 index 0000000..0b64ba4 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/mqc.h @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MQC_H +#define __MQC_H +/** +@file mqc.h +@brief Implementation of an MQ-Coder (MQC) + +The functions in MQC.C have for goal to realize the MQ-coder operations. The functions +in MQC.C are used by some function in T1.C. +*/ +#include "openjpeg.h" +/** @defgroup MQC MQC - Implementation of an MQ-Coder */ +/*@{*/ + +/** +This struct defines the state of a context. +*/ +typedef struct opj_mqc_state { + /** the probability of the Least Probable Symbol (0.75->0x8000, 1.5->0xffff) */ + OPJ_UINT32 qeval; + /** the Most Probable Symbol (0 or 1) */ + OPJ_INT32 mps; + /** next state if the next encoded symbol is the MPS */ + struct opj_mqc_state *nmps; + /** next state if the next encoded symbol is the LPS */ + struct opj_mqc_state *nlps; +} opj_mqc_state_t; + +#define MQC_NUMCTXS 32 + +/** +MQ coder +*/ +typedef struct opj_mqc { + OPJ_UINT32 c; + OPJ_UINT32 a; + OPJ_UINT32 ct; + OPJ_BYTE *bp; + OPJ_BYTE *start; + OPJ_BYTE *end; + opj_mqc_state_t *ctxs[MQC_NUMCTXS]; + opj_mqc_state_t **curctx; +} opj_mqc_t; + +/** @name Exported functions */ +/*@{*/ +/* ----------------------------------------------------------------------- */ +/** +Create a new MQC handle +@return Returns a new MQC handle if successful, returns NULL otherwise +*/ +opj_mqc_t* mqc_create(void); +/** +Destroy a previously created MQC handle +@param mqc MQC handle to destroy +*/ +void mqc_destroy(opj_mqc_t *mqc); +/** +Return the number of bytes written/read since initialisation +@param mqc MQC handle +@return Returns the number of bytes already encoded +*/ +OPJ_UINT32 mqc_numbytes(opj_mqc_t *mqc); +/** +Reset the states of all the context of the coder/decoder +(each context is set to a state where 0 and 1 are more or less equiprobable) +@param mqc MQC handle +*/ +void mqc_resetstates(opj_mqc_t *mqc); +/** +Set the state of a particular context +@param mqc MQC handle +@param ctxno Number that identifies the context +@param msb The MSB of the new state of the context +@param prob Number that identifies the probability of the symbols for the new state of the context +*/ +void mqc_setstate(opj_mqc_t *mqc, OPJ_UINT32 ctxno, OPJ_UINT32 msb, OPJ_INT32 prob); +/** +Initialize the encoder +@param mqc MQC handle +@param bp Pointer to the start of the buffer where the bytes will be written +*/ +void mqc_init_enc(opj_mqc_t *mqc, OPJ_BYTE *bp); +/** +Set the current context used for coding/decoding +@param mqc MQC handle +@param ctxno Number that identifies the context +*/ +#define mqc_setcurctx(mqc, ctxno) (mqc)->curctx = &(mqc)->ctxs[(OPJ_UINT32)(ctxno)] +/** +Encode a symbol using the MQ-coder +@param mqc MQC handle +@param d The symbol to be encoded (0 or 1) +*/ +void mqc_encode(opj_mqc_t *mqc, OPJ_UINT32 d); +/** +Flush the encoder, so that all remaining data is written +@param mqc MQC handle +*/ +void mqc_flush(opj_mqc_t *mqc); +/** +BYPASS mode switch, initialization operation. +JPEG 2000 p 505. +

    Not fully implemented and tested !!

    +@param mqc MQC handle +*/ +void mqc_bypass_init_enc(opj_mqc_t *mqc); +/** +BYPASS mode switch, coding operation. +JPEG 2000 p 505. +

    Not fully implemented and tested !!

    +@param mqc MQC handle +@param d The symbol to be encoded (0 or 1) +*/ +void mqc_bypass_enc(opj_mqc_t *mqc, OPJ_UINT32 d); +/** +BYPASS mode switch, flush operation +

    Not fully implemented and tested !!

    +@param mqc MQC handle +@return Returns 1 (always) +*/ +OPJ_UINT32 mqc_bypass_flush_enc(opj_mqc_t *mqc); +/** +RESET mode switch +@param mqc MQC handle +*/ +void mqc_reset_enc(opj_mqc_t *mqc); +/** +RESTART mode switch (TERMALL) +@param mqc MQC handle +@return Returns 1 (always) +*/ +OPJ_UINT32 mqc_restart_enc(opj_mqc_t *mqc); +/** +RESTART mode switch (TERMALL) reinitialisation +@param mqc MQC handle +*/ +void mqc_restart_init_enc(opj_mqc_t *mqc); +/** +ERTERM mode switch (PTERM) +@param mqc MQC handle +*/ +void mqc_erterm_enc(opj_mqc_t *mqc); +/** +SEGMARK mode switch (SEGSYM) +@param mqc MQC handle +*/ +void mqc_segmark_enc(opj_mqc_t *mqc); +/** +Initialize the decoder +@param mqc MQC handle +@param bp Pointer to the start of the buffer from which the bytes will be read +@param len Length of the input buffer +*/ +void mqc_init_dec(opj_mqc_t *mqc, OPJ_BYTE *bp, OPJ_UINT32 len); +/** +Decode a symbol +@param mqc MQC handle +@return Returns the decoded symbol (0 or 1) +*/ +OPJ_UINT32 mqc_decode(opj_mqc_t *mqc); +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __MQC_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/openjpeg.c b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/openjpeg.c new file mode 100644 index 0000000..b9fb403 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/openjpeg.c @@ -0,0 +1,947 @@ +/* + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef WIN32 +#include +#endif /* WIN32 */ + +#include "openjpeg.h" +#include "opj_malloc.h" +#include "j2k.h" +#include "jp2.h" +#include "event.h" +#include "cio.h" + +typedef struct opj_decompression +{ + bool (* opj_read_header) ( + void *p_codec, + opj_image_t **, + OPJ_INT32 * p_tile_x0, + OPJ_INT32 * p_tile_y0, + OPJ_UINT32 * p_tile_width, + OPJ_UINT32 * p_tile_height, + OPJ_UINT32 * p_nb_tiles_x, + OPJ_UINT32 * p_nb_tiles_y, + struct opj_stream_private *cio, + struct opj_event_mgr * p_manager); + opj_image_t* (* opj_decode) (void * p_codec, struct opj_stream_private *p_cio, struct opj_event_mgr * p_manager); + bool (*opj_read_tile_header)( + void * p_codec, + OPJ_UINT32 * p_tile_index, + OPJ_UINT32* p_data_size, + OPJ_INT32 * p_tile_x0, + OPJ_INT32 * p_tile_y0, + OPJ_INT32 * p_tile_x1, + OPJ_INT32 * p_tile_y1, + OPJ_UINT32 * p_nb_comps, + bool * p_should_go_on, + struct opj_stream_private *p_cio, + struct opj_event_mgr * p_manager); + bool (*opj_decode_tile_data)(void * p_codec,OPJ_UINT32 p_tile_index,OPJ_BYTE * p_data,OPJ_UINT32 p_data_size,struct opj_stream_private *p_cio,struct opj_event_mgr * p_manager); + bool (* opj_end_decompress) (void *p_codec,struct opj_stream_private *cio,struct opj_event_mgr * p_manager); + void (* opj_destroy) (void * p_codec); + void (*opj_setup_decoder) (void * p_codec,opj_dparameters_t * p_param); + bool (*opj_set_decode_area) (void * p_codec,OPJ_INT32 p_start_x,OPJ_INT32 p_end_x,OPJ_INT32 p_start_y,OPJ_INT32 p_end_y,struct opj_event_mgr * p_manager); + + +}opj_decompression_t; + +typedef struct opj_compression +{ + bool (* opj_start_compress) (void *p_codec,struct opj_stream_private *cio,struct opj_image * p_image, struct opj_event_mgr * p_manager); + bool (* opj_encode) (void * p_codec, struct opj_stream_private *p_cio, struct opj_event_mgr * p_manager); + bool (* opj_write_tile) (void * p_codec,OPJ_UINT32 p_tile_index,OPJ_BYTE * p_data,OPJ_UINT32 p_data_size,struct opj_stream_private * p_cio,struct opj_event_mgr * p_manager); + bool (* opj_end_compress) (void * p_codec, struct opj_stream_private *p_cio, struct opj_event_mgr * p_manager); + void (* opj_destroy) (void * p_codec); + void (*opj_setup_encoder) (void * p_codec,opj_cparameters_t * p_param,struct opj_image * p_image, struct opj_event_mgr * p_manager); + +}opj_compression_t; + + + +typedef struct opj_codec_private +{ + union + { /* code-blocks informations */ + opj_decompression_t m_decompression; + opj_compression_t m_compression; + } m_codec_data; + void * m_codec; + opj_event_mgr_t m_event_mgr; + unsigned is_decompressor : 1; +} +opj_codec_private_t; + + + +/** + * Default callback function. + * Do nothing. + */ +void opj_default_callback (const char *msg, void *client_data) +{ +#if 0 + fprintf( stderr, msg ); + assert( 0 ); +#endif +} + +void set_default_event_handler(opj_event_mgr_t * p_manager) +{ + p_manager->m_error_data = 00; + p_manager->m_warning_data = 00; + p_manager->m_info_data = 00; + p_manager->error_handler = opj_default_callback; + p_manager->info_handler = opj_default_callback; + p_manager->warning_handler = opj_default_callback; +} + +OPJ_UINT32 opj_read_from_file (void * p_buffer, OPJ_UINT32 p_nb_bytes, FILE * p_file) +{ + OPJ_UINT32 l_nb_read = fread(p_buffer,1,p_nb_bytes,p_file); + return l_nb_read ? l_nb_read : -1; +} + +OPJ_UINT32 opj_write_from_file (void * p_buffer, OPJ_UINT32 p_nb_bytes, FILE * p_file) +{ + return fwrite(p_buffer,1,p_nb_bytes,p_file); +} + +OPJ_SIZE_T opj_skip_from_file (OPJ_SIZE_T p_nb_bytes, FILE * p_user_data) +{ + if + (fseek(p_user_data,p_nb_bytes,SEEK_CUR)) + { + return -1; + } + return p_nb_bytes; +} + +bool opj_seek_from_file (OPJ_SIZE_T p_nb_bytes, FILE * p_user_data) +{ + if + (fseek(p_user_data,p_nb_bytes,SEEK_SET)) + { + return false; + } + return true; +} + +/* ---------------------------------------------------------------------- */ +#ifdef WIN32 +#ifndef OPJ_STATIC +BOOL APIENTRY +DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { + switch (ul_reason_for_call) { + case DLL_PROCESS_ATTACH : + break; + case DLL_PROCESS_DETACH : + break; + case DLL_THREAD_ATTACH : + case DLL_THREAD_DETACH : + break; + } + + return TRUE; +} +#endif /* OPJ_STATIC */ +#endif /* WIN32 */ + +/* ---------------------------------------------------------------------- */ + + +const char* OPJ_CALLCONV opj_version(void) { + return OPENJPEG_VERSION; +} + +opj_codec_t* OPJ_CALLCONV opj_create_decompress(OPJ_CODEC_FORMAT p_format) +{ + opj_codec_private_t *l_info = 00; + + l_info = (opj_codec_private_t*) opj_calloc(1, sizeof(opj_codec_private_t)); + if + (!l_info) + { + return 00; + } + memset(l_info, 0, sizeof(opj_codec_private_t)); + l_info->is_decompressor = 1; + switch + (p_format) + { + case CODEC_J2K: + l_info->m_codec_data.m_decompression.opj_decode = (opj_image_t* (*) (void *, struct opj_stream_private *, struct opj_event_mgr * ))j2k_decode; + l_info->m_codec_data.m_decompression.opj_end_decompress = (bool (*) (void *,struct opj_stream_private *,struct opj_event_mgr *))j2k_end_decompress; + l_info->m_codec_data.m_decompression.opj_read_header = (bool (*) ( + void *, + opj_image_t **, + OPJ_INT32 * , + OPJ_INT32 * , + OPJ_UINT32 * , + OPJ_UINT32 * , + OPJ_UINT32 * , + OPJ_UINT32 * , + struct opj_stream_private *, + struct opj_event_mgr * )) j2k_read_header; + l_info->m_codec_data.m_decompression.opj_destroy = (void (*) (void *))j2k_destroy; + l_info->m_codec_data.m_decompression.opj_setup_decoder = (void (*) (void * ,opj_dparameters_t * )) j2k_setup_decoder; + l_info->m_codec_data.m_decompression.opj_read_tile_header = (bool (*) ( + void *, + OPJ_UINT32*, + OPJ_UINT32*, + OPJ_INT32 * , + OPJ_INT32 * , + OPJ_INT32 * , + OPJ_INT32 * , + OPJ_UINT32 * , + bool *, + struct opj_stream_private *, + struct opj_event_mgr * )) j2k_read_tile_header; + l_info->m_codec_data.m_decompression.opj_decode_tile_data = (bool (*) (void *,OPJ_UINT32,OPJ_BYTE*,OPJ_UINT32,struct opj_stream_private *, struct opj_event_mgr * )) j2k_decode_tile; + l_info->m_codec_data.m_decompression.opj_set_decode_area = (bool (*) (void *,OPJ_INT32,OPJ_INT32,OPJ_INT32,OPJ_INT32, struct opj_event_mgr * )) j2k_set_decode_area; + l_info->m_codec = j2k_create_decompress(); + if + (! l_info->m_codec) + { + opj_free(l_info); + return 00; + } + break; + + case CODEC_JP2: + /* get a JP2 decoder handle */ + l_info->m_codec_data.m_decompression.opj_decode = (opj_image_t* (*) (void *, struct opj_stream_private *, struct opj_event_mgr * ))jp2_decode; + l_info->m_codec_data.m_decompression.opj_end_decompress = (bool (*) (void *,struct opj_stream_private *,struct opj_event_mgr *)) jp2_end_decompress; + l_info->m_codec_data.m_decompression.opj_read_header = (bool (*) ( + void *, + opj_image_t **, + + OPJ_INT32 * , + OPJ_INT32 * , + OPJ_UINT32 * , + OPJ_UINT32 * , + OPJ_UINT32 * , + OPJ_UINT32 * , + struct opj_stream_private *, + struct opj_event_mgr * )) jp2_read_header; + + l_info->m_codec_data.m_decompression.opj_read_tile_header = ( + bool (*) ( + void *, + OPJ_UINT32*, + OPJ_UINT32*, + OPJ_INT32*, + OPJ_INT32*, + OPJ_INT32 * , + OPJ_INT32 * , + OPJ_UINT32 * , + bool *, + struct opj_stream_private *, + struct opj_event_mgr * )) jp2_read_tile_header; + + l_info->m_codec_data.m_decompression.opj_decode_tile_data = (bool (*) (void *,OPJ_UINT32,OPJ_BYTE*,OPJ_UINT32,struct opj_stream_private *, struct opj_event_mgr * )) jp2_decode_tile; + + l_info->m_codec_data.m_decompression.opj_destroy = (void (*) (void *))jp2_destroy; + l_info->m_codec_data.m_decompression.opj_setup_decoder = (void (*) (void * ,opj_dparameters_t * )) jp2_setup_decoder; + l_info->m_codec_data.m_decompression.opj_set_decode_area = (bool (*) (void *,OPJ_INT32,OPJ_INT32,OPJ_INT32,OPJ_INT32, struct opj_event_mgr * )) jp2_set_decode_area; + + + l_info->m_codec = jp2_create(true); + if + (! l_info->m_codec) + { + opj_free(l_info); + return 00; + } + break; + case CODEC_UNKNOWN: + case CODEC_JPT: + default: + opj_free(l_info); + return 00; + } + set_default_event_handler(&(l_info->m_event_mgr)); + return (opj_codec_t*) l_info; +} + +void OPJ_CALLCONV opj_destroy_codec(opj_codec_t *p_info) +{ + if + (p_info) + { + opj_codec_private_t * l_info = (opj_codec_private_t *) p_info; + if + (l_info->is_decompressor) + { + l_info->m_codec_data.m_decompression.opj_destroy(l_info->m_codec); + } + else + { + l_info->m_codec_data.m_compression.opj_destroy(l_info->m_codec); + } + l_info->m_codec = 00; + opj_free(l_info); + } +} + +void OPJ_CALLCONV opj_set_default_decoder_parameters(opj_dparameters_t *parameters) { + if(parameters) { + memset(parameters, 0, sizeof(opj_dparameters_t)); + /* default decoding parameters */ + parameters->cp_layer = 0; + parameters->cp_reduce = 0; + + parameters->decod_format = -1; + parameters->cod_format = -1; +/* UniPG>> */ +#ifdef USE_JPWL + parameters->jpwl_correct = false; + parameters->jpwl_exp_comps = JPWL_EXPECTED_COMPONENTS; + parameters->jpwl_max_tiles = JPWL_MAXIMUM_TILES; +#endif /* USE_JPWL */ +/* <is_decompressor) + { + return false; + } + l_info->m_codec_data.m_decompression.opj_setup_decoder(l_info->m_codec,parameters); + return true; + } + return false; +} + +opj_image_t* OPJ_CALLCONV opj_decode(opj_codec_t *p_info, opj_stream_t *cio) +{ + if + (p_info && cio) + { + opj_codec_private_t * l_info = (opj_codec_private_t *) p_info; + opj_stream_private_t * l_cio = (opj_stream_private_t *) cio; + if + (! l_info->is_decompressor) + { + return 00; + } + return l_info->m_codec_data.m_decompression.opj_decode(l_info->m_codec,l_cio,&(l_info->m_event_mgr)); + } + return 00; +} + +/** + * Writes a tile with the given data. + * + * @param p_compressor the jpeg2000 codec. + * @param p_tile_index the index of the tile to write. At the moment, the tiles must be written from 0 to n-1 in sequence. + * @param p_data pointer to the data to write. Data is arranged in sequence, data_comp0, then data_comp1, then ... NO INTERLEAVING should be set. + * @param p_data_size this value os used to make sure the data being written is correct. The size must be equal to the sum for each component of tile_width * tile_height * component_size. component_size can be 1,2 or 4 bytes, + * depending on the precision of the given component. + * @param p_stream the stream to write data to. + */ +bool OPJ_CALLCONV opj_write_tile ( + opj_codec_t *p_codec, + OPJ_UINT32 p_tile_index, + OPJ_BYTE * p_data, + OPJ_UINT32 p_data_size, + opj_stream_t *p_stream + ) +{ + if + (p_codec && p_stream && p_data) + { + opj_codec_private_t * l_info = (opj_codec_private_t *) p_codec; + opj_stream_private_t * l_cio = (opj_stream_private_t *) p_stream; + if + (l_info->is_decompressor) + { + return false; + } + return l_info->m_codec_data.m_compression.opj_write_tile(l_info->m_codec,p_tile_index,p_data,p_data_size,l_cio,&(l_info->m_event_mgr)); + } + return false; +} + +/** + * Reads a tile header. This function is compulsory and allows one to know the size of the tile thta will be decoded. + * The user may need to refer to the image got by opj_read_header to understand the size being taken by the tile. + * + * @param p_codec the jpeg2000 codec. + * @param p_tile_index pointer to a value that will hold the index of the tile being decoded, in case of success. + * @param p_data_size pointer to a value that will hold the maximum size of the decoded data, in case of success. In case + * of truncated codestreams, the actual number of bytes decoded may be lower. The computation of the size is the same + * as depicted in opj_write_tile. + * @param p_tile_x0 pointer to a value that will hold the x0 pos of the tile (in the image). + * @param p_tile_y0 pointer to a value that will hold the y0 pos of the tile (in the image). + * @param p_tile_x1 pointer to a value that will hold the x1 pos of the tile (in the image). + * @param p_tile_y1 pointer to a value that will hold the y1 pos of the tile (in the image). + * @param p_nb_comps pointer to a value that will hold the number of components in the tile. + * @param p_should_go_on pointer to a boolean that will hold the fact that the decoding should go on. In case the + * codestream is over at the time of the call, the value will be set to false. The user should then stop + * the decoding. + * @param p_stream the stream to decode. + * @return true if the tile header could be decoded. In case the decoding should end, the returned value is still true. + * returning false may be the result of a shortage of memory or an internal error. + */ +bool OPJ_CALLCONV opj_read_tile_header( + opj_codec_t *p_codec, + OPJ_UINT32 * p_tile_index, + OPJ_UINT32 * p_data_size, + OPJ_INT32 * p_tile_x0, + OPJ_INT32 * p_tile_y0, + OPJ_INT32 * p_tile_x1, + OPJ_INT32 * p_tile_y1, + OPJ_UINT32 * p_nb_comps, + bool * p_should_go_on, + opj_stream_t * p_stream) +{ + if + (p_codec && p_stream && p_data_size && p_tile_index) + { + opj_codec_private_t * l_info = (opj_codec_private_t *) p_codec; + opj_stream_private_t * l_cio = (opj_stream_private_t *) p_stream; + if + (! l_info->is_decompressor) + { + return false; + } + return l_info->m_codec_data.m_decompression.opj_read_tile_header( + l_info->m_codec, + p_tile_index, + p_data_size, + p_tile_x0, + p_tile_y0, + p_tile_x1, + p_tile_y1, + p_nb_comps, + p_should_go_on, + l_cio,&(l_info->m_event_mgr)); + } + return false; +} + +/** + * Reads a tile data. This function is compulsory and allows one to decode tile data. opj_read_tile_header should be called before. + * The user may need to refer to the image got by opj_read_header to understand the size being taken by the tile. + * + * @param p_codec the jpeg2000 codec. + * @param p_tile_index the index of the tile being decoded, this should be the value set by opj_read_tile_header. + * @param p_data pointer to a memory block that will hold the decoded data. + * @param p_data_size size of p_data. p_data_size should be bigger or equal to the value set by opj_read_tile_header. + * @param p_stream the stream to decode. + * + * @return true if the data could be decoded. + */ +bool OPJ_CALLCONV opj_decode_tile_data( + opj_codec_t *p_codec, + OPJ_UINT32 p_tile_index, + OPJ_BYTE * p_data, + OPJ_UINT32 p_data_size, + opj_stream_t *p_stream + ) +{ + if + (p_codec && p_data && p_stream) + { + opj_codec_private_t * l_info = (opj_codec_private_t *) p_codec; + opj_stream_private_t * l_cio = (opj_stream_private_t *) p_stream; + if + (! l_info->is_decompressor) + { + return false; + } + return l_info->m_codec_data.m_decompression.opj_decode_tile_data(l_info->m_codec,p_tile_index,p_data,p_data_size,l_cio,&(l_info->m_event_mgr)); + } + return false; +} + +bool OPJ_CALLCONV opj_read_header ( + opj_codec_t *p_codec, + opj_image_t ** p_image, + OPJ_INT32 * p_tile_x0, + OPJ_INT32 * p_tile_y0, + OPJ_UINT32 * p_tile_width, + OPJ_UINT32 * p_tile_height, + OPJ_UINT32 * p_nb_tiles_x, + OPJ_UINT32 * p_nb_tiles_y, + opj_stream_t *p_cio) +{ + if + (p_codec && p_cio) + { + opj_codec_private_t * l_info = (opj_codec_private_t *) p_codec; + opj_stream_private_t * l_cio = (opj_stream_private_t *) p_cio; + if + (! l_info->is_decompressor) + { + return false; + } + return l_info->m_codec_data.m_decompression.opj_read_header( + l_info->m_codec, + p_image, + p_tile_x0, + p_tile_y0, + p_tile_width, + p_tile_height, + p_nb_tiles_x, + p_nb_tiles_y, + l_cio, + &(l_info->m_event_mgr)); + } + return false; +} + +/** + * Sets the given area to be decoded. This function should be called right after opj_read_header and before any tile header reading. + * + * @param p_codec the jpeg2000 codec. + * @param p_start_x the left position of the rectangle to decode (in image coordinates). + * @param p_end_x the right position of the rectangle to decode (in image coordinates). + * @param p_start_y the up position of the rectangle to decode (in image coordinates). + * @param p_end_y the bottom position of the rectangle to decode (in image coordinates). + * + * @return true if the area could be set. + */ +bool OPJ_CALLCONV opj_set_decode_area( + opj_codec_t *p_codec, + OPJ_INT32 p_start_x, + OPJ_INT32 p_start_y, + OPJ_INT32 p_end_x, + OPJ_INT32 p_end_y + ) +{ + if + (p_codec) + { + opj_codec_private_t * l_info = (opj_codec_private_t *) p_codec; + if + (! l_info->is_decompressor) + { + return false; + } + return l_info->m_codec_data.m_decompression.opj_set_decode_area( + l_info->m_codec, + p_start_x, + p_start_y, + p_end_x, + p_end_y, + &(l_info->m_event_mgr)); + + } + return false; + +} + +bool OPJ_CALLCONV opj_end_decompress (opj_codec_t *p_codec,opj_stream_t *p_cio) +{ + if + (p_codec && p_cio) + { + opj_codec_private_t * l_info = (opj_codec_private_t *) p_codec; + opj_stream_private_t * l_cio = (opj_stream_private_t *) p_cio; + if + (! l_info->is_decompressor) + { + return false; + } + return l_info->m_codec_data.m_decompression.opj_end_decompress(l_info->m_codec,l_cio,&(l_info->m_event_mgr)); + } + return false; +} + + +opj_codec_t* OPJ_CALLCONV opj_create_compress(OPJ_CODEC_FORMAT p_format) +{ + opj_codec_private_t *l_info = 00; + + l_info = (opj_codec_private_t*)opj_calloc(1, sizeof(opj_codec_private_t)); + if + (!l_info) + { + return 00; + } + memset(l_info, 0, sizeof(opj_codec_private_t)); + l_info->is_decompressor = 0; + switch + (p_format) + { + case CODEC_J2K: + l_info->m_codec_data.m_compression.opj_encode = (bool (*) (void *, struct opj_stream_private *, struct opj_event_mgr * )) j2k_encode; + l_info->m_codec_data.m_compression.opj_end_compress = (bool (*) (void *, struct opj_stream_private *, struct opj_event_mgr *)) j2k_end_compress; + l_info->m_codec_data.m_compression.opj_start_compress = (bool (*) (void *,struct opj_stream_private *,struct opj_image * , struct opj_event_mgr *)) j2k_start_compress; + l_info->m_codec_data.m_compression.opj_write_tile = (bool (*) (void *,OPJ_UINT32,OPJ_BYTE*,OPJ_UINT32,struct opj_stream_private *, struct opj_event_mgr *)) j2k_write_tile; + l_info->m_codec_data.m_compression.opj_destroy = (void (*) (void *)) j2k_destroy; + l_info->m_codec_data.m_compression.opj_setup_encoder = (void (*) (void *,opj_cparameters_t *,struct opj_image *, struct opj_event_mgr * )) j2k_setup_encoder; + + l_info->m_codec = j2k_create_compress(); + if + (! l_info->m_codec) + { + opj_free(l_info); + return 00; + } + break; + + case CODEC_JP2: + /* get a JP2 decoder handle */ + l_info->m_codec_data.m_compression.opj_encode = (bool (*) (void *, struct opj_stream_private *, struct opj_event_mgr * )) jp2_encode; + l_info->m_codec_data.m_compression.opj_end_compress = (bool (*) (void *, struct opj_stream_private *, struct opj_event_mgr *)) jp2_end_compress; + l_info->m_codec_data.m_compression.opj_start_compress = (bool (*) (void *,struct opj_stream_private *,struct opj_image * , struct opj_event_mgr *)) jp2_start_compress; + l_info->m_codec_data.m_compression.opj_write_tile = (bool (*) (void *,OPJ_UINT32,OPJ_BYTE*,OPJ_UINT32,struct opj_stream_private *, struct opj_event_mgr *)) jp2_write_tile; + l_info->m_codec_data.m_compression.opj_destroy = (void (*) (void *)) jp2_destroy; + l_info->m_codec_data.m_compression.opj_setup_encoder = (void (*) (void *,opj_cparameters_t *,struct opj_image *, struct opj_event_mgr * )) jp2_setup_encoder; + + l_info->m_codec = jp2_create(false); + if + (! l_info->m_codec) + { + opj_free(l_info); + return 00; + } + break; + case CODEC_UNKNOWN: + case CODEC_JPT: + default: + opj_free(l_info); + return 00; + } + set_default_event_handler(&(l_info->m_event_mgr)); + return (opj_codec_t*) l_info; +} + +void OPJ_CALLCONV opj_set_default_encoder_parameters(opj_cparameters_t *parameters) { + if(parameters) { + memset(parameters, 0, sizeof(opj_cparameters_t)); + /* default coding parameters */ + parameters->cp_cinema = OFF; + parameters->max_comp_size = 0; + parameters->numresolution = 6; + parameters->cp_rsiz = STD_RSIZ; + parameters->cblockw_init = 64; + parameters->cblockh_init = 64; + parameters->prog_order = LRCP; + parameters->roi_compno = -1; /* no ROI */ + parameters->subsampling_dx = 1; + parameters->subsampling_dy = 1; + parameters->tp_on = 0; + parameters->decod_format = -1; + parameters->cod_format = -1; + parameters->tcp_rates[0] = 0; + parameters->tcp_numlayers = 0; + parameters->cp_disto_alloc = 0; + parameters->cp_fixed_alloc = 0; + parameters->cp_fixed_quality = 0; +/* UniPG>> */ +#ifdef USE_JPWL + parameters->jpwl_epc_on = false; + parameters->jpwl_hprot_MH = -1; /* -1 means unassigned */ + { + int i; + for (i = 0; i < JPWL_MAX_NO_TILESPECS; i++) { + parameters->jpwl_hprot_TPH_tileno[i] = -1; /* unassigned */ + parameters->jpwl_hprot_TPH[i] = 0; /* absent */ + } + }; + { + int i; + for (i = 0; i < JPWL_MAX_NO_PACKSPECS; i++) { + parameters->jpwl_pprot_tileno[i] = -1; /* unassigned */ + parameters->jpwl_pprot_packno[i] = -1; /* unassigned */ + parameters->jpwl_pprot[i] = 0; /* absent */ + } + }; + parameters->jpwl_sens_size = 0; /* 0 means no ESD */ + parameters->jpwl_sens_addr = 0; /* 0 means auto */ + parameters->jpwl_sens_range = 0; /* 0 means packet */ + parameters->jpwl_sens_MH = -1; /* -1 means unassigned */ + { + int i; + for (i = 0; i < JPWL_MAX_NO_TILESPECS; i++) { + parameters->jpwl_sens_TPH_tileno[i] = -1; /* unassigned */ + parameters->jpwl_sens_TPH[i] = -1; /* absent */ + } + }; +#endif /* USE_JPWL */ +/* <is_decompressor) + { + l_codec->m_codec_data.m_compression.opj_setup_encoder(l_codec->m_codec,parameters,image,&(l_codec->m_event_mgr)); + return true; + } + } + return false; +} + +bool OPJ_CALLCONV opj_encode(opj_codec_t *p_info, opj_stream_t *cio) +{ + if + (p_info && cio) + { + opj_codec_private_t * l_codec = (opj_codec_private_t *) p_info; + opj_stream_private_t * l_cio = (opj_stream_private_t *) cio; + if + (! l_codec->is_decompressor) + { + l_codec->m_codec_data.m_compression.opj_encode(l_codec->m_codec,l_cio,&(l_codec->m_event_mgr)); + return true; + } + } + return false; + +} + +bool OPJ_CALLCONV opj_start_compress (opj_codec_t *p_codec,opj_image_t * p_image,opj_stream_t *p_cio) +{ + if + (p_codec && p_cio) + { + opj_codec_private_t * l_codec = (opj_codec_private_t *) p_codec; + opj_stream_private_t * l_cio = (opj_stream_private_t *) p_cio; + if + (! l_codec->is_decompressor) + { + return l_codec->m_codec_data.m_compression.opj_start_compress(l_codec->m_codec,l_cio,p_image,&(l_codec->m_event_mgr)); + } + } + return false; +} + +bool OPJ_CALLCONV opj_end_compress (opj_codec_t *p_codec,opj_stream_t *p_cio) +{ + if + (p_codec && p_cio) + { + opj_codec_private_t * l_codec = (opj_codec_private_t *) p_codec; + opj_stream_private_t * l_cio = (opj_stream_private_t *) p_cio; + if + (! l_codec->is_decompressor) + { + return l_codec->m_codec_data.m_compression.opj_end_compress(l_codec->m_codec,l_cio,&(l_codec->m_event_mgr)); + } + } + return false; + +} + +bool OPJ_CALLCONV opj_set_info_handler(opj_codec_t * p_codec, opj_msg_callback p_callback,void * p_user_data) +{ + opj_codec_private_t * l_codec = (opj_codec_private_t *) p_codec; + if + (! l_codec) + { + return false; + } + l_codec->m_event_mgr.info_handler = p_callback; + l_codec->m_event_mgr.m_info_data = p_user_data; + return true; +} + +bool OPJ_CALLCONV opj_set_warning_handler(opj_codec_t * p_codec, opj_msg_callback p_callback,void * p_user_data) +{ + opj_codec_private_t * l_codec = (opj_codec_private_t *) p_codec; + if + (! l_codec) + { + return false; + } + l_codec->m_event_mgr.warning_handler = p_callback; + l_codec->m_event_mgr.m_warning_data = p_user_data; + return true; +} + +bool OPJ_CALLCONV opj_set_error_handler(opj_codec_t * p_codec, opj_msg_callback p_callback,void * p_user_data) +{ + opj_codec_private_t * l_codec = (opj_codec_private_t *) p_codec; + if + (! l_codec) + { + return false; + } + l_codec->m_event_mgr.error_handler = p_callback; + l_codec->m_event_mgr.m_error_data = p_user_data; + return true; +} + +/*bool OPJ_CALLCONV opj_encode_with_info(opj_cinfo_t *cinfo, opj_stream_t *cio, opj_image_t *image, opj_codestream_info_t *cstr_info) { + if(cinfo && cio && image) { + switch(cinfo->codec_format) { + case CODEC_J2K: + return j2k_encode((opj_j2k_t*)cinfo->j2k_handle, (opj_stream_private_t *) cio, image, cstr_info); + case CODEC_JP2: + return jp2_encode((opj_jp2_t*)cinfo->jp2_handle, (opj_stream_private_t *) cio, image, cstr_info); + case CODEC_JPT: + case CODEC_UNKNOWN: + default: + break; + } + } + return false; +}*/ + +void OPJ_CALLCONV opj_destroy_cstr_info(opj_codestream_info_t *cstr_info) { + if + (cstr_info) + { + int tileno; + for (tileno = 0; tileno < cstr_info->tw * cstr_info->th; tileno++) { + opj_tile_info_t *tile_info = &cstr_info->tile[tileno]; + opj_free(tile_info->thresh); + opj_free(tile_info->packet); + opj_free(tile_info->tp); + } + opj_free(cstr_info->tile); + opj_free(cstr_info->marker); + } +} + +bool OPJ_CALLCONV opj_set_MCT(opj_cparameters_t *parameters,OPJ_FLOAT32 * pEncodingMatrix,OPJ_INT32 * p_dc_shift,OPJ_UINT32 pNbComp) +{ + OPJ_UINT32 l_matrix_size = pNbComp * pNbComp * sizeof(OPJ_FLOAT32); + OPJ_UINT32 l_dc_shift_size = pNbComp * sizeof(OPJ_INT32); + OPJ_UINT32 l_mct_total_size = l_matrix_size + l_dc_shift_size; + // add MCT capability + int rsiz = (int)parameters->cp_rsiz | (int)MCT; + parameters->cp_rsiz = (OPJ_RSIZ_CAPABILITIES)rsiz; + parameters->irreversible = 1; + // use array based MCT + parameters->tcp_mct = 2; + parameters->mct_data = opj_malloc(l_mct_total_size); + if + (! parameters->mct_data) + { + return false; + } + memcpy(parameters->mct_data,pEncodingMatrix,l_matrix_size); + memcpy(((OPJ_BYTE *) parameters->mct_data) + l_matrix_size,p_dc_shift,l_dc_shift_size); + return true; +} + +/** + * Restricts the decoding to the given image area. + * + * @param parameters the parameters to update. + * @param p_start_x the starting x position of the area to decode. + * @param p_start_y the starting y position of the area to decode. + * @param p_end_x the x end position of the area to decode. + * @param p_end_x the y end position of the area to decode. + */ +OPJ_API bool OPJ_CALLCONV opj_restrict_decoding (opj_dparameters_t *parameters,OPJ_INT32 p_start_x,OPJ_INT32 p_start_y,OPJ_INT32 p_end_x,OPJ_INT32 p_end_y) +{ + parameters->m_use_restrict_decode = 1; + parameters->m_decode_start_x = p_start_x; + parameters->m_decode_start_y = p_start_y; + parameters->m_decode_end_x = p_end_x; + parameters->m_decode_end_y = p_end_y; + return true; +} + +int j2k_get_reversible( + opj_j2k_t * p_j2k) +{ + opj_cp_t *cp = 00; + cp = &(p_j2k->m_cp); + return cp->tcps->tccps->qmfbid; +} +int jp2_get_reversible( + opj_jp2_t * p_jp2) +{ + return j2k_get_reversible(p_jp2->j2k); +} + +int OPJ_CALLCONV opj_get_reversible(opj_codec_t *p_info, opj_dparameters_t *parameters) +{ + int ret = -1; + if (p_info) + { + opj_codec_private_t * l_info = (opj_codec_private_t *) p_info; + if (l_info->is_decompressor) + { + switch(parameters->decod_format) + { + case 0: // J2K_CFMT: + ret = j2k_get_reversible(l_info->m_codec); + break; + case 1: // JP2_CFMT: + ret = jp2_get_reversible(l_info->m_codec); + break; + } + } + } + return ret; +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/openjpeg.h b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/openjpeg.h new file mode 100644 index 0000000..74fefe3 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/openjpeg.h @@ -0,0 +1,1072 @@ + /* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2006-2007, Parvatha Elangovan + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef OPENJPEG_H +#define OPENJPEG_H + +#if defined(OPJ_STATIC) || (!defined(WIN32) && !defined(__MINGW32__)) || defined(__WIN32__) + #define OPJ_API + #define OPJ_CALLCONV +#else + #define OPJ_CALLCONV __stdcall + #ifdef OPJ_EXPORTS + #define OPJ_API __declspec(dllexport) + #else + #define OPJ_API __declspec(dllimport) + #endif /* OPJ_EXPORTS */ +#endif /* !OPJ_STATIC || !WIN32 */ + +#ifndef __cplusplus + #if defined(HAVE_STDBOOL_H) + #include + #else + #if !defined(bool) + #define bool int + #endif + #if !defined(true) + #define true 1 + #endif + #if !defined(false) + #define false 0 + #endif + #endif +#endif /* __cplusplus */ +typedef unsigned int OPJ_UINT32; +typedef int OPJ_INT32; +typedef unsigned short OPJ_UINT16; +typedef short OPJ_INT16; +typedef char OPJ_CHAR; +typedef unsigned char OPJ_BYTE; +typedef unsigned int OPJ_SIZE_T; +typedef double OPJ_FLOAT64; +typedef float OPJ_FLOAT32; +#if defined(_MSC_VER) || defined(__BORLANDC__) + typedef __int64 OPJ_INT64; +#else + typedef long long OPJ_INT64; +#endif + +#define OPENJPEG_VERSION "2.0.0" +#include "openjpeg_mangle.h" +/* +========================================================== + Compiler directives +========================================================== +*/ +#include + + + + + +/* +========================================================== + Useful constant definitions +========================================================== +*/ + +#define OPJ_PATH_LEN 4096 /**< Maximum allowed size for filenames */ +#define J2K_MAXRLVLS 33 /**< Number of maximum resolution level authorized */ +#define J2K_MAXBANDS (3*J2K_MAXRLVLS-2) /**< Number of maximum sub-band linked to number of resolution level */ +#define J2K_DEFAULT_NB_SEGS 10 +#define J2K_STREAM_CHUNK_SIZE 0x100000 /** 1 mega by default */ +#define J2K_DEFAULT_HEADER_SIZE 1000 +#define J2K_MCC_DEFAULT_NB_RECORDS 10 +#define J2K_MCT_DEFAULT_NB_RECORDS 10 + +/* UniPG>> */ +#define JPWL_MAX_NO_TILESPECS 16 /**< Maximum number of tile parts expected by JPWL: increase at your will */ +#define JPWL_MAX_NO_PACKSPECS 16 /**< Maximum number of packet parts expected by JPWL: increase at your will */ +#define JPWL_MAX_NO_MARKERS 512 /**< Maximum number of JPWL markers: increase at your will */ +#define JPWL_PRIVATEINDEX_NAME "jpwl_index_privatefilename" /**< index file name used when JPWL is on */ +#define JPWL_EXPECTED_COMPONENTS 3 /**< Expect this number of components, so you'll find better the first EPB */ +#define JPWL_MAXIMUM_TILES 8192 /**< Expect this maximum number of tiles, to avoid some crashes */ +#define JPWL_MAXIMUM_HAMMING 2 /**< Expect this maximum number of bit errors in marker id's */ +#define JPWL_MAXIMUM_EPB_ROOM 65450 /**< Expect this maximum number of bytes for composition of EPBs */ +/* <> */ + /**@name JPWL encoding parameters */ + /*@{*/ + /** enables writing of EPC in MH, thus activating JPWL */ + bool jpwl_epc_on; + /** error protection method for MH (0,1,16,32,37-128) */ + int jpwl_hprot_MH; + /** tile number of header protection specification (>=0) */ + int jpwl_hprot_TPH_tileno[JPWL_MAX_NO_TILESPECS]; + /** error protection methods for TPHs (0,1,16,32,37-128) */ + int jpwl_hprot_TPH[JPWL_MAX_NO_TILESPECS]; + /** tile number of packet protection specification (>=0) */ + int jpwl_pprot_tileno[JPWL_MAX_NO_PACKSPECS]; + /** packet number of packet protection specification (>=0) */ + int jpwl_pprot_packno[JPWL_MAX_NO_PACKSPECS]; + /** error protection methods for packets (0,1,16,32,37-128) */ + int jpwl_pprot[JPWL_MAX_NO_PACKSPECS]; + /** enables writing of ESD, (0=no/1/2 bytes) */ + int jpwl_sens_size; + /** sensitivity addressing size (0=auto/2/4 bytes) */ + int jpwl_sens_addr; + /** sensitivity range (0-3) */ + int jpwl_sens_range; + /** sensitivity method for MH (-1=no,0-7) */ + int jpwl_sens_MH; + /** tile number of sensitivity specification (>=0) */ + int jpwl_sens_TPH_tileno[JPWL_MAX_NO_TILESPECS]; + /** sensitivity methods for TPHs (-1=no,0-7) */ + int jpwl_sens_TPH[JPWL_MAX_NO_TILESPECS]; + /*@}*/ +/* <> */ + /**@name JPWL decoding parameters */ + /*@{*/ + /** activates the JPWL correction capabilities */ + bool jpwl_correct; + /** expected number of components */ + int jpwl_exp_comps; + /** maximum number of tiles */ + int jpwl_max_tiles; + + /** use restrictive decoding ? */ + OPJ_UINT32 m_use_restrict_decode : 1; + /*@}*/ +/* <> */ +/** +Marker structure +*/ +typedef struct opj_marker_info_t { + /** marker type */ + unsigned short int type; + /** position in codestream */ + int pos; + /** length, marker val included */ + int len; +} opj_marker_info_t; +/* <> */ + /** number of markers */ + int marknum; + /** list of markers */ + opj_marker_info_t *marker; + /** actual size of markers array */ + int maxmarknum; +/* <cp. +@param dinfo decompressor handle +@param parameters decompression parameters +*/ +OPJ_API bool OPJ_CALLCONV opj_setup_decoder(opj_codec_t *dinfo, opj_dparameters_t *parameters); +#endif + +/** +Decode an image from a JPEG-2000 codestream +@param dinfo decompressor handle +@param cio Input buffer stream +@return Returns a decoded image if successful, returns NULL otherwise +*/ +OPJ_API opj_image_t* OPJ_CALLCONV opj_decode(opj_codec_t *p_decompressor, opj_stream_t * cio); + +OPJ_API int OPJ_CALLCONV opj_get_reversible(opj_codec_t *p_decompressor, opj_dparameters_t *parameters); + +/** + * Writes a tile with the given data. + * + * @param p_compressor the jpeg2000 codec. + * @param p_tile_index the index of the tile to write. At the moment, the tiles must be written from 0 to n-1 in sequence. + * @param p_data pointer to the data to write. Data is arranged in sequence, data_comp0, then data_comp1, then ... NO INTERLEAVING should be set. + * @param p_data_size this value os used to make sure the data being written is correct. The size must be equal to the sum for each component of tile_width * tile_height * component_size. component_size can be 1,2 or 4 bytes, + * depending on the precision of the given component. + * @param p_stream the stream to write data to. + * + * @return true if the data could be written. + */ +OPJ_API bool OPJ_CALLCONV opj_write_tile ( + opj_codec_t *p_codec, + OPJ_UINT32 p_tile_index, + OPJ_BYTE * p_data, + OPJ_UINT32 p_data_size, + opj_stream_t *p_stream + ); + +/** + * Reads a tile header. This function is compulsory and allows one to know the size of the tile thta will be decoded. + * The user may need to refer to the image got by opj_read_header to understand the size being taken by the tile. + * + * @param p_codec the jpeg2000 codec. + * @param p_tile_index pointer to a value that will hold the index of the tile being decoded, in case of success. + * @param p_data_size pointer to a value that will hold the maximum size of the decoded data, in case of success. In case + * of truncated codestreams, the actual number of bytes decoded may be lower. The computation of the size is the same + * as depicted in opj_write_tile. + * @param p_tile_x0 pointer to a value that will hold the x0 pos of the tile (in the image). + * @param p_tile_y0 pointer to a value that will hold the y0 pos of the tile (in the image). + * @param p_tile_x1 pointer to a value that will hold the x1 pos of the tile (in the image). + * @param p_tile_y1 pointer to a value that will hold the y1 pos of the tile (in the image). + * @param p_nb_comps pointer to a value that will hold the number of components in the tile. + * @param p_should_go_on pointer to a boolean that will hold the fact that the decoding should go on. In case the + * codestream is over at the time of the call, the value will be set to false. The user should then stop + * the decoding. + * @param p_stream the stream to decode. + * @return true if the tile header could be decoded. In case the decoding should end, the returned value is still true. + * returning false may be the result of a shortage of memory or an internal error. + */ +OPJ_API bool OPJ_CALLCONV opj_read_tile_header( + opj_codec_t *p_codec, + OPJ_UINT32 * p_tile_index, + OPJ_UINT32 * p_data_size, + OPJ_INT32 * p_tile_x0, + OPJ_INT32 * p_tile_y0, + OPJ_INT32 * p_tile_x1, + OPJ_INT32 * p_tile_y1, + OPJ_UINT32 * p_nb_comps, + bool * p_should_go_on, + opj_stream_t * p_stream); + + +/** + * Reads a tile data. This function is compulsory and allows one to decode tile data. opj_read_tile_header should be called before. + * The user may need to refer to the image got by opj_read_header to understand the size being taken by the tile. + * + * @param p_codec the jpeg2000 codec. + * @param p_tile_index the index of the tile being decoded, this should be the value set by opj_read_tile_header. + * @param p_data pointer to a memory block that will hold the decoded data. + * @param p_data_size size of p_data. p_data_size should be bigger or equal to the value set by opj_read_tile_header. + * @param p_stream the stream to decode. + * + * @return true if the data could be decoded. + */ +OPJ_API bool OPJ_CALLCONV opj_decode_tile_data( + opj_codec_t *p_codec, + OPJ_UINT32 p_tile_index, + OPJ_BYTE * p_data, + OPJ_UINT32 p_data_size, + opj_stream_t *p_stream + ); + +/** + * Sets the given area to be decoded. This function should be called right after opj_read_header and before any tile header reading. + * + * @param p_codec the jpeg2000 codec. + * @param p_start_x the left position of the rectangle to decode (in image coordinates). + * @param p_end_x the right position of the rectangle to decode (in image coordinates). + * @param p_start_y the up position of the rectangle to decode (in image coordinates). + * @param p_end_y the bottom position of the rectangle to decode (in image coordinates). + * + * @return true if the area could be set. + */ +OPJ_API bool OPJ_CALLCONV opj_set_decode_area( + opj_codec_t *p_codec, + OPJ_INT32 p_start_x, + OPJ_INT32 p_start_y, + OPJ_INT32 p_end_x, + OPJ_INT32 p_end_y + ); + + +/** +Decode an image from a JPEG-2000 codestream and extract the codestream information +@param dinfo decompressor handle +@param cio Input buffer stream +@param cstr_info Codestream information structure if needed afterwards, NULL otherwise +@return Returns a decoded image if successful, returns NULL otherwise +*/ +//OPJ_API opj_image_t* OPJ_CALLCONV opj_decode_with_info(opj_dinfo_t *dinfo, opj_stream_t cio, opj_codestream_info_t *cstr_info); +/** +Creates a J2K/JP2 compression structure +@param format Coder to select +@return Returns a handle to a compressor if successful, returns NULL otherwise +*/ +OPJ_API opj_codec_t* OPJ_CALLCONV opj_create_compress(OPJ_CODEC_FORMAT format); + +/** +Destroy a decompressor handle +@param dinfo decompressor handle to destroy +*/ +OPJ_API void OPJ_CALLCONV opj_destroy_codec(opj_codec_t * p_codec); + +/** +Set encoding parameters to default values, that means : +
      +
    • Lossless +
    • 1 tile +
    • Size of precinct : 2^15 x 2^15 (means 1 precinct) +
    • Size of code-block : 64 x 64 +
    • Number of resolutions: 6 +
    • No SOP marker in the codestream +
    • No EPH marker in the codestream +
    • No sub-sampling in x or y direction +
    • No mode switch activated +
    • Progression order: LRCP +
    • No index file +
    • No ROI upshifted +
    • No offset of the origin of the image +
    • No offset of the origin of the tiles +
    • Reversible DWT 5-3 +
    +@param parameters Compression parameters +*/ +OPJ_API void OPJ_CALLCONV opj_set_default_encoder_parameters(opj_cparameters_t *parameters); + +/** + * Sets the MCT matrix to use. + * + * @param parameters the parameters to change. + * @param pEncodingMatrix the encoding matrix. + * @param p_dc_shift the dc shift coefficients to use. + * @param pNbComp the number of components of the image. + * + * @return true if the parameters could be set. + */ +OPJ_API bool OPJ_CALLCONV opj_set_MCT(opj_cparameters_t *parameters,OPJ_FLOAT32 * pEncodingMatrix,OPJ_INT32 * p_dc_shift,OPJ_UINT32 pNbComp); + +/** + * Restricts the decoding to the given image area. + * + * @param parameters the parameters to update. + * @param p_start_x the starting x position of the area to decode. + * @param p_start_y the starting y position of the area to decode. + * @param p_end_x the x end position of the area to decode. + * @param p_end_x the y end position of the area to decode. + */ +OPJ_API bool OPJ_CALLCONV opj_restrict_decoding (opj_dparameters_t *parameters,OPJ_INT32 p_start_x,OPJ_INT32 p_start_y,OPJ_INT32 p_end_x,OPJ_INT32 p_end_y); + +#ifdef USE_OPJ_DEPRECATED +/** +Setup the encoder parameters using the current image and using user parameters. +@param cinfo Compressor handle +@param parameters Compression parameters +@param image Input filled image +*/ +OPJ_API bool OPJ_CALLCONV opj_setup_encoder(opj_codec_t *cinfo, opj_cparameters_t *parameters, opj_image_t *image); +#endif + +/** + * Decodes an image header. + * + * @param p_codec codec to use to decode the image. + * @param p_image pointer to a previously created image. + * @param p_tile_x0 pointer to a value that will hold the reference point x0 of the tiling grid. + * @param p_tile_y0 pointer to a value that will hold the reference point y0 of the tiling grid. + * @param p_tile_width pointer to a value that will hold the size in x of a tile in the grid. + * @param p_tile_height pointer to a value that will hold the size in y of a tile in the grid. + * @param p_nb_tiles_x pointer to a value that will hold the number of tiles in the x direction. + * @param p_nb_tiles_y pointer to a value that will hold the number of tiles in the y direction. + */ +OPJ_API bool OPJ_CALLCONV opj_read_header ( + opj_codec_t *p_codec, + opj_image_t ** p_image, + OPJ_INT32 * p_tile_x0, + OPJ_INT32 * p_tile_y0, + OPJ_UINT32 * p_tile_width, + OPJ_UINT32 * p_tile_height, + OPJ_UINT32 * p_nb_tiles_x, + OPJ_UINT32 * p_nb_tiles_y, + opj_stream_t *p_cio); + + +OPJ_API bool OPJ_CALLCONV opj_end_decompress (opj_codec_t *p_codec,opj_stream_t *p_cio); +/** +Encode an image into a JPEG-2000 codestream +@param cinfo compressor handle +@param cio Output buffer stream +@param image Image to encode +@param index Depreacted -> Set to NULL. To extract index, used opj_encode_wci() +@return Returns true if successful, returns false otherwise +*/ +OPJ_API bool OPJ_CALLCONV opj_encode(opj_codec_t *cinfo, opj_stream_t * cio); + +OPJ_API bool OPJ_CALLCONV opj_start_compress (opj_codec_t *p_codec,opj_image_t * p_image,opj_stream_t *p_cio); + +OPJ_API bool OPJ_CALLCONV opj_end_compress (opj_codec_t *p_codec,opj_stream_t *p_cio); +/** +Encode an image into a JPEG-2000 codestream and extract the codestream information +@param cinfo compressor handle +@param cio Output buffer stream +@param image Image to encode +@param cstr_info Codestream information structure if needed afterwards, NULL otherwise +@return Returns true if successful, returns false otherwise +*/ +//OPJ_API bool OPJ_CALLCONV opj_encode_with_info(opj_cinfo_t *cinfo, opj_stream_t cio, opj_image_t *image, opj_codestream_info_t *cstr_info); +/** +Destroy Codestream information after compression or decompression +@param cstr_info Codestream information structure +*/ +OPJ_API void OPJ_CALLCONV opj_destroy_cstr_info(opj_codestream_info_t *cstr_info); + +//============================================================================== +//============================================================================== +/** profiling part */ +#ifdef _PROFILE +void _ProfInit(void); +void _ProfPrint(void); +#define PROFINIT() _ProfInit(); +#define PROFSAVE(file) _ProfSave(file); +#define PROFPRINT() _ProfPrint(); +#else +#define PROFINIT() +#define PROFSAVE(file) +#define PROFPRINT() +#endif // !_PROFILE + +#ifdef __cplusplus +} +#endif + +#endif /* OPENJPEG_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/opj_configure.h b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/opj_configure.h new file mode 100644 index 0000000..7d7c63a --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/opj_configure.h @@ -0,0 +1,16 @@ +/* + * here is where system comupted values get stored these values should only + * change when the target compile platform changes + */ + +/* what byte order */ +#ifndef __OPJ_CONFIGURE_H +#define __OPJ_CONFIGURE_H +/* #undef CMAKE_WORDS_BIGENDIAN */ +#ifdef CMAKE_WORDS_BIGENDIAN + #define OPJ_BIG_ENDIAN +#else + #define OPJ_LITTLE_ENDIAN +#endif + +#endif /* __OPJ_CONFIGURE_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/opj_includes.h b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/opj_includes.h new file mode 100644 index 0000000..e75a220 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/opj_includes.h @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef OPJ_INCLUDES_H +#define OPJ_INCLUDES_H + +/* + ========================================================== + Standard includes used by the library + ========================================================== +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + ========================================================== + OpenJPEG interface + ========================================================== + */ + +/* + ========================================================== + OpenJPEG modules + ========================================================== +*/ + +/* Ignore GCC attributes if this is not GCC */ +#ifndef __GNUC__ + #define __attribute__(x) /* __attribute__(x) */ +#endif + +/* +The inline keyword is supported by C99 but not by C90. +Most compilers implement their own version of this keyword ... +*/ +#ifndef INLINE + #if defined(_MSC_VER) + #define INLINE __inline + #elif defined(__GNUC__) + #define INLINE __inline__ + #elif defined(__MWERKS__) + #define INLINE inline + #else + /* add other compilers here ... */ + #define INLINE + #endif /* defined() */ +#endif /* INLINE */ + +/* Are restricted pointers available? (C99) */ +#if (__STDC_VERSION__ != 199901L) + /* Not a C99 compiler */ + #ifdef __GNUC__ + #define restrict __restrict__ + #else + #define restrict /* restrict */ + #endif +#endif + +/* MSVC and Borland C do not have lrintf */ +#if defined(_MSC_VER) || defined(__BORLANDC__) + +/* MSVC 64bits doesn't support _asm */ +#if !defined(_WIN64) +static INLINE long lrintf(float f){ + int i; + + _asm{ + fld f + fistp i + }; + + return i; +} +#else +static INLINE long lrintf(float x){ + long r; + if (x>=0.f) + { + x+=0.5f; + } + else + { + x-=0.5f; + } + r = (long)(x); + if ( x != (float)(r) ) return r; + return 2*(r/2); +} +#endif + +#endif + +#endif /* OPJ_INCLUDES_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/opj_malloc.h b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/opj_malloc.h new file mode 100644 index 0000000..76ff5fd --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/opj_malloc.h @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2007, Callum Lerwick + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __OPJ_MALLOC_H +#define __OPJ_MALLOC_H +/** +@file opj_malloc.h +@brief Internal functions + +The functions in opj_malloc.h are internal utilities used for memory management. +*/ +#include "openjpeg.h" +#include "opj_includes.h" +/** @defgroup MISC MISC - Miscellaneous internal functions */ +/*@{*/ + +/** @name Exported functions */ +/*@{*/ +/* ----------------------------------------------------------------------- */ + +/** +Allocate an uninitialized memory block +@param size Bytes to allocate +@return Returns a void pointer to the allocated space, or NULL if there is insufficient memory available +*/ +#define opj_malloc(size) malloc(size) +#define my_opj_malloc(size) malloc(size) + +/** +Allocate a memory block with elements initialized to 0 +@param num Blocks to allocate +@param size Bytes per block to allocate +@return Returns a void pointer to the allocated space, or NULL if there is insufficient memory available +*/ +#define opj_calloc(num, size) calloc(num, size) + +/** +Allocate memory aligned to a 16 byte boundry +@param size Bytes to allocate +@return Returns a void pointer to the allocated space, or NULL if there is insufficient memory available +*/ +/* FIXME: These should be set with cmake tests, but we're currently not requiring use of cmake */ +#ifdef WIN32 + /* Someone should tell the mingw people that their malloc.h ought to provide _mm_malloc() */ + #ifdef __GNUC__ + #include + #define HAVE_MM_MALLOC + #else /* MSVC, Intel C++ */ + #include + #ifdef _mm_malloc + #define HAVE_MM_MALLOC + #endif + #endif +#else /* Not WIN32 */ + #if defined(__sun) + #define HAVE_MEMALIGN + /* Linux x86_64 and OSX always align allocations to 16 bytes */ + #elif !defined(__amd64__) && !defined(__APPLE__) + /* FIXME: Yes, this is a big assumption */ + #define HAVE_POSIX_MEMALIGN + #endif +#endif + +#define opj_aligned_malloc(size) malloc(size) +#define opj_aligned_free(m) free(m) + +#ifdef HAVE_MM_MALLOC + #undef opj_aligned_malloc + #define opj_aligned_malloc(size) _mm_malloc(size, 16) + #undef opj_aligned_free + #define opj_aligned_free(m) _mm_free(m) +#endif + +#ifdef HAVE_MEMALIGN + extern void* memalign(size_t, size_t); + #undef opj_aligned_malloc + #define opj_aligned_malloc(size) memalign(16, (size)) + #undef opj_aligned_free + #define opj_aligned_free(m) free(m) +#endif + +#ifdef HAVE_POSIX_MEMALIGN + #undef opj_aligned_malloc + extern int posix_memalign(void**, size_t, size_t); + + static INLINE void* __attribute__ ((malloc)) opj_aligned_malloc(size_t size){ + void* mem = NULL; + posix_memalign(&mem, 16, size); + return mem; + } + #undef opj_aligned_free + #define opj_aligned_free(m) free(m) +#endif + +/** +Reallocate memory blocks. +@param memblock Pointer to previously allocated memory block +@param size New size in bytes +@return Returns a void pointer to the reallocated (and possibly moved) memory block +*/ +#define opj_realloc(m, s) realloc(m, s) +#define my_opj_realloc(m,s) realloc(m,s) + + +/** +Deallocates or frees a memory block. +@param memblock Previously allocated memory block to be freed +*/ +#define opj_free(m) free(m) + +#ifdef __GNUC__ +#pragma GCC poison malloc calloc realloc free +#endif + +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __OPJ_MALLOC_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/pi.c b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/pi.c new file mode 100644 index 0000000..d8c7252 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/pi.c @@ -0,0 +1,2000 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2006-2007, Parvatha Elangovan + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "pi.h" +#include "int.h" +#include "opj_malloc.h" +#include "j2k.h" +/** @defgroup PI PI - Implementation of a packet iterator */ +/*@{*/ + +/** @name Local static functions */ +/*@{*/ + +/** +Get next packet in layer-resolution-component-precinct order. +@param pi packet iterator to modify +@return returns false if pi pointed to the last packet or else returns true +*/ +static bool pi_next_lrcp(opj_pi_iterator_t * pi); +/** +Get next packet in resolution-layer-component-precinct order. +@param pi packet iterator to modify +@return returns false if pi pointed to the last packet or else returns true +*/ +static bool pi_next_rlcp(opj_pi_iterator_t * pi); +/** +Get next packet in resolution-precinct-component-layer order. +@param pi packet iterator to modify +@return returns false if pi pointed to the last packet or else returns true +*/ +static bool pi_next_rpcl(opj_pi_iterator_t * pi); +/** +Get next packet in precinct-component-resolution-layer order. +@param pi packet iterator to modify +@return returns false if pi pointed to the last packet or else returns true +*/ +static bool pi_next_pcrl(opj_pi_iterator_t * pi); +/** +Get next packet in component-precinct-resolution-layer order. +@param pi packet iterator to modify +@return returns false if pi pointed to the last packet or else returns true +*/ +static bool pi_next_cprl(opj_pi_iterator_t * pi); + +/** + * Updates the coding parameters if the encoding is used with Progression order changes and final (or cinema parameters are used). + * + * @param p_cp the coding parameters to modify + * @param p_tileno the tile index being concerned. + * @param p_tx0 X0 parameter for the tile + * @param p_tx1 X1 parameter for the tile + * @param p_ty0 Y0 parameter for the tile + * @param p_ty1 Y1 parameter for the tile + * @param p_max_prec the maximum precision for all the bands of the tile + * @param p_max_res the maximum number of resolutions for all the poc inside the tile. + * @param dx_min the minimum dx of all the components of all the resolutions for the tile. + * @param dy_min the minimum dy of all the components of all the resolutions for the tile. + */ +void pi_update_encode_poc_and_final ( + opj_cp_t *p_cp, + OPJ_UINT32 p_tileno, + OPJ_INT32 p_tx0, + OPJ_INT32 p_tx1, + OPJ_INT32 p_ty0, + OPJ_INT32 p_ty1, + OPJ_UINT32 p_max_prec, + OPJ_UINT32 p_max_res, + OPJ_UINT32 p_dx_min, + OPJ_UINT32 p_dy_min); + +/** + * Updates the coding parameters if the encoding is not used with Progression order changes and final (and cinema parameters are used). + * + * @param p_cp the coding parameters to modify + * @param p_tileno the tile index being concerned. + * @param p_tx0 X0 parameter for the tile + * @param p_tx1 X1 parameter for the tile + * @param p_ty0 Y0 parameter for the tile + * @param p_ty1 Y1 parameter for the tile + * @param p_max_prec the maximum precision for all the bands of the tile + * @param p_max_res the maximum number of resolutions for all the poc inside the tile. + * @param dx_min the minimum dx of all the components of all the resolutions for the tile. + * @param dy_min the minimum dy of all the components of all the resolutions for the tile. + */ +void pi_update_encode_not_poc ( + opj_cp_t *p_cp, + OPJ_UINT32 p_num_comps, + OPJ_UINT32 p_tileno, + OPJ_INT32 p_tx0, + OPJ_INT32 p_tx1, + OPJ_INT32 p_ty0, + OPJ_INT32 p_ty1, + OPJ_UINT32 p_max_prec, + OPJ_UINT32 p_max_res, + OPJ_UINT32 p_dx_min, + OPJ_UINT32 p_dy_min); + +/** + * Gets the encoding parameters needed to update the coding parameters and all the pocs. + * + * @param p_image the image being encoded. + * @param p_cp the coding parameters. + * @param tileno the tile index of the tile being encoded. + * @param p_tx0 pointer that will hold the X0 parameter for the tile + * @param p_tx1 pointer that will hold the X1 parameter for the tile + * @param p_ty0 pointer that will hold the Y0 parameter for the tile + * @param p_ty1 pointer that will hold the Y1 parameter for the tile + * @param p_max_prec pointer that will hold the the maximum precision for all the bands of the tile + * @param p_max_res pointer that will hold the the maximum number of resolutions for all the poc inside the tile. + * @param dx_min pointer that will hold the the minimum dx of all the components of all the resolutions for the tile. + * @param dy_min pointer that will hold the the minimum dy of all the components of all the resolutions for the tile. + */ +void get_encoding_parameters( + const opj_image_t *p_image, + const opj_cp_t *p_cp, + OPJ_UINT32 tileno, + OPJ_INT32 * p_tx0, + OPJ_INT32 * p_tx1, + OPJ_INT32 * p_ty0, + OPJ_INT32 * p_ty1, + OPJ_UINT32 * p_dx_min, + OPJ_UINT32 * p_dy_min, + OPJ_UINT32 * p_max_prec, + OPJ_UINT32 * p_max_res + ); + +/** + * Gets the encoding parameters needed to update the coding parameters and all the pocs. + * The precinct widths, heights, dx and dy for each component at each resolution will be stored as well. + * the last parameter of the function should be an array of pointers of size nb components, each pointer leading + * to an area of size 4 * max_res. The data is stored inside this area with the following pattern : + * dx_compi_res0 , dy_compi_res0 , w_compi_res0, h_compi_res0 , dx_compi_res1 , dy_compi_res1 , w_compi_res1, h_compi_res1 , ... + * + * @param p_image the image being encoded. + * @param p_cp the coding parameters. + * @param tileno the tile index of the tile being encoded. + * @param p_tx0 pointer that will hold the X0 parameter for the tile + * @param p_tx1 pointer that will hold the X1 parameter for the tile + * @param p_ty0 pointer that will hold the Y0 parameter for the tile + * @param p_ty1 pointer that will hold the Y1 parameter for the tile + * @param p_max_prec pointer that will hold the the maximum precision for all the bands of the tile + * @param p_max_res pointer that will hold the the maximum number of resolutions for all the poc inside the tile. + * @param dx_min pointer that will hold the the minimum dx of all the components of all the resolutions for the tile. + * @param dy_min pointer that will hold the the minimum dy of all the components of all the resolutions for the tile. + * @param p_resolutions pointer to an area corresponding to the one described above. + */ +void get_all_encoding_parameters( + const opj_image_t *p_image, + const opj_cp_t *p_cp, + OPJ_UINT32 tileno, + OPJ_INT32 * p_tx0, + OPJ_INT32 * p_tx1, + OPJ_INT32 * p_ty0, + OPJ_INT32 * p_ty1, + OPJ_UINT32 * p_dx_min, + OPJ_UINT32 * p_dy_min, + OPJ_UINT32 * p_max_prec, + OPJ_UINT32 * p_max_res, + OPJ_UINT32 ** p_resolutions + ); +/** + * Allocates memory for a packet iterator. Data and data sizes are set by this operation. + * No other data is set. The include section of the packet iterator is not allocated. + * + * @param p_image the image used to initialize the packet iterator (in fact only the number of components is relevant. + * @param p_cp the coding parameters. + * @param p_tile_no the index of the tile from which creating the packet iterator. + */ +opj_pi_iterator_t * pi_create( + const opj_image_t *image, + const opj_cp_t *cp, + OPJ_UINT32 tileno + ); +void pi_update_decode_not_poc (opj_pi_iterator_t * p_pi,opj_tcp_t * p_tcp,OPJ_UINT32 p_max_precision,OPJ_UINT32 p_max_res); +void pi_update_decode_poc (opj_pi_iterator_t * p_pi,opj_tcp_t * p_tcp,OPJ_UINT32 p_max_precision,OPJ_UINT32 p_max_res); + + +/*@}*/ + +/*@}*/ + +/* +========================================================== + local functions +========================================================== +*/ + +static bool pi_next_lrcp(opj_pi_iterator_t * pi) { + opj_pi_comp_t *comp = 00; + opj_pi_resolution_t *res = 00; + OPJ_UINT32 index = 0; + + if (!pi->first) { + comp = &pi->comps[pi->compno]; + res = &comp->resolutions[pi->resno]; + goto LABEL_SKIP; + } else { + pi->first = 0; + } + + for (pi->layno = pi->poc.layno0; pi->layno < pi->poc.layno1; pi->layno++) { + for (pi->resno = pi->poc.resno0; pi->resno < pi->poc.resno1; + pi->resno++) { + for (pi->compno = pi->poc.compno0; pi->compno < pi->poc.compno1; pi->compno++) { + comp = &pi->comps[pi->compno]; + if (pi->resno >= comp->numresolutions) { + continue; + } + res = &comp->resolutions[pi->resno]; + if (!pi->tp_on){ + pi->poc.precno1 = res->pw * res->ph; + } + for (pi->precno = pi->poc.precno0; pi->precno < pi->poc.precno1; pi->precno++) { + index = pi->layno * pi->step_l + pi->resno * pi->step_r + pi->compno * pi->step_c + pi->precno * pi->step_p; + if (!pi->include[index]) { + pi->include[index] = 1; + return true; + } +LABEL_SKIP:; + } + } + } + } + + return false; +} + +static bool pi_next_rlcp(opj_pi_iterator_t * pi) { + opj_pi_comp_t *comp = 00; + opj_pi_resolution_t *res = 00; + OPJ_UINT32 index = 0; + + if (!pi->first) { + comp = &pi->comps[pi->compno]; + res = &comp->resolutions[pi->resno]; + goto LABEL_SKIP; + } else { + pi->first = 0; + } + + for (pi->resno = pi->poc.resno0; pi->resno < pi->poc.resno1; pi->resno++) { + for (pi->layno = pi->poc.layno0; pi->layno < pi->poc.layno1; pi->layno++) { + for (pi->compno = pi->poc.compno0; pi->compno < pi->poc.compno1; pi->compno++) { + comp = &pi->comps[pi->compno]; + if (pi->resno >= comp->numresolutions) { + continue; + } + res = &comp->resolutions[pi->resno]; + if(!pi->tp_on){ + pi->poc.precno1 = res->pw * res->ph; + } + for (pi->precno = pi->poc.precno0; pi->precno < pi->poc.precno1; pi->precno++) { + index = pi->layno * pi->step_l + pi->resno * pi->step_r + pi->compno * pi->step_c + pi->precno * pi->step_p; + if (!pi->include[index]) { + pi->include[index] = 1; + return true; + } +LABEL_SKIP:; + } + } + } + } + + return false; +} + +static bool pi_next_rpcl(opj_pi_iterator_t * pi) { + opj_pi_comp_t *comp = 00; + opj_pi_resolution_t *res = 00; + OPJ_UINT32 index = 0; + + if (!pi->first) { + goto LABEL_SKIP; + } else { + OPJ_UINT32 compno, resno; + pi->first = 0; + pi->dx = 0; + pi->dy = 0; + for (compno = 0; compno < pi->numcomps; compno++) { + comp = &pi->comps[compno]; + for (resno = 0; resno < comp->numresolutions; resno++) { + OPJ_UINT32 dx, dy; + res = &comp->resolutions[resno]; + dx = comp->dx * (1 << (res->pdx + comp->numresolutions - 1 - resno)); + dy = comp->dy * (1 << (res->pdy + comp->numresolutions - 1 - resno)); + pi->dx = !pi->dx ? dx : int_min(pi->dx, dx); + pi->dy = !pi->dy ? dy : int_min(pi->dy, dy); + } + } + } +if (!pi->tp_on){ + pi->poc.ty0 = pi->ty0; + pi->poc.tx0 = pi->tx0; + pi->poc.ty1 = pi->ty1; + pi->poc.tx1 = pi->tx1; + } + for (pi->resno = pi->poc.resno0; pi->resno < pi->poc.resno1; pi->resno++) { + for (pi->y = pi->poc.ty0; pi->y < pi->poc.ty1; pi->y += pi->dy - (pi->y % pi->dy)) { + for (pi->x = pi->poc.tx0; pi->x < pi->poc.tx1; pi->x += pi->dx - (pi->x % pi->dx)) { + for (pi->compno = pi->poc.compno0; pi->compno < pi->poc.compno1; pi->compno++) { + OPJ_UINT32 levelno; + OPJ_INT32 trx0, try0; + OPJ_INT32 trx1, try1; + OPJ_UINT32 rpx, rpy; + OPJ_INT32 prci, prcj; + comp = &pi->comps[pi->compno]; + if (pi->resno >= comp->numresolutions) { + continue; + } + res = &comp->resolutions[pi->resno]; + levelno = comp->numresolutions - 1 - pi->resno; + trx0 = int_ceildiv(pi->tx0, comp->dx << levelno); + try0 = int_ceildiv(pi->ty0, comp->dy << levelno); + trx1 = int_ceildiv(pi->tx1, comp->dx << levelno); + try1 = int_ceildiv(pi->ty1, comp->dy << levelno); + rpx = res->pdx + levelno; + rpy = res->pdy + levelno; + if (!((pi->y % (comp->dy << rpy) == 0) || ((pi->y == pi->ty0) && ((try0 << levelno) % (1 << rpy))))){ + continue; + } + if (!((pi->x % (comp->dx << rpx) == 0) || ((pi->x == pi->tx0) && ((trx0 << levelno) % (1 << rpx))))){ + continue; + } + + if ((res->pw==0)||(res->ph==0)) continue; + + if ((trx0==trx1)||(try0==try1)) continue; + + prci = int_floordivpow2(int_ceildiv(pi->x, comp->dx << levelno), res->pdx) + - int_floordivpow2(trx0, res->pdx); + prcj = int_floordivpow2(int_ceildiv(pi->y, comp->dy << levelno), res->pdy) + - int_floordivpow2(try0, res->pdy); + pi->precno = prci + prcj * res->pw; + for (pi->layno = pi->poc.layno0; pi->layno < pi->poc.layno1; pi->layno++) { + index = pi->layno * pi->step_l + pi->resno * pi->step_r + pi->compno * pi->step_c + pi->precno * pi->step_p; + if (!pi->include[index]) { + pi->include[index] = 1; + return true; + } +LABEL_SKIP:; + } + } + } + } + } + + return false; +} + +static bool pi_next_pcrl(opj_pi_iterator_t * pi) { + opj_pi_comp_t *comp = 00; + opj_pi_resolution_t *res = 00; + OPJ_UINT32 index = 0; + + if (!pi->first) { + comp = &pi->comps[pi->compno]; + goto LABEL_SKIP; + } else { + OPJ_UINT32 compno, resno; + pi->first = 0; + pi->dx = 0; + pi->dy = 0; + for (compno = 0; compno < pi->numcomps; compno++) { + comp = &pi->comps[compno]; + for (resno = 0; resno < comp->numresolutions; resno++) { + OPJ_UINT32 dx, dy; + res = &comp->resolutions[resno]; + dx = comp->dx * (1 << (res->pdx + comp->numresolutions - 1 - resno)); + dy = comp->dy * (1 << (res->pdy + comp->numresolutions - 1 - resno)); + pi->dx = !pi->dx ? dx : int_min(pi->dx, dx); + pi->dy = !pi->dy ? dy : int_min(pi->dy, dy); + } + } + } + if (!pi->tp_on){ + pi->poc.ty0 = pi->ty0; + pi->poc.tx0 = pi->tx0; + pi->poc.ty1 = pi->ty1; + pi->poc.tx1 = pi->tx1; + } + for (pi->y = pi->poc.ty0; pi->y < pi->poc.ty1; pi->y += pi->dy - (pi->y % pi->dy)) { + for (pi->x = pi->poc.tx0; pi->x < pi->poc.tx1; pi->x += pi->dx - (pi->x % pi->dx)) { + for (pi->compno = pi->poc.compno0; pi->compno < pi->poc.compno1; pi->compno++) { + comp = &pi->comps[pi->compno]; + // TODO + for (pi->resno = pi->poc.resno0; pi->resno < uint_min(pi->poc.resno1, comp->numresolutions); pi->resno++) { + OPJ_UINT32 levelno; + OPJ_INT32 trx0, try0; + OPJ_INT32 trx1, try1; + OPJ_UINT32 rpx, rpy; + OPJ_INT32 prci, prcj; + res = &comp->resolutions[pi->resno]; + levelno = comp->numresolutions - 1 - pi->resno; + trx0 = int_ceildiv(pi->tx0, comp->dx << levelno); + try0 = int_ceildiv(pi->ty0, comp->dy << levelno); + trx1 = int_ceildiv(pi->tx1, comp->dx << levelno); + try1 = int_ceildiv(pi->ty1, comp->dy << levelno); + rpx = res->pdx + levelno; + rpy = res->pdy + levelno; + if (!((pi->y % (comp->dy << rpy) == 0) || ((pi->y == pi->ty0) && ((try0 << levelno) % (1 << rpy))))){ + continue; + } + if (!((pi->x % (comp->dx << rpx) == 0) || ((pi->x == pi->tx0) && ((trx0 << levelno) % (1 << rpx))))){ + continue; + } + + if ((res->pw==0)||(res->ph==0)) continue; + + if ((trx0==trx1)||(try0==try1)) continue; + + prci = int_floordivpow2(int_ceildiv(pi->x, comp->dx << levelno), res->pdx) + - int_floordivpow2(trx0, res->pdx); + prcj = int_floordivpow2(int_ceildiv(pi->y, comp->dy << levelno), res->pdy) + - int_floordivpow2(try0, res->pdy); + pi->precno = prci + prcj * res->pw; + for (pi->layno = pi->poc.layno0; pi->layno < pi->poc.layno1; pi->layno++) { + index = pi->layno * pi->step_l + pi->resno * pi->step_r + pi->compno * pi->step_c + pi->precno * pi->step_p; + if (!pi->include[index]) { + pi->include[index] = 1; + return true; + } +LABEL_SKIP:; + } + } + } + } + } + + return false; +} + +static bool pi_next_cprl(opj_pi_iterator_t * pi) { + opj_pi_comp_t *comp = 00; + opj_pi_resolution_t *res = 00; + OPJ_UINT32 index = 0; + + if (!pi->first) { + comp = &pi->comps[pi->compno]; + goto LABEL_SKIP; + } else { + pi->first = 0; + } + + for (pi->compno = pi->poc.compno0; pi->compno < pi->poc.compno1; pi->compno++) { + OPJ_UINT32 resno; + comp = &pi->comps[pi->compno]; + pi->dx = 0; + pi->dy = 0; + for (resno = 0; resno < comp->numresolutions; resno++) { + OPJ_UINT32 dx, dy; + res = &comp->resolutions[resno]; + dx = comp->dx * (1 << (res->pdx + comp->numresolutions - 1 - resno)); + dy = comp->dy * (1 << (res->pdy + comp->numresolutions - 1 - resno)); + pi->dx = !pi->dx ? dx : int_min(pi->dx, dx); + pi->dy = !pi->dy ? dy : int_min(pi->dy, dy); + } + if (!pi->tp_on){ + pi->poc.ty0 = pi->ty0; + pi->poc.tx0 = pi->tx0; + pi->poc.ty1 = pi->ty1; + pi->poc.tx1 = pi->tx1; + } + for (pi->y = pi->poc.ty0; pi->y < pi->poc.ty1; pi->y += pi->dy - (pi->y % pi->dy)) { + for (pi->x = pi->poc.tx0; pi->x < pi->poc.tx1; pi->x += pi->dx - (pi->x % pi->dx)) { + // TODO + for (pi->resno = pi->poc.resno0; pi->resno < uint_min(pi->poc.resno1, comp->numresolutions); pi->resno++) { + OPJ_UINT32 levelno; + OPJ_INT32 trx0, try0; + OPJ_INT32 trx1, try1; + OPJ_UINT32 rpx, rpy; + OPJ_INT32 prci, prcj; + res = &comp->resolutions[pi->resno]; + levelno = comp->numresolutions - 1 - pi->resno; + trx0 = int_ceildiv(pi->tx0, comp->dx << levelno); + try0 = int_ceildiv(pi->ty0, comp->dy << levelno); + trx1 = int_ceildiv(pi->tx1, comp->dx << levelno); + try1 = int_ceildiv(pi->ty1, comp->dy << levelno); + rpx = res->pdx + levelno; + rpy = res->pdy + levelno; + if (!((pi->y % (comp->dy << rpy) == 0) || ((pi->y == pi->ty0) && ((try0 << levelno) % (1 << rpy))))){ + continue; + } + if (!((pi->x % (comp->dx << rpx) == 0) || ((pi->x == pi->tx0) && ((trx0 << levelno) % (1 << rpx))))){ + continue; + } + + if ((res->pw==0)||(res->ph==0)) continue; + + if ((trx0==trx1)||(try0==try1)) continue; + + prci = int_floordivpow2(int_ceildiv(pi->x, comp->dx << levelno), res->pdx) + - int_floordivpow2(trx0, res->pdx); + prcj = int_floordivpow2(int_ceildiv(pi->y, comp->dy << levelno), res->pdy) + - int_floordivpow2(try0, res->pdy); + pi->precno = prci + prcj * res->pw; + for (pi->layno = pi->poc.layno0; pi->layno < pi->poc.layno1; pi->layno++) { + index = pi->layno * pi->step_l + pi->resno * pi->step_r + pi->compno * pi->step_c + pi->precno * pi->step_p; + if (!pi->include[index]) { + pi->include[index] = 1; + return true; + } +LABEL_SKIP:; + } + } + } + } + } + + return false; +} + +/* +========================================================== + Packet iterator interface +========================================================== +*/ +opj_pi_iterator_t *pi_create_decode( + opj_image_t *p_image, + opj_cp_t *p_cp, + OPJ_UINT32 p_tile_no + ) +{ + // loop + OPJ_UINT32 pino; + OPJ_UINT32 compno, resno; + + // to store w, h, dx and dy fro all components and resolutions + OPJ_UINT32 * l_tmp_data; + OPJ_UINT32 ** l_tmp_ptr; + + // encoding prameters to set + OPJ_UINT32 l_max_res; + OPJ_UINT32 l_max_prec; + OPJ_INT32 l_tx0,l_tx1,l_ty0,l_ty1; + OPJ_UINT32 l_dx_min,l_dy_min; + OPJ_UINT32 l_bound; + OPJ_UINT32 l_step_p , l_step_c , l_step_r , l_step_l ; + OPJ_UINT32 l_data_stride; + + // pointers + opj_pi_iterator_t *l_pi = 00; + opj_tcp_t *l_tcp = 00; + const opj_tccp_t *l_tccp = 00; + opj_pi_comp_t *l_current_comp = 00; + opj_image_comp_t * l_img_comp = 00; + opj_pi_iterator_t * l_current_pi = 00; + OPJ_UINT32 * l_encoding_value_ptr = 00; + + // preconditions in debug + assert(p_cp != 00); + assert(p_image != 00); + assert(p_tile_no < p_cp->tw * p_cp->th); + + // initializations + l_tcp = &p_cp->tcps[p_tile_no]; + l_bound = l_tcp->numpocs+1; + + l_data_stride = 4 * J2K_MAXRLVLS; + l_tmp_data = (OPJ_UINT32*)opj_malloc( + l_data_stride * p_image->numcomps * sizeof(OPJ_UINT32)); + if + (! l_tmp_data) + { + return 00; + } + l_tmp_ptr = (OPJ_UINT32**)opj_malloc( + p_image->numcomps * sizeof(OPJ_UINT32 *)); + if + (! l_tmp_ptr) + { + opj_free(l_tmp_data); + return 00; + } + + // memory allocation for pi + l_pi = pi_create(p_image,p_cp,p_tile_no); + if + (!l_pi) + { + opj_free(l_tmp_data); + opj_free(l_tmp_ptr); + return 00; + } + + l_encoding_value_ptr = l_tmp_data; + // update pointer array + for + (compno = 0; compno < p_image->numcomps; ++compno) + { + l_tmp_ptr[compno] = l_encoding_value_ptr; + l_encoding_value_ptr += l_data_stride; + } + // get encoding parameters + get_all_encoding_parameters(p_image,p_cp,p_tile_no,&l_tx0,&l_tx1,&l_ty0,&l_ty1,&l_dx_min,&l_dy_min,&l_max_prec,&l_max_res,l_tmp_ptr); + + // step calculations + l_step_p = 1; + l_step_c = l_max_prec * l_step_p; + l_step_r = p_image->numcomps * l_step_c; + l_step_l = l_max_res * l_step_r; + + // set values for first packet iterator + l_current_pi = l_pi; + + // memory allocation for include + l_current_pi->include = (OPJ_INT16*) opj_calloc(l_tcp->numlayers * l_step_l, sizeof(OPJ_INT16)); + if + (!l_current_pi->include) + { + opj_free(l_tmp_data); + opj_free(l_tmp_ptr); + pi_destroy(l_pi, l_bound); + return 00; + } + memset(l_current_pi->include,0,l_tcp->numlayers * l_step_l* sizeof(OPJ_INT16)); + + // special treatment for the first packet iterator + l_current_comp = l_current_pi->comps; + l_img_comp = p_image->comps; + l_tccp = l_tcp->tccps; + + l_current_pi->tx0 = l_tx0; + l_current_pi->ty0 = l_ty0; + l_current_pi->tx1 = l_tx1; + l_current_pi->ty1 = l_ty1; + + //l_current_pi->dx = l_img_comp->dx; + //l_current_pi->dy = l_img_comp->dy; + + l_current_pi->step_p = l_step_p; + l_current_pi->step_c = l_step_c; + l_current_pi->step_r = l_step_r; + l_current_pi->step_l = l_step_l; + + /* allocation for components and number of components has already been calculated by pi_create */ + for + (compno = 0; compno < l_current_pi->numcomps; ++compno) + { + opj_pi_resolution_t *l_res = l_current_comp->resolutions; + l_encoding_value_ptr = l_tmp_ptr[compno]; + + l_current_comp->dx = l_img_comp->dx; + l_current_comp->dy = l_img_comp->dy; + /* resolutions have already been initialized */ + for + (resno = 0; resno < l_current_comp->numresolutions; resno++) + { + l_res->pdx = *(l_encoding_value_ptr++); + l_res->pdy = *(l_encoding_value_ptr++); + l_res->pw = *(l_encoding_value_ptr++); + l_res->ph = *(l_encoding_value_ptr++); + ++l_res; + } + ++l_current_comp; + ++l_img_comp; + ++l_tccp; + } + ++l_current_pi; + + for + (pino = 1 ; pinocomps; + opj_image_comp_t * l_img_comp = p_image->comps; + l_tccp = l_tcp->tccps; + + l_current_pi->tx0 = l_tx0; + l_current_pi->ty0 = l_ty0; + l_current_pi->tx1 = l_tx1; + l_current_pi->ty1 = l_ty1; + //l_current_pi->dx = l_dx_min; + //l_current_pi->dy = l_dy_min; + l_current_pi->step_p = l_step_p; + l_current_pi->step_c = l_step_c; + l_current_pi->step_r = l_step_r; + l_current_pi->step_l = l_step_l; + + /* allocation for components and number of components has already been calculated by pi_create */ + for + (compno = 0; compno < l_current_pi->numcomps; ++compno) + { + opj_pi_resolution_t *l_res = l_current_comp->resolutions; + l_encoding_value_ptr = l_tmp_ptr[compno]; + + l_current_comp->dx = l_img_comp->dx; + l_current_comp->dy = l_img_comp->dy; + /* resolutions have already been initialized */ + for + (resno = 0; resno < l_current_comp->numresolutions; resno++) + { + l_res->pdx = *(l_encoding_value_ptr++); + l_res->pdy = *(l_encoding_value_ptr++); + l_res->pw = *(l_encoding_value_ptr++); + l_res->ph = *(l_encoding_value_ptr++); + ++l_res; + } + ++l_current_comp; + ++l_img_comp; + ++l_tccp; + } + // special treatment + l_current_pi->include = (l_current_pi-1)->include; + ++l_current_pi; + } + opj_free(l_tmp_data); + l_tmp_data = 00; + opj_free(l_tmp_ptr); + l_tmp_ptr = 00; + if + (l_tcp->POC) + { + pi_update_decode_poc (l_pi,l_tcp,l_max_prec,l_max_res); + } + else + { + pi_update_decode_not_poc(l_pi,l_tcp,l_max_prec,l_max_res); + } + return l_pi; +} + +void pi_update_decode_poc (opj_pi_iterator_t * p_pi,opj_tcp_t * p_tcp,OPJ_UINT32 p_max_precision,OPJ_UINT32 p_max_res) +{ + // loop + OPJ_UINT32 pino; + + // encoding prameters to set + OPJ_UINT32 l_bound; + + opj_pi_iterator_t * l_current_pi = 00; + opj_poc_t* l_current_poc = 0; + + // preconditions in debug + assert(p_pi != 00); + assert(p_tcp != 00); + + // initializations + l_bound = p_tcp->numpocs+1; + l_current_pi = p_pi; + l_current_poc = p_tcp->pocs; + + for + (pino = 0;pinopoc.prg = l_current_poc->prg; + l_current_pi->first = 1; + + l_current_pi->poc.resno0 = l_current_poc->resno0; + l_current_pi->poc.compno0 = l_current_poc->compno0; + l_current_pi->poc.layno0 = 0; + l_current_pi->poc.precno0 = 0; + l_current_pi->poc.resno1 = l_current_poc->resno1; + l_current_pi->poc.compno1 = l_current_poc->compno1; + l_current_pi->poc.layno1 = l_current_poc->layno1; + l_current_pi->poc.precno1 = p_max_precision; + ++l_current_pi; + ++l_current_poc; + } +} + +void pi_update_decode_not_poc (opj_pi_iterator_t * p_pi,opj_tcp_t * p_tcp,OPJ_UINT32 p_max_precision,OPJ_UINT32 p_max_res) +{ + // loop + OPJ_UINT32 pino; + + // encoding prameters to set + OPJ_UINT32 l_bound; + + opj_pi_iterator_t * l_current_pi = 00; + // preconditions in debug + assert(p_tcp != 00); + assert(p_pi != 00); + + // initializations + l_bound = p_tcp->numpocs+1; + l_current_pi = p_pi; + + for + (pino = 0;pinopoc.prg = p_tcp->prg; + l_current_pi->first = 1; + l_current_pi->poc.resno0 = 0; + l_current_pi->poc.compno0 = 0; + l_current_pi->poc.layno0 = 0; + l_current_pi->poc.precno0 = 0; + l_current_pi->poc.resno1 = p_max_res; + l_current_pi->poc.compno1 = l_current_pi->numcomps; + l_current_pi->poc.layno1 = p_tcp->numlayers; + l_current_pi->poc.precno1 = p_max_precision; + ++l_current_pi; + } +} + +/** + * Creates a packet iterator for encoding. + * + * @param p_image the image being encoded. + * @param p_cp the coding parameters. + * @param p_tile_no index of the tile being encoded. + * @param p_t2_mode the type of pass for generating the packet iterator + * @return a list of packet iterator that points to the first packet of the tile (not true). +*/ +opj_pi_iterator_t *pi_initialise_encode( + const opj_image_t *p_image, + opj_cp_t *p_cp, + OPJ_UINT32 p_tile_no, + J2K_T2_MODE p_t2_mode + ) +{ + // loop + OPJ_UINT32 pino; + OPJ_UINT32 compno, resno; + + // to store w, h, dx and dy fro all components and resolutions + OPJ_UINT32 * l_tmp_data; + OPJ_UINT32 ** l_tmp_ptr; + + // encoding prameters to set + OPJ_UINT32 l_max_res; + OPJ_UINT32 l_max_prec; + OPJ_INT32 l_tx0,l_tx1,l_ty0,l_ty1; + OPJ_UINT32 l_dx_min,l_dy_min; + OPJ_UINT32 l_bound; + OPJ_UINT32 l_step_p , l_step_c , l_step_r , l_step_l ; + OPJ_UINT32 l_data_stride; + + // pointers + opj_pi_iterator_t *l_pi = 00; + opj_tcp_t *l_tcp = 00; + const opj_tccp_t *l_tccp = 00; + opj_pi_comp_t *l_current_comp = 00; + opj_image_comp_t * l_img_comp = 00; + opj_pi_iterator_t * l_current_pi = 00; + OPJ_UINT32 * l_encoding_value_ptr = 00; + + // preconditions in debug + assert(p_cp != 00); + assert(p_image != 00); + assert(p_tile_no < p_cp->tw * p_cp->th); + + // initializations + l_tcp = &p_cp->tcps[p_tile_no]; + l_bound = l_tcp->numpocs+1; + + l_data_stride = 4 * J2K_MAXRLVLS; + l_tmp_data = (OPJ_UINT32*)opj_malloc( + l_data_stride * p_image->numcomps * sizeof(OPJ_UINT32)); + if + (! l_tmp_data) + { + return 00; + } + l_tmp_ptr = (OPJ_UINT32**)opj_malloc( + p_image->numcomps * sizeof(OPJ_UINT32 *)); + if + (! l_tmp_ptr) + { + opj_free(l_tmp_data); + return 00; + } + + // memory allocation for pi + l_pi = pi_create(p_image,p_cp,p_tile_no); + if + (!l_pi) + { + opj_free(l_tmp_data); + opj_free(l_tmp_ptr); + return 00; + } + + l_encoding_value_ptr = l_tmp_data; + // update pointer array + for + (compno = 0; compno < p_image->numcomps; ++compno) + { + l_tmp_ptr[compno] = l_encoding_value_ptr; + l_encoding_value_ptr += l_data_stride; + } + // get encoding parameters + get_all_encoding_parameters(p_image,p_cp,p_tile_no,&l_tx0,&l_tx1,&l_ty0,&l_ty1,&l_dx_min,&l_dy_min,&l_max_prec,&l_max_res,l_tmp_ptr); + + // step calculations + l_step_p = 1; + l_step_c = l_max_prec * l_step_p; + l_step_r = p_image->numcomps * l_step_c; + l_step_l = l_max_res * l_step_r; + + // set values for first packet iterator + l_pi->tp_on = p_cp->m_specific_param.m_enc.m_tp_on; + l_current_pi = l_pi; + + // memory allocation for include + l_current_pi->include = (OPJ_INT16*) opj_calloc(l_tcp->numlayers * l_step_l, sizeof(OPJ_INT16)); + if + (!l_current_pi->include) + { + opj_free(l_tmp_data); + opj_free(l_tmp_ptr); + pi_destroy(l_pi, l_bound); + return 00; + } + memset(l_current_pi->include,0,l_tcp->numlayers * l_step_l* sizeof(OPJ_INT16)); + + // special treatment for the first packet iterator + l_current_comp = l_current_pi->comps; + l_img_comp = p_image->comps; + l_tccp = l_tcp->tccps; + l_current_pi->tx0 = l_tx0; + l_current_pi->ty0 = l_ty0; + l_current_pi->tx1 = l_tx1; + l_current_pi->ty1 = l_ty1; + l_current_pi->dx = l_dx_min; + l_current_pi->dy = l_dy_min; + l_current_pi->step_p = l_step_p; + l_current_pi->step_c = l_step_c; + l_current_pi->step_r = l_step_r; + l_current_pi->step_l = l_step_l; + + /* allocation for components and number of components has already been calculated by pi_create */ + for + (compno = 0; compno < l_current_pi->numcomps; ++compno) + { + opj_pi_resolution_t *l_res = l_current_comp->resolutions; + l_encoding_value_ptr = l_tmp_ptr[compno]; + + l_current_comp->dx = l_img_comp->dx; + l_current_comp->dy = l_img_comp->dy; + /* resolutions have already been initialized */ + for + (resno = 0; resno < l_current_comp->numresolutions; resno++) + { + l_res->pdx = *(l_encoding_value_ptr++); + l_res->pdy = *(l_encoding_value_ptr++); + l_res->pw = *(l_encoding_value_ptr++); + l_res->ph = *(l_encoding_value_ptr++); + ++l_res; + } + ++l_current_comp; + ++l_img_comp; + ++l_tccp; + } + ++l_current_pi; + + for + (pino = 1 ; pinocomps; + opj_image_comp_t * l_img_comp = p_image->comps; + l_tccp = l_tcp->tccps; + + l_current_pi->tx0 = l_tx0; + l_current_pi->ty0 = l_ty0; + l_current_pi->tx1 = l_tx1; + l_current_pi->ty1 = l_ty1; + l_current_pi->dx = l_dx_min; + l_current_pi->dy = l_dy_min; + l_current_pi->step_p = l_step_p; + l_current_pi->step_c = l_step_c; + l_current_pi->step_r = l_step_r; + l_current_pi->step_l = l_step_l; + + /* allocation for components and number of components has already been calculated by pi_create */ + for + (compno = 0; compno < l_current_pi->numcomps; ++compno) + { + opj_pi_resolution_t *l_res = l_current_comp->resolutions; + l_encoding_value_ptr = l_tmp_ptr[compno]; + + l_current_comp->dx = l_img_comp->dx; + l_current_comp->dy = l_img_comp->dy; + /* resolutions have already been initialized */ + for + (resno = 0; resno < l_current_comp->numresolutions; resno++) + { + l_res->pdx = *(l_encoding_value_ptr++); + l_res->pdy = *(l_encoding_value_ptr++); + l_res->pw = *(l_encoding_value_ptr++); + l_res->ph = *(l_encoding_value_ptr++); + ++l_res; + } + ++l_current_comp; + ++l_img_comp; + ++l_tccp; + } + // special treatment + l_current_pi->include = (l_current_pi-1)->include; + ++l_current_pi; + } + opj_free(l_tmp_data); + l_tmp_data = 00; + opj_free(l_tmp_ptr); + l_tmp_ptr = 00; + if + (l_tcp->POC && ( p_cp->m_specific_param.m_enc.m_cinema || p_t2_mode == FINAL_PASS)) + { + pi_update_encode_poc_and_final(p_cp,p_tile_no,l_tx0,l_tx1,l_ty0,l_ty1,l_max_prec,l_max_res,l_dx_min,l_dy_min); + } + else + { + pi_update_encode_not_poc(p_cp,p_image->numcomps,p_tile_no,l_tx0,l_tx1,l_ty0,l_ty1,l_max_prec,l_max_res,l_dx_min,l_dy_min); + } + return l_pi; +} + +/** + * Updates the encoding parameters of the codec. + * + * @param p_image the image being encoded. + * @param p_cp the coding parameters. + * @param p_tile_no index of the tile being encoded. +*/ +void pi_update_encoding_parameters( + const opj_image_t *p_image, + opj_cp_t *p_cp, + OPJ_UINT32 p_tile_no + ) +{ + // encoding prameters to set + OPJ_UINT32 l_max_res; + OPJ_UINT32 l_max_prec; + OPJ_INT32 l_tx0,l_tx1,l_ty0,l_ty1; + OPJ_UINT32 l_dx_min,l_dy_min; + + // pointers + opj_tcp_t *l_tcp = 00; + + // preconditions in debug + assert(p_cp != 00); + assert(p_image != 00); + assert(p_tile_no < p_cp->tw * p_cp->th); + + l_tcp = &(p_cp->tcps[p_tile_no]); + // get encoding parameters + get_encoding_parameters(p_image,p_cp,p_tile_no,&l_tx0,&l_tx1,&l_ty0,&l_ty1,&l_dx_min,&l_dy_min,&l_max_prec,&l_max_res); + if + (l_tcp->POC) + { + pi_update_encode_poc_and_final(p_cp,p_tile_no,l_tx0,l_tx1,l_ty0,l_ty1,l_max_prec,l_max_res,l_dx_min,l_dy_min); + } + else + { + pi_update_encode_not_poc(p_cp,p_image->numcomps,p_tile_no,l_tx0,l_tx1,l_ty0,l_ty1,l_max_prec,l_max_res,l_dx_min,l_dy_min); + } +} + + +/** + * Gets the encoding parameters needed to update the coding parameters and all the pocs. + * + * @param p_image the image being encoded. + * @param p_cp the coding parameters. + * @param p_tileno the tile index of the tile being encoded. + * @param p_tx0 pointer that will hold the X0 parameter for the tile + * @param p_tx1 pointer that will hold the X1 parameter for the tile + * @param p_ty0 pointer that will hold the Y0 parameter for the tile + * @param p_ty1 pointer that will hold the Y1 parameter for the tile + * @param p_max_prec pointer that will hold the the maximum precision for all the bands of the tile + * @param p_max_res pointer that will hold the the maximum number of resolutions for all the poc inside the tile. + * @param dx_min pointer that will hold the the minimum dx of all the components of all the resolutions for the tile. + * @param dy_min pointer that will hold the the minimum dy of all the components of all the resolutions for the tile. + */ +void get_encoding_parameters( + const opj_image_t *p_image, + const opj_cp_t *p_cp, + OPJ_UINT32 p_tileno, + OPJ_INT32 * p_tx0, + OPJ_INT32 * p_tx1, + OPJ_INT32 * p_ty0, + OPJ_INT32 * p_ty1, + OPJ_UINT32 * p_dx_min, + OPJ_UINT32 * p_dy_min, + OPJ_UINT32 * p_max_prec, + OPJ_UINT32 * p_max_res + ) +{ + // loop + OPJ_UINT32 compno, resno; + // pointers + const opj_tcp_t *l_tcp = 00; + const opj_tccp_t * l_tccp = 00; + const opj_image_comp_t * l_img_comp = 00; + + // position in x and y of tile + OPJ_UINT32 p, q; + + // preconditions in debug + assert(p_cp != 00); + assert(p_image != 00); + assert(p_tileno < p_cp->tw * p_cp->th); + + // initializations + l_tcp = &p_cp->tcps [p_tileno]; + l_img_comp = p_image->comps; + l_tccp = l_tcp->tccps; + + /* here calculation of tx0, tx1, ty0, ty1, maxprec, dx and dy */ + p = p_tileno % p_cp->tw; + q = p_tileno / p_cp->tw; + + // find extent of tile + *p_tx0 = int_max(p_cp->tx0 + p * p_cp->tdx, p_image->x0); + *p_tx1 = int_min(p_cp->tx0 + (p + 1) * p_cp->tdx, p_image->x1); + *p_ty0 = int_max(p_cp->ty0 + q * p_cp->tdy, p_image->y0); + *p_ty1 = int_min(p_cp->ty0 + (q + 1) * p_cp->tdy, p_image->y1); + + // max precision is 0 (can only grow) + *p_max_prec = 0; + *p_max_res = 0; + + // take the largest value for dx_min and dy_min + *p_dx_min = 0x7fffffff; + *p_dy_min = 0x7fffffff; + + for + (compno = 0; compno < p_image->numcomps; ++compno) + { + // aritmetic variables to calculate + OPJ_UINT32 l_level_no; + OPJ_INT32 l_rx0, l_ry0, l_rx1, l_ry1; + OPJ_INT32 l_px0, l_py0, l_px1, py1; + OPJ_UINT32 l_pdx, l_pdy; + OPJ_UINT32 l_pw, l_ph; + OPJ_UINT32 l_product; + OPJ_INT32 l_tcx0, l_tcy0, l_tcx1, l_tcy1; + + l_tcx0 = int_ceildiv(*p_tx0, l_img_comp->dx); + l_tcy0 = int_ceildiv(*p_ty0, l_img_comp->dy); + l_tcx1 = int_ceildiv(*p_tx1, l_img_comp->dx); + l_tcy1 = int_ceildiv(*p_ty1, l_img_comp->dy); + if + (l_tccp->numresolutions > *p_max_res) + { + *p_max_res = l_tccp->numresolutions; + } + // use custom size for precincts + for + (resno = 0; resno < l_tccp->numresolutions; ++resno) + { + OPJ_UINT32 l_dx, l_dy; + // precinct width and height + l_pdx = l_tccp->prcw[resno]; + l_pdy = l_tccp->prch[resno]; + + l_dx = l_img_comp->dx * (1 << (l_pdx + l_tccp->numresolutions - 1 - resno)); + l_dy = l_img_comp->dy * (1 << (l_pdy + l_tccp->numresolutions - 1 - resno)); + // take the minimum size for dx for each comp and resolution + *p_dx_min = uint_min(*p_dx_min, l_dx); + *p_dy_min = uint_min(*p_dy_min, l_dy); + // various calculations of extents + l_level_no = l_tccp->numresolutions - 1 - resno; + l_rx0 = int_ceildivpow2(l_tcx0, l_level_no); + l_ry0 = int_ceildivpow2(l_tcy0, l_level_no); + l_rx1 = int_ceildivpow2(l_tcx1, l_level_no); + l_ry1 = int_ceildivpow2(l_tcy1, l_level_no); + l_px0 = int_floordivpow2(l_rx0, l_pdx) << l_pdx; + l_py0 = int_floordivpow2(l_ry0, l_pdy) << l_pdy; + l_px1 = int_ceildivpow2(l_rx1, l_pdx) << l_pdx; + py1 = int_ceildivpow2(l_ry1, l_pdy) << l_pdy; + l_pw = (l_rx0==l_rx1)?0:((l_px1 - l_px0) >> l_pdx); + l_ph = (l_ry0==l_ry1)?0:((py1 - l_py0) >> l_pdy); + l_product = l_pw * l_ph; + // update precision + if + (l_product > *p_max_prec) + { + *p_max_prec = l_product; + } + } + ++l_img_comp; + ++l_tccp; + } +} + +/** + * Gets the encoding parameters needed to update the coding parameters and all the pocs. + * The precinct widths, heights, dx and dy for each component at each resolution will be stored as well. + * the last parameter of the function should be an array of pointers of size nb components, each pointer leading + * to an area of size 4 * max_res. The data is stored inside this area with the following pattern : + * dx_compi_res0 , dy_compi_res0 , w_compi_res0, h_compi_res0 , dx_compi_res1 , dy_compi_res1 , w_compi_res1, h_compi_res1 , ... + * + * @param p_image the image being encoded. + * @param p_cp the coding parameters. + * @param tileno the tile index of the tile being encoded. + * @param p_tx0 pointer that will hold the X0 parameter for the tile + * @param p_tx1 pointer that will hold the X1 parameter for the tile + * @param p_ty0 pointer that will hold the Y0 parameter for the tile + * @param p_ty1 pointer that will hold the Y1 parameter for the tile + * @param p_max_prec pointer that will hold the the maximum precision for all the bands of the tile + * @param p_max_res pointer that will hold the the maximum number of resolutions for all the poc inside the tile. + * @param dx_min pointer that will hold the the minimum dx of all the components of all the resolutions for the tile. + * @param dy_min pointer that will hold the the minimum dy of all the components of all the resolutions for the tile. + * @param p_resolutions pointer to an area corresponding to the one described above. + */ +void get_all_encoding_parameters( + const opj_image_t *p_image, + const opj_cp_t *p_cp, + OPJ_UINT32 tileno, + OPJ_INT32 * p_tx0, + OPJ_INT32 * p_tx1, + OPJ_INT32 * p_ty0, + OPJ_INT32 * p_ty1, + OPJ_UINT32 * p_dx_min, + OPJ_UINT32 * p_dy_min, + OPJ_UINT32 * p_max_prec, + OPJ_UINT32 * p_max_res, + OPJ_UINT32 ** p_resolutions + ) +{ + // loop + OPJ_UINT32 compno, resno; + + // pointers + const opj_tcp_t *tcp = 00; + const opj_tccp_t * l_tccp = 00; + const opj_image_comp_t * l_img_comp = 00; + + // to store l_dx, l_dy, w and h for each resolution and component. + OPJ_UINT32 * lResolutionPtr; + + // position in x and y of tile + OPJ_UINT32 p, q; + + // preconditions in debug + assert(p_cp != 00); + assert(p_image != 00); + assert(tileno < p_cp->tw * p_cp->th); + + // initializations + tcp = &p_cp->tcps [tileno]; + l_tccp = tcp->tccps; + l_img_comp = p_image->comps; + + // position in x and y of tile + + p = tileno % p_cp->tw; + q = tileno / p_cp->tw; + + /* here calculation of tx0, tx1, ty0, ty1, maxprec, l_dx and l_dy */ + *p_tx0 = int_max(p_cp->tx0 + p * p_cp->tdx, p_image->x0); + *p_tx1 = int_min(p_cp->tx0 + (p + 1) * p_cp->tdx, p_image->x1); + *p_ty0 = int_max(p_cp->ty0 + q * p_cp->tdy, p_image->y0); + *p_ty1 = int_min(p_cp->ty0 + (q + 1) * p_cp->tdy, p_image->y1); + + // max precision and resolution is 0 (can only grow) + *p_max_prec = 0; + *p_max_res = 0; + + // take the largest value for dx_min and dy_min + *p_dx_min = 0x7fffffff; + *p_dy_min = 0x7fffffff; + + for + (compno = 0; compno < p_image->numcomps; ++compno) + { + // aritmetic variables to calculate + OPJ_UINT32 l_level_no; + OPJ_INT32 l_rx0, l_ry0, l_rx1, l_ry1; + OPJ_INT32 l_px0, l_py0, l_px1, py1; + OPJ_UINT32 l_product; + OPJ_INT32 l_tcx0, l_tcy0, l_tcx1, l_tcy1; + OPJ_UINT32 l_pdx, l_pdy , l_pw , l_ph; + + lResolutionPtr = p_resolutions[compno]; + + l_tcx0 = int_ceildiv(*p_tx0, l_img_comp->dx); + l_tcy0 = int_ceildiv(*p_ty0, l_img_comp->dy); + l_tcx1 = int_ceildiv(*p_tx1, l_img_comp->dx); + l_tcy1 = int_ceildiv(*p_ty1, l_img_comp->dy); + if + (l_tccp->numresolutions > *p_max_res) + { + *p_max_res = l_tccp->numresolutions; + } + + // use custom size for precincts + l_level_no = l_tccp->numresolutions - 1; + for + (resno = 0; resno < l_tccp->numresolutions; ++resno) + { + OPJ_UINT32 l_dx, l_dy; + // precinct width and height + l_pdx = l_tccp->prcw[resno]; + l_pdy = l_tccp->prch[resno]; + *lResolutionPtr++ = l_pdx; + *lResolutionPtr++ = l_pdy; + l_dx = l_img_comp->dx * (1 << (l_pdx + l_level_no)); + l_dy = l_img_comp->dy * (1 << (l_pdy + l_level_no)); + // take the minimum size for l_dx for each comp and resolution + *p_dx_min = int_min(*p_dx_min, l_dx); + *p_dy_min = int_min(*p_dy_min, l_dy); + // various calculations of extents + + l_rx0 = int_ceildivpow2(l_tcx0, l_level_no); + l_ry0 = int_ceildivpow2(l_tcy0, l_level_no); + l_rx1 = int_ceildivpow2(l_tcx1, l_level_no); + l_ry1 = int_ceildivpow2(l_tcy1, l_level_no); + l_px0 = int_floordivpow2(l_rx0, l_pdx) << l_pdx; + l_py0 = int_floordivpow2(l_ry0, l_pdy) << l_pdy; + l_px1 = int_ceildivpow2(l_rx1, l_pdx) << l_pdx; + py1 = int_ceildivpow2(l_ry1, l_pdy) << l_pdy; + l_pw = (l_rx0==l_rx1)?0:((l_px1 - l_px0) >> l_pdx); + l_ph = (l_ry0==l_ry1)?0:((py1 - l_py0) >> l_pdy); + *lResolutionPtr++ = l_pw; + *lResolutionPtr++ = l_ph; + l_product = l_pw * l_ph; + // update precision + if + (l_product > *p_max_prec) + { + *p_max_prec = l_product; + } + --l_level_no; + } + ++l_tccp; + ++l_img_comp; + } +} + +/** + * Allocates memory for a packet iterator. Data and data sizes are set by this operation. + * No other data is set. The include section of the packet iterator is not allocated. + * + * @param p_image the image used to initialize the packet iterator (in fact only the number of components is relevant. + * @param p_cp the coding parameters. + * @param p_tile_no the index of the tile from which creating the packet iterator. + */ +opj_pi_iterator_t * pi_create( + const opj_image_t *image, + const opj_cp_t *cp, + OPJ_UINT32 tileno + ) +{ + // loop + OPJ_UINT32 pino, compno; + // number of poc in the p_pi + OPJ_UINT32 l_poc_bound; + + // pointers to tile coding parameters and components. + opj_pi_iterator_t *l_pi = 00; + opj_tcp_t *tcp = 00; + const opj_tccp_t *tccp = 00; + + // current packet iterator being allocated + opj_pi_iterator_t *l_current_pi = 00; + + // preconditions in debug + assert(cp != 00); + assert(image != 00); + assert(tileno < cp->tw * cp->th); + + // initializations + tcp = &cp->tcps[tileno]; + l_poc_bound = tcp->numpocs+1; + + + // memory allocations + l_pi = (opj_pi_iterator_t*) opj_calloc((l_poc_bound), sizeof(opj_pi_iterator_t)); + + if + (!l_pi) + { + return 00; + } + memset(l_pi,0,l_poc_bound * sizeof(opj_pi_iterator_t)); + l_current_pi = l_pi; + for + (pino = 0; pino < l_poc_bound ; ++pino) + { + l_current_pi->comps = (opj_pi_comp_t*) opj_calloc(image->numcomps, sizeof(opj_pi_comp_t)); + if + (! l_current_pi->comps) + { + pi_destroy(l_pi, l_poc_bound); + return 00; + } + l_current_pi->numcomps = image->numcomps; + memset(l_current_pi->comps,0,image->numcomps * sizeof(opj_pi_comp_t)); + for + (compno = 0; compno < image->numcomps; ++compno) + { + opj_pi_comp_t *comp = &l_current_pi->comps[compno]; + tccp = &tcp->tccps[compno]; + comp->resolutions = (opj_pi_resolution_t*) opj_malloc(tccp->numresolutions * sizeof(opj_pi_resolution_t)); + if + (!comp->resolutions) + { + pi_destroy(l_pi, l_poc_bound); + return 00; + } + comp->numresolutions = tccp->numresolutions; + memset(comp->resolutions,0,tccp->numresolutions * sizeof(opj_pi_resolution_t)); + } + ++l_current_pi; + } + return l_pi; +} + +/** + * Updates the coding parameters if the encoding is used with Progression order changes and final (or cinema parameters are used). + * + * @param p_cp the coding parameters to modify + * @param p_tileno the tile index being concerned. + * @param p_tx0 X0 parameter for the tile + * @param p_tx1 X1 parameter for the tile + * @param p_ty0 Y0 parameter for the tile + * @param p_ty1 Y1 parameter for the tile + * @param p_max_prec the maximum precision for all the bands of the tile + * @param p_max_res the maximum number of resolutions for all the poc inside the tile. + * @param dx_min the minimum dx of all the components of all the resolutions for the tile. + * @param dy_min the minimum dy of all the components of all the resolutions for the tile. + */ +void pi_update_encode_poc_and_final ( + opj_cp_t *p_cp, + OPJ_UINT32 p_tileno, + OPJ_INT32 p_tx0, + OPJ_INT32 p_tx1, + OPJ_INT32 p_ty0, + OPJ_INT32 p_ty1, + OPJ_UINT32 p_max_prec, + OPJ_UINT32 p_max_res, + OPJ_UINT32 p_dx_min, + OPJ_UINT32 p_dy_min) +{ + // loop + OPJ_UINT32 pino; + // tile coding parameter + opj_tcp_t *l_tcp = 00; + // current poc being updated + opj_poc_t * l_current_poc = 00; + + // number of pocs + OPJ_UINT32 l_poc_bound; + + // preconditions in debug + assert(p_cp != 00); + assert(p_tileno < p_cp->tw * p_cp->th); + + // initializations + l_tcp = &p_cp->tcps [p_tileno]; + /* number of iterations in the loop */ + l_poc_bound = l_tcp->numpocs+1; + + // start at first element, and to make sure the compiler will not make a calculation each time in the loop + // store a pointer to the current element to modify rather than l_tcp->pocs[i] + l_current_poc = l_tcp->pocs; + + l_current_poc->compS = l_current_poc->compno0; + l_current_poc->compE = l_current_poc->compno1; + l_current_poc->resS = l_current_poc->resno0; + l_current_poc->resE = l_current_poc->resno1; + l_current_poc->layE = l_current_poc->layno1; + + // special treatment for the first element + l_current_poc->layS = 0; + l_current_poc->prg = l_current_poc->prg1; + l_current_poc->prcS = 0; + + l_current_poc->prcE = p_max_prec; + l_current_poc->txS = p_tx0; + l_current_poc->txE = p_tx1; + l_current_poc->tyS = p_ty0; + l_current_poc->tyE = p_ty1; + l_current_poc->dx = p_dx_min; + l_current_poc->dy = p_dy_min; + + ++ l_current_poc; + for + (pino = 1;pino < l_poc_bound ; ++pino) + { + l_current_poc->compS = l_current_poc->compno0; + l_current_poc->compE= l_current_poc->compno1; + l_current_poc->resS = l_current_poc->resno0; + l_current_poc->resE = l_current_poc->resno1; + l_current_poc->layE = l_current_poc->layno1; + l_current_poc->prg = l_current_poc->prg1; + l_current_poc->prcS = 0; + // special treatment here different from the first element + l_current_poc->layS = (l_current_poc->layE > (l_current_poc-1)->layE) ? l_current_poc->layE : 0; + + l_current_poc->prcE = p_max_prec; + l_current_poc->txS = p_tx0; + l_current_poc->txE = p_tx1; + l_current_poc->tyS = p_ty0; + l_current_poc->tyE = p_ty1; + l_current_poc->dx = p_dx_min; + l_current_poc->dy = p_dy_min; + ++ l_current_poc; + } +} + +/** + * Updates the coding parameters if the encoding is not used with Progression order changes and final (and cinema parameters are used). + * + * @param p_cp the coding parameters to modify + * @param p_tileno the tile index being concerned. + * @param p_tx0 X0 parameter for the tile + * @param p_tx1 X1 parameter for the tile + * @param p_ty0 Y0 parameter for the tile + * @param p_ty1 Y1 parameter for the tile + * @param p_max_prec the maximum precision for all the bands of the tile + * @param p_max_res the maximum number of resolutions for all the poc inside the tile. + * @param dx_min the minimum dx of all the components of all the resolutions for the tile. + * @param dy_min the minimum dy of all the components of all the resolutions for the tile. + */ +void pi_update_encode_not_poc ( + opj_cp_t *p_cp, + OPJ_UINT32 p_num_comps, + OPJ_UINT32 p_tileno, + OPJ_INT32 p_tx0, + OPJ_INT32 p_tx1, + OPJ_INT32 p_ty0, + OPJ_INT32 p_ty1, + OPJ_UINT32 p_max_prec, + OPJ_UINT32 p_max_res, + OPJ_UINT32 p_dx_min, + OPJ_UINT32 p_dy_min) +{ + // loop + OPJ_UINT32 pino; + // tile coding parameter + opj_tcp_t *l_tcp = 00; + // current poc being updated + opj_poc_t * l_current_poc = 00; + // number of pocs + OPJ_UINT32 l_poc_bound; + + // preconditions in debug + assert(p_cp != 00); + assert(p_tileno < p_cp->tw * p_cp->th); + + // initializations + l_tcp = &p_cp->tcps [p_tileno]; + + /* number of iterations in the loop */ + l_poc_bound = l_tcp->numpocs+1; + + // start at first element, and to make sure the compiler will not make a calculation each time in the loop + // store a pointer to the current element to modify rather than l_tcp->pocs[i] + l_current_poc = l_tcp->pocs; + + for + (pino = 0; pino < l_poc_bound ; ++pino) + { + l_current_poc->compS = 0; + l_current_poc->compE = p_num_comps;/*p_image->numcomps;*/ + l_current_poc->resS = 0; + l_current_poc->resE = p_max_res; + l_current_poc->layS = 0; + l_current_poc->layE = l_tcp->numlayers; + l_current_poc->prg = l_tcp->prg; + l_current_poc->prcS = 0; + l_current_poc->prcE = p_max_prec; + l_current_poc->txS = p_tx0; + l_current_poc->txE = p_tx1; + l_current_poc->tyS = p_ty0; + l_current_poc->tyE = p_ty1; + l_current_poc->dx = p_dx_min; + l_current_poc->dy = p_dy_min; + ++ l_current_poc; + } +} + +/** + * Destroys a packet iterator array. + * + * @param p_pi the packet iterator array to destroy. + * @param p_nb_elements the number of elements in the array. + */ +void pi_destroy( + opj_pi_iterator_t *p_pi, + OPJ_UINT32 p_nb_elements) +{ + OPJ_UINT32 compno, pino; + opj_pi_iterator_t *l_current_pi = p_pi; + if + (p_pi) + { + if + (p_pi->include) + { + opj_free(p_pi->include); + p_pi->include = 00; + } + // TODO + for + (pino = 0; pino < p_nb_elements; ++pino) + { + if + (l_current_pi->comps) + { + opj_pi_comp_t *l_current_component = l_current_pi->comps; + for + (compno = 0; compno < l_current_pi->numcomps; compno++) + { + if + (l_current_component->resolutions) + { + opj_free(l_current_component->resolutions); + l_current_component->resolutions = 00; + } + ++l_current_component; + } + opj_free(l_current_pi->comps); + l_current_pi->comps = 0; + } + ++l_current_pi; + } + opj_free(p_pi); + } +} + +bool pi_next(opj_pi_iterator_t * pi) { + switch (pi->poc.prg) { + case LRCP: + return pi_next_lrcp(pi); + case RLCP: + return pi_next_rlcp(pi); + case RPCL: + return pi_next_rpcl(pi); + case PCRL: + return pi_next_pcrl(pi); + case CPRL: + return pi_next_cprl(pi); + case PROG_UNKNOWN: + return false; + } + + return false; +} + +OPJ_INT32 pi_check_next_level(OPJ_INT32 pos,opj_cp_t *cp,OPJ_UINT32 tileno, OPJ_UINT32 pino, const OPJ_CHAR *prog) +{ + OPJ_INT32 i,l; + opj_tcp_t *tcps =&cp->tcps[tileno]; + opj_poc_t *tcp = &tcps->pocs[pino]; + if(pos>=0){ + for(i=pos;pos>=0;i--){ + switch(prog[i]){ + case 'R': + if(tcp->res_t==tcp->resE){ + l=pi_check_next_level(pos-1,cp,tileno,pino,prog); + if(l==1){ + return 1; + }else{ + return 0; + } + }else{ + return 1; + } + break; + case 'C': + if(tcp->comp_t==tcp->compE){ + l=pi_check_next_level(pos-1,cp,tileno,pino,prog); + if(l==1){ + return 1; + }else{ + return 0; + } + }else{ + return 1; + } + break; + case 'L': + if(tcp->lay_t==tcp->layE){ + l=pi_check_next_level(pos-1,cp,tileno,pino,prog); + if(l==1){ + return 1; + }else{ + return 0; + } + }else{ + return 1; + } + break; + case 'P': + switch(tcp->prg){ + case LRCP||RLCP: + if(tcp->prc_t == tcp->prcE){ + l=pi_check_next_level(i-1,cp,tileno,pino,prog); + if(l==1){ + return 1; + }else{ + return 0; + } + }else{ + return 1; + } + break; + default: + if(tcp->tx0_t == tcp->txE){ + //TY + if(tcp->ty0_t == tcp->tyE){ + l=pi_check_next_level(i-1,cp,tileno,pino,prog); + if(l==1){ + return 1; + }else{ + return 0; + } + }else{ + return 1; + }//TY + }else{ + return 1; + } + break; + }//end case P + }//end switch + }//end for + }//end if + return 0; +} + + +void pi_create_encode( opj_pi_iterator_t *pi, opj_cp_t *cp,OPJ_UINT32 tileno, OPJ_UINT32 pino,OPJ_UINT32 tpnum, OPJ_INT32 tppos, J2K_T2_MODE t2_mode) +{ + const OPJ_CHAR *prog; + OPJ_INT32 i,l; + OPJ_UINT32 incr_top=1,resetX=0; + opj_tcp_t *tcps =&cp->tcps[tileno]; + opj_poc_t *tcp= &tcps->pocs[pino]; + + prog = j2k_convert_progression_order(tcp->prg); + + pi[pino].first = 1; + pi[pino].poc.prg = tcp->prg; + + if(!(cp->m_specific_param.m_enc.m_tp_on&& ((!cp->m_specific_param.m_enc.m_cinema && (t2_mode == FINAL_PASS)) || cp->m_specific_param.m_enc.m_cinema))){ + pi[pino].poc.resno0 = tcp->resS; + pi[pino].poc.resno1 = tcp->resE; + pi[pino].poc.compno0 = tcp->compS; + pi[pino].poc.compno1 = tcp->compE; + pi[pino].poc.layno0 = tcp->layS; + pi[pino].poc.layno1 = tcp->layE; + pi[pino].poc.precno0 = tcp->prcS; + pi[pino].poc.precno1 = tcp->prcE; + pi[pino].poc.tx0 = tcp->txS; + pi[pino].poc.ty0 = tcp->tyS; + pi[pino].poc.tx1 = tcp->txE; + pi[pino].poc.ty1 = tcp->tyE; + }else { + for(i=tppos+1;i<4;i++){ + switch(prog[i]){ + case 'R': + pi[pino].poc.resno0 = tcp->resS; + pi[pino].poc.resno1 = tcp->resE; + break; + case 'C': + pi[pino].poc.compno0 = tcp->compS; + pi[pino].poc.compno1 = tcp->compE; + break; + case 'L': + pi[pino].poc.layno0 = tcp->layS; + pi[pino].poc.layno1 = tcp->layE; + break; + case 'P': + switch(tcp->prg){ + case LRCP: + case RLCP: + pi[pino].poc.precno0 = tcp->prcS; + pi[pino].poc.precno1 = tcp->prcE; + break; + default: + pi[pino].poc.tx0 = tcp->txS; + pi[pino].poc.ty0 = tcp->tyS; + pi[pino].poc.tx1 = tcp->txE; + pi[pino].poc.ty1 = tcp->tyE; + break; + } + break; + } + } + + if(tpnum==0){ + for(i=tppos;i>=0;i--){ + switch(prog[i]){ + case 'C': + tcp->comp_t = tcp->compS; + pi[pino].poc.compno0 = tcp->comp_t; + pi[pino].poc.compno1 = tcp->comp_t+1; + tcp->comp_t+=1; + break; + case 'R': + tcp->res_t = tcp->resS; + pi[pino].poc.resno0 = tcp->res_t; + pi[pino].poc.resno1 = tcp->res_t+1; + tcp->res_t+=1; + break; + case 'L': + tcp->lay_t = tcp->layS; + pi[pino].poc.layno0 = tcp->lay_t; + pi[pino].poc.layno1 = tcp->lay_t+1; + tcp->lay_t+=1; + break; + case 'P': + switch(tcp->prg){ + case LRCP: + case RLCP: + tcp->prc_t = tcp->prcS; + pi[pino].poc.precno0 = tcp->prc_t; + pi[pino].poc.precno1 = tcp->prc_t+1; + tcp->prc_t+=1; + break; + default: + tcp->tx0_t = tcp->txS; + tcp->ty0_t = tcp->tyS; + pi[pino].poc.tx0 = tcp->tx0_t; + pi[pino].poc.tx1 = tcp->tx0_t + tcp->dx - (tcp->tx0_t % tcp->dx); + pi[pino].poc.ty0 = tcp->ty0_t; + pi[pino].poc.ty1 = tcp->ty0_t + tcp->dy - (tcp->ty0_t % tcp->dy); + tcp->tx0_t = pi[pino].poc.tx1; + tcp->ty0_t = pi[pino].poc.ty1; + break; + } + break; + } + } + incr_top=1; + }else{ + for(i=tppos;i>=0;i--){ + switch(prog[i]){ + case 'C': + pi[pino].poc.compno0 = tcp->comp_t-1; + pi[pino].poc.compno1 = tcp->comp_t; + break; + case 'R': + pi[pino].poc.resno0 = tcp->res_t-1; + pi[pino].poc.resno1 = tcp->res_t; + break; + case 'L': + pi[pino].poc.layno0 = tcp->lay_t-1; + pi[pino].poc.layno1 = tcp->lay_t; + break; + case 'P': + switch(tcp->prg){ + case LRCP: + case RLCP: + pi[pino].poc.precno0 = tcp->prc_t-1; + pi[pino].poc.precno1 = tcp->prc_t; + break; + default: + pi[pino].poc.tx0 = tcp->tx0_t - tcp->dx - (tcp->tx0_t % tcp->dx); + pi[pino].poc.tx1 = tcp->tx0_t ; + pi[pino].poc.ty0 = tcp->ty0_t - tcp->dy - (tcp->ty0_t % tcp->dy); + pi[pino].poc.ty1 = tcp->ty0_t ; + break; + } + break; + } + if(incr_top==1){ + switch(prog[i]){ + case 'R': + if(tcp->res_t==tcp->resE){ + l=pi_check_next_level(i-1,cp,tileno,pino,prog); + if(l==1){ + tcp->res_t = tcp->resS; + pi[pino].poc.resno0 = tcp->res_t; + pi[pino].poc.resno1 = tcp->res_t+1; + tcp->res_t+=1; + incr_top=1; + }else{ + incr_top=0; + } + }else{ + pi[pino].poc.resno0 = tcp->res_t; + pi[pino].poc.resno1 = tcp->res_t+1; + tcp->res_t+=1; + incr_top=0; + } + break; + case 'C': + if(tcp->comp_t ==tcp->compE){ + l=pi_check_next_level(i-1,cp,tileno,pino,prog); + if(l==1){ + tcp->comp_t = tcp->compS; + pi[pino].poc.compno0 = tcp->comp_t; + pi[pino].poc.compno1 = tcp->comp_t+1; + tcp->comp_t+=1; + incr_top=1; + }else{ + incr_top=0; + } + }else{ + pi[pino].poc.compno0 = tcp->comp_t; + pi[pino].poc.compno1 = tcp->comp_t+1; + tcp->comp_t+=1; + incr_top=0; + } + break; + case 'L': + if(tcp->lay_t == tcp->layE){ + l=pi_check_next_level(i-1,cp,tileno,pino,prog); + if(l==1){ + tcp->lay_t = tcp->layS; + pi[pino].poc.layno0 = tcp->lay_t; + pi[pino].poc.layno1 = tcp->lay_t+1; + tcp->lay_t+=1; + incr_top=1; + }else{ + incr_top=0; + } + }else{ + pi[pino].poc.layno0 = tcp->lay_t; + pi[pino].poc.layno1 = tcp->lay_t+1; + tcp->lay_t+=1; + incr_top=0; + } + break; + case 'P': + switch(tcp->prg){ + case LRCP: + case RLCP: + if(tcp->prc_t == tcp->prcE){ + l=pi_check_next_level(i-1,cp,tileno,pino,prog); + if(l==1){ + tcp->prc_t = tcp->prcS; + pi[pino].poc.precno0 = tcp->prc_t; + pi[pino].poc.precno1 = tcp->prc_t+1; + tcp->prc_t+=1; + incr_top=1; + }else{ + incr_top=0; + } + }else{ + pi[pino].poc.precno0 = tcp->prc_t; + pi[pino].poc.precno1 = tcp->prc_t+1; + tcp->prc_t+=1; + incr_top=0; + } + break; + default: + if(tcp->tx0_t >= tcp->txE){ + if(tcp->ty0_t >= tcp->tyE){ + l=pi_check_next_level(i-1,cp,tileno,pino,prog); + if(l==1){ + tcp->ty0_t = tcp->tyS; + pi[pino].poc.ty0 = tcp->ty0_t; + pi[pino].poc.ty1 = tcp->ty0_t + tcp->dy - (tcp->ty0_t % tcp->dy); + tcp->ty0_t = pi[pino].poc.ty1; + incr_top=1;resetX=1; + }else{ + incr_top=0;resetX=0; + } + }else{ + pi[pino].poc.ty0 = tcp->ty0_t; + pi[pino].poc.ty1 = tcp->ty0_t + tcp->dy - (tcp->ty0_t % tcp->dy); + tcp->ty0_t = pi[pino].poc.ty1; + incr_top=0;resetX=1; + } + if(resetX==1){ + tcp->tx0_t = tcp->txS; + pi[pino].poc.tx0 = tcp->tx0_t; + pi[pino].poc.tx1 = tcp->tx0_t + tcp->dx- (tcp->tx0_t % tcp->dx); + tcp->tx0_t = pi[pino].poc.tx1; + } + }else{ + pi[pino].poc.tx0 = tcp->tx0_t; + pi[pino].poc.tx1 = tcp->tx0_t + tcp->dx- (tcp->tx0_t % tcp->dx); + tcp->tx0_t = pi[pino].poc.tx1; + incr_top=0; + } + break; + } + break; + } + } + } + } + } +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/pi.h b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/pi.h new file mode 100644 index 0000000..0ddd0ba --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/pi.h @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __PI_H +#define __PI_H +/** +@file pi.h +@brief Implementation of a packet iterator (PI) + +The functions in PI.C have for goal to realize a packet iterator that permits to get the next +packet following the progression order and change of it. The functions in PI.C are used +by some function in T2.C. +*/ +#include "openjpeg.h" +#include "t2.h" +/** @defgroup PI PI - Implementation of a packet iterator */ +/*@{*/ +struct opj_poc; +struct opj_image; +struct opj_cp; + +/** +FIXME: documentation +*/ +typedef struct opj_pi_resolution { + OPJ_UINT32 pdx, pdy; + OPJ_UINT32 pw, ph; +} opj_pi_resolution_t; + +/** +FIXME: documentation +*/ +typedef struct opj_pi_comp { + OPJ_UINT32 dx, dy; + /** number of resolution levels */ + OPJ_UINT32 numresolutions; + opj_pi_resolution_t *resolutions; +} opj_pi_comp_t; + +/** +Packet iterator +*/ +typedef struct opj_pi_iterator { + /** Enabling Tile part generation*/ + OPJ_BYTE tp_on; + /** precise if the packet has been already used (usefull for progression order change) */ + OPJ_INT16 *include; + /** layer step used to localize the packet in the include vector */ + OPJ_UINT32 step_l; + /** resolution step used to localize the packet in the include vector */ + OPJ_UINT32 step_r; + /** component step used to localize the packet in the include vector */ + OPJ_UINT32 step_c; + /** precinct step used to localize the packet in the include vector */ + OPJ_UINT32 step_p; + /** component that identify the packet */ + OPJ_UINT32 compno; + /** resolution that identify the packet */ + OPJ_UINT32 resno; + /** precinct that identify the packet */ + OPJ_UINT32 precno; + /** layer that identify the packet */ + OPJ_UINT32 layno; + /** progression order change information */ + struct opj_poc poc; + /** number of components in the image */ + OPJ_UINT32 numcomps; + /** Components*/ + opj_pi_comp_t *comps; + OPJ_INT32 tx0, ty0, tx1, ty1; + OPJ_INT32 x, y; + OPJ_UINT32 dx, dy; + /** 0 if the first packet */ + OPJ_UINT32 first : 1; +} opj_pi_iterator_t; + +/** @name Exported functions */ +/*@{*/ +/* ----------------------------------------------------------------------- */ +/** + * Creates a packet iterator for encoding. + * + * @param p_image the image being encoded. + * @param p_cp the coding parameters. + * @param p_tile_no index of the tile being encoded. + * @param p_t2_mode the type of pass for generating the packet iterator + * @return a list of packet iterator that points to the first packet of the tile (not true). +*/ +opj_pi_iterator_t *pi_initialise_encode(const struct opj_image *image,struct opj_cp *cp, OPJ_UINT32 tileno,J2K_T2_MODE t2_mode); + +/** + * Updates the encoding parameters of the codec. + * + * @param p_image the image being encoded. + * @param p_cp the coding parameters. + * @param p_tile_no index of the tile being encoded. +*/ +void pi_update_encoding_parameters( + const struct opj_image *p_image, + struct opj_cp *p_cp, + OPJ_UINT32 p_tile_no + ); + + + +/** +Modify the packet iterator for enabling tile part generation +@param pi Handle to the packet iterator generated in pi_initialise_encode +@param cp Coding parameters +@param tileno Number that identifies the tile for which to list the packets +@param tpnum Tile part number of the current tile +@param tppos The position of the tile part flag in the progression order +*/ +void pi_create_encode( opj_pi_iterator_t *pi, struct opj_cp *cp,OPJ_UINT32 tileno, OPJ_UINT32 pino,OPJ_UINT32 tpnum, OPJ_INT32 tppos, J2K_T2_MODE t2_mode); + + +/** +Create a packet iterator for Decoder +@param image Raw image for which the packets will be listed +@param cp Coding parameters +@param tileno Number that identifies the tile for which to list the packets +@return Returns a packet iterator that points to the first packet of the tile +@see pi_destroy +*/ +opj_pi_iterator_t *pi_create_decode(struct opj_image * image, struct opj_cp * cp, OPJ_UINT32 tileno); + + + +/** + * Destroys a packet iterator array. + * + * @param p_pi the packet iterator array to destroy. + * @param p_nb_elements the number of elements in the array. + */ +void pi_destroy( + opj_pi_iterator_t *p_pi, + OPJ_UINT32 p_nb_elements); + +/** +Modify the packet iterator to point to the next packet +@param pi Packet iterator to modify +@return Returns false if pi pointed to the last packet or else returns true +*/ +bool pi_next(opj_pi_iterator_t * pi); + + +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __PI_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/profile.c b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/profile.c new file mode 100644 index 0000000..398fb4a --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/profile.c @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * Adapted from Herb Marselas +"Profiling, Data Analysis, Scalability, and Magic Numbers: Meeting the Minimum System Requirements for AGE OF EMPIRES 2: THE AGE OF KINGS" +Game Developer magazine +June, 2000 issue. +*/ + +#include "profile.h" +#include +#include +#include +//============================================================================== +static OPJ_PROFILE_LIST group_list [PGROUP_LASTGROUP]; + +//============================================================================== +static void GetTimeStamp(OPJ_UINT32 *pdwtime); + +//============================================================================== +#define SetMajorSection(entry, major) \ + { group_list[ entry ].section = entry ; \ + group_list[ entry ].sectionName = #major ; } + +//============================================================================== +void _ProfInit(void) +{ + // clear everything out + memset(group_list, 0, sizeof(group_list)); + + // set groups and parents for timing + SetMajorSection(PGROUP_DWT,PGROUP_DWT); + SetMajorSection(PGROUP_T1, PGROUP_T1); + SetMajorSection(PGROUP_T2, PGROUP_T2); +} // ProfInit + +//============================================================================== +void _ProfStart (OPJ_PROFILE_GROUP group) +{ + // make sure this hasn't been incorrectly started twice + if (group_list[group].start) + { + return; + } + + // get the start time + GetTimeStamp(&(group_list[group].start)); + +} // _ProfStart + +//============================================================================== +void _ProfStop(OPJ_PROFILE_GROUP group) +{ + // make sure we called start first + if (!group_list[group].start) + { + return; + } + + // get ending time + GetTimeStamp(&(group_list[group].end)); + + // calculate this latest elapsed interval + group_list[group].total_time += group_list[group].end - group_list[group].start; + + // reset starting time + group_list[group].start = 0; + + // incr the number of calls made + ++group_list[group].totalCalls; + +} // _ProfStop + +//============================================================================== +#define proftracef(id,totalTime) \ + fprintf(p, #id "\t%u\t\t%6.6f\t\t%12.6f\t%2.2f%%\n", \ + group_list[ id ].totalCalls, \ + (OPJ_FLOAT64) group_list[ id ].total_time / CLOCKS_PER_SEC, \ + ((OPJ_FLOAT64) group_list[ id ].total_time / (group_list[ id ].totalCalls ? group_list[ id ].totalCalls : 1)), \ + ((OPJ_FLOAT64) group_list[ id ].total_time / totalTime * 100)) + +#define proftracep(id,totalTime) \ + printf(#id "\t%u\t\t%6.6f\t\t%12.6f\t%2.2f%%\n", \ + group_list[ id ].totalCalls, \ + (OPJ_FLOAT64) group_list[ id ].total_time / CLOCKS_PER_SEC, \ + ((OPJ_FLOAT64) group_list[ id ].total_time / (group_list[ id ].totalCalls ? group_list[ id ].totalCalls : 1)), \ + ((OPJ_FLOAT64) group_list[ id ].total_time / totalTime * 100)) + +//============================================================================== +void _ProfSave(const OPJ_CHAR * pFileName) +{ + FILE *p = fopen(pFileName, "wt"); + OPJ_FLOAT64 totalTime = 0.; + OPJ_UINT32 i; + + if (!p) + { + return; + } + + for + (i=0;i + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * Adapted from Herb Marselas +"Profiling, Data Analysis, Scalability, and Magic Numbers: Meeting the Minimum System Requirements for AGE OF EMPIRES 2: THE AGE OF KINGS" +Game Developer magazine +June, 2000 issue. +*/ + + +#ifndef __PROFILE_H +#define __PROFILE_H + +#include "openjpeg.h" +//============================================================================== +typedef enum +{ + PGROUP_RATE, + PGROUP_DC_SHIFT, + PGROUP_MCT, + PGROUP_DWT, + PGROUP_T1, + PGROUP_T2, + PGROUP_LASTGROUP +} OPJ_PROFILE_GROUP; + +//============================================================================== +typedef struct PROFILELIST +{ + OPJ_UINT32 start; + OPJ_UINT32 end; + OPJ_UINT32 total_time; + OPJ_UINT32 totalCalls; + OPJ_PROFILE_GROUP section; + const OPJ_CHAR *sectionName; // string name of the profile group +} OPJ_PROFILE_LIST; + +//============================================================================== +void _ProfStart(OPJ_PROFILE_GROUP group); +void _ProfStop (OPJ_PROFILE_GROUP group); + +//============================================================================== +//============================================================================== +#ifdef _PROFILE +#define PROFINIT() _ProfInit(); +#define PROFSTART (group) _ProfStart (group); +#define PROFSTOP (group) _ProfStop (group); +#define PROFSAVE(file) _ProfSave(file); +#define PROFPRINT() _ProfPrint(); +#else +#define PROFINIT() +#define PROFSTART(group) +#define PROFSTOP (group) +#define PROFSAVE(file) +#define PROFPRINT() +#endif // !_PROFILE + +//============================================================================== +#endif // __PROFILE_H diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/raw.c b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/raw.c new file mode 100644 index 0000000..b3466dc --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/raw.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "raw.h" +#include "opj_malloc.h" + +/* +========================================================== + local functions +========================================================== +*/ + + +/* +========================================================== + RAW encoding interface +========================================================== +*/ + +opj_raw_t* raw_create(void) { + opj_raw_t *raw = (opj_raw_t*)opj_malloc(sizeof(opj_raw_t)); + return raw; +} + +void raw_destroy(opj_raw_t *raw) { + if(raw) { + opj_free(raw); + } +} + +OPJ_UINT32 raw_numbytes(opj_raw_t *raw) { + return raw->bp - raw->start; +} + +void raw_init_dec(opj_raw_t *raw, OPJ_BYTE *bp, OPJ_UINT32 len) { + raw->start = bp; + raw->lenmax = len; + raw->len = 0; + raw->c = 0; + raw->ct = 0; +} + +OPJ_UINT32 raw_decode(opj_raw_t *raw) { + OPJ_UINT32 d; + if (raw->ct == 0) { + raw->ct = 8; + if (raw->len == raw->lenmax) { + raw->c = 0xff; + } else { + if (raw->c == 0xff) { + raw->ct = 7; + } + raw->c = *(raw->start + raw->len); + raw->len++; + } + } + raw->ct--; + d = (raw->c >> raw->ct) & 0x01; + + return d; +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/raw.h b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/raw.h new file mode 100644 index 0000000..7f02052 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/raw.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __RAW_H +#define __RAW_H +/** +@file raw.h +@brief Implementation of operations for raw encoding (RAW) + +The functions in RAW.C have for goal to realize the operation of raw encoding linked +with the corresponding mode switch. +*/ +#include "openjpeg.h" +/** @defgroup RAW RAW - Implementation of operations for raw encoding */ +/*@{*/ + +/** +RAW encoding operations +*/ +typedef struct opj_raw { + /** temporary buffer where bits are coded or decoded */ + OPJ_BYTE c; + /** number of bits already read or free to write */ + OPJ_UINT32 ct; + /** maximum length to decode */ + OPJ_UINT32 lenmax; + /** length decoded */ + OPJ_UINT32 len; + /** pointer to the current position in the buffer */ + OPJ_BYTE *bp; + /** pointer to the start of the buffer */ + OPJ_BYTE *start; + /** pointer to the end of the buffer */ + unsigned char *end; +} opj_raw_t; + +/** @name Exported functions */ +/*@{*/ +/* ----------------------------------------------------------------------- */ +/** +Create a new RAW handle +@return Returns a new RAW handle if successful, returns NULL otherwise +*/ +opj_raw_t* raw_create(void); +/** +Destroy a previously created RAW handle +@param raw RAW handle to destroy +*/ +void raw_destroy(opj_raw_t *raw); +/** +Return the number of bytes written/read since initialisation +@param raw RAW handle to destroy +@return Returns the number of bytes already encoded +*/ +OPJ_UINT32 raw_numbytes(opj_raw_t *raw); +/** +Initialize the decoder +@param raw RAW handle +@param bp Pointer to the start of the buffer from which the bytes will be read +@param len Length of the input buffer +*/ +void raw_init_dec(opj_raw_t *raw, OPJ_BYTE *bp, OPJ_UINT32 len); +/** +Decode a symbol using raw-decoder. Cfr p.506 TAUBMAN +@param raw RAW handle +@return Returns the decoded symbol (0 or 1) +*/ +OPJ_UINT32 raw_decode(opj_raw_t *raw); +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __RAW_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/t1.c b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/t1.c new file mode 100644 index 0000000..68e2e53 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/t1.c @@ -0,0 +1,1284 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2007, Callum Lerwick + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "t1.h" +#include "t1_luts.h" +#include "opj_includes.h" +#include "j2k.h" +#include "tcd.h" +#include "mqc.h" +#include "raw.h" +#include "opj_malloc.h" +#include "int.h" +#include "dwt.h" +#include "fix.h" +/** @defgroup T1 T1 - Implementation of the tier-1 coding */ +/*@{*/ + +/** @name Local static functions */ +/*@{*/ + +static INLINE OPJ_BYTE t1_getctxno_zc(OPJ_UINT32 f, OPJ_UINT32 orient); +static OPJ_BYTE t1_getctxno_sc(OPJ_UINT32 f); +static INLINE OPJ_UINT32 t1_getctxno_mag(OPJ_UINT32 f); +static OPJ_BYTE t1_getspb(OPJ_UINT32 f); +static OPJ_INT16 t1_getnmsedec_sig(OPJ_UINT32 x, OPJ_UINT32 bitpos); +static OPJ_INT16 t1_getnmsedec_ref(OPJ_UINT32 x, OPJ_UINT32 bitpos); +static void t1_updateflags(flag_t *flagsp, OPJ_UINT32 s, OPJ_UINT32 stride); +/** +Encode significant pass +*/ +static void t1_enc_sigpass_step( + opj_t1_t *t1, + flag_t *flagsp, + OPJ_INT32 *datap, + OPJ_UINT32 orient, + OPJ_INT32 bpno, + OPJ_INT32 one, + OPJ_INT32 *nmsedec, + OPJ_BYTE type, + OPJ_UINT32 vsc); +/** +Decode significant pass +*/ +static void t1_dec_sigpass_step( + opj_t1_t *t1, + flag_t *flagsp, + OPJ_INT32 *datap, + OPJ_UINT32 orient, + OPJ_INT32 oneplushalf, + OPJ_BYTE type, + OPJ_UINT32 vsc); +/** +Encode significant pass +*/ +static void t1_enc_sigpass( + opj_t1_t *t1, + OPJ_INT32 bpno, + OPJ_UINT32 orient, + OPJ_INT32 *nmsedec, + OPJ_BYTE type, + OPJ_UINT32 cblksty); +/** +Decode significant pass +*/ +static void t1_dec_sigpass( + opj_t1_t *t1, + OPJ_INT32 bpno, + OPJ_UINT32 orient, + OPJ_BYTE type, + OPJ_UINT32 cblksty); +/** +Encode refinement pass +*/ +static void t1_enc_refpass_step( + opj_t1_t *t1, + flag_t *flagsp, + OPJ_INT32 *datap, + OPJ_INT32 bpno, + OPJ_INT32 one, + OPJ_INT32 *nmsedec, + OPJ_BYTE type, + OPJ_UINT32 vsc); +/** +Decode refinement pass +*/ +static void t1_dec_refpass_step( + opj_t1_t *t1, + flag_t *flagsp, + OPJ_INT32 *datap, + OPJ_INT32 poshalf, + OPJ_INT32 neghalf, + OPJ_BYTE type, + OPJ_UINT32 vsc); +/** +Encode refinement pass +*/ +static void t1_enc_refpass( + opj_t1_t *t1, + OPJ_INT32 bpno, + OPJ_INT32 *nmsedec, + OPJ_BYTE type, + OPJ_UINT32 cblksty); +/** +Decode refinement pass +*/ +static void t1_dec_refpass( + opj_t1_t *t1, + OPJ_INT32 bpno, + OPJ_BYTE type, + OPJ_UINT32 cblksty); +/** +Encode clean-up pass +*/ +static void t1_enc_clnpass_step( + opj_t1_t *t1, + flag_t *flagsp, + OPJ_INT32 *datap, + OPJ_UINT32 orient, + OPJ_INT32 bpno, + OPJ_INT32 one, + OPJ_INT32 *nmsedec, + OPJ_UINT32 partial, + OPJ_UINT32 vsc); +/** +Decode clean-up pass +*/ +static void t1_dec_clnpass_step( + opj_t1_t *t1, + flag_t *flagsp, + OPJ_INT32 *datap, + OPJ_UINT32 orient, + OPJ_INT32 oneplushalf, + OPJ_UINT32 partial, + OPJ_UINT32 vsc); +/** +Encode clean-up pass +*/ +static void t1_enc_clnpass( + opj_t1_t *t1, + OPJ_INT32 bpno, + OPJ_UINT32 orient, + OPJ_INT32 *nmsedec, + OPJ_UINT32 cblksty); +/** +Decode clean-up pass +*/ +static void t1_dec_clnpass( + opj_t1_t *t1, + OPJ_INT32 bpno, + OPJ_UINT32 orient, + OPJ_UINT32 cblksty); + +static OPJ_FLOAT64 t1_getwmsedec( + OPJ_INT32 nmsedec, + OPJ_UINT32 compno, + OPJ_UINT32 level, + OPJ_UINT32 orient, + OPJ_INT32 bpno, + OPJ_UINT32 qmfbid, + OPJ_FLOAT64 stepsize, + OPJ_UINT32 numcomps, + const OPJ_FLOAT64 * mct_norms); +/** +Encode 1 code-block +@param t1 T1 handle +@param cblk Code-block coding parameters +@param orient +@param compno Component number +@param level +@param qmfbid +@param stepsize +@param cblksty Code-block style +@param numcomps +@param tile +*/ +static void t1_encode_cblk( + opj_t1_t *t1, + opj_tcd_cblk_enc_t* cblk, + OPJ_UINT32 orient, + OPJ_UINT32 compno, + OPJ_UINT32 level, + OPJ_UINT32 qmfbid, + OPJ_FLOAT64 stepsize, + OPJ_UINT32 cblksty, + OPJ_UINT32 numcomps, + opj_tcd_tile_t * tile, + const OPJ_FLOAT64 * mct_norms); +/** +Decode 1 code-block +@param t1 T1 handle +@param cblk Code-block coding parameters +@param orient +@param roishift Region of interest shifting value +@param cblksty Code-block style +*/ +static void t1_decode_cblk( + opj_t1_t *t1, + opj_tcd_cblk_dec_t* cblk, + OPJ_UINT32 orient, + OPJ_UINT32 roishift, + OPJ_UINT32 cblksty); + +/*@}*/ + +/*@}*/ + +/* ----------------------------------------------------------------------- */ + +static OPJ_BYTE t1_getctxno_zc(OPJ_UINT32 f, OPJ_UINT32 orient) { + return lut_ctxno_zc[(orient << 8) | (f & T1_SIG_OTH)]; +} + +static OPJ_BYTE t1_getctxno_sc(OPJ_UINT32 f) { + return lut_ctxno_sc[(f & (T1_SIG_PRIM | T1_SGN)) >> 4]; +} + +static OPJ_UINT32 t1_getctxno_mag(OPJ_UINT32 f) { + OPJ_UINT32 tmp1 = (f & T1_SIG_OTH) ? T1_CTXNO_MAG + 1 : T1_CTXNO_MAG; + OPJ_UINT32 tmp2 = (f & T1_REFINE) ? T1_CTXNO_MAG + 2 : tmp1; + return (tmp2); +} + +static OPJ_BYTE t1_getspb(OPJ_UINT32 f) { + return lut_spb[(f & (T1_SIG_PRIM | T1_SGN)) >> 4]; +} + +static OPJ_INT16 t1_getnmsedec_sig(OPJ_UINT32 x, OPJ_UINT32 bitpos) +{ + if (bitpos > T1_NMSEDEC_FRACBITS) { + return lut_nmsedec_sig[(x >> (bitpos - T1_NMSEDEC_FRACBITS)) & ((1 << T1_NMSEDEC_BITS) - 1)]; + } + + return lut_nmsedec_sig0[x & ((1 << T1_NMSEDEC_BITS) - 1)]; +} + +static OPJ_INT16 t1_getnmsedec_ref(OPJ_UINT32 x, OPJ_UINT32 bitpos) { + if (bitpos > T1_NMSEDEC_FRACBITS) { + return lut_nmsedec_ref[(x >> (bitpos - T1_NMSEDEC_FRACBITS)) & ((1 << T1_NMSEDEC_BITS) - 1)]; + } + + return lut_nmsedec_ref0[x & ((1 << T1_NMSEDEC_BITS) - 1)]; +} + +static void t1_updateflags(flag_t *flagsp, OPJ_UINT32 s, OPJ_UINT32 stride) { + flag_t *np = flagsp - stride; + flag_t *sp = flagsp + stride; + + static const flag_t mod[] = { + T1_SIG_S, T1_SIG_S|T1_SGN_S, + T1_SIG_E, T1_SIG_E|T1_SGN_E, + T1_SIG_W, T1_SIG_W|T1_SGN_W, + T1_SIG_N, T1_SIG_N|T1_SGN_N + }; + + np[-1] |= T1_SIG_SE; + np[0] |= mod[s]; + np[1] |= T1_SIG_SW; + + flagsp[-1] |= mod[s+2]; + flagsp[0] |= T1_SIG; + flagsp[1] |= mod[s+4]; + + sp[-1] |= T1_SIG_NE; + sp[0] |= mod[s+6]; + sp[1] |= T1_SIG_NW; +} + +static void t1_enc_sigpass_step( + opj_t1_t *t1, + flag_t *flagsp, + OPJ_INT32 *datap, + OPJ_UINT32 orient, + OPJ_INT32 bpno, + OPJ_INT32 one, + OPJ_INT32 *nmsedec, + OPJ_BYTE type, + OPJ_UINT32 vsc) +{ + OPJ_INT32 v; + OPJ_UINT32 flag; + + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + flag = vsc ? ((*flagsp) & (~(T1_SIG_S | T1_SIG_SE | T1_SIG_SW | T1_SGN_S))) : (*flagsp); + if ((flag & T1_SIG_OTH) && !(flag & (T1_SIG | T1_VISIT))) { + v = int_abs(*datap) & one ? 1 : 0; + mqc_setcurctx(mqc, t1_getctxno_zc(flag, orient)); /* ESSAI */ + if (type == T1_TYPE_RAW) { /* BYPASS/LAZY MODE */ + mqc_bypass_enc(mqc, v); + } else { + mqc_encode(mqc, v); + } + if (v) { + v = *datap < 0 ? 1 : 0; + *nmsedec += t1_getnmsedec_sig(int_abs(*datap), bpno + T1_NMSEDEC_FRACBITS); + mqc_setcurctx(mqc, t1_getctxno_sc(flag)); /* ESSAI */ + if (type == T1_TYPE_RAW) { /* BYPASS/LAZY MODE */ + mqc_bypass_enc(mqc, v); + } else { + mqc_encode(mqc, v ^ t1_getspb(flag)); + } + t1_updateflags(flagsp, v, t1->flags_stride); + } + *flagsp |= T1_VISIT; + } +} + +static void t1_dec_sigpass_step( + opj_t1_t *t1, + flag_t *flagsp, + OPJ_INT32 *datap, + OPJ_UINT32 orient, + OPJ_INT32 oneplushalf, + OPJ_BYTE type, + OPJ_UINT32 vsc) +{ + OPJ_UINT32 v, flag; + + opj_raw_t *raw = t1->raw; /* RAW component */ + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + flag = vsc ? ((*flagsp) & (~(T1_SIG_S | T1_SIG_SE | T1_SIG_SW | T1_SGN_S))) : (*flagsp); + if ((flag & T1_SIG_OTH) && !(flag & (T1_SIG | T1_VISIT))) { + if (type == T1_TYPE_RAW) { + if (raw_decode(raw)) { + v = raw_decode(raw); /* ESSAI */ + *datap = v ? -oneplushalf : oneplushalf; + t1_updateflags(flagsp, v, t1->flags_stride); + } + } else { + mqc_setcurctx(mqc, t1_getctxno_zc(flag, orient)); + if (mqc_decode(mqc)) { + mqc_setcurctx(mqc, t1_getctxno_sc(flag)); + v = mqc_decode(mqc) ^ t1_getspb(flag); + *datap = v ? -oneplushalf : oneplushalf; + t1_updateflags(flagsp, v, t1->flags_stride); + } + } + *flagsp |= T1_VISIT; + } +} /* VSC and BYPASS by Antonin */ + +static void t1_enc_sigpass( + opj_t1_t *t1, + OPJ_INT32 bpno, + OPJ_UINT32 orient, + OPJ_INT32 *nmsedec, + OPJ_BYTE type, + OPJ_UINT32 cblksty) +{ + OPJ_UINT32 i, j, k, vsc; + OPJ_INT32 one; + + *nmsedec = 0; + one = 1 << (bpno + T1_NMSEDEC_FRACBITS); + for (k = 0; k < t1->h; k += 4) { + for (i = 0; i < t1->w; ++i) { + for (j = k; j < k + 4 && j < t1->h; ++j) { + vsc = ((cblksty & J2K_CCP_CBLKSTY_VSC) && (j == k + 3 || j == t1->h - 1)) ? 1 : 0; + t1_enc_sigpass_step( + t1, + &t1->flags[((j+1) * t1->flags_stride) + i + 1], + &t1->data[(j * t1->w) + i], + orient, + bpno, + one, + nmsedec, + type, + vsc); + } + } + } +} + +static void t1_dec_sigpass( + opj_t1_t *t1, + OPJ_INT32 bpno, + OPJ_UINT32 orient, + OPJ_BYTE type, + OPJ_UINT32 cblksty) +{ + OPJ_UINT32 i, j, k, vsc; + OPJ_INT32 one, half, oneplushalf; + one = 1 << bpno; + half = one >> 1; + oneplushalf = one | half; + for (k = 0; k < t1->h; k += 4) { + for (i = 0; i < t1->w; ++i) { + for (j = k; j < k + 4 && j < t1->h; ++j) { + vsc = ((cblksty & J2K_CCP_CBLKSTY_VSC) && (j == k + 3 || j == t1->h - 1)) ? 1 : 0; + t1_dec_sigpass_step( + t1, + &t1->flags[((j+1) * t1->flags_stride) + i + 1], + &t1->data[(j * t1->w) + i], + orient, + oneplushalf, + type, + vsc); + } + } + } +} /* VSC and BYPASS by Antonin */ + +static void t1_enc_refpass_step( + opj_t1_t *t1, + flag_t *flagsp, + OPJ_INT32 *datap, + OPJ_INT32 bpno, + OPJ_INT32 one, + OPJ_INT32 *nmsedec, + OPJ_BYTE type, + OPJ_UINT32 vsc) +{ + OPJ_INT32 v; + OPJ_UINT32 flag; + + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + flag = vsc ? ((*flagsp) & (~(T1_SIG_S | T1_SIG_SE | T1_SIG_SW | T1_SGN_S))) : (*flagsp); + if ((flag & (T1_SIG | T1_VISIT)) == T1_SIG) { + *nmsedec += t1_getnmsedec_ref(int_abs(*datap), bpno + T1_NMSEDEC_FRACBITS); + v = int_abs(*datap) & one ? 1 : 0; + mqc_setcurctx(mqc, t1_getctxno_mag(flag)); /* ESSAI */ + if (type == T1_TYPE_RAW) { /* BYPASS/LAZY MODE */ + mqc_bypass_enc(mqc, v); + } else { + mqc_encode(mqc, v); + } + *flagsp |= T1_REFINE; + } +} + +static void t1_dec_refpass_step( + opj_t1_t *t1, + flag_t *flagsp, + OPJ_INT32 *datap, + OPJ_INT32 poshalf, + OPJ_INT32 neghalf, + OPJ_BYTE type, + OPJ_UINT32 vsc) +{ + OPJ_INT32 t; + OPJ_UINT32 v,flag; + + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + opj_raw_t *raw = t1->raw; /* RAW component */ + + flag = vsc ? ((*flagsp) & (~(T1_SIG_S | T1_SIG_SE | T1_SIG_SW | T1_SGN_S))) : (*flagsp); + if ((flag & (T1_SIG | T1_VISIT)) == T1_SIG) { + mqc_setcurctx(mqc, t1_getctxno_mag(flag)); /* ESSAI */ + if (type == T1_TYPE_RAW) { + v = raw_decode(raw); + } else { + v = mqc_decode(mqc); + } + t = v ? poshalf : neghalf; + *datap += *datap < 0 ? -t : t; + *flagsp |= T1_REFINE; + } +} /* VSC and BYPASS by Antonin */ + +static void t1_enc_refpass( + opj_t1_t *t1, + OPJ_INT32 bpno, + OPJ_INT32 *nmsedec, + OPJ_BYTE type, + OPJ_UINT32 cblksty) +{ + OPJ_UINT32 i, j, k, vsc; + OPJ_INT32 one; + + *nmsedec = 0; + one = 1 << (bpno + T1_NMSEDEC_FRACBITS); + for (k = 0; k < t1->h; k += 4) { + for (i = 0; i < t1->w; ++i) { + for (j = k; j < k + 4 && j < t1->h; ++j) { + vsc = ((cblksty & J2K_CCP_CBLKSTY_VSC) && (j == k + 3 || j == t1->h - 1)) ? 1 : 0; + t1_enc_refpass_step( + t1, + &t1->flags[((j+1) * t1->flags_stride) + i + 1], + &t1->data[(j * t1->w) + i], + bpno, + one, + nmsedec, + type, + vsc); + } + } + } +} + +static void t1_dec_refpass( + opj_t1_t *t1, + OPJ_INT32 bpno, + OPJ_BYTE type, + OPJ_UINT32 cblksty) +{ + OPJ_UINT32 i, j, k; + OPJ_INT32 one, poshalf, neghalf; + OPJ_UINT32 vsc; + one = 1 << bpno; + poshalf = one >> 1; + neghalf = bpno > 0 ? -poshalf : -1; + for (k = 0; k < t1->h; k += 4) { + for (i = 0; i < t1->w; ++i) { + for (j = k; j < k + 4 && j < t1->h; ++j) { + vsc = ((cblksty & J2K_CCP_CBLKSTY_VSC) && (j == k + 3 || j == t1->h - 1)) ? 1 : 0; + t1_dec_refpass_step( + t1, + &t1->flags[((j+1) * t1->flags_stride) + i + 1], + &t1->data[(j * t1->w) + i], + poshalf, + neghalf, + type, + vsc); + } + } + } +} /* VSC and BYPASS by Antonin */ + +static void t1_enc_clnpass_step( + opj_t1_t *t1, + flag_t *flagsp, + OPJ_INT32 *datap, + OPJ_UINT32 orient, + OPJ_INT32 bpno, + OPJ_INT32 one, + OPJ_INT32 *nmsedec, + OPJ_UINT32 partial, + OPJ_UINT32 vsc) +{ + OPJ_INT32 v; + OPJ_UINT32 flag; + + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + flag = vsc ? ((*flagsp) & (~(T1_SIG_S | T1_SIG_SE | T1_SIG_SW | T1_SGN_S))) : (*flagsp); + if (partial) { + goto LABEL_PARTIAL; + } + if (!(*flagsp & (T1_SIG | T1_VISIT))) { + mqc_setcurctx(mqc, t1_getctxno_zc(flag, orient)); + v = int_abs(*datap) & one ? 1 : 0; + mqc_encode(mqc, v); + if (v) { +LABEL_PARTIAL: + *nmsedec += t1_getnmsedec_sig(int_abs(*datap), bpno + T1_NMSEDEC_FRACBITS); + mqc_setcurctx(mqc, t1_getctxno_sc(flag)); + v = *datap < 0 ? 1 : 0; + mqc_encode(mqc, v ^ t1_getspb(flag)); + t1_updateflags(flagsp, v, t1->flags_stride); + } + } + *flagsp &= ~T1_VISIT; +} + +static void t1_dec_clnpass_step( + opj_t1_t *t1, + flag_t *flagsp, + OPJ_INT32 *datap, + OPJ_UINT32 orient, + OPJ_INT32 oneplushalf, + OPJ_UINT32 partial, + OPJ_UINT32 vsc) +{ + OPJ_INT32 v; + OPJ_UINT32 flag; + + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + flag = vsc ? ((*flagsp) & (~(T1_SIG_S | T1_SIG_SE | T1_SIG_SW | T1_SGN_S))) : (*flagsp); + if (partial) { + goto LABEL_PARTIAL; + } + if (!(flag & (T1_SIG | T1_VISIT))) { + mqc_setcurctx(mqc, t1_getctxno_zc(flag, orient)); + if (mqc_decode(mqc)) { +LABEL_PARTIAL: + mqc_setcurctx(mqc, t1_getctxno_sc(flag)); + v = mqc_decode(mqc) ^ t1_getspb(flag); + *datap = v ? -oneplushalf : oneplushalf; + t1_updateflags(flagsp, v, t1->flags_stride); + } + } + *flagsp &= ~T1_VISIT; +} /* VSC and BYPASS by Antonin */ + +static void t1_enc_clnpass( + opj_t1_t *t1, + OPJ_INT32 bpno, + OPJ_UINT32 orient, + OPJ_INT32 *nmsedec, + OPJ_UINT32 cblksty) +{ + OPJ_UINT32 i, j, k; + OPJ_INT32 one; + OPJ_UINT32 agg, runlen, vsc; + + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + *nmsedec = 0; + one = 1 << (bpno + T1_NMSEDEC_FRACBITS); + for (k = 0; k < t1->h; k += 4) { + for (i = 0; i < t1->w; ++i) { + if (k + 3 < t1->h) { + if (cblksty & J2K_CCP_CBLKSTY_VSC) { + agg = !(MACRO_t1_flags(1 + k,1 + i) & (T1_SIG | T1_VISIT | T1_SIG_OTH) + || MACRO_t1_flags(1 + k + 1,1 + i) & (T1_SIG | T1_VISIT | T1_SIG_OTH) + || MACRO_t1_flags(1 + k + 2,1 + i) & (T1_SIG | T1_VISIT | T1_SIG_OTH) + || (MACRO_t1_flags(1 + k + 3,1 + i) + & (~(T1_SIG_S | T1_SIG_SE | T1_SIG_SW | T1_SGN_S))) & (T1_SIG | T1_VISIT | T1_SIG_OTH)); + } else { + agg = !(MACRO_t1_flags(1 + k,1 + i) & (T1_SIG | T1_VISIT | T1_SIG_OTH) + || MACRO_t1_flags(1 + k + 1,1 + i) & (T1_SIG | T1_VISIT | T1_SIG_OTH) + || MACRO_t1_flags(1 + k + 2,1 + i) & (T1_SIG | T1_VISIT | T1_SIG_OTH) + || MACRO_t1_flags(1 + k + 3,1 + i) & (T1_SIG | T1_VISIT | T1_SIG_OTH)); + } + } else { + agg = 0; + } + if (agg) { + for (runlen = 0; runlen < 4; ++runlen) { + if (int_abs(t1->data[((k + runlen)*t1->w) + i]) & one) + break; + } + mqc_setcurctx(mqc, T1_CTXNO_AGG); + mqc_encode(mqc, runlen != 4); + if (runlen == 4) { + continue; + } + mqc_setcurctx(mqc, T1_CTXNO_UNI); + mqc_encode(mqc, runlen >> 1); + mqc_encode(mqc, runlen & 1); + } else { + runlen = 0; + } + for (j = k + runlen; j < k + 4 && j < t1->h; ++j) { + vsc = ((cblksty & J2K_CCP_CBLKSTY_VSC) && (j == k + 3 || j == t1->h - 1)) ? 1 : 0; + t1_enc_clnpass_step( + t1, + &t1->flags[((j+1) * t1->flags_stride) + i + 1], + &t1->data[(j * t1->w) + i], + orient, + bpno, + one, + nmsedec, + agg && (j == k + runlen), + vsc); + } + } + } +} + +static void t1_dec_clnpass( + opj_t1_t *t1, + OPJ_INT32 bpno, + OPJ_UINT32 orient, + OPJ_UINT32 cblksty) +{ + OPJ_UINT32 i, j, k, one; + OPJ_INT32 half, oneplushalf; + OPJ_UINT32 agg, runlen, vsc; + OPJ_UINT32 segsym = cblksty & J2K_CCP_CBLKSTY_SEGSYM; + + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + one = 1 << bpno; + half = one >> 1; + oneplushalf = one | half; + for (k = 0; k < t1->h; k += 4) { + for (i = 0; i < t1->w; ++i) { + if (k + 3 < t1->h) { + if (cblksty & J2K_CCP_CBLKSTY_VSC) { + agg = !(MACRO_t1_flags(1 + k,1 + i) & (T1_SIG | T1_VISIT | T1_SIG_OTH) + || MACRO_t1_flags(1 + k + 1,1 + i) & (T1_SIG | T1_VISIT | T1_SIG_OTH) + || MACRO_t1_flags(1 + k + 2,1 + i) & (T1_SIG | T1_VISIT | T1_SIG_OTH) + || (MACRO_t1_flags(1 + k + 3,1 + i) + & (~(T1_SIG_S | T1_SIG_SE | T1_SIG_SW | T1_SGN_S))) & (T1_SIG | T1_VISIT | T1_SIG_OTH)); + } else { + agg = !(MACRO_t1_flags(1 + k,1 + i) & (T1_SIG | T1_VISIT | T1_SIG_OTH) + || MACRO_t1_flags(1 + k + 1,1 + i) & (T1_SIG | T1_VISIT | T1_SIG_OTH) + || MACRO_t1_flags(1 + k + 2,1 + i) & (T1_SIG | T1_VISIT | T1_SIG_OTH) + || MACRO_t1_flags(1 + k + 3,1 + i) & (T1_SIG | T1_VISIT | T1_SIG_OTH)); + } + } else { + agg = 0; + } + if (agg) { + mqc_setcurctx(mqc, T1_CTXNO_AGG); + if (!mqc_decode(mqc)) { + continue; + } + mqc_setcurctx(mqc, T1_CTXNO_UNI); + runlen = mqc_decode(mqc); + runlen = (runlen << 1) | mqc_decode(mqc); + } else { + runlen = 0; + } + for (j = k + runlen; j < k + 4 && j < t1->h; ++j) { + vsc = ((cblksty & J2K_CCP_CBLKSTY_VSC) && (j == k + 3 || j == t1->h - 1)) ? 1 : 0; + t1_dec_clnpass_step( + t1, + &t1->flags[((j+1) * t1->flags_stride) + i + 1], + &t1->data[(j * t1->w) + i], + orient, + oneplushalf, + agg && (j == k + runlen), + vsc); + } + } + } + if (segsym) { + OPJ_UINT32 v = 0; + mqc_setcurctx(mqc, T1_CTXNO_UNI); + v = mqc_decode(mqc); + v = (v << 1) | mqc_decode(mqc); + v = (v << 1) | mqc_decode(mqc); + v = (v << 1) | mqc_decode(mqc); + /* + if (v!=0xa) { + opj_event_msg(t1->cinfo, EVT_WARNING, "Bad segmentation symbol %x\n", v); + } + */ + } +} /* VSC and BYPASS by Antonin */ + + +/** mod fixed_quality */ +static OPJ_FLOAT64 t1_getwmsedec( + OPJ_INT32 nmsedec, + OPJ_UINT32 compno, + OPJ_UINT32 level, + OPJ_UINT32 orient, + OPJ_INT32 bpno, + OPJ_UINT32 qmfbid, + OPJ_FLOAT64 stepsize, + OPJ_UINT32 numcomps, + const OPJ_FLOAT64 * mct_norms) +{ + OPJ_FLOAT64 w1 = 1, w2, wmsedec; + if + (mct_norms) + { + w1 = mct_norms[compno]; + } + if (qmfbid == 1) + { + w2 = dwt_getnorm(level, orient); + } else { /* if (qmfbid == 0) */ + w2 = dwt_getnorm_real(level, orient); + } + wmsedec = w1 * w2 * stepsize * (1 << bpno); + wmsedec *= wmsedec * nmsedec / 8192.0; + return wmsedec; +} + +static bool allocate_buffers( + opj_t1_t *t1, + OPJ_UINT32 w, + OPJ_UINT32 h) +{ + OPJ_UINT32 datasize=w * h; + OPJ_UINT32 flagssize; + + if(datasize > t1->datasize){ + opj_aligned_free(t1->data); + t1->data = (OPJ_INT32*) opj_aligned_malloc(datasize * sizeof(OPJ_INT32)); + if(!t1->data){ + return false; + } + t1->datasize=datasize; + } + memset(t1->data,0,datasize * sizeof(OPJ_INT32)); + + t1->flags_stride=w+2; + flagssize=t1->flags_stride * (h+2); + + if(flagssize > t1->flagssize){ + opj_aligned_free(t1->flags); + t1->flags = (flag_t*) opj_aligned_malloc(flagssize * sizeof(flag_t)); + if(!t1->flags){ + return false; + } + t1->flagssize=flagssize; + } + memset(t1->flags,0,flagssize * sizeof(flag_t)); + + t1->w=w; + t1->h=h; + + return true; +} + +/** mod fixed_quality */ +static void t1_encode_cblk( + opj_t1_t *t1, + opj_tcd_cblk_enc_t* cblk, + OPJ_UINT32 orient, + OPJ_UINT32 compno, + OPJ_UINT32 level, + OPJ_UINT32 qmfbid, + OPJ_FLOAT64 stepsize, + OPJ_UINT32 cblksty, + OPJ_UINT32 numcomps, + opj_tcd_tile_t * tile, + const OPJ_FLOAT64 * mct_norms) +{ + OPJ_FLOAT64 cumwmsedec = 0.0; + + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + OPJ_UINT32 passno; + OPJ_INT32 bpno; + OPJ_UINT32 passtype; + OPJ_INT32 nmsedec = 0; + OPJ_INT32 max; + OPJ_UINT32 i; + OPJ_BYTE type = T1_TYPE_MQ; + OPJ_FLOAT64 tempwmsedec; + + max = 0; + for (i = 0; i < t1->w * t1->h; ++i) { + OPJ_INT32 tmp = abs(t1->data[i]); + max = int_max(max, tmp); + } + + cblk->numbps = max ? (int_floorlog2(max) + 1) - T1_NMSEDEC_FRACBITS : 0; + + bpno = cblk->numbps - 1; + passtype = 2; + + mqc_resetstates(mqc); + mqc_setstate(mqc, T1_CTXNO_UNI, 0, 46); + mqc_setstate(mqc, T1_CTXNO_AGG, 0, 3); + mqc_setstate(mqc, T1_CTXNO_ZC, 0, 4); + mqc_init_enc(mqc, cblk->data); + + for (passno = 0; bpno >= 0; ++passno) { + opj_tcd_pass_t *pass = &cblk->passes[passno]; + OPJ_UINT32 correction = 3; + type = ((bpno < ((OPJ_INT32) (cblk->numbps) - 4)) && (passtype < 2) && (cblksty & J2K_CCP_CBLKSTY_LAZY)) ? T1_TYPE_RAW : T1_TYPE_MQ; + + switch (passtype) { + case 0: + t1_enc_sigpass(t1, bpno, orient, &nmsedec, type, cblksty); + break; + case 1: + t1_enc_refpass(t1, bpno, &nmsedec, type, cblksty); + break; + case 2: + t1_enc_clnpass(t1, bpno, orient, &nmsedec, cblksty); + /* code switch SEGMARK (i.e. SEGSYM) */ + if (cblksty & J2K_CCP_CBLKSTY_SEGSYM) + mqc_segmark_enc(mqc); + break; + } + + /* fixed_quality */ + tempwmsedec = t1_getwmsedec(nmsedec, compno, level, orient, bpno, qmfbid, stepsize, numcomps,mct_norms) ; + cumwmsedec += tempwmsedec; + tile->distotile += tempwmsedec; + + /* Code switch "RESTART" (i.e. TERMALL) */ + if ((cblksty & J2K_CCP_CBLKSTY_TERMALL) && !((passtype == 2) && (bpno - 1 < 0))) { + if (type == T1_TYPE_RAW) { + mqc_flush(mqc); + correction = 1; + /* correction = mqc_bypass_flush_enc(); */ + } else { /* correction = mqc_restart_enc(); */ + mqc_flush(mqc); + correction = 1; + } + pass->term = 1; + } else { + if (((bpno < ((OPJ_INT32) (cblk->numbps) - 4) && (passtype > 0)) + || ((bpno == (cblk->numbps - 4)) && (passtype == 2))) && (cblksty & J2K_CCP_CBLKSTY_LAZY)) { + if (type == T1_TYPE_RAW) { + mqc_flush(mqc); + correction = 1; + /* correction = mqc_bypass_flush_enc(); */ + } else { /* correction = mqc_restart_enc(); */ + mqc_flush(mqc); + correction = 1; + } + pass->term = 1; + } else { + pass->term = 0; + } + } + + if (++passtype == 3) { + passtype = 0; + bpno--; + } + + if (pass->term && bpno > 0) { + type = ((bpno < ((OPJ_INT32) (cblk->numbps) - 4)) && (passtype < 2) && (cblksty & J2K_CCP_CBLKSTY_LAZY)) ? T1_TYPE_RAW : T1_TYPE_MQ; + if (type == T1_TYPE_RAW) + mqc_bypass_init_enc(mqc); + else + mqc_restart_init_enc(mqc); + } + + pass->distortiondec = cumwmsedec; + pass->rate = mqc_numbytes(mqc) + correction; /* FIXME */ + + /* Code-switch "RESET" */ + if (cblksty & J2K_CCP_CBLKSTY_RESET) + mqc_reset_enc(mqc); + } + + /* Code switch "ERTERM" (i.e. PTERM) */ + if (cblksty & J2K_CCP_CBLKSTY_PTERM) + mqc_erterm_enc(mqc); + else /* Default coding */ if (!(cblksty & J2K_CCP_CBLKSTY_LAZY)) + mqc_flush(mqc); + + cblk->totalpasses = passno; + + for (passno = 0; passnototalpasses; passno++) { + opj_tcd_pass_t *pass = &cblk->passes[passno]; + if (pass->rate > mqc_numbytes(mqc)) + pass->rate = mqc_numbytes(mqc); + /*Preventing generation of FF as last data byte of a pass*/ + if((pass->rate>1) && (cblk->data[pass->rate - 1] == 0xFF)){ + pass->rate--; + } + pass->len = pass->rate - (passno == 0 ? 0 : cblk->passes[passno - 1].rate); + } +} + +static void t1_decode_cblk( + opj_t1_t *t1, + opj_tcd_cblk_dec_t* cblk, + OPJ_UINT32 orient, + OPJ_UINT32 roishift, + OPJ_UINT32 cblksty) +{ + opj_raw_t *raw = t1->raw; /* RAW component */ + opj_mqc_t *mqc = t1->mqc; /* MQC component */ + + OPJ_INT32 bpno; + OPJ_UINT32 passtype; + OPJ_UINT32 segno, passno; + OPJ_BYTE type = T1_TYPE_MQ; /* BYPASS mode */ + + if(!allocate_buffers( + t1, + cblk->x1 - cblk->x0, + cblk->y1 - cblk->y0)) + { + return; + } + + bpno = roishift + cblk->numbps - 1; + passtype = 2; + + mqc_resetstates(mqc); + mqc_setstate(mqc, T1_CTXNO_UNI, 0, 46); + mqc_setstate(mqc, T1_CTXNO_AGG, 0, 3); + mqc_setstate(mqc, T1_CTXNO_ZC, 0, 4); + + for (segno = 0; segno < cblk->real_num_segs; ++segno) { + opj_tcd_seg_t *seg = &cblk->segs[segno]; + + /* BYPASS mode */ + type = ((bpno <= ((OPJ_INT32) (cblk->numbps) - 1) - 4) && (passtype < 2) && (cblksty & J2K_CCP_CBLKSTY_LAZY)) ? T1_TYPE_RAW : T1_TYPE_MQ; + /* FIXME: slviewer gets here with a null pointer. Why? Partially downloaded and/or corrupt textures? */ + if(seg->data == 00){ + continue; + } + if (type == T1_TYPE_RAW) { + raw_init_dec(raw, (*seg->data) + seg->dataindex, seg->len); + } else { + mqc_init_dec(mqc, (*seg->data) + seg->dataindex, seg->len); + } + + for (passno = 0; passno < seg->real_num_passes; ++passno) { + switch (passtype) { + case 0: + t1_dec_sigpass(t1, bpno+1, orient, type, cblksty); + break; + case 1: + t1_dec_refpass(t1, bpno+1, type, cblksty); + break; + case 2: + t1_dec_clnpass(t1, bpno+1, orient, cblksty); + break; + } + + if ((cblksty & J2K_CCP_CBLKSTY_RESET) && type == T1_TYPE_MQ) { + mqc_resetstates(mqc); + mqc_setstate(mqc, T1_CTXNO_UNI, 0, 46); + mqc_setstate(mqc, T1_CTXNO_AGG, 0, 3); + mqc_setstate(mqc, T1_CTXNO_ZC, 0, 4); + } + if (++passtype == 3) { + passtype = 0; + bpno--; + } + } + } +} + +/* ----------------------------------------------------------------------- */ +/** + * Creates a new Tier 1 handle + * and initializes the look-up tables of the Tier-1 coder/decoder + * @return a new T1 handle if successful, returns NULL otherwise +*/ +opj_t1_t* t1_create() +{ + opj_t1_t *l_t1 = 00; + + l_t1 = (opj_t1_t*) opj_malloc(sizeof(opj_t1_t)); + if + (!l_t1) + { + return 00; + } + memset(l_t1,0,sizeof(opj_t1_t)); + + /* create MQC and RAW handles */ + l_t1->mqc = mqc_create(); + if + (! l_t1->mqc) + { + t1_destroy(l_t1); + return 00; + } + l_t1->raw = raw_create(); + if + (! l_t1->raw) + { + t1_destroy(l_t1); + return 00; + } + return l_t1; +} + +/** + * Destroys a previously created T1 handle + * + * @param p_t1 Tier 1 handle to destroy +*/ +void t1_destroy(opj_t1_t *p_t1) +{ + if + (! p_t1) + { + return; + } + + /* destroy MQC and RAW handles */ + mqc_destroy(p_t1->mqc); + p_t1->mqc = 00; + raw_destroy(p_t1->raw); + p_t1->raw = 00; + if + (p_t1->data) + { + opj_aligned_free(p_t1->data); + p_t1->data = 00; + } + if + (p_t1->flags) + { + opj_aligned_free(p_t1->flags); + p_t1->flags = 00; + } + opj_free(p_t1); +} + +bool t1_encode_cblks( + opj_t1_t *t1, + opj_tcd_tile_t *tile, + opj_tcp_t *tcp, + const OPJ_FLOAT64 * mct_norms) +{ + OPJ_UINT32 compno, resno, bandno, precno, cblkno; + + tile->distotile = 0; /* fixed_quality */ + + for (compno = 0; compno < tile->numcomps; ++compno) { + opj_tcd_tilecomp_t* tilec = &tile->comps[compno]; + opj_tccp_t* tccp = &tcp->tccps[compno]; + OPJ_UINT32 tile_w = tilec->x1 - tilec->x0; + + for (resno = 0; resno < tilec->numresolutions; ++resno) { + opj_tcd_resolution_t *res = &tilec->resolutions[resno]; + + for (bandno = 0; bandno < res->numbands; ++bandno) { + opj_tcd_band_t* restrict band = &res->bands[bandno]; + + for (precno = 0; precno < res->pw * res->ph; ++precno) { + opj_tcd_precinct_t *prc = &band->precincts[precno]; + + for (cblkno = 0; cblkno < prc->cw * prc->ch; ++cblkno) { + opj_tcd_cblk_enc_t* cblk = &prc->cblks.enc[cblkno]; + OPJ_INT32 * restrict datap; + OPJ_INT32* restrict tiledp; + OPJ_UINT32 cblk_w; + OPJ_UINT32 cblk_h; + OPJ_UINT32 i, j; + + OPJ_INT32 x = cblk->x0 - band->x0; + OPJ_INT32 y = cblk->y0 - band->y0; + if (band->bandno & 1) { + opj_tcd_resolution_t *pres = &tilec->resolutions[resno - 1]; + x += pres->x1 - pres->x0; + } + if (band->bandno & 2) { + opj_tcd_resolution_t *pres = &tilec->resolutions[resno - 1]; + y += pres->y1 - pres->y0; + } + + if(!allocate_buffers( + t1, + cblk->x1 - cblk->x0, + cblk->y1 - cblk->y0)) + { + return false; + } + + datap=t1->data; + cblk_w = t1->w; + cblk_h = t1->h; + + tiledp=&tilec->data[(y * tile_w) + x]; + if (tccp->qmfbid == 1) { + for (j = 0; j < cblk_h; ++j) { + for (i = 0; i < cblk_w; ++i) { + OPJ_INT32 tmp = tiledp[(j * tile_w) + i]; + datap[(j * cblk_w) + i] = tmp << T1_NMSEDEC_FRACBITS; + } + } + } else { /* if (tccp->qmfbid == 0) */ + for (j = 0; j < cblk_h; ++j) { + for (i = 0; i < cblk_w; ++i) { + OPJ_INT32 tmp = tiledp[(j * tile_w) + i]; + datap[(j * cblk_w) + i] = + fix_mul( + tmp, + 8192 * 8192 / ((OPJ_INT32) floor(band->stepsize * 8192))) >> (11 - T1_NMSEDEC_FRACBITS); + } + } + } + + t1_encode_cblk( + t1, + cblk, + band->bandno, + compno, + tilec->numresolutions - 1 - resno, + tccp->qmfbid, + band->stepsize, + tccp->cblksty, + tile->numcomps, + tile, + mct_norms); + + } /* cblkno */ + } /* precno */ + } /* bandno */ + } /* resno */ + } /* compno */ + return true; +} + +void t1_decode_cblks( + opj_t1_t* t1, + opj_tcd_tilecomp_t* tilec, + opj_tccp_t* tccp) +{ + OPJ_UINT32 resno, bandno, precno, cblkno; + + OPJ_UINT32 tile_w = tilec->x1 - tilec->x0; + + for (resno = 0; resno < tilec->minimum_num_resolutions; ++resno) { + opj_tcd_resolution_t* res = &tilec->resolutions[resno]; + + for (bandno = 0; bandno < res->numbands; ++bandno) { + opj_tcd_band_t* restrict band = &res->bands[bandno]; + + for (precno = 0; precno < res->pw * res->ph; ++precno) { + opj_tcd_precinct_t* precinct = &band->precincts[precno]; + + for (cblkno = 0; cblkno < precinct->cw * precinct->ch; ++cblkno) { + opj_tcd_cblk_dec_t* cblk = &precinct->cblks.dec[cblkno]; + OPJ_INT32* restrict datap; + void* restrict tiledp; + OPJ_UINT32 cblk_w, cblk_h; + OPJ_INT32 x, y; + OPJ_UINT32 i, j; + + t1_decode_cblk( + t1, + cblk, + band->bandno, + tccp->roishift, + tccp->cblksty); + + x = cblk->x0 - band->x0; + y = cblk->y0 - band->y0; + if (band->bandno & 1) { + opj_tcd_resolution_t* pres = &tilec->resolutions[resno - 1]; + x += pres->x1 - pres->x0; + } + if (band->bandno & 2) { + opj_tcd_resolution_t* pres = &tilec->resolutions[resno - 1]; + y += pres->y1 - pres->y0; + } + + datap=t1->data; + cblk_w = t1->w; + cblk_h = t1->h; + + if (tccp->roishift) { + OPJ_INT32 thresh = 1 << tccp->roishift; + for (j = 0; j < cblk_h; ++j) { + for (i = 0; i < cblk_w; ++i) { + OPJ_INT32 val = datap[(j * cblk_w) + i]; + OPJ_INT32 mag = abs(val); + if (mag >= thresh) { + mag >>= tccp->roishift; + datap[(j * cblk_w) + i] = val < 0 ? -mag : mag; + } + } + } + } + + tiledp=(void*)&tilec->data[(y * tile_w) + x]; + if (tccp->qmfbid == 1) { + for (j = 0; j < cblk_h; ++j) { + for (i = 0; i < cblk_w; ++i) { + OPJ_INT32 tmp = datap[(j * cblk_w) + i]; + ((OPJ_INT32*)tiledp)[(j * tile_w) + i] = tmp / 2; + } + } + } else { /* if (tccp->qmfbid == 0) */ + for (j = 0; j < cblk_h; ++j) { + for (i = 0; i < cblk_w; ++i) { + float tmp = datap[(j * cblk_w) + i] * band->stepsize; + ((float*)tiledp)[(j * tile_w) + i] = tmp; + } + } + } + //opj_free(cblk->segs); + //cblk->segs = 00; + } /* cblkno */ + } /* precno */ + } /* bandno */ + } /* resno */ +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/t1.h b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/t1.h new file mode 100644 index 0000000..b98eca2 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/t1.h @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __T1_H +#define __T1_H +/** +@file t1.h +@brief Implementation of the tier-1 coding (coding of code-block coefficients) (T1) + +The functions in T1.C have for goal to realize the tier-1 coding operation. The functions +in T1.C are used by some function in TCD.C. +*/ +#include "openjpeg.h" +/** @defgroup T1 T1 - Implementation of the tier-1 coding */ +/*@{*/ +//#include "raw.h" +/* ----------------------------------------------------------------------- */ +#define T1_NMSEDEC_BITS 7 + +#define T1_SIG_NE 0x0001 /**< Context orientation : North-East direction */ +#define T1_SIG_SE 0x0002 /**< Context orientation : South-East direction */ +#define T1_SIG_SW 0x0004 /**< Context orientation : South-West direction */ +#define T1_SIG_NW 0x0008 /**< Context orientation : North-West direction */ +#define T1_SIG_N 0x0010 /**< Context orientation : North direction */ +#define T1_SIG_E 0x0020 /**< Context orientation : East direction */ +#define T1_SIG_S 0x0040 /**< Context orientation : South direction */ +#define T1_SIG_W 0x0080 /**< Context orientation : West direction */ +#define T1_SIG_OTH (T1_SIG_N|T1_SIG_NE|T1_SIG_E|T1_SIG_SE|T1_SIG_S|T1_SIG_SW|T1_SIG_W|T1_SIG_NW) +#define T1_SIG_PRIM (T1_SIG_N|T1_SIG_E|T1_SIG_S|T1_SIG_W) + +#define T1_SGN_N 0x0100 +#define T1_SGN_E 0x0200 +#define T1_SGN_S 0x0400 +#define T1_SGN_W 0x0800 +#define T1_SGN (T1_SGN_N|T1_SGN_E|T1_SGN_S|T1_SGN_W) + +#define T1_SIG 0x1000 +#define T1_REFINE 0x2000 +#define T1_VISIT 0x4000 + +#define T1_NUMCTXS_ZC 9 +#define T1_NUMCTXS_SC 5 +#define T1_NUMCTXS_MAG 3 +#define T1_NUMCTXS_AGG 1 +#define T1_NUMCTXS_UNI 1 + +#define T1_CTXNO_ZC 0 +#define T1_CTXNO_SC (T1_CTXNO_ZC+T1_NUMCTXS_ZC) +#define T1_CTXNO_MAG (T1_CTXNO_SC+T1_NUMCTXS_SC) +#define T1_CTXNO_AGG (T1_CTXNO_MAG+T1_NUMCTXS_MAG) +#define T1_CTXNO_UNI (T1_CTXNO_AGG+T1_NUMCTXS_AGG) +#define T1_NUMCTXS (T1_CTXNO_UNI+T1_NUMCTXS_UNI) + +#define T1_NMSEDEC_FRACBITS (T1_NMSEDEC_BITS-1) + +#define T1_TYPE_MQ 0 /**< Normal coding using entropy coder */ +#define T1_TYPE_RAW 1 /**< No encoding the information is store under raw format in codestream (mode switch RAW)*/ + +/* ----------------------------------------------------------------------- */ +struct opj_common_struct; +struct opj_tcd_tile; +struct opj_tcp; +struct opj_tcd_tilecomp; +struct opj_mqc; +struct opj_raw; +struct opj_tccp; + + +typedef short flag_t; + +/** +Tier-1 coding (coding of code-block coefficients) +*/ +typedef struct opj_t1 { + /** MQC component */ + struct opj_mqc *mqc; + /** RAW component */ + struct opj_raw *raw; + + OPJ_INT32 *data; + flag_t *flags; + OPJ_UINT32 w; + OPJ_UINT32 h; + OPJ_UINT32 datasize; + OPJ_UINT32 flagssize; + OPJ_UINT32 flags_stride; +} opj_t1_t; + +#define MACRO_t1_flags(x,y) t1->flags[((x)*(t1->flags_stride))+(y)] + +/** @name Exported functions */ +/*@{*/ +/* ----------------------------------------------------------------------- */ + +/** + * Creates a new Tier 1 handle + * and initializes the look-up tables of the Tier-1 coder/decoder + * @return a new T1 handle if successful, returns NULL otherwise +*/ +opj_t1_t* t1_create(); + +/** + * Destroys a previously created T1 handle + * + * @param p_t1 Tier 1 handle to destroy +*/ +void t1_destroy(opj_t1_t *p_t1); + +/** +Encode the code-blocks of a tile +@param t1 T1 handle +@param tile The tile to encode +@param tcp Tile coding parameters +*/ +bool t1_encode_cblks(opj_t1_t *t1, struct opj_tcd_tile *tile, struct opj_tcp *tcp,const OPJ_FLOAT64 * mct_norms); +/** +Decode the code-blocks of a tile +@param t1 T1 handle +@param tile The tile to decode +@param tcp Tile coding parameters +*/ +void t1_decode_cblks(opj_t1_t* t1, struct opj_tcd_tilecomp* tilec, struct opj_tccp* tccp); +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __T1_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/t1_luts.h b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/t1_luts.h new file mode 100644 index 0000000..da400ae --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/t1_luts.h @@ -0,0 +1,142 @@ +/* This file was automatically generated by t1_generate_luts.c */ + +static char lut_ctxno_zc[1024] = { + 0, 1, 1, 2, 1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 0, 1, 1, 2, 1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 0, 1, 1, 2, 1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 0, 3, 3, 6, 3, 6, 6, 8, 3, 6, 6, 8, 6, 8, 8, 8, 1, 4, 4, 7, 4, 7, 7, 8, 4, 7, 7, 8, 7, 8, 8, 8, + 1, 4, 4, 7, 4, 7, 7, 8, 4, 7, 7, 8, 7, 8, 8, 8, 2, 5, 5, 7, 5, 7, 7, 8, 5, 7, 7, 8, 7, 8, 8, 8, + 1, 4, 4, 7, 4, 7, 7, 8, 4, 7, 7, 8, 7, 8, 8, 8, 2, 5, 5, 7, 5, 7, 7, 8, 5, 7, 7, 8, 7, 8, 8, 8, + 2, 5, 5, 7, 5, 7, 7, 8, 5, 7, 7, 8, 7, 8, 8, 8, 2, 5, 5, 7, 5, 7, 7, 8, 5, 7, 7, 8, 7, 8, 8, 8, + 1, 4, 4, 7, 4, 7, 7, 8, 4, 7, 7, 8, 7, 8, 8, 8, 2, 5, 5, 7, 5, 7, 7, 8, 5, 7, 7, 8, 7, 8, 8, 8, + 2, 5, 5, 7, 5, 7, 7, 8, 5, 7, 7, 8, 7, 8, 8, 8, 2, 5, 5, 7, 5, 7, 7, 8, 5, 7, 7, 8, 7, 8, 8, 8, + 2, 5, 5, 7, 5, 7, 7, 8, 5, 7, 7, 8, 7, 8, 8, 8, 2, 5, 5, 7, 5, 7, 7, 8, 5, 7, 7, 8, 7, 8, 8, 8, + 2, 5, 5, 7, 5, 7, 7, 8, 5, 7, 7, 8, 7, 8, 8, 8, 2, 5, 5, 7, 5, 7, 7, 8, 5, 7, 7, 8, 7, 8, 8, 8 +}; + +static char lut_ctxno_sc[256] = { + 0x9, 0xa, 0xc, 0xd, 0xa, 0xa, 0xd, 0xd, 0xc, 0xd, 0xc, 0xd, 0xd, 0xd, 0xd, 0xd, + 0x9, 0xa, 0xc, 0xb, 0xa, 0x9, 0xd, 0xc, 0xc, 0xb, 0xc, 0xb, 0xd, 0xc, 0xd, 0xc, + 0x9, 0xa, 0xc, 0xb, 0xa, 0xa, 0xb, 0xb, 0xc, 0xd, 0x9, 0xa, 0xd, 0xd, 0xa, 0xa, + 0x9, 0xa, 0xc, 0xd, 0xa, 0x9, 0xb, 0xc, 0xc, 0xb, 0x9, 0xa, 0xd, 0xc, 0xa, 0x9, + 0x9, 0xa, 0xc, 0xd, 0xa, 0x9, 0xb, 0xc, 0xc, 0xd, 0xc, 0xd, 0xb, 0xc, 0xb, 0xc, + 0x9, 0xa, 0xc, 0xb, 0xa, 0xa, 0xb, 0xb, 0xc, 0xb, 0xc, 0xb, 0xb, 0xb, 0xb, 0xb, + 0x9, 0xa, 0xc, 0xb, 0xa, 0x9, 0xd, 0xc, 0xc, 0xd, 0x9, 0xa, 0xb, 0xc, 0xa, 0x9, + 0x9, 0xa, 0xc, 0xd, 0xa, 0xa, 0xd, 0xd, 0xc, 0xb, 0x9, 0xa, 0xb, 0xb, 0xa, 0xa, + 0x9, 0xa, 0xc, 0xd, 0xa, 0xa, 0xd, 0xd, 0xc, 0xb, 0x9, 0xa, 0xb, 0xb, 0xa, 0xa, + 0x9, 0xa, 0xc, 0xb, 0xa, 0x9, 0xd, 0xc, 0xc, 0xd, 0x9, 0xa, 0xb, 0xc, 0xa, 0x9, + 0x9, 0xa, 0xc, 0xb, 0xa, 0xa, 0xb, 0xb, 0xc, 0xb, 0xc, 0xb, 0xb, 0xb, 0xb, 0xb, + 0x9, 0xa, 0xc, 0xd, 0xa, 0x9, 0xb, 0xc, 0xc, 0xd, 0xc, 0xd, 0xb, 0xc, 0xb, 0xc, + 0x9, 0xa, 0xc, 0xd, 0xa, 0x9, 0xb, 0xc, 0xc, 0xb, 0x9, 0xa, 0xd, 0xc, 0xa, 0x9, + 0x9, 0xa, 0xc, 0xb, 0xa, 0xa, 0xb, 0xb, 0xc, 0xd, 0x9, 0xa, 0xd, 0xd, 0xa, 0xa, + 0x9, 0xa, 0xc, 0xb, 0xa, 0x9, 0xd, 0xc, 0xc, 0xb, 0xc, 0xb, 0xd, 0xc, 0xd, 0xc, + 0x9, 0xa, 0xc, 0xd, 0xa, 0xa, 0xd, 0xd, 0xc, 0xd, 0xc, 0xd, 0xd, 0xd, 0xd, 0xd +}; + +static char lut_spb[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, + 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, + 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 +}; + +static short lut_nmsedec_sig[1 << T1_NMSEDEC_BITS] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0180, 0x0300, 0x0480, 0x0600, 0x0780, 0x0900, 0x0a80, + 0x0c00, 0x0d80, 0x0f00, 0x1080, 0x1200, 0x1380, 0x1500, 0x1680, + 0x1800, 0x1980, 0x1b00, 0x1c80, 0x1e00, 0x1f80, 0x2100, 0x2280, + 0x2400, 0x2580, 0x2700, 0x2880, 0x2a00, 0x2b80, 0x2d00, 0x2e80, + 0x3000, 0x3180, 0x3300, 0x3480, 0x3600, 0x3780, 0x3900, 0x3a80, + 0x3c00, 0x3d80, 0x3f00, 0x4080, 0x4200, 0x4380, 0x4500, 0x4680, + 0x4800, 0x4980, 0x4b00, 0x4c80, 0x4e00, 0x4f80, 0x5100, 0x5280, + 0x5400, 0x5580, 0x5700, 0x5880, 0x5a00, 0x5b80, 0x5d00, 0x5e80, + 0x6000, 0x6180, 0x6300, 0x6480, 0x6600, 0x6780, 0x6900, 0x6a80, + 0x6c00, 0x6d80, 0x6f00, 0x7080, 0x7200, 0x7380, 0x7500, 0x7680 +}; + +static short lut_nmsedec_sig0[1 << T1_NMSEDEC_BITS] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0080, 0x0080, + 0x0080, 0x0080, 0x0100, 0x0100, 0x0100, 0x0180, 0x0180, 0x0200, + 0x0200, 0x0280, 0x0280, 0x0300, 0x0300, 0x0380, 0x0400, 0x0400, + 0x0480, 0x0500, 0x0580, 0x0580, 0x0600, 0x0680, 0x0700, 0x0780, + 0x0800, 0x0880, 0x0900, 0x0980, 0x0a00, 0x0a80, 0x0b80, 0x0c00, + 0x0c80, 0x0d00, 0x0e00, 0x0e80, 0x0f00, 0x1000, 0x1080, 0x1180, + 0x1200, 0x1300, 0x1380, 0x1480, 0x1500, 0x1600, 0x1700, 0x1780, + 0x1880, 0x1980, 0x1a80, 0x1b00, 0x1c00, 0x1d00, 0x1e00, 0x1f00, + 0x2000, 0x2100, 0x2200, 0x2300, 0x2400, 0x2500, 0x2680, 0x2780, + 0x2880, 0x2980, 0x2b00, 0x2c00, 0x2d00, 0x2e80, 0x2f80, 0x3100, + 0x3200, 0x3380, 0x3480, 0x3600, 0x3700, 0x3880, 0x3a00, 0x3b00, + 0x3c80, 0x3e00, 0x3f80, 0x4080, 0x4200, 0x4380, 0x4500, 0x4680, + 0x4800, 0x4980, 0x4b00, 0x4c80, 0x4e00, 0x4f80, 0x5180, 0x5300, + 0x5480, 0x5600, 0x5800, 0x5980, 0x5b00, 0x5d00, 0x5e80, 0x6080, + 0x6200, 0x6400, 0x6580, 0x6780, 0x6900, 0x6b00, 0x6d00, 0x6e80, + 0x7080, 0x7280, 0x7480, 0x7600, 0x7800, 0x7a00, 0x7c00, 0x7e00 +}; + +static short lut_nmsedec_ref[1 << T1_NMSEDEC_BITS] = { + 0x1800, 0x1780, 0x1700, 0x1680, 0x1600, 0x1580, 0x1500, 0x1480, + 0x1400, 0x1380, 0x1300, 0x1280, 0x1200, 0x1180, 0x1100, 0x1080, + 0x1000, 0x0f80, 0x0f00, 0x0e80, 0x0e00, 0x0d80, 0x0d00, 0x0c80, + 0x0c00, 0x0b80, 0x0b00, 0x0a80, 0x0a00, 0x0980, 0x0900, 0x0880, + 0x0800, 0x0780, 0x0700, 0x0680, 0x0600, 0x0580, 0x0500, 0x0480, + 0x0400, 0x0380, 0x0300, 0x0280, 0x0200, 0x0180, 0x0100, 0x0080, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0080, 0x0100, 0x0180, 0x0200, 0x0280, 0x0300, 0x0380, + 0x0400, 0x0480, 0x0500, 0x0580, 0x0600, 0x0680, 0x0700, 0x0780, + 0x0800, 0x0880, 0x0900, 0x0980, 0x0a00, 0x0a80, 0x0b00, 0x0b80, + 0x0c00, 0x0c80, 0x0d00, 0x0d80, 0x0e00, 0x0e80, 0x0f00, 0x0f80, + 0x1000, 0x1080, 0x1100, 0x1180, 0x1200, 0x1280, 0x1300, 0x1380, + 0x1400, 0x1480, 0x1500, 0x1580, 0x1600, 0x1680, 0x1700, 0x1780 +}; + +static short lut_nmsedec_ref0[1 << T1_NMSEDEC_BITS] = { + 0x2000, 0x1f00, 0x1e00, 0x1d00, 0x1c00, 0x1b00, 0x1a80, 0x1980, + 0x1880, 0x1780, 0x1700, 0x1600, 0x1500, 0x1480, 0x1380, 0x1300, + 0x1200, 0x1180, 0x1080, 0x1000, 0x0f00, 0x0e80, 0x0e00, 0x0d00, + 0x0c80, 0x0c00, 0x0b80, 0x0a80, 0x0a00, 0x0980, 0x0900, 0x0880, + 0x0800, 0x0780, 0x0700, 0x0680, 0x0600, 0x0580, 0x0580, 0x0500, + 0x0480, 0x0400, 0x0400, 0x0380, 0x0300, 0x0300, 0x0280, 0x0280, + 0x0200, 0x0200, 0x0180, 0x0180, 0x0100, 0x0100, 0x0100, 0x0080, + 0x0080, 0x0080, 0x0080, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0080, 0x0080, + 0x0080, 0x0080, 0x0100, 0x0100, 0x0100, 0x0180, 0x0180, 0x0200, + 0x0200, 0x0280, 0x0280, 0x0300, 0x0300, 0x0380, 0x0400, 0x0400, + 0x0480, 0x0500, 0x0580, 0x0580, 0x0600, 0x0680, 0x0700, 0x0780, + 0x0800, 0x0880, 0x0900, 0x0980, 0x0a00, 0x0a80, 0x0b80, 0x0c00, + 0x0c80, 0x0d00, 0x0e00, 0x0e80, 0x0f00, 0x1000, 0x1080, 0x1180, + 0x1200, 0x1300, 0x1380, 0x1480, 0x1500, 0x1600, 0x1700, 0x1780, + 0x1880, 0x1980, 0x1a80, 0x1b00, 0x1c00, 0x1d00, 0x1e00, 0x1f00 +}; diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/t2.c b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/t2.c new file mode 100644 index 0000000..812f70a --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/t2.c @@ -0,0 +1,1287 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "openjpeg.h" +#include "opj_includes.h" +#include "t2.h" +#include "bio.h" +#include "tcd.h" +#include "pi.h" +#include "event.h" +#include "j2k.h" +#include "tgt.h" +#include "int.h" +#include "opj_malloc.h" +#include "pi.h" + + +/** @defgroup T2 T2 - Implementation of a tier-2 coding */ +/*@{*/ + +/** @name Local static functions */ +/*@{*/ + +static void t2_putcommacode(opj_bio_t *bio, OPJ_UINT32 n); +static OPJ_UINT32 t2_getcommacode(opj_bio_t *bio); +/** +Variable length code for signalling delta Zil (truncation point) +@param bio Bit Input/Output component +@param n delta Zil +*/ +static void t2_putnumpasses(opj_bio_t *bio, OPJ_UINT32 n); +static OPJ_UINT32 t2_getnumpasses(opj_bio_t *bio); +/** +Encode a packet of a tile to a destination buffer +@param tile Tile for which to write the packets +@param tcp Tile coding parameters +@param pi Packet identity +@param dest Destination buffer +@param len Length of the destination buffer +@param cstr_info Codestream information structure +@param tileno Number of the tile encoded +@return +*/ +static bool t2_encode_packet( + OPJ_UINT32 tileno, + opj_tcd_tile_t *tile, + opj_tcp_t *tcp, + opj_pi_iterator_t *pi, + OPJ_BYTE *dest, + OPJ_UINT32 * p_data_written, + OPJ_UINT32 len, + opj_codestream_info_t *cstr_info); +/** +@param seg +@param cblksty +@param first +*/ +static bool t2_init_seg(opj_tcd_cblk_dec_t* cblk, OPJ_UINT32 index, OPJ_UINT32 cblksty, OPJ_UINT32 first); +/** +Decode a packet of a tile from a source buffer +@param t2 T2 handle +@param src Source buffer +@param len Length of the source buffer +@param tile Tile for which to write the packets +@param tcp Tile coding parameters +@param pi Packet identity +@return +*/ +static bool t2_decode_packet( + opj_t2_t* p_t2, + opj_tcd_tile_t *p_tile, + opj_tcp_t *p_tcp, + opj_pi_iterator_t *p_pi, + OPJ_BYTE *p_src, + OPJ_UINT32 * p_data_read, + OPJ_UINT32 p_max_length, + opj_packet_info_t *p_pack_info); + +/*@}*/ + +/*@}*/ + +/* ----------------------------------------------------------------------- */ + +/* #define RESTART 0x04 */ + +static void t2_putcommacode(opj_bio_t *bio, OPJ_UINT32 n) { + while + (--n != -1) + { + bio_write(bio, 1, 1); + } + bio_write(bio, 0, 1); +} + +static OPJ_UINT32 t2_getcommacode(opj_bio_t *bio) { + OPJ_UINT32 n = 0; + while + (bio_read(bio, 1)) + { + ++n; + } + return n; +} + +static void t2_putnumpasses(opj_bio_t *bio, OPJ_UINT32 n) { + if (n == 1) { + bio_write(bio, 0, 1); + } else if (n == 2) { + bio_write(bio, 2, 2); + } else if (n <= 5) { + bio_write(bio, 0xc | (n - 3), 4); + } else if (n <= 36) { + bio_write(bio, 0x1e0 | (n - 6), 9); + } else if (n <= 164) { + bio_write(bio, 0xff80 | (n - 37), 16); + } +} + +static OPJ_UINT32 t2_getnumpasses(opj_bio_t *bio) { + OPJ_UINT32 n; + if (!bio_read(bio, 1)) + return 1; + if (!bio_read(bio, 1)) + return 2; + if ((n = bio_read(bio, 2)) != 3) + return (3 + n); + if ((n = bio_read(bio, 5)) != 31) + return (6 + n); + return (37 + bio_read(bio, 7)); +} + +static bool t2_encode_packet( + OPJ_UINT32 tileno, + opj_tcd_tile_t * tile, + opj_tcp_t * tcp, + opj_pi_iterator_t *pi, + OPJ_BYTE *dest, + OPJ_UINT32 * p_data_written, + OPJ_UINT32 length, + opj_codestream_info_t *cstr_info) +{ + OPJ_UINT32 bandno, cblkno; + OPJ_BYTE *c = dest; + OPJ_UINT32 l_nb_bytes; + OPJ_UINT32 compno = pi->compno; /* component value */ + OPJ_UINT32 resno = pi->resno; /* resolution level value */ + OPJ_UINT32 precno = pi->precno; /* precinct value */ + OPJ_UINT32 layno = pi->layno; /* quality layer value */ + OPJ_UINT32 l_nb_blocks; + opj_tcd_band_t *band = 00; + opj_tcd_cblk_enc_t* cblk = 00; + opj_tcd_pass_t *pass = 00; + + opj_tcd_tilecomp_t *tilec = &tile->comps[compno]; + opj_tcd_resolution_t *res = &tilec->resolutions[resno]; + + opj_bio_t *bio = 00; /* BIO component */ + + /* */ + if (tcp->csty & J2K_CP_CSTY_SOP) { + c[0] = 255; + c[1] = 145; + c[2] = 0; + c[3] = 4; + c[4] = (tile->packno % 65536) / 256; + c[5] = (tile->packno % 65536) % 256; + c += 6; + length -= 6; + } + /* */ + + if (!layno) { + band = res->bands; + for + (bandno = 0; bandno < res->numbands; ++bandno) + { + opj_tcd_precinct_t *prc = &band->precincts[precno]; + tgt_reset(prc->incltree); + tgt_reset(prc->imsbtree); + l_nb_blocks = prc->cw * prc->ch; + for + (cblkno = 0; cblkno < l_nb_blocks; ++cblkno) + { + opj_tcd_cblk_enc_t* cblk = &prc->cblks.enc[cblkno]; + cblk->numpasses = 0; + tgt_setvalue(prc->imsbtree, cblkno, band->numbps - cblk->numbps); + } + ++band; + } + } + + bio = bio_create(); + bio_init_enc(bio, c, length); + bio_write(bio, 1, 1); /* Empty header bit */ + + /* Writing Packet header */ + band = res->bands; + for + (bandno = 0; bandno < res->numbands; ++bandno) + { + opj_tcd_precinct_t *prc = &band->precincts[precno]; + l_nb_blocks = prc->cw * prc->ch; + cblk = prc->cblks.enc; + for (cblkno = 0; cblkno < l_nb_blocks; ++cblkno) + { + opj_tcd_layer_t *layer = &cblk->layers[layno]; + if + (!cblk->numpasses && layer->numpasses) + { + tgt_setvalue(prc->incltree, cblkno, layno); + } + ++cblk; + } + cblk = prc->cblks.enc; + for + (cblkno = 0; cblkno < l_nb_blocks; cblkno++) + { + opj_tcd_layer_t *layer = &cblk->layers[layno]; + OPJ_UINT32 increment = 0; + OPJ_UINT32 nump = 0; + OPJ_UINT32 len = 0, passno; + OPJ_UINT32 l_nb_passes; + /* cblk inclusion bits */ + if (!cblk->numpasses) { + tgt_encode(bio, prc->incltree, cblkno, layno + 1); + } else { + bio_write(bio, layer->numpasses != 0, 1); + } + /* if cblk not included, go to the next cblk */ + if + (!layer->numpasses) + { + ++cblk; + continue; + } + /* if first instance of cblk --> zero bit-planes information */ + if + (!cblk->numpasses) + { + cblk->numlenbits = 3; + tgt_encode(bio, prc->imsbtree, cblkno, 999); + } + /* number of coding passes included */ + t2_putnumpasses(bio, layer->numpasses); + l_nb_passes = cblk->numpasses + layer->numpasses; + pass = cblk->passes + cblk->numpasses; + /* computation of the increase of the length indicator and insertion in the header */ + for + (passno = cblk->numpasses; passno < l_nb_passes; ++passno) + { + ++nump; + len += pass->len; + if + (pass->term || passno == (cblk->numpasses + layer->numpasses) - 1) + { + increment = int_max(increment, int_floorlog2(len) + 1 - (cblk->numlenbits + int_floorlog2(nump))); + len = 0; + nump = 0; + } + ++pass; + } + t2_putcommacode(bio, increment); + + /* computation of the new Length indicator */ + cblk->numlenbits += increment; + + pass = cblk->passes + cblk->numpasses; + /* insertion of the codeword segment length */ + for + (passno = cblk->numpasses; passno < l_nb_passes; ++passno) + { + nump++; + len += pass->len; + if + (pass->term || passno == (cblk->numpasses + layer->numpasses) - 1) + { + bio_write(bio, len, cblk->numlenbits + int_floorlog2(nump)); + len = 0; + nump = 0; + } + ++pass; + } + ++cblk; + } + ++band; + } + + if + (bio_flush(bio)) + { + bio_destroy(bio); + return false; /* modified to eliminate longjmp !! */ + } + l_nb_bytes = bio_numbytes(bio); + c += l_nb_bytes; + length -= l_nb_bytes; + bio_destroy(bio); + + /* */ + if (tcp->csty & J2K_CP_CSTY_EPH) { + c[0] = 255; + c[1] = 146; + c += 2; + length -= 2; + } + /* */ + + /* << INDEX */ + // End of packet header position. Currently only represents the distance to start of packet + // Will be updated later by incrementing with packet start value + if(cstr_info && cstr_info->index_write) { + opj_packet_info_t *info_PK = &cstr_info->tile[tileno].packet[cstr_info->packno]; + info_PK->end_ph_pos = (OPJ_INT32)(c - dest); + } + /* INDEX >> */ + + /* Writing the packet body */ + band = res->bands; + for + (bandno = 0; bandno < res->numbands; bandno++) + { + opj_tcd_precinct_t *prc = &band->precincts[precno]; + l_nb_blocks = prc->cw * prc->ch; + cblk = prc->cblks.enc; + for + (cblkno = 0; cblkno < l_nb_blocks; ++cblkno) + { + opj_tcd_layer_t *layer = &cblk->layers[layno]; + if + (!layer->numpasses) + { + ++cblk; + continue; + } + if + (layer->len > length) + { + return false; + } + memcpy(c, layer->data, layer->len); + cblk->numpasses += layer->numpasses; + c += layer->len; + length -= layer->len; + /* << INDEX */ + if(cstr_info && cstr_info->index_write) { + opj_packet_info_t *info_PK = &cstr_info->tile[tileno].packet[cstr_info->packno]; + info_PK->disto += layer->disto; + if (cstr_info->D_max < info_PK->disto) { + cstr_info->D_max = info_PK->disto; + } + } + ++cblk; + /* INDEX >> */ + } + ++band; + } + * p_data_written += (c - dest); + return true; +} + +static bool t2_init_seg(opj_tcd_cblk_dec_t* cblk, OPJ_UINT32 index, OPJ_UINT32 cblksty, OPJ_UINT32 first) +{ + opj_tcd_seg_t* seg = 00; + OPJ_UINT32 l_nb_segs = index + 1; + + if + (l_nb_segs > cblk->m_current_max_segs) + { + cblk->m_current_max_segs += J2K_DEFAULT_NB_SEGS; + cblk->segs = (opj_tcd_seg_t*) opj_realloc(cblk->segs, cblk->m_current_max_segs * sizeof(opj_tcd_seg_t)); + if + (! cblk->segs) + { + return false; + } + } + seg = &cblk->segs[index]; + memset(seg,0,sizeof(opj_tcd_seg_t)); + + if (cblksty & J2K_CCP_CBLKSTY_TERMALL) { + seg->maxpasses = 1; + } + else if (cblksty & J2K_CCP_CBLKSTY_LAZY) { + if (first) { + seg->maxpasses = 10; + } else { + seg->maxpasses = (((seg - 1)->maxpasses == 1) || ((seg - 1)->maxpasses == 10)) ? 2 : 1; + } + } else { + seg->maxpasses = 109; + } + return true; +} + +static bool t2_read_packet_header( + opj_t2_t* p_t2, + opj_tcd_tile_t *p_tile, + opj_tcp_t *p_tcp, + opj_pi_iterator_t *p_pi, + bool * p_is_data_present, + OPJ_BYTE *p_src_data, + OPJ_UINT32 * p_data_read, + OPJ_UINT32 p_max_length, + opj_packet_info_t *p_pack_info) +{ + /* loop */ + OPJ_UINT32 bandno, cblkno; + OPJ_UINT32 l_nb_code_blocks; + OPJ_UINT32 l_remaining_length; + OPJ_UINT32 l_header_length; + OPJ_UINT32 * l_modified_length_ptr = 00; + OPJ_BYTE *l_current_data = p_src_data; + opj_cp_t *l_cp = p_t2->cp; + opj_bio_t *l_bio = 00; /* BIO component */ + opj_tcd_band_t *l_band = 00; + opj_tcd_cblk_dec_t* l_cblk = 00; + opj_tcd_resolution_t* l_res = &p_tile->comps[p_pi->compno].resolutions[p_pi->resno]; + + OPJ_BYTE *l_header_data = 00; + OPJ_BYTE **l_header_data_start = 00; + + OPJ_UINT32 l_present; + + if + (p_pi->layno == 0) + { + l_band = l_res->bands; + /* reset tagtrees */ + for + (bandno = 0; bandno < l_res->numbands; ++bandno) + { + opj_tcd_precinct_t *l_prc = &l_band->precincts[p_pi->precno]; + + if ( + ! ((l_band->x1-l_band->x0 == 0)||(l_band->y1-l_band->y0 == 0))) + { + tgt_reset(l_prc->incltree); + tgt_reset(l_prc->imsbtree); + l_cblk = l_prc->cblks.dec; + l_nb_code_blocks = l_prc->cw * l_prc->ch; + for + (cblkno = 0; cblkno < l_nb_code_blocks; ++cblkno) + { + l_cblk->numsegs = 0; + l_cblk->real_num_segs = 0; + ++l_cblk; + } + } + ++l_band; + } + } + + /* SOP markers */ + + if (p_tcp->csty & J2K_CP_CSTY_SOP) { + if ((*l_current_data) != 0xff || (*(l_current_data + 1) != 0x91)) { + // TODO opj_event_msg(t2->cinfo->event_mgr, EVT_WARNING, "Expected SOP marker\n"); + } else { + l_current_data += 6; + } + + /** TODO : check the Nsop value */ + } + + /* + When the marker PPT/PPM is used the packet header are store in PPT/PPM marker + This part deal with this caracteristic + step 1: Read packet header in the saved structure + step 2: Return to codestream for decoding + */ + + l_bio = bio_create(); + if + (! l_bio) + { + return false; + } + + if + (l_cp->ppm == 1) + { /* PPM */ + l_header_data_start = &l_cp->ppm_data; + l_header_data = *l_header_data_start; + l_modified_length_ptr = &(l_cp->ppm_len); + + } + else if + (p_tcp->ppt == 1) + { /* PPT */ + l_header_data_start = &(p_tcp->ppt_data); + l_header_data = *l_header_data_start; + l_modified_length_ptr = &(p_tcp->ppt_len); + } + else + { /* Normal Case */ + l_header_data_start = &(l_current_data); + l_header_data = *l_header_data_start; + l_remaining_length = p_src_data+p_max_length-l_header_data; + l_modified_length_ptr = &(l_remaining_length); + } + bio_init_dec(l_bio, l_header_data,*l_modified_length_ptr); + l_present = bio_read(l_bio, 1); + if + (!l_present) + { + bio_inalign(l_bio); + l_header_data += bio_numbytes(l_bio); + bio_destroy(l_bio); + /* EPH markers */ + if (p_tcp->csty & J2K_CP_CSTY_EPH) { + if ((*l_header_data) != 0xff || (*(l_header_data + 1) != 0x92)) { + printf("Error : expected EPH marker\n"); + } else { + l_header_data += 2; + } + } + l_header_length = (l_header_data - *l_header_data_start); + *l_modified_length_ptr -= l_header_length; + *l_header_data_start += l_header_length; + /* << INDEX */ + // End of packet header position. Currently only represents the distance to start of packet + // Will be updated later by incrementing with packet start value + if + (p_pack_info) + { + p_pack_info->end_ph_pos = (OPJ_INT32)(l_current_data - p_src_data); + } + /* INDEX >> */ + * p_is_data_present = false; + *p_data_read = l_current_data - p_src_data; + return true; + } + + l_band = l_res->bands; + for + (bandno = 0; bandno < l_res->numbands; ++bandno) + { + opj_tcd_precinct_t *l_prc = &(l_band->precincts[p_pi->precno]); + + if ((l_band->x1-l_band->x0 == 0)||(l_band->y1-l_band->y0 == 0)) + { + ++l_band; + continue; + } + l_nb_code_blocks = l_prc->cw * l_prc->ch; + l_cblk = l_prc->cblks.dec; + for + (cblkno = 0; cblkno < l_nb_code_blocks; cblkno++) + { + OPJ_UINT32 l_included,l_increment, l_segno; + OPJ_INT32 n; + /* if cblk not yet included before --> inclusion tagtree */ + if + (!l_cblk->numsegs) + { + l_included = tgt_decode(l_bio, l_prc->incltree, cblkno, p_pi->layno + 1); + /* else one bit */ + } + else + { + l_included = bio_read(l_bio, 1); + } + /* if cblk not included */ + if + (!l_included) + { + l_cblk->numnewpasses = 0; + ++l_cblk; + continue; + } + /* if cblk not yet included --> zero-bitplane tagtree */ + if + (!l_cblk->numsegs) + { + OPJ_UINT32 i = 0; + while + (!tgt_decode(l_bio, l_prc->imsbtree, cblkno, i)) + { + ++i; + } + l_cblk->numbps = l_band->numbps + 1 - i; + l_cblk->numlenbits = 3; + } + /* number of coding passes */ + l_cblk->numnewpasses = t2_getnumpasses(l_bio); + l_increment = t2_getcommacode(l_bio); + /* length indicator increment */ + l_cblk->numlenbits += l_increment; + l_segno = 0; + if + (!l_cblk->numsegs) + { + if + (! t2_init_seg(l_cblk, l_segno, p_tcp->tccps[p_pi->compno].cblksty, 1)) + { + bio_destroy(l_bio); + return false; + } + + } + else + { + l_segno = l_cblk->numsegs - 1; + if + (l_cblk->segs[l_segno].numpasses == l_cblk->segs[l_segno].maxpasses) + { + ++l_segno; + if + (! t2_init_seg(l_cblk, l_segno, p_tcp->tccps[p_pi->compno].cblksty, 0)) + { + bio_destroy(l_bio); + return false; + } + } + } + n = l_cblk->numnewpasses; + + do { + l_cblk->segs[l_segno].numnewpasses = int_min(l_cblk->segs[l_segno].maxpasses - l_cblk->segs[l_segno].numpasses, n); + l_cblk->segs[l_segno].newlen = bio_read(l_bio, l_cblk->numlenbits + uint_floorlog2(l_cblk->segs[l_segno].numnewpasses)); + n -= l_cblk->segs[l_segno].numnewpasses; + if + (n > 0) + { + ++l_segno; + if + (! t2_init_seg(l_cblk, l_segno, p_tcp->tccps[p_pi->compno].cblksty, 0)) + { + bio_destroy(l_bio); + return false; + } + } + } + while (n > 0); + ++l_cblk; + } + ++l_band; + } + + if + (bio_inalign(l_bio)) + { + bio_destroy(l_bio); + return false; + } + + l_header_data += bio_numbytes(l_bio); + bio_destroy(l_bio); + + /* EPH markers */ + if (p_tcp->csty & J2K_CP_CSTY_EPH) { + if ((*l_header_data) != 0xff || (*(l_header_data + 1) != 0x92)) { + // TODO opj_event_msg(t2->cinfo->event_mgr, EVT_ERROR, "Expected EPH marker\n"); + } else { + l_header_data += 2; + } + } + + + l_header_length = (l_header_data - *l_header_data_start); + *l_modified_length_ptr -= l_header_length; + *l_header_data_start += l_header_length; + /* << INDEX */ + // End of packet header position. Currently only represents the distance to start of packet + // Will be updated later by incrementing with packet start value + if + (p_pack_info) + { + p_pack_info->end_ph_pos = (OPJ_INT32)(l_current_data - p_src_data); + } + /* INDEX >> */ + * p_is_data_present = true; + *p_data_read = l_current_data - p_src_data; + return true; +} + +static bool t2_read_packet_data( + opj_t2_t* p_t2, + opj_tcd_tile_t *p_tile, + opj_pi_iterator_t *p_pi, + OPJ_BYTE *p_src_data, + OPJ_UINT32 * p_data_read, + OPJ_UINT32 p_max_length, + opj_packet_info_t *pack_info) +{ + OPJ_UINT32 bandno, cblkno; + OPJ_UINT32 l_nb_code_blocks; + OPJ_BYTE *l_current_data = p_src_data; + opj_tcd_band_t *l_band = 00; + opj_tcd_cblk_dec_t* l_cblk = 00; + opj_tcd_resolution_t* l_res = &p_tile->comps[p_pi->compno].resolutions[p_pi->resno]; + + l_band = l_res->bands; + for + (bandno = 0; bandno < l_res->numbands; ++bandno) + { + opj_tcd_precinct_t *l_prc = &l_band->precincts[p_pi->precno]; + + if + ((l_band->x1-l_band->x0 == 0)||(l_band->y1-l_band->y0 == 0)) + { + ++l_band; + continue; + } + l_nb_code_blocks = l_prc->cw * l_prc->ch; + l_cblk = l_prc->cblks.dec; + for + (cblkno = 0; cblkno < l_nb_code_blocks; ++cblkno) + { + opj_tcd_seg_t *l_seg = 00; + if + (!l_cblk->numnewpasses) + { + /* nothing to do */ + ++l_cblk; + continue; + } + if + (!l_cblk->numsegs) + { + l_seg = l_cblk->segs; + ++l_cblk->numsegs; + l_cblk->len = 0; + } + else + { + l_seg = &l_cblk->segs[l_cblk->numsegs - 1]; + if + (l_seg->numpasses == l_seg->maxpasses) + { + ++l_seg; + ++l_cblk->numsegs; + } + } + + do + { + if + (l_current_data + l_seg->newlen > p_src_data + p_max_length) + { + return false; + } + +#ifdef USE_JPWL + /* we need here a j2k handle to verify if making a check to + the validity of cblocks parameters is selected from user (-W) */ + + /* let's check that we are not exceeding */ + if ((cblk->len + seg->newlen) > 8192) { + opj_event_msg(t2->cinfo, EVT_WARNING, + "JPWL: segment too long (%d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n", + seg->newlen, cblkno, precno, bandno, resno, compno); + if (!JPWL_ASSUME) { + opj_event_msg(t2->cinfo, EVT_ERROR, "JPWL: giving up\n"); + return -999; + } + seg->newlen = 8192 - cblk->len; + opj_event_msg(t2->cinfo, EVT_WARNING, " - truncating segment to %d\n", seg->newlen); + break; + }; + +#endif /* USE_JPWL */ + + memcpy(l_cblk->data + l_cblk->len, l_current_data, l_seg->newlen); + if + (l_seg->numpasses == 0) + { + l_seg->data = &l_cblk->data; + l_seg->dataindex = l_cblk->len; + } + l_current_data += l_seg->newlen; + l_seg->numpasses += l_seg->numnewpasses; + l_cblk->numnewpasses -= l_seg->numnewpasses; + + l_seg->real_num_passes = l_seg->numpasses; + l_cblk->len += l_seg->newlen; + l_seg->len += l_seg->newlen; + if + (l_cblk->numnewpasses > 0) + { + ++l_seg; + ++l_cblk->numsegs; + } + } + while (l_cblk->numnewpasses > 0); + l_cblk->real_num_segs = l_cblk->numsegs; + ++l_cblk; + } + ++l_band; + } + *(p_data_read) = l_current_data - p_src_data; + return true; +} + + +static bool t2_skip_packet_data( + opj_t2_t* p_t2, + opj_tcd_tile_t *p_tile, + opj_pi_iterator_t *p_pi, + OPJ_UINT32 * p_data_read, + OPJ_UINT32 p_max_length, + opj_packet_info_t *pack_info) +{ + OPJ_UINT32 bandno, cblkno; + OPJ_UINT32 l_nb_code_blocks; + opj_tcd_band_t *l_band = 00; + opj_tcd_cblk_dec_t* l_cblk = 00; + + opj_tcd_resolution_t* l_res = &p_tile->comps[p_pi->compno].resolutions[p_pi->resno]; + + *p_data_read = 0; + l_band = l_res->bands; + for + (bandno = 0; bandno < l_res->numbands; ++bandno) + { + opj_tcd_precinct_t *l_prc = &l_band->precincts[p_pi->precno]; + + if + ((l_band->x1-l_band->x0 == 0)||(l_band->y1-l_band->y0 == 0)) + { + ++l_band; + continue; + } + l_nb_code_blocks = l_prc->cw * l_prc->ch; + l_cblk = l_prc->cblks.dec; + for + (cblkno = 0; cblkno < l_nb_code_blocks; ++cblkno) + { + opj_tcd_seg_t *l_seg = 00; + if + (!l_cblk->numnewpasses) + { + /* nothing to do */ + ++l_cblk; + continue; + } + if + (!l_cblk->numsegs) + { + l_seg = l_cblk->segs; + ++l_cblk->numsegs; + l_cblk->len = 0; + } + else + { + l_seg = &l_cblk->segs[l_cblk->numsegs - 1]; + if + (l_seg->numpasses == l_seg->maxpasses) + { + ++l_seg; + ++l_cblk->numsegs; + } + } + + do + { + if + (* p_data_read + l_seg->newlen > p_max_length) + { + return false; + } + +#ifdef USE_JPWL + /* we need here a j2k handle to verify if making a check to + the validity of cblocks parameters is selected from user (-W) */ + + /* let's check that we are not exceeding */ + if ((cblk->len + seg->newlen) > 8192) { + opj_event_msg(t2->cinfo, EVT_WARNING, + "JPWL: segment too long (%d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n", + seg->newlen, cblkno, precno, bandno, resno, compno); + if (!JPWL_ASSUME) { + opj_event_msg(t2->cinfo, EVT_ERROR, "JPWL: giving up\n"); + return -999; + } + seg->newlen = 8192 - cblk->len; + opj_event_msg(t2->cinfo, EVT_WARNING, " - truncating segment to %d\n", seg->newlen); + break; + }; + +#endif /* USE_JPWL */ + *(p_data_read) += l_seg->newlen; + l_seg->numpasses += l_seg->numnewpasses; + l_cblk->numnewpasses -= l_seg->numnewpasses; + if + (l_cblk->numnewpasses > 0) + { + ++l_seg; + ++l_cblk->numsegs; + } + } + while (l_cblk->numnewpasses > 0); + ++l_cblk; + } + ++l_band; + } + return true; +} + +static bool t2_decode_packet( + opj_t2_t* p_t2, + opj_tcd_tile_t *p_tile, + opj_tcp_t *p_tcp, + opj_pi_iterator_t *p_pi, + OPJ_BYTE *p_src, + OPJ_UINT32 * p_data_read, + OPJ_UINT32 p_max_length, + opj_packet_info_t *p_pack_info) +{ + bool l_read_data; + OPJ_UINT32 l_nb_bytes_read = 0; + OPJ_UINT32 l_nb_total_bytes_read = 0; + + *p_data_read = 0; + + if + (! t2_read_packet_header(p_t2,p_tile,p_tcp,p_pi,&l_read_data,p_src,&l_nb_bytes_read,p_max_length,p_pack_info)) + { + return false; + } + p_src += l_nb_bytes_read; + l_nb_total_bytes_read += l_nb_bytes_read; + p_max_length -= l_nb_bytes_read; + /* we should read data for the packet */ + if + (l_read_data) + { + l_nb_bytes_read = 0; + if + (! t2_read_packet_data(p_t2,p_tile,p_pi,p_src,&l_nb_bytes_read,p_max_length,p_pack_info)) + { + return false; + } + l_nb_total_bytes_read += l_nb_bytes_read; + } + *p_data_read = l_nb_total_bytes_read; + return true; +} + +static bool t2_skip_packet( + opj_t2_t* p_t2, + opj_tcd_tile_t *p_tile, + opj_tcp_t *p_tcp, + opj_pi_iterator_t *p_pi, + OPJ_BYTE *p_src, + OPJ_UINT32 * p_data_read, + OPJ_UINT32 p_max_length, + opj_packet_info_t *p_pack_info) +{ + bool l_read_data; + OPJ_UINT32 l_nb_bytes_read = 0; + OPJ_UINT32 l_nb_total_bytes_read = 0; + + *p_data_read = 0; + + if + (! t2_read_packet_header(p_t2,p_tile,p_tcp,p_pi,&l_read_data,p_src,&l_nb_bytes_read,p_max_length,p_pack_info)) + { + return false; + } + p_src += l_nb_bytes_read; + l_nb_total_bytes_read += l_nb_bytes_read; + p_max_length -= l_nb_bytes_read; + /* we should read data for the packet */ + if + (l_read_data) + { + l_nb_bytes_read = 0; + if + (! t2_skip_packet_data(p_t2,p_tile,p_pi,&l_nb_bytes_read,p_max_length,p_pack_info)) + { + return false; + } + l_nb_total_bytes_read += l_nb_bytes_read; + } + *p_data_read = l_nb_total_bytes_read; + return true; +} + +/* ----------------------------------------------------------------------- */ + +bool t2_encode_packets( + opj_t2_t* p_t2, + OPJ_UINT32 p_tile_no, + opj_tcd_tile_t *p_tile, + OPJ_UINT32 p_maxlayers, + OPJ_BYTE *p_dest, + OPJ_UINT32 * p_data_written, + OPJ_UINT32 p_max_len, + opj_codestream_info_t *cstr_info, + OPJ_UINT32 p_tp_num, + OPJ_INT32 p_tp_pos, + OPJ_UINT32 p_pino, + J2K_T2_MODE p_t2_mode) +{ + OPJ_BYTE *l_current_data = p_dest; + OPJ_UINT32 l_nb_bytes = 0; + OPJ_UINT32 compno; + OPJ_UINT32 poc; + opj_pi_iterator_t *l_pi = 00; + opj_pi_iterator_t *l_current_pi = 00; + opj_image_t *l_image = p_t2->image; + opj_cp_t *l_cp = p_t2->cp; + opj_tcp_t *l_tcp = &l_cp->tcps[p_tile_no]; + OPJ_UINT32 pocno = l_cp->m_specific_param.m_enc.m_cinema == CINEMA4K_24? 2: 1; + OPJ_UINT32 l_max_comp = l_cp->m_specific_param.m_enc.m_max_comp_size > 0 ? l_image->numcomps : 1; + OPJ_UINT32 l_nb_pocs = l_tcp->numpocs + 1; + + l_pi = pi_initialise_encode(l_image, l_cp, p_tile_no, p_t2_mode); + if + (!l_pi) + { + return false; + } + * p_data_written = 0; + if + (p_t2_mode == THRESH_CALC ) + { /* Calculating threshold */ + l_current_pi = l_pi; + for + (compno = 0; compno < l_max_comp; ++compno) + { + OPJ_UINT32 l_comp_len = 0; + l_current_pi = l_pi; + + for + (poc = 0; poc < pocno ; ++poc) + { + OPJ_UINT32 l_tp_num = compno; + pi_create_encode(l_pi, l_cp,p_tile_no,poc,l_tp_num,p_tp_pos,p_t2_mode); + while + (pi_next(l_current_pi)) + { + if + (l_current_pi->layno < p_maxlayers) + { + l_nb_bytes = 0; + if + (! t2_encode_packet(p_tile_no,p_tile, l_tcp, l_current_pi, l_current_data, &l_nb_bytes, p_max_len, cstr_info)) + { + pi_destroy(l_pi, l_nb_pocs); + return false; + } + l_comp_len += l_nb_bytes; + l_current_data += l_nb_bytes; + p_max_len -= l_nb_bytes; + * p_data_written += l_nb_bytes; + } + } + if + (l_cp->m_specific_param.m_enc.m_max_comp_size) + { + if + (l_comp_len > l_cp->m_specific_param.m_enc.m_max_comp_size) + { + pi_destroy(l_pi, l_nb_pocs); + return false; + } + } + ++l_current_pi; + } + } + } + else + { /* t2_mode == FINAL_PASS */ + pi_create_encode(l_pi, l_cp,p_tile_no,p_pino,p_tp_num,p_tp_pos,p_t2_mode); + l_current_pi = &l_pi[p_pino]; + while + (pi_next(l_current_pi)) + { + if + (l_current_pi->layno < p_maxlayers) + { + l_nb_bytes=0; + if + (! t2_encode_packet(p_tile_no,p_tile, l_tcp, l_current_pi, l_current_data, &l_nb_bytes, p_max_len, cstr_info)) + { + pi_destroy(l_pi, l_nb_pocs); + return false; + } + l_current_data += l_nb_bytes; + p_max_len -= l_nb_bytes; + * p_data_written += l_nb_bytes; + + /* INDEX >> */ + if(cstr_info) { + if(cstr_info->index_write) { + opj_tile_info_t *info_TL = &cstr_info->tile[p_tile_no]; + opj_packet_info_t *info_PK = &info_TL->packet[cstr_info->packno]; + if (!cstr_info->packno) { + info_PK->start_pos = info_TL->end_header + 1; + } else { + info_PK->start_pos = ((l_cp->m_specific_param.m_enc.m_tp_on | l_tcp->POC)&& info_PK->start_pos) ? info_PK->start_pos : info_TL->packet[cstr_info->packno - 1].end_pos + 1; + } + info_PK->end_pos = info_PK->start_pos + l_nb_bytes - 1; + info_PK->end_ph_pos += info_PK->start_pos - 1; // End of packet header which now only represents the distance + // to start of packet is incremented by value of start of packet + } + + cstr_info->packno++; + } + /* << INDEX */ + ++p_tile->packno; + } + } + } + pi_destroy(l_pi, l_nb_pocs); + return true; +} + +bool t2_decode_packets( + opj_t2_t *p_t2, + OPJ_UINT32 p_tile_no, + struct opj_tcd_tile *p_tile, + OPJ_BYTE *p_src, + OPJ_UINT32 * p_data_read, + OPJ_UINT32 p_max_len, + struct opj_codestream_info *p_cstr_info) +{ + OPJ_BYTE *l_current_data = p_src; + opj_pi_iterator_t *l_pi = 00; + OPJ_UINT32 pino; + opj_image_t *l_image = p_t2->image; + opj_cp_t *l_cp = p_t2->cp; + opj_cp_t *cp = p_t2->cp; + opj_tcp_t *l_tcp = &(p_t2->cp->tcps[p_tile_no]); + OPJ_UINT32 l_nb_bytes_read; + OPJ_UINT32 l_nb_pocs = l_tcp->numpocs + 1; + opj_pi_iterator_t *l_current_pi = 00; + OPJ_UINT32 curtp = 0; + OPJ_UINT32 tp_start_packno; + opj_packet_info_t *l_pack_info = 00; + opj_image_comp_t* l_img_comp = 00; + + + if + (p_cstr_info) + { + l_pack_info = p_cstr_info->tile[p_tile_no].packet; + } + + /* create a packet iterator */ + l_pi = pi_create_decode(l_image, l_cp, p_tile_no); + if + (!l_pi) + { + return false; + } + + tp_start_packno = 0; + l_current_pi = l_pi; + + for + (pino = 0; pino <= l_tcp->numpocs; ++pino) + { + while + (pi_next(l_current_pi)) + { + + if + (l_tcp->num_layers_to_decode > l_current_pi->layno && l_current_pi->resno < p_tile->comps[l_current_pi->compno].minimum_num_resolutions) + { + l_nb_bytes_read = 0; + if + (! t2_decode_packet(p_t2,p_tile,l_tcp,l_current_pi,l_current_data,&l_nb_bytes_read,p_max_len,l_pack_info)) + { + pi_destroy(l_pi,l_nb_pocs); + return false; + } + l_img_comp = &(l_image->comps[l_current_pi->compno]); + l_img_comp->resno_decoded = uint_max(l_current_pi->resno, l_img_comp->resno_decoded); + } + else + { + l_nb_bytes_read = 0; + if + (! t2_skip_packet(p_t2,p_tile,l_tcp,l_current_pi,l_current_data,&l_nb_bytes_read,p_max_len,l_pack_info)) + { + pi_destroy(l_pi,l_nb_pocs); + return false; + } + } + l_current_data += l_nb_bytes_read; + p_max_len -= l_nb_bytes_read; + + /* INDEX >> */ + if(p_cstr_info) { + opj_tile_info_t *info_TL = &p_cstr_info->tile[p_tile_no]; + opj_packet_info_t *info_PK = &info_TL->packet[p_cstr_info->packno]; + if (!p_cstr_info->packno) { + info_PK->start_pos = info_TL->end_header + 1; + } else if (info_TL->packet[p_cstr_info->packno-1].end_pos >= (OPJ_INT32)p_cstr_info->tile[p_tile_no].tp[curtp].tp_end_pos){ // New tile part + info_TL->tp[curtp].tp_numpacks = p_cstr_info->packno - tp_start_packno; // Number of packets in previous tile-part + tp_start_packno = p_cstr_info->packno; + curtp++; + info_PK->start_pos = p_cstr_info->tile[p_tile_no].tp[curtp].tp_end_header+1; + } else { + info_PK->start_pos = (cp->m_specific_param.m_enc.m_tp_on && info_PK->start_pos) ? info_PK->start_pos : info_TL->packet[p_cstr_info->packno - 1].end_pos + 1; + } + info_PK->end_pos = info_PK->start_pos + l_nb_bytes_read - 1; + info_PK->end_ph_pos += info_PK->start_pos - 1; // End of packet header which now only represents the distance + ++p_cstr_info->packno; + } + /* << INDEX */ + } + ++l_current_pi; + } + /* INDEX >> */ + if + (p_cstr_info) { + p_cstr_info->tile[p_tile_no].tp[curtp].tp_numpacks = p_cstr_info->packno - tp_start_packno; // Number of packets in last tile-part + } + /* << INDEX */ + + /* don't forget to release pi */ + pi_destroy(l_pi,l_nb_pocs); + *p_data_read = l_current_data - p_src; + return true; +} + +/* ----------------------------------------------------------------------- */ +/** + * Creates a Tier 2 handle + * + * @param p_image Source or destination image + * @param p_cp Image coding parameters. + * @return a new T2 handle if successful, NULL otherwise. +*/ +opj_t2_t* t2_create( + opj_image_t *p_image, + opj_cp_t *p_cp) +{ + /* create the tcd structure */ + opj_t2_t *l_t2 = (opj_t2_t*)opj_malloc(sizeof(opj_t2_t)); + if + (!l_t2) + { + return 00; + } + memset(l_t2,0,sizeof(opj_t2_t)); + l_t2->image = p_image; + l_t2->cp = p_cp; + return l_t2; +} + +/** + * Destroys a Tier 2 handle. + * + * @param p_t2 the Tier 2 handle to destroy +*/ +void t2_destroy(opj_t2_t *p_t2) +{ + if + (p_t2) + { + opj_free(p_t2); + } +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/t2.h b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/t2.h new file mode 100644 index 0000000..050a264 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/t2.h @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __T2_H +#define __T2_H +/** +@file t2.h +@brief Implementation of a tier-2 coding (packetization of code-block data) (T2) + +*/ +#include "openjpeg.h" + +struct opj_common_struct; +struct opj_image; +struct opj_cp; +struct opj_tcd_tile; +struct opj_codestream_info; + +/** @defgroup T2 T2 - Implementation of a tier-2 coding */ +/*@{*/ + +/** +T2 encoding mode +*/ +typedef enum T2_MODE +{ + THRESH_CALC = 0, /** Function called in Rate allocation process*/ + FINAL_PASS = 1 /** Function called in Tier 2 process*/ +} +J2K_T2_MODE; + +/** +Tier-2 coding +*/ + +typedef struct opj_t2 { + /** Encoding: pointer to the src image. Decoding: pointer to the dst image. */ + struct opj_image *image; + /** pointer to the image coding parameters */ + struct opj_cp *cp; +} opj_t2_t; + +/** @name Exported functions */ +/*@{*/ +/* ----------------------------------------------------------------------- */ + +/** +Encode the packets of a tile to a destination buffer +@param t2 T2 handle +@param tileno number of the tile encoded +@param tile the tile for which to write the packets +@param maxlayers maximum number of layers +@param dest the destination buffer +@param len the length of the destination buffer +@param cstr_info Codestream information structure +@param tpnum Tile part number of the current tile +@param tppos The position of the tile part flag in the progression order +@param t2_mode If == 0 In Threshold calculation ,If == 1 Final pass +*/ +bool t2_encode_packets(opj_t2_t* t2,OPJ_UINT32 tileno, struct opj_tcd_tile *tile, OPJ_UINT32 maxlayers, OPJ_BYTE *dest, OPJ_UINT32 * p_data_written, OPJ_UINT32 len, struct opj_codestream_info *cstr_info,OPJ_UINT32 tpnum, OPJ_INT32 tppos,OPJ_UINT32 pino,J2K_T2_MODE t2_mode); +/** +Decode the packets of a tile from a source buffer +@param t2 T2 handle +@param src the source buffer +@param len length of the source buffer +@param tileno number that identifies the tile for which to decode the packets +@param tile tile for which to decode the packets + */ +bool t2_decode_packets(opj_t2_t *t2, OPJ_UINT32 tileno,struct opj_tcd_tile *tile, OPJ_BYTE *src, OPJ_UINT32 * p_data_read, OPJ_UINT32 len, struct opj_codestream_info *cstr_info); + +/** + * Creates a Tier 2 handle + * + * @param p_image Source or destination image + * @param p_cp Image coding parameters. + * @return a new T2 handle if successful, NULL otherwise. +*/ +opj_t2_t* t2_create(struct opj_image *p_image, struct opj_cp *p_cp); + +/** + * Destroys a Tier 2 handle. + * + * @param p_t2 the Tier 2 handle to destroy +*/ +void t2_destroy(opj_t2_t *t2); + +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __T2_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/tcd.c b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/tcd.c new file mode 100644 index 0000000..6b9c598 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/tcd.c @@ -0,0 +1,2121 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2006-2007, Parvatha Elangovan + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "tcd.h" +#include "openjpeg.h" +#include "j2k.h" +#include "opj_includes.h" +#include "event.h" +#include "t2.h" +#include "t1.h" +#include "opj_malloc.h" +#include "int.h" +#include "tgt.h" +#include "dwt.h" +#include "mct.h" +#include "j2k_lib.h" +#include "profile.h" + +/** + * Deallocates the encoding data of the given precinct. + */ +static void tcd_code_block_enc_deallocate (opj_tcd_precinct_t * p_precinct); +/** + * Allocates memory for an encoding code block. + */ +static bool tcd_code_block_enc_allocate (opj_tcd_cblk_enc_t * p_code_block); +/** + * Allocates memory for a decoding code block. + */ +static bool tcd_code_block_dec_allocate (opj_tcd_cblk_dec_t * p_code_block); +/** +Free the memory allocated for encoding +@param tcd TCD handle +*/ +static void tcd_free_tile(opj_tcd_t *tcd); + +/* ----------------------------------------------------------------------- */ + +/** +Create a new TCD handle +*/ +opj_tcd_t* tcd_create(bool p_is_decoder) +{ + opj_tcd_t *l_tcd = 00; + + /* create the tcd structure */ + l_tcd = (opj_tcd_t*) opj_malloc(sizeof(opj_tcd_t)); + if + (!l_tcd) + { + return 00; + } + memset(l_tcd,0,sizeof(opj_tcd_t)); + l_tcd->m_is_decoder = p_is_decoder ? 1 : 0; + l_tcd->tcd_image = (opj_tcd_image_t*)opj_malloc(sizeof(opj_tcd_image_t)); + if + (!l_tcd->tcd_image) + { + opj_free(l_tcd); + return 00; + } + memset(l_tcd->tcd_image,0,sizeof(opj_tcd_image_t)); + return l_tcd; +} + +/** +Destroy a previously created TCD handle +*/ +void tcd_destroy(opj_tcd_t *tcd) { + if + (tcd) + { + tcd_free_tile(tcd); + if + (tcd->tcd_image) + { + opj_free(tcd->tcd_image); + tcd->tcd_image = 00; + } + opj_free(tcd); + } +} + +/* ----------------------------------------------------------------------- */ +/** + * Initialize the tile coder and may reuse some meory. + * @param p_tcd TCD handle. + * @param p_image raw image. + * @param p_cp coding parameters. + * @param p_tile_no current tile index to encode. + * + * @return true if the encoding values could be set (false otherwise). +*/ +#define MACRO_TCD_ALLOCATE(FUNCTION,TYPE,FRACTION,ELEMENT,FUNCTION_ELEMENT) \ +bool FUNCTION \ + ( \ + opj_tcd_t *p_tcd, \ + OPJ_UINT32 p_tile_no \ + ) \ +{ \ + OPJ_UINT32 (*l_gain_ptr)(OPJ_UINT32) = 00; \ + OPJ_UINT32 compno, resno, bandno, precno, cblkno; \ + opj_tcp_t * l_tcp = 00; \ + opj_cp_t * l_cp = 00; \ + opj_tcd_tile_t * l_tile = 00; \ + opj_tccp_t *l_tccp = 00; \ + opj_tcd_tilecomp_t *l_tilec = 00; \ + opj_image_comp_t * l_image_comp = 00; \ + opj_tcd_resolution_t *l_res = 00; \ + opj_tcd_band_t *l_band = 00; \ + opj_stepsize_t * l_step_size = 00; \ + opj_tcd_precinct_t *l_current_precinct = 00; \ + TYPE* l_code_block = 00; \ + opj_image_t * l_image = 00; \ + OPJ_UINT32 p,q; \ + OPJ_UINT32 l_level_no; \ + OPJ_UINT32 l_pdx, l_pdy; \ + OPJ_UINT32 l_gain; \ + OPJ_INT32 l_x0b, l_y0b; \ + /* extent of precincts , top left, bottom right**/ \ + OPJ_INT32 l_tl_prc_x_start, l_tl_prc_y_start, l_br_prc_x_end, l_br_prc_y_end; \ + /* number of precinct for a resolution */ \ + OPJ_UINT32 l_nb_precincts; \ + /* room needed to store l_nb_precinct precinct for a resolution */ \ + OPJ_UINT32 l_nb_precinct_size; \ + /* number of code blocks for a precinct*/ \ + OPJ_UINT32 l_nb_code_blocks; \ + /* room needed to store l_nb_code_blocks code blocks for a precinct*/ \ + OPJ_UINT32 l_nb_code_blocks_size; \ + /* size of data for a tile */ \ + OPJ_UINT32 l_data_size; \ + l_cp = p_tcd->cp; \ + l_tcp = &(l_cp->tcps[p_tile_no]); \ + l_tile = p_tcd->tcd_image->tiles; \ + l_tccp = l_tcp->tccps; \ + l_tilec = l_tile->comps; \ + l_image = p_tcd->image; \ + l_image_comp = p_tcd->image->comps; \ + \ + p = p_tile_no % l_cp->tw; /* tile coordinates */ \ + q = p_tile_no / l_cp->tw; \ + \ + /* 4 borders of the tile rescale on the image if necessary */ \ + l_tile->x0 = int_max(l_cp->tx0 + p * l_cp->tdx, l_image->x0); \ + l_tile->y0 = int_max(l_cp->ty0 + q * l_cp->tdy, l_image->y0); \ + l_tile->x1 = int_min(l_cp->tx0 + (p + 1) * l_cp->tdx, l_image->x1); \ + l_tile->y1 = int_min(l_cp->ty0 + (q + 1) * l_cp->tdy, l_image->y1); \ + /*tile->numcomps = image->numcomps; */ \ + for \ + (compno = 0; compno < l_tile->numcomps; ++compno) \ + { \ + /* border of each l_tile component (global) */ \ + l_tilec->x0 = int_ceildiv(l_tile->x0, l_image_comp->dx); \ + l_tilec->y0 = int_ceildiv(l_tile->y0, l_image_comp->dy); \ + l_tilec->x1 = int_ceildiv(l_tile->x1, l_image_comp->dx); \ + l_tilec->y1 = int_ceildiv(l_tile->y1, l_image_comp->dy); \ + \ + l_data_size = (l_tilec->x1 - l_tilec->x0) \ + * (l_tilec->y1 - l_tilec->y0) * sizeof(OPJ_UINT32 ); \ + l_tilec->numresolutions = l_tccp->numresolutions; \ + if \ + (l_tccp->numresolutions < l_cp->m_specific_param.m_dec.m_reduce)\ + { \ + l_tilec->minimum_num_resolutions = 1; \ + } \ + else \ + { \ + l_tilec->minimum_num_resolutions = l_tccp->numresolutions - l_cp->m_specific_param.m_dec.m_reduce;\ + } \ + if \ + (l_tilec->data == 00) \ + { \ + l_tilec->data = (OPJ_INT32 *) opj_aligned_malloc(l_data_size); \ + if \ + (! l_tilec->data ) \ + { \ + return false; \ + } \ + l_tilec->data_size = l_data_size; \ + } \ + else if \ + (l_data_size > l_tilec->data_size) \ + { \ + l_tilec->data = (OPJ_INT32 *) opj_realloc(l_tilec->data, l_data_size);\ + if \ + (! l_tilec->data) \ + { \ + return false; \ + } \ + l_tilec->data_size = l_data_size; \ + } \ + l_data_size = l_tilec->numresolutions * sizeof(opj_tcd_resolution_t);\ + if \ + (l_tilec->resolutions == 00) \ + { \ + l_tilec->resolutions = (opj_tcd_resolution_t *) opj_malloc(l_data_size);\ + if \ + (! l_tilec->resolutions ) \ + { \ + return false; \ + } \ + l_tilec->resolutions_size = l_data_size; \ + memset(l_tilec->resolutions,0,l_data_size); \ + } \ + else if \ + (l_data_size > l_tilec->resolutions_size) \ + { \ + l_tilec->resolutions = (opj_tcd_resolution_t *) opj_realloc(l_tilec->resolutions, l_data_size);\ + if \ + (! l_tilec->resolutions) \ + { \ + return false; \ + } \ + memset(((OPJ_BYTE*) l_tilec->resolutions)+l_tilec->resolutions_size,0,l_data_size - l_tilec->resolutions_size);\ + l_tilec->resolutions_size = l_data_size; \ + } \ + l_level_no = l_tilec->numresolutions - 1; \ + l_res = l_tilec->resolutions; \ + l_step_size = l_tccp->stepsizes; \ + if \ + (l_tccp->qmfbid == 0) \ + { \ + l_gain_ptr = &dwt_getgain_real; \ + } \ + else \ + { \ + l_gain_ptr = &dwt_getgain; \ + } \ + for \ + (resno = 0; resno < l_tilec->numresolutions; ++resno) \ + { \ + OPJ_INT32 tlcbgxstart, tlcbgystart, brcbgxend, brcbgyend; \ + OPJ_UINT32 cbgwidthexpn, cbgheightexpn; \ + OPJ_UINT32 cblkwidthexpn, cblkheightexpn; \ + /* border for each resolution level (global) */ \ + l_res->x0 = int_ceildivpow2(l_tilec->x0, l_level_no); \ + l_res->y0 = int_ceildivpow2(l_tilec->y0, l_level_no); \ + l_res->x1 = int_ceildivpow2(l_tilec->x1, l_level_no); \ + l_res->y1 = int_ceildivpow2(l_tilec->y1, l_level_no); \ + /* p. 35, table A-23, ISO/IEC FDIS154444-1 : 2000 (18 august 2000) */\ + l_pdx = l_tccp->prcw[resno]; \ + l_pdy = l_tccp->prch[resno]; \ + /* p. 64, B.6, ISO/IEC FDIS15444-1 : 2000 (18 august 2000) */ \ + l_tl_prc_x_start = int_floordivpow2(l_res->x0, l_pdx) << l_pdx; \ + l_tl_prc_y_start = int_floordivpow2(l_res->y0, l_pdy) << l_pdy; \ + l_br_prc_x_end = int_ceildivpow2(l_res->x1, l_pdx) << l_pdx; \ + l_br_prc_y_end = int_ceildivpow2(l_res->y1, l_pdy) << l_pdy; \ + \ + l_res->pw = (l_res->x0 == l_res->x1) ? 0 : ((l_br_prc_x_end - l_tl_prc_x_start) >> l_pdx);\ + l_res->ph = (l_res->y0 == l_res->y1) ? 0 : ((l_br_prc_y_end - l_tl_prc_y_start) >> l_pdy);\ + l_nb_precincts = l_res->pw * l_res->ph; \ + l_nb_precinct_size = l_nb_precincts * sizeof(opj_tcd_precinct_t);\ + if \ + (resno == 0) \ + { \ + tlcbgxstart = l_tl_prc_x_start; \ + tlcbgystart = l_tl_prc_y_start; \ + brcbgxend = l_br_prc_x_end; \ + brcbgyend = l_br_prc_y_end; \ + cbgwidthexpn = l_pdx; \ + cbgheightexpn = l_pdy; \ + l_res->numbands = 1; \ + } \ + else \ + { \ + tlcbgxstart = int_ceildivpow2(l_tl_prc_x_start, 1); \ + tlcbgystart = int_ceildivpow2(l_tl_prc_y_start, 1); \ + brcbgxend = int_ceildivpow2(l_br_prc_x_end, 1); \ + brcbgyend = int_ceildivpow2(l_br_prc_y_end, 1); \ + cbgwidthexpn = l_pdx - 1; \ + cbgheightexpn = l_pdy - 1; \ + l_res->numbands = 3; \ + } \ + \ + cblkwidthexpn = uint_min(l_tccp->cblkw, cbgwidthexpn); \ + cblkheightexpn = uint_min(l_tccp->cblkh, cbgheightexpn); \ + l_band = l_res->bands; \ + for \ + (bandno = 0; bandno < l_res->numbands; ++bandno) \ + { \ + OPJ_INT32 numbps; \ + if \ + (resno == 0) \ + { \ + l_band->bandno = 0 ; \ + l_band->x0 = int_ceildivpow2(l_tilec->x0, l_level_no); \ + l_band->y0 = int_ceildivpow2(l_tilec->y0, l_level_no); \ + l_band->x1 = int_ceildivpow2(l_tilec->x1, l_level_no); \ + l_band->y1 = int_ceildivpow2(l_tilec->y1, l_level_no); \ + } \ + else \ + { \ + l_band->bandno = bandno + 1; \ + /* x0b = 1 if bandno = 1 or 3 */ \ + l_x0b = l_band->bandno&1; \ + /* y0b = 1 if bandno = 2 or 3 */ \ + l_y0b = (l_band->bandno)>>1; \ + /* l_band border (global) */ \ + l_band->x0 = int_ceildivpow2(l_tilec->x0 - (1 << l_level_no) * l_x0b, l_level_no + 1);\ + l_band->y0 = int_ceildivpow2(l_tilec->y0 - (1 << l_level_no) * l_y0b, l_level_no + 1);\ + l_band->x1 = int_ceildivpow2(l_tilec->x1 - (1 << l_level_no) * l_x0b, l_level_no + 1);\ + l_band->y1 = int_ceildivpow2(l_tilec->y1 - (1 << l_level_no) * l_y0b, l_level_no + 1);\ + } \ + /** avoid an if with storing function pointer */ \ + l_gain = (*l_gain_ptr) (l_band->bandno); \ + numbps = l_image_comp->prec + l_gain; \ + l_band->stepsize = (OPJ_FLOAT32)(((1.0 + l_step_size->mant / 2048.0) * pow(2.0, (OPJ_INT32) (numbps - l_step_size->expn)))) * FRACTION;\ + l_band->numbps = l_step_size->expn + l_tccp->numgbits - 1; /* WHY -1 ? */\ + if \ + (! l_band->precincts) \ + { \ + l_band->precincts = (opj_tcd_precinct_t *) opj_malloc(/*3 * */ l_nb_precinct_size);\ + if \ + (! l_band->precincts) \ + { \ + return false; \ + } \ + memset(l_band->precincts,0,l_nb_precinct_size); \ + l_band->precincts_data_size = l_nb_precinct_size; \ + } \ + else if \ + (l_band->precincts_data_size < l_nb_precinct_size) \ + { \ + l_band->precincts = (opj_tcd_precinct_t *) opj_realloc(l_band->precincts,/*3 * */ l_nb_precinct_size);\ + if \ + (! l_band->precincts) \ + { \ + return false; \ + } \ + memset(((OPJ_BYTE *) l_band->precincts) + l_band->precincts_data_size,0,l_nb_precinct_size - l_band->precincts_data_size);\ + l_band->precincts_data_size = l_nb_precinct_size; \ + } \ + l_current_precinct = l_band->precincts; \ + for \ + (precno = 0; precno < l_nb_precincts; ++precno) \ + { \ + OPJ_INT32 tlcblkxstart, tlcblkystart, brcblkxend, brcblkyend; \ + OPJ_INT32 cbgxstart = tlcbgxstart + (precno % l_res->pw) * (1 << cbgwidthexpn);\ + OPJ_INT32 cbgystart = tlcbgystart + (precno / l_res->pw) * (1 << cbgheightexpn);\ + OPJ_INT32 cbgxend = cbgxstart + (1 << cbgwidthexpn); \ + OPJ_INT32 cbgyend = cbgystart + (1 << cbgheightexpn); \ + /* precinct size (global) */ \ + l_current_precinct->x0 = int_max(cbgxstart, l_band->x0);\ + l_current_precinct->y0 = int_max(cbgystart, l_band->y0);\ + l_current_precinct->x1 = int_min(cbgxend, l_band->x1); \ + l_current_precinct->y1 = int_min(cbgyend, l_band->y1); \ + tlcblkxstart = int_floordivpow2(l_current_precinct->x0, cblkwidthexpn) << cblkwidthexpn;\ + tlcblkystart = int_floordivpow2(l_current_precinct->y0, cblkheightexpn) << cblkheightexpn;\ + brcblkxend = int_ceildivpow2(l_current_precinct->x1, cblkwidthexpn) << cblkwidthexpn;\ + brcblkyend = int_ceildivpow2(l_current_precinct->y1, cblkheightexpn) << cblkheightexpn;\ + l_current_precinct->cw = (brcblkxend - tlcblkxstart) >> cblkwidthexpn;\ + l_current_precinct->ch = (brcblkyend - tlcblkystart) >> cblkheightexpn;\ + l_nb_code_blocks = l_current_precinct->cw * l_current_precinct->ch;\ + l_nb_code_blocks_size = l_nb_code_blocks * sizeof(TYPE);\ + if \ + (! l_current_precinct->cblks.ELEMENT) \ + { \ + l_current_precinct->cblks.ELEMENT = (TYPE*) opj_malloc(l_nb_code_blocks_size);\ + if \ + (! l_current_precinct->cblks.ELEMENT ) \ + { \ + return false; \ + } \ + memset(l_current_precinct->cblks.ELEMENT,0,l_nb_code_blocks_size);\ + l_current_precinct->block_size = l_nb_code_blocks_size;\ + } \ + else if \ + (l_nb_code_blocks_size > l_current_precinct->block_size)\ + { \ + l_current_precinct->cblks.ELEMENT = (TYPE*) \ + opj_realloc(l_current_precinct->cblks.ELEMENT, l_nb_code_blocks_size);\ + if \ + (! l_current_precinct->cblks.ELEMENT ) \ + { \ + return false; \ + } \ + memset(((OPJ_BYTE *) l_current_precinct->cblks.ELEMENT) + l_current_precinct->block_size\ + ,0 \ + ,l_nb_code_blocks_size - l_current_precinct->block_size);\ + l_current_precinct->block_size = l_nb_code_blocks_size;\ + } \ + if \ + (! l_current_precinct->incltree) \ + { \ + l_current_precinct->incltree = tgt_create(l_current_precinct->cw,\ + l_current_precinct->ch);\ + } \ + else \ + { \ + l_current_precinct->incltree = tgt_init(l_current_precinct->incltree,\ + l_current_precinct->cw, \ + l_current_precinct->ch);\ + } \ + if \ + (! l_current_precinct->incltree) \ + { \ + return false; \ + } \ + if \ + (! l_current_precinct->imsbtree) \ + { \ + l_current_precinct->imsbtree = tgt_create( \ + l_current_precinct->cw,\ + l_current_precinct->ch);\ + } \ + else \ + { \ + l_current_precinct->imsbtree = tgt_init( \ + l_current_precinct->imsbtree,\ + l_current_precinct->cw,\ + l_current_precinct->ch);\ + } \ + if \ + (! l_current_precinct->imsbtree) \ + { \ + return false; \ + } \ + l_code_block = l_current_precinct->cblks.ELEMENT; \ + for \ + (cblkno = 0; cblkno < l_nb_code_blocks; ++cblkno) \ + { \ + OPJ_INT32 cblkxstart = tlcblkxstart + (cblkno % l_current_precinct->cw) * (1 << cblkwidthexpn);\ + OPJ_INT32 cblkystart = tlcblkystart + (cblkno / l_current_precinct->cw) * (1 << cblkheightexpn);\ + OPJ_INT32 cblkxend = cblkxstart + (1 << cblkwidthexpn); \ + OPJ_INT32 cblkyend = cblkystart + (1 << cblkheightexpn); \ + /* code-block size (global) */ \ + l_code_block->x0 = int_max(cblkxstart, l_current_precinct->x0);\ + l_code_block->y0 = int_max(cblkystart, l_current_precinct->y0);\ + l_code_block->x1 = int_min(cblkxend, l_current_precinct->x1);\ + l_code_block->y1 = int_min(cblkyend, l_current_precinct->y1);\ + if \ + (! FUNCTION_ELEMENT(l_code_block)) \ + { \ + return false; \ + } \ + ++l_code_block; \ + } \ + ++l_current_precinct; \ + } /* precno */ \ + ++l_band; \ + ++l_step_size; \ + } /* bandno */ \ + ++l_res; \ + --l_level_no; \ + } /* resno */ \ + ++l_tccp; \ + ++l_tilec; \ + ++l_image_comp; \ + } /* compno */ \ + return true; \ +} \ + +MACRO_TCD_ALLOCATE(tcd_init_encode_tile,opj_tcd_cblk_enc_t,1.f,enc,tcd_code_block_enc_allocate) +MACRO_TCD_ALLOCATE(tcd_init_decode_tile,opj_tcd_cblk_dec_t,0.5f,dec,tcd_code_block_dec_allocate) + +#undef MACRO_TCD_ALLOCATE + +/** + * Allocates memory for an encoding code block. + */ +bool tcd_code_block_enc_allocate (opj_tcd_cblk_enc_t * p_code_block) +{ + if + (! p_code_block->data) + { + p_code_block->data = (OPJ_BYTE*) opj_malloc(8192+1); + if + (! p_code_block->data) + { + return false; + } + p_code_block->data+=1; + /* no memset since data */ + p_code_block->layers = (opj_tcd_layer_t*) opj_malloc(100 * sizeof(opj_tcd_layer_t)); + if + (! p_code_block->layers) + { + return false; + } + p_code_block->passes = (opj_tcd_pass_t*) opj_malloc(100 * sizeof(opj_tcd_pass_t)); + if + (! p_code_block->passes) + { + return false; + } + } + memset(p_code_block->layers,0,100 * sizeof(opj_tcd_layer_t)); + memset(p_code_block->passes,0,100 * sizeof(opj_tcd_pass_t)); + return true; +} + +/** + * Allocates memory for a decoding code block. + */ +bool tcd_code_block_dec_allocate (opj_tcd_cblk_dec_t * p_code_block) +{ + OPJ_UINT32 l_seg_size; + + if + (! p_code_block->data) + { + p_code_block->data = (OPJ_BYTE*) opj_malloc(8192); + if + (! p_code_block->data) + { + return false; + } + l_seg_size = J2K_DEFAULT_NB_SEGS * sizeof(opj_tcd_seg_t); + p_code_block->segs = (opj_tcd_seg_t *) opj_malloc(l_seg_size); + if + (! p_code_block->segs) + { + return false; + } + memset(p_code_block->segs,0,l_seg_size); + p_code_block->m_current_max_segs = J2K_DEFAULT_NB_SEGS; + } + // TODO + //p_code_block->numsegs = 0; + return true; +} + +/** + * Deallocates the encoding data of the given precinct. + */ +void tcd_code_block_enc_deallocate (opj_tcd_precinct_t * p_precinct) +{ + OPJ_UINT32 cblkno , l_nb_code_blocks; + + opj_tcd_cblk_enc_t * l_code_block = p_precinct->cblks.enc; + if + (l_code_block) + { + l_nb_code_blocks = p_precinct->block_size / sizeof(opj_tcd_cblk_enc_t); + for + (cblkno = 0; cblkno < l_nb_code_blocks; ++cblkno) + { + if + (l_code_block->data) + { + opj_free(l_code_block->data-1); + l_code_block->data = 00; + } + if + (l_code_block->layers) + { + opj_free(l_code_block->layers ); + l_code_block->layers = 00; + } + if + (l_code_block->passes) + { + opj_free(l_code_block->passes ); + l_code_block->passes = 00; + } + ++l_code_block; + } + opj_free(p_precinct->cblks.enc); + p_precinct->cblks.enc = 00; + } +} + +/** + * Deallocates the encoding data of the given precinct. + */ +void tcd_code_block_dec_deallocate (opj_tcd_precinct_t * p_precinct) +{ + OPJ_UINT32 cblkno , l_nb_code_blocks; + + opj_tcd_cblk_dec_t * l_code_block = p_precinct->cblks.dec; + if + (l_code_block) + { + l_nb_code_blocks = p_precinct->block_size / sizeof(opj_tcd_cblk_dec_t); + for + (cblkno = 0; cblkno < l_nb_code_blocks; ++cblkno) + { + if + (l_code_block->data) + { + opj_free(l_code_block->data); + l_code_block->data = 00; + } + if + (l_code_block->segs) + { + opj_free(l_code_block->segs ); + l_code_block->segs = 00; + } + ++l_code_block; + } + opj_free(p_precinct->cblks.dec); + p_precinct->cblks.dec = 00; + } +} + +void tcd_free_tile(opj_tcd_t *p_tcd) +{ + OPJ_UINT32 compno, resno, bandno, precno; + opj_tcd_tile_t *l_tile = 00; + opj_tcd_tilecomp_t *l_tile_comp = 00; + opj_tcd_resolution_t *l_res = 00; + opj_tcd_band_t *l_band = 00; + opj_tcd_precinct_t *l_precinct = 00; + OPJ_UINT32 l_nb_resolutions, l_nb_precincts; + void (* l_tcd_code_block_deallocate) (opj_tcd_precinct_t *) = 00; + + if + (! p_tcd) + { + return; + } + if + (! p_tcd->tcd_image) + { + return; + } + if + (p_tcd->m_is_decoder) + { + l_tcd_code_block_deallocate = tcd_code_block_dec_deallocate; + } + else + { + l_tcd_code_block_deallocate = tcd_code_block_enc_deallocate; + } + + + l_tile = p_tcd->tcd_image->tiles; + if + (! l_tile) + { + return; + } + l_tile_comp = l_tile->comps; + + for + (compno = 0; compno < l_tile->numcomps; ++compno) + { + l_res = l_tile_comp->resolutions; + if + (l_res) + { + l_nb_resolutions = l_tile_comp->resolutions_size / sizeof(opj_tcd_resolution_t); + for + (resno = 0; resno < l_nb_resolutions; ++resno) + { + l_band = l_res->bands; + for + (bandno = 0; bandno < 3; ++bandno) + { + l_precinct = l_band->precincts; + if + (l_precinct) + { + l_nb_precincts = l_band->precincts_data_size / sizeof(opj_tcd_precinct_t); + for + (precno = 0; precno < l_nb_precincts; ++precno) + { + tgt_destroy(l_precinct->incltree); + l_precinct->incltree = 00; + tgt_destroy(l_precinct->imsbtree); + l_precinct->imsbtree = 00; + (*l_tcd_code_block_deallocate) (l_precinct); + ++l_precinct; + } + opj_free(l_band->precincts); + l_band->precincts = 00; + } + ++l_band; + } /* for (resno */ + ++l_res; + } + opj_free(l_tile_comp->resolutions); + l_tile_comp->resolutions = 00; + } + if + (l_tile_comp->data) + { + opj_aligned_free(l_tile_comp->data); + l_tile_comp->data = 00; + } + ++l_tile_comp; + } + opj_free(l_tile->comps); + l_tile->comps = 00; + opj_free(p_tcd->tcd_image->tiles); + p_tcd->tcd_image->tiles = 00; +} + +bool tcd_init( + opj_tcd_t *p_tcd, + opj_image_t * p_image, + opj_cp_t * p_cp + ) +{ + OPJ_UINT32 l_tile_comp_size; + + p_tcd->image = p_image; + p_tcd->cp = p_cp; + p_tcd->tcd_image->tiles = (opj_tcd_tile_t *) opj_malloc(sizeof(opj_tcd_tile_t)); + + if + (! p_tcd->tcd_image->tiles) + { + return false; + } + memset(p_tcd->tcd_image->tiles,0, sizeof(opj_tcd_tile_t)); + + l_tile_comp_size = p_image->numcomps * sizeof(opj_tcd_tilecomp_t); + p_tcd->tcd_image->tiles->comps = (opj_tcd_tilecomp_t *) opj_malloc(l_tile_comp_size); + if + (! p_tcd->tcd_image->tiles->comps ) + { + return false; + } + memset( p_tcd->tcd_image->tiles->comps , 0 , l_tile_comp_size); + p_tcd->tcd_image->tiles->numcomps = p_image->numcomps; + p_tcd->tp_pos = p_cp->m_specific_param.m_enc.m_tp_pos; + return true; +} + +void tcd_makelayer_fixed(opj_tcd_t *tcd, OPJ_UINT32 layno, OPJ_UINT32 final) { + OPJ_UINT32 compno, resno, bandno, precno, cblkno; + OPJ_INT32 value; /*, matrice[tcd_tcp->numlayers][tcd_tile->comps[0].numresolutions][3]; */ + OPJ_INT32 matrice[10][10][3]; + OPJ_UINT32 i, j, k; + + opj_cp_t *cp = tcd->cp; + opj_tcd_tile_t *tcd_tile = tcd->tcd_image->tiles; + opj_tcp_t *tcd_tcp = tcd->tcp; + + for (compno = 0; compno < tcd_tile->numcomps; compno++) { + opj_tcd_tilecomp_t *tilec = &tcd_tile->comps[compno]; + for (i = 0; i < tcd_tcp->numlayers; i++) { + for (j = 0; j < tilec->numresolutions; j++) { + for (k = 0; k < 3; k++) { + matrice[i][j][k] = + (OPJ_INT32) (cp->m_specific_param.m_enc.m_matrice[i * tilec->numresolutions * 3 + j * 3 + k] + * (OPJ_FLOAT32) (tcd->image->comps[compno].prec / 16.0)); + } + } + } + + for (resno = 0; resno < tilec->numresolutions; resno++) { + opj_tcd_resolution_t *res = &tilec->resolutions[resno]; + for (bandno = 0; bandno < res->numbands; bandno++) { + opj_tcd_band_t *band = &res->bands[bandno]; + for (precno = 0; precno < res->pw * res->ph; precno++) { + opj_tcd_precinct_t *prc = &band->precincts[precno]; + for (cblkno = 0; cblkno < prc->cw * prc->ch; cblkno++) { + opj_tcd_cblk_enc_t *cblk = &prc->cblks.enc[cblkno]; + opj_tcd_layer_t *layer = &cblk->layers[layno]; + OPJ_UINT32 n; + OPJ_INT32 imsb = tcd->image->comps[compno].prec - cblk->numbps; /* number of bit-plan equal to zero */ + /* Correction of the matrix of coefficient to include the IMSB information */ + if (layno == 0) { + value = matrice[layno][resno][bandno]; + if (imsb >= value) { + value = 0; + } else { + value -= imsb; + } + } else { + value = matrice[layno][resno][bandno] - matrice[layno - 1][resno][bandno]; + if (imsb >= matrice[layno - 1][resno][bandno]) { + value -= (imsb - matrice[layno - 1][resno][bandno]); + if (value < 0) { + value = 0; + } + } + } + + if (layno == 0) { + cblk->numpassesinlayers = 0; + } + + n = cblk->numpassesinlayers; + if (cblk->numpassesinlayers == 0) { + if (value != 0) { + n = 3 * value - 2 + cblk->numpassesinlayers; + } else { + n = cblk->numpassesinlayers; + } + } else { + n = 3 * value + cblk->numpassesinlayers; + } + + layer->numpasses = n - cblk->numpassesinlayers; + + if (!layer->numpasses) + continue; + + if (cblk->numpassesinlayers == 0) { + layer->len = cblk->passes[n - 1].rate; + layer->data = cblk->data; + } else { + layer->len = cblk->passes[n - 1].rate - cblk->passes[cblk->numpassesinlayers - 1].rate; + layer->data = cblk->data + cblk->passes[cblk->numpassesinlayers - 1].rate; + } + if (final) + cblk->numpassesinlayers = n; + } + } + } + } + } +} + +void tcd_rateallocate_fixed(opj_tcd_t *tcd) { + OPJ_UINT32 layno; + for (layno = 0; layno < tcd->tcp->numlayers; layno++) { + tcd_makelayer_fixed(tcd, layno, 1); + } +} + +void tcd_makelayer(opj_tcd_t *tcd, OPJ_UINT32 layno, OPJ_FLOAT64 thresh, OPJ_UINT32 final) { + OPJ_UINT32 compno, resno, bandno, precno, cblkno; + OPJ_UINT32 passno; + + opj_tcd_tile_t *tcd_tile = tcd->tcd_image->tiles; + + tcd_tile->distolayer[layno] = 0; /* fixed_quality */ + + for (compno = 0; compno < tcd_tile->numcomps; compno++) { + opj_tcd_tilecomp_t *tilec = &tcd_tile->comps[compno]; + for (resno = 0; resno < tilec->numresolutions; resno++) { + opj_tcd_resolution_t *res = &tilec->resolutions[resno]; + for (bandno = 0; bandno < res->numbands; bandno++) { + opj_tcd_band_t *band = &res->bands[bandno]; + for (precno = 0; precno < res->pw * res->ph; precno++) { + opj_tcd_precinct_t *prc = &band->precincts[precno]; + for (cblkno = 0; cblkno < prc->cw * prc->ch; cblkno++) { + opj_tcd_cblk_enc_t *cblk = &prc->cblks.enc[cblkno]; + opj_tcd_layer_t *layer = &cblk->layers[layno]; + + OPJ_UINT32 n; + if (layno == 0) { + cblk->numpassesinlayers = 0; + } + n = cblk->numpassesinlayers; + for (passno = cblk->numpassesinlayers; passno < cblk->totalpasses; passno++) { + OPJ_INT32 dr; + OPJ_FLOAT64 dd; + opj_tcd_pass_t *pass = &cblk->passes[passno]; + if (n == 0) { + dr = pass->rate; + dd = pass->distortiondec; + } else { + dr = pass->rate - cblk->passes[n - 1].rate; + dd = pass->distortiondec - cblk->passes[n - 1].distortiondec; + } + if (!dr) { + if (dd != 0) + n = passno + 1; + continue; + } + if (dd / dr >= thresh) + n = passno + 1; + } + layer->numpasses = n - cblk->numpassesinlayers; + + if (!layer->numpasses) { + layer->disto = 0; + continue; + } + if (cblk->numpassesinlayers == 0) { + layer->len = cblk->passes[n - 1].rate; + layer->data = cblk->data; + layer->disto = cblk->passes[n - 1].distortiondec; + } else { + layer->len = cblk->passes[n - 1].rate - cblk->passes[cblk->numpassesinlayers - 1].rate; + layer->data = cblk->data + cblk->passes[cblk->numpassesinlayers - 1].rate; + layer->disto = cblk->passes[n - 1].distortiondec - cblk->passes[cblk->numpassesinlayers - 1].distortiondec; + } + + tcd_tile->distolayer[layno] += layer->disto; /* fixed_quality */ + + if (final) + cblk->numpassesinlayers = n; + } + } + } + } + } +} + +bool tcd_rateallocate(opj_tcd_t *tcd, OPJ_BYTE *dest, OPJ_UINT32 * p_data_written, OPJ_UINT32 len, opj_codestream_info_t *cstr_info) { + OPJ_UINT32 compno, resno, bandno, precno, cblkno, layno; + OPJ_UINT32 passno; + OPJ_FLOAT64 min, max; + OPJ_FLOAT64 cumdisto[100]; /* fixed_quality */ + const OPJ_FLOAT64 K = 1; /* 1.1; fixed_quality */ + OPJ_FLOAT64 maxSE = 0; + + opj_cp_t *cp = tcd->cp; + opj_tcd_tile_t *tcd_tile = tcd->tcd_image->tiles; + opj_tcp_t *tcd_tcp = tcd->tcp; + + min = DBL_MAX; + max = 0; + + tcd_tile->numpix = 0; /* fixed_quality */ + + for (compno = 0; compno < tcd_tile->numcomps; compno++) { + opj_tcd_tilecomp_t *tilec = &tcd_tile->comps[compno]; + tilec->numpix = 0; + + for (resno = 0; resno < tilec->numresolutions; resno++) { + opj_tcd_resolution_t *res = &tilec->resolutions[resno]; + + for (bandno = 0; bandno < res->numbands; bandno++) { + opj_tcd_band_t *band = &res->bands[bandno]; + + for (precno = 0; precno < res->pw * res->ph; precno++) { + opj_tcd_precinct_t *prc = &band->precincts[precno]; + + for (cblkno = 0; cblkno < prc->cw * prc->ch; cblkno++) { + opj_tcd_cblk_enc_t *cblk = &prc->cblks.enc[cblkno]; + + for (passno = 0; passno < cblk->totalpasses; passno++) { + opj_tcd_pass_t *pass = &cblk->passes[passno]; + OPJ_INT32 dr; + OPJ_FLOAT64 dd, rdslope; + if (passno == 0) { + dr = pass->rate; + dd = pass->distortiondec; + } else { + dr = pass->rate - cblk->passes[passno - 1].rate; + dd = pass->distortiondec - cblk->passes[passno - 1].distortiondec; + } + if (dr == 0) { + continue; + } + rdslope = dd / dr; + if (rdslope < min) { + min = rdslope; + } + if (rdslope > max) { + max = rdslope; + } + } /* passno */ + + /* fixed_quality */ + tcd_tile->numpix += ((cblk->x1 - cblk->x0) * (cblk->y1 - cblk->y0)); + tilec->numpix += ((cblk->x1 - cblk->x0) * (cblk->y1 - cblk->y0)); + } /* cbklno */ + } /* precno */ + } /* bandno */ + } /* resno */ + + maxSE += (((OPJ_FLOAT64)(1 << tcd->image->comps[compno].prec) - 1.0) + * ((OPJ_FLOAT64)(1 << tcd->image->comps[compno].prec) -1.0)) + * ((OPJ_FLOAT64)(tilec->numpix)); + } /* compno */ + + /* index file */ + if(cstr_info) { + opj_tile_info_t *tile_info = &cstr_info->tile[tcd->tcd_tileno]; + tile_info->numpix = tcd_tile->numpix; + tile_info->distotile = tcd_tile->distotile; + tile_info->thresh = (OPJ_FLOAT64 *) opj_malloc(tcd_tcp->numlayers * sizeof(OPJ_FLOAT64)); + } + + for (layno = 0; layno < tcd_tcp->numlayers; layno++) { + OPJ_FLOAT64 lo = min; + OPJ_FLOAT64 hi = max; + bool success = false; + OPJ_UINT32 maxlen = tcd_tcp->rates[layno] ? uint_min(((OPJ_UINT32) ceil(tcd_tcp->rates[layno])), len) : len; + OPJ_FLOAT64 goodthresh = 0; + OPJ_FLOAT64 stable_thresh = 0; + OPJ_UINT32 i; + OPJ_FLOAT64 distotarget; /* fixed_quality */ + + /* fixed_quality */ + distotarget = tcd_tile->distotile - ((K * maxSE) / pow((OPJ_FLOAT32)10, tcd_tcp->distoratio[layno] / 10)); + + /* Don't try to find an optimal threshold but rather take everything not included yet, if + -r xx,yy,zz,0 (disto_alloc == 1 and rates == 0) + -q xx,yy,zz,0 (fixed_quality == 1 and distoratio == 0) + ==> possible to have some lossy layers and the last layer for sure lossless */ + if ( ((cp->m_specific_param.m_enc.m_disto_alloc==1) && (tcd_tcp->rates[layno]>0)) || ((cp->m_specific_param.m_enc.m_fixed_quality==1) && (tcd_tcp->distoratio[layno]>0))) { + opj_t2_t *t2 = t2_create(tcd->image, cp); + OPJ_FLOAT64 thresh = 0; + if + (t2 == 00) + { + return false; + } + + for + (i = 0; i < 128; ++i) + { + OPJ_FLOAT64 distoachieved = 0; /* fixed_quality */ + thresh = (lo + hi) / 2; + + tcd_makelayer(tcd, layno, thresh, 0); + + if (cp->m_specific_param.m_enc.m_fixed_quality) { /* fixed_quality */ + if(cp->m_specific_param.m_enc.m_cinema){ + if + (! t2_encode_packets(t2,tcd->tcd_tileno, tcd_tile, layno + 1, dest, p_data_written, maxlen, cstr_info,tcd->cur_tp_num,tcd->tp_pos,tcd->cur_pino,THRESH_CALC)) + { + lo = thresh; + continue; + } + else + { + distoachieved = layno == 0 ? + tcd_tile->distolayer[0] : cumdisto[layno - 1] + tcd_tile->distolayer[layno]; + if (distoachieved < distotarget) { + hi=thresh; + stable_thresh = thresh; + continue; + }else{ + lo=thresh; + } + } + }else{ + distoachieved = (layno == 0) ? + tcd_tile->distolayer[0] : (cumdisto[layno - 1] + tcd_tile->distolayer[layno]); + if (distoachieved < distotarget) { + hi = thresh; + stable_thresh = thresh; + continue; + } + lo = thresh; + } + } else { + if + (! t2_encode_packets(t2, tcd->tcd_tileno, tcd_tile, layno + 1, dest,p_data_written, maxlen, cstr_info,tcd->cur_tp_num,tcd->tp_pos,tcd->cur_pino,THRESH_CALC)) + { + /* TODO: what to do with l ??? seek / tell ??? */ + /* opj_event_msg(tcd->cinfo, EVT_INFO, "rate alloc: len=%d, max=%d\n", l, maxlen); */ + lo = thresh; + continue; + } + hi = thresh; + stable_thresh = thresh; + } + } + success = true; + goodthresh = stable_thresh == 0? thresh : stable_thresh; + t2_destroy(t2); + } else { + success = true; + goodthresh = min; + } + + if (!success) { + return false; + } + + if(cstr_info) { /* Threshold for Marcela Index */ + cstr_info->tile[tcd->tcd_tileno].thresh[layno] = goodthresh; + } + tcd_makelayer(tcd, layno, goodthresh, 1); + + /* fixed_quality */ + cumdisto[layno] = (layno == 0) ? tcd_tile->distolayer[0] : (cumdisto[layno - 1] + tcd_tile->distolayer[layno]); + } + + return true; +} + +OPJ_UINT32 tcd_get_encoded_tile_size ( + opj_tcd_t *p_tcd + ) +{ + OPJ_UINT32 i,l_data_size = 0; + opj_image_comp_t * l_img_comp = 00; + opj_tcd_tilecomp_t * l_tilec = 00; + OPJ_UINT32 l_size_comp, l_remaining; + + l_tilec = p_tcd->tcd_image->tiles->comps; + l_img_comp = p_tcd->image->comps; + for + (i=0;iimage->numcomps;++i) + { + l_size_comp = l_img_comp->prec >> 3; /*(/ 8)*/ + l_remaining = l_img_comp->prec & 7; /* (%8) */ + if + (l_remaining) + { + ++l_size_comp; + } + if + (l_size_comp == 3) + { + l_size_comp = 4; + } + l_data_size += l_size_comp * (l_tilec->x1 - l_tilec->x0) * (l_tilec->y1 - l_tilec->y0); + ++l_img_comp; + ++l_tilec; + } + return l_data_size; +} + +bool tcd_copy_tile_data ( + opj_tcd_t *p_tcd, + OPJ_BYTE * p_src, + OPJ_UINT32 p_src_length + ) +{ + OPJ_UINT32 i,j,l_data_size = 0; + opj_image_comp_t * l_img_comp = 00; + opj_tcd_tilecomp_t * l_tilec = 00; + OPJ_UINT32 l_size_comp, l_remaining; + OPJ_UINT32 l_nb_elem; + + l_data_size = tcd_get_encoded_tile_size(p_tcd); + if + (l_data_size != p_src_length) + { + return false; + } + l_tilec = p_tcd->tcd_image->tiles->comps; + l_img_comp = p_tcd->image->comps; + for + (i=0;iimage->numcomps;++i) + { + l_size_comp = l_img_comp->prec >> 3; /*(/ 8)*/ + l_remaining = l_img_comp->prec & 7; /* (%8) */ + l_nb_elem = (l_tilec->x1 - l_tilec->x0) * (l_tilec->y1 - l_tilec->y0); + if + (l_remaining) + { + ++l_size_comp; + } + if + (l_size_comp == 3) + { + l_size_comp = 4; + } + switch + (l_size_comp) + { + case 1: + { + OPJ_CHAR * l_src_ptr = (OPJ_CHAR *) p_src; + OPJ_INT32 * l_dest_ptr = l_tilec->data; + if + (l_img_comp->sgnd) + { + for + (j=0;jdata; + OPJ_INT16 * l_src_ptr = (OPJ_INT16 *) p_src; + if + (l_img_comp->sgnd) + { + for + (j=0;jdata; + for + (j=0;j p_dest_length) + { + return false; + } + + l_tilec = p_tcd->tcd_image->tiles->comps; + l_img_comp = p_tcd->image->comps; + for + (i=0;iimage->numcomps;++i) + { + l_size_comp = l_img_comp->prec >> 3; /*(/ 8)*/ + l_remaining = l_img_comp->prec & 7; /* (%8) */ + l_res = l_tilec->resolutions + l_img_comp->resno_decoded; + l_width = (l_res->x1 - l_res->x0); + l_height = (l_res->y1 - l_res->y0); + l_stride = (l_tilec->x1 - l_tilec->x0) - l_width; + if + (l_remaining) + { + ++l_size_comp; + } + if + (l_size_comp == 3) + { + l_size_comp = 4; + } + switch + (l_size_comp) + { + case 1: + { + OPJ_CHAR * l_dest_ptr = (OPJ_CHAR *) p_dest; + const OPJ_INT32 * l_src_ptr = l_tilec->data; + if + (l_img_comp->sgnd) + { + for + (j=0;jdata; + OPJ_INT16 * l_dest_ptr = (OPJ_INT16 *) p_dest; + if + (l_img_comp->sgnd) + { + for + (j=0;jdata; + for + (j=0;jtcd_image->tiles->comps; + l_img_comp = p_tcd->image->comps; + for + (i=0;iimage->numcomps;++i) + { + l_size_comp = l_img_comp->prec >> 3; /*(/ 8)*/ + l_remaining = l_img_comp->prec & 7; /* (%8) */ + if + (l_remaining) + { + ++l_size_comp; + } + if + (l_size_comp == 3) + { + l_size_comp = 4; + } + l_res = l_tile_comp->resolutions + l_tile_comp->minimum_num_resolutions - 1; + l_data_size += l_size_comp * (l_res->x1 - l_res->x0) * (l_res->y1 - l_res->y0); + ++l_img_comp; + ++l_tile_comp; + } + return l_data_size; +} + +bool tcd_dc_level_shift_encode ( + opj_tcd_t *p_tcd + ) +{ + OPJ_UINT32 compno; + opj_tcd_tilecomp_t * l_tile_comp = 00; + opj_tccp_t * l_tccp = 00; + opj_image_comp_t * l_img_comp = 00; + opj_tcp_t * l_tcp = 00; + opj_tcd_tile_t * l_tile; + OPJ_UINT32 l_nb_elem,i; + OPJ_INT32 * l_current_ptr; + + l_tile = p_tcd->tcd_image->tiles; + l_tile_comp = l_tile->comps; + l_tcp = p_tcd->tcp; + l_tccp = p_tcd->tcp->tccps; + l_img_comp = p_tcd->image->comps; + for + (compno = 0; compno < l_tile->numcomps; compno++) + { + l_current_ptr = l_tile_comp->data; + l_nb_elem = (l_tile_comp->x1 - l_tile_comp->x0) * (l_tile_comp->y1 - l_tile_comp->y0); + if + (l_tccp->qmfbid == 1) + { + for + (i = 0; i < l_nb_elem; ++i) + { + *l_current_ptr -= l_tccp->m_dc_level_shift ; + ++l_current_ptr; + } + } + else + { + for + (i = 0; i < l_nb_elem; ++i) + { + *l_current_ptr = (*l_current_ptr - l_tccp->m_dc_level_shift) << 11 ; + ++l_current_ptr; + } + } + ++l_img_comp; + ++l_tccp; + ++l_tile_comp; + } + return true; +} + +bool tcd_mct_encode ( + opj_tcd_t *p_tcd + ) +{ + opj_tcd_tile_t * l_tile = p_tcd->tcd_image->tiles; + opj_tcd_tilecomp_t * l_tile_comp = p_tcd->tcd_image->tiles->comps; + OPJ_UINT32 samples = (l_tile_comp->x1 - l_tile_comp->x0) * (l_tile_comp->y1 - l_tile_comp->y0); + OPJ_UINT32 i; + OPJ_BYTE ** l_data = 00; + opj_tcp_t * l_tcp = p_tcd->tcp; + if + (!p_tcd->tcp->mct) + { + return true; + } + + if + (p_tcd->tcp->mct == 2) + { + if + (! p_tcd->tcp->m_mct_coding_matrix) + { + return true; + } + l_data = (OPJ_BYTE **) opj_malloc(l_tile->numcomps*sizeof(OPJ_BYTE*)); + if + (! l_data) + { + return false; + } + for + (i=0;inumcomps;++i) + { + l_data[i] = (OPJ_BYTE*) l_tile_comp->data; + ++l_tile_comp; + } + if + (! mct_encode_custom(// MCT data + (OPJ_BYTE*) p_tcd->tcp->m_mct_coding_matrix, + // size of components + samples, + // components + l_data, + // nb of components (i.e. size of pData) + l_tile->numcomps, + // tells if the data is signed + p_tcd->image->comps->sgnd) + ) + { + opj_free(l_data); + return false; + } + opj_free(l_data); + } + else if (l_tcp->tccps->qmfbid == 0) + { + mct_encode_real(l_tile->comps[0].data, l_tile->comps[1].data, l_tile->comps[2].data, samples); + } + else + { + mct_encode(l_tile->comps[0].data, l_tile->comps[1].data, l_tile->comps[2].data, samples); + } + return true; +} + +bool tcd_dwt_encode ( + opj_tcd_t *p_tcd + ) +{ + opj_tcd_tile_t * l_tile = p_tcd->tcd_image->tiles; + opj_tcd_tilecomp_t * l_tile_comp = p_tcd->tcd_image->tiles->comps; + opj_tccp_t * l_tccp = p_tcd->tcp->tccps; + OPJ_UINT32 compno; + + + for + (compno = 0; compno < l_tile->numcomps; ++compno) + { + if + (l_tccp->qmfbid == 1) + { + if + (! dwt_encode(l_tile_comp)) + { + return false; + } + } + else if + (l_tccp->qmfbid == 0) + { + if + (! dwt_encode_real(l_tile_comp)) + { + return false; + } + } + ++l_tile_comp; + ++l_tccp; + } + return true; +} + +bool tcd_t1_encode ( + opj_tcd_t *p_tcd + ) +{ + opj_t1_t * l_t1; + const OPJ_FLOAT64 * l_mct_norms; + opj_tcp_t * l_tcp = p_tcd->tcp; + + l_t1 = t1_create(); + if + (l_t1 == 00) + { + return false; + } + if + (l_tcp->mct == 1) + { + // irreversible encoding + if + (l_tcp->tccps->qmfbid == 0) + { + l_mct_norms = get_mct_norms_real(); + } + else + { + l_mct_norms = get_mct_norms(); + } + } + else + { + l_mct_norms = (const OPJ_FLOAT64 *) (l_tcp->mct_norms); + } + + if + (! t1_encode_cblks(l_t1, p_tcd->tcd_image->tiles , l_tcp, l_mct_norms)) + { + t1_destroy(l_t1); + return false; + } + t1_destroy(l_t1); + return true; +} + +bool tcd_t2_encode ( + opj_tcd_t *p_tcd, + OPJ_BYTE * p_dest_data, + OPJ_UINT32 * p_data_written, + OPJ_UINT32 p_max_dest_size, + opj_codestream_info_t *p_cstr_info + ) +{ + opj_t2_t * l_t2; + + l_t2 = t2_create(p_tcd->image, p_tcd->cp); + if + (l_t2 == 00) + { + return false; + } + + if + (! t2_encode_packets( + l_t2, + p_tcd->tcd_tileno, + p_tcd->tcd_image->tiles, + p_tcd->tcp->numlayers, + p_dest_data, + p_data_written, + p_max_dest_size, + p_cstr_info, + p_tcd->tp_num, + p_tcd->tp_pos, + p_tcd->cur_pino, + FINAL_PASS)) + { + t2_destroy(l_t2); + return false; + } + t2_destroy(l_t2); + + /*---------------CLEAN-------------------*/ + return true; +} + +bool tcd_rate_allocate_encode( + opj_tcd_t *p_tcd, + OPJ_BYTE * p_dest_data, + OPJ_UINT32 p_max_dest_size, + opj_codestream_info_t *p_cstr_info + ) +{ + opj_cp_t * l_cp = p_tcd->cp; + OPJ_UINT32 l_nb_written = 0; + + if + (p_cstr_info) + { + p_cstr_info->index_write = 0; + } + if + (l_cp->m_specific_param.m_enc.m_disto_alloc|| l_cp->m_specific_param.m_enc.m_fixed_quality) + { /* fixed_quality */ + /* Normal Rate/distortion allocation */ + if + (! tcd_rateallocate(p_tcd, p_dest_data,&l_nb_written, p_max_dest_size, p_cstr_info)) + { + return false; + } + } + else + { + /* Fixed layer allocation */ + tcd_rateallocate_fixed(p_tcd); + } + return true; +} + +bool tcd_t2_decode ( + opj_tcd_t *p_tcd, + OPJ_BYTE * p_src_data, + OPJ_UINT32 * p_data_read, + OPJ_UINT32 p_max_src_size, + opj_codestream_info_t *p_cstr_info + ) +{ + opj_t2_t * l_t2; + + l_t2 = t2_create(p_tcd->image, p_tcd->cp); + if + (l_t2 == 00) + { + return false; + } + + if + (! t2_decode_packets( + l_t2, + p_tcd->tcd_tileno, + p_tcd->tcd_image->tiles, + p_src_data, + p_data_read, + p_max_src_size, + p_cstr_info)) + { + t2_destroy(l_t2); + return false; + } + t2_destroy(l_t2); + + /*---------------CLEAN-------------------*/ + return true; +} + +bool tcd_t1_decode ( + opj_tcd_t *p_tcd + ) +{ + OPJ_UINT32 compno; + opj_t1_t * l_t1; + opj_tcd_tile_t * l_tile = p_tcd->tcd_image->tiles; + opj_tcd_tilecomp_t* l_tile_comp = l_tile->comps; + opj_tccp_t * l_tccp = p_tcd->tcp->tccps; + + + l_t1 = t1_create(); + if + (l_t1 == 00) + { + return false; + } + for + (compno = 0; compno < l_tile->numcomps; ++compno) + { + /* The +3 is headroom required by the vectorized DWT */ + t1_decode_cblks(l_t1, l_tile_comp, l_tccp); + ++l_tile_comp; + ++l_tccp; + } + t1_destroy(l_t1); + return true; +} + +bool tcd_dwt_decode ( + opj_tcd_t *p_tcd + ) +{ + OPJ_UINT32 compno; + opj_tcd_tile_t * l_tile = p_tcd->tcd_image->tiles; + opj_tcd_tilecomp_t * l_tile_comp = l_tile->comps; + opj_tccp_t * l_tccp = p_tcd->tcp->tccps; + opj_image_comp_t * l_img_comp = p_tcd->image->comps; + + for + (compno = 0; compno < l_tile->numcomps; compno++) + { + /* + if (tcd->cp->reduce != 0) { + tcd->image->comps[compno].resno_decoded = + tile->comps[compno].numresolutions - tcd->cp->reduce - 1; + if (tcd->image->comps[compno].resno_decoded < 0) + { + return false; + } + } + numres2decode = tcd->image->comps[compno].resno_decoded + 1; + if(numres2decode > 0){ + */ + if + (l_tccp->qmfbid == 1) + { + if + (! dwt_decode(l_tile_comp, l_img_comp->resno_decoded+1)) + { + return false; + } + } + else + { + if + (! dwt_decode_real(l_tile_comp, l_img_comp->resno_decoded+1)) + { + return false; + } + } + ++l_tile_comp; + ++l_img_comp; + ++l_tccp; + } + return true; +} +bool tcd_mct_decode ( + opj_tcd_t *p_tcd + ) +{ + opj_tcd_tile_t * l_tile = p_tcd->tcd_image->tiles; + opj_tcp_t * l_tcp = p_tcd->tcp; + opj_tcd_tilecomp_t * l_tile_comp = l_tile->comps; + OPJ_UINT32 l_samples,i; + + if + (! l_tcp->mct) + { + return true; + } + l_samples = (l_tile_comp->x1 - l_tile_comp->x0) * (l_tile_comp->y1 - l_tile_comp->y0); + if + (l_tcp->mct == 2) + { + OPJ_BYTE ** l_data; + if + (! l_tcp->m_mct_decoding_matrix) + { + return true; + } + l_data = (OPJ_BYTE **) opj_malloc(l_tile->numcomps*sizeof(OPJ_BYTE*)); + if + (! l_data) + { + return false; + } + for + (i=0;inumcomps;++i) + { + l_data[i] = (OPJ_BYTE*) l_tile_comp->data; + ++l_tile_comp; + } + if + (! mct_decode_custom( // MCT data + (OPJ_BYTE*) l_tcp->m_mct_decoding_matrix, + // size of components + l_samples, + // components + l_data, + // nb of components (i.e. size of pData) + l_tile->numcomps, + // tells if the data is signed + p_tcd->image->comps->sgnd)) + { + opj_free(l_data); + return false; + } + opj_free(l_data); + } + else + { + if + (l_tcp->tccps->qmfbid == 1) + { + mct_decode( + l_tile->comps[0].data, + l_tile->comps[1].data, + l_tile->comps[2].data, + l_samples); + } + else + { + mct_decode_real( + (float*)l_tile->comps[0].data, + (float*)l_tile->comps[1].data, + (float*)l_tile->comps[2].data, + l_samples); + } + } + return true; +} + +bool tcd_dc_level_shift_decode ( + opj_tcd_t *p_tcd + ) +{ + OPJ_UINT32 compno; + opj_tcd_tilecomp_t * l_tile_comp = 00; + opj_tccp_t * l_tccp = 00; + opj_image_comp_t * l_img_comp = 00; + opj_tcd_resolution_t* l_res = 00; + opj_tcp_t * l_tcp = 00; + opj_tcd_tile_t * l_tile; + OPJ_UINT32 l_width,l_height,i,j; + OPJ_INT32 * l_current_ptr; + OPJ_INT32 l_min, l_max; + OPJ_UINT32 l_stride; + + l_tile = p_tcd->tcd_image->tiles; + l_tile_comp = l_tile->comps; + l_tcp = p_tcd->tcp; + l_tccp = p_tcd->tcp->tccps; + l_img_comp = p_tcd->image->comps; + + for + (compno = 0; compno < l_tile->numcomps; compno++) + { + l_res = l_tile_comp->resolutions + l_img_comp->resno_decoded; + l_width = (l_res->x1 - l_res->x0); + l_height = (l_res->y1 - l_res->y0); + l_stride = (l_tile_comp->x1 - l_tile_comp->x0) - l_width; + if + (l_img_comp->sgnd) + { + l_min = -(1 << (l_img_comp->prec - 1)); + l_max = (1 << (l_img_comp->prec - 1)) - 1; + } + else + { + l_min = 0; + l_max = (1 << l_img_comp->prec) - 1; + } + l_current_ptr = l_tile_comp->data; + if + (l_tccp->qmfbid == 1) + { + for + (j=0;jm_dc_level_shift, l_min, l_max); + ++l_current_ptr; + } + l_current_ptr += l_stride; + } + } + else + { + for + (j=0;jm_dc_level_shift, l_min, l_max); ; + ++l_current_ptr; + } + l_current_ptr += l_stride; + } + } + ++l_img_comp; + ++l_tccp; + ++l_tile_comp; + } + return true; +} + +bool tcd_encode_tile( + opj_tcd_t *p_tcd, + OPJ_UINT32 p_tile_no, + OPJ_BYTE *p_dest, + OPJ_UINT32 * p_data_written, + OPJ_UINT32 p_max_length, + opj_codestream_info_t *p_cstr_info) +{ + + if + (p_tcd->cur_tp_num == 0) + { + p_tcd->tcd_tileno = p_tile_no; + p_tcd->tcp = &p_tcd->cp->tcps[p_tile_no]; + /* INDEX >> "Precinct_nb_X et Precinct_nb_Y" */ + if(p_cstr_info) + { + OPJ_UINT32 l_num_packs = 0; + OPJ_UINT32 i; + opj_tcd_tilecomp_t *l_tilec_idx = &p_tcd->tcd_image->tiles->comps[0]; /* based on component 0 */ + opj_tccp_t *l_tccp = p_tcd->tcp->tccps; /* based on component 0 */ + for (i = 0; i < l_tilec_idx->numresolutions; i++) { + opj_tcd_resolution_t *l_res_idx = &l_tilec_idx->resolutions[i]; + + p_cstr_info->tile[p_tile_no].pw[i] = l_res_idx->pw; + p_cstr_info->tile[p_tile_no].ph[i] = l_res_idx->ph; + + l_num_packs += l_res_idx->pw * l_res_idx->ph; + p_cstr_info->tile[p_tile_no].pdx[i] = l_tccp->prcw[i]; + p_cstr_info->tile[p_tile_no].pdy[i] = l_tccp->prch[i]; + } + p_cstr_info->tile[p_tile_no].packet = (opj_packet_info_t*) opj_calloc(p_cstr_info->numcomps * p_cstr_info->numlayers * l_num_packs, sizeof(opj_packet_info_t)); + } + /* << INDEX */ + _ProfStart(PGROUP_DC_SHIFT); + /*---------------TILE-------------------*/ + if + (! tcd_dc_level_shift_encode(p_tcd)) + { + return false; + } + _ProfStop(PGROUP_DC_SHIFT); + + _ProfStart(PGROUP_MCT); + if + (! tcd_mct_encode(p_tcd)) + { + return false; + } + _ProfStop(PGROUP_MCT); + + _ProfStart(PGROUP_DWT); + if + (! tcd_dwt_encode(p_tcd)) + { + return false; + } + _ProfStop(PGROUP_DWT); + + _ProfStart(PGROUP_T1); + if + (! tcd_t1_encode(p_tcd)) + { + return false; + } + _ProfStop(PGROUP_T1); + + _ProfStart(PGROUP_RATE); + if + (! tcd_rate_allocate_encode(p_tcd,p_dest,p_max_length,p_cstr_info)) + { + return false; + } + _ProfStop(PGROUP_RATE); + + } + /*--------------TIER2------------------*/ + + /* INDEX */ + if + (p_cstr_info) + { + p_cstr_info->index_write = 1; + } + _ProfStart(PGROUP_T2); + if + (! tcd_t2_encode(p_tcd,p_dest,p_data_written,p_max_length,p_cstr_info)) + { + return false; + } + _ProfStop(PGROUP_T2); + /*---------------CLEAN-------------------*/ + return true; +} + +bool tcd_decode_tile( + opj_tcd_t *p_tcd, + OPJ_BYTE *p_src, + OPJ_UINT32 p_max_length, + OPJ_UINT32 p_tile_no, + opj_codestream_info_t *p_cstr_info) +{ + OPJ_UINT32 l_data_read; + p_tcd->tcd_tileno = p_tile_no; + p_tcd->tcp = &(p_tcd->cp->tcps[p_tile_no]); + + /* INDEX >> */ + if(p_cstr_info) { + OPJ_UINT32 resno, compno, numprec = 0; + for (compno = 0; compno < (OPJ_UINT32) p_cstr_info->numcomps; compno++) { + opj_tcp_t *tcp = &p_tcd->cp->tcps[0]; + opj_tccp_t *tccp = &tcp->tccps[compno]; + opj_tcd_tilecomp_t *tilec_idx = &p_tcd->tcd_image->tiles->comps[compno]; + for (resno = 0; resno < tilec_idx->numresolutions; resno++) { + opj_tcd_resolution_t *res_idx = &tilec_idx->resolutions[resno]; + p_cstr_info->tile[p_tile_no].pw[resno] = res_idx->pw; + p_cstr_info->tile[p_tile_no].ph[resno] = res_idx->ph; + numprec += res_idx->pw * res_idx->ph; + p_cstr_info->tile[p_tile_no].pdx[resno] = tccp->prcw[resno]; + p_cstr_info->tile[p_tile_no].pdy[resno] = tccp->prch[resno]; + } + } + p_cstr_info->tile[p_tile_no].packet = (opj_packet_info_t *) opj_malloc(p_cstr_info->numlayers * numprec * sizeof(opj_packet_info_t)); + p_cstr_info->packno = 0; + } + /* << INDEX */ + + /*--------------TIER2------------------*/ + _ProfStart(PGROUP_T2); + l_data_read = 0; + if + (! tcd_t2_decode(p_tcd,p_src,&l_data_read,p_max_length,p_cstr_info)) + { + return false; + } + _ProfStop(PGROUP_T2); + + /*------------------TIER1-----------------*/ + + _ProfStart(PGROUP_T1); + if + (! tcd_t1_decode(p_tcd)) + { + return false; + } + _ProfStop(PGROUP_T1); + + /*----------------DWT---------------------*/ + + _ProfStart(PGROUP_DWT); + if + (! tcd_dwt_decode(p_tcd)) + { + return false; + } + _ProfStop(PGROUP_DWT); + + /*----------------MCT-------------------*/ + _ProfStart(PGROUP_MCT); + if + (! tcd_mct_decode(p_tcd)) + { + return false; + } + _ProfStop(PGROUP_MCT); + + _ProfStart(PGROUP_DC_SHIFT); + if + (! tcd_dc_level_shift_decode(p_tcd)) + { + return false; + } + _ProfStop(PGROUP_DC_SHIFT); + + + /*---------------TILE-------------------*/ + return true; +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/tcd.h b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/tcd.h new file mode 100644 index 0000000..62bbdb7 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/tcd.h @@ -0,0 +1,344 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __TCD_H +#define __TCD_H +/** +@file tcd.h +@brief Implementation of a tile coder/decoder (TCD) + +The functions in TCD.C have for goal to encode or decode each tile independently from +each other. The functions in TCD.C are used by some function in J2K.C. +*/ +#include "openjpeg.h" +/** @defgroup TCD TCD - Implementation of a tile coder/decoder */ +/*@{*/ +struct opj_common_struct; +struct opj_codestream_info; +struct opj_image; +struct opj_tcp; +struct opj_cp; +struct opj_tgt_tree; + +/** +FIXME: documentation +*/ +typedef struct opj_tcd_seg { + OPJ_BYTE ** data; + OPJ_UINT32 dataindex; + OPJ_UINT32 numpasses; + OPJ_UINT32 real_num_passes; + OPJ_UINT32 len; + OPJ_UINT32 maxpasses; + OPJ_UINT32 numnewpasses; + OPJ_UINT32 newlen; +} opj_tcd_seg_t; + +/** +FIXME: documentation +*/ +typedef struct opj_tcd_pass { + OPJ_UINT32 rate; + OPJ_FLOAT64 distortiondec; + OPJ_UINT32 len; + OPJ_UINT32 term : 1; +} opj_tcd_pass_t; + +/** +FIXME: documentation +*/ +typedef struct opj_tcd_layer { + OPJ_UINT32 numpasses; /* Number of passes in the layer */ + OPJ_UINT32 len; /* len of information */ + OPJ_FLOAT64 disto; /* add for index (Cfr. Marcela) */ + OPJ_BYTE *data; /* data */ +} opj_tcd_layer_t; + +/** +FIXME: documentation +*/ +typedef struct opj_tcd_cblk_enc { + OPJ_BYTE* data; /* Data */ + opj_tcd_layer_t* layers; /* layer information */ + opj_tcd_pass_t* passes; /* information about the passes */ + OPJ_INT32 x0, y0, x1, y1; /* dimension of the code-blocks : left upper corner (x0, y0) right low corner (x1,y1) */ + OPJ_UINT32 numbps; + OPJ_UINT32 numlenbits; + OPJ_UINT32 numpasses; /* number of pass already done for the code-blocks */ + OPJ_UINT32 numpassesinlayers; /* number of passes in the layer */ + OPJ_UINT32 totalpasses; /* total number of passes */ +} opj_tcd_cblk_enc_t; + +typedef struct opj_tcd_cblk_dec { + OPJ_BYTE * data; /* Data */ + opj_tcd_seg_t* segs; /* segments informations */ + OPJ_INT32 x0, y0, x1, y1; /* dimension of the code-blocks : left upper corner (x0, y0) right low corner (x1,y1) */ + OPJ_UINT32 numbps; + OPJ_UINT32 numlenbits; + OPJ_UINT32 len; /* length */ + OPJ_UINT32 numnewpasses; /* number of pass added to the code-blocks */ + OPJ_UINT32 numsegs; /* number of segments */ + OPJ_UINT32 real_num_segs; + OPJ_UINT32 m_current_max_segs; +} opj_tcd_cblk_dec_t; + +/** +FIXME: documentation +*/ +typedef struct opj_tcd_precinct { + OPJ_INT32 x0, y0, x1, y1; /* dimension of the precinct : left upper corner (x0, y0) right low corner (x1,y1) */ + OPJ_UINT32 cw, ch; /* number of precinct in width and heigth */ + union{ /* code-blocks informations */ + opj_tcd_cblk_enc_t* enc; + opj_tcd_cblk_dec_t* dec; + } cblks; + OPJ_UINT32 block_size; /* size taken by cblks (in bytes) */ + struct opj_tgt_tree *incltree; /* inclusion tree */ + struct opj_tgt_tree *imsbtree; /* IMSB tree */ +} opj_tcd_precinct_t; + +/** +FIXME: documentation +*/ +typedef struct opj_tcd_band { + OPJ_INT32 x0, y0, x1, y1; /* dimension of the subband : left upper corner (x0, y0) right low corner (x1,y1) */ + OPJ_UINT32 bandno; + opj_tcd_precinct_t *precincts; /* precinct information */ + OPJ_UINT32 precincts_data_size; /* size of data taken by precincts */ + OPJ_INT32 numbps; + OPJ_FLOAT32 stepsize; +} opj_tcd_band_t; + +/** +FIXME: documentation +*/ +typedef struct opj_tcd_resolution { + OPJ_INT32 x0, y0, x1, y1; /* dimension of the resolution level : left upper corner (x0, y0) right low corner (x1,y1) */ + OPJ_UINT32 pw, ph; + OPJ_UINT32 numbands; /* number sub-band for the resolution level */ + opj_tcd_band_t bands[3]; /* subband information */ +} opj_tcd_resolution_t; + +/** +FIXME: documentation +*/ +typedef struct opj_tcd_tilecomp +{ + OPJ_INT32 x0, y0, x1, y1; /* dimension of component : left upper corner (x0, y0) right low corner (x1,y1) */ + OPJ_UINT32 numresolutions; /* number of resolutions level */ + OPJ_UINT32 minimum_num_resolutions; /* number of resolutions level to decode (at max)*/ + opj_tcd_resolution_t *resolutions; /* resolutions information */ + OPJ_UINT32 resolutions_size; /* size of data for resolutions (in bytes) */ + OPJ_INT32 *data; /* data of the component */ + OPJ_UINT32 data_size; /* size of the data of the component */ + OPJ_INT32 numpix; /* add fixed_quality */ +} opj_tcd_tilecomp_t; + +/** +FIXME: documentation +*/ +typedef struct opj_tcd_tile { + OPJ_INT32 x0, y0, x1, y1; /* dimension of the tile : left upper corner (x0, y0) right low corner (x1,y1) */ + OPJ_UINT32 numcomps; /* number of components in tile */ + opj_tcd_tilecomp_t *comps; /* Components information */ + OPJ_INT32 numpix; /* add fixed_quality */ + OPJ_FLOAT64 distotile; /* add fixed_quality */ + OPJ_FLOAT64 distolayer[100]; /* add fixed_quality */ + /** packet number */ + OPJ_UINT32 packno; +} opj_tcd_tile_t; + +/** +FIXME: documentation +*/ +typedef struct opj_tcd_image +{ + opj_tcd_tile_t *tiles; /* Tiles information */ +} +opj_tcd_image_t; + +/** +Tile coder/decoder +*/ +typedef struct opj_tcd +{ + /** Position of the tilepart flag in Progression order*/ + OPJ_INT32 tp_pos; + /** Tile part number*/ + OPJ_UINT32 tp_num; + /** Current tile part number*/ + OPJ_UINT32 cur_tp_num; + /** Total number of tileparts of the current tile*/ + OPJ_UINT32 cur_totnum_tp; + /** Current Packet iterator number */ + OPJ_UINT32 cur_pino; + /** info on each image tile */ + struct opj_tcd_image *tcd_image; + /** image */ + struct opj_image *image; + /** coding parameters */ + struct opj_cp *cp; + /** coding/decoding parameters common to all tiles */ + struct opj_tcp *tcp; + /** current encoded/decoded tile */ + OPJ_UINT32 tcd_tileno; + /** tell if the tcd is a decoder. */ + OPJ_UINT32 m_is_decoder : 1; +} opj_tcd_t; + +/** @name Exported functions */ +/*@{*/ +/* ----------------------------------------------------------------------- */ + +/** +Dump the content of a tcd structure +*/ +//void tcd_dump(FILE *fd, opj_tcd_t *tcd, opj_tcd_image_t *img); +/** +Create a new TCD handle +@param cinfo Codec context info +@return Returns a new TCD handle if successful returns NULL otherwise +*/ +opj_tcd_t* tcd_create(bool p_is_decoder); + +/** +Destroy a previously created TCD handle +@param tcd TCD handle to destroy +*/ +void tcd_destroy(opj_tcd_t *tcd); + + + + +/** + * Initialize the tile coder and may reuse some meory. + * @param p_tcd TCD handle. + * @param p_image raw image. + * @param p_cp coding parameters. + * @param p_tile_no current tile index to encode. + * + * @return true if the encoding values could be set (false otherwise). +*/ +bool tcd_init( + opj_tcd_t *p_tcd, + struct opj_image * p_image, + struct opj_cp * p_cp + ); + + +/** + * Allocates memory for decoding a specific tile. + * + * @param p_tcd the tile decoder. + * @param p_image the image to decode. + * @param p_cp the decoding parameters. + * @param p_tile_no the index of the tile received in sequence. This not necesseraly lead to the + * tile at index p_tile_no. + * @param p_cstr_info codestream info (if any). + * + * @return true if the remaining data is sufficient.s + */ +bool tcd_init_decode_tile( + opj_tcd_t *p_tcd, + OPJ_UINT32 p_tile_no + ); +/** + * Initialize the tile coder and may reuse some meory. + * @param p_tcd TCD handle. + * @param p_image raw image. + * @param p_cp coding parameters. + * @param p_tile_no current tile index to encode. + * + * @return true if the encoding values could be set (false otherwise). +*/ +bool tcd_init_encode_tile + ( + opj_tcd_t *p_tcd, + OPJ_UINT32 p_tile_no + ); + +void tcd_makelayer_fixed(opj_tcd_t *tcd, OPJ_UINT32 layno, OPJ_UINT32 final); +void tcd_rateallocate_fixed(opj_tcd_t *tcd); +void tcd_makelayer(opj_tcd_t *tcd, OPJ_UINT32 layno, OPJ_FLOAT64 thresh, OPJ_UINT32 final); +bool tcd_rateallocate(opj_tcd_t *tcd, OPJ_BYTE *dest, OPJ_UINT32 * p_data_written, OPJ_UINT32 len, struct opj_codestream_info *cstr_info); +/** + * Encodes a tile from the raw image into the given buffer. + * @param p_tcd Tile Coder handle + * @param p_tile_no Index of the tile to encode. + * @param p_dest Destination buffer + * @param p_data_written pointer to an int that is incremented by the number of bytes really written on p_dest + * @param p_len Maximum length of the destination buffer + * @param p_cstr_info Codestream information structure + * @return true if the coding is successfull. +*/ +bool tcd_encode_tile(opj_tcd_t *p_tcd, OPJ_UINT32 p_tile_no, OPJ_BYTE *p_dest, OPJ_UINT32 * p_data_written, OPJ_UINT32 p_len, struct opj_codestream_info *p_cstr_info); + +/** +Decode a tile from a buffer into a raw image +@param tcd TCD handle +@param src Source buffer +@param len Length of source buffer +@param tileno Number that identifies one of the tiles to be decoded +*/ +bool tcd_decode_tile(opj_tcd_t *tcd, OPJ_BYTE *src, OPJ_UINT32 len, OPJ_UINT32 tileno, struct opj_codestream_info *cstr_info); + +/** + * Copies tile data from the given memory block onto the system. + */ +bool tcd_copy_tile_data ( + opj_tcd_t *p_tcd, + OPJ_BYTE * p_src, + OPJ_UINT32 p_src_length + ); +/** + * Copies tile data from the system onto the given memory block. + */ +bool tcd_update_tile_data ( + opj_tcd_t *p_tcd, + OPJ_BYTE * p_dest, + OPJ_UINT32 p_dest_length + ); +/** + * Gets the maximum tile size that will be taken by the tile once decoded. + */ +OPJ_UINT32 tcd_get_decoded_tile_size ( + opj_tcd_t *p_tcd + ); + +OPJ_UINT32 tcd_get_encoded_tile_size ( + opj_tcd_t *p_tcd + ); +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __TCD_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/tgt.c b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/tgt.c new file mode 100644 index 0000000..120d5ae --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/tgt.c @@ -0,0 +1,344 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "tgt.h" +#include "bio.h" +#include "opj_malloc.h" + +/* +========================================================== + Tag-tree coder interface +========================================================== +*/ + +opj_tgt_tree_t *tgt_create(OPJ_UINT32 numleafsh, OPJ_UINT32 numleafsv) { + OPJ_INT32 nplh[32]; + OPJ_INT32 nplv[32]; + opj_tgt_node_t *node = 00; + opj_tgt_node_t *l_parent_node = 00; + opj_tgt_node_t *l_parent_node0 = 00; + opj_tgt_tree_t *tree = 00; + OPJ_UINT32 i; + OPJ_INT32 j,k; + OPJ_UINT32 numlvls; + OPJ_UINT32 n; + + tree = (opj_tgt_tree_t *) opj_malloc(sizeof(opj_tgt_tree_t)); + if(!tree) return 00; + memset(tree,0,sizeof(opj_tgt_tree_t)); + + tree->numleafsh = numleafsh; + tree->numleafsv = numleafsv; + + numlvls = 0; + nplh[0] = numleafsh; + nplv[0] = numleafsv; + tree->numnodes = 0; + do { + n = nplh[numlvls] * nplv[numlvls]; + nplh[numlvls + 1] = (nplh[numlvls] + 1) / 2; + nplv[numlvls + 1] = (nplv[numlvls] + 1) / 2; + tree->numnodes += n; + ++numlvls; + } while (n > 1); + + /* ADD */ + if (tree->numnodes == 0) { + opj_free(tree); + return 00; + } + + tree->nodes = (opj_tgt_node_t*) opj_calloc(tree->numnodes, sizeof(opj_tgt_node_t)); + if(!tree->nodes) { + opj_free(tree); + return 00; + } + memset(tree->nodes,0,tree->numnodes * sizeof(opj_tgt_node_t)); + tree->nodes_size = tree->numnodes * sizeof(opj_tgt_node_t); + + node = tree->nodes; + l_parent_node = &tree->nodes[tree->numleafsh * tree->numleafsv]; + l_parent_node0 = l_parent_node; + + for (i = 0; i < numlvls - 1; ++i) { + for (j = 0; j < nplv[i]; ++j) { + k = nplh[i]; + while (--k >= 0) { + node->parent = l_parent_node; + ++node; + if (--k >= 0) { + node->parent = l_parent_node; + ++node; + } + ++l_parent_node; + } + if ((j & 1) || j == nplv[i] - 1) { + l_parent_node0 = l_parent_node; + } else { + l_parent_node = l_parent_node0; + l_parent_node0 += nplh[i]; + } + } + } + node->parent = 0; + tgt_reset(tree); + return tree; +} +/** + * Reinitialises a tag-tree from an exixting one. + * + * @param p_tree the tree to reinitialize. + * @param p_num_leafs_h the width of the array of leafs of the tree + * @param p_num_leafs_v the height of the array of leafs of the tree + * @return a new tag-tree if successful, NULL otherwise +*/ +opj_tgt_tree_t *tgt_init(opj_tgt_tree_t * p_tree,OPJ_UINT32 p_num_leafs_h, OPJ_UINT32 p_num_leafs_v) +{ + OPJ_INT32 l_nplh[32]; + OPJ_INT32 l_nplv[32]; + opj_tgt_node_t *l_node = 00; + opj_tgt_node_t *l_parent_node = 00; + opj_tgt_node_t *l_parent_node0 = 00; + OPJ_UINT32 i; + OPJ_INT32 j,k; + OPJ_UINT32 l_num_levels; + OPJ_UINT32 n; + OPJ_UINT32 l_node_size; + + if + (! p_tree) + { + return 00; + } + if + ((p_tree->numleafsh != p_num_leafs_h) || (p_tree->numleafsv != p_num_leafs_v)) + { + p_tree->numleafsh = p_num_leafs_h; + p_tree->numleafsv = p_num_leafs_v; + + l_num_levels = 0; + l_nplh[0] = p_num_leafs_h; + l_nplv[0] = p_num_leafs_v; + p_tree->numnodes = 0; + do + { + n = l_nplh[l_num_levels] * l_nplv[l_num_levels]; + l_nplh[l_num_levels + 1] = (l_nplh[l_num_levels] + 1) / 2; + l_nplv[l_num_levels + 1] = (l_nplv[l_num_levels] + 1) / 2; + p_tree->numnodes += n; + ++l_num_levels; + } + while (n > 1); + + /* ADD */ + if + (p_tree->numnodes == 0) + { + tgt_destroy(p_tree); + return 00; + } + l_node_size = p_tree->numnodes * sizeof(opj_tgt_node_t); + if + (l_node_size > p_tree->nodes_size) + { + p_tree->nodes = (opj_tgt_node_t*) opj_realloc(p_tree->nodes, l_node_size); + if + (! p_tree->nodes) + { + tgt_destroy(p_tree); + return 00; + } + memset(((char *) p_tree->nodes) + p_tree->nodes_size, 0 , l_node_size - p_tree->nodes_size); + p_tree->nodes_size = l_node_size; + } + l_node = p_tree->nodes; + l_parent_node = &p_tree->nodes[p_tree->numleafsh * p_tree->numleafsv]; + l_parent_node0 = l_parent_node; + + for + (i = 0; i < l_num_levels - 1; ++i) + { + for + (j = 0; j < l_nplv[i]; ++j) + { + k = l_nplh[i]; + while + (--k >= 0) + { + l_node->parent = l_parent_node; + ++l_node; + if (--k >= 0) + { + l_node->parent = l_parent_node; + ++l_node; + } + ++l_parent_node; + } + if ((j & 1) || j == l_nplv[i] - 1) + { + l_parent_node0 = l_parent_node; + } + else + { + l_parent_node = l_parent_node0; + l_parent_node0 += l_nplh[i]; + } + } + } + l_node->parent = 0; + } + tgt_reset(p_tree); + + return p_tree; +} + +void tgt_destroy(opj_tgt_tree_t *p_tree) +{ + if + (! p_tree) + { + return; + } + if + (p_tree->nodes) + { + opj_free(p_tree->nodes); + p_tree->nodes = 00; + } + opj_free(p_tree); +} + +void tgt_reset(opj_tgt_tree_t *p_tree) { + OPJ_UINT32 i; + opj_tgt_node_t * l_current_node = 00;; + + if + (! p_tree) + { + return; + } + l_current_node = p_tree->nodes; + for + (i = 0; i < p_tree->numnodes; ++i) + { + l_current_node->value = 999; + l_current_node->low = 0; + l_current_node->known = 0; + ++l_current_node; + } +} + +void tgt_setvalue(opj_tgt_tree_t *tree, OPJ_UINT32 leafno, OPJ_INT32 value) { + opj_tgt_node_t *node; + node = &tree->nodes[leafno]; + while (node && node->value > value) { + node->value = value; + node = node->parent; + } +} + +void tgt_encode(opj_bio_t *bio, opj_tgt_tree_t *tree, OPJ_UINT32 leafno, OPJ_INT32 threshold) { + opj_tgt_node_t *stk[31]; + opj_tgt_node_t **stkptr; + opj_tgt_node_t *node; + OPJ_INT32 low; + + stkptr = stk; + node = &tree->nodes[leafno]; + while (node->parent) { + *stkptr++ = node; + node = node->parent; + } + + low = 0; + for (;;) { + if (low > node->low) { + node->low = low; + } else { + low = node->low; + } + + while (low < threshold) { + if (low >= node->value) { + if (!node->known) { + bio_write(bio, 1, 1); + node->known = 1; + } + break; + } + bio_write(bio, 0, 1); + ++low; + } + + node->low = low; + if (stkptr == stk) + break; + node = *--stkptr; + } +} + +OPJ_UINT32 tgt_decode(opj_bio_t *bio, opj_tgt_tree_t *tree, OPJ_UINT32 leafno, OPJ_INT32 threshold) { + opj_tgt_node_t *stk[31]; + opj_tgt_node_t **stkptr; + opj_tgt_node_t *node; + OPJ_INT32 low; + + stkptr = stk; + node = &tree->nodes[leafno]; + while (node->parent) { + *stkptr++ = node; + node = node->parent; + } + + low = 0; + for (;;) { + if (low > node->low) { + node->low = low; + } else { + low = node->low; + } + while (low < threshold && low < node->value) { + if (bio_read(bio, 1)) { + node->value = low; + } else { + ++low; + } + } + node->low = low; + if (stkptr == stk) { + break; + } + node = *--stkptr; + } + + return (node->value < threshold) ? 1 : 0; +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/tgt.h b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/tgt.h new file mode 100644 index 0000000..2aa8dc9 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/tgt.h @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __TGT_H +#define __TGT_H +/** +@file tgt.h +@brief Implementation of a tag-tree coder (TGT) + +The functions in TGT.C have for goal to realize a tag-tree coder. The functions in TGT.C +are used by some function in T2.C. +*/ +#include "openjpeg.h" +/** @defgroup TGT TGT - Implementation of a tag-tree coder */ +/*@{*/ +struct opj_bio; + +/** +Tag node +*/ +typedef struct opj_tgt_node +{ + struct opj_tgt_node *parent; + OPJ_INT32 value; + OPJ_INT32 low; + OPJ_UINT32 known : 1; +} opj_tgt_node_t; + +/** +Tag tree +*/ +typedef struct opj_tgt_tree +{ + OPJ_UINT32 numleafsh; + OPJ_UINT32 numleafsv; + OPJ_UINT32 numnodes; + opj_tgt_node_t *nodes; + OPJ_UINT32 nodes_size; /* maximum size taken by nodes */ +} opj_tgt_tree_t; + +/** @name Exported functions */ +/*@{*/ +/* ----------------------------------------------------------------------- */ +/** +Create a tag-tree +@param numleafsh Width of the array of leafs of the tree +@param numleafsv Height of the array of leafs of the tree +@return Returns a new tag-tree if successful, returns NULL otherwise +*/ +opj_tgt_tree_t *tgt_create(OPJ_UINT32 numleafsh, OPJ_UINT32 numleafsv); + +/** + * Reinitialises a tag-tree from an exixting one. + * + * @param p_tree the tree to reinitialize. + * @param p_num_leafs_h the width of the array of leafs of the tree + * @param p_num_leafs_v the height of the array of leafs of the tree + * @return a new tag-tree if successful, NULL otherwise +*/ +opj_tgt_tree_t *tgt_init(opj_tgt_tree_t * p_tree,OPJ_UINT32 p_num_leafs_h, OPJ_UINT32 p_num_leafs_v); + +/** +Destroy a tag-tree, liberating memory +@param tree Tag-tree to destroy +*/ +void tgt_destroy(opj_tgt_tree_t *tree); +/** +Reset a tag-tree (set all leaves to 0) +@param tree Tag-tree to reset +*/ +void tgt_reset(opj_tgt_tree_t *tree); +/** +Set the value of a leaf of a tag-tree +@param tree Tag-tree to modify +@param leafno Number that identifies the leaf to modify +@param value New value of the leaf +*/ +void tgt_setvalue(opj_tgt_tree_t *tree, OPJ_UINT32 leafno, OPJ_INT32 value); +/** +Encode the value of a leaf of the tag-tree up to a given threshold +@param bio Pointer to a BIO handle +@param tree Tag-tree to modify +@param leafno Number that identifies the leaf to encode +@param threshold Threshold to use when encoding value of the leaf +*/ +void tgt_encode(struct opj_bio *bio, opj_tgt_tree_t *tree, OPJ_UINT32 leafno, OPJ_INT32 threshold); +/** +Decode the value of a leaf of the tag-tree up to a given threshold +@param bio Pointer to a BIO handle +@param tree Tag-tree to decode +@param leafno Number that identifies the leaf to decode +@param threshold Threshold to use when decoding value of the leaf +@return Returns 1 if the node's value < threshold, returns 0 otherwise +*/ +OPJ_UINT32 tgt_decode(struct opj_bio *bio, opj_tgt_tree_t *tree, OPJ_UINT32 leafno, OPJ_INT32 threshold); +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __TGT_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/license.txt b/gdcm/Utilities/gdcmopenjpeg-v2/license.txt new file mode 100644 index 0000000..93abc45 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/license.txt @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/mj2/CMakeLists.txt b/gdcm/Utilities/gdcmopenjpeg-v2/mj2/CMakeLists.txt new file mode 100644 index 0000000..56a59d5 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/mj2/CMakeLists.txt @@ -0,0 +1,42 @@ +# Makefile for the MJ2 codecs of the OpenJPEG library: frames_to_mj2, mj2_to_frames, extract_j2k_from_mj2 and wrap_j2k_in_mj2 + +# Headers file are located here: +include_directories( + ${OPENJPEG_SOURCE_DIR}/libopenjpeg + ) + +add_executable(frames_to_mj2 + frames_to_mj2.c + compat/getopt.c + mj2_convert.c mj2.c ) +target_link_libraries(frames_to_mj2 ${OPJ_PREFIX}openjpeg) +if(UNIX) + target_link_libraries(frames_to_mj2 m) +endif() + +add_executable(mj2_to_frames + mj2_to_frames.c + compat/getopt.c mj2_convert.c mj2.c ) +target_link_libraries(mj2_to_frames ${OPJ_PREFIX}openjpeg) +if(UNIX) + target_link_libraries(mj2_to_frames m) +endif() + +add_executable(extract_j2k_from_mj2 + extract_j2k_from_mj2.c + mj2.c ) +target_link_libraries(extract_j2k_from_mj2 ${OPJ_PREFIX}openjpeg) +if(UNIX) + target_link_libraries(extract_j2k_from_mj2 m) +endif() + +add_executable(wrap_j2k_in_mj2 + wrap_j2k_in_mj2.c + mj2.c ) +target_link_libraries(wrap_j2k_in_mj2 ${OPJ_PREFIX}openjpeg) +if(UNIX) + target_link_libraries(wrap_j2k_in_mj2 m) +endif() + +install(TARGETS frames_to_mj2 mj2_to_frames extract_j2k_from_mj2 wrap_j2k_in_mj2 + DESTINATION bin) diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/mj2/Makefile b/gdcm/Utilities/gdcmopenjpeg-v2/mj2/Makefile new file mode 100644 index 0000000..18d6030 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/mj2/Makefile @@ -0,0 +1,20 @@ +# Makefile for the MJ2 codecs of the OpenJPEG library: frames_to_mj2, mj2_to_frames, extract_j2k_from_mj2 and wrap_j2k_in_mj2 + +CFLAGS = -O3 -lstdc++ # -g -p -pg + +all: frames_to_mj2 mj2_to_frames extract_j2k_from_mj2 wrap_j2k_in_mj2 + +frames_to_mj2: frames_to_mj2.c ../libopenjpeg.a + gcc $(CFLAGS) compat/getopt.c mj2_convert.c mj2.c frames_to_mj2.c -o frames_to_mj2 -L.. -lopenjpeg -I ../libopenjpeg/ -lm + +mj2_to_frames: mj2_to_frames.c ../libopenjpeg.a + gcc $(CFLAGS) compat/getopt.c mj2_convert.c mj2.c mj2_to_frames.c -o mj2_to_frames -L.. -lopenjpeg -I ../libopenjpeg/ -lm + +extract_j2k_from_mj2: extract_j2k_from_mj2.c ../libopenjpeg.a + gcc $(CFLAGS) mj2.c extract_j2k_from_mj2.c -o extract_j2k_from_mj2 -L.. -lopenjpeg -I ../libopenjpeg/ -lm + +wrap_j2k_in_mj2: wrap_j2k_in_mj2.c ../libopenjpeg.a + gcc $(CFLAGS) mj2.c wrap_j2k_in_mj2.c -o wrap_j2k_in_mj2 -L.. -lopenjpeg -I ../libopenjpeg/ -lm + +clean: + rm -f frames_to_mj2 mj2_to_frames extract_j2k_from_mj2 wrap_j2k_in_mj2 diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/mj2/extract_j2k_from_mj2.c b/gdcm/Utilities/gdcmopenjpeg-v2/mj2/extract_j2k_from_mj2.c new file mode 100644 index 0000000..08b5b2e --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/mj2/extract_j2k_from_mj2.c @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2003-2007, Francois-Olivier Devaux + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + +#include "openjpeg.h" +#include "j2k.h" +#include "jp2.h" +#include "mj2.h" + +/* -------------------------------------------------------------------------- */ + +/** +sample error callback expecting a FILE* client object +*/ +void error_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[ERROR] %s", msg); +} +/** +sample warning callback expecting a FILE* client object +*/ +void warning_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[WARNING] %s", msg); +} +/** +sample debug callback expecting a FILE* client object +*/ +void info_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[INFO] %s", msg); +} + +/* -------------------------------------------------------------------------- */ + + +int main(int argc, char *argv[]) { + opj_dinfo_t* dinfo; + opj_event_mgr_t event_mgr; /* event manager */ + int tnum; + unsigned int snum; + opj_mj2_t *movie; + mj2_tk_t *track; + mj2_sample_t *sample; + unsigned char* frame_codestream; + FILE *file, *outfile; + char outfilename[50]; + mj2_dparameters_t parameters; + + if (argc != 3) { + printf("Bad syntax: Usage: MJ2_extractor mj2filename output_location\n"); + printf("Example: MJ2_extractor foreman.mj2 output/foreman\n"); + return 1; + } + + file = fopen(argv[1], "rb"); + + if (!file) { + fprintf(stderr, "failed to open %s for reading\n", argv[1]); + return 1; + } + + /* + configure the event callbacks (not required) + setting of each callback is optionnal + */ + memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); + event_mgr.error_handler = error_callback; + event_mgr.warning_handler = warning_callback; + event_mgr.info_handler = info_callback; + + /* get a MJ2 decompressor handle */ + dinfo = mj2_create_decompress(); + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr); + + /* setup the decoder decoding parameters using user parameters */ + movie = (opj_mj2_t*) dinfo->mj2_handle; + mj2_setup_decoder(dinfo->mj2_handle, ¶meters); + + if (mj2_read_struct(file, movie)) // Creating the movie structure + return 1; + + // Decode first video track + tnum = 0; + while (movie->tk[tnum].track_type != 0) + tnum ++; + + track = &movie->tk[tnum]; + + fprintf(stdout,"Extracting %d frames from file...\n",track->num_samples); + + for (snum=0; snum < track->num_samples; snum++) + { + sample = &track->sample[snum]; + frame_codestream = (unsigned char*) malloc (sample->sample_size-8); // Skipping JP2C marker + fseek(file,sample->offset+8,SEEK_SET); + fread(frame_codestream,sample->sample_size-8,1, file); // Assuming that jp and ftyp markers size do + + sprintf(outfilename,"%s_%05d.j2k",argv[2],snum); + outfile = fopen(outfilename, "wb"); + if (!outfile) { + fprintf(stderr, "failed to open %s for writing\n",outfilename); + return 1; + } + fwrite(frame_codestream,sample->sample_size-8,1,outfile); + fclose(outfile); + free(frame_codestream); + } + fclose(file); + fprintf(stdout, "%d frames correctly extracted\n", snum); + + /* free remaining structures */ + if(dinfo) { + mj2_destroy_decompress((opj_mj2_t*)dinfo->mj2_handle); + } + + return 0; +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/mj2/frames_to_mj2.c b/gdcm/Utilities/gdcmopenjpeg-v2/mj2/frames_to_mj2.c new file mode 100644 index 0000000..676c5e3 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/mj2/frames_to_mj2.c @@ -0,0 +1,806 @@ +/* +* Copyright (c) 2003-2004, François-Olivier Devaux +* Copyright (c) 2002-2004, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include + +#include "openjpeg.h" +#include "j2k_lib.h" +#include "j2k.h" +#include "jp2.h" +#include "cio.h" +#include "mj2.h" +#include "mj2_convert.h" +#include "compat/getopt.h" + +/** +Size of memory first allocated for MOOV box +*/ +#define TEMP_BUF 10000 + +/* -------------------------------------------------------------------------- */ + +/** +sample error callback expecting a FILE* client object +*/ +void error_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[ERROR] %s", msg); +} +/** +sample warning callback expecting a FILE* client object +*/ +void warning_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[WARNING] %s", msg); +} +/** +sample debug callback expecting a FILE* client object +*/ +void info_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[INFO] %s", msg); +} + +/* -------------------------------------------------------------------------- */ + + +void help_display() +{ + fprintf(stdout,"HELP\n----\n\n"); + fprintf(stdout,"- the -h option displays this help information on screen\n\n"); + + + fprintf(stdout,"List of parameters for the MJ2 encoder:\n"); + fprintf(stdout,"\n"); + fprintf(stdout,"REMARKS:\n"); + fprintf(stdout,"---------\n"); + fprintf(stdout,"\n"); + fprintf + (stdout,"The markers written to the main_header are : SOC SIZ COD QCD COM.\n"); + fprintf + (stdout,"COD and QCD never appear in the tile_header.\n"); + fprintf(stdout,"\n"); + fprintf(stdout,"By default:\n"); + fprintf(stdout,"------------\n"); + fprintf(stdout,"\n"); + fprintf(stdout," * Lossless\n"); + fprintf(stdout," * 1 tile\n"); + fprintf(stdout," * Size of precinct : 2^15 x 2^15 (means 1 precinct)\n"); + fprintf(stdout," * Size of code-block : 64 x 64\n"); + fprintf(stdout," * Number of resolutions: 6\n"); + fprintf(stdout," * No SOP marker in the codestream\n"); + fprintf(stdout," * No EPH marker in the codestream\n"); + fprintf(stdout," * No sub-sampling in x or y direction\n"); + fprintf(stdout," * No mode switch activated\n"); + fprintf(stdout," * Progression order: LRCP\n"); + fprintf(stdout," * No index file\n"); + fprintf(stdout," * No ROI upshifted\n"); + fprintf(stdout," * No offset of the origin of the image\n"); + fprintf(stdout," * No offset of the origin of the tiles\n"); + fprintf(stdout," * Reversible DWT 5-3\n"); + fprintf(stdout,"\n"); + fprintf(stdout,"Parameters:\n"); + fprintf(stdout,"------------\n"); + fprintf(stdout,"\n"); + fprintf + (stdout,"Required Parameters (except with -h):\n"); + fprintf + (stdout,"-i : source file (-i source.yuv) \n"); + fprintf + (stdout,"-o : destination file (-o dest.mj2) \n"); + fprintf + (stdout,"Optional Parameters:\n"); + fprintf(stdout,"-h : display the help information \n"); + fprintf(stdout,"-r : different compression ratios for successive layers (-r 20,10,5)\n "); + fprintf(stdout," - The rate specified for each quality level is the desired \n"); + fprintf(stdout," compression factor.\n"); + fprintf(stdout," Example: -r 20,10,1 means quality 1: compress 20x, \n"); + fprintf(stdout," quality 2: compress 10x and quality 3: compress lossless\n"); + fprintf(stdout," (options -r and -q cannot be used together)\n "); + + fprintf(stdout,"-q : different psnr for successive layers (-q 30,40,50) \n "); + + fprintf(stdout," (options -r and -q cannot be used together)\n "); + + fprintf(stdout,"-n : number of resolutions (-n 3) \n"); + fprintf(stdout,"-b : size of code block (-b 32,32) \n"); + fprintf(stdout,"-c : size of precinct (-c 128,128) \n"); + fprintf(stdout,"-t : size of tile (-t 512,512) \n"); + fprintf + (stdout,"-p : progression order (-p LRCP) [LRCP, RLCP, RPCL, PCRL, CPRL] \n"); + fprintf + (stdout,"-s : subsampling factor (-s 2,2) [-s X,Y] \n"); + fprintf(stdout," Remark: subsampling bigger than 2 can produce error\n"); + fprintf + (stdout,"-SOP : write SOP marker before each packet \n"); + fprintf + (stdout,"-EPH : write EPH marker after each header packet \n"); + fprintf + (stdout,"-M : mode switch (-M 3) [1=BYPASS(LAZY) 2=RESET 4=RESTART(TERMALL)\n"); + fprintf + (stdout," 8=VSC 16=ERTERM(SEGTERM) 32=SEGMARK(SEGSYM)] \n"); + fprintf + (stdout," Indicate multiple modes by adding their values. \n"); + fprintf + (stdout," ex: RESTART(4) + RESET(2) + SEGMARK(32) = -M 38\n"); + fprintf + (stdout,"-ROI : c=%%d,U=%%d : quantization indices upshifted \n"); + fprintf + (stdout," for component c=%%d [%%d = 0,1,2]\n"); + fprintf + (stdout," with a value of U=%%d [0 <= %%d <= 37] (i.e. -ROI:c=0,U=25) \n"); + fprintf + (stdout,"-d : offset of the origin of the image (-d 150,300) \n"); + fprintf + (stdout,"-T : offset of the origin of the tiles (-T 100,75) \n"); + fprintf(stdout,"-I : use the irreversible DWT 9-7 (-I) \n"); + fprintf(stdout,"-W : image width, height and the dx and dy subsampling \n"); + fprintf(stdout," of the Cb and Cr components for YUV files \n"); + fprintf(stdout," (default is '352,288,2,2' for CIF format's 352x288 and 4:2:0)\n"); + fprintf(stdout,"-F : video frame rate (set to 25 by default)\n"); + + fprintf(stdout,"\n"); + fprintf(stdout,"IMPORTANT:\n"); + fprintf(stdout,"-----------\n"); + fprintf(stdout,"\n"); + fprintf(stdout,"The index file has the structure below:\n"); + fprintf(stdout,"---------------------------------------\n"); + fprintf(stdout,"\n"); + fprintf(stdout,"Image_height Image_width\n"); + fprintf(stdout,"progression order\n"); + fprintf(stdout,"Tiles_size_X Tiles_size_Y\n"); + fprintf(stdout,"Components_nb\n"); + fprintf(stdout,"Layers_nb\n"); + fprintf(stdout,"decomposition_levels\n"); + fprintf(stdout,"[Precincts_size_X_res_Nr Precincts_size_Y_res_Nr]...\n"); + fprintf(stdout," [Precincts_size_X_res_0 Precincts_size_Y_res_0]\n"); + fprintf(stdout,"Main_header_end_position\n"); + fprintf(stdout,"Codestream_size\n"); + fprintf(stdout,"Tile_0 start_pos end_Theader end_pos TotalDisto NumPix MaxMSE\n"); + fprintf(stdout,"Tile_1 '' '' '' '' '' ''\n"); + fprintf(stdout,"...\n"); + fprintf(stdout,"Tile_Nt '' '' '' '' '' ''\n"); + fprintf(stdout,"Tpacket_0 Tile layer res. comp. prec. start_pos end_pos disto\n"); + fprintf(stdout,"...\n"); + fprintf(stdout,"Tpacket_Np '' '' '' '' '' '' '' ''\n"); + + fprintf(stdout,"MaxDisto\n"); + + fprintf(stdout,"TotalDisto\n\n"); +} + +int give_progression(char progression[4]) +{ + if (progression[0] == 'L' && progression[1] == 'R' + && progression[2] == 'C' && progression[3] == 'P') { + return 0; + } else { + if (progression[0] == 'R' && progression[1] == 'L' + && progression[2] == 'C' && progression[3] == 'P') { + return 1; + } else { + if (progression[0] == 'R' && progression[1] == 'P' + && progression[2] == 'C' && progression[3] == 'L') { + return 2; + } else { + if (progression[0] == 'P' && progression[1] == 'C' + && progression[2] == 'R' && progression[3] == 'L') { + return 3; + } else { + if (progression[0] == 'C' && progression[1] == 'P' + && progression[2] == 'R' && progression[3] == 'L') { + return 4; + } else { + return -1; + } + } + } + } + } +} + + + + +int main(int argc, char **argv) +{ + mj2_cparameters_t mj2_parameters; /* MJ2 compression parameters */ + opj_cparameters_t *j2k_parameters; /* J2K compression parameters */ + opj_event_mgr_t event_mgr; /* event manager */ + opj_cio_t *cio; + char value; + opj_mj2_t *movie; + opj_image_t *img; + int i, j; + char *s, S1, S2, S3; + char *buf; + int x1, y1, len; + long mdat_initpos, offset; + FILE *mj2file; + int sampleno; + opj_cinfo_t* cinfo; + bool bSuccess; + int numframes; + double total_time = 0; + + /* default value */ + /* ------------- */ + mj2_parameters.Dim[0] = 0; + mj2_parameters.Dim[1] = 0; + mj2_parameters.w = 352; // CIF default value + mj2_parameters.h = 288; // CIF default value + mj2_parameters.CbCr_subsampling_dx = 2; // CIF default value + mj2_parameters.CbCr_subsampling_dy = 2; // CIF default value + mj2_parameters.frame_rate = 25; + /* + configure the event callbacks (not required) + setting of each callback is optionnal + */ + memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); + event_mgr.error_handler = error_callback; + event_mgr.warning_handler = warning_callback; + event_mgr.info_handler = NULL; + + /* set J2K encoding parameters to default values */ + opj_set_default_encoder_parameters(&mj2_parameters.j2k_parameters); + j2k_parameters = &mj2_parameters.j2k_parameters; + + /* Create comment for codestream */ + if(j2k_parameters->cp_comment == NULL) { + const char comment[] = "Created by OpenJPEG version "; + const size_t clen = strlen(comment); + const char *version = opj_version(); + j2k_parameters->cp_comment = (char*)malloc(clen+strlen(version)+1); + sprintf(j2k_parameters->cp_comment,"%s%s", comment, version); + } + + mj2_parameters.decod_format = 0; + mj2_parameters.cod_format = 0; + + while (1) { + int c = getopt(argc, argv, + "i:o:r:q:f:t:n:c:b:p:s:d:h P:S:E:M:R:T:C:I:W:F:"); + if (c == -1) + break; + switch (c) { + case 'i': /* IN fill */ + { + char *infile = optarg; + s = optarg; + while (*s) { + s++; + } + s--; + S3 = *s; + s--; + S2 = *s; + s--; + S1 = *s; + + if ((S1 == 'y' && S2 == 'u' && S3 == 'v') + || (S1 == 'Y' && S2 == 'U' && S3 == 'V')) { + mj2_parameters.decod_format = YUV_DFMT; + } + else { + fprintf(stderr, + "!! Unrecognized format for infile : %c%c%c [accept only *.yuv] !!\n\n", + S1, S2, S3); + return 1; + } + strncpy(mj2_parameters.infile, infile, sizeof(mj2_parameters.infile)-1); + } + break; + /* ----------------------------------------------------- */ + case 'o': /* OUT fill */ + { + char *outfile = optarg; + while (*outfile) { + outfile++; + } + outfile--; + S3 = *outfile; + outfile--; + S2 = *outfile; + outfile--; + S1 = *outfile; + + outfile = optarg; + + if ((S1 == 'm' && S2 == 'j' && S3 == '2') + || (S1 == 'M' && S2 == 'J' && S3 == '2')) + mj2_parameters.cod_format = MJ2_CFMT; + else { + fprintf(stderr, + "Unknown output format image *.%c%c%c [only *.mj2]!! \n", + S1, S2, S3); + return 1; + } + strncpy(mj2_parameters.outfile, outfile, sizeof(mj2_parameters.outfile)-1); + } + break; + /* ----------------------------------------------------- */ + case 'r': /* rates rates/distorsion */ + { + float rate; + s = optarg; + while (sscanf(s, "%f", &rate) == 1) { + j2k_parameters->tcp_rates[j2k_parameters->tcp_numlayers] = rate * 2; + j2k_parameters->tcp_numlayers++; + while (*s && *s != ',') { + s++; + } + if (!*s) + break; + s++; + } + j2k_parameters->cp_disto_alloc = 1; + } + break; + /* ----------------------------------------------------- */ + case 'q': /* add fixed_quality */ + s = optarg; + while (sscanf(s, "%f", &j2k_parameters->tcp_distoratio[j2k_parameters->tcp_numlayers]) == 1) { + j2k_parameters->tcp_numlayers++; + while (*s && *s != ',') { + s++; + } + if (!*s) + break; + s++; + } + j2k_parameters->cp_fixed_quality = 1; + break; + /* dda */ + /* ----------------------------------------------------- */ + case 'f': /* mod fixed_quality (before : -q) */ + { + int *row = NULL, *col = NULL; + int numlayers = 0, numresolution = 0, matrix_width = 0; + + s = optarg; + sscanf(s, "%d", &numlayers); + s++; + if (numlayers > 9) + s++; + + j2k_parameters->tcp_numlayers = numlayers; + numresolution = j2k_parameters->numresolution; + matrix_width = numresolution * 3; + j2k_parameters->cp_matrice = (int *) malloc(numlayers * matrix_width * sizeof(int)); + s = s + 2; + + for (i = 0; i < numlayers; i++) { + row = &j2k_parameters->cp_matrice[i * matrix_width]; + col = row; + j2k_parameters->tcp_rates[i] = 1; + sscanf(s, "%d,", &col[0]); + s += 2; + if (col[0] > 9) + s++; + col[1] = 0; + col[2] = 0; + for (j = 1; j < numresolution; j++) { + col += 3; + sscanf(s, "%d,%d,%d", &col[0], &col[1], &col[2]); + s += 6; + if (col[0] > 9) + s++; + if (col[1] > 9) + s++; + if (col[2] > 9) + s++; + } + if (i < numlayers - 1) + s++; + } + j2k_parameters->cp_fixed_alloc = 1; + } + break; + /* ----------------------------------------------------- */ + case 't': /* tiles */ + sscanf(optarg, "%d,%d", &j2k_parameters->cp_tdx, &j2k_parameters->cp_tdy); + j2k_parameters->tile_size_on = true; + break; + /* ----------------------------------------------------- */ + case 'n': /* resolution */ + sscanf(optarg, "%d", &j2k_parameters->numresolution); + break; + /* ----------------------------------------------------- */ + case 'c': /* precinct dimension */ + { + char sep; + int res_spec = 0; + + char *s = optarg; + do { + sep = 0; + sscanf(s, "[%d,%d]%c", &j2k_parameters->prcw_init[res_spec], + &j2k_parameters->prch_init[res_spec], &sep); + j2k_parameters->csty |= 0x01; + res_spec++; + s = strpbrk(s, "]") + 2; + } + while (sep == ','); + j2k_parameters->res_spec = res_spec; + } + break; + + /* ----------------------------------------------------- */ + case 'b': /* code-block dimension */ + { + int cblockw_init = 0, cblockh_init = 0; + sscanf(optarg, "%d,%d", &cblockw_init, &cblockh_init); + if (cblockw_init * cblockh_init > 4096 || cblockw_init > 1024 + || cblockw_init < 4 || cblockh_init > 1024 || cblockh_init < 4) { + fprintf(stderr, + "!! Size of code_block error (option -b) !!\n\nRestriction :\n" + " * width*height<=4096\n * 4<=width,height<= 1024\n\n"); + return 1; + } + j2k_parameters->cblockw_init = cblockw_init; + j2k_parameters->cblockh_init = cblockh_init; + } + break; + /* ----------------------------------------------------- */ + case 'p': /* progression order */ + { + char progression[4]; + + strncpy(progression, optarg, 4); + j2k_parameters->prog_order = give_progression(progression); + if (j2k_parameters->prog_order == -1) { + fprintf(stderr, "Unrecognized progression order " + "[LRCP, RLCP, RPCL, PCRL, CPRL] !!\n"); + return 1; + } + } + break; + /* ----------------------------------------------------- */ + case 's': /* subsampling factor */ + { + if (sscanf(optarg, "%d,%d", &j2k_parameters->subsampling_dx, + &j2k_parameters->subsampling_dy) != 2) { + fprintf(stderr, "'-s' sub-sampling argument error ! [-s dx,dy]\n"); + return 1; + } + } + break; + /* ----------------------------------------------------- */ + case 'd': /* coordonnate of the reference grid */ + { + if (sscanf(optarg, "%d,%d", &j2k_parameters->image_offset_x0, + &j2k_parameters->image_offset_y0) != 2) { + fprintf(stderr, "-d 'coordonnate of the reference grid' argument " + "error !! [-d x0,y0]\n"); + return 1; + } + } + break; + /* ----------------------------------------------------- */ + case 'h': /* Display an help description */ + help_display(); + return 0; + break; + /* ----------------------------------------------------- */ + case 'P': /* POC */ + { + int numpocs = 0; /* number of progression order change (POC) default 0 */ + opj_poc_t *POC = NULL; /* POC : used in case of Progression order change */ + + char *s = optarg; + POC = j2k_parameters->POC; + + while (sscanf(s, "T%d=%d,%d,%d,%d,%d,%4s", &POC[numpocs].tile, + &POC[numpocs].resno0, &POC[numpocs].compno0, + &POC[numpocs].layno1, &POC[numpocs].resno1, + &POC[numpocs].compno1, &POC[numpocs].progorder) == 7) { + POC[numpocs].prg1 = give_progression(POC[numpocs].progorder); + numpocs++; + while (*s && *s != '/') { + s++; + } + if (!*s) { + break; + } + s++; + } + j2k_parameters->numpocs = numpocs; + } + break; + /* ------------------------------------------------------ */ + case 'S': /* SOP marker */ + j2k_parameters->csty |= 0x02; + break; + /* ------------------------------------------------------ */ + case 'E': /* EPH marker */ + j2k_parameters->csty |= 0x04; + break; + /* ------------------------------------------------------ */ + case 'M': /* Mode switch pas tous au point !! */ + if (sscanf(optarg, "%d", &value) == 1) { + for (i = 0; i <= 5; i++) { + int cache = value & (1 << i); + if (cache) + j2k_parameters->mode |= (1 << i); + } + } + break; + /* ------------------------------------------------------ */ + case 'R': /* ROI */ + { + if (sscanf(optarg, "OI:c=%d,U=%d", &j2k_parameters->roi_compno, + &j2k_parameters->roi_shift) != 2) { + fprintf(stderr, "ROI error !! [-ROI:c='compno',U='shift']\n"); + return 1; + } + } + break; + /* ------------------------------------------------------ */ + case 'T': /* Tile offset */ + { + if (sscanf(optarg, "%d,%d", &j2k_parameters->cp_tx0, &j2k_parameters->cp_ty0) != 2) { + fprintf(stderr, "-T 'tile offset' argument error !! [-T X0,Y0]"); + return 1; + } + } + break; + /* ------------------------------------------------------ */ + case 'C': /* Add a comment */ + { + j2k_parameters->cp_comment = (char*)malloc(strlen(optarg) + 1); + if(j2k_parameters->cp_comment) { + strcpy(j2k_parameters->cp_comment, optarg); + } + } + break; + /* ------------------------------------------------------ */ + case 'I': /* reversible or not */ + { + j2k_parameters->irreversible = 1; + } + break; + /* ------------------------------------------------------ */ + case 'W': /* Width and Height and Cb and Cr subsampling in case of YUV format files */ + if (sscanf + (optarg, "%d,%d,%d,%d", &mj2_parameters.w, &mj2_parameters.h, &mj2_parameters.CbCr_subsampling_dx, + &mj2_parameters.CbCr_subsampling_dy) != 4) { + fprintf(stderr, "-W argument error"); + return 1; + } + break; + /* ------------------------------------------------------ */ + case 'F': /* Video frame rate */ + if (sscanf(optarg, "%d", &mj2_parameters.frame_rate) != 1) { + fprintf(stderr, "-F argument error"); + return 1; + } + break; + /* ------------------------------------------------------ */ + default: + return 1; + } + } + + /* Error messages */ + /* -------------- */ + if (!mj2_parameters.cod_format || !mj2_parameters.decod_format) { + fprintf(stderr, + "Correct usage: mj2_encoder -i yuv-file -o mj2-file (+ options)\n"); + return 1; + } + + if ((j2k_parameters->cp_disto_alloc || j2k_parameters->cp_fixed_alloc || j2k_parameters->cp_fixed_quality) + && (!(j2k_parameters->cp_disto_alloc ^ j2k_parameters->cp_fixed_alloc ^ j2k_parameters->cp_fixed_quality))) { + fprintf(stderr, "Error: options -r -q and -f cannot be used together !!\n"); + return 1; + } /* mod fixed_quality */ + + /* if no rate entered, lossless by default */ + if (j2k_parameters->tcp_numlayers == 0) { + j2k_parameters->tcp_rates[0] = 0; /* MOD antonin : losslessbug */ + j2k_parameters->tcp_numlayers++; + j2k_parameters->cp_disto_alloc = 1; + } + + if((j2k_parameters->cp_tx0 > j2k_parameters->image_offset_x0) || (j2k_parameters->cp_ty0 > j2k_parameters->image_offset_y0)) { + fprintf(stderr, + "Error: Tile offset dimension is unnappropriate --> TX0(%d)<=IMG_X0(%d) TYO(%d)<=IMG_Y0(%d) \n", + j2k_parameters->cp_tx0, j2k_parameters->image_offset_x0, j2k_parameters->cp_ty0, j2k_parameters->image_offset_y0); + return 1; + } + + for (i = 0; i < j2k_parameters->numpocs; i++) { + if (j2k_parameters->POC[i].prg == -1) { + fprintf(stderr, + "Unrecognized progression order in option -P (POC n %d) [LRCP, RLCP, RPCL, PCRL, CPRL] !!\n", + i + 1); + } + } + + if (j2k_parameters->cp_tdx > mj2_parameters.Dim[0] || j2k_parameters->cp_tdy > mj2_parameters.Dim[1]) { + fprintf(stderr, + "Error: Tile offset dimension is unnappropriate --> TX0(%d)<=IMG_X0(%d) TYO(%d)<=IMG_Y0(%d) \n", + j2k_parameters->cp_tdx, mj2_parameters.Dim[0], j2k_parameters->cp_tdy, mj2_parameters.Dim[1]); + return 1; + } + + /* to respect profile - 0 */ + /* ---------------------- */ + + x1 = !mj2_parameters.Dim[0] ? (mj2_parameters.w - 1) * j2k_parameters->subsampling_dx + + 1 : mj2_parameters.Dim[0] + (mj2_parameters.w - 1) * j2k_parameters->subsampling_dx + 1; + y1 = !mj2_parameters.Dim[1] ? (mj2_parameters.h - 1) * j2k_parameters->subsampling_dy + + 1 : mj2_parameters.Dim[1] + (mj2_parameters.h - 1) * j2k_parameters->subsampling_dy + 1; + mj2_parameters.numcomps = 3; /* Because YUV files only have 3 components */ + mj2_parameters.prec = 8; /* Because in YUV files, components have 8-bit depth */ + + j2k_parameters->tcp_mct = 0; + + mj2file = fopen(mj2_parameters.outfile, "wb"); + + if (!mj2file) { + fprintf(stderr, "failed to open %s for writing\n", argv[2]); + return 1; + } + + /* get a MJ2 decompressor handle */ + cinfo = mj2_create_compress(); + movie = cinfo->mj2_handle; + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)cinfo, &event_mgr, stderr); + + /* setup encoder parameters */ + mj2_setup_encoder(movie, &mj2_parameters); + + movie->tk[0].num_samples = yuv_num_frames(&movie->tk[0],mj2_parameters.infile); + if (movie->tk[0].num_samples == -1) { + return 1; + } + + // One sample per chunk + movie->tk[0].chunk = (mj2_chunk_t*) malloc(movie->tk[0].num_samples * sizeof(mj2_chunk_t)); + movie->tk[0].sample = (mj2_sample_t*) malloc(movie->tk[0].num_samples * sizeof(mj2_sample_t)); + + if (mj2_init_stdmovie(movie)) { + fprintf(stderr, "Error with movie initialization"); + return 1; + }; + + // Writing JP, FTYP and MDAT boxes + buf = (char*) malloc (300 * sizeof(char)); // Assuming that the JP and FTYP + // boxes won't be longer than 300 bytes + cio = opj_cio_open((opj_common_ptr)movie->cinfo, buf, 300); + mj2_write_jp(cio); + mj2_write_ftyp(movie, cio); + mdat_initpos = cio_tell(cio); + cio_skip(cio, 4); + cio_write(cio, MJ2_MDAT, 4); + fwrite(buf,cio_tell(cio),1,mj2file); + offset = cio_tell(cio); + opj_cio_close(cio); + free(buf); + + for (i = 0; i < movie->num_stk + movie->num_htk + movie->num_vtk; i++) { + if (movie->tk[i].track_type != 0) { + fprintf(stderr, "Unable to write sound or hint tracks\n"); + } else { + mj2_tk_t *tk; + int buflen = 0; + + tk = &movie->tk[i]; + tk->num_chunks = tk->num_samples; + numframes = tk->num_samples; + + fprintf(stderr, "Video Track number %d\n", i + 1); + + img = mj2_image_create(tk, j2k_parameters); + buflen = 2 * (tk->w * tk->h * 8); + buf = (char *) malloc(buflen*sizeof(char)); + + for (sampleno = 0; sampleno < numframes; sampleno++) { + double init_time = opj_clock(); + double elapsed_time; + if (yuvtoimage(tk, img, sampleno, j2k_parameters, mj2_parameters.infile)) { + fprintf(stderr, "Error with frame number %d in YUV file\n", sampleno); + return 1; + } + + /* setup the encoder parameters using the current image and user parameters */ + opj_setup_encoder(cinfo, j2k_parameters, img); + + cio = opj_cio_open((opj_common_ptr)movie->cinfo, buf, buflen); + + cio_skip(cio, 4); + cio_write(cio, JP2_JP2C, 4); // JP2C + + /* encode the image */ + bSuccess = opj_encode(cinfo, cio, img, NULL); + if (!bSuccess) { + opj_cio_close(cio); + fprintf(stderr, "failed to encode image\n"); + return 1; + } + + len = cio_tell(cio) - 8; + cio_seek(cio, 0); + cio_write(cio, len+8,4); + opj_cio_close(cio); + tk->sample[sampleno].sample_size = len+8; + tk->sample[sampleno].offset = offset; + tk->chunk[sampleno].offset = offset; // There is one sample per chunk + fwrite(buf, 1, len+8, mj2file); + offset += len+8; + elapsed_time = opj_clock()-init_time; + fprintf(stderr, "Frame number %d/%d encoded in %.2f mseconds\n", sampleno + 1, numframes, elapsed_time*1000); + total_time += elapsed_time; + + } + /* free buffer data */ + free(buf); + /* free image data */ + opj_image_destroy(img); + } + } + + fseek(mj2file, mdat_initpos, SEEK_SET); + + buf = (char*) malloc(4*sizeof(char)); + + // Init a cio to write box length variable in a little endian way + cio = opj_cio_open(NULL, buf, 4); + cio_write(cio, offset - mdat_initpos, 4); + fwrite(buf, 4, 1, mj2file); + fseek(mj2file,0,SEEK_END); + free(buf); + + // Writing MOOV box + buf = (char*) malloc ((TEMP_BUF+numframes*20) * sizeof(char)); + cio = opj_cio_open(movie->cinfo, buf, (TEMP_BUF+numframes*20)); + mj2_write_moov(movie, cio); + fwrite(buf,cio_tell(cio),1,mj2file); + free(buf); + + fprintf(stdout,"Total encoding time: %.2f s for %d frames (%.1f fps)\n", total_time, numframes, (float)numframes/total_time); + + // Ending program + + fclose(mj2file); + /* free remaining compression structures */ + mj2_destroy_compress(movie); + free(cinfo); + /* free user parameters structure */ + if(j2k_parameters->cp_comment) free(j2k_parameters->cp_comment); + if(j2k_parameters->cp_matrice) free(j2k_parameters->cp_matrice); + opj_cio_close(cio); + + return 0; +} + + diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/mj2/meta_out.c b/gdcm/Utilities/gdcmopenjpeg-v2/mj2/meta_out.c new file mode 100644 index 0000000..6d714d4 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/mj2/meta_out.c @@ -0,0 +1,2181 @@ +/* meta_out.c */ +/* Dump MJ2, JP2 metadata (partial so far) to xml file */ +/* Callable from mj2_to_metadata */ +/* Contributed to Open JPEG by Glenn Pearson, contract software developer, U.S. National Library of Medicine. + +The base code in this file was developed by the author as part of a video archiving +project for the U.S. National Library of Medicine, Bethesda, MD. +It is the policy of NLM (and U.S. government) to not assert copyright. + +A non-exclusive copy of this code has been contributed to the Open JPEG project. +Except for copyright, inclusion of the code within Open JPEG for distribution and use +can be bound by the Open JPEG open-source license and disclaimer, expressed elsewhere. +*/ + +#include /* for time functions */ + +#include "opj_includes.h" +#include "mj2.h" + +#include +#include "meta_out.h" + +static BOOL notes = TRUE; +static BOOL sampletables = FALSE; +static BOOL raw = TRUE; +static BOOL derived = TRUE; + +opj_tcp_t *j2k_default_tcp; + +/* Forwards */ +int xml_write_overall_header(FILE *file, FILE *xmlout, opj_mj2_t * movie, unsigned int sampleframe, opj_event_mgr_t *event_mgr); +int xml_write_moov(FILE *file, FILE *xmlout, opj_mj2_t * movie, unsigned int sampleframe, opj_event_mgr_t *event_mgr); + +void uint_to_chars(unsigned int value, char* buf); + +void xml_write_trak(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum, unsigned int sampleframe, opj_event_mgr_t *event_mgr); +void xml_write_tkhd(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum); +void xml_write_udta(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum); +void xml_write_mdia(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum); +void xml_write_stbl(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum); + +void UnixTimeToFileTime(time_t t, LPFILETIME pft); +void UnixTimeToSystemTime(time_t t, LPSYSTEMTIME pst); +void xml_time_out(FILE* xmlout, time_t t); + +void int16_to_3packedchars(short int value, char* buf); + +void xml_write_moov_udta(FILE* xmlout, opj_mj2_t * movie); +void xml_write_free_and_skip(FILE* xmlout, opj_mj2_t * movie); +void xml_write_uuid(FILE* xmlout, opj_mj2_t * movie); + +int xml_out_frame(FILE* file, FILE* xmlout, mj2_sample_t *sample, unsigned int snum, opj_event_mgr_t *event_mgr); + +void xml_out_frame_siz(FILE* xmlout, opj_image_t *img, opj_cp_t *cp); +void xml_out_frame_cod(FILE* xmlout, opj_tcp_t *tcp); +void xml_out_frame_coc(FILE* xmlout, opj_tcp_t *tcp, int numcomps); /* opj_image_t *img); */ +BOOL same_component_style(opj_tccp_t *tccp1, opj_tccp_t *tccp2); +void xml_out_frame_qcd(FILE* xmlout, opj_tcp_t *tcp); +void xml_out_frame_qcc(FILE* xmlout, opj_tcp_t *tcp, int numcomps); /* opj_image_t *img); */ +BOOL same_component_quantization(opj_tccp_t *tccp1, opj_tccp_t *tccp2); +void xml_out_frame_rgn(FILE* xmlout, opj_tcp_t *tcp, int numcomps);/* opj_image_t *img);*/ +void xml_out_frame_poc(FILE* xmlout, opj_tcp_t *tcp); +void xml_out_frame_ppm(FILE* xmlout, opj_cp_t *cp); +void xml_out_frame_ppt(FILE* xmlout, opj_tcp_t *tcp); +void xml_out_frame_tlm(FILE* xmlout); /* j2k_default_tcp is passed globally */ /* NO-OP. TLM NOT SAVED IN DATA STRUCTURE */ +void xml_out_frame_plm(FILE* xmlout); /* j2k_default_tcp is passed globally */ /* NO-OP. PLM NOT SAVED IN DATA STRUCTURE. opt in main; can be used in conjunction with PLT */ +void xml_out_frame_plt(FILE* xmlout, opj_tcp_t *tcp); /* NO-OP. PLM NOT SAVED IN DATA STRUCTURE. opt in main; can be used in conjunction with PLT */ +void xml_out_frame_crg(FILE* xmlout); /* j2k_default_tcp is passed globally */ /* opt in main; */ +void xml_out_frame_com(FILE* xmlout, opj_tcp_t *tcp); /* NO-OP. COM NOT SAVED IN DATA STRUCTURE */ /* opt in main; */ +void xml_out_dump_hex(FILE* xmlout, char *data, int data_len, char* s); +void xml_out_dump_hex_and_ascii(FILE* xmlout, char *data, int data_len, char* s); +void xml_out_frame_jp2h(FILE* xmlout, opj_jp2_t *jp2_struct); +#ifdef NOTYET +/* Shown with cp, extended, as data structure... but it could be a new different one */ +void xml_out_frame_jp2i(FILE* xmlout, opj_cp_t *cp);/* IntellectualProperty 'jp2i' (no restrictions on location) */ +void xml_out_frame_xml(FILE* xmlout, opj_cp_t *cp); /* XML 'xml\040' (0x786d6c20). Can appear multiply */ +void xml_out_frame_uuid(FILE* xmlout, opj_cp_t *cp); /* UUID 'uuid' (top level only) */ +void xml_out_frame_uinf(FILE* xmlout, opj_cp_t *cp); /* UUIDInfo 'uinf', includes UUIDList 'ulst' and URL 'url\40' */ +void xml_out_frame_unknown_type(FILE* xmlout, opj_cp_t *cp); +#endif + + +void xml_write_init(BOOL n, BOOL t, BOOL r, BOOL d) +{ + /* Init file globals */ + notes = n; + sampletables = t; + raw = r; + derived = d; +} + +int xml_write_struct(FILE* file, FILE *xmlout, opj_mj2_t * movie, unsigned int sampleframe, char* stringDTD, opj_event_mgr_t *event_mgr) { + + if(stringDTD != NULL) + { + fprintf(xmlout,"\n"); + /* stringDTD is known to start with "SYSTEM " or "PUBLIC " */ + /* typical: SYSTEM mj2_to_metadata.dtd */ + stringDTD[6] = '\0'; /* Break into two strings at space, so quotes can be inserted. */ + fprintf(xmlout,"\n", stringDTD, stringDTD+7); + stringDTD[6] = ' '; /* restore for sake of debugger or memory allocator */ + } else + fprintf(xmlout,"\n"); + + fprintf(xmlout, "\n"); + xml_write_overall_header(file, xmlout, movie, sampleframe, event_mgr); + fprintf(xmlout, ""); + return 0; +} + +/* ------------- */ + +int xml_write_overall_header(FILE *file, FILE *xmlout, opj_mj2_t * movie, unsigned int sampleframe, opj_event_mgr_t *event_mgr) +{ + int i; + char buf[5]; + buf[4] = '\0'; + + fprintf(xmlout, " \n"); + // Called after structure initialized by mj2_read_ftyp + fprintf(xmlout, " \n"); + uint_to_chars(movie->brand, buf); + fprintf(xmlout, " %s\n", buf); /* 4 character; BR */ + fprintf(xmlout, " %u\n", movie->minversion); /* 4 char; MinV */ + fprintf(xmlout, " \n",movie->num_cl); + for (i = movie->num_cl - 1; i > -1; i--) /* read routine stored in reverse order, so let's undo damage */ + { + uint_to_chars(movie->cl[i], buf); + fprintf(xmlout, " %s\n", buf); /*4 characters, each CLi */ + } + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + xml_write_moov(file, xmlout, movie, sampleframe, event_mgr); + // To come? // This is the container for media data that can also be accessed through track structures, + // so is redundant, and simply not of interest as metadata + // // Allows incremental build up of movie. Probably not in Simple Profile + xml_write_free_and_skip(xmlout, movie); /* NO OP so far */ /* May be a place where user squirrels metadata */ + xml_write_uuid(xmlout, movie); /* NO OP so far */ /* May be a place where user squirrels metadata */ + return 0; +} + +/* ------------- */ + +int xml_write_moov(FILE *file, FILE *xmlout, opj_mj2_t * movie, unsigned int sampleframe, opj_event_mgr_t *event_mgr) +{ + unsigned int tnum; + mj2_tk_t *track; + + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + if(raw) + fprintf(xmlout, " %u\n", movie->creation_time); + if(notes) + fprintf(xmlout, " \n"); + /* 2082844800 = seconds between 1/1/04 and 1/1/70 */ + /* There's still a time zone offset problem not solved... but spec is ambigous as to whether stored time + should be local or UTC */ + if(derived) { + fprintf(xmlout, " "); + xml_time_out(xmlout, movie->creation_time - 2082844800); + fprintf(xmlout,"\n"); + } + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + if(raw) + fprintf(xmlout, " %u\n", movie->modification_time); + if(derived) { + fprintf(xmlout, " "); + xml_time_out(xmlout, movie->modification_time - 2082844800); + fprintf(xmlout,"\n"); + } + fprintf(xmlout, " \n"); + fprintf(xmlout, " %d\n", movie->timescale); + if(notes) + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); /* Rate to play presentation (default = 0x00010000) */ + if(notes) { + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } + if(raw) + fprintf(xmlout, " 0x%08x\n", movie->rate); + if(derived) + fprintf(xmlout, " %12.6f\n", (double)movie->rate/(double)0x00010000); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + if(raw) + fprintf(xmlout, " %u\n", movie->duration); + if(derived) + fprintf(xmlout, " %12.3f\n", (double)movie->duration/(double)movie->timescale); // Make this double later to get fractional seconds + fprintf(xmlout, " \n"); +#ifdef CURRENTSTRUCT + movie->volume = movie->volume << 8; +#endif + fprintf(xmlout, " \n"); + if(notes) { + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } + if(raw) + fprintf(xmlout, " 0x%04x\n", movie->volume); + if(derived) + fprintf(xmlout, " %6.3f\n", (double)movie->volume/(double)0x0100); + fprintf(xmlout, " \n"); +#ifdef CURRENTSTRUCT + if(notes) + fprintf(xmlout, " \n"); + movie->volume = movie->volume >> 8; +#endif + /* Transformation matrix for video */ + fprintf(xmlout, " \n"); + if(notes) { + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } + fprintf(xmlout, " 0x%08x\n", movie->trans_matrix[0]); + fprintf(xmlout, " 0x%08x\n", movie->trans_matrix[1]); + fprintf(xmlout, " 0x%08x\n", movie->trans_matrix[2]); + fprintf(xmlout, " 0x%08x\n", movie->trans_matrix[3]); + fprintf(xmlout, " 0x%08x\n", movie->trans_matrix[4]); + fprintf(xmlout, " 0x%08x\n", movie->trans_matrix[5]); + fprintf(xmlout, " 0x%08x\n", movie->trans_matrix[6]); + fprintf(xmlout, " 0x%08x\n", movie->trans_matrix[7]); + fprintf(xmlout, " 0x%08x\n", movie->trans_matrix[8]); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n", movie->num_vtk); + fprintf(xmlout, " \n", movie->num_stk); + fprintf(xmlout, " %d\n", movie->num_htk); + if(notes) + fprintf(xmlout, " \n"); + /* See Part 3 Amend 2 Section 4.2 for relation of MJ2 to Part 12 Sections 7 and 10 hints */ + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + /* Idea for the future: It would be possible to add code to verify that the file values: + 1) are legal and self-consistent + 2) comply with particular JP2 and/or MJ2 profiles. + This could be reported here as additional XML elements */ + + // Find first video track + tnum = 0; + while (movie->tk[tnum].track_type != 0) + tnum ++; + + track = &(movie->tk[tnum]); + // For now, output info on first video track + xml_write_trak(file, xmlout, track, tnum, sampleframe, event_mgr); + + // to come: // possibly not in Simple Profile + xml_write_moov_udta(xmlout, movie); /* NO OP so far */ /* contains */ + fprintf(xmlout, " \n"); + return 0; +} + +/* --------------- */ + +void uint_to_chars(unsigned int value, char* buf) +{ + /* buf is at least char[5] */ + int i; + for (i = 3; i >= 0; i--) + { + buf[i] = (value & 0x000000ff); + value = (value >> 8); + } + buf[4] = '\0'; /* Precautionary */ +} + +/* ------------- */ + +/* WINDOWS SPECIFIC */ + +void UnixTimeToFileTime(time_t t, LPFILETIME pft) +{ + /* Windows specific. From MS Q167296 */ + /* 'time_t' represents seconds since midnight January 1, 1970 UTC (coordinated universal time). */ + /* 64-bit FILETIME structure represents the number of 100-nanosecond intervals since January 1, 1601 UTC (coordinate universal time). */ + LONGLONG ll; /* LONGLONG is a 64-bit value. */ + ll = Int32x32To64(t, 10000000) + 116444736000000000; + pft->dwLowDateTime = (DWORD)ll; + /* pft->dwLowDateTime = (DWORD)(0x00000000ffffffff & ll); */ + pft->dwHighDateTime = (DWORD)(ll >> 32); +} +// Once the UNIX time is converted to a FILETIME structure, +// other Win32 time formats can be easily obtained by using Win32 functions such +// as FileTimeToSystemTime() and FileTimeToDosDateTime(). + +/* ------------- */ + +void UnixTimeToSystemTime(time_t t, LPSYSTEMTIME pst) +{ + /* Windows specific */ + FILETIME ft; + UnixTimeToFileTime(t, &ft); + FileTimeToLocalFileTime( &ft, &ft ); /* Adjust from UTC to local time zone */ + FileTimeToSystemTime(&ft, pst); +} + +/* ------------- */ + +void xml_time_out(FILE* xmlout, time_t t) +{ + /* Windows specific */ + SYSTEMTIME st; + char szLocalDate[255], szLocalTime[255]; + UnixTimeToSystemTime( t, &st ); + GetDateFormat( LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, szLocalDate, 255 ); + GetTimeFormat( LOCALE_USER_DEFAULT, 0, &st, NULL, szLocalTime, 255 ); + fprintf(xmlout, "%s %s", szLocalDate, szLocalTime ); +} + +/* END WINDOWS SPECIFIC */ + +/* ------------- */ + +void xml_write_moov_udta(FILE* xmlout, opj_mj2_t * movie) { + /* Compare with xml_write_udta */ +#ifdef NOTYET + /* NO-OP so far. Optional UserData 'udta' (zero or one in moov or each trak) + can contain multiple Copyright 'cprt' with different language codes */ + /* There may be nested non-standard boxes within udta */ + IMAGINE movie->udta, movie->copyright_count, movie->copyright_language[i] (array of 16bit ints), movie->copyright_notice[i] (array of buffers) + PROBABLY ALSO NEED movie->udta_len or special handler for non-standard boxes + char buf[5]; + int i; + + if(movie->udta != 1) + return; /* Not present */ + + fprintf(xmlout, " \n"); + for(i = 0; i < movie->copyright_count; i++) { + fprintf(xmlout, " Instance=\"%d\">\n", i+1); + int16_to_3packedchars((short int)movie->copyright_languages[i], buf); + fprintf(xmlout, " %s\n", buf); /* 3 chars */ + fprintf(xmlout, " %s\n",movie->copyright_notices[i]); + fprintf(xmlout, " \n", i+1); + } + /* TO DO: Non-standard boxes */ + fprintf(xmlout, " \n"); +#endif +} + +void xml_write_free_and_skip(FILE* xmlout, opj_mj2_t * movie) { +#ifdef NOTYET + /* NO-OP so far. There can be zero or more instances of free and/or skip + at the top level of the file. This may be a place where the user squirrel's metadata. + Let's assume unstructured, and do a dump */ + IMAGINE movie->free_and_skip, movie->free_and_skip_count, movie->free_and_skip_content[i] (array of buffers), + movie->free_and_skip_len[i] (array of ints), movie->is_skip[i] (array of BOOL) + int i; + + if(movie->free_and_skip != 1) + return; /* Not present */ + + for(i = 0; i < movie->free_and_skip_count; i++) { + if(movie->is_skip[i]) + fprintf(xmlout, " \n"); + else + fprintf(xmlout, " \n"); + + xml_out_dump_hex_and_ascii(xmlout, movie->free_and_skip_contents[i], movie->free_and_skip_len[i]); + + if(movie->is_skip[i]) + fprintf(xmlout, " \n"); + else + fprintf(xmlout, " \n"); + } +#endif +} + +void xml_write_uuid(FILE* xmlout, opj_mj2_t * movie) { +/* Univeral Unique IDs of 16 bytes. */ +#ifdef NOTYET + /* NO-OP so far. There can be zero or more instances of private uuid boxes in a file. + This function supports the top level of the file, but uuid may be elsewhere [not yet supported]. + This may be a place where the user squirrel's metadata. Let's assume unstructured, and do a dump */ + IMAGINE movie->uuid, movie->uuid_count, movie->uuid_content[i] (array of buffers), + movie->uuid_len[i] (array of ints), movie->uuid_type[i] (array of 17-byte (16+null termination) buffers) + int i; + + if(movie->uuid != 1) + return; /* Not present */ + + for(i = 0; i < movie->uuid_count; i++) { + fprintf(xmlout, " \n", movie->uuid_type[i]); + // See Part III section 5.2.1, 6.1, 6.2 + xml_out_dump_hex_and_ascii(xmlout, movie->uuid_contents[i], movie->uuid_len[i]); + fprintf(xmlout, " \n"); + } +#endif +} + +/* ------------- */ + +void xml_write_trak(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum, unsigned int sampleframe, opj_event_mgr_t *event_mgr) +{ + fprintf(xmlout, " \n", tnum); + xml_write_tkhd(file, xmlout, track, tnum); + // TO DO: TrackReferenceContainer 'tref' just used in hint track + // TO DO: EditListContainer 'edts', contains EditList 'elst' with media-time, segment-duration, media-rate + xml_write_mdia(file, xmlout, track, tnum); + xml_write_udta(file, xmlout, track, tnum); // NO-OP so far. Optional UserData 'udta', can contain multiple Copyright 'cprt' + + if(track->track_type==0) { /* Only do for visual track */ + /* sampleframe is from user option -f. 1 = first frame */ + /* sampleframe of 0 is a user requests: no jp2 header */ + /* Treat out-of-bounds values in the same way */ + if(sampleframe > 0 && sampleframe <= track->num_samples) + { + mj2_sample_t *sample; + unsigned int snum; + + snum = sampleframe-1; + // Someday maybe do a smart range scan... for (snum=0; snum < track->num_samples; snum++){ + // fprintf(stdout,"Frame %d: ",snum+1); + sample = &track->sample[snum]; + if(xml_out_frame(file, xmlout, sample, snum, event_mgr)) + return; /* Not great error handling here */ + } + } + fprintf(xmlout, " \n"); +} + +/* ------------- */ + +void xml_write_tkhd(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum) +{ + fprintf(xmlout, " \n"); + if(notes) { + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } + fprintf(xmlout, " %u\n", track->track_ID); + if(track->track_type==0) /* For visual track */ + { + fprintf(xmlout, " %d\n", track->layer); + if(notes) + fprintf(xmlout," \n"); + } + if(track->track_type!=0) /* volume irrelevant for visual track */ + { +#ifdef CURRENTSTRUCT + track->volume = track->volume << 8; +#endif + fprintf(xmlout, " \n"); + if(notes) { + fprintf(xmlout," \n"); + fprintf(xmlout," \n"); + } + if(raw) + fprintf(xmlout," 0x%04x\n", track->volume); + if(derived) + fprintf(xmlout," %6.3f\n", (double)track->volume/(double)0x0100); + fprintf(xmlout, " \n"); +#ifdef CURRENTSTRUCT + if(notes) + fprintf(xmlout, " \n"); + track->volume = track->volume >> 8; +#endif + } + if(track->track_type==0) + { + /* Transformation matrix for video */ + fprintf(xmlout, " \n"); + if(notes) { + fprintf(xmlout," \n"); + fprintf(xmlout," \n"); + } + fprintf(xmlout, " 0x%08x\n", track->trans_matrix[0]); + fprintf(xmlout, " 0x%08x\n", track->trans_matrix[1]); + fprintf(xmlout, " 0x%08x\n", track->trans_matrix[2]); + fprintf(xmlout, " 0x%08x\n", track->trans_matrix[3]); + fprintf(xmlout, " 0x%08x\n", track->trans_matrix[4]); + fprintf(xmlout, " 0x%08x\n", track->trans_matrix[5]); + fprintf(xmlout, " 0x%08x\n", track->trans_matrix[6]); + fprintf(xmlout, " 0x%08x\n", track->trans_matrix[7]); + fprintf(xmlout, " 0x%08x\n", track->trans_matrix[8]); + fprintf(xmlout, " \n"); + } +#ifdef CURRENTSTRUCT + track->w = track->w << 16; + track->h = track->h << 16; +#endif + if(notes) { + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } + fprintf(xmlout, " \n"); + if(raw) + fprintf(xmlout, " 0x%08x\n", track->w); + if(derived) + fprintf(xmlout, " %12.6f\n", (double)track->w/(double)0x00010000); /* Rate to play presentation (default = 0x00010000) */ + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + if(raw) + fprintf(xmlout, " 0x%08x\n", track->h); + if(derived) + fprintf(xmlout, " %12.6f\n", (double)track->h/(double)0x00010000); /* Rate to play presentation (default = 0x00010000) */ + fprintf(xmlout, " \n"); +#ifdef CURRENTSTRUCT + if(notes) { + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } + track->w = track->w >> 16; + track->h = track->h >> 16; +#endif + fprintf(xmlout, " \n"); +} + +/* ------------- */ + +void xml_write_udta(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum) { + /* NO-OP so far. Optional UserData 'udta' (zero or one in moov or each trak) + can contain multiple Copyright 'cprt' with different language codes */ + /* There may be nested non-standard boxes within udta */ +#ifdef NOTYET + IMAGINE track->udta, track->copyright_count, track->copyright_language[i] (array of 16bit ints), track->copyright_notice[i] (array of buffers) + PROBABLY ALSO NEED track->udta_len or special handler for non-standard boxes + char buf[5]; + int i; + + if(track->udta != 1) + return; /* Not present */ + + fprintf(xmlout, " \n"); + for(i = 0; i < track->copyright_count; i++) { + fprintf(xmlout, " Instance=\"%d\">\n", i+1); + int16_to_3packedchars((short int)track->copyright_languages[i], buf); + fprintf(xmlout, " %s\n", buf); /* 3 chars */ + fprintf(xmlout, " %s\n",track->copyright_notices[i]); + fprintf(xmlout, " \n", i+1); + } + /* TO DO: Non-standard boxes */ + fprintf(xmlout, " \n"); +#endif +} + +/* ------------- */ + +void xml_write_mdia(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum) +{ + char buf[5]; + int i, k; + buf[4] = '\0'; + + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + if(raw) + fprintf(xmlout, " %u\n", track->creation_time); + if(notes) + fprintf(xmlout, " \n"); + /* 2082844800 = seconds between 1/1/04 and 1/1/70 */ + /* There's still a time zone offset problem not solved... but spec is ambigous as to whether stored time + should be local or UTC */ + if(derived) { + fprintf(xmlout, " "); + xml_time_out(xmlout, track->creation_time - 2082844800); + fprintf(xmlout,"\n"); + } + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + if(raw) + fprintf(xmlout, " %u\n", track->modification_time); + if(derived) { + fprintf(xmlout, " "); + xml_time_out(xmlout, track->modification_time - 2082844800); + fprintf(xmlout,"\n"); + } + fprintf(xmlout, " \n"); + fprintf(xmlout, " %d\n", track->timescale); + if(notes) + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + if(raw) + fprintf(xmlout, " %u\n", track->duration); + if(derived) + fprintf(xmlout, " %12.3f\n", (double)track->duration/(double)track->timescale); // Make this double later to get fractional seconds + fprintf(xmlout, " \n"); + int16_to_3packedchars((short int)track->language, buf); + fprintf(xmlout, " %s\n", buf); /* 3 chars */ + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + switch(track->track_type) + { + case 0: + fprintf(xmlout, " video media track\n"); break; + case 1: + fprintf(xmlout, " Sound\n"); break; + case 2: + fprintf(xmlout, " Hint\n"); break; + } + if(notes) { + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + switch(track->track_type) + { + case 0: + fprintf(xmlout, " \n"); + fprintf(xmlout, " 0x%02x\n", track->graphicsmode); + if(notes) { + fprintf(xmlout," \n"); + fprintf(xmlout," \n"); + fprintf(xmlout," \n"); + fprintf(xmlout," \n"); +/* fprintf(xmlout," \n"); This was evidently dropped upon amendment */ + fprintf(xmlout," \n"); + fprintf(xmlout," \n"); + } + fprintf(xmlout, " \n"); + fprintf(xmlout, " 0x%02x\n", track->opcolor[0]); + fprintf(xmlout, " 0x%02x\n",track->opcolor[1]); + fprintf(xmlout, " 0x%02x\n",track->opcolor[2]); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + break; + case 1: + fprintf(xmlout, " \n"); +#ifdef CURRENTSTRUCT + track->balance = track->balance << 8; +#endif + fprintf(xmlout, " \n"); + if(notes) { + fprintf(xmlout," \n"); + fprintf(xmlout," \n"); + fprintf(xmlout," \n"); + } + if(raw) + fprintf(xmlout," 0x%04x\n", track->balance); + if(derived) + fprintf(xmlout," %6.3f\n", (double)track->balance/(double)0x0100); + fprintf(xmlout, " \n"); +#ifdef CURRENTSTRUCT + if(notes) + fprintf(xmlout," \n"); + track->balance = track->balance >> 8; +#endif + fprintf(xmlout, " \n"); + break; + case 2: + fprintf(xmlout, " \n"); + fprintf(xmlout, " %d\n", track->maxPDUsize); + if(notes) + fprintf(xmlout," \n"); + fprintf(xmlout, " %d\n", track->avgPDUsize); + if(notes) + fprintf(xmlout," \n"); + fprintf(xmlout, " %d\n", track->maxbitrate); + if(notes) + fprintf(xmlout," \n"); + fprintf(xmlout, " %d\n", track->avgbitrate); + if(notes) + fprintf(xmlout," \n"); + fprintf(xmlout, " %d\n", track->slidingavgbitrate); + if(notes) + fprintf(xmlout," \n"); + fprintf(xmlout, " \n"); + break; + } + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n", track->num_url, track->num_urn); // table w. flags, URLs, URNs + // Data structure does not distinguish between single URL, single URN, or DREF table or URLs & URNs. + // We could infer those, but for now just present everything as a DREF table. + if(notes) + fprintf(xmlout, " \n"); + for(k = 0; k < track->num_url; k++) { + fprintf(xmlout, " \n"); // table w. flags, URLs, URNs + if(notes) + fprintf(xmlout," \n"); + for(i = 0; i < 4; i++) { + uint_to_chars(track->url[track->num_url].location[i], buf); + fprintf(xmlout, " %s\n"); + } + fprintf(xmlout, " \n"); // table w. flags, URLs, URNs + } + for(k = 0; k < track->num_urn; k++) { + fprintf(xmlout," \n"); // table w. flags, URLs, URNs + // Only the first 16 bytes are recorded in the data structure currently. + if(notes) + fprintf(xmlout," \n"); + fprintf(xmlout, " "); + for(i = 0; i < 4; i++) { + uint_to_chars(track->urn[track->num_urn].name[i], buf); + fprintf(xmlout,"%s", buf); + } + fprintf(xmlout, "\n"); + fprintf(xmlout, " "); + for(i = 0; i < 4; i++) { + uint_to_chars(track->urn[track->num_urn].location[i], buf); + fprintf(xmlout,"%s"); + } + fprintf(xmlout, "\n"); + fprintf(xmlout, " \n"); + } + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + + xml_write_stbl(file, xmlout, track, tnum); /* SampleTable */ + + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); +} + +/* ------------- */ + +void xml_write_stbl(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum) +{ + char buf[5], buf33[33]; + int i, len; + buf[4] = '\0'; + + fprintf(xmlout, " \n"); + if(notes) + fprintf(xmlout, " \n"); + switch(track->track_type) + { + case 0: + // There could be multiple instances of this, but "entry_count" is just a local at read-time. + // And it's used wrong, too, as count of just visual type, when it's really all 3 types. + // This is referred to as "smj2" within mj2.c + fprintf(xmlout, " \n"); + if(notes) { + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } + /* No shifting required. If CURRENTSTRUCT gets changed, then may need to revisit treatment of these */ + fprintf(xmlout, " %d\n", track->w); + fprintf(xmlout, " %d\n", track->h); +// Horizresolution and vertresolution don't require shifting, already stored right in CURRENTSTRUCT + if(notes) { + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } + fprintf(xmlout, " \n"); + if(raw) + fprintf(xmlout, " 0x%08x\n", track->horizresolution); + if(derived) + fprintf(xmlout, " %12.6f\n", (double)track->horizresolution/(double)0x00010000); /* Rate to play presentation (default = 0x00010000) */ + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + if(raw) + fprintf(xmlout, " 0x%08x\n", track->vertresolution); + if(derived) + fprintf(xmlout, " %12.6f\n", (double)track->vertresolution/(double)0x00010000); /* Rate to play presentation (default = 0x00010000) */ + fprintf(xmlout, " \n"); + + buf33[0] = '\0'; + for(i = 0; i < 8; i++) { + uint_to_chars((unsigned int)track->compressorname[i], buf); + strcat(buf33, buf); /* This loads up (4 * 8) + 1 chars, but trailing ones are usually junk */ + } + len = (int)buf33[0]; /* First byte has string length in bytes. There may be garbage beyond it. */ + buf33[len+1] = '\0'; /* Suppress it */ + fprintf(xmlout, " %s\n", buf33+1); /* Start beyond first byte */ + if(notes) { + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } + fprintf(xmlout, " 0x%02x\n",track->depth); + if(notes) { + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } + + xml_out_frame_jp2h(xmlout, &(track->jp2_struct)); /* JP2 Header */ + + /* Following subboxes are optional */ + fprintf(xmlout, " \n"); + fprintf(xmlout, " %d\n", (unsigned int)track->fieldcount); /* uchar as 1 byte uint */ + if(notes) + fprintf(xmlout, " \n"); + fprintf(xmlout, " %d\n", (unsigned int)track->fieldorder); /* uchar as 1 byte uint */ + if(notes) { + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } + fprintf(xmlout, " \n"); + + fprintf(xmlout, " \n",track->num_br); + for (i = 0; i < track->num_br; i++) /* read routine stored in reverse order, so let's undo damage */ + { + uint_to_chars(track->br[i], buf); + fprintf(xmlout, " %s\n", buf); /*4 characters, each CLi */ + } + fprintf(xmlout, " \n"); + + fprintf(xmlout, " \n",track->num_jp2x); + for (i = 0; i < track->num_jp2x; i++) + { // We'll probably need better formatting than this + fprintf(xmlout, " 0x%02x\n", track->jp2xdata[i]); /* Each entry is single byte */ + } + fprintf(xmlout, " \n"); + + fprintf(xmlout, " \n"); /* These values are all 1 byte */ + if(notes) + fprintf(xmlout, " \n"); + fprintf(xmlout, " %d\n", track->hsub); + fprintf(xmlout, " %d\n", track->vsub); + fprintf(xmlout, " %d\n", track->hoff); + fprintf(xmlout, " %d\n", track->voff); + if(notes) { + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } + fprintf(xmlout, " \n"); /* These values are all 1 byte */ + + fprintf(xmlout, " \n"); /* Part III Appx. 2 */ + fprintf(xmlout, " %u\n", (unsigned int)track->or_fieldcount); /* uchar as 1-byte uint */ + if(notes) + fprintf(xmlout, " \n"); + fprintf(xmlout, " %u\n", (unsigned int)track->or_fieldorder); /* uchar as 1-byte uint */ + if(notes) { + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + break; + case 1: case 2: + if(notes) + fprintf(xmlout, " \n"); break; + } + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " %d\n", track->num_samples); + if(notes) + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n", track->num_tts); + for (i = 0; i < track->num_tts; i++) { + fprintf(xmlout, " \n", + i+1, track->tts[i].sample_count, track->tts[i].sample_delta); + } + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + + fprintf(xmlout, " \n", track->num_samplestochunk); + for (i = 0; i < track->num_samplestochunk; i++) { + fprintf(xmlout, " %u\n",track->sampletochunk[i].first_chunk); /* 4 bytes */ + fprintf(xmlout, " %u\n",track->sampletochunk[i].samples_per_chunk); /* 4 bytes */ + fprintf(xmlout, " %u\n",track->sampletochunk[i].sample_descr_idx); /* 4 bytes */ + } + fprintf(xmlout, " \n"); + // After reading this info in, track->num_chunks is calculated and a decompressed table established internally. + + fprintf(xmlout, " \n"); + if(track->same_sample_size) { + // all values in track->sample[i].sample_size are equal. Grab the first one. + fprintf(xmlout, " %u\n", track->sample[0].sample_size); + if(notes) { + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } + } else { + fprintf(xmlout, " 0\n"); + if(notes) + if(sampletables) + fprintf(xmlout," \n"); + else + fprintf(xmlout," \n"); + fprintf(xmlout, " %u\n", track->num_samples); + if(sampletables) + for (i = 0; i < (int)track->num_samples; i++) { + fprintf(xmlout, " %u\n", i+1, track->sample[i].sample_size); + } + } + fprintf(xmlout, " \n"); + + fprintf(xmlout, " \n"); + // Structure not yet - Variant ChunkLargeOffset 'co64' + fprintf(xmlout, " %u\n", track->num_chunks); + if(notes) { + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } + if(sampletables) + for (i = 0; i < (int)track->num_chunks; i++) + fprintf(xmlout, " %u\n", i+1, track->chunk[i].offset); + fprintf(xmlout, " \n"); + + fprintf(xmlout, " \n"); +} + +/* ------------- */ + +int xml_out_frame(FILE* file, FILE* xmlout, mj2_sample_t *sample, unsigned int snum, opj_event_mgr_t *event_mgr) +{ + opj_dparameters_t parameters; /* decompression parameters */ + opj_image_t *img; + opj_cp_t *cp; + int i; + int numcomps; + unsigned char* frame_codestream; + opj_dinfo_t* dinfo = NULL; /* handle to a decompressor */ + opj_cio_t *cio = NULL; + opj_j2k_t *j2k; + + /* JPEG 2000 compressed image data */ + + /* get a decoder handle */ + dinfo = opj_create_decompress(CODEC_J2K); + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)dinfo, event_mgr, stderr); + + /* setup the decoder decoding parameters using the current image and user parameters */ + parameters.cp_limit_decoding = DECODE_ALL_BUT_PACKETS; + opj_setup_decoder(dinfo, ¶meters); + + frame_codestream = (unsigned char*) malloc (sample->sample_size-8); /* Skipping JP2C marker */ + if(frame_codestream == NULL) + return 1; + + fseek(file,sample->offset+8,SEEK_SET); + fread(frame_codestream,sample->sample_size-8,1, file); /* Assuming that jp and ftyp markers size do */ + + /* open a byte stream */ + cio = opj_cio_open((opj_common_ptr)dinfo, frame_codestream, sample->sample_size-8); + + /* Decode J2K to image: */ + img = opj_decode(dinfo, cio); + if (!img) { + fprintf(stderr, "ERROR -> j2k_to_image: failed to decode image!\n"); + opj_destroy_decompress(dinfo); + opj_cio_close(cio); + return 1; + } + + j2k = (opj_j2k_t*)dinfo->j2k_handle; + j2k_default_tcp = j2k->default_tcp; + cp = j2k->cp; + + numcomps = img->numcomps; + /* Alignments: " < To help maintain xml pretty-printing */ + fprintf(xmlout, " \n", snum+1); + fprintf(xmlout, " \n"); + /* There can be multiple codestreams; a particular image is entirely within a single codestream */ + /* TO DO: A frame can be represented by two I-guess-contigious codestreams if its interleaved. */ + fprintf(xmlout, " \n"); + /* "cp" stands for "coding parameter"; "tcp" is tile coding parameters, "tccp" is tile-component coding parameters */ + xml_out_frame_siz(xmlout, img, cp); /* reqd in main */ + xml_out_frame_cod(xmlout, j2k_default_tcp); /* reqd in main */ + xml_out_frame_coc(xmlout, j2k_default_tcp, numcomps); /* opt in main, at most 1 per component */ + xml_out_frame_qcd(xmlout, j2k_default_tcp); /* reqd in main */ + xml_out_frame_qcc(xmlout, j2k_default_tcp, numcomps); /* opt in main, at most 1 per component */ + xml_out_frame_rgn(xmlout, j2k_default_tcp, numcomps); /* opt, at most 1 per component */ + xml_out_frame_poc(xmlout, j2k_default_tcp); /* opt (but reqd in main or tile for any progression order changes) */ + /* Next four get j2k_default_tcp passed globally: */ +#ifdef SUPPRESS_FOR_NOW + xml_out_frame_ppm(xmlout, cp); /* opt (but either PPM or PPT [distributed in tile headers] or codestream packet header reqd) */ +#endif + xml_out_frame_tlm(xmlout); /* NO-OP. TLM NOT SAVED IN DATA STRUCTURE */ /* opt */ + xml_out_frame_plm(xmlout); /* NO-OP. PLM NOT SAVED IN DATA STRUCTURE */ /* opt in main; can be used in conjunction with PLT */ + xml_out_frame_crg(xmlout); /* NO-OP. CRG NOT SAVED IN DATA STRUCTURE */ /* opt in main; */ + xml_out_frame_com(xmlout, j2k_default_tcp); /* NO-OP. COM NOT SAVED IN DATA STRUCTURE */ /* opt in main; */ + + fprintf(xmlout, " \n"); + + /* TO DO: all the tile headers (sigh) */ + fprintf(xmlout, " \n", cp->tileno_size); /* size of the vector tileno */ + for(i = 0; i < cp->tileno_size; i++) { /* I think cp->tileno_size will be same number as (cp->tw * cp->th) or as global j2k_curtileno */ + // Standard seems to use zero-based # for tile-part. + fprintf(xmlout, " \n", i, cp->tileno[i]); /* ID number of the tiles present in the codestream */ + fprintf(xmlout, " \n"); + /* All markers in tile-part headers (between SOT and SOD) are optional, unless structure requires. */ + if(i == 0) { + xml_out_frame_cod(xmlout, &(cp->tcps[i])); /* No more than 1 per tile */ + xml_out_frame_coc(xmlout, &(cp->tcps[i]), numcomps); /* No more than 1 per component */ + xml_out_frame_qcd(xmlout, &(cp->tcps[i])); /* No more than 1 per tile */ + xml_out_frame_qcc(xmlout, &(cp->tcps[i]), numcomps); /* No more than 1 per component */ + xml_out_frame_rgn(xmlout, &(cp->tcps[i]), numcomps); /* No more than 1 per component */ + } + xml_out_frame_poc(xmlout, &(cp->tcps[i])); /* Reqd only if any progression order changes different from main POC */ +#ifdef SUPPRESS_FOR_NOW + xml_out_frame_ppt(xmlout, &(cp->tcps[i])); /* Either PPT [distributed in tile headers] or PPM or codestream packet header reqd. */ +#endif + xml_out_frame_plt(xmlout, &(cp->tcps[i])); /* NO-OP. PLT NOT SAVED IN DATA STRUCTURE */ /* Can be used in conjunction with main's PLM */ + xml_out_frame_com(xmlout, &(cp->tcps[i])); /* NO-OP. COM NOT SAVED IN DATA STRUCTURE */ + /* opj_tcp_t * cp->tcps; "tile coding parameters" */ + /* Maybe not: fprintf(xmlout, " <>%d, cp->matrice[i]; */ /* Fixed layer */ + fprintf(xmlout, " \n"); + if(notes) + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } + fprintf(xmlout, " \n"); /* size of the vector tileno */ + +#ifdef NOTYET + IMAGINE the cp object has data to support the following... but we could use an new different data structure instead + /* I'm unclear if the span of the original fread(frame_codestream...) included the following items if they're trailing. */ + /* ALSO TO DO, BUT DATA STRUCTURE DOESN'T HANDLE YET: boxes (anywhere in file except before the Filetype box): */ + xml_out_frame_jp2i(xmlout, &cp); /* IntellectualProperty 'jp2i' (no restrictions on location) */ + xml_out_frame_xml(xmlout, &cp); /* XML 'xml\040' (0x786d6c20). Can appear multiply */ + xml_out_frame_uuid(xmlout, &cp); /* UUID 'uuid' (top level only) */ + xml_out_frame_uinf(xmlout, &cp); /* UUIDInfo 'uinf', includes UUIDList 'ulst' and URL 'url\40' */ +#endif + + fprintf(xmlout, " \n"); + + /* Extra commentary: */ + if(notes) { + fprintf(xmlout, " \n"); + if (((img->numcomps == 3) && (img->comps[0].dx == img->comps[1].dx / 2) + && (img->comps[0].dx == img->comps[2].dx / 2 ) && (img->comps[0].dx == 1)) + || (img->numcomps == 1)) { + fprintf(xmlout, " \n"); + } + else if ((img->numcomps == 3) && + (img->comps[0].dx == 1) && (img->comps[1].dx == 1)&& + (img->comps[2].dx == 1)) {// If YUV 4:4:4 input --> to bmp + fprintf(xmlout, " \n"); + } + else { + fprintf(xmlout, " \n"); + } + } + + opj_destroy_decompress(dinfo); + opj_cio_close(cio); + free(frame_codestream); + + return 0; +} + +/* ------------- */ + +void int16_to_3packedchars(short int value, char* buf) +{ + /* This is to retrieve the 3-letter ASCII language code */ + /* Each char is packed into 5 bits, as difference from 0x60 */ + int i; + for (i = 2; i >= 0; i--) + { + buf[i] = (value & 0x001f) + 0x60; + value = (value >>5); + } + buf[3] = '\0'; +} + +/* ------------- */ + +void xml_out_frame_siz(FILE* xmlout, opj_image_t *img, opj_cp_t *cp) +{ + opj_image_comp_t *comp; + int i; + + fprintf(xmlout, " \n"); + // This is similar to j2k.c's j2k_dump_image. + // Not of interest: Lsiz, Rsiz + fprintf(xmlout, " %d\n", img->x1); + fprintf(xmlout, " %d\n", img->y1); + if(notes) + fprintf(xmlout, " \n"); + fprintf(xmlout, " %d\n", img->x0); + fprintf(xmlout, " %d\n", img->y0); + if(notes) + fprintf(xmlout, " \n"); + fprintf(xmlout, " %d\n", cp->tdx); + fprintf(xmlout, " %d\n", cp->tdy); + if(notes) + fprintf(xmlout, " \n"); + fprintf(xmlout, " %d\n", cp->tx0); + fprintf(xmlout, " %d\n", cp->ty0); + if(notes) + fprintf(xmlout, " \n"); + fprintf(xmlout, " %d\n", img->numcomps); + if(notes) { + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + //fprintf(xmlout," \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } + + for (i = 0; i < img->numcomps; i++) {/* image-components */ + comp = &(img->comps[i]); + fprintf(xmlout, " \n", i+1); + fprintf(xmlout, " \n"); + if(raw) + fprintf(xmlout," 0x%02x\n", (comp->sgnd << 7) & (comp->prec - 1)); + if(derived) { + fprintf(xmlout," %d\n", comp->sgnd); + fprintf(xmlout," %d\n", comp->prec); + } + fprintf(xmlout, " \n"); + fprintf(xmlout, " %d\n", comp->dx); + fprintf(xmlout, " %d\n", comp->dy); + fprintf(xmlout, " %d\n", comp->w); + fprintf(xmlout, " %d\n", comp->h); + /* Rest of these aren't calculated when SIZ is read: + fprintf(xmlout, " %d\n", comp->x0); + fprintf(xmlout, " %d\n", comp->y0); + if(notes) + fprintf(xmlout," \n"); + fprintf(xmlout, " %d\n", comp->bpp); + fprintf(xmlout, " %d\n", comp->resno_decoded); */ + // SUPPRESS: n/a to mj2_to_metadata. fprintf(xmlout," %dfactor); + /* factor = number of division by 2 of the out image compare to the original size of image */ + // TO DO comp->data: int *data; /* image-component data */ + + fprintf(xmlout, " \n"); + } + fprintf(xmlout, " \n"); +} + +/* ------------- */ + +void xml_out_frame_cod(FILE* xmlout, opj_tcp_t *tcp) +{ +/* Could be called with tcp = &j2k_default_tcp; +/* Or, for tile-part header, with &j2k_cp->tcps[j2k_curtileno] +/* Alignment for main:" < < < < To help maintain xml pretty-printing */ +/* Alignment for tile:" < < < To help maintain xml pretty-printing */ + opj_tccp_t *tccp; + int i; + char spaces[13] = " "; /* 12 spaces if tilepart*/ + char* s = spaces; + if(tcp == j2k_default_tcp) { + s++;s++; /* shorten s to 10 spaces if main */ + } + tccp = &(tcp->tccps[0]); + + fprintf(xmlout, "%s\n",s); /* Required in main header */ + /* Not retained or of interest: Lcod */ + fprintf(xmlout, "%s 0x%02x\n", s, tcp->csty); /* 1 byte */ + if(notes) { + fprintf(xmlout, "%s \n",s); + fprintf(xmlout, "%s \n",s); + fprintf(xmlout, "%s \n",s); + fprintf(xmlout, "%s \n",s); + fprintf(xmlout, "%s \n",s); + } + fprintf(xmlout, "%s \n",s); + fprintf(xmlout, "%s %d\n", s, tcp->prg); /* 1 byte, SGcod (A) */ + if(notes) { + fprintf(xmlout, "%s \n",s); + fprintf(xmlout, "%s \n",s); + fprintf(xmlout, "%s \n",s); + } + fprintf(xmlout, "%s %d\n", s, tcp->numlayers); /* 2 bytes, SGcod (B) */ + fprintf(xmlout, "%s %d\n", s, tcp->mct); /* 1 byte, SGcod (C). More or less boolean */ + if(notes) + fprintf(xmlout, "%s \n",s); + fprintf(xmlout, "%s \n",s); + /* This code will compile only if declaration of j2k_default_tcp is changed from static (to implicit extern) in j2k.c */ + fprintf(xmlout, "%s \n",s); + /* Internal data structure tccp defines separate defaults for each component, but they all get the same values */ + /* So we only have to report the first component's values here. */ + /* Compare j2k_read_cox(...) */ + fprintf(xmlout, "%s %d\n", s, tccp->numresolutions - 1); /* 1 byte, SPcox (D) */ + fprintf(xmlout, "%s %d\n", s, tccp->cblkw - 2); /* 1 byte, SPcox (E) */ + fprintf(xmlout, "%s %d\n", s, tccp->cblkh - 2); /* 1 byte, SPcox (F) */ + if(notes) { + fprintf(xmlout, "%s \n",s); + fprintf(xmlout, "%s \n", s); + } + fprintf(xmlout, "%s 0x%02x\n", s, tccp->cblksty); /* 1 byte, SPcox (G) */ + if(notes) { + fprintf(xmlout, "%s \n",s); + fprintf(xmlout, "%s \n",s); + fprintf(xmlout, "%s \n",s); + fprintf(xmlout, "%s \n",s); + fprintf(xmlout, "%s \n",s); + fprintf(xmlout, "%s \n",s); + fprintf(xmlout, "%s \n",s); + } + fprintf(xmlout, "%s %d\n", s, tccp->qmfbid); /* 1 byte, SPcox (H) */ + if(notes) + fprintf(xmlout, "%s \n",s); + if (tccp->csty & J2K_CP_CSTY_PRT) { + fprintf(xmlout, "%s \n",s); /* 1 byte, SPcox (I_i) */ + if(notes) + fprintf(xmlout, "%s \n",s); + for (i = 0; i < tccp->numresolutions; i++) { + fprintf(xmlout, "%s \n", s, i); + if(raw) + fprintf(xmlout,"%s 0x%02x\n", s, (tccp->prch[i] << 4) | tccp->prcw[i]); /* packed into 1 byte, SPcox (G) */ + if(derived) { + fprintf(xmlout,"%s %d\n", s, tccp->prcw[i]); + fprintf(xmlout,"%s %d\n", s, tccp->prch[i]); + } + fprintf(xmlout, "%s \n", s, i); + } + fprintf(xmlout, "%s \n",s); /* 1 byte, SPcox (I_i) */ + } + fprintf(xmlout, "%s \n",s); + fprintf(xmlout, "%s\n",s); +} + +/* ------------- */ + +void xml_out_frame_coc(FILE* xmlout, opj_tcp_t *tcp, int numcomps) /* Optional in main & tile-part headers */ +{ +/* Uses global j2k_default_tcp */ + opj_tccp_t *tccp, *firstcomp_tccp; + int i, compno; + char spaces[13] = " "; /* 12 spaces if tilepart*/ + char* s = spaces; + if(tcp == j2k_default_tcp) { + s++;s++; /* shorten s to 10 spaces if main */ + } + + firstcomp_tccp = &(tcp->tccps[0]); + /* Internal data structure tccp defines separate defaults for each component, set from main */ + /* default, then selectively overwritten. */ + /* Compare j2k_read_cox(...) */ + /* We don't really know which was the default, and which were not */ + /* Let's pretend that [0] is the default and all others are not */ + if(notes) { + fprintf(xmlout, "%s\n", s); + if(tcp == j2k_default_tcp) + fprintf(xmlout, "%s\n", s); + else + fprintf(xmlout, "%s\n", s); + } + for (compno = 1; compno < numcomps; compno++) /* spec says components are zero-based */ + { + tccp = &tcp->tccps[compno]; + if(same_component_style(firstcomp_tccp, tccp)) + continue; + +/* Alignments: " < < < < < To help maintain xml pretty-printing */ + fprintf(xmlout, "%s\n", s); /* Optional in main header, at most 1 per component */ + if(notes) + fprintf(xmlout, "%s \n", s); + /* Overrides the main COD for the specific component */ + /* Not retained or of interest: Lcod */ + fprintf(xmlout, "%s 0x%02x\n", s, tccp->csty); /* 1 byte */ + if(notes) { + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + } + fprintf(xmlout, "%s %d\n", s, compno); /* 1 or 2 bytes */ + /* Unfortunately compo isn't retained in j2k_read_coc: compno = cio_read(j2k_img->numcomps <= 256 ? 1 : 2); /* Ccoc */ + /*if(j2k_img_numcomps <=256) + component is 1 byte + else + compno is 2 byte */ + + /* This code will compile only if declaration of j2k_default_tcp is changed from static (to implicit extern) in j2k.c */ + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s %d\n", s, tccp->numresolutions - 1); /* 1 byte, SPcox (D) */ + fprintf(xmlout, "%s %d\n", s, tccp->cblkw - 2); /* 1 byte, SPcox (E) */ + fprintf(xmlout, "%s %d\n", s, tccp->cblkh - 2); /* 1 byte, SPcox (F) */ + if(notes) { + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + } + fprintf(xmlout, "%s 0x%02x\n", s, tccp->cblksty); /* 1 byte, SPcox (G) */ + if(notes) { + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + } + fprintf(xmlout, "%s %d\n", s, tccp->qmfbid); /* 1 byte, SPcox (H) */ + if(notes) + fprintf(xmlout, "%s \n", s); + if (tccp->csty & J2K_CP_CSTY_PRT) { + fprintf(xmlout, "%s \n", s); /* 1 byte, SPcox (I_i) */ + if(notes) + fprintf(xmlout, "%s \n", s); + for (i = 0; i < tccp->numresolutions-1; i++) { /* subtract 1 to get # of decomposition levels */ + fprintf(xmlout, "%s \n", s, i); + if(raw) + fprintf(xmlout,"%s 0x%02x\n", s, (tccp->prch[i] << 4) | tccp->prcw[i]); /* packed into 1 byte, SPcox (G) */ + if(derived) { + fprintf(xmlout,"%s %d\n", s, tccp->prcw[i]); + fprintf(xmlout,"%s %d\n", s, tccp->prch[i]); + } + fprintf(xmlout, "%s \n", s, i); + } + fprintf(xmlout, "%s \n", s); /* 1 byte, SPcox (I_i) */ + } + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s\n", s); + } +} + +/* ------------- */ + +BOOL same_component_style(opj_tccp_t *tccp1, opj_tccp_t *tccp2) +{ + int i; + + if(tccp1->numresolutions != tccp2->numresolutions) + return FALSE; + if(tccp1->cblkw != tccp2->cblkw) + return FALSE; + if(tccp1->cblkh != tccp2->cblkh) + return FALSE; + if(tccp1->cblksty != tccp2->cblksty) + return FALSE; + if(tccp1->csty != tccp2->csty) + return FALSE; + + if (tccp1->csty & J2K_CP_CSTY_PRT) { + for (i = 0; i < tccp1->numresolutions; i++) { + if(tccp1->prcw[i] != tccp2->prcw[i] || tccp1->prch[i] != tccp2->prch[i]) + return FALSE; + } + } + return TRUE; +} + +/* ------------- */ + +void xml_out_frame_qcd(FILE* xmlout, opj_tcp_t *tcp) +{ + /* This code will compile only if declaration of j2k_default_tcp is changed from static (to implicit extern) in j2k.c */ + opj_tccp_t *tccp; + int bandno, numbands; + char spaces[13] = " "; /* 12 spaces if tilepart*/ + char* s = spaces; + if(tcp == j2k_default_tcp) { + s++;s++; /* shorten s to 10 spaces if main */ + } + + /* Compare j2k_read_qcx */ + fprintf(xmlout, "%s\n", s); /* Required in main header, single occurrence */ + tccp = &(tcp->tccps[0]); + /* Not retained or of interest: Lqcd */ + fprintf(xmlout, "%s \n", s); /* 1 byte */ + if(notes) + fprintf(xmlout, "%s \n", s); + if(raw) + fprintf(xmlout, "%s 0x%02x\n", s, (tccp->numgbits) << 5 | tccp->qntsty); + if(derived) + fprintf(xmlout, "%s %d\n", s, tccp->qntsty); + if(notes) { + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + } + if(derived) + fprintf(xmlout, "%s %d\n", s, tccp->numgbits); + if(notes) + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + + /* Problem: numbands in some cases is calculated from len, which is not retained or available here at this time */ + /* So we'll just dump all internal values */ + /* We could calculate it, but I'm having trouble believing the length equations in the standard */ + + fprintf(xmlout, "%s \n", s); + switch(tccp->qntsty) { + case J2K_CCP_QNTSTY_NOQNT: /* no quantization */ + /* This is what standard says, but I don't believe it: len = 4 + (3*decomp); */ + numbands = J2K_MAXBANDS; /* should be: numbands = len - 1; */ + /* Better: IMAGINE numbands = tccp->stepsize_numbands; */ + /* Instead look for first zero exponent, quit there. Adequate? */ + fprintf(xmlout, "%s \n", s); + if(notes) { + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + } + for (bandno = 0; bandno < numbands; bandno++) { + if(tccp->stepsizes[bandno].expn == 0) + break; /* Remove when we have real numbands */ + fprintf(xmlout, "%s \n", s, bandno); + if(raw) + fprintf(xmlout,"%s 0x%02x\n", s, tccp->stepsizes[bandno].expn << 3); + if(derived) + fprintf(xmlout,"%s %d\n", s, tccp->stepsizes[bandno].expn); + fprintf(xmlout, "%s \n", s); + } + fprintf(xmlout, "%s \n", s); + break; + case J2K_CCP_QNTSTY_SIQNT: /* scalar quantization derived */ + /* This is what standard says. Should I believe it:: len = 5; + /* numbands = 1; */ + fprintf(xmlout, "%s \n", s); + if(notes) + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + if(notes) + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + } + + for (bandno = 1; bandno < J2K_MAXBANDS; bandno++) { + if(tccp->stepsizes[bandno].expn == 0) + break; + + fprintf(xmlout, "%s %d\n", s, bandno, tccp->stepsizes[bandno].expn); + } + + fprintf(xmlout, "%s \n", s); + break; + + default: /* J2K_CCP_QNTSTY_SEQNT */ /* scalar quantization expounded */ + /* This is what standard says, but should I believe it: len = 5 + 6*decomp; */ + numbands = J2K_MAXBANDS; /* should be: (len - 1) / 2;*/ + /* Better: IMAGINE numbands = tccp->stepsize_numbands; */ + fprintf(xmlout, "%s \n", s); + if(notes) { + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + } + for (bandno = 0; bandno < numbands; bandno++) { + if(tccp->stepsizes[bandno].expn == 0 && tccp->stepsizes[bandno].mant == 0) + break; /* Remove when we have real numbands */ + + fprintf(xmlout, "%s \n", s, bandno); + if(raw) + fprintf(xmlout,"%s 0x%02x\n", s, (tccp->stepsizes[bandno].expn << 11) | tccp->stepsizes[bandno].mant); + if(derived) { + fprintf(xmlout,"%s %d\n", s, tccp->stepsizes[bandno].expn); + fprintf(xmlout,"%s %d\n", s, tccp->stepsizes[bandno].mant); + } + fprintf(xmlout, "%s \n", s); + } + fprintf(xmlout, "%s \n", s); + break; + } /* switch */ + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s\n", s); + +/* Alignments: " < < < < < To help maintain xml pretty-printing */ +} + +/* ------------- */ + +void xml_out_frame_qcc(FILE* xmlout, opj_tcp_t *tcp, int numcomps) +{ +/* Uses global j2k_default_tcp */ + /* This code will compile only if declaration of j2k_default_tcp is changed from static (to implicit extern) in j2k.c */ + opj_tccp_t *tccp, *firstcomp_tccp; + int bandno, numbands; + int compno; + char spaces[13] = " "; /* 12 spaces if tilepart*/ + char* s = spaces; + if(tcp == j2k_default_tcp) { + s++;s++; /* shorten s to 10 spaces if main */ + } + + firstcomp_tccp = &(tcp->tccps[0]); + /* Internal data structure tccp defines separate defaults for each component, set from main */ + /* default, then selectively overwritten. */ + /* Compare j2k_read_qcx(...) */ + /* We don't really know which was the default, and which were not */ + /* Let's pretend that [0] is the default and all others are not */ + if(notes) { + fprintf(xmlout, "%s\n", s); + if(tcp == j2k_default_tcp) + fprintf(xmlout, "%s\n", s); + else + fprintf(xmlout, "%s\n", s); + } + for (compno = 1; compno < numcomps; compno++) /* spec says components are zero-based */ + { + tccp = &(tcp->tccps[compno]); + if(same_component_quantization(firstcomp_tccp, tccp)) + continue; + + /* Compare j2k_read_qcx */ + fprintf(xmlout, "%s\n", s, compno); /* Required in main header, single occurrence */ + tccp = &j2k_default_tcp->tccps[0]; + /* Not retained or perhaps of interest: Lqcd It maybe can be calculated. */ + fprintf(xmlout, "%s \n", s); /* 1 byte */ + if(notes) + fprintf(xmlout, "%s \n", s); + if(raw) + fprintf(xmlout, "%s 0x%02x\n", s, (tccp->numgbits) << 5 | tccp->qntsty); + if(derived) + fprintf(xmlout, "%s %d\n", s, tccp->qntsty); + if(notes) { + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + } + if(derived) + fprintf(xmlout, "%s %d\n", s, tccp->numgbits); + if(notes) + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + + /* Problem: numbands in some cases is calculated from len, which is not retained or available here at this time */ + /* So we'll just dump all internal values */ + fprintf(xmlout, "%s \n", s); + switch(tccp->qntsty) { + case J2K_CCP_QNTSTY_NOQNT: + numbands = J2K_MAXBANDS; /* should be: numbands = len - 1; */ + /* Better: IMAGINE numbands = tccp->stepsize_numbands; */ + + /* Instead look for first zero exponent, quit there. Adequate? */ + fprintf(xmlout, "%s \n", s); + if(notes) { + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + } + for (bandno = 0; bandno < numbands; bandno++) { + if(tccp->stepsizes[bandno].expn == 0) + break; /* Remove this once we have real numbands */ + fprintf(xmlout, "%s \n", s, bandno); + if(raw) + fprintf(xmlout,"%s 0x%02x\n", s, tccp->stepsizes[bandno].expn << 3); + if(derived) + fprintf(xmlout,"%s %d\n", s, tccp->stepsizes[bandno].expn); + fprintf(xmlout, "%s \n", s); + } + fprintf(xmlout, "%s \n", s); + break; + case J2K_CCP_QNTSTY_SIQNT: + /* numbands = 1; */ + fprintf(xmlout, "%s \n", s); + if(notes) + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + if(notes) + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + } + + for (bandno = 1; bandno < J2K_MAXBANDS; bandno++) { + if(tccp->stepsizes[bandno].expn == 0) + break; + + fprintf(xmlout, "%s %d\n", s, bandno, tccp->stepsizes[bandno].expn); + } + fprintf(xmlout, "%s \n", s); + break; + + default: /* J2K_CCP_QNTSTY_SEQNT */ + numbands = J2K_MAXBANDS; /* should be: (len - 1) / 2;*/ + /* Better: IMAGINE numbands = tccp->stepsize_numbands; */ + fprintf(xmlout, "%s \n", s); + if(notes) { + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + } + for (bandno = 0; bandno < numbands; bandno++) { + if(tccp->stepsizes[bandno].expn == 0 && tccp->stepsizes[bandno].mant == 0) + break; /* Remove this once we have real numbands count */ + fprintf(xmlout, "%s \n", s, bandno); + if(raw) + fprintf(xmlout,"%s 0x%02x\n", s, (tccp->stepsizes[bandno].expn << 11) | tccp->stepsizes[bandno].mant); + if(derived) { + fprintf(xmlout,"%s %d\n", s, tccp->stepsizes[bandno].expn); + fprintf(xmlout,"%s %d\n", s, tccp->stepsizes[bandno].mant); + } + fprintf(xmlout, "%s \n", s); + } + fprintf(xmlout, "%s \n", s); + break; + } /* switch */ + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s\n", s); + } +/* Alignments: " < < < < < To help maintain xml pretty-printing */ +} + +/* ------------- */ + +BOOL same_component_quantization(opj_tccp_t *tccp1, opj_tccp_t *tccp2) +{ + int bandno, numbands; + + if(tccp1->qntsty != tccp2->qntsty) + return FALSE; + if(tccp1->numgbits != tccp2->numgbits) + return FALSE; + + switch(tccp1->qntsty) { + case J2K_CCP_QNTSTY_NOQNT: + numbands = J2K_MAXBANDS; /* should be: numbands = len - 1; */ + /* Instead look for first zero exponent, quit there. Adequate? */ + for (bandno = 0; bandno < numbands; bandno++) { + if(tccp1->stepsizes[bandno].expn == 0) + break; + if(tccp1->stepsizes[bandno].expn != tccp2->stepsizes[bandno].expn) + return FALSE; + } + break; + case J2K_CCP_QNTSTY_SIQNT: + /* numbands = 1; */ + if(tccp1->stepsizes[0].expn != tccp2->stepsizes[0].expn || tccp1->stepsizes[0].mant != tccp2->stepsizes[0].mant) + return FALSE; + /* Don't need to check remainder, since they are calculated from [0] */ + break; + + default: /* J2K_CCP_QNTSTY_SEQNT */ + numbands = J2K_MAXBANDS; /* should be: (len - 1) / 2;*/ + /* This comparison may cause us problems with trailing junk values. */ + for (bandno = 0; bandno < numbands; bandno++) { + if(tccp1->stepsizes[bandno].expn != tccp2->stepsizes[bandno].expn || tccp1->stepsizes[bandno].mant != tccp2->stepsizes[bandno].mant); + return FALSE; + } + break; + } /* switch */ + return TRUE; +} + +/* ------------- */ + +void xml_out_frame_rgn(FILE* xmlout, opj_tcp_t *tcp, int numcomps) +{ + int compno, SPrgn; + /* MJ2 files can have regions of interest if hybridized with JPX Part II */ + char spaces[13] = " "; /* 12 spaces if tilepart*/ + char* s = spaces; + if(tcp == j2k_default_tcp) { + s++;s++; /* shorten s to 10 spaces if main */ + } + + for(compno = 0; compno < numcomps; compno++) { + SPrgn = tcp->tccps[compno].roishift; /* 1 byte; SPrgn */ + if(SPrgn == 0) + continue; /* Yet another kludge */ + + fprintf(xmlout, "%s\n", s); /* Optional in main header, at most 1 per component */ + if(notes) + fprintf(xmlout, "%s\n", s); + /* Not retained or of interest: Lrgd */ + fprintf(xmlout, "%s 0\n", s); /* 1 byte */ + if(notes) + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s %d\n", s, compno); /* 1 or 2 bytes */ + fprintf(xmlout, "%s %d\n", s, SPrgn); /* 1 byte */ + if(notes) + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "POC != 1) + return; /* Not present */ + + fprintf(xmlout, "%s\n", s); /* Optional in main header, at most 1 per component */ + /* j2k_read_poc seems to allow accumulation of default pocs from multiple POC segments, but does + the spec really allow that? */ + /* 2 bytes, not retained; Lpoc */ + /* I probably didn't get this dump precisely right. */ + for (i = 0; i < tcp->numpocs; i++) { + poc = &tcp->pocs[i]; + fprintf(xmlout, "%s \n", s, i+1); + fprintf(xmlout, "%S %d\n", s, poc->resno0); /* 1 byte, RSpoc_i */ + if(notes) + fprintf(xmlout,"%s \n", s); + fprintf(xmlout, "%s %d\n", s, poc->compno0);/* j2k_img->numcomps <= 256 ? 1 byte : 2 bytes; CSpoc_i */ + if(notes) + fprintf(xmlout,"%s \n", s); + fprintf(xmlout, "%s %d\n", s, poc->layno1); /* int_min(cio_read(2), tcp->numlayers); /* 2 bytes; LYEpoc_i */ + if(notes) + fprintf(xmlout,"%s \n", s); + fprintf(xmlout, "%s %d\n", s, poc->resno1); /*int_min(cio_read(1), tccp->numresolutions); /* REpoc_i */ + if(notes) + fprintf(xmlout,"%s \n", s); + fprintf(xmlout, "%s %d\n", s, poc->compno1); /* int_min(cio_read(j2k_img->numcomps <= 256 ? 1 : 2), j2k_img->numcomps); /* CEpoc_i */ + if(notes) + fprintf(xmlout,"%s \n", s); + fprintf(xmlout, "%s %d\n", s, poc->prg); /* 1 byte Ppoc_i */ + if(notes) { + fprintf(xmlout,"%s \n", s); + fprintf(xmlout,"%s \n", s); + fprintf(xmlout,"%s \n", s); + } + fprintf(xmlout, "%s \n", s); + } + fprintf(xmlout, "%sppm != 1) + return; /* Not present */ +/* Main header uses indent of 10 spaces */ + fprintf(xmlout, " \n"); /* Optional in main header, but if not, must be in PPT or codestream */ + /* 2 bytes Lppm not saved */ + if(notes) { + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } + + /* 1 byte, not retained ; Zppm is sequence # of this PPM header */ + /* 4 bytes, possibly overwritten multiple times in j2k_cp->ppm_previous: Nppm */ + /* Use j symbol for index instead of i, to make comparable with j2k_read_ppm */ + /* Not real clear whether to use ppm->store or ppm_len as upper bound */ + fprintf(xmlout, " \n"); + xml_out_dump_hex(xmlout, cp->ppm_data, cp->ppm_len); + /* Dump packet headers 1 byte at a time: lppm[i][j] */ + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); /* Optional in main header, but if not, must be in PPT or codestream */ +} + +/* ------------- */ + +void xml_out_frame_ppt(FILE *xmlout, opj_tcp_t *tcp) { /* For tile-part header, not main (which uses PPM instead). */ +/* Either the PPM or PPT is required if the packet headers are not distributed in the bit stream */ +/* Use of PPM and PPT are mutually exclusive. */ +/* Compare j2k_read_ppt() */ + int j; + + if(tcp->ppt != 1) + return; /* Not present */ + + /* Tile-part indents are 12 spaces */ + fprintf(xmlout, " \n"); /* Optional in main header, but if not, must be in PPT or codestream */ + /* 2 bytes Lppm not saved */ + if(notes) { + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } + + /* 1 byte, not retained ; Zppt is sequence # of this PPT header */ + /* 4 bytes, possibly overwritten multiple times in j2k_cp->ppt_previous: Nppt */ + /* Use j symbol for index instead of i, to make comparable with j2k_read_ppt */ + /* Not real clear whether to use ppt->store or ppt_len as upper bound */ + fprintf(xmlout, " \n"); + xml_out_dump_hex(xmlout, tcp->ppt_data, tcp->ppt_len); + /* Dump packet headers 1 byte at a time: lppt[i][j] */ + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); /* Optional in tile-part header, but if not, must be in PPM or codestream */ +} +#endif SUPPRESS_FOR_NOW + +/* ------------- */ + +void xml_out_frame_tlm(FILE* xmlout) { /* opt, main header only. May be multiple. */ +/* Compare j2k_read_tlm()... which doesn't retain anything! */ +/* Plan: Since this is only called from main header, not tilepart, use global j2k_default_tcp rather than parameter */ +/* Main header indents are 10 spaces */ +} + +/* ------------- */ + +void xml_out_frame_plm(FILE* xmlout) { /* opt, main header only; can be used in conjunction with tile-part's PLT */ +/* NO-OP. PLM NOT SAVED IN DATA STRUCTURE */ + /* Compare j2k_read_plm()... which doesn't retain anything! */ +/* Plan: Since this is only called from main header, not tilepart, use global j2k_default_tcp rather than parameter */ +/* Main header indents are 10 spaces */ +} + +/* ------------- */ + +void xml_out_frame_plt(FILE* xmlout, opj_tcp_t *tcp) { /* opt, tile-part headers only; can be used in conjunction with main header's PLM */ +/* NO-OP. PLT NOT SAVED IN DATA STRUCTURE */ + /* Compare j2k_read_plt()... which doesn't retain anything! */ +/* Tile-part header indents are 12 spaces */ +} + +/* ------------- */ + +void xml_out_frame_crg(FILE* xmlout) { /* NO-OP. CRG NOT SAVED IN DATA STRUCTURE */ /* opt, main header only; */ +/* Compare j2k_read_crg()... which doesn't retain anything! */ +/* Plan: Since this is only called from main header, not tilepart, use global j2k_default_tcp rather than parameter */ +#ifdef NOTYET + THIS PSEUDOCODE IMAGINES THESE EXIST: j2k_default_tcp->crg, j2k_default_tcp->crg_i, j2k_default_tcp->crg_xcrg*, j2k_default_tcp->crg_ycrg* + (POSSIBLY DON'T NEED crg_i, CAN GET NUMBER OR COMPONENTS FROM ELSEWHERE) + if(j2k_default_tcp->crg != 1 || j2k_default_tcp->crg_i == 0) + return; /* Not present */ + +/* Main header indents are 10 spaces */ + fprintf(xmlout, " \n", j2k_default_tcp->crg_i); + if(notes) { + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } + /* This isn't the most compact form of table, but is OK when number of components is small, as is likely. */ + for (i = 0; i < j2k_default_tcp->crg_i; i++) { + fprintf(xmlout, " \n", i+1); + fprintf(xmlout, " \n"); + if(raw) + fprintf(xmlout," %d\n", j2k_default_tcp->crg_xcrg[i]); + if(derived) { + /* Calculate n * 100%/65536; 4 digits after decimal point is sufficiently accurate */ + fprintf(xmlout," %.4f\n", ((double)j2k_default_tcp->crg_xcrg[i])/655.36); + /* We could do another calculation that include XRsiz[i]; maybe later. */ + } + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + if(raw) + fprintf(xmlout," %d\n", j2k_default_tcp->crg_ycrg[i]); + if(derived) { + fprintf(xmlout," %f\n", ((double)j2k_default_tcp->crg_ycrg[i])/655.36); + } + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } + + fprintf(xmlout, " \n"); + +#endif +} + +/* ------------- */ + +/* Regrettably from a metadata point of view, j2k_read_com() skips over any comments in main header or tile-part-header */ +void xml_out_frame_com(FILE* xmlout, opj_tcp_t *tcp) { /* NO-OP. COM NOT SAVED IN DATA STRUCTURE */ /* opt in main or tile-part headers; */ +/* Compare j2k_read_com()... which doesn't retain anything! */ +#ifdef NOTYET + char spaces[13] = " "; /* 12 spaces if tilepart*/ + char* s = spaces; + if(tcp == &j2k_default_tcp) { + s++;s++; /* shorten s to 10 spaces if main */ + } + THIS PSEUDOCODE IMAGINES THESE EXIST: tcp->com, tcp->com_len, tcp->com_data array + if(tcp->com != 1) + return; /* Not present */ + + fprintf(xmlout, "%s\n", s); /* Optional in main or tile-part header */ + xml_out_dump_hex_and_ascii(tcp->com_data, tcp->com_len, s); + fprintf(xmlout, "%s\n", s); +#endif +} + +void xml_out_dump_hex(FILE* xmlout, char *data, int data_len, char* s) { + /* s is a string of spaces for indent */ + int i; + + /* This is called when raw is true, or there is no appropriate derived form */ + fprintf(xmlout, "%s\n", s); + fprintf(xmlout, "%s ", s); /* Inadequate for pretty printing */ + for (i = 0; i < data_len; i++) { /* Dump packet headers */ + fprintf(xmlout, "%02x", data[i]); + } + fprintf(xmlout, "%s\n", s); +} + +/* Define this as an even number: */ +#define BYTES_PER_DUMP_LINE 40 +/* Current total width for Hex and ASCII is : 11 spaces lead + (3 * BPDL) + 2 spaces + BPDL */ +void xml_out_dump_hex_and_ascii(FILE* xmlout, char *data, int data_len, char* s) { + /* s is a string of spaces for indent */ + int i,j; + + if(raw) + xml_out_dump_hex(xmlout, data, data_len, s); + + if(derived) { + fprintf(xmlout, "%s\n", s); + for (i = 0; i < data_len; ) { + fprintf(xmlout,"%s ", s); /* Additional leading space added in loop */ + /* First column: hex */ + for (j = 0; j < BYTES_PER_DUMP_LINE; j++) /* Dump bytes */ + fprintf(xmlout," %02x", data[i+j]); + /* Space between columns... */ fprintf(xmlout, " "); + /* Second column: ASCII */ + for (j = 0; j < BYTES_PER_DUMP_LINE; j++, i++) { + if(isprint((int)data[i]) && i < data_len) + fprintf(xmlout,"%c", data[i]); + else + fprintf(xmlout," "); + } + /* If we also wanted to output UCS-2 Unicode as a third column, then entire document + must use fwprintf. Forget about it for now. As it stands, if data is UCS-2 format but still + the ASCII set, then we'll be able to read every other byte as ASCII in column 2. If + data is UTF-8 format but still ASCII, then we'll be able to read every byte as ASCII + in column 2. */ + } + fprintf(xmlout, "%s\n", s); + } +} + + +/* ------------- */ + +void xml_out_frame_jp2h(FILE* xmlout, opj_jp2_t *jp2_struct) { /* JP2 Header */ +/* Compare jp2_read_jp2h(opj_jp2_t * jp2_struct) */ + int i; + + fprintf(xmlout, " \n"); + +/* Compare jp2_read_ihdr(jp2_struct)) */ + fprintf(xmlout, " \n"); + fprintf(xmlout, " %d\n", jp2_struct->h); /* 4 bytes */ + fprintf(xmlout, " %d\n", jp2_struct->w); /* 4 bytes */ + if(notes) + fprintf(xmlout, " \n"); + fprintf(xmlout, " %d\n", jp2_struct->numcomps); /* 2 bytes */ + if(notes) + fprintf(xmlout, " \n"); /* 2 bytes */ + fprintf(xmlout, " \n"); /* 1 byte */ + if(jp2_struct->bpc == 255) { + fprintf(xmlout, " 0x%02x\n", jp2_struct->bpc); /* 1 byte */ + if(notes) + fprintf(xmlout, " \n"); + } else { /* Not 0xff */ + if(raw) { + fprintf(xmlout, " 0x%02x\n", jp2_struct->bpc); /* 1 byte */ + if(notes) + fprintf(xmlout," \n"); + } + if(derived) { + fprintf(xmlout, " %d\n", jp2_struct->bpc & 0x7f); + fprintf(xmlout, " %d\n", jp2_struct->bpc >> 7); + } + } + fprintf(xmlout, " \n"); + fprintf(xmlout, " %d\n", jp2_struct->C); /* 1 byte */ + if(notes) + fprintf(xmlout, " \n"); /* 2 bytes */ + fprintf(xmlout, " %d\n", jp2_struct->UnkC); /* 1 byte */ + if(notes) + fprintf(xmlout, " \n"); /* 1 byte */ + fprintf(xmlout, " %d\n", jp2_struct->IPR); /* 1 byte */ + if(notes) + fprintf(xmlout, " \n"); /* 2 bytes */ + fprintf(xmlout, " \n"); + + if (jp2_struct->bpc == 255) + { + fprintf(xmlout, " \n"); + if(notes) + fprintf(xmlout, " \n"); + /* Bits per pixel varies with components */ + /* Compare jp2_read_bpcc(jp2_struct) */ + for (i = 0; i < (int)jp2_struct->numcomps; i++) { + if(raw) + fprintf(xmlout," 0x%02x\n", jp2_struct->comps[i].bpcc); /* 1 byte */ + if(derived) { + fprintf(xmlout," %d\n", (jp2_struct->comps[i].bpcc & 0x7f)+1); + fprintf(xmlout," %d\n", jp2_struct->comps[i].bpcc >> 7); + } + } + fprintf(xmlout, " \n"); + } + + /* Compare jp2_read_colr(jp2_struct) */ + fprintf(xmlout, " \n"); + fprintf(xmlout, " %d\n", jp2_struct->meth); /* 1 byte */ + if(notes) { + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } + fprintf(xmlout, " %d\n", jp2_struct->precedence); /* 1 byte */ + if(notes) + fprintf(xmlout, " \n"); + fprintf(xmlout, " %d\n", jp2_struct->approx); /* 1 byte */ + if(notes) + fprintf(xmlout, " \n"); + + if (jp2_struct->meth == 1) { + fprintf(xmlout, " %d\n", jp2_struct->enumcs); /* 4 bytes */ + if(notes) { + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } + } + else + if(notes) + fprintf(xmlout, " \n"); + /* only 1 byte is read and nothing stored */ + fprintf(xmlout, " \n"); + + /* TO DO? No OpenJPEG support. + Palette 'pclr' + ComponentMapping 'cmap' + ChannelDefinition 'cdef' + Resolution 'res' + */ + fprintf(xmlout, " \n"); +} +/* ------------- */ + +#ifdef NOTYET +IMAGE these use cp structure, extended... but we could use a new data structure instead +void xml_out_frame_jp2i(FILE* xmlout, opj_cp_t *cp) { + /* IntellectualProperty 'jp2i' (no restrictions on location) */ + int i; + IMAGE cp->jp2i, cp->jp2i_count, cp->jp2i_data (array of chars), cp->cp2i_len (array of ints) + if(cp->jp2i != 1) + return; /* Not present */ + + for(i = 0; i < cp->jp2i_count; i++) + { + fprintf(xmlout, " \n"); + /* I think this can be anything, including binary, so do a dump */ + /* Is it better to indent or not indent this content? Indent is better for reading, but + worse for cut/paste. */ + xml_out_dump_hex_and_ascii(xmlout, cp->jp2i_data[i], cp->jp2i_len[i]); + fprintf(xmlout, " \n"); + } +} + +void xml_out_frame_xml(FILE* xmlout, opj_cp_t *cp) { + /* XML 'xml\040' (0x786d6c20). Can appear multiply, before or after jp2c codestreams */ + IMAGE cp->xml, cp->xml_count, cp->xml_data (array of chars) + MAYBE WE DON'T NEED cp->xml_len (array of ints) IF WE ASSUME xml_data IS NULL-TERMINATED. + ASSUME ASSUME EACH LINE IS ENDED BY \n. + int i; + if(cp->xml != 1) + return; /* Not present */ + + for(i = 0; i < cp->xml_count; i++) + { + fprintf(xmlout, " \n", i+1); + /* Is it better to indent or not indent this content? Indent is better for reading, but + worse for cut/paste. Being lazy, didn't indent here. */ + fprintf(xmlout,cp->xml_data[i]); /* May be multiple lines */ /* Could check if this is well-formed */ + fprintf(xmlout, " \n"); + } +} + +void xml_out_frame_uuid(FILE* xmlout, opj_cp_t *cp) { + /* UUID 'uuid' (top level only) */ + /* Part I 1.7.2 says: may appear multiply in JP2 file, anywhere except before File Type box */ + /* Part III 5.2.1 says: Private extensions shall be achieved through the 'uuid' type. */ + /* A UUID is a 16-byte value. There is a conventional string representation for it: + "0x12345678-9ABC-DEF0-1234-567890ABCDEF". Let's assume that is what is stored in uuid_value */ + + /* Part III 6.1 Any other MJ2 box type could be alternatively written as a 'uuid' box, with value given + as : 0xXXXXXXXX-0011-0010-8000-00AA00389B71, where the Xs are the boxtype in hex. However, + such a file is "not compliant; systems may choose to read [such] objects ... as equivalent to the box of + the same type, or not." Here, we choose not to. */ + int i; + IMAGE cp->uuid, cp->uuid_count, cp->uuid_value (array of uuids... let's say fixed-length strings) cp->uuid_data (array of char buffers), cp->uuid_len (array of ints) + if(cp->juuid != 1) + return; /* Not present */ + + for(i = 0; i < cp->uuid_count; i++) + { + fprintf(xmlout, " + fprintf(xmlout, " %s\n", cp->uuid_value[i]); + fprintf(xmlout, " \n"); + /* I think this can be anything, including binary, so do a dump */ + /* Is it better to indent or not indent this content? Indent is better for reading, but + worse for cut/paste. */ + xml_out_dump_hex_and_ascii(xmlout, cp->uuid_data[i], cp->uuid_len[i]); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } +} + +void xml_out_frame_uinf(FILE* xmlout, opj_cp_t *cp) { + /* UUIDInfo 'uinf', includes UUIDList 'ulst' and URL 'url\40' */ + /* Part I 1.7.3 says: may appear multiply in JP2 file, anywhere at the top level except before File Type box */ + /* So there may be multiple ulst's, and each can have multiple UUIDs listed (with a single URL) */ + /* This is not quite as vendor-specific as UUIDs, or at least is meant to be generally readable */ + /* Assume UUIDs stored in canonical string format */ + int i, j; + IMAGE cp->uinf, cp->uinf_count, cp->uinf_ulst_nu (array of ints) + cp->uinf_uuid (2 dimensional array of uuids... let's say fixed-length strings), + cp->uinf_url (array of char buffers) + + if(cp->uinf != 1) + return; /* Not present */ + + for(i = 0; i < cp->uuid_count; i++) + { + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n",cp->cp->uinf_ulst_nu[i]); + for(j = 0; j < cp->uinf_ulst_nu[i]; j++) + fprintf(xmlout, " %s\n", cp->uuif_uuid[i][j], j+1); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + /* Could add VERS and FLAG here */ + fprintf(xmlout, " \n"); + fprintf(xmlout, " %s",cp->uinf_url[i]); /* Probably single line, so indent works */ /* In theory, could check if this is well-formed, or good live link */ + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } +} + +IMAGE these use cp structure, extended... but we could use a new data structure instead +void xml_out_frame_unknown_type(FILE* xmlout, opj_cp_t *cp) { + /* Part III 5.2.1 says "Type fields not defined here are reserved. Private extensions + shall be acieved through the 'uuid' type." [This implies an unknown + type would be an error, but then...] "Boxes not explicitly defined in this standard, + or otherwise unrecognized by a reader, may be ignored." + Also, it says "the following types are not and will not be used, or used only in + their existing sense, in future versions of this specification, to avoid conflict + with existing content using earlier pre-standard versions of this format: + clip, crgn, matt, kmat, pnot, ctab, load, imap; + track reference types tmcd, chap, sync,scpt, ssrc" + [But good luck figuring out the mapping.] + Part III Amend. 2 4.1 is stronger: "All these specifications [of this family, e.g., + JP2 Part I, ISO Base format (Part 12) leading to MP4, Quicktime, and possibly including + MJ2] require that readers ignore objects that are unrecognizable to them". + */ + int i; + IMAGE cp->unknown_type, cp->unknown_type_count, cp->unknown_type_boxtype (array of buf[5]s), cp->unknown_type_data (array of chars), cp->unknown_type_len (array of ints) + if(cp->unknown_type != 1) + return; /* Not present */ + + for(i = 0; i < cp->unknown_type_count; i++) + { + fprintf(xmlout, " \n", cp->unknown_type_boxtype[i]); + /* Can be anything, including binary, so do a dump */ + /* Is it better to indent or not indent this content? Indent is better for reading, but + worse for cut/paste. */ + xml_out_dump_hex_and_ascii(xmlout, cp->unknown_type_data[i], cp->unknown_type_len[i]); + fprintf(xmlout, " \n"); + } +} + +#endif diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/mj2/meta_out.h b/gdcm/Utilities/gdcmopenjpeg-v2/mj2/meta_out.h new file mode 100644 index 0000000..be1965d --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/mj2/meta_out.h @@ -0,0 +1,12 @@ +/* meta_out.h */ +/* Dump MJ2, JP2 metadata (partial so far) to xml file */ +/* Callable from mj2_to_metadata */ +/* Contributed to Open JPEG by Glenn Pearson, U.S. National Library of Medicine */ + +#define BOOL int +#define FALSE 0 +#define TRUE 1 + +void xml_write_init(BOOL n, BOOL t, BOOL r, BOOL d); + +int xml_write_struct(FILE *file, FILE *xmlout, opj_mj2_t * movie, unsigned int sampleframe, char* stringDTD, opj_event_mgr_t *event_mgr); diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/mj2/mj2.c b/gdcm/Utilities/gdcmopenjpeg-v2/mj2/mj2.c new file mode 100644 index 0000000..8c39d15 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/mj2/mj2.c @@ -0,0 +1,2906 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2003-2007, Francois-Olivier Devaux + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "opj_includes.h" +#include "mj2.h" + +/** @defgroup JP2 JP2 - JPEG-2000 file format reader/writer */ +/*@{*/ + +/** @name Local static functions */ +/*@{*/ + +/** +Read box headers +@param cinfo Codec context info +@param cio Input stream +@param box +@return Returns true if successful, returns false otherwise +*/ +static bool jp2_read_boxhdr(opj_common_ptr cinfo, opj_cio_t *cio, opj_jp2_box_t *box); + +/* +* +* Read box headers +* +*/ + +int mj2_read_boxhdr(mj2_box_t * box, opj_cio_t *cio) +{ + box->init_pos = cio_tell(cio); + box->length = cio_read(cio, 4); + box->type = cio_read(cio, 4); + if (box->length == 1) { + if (cio_read(cio, 4) != 0) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Cannot handle box sizes higher than 2^32\n"); + return 1; + }; + box->length = cio_read(cio, 4); + if (box->length == 0) + box->length = cio_numbytesleft(cio) + 12; + } + else if (box->length == 0) { + box->length = cio_numbytesleft(cio) + 8; + } + return 0; +} + +/* +* +* Initialisation of a Standard Movie, given a simple movie structure defined by the user +* The movie will have one sample per chunk +* +* Arguments: opj_mj2_t * movie +* Several variables of "movie" must be defined in order to enable a correct execution of +* this function: +* - The number of tracks of each type (movie->num_vtk, movie->num_stk, movie->num_htk) +* - The memory for each must be allocated (movie->tk) +* - For each track: +* The track type (tk->track_type) +* The number of sample (tk->num_samples) +* The sample rate (tk->sample_rate) +* +*/ + +int mj2_init_stdmovie(opj_mj2_t * movie) +{ + int i; + unsigned int j; + time_t ltime; + + movie->brand = MJ2_MJ2; + movie->minversion = 0; + movie->num_cl = 2; + movie->cl = (unsigned int*) opj_malloc(movie->num_cl * sizeof(unsigned int)); + + movie->cl[0] = MJ2_MJ2; + movie->cl[1] = MJ2_MJ2S; + time(<ime); /* Time since 1/1/70 */ + movie->creation_time = (unsigned int) ltime + 2082844800; /* Seconds between 1/1/04 and 1/1/70 */ + movie->timescale = 1000; + + movie->rate = 1 << 16; /* Rate to play presentation (default = 0x00010000) */ + movie->volume = 1 << 8; /* Movie volume (default = 0x0100) */ + movie->trans_matrix[0] = 0x00010000; /* Transformation matrix for video */ + movie->trans_matrix[1] = 0; /* Unity is { 0x00010000,0,0,0,0x00010000,0,0,0,0x40000000 } */ + movie->trans_matrix[2] = 0; + movie->trans_matrix[3] = 0; + movie->trans_matrix[4] = 0x00010000; + movie->trans_matrix[5] = 0; + movie->trans_matrix[6] = 0; + movie->trans_matrix[7] = 0; + movie->trans_matrix[8] = 0x40000000; + movie->next_tk_id = 1; + + for (i = 0; i < movie->num_htk + movie->num_stk + movie->num_vtk; i++) { + mj2_tk_t *tk = &movie->tk[i]; + movie->next_tk_id++; + tk->jp2_struct.comps = NULL; + tk->jp2_struct.cl = NULL; + + if (tk->track_type == 0) { + if (tk->num_samples == 0) + return 1; + + tk->Dim[0] = 0; + tk->Dim[1] = 0; + + tk->timescale = 1000; /* Timescale = 1 ms */ + + tk->chunk[0].num_samples = 1; + tk->chunk[0].sample_descr_idx = 1; + + tk->same_sample_size = 0; + + tk->num_samplestochunk = 1; /* One sample per chunk */ + tk->sampletochunk = (mj2_sampletochunk_t*) opj_malloc(tk->num_samplestochunk * sizeof(mj2_sampletochunk_t)); + tk->sampletochunk[0].first_chunk = 1; + tk->sampletochunk[0].samples_per_chunk = 1; + tk->sampletochunk[0].sample_descr_idx = 1; + + if (tk->sample_rate == 0) { + opj_event_msg(tk->cinfo, EVT_ERROR, + "Error while initializing MJ2 movie: Sample rate of track %d must be different from zero\n", + tk->track_ID); + return 1; + } + + for (j = 0; j < tk->num_samples; j++) { + tk->sample[j].sample_delta = tk->timescale / tk->sample_rate; + } + + tk->num_tts = 1; + tk->tts = (mj2_tts_t*) opj_malloc(tk->num_tts * sizeof(mj2_tts_t)); + tk->tts[0].sample_count = tk->num_samples; + tk->tts[0].sample_delta = tk->timescale / tk->sample_rate; + + tk->horizresolution = 0x00480000; /* Horizontal resolution (typically 72) */ + tk->vertresolution = 0x00480000; /* Vertical resolution (typically 72) */ + tk->compressorname[0] = 0x0f4d6f74; /* Compressor Name[]: Motion JPEG2000 */ + tk->compressorname[1] = 0x696f6e20; + tk->compressorname[2] = 0x4a504547; + tk->compressorname[3] = 0x32303030; + tk->compressorname[4] = 0x00120000; + tk->compressorname[5] = 0; + tk->compressorname[6] = 0x00000042; + tk->compressorname[7] = 0x000000DC; + tk->num_url = 0; /* Number of URL */ + tk->num_urn = 0; /* Number of URN */ + tk->graphicsmode = 0; /* Graphicsmode */ + tk->opcolor[0] = 0; /* OpColor */ + tk->opcolor[1] = 0; /* OpColor */ + tk->opcolor[2] = 0; /* OpColor */ + tk->creation_time = movie->creation_time; /* Seconds between 1/1/04 and 1/1/70 */ + tk->language = 0; /* Language (undefined) */ + tk->layer = 0; + tk->volume = 1 << 8; /* Movie volume (default = 0x0100) */ + tk->trans_matrix[0] = 0x00010000; /* Transformation matrix for track */ + tk->trans_matrix[1] = 0; /* Unity is { 0x00010000,0,0,0,0x00010000,0,0,0,0x40000000 } */ + tk->trans_matrix[2] = 0; + tk->trans_matrix[3] = 0; + tk->trans_matrix[4] = 0x00010000; + tk->trans_matrix[5] = 0; + tk->trans_matrix[6] = 0; + tk->trans_matrix[7] = 0; + tk->trans_matrix[8] = 0x40000000; + tk->fieldcount = 1; + tk->fieldorder = 0; + tk->or_fieldcount = 1; + tk->or_fieldorder = 0; + tk->num_br = 2; + tk->br = (unsigned int*) opj_malloc(tk->num_br * sizeof(unsigned int)); + tk->br[0] = MJ2_JP2; + tk->br[1] = MJ2_J2P0; + tk->num_jp2x = 0; + tk->hsub = 2; /* 4:2:0 */ + tk->vsub = 2; /* 4:2:0 */ + tk->hoff = 0; + tk->voff = 0; + tk->visual_w = tk->w << 16; + tk->visual_h = tk->h << 16; + } + else { + tk->num_br = 0; + tk->jp2xdata = NULL; + } + } + return 0; +} + +/* +* Time To Sample box Decompact +* +*/ +void mj2_tts_decompact(mj2_tk_t * tk) +{ + int i, j; + tk->num_samples = 0; + for (i = 0; i < tk->num_tts; i++) { + tk->num_samples += tk->tts[i].sample_count; + } + + tk->sample = (mj2_sample_t*) opj_malloc(tk->num_samples * sizeof(mj2_sample_t)); + + for (i = 0; i < tk->num_tts; i++) { + for (j = 0; j < tk->tts[i].sample_count; j++) { + tk->sample[j].sample_delta = tk->tts[i].sample_delta; + } + } +} + +/* +* Sample To Chunk box Decompact +* +*/ +void mj2_stsc_decompact(mj2_tk_t * tk) +{ + int j, i; + unsigned int k; + int sampleno=0; + + if (tk->num_samplestochunk == 1) { + tk->num_chunks = + (unsigned int) ceil((double) tk->num_samples / + (double) tk->sampletochunk[0].samples_per_chunk); + tk->chunk = (mj2_chunk_t*) opj_malloc(tk->num_chunks * sizeof(mj2_chunk_t)); + for (k = 0; k < tk->num_chunks; k++) { + tk->chunk[k].num_samples = tk->sampletochunk[0].samples_per_chunk; + } + + } else { + tk->chunk = (mj2_chunk_t*) opj_malloc(tk->num_samples * sizeof(mj2_chunk_t)); + tk->num_chunks = 0; + for (i = 0; i < tk->num_samplestochunk -1 ; i++) { + for (j = tk->sampletochunk[i].first_chunk - 1; + j < tk->sampletochunk[i + 1].first_chunk - 1; j++) { + tk->chunk[j].num_samples = tk->sampletochunk[i].samples_per_chunk; + tk->num_chunks++; + sampleno += tk->chunk[j].num_samples; + } + } + tk->num_chunks += (int)(tk->num_samples - sampleno) / tk->sampletochunk[tk->num_samplestochunk - 1].samples_per_chunk; + for (k = tk->sampletochunk[tk->num_samplestochunk - 1].first_chunk - 1; + k < tk->num_chunks; k++) { + tk->chunk[k].num_samples = + tk->sampletochunk[tk->num_samplestochunk - 1].samples_per_chunk; + } + tk->chunk = opj_realloc(tk->chunk, tk->num_chunks * sizeof(mj2_chunk_t)); + } + +} + + +/* +* Chunk offset box Decompact +* +*/ +void mj2_stco_decompact(mj2_tk_t * tk) +{ + int j; + unsigned int i; + int k = 0; + int intra_chunk_offset; + + for (i = 0; i < tk->num_chunks; i++) { + intra_chunk_offset = 0; + for (j = 0; j < tk->chunk[i].num_samples; j++) { + tk->sample[k].offset = intra_chunk_offset + tk->chunk[i].offset; + intra_chunk_offset += tk->sample[k].sample_size; + k++; + } + } +} + +/* +* Write the JP box +* +* JP Signature box +* +*/ +void mj2_write_jp(opj_cio_t *cio) +{ + mj2_box_t box; + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + + cio_write(cio, MJ2_JP, 4); /* JP */ + cio_write(cio, 0x0d0a870a, 4); /* 0x0d0a870a required in a JP box */ + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the JP box +* +* JPEG 2000 signature +* +*/ +int mj2_read_jp(opj_cio_t *cio) +{ + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); + if (MJ2_JP != box.type) { /* Check Marker */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected JP Marker\n"); + return 1; + } + if (0x0d0a870a != cio_read(cio, 4)) { /* read the 0x0d0a870a required in a JP box */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with JP Marker\n"); + return 1; + } + if (cio_tell(cio) - box.init_pos != box.length) { /* Check box length */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with JP Box size \n"); + return 1; + } + return 0; + +} + +/* +* Write the FTYP box +* +* File type box +* +*/ +void mj2_write_ftyp(opj_mj2_t * movie, opj_cio_t *cio) +{ + int i; + mj2_box_t box; + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + + cio_write(cio, MJ2_FTYP, 4); /* FTYP */ + cio_write(cio, movie->brand, 4); /* BR */ + cio_write(cio, movie->minversion, 4); /* MinV */ + + for (i = 0; i < movie->num_cl; i++) + cio_write(cio, movie->cl[i], 4); /* CL */ + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* Length */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the FTYP box +* +* File type box +* +*/ +int mj2_read_ftyp(opj_mj2_t * movie, opj_cio_t *cio) +{ + int i; + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); /* Box Size */ + if (MJ2_FTYP != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected FTYP Marker\n"); + return 1; + } + + movie->brand = cio_read(cio, 4); /* BR */ + movie->minversion = cio_read(cio, 4); /* MinV */ + movie->num_cl = (box.length - 16) / 4; + movie->cl = (unsigned int*) opj_malloc(movie->num_cl * sizeof(unsigned int)); + + for (i = movie->num_cl - 1; i > -1; i--) + movie->cl[i] = cio_read(cio, 4); /* CLi */ + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with FTYP Box\n"); + return 1; + } + return 0; +} + + +/* +* Write the STCO box +* +* Chunk Offset Box +* +*/ +void mj2_write_stco(mj2_tk_t * tk, opj_cio_t *cio) +{ + mj2_box_t box; + unsigned int i; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + cio_write(cio, MJ2_STCO, 4); /* STCO */ + + cio_write(cio, 0, 4); /* Version = 0, flags = 0 */ + + cio_write(cio, tk->num_chunks, 4); /* Entry Count */ + + for (i = 0; i < tk->num_chunks; i++) { + cio_write(cio, tk->chunk[i].offset, 4); /* Entry offset */ + } + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the STCO box +* +* Chunk Offset Box +* +*/ +int mj2_read_stco(mj2_tk_t * tk, opj_cio_t *cio) +{ + unsigned int i; + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); /* Box Size */ + if (MJ2_STCO != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected STCO Marker\n"); + return 1; + } + + if (0 != cio_read(cio, 1)) { /* Version = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Only Version 0 handled in STCO box\n"); + return 1; + } + + if (0 != cio_read(cio, 3)) { /* Flags = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with flag in STCO box. Expected flag 0\n"); + return 1; + } + + + if (cio_read(cio, 4) != tk->num_chunks) { + opj_event_msg(cio->cinfo, EVT_ERROR, + "Error in STCO box: expecting same amount of entry-count as chunks \n"); + } else { + for (i = 0; i < tk->num_chunks; i++) { + tk->chunk[i].offset = cio_read(cio, 4); /* Entry offset */ + } + } + + mj2_stco_decompact(tk); + + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with STCO Box size\n"); + return 1; + } + return 0; +} + +/* +* Write the STSZ box +* +* Sample size box +* +*/ +void mj2_write_stsz(mj2_tk_t * tk, opj_cio_t *cio) +{ + mj2_box_t box; + unsigned int i; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + cio_write(cio, MJ2_STSZ, 4); /* STSZ */ + + cio_write(cio, 0, 4); /* Version = 0, flags = 0 */ + + if (tk->same_sample_size == 1) { /* If they all have the same size */ + cio_write(cio, tk->sample[0].sample_size, 4); /* Size */ + + cio_write(cio, 1, 4); /* Entry count = 1 */ + } + + else { + cio_write(cio, 0, 4); /* Sample Size = 0 becase they all have different sizes */ + + cio_write(cio, tk->num_samples, 4); /* Sample Count */ + + for (i = 0; i < tk->num_samples; i++) { + cio_write(cio, tk->sample[i].sample_size, 4); + } + } + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the STSZ box +* +* Sample size box +* +*/ +int mj2_read_stsz(mj2_tk_t * tk, opj_cio_t *cio) +{ + int sample_size; + unsigned int i; + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); /* Box Size */ + if (MJ2_STSZ != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected STSZ Marker\n"); + return 1; + } + + + if (0 != cio_read(cio, 1)) { /* Version = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Only Version 0 handled in STSZ box\n"); + return 1; + } + + if (0 != cio_read(cio, 3)) { /* Flags = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with flag in STSZ box. Expected flag 0\n"); + return 1; + } + + sample_size = cio_read(cio, 4); + + if (sample_size != 0) { /* Samples do have the same size */ + tk->same_sample_size = 1; + for (i = 0; i < tk->num_samples; i++) { + tk->sample[i].sample_size = sample_size; + } + cio_skip(cio,4); /* Sample count = 1 */ + } else { + tk->same_sample_size = 0; + if (tk->num_samples != cio_read(cio, 4)) { /* Sample count */ + opj_event_msg(cio->cinfo, EVT_ERROR, + "Error in STSZ box. Expected that sample-count is number of samples in track\n"); + return 1; + } + for (i = 0; i < tk->num_samples; i++) { + tk->sample[i].sample_size = cio_read(cio, 4); /* Sample Size */ + } + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with STSZ Box size\n"); + return 1; + } + } + return 0; + +} + +/* +* Write the STSC box +* +* Sample to Chunk +* +*/ +void mj2_write_stsc(mj2_tk_t * tk, opj_cio_t *cio) +{ + int i; + mj2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + cio_write(cio, MJ2_STSC, 4); /* STSC */ + + cio_write(cio, 0, 4); /* Version = 0, flags = 0 */ + + cio_write(cio, tk->num_samplestochunk, 4); /* Entry Count */ + + for (i = 0; i < tk->num_samplestochunk; i++) { + cio_write(cio, tk->sampletochunk[i].first_chunk, 4); /* First Chunk */ + cio_write(cio, tk->sampletochunk[i].samples_per_chunk, 4); /* Samples per chunk */ + cio_write(cio, tk->sampletochunk[i].sample_descr_idx, 4); /* Samples description index */ + } + + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the STSC box +* +* Sample to Chunk +* +*/ +int mj2_read_stsc(mj2_tk_t * tk, opj_cio_t *cio) +{ + int i; + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); /* Box Size */ + if (MJ2_STSC != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected STSC Marker\n"); + return 1; + } + + + if (0 != cio_read(cio, 1)) { /* Version = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Only Version 0 handled in STSC box\n"); + return 1; + } + + if (0 != cio_read(cio, 3)) { /* Flags = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with flag in STSC box. Expected flag 0\n"); + return 1; + } + + tk->num_samplestochunk = cio_read(cio, 4); + + tk->sampletochunk = (mj2_sampletochunk_t*) opj_malloc(tk->num_samplestochunk * sizeof(mj2_sampletochunk_t)); + + for (i = 0; i < tk->num_samplestochunk; i++) { + tk->sampletochunk[i].first_chunk = cio_read(cio, 4); + tk->sampletochunk[i].samples_per_chunk = cio_read(cio, 4); + tk->sampletochunk[i].sample_descr_idx = cio_read(cio, 4); + } + + mj2_stsc_decompact(tk); /* decompact sample to chunk box */ + + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with STSC Box size\n"); + return 1; + } + return 0; +} + +/* +* Write the STTS box +* +* Time to Sample Box +* +*/ +void mj2_write_stts(mj2_tk_t * tk, opj_cio_t *cio) +{ + + int i; + mj2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + cio_write(cio, MJ2_STTS, 4); /* STTS */ + + cio_write(cio, 0, 4); /* Version = 0, flags = 0 */ + + cio_write(cio, tk->num_tts, 4); /* entry_count */ + for (i = 0; i < tk->num_tts; i++) { + cio_write(cio, tk->tts[i].sample_count, 4); /* Sample-count */ + cio_write(cio, tk->tts[i].sample_delta, 4); /* Sample-Delta */ + } + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the STTS box +* +* +* +*/ +int mj2_read_stts(mj2_tk_t * tk, opj_cio_t *cio) +{ + int i; + + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); + if (MJ2_STTS != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected STTS Marker\n"); + return 1; + } + + + if (0 != cio_read(cio, 1)) { /* Version = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Only Version 0 handled in STTS box\n"); + return 1; + } + + if (0 != cio_read(cio, 3)) { /* Flags = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with flag in STTS box. Expected flag 0\n"); + return 1; + } + + tk->num_tts = cio_read(cio, 4); + + tk->tts = (mj2_tts_t*) opj_malloc(tk->num_tts * sizeof(mj2_tts_t)); + + for (i = 0; i < tk->num_tts; i++) { + tk->tts[i].sample_count = cio_read(cio, 4); + tk->tts[i].sample_delta = cio_read(cio, 4); + } + + mj2_tts_decompact(tk); + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with STTS Box size\n"); + return 1; + } + return 0; +} + +/* +* Write the FIEL box +* +* Field coding Box +* +*/ +void mj2_write_fiel(mj2_tk_t * tk, opj_cio_t *cio) +{ + + mj2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + cio_write(cio, MJ2_FIEL, 4); /* STTS */ + + cio_write(cio, tk->fieldcount, 1); /* Field count */ + cio_write(cio, tk->fieldorder, 1); /* Field order */ + + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the FIEL box +* +* Field coding Box +* +*/ +int mj2_read_fiel(mj2_tk_t * tk, opj_cio_t *cio) +{ + + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); + if (MJ2_FIEL != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected FIEL Marker\n"); + return 1; + } + + + tk->fieldcount = cio_read(cio, 1); + tk->fieldorder = cio_read(cio, 1); + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with FIEL Box size\n"); + return 1; + } + return 0; +} + +/* +* Write the ORFO box +* +* Original Format Box +* +*/ +void mj2_write_orfo(mj2_tk_t * tk, opj_cio_t *cio) +{ + mj2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + cio_write(cio, MJ2_ORFO, 4); + + cio_write(cio, tk->or_fieldcount, 1); /* Original Field count */ + cio_write(cio, tk->or_fieldorder, 1); /* Original Field order */ + + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the ORFO box +* +* Original Format Box +* +*/ +int mj2_read_orfo(mj2_tk_t * tk, opj_cio_t *cio) +{ + + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); + if (MJ2_ORFO != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected ORFO Marker\n"); + return 1; + } + + + tk->or_fieldcount = cio_read(cio, 1); + tk->or_fieldorder = cio_read(cio, 1); + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with ORFO Box size\n"); + return 1; + } + return 0; +} + +/* +* Write the JP2P box +* +* MJP2 Profile Box +* +*/ +void mj2_write_jp2p(mj2_tk_t * tk, opj_cio_t *cio) +{ + + int i; + mj2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + cio_write(cio, MJ2_JP2P, 4); + + cio_write(cio, 0, 4); /* Version 0, flags =0 */ + + for (i = 0; i < tk->num_br; i++) { + cio_write(cio, tk->br[i], 4); + } + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the JP2P box +* +* MJP2 Profile Box +* +*/ +int mj2_read_jp2p(mj2_tk_t * tk, opj_cio_t *cio) +{ + int i; + + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); + if (MJ2_JP2P != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected JP2P Marker\n"); + return 1; + } + + if (0 != cio_read(cio, 1)) { /* Version = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Only Version 0 handled in JP2P box\n"); + return 1; + } + + if (0 != cio_read(cio, 3)) { /* Flags = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with flag in JP2P box. Expected flag 0\n"); + return 1; + } + + + tk->num_br = (box.length - 12) / 4; + tk->br = (unsigned int*) opj_malloc(tk->num_br * sizeof(unsigned int)); + + for (i = 0; i < tk->num_br; i++) { + tk->br[i] = cio_read(cio, 4); + } + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with JP2P Box size\n"); + return 1; + } + return 0; +} + +/* +* Write the JP2X box +* +* MJP2 Prefix Box +* +*/ +void mj2_write_jp2x(mj2_tk_t * tk, opj_cio_t *cio) +{ + + int i; + mj2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + cio_write(cio, MJ2_JP2X, 4); + + for (i = 0; i < tk->num_jp2x; i++) { + cio_write(cio, tk->jp2xdata[i], 1); + } + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the JP2X box +* +* MJP2 Prefix Box +* +*/ +int mj2_read_jp2x(mj2_tk_t * tk, opj_cio_t *cio) +{ + unsigned int i; + + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); + if (MJ2_JP2X != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected JP2X Marker\n"); + return 1; + } + + + tk->num_jp2x = (box.length - 8); + tk->jp2xdata = (unsigned char*) opj_malloc(tk->num_jp2x * sizeof(unsigned char)); + + for (i = 0; i < tk->num_jp2x; i++) { + tk->jp2xdata[i] = cio_read(cio, 1); + } + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with JP2X Box size\n"); + return 1; + } + return 0; +} + +/* +* Write the JSUB box +* +* MJP2 Subsampling Box +* +*/ +void mj2_write_jsub(mj2_tk_t * tk, opj_cio_t *cio) +{ + + mj2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + cio_write(cio, MJ2_JSUB, 4); + + cio_write(cio, tk->hsub, 1); + cio_write(cio, tk->vsub, 1); + cio_write(cio, tk->hoff, 1); + cio_write(cio, tk->voff, 1); + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the JSUB box +* +* MJP2 Subsampling Box +* +*/ +int mj2_read_jsub(mj2_tk_t * tk, opj_cio_t *cio) +{ + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); + if (MJ2_JSUB != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected JSUB Marker\n"); + return 1; + } + + tk->hsub = cio_read(cio, 1); + tk->vsub = cio_read(cio, 1); + tk->hoff = cio_read(cio, 1);; + tk->voff = cio_read(cio, 1); + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with JSUB Box size\n"); + return 1; + } + return 0; +} + +/* +* Write the SMJ2 box +* +* Visual Sample Entry Description +* +*/ +void mj2_write_smj2(mj2_tk_t * tk, opj_cio_t *cio) +{ + mj2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + cio_write(cio, MJ2_MJ2, 4); /* MJ2 */ + + cio_write(cio, 0, 4); /* Version = 0, flags = 0 */ + + cio_write(cio, 1, 4); + + cio_write(cio, 0, 2); /* Pre-defined */ + + cio_write(cio, 0, 2); /* Reserved */ + + cio_write(cio, 0, 4); /* Pre-defined */ + cio_write(cio, 0, 4); /* Pre-defined */ + cio_write(cio, 0, 4); /* Pre-defined */ + + cio_write(cio, tk->w, 2); /* Width */ + cio_write(cio, tk->h, 2); /* Height */ + + cio_write(cio, tk->horizresolution, 4); /* Horizontal resolution */ + cio_write(cio, tk->vertresolution, 4); /* Vertical resolution */ + + cio_write(cio, 0, 4); /* Reserved */ + + cio_write(cio, 1, 2); /* Pre-defined = 1 */ + + cio_write(cio, tk->compressorname[0], 4); /* Compressor Name */ + cio_write(cio, tk->compressorname[1], 4); + cio_write(cio, tk->compressorname[2], 4); + cio_write(cio, tk->compressorname[3], 4); + cio_write(cio, tk->compressorname[4], 4); + cio_write(cio, tk->compressorname[5], 4); + cio_write(cio, tk->compressorname[6], 4); + cio_write(cio, tk->compressorname[7], 4); + + cio_write(cio, tk->depth, 2); /* Depth */ + + cio_write(cio, 0xffff, 2); /* Pre-defined = -1 */ + + jp2_write_jp2h(&tk->jp2_struct, cio); + + mj2_write_fiel(tk, cio); + + if (tk->num_br != 0) + mj2_write_jp2p(tk, cio); + if (tk->num_jp2x != 0) + mj2_write_jp2x(tk, cio); + + mj2_write_jsub(tk, cio); + mj2_write_orfo(tk, cio); + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the SMJ2 box +* +* Visual Sample Entry Description +* +*/ +int mj2_read_smj2(opj_image_t * img, mj2_tk_t * tk, opj_cio_t *cio) +{ + mj2_box_t box; + mj2_box_t box2; + int i; + + mj2_read_boxhdr(&box, cio); + + if (MJ2_MJ2 != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error in SMJ2 box: Expected MJ2 Marker\n"); + return 1; + } + + if (0 != cio_read(cio, 1)) { /* Version = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Only Version 0 handled in MJP2 box\n"); + return 1; + } + + if (0 != cio_read(cio, 3)) { /* Flags = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with flag in MJP2 box. Expected flag 0\n"); + return 1; + } + + cio_skip(cio,4); + + cio_skip(cio,2); /* Pre-defined */ + + cio_skip(cio,2); /* Reserved */ + + cio_skip(cio,4); /* Pre-defined */ + cio_skip(cio,4); /* Pre-defined */ + cio_skip(cio,4); /* Pre-defined */ + + tk->w = cio_read(cio, 2); /* Width */ + tk->h = cio_read(cio, 2); /* Height */ + + tk->horizresolution = cio_read(cio, 4); /* Horizontal resolution */ + tk->vertresolution = cio_read(cio, 4); /* Vertical resolution */ + + cio_skip(cio,4); /* Reserved */ + + cio_skip(cio,2); /* Pre-defined = 1 */ + + tk->compressorname[0] = cio_read(cio, 4); /* Compressor Name */ + tk->compressorname[1] = cio_read(cio, 4); + tk->compressorname[2] = cio_read(cio, 4); + tk->compressorname[3] = cio_read(cio, 4); + tk->compressorname[4] = cio_read(cio, 4); + tk->compressorname[5] = cio_read(cio, 4); + tk->compressorname[6] = cio_read(cio, 4); + tk->compressorname[7] = cio_read(cio, 4); + + tk->depth = cio_read(cio, 2); /* Depth */ + + /* Init std value */ + tk->num_jp2x = 0; + tk->fieldcount = 1; + tk->fieldorder = 0; + tk->or_fieldcount = 1; + tk->or_fieldorder = 0; + + cio_skip(cio,2); /* Pre-defined = -1 */ + + if (!jp2_read_jp2h(&tk->jp2_struct, cio)) { + opj_event_msg(tk->cinfo, EVT_ERROR, "Error reading JP2H Box\n"); + return 1; + } + + tk->jp2_struct.comps = (opj_jp2_comps_t*) opj_malloc(tk->jp2_struct.numcomps * sizeof(opj_jp2_comps_t)); + tk->jp2_struct.cl = (int*) opj_malloc(sizeof(int)); + + tk->num_br = 0; + tk->num_jp2x = 0; + + for (i = 0; cio_tell(cio) - box.init_pos < box.length; i++) { + mj2_read_boxhdr(&box2, cio); + cio_seek(cio, box2.init_pos); + switch (box2.type) { + case MJ2_FIEL: + if (mj2_read_fiel(tk, cio)) + return 1; + break; + + case MJ2_JP2P: + if (mj2_read_jp2p(tk, cio)) + return 1; + break; + + case MJ2_JP2X: + if (mj2_read_jp2x(tk, cio)) + return 1; + break; + + case MJ2_JSUB: + if (mj2_read_jsub(tk, cio)) + return 1; + break; + + case MJ2_ORFO: + if (mj2_read_orfo(tk, cio)) + return 1; + break; + + default: + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with MJP2 Box size\n"); + return 1; + break; + + } + } + return 0; +} + + +/* +* Write the STSD box +* +* Sample Description +* +*/ +void mj2_write_stsd(mj2_tk_t * tk, opj_cio_t *cio) +{ + mj2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + cio_write(cio, MJ2_STSD, 4); /* STSD */ + + cio_write(cio, 0, 4); /* Version = 0, flags = 0 */ + + cio_write(cio, 1, 4); /* entry_count = 1 (considering same JP2 headerboxes) */ + + if (tk->track_type == 0) { + mj2_write_smj2(tk, cio); + } else if (tk->track_type == 1) { + // Not implemented + } + if (tk->track_type == 2) { + // Not implemented + } + + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the STSD box +* +* Sample Description +* +*/ +int mj2_read_stsd(mj2_tk_t * tk, opj_image_t * img, opj_cio_t *cio) +{ + int i; + int entry_count, len_2skip; + + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); + + if (MJ2_STSD != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected STSD Marker\n"); + return 1; + } + + if (0 != cio_read(cio, 1)) { /* Version = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Only Version 0 handled in STSD box\n"); + return 1; + } + + if (0 != cio_read(cio, 3)) { /* Flags = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with flag in STSD box. Expected flag 0\n"); + return 1; + } + + entry_count = cio_read(cio, 4); + + if (tk->track_type == 0) { + for (i = 0; i < entry_count; i++) { + if (mj2_read_smj2(img, tk, cio)) + return 1; + } + } else if (tk->track_type == 1) { + len_2skip = cio_read(cio, 4); // Not implemented -> skipping box + cio_skip(cio,len_2skip - 4); + } else if (tk->track_type == 2) { + len_2skip = cio_read(cio, 4); // Not implemented -> skipping box + cio_skip(cio,len_2skip - 4); + } + + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with STSD Box size\n"); + return 1; + } + return 0; +} + +/* +* Write the STBL box +* +* Sample table box box +* +*/ +void mj2_write_stbl(mj2_tk_t * tk, opj_cio_t *cio) +{ + mj2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + cio_write(cio, MJ2_STBL, 4); /* STBL */ + + mj2_write_stsd(tk, cio); + mj2_write_stts(tk, cio); + mj2_write_stsc(tk, cio); + mj2_write_stsz(tk, cio); + mj2_write_stco(tk, cio); + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the STBL box +* +* Sample table box box +* +*/ +int mj2_read_stbl(mj2_tk_t * tk, opj_image_t * img, opj_cio_t *cio) +{ + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); + if (MJ2_STBL != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected STBL Marker\n"); + return 1; + } + + if (mj2_read_stsd(tk, img, cio)) + return 1; + if (mj2_read_stts(tk, cio)) + return 1; + if (mj2_read_stsc(tk, cio)) + return 1; + if (mj2_read_stsz(tk, cio)) + return 1; + if (mj2_read_stco(tk, cio)) + return 1; + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with STBL Box size\n"); + return 1; + } + return 0; +} + +/* +* Write the URL box +* +* URL box +* +*/ +void mj2_write_url(mj2_tk_t * tk, int url_num, opj_cio_t *cio) +{ + mj2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + cio_write(cio, MJ2_URL, 4); /* URL */ + + if (url_num == 0) + cio_write(cio, 1, 4); /* Version = 0, flags = 1 because stored in same file */ + else { + cio_write(cio, 0, 4); /* Version = 0, flags = 0 */ + cio_write(cio, tk->url[url_num - 1].location[0], 4); + cio_write(cio, tk->url[url_num - 1].location[1], 4); + cio_write(cio, tk->url[url_num - 1].location[2], 4); + cio_write(cio, tk->url[url_num - 1].location[3], 4); + } + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the URL box +* +* URL box +* +*/ +int mj2_read_url(mj2_tk_t * tk, int urn_num, opj_cio_t *cio) +{ + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); + if (MJ2_URL != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected URL Marker\n"); + return 1; + } + + if (0 != cio_read(cio, 1)) { /* Version = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Only Version 0 handled in URL box\n"); + return 1; + } + + if (1 != cio_read(cio, 3)) { /* If flags = 1 --> media data in file */ + tk->url[urn_num].location[0] = cio_read(cio, 4); + tk->url[urn_num].location[1] = cio_read(cio, 4); + tk->url[urn_num].location[2] = cio_read(cio, 4); + tk->url[urn_num].location[3] = cio_read(cio, 4); + } else { + tk->num_url--; + } + + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with URL Box size\n"); + return 1; + } + return 0; +} + +/* +* Write the URN box +* +* URN box +* +*/ +void mj2_write_urn(mj2_tk_t * tk, int urn_num, opj_cio_t *cio) +{ + mj2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + cio_write(cio, MJ2_URN, 4); /* URN */ + + cio_write(cio, 0, 4); /* Version = 0, flags = 0 */ + + cio_write(cio, tk->urn[urn_num].name[0], 4); + cio_write(cio, tk->urn[urn_num].name[1], 4); + cio_write(cio, tk->urn[urn_num].name[2], 4); + cio_write(cio, tk->urn[urn_num].name[3], 4); + cio_write(cio, tk->urn[urn_num].location[0], 4); + cio_write(cio, tk->urn[urn_num].location[1], 4); + cio_write(cio, tk->urn[urn_num].location[2], 4); + cio_write(cio, tk->urn[urn_num].location[3], 4); + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the URN box +* +* URN box +* +*/ +int mj2_read_urn(mj2_tk_t * tk, int urn_num, opj_cio_t *cio) +{ + + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); + if (MJ2_URN != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected URN Marker\n"); + return 1; + } + + if (0 != cio_read(cio, 1)) { /* Version = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Only Version 0 handled in URN box\n"); + return 1; + } + + if (1 != cio_read(cio, 3)) { /* If flags = 1 --> media data in file */ + tk->urn[urn_num].name[0] = cio_read(cio, 4); + tk->urn[urn_num].name[1] = cio_read(cio, 4); + tk->urn[urn_num].name[2] = cio_read(cio, 4); + tk->urn[urn_num].name[3] = cio_read(cio, 4); + tk->urn[urn_num].location[0] = cio_read(cio, 4); + tk->urn[urn_num].location[1] = cio_read(cio, 4); + tk->urn[urn_num].location[2] = cio_read(cio, 4); + tk->urn[urn_num].location[3] = cio_read(cio, 4); + } + + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with URN Box size\n"); + return 1; + } + return 0; +} + + +/* +* Write the DREF box +* +* Data reference box +* +*/ +void mj2_write_dref(mj2_tk_t * tk, opj_cio_t *cio) +{ + int i; + mj2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + cio_write(cio, MJ2_DREF, 4); /* DREF */ + + cio_write(cio, 0, 4); /* Version = 0, flags = 0 */ + + if (tk->num_url + tk->num_urn == 0) { /* Media data in same file */ + cio_write(cio, 1, 4); /* entry_count = 1 */ + mj2_write_url(tk, 0, cio); + } else { + cio_write(cio, tk->num_url + tk->num_urn, 4); /* entry_count */ + + for (i = 0; i < tk->num_url; i++) + mj2_write_url(tk, i + 1, cio); + + for (i = 0; i < tk->num_urn; i++) + mj2_write_urn(tk, i, cio); + } + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the DREF box +* +* Data reference box +* +*/ +int mj2_read_dref(mj2_tk_t * tk, opj_cio_t *cio) +{ + + int i; + int entry_count, marker; + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); + if (MJ2_DREF != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected DREF Marker\n"); + return 1; + } + + if (0 != cio_read(cio, 1)) { /* Version = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Only Version 0 handled in DREF box\n"); + return 1; + } + + if (0 != cio_read(cio, 3)) { /* Flags = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with flag in DREF box. Expected flag 0\n"); + return 1; + } + + entry_count = cio_read(cio, 4); + tk->num_url = 0; + tk->num_urn = 0; + + for (i = 0; i < entry_count; i++) { + cio_skip(cio,4); + marker = cio_read(cio, 4); + if (marker == MJ2_URL) { + cio_skip(cio,-8); + tk->num_url++; + if (mj2_read_url(tk, tk->num_url, cio)) + return 1; + } else if (marker == MJ2_URN) { + cio_skip(cio,-8); + tk->num_urn++; + if (mj2_read_urn(tk, tk->num_urn, cio)) + return 1; + } else { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with in DREF box. Expected URN or URL box\n"); + return 1; + } + + } + + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with DREF Box size\n"); + return 1; + } + return 0; +} + +/* +* Write the DINF box +* +* Data information box +* +*/ +void mj2_write_dinf(mj2_tk_t * tk, opj_cio_t *cio) +{ + mj2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + cio_write(cio, MJ2_DINF, 4); /* DINF */ + + mj2_write_dref(tk, cio); + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the DINF box +* +* Data information box +* +*/ +int mj2_read_dinf(mj2_tk_t * tk, opj_cio_t *cio) +{ + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); + if (MJ2_DINF != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected DINF Marker\n"); + return 1; + } + + if (mj2_read_dref(tk, cio)) + return 1; + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with DINF Box size\n"); + return 1; + } + return 0; +} + +/* +* Write the VMHD box +* +* Video Media information box +* +*/ +void mj2_write_vmhd(mj2_tk_t * tk, opj_cio_t *cio) +{ + mj2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + cio_write(cio, MJ2_VMHD, 4); /* VMHD */ + + cio_write(cio, 1, 4); /* Version = 0, flags = 1 */ + + cio_write(cio, tk->graphicsmode, 2); + cio_write(cio, tk->opcolor[0], 2); + cio_write(cio, tk->opcolor[1], 2); + cio_write(cio, tk->opcolor[2], 2); + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the VMHD box +* +* Video Media information box +* +*/ +int mj2_read_vmhd(mj2_tk_t * tk, opj_cio_t *cio) +{ + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); + if (MJ2_VMHD != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected VMHD Marker\n"); + return 1; + } + + if (0 != cio_read(cio, 1)) { /* Version = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Only Version 0 handled in VMHD box\n"); + return 1; + } + + if (1 != cio_read(cio, 3)) { /* Flags = 1 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with flag in VMHD box. Expected flag 1\n"); + return 1; + } + + tk->track_type = 0; + tk->graphicsmode = cio_read(cio, 2); + tk->opcolor[0] = cio_read(cio, 2); + tk->opcolor[1] = cio_read(cio, 2); + tk->opcolor[2] = cio_read(cio, 2); + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with VMHD Box size\n"); + return 1; + } + return 0; +} + +/* +* Write the SMHD box +* +* Sound Media information box +* +*/ +void mj2_write_smhd(mj2_tk_t * tk, opj_cio_t *cio) +{ + mj2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + cio_write(cio, MJ2_SMHD, 4); /* SMHD */ + + cio_write(cio, 0, 4); /* Version = 0, flags = 0 */ + + cio_write(cio, tk->balance, 2); + + cio_write(cio, 0, 2); /* Reserved */ + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the SMHD box +* +* Sound Media information box +* +*/ +int mj2_read_smhd(mj2_tk_t * tk, opj_cio_t *cio) +{ + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); + if (MJ2_SMHD != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected SMHD Marker\n"); + return 1; + } + + if (0 != cio_read(cio, 1)) { /* Version = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Only Version 0 handled in SMHD box\n"); + return 1; + } + + if (0 != cio_read(cio, 3)) { /* Flags = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with flag in SMHD box. Expected flag 0\n"); + return 1; + } + + tk->track_type = 1; + tk->balance = cio_read(cio, 2); + + /* Init variables to zero to avoid problems when freeeing memory + The values will possibly be overidded when decoding the track structure */ + tk->num_br = 0; + tk->num_url = 0; + tk->num_urn = 0; + tk->num_chunks = 0; + tk->num_tts = 0; + tk->num_samplestochunk = 0; + tk->num_samples = 0; + + cio_skip(cio,2); /* Reserved */ + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with SMHD Box size\n"); + return 1; + } + return 0; +} + +/* +* Write the HMHD box +* +* Hint Media information box +* +*/ +void mj2_write_hmhd(mj2_tk_t * tk, opj_cio_t *cio) +{ + mj2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + cio_write(cio, MJ2_HMHD, 4); /* HMHD */ + + cio_write(cio, 0, 4); /* Version = 0, flags = 0 */ + + cio_write(cio, tk->maxPDUsize, 2); + cio_write(cio, tk->avgPDUsize, 2); + cio_write(cio, tk->maxbitrate, 4); + cio_write(cio, tk->avgbitrate, 4); + cio_write(cio, tk->slidingavgbitrate, 4); + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the HMHD box +* +* Hint Media information box +* +*/ +int mj2_read_hmhd(mj2_tk_t * tk, opj_cio_t *cio) +{ + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); + if (MJ2_HMHD != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected HMHD Marker\n"); + return 1; + } + + if (0 != cio_read(cio, 1)) { /* Version = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Only Version 0 handled in HMHD box\n"); + return 1; + } + + if (0 != cio_read(cio, 3)) { /* Flags = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with flag in HMHD box. Expected flag 0\n"); + return 1; + } + + tk->track_type = 2; + tk->maxPDUsize = cio_read(cio, 2); + tk->avgPDUsize = cio_read(cio, 2); + tk->maxbitrate = cio_read(cio, 4); + tk->avgbitrate = cio_read(cio, 4); + tk->slidingavgbitrate = cio_read(cio, 4); + + /* Init variables to zero to avoid problems when freeeing memory + The values will possibly be overidded when decoding the track structure */ + tk->num_br = 0; + tk->num_url = 0; + tk->num_urn = 0; + tk->num_chunks = 0; + tk->num_tts = 0; + tk->num_samplestochunk = 0; + tk->num_samples = 0; + + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with HMHD Box size\n"); + return 1; + } + return 0; +} + +/* +* Write the MINF box +* +* Media information box +* +*/ +void mj2_write_minf(mj2_tk_t * tk, opj_cio_t *cio) +{ + mj2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + cio_write(cio, MJ2_MINF, 4); /* MINF */ + + if (tk->track_type == 0) { + mj2_write_vmhd(tk, cio); + } else if (tk->track_type == 1) { + mj2_write_smhd(tk, cio); + } else if (tk->track_type == 2) { + mj2_write_hmhd(tk, cio); + } + + mj2_write_dinf(tk, cio); + mj2_write_stbl(tk, cio); + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the MINF box +* +* Media information box +* +*/ +int mj2_read_minf(mj2_tk_t * tk, opj_image_t * img, opj_cio_t *cio) +{ + + unsigned int box_type; + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); + if (MJ2_MINF != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected MINF Marker\n"); + return 1; + } + + cio_skip(cio,4); + box_type = cio_read(cio, 4); + cio_skip(cio,-8); + + if (box_type == MJ2_VMHD) { + if (mj2_read_vmhd(tk, cio)) + return 1; + } else if (box_type == MJ2_SMHD) { + if (mj2_read_smhd(tk, cio)) + return 1; + } else if (box_type == MJ2_HMHD) { + if (mj2_read_hmhd(tk, cio)) + return 1; + } else { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error in MINF box expected vmhd, smhd or hmhd\n"); + return 1; + } + + if (mj2_read_dinf(tk, cio)) + return 1; + + if (mj2_read_stbl(tk, img, cio)) + return 1; + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with MINF Box size\n"); + return 1; + } + return 0; +} + +/* +* Write the HDLR box +* +* Handler reference box +* +*/ +void mj2_write_hdlr(mj2_tk_t * tk, opj_cio_t *cio) +{ + mj2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + cio_write(cio, MJ2_HDLR, 4); /* HDLR */ + + cio_write(cio, 0, 4); /* Version = 0, flags = 0 */ + + cio_write(cio, 0, 4); /* Predefine */ + + tk->name = 0; /* The track name is immediately determined by the track type */ + + if (tk->track_type == 0) { + tk->handler_type = 0x76696465; /* Handler type: vide */ + cio_write(cio, tk->handler_type, 4); + + cio_write(cio, 0, 4); + cio_write(cio, 0, 4); + cio_write(cio, 0, 4); /* Reserved */ + + cio_write(cio, 0x76696465, 4); + cio_write(cio, 0x6F206d65, 4); + cio_write(cio, 0x64696120, 4); + cio_write(cio, 0x74726163, 4); + cio_write(cio, 0x6b00, 2); /* String: video media track */ + } else if (tk->track_type == 1) { + tk->handler_type = 0x736F756E; /* Handler type: soun */ + cio_write(cio, tk->handler_type, 4); + + cio_write(cio, 0, 4); + cio_write(cio, 0, 4); + cio_write(cio, 0, 4); /* Reserved */ + + cio_write(cio, 0x536F756E, 4); + cio_write(cio, 0x6400, 2); /* String: Sound */ + } else if (tk->track_type == 2) { + tk->handler_type = 0x68696E74; /* Handler type: hint */ + cio_write(cio, tk->handler_type, 4); + + cio_write(cio, 0, 4); + cio_write(cio, 0, 4); + cio_write(cio, 0, 4); /* Reserved */ + + cio_write(cio, 0x48696E74, 4); + cio_write(cio, 0, 2); /* String: Hint */ + } + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the HDLR box +* +* Handler reference box +* +*/ +int mj2_read_hdlr(mj2_tk_t * tk, opj_cio_t *cio) +{ + int i; + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); + if (MJ2_HDLR != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected HDLR Marker\n"); + return 1; + } + + + if (0 != cio_read(cio, 1)) { /* Version = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Only Version 0 handled in HDLR box\n"); + return 1; + } + + if (0 != cio_read(cio, 3)) { /* Flags = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with flag in HDLR box. Expected flag 0\n"); + return 1; + } + + cio_skip(cio,4); /* Reserved */ + + tk->handler_type = cio_read(cio, 4); + cio_skip(cio,12); /* Reserved */ + + tk->name_size = box.length - 32; + + tk->name = (char*) opj_malloc(tk->name_size * sizeof(char)); + for (i = 0; i < tk->name_size; i++) { + tk->name[i] = cio_read(cio, 1); /* Name */ + } + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with HDLR Box size\n"); + return 1; + } + return 0; +} + +/* +* Write the MDHD box +* +* Media Header Box +* +*/ +void mj2_write_mdhd(mj2_tk_t * tk, opj_cio_t *cio) +{ + mj2_box_t box; + unsigned int i; + time_t ltime; + unsigned int modification_time; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + cio_write(cio, MJ2_MDHD, 4); /* MDHD */ + + cio_write(cio, 0, 4); /* Version = 0, flags = 0 */ + + cio_write(cio, tk->creation_time, 4); /* Creation Time */ + + time(<ime); /* Time since 1/1/70 */ + modification_time = (unsigned int)ltime + 2082844800; /* Seoonds between 1/1/04 and 1/1/70 */ + + cio_write(cio, modification_time, 4); /* Modification Time */ + + cio_write(cio, tk->timescale, 4); /* Timescale */ + + tk->duration = 0; + + for (i = 0; i < tk->num_samples; i++) + tk->duration += tk->sample[i].sample_delta; + + cio_write(cio, tk->duration, 4); /* Duration */ + + cio_write(cio, tk->language, 2); /* Language */ + + cio_write(cio, 0, 2); /* Predefined */ + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the MDHD box +* +* Media Header Box +* +*/ +int mj2_read_mdhd(mj2_tk_t * tk, opj_cio_t *cio) +{ + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); + if (!(MJ2_MHDR == box.type || MJ2_MDHD == box.type)) { // Kakadu writes MHDR instead of MDHD + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected MDHD Marker\n"); + return 1; + } + + if (0 != cio_read(cio, 1)) { /* Version = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Only Version 0 handled in MDHD box\n"); + return 1; + } + + if (0 != cio_read(cio, 3)) { /* Flags = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with flag in MDHD box. Expected flag 0\n"); + return 1; + } + + + tk->creation_time = cio_read(cio, 4); /* Creation Time */ + + tk->modification_time = cio_read(cio, 4); /* Modification Time */ + + tk->timescale = cio_read(cio, 4); /* Timescale */ + + tk->duration = cio_read(cio, 4); /* Duration */ + + tk->language = cio_read(cio, 2); /* Language */ + + cio_skip(cio,2); /* Predefined */ + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with MDHD Box size\n"); + return 1; + } + return 0; +} + +/* +* Write the MDIA box +* +* Media box +* +*/ +void mj2_write_mdia(mj2_tk_t * tk, opj_cio_t *cio) +{ + mj2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + cio_write(cio, MJ2_MDIA, 4); /* MDIA */ + + mj2_write_mdhd(tk, cio); + mj2_write_hdlr(tk, cio); + mj2_write_minf(tk, cio); + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the MDIA box +* +* Media box +* +*/ +int mj2_read_mdia(mj2_tk_t * tk, opj_image_t * img, opj_cio_t *cio) +{ + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); + if (MJ2_MDIA != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected MDIA Marker\n"); + return 1; + } + + if (mj2_read_mdhd(tk, cio)) + return 1; + if (mj2_read_hdlr(tk, cio)) + return 1; + if (mj2_read_minf(tk, img, cio)) + return 1; + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with MDIA Box size\n"); + return 1; + } + return 0; +} + +/* +* Write the TKHD box +* +* Track Header box +* +*/ +void mj2_write_tkhd(mj2_tk_t * tk, opj_cio_t *cio) +{ + mj2_box_t box; + unsigned int i; + time_t ltime; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + + cio_write(cio, MJ2_TKHD, 4); /* TKHD */ + + cio_write(cio, 3, 4); /* Version=0, flags=3 */ + + time(<ime); /* Time since 1/1/70 */ + tk->modification_time = (unsigned int)ltime + 2082844800; /* Seoonds between 1/1/04 and 1/1/70 */ + + cio_write(cio, tk->creation_time, 4); /* Creation Time */ + + cio_write(cio, tk->modification_time, 4); /* Modification Time */ + + cio_write(cio, tk->track_ID, 4); /* Track ID */ + + cio_write(cio, 0, 4); /* Reserved */ + + tk->duration = 0; + + for (i = 0; i < tk->num_samples; i++) + tk->duration += tk->sample[i].sample_delta; + + cio_write(cio, tk->duration, 4); /* Duration */ + + cio_write(cio, 0, 4); /* Reserved */ + cio_write(cio, 0, 4); /* Reserved */ + + cio_write(cio, tk->layer, 2); /* Layer */ + + cio_write(cio, 0, 2); /* Predefined */ + + cio_write(cio, tk->volume, 2); /* Volume */ + + cio_write(cio, 0, 2); /* Reserved */ + + cio_write(cio, tk->trans_matrix[0], 4); /* Transformation matrix for track */ + cio_write(cio, tk->trans_matrix[1], 4); + cio_write(cio, tk->trans_matrix[2], 4); + cio_write(cio, tk->trans_matrix[3], 4); + cio_write(cio, tk->trans_matrix[4], 4); + cio_write(cio, tk->trans_matrix[5], 4); + cio_write(cio, tk->trans_matrix[6], 4); + cio_write(cio, tk->trans_matrix[7], 4); + cio_write(cio, tk->trans_matrix[8], 4); + + cio_write(cio, tk->visual_w, 4); /* Video Visual Width */ + + cio_write(cio, tk->visual_h, 4); /* Video Visual Height */ + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the TKHD box +* +* Track Header box +* +*/ +int mj2_read_tkhd(mj2_tk_t * tk, opj_cio_t *cio) +{ + int flag; + + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); + + if (MJ2_TKHD != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected TKHD Marker\n"); + return 1; + } + + if (0 != cio_read(cio, 1)) { /* Version = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Only Version 0 handled in TKHD box\n"); + return 1; + } + + flag = cio_read(cio, 3); + + if (!(flag == 1 || flag == 2 || flag == 3 || flag == 4)) { /* Flags = 1,2,3 or 4 */ + opj_event_msg(cio->cinfo, EVT_ERROR, + "Error with flag in TKHD box: Expected flag 1,2,3 or 4\n"); + return 1; + } + + tk->creation_time = cio_read(cio, 4); /* Creation Time */ + + tk->modification_time = cio_read(cio, 4); /* Modification Time */ + + tk->track_ID = cio_read(cio, 4); /* Track ID */ + + cio_skip(cio,4); /* Reserved */ + + tk->duration = cio_read(cio, 4); /* Duration */ + + cio_skip(cio,8); /* Reserved */ + + tk->layer = cio_read(cio, 2); /* Layer */ + + cio_read(cio, 2); /* Predefined */ + + tk->volume = cio_read(cio, 2); /* Volume */ + + cio_skip(cio,2); /* Reserved */ + + tk->trans_matrix[0] = cio_read(cio, 4); /* Transformation matrix for track */ + tk->trans_matrix[1] = cio_read(cio, 4); + tk->trans_matrix[2] = cio_read(cio, 4); + tk->trans_matrix[3] = cio_read(cio, 4); + tk->trans_matrix[4] = cio_read(cio, 4); + tk->trans_matrix[5] = cio_read(cio, 4); + tk->trans_matrix[6] = cio_read(cio, 4); + tk->trans_matrix[7] = cio_read(cio, 4); + tk->trans_matrix[8] = cio_read(cio, 4); + + tk->visual_w = cio_read(cio, 4); /* Video Visual Width */ + + tk->visual_h = cio_read(cio, 4); /* Video Visual Height */ + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with TKHD Box size\n"); + return 1; + } + return 0; +} + +/* +* Write the TRAK box +* +* Track box +* +*/ +void mj2_write_trak(mj2_tk_t * tk, opj_cio_t *cio) +{ + mj2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + + cio_write(cio, MJ2_TRAK, 4); /* TRAK */ + + mj2_write_tkhd(tk, cio); + mj2_write_mdia(tk, cio); + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the TRAK box +* +* Track box +* +*/ +int mj2_read_trak(mj2_tk_t * tk, opj_image_t * img, opj_cio_t *cio) +{ + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); + if (MJ2_TRAK != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected TRAK Marker\n"); + return 1; + } + if (mj2_read_tkhd(tk, cio)) + return 1; + if (mj2_read_mdia(tk, img, cio)) + return 1; + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with TRAK Box\n"); + return 1; + } + return 0; +} + +/* +* Write the MVHD box +* +* Movie header Box +* +*/ +void mj2_write_mvhd(opj_mj2_t * movie, opj_cio_t *cio) +{ + int i; + mj2_box_t box; + unsigned j; + time_t ltime; + int max_tk_num = 0; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + cio_write(cio, MJ2_MVHD, 4); /* MVHD */ + + cio_write(cio, 0, 4); /* Version = 0, flags = 0 */ + + time(<ime); /* Time since 1/1/70 */ + movie->modification_time = (unsigned int)ltime + 2082844800; /* Seoonds between 1/1/04 and 1/1/70 */ + + cio_write(cio, movie->creation_time, 4); /* Creation Time */ + + cio_write(cio, movie->modification_time, 4); /* Modification Time */ + + cio_write(cio, movie->timescale, 4); /* Timescale */ + + movie->duration = 0; + + for (i = 0; i < (movie->num_stk + movie->num_htk + movie->num_vtk); i++) { + mj2_tk_t *tk = &movie->tk[i]; + + for (j = 0; j < tk->num_samples; j++) { + movie->duration += tk->sample[j].sample_delta; + } + } + + cio_write(cio, movie->duration, 4); + + cio_write(cio, movie->rate, 4); /* Rate to play presentation */ + + cio_write(cio, movie->volume, 2); /* Volume */ + + cio_write(cio, 0, 2); /* Reserved */ + cio_write(cio, 0, 4); /* Reserved */ + cio_write(cio, 0, 4); /* Reserved */ + + cio_write(cio, movie->trans_matrix[0], 4); /* Transformation matrix for video */ + cio_write(cio, movie->trans_matrix[1], 4); + cio_write(cio, movie->trans_matrix[2], 4); + cio_write(cio, movie->trans_matrix[3], 4); + cio_write(cio, movie->trans_matrix[4], 4); + cio_write(cio, movie->trans_matrix[5], 4); + cio_write(cio, movie->trans_matrix[6], 4); + cio_write(cio, movie->trans_matrix[7], 4); + cio_write(cio, movie->trans_matrix[8], 4); + + cio_write(cio, 0, 4); /* Pre-defined */ + cio_write(cio, 0, 4); /* Pre-defined */ + cio_write(cio, 0, 4); /* Pre-defined */ + cio_write(cio, 0, 4); /* Pre-defined */ + cio_write(cio, 0, 4); /* Pre-defined */ + cio_write(cio, 0, 4); /* Pre-defined */ + + + for (i = 0; i < movie->num_htk + movie->num_stk + movie->num_vtk; i++) { + if (max_tk_num < movie->tk[i].track_ID) + max_tk_num = movie->tk[i].track_ID; + } + + movie->next_tk_id = max_tk_num + 1; + + cio_write(cio, movie->next_tk_id, 4); /* ID of Next track to be added */ + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the MVHD box +* +* Movie header Box +* +*/ +int mj2_read_mvhd(opj_mj2_t * movie, opj_cio_t *cio) +{ + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); + if (MJ2_MVHD != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected MVHD Marker\n"); + return 1; + } + + + if (0 != cio_read(cio, 4)) { /* Version = 0, flags = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Only Version 0 handled in MVHD box\n"); + } + + movie->creation_time = cio_read(cio, 4); /* Creation Time */ + + movie->modification_time = cio_read(cio, 4); /* Modification Time */ + + movie->timescale = cio_read(cio, 4); /* Timescale */ + + movie->duration = cio_read(cio, 4); /* Duration */ + + movie->rate = cio_read(cio, 4); /* Rate to play presentation */ + + movie->volume = cio_read(cio, 2); /* Volume */ + + cio_skip(cio,10); /* Reserved */ + + movie->trans_matrix[0] = cio_read(cio, 4); /* Transformation matrix for video */ + movie->trans_matrix[1] = cio_read(cio, 4); + movie->trans_matrix[2] = cio_read(cio, 4); + movie->trans_matrix[3] = cio_read(cio, 4); + movie->trans_matrix[4] = cio_read(cio, 4); + movie->trans_matrix[5] = cio_read(cio, 4); + movie->trans_matrix[6] = cio_read(cio, 4); + movie->trans_matrix[7] = cio_read(cio, 4); + movie->trans_matrix[8] = cio_read(cio, 4); + + cio_skip(cio,24); /* Pre-defined */ + + movie->next_tk_id = cio_read(cio, 4); /* ID of Next track to be added */ + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with MVHD Box Size\n"); + return 1; + } + return 0; +} + + +/* +* Write the MOOV box +* +* Movie Box +* +*/ +void mj2_write_moov(opj_mj2_t * movie, opj_cio_t *cio) +{ + int i; + mj2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + cio_write(cio, MJ2_MOOV, 4); /* MOOV */ + + mj2_write_mvhd(movie, cio); + + for (i = 0; i < (movie->num_stk + movie->num_htk + movie->num_vtk); i++) { + mj2_write_trak(&movie->tk[i], cio); + } + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the MOOV box +* +* Movie Box +* +*/ +int mj2_read_moov(opj_mj2_t * movie, opj_image_t * img, opj_cio_t *cio) +{ + unsigned int i; + mj2_box_t box; + mj2_box_t box2; + + mj2_read_boxhdr(&box, cio); + if (MJ2_MOOV != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected MOOV Marker\n"); + return 1; + } + + if (mj2_read_mvhd(movie, cio)) + return 1; + + movie->tk = (mj2_tk_t*) opj_malloc((movie->next_tk_id - 1) * sizeof(mj2_tk_t)); + + for (i = 0; cio_tell(cio) - box.init_pos < box.length; i++) { + mj2_tk_t *tk = &movie->tk[i]; + tk->cinfo = movie->cinfo; + mj2_read_boxhdr(&box2, cio); + if (box2.type == MJ2_TRAK) { + cio_seek(cio, box2.init_pos); + if (mj2_read_trak(tk, img, cio)) + return 1; + + if (tk->track_type == 0) { + movie->num_vtk++; + } else if (tk->track_type == 1) { + movie->num_stk++; + } else if (tk->track_type == 2) { + movie->num_htk++; + } + } else if (box2.type == MJ2_MVEX) { + cio_seek(cio, box2.init_pos); + cio_skip(cio,box2.length); + i--; + } else { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with MOOV Box: Expected TRAK or MVEX box\n"); + return 1; + } + } + return 0; +} + +int mj2_read_struct(FILE *file, opj_mj2_t *movie) { + mj2_box_t box; + opj_image_t img; + char * src; + int fsresult; + int foffset; + opj_cio_t *cio; + + /* open a byte stream for reading */ + src = (char*) opj_malloc(300 * sizeof(char)); + + /* Assuming that jp and ftyp markers size do + not exceed 300 bytes */ + fread(src,300,1, file); + + cio = opj_cio_open((opj_common_ptr)movie->cinfo, src, 300); + + if (mj2_read_jp(cio)) + return 1; + if (mj2_read_ftyp(movie, cio)) + return 1; + + fsresult = fseek(file,cio_tell(cio),SEEK_SET); + if( fsresult ) { + opj_event_msg(cio->cinfo, EVT_ERROR, "End of file reached while trying to read data after FTYP box\n" ); + return 1; + } + + foffset = cio_tell(cio); + + box.type = 0; + + fread(src,30,1,file); + cio = opj_cio_open((opj_common_ptr)movie->cinfo, src, 300); + mj2_read_boxhdr(&box, cio); + + while(box.type != MJ2_MOOV) { + + switch(box.type) + { + case MJ2_MDAT: + fsresult = fseek(file,foffset+box.length,SEEK_SET); + if( fsresult ) { + opj_event_msg(cio->cinfo, EVT_ERROR, "End of file reached while trying to read MDAT box\n" ); + return 1; + } + foffset += box.length; + break; + + case MJ2_MOOF: + fsresult = fseek(file,foffset+box.length,SEEK_SET); + if( fsresult ) { + opj_event_msg(cio->cinfo, EVT_ERROR, "End of file reached while trying to read MOOF box\n" ); + return 1; + } + foffset += box.length; + break; + case MJ2_FREE: + fsresult = fseek(file,foffset+box.length,SEEK_SET); + if( fsresult ) { + opj_event_msg(cio->cinfo, EVT_ERROR, "End of file reached while trying to read FREE box\n" ); + return 1; + } + foffset += box.length; + break; + case MJ2_SKIP: + fsresult = fseek(file,foffset+box.length,SEEK_SET); + if( fsresult ) { + opj_event_msg(cio->cinfo, EVT_ERROR, "End of file reached while trying to read SKIP box\n" ); + return 1; + } + foffset += box.length; + break; + default: + opj_event_msg(cio->cinfo, EVT_ERROR, "Unknown box in MJ2 stream\n"); + fsresult = fseek(file,foffset+box.length,SEEK_SET); + if( fsresult ) { + opj_event_msg(cio->cinfo, EVT_ERROR, "End of file reached while trying to read end of unknown box\n"); + return 1; + } + foffset += box.length; + break; + } + fsresult = fread(src,8,1,file); + if (fsresult != 1) { + opj_event_msg(cio->cinfo, EVT_ERROR, "MOOV box not found in file\n"); + return 1; + } + cio = opj_cio_open((opj_common_ptr)movie->cinfo, src, 8); + mj2_read_boxhdr(&box, cio); + } + + fseek(file,foffset,SEEK_SET); + src = opj_realloc(src,box.length); + fsresult = fread(src,box.length,1,file); + if (fsresult != 1) { + opj_event_msg(cio->cinfo, EVT_ERROR, "End of file reached while trying to read MOOV box\n"); + return 1; + } + + cio = opj_cio_open((opj_common_ptr)movie->cinfo, src, box.length); + + if (mj2_read_moov(movie, &img, cio)) + return 1; + + opj_free(src); + return 0; +} + +/* ----------------------------------------------------------------------- */ +/* MJ2 decoder interface */ +/* ----------------------------------------------------------------------- */ + +opj_dinfo_t* mj2_create_decompress() { + opj_mj2_t* mj2; + opj_dinfo_t *dinfo = (opj_dinfo_t*) opj_calloc(1, sizeof(opj_dinfo_t)); + if(!dinfo) return NULL; + + dinfo->is_decompressor = true; + + mj2 = (opj_mj2_t*) opj_calloc(1, sizeof(opj_mj2_t)); + dinfo->mj2_handle = mj2; + if(mj2) { + mj2->cinfo = (opj_common_ptr)dinfo; + } + mj2->j2k = j2k_create_decompress((opj_common_ptr)dinfo); + dinfo->j2k_handle = mj2->j2k; + + return dinfo; +} + +void mj2_setup_decoder(opj_mj2_t *movie, mj2_dparameters_t *mj2_parameters) { + movie->num_vtk=0; + movie->num_stk=0; + movie->num_htk=0; + + /* setup the J2K decoder parameters */ + j2k_setup_decoder(movie->cinfo->j2k_handle, &mj2_parameters->j2k_parameters); + +} + +void mj2_destroy_decompress(opj_mj2_t *movie) { + if(movie) { + int i; + mj2_tk_t *tk=NULL; + + if (movie->cinfo->j2k_handle) + j2k_destroy_compress(movie->j2k); + + if (movie->num_cl != 0) + opj_free(movie->cl); + + for (i = 0; i < movie->num_vtk + movie->num_stk + movie->num_htk; i++) { + tk = &movie->tk[i]; + if (tk->name_size != 0) + opj_free(tk->name); + if (tk->track_type == 0) {// Video track + if (tk->jp2_struct.comps != 0) + opj_free(tk->jp2_struct.comps); + if (tk->jp2_struct.cl != 0) + opj_free(tk->jp2_struct.cl); + if (tk->num_jp2x != 0) + opj_free(tk->jp2xdata); + + } + if (tk->num_url != 0) + opj_free(tk->url); + if (tk->num_urn != 0) + opj_free(tk->urn); + if (tk->num_br != 0) + opj_free(tk->br); + if (tk->num_tts != 0) + opj_free(tk->tts); + if (tk->num_chunks != 0) + opj_free(tk->chunk); + if (tk->num_samplestochunk != 0) + opj_free(tk->sampletochunk); + if (tk->num_samples != 0) + opj_free(tk->sample); + } + + opj_free(movie->tk); + } + opj_free(movie); +} + +/* ----------------------------------------------------------------------- */ +/* MJ2 encoder interface */ +/* ----------------------------------------------------------------------- */ + + +opj_cinfo_t* mj2_create_compress() { + opj_mj2_t* mj2; + opj_cinfo_t *cinfo = (opj_cinfo_t*) opj_calloc(1, sizeof(opj_cinfo_t)); + if(!cinfo) return NULL; + + mj2 = (opj_mj2_t*) opj_calloc(1, sizeof(opj_mj2_t)); + cinfo->mj2_handle = mj2; + if(mj2) { + mj2->cinfo = (opj_common_ptr)cinfo; + } + + mj2->j2k = j2k_create_compress(mj2->cinfo); + cinfo->j2k_handle = mj2->j2k; + + return cinfo; +} + +void mj2_setup_encoder(opj_mj2_t *movie, mj2_cparameters_t *parameters) { + if(movie && parameters) { + opj_jp2_t *jp2_struct; + + movie->num_htk = 0; // No hint tracks + movie->num_stk = 0; // No sound tracks + movie->num_vtk = 1; // One video track + + movie->brand = MJ2_MJ2; // One brand: MJ2 + movie->num_cl = 2; // Two compatible brands: MJ2 and MJ2S + movie->cl = (unsigned int*) opj_malloc(movie->num_cl * sizeof(unsigned int)); + movie->cl[0] = MJ2_MJ2; + movie->cl[1] = MJ2_MJ2S; + movie->minversion = 0; // Minimum version: 0 + + movie->tk = (mj2_tk_t*) opj_malloc(sizeof(mj2_tk_t)); //Memory allocation for the video track + movie->tk[0].track_ID = 1; // Track ID = 1 + movie->tk[0].track_type = 0; // Video track + movie->tk[0].Dim[0] = parameters->Dim[0]; + movie->tk[0].Dim[1] = parameters->Dim[1]; + movie->tk[0].w = parameters->w; + movie->tk[0].h = parameters->h; + movie->tk[0].CbCr_subsampling_dx = parameters->CbCr_subsampling_dx; + movie->tk[0].CbCr_subsampling_dy = parameters->CbCr_subsampling_dy; + movie->tk[0].sample_rate = parameters->frame_rate; + movie->tk[0].name_size = 0; + movie->tk[0].chunk = (mj2_chunk_t*) opj_malloc(sizeof(mj2_chunk_t)); + movie->tk[0].sample = (mj2_sample_t*) opj_malloc(sizeof(mj2_sample_t)); + + jp2_struct = &movie->tk[0].jp2_struct; + jp2_struct->numcomps = 3; // NC + jp2_struct->comps = (opj_jp2_comps_t*) opj_malloc(jp2_struct->numcomps * sizeof(opj_jp2_comps_t)); + jp2_struct->precedence = 0; /* PRECEDENCE*/ + jp2_struct->approx = 0; /* APPROX*/ + jp2_struct->brand = JP2_JP2; /* BR */ + jp2_struct->minversion = 0; /* MinV */ + jp2_struct->numcl = 1; + jp2_struct->cl = (unsigned int*) opj_malloc(jp2_struct->numcl * sizeof(int)); + jp2_struct->cl[0] = JP2_JP2; /* CL0 : JP2 */ + jp2_struct->C = 7; /* C : Always 7*/ + jp2_struct->UnkC = 0; /* UnkC, colorspace specified in colr box*/ + jp2_struct->IPR = 0; /* IPR, no intellectual property*/ + jp2_struct->w = parameters->w; + jp2_struct->h = parameters->h; + jp2_struct->bpc = 7; + jp2_struct->meth = 1; + jp2_struct->enumcs = 18; // YUV + } +} + +void mj2_destroy_compress(opj_mj2_t *movie) { + if(movie) { + int i; + mj2_tk_t *tk=NULL; + + if (movie->cinfo->j2k_handle) { + j2k_destroy_compress(movie->j2k); + } + + if (movie->num_cl != 0) + opj_free(movie->cl); + + for (i = 0; i < movie->num_vtk + movie->num_stk + movie->num_htk; i++) { + tk = &movie->tk[i]; + if (tk->name_size != 0) + opj_free(tk->name); + if (tk->track_type == 0) {// Video track + if (tk->jp2_struct.comps != 0) + opj_free(tk->jp2_struct.comps); + if (tk->jp2_struct.cl != 0) + opj_free(tk->jp2_struct.cl); + if (tk->num_jp2x != 0) + opj_free(tk->jp2xdata); + + } + if (tk->num_url != 0) + opj_free(tk->url); + if (tk->num_urn != 0) + opj_free(tk->urn); + if (tk->num_br != 0) + opj_free(tk->br); + if (tk->num_tts != 0) + opj_free(tk->tts); + if (tk->num_chunks != 0) + opj_free(tk->chunk); + if (tk->num_samplestochunk != 0) + opj_free(tk->sampletochunk); + if (tk->num_samples != 0) + opj_free(tk->sample); + } + + opj_free(movie->tk); + } + opj_free(movie); +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/mj2/mj2.h b/gdcm/Utilities/gdcmopenjpeg-v2/mj2/mj2.h new file mode 100644 index 0000000..2903c7a --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/mj2/mj2.h @@ -0,0 +1,391 @@ +/* +* Copyright (c) 2003-2004, François-Olivier Devaux +* Copyright (c) 2003-2004, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium +* All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MJ2_H +#define __MJ2_H +/** +@file mj2.h +@brief The Motion JPEG 2000 file format Reader/Writer (MJ22) + +*/ + +/** @defgroup MJ2 MJ2 - Motion JPEG 2000 file format reader/writer */ +/*@{*/ + +#define MJ2_JP 0x6a502020 +#define MJ2_FTYP 0x66747970 +#define MJ2_MJ2 0x6d6a7032 +#define MJ2_MJ2S 0x6d6a3273 +#define MJ2_MDAT 0x6d646174 +#define MJ2_MOOV 0x6d6f6f76 +#define MJ2_MVHD 0x6d766864 +#define MJ2_TRAK 0x7472616b +#define MJ2_TKHD 0x746b6864 +#define MJ2_MDIA 0x6d646961 +#define MJ2_MDHD 0x6d646864 +#define MJ2_MHDR 0x6d686472 +#define MJ2_HDLR 0x68646C72 +#define MJ2_MINF 0x6d696e66 +#define MJ2_VMHD 0x766d6864 +#define MJ2_SMHD 0x736d6864 +#define MJ2_HMHD 0x686d6864 +#define MJ2_DINF 0x64696e66 +#define MJ2_DREF 0x64726566 +#define MJ2_URL 0x75726c20 +#define MJ2_URN 0x75726e20 +#define MJ2_STBL 0x7374626c +#define MJ2_STSD 0x73747364 +#define MJ2_STTS 0x73747473 +#define MJ2_STSC 0x73747363 +#define MJ2_STSZ 0x7374737a +#define MJ2_STCO 0x7374636f +#define MJ2_MOOF 0x6d6f6f66 +#define MJ2_FREE 0x66726565 +#define MJ2_SKIP 0x736b6970 +#define MJ2_JP2C 0x6a703263 +#define MJ2_FIEL 0x6669656c +#define MJ2_JP2P 0x6a703270 +#define MJ2_JP2X 0x6a703278 +#define MJ2_JSUB 0x6a737562 +#define MJ2_ORFO 0x6f72666f +#define MJ2_MVEX 0x6d766578 +#define MJ2_JP2 0x6a703220 +#define MJ2_J2P0 0x4a325030 + +/** +Decompressed format used in parameters +YUV = 0 +*/ +#define YUV_DFMT 1 + +/** +Compressed format used in parameters +MJ2 = 0 +*/ +#define MJ2_CFMT 2 + + +/* ----------------------------------------------------------------------- */ + +/** +Time To Sample +*/ +typedef struct mj2_tts { + int sample_count; + int sample_delta; +} mj2_tts_t; + +/** +Chunk +*/ +typedef struct mj2_chunk { + int num_samples; + int sample_descr_idx; + int offset; +} mj2_chunk_t; + +/** +Sample to chunk +*/ +typedef struct mj2_sampletochunk { + int first_chunk; + int samples_per_chunk; + int sample_descr_idx; +} mj2_sampletochunk_t; + +/** +Sample +*/ +typedef struct mj2_sample { + unsigned int sample_size; + unsigned int offset; + unsigned int sample_delta; +} mj2_sample_t; + +/** +URL +*/ +typedef struct mj2_url { + int location[4]; +} mj2_url_t; + +/** +URN +*/ +typedef struct mj2_urn { + int name[2]; + int location[4]; +} mj2_urn_t; + +/** +Video Track Parameters +*/ +typedef struct mj2_tk { + /** codec context */ + opj_common_ptr cinfo; + int track_ID; + int track_type; + unsigned int creation_time; + unsigned int modification_time; + int duration; + int timescale; + int layer; + int volume; + int language; + int balance; + int maxPDUsize; + int avgPDUsize; + int maxbitrate; + int avgbitrate; + int slidingavgbitrate; + int graphicsmode; + int opcolor[3]; + int num_url; + mj2_url_t *url; + int num_urn; + mj2_urn_t *urn; + int Dim[2]; + int w; + int h; + int visual_w; + int visual_h; + int CbCr_subsampling_dx; + int CbCr_subsampling_dy; + int sample_rate; + int sample_description; + int horizresolution; + int vertresolution; + int compressorname[8]; + int depth; + unsigned char fieldcount; + unsigned char fieldorder; + unsigned char or_fieldcount; + unsigned char or_fieldorder; + int num_br; + unsigned int *br; + unsigned char num_jp2x; + unsigned char *jp2xdata; + unsigned char hsub; + unsigned char vsub; + unsigned char hoff; + unsigned char voff; + int trans_matrix[9]; + /** Number of samples */ + unsigned int num_samples; + int transorm; + int handler_type; + int name_size; + unsigned char same_sample_size; + int num_tts; + /** Time to sample */ + mj2_tts_t *tts; + unsigned int num_chunks; + mj2_chunk_t *chunk; + int num_samplestochunk; + mj2_sampletochunk_t *sampletochunk; + char *name; + opj_jp2_t jp2_struct; + /** Sample parameters */ + mj2_sample_t *sample; +} mj2_tk_t; + +/** +MJ2 box +*/ +typedef struct mj2_box { + int length; + int type; + int init_pos; +} mj2_box_t; + +/** +MJ2 Movie +*/ +typedef struct opj_mj2 { + /** codec context */ + opj_common_ptr cinfo; + /** handle to the J2K codec */ + opj_j2k_t *j2k; + unsigned int brand; + unsigned int minversion; + int num_cl; + unsigned int *cl; + unsigned int creation_time; + unsigned int modification_time; + int timescale; + unsigned int duration; + int rate; + int num_vtk; + int num_stk; + int num_htk; + int volume; + int trans_matrix[9]; + int next_tk_id; + /** Track Parameters */ + mj2_tk_t *tk; +} opj_mj2_t; + +/** +Decompression parameters +*/ +typedef struct mj2_dparameters { + /**@name command line encoder parameters (not used inside the library) */ + /*@{*/ + /** input file name */ + char infile[OPJ_PATH_LEN]; + /** output file name */ + char outfile[OPJ_PATH_LEN]; + /** J2K decompression parameters */ + opj_dparameters_t j2k_parameters; +} mj2_dparameters_t; + +/** +Compression parameters +*/ +typedef struct mj2_cparameters { + /**@name command line encoder parameters (not used inside the library) */ + /*@{*/ + /** J2K compression parameters */ + opj_cparameters_t j2k_parameters; + /** input file name */ + char infile[OPJ_PATH_LEN]; + /** output file name */ + char outfile[OPJ_PATH_LEN]; + /** input file format 0:MJ2 */ + int decod_format; + /** output file format 0:YUV */ + int cod_format; + /** Portion of the image coded */ + int Dim[2]; + /** YUV Frame width */ + int w; + /** YUV Frame height */ + int h; + /* Sample rate of YUV 4:4:4, 4:2:2 or 4:2:0 */ + int CbCr_subsampling_dx; + /* Sample rate of YUV 4:4:4, 4:2:2 or 4:2:0 */ + int CbCr_subsampling_dy; + /* Video Frame Rate */ + int frame_rate; + /* In YUV files, numcomps always considered as 3 */ + int numcomps; + /* In YUV files, precision always considered as 8 */ + int prec; +} mj2_cparameters_t; + + +/** @name Exported functions */ +/*@{*/ +/* ----------------------------------------------------------------------- */ +/** +Write the JP box +*/ +void mj2_write_jp(opj_cio_t *cio); +/** +Write the FTYP box +@param movie MJ2 movie +@param cio Output buffer stream +*/ +void mj2_write_ftyp(opj_mj2_t *movie, opj_cio_t *cio); +/** +Creates an MJ2 decompression structure +@return Returns a handle to a MJ2 decompressor if successful, returns NULL otherwise +*/ +opj_dinfo_t* mj2_create_decompress(); +/** +Destroy a MJ2 decompressor handle +@param movie MJ2 decompressor handle to destroy +*/ +void mj2_destroy_decompress(opj_mj2_t *movie); +/** +Setup the decoder decoding parameters using user parameters. +Decoding parameters are returned in mj2->j2k->cp. +@param movie MJ2 decompressor handle +@param parameters decompression parameters +*/ +void mj2_setup_decoder(opj_mj2_t *movie, mj2_dparameters_t *mj2_parameters); +/** +Decode an image from a JPEG-2000 file stream +@param movie MJ2 decompressor handle +@param cio Input buffer stream +@return Returns a decoded image if successful, returns NULL otherwise +*/ +opj_image_t* mj2_decode(opj_mj2_t *movie, opj_cio_t *cio); +/** +Creates a MJ2 compression structure +@return Returns a handle to a MJ2 compressor if successful, returns NULL otherwise +*/ +opj_cinfo_t* mj2_create_compress(); +/** +Destroy a MJ2 compressor handle +@param movie MJ2 compressor handle to destroy +*/ +void mj2_destroy_compress(opj_mj2_t *movie); +/** +Setup the encoder parameters using the current image and using user parameters. +Coding parameters are returned in mj2->j2k->cp. +@param movie MJ2 compressor handle +@param parameters compression parameters +*/ +void mj2_setup_encoder(opj_mj2_t *movie, mj2_cparameters_t *parameters); +/** +Encode an image into a JPEG-2000 file stream +@param movie MJ2 compressor handle +@param cio Output buffer stream +@param image Image to encode +@param index Name of the index file if required, NULL otherwise +@return Returns true if successful, returns false otherwise +*/ +bool mj2_encode(opj_mj2_t *movie, opj_cio_t *cio, opj_image_t *image, char *index); + +/** +Init a Standard MJ2 movie +@param movie MJ2 Movie +@return Returns 0 if successful, returns 1 otherwise +*/ +int mj2_init_stdmovie(opj_mj2_t *movie); +/** +Read the structure of an MJ2 file +@param File MJ2 input File +@param movie J2 movie structure +@return Returns 0 if successful, returns 1 otherwise +*/ +int mj2_read_struct(FILE *file, opj_mj2_t *mj2); +/** +Write the the MOOV box to an output buffer stream +@param movie MJ2 movie structure +@param cio Output buffer stream +*/ +void mj2_write_moov(opj_mj2_t *movie, opj_cio_t *cio); + + +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __MJ2_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/mj2/mj2_convert.c b/gdcm/Utilities/gdcmopenjpeg-v2/mj2/mj2_convert.c new file mode 100644 index 0000000..6b2b65a --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/mj2/mj2_convert.c @@ -0,0 +1,329 @@ +/* +* Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium +* Copyright (c) 2002-2007, Professor Benoit Macq +* Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "opj_includes.h" +#include "mj2.h" + +/* ----------------------- */ +/* */ +/* */ +/* Count the number of frames */ +/* in a YUV file */ +/* */ +/* ----------------------- */ + +int yuv_num_frames(mj2_tk_t * tk, char *infile) +{ + int numimages, frame_size; + long end_of_f; + FILE *f; + + f = fopen(infile,"rb"); + if (!f) { + fprintf(stderr, "failed to open %s for reading\n",infile); + return -1; + } + + frame_size = (int) (tk->w * tk->h * (1.0 + (double) 2 / (double) (tk->CbCr_subsampling_dx * tk->CbCr_subsampling_dy))); /* Calculate frame size */ + + fseek(f, 0, SEEK_END); + end_of_f = ftell(f); /* Calculate file size */ + + if (end_of_f < frame_size) { + fprintf(stderr, + "YUV does not contains any frame of %d x %d size\n", tk->w, + tk->h); + return -1; + } + + numimages = end_of_f / frame_size; /* Calculate number of images */ + fclose(f); + + return numimages; +} + +// ----------------------- +// +// +// YUV to IMAGE +// +// ----------------------- + +opj_image_t *mj2_image_create(mj2_tk_t * tk, opj_cparameters_t *parameters) +{ + opj_image_cmptparm_t cmptparm[3]; + opj_image_t * img; + int i; + int numcomps = 3; + int subsampling_dx = parameters->subsampling_dx; + int subsampling_dy = parameters->subsampling_dy; + + /* initialize image components */ + memset(&cmptparm[0], 0, 3 * sizeof(opj_image_cmptparm_t)); + for(i = 0; i < numcomps; i++) { + cmptparm[i].prec = 8; + cmptparm[i].bpp = 8; + cmptparm[i].sgnd = 0; + cmptparm[i].dx = i ? subsampling_dx * tk->CbCr_subsampling_dx : subsampling_dx; + cmptparm[i].dy = i ? subsampling_dy * tk->CbCr_subsampling_dy : subsampling_dy; + cmptparm[i].w = tk->w; + cmptparm[i].h = tk->h; + } + /* create the image */ + img = opj_image_create(numcomps, cmptparm, CLRSPC_SRGB); + return img; +} + +char yuvtoimage(mj2_tk_t * tk, opj_image_t * img, int frame_num, opj_cparameters_t *parameters, char* infile) +{ + int i, compno; + int offset; + long end_of_f, position; + int numcomps = 3; + int subsampling_dx = parameters->subsampling_dx; + int subsampling_dy = parameters->subsampling_dy; + FILE *yuvfile; + + yuvfile = fopen(infile,"rb"); + if (!yuvfile) { + fprintf(stderr, "failed to open %s for readings\n",parameters->infile); + return 1; + } + + offset = (int) ((double) (frame_num * tk->w * tk->h) * (1.0 + + 1.0 * (double) 2 / (double) (tk->CbCr_subsampling_dx * tk->CbCr_subsampling_dy))); + fseek(yuvfile, 0, SEEK_END); + end_of_f = ftell(yuvfile); + fseek(yuvfile, sizeof(unsigned char) * offset, SEEK_SET); + position = ftell(yuvfile); + if (position >= end_of_f) { + fprintf(stderr, "Cannot reach frame number %d in yuv file !!\n", + frame_num); + fclose(yuvfile); + return 1; + } + + img->x0 = tk->Dim[0]; + img->y0 = tk->Dim[1]; + img->x1 = !tk->Dim[0] ? (tk->w - 1) * subsampling_dx + 1 : tk->Dim[0] + + (tk->w - 1) * subsampling_dx + 1; + img->y1 = !tk->Dim[1] ? (tk->h - 1) * subsampling_dy + 1 : tk->Dim[1] + + (tk->h - 1) * subsampling_dy + 1; + + for(compno = 0; compno < numcomps; compno++) { + for (i = 0; i < (tk->w * tk->h / (img->comps[compno].dx * img->comps[compno].dy)) + && !feof(yuvfile); i++) { + if (!fread(&img->comps[compno].data[i], 1, 1, yuvfile)) { + fprintf(stderr, "Error reading %s file !!\n", infile); + return 1; + } + } + } + fclose(yuvfile); + + return 0; +} + + + +// ----------------------- +// +// +// IMAGE to YUV +// +// ----------------------- + + +bool imagetoyuv(opj_image_t * img, char *outfile) +{ + FILE *f; + int i; + + if (img->numcomps == 3) { + if (img->comps[0].dx != img->comps[1].dx / 2 + || img->comps[1].dx != img->comps[2].dx) { + fprintf(stderr, + "Error with the input image components size: cannot create yuv file)\n"); + return false; + } + } else if (!(img->numcomps == 1)) { + fprintf(stderr, + "Error with the number of image components(must be one or three)\n"); + return false; + } + + f = fopen(outfile, "a+b"); + if (!f) { + fprintf(stderr, "failed to open %s for writing\n", outfile); + return false; + } + + + for (i = 0; i < (img->comps[0].w * img->comps[0].h); i++) { + unsigned char y; + y = img->comps[0].data[i]; + fwrite(&y, 1, 1, f); + } + + + if (img->numcomps == 3) { + for (i = 0; i < (img->comps[1].w * img->comps[1].h); i++) { + unsigned char cb; + cb = img->comps[1].data[i]; + fwrite(&cb, 1, 1, f); + } + + + for (i = 0; i < (img->comps[2].w * img->comps[2].h); i++) { + unsigned char cr; + cr = img->comps[2].data[i]; + fwrite(&cr, 1, 1, f); + } + } else if (img->numcomps == 1) { + for (i = 0; i < (img->comps[0].w * img->comps[0].h * 0.25); i++) { + unsigned char cb = 125; + fwrite(&cb, 1, 1, f); + } + + + for (i = 0; i < (img->comps[0].w * img->comps[0].h * 0.25); i++) { + unsigned char cr = 125; + fwrite(&cr, 1, 1, f); + } + } + fclose(f); + return true; +} + +// ----------------------- +// +// +// IMAGE to BMP +// +// ----------------------- + +int imagetobmp(opj_image_t * img, char *outfile) { + int w,wr,h,hr,i,pad; + FILE *f; + + if (img->numcomps == 3 && img->comps[0].dx == img->comps[1].dx + && img->comps[1].dx == img->comps[2].dx + && img->comps[0].dy == img->comps[1].dy + && img->comps[1].dy == img->comps[2].dy + && img->comps[0].prec == img->comps[1].prec + && img->comps[1].prec == img->comps[2].prec) { + /* -->> -->> -->> -->> + + 24 bits color + + <<-- <<-- <<-- <<-- */ + + f = fopen(outfile, "wb"); + if (!f) { + fprintf(stderr, "failed to open %s for writing\n", outfile); + return 1; + } + + w = img->comps[0].w; + wr = int_ceildivpow2(img->comps[0].w, img->comps[0].factor); + + h = img->comps[0].h; + hr = int_ceildivpow2(img->comps[0].h, img->comps[0].factor); + + fprintf(f, "BM"); + + /* FILE HEADER */ + /* ------------- */ + fprintf(f, "%c%c%c%c", + (unsigned char) (hr * wr * 3 + 3 * hr * (wr % 2) + + 54) & 0xff, + (unsigned char) ((hr * wr * 3 + 3 * hr * (wr % 2) + 54) + >> 8) & 0xff, + (unsigned char) ((hr * wr * 3 + 3 * hr * (wr % 2) + 54) + >> 16) & 0xff, + (unsigned char) ((hr * wr * 3 + 3 * hr * (wr % 2) + 54) + >> 24) & 0xff); + fprintf(f, "%c%c%c%c", (0) & 0xff, ((0) >> 8) & 0xff, + ((0) >> 16) & 0xff, ((0) >> 24) & 0xff); + fprintf(f, "%c%c%c%c", (54) & 0xff, ((54) >> 8) & 0xff, + ((54) >> 16) & 0xff, ((54) >> 24) & 0xff); + + /* INFO HEADER */ + /* ------------- */ + fprintf(f, "%c%c%c%c", (40) & 0xff, ((40) >> 8) & 0xff, + ((40) >> 16) & 0xff, ((40) >> 24) & 0xff); + fprintf(f, "%c%c%c%c", (unsigned char) ((wr) & 0xff), + (unsigned char) ((wr) >> 8) & 0xff, + (unsigned char) ((wr) >> 16) & 0xff, + (unsigned char) ((wr) >> 24) & 0xff); + fprintf(f, "%c%c%c%c", (unsigned char) ((hr) & 0xff), + (unsigned char) ((hr) >> 8) & 0xff, + (unsigned char) ((hr) >> 16) & 0xff, + (unsigned char) ((hr) >> 24) & 0xff); + fprintf(f, "%c%c", (1) & 0xff, ((1) >> 8) & 0xff); + fprintf(f, "%c%c", (24) & 0xff, ((24) >> 8) & 0xff); + fprintf(f, "%c%c%c%c", (0) & 0xff, ((0) >> 8) & 0xff, + ((0) >> 16) & 0xff, ((0) >> 24) & 0xff); + fprintf(f, "%c%c%c%c", + (unsigned char) (3 * hr * wr + + 3 * hr * (wr % 2)) & 0xff, + (unsigned char) ((hr * wr * 3 + 3 * hr * (wr % 2)) >> + 8) & 0xff, + (unsigned char) ((hr * wr * 3 + 3 * hr * (wr % 2)) >> + 16) & 0xff, + (unsigned char) ((hr * wr * 3 + 3 * hr * (wr % 2)) >> + 24) & 0xff); + fprintf(f, "%c%c%c%c", (7834) & 0xff, ((7834) >> 8) & 0xff, + ((7834) >> 16) & 0xff, ((7834) >> 24) & 0xff); + fprintf(f, "%c%c%c%c", (7834) & 0xff, ((7834) >> 8) & 0xff, + ((7834) >> 16) & 0xff, ((7834) >> 24) & 0xff); + fprintf(f, "%c%c%c%c", (0) & 0xff, ((0) >> 8) & 0xff, + ((0) >> 16) & 0xff, ((0) >> 24) & 0xff); + fprintf(f, "%c%c%c%c", (0) & 0xff, ((0) >> 8) & 0xff, + ((0) >> 16) & 0xff, ((0) >> 24) & 0xff); + + for (i = 0; i < wr * hr; i++) { + unsigned char R, G, B; + /* a modifier */ + // R = img->comps[0].data[w * h - ((i) / (w) + 1) * w + (i) % (w)]; + R = img->comps[0].data[w * hr - ((i) / (wr) + 1) * w + (i) % (wr)]; + // G = img->comps[1].data[w * h - ((i) / (w) + 1) * w + (i) % (w)]; + G = img->comps[1].data[w * hr - ((i) / (wr) + 1) * w + (i) % (wr)]; + // B = img->comps[2].data[w * h - ((i) / (w) + 1) * w + (i) % (w)]; + B = img->comps[2].data[w * hr - ((i) / (wr) + 1) * w + (i) % (wr)]; + fprintf(f, "%c%c%c", B, G, R); + + if ((i + 1) % wr == 0) { + for (pad = (3 * wr) % 4 ? 4 - (3 * wr) % 4 : 0; pad > 0; pad--) /* ADD */ + fprintf(f, "%c", 0); + } + } + fclose(f); + } + return 0; +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/mj2/mj2_convert.h b/gdcm/Utilities/gdcmopenjpeg-v2/mj2/mj2_convert.h new file mode 100644 index 0000000..78e6c47 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/mj2/mj2_convert.h @@ -0,0 +1,45 @@ +/* +* Copyright (c) 2003-2004, François-Olivier Devaux +* Copyright (c) 2002-2004, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "mj2.h" + +#ifndef __MJ2_CONVERT_H +#define __MJ2_CONVERT_H + +int imagetoyuv(opj_image_t * img, char *outfile); + +int imagetobmp(opj_image_t * img, char *outfile); + +opj_image_t *mj2_image_create(mj2_tk_t * tk, opj_cparameters_t *parameters); + +char yuvtoimage(mj2_tk_t * tk, opj_image_t * img, int frame_num, opj_cparameters_t *parameters, char* infile); + +int yuv_num_frames(mj2_tk_t * tk, char *infile); + + +#endif diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/mj2/mj2_to_frames.c b/gdcm/Utilities/gdcmopenjpeg-v2/mj2/mj2_to_frames.c new file mode 100644 index 0000000..73fee46 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/mj2/mj2_to_frames.c @@ -0,0 +1,225 @@ +/* +* Copyright (c) 2003-2004, François-Olivier Devaux +* Copyright (c) 2002-2004, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include + +#include "openjpeg.h" +#include "j2k_lib.h" +#include "j2k.h" +#include "jp2.h" +#include "mj2.h" +#include "mj2_convert.h" + +/* -------------------------------------------------------------------------- */ + +/** +sample error callback expecting a FILE* client object +*/ +void error_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[ERROR] %s", msg); +} +/** +sample warning callback expecting a FILE* client object +*/ +void warning_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[WARNING] %s", msg); +} +/** +sample debug callback expecting a FILE* client object +*/ +void info_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[INFO] %s", msg); +} + +/* -------------------------------------------------------------------------- */ + + +int main(int argc, char *argv[]) { + mj2_dparameters_t mj2_parameters; /* decompression parameters */ + opj_dinfo_t* dinfo; + opj_event_mgr_t event_mgr; /* event manager */ + opj_cio_t *cio = NULL; + unsigned int tnum, snum; + opj_mj2_t *movie; + mj2_tk_t *track; + mj2_sample_t *sample; + unsigned char* frame_codestream; + FILE *file, *outfile; + char outfilename[50]; + opj_image_t *img = NULL; + unsigned int max_codstrm_size = 0; + double total_time = 0; + unsigned int numframes = 0; + + if (argc != 3) { + printf("Bad syntax: Usage: mj2_to_frames inputfile.mj2 outputfile.yuv\n"); + printf("Example: MJ2_decoder foreman.mj2 foreman.yuv\n"); + return 1; + } + + file = fopen(argv[1], "rb"); + + if (!file) { + fprintf(stderr, "failed to open %s for reading\n", argv[1]); + return 1; + } + + // Checking output file + outfile = fopen(argv[2], "w"); + if (!file) { + fprintf(stderr, "failed to open %s for writing\n", argv[2]); + return 1; + } + fclose(outfile); + + /* + configure the event callbacks (not required) + setting of each callback is optionnal + */ + memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); + event_mgr.error_handler = error_callback; + event_mgr.warning_handler = warning_callback; + event_mgr.info_handler = NULL; + + /* get a MJ2 decompressor handle */ + dinfo = mj2_create_decompress(); + movie = dinfo->mj2_handle; + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr); + + /* set J2K decoding parameters to default values */ + opj_set_default_decoder_parameters(&mj2_parameters.j2k_parameters); + + /* setup the decoder decoding parameters using user parameters */ + mj2_setup_decoder(dinfo->mj2_handle, &mj2_parameters); + + if (mj2_read_struct(file, movie)) // Creating the movie structure + return 1; + + // Decode first video track + for (tnum=0; tnum < (unsigned int)(movie->num_htk + movie->num_stk + movie->num_vtk); tnum++) { + if (movie->tk[tnum].track_type == 0) + break; + } + + if (movie->tk[tnum].track_type != 0) { + printf("Error. Movie does not contain any video track\n"); + return 1; + } + + track = &movie->tk[tnum]; + + // Output info on first video tracl + fprintf(stdout,"The first video track contains %d frames.\nWidth: %d, Height: %d \n\n", + track->num_samples, track->w, track->h); + + max_codstrm_size = track->sample[0].sample_size-8; + frame_codestream = (unsigned char*) malloc(max_codstrm_size * sizeof(unsigned char)); + + numframes = track->num_samples; + + for (snum=0; snum < numframes; snum++) + { + double init_time = opj_clock(); + double elapsed_time; + + sample = &track->sample[snum]; + if (sample->sample_size-8 > max_codstrm_size) { + max_codstrm_size = sample->sample_size-8; + if ((frame_codestream = realloc(frame_codestream, max_codstrm_size)) == NULL) { + printf("Error reallocation memory\n"); + return 1; + }; + } + fseek(file,sample->offset+8,SEEK_SET); + fread(frame_codestream, sample->sample_size-8, 1, file); // Assuming that jp and ftyp markers size do + + /* open a byte stream */ + cio = opj_cio_open((opj_common_ptr)dinfo, frame_codestream, sample->sample_size-8); + + img = opj_decode(dinfo, cio); // Decode J2K to image + + if (((img->numcomps == 3) && (img->comps[0].dx == img->comps[1].dx / 2) + && (img->comps[0].dx == img->comps[2].dx / 2 ) && (img->comps[0].dx == 1)) + || (img->numcomps == 1)) { + + if (!imagetoyuv(img, argv[2])) // Convert image to YUV + return 1; + } + else if ((img->numcomps == 3) && + (img->comps[0].dx == 1) && (img->comps[1].dx == 1)&& + (img->comps[2].dx == 1))// If YUV 4:4:4 input --> to bmp + { + fprintf(stdout,"The frames will be output in a bmp format (output_1.bmp, ...)\n"); + sprintf(outfilename,"output_%d.bmp",snum); + if (imagetobmp(img, outfilename)) // Convert image to BMP + return 1; + + } + else { + fprintf(stdout,"Image component dimensions are unknown. Unable to output image\n"); + fprintf(stdout,"The frames will be output in a j2k file (output_1.j2k, ...)\n"); + + sprintf(outfilename,"output_%d.j2k",snum); + outfile = fopen(outfilename, "wb"); + if (!outfile) { + fprintf(stderr, "failed to open %s for writing\n",outfilename); + return 1; + } + fwrite(frame_codestream,sample->sample_size-8,1,outfile); + fclose(outfile); + } + /* close the byte stream */ + opj_cio_close(cio); + /* free image data structure */ + opj_image_destroy(img); + elapsed_time = opj_clock()-init_time; + fprintf(stderr, "Frame number %d/%d decoded in %.2f mseconds\n", snum + 1, numframes, elapsed_time*1000); + total_time += elapsed_time; + + } + + free(frame_codestream); + fclose(file); + + /* free remaining structures */ + if(dinfo) { + mj2_destroy_decompress((opj_mj2_t*)dinfo->mj2_handle); + } + free(dinfo); + + fprintf(stdout, "%d frame(s) correctly decompressed\n", snum); + fprintf(stdout,"Total decoding time: %.2f seconds (%.1f fps)\n", total_time, (float)numframes/total_time); + + return 0; +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/mj2/mj2_to_metadata.c b/gdcm/Utilities/gdcmopenjpeg-v2/mj2/mj2_to_metadata.c new file mode 100644 index 0000000..9a326ef --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/mj2/mj2_to_metadata.c @@ -0,0 +1,312 @@ +/* mj2_to_metadata.c */ +/* Dump MJ2, JP2 metadata (partial so far) to xml file */ +/* Contributed to Open JPEG by Glenn Pearson, contract software developer, U.S. National Library of Medicine. + +The base code in this file was developed by the author as part of a video archiving +project for the U.S. National Library of Medicine, Bethesda, MD. +It is the policy of NLM (and U.S. government) to not assert copyright. + +A non-exclusive copy of this code has been contributed to the Open JPEG project. +Except for copyright, inclusion of the code within Open JPEG for distribution and use +can be bound by the Open JPEG open-source license and disclaimer, expressed elsewhere. +*/ + +#include "opj_includes.h" +#include "mj2.h" + +#include "mj2_to_metadata.h" +#include +#include "compat/getopt.h" + +/* -------------------------------------------------------------------------- */ + +/** +sample error callback expecting a FILE* client object +*/ +void error_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[ERROR] %s", msg); +} +/** +sample warning callback expecting a FILE* client object +*/ +void warning_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[WARNING] %s", msg); +} +/** +sample debug callback expecting a FILE* client object +*/ +void info_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[INFO] %s", msg); +} + +/* -------------------------------------------------------------------------- */ + + + +/* ------------- */ + +void help_display() +{ + /* "1234567890123456789012345678901234567890123456789012345678901234567890123456789" */ + fprintf(stdout," Help for the 'mj2_to_metadata' Program\n"); + fprintf(stdout," ======================================\n"); + fprintf(stdout,"The -h option displays this information on screen.\n\n"); + + fprintf(stdout,"mj2_to_metadata generates an XML file from a Motion JPEG 2000 file.\n"); + fprintf(stdout,"The generated XML shows the structural, but not (yet) curatorial,\n"); + fprintf(stdout,"metadata from the movie header and from the JPEG 2000 image and tile\n"); + fprintf(stdout,"headers of a sample frame. Excluded: low-level packed-bits image data.\n\n"); + + fprintf(stdout,"By Default\n"); + fprintf(stdout,"----------\n"); + fprintf(stdout,"The metadata includes the jp2 image and tile headers of the first frame.\n"); + fprintf(stdout,"\n"); + fprintf(stdout,"Metadata values are shown in 'raw' form (e.g., hexidecimal) as stored in the\n"); + fprintf(stdout,"file, and, if apt, in a 'derived' form that is more quickly grasped.\n"); + fprintf(stdout,"\n"); + fprintf(stdout,"Notes explaining the XML are embedded as terse comments. These include\n"); + fprintf(stdout," meaning of non-obvious tag abbreviations;\n"); + fprintf(stdout," range and precision of valid values;\n"); + fprintf(stdout," interpretations of values, such as enumerations; and\n"); + fprintf(stdout," current implementation limitations.\n"); + fprintf(stdout,"\n"); + fprintf(stdout,"The sample-size and chunk-offset tables, each with 1 row per frame, are not reported.\n"); + fprintf(stdout,"\n"); + fprintf(stdout,"The file is self-contained and no verification (e.g., against a DTD) is requested.\n"); + fprintf(stdout,"\n"); + fprintf(stdout,"Required Parameters (except with -h)\n"); + fprintf(stdout,"------------------------------------\n"); + fprintf(stdout,"[Caution: file strings that contain spaces should be wrapped with quotes.]\n"); + fprintf(stdout,"-i input.mj2 : where 'input' is any source file name or path.\n"); + fprintf(stdout," MJ2 files created with 'frames_to_mj2' are supported so far.\n"); + fprintf(stdout," These are silent, single-track, 'MJ2 Simple Profile' videos.\n"); + fprintf(stdout,"-o output.xml : where 'output' is any destination file name or path.\n"); + fprintf(stdout,"\n"); + fprintf(stdout,"Optional Parameters\n"); + fprintf(stdout,"-------------------\n"); + fprintf(stdout,"-h : Display this help information.\n"); + fprintf(stdout,"-n : Suppress all mj2_to_metadata notes.\n"); + fprintf(stdout,"-t : Include sample-size and chunk-offset tables.\n"); + fprintf(stdout,"-f n : where n > 0. Include jp2 header info for frame n [default=1].\n"); + fprintf(stdout,"-f 0 : No jp2 header info.\n"); + fprintf(stdout,"-r : Suppress all 'raw' data for which a 'derived' form exists.\n"); + fprintf(stdout,"-d : Suppress all 'derived' data.\n"); + fprintf(stdout," (If both -r and -d given, -r will be ignored.)\n"); + fprintf(stdout,"-v string : Verify against the DTD file located by the string.\n"); + fprintf(stdout," Prepend quoted 'string' with either SYSTEM or PUBLIC keyword.\n"); + fprintf(stdout," Thus, for the distributed DTD placed in the same directory as\n"); + fprintf(stdout," the output file: -v \"SYSTEM mj2_to_metadata.dtd\"\n"); + fprintf(stdout," \"PUBLIC\" is used with an access protocol (e.g., http:) + URL.\n"); + /* More to come */ + fprintf(stdout,"\n"); + /* "1234567890123456789012345678901234567890123456789012345678901234567890123456789" */ +} + +/* ------------- */ + +int main(int argc, char *argv[]) { + + opj_dinfo_t* dinfo; + opj_event_mgr_t event_mgr; /* event manager */ + + FILE *file, *xmlout; +/* char xmloutname[50]; */ + opj_mj2_t *movie; + + char* infile = 0; + char* outfile = 0; + char* s, S1, S2, S3; + int len; + unsigned int sampleframe = 1; /* First frame */ + char* stringDTD = NULL; + BOOL notes = TRUE; + BOOL sampletables = FALSE; + BOOL raw = TRUE; + BOOL derived = TRUE; + mj2_dparameters_t parameters; + + while (TRUE) { + /* ':' after letter means it takes an argument */ + int c = getopt(argc, argv, "i:o:f:v:hntrd"); + /* FUTURE: Reserve 'p' for pruning file (which will probably make -t redundant) */ + if (c == -1) + break; + switch (c) { + case 'i': /* IN file */ + infile = optarg; + s = optarg; + while (*s) { s++; } /* Run to filename end */ + s--; + S3 = *s; + s--; + S2 = *s; + s--; + S1 = *s; + + if ((S1 == 'm' && S2 == 'j' && S3 == '2') + || (S1 == 'M' && S2 == 'J' && S3 == '2')) { + break; + } + fprintf(stderr, "Input file name must have .mj2 extension, not .%c%c%c.\n", S1, S2, S3); + return 1; + + /* ----------------------------------------------------- */ + case 'o': /* OUT file */ + outfile = optarg; + while (*outfile) { outfile++; } /* Run to filename end */ + outfile--; + S3 = *outfile; + outfile--; + S2 = *outfile; + outfile--; + S1 = *outfile; + + outfile = optarg; + + if ((S1 == 'x' && S2 == 'm' && S3 == 'l') + || (S1 == 'X' && S2 == 'M' && S3 == 'L')) + break; + + fprintf(stderr, + "Output file name must have .xml extension, not .%c%c%c\n", S1, S2, S3); + return 1; + + /* ----------------------------------------------------- */ + case 'f': /* Choose sample frame. 0 = none */ + sscanf(optarg, "%u", &sampleframe); + break; + + /* ----------------------------------------------------- */ + case 'v': /* Verification by DTD. */ + stringDTD = optarg; + /* We will not insist upon last 3 chars being "dtd", since non-file + access protocol may be used. */ + if(strchr(stringDTD,'"') != NULL) { + fprintf(stderr, "-D's string must not contain any embedded double-quote characters.\n"); + return 1; + } + + if (strncmp(stringDTD,"PUBLIC ",7) == 0 || strncmp(stringDTD,"SYSTEM ",7) == 0) + break; + + fprintf(stderr, "-D's string must start with \"PUBLIC \" or \"SYSTEM \"\n"); + return 1; + + /* ----------------------------------------------------- */ + case 'n': /* Suppress comments */ + notes = FALSE; + break; + + /* ----------------------------------------------------- */ + case 't': /* Show sample size and chunk offset tables */ + sampletables = TRUE; + break; + + /* ----------------------------------------------------- */ + case 'h': /* Display an help description */ + help_display(); + return 0; + + /* ----------------------------------------------------- */ + case 'r': /* Suppress raw data */ + raw = FALSE; + break; + + /* ----------------------------------------------------- */ + case 'd': /* Suppress derived data */ + derived = FALSE; + break; + + /* ----------------------------------------------------- */ + default: + return 1; + } /* switch */ + } /* while */ + + if(!raw && !derived) + raw = TRUE; /* At least one of 'raw' and 'derived' must be true */ + + /* Error messages */ + /* -------------- */ + if (!infile || !outfile) { + fprintf(stderr,"Correct usage: mj2_to_metadata -i mj2-file -o xml-file (plus options)\n"); + return 1; + } + +/* was: + if (argc != 3) { + printf("Bad syntax: Usage: MJ2_to_metadata inputfile.mj2 outputfile.xml\n"); + printf("Example: MJ2_to_metadata foreman.mj2 foreman.xml\n"); + return 1; + } +*/ + len = strlen(infile); + if(infile[0] == ' ') + { + infile++; /* There may be a leading blank if user put space after -i */ + } + + file = fopen(infile, "rb"); /* was: argv[1] */ + + if (!file) { + fprintf(stderr, "Failed to open %s for reading.\n", infile); /* was: argv[1] */ + return 1; + } + + len = strlen(outfile); + if(outfile[0] == ' ') + { + outfile++; /* There may be a leading blank if user put space after -o */ + } + + // Checking output file + xmlout = fopen(outfile, "w"); /* was: argv[2] */ + if (!xmlout) { + fprintf(stderr, "Failed to open %s for writing.\n", outfile); /* was: argv[2] */ + return 1; + } + // Leave it open + + /* + configure the event callbacks (not required) + setting of each callback is optionnal + */ + memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); + event_mgr.error_handler = error_callback; + event_mgr.warning_handler = warning_callback; + event_mgr.info_handler = info_callback; + + /* get a MJ2 decompressor handle */ + dinfo = mj2_create_decompress(); + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr); + + /* setup the decoder decoding parameters using user parameters */ + movie = (opj_mj2_t*) dinfo->mj2_handle; + mj2_setup_decoder(dinfo->mj2_handle, ¶meters); + + if (mj2_read_struct(file, movie)) // Creating the movie structure + { + fclose(xmlout); + return 1; + } + + xml_write_init(notes, sampletables, raw, derived); + xml_write_struct(file, xmlout, movie, sampleframe, stringDTD, &event_mgr); + fclose(xmlout); + + fprintf(stderr,"Metadata correctly extracted to XML file \n");; + + /* free remaining structures */ + if(dinfo) { + mj2_destroy_decompress((opj_mj2_t*)dinfo->mj2_handle); + } + + return 0; +} + + diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/mj2/mj2_to_metadata.dtd b/gdcm/Utilities/gdcmopenjpeg-v2/mj2/mj2_to_metadata.dtd new file mode 100644 index 0000000..249de1a --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/mj2/mj2_to_metadata.dtd @@ -0,0 +1,425 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/mj2/mj2_to_metadata.h b/gdcm/Utilities/gdcmopenjpeg-v2/mj2/mj2_to_metadata.h new file mode 100644 index 0000000..f4c3491 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/mj2/mj2_to_metadata.h @@ -0,0 +1,9 @@ +/* mj2_to_metadata.h */ +/* Dump MJ2, JP2 metadata (partial so far) to xml file */ +/* Contributed to Open JPEG by Glenn Pearson, U.S. National Library of Medicine */ + +#define BOOL int +#define FALSE 0 +#define TRUE 1 + +#include "meta_out.h" diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/mj2/mj2_to_metadata_Notes.doc b/gdcm/Utilities/gdcmopenjpeg-v2/mj2/mj2_to_metadata_Notes.doc new file mode 100644 index 0000000000000000000000000000000000000000..05ccec2068dd5bff73cf83aab716406f6c1db099 GIT binary patch literal 35328 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 literal 0 HcmV?d00001 diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/mj2/readme.txt b/gdcm/Utilities/gdcmopenjpeg-v2/mj2/readme.txt new file mode 100644 index 0000000..29b8c86 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/mj2/readme.txt @@ -0,0 +1,3 @@ +Attention : the motion jpeg 2000 files currently only work with OpenJPEG v0.97 that you can find here : + +http://www.openjpeg.org/openjpeg_v097.tar.gz \ No newline at end of file diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/mj2/wrap_j2k_in_mj2.c b/gdcm/Utilities/gdcmopenjpeg-v2/mj2/wrap_j2k_in_mj2.c new file mode 100644 index 0000000..85ac294 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/mj2/wrap_j2k_in_mj2.c @@ -0,0 +1,368 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2003-2007, Francois-Olivier Devaux + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + +#include "openjpeg.h" +#include "j2k.h" +#include "jp2.h" +#include "cio.h" +#include "mj2.h" + +static int int_ceildiv(int a, int b) { + return (a + b - 1) / b; +} + +/** +Size of memory first allocated for MOOV box +*/ +#define TEMP_BUF 10000 + + +/* -------------------------------------------------------------------------- */ + +/** +sample error callback expecting a FILE* client object +*/ +void error_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[ERROR] %s", msg); +} +/** +sample warning callback expecting a FILE* client object +*/ +void warning_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[WARNING] %s", msg); +} +/** +sample debug callback expecting a FILE* client object +*/ +void info_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[INFO] %s", msg); +} + +/* -------------------------------------------------------------------------- */ + + + +static void read_siz_marker(FILE *file, opj_image_t *image) +{ + int len,i; + char buf, buf2[2]; + char *siz_buffer; + opj_cio_t *cio; + + fseek(file, 0, SEEK_SET); + do { + fread(&buf,1,1, file); + if (buf==(char)0xff) + fread(&buf,1,1, file); + } + while (!(buf==(char)0x51)); + + fread(buf2,2,1,file); /* Lsiz */ + len = ((buf2[0])<<8) + buf2[1]; + + siz_buffer = (char*) malloc(len * sizeof(char)); + fread(siz_buffer,len, 1, file); + cio = opj_cio_open(NULL, siz_buffer, len); + + cio_read(cio, 2); /* Rsiz (capabilities) */ + image->x1 = cio_read(cio, 4); /* Xsiz */ + image->y1 = cio_read(cio, 4); /* Ysiz */ + image->x0 = cio_read(cio, 4); /* X0siz */ + image->y0 = cio_read(cio, 4); /* Y0siz */ + cio_skip(cio, 16); /* XTsiz, YTsiz, XT0siz, YT0siz */ + + image->numcomps = cio_read(cio,2); /* Csiz */ + image->comps = + (opj_image_comp_t *) malloc(image->numcomps * sizeof(opj_image_comp_t)); + + for (i = 0; i < image->numcomps; i++) { + int tmp; + tmp = cio_read(cio,1); /* Ssiz_i */ + image->comps[i].prec = (tmp & 0x7f) + 1; + image->comps[i].sgnd = tmp >> 7; + image->comps[i].dx = cio_read(cio,1); /* XRsiz_i */ + image->comps[i].dy = cio_read(cio,1); /* YRsiz_i */ + image->comps[i].resno_decoded = 0; /* number of resolution decoded */ + image->comps[i].factor = 0; /* reducing factor by component */ + } + fseek(file, 0, SEEK_SET); + opj_cio_close(cio); +} + +static void setparams(opj_mj2_t *movie, opj_image_t *image) { + int i, depth_0, depth, sign; + + movie->tk[0].sample_rate = 25; + movie->tk[0].w = int_ceildiv(image->x1 - image->x0, image->comps[0].dx); + movie->tk[0].h = int_ceildiv(image->y1 - image->y0, image->comps[0].dy); + mj2_init_stdmovie(movie); + + movie->tk[0].depth = image->comps[0].prec; + + if (image->numcomps==3) { + if ((image->comps[0].dx == 1) + && (image->comps[1].dx == 1) + && (image->comps[2].dx == 1)) + movie->tk[0].CbCr_subsampling_dx = 1; + else + if ((image->comps[0].dx == 1) + && (image->comps[1].dx == 2) + && (image->comps[2].dx == 2)) + movie->tk[0].CbCr_subsampling_dx = 2; + else + fprintf(stderr,"Image component sizes are incoherent\n"); + + if ((image->comps[0].dy == 1) + && (image->comps[1].dy == 1) + && (image->comps[2].dy == 1)) + movie->tk[0].CbCr_subsampling_dy = 1; + else + if ((image->comps[0].dy == 1) + && (image->comps[1].dy == 2) + && (image->comps[2].dy == 2)) + movie->tk[0].CbCr_subsampling_dy = 2; + else + fprintf(stderr,"Image component sizes are incoherent\n"); + } + + movie->tk[0].sample_rate = 25; + + movie->tk[0].jp2_struct.numcomps = image->numcomps; // NC + + /* Init Standard jp2 structure */ + + movie->tk[0].jp2_struct.comps = + (opj_jp2_comps_t *) malloc(movie->tk[0].jp2_struct.numcomps * sizeof(opj_jp2_comps_t)); + movie->tk[0].jp2_struct.precedence = 0; /* PRECEDENCE*/ + movie->tk[0].jp2_struct.approx = 0; /* APPROX*/ + movie->tk[0].jp2_struct.brand = JP2_JP2; /* BR */ + movie->tk[0].jp2_struct.minversion = 0; /* MinV */ + movie->tk[0].jp2_struct.numcl = 1; + movie->tk[0].jp2_struct.cl = (unsigned int *) malloc(movie->tk[0].jp2_struct.numcl * sizeof(int)); + movie->tk[0].jp2_struct.cl[0] = JP2_JP2; /* CL0 : JP2 */ + movie->tk[0].jp2_struct.C = 7; /* C : Always 7*/ + movie->tk[0].jp2_struct.UnkC = 0; /* UnkC, colorspace specified in colr box*/ + movie->tk[0].jp2_struct.IPR = 0; /* IPR, no intellectual property*/ + movie->tk[0].jp2_struct.w = int_ceildiv(image->x1 - image->x0, image->comps[0].dx); + movie->tk[0].jp2_struct.h = int_ceildiv(image->y1 - image->y0, image->comps[0].dy); + + depth_0 = image->comps[0].prec - 1; + sign = image->comps[0].sgnd; + movie->tk[0].jp2_struct.bpc = depth_0 + (sign << 7); + + for (i = 1; i < image->numcomps; i++) { + depth = image->comps[i].prec - 1; + sign = image->comps[i].sgnd; + if (depth_0 != depth) + movie->tk[0].jp2_struct.bpc = 255; + } + + for (i = 0; i < image->numcomps; i++) + movie->tk[0].jp2_struct.comps[i].bpcc = + image->comps[i].prec - 1 + (image->comps[i].sgnd << 7); + + if ((image->numcomps == 1 || image->numcomps == 3) + && (movie->tk[0].jp2_struct.bpc != 255)) + movie->tk[0].jp2_struct.meth = 1; + else + movie->tk[0].jp2_struct.meth = 2; + + if (image->numcomps == 1) + movie->tk[0].jp2_struct.enumcs = 17; // Grayscale + + else + if ((image->comps[0].dx == 1) + && (image->comps[1].dx == 1) + && (image->comps[2].dx == 1) + && (image->comps[0].dy == 1) + && (image->comps[1].dy == 1) + && (image->comps[2].dy == 1)) + movie->tk[0].jp2_struct.enumcs = 16; // RGB + + else + if ((image->comps[0].dx == 1) + && (image->comps[1].dx == 2) + && (image->comps[2].dx == 2) + && (image->comps[0].dy == 1) + && (image->comps[1].dy == 2) + && (image->comps[2].dy == 2)) + movie->tk[0].jp2_struct.enumcs = 18; // YUV + + else + movie->tk[0].jp2_struct.enumcs = 0; // Unkown profile */ +} + +int main(int argc, char *argv[]) { + opj_cinfo_t* cinfo; + opj_event_mgr_t event_mgr; /* event manager */ + unsigned int snum; + opj_mj2_t *movie; + mj2_sample_t *sample; + unsigned char* frame_codestream; + FILE *mj2file, *j2kfile; + char j2kfilename[50]; + char *buf; + int offset, mdat_initpos; + opj_image_t img; + opj_cio_t *cio; + mj2_cparameters_t parameters; + + if (argc != 3) { + printf("Bad syntax: Usage: MJ2_Wrapper source_location mj2_filename\n"); + printf("Example: MJ2_Wrapper input/input output.mj2\n"); + return 1; + } + + mj2file = fopen(argv[2], "wb"); + + if (!mj2file) { + fprintf(stderr, "failed to open %s for writing\n", argv[2]); + return 1; + } + + /* + configure the event callbacks (not required) + setting of each callback is optionnal + */ + memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); + event_mgr.error_handler = error_callback; + event_mgr.warning_handler = warning_callback; + event_mgr.info_handler = info_callback; + + /* get a MJ2 decompressor handle */ + cinfo = mj2_create_compress(); + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)cinfo, &event_mgr, stderr); + + /* setup the decoder encoding parameters using user parameters */ + movie = (opj_mj2_t*) cinfo->mj2_handle; + mj2_setup_encoder(cinfo->mj2_handle, ¶meters); + + + /* Writing JP, FTYP and MDAT boxes + Assuming that the JP and FTYP boxes won't be longer than 300 bytes */ + + buf = (char*) malloc (300 * sizeof(char)); + cio = opj_cio_open(movie->cinfo, buf, 300); + mj2_write_jp(cio); + mj2_write_ftyp(movie, cio); + mdat_initpos = cio_tell(cio); + cio_skip(cio, 4); + cio_write(cio,MJ2_MDAT, 4); + fwrite(buf,cio_tell(cio),1,mj2file); + free(buf); + + // Insert each j2k codestream in a JP2C box + snum=0; + offset = 0; + while(1) + { + sample = &movie->tk[0].sample[snum]; + sprintf(j2kfilename,"%s_%05d.j2k",argv[1],snum); + j2kfile = fopen(j2kfilename, "rb"); + if (!j2kfile) { + if (snum==0) { // Could not open a single codestream + fprintf(stderr, "failed to open %s for reading\n",j2kfilename); + return 1; + } + else { // Tried to open a inexistant codestream + fprintf(stdout,"%d frames are being added to the MJ2 file\n",snum); + break; + } + } + + // Calculating offset for samples and chunks + offset += cio_tell(cio); + sample->offset = offset; + movie->tk[0].chunk[snum].offset = offset; // There will be one sample per chunk + + // Calculating sample size + fseek(j2kfile,0,SEEK_END); + sample->sample_size = ftell(j2kfile) + 8; // Sample size is codestream + JP2C box header + fseek(j2kfile,0,SEEK_SET); + + // Reading siz marker of j2k image for the first codestream + if (snum==0) + read_siz_marker(j2kfile, &img); + + // Writing JP2C box header + frame_codestream = (unsigned char*) malloc (sample->sample_size+8); + cio = opj_cio_open(movie->cinfo, frame_codestream, sample->sample_size); + cio_write(cio,sample->sample_size, 4); // Sample size + cio_write(cio,JP2_JP2C, 4); // JP2C + + // Writing codestream from J2K file to MJ2 file + fread(frame_codestream+8,sample->sample_size-8,1,j2kfile); + fwrite(frame_codestream,sample->sample_size,1,mj2file); + cio_skip(cio, sample->sample_size-8); + + // Ending loop + fclose(j2kfile); + snum++; + movie->tk[0].sample = realloc(movie->tk[0].sample, (snum+1) * sizeof(mj2_sample_t)); + movie->tk[0].chunk = realloc(movie->tk[0].chunk, (snum+1) * sizeof(mj2_chunk_t)); + free(frame_codestream); + } + + // Writing the MDAT box length in header + offset += cio_tell(cio); + buf = (char*) malloc (4 * sizeof(char)); + cio = opj_cio_open(movie->cinfo, buf, 4); + cio_write(cio,offset-mdat_initpos,4); + fseek(mj2file,(long)mdat_initpos,SEEK_SET); + fwrite(buf,4,1,mj2file); + fseek(mj2file,0,SEEK_END); + free(buf); + + // Setting movie parameters + movie->tk[0].num_samples=snum; + movie->tk[0].num_chunks=snum; + setparams(movie, &img); + + // Writing MOOV box + buf = (char*) malloc ((TEMP_BUF+snum*20) * sizeof(char)); + cio = opj_cio_open(movie->cinfo, buf, (TEMP_BUF+snum*20)); + mj2_write_moov(movie, cio); + fwrite(buf,cio_tell(cio),1,mj2file); + + // Ending program + fclose(mj2file); + free(img.comps); + opj_cio_close(cio); + mj2_destroy_compress(movie); + + return 0; +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/openjpeg_mangle.h.in b/gdcm/Utilities/gdcmopenjpeg-v2/openjpeg_mangle.h.in new file mode 100644 index 0000000..62f15ec --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/openjpeg_mangle.h.in @@ -0,0 +1,278 @@ +/* This file was generated by CMake http://www.cmake.org */ + +#ifndef @MANGLE_PREFIX@_mangle_h +#define @MANGLE_PREFIX@_mangle_h + +/* + * This header file mangles all symbols exported from the openjpeg library. + * It is included in all files while building the openjpeg library. Due to + * namespace pollution, no openjpeg headers should be included in .h files in + * GDCM. + * + * The following command was used to obtain the symbol list: + * + * nm lib@MANGLE_PREFIX@.a | grep " [RT] " + */ + +#define MCT_ELEMENT_SIZE @MANGLE_PREFIX@_MCT_ELEMENT_SIZE +#define _ProfInit @MANGLE_PREFIX@__ProfInit +#define _ProfPrint @MANGLE_PREFIX@__ProfPrint +#define _ProfSave @MANGLE_PREFIX@__ProfSave +#define _ProfStart @MANGLE_PREFIX@__ProfStart +#define _ProfStop @MANGLE_PREFIX@__ProfStop +#define bio_create @MANGLE_PREFIX@_bio_create +#define bio_destroy @MANGLE_PREFIX@_bio_destroy +#define bio_flush @MANGLE_PREFIX@_bio_flush +#define bio_inalign @MANGLE_PREFIX@_bio_inalign +#define bio_init_dec @MANGLE_PREFIX@_bio_init_dec +#define bio_init_enc @MANGLE_PREFIX@_bio_init_enc +#define bio_numbytes @MANGLE_PREFIX@_bio_numbytes +#define bio_read @MANGLE_PREFIX@_bio_read +#define bio_write @MANGLE_PREFIX@_bio_write +#define dwt_calc_explicit_stepsizes @MANGLE_PREFIX@_dwt_calc_explicit_stepsizes +#define dwt_decode @MANGLE_PREFIX@_dwt_decode +#define dwt_decode_real @MANGLE_PREFIX@_dwt_decode_real +#define dwt_encode @MANGLE_PREFIX@_dwt_encode +#define dwt_encode_real @MANGLE_PREFIX@_dwt_encode_real +#define dwt_getgain @MANGLE_PREFIX@_dwt_getgain +#define dwt_getgain_real @MANGLE_PREFIX@_dwt_getgain_real +#define dwt_getnorm @MANGLE_PREFIX@_dwt_getnorm +#define dwt_getnorm_real @MANGLE_PREFIX@_dwt_getnorm_real +#define get_all_encoding_parameters @MANGLE_PREFIX@_get_all_encoding_parameters +#define get_default_stride @MANGLE_PREFIX@_get_default_stride +#define get_encoding_parameters @MANGLE_PREFIX@_get_encoding_parameters +#define get_mct_norms @MANGLE_PREFIX@_get_mct_norms +#define get_mct_norms_real @MANGLE_PREFIX@_get_mct_norms_real +#define get_tp_stride @MANGLE_PREFIX@_get_tp_stride +#define j2k_build_decoder @MANGLE_PREFIX@_j2k_build_decoder +#define j2k_build_encoder @MANGLE_PREFIX@_j2k_build_encoder +#define j2k_convert_progression_order @MANGLE_PREFIX@_j2k_convert_progression_order +#define j2k_copy_default_tcp_and_create_tcd @MANGLE_PREFIX@_j2k_copy_default_tcp_and_create_tcd +#define j2k_create_compress @MANGLE_PREFIX@_j2k_create_compress +#define j2k_create_decompress @MANGLE_PREFIX@_j2k_create_decompress +#define j2k_decode @MANGLE_PREFIX@_j2k_decode +#define j2k_decode_tile @MANGLE_PREFIX@_j2k_decode_tile +#define j2k_decode_tiles @MANGLE_PREFIX@_j2k_decode_tiles +#define j2k_decoding_validation @MANGLE_PREFIX@_j2k_decoding_validation +#define j2k_destroy @MANGLE_PREFIX@_j2k_destroy +#define j2k_destroy_header_memory @MANGLE_PREFIX@_j2k_destroy_header_memory +#define j2k_dump_image @MANGLE_PREFIX@_j2k_dump_image +#define j2k_encode @MANGLE_PREFIX@_j2k_encode +#define j2k_encoding_validation @MANGLE_PREFIX@_j2k_encoding_validation +#define j2k_end_compress @MANGLE_PREFIX@_j2k_end_compress +#define j2k_end_decompress @MANGLE_PREFIX@_j2k_end_decompress +#define j2k_mct_read_functions_to_float @MANGLE_PREFIX@_j2k_mct_read_functions_to_float +#define j2k_mct_read_functions_to_int32 @MANGLE_PREFIX@_j2k_mct_read_functions_to_int32 +#define j2k_mct_validation @MANGLE_PREFIX@_j2k_mct_validation +#define j2k_mct_write_functions_from_float @MANGLE_PREFIX@_j2k_mct_write_functions_from_float +#define j2k_memory_marker_handler_tab @MANGLE_PREFIX@_j2k_memory_marker_handler_tab +#define j2k_prog_order_list @MANGLE_PREFIX@_j2k_prog_order_list +#define j2k_read_header @MANGLE_PREFIX@_j2k_read_header +#define j2k_read_header_procedure @MANGLE_PREFIX@_j2k_read_header_procedure +#define j2k_read_tile_header @MANGLE_PREFIX@_j2k_read_tile_header +#define j2k_set_decode_area @MANGLE_PREFIX@_j2k_set_decode_area +#define j2k_setup_decoder @MANGLE_PREFIX@_j2k_setup_decoder +#define j2k_setup_decoding @MANGLE_PREFIX@_j2k_setup_decoding +#define j2k_setup_encoder @MANGLE_PREFIX@_j2k_setup_encoder +#define j2k_setup_header_reading @MANGLE_PREFIX@_j2k_setup_header_reading +#define j2k_setup_header_writting @MANGLE_PREFIX@_j2k_setup_header_writting +#define j2k_setup_mct_encoding @MANGLE_PREFIX@_j2k_setup_mct_encoding +#define j2k_start_compress @MANGLE_PREFIX@_j2k_start_compress +#define j2k_write_tile @MANGLE_PREFIX@_j2k_write_tile +#define jp2_create @MANGLE_PREFIX@_jp2_create +#define jp2_decode @MANGLE_PREFIX@_jp2_decode +#define jp2_decode_tile @MANGLE_PREFIX@_jp2_decode_tile +#define jp2_default_validation @MANGLE_PREFIX@_jp2_default_validation +#define jp2_destroy @MANGLE_PREFIX@_jp2_destroy +#define jp2_encode @MANGLE_PREFIX@_jp2_encode +#define jp2_end_compress @MANGLE_PREFIX@_jp2_end_compress +#define jp2_end_decompress @MANGLE_PREFIX@_jp2_end_decompress +#define jp2_header @MANGLE_PREFIX@_jp2_header +#define jp2_img_header @MANGLE_PREFIX@_jp2_img_header +#define jp2_read_header @MANGLE_PREFIX@_jp2_read_header +#define jp2_read_header_procedure @MANGLE_PREFIX@_jp2_read_header_procedure +#define jp2_read_jp2h @MANGLE_PREFIX@_jp2_read_jp2h +#define jp2_read_tile_header @MANGLE_PREFIX@_jp2_read_tile_header +#define jp2_set_decode_area @MANGLE_PREFIX@_jp2_set_decode_area +#define jp2_setup_decoder @MANGLE_PREFIX@_jp2_setup_decoder +#define jp2_setup_encoder @MANGLE_PREFIX@_jp2_setup_encoder +#define jp2_skip_jp2c @MANGLE_PREFIX@_jp2_skip_jp2c +#define jp2_start_compress @MANGLE_PREFIX@_jp2_start_compress +#define jp2_write_jp2h @MANGLE_PREFIX@_jp2_write_jp2h +#define jp2_write_tile @MANGLE_PREFIX@_jp2_write_tile +#define jpt_init_msg_header @MANGLE_PREFIX@_jpt_init_msg_header +#define jpt_read_VBAS_info @MANGLE_PREFIX@_jpt_read_VBAS_info +#define jpt_read_msg_header @MANGLE_PREFIX@_jpt_read_msg_header +#define jpt_reinit_msg_header @MANGLE_PREFIX@_jpt_reinit_msg_header +#define mct_decode @MANGLE_PREFIX@_mct_decode +#define mct_decode_custom @MANGLE_PREFIX@_mct_decode_custom +#define mct_decode_real @MANGLE_PREFIX@_mct_decode_real +#define mct_encode @MANGLE_PREFIX@_mct_encode +#define mct_encode_custom @MANGLE_PREFIX@_mct_encode_custom +#define mct_encode_real @MANGLE_PREFIX@_mct_encode_real +#define mct_getnorm @MANGLE_PREFIX@_mct_getnorm +#define mct_getnorm_real @MANGLE_PREFIX@_mct_getnorm_real +#define mqc_bypass_enc @MANGLE_PREFIX@_mqc_bypass_enc +#define mqc_bypass_flush_enc @MANGLE_PREFIX@_mqc_bypass_flush_enc +#define mqc_bypass_init_enc @MANGLE_PREFIX@_mqc_bypass_init_enc +#define mqc_create @MANGLE_PREFIX@_mqc_create +#define mqc_decode @MANGLE_PREFIX@_mqc_decode +#define mqc_destroy @MANGLE_PREFIX@_mqc_destroy +#define mqc_encode @MANGLE_PREFIX@_mqc_encode +#define mqc_erterm_enc @MANGLE_PREFIX@_mqc_erterm_enc +#define mqc_flush @MANGLE_PREFIX@_mqc_flush +#define mqc_init_dec @MANGLE_PREFIX@_mqc_init_dec +#define mqc_init_enc @MANGLE_PREFIX@_mqc_init_enc +#define mqc_numbytes @MANGLE_PREFIX@_mqc_numbytes +#define mqc_reset_enc @MANGLE_PREFIX@_mqc_reset_enc +#define mqc_resetstates @MANGLE_PREFIX@_mqc_resetstates +#define mqc_restart_enc @MANGLE_PREFIX@_mqc_restart_enc +#define mqc_restart_init_enc @MANGLE_PREFIX@_mqc_restart_init_enc +#define mqc_segmark_enc @MANGLE_PREFIX@_mqc_segmark_enc +#define mqc_setstate @MANGLE_PREFIX@_mqc_setstate +#define opj_calculate_norms @MANGLE_PREFIX@_opj_calculate_norms +#define opj_clock @MANGLE_PREFIX@_opj_clock +#define opj_create_compress @MANGLE_PREFIX@_opj_create_compress +#define opj_create_decompress @MANGLE_PREFIX@_opj_create_decompress +#define opj_decode @MANGLE_PREFIX@_opj_decode +#define opj_decode_tile_data @MANGLE_PREFIX@_opj_decode_tile_data +#define opj_default_callback @MANGLE_PREFIX@_opj_default_callback +#define opj_destroy_codec @MANGLE_PREFIX@_opj_destroy_codec +#define opj_destroy_cstr_info @MANGLE_PREFIX@_opj_destroy_cstr_info +#define opj_encode @MANGLE_PREFIX@_opj_encode +#define opj_end_compress @MANGLE_PREFIX@_opj_end_compress +#define opj_end_decompress @MANGLE_PREFIX@_opj_end_decompress +#define opj_event_msg @MANGLE_PREFIX@_opj_event_msg +#define opj_image_comp_update @MANGLE_PREFIX@_opj_image_comp_update +#define opj_image_create @MANGLE_PREFIX@_opj_image_create +#define opj_image_create0 @MANGLE_PREFIX@_opj_image_create0 +#define opj_image_destroy @MANGLE_PREFIX@_opj_image_destroy +#define opj_image_tile_create @MANGLE_PREFIX@_opj_image_tile_create +#define opj_lupDecompose @MANGLE_PREFIX@_opj_lupDecompose +#define opj_lupInvert @MANGLE_PREFIX@_opj_lupInvert +#define opj_lupSolve @MANGLE_PREFIX@_opj_lupSolve +#define opj_matrix_inversion_f @MANGLE_PREFIX@_opj_matrix_inversion_f +#define opj_procedure_list_add_procedure @MANGLE_PREFIX@_opj_procedure_list_add_procedure +#define opj_procedure_list_clear @MANGLE_PREFIX@_opj_procedure_list_clear +#define opj_procedure_list_create @MANGLE_PREFIX@_opj_procedure_list_create +#define opj_procedure_list_destroy @MANGLE_PREFIX@_opj_procedure_list_destroy +#define opj_procedure_list_get_first_procedure @MANGLE_PREFIX@_opj_procedure_list_get_first_procedure +#define opj_procedure_list_get_nb_procedures @MANGLE_PREFIX@_opj_procedure_list_get_nb_procedures +#define opj_read_bytes_BE @MANGLE_PREFIX@_opj_read_bytes_BE +#define opj_read_bytes_LE @MANGLE_PREFIX@_opj_read_bytes_LE +#define opj_read_double_BE @MANGLE_PREFIX@_opj_read_double_BE +#define opj_read_double_LE @MANGLE_PREFIX@_opj_read_double_LE +#define opj_read_float_BE @MANGLE_PREFIX@_opj_read_float_BE +#define opj_read_float_LE @MANGLE_PREFIX@_opj_read_float_LE +#define opj_read_from_file @MANGLE_PREFIX@_opj_read_from_file +#define opj_read_header @MANGLE_PREFIX@_opj_read_header +#define opj_read_tile_header @MANGLE_PREFIX@_opj_read_tile_header +#define opj_restrict_decoding @MANGLE_PREFIX@_opj_restrict_decoding +#define opj_seek_from_file @MANGLE_PREFIX@_opj_seek_from_file +#define opj_set_MCT @MANGLE_PREFIX@_opj_set_MCT +#define opj_set_decode_area @MANGLE_PREFIX@_opj_set_decode_area +#define opj_set_default_decoder_parameters @MANGLE_PREFIX@_opj_set_default_decoder_parameters +#define opj_set_default_encoder_parameters @MANGLE_PREFIX@_opj_set_default_encoder_parameters +#define opj_set_error_handler @MANGLE_PREFIX@_opj_set_error_handler +#define opj_set_info_handler @MANGLE_PREFIX@_opj_set_info_handler +#define opj_set_warning_handler @MANGLE_PREFIX@_opj_set_warning_handler +#define opj_setup_decoder @MANGLE_PREFIX@_opj_setup_decoder +#define opj_setup_encoder @MANGLE_PREFIX@_opj_setup_encoder +#define opj_skip_from_file @MANGLE_PREFIX@_opj_skip_from_file +#define opj_start_compress @MANGLE_PREFIX@_opj_start_compress +#define opj_stream_create @MANGLE_PREFIX@_opj_stream_create +#define opj_stream_create_default_file_stream @MANGLE_PREFIX@_opj_stream_create_default_file_stream +#define opj_stream_create_file_stream @MANGLE_PREFIX@_opj_stream_create_file_stream +#define opj_stream_default_create @MANGLE_PREFIX@_opj_stream_default_create +#define opj_stream_default_read @MANGLE_PREFIX@_opj_stream_default_read +#define opj_stream_default_seek @MANGLE_PREFIX@_opj_stream_default_seek +#define opj_stream_default_skip @MANGLE_PREFIX@_opj_stream_default_skip +#define opj_stream_default_write @MANGLE_PREFIX@_opj_stream_default_write +#define opj_stream_destroy @MANGLE_PREFIX@_opj_stream_destroy +#define opj_stream_flush @MANGLE_PREFIX@_opj_stream_flush +#define opj_stream_has_seek @MANGLE_PREFIX@_opj_stream_has_seek +#define opj_stream_read_data @MANGLE_PREFIX@_opj_stream_read_data +#define opj_stream_read_seek @MANGLE_PREFIX@_opj_stream_read_seek +#define opj_stream_read_skip @MANGLE_PREFIX@_opj_stream_read_skip +#define opj_stream_seek @MANGLE_PREFIX@_opj_stream_seek +#define opj_stream_set_read_function @MANGLE_PREFIX@_opj_stream_set_read_function +#define opj_stream_set_seek_function @MANGLE_PREFIX@_opj_stream_set_seek_function +#define opj_stream_set_skip_function @MANGLE_PREFIX@_opj_stream_set_skip_function +#define opj_stream_set_user_data @MANGLE_PREFIX@_opj_stream_set_user_data +#define opj_stream_set_write_function @MANGLE_PREFIX@_opj_stream_set_write_function +#define opj_stream_skip @MANGLE_PREFIX@_opj_stream_skip +#define opj_stream_tell @MANGLE_PREFIX@_opj_stream_tell +#define opj_stream_write_data @MANGLE_PREFIX@_opj_stream_write_data +#define opj_stream_write_seek @MANGLE_PREFIX@_opj_stream_write_seek +#define opj_stream_write_skip @MANGLE_PREFIX@_opj_stream_write_skip +#define opj_version @MANGLE_PREFIX@_opj_version +#define opj_write_bytes_BE @MANGLE_PREFIX@_opj_write_bytes_BE +#define opj_write_bytes_LE @MANGLE_PREFIX@_opj_write_bytes_LE +#define opj_write_double_BE @MANGLE_PREFIX@_opj_write_double_BE +#define opj_write_double_LE @MANGLE_PREFIX@_opj_write_double_LE +#define opj_write_float_BE @MANGLE_PREFIX@_opj_write_float_BE +#define opj_write_float_LE @MANGLE_PREFIX@_opj_write_float_LE +#define opj_write_from_file @MANGLE_PREFIX@_opj_write_from_file +#define opj_write_tile @MANGLE_PREFIX@_opj_write_tile +#define pi_check_next_level @MANGLE_PREFIX@_pi_check_next_level +#define pi_create @MANGLE_PREFIX@_pi_create +#define pi_create_decode @MANGLE_PREFIX@_pi_create_decode +#define pi_create_encode @MANGLE_PREFIX@_pi_create_encode +#define pi_destroy @MANGLE_PREFIX@_pi_destroy +#define pi_initialise_encode @MANGLE_PREFIX@_pi_initialise_encode +#define pi_next @MANGLE_PREFIX@_pi_next +#define pi_update_decode_not_poc @MANGLE_PREFIX@_pi_update_decode_not_poc +#define pi_update_decode_poc @MANGLE_PREFIX@_pi_update_decode_poc +#define pi_update_encode_not_poc @MANGLE_PREFIX@_pi_update_encode_not_poc +#define pi_update_encode_poc_and_final @MANGLE_PREFIX@_pi_update_encode_poc_and_final +#define pi_update_encoding_parameters @MANGLE_PREFIX@_pi_update_encoding_parameters +#define raw_create @MANGLE_PREFIX@_raw_create +#define raw_decode @MANGLE_PREFIX@_raw_decode +#define raw_destroy @MANGLE_PREFIX@_raw_destroy +#define raw_init_dec @MANGLE_PREFIX@_raw_init_dec +#define raw_numbytes @MANGLE_PREFIX@_raw_numbytes +#define set_default_event_handler @MANGLE_PREFIX@_set_default_event_handler +#define t1_create @MANGLE_PREFIX@_t1_create +#define t1_decode_cblks @MANGLE_PREFIX@_t1_decode_cblks +#define t1_destroy @MANGLE_PREFIX@_t1_destroy +#define t1_encode_cblks @MANGLE_PREFIX@_t1_encode_cblks +#define t2_create @MANGLE_PREFIX@_t2_create +#define t2_decode_packets @MANGLE_PREFIX@_t2_decode_packets +#define t2_destroy @MANGLE_PREFIX@_t2_destroy +#define t2_encode_packets @MANGLE_PREFIX@_t2_encode_packets +#define tcd_code_block_dec_deallocate @MANGLE_PREFIX@_tcd_code_block_dec_deallocate +#define tcd_copy_tile_data @MANGLE_PREFIX@_tcd_copy_tile_data +#define tcd_create @MANGLE_PREFIX@_tcd_create +#define tcd_dc_level_shift_decode @MANGLE_PREFIX@_tcd_dc_level_shift_decode +#define tcd_dc_level_shift_encode @MANGLE_PREFIX@_tcd_dc_level_shift_encode +#define tcd_decode_tile @MANGLE_PREFIX@_tcd_decode_tile +#define tcd_destroy @MANGLE_PREFIX@_tcd_destroy +#define tcd_dwt_decode @MANGLE_PREFIX@_tcd_dwt_decode +#define tcd_dwt_encode @MANGLE_PREFIX@_tcd_dwt_encode +#define tcd_encode_tile @MANGLE_PREFIX@_tcd_encode_tile +#define tcd_get_decoded_tile_size @MANGLE_PREFIX@_tcd_get_decoded_tile_size +#define tcd_get_encoded_tile_size @MANGLE_PREFIX@_tcd_get_encoded_tile_size +#define tcd_init @MANGLE_PREFIX@_tcd_init +#define tcd_init_decode_tile @MANGLE_PREFIX@_tcd_init_decode_tile +#define tcd_init_encode_tile @MANGLE_PREFIX@_tcd_init_encode_tile +#define tcd_makelayer @MANGLE_PREFIX@_tcd_makelayer +#define tcd_makelayer_fixed @MANGLE_PREFIX@_tcd_makelayer_fixed +#define tcd_mct_decode @MANGLE_PREFIX@_tcd_mct_decode +#define tcd_mct_encode @MANGLE_PREFIX@_tcd_mct_encode +#define tcd_rate_allocate_encode @MANGLE_PREFIX@_tcd_rate_allocate_encode +#define tcd_rateallocate @MANGLE_PREFIX@_tcd_rateallocate +#define tcd_rateallocate_fixed @MANGLE_PREFIX@_tcd_rateallocate_fixed +#define tcd_t1_decode @MANGLE_PREFIX@_tcd_t1_decode +#define tcd_t1_encode @MANGLE_PREFIX@_tcd_t1_encode +#define tcd_t2_decode @MANGLE_PREFIX@_tcd_t2_decode +#define tcd_t2_encode @MANGLE_PREFIX@_tcd_t2_encode +#define tcd_update_tile_data @MANGLE_PREFIX@_tcd_update_tile_data +#define tgt_create @MANGLE_PREFIX@_tgt_create +#define tgt_decode @MANGLE_PREFIX@_tgt_decode +#define tgt_destroy @MANGLE_PREFIX@_tgt_destroy +#define tgt_encode @MANGLE_PREFIX@_tgt_encode +#define tgt_init @MANGLE_PREFIX@_tgt_init +#define tgt_reset @MANGLE_PREFIX@_tgt_reset +#define tgt_setvalue @MANGLE_PREFIX@_tgt_setvalue + +#endif diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/opj_configure.h.in b/gdcm/Utilities/gdcmopenjpeg-v2/opj_configure.h.in new file mode 100644 index 0000000..fad7612 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/opj_configure.h.in @@ -0,0 +1,16 @@ +/* + * here is where system comupted values get stored these values should only + * change when the target compile platform changes + */ + +/* what byte order */ +#ifndef __OPJ_CONFIGURE_H +#define __OPJ_CONFIGURE_H +#cmakedefine CMAKE_WORDS_BIGENDIAN +#ifdef CMAKE_WORDS_BIGENDIAN + #define OPJ_BIG_ENDIAN +#else + #define OPJ_LITTLE_ENDIAN +#endif + +#endif /* __OPJ_CONFIGURE_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/test_Free_image_V2_tile_handling/CMakeLists.txt b/gdcm/Utilities/gdcmopenjpeg-v2/test_Free_image_V2_tile_handling/CMakeLists.txt new file mode 100644 index 0000000..cc55b49 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/test_Free_image_V2_tile_handling/CMakeLists.txt @@ -0,0 +1,27 @@ +# Build the demo app, small examples + +# First thing define the common source: + +# Then check if getopt is present: +include (${CMAKE_ROOT}/Modules/CheckIncludeFile.cmake) + +# Headers file are located here: +include_directories( + ${OPENJPEG_SOURCE_DIR}/libopenjpeg + ) + +# Do the proper thing when building static...if only there was configured +# headers or def files instead +if(NOT BUILD_SHARED_LIBS) + add_definitions(-DOPJ_STATIC) +endif() + +#include(${OPENJPEG_SOURCE_DIR}/CMake/Free_CMakeImport.cmake) +add_definitions ( -DFREEIMAGE_LIB ) + +# Loop over all executables: +foreach(exe test2_encoder test2_decoder) + add_executable(${exe} ${exe}.c) + target_link_libraries(${exe} ${OPJ_PREFIX}openjpeg) + target_link_libraries(${exe} ${FREEIMAGE_LIBRARIES}) +endforeach() diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/test_Free_image_V2_tile_handling/test2_decoder.c b/gdcm/Utilities/gdcmopenjpeg-v2/test_Free_image_V2_tile_handling/test2_decoder.c new file mode 100644 index 0000000..ce89eb4 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/test_Free_image_V2_tile_handling/test2_decoder.c @@ -0,0 +1,367 @@ +/* + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define USE_OPJ_DEPRECATED +/* set this macro to enable profiling for the given test */ +/* warning : in order to be effective, openjpeg must have been built with profiling enabled !! */ +//#define _PROFILE +#include "openjpeg.h" +#include "FreeImage.h" +#ifdef WIN32 +#include +#endif +#include +#include + +#define NB_EXTENSIONS 2 +/* -------------------------------------------------------------------------- */ +struct opj_format +{ + const char * m_extension; + OPJ_CODEC_FORMAT m_format; +}; + +const struct opj_format c_extensions[] = +{ + {".j2k",CODEC_J2K}, + {".jp2",CODEC_JP2} +}; + +OPJ_CODEC_FORMAT get_format (const char * l_file_name) +{ + OPJ_INT32 i; + const struct opj_format * l_current = c_extensions; + for + (i=0;im_extension,l_file_name + strlen(l_file_name)-4,4)) + { + return l_current->m_format; + } + ++l_current; + } + return CODEC_UNKNOWN; +} + +/** +sample error callback expecting a FILE* client object +*/ +void error_callback_file(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[ERROR] %s", msg); +} +/** +sample warning callback expecting a FILE* client object +*/ +void warning_callback_file(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[WARNING] %s", msg); +} +/** +sample error debug callback expecting no client object +*/ +void error_callback(const char *msg, void *client_data) { + (void)client_data; + fprintf(stdout, "[ERROR] %s", msg); +} +/** +sample warning debug callback expecting no client object +*/ +void warning_callback(const char *msg, void *client_data) { + (void)client_data; + fprintf(stdout, "[WARNING] %s", msg); +} +/** +sample debug callback expecting no client object +*/ +void info_callback(const char *msg, void *client_data) { + (void)client_data; + fprintf(stdout, "[INFO] %s", msg); +} + +/* -------------------------------------------------------------------------- */ + +int main (int argc,char * argv []) +{ + opj_dparameters_t l_param; + opj_codec_t * l_codec; + opj_image_t * l_image; + FILE * l_file; + opj_stream_t * l_stream; + OPJ_UINT32 l_data_size; + OPJ_UINT32 l_max_data_size = 1000; + OPJ_UINT32 l_tile_index; + OPJ_BYTE * l_data = (OPJ_BYTE *) malloc(1000); + bool l_go_on = true; + OPJ_INT32 l_tile_x0,l_tile_y0; + OPJ_UINT32 l_tile_width,l_tile_height,l_nb_tiles_x,l_nb_tiles_y,l_nb_comps; + OPJ_INT32 l_current_tile_x0,l_current_tile_y0,l_current_tile_x1,l_current_tile_y1; + char * l_input_file,* l_output_file; + OPJ_INT32 l_min_x, l_min_y, l_max_x, l_max_y; + OPJ_CODEC_FORMAT l_codec_format; + FIBITMAP * l_bitmap; + unsigned char * l_image_data; + OPJ_INT32 l_req_x,l_req_y; + OPJ_UINT32 l_image_width,l_image_height,l_image_boundary,l_offset; + unsigned char * l_tile_ptr [3]; + unsigned char * l_line_ptr, * l_current_ptr; + OPJ_UINT32 i,j; + + if + (argc != 8) + { + printf("usage : ... \n"); + return 1; + } + + PROFINIT(); + FreeImage_Initialise(0); + + l_input_file = argv[1]; + l_output_file = argv[2]; + l_min_x = atoi(argv[3]); + l_min_y = atoi(argv[4]); + l_max_x = atoi(argv[5]); + l_max_y = atoi(argv[6]); + + l_codec_format = get_format(l_input_file); + + if + ((! l_data) || (l_codec_format == CODEC_UNKNOWN)) + { + return 1; + } + + + opj_set_default_decoder_parameters(&l_param); + + /** you may here add custom decoding parameters */ + /* do not use layer decoding limitations */ + l_param.cp_layer = 0; + + /* do not use resolutions reductions */ + l_param.cp_reduce = atoi(argv[7]); + + /* to decode only a part of the image data */ + //opj_restrict_decoding(&l_param,0,0,1000,1000); + + l_codec = opj_create_decompress(l_codec_format); + if + (! l_codec) + { + free(l_data); + return 1; + } + + /* catch events using our callbacks and give a local context */ + opj_set_info_handler(l_codec, info_callback,00); + opj_set_warning_handler(l_codec, warning_callback,00); + opj_set_error_handler(l_codec, error_callback,00); + opj_restrict_decoding(&l_param,l_min_x, l_min_y, l_max_x, l_max_y); + + if + (! opj_setup_decoder(l_codec,&l_param)) + { + free(l_data); + opj_destroy_codec(l_codec); + return 1; + } + + l_file = fopen(l_input_file,"rb"); + if + (! l_file) + { + fprintf(stdout, "Error opening input file\n"); + free(l_data); + opj_destroy_codec(l_codec); + return 1; + } + + l_stream = opj_stream_create_default_file_stream(l_file,true); + + if + (! opj_read_header(l_codec, + &l_image, + &l_tile_x0, + &l_tile_y0, + &l_tile_width, + &l_tile_height, + &l_nb_tiles_x, + &l_nb_tiles_y, + l_stream)) + { + free(l_data); + opj_stream_destroy(l_stream); + fclose(l_file); + opj_destroy_codec(l_codec); + return 1; + } + + if + ((l_tile_x0 != 0) || (l_tile_y0 != 0)) + { + free(l_data); + opj_stream_destroy(l_stream); + fclose(l_file); + opj_destroy_codec(l_codec); + return 1; + } + + l_min_x -= l_min_x % l_tile_width; + l_min_y -= l_min_y % l_tile_height; + + l_req_x = l_max_x % l_tile_width; + if + (l_req_x) + { + l_max_x += l_tile_width - l_req_x; + } + + l_req_y = l_max_y % l_tile_height; + if + (l_req_y) + { + l_max_y += l_tile_height - l_req_y; + } + + l_min_x = l_min_x < l_image->x0 ? l_image->x0 : l_min_x; + l_min_y = l_min_y < l_image->y0 ? l_image->y0 : l_min_y; + l_max_x = l_max_x > l_image->x1 ? l_image->x1 : l_max_x; + l_max_y = l_max_y > l_image->y1 ? l_image->y1 : l_max_y; + + l_image_width = (l_max_x - l_min_x + (1 << l_param.cp_reduce) - 1) >> l_param.cp_reduce; + l_image_height = (l_max_y - l_min_y + (1 << l_param.cp_reduce) - 1) >> l_param.cp_reduce; + l_image_boundary = 3 * l_image_width; + l_req_x = l_image_boundary % 4; + if + (l_req_x) + { + l_image_boundary += 4-l_req_x; + } + + l_bitmap = FreeImage_Allocate(l_image_width, l_image_height, 24, 0, 0, 0); + l_image_data = FreeImage_GetBits(l_bitmap); + + while + (l_go_on) + { + if + (! opj_read_tile_header( + l_codec, + &l_tile_index, + &l_data_size, + &l_current_tile_x0, + &l_current_tile_y0, + &l_current_tile_x1, + &l_current_tile_y1, + &l_nb_comps, + &l_go_on, + l_stream)) + { + free(l_data); + opj_stream_destroy(l_stream); + fclose(l_file); + opj_destroy_codec(l_codec); + opj_image_destroy(l_image); + return 1; + } + if + (l_go_on) + { + if + (l_data_size > l_max_data_size) + { + l_data = (OPJ_BYTE *) realloc(l_data,l_data_size); + if + (! l_data) + { + opj_stream_destroy(l_stream); + fclose(l_file); + opj_destroy_codec(l_codec); + opj_image_destroy(l_image); + return 1; + } + l_max_data_size = l_data_size; + } + + if + (! opj_decode_tile_data(l_codec,l_tile_index,l_data,l_data_size,l_stream)) + { + free(l_data); + opj_stream_destroy(l_stream); + fclose(l_file); + opj_destroy_codec(l_codec); + opj_image_destroy(l_image); + return 1; + } + /** now should inspect image to know the reduction factor and then how to behave with data */ + l_offset = (((l_max_y - l_current_tile_y0 + (1 << l_param.cp_reduce) - 1)>>l_param.cp_reduce) - 1) * l_image_boundary + ((l_current_tile_x0 - l_min_x + (1 << l_param.cp_reduce) - 1)>> l_param.cp_reduce )* 3; + + l_tile_width = (l_current_tile_x1 - l_current_tile_x0 + (1 << l_param.cp_reduce) - 1)>>l_param.cp_reduce; + l_tile_height = (l_current_tile_y1 - l_current_tile_y0 + (1 << l_param.cp_reduce) - 1)>>l_param.cp_reduce; + l_tile_ptr[0] = l_data + 2 * l_tile_width * l_tile_height; + l_tile_ptr[1] = l_data + l_tile_width * l_tile_height; + l_tile_ptr[2] = l_data ; + l_line_ptr = l_image_data + l_offset; + for + (i=0;i + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#define USE_OPJ_DEPRECATED +/* set this macro to enable profiling for the given test */ +/* warning : in order to be effective, openjpeg must have been built with profiling enabled !! */ +//#define _PROFILE + +#include "openjpeg.h" +#include +#include +#include + +/* -------------------------------------------------------------------------- */ + +/** +sample error callback expecting a FILE* client object +*/ +void error_callback_file(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[ERROR] %s", msg); +} +/** +sample warning callback expecting a FILE* client object +*/ +void warning_callback_file(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[WARNING] %s", msg); +} +/** +sample error debug callback expecting no client object +*/ +void error_callback(const char *msg, void *client_data) { + (void)client_data; + fprintf(stdout, "[ERROR] %s", msg); +} +/** +sample warning debug callback expecting no client object +*/ +void warning_callback(const char *msg, void *client_data) { + (void)client_data; + fprintf(stdout, "[WARNING] %s", msg); +} +/** +sample debug callback expecting no client object +*/ +void info_callback(const char *msg, void *client_data) { + (void)client_data; + fprintf(stdout, "[INFO] %s", msg); +} + +struct opj_format +{ + const char * m_extension; + OPJ_CODEC_FORMAT m_format; +}; + +const struct opj_format c_extensions[] = +{ + {".j2k",CODEC_J2K}, + {".jp2",CODEC_JP2} +}; + +#define NB_EXTENSIONS 2 +OPJ_CODEC_FORMAT get_format (const char * l_file_name) +{ + OPJ_INT32 i; + const struct opj_format * l_current = c_extensions; + for + (i=0;im_extension,l_file_name + strlen(l_file_name)-4,4)) + { + return l_current->m_format; + } + ++l_current; + } + return CODEC_UNKNOWN; +} + +/* -------------------------------------------------------------------------- */ + +int main (int argc, char * argv []) +{ + opj_cparameters_t l_param; + opj_codec_t * l_codec; + opj_image_t * l_image; + opj_image_cmptparm_t l_params [3]; + FILE * l_file; + opj_stream_t * l_stream; + opj_image_cmptparm_t * l_current_param_ptr; + OPJ_UINT32 i,j,k,l; + OPJ_BYTE *l_tile_data,*l_line_ptr,*l_current_ptr; + OPJ_BYTE * l_tile_ptr [3]; + OPJ_UINT32 l_tile_width,l_image_width,l_image_height,l_chunk_size,l_image_boundary,l_req_x,l_req_y,l_nb_tiles_x,l_nb_tiles_y,l_current_tile_nb,l_data_size; + OPJ_UINT32 l_offset; + + OPJ_CODEC_FORMAT l_codec_format; + FIBITMAP * l_bitmap; + FREE_IMAGE_FORMAT l_input_format; + unsigned char * l_image_data; + char * l_input_file,*l_output_file; + if + (argc != 6) + { + printf("usage \n"); + return 1; + } + + l_input_file = argv[1]; + l_output_file = argv[2]; + l_tile_width = atoi(argv[3]); + + FreeImage_Initialise(0); + + l_codec_format = get_format(l_output_file); + if + (l_codec_format == CODEC_UNKNOWN) + { + return 1; + } + + l_input_format = FreeImage_GetFileType(l_input_file,0); + if + (l_input_format == -1) + { + return 1; + } + l_bitmap = FreeImage_Load(l_input_format,l_input_file,0); + l_image_data = FreeImage_GetBits(l_bitmap); + l_image_width = FreeImage_GetWidth(l_bitmap); + l_image_height = FreeImage_GetHeight(l_bitmap); + l_chunk_size = FreeImage_GetBPP(l_bitmap); + l_chunk_size /= 8; + + if + (l_chunk_size < 3) + { + return 1; + } + l_image_boundary = l_image_width * l_chunk_size; + + l_req_x = l_image_boundary % 4; + if + (l_req_x) + { + l_image_boundary += 4 - l_req_x; + } + + l_tile_data = (OPJ_BYTE*) malloc(l_tile_width * l_tile_width * 3); + + l_nb_tiles_x = l_image_width / l_tile_width; + l_req_x = l_image_width % l_tile_width; + l_nb_tiles_y = l_image_height / l_tile_width; + l_req_y = l_image_height % l_tile_width; + + opj_set_default_encoder_parameters(&l_param); + /** you may here add custom encoding parameters */ + /* rate specifications */ + /** number of quality layers in the stream */ + l_param.tcp_numlayers = 1; + l_param.cp_fixed_quality = 1; + /* is using others way of calculation */ + /* l_param.cp_disto_alloc = 1 or l_param.cp_fixed_alloc = 1 */ + /* l_param.tcp_rates[0] = ... */ + + + /* tile definitions parameters */ + /* position of the tile grid aligned with the image */ + l_param.cp_tx0 = 0; + l_param.cp_ty0 = 0; + /* tile size, we are using tile based encoding */ + l_param.tile_size_on = true; + l_param.cp_tdx = l_tile_width; + l_param.cp_tdy = l_tile_width; + + /* use irreversible encoding ?*/ + l_param.irreversible = atoi(argv[5]); + + /* do not bother with mct, the rsiz is set when calling opj_set_MCT*/ + /*l_param.cp_rsiz = STD_RSIZ;*/ + + /* no cinema */ + /*l_param.cp_cinema = 0;*/ + + /* no not bother using SOP or EPH markers, do not use custom size precinct */ + /* number of precincts to specify */ + /* l_param.csty = 0;*/ + /* l_param.res_spec = ... */ + /* l_param.prch_init[i] = .. */ + /* l_param.prcw_init[i] = .. */ + + + /* do not use progression order changes */ + /*l_param.numpocs = 0;*/ + /* l_param.POC[i].... */ + + /* do not restrain the size for a component.*/ + /* l_param.max_comp_size = 0; */ + + /** block encoding style for each component, do not use at the moment */ + /** J2K_CCP_CBLKSTY_TERMALL, J2K_CCP_CBLKSTY_LAZY, J2K_CCP_CBLKSTY_VSC, J2K_CCP_CBLKSTY_SEGSYM, J2K_CCP_CBLKSTY_RESET */ + /* l_param.mode = 0;*/ + + /** number of resolutions */ + l_param.numresolution = atoi(argv[4]); + + /** progression order to use*/ + /** LRCP, RLCP, RPCL, PCRL, CPRL */ + l_param.prog_order = LRCP; + + /** no "region" of interest, more precisally component */ + /* l_param.roi_compno = -1; */ + /* l_param.roi_shift = 0; */ + + /* we are not using multiple tile parts for a tile. */ + /* l_param.tp_on = 0; */ + /* l_param.tp_flag = 0; */ + + l_param.tcp_mct = 1; + /* if we are using mct */ + /* opj_set_MCT(&l_param,l_mct,l_offsets,NUM_COMPS); */ + + + /* image definition */ + l_current_param_ptr = l_params; + for + (i=0;i<3;++i) + { + /* do not bother bpp useless */ + /*l_current_param_ptr->bpp = COMP_PREC;*/ + l_current_param_ptr->dx = 1; + l_current_param_ptr->dy = 1; + l_current_param_ptr->h = l_image_height; + l_current_param_ptr->sgnd = 0; + l_current_param_ptr->prec = 8; + l_current_param_ptr->w = l_image_width; + l_current_param_ptr->x0 = 0; + l_current_param_ptr->y0 = 0; + ++l_current_param_ptr; + } + + l_codec = opj_create_compress(l_codec_format); + if + (! l_codec) + { + return 1; + } + + /* catch events using our callbacks and give a local context */ + opj_set_info_handler(l_codec, info_callback,00); + opj_set_warning_handler(l_codec, warning_callback,00); + opj_set_error_handler(l_codec, error_callback,00); + + l_image = opj_image_tile_create(3,l_params,CLRSPC_SRGB); + if + (! l_image) + { + opj_destroy_codec(l_codec); + return 1; + } + l_image->x0 = 0; + l_image->y0 = 0; + l_image->x1 = l_image_width; + l_image->y1 = l_image_height; + l_image->color_space = CLRSPC_SRGB; + + if + (! opj_setup_encoder(l_codec,&l_param,l_image)) + { + opj_destroy_codec(l_codec); + opj_image_destroy(l_image); + return 1; + } + + l_file = fopen(l_output_file,"wb"); + if + (! l_file) + { + opj_destroy_codec(l_codec); + opj_image_destroy(l_image); + return 1; + } + + l_stream = opj_stream_create_default_file_stream(l_file,false); + + if + (! opj_start_compress(l_codec,l_image,l_stream)) + { + opj_stream_destroy(l_stream); + fclose(l_file); + opj_destroy_codec(l_codec); + opj_image_destroy(l_image); + return 1; + } + + l_current_tile_nb = 0; + + for + (i=0;i + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#define USE_OPJ_DEPRECATED +/* set this macro to enable profiling for the given test */ +/* warning : in order to be effective, openjpeg must have been built with profiling enabled !! */ +//#define _PROFILE + +#include "openjpeg.h" +#include "stdlib.h" +#ifdef WIN32 +#include +#else +#include +#endif +#define DA_X0 0 +#define DA_Y0 0 +#define DA_X1 1000 +#define DA_Y1 1000 +#define INPUT_FILE "test.j2k" + +/* -------------------------------------------------------------------------- */ + +/** +sample error callback expecting a FILE* client object +*/ +void error_callback_file(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[ERROR] %s", msg); +} +/** +sample warning callback expecting a FILE* client object +*/ +void warning_callback_file(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[WARNING] %s", msg); +} +/** +sample error debug callback expecting no client object +*/ +void error_callback(const char *msg, void *client_data) { + (void)client_data; + fprintf(stdout, "[ERROR] %s", msg); +} +/** +sample warning debug callback expecting no client object +*/ +void warning_callback(const char *msg, void *client_data) { + (void)client_data; + fprintf(stdout, "[WARNING] %s", msg); +} +/** +sample debug callback expecting no client object +*/ +void info_callback(const char *msg, void *client_data) { + (void)client_data; + fprintf(stdout, "[INFO] %s", msg); +} + +/* -------------------------------------------------------------------------- */ + +int main () +{ + opj_dparameters_t l_param; + opj_codec_t * l_codec; + opj_image_t * l_image; + FILE * l_file; + opj_stream_t * l_stream; + OPJ_UINT32 l_data_size; + OPJ_UINT32 l_max_data_size = 1000; + OPJ_UINT32 l_tile_index; + OPJ_BYTE * l_data = (OPJ_BYTE *) malloc(1000); + bool l_go_on = true; + OPJ_INT32 l_tile_x0,l_tile_y0; + OPJ_UINT32 l_tile_width,l_tile_height,l_nb_tiles_x,l_nb_tiles_y,l_nb_comps; + OPJ_INT32 l_current_tile_x0,l_current_tile_y0,l_current_tile_x1,l_current_tile_y1; + + PROFINIT(); + + + if + (! l_data) + { + return 1; + } + opj_set_default_decoder_parameters(&l_param); + + /** you may here add custom decoding parameters */ + /* do not use layer decoding limitations */ + l_param.cp_layer = 0; + + /* do not use resolutions reductions */ + l_param.cp_reduce = 0; + + /* to decode only a part of the image data */ + //opj_restrict_decoding(&l_param,0,0,1000,1000); + + l_codec = opj_create_decompress(CODEC_J2K); + if + (! l_codec) + { + free(l_data); + return 1; + } + + /* catch events using our callbacks and give a local context */ + opj_set_info_handler(l_codec, info_callback,00); + opj_set_warning_handler(l_codec, warning_callback,00); + opj_set_error_handler(l_codec, error_callback,00); + + if + (! opj_setup_decoder(l_codec,&l_param)) + { + free(l_data); + opj_destroy_codec(l_codec); + return 1; + } + + l_file = fopen(INPUT_FILE,"rb"); + if + (! l_file) + { + fprintf(stdout, "Error opening input file\n"); + free(l_data); + opj_destroy_codec(l_codec); + return 1; + } + + l_stream = opj_stream_create_default_file_stream(l_file,true); + + if + (! opj_read_header(l_codec, + &l_image, + &l_tile_x0, + &l_tile_y0, + &l_tile_width, + &l_tile_height, + &l_nb_tiles_x, + &l_nb_tiles_y, + l_stream)) + { + free(l_data); + opj_stream_destroy(l_stream); + fclose(l_file); + opj_destroy_codec(l_codec); + return 1; + } + printf("Setting decoding area to %d,%d,%d,%d\n", DA_X0, DA_Y0, DA_X1, DA_Y1); + opj_set_decode_area(l_codec, DA_X0, DA_Y0, DA_X1, DA_Y1); + while + (l_go_on) + { + if + (! opj_read_tile_header( + l_codec, + &l_tile_index, + &l_data_size, + &l_current_tile_x0, + &l_current_tile_y0, + &l_current_tile_x1, + &l_current_tile_y1, + &l_nb_comps, + &l_go_on, + l_stream)) + { + free(l_data); + opj_stream_destroy(l_stream); + fclose(l_file); + opj_destroy_codec(l_codec); + opj_image_destroy(l_image); + return 1; + } + if + (l_go_on) + { + if + (l_data_size > l_max_data_size) + { + l_data = (OPJ_BYTE *) realloc(l_data,l_data_size); + if + (! l_data) + { + opj_stream_destroy(l_stream); + fclose(l_file); + opj_destroy_codec(l_codec); + opj_image_destroy(l_image); + return 1; + } + l_max_data_size = l_data_size; + } + + if + (! opj_decode_tile_data(l_codec,l_tile_index,l_data,l_data_size,l_stream)) + { + free(l_data); + opj_stream_destroy(l_stream); + fclose(l_file); + opj_destroy_codec(l_codec); + opj_image_destroy(l_image); + return 1; + } + /** now should inspect image to know the reduction factor and then how to behave with data */ + } + } + if + (! opj_end_decompress(l_codec,l_stream)) + { + free(l_data); + opj_stream_destroy(l_stream); + fclose(l_file); + opj_destroy_codec(l_codec); + opj_image_destroy(l_image); + return 1; + } + free(l_data); + opj_stream_destroy(l_stream); + fclose(l_file); + opj_destroy_codec(l_codec); + opj_image_destroy(l_image); + + // Print profiling + PROFPRINT(); + + return 0; +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/test_V2_tile_handling/test_encoder.c b/gdcm/Utilities/gdcmopenjpeg-v2/test_V2_tile_handling/test_encoder.c new file mode 100644 index 0000000..2a10f49 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/test_V2_tile_handling/test_encoder.c @@ -0,0 +1,301 @@ +/* + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#define USE_OPJ_DEPRECATED + +#include "openjpeg.h" +#include "stdlib.h" + +/* set this macro to enable profiling for the given test */ +/* warning : in order to be effective, openjpeg must have been built with profiling enabled !! */ +//#define _PROFILE + +#ifdef WIN32 +#include "windows.h" // needed for rand() function +#else +#include +#endif + + +#define NUM_COMPS 3 +#define IMAGE_WIDTH 2000 +#define IMAGE_HEIGHT 2000 +#define TILE_WIDTH 1000 +#define TILE_HEIGHT 1000 +#define COMP_PREC 8 +#define OUTPUT_FILE "test.j2k" + +/* -------------------------------------------------------------------------- */ + +/** +sample error callback expecting a FILE* client object +*/ +void error_callback_file(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[ERROR] %s", msg); +} +/** +sample warning callback expecting a FILE* client object +*/ +void warning_callback_file(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[WARNING] %s", msg); +} +/** +sample error debug callback expecting no client object +*/ +void error_callback(const char *msg, void *client_data) { + (void)client_data; + fprintf(stdout, "[ERROR] %s", msg); +} +/** +sample warning debug callback expecting no client object +*/ +void warning_callback(const char *msg, void *client_data) { + (void)client_data; + fprintf(stdout, "[WARNING] %s", msg); +} +/** +sample debug callback expecting no client object +*/ +void info_callback(const char *msg, void *client_data) { + (void)client_data; + fprintf(stdout, "[INFO] %s", msg); +} + +/* -------------------------------------------------------------------------- */ + +int main () +{ + opj_cparameters_t l_param; + opj_codec_t * l_codec; + opj_image_t * l_image; + opj_image_cmptparm_t l_params [NUM_COMPS]; + FILE * l_file; + opj_stream_t * l_stream; + OPJ_UINT32 l_nb_tiles = (IMAGE_WIDTH/TILE_WIDTH) * (IMAGE_HEIGHT/TILE_HEIGHT); + OPJ_UINT32 l_data_size = TILE_WIDTH * TILE_HEIGHT * NUM_COMPS * (COMP_PREC/8); + +#ifdef USING_MCT + const OPJ_FLOAT32 l_mct [] = + { + 1 , 0 , 0 , + 0 , 1 , 0 , + 0 , 0 , 1 + }; + + const OPJ_INT32 l_offsets [] = + { + 128 , 128 , 128 + }; +#endif + + opj_image_cmptparm_t * l_current_param_ptr; + OPJ_UINT32 i; + OPJ_BYTE *l_data; + + PROFINIT(); + l_data = (OPJ_BYTE*) malloc(TILE_WIDTH * TILE_HEIGHT * NUM_COMPS * (COMP_PREC/8) * sizeof(OPJ_BYTE)); + + fprintf(stdout, "Encoding random values -> keep in mind that this is very hard to compress\n"); + for + (i=0;ibpp = COMP_PREC;*/ + l_current_param_ptr->dx = 1; + l_current_param_ptr->dy = 1; + l_current_param_ptr->h = IMAGE_HEIGHT; + l_current_param_ptr->sgnd = 0; + l_current_param_ptr->prec = COMP_PREC; + l_current_param_ptr->w = IMAGE_WIDTH; + l_current_param_ptr->x0 = 0; + l_current_param_ptr->y0 = 0; + ++l_current_param_ptr; + } + + l_codec = opj_create_compress(CODEC_J2K); + if + (! l_codec) + { + return 1; + } + + /* catch events using our callbacks and give a local context */ + opj_set_info_handler(l_codec, info_callback,00); + opj_set_warning_handler(l_codec, warning_callback,00); + opj_set_error_handler(l_codec, error_callback,00); + + l_image = opj_image_tile_create(NUM_COMPS,l_params,CLRSPC_SRGB); + if + (! l_image) + { + opj_destroy_codec(l_codec); + return 1; + } + l_image->x0 = 0; + l_image->y0 = 0; + l_image->x1 = IMAGE_WIDTH; + l_image->y1 = IMAGE_HEIGHT; + l_image->color_space = CLRSPC_SRGB; + + if + (! opj_setup_encoder(l_codec,&l_param,l_image)) + { + opj_destroy_codec(l_codec); + opj_image_destroy(l_image); + return 1; + } + + l_file = fopen(OUTPUT_FILE,"wb"); + if + (! l_file) + { + opj_destroy_codec(l_codec); + opj_image_destroy(l_image); + return 1; + } + + l_stream = opj_stream_create_default_file_stream(l_file,false); + + if + (! opj_start_compress(l_codec,l_image,l_stream)) + { + opj_stream_destroy(l_stream); + fclose(l_file); + opj_destroy_codec(l_codec); + opj_image_destroy(l_image); + return 1; + } + for + (i=0;i + +namespace utf8 +{ + // Exceptions that may be thrown from the library functions. + class invalid_code_point : public std::exception { + uint32_t cp; + public: + invalid_code_point(uint32_t cp) : cp(cp) {} + virtual const char* what() const throw() { return "Invalid code point"; } + uint32_t code_point() const {return cp;} + }; + + class invalid_utf8 : public std::exception { + uint8_t u8; + public: + invalid_utf8 (uint8_t u) : u8(u) {} + virtual const char* what() const throw() { return "Invalid UTF-8"; } + uint8_t utf8_octet() const {return u8;} + }; + + class invalid_utf16 : public std::exception { + uint16_t u16; + public: + invalid_utf16 (uint16_t u) : u16(u) {} + virtual const char* what() const throw() { return "Invalid UTF-16"; } + uint16_t utf16_word() const {return u16;} + }; + + class not_enough_room : public std::exception { + public: + virtual const char* what() const throw() { return "Not enough space"; } + }; + + /// The library API - functions intended to be called by the users + + template + output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, uint32_t replacement) + { + while (start != end) { + octet_iterator sequence_start = start; + internal::utf_error err_code = internal::validate_next(start, end); + switch (err_code) { + case internal::UTF8_OK : + for (octet_iterator it = sequence_start; it != start; ++it) + *out++ = *it; + break; + case internal::NOT_ENOUGH_ROOM: + throw not_enough_room(); + case internal::INVALID_LEAD: + append (replacement, out); + ++start; + break; + case internal::INCOMPLETE_SEQUENCE: + case internal::OVERLONG_SEQUENCE: + case internal::INVALID_CODE_POINT: + append (replacement, out); + ++start; + // just one replacement mark for the sequence + while (internal::is_trail(*start) && start != end) + ++start; + break; + } + } + return out; + } + + template + inline output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out) + { + static const uint32_t replacement_marker = internal::mask16(0xfffd); + return replace_invalid(start, end, out, replacement_marker); + } + + template + octet_iterator append(uint32_t cp, octet_iterator result) + { + if (!internal::is_code_point_valid(cp)) + throw invalid_code_point(cp); + + if (cp < 0x80) // one octet + *(result++) = static_cast(cp); + else if (cp < 0x800) { // two octets + *(result++) = static_cast((cp >> 6) | 0xc0); + *(result++) = static_cast((cp & 0x3f) | 0x80); + } + else if (cp < 0x10000) { // three octets + *(result++) = static_cast((cp >> 12) | 0xe0); + *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); + *(result++) = static_cast((cp & 0x3f) | 0x80); + } + else { // four octets + *(result++) = static_cast((cp >> 18) | 0xf0); + *(result++) = static_cast(((cp >> 12) & 0x3f) | 0x80); + *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); + *(result++) = static_cast((cp & 0x3f) | 0x80); + } + return result; + } + + template + uint32_t next(octet_iterator& it, octet_iterator end) + { + uint32_t cp = 0; + internal::utf_error err_code = internal::validate_next(it, end, &cp); + switch (err_code) { + case internal::UTF8_OK : + break; + case internal::NOT_ENOUGH_ROOM : + throw not_enough_room(); + case internal::INVALID_LEAD : + case internal::INCOMPLETE_SEQUENCE : + case internal::OVERLONG_SEQUENCE : + throw invalid_utf8(*it); + case internal::INVALID_CODE_POINT : + throw invalid_code_point(cp); + } + return cp; + } + + template + uint32_t peek_next(octet_iterator it, octet_iterator end) + { + return next(it, end); + } + + template + uint32_t prior(octet_iterator& it, octet_iterator start) + { + octet_iterator end = it; + while (internal::is_trail(*(--it))) + if (it < start) + throw invalid_utf8(*it); // error - no lead byte in the sequence + octet_iterator temp = it; + return next(temp, end); + } + + /// Deprecated in versions that include "prior" + template + uint32_t previous(octet_iterator& it, octet_iterator pass_start) + { + octet_iterator end = it; + while (internal::is_trail(*(--it))) + if (it == pass_start) + throw invalid_utf8(*it); // error - no lead byte in the sequence + octet_iterator temp = it; + return next(temp, end); + } + + template + void advance (octet_iterator& it, distance_type n, octet_iterator end) + { + for (distance_type i = 0; i < n; ++i) + next(it, end); + } + + template + typename std::iterator_traits::difference_type + distance (octet_iterator first, octet_iterator last) + { + typename std::iterator_traits::difference_type dist; + for (dist = 0; first < last; ++dist) + next(first, last); + return dist; + } + + template + octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result) + { + while (start != end) { + uint32_t cp = internal::mask16(*start++); + // Take care of surrogate pairs first + if (internal::is_lead_surrogate(cp)) { + if (start != end) { + uint32_t trail_surrogate = internal::mask16(*start++); + if (internal::is_trail_surrogate(trail_surrogate)) + cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET; + else + throw invalid_utf16(static_cast(trail_surrogate)); + } + else + throw invalid_utf16(static_cast(cp)); + + } + // Lone trail surrogate + else if (internal::is_trail_surrogate(cp)) + throw invalid_utf16(static_cast(cp)); + + result = append(cp, result); + } + return result; + } + + template + u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result) + { + while (start != end) { + uint32_t cp = next(start, end); + if (cp > 0xffff) { //make a surrogate pair + *result++ = static_cast((cp >> 10) + internal::LEAD_OFFSET); + *result++ = static_cast((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN); + } + else + *result++ = static_cast(cp); + } + return result; + } + + template + octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result) + { + while (start != end) + result = append(*(start++), result); + + return result; + } + + template + u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result) + { + while (start < end) + (*result++) = next(start, end); + + return result; + } + + // The iterator class + template + class iterator : public std::iterator { + octet_iterator it; + octet_iterator range_start; + octet_iterator range_end; + public: + iterator () {}; + explicit iterator (const octet_iterator& octet_it, + const octet_iterator& range_start, + const octet_iterator& range_end) : + it(octet_it), range_start(range_start), range_end(range_end) + { + if (it < range_start || it > range_end) + throw std::out_of_range("Invalid utf-8 iterator position"); + } + // the default "big three" are OK + octet_iterator base () const { return it; } + uint32_t operator * () const + { + octet_iterator temp = it; + return next(temp, range_end); + } + bool operator == (const iterator& rhs) const + { + if (range_start != rhs.range_start || range_end != rhs.range_end) + throw std::logic_error("Comparing utf-8 iterators defined with different ranges"); + return (it == rhs.it); + } + bool operator != (const iterator& rhs) const + { + return !(operator == (rhs)); + } + iterator& operator ++ () + { + next(it, range_end); + return *this; + } + iterator operator ++ (int) + { + iterator temp = *this; + next(it, range_end); + return temp; + } + iterator& operator -- () + { + prior(it, range_start); + return *this; + } + iterator operator -- (int) + { + iterator temp = *this; + prior(it, range_start); + return temp; + } + }; // class iterator + +} // namespace utf8 + +#endif //header guard + + diff --git a/gdcm/Utilities/gdcmutfcpp/utf8/core.h b/gdcm/Utilities/gdcmutfcpp/utf8/core.h new file mode 100644 index 0000000..5a55f06 --- /dev/null +++ b/gdcm/Utilities/gdcmutfcpp/utf8/core.h @@ -0,0 +1,346 @@ +// Copyright 2006 Nemanja Trifunovic + +/* +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + + +#ifndef UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 +#define UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 + +#include + +namespace utf8 +{ + // The typedefs for 8-bit, 16-bit and 32-bit unsigned integers + // You may need to change them to match your system. + // These typedefs have the same names as ones from cstdint, or boost/cstdint + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + typedef unsigned int uint32_t; + +// Helper code - not intended to be directly called by the library users. May be changed at any time +namespace internal +{ + // Unicode constants + // Leading (high) surrogates: 0xd800 - 0xdbff + // Trailing (low) surrogates: 0xdc00 - 0xdfff + const uint16_t LEAD_SURROGATE_MIN = 0xd800u; + const uint16_t LEAD_SURROGATE_MAX = 0xdbffu; + const uint16_t TRAIL_SURROGATE_MIN = 0xdc00u; + const uint16_t TRAIL_SURROGATE_MAX = 0xdfffu; + const uint16_t LEAD_OFFSET = LEAD_SURROGATE_MIN - (0x10000 >> 10); + const uint32_t SURROGATE_OFFSET = 0x10000u - (LEAD_SURROGATE_MIN << 10) - TRAIL_SURROGATE_MIN; + + // Maximum valid value for a Unicode code point + const uint32_t CODE_POINT_MAX = 0x0010ffffu; + + template + inline uint8_t mask8(octet_type oc) + { + return static_cast(0xff & oc); + } + template + inline uint16_t mask16(u16_type oc) + { + return static_cast(0xffff & oc); + } + template + inline bool is_trail(octet_type oc) + { + return ((mask8(oc) >> 6) == 0x2); + } + + template + inline bool is_lead_surrogate(u16 cp) + { + return (cp >= LEAD_SURROGATE_MIN && cp <= LEAD_SURROGATE_MAX); + } + + template + inline bool is_trail_surrogate(u16 cp) + { + return (cp >= TRAIL_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX); + } + + template + inline bool is_surrogate(u16 cp) + { + return (cp >= LEAD_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX); + } + + template + inline bool is_code_point_valid(u32 cp) + { + return (cp <= CODE_POINT_MAX && !is_surrogate(cp) && cp != 0xfffe && cp != 0xffff); + } + + template + inline typename std::iterator_traits::difference_type + sequence_length(octet_iterator lead_it) + { + uint8_t lead = mask8(*lead_it); + if (lead < 0x80) + return 1; + else if ((lead >> 5) == 0x6) + return 2; + else if ((lead >> 4) == 0xe) + return 3; + else if ((lead >> 3) == 0x1e) + return 4; + else + return 0; + } + + inline bool is_overlong_sequence(uint32_t cp, int length) + { + if (cp < 0x80) { + if (length != 1) + return true; + } + else if (cp < 0x800) { + if (length != 2) + return true; + } + else if (cp < 0x10000) { + if (length != 3) + return true; + } + + return false; + } + + enum utf_error {UTF8_OK, NOT_ENOUGH_ROOM, INVALID_LEAD, INCOMPLETE_SEQUENCE, OVERLONG_SEQUENCE, INVALID_CODE_POINT}; + + /// get_sequence_x functions decode utf-8 sequences of the length x + + template + utf_error get_sequence_1(octet_iterator& it, octet_iterator end, uint32_t* code_point) + { + if (it != end) { + if (code_point) + *code_point = mask8(*it); + return UTF8_OK; + } + return NOT_ENOUGH_ROOM; + } + + template + utf_error get_sequence_2(octet_iterator& it, octet_iterator end, uint32_t* code_point) + { + utf_error ret_code = NOT_ENOUGH_ROOM; + + if (it != end) { + uint32_t cp = mask8(*it); + if (++it != end) { + if (is_trail(*it)) { + cp = ((cp << 6) & 0x7ff) + ((*it) & 0x3f); + + if (code_point) + *code_point = cp; + ret_code = UTF8_OK; + } + else + ret_code = INCOMPLETE_SEQUENCE; + } + else + ret_code = NOT_ENOUGH_ROOM; + } + + return ret_code; + } + + template + utf_error get_sequence_3(octet_iterator& it, octet_iterator end, uint32_t* code_point) + { + utf_error ret_code = NOT_ENOUGH_ROOM; + + if (it != end) { + uint32_t cp = mask8(*it); + if (++it != end) { + if (is_trail(*it)) { + cp = ((cp << 12) & 0xffff) + ((mask8(*it) << 6) & 0xfff); + if (++it != end) { + if (is_trail(*it)) { + cp += (*it) & 0x3f; + + if (code_point) + *code_point = cp; + ret_code = UTF8_OK; + } + else + ret_code = INCOMPLETE_SEQUENCE; + } + else + ret_code = NOT_ENOUGH_ROOM; + } + else + ret_code = INCOMPLETE_SEQUENCE; + } + else + ret_code = NOT_ENOUGH_ROOM; + } + + return ret_code; + } + + template + utf_error get_sequence_4(octet_iterator& it, octet_iterator end, uint32_t* code_point) + { + utf_error ret_code = NOT_ENOUGH_ROOM; + + if (it != end) { + uint32_t cp = mask8(*it); + if (++it != end) { + if (is_trail(*it)) { + cp = ((cp << 18) & 0x1fffff) + ((mask8(*it) << 12) & 0x3ffff); + if (++it != end) { + if (is_trail(*it)) { + cp += (mask8(*it) << 6) & 0xfff; + if (++it != end) { + if (is_trail(*it)) { + cp += (*it) & 0x3f; + + if (code_point) + *code_point = cp; + ret_code = UTF8_OK; + } + else + ret_code = INCOMPLETE_SEQUENCE; + } + else + ret_code = NOT_ENOUGH_ROOM; + } + else + ret_code = INCOMPLETE_SEQUENCE; + } + else + ret_code = NOT_ENOUGH_ROOM; + } + else + ret_code = INCOMPLETE_SEQUENCE; + } + else + ret_code = NOT_ENOUGH_ROOM; + } + + return ret_code; + } + + template + utf_error validate_next(octet_iterator& it, octet_iterator end, uint32_t* code_point) + { + // Save the original value of it so we can go back in case of failure + // Of course, it does not make much sense with i.e. stream iterators + octet_iterator original_it = it; + + uint32_t cp = 0; + // Determine the sequence length based on the lead octet + typedef typename std::iterator_traits::difference_type octet_difference_type; + octet_difference_type length = sequence_length(it); + if (length == 0) + return INVALID_LEAD; + + // Now that we have a valid sequence length, get trail octets and calculate the code point + utf_error err = UTF8_OK; + switch (length) { + case 1: + err = get_sequence_1(it, end, &cp); + break; + case 2: + err = get_sequence_2(it, end, &cp); + break; + case 3: + err = get_sequence_3(it, end, &cp); + break; + case 4: + err = get_sequence_4(it, end, &cp); + break; + } + + if (err == UTF8_OK) { + // Decoding succeeded. Now, security checks... + if (is_code_point_valid(cp)) { + if (!is_overlong_sequence(cp, length)){ + // Passed! Return here. + if (code_point) + *code_point = cp; + ++it; + return UTF8_OK; + } + else + err = OVERLONG_SEQUENCE; + } + else + err = INVALID_CODE_POINT; + } + + // Failure branch - restore the original value of the iterator + it = original_it; + return err; + } + + template + inline utf_error validate_next(octet_iterator& it, octet_iterator end) { + return validate_next(it, end, 0); + } + +} // namespace internal + + /// The library API - functions intended to be called by the users + + // Byte order mark + const uint8_t bom[] = {0xef, 0xbb, 0xbf}; + + template + octet_iterator find_invalid(octet_iterator start, octet_iterator end) + { + octet_iterator result = start; + while (result != end) { + internal::utf_error err_code = internal::validate_next(result, end); + if (err_code != internal::UTF8_OK) + return result; + } + return result; + } + + template + inline bool is_valid(octet_iterator start, octet_iterator end) + { + return (find_invalid(start, end) == end); + } + + template + inline bool is_bom (octet_iterator it) + { + return ( + (internal::mask8(*it++)) == bom[0] && + (internal::mask8(*it++)) == bom[1] && + (internal::mask8(*it)) == bom[2] + ); + } +} // namespace utf8 + +#endif // header guard + + diff --git a/gdcm/Utilities/gdcmutfcpp/utf8/unchecked.h b/gdcm/Utilities/gdcmutfcpp/utf8/unchecked.h new file mode 100644 index 0000000..d3110cb --- /dev/null +++ b/gdcm/Utilities/gdcmutfcpp/utf8/unchecked.h @@ -0,0 +1,228 @@ +// Copyright 2006 Nemanja Trifunovic + +/* +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + + +#ifndef UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 +#define UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 + +#include "core.h" + +namespace utf8 +{ + namespace unchecked + { + template + octet_iterator append(uint32_t cp, octet_iterator result) + { + if (cp < 0x80) // one octet + *(result++) = static_cast(cp); + else if (cp < 0x800) { // two octets + *(result++) = static_cast((cp >> 6) | 0xc0); + *(result++) = static_cast((cp & 0x3f) | 0x80); + } + else if (cp < 0x10000) { // three octets + *(result++) = static_cast((cp >> 12) | 0xe0); + *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); + *(result++) = static_cast((cp & 0x3f) | 0x80); + } + else { // four octets + *(result++) = static_cast((cp >> 18) | 0xf0); + *(result++) = static_cast(((cp >> 12) & 0x3f)| 0x80); + *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); + *(result++) = static_cast((cp & 0x3f) | 0x80); + } + return result; + } + + template + uint32_t next(octet_iterator& it) + { + uint32_t cp = internal::mask8(*it); + typename std::iterator_traits::difference_type length = utf8::internal::sequence_length(it); + switch (length) { + case 1: + break; + case 2: + it++; + cp = ((cp << 6) & 0x7ff) + ((*it) & 0x3f); + break; + case 3: + ++it; + cp = ((cp << 12) & 0xffff) + ((internal::mask8(*it) << 6) & 0xfff); + ++it; + cp += (*it) & 0x3f; + break; + case 4: + ++it; + cp = ((cp << 18) & 0x1fffff) + ((internal::mask8(*it) << 12) & 0x3ffff); + ++it; + cp += (internal::mask8(*it) << 6) & 0xfff; + ++it; + cp += (*it) & 0x3f; + break; + } + ++it; + return cp; + } + + template + uint32_t peek_next(octet_iterator it) + { + return next(it); + } + + template + uint32_t prior(octet_iterator& it) + { + while (internal::is_trail(*(--it))) ; + octet_iterator temp = it; + return next(temp); + } + + // Deprecated in versions that include prior, but only for the sake of consistency (see utf8::previous) + template + inline uint32_t previous(octet_iterator& it) + { + return prior(it); + } + + template + void advance (octet_iterator& it, distance_type n) + { + for (distance_type i = 0; i < n; ++i) + next(it); + } + + template + typename std::iterator_traits::difference_type + distance (octet_iterator first, octet_iterator last) + { + typename std::iterator_traits::difference_type dist; + for (dist = 0; first < last; ++dist) + next(first); + return dist; + } + + template + octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result) + { + while (start != end) { + uint32_t cp = internal::mask16(*start++); + // Take care of surrogate pairs first + if (internal::is_lead_surrogate(cp)) { + uint32_t trail_surrogate = internal::mask16(*start++); + cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET; + } + result = append(cp, result); + } + return result; + } + + template + u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result) + { + while (start != end) { + uint32_t cp = next(start); + if (cp > 0xffff) { //make a surrogate pair + *result++ = static_cast((cp >> 10) + internal::LEAD_OFFSET); + *result++ = static_cast((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN); + } + else + *result++ = static_cast(cp); + } + return result; + } + + template + octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result) + { + while (start != end) + result = append(*(start++), result); + + return result; + } + + template + u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result) + { + while (start < end) + (*result++) = next(start); + + return result; + } + + // The iterator class + template + class iterator : public std::iterator { + octet_iterator it; + public: + iterator () {}; + explicit iterator (const octet_iterator& octet_it): it(octet_it) {} + // the default "big three" are OK + octet_iterator base () const { return it; } + uint32_t operator * () const + { + octet_iterator temp = it; + return next(temp); + } + bool operator == (const iterator& rhs) const + { + return (it == rhs.it); + } + bool operator != (const iterator& rhs) const + { + return !(operator == (rhs)); + } + iterator& operator ++ () + { + std::advance(it, internal::sequence_length(it)); + return *this; + } + iterator operator ++ (int) + { + iterator temp = *this; + std::advance(it, internal::sequence_length(it)); + return temp; + } + iterator& operator -- () + { + prior(it); + return *this; + } + iterator operator -- (int) + { + iterator temp = *this; + prior(it); + return temp; + } + }; // class iterator + + } // namespace utf8::unchecked +} // namespace utf8 + + +#endif // header guard + diff --git a/gdcm/Utilities/gdcmuuid/.NoDartCoverage b/gdcm/Utilities/gdcmuuid/.NoDartCoverage new file mode 100644 index 0000000..3c99729 --- /dev/null +++ b/gdcm/Utilities/gdcmuuid/.NoDartCoverage @@ -0,0 +1 @@ +# do not do coverage in this directory diff --git a/gdcm/Utilities/gdcmuuid/CMakeLists.txt b/gdcm/Utilities/gdcmuuid/CMakeLists.txt new file mode 100644 index 0000000..5fd8a14 --- /dev/null +++ b/gdcm/Utilities/gdcmuuid/CMakeLists.txt @@ -0,0 +1,125 @@ +cmake_minimum_required(VERSION 2.8.9) + +if(NOT UUID_NAMESPACE) + set(UUID_NAMESPACE "UUID") + set(UUID_STANDALONE 1) +endif() +# In all cases: +string(TOLOWER ${UUID_NAMESPACE} UUID_LIBRARY_NAME) + +project(${UUID_NAMESPACE} C) + +# Do full dependency headers. +include_regular_expression("^.*$") + +set(UUID_SRCS +compare.c +gen_uuid.c +pack.c +parse.c +unpack.c +unparse.c +uuid_time.c +uuid.h +uuidP.h +) + +#include (${CMAKE_ROOT}/Modules/CheckIncludeFile.cmake) + +if(WIN32) + if (BUILD_SHARED_LIBS) + add_definitions(-DUUID_DLL) + endif () +endif() + +if(COMMAND CHECK_INCLUDE_FILE_CONCAT) +else() +include (${CMAKE_ROOT}/Modules/CheckIncludeFile.cmake) +include (${CMAKE_ROOT}/Modules/CheckIncludeFiles.cmake) + +macro(CHECK_INCLUDE_FILE_CONCAT FILE VARIABLE) + CHECK_INCLUDE_FILES("${UUID_INCLUDES};${FILE}" ${VARIABLE}) + if(${VARIABLE}) + set(UUID_INCLUDES ${UUID_INCLUDES} ${FILE}) + endif() +endmacro() +endif() + +CHECK_INCLUDE_FILE_CONCAT("stdlib.h" HAVE_STDLIB_H) +if(UNIX) #Avoid polluting Win32 cmakecache + CHECK_INCLUDE_FILE_CONCAT("unistd.h" HAVE_UNISTD_H) + CHECK_INCLUDE_FILE_CONCAT("inttypes.h" HAVE_INTTYPES_H) + CHECK_INCLUDE_FILE_CONCAT("sys/ioctl.h" HAVE_SYS_IOCTL_H) + CHECK_INCLUDE_FILE_CONCAT("sys/time.h" HAVE_SYS_TIME_H) + CHECK_INCLUDE_FILE_CONCAT("sys/file.h" HAVE_SYS_FILE_H) + CHECK_INCLUDE_FILE_CONCAT("sys/socket.h" HAVE_SYS_SOCKET_H) + CHECK_INCLUDE_FILE_CONCAT("sys/sockio.h" HAVE_SYS_SOCKIO_H) + CHECK_INCLUDE_FILE_CONCAT("net/if.h" HAVE_NET_IF_H) + CHECK_INCLUDE_FILE_CONCAT("netinet/in.h" HAVE_NETINET_IN_H) + CHECK_INCLUDE_FILE_CONCAT("net/if_dl.h" HAVE_NET_IF_DL_H) + CHECK_INCLUDE_FILE_CONCAT("net/if_arp.h" HAVE_NET_IF_ARP_H) +endif() +if(WIN32) #Avoid polluting UNIX cmakecache + CHECK_INCLUDE_FILE_CONCAT("winsock.h" HAVE_WINSOCK_H) +endif() + +set(UUID_HAVES_ALL + HAVE_STDLIB_H + HAVE_UNISTD_H + HAVE_INTTYPES_H + HAVE_SYS_IOCTL_H + #HAVE_SYS_TIME_H + HAVE_SYS_FILE_H + HAVE_SYS_SOCKET_H + HAVE_SYS_SOCKIO_H + HAVE_NET_IF_H + HAVE_NETINET_IN_H + HAVE_NET_IF_DL_H + HAVE_NET_IF_ARP_H + HAVE_WINSOCK_H +) + +set(UUID_HAVES) +foreach(have ${UUID_HAVES_ALL}) + if(${${have}}) + set(UUID_HAVES "${UUID_HAVES} -D${have}") + endif() +endforeach() +# Pass all -D : +if( UUID_HAVES ) +set_source_files_properties( ${UUID_SRCS} + PROPERTIES COMPILE_FLAGS ${UUID_HAVES}) +endif() + +set(MANGLE_PREFIX ${UUID_LIBRARY_NAME}) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/uuid_mangle.h.in + ${CMAKE_CURRENT_BINARY_DIR}/uuid_mangle.h + @ONLY ) + +# for uuid_mangle.h +include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR}) + +add_library(${UUID_LIBRARY_NAME} ${UUID_SRCS}) +if(GDCM_LIBRARY_PROPERTIES) +set_target_properties(${UUID_LIBRARY_NAME} PROPERTIES ${GDCM_LIBRARY_PROPERTIES}) +endif() +if(WIN32 AND NOT CYGWIN) + target_link_libraries(${UUID_LIBRARY_NAME} iphlpapi) +endif() + +if(NOT UUID_INSTALL_BIN_DIR) + set(UUID_INSTALL_BIN_DIR "bin") +endif() +if(NOT UUID_INSTALL_LIB_DIR) + set(UUID_INSTALL_LIB_DIR "lib") +endif() + +if(NOT UUID_INSTALL_NO_LIBRARIES) + install(TARGETS ${UUID_LIBRARY_NAME} + EXPORT ${GDCM_TARGETS_NAME} + RUNTIME DESTINATION ${UUID_INSTALL_BIN_DIR} COMPONENT Applications + LIBRARY DESTINATION ${UUID_INSTALL_LIB_DIR} COMPONENT Libraries + ARCHIVE DESTINATION ${UUID_INSTALL_LIB_DIR} COMPONENT DebugDevel + ${CPACK_NAMELINK_TYPE} + ) +endif() diff --git a/gdcm/Utilities/gdcmuuid/COPYING b/gdcm/Utilities/gdcmuuid/COPYING new file mode 100644 index 0000000..8dcc0ee --- /dev/null +++ b/gdcm/Utilities/gdcmuuid/COPYING @@ -0,0 +1,31 @@ +/* + * Copyright (C) 1996, 1997 Theodore Ts'o. + * + * %Begin-Header% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * %End-Header% + */ diff --git a/gdcm/Utilities/gdcmuuid/compare.c b/gdcm/Utilities/gdcmuuid/compare.c new file mode 100644 index 0000000..b2c0d3a --- /dev/null +++ b/gdcm/Utilities/gdcmuuid/compare.c @@ -0,0 +1,55 @@ +/* vi: set sw=4 ts=4: */ +/* + * compare.c --- compare whether or not two UUID's are the same + * + * Returns 0 if the two UUID's are different, and 1 if they are the same. + * + * Copyright (C) 1996, 1997 Theodore Ts'o. + * + * %Begin-Header% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * %End-Header% + */ + +#include "uuidP.h" +#include + +#define UUCMP(u1,u2) if (u1 != u2) return((u1 < u2) ? -1 : 1); + +int uuid_compare(const uuid_t uu1, const uuid_t uu2) +{ + struct uuid uuid1, uuid2; + + uuid_unpack(uu1, &uuid1); + uuid_unpack(uu2, &uuid2); + + UUCMP(uuid1.time_low, uuid2.time_low); + UUCMP(uuid1.time_mid, uuid2.time_mid); + UUCMP(uuid1.time_hi_and_version, uuid2.time_hi_and_version); + UUCMP(uuid1.clock_seq, uuid2.clock_seq); + return memcmp(uuid1.node, uuid2.node, 6); +} diff --git a/gdcm/Utilities/gdcmuuid/gen_uuid.c b/gdcm/Utilities/gdcmuuid/gen_uuid.c new file mode 100644 index 0000000..106d860 --- /dev/null +++ b/gdcm/Utilities/gdcmuuid/gen_uuid.c @@ -0,0 +1,430 @@ +/* vi: set sw=4 ts=4: */ +/* + * gen_uuid.c --- generate a DCE-compatible uuid + * + * Copyright (C) 1996, 1997, 1998, 1999 Theodore Ts'o. + * + * %Begin-Header% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * %End-Header% + */ + +/* + * Force inclusion of SVID stuff since we need it if we're compiling in + * gcc-wall wall mode + */ +#define _SVID_SOURCE + +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#include +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_FILE_H +#include +#endif +#if HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_IOCTL_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_SYS_SOCKIO_H +#include +#endif +#ifdef HAVE_NET_IF_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NET_IF_DL_H +#include +#endif +#ifdef HAVE_WINSOCK_H +#include /* timeval */ +#endif + +#include "uuidP.h" + +#ifdef HAVE_SRANDOM +#define srand(x) srandom(x) +#define rand() random() +#endif + +#if defined(_WIN32) +/* offer a limited gettimeofday on Win32 system */ +#include +static int gettimeofday(struct timeval *tv, struct timezone *tz) +{ + FILETIME ft; + const uint64_t c1 = 27111902; + const uint64_t c2 = 3577643008UL; + const uint64_t OFFSET = (c1 << 32) + c2; + uint64_t filetime; + GetSystemTimeAsFileTime(&ft); + + filetime = ft.dwHighDateTime; + filetime = filetime << 32; + filetime += ft.dwLowDateTime; + filetime -= OFFSET; + + memset(tv,0, sizeof(*tv)); + assert( sizeof(*tv) == sizeof(struct timeval)); + tv->tv_sec = (time_t)(filetime / 10000000); /* seconds since epoch */ + tv->tv_usec = (uint32_t)((filetime % 10000000) / 10); + + return 0; +} +/* provide unimplemented open call */ +#define O_NONBLOCK 0 +int open(const char *pathname, int flags) +{ + return -1; +} +typedef int pid_t; +pid_t getpid(void) +{ + return 0; +} +typedef int uid_t; +uid_t getuid(void) +{ + return 0; +} +typedef int ssize_t; +ssize_t read(int fd, void *buf, size_t count) +{ + return -1; +} +#endif + +static int get_random_fd(void) +{ + struct timeval tv; + static int fd = -2; + int i; + + if (fd == -2) { + gettimeofday(&tv, 0); + fd = open("/dev/urandom", O_RDONLY); + if (fd == -1) + fd = open("/dev/random", O_RDONLY | O_NONBLOCK); + srand((getpid() << 16) ^ getuid() ^ tv.tv_sec ^ tv.tv_usec); + } + /* Crank the random number generator a few times */ + gettimeofday(&tv, 0); + for (i = (tv.tv_sec ^ tv.tv_usec) & 0x1F; i > 0; i--) + rand(); + return fd; +} + + +/* + * Generate a series of random bytes. Use /dev/urandom if possible, + * and if not, use srandom/random. + */ +static void get_random_bytes(void *buf, int nbytes) +{ + int i, n = nbytes, fd = get_random_fd(); + int lose_counter = 0; + unsigned char *cp = (unsigned char *) buf; + + if (fd >= 0) { + while (n > 0) { + i = read(fd, cp, n); + if (i <= 0) { + if (lose_counter++ > 16) + break; + continue; + } + n -= i; + cp += i; + lose_counter = 0; + } + } + + /* + * We do this all the time, but this is the only source of + * randomness if /dev/random/urandom is out to lunch. + */ + for (cp = buf, i = 0; i < nbytes; i++) + *cp++ ^= (rand() >> 7) & 0xFF; +} + +#if defined(_WIN32) +#include /* very important */ + +#include /* remember to link w/ iphlpapi.lib */ +#if defined(uuid_t) +#undef uuid_t +#endif + + +#define IP_LOCALHOST 0x0100007F + +static int get_node_id(unsigned char *byMAC) +{ + DWORD i, dwSize; + PMIB_IPADDRTABLE pAddr = NULL; + MIB_IFROW iInfo; + PFIXED_INFO pFI = NULL; + + /* Get all IP addresses held by this machine; if it's connected to a network, there's at least one + that's not localhost */ + dwSize = 0; + GetIpAddrTable(NULL, &dwSize, TRUE); + pAddr = (PMIB_IPADDRTABLE)malloc(sizeof(BYTE) * dwSize); + if (!GetIpAddrTable(pAddr, &dwSize, TRUE)) + { + for (i = 0; i < pAddr->dwNumEntries; ++i) + { + if (IP_LOCALHOST != pAddr->table[i].dwAddr) + { + /* Not localhost, so get the interface */ + memset(&iInfo, 0, sizeof(MIB_IFROW)); + iInfo.dwIndex = pAddr->table[i].dwIndex; + GetIfEntry(&iInfo); + + if (MIB_IF_TYPE_ETHERNET == iInfo.dwType) + { + /*iInfo.bPhysAddr contains the MAC address of this interface*/ + memcpy(byMAC, iInfo.bPhysAddr, iInfo.dwPhysAddrLen); + free(pAddr); + return 1; + } + } + } + } + free(pAddr); + return 0; +} +#else +/* + * Get the ethernet hardware address, if we can find it... + */ +static int get_node_id(unsigned char *node_id) +{ +#ifdef HAVE_NET_IF_H + int sd; + struct ifreq ifr, *ifrp; + struct ifconf ifc; + char buf[1024]; + int n, i; + unsigned char *a; +#ifdef HAVE_NET_IF_DL_H + struct sockaddr_dl *sdlp; +#endif + +/* + * BSD 4.4 defines the size of an ifreq to be + * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len + * However, under earlier systems, sa_len isn't present, so the size is + * just sizeof(struct ifreq) + */ +#ifdef HAVE_SA_LEN +#ifndef max +#define max(a,b) ((a) > (b) ? (a) : (b)) +#endif +#define ifreq_size(i) max(sizeof(struct ifreq),\ + sizeof((i).ifr_name)+(i).ifr_addr.sa_len) +#else +#define ifreq_size(i) sizeof(struct ifreq) +#endif /* HAVE_SA_LEN*/ + + sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); + if (sd < 0) { + return -1; + } + memset(buf, 0, sizeof(buf)); + ifc.ifc_len = sizeof(buf); + ifc.ifc_buf = buf; + if (ioctl (sd, SIOCGIFCONF, (char *)&ifc) < 0) { + close(sd); + return -1; + } + n = ifc.ifc_len; + for (i = 0; i < n; i+= ifreq_size(*ifrp) ) { + ifrp = (struct ifreq *)((char *) ifc.ifc_buf+i); + strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ); +#ifdef SIOCGIFHWADDR + if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0) + continue; + a = (unsigned char *) &ifr.ifr_hwaddr.sa_data; +#else +#ifdef SIOCGENADDR + if (ioctl(sd, SIOCGENADDR, &ifr) < 0) + continue; + a = (unsigned char *) ifr.ifr_enaddr; +#else +#ifdef HAVE_NET_IF_DL_H + sdlp = (struct sockaddr_dl *) &ifrp->ifr_addr; + if ((sdlp->sdl_family != AF_LINK) || (sdlp->sdl_alen != 6)) + continue; + a = (unsigned char *) &sdlp->sdl_data[sdlp->sdl_nlen]; +#else + /* + * XXX we don't have a way of getting the hardware + * address + */ + close(sd); + return 0; +#endif /* HAVE_NET_IF_DL_H */ +#endif /* SIOCGENADDR */ +#endif /* SIOCGIFHWADDR */ + if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5]) + continue; + if (node_id) { + memcpy(node_id, a, 6); + close(sd); + return 1; + } + } + close(sd); +#endif + return 0; +} +#endif /*defined(_WIN32)*/ + +/* Expose get_node_id to API */ +int uuid_get_node_id(unsigned char *node_id) +{ + return get_node_id(node_id); +} + + +/* Assume that the gettimeofday() has microsecond granularity */ +#define MAX_ADJUSTMENT 10 + +static int get_clock(uint32_t *clock_high, uint32_t *clock_low, + uint16_t *ret_clock_seq) +{ + static int adjustment = 0; + static struct timeval last = {0, 0}; + static uint16_t clock_seq; + struct timeval tv; + uint64_t clock_reg; + +try_again: + gettimeofday(&tv, 0); + if ((last.tv_sec == 0) && (last.tv_usec == 0)) { + get_random_bytes(&clock_seq, sizeof(clock_seq)); + clock_seq &= 0x3FFF; + last = tv; + last.tv_sec--; + } + if ((tv.tv_sec < last.tv_sec) || + ((tv.tv_sec == last.tv_sec) && + (tv.tv_usec < last.tv_usec))) { + clock_seq = (clock_seq+1) & 0x3FFF; + adjustment = 0; + last = tv; + } else if ((tv.tv_sec == last.tv_sec) && + (tv.tv_usec == last.tv_usec)) { + if (adjustment >= MAX_ADJUSTMENT) + goto try_again; + adjustment++; + } else { + adjustment = 0; + last = tv; + } + + clock_reg = tv.tv_usec*10 + adjustment; + clock_reg += ((uint64_t) tv.tv_sec)*10000000; + clock_reg += (((uint64_t) 0x01B21DD2) << 32) + 0x13814000; + + *clock_high = clock_reg >> 32; + *clock_low = clock_reg; + *ret_clock_seq = clock_seq; + return 0; +} + +void uuid_generate_time(uuid_t out) +{ + static unsigned char node_id[6]; + static int has_init = 0; + struct uuid uu; + uint32_t clock_mid; + + if (!has_init) { + if (get_node_id(node_id) <= 0) { + get_random_bytes(node_id, 6); + /* + * Set multicast bit, to prevent conflicts + * with IEEE 802 addresses obtained from + * network cards + */ + node_id[0] |= 0x01; + } + has_init = 1; + } + get_clock(&clock_mid, &uu.time_low, &uu.clock_seq); + uu.clock_seq |= 0x8000; + uu.time_mid = (uint16_t) clock_mid; + uu.time_hi_and_version = ((clock_mid >> 16) & 0x0FFF) | 0x1000; + memcpy(uu.node, node_id, 6); + uuid_pack(&uu, out); +} + +void uuid_generate_random(uuid_t out) +{ + uuid_t buf; + struct uuid uu; + + get_random_bytes(buf, sizeof(buf)); + uuid_unpack(buf, &uu); + + uu.clock_seq = (uu.clock_seq & 0x3FFF) | 0x8000; + uu.time_hi_and_version = (uu.time_hi_and_version & 0x0FFF) | 0x4000; + uuid_pack(&uu, out); +} + + +/* + * This is the generic front-end to uuid_generate_random and + * uuid_generate_time. It uses uuid_generate_random only if + * /dev/urandom is available, since otherwise we won't have + * high-quality randomness. + */ +void uuid_generate(uuid_t out) +{ + if (get_random_fd() >= 0) + uuid_generate_random(out); + else + uuid_generate_time(out); +} diff --git a/gdcm/Utilities/gdcmuuid/pack.c b/gdcm/Utilities/gdcmuuid/pack.c new file mode 100644 index 0000000..b166c2a --- /dev/null +++ b/gdcm/Utilities/gdcmuuid/pack.c @@ -0,0 +1,69 @@ +/* vi: set sw=4 ts=4: */ +/* + * Internal routine for packing UUID's + * + * Copyright (C) 1996, 1997 Theodore Ts'o. + * + * %Begin-Header% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * %End-Header% + */ + +#include +#include "uuidP.h" + +void uuid_pack(const struct uuid *uu, uuid_t ptr) +{ + uint32_t tmp; + unsigned char *out = ptr; + + tmp = uu->time_low; + out[3] = (unsigned char) tmp; + tmp >>= 8; + out[2] = (unsigned char) tmp; + tmp >>= 8; + out[1] = (unsigned char) tmp; + tmp >>= 8; + out[0] = (unsigned char) tmp; + + tmp = uu->time_mid; + out[5] = (unsigned char) tmp; + tmp >>= 8; + out[4] = (unsigned char) tmp; + + tmp = uu->time_hi_and_version; + out[7] = (unsigned char) tmp; + tmp >>= 8; + out[6] = (unsigned char) tmp; + + tmp = uu->clock_seq; + out[9] = (unsigned char) tmp; + tmp >>= 8; + out[8] = (unsigned char) tmp; + + memcpy(out+10, uu->node, 6); +} diff --git a/gdcm/Utilities/gdcmuuid/parse.c b/gdcm/Utilities/gdcmuuid/parse.c new file mode 100644 index 0000000..1b50035 --- /dev/null +++ b/gdcm/Utilities/gdcmuuid/parse.c @@ -0,0 +1,80 @@ +/* vi: set sw=4 ts=4: */ +/* + * parse.c --- UUID parsing + * + * Copyright (C) 1996, 1997 Theodore Ts'o. + * + * %Begin-Header% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * %End-Header% + */ + +#include +#include +#include +#include + +#include "uuidP.h" + +int uuid_parse(const char *in, uuid_t uu) +{ + struct uuid uuid; + int i; + const char *cp; + char buf[3]; + + if (strlen(in) != 36) + return -1; + for (i=0, cp = in; i <= 36; i++,cp++) { + if ((i == 8) || (i == 13) || (i == 18) || + (i == 23)) { + if (*cp == '-') + continue; + else + return -1; + } + if (i== 36) + if (*cp == 0) + continue; + if (!isxdigit(*cp)) + return -1; + } + uuid.time_low = strtoul(in, NULL, 16); + uuid.time_mid = strtoul(in+9, NULL, 16); + uuid.time_hi_and_version = strtoul(in+14, NULL, 16); + uuid.clock_seq = strtoul(in+19, NULL, 16); + cp = in+24; + buf[2] = 0; + for (i=0; i < 6; i++) { + buf[0] = *cp++; + buf[1] = *cp++; + uuid.node[i] = strtoul(buf, NULL, 16); + } + + uuid_pack(&uuid, uu); + return 0; +} diff --git a/gdcm/Utilities/gdcmuuid/unpack.c b/gdcm/Utilities/gdcmuuid/unpack.c new file mode 100644 index 0000000..f9cd4e8 --- /dev/null +++ b/gdcm/Utilities/gdcmuuid/unpack.c @@ -0,0 +1,63 @@ +/* vi: set sw=4 ts=4: */ +/* + * Internal routine for unpacking UUID + * + * Copyright (C) 1996, 1997 Theodore Ts'o. + * + * %Begin-Header% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * %End-Header% + */ + +#include +#include "uuidP.h" + +void uuid_unpack(const uuid_t in, struct uuid *uu) +{ + const uint8_t *ptr = in; + uint32_t tmp; + + tmp = *ptr++; + tmp = (tmp << 8) | *ptr++; + tmp = (tmp << 8) | *ptr++; + tmp = (tmp << 8) | *ptr++; + uu->time_low = tmp; + + tmp = *ptr++; + tmp = (tmp << 8) | *ptr++; + uu->time_mid = tmp; + + tmp = *ptr++; + tmp = (tmp << 8) | *ptr++; + uu->time_hi_and_version = tmp; + + tmp = *ptr++; + tmp = (tmp << 8) | *ptr++; + uu->clock_seq = tmp; + + memcpy(uu->node, ptr, 6); +} diff --git a/gdcm/Utilities/gdcmuuid/unparse.c b/gdcm/Utilities/gdcmuuid/unparse.c new file mode 100644 index 0000000..5685c51 --- /dev/null +++ b/gdcm/Utilities/gdcmuuid/unparse.c @@ -0,0 +1,77 @@ +/* vi: set sw=4 ts=4: */ +/* + * unparse.c -- convert a UUID to string + * + * Copyright (C) 1996, 1997 Theodore Ts'o. + * + * %Begin-Header% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * %End-Header% + */ + +#include + +#include "uuidP.h" + +static const char *fmt_lower = + "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x"; + +static const char *fmt_upper = + "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X"; + +#ifdef UUID_UNPARSE_DEFAULT_UPPER +#define FMT_DEFAULT fmt_upper +#else +#define FMT_DEFAULT fmt_lower +#endif + +static void uuid_unparse_x(const uuid_t uu, char *out, const char *fmt) +{ + struct uuid uuid; + + uuid_unpack(uu, &uuid); + sprintf(out, fmt, + uuid.time_low, uuid.time_mid, uuid.time_hi_and_version, + uuid.clock_seq >> 8, uuid.clock_seq & 0xFF, + uuid.node[0], uuid.node[1], uuid.node[2], + uuid.node[3], uuid.node[4], uuid.node[5]); +} + +void uuid_unparse_lower(const uuid_t uu, char *out) +{ + uuid_unparse_x(uu, out, fmt_lower); +} + +void uuid_unparse_upper(const uuid_t uu, char *out) +{ + uuid_unparse_x(uu, out, fmt_upper); +} + +void uuid_unparse(const uuid_t uu, char *out) +{ + uuid_unparse_x(uu, out, FMT_DEFAULT); +} diff --git a/gdcm/Utilities/gdcmuuid/uuid.h b/gdcm/Utilities/gdcmuuid/uuid.h new file mode 100644 index 0000000..3dc5d6d --- /dev/null +++ b/gdcm/Utilities/gdcmuuid/uuid.h @@ -0,0 +1,129 @@ +/* vi: set sw=4 ts=4: */ +/* + * Public include file for the UUID library + * + * Copyright (C) 1996, 1997, 1998 Theodore Ts'o. + * + * %Begin-Header% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * %End-Header% + */ + +#ifndef _UUID_UUID_H +#define _UUID_UUID_H + +#include "uuid_mangle.h" + +#if defined(_WIN32) && defined(UUID_DLL) + #if defined(uuid_EXPORTS) + #define UUID_EXPORT __declspec( dllexport ) + #else + #define UUID_EXPORT __declspec( dllimport ) + #endif +#else +#if __GNUC__ >= 4 +#define UUID_EXPORT __attribute__ ((visibility ("default"))) +#else + #define UUID_EXPORT +#endif +#endif /*defined(WIN32)*/ + + +#include +#include +#ifdef HAVE_SYS_TIME_H +#include /* timeval CYGWIN is important */ +#endif + +/* apparently types.h or time.h is polluting our namespace on Win32... */ +#if defined(uuid_t) +#undef uuid_t +#endif +typedef unsigned char uuid_t[16]; + +/* UUID Variant definitions */ +#define UUID_VARIANT_NCS 0 +#define UUID_VARIANT_DCE 1 +#define UUID_VARIANT_MICROSOFT 2 +#define UUID_VARIANT_OTHER 3 + +/* UUID Type definitions */ +#define UUID_TYPE_DCE_TIME 1 +#define UUID_TYPE_DCE_RANDOM 4 + +/* Allow UUID constants to be defined */ +#ifdef __GNUC__ +#define UUID_DEFINE(name,u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15) \ + static const uuid_t name ATTRIBUTE_UNUSED = {u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15} +#else +#define UUID_DEFINE(name,u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15) \ + static const uuid_t name = {u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15} +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* clear.c */ +/*void uuid_clear(uuid_t uu);*/ +#define uuid_clear(uu) memset(uu, 0, sizeof(uu)) + +/* compare.c */ +int uuid_compare(const uuid_t uu1, const uuid_t uu2); + +/* copy.c */ +/*void uuid_copy(uuid_t dst, const uuid_t src);*/ +#define uuid_copy(dst,src) memcpy(dst, src, sizeof(dst)) + +/* gen_uuid.c */ +UUID_EXPORT void uuid_generate(uuid_t out); +void uuid_generate_random(uuid_t out); +UUID_EXPORT int uuid_get_node_id(unsigned char *node_id); +void uuid_generate_time(uuid_t out); + +/* isnull.c */ +/*int uuid_is_null(const uuid_t uu);*/ +#define uuid_is_null(uu) (!memcmp(uu, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", sizeof(uu))) + +/* parse.c */ +UUID_EXPORT int uuid_parse(const char *in, uuid_t uu); + +/* unparse.c */ +UUID_EXPORT void uuid_unparse(const uuid_t uu, char *out); +void uuid_unparse_lower(const uuid_t uu, char *out); +void uuid_unparse_upper(const uuid_t uu, char *out); + +/* uuid_time.c */ +time_t uuid_time(const uuid_t uu, struct timeval *ret_tv); +int uuid_type(const uuid_t uu); +int uuid_variant(const uuid_t uu); + +#ifdef __cplusplus +} +#endif + +#endif /* _UUID_UUID_H */ diff --git a/gdcm/Utilities/gdcmuuid/uuidP.h b/gdcm/Utilities/gdcmuuid/uuidP.h new file mode 100644 index 0000000..1090065 --- /dev/null +++ b/gdcm/Utilities/gdcmuuid/uuidP.h @@ -0,0 +1,72 @@ +/* vi: set sw=4 ts=4: */ +/* + * uuid.h -- private header file for uuids + * + * Copyright (C) 1996, 1997 Theodore Ts'o. + * + * %Begin-Header% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * %End-Header% + */ + +#if HAVE_INTTYPES_H +#include +#endif +#if defined(_MSC_VER) || defined(__BORLANDC__) +typedef signed __int8 int8_t; +typedef signed __int16 int16_t; +typedef signed __int32 int32_t; +typedef signed __int64 int64_t; +typedef unsigned __int8 uint8_t; +typedef unsigned __int16 uint16_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int64 uint64_t; +#endif +#include + +#include "uuid.h" + +/* + * Offset between 15-Oct-1582 and 1-Jan-70 + */ +#define TIME_OFFSET_HIGH 0x01B21DD2 +#define TIME_OFFSET_LOW 0x13814000 + +struct uuid { + uint32_t time_low; + uint16_t time_mid; + uint16_t time_hi_and_version; + uint16_t clock_seq; + uint8_t node[6]; +}; + + +/* + * prototypes + */ +void uuid_pack(const struct uuid *uu, uuid_t ptr); +void uuid_unpack(const uuid_t in, struct uuid *uu); diff --git a/gdcm/Utilities/gdcmuuid/uuid_mangle.h.in b/gdcm/Utilities/gdcmuuid/uuid_mangle.h.in new file mode 100644 index 0000000..5c23aeb --- /dev/null +++ b/gdcm/Utilities/gdcmuuid/uuid_mangle.h.in @@ -0,0 +1,36 @@ +/* This file was generated by CMake http://www.cmake.org */ + +#ifndef @MANGLE_PREFIX@_mangle_h +#define @MANGLE_PREFIX@_mangle_h + +/* + * This header file mangles all symbols exported from the uuid library. + * It is included in all files while building the uuid library. Due to + * namespace pollution, no uuid headers should be included in .h files in + * GDCM. + * + * The following command was used to obtain the symbol list: + * + * nm lib@MANGLE_PREFIX@.a | grep " [TR] " + */ + +#define uuid_compare @MANGLE_PREFIX@_uuid_compare +#define uuid_generate @MANGLE_PREFIX@_uuid_generate +#define uuid_generate_random @MANGLE_PREFIX@_uuid_generate_random +#define uuid_generate_time @MANGLE_PREFIX@_uuid_generate_time +#define uuid_get_node_id @MANGLE_PREFIX@_uuid_get_node_id +#define uuid_pack @MANGLE_PREFIX@_uuid_pack +#define uuid_parse @MANGLE_PREFIX@_uuid_parse +#define uuid_time @MANGLE_PREFIX@_uuid_time +#define uuid_type @MANGLE_PREFIX@_uuid_type +#define uuid_unpack @MANGLE_PREFIX@_uuid_unpack +#define uuid_unparse @MANGLE_PREFIX@_uuid_unparse +#define uuid_unparse_lower @MANGLE_PREFIX@_uuid_unparse_lower +#define uuid_unparse_upper @MANGLE_PREFIX@_uuid_unparse_upper +#define uuid_variant @MANGLE_PREFIX@_uuid_variant + +#define uuid_EXPORTS @MANGLE_PREFIX@uuid_EXPORTS + +#cmakedefine HAVE_SYS_TIME_H + +#endif diff --git a/gdcm/Utilities/gdcmuuid/uuid_time.c b/gdcm/Utilities/gdcmuuid/uuid_time.c new file mode 100644 index 0000000..8e509ba --- /dev/null +++ b/gdcm/Utilities/gdcmuuid/uuid_time.c @@ -0,0 +1,166 @@ +/* vi: set sw=4 ts=4: */ +/* + * uuid_time.c --- Interpret the time field from a uuid. This program + * violates the UUID abstraction barrier by reaching into the guts + * of a UUID and interpreting it. + * + * Copyright (C) 1998, 1999 Theodore Ts'o. + * + * %Begin-Header% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * %End-Header% + */ + +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#include +#include +#ifdef HAVE_WINSOCK_H +#include /* timeval */ +#endif + +#include "uuidP.h" + +time_t uuid_time(const uuid_t uu, struct timeval *ret_tv) +{ + struct uuid uuid; + uint32_t high; + struct timeval tv; + uint64_t clock_reg; + + uuid_unpack(uu, &uuid); + + high = uuid.time_mid | ((uuid.time_hi_and_version & 0xFFF) << 16); + clock_reg = uuid.time_low | ((uint64_t) high << 32); + + clock_reg -= (((uint64_t) 0x01B21DD2) << 32) + 0x13814000; + tv.tv_sec = clock_reg / 10000000; + tv.tv_usec = (clock_reg % 10000000) / 10; + + if (ret_tv) + *ret_tv = tv; + + return tv.tv_sec; +} + +int uuid_type(const uuid_t uu) +{ + struct uuid uuid; + + uuid_unpack(uu, &uuid); + return ((uuid.time_hi_and_version >> 12) & 0xF); +} + +int uuid_variant(const uuid_t uu) +{ + struct uuid uuid; + int var; + + uuid_unpack(uu, &uuid); + var = uuid.clock_seq; + + if ((var & 0x8000) == 0) + return UUID_VARIANT_NCS; + if ((var & 0x4000) == 0) + return UUID_VARIANT_DCE; + if ((var & 0x2000) == 0) + return UUID_VARIANT_MICROSOFT; + return UUID_VARIANT_OTHER; +} + +#ifdef DEBUG +static const char *variant_string(int variant) +{ + switch (variant) { + case UUID_VARIANT_NCS: + return "NCS"; + case UUID_VARIANT_DCE: + return "DCE"; + case UUID_VARIANT_MICROSOFT: + return "Microsoft"; + default: + return "Other"; + } +} + + +int +main(int argc, char **argv) +{ + uuid_t buf; + time_t time_reg; + struct timeval tv; + int type, variant; + + if (argc != 2) { + fprintf(stderr, "Usage: %s uuid\n", argv[0]); + exit(1); + } + if (uuid_parse(argv[1], buf)) { + fprintf(stderr, "Invalid UUID: %s\n", argv[1]); + exit(1); + } + variant = uuid_variant(buf); + type = uuid_type(buf); + time_reg = uuid_time(buf, &tv); + + printf("UUID variant is %d (%s)\n", variant, variant_string(variant)); + if (variant != UUID_VARIANT_DCE) { + printf("Warning: This program only knows how to interpret " + "DCE UUIDs.\n\tThe rest of the output is likely " + "to be incorrect!!\n"); + } + printf("UUID type is %d", type); + switch (type) { + case 1: + printf(" (time based)\n"); + break; + case 2: + printf(" (DCE)\n"); + break; + case 3: + printf(" (name-based)\n"); + break; + case 4: + printf(" (random)\n"); + break; + default: + bb_putchar('\n'); + } + if (type != 1) { + printf("Warning: not a time-based UUID, so UUID time " + "decoding will likely not work!\n"); + } + printf("UUID time is: (%ld, %ld): %s\n", tv.tv_sec, tv.tv_usec, + ctime(&time_reg)); + + return 0; +} +#endif diff --git a/gdcm/Utilities/gdcmzlib/.NoDartCoverage b/gdcm/Utilities/gdcmzlib/.NoDartCoverage new file mode 100644 index 0000000..3c99729 --- /dev/null +++ b/gdcm/Utilities/gdcmzlib/.NoDartCoverage @@ -0,0 +1 @@ +# do not do coverage in this directory diff --git a/gdcm/Utilities/gdcmzlib/CMakeLists.txt b/gdcm/Utilities/gdcmzlib/CMakeLists.txt new file mode 100644 index 0000000..cb48066 --- /dev/null +++ b/gdcm/Utilities/gdcmzlib/CMakeLists.txt @@ -0,0 +1,69 @@ +cmake_minimum_required(VERSION 2.8.9) + +if(NOT ZLIB_NAMESPACE) + set(ZLIB_NAMESPACE "ZLIB") + set(ZLIB_STANDALONE 1) +endif() +# In all cases: +string(TOLOWER ${ZLIB_NAMESPACE} ZLIB_LIBRARY_NAME) + +project(${ZLIB_NAMESPACE} C) + +# Do full dependency headers. +include_regular_expression("^.*$") + +# source files for zlib +set(ZLIB_SRCS + adler32.c + compress.c + crc32.c + deflate.c + #example.c + gzio.c + infback.c + inffast.c + inflate.c + inftrees.c + #minigzip.c + trees.c + uncompr.c + zutil.c + ) + + +# for windows add the .def and .rc files to the source list if building shared libs +if(WIN32) + if(BUILD_SHARED_LIBS) + set(ZLIB_DLL 1) + if(NOT UNIX) + if(NOT BORLAND) + if(NOT MINGW) + set(ZLIB_SRCS ${ZLIB_SRCS} zlib.def zlib.rc ) + endif() + endif() + endif() + endif() +endif() + + configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/zconf.in.h + ${CMAKE_CURRENT_BINARY_DIR}/zconf.h + ) +include_directories( + ${CMAKE_CURRENT_BINARY_DIR} +) + + +add_library(${ZLIB_LIBRARY_NAME} ${ZLIB_SRCS}) +set_target_properties(${ZLIB_LIBRARY_NAME} PROPERTIES ${GDCM_LIBRARY_PROPERTIES}) +set_target_properties(${ZLIB_LIBRARY_NAME} PROPERTIES LINKER_LANGUAGE C) + +if(NOT ZLIB_INSTALL_NO_LIBRARIES) + install(TARGETS ${ZLIB_LIBRARY_NAME} + EXPORT ${GDCM_TARGETS_NAME} + RUNTIME DESTINATION ${ZLIB_INSTALL_BIN_DIR} COMPONENT Applications + LIBRARY DESTINATION ${ZLIB_INSTALL_LIB_DIR} COMPONENT Libraries + ARCHIVE DESTINATION ${ZLIB_INSTALL_LIB_DIR} COMPONENT DebugDevel + ${CPACK_NAMELINK_TYPE} + ) +endif() diff --git a/gdcm/Utilities/gdcmzlib/COPYING b/gdcm/Utilities/gdcmzlib/COPYING new file mode 100644 index 0000000..ce56d60 --- /dev/null +++ b/gdcm/Utilities/gdcmzlib/COPYING @@ -0,0 +1,30 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.3, July 18th, 2005 + + Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + diff --git a/gdcm/Utilities/gdcmzlib/ChangeLog b/gdcm/Utilities/gdcmzlib/ChangeLog new file mode 100644 index 0000000..7f6869d --- /dev/null +++ b/gdcm/Utilities/gdcmzlib/ChangeLog @@ -0,0 +1,855 @@ + + ChangeLog file for zlib + +Changes in 1.2.3 (18 July 2005) +- Apply security vulnerability fixes to contrib/infback9 as well +- Clean up some text files (carriage returns, trailing space) +- Update testzlib, vstudio, masmx64, and masmx86 in contrib [Vollant] + +Changes in 1.2.2.4 (11 July 2005) +- Add inflatePrime() function for starting inflation at bit boundary +- Avoid some Visual C warnings in deflate.c +- Avoid more silly Visual C warnings in inflate.c and inftrees.c for 64-bit + compile +- Fix some spelling errors in comments [Betts] +- Correct inflateInit2() error return documentation in zlib.h +- Added zran.c example of compressed data random access to examples + directory, shows use of inflatePrime() +- Fix cast for assignments to strm->state in inflate.c and infback.c +- Fix zlibCompileFlags() in zutil.c to use 1L for long shifts [Oberhumer] +- Move declarations of gf2 functions to right place in crc32.c [Oberhumer] +- Add cast in trees.c t avoid a warning [Oberhumer] +- Avoid some warnings in fitblk.c, gun.c, gzjoin.c in examples [Oberhumer] +- Update make_vms.com [Zinser] +- Initialize state->write in inflateReset() since copied in inflate_fast() +- Be more strict on incomplete code sets in inflate_table() and increase + ENOUGH and MAXD -- this repairs a possible security vulnerability for + invalid inflate input. Thanks to Tavis Ormandy and Markus Oberhumer for + discovering the vulnerability and providing test cases. +- Add ia64 support to configure for HP-UX [Smith] +- Add error return to gzread() for format or i/o error [Levin] +- Use malloc.h for OS/2 [Necasek] + +Changes in 1.2.2.3 (27 May 2005) +- Replace 1U constants in inflate.c and inftrees.c for 64-bit compile +- Typecast fread() return values in gzio.c [Vollant] +- Remove trailing space in minigzip.c outmode (VC++ can't deal with it) +- Fix crc check bug in gzread() after gzungetc() [Heiner] +- Add the deflateTune() function to adjust internal compression parameters +- Add a fast gzip decompressor, gun.c, to examples (use of inflateBack) +- Remove an incorrect assertion in examples/zpipe.c +- Add C++ wrapper in infback9.h [Donais] +- Fix bug in inflateCopy() when decoding fixed codes +- Note in zlib.h how much deflateSetDictionary() actually uses +- Remove USE_DICT_HEAD in deflate.c (would mess up inflate if used) +- Add _WIN32_WCE to define WIN32 in zconf.in.h [Spencer] +- Don't include stderr.h or errno.h for _WIN32_WCE in zutil.h [Spencer] +- Add gzdirect() function to indicate transparent reads +- Update contrib/minizip [Vollant] +- Fix compilation of deflate.c when both ASMV and FASTEST [Oberhumer] +- Add casts in crc32.c to avoid warnings [Oberhumer] +- Add contrib/masmx64 [Vollant] +- Update contrib/asm586, asm686, masmx86, testzlib, vstudio [Vollant] + +Changes in 1.2.2.2 (30 December 2004) +- Replace structure assignments in deflate.c and inflate.c with zmemcpy to + avoid implicit memcpy calls (portability for no-library compilation) +- Increase sprintf() buffer size in gzdopen() to allow for large numbers +- Add INFLATE_STRICT to check distances against zlib header +- Improve WinCE errno handling and comments [Chang] +- Remove comment about no gzip header processing in FAQ +- Add Z_FIXED strategy option to deflateInit2() to force fixed trees +- Add updated make_vms.com [Coghlan], update README +- Create a new "examples" directory, move gzappend.c there, add zpipe.c, + fitblk.c, gzlog.[ch], gzjoin.c, and zlib_how.html. +- Add FAQ entry and comments in deflate.c on uninitialized memory access +- Add Solaris 9 make options in configure [Gilbert] +- Allow strerror() usage in gzio.c for STDC +- Fix DecompressBuf in contrib/delphi/ZLib.pas [ManChesTer] +- Update contrib/masmx86/inffas32.asm and gvmat32.asm [Vollant] +- Use z_off_t for adler32_combine() and crc32_combine() lengths +- Make adler32() much faster for small len +- Use OS_CODE in deflate() default gzip header + +Changes in 1.2.2.1 (31 October 2004) +- Allow inflateSetDictionary() call for raw inflate +- Fix inflate header crc check bug for file names and comments +- Add deflateSetHeader() and gz_header structure for custom gzip headers +- Add inflateGetheader() to retrieve gzip headers +- Add crc32_combine() and adler32_combine() functions +- Add alloc_func, free_func, in_func, out_func to Z_PREFIX list +- Use zstreamp consistently in zlib.h (inflate_back functions) +- Remove GUNZIP condition from definition of inflate_mode in inflate.h + and in contrib/inflate86/inffast.S [Truta, Anderson] +- Add support for AMD64 in contrib/inflate86/inffas86.c [Anderson] +- Update projects/README.projects and projects/visualc6 [Truta] +- Update win32/DLL_FAQ.txt [Truta] +- Avoid warning under NO_GZCOMPRESS in gzio.c; fix typo [Truta] +- Deprecate Z_ASCII; use Z_TEXT instead [Truta] +- Use a new algorithm for setting strm->data_type in trees.c [Truta] +- Do not define an exit() prototype in zutil.c unless DEBUG defined +- Remove prototype of exit() from zutil.c, example.c, minigzip.c [Truta] +- Add comment in zlib.h for Z_NO_FLUSH parameter to deflate() +- Fix Darwin build version identification [Peterson] + +Changes in 1.2.2 (3 October 2004) +- Update zlib.h comments on gzip in-memory processing +- Set adler to 1 in inflateReset() to support Java test suite [Walles] +- Add contrib/dotzlib [Ravn] +- Update win32/DLL_FAQ.txt [Truta] +- Update contrib/minizip [Vollant] +- Move contrib/visual-basic.txt to old/ [Truta] +- Fix assembler builds in projects/visualc6/ [Truta] + +Changes in 1.2.1.2 (9 September 2004) +- Update INDEX file +- Fix trees.c to update strm->data_type (no one ever noticed!) +- Fix bug in error case in inflate.c, infback.c, and infback9.c [Brown] +- Add "volatile" to crc table flag declaration (for DYNAMIC_CRC_TABLE) +- Add limited multitasking protection to DYNAMIC_CRC_TABLE +- Add NO_vsnprintf for VMS in zutil.h [Mozilla] +- Don't declare strerror() under VMS [Mozilla] +- Add comment to DYNAMIC_CRC_TABLE to use get_crc_table() to initialize +- Update contrib/ada [Anisimkov] +- Update contrib/minizip [Vollant] +- Fix configure to not hardcode directories for Darwin [Peterson] +- Fix gzio.c to not return error on empty files [Brown] +- Fix indentation; update version in contrib/delphi/ZLib.pas and + contrib/pascal/zlibpas.pas [Truta] +- Update mkasm.bat in contrib/masmx86 [Truta] +- Update contrib/untgz [Truta] +- Add projects/README.projects [Truta] +- Add project for MS Visual C++ 6.0 in projects/visualc6 [Cadieux, Truta] +- Update win32/DLL_FAQ.txt [Truta] +- Update list of Z_PREFIX symbols in zconf.h [Randers-Pehrson, Truta] +- Remove an unnecessary assignment to curr in inftrees.c [Truta] +- Add OS/2 to exe builds in configure [Poltorak] +- Remove err dummy parameter in zlib.h [Kientzle] + +Changes in 1.2.1.1 (9 January 2004) +- Update email address in README +- Several FAQ updates +- Fix a big fat bug in inftrees.c that prevented decoding valid + dynamic blocks with only literals and no distance codes -- + Thanks to "Hot Emu" for the bug report and sample file +- Add a note to puff.c on no distance codes case. + +Changes in 1.2.1 (17 November 2003) +- Remove a tab in contrib/gzappend/gzappend.c +- Update some interfaces in contrib for new zlib functions +- Update zlib version number in some contrib entries +- Add Windows CE definition for ptrdiff_t in zutil.h [Mai, Truta] +- Support shared libraries on Hurd and KFreeBSD [Brown] +- Fix error in NO_DIVIDE option of adler32.c + +Changes in 1.2.0.8 (4 November 2003) +- Update version in contrib/delphi/ZLib.pas and contrib/pascal/zlibpas.pas +- Add experimental NO_DIVIDE #define in adler32.c + - Possibly faster on some processors (let me know if it is) +- Correct Z_BLOCK to not return on first inflate call if no wrap +- Fix strm->data_type on inflate() return to correctly indicate EOB +- Add deflatePrime() function for appending in the middle of a byte +- Add contrib/gzappend for an example of appending to a stream +- Update win32/DLL_FAQ.txt [Truta] +- Delete Turbo C comment in README [Truta] +- Improve some indentation in zconf.h [Truta] +- Fix infinite loop on bad input in configure script [Church] +- Fix gzeof() for concatenated gzip files [Johnson] +- Add example to contrib/visual-basic.txt [Michael B.] +- Add -p to mkdir's in Makefile.in [vda] +- Fix configure to properly detect presence or lack of printf functions +- Add AS400 support [Monnerat] +- Add a little Cygwin support [Wilson] + +Changes in 1.2.0.7 (21 September 2003) +- Correct some debug formats in contrib/infback9 +- Cast a type in a debug statement in trees.c +- Change search and replace delimiter in configure from % to # [Beebe] +- Update contrib/untgz to 0.2 with various fixes [Truta] +- Add build support for Amiga [Nikl] +- Remove some directories in old that have been updated to 1.2 +- Add dylib building for Mac OS X in configure and Makefile.in +- Remove old distribution stuff from Makefile +- Update README to point to DLL_FAQ.txt, and add comment on Mac OS X +- Update links in README + +Changes in 1.2.0.6 (13 September 2003) +- Minor FAQ updates +- Update contrib/minizip to 1.00 [Vollant] +- Remove test of gz functions in example.c when GZ_COMPRESS defined [Truta] +- Update POSTINC comment for 68060 [Nikl] +- Add contrib/infback9 with deflate64 decoding (unsupported) +- For MVS define NO_vsnprintf and undefine FAR [van Burik] +- Add pragma for fdopen on MVS [van Burik] + +Changes in 1.2.0.5 (8 September 2003) +- Add OF to inflateBackEnd() declaration in zlib.h +- Remember start when using gzdopen in the middle of a file +- Use internal off_t counters in gz* functions to properly handle seeks +- Perform more rigorous check for distance-too-far in inffast.c +- Add Z_BLOCK flush option to return from inflate at block boundary +- Set strm->data_type on return from inflate + - Indicate bits unused, if at block boundary, and if in last block +- Replace size_t with ptrdiff_t in crc32.c, and check for correct size +- Add condition so old NO_DEFLATE define still works for compatibility +- FAQ update regarding the Windows DLL [Truta] +- INDEX update: add qnx entry, remove aix entry [Truta] +- Install zlib.3 into mandir [Wilson] +- Move contrib/zlib_dll_FAQ.txt to win32/DLL_FAQ.txt; update [Truta] +- Adapt the zlib interface to the new DLL convention guidelines [Truta] +- Introduce ZLIB_WINAPI macro to allow the export of functions using + the WINAPI calling convention, for Visual Basic [Vollant, Truta] +- Update msdos and win32 scripts and makefiles [Truta] +- Export symbols by name, not by ordinal, in win32/zlib.def [Truta] +- Add contrib/ada [Anisimkov] +- Move asm files from contrib/vstudio/vc70_32 to contrib/asm386 [Truta] +- Rename contrib/asm386 to contrib/masmx86 [Truta, Vollant] +- Add contrib/masm686 [Truta] +- Fix offsets in contrib/inflate86 and contrib/masmx86/inffas32.asm + [Truta, Vollant] +- Update contrib/delphi; rename to contrib/pascal; add example [Truta] +- Remove contrib/delphi2; add a new contrib/delphi [Truta] +- Avoid inclusion of the nonstandard in contrib/iostream, + and fix some method prototypes [Truta] +- Fix the ZCR_SEED2 constant to avoid warnings in contrib/minizip + [Truta] +- Avoid the use of backslash (\) in contrib/minizip [Vollant] +- Fix file time handling in contrib/untgz; update makefiles [Truta] +- Update contrib/vstudio/vc70_32 to comply with the new DLL guidelines + [Vollant] +- Remove contrib/vstudio/vc15_16 [Vollant] +- Rename contrib/vstudio/vc70_32 to contrib/vstudio/vc7 [Truta] +- Update README.contrib [Truta] +- Invert the assignment order of match_head and s->prev[...] in + INSERT_STRING [Truta] +- Compare TOO_FAR with 32767 instead of 32768, to avoid 16-bit warnings + [Truta] +- Compare function pointers with 0, not with NULL or Z_NULL [Truta] +- Fix prototype of syncsearch in inflate.c [Truta] +- Introduce ASMINF macro to be enabled when using an ASM implementation + of inflate_fast [Truta] +- Change NO_DEFLATE to NO_GZCOMPRESS [Truta] +- Modify test_gzio in example.c to take a single file name as a + parameter [Truta] +- Exit the example.c program if gzopen fails [Truta] +- Add type casts around strlen in example.c [Truta] +- Remove casting to sizeof in minigzip.c; give a proper type + to the variable compared with SUFFIX_LEN [Truta] +- Update definitions of STDC and STDC99 in zconf.h [Truta] +- Synchronize zconf.h with the new Windows DLL interface [Truta] +- Use SYS16BIT instead of __32BIT__ to distinguish between + 16- and 32-bit platforms [Truta] +- Use far memory allocators in small 16-bit memory models for + Turbo C [Truta] +- Add info about the use of ASMV, ASMINF and ZLIB_WINAPI in + zlibCompileFlags [Truta] +- Cygwin has vsnprintf [Wilson] +- In Windows16, OS_CODE is 0, as in MSDOS [Truta] +- In Cygwin, OS_CODE is 3 (Unix), not 11 (Windows32) [Wilson] + +Changes in 1.2.0.4 (10 August 2003) +- Minor FAQ updates +- Be more strict when checking inflateInit2's windowBits parameter +- Change NO_GUNZIP compile option to NO_GZIP to cover deflate as well +- Add gzip wrapper option to deflateInit2 using windowBits +- Add updated QNX rule in configure and qnx directory [Bonnefoy] +- Make inflate distance-too-far checks more rigorous +- Clean up FAR usage in inflate +- Add casting to sizeof() in gzio.c and minigzip.c + +Changes in 1.2.0.3 (19 July 2003) +- Fix silly error in gzungetc() implementation [Vollant] +- Update contrib/minizip and contrib/vstudio [Vollant] +- Fix printf format in example.c +- Correct cdecl support in zconf.in.h [Anisimkov] +- Minor FAQ updates + +Changes in 1.2.0.2 (13 July 2003) +- Add ZLIB_VERNUM in zlib.h for numerical preprocessor comparisons +- Attempt to avoid warnings in crc32.c for pointer-int conversion +- Add AIX to configure, remove aix directory [Bakker] +- Add some casts to minigzip.c +- Improve checking after insecure sprintf() or vsprintf() calls +- Remove #elif's from crc32.c +- Change leave label to inf_leave in inflate.c and infback.c to avoid + library conflicts +- Remove inflate gzip decoding by default--only enable gzip decoding by + special request for stricter backward compatibility +- Add zlibCompileFlags() function to return compilation information +- More typecasting in deflate.c to avoid warnings +- Remove leading underscore from _Capital #defines [Truta] +- Fix configure to link shared library when testing +- Add some Windows CE target adjustments [Mai] +- Remove #define ZLIB_DLL in zconf.h [Vollant] +- Add zlib.3 [Rodgers] +- Update RFC URL in deflate.c and algorithm.txt [Mai] +- Add zlib_dll_FAQ.txt to contrib [Truta] +- Add UL to some constants [Truta] +- Update minizip and vstudio [Vollant] +- Remove vestigial NEED_DUMMY_RETURN from zconf.in.h +- Expand use of NO_DUMMY_DECL to avoid all dummy structures +- Added iostream3 to contrib [Schwardt] +- Replace rewind() with fseek() for WinCE [Truta] +- Improve setting of zlib format compression level flags + - Report 0 for huffman and rle strategies and for level == 0 or 1 + - Report 2 only for level == 6 +- Only deal with 64K limit when necessary at compile time [Truta] +- Allow TOO_FAR check to be turned off at compile time [Truta] +- Add gzclearerr() function [Souza] +- Add gzungetc() function + +Changes in 1.2.0.1 (17 March 2003) +- Add Z_RLE strategy for run-length encoding [Truta] + - When Z_RLE requested, restrict matches to distance one + - Update zlib.h, minigzip.c, gzopen(), gzdopen() for Z_RLE +- Correct FASTEST compilation to allow level == 0 +- Clean up what gets compiled for FASTEST +- Incorporate changes to zconf.in.h [Vollant] + - Refine detection of Turbo C need for dummy returns + - Refine ZLIB_DLL compilation + - Include additional header file on VMS for off_t typedef +- Try to use _vsnprintf where it supplants vsprintf [Vollant] +- Add some casts in inffast.c +- Enchance comments in zlib.h on what happens if gzprintf() tries to + write more than 4095 bytes before compression +- Remove unused state from inflateBackEnd() +- Remove exit(0) from minigzip.c, example.c +- Get rid of all those darn tabs +- Add "check" target to Makefile.in that does the same thing as "test" +- Add "mostlyclean" and "maintainer-clean" targets to Makefile.in +- Update contrib/inflate86 [Anderson] +- Update contrib/testzlib, contrib/vstudio, contrib/minizip [Vollant] +- Add msdos and win32 directories with makefiles [Truta] +- More additions and improvements to the FAQ + +Changes in 1.2.0 (9 March 2003) +- New and improved inflate code + - About 20% faster + - Does not allocate 32K window unless and until needed + - Automatically detects and decompresses gzip streams + - Raw inflate no longer needs an extra dummy byte at end + - Added inflateBack functions using a callback interface--even faster + than inflate, useful for file utilities (gzip, zip) + - Added inflateCopy() function to record state for random access on + externally generated deflate streams (e.g. in gzip files) + - More readable code (I hope) +- New and improved crc32() + - About 50% faster, thanks to suggestions from Rodney Brown +- Add deflateBound() and compressBound() functions +- Fix memory leak in deflateInit2() +- Permit setting dictionary for raw deflate (for parallel deflate) +- Fix const declaration for gzwrite() +- Check for some malloc() failures in gzio.c +- Fix bug in gzopen() on single-byte file 0x1f +- Fix bug in gzread() on concatenated file with 0x1f at end of buffer + and next buffer doesn't start with 0x8b +- Fix uncompress() to return Z_DATA_ERROR on truncated input +- Free memory at end of example.c +- Remove MAX #define in trees.c (conflicted with some libraries) +- Fix static const's in deflate.c, gzio.c, and zutil.[ch] +- Declare malloc() and free() in gzio.c if STDC not defined +- Use malloc() instead of calloc() in zutil.c if int big enough +- Define STDC for AIX +- Add aix/ with approach for compiling shared library on AIX +- Add HP-UX support for shared libraries in configure +- Add OpenUNIX support for shared libraries in configure +- Use $cc instead of gcc to build shared library +- Make prefix directory if needed when installing +- Correct Macintosh avoidance of typedef Byte in zconf.h +- Correct Turbo C memory allocation when under Linux +- Use libz.a instead of -lz in Makefile (assure use of compiled library) +- Update configure to check for snprintf or vsnprintf functions and their + return value, warn during make if using an insecure function +- Fix configure problem with compile-time knowledge of HAVE_UNISTD_H that + is lost when library is used--resolution is to build new zconf.h +- Documentation improvements (in zlib.h): + - Document raw deflate and inflate + - Update RFCs URL + - Point out that zlib and gzip formats are different + - Note that Z_BUF_ERROR is not fatal + - Document string limit for gzprintf() and possible buffer overflow + - Note requirement on avail_out when flushing + - Note permitted values of flush parameter of inflate() +- Add some FAQs (and even answers) to the FAQ +- Add contrib/inflate86/ for x86 faster inflate +- Add contrib/blast/ for PKWare Data Compression Library decompression +- Add contrib/puff/ simple inflate for deflate format description + +Changes in 1.1.4 (11 March 2002) +- ZFREE was repeated on same allocation on some error conditions. + This creates a security problem described in + http://www.zlib.org/advisory-2002-03-11.txt +- Returned incorrect error (Z_MEM_ERROR) on some invalid data +- Avoid accesses before window for invalid distances with inflate window + less than 32K. +- force windowBits > 8 to avoid a bug in the encoder for a window size + of 256 bytes. (A complete fix will be available in 1.1.5). + +Changes in 1.1.3 (9 July 1998) +- fix "an inflate input buffer bug that shows up on rare but persistent + occasions" (Mark) +- fix gzread and gztell for concatenated .gz files (Didier Le Botlan) +- fix gzseek(..., SEEK_SET) in write mode +- fix crc check after a gzeek (Frank Faubert) +- fix miniunzip when the last entry in a zip file is itself a zip file + (J Lillge) +- add contrib/asm586 and contrib/asm686 (Brian Raiter) + See http://www.muppetlabs.com/~breadbox/software/assembly.html +- add support for Delphi 3 in contrib/delphi (Bob Dellaca) +- add support for C++Builder 3 and Delphi 3 in contrib/delphi2 (Davide Moretti) +- do not exit prematurely in untgz if 0 at start of block (Magnus Holmgren) +- use macro EXTERN instead of extern to support DLL for BeOS (Sander Stoks) +- added a FAQ file + +- Support gzdopen on Mac with Metrowerks (Jason Linhart) +- Do not redefine Byte on Mac (Brad Pettit & Jason Linhart) +- define SEEK_END too if SEEK_SET is not defined (Albert Chin-A-Young) +- avoid some warnings with Borland C (Tom Tanner) +- fix a problem in contrib/minizip/zip.c for 16-bit MSDOS (Gilles Vollant) +- emulate utime() for WIN32 in contrib/untgz (Gilles Vollant) +- allow several arguments to configure (Tim Mooney, Frodo Looijaard) +- use libdir and includedir in Makefile.in (Tim Mooney) +- support shared libraries on OSF1 V4 (Tim Mooney) +- remove so_locations in "make clean" (Tim Mooney) +- fix maketree.c compilation error (Glenn, Mark) +- Python interface to zlib now in Python 1.5 (Jeremy Hylton) +- new Makefile.riscos (Rich Walker) +- initialize static descriptors in trees.c for embedded targets (Nick Smith) +- use "foo-gz" in example.c for RISCOS and VMS (Nick Smith) +- add the OS/2 files in Makefile.in too (Andrew Zabolotny) +- fix fdopen and halloc macros for Microsoft C 6.0 (Tom Lane) +- fix maketree.c to allow clean compilation of inffixed.h (Mark) +- fix parameter check in deflateCopy (Gunther Nikl) +- cleanup trees.c, use compressed_len only in debug mode (Christian Spieler) +- Many portability patches by Christian Spieler: + . zutil.c, zutil.h: added "const" for zmem* + . Make_vms.com: fixed some typos + . Make_vms.com: msdos/Makefile.*: removed zutil.h from some dependency lists + . msdos/Makefile.msc: remove "default rtl link library" info from obj files + . msdos/Makefile.*: use model-dependent name for the built zlib library + . msdos/Makefile.emx, nt/Makefile.emx, nt/Makefile.gcc: + new makefiles, for emx (DOS/OS2), emx&rsxnt and mingw32 (Windows 9x / NT) +- use define instead of typedef for Bytef also for MSC small/medium (Tom Lane) +- replace __far with _far for better portability (Christian Spieler, Tom Lane) +- fix test for errno.h in configure (Tim Newsham) + +Changes in 1.1.2 (19 March 98) +- added contrib/minzip, mini zip and unzip based on zlib (Gilles Vollant) + See http://www.winimage.com/zLibDll/unzip.html +- preinitialize the inflate tables for fixed codes, to make the code + completely thread safe (Mark) +- some simplifications and slight speed-up to the inflate code (Mark) +- fix gzeof on non-compressed files (Allan Schrum) +- add -std1 option in configure for OSF1 to fix gzprintf (Martin Mokrejs) +- use default value of 4K for Z_BUFSIZE for 16-bit MSDOS (Tim Wegner + Glenn) +- added os2/Makefile.def and os2/zlib.def (Andrew Zabolotny) +- add shared lib support for UNIX_SV4.2MP (MATSUURA Takanori) +- do not wrap extern "C" around system includes (Tom Lane) +- mention zlib binding for TCL in README (Andreas Kupries) +- added amiga/Makefile.pup for Amiga powerUP SAS/C PPC (Andreas Kleinert) +- allow "make install prefix=..." even after configure (Glenn Randers-Pehrson) +- allow "configure --prefix $HOME" (Tim Mooney) +- remove warnings in example.c and gzio.c (Glenn Randers-Pehrson) +- move Makefile.sas to amiga/Makefile.sas + +Changes in 1.1.1 (27 Feb 98) +- fix macros _tr_tally_* in deflate.h for debug mode (Glenn Randers-Pehrson) +- remove block truncation heuristic which had very marginal effect for zlib + (smaller lit_bufsize than in gzip 1.2.4) and degraded a little the + compression ratio on some files. This also allows inlining _tr_tally for + matches in deflate_slow. +- added msdos/Makefile.w32 for WIN32 Microsoft Visual C++ (Bob Frazier) + +Changes in 1.1.0 (24 Feb 98) +- do not return STREAM_END prematurely in inflate (John Bowler) +- revert to the zlib 1.0.8 inflate to avoid the gcc 2.8.0 bug (Jeremy Buhler) +- compile with -DFASTEST to get compression code optimized for speed only +- in minigzip, try mmap'ing the input file first (Miguel Albrecht) +- increase size of I/O buffers in minigzip.c and gzio.c (not a big gain + on Sun but significant on HP) + +- add a pointer to experimental unzip library in README (Gilles Vollant) +- initialize variable gcc in configure (Chris Herborth) + +Changes in 1.0.9 (17 Feb 1998) +- added gzputs and gzgets functions +- do not clear eof flag in gzseek (Mark Diekhans) +- fix gzseek for files in transparent mode (Mark Diekhans) +- do not assume that vsprintf returns the number of bytes written (Jens Krinke) +- replace EXPORT with ZEXPORT to avoid conflict with other programs +- added compress2 in zconf.h, zlib.def, zlib.dnt +- new asm code from Gilles Vollant in contrib/asm386 +- simplify the inflate code (Mark): + . Replace ZALLOC's in huft_build() with single ZALLOC in inflate_blocks_new() + . ZALLOC the length list in inflate_trees_fixed() instead of using stack + . ZALLOC the value area for huft_build() instead of using stack + . Simplify Z_FINISH check in inflate() + +- Avoid gcc 2.8.0 comparison bug a little differently than zlib 1.0.8 +- in inftrees.c, avoid cc -O bug on HP (Farshid Elahi) +- in zconf.h move the ZLIB_DLL stuff earlier to avoid problems with + the declaration of FAR (Gilles VOllant) +- install libz.so* with mode 755 (executable) instead of 644 (Marc Lehmann) +- read_buf buf parameter of type Bytef* instead of charf* +- zmemcpy parameters are of type Bytef*, not charf* (Joseph Strout) +- do not redeclare unlink in minigzip.c for WIN32 (John Bowler) +- fix check for presence of directories in "make install" (Ian Willis) + +Changes in 1.0.8 (27 Jan 1998) +- fixed offsets in contrib/asm386/gvmat32.asm (Gilles Vollant) +- fix gzgetc and gzputc for big endian systems (Markus Oberhumer) +- added compress2() to allow setting the compression level +- include sys/types.h to get off_t on some systems (Marc Lehmann & QingLong) +- use constant arrays for the static trees in trees.c instead of computing + them at run time (thanks to Ken Raeburn for this suggestion). To create + trees.h, compile with GEN_TREES_H and run "make test". +- check return code of example in "make test" and display result +- pass minigzip command line options to file_compress +- simplifying code of inflateSync to avoid gcc 2.8 bug + +- support CC="gcc -Wall" in configure -s (QingLong) +- avoid a flush caused by ftell in gzopen for write mode (Ken Raeburn) +- fix test for shared library support to avoid compiler warnings +- zlib.lib -> zlib.dll in msdos/zlib.rc (Gilles Vollant) +- check for TARGET_OS_MAC in addition to MACOS (Brad Pettit) +- do not use fdopen for Metrowerks on Mac (Brad Pettit)) +- add checks for gzputc and gzputc in example.c +- avoid warnings in gzio.c and deflate.c (Andreas Kleinert) +- use const for the CRC table (Ken Raeburn) +- fixed "make uninstall" for shared libraries +- use Tracev instead of Trace in infblock.c +- in example.c use correct compressed length for test_sync +- suppress +vnocompatwarnings in configure for HPUX (not always supported) + +Changes in 1.0.7 (20 Jan 1998) +- fix gzseek which was broken in write mode +- return error for gzseek to negative absolute position +- fix configure for Linux (Chun-Chung Chen) +- increase stack space for MSC (Tim Wegner) +- get_crc_table and inflateSyncPoint are EXPORTed (Gilles Vollant) +- define EXPORTVA for gzprintf (Gilles Vollant) +- added man page zlib.3 (Rick Rodgers) +- for contrib/untgz, fix makedir() and improve Makefile + +- check gzseek in write mode in example.c +- allocate extra buffer for seeks only if gzseek is actually called +- avoid signed/unsigned comparisons (Tim Wegner, Gilles Vollant) +- add inflateSyncPoint in zconf.h +- fix list of exported functions in nt/zlib.dnt and mdsos/zlib.def + +Changes in 1.0.6 (19 Jan 1998) +- add functions gzprintf, gzputc, gzgetc, gztell, gzeof, gzseek, gzrewind and + gzsetparams (thanks to Roland Giersig and Kevin Ruland for some of this code) +- Fix a deflate bug occurring only with compression level 0 (thanks to + Andy Buckler for finding this one). +- In minigzip, pass transparently also the first byte for .Z files. +- return Z_BUF_ERROR instead of Z_OK if output buffer full in uncompress() +- check Z_FINISH in inflate (thanks to Marc Schluper) +- Implement deflateCopy (thanks to Adam Costello) +- make static libraries by default in configure, add --shared option. +- move MSDOS or Windows specific files to directory msdos +- suppress the notion of partial flush to simplify the interface + (but the symbol Z_PARTIAL_FLUSH is kept for compatibility with 1.0.4) +- suppress history buffer provided by application to simplify the interface + (this feature was not implemented anyway in 1.0.4) +- next_in and avail_in must be initialized before calling inflateInit or + inflateInit2 +- add EXPORT in all exported functions (for Windows DLL) +- added Makefile.nt (thanks to Stephen Williams) +- added the unsupported "contrib" directory: + contrib/asm386/ by Gilles Vollant + 386 asm code replacing longest_match(). + contrib/iostream/ by Kevin Ruland + A C++ I/O streams interface to the zlib gz* functions + contrib/iostream2/ by Tyge Løvset + Another C++ I/O streams interface + contrib/untgz/ by "Pedro A. Aranda Guti\irrez" + A very simple tar.gz file extractor using zlib + contrib/visual-basic.txt by Carlos Rios + How to use compress(), uncompress() and the gz* functions from VB. +- pass params -f (filtered data), -h (huffman only), -1 to -9 (compression + level) in minigzip (thanks to Tom Lane) + +- use const for rommable constants in deflate +- added test for gzseek and gztell in example.c +- add undocumented function inflateSyncPoint() (hack for Paul Mackerras) +- add undocumented function zError to convert error code to string + (for Tim Smithers) +- Allow compilation of gzio with -DNO_DEFLATE to avoid the compression code. +- Use default memcpy for Symantec MSDOS compiler. +- Add EXPORT keyword for check_func (needed for Windows DLL) +- add current directory to LD_LIBRARY_PATH for "make test" +- create also a link for libz.so.1 +- added support for FUJITSU UXP/DS (thanks to Toshiaki Nomura) +- use $(SHAREDLIB) instead of libz.so in Makefile.in (for HPUX) +- added -soname for Linux in configure (Chun-Chung Chen, +- assign numbers to the exported functions in zlib.def (for Windows DLL) +- add advice in zlib.h for best usage of deflateSetDictionary +- work around compiler bug on Atari (cast Z_NULL in call of s->checkfn) +- allow compilation with ANSI keywords only enabled for TurboC in large model +- avoid "versionString"[0] (Borland bug) +- add NEED_DUMMY_RETURN for Borland +- use variable z_verbose for tracing in debug mode (L. Peter Deutsch). +- allow compilation with CC +- defined STDC for OS/2 (David Charlap) +- limit external names to 8 chars for MVS (Thomas Lund) +- in minigzip.c, use static buffers only for 16-bit systems +- fix suffix check for "minigzip -d foo.gz" +- do not return an error for the 2nd of two consecutive gzflush() (Felix Lee) +- use _fdopen instead of fdopen for MSC >= 6.0 (Thomas Fanslau) +- added makelcc.bat for lcc-win32 (Tom St Denis) +- in Makefile.dj2, use copy and del instead of install and rm (Frank Donahoe) +- Avoid expanded $Id$. Use "rcs -kb" or "cvs admin -kb" to avoid Id expansion. +- check for unistd.h in configure (for off_t) +- remove useless check parameter in inflate_blocks_free +- avoid useless assignment of s->check to itself in inflate_blocks_new +- do not flush twice in gzclose (thanks to Ken Raeburn) +- rename FOPEN as F_OPEN to avoid clash with /usr/include/sys/file.h +- use NO_ERRNO_H instead of enumeration of operating systems with errno.h +- work around buggy fclose on pipes for HP/UX +- support zlib DLL with BORLAND C++ 5.0 (thanks to Glenn Randers-Pehrson) +- fix configure if CC is already equal to gcc + +Changes in 1.0.5 (3 Jan 98) +- Fix inflate to terminate gracefully when fed corrupted or invalid data +- Use const for rommable constants in inflate +- Eliminate memory leaks on error conditions in inflate +- Removed some vestigial code in inflate +- Update web address in README + +Changes in 1.0.4 (24 Jul 96) +- In very rare conditions, deflate(s, Z_FINISH) could fail to produce an EOF + bit, so the decompressor could decompress all the correct data but went + on to attempt decompressing extra garbage data. This affected minigzip too. +- zlibVersion and gzerror return const char* (needed for DLL) +- port to RISCOS (no fdopen, no multiple dots, no unlink, no fileno) +- use z_error only for DEBUG (avoid problem with DLLs) + +Changes in 1.0.3 (2 Jul 96) +- use z_streamp instead of z_stream *, which is now a far pointer in MSDOS + small and medium models; this makes the library incompatible with previous + versions for these models. (No effect in large model or on other systems.) +- return OK instead of BUF_ERROR if previous deflate call returned with + avail_out as zero but there is nothing to do +- added memcmp for non STDC compilers +- define NO_DUMMY_DECL for more Mac compilers (.h files merged incorrectly) +- define __32BIT__ if __386__ or i386 is defined (pb. with Watcom and SCO) +- better check for 16-bit mode MSC (avoids problem with Symantec) + +Changes in 1.0.2 (23 May 96) +- added Windows DLL support +- added a function zlibVersion (for the DLL support) +- fixed declarations using Bytef in infutil.c (pb with MSDOS medium model) +- Bytef is define's instead of typedef'd only for Borland C +- avoid reading uninitialized memory in example.c +- mention in README that the zlib format is now RFC1950 +- updated Makefile.dj2 +- added algorithm.doc + +Changes in 1.0.1 (20 May 96) [1.0 skipped to avoid confusion] +- fix array overlay in deflate.c which sometimes caused bad compressed data +- fix inflate bug with empty stored block +- fix MSDOS medium model which was broken in 0.99 +- fix deflateParams() which could generated bad compressed data. +- Bytef is define'd instead of typedef'ed (work around Borland bug) +- added an INDEX file +- new makefiles for DJGPP (Makefile.dj2), 32-bit Borland (Makefile.b32), + Watcom (Makefile.wat), Amiga SAS/C (Makefile.sas) +- speed up adler32 for modern machines without auto-increment +- added -ansi for IRIX in configure +- static_init_done in trees.c is an int +- define unlink as delete for VMS +- fix configure for QNX +- add configure branch for SCO and HPUX +- avoid many warnings (unused variables, dead assignments, etc...) +- no fdopen for BeOS +- fix the Watcom fix for 32 bit mode (define FAR as empty) +- removed redefinition of Byte for MKWERKS +- work around an MWKERKS bug (incorrect merge of all .h files) + +Changes in 0.99 (27 Jan 96) +- allow preset dictionary shared between compressor and decompressor +- allow compression level 0 (no compression) +- add deflateParams in zlib.h: allow dynamic change of compression level + and compression strategy. +- test large buffers and deflateParams in example.c +- add optional "configure" to build zlib as a shared library +- suppress Makefile.qnx, use configure instead +- fixed deflate for 64-bit systems (detected on Cray) +- fixed inflate_blocks for 64-bit systems (detected on Alpha) +- declare Z_DEFLATED in zlib.h (possible parameter for deflateInit2) +- always return Z_BUF_ERROR when deflate() has nothing to do +- deflateInit and inflateInit are now macros to allow version checking +- prefix all global functions and types with z_ with -DZ_PREFIX +- make falloc completely reentrant (inftrees.c) +- fixed very unlikely race condition in ct_static_init +- free in reverse order of allocation to help memory manager +- use zlib-1.0/* instead of zlib/* inside the tar.gz +- make zlib warning-free with "gcc -O3 -Wall -Wwrite-strings -Wpointer-arith + -Wconversion -Wstrict-prototypes -Wmissing-prototypes" +- allow gzread on concatenated .gz files +- deflateEnd now returns Z_DATA_ERROR if it was premature +- deflate is finally (?) fully deterministic (no matches beyond end of input) +- Document Z_SYNC_FLUSH +- add uninstall in Makefile +- Check for __cpluplus in zlib.h +- Better test in ct_align for partial flush +- avoid harmless warnings for Borland C++ +- initialize hash_head in deflate.c +- avoid warning on fdopen (gzio.c) for HP cc -Aa +- include stdlib.h for STDC compilers +- include errno.h for Cray +- ignore error if ranlib doesn't exist +- call ranlib twice for NeXTSTEP +- use exec_prefix instead of prefix for libz.a +- renamed ct_* as _tr_* to avoid conflict with applications +- clear z->msg in inflateInit2 before any error return +- initialize opaque in example.c, gzio.c, deflate.c and inflate.c +- fixed typo in zconf.h (_GNUC__ => __GNUC__) +- check for WIN32 in zconf.h and zutil.c (avoid farmalloc in 32-bit mode) +- fix typo in Make_vms.com (f$trnlnm -> f$getsyi) +- in fcalloc, normalize pointer if size > 65520 bytes +- don't use special fcalloc for 32 bit Borland C++ +- use STDC instead of __GO32__ to avoid redeclaring exit, calloc, etc... +- use Z_BINARY instead of BINARY +- document that gzclose after gzdopen will close the file +- allow "a" as mode in gzopen. +- fix error checking in gzread +- allow skipping .gz extra-field on pipes +- added reference to Perl interface in README +- put the crc table in FAR data (I dislike more and more the medium model :) +- added get_crc_table +- added a dimension to all arrays (Borland C can't count). +- workaround Borland C bug in declaration of inflate_codes_new & inflate_fast +- guard against multiple inclusion of *.h (for precompiled header on Mac) +- Watcom C pretends to be Microsoft C small model even in 32 bit mode. +- don't use unsized arrays to avoid silly warnings by Visual C++: + warning C4746: 'inflate_mask' : unsized array treated as '__far' + (what's wrong with far data in far model?). +- define enum out of inflate_blocks_state to allow compilation with C++ + +Changes in 0.95 (16 Aug 95) +- fix MSDOS small and medium model (now easier to adapt to any compiler) +- inlined send_bits +- fix the final (:-) bug for deflate with flush (output was correct but + not completely flushed in rare occasions). +- default window size is same for compression and decompression + (it's now sufficient to set MAX_WBITS in zconf.h). +- voidp -> voidpf and voidnp -> voidp (for consistency with other + typedefs and because voidnp was not near in large model). + +Changes in 0.94 (13 Aug 95) +- support MSDOS medium model +- fix deflate with flush (could sometimes generate bad output) +- fix deflateReset (zlib header was incorrectly suppressed) +- added support for VMS +- allow a compression level in gzopen() +- gzflush now calls fflush +- For deflate with flush, flush even if no more input is provided. +- rename libgz.a as libz.a +- avoid complex expression in infcodes.c triggering Turbo C bug +- work around a problem with gcc on Alpha (in INSERT_STRING) +- don't use inline functions (problem with some gcc versions) +- allow renaming of Byte, uInt, etc... with #define. +- avoid warning about (unused) pointer before start of array in deflate.c +- avoid various warnings in gzio.c, example.c, infblock.c, adler32.c, zutil.c +- avoid reserved word 'new' in trees.c + +Changes in 0.93 (25 June 95) +- temporarily disable inline functions +- make deflate deterministic +- give enough lookahead for PARTIAL_FLUSH +- Set binary mode for stdin/stdout in minigzip.c for OS/2 +- don't even use signed char in inflate (not portable enough) +- fix inflate memory leak for segmented architectures + +Changes in 0.92 (3 May 95) +- don't assume that char is signed (problem on SGI) +- Clear bit buffer when starting a stored block +- no memcpy on Pyramid +- suppressed inftest.c +- optimized fill_window, put longest_match inline for gcc +- optimized inflate on stored blocks. +- untabify all sources to simplify patches + +Changes in 0.91 (2 May 95) +- Default MEM_LEVEL is 8 (not 9 for Unix) as documented in zlib.h +- Document the memory requirements in zconf.h +- added "make install" +- fix sync search logic in inflateSync +- deflate(Z_FULL_FLUSH) now works even if output buffer too short +- after inflateSync, don't scare people with just "lo world" +- added support for DJGPP + +Changes in 0.9 (1 May 95) +- don't assume that zalloc clears the allocated memory (the TurboC bug + was Mark's bug after all :) +- let again gzread copy uncompressed data unchanged (was working in 0.71) +- deflate(Z_FULL_FLUSH), inflateReset and inflateSync are now fully implemented +- added a test of inflateSync in example.c +- moved MAX_WBITS to zconf.h because users might want to change that. +- document explicitly that zalloc(64K) on MSDOS must return a normalized + pointer (zero offset) +- added Makefiles for Microsoft C, Turbo C, Borland C++ +- faster crc32() + +Changes in 0.8 (29 April 95) +- added fast inflate (inffast.c) +- deflate(Z_FINISH) now returns Z_STREAM_END when done. Warning: this + is incompatible with previous versions of zlib which returned Z_OK. +- work around a TurboC compiler bug (bad code for b << 0, see infutil.h) + (actually that was not a compiler bug, see 0.81 above) +- gzread no longer reads one extra byte in certain cases +- In gzio destroy(), don't reference a freed structure +- avoid many warnings for MSDOS +- avoid the ERROR symbol which is used by MS Windows + +Changes in 0.71 (14 April 95) +- Fixed more MSDOS compilation problems :( There is still a bug with + TurboC large model. + +Changes in 0.7 (14 April 95) +- Added full inflate support. +- Simplified the crc32() interface. The pre- and post-conditioning + (one's complement) is now done inside crc32(). WARNING: this is + incompatible with previous versions; see zlib.h for the new usage. + +Changes in 0.61 (12 April 95) +- workaround for a bug in TurboC. example and minigzip now work on MSDOS. + +Changes in 0.6 (11 April 95) +- added minigzip.c +- added gzdopen to reopen a file descriptor as gzFile +- added transparent reading of non-gziped files in gzread. +- fixed bug in gzread (don't read crc as data) +- fixed bug in destroy (gzio.c) (don't return Z_STREAM_END for gzclose). +- don't allocate big arrays in the stack (for MSDOS) +- fix some MSDOS compilation problems + +Changes in 0.5: +- do real compression in deflate.c. Z_PARTIAL_FLUSH is supported but + not yet Z_FULL_FLUSH. +- support decompression but only in a single step (forced Z_FINISH) +- added opaque object for zalloc and zfree. +- added deflateReset and inflateReset +- added a variable zlib_version for consistency checking. +- renamed the 'filter' parameter of deflateInit2 as 'strategy'. + Added Z_FILTERED and Z_HUFFMAN_ONLY constants. + +Changes in 0.4: +- avoid "zip" everywhere, use zlib instead of ziplib. +- suppress Z_BLOCK_FLUSH, interpret Z_PARTIAL_FLUSH as block flush + if compression method == 8. +- added adler32 and crc32 +- renamed deflateOptions as deflateInit2, call one or the other but not both +- added the method parameter for deflateInit2. +- added inflateInit2 +- simplied considerably deflateInit and inflateInit by not supporting + user-provided history buffer. This is supported only in deflateInit2 + and inflateInit2. + +Changes in 0.3: +- prefix all macro names with Z_ +- use Z_FINISH instead of deflateEnd to finish compression. +- added Z_HUFFMAN_ONLY +- added gzerror() diff --git a/gdcm/Utilities/gdcmzlib/FAQ b/gdcm/Utilities/gdcmzlib/FAQ new file mode 100644 index 0000000..441d910 --- /dev/null +++ b/gdcm/Utilities/gdcmzlib/FAQ @@ -0,0 +1,339 @@ + + Frequently Asked Questions about zlib + + +If your question is not there, please check the zlib home page +http://www.zlib.org which may have more recent information. +The lastest zlib FAQ is at http://www.gzip.org/zlib/zlib_faq.html + + + 1. Is zlib Y2K-compliant? + + Yes. zlib doesn't handle dates. + + 2. Where can I get a Windows DLL version? + + The zlib sources can be compiled without change to produce a DLL. + See the file win32/DLL_FAQ.txt in the zlib distribution. + Pointers to the precompiled DLL are found in the zlib web site at + http://www.zlib.org. + + 3. Where can I get a Visual Basic interface to zlib? + + See + * http://www.dogma.net/markn/articles/zlibtool/zlibtool.htm + * contrib/visual-basic.txt in the zlib distribution + * win32/DLL_FAQ.txt in the zlib distribution + + 4. compress() returns Z_BUF_ERROR. + + Make sure that before the call of compress, the length of the compressed + buffer is equal to the total size of the compressed buffer and not + zero. For Visual Basic, check that this parameter is passed by reference + ("as any"), not by value ("as long"). + + 5. deflate() or inflate() returns Z_BUF_ERROR. + + Before making the call, make sure that avail_in and avail_out are not + zero. When setting the parameter flush equal to Z_FINISH, also make sure + that avail_out is big enough to allow processing all pending input. + Note that a Z_BUF_ERROR is not fatal--another call to deflate() or + inflate() can be made with more input or output space. A Z_BUF_ERROR + may in fact be unavoidable depending on how the functions are used, since + it is not possible to tell whether or not there is more output pending + when strm.avail_out returns with zero. + + 6. Where's the zlib documentation (man pages, etc.)? + + It's in zlib.h for the moment, and Francis S. Lin has converted it to a + web page zlib.html. Volunteers to transform this to Unix-style man pages, + please contact us (zlib@gzip.org). Examples of zlib usage are in the files + example.c and minigzip.c. + + 7. Why don't you use GNU autoconf or libtool or ...? + + Because we would like to keep zlib as a very small and simple + package. zlib is rather portable and doesn't need much configuration. + + 8. I found a bug in zlib. + + Most of the time, such problems are due to an incorrect usage of + zlib. Please try to reproduce the problem with a small program and send + the corresponding source to us at zlib@gzip.org . Do not send + multi-megabyte data files without prior agreement. + + 9. Why do I get "undefined reference to gzputc"? + + If "make test" produces something like + + example.o(.text+0x154): undefined reference to `gzputc' + + check that you don't have old files libz.* in /usr/lib, /usr/local/lib or + /usr/X11R6/lib. Remove any old versions, then do "make install". + +10. I need a Delphi interface to zlib. + + See the contrib/delphi directory in the zlib distribution. + +11. Can zlib handle .zip archives? + + Not by itself, no. See the directory contrib/minizip in the zlib + distribution. + +12. Can zlib handle .Z files? + + No, sorry. You have to spawn an uncompress or gunzip subprocess, or adapt + the code of uncompress on your own. + +13. How can I make a Unix shared library? + + make clean + ./configure -s + make + +14. How do I install a shared zlib library on Unix? + + After the above, then: + + make install + + However, many flavors of Unix come with a shared zlib already installed. + Before going to the trouble of compiling a shared version of zlib and + trying to install it, you may want to check if it's already there! If you + can #include , it's there. The -lz option will probably link to it. + +15. I have a question about OttoPDF. + + We are not the authors of OttoPDF. The real author is on the OttoPDF web + site: Joel Hainley, jhainley@myndkryme.com. + +16. Can zlib decode Flate data in an Adobe PDF file? + + Yes. See http://www.fastio.com/ (ClibPDF), or http://www.pdflib.com/ . + To modify PDF forms, see http://sourceforge.net/projects/acroformtool/ . + +17. Why am I getting this "register_frame_info not found" error on Solaris? + + After installing zlib 1.1.4 on Solaris 2.6, running applications using zlib + generates an error such as: + + ld.so.1: rpm: fatal: relocation error: file /usr/local/lib/libz.so: + symbol __register_frame_info: referenced symbol not found + + The symbol __register_frame_info is not part of zlib, it is generated by + the C compiler (cc or gcc). You must recompile applications using zlib + which have this problem. This problem is specific to Solaris. See + http://www.sunfreeware.com for Solaris versions of zlib and applications + using zlib. + +18. Why does gzip give an error on a file I make with compress/deflate? + + The compress and deflate functions produce data in the zlib format, which + is different and incompatible with the gzip format. The gz* functions in + zlib on the other hand use the gzip format. Both the zlib and gzip + formats use the same compressed data format internally, but have different + headers and trailers around the compressed data. + +19. Ok, so why are there two different formats? + + The gzip format was designed to retain the directory information about + a single file, such as the name and last modification date. The zlib + format on the other hand was designed for in-memory and communication + channel applications, and has a much more compact header and trailer and + uses a faster integrity check than gzip. + +20. Well that's nice, but how do I make a gzip file in memory? + + You can request that deflate write the gzip format instead of the zlib + format using deflateInit2(). You can also request that inflate decode + the gzip format using inflateInit2(). Read zlib.h for more details. + +21. Is zlib thread-safe? + + Yes. However any library routines that zlib uses and any application- + provided memory allocation routines must also be thread-safe. zlib's gz* + functions use stdio library routines, and most of zlib's functions use the + library memory allocation routines by default. zlib's Init functions allow + for the application to provide custom memory allocation routines. + + Of course, you should only operate on any given zlib or gzip stream from a + single thread at a time. + +22. Can I use zlib in my commercial application? + + Yes. Please read the license in zlib.h. + +23. Is zlib under the GNU license? + + No. Please read the license in zlib.h. + +24. The license says that altered source versions must be "plainly marked". So + what exactly do I need to do to meet that requirement? + + You need to change the ZLIB_VERSION and ZLIB_VERNUM #defines in zlib.h. In + particular, the final version number needs to be changed to "f", and an + identification string should be appended to ZLIB_VERSION. Version numbers + x.x.x.f are reserved for modifications to zlib by others than the zlib + maintainers. For example, if the version of the base zlib you are altering + is "1.2.3.4", then in zlib.h you should change ZLIB_VERNUM to 0x123f, and + ZLIB_VERSION to something like "1.2.3.f-zachary-mods-v3". You can also + update the version strings in deflate.c and inftrees.c. + + For altered source distributions, you should also note the origin and + nature of the changes in zlib.h, as well as in ChangeLog and README, along + with the dates of the alterations. The origin should include at least your + name (or your company's name), and an email address to contact for help or + issues with the library. + + Note that distributing a compiled zlib library along with zlib.h and + zconf.h is also a source distribution, and so you should change + ZLIB_VERSION and ZLIB_VERNUM and note the origin and nature of the changes + in zlib.h as you would for a full source distribution. + +25. Will zlib work on a big-endian or little-endian architecture, and can I + exchange compressed data between them? + + Yes and yes. + +26. Will zlib work on a 64-bit machine? + + It should. It has been tested on 64-bit machines, and has no dependence + on any data types being limited to 32-bits in length. If you have any + difficulties, please provide a complete problem report to zlib@gzip.org + +27. Will zlib decompress data from the PKWare Data Compression Library? + + No. The PKWare DCL uses a completely different compressed data format + than does PKZIP and zlib. However, you can look in zlib's contrib/blast + directory for a possible solution to your problem. + +28. Can I access data randomly in a compressed stream? + + No, not without some preparation. If when compressing you periodically + use Z_FULL_FLUSH, carefully write all the pending data at those points, + and keep an index of those locations, then you can start decompression + at those points. You have to be careful to not use Z_FULL_FLUSH too + often, since it can significantly degrade compression. + +29. Does zlib work on MVS, OS/390, CICS, etc.? + + We don't know for sure. We have heard occasional reports of success on + these systems. If you do use it on one of these, please provide us with + a report, instructions, and patches that we can reference when we get + these questions. Thanks. + +30. Is there some simpler, easier to read version of inflate I can look at + to understand the deflate format? + + First off, you should read RFC 1951. Second, yes. Look in zlib's + contrib/puff directory. + +31. Does zlib infringe on any patents? + + As far as we know, no. In fact, that was originally the whole point behind + zlib. Look here for some more information: + + http://www.gzip.org/#faq11 + +32. Can zlib work with greater than 4 GB of data? + + Yes. inflate() and deflate() will process any amount of data correctly. + Each call of inflate() or deflate() is limited to input and output chunks + of the maximum value that can be stored in the compiler's "unsigned int" + type, but there is no limit to the number of chunks. Note however that the + strm.total_in and strm_total_out counters may be limited to 4 GB. These + counters are provided as a convenience and are not used internally by + inflate() or deflate(). The application can easily set up its own counters + updated after each call of inflate() or deflate() to count beyond 4 GB. + compress() and uncompress() may be limited to 4 GB, since they operate in a + single call. gzseek() and gztell() may be limited to 4 GB depending on how + zlib is compiled. See the zlibCompileFlags() function in zlib.h. + + The word "may" appears several times above since there is a 4 GB limit + only if the compiler's "long" type is 32 bits. If the compiler's "long" + type is 64 bits, then the limit is 16 exabytes. + +33. Does zlib have any security vulnerabilities? + + The only one that we are aware of is potentially in gzprintf(). If zlib + is compiled to use sprintf() or vsprintf(), then there is no protection + against a buffer overflow of a 4K string space, other than the caller of + gzprintf() assuring that the output will not exceed 4K. On the other + hand, if zlib is compiled to use snprintf() or vsnprintf(), which should + normally be the case, then there is no vulnerability. The ./configure + script will display warnings if an insecure variation of sprintf() will + be used by gzprintf(). Also the zlibCompileFlags() function will return + information on what variant of sprintf() is used by gzprintf(). + + If you don't have snprintf() or vsnprintf() and would like one, you can + find a portable implementation here: + + http://www.ijs.si/software/snprintf/ + + Note that you should be using the most recent version of zlib. Versions + 1.1.3 and before were subject to a double-free vulnerability. + +34. Is there a Java version of zlib? + + Probably what you want is to use zlib in Java. zlib is already included + as part of the Java SDK in the java.util.zip package. If you really want + a version of zlib written in the Java language, look on the zlib home + page for links: http://www.zlib.org/ + +35. I get this or that compiler or source-code scanner warning when I crank it + up to maximally-pedantic. Can't you guys write proper code? + + Many years ago, we gave up attempting to avoid warnings on every compiler + in the universe. It just got to be a waste of time, and some compilers + were downright silly. So now, we simply make sure that the code always + works. + +36. Valgrind (or some similar memory access checker) says that deflate is + performing a conditional jump that depends on an uninitialized value. + Isn't that a bug? + + No. That is intentional for performance reasons, and the output of + deflate is not affected. This only started showing up recently since + zlib 1.2.x uses malloc() by default for allocations, whereas earlier + versions used calloc(), which zeros out the allocated memory. + +37. Will zlib read the (insert any ancient or arcane format here) compressed + data format? + + Probably not. Look in the comp.compression FAQ for pointers to various + formats and associated software. + +38. How can I encrypt/decrypt zip files with zlib? + + zlib doesn't support encryption. The original PKZIP encryption is very weak + and can be broken with freely available programs. To get strong encryption, + use GnuPG, http://www.gnupg.org/ , which already includes zlib compression. + For PKZIP compatible "encryption", look at http://www.info-zip.org/ + +39. What's the difference between the "gzip" and "deflate" HTTP 1.1 encodings? + + "gzip" is the gzip format, and "deflate" is the zlib format. They should + probably have called the second one "zlib" instead to avoid confusion + with the raw deflate compressed data format. While the HTTP 1.1 RFC 2616 + correctly points to the zlib specification in RFC 1950 for the "deflate" + transfer encoding, there have been reports of servers and browsers that + incorrectly produce or expect raw deflate data per the deflate + specficiation in RFC 1951, most notably Microsoft. So even though the + "deflate" transfer encoding using the zlib format would be the more + efficient approach (and in fact exactly what the zlib format was designed + for), using the "gzip" transfer encoding is probably more reliable due to + an unfortunate choice of name on the part of the HTTP 1.1 authors. + + Bottom line: use the gzip format for HTTP 1.1 encoding. + +40. Does zlib support the new "Deflate64" format introduced by PKWare? + + No. PKWare has apparently decided to keep that format proprietary, since + they have not documented it as they have previous compression formats. + In any case, the compression improvements are so modest compared to other + more modern approaches, that it's not worth the effort to implement. + +41. Can you please sign these lengthy legal documents and fax them back to us + so that we can use your software in our product? + + No. Go away. Shoo. diff --git a/gdcm/Utilities/gdcmzlib/INDEX b/gdcm/Utilities/gdcmzlib/INDEX new file mode 100644 index 0000000..0587e59 --- /dev/null +++ b/gdcm/Utilities/gdcmzlib/INDEX @@ -0,0 +1,51 @@ +ChangeLog history of changes +FAQ Frequently Asked Questions about zlib +INDEX this file +Makefile makefile for Unix (generated by configure) +Makefile.in makefile for Unix (template for configure) +README guess what +algorithm.txt description of the (de)compression algorithm +configure configure script for Unix +zconf.in.h template for zconf.h (used by configure) + +amiga/ makefiles for Amiga SAS C +as400/ makefiles for IBM AS/400 +msdos/ makefiles for MSDOS +old/ makefiles for various architectures and zlib documentation + files that have not yet been updated for zlib 1.2.x +projects/ projects for various Integrated Development Environments +qnx/ makefiles for QNX +win32/ makefiles for Windows + + zlib public header files (must be kept): +zconf.h +zlib.h + + private source files used to build the zlib library: +adler32.c +compress.c +crc32.c +crc32.h +deflate.c +deflate.h +gzio.c +infback.c +inffast.c +inffast.h +inffixed.h +inflate.c +inflate.h +inftrees.c +inftrees.h +trees.c +trees.h +uncompr.c +zutil.c +zutil.h + + source files for sample programs: +example.c +minigzip.c + + unsupported contribution by third parties +See contrib/README.contrib diff --git a/gdcm/Utilities/gdcmzlib/README b/gdcm/Utilities/gdcmzlib/README new file mode 100644 index 0000000..758cc50 --- /dev/null +++ b/gdcm/Utilities/gdcmzlib/README @@ -0,0 +1,125 @@ +ZLIB DATA COMPRESSION LIBRARY + +zlib 1.2.3 is a general purpose data compression library. All the code is +thread safe. The data format used by the zlib library is described by RFCs +(Request for Comments) 1950 to 1952 in the files +http://www.ietf.org/rfc/rfc1950.txt (zlib format), rfc1951.txt (deflate format) +and rfc1952.txt (gzip format). These documents are also available in other +formats from ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html + +All functions of the compression library are documented in the file zlib.h +(volunteer to write man pages welcome, contact zlib@gzip.org). A usage example +of the library is given in the file example.c which also tests that the library +is working correctly. Another example is given in the file minigzip.c. The +compression library itself is composed of all source files except example.c and +minigzip.c. + +To compile all files and run the test program, follow the instructions given at +the top of Makefile. In short "make test; make install" should work for most +machines. For Unix: "./configure; make test; make install". For MSDOS, use one +of the special makefiles such as Makefile.msc. For VMS, use make_vms.com. + +Questions about zlib should be sent to , or to Gilles Vollant + for the Windows DLL version. The zlib home page is +http://www.zlib.org or http://www.gzip.org/zlib/ Before reporting a problem, +please check this site to verify that you have the latest version of zlib; +otherwise get the latest version and check whether the problem still exists or +not. + +PLEASE read the zlib FAQ http://www.gzip.org/zlib/zlib_faq.html before asking +for help. + +Mark Nelson wrote an article about zlib for the Jan. 1997 +issue of Dr. Dobb's Journal; a copy of the article is available in +http://dogma.net/markn/articles/zlibtool/zlibtool.htm + +The changes made in version 1.2.3 are documented in the file ChangeLog. + +Unsupported third party contributions are provided in directory "contrib". + +A Java implementation of zlib is available in the Java Development Kit +http://java.sun.com/j2se/1.4.2/docs/api/java/util/zip/package-summary.html +See the zlib home page http://www.zlib.org for details. + +A Perl interface to zlib written by Paul Marquess is in the +CPAN (Comprehensive Perl Archive Network) sites +http://www.cpan.org/modules/by-module/Compress/ + +A Python interface to zlib written by A.M. Kuchling is +available in Python 1.5 and later versions, see +http://www.python.org/doc/lib/module-zlib.html + +A zlib binding for TCL written by Andreas Kupries is +availlable at http://www.oche.de/~akupries/soft/trf/trf_zip.html + +An experimental package to read and write files in .zip format, written on top +of zlib by Gilles Vollant , is available in the +contrib/minizip directory of zlib. + + +Notes for some targets: + +- For Windows DLL versions, please see win32/DLL_FAQ.txt + +- For 64-bit Irix, deflate.c must be compiled without any optimization. With + -O, one libpng test fails. The test works in 32 bit mode (with the -n32 + compiler flag). The compiler bug has been reported to SGI. + +- zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1 it works + when compiled with cc. + +- On Digital Unix 4.0D (formely OSF/1) on AlphaServer, the cc option -std1 is + necessary to get gzprintf working correctly. This is done by configure. + +- zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works with + other compilers. Use "make test" to check your compiler. + +- gzdopen is not supported on RISCOS, BEOS and by some Mac compilers. + +- For PalmOs, see http://palmzlib.sourceforge.net/ + +- When building a shared, i.e. dynamic library on Mac OS X, the library must be + installed before testing (do "make install" before "make test"), since the + library location is specified in the library. + + +Acknowledgments: + + The deflate format used by zlib was defined by Phil Katz. The deflate + and zlib specifications were written by L. Peter Deutsch. Thanks to all the + people who reported problems and suggested various improvements in zlib; + they are too numerous to cite here. + +Copyright notice: + + (C) 1995-2004 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + +If you use the zlib library in a product, we would appreciate *not* +receiving lengthy legal documents to sign. The sources are provided +for free but without warranty of any kind. The library has been +entirely written by Jean-loup Gailly and Mark Adler; it does not +include third-party code. + +If you redistribute modified sources, we would appreciate that you include +in the file ChangeLog history information documenting your changes. Please +read the FAQ for more information on the distribution of modified source +versions. diff --git a/gdcm/Utilities/gdcmzlib/adler32.c b/gdcm/Utilities/gdcmzlib/adler32.c new file mode 100644 index 0000000..007ba26 --- /dev/null +++ b/gdcm/Utilities/gdcmzlib/adler32.c @@ -0,0 +1,149 @@ +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-2004 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +#define BASE 65521UL /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +/* use NO_DIVIDE if your processor does not do division in hardware */ +#ifdef NO_DIVIDE +# define MOD(a) \ + do { \ + if (a >= (BASE << 16)) a -= (BASE << 16); \ + if (a >= (BASE << 15)) a -= (BASE << 15); \ + if (a >= (BASE << 14)) a -= (BASE << 14); \ + if (a >= (BASE << 13)) a -= (BASE << 13); \ + if (a >= (BASE << 12)) a -= (BASE << 12); \ + if (a >= (BASE << 11)) a -= (BASE << 11); \ + if (a >= (BASE << 10)) a -= (BASE << 10); \ + if (a >= (BASE << 9)) a -= (BASE << 9); \ + if (a >= (BASE << 8)) a -= (BASE << 8); \ + if (a >= (BASE << 7)) a -= (BASE << 7); \ + if (a >= (BASE << 6)) a -= (BASE << 6); \ + if (a >= (BASE << 5)) a -= (BASE << 5); \ + if (a >= (BASE << 4)) a -= (BASE << 4); \ + if (a >= (BASE << 3)) a -= (BASE << 3); \ + if (a >= (BASE << 2)) a -= (BASE << 2); \ + if (a >= (BASE << 1)) a -= (BASE << 1); \ + if (a >= BASE) a -= BASE; \ + } while (0) +# define MOD4(a) \ + do { \ + if (a >= (BASE << 4)) a -= (BASE << 4); \ + if (a >= (BASE << 3)) a -= (BASE << 3); \ + if (a >= (BASE << 2)) a -= (BASE << 2); \ + if (a >= (BASE << 1)) a -= (BASE << 1); \ + if (a >= BASE) a -= BASE; \ + } while (0) +#else +# define MOD(a) a %= BASE +# define MOD4(a) a %= BASE +#endif + +/* ========================================================================= */ +uLong ZEXPORT adler32(adler, buf, len) + uLong adler; + const Bytef *buf; + uInt len; +{ + unsigned long sum2; + unsigned n; + + /* split Adler-32 into component sums */ + sum2 = (adler >> 16) & 0xffff; + adler &= 0xffff; + + /* in case user likes doing a byte at a time, keep it fast */ + if (len == 1) { + adler += buf[0]; + if (adler >= BASE) + adler -= BASE; + sum2 += adler; + if (sum2 >= BASE) + sum2 -= BASE; + return adler | (sum2 << 16); + } + + /* initial Adler-32 value (deferred check for len == 1 speed) */ + if (buf == Z_NULL) + return 1L; + + /* in case short lengths are provided, keep it somewhat fast */ + if (len < 16) { + while (len--) { + adler += *buf++; + sum2 += adler; + } + if (adler >= BASE) + adler -= BASE; + MOD4(sum2); /* only added so many BASE's */ + return adler | (sum2 << 16); + } + + /* do length NMAX blocks -- requires just one modulo operation */ + while (len >= NMAX) { + len -= NMAX; + n = NMAX / 16; /* NMAX is divisible by 16 */ + do { + DO16(buf); /* 16 sums unrolled */ + buf += 16; + } while (--n); + MOD(adler); + MOD(sum2); + } + + /* do remaining bytes (less than NMAX, still just one modulo) */ + if (len) { /* avoid modulos if none remaining */ + while (len >= 16) { + len -= 16; + DO16(buf); + buf += 16; + } + while (len--) { + adler += *buf++; + sum2 += adler; + } + MOD(adler); + MOD(sum2); + } + + /* return recombined sums */ + return adler | (sum2 << 16); +} + +/* ========================================================================= */ +uLong ZEXPORT adler32_combine(adler1, adler2, len2) + uLong adler1; + uLong adler2; + z_off_t len2; +{ + unsigned long sum1; + unsigned long sum2; + unsigned rem; + + /* the derivation of this formula is left as an exercise for the reader */ + rem = (unsigned)(len2 % BASE); + sum1 = adler1 & 0xffff; + sum2 = rem * sum1; + MOD(sum2); + sum1 += (adler2 & 0xffff) + BASE - 1; + sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; + if (sum1 > BASE) sum1 -= BASE; + if (sum1 > BASE) sum1 -= BASE; + if (sum2 > (BASE << 1)) sum2 -= (BASE << 1); + if (sum2 > BASE) sum2 -= BASE; + return sum1 | (sum2 << 16); +} diff --git a/gdcm/Utilities/gdcmzlib/algorithm.txt b/gdcm/Utilities/gdcmzlib/algorithm.txt new file mode 100644 index 0000000..b022dde --- /dev/null +++ b/gdcm/Utilities/gdcmzlib/algorithm.txt @@ -0,0 +1,209 @@ +1. Compression algorithm (deflate) + +The deflation algorithm used by gzip (also zip and zlib) is a variation of +LZ77 (Lempel-Ziv 1977, see reference below). It finds duplicated strings in +the input data. The second occurrence of a string is replaced by a +pointer to the previous string, in the form of a pair (distance, +length). Distances are limited to 32K bytes, and lengths are limited +to 258 bytes. When a string does not occur anywhere in the previous +32K bytes, it is emitted as a sequence of literal bytes. (In this +description, `string' must be taken as an arbitrary sequence of bytes, +and is not restricted to printable characters.) + +Literals or match lengths are compressed with one Huffman tree, and +match distances are compressed with another tree. The trees are stored +in a compact form at the start of each block. The blocks can have any +size (except that the compressed data for one block must fit in +available memory). A block is terminated when deflate() determines that +it would be useful to start another block with fresh trees. (This is +somewhat similar to the behavior of LZW-based _compress_.) + +Duplicated strings are found using a hash table. All input strings of +length 3 are inserted in the hash table. A hash index is computed for +the next 3 bytes. If the hash chain for this index is not empty, all +strings in the chain are compared with the current input string, and +the longest match is selected. + +The hash chains are searched starting with the most recent strings, to +favor small distances and thus take advantage of the Huffman encoding. +The hash chains are singly linked. There are no deletions from the +hash chains, the algorithm simply discards matches that are too old. + +To avoid a worst-case situation, very long hash chains are arbitrarily +truncated at a certain length, determined by a runtime option (level +parameter of deflateInit). So deflate() does not always find the longest +possible match but generally finds a match which is long enough. + +deflate() also defers the selection of matches with a lazy evaluation +mechanism. After a match of length N has been found, deflate() searches for +a longer match at the next input byte. If a longer match is found, the +previous match is truncated to a length of one (thus producing a single +literal byte) and the process of lazy evaluation begins again. Otherwise, +the original match is kept, and the next match search is attempted only N +steps later. + +The lazy match evaluation is also subject to a runtime parameter. If +the current match is long enough, deflate() reduces the search for a longer +match, thus speeding up the whole process. If compression ratio is more +important than speed, deflate() attempts a complete second search even if +the first match is already long enough. + +The lazy match evaluation is not performed for the fastest compression +modes (level parameter 1 to 3). For these fast modes, new strings +are inserted in the hash table only when no match was found, or +when the match is not too long. This degrades the compression ratio +but saves time since there are both fewer insertions and fewer searches. + + +2. Decompression algorithm (inflate) + +2.1 Introduction + +The key question is how to represent a Huffman code (or any prefix code) so +that you can decode fast. The most important characteristic is that shorter +codes are much more common than longer codes, so pay attention to decoding the +short codes fast, and let the long codes take longer to decode. + +inflate() sets up a first level table that covers some number of bits of +input less than the length of longest code. It gets that many bits from the +stream, and looks it up in the table. The table will tell if the next +code is that many bits or less and how many, and if it is, it will tell +the value, else it will point to the next level table for which inflate() +grabs more bits and tries to decode a longer code. + +How many bits to make the first lookup is a tradeoff between the time it +takes to decode and the time it takes to build the table. If building the +table took no time (and if you had infinite memory), then there would only +be a first level table to cover all the way to the longest code. However, +building the table ends up taking a lot longer for more bits since short +codes are replicated many times in such a table. What inflate() does is +simply to make the number of bits in the first table a variable, and then +to set that variable for the maximum speed. + +For inflate, which has 286 possible codes for the literal/length tree, the size +of the first table is nine bits. Also the distance trees have 30 possible +values, and the size of the first table is six bits. Note that for each of +those cases, the table ended up one bit longer than the ``average'' code +length, i.e. the code length of an approximately flat code which would be a +little more than eight bits for 286 symbols and a little less than five bits +for 30 symbols. + + +2.2 More details on the inflate table lookup + +Ok, you want to know what this cleverly obfuscated inflate tree actually +looks like. You are correct that it's not a Huffman tree. It is simply a +lookup table for the first, let's say, nine bits of a Huffman symbol. The +symbol could be as short as one bit or as long as 15 bits. If a particular +symbol is shorter than nine bits, then that symbol's translation is duplicated +in all those entries that start with that symbol's bits. For example, if the +symbol is four bits, then it's duplicated 32 times in a nine-bit table. If a +symbol is nine bits long, it appears in the table once. + +If the symbol is longer than nine bits, then that entry in the table points +to another similar table for the remaining bits. Again, there are duplicated +entries as needed. The idea is that most of the time the symbol will be short +and there will only be one table look up. (That's whole idea behind data +compression in the first place.) For the less frequent long symbols, there +will be two lookups. If you had a compression method with really long +symbols, you could have as many levels of lookups as is efficient. For +inflate, two is enough. + +So a table entry either points to another table (in which case nine bits in +the above example are gobbled), or it contains the translation for the symbol +and the number of bits to gobble. Then you start again with the next +ungobbled bit. + +You may wonder: why not just have one lookup table for how ever many bits the +longest symbol is? The reason is that if you do that, you end up spending +more time filling in duplicate symbol entries than you do actually decoding. +At least for deflate's output that generates new trees every several 10's of +kbytes. You can imagine that filling in a 2^15 entry table for a 15-bit code +would take too long if you're only decoding several thousand symbols. At the +other extreme, you could make a new table for every bit in the code. In fact, +that's essentially a Huffman tree. But then you spend two much time +traversing the tree while decoding, even for short symbols. + +So the number of bits for the first lookup table is a trade of the time to +fill out the table vs. the time spent looking at the second level and above of +the table. + +Here is an example, scaled down: + +The code being decoded, with 10 symbols, from 1 to 6 bits long: + +A: 0 +B: 10 +C: 1100 +D: 11010 +E: 11011 +F: 11100 +G: 11101 +H: 11110 +I: 111110 +J: 111111 + +Let's make the first table three bits long (eight entries): + +000: A,1 +001: A,1 +010: A,1 +011: A,1 +100: B,2 +101: B,2 +110: -> table X (gobble 3 bits) +111: -> table Y (gobble 3 bits) + +Each entry is what the bits decode as and how many bits that is, i.e. how +many bits to gobble. Or the entry points to another table, with the number of +bits to gobble implicit in the size of the table. + +Table X is two bits long since the longest code starting with 110 is five bits +long: + +00: C,1 +01: C,1 +10: D,2 +11: E,2 + +Table Y is three bits long since the longest code starting with 111 is six +bits long: + +000: F,2 +001: F,2 +010: G,2 +011: G,2 +100: H,2 +101: H,2 +110: I,3 +111: J,3 + +So what we have here are three tables with a total of 20 entries that had to +be constructed. That's compared to 64 entries for a single table. Or +compared to 16 entries for a Huffman tree (six two entry tables and one four +entry table). Assuming that the code ideally represents the probability of +the symbols, it takes on the average 1.25 lookups per symbol. That's compared +to one lookup for the single table, or 1.66 lookups per symbol for the +Huffman tree. + +There, I think that gives you a picture of what's going on. For inflate, the +meaning of a particular symbol is often more than just a letter. It can be a +byte (a "literal"), or it can be either a length or a distance which +indicates a base value and a number of bits to fetch after the code that is +added to the base value. Or it might be the special end-of-block code. The +data structures created in inftrees.c try to encode all that information +compactly in the tables. + + +Jean-loup Gailly Mark Adler +jloup@gzip.org madler@alumni.caltech.edu + + +References: + +[LZ77] Ziv J., Lempel A., ``A Universal Algorithm for Sequential Data +Compression,'' IEEE Transactions on Information Theory, Vol. 23, No. 3, +pp. 337-343. + +``DEFLATE Compressed Data Format Specification'' available in +http://www.ietf.org/rfc/rfc1951.txt diff --git a/gdcm/Utilities/gdcmzlib/compress.c b/gdcm/Utilities/gdcmzlib/compress.c new file mode 100644 index 0000000..df04f01 --- /dev/null +++ b/gdcm/Utilities/gdcmzlib/compress.c @@ -0,0 +1,79 @@ +/* compress.c -- compress a memory buffer + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least 0.1% larger than sourceLen plus + 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ +int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; + int level; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; +#ifdef MAXSEG_64K + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; +#endif + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + stream.opaque = (voidpf)0; + + err = deflateInit(&stream, level); + if (err != Z_OK) return err; + + err = deflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + deflateEnd(&stream); + return err == Z_OK ? Z_BUF_ERROR : err; + } + *destLen = stream.total_out; + + err = deflateEnd(&stream); + return err; +} + +/* =========================================================================== + */ +int ZEXPORT compress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); +} + +/* =========================================================================== + If the default memLevel or windowBits for deflateInit() is changed, then + this function needs to be updated. + */ +uLong ZEXPORT compressBound (sourceLen) + uLong sourceLen; +{ + return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + 11; +} diff --git a/gdcm/Utilities/gdcmzlib/crc32.c b/gdcm/Utilities/gdcmzlib/crc32.c new file mode 100644 index 0000000..f658a9e --- /dev/null +++ b/gdcm/Utilities/gdcmzlib/crc32.c @@ -0,0 +1,423 @@ +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Thanks to Rodney Brown for his contribution of faster + * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing + * tables for updating the shift register in one step with three exclusive-ors + * instead of four steps with four exclusive-ors. This results in about a + * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. + */ + +/* @(#) $Id$ */ + +/* + Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore + protection on the static variables used to control the first-use generation + of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should + first call get_crc_table() to initialize the tables before allowing more than + one thread to use crc32(). + */ + +#ifdef MAKECRCH +# include +# ifndef DYNAMIC_CRC_TABLE +# define DYNAMIC_CRC_TABLE +# endif /* !DYNAMIC_CRC_TABLE */ +#endif /* MAKECRCH */ + +#include "zutil.h" /* for STDC and FAR definitions */ + +#define local static + +/* Find a four-byte integer type for crc32_little() and crc32_big(). */ +#ifndef NOBYFOUR +# ifdef STDC /* need ANSI C limits.h to determine sizes */ +# include +# define BYFOUR +# if (UINT_MAX == 0xffffffffUL) + typedef unsigned int u4; +# else +# if (ULONG_MAX == 0xffffffffUL) + typedef unsigned long u4; +# else +# if (USHRT_MAX == 0xffffffffUL) + typedef unsigned short u4; +# else +# undef BYFOUR /* can't find a four-byte integer type! */ +# endif +# endif +# endif +# endif /* STDC */ +#endif /* !NOBYFOUR */ + +/* Definitions for doing the crc four data bytes at a time. */ +#ifdef BYFOUR +# define REV(w) (((w)>>24)+(((w)>>8)&0xff00)+ \ + (((w)&0xff00)<<8)+(((w)&0xff)<<24)) + local unsigned long crc32_little OF((unsigned long, + const unsigned char FAR *, unsigned)); + local unsigned long crc32_big OF((unsigned long, + const unsigned char FAR *, unsigned)); +# define TBLS 8 +#else +# define TBLS 1 +#endif /* BYFOUR */ + +/* Local functions for crc concatenation */ +local unsigned long gf2_matrix_times OF((unsigned long *mat, + unsigned long vec)); +local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat)); + +#ifdef DYNAMIC_CRC_TABLE + +local volatile int crc_table_empty = 1; +local unsigned long FAR crc_table[TBLS][256]; +local void make_crc_table OF((void)); +#ifdef MAKECRCH + local void write_table OF((FILE *, const unsigned long FAR *)); +#endif /* MAKECRCH */ +/* + Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: + x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. + + Polynomials over GF(2) are represented in binary, one bit per coefficient, + with the lowest powers in the most significant bit. Then adding polynomials + is just exclusive-or, and multiplying a polynomial by x is a right shift by + one. If we call the above polynomial p, and represent a byte as the + polynomial q, also with the lowest power in the most significant bit (so the + byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, + where a mod b means the remainder after dividing a by b. + + This calculation is done using the shift-register method of multiplying and + taking the remainder. The register is initialized to zero, and for each + incoming bit, x^32 is added mod p to the register if the bit is a one (where + x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by + x (which is shifting right by one and adding x^32 mod p if the bit shifted + out is a one). We start with the highest power (least significant bit) of + q and repeat for all eight bits of q. + + The first table is simply the CRC of all possible eight bit values. This is + all the information needed to generate CRCs on data a byte at a time for all + combinations of CRC register values and incoming bytes. The remaining tables + allow for word-at-a-time CRC calculation for both big-endian and little- + endian machines, where a word is four bytes. +*/ +local void make_crc_table() +{ + unsigned long c; + int n, k; + unsigned long poly; /* polynomial exclusive-or pattern */ + /* terms of polynomial defining this crc (except x^32): */ + static volatile int first = 1; /* flag to limit concurrent making */ + static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + + /* See if another task is already doing this (not thread-safe, but better + than nothing -- significantly reduces duration of vulnerability in + case the advice about DYNAMIC_CRC_TABLE is ignored) */ + if (first) { + first = 0; + + /* make exclusive-or pattern from polynomial (0xedb88320UL) */ + poly = 0UL; + for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++) + poly |= 1UL << (31 - p[n]); + + /* generate a crc for every 8-bit value */ + for (n = 0; n < 256; n++) { + c = (unsigned long)n; + for (k = 0; k < 8; k++) + c = c & 1 ? poly ^ (c >> 1) : c >> 1; + crc_table[0][n] = c; + } + +#ifdef BYFOUR + /* generate crc for each value followed by one, two, and three zeros, + and then the byte reversal of those as well as the first table */ + for (n = 0; n < 256; n++) { + c = crc_table[0][n]; + crc_table[4][n] = REV(c); + for (k = 1; k < 4; k++) { + c = crc_table[0][c & 0xff] ^ (c >> 8); + crc_table[k][n] = c; + crc_table[k + 4][n] = REV(c); + } + } +#endif /* BYFOUR */ + + crc_table_empty = 0; + } + else { /* not first */ + /* wait for the other guy to finish (not efficient, but rare) */ + while (crc_table_empty) + ; + } + +#ifdef MAKECRCH + /* write out CRC tables to crc32.h */ + { + FILE *out; + + out = fopen("crc32.h", "w"); + if (out == NULL) return; + fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); + fprintf(out, " * Generated automatically by crc32.c\n */\n\n"); + fprintf(out, "local const unsigned long FAR "); + fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); + write_table(out, crc_table[0]); +# ifdef BYFOUR + fprintf(out, "#ifdef BYFOUR\n"); + for (k = 1; k < 8; k++) { + fprintf(out, " },\n {\n"); + write_table(out, crc_table[k]); + } + fprintf(out, "#endif\n"); +# endif /* BYFOUR */ + fprintf(out, " }\n};\n"); + fclose(out); + } +#endif /* MAKECRCH */ +} + +#ifdef MAKECRCH +local void write_table(out, table) + FILE *out; + const unsigned long FAR *table; +{ + int n; + + for (n = 0; n < 256; n++) + fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", table[n], + n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); +} +#endif /* MAKECRCH */ + +#else /* !DYNAMIC_CRC_TABLE */ +/* ======================================================================== + * Tables of CRC-32s of all single-byte values, made by make_crc_table(). + */ +#include "crc32.h" +#endif /* DYNAMIC_CRC_TABLE */ + +/* ========================================================================= + * This function can be used by asm versions of crc32() + */ +const unsigned long FAR * ZEXPORT get_crc_table() +{ +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + return (const unsigned long FAR *)crc_table; +} + +/* ========================================================================= */ +#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8) +#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 + +/* ========================================================================= */ +unsigned long ZEXPORT crc32(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + if (buf == Z_NULL) return 0UL; + +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + +#ifdef BYFOUR + if (sizeof(void *) == sizeof(ptrdiff_t)) { + u4 endian; + + endian = 1; + if (*((unsigned char *)(&endian))) + return crc32_little(crc, buf, len); + else + return crc32_big(crc, buf, len); + } +#endif /* BYFOUR */ + crc = crc ^ 0xffffffffUL; + while (len >= 8) { + DO8; + len -= 8; + } + if (len) do { + DO1; + } while (--len); + return crc ^ 0xffffffffUL; +} + +#ifdef BYFOUR + +/* ========================================================================= */ +#define DOLIT4 c ^= *buf4++; \ + c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ + crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] +#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 + +/* ========================================================================= */ +local unsigned long crc32_little(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register u4 c; + register const u4 FAR *buf4; + + c = (u4)crc; + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + len--; + } + + buf4 = (const u4 FAR *)(const void FAR *)buf; + while (len >= 32) { + DOLIT32; + len -= 32; + } + while (len >= 4) { + DOLIT4; + len -= 4; + } + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + } while (--len); + c = ~c; + return (unsigned long)c; +} + +/* ========================================================================= */ +#define DOBIG4 c ^= *++buf4; \ + c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ + crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] +#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 + +/* ========================================================================= */ +local unsigned long crc32_big(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register u4 c; + register const u4 FAR *buf4; + + c = REV((u4)crc); + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + len--; + } + + buf4 = (const u4 FAR *)(const void FAR *)buf; + buf4--; + while (len >= 32) { + DOBIG32; + len -= 32; + } + while (len >= 4) { + DOBIG4; + len -= 4; + } + buf4++; + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + } while (--len); + c = ~c; + return (unsigned long)(REV(c)); +} + +#endif /* BYFOUR */ + +#define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */ + +/* ========================================================================= */ +local unsigned long gf2_matrix_times(mat, vec) + unsigned long *mat; + unsigned long vec; +{ + unsigned long sum; + + sum = 0; + while (vec) { + if (vec & 1) + sum ^= *mat; + vec >>= 1; + mat++; + } + return sum; +} + +/* ========================================================================= */ +local void gf2_matrix_square(square, mat) + unsigned long *square; + unsigned long *mat; +{ + int n; + + for (n = 0; n < GF2_DIM; n++) + square[n] = gf2_matrix_times(mat, mat[n]); +} + +/* ========================================================================= */ +uLong ZEXPORT crc32_combine(crc1, crc2, len2) + uLong crc1; + uLong crc2; + z_off_t len2; +{ + int n; + unsigned long row; + unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */ + unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */ + + /* degenerate case */ + if (len2 == 0) + return crc1; + + /* put operator for one zero bit in odd */ + odd[0] = 0xedb88320L; /* CRC-32 polynomial */ + row = 1; + for (n = 1; n < GF2_DIM; n++) { + odd[n] = row; + row <<= 1; + } + + /* put operator for two zero bits in even */ + gf2_matrix_square(even, odd); + + /* put operator for four zero bits in odd */ + gf2_matrix_square(odd, even); + + /* apply len2 zeros to crc1 (first square will put the operator for one + zero byte, eight zero bits, in even) */ + do { + /* apply zeros operator for this bit of len2 */ + gf2_matrix_square(even, odd); + if (len2 & 1) + crc1 = gf2_matrix_times(even, crc1); + len2 >>= 1; + + /* if no more bits set, then done */ + if (len2 == 0) + break; + + /* another iteration of the loop with odd and even swapped */ + gf2_matrix_square(odd, even); + if (len2 & 1) + crc1 = gf2_matrix_times(odd, crc1); + len2 >>= 1; + + /* if no more bits set, then done */ + } while (len2 != 0); + + /* return combined crc */ + crc1 ^= crc2; + return crc1; +} diff --git a/gdcm/Utilities/gdcmzlib/crc32.h b/gdcm/Utilities/gdcmzlib/crc32.h new file mode 100644 index 0000000..8053b61 --- /dev/null +++ b/gdcm/Utilities/gdcmzlib/crc32.h @@ -0,0 +1,441 @@ +/* crc32.h -- tables for rapid CRC calculation + * Generated automatically by crc32.c + */ + +local const unsigned long FAR crc_table[TBLS][256] = +{ + { + 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, + 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, + 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, + 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, + 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, + 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, + 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, + 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, + 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, + 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, + 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, + 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, + 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, + 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, + 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, + 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, + 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, + 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, + 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, + 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, + 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, + 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, + 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, + 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, + 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, + 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, + 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, + 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, + 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, + 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, + 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, + 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, + 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, + 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, + 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, + 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, + 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, + 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, + 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, + 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, + 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, + 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, + 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, + 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, + 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, + 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, + 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, + 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, + 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, + 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, + 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, + 0x2d02ef8dUL +#ifdef BYFOUR + }, + { + 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, + 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, + 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, + 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, + 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, + 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, + 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, + 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, + 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, + 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, + 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, + 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, + 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, + 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, + 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, + 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, + 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, + 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, + 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, + 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, + 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, + 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, + 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, + 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, + 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, + 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, + 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, + 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, + 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, + 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, + 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, + 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, + 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, + 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, + 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, + 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, + 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, + 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, + 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, + 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, + 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, + 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, + 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, + 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, + 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, + 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, + 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, + 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, + 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, + 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, + 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, + 0x9324fd72UL + }, + { + 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, + 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, + 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, + 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, + 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, + 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, + 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, + 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, + 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, + 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, + 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, + 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, + 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, + 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, + 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, + 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, + 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, + 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, + 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, + 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, + 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, + 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, + 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, + 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, + 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, + 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, + 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, + 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, + 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, + 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, + 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, + 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, + 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, + 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, + 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, + 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, + 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, + 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, + 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, + 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, + 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, + 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, + 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, + 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, + 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, + 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, + 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, + 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, + 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, + 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, + 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, + 0xbe9834edUL + }, + { + 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, + 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, + 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, + 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, + 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, + 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, + 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, + 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, + 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, + 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, + 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, + 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, + 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, + 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, + 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, + 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, + 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, + 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, + 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, + 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, + 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, + 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, + 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, + 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, + 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, + 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, + 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, + 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, + 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, + 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, + 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, + 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, + 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, + 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, + 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, + 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, + 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, + 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, + 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, + 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, + 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, + 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, + 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, + 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, + 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, + 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, + 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, + 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, + 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, + 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, + 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, + 0xde0506f1UL + }, + { + 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, + 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, + 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, + 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, + 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, + 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, + 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, + 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, + 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, + 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, + 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, + 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, + 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, + 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, + 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, + 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, + 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, + 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, + 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, + 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, + 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, + 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, + 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, + 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, + 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, + 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, + 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, + 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, + 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, + 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, + 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, + 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, + 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, + 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, + 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, + 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, + 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, + 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, + 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, + 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, + 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, + 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, + 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, + 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, + 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, + 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, + 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, + 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, + 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, + 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, + 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, + 0x8def022dUL + }, + { + 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, + 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, + 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, + 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, + 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, + 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, + 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, + 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, + 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, + 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, + 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, + 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, + 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, + 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, + 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, + 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, + 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, + 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, + 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, + 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, + 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, + 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, + 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, + 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, + 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, + 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, + 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, + 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, + 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, + 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, + 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, + 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, + 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, + 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, + 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, + 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, + 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, + 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, + 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, + 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, + 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, + 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, + 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, + 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, + 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, + 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, + 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, + 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, + 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, + 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, + 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, + 0x72fd2493UL + }, + { + 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, + 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, + 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, + 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, + 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, + 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, + 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, + 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, + 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, + 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, + 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, + 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, + 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, + 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, + 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, + 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, + 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, + 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, + 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, + 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, + 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, + 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, + 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, + 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, + 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, + 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, + 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, + 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, + 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, + 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, + 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, + 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, + 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, + 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, + 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, + 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, + 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, + 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, + 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, + 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, + 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, + 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, + 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, + 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, + 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, + 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, + 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, + 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, + 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, + 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, + 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, + 0xed3498beUL + }, + { + 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, + 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, + 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, + 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, + 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, + 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, + 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, + 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, + 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, + 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, + 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, + 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, + 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, + 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, + 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, + 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, + 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, + 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, + 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, + 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, + 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, + 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, + 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, + 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, + 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, + 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, + 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, + 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, + 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, + 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, + 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, + 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, + 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, + 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, + 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, + 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, + 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, + 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, + 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, + 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, + 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, + 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, + 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, + 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, + 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, + 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, + 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, + 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, + 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, + 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, + 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, + 0xf10605deUL +#endif + } +}; diff --git a/gdcm/Utilities/gdcmzlib/deflate.c b/gdcm/Utilities/gdcmzlib/deflate.c new file mode 100644 index 0000000..29ce1f6 --- /dev/null +++ b/gdcm/Utilities/gdcmzlib/deflate.c @@ -0,0 +1,1736 @@ +/* deflate.c -- compress data using the deflation algorithm + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process depends on being able to identify portions + * of the input text which are identical to earlier input (within a + * sliding window trailing behind the input currently being processed). + * + * The most straightforward technique turns out to be the fastest for + * most input files: try all possible matches and select the longest. + * The key feature of this algorithm is that insertions into the string + * dictionary are very simple and thus fast, and deletions are avoided + * completely. Insertions are performed at each input character, whereas + * string matches are performed only when the previous match ends. So it + * is preferable to spend more time in matches to allow very fast string + * insertions and avoid deletions. The matching algorithm for small + * strings is inspired from that of Rabin & Karp. A brute force approach + * is used to find longer strings when a small match has been found. + * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze + * (by Leonid Broukhis). + * A previous version of this file used a more sophisticated algorithm + * (by Fiala and Greene) which is guaranteed to run in linear amortized + * time, but has a larger average cost, uses more memory and is patented. + * However the F&G algorithm may be faster for some highly redundant + * files if the parameter max_chain_length (described below) is too large. + * + * ACKNOWLEDGEMENTS + * + * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and + * I found it in 'freeze' written by Leonid Broukhis. + * Thanks to many people for bug reports and testing. + * + * REFERENCES + * + * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". + * Available in http://www.ietf.org/rfc/rfc1951.txt + * + * A description of the Rabin and Karp algorithm is given in the book + * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. + * + * Fiala,E.R., and Greene,D.H. + * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 + * + */ + +/* @(#) $Id$ */ + +#include "deflate.h" + +const char deflate_copyright[] = + " deflate 1.2.3 Copyright 1995-2005 Jean-loup Gailly "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* =========================================================================== + * Function prototypes. + */ +typedef enum { + need_more, /* block not completed, need more input or more output */ + block_done, /* block flush performed */ + finish_started, /* finish started, need only more output at next deflate */ + finish_done /* finish done, accept no more input or output */ +} block_state; + +typedef block_state (*compress_func) OF((deflate_state *s, int flush)); +/* Compression function. Returns the block state after the call. */ + +local void fill_window OF((deflate_state *s)); +local block_state deflate_stored OF((deflate_state *s, int flush)); +local block_state deflate_fast OF((deflate_state *s, int flush)); +#ifndef FASTEST +local block_state deflate_slow OF((deflate_state *s, int flush)); +#endif +local void lm_init OF((deflate_state *s)); +local void putShortMSB OF((deflate_state *s, uInt b)); +local void flush_pending OF((z_streamp strm)); +local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); +#ifndef FASTEST +#ifdef ASMV + void match_init OF((void)); /* asm code initialization */ + uInt longest_match OF((deflate_state *s, IPos cur_match)); +#else +local uInt longest_match OF((deflate_state *s, IPos cur_match)); +#endif +#endif +local uInt longest_match_fast OF((deflate_state *s, IPos cur_match)); + +#ifdef DEBUG +local void check_match OF((deflate_state *s, IPos start, IPos match, + int length)); +#endif + +/* =========================================================================== + * Local data + */ + +#define NIL 0 +/* Tail of hash chains */ + +#ifndef TOO_FAR +# define TOO_FAR 4096 +#endif +/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +/* Values for max_lazy_match, good_match and max_chain_length, depending on + * the desired pack level (0..9). The values given below have been tuned to + * exclude worst case performance for pathological files. Better values may be + * found for specific files. + */ +typedef struct config_s { + ush good_length; /* reduce lazy search above this match length */ + ush max_lazy; /* do not perform lazy search above this match length */ + ush nice_length; /* quit search above this match length */ + ush max_chain; + compress_func func; +} config; + +#ifdef FASTEST +local const config configuration_table[2] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */ +#else +local const config configuration_table[10] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ +/* 2 */ {4, 5, 16, 8, deflate_fast}, +/* 3 */ {4, 6, 32, 32, deflate_fast}, + +/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ +/* 5 */ {8, 16, 32, 32, deflate_slow}, +/* 6 */ {8, 16, 128, 128, deflate_slow}, +/* 7 */ {8, 32, 128, 256, deflate_slow}, +/* 8 */ {32, 128, 258, 1024, deflate_slow}, +/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ +#endif + +/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 + * For deflate_fast() (levels <= 3) good is ignored and lazy has a different + * meaning. + */ + +#define EQUAL 0 +/* result of memcmp for equal strings */ + +#ifndef NO_DUMMY_DECL +struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ +#endif + +/* =========================================================================== + * Update a hash value with the given input byte + * IN assertion: all calls to to UPDATE_HASH are made with consecutive + * input characters, so that a running hash key can be computed from the + * previous key instead of complete recalculation each time. + */ +#define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) + + +/* =========================================================================== + * Insert string str in the dictionary and set match_head to the previous head + * of the hash chain (the most recent string with same hash key). Return + * the previous length of the hash chain. + * If this file is compiled with -DFASTEST, the compression level is forced + * to 1, and no hash chains are maintained. + * IN assertion: all calls to to INSERT_STRING are made with consecutive + * input characters and the first MIN_MATCH bytes of str are valid + * (except for the last MIN_MATCH-1 bytes of the input file). + */ +#ifdef FASTEST +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#else +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#endif + +/* =========================================================================== + * Initialize the hash table (avoiding 64K overflow for 16 bit systems). + * prev[] will be initialized on the fly. + */ +#define CLEAR_HASH(s) \ + s->head[s->hash_size-1] = NIL; \ + zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); + +/* ========================================================================= */ +int ZEXPORT deflateInit_(strm, level, version, stream_size) + z_streamp strm; + int level; + const char *version; + int stream_size; +{ + return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY, version, stream_size); + /* To do: ignore strm->next_in if we use it as window */ +} + +/* ========================================================================= */ +int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, + version, stream_size) + z_streamp strm; + int level; + int method; + int windowBits; + int memLevel; + int strategy; + const char *version; + int stream_size; +{ + deflate_state *s; + int wrap = 1; + static const char my_version[] = ZLIB_VERSION; + + ushf *overlay; + /* We overlay pending_buf and d_buf+l_buf. This works since the average + * output size for (length,distance) codes is <= 24 bits. + */ + + if (version == Z_NULL || version[0] != my_version[0] || + stream_size != sizeof(z_stream)) { + return Z_VERSION_ERROR; + } + if (strm == Z_NULL) return Z_STREAM_ERROR; + + strm->msg = Z_NULL; + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + + if (windowBits < 0) { /* suppress zlib wrapper */ + wrap = 0; + windowBits = -windowBits; + } +#ifdef GZIP + else if (windowBits > 15) { + wrap = 2; /* write gzip wrapper instead */ + windowBits -= 16; + } +#endif + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || + windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_FIXED) { + return Z_STREAM_ERROR; + } + if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ + s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); + if (s == Z_NULL) return Z_MEM_ERROR; + strm->state = (struct internal_state FAR *)s; + s->strm = strm; + + s->wrap = wrap; + s->gzhead = Z_NULL; + s->w_bits = windowBits; + s->w_size = 1 << s->w_bits; + s->w_mask = s->w_size - 1; + + s->hash_bits = memLevel + 7; + s->hash_size = 1 << s->hash_bits; + s->hash_mask = s->hash_size - 1; + s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); + + s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); + s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); + s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); + + s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ + + overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); + s->pending_buf = (uchf *) overlay; + s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); + + if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || + s->pending_buf == Z_NULL) { + s->status = FINISH_STATE; + strm->msg = (char*)ERR_MSG(Z_MEM_ERROR); + deflateEnd (strm); + return Z_MEM_ERROR; + } + s->d_buf = overlay + s->lit_bufsize/sizeof(ush); + s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; + + s->level = level; + s->strategy = strategy; + s->method = (Byte)method; + + return deflateReset(strm); +} + +/* ========================================================================= */ +int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) + z_streamp strm; + const Bytef *dictionary; + uInt dictLength; +{ + deflate_state *s; + uInt length = dictLength; + uInt n; + IPos hash_head = 0; + + if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL || + strm->state->wrap == 2 || + (strm->state->wrap == 1 && strm->state->status != INIT_STATE)) + return Z_STREAM_ERROR; + + s = strm->state; + if (s->wrap) + strm->adler = adler32(strm->adler, dictionary, dictLength); + + if (length < MIN_MATCH) return Z_OK; + if (length > MAX_DIST(s)) { + length = MAX_DIST(s); + dictionary += dictLength - length; /* use the tail of the dictionary */ + } + zmemcpy(s->window, dictionary, length); + s->strstart = length; + s->block_start = (long)length; + + /* Insert all strings in the hash table (except for the last two bytes). + * s->lookahead stays null, so s->ins_h will be recomputed at the next + * call of fill_window. + */ + s->ins_h = s->window[0]; + UPDATE_HASH(s, s->ins_h, s->window[1]); + for (n = 0; n <= length - MIN_MATCH; n++) { + INSERT_STRING(s, n, hash_head); + } + if (hash_head) hash_head = 0; /* to make compiler happy */ + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateReset (strm) + z_streamp strm; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) { + return Z_STREAM_ERROR; + } + + strm->total_in = strm->total_out = 0; + strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ + strm->data_type = Z_UNKNOWN; + + s = (deflate_state *)strm->state; + s->pending = 0; + s->pending_out = s->pending_buf; + + if (s->wrap < 0) { + s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ + } + s->status = s->wrap ? INIT_STATE : BUSY_STATE; + strm->adler = +#ifdef GZIP + s->wrap == 2 ? crc32(0L, Z_NULL, 0) : +#endif + adler32(0L, Z_NULL, 0); + s->last_flush = Z_NO_FLUSH; + + _tr_init(s); + lm_init(s); + + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateSetHeader (strm, head) + z_streamp strm; + gz_headerp head; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (strm->state->wrap != 2) return Z_STREAM_ERROR; + strm->state->gzhead = head; + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflatePrime (strm, bits, value) + z_streamp strm; + int bits; + int value; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + strm->state->bi_valid = bits; + strm->state->bi_buf = (ush)(value & ((1 << bits) - 1)); + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateParams(strm, level, strategy) + z_streamp strm; + int level; + int strategy; +{ + deflate_state *s; + compress_func func; + int err = Z_OK; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { + return Z_STREAM_ERROR; + } + func = configuration_table[s->level].func; + + if (func != configuration_table[level].func && strm->total_in != 0) { + /* Flush the last buffer: */ + err = deflate(strm, Z_PARTIAL_FLUSH); + } + if (s->level != level) { + s->level = level; + s->max_lazy_match = configuration_table[level].max_lazy; + s->good_match = configuration_table[level].good_length; + s->nice_match = configuration_table[level].nice_length; + s->max_chain_length = configuration_table[level].max_chain; + } + s->strategy = strategy; + return err; +} + +/* ========================================================================= */ +int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain) + z_streamp strm; + int good_length; + int max_lazy; + int nice_length; + int max_chain; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + s->good_match = good_length; + s->max_lazy_match = max_lazy; + s->nice_match = nice_length; + s->max_chain_length = max_chain; + return Z_OK; +} + +/* ========================================================================= + * For the default windowBits of 15 and memLevel of 8, this function returns + * a close to exact, as well as small, upper bound on the compressed size. + * They are coded as constants here for a reason--if the #define's are + * changed, then this function needs to be changed as well. The return + * value for 15 and 8 only works for those exact settings. + * + * For any setting other than those defaults for windowBits and memLevel, + * the value returned is a conservative worst case for the maximum expansion + * resulting from using fixed blocks instead of stored blocks, which deflate + * can emit on compressed data for some combinations of the parameters. + * + * This function could be more sophisticated to provide closer upper bounds + * for every combination of windowBits and memLevel, as well as wrap. + * But even the conservative upper bound of about 14% expansion does not + * seem onerous for output buffer allocation. + */ +uLong ZEXPORT deflateBound(strm, sourceLen) + z_streamp strm; + uLong sourceLen; +{ + deflate_state *s; + uLong destLen; + + /* conservative upper bound */ + destLen = sourceLen + + ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 11; + + /* if can't get parameters, return conservative bound */ + if (strm == Z_NULL || strm->state == Z_NULL) + return destLen; + + /* if not default parameters, return conservative bound */ + s = strm->state; + if (s->w_bits != 15 || s->hash_bits != 8 + 7) + return destLen; + + /* default settings: return tight bound for that case */ + return compressBound(sourceLen); +} + +/* ========================================================================= + * Put a short in the pending buffer. The 16-bit value is put in MSB order. + * IN assertion: the stream state is correct and there is enough room in + * pending_buf. + */ +local void putShortMSB (s, b) + deflate_state *s; + uInt b; +{ + put_byte(s, (Byte)(b >> 8)); + put_byte(s, (Byte)(b & 0xff)); +} + +/* ========================================================================= + * Flush as much pending output as possible. All deflate() output goes + * through this function so some applications may wish to modify it + * to avoid allocating a large strm->next_out buffer and copying into it. + * (See also read_buf()). + */ +local void flush_pending(strm) + z_streamp strm; +{ + unsigned len = strm->state->pending; + + if (len > strm->avail_out) len = strm->avail_out; + if (len == 0) return; + + zmemcpy(strm->next_out, strm->state->pending_out, len); + strm->next_out += len; + strm->state->pending_out += len; + strm->total_out += len; + strm->avail_out -= len; + strm->state->pending -= len; + if (strm->state->pending == 0) { + strm->state->pending_out = strm->state->pending_buf; + } +} + +/* ========================================================================= */ +int ZEXPORT deflate (strm, flush) + z_streamp strm; + int flush; +{ + int old_flush; /* value of flush param for previous deflate call */ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + flush > Z_FINISH || flush < 0) { + return Z_STREAM_ERROR; + } + s = strm->state; + + if (strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0) || + (s->status == FINISH_STATE && flush != Z_FINISH)) { + ERR_RETURN(strm, Z_STREAM_ERROR); + } + if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); + + s->strm = strm; /* just in case */ + old_flush = s->last_flush; + s->last_flush = flush; + + /* Write the header */ + if (s->status == INIT_STATE) { +#ifdef GZIP + if (s->wrap == 2) { + strm->adler = crc32(0L, Z_NULL, 0); + put_byte(s, 31); + put_byte(s, 139); + put_byte(s, 8); + if (s->gzhead == NULL) { + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, OS_CODE); + s->status = BUSY_STATE; + } + else { + put_byte(s, (s->gzhead->text ? 1 : 0) + + (s->gzhead->hcrc ? 2 : 0) + + (s->gzhead->extra == Z_NULL ? 0 : 4) + + (s->gzhead->name == Z_NULL ? 0 : 8) + + (s->gzhead->comment == Z_NULL ? 0 : 16) + ); + put_byte(s, (Byte)(s->gzhead->time & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff)); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, s->gzhead->os & 0xff); + if (s->gzhead->extra != NULL) { + put_byte(s, s->gzhead->extra_len & 0xff); + put_byte(s, (s->gzhead->extra_len >> 8) & 0xff); + } + if (s->gzhead->hcrc) + strm->adler = crc32(strm->adler, s->pending_buf, + s->pending); + s->gzindex = 0; + s->status = EXTRA_STATE; + } + } + else +#endif + { + uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; + uInt level_flags; + + if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) + level_flags = 0; + else if (s->level < 6) + level_flags = 1; + else if (s->level == 6) + level_flags = 2; + else + level_flags = 3; + header |= (level_flags << 6); + if (s->strstart != 0) header |= PRESET_DICT; + header += 31 - (header % 31); + + s->status = BUSY_STATE; + putShortMSB(s, header); + + /* Save the adler32 of the preset dictionary: */ + if (s->strstart != 0) { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + strm->adler = adler32(0L, Z_NULL, 0); + } + } +#ifdef GZIP + if (s->status == EXTRA_STATE) { + if (s->gzhead->extra != NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + + while (s->gzindex < (s->gzhead->extra_len & 0xffff)) { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) + break; + } + put_byte(s, s->gzhead->extra[s->gzindex]); + s->gzindex++; + } + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (s->gzindex == s->gzhead->extra_len) { + s->gzindex = 0; + s->status = NAME_STATE; + } + } + else + s->status = NAME_STATE; + } + if (s->status == NAME_STATE) { + if (s->gzhead->name != NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + int val; + + do { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) { + val = 1; + break; + } + } + val = s->gzhead->name[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (val == 0) { + s->gzindex = 0; + s->status = COMMENT_STATE; + } + } + else + s->status = COMMENT_STATE; + } + if (s->status == COMMENT_STATE) { + if (s->gzhead->comment != NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + int val; + + do { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) { + val = 1; + break; + } + } + val = s->gzhead->comment[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (val == 0) + s->status = HCRC_STATE; + } + else + s->status = HCRC_STATE; + } + if (s->status == HCRC_STATE) { + if (s->gzhead->hcrc) { + if (s->pending + 2 > s->pending_buf_size) + flush_pending(strm); + if (s->pending + 2 <= s->pending_buf_size) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + strm->adler = crc32(0L, Z_NULL, 0); + s->status = BUSY_STATE; + } + } + else + s->status = BUSY_STATE; + } +#endif + + /* Flush as much pending output as possible */ + if (s->pending != 0) { + flush_pending(strm); + if (strm->avail_out == 0) { + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: + */ + s->last_flush = -1; + return Z_OK; + } + + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Z_FINISH, we keep + * returning Z_STREAM_END instead of Z_BUF_ERROR. + */ + } else if (strm->avail_in == 0 && flush <= old_flush && + flush != Z_FINISH) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* User must not provide more input after the first FINISH: */ + if (s->status == FINISH_STATE && strm->avail_in != 0) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* Start a new block or continue the current one. + */ + if (strm->avail_in != 0 || s->lookahead != 0 || + (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { + block_state bstate; + + bstate = (*(configuration_table[s->level].func))(s, flush); + + if (bstate == finish_started || bstate == finish_done) { + s->status = FINISH_STATE; + } + if (bstate == need_more || bstate == finish_started) { + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ + } + return Z_OK; + /* If flush != Z_NO_FLUSH && avail_out == 0, the next call + * of deflate should use the same flush parameter to make sure + * that the flush is complete. So we don't have to output an + * empty block here, this will be done at next call. This also + * ensures that for a very small output buffer, we emit at most + * one empty block. + */ + } + if (bstate == block_done) { + if (flush == Z_PARTIAL_FLUSH) { + _tr_align(s); + } else { /* FULL_FLUSH or SYNC_FLUSH */ + _tr_stored_block(s, (char*)0, 0L, 0); + /* For a full flush, this empty block will be recognized + * as a special marker by inflate_sync(). + */ + if (flush == Z_FULL_FLUSH) { + CLEAR_HASH(s); /* forget history */ + } + } + flush_pending(strm); + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ + return Z_OK; + } + } + } + Assert(strm->avail_out > 0, "bug2"); + + if (flush != Z_FINISH) return Z_OK; + if (s->wrap <= 0) return Z_STREAM_END; + + /* Write the trailer */ +#ifdef GZIP + if (s->wrap == 2) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 16) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 24) & 0xff)); + put_byte(s, (Byte)(strm->total_in & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 8) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 16) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 24) & 0xff)); + } + else +#endif + { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + flush_pending(strm); + /* If avail_out is zero, the application will call deflate again + * to flush the rest. + */ + if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ + return s->pending != 0 ? Z_OK : Z_STREAM_END; +} + +/* ========================================================================= */ +int ZEXPORT deflateEnd (strm) + z_streamp strm; +{ + int status; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + + status = strm->state->status; + if (status != INIT_STATE && + status != EXTRA_STATE && + status != NAME_STATE && + status != COMMENT_STATE && + status != HCRC_STATE && + status != BUSY_STATE && + status != FINISH_STATE) { + return Z_STREAM_ERROR; + } + + /* Deallocate in reverse order of allocations: */ + TRY_FREE(strm, strm->state->pending_buf); + TRY_FREE(strm, strm->state->head); + TRY_FREE(strm, strm->state->prev); + TRY_FREE(strm, strm->state->window); + + ZFREE(strm, strm->state); + strm->state = Z_NULL; + + return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; +} + +/* ========================================================================= + * Copy the source state to the destination state. + * To simplify the source, this is not supported for 16-bit MSDOS (which + * doesn't have enough memory anyway to duplicate compression states). + */ +int ZEXPORT deflateCopy (dest, source) + z_streamp dest; + z_streamp source; +{ +#ifdef MAXSEG_64K + return Z_STREAM_ERROR; +#else + deflate_state *ds; + deflate_state *ss; + ushf *overlay; + + + if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) { + return Z_STREAM_ERROR; + } + + ss = source->state; + + zmemcpy(dest, source, sizeof(z_stream)); + + ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); + if (ds == Z_NULL) return Z_MEM_ERROR; + dest->state = (struct internal_state FAR *) ds; + zmemcpy(ds, ss, sizeof(deflate_state)); + ds->strm = dest; + + ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); + ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); + ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); + overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); + ds->pending_buf = (uchf *) overlay; + + if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || + ds->pending_buf == Z_NULL) { + deflateEnd (dest); + return Z_MEM_ERROR; + } + /* following zmemcpy do not work for 16-bit MSDOS */ + zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); + zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos)); + zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos)); + zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); + + ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); + ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); + ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; + + ds->l_desc.dyn_tree = ds->dyn_ltree; + ds->d_desc.dyn_tree = ds->dyn_dtree; + ds->bl_desc.dyn_tree = ds->bl_tree; + + return Z_OK; +#endif /* MAXSEG_64K */ +} + +/* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->next_in buffer and copying from it. + * (See also flush_pending()). + */ +local int read_buf(strm, buf, size) + z_streamp strm; + Bytef *buf; + unsigned size; +{ + unsigned len = strm->avail_in; + + if (len > size) len = size; + if (len == 0) return 0; + + strm->avail_in -= len; + + if (strm->state->wrap == 1) { + strm->adler = adler32(strm->adler, strm->next_in, len); + } +#ifdef GZIP + else if (strm->state->wrap == 2) { + strm->adler = crc32(strm->adler, strm->next_in, len); + } +#endif + zmemcpy(buf, strm->next_in, len); + strm->next_in += len; + strm->total_in += len; + + return (int)len; +} + +/* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ +local void lm_init (s) + deflate_state *s; +{ + s->window_size = (ulg)2L*s->w_size; + + CLEAR_HASH(s); + + /* Set the default configuration parameters: + */ + s->max_lazy_match = configuration_table[s->level].max_lazy; + s->good_match = configuration_table[s->level].good_length; + s->nice_match = configuration_table[s->level].nice_length; + s->max_chain_length = configuration_table[s->level].max_chain; + + s->strstart = 0; + s->block_start = 0L; + s->lookahead = 0; + s->match_length = s->prev_length = MIN_MATCH-1; + s->match_available = 0; + s->ins_h = 0; +#ifndef FASTEST +#ifdef ASMV + match_init(); /* initialize the asm code */ +#endif +#endif +} + +#ifndef FASTEST +/* =========================================================================== + * Set match_start to the longest match starting at the given string and + * return its length. Matches shorter or equal to prev_length are discarded, + * in which case the result is equal to prev_length and match_start is + * garbage. + * IN assertions: cur_match is the head of the hash chain for the current + * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 + * OUT assertion: the match length is not greater than s->lookahead. + */ +#ifndef ASMV +/* For 80x86 and 680x0, an optimized version will be provided in match.asm or + * match.S. The code will be functionally equivalent. + */ +local uInt longest_match(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + unsigned chain_length = s->max_chain_length;/* max hash chain length */ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + int best_len = s->prev_length; /* best match length so far */ + int nice_match = s->nice_match; /* stop if match long enough */ + IPos limit = s->strstart > (IPos)MAX_DIST(s) ? + s->strstart - (IPos)MAX_DIST(s) : NIL; + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + Posf *prev = s->prev; + uInt wmask = s->w_mask; + +#ifdef UNALIGNED_OK + /* Compare two bytes at a time. Note: this is not always beneficial. + * Try with and without -DUNALIGNED_OK to check. + */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; + register ush scan_start = *(ushf*)scan; + register ush scan_end = *(ushf*)(scan+best_len-1); +#else + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + register Byte scan_end1 = scan[best_len-1]; + register Byte scan_end = scan[best_len]; +#endif + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + /* Do not waste too much time if we already have a good match: */ + if (s->prev_length >= s->good_match) { + chain_length >>= 2; + } + /* Do not look for matches beyond the end of the input. This is necessary + * to make deflate deterministic. + */ + if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + do { + Assert(cur_match < s->strstart, "no future"); + match = s->window + cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2. Note that the checks below + * for insufficient lookahead only occur occasionally for performance + * reasons. Therefore uninitialized memory will be accessed, and + * conditional jumps will be made that depend on those values. + * However the length of the match is limited to the lookahead, so + * the output of deflate is not affected by the uninitialized values. + */ +#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) + /* This code assumes sizeof(unsigned short) == 2. Do not use + * UNALIGNED_OK if your compiler uses a different size. + */ + if (*(ushf*)(match+best_len-1) != scan_end || + *(ushf*)match != scan_start) continue; + + /* It is not necessary to compare scan[2] and match[2] since they are + * always equal when the other bytes match, given that the hash keys + * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at + * strstart+3, +5, ... up to strstart+257. We check for insufficient + * lookahead only every 4th comparison; the 128th check will be made + * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is + * necessary to put more guard bytes at the end of the window, or + * to check more often for insufficient lookahead. + */ + Assert(scan[2] == match[2], "scan[2]?"); + scan++, match++; + do { + } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + scan < strend); + /* The funny "do {}" generates better code on most compilers */ + + /* Here, scan <= window+strstart+257 */ + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + if (*scan == *match) scan++; + + len = (MAX_MATCH - 1) - (int)(strend-scan); + scan = strend - (MAX_MATCH-1); + +#else /* UNALIGNED_OK */ + + if (match[best_len] != scan_end || + match[best_len-1] != scan_end1 || + *match != *scan || + *++match != scan[1]) continue; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match++; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + scan = strend - MAX_MATCH; + +#endif /* UNALIGNED_OK */ + + if (len > best_len) { + s->match_start = cur_match; + best_len = len; + if (len >= nice_match) break; +#ifdef UNALIGNED_OK + scan_end = *(ushf*)(scan+best_len-1); +#else + scan_end1 = scan[best_len-1]; + scan_end = scan[best_len]; +#endif + } + } while ((cur_match = prev[cur_match & wmask]) > limit + && --chain_length != 0); + + if ((uInt)best_len <= s->lookahead) return (uInt)best_len; + return s->lookahead; +} +#endif /* ASMV */ +#endif /* FASTEST */ + +/* --------------------------------------------------------------------------- + * Optimized version for level == 1 or strategy == Z_RLE only + */ +local uInt longest_match_fast(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + Assert(cur_match < s->strstart, "no future"); + + match = s->window + cur_match; + + /* Return failure if the match length is less than 2: + */ + if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match += 2; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + + if (len < MIN_MATCH) return MIN_MATCH - 1; + + s->match_start = cur_match; + return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; +} + +#ifdef DEBUG +/* =========================================================================== + * Check that the match at match_start is indeed a match. + */ +local void check_match(s, start, match, length) + deflate_state *s; + IPos start, match; + int length; +{ + /* check that the match is indeed a match */ + if (zmemcmp(s->window + match, + s->window + start, length) != EQUAL) { + fprintf(stderr, " start %u, match %u, length %d\n", + start, match, length); + do { + fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); + } while (--length != 0); + z_error("invalid match"); + } + if (z_verbose > 1) { + fprintf(stderr,"\\[%d,%d]", start-match, length); + do { putc(s->window[start++], stderr); } while (--length != 0); + } +} +#else +# define check_match(s, start, match, length) +#endif /* DEBUG */ + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ +local void fill_window(s) + deflate_state *s; +{ + register unsigned n, m; + register Posf *p; + unsigned more; /* Amount of free space at the end of the window. */ + uInt wsize = s->w_size; + + do { + more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); + + /* Deal with !@#$% 64K limit: */ + if (sizeof(int) <= 2) { + if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + more = wsize; + + } else if (more == (unsigned)(-1)) { + /* Very unlikely, but possible on 16 bit machine if + * strstart == 0 && lookahead == 1 (input done a byte at time) + */ + more--; + } + } + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + if (s->strstart >= wsize+MAX_DIST(s)) { + + zmemcpy(s->window, s->window+wsize, (unsigned)wsize); + s->match_start -= wsize; + s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ + s->block_start -= (long) wsize; + + /* Slide the hash table (could be avoided with 32 bit values + at the expense of memory usage). We slide even when level == 0 + to keep the hash table consistent if we switch back to level > 0 + later. (Using level 0 permanently is not an optimal usage of + zlib, so we don't care about this pathological case.) + */ + /* %%% avoid this when Z_RLE */ + n = s->hash_size; + p = &s->head[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + } while (--n); + + n = wsize; +#ifndef FASTEST + p = &s->prev[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); +#endif + more += wsize; + } + if (s->strm->avail_in == 0) return; + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + Assert(more >= 2, "more < 2"); + + n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); + s->lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s->lookahead >= MIN_MATCH) { + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + + } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); +} + +/* =========================================================================== + * Flush the current block, with given end-of-file flag. + * IN assertion: strstart is set to the end of the current match. + */ +#define FLUSH_BLOCK_ONLY(s, eof) { \ + _tr_flush_block(s, (s->block_start >= 0L ? \ + (charf *)&s->window[(unsigned)s->block_start] : \ + (charf *)Z_NULL), \ + (ulg)((long)s->strstart - s->block_start), \ + (eof)); \ + s->block_start = s->strstart; \ + flush_pending(s->strm); \ + Tracev((stderr,"[FLUSH]")); \ +} + +/* Same but force premature exit if necessary. */ +#define FLUSH_BLOCK(s, eof) { \ + FLUSH_BLOCK_ONLY(s, eof); \ + if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \ +} + +/* =========================================================================== + * Copy without compression as much as possible from the input stream, return + * the current block state. + * This function does not insert new strings in the dictionary since + * uncompressible data is probably not useful. This function is used + * only for the level=0 compression option. + * NOTE: this function should be optimized to avoid extra copying from + * window to pending_buf. + */ +local block_state deflate_stored(s, flush) + deflate_state *s; + int flush; +{ + /* Stored blocks are limited to 0xffff bytes, pending_buf is limited + * to pending_buf_size, and each stored block has a 5 byte header: + */ + ulg max_block_size = 0xffff; + ulg max_start; + + if (max_block_size > s->pending_buf_size - 5) { + max_block_size = s->pending_buf_size - 5; + } + + /* Copy as much as possible from input to output: */ + for (;;) { + /* Fill the window as much as possible: */ + if (s->lookahead <= 1) { + + Assert(s->strstart < s->w_size+MAX_DIST(s) || + s->block_start >= (long)s->w_size, "slide too late"); + + fill_window(s); + if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; + + if (s->lookahead == 0) break; /* flush the current block */ + } + Assert(s->block_start >= 0L, "block gone"); + + s->strstart += s->lookahead; + s->lookahead = 0; + + /* Emit a stored block if pending_buf will be full: */ + max_start = s->block_start + max_block_size; + if (s->strstart == 0 || (ulg)s->strstart >= max_start) { + /* strstart == 0 is possible when wraparound on 16-bit machine */ + s->lookahead = (uInt)(s->strstart - max_start); + s->strstart = (uInt)max_start; + FLUSH_BLOCK(s, 0); + } + /* Flush if we may have to slide, otherwise block_start may become + * negative and the data will be gone: + */ + if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { + FLUSH_BLOCK(s, 0); + } + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +/* =========================================================================== + * Compress as much as possible from the input stream, return the current + * block state. + * This function does not perform lazy evaluation of matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ +local block_state deflate_fast(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of the hash chain */ + int bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < MIN_MATCH + */ + if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ +#ifdef FASTEST + if ((s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) || + (s->strategy == Z_RLE && s->strstart - hash_head == 1)) { + s->match_length = longest_match_fast (s, hash_head); + } +#else + if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) { + s->match_length = longest_match (s, hash_head); + } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { + s->match_length = longest_match_fast (s, hash_head); + } +#endif + /* longest_match() or longest_match_fast() sets match_start */ + } + if (s->match_length >= MIN_MATCH) { + check_match(s, s->strstart, s->match_start, s->match_length); + + _tr_tally_dist(s, s->strstart - s->match_start, + s->match_length - MIN_MATCH, bflush); + + s->lookahead -= s->match_length; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ +#ifndef FASTEST + if (s->match_length <= s->max_insert_length && + s->lookahead >= MIN_MATCH) { + s->match_length--; /* string at strstart already in table */ + do { + s->strstart++; + INSERT_STRING(s, s->strstart, hash_head); + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } while (--s->match_length != 0); + s->strstart++; + } else +#endif + { + s->strstart += s->match_length; + s->match_length = 0; + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ + } + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +#ifndef FASTEST +/* =========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ +local block_state deflate_slow(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of hash chain */ + int bflush; /* set if current block must be flushed */ + + /* Process the input block. */ + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + */ + s->prev_length = s->match_length, s->prev_match = s->match_start; + s->match_length = MIN_MATCH-1; + + if (hash_head != NIL && s->prev_length < s->max_lazy_match && + s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) { + s->match_length = longest_match (s, hash_head); + } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { + s->match_length = longest_match_fast (s, hash_head); + } + /* longest_match() or longest_match_fast() sets match_start */ + + if (s->match_length <= 5 && (s->strategy == Z_FILTERED +#if TOO_FAR <= 32767 + || (s->match_length == MIN_MATCH && + s->strstart - s->match_start > TOO_FAR) +#endif + )) { + + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + s->match_length = MIN_MATCH-1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { + uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; + /* Do not insert strings in hash table beyond this. */ + + check_match(s, s->strstart-1, s->prev_match, s->prev_length); + + _tr_tally_dist(s, s->strstart -1 - s->prev_match, + s->prev_length - MIN_MATCH, bflush); + + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. If there is not + * enough lookahead, the last two strings are not inserted in + * the hash table. + */ + s->lookahead -= s->prev_length-1; + s->prev_length -= 2; + do { + if (++s->strstart <= max_insert) { + INSERT_STRING(s, s->strstart, hash_head); + } + } while (--s->prev_length != 0); + s->match_available = 0; + s->match_length = MIN_MATCH-1; + s->strstart++; + + if (bflush) FLUSH_BLOCK(s, 0); + + } else if (s->match_available) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + if (bflush) { + FLUSH_BLOCK_ONLY(s, 0); + } + s->strstart++; + s->lookahead--; + if (s->strm->avail_out == 0) return need_more; + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + s->match_available = 1; + s->strstart++; + s->lookahead--; + } + } + Assert (flush != Z_NO_FLUSH, "no flush?"); + if (s->match_available) { + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + s->match_available = 0; + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} +#endif /* FASTEST */ + +#if 0 +/* =========================================================================== + * For Z_RLE, simply look for runs of bytes, generate matches only of distance + * one. Do not maintain a hash table. (It will be regenerated if this run of + * deflate switches away from Z_RLE.) + */ +local block_state deflate_rle(s, flush) + deflate_state *s; + int flush; +{ + int bflush; /* set if current block must be flushed */ + uInt run; /* length of run */ + uInt max; /* maximum length of run */ + uInt prev; /* byte at distance one to match */ + Bytef *scan; /* scan for end of run */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the longest encodable run. + */ + if (s->lookahead < MAX_MATCH) { + fill_window(s); + if (s->lookahead < MAX_MATCH && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* See how many times the previous byte repeats */ + run = 0; + if (s->strstart > 0) { /* if there is a previous byte, that is */ + max = s->lookahead < MAX_MATCH ? s->lookahead : MAX_MATCH; + scan = s->window + s->strstart - 1; + prev = *scan++; + do { + if (*scan++ != prev) + break; + } while (++run < max); + } + + /* Emit match if have run of MIN_MATCH or longer, else emit literal */ + if (run >= MIN_MATCH) { + check_match(s, s->strstart, s->strstart - 1, run); + _tr_tally_dist(s, 1, run - MIN_MATCH, bflush); + s->lookahead -= run; + s->strstart += run; + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} +#endif diff --git a/gdcm/Utilities/gdcmzlib/deflate.h b/gdcm/Utilities/gdcmzlib/deflate.h new file mode 100644 index 0000000..05a5ab3 --- /dev/null +++ b/gdcm/Utilities/gdcmzlib/deflate.h @@ -0,0 +1,331 @@ +/* deflate.h -- internal compression state + * Copyright (C) 1995-2004 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef DEFLATE_H +#define DEFLATE_H + +#include "zutil.h" + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer creation by deflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip encoding + should be left enabled. */ +#ifndef NO_GZIP +# define GZIP +#endif + +/* =========================================================================== + * Internal compression state. + */ + +#define LENGTH_CODES 29 +/* number of length codes, not counting the special END_BLOCK code */ + +#define LITERALS 256 +/* number of literal bytes 0..255 */ + +#define L_CODES (LITERALS+1+LENGTH_CODES) +/* number of Literal or Length codes, including the END_BLOCK code */ + +#define D_CODES 30 +/* number of distance codes */ + +#define BL_CODES 19 +/* number of codes used to transfer the bit lengths */ + +#define HEAP_SIZE (2*L_CODES+1) +/* maximum heap size */ + +#define MAX_BITS 15 +/* All codes must not exceed MAX_BITS bits */ + +#define INIT_STATE 42 +#define EXTRA_STATE 69 +#define NAME_STATE 73 +#define COMMENT_STATE 91 +#define HCRC_STATE 103 +#define BUSY_STATE 113 +#define FINISH_STATE 666 +/* Stream status */ + + +/* Data structure describing a single value and its code string. */ +typedef struct ct_data_s { + union { + ush freq; /* frequency count */ + ush code; /* bit string */ + } fc; + union { + ush dad; /* father node in Huffman tree */ + ush len; /* length of bit string */ + } dl; +} FAR ct_data; + +#define Freq fc.freq +#define Code fc.code +#define Dad dl.dad +#define Len dl.len + +typedef struct static_tree_desc_s static_tree_desc; + +typedef struct tree_desc_s { + ct_data *dyn_tree; /* the dynamic tree */ + int max_code; /* largest code with non zero frequency */ + static_tree_desc *stat_desc; /* the corresponding static tree */ +} FAR tree_desc; + +typedef ush Pos; +typedef Pos FAR Posf; +typedef unsigned IPos; + +/* A Pos is an index in the character window. We use short instead of int to + * save space in the various tables. IPos is used only for parameter passing. + */ + +typedef struct internal_state { + z_streamp strm; /* pointer back to this zlib stream */ + int status; /* as the name implies */ + Bytef *pending_buf; /* output still pending */ + ulg pending_buf_size; /* size of pending_buf */ + Bytef *pending_out; /* next pending byte to output to the stream */ + uInt pending; /* nb of bytes in the pending buffer */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + gz_headerp gzhead; /* gzip header information to write */ + uInt gzindex; /* where in extra, name, or comment */ + Byte method; /* STORED (for zip only) or DEFLATED */ + int last_flush; /* value of flush param for previous deflate call */ + + /* used by deflate.c: */ + + uInt w_size; /* LZ77 window size (32K by default) */ + uInt w_bits; /* log2(w_size) (8..16) */ + uInt w_mask; /* w_size - 1 */ + + Bytef *window; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. Also, it limits + * the window size to 64K, which is quite useful on MSDOS. + * To do: use the user input buffer as sliding window. + */ + + ulg window_size; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + Posf *prev; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + Posf *head; /* Heads of the hash chains or NIL. */ + + uInt ins_h; /* hash index of string to be inserted */ + uInt hash_size; /* number of elements in hash table */ + uInt hash_bits; /* log2(hash_size) */ + uInt hash_mask; /* hash_size-1 */ + + uInt hash_shift; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + long block_start; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + uInt match_length; /* length of best match */ + IPos prev_match; /* previous match */ + int match_available; /* set if previous match exists */ + uInt strstart; /* start of string to insert */ + uInt match_start; /* start of matching string */ + uInt lookahead; /* number of valid bytes ahead in window */ + + uInt prev_length; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + uInt max_chain_length; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + uInt max_lazy_match; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ +# define max_insert_length max_lazy_match + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + int level; /* compression level (1..9) */ + int strategy; /* favor or force Huffman coding*/ + + uInt good_match; + /* Use a faster search when the previous match is longer than this */ + + int nice_match; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + /* Didn't use ct_data typedef below to supress compiler warning */ + struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + struct tree_desc_s l_desc; /* desc. for literal tree */ + struct tree_desc_s d_desc; /* desc. for distance tree */ + struct tree_desc_s bl_desc; /* desc. for bit length tree */ + + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + int heap_len; /* number of elements in the heap */ + int heap_max; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + uch depth[2*L_CODES+1]; + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + uchf *l_buf; /* buffer for literals or lengths */ + + uInt lit_bufsize; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + uInt last_lit; /* running index in l_buf */ + + ushf *d_buf; + /* Buffer for distances. To simplify the code, d_buf and l_buf have + * the same number of elements. To use different lengths, an extra flag + * array would be necessary. + */ + + ulg opt_len; /* bit length of current block with optimal trees */ + ulg static_len; /* bit length of current block with static trees */ + uInt matches; /* number of string matches in current block */ + int last_eob_len; /* bit length of EOB code for last block */ + +#ifdef DEBUG + ulg compressed_len; /* total bit length of compressed file mod 2^32 */ + ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ +#endif + + ush bi_buf; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + int bi_valid; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + +} FAR deflate_state; + +/* Output a byte on the stream. + * IN assertion: there is enough room in pending_buf. + */ +#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} + + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) +/* In order to simplify the code, particularly on 16 bit machines, match + * distances are limited to MAX_DIST instead of WSIZE. + */ + + /* in trees.c */ +void _tr_init OF((deflate_state *s)); +int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); +void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); +void _tr_align OF((deflate_state *s)); +void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); + +#define d_code(dist) \ + ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) +/* Mapping from a distance to a distance code. dist is the distance - 1 and + * must not have side effects. _dist_code[256] and _dist_code[257] are never + * used. + */ + +#ifndef DEBUG +/* Inline versions of _tr_tally for speed: */ + +#if defined(GEN_TREES_H) || !defined(STDC) + extern uch _length_code[]; + extern uch _dist_code[]; +#else + extern const uch _length_code[]; + extern const uch _dist_code[]; +#endif + +# define _tr_tally_lit(s, c, flush) \ + { uch cc = (c); \ + s->d_buf[s->last_lit] = 0; \ + s->l_buf[s->last_lit++] = cc; \ + s->dyn_ltree[cc].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +# define _tr_tally_dist(s, distance, length, flush) \ + { uch len = (length); \ + ush dist = (distance); \ + s->d_buf[s->last_lit] = dist; \ + s->l_buf[s->last_lit++] = len; \ + dist--; \ + s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ + s->dyn_dtree[d_code(dist)].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +#else +# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) +# define _tr_tally_dist(s, distance, length, flush) \ + flush = _tr_tally(s, distance, length) +#endif + +#endif /* DEFLATE_H */ diff --git a/gdcm/Utilities/gdcmzlib/example.c b/gdcm/Utilities/gdcmzlib/example.c new file mode 100644 index 0000000..6c8a0ee --- /dev/null +++ b/gdcm/Utilities/gdcmzlib/example.c @@ -0,0 +1,565 @@ +/* example.c -- usage example of the zlib compression library + * Copyright (C) 1995-2004 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#include +#include "zlib.h" + +#ifdef STDC +# include +# include +#endif + +#if defined(VMS) || defined(RISCOS) +# define TESTFILE "foo-gz" +#else +# define TESTFILE "foo.gz" +#endif + +#define CHECK_ERR(err, msg) { \ + if (err != Z_OK) { \ + fprintf(stderr, "%s error: %d\n", msg, err); \ + exit(1); \ + } \ +} + +const char hello[] = "hello, hello!"; +/* "hello world" would be more standard, but the repeated "hello" + * stresses the compression code better, sorry... + */ + +const char dictionary[] = "hello"; +uLong dictId; /* Adler32 value of the dictionary */ + +void test_compress OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_gzio OF((const char *fname, + Byte *uncompr, uLong uncomprLen)); +void test_deflate OF((Byte *compr, uLong comprLen)); +void test_inflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_large_deflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_large_inflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_flush OF((Byte *compr, uLong *comprLen)); +void test_sync OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_dict_deflate OF((Byte *compr, uLong comprLen)); +void test_dict_inflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +int main OF((int argc, char *argv[])); + +/* =========================================================================== + * Test compress() and uncompress() + */ +void test_compress(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + uLong len = (uLong)strlen(hello)+1; + + err = compress(compr, &comprLen, (const Bytef*)hello, len); + CHECK_ERR(err, "compress"); + + strcpy((char*)uncompr, "garbage"); + + err = uncompress(uncompr, &uncomprLen, compr, comprLen); + CHECK_ERR(err, "uncompress"); + + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad uncompress\n"); + exit(1); + } else { + printf("uncompress(): %s\n", (char *)uncompr); + } +} + +/* =========================================================================== + * Test read/write of .gz files + */ +void test_gzio(fname, uncompr, uncomprLen) + const char *fname; /* compressed file name */ + Byte *uncompr; + uLong uncomprLen; +{ +#ifdef NO_GZCOMPRESS + fprintf(stderr, "NO_GZCOMPRESS -- gz* functions cannot compress\n"); +#else + int err; + int len = (int)strlen(hello)+1; + gzFile file; + z_off_t pos; + + file = gzopen(fname, "wb"); + if (file == NULL) { + fprintf(stderr, "gzopen error\n"); + exit(1); + } + gzputc(file, 'h'); + if (gzputs(file, "ello") != 4) { + fprintf(stderr, "gzputs err: %s\n", gzerror(file, &err)); + exit(1); + } + if (gzprintf(file, ", %s!", "hello") != 8) { + fprintf(stderr, "gzprintf err: %s\n", gzerror(file, &err)); + exit(1); + } + gzseek(file, 1L, SEEK_CUR); /* add one zero byte */ + gzclose(file); + + file = gzopen(fname, "rb"); + if (file == NULL) { + fprintf(stderr, "gzopen error\n"); + exit(1); + } + strcpy((char*)uncompr, "garbage"); + + if (gzread(file, uncompr, (unsigned)uncomprLen) != len) { + fprintf(stderr, "gzread err: %s\n", gzerror(file, &err)); + exit(1); + } + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad gzread: %s\n", (char*)uncompr); + exit(1); + } else { + printf("gzread(): %s\n", (char*)uncompr); + } + + pos = gzseek(file, -8L, SEEK_CUR); + if (pos != 6 || gztell(file) != pos) { + fprintf(stderr, "gzseek error, pos=%ld, gztell=%ld\n", + (long)pos, (long)gztell(file)); + exit(1); + } + + if (gzgetc(file) != ' ') { + fprintf(stderr, "gzgetc error\n"); + exit(1); + } + + if (gzungetc(' ', file) != ' ') { + fprintf(stderr, "gzungetc error\n"); + exit(1); + } + + gzgets(file, (char*)uncompr, (int)uncomprLen); + if (strlen((char*)uncompr) != 7) { /* " hello!" */ + fprintf(stderr, "gzgets err after gzseek: %s\n", gzerror(file, &err)); + exit(1); + } + if (strcmp((char*)uncompr, hello + 6)) { + fprintf(stderr, "bad gzgets after gzseek\n"); + exit(1); + } else { + printf("gzgets() after gzseek: %s\n", (char*)uncompr); + } + + gzclose(file); +#endif +} + +/* =========================================================================== + * Test deflate() with small buffers + */ +void test_deflate(compr, comprLen) + Byte *compr; + uLong comprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + uLong len = (uLong)strlen(hello)+1; + + c_stream.zalloc = (alloc_func)0; + c_stream.zfree = (free_func)0; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION); + CHECK_ERR(err, "deflateInit"); + + c_stream.next_in = (Bytef*)hello; + c_stream.next_out = compr; + + while (c_stream.total_in != len && c_stream.total_out < comprLen) { + c_stream.avail_in = c_stream.avail_out = 1; /* force small buffers */ + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + } + /* Finish the stream, still forcing small buffers: */ + for (;;) { + c_stream.avail_out = 1; + err = deflate(&c_stream, Z_FINISH); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "deflate"); + } + + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); +} + +/* =========================================================================== + * Test inflate() with small buffers + */ +void test_inflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = (alloc_func)0; + d_stream.zfree = (free_func)0; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = compr; + d_stream.avail_in = 0; + d_stream.next_out = uncompr; + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + while (d_stream.total_out < uncomprLen && d_stream.total_in < comprLen) { + d_stream.avail_in = d_stream.avail_out = 1; /* force small buffers */ + err = inflate(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "inflate"); + } + + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad inflate\n"); + exit(1); + } else { + printf("inflate(): %s\n", (char *)uncompr); + } +} + +/* =========================================================================== + * Test deflate() with large buffers and dynamic change of compression level + */ +void test_large_deflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + + c_stream.zalloc = (alloc_func)0; + c_stream.zfree = (free_func)0; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_BEST_SPEED); + CHECK_ERR(err, "deflateInit"); + + c_stream.next_out = compr; + c_stream.avail_out = (uInt)comprLen; + + /* At this point, uncompr is still mostly zeroes, so it should compress + * very well: + */ + c_stream.next_in = uncompr; + c_stream.avail_in = (uInt)uncomprLen; + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + if (c_stream.avail_in != 0) { + fprintf(stderr, "deflate not greedy\n"); + exit(1); + } + + /* Feed in already compressed data and switch to no compression: */ + deflateParams(&c_stream, Z_NO_COMPRESSION, Z_DEFAULT_STRATEGY); + c_stream.next_in = compr; + c_stream.avail_in = (uInt)comprLen/2; + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + + /* Switch back to compressing mode: */ + deflateParams(&c_stream, Z_BEST_COMPRESSION, Z_FILTERED); + c_stream.next_in = uncompr; + c_stream.avail_in = (uInt)uncomprLen; + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + + err = deflate(&c_stream, Z_FINISH); + if (err != Z_STREAM_END) { + fprintf(stderr, "deflate should report Z_STREAM_END\n"); + exit(1); + } + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); +} + +/* =========================================================================== + * Test inflate() with large buffers + */ +void test_large_inflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = (alloc_func)0; + d_stream.zfree = (free_func)0; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = compr; + d_stream.avail_in = (uInt)comprLen; + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + for (;;) { + d_stream.next_out = uncompr; /* discard the output */ + d_stream.avail_out = (uInt)uncomprLen; + err = inflate(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "large inflate"); + } + + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + if (d_stream.total_out != 2*uncomprLen + comprLen/2) { + fprintf(stderr, "bad large inflate: %ld\n", d_stream.total_out); + exit(1); + } else { + printf("large_inflate(): OK\n"); + } +} + +/* =========================================================================== + * Test deflate() with full flush + */ +void test_flush(compr, comprLen) + Byte *compr; + uLong *comprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + uInt len = (uInt)strlen(hello)+1; + + c_stream.zalloc = (alloc_func)0; + c_stream.zfree = (free_func)0; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION); + CHECK_ERR(err, "deflateInit"); + + c_stream.next_in = (Bytef*)hello; + c_stream.next_out = compr; + c_stream.avail_in = 3; + c_stream.avail_out = (uInt)*comprLen; + err = deflate(&c_stream, Z_FULL_FLUSH); + CHECK_ERR(err, "deflate"); + + compr[3]++; /* force an error in first compressed block */ + c_stream.avail_in = len - 3; + + err = deflate(&c_stream, Z_FINISH); + if (err != Z_STREAM_END) { + CHECK_ERR(err, "deflate"); + } + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); + + *comprLen = c_stream.total_out; +} + +/* =========================================================================== + * Test inflateSync() + */ +void test_sync(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = (alloc_func)0; + d_stream.zfree = (free_func)0; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = compr; + d_stream.avail_in = 2; /* just read the zlib header */ + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + d_stream.next_out = uncompr; + d_stream.avail_out = (uInt)uncomprLen; + + inflate(&d_stream, Z_NO_FLUSH); + CHECK_ERR(err, "inflate"); + + d_stream.avail_in = (uInt)comprLen-2; /* read all compressed data */ + err = inflateSync(&d_stream); /* but skip the damaged part */ + CHECK_ERR(err, "inflateSync"); + + err = inflate(&d_stream, Z_FINISH); + if (err != Z_DATA_ERROR) { + fprintf(stderr, "inflate should report DATA_ERROR\n"); + /* Because of incorrect adler32 */ + exit(1); + } + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + printf("after inflateSync(): hel%s\n", (char *)uncompr); +} + +/* =========================================================================== + * Test deflate() with preset dictionary + */ +void test_dict_deflate(compr, comprLen) + Byte *compr; + uLong comprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + + c_stream.zalloc = (alloc_func)0; + c_stream.zfree = (free_func)0; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_BEST_COMPRESSION); + CHECK_ERR(err, "deflateInit"); + + err = deflateSetDictionary(&c_stream, + (const Bytef*)dictionary, sizeof(dictionary)); + CHECK_ERR(err, "deflateSetDictionary"); + + dictId = c_stream.adler; + c_stream.next_out = compr; + c_stream.avail_out = (uInt)comprLen; + + c_stream.next_in = (Bytef*)hello; + c_stream.avail_in = (uInt)strlen(hello)+1; + + err = deflate(&c_stream, Z_FINISH); + if (err != Z_STREAM_END) { + fprintf(stderr, "deflate should report Z_STREAM_END\n"); + exit(1); + } + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); +} + +/* =========================================================================== + * Test inflate() with a preset dictionary + */ +void test_dict_inflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = (alloc_func)0; + d_stream.zfree = (free_func)0; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = compr; + d_stream.avail_in = (uInt)comprLen; + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + d_stream.next_out = uncompr; + d_stream.avail_out = (uInt)uncomprLen; + + for (;;) { + err = inflate(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) break; + if (err == Z_NEED_DICT) { + if (d_stream.adler != dictId) { + fprintf(stderr, "unexpected dictionary"); + exit(1); + } + err = inflateSetDictionary(&d_stream, (const Bytef*)dictionary, + sizeof(dictionary)); + } + CHECK_ERR(err, "inflate with dict"); + } + + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad inflate with dict\n"); + exit(1); + } else { + printf("inflate with dictionary: %s\n", (char *)uncompr); + } +} + +/* =========================================================================== + * Usage: example [output.gz [input.gz]] + */ + +int main(argc, argv) + int argc; + char *argv[]; +{ + Byte *compr, *uncompr; + uLong comprLen = 10000*sizeof(int); /* don't overflow on MSDOS */ + uLong uncomprLen = comprLen; + static const char* myVersion = ZLIB_VERSION; + + if (zlibVersion()[0] != myVersion[0]) { + fprintf(stderr, "incompatible zlib version\n"); + exit(1); + + } else if (strcmp(zlibVersion(), ZLIB_VERSION) != 0) { + fprintf(stderr, "warning: different zlib version\n"); + } + + printf("zlib version %s = 0x%04x, compile flags = 0x%lx\n", + ZLIB_VERSION, ZLIB_VERNUM, zlibCompileFlags()); + + compr = (Byte*)calloc((uInt)comprLen, 1); + uncompr = (Byte*)calloc((uInt)uncomprLen, 1); + /* compr and uncompr are cleared to avoid reading uninitialized + * data and to ensure that uncompr compresses well. + */ + if (compr == Z_NULL || uncompr == Z_NULL) { + printf("out of memory\n"); + exit(1); + } + test_compress(compr, comprLen, uncompr, uncomprLen); + + test_gzio((argc > 1 ? argv[1] : TESTFILE), + uncompr, uncomprLen); + + test_deflate(compr, comprLen); + test_inflate(compr, comprLen, uncompr, uncomprLen); + + test_large_deflate(compr, comprLen, uncompr, uncomprLen); + test_large_inflate(compr, comprLen, uncompr, uncomprLen); + + test_flush(compr, &comprLen); + test_sync(compr, comprLen, uncompr, uncomprLen); + comprLen = uncomprLen; + + test_dict_deflate(compr, comprLen); + test_dict_inflate(compr, comprLen, uncompr, uncomprLen); + + free(compr); + free(uncompr); + + return 0; +} diff --git a/gdcm/Utilities/gdcmzlib/examples/README.examples b/gdcm/Utilities/gdcmzlib/examples/README.examples new file mode 100644 index 0000000..5632d7a --- /dev/null +++ b/gdcm/Utilities/gdcmzlib/examples/README.examples @@ -0,0 +1,42 @@ +This directory contains examples of the use of zlib. + +fitblk.c + compress just enough input to nearly fill a requested output size + - zlib isn't designed to do this, but fitblk does it anyway + +gun.c + uncompress a gzip file + - illustrates the use of inflateBack() for high speed file-to-file + decompression using call-back functions + - is approximately twice as fast as gzip -d + - also provides Unix uncompress functionality, again twice as fast + +gzappend.c + append to a gzip file + - illustrates the use of the Z_BLOCK flush parameter for inflate() + - illustrates the use of deflatePrime() to start at any bit + +gzjoin.c + join gzip files without recalculating the crc or recompressing + - illustrates the use of the Z_BLOCK flush parameter for inflate() + - illustrates the use of crc32_combine() + +gzlog.c +gzlog.h + efficiently maintain a message log file in gzip format + - illustrates use of raw deflate and Z_SYNC_FLUSH + - illustrates use of gzip header extra field + +zlib_how.html + painfully comprehensive description of zpipe.c (see below) + - describes in excruciating detail the use of deflate() and inflate() + +zpipe.c + reads and writes zlib streams from stdin to stdout + - illustrates the proper use of deflate() and inflate() + - deeply commented in zlib_how.html (see above) + +zran.c + index a zlib or gzip stream and randomly access it + - illustrates the use of Z_BLOCK, inflatePrime(), and + inflateSetDictionary() to provide random access diff --git a/gdcm/Utilities/gdcmzlib/examples/fitblk.c b/gdcm/Utilities/gdcmzlib/examples/fitblk.c new file mode 100644 index 0000000..c61de5c --- /dev/null +++ b/gdcm/Utilities/gdcmzlib/examples/fitblk.c @@ -0,0 +1,233 @@ +/* fitblk.c: example of fitting compressed output to a specified size + Not copyrighted -- provided to the public domain + Version 1.1 25 November 2004 Mark Adler */ + +/* Version history: + 1.0 24 Nov 2004 First version + 1.1 25 Nov 2004 Change deflateInit2() to deflateInit() + Use fixed-size, stack-allocated raw buffers + Simplify code moving compression to subroutines + Use assert() for internal errors + Add detailed description of approach + */ + +/* Approach to just fitting a requested compressed size: + + fitblk performs three compression passes on a portion of the input + data in order to determine how much of that input will compress to + nearly the requested output block size. The first pass generates + enough deflate blocks to produce output to fill the requested + output size plus a specfied excess amount (see the EXCESS define + below). The last deflate block may go quite a bit past that, but + is discarded. The second pass decompresses and recompresses just + the compressed data that fit in the requested plus excess sized + buffer. The deflate process is terminated after that amount of + input, which is less than the amount consumed on the first pass. + The last deflate block of the result will be of a comparable size + to the final product, so that the header for that deflate block and + the compression ratio for that block will be about the same as in + the final product. The third compression pass decompresses the + result of the second step, but only the compressed data up to the + requested size minus an amount to allow the compressed stream to + complete (see the MARGIN define below). That will result in a + final compressed stream whose length is less than or equal to the + requested size. Assuming sufficient input and a requested size + greater than a few hundred bytes, the shortfall will typically be + less than ten bytes. + + If the input is short enough that the first compression completes + before filling the requested output size, then that compressed + stream is return with no recompression. + + EXCESS is chosen to be just greater than the shortfall seen in a + two pass approach similar to the above. That shortfall is due to + the last deflate block compressing more efficiently with a smaller + header on the second pass. EXCESS is set to be large enough so + that there is enough uncompressed data for the second pass to fill + out the requested size, and small enough so that the final deflate + block of the second pass will be close in size to the final deflate + block of the third and final pass. MARGIN is chosen to be just + large enough to assure that the final compression has enough room + to complete in all cases. + */ + +#include +#include +#include +#include "zlib.h" + +#define local static + +/* print nastygram and leave */ +local void quit(char *why) +{ + fprintf(stderr, "fitblk abort: %s\n", why); + exit(1); +} + +#define RAWLEN 4096 /* intermediate uncompressed buffer size */ + +/* compress from file to def until provided buffer is full or end of + input reached; return last deflate() return value, or Z_ERRNO if + there was read error on the file */ +local int partcompress(FILE *in, z_streamp def) +{ + int ret, flush; + unsigned char raw[RAWLEN]; + + flush = Z_NO_FLUSH; + do { + def->avail_in = fread(raw, 1, RAWLEN, in); + if (ferror(in)) + return Z_ERRNO; + def->next_in = raw; + if (feof(in)) + flush = Z_FINISH; + ret = deflate(def, flush); + assert(ret != Z_STREAM_ERROR); + } while (def->avail_out != 0 && flush == Z_NO_FLUSH); + return ret; +} + +/* recompress from inf's input to def's output; the input for inf and + the output for def are set in those structures before calling; + return last deflate() return value, or Z_MEM_ERROR if inflate() + was not able to allocate enough memory when it needed to */ +local int recompress(z_streamp inf, z_streamp def) +{ + int ret, flush; + unsigned char raw[RAWLEN]; + + flush = Z_NO_FLUSH; + do { + /* decompress */ + inf->avail_out = RAWLEN; + inf->next_out = raw; + ret = inflate(inf, Z_NO_FLUSH); + assert(ret != Z_STREAM_ERROR && ret != Z_DATA_ERROR && + ret != Z_NEED_DICT); + if (ret == Z_MEM_ERROR) + return ret; + + /* compress what was decompresed until done or no room */ + def->avail_in = RAWLEN - inf->avail_out; + def->next_in = raw; + if (inf->avail_out != 0) + flush = Z_FINISH; + ret = deflate(def, flush); + assert(ret != Z_STREAM_ERROR); + } while (ret != Z_STREAM_END && def->avail_out != 0); + return ret; +} + +#define EXCESS 256 /* empirically determined stream overage */ +#define MARGIN 8 /* amount to back off for completion */ + +/* compress from stdin to fixed-size block on stdout */ +int main(int argc, char **argv) +{ + int ret; /* return code */ + unsigned size; /* requested fixed output block size */ + unsigned have; /* bytes written by deflate() call */ + unsigned char *blk; /* intermediate and final stream */ + unsigned char *tmp; /* close to desired size stream */ + z_stream def, inf; /* zlib deflate and inflate states */ + + /* get requested output size */ + if (argc != 2) + quit("need one argument: size of output block"); + ret = strtol(argv[1], argv + 1, 10); + if (argv[1][0] != 0) + quit("argument must be a number"); + if (ret < 8) /* 8 is minimum zlib stream size */ + quit("need positive size of 8 or greater"); + size = (unsigned)ret; + + /* allocate memory for buffers and compression engine */ + blk = malloc(size + EXCESS); + def.zalloc = Z_NULL; + def.zfree = Z_NULL; + def.opaque = Z_NULL; + ret = deflateInit(&def, Z_DEFAULT_COMPRESSION); + if (ret != Z_OK || blk == NULL) + quit("out of memory"); + + /* compress from stdin until output full, or no more input */ + def.avail_out = size + EXCESS; + def.next_out = blk; + ret = partcompress(stdin, &def); + if (ret == Z_ERRNO) + quit("error reading input"); + + /* if it all fit, then size was undersubscribed -- done! */ + if (ret == Z_STREAM_END && def.avail_out >= EXCESS) { + /* write block to stdout */ + have = size + EXCESS - def.avail_out; + if (fwrite(blk, 1, have, stdout) != have || ferror(stdout)) + quit("error writing output"); + + /* clean up and print results to stderr */ + ret = deflateEnd(&def); + assert(ret != Z_STREAM_ERROR); + free(blk); + fprintf(stderr, + "%u bytes unused out of %u requested (all input)\n", + size - have, size); + return 0; + } + + /* it didn't all fit -- set up for recompression */ + inf.zalloc = Z_NULL; + inf.zfree = Z_NULL; + inf.opaque = Z_NULL; + inf.avail_in = 0; + inf.next_in = Z_NULL; + ret = inflateInit(&inf); + tmp = malloc(size + EXCESS); + if (ret != Z_OK || tmp == NULL) + quit("out of memory"); + ret = deflateReset(&def); + assert(ret != Z_STREAM_ERROR); + + /* do first recompression close to the right amount */ + inf.avail_in = size + EXCESS; + inf.next_in = blk; + def.avail_out = size + EXCESS; + def.next_out = tmp; + ret = recompress(&inf, &def); + if (ret == Z_MEM_ERROR) + quit("out of memory"); + + /* set up for next reocmpression */ + ret = inflateReset(&inf); + assert(ret != Z_STREAM_ERROR); + ret = deflateReset(&def); + assert(ret != Z_STREAM_ERROR); + + /* do second and final recompression (third compression) */ + inf.avail_in = size - MARGIN; /* assure stream will complete */ + inf.next_in = tmp; + def.avail_out = size; + def.next_out = blk; + ret = recompress(&inf, &def); + if (ret == Z_MEM_ERROR) + quit("out of memory"); + assert(ret == Z_STREAM_END); /* otherwise MARGIN too small */ + + /* done -- write block to stdout */ + have = size - def.avail_out; + if (fwrite(blk, 1, have, stdout) != have || ferror(stdout)) + quit("error writing output"); + + /* clean up and print results to stderr */ + free(tmp); + ret = inflateEnd(&inf); + assert(ret != Z_STREAM_ERROR); + ret = deflateEnd(&def); + assert(ret != Z_STREAM_ERROR); + free(blk); + fprintf(stderr, + "%u bytes unused out of %u requested (%lu input)\n", + size - have, size, def.total_in); + return 0; +} diff --git a/gdcm/Utilities/gdcmzlib/examples/gun.c b/gdcm/Utilities/gdcmzlib/examples/gun.c new file mode 100644 index 0000000..bfec590 --- /dev/null +++ b/gdcm/Utilities/gdcmzlib/examples/gun.c @@ -0,0 +1,693 @@ +/* gun.c -- simple gunzip to give an example of the use of inflateBack() + * Copyright (C) 2003, 2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + Version 1.3 12 June 2005 Mark Adler */ + +/* Version history: + 1.0 16 Feb 2003 First version for testing of inflateBack() + 1.1 21 Feb 2005 Decompress concatenated gzip streams + Remove use of "this" variable (C++ keyword) + Fix return value for in() + Improve allocation failure checking + Add typecasting for void * structures + Add -h option for command version and usage + Add a bunch of comments + 1.2 20 Mar 2005 Add Unix compress (LZW) decompression + Copy file attributes from input file to output file + 1.3 12 Jun 2005 Add casts for error messages [Oberhumer] + */ + +/* + gun [ -t ] [ name ... ] + + decompresses the data in the named gzip files. If no arguments are given, + gun will decompress from stdin to stdout. The names must end in .gz, -gz, + .z, -z, _z, or .Z. The uncompressed data will be written to a file name + with the suffix stripped. On success, the original file is deleted. On + failure, the output file is deleted. For most failures, the command will + continue to process the remaining names on the command line. A memory + allocation failure will abort the command. If -t is specified, then the + listed files or stdin will be tested as gzip files for integrity (without + checking for a proper suffix), no output will be written, and no files + will be deleted. + + Like gzip, gun allows concatenated gzip streams and will decompress them, + writing all of the uncompressed data to the output. Unlike gzip, gun allows + an empty file on input, and will produce no error writing an empty output + file. + + gun will also decompress files made by Unix compress, which uses LZW + compression. These files are automatically detected by virtue of their + magic header bytes. Since the end of Unix compress stream is marked by the + end-of-file, they cannot be concantenated. If a Unix compress stream is + encountered in an input file, it is the last stream in that file. + + Like gunzip and uncompress, the file attributes of the orignal compressed + file are maintained in the final uncompressed file, to the extent that the + user permissions allow it. + + On my Mac OS X PowerPC G4, gun is almost twice as fast as gunzip (version + 1.2.4) is on the same file, when gun is linked with zlib 1.2.2. Also the + LZW decompression provided by gun is about twice as fast as the standard + Unix uncompress command. + */ + +/* external functions and related types and constants */ +#include /* fprintf() */ +#include /* malloc(), free() */ +#include /* strerror(), strcmp(), strlen(), memcpy() */ +#include /* errno */ +#include /* open() */ +#include /* read(), write(), close(), chown(), unlink() */ +#include +#include /* stat(), chmod() */ +#include /* utime() */ +#include "zlib.h" /* inflateBackInit(), inflateBack(), */ + /* inflateBackEnd(), crc32() */ + +/* function declaration */ +#define local static + +/* buffer constants */ +#define SIZE 32768U /* input and output buffer sizes */ +#define PIECE 16384 /* limits i/o chunks for 16-bit int case */ + +/* structure for infback() to pass to input function in() -- it maintains the + input file and a buffer of size SIZE */ +struct ind { + int infile; + unsigned char *inbuf; +}; + +/* Load input buffer, assumed to be empty, and return bytes loaded and a + pointer to them. read() is called until the buffer is full, or until it + returns end-of-file or error. Return 0 on error. */ +local unsigned in(void *in_desc, unsigned char **buf) +{ + int ret; + unsigned len; + unsigned char *next; + struct ind *me = (struct ind *)in_desc; + + next = me->inbuf; + *buf = next; + len = 0; + do { + ret = PIECE; + if ((unsigned)ret > SIZE - len) + ret = (int)(SIZE - len); + ret = (int)read(me->infile, next, ret); + if (ret == -1) { + len = 0; + break; + } + next += ret; + len += ret; + } while (ret != 0 && len < SIZE); + return len; +} + +/* structure for infback() to pass to output function out() -- it maintains the + output file, a running CRC-32 check on the output and the total number of + bytes output, both for checking against the gzip trailer. (The length in + the gzip trailer is stored modulo 2^32, so it's ok if a long is 32 bits and + the output is greater than 4 GB.) */ +struct outd { + int outfile; + int check; /* true if checking crc and total */ + unsigned long crc; + unsigned long total; +}; + +/* Write output buffer and update the CRC-32 and total bytes written. write() + is called until all of the output is written or an error is encountered. + On success out() returns 0. For a write failure, out() returns 1. If the + output file descriptor is -1, then nothing is written. + */ +local int out(void *out_desc, unsigned char *buf, unsigned len) +{ + int ret; + struct outd *me = (struct outd *)out_desc; + + if (me->check) { + me->crc = crc32(me->crc, buf, len); + me->total += len; + } + if (me->outfile != -1) + do { + ret = PIECE; + if ((unsigned)ret > len) + ret = (int)len; + ret = (int)write(me->outfile, buf, ret); + if (ret == -1) + return 1; + buf += ret; + len -= ret; + } while (len != 0); + return 0; +} + +/* next input byte macro for use inside lunpipe() and gunpipe() */ +#define NEXT() (have ? 0 : (have = in(indp, &next)), \ + last = have ? (have--, (int)(*next++)) : -1) + +/* memory for gunpipe() and lunpipe() -- + the first 256 entries of prefix[] and suffix[] are never used, could + have offset the index, but it's faster to waste the memory */ +unsigned char inbuf[SIZE]; /* input buffer */ +unsigned char outbuf[SIZE]; /* output buffer */ +unsigned short prefix[65536]; /* index to LZW prefix string */ +unsigned char suffix[65536]; /* one-character LZW suffix */ +unsigned char match[65280 + 2]; /* buffer for reversed match or gzip + 32K sliding window */ + +/* throw out what's left in the current bits byte buffer (this is a vestigial + aspect of the compressed data format derived from an implementation that + made use of a special VAX machine instruction!) */ +#define FLUSHCODE() \ + do { \ + left = 0; \ + rem = 0; \ + if (chunk > have) { \ + chunk -= have; \ + have = 0; \ + if (NEXT() == -1) \ + break; \ + chunk--; \ + if (chunk > have) { \ + chunk = have = 0; \ + break; \ + } \ + } \ + have -= chunk; \ + next += chunk; \ + chunk = 0; \ + } while (0) + +/* Decompress a compress (LZW) file from indp to outfile. The compress magic + header (two bytes) has already been read and verified. There are have bytes + of buffered input at next. strm is used for passing error information back + to gunpipe(). + + lunpipe() will return Z_OK on success, Z_BUF_ERROR for an unexpected end of + file, read error, or write error (a write error indicated by strm->next_in + not equal to Z_NULL), or Z_DATA_ERROR for invalid input. + */ +local int lunpipe(unsigned have, unsigned char *next, struct ind *indp, + int outfile, z_stream *strm) +{ + int last; /* last byte read by NEXT(), or -1 if EOF */ + int chunk; /* bytes left in current chunk */ + int left; /* bits left in rem */ + unsigned rem; /* unused bits from input */ + int bits; /* current bits per code */ + unsigned code; /* code, table traversal index */ + unsigned mask; /* mask for current bits codes */ + int max; /* maximum bits per code for this stream */ + int flags; /* compress flags, then block compress flag */ + unsigned end; /* last valid entry in prefix/suffix tables */ + unsigned temp; /* current code */ + unsigned prev; /* previous code */ + unsigned final; /* last character written for previous code */ + unsigned stack; /* next position for reversed string */ + unsigned outcnt; /* bytes in output buffer */ + struct outd outd; /* output structure */ + + /* set up output */ + outd.outfile = outfile; + outd.check = 0; + + /* process remainder of compress header -- a flags byte */ + flags = NEXT(); + if (last == -1) + return Z_BUF_ERROR; + if (flags & 0x60) { + strm->msg = (char *)"unknown lzw flags set"; + return Z_DATA_ERROR; + } + max = flags & 0x1f; + if (max < 9 || max > 16) { + strm->msg = (char *)"lzw bits out of range"; + return Z_DATA_ERROR; + } + if (max == 9) /* 9 doesn't really mean 9 */ + max = 10; + flags &= 0x80; /* true if block compress */ + + /* clear table */ + bits = 9; + mask = 0x1ff; + end = flags ? 256 : 255; + + /* set up: get first 9-bit code, which is the first decompressed byte, but + don't create a table entry until the next code */ + if (NEXT() == -1) /* no compressed data is ok */ + return Z_OK; + final = prev = (unsigned)last; /* low 8 bits of code */ + if (NEXT() == -1) /* missing a bit */ + return Z_BUF_ERROR; + if (last & 1) { /* code must be < 256 */ + strm->msg = (char *)"invalid lzw code"; + return Z_DATA_ERROR; + } + rem = (unsigned)last >> 1; /* remaining 7 bits */ + left = 7; + chunk = bits - 2; /* 7 bytes left in this chunk */ + outbuf[0] = (unsigned char)final; /* write first decompressed byte */ + outcnt = 1; + + /* decode codes */ + stack = 0; + for (;;) { + /* if the table will be full after this, increment the code size */ + if (end >= mask && bits < max) { + FLUSHCODE(); + bits++; + mask <<= 1; + mask++; + } + + /* get a code of length bits */ + if (chunk == 0) /* decrement chunk modulo bits */ + chunk = bits; + code = rem; /* low bits of code */ + if (NEXT() == -1) { /* EOF is end of compressed data */ + /* write remaining buffered output */ + if (outcnt && out(&outd, outbuf, outcnt)) { + strm->next_in = outbuf; /* signal write error */ + return Z_BUF_ERROR; + } + return Z_OK; + } + code += (unsigned)last << left; /* middle (or high) bits of code */ + left += 8; + chunk--; + if (bits > left) { /* need more bits */ + if (NEXT() == -1) /* can't end in middle of code */ + return Z_BUF_ERROR; + code += (unsigned)last << left; /* high bits of code */ + left += 8; + chunk--; + } + code &= mask; /* mask to current code length */ + left -= bits; /* number of unused bits */ + rem = (unsigned)last >> (8 - left); /* unused bits from last byte */ + + /* process clear code (256) */ + if (code == 256 && flags) { + FLUSHCODE(); + bits = 9; /* initialize bits and mask */ + mask = 0x1ff; + end = 255; /* empty table */ + continue; /* get next code */ + } + + /* special code to reuse last match */ + temp = code; /* save the current code */ + if (code > end) { + /* Be picky on the allowed code here, and make sure that the code + we drop through (prev) will be a valid index so that random + input does not cause an exception. The code != end + 1 check is + empirically derived, and not checked in the original uncompress + code. If this ever causes a problem, that check could be safely + removed. Leaving this check in greatly improves gun's ability + to detect random or corrupted input after a compress header. + In any case, the prev > end check must be retained. */ + if (code != end + 1 || prev > end) { + strm->msg = (char *)"invalid lzw code"; + return Z_DATA_ERROR; + } + match[stack++] = (unsigned char)final; + code = prev; + } + + /* walk through linked list to generate output in reverse order */ + while (code >= 256) { + match[stack++] = suffix[code]; + code = prefix[code]; + } + match[stack++] = (unsigned char)code; + final = code; + + /* link new table entry */ + if (end < mask) { + end++; + prefix[end] = (unsigned short)prev; + suffix[end] = (unsigned char)final; + } + + /* set previous code for next iteration */ + prev = temp; + + /* write output in forward order */ + while (stack > SIZE - outcnt) { + while (outcnt < SIZE) + outbuf[outcnt++] = match[--stack]; + if (out(&outd, outbuf, outcnt)) { + strm->next_in = outbuf; /* signal write error */ + return Z_BUF_ERROR; + } + outcnt = 0; + } + do { + outbuf[outcnt++] = match[--stack]; + } while (stack); + + /* loop for next code with final and prev as the last match, rem and + left provide the first 0..7 bits of the next code, end is the last + valid table entry */ + } +} + +/* Decompress a gzip file from infile to outfile. strm is assumed to have been + successfully initialized with inflateBackInit(). The input file may consist + of a series of gzip streams, in which case all of them will be decompressed + to the output file. If outfile is -1, then the gzip stream(s) integrity is + checked and nothing is written. + + The return value is a zlib error code: Z_MEM_ERROR if out of memory, + Z_DATA_ERROR if the header or the compressed data is invalid, or if the + trailer CRC-32 check or length doesn't match, Z_BUF_ERROR if the input ends + prematurely or a write error occurs, or Z_ERRNO if junk (not a another gzip + stream) follows a valid gzip stream. + */ +local int gunpipe(z_stream *strm, int infile, int outfile) +{ + int ret, first, last; + unsigned have, flags, len; + unsigned char *next; + struct ind ind, *indp; + struct outd outd; + + /* setup input buffer */ + ind.infile = infile; + ind.inbuf = inbuf; + indp = &ind; + + /* decompress concatenated gzip streams */ + have = 0; /* no input data read in yet */ + first = 1; /* looking for first gzip header */ + strm->next_in = Z_NULL; /* so Z_BUF_ERROR means EOF */ + for (;;) { + /* look for the two magic header bytes for a gzip stream */ + if (NEXT() == -1) { + ret = Z_OK; + break; /* empty gzip stream is ok */ + } + if (last != 31 || (NEXT() != 139 && last != 157)) { + strm->msg = (char *)"incorrect header check"; + ret = first ? Z_DATA_ERROR : Z_ERRNO; + break; /* not a gzip or compress header */ + } + first = 0; /* next non-header is junk */ + + /* process a compress (LZW) file -- can't be concatenated after this */ + if (last == 157) { + ret = lunpipe(have, next, indp, outfile, strm); + break; + } + + /* process remainder of gzip header */ + ret = Z_BUF_ERROR; + if (NEXT() != 8) { /* only deflate method allowed */ + if (last == -1) break; + strm->msg = (char *)"unknown compression method"; + ret = Z_DATA_ERROR; + break; + } + flags = NEXT(); /* header flags */ + NEXT(); /* discard mod time, xflgs, os */ + NEXT(); + NEXT(); + NEXT(); + NEXT(); + NEXT(); + if (last == -1) break; + if (flags & 0xe0) { + strm->msg = (char *)"unknown header flags set"; + ret = Z_DATA_ERROR; + break; + } + if (flags & 4) { /* extra field */ + len = NEXT(); + len += (unsigned)(NEXT()) << 8; + if (last == -1) break; + while (len > have) { + len -= have; + have = 0; + if (NEXT() == -1) break; + len--; + } + if (last == -1) break; + have -= len; + next += len; + } + if (flags & 8) /* file name */ + while (NEXT() != 0 && last != -1) + ; + if (flags & 16) /* comment */ + while (NEXT() != 0 && last != -1) + ; + if (flags & 2) { /* header crc */ + NEXT(); + NEXT(); + } + if (last == -1) break; + + /* set up output */ + outd.outfile = outfile; + outd.check = 1; + outd.crc = crc32(0L, Z_NULL, 0); + outd.total = 0; + + /* decompress data to output */ + strm->next_in = next; + strm->avail_in = have; + ret = inflateBack(strm, in, indp, out, &outd); + if (ret != Z_STREAM_END) break; + next = strm->next_in; + have = strm->avail_in; + strm->next_in = Z_NULL; /* so Z_BUF_ERROR means EOF */ + + /* check trailer */ + ret = Z_BUF_ERROR; + if (NEXT() != (outd.crc & 0xff) || + NEXT() != ((outd.crc >> 8) & 0xff) || + NEXT() != ((outd.crc >> 16) & 0xff) || + NEXT() != ((outd.crc >> 24) & 0xff)) { + /* crc error */ + if (last != -1) { + strm->msg = (char *)"incorrect data check"; + ret = Z_DATA_ERROR; + } + break; + } + if (NEXT() != (outd.total & 0xff) || + NEXT() != ((outd.total >> 8) & 0xff) || + NEXT() != ((outd.total >> 16) & 0xff) || + NEXT() != ((outd.total >> 24) & 0xff)) { + /* length error */ + if (last != -1) { + strm->msg = (char *)"incorrect length check"; + ret = Z_DATA_ERROR; + } + break; + } + + /* go back and look for another gzip stream */ + } + + /* clean up and return */ + return ret; +} + +/* Copy file attributes, from -> to, as best we can. This is best effort, so + no errors are reported. The mode bits, including suid, sgid, and the sticky + bit are copied (if allowed), the owner's user id and group id are copied + (again if allowed), and the access and modify times are copied. */ +local void copymeta(char *from, char *to) +{ + struct stat was; + struct utimbuf when; + + /* get all of from's Unix meta data, return if not a regular file */ + if (stat(from, &was) != 0 || (was.st_mode & S_IFMT) != S_IFREG) + return; + + /* set to's mode bits, ignore errors */ + (void)chmod(to, was.st_mode & 07777); + + /* copy owner's user and group, ignore errors */ + (void)chown(to, was.st_uid, was.st_gid); + + /* copy access and modify times, ignore errors */ + when.actime = was.st_atime; + when.modtime = was.st_mtime; + (void)utime(to, &when); +} + +/* Decompress the file inname to the file outnname, of if test is true, just + decompress without writing and check the gzip trailer for integrity. If + inname is NULL or an empty string, read from stdin. If outname is NULL or + an empty string, write to stdout. strm is a pre-initialized inflateBack + structure. When appropriate, copy the file attributes from inname to + outname. + + gunzip() returns 1 if there is an out-of-memory error or an unexpected + return code from gunpipe(). Otherwise it returns 0. + */ +local int gunzip(z_stream *strm, char *inname, char *outname, int test) +{ + int ret; + int infile, outfile; + + /* open files */ + if (inname == NULL || *inname == 0) { + inname = "-"; + infile = 0; /* stdin */ + } + else { + infile = open(inname, O_RDONLY, 0); + if (infile == -1) { + fprintf(stderr, "gun cannot open %s\n", inname); + return 0; + } + } + if (test) + outfile = -1; + else if (outname == NULL || *outname == 0) { + outname = "-"; + outfile = 1; /* stdout */ + } + else { + outfile = open(outname, O_CREAT | O_TRUNC | O_WRONLY, 0666); + if (outfile == -1) { + close(infile); + fprintf(stderr, "gun cannot create %s\n", outname); + return 0; + } + } + errno = 0; + + /* decompress */ + ret = gunpipe(strm, infile, outfile); + if (outfile > 2) close(outfile); + if (infile > 2) close(infile); + + /* interpret result */ + switch (ret) { + case Z_OK: + case Z_ERRNO: + if (infile > 2 && outfile > 2) { + copymeta(inname, outname); /* copy attributes */ + unlink(inname); + } + if (ret == Z_ERRNO) + fprintf(stderr, "gun warning: trailing garbage ignored in %s\n", + inname); + break; + case Z_DATA_ERROR: + if (outfile > 2) unlink(outname); + fprintf(stderr, "gun data error on %s: %s\n", inname, strm->msg); + break; + case Z_MEM_ERROR: + if (outfile > 2) unlink(outname); + fprintf(stderr, "gun out of memory error--aborting\n"); + return 1; + case Z_BUF_ERROR: + if (outfile > 2) unlink(outname); + if (strm->next_in != Z_NULL) { + fprintf(stderr, "gun write error on %s: %s\n", + outname, strerror(errno)); + } + else if (errno) { + fprintf(stderr, "gun read error on %s: %s\n", + inname, strerror(errno)); + } + else { + fprintf(stderr, "gun unexpected end of file on %s\n", + inname); + } + break; + default: + if (outfile > 2) unlink(outname); + fprintf(stderr, "gun internal error--aborting\n"); + return 1; + } + return 0; +} + +/* Process the gun command line arguments. See the command syntax near the + beginning of this source file. */ +int main(int argc, char **argv) +{ + int ret, len, test; + char *outname; + unsigned char *window; + z_stream strm; + + /* initialize inflateBack state for repeated use */ + window = match; /* reuse LZW match buffer */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + ret = inflateBackInit(&strm, 15, window); + if (ret != Z_OK) { + fprintf(stderr, "gun out of memory error--aborting\n"); + return 1; + } + + /* decompress each file to the same name with the suffix removed */ + argc--; + argv++; + test = 0; + if (argc && strcmp(*argv, "-h") == 0) { + fprintf(stderr, "gun 1.3 (12 Jun 2005)\n"); + fprintf(stderr, "Copyright (c) 2005 Mark Adler\n"); + fprintf(stderr, "usage: gun [-t] [file1.gz [file2.Z ...]]\n"); + return 0; + } + if (argc && strcmp(*argv, "-t") == 0) { + test = 1; + argc--; + argv++; + } + if (argc) + do { + if (test) + outname = NULL; + else { + len = (int)strlen(*argv); + if (strcmp(*argv + len - 3, ".gz") == 0 || + strcmp(*argv + len - 3, "-gz") == 0) + len -= 3; + else if (strcmp(*argv + len - 2, ".z") == 0 || + strcmp(*argv + len - 2, "-z") == 0 || + strcmp(*argv + len - 2, "_z") == 0 || + strcmp(*argv + len - 2, ".Z") == 0) + len -= 2; + else { + fprintf(stderr, "gun error: no gz type on %s--skipping\n", + *argv); + continue; + } + outname = malloc(len + 1); + if (outname == NULL) { + fprintf(stderr, "gun out of memory error--aborting\n"); + ret = 1; + break; + } + memcpy(outname, *argv, len); + outname[len] = 0; + } + ret = gunzip(&strm, *argv, outname, test); + if (outname != NULL) free(outname); + if (ret) break; + } while (argv++, --argc); + else + ret = gunzip(&strm, NULL, NULL, test); + + /* clean up */ + inflateBackEnd(&strm); + return ret; +} diff --git a/gdcm/Utilities/gdcmzlib/examples/gzappend.c b/gdcm/Utilities/gdcmzlib/examples/gzappend.c new file mode 100644 index 0000000..e9e878e --- /dev/null +++ b/gdcm/Utilities/gdcmzlib/examples/gzappend.c @@ -0,0 +1,500 @@ +/* gzappend -- command to append to a gzip file + + Copyright (C) 2003 Mark Adler, all rights reserved + version 1.1, 4 Nov 2003 + + This software is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Mark Adler madler@alumni.caltech.edu + */ + +/* + * Change history: + * + * 1.0 19 Oct 2003 - First version + * 1.1 4 Nov 2003 - Expand and clarify some comments and notes + * - Add version and copyright to help + * - Send help to stdout instead of stderr + * - Add some preemptive typecasts + * - Add L to constants in lseek() calls + * - Remove some debugging information in error messages + * - Use new data_type definition for zlib 1.2.1 + * - Simplfy and unify file operations + * - Finish off gzip file in gztack() + * - Use deflatePrime() instead of adding empty blocks + * - Keep gzip file clean on appended file read errors + * - Use in-place rotate instead of auxiliary buffer + * (Why you ask? Because it was fun to write!) + */ + +/* + gzappend takes a gzip file and appends to it, compressing files from the + command line or data from stdin. The gzip file is written to directly, to + avoid copying that file, in case it's large. Note that this results in the + unfriendly behavior that if gzappend fails, the gzip file is corrupted. + + This program was written to illustrate the use of the new Z_BLOCK option of + zlib 1.2.x's inflate() function. This option returns from inflate() at each + block boundary to facilitate locating and modifying the last block bit at + the start of the final deflate block. Also whether using Z_BLOCK or not, + another required feature of zlib 1.2.x is that inflate() now provides the + number of unusued bits in the last input byte used. gzappend will not work + with versions of zlib earlier than 1.2.1. + + gzappend first decompresses the gzip file internally, discarding all but + the last 32K of uncompressed data, and noting the location of the last block + bit and the number of unused bits in the last byte of the compressed data. + The gzip trailer containing the CRC-32 and length of the uncompressed data + is verified. This trailer will be later overwritten. + + Then the last block bit is cleared by seeking back in the file and rewriting + the byte that contains it. Seeking forward, the last byte of the compressed + data is saved along with the number of unused bits to initialize deflate. + + A deflate process is initialized, using the last 32K of the uncompressed + data from the gzip file to initialize the dictionary. If the total + uncompressed data was less than 32K, then all of it is used to initialize + the dictionary. The deflate output bit buffer is also initialized with the + last bits from the original deflate stream. From here on, the data to + append is simply compressed using deflate, and written to the gzip file. + When that is complete, the new CRC-32 and uncompressed length are written + as the trailer of the gzip file. + */ + +#include +#include +#include +#include +#include +#include "zlib.h" + +#define local static +#define LGCHUNK 14 +#define CHUNK (1U << LGCHUNK) +#define DSIZE 32768U + +/* print an error message and terminate with extreme prejudice */ +local void bye(char *msg1, char *msg2) +{ + fprintf(stderr, "gzappend error: %s%s\n", msg1, msg2); + exit(1); +} + +/* return the greatest common divisor of a and b using Euclid's algorithm, + modified to be fast when one argument much greater than the other, and + coded to avoid unnecessary swapping */ +local unsigned gcd(unsigned a, unsigned b) +{ + unsigned c; + + while (a && b) + if (a > b) { + c = b; + while (a - c >= c) + c <<= 1; + a -= c; + } + else { + c = a; + while (b - c >= c) + c <<= 1; + b -= c; + } + return a + b; +} + +/* rotate list[0..len-1] left by rot positions, in place */ +local void rotate(unsigned char *list, unsigned len, unsigned rot) +{ + unsigned char tmp; + unsigned cycles; + unsigned char *start, *last, *to, *from; + + /* normalize rot and handle degenerate cases */ + if (len < 2) return; + if (rot >= len) rot %= len; + if (rot == 0) return; + + /* pointer to last entry in list */ + last = list + (len - 1); + + /* do simple left shift by one */ + if (rot == 1) { + tmp = *list; + memcpy(list, list + 1, len - 1); + *last = tmp; + return; + } + + /* do simple right shift by one */ + if (rot == len - 1) { + tmp = *last; + memmove(list + 1, list, len - 1); + *list = tmp; + return; + } + + /* otherwise do rotate as a set of cycles in place */ + cycles = gcd(len, rot); /* number of cycles */ + do { + start = from = list + cycles; /* start index is arbitrary */ + tmp = *from; /* save entry to be overwritten */ + for (;;) { + to = from; /* next step in cycle */ + from += rot; /* go right rot positions */ + if (from > last) from -= len; /* (pointer better not wrap) */ + if (from == start) break; /* all but one shifted */ + *to = *from; /* shift left */ + } + *to = tmp; /* complete the circle */ + } while (--cycles); +} + +/* structure for gzip file read operations */ +typedef struct { + int fd; /* file descriptor */ + int size; /* 1 << size is bytes in buf */ + unsigned left; /* bytes available at next */ + unsigned char *buf; /* buffer */ + unsigned char *next; /* next byte in buffer */ + char *name; /* file name for error messages */ +} file; + +/* reload buffer */ +local int readin(file *in) +{ + int len; + + len = read(in->fd, in->buf, 1 << in->size); + if (len == -1) bye("error reading ", in->name); + in->left = (unsigned)len; + in->next = in->buf; + return len; +} + +/* read from file in, exit if end-of-file */ +local int readmore(file *in) +{ + if (readin(in) == 0) bye("unexpected end of ", in->name); + return 0; +} + +#define read1(in) (in->left == 0 ? readmore(in) : 0, \ + in->left--, *(in->next)++) + +/* skip over n bytes of in */ +local void skip(file *in, unsigned n) +{ + unsigned bypass; + + if (n > in->left) { + n -= in->left; + bypass = n & ~((1U << in->size) - 1); + if (bypass) { + if (lseek(in->fd, (off_t)bypass, SEEK_CUR) == -1) + bye("seeking ", in->name); + n -= bypass; + } + readmore(in); + if (n > in->left) + bye("unexpected end of ", in->name); + } + in->left -= n; + in->next += n; +} + +/* read a four-byte unsigned integer, little-endian, from in */ +unsigned long read4(file *in) +{ + unsigned long val; + + val = read1(in); + val += (unsigned)read1(in) << 8; + val += (unsigned long)read1(in) << 16; + val += (unsigned long)read1(in) << 24; + return val; +} + +/* skip over gzip header */ +local void gzheader(file *in) +{ + int flags; + unsigned n; + + if (read1(in) != 31 || read1(in) != 139) bye(in->name, " not a gzip file"); + if (read1(in) != 8) bye("unknown compression method in", in->name); + flags = read1(in); + if (flags & 0xe0) bye("unknown header flags set in", in->name); + skip(in, 6); + if (flags & 4) { + n = read1(in); + n += (unsigned)(read1(in)) << 8; + skip(in, n); + } + if (flags & 8) while (read1(in) != 0) ; + if (flags & 16) while (read1(in) != 0) ; + if (flags & 2) skip(in, 2); +} + +/* decompress gzip file "name", return strm with a deflate stream ready to + continue compression of the data in the gzip file, and return a file + descriptor pointing to where to write the compressed data -- the deflate + stream is initialized to compress using level "level" */ +local int gzscan(char *name, z_stream *strm, int level) +{ + int ret, lastbit, left, full; + unsigned have; + unsigned long crc, tot; + unsigned char *window; + off_t lastoff, end; + file gz; + + /* open gzip file */ + gz.name = name; + gz.fd = open(name, O_RDWR, 0); + if (gz.fd == -1) bye("cannot open ", name); + gz.buf = malloc(CHUNK); + if (gz.buf == NULL) bye("out of memory", ""); + gz.size = LGCHUNK; + gz.left = 0; + + /* skip gzip header */ + gzheader(&gz); + + /* prepare to decompress */ + window = malloc(DSIZE); + if (window == NULL) bye("out of memory", ""); + strm->zalloc = Z_NULL; + strm->zfree = Z_NULL; + strm->opaque = Z_NULL; + ret = inflateInit2(strm, -15); + if (ret != Z_OK) bye("out of memory", " or library mismatch"); + + /* decompress the deflate stream, saving append information */ + lastbit = 0; + lastoff = lseek(gz.fd, 0L, SEEK_CUR) - gz.left; + left = 0; + strm->avail_in = gz.left; + strm->next_in = gz.next; + crc = crc32(0L, Z_NULL, 0); + have = full = 0; + do { + /* if needed, get more input */ + if (strm->avail_in == 0) { + readmore(&gz); + strm->avail_in = gz.left; + strm->next_in = gz.next; + } + + /* set up output to next available section of sliding window */ + strm->avail_out = DSIZE - have; + strm->next_out = window + have; + + /* inflate and check for errors */ + ret = inflate(strm, Z_BLOCK); + if (ret == Z_STREAM_ERROR) bye("internal stream error!", ""); + if (ret == Z_MEM_ERROR) bye("out of memory", ""); + if (ret == Z_DATA_ERROR) + bye("invalid compressed data--format violated in", name); + + /* update crc and sliding window pointer */ + crc = crc32(crc, window + have, DSIZE - have - strm->avail_out); + if (strm->avail_out) + have = DSIZE - strm->avail_out; + else { + have = 0; + full = 1; + } + + /* process end of block */ + if (strm->data_type & 128) { + if (strm->data_type & 64) + left = strm->data_type & 0x1f; + else { + lastbit = strm->data_type & 0x1f; + lastoff = lseek(gz.fd, 0L, SEEK_CUR) - strm->avail_in; + } + } + } while (ret != Z_STREAM_END); + inflateEnd(strm); + gz.left = strm->avail_in; + gz.next = strm->next_in; + + /* save the location of the end of the compressed data */ + end = lseek(gz.fd, 0L, SEEK_CUR) - gz.left; + + /* check gzip trailer and save total for deflate */ + if (crc != read4(&gz)) + bye("invalid compressed data--crc mismatch in ", name); + tot = strm->total_out; + if ((tot & 0xffffffffUL) != read4(&gz)) + bye("invalid compressed data--length mismatch in", name); + + /* if not at end of file, warn */ + if (gz.left || readin(&gz)) + fprintf(stderr, + "gzappend warning: junk at end of gzip file overwritten\n"); + + /* clear last block bit */ + lseek(gz.fd, lastoff - (lastbit != 0), SEEK_SET); + if (read(gz.fd, gz.buf, 1) != 1) bye("reading after seek on ", name); + *gz.buf = (unsigned char)(*gz.buf ^ (1 << ((8 - lastbit) & 7))); + lseek(gz.fd, -1L, SEEK_CUR); + if (write(gz.fd, gz.buf, 1) != 1) bye("writing after seek to ", name); + + /* if window wrapped, build dictionary from window by rotating */ + if (full) { + rotate(window, DSIZE, have); + have = DSIZE; + } + + /* set up deflate stream with window, crc, total_in, and leftover bits */ + ret = deflateInit2(strm, level, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY); + if (ret != Z_OK) bye("out of memory", ""); + deflateSetDictionary(strm, window, have); + strm->adler = crc; + strm->total_in = tot; + if (left) { + lseek(gz.fd, --end, SEEK_SET); + if (read(gz.fd, gz.buf, 1) != 1) bye("reading after seek on ", name); + deflatePrime(strm, 8 - left, *gz.buf); + } + lseek(gz.fd, end, SEEK_SET); + + /* clean up and return */ + free(window); + free(gz.buf); + return gz.fd; +} + +/* append file "name" to gzip file gd using deflate stream strm -- if last + is true, then finish off the deflate stream at the end */ +local void gztack(char *name, int gd, z_stream *strm, int last) +{ + int fd, len, ret; + unsigned left; + unsigned char *in, *out; + + /* open file to compress and append */ + fd = 0; + if (name != NULL) { + fd = open(name, O_RDONLY, 0); + if (fd == -1) + fprintf(stderr, "gzappend warning: %s not found, skipping ...\n", + name); + } + + /* allocate buffers */ + in = fd == -1 ? NULL : malloc(CHUNK); + out = malloc(CHUNK); + if (out == NULL) bye("out of memory", ""); + + /* compress input file and append to gzip file */ + do { + /* get more input */ + len = fd == -1 ? 0 : read(fd, in, CHUNK); + if (len == -1) { + fprintf(stderr, + "gzappend warning: error reading %s, skipping rest ...\n", + name); + len = 0; + } + strm->avail_in = (unsigned)len; + strm->next_in = in; + if (len) strm->adler = crc32(strm->adler, in, (unsigned)len); + + /* compress and write all available output */ + do { + strm->avail_out = CHUNK; + strm->next_out = out; + ret = deflate(strm, last && len == 0 ? Z_FINISH : Z_NO_FLUSH); + left = CHUNK - strm->avail_out; + while (left) { + len = write(gd, out + CHUNK - strm->avail_out - left, left); + if (len == -1) bye("writing gzip file", ""); + left -= (unsigned)len; + } + } while (strm->avail_out == 0 && ret != Z_STREAM_END); + } while (len != 0); + + /* write trailer after last entry */ + if (last) { + deflateEnd(strm); + out[0] = (unsigned char)(strm->adler); + out[1] = (unsigned char)(strm->adler >> 8); + out[2] = (unsigned char)(strm->adler >> 16); + out[3] = (unsigned char)(strm->adler >> 24); + out[4] = (unsigned char)(strm->total_in); + out[5] = (unsigned char)(strm->total_in >> 8); + out[6] = (unsigned char)(strm->total_in >> 16); + out[7] = (unsigned char)(strm->total_in >> 24); + len = 8; + do { + ret = write(gd, out + 8 - len, len); + if (ret == -1) bye("writing gzip file", ""); + len -= ret; + } while (len); + close(gd); + } + + /* clean up and return */ + free(out); + if (in != NULL) free(in); + if (fd > 0) close(fd); +} + +/* process the compression level option if present, scan the gzip file, and + append the specified files, or append the data from stdin if no other file + names are provided on the command line -- the gzip file must be writable + and seekable */ +int main(int argc, char **argv) +{ + int gd, level; + z_stream strm; + + /* ignore command name */ + argv++; + + /* provide usage if no arguments */ + if (*argv == NULL) { + printf("gzappend 1.1 (4 Nov 2003) Copyright (C) 2003 Mark Adler\n"); + printf( + "usage: gzappend [-level] file.gz [ addthis [ andthis ... ]]\n"); + return 0; + } + + /* set compression level */ + level = Z_DEFAULT_COMPRESSION; + if (argv[0][0] == '-') { + if (argv[0][1] < '0' || argv[0][1] > '9' || argv[0][2] != 0) + bye("invalid compression level", ""); + level = argv[0][1] - '0'; + if (*++argv == NULL) bye("no gzip file name after options", ""); + } + + /* prepare to append to gzip file */ + gd = gzscan(*argv++, &strm, level); + + /* append files on command line, or from stdin if none */ + if (*argv == NULL) + gztack(NULL, gd, &strm, 1); + else + do { + gztack(*argv, gd, &strm, argv[1] == NULL); + } while (*++argv != NULL); + return 0; +} diff --git a/gdcm/Utilities/gdcmzlib/examples/gzjoin.c b/gdcm/Utilities/gdcmzlib/examples/gzjoin.c new file mode 100644 index 0000000..129347c --- /dev/null +++ b/gdcm/Utilities/gdcmzlib/examples/gzjoin.c @@ -0,0 +1,448 @@ +/* gzjoin -- command to join gzip files into one gzip file + + Copyright (C) 2004 Mark Adler, all rights reserved + version 1.0, 11 Dec 2004 + + This software is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Mark Adler madler@alumni.caltech.edu + */ + +/* + * Change history: + * + * 1.0 11 Dec 2004 - First version + * 1.1 12 Jun 2005 - Changed ssize_t to long for portability + */ + +/* + gzjoin takes one or more gzip files on the command line and writes out a + single gzip file that will uncompress to the concatenation of the + uncompressed data from the individual gzip files. gzjoin does this without + having to recompress any of the data and without having to calculate a new + crc32 for the concatenated uncompressed data. gzjoin does however have to + decompress all of the input data in order to find the bits in the compressed + data that need to be modified to concatenate the streams. + + gzjoin does not do an integrity check on the input gzip files other than + checking the gzip header and decompressing the compressed data. They are + otherwise assumed to be complete and correct. + + Each joint between gzip files removes at least 18 bytes of previous trailer + and subsequent header, and inserts an average of about three bytes to the + compressed data in order to connect the streams. The output gzip file + has a minimal ten-byte gzip header with no file name or modification time. + + This program was written to illustrate the use of the Z_BLOCK option of + inflate() and the crc32_combine() function. gzjoin will not compile with + versions of zlib earlier than 1.2.3. + */ + +#include /* fputs(), fprintf(), fwrite(), putc() */ +#include /* exit(), malloc(), free() */ +#include /* open() */ +#include /* close(), read(), lseek() */ +#include "zlib.h" + /* crc32(), crc32_combine(), inflateInit2(), inflate(), inflateEnd() */ + +#define local static + +/* exit with an error (return a value to allow use in an expression) */ +local int bail(char *why1, char *why2) +{ + fprintf(stderr, "gzjoin error: %s%s, output incomplete\n", why1, why2); + exit(1); + return 0; +} + +/* -- simple buffered file input with access to the buffer -- */ + +#define CHUNK 32768 /* must be a power of two and fit in unsigned */ + +/* bin buffered input file type */ +typedef struct { + char *name; /* name of file for error messages */ + int fd; /* file descriptor */ + unsigned left; /* bytes remaining at next */ + unsigned char *next; /* next byte to read */ + unsigned char *buf; /* allocated buffer of length CHUNK */ +} bin; + +/* close a buffered file and free allocated memory */ +local void bclose(bin *in) +{ + if (in != NULL) { + if (in->fd != -1) + close(in->fd); + if (in->buf != NULL) + free(in->buf); + free(in); + } +} + +/* open a buffered file for input, return a pointer to type bin, or NULL on + failure */ +local bin *bopen(char *name) +{ + bin *in; + + in = malloc(sizeof(bin)); + if (in == NULL) + return NULL; + in->buf = malloc(CHUNK); + in->fd = open(name, O_RDONLY, 0); + if (in->buf == NULL || in->fd == -1) { + bclose(in); + return NULL; + } + in->left = 0; + in->next = in->buf; + in->name = name; + return in; +} + +/* load buffer from file, return -1 on read error, 0 or 1 on success, with + 1 indicating that end-of-file was reached */ +local int bload(bin *in) +{ + long len; + + if (in == NULL) + return -1; + if (in->left != 0) + return 0; + in->next = in->buf; + do { + len = (long)read(in->fd, in->buf + in->left, CHUNK - in->left); + if (len < 0) + return -1; + in->left += (unsigned)len; + } while (len != 0 && in->left < CHUNK); + return len == 0 ? 1 : 0; +} + +/* get a byte from the file, bail if end of file */ +#define bget(in) (in->left ? 0 : bload(in), \ + in->left ? (in->left--, *(in->next)++) : \ + bail("unexpected end of file on ", in->name)) + +/* get a four-byte little-endian unsigned integer from file */ +local unsigned long bget4(bin *in) +{ + unsigned long val; + + val = bget(in); + val += (unsigned long)(bget(in)) << 8; + val += (unsigned long)(bget(in)) << 16; + val += (unsigned long)(bget(in)) << 24; + return val; +} + +/* skip bytes in file */ +local void bskip(bin *in, unsigned skip) +{ + /* check pointer */ + if (in == NULL) + return; + + /* easy case -- skip bytes in buffer */ + if (skip <= in->left) { + in->left -= skip; + in->next += skip; + return; + } + + /* skip what's in buffer, discard buffer contents */ + skip -= in->left; + in->left = 0; + + /* seek past multiples of CHUNK bytes */ + if (skip > CHUNK) { + unsigned left; + + left = skip & (CHUNK - 1); + if (left == 0) { + /* exact number of chunks: seek all the way minus one byte to check + for end-of-file with a read */ + lseek(in->fd, skip - 1, SEEK_CUR); + if (read(in->fd, in->buf, 1) != 1) + bail("unexpected end of file on ", in->name); + return; + } + + /* skip the integral chunks, update skip with remainder */ + lseek(in->fd, skip - left, SEEK_CUR); + skip = left; + } + + /* read more input and skip remainder */ + bload(in); + if (skip > in->left) + bail("unexpected end of file on ", in->name); + in->left -= skip; + in->next += skip; +} + +/* -- end of buffered input functions -- */ + +/* skip the gzip header from file in */ +local void gzhead(bin *in) +{ + int flags; + + /* verify gzip magic header and compression method */ + if (bget(in) != 0x1f || bget(in) != 0x8b || bget(in) != 8) + bail(in->name, " is not a valid gzip file"); + + /* get and verify flags */ + flags = bget(in); + if ((flags & 0xe0) != 0) + bail("unknown reserved bits set in ", in->name); + + /* skip modification time, extra flags, and os */ + bskip(in, 6); + + /* skip extra field if present */ + if (flags & 4) { + unsigned len; + + len = bget(in); + len += (unsigned)(bget(in)) << 8; + bskip(in, len); + } + + /* skip file name if present */ + if (flags & 8) + while (bget(in) != 0) + ; + + /* skip comment if present */ + if (flags & 16) + while (bget(in) != 0) + ; + + /* skip header crc if present */ + if (flags & 2) + bskip(in, 2); +} + +/* write a four-byte little-endian unsigned integer to out */ +local void put4(unsigned long val, FILE *out) +{ + putc(val & 0xff, out); + putc((val >> 8) & 0xff, out); + putc((val >> 16) & 0xff, out); + putc((val >> 24) & 0xff, out); +} + +/* Load up zlib stream from buffered input, bail if end of file */ +local void zpull(z_streamp strm, bin *in) +{ + if (in->left == 0) + bload(in); + if (in->left == 0) + bail("unexpected end of file on ", in->name); + strm->avail_in = in->left; + strm->next_in = in->next; +} + +/* Write header for gzip file to out and initialize trailer. */ +local void gzinit(unsigned long *crc, unsigned long *tot, FILE *out) +{ + fwrite("\x1f\x8b\x08\0\0\0\0\0\0\xff", 1, 10, out); + *crc = crc32(0L, Z_NULL, 0); + *tot = 0; +} + +/* Copy the compressed data from name, zeroing the last block bit of the last + block if clr is true, and adding empty blocks as needed to get to a byte + boundary. If clr is false, then the last block becomes the last block of + the output, and the gzip trailer is written. crc and tot maintains the + crc and length (modulo 2^32) of the output for the trailer. The resulting + gzip file is written to out. gzinit() must be called before the first call + of gzcopy() to write the gzip header and to initialize crc and tot. */ +local void gzcopy(char *name, int clr, unsigned long *crc, unsigned long *tot, + FILE *out) +{ + int ret; /* return value from zlib functions */ + int pos; /* where the "last block" bit is in byte */ + int last; /* true if processing the last block */ + bin *in; /* buffered input file */ + unsigned char *start; /* start of compressed data in buffer */ + unsigned char *junk; /* buffer for uncompressed data -- discarded */ + z_off_t len; /* length of uncompressed data (support > 4 GB) */ + z_stream strm; /* zlib inflate stream */ + + /* open gzip file and skip header */ + in = bopen(name); + if (in == NULL) + bail("could not open ", name); + gzhead(in); + + /* allocate buffer for uncompressed data and initialize raw inflate + stream */ + junk = malloc(CHUNK); + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = 0; + strm.next_in = Z_NULL; + ret = inflateInit2(&strm, -15); + if (junk == NULL || ret != Z_OK) + bail("out of memory", ""); + + /* inflate and copy compressed data, clear last-block bit if requested */ + len = 0; + zpull(&strm, in); + start = strm.next_in; + last = start[0] & 1; + if (last && clr) + start[0] &= ~1; + strm.avail_out = 0; + for (;;) { + /* if input used and output done, write used input and get more */ + if (strm.avail_in == 0 && strm.avail_out != 0) { + fwrite(start, 1, strm.next_in - start, out); + start = in->buf; + in->left = 0; + zpull(&strm, in); + } + + /* decompress -- return early when end-of-block reached */ + strm.avail_out = CHUNK; + strm.next_out = junk; + ret = inflate(&strm, Z_BLOCK); + switch (ret) { + case Z_MEM_ERROR: + bail("out of memory", ""); + case Z_DATA_ERROR: + bail("invalid compressed data in ", in->name); + } + + /* update length of uncompressed data */ + len += CHUNK - strm.avail_out; + + /* check for block boundary (only get this when block copied out) */ + if (strm.data_type & 128) { + /* if that was the last block, then done */ + if (last) + break; + + /* number of unused bits in last byte */ + pos = strm.data_type & 7; + + /* find the next last-block bit */ + if (pos != 0) { + /* next last-block bit is in last used byte */ + pos = 0x100 >> pos; + last = strm.next_in[-1] & pos; + if (last && clr) + strm.next_in[-1] &= ~pos; + } + else { + /* next last-block bit is in next unused byte */ + if (strm.avail_in == 0) { + /* don't have that byte yet -- get it */ + fwrite(start, 1, strm.next_in - start, out); + start = in->buf; + in->left = 0; + zpull(&strm, in); + } + last = strm.next_in[0] & 1; + if (last && clr) + strm.next_in[0] &= ~1; + } + } + } + + /* update buffer with unused input */ + in->left = strm.avail_in; + in->next = strm.next_in; + + /* copy used input, write empty blocks to get to byte boundary */ + pos = strm.data_type & 7; + fwrite(start, 1, in->next - start - 1, out); + last = in->next[-1]; + if (pos == 0 || !clr) + /* already at byte boundary, or last file: write last byte */ + putc(last, out); + else { + /* append empty blocks to last byte */ + last &= ((0x100 >> pos) - 1); /* assure unused bits are zero */ + if (pos & 1) { + /* odd -- append an empty stored block */ + putc(last, out); + if (pos == 1) + putc(0, out); /* two more bits in block header */ + fwrite("\0\0\xff\xff", 1, 4, out); + } + else { + /* even -- append 1, 2, or 3 empty fixed blocks */ + switch (pos) { + case 6: + putc(last | 8, out); + last = 0; + case 4: + putc(last | 0x20, out); + last = 0; + case 2: + putc(last | 0x80, out); + putc(0, out); + } + } + } + + /* update crc and tot */ + *crc = crc32_combine(*crc, bget4(in), len); + *tot += (unsigned long)len; + + /* clean up */ + inflateEnd(&strm); + free(junk); + bclose(in); + + /* write trailer if this is the last gzip file */ + if (!clr) { + put4(*crc, out); + put4(*tot, out); + } +} + +/* join the gzip files on the command line, write result to stdout */ +int main(int argc, char **argv) +{ + unsigned long crc, tot; /* running crc and total uncompressed length */ + + /* skip command name */ + argc--; + argv++; + + /* show usage if no arguments */ + if (argc == 0) { + fputs("gzjoin usage: gzjoin f1.gz [f2.gz [f3.gz ...]] > fjoin.gz\n", + stderr); + return 0; + } + + /* join gzip files on command line and write to stdout */ + gzinit(&crc, &tot, stdout); + while (argc--) + gzcopy(*argv++, argc, &crc, &tot, stdout); + + /* done */ + return 0; +} diff --git a/gdcm/Utilities/gdcmzlib/examples/gzlog.c b/gdcm/Utilities/gdcmzlib/examples/gzlog.c new file mode 100644 index 0000000..f71f817 --- /dev/null +++ b/gdcm/Utilities/gdcmzlib/examples/gzlog.c @@ -0,0 +1,413 @@ +/* + * gzlog.c + * Copyright (C) 2004 Mark Adler + * For conditions of distribution and use, see copyright notice in gzlog.h + * version 1.0, 26 Nov 2004 + * + */ + +#include /* memcmp() */ +#include /* malloc(), free(), NULL */ +#include /* size_t, off_t */ +#include /* read(), close(), sleep(), ftruncate(), */ + /* lseek() */ +#include /* open() */ +#include /* flock() */ +#include "zlib.h" /* deflateInit2(), deflate(), deflateEnd() */ + +#include "gzlog.h" /* interface */ +#define local static + +/* log object structure */ +typedef struct { + int id; /* object identifier */ + int fd; /* log file descriptor */ + off_t extra; /* offset of extra "ap" subfield */ + off_t mark_off; /* offset of marked data */ + off_t last_off; /* offset of last block */ + unsigned long crc; /* uncompressed crc */ + unsigned long len; /* uncompressed length (modulo 2^32) */ + unsigned stored; /* length of current stored block */ +} gz_log; + +#define GZLOGID 19334 /* gz_log object identifier */ + +#define LOCK_RETRY 1 /* retry lock once a second */ +#define LOCK_PATIENCE 1200 /* try about twenty minutes before forcing */ + +/* acquire a lock on a file */ +local int lock(int fd) +{ + int patience; + + /* try to lock every LOCK_RETRY seconds for LOCK_PATIENCE seconds */ + patience = LOCK_PATIENCE; + do { + if (flock(fd, LOCK_EX + LOCK_NB) == 0) + return 0; + (void)sleep(LOCK_RETRY); + patience -= LOCK_RETRY; + } while (patience > 0); + + /* we've run out of patience -- give up */ + return -1; +} + +/* release lock */ +local void unlock(int fd) +{ + (void)flock(fd, LOCK_UN); +} + +/* release a log object */ +local void log_clean(gz_log *log) +{ + unlock(log->fd); + (void)close(log->fd); + free(log); +} + +/* read an unsigned long from a byte buffer little-endian */ +local unsigned long make_ulg(unsigned char *buf) +{ + int n; + unsigned long val; + + val = (unsigned long)(*buf++); + for (n = 8; n < 32; n += 8) + val += (unsigned long)(*buf++) << n; + return val; +} + +/* read an off_t from a byte buffer little-endian */ +local off_t make_off(unsigned char *buf) +{ + int n; + off_t val; + + val = (off_t)(*buf++); + for (n = 8; n < 64; n += 8) + val += (off_t)(*buf++) << n; + return val; +} + +/* write an unsigned long little-endian to byte buffer */ +local void dice_ulg(unsigned long val, unsigned char *buf) +{ + int n; + + for (n = 0; n < 4; n++) { + *buf++ = val & 0xff; + val >>= 8; + } +} + +/* write an off_t little-endian to byte buffer */ +local void dice_off(off_t val, unsigned char *buf) +{ + int n; + + for (n = 0; n < 8; n++) { + *buf++ = val & 0xff; + val >>= 8; + } +} + +/* initial, empty gzip file for appending */ +local char empty_gz[] = { + 0x1f, 0x8b, /* magic gzip id */ + 8, /* compression method is deflate */ + 4, /* there is an extra field */ + 0, 0, 0, 0, /* no modification time provided */ + 0, 0xff, /* no extra flags, no OS */ + 20, 0, 'a', 'p', 16, 0, /* extra field with "ap" subfield */ + 32, 0, 0, 0, 0, 0, 0, 0, /* offset of uncompressed data */ + 32, 0, 0, 0, 0, 0, 0, 0, /* offset of last block */ + 1, 0, 0, 0xff, 0xff, /* empty stored block (last) */ + 0, 0, 0, 0, /* crc */ + 0, 0, 0, 0 /* uncompressed length */ +}; + +/* initialize a log object with locking */ +void *gzlog_open(char *path) +{ + unsigned xlen; + unsigned char temp[20]; + unsigned sub_len; + int good; + gz_log *log; + + /* allocate log structure */ + log = malloc(sizeof(gz_log)); + if (log == NULL) + return NULL; + log->id = GZLOGID; + + /* open file, creating it if necessary, and locking it */ + log->fd = open(path, O_RDWR | O_CREAT, 0600); + if (log->fd < 0) { + free(log); + return NULL; + } + if (lock(log->fd)) { + close(log->fd); + free(log); + return NULL; + } + + /* if file is empty, write new gzip stream */ + if (lseek(log->fd, 0, SEEK_END) == 0) { + if (write(log->fd, empty_gz, sizeof(empty_gz)) != sizeof(empty_gz)) { + log_clean(log); + return NULL; + } + } + + /* check gzip header */ + (void)lseek(log->fd, 0, SEEK_SET); + if (read(log->fd, temp, 12) != 12 || temp[0] != 0x1f || + temp[1] != 0x8b || temp[2] != 8 || (temp[3] & 4) == 0) { + log_clean(log); + return NULL; + } + + /* process extra field to find "ap" sub-field */ + xlen = temp[10] + (temp[11] << 8); + good = 0; + while (xlen) { + if (xlen < 4 || read(log->fd, temp, 4) != 4) + break; + sub_len = temp[2]; + sub_len += temp[3] << 8; + xlen -= 4; + if (memcmp(temp, "ap", 2) == 0 && sub_len == 16) { + good = 1; + break; + } + if (xlen < sub_len) + break; + (void)lseek(log->fd, sub_len, SEEK_CUR); + xlen -= sub_len; + } + if (!good) { + log_clean(log); + return NULL; + } + + /* read in "ap" sub-field */ + log->extra = lseek(log->fd, 0, SEEK_CUR); + if (read(log->fd, temp, 16) != 16) { + log_clean(log); + return NULL; + } + log->mark_off = make_off(temp); + log->last_off = make_off(temp + 8); + + /* get crc, length of gzip file */ + (void)lseek(log->fd, log->last_off, SEEK_SET); + if (read(log->fd, temp, 13) != 13 || + memcmp(temp, "\001\000\000\377\377", 5) != 0) { + log_clean(log); + return NULL; + } + log->crc = make_ulg(temp + 5); + log->len = make_ulg(temp + 9); + + /* set up to write over empty last block */ + (void)lseek(log->fd, log->last_off + 5, SEEK_SET); + log->stored = 0; + return (void *)log; +} + +/* maximum amount to put in a stored block before starting a new one */ +#define MAX_BLOCK 16384 + +/* write a block to a log object */ +int gzlog_write(void *obj, char *data, size_t len) +{ + size_t some; + unsigned char temp[5]; + gz_log *log; + + /* check object */ + log = (gz_log *)obj; + if (log == NULL || log->id != GZLOGID) + return 1; + + /* write stored blocks until all of the input is written */ + do { + some = MAX_BLOCK - log->stored; + if (some > len) + some = len; + if (write(log->fd, data, some) != some) + return 1; + log->crc = crc32(log->crc, data, some); + log->len += some; + len -= some; + data += some; + log->stored += some; + + /* if the stored block is full, end it and start another */ + if (log->stored == MAX_BLOCK) { + (void)lseek(log->fd, log->last_off, SEEK_SET); + temp[0] = 0; + dice_ulg(log->stored + ((unsigned long)(~log->stored) << 16), + temp + 1); + if (write(log->fd, temp, 5) != 5) + return 1; + log->last_off = lseek(log->fd, log->stored, SEEK_CUR); + (void)lseek(log->fd, 5, SEEK_CUR); + log->stored = 0; + } + } while (len); + return 0; +} + +/* recompress the remaining stored deflate data in place */ +local int recomp(gz_log *log) +{ + z_stream strm; + size_t len, max; + unsigned char *in; + unsigned char *out; + unsigned char temp[16]; + + /* allocate space and read it all in (it's around 1 MB) */ + len = log->last_off - log->mark_off; + max = len + (len >> 12) + (len >> 14) + 11; + out = malloc(max); + if (out == NULL) + return 1; + in = malloc(len); + if (in == NULL) { + free(out); + return 1; + } + (void)lseek(log->fd, log->mark_off, SEEK_SET); + if (read(log->fd, in, len) != len) { + free(in); + free(out); + return 1; + } + + /* recompress in memory, decoding stored data as we go */ + /* note: this assumes that unsigned is four bytes or more */ + /* consider not making that assumption */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + if (deflateInit2(&strm, Z_BEST_COMPRESSION, Z_DEFLATED, -15, 8, + Z_DEFAULT_STRATEGY) != Z_OK) { + free(in); + free(out); + return 1; + } + strm.next_in = in; + strm.avail_out = max; + strm.next_out = out; + while (len >= 5) { + if (strm.next_in[0] != 0) + break; + strm.avail_in = strm.next_in[1] + (strm.next_in[2] << 8); + strm.next_in += 5; + len -= 5; + if (strm.avail_in != 0) { + if (len < strm.avail_in) + break; + len -= strm.avail_in; + (void)deflate(&strm, Z_NO_FLUSH); + if (strm.avail_in != 0 || strm.avail_out == 0) + break; + } + } + (void)deflate(&strm, Z_SYNC_FLUSH); + (void)deflateEnd(&strm); + free(in); + if (len != 0 || strm.avail_out == 0) { + free(out); + return 1; + } + + /* overwrite stored data with compressed data */ + (void)lseek(log->fd, log->mark_off, SEEK_SET); + len = max - strm.avail_out; + if (write(log->fd, out, len) != len) { + free(out); + return 1; + } + free(out); + + /* write last empty block, crc, and length */ + log->mark_off = log->last_off = lseek(log->fd, 0, SEEK_CUR); + temp[0] = 1; + dice_ulg(0xffffL << 16, temp + 1); + dice_ulg(log->crc, temp + 5); + dice_ulg(log->len, temp + 9); + if (write(log->fd, temp, 13) != 13) + return 1; + + /* truncate file to discard remaining stored data and old trailer */ + ftruncate(log->fd, lseek(log->fd, 0, SEEK_CUR)); + + /* update extra field to point to new last empty block */ + (void)lseek(log->fd, log->extra, SEEK_SET); + dice_off(log->mark_off, temp); + dice_off(log->last_off, temp + 8); + if (write(log->fd, temp, 16) != 16) + return 1; + return 0; +} + +/* maximum accumulation of stored blocks before compressing */ +#define MAX_STORED 1048576 + +/* close log object */ +int gzlog_close(void *obj) +{ + unsigned char temp[8]; + gz_log *log; + + /* check object */ + log = (gz_log *)obj; + if (log == NULL || log->id != GZLOGID) + return 1; + + /* go to start of most recent block being written */ + (void)lseek(log->fd, log->last_off, SEEK_SET); + + /* if some stuff was put there, update block */ + if (log->stored) { + temp[0] = 0; + dice_ulg(log->stored + ((unsigned long)(~log->stored) << 16), + temp + 1); + if (write(log->fd, temp, 5) != 5) + return 1; + log->last_off = lseek(log->fd, log->stored, SEEK_CUR); + } + + /* write last block (empty) */ + if (write(log->fd, "\001\000\000\377\377", 5) != 5) + return 1; + + /* write updated crc and uncompressed length */ + dice_ulg(log->crc, temp); + dice_ulg(log->len, temp + 4); + if (write(log->fd, temp, 8) != 8) + return 1; + + /* put offset of that last block in gzip extra block */ + (void)lseek(log->fd, log->extra + 8, SEEK_SET); + dice_off(log->last_off, temp); + if (write(log->fd, temp, 8) != 8) + return 1; + + /* if more than 1 MB stored, then time to compress it */ + if (log->last_off - log->mark_off > MAX_STORED) { + if (recomp(log)) + return 1; + } + + /* unlock and close file */ + log_clean(log); + return 0; +} diff --git a/gdcm/Utilities/gdcmzlib/examples/gzlog.h b/gdcm/Utilities/gdcmzlib/examples/gzlog.h new file mode 100644 index 0000000..a800bd5 --- /dev/null +++ b/gdcm/Utilities/gdcmzlib/examples/gzlog.h @@ -0,0 +1,58 @@ +/* gzlog.h + Copyright (C) 2004 Mark Adler, all rights reserved + version 1.0, 26 Nov 2004 + + This software is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Mark Adler madler@alumni.caltech.edu + */ + +/* + The gzlog object allows writing short messages to a gzipped log file, + opening the log file locked for small bursts, and then closing it. The log + object works by appending stored data to the gzip file until 1 MB has been + accumulated. At that time, the stored data is compressed, and replaces the + uncompressed data in the file. The log file is truncated to its new size at + that time. After closing, the log file is always valid gzip file that can + decompressed to recover what was written. + + A gzip header "extra" field contains two file offsets for appending. The + first points to just after the last compressed data. The second points to + the last stored block in the deflate stream, which is empty. All of the + data between those pointers is uncompressed. + */ + +/* Open a gzlog object, creating the log file if it does not exist. Return + NULL on error. Note that gzlog_open() could take a long time to return if + there is difficulty in locking the file. */ +void *gzlog_open(char *path); + +/* Write to a gzlog object. Return non-zero on error. This function will + simply write data to the file uncompressed. Compression of the data + will not occur until gzlog_close() is called. It is expected that + gzlog_write() is used for a short message, and then gzlog_close() is + called. If a large amount of data is to be written, then the application + should write no more than 1 MB at a time with gzlog_write() before + calling gzlog_close() and then gzlog_open() again. */ +int gzlog_write(void *log, char *data, size_t len); + +/* Close a gzlog object. Return non-zero on error. The log file is locked + until this function is called. This function will compress stored data + at the end of the gzip file if at least 1 MB has been accumulated. Note + that the file will not be a valid gzip file until this function completes. + */ +int gzlog_close(void *log); diff --git a/gdcm/Utilities/gdcmzlib/examples/zlib_how.html b/gdcm/Utilities/gdcmzlib/examples/zlib_how.html new file mode 100644 index 0000000..40998db --- /dev/null +++ b/gdcm/Utilities/gdcmzlib/examples/zlib_how.html @@ -0,0 +1,523 @@ + + + + +zlib Usage Example + + + +

    zlib Usage Example

    +We often get questions about how the deflate() and inflate() functions should be used. +Users wonder when they should provide more input, when they should use more output, +what to do with a Z_BUF_ERROR, how to make sure the process terminates properly, and +so on. So for those who have read zlib.h (a few times), and +would like further edification, below is an annotated example in C of simple routines to compress and decompress +from an input file to an output file using deflate() and inflate() respectively. The +annotations are interspersed between lines of the code. So please read between the lines. +We hope this helps explain some of the intricacies of zlib. +

    +Without further adieu, here is the program zpipe.c: +

    
    +/* zpipe.c: example of proper use of zlib's inflate() and deflate()
    +   Not copyrighted -- provided to the public domain
    +   Version 1.2  9 November 2004  Mark Adler */
    +
    +/* Version history:
    +   1.0  30 Oct 2004  First version
    +   1.1   8 Nov 2004  Add void casting for unused return values
    +                     Use switch statement for inflate() return values
    +   1.2   9 Nov 2004  Add assertions to document zlib guarantees
    + */
    +
    +We now include the header files for the required definitions. From +stdio.h we use fopen(), fread(), fwrite(), +feof(), ferror(), and fclose() for file i/o, and +fputs() for error messages. From string.h we use +strcmp() for command line argument processing. +From assert.h we use the assert() macro. +From zlib.h +we use the basic compression functions deflateInit(), +deflate(), and deflateEnd(), and the basic decompression +functions inflateInit(), inflate(), and +inflateEnd(). +
    
    +#include <stdio.h>
    +#include <string.h>
    +#include <assert.h>
    +#include "zlib.h"
    +
    +CHUNK is simply the buffer size for feeding data to and pulling data +from the zlib routines. Larger buffer sizes would be more efficient, +especially for inflate(). If the memory is available, buffers sizes +on the order of 128K or 256K bytes should be used. +
    
    +#define CHUNK 16384
    +
    +The def() routine compresses data from an input file to an output file. The output data +will be in the zlib format, which is different from the gzip or zip +formats. The zlib format has a very small header of only two bytes to identify it as +a zlib stream and to provide decoding information, and a four-byte trailer with a fast +check value to verify the integrity of the uncompressed data after decoding. +
    
    +/* Compress from file source to file dest until EOF on source.
    +   def() returns Z_OK on success, Z_MEM_ERROR if memory could not be
    +   allocated for processing, Z_STREAM_ERROR if an invalid compression
    +   level is supplied, Z_VERSION_ERROR if the version of zlib.h and the
    +   version of the library linked do not match, or Z_ERRNO if there is
    +   an error reading or writing the files. */
    +int def(FILE *source, FILE *dest, int level)
    +{
    +
    +Here are the local variables for def(). ret will be used for zlib +return codes. flush will keep track of the current flushing state for deflate(), +which is either no flushing, or flush to completion after the end of the input file is reached. +have is the amount of data returned from deflate(). The strm structure +is used to pass information to and from the zlib routines, and to maintain the +deflate() state. in and out are the input and output buffers for +deflate(). +
    
    +    int ret, flush;
    +    unsigned have;
    +    z_stream strm;
    +    char in[CHUNK];
    +    char out[CHUNK];
    +
    +The first thing we do is to initialize the zlib state for compression using +deflateInit(). This must be done before the first use of deflate(). +The zalloc, zfree, and opaque fields in the strm +structure must be initialized before calling deflateInit(). Here they are +set to the zlib constant Z_NULL to request that zlib use +the default memory allocation routines. An application may also choose to provide +custom memory allocation routines here. deflateInit() will allocate on the +order of 256K bytes for the internal state. +(See zlib Technical Details.) +

    +deflateInit() is called with a pointer to the structure to be initialized and +the compression level, which is an integer in the range of -1 to 9. Lower compression +levels result in faster execution, but less compression. Higher levels result in +greater compression, but slower execution. The zlib constant Z_DEFAULT_COMPRESSION, +equal to -1, +provides a good compromise between compression and speed and is equivalent to level 6. +Level 0 actually does no compression at all, and in fact expands the data slightly to produce +the zlib format (it is not a byte-for-byte copy of the input). +More advanced applications of zlib +may use deflateInit2() here instead. Such an application may want to reduce how +much memory will be used, at some price in compression. Or it may need to request a +gzip header and trailer instead of a zlib header and trailer, or raw +encoding with no header or trailer at all. +

    +We must check the return value of deflateInit() against the zlib constant +Z_OK to make sure that it was able to +allocate memory for the internal state, and that the provided arguments were valid. +deflateInit() will also check that the version of zlib that the zlib.h +file came from matches the version of zlib actually linked with the program. This +is especially important for environments in which zlib is a shared library. +

    +Note that an application can initialize multiple, independent zlib streams, which can +operate in parallel. The state information maintained in the structure allows the zlib +routines to be reentrant. +

    
    +    /* allocate deflate state */
    +    strm.zalloc = Z_NULL;
    +    strm.zfree = Z_NULL;
    +    strm.opaque = Z_NULL;
    +    ret = deflateInit(&strm, level);
    +    if (ret != Z_OK)
    +        return ret;
    +
    +With the pleasantries out of the way, now we can get down to business. The outer do-loop +reads all of the input file and exits at the bottom of the loop once end-of-file is reached. +This loop contains the only call of deflate(). So we must make sure that all of the +input data has been processed and that all of the output data has been generated and consumed +before we fall out of the loop at the bottom. +
    
    +    /* compress until end of file */
    +    do {
    +
    +We start off by reading data from the input file. The number of bytes read is put directly +into avail_in, and a pointer to those bytes is put into next_in. We also +check to see if end-of-file on the input has been reached. If we are at the end of file, then flush is set to the +zlib constant Z_FINISH, which is later passed to deflate() to +indicate that this is the last chunk of input data to compress. We need to use feof() +to check for end-of-file as opposed to seeing if fewer than CHUNK bytes have been read. The +reason is that if the input file length is an exact multiple of CHUNK, we will miss +the fact that we got to the end-of-file, and not know to tell deflate() to finish +up the compressed stream. If we are not yet at the end of the input, then the zlib +constant Z_NO_FLUSH will be passed to deflate to indicate that we are still +in the middle of the uncompressed data. +

    +If there is an error in reading from the input file, the process is aborted with +deflateEnd() being called to free the allocated zlib state before returning +the error. We wouldn't want a memory leak, now would we? deflateEnd() can be called +at any time after the state has been initialized. Once that's done, deflateInit() (or +deflateInit2()) would have to be called to start a new compression process. There is +no point here in checking the deflateEnd() return code. The deallocation can't fail. +

    
    +        strm.avail_in = fread(in, 1, CHUNK, source);
    +        if (ferror(source)) {
    +            (void)deflateEnd(&strm);
    +            return Z_ERRNO;
    +        }
    +        flush = feof(source) ? Z_FINISH : Z_NO_FLUSH;
    +        strm.next_in = in;
    +
    +The inner do-loop passes our chunk of input data to deflate(), and then +keeps calling deflate() until it is done producing output. Once there is no more +new output, deflate() is guaranteed to have consumed all of the input, i.e., +avail_in will be zero. +
    
    +        /* run deflate() on input until output buffer not full, finish
    +           compression if all of source has been read in */
    +        do {
    +
    +Output space is provided to deflate() by setting avail_out to the number +of available output bytes and next_out to a pointer to that space. +
    
    +            strm.avail_out = CHUNK;
    +            strm.next_out = out;
    +
    +Now we call the compression engine itself, deflate(). It takes as many of the +avail_in bytes at next_in as it can process, and writes as many as +avail_out bytes to next_out. Those counters and pointers are then +updated past the input data consumed and the output data written. It is the amount of +output space available that may limit how much input is consumed. +Hence the inner loop to make sure that +all of the input is consumed by providing more output space each time. Since avail_in +and next_in are updated by deflate(), we don't have to mess with those +between deflate() calls until it's all used up. +

    +The parameters to deflate() are a pointer to the strm structure containing +the input and output information and the internal compression engine state, and a parameter +indicating whether and how to flush data to the output. Normally deflate will consume +several K bytes of input data before producing any output (except for the header), in order +to accumulate statistics on the data for optimum compression. It will then put out a burst of +compressed data, and proceed to consume more input before the next burst. Eventually, +deflate() +must be told to terminate the stream, complete the compression with provided input data, and +write out the trailer check value. deflate() will continue to compress normally as long +as the flush parameter is Z_NO_FLUSH. Once the Z_FINISH parameter is provided, +deflate() will begin to complete the compressed output stream. However depending on how +much output space is provided, deflate() may have to be called several times until it +has provided the complete compressed stream, even after it has consumed all of the input. The flush +parameter must continue to be Z_FINISH for those subsequent calls. +

    +There are other values of the flush parameter that are used in more advanced applications. You can +force deflate() to produce a burst of output that encodes all of the input data provided +so far, even if it wouldn't have otherwise, for example to control data latency on a link with +compressed data. You can also ask that deflate() do that as well as erase any history up to +that point so that what follows can be decompressed independently, for example for random access +applications. Both requests will degrade compression by an amount depending on how often such +requests are made. +

    +deflate() has a return value that can indicate errors, yet we do not check it here. Why +not? Well, it turns out that deflate() can do no wrong here. Let's go through +deflate()'s return values and dispense with them one by one. The possible values are +Z_OK, Z_STREAM_END, Z_STREAM_ERROR, or Z_BUF_ERROR. Z_OK +is, well, ok. Z_STREAM_END is also ok and will be returned for the last call of +deflate(). This is already guaranteed by calling deflate() with Z_FINISH +until it has no more output. Z_STREAM_ERROR is only possible if the stream is not +initialized properly, but we did initialize it properly. There is no harm in checking for +Z_STREAM_ERROR here, for example to check for the possibility that some +other part of the application inadvertently clobbered the memory containing the zlib state. +Z_BUF_ERROR will be explained further below, but +suffice it to say that this is simply an indication that deflate() could not consume +more input or produce more output. deflate() can be called again with more output space +or more available input, which it will be in this code. +

    
    +            ret = deflate(&strm, flush);    /* no bad return value */
    +            assert(ret != Z_STREAM_ERROR);  /* state not clobbered */
    +
    +Now we compute how much output deflate() provided on the last call, which is the +difference between how much space was provided before the call, and how much output space +is still available after the call. Then that data, if any, is written to the output file. +We can then reuse the output buffer for the next call of deflate(). Again if there +is a file i/o error, we call deflateEnd() before returning to avoid a memory leak. +
    
    +            have = CHUNK - strm.avail_out;
    +            if (fwrite(out, 1, have, dest) != have || ferror(dest)) {
    +                (void)deflateEnd(&strm);
    +                return Z_ERRNO;
    +            }
    +
    +The inner do-loop is repeated until the last deflate() call fails to fill the +provided output buffer. Then we know that deflate() has done as much as it can with +the provided input, and that all of that input has been consumed. We can then fall out of this +loop and reuse the input buffer. +

    +The way we tell that deflate() has no more output is by seeing that it did not fill +the output buffer, leaving avail_out greater than zero. However suppose that +deflate() has no more output, but just so happened to exactly fill the output buffer! +avail_out is zero, and we can't tell that deflate() has done all it can. +As far as we know, deflate() +has more output for us. So we call it again. But now deflate() produces no output +at all, and avail_out remains unchanged as CHUNK. That deflate() call +wasn't able to do anything, either consume input or produce output, and so it returns +Z_BUF_ERROR. (See, I told you I'd cover this later.) However this is not a problem at +all. Now we finally have the desired indication that deflate() is really done, +and so we drop out of the inner loop to provide more input to deflate(). +

    +With flush set to Z_FINISH, this final set of deflate() calls will +complete the output stream. Once that is done, subsequent calls of deflate() would return +Z_STREAM_ERROR if the flush parameter is not Z_FINISH, and do no more processing +until the state is reinitialized. +

    +Some applications of zlib have two loops that call deflate() +instead of the single inner loop we have here. The first loop would call +without flushing and feed all of the data to deflate(). The second loop would call +deflate() with no more +data and the Z_FINISH parameter to complete the process. As you can see from this +example, that can be avoided by simply keeping track of the current flush state. +

    
    +        } while (strm.avail_out == 0);
    +        assert(strm.avail_in == 0);     /* all input will be used */
    +
    +Now we check to see if we have already processed all of the input file. That information was +saved in the flush variable, so we see if that was set to Z_FINISH. If so, +then we're done and we fall out of the outer loop. We're guaranteed to get Z_STREAM_END +from the last deflate() call, since we ran it until the last chunk of input was +consumed and all of the output was generated. +
    
    +        /* done when last data in file processed */
    +    } while (flush != Z_FINISH);
    +    assert(ret == Z_STREAM_END);        /* stream will be complete */
    +
    +The process is complete, but we still need to deallocate the state to avoid a memory leak +(or rather more like a memory hemorrhage if you didn't do this). Then +finally we can return with a happy return value. +
    
    +    /* clean up and return */
    +    (void)deflateEnd(&strm);
    +    return Z_OK;
    +}
    +
    +Now we do the same thing for decompression in the inf() routine. inf() +decompresses what is hopefully a valid zlib stream from the input file and writes the +uncompressed data to the output file. Much of the discussion above for def() +applies to inf() as well, so the discussion here will focus on the differences between +the two. +
    
    +/* Decompress from file source to file dest until stream ends or EOF.
    +   inf() returns Z_OK on success, Z_MEM_ERROR if memory could not be
    +   allocated for processing, Z_DATA_ERROR if the deflate data is
    +   invalid or incomplete, Z_VERSION_ERROR if the version of zlib.h and
    +   the version of the library linked do not match, or Z_ERRNO if there
    +   is an error reading or writing the files. */
    +int inf(FILE *source, FILE *dest)
    +{
    +
    +The local variables have the same functionality as they do for def(). The +only difference is that there is no flush variable, since inflate() +can tell from the zlib stream itself when the stream is complete. +
    
    +    int ret;
    +    unsigned have;
    +    z_stream strm;
    +    char in[CHUNK];
    +    char out[CHUNK];
    +
    +The initialization of the state is the same, except that there is no compression level, +of course, and two more elements of the structure are initialized. avail_in +and next_in must be initialized before calling inflateInit(). This +is because the application has the option to provide the start of the zlib stream in +order for inflateInit() to have access to information about the compression +method to aid in memory allocation. In the current implementation of zlib +(up through versions 1.2.x), the method-dependent memory allocations are deferred to the first call of +inflate() anyway. However those fields must be initialized since later versions +of zlib that provide more compression methods may take advantage of this interface. +In any case, no decompression is performed by inflateInit(), so the +avail_out and next_out fields do not need to be initialized before calling. +

    +Here avail_in is set to zero and next_in is set to Z_NULL to +indicate that no input data is being provided. +

    
    +    /* allocate inflate state */
    +    strm.zalloc = Z_NULL;
    +    strm.zfree = Z_NULL;
    +    strm.opaque = Z_NULL;
    +    strm.avail_in = 0;
    +    strm.next_in = Z_NULL;
    +    ret = inflateInit(&strm);
    +    if (ret != Z_OK)
    +        return ret;
    +
    +The outer do-loop decompresses input until inflate() indicates +that it has reached the end of the compressed data and has produced all of the uncompressed +output. This is in contrast to def() which processes all of the input file. +If end-of-file is reached before the compressed data self-terminates, then the compressed +data is incomplete and an error is returned. +
    
    +    /* decompress until deflate stream ends or end of file */
    +    do {
    +
    +We read input data and set the strm structure accordingly. If we've reached the +end of the input file, then we leave the outer loop and report an error, since the +compressed data is incomplete. Note that we may read more data than is eventually consumed +by inflate(), if the input file continues past the zlib stream. +For applications where zlib streams are embedded in other data, this routine would +need to be modified to return the unused data, or at least indicate how much of the input +data was not used, so the application would know where to pick up after the zlib stream. +
    
    +        strm.avail_in = fread(in, 1, CHUNK, source);
    +        if (ferror(source)) {
    +            (void)inflateEnd(&strm);
    +            return Z_ERRNO;
    +        }
    +        if (strm.avail_in == 0)
    +            break;
    +        strm.next_in = in;
    +
    +The inner do-loop has the same function it did in def(), which is to +keep calling inflate() until has generated all of the output it can with the +provided input. +
    
    +        /* run inflate() on input until output buffer not full */
    +        do {
    +
    +Just like in def(), the same output space is provided for each call of inflate(). +
    
    +            strm.avail_out = CHUNK;
    +            strm.next_out = out;
    +
    +Now we run the decompression engine itself. There is no need to adjust the flush parameter, since +the zlib format is self-terminating. The main difference here is that there are +return values that we need to pay attention to. Z_DATA_ERROR +indicates that inflate() detected an error in the zlib compressed data format, +which means that either the data is not a zlib stream to begin with, or that the data was +corrupted somewhere along the way since it was compressed. The other error to be processed is +Z_MEM_ERROR, which can occur since memory allocation is deferred until inflate() +needs it, unlike deflate(), whose memory is allocated at the start by deflateInit(). +

    +Advanced applications may use +deflateSetDictionary() to prime deflate() with a set of likely data to improve the +first 32K or so of compression. This is noted in the zlib header, so inflate() +requests that that dictionary be provided before it can start to decompress. Without the dictionary, +correct decompression is not possible. For this routine, we have no idea what the dictionary is, +so the Z_NEED_DICT indication is converted to a Z_DATA_ERROR. +

    +inflate() can also return Z_STREAM_ERROR, which should not be possible here, +but could be checked for as noted above for def(). Z_BUF_ERROR does not need to be +checked for here, for the same reasons noted for def(). Z_STREAM_END will be +checked for later. +

    
    +            ret = inflate(&strm, Z_NO_FLUSH);
    +            assert(ret != Z_STREAM_ERROR);  /* state not clobbered */
    +            switch (ret) {
    +            case Z_NEED_DICT:
    +                ret = Z_DATA_ERROR;     /* and fall through */
    +            case Z_DATA_ERROR:
    +            case Z_MEM_ERROR:
    +                (void)inflateEnd(&strm);
    +                return ret;
    +            }
    +
    +The output of inflate() is handled identically to that of deflate(). +
    
    +            have = CHUNK - strm.avail_out;
    +            if (fwrite(out, 1, have, dest) != have || ferror(dest)) {
    +                (void)inflateEnd(&strm);
    +                return Z_ERRNO;
    +            }
    +
    +The inner do-loop ends when inflate() has no more output as indicated +by not filling the output buffer, just as for deflate(). In this case, we cannot +assert that strm.avail_in will be zero, since the deflate stream may end before the file +does. +
    
    +        } while (strm.avail_out == 0);
    +
    +The outer do-loop ends when inflate() reports that it has reached the +end of the input zlib stream, has completed the decompression and integrity +check, and has provided all of the output. This is indicated by the inflate() +return value Z_STREAM_END. The inner loop is guaranteed to leave ret +equal to Z_STREAM_END if the last chunk of the input file read contained the end +of the zlib stream. So if the return value is not Z_STREAM_END, the +loop continues to read more input. +
    
    +        /* done when inflate() says it's done */
    +    } while (ret != Z_STREAM_END);
    +
    +At this point, decompression successfully completed, or we broke out of the loop due to no +more data being available from the input file. If the last inflate() return value +is not Z_STREAM_END, then the zlib stream was incomplete and a data error +is returned. Otherwise, we return with a happy return value. Of course, inflateEnd() +is called first to avoid a memory leak. +
    
    +    /* clean up and return */
    +    (void)inflateEnd(&strm);
    +    return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
    +}
    +
    +That ends the routines that directly use zlib. The following routines make this +a command-line program by running data through the above routines from stdin to +stdout, and handling any errors reported by def() or inf(). +

    +zerr() is used to interpret the possible error codes from def() +and inf(), as detailed in their comments above, and print out an error message. +Note that these are only a subset of the possible return values from deflate() +and inflate(). +

    
    +/* report a zlib or i/o error */
    +void zerr(int ret)
    +{
    +    fputs("zpipe: ", stderr);
    +    switch (ret) {
    +    case Z_ERRNO:
    +        if (ferror(stdin))
    +            fputs("error reading stdin\n", stderr);
    +        if (ferror(stdout))
    +            fputs("error writing stdout\n", stderr);
    +        break;
    +    case Z_STREAM_ERROR:
    +        fputs("invalid compression level\n", stderr);
    +        break;
    +    case Z_DATA_ERROR:
    +        fputs("invalid or incomplete deflate data\n", stderr);
    +        break;
    +    case Z_MEM_ERROR:
    +        fputs("out of memory\n", stderr);
    +        break;
    +    case Z_VERSION_ERROR:
    +        fputs("zlib version mismatch!\n", stderr);
    +    }
    +}
    +
    +Here is the main() routine used to test def() and inf(). The +zpipe command is simply a compression pipe from stdin to stdout, if +no arguments are given, or it is a decompression pipe if zpipe -d is used. If any other +arguments are provided, no compression or decompression is performed. Instead a usage +message is displayed. Examples are zpipe < foo.txt > foo.txt.z to compress, and +zpipe -d < foo.txt.z > foo.txt to decompress. +
    
    +/* compress or decompress from stdin to stdout */
    +int main(int argc, char **argv)
    +{
    +    int ret;
    +
    +    /* do compression if no arguments */
    +    if (argc == 1) {
    +        ret = def(stdin, stdout, Z_DEFAULT_COMPRESSION);
    +        if (ret != Z_OK)
    +            zerr(ret);
    +        return ret;
    +    }
    +
    +    /* do decompression if -d specified */
    +    else if (argc == 2 && strcmp(argv[1], "-d") == 0) {
    +        ret = inf(stdin, stdout);
    +        if (ret != Z_OK)
    +            zerr(ret);
    +        return ret;
    +    }
    +
    +    /* otherwise, report usage */
    +    else {
    +        fputs("zpipe usage: zpipe [-d] < source > dest\n", stderr);
    +        return 1;
    +    }
    +}
    +
    +
    +Copyright (c) 2004 by Mark Adler
    Last modified 13 November 2004
    + + diff --git a/gdcm/Utilities/gdcmzlib/examples/zpipe.c b/gdcm/Utilities/gdcmzlib/examples/zpipe.c new file mode 100644 index 0000000..26abb56 --- /dev/null +++ b/gdcm/Utilities/gdcmzlib/examples/zpipe.c @@ -0,0 +1,191 @@ +/* zpipe.c: example of proper use of zlib's inflate() and deflate() + Not copyrighted -- provided to the public domain + Version 1.2 9 November 2004 Mark Adler */ + +/* Version history: + 1.0 30 Oct 2004 First version + 1.1 8 Nov 2004 Add void casting for unused return values + Use switch statement for inflate() return values + 1.2 9 Nov 2004 Add assertions to document zlib guarantees + 1.3 6 Apr 2005 Remove incorrect assertion in inf() + */ + +#include +#include +#include +#include "zlib.h" + +#define CHUNK 16384 + +/* Compress from file source to file dest until EOF on source. + def() returns Z_OK on success, Z_MEM_ERROR if memory could not be + allocated for processing, Z_STREAM_ERROR if an invalid compression + level is supplied, Z_VERSION_ERROR if the version of zlib.h and the + version of the library linked do not match, or Z_ERRNO if there is + an error reading or writing the files. */ +int def(FILE *source, FILE *dest, int level) +{ + int ret, flush; + unsigned have; + z_stream strm; + char in[CHUNK]; + char out[CHUNK]; + + /* allocate deflate state */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + ret = deflateInit(&strm, level); + if (ret != Z_OK) + return ret; + + /* compress until end of file */ + do { + strm.avail_in = fread(in, 1, CHUNK, source); + if (ferror(source)) { + (void)deflateEnd(&strm); + return Z_ERRNO; + } + flush = feof(source) ? Z_FINISH : Z_NO_FLUSH; + strm.next_in = in; + + /* run deflate() on input until output buffer not full, finish + compression if all of source has been read in */ + do { + strm.avail_out = CHUNK; + strm.next_out = out; + ret = deflate(&strm, flush); /* no bad return value */ + assert(ret != Z_STREAM_ERROR); /* state not clobbered */ + have = CHUNK - strm.avail_out; + if (fwrite(out, 1, have, dest) != have || ferror(dest)) { + (void)deflateEnd(&strm); + return Z_ERRNO; + } + } while (strm.avail_out == 0); + assert(strm.avail_in == 0); /* all input will be used */ + + /* done when last data in file processed */ + } while (flush != Z_FINISH); + assert(ret == Z_STREAM_END); /* stream will be complete */ + + /* clean up and return */ + (void)deflateEnd(&strm); + return Z_OK; +} + +/* Decompress from file source to file dest until stream ends or EOF. + inf() returns Z_OK on success, Z_MEM_ERROR if memory could not be + allocated for processing, Z_DATA_ERROR if the deflate data is + invalid or incomplete, Z_VERSION_ERROR if the version of zlib.h and + the version of the library linked do not match, or Z_ERRNO if there + is an error reading or writing the files. */ +int inf(FILE *source, FILE *dest) +{ + int ret; + unsigned have; + z_stream strm; + char in[CHUNK]; + char out[CHUNK]; + + /* allocate inflate state */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = 0; + strm.next_in = Z_NULL; + ret = inflateInit(&strm); + if (ret != Z_OK) + return ret; + + /* decompress until deflate stream ends or end of file */ + do { + strm.avail_in = fread(in, 1, CHUNK, source); + if (ferror(source)) { + (void)inflateEnd(&strm); + return Z_ERRNO; + } + if (strm.avail_in == 0) + break; + strm.next_in = in; + + /* run inflate() on input until output buffer not full */ + do { + strm.avail_out = CHUNK; + strm.next_out = out; + ret = inflate(&strm, Z_NO_FLUSH); + assert(ret != Z_STREAM_ERROR); /* state not clobbered */ + switch (ret) { + case Z_NEED_DICT: + ret = Z_DATA_ERROR; /* and fall through */ + case Z_DATA_ERROR: + case Z_MEM_ERROR: + (void)inflateEnd(&strm); + return ret; + } + have = CHUNK - strm.avail_out; + if (fwrite(out, 1, have, dest) != have || ferror(dest)) { + (void)inflateEnd(&strm); + return Z_ERRNO; + } + } while (strm.avail_out == 0); + + /* done when inflate() says it's done */ + } while (ret != Z_STREAM_END); + + /* clean up and return */ + (void)inflateEnd(&strm); + return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR; +} + +/* report a zlib or i/o error */ +void zerr(int ret) +{ + fputs("zpipe: ", stderr); + switch (ret) { + case Z_ERRNO: + if (ferror(stdin)) + fputs("error reading stdin\n", stderr); + if (ferror(stdout)) + fputs("error writing stdout\n", stderr); + break; + case Z_STREAM_ERROR: + fputs("invalid compression level\n", stderr); + break; + case Z_DATA_ERROR: + fputs("invalid or incomplete deflate data\n", stderr); + break; + case Z_MEM_ERROR: + fputs("out of memory\n", stderr); + break; + case Z_VERSION_ERROR: + fputs("zlib version mismatch!\n", stderr); + } +} + +/* compress or decompress from stdin to stdout */ +int main(int argc, char **argv) +{ + int ret; + + /* do compression if no arguments */ + if (argc == 1) { + ret = def(stdin, stdout, Z_DEFAULT_COMPRESSION); + if (ret != Z_OK) + zerr(ret); + return ret; + } + + /* do decompression if -d specified */ + else if (argc == 2 && strcmp(argv[1], "-d") == 0) { + ret = inf(stdin, stdout); + if (ret != Z_OK) + zerr(ret); + return ret; + } + + /* otherwise, report usage */ + else { + fputs("zpipe usage: zpipe [-d] < source > dest\n", stderr); + return 1; + } +} diff --git a/gdcm/Utilities/gdcmzlib/examples/zran.c b/gdcm/Utilities/gdcmzlib/examples/zran.c new file mode 100644 index 0000000..8c7717e --- /dev/null +++ b/gdcm/Utilities/gdcmzlib/examples/zran.c @@ -0,0 +1,404 @@ +/* zran.c -- example of zlib/gzip stream indexing and random access + * Copyright (C) 2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + Version 1.0 29 May 2005 Mark Adler */ + +/* Illustrate the use of Z_BLOCK, inflatePrime(), and inflateSetDictionary() + for random access of a compressed file. A file containing a zlib or gzip + stream is provided on the command line. The compressed stream is decoded in + its entirety, and an index built with access points about every SPAN bytes + in the uncompressed output. The compressed file is left open, and can then + be read randomly, having to decompress on the average SPAN/2 uncompressed + bytes before getting to the desired block of data. + + An access point can be created at the start of any deflate block, by saving + the starting file offset and bit of that block, and the 32K bytes of + uncompressed data that precede that block. Also the uncompressed offset of + that block is saved to provide a referece for locating a desired starting + point in the uncompressed stream. build_index() works by decompressing the + input zlib or gzip stream a block at a time, and at the end of each block + deciding if enough uncompressed data has gone by to justify the creation of + a new access point. If so, that point is saved in a data structure that + grows as needed to accommodate the points. + + To use the index, an offset in the uncompressed data is provided, for which + the latest accees point at or preceding that offset is located in the index. + The input file is positioned to the specified location in the index, and if + necessary the first few bits of the compressed data is read from the file. + inflate is initialized with those bits and the 32K of uncompressed data, and + the decompression then proceeds until the desired offset in the file is + reached. Then the decompression continues to read the desired uncompressed + data from the file. + + Another approach would be to generate the index on demand. In that case, + requests for random access reads from the compressed data would try to use + the index, but if a read far enough past the end of the index is required, + then further index entries would be generated and added. + + There is some fair bit of overhead to starting inflation for the random + access, mainly copying the 32K byte dictionary. So if small pieces of the + file are being accessed, it would make sense to implement a cache to hold + some lookahead and avoid many calls to extract() for small lengths. + + Another way to build an index would be to use inflateCopy(). That would + not be constrained to have access points at block boundaries, but requires + more memory per access point, and also cannot be saved to file due to the + use of pointers in the state. The approach here allows for storage of the + index in a file. + */ + +#include +#include +#include +#include "zlib.h" + +#define local static + +#define SPAN 1048576L /* desired distance between access points */ +#define WINSIZE 32768U /* sliding window size */ +#define CHUNK 16384 /* file input buffer size */ + +/* access point entry */ +struct point { + off_t out; /* corresponding offset in uncompressed data */ + off_t in; /* offset in input file of first full byte */ + int bits; /* number of bits (1-7) from byte at in - 1, or 0 */ + unsigned char window[WINSIZE]; /* preceding 32K of uncompressed data */ +}; + +/* access point list */ +struct access { + int have; /* number of list entries filled in */ + int size; /* number of list entries allocated */ + struct point *list; /* allocated list */ +}; + +/* Deallocate an index built by build_index() */ +local void free_index(struct access *index) +{ + if (index != NULL) { + free(index->list); + free(index); + } +} + +/* Add an entry to the access point list. If out of memory, deallocate the + existing list and return NULL. */ +local struct access *addpoint(struct access *index, int bits, + off_t in, off_t out, unsigned left, unsigned char *window) +{ + struct point *next; + + /* if list is empty, create it (start with eight points) */ + if (index == NULL) { + index = malloc(sizeof(struct access)); + if (index == NULL) return NULL; + index->list = malloc(sizeof(struct point) << 3); + if (index->list == NULL) { + free(index); + return NULL; + } + index->size = 8; + index->have = 0; + } + + /* if list is full, make it bigger */ + else if (index->have == index->size) { + index->size <<= 1; + next = realloc(index->list, sizeof(struct point) * index->size); + if (next == NULL) { + free_index(index); + return NULL; + } + index->list = next; + } + + /* fill in entry and increment how many we have */ + next = index->list + index->have; + next->bits = bits; + next->in = in; + next->out = out; + if (left) + memcpy(next->window, window + WINSIZE - left, left); + if (left < WINSIZE) + memcpy(next->window + left, window, WINSIZE - left); + index->have++; + + /* return list, possibly reallocated */ + return index; +} + +/* Make one entire pass through the compressed stream and build an index, with + access points about every span bytes of uncompressed output -- span is + chosen to balance the speed of random access against the memory requirements + of the list, about 32K bytes per access point. Note that data after the end + of the first zlib or gzip stream in the file is ignored. build_index() + returns the number of access points on success (>= 1), Z_MEM_ERROR for out + of memory, Z_DATA_ERROR for an error in the input file, or Z_ERRNO for a + file read error. On success, *built points to the resulting index. */ +local int build_index(FILE *in, off_t span, struct access **built) +{ + int ret; + off_t totin, totout; /* our own total counters to avoid 4GB limit */ + off_t last; /* totout value of last access point */ + struct access *index; /* access points being generated */ + z_stream strm; + unsigned char input[CHUNK]; + unsigned char window[WINSIZE]; + + /* initialize inflate */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = 0; + strm.next_in = Z_NULL; + ret = inflateInit2(&strm, 47); /* automatic zlib or gzip decoding */ + if (ret != Z_OK) + return ret; + + /* inflate the input, maintain a sliding window, and build an index -- this + also validates the integrity of the compressed data using the check + information at the end of the gzip or zlib stream */ + totin = totout = last = 0; + index = NULL; /* will be allocated by first addpoint() */ + strm.avail_out = 0; + do { + /* get some compressed data from input file */ + strm.avail_in = fread(input, 1, CHUNK, in); + if (ferror(in)) { + ret = Z_ERRNO; + goto build_index_error; + } + if (strm.avail_in == 0) { + ret = Z_DATA_ERROR; + goto build_index_error; + } + strm.next_in = input; + + /* process all of that, or until end of stream */ + do { + /* reset sliding window if necessary */ + if (strm.avail_out == 0) { + strm.avail_out = WINSIZE; + strm.next_out = window; + } + + /* inflate until out of input, output, or at end of block -- + update the total input and output counters */ + totin += strm.avail_in; + totout += strm.avail_out; + ret = inflate(&strm, Z_BLOCK); /* return at end of block */ + totin -= strm.avail_in; + totout -= strm.avail_out; + if (ret == Z_NEED_DICT) + ret = Z_DATA_ERROR; + if (ret == Z_MEM_ERROR || ret == Z_DATA_ERROR) + goto build_index_error; + if (ret == Z_STREAM_END) + break; + + /* if at end of block, consider adding an index entry (note that if + data_type indicates an end-of-block, then all of the + uncompressed data from that block has been delivered, and none + of the compressed data after that block has been consumed, + except for up to seven bits) -- the totout == 0 provides an + entry point after the zlib or gzip header, and assures that the + index always has at least one access point; we avoid creating an + access point after the last block by checking bit 6 of data_type + */ + if ((strm.data_type & 128) && !(strm.data_type & 64) && + (totout == 0 || totout - last > span)) { + index = addpoint(index, strm.data_type & 7, totin, + totout, strm.avail_out, window); + if (index == NULL) { + ret = Z_MEM_ERROR; + goto build_index_error; + } + last = totout; + } + } while (strm.avail_in != 0); + } while (ret != Z_STREAM_END); + + /* clean up and return index (release unused entries in list) */ + (void)inflateEnd(&strm); + index = realloc(index, sizeof(struct point) * index->have); + index->size = index->have; + *built = index; + return index->size; + + /* return error */ + build_index_error: + (void)inflateEnd(&strm); + if (index != NULL) + free_index(index); + return ret; +} + +/* Use the index to read len bytes from offset into buf, return bytes read or + negative for error (Z_DATA_ERROR or Z_MEM_ERROR). If data is requested past + the end of the uncompressed data, then extract() will return a value less + than len, indicating how much as actually read into buf. This function + should not return a data error unless the file was modified since the index + was generated. extract() may also return Z_ERRNO if there is an error on + reading or seeking the input file. */ +local int extract(FILE *in, struct access *index, off_t offset, + unsigned char *buf, int len) +{ + int ret, skip; + z_stream strm; + struct point *here; + unsigned char input[CHUNK]; + unsigned char discard[WINSIZE]; + + /* proceed only if something reasonable to do */ + if (len < 0) + return 0; + + /* find where in stream to start */ + here = index->list; + ret = index->have; + while (--ret && here[1].out <= offset) + here++; + + /* initialize file and inflate state to start there */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = 0; + strm.next_in = Z_NULL; + ret = inflateInit2(&strm, -15); /* raw inflate */ + if (ret != Z_OK) + return ret; + ret = fseeko(in, here->in - (here->bits ? 1 : 0), SEEK_SET); + if (ret == -1) + goto extract_ret; + if (here->bits) { + ret = getc(in); + if (ret == -1) { + ret = ferror(in) ? Z_ERRNO : Z_DATA_ERROR; + goto extract_ret; + } + (void)inflatePrime(&strm, here->bits, ret >> (8 - here->bits)); + } + (void)inflateSetDictionary(&strm, here->window, WINSIZE); + + /* skip uncompressed bytes until offset reached, then satisfy request */ + offset -= here->out; + strm.avail_in = 0; + skip = 1; /* while skipping to offset */ + do { + /* define where to put uncompressed data, and how much */ + if (offset == 0 && skip) { /* at offset now */ + strm.avail_out = len; + strm.next_out = buf; + skip = 0; /* only do this once */ + } + if (offset > WINSIZE) { /* skip WINSIZE bytes */ + strm.avail_out = WINSIZE; + strm.next_out = discard; + offset -= WINSIZE; + } + else if (offset != 0) { /* last skip */ + strm.avail_out = (unsigned)offset; + strm.next_out = discard; + offset = 0; + } + + /* uncompress until avail_out filled, or end of stream */ + do { + if (strm.avail_in == 0) { + strm.avail_in = fread(input, 1, CHUNK, in); + if (ferror(in)) { + ret = Z_ERRNO; + goto extract_ret; + } + if (strm.avail_in == 0) { + ret = Z_DATA_ERROR; + goto extract_ret; + } + strm.next_in = input; + } + ret = inflate(&strm, Z_NO_FLUSH); /* normal inflate */ + if (ret == Z_NEED_DICT) + ret = Z_DATA_ERROR; + if (ret == Z_MEM_ERROR || ret == Z_DATA_ERROR) + goto extract_ret; + if (ret == Z_STREAM_END) + break; + } while (strm.avail_out != 0); + + /* if reach end of stream, then don't keep trying to get more */ + if (ret == Z_STREAM_END) + break; + + /* do until offset reached and requested data read, or stream ends */ + } while (skip); + + /* compute number of uncompressed bytes read after offset */ + ret = skip ? 0 : len - strm.avail_out; + + /* clean up and return bytes read or error */ + extract_ret: + (void)inflateEnd(&strm); + return ret; +} + +/* Demonstrate the use of build_index() and extract() by processing the file + provided on the command line, and the extracting 16K from about 2/3rds of + the way through the uncompressed output, and writing that to stdout. */ +int main(int argc, char **argv) +{ + int len; + off_t offset; + FILE *in; + struct access *index; + unsigned char buf[CHUNK]; + + /* open input file */ + if (argc != 2) { + fprintf(stderr, "usage: zran file.gz\n"); + return 1; + } + in = fopen(argv[1], "rb"); + if (in == NULL) { + fprintf(stderr, "zran: could not open %s for reading\n", argv[1]); + return 1; + } + + /* build index */ + len = build_index(in, SPAN, &index); + if (len < 0) { + fclose(in); + switch (len) { + case Z_MEM_ERROR: + fprintf(stderr, "zran: out of memory\n"); + break; + case Z_DATA_ERROR: + fprintf(stderr, "zran: compressed data error in %s\n", argv[1]); + break; + case Z_ERRNO: + fprintf(stderr, "zran: read error on %s\n", argv[1]); + break; + default: + fprintf(stderr, "zran: error %d while building index\n", len); + } + return 1; + } + fprintf(stderr, "zran: built index with %d access points\n", len); + + /* use index by reading some bytes from an arbitrary offset */ + offset = (index->list[index->have - 1].out << 1) / 3; + len = extract(in, index, offset, buf, CHUNK); + if (len < 0) + fprintf(stderr, "zran: extraction failed: %s error\n", + len == Z_MEM_ERROR ? "out of memory" : "input corrupted"); + else { + fwrite(buf, 1, len, stdout); + fprintf(stderr, "zran: extracted %d bytes at %llu\n", len, offset); + } + + /* clean up and exit */ + free_index(index); + fclose(in); + return 0; +} diff --git a/gdcm/Utilities/gdcmzlib/gzio.c b/gdcm/Utilities/gdcmzlib/gzio.c new file mode 100644 index 0000000..7e90f49 --- /dev/null +++ b/gdcm/Utilities/gdcmzlib/gzio.c @@ -0,0 +1,1026 @@ +/* gzio.c -- IO on .gz files + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Compile this file with -DNO_GZCOMPRESS to avoid the compression code. + */ + +/* @(#) $Id$ */ + +#include + +#include "zutil.h" + +#ifdef NO_DEFLATE /* for compatibility with old definition */ +# define NO_GZCOMPRESS +#endif + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +#ifndef Z_BUFSIZE +# ifdef MAXSEG_64K +# define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */ +# else +# define Z_BUFSIZE 16384 +# endif +#endif +#ifndef Z_PRINTF_BUFSIZE +# define Z_PRINTF_BUFSIZE 4096 +#endif + +#ifdef __MVS__ +# pragma map (fdopen , "\174\174FDOPEN") + FILE *fdopen(int, const char *); +#endif + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern void free OF((voidpf ptr)); +#endif + +#define ALLOC(size) malloc(size) +#define TRYFREE(p) {if (p) free(p);} + +static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ +#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define RESERVED 0xE0 /* bits 5..7: reserved */ + +typedef struct gz_stream { + z_stream stream; + int z_err; /* error code for last stream operation */ + int z_eof; /* set if end of input file */ + FILE *file; /* .gz file */ + Byte *inbuf; /* input buffer */ + Byte *outbuf; /* output buffer */ + uLong crc; /* crc32 of uncompressed data */ + char *msg; /* error message */ + char *path; /* path name for debugging only */ + int transparent; /* 1 if input file is not a .gz file */ + char mode; /* 'w' or 'r' */ + z_off_t start; /* start of compressed data in file (header skipped) */ + z_off_t in; /* bytes into deflate or inflate */ + z_off_t out; /* bytes out of deflate or inflate */ + int back; /* one character push-back */ + int last; /* true if push-back is last character */ +} gz_stream; + + +local gzFile gz_open OF((const char *path, const char *mode, int fd)); +local int do_flush OF((gzFile file, int flush)); +local int get_byte OF((gz_stream *s)); +local void check_header OF((gz_stream *s)); +local int destroy OF((gz_stream *s)); +local void putLong OF((FILE *file, uLong x)); +local uLong getLong OF((gz_stream *s)); + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb"). The file is given either by file descriptor + or path name (if fd == -1). + gz_open returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). +*/ +local gzFile gz_open (path, mode, fd) + const char *path; + const char *mode; + int fd; +{ + int err; + int level = Z_DEFAULT_COMPRESSION; /* compression level */ + int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */ + char *p = (char*)mode; + gz_stream *s; + char fmode[80]; /* copy of mode, without the compression level */ + char *m = fmode; + + if (!path || !mode) return Z_NULL; + + s = (gz_stream *)ALLOC(sizeof(gz_stream)); + if (!s) return Z_NULL; + + s->stream.zalloc = (alloc_func)0; + s->stream.zfree = (free_func)0; + s->stream.opaque = (voidpf)0; + s->stream.next_in = s->inbuf = Z_NULL; + s->stream.next_out = s->outbuf = Z_NULL; + s->stream.avail_in = s->stream.avail_out = 0; + s->file = NULL; + s->z_err = Z_OK; + s->z_eof = 0; + s->in = 0; + s->out = 0; + s->back = EOF; + s->crc = crc32(0L, Z_NULL, 0); + s->msg = NULL; + s->transparent = 0; + + s->path = (char*)ALLOC(strlen(path)+1); + if (s->path == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + strcpy(s->path, path); /* do this early for debugging */ + + s->mode = '\0'; + do { + if (*p == 'r') s->mode = 'r'; + if (*p == 'w' || *p == 'a') s->mode = 'w'; + if (*p >= '0' && *p <= '9') { + level = *p - '0'; + } else if (*p == 'f') { + strategy = Z_FILTERED; + } else if (*p == 'h') { + strategy = Z_HUFFMAN_ONLY; + } else if (*p == 'R') { + strategy = Z_RLE; + } else { + *m++ = *p; /* copy the mode */ + } + } while (*p++ && m != fmode + sizeof(fmode)); + if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL; + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + err = Z_STREAM_ERROR; +#else + err = deflateInit2(&(s->stream), level, + Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy); + /* windowBits is passed < 0 to suppress zlib header */ + + s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); +#endif + if (err != Z_OK || s->outbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } else { + s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); + + err = inflateInit2(&(s->stream), -MAX_WBITS); + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are + * present after the compressed stream. + */ + if (err != Z_OK || s->inbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } + s->stream.avail_out = Z_BUFSIZE; + + errno = 0; + s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode); + + if (s->file == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + if (s->mode == 'w') { + /* Write a very simple .gz header: + */ + fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1], + Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE); + s->start = 10L; + /* We use 10L instead of ftell(s->file) to because ftell causes an + * fflush on some systems. This version of the library doesn't use + * start anyway in write mode, so this initialization is not + * necessary. + */ + } else { + check_header(s); /* skip the .gz header */ + s->start = ftell(s->file) - s->stream.avail_in; + } + + return (gzFile)s; +} + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. +*/ +gzFile ZEXPORT gzopen (path, mode) + const char *path; + const char *mode; +{ + return gz_open (path, mode, -1); +} + +/* =========================================================================== + Associate a gzFile with the file descriptor fd. fd is not dup'ed here + to mimic the behavio(u)r of fdopen. +*/ +gzFile ZEXPORT gzdopen (fd, mode) + int fd; + const char *mode; +{ + char name[46]; /* allow for up to 128-bit integers */ + + if (fd < 0) return (gzFile)Z_NULL; + sprintf(name, "", fd); /* for debugging */ + + return gz_open (name, mode, fd); +} + +/* =========================================================================== + * Update the compression level and strategy + */ +int ZEXPORT gzsetparams (file, level, strategy) + gzFile file; + int level; + int strategy; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + /* Make room to allow flushing */ + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + } + s->stream.avail_out = Z_BUFSIZE; + } + + return deflateParams (&(s->stream), level, strategy); +} + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been sucessfully opened for reading. +*/ +local int get_byte(s) + gz_stream *s; +{ + if (s->z_eof) return EOF; + if (s->stream.avail_in == 0) { + errno = 0; + s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) s->z_err = Z_ERRNO; + return EOF; + } + s->stream.next_in = s->inbuf; + } + s->stream.avail_in--; + return *(s->stream.next_in)++; +} + +/* =========================================================================== + Check the gzip header of a gz_stream opened for reading. Set the stream + mode to transparent if the gzip magic header is not present; set s->err + to Z_DATA_ERROR if the magic header is present but the rest of the header + is incorrect. + IN assertion: the stream s has already been created sucessfully; + s->stream.avail_in is zero for the first time, but may be non-zero + for concatenated .gz files. +*/ +local void check_header(s) + gz_stream *s; +{ + int method; /* method byte */ + int flags; /* flags byte */ + uInt len; + int c; + + /* Assure two bytes in the buffer so we can peek ahead -- handle case + where first byte of header is at the end of the buffer after the last + gzip segment */ + len = s->stream.avail_in; + if (len < 2) { + if (len) s->inbuf[0] = s->stream.next_in[0]; + errno = 0; + len = (uInt)fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file); + if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO; + s->stream.avail_in += len; + s->stream.next_in = s->inbuf; + if (s->stream.avail_in < 2) { + s->transparent = s->stream.avail_in; + return; + } + } + + /* Peek ahead to check the gzip magic header */ + if (s->stream.next_in[0] != gz_magic[0] || + s->stream.next_in[1] != gz_magic[1]) { + s->transparent = 1; + return; + } + s->stream.avail_in -= 2; + s->stream.next_in += 2; + + /* Check the rest of the gzip header */ + method = get_byte(s); + flags = get_byte(s); + if (method != Z_DEFLATED || (flags & RESERVED) != 0) { + s->z_err = Z_DATA_ERROR; + return; + } + + /* Discard time, xflags and OS code: */ + for (len = 0; len < 6; len++) (void)get_byte(s); + + if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ + len = (uInt)get_byte(s); + len += ((uInt)get_byte(s))<<8; + /* len is garbage if EOF but the loop below will quit anyway */ + while (len-- != 0 && get_byte(s) != EOF) ; + } + if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ + for (len = 0; len < 2; len++) (void)get_byte(s); + } + s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK; +} + + /* =========================================================================== + * Cleanup then free the given gz_stream. Return a zlib error code. + Try freeing in the reverse order of allocations. + */ +local int destroy (s) + gz_stream *s; +{ + int err = Z_OK; + + if (!s) return Z_STREAM_ERROR; + + TRYFREE(s->msg); + + if (s->stream.state != NULL) { + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + err = Z_STREAM_ERROR; +#else + err = deflateEnd(&(s->stream)); +#endif + } else if (s->mode == 'r') { + err = inflateEnd(&(s->stream)); + } + } + if (s->file != NULL && fclose(s->file)) { +#ifdef ESPIPE + if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */ +#endif + err = Z_ERRNO; + } + if (s->z_err < 0) err = s->z_err; + + TRYFREE(s->inbuf); + TRYFREE(s->outbuf); + TRYFREE(s->path); + TRYFREE(s); + return err; +} + +/* =========================================================================== + Reads the given number of uncompressed bytes from the compressed file. + gzread returns the number of bytes actually read (0 for end of file). +*/ +int ZEXPORT gzread (file, buf, len) + gzFile file; + voidp buf; + unsigned len; +{ + gz_stream *s = (gz_stream*)file; + Bytef *start = (Bytef*)buf; /* starting point for crc computation */ + Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */ + + if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR; + + if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1; + if (s->z_err == Z_STREAM_END) return 0; /* EOF */ + + next_out = (Byte*)buf; + s->stream.next_out = (Bytef*)buf; + s->stream.avail_out = len; + + if (s->stream.avail_out && s->back != EOF) { + *next_out++ = s->back; + s->stream.next_out++; + s->stream.avail_out--; + s->back = EOF; + s->out++; + start++; + if (s->last) { + s->z_err = Z_STREAM_END; + return 1; + } + } + + while (s->stream.avail_out != 0) { + + if (s->transparent) { + /* Copy first the lookahead bytes: */ + uInt n = s->stream.avail_in; + if (n > s->stream.avail_out) n = s->stream.avail_out; + if (n > 0) { + zmemcpy(s->stream.next_out, s->stream.next_in, n); + next_out += n; + s->stream.next_out = next_out; + s->stream.next_in += n; + s->stream.avail_out -= n; + s->stream.avail_in -= n; + } + if (s->stream.avail_out > 0) { + s->stream.avail_out -= + (uInt)fread(next_out, 1, s->stream.avail_out, s->file); + } + len -= s->stream.avail_out; + s->in += len; + s->out += len; + if (len == 0) s->z_eof = 1; + return (int)len; + } + if (s->stream.avail_in == 0 && !s->z_eof) { + + errno = 0; + s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) { + s->z_err = Z_ERRNO; + break; + } + } + s->stream.next_in = s->inbuf; + } + s->in += s->stream.avail_in; + s->out += s->stream.avail_out; + s->z_err = inflate(&(s->stream), Z_NO_FLUSH); + s->in -= s->stream.avail_in; + s->out -= s->stream.avail_out; + + if (s->z_err == Z_STREAM_END) { + /* Check CRC and original size */ + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + start = s->stream.next_out; + + if (getLong(s) != s->crc) { + s->z_err = Z_DATA_ERROR; + } else { + (void)getLong(s); + /* The uncompressed length returned by above getlong() may be + * different from s->out in case of concatenated .gz files. + * Check for such files: + */ + check_header(s); + if (s->z_err == Z_OK) { + inflateReset(&(s->stream)); + s->crc = crc32(0L, Z_NULL, 0); + } + } + } + if (s->z_err != Z_OK || s->z_eof) break; + } + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + + if (len == s->stream.avail_out && + (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO)) + return -1; + return (int)(len - s->stream.avail_out); +} + + +/* =========================================================================== + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ +int ZEXPORT gzgetc(file) + gzFile file; +{ + unsigned char c; + + return gzread(file, &c, 1) == 1 ? c : -1; +} + + +/* =========================================================================== + Push one byte back onto the stream. +*/ +int ZEXPORT gzungetc(c, file) + int c; + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r' || c == EOF || s->back != EOF) return EOF; + s->back = c; + s->out--; + s->last = (s->z_err == Z_STREAM_END); + if (s->last) s->z_err = Z_OK; + s->z_eof = 0; + return c; +} + + +/* =========================================================================== + Reads bytes from the compressed file until len-1 characters are + read, or a newline character is read and transferred to buf, or an + end-of-file condition is encountered. The string is then terminated + with a null character. + gzgets returns buf, or Z_NULL in case of error. + + The current implementation is not optimized at all. +*/ +char * ZEXPORT gzgets(file, buf, len) + gzFile file; + char *buf; + int len; +{ + char *b = buf; + if (buf == Z_NULL || len <= 0) return Z_NULL; + + while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ; + *buf = '\0'; + return b == buf && len > 0 ? Z_NULL : b; +} + + +#ifndef NO_GZCOMPRESS +/* =========================================================================== + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of bytes actually written (0 in case of error). +*/ +int ZEXPORT gzwrite (file, buf, len) + gzFile file; + voidpc buf; + unsigned len; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.next_in = (Bytef*)buf; + s->stream.avail_in = len; + + while (s->stream.avail_in != 0) { + + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + break; + } + s->stream.avail_out = Z_BUFSIZE; + } + s->in += s->stream.avail_in; + s->out += s->stream.avail_out; + s->z_err = deflate(&(s->stream), Z_NO_FLUSH); + s->in -= s->stream.avail_in; + s->out -= s->stream.avail_out; + if (s->z_err != Z_OK) break; + } + s->crc = crc32(s->crc, (const Bytef *)buf, len); + + return (int)(len - s->stream.avail_in); +} + + +/* =========================================================================== + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). +*/ +#ifdef STDC +#include + +int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...) +{ + char buf[Z_PRINTF_BUFSIZE]; + va_list va; + int len; + + buf[sizeof(buf) - 1] = 0; + va_start(va, format); +#ifdef NO_vsnprintf +# ifdef HAS_vsprintf_void + (void)vsprintf(buf, format, va); + va_end(va); + for (len = 0; len < sizeof(buf); len++) + if (buf[len] == 0) break; +# else + len = vsprintf(buf, format, va); + va_end(va); +# endif +#else +# ifdef HAS_vsnprintf_void + (void)vsnprintf(buf, sizeof(buf), format, va); + va_end(va); + len = strlen(buf); +# else + len = vsnprintf(buf, sizeof(buf), format, va); + va_end(va); +# endif +#endif + if (len <= 0 || len >= (int)sizeof(buf) || buf[sizeof(buf) - 1] != 0) + return 0; + return gzwrite(file, buf, (unsigned)len); +} +#else /* not ANSI C */ + +int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) + gzFile file; + const char *format; + int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; +{ + char buf[Z_PRINTF_BUFSIZE]; + int len; + + buf[sizeof(buf) - 1] = 0; +#ifdef NO_snprintf +# ifdef HAS_sprintf_void + sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + for (len = 0; len < sizeof(buf); len++) + if (buf[len] == 0) break; +# else + len = sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#else +# ifdef HAS_snprintf_void + snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + len = strlen(buf); +# else + len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#endif + if (len <= 0 || len >= sizeof(buf) || buf[sizeof(buf) - 1] != 0) + return 0; + return gzwrite(file, buf, len); +} +#endif + +/* =========================================================================== + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ +int ZEXPORT gzputc(file, c) + gzFile file; + int c; +{ + unsigned char cc = (unsigned char) c; /* required for big endian systems */ + + return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1; +} + + +/* =========================================================================== + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ +int ZEXPORT gzputs(file, s) + gzFile file; + const char *s; +{ + return gzwrite(file, (char*)s, (unsigned)strlen(s)); +} + + +/* =========================================================================== + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. +*/ +local int do_flush (file, flush) + gzFile file; + int flush; +{ + uInt len; + int done = 0; + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.avail_in = 0; /* should be zero already anyway */ + + for (;;) { + len = Z_BUFSIZE - s->stream.avail_out; + + if (len != 0) { + if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) { + s->z_err = Z_ERRNO; + return Z_ERRNO; + } + s->stream.next_out = s->outbuf; + s->stream.avail_out = Z_BUFSIZE; + } + if (done) break; + s->out += s->stream.avail_out; + s->z_err = deflate(&(s->stream), flush); + s->out -= s->stream.avail_out; + + /* Ignore the second of two consecutive flushes: */ + if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK; + + /* deflate has finished flushing only when it hasn't used up + * all the available space in the output buffer: + */ + done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END); + + if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break; + } + return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; +} + +int ZEXPORT gzflush (file, flush) + gzFile file; + int flush; +{ + gz_stream *s = (gz_stream*)file; + int err = do_flush (file, flush); + + if (err) return err; + fflush(s->file); + return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; +} +#endif /* NO_GZCOMPRESS */ + +/* =========================================================================== + Sets the starting position for the next gzread or gzwrite on the given + compressed file. The offset represents a number of bytes in the + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error. + SEEK_END is not implemented, returns error. + In this version of the library, gzseek can be extremely slow. +*/ +z_off_t ZEXPORT gzseek (file, offset, whence) + gzFile file; + z_off_t offset; + int whence; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || whence == SEEK_END || + s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) { + return -1L; + } + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + return -1L; +#else + if (whence == SEEK_SET) { + offset -= s->in; + } + if (offset < 0) return -1L; + + /* At this point, offset is the number of zero bytes to write. */ + if (s->inbuf == Z_NULL) { + s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */ + if (s->inbuf == Z_NULL) return -1L; + zmemzero(s->inbuf, Z_BUFSIZE); + } + while (offset > 0) { + uInt size = Z_BUFSIZE; + if (offset < Z_BUFSIZE) size = (uInt)offset; + + size = gzwrite(file, s->inbuf, size); + if (size == 0) return -1L; + + offset -= size; + } + return s->in; +#endif + } + /* Rest of function is for reading only */ + + /* compute absolute position */ + if (whence == SEEK_CUR) { + offset += s->out; + } + if (offset < 0) return -1L; + + if (s->transparent) { + /* map to fseek */ + s->back = EOF; + s->stream.avail_in = 0; + s->stream.next_in = s->inbuf; + if (fseek(s->file, offset, SEEK_SET) < 0) return -1L; + + s->in = s->out = offset; + return offset; + } + + /* For a negative seek, rewind and use positive seek */ + if (offset >= s->out) { + offset -= s->out; + } else if (gzrewind(file) < 0) { + return -1L; + } + /* offset is now the number of bytes to skip. */ + + if (offset != 0 && s->outbuf == Z_NULL) { + s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); + if (s->outbuf == Z_NULL) return -1L; + } + if (offset && s->back != EOF) { + s->back = EOF; + s->out++; + offset--; + if (s->last) s->z_err = Z_STREAM_END; + } + while (offset > 0) { + int size = Z_BUFSIZE; + if (offset < Z_BUFSIZE) size = (int)offset; + + size = gzread(file, s->outbuf, (uInt)size); + if (size <= 0) return -1L; + offset -= size; + } + return s->out; +} + +/* =========================================================================== + Rewinds input file. +*/ +int ZEXPORT gzrewind (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r') return -1; + + s->z_err = Z_OK; + s->z_eof = 0; + s->back = EOF; + s->stream.avail_in = 0; + s->stream.next_in = s->inbuf; + s->crc = crc32(0L, Z_NULL, 0); + if (!s->transparent) (void)inflateReset(&s->stream); + s->in = 0; + s->out = 0; + return fseek(s->file, s->start, SEEK_SET); +} + +/* =========================================================================== + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. +*/ +z_off_t ZEXPORT gztell (file) + gzFile file; +{ + return gzseek(file, 0L, SEEK_CUR); +} + +/* =========================================================================== + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ +int ZEXPORT gzeof (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + /* With concatenated compressed files that can have embedded + * crc trailers, z_eof is no longer the only/best indicator of EOF + * on a gz_stream. Handle end-of-stream error explicitly here. + */ + if (s == NULL || s->mode != 'r') return 0; + if (s->z_eof) return 1; + return s->z_err == Z_STREAM_END; +} + +/* =========================================================================== + Returns 1 if reading and doing so transparently, otherwise zero. +*/ +int ZEXPORT gzdirect (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r') return 0; + return s->transparent; +} + +/* =========================================================================== + Outputs a long in LSB order to the given file +*/ +local void putLong (file, x) + FILE *file; + uLong x; +{ + int n; + for (n = 0; n < 4; n++) { + fputc((int)(x & 0xff), file); + x >>= 8; + } +} + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets z_err in case + of error. +*/ +local uLong getLong (s) + gz_stream *s; +{ + uLong x = (uLong)get_byte(s); + int c; + + x += ((uLong)get_byte(s))<<8; + x += ((uLong)get_byte(s))<<16; + c = get_byte(s); + if (c == EOF) s->z_err = Z_DATA_ERROR; + x += ((uLong)c)<<24; + return x; +} + +/* =========================================================================== + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. +*/ +int ZEXPORT gzclose (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL) return Z_STREAM_ERROR; + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + return Z_STREAM_ERROR; +#else + if (do_flush (file, Z_FINISH) != Z_OK) + return destroy((gz_stream*)file); + + putLong (s->file, s->crc); + putLong (s->file, (uLong)(s->in & 0xffffffff)); +#endif + } + return destroy((gz_stream*)file); +} + +#ifdef STDC +# define zstrerror(errnum) strerror(errnum) +#else +# define zstrerror(errnum) "" +#endif + +/* =========================================================================== + Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ +const char * ZEXPORT gzerror (file, errnum) + gzFile file; + int *errnum; +{ + char *m; + gz_stream *s = (gz_stream*)file; + + if (s == NULL) { + *errnum = Z_STREAM_ERROR; + return (const char*)ERR_MSG(Z_STREAM_ERROR); + } + *errnum = s->z_err; + if (*errnum == Z_OK) return (const char*)""; + + m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg); + + if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err); + + TRYFREE(s->msg); + s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3); + if (s->msg == Z_NULL) return (const char*)ERR_MSG(Z_MEM_ERROR); + strcpy(s->msg, s->path); + strcat(s->msg, ": "); + strcat(s->msg, m); + return (const char*)s->msg; +} + +/* =========================================================================== + Clear the error and end-of-file flags, and do the same for the real file. +*/ +void ZEXPORT gzclearerr (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL) return; + if (s->z_err != Z_STREAM_END) s->z_err = Z_OK; + s->z_eof = 0; + clearerr(s->file); +} diff --git a/gdcm/Utilities/gdcmzlib/infback.c b/gdcm/Utilities/gdcmzlib/infback.c new file mode 100644 index 0000000..455dbc9 --- /dev/null +++ b/gdcm/Utilities/gdcmzlib/infback.c @@ -0,0 +1,623 @@ +/* infback.c -- inflate using a call-back interface + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + This code is largely copied from inflate.c. Normally either infback.o or + inflate.o would be linked into an application--not both. The interface + with inffast.c is retained so that optimized assembler-coded versions of + inflate_fast() can be used with either inflate.c or infback.c. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); + +/* + strm provides memory allocation functions in zalloc and zfree, or + Z_NULL to use the library memory allocation functions. + + windowBits is in the range 8..15, and window is a user-supplied + window and output buffer that is 2**windowBits bytes. + */ +int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size) +z_streamp strm; +int windowBits; +unsigned char FAR *window; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL || window == Z_NULL || + windowBits < 8 || windowBits > 15) + return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *)ZALLOC(strm, 1, + sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (struct internal_state FAR *)state; + state->dmax = 32768U; + state->wbits = windowBits; + state->wsize = 1U << windowBits; + state->window = window; + state->write = 0; + state->whave = 0; + return Z_OK; +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +/* Macros for inflateBack(): */ + +/* Load returned state from inflate_fast() */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Set state from registers for inflate_fast() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Assure that some input is available. If input is requested, but denied, + then return a Z_BUF_ERROR from inflateBack(). */ +#define PULL() \ + do { \ + if (have == 0) { \ + have = in(in_desc, &next); \ + if (have == 0) { \ + next = Z_NULL; \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflateBack() + with an error if there is no input available. */ +#define PULLBYTE() \ + do { \ + PULL(); \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflateBack() with + an error. */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Assure that some output space is available, by writing out the window + if it's full. If the write fails, return from inflateBack() with a + Z_BUF_ERROR. */ +#define ROOM() \ + do { \ + if (left == 0) { \ + put = state->window; \ + left = state->wsize; \ + state->whave = left; \ + if (out(out_desc, put, left)) { \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* + strm provides the memory allocation functions and window buffer on input, + and provides information on the unused input on return. For Z_DATA_ERROR + returns, strm will also provide an error message. + + in() and out() are the call-back input and output functions. When + inflateBack() needs more input, it calls in(). When inflateBack() has + filled the window with output, or when it completes with data in the + window, it calls out() to write out the data. The application must not + change the provided input until in() is called again or inflateBack() + returns. The application must not change the window/output buffer until + inflateBack() returns. + + in() and out() are called with a descriptor parameter provided in the + inflateBack() call. This parameter can be a structure that provides the + information required to do the read or write, as well as accumulated + information on the input and output such as totals and check values. + + in() should return zero on failure. out() should return non-zero on + failure. If either in() or out() fails, than inflateBack() returns a + Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it + was in() or out() that caused in the error. Otherwise, inflateBack() + returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format + error, or Z_MEM_ERROR if it could not allocate memory for the state. + inflateBack() can also return Z_STREAM_ERROR if the input parameters + are not correct, i.e. strm is Z_NULL or the state was not initialized. + */ +int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc) +z_streamp strm; +in_func in; +void FAR *in_desc; +out_func out; +void FAR *out_desc; +{ + struct inflate_state FAR *state; + unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code this; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + /* Check that the strm exists and that the state was initialized */ + if (strm == Z_NULL || strm->state == Z_NULL) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* Reset the state */ + strm->msg = Z_NULL; + state->mode = TYPE; + state->last = 0; + state->whave = 0; + next = strm->next_in; + have = next != Z_NULL ? strm->avail_in : 0; + hold = 0; + bits = 0; + put = state->window; + left = state->wsize; + + /* Inflate until end of block marked as last */ + for (;;) + switch (state->mode) { + case TYPE: + /* determine and dispatch block type */ + if (state->last) { + BYTEBITS(); + state->mode = DONE; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + + case STORED: + /* get and verify stored block length */ + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + + /* copy stored block from input to output */ + while (state->length != 0) { + copy = state->length; + PULL(); + ROOM(); + if (copy > have) copy = have; + if (copy > left) copy = left; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + + case TABLE: + /* get dynamic table entries descriptor */ + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + + /* get code length code lengths (not a typo) */ + state->have = 0; + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + + /* get length and distance code code lengths */ + state->have = 0; + while (state->have < state->nlen + state->ndist) { + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.val < 16) { + NEEDBITS(this.bits); + DROPBITS(this.bits); + state->lens[state->have++] = this.val; + } + else { + if (this.val == 16) { + NEEDBITS(this.bits + 2); + DROPBITS(this.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = (unsigned)(state->lens[state->have - 1]); + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (this.val == 17) { + NEEDBITS(this.bits + 3); + DROPBITS(this.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(this.bits + 7); + DROPBITS(this.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) break; + + /* build code tables */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + + case LEN: + /* use inflate_fast() if we have enough input and output */ + if (have >= 6 && left >= 258) { + RESTORE(); + if (state->whave < state->wsize) + state->whave = state->wsize - left; + inflate_fast(strm, state->wsize); + LOAD(); + break; + } + + /* get a literal, length, or end-of-block code */ + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.op && (this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + state->length = (unsigned)this.val; + + /* process literal */ + if (this.op == 0) { + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + ROOM(); + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + } + + /* process end of block */ + if (this.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + + /* invalid code */ + if (this.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + + /* length code -- get extra bits, if any */ + state->extra = (unsigned)(this.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + + /* get distance code */ + for (;;) { + this = state->distcode[BITS(state->distbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if ((this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + if (this.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)this.val; + + /* get distance extra bits, if any */ + state->extra = (unsigned)(this.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } + if (state->offset > state->wsize - (state->whave < state->wsize ? + left : 0)) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + + /* copy match from window to output */ + do { + ROOM(); + copy = state->wsize - state->offset; + if (copy < left) { + from = put + copy; + copy = left - copy; + } + else { + from = put - state->offset; + copy = left; + } + if (copy > state->length) copy = state->length; + state->length -= copy; + left -= copy; + do { + *put++ = *from++; + } while (--copy); + } while (state->length != 0); + break; + + case DONE: + /* inflate stream terminated properly -- write leftover output */ + ret = Z_STREAM_END; + if (left < state->wsize) { + if (out(out_desc, state->window, state->wsize - left)) + ret = Z_BUF_ERROR; + } + goto inf_leave; + + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + + default: /* can't happen, but makes compilers happy */ + ret = Z_STREAM_ERROR; + goto inf_leave; + } + + /* Return unused input */ + inf_leave: + strm->next_in = next; + strm->avail_in = have; + return ret; +} + +int ZEXPORT inflateBackEnd(strm) +z_streamp strm; +{ + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} diff --git a/gdcm/Utilities/gdcmzlib/inffast.c b/gdcm/Utilities/gdcmzlib/inffast.c new file mode 100644 index 0000000..bbee92e --- /dev/null +++ b/gdcm/Utilities/gdcmzlib/inffast.c @@ -0,0 +1,318 @@ +/* inffast.c -- fast decoding + * Copyright (C) 1995-2004 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifndef ASMINF + +/* Allow machine dependent optimization for post-increment or pre-increment. + Based on testing to date, + Pre-increment preferred for: + - PowerPC G3 (Adler) + - MIPS R5000 (Randers-Pehrson) + Post-increment preferred for: + - none + No measurable difference: + - Pentium III (Anderson) + - M68060 (Nikl) + */ +#ifdef POSTINC +# define OFF 0 +# define PUP(a) *(a)++ +#else +# define OFF 1 +# define PUP(a) *++(a) +#endif + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state->mode == LEN + strm->avail_in >= 6 + strm->avail_out >= 258 + start >= strm->avail_out + state->bits < 8 + + On return, state->mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm->avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm->avail_out >= 258 for each loop to avoid checking for + output space. + */ +void inflate_fast(strm, start) +z_streamp strm; +unsigned start; /* inflate()'s starting value for strm->avail_out */ +{ + struct inflate_state FAR *state; + unsigned char FAR *in; /* local strm->next_in */ + unsigned char FAR *last; /* while in < last, enough input available */ + unsigned char FAR *out; /* local strm->next_out */ + unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ + unsigned char FAR *end; /* while out < end, enough space available */ +#ifdef INFLATE_STRICT + unsigned dmax; /* maximum distance from zlib header */ +#endif + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned write; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ + unsigned long hold; /* local strm->hold */ + unsigned bits; /* local strm->bits */ + code const FAR *lcode; /* local strm->lencode */ + code const FAR *dcode; /* local strm->distcode */ + unsigned lmask; /* mask for first level of length codes */ + unsigned dmask; /* mask for first level of distance codes */ + code this; /* retrieved table entry */ + unsigned op; /* code bits, operation, extra bits, or */ + /* window position, window bytes to copy */ + unsigned len; /* match length, unused bytes */ + unsigned dist; /* match distance */ + unsigned char FAR *from; /* where to copy match from */ + + /* copy state to local variables */ + state = (struct inflate_state FAR *)strm->state; + in = strm->next_in - OFF; + last = in + (strm->avail_in - 5); + out = strm->next_out - OFF; + beg = out - (start - strm->avail_out); + end = out + (strm->avail_out - 257); +#ifdef INFLATE_STRICT + dmax = state->dmax; +#endif + wsize = state->wsize; + whave = state->whave; + write = state->write; + window = state->window; + hold = state->hold; + bits = state->bits; + lcode = state->lencode; + dcode = state->distcode; + lmask = (1U << state->lenbits) - 1; + dmask = (1U << state->distbits) - 1; + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + do { + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + this = lcode[hold & lmask]; + dolen: + op = (unsigned)(this.bits); + hold >>= op; + bits -= op; + op = (unsigned)(this.op); + if (op == 0) { /* literal */ + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + PUP(out) = (unsigned char)(this.val); + } + else if (op & 16) { /* length base */ + len = (unsigned)(this.val); + op &= 15; /* number of extra bits */ + if (op) { + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + len += (unsigned)hold & ((1U << op) - 1); + hold >>= op; + bits -= op; + } + Tracevv((stderr, "inflate: length %u\n", len)); + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + this = dcode[hold & dmask]; + dodist: + op = (unsigned)(this.bits); + hold >>= op; + bits -= op; + op = (unsigned)(this.op); + if (op & 16) { /* distance base */ + dist = (unsigned)(this.val); + op &= 15; /* number of extra bits */ + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + } + dist += (unsigned)hold & ((1U << op) - 1); +#ifdef INFLATE_STRICT + if (dist > dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + hold >>= op; + bits -= op; + Tracevv((stderr, "inflate: distance %u\n", dist)); + op = (unsigned)(out - beg); /* max distance in output */ + if (dist > op) { /* see if copy from window */ + op = dist - op; /* distance back in window */ + if (op > whave) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + from = window - OFF; + if (write == 0) { /* very common case */ + from += wsize - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + else if (write < op) { /* wrap around window */ + from += wsize + write - op; + op -= write; + if (op < len) { /* some from end of window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = window - OFF; + if (write < len) { /* some from start of window */ + op = write; + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + } + else { /* contiguous in window */ + from += write - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + while (len > 2) { + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + else { + from = out - dist; /* copy direct from output */ + do { /* minimum length is three */ + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } while (len > 2); + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + } + else if ((op & 64) == 0) { /* 2nd level distance code */ + this = dcode[this.val + (hold & ((1U << op) - 1))]; + goto dodist; + } + else { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + } + else if ((op & 64) == 0) { /* 2nd level length code */ + this = lcode[this.val + (hold & ((1U << op) - 1))]; + goto dolen; + } + else if (op & 32) { /* end-of-block */ + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + else { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + } while (in < last && out < end); + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + len = bits >> 3; + in -= len; + bits -= len << 3; + hold &= (1U << bits) - 1; + + /* update state and return */ + strm->next_in = in + OFF; + strm->next_out = out + OFF; + strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); + strm->avail_out = (unsigned)(out < end ? + 257 + (end - out) : 257 - (out - end)); + state->hold = hold; + state->bits = bits; + return; +} + +/* + inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): + - Using bit fields for code structure + - Different op definition to avoid & for extra bits (do & for table bits) + - Three separate decoding do-loops for direct, window, and write == 0 + - Special case for distance > 1 copies to do overlapped load and store copy + - Explicit branch predictions (based on measured branch probabilities) + - Deferring match copy and interspersed it with decoding subsequent codes + - Swapping literal/length else + - Swapping window/direct else + - Larger unrolled copy loops (three is about right) + - Moving len -= 3 statement into middle of loop + */ + +#endif /* !ASMINF */ diff --git a/gdcm/Utilities/gdcmzlib/inffast.h b/gdcm/Utilities/gdcmzlib/inffast.h new file mode 100644 index 0000000..1e88d2d --- /dev/null +++ b/gdcm/Utilities/gdcmzlib/inffast.h @@ -0,0 +1,11 @@ +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +void inflate_fast OF((z_streamp strm, unsigned start)); diff --git a/gdcm/Utilities/gdcmzlib/inffixed.h b/gdcm/Utilities/gdcmzlib/inffixed.h new file mode 100644 index 0000000..75ed4b5 --- /dev/null +++ b/gdcm/Utilities/gdcmzlib/inffixed.h @@ -0,0 +1,94 @@ + /* inffixed.h -- table for decoding fixed codes + * Generated automatically by makefixed(). + */ + + /* WARNING: this file should *not* be used by applications. It + is part of the implementation of the compression library and + is subject to change. Applications should only use zlib.h. + */ + + static const code lenfix[512] = { + {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, + {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, + {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, + {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, + {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, + {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, + {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, + {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, + {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, + {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, + {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, + {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, + {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, + {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, + {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, + {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, + {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, + {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, + {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, + {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, + {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, + {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, + {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, + {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, + {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, + {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, + {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, + {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, + {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, + {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, + {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, + {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, + {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, + {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, + {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, + {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, + {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, + {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, + {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, + {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, + {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, + {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, + {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, + {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, + {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, + {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, + {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, + {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, + {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, + {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, + {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, + {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, + {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, + {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, + {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, + {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, + {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, + {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, + {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, + {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, + {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, + {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, + {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, + {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, + {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, + {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, + {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, + {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, + {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, + {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, + {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, + {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, + {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, + {0,9,255} + }; + + static const code distfix[32] = { + {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, + {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, + {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, + {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, + {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, + {22,5,193},{64,5,0} + }; diff --git a/gdcm/Utilities/gdcmzlib/inflate.c b/gdcm/Utilities/gdcmzlib/inflate.c new file mode 100644 index 0000000..792fdee --- /dev/null +++ b/gdcm/Utilities/gdcmzlib/inflate.c @@ -0,0 +1,1368 @@ +/* inflate.c -- zlib decompression + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * Change history: + * + * 1.2.beta0 24 Nov 2002 + * - First version -- complete rewrite of inflate to simplify code, avoid + * creation of window when not needed, minimize use of window when it is + * needed, make inffast.c even faster, implement gzip decoding, and to + * improve code readability and style over the previous zlib inflate code + * + * 1.2.beta1 25 Nov 2002 + * - Use pointers for available input and output checking in inffast.c + * - Remove input and output counters in inffast.c + * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 + * - Remove unnecessary second byte pull from length extra in inffast.c + * - Unroll direct copy to three copies per loop in inffast.c + * + * 1.2.beta2 4 Dec 2002 + * - Change external routine names to reduce potential conflicts + * - Correct filename to inffixed.h for fixed tables in inflate.c + * - Make hbuf[] unsigned char to match parameter type in inflate.c + * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) + * to avoid negation problem on Alphas (64 bit) in inflate.c + * + * 1.2.beta3 22 Dec 2002 + * - Add comments on state->bits assertion in inffast.c + * - Add comments on op field in inftrees.h + * - Fix bug in reuse of allocated window after inflateReset() + * - Remove bit fields--back to byte structure for speed + * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths + * - Change post-increments to pre-increments in inflate_fast(), PPC biased? + * - Add compile time option, POSTINC, to use post-increments instead (Intel?) + * - Make MATCH copy in inflate() much faster for when inflate_fast() not used + * - Use local copies of stream next and avail values, as well as local bit + * buffer and bit count in inflate()--for speed when inflate_fast() not used + * + * 1.2.beta4 1 Jan 2003 + * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings + * - Move a comment on output buffer sizes from inffast.c to inflate.c + * - Add comments in inffast.c to introduce the inflate_fast() routine + * - Rearrange window copies in inflate_fast() for speed and simplification + * - Unroll last copy for window match in inflate_fast() + * - Use local copies of window variables in inflate_fast() for speed + * - Pull out common write == 0 case for speed in inflate_fast() + * - Make op and len in inflate_fast() unsigned for consistency + * - Add FAR to lcode and dcode declarations in inflate_fast() + * - Simplified bad distance check in inflate_fast() + * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new + * source file infback.c to provide a call-back interface to inflate for + * programs like gzip and unzip -- uses window as output buffer to avoid + * window copying + * + * 1.2.beta5 1 Jan 2003 + * - Improved inflateBack() interface to allow the caller to provide initial + * input in strm. + * - Fixed stored blocks bug in inflateBack() + * + * 1.2.beta6 4 Jan 2003 + * - Added comments in inffast.c on effectiveness of POSTINC + * - Typecasting all around to reduce compiler warnings + * - Changed loops from while (1) or do {} while (1) to for (;;), again to + * make compilers happy + * - Changed type of window in inflateBackInit() to unsigned char * + * + * 1.2.beta7 27 Jan 2003 + * - Changed many types to unsigned or unsigned short to avoid warnings + * - Added inflateCopy() function + * + * 1.2.0 9 Mar 2003 + * - Changed inflateBack() interface to provide separate opaque descriptors + * for the in() and out() functions + * - Changed inflateBack() argument and in_func typedef to swap the length + * and buffer address return values for the input function + * - Check next_in and next_out for Z_NULL on entry to inflate() + * + * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifdef MAKEFIXED +# ifndef BUILDFIXED +# define BUILDFIXED +# endif +#endif + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); +local int updatewindow OF((z_streamp strm, unsigned out)); +#ifdef BUILDFIXED + void makefixed OF((void)); +#endif +local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf, + unsigned len)); + +int ZEXPORT inflateReset(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + strm->total_in = strm->total_out = state->total = 0; + strm->msg = Z_NULL; + strm->adler = 1; /* to support ill-conceived Java test suite */ + state->mode = HEAD; + state->last = 0; + state->havedict = 0; + state->dmax = 32768U; + state->head = Z_NULL; + state->wsize = 0; + state->whave = 0; + state->write = 0; + state->hold = 0; + state->bits = 0; + state->lencode = state->distcode = state->next = state->codes; + Tracev((stderr, "inflate: reset\n")); + return Z_OK; +} + +int ZEXPORT inflatePrime(strm, bits, value) +z_streamp strm; +int bits; +int value; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR; + value &= (1L << bits) - 1; + state->hold += value << state->bits; + state->bits += bits; + return Z_OK; +} + +int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) +z_streamp strm; +int windowBits; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL) return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *) + ZALLOC(strm, 1, sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (struct internal_state FAR *)state; + if (windowBits < 0) { + state->wrap = 0; + windowBits = -windowBits; + } + else { + state->wrap = (windowBits >> 4) + 1; +#ifdef GUNZIP + if (windowBits < 48) windowBits &= 15; +#endif + } + if (windowBits < 8 || windowBits > 15) { + ZFREE(strm, state); + strm->state = Z_NULL; + return Z_STREAM_ERROR; + } + state->wbits = (unsigned)windowBits; + state->window = Z_NULL; + return inflateReset(strm); +} + +int ZEXPORT inflateInit_(strm, version, stream_size) +z_streamp strm; +const char *version; +int stream_size; +{ + return inflateInit2_(strm, DEF_WBITS, version, stream_size); +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +#ifdef MAKEFIXED +#include + +/* + Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also + defines BUILDFIXED, so the tables are built on the fly. makefixed() writes + those tables to stdout, which would be piped to inffixed.h. A small program + can simply call makefixed to do this: + + void makefixed(void); + + int main(void) + { + makefixed(); + return 0; + } + + Then that can be linked with zlib built with MAKEFIXED defined and run: + + a.out > inffixed.h + */ +void makefixed() +{ + unsigned low, size; + struct inflate_state state; + + fixedtables(&state); + puts(" /* inffixed.h -- table for decoding fixed codes"); + puts(" * Generated automatically by makefixed()."); + puts(" */"); + puts(""); + puts(" /* WARNING: this file should *not* be used by applications."); + puts(" It is part of the implementation of this library and is"); + puts(" subject to change. Applications should only use zlib.h."); + puts(" */"); + puts(""); + size = 1U << 9; + printf(" static const code lenfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 7) == 0) printf("\n "); + printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits, + state.lencode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); + size = 1U << 5; + printf("\n static const code distfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 6) == 0) printf("\n "); + printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, + state.distcode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); +} +#endif /* MAKEFIXED */ + +/* + Update the window with the last wsize (normally 32K) bytes written before + returning. If window does not exist yet, create it. This is only called + when a window is already in use, or when output has been written during this + inflate call, but the end of the deflate stream has not been reached yet. + It is also called to create a window for dictionary data when a dictionary + is loaded. + + Providing output buffers larger than 32K to inflate() should provide a speed + advantage, since only the last 32K of output is copied to the sliding window + upon return from inflate(), and since all distances after the first 32K of + output will fall in the output data, making match copies simpler and faster. + The advantage may be dependent on the size of the processor's data caches. + */ +local int updatewindow(strm, out) +z_streamp strm; +unsigned out; +{ + struct inflate_state FAR *state; + unsigned copy, dist; + + state = (struct inflate_state FAR *)strm->state; + + /* if it hasn't been done already, allocate space for the window */ + if (state->window == Z_NULL) { + state->window = (unsigned char FAR *) + ZALLOC(strm, 1U << state->wbits, + sizeof(unsigned char)); + if (state->window == Z_NULL) return 1; + } + + /* if window not in use yet, initialize */ + if (state->wsize == 0) { + state->wsize = 1U << state->wbits; + state->write = 0; + state->whave = 0; + } + + /* copy state->wsize or less output bytes into the circular window */ + copy = out - strm->avail_out; + if (copy >= state->wsize) { + zmemcpy(state->window, strm->next_out - state->wsize, state->wsize); + state->write = 0; + state->whave = state->wsize; + } + else { + dist = state->wsize - state->write; + if (dist > copy) dist = copy; + zmemcpy(state->window + state->write, strm->next_out - copy, dist); + copy -= dist; + if (copy) { + zmemcpy(state->window, strm->next_out - copy, copy); + state->write = copy; + state->whave = state->wsize; + } + else { + state->write += dist; + if (state->write == state->wsize) state->write = 0; + if (state->whave < state->wsize) state->whave += dist; + } + } + return 0; +} + +/* Macros for inflate(): */ + +/* check function to use adler32() for zlib or crc32() for gzip */ +#ifdef GUNZIP +# define UPDATE(check, buf, len) \ + (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) +#else +# define UPDATE(check, buf, len) adler32(check, buf, len) +#endif + +/* check macros for header crc */ +#ifdef GUNZIP +# define CRC2(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + check = crc32(check, hbuf, 2); \ + } while (0) + +# define CRC4(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + hbuf[2] = (unsigned char)((word) >> 16); \ + hbuf[3] = (unsigned char)((word) >> 24); \ + check = crc32(check, hbuf, 4); \ + } while (0) +#endif + +/* Load registers with state in inflate() for speed */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Restore state from registers in inflate() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflate() + if there is no input available. */ +#define PULLBYTE() \ + do { \ + if (have == 0) goto inf_leave; \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflate(). */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Reverse the bytes in a 32-bit value */ +#define REVERSE(q) \ + ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ + (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) + +/* + inflate() uses a state machine to process as much input data and generate as + much output data as possible before returning. The state machine is + structured roughly as follows: + + for (;;) switch (state) { + ... + case STATEn: + if (not enough input data or output space to make progress) + return; + ... make progress ... + state = STATEm; + break; + ... + } + + so when inflate() is called again, the same case is attempted again, and + if the appropriate resources are provided, the machine proceeds to the + next state. The NEEDBITS() macro is usually the way the state evaluates + whether it can proceed or should return. NEEDBITS() does the return if + the requested bits are not available. The typical use of the BITS macros + is: + + NEEDBITS(n); + ... do something with BITS(n) ... + DROPBITS(n); + + where NEEDBITS(n) either returns from inflate() if there isn't enough + input left to load n bits into the accumulator, or it continues. BITS(n) + gives the low n bits in the accumulator. When done, DROPBITS(n) drops + the low n bits off the accumulator. INITBITS() clears the accumulator + and sets the number of available bits to zero. BYTEBITS() discards just + enough bits to put the accumulator on a byte boundary. After BYTEBITS() + and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. + + NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return + if there is no input available. The decoding of variable length codes uses + PULLBYTE() directly in order to pull just enough bytes to decode the next + code, and no more. + + Some states loop until they get enough input, making sure that enough + state information is maintained to continue the loop where it left off + if NEEDBITS() returns in the loop. For example, want, need, and keep + would all have to actually be part of the saved state in case NEEDBITS() + returns: + + case STATEw: + while (want < need) { + NEEDBITS(n); + keep[want++] = BITS(n); + DROPBITS(n); + } + state = STATEx; + case STATEx: + + As shown above, if the next state is also the next case, then the break + is omitted. + + A state may also return if there is not enough output space available to + complete that state. Those states are copying stored data, writing a + literal byte, and copying a matching string. + + When returning, a "goto inf_leave" is used to update the total counters, + update the check value, and determine whether any progress has been made + during that inflate() call in order to return the proper return code. + Progress is defined as a change in either strm->avail_in or strm->avail_out. + When there is a window, goto inf_leave will update the window with the last + output written. If a goto inf_leave occurs in the middle of decompression + and there is no window currently, goto inf_leave will create one and copy + output to the window for the next call of inflate(). + + In this implementation, the flush parameter of inflate() only affects the + return code (per zlib.h). inflate() always writes as much as possible to + strm->next_out, given the space available and the provided input--the effect + documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers + the allocation of and copying into a sliding window until necessary, which + provides the effect documented in zlib.h for Z_FINISH when the entire input + stream available. So the only thing the flush parameter actually does is: + when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it + will return Z_BUF_ERROR if it has not reached the end of the stream. + */ + +int ZEXPORT inflate(strm, flush) +z_streamp strm; +int flush; +{ + struct inflate_state FAR *state; + unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned in, out; /* save starting available input and output */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code this; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ +#ifdef GUNZIP + unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ +#endif + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0)) + return Z_STREAM_ERROR; + + state = (struct inflate_state FAR *)strm->state; + if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ + LOAD(); + in = have; + out = left; + ret = Z_OK; + for (;;) + switch (state->mode) { + case HEAD: + if (state->wrap == 0) { + state->mode = TYPEDO; + break; + } + NEEDBITS(16); +#ifdef GUNZIP + if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ + state->check = crc32(0L, Z_NULL, 0); + CRC2(state->check, hold); + INITBITS(); + state->mode = FLAGS; + break; + } + state->flags = 0; /* expect zlib header */ + if (state->head != Z_NULL) + state->head->done = -1; + if (!(state->wrap & 1) || /* check if zlib header allowed */ +#else + if ( +#endif + ((BITS(8) << 8) + (hold >> 8)) % 31) { + strm->msg = (char *)"incorrect header check"; + state->mode = BAD; + break; + } + if (BITS(4) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + DROPBITS(4); + len = BITS(4) + 8; + if (len > state->wbits) { + strm->msg = (char *)"invalid window size"; + state->mode = BAD; + break; + } + state->dmax = 1U << len; + Tracev((stderr, "inflate: zlib header ok\n")); + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = hold & 0x200 ? DICTID : TYPE; + INITBITS(); + break; +#ifdef GUNZIP + case FLAGS: + NEEDBITS(16); + state->flags = (int)(hold); + if ((state->flags & 0xff) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + if (state->flags & 0xe000) { + strm->msg = (char *)"unknown header flags set"; + state->mode = BAD; + break; + } + if (state->head != Z_NULL) + state->head->text = (int)((hold >> 8) & 1); + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = TIME; + case TIME: + NEEDBITS(32); + if (state->head != Z_NULL) + state->head->time = hold; + if (state->flags & 0x0200) CRC4(state->check, hold); + INITBITS(); + state->mode = OS; + case OS: + NEEDBITS(16); + if (state->head != Z_NULL) { + state->head->xflags = (int)(hold & 0xff); + state->head->os = (int)(hold >> 8); + } + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = EXLEN; + case EXLEN: + if (state->flags & 0x0400) { + NEEDBITS(16); + state->length = (unsigned)(hold); + if (state->head != Z_NULL) + state->head->extra_len = (unsigned)hold; + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + } + else if (state->head != Z_NULL) + state->head->extra = Z_NULL; + state->mode = EXTRA; + case EXTRA: + if (state->flags & 0x0400) { + copy = state->length; + if (copy > have) copy = have; + if (copy) { + if (state->head != Z_NULL && + state->head->extra != Z_NULL) { + len = state->head->extra_len - state->length; + zmemcpy(state->head->extra + len, next, + len + copy > state->head->extra_max ? + state->head->extra_max - len : copy); + } + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + state->length -= copy; + } + if (state->length) goto inf_leave; + } + state->length = 0; + state->mode = NAME; + case NAME: + if (state->flags & 0x0800) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->name != Z_NULL && + state->length < state->head->name_max) + state->head->name[state->length++] = len; + } while (len && copy < have); + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->name = Z_NULL; + state->length = 0; + state->mode = COMMENT; + case COMMENT: + if (state->flags & 0x1000) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->comment != Z_NULL && + state->length < state->head->comm_max) + state->head->comment[state->length++] = len; + } while (len && copy < have); + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->comment = Z_NULL; + state->mode = HCRC; + case HCRC: + if (state->flags & 0x0200) { + NEEDBITS(16); + if (hold != (state->check & 0xffff)) { + strm->msg = (char *)"header crc mismatch"; + state->mode = BAD; + break; + } + INITBITS(); + } + if (state->head != Z_NULL) { + state->head->hcrc = (int)((state->flags >> 9) & 1); + state->head->done = 1; + } + strm->adler = state->check = crc32(0L, Z_NULL, 0); + state->mode = TYPE; + break; +#endif + case DICTID: + NEEDBITS(32); + strm->adler = state->check = REVERSE(hold); + INITBITS(); + state->mode = DICT; + case DICT: + if (state->havedict == 0) { + RESTORE(); + return Z_NEED_DICT; + } + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = TYPE; + case TYPE: + if (flush == Z_BLOCK) goto inf_leave; + case TYPEDO: + if (state->last) { + BYTEBITS(); + state->mode = CHECK; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + case STORED: + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + state->mode = COPY; + case COPY: + copy = state->length; + if (copy) { + if (copy > have) copy = have; + if (copy > left) copy = left; + if (copy == 0) goto inf_leave; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + break; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + case TABLE: + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + state->have = 0; + state->mode = LENLENS; + case LENLENS: + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + state->have = 0; + state->mode = CODELENS; + case CODELENS: + while (state->have < state->nlen + state->ndist) { + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.val < 16) { + NEEDBITS(this.bits); + DROPBITS(this.bits); + state->lens[state->have++] = this.val; + } + else { + if (this.val == 16) { + NEEDBITS(this.bits + 2); + DROPBITS(this.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = state->lens[state->have - 1]; + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (this.val == 17) { + NEEDBITS(this.bits + 3); + DROPBITS(this.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(this.bits + 7); + DROPBITS(this.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) break; + + /* build code tables */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + case LEN: + if (have >= 6 && left >= 258) { + RESTORE(); + inflate_fast(strm, out); + LOAD(); + break; + } + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.op && (this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + state->length = (unsigned)this.val; + if ((int)(this.op) == 0) { + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + state->mode = LIT; + break; + } + if (this.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + if (this.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + state->extra = (unsigned)(this.op) & 15; + state->mode = LENEXT; + case LENEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + state->mode = DIST; + case DIST: + for (;;) { + this = state->distcode[BITS(state->distbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if ((this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + if (this.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)this.val; + state->extra = (unsigned)(this.op) & 15; + state->mode = DISTEXT; + case DISTEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } +#ifdef INFLATE_STRICT + if (state->offset > state->dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + if (state->offset > state->whave + out - left) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + state->mode = MATCH; + case MATCH: + if (left == 0) goto inf_leave; + copy = out - left; + if (state->offset > copy) { /* copy from window */ + copy = state->offset - copy; + if (copy > state->write) { + copy -= state->write; + from = state->window + (state->wsize - copy); + } + else + from = state->window + (state->write - copy); + if (copy > state->length) copy = state->length; + } + else { /* copy from output */ + from = put - state->offset; + copy = state->length; + } + if (copy > left) copy = left; + left -= copy; + state->length -= copy; + do { + *put++ = *from++; + } while (--copy); + if (state->length == 0) state->mode = LEN; + break; + case LIT: + if (left == 0) goto inf_leave; + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + case CHECK: + if (state->wrap) { + NEEDBITS(32); + out -= left; + strm->total_out += out; + state->total += out; + if (out) + strm->adler = state->check = + UPDATE(state->check, put - out, out); + out = left; + if (( +#ifdef GUNZIP + state->flags ? hold : +#endif + REVERSE(hold)) != state->check) { + strm->msg = (char *)"incorrect data check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: check matches trailer\n")); + } +#ifdef GUNZIP + state->mode = LENGTH; + case LENGTH: + if (state->wrap && state->flags) { + NEEDBITS(32); + if (hold != (state->total & 0xffffffffUL)) { + strm->msg = (char *)"incorrect length check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: length matches trailer\n")); + } +#endif + state->mode = DONE; + case DONE: + ret = Z_STREAM_END; + goto inf_leave; + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + case MEM: + return Z_MEM_ERROR; + case SYNC: + default: + return Z_STREAM_ERROR; + } + + /* + Return from inflate(), updating the total counts and the check value. + If there was no progress during the inflate() call, return a buffer + error. Call updatewindow() to create and/or update the window state. + Note: a memory error from inflate() is non-recoverable. + */ + inf_leave: + RESTORE(); + if (state->wsize || (state->mode < CHECK && out != strm->avail_out)) + if (updatewindow(strm, out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + in -= strm->avail_in; + out -= strm->avail_out; + strm->total_in += in; + strm->total_out += out; + state->total += out; + if (state->wrap && out) + strm->adler = state->check = + UPDATE(state->check, strm->next_out - out, out); + strm->data_type = state->bits + (state->last ? 64 : 0) + + (state->mode == TYPE ? 128 : 0); + if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) + ret = Z_BUF_ERROR; + return ret; +} + +int ZEXPORT inflateEnd(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->window != Z_NULL) ZFREE(strm, state->window); + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} + +int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) +z_streamp strm; +const Bytef *dictionary; +uInt dictLength; +{ + struct inflate_state FAR *state; + unsigned long id; + + /* check state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->wrap != 0 && state->mode != DICT) + return Z_STREAM_ERROR; + + /* check for correct dictionary id */ + if (state->mode == DICT) { + id = adler32(0L, Z_NULL, 0); + id = adler32(id, dictionary, dictLength); + if (id != state->check) + return Z_DATA_ERROR; + } + + /* copy dictionary to window */ + if (updatewindow(strm, strm->avail_out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + if (dictLength > state->wsize) { + zmemcpy(state->window, dictionary + dictLength - state->wsize, + state->wsize); + state->whave = state->wsize; + } + else { + zmemcpy(state->window + state->wsize - dictLength, dictionary, + dictLength); + state->whave = dictLength; + } + state->havedict = 1; + Tracev((stderr, "inflate: dictionary set\n")); + return Z_OK; +} + +int ZEXPORT inflateGetHeader(strm, head) +z_streamp strm; +gz_headerp head; +{ + struct inflate_state FAR *state; + + /* check state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if ((state->wrap & 2) == 0) return Z_STREAM_ERROR; + + /* save header structure */ + state->head = head; + head->done = 0; + return Z_OK; +} + +/* + Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found + or when out of input. When called, *have is the number of pattern bytes + found in order so far, in 0..3. On return *have is updated to the new + state. If on return *have equals four, then the pattern was found and the + return value is how many bytes were read including the last byte of the + pattern. If *have is less than four, then the pattern has not been found + yet and the return value is len. In the latter case, syncsearch() can be + called again with more data and the *have state. *have is initialized to + zero for the first call. + */ +local unsigned syncsearch(have, buf, len) +unsigned FAR *have; +unsigned char FAR *buf; +unsigned len; +{ + unsigned got; + unsigned next; + + got = *have; + next = 0; + while (next < len && got < 4) { + if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) + got++; + else if (buf[next]) + got = 0; + else + got = 4 - got; + next++; + } + *have = got; + return next; +} + +int ZEXPORT inflateSync(strm) +z_streamp strm; +{ + unsigned len; /* number of bytes to look at or looked at */ + unsigned long in, out; /* temporary to save total_in and total_out */ + unsigned char buf[4]; /* to restore bit buffer to byte string */ + struct inflate_state FAR *state; + + /* check parameters */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; + + /* if first time, start search in bit buffer */ + if (state->mode != SYNC) { + state->mode = SYNC; + state->hold <<= state->bits & 7; + state->bits -= state->bits & 7; + len = 0; + while (state->bits >= 8) { + buf[len++] = (unsigned char)(state->hold); + state->hold >>= 8; + state->bits -= 8; + } + state->have = 0; + syncsearch(&(state->have), buf, len); + } + + /* search available input */ + len = syncsearch(&(state->have), strm->next_in, strm->avail_in); + strm->avail_in -= len; + strm->next_in += len; + strm->total_in += len; + + /* return no joy or set up to restart inflate() on a new block */ + if (state->have != 4) return Z_DATA_ERROR; + in = strm->total_in; out = strm->total_out; + inflateReset(strm); + strm->total_in = in; strm->total_out = out; + state->mode = TYPE; + return Z_OK; +} + +/* + Returns true if inflate is currently at the end of a block generated by + Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + implementation to provide an additional safety check. PPP uses + Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored + block. When decompressing, PPP checks that at the end of input packet, + inflate is waiting for these length bytes. + */ +int ZEXPORT inflateSyncPoint(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + return state->mode == STORED && state->bits == 0; +} + +int ZEXPORT inflateCopy(dest, source) +z_streamp dest; +z_streamp source; +{ + struct inflate_state FAR *state; + struct inflate_state FAR *copy; + unsigned char FAR *window; + unsigned wsize; + + /* check input */ + if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL || + source->zalloc == (alloc_func)0 || source->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)source->state; + + /* allocate space */ + copy = (struct inflate_state FAR *) + ZALLOC(source, 1, sizeof(struct inflate_state)); + if (copy == Z_NULL) return Z_MEM_ERROR; + window = Z_NULL; + if (state->window != Z_NULL) { + window = (unsigned char FAR *) + ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); + if (window == Z_NULL) { + ZFREE(source, copy); + return Z_MEM_ERROR; + } + } + + /* copy state */ + zmemcpy(dest, source, sizeof(z_stream)); + zmemcpy(copy, state, sizeof(struct inflate_state)); + if (state->lencode >= state->codes && + state->lencode <= state->codes + ENOUGH - 1) { + copy->lencode = copy->codes + (state->lencode - state->codes); + copy->distcode = copy->codes + (state->distcode - state->codes); + } + copy->next = copy->codes + (state->next - state->codes); + if (window != Z_NULL) { + wsize = 1U << state->wbits; + zmemcpy(window, state->window, wsize); + } + copy->window = window; + dest->state = (struct internal_state FAR *)copy; + return Z_OK; +} diff --git a/gdcm/Utilities/gdcmzlib/inflate.h b/gdcm/Utilities/gdcmzlib/inflate.h new file mode 100644 index 0000000..07bd3e7 --- /dev/null +++ b/gdcm/Utilities/gdcmzlib/inflate.h @@ -0,0 +1,115 @@ +/* inflate.h -- internal inflate state definition + * Copyright (C) 1995-2004 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer decoding by inflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip decoding + should be left enabled. */ +#ifndef NO_GZIP +# define GUNZIP +#endif + +/* Possible inflate modes between inflate() calls */ +typedef enum { + HEAD, /* i: waiting for magic header */ + FLAGS, /* i: waiting for method and flags (gzip) */ + TIME, /* i: waiting for modification time (gzip) */ + OS, /* i: waiting for extra flags and operating system (gzip) */ + EXLEN, /* i: waiting for extra length (gzip) */ + EXTRA, /* i: waiting for extra bytes (gzip) */ + NAME, /* i: waiting for end of file name (gzip) */ + COMMENT, /* i: waiting for end of comment (gzip) */ + HCRC, /* i: waiting for header crc (gzip) */ + DICTID, /* i: waiting for dictionary check value */ + DICT, /* waiting for inflateSetDictionary() call */ + TYPE, /* i: waiting for type bits, including last-flag bit */ + TYPEDO, /* i: same, but skip check to exit inflate on new block */ + STORED, /* i: waiting for stored size (length and complement) */ + COPY, /* i/o: waiting for input or output to copy stored block */ + TABLE, /* i: waiting for dynamic block table lengths */ + LENLENS, /* i: waiting for code length code lengths */ + CODELENS, /* i: waiting for length/lit and distance code lengths */ + LEN, /* i: waiting for length/lit code */ + LENEXT, /* i: waiting for length extra bits */ + DIST, /* i: waiting for distance code */ + DISTEXT, /* i: waiting for distance extra bits */ + MATCH, /* o: waiting for output space to copy string */ + LIT, /* o: waiting for output space to write literal */ + CHECK, /* i: waiting for 32-bit check value */ + LENGTH, /* i: waiting for 32-bit length (gzip) */ + DONE, /* finished check, done -- remain here until reset */ + BAD, /* got a data error -- remain here until reset */ + MEM, /* got an inflate() memory error -- remain here until reset */ + SYNC /* looking for synchronization bytes to restart inflate() */ +} inflate_mode; + +/* + State transitions between above modes - + + (most modes can go to the BAD or MEM mode -- not shown for clarity) + + Process header: + HEAD -> (gzip) or (zlib) + (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME + NAME -> COMMENT -> HCRC -> TYPE + (zlib) -> DICTID or TYPE + DICTID -> DICT -> TYPE + Read deflate blocks: + TYPE -> STORED or TABLE or LEN or CHECK + STORED -> COPY -> TYPE + TABLE -> LENLENS -> CODELENS -> LEN + Read deflate codes: + LEN -> LENEXT or LIT or TYPE + LENEXT -> DIST -> DISTEXT -> MATCH -> LEN + LIT -> LEN + Process trailer: + CHECK -> LENGTH -> DONE + */ + +/* state maintained between inflate() calls. Approximately 7K bytes. */ +struct inflate_state { + inflate_mode mode; /* current inflate mode */ + int last; /* true if processing last block */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + int havedict; /* true if dictionary provided */ + int flags; /* gzip header method and flags (0 if zlib) */ + unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ + unsigned long check; /* protected copy of check value */ + unsigned long total; /* protected copy of output count */ + gz_headerp head; /* where to save gzip header information */ + /* sliding window */ + unsigned wbits; /* log base 2 of requested window size */ + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned write; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if needed */ + /* bit accumulator */ + unsigned long hold; /* input bit accumulator */ + unsigned bits; /* number of bits in "in" */ + /* for string and stored block copying */ + unsigned length; /* literal or length of data to copy */ + unsigned offset; /* distance back to copy string from */ + /* for table and code decoding */ + unsigned extra; /* extra bits needed */ + /* fixed and dynamic code tables */ + code const FAR *lencode; /* starting table for length/literal codes */ + code const FAR *distcode; /* starting table for distance codes */ + unsigned lenbits; /* index bits for lencode */ + unsigned distbits; /* index bits for distcode */ + /* dynamic table building */ + unsigned ncode; /* number of code length code lengths */ + unsigned nlen; /* number of length code lengths */ + unsigned ndist; /* number of distance code lengths */ + unsigned have; /* number of code lengths in lens[] */ + code FAR *next; /* next available space in codes[] */ + unsigned short lens[320]; /* temporary storage for code lengths */ + unsigned short work[288]; /* work area for code table building */ + code codes[ENOUGH]; /* space for code tables */ +}; diff --git a/gdcm/Utilities/gdcmzlib/inftrees.c b/gdcm/Utilities/gdcmzlib/inftrees.c new file mode 100644 index 0000000..8a9c13f --- /dev/null +++ b/gdcm/Utilities/gdcmzlib/inftrees.c @@ -0,0 +1,329 @@ +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" + +#define MAXBITS 15 + +const char inflate_copyright[] = + " inflate 1.2.3 Copyright 1995-2005 Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* + Build a set of tables to decode the provided canonical Huffman code. + The code lengths are lens[0..codes-1]. The result starts at *table, + whose indices are 0..2^bits-1. work is a writable array of at least + lens shorts, which is used as a work area. type is the type of code + to be generated, CODES, LENS, or DISTS. On return, zero is success, + -1 is an invalid code, and +1 means that ENOUGH isn't enough. table + on return points to the next available entry's address. bits is the + requested root table index bits, and on return it is the actual root + table index bits. It will differ if the request is greater than the + longest code or if it is less than the shortest code. + */ +int inflate_table(type, lens, codes, table, bits, work) +codetype type; +unsigned short FAR *lens; +unsigned codes; +code FAR * FAR *table; +unsigned FAR *bits; +unsigned short FAR *work; +{ + unsigned len; /* a code's length in bits */ + unsigned sym; /* index of code symbols */ + unsigned min, max; /* minimum and maximum code lengths */ + unsigned root; /* number of index bits for root table */ + unsigned curr; /* number of index bits for current table */ + unsigned drop; /* code bits to drop for sub-table */ + int left; /* number of prefix codes available */ + unsigned used; /* code entries in table used */ + unsigned huff; /* Huffman code */ + unsigned incr; /* for incrementing code, index */ + unsigned fill; /* index for replicating entries */ + unsigned low; /* low bits for current root entry */ + unsigned mask; /* mask for low root bits */ + code this; /* table entry for duplication */ + code FAR *next; /* next available space in table */ + const unsigned short FAR *base; /* base value table to use */ + const unsigned short FAR *extra; /* extra bits table to use */ + int end; /* use base and extra for symbol > end */ + unsigned short count[MAXBITS+1]; /* number of codes of each length */ + unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ + static const unsigned short lbase[31] = { /* Length codes 257..285 base */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + static const unsigned short lext[31] = { /* Length codes 257..285 extra */ + 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 201, 196}; + static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577, 0, 0}; + static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ + 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, + 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, + 28, 28, 29, 29, 64, 64}; + + /* + Process a set of code lengths to create a canonical Huffman code. The + code lengths are lens[0..codes-1]. Each length corresponds to the + symbols 0..codes-1. The Huffman code is generated by first sorting the + symbols by length from short to long, and retaining the symbol order + for codes with equal lengths. Then the code starts with all zero bits + for the first code of the shortest length, and the codes are integer + increments for the same length, and zeros are appended as the length + increases. For the deflate format, these bits are stored backwards + from their more natural integer increment ordering, and so when the + decoding tables are built in the large loop below, the integer codes + are incremented backwards. + + This routine assumes, but does not check, that all of the entries in + lens[] are in the range 0..MAXBITS. The caller must assure this. + 1..MAXBITS is interpreted as that code length. zero means that that + symbol does not occur in this code. + + The codes are sorted by computing a count of codes for each length, + creating from that a table of starting indices for each length in the + sorted table, and then entering the symbols in order in the sorted + table. The sorted table is work[], with that space being provided by + the caller. + + The length counts are used for other purposes as well, i.e. finding + the minimum and maximum length codes, determining if there are any + codes at all, checking for a valid set of lengths, and looking ahead + at length counts to determine sub-table sizes when building the + decoding tables. + */ + + /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ + for (len = 0; len <= MAXBITS; len++) + count[len] = 0; + for (sym = 0; sym < codes; sym++) + count[lens[sym]]++; + + /* bound code lengths, force root to be within code lengths */ + root = *bits; + for (max = MAXBITS; max >= 1; max--) + if (count[max] != 0) break; + if (root > max) root = max; + if (max == 0) { /* no symbols to code at all */ + this.op = (unsigned char)64; /* invalid code marker */ + this.bits = (unsigned char)1; + this.val = (unsigned short)0; + *(*table)++ = this; /* make a table to force an error */ + *(*table)++ = this; + *bits = 1; + return 0; /* no symbols, but wait for decoding to report error */ + } + for (min = 1; min <= MAXBITS; min++) + if (count[min] != 0) break; + if (root < min) root = min; + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; + left -= count[len]; + if (left < 0) return -1; /* over-subscribed */ + } + if (left > 0 && (type == CODES || max != 1)) + return -1; /* incomplete set */ + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) + offs[len + 1] = offs[len] + count[len]; + + /* sort symbols by length, by symbol order within each length */ + for (sym = 0; sym < codes; sym++) + if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; + + /* + Create and fill in decoding tables. In this loop, the table being + filled is at next and has curr index bits. The code being used is huff + with length len. That code is converted to an index by dropping drop + bits off of the bottom. For codes where len is less than drop + curr, + those top drop + curr - len bits are incremented through all values to + fill the table with replicated entries. + + root is the number of index bits for the root table. When len exceeds + root, sub-tables are created pointed to by the root entry with an index + of the low root bits of huff. This is saved in low to check for when a + new sub-table should be started. drop is zero when the root table is + being filled, and drop is root when sub-tables are being filled. + + When a new sub-table is needed, it is necessary to look ahead in the + code lengths to determine what size sub-table is needed. The length + counts are used for this, and so count[] is decremented as codes are + entered in the tables. + + used keeps track of how many table entries have been allocated from the + provided *table space. It is checked when a LENS table is being made + against the space in *table, ENOUGH, minus the maximum space needed by + the worst case distance code, MAXD. This should never happen, but the + sufficiency of ENOUGH has not been proven exhaustively, hence the check. + This assumes that when type == LENS, bits == 9. + + sym increments through all symbols, and the loop terminates when + all codes of length max, i.e. all codes, have been processed. This + routine permits incomplete codes, so another loop after this one fills + in the rest of the decoding tables with invalid code markers. + */ + + /* set up for code type */ + switch (type) { + case CODES: + base = extra = work; /* dummy value--not used */ + end = 19; + break; + case LENS: + base = lbase; + base -= 257; + extra = lext; + extra -= 257; + end = 256; + break; + default: /* DISTS */ + base = dbase; + extra = dext; + end = -1; + } + + /* initialize state for loop */ + huff = 0; /* starting code */ + sym = 0; /* starting code symbol */ + len = min; /* starting code length */ + next = *table; /* current table to fill in */ + curr = root; /* current table index bits */ + drop = 0; /* current bits to drop from code for index */ + low = (unsigned)(-1); /* trigger new sub-table when len > root */ + used = 1U << root; /* use root table entries */ + mask = used - 1; /* mask for comparing low */ + + /* check available table space */ + if (type == LENS && used >= ENOUGH - MAXD) + return 1; + + /* process all codes and make table entries */ + for (;;) { + /* create table entry */ + this.bits = (unsigned char)(len - drop); + if ((int)(work[sym]) < end) { + this.op = (unsigned char)0; + this.val = work[sym]; + } + else if ((int)(work[sym]) > end) { + this.op = (unsigned char)(extra[work[sym]]); + this.val = base[work[sym]]; + } + else { + this.op = (unsigned char)(32 + 64); /* end of block */ + this.val = 0; + } + + /* replicate for those indices with low len bits equal to huff */ + incr = 1U << (len - drop); + fill = 1U << curr; + min = fill; /* save offset to next table */ + do { + fill -= incr; + next[(huff >> drop) + fill] = this; + } while (fill != 0); + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + + /* go to next symbol, update count, len */ + sym++; + if (--(count[len]) == 0) { + if (len == max) break; + len = lens[work[sym]]; + } + + /* create new sub-table if needed */ + if (len > root && (huff & mask) != low) { + /* if first time, transition to sub-tables */ + if (drop == 0) + drop = root; + + /* increment past last table */ + next += min; /* here min is 1 << curr */ + + /* determine length of next table */ + curr = len - drop; + left = (int)(1 << curr); + while (curr + drop < max) { + left -= count[curr + drop]; + if (left <= 0) break; + curr++; + left <<= 1; + } + + /* check for enough space */ + used += 1U << curr; + if (type == LENS && used >= ENOUGH - MAXD) + return 1; + + /* point entry in root table to sub-table */ + low = huff & mask; + (*table)[low].op = (unsigned char)curr; + (*table)[low].bits = (unsigned char)root; + (*table)[low].val = (unsigned short)(next - *table); + } + } + + /* + Fill in rest of table for incomplete codes. This loop is similar to the + loop above in incrementing huff for table indices. It is assumed that + len is equal to curr + drop, so there is no loop needed to increment + through high index bits. When the current sub-table is filled, the loop + drops back to the root table to fill in any remaining entries there. + */ + this.op = (unsigned char)64; /* invalid code marker */ + this.bits = (unsigned char)(len - drop); + this.val = (unsigned short)0; + while (huff != 0) { + /* when done with sub-table, drop back to root table */ + if (drop != 0 && (huff & mask) != low) { + drop = 0; + len = root; + next = *table; + this.bits = (unsigned char)len; + } + + /* put invalid code marker in table */ + next[huff >> drop] = this; + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + } + + /* set return parameters */ + *table += used; + *bits = root; + return 0; +} diff --git a/gdcm/Utilities/gdcmzlib/inftrees.h b/gdcm/Utilities/gdcmzlib/inftrees.h new file mode 100644 index 0000000..b1104c8 --- /dev/null +++ b/gdcm/Utilities/gdcmzlib/inftrees.h @@ -0,0 +1,55 @@ +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Structure for decoding tables. Each entry provides either the + information needed to do the operation requested by the code that + indexed that table entry, or it provides a pointer to another + table that indexes more bits of the code. op indicates whether + the entry is a pointer to another table, a literal, a length or + distance, an end-of-block, or an invalid code. For a table + pointer, the low four bits of op is the number of index bits of + that table. For a length or distance, the low four bits of op + is the number of extra bits to get after the code. bits is + the number of bits in this code or part of the code to drop off + of the bit buffer. val is the actual byte to output in the case + of a literal, the base length or distance, or the offset from + the current table to the next table. Each entry is four bytes. */ +typedef struct { + unsigned char op; /* operation, extra bits, table bits */ + unsigned char bits; /* bits in this part of the code */ + unsigned short val; /* offset in table or code value */ +} code; + +/* op values as set by inflate_table(): + 00000000 - literal + 0000tttt - table link, tttt != 0 is the number of table index bits + 0001eeee - length or distance, eeee is the number of extra bits + 01100000 - end of block + 01000000 - invalid code + */ + +/* Maximum size of dynamic tree. The maximum found in a long but non- + exhaustive search was 1444 code structures (852 for length/literals + and 592 for distances, the latter actually the result of an + exhaustive search). The true maximum is not known, but the value + below is more than safe. */ +#define ENOUGH 2048 +#define MAXD 592 + +/* Type of code to build for inftable() */ +typedef enum { + CODES, + LENS, + DISTS +} codetype; + +extern int inflate_table OF((codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work)); diff --git a/gdcm/Utilities/gdcmzlib/minigzip.c b/gdcm/Utilities/gdcmzlib/minigzip.c new file mode 100644 index 0000000..4524b96 --- /dev/null +++ b/gdcm/Utilities/gdcmzlib/minigzip.c @@ -0,0 +1,322 @@ +/* minigzip.c -- simulate gzip using the zlib compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * minigzip is a minimal implementation of the gzip utility. This is + * only an example of using zlib and isn't meant to replace the + * full-featured gzip. No attempt is made to deal with file systems + * limiting names to 14 or 8+3 characters, etc... Error checking is + * very limited. So use minigzip only for testing; use gzip for the + * real thing. On MSDOS, use only on file names without extension + * or in pipe mode. + */ + +/* @(#) $Id$ */ + +#include +#include "zlib.h" + +#ifdef STDC +# include +# include +#endif + +#ifdef USE_MMAP +# include +# include +# include +#endif + +#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__) +# include +# include +# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY) +#else +# define SET_BINARY_MODE(file) +#endif + +#ifdef VMS +# define unlink delete +# define GZ_SUFFIX "-gz" +#endif +#ifdef RISCOS +# define unlink remove +# define GZ_SUFFIX "-gz" +# define fileno(file) file->__file +#endif +#if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fileno */ +#endif + +#ifndef WIN32 /* unlink already in stdio.h for WIN32 */ + extern int unlink OF((const char *)); +#endif + +#ifndef GZ_SUFFIX +# define GZ_SUFFIX ".gz" +#endif +#define SUFFIX_LEN (sizeof(GZ_SUFFIX)-1) + +#define BUFLEN 16384 +#define MAX_NAME_LEN 1024 + +#ifdef MAXSEG_64K +# define local static + /* Needed for systems with limitation on stack size. */ +#else +# define local +#endif + +char *prog; + +void error OF((const char *msg)); +void gz_compress OF((FILE *in, gzFile out)); +#ifdef USE_MMAP +int gz_compress_mmap OF((FILE *in, gzFile out)); +#endif +void gz_uncompress OF((gzFile in, FILE *out)); +void file_compress OF((char *file, char *mode)); +void file_uncompress OF((char *file)); +int main OF((int argc, char *argv[])); + +/* =========================================================================== + * Display error message and exit + */ +void error(msg) + const char *msg; +{ + fprintf(stderr, "%s: %s\n", prog, msg); + exit(1); +} + +/* =========================================================================== + * Compress input to output then close both files. + */ + +void gz_compress(in, out) + FILE *in; + gzFile out; +{ + local char buf[BUFLEN]; + int len; + int err; + +#ifdef USE_MMAP + /* Try first compressing with mmap. If mmap fails (minigzip used in a + * pipe), use the normal fread loop. + */ + if (gz_compress_mmap(in, out) == Z_OK) return; +#endif + for (;;) { + len = (int)fread(buf, 1, sizeof(buf), in); + if (ferror(in)) { + perror("fread"); + exit(1); + } + if (len == 0) break; + + if (gzwrite(out, buf, (unsigned)len) != len) error(gzerror(out, &err)); + } + fclose(in); + if (gzclose(out) != Z_OK) error("failed gzclose"); +} + +#ifdef USE_MMAP /* MMAP version, Miguel Albrecht */ + +/* Try compressing the input file at once using mmap. Return Z_OK if + * if success, Z_ERRNO otherwise. + */ +int gz_compress_mmap(in, out) + FILE *in; + gzFile out; +{ + int len; + int err; + int ifd = fileno(in); + caddr_t buf; /* mmap'ed buffer for the entire input file */ + off_t buf_len; /* length of the input file */ + struct stat sb; + + /* Determine the size of the file, needed for mmap: */ + if (fstat(ifd, &sb) < 0) return Z_ERRNO; + buf_len = sb.st_size; + if (buf_len <= 0) return Z_ERRNO; + + /* Now do the actual mmap: */ + buf = mmap((caddr_t) 0, buf_len, PROT_READ, MAP_SHARED, ifd, (off_t)0); + if (buf == (caddr_t)(-1)) return Z_ERRNO; + + /* Compress the whole file at once: */ + len = gzwrite(out, (char *)buf, (unsigned)buf_len); + + if (len != (int)buf_len) error(gzerror(out, &err)); + + munmap(buf, buf_len); + fclose(in); + if (gzclose(out) != Z_OK) error("failed gzclose"); + return Z_OK; +} +#endif /* USE_MMAP */ + +/* =========================================================================== + * Uncompress input to output then close both files. + */ +void gz_uncompress(in, out) + gzFile in; + FILE *out; +{ + local char buf[BUFLEN]; + int len; + int err; + + for (;;) { + len = gzread(in, buf, sizeof(buf)); + if (len < 0) error (gzerror(in, &err)); + if (len == 0) break; + + if ((int)fwrite(buf, 1, (unsigned)len, out) != len) { + error("failed fwrite"); + } + } + if (fclose(out)) error("failed fclose"); + + if (gzclose(in) != Z_OK) error("failed gzclose"); +} + + +/* =========================================================================== + * Compress the given file: create a corresponding .gz file and remove the + * original. + */ +void file_compress(file, mode) + char *file; + char *mode; +{ + local char outfile[MAX_NAME_LEN]; + FILE *in; + gzFile out; + + strcpy(outfile, file); + strcat(outfile, GZ_SUFFIX); + + in = fopen(file, "rb"); + if (in == NULL) { + perror(file); + exit(1); + } + out = gzopen(outfile, mode); + if (out == NULL) { + fprintf(stderr, "%s: can't gzopen %s\n", prog, outfile); + exit(1); + } + gz_compress(in, out); + + unlink(file); +} + + +/* =========================================================================== + * Uncompress the given file and remove the original. + */ +void file_uncompress(file) + char *file; +{ + local char buf[MAX_NAME_LEN]; + char *infile, *outfile; + FILE *out; + gzFile in; + uInt len = (uInt)strlen(file); + + strcpy(buf, file); + + if (len > SUFFIX_LEN && strcmp(file+len-SUFFIX_LEN, GZ_SUFFIX) == 0) { + infile = file; + outfile = buf; + outfile[len-3] = '\0'; + } else { + outfile = file; + infile = buf; + strcat(infile, GZ_SUFFIX); + } + in = gzopen(infile, "rb"); + if (in == NULL) { + fprintf(stderr, "%s: can't gzopen %s\n", prog, infile); + exit(1); + } + out = fopen(outfile, "wb"); + if (out == NULL) { + perror(file); + exit(1); + } + + gz_uncompress(in, out); + + unlink(infile); +} + + +/* =========================================================================== + * Usage: minigzip [-d] [-f] [-h] [-r] [-1 to -9] [files...] + * -d : decompress + * -f : compress with Z_FILTERED + * -h : compress with Z_HUFFMAN_ONLY + * -r : compress with Z_RLE + * -1 to -9 : compression level + */ + +int main(argc, argv) + int argc; + char *argv[]; +{ + int uncompr = 0; + gzFile file; + char outmode[20]; + + strcpy(outmode, "wb6 "); + + prog = argv[0]; + argc--, argv++; + + while (argc > 0) { + if (strcmp(*argv, "-d") == 0) + uncompr = 1; + else if (strcmp(*argv, "-f") == 0) + outmode[3] = 'f'; + else if (strcmp(*argv, "-h") == 0) + outmode[3] = 'h'; + else if (strcmp(*argv, "-r") == 0) + outmode[3] = 'R'; + else if ((*argv)[0] == '-' && (*argv)[1] >= '1' && (*argv)[1] <= '9' && + (*argv)[2] == 0) + outmode[2] = (*argv)[1]; + else + break; + argc--, argv++; + } + if (outmode[3] == ' ') + outmode[3] = 0; + if (argc == 0) { + SET_BINARY_MODE(stdin); + SET_BINARY_MODE(stdout); + if (uncompr) { + file = gzdopen(fileno(stdin), "rb"); + if (file == NULL) error("can't gzdopen stdin"); + gz_uncompress(file, stdout); + } else { + file = gzdopen(fileno(stdout), outmode); + if (file == NULL) error("can't gzdopen stdout"); + gz_compress(stdin, file); + } + } else { + do { + if (uncompr) { + file_uncompress(*argv); + } else { + file_compress(*argv, outmode); + } + } while (argv++, --argc); + } + return 0; +} diff --git a/gdcm/Utilities/gdcmzlib/trees.c b/gdcm/Utilities/gdcmzlib/trees.c new file mode 100644 index 0000000..395e4e1 --- /dev/null +++ b/gdcm/Utilities/gdcmzlib/trees.c @@ -0,0 +1,1219 @@ +/* trees.c -- output deflated data using Huffman coding + * Copyright (C) 1995-2005 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process uses several Huffman trees. The more + * common source values are represented by shorter bit sequences. + * + * Each code tree is stored in a compressed form which is itself + * a Huffman encoding of the lengths of all the code strings (in + * ascending order by source values). The actual code strings are + * reconstructed from the lengths in the inflate process, as described + * in the deflate specification. + * + * REFERENCES + * + * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". + * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc + * + * Storer, James A. + * Data Compression: Methods and Theory, pp. 49-50. + * Computer Science Press, 1988. ISBN 0-7167-8156-5. + * + * Sedgewick, R. + * Algorithms, p290. + * Addison-Wesley, 1983. ISBN 0-201-06672-6. + */ + +/* @(#) $Id$ */ + +/* #define GEN_TREES_H */ + +#include "deflate.h" + +#ifdef DEBUG +# include +#endif + +/* =========================================================================== + * Constants + */ + +#define MAX_BL_BITS 7 +/* Bit length codes must not exceed MAX_BL_BITS bits */ + +#define END_BLOCK 256 +/* end of block literal code */ + +#define REP_3_6 16 +/* repeat previous bit length 3-6 times (2 bits of repeat count) */ + +#define REPZ_3_10 17 +/* repeat a zero length 3-10 times (3 bits of repeat count) */ + +#define REPZ_11_138 18 +/* repeat a zero length 11-138 times (7 bits of repeat count) */ + +local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ + = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; + +local const int extra_dbits[D_CODES] /* extra bits for each distance code */ + = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ + = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; + +local const uch bl_order[BL_CODES] + = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; +/* The lengths of the bit length codes are sent in order of decreasing + * probability, to avoid transmitting the lengths for unused bit length codes. + */ + +#define Buf_size (8 * 2*sizeof(char)) +/* Number of bits used within bi_buf. (bi_buf might be implemented on + * more than 16 bits on some systems.) + */ + +/* =========================================================================== + * Local data. These are initialized only once. + */ + +#define DIST_CODE_LEN 512 /* see definition of array dist_code below */ + +#if defined(GEN_TREES_H) || !defined(STDC) +/* non ANSI compilers may not accept trees.h */ + +local ct_data static_ltree[L_CODES+2]; +/* The static literal tree. Since the bit lengths are imposed, there is no + * need for the L_CODES extra codes used during heap construction. However + * The codes 286 and 287 are needed to build a canonical tree (see _tr_init + * below). + */ + +local ct_data static_dtree[D_CODES]; +/* The static distance tree. (Actually a trivial tree since all codes use + * 5 bits.) + */ + +uch _dist_code[DIST_CODE_LEN]; +/* Distance codes. The first 256 values correspond to the distances + * 3 .. 258, the last 256 values correspond to the top 8 bits of + * the 15 bit distances. + */ + +uch _length_code[MAX_MATCH-MIN_MATCH+1]; +/* length code for each normalized match length (0 == MIN_MATCH) */ + +local int base_length[LENGTH_CODES]; +/* First normalized length for each code (0 = MIN_MATCH) */ + +local int base_dist[D_CODES]; +/* First normalized distance for each code (0 = distance of 1) */ + +#else +# include "trees.h" +#endif /* GEN_TREES_H */ + +struct static_tree_desc_s { + const ct_data *static_tree; /* static tree or NULL */ + const intf *extra_bits; /* extra bits for each code or NULL */ + int extra_base; /* base index for extra_bits */ + int elems; /* max number of elements in the tree */ + int max_length; /* max bit length for the codes */ +}; + +local static_tree_desc static_l_desc = +{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; + +local static_tree_desc static_d_desc = +{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; + +local static_tree_desc static_bl_desc = +{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; + +/* =========================================================================== + * Local (static) routines in this file. + */ + +local void tr_static_init OF((void)); +local void init_block OF((deflate_state *s)); +local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); +local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); +local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); +local void build_tree OF((deflate_state *s, tree_desc *desc)); +local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local int build_bl_tree OF((deflate_state *s)); +local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, + int blcodes)); +local void compress_block OF((deflate_state *s, ct_data *ltree, + ct_data *dtree)); +local void set_data_type OF((deflate_state *s)); +local unsigned bi_reverse OF((unsigned value, int length)); +local void bi_windup OF((deflate_state *s)); +local void bi_flush OF((deflate_state *s)); +local void copy_block OF((deflate_state *s, charf *buf, unsigned len, + int header)); + +#ifdef GEN_TREES_H +local void gen_trees_header OF((void)); +#endif + +#ifndef DEBUG +# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) + /* Send a code of the given tree. c and tree must not have side effects */ + +#else /* DEBUG */ +# define send_code(s, c, tree) \ + { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ + send_bits(s, tree[c].Code, tree[c].Len); } +#endif + +/* =========================================================================== + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ +#define put_short(s, w) { \ + put_byte(s, (uch)((w) & 0xff)); \ + put_byte(s, (uch)((ush)(w) >> 8)); \ +} + +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ +#ifdef DEBUG +local void send_bits OF((deflate_state *s, int value, int length)); + +local void send_bits(s, value, length) + deflate_state *s; + int value; /* value to send */ + int length; /* number of bits */ +{ + Tracevv((stderr," l %2d v %4x ", length, value)); + Assert(length > 0 && length <= 15, "invalid length"); + s->bits_sent += (ulg)length; + + /* If not enough room in bi_buf, use (valid) bits from bi_buf and + * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) + * unused bits in value. + */ + if (s->bi_valid > (int)Buf_size - length) { + s->bi_buf |= (value << s->bi_valid); + put_short(s, s->bi_buf); + s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); + s->bi_valid += length - Buf_size; + } else { + s->bi_buf |= value << s->bi_valid; + s->bi_valid += length; + } +} +#else /* !DEBUG */ + +#define send_bits(s, value, length) \ +{ int len = length;\ + if (s->bi_valid > (int)Buf_size - len) {\ + int val = value;\ + s->bi_buf |= (val << s->bi_valid);\ + put_short(s, s->bi_buf);\ + s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ + s->bi_valid += len - Buf_size;\ + } else {\ + s->bi_buf |= (value) << s->bi_valid;\ + s->bi_valid += len;\ + }\ +} +#endif /* DEBUG */ + + +/* the arguments must not have side effects */ + +/* =========================================================================== + * Initialize the various 'constant' tables. + */ +local void tr_static_init() +{ +#if defined(GEN_TREES_H) || !defined(STDC) + static int static_init_done = 0; + int n; /* iterates over tree elements */ + int bits; /* bit counter */ + int length; /* length value */ + int code; /* code value */ + int dist; /* distance index */ + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + if (static_init_done) return; + + /* For some embedded targets, global variables are not initialized: */ + static_l_desc.static_tree = static_ltree; + static_l_desc.extra_bits = extra_lbits; + static_d_desc.static_tree = static_dtree; + static_d_desc.extra_bits = extra_dbits; + static_bl_desc.extra_bits = extra_blbits; + + /* Initialize the mapping length (0..255) -> length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES-1; code++) { + base_length[code] = length; + for (n = 0; n < (1< dist code (0..29) */ + dist = 0; + for (code = 0 ; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ + for ( ; code < D_CODES; code++) { + base_dist[code] = dist << 7; + for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { + _dist_code[256 + dist++] = (uch)code; + } + } + Assert (dist == 256, "tr_static_init: 256+dist != 512"); + + /* Construct the codes of the static literal tree */ + for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; + n = 0; + while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; + while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; + while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; + while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; + /* Codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); + + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES; n++) { + static_dtree[n].Len = 5; + static_dtree[n].Code = bi_reverse((unsigned)n, 5); + } + static_init_done = 1; + +# ifdef GEN_TREES_H + gen_trees_header(); +# endif +#endif /* defined(GEN_TREES_H) || !defined(STDC) */ +} + +/* =========================================================================== + * Genererate the file trees.h describing the static trees. + */ +#ifdef GEN_TREES_H +# ifndef DEBUG +# include +# endif + +# define SEPARATOR(i, last, width) \ + ((i) == (last)? "\n};\n\n" : \ + ((i) % (width) == (width)-1 ? ",\n" : ", ")) + +void gen_trees_header() +{ + FILE *header = fopen("trees.h", "w"); + int i; + + Assert (header != NULL, "Can't open trees.h"); + fprintf(header, + "/* header created automatically with -DGEN_TREES_H */\n\n"); + + fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); + for (i = 0; i < L_CODES+2; i++) { + fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, + static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); + } + + fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, + static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); + } + + fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n"); + for (i = 0; i < DIST_CODE_LEN; i++) { + fprintf(header, "%2u%s", _dist_code[i], + SEPARATOR(i, DIST_CODE_LEN-1, 20)); + } + + fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); + for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { + fprintf(header, "%2u%s", _length_code[i], + SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); + } + + fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); + for (i = 0; i < LENGTH_CODES; i++) { + fprintf(header, "%1u%s", base_length[i], + SEPARATOR(i, LENGTH_CODES-1, 20)); + } + + fprintf(header, "local const int base_dist[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "%5u%s", base_dist[i], + SEPARATOR(i, D_CODES-1, 10)); + } + + fclose(header); +} +#endif /* GEN_TREES_H */ + +/* =========================================================================== + * Initialize the tree data structures for a new zlib stream. + */ +void _tr_init(s) + deflate_state *s; +{ + tr_static_init(); + + s->l_desc.dyn_tree = s->dyn_ltree; + s->l_desc.stat_desc = &static_l_desc; + + s->d_desc.dyn_tree = s->dyn_dtree; + s->d_desc.stat_desc = &static_d_desc; + + s->bl_desc.dyn_tree = s->bl_tree; + s->bl_desc.stat_desc = &static_bl_desc; + + s->bi_buf = 0; + s->bi_valid = 0; + s->last_eob_len = 8; /* enough lookahead for inflate */ +#ifdef DEBUG + s->compressed_len = 0L; + s->bits_sent = 0L; +#endif + + /* Initialize the first block of the first file: */ + init_block(s); +} + +/* =========================================================================== + * Initialize a new block. + */ +local void init_block(s) + deflate_state *s; +{ + int n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; + for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; + for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; + + s->dyn_ltree[END_BLOCK].Freq = 1; + s->opt_len = s->static_len = 0L; + s->last_lit = s->matches = 0; +} + +#define SMALLEST 1 +/* Index within the heap array of least frequent node in the Huffman tree */ + + +/* =========================================================================== + * Remove the smallest element from the heap and recreate the heap with + * one less element. Updates heap and heap_len. + */ +#define pqremove(s, tree, top) \ +{\ + top = s->heap[SMALLEST]; \ + s->heap[SMALLEST] = s->heap[s->heap_len--]; \ + pqdownheap(s, tree, SMALLEST); \ +} + +/* =========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ +#define smaller(tree, n, m, depth) \ + (tree[n].Freq < tree[m].Freq || \ + (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) + +/* =========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ +local void pqdownheap(s, tree, k) + deflate_state *s; + ct_data *tree; /* the tree to restore */ + int k; /* node to move down */ +{ + int v = s->heap[k]; + int j = k << 1; /* left son of k */ + while (j <= s->heap_len) { + /* Set j to the smallest of the two sons: */ + if (j < s->heap_len && + smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { + j++; + } + /* Exit if v is smaller than both sons */ + if (smaller(tree, v, s->heap[j], s->depth)) break; + + /* Exchange v with the smallest son */ + s->heap[k] = s->heap[j]; k = j; + + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + s->heap[k] = v; +} + +/* =========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ +local void gen_bitlen(s, desc) + deflate_state *s; + tree_desc *desc; /* the tree descriptor */ +{ + ct_data *tree = desc->dyn_tree; + int max_code = desc->max_code; + const ct_data *stree = desc->stat_desc->static_tree; + const intf *extra = desc->stat_desc->extra_bits; + int base = desc->stat_desc->extra_base; + int max_length = desc->stat_desc->max_length; + int h; /* heap index */ + int n, m; /* iterate over the tree elements */ + int bits; /* bit length */ + int xbits; /* extra bits */ + ush f; /* frequency */ + int overflow = 0; /* number of elements with bit length too large */ + + for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ + + for (h = s->heap_max+1; h < HEAP_SIZE; h++) { + n = s->heap[h]; + bits = tree[tree[n].Dad].Len + 1; + if (bits > max_length) bits = max_length, overflow++; + tree[n].Len = (ush)bits; + /* We overwrite tree[n].Dad which is no longer needed */ + + if (n > max_code) continue; /* not a leaf node */ + + s->bl_count[bits]++; + xbits = 0; + if (n >= base) xbits = extra[n-base]; + f = tree[n].Freq; + s->opt_len += (ulg)f * (bits + xbits); + if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); + } + if (overflow == 0) return; + + Trace((stderr,"\nbit length overflow\n")); + /* This happens for example on obj2 and pic of the Calgary corpus */ + + /* Find the first bit length which could increase: */ + do { + bits = max_length-1; + while (s->bl_count[bits] == 0) bits--; + s->bl_count[bits]--; /* move one leaf down the tree */ + s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ + s->bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for (bits = max_length; bits != 0; bits--) { + n = s->bl_count[bits]; + while (n != 0) { + m = s->heap[--h]; + if (m > max_code) continue; + if ((unsigned) tree[m].Len != (unsigned) bits) { + Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); + s->opt_len += ((long)bits - (long)tree[m].Len) + *(long)tree[m].Freq; + tree[m].Len = (ush)bits; + } + n--; + } + } +} + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +local void gen_codes (tree, max_code, bl_count) + ct_data *tree; /* the tree to decorate */ + int max_code; /* largest code with non zero frequency */ + ushf *bl_count; /* number of codes at each bit length */ +{ + ush next_code[MAX_BITS+1]; /* next code value for each bit length */ + ush code = 0; /* running code value */ + int bits; /* bit index */ + int n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + next_code[bits] = code = (code + bl_count[bits-1]) << 1; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + Assert (code + bl_count[MAX_BITS]-1 == (1<dyn_tree; + const ct_data *stree = desc->stat_desc->static_tree; + int elems = desc->stat_desc->elems; + int n, m; /* iterate over heap elements */ + int max_code = -1; /* largest code with non zero frequency */ + int node; /* new node being created */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[0] is not used. + */ + s->heap_len = 0, s->heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) { + if (tree[n].Freq != 0) { + s->heap[++(s->heap_len)] = max_code = n; + s->depth[n] = 0; + } else { + tree[n].Len = 0; + } + } + + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while (s->heap_len < 2) { + node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); + tree[node].Freq = 1; + s->depth[node] = 0; + s->opt_len--; if (stree) s->static_len -= stree[node].Len; + /* node is 0 or 1 so it does not have extra bits */ + } + desc->max_code = max_code; + + /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + node = elems; /* next internal node of the tree */ + do { + pqremove(s, tree, n); /* n = node of least frequency */ + m = s->heap[SMALLEST]; /* m = node of next least frequency */ + + s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ + s->heap[--(s->heap_max)] = m; + + /* Create a new node father of n and m */ + tree[node].Freq = tree[n].Freq + tree[m].Freq; + s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ? + s->depth[n] : s->depth[m]) + 1); + tree[n].Dad = tree[m].Dad = (ush)node; +#ifdef DUMP_BL_TREE + if (tree == s->bl_tree) { + fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", + node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); + } +#endif + /* and insert the new node in the heap */ + s->heap[SMALLEST] = node++; + pqdownheap(s, tree, SMALLEST); + + } while (s->heap_len >= 2); + + s->heap[--(s->heap_max)] = s->heap[SMALLEST]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen(s, (tree_desc *)desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes ((ct_data *)tree, max_code, s->bl_count); +} + +/* =========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. + */ +local void scan_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + if (nextlen == 0) max_count = 138, min_count = 3; + tree[max_code+1].Len = (ush)0xffff; /* guard */ + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + s->bl_tree[curlen].Freq += count; + } else if (curlen != 0) { + if (curlen != prevlen) s->bl_tree[curlen].Freq++; + s->bl_tree[REP_3_6].Freq++; + } else if (count <= 10) { + s->bl_tree[REPZ_3_10].Freq++; + } else { + s->bl_tree[REPZ_11_138].Freq++; + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ +local void send_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + /* tree[max_code+1].Len = -1; */ /* guard already set */ + if (nextlen == 0) max_count = 138, min_count = 3; + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + do { send_code(s, curlen, s->bl_tree); } while (--count != 0); + + } else if (curlen != 0) { + if (curlen != prevlen) { + send_code(s, curlen, s->bl_tree); count--; + } + Assert(count >= 3 && count <= 6, " 3_6?"); + send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); + + } else if (count <= 10) { + send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); + + } else { + send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ +local int build_bl_tree(s) + deflate_state *s; +{ + int max_blindex; /* index of last bit length code of non zero freq */ + + /* Determine the bit length frequencies for literal and distance trees */ + scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); + scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); + + /* Build the bit length tree: */ + build_tree(s, (tree_desc *)(&(s->bl_desc))); + /* opt_len now includes the length of the tree representations, except + * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { + if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; + } + /* Update opt_len to include the bit length tree and counts */ + s->opt_len += 3*(max_blindex+1) + 5+5+4; + Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", + s->opt_len, s->static_len)); + + return max_blindex; +} + +/* =========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ +local void send_all_trees(s, lcodes, dcodes, blcodes) + deflate_state *s; + int lcodes, dcodes, blcodes; /* number of codes for each tree */ +{ + int rank; /* index in bl_order */ + + Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + "too many codes"); + Tracev((stderr, "\nbl counts: ")); + send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes-1, 5); + send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ + for (rank = 0; rank < blcodes; rank++) { + Tracev((stderr, "\nbl code %2d ", bl_order[rank])); + send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); + } + Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ + Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ + Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); +} + +/* =========================================================================== + * Send a stored block + */ +void _tr_stored_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */ +#ifdef DEBUG + s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; + s->compressed_len += (stored_len + 4) << 3; +#endif + copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ +} + +/* =========================================================================== + * Send one empty static block to give enough lookahead for inflate. + * This takes 10 bits, of which 7 may remain in the bit buffer. + * The current inflate code requires 9 bits of lookahead. If the + * last two codes for the previous block (real code plus EOB) were coded + * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode + * the last real code. In this case we send two empty static blocks instead + * of one. (There are no problems if the previous block is stored or fixed.) + * To simplify the code, we assume the worst case of last real code encoded + * on one bit only. + */ +void _tr_align(s) + deflate_state *s; +{ + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ +#endif + bi_flush(s); + /* Of the 10 bits for the empty block, we have already sent + * (10 - bi_valid) bits. The lookahead for the last real code (before + * the EOB of the previous block) was thus at least one plus the length + * of the EOB plus what we have just sent of the empty static block. + */ + if (1 + s->last_eob_len + 10 - s->bi_valid < 9) { + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; +#endif + bi_flush(s); + } + s->last_eob_len = 7; +} + +/* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and output the encoded block to the zip file. + */ +void _tr_flush_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block, or NULL if too old */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ + int max_blindex = 0; /* index of last bit length code of non zero freq */ + + /* Build the Huffman trees unless a stored block is forced */ + if (s->level > 0) { + + /* Check if the file is binary or text */ + if (stored_len > 0 && s->strm->data_type == Z_UNKNOWN) + set_data_type(s); + + /* Construct the literal and distance trees */ + build_tree(s, (tree_desc *)(&(s->l_desc))); + Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + + build_tree(s, (tree_desc *)(&(s->d_desc))); + Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(s); + + /* Determine the best encoding. Compute the block lengths in bytes. */ + opt_lenb = (s->opt_len+3+7)>>3; + static_lenb = (s->static_len+3+7)>>3; + + Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", + opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, + s->last_lit)); + + if (static_lenb <= opt_lenb) opt_lenb = static_lenb; + + } else { + Assert(buf != (char*)0, "lost buf"); + opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ + } + +#ifdef FORCE_STORED + if (buf != (char*)0) { /* force stored block */ +#else + if (stored_len+4 <= opt_lenb && buf != (char*)0) { + /* 4: two words for the lengths */ +#endif + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + _tr_stored_block(s, buf, stored_len, eof); + +#ifdef FORCE_STATIC + } else if (static_lenb >= 0) { /* force static trees */ +#else + } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) { +#endif + send_bits(s, (STATIC_TREES<<1)+eof, 3); + compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->static_len; +#endif + } else { + send_bits(s, (DYN_TREES<<1)+eof, 3); + send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, + max_blindex+1); + compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->opt_len; +#endif + } + Assert (s->compressed_len == s->bits_sent, "bad compressed size"); + /* The above check is made mod 2^32, for files larger than 512 MB + * and uLong implemented on 32 bits. + */ + init_block(s); + + if (eof) { + bi_windup(s); +#ifdef DEBUG + s->compressed_len += 7; /* align on byte boundary */ +#endif + } + Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, + s->compressed_len-7*eof)); +} + +/* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ +int _tr_tally (s, dist, lc) + deflate_state *s; + unsigned dist; /* distance of matched string */ + unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ +{ + s->d_buf[s->last_lit] = (ush)dist; + s->l_buf[s->last_lit++] = (uch)lc; + if (dist == 0) { + /* lc is the unmatched char */ + s->dyn_ltree[lc].Freq++; + } else { + s->matches++; + /* Here, lc is the match length - MIN_MATCH */ + dist--; /* dist = match distance - 1 */ + Assert((ush)dist < (ush)MAX_DIST(s) && + (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && + (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); + + s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; + s->dyn_dtree[d_code(dist)].Freq++; + } + +#ifdef TRUNCATE_BLOCK + /* Try to guess if it is profitable to stop the current block here */ + if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { + /* Compute an upper bound for the compressed length */ + ulg out_length = (ulg)s->last_lit*8L; + ulg in_length = (ulg)((long)s->strstart - s->block_start); + int dcode; + for (dcode = 0; dcode < D_CODES; dcode++) { + out_length += (ulg)s->dyn_dtree[dcode].Freq * + (5L+extra_dbits[dcode]); + } + out_length >>= 3; + Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", + s->last_lit, in_length, out_length, + 100L - out_length*100L/in_length)); + if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; + } +#endif + return (s->last_lit == s->lit_bufsize-1); + /* We avoid equality with lit_bufsize because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ +} + +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +local void compress_block(s, ltree, dtree) + deflate_state *s; + ct_data *ltree; /* literal tree */ + ct_data *dtree; /* distance tree */ +{ + unsigned dist; /* distance of matched string */ + int lc; /* match length or unmatched char (if dist == 0) */ + unsigned lx = 0; /* running index in l_buf */ + unsigned code; /* the code to send */ + int extra; /* number of extra bits to send */ + + if (s->last_lit != 0) do { + dist = s->d_buf[lx]; + lc = s->l_buf[lx++]; + if (dist == 0) { + send_code(s, lc, ltree); /* send a literal byte */ + Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = _length_code[lc]; + send_code(s, code+LITERALS+1, ltree); /* send the length code */ + extra = extra_lbits[code]; + if (extra != 0) { + lc -= base_length[code]; + send_bits(s, lc, extra); /* send the extra length bits */ + } + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + Assert (code < D_CODES, "bad d_code"); + + send_code(s, code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra != 0) { + dist -= base_dist[code]; + send_bits(s, dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + + /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ + Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, + "pendingBuf overflow"); + + } while (lx < s->last_lit); + + send_code(s, END_BLOCK, ltree); + s->last_eob_len = ltree[END_BLOCK].Len; +} + +/* =========================================================================== + * Set the data type to BINARY or TEXT, using a crude approximation: + * set it to Z_TEXT if all symbols are either printable characters (33 to 255) + * or white spaces (9 to 13, or 32); or set it to Z_BINARY otherwise. + * IN assertion: the fields Freq of dyn_ltree are set. + */ +local void set_data_type(s) + deflate_state *s; +{ + int n; + + for (n = 0; n < 9; n++) + if (s->dyn_ltree[n].Freq != 0) + break; + if (n == 9) + for (n = 14; n < 32; n++) + if (s->dyn_ltree[n].Freq != 0) + break; + s->strm->data_type = (n == 32) ? Z_TEXT : Z_BINARY; +} + +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ +local unsigned bi_reverse(code, len) + unsigned code; /* the value to invert */ + int len; /* its bit length */ +{ + register unsigned res = 0; + do { + res |= code & 1; + code >>= 1, res <<= 1; + } while (--len > 0); + return res >> 1; +} + +/* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ +local void bi_flush(s) + deflate_state *s; +{ + if (s->bi_valid == 16) { + put_short(s, s->bi_buf); + s->bi_buf = 0; + s->bi_valid = 0; + } else if (s->bi_valid >= 8) { + put_byte(s, (Byte)s->bi_buf); + s->bi_buf >>= 8; + s->bi_valid -= 8; + } +} + +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ +local void bi_windup(s) + deflate_state *s; +{ + if (s->bi_valid > 8) { + put_short(s, s->bi_buf); + } else if (s->bi_valid > 0) { + put_byte(s, (Byte)s->bi_buf); + } + s->bi_buf = 0; + s->bi_valid = 0; +#ifdef DEBUG + s->bits_sent = (s->bits_sent+7) & ~7; +#endif +} + +/* =========================================================================== + * Copy a stored block, storing first the length and its + * one's complement if requested. + */ +local void copy_block(s, buf, len, header) + deflate_state *s; + charf *buf; /* the input data */ + unsigned len; /* its length */ + int header; /* true if block header must be written */ +{ + bi_windup(s); /* align on byte boundary */ + s->last_eob_len = 8; /* enough lookahead for inflate */ + + if (header) { + put_short(s, (ush)len); + put_short(s, (ush)~len); +#ifdef DEBUG + s->bits_sent += 2*16; +#endif + } +#ifdef DEBUG + s->bits_sent += (ulg)len<<3; +#endif + while (len--) { + put_byte(s, *buf++); + } +} diff --git a/gdcm/Utilities/gdcmzlib/trees.h b/gdcm/Utilities/gdcmzlib/trees.h new file mode 100644 index 0000000..72facf9 --- /dev/null +++ b/gdcm/Utilities/gdcmzlib/trees.h @@ -0,0 +1,128 @@ +/* header created automatically with -DGEN_TREES_H */ + +local const ct_data static_ltree[L_CODES+2] = { +{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, +{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, +{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, +{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, +{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, +{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, +{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, +{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, +{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, +{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, +{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, +{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, +{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, +{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, +{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, +{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, +{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, +{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, +{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, +{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, +{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, +{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, +{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, +{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, +{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, +{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, +{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, +{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, +{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, +{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, +{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, +{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, +{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, +{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, +{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, +{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, +{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, +{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, +{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, +{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, +{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, +{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, +{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, +{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, +{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, +{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, +{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, +{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, +{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, +{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, +{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, +{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, +{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, +{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, +{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, +{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, +{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, +{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} +}; + +local const ct_data static_dtree[D_CODES] = { +{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, +{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, +{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, +{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, +{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, +{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} +}; + +const uch _dist_code[DIST_CODE_LEN] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, +10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, +11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, +12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, +18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 +}; + +const uch _length_code[MAX_MATCH-MIN_MATCH+1]= { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, +13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, +17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, +19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, +21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, +22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 +}; + +local const int base_length[LENGTH_CODES] = { +0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, +64, 80, 96, 112, 128, 160, 192, 224, 0 +}; + +local const int base_dist[D_CODES] = { + 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, + 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, + 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 +}; + diff --git a/gdcm/Utilities/gdcmzlib/uncompr.c b/gdcm/Utilities/gdcmzlib/uncompr.c new file mode 100644 index 0000000..b59e3d0 --- /dev/null +++ b/gdcm/Utilities/gdcmzlib/uncompr.c @@ -0,0 +1,61 @@ +/* uncompr.c -- decompress a memory buffer + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted. +*/ +int ZEXPORT uncompress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; + + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + + err = inflateInit(&stream); + if (err != Z_OK) return err; + + err = inflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + inflateEnd(&stream); + if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) + return Z_DATA_ERROR; + return err; + } + *destLen = stream.total_out; + + err = inflateEnd(&stream); + return err; +} diff --git a/gdcm/Utilities/gdcmzlib/zconf.in.h b/gdcm/Utilities/gdcmzlib/zconf.in.h new file mode 100644 index 0000000..6234486 --- /dev/null +++ b/gdcm/Utilities/gdcmzlib/zconf.in.h @@ -0,0 +1,338 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#ifndef ZCONF_H +#define ZCONF_H + +#cmakedefine ZLIB_DLL + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + */ +#ifdef Z_PREFIX +# define deflateInit_ z_deflateInit_ +# define deflate z_deflate +# define deflateEnd z_deflateEnd +# define inflateInit_ z_inflateInit_ +# define inflate z_inflate +# define inflateEnd z_inflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateSetDictionary z_deflateSetDictionary +# define deflateCopy z_deflateCopy +# define deflateReset z_deflateReset +# define deflateParams z_deflateParams +# define deflateBound z_deflateBound +# define deflatePrime z_deflatePrime +# define inflateInit2_ z_inflateInit2_ +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateCopy z_inflateCopy +# define inflateReset z_inflateReset +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# define uncompress z_uncompress +# define adler32 z_adler32 +# define crc32 z_crc32 +# define get_crc_table z_get_crc_table +# define zError z_zError + +# define alloc_func z_alloc_func +# define free_func z_free_func +# define in_func z_in_func +# define out_func z_out_func +# define Byte z_Byte +# define uInt z_uInt +# define uLong z_uLong +# define Bytef z_Bytef +# define charf z_charf +# define intf z_intf +# define uIntf z_uIntf +# define uLongf z_uLongf +# define voidpf z_voidpf +# define voidp z_voidp +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# if __GNUC__ >= 4 +# define ZEXTERN __attribute__ ((visibility ("default"))) +# else +# define ZEXTERN extern +# endif +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */ +# include /* for off_t */ +# include /* for SEEK_* and off_t */ +# ifdef VMS +# include /* for off_t */ +# endif +# define z_off_t off_t +#endif +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif +#ifndef z_off_t +# define z_off_t long +#endif + +#if defined(__OS400__) +# define NO_vsnprintf +#endif + +#if defined(__MVS__) +# define NO_vsnprintf +# ifdef FAR +# undef FAR +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) +# pragma map(deflateInit_,"DEIN") +# pragma map(deflateInit2_,"DEIN2") +# pragma map(deflateEnd,"DEEND") +# pragma map(deflateBound,"DEBND") +# pragma map(inflateInit_,"ININ") +# pragma map(inflateInit2_,"ININ2") +# pragma map(inflateEnd,"INEND") +# pragma map(inflateSync,"INSY") +# pragma map(inflateSetDictionary,"INSEDI") +# pragma map(compressBound,"CMBND") +# pragma map(inflate_table,"INTABL") +# pragma map(inflate_fast,"INFA") +# pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/gdcm/Utilities/gdcmzlib/zlib.3 b/gdcm/Utilities/gdcmzlib/zlib.3 new file mode 100644 index 0000000..90b8162 --- /dev/null +++ b/gdcm/Utilities/gdcmzlib/zlib.3 @@ -0,0 +1,159 @@ +.TH ZLIB 3 "18 July 2005" +.SH NAME +zlib \- compression/decompression library +.SH SYNOPSIS +[see +.I zlib.h +for full description] +.SH DESCRIPTION +The +.I zlib +library is a general purpose data compression library. +The code is thread safe. +It provides in-memory compression and decompression functions, +including integrity checks of the uncompressed data. +This version of the library supports only one compression method (deflation) +but other algorithms will be added later +and will have the same stream interface. +.LP +Compression can be done in a single step if the buffers are large enough +(for example if an input file is mmap'ed), +or can be done by repeated calls of the compression function. +In the latter case, +the application must provide more input and/or consume the output +(providing more output space) before each call. +.LP +The library also supports reading and writing files in +.IR gzip (1) +(.gz) format +with an interface similar to that of stdio. +.LP +The library does not install any signal handler. +The decoder checks the consistency of the compressed data, +so the library should never crash even in case of corrupted input. +.LP +All functions of the compression library are documented in the file +.IR zlib.h . +The distribution source includes examples of use of the library +in the files +.I example.c +and +.IR minigzip.c . +.LP +Changes to this version are documented in the file +.I ChangeLog +that accompanies the source, +and are concerned primarily with bug fixes and portability enhancements. +.LP +A Java implementation of +.I zlib +is available in the Java Development Kit 1.1: +.IP +http://www.javasoft.com/products/JDK/1.1/docs/api/Package-java.util.zip.html +.LP +A Perl interface to +.IR zlib , +written by Paul Marquess (pmqs@cpan.org), +is available at CPAN (Comprehensive Perl Archive Network) sites, +including: +.IP +http://www.cpan.org/modules/by-module/Compress/ +.LP +A Python interface to +.IR zlib , +written by A.M. Kuchling (amk@magnet.com), +is available in Python 1.5 and later versions: +.IP +http://www.python.org/doc/lib/module-zlib.html +.LP +A +.I zlib +binding for +.IR tcl (1), +written by Andreas Kupries (a.kupries@westend.com), +is availlable at: +.IP +http://www.westend.com/~kupries/doc/trf/man/man.html +.LP +An experimental package to read and write files in .zip format, +written on top of +.I zlib +by Gilles Vollant (info@winimage.com), +is available at: +.IP +http://www.winimage.com/zLibDll/unzip.html +and also in the +.I contrib/minizip +directory of the main +.I zlib +web site. +.SH "SEE ALSO" +The +.I zlib +web site can be found at either of these locations: +.IP +http://www.zlib.org +.br +http://www.gzip.org/zlib/ +.LP +The data format used by the zlib library is described by RFC +(Request for Comments) 1950 to 1952 in the files: +.IP +http://www.ietf.org/rfc/rfc1950.txt (concerning zlib format) +.br +http://www.ietf.org/rfc/rfc1951.txt (concerning deflate format) +.br +http://www.ietf.org/rfc/rfc1952.txt (concerning gzip format) +.LP +These documents are also available in other formats from: +.IP +ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html +.LP +Mark Nelson (markn@ieee.org) wrote an article about +.I zlib +for the Jan. 1997 issue of Dr. Dobb's Journal; +a copy of the article is available at: +.IP +http://dogma.net/markn/articles/zlibtool/zlibtool.htm +.SH "REPORTING PROBLEMS" +Before reporting a problem, +please check the +.I zlib +web site to verify that you have the latest version of +.IR zlib ; +otherwise, +obtain the latest version and see if the problem still exists. +Please read the +.I zlib +FAQ at: +.IP +http://www.gzip.org/zlib/zlib_faq.html +.LP +before asking for help. +Send questions and/or comments to zlib@gzip.org, +or (for the Windows DLL version) to Gilles Vollant (info@winimage.com). +.SH AUTHORS +Version 1.2.3 +Copyright (C) 1995-2005 Jean-loup Gailly (jloup@gzip.org) +and Mark Adler (madler@alumni.caltech.edu). +.LP +This software is provided "as-is," +without any express or implied warranty. +In no event will the authors be held liable for any damages +arising from the use of this software. +See the distribution directory with respect to requirements +governing redistribution. +The deflate format used by +.I zlib +was defined by Phil Katz. +The deflate and +.I zlib +specifications were written by L. Peter Deutsch. +Thanks to all the people who reported problems and suggested various +improvements in +.IR zlib ; +who are too numerous to cite here. +.LP +UNIX manual page by R. P. C. Rodgers, +U.S. National Library of Medicine (rodgers@nlm.nih.gov). +.\" end of man page diff --git a/gdcm/Utilities/gdcmzlib/zlib.def.in b/gdcm/Utilities/gdcmzlib/zlib.def.in new file mode 100644 index 0000000..74dfdb8 --- /dev/null +++ b/gdcm/Utilities/gdcmzlib/zlib.def.in @@ -0,0 +1,92 @@ + +VERSION 1.23 + +HEAPSIZE 1048576,8192 + +EXPORTS + adler32 @1 + compress @2 + crc32 @3 + deflate @4 + deflateCopy @5 + deflateEnd @6 + deflateInit2_ @7 + deflateInit_ @8 + deflateParams @9 + deflateReset @10 + deflateSetDictionary @11 + gzclose @12 + gzdopen @13 + gzerror @14 + gzflush @15 + gzopen @16 + gzread @17 + gzwrite @18 + inflate @19 + inflateEnd @20 + inflateInit2_ @21 + inflateInit_ @22 + inflateReset @23 + inflateSetDictionary @24 + inflateSync @25 + uncompress @26 + zlibVersion @27 + gzprintf @28 + gzputc @29 + gzgetc @30 + gzseek @31 + gzrewind @32 + gztell @33 + gzeof @34 + gzsetparams @35 + zError @36 + inflateSyncPoint @37 + get_crc_table @38 + compress2 @39 + gzputs @40 + gzgets @41 + inflateCopy @42 + inflateBackInit_ @43 + inflateBack @44 + inflateBackEnd @45 + compressBound @46 + deflateBound @47 + gzclearerr @48 + gzungetc @49 + zlibCompileFlags @50 + deflatePrime @51 + + unzOpen @61 + unzClose @62 + unzGetGlobalInfo @63 + unzGetCurrentFileInfo @64 + unzGoToFirstFile @65 + unzGoToNextFile @66 + unzOpenCurrentFile @67 + unzReadCurrentFile @68 + unzOpenCurrentFile3 @69 + unztell @70 + unzeof @71 + unzCloseCurrentFile @72 + unzGetGlobalComment @73 + unzStringFileNameCompare @74 + unzLocateFile @75 + unzGetLocalExtrafield @76 + unzOpen2 @77 + unzOpenCurrentFile2 @78 + unzOpenCurrentFilePassword @79 + + zipOpen @80 + zipOpenNewFileInZip @81 + zipWriteInFileInZip @82 + zipCloseFileInZip @83 + zipClose @84 + zipOpenNewFileInZip2 @86 + zipCloseFileInZipRaw @87 + zipOpen2 @88 + zipOpenNewFileInZip3 @89 + + unzGetFilePos @100 + unzGoToFilePos @101 + + fill_win32_filefunc @110 diff --git a/gdcm/Utilities/gdcmzlib/zlib.h b/gdcm/Utilities/gdcmzlib/zlib.h new file mode 100644 index 0000000..0228179 --- /dev/null +++ b/gdcm/Utilities/gdcmzlib/zlib.h @@ -0,0 +1,1357 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.3, July 18th, 2005 + + Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.2.3" +#define ZLIB_VERNUM 0x1230 + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed + data. This version of the library supports only one compression method + (deflation) but other algorithms will be added later and will have the same + stream interface. + + Compression can be done in a single step if the buffers are large + enough (for example if an input file is mmap'ed), or can be done by + repeated calls of the compression function. In the latter case, the + application must provide more input and/or consume the output + (providing more output space) before each call. + + The compressed data format used by default by the in-memory functions is + the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped + around a deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + This library can optionally read and write gzip streams in memory as well. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never + crash even in case of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total nb of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total nb of bytes output so far */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: binary or text */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + gzip header information passed to and from zlib routines. See RFC 1952 + for more details on the meanings of these fields. +*/ +typedef struct gz_header_s { + int text; /* true if compressed data believed to be text */ + uLong time; /* modification time */ + int xflags; /* extra flags (not used when writing a gzip file) */ + int os; /* operating system */ + Bytef *extra; /* pointer to extra field or Z_NULL if none */ + uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ + uInt extra_max; /* space at extra (only when reading header) */ + Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ + uInt name_max; /* space at name (only when reading header) */ + Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ + uInt comm_max; /* space at comment (only when reading header) */ + int hcrc; /* true if there was or will be a header crc */ + int done; /* true when done reading gzip header (not used + when writing a gzip file) */ +} gz_header; + +typedef gz_header FAR *gz_headerp; + +/* + The application must update next_in and avail_in when avail_in has + dropped to zero. It must update next_out and avail_out when avail_out + has dropped to zero. The application must initialize zalloc, zfree and + opaque before calling the init function. All other fields are set by the + compression library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this + if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, + pointers returned by zalloc for objects of exactly 65536 bytes *must* + have their offset normalized to zero. The default allocation function + provided by this library ensures this (see zutil.c). To reduce memory + requirements and avoid any allocation of 64K objects, at the expense of + compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or + progress reports. After compression, total_in holds the total size of + the uncompressed data and may be saved for use in the decompressor + (particularly if the decompressor wants to decompress everything in + a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +/* Allowed flush values; see deflate() and inflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative + * values are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_FIXED 4 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_TEXT 1 +#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ +#define Z_UNKNOWN 2 +/* Possible values of the data_type field (though see inflate()) */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is + not compatible with the zlib.h header file used by the application. + This check is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. + If zalloc and zfree are set to Z_NULL, deflateInit updates them to + use default allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at + all (the input data is simply copied a block at a time). + Z_DEFAULT_COMPRESSION requests a default compromise between speed and + compression (currently equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if level is not a valid compression level, + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). + msg is set to null if there is no error message. deflateInit does not + perform any compression: this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce some + output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). + Some output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating avail_in or avail_out accordingly; avail_out + should never be zero before the call. The application can consume the + compressed output when it wants, for example when the output buffer is full + (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK + and with zero avail_out, it must be called again after making room in the + output buffer because there might be more output pending. + + Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to + decide how much data to accumualte before producing output, in order to + maximize compression. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In particular + avail_in is zero after the call if enough output space has been provided + before the call.) Flushing may degrade compression for some compression + algorithms and so it should be used only when necessary. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six to avoid repeated flush markers due to + avail_out == 0 on return. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there + was enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the + stream are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least + the value returned by deflateBound (see below). If deflate does not return + Z_STREAM_END, then it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so far (that is, total_in bytes). + + deflate() may update strm->data_type if it can make a good guess about + the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered + binary. This field is only for information purposes and does not affect + the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not + fatal, and deflate() can be called again with more input and more output + space to continue compressing. +*/ + + +ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, + msg may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the exact + value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller. msg is set to null if there is no error + message. inflateInit does not perform any decompression apart from reading + the zlib header if present: this will be done by inflate(). (So next_in and + avail_in may be modified, but next_out and avail_out are unchanged.) +*/ + + +ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing + will resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there + is no more input data or no more space in the output buffer (see below + about the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating the next_* and avail_* values accordingly. + The application can consume the uncompressed output when it wants, for + example when the output buffer is full (avail_out == 0), or after each + call of inflate(). If inflate returns Z_OK and with zero avail_out, it + must be called again after making room in the output buffer because there + might be more output pending. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, + Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() stop + if and when it gets to the next deflate block boundary. When decoding the + zlib or gzip format, this will cause inflate() to return immediately after + the header and before the first block. When doing a raw inflate, inflate() + will go ahead and process the first block, and will return when it gets to + the end of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + Also to assist in this, on return inflate() will set strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 + if inflate() is currently decoding the last block in the deflate stream, + plus 128 if inflate() returned immediately after decoding an end-of-block + code or decoding the complete header up to just before the first byte of the + deflate stream. The end-of-block will not be indicated until all of the + uncompressed data from that block has been written to strm->next_out. The + number of unused bits may in general be greater than seven, except when + bit 7 of data_type is set, in which case the number of unused bits will be + less than eight. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step + (a single call of inflate), the parameter flush should be set to + Z_FINISH. In this case all pending input is processed and all pending + output is flushed; avail_out must be large enough to hold all the + uncompressed data. (The size of the uncompressed data may have been saved + by the compressor for this purpose.) The next operation on this stream must + be inflateEnd to deallocate the decompression state. The use of Z_FINISH + is never required, but can be used to inform inflate that a faster approach + may be used for the single inflate() call. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the only effect of the flush parameter in this implementation + is on the return value of inflate(), as noted below, or when it returns early + because Z_BLOCK is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm->adler to the adler32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the adler32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed adler32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() will decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically. Any information + contained in the gzip header is not retained, so applications that need that + information should instead use raw inflate, see inflateInit2() below, or + inflateBack() and perform their own processing of the gzip header and + trailer. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect check + value), Z_STREAM_ERROR if the stream structure was inconsistent (for example + if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory, + Z_BUF_ERROR if no progress is possible or if there was not enough room in the + output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may then + call inflateSync() to look for a good compression block if a partial recovery + of the data is desired. +*/ + + +ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by + the caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute an adler32 check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), + no header crc, and the operating system will be set to 255 (unknown). If a + gzip stream is being written, strm->adler is a crc32 instead of an adler32. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but + is slow and reduces compression ratio; memLevel=9 uses maximum memory + for optimal speed. The default value is 8. See zconf.h for total memory + usage as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as + Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy + parameter only affects the compression ratio but not the correctness of the + compressed output even if it is not set appropriately. Z_FIXED prevents the + use of dynamic Huffman codes, allowing for a simpler decoder for special + applications. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid + method). msg is set to null if there is no error message. deflateInit2 does + not perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. This function must be called + immediately after deflateInit, deflateInit2 or deflateReset, before any + call of deflate. The compressor and decompressor must use exactly the same + dictionary (see inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size in + deflate or deflate2. Thus the strings most likely to be useful should be + put at the end of the dictionary, not at the front. In addition, the + current implementation of deflate will use at most the window size minus + 262 bytes of the provided dictionary. + + Upon return of this function, strm->adler is set to the adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) If a raw deflate was requested, then the + adler32 value is not computed and strm->adler is not set. + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if the compression method is bsort). deflateSetDictionary does not + perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and + can consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. + The stream will keep the same compression level and any other attributes + that may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different + strategy. If the compression level is changed, the input available so far + is compressed with the old level (and may be flushed); the new level will + take effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to + be compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR + if strm->avail_out was zero. +*/ + +ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, + int good_length, + int max_lazy, + int nice_length, + int max_chain)); +/* + Fine tune deflate's internal compression parameters. This should only be + used by someone who understands the algorithm used by zlib's deflate for + searching for the best matching string, and even then only by the most + fanatic optimizer trying to squeeze out the last compressed bit for their + specific input data. Read the deflate.c source code for the meaning of the + max_lazy, good_length, nice_length, and max_chain parameters. + + deflateTune() can be called after deflateInit() or deflateInit2(), and + returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. + */ + +ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, + uLong sourceLen)); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() + or deflateInit2(). This would be used to allocate an output buffer + for deflation in a single pass, and so would be called before deflate(). +*/ + +ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the + bits leftover from a previous deflate stream when appending to it. As such, + this function can only be used for raw deflate, and must be used before the + first deflate() call after a deflateInit2() or deflateReset(). bits must be + less than or equal to 16, and that many of the least significant bits of + value will be inserted in the output. + + deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, + gz_headerp head)); +/* + deflateSetHeader() provides gzip header information for when a gzip + stream is requested by deflateInit2(). deflateSetHeader() may be called + after deflateInit2() or deflateReset() and before the first call of + deflate(). The text, time, os, extra field, name, and comment information + in the provided gz_header structure are written to the gzip header (xflag is + ignored -- the extra flags are set according to the compression level). The + caller must assure that, if not Z_NULL, name and comment are terminated with + a zero byte, and that if extra is not Z_NULL, that extra_len bytes are + available there. If hcrc is true, a gzip header crc is included. Note that + the current versions of the command-line version of gzip (up through version + 1.3.x) do not support header crc's, and will report that it is a "multi-part + gzip file" and give up. + + If deflateSetHeader is not used, the default gzip header has text false, + the time set to zero, and os set to 255, with no extra, name, or comment + fields. The gzip header is returned to the default state by deflateReset(). + + deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an adler32 or a crc32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is + a crc32 instead of an adler32. + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as a null strm). msg + is set to null if there is no error message. inflateInit2 does not perform + any decompression apart from reading the zlib header if present: this will + be done by inflate(). (So next_in and avail_in may be modified, but next_out + and avail_out are unchanged.) +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate, + if that call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the adler32 value returned by that call of inflate. + The compressor and decompressor must use exactly the same dictionary (see + deflateSetDictionary). For raw inflate, this function can be called + immediately after inflateInit2() or inflateReset() and before any call of + inflate() to set the dictionary. The application must insure that the + dictionary that was used for compression is provided. + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a full flush point (see above the + description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR + if no more input was provided, Z_DATA_ERROR if no flush point has been found, + or Z_STREAM_ERROR if the stream structure was inconsistent. In the success + case, the application may save the current current value of total_in which + indicates where valid compressed data was found. In the error case, the + application may repeatedly call inflateSync, providing more input each time, + until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. + The stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + This function inserts bits in the inflate input stream. The intent is + that this function is used to start inflating at a bit position in the + middle of a byte. The provided bits will be used before any bytes are used + from next_in. This function should only be used with raw inflate, and + should be used before the first inflate() call after inflateInit2() or + inflateReset(). bits must be less than or equal to 16, and that many of the + least significant bits of value will be inserted in the input. + + inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, + gz_headerp head)); +/* + inflateGetHeader() requests that gzip header information be stored in the + provided gz_header structure. inflateGetHeader() may be called after + inflateInit2() or inflateReset(), and before the first call of inflate(). + As inflate() processes the gzip stream, head->done is zero until the header + is completed, at which time head->done is set to one. If a zlib stream is + being decoded, then head->done is set to -1 to indicate that there will be + no gzip header information forthcoming. Note that Z_BLOCK can be used to + force inflate() to return immediately after header processing is complete + and before any actual data is decompressed. + + The text, time, xflags, and os fields are filled in with the gzip header + contents. hcrc is set to true if there is a header CRC. (The header CRC + was valid if done is set to one.) If extra is not Z_NULL, then extra_max + contains the maximum number of bytes to write to extra. Once done is true, + extra_len contains the actual extra field length, and extra contains the + extra field, or that field truncated if extra_max is less than extra_len. + If name is not Z_NULL, then up to name_max characters are written there, + terminated with a zero unless the length is greater than name_max. If + comment is not Z_NULL, then up to comm_max characters are written there, + terminated with a zero unless the length is greater than comm_max. When + any of extra, name, or comment are not Z_NULL and the respective field is + not present in the header, then that field is set to Z_NULL to signal its + absence. This allows the use of deflateSetHeader() with the returned + structure to duplicate the header. However if those fields are set to + allocated memory, then the application will need to save those pointers + elsewhere so that they can be eventually freed. + + If inflateGetHeader is not used, then the header information is simply + discarded. The header is always checked for validity, including the header + CRC if present. inflateReset() will reset the process to discard the header + information. The application would need to call inflateGetHeader() again to + retrieve the header from the next gzip stream. + + inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, + unsigned char FAR *window)); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the paramaters are invalid, Z_MEM_ERROR if the internal state could not + be allocated, or Z_VERSION_ERROR if the version of the library does not + match the version of the header file. +*/ + +typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); +typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); + +ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is more efficient than inflate() for + file i/o applications in that it avoids copying between the output and the + sliding window by simply making the window itself the output buffer. This + function trusts the application to not change the output buffer passed by + the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free + the allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects + only the raw deflate stream to decompress. This is different from the + normal behavior of inflate(), which expects either a zlib or gzip header and + trailer around the deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero--buf is ignored in that + case--and inflateBack() will return a buffer error. inflateBack() will call + out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() + should return zero on success, or non-zero on failure. If out() returns + non-zero, inflateBack() will return with an error. Neither in() nor out() + are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format + error in the deflate stream (in which case strm->msg is set to indicate the + nature of the error), or Z_STREAM_ERROR if the stream was not properly + initialized. In the case of Z_BUF_ERROR, an input or output error can be + distinguished using strm->next_in which will be Z_NULL only if in() returned + an error. If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to + out() returning non-zero. (in() will always be called before out(), so + strm->next_in is assured to be defined if out() returns non-zero.) Note + that inflateBack() cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + + + /* utility functions */ + +/* + The following utility functions are implemented on top of the + basic stream-oriented functions. To simplify the interface, some + default options are assumed (compression level and memory usage, + standard memory allocation functions). The source code of these + utility functions can easily be modified if you need special options. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be at least the value returned + by compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + This function can be used to compress a whole file at once if the + input file is mmap'ed. + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before + a compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. +*/ + + +typedef voidp gzFile; + +ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); +/* + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb") but can also include a compression level + ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for + Huffman only compression as in "wb1h", or 'R' for run-length encoding + as in "wb1R". (See the description of deflateInit2 for more information + about the strategy parameter.) + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. + + gzopen returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). */ + +ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +/* + gzdopen() associates a gzFile with the file descriptor fd. File + descriptors are obtained from calls like open, dup, creat, pipe or + fileno (in the file has been previously opened with fopen). + The mode parameter is as in gzopen. + The next call of gzclose on the returned gzFile will also close the + file descriptor fd, just like fclose(fdopen(fd), mode) closes the file + descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). + gzdopen returns NULL if there was insufficient memory to allocate + the (de)compression state. +*/ + +ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. + If the input file was not in gzip format, gzread copies the given number + of bytes into the buffer. + gzread returns the number of uncompressed bytes actually read (0 for + end of file, -1 for error). */ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + voidpc buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes actually written + (0 in case of error). +*/ + +ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). The number of + uncompressed bytes written is limited to 4095. The caller should assure that + this limit is not exceeded. If it is exceeded, then gzprintf() will return + return an error (0) with nothing written. In this case, there may also be a + buffer overflow with unpredictable consequences, which is possible only if + zlib was compiled with the insecure functions sprintf() or vsprintf() + because the secure snprintf() or vsnprintf() functions were not available. +*/ + +ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or + a newline character is read and transferred to buf, or an end-of-file + condition is encountered. The string is then terminated with a null + character. + gzgets returns buf, or Z_NULL in case of error. +*/ + +ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ + +ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +/* + Push one character back onto the stream to be read again later. + Only one character of push-back is allowed. gzungetc() returns the + character pushed, or -1 on failure. gzungetc() will fail if a + character has been pushed but not read yet, or if c is -1. The pushed + character will be discarded if the stream is repositioned with gzseek() + or gzrewind(). +*/ + +ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. The return value is the zlib + error number (see function gzerror below). gzflush returns Z_OK if + the flush parameter is Z_FINISH and all output could be flushed. + gzflush should be called only when strictly necessary because it can + degrade compression. +*/ + +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t offset, int whence)); +/* + Sets the starting position for the next gzread or gzwrite on the + given compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); +/* + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ + +ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); +/* + Returns 1 if file is being read directly without decompression, otherwise + zero. +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. The return value is the zlib + error number (see function gzerror below). +*/ + +ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ + +ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +/* + Clears the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the + compression library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is NULL, this function returns + the required initial value for the checksum. + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, + z_off_t len2)); +/* + Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 + and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for + each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of + seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running CRC-32 with the bytes buf[0..len-1] and return the + updated CRC-32. If buf is NULL, this function returns the required initial + value for the for the crc. Pre- and post-conditioning (one's complement) is + performed within this function so it shouldn't be done by the application. + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + +ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); + +/* + Combine two CRC-32 check values into one. For two sequences of bytes, + seq1 and seq2 with lengths len1 and len2, CRC-32 check values were + calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 + check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and + len2. +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size)); +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) +#define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, sizeof(z_stream)) + + +#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) + struct internal_state {int dummy;}; /* hack for buggy compilers */ +#endif + +ZEXTERN const char * ZEXPORT zError OF((int)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z)); +ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/gdcm/Utilities/gdcmzlib/zlib.rc b/gdcm/Utilities/gdcmzlib/zlib.rc new file mode 100644 index 0000000..58f7567 --- /dev/null +++ b/gdcm/Utilities/gdcmzlib/zlib.rc @@ -0,0 +1,32 @@ +#include + +#define IDR_VERSION1 1 +IDR_VERSION1 VERSIONINFO MOVEABLE IMPURE LOADONCALL DISCARDABLE + FILEVERSION 1,2,3,0 + PRODUCTVERSION 1,2,3,0 + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK + FILEFLAGS 0 + FILEOS VOS_DOS_WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE 0 // not used +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904E4" + //language ID = U.S. English, char set = Windows, Multilingual + + BEGIN + VALUE "FileDescription", "zlib data compression library\0" + VALUE "FileVersion", "1.2.3.0\0" + VALUE "InternalName", "zlib\0" + VALUE "OriginalFilename", "zlib.dll\0" + VALUE "ProductName", "ZLib.DLL\0" + VALUE "Comments","DLL support by Alessandro Iacopetti & Gilles Vollant\0" + VALUE "LegalCopyright", "(C) 1995-2003 Jean-loup Gailly & Mark Adler\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0409, 1252 + END +END diff --git a/gdcm/Utilities/gdcmzlib/zutil.c b/gdcm/Utilities/gdcmzlib/zutil.c new file mode 100644 index 0000000..d55f594 --- /dev/null +++ b/gdcm/Utilities/gdcmzlib/zutil.c @@ -0,0 +1,318 @@ +/* zutil.c -- target dependent utility functions for the compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#include "zutil.h" + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +const char * const z_errmsg[10] = { +"need dictionary", /* Z_NEED_DICT 2 */ +"stream end", /* Z_STREAM_END 1 */ +"", /* Z_OK 0 */ +"file error", /* Z_ERRNO (-1) */ +"stream error", /* Z_STREAM_ERROR (-2) */ +"data error", /* Z_DATA_ERROR (-3) */ +"insufficient memory", /* Z_MEM_ERROR (-4) */ +"buffer error", /* Z_BUF_ERROR (-5) */ +"incompatible version",/* Z_VERSION_ERROR (-6) */ +""}; + + +const char * ZEXPORT zlibVersion() +{ + return ZLIB_VERSION; +} + +uLong ZEXPORT zlibCompileFlags() +{ + uLong flags; + + flags = 0; + switch (sizeof(uInt)) { + case 2: break; + case 4: flags += 1; break; + case 8: flags += 2; break; + default: flags += 3; + } + switch (sizeof(uLong)) { + case 2: break; + case 4: flags += 1 << 2; break; + case 8: flags += 2 << 2; break; + default: flags += 3 << 2; + } + switch (sizeof(voidpf)) { + case 2: break; + case 4: flags += 1 << 4; break; + case 8: flags += 2 << 4; break; + default: flags += 3 << 4; + } + switch (sizeof(z_off_t)) { + case 2: break; + case 4: flags += 1 << 6; break; + case 8: flags += 2 << 6; break; + default: flags += 3 << 6; + } +#ifdef DEBUG + flags += 1 << 8; +#endif +#if defined(ASMV) || defined(ASMINF) + flags += 1 << 9; +#endif +#ifdef ZLIB_WINAPI + flags += 1 << 10; +#endif +#ifdef BUILDFIXED + flags += 1 << 12; +#endif +#ifdef DYNAMIC_CRC_TABLE + flags += 1 << 13; +#endif +#ifdef NO_GZCOMPRESS + flags += 1L << 16; +#endif +#ifdef NO_GZIP + flags += 1L << 17; +#endif +#ifdef PKZIP_BUG_WORKAROUND + flags += 1L << 20; +#endif +#ifdef FASTEST + flags += 1L << 21; +#endif +#ifdef STDC +# ifdef NO_vsnprintf + flags += 1L << 25; +# ifdef HAS_vsprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_vsnprintf_void + flags += 1L << 26; +# endif +# endif +#else + flags += 1L << 24; +# ifdef NO_snprintf + flags += 1L << 25; +# ifdef HAS_sprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_snprintf_void + flags += 1L << 26; +# endif +# endif +#endif + return flags; +} + +#ifdef DEBUG + +# ifndef verbose +# define verbose 0 +# endif +int z_verbose = verbose; + +void z_error (m) + char *m; +{ + fprintf(stderr, "%s\n", m); + exit(1); +} +#endif + +/* exported to allow conversion of error code to string for compress() and + * uncompress() + */ +const char * ZEXPORT zError(err) + int err; +{ + return ERR_MSG(err); +} + +#if defined(_WIN32_WCE) + /* The Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. + * Its value is always 0 and should not be used. + */ + int errno = 0; +#endif + +#ifndef HAVE_MEMCPY + +void zmemcpy(dest, source, len) + Bytef* dest; + const Bytef* source; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = *source++; /* ??? to be unrolled */ + } while (--len != 0); +} + +int zmemcmp(s1, s2, len) + const Bytef* s1; + const Bytef* s2; + uInt len; +{ + uInt j; + + for (j = 0; j < len; j++) { + if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; + } + return 0; +} + +void zmemzero(dest, len) + Bytef* dest; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = 0; /* ??? to be unrolled */ + } while (--len != 0); +} +#endif + + +#ifdef SYS16BIT + +#ifdef __TURBOC__ +/* Turbo C in 16-bit mode */ + +# define MY_ZCALLOC + +/* Turbo C malloc() does not allow dynamic allocation of 64K bytes + * and farmalloc(64K) returns a pointer with an offset of 8, so we + * must fix the pointer. Warning: the pointer must be put back to its + * original form in order to free it, use zcfree(). + */ + +#define MAX_PTR 10 +/* 10*64K = 640K */ + +local int next_ptr = 0; + +typedef struct ptr_table_s { + voidpf org_ptr; + voidpf new_ptr; +} ptr_table; + +local ptr_table table[MAX_PTR]; +/* This table is used to remember the original form of pointers + * to large buffers (64K). Such pointers are normalized with a zero offset. + * Since MSDOS is not a preemptive multitasking OS, this table is not + * protected from concurrent access. This hack doesn't work anyway on + * a protected system like OS/2. Use Microsoft C instead. + */ + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + voidpf buf = opaque; /* just to make some compilers happy */ + ulg bsize = (ulg)items*size; + + /* If we allocate less than 65520 bytes, we assume that farmalloc + * will return a usable pointer which doesn't have to be normalized. + */ + if (bsize < 65520L) { + buf = farmalloc(bsize); + if (*(ush*)&buf != 0) return buf; + } else { + buf = farmalloc(bsize + 16L); + } + if (buf == NULL || next_ptr >= MAX_PTR) return NULL; + table[next_ptr].org_ptr = buf; + + /* Normalize the pointer to seg:0 */ + *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; + *(ush*)&buf = 0; + table[next_ptr++].new_ptr = buf; + return buf; +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + int n; + if (*(ush*)&ptr != 0) { /* object < 64K */ + farfree(ptr); + return; + } + /* Find the original pointer */ + for (n = 0; n < next_ptr; n++) { + if (ptr != table[n].new_ptr) continue; + + farfree(table[n].org_ptr); + while (++n < next_ptr) { + table[n-1] = table[n]; + } + next_ptr--; + return; + } + ptr = opaque; /* just to make some compilers happy */ + Assert(0, "zcfree: ptr not found"); +} + +#endif /* __TURBOC__ */ + + +#ifdef M_I86 +/* Microsoft C in 16-bit mode */ + +# define MY_ZCALLOC + +#if (!defined(_MSC_VER) || (_MSC_VER <= 600)) +# define _halloc halloc +# define _hfree hfree +#endif + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + return _halloc((long)items, size); +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + _hfree(ptr); +} + +#endif /* M_I86 */ + +#endif /* SYS16BIT */ + + +#ifndef MY_ZCALLOC /* Any system without a special alloc function */ + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern voidp calloc OF((uInt items, uInt size)); +extern void free OF((voidpf ptr)); +#endif + +voidpf zcalloc (opaque, items, size) + voidpf opaque; + unsigned items; + unsigned size; +{ + if (opaque) items += size - size; /* make compiler happy */ + return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : + (voidpf)calloc(items, size); +} + +void zcfree (opaque, ptr) + voidpf opaque; + voidpf ptr; +{ + free(ptr); + if (opaque) return; /* make compiler happy */ +} + +#endif /* MY_ZCALLOC */ diff --git a/gdcm/Utilities/gdcmzlib/zutil.h b/gdcm/Utilities/gdcmzlib/zutil.h new file mode 100644 index 0000000..b7d5eff --- /dev/null +++ b/gdcm/Utilities/gdcmzlib/zutil.h @@ -0,0 +1,269 @@ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef ZUTIL_H +#define ZUTIL_H + +#define ZLIB_INTERNAL +#include "zlib.h" + +#ifdef STDC +# ifndef _WIN32_WCE +# include +# endif +# include +# include +#endif +#ifdef NO_ERRNO_H +# ifdef _WIN32_WCE + /* The Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. + * Its value is always 0 and should not be used. We rename it to + * avoid conflict with other libraries that use the same workaround. + */ +# define errno z_errno +# endif + extern int errno; +#else +# ifndef _WIN32_WCE +# include +# endif +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = (char*)ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + +#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) +# define OS_CODE 0x00 +# if defined(__TURBOC__) || defined(__BORLANDC__) +# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) + /* Allow compilation with ANSI keywords only enabled */ + void _Cdecl farfree( void *block ); + void *_Cdecl farmalloc( unsigned long nbytes ); +# else +# include +# endif +# else /* MSC or DJGPP */ +# include +# endif +#endif + +#ifdef AMIGA +# define OS_CODE 0x01 +#endif + +#if defined(VAXC) || defined(VMS) +# define OS_CODE 0x02 +# define F_OPEN(name, mode) \ + fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") +#endif + +#if defined(ATARI) || defined(atarist) +# define OS_CODE 0x05 +#endif + +#ifdef OS2 +# define OS_CODE 0x06 +# ifdef M_I86 + #include +# endif +#endif + +#if defined(MACOS) || defined(TARGET_OS_MAC) +# define OS_CODE 0x07 +# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fdopen */ +# else +# ifndef fdopen +# define fdopen(fd,mode) NULL /* No fdopen() */ +# endif +# endif +#endif + +#ifdef TOPS20 +# define OS_CODE 0x0a +#endif + +#ifdef WIN32 +# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */ +# define OS_CODE 0x0b +# endif +#endif + +#ifdef __50SERIES /* Prime/PRIMOS */ +# define OS_CODE 0x0f +#endif + +#if defined(_BEOS_) || defined(RISCOS) +# define fdopen(fd,mode) NULL /* No fdopen() */ +#endif + +#if (defined(_MSC_VER) && (_MSC_VER > 600)) +# if defined(_WIN32_WCE) +# define fdopen(fd,mode) NULL /* No fdopen() */ +# ifndef _PTRDIFF_T_DEFINED + typedef int ptrdiff_t; +# define _PTRDIFF_T_DEFINED +# endif +# else +# define fdopen(fd,type) _fdopen(fd,type) +# endif +#endif + + /* common defaults */ + +#ifndef OS_CODE +# define OS_CODE 0x03 /* assume Unix */ +#endif + +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#if defined(__CYGWIN__) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#ifndef HAVE_VSNPRINTF +# ifdef MSDOS + /* vsnprintf may exist on some MS-DOS compilers (DJGPP?), + but for now we just assume it doesn't. */ +# define NO_vsnprintf +# endif +# ifdef __TURBOC__ +# define NO_vsnprintf +# endif +# ifdef WIN32 + /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ +# if !defined(vsnprintf) && !defined(NO_vsnprintf) +# define vsnprintf _vsnprintf +# endif +# endif +# ifdef __SASC +# define NO_vsnprintf +# endif +#endif +#ifdef VMS +# define NO_vsnprintf +#endif + +#if defined(pyr) +# define NO_MEMCPY +#endif +#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) + /* Use our own functions for small and medium model with MSC <= 5.0. + * You may have to use the same strategy for Borland C (untested). + * The __SC__ check is for Symantec. + */ +# define NO_MEMCPY +#endif +#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) +# define HAVE_MEMCPY +#endif +#ifdef HAVE_MEMCPY +# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ +# define zmemcpy _fmemcpy +# define zmemcmp _fmemcmp +# define zmemzero(dest, len) _fmemset(dest, 0, len) +# else +# define zmemcpy memcpy +# define zmemcmp memcmp +# define zmemzero(dest, len) memset(dest, 0, len) +# endif +#else + extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); + extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); + extern void zmemzero OF((Bytef* dest, uInt len)); +#endif + +/* Diagnostic functions */ +#ifdef DEBUG +# include + extern int z_verbose; + extern void z_error OF((char *m)); +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) {if (z_verbose>=0) fprintf x ;} +# define Tracev(x) {if (z_verbose>0) fprintf x ;} +# define Tracevv(x) {if (z_verbose>1) fprintf x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + +voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); +void zcfree OF((voidpf opaque, voidpf ptr)); + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + +#endif /* ZUTIL_H */ diff --git a/gdcm/Utilities/getopt/CMakeLists.txt b/gdcm/Utilities/getopt/CMakeLists.txt new file mode 100644 index 0000000..964b16b --- /dev/null +++ b/gdcm/Utilities/getopt/CMakeLists.txt @@ -0,0 +1,79 @@ +cmake_minimum_required(VERSION 2.8.9) + +if(NOT GETOPT_NAMESPACE) + set(GETOPT_NAMESPACE "GETOPT") + set(GETOPT_STANDALONE 1) +endif() +# In all cases: +string(TOLOWER ${GETOPT_NAMESPACE} GETOPT_LIBRARY_NAME) + +project(${GETOPT_NAMESPACE} C) + +#set(BUILD_SHARED_LIBS OFF) + +set(GETOPT_SRCS + getopt.c + getopt_long.c + ) +if(WIN32) + if (BUILD_SHARED_LIBS) + add_definitions(-DGETOPT_DLL) + endif () +endif() + +#include_directories(BEFORE +# ${CMAKE_CURRENT_SOURCE_DIR} +# ) + +set(GETOPT_MAJOR_VERSION 1) +set(GETOPT_MINOR_VERSION 0) +set(GETOPT_BUILD_VERSION 0) +set(GETOPT_VERSION + "${GETOPT_MAJOR_VERSION}.${GETOPT_MINOR_VERSION}.${GETOPT_BUILD_VERSION}") + +set(GETOPT_LIBRARY_PROPERTIES ${GETOPT_LIBRARY_PROPERTIES} + VERSION "${GETOPT_VERSION}" + SOVERSION "${GETOPT_MAJOR_VERSION}.${GETOPT_MINOR_VERSION}" +) + +# Only build this lib static. On most unix system +# we will be using the standart getopt +# so this lib will be for the poor Win32 user (those +# guys really need help) +add_library(${GETOPT_LIBRARY_NAME} ${GETOPT_SRCS}) +set_target_properties(${GETOPT_LIBRARY_NAME} PROPERTIES ${GETOPT_LIBRARY_PROPERTIES}) +if(CMAKE_COMPILER_IS_GNUCXX AND MINGW) + # For some reason mingw fails to export the optind which is clearly marked as exported (using extern symbol) + # ... for now use this flag : + set_target_properties(${GETOPT_LIBRARY_NAME} PROPERTIES LINK_FLAGS "-Wl,--export-all-symbols") +endif() + +#if(BUILD_EXAMPLES) +#if(GDCM_BUILD_TESTING) +#add_executable(ex_getopt ex_getopt.c) +#target_link_libraries(ex_getopt ${GETOPT_LIBRARY_NAME}) +#if(NOT GETOPT_INSTALL_NO_LIBRARIES) +# install(TARGETS ex_getopt +# RUNTIME DESTINATION ${GETOPT_INSTALL_BIN_DIR} COMPONENT Applications +# LIBRARY DESTINATION ${GETOPT_INSTALL_LIB_DIR} COMPONENT Libraries +# ARCHIVE DESTINATION ${GETOPT_INSTALL_LIB_DIR} COMPONENT DebugDevel +# ${CPACK_NAMELINK_TYPE} +# ) +#endif() +#endif() +#endif() + +if(NOT GETOPT_INSTALL_NO_LIBRARIES) + install(TARGETS ${GETOPT_LIBRARY_NAME} + EXPORT ${GDCM_TARGETS_NAME} + RUNTIME DESTINATION ${GETOPT_INSTALL_BIN_DIR} COMPONENT Applications + LIBRARY DESTINATION ${GETOPT_INSTALL_LIB_DIR} COMPONENT Libraries #${NAMELINK_SKIP} + ARCHIVE DESTINATION ${GETOPT_INSTALL_LIB_DIR} COMPONENT DebugDevel + ) + #if(NAMELINK_ONLY) + # install(TARGETS ${GETOPT_LIBRARY_NAME} + # LIBRARY DESTINATION ${GETOPT_INSTALL_LIB_DIR} COMPONENT DebugDevel ${NAMELINK_ONLY} + # ) + #endif() +endif() + diff --git a/gdcm/Utilities/getopt/COPYING b/gdcm/Utilities/getopt/COPYING new file mode 100644 index 0000000..6b29233 --- /dev/null +++ b/gdcm/Utilities/getopt/COPYING @@ -0,0 +1,36 @@ +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Dieter Baron and Thomas Klausner. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + diff --git a/gdcm/Utilities/getopt/README b/gdcm/Utilities/getopt/README new file mode 100644 index 0000000..28c41e0 --- /dev/null +++ b/gdcm/Utilities/getopt/README @@ -0,0 +1,3 @@ +The source was taken from http://svn.xiph.org/trunk/theora-exp/win32/compatibility/ + +Seems to compiles with VS 7.1 (free) and bcc 5.5.1 diff --git a/gdcm/Utilities/getopt/ex_getopt.c b/gdcm/Utilities/getopt/ex_getopt.c new file mode 100644 index 0000000..a3c85f8 --- /dev/null +++ b/gdcm/Utilities/getopt/ex_getopt.c @@ -0,0 +1,97 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + * ./bin/ex_getopt -a -b -c foo -d bar -1 + */ + +#include /* for printf */ +#include /* for exit */ +#include "getopt.h" + +int +main (int argc, char **argv) { + int c; + int digit_optind = 0; + //int optind = 0; + //int optarg = 0; + + while (1) { + int this_option_optind = optind ? optind : 1; + int option_index = 0; + static struct option long_options[] = { + {"add", 1, 0, 0}, + {"append", 0, 0, 0}, + {"delete", 1, 0, 0}, + {"verbose", 0, 0, 0}, + {"create", 1, 0, 'c'}, + {"file", 1, 0, 0}, + {0, 0, 0, 0} + }; + + c = getopt_long (argc, argv, "abc:d:012", + long_options, &option_index); + if (c == -1) + break; + + switch (c) { + case 0: + printf ("option %s", long_options[option_index].name); + if (optarg) + printf (" with arg %s", optarg); + printf ("\n"); + break; + + case '0': + case '1': + case '2': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value ’%s’\n", optarg); + break; + + case 'd': + printf ("option d with value ’%s’\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + diff --git a/gdcm/Utilities/getopt/getopt.c b/gdcm/Utilities/getopt/getopt.c new file mode 100644 index 0000000..4cfe746 --- /dev/null +++ b/gdcm/Utilities/getopt/getopt.c @@ -0,0 +1,122 @@ +/* + * Copyright (c) 1987, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/*#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)getopt.c 8.3 (Berkeley) 4/27/95"; +#endif /* LIBC_SCCS and not lint +#include +//__FBSDID("$FreeBSD: src/lib/libc/stdlib/getopt.c,v 1.6 2002/03/29 22:43:42 markm Exp $"); + +#include "namespace.h"*/ +#include +#include +#include +/*#include "un-namespace.h"*/ + +/*#include "libc_private.h"*/ + +int opterr = 1, /* if error message should be printed */ + optind = 1, /* index into parent argv vector */ + optopt, /* character checked for validity */ + optreset; /* reset getopt */ +char *optarg; /* argument associated with option */ + +#define BADCH (int)'?' +#define BADARG (int)':' +#define EMSG "" + +/* + * getopt -- + * Parse argc/argv argument vector. + */ +int +getopt(nargc, nargv, ostr) + int nargc; + char * const *nargv; + const char *ostr; +{ + static char *place = EMSG; /* option letter processing */ + char *oli; /* option letter list index */ + + if (optreset || !*place) { /* update scanning pointer */ + optreset = 0; + if (optind >= nargc || *(place = nargv[optind]) != '-') { + place = EMSG; + return (-1); + } + if (place[1] && *++place == '-') { /* found "--" */ + ++optind; + place = EMSG; + return (-1); + } + } /* option letter okay? */ + if ((optopt = (int)*place++) == (int)':' || + !(oli = strchr(ostr, optopt))) { + /* + * if the user didn't specify '-' as an option, + * assume it means -1. + */ + if (optopt == (int)'-') + return (-1); + if (!*place) + ++optind; + if (opterr && *ostr != ':' && optopt != BADCH) + (void)fprintf(stderr, "%s: illegal option -- %c\n", + "progname", optopt); + return (BADCH); + } + if (*++oli != ':') { /* don't need argument */ + optarg = NULL; + if (!*place) + ++optind; + } + else { /* need an argument */ + if (*place) /* no white space */ + optarg = place; + else if (nargc <= ++optind) { /* no arg */ + place = EMSG; + if (*ostr == ':') + return (BADARG); + if (opterr) + (void)fprintf(stderr, + "%s: option requires an argument -- %c\n", + "progname", optopt); + return (BADCH); + } + else /* white space */ + optarg = nargv[optind]; + place = EMSG; + ++optind; + } + return (optopt); /* dump back option letter */ +} diff --git a/gdcm/Utilities/getopt/getopt.h b/gdcm/Utilities/getopt/getopt.h new file mode 100644 index 0000000..42a9445 --- /dev/null +++ b/gdcm/Utilities/getopt/getopt.h @@ -0,0 +1,126 @@ +/* $NetBSD: getopt.h,v 1.4 2000/07/07 10:43:54 ad Exp $ */ +/* $FreeBSD: src/include/getopt.h,v 1.1 2002/09/29 04:14:30 eric Exp $ */ + +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Dieter Baron and Thomas Klausner. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _GETOPT_H_ +#define _GETOPT_H_ + +#ifdef _WIN32 +/* from */ +# ifdef __cplusplus +# define __BEGIN_DECLS extern "C" { +# define __END_DECLS } +# else +# define __BEGIN_DECLS +# define __END_DECLS +# endif +# define __P(args) args +#endif + +/*#ifndef _WIN32 +#include +//#include +#endif*/ + +#if defined(_WIN32) && defined(GETOPT_DLL) + #if defined(gdcmgetopt_EXPORTS) + #define GETOPT_EXPORT __declspec( dllexport ) + #else + #define GETOPT_EXPORT __declspec( dllimport ) + #endif +#else + #define GETOPT_EXPORT +#endif /*defined(WIN32)*/ + +#if defined(_WIN32) && defined(GETOPT_DLL) + #if defined(gdcmgetopt_EXPORTS) + #define GETOPT_EXTERN __declspec( dllexport ) + #else + #define GETOPT_EXTERN __declspec( dllimport ) + #endif +#else + #define GETOPT_EXTERN extern +#endif /*defined(WIN32)*/ + + + +/* + * Gnu like getopt_long() and BSD4.4 getsubopt()/optreset extensions + */ +#if !defined(_POSIX_SOURCE) && !defined(_XOPEN_SOURCE) +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 + +struct option { + /* name of long option */ + const char *name; + /* + * one of no_argument, required_argument, and optional_argument: + * whether option takes an argument + */ + int has_arg; + /* if not NULL, set *flag to val when option found */ + int *flag; + /* if flag not NULL, value to set *flag to; else return value */ + int val; +}; + +__BEGIN_DECLS +GETOPT_EXPORT int getopt_long __P((int, char * const *, const char *, + const struct option *, int *)); +__END_DECLS +#endif + +#ifdef _WIN32 +/* These are global getopt variables */ +__BEGIN_DECLS + +GETOPT_EXTERN int opterr, /* if error message should be printed */ + optind, /* index into parent argv vector */ + optopt, /* character checked for validity */ + optreset; /* reset getopt */ +GETOPT_EXTERN char* optarg; /* argument associated with option */ + +/* Original getopt */ +GETOPT_EXPORT int getopt __P((int, char * const *, const char *)); + +__END_DECLS +#endif + +#endif /* !_GETOPT_H_ */ diff --git a/gdcm/Utilities/getopt/getopt_long.c b/gdcm/Utilities/getopt/getopt_long.c new file mode 100644 index 0000000..7163c6a --- /dev/null +++ b/gdcm/Utilities/getopt/getopt_long.c @@ -0,0 +1,547 @@ +/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */ +/* $FreeBSD: src/lib/libc/stdlib/getopt_long.c,v 1.2 2002/10/16 22:18:42 alfred Exp $ */ + +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Dieter Baron and Thomas Klausner. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "getopt.h" +#include +#include + +#ifdef _WIN32 + +/* Windows needs warnx(). We change the definition though: + * 1. (another) global is defined, opterrmsg, which holds the error message + * 2. errors are always printed out on stderr w/o the program name + * Note that opterrmsg always gets set no matter what opterr is set to. The + * error message will not be printed if opterr is 0 as usual. + */ + +#include +#include + +GETOPT_EXTERN char opterrmsg[128]; +char opterrmsg[128]; /* last error message is stored here */ + +static void warnx(int print_error, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + if (fmt != NULL) + _vsnprintf(opterrmsg, 128, fmt, ap); + else + opterrmsg[0]='\0'; + va_end(ap); + if (print_error) { + fprintf(stderr, opterrmsg); + fprintf(stderr, "\n"); + } +} + +#endif /*_WIN32*/ + +/* not part of the original file */ +#ifndef _DIAGASSERT +#define _DIAGASSERT(X) +#endif + +#if HAVE_CONFIG_H && !HAVE_GETOPT_LONG && !HAVE_DECL_OPTIND +#define REPLACE_GETOPT +#endif + +#ifdef REPLACE_GETOPT +#ifdef __weak_alias +__weak_alias(getopt,_getopt) +#endif +int opterr = 1; /* if error message should be printed */ +int optind = 1; /* index into parent argv vector */ +int optopt = '?'; /* character checked for validity */ +int optreset; /* reset getopt */ +char *optarg; /* argument associated with option */ +#elif HAVE_CONFIG_H && !HAVE_DECL_OPTRESET +static int optreset; +#endif + +#ifdef __weak_alias +__weak_alias(getopt_long,_getopt_long) +#endif + +#if !HAVE_GETOPT_LONG +#define IGNORE_FIRST (*options == '-' || *options == '+') +#define PRINT_ERROR ((opterr) && ((*options != ':') \ + || (IGNORE_FIRST && options[1] != ':'))) +#define IS_POSIXLY_CORRECT (getenv("POSIXLY_CORRECT") != NULL) +#define PERMUTE (!IS_POSIXLY_CORRECT && !IGNORE_FIRST) +/* XXX: GNU ignores PC if *options == '-' */ +#define IN_ORDER (!IS_POSIXLY_CORRECT && *options == '-') + +/* return values */ +#define BADCH (int)'?' +#define BADARG ((IGNORE_FIRST && options[1] == ':') \ + || (*options == ':') ? (int)':' : (int)'?') +#define INORDER (int)1 + +#define EMSG "" + +static int getopt_internal(int, char * const *, const char *); +static int gcd(int, int); +static void permute_args(int, int, int, char * const *); + +static char *place = EMSG; /* option letter processing */ + +/* XXX: set optreset to 1 rather than these two */ +static int nonopt_start = -1; /* first non option argument (for permute) */ +static int nonopt_end = -1; /* first option after non options (for permute) */ + +/* Error messages */ +static const char recargchar[] = "option requires an argument -- %c"; +static const char recargstring[] = "option requires an argument -- %s"; +static const char ambig[] = "ambiguous option -- %.*s"; +static const char noarg[] = "option doesn't take an argument -- %.*s"; +static const char illoptchar[] = "unknown option -- %c"; +static const char illoptstring[] = "unknown option -- %s"; + + +/* + * Compute the greatest common divisor of a and b. + */ +static int +gcd(a, b) + int a; + int b; +{ + int c; + + c = a % b; + while (c != 0) { + a = b; + b = c; + c = a % b; + } + + return b; +} + +/* + * Exchange the block from nonopt_start to nonopt_end with the block + * from nonopt_end to opt_end (keeping the same order of arguments + * in each block). + */ +static void +permute_args(panonopt_start, panonopt_end, opt_end, nargv) + int panonopt_start; + int panonopt_end; + int opt_end; + char * const *nargv; +{ + int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; + char *swap; + + _DIAGASSERT(nargv != NULL); + + /* + * compute lengths of blocks and number and size of cycles + */ + nnonopts = panonopt_end - panonopt_start; + nopts = opt_end - panonopt_end; + ncycle = gcd(nnonopts, nopts); + cyclelen = (opt_end - panonopt_start) / ncycle; + + for (i = 0; i < ncycle; i++) { + cstart = panonopt_end+i; + pos = cstart; + for (j = 0; j < cyclelen; j++) { + if (pos >= panonopt_end) + pos -= nnonopts; + else + pos += nopts; + swap = nargv[pos]; + /* LINTED const cast */ + ((char **) nargv)[pos] = nargv[cstart]; + /* LINTED const cast */ + ((char **)nargv)[cstart] = swap; + } + } +} + +/* + * getopt_internal -- + * Parse argc/argv argument vector. Called by user level routines. + * Returns -2 if -- is found (can be long option or end of options marker). + */ +static int +getopt_internal(nargc, nargv, options) + int nargc; + char * const *nargv; + const char *options; +{ + char *oli; /* option letter list index */ + int optchar; + + _DIAGASSERT(nargv != NULL); + _DIAGASSERT(options != NULL); + + optarg = NULL; + + /* + * XXX Some programs (like rsyncd) expect to be able to + * XXX re-initialize optind to 0 and have getopt_long(3) + * XXX properly function again. Work around this braindamage. + */ + if (optind == 0) + optind = 1; + + if (optreset) + nonopt_start = nonopt_end = -1; +start: + if (optreset || !*place) { /* update scanning pointer */ + optreset = 0; + if (optind >= nargc) { /* end of argument vector */ + place = EMSG; + if (nonopt_end != -1) { + /* do permutation, if we have to */ + permute_args(nonopt_start, nonopt_end, + optind, nargv); + optind -= nonopt_end - nonopt_start; + } + else if (nonopt_start != -1) { + /* + * If we skipped non-options, set optind + * to the first of them. + */ + optind = nonopt_start; + } + nonopt_start = nonopt_end = -1; + return -1; + } + if ((*(place = nargv[optind]) != '-') + || (place[1] == '\0')) { /* found non-option */ + place = EMSG; + if (IN_ORDER) { + /* + * GNU extension: + * return non-option as argument to option 1 + */ + optarg = nargv[optind++]; + return INORDER; + } + if (!PERMUTE) { + /* + * if no permutation wanted, stop parsing + * at first non-option + */ + return -1; + } + /* do permutation */ + if (nonopt_start == -1) + nonopt_start = optind; + else if (nonopt_end != -1) { + permute_args(nonopt_start, nonopt_end, + optind, nargv); + nonopt_start = optind - + (nonopt_end - nonopt_start); + nonopt_end = -1; + } + optind++; + /* process next argument */ + goto start; + } + if (nonopt_start != -1 && nonopt_end == -1) + nonopt_end = optind; + if (place[1] && *++place == '-') { /* found "--" */ + place++; + return -2; + } + } + if ((optchar = (int)*place++) == (int)':' || + (oli = strchr(options + (IGNORE_FIRST ? 1 : 0), optchar)) == NULL) { + /* option letter unknown or ':' */ + if (!*place) + ++optind; +#ifndef _WIN32 + if (PRINT_ERROR) + warnx(illoptchar, optchar); +#else + warnx(PRINT_ERROR, illoptchar, optchar); +#endif + optopt = optchar; + return BADCH; + } + if (optchar == 'W' && oli[1] == ';') { /* -W long-option */ + /* XXX: what if no long options provided (called by getopt)? */ + if (*place) + return -2; + + if (++optind >= nargc) { /* no arg */ + place = EMSG; +#ifndef _WIN32 + if (PRINT_ERROR) + warnx(recargchar, optchar); +#else + warnx(PRINT_ERROR, recargchar, optchar); +#endif + optopt = optchar; + return BADARG; + } else /* white space */ + place = nargv[optind]; + /* + * Handle -W arg the same as --arg (which causes getopt to + * stop parsing). + */ + return -2; + } + if (*++oli != ':') { /* doesn't take argument */ + if (!*place) + ++optind; + } else { /* takes (optional) argument */ + optarg = NULL; + if (*place) /* no white space */ + optarg = place; + /* XXX: disable test for :: if PC? (GNU doesn't) */ + else if (oli[1] != ':') { /* arg not optional */ + if (++optind >= nargc) { /* no arg */ + place = EMSG; +#ifndef _WIN32 + if (PRINT_ERROR) + warnx(recargchar, optchar); +#else + warnx(PRINT_ERROR, recargchar, optchar); +#endif + optopt = optchar; + return BADARG; + } else + optarg = nargv[optind]; + } + place = EMSG; + ++optind; + } + /* dump back option letter */ + return optchar; +} + +#ifdef REPLACE_GETOPT +/* + * getopt -- + * Parse argc/argv argument vector. + * + * [eventually this will replace the real getopt] + */ +int +getopt(nargc, nargv, options) + int nargc; + char * const *nargv; + const char *options; +{ + int retval; + + _DIAGASSERT(nargv != NULL); + _DIAGASSERT(options != NULL); + + if ((retval = getopt_internal(nargc, nargv, options)) == -2) { + ++optind; + /* + * We found an option (--), so if we skipped non-options, + * we have to permute. + */ + if (nonopt_end != -1) { + permute_args(nonopt_start, nonopt_end, optind, + nargv); + optind -= nonopt_end - nonopt_start; + } + nonopt_start = nonopt_end = -1; + retval = -1; + } + return retval; +} +#endif + +/* + * getopt_long -- + * Parse argc/argv argument vector. + */ +int +getopt_long(nargc, nargv, options, long_options, idx) + int nargc; + char * const *nargv; + const char *options; + const struct option *long_options; + int *idx; +{ + int retval; + + _DIAGASSERT(nargv != NULL); + _DIAGASSERT(options != NULL); + _DIAGASSERT(long_options != NULL); + /* idx may be NULL */ + + if ((retval = getopt_internal(nargc, nargv, options)) == -2) { + char *current_argv, *has_equal; + size_t current_argv_len; + int i, match; + + current_argv = place; + match = -1; + + optind++; + place = EMSG; + + if (*current_argv == '\0') { /* found "--" */ + /* + * We found an option (--), so if we skipped + * non-options, we have to permute. + */ + if (nonopt_end != -1) { + permute_args(nonopt_start, nonopt_end, + optind, nargv); + optind -= nonopt_end - nonopt_start; + } + nonopt_start = nonopt_end = -1; + return -1; + } + if ((has_equal = strchr(current_argv, '=')) != NULL) { + /* argument found (--option=arg) */ + current_argv_len = has_equal - current_argv; + has_equal++; + } else + current_argv_len = strlen(current_argv); + + for (i = 0; long_options[i].name; i++) { + /* find matching long option */ + if (strncmp(current_argv, long_options[i].name, + current_argv_len)) + continue; + + if (strlen(long_options[i].name) == + (unsigned)current_argv_len) { + /* exact match */ + match = i; + break; + } + if (match == -1) /* partial match */ + match = i; + else { + /* ambiguous abbreviation */ +#ifndef _WIN32 + if (PRINT_ERROR) + warnx(ambig, (int)current_argv_len, + current_argv); +#else + warnx(PRINT_ERROR, ambig, (int)current_argv_len, + current_argv); +#endif + optopt = 0; + return BADCH; + } + } + if (match != -1) { /* option found */ + if (long_options[match].has_arg == no_argument + && has_equal) { +#ifndef _WIN32 + if (PRINT_ERROR) + warnx(noarg, (int)current_argv_len, + current_argv); +#else + warnx(PRINT_ERROR, noarg, (int)current_argv_len, + current_argv); +#endif + /* + * XXX: GNU sets optopt to val regardless of + * flag + */ + if (long_options[match].flag == NULL) + optopt = long_options[match].val; + else + optopt = 0; + return BADARG; + } + if (long_options[match].has_arg == required_argument || + long_options[match].has_arg == optional_argument) { + if (has_equal) + optarg = has_equal; + else if (long_options[match].has_arg == + required_argument) { + /* + * optional argument doesn't use + * next nargv + */ + optarg = nargv[optind++]; + } + } + if ((long_options[match].has_arg == required_argument) + && (optarg == NULL)) { + /* + * Missing argument; leading ':' + * indicates no error should be generated + */ +#ifndef _WIN32 + if (PRINT_ERROR) + warnx(recargstring, current_argv); +#else + warnx(PRINT_ERROR, recargstring, current_argv); +#endif + /* + * XXX: GNU sets optopt to val regardless + * of flag + */ + if (long_options[match].flag == NULL) + optopt = long_options[match].val; + else + optopt = 0; + --optind; + return BADARG; + } + } else { /* unknown option */ +#ifndef _WIN32 + if (PRINT_ERROR) + warnx(illoptstring, current_argv); +#else + warnx(PRINT_ERROR, illoptstring, current_argv); +#endif + optopt = 0; + return BADCH; + } + if (long_options[match].flag) { + *long_options[match].flag = long_options[match].val; + retval = 0; + } else + retval = long_options[match].val; + if (idx) + *idx = match; + } + return retval; +} +#endif /* !GETOPT_LONG */ diff --git a/gdcm/Utilities/pvrg/CHANGES b/gdcm/Utilities/pvrg/CHANGES new file mode 100644 index 0000000..b76b7db --- /dev/null +++ b/gdcm/Utilities/pvrg/CHANGES @@ -0,0 +1,63 @@ +2/24/93 (JPEG Version 1.1) + +BUG FIXES: + +Changed the fill marker handling. On early JPEG revisions, one +interpretation is that fill markers came in pairs of 0xff 0xff, but +now it can be an arbitrary number of 0xff bytes. A one line fix in +stream.c handles this. + +The arbitrary frame width and frame height is handled much more +robustly. Decimated frames default frame size is handled with +rounding up rather than rounding down to keep compatiblity with the +JPEG CD. This has changes in marker.c and jpeg.c and io.c. + +CODE: + +(marker.c) (io.c) (jpeg.c) Setting the Framewidth and Frameheight that +violate logical MDU blocks will flag warnings. The frame rounding has +been changed from rounding down to rounding up. Rounding up preserves +MDU properties and is consistent with the CD specs. (We do not round +down anymore). The previous Framewidth and Frameheight does not work +with values that cross MDU boundaries; It now works arbitrarily. + + 1) In decoding, if any space is created, the space is set to "zero" bytes + (depending on the implementation of disk file "holes"). + + 2) In encoding, if any space is required, the space is set to pel + replication of the boundaries. + +(jpeg.c) The default filename is now componentfile0.jpg rather than +componentfile0.J. + +DOCUMENTATION: + +The colorspace section was edited to include more precise matrices and +a description of CCIR-601 versus JFIF style YUV->RGB conversion. + +Some printers (non-laserwriters) have been unable to cope with the +doc.ps files, specifically problems occurred in the postscript include +files. For some reason, Apple laserwriters and ghostscript do not +seem to be afflicted by the above problem. We have found a change in +the dvi2ps postscript header that seems to fix this problem for Sun +newsprint (and probably other) printers as well. If this still is a +problem, the raw tex and .ps files are available in the file +JPEGDOCv1.1.tar.Z. Caution: the special scaling command has different +relative scales for different dvi2ps, dvips programs - can be a factor +of 100 off depending on the version of the header file. + +6/14/93 + +Changed a few things in the documentation to reflect the YCbCr +terminology. Other than that, essentially the same. Added some +declaration for SYSTEM V libraries and libraries without ftruncate(). + +Version(1.2) + +7/28/93 + +Changed the lossless predictor encoding functions so that 16 bit +accuracy is attained. Some problems occurred with improper modulo +arithmetic when full 16 bits were used with certain predictors. The +changes were in codec.c Lossless*() and a couple of lines in jpeg.c +which used &0xffff to properly trim the values. diff --git a/gdcm/Utilities/pvrg/CMakeLists.txt b/gdcm/Utilities/pvrg/CMakeLists.txt new file mode 100644 index 0000000..f976926 --- /dev/null +++ b/gdcm/Utilities/pvrg/CMakeLists.txt @@ -0,0 +1,48 @@ + +set( + PVRG_SRCS + jpeg.c + codec.c + huffman.c + io.c + chendct.c + leedct.c + marker.c + stream.c + transform.c + lexer.c +) + + +# might not be portable, so simply rename the function in the code itself... +#set_source_files_properties(jpeg.c +# PROPERTIES +# COMPILE_FLAGS -Dmain=pvrgmain +#) +if(MSVC) +add_definitions(-DNOTRUNCATE) +else() +add_definitions(-DSYSV -DNOTRUNCATE) +endif() +#add_definitions(-DIO_DEBUG) +#add_library(pvrg ${PVRG_SRCS}) + +add_executable(gdcmjpeg ${PVRG_SRCS}) +#target_link_libraries(pvrgjpeg pvrg) + + +# +# Should you wish to modify the interpreter +# modify this portion here. +# +# Make sure that you move the first comment from the start to +# within the braces %{ /* */ %} in lexer.l, +# otherwise it will give you a error (definitions too long). +# +# Caution: Sometimes -ll is required. +# +# +#lexer.c: lexer.l +# lex lexer.l +# mv lex.yy.c lexer.c +# diff --git a/gdcm/Utilities/pvrg/COPYING b/gdcm/Utilities/pvrg/COPYING new file mode 100644 index 0000000..8732463 --- /dev/null +++ b/gdcm/Utilities/pvrg/COPYING @@ -0,0 +1,17 @@ +/************************************************************* +Copyright (C) 1990, 1991, 1993 Andy C. Hung, all rights reserved. +PUBLIC DOMAIN LICENSE: Stanford University Portable Video Research +Group. If you use this software, you agree to the following: This +program package is purely experimental, and is licensed "as is". +Permission is granted to use, modify, and distribute this program +without charge for any purpose, provided this license/ disclaimer +notice appears in the copies. No warranty or maintenance is given, +either expressed or implied. In no event shall the author(s) be +liable to you or a third party for any special, incidental, +consequential, or other damages, arising out of the use or inability +to use the program for any purpose (or the loss of data), even if we +have been advised of such possibilities. Any public reference or +advertisement of this source code should refer to it as the Portable +Video Research Group (PVRG) code, and not by any author(s) (or +Stanford University) name. +*************************************************************/ diff --git a/gdcm/Utilities/pvrg/PORTABILITY b/gdcm/Utilities/pvrg/PORTABILITY new file mode 100644 index 0000000..05c85be --- /dev/null +++ b/gdcm/Utilities/pvrg/PORTABILITY @@ -0,0 +1,8 @@ + +For PC's the portability problem may be in the shift-division in the +DCT's and the UNIX calls open, read, ftruncate, etc. + +For modification of the lexer.l file: Lex does not accept comments in +the heading, unfortunately, the automatic header program puts that at +the top. Put the first comment (pvrg disclaimer, etc.) into the %{ %} +body and all should be fine. diff --git a/gdcm/Utilities/pvrg/README b/gdcm/Utilities/pvrg/README new file mode 100644 index 0000000..c876fb2 --- /dev/null +++ b/gdcm/Utilities/pvrg/README @@ -0,0 +1,168 @@ + + MPEG, CCITT H.261 (P*64), JPEG + Image and Image sequence compression/decompression C software engines. + + +The Portable Video Research Group at Stanford have developed +image/image sequence compression and decompression engines (codecs) +for MPEG, CCITT H.261, and JPEG. The primary goal of these codecs is +to provide the functionality - these codecs are not optimized for +speed, rather completeness, and some of the code is kludgey. + +Development of MPEG, P64, and JPEG engines has not been the primary +goal of the Portable Video Research Group. Our research has been +focused on software and hardware for portable wireless digital video +communication. The charter of this group ended in the summer of 1994. + +COMMENTS/DISCLAIMERS: + +This code has been compiled on the Sun Sparc and DECstation UNIX +machines; some code has been further checked on HP workstations. + +For comments, bugs, and other mail relating to the source code, we +appreciate any comments. The code author can still be reached at Andy +C. Hung at achung@cs.stanford.edu. The standard public domain +disclaimer applies: Caveat Emptor - no guarantee on accuracy or +software support. + +References related to these codecs should NOT use any author's name, +or refer to Stanford University. Rather the Portable Video Research +Group or the acronym (PVRG) should be used, such as PVRG-MPEG, +PVRG-P64, PVRG-JPEG. + +ANONYMOUS FTP: + +The following files can be obtained through anonymous ftp from +havefun.stanford.edu, IP address [36.2.0.35]. The procedure is to use +ftp with the user name "anonymous" and an e-mail address for the +password. + +CODEC DESCRIPTION: + +I) PVRG-MPEG CODEC: (pub/mpeg/MPEGv1.2.1.tar.Z) + +This public domain video encoder and decoder was generated according +to the Santa Clara August 1991 format. It has been tested +successfully with decoders using the Paris December 1991 format. The +codec is capable of encoding all MPEG types of frames. The algorithms +for rate control, buffer-constrained encoding, and quantization +decisions are similar, but not identical, to that of the (simulation +model 1-3) MPEG document. The rate control used is a simple +proportional Q-stepsize/Buffer loop that works though not very well - +better rate-control is the essence for good quality buffer-constrained +MPEG encoding. Verification of the buffering is possible so as to +provide streams for real-time decoders. + +The MPEG codec performs compression and decompression on raw raster +scanned YCbCr (also known as digital YUV) files. The companion display +program for the X window system is described in section IV) below. A +manual of approximately 50 pages describes the program's use. + +There are also MPEG compressed files from the table tennis sequence in +tennis.mpg and the flower garden sequence in flowg.mpg. + +This codec was recently tested with the MPEG decoder of the Berkeley +Plateau Research group. If what you want is decoding and X display, +then you might want to look into their faster public domain MPEG +decoder/viewer. The Berkeley player is available via anonymous ftp +from toe.cs.berkeley.edu (128.32.149.117) in +/pub/multimedia/mpeg/mpeg-2.0.tar.Z. There is also an encoder at that +site. An ISO mpeg2 encoder and decoder is available by anonymous ftp +from ftp.netcom.com in the directory pub/c/cfogg/mpeg2 (alternate sites +may include ftp.uu.net). + + +II) PVRG-P64 CODEC: (pub/p64/P64v1.2.tar.Z) + +This public domain video encoder and decoder is based on the CCITT +H.261 specification. Some encoding algorithms are based on the RM 8 +encoder. We have tested it against a verified encoded sequence on the +CCITT 1992 specifications, but we would still appreciate anyone having +p64 video test sequences to let know. Like the MPEG codec, it +supports all the encoding and decoding modes, and has provisions for +buffer-constrained encoding, so it can produce streams for real-time +decoders. + +The H.261 codec takes the similar YCbCr raster scanned files as the MPEG +codec, and performs compression and decompresion on raster scanned +YCbCr files. It can take standard CIF or NTSC-CIF files. The display +of these programs is described in section IV) below. A manual of +approximately 50 pages describes its use. + +There are also P64 compressed files from the table tennis sequence in +table.p64 and the flower garden sequence in flowg.p64. The Inria +codec also performs H.261 video compression and is integrated into a +teleconferencing system; it can be obtained from avahi.inria.fr, in +/pub/h261.tar.Z. + +III) PVRG-JPEG CODEC: (pub/jpeg/JPEGv1.2.tar.Z) + +This public domain image encoder and decoder is based on the JPEG +Committee Draft. It supports all of the baseline for encoding and +decoding. The JPEG encoder is flexible in the variety of output +possible. It also supports lossless coding, though not as speedy as +we would like. The manual is approximately 50 pages long which +describes its use. The display program for JFIF-style (YCbCr) files is +described in section IV) below. The JFIF style is not a requirement +for this codec - it can compress and decompress CMYK, RGB, RGBalpha, +and other formats - this codec may be helpful if you wish to extract +information from non-JFIF encoded JPEG files. + +This codec has been tested on publicly available JPEG data. For +general purpose X display, you might want to try the program "xv" +(version 2.0 or greater). The JPEG engine of the program "xv" is +based on the free, portable C code for JPEG compression available from +the Independent JPEG Group. (anonymous login - ftp.uu.net (137.39.1.9 +or 192.48.96.9) /graphics/jpeg/jpegsrc.v4.tar.Z). + +IV) X VIEWER: (pub/cv/CVv1.2.1.tar.Z) + +This viewer allows the user to look at image or image sequences +generated through the codecs described above. These image or image +sequences are in the YCbCr (also known as digital YUV) colorspace +(either JFIF specified or CCIR 601 specified) and may be 4:1:1 (CIF, +or MPEG 4:2:0 style) or 2:1:1 (CCIR-601 4:2:2 style) or 1:1:1 +(non-decimated or CCIR-601 4:4:4 style). A short manual of +approximately 2 pages describes its use. + +ACKNOWLEDGEMENTS: + +Funded by the Defense Advanced Research Projects Agency. + +I am especially grateful to Hewlett Packard and Storm Technology for +their financial support during the earlier stages of codec +development. Any errors in the code and documentation are my own. +The following people are acknowledged for their advice and assistance. +Thanks, one and all. + + The Portable Video Research Group at Stanford: + Teresa Meng, Peter Black, Navin Chaddha, Ben Gordon, + Sheila Hemami, Wee-Chiew Tan, Eli Tsern. + + Adriaan Ligtenberg of Storm Technology. + Jeanne Wiseman, Andrew Fitzhugh, Gregory Yovanof and + Chuck Rosenberg of Hewlett Packard. + Eric Hamilton and Jean-Georges Fritsch of C-Cube Microsystems. + + Lawrence Rowe of the Berkeley Plateau Research Group. + Tom Lane of the Independent JPEG Group. + Katsumi Tahara, Sony. + Ciaran Mc Goldrick. + Karl Lillevold. + Mats Lofkvist. + Hiroshi Saitoh, Panasonic. + Frank Gadegast. + Chad Fogg, Cascade. + Thierry Turletti, Inria. + Anders Klemets. + Graham Logan. + Jelle van Zeijl. + George Warner, AT&T. + Chris Adams, Hewlett Packard. + Kent Murray, Atlantic Centre For Remote Sensing Of The Oceans. + I. C. Yang. + Donald Lindsay. + Harald A. Schiller, Tektronix. + Ismail Dalgic. + Tom Shield. + Y. Fujii. diff --git a/gdcm/Utilities/pvrg/SETUP b/gdcm/Utilities/pvrg/SETUP new file mode 100644 index 0000000..750670a --- /dev/null +++ b/gdcm/Utilities/pvrg/SETUP @@ -0,0 +1,80 @@ +JPEG version 1.2 + +1) Printing documentation: + +Documentation is in the PostScript file doc.ps. It is about 50 pages +long. + +2) Making the program. + +The makefile should be setup for most UNIX systems as is. Simply type +"make" in the source code directory. + +For SYSV only libraries, substitute the first line in the makefile +#DEFINES = -DSYSV -DNOTRUNCATE for +#DEFINES + +which allows for SYSV libraries to be used instead. The NOTRUNCATE +flag avoids the lack of the ftruncate() call used in io.c. + +Caution: For the compilation, the lexer.l file should be older than +the lexer.c file otherwise many machines will try and lex the lexer.l +file (thus clobbering potentially the lexer.c file). In general, the +tar will take out the lexer.l file first (it's specified to do that), +so there shouldn't be any problems unless the directory is _copied_ +and then remade, in which case, the lexer.c file will be older because +is lexically of lesser value than lexer.l. This is a potential bug. + +3) Testing the program. + +Two small test files are nonint.jpg and blkint.jpg. If you wish to +extract them, type + +jpeg -d -s nonint.jpg +jpeg -d -s blkint.jpg + +The resulting files should be in + +nonint.jpg.1 nonint.jpg.2 nonint.jpg.3 +blkint.jpg.1 blkint.jpg.2 blkint.jpg.3 + +These files are raw raster-scan component files 128x128 for the Y +(.1), 64x128 for the U(.2) and V(.3). + +4) Displaying the decompressed files. + +The decompressed *.1 *.2 *.3 files may be displayed through the +program "cv" which may be obtained by anonymous ftp from +havefun.stanford.edu:pub/cv/CVv1.1.tar.Z. If the program is in your +current directory search-path, type + +cv -iw 128 -ih 128 nonint.jpg -SF + +or + +cv -iw 128 -ih 128 blkint.jpg -SF + +5) Recompressing the sample files + +Use the following commands to recompress the nonint.jpg.* component +files into the nonint.jpg2 file: + +jpeg -iw 128 -ih 128 -n -hf 2 nonint.jpg.1 nonint.jpg.2 nonint.jpg.3 \ + -s nonint2.jpg + +Use the following commands to recompress the blkint.jpg.* component +files into the blkint.jpg2 file: + +jpeg -iw 128 -ih 128 -hf 2 blkint.jpg.1 blkint.jpg.2 blkint.jpg.3 \ + -s blkint2.jpg + +Surprisingly, recompressing and decompressing the blkint should yield +the same result. (The nonint files will not yield the same result - +but very close - since the non-interleaved mode defaults to using the +LUMINANCE quantization matrix for the first color component of each +scan.) See the documentation for more details on other parameters. + +6) Some short interpreted programs for the encoder: (See Chapter 4 of +the documentation behind these programs). + +test.huff test.3stream test.q diff --git a/gdcm/Utilities/pvrg/chendct.c b/gdcm/Utilities/pvrg/chendct.c new file mode 100644 index 0000000..9f56e3d --- /dev/null +++ b/gdcm/Utilities/pvrg/chendct.c @@ -0,0 +1,377 @@ +/************************************************************* +Copyright (C) 1990, 1991, 1993 Andy C. Hung, all rights reserved. +PUBLIC DOMAIN LICENSE: Stanford University Portable Video Research +Group. If you use this software, you agree to the following: This +program package is purely experimental, and is licensed "as is". +Permission is granted to use, modify, and distribute this program +without charge for any purpose, provided this license/ disclaimer +notice appears in the copies. No warranty or maintenance is given, +either expressed or implied. In no event shall the author(s) be +liable to you or a third party for any special, incidental, +consequential, or other damages, arising out of the use or inability +to use the program for any purpose (or the loss of data), even if we +have been advised of such possibilities. Any public reference or +advertisement of this source code should refer to it as the Portable +Video Research Group (PVRG) code, and not by any author(s) (or +Stanford University) name. +*************************************************************/ +/* +************************************************************ +chendct.c + +A simple DCT algorithm that seems to have fairly nice arithmetic +properties. + +W. H. Chen, C. H. Smith and S. C. Fralick "A fast computational +algorithm for the discrete cosine transform," IEEE Trans. Commun., +vol. COM-25, pp. 1004-1009, Sept 1977. + +************************************************************ +*/ + +/*LABEL chendct.c */ + +/*PUBLIC*/ + +extern void ChenDct(); +extern void ChenIDct(); + +/*PRIVATE*/ + +/* Standard Macros */ + +#define NO_MULTIPLY + +#ifdef NO_MULTIPLY +#define LS(r,s) ((r) << (s)) +#define RS(r,s) ((r) >> (s)) /* Caution with rounding... */ +#else +#define LS(r,s) ((r) * (1 << (s))) +#define RS(r,s) ((r) / (1 << (s))) /* Correct rounding */ +#endif + +#define MSCALE(expr) RS((expr),9) + +/* Cos constants */ + +#define c1d4 362L + +#define c1d8 473L +#define c3d8 196L + +#define c1d16 502L +#define c3d16 426L +#define c5d16 284L +#define c7d16 100L + +/* + VECTOR_DEFINITION makes the temporary variables vectors. + Useful for machines with small register spaces. + + */ + +#ifdef VECTOR_DEFINITION +#define a0 a[0] +#define a1 a[1] +#define a2 a[2] +#define a3 a[3] +#define b0 b[0] +#define b1 b[1] +#define b2 b[2] +#define b3 b[3] +#define c0 c[0] +#define c1 c[1] +#define c2 c[2] +#define c3 c[3] +#endif + +/*START*/ +/*BFUNC + +ChenDCT() implements the Chen forward dct. Note that there are two +input vectors that represent x=input, and y=output, and must be +defined (and storage allocated) before this routine is called. + +EFUNC*/ + +void ChenDct(x,y) + int *x; + int *y; +{ + register int i; + register int *aptr,*bptr; +#ifdef VECTOR_DEFINITION + register int a[4]; + register int b[4]; + register int c[4]; +#else + register int a0,a1,a2,a3; + register int b0,b1,b2,b3; + register int c0,c1,c2,c3; +#endif + + /* Loop over columns */ + + for(i=0;i<8;i++) + { + aptr = x+i; + bptr = aptr+56; + + a0 = LS((*aptr+*bptr),2); + c3 = LS((*aptr-*bptr),2); + aptr += 8; + bptr -= 8; + a1 = LS((*aptr+*bptr),2); + c2 = LS((*aptr-*bptr),2); + aptr += 8; + bptr -= 8; + a2 = LS((*aptr+*bptr),2); + c1 = LS((*aptr-*bptr),2); + aptr += 8; + bptr -= 8; + a3 = LS((*aptr+*bptr),2); + c0 = LS((*aptr-*bptr),2); + + b0 = a0+a3; + b1 = a1+a2; + b2 = a1-a2; + b3 = a0-a3; + + aptr = y+i; + + *aptr = MSCALE(c1d4*(b0+b1)); + aptr[32] = MSCALE(c1d4*(b0-b1)); + + aptr[16] = MSCALE((c3d8*b2)+(c1d8*b3)); + aptr[48] = MSCALE((c3d8*b3)-(c1d8*b2)); + + b0 = MSCALE(c1d4*(c2-c1)); + b1 = MSCALE(c1d4*(c2+c1)); + + a0 = c0+b0; + a1 = c0-b0; + a2 = c3-b1; + a3 = c3+b1; + + aptr[8] = MSCALE((c7d16*a0)+(c1d16*a3)); + aptr[24] = MSCALE((c3d16*a2)-(c5d16*a1)); + aptr[40] = MSCALE((c3d16*a1)+(c5d16*a2)); + aptr[56] = MSCALE((c7d16*a3)-(c1d16*a0)); + } + + for(i=0;i<8;i++) + { /* Loop over rows */ + aptr = y+LS(i,3); + bptr = aptr+7; + + c3 = RS((*(aptr)-*(bptr)),1); + a0 = RS((*(aptr++)+*(bptr--)),1); + c2 = RS((*(aptr)-*(bptr)),1); + a1 = RS((*(aptr++)+*(bptr--)),1); + c1 = RS((*(aptr)-*(bptr)),1); + a2 = RS((*(aptr++)+*(bptr--)),1); + c0 = RS((*(aptr)-*(bptr)),1); + a3 = RS((*(aptr)+*(bptr)),1); + + b0 = a0+a3; + b1 = a1+a2; + b2 = a1-a2; + b3 = a0-a3; + + aptr = y+LS(i,3); + + *aptr = MSCALE(c1d4*(b0+b1)); + aptr[4] = MSCALE(c1d4*(b0-b1)); + aptr[2] = MSCALE((c3d8*b2)+(c1d8*b3)); + aptr[6] = MSCALE((c3d8*b3)-(c1d8*b2)); + + b0 = MSCALE(c1d4*(c2-c1)); + b1 = MSCALE(c1d4*(c2+c1)); + + a0 = c0+b0; + a1 = c0-b0; + a2 = c3-b1; + a3 = c3+b1; + + aptr[1] = MSCALE((c7d16*a0)+(c1d16*a3)); + aptr[3] = MSCALE((c3d16*a2)-(c5d16*a1)); + aptr[5] = MSCALE((c3d16*a1)+(c5d16*a2)); + aptr[7] = MSCALE((c7d16*a3)-(c1d16*a0)); + } + + /* We have an additional factor of 8 in the Chen algorithm. */ + + for(i=0,aptr=y;i<64;i++,aptr++) + *aptr = (((*aptr<0) ? (*aptr-4) : (*aptr+4))/8); +} + + +/*BFUNC + +ChenIDCT() implements the Chen inverse dct. Note that there are two +input vectors that represent x=input, and y=output, and must be +defined (and storage allocated) before this routine is called. + +EFUNC*/ + +void ChenIDct(x,y) + int *x; + int *y; +{ + register int i; + register int *aptr; +#ifdef VECTOR_DEFINITION + register int a[4]; + register int b[4]; + register int c[4]; +#else + register int a0,a1,a2,a3; + register int b0,b1,b2,b3; + register int c0,c1,c2,c3; +#endif + + /* Loop over columns */ + + for(i=0;i<8;i++) + { + aptr = x+i; + b0 = LS(*aptr,2); + aptr += 8; + a0 = LS(*aptr,2); + aptr += 8; + b2 = LS(*aptr,2); + aptr += 8; + a1 = LS(*aptr,2); + aptr += 8; + b1 = LS(*aptr,2); + aptr += 8; + a2 = LS(*aptr,2); + aptr += 8; + b3 = LS(*aptr,2); + aptr += 8; + a3 = LS(*aptr,2); + + /* Split into even mode b0 = x0 b1 = x4 b2 = x2 b3 = x6. + And the odd terms a0 = x1 a1 = x3 a2 = x5 a3 = x7. + */ + + c0 = MSCALE((c7d16*a0)-(c1d16*a3)); + c1 = MSCALE((c3d16*a2)-(c5d16*a1)); + c2 = MSCALE((c3d16*a1)+(c5d16*a2)); + c3 = MSCALE((c1d16*a0)+(c7d16*a3)); + + /* First Butterfly on even terms.*/ + + a0 = MSCALE(c1d4*(b0+b1)); + a1 = MSCALE(c1d4*(b0-b1)); + + a2 = MSCALE((c3d8*b2)-(c1d8*b3)); + a3 = MSCALE((c1d8*b2)+(c3d8*b3)); + + b0 = a0+a3; + b1 = a1+a2; + b2 = a1-a2; + b3 = a0-a3; + + /* Second Butterfly */ + + a0 = c0+c1; + a1 = c0-c1; + a2 = c3-c2; + a3 = c3+c2; + + c0 = a0; + c1 = MSCALE(c1d4*(a2-a1)); + c2 = MSCALE(c1d4*(a2+a1)); + c3 = a3; + + aptr = y+i; + *aptr = b0+c3; + aptr += 8; + *aptr = b1+c2; + aptr += 8; + *aptr = b2+c1; + aptr += 8; + *aptr = b3+c0; + aptr += 8; + *aptr = b3-c0; + aptr += 8; + *aptr = b2-c1; + aptr += 8; + *aptr = b1-c2; + aptr += 8; + *aptr = b0-c3; + } + + /* Loop over rows */ + + for(i=0;i<8;i++) + { + aptr = y+LS(i,3); + b0 = *(aptr++); + a0 = *(aptr++); + b2 = *(aptr++); + a1 = *(aptr++); + b1 = *(aptr++); + a2 = *(aptr++); + b3 = *(aptr++); + a3 = *(aptr); + + /* + Split into even mode b0 = x0 b1 = x4 b2 = x2 b3 = x6. + And the odd terms a0 = x1 a1 = x3 a2 = x5 a3 = x7. + */ + + c0 = MSCALE((c7d16*a0)-(c1d16*a3)); + c1 = MSCALE((c3d16*a2)-(c5d16*a1)); + c2 = MSCALE((c3d16*a1)+(c5d16*a2)); + c3 = MSCALE((c1d16*a0)+(c7d16*a3)); + + /* First Butterfly on even terms.*/ + + a0 = MSCALE(c1d4*(b0+b1)); + a1 = MSCALE(c1d4*(b0-b1)); + + a2 = MSCALE((c3d8*b2)-(c1d8*b3)); + a3 = MSCALE((c1d8*b2)+(c3d8*b3)); + + /* Calculate last set of b's */ + + b0 = a0+a3; + b1 = a1+a2; + b2 = a1-a2; + b3 = a0-a3; + + /* Second Butterfly */ + + a0 = c0+c1; + a1 = c0-c1; + a2 = c3-c2; + a3 = c3+c2; + + c0 = a0; + c1 = MSCALE(c1d4*(a2-a1)); + c2 = MSCALE(c1d4*(a2+a1)); + c3 = a3; + + aptr = y+LS(i,3); + *(aptr++) = b0+c3; + *(aptr++) = b1+c2; + *(aptr++) = b2+c1; + *(aptr++) = b3+c0; + *(aptr++) = b3-c0; + *(aptr++) = b2-c1; + *(aptr++) = b1-c2; + *(aptr) = b0-c3; + } + + /* + Retrieve correct accuracy. We have additional factor + of 16 that must be removed. + */ + + for(i=0,aptr=y;i<64;i++,aptr++) + *aptr = (((*aptr<0) ? (*aptr-8) : (*aptr+8)) /16); +} + +/*END*/ diff --git a/gdcm/Utilities/pvrg/codec.c b/gdcm/Utilities/pvrg/codec.c new file mode 100644 index 0000000..b926ca6 --- /dev/null +++ b/gdcm/Utilities/pvrg/codec.c @@ -0,0 +1,691 @@ +/************************************************************* +Copyright (C) 1990, 1991, 1993 Andy C. Hung, all rights reserved. +PUBLIC DOMAIN LICENSE: Stanford University Portable Video Research +Group. If you use this software, you agree to the following: This +program package is purely experimental, and is licensed "as is". +Permission is granted to use, modify, and distribute this program +without charge for any purpose, provided this license/ disclaimer +notice appears in the copies. No warranty or maintenance is given, +either expressed or implied. In no event shall the author(s) be +liable to you or a third party for any special, incidental, +consequential, or other damages, arising out of the use or inability +to use the program for any purpose (or the loss of data), even if we +have been advised of such possibilities. Any public reference or +advertisement of this source code should refer to it as the Portable +Video Research Group (PVRG) code, and not by any author(s) (or +Stanford University) name. +*************************************************************/ +/* +************************************************************ +codec.c + +This file contains much of the transform coding routines to manipulate +the Huffman stream. + +************************************************************ +*/ + +/*LABEL codec.c */ + +/* Include files. */ +#include "globals.h" +#include "csize.h" + +#include /* abs */ + +/* Definitions for renaming functions. */ + +#define fputv meputv +#define fgetv megetv + +/* Exportable functions. */ + +/*PUBLIC*/ + +extern void FrequencyAC(); +extern void EncodeAC(); +extern void DecodeAC(); +extern int DecodeDC(); +extern void FrequencyDC(); +extern void EncodeDC(); +extern void ResetCodec(); +extern void ClearFrameFrequency(); +extern void AddFrequency(); +extern void InstallFrequency(); +extern void InstallPrediction(); +extern void PrintACEhuff(); +extern void PrintDCEhuff(); +extern int SizeACEhuff(); +extern int SizeDCEhuff(); + +extern int LosslessDecodeDC(); +extern void LosslessFrequencyDC(); +extern void LosslessEncodeDC(); + +/*PRIVATE*/ + +/* Imported Variables. */ + +extern int bit_set_mask[]; /* Used for testing sign extension. */ +extern int Loud; /* General debug level. */ +extern FRAME *CFrame; /* Frame parameter. */ +extern IMAGE *CImage; /* Image parameter. */ +extern SCAN *CScan; /* Scan parameter. */ + +/* Local Variables */ + +static int *LastDC=NULL; /* Last DC value for DPCM. */ +static int *ACFrequency=NULL; /* AC Frequency table to accum. statistics.*/ +static int *DCFrequency=NULL; /* DC Frequency table to accum. statistics.*/ +static int extend_mask[]={ /* Used for sign extensions. */ +0xFFFFFFFE, +0xFFFFFFFC, +0xFFFFFFF8, +0xFFFFFFF0, +0xFFFFFFE0, +0xFFFFFFC0, +0xFFFFFF80, +0xFFFFFF00, +0xFFFFFE00, +0xFFFFFC00, +0xFFFFF800, +0xFFFFF000, +0xFFFFE000, +0xFFFFC000, +0xFFFF8000, +0xFFFF0000, +0xFFFE0000, +0xFFFC0000, +0xFFF80000, +0xFFF00000 +}; + +/*START*/ + +/*BFUNC + +FrequencyAC() is used to accumulate the Huffman codes for the input +matrix. The Huffman codes are not actually stored but rather the count +of each code is stored so that construction of a Custom Table is +possible. + +EFUNC*/ + +void FrequencyAC(matrix) + int *matrix; +{ + BEGIN("FrequencyAC") + int i,k,r,ssss,cofac; + + for(k=r=0;++k < BLOCKSIZE;) /* Like EncodeAC below except don't write out */ + { + cofac = abs(matrix[k]); /* Find absolute size */ + if (cofac < 256) + { + ssss = csize[cofac]; + } + else + { + cofac = cofac >> 8; + ssss = csize[cofac] + 8; + } + if (matrix[k] == 0) /* Check for zeroes */ + { + if (k == BLOCKSIZE-1) /* If end of block, then process */ + { +#ifdef CODEC_DEBUG + printf("AC FEncoding EOB %d\n",0); +#endif + ACFrequency[0]++; /* Increment EOB frequency */ + break; + } + r++; + } + else + { + while(r > 15) /* Convert, r, ssss, into RLE */ + { +#ifdef CODEC_DEBUG + printf("AC FEncoding OVFL %d\n",240); +#endif + ACFrequency[240]++; /* Increment ZRL extender freq */ + r -= 16; + } + i = 16*r + ssss; /* Make code */ + r = 0; +#ifdef CODEC_DEBUG + printf("AC FEncoding nnnnssss %d\n",i); +#endif + ACFrequency[i]++; /* Increment frequency of such code. */ + } + } +} + +/*BFUNC + +EncodeAC() takes the matrix and encodes it by passing the values +of the codes found to the Huffman package. + +EFUNC*/ + +void EncodeAC(matrix) + int *matrix; +{ + BEGIN("EncodeAC") + int i,k,r,ssss,cofac; + + for(k=r=0;++k> 8; + ssss = csize[cofac] + 8; + } + if (matrix[k] == 0) /* Check for zeroes */ + { + if (k == BLOCKSIZE-1) + { +#ifdef CODEC_DEBUG + printf("AC Encoding EOB %d\n",0); +#endif + EncodeHuffman(0); + break; + } + r++; /* Increment run-length of zeroes */ + } + else + { + while(r > 15) /* If run-length > 15, time for */ + { /* Run-length extension */ +#ifdef CODEC_DEBUG + printf("AC Encoding OVFL %d\n",240); +#endif + EncodeHuffman(240); + r -= 16; + } + i = 16*r + ssss; /* Now we can find code byte */ +#ifdef CODEC_DEBUG + printf("AC Encoding nnnnssss %d\n",i); +#endif + r = 0; + EncodeHuffman(i); /* Encode RLE code */ + if (matrix[k]< 0) /* Follow by significant bits */ + { + fputv(ssss,matrix[k]-1); + } + else + { + fputv(ssss,matrix[k]); + } + + } + } +} + +/*BFUNC + +DecodeAC() is used to decode the AC coefficients from the stream in +the stream package. The information generated is stored in the matrix +passed to it. + +EFUNC*/ + +void DecodeAC(matrix) + int *matrix; +{ + BEGIN("DecodeAC") + int k,r,s,n; + register int *mptr; + + for(mptr=matrix+1;mptr> 4) & 0xf; /* n = run-length */ + if (s) + { + if ((k += n)>=BLOCKSIZE) break; /* JPEG Mistake */ + matrix[k] = fgetv(s); /* Get s bits */ + + s--; /* Align s */ + if ((matrix[k] & bit_set_mask[s]) == 0) /* Also (1 << s) */ + { + matrix[k] |= extend_mask[s]; /* Also (-1 << s) + 1 */ + matrix[k]++; /* Increment 2's c */ + } + k++; /* Goto next element */ + } + else if (n == 15) /* Zero run length code extnd */ + k += 16; + else + { + break; + } + } +} + +/*BFUNC + +DecodeDC() is used to decode a DC value from the input stream. +It returns the actual number found. + +EFUNC*/ + +int DecodeDC() +{ + BEGIN("DecodeDC") + int s,diff; + + s = DecodeHuffman(); +#ifdef CODEC_DEBUG + printf("DC Decode sig. %d\n",s); +#endif + + if (s) + { + diff = fgetv(s); + s--; /* 2's Bit Align */ +#ifdef CODEC_DEBUG + printf("Raw DC Decode %d\n",diff); +#endif + if ((diff & bit_set_mask[s]) == 0) + { + diff |= extend_mask[s]; + diff++; + } + diff += *LastDC; /* Change the last DC */ + *LastDC = diff; + } + return(*LastDC); +} + +/*BFUNC + +FrequencyDC() is used to accumulate statistics on what DC codes occur +most frequently. + +EFUNC*/ + +void FrequencyDC(coef) + int coef; +{ + BEGIN("FrequencyDC") + int s,diff,cofac; + + diff = coef - *LastDC; /* Do DPCM */ + *LastDC = coef; + cofac = abs(diff); + if (cofac < 256) /* Find "code" */ + { + s = csize[cofac]; + } + else + { + cofac = cofac >> 8; + s = csize[cofac] + 8; + } +#ifdef CODEC_DEBUG + printf("DC FEncoding Difference %d Size %d\n",diff,s); +#endif + DCFrequency[s]++; /* Increment frequency of such code */ +} + +/*BFUNC + +EncodeDC() encodes the input coefficient to the stream using the +currently installed DC Huffman table. + +EFUNC*/ + +void EncodeDC(coef) + int coef; +{ + BEGIN("EncodeDC") + int s,diff,cofac; + + diff = coef - *LastDC; + *LastDC = coef; /* Do DPCM */ + cofac = abs(diff); + if (cofac < 256) + { + s = csize[cofac]; /* Find true size */ + } + else + { + cofac = cofac >> 8; + s = csize[cofac] + 8; + } +#ifdef CODEC_DEBUG + printf("DC Encoding Difference %d Size %d\n",diff,s); +#endif + EncodeHuffman(s); /* Encode size */ + if (diff < 0) /* Encode difference */ + { + diff--; + } + fputv(s,diff); +} + +/*BFUNC + +ResetCodec() is used to reset all the DC prediction values. This +function is primarily used for initialization and resynchronization. + +EFUNC*/ + +void ResetCodec() +{ + BEGIN("ResetCodec") + int i; + + for(i=0;iNumberComponents;i++) + { + *CScan->LastDC[i] = 0; /* Sets all DC predictions to 0 */ + } +} + +/*BFUNC + +ClearFrameFrequency() clears all current statistics. + +EFUNC*/ + +void ClearFrameFrequency() +{ + int i; + int *iptr; + + for(i=0;iNumberComponents;i++) + { + *CScan->LastDC[i] = 0; + for(iptr=CScan->ACFrequency[i]; + iptrACFrequency[i]+257;iptr++) + { + *iptr = 0; + } + for(iptr=CScan->DCFrequency[i]; + iptrDCFrequency[i]+257;iptr++) + { + *iptr = 0; + } + } +} + +/*BFUNC + +AddFrequency() is used to combine the first set of frequencies denoted +by the first pointer to the second set of frequencies denoted by the +second pointer. + +EFUNC*/ + +void AddFrequency(ptr1,ptr2) + int *ptr1; + int *ptr2; +{ + BEGIN("AddFrequency") + int i; + + for(i=0;i<256;i++) + { + *(ptr1) = *(ptr1) + *(ptr2); + ptr1++; + ptr2++; + } + *(ptr1) = MAX(*(ptr1),*(ptr2)); +} + +/*BFUNC + +InstallFrequency() is used to install a particular frequency set of +arrays (denoted by the [index] scan component from the Scan +parameters). + +EFUNC*/ + +void InstallFrequency(index) + int index; +{ + BEGIN("InstallFrequency") + ACFrequency = CScan->ACFrequency[index]; /* Set the right pointers */ + DCFrequency = CScan->DCFrequency[index]; + LastDC = CScan->LastDC[index]; +} + + +/*BFUNC + +InstallPrediction() is used to install a particular DC prediction for +use in frequency counting, encoding and decoding. + +EFUNC*/ + +void InstallPrediction(index) + int index; +{ + BEGIN("InstallPrediction") + + LastDC = CScan->LastDC[index]; /* Set the right pointer */ +} + +/*BFUNC + +PrintACEhuff() prints out the [index] AC Huffman encoding structure in +the Image structure. + +EFUNC*/ + +void PrintACEhuff(index) + int index; +{ + BEGIN("PrintACEhuff") + int place; + EHUFF *eh; + int *freq; + int i,j; + + freq = CScan->ACFrequency[index]; + eh = CImage->ACEhuff[index]; + printf("Code:[Frequency:Size]:TotalBits\n"); + for(place=0,i=0;i<8;i++) + { + for(j=0;j<8;j++) + { + printf("%2x:[%d:%d]:%d ", + place,freq[place],eh->ehufsi[place], + freq[place]*eh->ehufsi[place]); + place++; + } + printf("\n"); + } +} + +/*BFUNC + +SizeACEhuff() returns the size in bits necessary to code the +particular frequency spectrum by the indexed ehuff. + +EFUNC*/ + +int SizeACEhuff(index) + int index; +{ + BEGIN("SizeACEhuff") + int place,sumbits; + EHUFF *eh; + int *freq; + + freq = CScan->ACFrequency[index]; + eh = CImage->ACEhuff[index]; + for(sumbits=0,place=0;place<256;place++) /* For all codes, */ + { /* return freq * codelength */ + sumbits += freq[place]*(eh->ehufsi[place] + (place & 0x0f)); + } + return(sumbits); +} + +/*BFUNC + +PrintDCEhuff() prints out the DC encoding Huffman structure in the +CImage structure according to the position specified by [index]. + +EFUNC*/ + +void PrintDCEhuff(index) + int index; +{ + BEGIN("PrintDCEhuff") + int place; + EHUFF *eh; + int *freq; + int i,j; + + freq = CScan->DCFrequency[index]; + eh = CImage->DCEhuff[index]; + printf("Code:[Frequency:Size]:TotalBits\n"); + for(place=0,i=0;i<8;i++) + { + for(j=0;j<8;j++) + { + printf("%2x:[%d:%d]:%d ", + place,freq[place],eh->ehufsi[place], + freq[place]*eh->ehufsi[place]); + place++; + } + printf("\n"); + } +} + + +/*BFUNC + +SizeDCEhuff() returns the bit size of the frequency and codes held by +the indexed dc codebook and frequency. + +EFUNC*/ + +int SizeDCEhuff(index) + int index; +{ + BEGIN("SizeDCEhuff") + int place,sumbits; + EHUFF *eh; + int *freq; + + freq = CScan->DCFrequency[index]; + eh = CImage->DCEhuff[index]; + for(sumbits=0,place=0;place<256;place++) /* For all codes */ + { /* Return freq * codelength */ + sumbits += freq[place]*(eh->ehufsi[place] + place); + } + return(sumbits); +} + + +/*BFUNC + +LosslessFrequencyDC() is used to accumulate statistics on what DC codes occur +most frequently. + +EFUNC*/ + +void LosslessFrequencyDC(coef) + int coef; +{ + BEGIN("FrequencyDC") + int s,cofac; + + cofac = coef&0xffff; /* Take modulo */ + if (cofac & 0x8000) /* if signed, then get absoulte val*/ + cofac = 0x10000-cofac; + + for(s=0;cofac>=256;s+=8,cofac>>=8); /* Find "code" */ + s += csize[cofac]; + +#ifdef CODEC_DEBUG + printf("DC FEncoding Difference %d Size %d\n",diff,s); +#endif + DCFrequency[s]++; /* Increment frequency of such code */ +} + +/*BFUNC + +LosslessEncodeDC() encodes the input coefficient to the stream using +the currently installed DC Huffman table. The only exception is the +SSSS value of 16. + +EFUNC*/ + +void LosslessEncodeDC(coef) + int coef; +{ + BEGIN("EncodeDC") + int s,cofac; + + cofac = coef&0xffff; /* Take modulo */ + if (cofac & 0x8000) /* if signed, then get absoulte val*/ + cofac = 0x10000-cofac; + + for(s=0;cofac>=256;s+=8,cofac>>=8); /* Find "code" */ + s += csize[cofac]; + +#ifdef CODEC_DEBUG + printf("DC Encoding Difference %d Size %d\n",coeff,s); +#endif + EncodeHuffman(s); /* Encode size */ + if (coef &0x8000) /* Encode difference */ + coef--; + if (s!=16) fputv(s,coef); +} + +/*BFUNC + +LosslessDecodeDC() is used to decode a DC value from the input stream. +It returns the actual number found. + +EFUNC*/ + +int LosslessDecodeDC() +{ + BEGIN("DecodeDC") + int s,coef; + + s = DecodeHuffman(); +#ifdef CODEC_DEBUG + printf("DC Decode sig. %d\n",s); +#endif + + /* FIXME begin bug http://groups.google.com/group/comp.protocols.dicom/msg/6d90002f734a12eb?dmode=source */ + if (s==16) return(32768); + /* end bug */ + else if (s) + { + coef = fgetv(s); + s--; /* 2's Bit Align */ +#ifdef CODEC_DEBUG + printf("Raw DC Decode %d\n",coef); +#endif + if ((coef & bit_set_mask[s]) == 0) + { + coef |= extend_mask[s]; + coef++; + } + return(coef); + } + else return(0); +} + +/*END*/ diff --git a/gdcm/Utilities/pvrg/csize.h b/gdcm/Utilities/pvrg/csize.h new file mode 100644 index 0000000..21d4d96 --- /dev/null +++ b/gdcm/Utilities/pvrg/csize.h @@ -0,0 +1,289 @@ +/************************************************************* +Copyright (C) 1990, 1991, 1993 Andy C. Hung, all rights reserved. +PUBLIC DOMAIN LICENSE: Stanford University Portable Video Research +Group. If you use this software, you agree to the following: This +program package is purely experimental, and is licensed "as is". +Permission is granted to use, modify, and distribute this program +without charge for any purpose, provided this license/ disclaimer +notice appears in the copies. No warranty or maintenance is given, +either expressed or implied. In no event shall the author(s) be +liable to you or a third party for any special, incidental, +consequential, or other damages, arising out of the use or inability +to use the program for any purpose (or the loss of data), even if we +have been advised of such possibilities. Any public reference or +advertisement of this source code should refer to it as the Portable +Video Research Group (PVRG) code, and not by any author(s) (or +Stanford University) name. +*************************************************************/ +/* +************************************************************ +csize.h + +This file contains one array which has in by value index, the "size" +of the value in bits. + +************************************************************ +*/ + +#ifndef CSIZE_DONE +#define CSIZE_DONE + +static int csize[] = { +0, +1, +2, +2, +3, +3, +3, +3, +4, +4, +4, +4, +4, +4, +4, +4, +5, +5, +5, +5, +5, +5, +5, +5, +5, +5, +5, +5, +5, +5, +5, +5, +6, +6, +6, +6, +6, +6, +6, +6, +6, +6, +6, +6, +6, +6, +6, +6, +6, +6, +6, +6, +6, +6, +6, +6, +6, +6, +6, +6, +6, +6, +6, +6, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +7, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8, +8}; + +#endif diff --git a/gdcm/Utilities/pvrg/dct.h b/gdcm/Utilities/pvrg/dct.h new file mode 100644 index 0000000..f0086ba --- /dev/null +++ b/gdcm/Utilities/pvrg/dct.h @@ -0,0 +1,174 @@ +/************************************************************* +Copyright (C) 1990, 1991, 1993 Andy C. Hung, all rights reserved. +PUBLIC DOMAIN LICENSE: Stanford University Portable Video Research +Group. If you use this software, you agree to the following: This +program package is purely experimental, and is licensed "as is". +Permission is granted to use, modify, and distribute this program +without charge for any purpose, provided this license/ disclaimer +notice appears in the copies. No warranty or maintenance is given, +either expressed or implied. In no event shall the author(s) be +liable to you or a third party for any special, incidental, +consequential, or other damages, arising out of the use or inability +to use the program for any purpose (or the loss of data), even if we +have been advised of such possibilities. Any public reference or +advertisement of this source code should refer to it as the Portable +Video Research Group (PVRG) code, and not by any author(s) (or +Stanford University) name. +*************************************************************/ +/* +************************************************************ +dct.h + +This file contains the basic DCT matrix values for the reference DCT +transform. It doesn't matter if it is slow because it is rarely used. +A butterfly would be much faster. + +************************************************************ +*/ + +#ifndef DCT_DONE +#define DCT_DONE + +#define DC_QUARTER 1.41421356237309504880 +#define DC_THREE_EIGHTHS 0.76536686473017954348 +#define DC_ONE_EIGHTH 1.84775906502257351226 + +/* Bitshifted Twelve */ + +#define IC_QUARTER 2896 +#define IC_THREE_EIGHTHS 1567 +#define IC_ONE_EIGHTH 3784 + + +double DctMatrix[] = { +0.3535533905932737, +0.3535533905932737, +0.3535533905932737, +0.3535533905932737, +0.3535533905932737, +0.3535533905932737, +0.3535533905932737, +0.3535533905932737, +0.4903926402016152, +0.4157348061512727, +0.2777851165098011, +0.0975451610080642, +-0.0975451610080641, +-0.2777851165098010, +-0.4157348061512727, +-0.4903926402016152, +0.4619397662556434, +0.1913417161825449, +-0.1913417161825449, +-0.4619397662556434, +-0.4619397662556434, +-0.1913417161825452, +0.1913417161825450, +0.4619397662556432, +0.4157348061512727, +-0.0975451610080641, +-0.4903926402016152, +-0.2777851165098011, +0.2777851165098009, +0.4903926402016153, +0.0975451610080640, +-0.4157348061512721, +0.3535533905932738, +-0.3535533905932737, +-0.3535533905932738, +0.3535533905932737, +0.3535533905932738, +-0.3535533905932733, +-0.3535533905932736, +0.3535533905932733, +0.2777851165098011, +-0.4903926402016152, +0.0975451610080641, +0.4157348061512728, +-0.4157348061512726, +-0.0975451610080649, +0.4903926402016152, +-0.2777851165098008, +0.1913417161825449, +-0.4619397662556434, +0.4619397662556432, +-0.1913417161825449, +-0.1913417161825453, +0.4619397662556437, +-0.4619397662556435, +0.1913417161825431, +0.0975451610080642, +-0.2777851165098011, +0.4157348061512728, +-0.4903926402016153, +0.4903926402016152, +-0.4157348061512720, +0.2777851165098022, +-0.0975451610080625}; +static double IDctMatrix[] = { +0.3535533905932737, +0.4903926402016152, +0.4619397662556434, +0.4157348061512727, +0.3535533905932738, +0.2777851165098011, +0.1913417161825449, +0.0975451610080642, +0.3535533905932737, +0.4157348061512727, +0.1913417161825449, +-0.0975451610080641, +-0.3535533905932737, +-0.4903926402016152, +-0.4619397662556434, +-0.2777851165098011, +0.3535533905932737, +0.2777851165098011, +-0.1913417161825449, +-0.4903926402016152, +-0.3535533905932738, +0.0975451610080641, +0.4619397662556432, +0.4157348061512728, +0.3535533905932737, +0.0975451610080642, +-0.4619397662556434, +-0.2777851165098011, +0.3535533905932737, +0.4157348061512728, +-0.1913417161825449, +-0.4903926402016153, +0.3535533905932737, +-0.0975451610080641, +-0.4619397662556434, +0.2777851165098009, +0.3535533905932738, +-0.4157348061512726, +-0.1913417161825453, +0.4903926402016152, +0.3535533905932737, +-0.2777851165098010, +-0.1913417161825452, +0.4903926402016153, +-0.3535533905932733, +-0.0975451610080649, +0.4619397662556437, +-0.4157348061512720, +0.3535533905932737, +-0.4157348061512727, +0.1913417161825450, +0.0975451610080640, +-0.3535533905932736, +0.4903926402016152, +-0.4619397662556435, +0.2777851165098022, +0.3535533905932737, +-0.4903926402016152, +0.4619397662556432, +-0.4157348061512721, +0.3535533905932733, +-0.2777851165098008, +0.1913417161825431, +-0.0975451610080625}; + +#endif diff --git a/gdcm/Utilities/pvrg/globals.h b/gdcm/Utilities/pvrg/globals.h new file mode 100644 index 0000000..ca188bf --- /dev/null +++ b/gdcm/Utilities/pvrg/globals.h @@ -0,0 +1,189 @@ +/************************************************************* +Copyright (C) 1990, 1991, 1993 Andy C. Hung, all rights reserved. +PUBLIC DOMAIN LICENSE: Stanford University Portable Video Research +Group. If you use this software, you agree to the following: This +program package is purely experimental, and is licensed "as is". +Permission is granted to use, modify, and distribute this program +without charge for any purpose, provided this license/ disclaimer +notice appears in the copies. No warranty or maintenance is given, +either expressed or implied. In no event shall the author(s) be +liable to you or a third party for any special, incidental, +consequential, or other damages, arising out of the use or inability +to use the program for any purpose (or the loss of data), even if we +have been advised of such possibilities. Any public reference or +advertisement of this source code should refer to it as the Portable +Video Research Group (PVRG) code, and not by any author(s) (or +Stanford University) name. +*************************************************************/ +/* +************************************************************ +globals.h + +This file contains the global includes and other definitions. + +************************************************************ +*/ + +#ifndef GLOBAL_DONE +#define GLOBAL_DONE + +#include +#include "prototypes.h" +#include "param.h" +#include "system.h" + + +/* Map stream functions to those used in stream.c (MSB) */ +/* Makes for easy alterations for least-significant bit non-JPEG defns. */ + +#define sropen mropen +#define srclose mrclose +#define swopen mwopen +#define swclose mwclose + +#define sgetb megetb +#define sgetv megetv +#define sputv meputv + +#define swtell mwtell +#define srtell mrtell + +#define swseek mwseek +#define srseek mrseek + +#define IMAGE struct Image_Definition +#define FRAME struct Frame_Definition +#define SCAN struct Scan_Definition + +#define MUTE 0 +#define WHISPER 1 +#define TALK 2 +#define NOISY 3 +#define SCREAM 4 + + +/* The defined flag for encoding/decoding. */ +#define J_DECODER 1 +#define J_FULLHUFFMAN 2 +#define J_DEFAULTHUFFMAN 4 +#define J_LOSSLESS 8 + +/* Some flags for JpegCustomScan() */ + +#define CUSTOM_DO_DC 1 +#define CUSTOM_DO_AC 2 + +/* Error flags */ + +#define ERROR_NONE 0 +#define ERROR_BOUNDS 1 /*Input Values out of bounds */ +#define ERROR_HUFFMAN_READ 2 /*Huffman Decoder finds bad code */ +#define ERROR_HUFFMAN_ENCODE 3 /*Undefined value in encoder */ +#define ERROR_MARKER 4 /*Error Found in Marker */ +#define ERROR_INIT_FILE 5 /*Cannot initialize files */ +#define ERROR_UNRECOVERABLE 6 /*No recovery mode specified */ +#define ERROR_PREMATURE_EOF 7 /*End of file unexpected */ +#define ERROR_MARKER_STRUCTURE 8 /*Bad Marker Structure */ +#define ERROR_WRITE 9 /*Cannot write output */ +#define ERROR_READ 10 /*Cannot write input */ +#define ERROR_PARAMETER 11 /*System Parameter Error */ +#define ERROR_MEMORY 12 /*Memory exceeded */ + +typedef int iFunc(); +typedef void vFunc(); + +/* A flag obtaining macro */ +#define GetFlag(value,flag) (((value) & (flag)) ? 1:0) + +/* MAX and MIN macros */ +#define MAX(x,y) ((x > y) ? x:y) +#define MIN(x,y) ((x > y) ? y:x) + +/* BEGIN is used to start most routines. It sets up the Routine Name */ +/* which is used in the WHEREAMI() macro */ +#ifdef CODEC_DEBUG +#define BEGIN(name) static char RoutineName[]= name; +#else +#define BEGIN(name) +#endif /*CODEC_DEBUG*/ +/* WHEREAMI prints out current location in code. */ +#ifdef CODEC_DEBUG +#define WHEREAMI() printf("F>%s:R>%s:L>%d: ",\ + __FILE__,RoutineName,__LINE__) +#else +#define WHEREAMI() +#endif /* CODEC_DEBUG */ + +/* InBounds is used to test whether a value is in or out of bounds. */ +#define InBounds(var,lo,hi,str)\ +{if (((var) < (lo)) || ((var) > (hi)))\ +{WHEREAMI(); printf("%s in %d\n",(str),(var));ErrorValue=ERROR_BOUNDS;}} + +/* MakeStructure makes the named structure */ +#define MakeStructure(named_st) ((named_st *) malloc(sizeof(named_st))) + +IMAGE { +char *StreamFileName; /* Name of compressed stream file */ +int JpegMode; /* Mode of JPEG encoder */ +int Jfif; /* If set, automatically drop JFIF marker */ +int ImageSequence; /* Index in image sequence */ +int NumberQuantizationMatrices; /* Number of quantization matrices */ +int *QuantizationMatrices[MAXIMUM_DEVICES]; /* Pointers to q-matrices */ +int NumberACTables; /* Number of AC Huffman tables */ +DHUFF *ACDhuff[MAXIMUM_DEVICES]; /* Decoder huffman tables */ +EHUFF *ACEhuff[MAXIMUM_DEVICES]; /* Encoder huffman tables */ +XHUFF *ACXhuff[MAXIMUM_DEVICES]; /* Transmittable huffman tables */ +int NumberDCTables; /* Number of DC Huffman tables */ +DHUFF *DCDhuff[MAXIMUM_DEVICES]; /* Decoder huffman tables */ +EHUFF *DCEhuff[MAXIMUM_DEVICES]; /* Encoder huffman tables */ +XHUFF *DCXhuff[MAXIMUM_DEVICES]; /* Transmittable huffman tables */ +}; + +FRAME { +int Type; /* SOF(X) where X is type (4 bits) */ +char *ComponentFileName[MAXIMUM_COMPONENTS]; /* image component file names */ +int InsertDnl; /* DNL flag (-2 = AUTO) (-1 = ENABLE) (>0 ) */ +int Q; /* Q Factor (0 disables) */ +int DataPrecision; /* Data Precision (not used) */ +int GlobalHeight; /* Dimensions of overall image */ +int GlobalWidth; +int ResyncInterval; /* Resync interval (0 disables) */ +int GlobalNumberComponents; /* Global number of components */ +int cn[MAXIMUM_COMPONENTS]; /* Translation index used */ +int hf[MAXIMUM_COMPONENTS]; /* Horizontal frequency */ +int vf[MAXIMUM_COMPONENTS]; /* Vertical frequency */ +int tq[MAXIMUM_COMPONENTS]; /* Quantization table used by */ +int Width[MAXIMUM_COMPONENTS]; /* Dimensions of component files */ +int Height[MAXIMUM_COMPONENTS]; +int BufferSize; /* Buffer sizes used */ +int Maxv, Maxh; /* Max Sampling Freq */ +int MDUWide, MDUHigh; /* Number MDU wide */ +int tmpfile; +IMAGE *Image; +}; + +SCAN { +int NumberComponents; /* Number of components in scan */ +int SSS; /* Spectral Selection Start (not used) */ +int SSE; /* Spectral Selection End (not used) */ +int SAH; /* Spectral approximation (not used) */ +int SAL; /* Spectral approximation (not used) */ +int *LastDC[MAXIMUM_SOURCES]; /* LastDC DPCM predictor */ +int *ACFrequency[MAXIMUM_SOURCES]; /* Frequency charts for custom huffman */ +int *DCFrequency[MAXIMUM_SOURCES]; /* table building */ +int LosslessBuffer[MAXIMUM_SOURCES][LOSSLESSBUFFERSIZE]; +int MDUWide, MDUHigh; + /* a integer buffer for lossless coding */ +IOBUF *Iob[MAXIMUM_SOURCES]; /* IOB per scan index */ +int ci[MAXIMUM_SOURCES]; /* Index */ +int ta[MAXIMUM_SOURCES]; /* AC Tables for that scan index */ +int td[MAXIMUM_SOURCES]; /* DC Tables for scan index */ +int NumberACTablesSend; /* Number of tables to send */ +int NumberDCTablesSend; +int NumberQTablesSend; +int sa[MAXIMUM_SOURCES]; /* AC table indices to send */ +int sd[MAXIMUM_SOURCES]; /* DC table indices to send */ +int sq[MAXIMUM_SOURCES]; /* Quantization table indices to send */ +}; + +#endif diff --git a/gdcm/Utilities/pvrg/huffman.c b/gdcm/Utilities/pvrg/huffman.c new file mode 100644 index 0000000..f1f6444 --- /dev/null +++ b/gdcm/Utilities/pvrg/huffman.c @@ -0,0 +1,833 @@ +/************************************************************* +Copyright (C) 1990, 1991, 1993 Andy C. Hung, all rights reserved. +PUBLIC DOMAIN LICENSE: Stanford University Portable Video Research +Group. If you use this software, you agree to the following: This +program package is purely experimental, and is licensed "as is". +Permission is granted to use, modify, and distribute this program +without charge for any purpose, provided this license/ disclaimer +notice appears in the copies. No warranty or maintenance is given, +either expressed or implied. In no event shall the author(s) be +liable to you or a third party for any special, incidental, +consequential, or other damages, arising out of the use or inability +to use the program for any purpose (or the loss of data), even if we +have been advised of such possibilities. Any public reference or +advertisement of this source code should refer to it as the Portable +Video Research Group (PVRG) code, and not by any author(s) (or +Stanford University) name. +*************************************************************/ + +/* +************************************************************ +huffman.c + +This file represents the core Huffman routines, most of them +implemented with the JPEG reference. These routines are not very fast +and can be improved, but comprise very little of software run-time. + +************************************************************ +*/ + +/*LABEL huffman.c */ + +/* Include files */ + +#include "globals.h" +#include "stream.h" +#include /* exit */ + +/*PUBLIC*/ + +static void CodeSize(); +static void CountBits(); +static void AdjustBits(); +static void SortInput(); +static void SizeTable(); +static void CodeTable(); +static void OrderCodes(); +static void DecoderTables(); + +extern void MakeHuffman(); +extern void SpecifiedHuffman(); +extern void MakeDecoderHuffman(); +extern void ReadHuffman(); +extern void WriteHuffman(); +extern int DecodeHuffman(); +extern void EncodeHuffman(); +extern void MakeXhuff(); +extern void MakeEhuff(); +extern void MakeDhuff(); +extern void UseACHuffman(); +extern void UseDCHuffman(); +extern void SetACHuffman(); +extern void SetDCHuffman(); +extern void PrintHuffman(); +extern void PrintTable(); + +/*PRIVATE*/ + +extern int Loud; +extern int ErrorValue; +extern IMAGE *CImage; +extern FRAME *CFrame; +extern SCAN *CScan; + + +static int frequency[257]; +static int codesize[257]; +static int huffsize[257]; +static int huffcode[257]; +static int lastp; +static int others[257]; +static XHUFF *Xhuff=NULL; +static DHUFF *Dhuff=NULL; +static EHUFF *Ehuff=NULL; + +#define fgetb megetb +#define fputv meputv + +#define ClearFrequency() \ +{int *cfip; for(cfip=frequency;cfipbits;cbipbits+36;*(cbip++)=0);} +#define ClearEcodes() \ +{int *cip,*dip;dip=Ehuff->ehufsi;cip=Ehuff->ehufco;\ + while(cip=codesize;csptr--) + { + if (*csptr) + { + Xhuff->bits[*csptr]++; + } + } +} + +/*BFUNC + +AdjustBits() is used to trim the Huffman code tree into 16 bit code +words only. + +EFUNC*/ + +static void AdjustBits() +{ + BEGIN("AdjustBits") + int i,j; + + i=32; + while(1) + { + if (Xhuff->bits[i]>0) + { + j = i-1; + while(!Xhuff->bits[--j]); /* Change from JPEG Manual */ + Xhuff->bits[i] -= 2; /* Remove 2 of the longest hufco */ + Xhuff->bits[i-1]++; /* Add one hufco to its prefix */ + Xhuff->bits[j]--; /* Remove hufco from next length */ + Xhuff->bits[j+1] += 2; /* to be prefix to one hufco */ + } /* from j term and the one */ + /* hufco from the i (longest) term.*/ + else if (--i==16) + { + break; + } + } + while(!Xhuff->bits[i]) /* If fortunate enough not to use */ + { /* any 16 bit codes, then find out */ + i--; /* where last codes are. */ + } + Xhuff->bits[i]--; /* Get rid of the extra code that generated 0xffff */ +} + +/*BFUNC + +SortInput() assembles the codes in increasing order with code length. +Since we know the bit-lengths in increasing order, they will +correspond to the codes with decreasing frequency. This sort is O(mn),), +not the greatest. + +EFUNC*/ + +static void SortInput() +{ + BEGIN("SortInput") + int i,j,p; + + for(p=0,i=1;i<33;i++) /* Designate a length in i. */ + { + for(j=0;j<256;j++) /* Find all codes with a given length. */ + { + if (codesize[j]==i) + { + Xhuff->huffval[p++] = j; /* Add that value to be associated */ + } /* with the next largest code. */ + } + } +} + +/*BFUNC + +SizeTable() is used to associate a size with the code in increasing +length. For example, it would be 44556677... in huffsize[]. Lastp is +the number of codes used. + +EFUNC*/ + +static void SizeTable() +{ + BEGIN("SizeTable") + int i,j,p; + + for(p=0,i=1;i<17;i++) + { + for(j=1;j<=Xhuff->bits[i];j++) + { + huffsize[p++] = i; + } + } + huffsize[p] = 0; + lastp = p; +} + + +/*BFUNC + +CodeTable() is used to generate the codes once the hufsizes are known. + +EFUNC*/ + +static void CodeTable() +{ + BEGIN("CodeTable") + int p,code,size; + + p=0; + code=0; + size = huffsize[0]; + while(1) + { + do + { + huffcode[p++] = code++; + } + while((huffsize[p]==size)&&(p<257)); /* Overflow Detection */ + if (!huffsize[p]) /* All finished. */ + { + break; + } + do /* Shift next code to expand prefix. */ + { + code <<= 1; + size++; + } + while(huffsize[p] != size); + } +} + +/*BFUNC + +OrderCodes() reorders from the monotonically increasing Huffman-code +words into an array which is indexed on the actual value represented +by the codes. This converts the Xhuff structure into an Ehuff +structure. + +EFUNC*/ + +static void OrderCodes() +{ + BEGIN("OrderCodes") + int index,p; + + for(p=0;phuffval[p]; + Ehuff->ehufco[index] = huffcode[p]; + Ehuff->ehufsi[index] = huffsize[p]; + } +} + +/*BFUNC + +DecoderTables() takes the Xhuff and converts it to a form suitable for +the JPEG suggested decoder. This is not the fastest method but it is +the reference method. + +EFUNC*/ + +static void DecoderTables() +{ + BEGIN("DecoderTables") + int l,p; + + for(Dhuff->ml=1,p=0,l=1;l<=16;l++) + { + if (Xhuff->bits[l]==0) + { + Dhuff->maxcode[l] = -1; /* Watch out JPEG is wrong here */ + } /* We use -1 to indicate skipping. */ + else + { + Dhuff->valptr[l]=p; + Dhuff->mincode[l]=huffcode[p]; + p+=Xhuff->bits[l]-1; + Dhuff->maxcode[l]=huffcode[p]; + Dhuff->ml = l; + p++; + } + } + Dhuff->maxcode[Dhuff->ml]++; +} + +/*BFUNC + +MakeHuffman() is used to create the Huffman table from the frequency +passed into it. + +EFUNC*/ + +void MakeHuffman(freq) + int *freq; +{ + BEGIN("MakeHuffman") + int *ptr; + + for(ptr=frequency;ptrbits[i+1] = bts[i]; /* Shift offset for internal specs.*/ + } + for(i=0;ihuffval[i] = hvls[i]; + } + SizeTable(); /*From Xhuff to Ehuff */ + CodeTable(); + OrderCodes(); +} + +/*BFUNC + +MakeDecoderHuffman() creates the decoder tables from the Xhuff structure. + +EFUNC*/ + +void MakeDecoderHuffman() +{ + BEGIN("MakeDecoderHuffman") + + SizeTable(); + CodeTable(); + DecoderTables(); +} + +/*BFUNC + +ReadHuffman() reads in a Huffman structure from the currently open +stream. + +EFUNC*/ + +void ReadHuffman() +{ + BEGIN("ReadHuffman") + int i,accum; + + for(accum=0,i=1;i<=16;i++) + { + Xhuff->bits[i]=bgetc(); + accum += Xhuff->bits[i]; + } + if (Loud > NOISY) + { + printf("Huffman Read In:\n"); + printf("NUMBER OF CODES %d\n",accum); + } + for(i=0;ihuffval[i] = bgetc(); + } + SizeTable(); + CodeTable(); + DecoderTables(); + if (Loud > NOISY) + { + printf("Huffman Read In:\n"); + for(i=1;i<=16;i++) + { + printf("DHUFF->MAXCODE DHUFF->MINCODE DHUFF->VALPTR %d %d %d\n", + Dhuff->maxcode[i],Dhuff->mincode[i],Dhuff->valptr[i]); + } + } +} + +/*BFUNC + +WriteHuffman() writes the Huffman out to the stream. This Huffman +structure is written from the Xhuff structure. + +EFUNC*/ + +void WriteHuffman() +{ + BEGIN("WriteHuffman") + int i,accum; + + if (Xhuff) + { + for(accum=0,i=1;i<=16;i++) + { + bputc(Xhuff->bits[i]); + accum += Xhuff->bits[i]; + } + for(i=0;ihuffval[i]); + } + } + else + { + WHEREAMI(); + printf("Null Huffman table found.\n"); + } +} + +/*BFUNC + +DecodeHuffman() returns the value decoded from the Huffman stream. +The Dhuff must be loaded before this function be called. + +EFUNC*/ + +int DecodeHuffman() +{ + BEGIN("DecodeHuffman") + int code,l,p; + + if (!Dhuff) + { + WHEREAMI(); + printf("Unreferenced decoder Huffman table!\n"); + exit(ERROR_HUFFMAN_READ); + } + code = fgetb(); + for(l=1;code>Dhuff->maxcode[l];l++) + { + if (Loud > WHISPER) + { + WHEREAMI(); + printf("CurrentCode=%d Length=%d Dhuff->Maxcode=%d\n", + code,l,Dhuff->maxcode[l]); + } + code= (code<<1)+fgetb(); + } + if(codemaxcode[Dhuff->ml]) + { + p = Dhuff->valptr[l] + code - Dhuff->mincode[l]; + if (Loud > WHISPER) + { + WHEREAMI(); + printf("HuffmanDecoded code: %d value: %d\n",p,Xhuff->huffval[p]); + } + return(Xhuff->huffval[p]); + } + else + { + WHEREAMI(); + /*printf("Huffman read error: l=%d code=%d\n");*/ + Resync(); + ErrorValue = ERROR_HUFFMAN_READ; + return(0); + } +} + +/*BFUNC + +EncodeHuffman() places the Huffman code for the value onto the stream. + +EFUNC*/ + +void EncodeHuffman(value) + int value; +{ + BEGIN("EncodeHuffman") + + if (Loud > WHISPER) + { + WHEREAMI(); + printf("HUFFMAN_OUTPUT value=%d Ehuff->ehufsi=%d Ehuff->ehufco=%d\n", + value,Ehuff->ehufsi[value],Ehuff->ehufco[value]); + } + if (!Ehuff) + { + WHEREAMI(); + printf("Encoding with Null Huffman table.\n"); + exit(ERROR_HUFFMAN_ENCODE); + } + if (Ehuff->ehufsi[value]) + { + fputv(Ehuff->ehufsi[value],Ehuff->ehufco[value]); + } + else + { + WHEREAMI(); + printf("Null Code for [%d] Encountered:\n",value); + printf("*** Dumping Huffman Table ***\n"); + PrintHuffman(); + printf("***\n"); + ErrorValue = ERROR_HUFFMAN_ENCODE; + exit(ErrorValue); + } +} + +/*BFUNC + +MakeXhuff() creates a Huffman structure and puts it into the current +slot. + +EFUNC*/ + +void MakeXhuff() +{ + BEGIN("MakeXhuff") + + if (!(Xhuff = MakeStructure(XHUFF))) + { + WHEREAMI(); + printf("Cannot allocate memory for Xhuff structure.\n"); + exit(ERROR_MEMORY); + } +} + +/*BFUNC + +MakeEhuff() creates a Huffman structure and puts it into the current +slot. + +EFUNC*/ + +void MakeEhuff() +{ + BEGIN("MakeEhuff") + + if (!(Ehuff = MakeStructure(EHUFF))) + { + WHEREAMI(); + printf("Cannot allocate memory for Ehuff structure.\n"); + exit(ERROR_MEMORY); + } +} + +/*BFUNC + +MakeDhuff() creates a Huffman structure and puts it into the current +slot. + +EFUNC*/ + +void MakeDhuff() +{ + BEGIN("MakeDhuff") + + if (!(Dhuff = MakeStructure(DHUFF))) + { + WHEREAMI(); + printf("Cannot allocate memory for Dhuff structure.\n"); + exit(ERROR_MEMORY); + } +} + +/*BFUNC + +UseACHuffman() installs the appropriate Huffman structure from the +CImage structure. + +EFUNC*/ + +void UseACHuffman(index) + int index; +{ + BEGIN("UseACHuffman") + + Xhuff = CImage->ACXhuff[index]; + Dhuff = CImage->ACDhuff[index]; + Ehuff = CImage->ACEhuff[index]; + if (!Dhuff && !Ehuff) + { + WHEREAMI(); + printf("Reference to nonexistent table %d.\n",index); + } +} + +/*BFUNC + +UseDCHuffman() installs the DC Huffman structure from the CImage +structure. + +EFUNC*/ + +void UseDCHuffman(index) + int index; +{ + BEGIN("UseDCHuffman") + + Xhuff = CImage->DCXhuff[index]; + Dhuff = CImage->DCDhuff[index]; + Ehuff = CImage->DCEhuff[index]; + if (!Dhuff && !Ehuff) + { + WHEREAMI(); + printf("Reference to nonexistent table %d.\n",index); + } +} + +/*BFUNC + +SetACHuffman() sets the CImage structure contents to be the current +Huffman structure. + +EFUNC*/ + +void SetACHuffman(index) + int index; +{ + BEGIN("SetACHuffman") + + CImage->ACXhuff[index] = Xhuff; + CImage->ACDhuff[index] = Dhuff; + CImage->ACEhuff[index] = Ehuff; +} + +/*BFUNC + +SetDCHuffman() sets the CImage structure contents to be the current +Huffman structure. + +EFUNC*/ + +void SetDCHuffman(index) + int index; +{ + BEGIN("SetDCHuffman") + + CImage->DCXhuff[index] = Xhuff; + CImage->DCDhuff[index] = Dhuff; + CImage->DCEhuff[index] = Ehuff; +} + +/*BFUNC + +PrintHuffman() prints out the current Huffman structure. + +EFUNC*/ + +void PrintHuffman() +{ + BEGIN("PrintHuffman") + int i; + + if (Xhuff) + { + printf("Xhuff ID: %p\n",(void*)Xhuff); + printf("Bits: [length:number]\n"); + for(i=1;i<9;i++) + { + printf("[%d:%d]",i,Xhuff->bits[i]); + } + printf("\n"); + for(i=9;i<17;i++) + { + printf("[%d:%d]",i,Xhuff->bits[i]); + } + printf("\n"); + + printf("Huffval:\n"); + PrintTable(Xhuff->huffval); + } + if (Ehuff) + { + printf("Ehuff ID: %p\n",(void*)Ehuff); + printf("Ehufco:\n"); + PrintTable(Ehuff->ehufco); + printf("Ehufsi:\n"); + PrintTable(Ehuff->ehufsi); + } + if (Dhuff) + { + printf("Dhuff ID: %p\n",(void*)Dhuff); + printf("MaxLength: %d\n",Dhuff->ml); + printf("[index:MaxCode:MinCode:ValPtr]\n"); + for(i=1;i<5;i++) + { + printf("[%d:%2x:%2x:%2x]", + i, + Dhuff->maxcode[i], + Dhuff->mincode[i], + Dhuff->valptr[i]); + } + printf("\n"); + for(i=5;i<9;i++) + { + printf("[%d:%2x:%2x:%2x]", + i, + Dhuff->maxcode[i], + Dhuff->mincode[i], + Dhuff->valptr[i]); + } + printf("\n"); + for(i=9;i<13;i++) + { + printf("[%d:%2x:%2x:%2x]", + i, + Dhuff->maxcode[i], + Dhuff->mincode[i], + Dhuff->valptr[i]); + } + printf("\n"); + for(i=13;i<17;i++) + { + printf("[%d:%2x:%2x:%2x]", + i, + Dhuff->maxcode[i], + Dhuff->mincode[i], + Dhuff->valptr[i]); + } + printf("\n"); + } +} + +/*BFUNC + +PrintTable() prints out a table to the screen. The table is assumed to +be a 16x16 matrix represented by a single integer pointer. + +EFUNC*/ + +void PrintTable(table) + int *table; +{ + BEGIN("PrintTable") + int i,j; + + for(i=0;i<16;i++) + { + for(j=0;j<16;j++) + { + printf("%2x ",*(table++)); + } + printf("\n"); + } +} + + + +/*END*/ diff --git a/gdcm/Utilities/pvrg/io.c b/gdcm/Utilities/pvrg/io.c new file mode 100644 index 0000000..743f635 --- /dev/null +++ b/gdcm/Utilities/pvrg/io.c @@ -0,0 +1,1169 @@ +/************************************************************* +Copyright (C) 1990, 1991, 1993 Andy C. Hung, all rights reserved. +PUBLIC DOMAIN LICENSE: Stanford University Portable Video Research +Group. If you use this software, you agree to the following: This +program package is purely experimental, and is licensed "as is". +Permission is granted to use, modify, and distribute this program +without charge for any purpose, provided this license/ disclaimer +notice appears in the copies. No warranty or maintenance is given, +either expressed or implied. In no event shall the author(s) be +liable to you or a third party for any special, incidental, +consequential, or other damages, arising out of the use or inability +to use the program for any purpose (or the loss of data), even if we +have been advised of such possibilities. Any public reference or +advertisement of this source code should refer to it as the Portable +Video Research Group (PVRG) code, and not by any author(s) (or +Stanford University) name. +*************************************************************/ +/* +************************************************************ +io.c + +This package is used to manipulate the raw image files. + +There are two standards: block based, assumed to be in sizes of the +DCT block, herein defined as BlockWidth and BlockHeight; and a special +case, two-line-based, assumed to be of two lines per. + +************************************************************ +*/ + +/*LABEL io.c */ + +/* Include definitions. */ +#include "globals.h" +#ifdef SYSV +#include +#include +#endif +#include /* malloc */ +#include +#include +#include +#include /* memcpy */ +#include /* memcpy */ +#ifdef WIN32 +#include /* lseek on win32 */ +#endif + + +/* Functions which are local and which are exported. */ + +/*PUBLIC*/ + +static BUFFER *MakeXBuffer(); +static void WriteXBuffer(); +static void ReadXBuffer(); +static void ReadResizeBuffer(); +static void FlushBuffer(); +static void BlockMoveTo(); +static void ReadXBound(); +static void WriteXBound(); + +static void LineMoveTo(); + +extern void ReadBlock(); +extern void WriteBlock(); +extern void ResizeIob(); +extern void RewindIob(); +extern void FlushIob(); +extern void SeekEndIob(); +extern void CloseIob(); +extern void MakeIob(); +extern void PrintIob(); +extern void InstallIob(); +extern void TerminateFile(); + +extern void ReadLine(); +extern void ReadPreambleLine(); +extern void WriteLine(); +extern void LineResetBuffers(); + + +/*PRIVATE*/ + +/* External variables */ +extern int Loud; +extern int PointTransform; /* Used for shifting the pels from the I/O */ +extern IMAGE *CImage; +extern FRAME *CFrame; +extern SCAN *CScan; + +/* Internal variables. */ +static IOBUF *Iob=NULL; /* Internal I/O buffer. */ +static int BlockWidth = BLOCKWIDTH; /* Block width. */ +static int BlockHeight = BLOCKHEIGHT; /* Block height. */ + +/* Buffer calculation information */ + +#define BufferIndex(i,iobuf) (iobuf)->blist[(i)] +#define TrueBufferPos(buffer) (((buffer)->currentoffs - \ +((buffer)->tptr - (buffer)->bptr))/buffer->wsize) + + +/*START*/ +/*BFUNC + +MakeXBuffer() constructs a holding buffer for the stream input. It +takes up a size passed into it and returns the appropriate buffer +structure. + +EFUNC*/ + +static BUFFER *MakeXBuffer(nelem,wsize) + int nelem; + int wsize; +{ + BEGIN("MakeXBuffer") + BUFFER *temp; + + if (!(temp = MakeStructure(BUFFER))) /* Make structure */ + { + WHEREAMI(); + printf("Cannot allocate buffer structure.\n"); + exit(ERROR_MEMORY); + } + temp->disable=0; /* Not disabled */ + temp->wsize = wsize; /* Set up word size */ + temp->size=nelem*wsize; /* Set up size, offset */ + temp->currentoffs = 0; + temp->streamoffs = 0; + if (!(temp->space =(unsigned char *) /* Allocate buffer space */ + calloc(temp->size+1,sizeof(unsigned char)))) + { + WHEREAMI(); + printf("Cannot allocate buffer memory.\n"); + exit(ERROR_MEMORY); + } + temp->tptr = temp->bptr = temp->space; + return(temp); +} + +/*BFUNC + +ResizeIob() is used to resize the Iob height and width to conform to +that of the CScan. This is used for the dynamic Number-of-lines +rescaling. + +EFUNC*/ + +void ResizeIob() +{ + BEGIN("ResizeIob") + int index; + + for(index=0;indexNumberComponents;index++) + { + CScan->Iob[index]->width = CFrame->Width[CScan->ci[index]]; + CScan->Iob[index]->height = CFrame->Height[CScan->ci[index]]; + } +} + +/*BFUNC + +MakeIob() is used to create an Iob structure for use in the CScan +structure. An Iob consists of several Buffer structures with some +additional sizing information. The input flags set up the parameters +of the stream. + +EFUNC*/ + +void MakeIob(type,flags,wsize) + int type; + int flags; + int wsize; +{ + BEGIN("MakeIob") + int index,sofs; + BUFFER **current; + IOBUF *temp; + + for(index=0;indexNumberComponents;index++) /* Make IOBUF */ + { /* For each component */ + if (!(temp = MakeStructure(IOBUF))) + { + WHEREAMI(); + printf("Cannot allocate IOBUF structure.\n"); + exit(ERROR_MEMORY); + } + temp->linelastdefault=(1<<(CFrame->DataPrecision-PointTransform-1)); + temp->type = type; + temp->wsize = wsize; + temp->hpos=0; + temp->vpos=0; + temp->width = CFrame->Width[CScan->ci[index]]; /* Set up widthxheight */ + temp->height = CFrame->Height[CScan->ci[index]]; + if (CScan->NumberComponents==1) + { + temp->hor = 1; /* For non-interleaved mode the freq */ + temp->ver = 1; /* is always 1x1 */ + } + else + { + temp->hor = CFrame->hf[CScan->ci[index]]; /* and hf x vf */ + temp->ver = CFrame->vf[CScan->ci[index]]; + } + switch(temp->type) + { + case IOB_BLOCK: /* BLOCK TYPE */ + temp->num = temp->ver*BlockHeight; + break; + case IOB_LINE: /* LINE TYPE */ + temp->num = temp->ver + 1; + break; + default: + WHEREAMI(); + printf("Illegal type specified: %d.\n",type); + exit(ERROR_BOUNDS); + } + temp->flags = flags; /* and also flags */ + if (!(temp->blist = /*Set up buffer list */ + (BUFFER **) calloc(temp->num,sizeof(BUFFER *)))) + { + WHEREAMI(); + printf("Cannot allocate Iob bufferlist.\n"); + exit(ERROR_MEMORY); + } + if( CFrame->tmpfile ) + { + temp->file = CFrame->tmpfile; + } + else + { + if ((temp->file = /* Open file */ + open(CFrame->ComponentFileName[CScan->ci[index]], + flags,UMASK)) < 0) + { + WHEREAMI(); + printf("Cannot open file %s.\n", + CFrame->ComponentFileName[CScan->ci[index]]); + exit(ERROR_INIT_FILE); + } /* Make buffer for every line of component in MDU */ + } + + for(sofs=0,current=temp->blist;currentblist+temp->num;current++) + { + *current = MakeXBuffer(CFrame->BufferSize, wsize); + (*current)->streamoffs = sofs; + (*current)->iob = temp; + (*current)->data_linelast = temp->linelastdefault; + if (!temp->height || (current - temp->blist) < temp->height-1) + { + sofs += CFrame->Width[CScan->ci[index]]*wsize; + } + } + CScan->Iob[index] = temp; + } +} + +/*BFUNC + +PrintIob() is used to print the current input buffer to the stdio +stream. + +EFUNC*/ + +void PrintIob() +{ + BEGIN("PrintIob") + + if (Iob) + { + printf("*** Iob ID: %p ***\n",(void*)Iob); + printf("Number of Buffers: %d Width: %d Height: %d\n", + Iob->num,Iob->width,Iob->height); + printf("hpos: %d vpos: %d hor-freq: %d ver-freq: %d\n", + Iob->hpos,Iob->vpos,Iob->hor,Iob->ver); + printf("filed: %d flags: %d BufferListId: %p\n", + Iob->file,Iob->flags,(void*)Iob->blist); + } + else + { + printf("*** Iob ID: NULL ***\n"); + } +} + +/*BFUNC + +WriteXBuffer() writes out len elements from storage out to the buffer +structure specified. This is can result in a multiple of len bytes +being written out depending on the element structure. + +EFUNC*/ + +static void WriteXBuffer(len,storage,buffer) + int len; + int *storage; + BUFFER *buffer; +{ + BEGIN("WriteXBuffer") + int diff,wout; + + if (buffer->disable) + { + WHEREAMI(); + printf("Attempting to write to disabled buffer!\n"); + } + /* printf("Writing:%d bytes\n",len);*/ + diff = buffer->size - (buffer->bptr - buffer->space); /* Find room left */ + diff = diff/buffer->wsize; /* Scale by element # */ + if(len > diff) + { /* Put as many elems in */ + WriteXBuffer(diff,storage,buffer); /* If no room, then flush current */ + FlushBuffer(buffer); /* buffer out to disk */ + len -= diff; + storage += diff; + } + switch(buffer->wsize) /* Because of compatibility differences between */ + { /* UNIX implementations, we are forced to do this */ + case 1: /* explicit ordering of bytes... */ + while(len--) /* Write the rest of the buffer out to the disk */ + { + wout = *(storage++)<bptr++) = (unsigned char) wout; + } + break; + case 2: + while(len--) /* Write the rest of the buffer out to the disk */ + { + wout = *(storage++)<bptr++) = (unsigned char) (wout>>8)&0xff; + *(buffer->bptr++) = (unsigned char) wout&0xff; + } + break; + case 3: + while(len--) /* Write the rest of the buffer out to the disk */ + { + wout = *(storage++)<bptr++) = (unsigned char) (wout>>16)&0xff; + *(buffer->bptr++) = (unsigned char) (wout>>8)&0xff; + *(buffer->bptr++) = (unsigned char) wout&0xff; + } + break; + case 4: + while(len--) /* Write the rest of the buffer out to the disk */ + { + wout = *(storage++)<bptr++) = (unsigned char) (wout>>24)&0xff; + *(buffer->bptr++) = (unsigned char) (wout>>16)&0xff; + *(buffer->bptr++) = (unsigned char) (wout>>8)&0xff; + *(buffer->bptr++) = (unsigned char) wout&0xff; + } + break; + default: + WHEREAMI(); + printf("Illegal word size in characters %d.\n",buffer->wsize); + exit(ERROR_BOUNDS); + break; + } +} + +/*BFUNC + +ReadXBuffer() is fetches len amount of elements into storage from the +buffer structure. This may actually amount to an arbitrary number of +characters depending on the word size. + +EFUNC*/ + +static void ReadXBuffer(len,storage,buffer) + int len; + int *storage; + BUFFER *buffer; +{ + BEGIN("ReadXBuffer") + int i,numchars,maxelem,rin; + + if (buffer->disable) + { + for(i=0;idata_linelast; + return; + } + + numchars = len*buffer->wsize; + /* The following command recurses because */ + /* it's slightly more efficient that way */ + /* when the probability of recursion is */ + /* negligible. */ + while (numchars > buffer->size) /* We ask more than the buffer can handle */ + { /* Inefficient for small buffer sizes */ + maxelem = buffer->size/buffer->wsize; + ReadXBuffer(maxelem, storage, buffer); /* Split up into several reads */ + storage += maxelem; + len -= maxelem; + numchars -= maxelem*buffer->wsize; + } + if(numchars > (buffer->tptr - buffer->bptr)) /* If we request > bytes */ + ReadResizeBuffer(numchars,buffer); /* Read those bytes in */ + switch(buffer->wsize) /* Again, explicit input of bytes */ + { + case 1: + while(len--) /* Now copy over to storage */ + { + rin = (int) *(buffer->bptr++); + *(storage++) = rin >> PointTransform; + } + break; + case 2: + while(len--) /* Now copy over to storage */ + { + rin = (((int)*(buffer->bptr++))<<8); + rin |= *(buffer->bptr++); + *(storage++) = rin >> PointTransform; + } + break; + case 3: + while(len--) /* Now copy over to storage */ + { + rin = (((int)*(buffer->bptr++))<<16); + rin |= (((int)*(buffer->bptr++))<<8); + rin |= (*(buffer->bptr++)); + *(storage++) = rin >> PointTransform; + } + break; + case 4: + while(len--) /* Now copy over to storage */ + { + rin = (((int)*(buffer->bptr++))<<24); + rin |= (((int)*(buffer->bptr++))<<16); + rin |= (((int)*(buffer->bptr++))<<8); + rin |= (*(buffer->bptr++)); + *(storage++) = rin >> PointTransform; + } + break; + default: + WHEREAMI(); + printf("Illegal word size in characters %d.\n",buffer->wsize); + exit(ERROR_BOUNDS); + break; + } +#ifdef IO_DEBUG + WHEREAMI(); + printf("last read: %d",*(storage-1)); + printf("\n"); +#endif +} + +/*BFUNC + +ReadResizeBuffer() reads len bytes from the stream and puts it +into the buffer. + +EFUNC*/ + +static void ReadResizeBuffer(len,buffer) + int len; + BUFFER *buffer; +{ + BEGIN("ReadResizeBuffer") + int retval,diff,location,amount; + + diff = buffer->tptr - buffer->bptr; /* Find out the current usage */ + if (len > buffer->size-1) /* calculate if we can hold it */ + { + WHEREAMI(); + printf("Length Request Too Large.\n"); + exit(ERROR_PARAMETER); + } +#ifdef IO_DEBUG + printf("SPACE: %x BPTR: %x DIFF: %d\n",buffer->space,buffer->bptr,diff); + printf("ReadLseek %d\n",buffer->streamoffs+buffer->currentoffs); +#endif + assert( diff >= 0 ); + memcpy(buffer->space,buffer->bptr,diff); /* Move buffer down. */ + buffer->bptr = buffer->space; /* Reset pointers. */ + buffer->tptr = buffer->space + diff; + + location = buffer->streamoffs+buffer->currentoffs; + amount = buffer->size-(buffer->tptr - buffer->space); + lseek(buffer->iob->file,location,SEEK_SET); +#ifdef IO_DEBUG + printf("Read: Filed %d Buf: %x NBytes: %d\n", + buffer->iob->file,buffer->tptr,amount); +#endif + if ((retval = read(buffer->iob->file, /* Do the read */ + buffer->tptr, + amount)) < 0) + { + WHEREAMI(); + printf("Cannot Resize.\n"); + exit(ERROR_READ); + } +#ifdef IO_DEBUG + printf("ReadReturn numbytes %d\n",retval); +#endif + buffer->tptr += retval; /* Alter pointers */ + buffer->currentoffs += retval; +} + +/*BFUNC + +FlushBuffer() saves the rest of the bytes in the buffer out to the +disk. + +EFUNC*/ + +static void FlushBuffer(buffer) + BUFFER *buffer; +{ + BEGIN("FlushBuffer") + int retval; + +#ifdef IO_DEBUG + printf("WriteLseek %d\n",buffer->streamoffs+buffer->currentoffs); +#endif + lseek(buffer->iob->file,buffer->streamoffs+buffer->currentoffs,SEEK_SET); + if ((retval = write(buffer->iob->file, + buffer->space, + (buffer->bptr - buffer->space))) < 0) + { + WHEREAMI(); + printf("Cannot flush buffer.\n"); + exit(ERROR_WRITE); + } + buffer->currentoffs += (buffer->bptr - buffer->space); + buffer->bptr = buffer->space; +} + +/*BFUNC + +ReadBlock() is used to get a block from the current Iob. This function +returns (for the JPEG case) 64 bytes in the store integer array. It +is stored in row-major form; that is, the row index changes least +rapidly. + +EFUNC*/ + +void ReadBlock(store) + int *store; +{ + BEGIN("ReadBlock") + int i,voffs; + + voffs = (Iob->vpos % Iob->ver)*BlockHeight; /* Find current v offset*/ +#ifdef IO_DEBUG + for(i=0;iblist[i]->Iob); + } +#endif + for(i=voffs;iblist[i]->Iob); +#endif + ReadXBound(BlockWidth,store,Iob->blist[i]); /* get blockwidth elms */ + store+=BlockWidth; /* Storage array & increment */ + } /* by blockwidth */ + if ((++Iob->hpos % Iob->hor)==0) /* Increment MDU block pos */ + { + if ((++Iob->vpos % Iob->ver) == 0) + { + if (Iob->hpos < CScan->MDUWide*Iob->hor) + { + Iob->vpos -= Iob->ver; + } + else + { + Iob->hpos = 0; /* If at end of raster width*/ + BlockMoveTo(); /* Reload buffers from start */ + } /* of next line. */ + } + else + { + Iob->hpos -= Iob->hor; + } + } +} + +/*BFUNC + +WriteBlock() writes an array of data in the integer array pointed to +by store out to the driver specified by the IOB. The integer array is +stored in row-major form, that is, the first row of (8) elements, the +second row of (8) elements.... + +EFUNC*/ + +void WriteBlock(store) + int *store; +{ + BEGIN("WriteBlock") + int i,voffs; + + voffs = (Iob->vpos % Iob->ver)*BlockHeight; /* Find vertical buffer offs. */ + for(i=voffs;iheight || (((Iob->vpos/Iob->ver)*BlockHeight + i) < + Iob->height)) + { + WriteXBound(BlockWidth,store,Iob->blist[i]); /* write Block elms */ + store+=BlockWidth; /* Iob indexed by offset */ + } + } + if ((++Iob->hpos % Iob->hor)==0) /* Increment block position */ + { /* in MDU. */ + if ((++Iob->vpos % Iob->ver) == 0) + { + if (Iob->hpos < CScan->MDUWide*Iob->hor) + { + Iob->vpos -= Iob->ver; + } + else + { + Iob->hpos = 0; /* If at end of image (width) */ + FlushIob(); /* Flush current IOB and */ + BlockMoveTo(); /* Move to next lower MDU line */ + } + } + else + { + Iob->hpos -= Iob->hor; + } + } +} + + +/*BFUNC + +BlockMoveTo() is used to move to a specific vertical and horizontal +location (block wise) specified by the current Iob. That means you set +the current Iob parameters and then call BlockMoveTo(). + +EFUNC*/ + +static void BlockMoveTo() +{ + BEGIN("BlockMoveTo") + int i,vertical,horizontal; + + if (Loud > MUTE) + { + WHEREAMI(); + printf("%p Moving To [Horizontal:Vertical] [%d:%d] \n", + (void*)Iob,Iob->hpos,Iob->vpos); + } + horizontal = Iob->hpos * BlockWidth; /* Calculate actual */ + vertical = Iob->vpos * BlockHeight; /* Pixel position */ + for(i=0;iver*BlockHeight;i++) + { + if (Iob->height) + { + vertical = + ((vertical < Iob->height) ? + vertical : Iob->height-1); + } + Iob->blist[i]->tptr = /* Reset pointer space */ + Iob->blist[i]->bptr = /* To show no contents */ + Iob->blist[i]->space; + Iob->blist[i]->currentoffs = horizontal* Iob->wsize;/* reset h offset */ + Iob->blist[i]->streamoffs = vertical * Iob->width * + Iob->wsize; /* Reset v offset */ + vertical++; + } +} + +/*BFUNC + +RewindIob() brings all the pointers to the start of the file. The reset +does not flush the buffers if writing. + +EFUNC*/ + +void RewindIob() +{ + BEGIN("RewindIob") + int i; + + switch(Iob->type) + { + case IOB_BLOCK: + BlockWidth = BLOCKWIDTH; /* Block width. */ + BlockHeight = BLOCKHEIGHT; /* Block height. */ + for(i=0;iver*BlockHeight;i++) + { + Iob->blist[i]->tptr = + Iob->blist[i]->bptr = + Iob->blist[i]->space; + Iob->blist[i]->currentoffs = 0; + Iob->blist[i]->streamoffs = i * Iob->width * Iob->wsize; + } + Iob->hpos = Iob->vpos = 0; + break; + case IOB_LINE: + Iob->linelastdefault=(1<<(CFrame->DataPrecision-PointTransform-1)); + for(i= 0;iver+1;i++) + { + Iob->blist[i]->tptr = + Iob->blist[i]->bptr = + Iob->blist[i]->space; + Iob->blist[i]->currentoffs = 0; + if (!i) + { + Iob->blist[i]->streamoffs = 0; + Iob->blist[i]->disable=1; + } + else + { + Iob->blist[i]->streamoffs = (i-1) * Iob->width * Iob->wsize; + Iob->blist[i]->disable=0; + } + Iob->blist[i]->data_linelast = Iob->linelastdefault; + } + Iob->hpos = 0; + Iob->vpos = -1; + break; + default: + WHEREAMI(); + printf("Bad IOB type: %d\n",Iob->type); + break; + } +} + +/*BFUNC + +FlushIob() is used to flush all the buffers in the current Iob. This +is done at the conclusion of a write on the current buffers. + +EFUNC*/ + +void FlushIob() +{ + BEGIN("FlushIob") + int i; + + if (Loud > MUTE) + printf("IOB: %p Flushing buffers\n",(void*)Iob); + switch(Iob->type) + { + case IOB_BLOCK: + for(i=0;iver*BlockHeight;i++) + FlushBuffer(Iob->blist[i]); + break; + case IOB_LINE: + Iob->blist[0]->data_linelast=Iob->linelastdefault; + for(i=1;iver+1;i++) + { + Iob->blist[i]->data_linelast=Iob->linelastdefault; + FlushBuffer(Iob->blist[i]); + } + break; + default: + WHEREAMI(); + printf("Illegal IOB type: %d.\n",Iob->type); + break; + } +} + +/*BFUNC + +SeekEndIob() is used to seek the end of all the buffers in the current +Iob. This is done at the conclusion of a write, to avoid DNL problems. + +EFUNC*/ + +void SeekEndIob() +{ + BEGIN("SeekEndIob") + int size,tsize; + static unsigned char Terminator[] = {0x80,0x00}; + + size = lseek(Iob->file,0,SEEK_END); + tsize = Iob->width*Iob->height*Iob->wsize; + if (size != tsize) + { + WHEREAMI(); + printf("End not flush, making flush (actual: %d != target:%d)\n", + size,tsize); + + if (sizefile,tsize-1,SEEK_SET); /* Seek and terminate */ + write(Iob->file,Terminator,1); + } + else if (size > tsize) + { +#ifdef NOTRUNCATE + WHEREAMI(); + printf("file is too large, only first %d bytes valid\n", + tsize); +#else +#ifdef WIN32 + chsize(Iob->file,tsize); /* no ftruncate on WIN32... */ +#else + ftruncate(Iob->file,tsize); /* simply truncate*/ +#endif +#endif + } + } +} + + +/*BFUNC + +CloseIob() is used to close the current Iob. + +EFUNC*/ + +void CloseIob() +{ + BEGIN("CloseIob") + + if( !CFrame->tmpfile ) /* if file is closed we loose it for good */ +{ + close(Iob->file); +} +} + +/*BFUNC + +ReadXBound() reads nelem elements of information from the specified +buffer. It detects to see whether a load is necessary or not, or +whether the current buffer is out of the image width bounds. + +EFUNC*/ + +static void ReadXBound(nelem,cstore,buffer) + int nelem; + int *cstore; + BUFFER *buffer; +{ + BEGIN("ReadXBound") + int i,diff; + + if ((diff = buffer->iob->width - TrueBufferPos(buffer)) <= nelem) + { +#ifdef IO_DEBUG + printf("ReadBound: Trailing Edge Detected. Diff: %d\n",diff); +#endif + if (diff <= 0) + { + for(i=0;ioverflow; + } + else + { + ReadXBuffer(diff,cstore,buffer); + buffer->overflow = (unsigned int) cstore[diff-1]; + for(i=diff;iiob->width - TrueBufferPos(buffer)) <= nelem) + { /* Diff is balance to write to disk */ + if (diff > 0) /* Write balance out to disk */ + WriteXBuffer(diff,cstore,buffer); + } + else /* If more than numberelem, then can put all */ + WriteXBuffer(nelem,cstore,buffer); /* to the buffer. */ +} + +/*BFUNC + +InstallIob() is used to install the Iob in the current scan as the +real Iob. + +EFUNC*/ + +void InstallIob(index) + int index; +{ + BEGIN("InstallIob") + + if (!(Iob = CScan->Iob[index])) + { + WHEREAMI(); + printf("Warning, NULL Iob installed.\n"); + } +} + + +/*BFUNC + +TerminateFile() is a function that ensures that the entire file +defined by the Iob is properly flush with the filesize specifications. +This function is used when some fatal error occurs. + +EFUNC*/ + + +void TerminateFile() +{ + BEGIN("TerminateFile") + int i,size; + static unsigned char Terminator[] = {0x80,0x00}; + + if (CFrame->GlobalHeight) + { + printf("> GH:%d GW:%d R:%d\n", + CFrame->GlobalHeight, + CFrame->GlobalWidth, + CFrame->ResyncInterval); + for(i=0;iNumberComponents;i++) + { + if (CScan->Iob[i]) + { + printf(">> C:%d N:%s H:%d W:%d hf:%d vf:%d\n", + CScan->ci[i], + CFrame->ComponentFileName[CScan->ci[i]], + CFrame->Height[CScan->ci[i]], + CFrame->Width[CScan->ci[i]], + CFrame->hf[CScan->ci[i]], + CFrame->vf[CScan->ci[i]]); + InstallIob(i); + FlushIob(); + size = lseek(CScan->Iob[i]->file,0,SEEK_END); + if (size != + CFrame->Width[CScan->ci[i]]*CFrame->Height[CScan->ci[i]]* + CScan->Iob[i]->wsize) + { /* Terminate file */ + lseek(CScan->Iob[i]->file, /* by seeking to end */ + (CFrame->Width[CScan->ci[i]]* /* And writing byte */ + CFrame->Height[CScan->ci[i]]* + CScan->Iob[i]->wsize)-1, /* Making flush with */ + SEEK_SET); /* Original size */ + write(CScan->Iob[i]->file,Terminator,1); + } + } + } + } + else + { + WHEREAMI(); + printf("Unknown number of lines. Cannot flush file.\n"); + } +} + + +/*BFUNC + +ReadLine() reads in the lines required by the lossless function. The +array *store should be large enough to handle the line information +read. + +In total, there should be (HORIZONTALFREQUENCY+1) * nelem +(VERTICALFREQUENCY+1) elements in the *store array. This forms a +matrix with each line consisting of: + +[PastPredictor 1 element] nelem* [HORIZONTALFREQUENCY elements] + +And there are (VERTICALFREQUENCY+1) of such lines in the matrix: + +Previous line (2**Precision-1) if beyond specifications of window +Active line 1... +... +Active line VERTICALFREQUENCY... + + +EFUNC*/ + +void ReadLine(nelem,store) + int nelem; + int *store; +{ + BEGIN("ReadLine") + int i; + + for(i=0;iver+1;i++) /* Use voffs to index into */ + { /* Buffer list of IOB */ +#ifdef IO_DEBUG + printf("%d Iob %x\n",i,Iob->blist[i]->Iob); +#endif + *(store++)=Iob->blist[i]->data_linelast; + ReadXBound(Iob->hor*nelem,store,Iob->blist[i]); + store+=Iob->hor*nelem; + Iob->blist[i]->data_linelast = *(store-1); + } + Iob->hpos += Iob->hor*nelem; + if (Iob->hpos >= CScan->MDUWide*Iob->hor) + { + Iob->vpos += Iob->ver; + Iob->hpos = 0; /* If at end of raster width*/ + LineMoveTo(); /* Reload buffers from start */ + } /* of next line. */ +} + +/*BFUNC + +ReadPreambleLine() reads the first line of the *store array for the +WriteLine() companion command. It reads it so that prediction can be +accomplished with minimum effort and storage. + +This command is executed before decoding a particular line for the +prediction values; WriteLine() is called after the decoding is done. + +EFUNC*/ + +void ReadPreambleLine(nelem,store) + int nelem; + int *store; +{ + BEGIN("ReadPreambleLine") + int i; + int preamblelength=1; + + for(i=0;iver+1;i++) /* Use voffs to index into */ + { /* Buffer list of IOB */ +#ifdef IO_DEBUG + printf("%d Iob %x\n",i,Iob->blist[i]->Iob); +#endif + if (iblist[i]->data_linelast; + ReadXBound(Iob->hor*nelem,store,Iob->blist[i]); + store+=Iob->hor*nelem; + Iob->blist[i]->data_linelast = *(store-1); + } + else + { + *(store) = Iob->blist[i]->data_linelast; + store += Iob->hor*nelem+1; + } + } +} + + +/*BFUNC + +WriteLine() is used to write a particular line out to the IOB. The +line must be of the proper form in the array for this function to +work. + +In total, there should be (HORIZONTALFREQUENCY+1) * nelem +(VERTICALFREQUENCY+1) elements in the *store array. This forms a +matrix with each line consisting of: + +[PastPredictor 1 element] nelem* [HORIZONTALFREQUENCY elements] + +And there are (VERTICALFREQUENCY+1) of such lines in the matrix: + +Previous line (2**Precision-1) if beyond specifications of window +Active line 1... +... +Active line VERTICALFREQUENCY... + + +EFUNC*/ + +void WriteLine(nelem,store) + int nelem; + int *store; +{ + BEGIN("WriteLine") + int i; + + store += Iob->hor*nelem+1; /* Get rid of first line */ + for(i=1;iver+1;i++) /* Use voffs to index into */ + { /* Buffer list of IOB */ +#ifdef IO_DEBUG + printf("WriteLine: %d Store: %d Iobblist: %x\n", + i,*(store+1),Iob->blist[i]); +#endif + + WriteXBound(Iob->hor*nelem,store+1,Iob->blist[i]); + store+=(Iob->hor*nelem)+1; + Iob->blist[i]->data_linelast = *(store-1); + } + Iob->hpos += Iob->hor*nelem; + if (Iob->hpos >= CScan->MDUWide*Iob->hor) + { + Iob->vpos += Iob->ver; + Iob->hpos = 0; /* If at end of raster width*/ + FlushIob(); /* Flush current IOB and */ + LineMoveTo(); /* Reload buffers from start */ + } /* of next line. */ +} + +/*BFUNC + +LineResetBuffers() resets all of the line buffers to the +(2\^DataPrecision-1) state. The previous state is the default +prediction. This commmand is used for resynchronization. The +implementation here does a trivial resetting. + +EFUNC */ + +extern void LineResetBuffers() +{ + BEGIN("LineResetBuffers") + int i; + + if (Iob->type!=IOB_LINE) + { + WHEREAMI(); + printf("Attempting to line reset a non-line buffer!\n"); + exit(ERROR_PARAMETER); + } + for(i=0;iver+1;i++) + Iob->blist[i]->data_linelast = Iob->linelastdefault; +} + +/*BFUNC + +LineMoveTo() is used to move to a specific vertical and horizontal +location (line wise) specified by the current Iob. That means you set +the current Iob parameters and then call LineMoveTo(). + +EFUNC*/ + +static void LineMoveTo() +{ + BEGIN("LineMoveTo") + int i,vertical,horizontal; + + if (Loud > MUTE) + { + WHEREAMI(); + printf("%p Moving To [Horizontal:Vertical] [%d:%d] \n", + (void*)Iob,Iob->hpos,Iob->vpos); + } + horizontal = Iob->hpos; + vertical = Iob->vpos; + for(i=0;iver+1;i++) + { /* Reset last element read */ + if (vertical<0) + { + Iob->blist[i]->disable=1; + continue; + } + Iob->blist[i]->disable=0; + Iob->blist[i]->data_linelast=Iob->linelastdefault; + if (Iob->height) + { + vertical = + ((vertical < Iob->height) ? + vertical : Iob->height-1); + } + Iob->blist[i]->tptr = /* Reset pointer space */ + Iob->blist[i]->bptr = /* To show no contents */ + Iob->blist[i]->space; + Iob->blist[i]->currentoffs = horizontal* Iob->wsize; /* Reset h offset */ + Iob->blist[i]->streamoffs = vertical * Iob->width * + Iob->wsize; /* Reset v offset */ + vertical++; + } +} + + + +/*END*/ diff --git a/gdcm/Utilities/pvrg/jpeg.1 b/gdcm/Utilities/pvrg/jpeg.1 new file mode 100644 index 0000000..3250a08 --- /dev/null +++ b/gdcm/Utilities/pvrg/jpeg.1 @@ -0,0 +1,229 @@ +.TH JPEG 1 "14 June 1993" +.UC 4 +.SH NAME +jpeg \- JPEG compression and decompression +.SH SYNOPSIS +.B +jpeg -iw ImageWidth -ih ImageHeight [-JFIF] [-q(l) Q-Factor] +.B + [-a] [-b] [-d] [-k predictortype] [-n] [-o] [-y] [-z] +.B + [-p PrecisionValue] [-t pointtransform] +.B + [-r ResyncInterval] [-s StreamName] +.B + [[-ci ComponentIndex1] [-fw FrameWidth1] [-fh FrameHeight1] +.B + [-hf HorizontalFrequency1] [-vf VerticalFrequency1] +.B + ComponentFile1] +.B + [[-ci ComponentIndex2] [-fw FrameWidth2] [-fh FrameHeight2] +.B + [-hf HorizontalFrequency2] [-vf VerticalFrequency2] +.B + ComponentFile2] +.B + .... +.br +.SH DESCRIPTION +.I jpeg +is a still-image compression/decompression program that performs +JPEG encoding and decoding of multiple raster-scanned files. +.PP +.SH OPTIONS +.TP +.B ImageWidth +specifies the width of the original image. This should correspond to +the width of the widest component and, thus, the width of the +``original image''. All components have widths roughly corresponding +to an integer decimation ratio from this specification. +.br +.TP +.B ImageHeight +specifies the height of the tallest component. This +corresponds to the height of the ``original image''. +.TP +.B -JFIF +specifies that a JFIF header is placed on the encoded stream. This is +unnecessary for decoding. +.TP +.B Q-Factor +option specifies a multiplicative factor for the quantization: each +quantization coefficient of the default matrix is scaled by +(Q-Factor/50). A Q-Factor of 0 is the same thing as a Q-Factor of 50 +because it disables this function. +.B -q +specifies an 8 bit +quantization matrix; +.B -ql +specifies a 16 bit quantization matrix, +useful for 12 bit data. +.TP +.B -a +enables the double-precision floating point Reference DCT. (Default +is Chen DCT.) +.TP +.B -b +enables the Lee DCT. (Default is Chen DCT.) +.TP +.B -d +enables decoding. See below. +.TP +.B -k predictortype +The lossless predictor type, specified as an integer between 1-7. +If specified, then lossless mode is used. +.TP +.B -n +This option specifies that the files should not be transmitted in +interleaved format. +.TP +.B -o +signals that the command interpreter will read from the standard +input. +.TP +.B -p +Specifies the precision. Normally should be between 2-16 for +lossless; 8 or 12 for DCT. If it is specified as a number greater +than 8 then the input is considered to be unsigned shorts (16 bits, +msb first). Not aggressively checked. +.TP +.B -t pointtransform +Specifies the shifting (right) upon loading input and shifting (left) +upon writing input. Generally used by the lossless mode only. Can +be used by the DCT mode to add or subtract bits. +.TP +.B -y +for decoding only, signals that +.I no +resynchronization is enabled, +thus ignore any markers found in the data stream. +.TP +.B -z +enables use of default Huffman tables. This converts the coding from a +two-pass system using the first pass to generate custom tables to a +one-pass system using internal default tables. With this option, the +compression speed is nearly doubled, but because the internal tables +are not custom to the image, the compressed file size increases +slightly. +.TP +.B ResyncInterval +specifies a resync (restart) +interval for the input file--if set to 0 (default), resynchronization +is disabled; otherwise it signifies the number of MDU +between a resync marker. +.TP +.B StreamName +is the place to load(decoder)/store(encoder) +the coded image--if unspecified it defaults to +.B ComponentFile1.jpg. + +.br +For every component in the image we have: + +.TP +.B +ComponentIndex +describes the component index where the file data should be associated +with. The possible values are between 0 and 255. As a rule Y is in +1; U is in 2; V is in 3. The file specfications, if left undisturbed, +will result in component location of 1 for the first component file, 2 +for the second component file, and so on. If +.B -ci +is specified for the +previous component file, then the next component index defaults to the +previous component index plus 1. +.TP +.B FrameWidth +describes the actual width of the component. This should be +determinable by the size of the original image (ImageHeight and +ImageWidth) and the frequency sampling of that component. +This program assumes that the sampling component will be round +.I up +to the nearest integer and other programs may not +necessarily follow that convention, we allow precise specification of +the FrameWidth. The program will notify the user if the +framewidth and frameheight specifications do not correspond to +a logical MDU pattern and thus will refuse to take the input +(in fact, sometimes rounding down will not result in a logical MDU pattern). +.TP +.B FrameHeight +describes the actual height of the component. Multiplied together with +FrameWidth, this should equal the file size of the component. See the +above discussion on the actual specification. +.TP +.B Hor-Frequency +specifies the block sampling frequency of +the component in the horizontal direction for every MDU transmitted. +.TP +.B +Ver-Frequency +specifies the block sampling frequency of +the component in the vertical direction. When multiplied together with +the Horizontal frequency, it corresponds to the number of blocks of +that component in the MDU. +.TP +.B +ComponentFile\fIn\fR +represents the directory path location of the \fIn\fRth component file. +.PP +.SH EXAMPLES +In order to encode a set of raster-scanned files: +128x128 in +.B image.Y; +64x128 in +.B image.U; +and 64x128 in +.B image.V +into the file +.B image.jpg, +the command is + +.br +.B +jpeg -iw 128 -ih 128 -hf 2 image.Y image.U image.V -s image.jpg +.br + +In order to decode a compressed file in +.B image.jpg, +type + +.br +.B +jpeg -d -s image.jpg +.br + +The three output files will be in +.B +image.jpg.1 image.jpg.2 image.jpg.3. +The images can be displayed by the +.I cv +program. +The images can also be converted to ppm and back through +the programs +.I cyuv2ppm +and +.I ppm2cyuv +Those utility programs available by anonymous ftp from +.I havefun.stanford.edu:pub/cv/CVv1.2.1.tar.Z. +.br +There are many more options within an internal command interpreter. +Please see the accompanying documentation in +.I doc.ps +for more details. +.PP +.SH FTP +.I jpeg +is available by anonymous ftp from +.I havefun.stanford.edu:pub/jpeg/JPEGv1.2.tar.Z. +.PP +.SH BUGS +Somewhat slower than many commercial implementations, +some bugs are probably lurking around. +Lossless coding and decoding are especially slow. +Please inform the author at achung@cs.stanford.edu if any bugs +are found. +.PP +.SH AUTHOR +.PP +Andy Hung diff --git a/gdcm/Utilities/pvrg/jpeg.c b/gdcm/Utilities/pvrg/jpeg.c new file mode 100644 index 0000000..e9a8380 --- /dev/null +++ b/gdcm/Utilities/pvrg/jpeg.c @@ -0,0 +1,2219 @@ +/************************************************************* +Copyright (C) 1990, 1991, 1993 Andy C. Hung, all rights reserved. +PUBLIC DOMAIN LICENSE: Stanford University Portable Video Research +Group. If you use this software, you agree to the following: This +program package is purely experimental, and is licensed "as is". +Permission is granted to use, modify, and distribute this program +without charge for any purpose, provided this license/ disclaimer +notice appears in the copies. No warranty or maintenance is given, +either expressed or implied. In no event shall the author(s) be +liable to you or a third party for any special, incidental, +consequential, or other damages, arising out of the use or inability +to use the program for any purpose (or the loss of data), even if we +have been advised of such possibilities. Any public reference or +advertisement of this source code should refer to it as the Portable +Video Research Group (PVRG) code, and not by any author(s) (or +Stanford University) name. +*************************************************************/ +/* +************************************************************ +jpeg.c + +This file contains the main calling routines for the JPEG coder. + +************************************************************ +*/ + +/*LABEL jpeg.c */ + +/* Include files. */ + +#include "tables.h" +#include "marker.h" +#include "globals.h" +#ifdef SYSV +#include +#endif +#include /* exit */ +#include /* strlen */ + +/* + Define the functions to be used with ANSI prototyping. + */ + +/*PUBLIC*/ + +static void JpegEncodeFrame(); +static void JpegDecodeFrame(); +static void JpegDecodeScan(); +static void JpegLosslessDecodeScan(); +static void Help(); + +extern void PrintImage(); +extern void PrintFrame(); +extern void PrintScan(); +extern void MakeImage(); +extern void MakeFrame(); +extern void MakeScanFrequency(); +extern void MakeScan(); +extern void MakeConsistentFileNames(); +extern void CheckValidity(); +extern int CheckBaseline(); +extern void ConfirmFileSize(); +extern void JpegQuantizationFrame(); +extern void JpegDefaultHuffmanScan(); +extern void JpegFrequencyScan(); +extern void JpegCustomScan(); +extern void JpegEncodeScan(); + +extern void JpegLosslessFrequencyScan(); +extern void JpegLosslessEncodeScan(); + +/*PRIVATE*/ + +/* These variables occur in the stream definition. */ + +extern int CleartoResync; +extern int LastKnownResync; +extern int ResyncEnable; +extern int ResyncCount; +extern int EndofFile; +extern int EndofImage; + +/* Define the parameter passing structures. */ +IMAGE *CImage=NULL; /* Current Image variables structure */ +FRAME *CFrame=NULL; /* Current Frame variables structure */ +SCAN *CScan=NULL; /* Current Scan variables structure */ + +/* Define the MDU counters. */ +int CurrentMDU=0; /* Holds the value of the current MDU */ +int NumberMDU=0; /* This number is the number of MDU's */ + +/* Define Lossless info */ + +int LosslessPredictorType=0; /* The lossless predictor used */ +int PointTransform=0; /* This parameter affects the shifting in io.c */ + +/* How we break things up */ + +int ScanComponentThreshold=SCAN_COMPONENT_THRESHOLD; + +/* Define the support/utility variables.*/ +int ErrorValue=0; /* Holds error upon return */ +int Loud=MUTE; /* Loudness gives level of debug traces */ +int HuffmanTrace=0; /* When set, dumps Huffman statistics */ +int Notify=1; /* When set, gives image size feedback */ +int Robust=0; +static int LargeQ=0; /* When set, large quantization is enabled */ + +/* We default to the Chen DCT algorithm. */ +vFunc *UseDct = ChenDct; /* This is the DCT algorithm to use */ +vFunc *UseIDct = ChenIDct; /* This is the inverse DCT algorithm to use */ + +/* Add some macros to ease readability. */ +#define DefaultDct (*UseDct) +#define DefaultIDct (*UseIDct) + +/*START*/ + +/*BFUNC + +main() is first called by the shell routine upon execution of the +program. + +EFUNC*/ + +int main(argc,argv) + int argc; + char **argv; +{ + BEGIN("main") + int i,ComponentIndex; + int Oracle=0; /* Oracle means that we use the lexer interactively */ + + MakeImage(); /* Construct the image structures */ + MakeFrame(); + MakeScan(); + + if (argc == 1) /* No arguments then print help info */ + { + Help(); + exit(-1); + } + + ComponentIndex=1; /* Start with index 1 (Could be zero, but JFIF compat) */ + for(i=1;iJfif=1; + else if (!strcmp(argv[i],"-ci")) + ComponentIndex=atoi(argv[++i]); + else if (*(argv[i]) == '-') /* Strip off first "dash" */ + { + switch(*(++argv[i])) + { + case 'a': /* -a Reference DCT */ + UseDct = ReferenceDct; + UseIDct = ReferenceIDct; + break; + case 'b': /* -b Lee DCT */ + UseDct = LeeDct; + UseIDct = LeeIDct; + break; + case 'd': /* -d Decode */ + CImage->JpegMode = J_DECODER; + break; + case 'k': /* -k Lossless mode */ + CImage->JpegMode = J_LOSSLESS; + CFrame->Type=3; + LosslessPredictorType = atoi(argv[++i]); + break; + case 'f': + switch(*(++argv[i])) + { + case 'w': /* -fw Frame width */ + CFrame->Width[ComponentIndex] = + atoi(argv[++i]); + break; + case 'h': /* -fh Frame height */ + CFrame->Height[ComponentIndex] = + atoi(argv[++i]); + break; + default: + WHEREAMI(); + printf("Illegal option: f%c.\n", + *argv[i]); + exit(ERROR_BOUNDS); + break; + } + break; + case 'i': + switch(*(++argv[i])) + { + case 'w': /* -iw Image width */ + CFrame->GlobalWidth = atoi(argv[++i]); + break; + case 'h': /* -ih Image height */ + CFrame->GlobalHeight = atoi(argv[++i]); + break; + default: + WHEREAMI(); + printf("Illegal option: i%c.\n", + *argv[i]); + exit(ERROR_BOUNDS); + break; + } + break; + case 'h': /* -h horizontal frequency */ + CFrame->hf[ComponentIndex] = + atoi(argv[++i]); + break; +#ifndef PRODUCTION_VERSION + case 'l': /* -l loudness for debugging */ + Loud = atoi(argv[++i]); + break; +#endif + case 'n': /* Set non-interleaved mode */ + ScanComponentThreshold=1; + break; + case 'o': /* -o Oracle mode (input parsing)*/ + Oracle=1; + break; + case 'p': + CFrame->DataPrecision = atoi(argv[++i]); + if (!CFrame->Type) CFrame->Type = 1; + break; + case 'r': /* -r resynchronization */ + CFrame->ResyncInterval = atoi(argv[++i]); + break; + case 'q': /* -q Q factor */ + if (*(++argv[i])=='l') LargeQ=1; + CFrame->Q = atoi(argv[++i]); + break; + case 'v': /* -v vertical frequency */ + CFrame->vf[ComponentIndex] = atoi(argv[++i]); + break; + case 's': /* -s stream file name */ + CImage->StreamFileName = argv[++i]; + break; + case 't': + PointTransform=atoi(argv[++i]); + break; +#ifndef PRODUCTION_VERSION + case 'x': /* -x trace */ + HuffmanTrace = 1; + break; +#endif + case 'u': /* -u disable width/size output */ + Notify=0; + break; + case 'y': + Robust=1; + break; + case 'z': /* -z use default Huffman */ + CImage->JpegMode |= J_DEFAULTHUFFMAN; + break; + case 'g': /* -g GDCM secret option */ + CFrame->tmpfile = atoi(argv[++i]); /* very bad programming but should work :) */ + break; + default: + WHEREAMI(); + printf("Illegal option in command line: %c.\n", + *argv[i]); + exit(ERROR_BOUNDS); + break; + } + } + else /* If not a "-" then a filename */ + { + CFrame->cn[CFrame->GlobalNumberComponents++]= ComponentIndex; + if (!CFrame->vf[ComponentIndex]) + CFrame->vf[ComponentIndex]=1; + if (!CFrame->hf[ComponentIndex]) + CFrame->hf[ComponentIndex]=1; + CFrame->ComponentFileName[ComponentIndex] = argv[i]; + ComponentIndex++; + } + } + + if (Oracle) /* If Oracle set */ + { + initparser(); /* Initialize interactive parser */ + parser(); /* parse input from stdin */ + exit(ErrorValue); + } + + /* Otherwise act on information */ + + if (!(GetFlag(CImage->JpegMode,J_DECODER)) && /* Check for files */ + (CFrame->GlobalNumberComponents == 0)) + { + WHEREAMI(); + printf("No component file specified.\n"); + exit(ERROR_BOUNDS); + } + if (CImage->StreamFileName == NULL) /* Check for stream name */ + { + if (CFrame->ComponentFileName[CFrame->cn[0]]) /* If doesn't exist */ + { /* Create one. */ + CImage->StreamFileName = + (char *) calloc(strlen(CFrame->ComponentFileName[CFrame->cn[0]])+6, + sizeof(char)); + sprintf(CImage->StreamFileName,"%s.jpg", + CFrame->ComponentFileName[CFrame->cn[0]]); + } + else + { + WHEREAMI(); + printf("No stream filename.\n"); + exit(ERROR_BOUNDS); + } + } + if (GetFlag(CImage->JpegMode,J_DECODER)) /* If decoder flag set then */ + { /* decode frame. */ + JpegDecodeFrame(); + } + else + { + if (!(CFrame->GlobalWidth) || !(CFrame->GlobalHeight)) /* Dimensions ? */ + { + WHEREAMI(); + printf("Unspecified frame size.\n"); + exit(ERROR_BOUNDS); + } + swopen(CImage->StreamFileName,0); /* Open output file, index 0*/ + JpegEncodeFrame(); /* Encode the frame */ + swclose(); /* Flush remaining bits */ + } + /*exit(ErrorValue);*/ + return(ErrorValue); +} + +/*BFUNC + +JpegEncodeFrame() handles the basic encoding of the routines provided that +CFrame and CImage are set up properly. It creates the appropriate +CScan to handle the intermediate variables. + +EFUNC*/ + +static void JpegEncodeFrame() +{ + BEGIN("JpegEncodeFrame") + int i,CurrentComponent; + + CurrentComponent=0; /* Write start of image, start of frame */ + WriteSoi(); + if (CImage->Jfif) WriteJfif(); /* Write JFIF marker if necessary */ + MakeConsistentFrameSize(); /* Do it here when everything defined */ + JpegQuantizationFrame(); /* Set up quantization matrices */ + WriteSof(); + if (CFrame->ResyncInterval) /* If resync enabled put DRI marker */ + { + WriteDri(); + } + while(1) /* This loop breaks up a large number of */ + { /* components into small scans */ + if (CFrame->GlobalNumberComponents<=CurrentComponent) + { + break; /* All encoded */ + } + else if (CFrame->GlobalNumberComponents-CurrentComponent <= + ScanComponentThreshold) + { /* If less/equal to (SCT) components do it */ + CScan->NumberComponents = + CFrame->GlobalNumberComponents-CurrentComponent; + for(i=0;CurrentComponentGlobalNumberComponents; + CurrentComponent++,i++) + { + CScan->ci[i]=CFrame->cn[CurrentComponent]; + } + } + else + { /* Break into (SCT) componets */ + CScan->NumberComponents = ScanComponentThreshold; + for(i=0;ici[i]=CFrame->cn[CurrentComponent]; + } + } + CheckValidity(); /* Check validity */ + CheckBaseline(); /* See if type is correct */ + + if (Loud > MUTE) + { + PrintImage(); + PrintFrame(); + PrintScan(); + } + ConfirmFileSize(); /* Does files on disk agree? */ + if (GetFlag(CImage->JpegMode,J_LOSSLESS)) + { + MakeIob(IOB_LINE,O_RDONLY, + ((CFrame->DataPrecision>8)?2:1)); /* Make IO read struct*/ + JpegLosslessFrequencyScan(); /* Else make custom stables */ + JpegCustomScan(CUSTOM_DO_DC); + WriteDht(); /* write Huffman tables */ + JpegLosslessEncodeScan(); + } + else if (GetFlag(CImage->JpegMode,J_DEFAULTHUFFMAN)) + { + MakeIob(IOB_BLOCK,O_RDONLY, + ((CFrame->DataPrecision>8)?2:1)); /* Make IO read struct */ + + JpegDefaultHuffmanScan(); /* If default tables, then set up */ + WriteDqt(); /* Write out quantization */ + WriteDht(); /* and Huffman tables */ + JpegEncodeScan(); /* Encode the scan */ + } + else + { + MakeIob(IOB_BLOCK,O_RDONLY, + ((CFrame->DataPrecision>8)?2:1)); /* Make IO read struct*/ + JpegFrequencyScan(); /* Else make custom tables */ + JpegCustomScan(CUSTOM_DO_AC|CUSTOM_DO_DC); + WriteDqt(); /* Write out quantization */ + WriteDht(); /* and Huffman tables */ + JpegEncodeScan(); /* Encode the scan */ + } + for(i=0;iNumberComponents;i++) /* Close all components */ + { + InstallIob(i); + CloseIob(); + } + } + WriteEoi(); /* All finished, Write eoi */ +} + +/*BFUNC + +JpegQuantizationFrame() sets up the default quantization matrices to be +used in the scan. Not to be used with user-specified quantization. + +EFUNC*/ + +void JpegQuantizationFrame() +{ + BEGIN("JpegQuantizationFrame") + int i; + + if (CFrame->Q) /* if Q rescale quantization matrices */ + CImage->QuantizationMatrices[0] = + ScaleMatrix(CFrame->Q,Q_PRECISION,LargeQ,LuminanceQuantization); + else + CImage->QuantizationMatrices[0] = LuminanceQuantization; + + CScan->sq[CScan->NumberQTablesSend++] = 0; /* Queue luminance to send */ + if (CFrame->GlobalNumberComponents>1) + { + if (CFrame->Q) /* rescale quantization matrices */ + CImage->QuantizationMatrices[1] = + ScaleMatrix(CFrame->Q,Q_PRECISION,LargeQ,ChrominanceQuantization); + else + CImage->QuantizationMatrices[1] = ChrominanceQuantization; + CScan->sq[CScan->NumberQTablesSend++] = 1; /* Queue table to send */ + } + for(i=0;iGlobalNumberComponents;i++) + { + if (i%ScanComponentThreshold) + CFrame->tq[CFrame->cn[i]]=1; /* chrominance q for non-primaries */ + else + CFrame->tq[CFrame->cn[i]]=0; /* luminance q starts each scan */ + } +} + +/*BFUNC + +JpegDefaultHuffmanScan() creates the default tables for baseline use. + +EFUNC*/ + +void JpegDefaultHuffmanScan() +{ + BEGIN("JpegDefaultScan") + int i; + + if (CFrame->DataPrecision>8) + { + WHEREAMI(); + printf("Default tables attempted with precision > 8.\n"); + exit(ERROR_BOUNDS); + } + MakeXhuff(); /* Make luminance DC Huffman */ + MakeEhuff(); + SpecifiedHuffman(LuminanceDCBits,LuminanceDCValues); + SetDCHuffman(0); + MakeXhuff(); /* Make luminance AC Huffman */ + MakeEhuff(); + SpecifiedHuffman(LuminanceACBits,LuminanceACValues); + SetACHuffman(0); + MakeXhuff(); + MakeEhuff(); + CScan->td[0] = 0; + CScan->ta[0] = 0; + CScan->sa[CScan->NumberACTablesSend++] = 0; /* Queue to transmit table */ + CScan->sd[CScan->NumberDCTablesSend++] = 0; + if(CScan->NumberComponents>1) /* Make chrominance Huffman tables */ + { /* Only if necessary */ + SpecifiedHuffman(ChrominanceDCBits,ChrominanceDCValues); + SetDCHuffman(1); + MakeXhuff(); + MakeEhuff(); + SpecifiedHuffman(ChrominanceACBits,ChrominanceACValues); + SetACHuffman(1); + for(i=1;iNumberComponents;i++) + { + CScan->td[i] = 1; + CScan->ta[i] = 1; + } + CScan->sa[CScan->NumberACTablesSend++] = 1; + CScan->sd[CScan->NumberDCTablesSend++] = 1; + CImage->NumberACTables = MAX(CImage->NumberACTables,2); + CImage->NumberDCTables = MAX(CImage->NumberDCTables,2); + } + else + { + CImage->NumberACTables = MAX(CImage->NumberACTables,1); + CImage->NumberDCTables = MAX(CImage->NumberDCTables,1); + } +} + +/*BFUNC + +JpegFrequencyScan() assembles the frequency statistics for the given +scan, making one AC Freq, DC Freq statistic per component specified. +This function should be used before making custom quantization tables. + +EFUNC*/ + +void JpegFrequencyScan() +{ + BEGIN("JpegFrequencyScan") + int i,j,h,v,dohf,dovf; + int input[64],output[64]; + int DCTBound,DCTShift; + + InstallIob(0); /* Zero out for fast single-component */ + InstallPrediction(0); /* operation. */ + InstallFrequency(0); + CheckScan(); + NumberMDU = CScan->MDUWide*CScan->MDUHigh; + ClearFrameFrequency(); + ResetCodec(); + DCTBound = ((CFrame->DataPrecision>8)?16383:1023); + DCTShift = ((CFrame->DataPrecision>8)?2048:128); + for(i=0;iResyncInterval)) + { + if (!(i % CFrame->ResyncInterval)) /* Resync the codec */ + ResetCodec(); + } + for(j=0;jNumberComponents;j++) + { + InstallIob(j); + InstallPrediction(j); /* Install statistics tables */ + InstallFrequency(j); + if (CScan->NumberComponents==1) + dohf=dovf=1; + else + { + dohf = CFrame->hf[CScan->ci[j]]; + dovf = CFrame->vf[CScan->ci[j]]; + } + for(v=0;v + QuantizationMatrices[CFrame-> + tq[CScan->ci[j]]]); + ZigzagMatrix(output,input); + FrequencyDC(*input); /* Freq accumulates */ + FrequencyAC(input); /* stats w/o encoding */ + } + } + } + } + for(i=0;iNumberComponents;i++) /* Rewind to start */ + { + InstallIob(i); + RewindIob(); + } +} + +/*BFUNC + +JpegCustomScan() assembles custom Huffman tables for the input. +It defaults to baseline unless FULLHUFFMAN flag is set. + +EFUNC*/ + +void JpegCustomScan(flags) + int flags; +{ + BEGIN("JpegCustomScan") + int i,Sumbits; + + if ((GetFlag(CImage->JpegMode,J_FULLHUFFMAN)) || + (CScan->NumberComponents < 3)) + { + for(i=0;iNumberComponents;i++) + { + if (GetFlag(flags,CUSTOM_DO_DC)) + { + MakeXhuff(); + MakeEhuff(); + MakeHuffman(CScan->DCFrequency[i]); + SetDCHuffman(i); + CScan->td[i] = i; + CScan->sd[CScan->NumberDCTablesSend++] = i; + } + if (GetFlag(flags,CUSTOM_DO_AC)) + { + MakeXhuff(); + MakeEhuff(); + MakeHuffman(CScan->ACFrequency[i]); + SetACHuffman(i); + CScan->ta[i] = i; + CScan->sa[CScan->NumberACTablesSend++] = i; + } + InstallIob(i); + RewindIob(); + } + CImage->NumberACTables = MAX(CImage->NumberACTables, + CScan->NumberComponents); + CImage->NumberDCTables = MAX(CImage->NumberDCTables, + CScan->NumberComponents); + } + else + { + if (GetFlag(flags,CUSTOM_DO_DC)) + { + MakeXhuff(); /* 0 Component has custom Huffman */ + MakeEhuff(); + MakeHuffman(CScan->DCFrequency[0]); + SetDCHuffman(0); + CScan->td[0] = 0; /* 0 component uses tables 0 */ + CScan->sd[CScan->NumberDCTablesSend++] = 0; /* Queue to send */ + } + if (GetFlag(flags,CUSTOM_DO_AC)) + { + MakeXhuff(); + MakeEhuff(); + MakeHuffman(CScan->ACFrequency[0]); + SetACHuffman(0); + CScan->ta[0] = 0; + CScan->sa[CScan->NumberACTablesSend++] = 0; /* Queue table send */ + } + if (CScan->NumberComponents > 1) + { + if (GetFlag(flags,CUSTOM_DO_DC)) + { + for(i=2;iNumberComponents;i++) /* Rest share Huffman*/ + { /* Accum. frequencies */ + AddFrequency(CScan->DCFrequency[1],CScan->DCFrequency[i]); + } + MakeXhuff(); + MakeEhuff(); + MakeHuffman(CScan->DCFrequency[1]); + SetDCHuffman(1); + for(i=1;iNumberComponents;i++) /* Rest use table 1 */ + CScan->td[i] = 1; + CScan->sd[CScan->NumberDCTablesSend++] = 1;/* Queue to send */ + } + if (GetFlag(flags,CUSTOM_DO_AC)) + { + for(i=2;iNumberComponents;i++) /*Accum. frequencies */ + { + AddFrequency(CScan->ACFrequency[1],CScan->ACFrequency[i]); + } + MakeXhuff(); + MakeEhuff(); + MakeHuffman(CScan->ACFrequency[1]); + SetACHuffman(1); + for(i=1;iNumberComponents;i++) /* Rest use table 1 */ + CScan->ta[i] = 1; + CScan->sa[CScan->NumberACTablesSend++] = 1; /* Queue to send */ + } + CImage->NumberACTables = MAX(CImage->NumberACTables,2);/*reset */ + CImage->NumberDCTables = MAX(CImage->NumberDCTables,2);/* limits */ + } + else + { + CImage->NumberACTables = MAX(CImage->NumberACTables,1); /* Reset */ + CImage->NumberDCTables = MAX(CImage->NumberDCTables,1); /* limits */ + } + } + if (HuffmanTrace) /* If trace flag, then dump out frequency tables */ + { + Sumbits = 0; + for(i=0;iNumberACTables;i++) + { + WHEREAMI(); + printf("AC Code Frequency: Table %d\n",i); + PrintACEhuff(i); + Sumbits += SizeACEhuff(i); + } + for(i=0;iNumberDCTables;i++) + { + WHEREAMI(); + printf("DC Code Frequency: Table %d\n",i); + PrintDCEhuff(i); + Sumbits += SizeDCEhuff(i); + } + WHEREAMI(); + printf("Total bits: %d bytes: %d\n", + Sumbits,(Sumbits+7)/8); + } +} + +/*BFUNC + +JpegEncodeScan() encodes the scan that is given to it. We assume that +the quantization and the Huffman tables have already been specified. + +EFUNC*/ + +void JpegEncodeScan() +{ + BEGIN("JpegEncodeScan") + int i,j,h,v,dohf,dovf; + int input[64],output[64]; + int DCTBound,DCTShift; + + InstallIob(0); + CheckScan(); + NumberMDU = CScan->MDUWide*CScan->MDUHigh; + ClearFrameFrequency(); + ResetCodec(); + DCTBound = ((CFrame->DataPrecision>8)?16383:1023); + DCTShift = ((CFrame->DataPrecision>8)?2048:128); + ResyncCount=0; /* Reset the resync counter for every scan */ + if (CFrame->InsertDnl>0) /* If DNL is greater than 0, insert */ + { /* into according Resync interval */ + if (!(CFrame->ResyncInterval)) + WriteDnl(); /* Automatically write a dnl if no resync is enabled.*/ + else /* If DNL > MDU, then put in last resync */ + CFrame->InsertDnl = MAX(CFrame->InsertDnl, /* interval */ + NumberMDU/CFrame->ResyncInterval); + } + WriteSos(); /* Start of Scan */ + for(i=0;iResyncInterval)) + { + if (!(i % CFrame->ResyncInterval)) /* Check for resync */ + { + if ((i/CFrame->ResyncInterval)==CFrame->InsertDnl) + { + WriteDnl(); /* If resync matches use DNL */ + CFrame->InsertDnl=0; /* Mission accomplished. */ + } + WriteResync(); /* Write resync */ + ResetCodec(); + } + } + for(j=0;jNumberComponents;j++) + { + if (Loud > MUTE) + { + WHEREAMI(); + printf("[Pass 2 [Component:MDU] [%d:%d]]\n",j,i); + } + InstallIob(j); /* Install component j */ + InstallPrediction(j); + if (CScan->NumberComponents==1) + dohf=dovf=1; + else + { + dohf = CFrame->hf[CScan->ci[j]]; + dovf = CFrame->vf[CScan->ci[j]]; + } + for(v=0;v WHISPER) + { + WHEREAMI(); + printf("Raw input:\n"); + PrintMatrix(input); + } + PreshiftDctMatrix(input,DCTShift); /* Shift */ + DefaultDct(input,output); /* DCT */ + BoundDctMatrix(output,DCTBound); /* Bound, limit */ + Quantize(output, /* Quantize */ + CImage-> + QuantizationMatrices[CFrame-> + tq[CScan->ci[j]]]); + ZigzagMatrix(output,input); /* Zigzag trace */ + if (Loud > TALK) + { + WHEREAMI(); + printf("Cooked Output:\n"); + PrintMatrix(input); + } + UseDCHuffman(CScan->td[j]); + EncodeDC(*input); /* Encode DC component */ + UseACHuffman(CScan->ta[j]); + EncodeAC(input); /* Encode AC component */ + } + } + } + } + if (CFrame->InsertDnl==-2) /* -2 is automatic DNL insertion */ + { + WriteDnl(); /* Put DNL here */ + CFrame->InsertDnl=0; + } + for(i=0;iNumberComponents;i++) /* Rewind to start */ + { + InstallIob(i); + RewindIob(); + } +} + +/*BFUNC + +JpegLosslessFrequencyScan() accumulates the frequencies into the DC +frequency index. + +EFUNC*/ + +void JpegLosslessFrequencyScan() +{ + BEGIN("JpegLosslessFrequencyScan") + int x,y,j,h,v,px; + int height,width,horfreq,value; + int MaxElem,CurrentElem,NumberElem; + int StartofLine=1,UseType=1; /* Start with type 1 coding */ + int *input; + + CheckScan(); + for(j=0;jNumberComponents;j++) /* Rewind to start */ + { + InstallIob(j); + RewindIob(); + } + if (CScan->NumberComponents==1) /* Calculate maximum number of */ + MaxElem= LOSSLESSBUFFERSIZE/4; /* elements can be loaded in */ + else + { + MaxElem= LOSSLESSBUFFERSIZE/ + ((CFrame->vf[CScan->ci[0]]+1)*(CFrame->hf[CScan->ci[0]]+1)); + for(j=1;jNumberComponents;j++) /* Rewind to start */ + { + x=LOSSLESSBUFFERSIZE/ + ((CFrame->vf[CScan->ci[j]]+1)*(CFrame->hf[CScan->ci[j]]+1)); + if (x < MaxElem) MaxElem=x; + } + } + CScan->SSS=LosslessPredictorType; + CScan->SAL=PointTransform; + ClearFrameFrequency(); + InstallIob(0); /* Set up values for fast non-interleaved mode */ + InstallFrequency(0); + if (CScan->NumberComponents==1) + height=horfreq=1; + else + { + height=CFrame->vf[CScan->ci[0]]; + horfreq=CFrame->hf[CScan->ci[0]]; + } + NumberMDU = CScan->MDUWide*CScan->MDUHigh; + CurrentMDU=0; + if ((CFrame->ResyncInterval)&&(CFrame->ResyncInterval % CScan->MDUWide)) + { + WHEREAMI(); + printf("Resync Interval not an integer multiple of MDU's wide.\n"); + printf("Proceeding anyways.\n"); + if (MaxElem>=CFrame->ResyncInterval) + MaxElem=CFrame->ResyncInterval; /* Reduce to resync interval */ + else + MaxElem=1; /* Can't proceed quickly */ + } + CurrentElem=NumberElem=0; + for(y=0;yMDUHigh;y++) + { + for(x=0;xMDUWide;x++) + { + if (CurrentMDU && (CFrame->ResyncInterval)) + { + if (!(CurrentMDU % CFrame->ResyncInterval)) /* Check resync */ + { + UseType=1; /* Reset codec */ + for(j=0;jNumberComponents;j++) + { + InstallIob(j); + LineResetBuffers(); + } + } + } + if (!(CurrentMDU%CScan->MDUWide)&&(CurrentMDU)) /* Reset CScan type */ + { + UseType=2; /* Start of line */ + StartofLine=1; /* uses top pel predictor */ + } + CurrentElem++; + if (CurrentElem>=NumberElem) + { + NumberElem = MIN((CScan->MDUWide-x),MaxElem); + CurrentElem=0; + for(j=0;jNumberComponents;j++) + { + InstallIob(j); /* Install component j */ + ReadLine(NumberElem, /* Read in some elements*/ + CScan->LosslessBuffer[j]); + } + } + if (CScan->NumberComponents==1) + { + width=horfreq*NumberElem+1; + input = &CScan->LosslessBuffer[0][CurrentElem]; + if (Loud > NOISY) + { + WHEREAMI(); + printf("[Pass 1 [Component:MDU:Total] [%d:%d:%d]]\n", + 0,CurrentMDU,NumberMDU); + } + switch(UseType) /* Same as lossless coding predictor*/ + { + case 1: + px = input[width]; + break; + case 2: + px = input[1]; + break; + case 3: + px = input[0]; + break; + case 4: + px = input[width] + input[1] - input[0]; + break; + case 5: + px = input[width] + ((input[1] - input[0])>>1); + break; + case 6: + px = input[1] + ((input[width] - input[0])>>1); + break; + case 7: + px = (input[1]+input[width])>>1; /* No rounding */ + break; + default: + WHEREAMI(); + printf("Lossless mode %d not supported.\n",UseType); + break; + } + value=input[width+1]-px; + if (Loud > NOISY) + printf("IN=%d PX=%d FRE: %d\n", + input[width+1],px,value); + LosslessFrequencyDC(value); + } + else + { + for(j=0;jNumberComponents;j++) + { + if (Loud > NOISY) + { + WHEREAMI(); + printf("[Pass 1 [Component:MDU:Total] [%d:%d:%d]]\n", + j,CurrentMDU,NumberMDU); + } + InstallFrequency(j); + height=CFrame->vf[CScan->ci[j]]; + horfreq=CFrame->hf[CScan->ci[j]]; + width=horfreq*NumberElem+1; + input = &CScan->LosslessBuffer[j][CurrentElem*horfreq]; + for(v=1;v<=height;v++) + { + for(h=1;h<=horfreq;h++) + { + switch(UseType) /* lossless coding predictor*/ + { + case 1: + px = input[(v*(width))+h-1]; + break; + case 2: + px = input[((v-1)*(width))+h]; + break; + case 3: + px = input[((v-1)*(width))+h-1]; + break; + case 4: + px = input[(v*(width))+h-1] + + input[((v-1)*(width))+h] - + input[((v-1)*(width))+h-1]; + break; + case 5: + px = input[(v*(width))+h-1] + + ((input[((v-1)*(width))+h] - + input[((v-1)*(width))+h-1])>>1); + break; + case 6: + px = input[((v-1)*(width))+h] + + ((input[(v*(width))+h-1] - + input[((v-1)*(width))+h-1])>>1); + break; + case 7: + px = (input[((v-1)*(width))+h] + + input[(v*(width))+h-1])>>1; + break; + default: + WHEREAMI(); + printf("Lossless mode: %d not supported.\n", + UseType); + break; + } + value=input[(v*(width))+h]-px; + if (Loud > NOISY) + printf("IN=%d PX=%d FRE: %d\n", + input[(v*(width))+h],px,value); + LosslessFrequencyDC(value); + } + } + } + } + CurrentMDU++; + if (StartofLine) + { + UseType=CScan->SSS; + StartofLine=0; + } + } + } + for(j=0;jNumberComponents;j++) /* Rewind to start */ + { + InstallIob(j); + RewindIob(); + } +} + +/*BFUNC + +JpegEncodeLosslessScan() encodes the scan that is given to it by lossless +techniques. The Huffman table should already be specified. + +EFUNC*/ + +void JpegLosslessEncodeScan() +{ + BEGIN("JpegEncodeLosslessScan") + int x,y,j,h,v,px; + int height,width,horfreq,value; + int MaxElem,CurrentElem,NumberElem; + int StartofLine=1,UseType=1; /* Start with type 1 coding */ + int *input; + + CheckScan(); + for(j=0;jNumberComponents;j++) /* Important to rewind to start */ + { /* for lossless coding... */ + InstallIob(j); + RewindIob(); + } + if (CScan->NumberComponents==1) /* Calculate maximum number of */ + MaxElem= LOSSLESSBUFFERSIZE/4; /* elements can be loaded in */ + else + { + MaxElem= LOSSLESSBUFFERSIZE/ + ((CFrame->vf[CScan->ci[0]]+1)*(CFrame->hf[CScan->ci[0]]+1)); + for(j=1;jNumberComponents;j++) /* Rewind to start */ + { + x=LOSSLESSBUFFERSIZE/ + ((CFrame->vf[CScan->ci[j]]+1)*(CFrame->hf[CScan->ci[j]]+1)); + if (x < MaxElem) MaxElem=x; + } + } + CScan->SSS=LosslessPredictorType; + CScan->SAL=PointTransform; + InstallIob(0); + UseDCHuffman(CScan->td[0]); /* Install DC table */ + if (CScan->NumberComponents==1) + height=horfreq=1; + else + { + height=CFrame->vf[CScan->ci[0]]; + horfreq=CFrame->hf[CScan->ci[0]]; + } + NumberMDU = CScan->MDUWide*CScan->MDUHigh; + ResyncCount=0; /* Reset the resync counter for every scan */ + if (CFrame->InsertDnl>0) /* If DNL is greater than 0, insert */ + { /* into according Resync interval */ + if (!(CFrame->ResyncInterval)) + WriteDnl(); /* Automatically write a dnl if no resync is enabled.*/ + else /* If DNL > MDU, then put in last resync */ + CFrame->InsertDnl = MAX(CFrame->InsertDnl, /* interval */ + NumberMDU/CFrame->ResyncInterval); + } + WriteSos(); /* Start of Scan */ + CurrentMDU=0; + if ((CFrame->ResyncInterval)&&(CFrame->ResyncInterval % CScan->MDUWide)) + { + WHEREAMI(); + printf("Resync Interval not an integer multiple of MDU's wide.\n"); + printf("Proceeding anyways.\n"); + if (MaxElem>=CFrame->ResyncInterval) + MaxElem=CFrame->ResyncInterval; /* Reduce to resync interval */ + else + MaxElem=1; /* Can't proceed quickly */ + } + CurrentElem=NumberElem=0; + for(y=0;yMDUHigh;y++) + { + for(x=0;xMDUWide;x++) + { + if (CurrentMDU && (CFrame->ResyncInterval)) + { + if (!(CurrentMDU % CFrame->ResyncInterval)) /* Check resync */ + { + if ((CurrentMDU/CFrame->ResyncInterval)==CFrame->InsertDnl) + { + WriteDnl(); /* If resync matches use DNL */ + CFrame->InsertDnl=0; /* Mission accomplished. */ + } + WriteResync(); /* Write resync */ + UseType=1; /* Reset codec */ + for(j=0;jNumberComponents;j++) + { + InstallIob(j); + LineResetBuffers(); + } + } + } + if (!(CurrentMDU%CScan->MDUWide)&&(CurrentMDU)) /* Reset CScan type */ + { + UseType=2; /* Start of line */ + StartofLine=1; /* uses top pel predictor */ + } + CurrentElem++; + if (CurrentElem>=NumberElem) + { + NumberElem = MIN((CScan->MDUWide-x),MaxElem); + CurrentElem=0; + for(j=0;jNumberComponents;j++) + { + InstallIob(j); /* Install component j */ + ReadLine(NumberElem, /* Read in some elements*/ + CScan->LosslessBuffer[j]); + } + } + if (CScan->NumberComponents==1) + { + if (Loud > MUTE) + { + WHEREAMI(); + printf("[Pass 2 [Component:MDU:Total] [%d:%d:%d]]\n", + 0,CurrentMDU,NumberMDU); + } + input = &CScan->LosslessBuffer[0][CurrentElem]; + width=horfreq*NumberElem+1; + switch(UseType) /* Same as lossless coding predictor*/ + { + case 1: + px = input[width]; + break; + case 2: + px = input[1]; + break; + case 3: + px = input[0]; + break; + case 4: + px = input[width] + input[1] - input[0]; + break; + case 5: + px = input[width] + ((input[1] - input[0])>>1); + break; + case 6: + px = input[1] + ((input[width] - input[0])>>1); + break; + case 7: + px = (input[1] + input[width])>>1; /* No rounding */ + break; + default: + WHEREAMI(); + printf("Lossless mode %d not supported.\n",UseType); + break; + } + value=input[width+1]-px; + if (Loud > MUTE) + printf("IN=%d PX=%d FRE: %d\n", + input[width+1],px,value); + LosslessEncodeDC(value); + } + else + { + for(j=0;jNumberComponents;j++) + { + if (Loud > MUTE) + { + WHEREAMI(); + printf("[Pass 2 [Component:MDU] [%d:%d]]\n", + j,CurrentMDU); + } + height=CFrame->vf[CScan->ci[j]]; + horfreq=CFrame->hf[CScan->ci[j]]; + width=horfreq*NumberElem+1; + input = &CScan->LosslessBuffer[j][CurrentElem*horfreq]; + UseDCHuffman(CScan->td[j]); + for(v=1;v<=height;v++) + { + for(h=1;h<=horfreq;h++) + { + switch(UseType) /* Same as lossless predictor*/ + { + case 1: + px = input[(v*(width))+h-1]; + break; + case 2: + px = input[((v-1)*(width))+h]; + break; + case 3: + px = input[((v-1)*(width))+h-1]; + break; + case 4: + px = input[(v*(width))+h-1] + + input[((v-1)*(width))+h] - + input[((v-1)*(width))+h-1]; + break; + case 5: + px = input[(v*(width))+h-1] + + ((input[((v-1)*(width))+h] - + input[((v-1)*(width))+h-1])>>1); + break; + case 6: + px = input[((v-1)*(width))+h] + + ((input[(v*(width))+h-1] - + input[((v-1)*(width))+h-1])>>1); + break; + case 7: + px = (input[((v-1)*(width))+h] + + input[(v*(width))+h-1])>>1; + break; + default: + WHEREAMI(); + printf("Lossless mode %d not supported.\n", + UseType); + break; + } + value=input[(v*(width))+h]-px; + if (Loud > MUTE) + { + printf("IN=%d PX=%d ENC: %d\n", + input[(v*(width))+h],px,value); + } + LosslessEncodeDC(value); /* Encode as DC component */ + } + } + } + } + CurrentMDU++; + if (StartofLine) + { + UseType=CScan->SSS; + StartofLine=0; + } + } + } + if (CFrame->InsertDnl==-2) /* -2 is automatic DNL insertion */ + { + WriteDnl(); + CFrame->InsertDnl=0; + } + + for(j=0;jNumberComponents;j++) /* Rewind to start */ + { + InstallIob(j); + RewindIob(); + } +} + +/*BFUNC + +JpegDecodeFrame(general,) + ) is used to decode a file. In general; is used to decode a file. In general, CFrame should +hold just enough information to set up the file structure; that is, +which file is to be opened for what component. + +EFUNC*/ + +static void JpegDecodeFrame() +{ + BEGIN("JpegDecodeFrame") + int i; + + sropen(CImage->StreamFileName,0); /* Zero index */ + if (ScreenAllMarker() < 0) /* Do all markers pending */ + { + WHEREAMI(); + printf("No initial marker found!\n"); + exit(-1); + } + while(1) + { + if (NumberMDU>=0) /* If NumberMDU is positive proceed */ + { + if (CurrentMDU >= NumberMDU) /* If all decoded */ + { + if (Notify) /* Print statistics */ + { + printf("> GW:%d GH:%d R:%d\n", + CFrame->GlobalWidth, + CFrame->GlobalHeight, + CFrame->ResyncInterval); + } + for(i=0;iNumberComponents;i++) /* Print Scan info */ + { + if (Notify) + { + printf(">> C:%d N:%s W:%d H:%d hf:%d vf:%d\n", + CScan->ci[i], + CFrame->ComponentFileName[CScan->ci[i]], + CFrame->Width[CScan->ci[i]], + CFrame->Height[CScan->ci[i]], + CFrame->hf[CScan->ci[i]], + CFrame->vf[CScan->ci[i]]); + } + InstallIob(i); + FlushIob(); /* Close image files */ + SeekEndIob(); + CloseIob(); + } + CurrentMDU=0; + if (ScreenAllMarker()<0) /* See if any more images*/ + { + WHEREAMI(); + printf("No trailing marker found!\n"); + exit(-1); + } + if ((EndofFile)||(EndofImage)) /* Nothing, then return */ + { + srclose(); + break; + } + } + } + if (CFrame->Type==3) + JpegLosslessDecodeScan(); + else + JpegDecodeScan(); + } +} + +/*BFUNC + +JpegLosslessDecodeScan() is used to losslessly decode a portion of the +image called the scan. This routine uses the internal lossless +buffers to reduce the overhead in writing. However, one must note +that the overhead is mostly in the Huffman decoding. + +EFUNC*/ + +static void JpegLosslessDecodeScan() +{ + BEGIN("JpegLosslessDecodeScan") + int j,v,h,value,px; + int height,horfreq,width; + int MaxElem,CurrentElem,NumberElem; + int StartofLine=1,UseType=1; /* Start with type 1 coding */ + int *input; + + PointTransform=CScan->SAL; + for(j=0;jNumberComponents;j++) /* Important to rewind to start */ + { /* for lossless coding... */ + InstallIob(j); + RewindIob(); + } + if (CScan->NumberComponents==1) /* Calculate maximum number of */ + MaxElem= LOSSLESSBUFFERSIZE/4; /* elements can be loaded in */ + else + { + MaxElem= LOSSLESSBUFFERSIZE/ + ((CFrame->vf[CScan->ci[0]]+1)*(CFrame->hf[CScan->ci[0]]+1)); + for(j=1;jNumberComponents;j++) /* Rewind to start */ + { + v=LOSSLESSBUFFERSIZE/ + ((CFrame->vf[CScan->ci[j]]+1)*(CFrame->hf[CScan->ci[j]]+1)); + if (v < MaxElem) MaxElem=v; + } + } + InstallIob(0); + UseDCHuffman(CScan->td[0]); /* Install DC table */ + if (CScan->NumberComponents==1) + height=horfreq=1; + else + { + height=CFrame->vf[CScan->ci[0]]; + horfreq=CFrame->hf[CScan->ci[0]]; + } + if ((CFrame->ResyncInterval)&&(CFrame->ResyncInterval % CScan->MDUWide)) + { + WHEREAMI(); + printf("Resync Interval not an integer multiple of MDU's wide.\n"); + printf("Proceeding anyways.\n"); + if (MaxElem>=CFrame->ResyncInterval) + MaxElem=CFrame->ResyncInterval; /* Reduce to resync interval */ + else + MaxElem=1; /* Can't proceed quickly */ + } + CurrentElem=NumberElem=0; + while(1) + { + if ((NumberMDU<0)&&(!(CurrentMDU%CScan->MDUWide))) + { + if (CheckMarker()==0xdc) + ScreenMarker(); + } + if (NumberMDU>=0) /* If NumberMDU is positive proceed */ + { + if (CurrentMDU >= NumberMDU) /* If all decoded */ + return; + } + + if (CFrame->ResyncInterval) /* Flag to decoder stream */ + ResyncEnable = 1; + if (CurrentMDU && (CFrame->ResyncInterval)) + { /* If resync interval */ + if ((CurrentMDU % CFrame->ResyncInterval)==0) + { + if (!CleartoResync) /* If not in error recovery*/ + ReadResync(); /* read resync. */ + if (CleartoResync) + { + /* + Clear until we have LastKnownResync: + the offset is by 1 because we add the resync i%8 + _after_ we code the ith resync interval... + */ + if (((CurrentMDU/CFrame->ResyncInterval)&0x07)== + ((LastKnownResync+1)&0x07)) + CleartoResync = 0; /* Finished with resync clearing */ + } + UseType=1; /* Reset codec */ + for(j=0;jNumberComponents;j++) /* reset line buffers */ + { /* Type is previous pel */ + InstallIob(j); + LineResetBuffers(); + } + } + } + if (!(CurrentMDU%CScan->MDUWide)&&(CurrentMDU)) /* Reset CScan type */ + { + UseType=2; /* Start of line */ + StartofLine=1; /* uses top pel predictor */ + } + + if (CurrentElem>=NumberElem) + { + NumberElem = MIN((CScan->MDUWide-(CurrentMDU%CScan->MDUWide)), + MaxElem); + CurrentElem=0; + for(j=0;jNumberComponents;j++) + { + InstallIob(j); /* Install component j */ + ReadPreambleLine(NumberElem, /* Read in some elements*/ + CScan->LosslessBuffer[j]); + } + } + if (CScan->NumberComponents==1) + { + width=horfreq*NumberElem+1; + input = &CScan->LosslessBuffer[0][CurrentElem]; + switch(UseType) /* Same as lossless coding predictor*/ + { + case 1: + px = input[width]; + break; + case 2: + px = input[1]; + break; + case 3: + px = input[0]; + break; + case 4: + px = input[width] + input[1] - input[0]; + break; + case 5: + px = input[width] + ((input[1] - input[0])>>1); + break; + case 6: + px = input[1] + ((input[width] - input[0])>>1); + break; + case 7: + px = (input[1] + input[width])>>1; /* No rounding */ + break; + default: + WHEREAMI(); + printf("Lossless mode %d not supported.\n",UseType); + break; + } + if (CleartoResync) /* If CleartoResync, flush */ + input[width+1] = 0; + else + { + value = LosslessDecodeDC(); + input[width+1] = (value+px)&0xffff; + if (Loud > MUTE) + { + printf("OUT=%d PX=%d VAL: %d\n", + input[width+1],px,value); + } + } + } + else + { + for(j=0;jNumberComponents;j++) /* Decode MDU */ + { + if (Loud > MUTE) + { + WHEREAMI(); + printf("[Decoder Pass [Component:MDU:#MDU] [%d:%d:%d]]\n", + j,CurrentMDU,NumberMDU); + } + InstallIob(j); /* Install component */ + height=CFrame->vf[CScan->ci[j]]; + horfreq=CFrame->hf[CScan->ci[j]]; + width=horfreq*NumberElem+1; + input = &CScan->LosslessBuffer[j][CurrentElem*horfreq]; + UseDCHuffman(CScan->td[j]); /* Install DC table */ + for(v=1;v<=height;v++) + { + for(h=1;h<=horfreq;h++) + { + switch(UseType) /* Same as lossless coding predictor*/ + { + case 1: + px = input[(v*(width))+h-1]; + break; + case 2: + px = input[((v-1)*(width))+h]; + break; + case 3: + px = input[((v-1)*(width))+h-1]; + break; + case 4: + px = input[(v*(width))+h-1] + + input[((v-1)*(width))+h] - + input[((v-1)*(width))+h-1]; + break; + case 5: + px = input[(v*(width))+h-1] + + ((input[((v-1)*(width))+h] - + input[((v-1)*(width))+h-1])>>1); + break; + case 6: + px = input[((v-1)*(width))+h] + + ((input[(v*(width))+h-1] - + input[((v-1)*(width))+h-1])>>1); + break; + case 7: + px = (input[((v-1)*(width))+h] + + input[(v*(width))+h-1])>>1; + break; + default: + WHEREAMI(); + printf("Lossless mode %d not supported.\n", + UseType); + break; + } + if (CleartoResync) /* If CleartoResync, flush */ + input[(v*(width))+h] = 0; + else + { + value = LosslessDecodeDC(); + input[(v*(width))+h] = (value+px)&0xffff; + if (Loud > MUTE) + { + printf("OUT=%d PX=%d VAL: %d\n", + input[(v*(width))+h],px,value); + } + } + } + } + } + } + CurrentElem++; + if (CurrentElem>=NumberElem) + { + for(j=0;jNumberComponents;j++) + { + InstallIob(j); /* Install component j */ + WriteLine(NumberElem, /* Write out elements*/ + CScan->LosslessBuffer[j]); + } + } + CurrentMDU++; + if (StartofLine) + { + UseType=CScan->SSS; + StartofLine=0; + } + } +} + +/*BFUNC + +JpegDecodeScan() is used to decode a portion of the image called the +scan. Everything is read upon getting to this stage. + +EFUNC*/ + +static void JpegDecodeScan() +{ + BEGIN("JpegDecodeScan") + int j,v,h,dovf,dohf; + int input[64],output[64]; + int IDCTBound,IDCTShift; + + while(1) + { + if ((NumberMDU<0)&&(!(CurrentMDU%CScan->MDUWide))) + { + if (CheckMarker()==0xdc) + ScreenMarker(); + } + if (NumberMDU>=0) /* If NumberMDU is positive proceed */ + { + if (CurrentMDU >= NumberMDU) /* If all decoded */ + return; + } + if (CFrame->ResyncInterval) /* Flag to decoder stream */ + { + ResyncEnable = 1; + } + if (CurrentMDU && (CFrame->ResyncInterval)) + { /* If resync interval */ + if ((CurrentMDU % CFrame->ResyncInterval)==0) + { + if (!CleartoResync) /* If not in error recovery*/ + { /* read resync. */ + ReadResync(); + } + if (CleartoResync) + { + /* + Clear until we have LastKnownResync: + the offset is by 1 because we add the resync i%8 + _after_ we code the ith resync interval... + */ + if (((CurrentMDU/CFrame->ResyncInterval)&0x07)== + ((LastKnownResync+1)&0x07)) + { + CleartoResync = 0; /* Finished with resync clearing */ + } + } + ResetCodec(); /* Reset codec */ + } + } + IDCTBound=((CFrame->DataPrecision>8)?4095:255); + IDCTShift=((CFrame->DataPrecision>8)?2048:128); + for(j=0;jNumberComponents;j++) /* Decode MDU */ + { + if (Loud > MUTE) + { + WHEREAMI(); + printf("[Decoder Pass [Component:MDU:#MDU] [%d:%d:%d]]\n", + j,CurrentMDU,NumberMDU); + } + InstallPrediction(j); /* Install component */ + InstallIob(j); + if (CScan->NumberComponents==1) /* Check for non-interleaved mode */ + dohf=dovf=1; + else + { + dohf = CFrame->hf[CScan->ci[j]]; + dovf = CFrame->vf[CScan->ci[j]]; + } + for(v=0;vtd[j]); /* Install DC table */ + *input = DecodeDC(); /* Decode DC */ + UseACHuffman(CScan->ta[j]); /* Install AC table */ + DecodeAC(input); /* Decode AC */ + if (Loud > TALK) + { + printf("Cooked Input\n"); + PrintMatrix(input); + } + IZigzagMatrix(input,output); /* Inverse zigzag */ + IQuantize(output, /* Inverse quantize */ + CImage-> + QuantizationMatrices[CFrame-> + tq[CScan->ci[j]]]); + DefaultIDct(output,input); /* Inverse DCT */ + PostshiftIDctMatrix(input,IDCTShift); + /* Shift (all positive)*/ + BoundIDctMatrix(input,IDCTBound); /* Bound */ + if (Loud > WHISPER) + { + printf("Raw Output\n"); + PrintMatrix(input); + } + } + WriteBlock(input); /* Write out */ + } + } + } + CurrentMDU++; + } +} + +/*BFUNC + +PrintImage() prints out the Image structure of the CURRENT image. It +is primarily used for debugging. The image structure consists of the +data that is held to be fixed even though multiple scans (or multiple +frames, even though it is not advertised as such by JPEG) are +received. + +EFUNC*/ + +void PrintImage() +{ + BEGIN("PrintImage") + int i; + + printf("*** Image ID: %p ***\n",(void*)CImage); /* %p should work ... */ + if (CImage) + { + if (CImage->StreamFileName) + { + printf("StreamFileName %s\n",(CImage->StreamFileName ? + CImage->StreamFileName : + "Null")); + } + printf("InternalMode: %d ImageSequence: %d\n", + CImage->JpegMode,CImage->ImageSequence); + printf("NumberQuantizationMatrices %d\n", + CImage->NumberQuantizationMatrices); + for(i=0;iNumberQuantizationMatrices;i++) + { + printf("Quantization Matrix [%d]\n",i); + PrintMatrix(CImage->QuantizationMatrices[i]); + } + printf("NumberDCTables %d\n", + CImage->NumberDCTables); + for(i=0;iNumberDCTables;i++) + { + printf("DC Huffman Table[%d]\n",i); + UseDCHuffman(i); + PrintHuffman(); + } + printf("NumberACTables %d\n", + CImage->NumberACTables); + for(i=0;iNumberACTables;i++) + { + printf("AC Huffman Table[%d]\n",i); + UseACHuffman(i); + PrintHuffman(); + } + } +} + +/*BFUNC + +PrintFrame() is used to print the information specific to loading in +the frame. This corresponds roughly to the information received by the +SOF marker code. + +EFUNC*/ + +void PrintFrame() +{ + BEGIN("PrintFrame") + int i; + + printf("*** Frame ID: %p *** (TYPE: %d)\n",(void*)CFrame,CFrame->Type); + if (CFrame) + { + printf("DataPrecision: %d ResyncInterval: %d\n", + CFrame->DataPrecision,CFrame->ResyncInterval); + printf("Height: %d Width: %d\n", + CFrame->GlobalHeight,CFrame->GlobalWidth); + printf("BufferSize: %d Image: %p\n",CFrame->BufferSize,(void*)CFrame->Image); + printf("NumberComponents %d\n", + CFrame->GlobalNumberComponents); + for(i=0;iGlobalNumberComponents;i++) + { + printf("ComponentFileName %s\n", + ((CFrame->ComponentFileName[CFrame->cn[i]]) ? + CFrame->ComponentFileName[CFrame->cn[i]] : "Null")); + printf("HorizontalFrequency: %d VerticalFrequency: %d\n", + CFrame->hf[CFrame->cn[i]],CFrame->vf[CFrame->cn[i]]); + printf("Height: %d Width: %d\n", + CFrame->Height[CFrame->cn[i]],CFrame->Width[CFrame->cn[i]]); + InstallIob(i); + PrintIob(); + } + } +} + +/*BFUNC + +PrintScan() is used to print the information in the CScan structure. +This roughly corresponds to the information received by the Scan +marker code. + +EFUNC*/ + +void PrintScan() +{ + BEGIN("PrintScan") + int i; + + printf("*** Scan ID: %p ***\n",(void*)CScan); + if (CScan) + { + printf("NumberComponents %d\n", + CScan->NumberComponents); + for(i=0;iNumberComponents;i++) + { + printf("Component: %d Index: %d\n", + i,CScan->ci[i]); + printf("DC Huffman Table: %d AC Huffman Table: %d\n", + CScan->td[i],CScan->ta[i]); + printf("LastDC: %d Iob: %p\n", + *(CScan->LastDC[i]),(void*)CScan->Iob[i]); + } + printf("NumberACSend: %d NumberDCSend: %d NumberQSend: %d\n", + CScan->NumberACTablesSend, + CScan->NumberDCTablesSend, + CScan->NumberQTablesSend); + } +} + +/*BFUNC + +MakeImage() makes an image and puts it into the Current Image pointer +(CImage). It initializes the structure appropriate to the JPEG initial +specifications. + +EFUNC*/ + +void MakeImage() +{ + BEGIN("MakeImage") + + if (!(CImage = MakeStructure(IMAGE))) + { + WHEREAMI(); + printf("Cannot allocate memory for Image structure.\n"); + exit(ERROR_MEMORY); + } + CImage->StreamFileName = NULL; + CImage->JpegMode = 0; + CImage->Jfif=0; + CImage->ImageSequence = -1; /* First element in sequence is 0 */ + CImage->NumberQuantizationMatrices = 2; /* Default # matrices is 2 */ + CImage->QuantizationMatrices[0] = LuminanceQuantization; + CImage->QuantizationMatrices[1] = ChrominanceQuantization; + CImage->NumberACTables = 0; /* No tables defined yet */ + CImage->NumberDCTables = 0; +} + +/*BFUNC + +MakeFrame() constructs a Frame Structure and puts it in the Current +Frame pointer (CFrame). + +EFUNC*/ + +void MakeFrame() +{ + BEGIN("MakeFrame") + int i; + + if (!(CFrame = MakeStructure(FRAME))) + { + WHEREAMI(); + printf("Cannot allocate memory for Frame structure.\n"); + exit(ERROR_MEMORY); + } + CFrame->Type=0; /* Baseline type */ + CFrame->InsertDnl = 0; /* Set to default position */ + CFrame->Q = 0; + CFrame->tmpfile = 0; + CFrame->GlobalHeight = 0; + CFrame->GlobalWidth = 0; + CFrame->DataPrecision = 8; /* Default 8 precision */ + CFrame->ResyncInterval = 0; + CFrame->GlobalNumberComponents = 0; + for(i=0;icn[i] = 0; /* Clean out all slots */ + CFrame->hf[i] = 0; + CFrame->vf[i] = 0; + CFrame->tq[i] = 0; + CFrame->Height[i] = 0; + CFrame->Width[i] = 0; + CFrame->ComponentFileName[i] = 0; + } + CFrame->BufferSize = BUFFERSIZE; + CFrame->Image = CImage; +} + +/*BFUNC + +MakeScanFrequency() constructs a set of scan information for the +current variables. These frequency markers are used for creating the +JPEG custom matrices. + +EFUNC*/ + +void MakeScanFrequency() +{ + BEGIN("MakeScanFrequency") + int i; + + for(i=0;iLastDC[i] = MakeStructure(int))) + { + WHEREAMI(); + printf("Cannot allocate LastDC integer store.\n"); + exit(ERROR_MEMORY); + } + if (!(CScan->ACFrequency[i] = (int *) calloc(257,sizeof(int)))) + { + WHEREAMI(); + printf("Cannot allocate AC Frequency array.\n"); + exit(ERROR_MEMORY); + } + if (!(CScan->DCFrequency[i] = (int *) calloc(257,sizeof(int)))) + { + WHEREAMI(); + printf("Cannot allocate DC Frequency array.\n"); + exit(ERROR_MEMORY); + } + } +} + +/*BFUNC + +MakeScan() is used for creating the Scan structure which holds most of +the information in the Scan marker code. + +EFUNC*/ + +void MakeScan() +{ + BEGIN("MakeScan") + int i; + + if (!(CScan = MakeStructure(SCAN))) + { + WHEREAMI(); + printf("Cannot allocate memory for Scan structure.\n"); + exit(ERROR_MEMORY); + } + CScan->NumberACTablesSend = 0; /* Install with default values */ + CScan->NumberDCTablesSend = 0; + CScan->NumberComponents = 0; + for(i=0;ici[i] = 0; + CScan->ta[i] = 0; + CScan->td[i] = 0; + CScan->sa[i] = 0; + CScan->sd[i] = 0; + CScan->sq[i] = 0; + } + CScan->SSS=0; + CScan->SSE=0; + CScan->SAH=0; + CScan->SAL=0; + MakeScanFrequency(); +} + +/*BFUNC + +MakeConsistentFileNames() is used to construct consistent filenames +for opening and closing of data storage. It is used primarily by the +decoder when all the files may not necessarily be specified. + +EFUNC*/ + +void MakeConsistentFileNames() +{ + BEGIN("MakeConsistentFileNames") + int i; + + for(i=0;iNumberComponents;i++) + { + if (CImage->ImageSequence) /* If in sequence, must add sequence */ + { /* identifier */ + CFrame->ComponentFileName[CScan->ci[i]] = + (char *) calloc(strlen(CImage->StreamFileName)+16,sizeof(char)); + sprintf(CFrame->ComponentFileName[CScan->ci[i]],"%s.%d.%d", + CImage->StreamFileName,CImage->ImageSequence,CScan->ci[i]); + } + else if (CFrame->ComponentFileName[CScan->ci[i]] == NULL) + { /* Otherwise if none specified, create. */ + CFrame->ComponentFileName[CScan->ci[i]] = + (char *) calloc(strlen(CImage->StreamFileName)+8,sizeof(char)); + sprintf(CFrame->ComponentFileName[CScan->ci[i]],"%s.%d", + CImage->StreamFileName,CScan->ci[i]); + } + } +} + +/*BFUNC + +CheckValidity() checks whether the current values in CFrame and CScan +meet the internal specifications for correctness and the algorithm +can guarantee completion. + +EFUNC*/ + +void CheckValidity() +{ + BEGIN("CheckValidity") + int i; + + ErrorValue = 0; /* Check if within internal specs */ + InBounds(CFrame->GlobalWidth,0,MAXIMUM_IMAGE_WIDTH,"Bad Image Width"); + InBounds(CFrame->GlobalHeight,0,MAXIMUM_IMAGE_HEIGHT,"Bad Image Height"); + if (CFrame->Q<0) + { + WHEREAMI(); + printf("Q factor is negative - must be positive\n"); + } + if ((CFrame->DataPrecision!=8)&&(CFrame->DataPrecision!=12)) + { + if (CImage->JpegMode == J_LOSSLESS) + { + if (CFrame->DataPrecision<=16) + printf("Precision type: %d\n",CFrame->DataPrecision); + else + printf("Caution: precision type: %d greater than 16.\n", + CFrame->DataPrecision); + } + else + printf("Caution: precision type: %d not 8 or 12.\n", + CFrame->DataPrecision); + } + InBounds(CScan->NumberComponents,1,15,"Bad Number of Components"); + for(i=0;iNumberComponents;i++) + { + InBounds(CFrame->Width[CScan->ci[i]],0,MAXIMUM_IMAGE_WIDTH, + "Bad Frame Width"); + InBounds(CFrame->Height[CScan->ci[i]],0,MAXIMUM_IMAGE_HEIGHT, + "Bad Frame Height"); + InBounds(CFrame->hf[CScan->ci[i]],1,MAXIMUM_HORIZONTAL_FREQUENCY, + "Bad Horizontal Frequency"); + InBounds(CFrame->vf[CScan->ci[i]],1,MAXIMUM_VERTICAL_FREQUENCY, + "Bad Vertical Frequency"); + } + InBounds(LosslessPredictorType,0,7,"Bad Lossless Predictor Type"); + if (PointTransform) + { + if (!(LosslessPredictorType)) + { + WHEREAMI(); + printf("Point Transform specified without lossless prediction.\n"); + printf("Shifting of input/output should be anticipated.\n"); + } + else + InBounds(PointTransform,0,14,"Bad Point Transform"); + } + if (ErrorValue) + { + WHEREAMI(); + printf("Invalid input detected.\n"); + exit(ErrorValue); + } +} + +/*BFUNC + +CheckBaseline() checks whether the internal values meet JPEG Baseline +specifications. + +EFUNC*/ + +int CheckBaseline() +{ + BEGIN("CheckBaseline") + int i; + + ErrorValue = 0; /* Check for JPEG specs */ + InBounds(CFrame->GlobalWidth,0,MAXIMUM_IMAGE_WIDTH,"Bad Image Width"); + InBounds(CFrame->GlobalHeight,0,MAXIMUM_IMAGE_HEIGHT,"Bad Image Height"); + if (CFrame->Q<0) + { + WHEREAMI(); + printf("Q factor is negative - must be positive\n"); + } + InBounds(CScan->NumberComponents,1,4,"Bad Number of Components"); + for(i=0;iNumberComponents;i++) + { + InBounds(CFrame->Width[CScan->ci[i]],0,MAXIMUM_IMAGE_WIDTH, + "Bad Frame Width"); + InBounds(CFrame->Height[CScan->ci[i]],0,MAXIMUM_IMAGE_HEIGHT, + "Bad Frame Height"); + InBounds(CFrame->hf[CScan->ci[i]],1,MAXIMUM_JPEG_HORIZONTAL_FREQUENCY, + "Bad Horizontal Frequency"); + InBounds(CFrame->vf[CScan->ci[i]],1,MAXIMUM_JPEG_VERTICAL_FREQUENCY, + "Bad Vertical Frequency"); + } + if (ErrorValue) + { + printf("Caution: JPEG++ Mode.\n"); + ErrorValue = 0; + } + return 0; +} + +/*BFUNC + +ConfirmFileSize() checks to see if the files used in the scan actually +exist and correspond in size to the input given. + +EFUNC*/ + +void ConfirmFileSize() +{ + BEGIN("ConfirmFileSize") + int i,FileSize; + FILE *test; + + for(i=0;iNumberComponents;i++) /* Do for all components in scan*/ + { + if (CFrame->ComponentFileName[CScan->ci[i]]) + { + if ((test = fopen(CFrame->ComponentFileName[CScan->ci[i]], + "rb")) == NULL) + { + WHEREAMI(); + printf("Cannot open filename %s\n", + CFrame->ComponentFileName[CScan->ci[i]]); + exit(ERROR_BOUNDS); + } + fseek(test,0,2); /* Go to end */ + FileSize = ftell(test); /* Find number of bytes */ + rewind(test); + if (CFrame->Height[CScan->ci[i]] == 0) /* Must have good dimens*/ + { + if (CFrame->Width[CScan->ci[i]] == 0) + { + WHEREAMI(); + printf("Bad file specification in %s.\n", + CFrame->ComponentFileName[CScan->ci[i]]); + } + else + { + CFrame->Height[CScan->ci[i]] = FileSize / + (CFrame->Width[CScan->ci[i]]* + ((CFrame->DataPrecision>8)?2:1)); + WHEREAMI(); + printf("Autosizing height to %d\n", + CFrame->Height[CScan->ci[i]]); + } + } /* Dimensions must conform */ + if (FileSize != + CFrame->Width[CScan->ci[i]] * CFrame->Height[CScan->ci[i]]* + ((CFrame->DataPrecision>8)?2:1)) + { + WHEREAMI(); + printf("File size conflict in %s, est: %d act: %d \n", + CFrame->ComponentFileName[CScan->ci[i]], + CFrame->Width[CScan->ci[i]]*CFrame->Height[CScan->ci[i]]* + ((CFrame->DataPrecision>8)?2:1), + FileSize); + exit(ERROR_BOUNDS); + } + fclose(test); + } + } +} + +/*BFUNC + +Help() prints out general information regarding the use of this +JPEG software. + +EFUNC*/ + +static void Help() +{ + BEGIN("Help") + + printf("jpeg -iw ImageWidth -ih ImageHeight [-JFIF] [-q(l) Q-Factor]\n"); + printf(" [-a] [-b] [-d] [-k predictortype] [-n] [-o] [-y] [-z]\n"); + printf(" [-p PrecisionValue] [-t pointtransform]\n"); + printf(" [-r ResyncInterval] [-s StreamName]\n"); + printf(" [[-ci ComponentIndex1] [-fw FrameWidth1] [-fh FrameHeight1]\n"); + printf(" [-hf HorizontalFrequency1] [-vf VerticalFrequency1]\n"); + printf(" ComponentFile1]\n"); + printf(" [[-ci ComponentIndex2] [-fw FrameWidth2] [-fh FrameHeight2]\n"); + printf(" [-hf HorizontalFrequency2] [-vf VerticalFrequency2]\n"); + printf(" ComponentFile1]\n"); + printf(" ....\n\n"); + printf("-JFIF puts a JFIF marker. Don't change component indices.\n"); + printf("-a enables Reference DCT.\n"); + printf("-b enables Lee DCT.\n"); + printf("-d decoder enable.\n"); + printf("-[k predictortype] enables lossless mode.\n"); + printf("-q specifies quantization factor; -ql specifies can be long.\n"); + printf("-n enables non-interleaved mode.\n"); + printf("-[t pointtransform] is the number of bits for the PT shift.\n"); + printf("-o enables the Command Interpreter.\n"); + printf("-p specifies precision.\n"); + printf("-y run in robust mode against errors (cannot be used with DNL).\n"); + printf("-z uses default Huffman tables.\n"); +} + +/*END*/ diff --git a/gdcm/Utilities/pvrg/leedct.c b/gdcm/Utilities/pvrg/leedct.c new file mode 100644 index 0000000..9f7c3a2 --- /dev/null +++ b/gdcm/Utilities/pvrg/leedct.c @@ -0,0 +1,468 @@ +/************************************************************* +Copyright (C) 1990, 1991, 1993 Andy C. Hung, all rights reserved. +PUBLIC DOMAIN LICENSE: Stanford University Portable Video Research +Group. If you use this software, you agree to the following: This +program package is purely experimental, and is licensed "as is". +Permission is granted to use, modify, and distribute this program +without charge for any purpose, provided this license/ disclaimer +notice appears in the copies. No warranty or maintenance is given, +either expressed or implied. In no event shall the author(s) be +liable to you or a third party for any special, incidental, +consequential, or other damages, arising out of the use or inability +to use the program for any purpose (or the loss of data), even if we +have been advised of such possibilities. Any public reference or +advertisement of this source code should refer to it as the Portable +Video Research Group (PVRG) code, and not by any author(s) (or +Stanford University) name. +*************************************************************/ +/* +************************************************************ +leedct.c + +This is the Byeong Gi Lee algorithm from IEEE Trans. Accoustics, +Speech, and Signal Processing, Vol ASSP-32, No. 6, December 1984, pp. +1243 -1245. + +************************************************************ +*/ + +/*LABEL leedct.c */ + +/*PUBLIC*/ + +extern void LeeIDct(); +extern void LeeDct(); + +/*PRIVATE*/ + +/* Standard Macros */ + +#define LS(r,s) ((r) << (s)) +#define RS(r,s) ((r) >> (s)) /* Caution with rounding... */ + +#define MSCALE(expr) RS((expr),9) + +#define IDCTSCALE(x) (((x<0) ? (x-8) : (x+8))/16); +#define DCTSCALE(x) (((x<0) ? (x-8) : (x+8))/16); + +/* Cos Table */ + +#define twoc1d4 724L +#define twoc1d8 946L +#define twoc3d8 392L +#define twoc1d16 1004L +#define twoc3d16 851L +#define twoc5d16 569L +#define twoc7d16 200L +#define sqrt2 724L + +/* 1/Cos Table */ + +#define itwoc1d4 362L +#define itwoc1d8 277L +#define itwoc3d8 669L +#define itwoc1d16 261L +#define itwoc3d16 308L +#define itwoc5d16 461L +#define itwoc7d16 1312L +#define isqrt2 362L + +#define x0 tx0 +#define x1 tx1 +#define x2 tx2 +#define x3 tx3 +#define x4 ex4 +#define x5 ex5 +#define x6 ex6 +#define x7 ex7 + +#define r0 rx0 +#define r1 rx1 +#define r2 rx2 +#define r3 rx3 + +#define s0 rx0 +#define s1 rx1 +#define s2 rx2 +#define s3 rx3 + +#define f0 ex0 +#define f1 ex1 +#define f2 ex2 +#define f3 ex3 + +#define g0 ex4 +#define g1 ex5 +#define g2 ex6 +#define g3 ex7 + +#define b1 gx0 +#define b2 gx0 +#define b3 gx1 + +#define a1 gx2 +#define a3 gx2 +#define c1 gx2 +#define c3 gx2 + +#define ihold gx1 + +/*START*/ + +/*BFUNC + +LeeIDct is implemented according to the inverse dct flow diagram in +the paper. It takes two input arrays that must be defined before the +call. + +EFUNC*/ + +void LeeIDct(x,y) + int *x; + int *y; +{ + register int ex0,ex1,ex2,ex3,ex4,ex5,ex6,ex7; + register int tx0,tx1,tx2,tx3; + register int rx0,rx1,rx2,rx3; + register int gx0,gx1,gx2; + register int *iptr,*jptr; + register int i; + + /* Do rows */ + + for(jptr=y,iptr=x,i=0;i<8;i++) + { + x0 = MSCALE(isqrt2*LS(*(iptr++),2)); + x1 = LS(*(iptr++),2); + x2 = LS(*(iptr++),2); + x3 = LS(*(iptr++),2); + x4 = LS(*(iptr++),2); + x5 = LS(*(iptr++),2); + x6 = LS(*(iptr++),2); + x7 = LS(*(iptr++),2); + + a1 = MSCALE(itwoc1d4*x4); + r0 = x0+a1; + r1 = x0-a1; + + a3 = MSCALE(itwoc1d4*(x2+x6)); + r2 = MSCALE(itwoc1d8*(x2+a3)); + r3 = MSCALE(itwoc3d8*(x2-a3)); + + f0 = r0+r2; + f1 = r1+r3; + f2 = r0-r2; + f3 = r1-r3; + + b1 = x3+x5; + c1 = MSCALE(itwoc1d4*b1); + s0 = x1+c1; + s1 = x1-c1; + + b2 = x1+x3; + b3 = x5+x7; + c3 = MSCALE(itwoc1d4*(b2+b3)); + s2 = MSCALE(itwoc1d8*(b2+c3)); + s3 = MSCALE(itwoc3d8*(b2-c3)); + + g0 = MSCALE(itwoc1d16*(s0+s2)); + g1 = MSCALE(itwoc3d16*(s1+s3)); + g2 = MSCALE(itwoc7d16*(s0-s2)); + g3 = MSCALE(itwoc5d16*(s1-s3)); + + *(jptr++) = f0+g0; + *(jptr++) = f1+g1; + *(jptr++) = f3+g3; + *(jptr++) = f2+g2; + + *(jptr++) = f2-g2; + *(jptr++) = f3-g3; + *(jptr++) = f1-g1; + *(jptr++) = f0-g0; + } + + + /* Do columns */ + + for(i=0;i<8;i++) + { + jptr = iptr = y+i; + + +#ifdef PVERSION + + x0 = MSCALE(isqrt2*(*(iptr))); + iptr += 8; + x1 = *(iptr); + iptr += 8; + x2 = *(iptr); + iptr += 8; + x3 = *(iptr); + iptr += 8; + x4 = *(iptr); + iptr += 8; + x5 = *(iptr); + iptr += 8; + x6 = *(iptr); + iptr += 8; + x7 = *(iptr); + +#else + +#undef x1 +#undef x2 +#undef x3 +#undef x4 +#undef x5 +#undef x6 +#undef x7 + +#define x1 iptr[8] +#define x2 iptr[16] +#define x3 iptr[24] +#define x4 iptr[32] +#define x5 iptr[40] +#define x6 iptr[48] +#define x7 iptr[56] + + x0 = MSCALE(isqrt2*(*iptr)); + +#endif + + a1 = MSCALE(itwoc1d4*x4); + r0 = x0+a1; + r1 = x0-a1; + + a3 = MSCALE(itwoc1d4*(x2+x6)); + r2 = MSCALE(itwoc1d8*(x2+a3)); + r3 = MSCALE(itwoc3d8*(x2-a3)); + + f0 = r0+r2; + f1 = r1+r3; + f2 = r0-r2; + f3 = r1-r3; + + b1 = x3+x5; + c1 = MSCALE(itwoc1d4*b1); + s0 = x1+c1; + s1 = x1-c1; + + b2 = x1+x3; + b3 = x5+x7; + c3 = MSCALE(itwoc1d4*(b2+b3)); + s2 = MSCALE(itwoc1d8*(b2+c3)); + s3 = MSCALE(itwoc3d8*(b2-c3)); + + g0 = MSCALE(itwoc1d16*(s0+s2)); + g1 = MSCALE(itwoc3d16*(s1+s3)); + g2 = MSCALE(itwoc7d16*(s0-s2)); + g3 = MSCALE(itwoc5d16*(s1-s3)); + + ihold = f0+g0; + (*jptr) = IDCTSCALE(ihold); + jptr += 8; + ihold = f1+g1; + (*jptr) = IDCTSCALE(ihold); + jptr += 8; + ihold = f3+g3; + (*jptr) = IDCTSCALE(ihold); + jptr += 8; + ihold = f2+g2; + (*jptr) = IDCTSCALE(ihold); + jptr += 8; + ihold = f2-g2; + (*jptr) = IDCTSCALE(ihold); + jptr += 8; + ihold = f3-g3; + (*jptr) = IDCTSCALE(ihold); + jptr += 8; + ihold = f1-g1; + (*jptr) = IDCTSCALE(ihold); + jptr += 8; + ihold = f0-g0; + (*jptr) = IDCTSCALE(ihold); + + } +} + +#undef f0 +#undef f1 +#undef f2 +#undef f3 + +#undef g0 +#undef g1 +#undef g2 +#undef g3 + +#undef r0 +#undef r1 +#undef r2 +#undef r3 + +#undef s0 +#undef s1 +#undef s2 +#undef s3 + +#define f0 rx0 +#define f1 rx1 +#define f2 rx2 +#define f3 rx3 + +#define r0 rx4 +#define r1 rx5 +#define r2 rx6 +#define r3 rx7 + +#define g0 sx0 +#define g1 sx1 +#define g2 sx2 +#define g3 sx3 + +#define s0 rx4 +#define s1 rx5 +#define s2 rx6 +#define s3 rx7 + + +/*BFUNC + +LeeDct is implemented by reversing the arrows in the inverse dct flow +diagram. It takes two input arrays that must be defined before the +call. + +EFUNC*/ + +void LeeDct(x,y) + int *x; + int *y; +{ + register int rx0,rx1,rx2,rx3,rx4,rx5,rx6,rx7; + register int sx0,sx1,sx2,sx3; + register int hold,c2; + register int *iptr,*jptr; + +#undef x0 +#undef x1 +#undef x2 +#undef x3 +#undef x4 +#undef x5 +#undef x6 +#undef x7 + +#define x0 iptr[0] +#define x1 iptr[1] +#define x2 iptr[2] +#define x3 iptr[3] +#define x4 iptr[4] +#define x5 iptr[5] +#define x6 iptr[6] +#define x7 iptr[7] + + for(jptr=y,iptr=x;iptr 0 +#define FLEX_BETA +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include +#include +#include +#include + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have . Non-C99 systems may or may not. */ + +#if __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; +#endif /* ! C99 */ + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#endif /* ! FLEXINT_H */ + +#ifdef __cplusplus + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +#if __STDC__ + +#define YY_USE_CONST + +#endif /* __STDC__ */ +#endif /* ! __cplusplus */ + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index. If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN (yy_start) = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START (((yy_start) - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart(yyin ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#define YY_BUF_SIZE 16384 +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +extern int yyleng; + +extern FILE *yyin, *yyout; + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + /* Note: We specifically omit the test for yy_rule_can_match_eol because it requires + * access to the local variable yy_act. Since yyless() is a macro, it would break + * existing scanners that call yyless() from OUTSIDE yylex. + * One obvious solution it to make yy_act a global. I tried that, and saw + * a 5% performance hit in a non-yylineno scanner, because yy_act is + * normally declared as a register variable-- so it is not worth it. + */ + #define YY_LESS_LINENO(n) \ + do { \ + int yyl;\ + for ( yyl = n; yyl < yyleng; ++yyl )\ + if ( yytext[yyl] == '\n' )\ + --yylineno;\ + }while(0) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = (yy_hold_char); \ + YY_RESTORE_YY_MORE_OFFSET \ + (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) + +#define unput(c) yyunput( c, (yytext_ptr) ) + +/* The following is because we cannot portably get our hands on size_t + * (without autoconf's help, which isn't available because we want + * flex-generated scanners to compile on their own). + */ + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef unsigned int yy_size_t; +#endif + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* Stack of input buffers. */ +static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ +static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ +static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ + ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ + : NULL) + +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] + +/* yy_hold_char holds the character lost when yytext is formed. */ +static char yy_hold_char; +static int yy_n_chars; /* number of characters read into yy_ch_buf */ +int yyleng; + +/* Points to current character in buffer. */ +static char *yy_c_buf_p = (char *) 0; +static int yy_init = 0; /* whether we need to initialize */ +static int yy_start = 0; /* start state number */ + +/* Flag which is used to allow yywrap()'s to do buffer switches + * instead of setting up a fresh yyin. A bit of a hack ... + */ +static int yy_did_buffer_switch_on_eof; + +void yyrestart (FILE *input_file ); +void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ); +YY_BUFFER_STATE yy_create_buffer (FILE *file,int size ); +void yy_delete_buffer (YY_BUFFER_STATE b ); +void yy_flush_buffer (YY_BUFFER_STATE b ); +void yypush_buffer_state (YY_BUFFER_STATE new_buffer ); +void yypop_buffer_state (void ); + +static void yyensure_buffer_stack (void ); +static void yy_load_buffer_state (void ); +static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ); + +#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ) + +YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ); +YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ); +YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len ); + +void *yyalloc (yy_size_t ); +void *yyrealloc (void *,yy_size_t ); +void yyfree (void * ); + +#define yy_new_buffer yy_create_buffer + +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + yyensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer(yyin,YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } + +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + yyensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer(yyin,YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +/* Begin user sect3 */ + +typedef unsigned char YY_CHAR; + +FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; + +typedef int yy_state_type; + +extern int yylineno; + +int yylineno = 1; + +extern char *yytext; +#define yytext_ptr yytext + +static yy_state_type yy_get_previous_state (void ); +static yy_state_type yy_try_NUL_trans (yy_state_type current_state ); +static int yy_get_next_buffer (void ); +static void yy_fatal_error (yyconst char msg[] ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + (yytext_ptr) = yy_bp; \ + yyleng = (size_t) (yy_cp - yy_bp); \ + (yy_hold_char) = *yy_cp; \ + *yy_cp = '\0'; \ + (yy_c_buf_p) = yy_cp; + +#define YY_NUM_RULES 18 +#define YY_END_OF_BUFFER 19 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static yyconst flex_int16_t yy_accept[73] = + { 0, + 0, 0, 0, 0, 0, 0, 19, 18, 16, 1, + 1, 16, 12, 16, 12, 12, 4, 4, 4, 12, + 12, 12, 2, 2, 10, 11, 17, 17, 17, 1, + 0, 13, 0, 0, 0, 12, 3, 14, 3, 4, + 4, 0, 8, 0, 6, 8, 0, 8, 2, 2, + 2, 15, 13, 9, 0, 0, 3, 0, 0, 3, + 7, 5, 0, 0, 3, 0, 0, 3, 3, 0, + 3, 0 + } ; + +static yyconst flex_int32_t yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 1, 4, 5, 1, 1, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, 17, 17, + 17, 17, 17, 17, 17, 18, 18, 19, 20, 21, + 22, 23, 1, 1, 24, 25, 25, 24, 26, 24, + 27, 28, 27, 27, 27, 27, 27, 27, 29, 27, + 27, 27, 27, 27, 27, 27, 27, 30, 27, 27, + 31, 32, 33, 34, 1, 1, 24, 25, 25, 24, + + 24, 24, 27, 28, 27, 27, 27, 27, 27, 27, + 29, 27, 27, 27, 27, 27, 27, 27, 27, 30, + 27, 27, 35, 36, 37, 38, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static yyconst flex_int32_t yy_meta[39] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, + 1, 1, 1, 2, 2, 2, 3, 4, 3, 3, + 1, 1, 1, 1, 1, 1, 1, 1 + } ; + +static yyconst flex_int16_t yy_base[80] = + { 0, + 0, 0, 0, 0, 29, 30, 122, 207, 207, 39, + 44, 39, 207, 84, 34, 105, 58, 24, 39, 89, + 35, 88, 73, 0, 207, 207, 207, 81, 82, 57, + 45, 207, 61, 73, 78, 207, 88, 207, 91, 0, + 0, 45, 42, 107, 207, 45, 0, 207, 0, 0, + 0, 207, 81, 207, 62, 123, 111, 131, 134, 108, + 50, 0, 138, 140, 143, 151, 154, 157, 160, 163, + 166, 207, 184, 188, 192, 196, 199, 202, 61 + } ; + +static yyconst flex_int16_t yy_def[80] = + { 0, + 73, 73, 72, 3, 74, 74, 72, 72, 72, 72, + 72, 75, 72, 76, 72, 72, 72, 17, 18, 72, + 72, 72, 72, 77, 72, 72, 72, 72, 72, 72, + 75, 72, 75, 72, 72, 72, 72, 72, 72, 18, + 19, 78, 78, 72, 72, 72, 79, 72, 23, 77, + 77, 72, 75, 72, 72, 72, 72, 72, 72, 44, + 72, 79, 72, 72, 72, 72, 72, 72, 72, 72, + 72, 0, 72, 72, 72, 72, 72, 72, 72 + } ; + +static yyconst flex_int16_t yy_nxt[246] = + { 0, + 9, 10, 11, 12, 13, 13, 14, 13, 13, 13, + 13, 13, 13, 15, 16, 17, 18, 19, 20, 13, + 21, 13, 22, 23, 23, 23, 24, 24, 24, 24, + 25, 9, 26, 13, 13, 13, 13, 13, 28, 28, + 30, 30, 32, 29, 29, 30, 30, 36, 32, 37, + 37, 37, 48, 72, 41, 41, 36, 36, 30, 30, + 61, 61, 62, 42, 53, 61, 61, 72, 54, 45, + 33, 39, 45, 40, 40, 41, 33, 63, 63, 54, + 34, 42, 43, 44, 32, 45, 46, 47, 49, 49, + 49, 38, 33, 55, 55, 52, 49, 49, 49, 50, + + 51, 50, 50, 37, 37, 37, 57, 57, 57, 36, + 36, 34, 33, 56, 38, 35, 58, 59, 72, 59, + 72, 72, 60, 60, 60, 72, 57, 57, 57, 72, + 42, 42, 42, 64, 45, 64, 66, 72, 65, 65, + 65, 67, 72, 67, 54, 72, 68, 68, 68, 69, + 69, 69, 72, 34, 34, 65, 65, 65, 65, 65, + 65, 70, 72, 70, 72, 72, 71, 71, 71, 68, + 68, 68, 68, 68, 68, 69, 69, 69, 71, 71, + 71, 71, 71, 71, 8, 8, 8, 8, 27, 27, + 27, 27, 31, 31, 31, 31, 34, 34, 34, 34, + + 50, 50, 50, 42, 72, 42, 7, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72 + } ; + +static yyconst flex_int16_t yy_chk[246] = + { 0, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 5, 6, + 10, 10, 12, 5, 6, 11, 11, 15, 31, 15, + 15, 15, 18, 18, 19, 19, 21, 21, 30, 30, + 46, 46, 79, 19, 33, 61, 61, 19, 55, 43, + 12, 17, 42, 17, 17, 17, 31, 55, 55, 34, + 35, 17, 17, 17, 53, 17, 17, 17, 23, 23, + 23, 29, 33, 35, 35, 28, 23, 23, 23, 23, + + 23, 23, 23, 37, 37, 37, 39, 39, 39, 22, + 20, 35, 53, 37, 16, 14, 39, 44, 60, 44, + 60, 7, 44, 44, 44, 0, 57, 57, 57, 0, + 44, 44, 44, 56, 44, 56, 57, 0, 56, 56, + 56, 58, 0, 58, 63, 0, 58, 58, 58, 59, + 59, 59, 0, 63, 63, 64, 64, 64, 65, 65, + 65, 66, 0, 66, 0, 0, 66, 66, 66, 67, + 67, 67, 68, 68, 68, 69, 69, 69, 70, 70, + 70, 71, 71, 71, 73, 73, 73, 73, 74, 74, + 74, 74, 75, 75, 75, 75, 76, 76, 76, 76, + + 77, 77, 77, 78, 0, 78, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72 + } ; + +/* Table of booleans, true if rule could match eol. */ +static yyconst flex_int32_t yy_rule_can_match_eol[19] = + { 0, +1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, }; + +static yy_state_type yy_last_accepting_state; +static char *yy_last_accepting_cpos; + +extern int yy_flex_debug; +int yy_flex_debug = 0; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +char *yytext; +#line 1 "lexer.l" +/************************************************************* +Copyright (C) 1990, 1991, 1993 Andy C. Hung, all rights reserved. +PUBLIC DOMAIN LICENSE: Stanford University Portable Video Research +Group. If you use this software, you agree to the following: This +program package is purely experimental, and is licensed "as is". +Permission is granted to use, modify, and distribute this program +without charge for any purpose, provided this license/ disclaimer +notice appears in the copies. No warranty or maintenance is given, +either expressed or implied. In no event shall the author(s) be +liable to you or a third party for any special, incidental, +consequential, or other damages, arising out of the use or inability +to use the program for any purpose (or the loss of data), even if we +have been advised of such possibilities. Any public reference or +advertisement of this source code should refer to it as the Portable +Video Research Group (PVRG) code, and not by any author(s) (or +Stanford University) name. +*************************************************************/ +#line 20 "lexer.l" + +/*LABEL lexer.c */ + +/* + * flex command was run this way: + * + * $ lex -olexer.c lexer.l + */ + +/* We do not care of interactive mode */ +#define YY_NEVER_INTERACTIVE 1 +#define YY_NO_UNPUT 1 + +/* Do not include unistd.h in generated source. */ +#define YY_NO_UNISTD_H + +/* Skip declaring this function. It is a macro. */ +#define YY_SKIP_YYWRAP + +/* Redefine the yywrap so that we don't have + to worry about lex library */ + +# define yywrap() (1) + +static char *ReservedWords[] = { /* Token names */ +"COMPONENT", +"SCAN", +"QUANTIZATION", +"DCSPEC", +"ACCUSTOM", +"DCCUSTOM", +"PRINTSCAN", +"PRINTFRAME", +"PRINTIMAGE", +"OPENSCAN", +"ACSPEC", +"WRITESCAN", +"WRITEFRAME", +"WRITESOI", +"WRITEQUANTIZATION", +"WRITERESYNC", +"WRITEHUFFMAN", +"FREQUENCY", +"ACSEND", +"DCSEND", +"QSEND", +"STREAMNAME", +"IMAGEHEIGHT", +"IMAGEWIDTH", +"RESYNC", +"BUFFER", +"OPENSTREAM", +"CLOSESTREAM", +"FRAMEHEIGHT", +"FRAMEWIDTH", +"CLOSESCAN", +"WRITEEOI", +"ECHO", +"WRITESPECIAL", +"WRITEDIRECT", +"LUMINANCEDEFAULT", +"CHROMINANCEDEFAULT", +"ENABLE", +"SCANDNL", +"WRITEDNL", +"AUTO", +"EMPTY", +""}; + +#define R_COMPONENT 1 /* Token values mapped to token names */ +#define R_SCAN 2 +#define R_QUANTIZATION 3 +#define R_DCSPEC 4 +#define R_ACCUSTOM 5 +#define R_DCCUSTOM 6 +#define R_PRINTSCAN 7 +#define R_PRINTFRAME 8 +#define R_PRINTIMAGE 9 +#define R_OPENSCAN 10 +#define R_ACSPEC 11 +#define R_WRITESCAN 12 +#define R_WRITEFRAME 13 +#define R_WRITESOI 14 +#define R_WRITEQUANTIZATION 15 +#define R_WRITERESYNC 16 +#define R_WRITEHUFFMAN 17 +#define R_FREQUENCY 18 +#define R_ACSEND 19 +#define R_DCSEND 20 +#define R_QSEND 21 +#define R_STREAMNAME 22 +#define R_IMAGEHEIGHT 23 +#define R_IMAGEWIDTH 24 +#define R_RESYNC 25 +#define R_BUFFER 26 +#define R_OPENSTREAM 27 +#define R_CLOSESTREAM 28 +#define R_FRAMEHEIGHT 29 +#define R_FRAMEWIDTH 30 +#define R_CLOSESCAN 31 +#define R_WRITEEOI 32 +#define R_ECHO 33 +#define R_WRITESPECIAL 34 +#define R_WRITEDIRECT 35 +#define R_LUMINANCEDEFAULT 36 +#define R_CHROMINANCEDEFAULT 37 +#define R_ENABLE 38 +#define R_SCANDNL 39 +#define R_WRITEDNL 40 +#define R_AUTO 41 +#define R_EMPTY 42 + +#define R_INTEGER 1000 /* Special TYPES for tokens */ +#define R_LBRACKET 1001 +#define R_RBRACKET 1002 +#define R_ID 1003 +#define R_STRING 1004 + +int CommentDepth = 0; /* depth of comment nesting */ +int yyint=0; /* Return value for integers */ +int LexDebug=0; /* Status of lex debugging */ + +#define PRIME 211 +#define EOS '\0' + +#define MakeStructure(S) (S *) malloc(sizeof(S)) +#define InsertLink(link,list){\ +if(!list){list=link;}else{link->next=list;list=link;}} + +#define LINK struct link_def +struct id { /* Default id structure */ + char *name; /* Key */ + int tokentype; /* Token type */ + int count; /* Count of # references */ +}; + +LINK { /* A link for the hash buckets */ +struct id *lid; /* Current id */ +LINK *next; /* Pointer to next id */ +}; + +/*PUBLIC*/ + +extern void initparser(); +extern void parser(); + +static int hashpjw(); +static LINK * MakeLink(); +static struct id * enter(); +static int getint(); +static char * getstr(); + +/*PRIVATE*/ + +/*NOPROTO*/ + + +#line 723 "lexer.c" + +#define INITIAL 0 +#define NORMAL 1 +#define COMMENT 2 + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +static int yy_init_globals (void ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap (void ); +#else +extern int yywrap (void ); +#endif +#endif + + static void yyunput (int c,char *buf_ptr ); + +#ifndef yytext_ptr +static void yy_flex_strncpy (char *,yyconst char *,int ); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * ); +#endif + +#ifndef YY_NO_INPUT + +#ifdef __cplusplus +static int yyinput (void ); +#else +static int input (void ); +#endif + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 8192 +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO (void) fwrite( yytext, yyleng, 1, yyout ) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ + size_t n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else \ + { \ + errno=0; \ + while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(yyin); \ + } \ + }\ +\ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int yylex (void); + +#define YY_DECL int yylex (void) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + register yy_state_type yy_current_state; + register char *yy_cp, *yy_bp; + register int yy_act; + +#line 200 "lexer.l" + + +#line 881 "lexer.c" + + if ( !(yy_init) ) + { + (yy_init) = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! (yy_start) ) + (yy_start) = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! YY_CURRENT_BUFFER ) { + yyensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer(yyin,YY_BUF_SIZE ); + } + + yy_load_buffer_state( ); + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + yy_cp = (yy_c_buf_p); + + /* Support of yytext. */ + *yy_cp = (yy_hold_char); + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = (yy_start); +yy_match: + do + { + register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 73 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + ++yy_cp; + } + while ( yy_base[yy_current_state] != 207 ); + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + if ( yy_act == 0 ) + { /* have to back up */ + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); + yy_act = yy_accept[yy_current_state]; + } + + YY_DO_BEFORE_ACTION; + + if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] ) + { + int yyl; + for ( yyl = 0; yyl < yyleng; ++yyl ) + if ( yytext[yyl] == '\n' ) + + yylineno++; +; + } + +do_action: /* This label is used only to access EOF actions. */ + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = (yy_hold_char); + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); + goto yy_find_action; + +case 1: +/* rule 1 can match eol */ +YY_RULE_SETUP +#line 202 "lexer.l" +{} + YY_BREAK +case 2: +YY_RULE_SETUP +#line 204 "lexer.l" +{struct id *temp; temp = enter(0,yytext,yyleng); + if (LexDebug) + { + printf("%s : %s (%d)\n", + yytext, + ((temp->tokentype) ? "RESERVED" : "IDENTIFIER"), + temp->count); + } + if (temp->tokentype) + { + return(temp->tokentype); + } + else + { + return(R_ID); + } + } + YY_BREAK +case 3: +YY_RULE_SETUP +#line 221 "lexer.l" +{if (LexDebug) + { + printf("%s : %s\n", yytext, "REAL"); + } + } + YY_BREAK +case 4: +YY_RULE_SETUP +#line 226 "lexer.l" +{if (LexDebug) + { + printf("%s : %s\n", yytext, "INTEGER"); + } + yyint = atoi(yytext); + return(R_INTEGER);} + YY_BREAK +case 5: +YY_RULE_SETUP +#line 232 "lexer.l" +{if (LexDebug) + { + printf("%s : %s\n", yytext, "(HEX)INTEGER"); + } + yyint = strtol(yytext+2,NULL,16); + return(R_INTEGER);} + YY_BREAK +case 6: +YY_RULE_SETUP +#line 238 "lexer.l" +{if (LexDebug) + { + printf("%s : %s\n", yytext, "(HEX)INTEGER"); + } + yyint = strtol(yytext,NULL,16); + return(R_INTEGER);} + YY_BREAK +case 7: +YY_RULE_SETUP +#line 244 "lexer.l" +{if (LexDebug) + { + printf("%s : %s\n", yytext, "(OCT)INTEGER"); + } + yyint = strtol(yytext+2,NULL,8); + return(R_INTEGER);} + YY_BREAK +case 8: +YY_RULE_SETUP +#line 250 "lexer.l" +{if (LexDebug) + { + printf("%s : %s\n", yytext, "(OCT)INTEGER"); + } + yyint = strtol(yytext,NULL,8); + return(R_INTEGER);} + YY_BREAK +case 9: +/* rule 9 can match eol */ +YY_RULE_SETUP +#line 256 "lexer.l" +{if (LexDebug) + { + printf("%s : %s\n", yytext, "(CHAR)INTEGER"); + } + if (yyleng>4) + { + yyint = strtol(yytext+2,NULL,8); + } + else + { + if (*(yytext+1)=='\\') + { + switch(*(yytext+2)) + { + case '0': + yyint=0; + break; + case 'b': + yyint = 0x8; + break; + case 'i': + yyint = 0x9; + break; + case 'n': + yyint = 0xa; + break; + case 'v': + yyint = 0xb; + break; + case 'f': + yyint = 0xc; + break; + case 'r': + yyint = 0xd; + break; + default: + yyint=(*yytext+2); + break; + } + } + else + { + yyint = *(yytext+1); + } + } + return(R_INTEGER);} + YY_BREAK +case 10: +YY_RULE_SETUP +#line 302 "lexer.l" +{if (LexDebug) + { + printf("%s : %s\n", yytext, "LBRACKET"); + } + return(R_LBRACKET);} + YY_BREAK +case 11: +YY_RULE_SETUP +#line 307 "lexer.l" +{if (LexDebug) + { + printf("%s : %s\n", yytext, "RBRACKET"); + } + return(R_RBRACKET);} + YY_BREAK +case 12: +YY_RULE_SETUP +#line 312 "lexer.l" +{if (LexDebug) + { + printf("%s : %s\n", yytext, "OPERATOR"); + } + } + YY_BREAK +case 13: +/* rule 13 can match eol */ +YY_RULE_SETUP +#line 317 "lexer.l" +{if (LexDebug) + { + printf("%s : %s\n", yytext, "STRING"); + } + return(R_STRING);} + YY_BREAK +case 14: +YY_RULE_SETUP +#line 323 "lexer.l" +{CommentDepth++; BEGIN COMMENT;} + YY_BREAK +case 15: +YY_RULE_SETUP +#line 325 "lexer.l" +{CommentDepth--;if(!CommentDepth) BEGIN NORMAL;} + YY_BREAK +case 16: +YY_RULE_SETUP +#line 327 "lexer.l" +{ + /* None of the above rules applicable, so + it's a bad symbol. */ + printf("Bad input char '%c' on line %d\n", + yytext[0], + yylineno); + } + YY_BREAK +case 17: +/* rule 17 can match eol */ +YY_RULE_SETUP +#line 335 "lexer.l" +{} /*Everything's AOK */ + YY_BREAK +case 18: +YY_RULE_SETUP +#line 337 "lexer.l" +ECHO; + YY_BREAK +#line 1180 "lexer.c" +case YY_STATE_EOF(INITIAL): +case YY_STATE_EOF(NORMAL): +case YY_STATE_EOF(COMMENT): + yyterminate(); + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = (yy_hold_char); + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state ); + + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++(yy_c_buf_p); + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = (yy_c_buf_p); + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( ) ) + { + case EOB_ACT_END_OF_FILE: + { + (yy_did_buffer_switch_on_eof) = 0; + + if ( yywrap( ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + (yy_c_buf_p) = + (yytext_ptr) + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( ); + + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + (yy_c_buf_p) = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; + + yy_current_state = yy_get_previous_state( ); + + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ +} /* end of yylex */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer (void) +{ + register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + register char *source = (yytext_ptr); + register int number_to_move, i; + int ret_val; + + if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; + + else + { + int num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = YY_CURRENT_BUFFER; + + int yy_c_buf_p_offset = + (int) ((yy_c_buf_p) - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = 0; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - + number_to_move - 1; + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + (yy_n_chars), (size_t) num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + if ( (yy_n_chars) == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart(yyin ); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + (yy_n_chars) += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; + + (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + + static yy_state_type yy_get_previous_state (void) +{ + register yy_state_type yy_current_state; + register char *yy_cp; + + yy_current_state = (yy_start); + + for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) + { + register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 73 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) +{ + register int yy_is_jam; + register char *yy_cp = (yy_c_buf_p); + + register YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 73 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_is_jam = (yy_current_state == 72); + + return yy_is_jam ? 0 : yy_current_state; +} + + static void yyunput (int c, register char * yy_bp ) +{ + register char *yy_cp; + + yy_cp = (yy_c_buf_p); + + /* undo effects of setting up yytext */ + *yy_cp = (yy_hold_char); + + if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) + { /* need to shift things up to make room */ + /* +2 for EOB chars. */ + register int number_to_move = (yy_n_chars) + 2; + register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ + YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; + register char *source = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; + + while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + *--dest = *--source; + + yy_cp += (int) (dest - source); + yy_bp += (int) (dest - source); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size; + + if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) + YY_FATAL_ERROR( "flex scanner push-back overflow" ); + } + + *--yy_cp = (char) c; + + if ( c == '\n' ){ + --yylineno; + } + + (yytext_ptr) = yy_bp; + (yy_hold_char) = *yy_cp; + (yy_c_buf_p) = yy_cp; +} + +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static int yyinput (void) +#else + static int input (void) +#endif + +{ + int c; + + *(yy_c_buf_p) = (yy_hold_char); + + if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + /* This was really a NUL. */ + *(yy_c_buf_p) = '\0'; + + else + { /* need more input */ + int offset = (yy_c_buf_p) - (yytext_ptr); + ++(yy_c_buf_p); + + switch ( yy_get_next_buffer( ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart(yyin ); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap( ) ) + return EOF; + + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(); +#else + return input(); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + (yy_c_buf_p) = (yytext_ptr) + offset; + break; + } + } + } + + c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ + *(yy_c_buf_p) = '\0'; /* preserve yytext */ + (yy_hold_char) = *++(yy_c_buf_p); + + if ( c == '\n' ) + + yylineno++; +; + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * + * @note This function does not reset the start condition to @c INITIAL . + */ + void yyrestart (FILE * input_file ) +{ + + if ( ! YY_CURRENT_BUFFER ){ + yyensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer(yyin,YY_BUF_SIZE ); + } + + yy_init_buffer(YY_CURRENT_BUFFER,input_file ); + yy_load_buffer_state( ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * + */ + void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ) +{ + + /* TODO. We should be able to replace this entire function body + * with + * yypop_buffer_state(); + * yypush_buffer_state(new_buffer); + */ + yyensure_buffer_stack (); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + yy_load_buffer_state( ); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + (yy_did_buffer_switch_on_eof) = 1; +} + +static void yy_load_buffer_state (void) +{ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + (yy_hold_char) = *(yy_c_buf_p); +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * + * @return the allocated buffer state. + */ + YY_BUFFER_STATE yy_create_buffer (FILE * file, int size ) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer(b,file ); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with yy_create_buffer() + * + */ + void yy_delete_buffer (YY_BUFFER_STATE b ) +{ + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yyfree((void *) b->yy_ch_buf ); + + yyfree((void *) b ); +} + +#ifndef __cplusplus +extern int isatty (int ); +#endif /* __cplusplus */ + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a yyrestart() or at EOF. + */ + static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file ) + +{ + int oerrno = errno; + + yy_flush_buffer(b ); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then yy_init_buffer was _probably_ + * called from yyrestart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + + b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; + + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * + */ + void yy_flush_buffer (YY_BUFFER_STATE b ) +{ + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + yy_load_buffer_state( ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * + */ +void yypush_buffer_state (YY_BUFFER_STATE new_buffer ) +{ + if (new_buffer == NULL) + return; + + yyensure_buffer_stack(); + + /* This block is copied from yy_switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + (yy_buffer_stack_top)++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from yy_switch_to_buffer. */ + yy_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * + */ +void yypop_buffer_state (void) +{ + if (!YY_CURRENT_BUFFER) + return; + + yy_delete_buffer(YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + if ((yy_buffer_stack_top) > 0) + --(yy_buffer_stack_top); + + if (YY_CURRENT_BUFFER) { + yy_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void yyensure_buffer_stack (void) +{ + int num_to_alloc; + + if (!(yy_buffer_stack)) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; + (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + ); + + memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + (yy_buffer_stack_max) = num_to_alloc; + (yy_buffer_stack_top) = 0; + return; + } + + if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + int grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = (yy_buffer_stack_max) + grow_size; + (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc + ((yy_buffer_stack), + num_to_alloc * sizeof(struct yy_buffer_state*) + ); + + /* zero only the new slots.*/ + memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); + (yy_buffer_stack_max) = num_to_alloc; + } +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return 0; + + b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + + b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = 0; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer(b ); + + return b; +} + +/** Setup the input buffer state to scan a string. The next call to yylex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + * + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * yy_scan_bytes() instead. + */ +YY_BUFFER_STATE yy_scan_string (yyconst char * yystr ) +{ + + return yy_scan_bytes(yystr,strlen(yystr) ); +} + +/** Setup the input buffer state to scan the given bytes. The next call to yylex() will + * scan from a @e copy of @a bytes. + * @param bytes the byte buffer to scan + * @param len the number of bytes in the buffer pointed to by @a bytes. + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len ) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = _yybytes_len + 2; + buf = (char *) yyalloc(n ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; + + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer(buf,n ); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void yy_fatal_error (yyconst char* msg ) +{ + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + yytext[yyleng] = (yy_hold_char); \ + (yy_c_buf_p) = yytext + yyless_macro_arg; \ + (yy_hold_char) = *(yy_c_buf_p); \ + *(yy_c_buf_p) = '\0'; \ + yyleng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/** Get the current line number. + * + */ +int yyget_lineno (void) +{ + + return yylineno; +} + +/** Get the input stream. + * + */ +FILE *yyget_in (void) +{ + return yyin; +} + +/** Get the output stream. + * + */ +FILE *yyget_out (void) +{ + return yyout; +} + +/** Get the length of the current token. + * + */ +int yyget_leng (void) +{ + return yyleng; +} + +/** Get the current token. + * + */ + +char *yyget_text (void) +{ + return yytext; +} + +/** Set the current line number. + * @param line_number + * + */ +void yyset_lineno (int line_number ) +{ + + yylineno = line_number; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param in_str A readable stream. + * + * @see yy_switch_to_buffer + */ +void yyset_in (FILE * in_str ) +{ + yyin = in_str ; +} + +void yyset_out (FILE * out_str ) +{ + yyout = out_str ; +} + +int yyget_debug (void) +{ + return yy_flex_debug; +} + +void yyset_debug (int bdebug ) +{ + yy_flex_debug = bdebug ; +} + +static int yy_init_globals (void) +{ + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from yylex_destroy(), so don't allocate here. + */ + + /* We do not touch yylineno unless the option is enabled. */ + yylineno = 1; + + (yy_buffer_stack) = 0; + (yy_buffer_stack_top) = 0; + (yy_buffer_stack_max) = 0; + (yy_c_buf_p) = (char *) 0; + (yy_init) = 0; + (yy_start) = 0; + +/* Defined in main.c */ +#ifdef YY_STDINIT + yyin = stdin; + yyout = stdout; +#else + yyin = (FILE *) 0; + yyout = (FILE *) 0; +#endif + + /* For future reference: Set errno on error, since we are called by + * yylex_init() + */ + return 0; +} + +/* yylex_destroy is for both reentrant and non-reentrant scanners. */ +int yylex_destroy (void) +{ + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + yy_delete_buffer(YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + yypop_buffer_state(); + } + + /* Destroy the stack itself. */ + yyfree((yy_buffer_stack) ); + (yy_buffer_stack) = NULL; + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * yylex() is called, initialization will occur. */ + yy_init_globals( ); + + return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) +{ + register int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * s ) +{ + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *yyalloc (yy_size_t size ) +{ + return (void *) malloc( size ); +} + +void *yyrealloc (void * ptr, yy_size_t size ) +{ + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return (void *) realloc( (char *) ptr, size ); +} + +void yyfree (void * ptr ) +{ + free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +#line 337 "lexer.l" + + + +/*PROTO*/ +LINK *HashTable[PRIME]; /* My little hash table */ + +/*START*/ + +/*BFUNC + +initparser() is used to place the Reserved Words into the hash table. +It must be called before the parser command is called. + +EFUNC*/ + +void initparser() +{ + char i,**sptr; + BEGIN NORMAL; + + for(i=1,sptr=ReservedWords;**sptr!='\0';i++,sptr++) + { /* Add Reserved Words */ + enter(i,*sptr,strlen(*sptr)); /* Put reserved words in */ + } /* hash table */ +} + +#undef BEGIN +#undef MakeStructure +#include "globals.h" +#include "stream.h" +#include "tables.h" + +extern FRAME *CFrame; +extern IMAGE *CImage; +extern SCAN *CScan; +extern int ErrorValue; + +/*BFUNC + +hashpjw() returns a hash value for a string input. + +EFUNC*/ + +static int hashpjw(s) + char *s; +{ + BEGIN("hashpjw") + char *p; + unsigned int g, h; + h=0; + + for(p=s;*p!=EOS;p++) /* Taken from Aho Sethi Ullman Compilers book. */ + { + h = (h << 4) + *p; + if ((g = h&0xf0000000)) + { + h = h ^(g >> 24); + h = h ^ g; + } + } + return(h % PRIME); +} + +/*BFUNC + +MakeLink() is used to construct a link object. The link +is used for the hash table construct. + +EFUNC*/ + + +static LINK *MakeLink(tokentype,str,len) + int tokentype; + char *str; + int len; +{ + BEGIN("MakeLink") + LINK *temp; + + if (!(temp = MakeStructure(LINK))) /* Make link */ + { + WHEREAMI(); + printf("Cannot make a LINK.\n"); + exit(ERROR_MEMORY); + } + if (!(temp->lid = MakeStructure(struct id))) /* Make id */ + { + printf("Cannot make an id.\n"); + exit(ERROR_MEMORY); + } + temp->next = NULL; /* Set fields */ + if (!(temp->lid->name =(char *)calloc(len+1,sizeof(char)))) + { + printf("Cannot make a string space for the link.\n"); + exit(ERROR_MEMORY); + } + strcpy(temp->lid->name,str); /* Copy key */ + temp->lid->tokentype = tokentype; + temp->lid->count = 1; + return(temp); +} + +/*BFUNC + +enter() is used to enter a Reserved Word or ID into the hash table. + +EFUNC*/ + +static struct id *enter(tokentype,str,len) + int tokentype; + char *str; + int len; +{ + BEGIN("enter") + int hashnum; + LINK *temp,*current; + char *ptr; + + for(ptr=str;*ptr!='\0';ptr++) /* All capitals is fine */ + { + if ((*ptr>='a') && (*ptr<='z')) + { + *ptr = *ptr - ('a'-'A'); + } + } + hashnum = hashpjw(str); /* Check if in hash table */ + for(temp=NULL,current=HashTable[hashnum]; + current!= NULL; + current=current->next) + { + if (strcmp(str,current->lid->name) == 0) + { + temp=current; + break; + } + } + if (temp) /* Yes, found ID then return */ + { + temp->lid->count++; + return(temp->lid); + } + else /* Else make our own ID and return that*/ + { + temp = MakeLink(tokentype,str,len); + InsertLink(temp,HashTable[hashnum]); + return(temp->lid); + } +} + +/*BFUNC + +getint() takes an integer from the input. + +EFUNC*/ + +static int getint() +{ + BEGIN("getint") + int type; + if ((type=yylex())!=R_INTEGER) + { + printf("Bad input, not integer, '%s' on line %d\n", + yytext, + yylineno); + return(0); + } + return(yyint); +} + +/*BFUNC + +getstr() gets a string from the input. It copies the string to +temporary storage before it returns the pointer. + +EFUNC*/ + +static char *getstr() +{ + BEGIN("getstr") + char *tmp,*ptr,*bptr; + int i,accum,flag; + if (yylex() != R_STRING) /* Check if string */ + { + printf("String expected.\n"); + if (!(tmp=(char *) malloc(sizeof(char)))) + { + WHEREAMI(); + printf("Cannot allocate for null string.\n"); + exit(ERROR_MEMORY); + } + *tmp='\0'; + return(tmp); + } + if (!(tmp=(char *)calloc(strlen(yytext)+1,sizeof(char)))) /* Make space */ + { + WHEREAMI(); + printf("Cannot allocate %d string space.\n",yyleng); + exit(ERROR_MEMORY); + } + for(bptr=yytext+1,ptr=tmp;*bptr!='"';bptr++,ptr++) /* Copy to string */ + { + if (*bptr=='\\') + { + bptr++; + for(flag=0,accum=0,i=0;i<3;i++) /* Octal character lookahead */ + { + if ((*bptr>='0')&&(*bptr<='7')) + { + accum = (accum<<3)+(*bptr-'0'); + bptr++; + flag=1; + } + else + { + break; + } + } + if (flag) + { + bptr--; + *ptr=accum; + } + else /* Do conversions, if necessary */ + { + switch(*(bptr)) + { + case '0': + *ptr = 0; + break; + case 'b': + *ptr = 0x8; + break; + case 'i': + *ptr = 0x9; + break; + case 'n': + *ptr = 0xa; + break; + case 'v': + *ptr = 0xb; + break; + case 'f': + *ptr = 0xc; + break; + case 'r': + *ptr = 0xd; + break; + default: + *ptr=(*bptr); + } + } + } + else + { + *ptr = (*bptr); + } + } + *ptr='\0'; + return(tmp); +} + +/*BFUNC + +parser() handles all of the parsing required for the Command +Interpreter. It is basically a while statement with a very large case +statement for every input. The Command Interpreter is essentially +driven by the keywords. All unmatched values such as integers, +strings, and brackets, are ignored. + +EFUNC*/ + +#define ARRAYBEGIN if (ntoken==R_LBRACKET)\ + {\ + arrayflag=1;\ + ntoken=yylex();\ + }\ + if (ntoken!=R_INTEGER)\ + {\ + WHEREAMI();\ + printf("Expected integer.\n");\ + break;\ + }\ + while(1)\ + { + +#define ARRAYEND if (arrayflag)\ + {\ + if ((ntoken=yylex())==R_RBRACKET) break;\ + else if (ntoken!=R_INTEGER)\ + {\ + WHEREAMI();\ + printf("Expected integer or right bracket.\n");\ + break;\ + }\ + }\ + else break;\ + } + +void parser() +{ + BEGIN("parser") + int i,dest,value,token,ntoken,arrayflag; + int accum; + int Start,End; + int *ptr,*ptr2; + + while((token=yylex())) /* The code handling is simple enough. */ + { /* just read the code and documentation */ + ErrorValue=0; /* book... */ + arrayflag=0; + switch(token) + { + case R_ECHO: + printf("%s\n",getstr()); + break; + case R_PRINTIMAGE: + PrintImage(); + break; + case R_PRINTFRAME: + PrintFrame(); + break; + case R_PRINTSCAN: + PrintScan(); + break; + case R_COMPONENT: + ntoken=yylex(); + ARRAYBEGIN; + dest = yyint; + InBounds(dest,0,MAXIMUM_COMPONENTS-1,"Bad component reference"); + if (ErrorValue) break; + if (yylex()!=R_LBRACKET) + { + WHEREAMI(); + printf("Expected left bracket.\n"); + break; + } + CFrame->ComponentFileName[dest] = getstr(); + value=getint(); + InBounds(value,0,MAXIMUM_HORIZONTAL_FREQUENCY, + "Bad horizontal frequency"); + if (ErrorValue) break; + CFrame->hf[dest]=value; + value=getint(); + InBounds(value,0,MAXIMUM_VERTICAL_FREQUENCY, + "Bad vertical frequency"); + if (ErrorValue) break; + CFrame->vf[dest]=value; + value=getint(); + InBounds(value,0,MAXIMUM_DEVICES-1,"Bad device reference"); + if (ErrorValue) break; + CFrame->tq[dest]=value; + CFrame->cn[CFrame->GlobalNumberComponents++]=dest;/*Know to use it*/ + if (yylex()!=R_RBRACKET) + { + WHEREAMI(); + printf("Expected right bracket.\n"); + break; + } + ARRAYEND; + break; + case R_SCAN: + CScan->NumberComponents=0; + ntoken=yylex(); + ARRAYBEGIN; + if (CScan->NumberComponents>=MAXIMUM_SOURCES) + { + WHEREAMI(); + printf("Exceeded number of sources per scan.\n"); + break; + } + InBounds(yyint,0,MAXIMUM_COMPONENTS-1,"Bad component reference"); + if (ErrorValue) break; + for(i=0;iGlobalNumberComponents;i++) /* Check there */ + if (CFrame->cn[i]==yyint) break; + if (i==CFrame->GlobalNumberComponents) + { + WHEREAMI(); + printf("Scan index not defined in frame yet.\n"); + break; + } + CScan->ci[CScan->NumberComponents] = yyint; + if (yylex()!=R_LBRACKET) + { + WHEREAMI(); + printf("Expected left bracket.\n"); + break; + } + value=getint(); + InBounds(value,0,MAXIMUM_DEVICES-1,"Bad device reference"); + if (ErrorValue) break; + CScan->td[CScan->NumberComponents]=value; + value=getint(); + InBounds(value,0,MAXIMUM_DEVICES-1,"Bad device reference"); + if (ErrorValue) break; + CScan->ta[CScan->NumberComponents]=value; + CScan->NumberComponents++; + if (yylex()!=R_RBRACKET) + { + WHEREAMI(); + printf("Expected right bracket.\n"); + break; + } + ARRAYEND; + break; + case R_QUANTIZATION: + ntoken=yylex(); + ARRAYBEGIN; + dest = yyint; + InBounds(dest,0,MAXIMUM_DEVICES-1, + "Bad quantization reference."); + if (ErrorValue) break; + ntoken=yylex(); + if (ntoken==R_LUMINANCEDEFAULT) + { + CImage->QuantizationMatrices[dest]=LuminanceQuantization; + break; + } + else if (ntoken==R_CHROMINANCEDEFAULT) + { + CImage->QuantizationMatrices[dest]=ChrominanceQuantization; + break; + } + else if (ntoken!=R_LBRACKET) + { + WHEREAMI(); + printf("Expected left bracket.\n"); + break; + } + CImage->NumberQuantizationMatrices = + MAX(CImage->NumberQuantizationMatrices,(dest+1)); + if (!(ptr=(int *)calloc(64,sizeof(int)))) + { + WHEREAMI(); + printf("Cannot allocate quantization matrix.\n"); + exit(ERROR_MEMORY); + } + CImage->NumberQuantizationMatrices = + MAX(CImage->NumberQuantizationMatrices,(dest+1)); + CImage->QuantizationMatrices[dest]=ptr; + for(i=0;i<64;i++) + { + ptr[i]=16; + } + for(i=0;i<65;i++,ptr++) /* One additional to force r-bracket */ + { + if ((ntoken=yylex())!=R_INTEGER) break; + InBounds(yyint,1,65535,"Integer out of bounds"); + if (ErrorValue) yyint=16; + *ptr = yyint; + } + if (ntoken!=R_RBRACKET) + { + WHEREAMI(); + printf("Expected integer or right bracket.\n"); + break; + } + ARRAYEND; + break; + case R_ACSEND: + ntoken=yylex(); + if (ntoken==R_EMPTY) + { + CScan->NumberACTablesSend = 0; + break; + } + ARRAYBEGIN; + if (CScan->NumberACTablesSend>=MAXIMUM_DEVICES) + { + WHEREAMI(); + printf("AC Huffman queue full.\n"); + break; + } + InBounds(yyint,0,MAXIMUM_DEVICES-1,"Bad device reference"); + if (ErrorValue) break; + CScan->sa[CScan->NumberACTablesSend++] = yyint; + ARRAYEND; + break; + case R_DCSEND: + ntoken=yylex(); + if (ntoken==R_EMPTY) + { + CScan->NumberDCTablesSend = 0; + break; + } + ARRAYBEGIN; + if (CScan->NumberDCTablesSend>=MAXIMUM_DEVICES) + { + WHEREAMI(); + printf("DC Huffman queue full.\n"); + break; + } + InBounds(yyint,0,MAXIMUM_DEVICES-1,"Bad device reference"); + if (ErrorValue) break; + CScan->sd[CScan->NumberDCTablesSend++] = yyint; + ARRAYEND; + break; + case R_QSEND: + ntoken=yylex(); + if (ntoken==R_EMPTY) + { + CScan->NumberQTablesSend = 0; + break; + } + ARRAYBEGIN; + if (CScan->NumberQTablesSend>=MAXIMUM_DEVICES) + { + WHEREAMI(); + printf("Quantization queue full.\n"); + break; + } + InBounds(yyint,0,MAXIMUM_DEVICES-1,"Bad device reference"); + if (ErrorValue) break; + CScan->sq[CScan->NumberQTablesSend++] = yyint; + ARRAYEND; + break; + case R_STREAMNAME: + CImage->StreamFileName = getstr(); + break; + case R_IMAGEWIDTH: + value=getint(); + InBounds(value,0,MAXIMUM_IMAGE_WIDTH,"Bad image width"); + CFrame->GlobalWidth = value; + break; + case R_IMAGEHEIGHT: + value=getint(); + InBounds(value,0,MAXIMUM_IMAGE_HEIGHT,"Bad image height"); + CFrame->GlobalHeight = value; + break; + case R_SCANDNL: + ntoken=yylex(); + switch(ntoken) + { + case R_AUTO: + CFrame->InsertDnl= -2; + break; + case R_ENABLE: + CFrame->InsertDnl= -1; + break; + case R_INTEGER: + CFrame->InsertDnl = yyint; + break; + default: + WHEREAMI(); + printf("Expected integer.\n"); + break; + } + break; + case R_FRAMEWIDTH: + ntoken=yylex(); + ARRAYBEGIN; + dest = yyint; + InBounds(dest,0,MAXIMUM_COMPONENTS-1,"Bad component destination"); + if (ErrorValue) break; + value=getint(); + InBounds(value,0,MAXIMUM_IMAGE_WIDTH,"Bad frame width"); + if (ErrorValue) break; + CFrame->Width[dest] = value; + ARRAYEND; + break; + case R_FRAMEHEIGHT: + ntoken=yylex(); + ARRAYBEGIN; + dest = yyint; + InBounds(dest,0,MAXIMUM_COMPONENTS-1,"Bad component destination"); + if (ErrorValue) break; + value=getint(); + InBounds(value,0,MAXIMUM_IMAGE_HEIGHT,"Bad frame height"); + if (ErrorValue) break; + CFrame->Height[dest] = value; + ARRAYEND; + break; + case R_RESYNC: + value = getint(); + InBounds(value,0,MAXIMUM_RESYNC_INTERVAL,"Bad resync interval"); + if (ErrorValue) break; + CFrame->ResyncInterval = value; + break; + case R_BUFFER: + value = getint(); + InBounds(value,MINIMUM_BUFFERSIZE, + MAXIMUM_BUFFERSIZE,"Bad buffersize"); + if (ErrorValue) break; + CFrame->BufferSize = value; + break; + case R_OPENSCAN: + CheckValidity(); + CheckBaseline(); + ConfirmFileSize(); + MakeIob(IOB_BLOCK,O_RDONLY,1); + break; + case R_CLOSESCAN: + for(i=0;iNumberComponents;i++) /* Close all components */ + { + InstallIob(i); + CloseIob(); + } + break; + case R_OPENSTREAM: + if (CImage->StreamFileName) + { + swopen(CImage->StreamFileName,0); /* Index 0 open */ + } + else + { + printf("StreamFileName: Null. Failed\n"); + } + break; + case R_CLOSESTREAM: + swclose(); + break; + case R_FREQUENCY: + JpegFrequencyScan(); + break; + case R_WRITESPECIAL: + ntoken=yylex(); + ARRAYBEGIN; + value = yyint; + swbytealign(); + bputc(0xFF); /* Marker */ + bputc(value&0xff); + Start = swtell(); + bputw(0); + if (yylex()!=R_LBRACKET) + { + WHEREAMI(); + printf("Expected left bracket.\n"); + End = swtell(); + swseek(Start); + bputw((End-Start) >> 3); + swseek(End); + break; + } + while((ntoken=yylex())==R_INTEGER) + { + bputc(yyint&0xff); + } + if (ntoken!=R_RBRACKET) + { + WHEREAMI(); + printf("Expected integer or right bracket.\n"); + End = swtell(); + swseek(Start); + bputw((End-Start) >> 3); + swseek(End); + break; + } + End = swtell(); + swseek(Start); + bputw((End-Start) >> 3); + swseek(End); + ARRAYEND; + break; + case R_WRITEDIRECT: + swbytealign(); + if (yylex()!=R_LBRACKET) + { + WHEREAMI(); + printf("Expected left bracket.\n"); + break; + } + while((ntoken=yylex())==R_INTEGER) + { + bputc(yyint&0xff); + } + if (ntoken!=R_RBRACKET) + { + WHEREAMI(); + printf("Expected integer or right bracket.\n"); + break; + } + break; + case R_WRITESCAN: + JpegEncodeScan(); + break; + case R_WRITEFRAME: + MakeConsistentFrameSize(); /* Do it here when everything defined */ + WriteSof(); + break; + case R_WRITESOI: + WriteSoi(); + break; + case R_WRITEEOI: + WriteEoi(); + break; + case R_WRITEQUANTIZATION: + WriteDqt(); + break; + case R_WRITERESYNC: + WriteDri(); + break; + case R_WRITEDNL: + WriteDnl(); + break; + case R_WRITEHUFFMAN: + WriteDht(); + break; + case R_ACCUSTOM: + ntoken=yylex(); + ARRAYBEGIN; + dest = yyint; + InBounds(dest,0,MAXIMUM_DEVICES-1,"Bad device reference"); + if (ErrorValue) break; + if (yylex()!=R_LBRACKET) + { + WHEREAMI(); + printf("Expected left bracket.\n"); + break; + } + MakeXhuff(); + MakeEhuff(); + if (!(ptr=(int *)calloc(257,sizeof(int)))) + { + WHEREAMI(); + printf("Out of custom frequency space.\n"); + exit(ERROR_MEMORY); + } + for(i=0;i<257;i++) + { + ptr[i]=0; + } + while((ntoken=yylex())==R_INTEGER) + { + InBounds(yyint,0,MAXIMUM_SOURCES-1,"Bad frequency reference"); + if(ErrorValue) yyint=0; + AddFrequency(ptr,CScan->ACFrequency[yyint]); + } + if (ntoken!=R_RBRACKET) + { + WHEREAMI(); + printf("Expected right bracket.\n"); + break; + } + MakeHuffman(ptr); + SetACHuffman(dest); + CImage->NumberACTables = + MAX(CImage->NumberACTables,(dest+1)); + ARRAYEND; + break; + case R_DCCUSTOM: + ntoken=yylex(); + ARRAYBEGIN; + dest = yyint; + InBounds(dest,0,MAXIMUM_DEVICES-1,"Bad device reference"); + if (ErrorValue) break; + if (yylex()!=R_LBRACKET) + { + WHEREAMI(); + printf("Expected left bracket.\n"); + break; + } + MakeXhuff(); + MakeEhuff(); + if (!(ptr=(int *)calloc(257,sizeof(int)))) + { + WHEREAMI(); + printf("Out of custom frequency space.\n"); + exit(ERROR_MEMORY); + } + for(i=0;i<257;i++) + { + ptr[i]=0; + } + while((ntoken=yylex())==R_INTEGER) + { + InBounds(yyint,0,MAXIMUM_SOURCES-1,"Bad frequency reference"); + if(ErrorValue) yyint=0; + AddFrequency(ptr,CScan->DCFrequency[yyint]); + } + if (ntoken!=R_RBRACKET) + { + WHEREAMI(); + printf("Expected right bracket.\n"); + break; + } + MakeHuffman(ptr); + SetDCHuffman(dest); + CImage->NumberDCTables = + MAX(CImage->NumberDCTables,(dest+1)); + ARRAYEND; + break; + case R_ACSPEC: + ntoken=yylex(); + ARRAYBEGIN; + dest = yyint; + InBounds(dest,0,MAXIMUM_DEVICES-1,"Bad device reference"); + if (ErrorValue) break; + MakeXhuff(); + MakeEhuff(); + if ((ntoken=yylex())==R_LBRACKET) + { + if (!(ptr=(int *)calloc(38,sizeof(int)))) /* Get bits */ + { + WHEREAMI(); + printf("Out of custom bits space.\n"); + exit(ERROR_MEMORY); + } + for(i=0;i<32;i++) + { + ptr[i]=0; + } + for(accum=0,i=0;i<17;i++) /* First index is bitlength of 1. */ + { /* One additional to force r-bracket. */ + ntoken=yylex(); + if (ntoken==R_INTEGER) + { + accum+=yyint; + ptr[i]=yyint; + } + else break; + } + if (ntoken!=R_RBRACKET) + { + WHEREAMI(); + printf("Expected integer or right bracket.\n"); + break; + } + if (yylex()!=R_LBRACKET) /* Get values */ + { + WHEREAMI(); + printf("Expected left bracket.\n"); + break; + } + if (!(ptr2=(int *)calloc(257,sizeof(int)))) + { + WHEREAMI(); + printf("Out of custom Huffman value space.\n"); + exit(ERROR_MEMORY); + } + for(i=0;i<257;i++) + { + ptr2[i]=0; + } + for(i=0;i<257;i++) /* One additinal to force r-bracket */ + { + ntoken=yylex(); + if (ntoken==R_INTEGER) + { + ptr2[i]=yyint; + } + else break; + } + if (i!=accum) + { + WHEREAMI(); + printf("Number of bitlengths != number of values."); + } + if (ntoken!=R_RBRACKET) + { + WHEREAMI(); + printf("Expected integer or right bracket.\n"); + break; + } + SpecifiedHuffman(ptr,ptr2); + } + else if (ntoken==R_CHROMINANCEDEFAULT) + { + SpecifiedHuffman(ChrominanceACBits,ChrominanceACValues); + } + else if (ntoken==R_LUMINANCEDEFAULT) + { + SpecifiedHuffman(LuminanceACBits,LuminanceACValues); + } + else + { + WHEREAMI(); + printf("Expected left bracket or ACDEFAULT.\n"); + break; + } + SetACHuffman(dest); + CImage->NumberACTables = + MAX(CImage->NumberACTables,(dest+1)); + ARRAYEND; + break; + case R_DCSPEC: + ntoken=yylex(); + ARRAYBEGIN; + dest = yyint; + InBounds(dest,0,MAXIMUM_DEVICES-1,"Bad device reference"); + if (ErrorValue) break; + MakeXhuff(); + MakeEhuff(); + if ((ntoken=yylex())==R_LBRACKET) + { + if (!(ptr=(int *)calloc(38,sizeof(int)))) /* Get bits */ + { + WHEREAMI(); + printf("Out of custom bits space.\n"); + exit(ERROR_MEMORY); + } + for(i=0;i<32;i++) + { + ptr[i]=0; + } + for(accum=0,i=0;i<17;i++) /* First index is bitlength of 1. */ + { /* 0-16 to force right bracket. */ + ntoken=yylex(); + if (ntoken==R_INTEGER) + { + accum+=yyint; + ptr[i]=yyint; + } + else break; + } + if (ntoken!=R_RBRACKET) + { + WHEREAMI(); + printf("Expected integer or right bracket.\n"); + break; + } + if (yylex()!=R_LBRACKET) /* Get values */ + { + WHEREAMI(); + printf("Expected left bracket.\n"); + break; + } + if (!(ptr2=(int *)calloc(257,sizeof(int)))) + { + WHEREAMI(); + printf("Out of custom Huffman value space.\n"); + exit(ERROR_MEMORY); + } + for(i=0;i<257;i++) + { + ptr2[i]=0; + } + for(i=0;i<257;i++) /*One additional to force r-bracket.*/ + { + ntoken=yylex(); + if (ntoken==R_INTEGER) + { + ptr2[i]=yyint; + } + else break; + } + if (i!=accum) + { + WHEREAMI(); + printf("Number of bitlengths != number of values."); + } + if (ntoken!=R_RBRACKET) + { + WHEREAMI(); + printf("Expected integer or right bracket.\n"); + break; + } + SpecifiedHuffman(ptr,ptr2); + } + else if (ntoken==R_CHROMINANCEDEFAULT) + { + SpecifiedHuffman(ChrominanceDCBits,ChrominanceDCValues); + } + else if (ntoken==R_LUMINANCEDEFAULT) + { + SpecifiedHuffman(LuminanceDCBits,LuminanceDCValues); + } + else + { + WHEREAMI(); + printf("Expected left bracket or DCDEFAULT.\n"); + break; + } + SetDCHuffman(dest); + CImage->NumberDCTables = + MAX(CImage->NumberDCTables,(dest+1)); + ARRAYEND; + break; + } + } +} + +/*NOPROTO*/ +/*END*/ diff --git a/gdcm/Utilities/pvrg/lexer.l b/gdcm/Utilities/pvrg/lexer.l new file mode 100644 index 0000000..9860eab --- /dev/null +++ b/gdcm/Utilities/pvrg/lexer.l @@ -0,0 +1,1307 @@ +/************************************************************* +Copyright (C) 1990, 1991, 1993 Andy C. Hung, all rights reserved. +PUBLIC DOMAIN LICENSE: Stanford University Portable Video Research +Group. If you use this software, you agree to the following: This +program package is purely experimental, and is licensed "as is". +Permission is granted to use, modify, and distribute this program +without charge for any purpose, provided this license/ disclaimer +notice appears in the copies. No warranty or maintenance is given, +either expressed or implied. In no event shall the author(s) be +liable to you or a third party for any special, incidental, +consequential, or other damages, arising out of the use or inability +to use the program for any purpose (or the loss of data), even if we +have been advised of such possibilities. Any public reference or +advertisement of this source code should refer to it as the Portable +Video Research Group (PVRG) code, and not by any author(s) (or +Stanford University) name. +*************************************************************/ +%option yylineno +%{ + +/*LABEL lexer.c */ + +/* + * flex command was run this way: + * + * $ lex -olexer.c lexer.l + */ + +/* We do not care of interactive mode */ +#define YY_NEVER_INTERACTIVE 1 +#define YY_NO_UNPUT 1 + +/* Do not include unistd.h in generated source. */ +#define YY_NO_UNISTD_H + +/* Skip declaring this function. It is a macro. */ +#define YY_SKIP_YYWRAP + +/* Redefine the yywrap so that we don't have + to worry about lex library */ + +# define yywrap() (1) + +static char *ReservedWords[] = { /* Token names */ +"COMPONENT", +"SCAN", +"QUANTIZATION", +"DCSPEC", +"ACCUSTOM", +"DCCUSTOM", +"PRINTSCAN", +"PRINTFRAME", +"PRINTIMAGE", +"OPENSCAN", +"ACSPEC", +"WRITESCAN", +"WRITEFRAME", +"WRITESOI", +"WRITEQUANTIZATION", +"WRITERESYNC", +"WRITEHUFFMAN", +"FREQUENCY", +"ACSEND", +"DCSEND", +"QSEND", +"STREAMNAME", +"IMAGEHEIGHT", +"IMAGEWIDTH", +"RESYNC", +"BUFFER", +"OPENSTREAM", +"CLOSESTREAM", +"FRAMEHEIGHT", +"FRAMEWIDTH", +"CLOSESCAN", +"WRITEEOI", +"ECHO", +"WRITESPECIAL", +"WRITEDIRECT", +"LUMINANCEDEFAULT", +"CHROMINANCEDEFAULT", +"ENABLE", +"SCANDNL", +"WRITEDNL", +"AUTO", +"EMPTY", +""}; + +#define R_COMPONENT 1 /* Token values mapped to token names */ +#define R_SCAN 2 +#define R_QUANTIZATION 3 +#define R_DCSPEC 4 +#define R_ACCUSTOM 5 +#define R_DCCUSTOM 6 +#define R_PRINTSCAN 7 +#define R_PRINTFRAME 8 +#define R_PRINTIMAGE 9 +#define R_OPENSCAN 10 +#define R_ACSPEC 11 +#define R_WRITESCAN 12 +#define R_WRITEFRAME 13 +#define R_WRITESOI 14 +#define R_WRITEQUANTIZATION 15 +#define R_WRITERESYNC 16 +#define R_WRITEHUFFMAN 17 +#define R_FREQUENCY 18 +#define R_ACSEND 19 +#define R_DCSEND 20 +#define R_QSEND 21 +#define R_STREAMNAME 22 +#define R_IMAGEHEIGHT 23 +#define R_IMAGEWIDTH 24 +#define R_RESYNC 25 +#define R_BUFFER 26 +#define R_OPENSTREAM 27 +#define R_CLOSESTREAM 28 +#define R_FRAMEHEIGHT 29 +#define R_FRAMEWIDTH 30 +#define R_CLOSESCAN 31 +#define R_WRITEEOI 32 +#define R_ECHO 33 +#define R_WRITESPECIAL 34 +#define R_WRITEDIRECT 35 +#define R_LUMINANCEDEFAULT 36 +#define R_CHROMINANCEDEFAULT 37 +#define R_ENABLE 38 +#define R_SCANDNL 39 +#define R_WRITEDNL 40 +#define R_AUTO 41 +#define R_EMPTY 42 + +#define R_INTEGER 1000 /* Special TYPES for tokens */ +#define R_LBRACKET 1001 +#define R_RBRACKET 1002 +#define R_ID 1003 +#define R_STRING 1004 + +int CommentDepth = 0; /* depth of comment nesting */ +int yyint=0; /* Return value for integers */ +int LexDebug=0; /* Status of lex debugging */ + +#define PRIME 211 +#define EOS '\0' + +#define MakeStructure(S) (S *) malloc(sizeof(S)) +#define InsertLink(link,list){\ +if(!list){list=link;}else{link->next=list;list=link;}} + +#define LINK struct link_def +struct id { /* Default id structure */ + char *name; /* Key */ + int tokentype; /* Token type */ + int count; /* Count of # references */ +}; + +LINK { /* A link for the hash buckets */ +struct id *lid; /* Current id */ +LINK *next; /* Pointer to next id */ +}; + +/*PUBLIC*/ + +extern void initparser(); +extern void parser(); + +static int hashpjw(); +static LINK * MakeLink(); +static struct id * enter(); +static int getint(); +static char * getstr(); + +/*PRIVATE*/ + +/*NOPROTO*/ + +%} + +Delim [ \t\n] +WhiteSpace {Delim}+ +Letter [a-zA-Z] +Digit [0-9] +HexDigit ({Digit}|[a-fA-F]) +OctalDigit [0-7] +Id {Letter}({Letter}|{Digit})* +DecInteger {Digit}+ +HexInteger 0[xX]{HexDigit}+ +OctInteger 0[oO]{OctalDigit}+ +HexInteger2 {HexDigit}+[Hh] +OctInteger2 {OctalDigit}+[BCObco] +CharInteger '([^\\]|\\([\n^\n]|{OctalDigit}{1,3}))' +ScaleFactor E[-+]?{Digit}+ +Real1 ({Digit}+"."{Digit}*({ScaleFactor})?) +Real2 ({Digit}*"."{Digit}+({ScaleFactor})?) +Real3 ({Digit}+{ScaleFactor}) +Real {Real1}|{Real2}|{Real3} +Operator (\+|=|\-|#|\*|\<|\>|\/|:=|\<\>|\&|\<=|\.|\>=|\,|\.\.|;|:|\(|\)|\[|\]|\{|\}|\^|\||~) +String \"([^\"]|\\\")*\" + +%S NORMAL COMMENT +%% + +{WhiteSpace} {} + +{Id} {struct id *temp; temp = enter(0,yytext,yyleng); + if (LexDebug) + { + printf("%s : %s (%d)\n", + yytext, + ((temp->tokentype) ? "RESERVED" : "IDENTIFIER"), + temp->count); + } + if (temp->tokentype) + { + return(temp->tokentype); + } + else + { + return(R_ID); + } + } +{Real} {if (LexDebug) + { + printf("%s : %s\n", yytext, "REAL"); + } + } +{DecInteger} {if (LexDebug) + { + printf("%s : %s\n", yytext, "INTEGER"); + } + yyint = atoi(yytext); + return(R_INTEGER);} +{HexInteger} {if (LexDebug) + { + printf("%s : %s\n", yytext, "(HEX)INTEGER"); + } + yyint = strtol(yytext+2,NULL,16); + return(R_INTEGER);} +{HexInteger2} {if (LexDebug) + { + printf("%s : %s\n", yytext, "(HEX)INTEGER"); + } + yyint = strtol(yytext,NULL,16); + return(R_INTEGER);} +{OctInteger} {if (LexDebug) + { + printf("%s : %s\n", yytext, "(OCT)INTEGER"); + } + yyint = strtol(yytext+2,NULL,8); + return(R_INTEGER);} +{OctInteger2} {if (LexDebug) + { + printf("%s : %s\n", yytext, "(OCT)INTEGER"); + } + yyint = strtol(yytext,NULL,8); + return(R_INTEGER);} +{CharInteger} {if (LexDebug) + { + printf("%s : %s\n", yytext, "(CHAR)INTEGER"); + } + if (yyleng>4) + { + yyint = strtol(yytext+2,NULL,8); + } + else + { + if (*(yytext+1)=='\\') + { + switch(*(yytext+2)) + { + case '0': + yyint=0; + break; + case 'b': + yyint = 0x8; + break; + case 'i': + yyint = 0x9; + break; + case 'n': + yyint = 0xa; + break; + case 'v': + yyint = 0xb; + break; + case 'f': + yyint = 0xc; + break; + case 'r': + yyint = 0xd; + break; + default: + yyint=(*yytext+2); + break; + } + } + else + { + yyint = *(yytext+1); + } + } + return(R_INTEGER);} +\[ {if (LexDebug) + { + printf("%s : %s\n", yytext, "LBRACKET"); + } + return(R_LBRACKET);} +\] {if (LexDebug) + { + printf("%s : %s\n", yytext, "RBRACKET"); + } + return(R_RBRACKET);} +{Operator} {if (LexDebug) + { + printf("%s : %s\n", yytext, "OPERATOR"); + } + } +{String} {if (LexDebug) + { + printf("%s : %s\n", yytext, "STRING"); + } + return(R_STRING);} + +"/*" {CommentDepth++; BEGIN COMMENT;} + +"*/" {CommentDepth--;if(!CommentDepth) BEGIN NORMAL;} + +. { + /* None of the above rules applicable, so + it's a bad symbol. */ + printf("Bad input char '%c' on line %d\n", + yytext[0], + yylineno); + } + +.|\n {} /*Everything's AOK */ + +%% + +/*PROTO*/ +LINK *HashTable[PRIME]; /* My little hash table */ + +/*START*/ + +/*BFUNC + +initparser() is used to place the Reserved Words into the hash table. +It must be called before the parser command is called. + +EFUNC*/ + +void initparser() +{ + char i,**sptr; + BEGIN NORMAL; + + for(i=1,sptr=ReservedWords;**sptr!='\0';i++,sptr++) + { /* Add Reserved Words */ + enter(i,*sptr,strlen(*sptr)); /* Put reserved words in */ + } /* hash table */ +} + +#undef BEGIN +#undef MakeStructure +#include "globals.h" +#include "stream.h" +#include "tables.h" + +extern FRAME *CFrame; +extern IMAGE *CImage; +extern SCAN *CScan; +extern int ErrorValue; + +/*BFUNC + +hashpjw() returns a hash value for a string input. + +EFUNC*/ + +static int hashpjw(s) + char *s; +{ + BEGIN("hashpjw") + char *p; + unsigned int g, h; + h=0; + + for(p=s;*p!=EOS;p++) /* Taken from Aho Sethi Ullman Compilers book. */ + { + h = (h << 4) + *p; + if ((g = h&0xf0000000)) + { + h = h ^(g >> 24); + h = h ^ g; + } + } + return(h % PRIME); +} + +/*BFUNC + +MakeLink() is used to construct a link object. The link +is used for the hash table construct. + +EFUNC*/ + + +static LINK *MakeLink(tokentype,str,len) + int tokentype; + char *str; + int len; +{ + BEGIN("MakeLink") + LINK *temp; + + if (!(temp = MakeStructure(LINK))) /* Make link */ + { + WHEREAMI(); + printf("Cannot make a LINK.\n"); + exit(ERROR_MEMORY); + } + if (!(temp->lid = MakeStructure(struct id))) /* Make id */ + { + printf("Cannot make an id.\n"); + exit(ERROR_MEMORY); + } + temp->next = NULL; /* Set fields */ + if (!(temp->lid->name =(char *)calloc(len+1,sizeof(char)))) + { + printf("Cannot make a string space for the link.\n"); + exit(ERROR_MEMORY); + } + strcpy(temp->lid->name,str); /* Copy key */ + temp->lid->tokentype = tokentype; + temp->lid->count = 1; + return(temp); +} + +/*BFUNC + +enter() is used to enter a Reserved Word or ID into the hash table. + +EFUNC*/ + +static struct id *enter(tokentype,str,len) + int tokentype; + char *str; + int len; +{ + BEGIN("enter") + int hashnum; + LINK *temp,*current; + char *ptr; + + for(ptr=str;*ptr!='\0';ptr++) /* All capitals is fine */ + { + if ((*ptr>='a') && (*ptr<='z')) + { + *ptr = *ptr - ('a'-'A'); + } + } + hashnum = hashpjw(str); /* Check if in hash table */ + for(temp=NULL,current=HashTable[hashnum]; + current!= NULL; + current=current->next) + { + if (strcmp(str,current->lid->name) == 0) + { + temp=current; + break; + } + } + if (temp) /* Yes, found ID then return */ + { + temp->lid->count++; + return(temp->lid); + } + else /* Else make our own ID and return that*/ + { + temp = MakeLink(tokentype,str,len); + InsertLink(temp,HashTable[hashnum]); + return(temp->lid); + } +} + +/*BFUNC + +getint() takes an integer from the input. + +EFUNC*/ + +static int getint() +{ + BEGIN("getint") + int type; + if ((type=yylex())!=R_INTEGER) + { + printf("Bad input, not integer, '%s' on line %d\n", + yytext, + yylineno); + return(0); + } + return(yyint); +} + +/*BFUNC + +getstr() gets a string from the input. It copies the string to +temporary storage before it returns the pointer. + +EFUNC*/ + +static char *getstr() +{ + BEGIN("getstr") + char *tmp,*ptr,*bptr; + int i,accum,flag; + if (yylex() != R_STRING) /* Check if string */ + { + printf("String expected.\n"); + if (!(tmp=(char *) malloc(sizeof(char)))) + { + WHEREAMI(); + printf("Cannot allocate for null string.\n"); + exit(ERROR_MEMORY); + } + *tmp='\0'; + return(tmp); + } + if (!(tmp=(char *)calloc(strlen(yytext)+1,sizeof(char)))) /* Make space */ + { + WHEREAMI(); + printf("Cannot allocate %d string space.\n",yyleng); + exit(ERROR_MEMORY); + } + for(bptr=yytext+1,ptr=tmp;*bptr!='"';bptr++,ptr++) /* Copy to string */ + { + if (*bptr=='\\') + { + bptr++; + for(flag=0,accum=0,i=0;i<3;i++) /* Octal character lookahead */ + { + if ((*bptr>='0')&&(*bptr<='7')) + { + accum = (accum<<3)+(*bptr-'0'); + bptr++; + flag=1; + } + else + { + break; + } + } + if (flag) + { + bptr--; + *ptr=accum; + } + else /* Do conversions, if necessary */ + { + switch(*(bptr)) + { + case '0': + *ptr = 0; + break; + case 'b': + *ptr = 0x8; + break; + case 'i': + *ptr = 0x9; + break; + case 'n': + *ptr = 0xa; + break; + case 'v': + *ptr = 0xb; + break; + case 'f': + *ptr = 0xc; + break; + case 'r': + *ptr = 0xd; + break; + default: + *ptr=(*bptr); + } + } + } + else + { + *ptr = (*bptr); + } + } + *ptr='\0'; + return(tmp); +} + +/*BFUNC + +parser() handles all of the parsing required for the Command +Interpreter. It is basically a while statement with a very large case +statement for every input. The Command Interpreter is essentially +driven by the keywords. All unmatched values such as integers, +strings, and brackets, are ignored. + +EFUNC*/ + +#define ARRAYBEGIN if (ntoken==R_LBRACKET)\ + {\ + arrayflag=1;\ + ntoken=yylex();\ + }\ + if (ntoken!=R_INTEGER)\ + {\ + WHEREAMI();\ + printf("Expected integer.\n");\ + break;\ + }\ + while(1)\ + { + +#define ARRAYEND if (arrayflag)\ + {\ + if ((ntoken=yylex())==R_RBRACKET) break;\ + else if (ntoken!=R_INTEGER)\ + {\ + WHEREAMI();\ + printf("Expected integer or right bracket.\n");\ + break;\ + }\ + }\ + else break;\ + } + +void parser() +{ + BEGIN("parser") + int i,dest,value,token,ntoken,arrayflag; + int accum; + int Start,End; + int *ptr,*ptr2; + + while((token=yylex())) /* The code handling is simple enough. */ + { /* just read the code and documentation */ + ErrorValue=0; /* book... */ + arrayflag=0; + switch(token) + { + case R_ECHO: + printf("%s\n",getstr()); + break; + case R_PRINTIMAGE: + PrintImage(); + break; + case R_PRINTFRAME: + PrintFrame(); + break; + case R_PRINTSCAN: + PrintScan(); + break; + case R_COMPONENT: + ntoken=yylex(); + ARRAYBEGIN; + dest = yyint; + InBounds(dest,0,MAXIMUM_COMPONENTS-1,"Bad component reference"); + if (ErrorValue) break; + if (yylex()!=R_LBRACKET) + { + WHEREAMI(); + printf("Expected left bracket.\n"); + break; + } + CFrame->ComponentFileName[dest] = getstr(); + value=getint(); + InBounds(value,0,MAXIMUM_HORIZONTAL_FREQUENCY, + "Bad horizontal frequency"); + if (ErrorValue) break; + CFrame->hf[dest]=value; + value=getint(); + InBounds(value,0,MAXIMUM_VERTICAL_FREQUENCY, + "Bad vertical frequency"); + if (ErrorValue) break; + CFrame->vf[dest]=value; + value=getint(); + InBounds(value,0,MAXIMUM_DEVICES-1,"Bad device reference"); + if (ErrorValue) break; + CFrame->tq[dest]=value; + CFrame->cn[CFrame->GlobalNumberComponents++]=dest;/*Know to use it*/ + if (yylex()!=R_RBRACKET) + { + WHEREAMI(); + printf("Expected right bracket.\n"); + break; + } + ARRAYEND; + break; + case R_SCAN: + CScan->NumberComponents=0; + ntoken=yylex(); + ARRAYBEGIN; + if (CScan->NumberComponents>=MAXIMUM_SOURCES) + { + WHEREAMI(); + printf("Exceeded number of sources per scan.\n"); + break; + } + InBounds(yyint,0,MAXIMUM_COMPONENTS-1,"Bad component reference"); + if (ErrorValue) break; + for(i=0;iGlobalNumberComponents;i++) /* Check there */ + if (CFrame->cn[i]==yyint) break; + if (i==CFrame->GlobalNumberComponents) + { + WHEREAMI(); + printf("Scan index not defined in frame yet.\n"); + break; + } + CScan->ci[CScan->NumberComponents] = yyint; + if (yylex()!=R_LBRACKET) + { + WHEREAMI(); + printf("Expected left bracket.\n"); + break; + } + value=getint(); + InBounds(value,0,MAXIMUM_DEVICES-1,"Bad device reference"); + if (ErrorValue) break; + CScan->td[CScan->NumberComponents]=value; + value=getint(); + InBounds(value,0,MAXIMUM_DEVICES-1,"Bad device reference"); + if (ErrorValue) break; + CScan->ta[CScan->NumberComponents]=value; + CScan->NumberComponents++; + if (yylex()!=R_RBRACKET) + { + WHEREAMI(); + printf("Expected right bracket.\n"); + break; + } + ARRAYEND; + break; + case R_QUANTIZATION: + ntoken=yylex(); + ARRAYBEGIN; + dest = yyint; + InBounds(dest,0,MAXIMUM_DEVICES-1, + "Bad quantization reference."); + if (ErrorValue) break; + ntoken=yylex(); + if (ntoken==R_LUMINANCEDEFAULT) + { + CImage->QuantizationMatrices[dest]=LuminanceQuantization; + break; + } + else if (ntoken==R_CHROMINANCEDEFAULT) + { + CImage->QuantizationMatrices[dest]=ChrominanceQuantization; + break; + } + else if (ntoken!=R_LBRACKET) + { + WHEREAMI(); + printf("Expected left bracket.\n"); + break; + } + CImage->NumberQuantizationMatrices = + MAX(CImage->NumberQuantizationMatrices,(dest+1)); + if (!(ptr=(int *)calloc(64,sizeof(int)))) + { + WHEREAMI(); + printf("Cannot allocate quantization matrix.\n"); + exit(ERROR_MEMORY); + } + CImage->NumberQuantizationMatrices = + MAX(CImage->NumberQuantizationMatrices,(dest+1)); + CImage->QuantizationMatrices[dest]=ptr; + for(i=0;i<64;i++) + { + ptr[i]=16; + } + for(i=0;i<65;i++,ptr++) /* One additional to force r-bracket */ + { + if ((ntoken=yylex())!=R_INTEGER) break; + InBounds(yyint,1,65535,"Integer out of bounds"); + if (ErrorValue) yyint=16; + *ptr = yyint; + } + if (ntoken!=R_RBRACKET) + { + WHEREAMI(); + printf("Expected integer or right bracket.\n"); + break; + } + ARRAYEND; + break; + case R_ACSEND: + ntoken=yylex(); + if (ntoken==R_EMPTY) + { + CScan->NumberACTablesSend = 0; + break; + } + ARRAYBEGIN; + if (CScan->NumberACTablesSend>=MAXIMUM_DEVICES) + { + WHEREAMI(); + printf("AC Huffman queue full.\n"); + break; + } + InBounds(yyint,0,MAXIMUM_DEVICES-1,"Bad device reference"); + if (ErrorValue) break; + CScan->sa[CScan->NumberACTablesSend++] = yyint; + ARRAYEND; + break; + case R_DCSEND: + ntoken=yylex(); + if (ntoken==R_EMPTY) + { + CScan->NumberDCTablesSend = 0; + break; + } + ARRAYBEGIN; + if (CScan->NumberDCTablesSend>=MAXIMUM_DEVICES) + { + WHEREAMI(); + printf("DC Huffman queue full.\n"); + break; + } + InBounds(yyint,0,MAXIMUM_DEVICES-1,"Bad device reference"); + if (ErrorValue) break; + CScan->sd[CScan->NumberDCTablesSend++] = yyint; + ARRAYEND; + break; + case R_QSEND: + ntoken=yylex(); + if (ntoken==R_EMPTY) + { + CScan->NumberQTablesSend = 0; + break; + } + ARRAYBEGIN; + if (CScan->NumberQTablesSend>=MAXIMUM_DEVICES) + { + WHEREAMI(); + printf("Quantization queue full.\n"); + break; + } + InBounds(yyint,0,MAXIMUM_DEVICES-1,"Bad device reference"); + if (ErrorValue) break; + CScan->sq[CScan->NumberQTablesSend++] = yyint; + ARRAYEND; + break; + case R_STREAMNAME: + CImage->StreamFileName = getstr(); + break; + case R_IMAGEWIDTH: + value=getint(); + InBounds(value,0,MAXIMUM_IMAGE_WIDTH,"Bad image width"); + CFrame->GlobalWidth = value; + break; + case R_IMAGEHEIGHT: + value=getint(); + InBounds(value,0,MAXIMUM_IMAGE_HEIGHT,"Bad image height"); + CFrame->GlobalHeight = value; + break; + case R_SCANDNL: + ntoken=yylex(); + switch(ntoken) + { + case R_AUTO: + CFrame->InsertDnl= -2; + break; + case R_ENABLE: + CFrame->InsertDnl= -1; + break; + case R_INTEGER: + CFrame->InsertDnl = yyint; + break; + default: + WHEREAMI(); + printf("Expected integer.\n"); + break; + } + break; + case R_FRAMEWIDTH: + ntoken=yylex(); + ARRAYBEGIN; + dest = yyint; + InBounds(dest,0,MAXIMUM_COMPONENTS-1,"Bad component destination"); + if (ErrorValue) break; + value=getint(); + InBounds(value,0,MAXIMUM_IMAGE_WIDTH,"Bad frame width"); + if (ErrorValue) break; + CFrame->Width[dest] = value; + ARRAYEND; + break; + case R_FRAMEHEIGHT: + ntoken=yylex(); + ARRAYBEGIN; + dest = yyint; + InBounds(dest,0,MAXIMUM_COMPONENTS-1,"Bad component destination"); + if (ErrorValue) break; + value=getint(); + InBounds(value,0,MAXIMUM_IMAGE_HEIGHT,"Bad frame height"); + if (ErrorValue) break; + CFrame->Height[dest] = value; + ARRAYEND; + break; + case R_RESYNC: + value = getint(); + InBounds(value,0,MAXIMUM_RESYNC_INTERVAL,"Bad resync interval"); + if (ErrorValue) break; + CFrame->ResyncInterval = value; + break; + case R_BUFFER: + value = getint(); + InBounds(value,MINIMUM_BUFFERSIZE, + MAXIMUM_BUFFERSIZE,"Bad buffersize"); + if (ErrorValue) break; + CFrame->BufferSize = value; + break; + case R_OPENSCAN: + CheckValidity(); + CheckBaseline(); + ConfirmFileSize(); + MakeIob(IOB_BLOCK,O_RDONLY,1); + break; + case R_CLOSESCAN: + for(i=0;iNumberComponents;i++) /* Close all components */ + { + InstallIob(i); + CloseIob(); + } + break; + case R_OPENSTREAM: + if (CImage->StreamFileName) + { + swopen(CImage->StreamFileName,0); /* Index 0 open */ + } + else + { + printf("StreamFileName: Null. Failed\n"); + } + break; + case R_CLOSESTREAM: + swclose(); + break; + case R_FREQUENCY: + JpegFrequencyScan(); + break; + case R_WRITESPECIAL: + ntoken=yylex(); + ARRAYBEGIN; + value = yyint; + swbytealign(); + bputc(0xFF); /* Marker */ + bputc(value&0xff); + Start = swtell(); + bputw(0); + if (yylex()!=R_LBRACKET) + { + WHEREAMI(); + printf("Expected left bracket.\n"); + End = swtell(); + swseek(Start); + bputw((End-Start) >> 3); + swseek(End); + break; + } + while((ntoken=yylex())==R_INTEGER) + { + bputc(yyint&0xff); + } + if (ntoken!=R_RBRACKET) + { + WHEREAMI(); + printf("Expected integer or right bracket.\n"); + End = swtell(); + swseek(Start); + bputw((End-Start) >> 3); + swseek(End); + break; + } + End = swtell(); + swseek(Start); + bputw((End-Start) >> 3); + swseek(End); + ARRAYEND; + break; + case R_WRITEDIRECT: + swbytealign(); + if (yylex()!=R_LBRACKET) + { + WHEREAMI(); + printf("Expected left bracket.\n"); + break; + } + while((ntoken=yylex())==R_INTEGER) + { + bputc(yyint&0xff); + } + if (ntoken!=R_RBRACKET) + { + WHEREAMI(); + printf("Expected integer or right bracket.\n"); + break; + } + break; + case R_WRITESCAN: + JpegEncodeScan(); + break; + case R_WRITEFRAME: + MakeConsistentFrameSize(); /* Do it here when everything defined */ + WriteSof(); + break; + case R_WRITESOI: + WriteSoi(); + break; + case R_WRITEEOI: + WriteEoi(); + break; + case R_WRITEQUANTIZATION: + WriteDqt(); + break; + case R_WRITERESYNC: + WriteDri(); + break; + case R_WRITEDNL: + WriteDnl(); + break; + case R_WRITEHUFFMAN: + WriteDht(); + break; + case R_ACCUSTOM: + ntoken=yylex(); + ARRAYBEGIN; + dest = yyint; + InBounds(dest,0,MAXIMUM_DEVICES-1,"Bad device reference"); + if (ErrorValue) break; + if (yylex()!=R_LBRACKET) + { + WHEREAMI(); + printf("Expected left bracket.\n"); + break; + } + MakeXhuff(); + MakeEhuff(); + if (!(ptr=(int *)calloc(257,sizeof(int)))) + { + WHEREAMI(); + printf("Out of custom frequency space.\n"); + exit(ERROR_MEMORY); + } + for(i=0;i<257;i++) + { + ptr[i]=0; + } + while((ntoken=yylex())==R_INTEGER) + { + InBounds(yyint,0,MAXIMUM_SOURCES-1,"Bad frequency reference"); + if(ErrorValue) yyint=0; + AddFrequency(ptr,CScan->ACFrequency[yyint]); + } + if (ntoken!=R_RBRACKET) + { + WHEREAMI(); + printf("Expected right bracket.\n"); + break; + } + MakeHuffman(ptr); + SetACHuffman(dest); + CImage->NumberACTables = + MAX(CImage->NumberACTables,(dest+1)); + ARRAYEND; + break; + case R_DCCUSTOM: + ntoken=yylex(); + ARRAYBEGIN; + dest = yyint; + InBounds(dest,0,MAXIMUM_DEVICES-1,"Bad device reference"); + if (ErrorValue) break; + if (yylex()!=R_LBRACKET) + { + WHEREAMI(); + printf("Expected left bracket.\n"); + break; + } + MakeXhuff(); + MakeEhuff(); + if (!(ptr=(int *)calloc(257,sizeof(int)))) + { + WHEREAMI(); + printf("Out of custom frequency space.\n"); + exit(ERROR_MEMORY); + } + for(i=0;i<257;i++) + { + ptr[i]=0; + } + while((ntoken=yylex())==R_INTEGER) + { + InBounds(yyint,0,MAXIMUM_SOURCES-1,"Bad frequency reference"); + if(ErrorValue) yyint=0; + AddFrequency(ptr,CScan->DCFrequency[yyint]); + } + if (ntoken!=R_RBRACKET) + { + WHEREAMI(); + printf("Expected right bracket.\n"); + break; + } + MakeHuffman(ptr); + SetDCHuffman(dest); + CImage->NumberDCTables = + MAX(CImage->NumberDCTables,(dest+1)); + ARRAYEND; + break; + case R_ACSPEC: + ntoken=yylex(); + ARRAYBEGIN; + dest = yyint; + InBounds(dest,0,MAXIMUM_DEVICES-1,"Bad device reference"); + if (ErrorValue) break; + MakeXhuff(); + MakeEhuff(); + if ((ntoken=yylex())==R_LBRACKET) + { + if (!(ptr=(int *)calloc(38,sizeof(int)))) /* Get bits */ + { + WHEREAMI(); + printf("Out of custom bits space.\n"); + exit(ERROR_MEMORY); + } + for(i=0;i<32;i++) + { + ptr[i]=0; + } + for(accum=0,i=0;i<17;i++) /* First index is bitlength of 1. */ + { /* One additional to force r-bracket. */ + ntoken=yylex(); + if (ntoken==R_INTEGER) + { + accum+=yyint; + ptr[i]=yyint; + } + else break; + } + if (ntoken!=R_RBRACKET) + { + WHEREAMI(); + printf("Expected integer or right bracket.\n"); + break; + } + if (yylex()!=R_LBRACKET) /* Get values */ + { + WHEREAMI(); + printf("Expected left bracket.\n"); + break; + } + if (!(ptr2=(int *)calloc(257,sizeof(int)))) + { + WHEREAMI(); + printf("Out of custom Huffman value space.\n"); + exit(ERROR_MEMORY); + } + for(i=0;i<257;i++) + { + ptr2[i]=0; + } + for(i=0;i<257;i++) /* One additinal to force r-bracket */ + { + ntoken=yylex(); + if (ntoken==R_INTEGER) + { + ptr2[i]=yyint; + } + else break; + } + if (i!=accum) + { + WHEREAMI(); + printf("Number of bitlengths != number of values."); + } + if (ntoken!=R_RBRACKET) + { + WHEREAMI(); + printf("Expected integer or right bracket.\n"); + break; + } + SpecifiedHuffman(ptr,ptr2); + } + else if (ntoken==R_CHROMINANCEDEFAULT) + { + SpecifiedHuffman(ChrominanceACBits,ChrominanceACValues); + } + else if (ntoken==R_LUMINANCEDEFAULT) + { + SpecifiedHuffman(LuminanceACBits,LuminanceACValues); + } + else + { + WHEREAMI(); + printf("Expected left bracket or ACDEFAULT.\n"); + break; + } + SetACHuffman(dest); + CImage->NumberACTables = + MAX(CImage->NumberACTables,(dest+1)); + ARRAYEND; + break; + case R_DCSPEC: + ntoken=yylex(); + ARRAYBEGIN; + dest = yyint; + InBounds(dest,0,MAXIMUM_DEVICES-1,"Bad device reference"); + if (ErrorValue) break; + MakeXhuff(); + MakeEhuff(); + if ((ntoken=yylex())==R_LBRACKET) + { + if (!(ptr=(int *)calloc(38,sizeof(int)))) /* Get bits */ + { + WHEREAMI(); + printf("Out of custom bits space.\n"); + exit(ERROR_MEMORY); + } + for(i=0;i<32;i++) + { + ptr[i]=0; + } + for(accum=0,i=0;i<17;i++) /* First index is bitlength of 1. */ + { /* 0-16 to force right bracket. */ + ntoken=yylex(); + if (ntoken==R_INTEGER) + { + accum+=yyint; + ptr[i]=yyint; + } + else break; + } + if (ntoken!=R_RBRACKET) + { + WHEREAMI(); + printf("Expected integer or right bracket.\n"); + break; + } + if (yylex()!=R_LBRACKET) /* Get values */ + { + WHEREAMI(); + printf("Expected left bracket.\n"); + break; + } + if (!(ptr2=(int *)calloc(257,sizeof(int)))) + { + WHEREAMI(); + printf("Out of custom Huffman value space.\n"); + exit(ERROR_MEMORY); + } + for(i=0;i<257;i++) + { + ptr2[i]=0; + } + for(i=0;i<257;i++) /*One additional to force r-bracket.*/ + { + ntoken=yylex(); + if (ntoken==R_INTEGER) + { + ptr2[i]=yyint; + } + else break; + } + if (i!=accum) + { + WHEREAMI(); + printf("Number of bitlengths != number of values."); + } + if (ntoken!=R_RBRACKET) + { + WHEREAMI(); + printf("Expected integer or right bracket.\n"); + break; + } + SpecifiedHuffman(ptr,ptr2); + } + else if (ntoken==R_CHROMINANCEDEFAULT) + { + SpecifiedHuffman(ChrominanceDCBits,ChrominanceDCValues); + } + else if (ntoken==R_LUMINANCEDEFAULT) + { + SpecifiedHuffman(LuminanceDCBits,LuminanceDCValues); + } + else + { + WHEREAMI(); + printf("Expected left bracket or DCDEFAULT.\n"); + break; + } + SetDCHuffman(dest); + CImage->NumberDCTables = + MAX(CImage->NumberDCTables,(dest+1)); + ARRAYEND; + break; + } + } +} + +/*NOPROTO*/ +/*END*/ diff --git a/gdcm/Utilities/pvrg/marker.c b/gdcm/Utilities/pvrg/marker.c new file mode 100644 index 0000000..d107cf0 --- /dev/null +++ b/gdcm/Utilities/pvrg/marker.c @@ -0,0 +1,806 @@ +/************************************************************* +Copyright (C) 1990, 1991, 1993 Andy C. Hung, all rights reserved. +PUBLIC DOMAIN LICENSE: Stanford University Portable Video Research +Group. If you use this software, you agree to the following: This +program package is purely experimental, and is licensed "as is". +Permission is granted to use, modify, and distribute this program +without charge for any purpose, provided this license/ disclaimer +notice appears in the copies. No warranty or maintenance is given, +either expressed or implied. In no event shall the author(s) be +liable to you or a third party for any special, incidental, +consequential, or other damages, arising out of the use or inability +to use the program for any purpose (or the loss of data), even if we +have been advised of such possibilities. Any public reference or +advertisement of this source code should refer to it as the Portable +Video Research Group (PVRG) code, and not by any author(s) (or +Stanford University) name. +*************************************************************/ + +/* +************************************************************ +marker.c + +This file contains the Marker library which uses the direct buffer +access routines bgetc... + +************************************************************ +*/ + +/*LABEL marker.c */ + +/*Include files */ +#include "globals.h" +#include "stream.h" +#include "marker.h" +#ifdef SYSV +#include +#endif +#include /* exit */ + +/*PUBLIC*/ +extern void WriteSoi(); +extern void WriteEoi(); +extern void WriteJfif(); +extern void WriteSof(); +extern void WriteDri(); +extern void WriteDqt(); +extern void WriteSos(); +extern void WriteDht(); +extern void ReadSof(); +extern void ReadDqt(); +extern void ReadDht(); +extern void ReadDri(); +extern void ReadDnl(); +extern int CheckMarker(); +extern void CheckScan(); +extern void ReadSos(); +extern void MakeConsistentFrameSize(); +/*PRIVATE*/ + +/* External marker definition */ + +extern FRAME *CFrame; +extern IMAGE *CImage; +extern SCAN *CScan; +extern int NumberMDU; +extern int Loud; +extern int izigzag_index[]; + +#define Zigzag(i) izigzag_index[i] + +/*START*/ + +/*BFUNC + +WriteSoi() puts an SOI marker onto the stream. + +EFUNC*/ + +void WriteSoi() +{ + BEGIN("WriteSoi") + + swbytealign(); + bputc(MARKER_MARKER); + bputc(MARKER_SOI); +} + +/*BFUNC + +WriteEoi() puts an EOI marker onto the stream. + +EFUNC*/ + +void WriteEoi() +{ + BEGIN("WriteEoi") + + swbytealign(); + bputc(MARKER_MARKER); + bputc(MARKER_EOI); +} + +/*BFUNC + +WriteJfif() puts an JFIF APP0 marker onto the stream. This is a +generic 1x1 aspect ratio, no thumbnail specification. + +EFUNC*/ + +void WriteJfif() +{ + BEGIN("WriteJfif") + int Start,End; + + swbytealign(); + bputc(MARKER_MARKER); + bputc(MARKER_APP); + Start = swtell(); /* Find out the start of position. */ + bputw(0); /* Put a 0 down onto the stream. */ + bputc(0x4a); bputc(0x46); bputc(0x49); bputc(0x46); bputc(0x00); + bputc(0x01); bputc(0x02); /*Version 1.02*/ + bputc(0x00); /* No absolute DPI */ + bputw(1); /* Aspect ratio */ + bputw(1); + bputc(0x00); /* No thumbnails */ + bputc(0x00); + + End = swtell(); /* Find out end of the marker. */ + swseek(Start); /* Rewind */ + bputw((End-Start) >> 3); /* Put marker there. */ + if ((Start-End) & 0x7) /* if not byte flush, then problems. */ + { + WHEREAMI(); + printf("Bad frame marker, not byte flush.\n"); + } + swseek(End); +} +/*BFUNC + +WriteSof() puts an SOF marker onto the stream. + +EFUNC*/ + +void WriteSof() +{ + BEGIN("WriteSof") + int i,j,Start,End; + + swbytealign(); + bputc(MARKER_MARKER); + bputc(MARKER_SOF|(CFrame->Type&0xf)); + Start = swtell(); /* Find out the start of position. */ + bputw(0); /* Put a 0 down onto the stream. */ + bputc(CFrame->DataPrecision); + if (!CFrame->InsertDnl) {bputw(CFrame->GlobalHeight);} + else {bputw(0);} + bputw(CFrame->GlobalWidth); + bputc(CFrame->GlobalNumberComponents); + for(i=0;iGlobalNumberComponents;i++) + { + bputc(j=CFrame->cn[i]); /* Store off in index */ + bputn(CFrame->hf[j],CFrame->vf[j]); + bputc(CFrame->tq[j]); + } + End = swtell(); /* Find out end of the marker. */ + swseek(Start); /* Rewind */ + bputw((End-Start) >> 3); /* Put marker there. */ + if ((Start-End) & 0x7) /* if not byte flush, then problems. */ + { + WHEREAMI(); + printf("Bad frame marker, not byte flush.\n"); + } + swseek(End); +} + +/*BFUNC + +WriteDri() writes out a resync (or restart) interval out to the +stream. If unspecified, resync is not enabled. + +EFUNC*/ + +void WriteDri() +{ + BEGIN("WriteDri") + + swbytealign(); + bputc(MARKER_MARKER); + bputc(MARKER_DRI); + bputw(4); /* Constant length of 4 */ + bputw(CFrame->ResyncInterval); +} + +/*BFUNC + +WriteDnl() writes out a number of line marker out to the stream. Note +that we must have defined number of lines before as 0. + +EFUNC*/ + + +void WriteDnl() +{ + BEGIN("WriteDnl") + + swbytealign(); + bputc(MARKER_MARKER); + bputc(MARKER_DNL); + bputw(4); /* Constant length of 4 */ + bputw(CFrame->GlobalHeight); +} + +/*BFUNC + +WriteDqt() writes out the quantization matrices in the CImage +structure. + +EFUNC*/ + +void WriteDqt() +{ + BEGIN("WriteDqt") + int i,j,bignum_p,Start,End,*qmatrix; + + if (!(CScan->NumberQTablesSend)) + return; /* No tables to transmit, then ignore. */ + swbytealign(); + bputc(MARKER_MARKER); + bputc(MARKER_DQT); + Start = swtell(); + bputw(0); + for(i=0;iNumberQTablesSend;i++) + { + qmatrix = CImage->QuantizationMatrices[CScan->sq[i]]; + for(bignum_p=0,j=63;j>=0;j--) + { + if(qmatrix[j]>255) + { + bignum_p=0x10; + break; + } + } + bputc((bignum_p|CScan->sq[i])); /* Precision defined for big numbers */ + if (bignum_p) + { + for(j=0;j<64;j++) + bputw(qmatrix[Zigzag(j)]); + } + else + { + for(j=0;j<64;j++) + bputc(qmatrix[Zigzag(j)]); + } + } + CScan->NumberQTablesSend=0; /* Clear out queue */ + End = swtell(); /* Assume a marker code will follow.*/ + swseek(Start); /* bputc(END_QUANTIZATION_TABLE);*/ + bputw((End-Start) >> 3); + if ((Start-End) & 0x7) + { + WHEREAMI(); + printf("DQT marker not byte flush.\n"); + } + swseek(End); +} + +/*BFUNC + +WriteSos() writes a start of scan marker. + +EFUNC*/ + +void WriteSos() +{ + BEGIN("WriteSos") + int i,Start,End; + + swbytealign(); + bputc(MARKER_MARKER); + bputc(MARKER_SOS); + Start = swtell(); + bputw(0); + bputc(CScan->NumberComponents); + for(i=0;iNumberComponents;i++) + { + bputc(CScan->ci[i]); + bputn(CScan->td[i],CScan->ta[i]); + } + bputc(CScan->SSS); + bputc(CScan->SSE); + bputn(CScan->SAH,CScan->SAL); + End = swtell(); + swseek(Start); + bputw((End-Start) >> 3); + if ((Start-End) & 0x7) + { + WHEREAMI(); + printf("Bad scan marker not byte flush.\n"); + } + swseek(End); +} + +/*BFUNC + +WriteDht() writes out the Huffman tables to send. + +EFUNC*/ + +void WriteDht() +{ + BEGIN("WriteDht") + int i,Start,End; + + if (!(CScan->NumberDCTablesSend) && !(CScan->NumberACTablesSend)) + return; /* No tables to transmit, then ignore. */ + swbytealign(); + bputc(MARKER_MARKER); + bputc(MARKER_DHT); + Start = swtell(); + bputw(0); + for(i=0;iNumberDCTablesSend;i++) + { + bputc(CScan->sd[i]); + UseDCHuffman(CScan->sd[i]); + WriteHuffman(); + } + for(i=0;iNumberACTablesSend;i++) + { + bputc(CScan->sa[i]|0x10); + UseACHuffman(CScan->sa[i]); + WriteHuffman(); + } + CScan->NumberDCTablesSend=0; /* Clear out send queue */ + CScan->NumberACTablesSend=0; + /* + We end on a new marker... so an end of code table is unnecessary. + bputc(END_CODE_TABLE); + */ + End = swtell(); + swseek(Start); + bputw((End-Start) >> 3); + if ((Start-End) & 0x7) + { + WHEREAMI(); + printf("Bad scan marker not byte flush.\n"); + } + swseek(End); +} + + +/*BFUNC + + ReadSof() reads a start of frame marker from the stream. We assume that + the first two bytes (marker prefix) have already been stripped. + + EFUNC*/ + +void ReadSof(Type) + int Type; +{ + BEGIN("ReadSof") + int i,j,Length,Start,End,rb; + + Start = srtell(); + Length = bgetw(); + if (Loud > MUTE) + printf("Frame Length %d\n",Length); + CFrame->Type=Type; + CFrame->DataPrecision = bgetc(); + CFrame->GlobalHeight = bgetw(); + CFrame->GlobalWidth = bgetw(); + + for(i=0;ihf[i]=CFrame->vf[i]=CFrame->tq[i]=0; + CFrame->GlobalNumberComponents = bgetc(); + for(i=0;iGlobalNumberComponents;i++) + { + j = bgetc(); + rb = bgetc(); + CFrame->cn[i] = j; + CFrame->hf[j] = hinyb(rb); + CFrame->vf[j] = lonyb(rb); + CFrame->tq[j] = bgetc(); + } + MakeConsistentFrameSize(); + End = srtell(); + if ((End-Start) != (Length<<3)) + { + WHEREAMI(); + printf("Bad read frame length.\n"); + } + if (Loud > MUTE) + { + PrintImage(); + PrintFrame(); + } +} + +/*BFUNC + + ReadDqt() reads a quantization table marker from the stream. + The first two bytes have been stripped off. + + EFUNC*/ + +void ReadDqt() +{ + BEGIN("ReadDqt") + int i,Length,Qget,Index,Precision,Start,End; + + Start = srtell(); + Length = bgetw(); + if (Loud > MUTE) + printf("Quantization Length %d\n",Length); + while((Qget=bgetc()) != END_QUANTIZATION_TABLE) + { + Index = Qget & 0xf; + Precision = (Qget >> 4)&0xf; + if (Precision > 1) + { + printf("Bad Precision: %d in Quantization Download\n", + Precision); + printf("*** Dumping Image ***\n"); + PrintImage(); + printf("*** Dumping Frame ***\n"); + PrintFrame(); + exit(ERROR_MARKER); + } /* Load in q-matrices */ + CImage->QuantizationMatrices[Index] = (int *) calloc(65,sizeof(int)); + if (Precision) /* If precision then word quantization*/ + { + for(i=0;i<64;i++) + { + if (!(CImage->QuantizationMatrices[Index][Zigzag(i)]=bgetw())) + { + printf("marker.c:ReadDqt: Quantization value of zero.\n"); + if (i) + { + printf("marker.c:ReadDqt: Changing to i-1.\n"); + CImage->QuantizationMatrices[Index][Zigzag(i)]= + CImage->QuantizationMatrices[Index][Zigzag(i-1)]; + } + else + { + printf("marker.c:ReadDqt: Changing to 16.\n"); + CImage->QuantizationMatrices[Index][Zigzag(i)]=16; + } + } + } + } + else /* Otherwise byte quantization */ + { + for(i=0;i<64;i++) + { + if (!(CImage->QuantizationMatrices[Index][Zigzag(i)]=bgetc())) + { + printf("marker.c:ReadDqt: Quantization value of zero.\n"); + if (i) + { + printf("marker.c:ReadDqt: Changing to i-1.\n"); + CImage->QuantizationMatrices[Index][Zigzag(i)]= + CImage->QuantizationMatrices[Index][Zigzag(i-1)]; + } + else + { + printf("marker.c:ReadDqt: Changing to 16.\n"); + CImage->QuantizationMatrices[Index][Zigzag(i)]=16; + } + } + } + } + } + bpushc(END_QUANTIZATION_TABLE); + End = srtell(); + if ((End-Start) != (Length<<3)) + { + WHEREAMI(); + printf("Bad DQT read length.\n"); + } + if (Loud > MUTE) + { + PrintImage(); + PrintFrame(); + } +} + + +/*BFUNC + + ReadDht() reads a Huffman marker from the stream. We assume that the + first two bytes have been stripped off. + + EFUNC*/ + +void ReadDht() +{ + BEGIN("ReadDht") + int Index,Where,Length,Start,End; + + Start = srtell(); + Length = bgetw(); + if (Loud > MUTE) + printf("Define Huffman length %d\n",Length); + while((Index = bgetc()) != END_CODE_TABLE) + { + Where = (Index >> 4) & 0x0f; /* Find location to place it in */ + Index = Index & 0x0f; + MakeXhuff(); /* Make Huffman table */ + MakeDhuff(); + ReadHuffman(); + if (Where) + { + SetACHuffman(Index); /* Set current Huffman limit */ + CImage->NumberACTables = MAX(CImage->NumberACTables,(Index+1)); + } + else + { + SetDCHuffman(Index); + CImage->NumberDCTables = MAX(CImage->NumberDCTables,(Index+1)); + } + } + bpushc(END_CODE_TABLE); + End = srtell(); + if ((End-Start) != (Length<<3)) + { + WHEREAMI(); + printf("Bad DHT length.\n"); + } + if (Loud > MUTE) + PrintImage(); +} + +/*BFUNC + + ReadDri() reads a resync interval marker from the stream. We assume + the first two bytes are stripped off. + + EFUNC*/ + +void ReadDri() +{ + BEGIN("ReadDri") + int Length; + + if ((Length=bgetw())!=4) /* Constant length of 4 */ + { + WHEREAMI(); + printf("Bad length %d, should be 4.\n",Length); + } + CFrame->ResyncInterval = bgetw(); +} + +/*BFUNC + + ReadDnl() reads a number of lines marker from the stream. The first + two bytes should be stripped off. + + EFUNC*/ + +void ReadDnl() +{ + BEGIN("ReadDnl") + int Length; + + if ((Length=bgetw())!=4) /* Constant length of 4 */ + printf("marker.c:ReadDnl: Bad length %d, should be 4.\n",Length); + CFrame->GlobalHeight = bgetw(); + if (CScan->NumberComponents) + { + MakeConsistentFrameSize(); + CheckScan(); + ResizeIob(); + if (CFrame->GlobalHeight) + { + InstallIob(0); + if (CFrame->Type==3) + NumberMDU = CScan->MDUWide*CScan->MDUHigh; + else + NumberMDU = CScan->MDUWide*CScan->MDUHigh; + } + else + NumberMDU = -1; + } +} + +/*BFUNC + +CheckMarker() checks to see if there is a marker in the stream ahead. +This function presumes that ungetc is not allowed to push more than +one byte back. + +EFUNC*/ + +int CheckMarker() +{ + BEGIN("CheckMarker") + int Length; + int v1; + + Length = brtell(); + v1=bgetw(); + + if (v1>=0xffc0) + { + brseek(Length,0L); + return(v1&0xff); + } + brseek(Length,0L); + return(0); +} + +/*BFUNC + +ReadSos() reads in a start of scan from the stream. The first two +bytes should have been stripped off. + +EFUNC*/ + +void ReadSos() +{ + BEGIN("ReadSos") + int i,Length,Start,End,rb; + + Start = srtell(); + Length = bgetw(); + if (Loud > MUTE) + { + WHEREAMI(); + printf("Scan length %d\n",Length); + } + CScan->NumberComponents = bgetc(); + for(i=0;iNumberComponents;i++) + { + CScan->ci[i] = bgetc(); + rb = bgetc(); + CScan->td[i] = hinyb(rb); + CScan->ta[i] = lonyb(rb); + } + CScan->SSS = bgetc(); + CScan->SSE = bgetc(); + rb = bgetc(); + CScan->SAH = hinyb(rb); + CScan->SAL = lonyb(rb); + + End = srtell(); + if ((End-Start) != (Length<<3)) + { + WHEREAMI(); + printf("Bad scan length.\n"); + } + if (Loud > MUTE) + PrintScan(); + MakeConsistentFileNames(); /* A Scan marker always makes new files */ + CheckValidity(); + CheckBaseline(); + CheckScan(); + /* Create the io buffer structure */ + + if (CFrame->Type==3) + { + MakeIob(IOB_LINE,O_RDWR | O_CREAT, + ((CFrame->DataPrecision>8)?2:1)); + if (CFrame->GlobalHeight) + { + InstallIob(0); + NumberMDU = CScan->MDUWide*CScan->MDUHigh; + } + else NumberMDU = -1; + } + else + { + MakeIob(IOB_BLOCK,O_RDWR | O_CREAT | O_TRUNC, + ((CFrame->DataPrecision>8)?2:1)); + if (CFrame->GlobalHeight) + { + InstallIob(0); + NumberMDU = CScan->MDUWide*CScan->MDUHigh; + } + else NumberMDU = -1; + } + + /* Sometimes rewinding is necessary */ + /* for(i=0;iNumberComponents;i++) + { + InstallIob(i); + RewindIob(); + } */ + ResetCodec(); /* Reset codec for information */ +} + +/*BFUNC + +CheckScan() sets the MDU dimensions for the CScan structure. + +EFUNC*/ + +void CheckScan() +{ + int i; + + if (CScan->NumberComponents==1) + { + i = (((CFrame->GlobalWidth*CFrame->hf[CScan->ci[0]])-1)/CFrame->Maxh)+1; + if (CFrame->Type!=3) + i = ((i-1)/8)+1; + CScan->MDUWide = i; + + i = (((CFrame->GlobalHeight*CFrame->vf[CScan->ci[0]])-1)/CFrame->Maxv)+1; + if (CFrame->Type!=3) + i = ((i-1)/8)+1; + CScan->MDUHigh = i; + } + else + { + CScan->MDUWide=CFrame->MDUWide; + CScan->MDUHigh=CFrame->MDUHigh; + } +} + +/*BFUNC + +MakeConsistentFrameSize() makes a consistent frame size for all of the +horizontal and vertical frequencies read. + +EFUNC*/ + +void MakeConsistentFrameSize() +{ + BEGIN("MakeConsistentFrameSize") + int i,Maxh,Maxv; + int TestWide, TestHigh; + + Maxv = Maxh = 1; + for(i=0;ivf[i] > Maxv) + Maxv = CFrame->vf[i]; + if (CFrame->hf[i] > Maxh) + Maxh = CFrame->hf[i]; + } + + for(i=0;ihf[i]) + { + if (!CFrame->Width[i]) + CFrame->Width[i] = + (((CFrame->GlobalWidth*CFrame->hf[i])-1)/Maxh)+1; + if (!CFrame->Height[i]) + CFrame->Height[i] = + (((CFrame->GlobalHeight*CFrame->vf[i])-1)/Maxv)+1; + } + } + + CFrame->Maxv = Maxv; CFrame->Maxh = Maxh; + + CFrame->MDUWide = (CFrame->GlobalWidth-1)/Maxh +1; + if (CFrame->GlobalHeight) + CFrame->MDUHigh = (CFrame->GlobalHeight-1)/Maxv +1; + else + CFrame->MDUHigh = 0; + + if (CFrame->Type!=3) + { + CFrame->MDUWide= (CFrame->MDUWide-1)/8 +1; + if (CFrame->MDUHigh) + CFrame->MDUHigh= (CFrame->MDUHigh-1)/8 +1; + } + + for(i=0;ihf[i]) + { + TestWide = ((CFrame->Width[i]-1)/(CFrame->hf[i]))+1; + if (CFrame->Type!=3) TestWide= (TestWide-1)/8 +1; + + if (CFrame->MDUWide!=TestWide) + { + WHEREAMI(); + printf("Inconsistent frame width.\n"); + printf("Component[%dx%d]\n", + CFrame->Width[i],CFrame->Height[i]); + printf("MDU Wide: Image, Component %d!= %d.\n", + CFrame->MDUWide,TestWide); + } + if (CFrame->MDUHigh) + { + TestHigh = ((CFrame->Height[i]-1)/(CFrame->vf[i]))+1; + if (CFrame->Type!=3) TestHigh= (TestHigh-1)/8 +1; + if (CFrame->MDUHigh!=TestHigh) + { + WHEREAMI(); + printf("Inconsistent frame height.\n"); + printf("Component[%dx%d]\n", + CFrame->Width[i],CFrame->Height[i]); + printf("MDU High: Image, Component %d!= %d.\n", + CFrame->MDUHigh,TestHigh); + } + } + } + } +} + + + +/*END*/ diff --git a/gdcm/Utilities/pvrg/marker.h b/gdcm/Utilities/pvrg/marker.h new file mode 100644 index 0000000..c5b05c5 --- /dev/null +++ b/gdcm/Utilities/pvrg/marker.h @@ -0,0 +1,57 @@ +/************************************************************* +Copyright (C) 1990, 1991, 1993 Andy C. Hung, all rights reserved. +PUBLIC DOMAIN LICENSE: Stanford University Portable Video Research +Group. If you use this software, you agree to the following: This +program package is purely experimental, and is licensed "as is". +Permission is granted to use, modify, and distribute this program +without charge for any purpose, provided this license/ disclaimer +notice appears in the copies. No warranty or maintenance is given, +either expressed or implied. In no event shall the author(s) be +liable to you or a third party for any special, incidental, +consequential, or other damages, arising out of the use or inability +to use the program for any purpose (or the loss of data), even if we +have been advised of such possibilities. Any public reference or +advertisement of this source code should refer to it as the Portable +Video Research Group (PVRG) code, and not by any author(s) (or +Stanford University) name. +*************************************************************/ + +/* +************************************************************ +marker.h + +Some basic definitions of commonly occurring markers. + +************************************************************ +*/ + +#ifndef MARKER_DONE +#define MARKER_DONE + +#define END_QUANTIZATION_TABLE 0xFF +#define END_CODE_TABLE 0xFF + +#define MARKER_MARKER 0xff +#define MARKER_FIL 0xff + +#define MARKER_SOI 0xd8 +#define MARKER_EOI 0xd9 +#define MARKER_SOS 0xda +#define MARKER_DQT 0xdb +#define MARKER_DNL 0xdc +#define MARKER_DRI 0xdd +#define MARKER_DHP 0xde +#define MARKER_EXP 0xdf + +#define MARKER_DHT 0xc4 + +#define MARKER_SOF 0xc0 +#define MARKER_RSC 0xd0 +#define MARKER_APP 0xe0 +#define MARKER_JPG 0xf0 + +#define MARKER_RSC_MASK 0xf8 + +int CheckMarker(); + +#endif diff --git a/gdcm/Utilities/pvrg/param.h b/gdcm/Utilities/pvrg/param.h new file mode 100644 index 0000000..b3e9c18 --- /dev/null +++ b/gdcm/Utilities/pvrg/param.h @@ -0,0 +1,112 @@ +/************************************************************* +Copyright (C) 1990, 1991, 1993 Andy C. Hung, all rights reserved. +PUBLIC DOMAIN LICENSE: Stanford University Portable Video Research +Group. If you use this software, you agree to the following: This +program package is purely experimental, and is licensed "as is". +Permission is granted to use, modify, and distribute this program +without charge for any purpose, provided this license/ disclaimer +notice appears in the copies. No warranty or maintenance is given, +either expressed or implied. In no event shall the author(s) be +liable to you or a third party for any special, incidental, +consequential, or other damages, arising out of the use or inability +to use the program for any purpose (or the loss of data), even if we +have been advised of such possibilities. Any public reference or +advertisement of this source code should refer to it as the Portable +Video Research Group (PVRG) code, and not by any author(s) (or +Stanford University) name. +*************************************************************/ +/* +************************************************************ +param.h + +The basic system parameters are kept here. + +************************************************************ +*/ + +#ifndef PARAM_DONE +#define PARAM_DONE + +/* This is the general definition for the size and width of the + JPEG blocks. Do not change. + */ +#define BLOCKSIZE 64 +#define BLOCKWIDTH 8 +#define BLOCKHEIGHT 8 + +/* Definitions for JPEG and internal compatibility. */ + +#define MAXIMUM_HORIZONTAL_FREQUENCY 15 +#define MAXIMUM_VERTICAL_FREQUENCY 15 + +#define MAXIMUM_JPEG_HORIZONTAL_FREQUENCY 4 +#define MAXIMUM_JPEG_VERTICAL_FREQUENCY 4 + +#define MINIMUM_BUFFERSIZE 16 + +#define MAXIMUM_UNSIGNED16 65535 +#define MAXIMUM_RESYNC_INTERVAL 65535 +#define MAXIMUM_BUFFERSIZE 65535 +#define MAXIMUM_IMAGE_HEIGHT 65535 +#define MAXIMUM_IMAGE_WIDTH 65535 + +/* Devices: Number of active devices operating at one time. + Quantization tables, huffman tables, etc. are all devices. + */ +#define MAXIMUM_DEVICES 16 + +/* Sources: Number of active sources in stream at one time. + A source is one interleave possibility. + */ +#define MAXIMUM_SOURCES 16 + +/* Components: Number of components that can be active per frame. + A component consists of one complete plane of the image. +*/ +#define MAXIMUM_COMPONENTS 256 + +/* Q value as defined by archaic and now defunct F-Factor: + Used to rescale quantization matrices. + */ + +#define Q_PRECISION 50 + +/* Scan component threshold is the maximum number of components put +in per scan */ + +#define SCAN_COMPONENT_THRESHOLD 4 + +/* Mask to be used for creating files. */ +#define UMASK 0666 /* Octal */ + +/* Buffersize is used as the default I/O buffer. A smaller size ensures + less storage space. A larger size requires more storage space. + 256 seems like a good number for smaller machines, but for machines + with greater than 0.5 MB of memory, 1024 would be better because + it reduces on the number of seeks necessary. Helpful for macro-sized + words such as 16 bit or 24 bit to have a proper multiple of such + word. + */ +#define BUFFERSIZE 256 + +/* Lossless Buffersize is a variable that is kept for the lossless + streams. It can be any positive number, though a larger number + will speed up the processing of information. A large number also + will cause (MAXIMUM_SOURCES)*(LOSSLESSBUFFERSIZE)*sizeof(int) + storage consumption. To ensure proper operation, this should + be equivalent to the BUFFERSIZE variable * dimensions of the + scan frequencies so that two fetches are not required for filling + the lossless buffer. (It would make having the upper buffer useless). + The minimum number is (MAX_HF+1)*(MAX_VF+1) */ + +#define LOSSLESSBUFFERSIZE 289 + +/* Number of streams is the number of active read/write streams possible. + For all jpeg operations, this value is 1.*/ + +#define NUMBER_OF_STREAMS 1 + +#define ISO_DCT +#define LEE_DCT + +#endif diff --git a/gdcm/Utilities/pvrg/prototypes.h b/gdcm/Utilities/pvrg/prototypes.h new file mode 100644 index 0000000..d1e9374 --- /dev/null +++ b/gdcm/Utilities/pvrg/prototypes.h @@ -0,0 +1,198 @@ +/************************************************************* +Copyright (C) 1990, 1991, 1993 Andy C. Hung, all rights reserved. +PUBLIC DOMAIN LICENSE: Stanford University Portable Video Research +Group. If you use this software, you agree to the following: This +program package is purely experimental, and is licensed "as is". +Permission is granted to use, modify, and distribute this program +without charge for any purpose, provided this license/ disclaimer +notice appears in the copies. No warranty or maintenance is given, +either expressed or implied. In no event shall the author(s) be +liable to you or a third party for any special, incidental, +consequential, or other damages, arising out of the use or inability +to use the program for any purpose (or the loss of data), even if we +have been advised of such possibilities. Any public reference or +advertisement of this source code should refer to it as the Portable +Video Research Group (PVRG) code, and not by any author(s) (or +Stanford University) name. +*************************************************************/ +/* +************************************************************ +prototypes.h + +This file contains the functional prototypes for typechecking. + +************************************************************ +*/ + +#ifndef PROTOTYPES_DONE +#define PROTOTYPES_DONE + +/* jpeg.c */ + + +extern void PrintImage(); +extern void PrintFrame(); +extern void PrintScan(); +extern void MakeImage(); +extern void MakeFrame(); +extern void MakeScanFrequency(); +extern void MakeScan(); +extern void MakeConsistentFileNames(); +extern void CheckValidity(); +extern int CheckBaseline(); +extern void ConfirmFileSize(); +extern void JpegQuantizationFrame(); +extern void JpegDefaultHuffmanScan(); +extern void JpegFrequencyScan(); +extern void JpegCustomScan(); +extern void JpegEncodeScan(); +extern void JpegLosslessFrequencyScan(); +extern void JpegLosslessEncodeScan(); + +/* codec.c */ + +extern void FrequencyAC(); +extern void EncodeAC(); +extern void DecodeAC(); +extern int DecodeDC(); +extern void FrequencyDC(); +extern void EncodeDC(); +extern void ResetCodec(); +extern void ClearFrameFrequency(); +extern void AddFrequency(); +extern void InstallFrequency(); +extern void InstallPrediction(); +extern void PrintACEhuff(); +extern void PrintDCEhuff(); +extern int SizeACEhuff(); +extern int SizeDCEhuff(); + +extern int LosslessDecodeDC(); +extern void LosslessFrequencyDC(); +extern void LosslessEncodeDC(); + +/* huffman.c */ + +extern void MakeHuffman(); +extern void SpecifiedHuffman(); +extern void MakeDecoderHuffman(); +extern void ReadHuffman(); +extern void WriteHuffman(); +extern int DecodeHuffman(); +extern void EncodeHuffman(); +extern void MakeXhuff(); +extern void MakeEhuff(); +extern void MakeDhuff(); +extern void UseACHuffman(); +extern void UseDCHuffman(); +extern void SetACHuffman(); +extern void SetDCHuffman(); +extern void PrintHuffman(); +extern void PrintTable(); + +/* io.c */ + + +extern void ReadBlock(); +extern void WriteBlock(); +extern void ResizeIob(); +extern void RewindIob(); +extern void FlushIob(); +extern void SeekEndIob(); +extern void CloseIob(); +extern void MakeIob(); +extern void PrintIob(); +extern int NumberBlocksIob(); +extern int NumberBlockMDUIob(); +extern void InstallIob(); +extern void TerminateFile(); + +extern int NumberLineMDUIob(); +extern void ReadLine(); +extern void ReadPreambleLine(); +extern void WriteLine(); +extern int LineNumberMDUWideIob(); +extern int LineNumberMDUHighIob(); +extern void LineResetBuffers(); + +/* chendct.c */ + +extern void ChenDct(); +extern void ChenIDct(); + +/* leedct.c */ + +extern void LeeIDct(); +extern void LeeDct(); + +/* lexer.c */ + +extern void initparser(); +extern void parser(); + +/* marker.c */ + +extern void WriteSoi(); +extern void WriteEoi(); +extern void WriteJfif(); +extern void WriteSof(); +extern void WriteDri(); +extern void WriteDqt(); +extern void WriteSos(); +extern void WriteDnl(); +extern void WriteDht(); +extern void ReadSof(); +extern void ReadDqt(); +extern void ReadDht(); +extern void ReadDri(); +extern void ReadDnl(); +extern void ReadSos(); +extern void CheckScan(); +extern void MakeConsistentFrameSize(); + +/* stream.c */ + +extern void initstream(); +extern void pushstream(); +extern void popstream(); +extern void bpushc(); +extern int bgetc(); +extern void bputc(); +extern void mropen(); +extern void mrclose(); +extern void mwopen(); +extern void swbytealign(); +extern void mwclose(); +extern long mwtell(); +extern long mrtell(); +extern void mwseek(); +extern void mrseek(); +extern int megetb(); +extern void meputv(); +extern int megetv(); +extern int DoMarker(); +extern int ScreenMarker(); +extern void Resync(); +extern void WriteResync(); +extern int ReadResync(); +extern int ScreenAllMarker(); +extern int DoAllMarker(); + +/* transform.c */ + +extern void ReferenceDct(); +extern void ReferenceIDct(); +extern void TransposeMatrix(); +extern void Quantize(); +extern void IQuantize(); +extern void PreshiftDctMatrix(); +extern void PostshiftIDctMatrix(); +extern void BoundDctMatrix(); +extern void BoundIDctMatrix(); +extern void ZigzagMatrix(); +extern void IZigzagMatrix(); +extern int *ScaleMatrix(); +extern void PrintMatrix(); +extern void ClearMatrix(); + +#endif diff --git a/gdcm/Utilities/pvrg/pvrgjpeg.c b/gdcm/Utilities/pvrg/pvrgjpeg.c new file mode 100644 index 0000000..72675ba --- /dev/null +++ b/gdcm/Utilities/pvrg/pvrgjpeg.c @@ -0,0 +1,25 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +/* simple wrapper around the fake pvrg 'main' function, so that we can still + * build the library and a separate executable + */ + +/* forward declaration */ +int pvrgmain(int argc, char *argv[]); + +int main(int argc, char *argv[]) +{ + return pvrgmain(argc, argv); +} diff --git a/gdcm/Utilities/pvrg/stream.c b/gdcm/Utilities/pvrg/stream.c new file mode 100644 index 0000000..caf82d3 --- /dev/null +++ b/gdcm/Utilities/pvrg/stream.c @@ -0,0 +1,1015 @@ +/************************************************************* +Copyright (C) 1990, 1991, 1993 Andy C. Hung, all rights reserved. +PUBLIC DOMAIN LICENSE: Stanford University Portable Video Research +Group. If you use this software, you agree to the following: This +program package is purely experimental, and is licensed "as is". +Permission is granted to use, modify, and distribute this program +without charge for any purpose, provided this license/ disclaimer +notice appears in the copies. No warranty or maintenance is given, +either expressed or implied. In no event shall the author(s) be +liable to you or a third party for any special, incidental, +consequential, or other damages, arising out of the use or inability +to use the program for any purpose (or the loss of data), even if we +have been advised of such possibilities. Any public reference or +advertisement of this source code should refer to it as the Portable +Video Research Group (PVRG) code, and not by any author(s) (or +Stanford University) name. +*************************************************************/ + +/* +************************************************************ +stream.c + +This file is used for management of bit-aligned files. + +************************************************************ +*/ + +/*LABEL stream.c */ + +/* Include files */ + +#include "globals.h" +#include "marker.h" +#include "stream.h" +#include /* exit */ + +/*PUBLIC*/ + +extern void initstream(); +extern void pushstream(); +extern void popstream(); +extern void bpushc(); +extern int bgetc(); +extern void bputc(); +extern void mropen(); +extern void mrclose(); +extern void mwopen(); +extern void swbytealign(); +extern void mwclose(); +extern long mwtell(); +extern long mrtell(); +extern void mwseek(); +extern void mrseek(); +extern int megetb(); +extern void meputv(); +extern int megetv(); +extern int DoMarker(); +extern int ScreenMarker(); +extern void Resync(); +extern void WriteResync(); +extern int ReadResync(); +extern int ScreenAllMarker(); +extern int DoAllMarker(); + +static int pgetc(); + +/*PRIVATE*/ + +/* External values */ + +extern int ErrorValue; +extern IMAGE *CImage; +extern int Robust; /* Whether to ignore scan markers and such */ + +/* Masks */ +int bit_set_mask[] = { /* This is 2^i at ith position */ +0x00000001,0x00000002,0x00000004,0x00000008, +0x00000010,0x00000020,0x00000040,0x00000080, +0x00000100,0x00000200,0x00000400,0x00000800, +0x00001000,0x00002000,0x00004000,0x00008000, +0x00010000,0x00020000,0x00040000,0x00080000, +0x00100000,0x00200000,0x00400000,0x00800000, +0x01000000,0x02000000,0x04000000,0x08000000, +0x10000000,0x20000000,0x40000000,0x80000000}; +int lmask[] = { /* This is 2^{i+1}-1 */ +0x00000001,0x00000003,0x00000007,0x0000000f, +0x0000001f,0x0000003f,0x0000007f,0x000000ff, +0x000001ff,0x000003ff,0x000007ff,0x00000fff, +0x00001fff,0x00003fff,0x00007fff,0x0000ffff, +0x0001ffff,0x0003ffff,0x0007ffff,0x000fffff, +0x001fffff,0x003fffff,0x007fffff,0x00ffffff, +0x01ffffff,0x03ffffff,0x07ffffff,0x0fffffff, +0x1fffffff,0x3fffffff,0x7fffffff,0xffffffff}; + +#ifdef __OLD +int umask[] = { /* This is -1 XOR 2^{i+1}-1 */ +0xfffffffe,0xfffffffc,0xfffffff8,0xfffffff0, +0xffffffe0,0xffffffc0,0xffffff80,0xffffff00, +0xfffffe00,0xfffffc00,0xfffff800,0xfffff000, +0xffffe000,0xffffc000,0xffff8000,0xffff0000, +0xfffe0000,0xfffc0000,0xfff80000,0xfff00000, +0xffe00000,0xffc00000,0xff800000,0xff000000, +0xfe000000,0xfc000000,0xf8000000,0xf0000000, +0xe0000000,0xc0000000,0x80000000,0x00000000}; +#endif + +/* Internally kept variables for global flag communication */ + +int CleartoResync=0; /* Return black blocks until last Resync reached*/ +int ResyncEnable=0; /* This enables the resync feature */ +int ResyncCount=0; /* This is the resync marker count */ +int LastKnownResync=0; /* This is the index of the next Resync */ +int EndofFile=0; /* End of file means read stream exhausted */ +int EndofImage=0; /* End of image means EOI image marker found */ + +/* Static variables that keep internal state. */ + +static FILE *swout; +static FILE *srin; +static unsigned int current_write_byte; +static unsigned int current_read_byte; +static unsigned int marker_read_byte; +static int read_position; +static int write_position; +static int InResync=0; + +/* Stack of variables to handle multiple streams. */ + +static int Stack_Stream_Current= -1; +static int Stack_Stream_Active[NUMBER_OF_STREAMS]; +static int Stack_Stream_CleartoResync[NUMBER_OF_STREAMS]; +static int Stack_Stream_ResyncEnable[NUMBER_OF_STREAMS]; +static int Stack_Stream_ResyncCount[NUMBER_OF_STREAMS]; +static int Stack_Stream_LastKnownResync[NUMBER_OF_STREAMS]; +static int Stack_Stream_EndofFile[NUMBER_OF_STREAMS]; +static int Stack_Stream_EndofImage[NUMBER_OF_STREAMS]; +static FILE * Stack_Stream_swout[NUMBER_OF_STREAMS]; +static FILE * Stack_Stream_srin[NUMBER_OF_STREAMS]; +static unsigned int Stack_Stream_current_write_byte[NUMBER_OF_STREAMS]; +static unsigned int Stack_Stream_current_read_byte[NUMBER_OF_STREAMS]; +static unsigned int Stack_Stream_marker_read_byte[NUMBER_OF_STREAMS]; +static int Stack_Stream_read_position[NUMBER_OF_STREAMS]; +static int Stack_Stream_write_position[NUMBER_OF_STREAMS]; + +/*START*/ + +/* STACK STREAM LIBRARY */ + +/*BFUNC + +initstream() initializes all of the stream variables-- especially the +stack. Not necessary to call unless you wish to use more than one +stream variable. + +EFUNC*/ + +void initstream() +{ + BEGIN("initstream") + int i; + + Stack_Stream_Current= -1; + for(i=0;i=0) pushstream(); + CleartoResync=Stack_Stream_CleartoResync[index]; + ResyncEnable=Stack_Stream_ResyncEnable[index]; + ResyncCount=Stack_Stream_ResyncCount[index]; + LastKnownResync=Stack_Stream_LastKnownResync[index]; + EndofFile=Stack_Stream_EndofFile[index]; + EndofImage=Stack_Stream_EndofImage[index]; + swout=Stack_Stream_swout[index]; + srin=Stack_Stream_srin[index]; + current_write_byte=Stack_Stream_current_write_byte[index]; + current_read_byte=Stack_Stream_current_read_byte[index]; + marker_read_byte=Stack_Stream_marker_read_byte[index]; + read_position=Stack_Stream_read_position[index]; + write_position=Stack_Stream_write_position[index]; +} + +/* THAT'S ALL FOR THE STACK STREAM LIBRARY! */ + +/* BUFFER LIBRARY */ + +/*BFUNC + +brtell() is used to find the location in the read stream. + +EFUNC*/ + +int brtell() + {BEGIN("brtell") return(ftell(srin));} + +/*BFUNC + +brseek() is used to find the location in the read stream. + +EFUNC*/ + +int brseek(offset,ptr) + int offset; + int ptr; + {BEGIN("brseek") return(fseek(srin,offset,ptr));} + +/*BFUNC + +bpushc() is used to unget a character value from the current stream. + +EFUNC*/ + +void bpushc(value) + int value; + {BEGIN("bpushc") ungetc(value,srin);} + +/*BFUNC + +bgetc() gets a character from the stream. It is byte aligned and +bypasses bit buffering. + +EFUNC*/ + +int bgetc() + {BEGIN("bgetc") return(getc(srin));} + +/*BFUNC + +bgetw() gets a msb word from the stream. + +EFUNC*/ + +int bgetw() + {BEGIN("bgetw") int fu; fu=getc(srin); return ((fu << 8)| getc(srin));} + +/*BFUNC + +bputc() puts a character into the stream. It is byte aligned and +bypasses the bit buffering. + +EFUNC*/ + +void bputc(c) + int c; + {BEGIN("bputc") putc(c,swout);} + +/* PROTECTED MARKER GETS AND FETCHES */ + +/*BFUNC + +pgetc() gets a character onto the stream but it checks to see +if there are any marker conflicts. + +EFUNC*/ + +static int pgetc() +{ + BEGIN("pgetc") + int temp; + + if (CleartoResync) /* If cleartoresync do not read from stream */ + { + return(0); + } + if ((temp = bgetc())==MARKER_MARKER) /* If MARKER then */ + { + if ((temp = bgetc())) /* if next is not 0xff, then marker */ + { + WHEREAMI(); + printf("Unanticipated marker detected.\n"); + if (!ResyncEnable) DoAllMarker(); /* If no resync enabled */ + } /* could be marker */ + else + { + return(MARKER_MARKER); /* else truly 0xff */ + } + } + return(temp); +} + +/*BMACRO + +pputc(stream,) + ) puts a value onto the stream; puts a value onto the stream, appending an extra '0' if it +matches the marker code. + +EMACRO*/ + +#define pputc(val) {bputc(val); if (val==MARKER_MARKER) bputc(0);} + +/* MAIN ROUTINES */ + +/*BFUNC + +mropen() opens a given filename as the input read stream. + +EFUNC*/ + +void mropen(filename,index) + char *filename; + int index; +{ + BEGIN("mropen") + + if (Stack_Stream_Active[index]) + { + WHEREAMI(); + printf("%s cannot be opened because %d stream slot filled.\n", + filename,index); + exit(ERROR_BOUNDS); + } + if (Stack_Stream_Current!=index) pushstream(); + current_read_byte=0; + read_position = -1; + if ((srin = fopen(filename,"rb"))==NULL) + { + WHEREAMI(); + printf("Cannot read input file %s.\n", + filename); + exit(ERROR_INIT_FILE); + } + CleartoResync=0; + ResyncEnable=0; + ResyncCount=0; + LastKnownResync=0; + EndofFile=0; + EndofImage=1; /* We start after "virtual" end of previous image */ + Stack_Stream_Current= index; + Stack_Stream_Active[index]=1; +} + +/*BFUNC + +mrclose() closes the input read stream. + +EFUNC*/ + +void mrclose() +{ + BEGIN("mrclose") + fclose(srin); + srin=NULL; + if (swout==NULL) + { + Stack_Stream_Active[Stack_Stream_Current]=0; + Stack_Stream_Current= -1; + } +} + +/*BFUNC + +mwopen() opens the stream for writing. Note that reading and +writing can occur simultaneously because the read and write +routines are independently buffered. + +EFUNC*/ + +void mwopen(filename,index) + char *filename; + int index; +{ + BEGIN("mwopen") + + if (Stack_Stream_Active[index]) + { + WHEREAMI(); + printf("%s cannot be opened because %d stream slot filled.\n", + filename,index); + exit(ERROR_BOUNDS); + } + if ((Stack_Stream_Current!=index)) pushstream(); + current_write_byte=0; + write_position=7; + if ((swout = fopen(filename,"wb+"))==NULL) + { + WHEREAMI(); + printf("Cannot open output file %s.\n",filename); + exit(ERROR_INIT_FILE); + } + Stack_Stream_Current= index; + Stack_Stream_Active[index]=1; +} + +/*BFUNC + +swbytealign() flushes the current bit-buffered byte out to the stream. +This is used before marker codes. + +EFUNC*/ + +void swbytealign() +{ + BEGIN("swbytealign") + + if (write_position !=7) + { + current_write_byte |= lmask[write_position]; + pputc(current_write_byte); + write_position=7; + current_write_byte=0; + } +} + +/*BFUNC + +mwclose() closes the stream that has been opened for writing. + +EFUNC*/ + +void mwclose() +{ + BEGIN("mwclose") + + swbytealign(); + fclose(swout); + swout=NULL; + if (srin==NULL) + { + Stack_Stream_Active[Stack_Stream_Current]=0; + Stack_Stream_Current= -1; + } +} + +/*BFUNC + +mwtell() returns the bit position on the write stream. + +EFUNC*/ + +long mwtell() +{ + BEGIN("mwtell") + + return((ftell(swout)<<3) + (7 - write_position)); +} + +/*BFUNC + +mrtell() returns the bit position on the read stream. + +EFUNC*/ + +long mrtell() +{ + BEGIN("mrtell") + + return((ftell(srin)<<3) - (read_position+1)); +} + +/*BFUNC + +mwseek returns the bit position on the write stream. + +EFUNC*/ + +void mwseek(distance) + long distance; +{ + BEGIN("mwseek") + int length; + + if (write_position!=7) /* Must flush out current byte */ + { + putc(current_write_byte,swout); + } + fseek(swout,0,2L); /* Find end */ + length = ftell(swout); + fseek(swout,((distance+7)>>3),0L); + if ((length<<3) <= distance) /* Make sure we read clean stuff */ + { + current_write_byte = 0; + write_position = 7 - (distance & 0x7); + } + else + { + current_write_byte = getc(swout); /* if within bounds, then read byte */ + write_position = 7 - (distance & 0x7); + fseek(swout,((distance+7)>>3),0L); /* Reset seek pointer for write */ + } +} + + +/*BFUNC + +mrseek() jumps to a bit position on the read stream. + +EFUNC*/ + +void mrseek(distance) + long distance; +{ + BEGIN("mrseek") + + fseek(srin,(distance>>3),0L); /* Go to location */ + current_read_byte = bgetc(); /* read byte in */ + read_position = 7 - (distance % 8); +} + + +/*BFUNC + +megetb() gets a bit from the read stream. + +EFUNC*/ + +int megetb() +{ + BEGIN("megetb") + + if (read_position < 0) + { + current_read_byte = pgetc(); + read_position=7; + } + if (current_read_byte&bit_set_mask[read_position--]) + { + return(1); + } + return(0); +} + +/*BFUNC + +meputv() puts n bits from b onto the writer stream. + +EFUNC*/ + +void meputv(n,b) + int n; + int b; +{ + BEGIN("meputv") + int p; + + n--; + b &= lmask[n]; + p = n - write_position; + if (!p) /* Can do parallel save immediately */ + { + current_write_byte |= b; + pputc(current_write_byte); + current_write_byte = 0; + write_position = 7; + return; + } + else if (p < 0) /* if can fit, we have to shift byte */ + { + p = -p; + current_write_byte |= (b << p); + write_position = p-1; + return; + } + current_write_byte |= (b >> p); /* cannot fit. we must do putc's */ + pputc(current_write_byte); /* Save off remainder */ + while(p > 7) /* Save off bytes while remaining > 7 */ + { + p -= 8; + current_write_byte = (b >> p) & lmask[7]; + pputc(current_write_byte); + } + if (!p) /* If zero then reset position */ + { + write_position = 7; + current_write_byte = 0; + } + else /* Otherwise reset write byte buffer */ + { + write_position = 8-p; + current_write_byte = (b << write_position) & lmask[7]; + write_position--; + } +} + +/*BFUNC + +megetv() gets n bits from the read stream and returns it. + +EFUNC*/ + +int megetv(n) + int n; +{ + BEGIN("megetv") + int p,rv; + + n--; + p = n-read_position; + while(p > 0) + { + if (read_position>23) /* If byte buffer contains almost entire word */ + { + rv = (current_read_byte << p); /* Manipulate buffer */ + current_read_byte = pgetc(); /* Change read bytes */ + rv |= (current_read_byte >> (8-p)); + read_position = 7-p; + return(rv & lmask[n]); /* Can return pending residual val */ + } + current_read_byte = (current_read_byte << 8) | pgetc(); + read_position += 8; /* else shift in new information */ + p -= 8; + } + if (!p) /* If position is zero */ + { + read_position = -1; /* Can return current byte */ + return(current_read_byte & lmask[n]); + } + p = -p; /* Else reverse position and shift */ + read_position = p-1; + return((current_read_byte >> p) & lmask[n]); +} + + +/*BFUNC + +DoMarker() performs marker analysis. We assume that the Current Marker +head has been read (0xFF) plus top information is at +marker\_read\_byte. + +EFUNC*/ + +int DoMarker() +{ + BEGIN("DoMarker") + int i,hin,lon,marker,length; + + current_read_byte = 0; + read_position= -1; /* Make sure we are byte-flush. */ + while(marker_read_byte==MARKER_FIL) /* Get rid of FIL markers */ + { +#ifdef VERSION_1_0 + if ((marker_read_byte = bgetc())!=MARKER_MARKER) + { + WHEREAMI(); + printf("Unknown FIL marker. Bypassing.\n"); + ErrorValue = ERROR_MARKER; + return(0); + } +#endif + marker_read_byte = bgetc(); + } + lon = marker_read_byte & 0x0f; /* Segregate between hi and lo */ + hin = (marker_read_byte>>4) & 0x0f; /* nybbles for the marker read byte */ + marker = marker_read_byte; + + if (InResync) + { + if ((marker <0xd0)||(marker>0xd7)) + { + WHEREAMI(); + printf("Illegal resync marker found.\n"); + return(0); + } + } + switch(hin) /* Pretty much self explanatory */ + { + case 0x0c: /* Frame Style Marker */ + switch(lon) + { + case 0x04: + ReadDht(); + break; + case 0x00: + case 0x01: + case 0x03: + ReadSof(lon); + break; + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: + WHEREAMI(); + printf("Arithmetic coding not supported.\n"); + length = bgetw(); + for(i=2;i 7) + { + switch(lon) + { + case 0x08: /* Start of Image */ + EndofImage=0; /* If End of Image occurs */ + CImage->ImageSequence++; /* reset, and increment sequence */ + break; + case 0x09: /* End of Image */ + EndofImage=1; + break; + case 0x0a: + ResyncCount=0; /* SOS clears the resync count */ + ReadSos(); + break; + case 0x0b: + ReadDqt(); + break; + case 0x0c: + ReadDnl(); + break; + case 0x0d: + ReadDri(); + break; + default: + WHEREAMI(); + printf("Hierarchical markers found.\n"); + length = bgetw(); + for(i=2;i= 0) + { + if ((ValueRead & MARKER_RSC_MASK)!=MARKER_RSC) /* Strange marker found */ + { + if (ValueRead != MARKER_DNL) /* DNL only other possibility */ + { /* actually excluded, never reached */ + WHEREAMI(); /* 11/19/91 ACH */ + printf("Non-Resync marker found for resync.\n"); + printf("Trying again.\n"); + } + } + else + { + ValueRead = ValueRead & 0x07; /* If so, then check resync count */ + if (ValueRead != ResyncCount) + { + WHEREAMI(); + printf("Bad resync counter. No search done.\n"); + } + ResyncCount = (ResyncCount+1)&0x07; + /* Flush spurious markers. */ + while((ValueRead = ScreenMarker()) >= 0); + InResync=0; + return(0); + } + } + WHEREAMI(); + printf("Anticipated resync not found.\n"); + Resync(); + InResync=0; + return(-1); +} + +/*BFUNC + +ScreenAllMarker() looks for all the markers on the stream. It returns +a 0 if a marker has been found, -1 if no markers exist. + +EFUNC*/ + +int ScreenAllMarker() +{ + BEGIN("ScreenAllMarker") + + if (ScreenMarker()<0) + { + return(-1); + } + while(ScreenMarker()>=0); /* Flush out all markers */ + return(0); +} + +/*BFUNC + +DoAllMarker() is the same as ScreenAllMarker except we assume that the +prefix markerbyte (0xff) has been read and the second byte of the +prefix is in the marker\_byte variable. It returns a -1 if there is an +error in reading the marker. + +EFUNC*/ + +int DoAllMarker() +{ + BEGIN("DoAllMarker") + + if (DoMarker()<0) + { + return(-1); + } + while(ScreenMarker()>=0); /* Flush out all markers */ + return(0); +} + +/*END*/ diff --git a/gdcm/Utilities/pvrg/stream.h b/gdcm/Utilities/pvrg/stream.h new file mode 100644 index 0000000..dd3a20e --- /dev/null +++ b/gdcm/Utilities/pvrg/stream.h @@ -0,0 +1,40 @@ +/************************************************************* +Copyright (C) 1990, 1991, 1993 Andy C. Hung, all rights reserved. +PUBLIC DOMAIN LICENSE: Stanford University Portable Video Research +Group. If you use this software, you agree to the following: This +program package is purely experimental, and is licensed "as is". +Permission is granted to use, modify, and distribute this program +without charge for any purpose, provided this license/ disclaimer +notice appears in the copies. No warranty or maintenance is given, +either expressed or implied. In no event shall the author(s) be +liable to you or a third party for any special, incidental, +consequential, or other damages, arising out of the use or inability +to use the program for any purpose (or the loss of data), even if we +have been advised of such possibilities. Any public reference or +advertisement of this source code should refer to it as the Portable +Video Research Group (PVRG) code, and not by any author(s) (or +Stanford University) name. +*************************************************************/ + +/* +************************************************************ +stream.h + +This file contains simple macros for better access to the direct +stream. + +************************************************************ +*/ + +#ifndef STREAM_DONE +#define STREAM_DONE + +#define bputw(word) {bputc((word>>8)&0xff); bputc(word&0xff);} +#define bputn(nybbleh,nybblel) {bputc(((nybbleh&0x0f)<<4)|(nybblel&0x0f));} +#define hinyb(val) ((val>>4)&0x0f) +#define lonyb(val) (val & 0x0f) +int bgetw(); +int brtell(); +int brseek(int offset,int ptr); + +#endif diff --git a/gdcm/Utilities/pvrg/system.h b/gdcm/Utilities/pvrg/system.h new file mode 100644 index 0000000..a890ce9 --- /dev/null +++ b/gdcm/Utilities/pvrg/system.h @@ -0,0 +1,102 @@ +/************************************************************* +Copyright (C) 1990, 1991, 1993 Andy C. Hung, all rights reserved. +PUBLIC DOMAIN LICENSE: Stanford University Portable Video Research +Group. If you use this software, you agree to the following: This +program package is purely experimental, and is licensed "as is". +Permission is granted to use, modify, and distribute this program +without charge for any purpose, provided this license/ disclaimer +notice appears in the copies. No warranty or maintenance is given, +either expressed or implied. In no event shall the author(s) be +liable to you or a third party for any special, incidental, +consequential, or other damages, arising out of the use or inability +to use the program for any purpose (or the loss of data), even if we +have been advised of such possibilities. Any public reference or +advertisement of this source code should refer to it as the Portable +Video Research Group (PVRG) code, and not by any author(s) (or +Stanford University) name. +*************************************************************/ +/* +************************************************************ +system.h + +This file contains the miscellaneous definitions for running +the JPEG coder. + +************************************************************ +*/ + +#ifndef SYSTEM_DONE +#define SYSTEM_DONE +/*#include */ +#include +#include +#include + +#define IOB_BLOCK 0 +#define IOB_LINE 1 +#define IOB_OVERSAMPLEBLOCK 2 + +#define BUFFER struct io_buffer +#define IOBUF struct io_buffer_list + +#define XHUFF struct huffman_standard_structure +#define EHUFF struct huffman_encoder +#define DHUFF struct huffman_decoder + +BUFFER { +unsigned int overflow; /* The last buffer character on line overflow */ +int data_linelast; /* The last element read out for line buffering */ +int disable; /* Stream is disabled! */ +int wsize; /* Element word size in characters */ +int size; /* Size of buffer in characters */ +long currentoffs; /* Current offset from left edge of image */ +long streamoffs; /* Stream offset (the pixel index of left edge) */ +unsigned char *space; /* Space is the raw buffer pointer */ +unsigned char *bptr; /* Current base pointer of buffer */ +unsigned char *tptr; /* Current top pointer of buffer */ +IOBUF *iob; /* References own IOB */ +}; + + +IOBUF { +int type; /* Iob type */ +int num; /* Number of buffers */ +int wsize; /* Element word size in characters */ +int hpos; /* Current block position in image */ +int vpos; +int hor; /* Sampling frequency */ +int ver; +int width; /* Width and height of image */ +int height; +int file; /* File descriptor */ +int flags; /* File mode flags */ +int linelastdefault; /* Last line element default */ +BUFFER **blist; /* A list of buffers */ +}; + +/* XHUFF contains all the information that needs be transmitted */ +/* EHUFF and DHUFF are derivable from XHUFF */ + +XHUFF { +int bits[36]; /* Bit-length frequency (indexed on length */ +int huffval[257]; /* Huffman value index */ +}; + +/* Encoder tables */ + +EHUFF { +int ehufco[257]; /* Encoder huffman code indexed on code word */ +int ehufsi[257]; /* Encoder huffman code-size indexed on code word */ +}; + +/* Decoder tables */ + +DHUFF { +int ml; /* Maximum length */ +int maxcode[36]; /* Max code for a given bit length -1 if no codes */ +int mincode[36]; /* Min code for a given bit length */ +int valptr[36]; /* First index (of min-code) for a given bit-length */ +}; + + +#endif diff --git a/gdcm/Utilities/pvrg/tables.h b/gdcm/Utilities/pvrg/tables.h new file mode 100644 index 0000000..5e1d3d2 --- /dev/null +++ b/gdcm/Utilities/pvrg/tables.h @@ -0,0 +1,119 @@ +/************************************************************* +Copyright (C) 1990, 1991, 1993 Andy C. Hung, all rights reserved. +PUBLIC DOMAIN LICENSE: Stanford University Portable Video Research +Group. If you use this software, you agree to the following: This +program package is purely experimental, and is licensed "as is". +Permission is granted to use, modify, and distribute this program +without charge for any purpose, provided this license/ disclaimer +notice appears in the copies. No warranty or maintenance is given, +either expressed or implied. In no event shall the author(s) be +liable to you or a third party for any special, incidental, +consequential, or other damages, arising out of the use or inability +to use the program for any purpose (or the loss of data), even if we +have been advised of such possibilities. Any public reference or +advertisement of this source code should refer to it as the Portable +Video Research Group (PVRG) code, and not by any author(s) (or +Stanford University) name. +*************************************************************/ + +/* +************************************************************ +tables.h + +This file contains the default huffman and quantization tables. + +************************************************************ +*/ + +#ifndef TABLES_DONE +#define TABLES_DONE + +static int LuminanceQuantization[] = { +16, 11, 10, 16, 24, 40, 51, 61, +12, 12, 14, 19, 26, 58, 60, 55, +14, 13, 16, 24, 40, 57, 69, 56, +14, 17, 22, 29, 51, 87, 80, 62, +18, 22, 37, 56, 68, 109, 103, 77, +24, 35, 55, 64, 81, 104, 113, 92, +49, 64, 78, 87, 103, 121, 120, 101, +72, 92, 95, 98, 112, 100, 103, 99}; + +static int ChrominanceQuantization[] = { +17, 18, 24, 47, 99, 99, 99, 99, +18, 21, 26, 66, 99, 99, 99, 99, +24, 26, 56, 99, 99, 99, 99, 99, +47, 66, 99, 99, 99, 99, 99, 99, +99, 99, 99, 99, 99, 99, 99, 99, +99, 99, 99, 99, 99, 99, 99, 99, +99, 99, 99, 99, 99, 99, 99, 99, +99, 99, 99, 99, 99, 99, 99, 99}; + +static int LuminanceDCBits[] = { +0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +static int LuminanceDCValues[] = { +0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b}; + +static int ChrominanceDCBits[] = { +0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}; + +static int ChrominanceDCValues[] = { +0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b}; + +static int LuminanceACBits[] = { +0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, +0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d}; + +static int LuminanceACValues[] = { +0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, +0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, +0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, +0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, +0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, +0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, +0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, +0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, +0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, +0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, +0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, +0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, +0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, +0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, +0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, +0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, +0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, +0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, +0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, +0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, +0xf9, 0xfa}; + +static int ChrominanceACBits[] = { +0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, +0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77}; + +static int ChrominanceACValues[] = { +0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, +0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, +0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, +0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, +0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, +0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, +0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, +0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, +0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, +0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, +0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, +0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, +0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, +0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, +0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, +0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, +0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, +0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, +0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, +0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, +0xf9, 0xfa}; + +#endif diff --git a/gdcm/Utilities/pvrg/transform.c b/gdcm/Utilities/pvrg/transform.c new file mode 100644 index 0000000..f3bee7c --- /dev/null +++ b/gdcm/Utilities/pvrg/transform.c @@ -0,0 +1,525 @@ +/************************************************************* +Copyright (C) 1990, 1991, 1993 Andy C. Hung, all rights reserved. +PUBLIC DOMAIN LICENSE: Stanford University Portable Video Research +Group. If you use this software, you agree to the following: This +program package is purely experimental, and is licensed "as is". +Permission is granted to use, modify, and distribute this program +without charge for any purpose, provided this license/ disclaimer +notice appears in the copies. No warranty or maintenance is given, +either expressed or implied. In no event shall the author(s) be +liable to you or a third party for any special, incidental, +consequential, or other damages, arising out of the use or inability +to use the program for any purpose (or the loss of data), even if we +have been advised of such possibilities. Any public reference or +advertisement of this source code should refer to it as the Portable +Video Research Group (PVRG) code, and not by any author(s) (or +Stanford University) name. +*************************************************************/ + +/* +************************************************************ +transform.c + +This file contains the reference DCT, the zig-zag and quantization +algorithms. + +************************************************************ +*/ + +/*LABEL transform.c */ + +/* Include files */ + +#include "globals.h" +#include "dct.h" +#include +#include /* exit */ + +/*PUBLIC*/ + +extern void ReferenceDct(); +extern void ReferenceIDct(); +extern void TransposeMatrix(); +extern void Quantize(); +extern void IQuantize(); +extern void PreshiftDctMatrix(); +extern void PostshiftIDctMatrix(); +extern void BoundDctMatrix(); +extern void BoundIDctMatrix(); +extern void ZigzagMatrix(); +extern void IZigzagMatrix(); +extern int *ScaleMatrix(); +extern void PrintMatrix(); +extern void ClearMatrix(); + +static void DoubleReferenceDct1D(); +static void DoubleReferenceIDct1D(); +static void DoubleTransposeMatrix(); + +/*PRIVATE*/ + +/* The transposition indices */ + +int transpose_index[] = /* Is a transpose map for matrix transp. */ +{0, 8, 16, 24, 32, 40, 48, 56, + 1, 9, 17, 25, 33, 41, 49, 57, + 2, 10, 18, 26, 34, 42, 50, 58, + 3, 11, 19, 27, 35, 43, 51, 59, + 4, 12, 20, 28, 36, 44, 52, 60, + 5, 13, 21, 29, 37, 45, 53, 61, + 6, 14, 22, 30, 38, 46, 54, 62, + 7, 15, 23, 31, 39, 47, 55, 63}; + +int zigzag_index[] = /* Is zig-zag map for matrix -> scan array */ +{0, 1, 5, 6, 14, 15, 27, 28, + 2, 4, 7, 13, 16, 26, 29, 42, + 3, 8, 12, 17, 25, 30, 41, 43, + 9, 11, 18, 24, 31, 40, 44, 53, +10, 19, 23, 32, 39, 45, 52, 54, +20, 22, 33, 38, 46, 51, 55, 60, +21, 34, 37, 47, 50, 56, 59, 61, +35, 36, 48, 49, 57, 58, 62, 63}; + +int izigzag_index[] = +{0, 1, 8, 16, 9, 2, 3, 10, +17, 24, 32, 25, 18, 11, 4, 5, +12, 19, 26, 33, 40, 48, 41, 34, +27, 20, 13, 6, 7, 14, 21, 28, +35, 42, 49, 56, 57, 50, 43, 36, +29, 22, 15, 23, 30, 37, 44, 51, +58, 59, 52, 45, 38, 31, 39, 46, +53, 60, 61, 54, 47, 55, 62, 63}; + +/*Some definitions */ + +#define MakeMatrix() (int *) calloc(BLOCKSIZE,sizeof(int)) +#define FixedMultiply(s,x,y) x = ((x * y) >> s); +#define DCT_OFFSET 128 + +/*START*/ + +/*BFUNC + +ReferenceDct() does a reference DCT on the input (matrix) and output +(new matrix). + +EFUNC*/ + +void ReferenceDct(matrix,newmatrix) + int *matrix; + int *newmatrix; +{ + BEGIN("ReferenceDct") + int *mptr; + double *sptr,*dptr; + double sourcematrix[BLOCKSIZE],destmatrix[BLOCKSIZE]; + + for(sptr=sourcematrix,mptr=matrix;mptr 0 ? (*(sptr)+0.5):(*(sptr)-0.5)); + } +} + +/*BFUNC + +DoubleReferenceDCT1D() does a 8 point dct on an array of double +input and places the result in a double output. + +EFUNC*/ + +static void DoubleReferenceDct1D(ivect,ovect) + double *ivect; + double *ovect; +{ + BEGIN("DoubleReferenceDct1D") + double *mptr,*iptr,*optr; + + for(mptr=DctMatrix,optr=ovect;optr 0 ? (*(sptr)+0.5):(*(sptr)-0.5)); + } +} + +/*BFUNC + +DoubleReferenceIDct1D() does an 8 point inverse dct on ivect and +puts the output in ovect. + +EFUNC*/ + +static void DoubleReferenceIDct1D(ivect,ovect) + double *ivect; + double *ovect; +{ + BEGIN("DoubleReferenceIDct1D") + double *mptr,*iptr,*optr; + + for(mptr = IDctMatrix,optr=ovect;optr 0) /* Rounding is different for +/- coeffs */ + { + *mptr = (*mptr + *qmatrix/2)/ (*qmatrix); + qmatrix++; + } + else + { + *mptr = (*mptr - *qmatrix/2)/ (*qmatrix); + qmatrix++; + } + } +} + +/*BFUNC + +IQuantize() takes an input matrix and does an inverse quantization +and puts the output int qmatrix. + +EFUNC*/ + +void IQuantize(matrix,qmatrix) + int *matrix; + int *qmatrix; +{ + BEGIN("IQuantize") + int *mptr; + + if (!qmatrix) + { + WHEREAMI(); + printf("No quantization matrix specified!\n"); + exit(ERROR_BOUNDS); + } + for(mptr=matrix;mptr 0) + *mptr = Bound; + } +} + +/*BFUNC + +BoundIDctMatrix bounds the inverse dct matrix so that no pixel has a +value greater than 255 (4095) or less than 0. + +EFUNC*/ + +void BoundIDctMatrix(matrix,Bound) + int *matrix; + int Bound; +{ + BEGIN("BoundIDctMatrix") + int *mptr; + + for(mptr=matrix;mptr Bound) {*mptr = Bound;} + } +} + +/*BFUNC + +IZigzagMatrix() performs an inverse zig-zag translation on the +input imatrix and places the output in omatrix. + +EFUNC*/ + +void IZigzagMatrix(imatrix,omatrix) + int *imatrix; + int *omatrix; +{ + BEGIN("IZigzagMatrix") + int *tptr; + + for(tptr=zigzag_index;tptr Limit) + *tptr = Limit; + else if (*tptr < 1) + *tptr = 1; + } + return(Temp); +} + +/*BFUNC + +PrintMatrix() prints an 8x8 matrix in row/column form. + +EFUNC*/ + +void PrintMatrix(matrix) + int *matrix; +{ + BEGIN("PrintMatrix") + int i,j; + + if (matrix) + { + for(i=0;i +#include // abort + +#include "rlelib.h" + +void std_print_header(rle_compressed_frame * frame) +{ + rle_header *header = frame->header; + unsigned long ns = header->num_segments; + printf("%lu\n", ns); +} + + +int write_RLE_file(const char *filename) +{ + assert(0); + return 0; +} + + +int fill_input_buffer(rle_decompressed_frame * frame) +{ + return 1; +} + +int read_RLE_file(const char *filename) +{ + assert(0); + return 1; +} + +int main(int argc, char *argv[]) +{ + rle_decompress_struct cinfo; + FILE * infile; + + const char *filename; + if( argc < 2 ) + { + return 1; + } + filename = argv[1]; + + if ((infile = fopen(filename, "rb")) == NULL) { + fprintf(stderr, "can't open %s\n", filename); + return 0; + } + + rle_create_decompress(&cinfo); + + int i; + int dims[2] = { 1760,1760 }; + int bpp = 16; + rle_stdio_src(&cinfo, infile, dims); + + printf("num segment: %d\n", cinfo.header->num_segments ); + printf("offsets table:\n"); + for(i = 0; i < 16; ++i) + printf("offset: %d\n", cinfo.header->offset[i] ); + + (void) rle_start_decompress(&cinfo); + + char *buffer = (char*)malloc( dims[0] * (bpp / 8) ); + while( cinfo.current_segment < cinfo.header->num_segments ) { + while (cinfo.output_scanline < cinfo.output_height) { + (void) rle_read_scanlines(&cinfo, buffer, 1); + /*put_scanline_someplace(buffer[0], row_stride);*/ + } + } + free(buffer); + + (void) rle_finish_decompress(&cinfo); + + rle_destroy_decompress(&cinfo); + + fclose(infile); + + return 0; +} diff --git a/gdcm/Utilities/rle/rle.c b/gdcm/Utilities/rle/rle.c new file mode 100644 index 0000000..e549fd6 --- /dev/null +++ b/gdcm/Utilities/rle/rle.c @@ -0,0 +1,35 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "rlelib.h" + + +int rle_decode_init(rle_compressed_frame * frame) +{ + return 0; +} + +int rle_decode_segment(rle_compressed_frame * frame) +{ + return 0; +} + +int rle_decode_frame(rle_compressed_frame * frame) +{ + return 0; +} + +int rle_decode_end() +{ + return 0; +} diff --git a/gdcm/Utilities/rle/rledump.c b/gdcm/Utilities/rle/rledump.c new file mode 100644 index 0000000..ded020b --- /dev/null +++ b/gdcm/Utilities/rle/rledump.c @@ -0,0 +1,53 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "rlelib.h" + +int main(int argc, char *argv[]) +{ + rle_decompress_struct cinfo; + FILE * infile; + int i; + + const char *filename; + if( argc < 2 ) + { + return 1; + } + filename = argv[1]; + + if ((infile = fopen(filename, "rb")) == NULL) { + fprintf(stderr, "can't open %s\n", filename); + return 0; + } + + rle_create_decompress(&cinfo); + + /* Dimensions: (1760,1760,1)*/ + int dims[2] = { 1760,1760 }; + rle_stdio_src(&cinfo, infile, dims); + + /*rle_header *h = cinfo.header;*/ + printf("num segment: %d\n", cinfo.header->num_segments ); + printf("offsets table:\n"); + for(i = 0; i < 16; ++i) + printf("offset: %d\n", cinfo.header->offset[i] ); + + /* Simply dump the file info:*/ + + rle_destroy_decompress(&cinfo); + + fclose(infile); + + return 0; +} diff --git a/gdcm/Utilities/rle/rlelib.c b/gdcm/Utilities/rle/rlelib.c new file mode 100644 index 0000000..876557b --- /dev/null +++ b/gdcm/Utilities/rle/rlelib.c @@ -0,0 +1,162 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "rlelib.h" + +void rle_stdio_src(rle_decompress_struct *cinfo, FILE *infile, int *dims) +{ + int i; + /*is.read((char*)(&Header), sizeof(uint32_t)*16);*/ + size_t len = fread(cinfo->header, sizeof(uint32_t), 16, infile); + cinfo->row = dims[0]; + cinfo->col = dims[1]; + if( cinfo->header->num_segments > 16 || cinfo->header->num_segments < 1 ) + { + /* Need to throw something here*/ + assert(0); + } + if( cinfo->header->offset[0] != 64 ) + { + /* Need to throw something here*/ + assert(0); + } + for(i=1; i < cinfo->header->num_segments; ++i) + { + if( cinfo->header->offset[i-1] > cinfo->header->offset[i] ) + { + /* Need to throw something here*/ + assert(0); + } + } + for(i=cinfo->header->num_segments; i < 16; ++i) + { + if( cinfo->header->offset[i] != 0 ) + { + /* Need to throw something here*/ + /*assert(0);*/ + fprintf(stderr, "Impossible : %d for offset # %d\n", cinfo->header->offset[i], i ); + } + } + cinfo->stream = infile; + + cinfo->output_height = dims[1]; +} + +/* + * G.3.2 The RLE decoder + * Pseudo code for the RLE decoder is shown below: + * Loop until the number of output bytes equals the uncompressed segment size + * Read the next source byte into n + * If n> =0 and n <= 127 then + * output the next n+1 bytes literally + * Elseif n <= - 1 and n >= -127 then + * output the next byte -n+1 times + * Elseif n = - 128 then + * output nothing + * Endif + * Endloop + */ + +int rle_start_decompress(rle_decompress_struct *cinfo) +{ + fseek(cinfo->stream, cinfo->header->offset[0], SEEK_SET ); + cinfo->current_pos = 0; + return 1; +} + +void rle_create_decompress(rle_decompress_struct *cinfo) +{ + int i; + cinfo->output_scanline = 0; + cinfo->output_height = 0; + cinfo->current_segment = 0; + cinfo->header = (rle_header*)malloc(sizeof(rle_header)); + cinfo->header->num_segments = 0; + for(i = 0; i < 16; ++i) + cinfo->header->offset[i] = 0; +} + +int rle_read_scanlines(rle_decompress_struct *cinfo, char *buffer, int f) +{ + signed char byte; + signed char nextbyte; + unsigned long length = cinfo->row * cinfo->col; + /* read too much ! */ + printf("%d vs %d \n", cinfo->current_pos, length ) ; + printf("scan %d \n", cinfo->output_scanline ) ; + if( cinfo->current_segment > cinfo->header->num_segments ) + { + return 0; + } + + unsigned long noutbytes = 0; + char * p = buffer; + int c; + while( noutbytes < cinfo->row ) + { + size_t s1 = fread(&byte, 1, 1, cinfo->stream); + if( byte >= 0 ) + { + fread(p, (int)byte+1, 1, cinfo->stream); + p+=(int)byte+1; + noutbytes += (int)byte+1; + } + else if( byte < 0 && byte > -128 ) + { + size_t s2 = fread(&nextbyte, 1, 1, cinfo->stream); + for( c = 0; c < (int)-byte + 1; ++c ) + { + *p++ = nextbyte; + noutbytes++; + } + } + else + { + assert( byte == -128 ); + } + } + assert( p - buffer == cinfo->row ); + assert( noutbytes == cinfo->row ); + cinfo->current_pos += cinfo->row; + long pos = ftell(cinfo->stream); + /*printf("pos: %d\n",pos);*/ + cinfo->output_scanline++; + + assert( cinfo->current_pos <= length ); + if( cinfo->current_pos >= length ) + { + /* if( cinfo->current_segment > cinfo->header->num_segments ) + { + return 0; + } + else*/ + { + cinfo->current_segment++; + cinfo->output_scanline = 0; + } + } + + return 1; +} + +int rle_finish_decompress(rle_decompress_struct *cinfo) +{ + return 1; +} + +void rle_destroy_decompress(rle_decompress_struct *cinfo) +{ + cinfo->output_scanline = 0; /* why not*/ + cinfo->output_height = 0; /* why not*/ + free(cinfo->header); +} diff --git a/gdcm/Utilities/rle/rlelib.h b/gdcm/Utilities/rle/rlelib.h new file mode 100644 index 0000000..401c93b --- /dev/null +++ b/gdcm/Utilities/rle/rlelib.h @@ -0,0 +1,67 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef RLELIB_H +#define RLELIB_H + +#include +#include +#include +#include + +#define RLE_LIB_VERSION 0.0.1 + +typedef struct +{ + uint32_t num_segments; + uint32_t offset[15]; + void (*print_header) (void); +} rle_header; + +typedef struct +{ + rle_header * header; +} rle_compressed_frame; + +typedef struct +{ + rle_header * header; +} rle_decompressed_frame; + +typedef struct +{ + int (*fill_input_buffer) (rle_decompressed_frame*); +} source_mgr; + +typedef struct +{ + int output_scanline; + int output_height; + /*int bits_allocated; // 8 or 16, when 16 need to do padded composite*/ + int row; + int col; + FILE *stream; + int current_segment; + unsigned long current_pos; + rle_header *header; +} rle_decompress_struct; + + +void rle_stdio_src(rle_decompress_struct *cinfo, FILE *infile, int *dims); +int rle_start_decompress(rle_decompress_struct *cinfo); +void rle_create_decompress(rle_decompress_struct *cinfo); +int rle_read_scanlines(rle_decompress_struct *cinfo, char *buffer, int f); +int rle_finish_decompress(rle_decompress_struct *cinfo); +void rle_destroy_decompress(rle_decompress_struct *cinfo); + +#endif /* RLELIB_H */ diff --git a/gdcm/Utilities/socketxx/.NoDartCoverage b/gdcm/Utilities/socketxx/.NoDartCoverage new file mode 100644 index 0000000..3c99729 --- /dev/null +++ b/gdcm/Utilities/socketxx/.NoDartCoverage @@ -0,0 +1 @@ +# do not do coverage in this directory diff --git a/gdcm/Utilities/socketxx/AUTHORS b/gdcm/Utilities/socketxx/AUTHORS new file mode 100644 index 0000000..579bc8a --- /dev/null +++ b/gdcm/Utilities/socketxx/AUTHORS @@ -0,0 +1,8 @@ +Main Author: +============ + +1992-1996 Gnanasekaran Swaminathan + +Other Authors: + +2002-2004 Herbert Straub diff --git a/gdcm/Utilities/socketxx/CMakeLists.txt b/gdcm/Utilities/socketxx/CMakeLists.txt new file mode 100644 index 0000000..41529b9 --- /dev/null +++ b/gdcm/Utilities/socketxx/CMakeLists.txt @@ -0,0 +1,52 @@ +cmake_minimum_required(VERSION 2.8.9) + +# http://www.linuxhacker.at/socketxx +if(NOT SOCKETXX_NAMESPACE) + set(SOCKETXX_NAMESPACE "SOCKETXX") + set(SOCKETXX_STANDALONE 1) +endif() +# In all cases: +string(TOLOWER ${SOCKETXX_NAMESPACE} SOCKETXX_LIBRARY_NAME) + +project(${SOCKETXX_NAMESPACE} CXX) + +if(NOT SOCKETXX_INSTALL_BIN_DIR) + set(SOCKETXX_INSTALL_BIN_DIR "bin") +endif() +if(NOT SOCKETXX_INSTALL_LIB_DIR) + set(SOCKETXX_INSTALL_LIB_DIR "lib") +endif() +if(NOT SOCKETXX_INSTALL_INCLUDE_DIR) + set(SOCKETXX_INSTALL_INCLUDE_DIR "include") +endif() + +# configure.in:LIBSOCKET_SO_VERSION +# LIBSOCKET_SO_VERSION=1:2:0 +# SOCKET_VERSION=1.12.12 + +#----------------------------------------------------------------------------- +# SOCKETXX version number +set(SOCKETXX_MAJOR_VERSION 1) +set(SOCKETXX_MINOR_VERSION 2) +set(SOCKETXX_BUILD_VERSION 0) +set(SOCKETXX_VERSION + "${SOCKETXX_MAJOR_VERSION}.${SOCKETXX_MINOR_VERSION}.${SOCKETXX_BUILD_VERSION}" + ) +set(SOCKETXX_API_VERSION + "${SOCKETXX_MAJOR_VERSION}.${SOCKETXX_MINOR_VERSION}" + ) +set(SOCKETXX_LIBRARY_PROPERTIES + VERSION "${SOCKETXX_VERSION}" + SOVERSION "${SOCKETXX_API_VERSION}" + ) + +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR} + ) + +#option(BUILD_SHARED_LIBS "Build with shared libraries." ON) + +add_subdirectory(socket++) +#add_subdirectory(test) #these just don't work on windows + + diff --git a/gdcm/Utilities/socketxx/COPYING b/gdcm/Utilities/socketxx/COPYING new file mode 100644 index 0000000..31040c2 --- /dev/null +++ b/gdcm/Utilities/socketxx/COPYING @@ -0,0 +1,15 @@ +Copyright Notice: +----------------- +Copyright (C) 1992-1996 Gnanasekaran Swaminathan + +Permission is granted to use at your own risk and distribute this software +in source and binary forms provided the above copyright notice and this +paragraph are preserved on all copies. This software is provided "as is" +with no express or implied warranty. + + +Copyright Notice: +----------------- +Portions Copyright (C) 2002-2003 Herbert Straub for all my changes (see ChangeLog) + + diff --git a/gdcm/Utilities/socketxx/socket++/CMakeLists.txt b/gdcm/Utilities/socketxx/socket++/CMakeLists.txt new file mode 100644 index 0000000..4f6480c --- /dev/null +++ b/gdcm/Utilities/socketxx/socket++/CMakeLists.txt @@ -0,0 +1,103 @@ +# common +set(VERSION "1.12.12") +set(PACKAGE "socket++") + +#set(CMAKE_REQUIRED_INCLUDES "string.h") +include(CheckFunctionExists) +CHECK_FUNCTION_EXISTS(strsignal SOCKETXX_HAVE_STRSIGNAL) + +# specific +if(WIN32) +else() + # FIXME this should be try_compile: + set(EXTERN_C_BEGIN) + set(SYS_SIGLIST sys_siglist) + set(SIGHND_ARGTYPE int) + set(SYS_ERRLIST sys_errlist) + set(SYS_ERRLIST_DECLARED 1) + set(_S_LIBGXX 0) + set(HAVE_DLFCN_H 1) + set(HAVE_FORK 1) + set(HAVE_MEMORY_H 1) + set(HAVE_SELECT 1) + set(HAVE_SSTREAM 1) + set(HAVE_STDINT_H 1) + set(HAVE_STDLIB_H 1) + set(HAVE_STRING 1) + set(HAVE_STRINGS_H 1) + set(HAVE_STRING_H 1) + set(HAVE_SYS_STAT_H 1) + set(HAVE_SYS_TYPES_H 1) + set(HAVE_SYS_WAIT_H 1) + set(HAVE_UNISTD_H 1) + set(HAVE_VFORK 1) + set(HAVE_VFORK_H 0) + set(HAVE_WORKING_FORK 1) + set(HAVE_WORKING_VFORK 1) + set(RETSIGTYPE void) + set(STDC_HEADERS 1) +endif() + +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/config.h.in + ${CMAKE_CURRENT_BINARY_DIR}/config.h + ) + +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} + ) + +set(libsocket___la_SOURCES + sockstream.cpp sockstream.h + sockinet.cpp sockinet.h + #pipestream.cpp pipestream.h + fork.cpp fork.h + protocol.cpp protocol.h + echo.cpp echo.h + #smtp.cpp smtp.h + #ftp.cpp ftp.h + #sig.cpp sig.h + ) + +if(UNIX) + set(libsocket___la_SOURCES + ${libsocket___la_SOURCES} + #sockunix.cpp sockunix.h + ) +endif() + +add_library(${SOCKETXX_LIBRARY_NAME} ${libsocket___la_SOURCES}) +set_target_properties(${SOCKETXX_LIBRARY_NAME} PROPERTIES ${SOCKETXX_LIBRARY_PROPERTIES} LINK_INTERFACE_LIBRARIES "") +if(WIN32) + target_link_libraries(${SOCKETXX_LIBRARY_NAME} ws2_32.lib) +endif() +if(CMAKE_SYSTEM MATCHES "SunOS.*") + target_link_libraries(${SOCKETXX_LIBRARY_NAME} socket nsl) +endif() + +# Install library +if(NOT SOCKETXX_INSTALL_NO_LIBRARIES) + # Runtime + install(TARGETS ${SOCKETXX_LIBRARY_NAME} + EXPORT ${GDCM_TARGETS_NAME} + RUNTIME DESTINATION ${SOCKETXX_INSTALL_BIN_DIR} COMPONENT Applications + LIBRARY DESTINATION ${SOCKETXX_INSTALL_LIB_DIR} COMPONENT Libraries ${NAMELINK_SKIP} + ARCHIVE DESTINATION ${SOCKETXX_INSTALL_LIB_DIR} COMPONENT DebugDevel + ) + #Development + if(NAMELINK_ONLY) + install(TARGETS ${SOCKETXX_LIBRARY_NAME} + EXPORT ${GDCM_TARGETS_NAME} + LIBRARY DESTINATION ${SOCKETXX_INSTALL_LIB_DIR} COMPONENT DebugDevel ${NAMELINK_ONLY} + ) + endif() +endif() + +if(NOT SOCKETXX_INSTALL_NO_DEVELOPMENT) + file(GLOB header_files "*.h") + install(FILES ${header_files} + DESTINATION ${SOCKETXX_INSTALL_INCLUDE_DIR} COMPONENT Headers + ) +endif() + diff --git a/gdcm/Utilities/socketxx/socket++/config.h.in b/gdcm/Utilities/socketxx/socket++/config.h.in new file mode 100644 index 0000000..319b690 --- /dev/null +++ b/gdcm/Utilities/socketxx/socket++/config.h.in @@ -0,0 +1,135 @@ +/* socket++/config.h.in. Generated from configure.in by autoheader. */ +/* Define if extern "C" is needed arround include files */ +#define EXTERN_C_BEGIN @EXTERN_C_BEGIN@ +#define EXTERN_C_END @EXTERN_C_END@ + +/* Define whether or not system has strsignal */ +#cmakedefine SOCKETXX_HAVE_STRSIGNAL + +#ifndef SOCKETXX_HAVE_STRSIGNAL +/* Define either as _sys_siglist or sys_siglist */ +#define SYS_SIGLIST @SYS_SIGLIST@ +#endif + +/* Define the argument type for signal handler function */ +#define SIGHND_ARGTYPE @SIGHND_ARGTYPE@ + +/* Define either as _sys_errlist or sys_errlist */ +#define SYS_ERRLIST @SYS_ERRLIST@ + +/* Define SYS_ERRLIST_DECLARED if extern char* SYS_ERRLIST []; is found */ +#define SYS_ERRLIST_DECLARED @SYS_ERRLIST_DECLARED@ + +/* Define SA_RESTART if it is not defined in sys/signal.h */ +#cmakedefine SA_RESTART + +/* Define if you have libg++ */ +#define _S_LIBGXX @_S_LIBGXX@ + +/* Version */ +#cmakedefine SOCKET_MAJOR_VERSION +#cmakedefine SOCKET_MINOR_VERSION +#cmakedefine SOCKET_MICRO_VERSION + +/* Configuration Options */ +#cmakedefine ENABLE_DEBUG + +#cmakedefine GDCM_BUILD_SHARED_LIBS + + + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H @HAVE_DLFCN_H@ + +/* Define to 1 if you have the `fork' function. */ +#define HAVE_FORK @HAVE_FORK@ + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H @HAVE_INTTYPES_H@ + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H @HAVE_MEMORY_H@ + +/* Define to 1 if you have the `select' function. */ +#define HAVE_SELECT @HAVE_SELECT@ + +/* Define to 1 if you have the header file. */ +#define HAVE_SSTREAM @HAVE_SSTREAM@ + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H @HAVE_STDINT_H@ + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H @HAVE_STDLIB_H@ + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING @HAVE_STRING@ + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H @HAVE_STRINGS_H@ + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H @HAVE_STRING_H@ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H @HAVE_SYS_STAT_H@ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H @HAVE_SYS_TYPES_H@ + +/* Define to 1 if you have that is POSIX.1 compatible. */ +#define HAVE_SYS_WAIT_H @HAVE_SYS_WAIT_H@ + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H @HAVE_UNISTD_H@ + +/* Define to 1 if you have the `vfork' function. */ +#define HAVE_VFORK @HAVE_VFORK@ + +/* Define to 1 if you have the header file. */ +#define HAVE_VFORK_H @HAVE_VFORK_H@ + +/* Define to 1 if `fork' works. */ +#define HAVE_WORKING_FORK @HAVE_WORKING_FORK@ + +/* Define to 1 if `vfork' works. */ +#define HAVE_WORKING_VFORK @HAVE_WORKING_VFORK@ + +/* Name of package */ +#define PACKAGE "@PACKAGE@" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "@PACKAGE_BUGREPORT@" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "@PACKAGE_NAME@" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "@PACKAGE_STRING@" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "@PACKAGE_TARNAME@" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "@PACKAGE_URL@" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "@PACKAGE_VERSION@" + +/* Define as the return type of signal handlers (`int' or `void'). */ +#define RETSIGTYPE @RETSIGTYPE@ + +/* Define to 1 if you have the ANSI C header files. */ +#ifndef STDC_HEADERS +#define STDC_HEADERS @STDC_HEADERS@ +#endif + +/* Version number of package */ +#define VERSION "@VERSION@" + +/* Define to `int' if does not define. */ +#cmakedefine pid_t + +/* Define as `fork' if `vfork' does not work. */ +#cmakedefine vfork +#include diff --git a/gdcm/Utilities/socketxx/socket++/echo.cpp b/gdcm/Utilities/socketxx/socket++/echo.cpp new file mode 100644 index 0000000..950d18b --- /dev/null +++ b/gdcm/Utilities/socketxx/socket++/echo.cpp @@ -0,0 +1,67 @@ +// echo.C -*- C++ -*- socket library +// Copyright (C) 1992-1996 Gnanasekaran Swaminathan +// +// Permission is granted to use at your own risk and distribute this software +// in source and binary forms provided the above copyright notice and this +// paragraph are preserved on all copies. This software is provided "as is" +// with no express or implied warranty. +// +// Version: 12Jan97 1.11 + + +#include + +#include +#ifndef WIN32 +#include +#endif +#include + +using namespace std; + +void echo::echobuf::serve_clients (int portno) +{ + if (protocol_name ()) { + if (portno < 0) + sockinetbuf::bind ((unsigned long) INADDR_ANY, "echo", protocol_name ()); + else if (portno <= 1024) { + sockinetbuf::bind (); + } else + sockinetbuf::bind ((unsigned long) INADDR_ANY, portno); + + // act as a server now + listen (sockbuf::somaxconn); + + // commit suicide when we receive SIGTERM + //but only if you're not on windows, which doesn't have forking +#ifndef WIN32 + Fork::suicide_signal (SIGTERM); +#endif + + for (;;) { + sockbuf s = accept (); + //!!! FIXME this is most definitely broken for windows. +#ifndef WIN32 + Fork f (1, 1); // kill my children when I get terminated. + if (f.is_child ()) { +#else //win32 has no forking + {//if win32, no forking, in the main process +#endif + char buf [1024]; + int rcnt; + + while ((rcnt = s.read (buf, 1024)) > 0) + while (rcnt != 0) { + int wcnt = s.write (buf, rcnt); + if (wcnt == -1) throw sockerr (errno); + rcnt -= wcnt; + } +#ifndef WIN32 + sleep (300); + exit (0); +#endif + } + } + } +} + diff --git a/gdcm/Utilities/socketxx/socket++/echo.h b/gdcm/Utilities/socketxx/socket++/echo.h new file mode 100644 index 0000000..32f946f --- /dev/null +++ b/gdcm/Utilities/socketxx/socket++/echo.h @@ -0,0 +1,44 @@ +// echo.h -*- C++ -*- socket library +// Copyright (C) 1992-1996 Gnanasekaran Swaminathan +// +// Permission is granted to use at your own risk and distribute this software +// in source and binary forms provided the above copyright notice and this +// paragraph are preserved on all copies. This software is provided "as is" +// with no express or implied warranty. +// +// Version: 12Jan97 1.11 + +#ifndef ECHO_H +#define ECHO_H + +#include + +class MY_API echo: public protocol +{ +public: + class MY_API echobuf: public protocol::protocolbuf { + public: + echobuf (sockinetbuf& si): protocol::protocolbuf (si) {} + echobuf (protocol::p_name pname) : protocol::protocolbuf (pname) {} + + virtual void serve_clients (int portno = -1); + virtual const char* rfc_name () const { return "echo"; } + virtual const char* rfc_doc () const { return "rfc862"; } + }; + +protected: + echo (): std::ios(0) {} + +public: + echo (protocol::p_name pname) + : std::ios (0) + { + std::ios::init (new echobuf (pname)); + } + ~echo () { delete std::ios::rdbuf (); std::ios::init (0); } + + echobuf* rdbuf () { return (echobuf*) protocol::rdbuf (); } + echobuf* operator -> () { return rdbuf (); } +}; + +#endif // !ECHO_H diff --git a/gdcm/Utilities/socketxx/socket++/fork.cpp b/gdcm/Utilities/socketxx/socket++/fork.cpp new file mode 100644 index 0000000..2ff27da --- /dev/null +++ b/gdcm/Utilities/socketxx/socket++/fork.cpp @@ -0,0 +1,204 @@ +// Fork.C -*- C++ -*- socket library +// Copyright (C) 1992-1996 Gnanasekaran Swaminathan +// +// Permission is granted to use at your own risk and distribute this software +// in source and binary forms provided the above copyright notice and this +// paragraph are preserved on all copies. This software is provided "as is" +// with no express or implied warranty. +// +// Version: 12Jan97 1.11 + +#ifndef WIN32 + +#include + +#include +#include // perror in solaris2.3 is declared here +#include +#include +#include +#include +#include + +#include + +using std::cerr; +using std::endl; + +Fork::ForkProcess* Fork::ForkProcess::list = 0; +Fork::KillForks Fork::killall; + +Fork::~Fork () +{ + if (process->pid <= 0) + delete process; +} + +Fork::KillForks::~KillForks () + // First, kill all children whose kill_child flag is set. + // Second, wait for other children to die. +{ + for (ForkProcess* cur = Fork::ForkProcess::list; cur; cur = cur->next) + if (cur->kill_child) + delete cur; + + while (Fork::ForkProcess::list && wait (0) > 0) {} +} + +Fork::ForkProcess::ForkProcess (bool kill, bool give_reason) + : kill_child (kill), reason (give_reason), next (0) +{ + if (list == 0) { + struct sigaction sa; + sa.sa_handler = (void(*)(int)) sighnd (&Fork::ForkProcess::reaper_nohang); + sigemptyset (&sa.sa_mask); + sa.sa_flags = SA_RESTART; + sigaction (SIGCHLD, &sa, 0); + } + + pid = fork (); + + if (pid > 0) { + next = list; + list = this; + } else if (pid == 0) { + // child process. clear list + ForkProcess* p = list; + while (p) { + ForkProcess* nxt = p->next; + p->pid = 0; + delete p; + p = nxt; + } + list = 0; + + if (kill_child) { + struct sigaction sa; + sa.sa_handler = (void(*)(int)) sighnd (&Fork::ForkProcess::commit_suicide); + sigemptyset (&sa.sa_mask); + sa.sa_flags = SA_RESTART; + sigaction (SIGTERM, &sa, 0); + } + } +} + +Fork::ForkProcess::~ForkProcess () +{ + if (pid > 0) { + if (kill_child) + kill (pid, SIGTERM); + reap_child (); + + // I remove myself from list + if (list == this) + list = list->next; + else { + for (ForkProcess* p = list; p; p = p->next) + if (p->next == this) { + p->next = next; + break; + } + } + } +} + +void Fork::ForkProcess::kill_process () const +{ + if (pid > 0) { + kill (pid, SIGKILL); + reap_child (); + } +} + +void Fork::ForkProcess::reap_child () const +{ + int status; + if (pid > 0 && waitpid (pid, &status, 0) == pid && reason) + infanticide_reason (pid, status); +} + +void Fork::ForkProcess::infanticide_reason (pid_t pid, int status) +{ + if (pid <= 0) + return; + +#ifdef SOCKETXX_HAVE_STRSIGNAL + if (WIFSTOPPED (status)) + cerr << "process " << pid << " gets " + << strsignal(WSTOPSIG (status)) << endl; + else if (WIFEXITED (status)) + cerr << "process " << pid << " exited with status " + << WEXITSTATUS (status) << endl; + else if (WIFSIGNALED (status)) + cerr << "process " << pid << " got " + << strsignal(WTERMSIG (status)) << endl; +#else + if (WIFSTOPPED (status)) + cerr << "process " << pid << " gets " + << SYS_SIGLIST [WSTOPSIG (status)] << endl; + else if (WIFEXITED (status)) + cerr << "process " << pid << " exited with status " + << WEXITSTATUS (status) << endl; + else if (WIFSIGNALED (status)) + cerr << "process " << pid << " got " + << SYS_SIGLIST [WTERMSIG (status)] << endl; +#endif // SOCKETXX_HAVE_STRSIGNAL +} + +void Fork::ForkProcess::reaper_nohang (int signo) +{ + if (signo != SIGCHLD) + return; + + int status; + pid_t wpid; + if ((wpid = waitpid (-1, &status, WNOHANG)) > 0) { + ForkProcess* prev = 0; + ForkProcess* cur = list; + while (cur) { + if (cur->pid == wpid) { + cur->pid = -1; + if (prev) + prev->next = cur->next; + else + list = list->next; + + if (cur->reason) + infanticide_reason (wpid, status); + + delete cur; + break; + } + prev = cur; + cur = cur->next; + } + } +} + +void Fork::ForkProcess::commit_suicide (int) +{ + // if this process has any children we kill them. + + ForkProcess* p = list; + while (p) { + ForkProcess* next = p->next; + if (!p->kill_child) // otherwise ForkProcess::~ForkProcess will take care + kill (p->pid, SIGKILL); + delete p; // ForkProcess::~ForkProcess will call reap_child (). + p = next; + } + + exit (0x0f); +} + +void Fork::suicide_signal (int signo) + // commit suicide at the signal signo +{ + struct sigaction sa; + sa.sa_handler = (void(*)(int)) sighnd (&Fork::ForkProcess::commit_suicide); + sigemptyset (&sa.sa_mask); + sa.sa_flags = 0; + if (sigaction (signo, &sa, 0) == -1) + perror ("Fork: Cannot commit suicide with the specified signal"); +} +#endif //windows does not get fork diff --git a/gdcm/Utilities/socketxx/socket++/fork.h b/gdcm/Utilities/socketxx/socket++/fork.h new file mode 100644 index 0000000..34a4d04 --- /dev/null +++ b/gdcm/Utilities/socketxx/socket++/fork.h @@ -0,0 +1,70 @@ +// Fork.h -*- C++ -*- socket library +// Copyright (C) 1992-1996 Gnanasekaran Swaminathan +// +// Permission is granted to use at your own risk and distribute this software +// in source and binary forms provided the above copyright notice and this +// paragraph are preserved on all copies. This software is provided "as is" +// with no express or implied warranty. +// +// Version: 12Jan97 1.11 + +#ifndef FORK_H +#define FORK_H + +#ifndef WIN32 +#include +#include +#include + +class Fork { + public: + class KillForks { + public: + KillForks () {} + ~KillForks (); + }; + + class ForkProcess { + friend Fork::KillForks::~KillForks (); + + static void infanticide_reason (pid_t pid, int status); + static void reaper_nohang (int); + + static ForkProcess* list; + + public: + pid_t pid; + const bool kill_child; + const bool reason; + ForkProcess* next; + + ForkProcess (bool kill, bool give_reason); + ~ForkProcess (); + + void kill_process () const; + void reap_child () const; + + static void commit_suicide (int); + }; + private: + static KillForks killall; + + ForkProcess* process; + + Fork (Fork&); // no copy constructor definition provided + Fork& operator = (Fork&); // no assignment operator definition provided + + public: + Fork (bool kill = 0, bool reason = 0) + : process (new ForkProcess (kill, reason)) {} + ~Fork (); + + int is_child () const { return process->pid == 0; } + int is_parent () const { return process->pid > 0; } + int process_id () const { return process->pid; } + + static void suicide_signal (int signo = SIGTERM); +}; + +#endif//windows does not define fork, and never will. +#endif // FORK_H diff --git a/gdcm/Utilities/socketxx/socket++/ftp.cpp b/gdcm/Utilities/socketxx/socket++/ftp.cpp new file mode 100644 index 0000000..7df90dd --- /dev/null +++ b/gdcm/Utilities/socketxx/socket++/ftp.cpp @@ -0,0 +1,339 @@ +// ftp.h +// Copyright (C) 1992-1996 Gnanasekaran Swaminathan +// +// Permission is granted to use at your own risk and distribute this software +// in source and binary forms provided the above copyright notice and this +// paragraph are preserved on all copies. This software is provided "as is" +// with no express or implied warranty. +// +// Version: 12Jan97 1.11 + +#include "config.h" + +#include +#include +#include +#include +#ifndef WIN32 +#include +#include +#else +#ifndef EADDRNOTAVAIL +# define EADDRNOTAVAIL WSAEADDRNOTAVAIL +#endif +#endif +#include +#include // for sprintf +#include + +#ifdef __APPLE__ +#include //for inet_ntoa +#endif//__APPLE__ + +using namespace std; + +#if defined (__osf__) && defined (__DECCXX) + extern "C" { +# include + } +#else +#ifndef WIN32 +# include +#endif +#endif + +char reptype [][8] = { + "A N", + "A T", + "A C", + "E N", + "E T", + "E C", + "I", + "L " +}; + +char filestru [][8] = { + "F", + "R", + "P" +}; + +char transmode [][8] = { + "S", + "B", + "C" +}; + +// ftpdata waits on a port at the local machine. +// When a connection is made, it receives a file from remote +// host if the ostream o is set, or it sends a file to the remote +// host if the istream i is set. +ftp::replycodea ftp::ftpbuf::ftpdata (int portno, istream* i, ostream* o, + const char* cmd, const char* arg) +{ + sockinetbuf sb (sockbuf::sock_stream, 0); + + sb.bind_until_success (portno); + useraddr (sb.localaddr ()); + + sb.listen (1); + + if (send_cmd (cmd, arg) >= ftp::rca_error) + return ftp::rca_error; + + if (o) { + sockbuf c = sb.accept (); + + // read data from c and put it in o + char buf [1024]; + std::streamsize rdsz; + + while ((rdsz = c.sgetn (buf, 1024)) != EOF) + o->write (buf, rdsz); + } else if (i) { + sockbuf c = sb.accept (); + + // read data from i and send it to c + char buf [1024]; + std::streamsize rdsz; + streambuf* rb = i->rdbuf (); + + while ((rdsz = rb->sgetn (buf, 1024)) > 0) { + int wrsz = c.sputn (buf, rdsz); + if (rdsz != wrsz) + cerr << "write error\n"; + } + } + + // Note: sockbuf object c must have been destructed by the time you reach + // here. + + return get_response (); +} + +ftp::replycodea ftp::ftpbuf::get_response () + // get all the response that one can get and send all of them to o +{ + // if o is 0, then we trash data. + int firstline = 1; + while (underflow () != EOF) { + int n = in_avail (); + if (n < 5) + continue; + + // data is of this form: 221 repsonse or 221-response + char* q = gptr (); + char* p = q; + + // zap upto + int i = 0; + for (i = 2; i <= n; i++, p++) + if (*p == '\r' && *(p+1) == '\n') { + break; + } + if (o) + o->write (q, i); + gbump (i); + + if (firstline) { + strncpy (replycode, q, 3); + replycode [3] = ' '; + if (q [3] == ' ') + break; + firstline = 0; + } else if (strncmp (q, replycode, 4) == 0) + break; + } + + return (replycodea) replycode [0]; +} + +ftp::replycodea ftp::ftpbuf::send_cmd (const char* cmd, + const char* arg) +{ + xsputn (cmd, ::strlen (cmd)); + if (arg) { + xsputn (" ", 1); + xsputn (arg, ::strlen (arg)); + } + xsputn ("\r\n", 2); + sync (); + + return get_response (); +} + +ftp::ftp (ostream* out) +: ios (0) +{ + ios::init (new ftpbuf (out)); +} + +ftp::ftpbuf::ftpbuf (ostream* out) +: protocol::protocolbuf (protocol::tcp), + o (out) +{ + replycode [4] = 0; +} + +void ftp::ftpbuf::serve_clients (int portno) +// right now no server ftp class can be used as a server +{} + +ftp::replycodea ftp::ftpbuf::cd (const char* dir) +{ + return send_cmd ("CWD", dir); +} + +ftp::replycodea ftp::ftpbuf::useraddr (sockinetaddr sa) +{ + if (sa.sin_addr.s_addr == 0) { + // local host + char hostname [64]; + if (::gethostname (hostname, 63) == -1) throw sockerr (EADDRNOTAVAIL); + hostent* hp = gethostbyname (hostname); + if (hp == 0) throw sockerr (EADDRNOTAVAIL); + memcpy (&sa.sin_addr, hp->h_addr, hp->h_length); + } + + struct in_addr ina = sa.sin_addr; + int portno = ntohs(sa.sin_port); + char* ina_p = inet_ntoa (ina); + char addr [80]; + + char* p = 0; + strcpy (addr, ina_p); + while ((p = strchr (addr, '.'))) + *p = ','; + + int hi_portno = portno >> 8; + int lo_portno = portno & 0xff; + + sprintf (addr + strlen (addr), ",%d,%d", hi_portno, lo_portno); + + return send_cmd ("PORT", addr); +} + +ftp::replycodea ftp::ftpbuf::useraddr (const char* hostname, int portno) +{ + return useraddr (sockinetaddr (hostname, portno)); +} + +ftp::replycodea ftp::ftpbuf::server_port (int portno) +{ + int hi_portno = portno >> 8; + int lo_portno = portno & 0xff; + char port [80]; + + sprintf (port, "%d,%d", hi_portno, lo_portno); + + return send_cmd ("PASV", port); +} + +ftp::replycodea ftp::ftpbuf::rep_type (ftp::reptype rt) +{ + return send_cmd ("TYPE", ::reptype [int(rt)]); +} + +ftp::replycodea ftp::ftpbuf::file_stru (ftp::filestru fs) +{ + return send_cmd ("STRU", ::filestru [int(fs)]); +} + +ftp::replycodea ftp::ftpbuf::trans_mode (ftp::transmode tm) +{ + return send_cmd ("STRU", ::transmode [int(tm)]); +} + +ftp::replycodea ftp::ftpbuf::getfile (const char* rpath, const char* lpath) +{ + if (lpath == 0) + lpath = rpath; + + if (rpath == 0) + list (); + + ofstream f (lpath); + return ftpdata (10000, 0, &f, "RETR", rpath); +} + +ftp::replycodea ftp::ftpbuf::list (const char* rpath, int justnames) +{ + if (justnames) + return ftpdata (10000, 0, o, "NLST", rpath); + else + return ftpdata (10000, 0, o, "LIST", rpath); +} + +ftp::replycodea ftp::ftpbuf::putfile (const char* lpath, const char* rpath) +{ + if (rpath == 0) + rpath = lpath; + + if (lpath == 0) + return ftp::rca_error; + + ifstream f(lpath); + return ftpdata (10000, &f, 0, "STOR", rpath); +} + +ftp::replycodea ftp::ftpbuf::putfile (const char* lpath) +{ + if (lpath == 0) + return ftp::rca_error; + + ifstream f(lpath); + return ftpdata (10000, &f, 0, "STOU", lpath); +} + +ftp::replycodea ftp::ftpbuf::append (const char* lpath, const char* rpath) +{ + if (lpath == 0) + return ftp::rca_error; + + if (rpath == 0) + rpath = lpath; + + ifstream f(lpath); + return ftpdata (10000, &f, 0, "APPE", 0); +} + +ftp::replycodea ftp::ftpbuf::allocate (int numbytes) +{ + char b[32]; + sprintf (b, "%d", numbytes); + return send_cmd ("ALLO", b); +} + +ftp::replycodea ftp::ftpbuf::restart (int marker) +{ + char b[32]; + sprintf (b, "%d", marker); + return send_cmd ("REST", b); +} + +ftp::replycodea ftp::ftpbuf::rename (const char* rpath, const char* newrpath) +{ + if (rpath == 0 || newrpath == 0) + return ftp::rca_error; + + if (send_cmd ("RNFR", rpath) >= ftp::rca_error) + return rca_error; + + return send_cmd ("RNTO", newrpath); +} + +ftp::replycodea ftp::ftpbuf::rmfile (const char* rpath) +{ + return send_cmd ("DELE", rpath); +} + +ftp::replycodea ftp::ftpbuf::rmdir (const char* rpath) +{ + return send_cmd ("RMD", rpath); +} + +ftp::replycodea ftp::ftpbuf::mkdir (const char* rpath) +{ + return send_cmd ("MKD", rpath); +} diff --git a/gdcm/Utilities/socketxx/socket++/ftp.h b/gdcm/Utilities/socketxx/socket++/ftp.h new file mode 100644 index 0000000..7efd05a --- /dev/null +++ b/gdcm/Utilities/socketxx/socket++/ftp.h @@ -0,0 +1,139 @@ +// ftp.h +// Copyright (C) 1992-1996 Gnanasekaran Swaminathan +// +// Permission is granted to use at your own risk and distribute this software +// in source and binary forms provided the above copyright notice and this +// paragraph are preserved on all copies. This software is provided "as is" +// with no express or implied warranty. +// +// Version: 12Jan97 1.11 + +#ifndef FTP_H +#define FTP_H + +#include +#ifndef WIN32 +# include +#else +#define MAXPATHLEN MAX_PATH +#endif // !WIN32 + +class ftp: public protocol { + public: + enum reptype { + rt_ascii_nonprint, + rt_ascii_telnet, + rt_ascii_asa, + rt_ebcdic_nonprint, + rt_ebcdic_telnet, + rt_ebcdic_asa, + rt_image, + rt_local + }; + + enum filestru { + fs_file, + fs_record, + fs_page + }; + + enum transmode { + tm_stream, + tm_block, + tm_comp + }; + + enum replycodea { + rca_posprelim = '1', + rca_poscomp = '2', + rca_posinter = '3', + rca_error = '4', + rca_negtranscomp = '4', + rca_negpermcomp = '5' + }; + + enum replycodeb { + rcb_syntax = '0', + rcb_info = '1', + rcb_conn = '2', + rcb_auth = '3', + rcb_unspec = '4', + rcb_filesys = '5' + }; + + class ftpbuf: public protocol::protocolbuf { + // the following are used when this is used as a server + char* usr; + char* password; + char* account; + char cwd [MAXPATHLEN]; + char parentdir [MAXPATHLEN]; + filestru fs; + transmode tm; + sockinetaddr udata; // user will listen at this addr for data conn. + int serverportno; + char replycode [5]; + + std::ostream* o; + + replycodea send_cmd (const char* cmd, const char* arg=0); + replycodea ftpdata (int portno, std::istream* i, std::ostream* out, + const char* cmd, const char* arg=0); + + ftpbuf (ftpbuf&); + ftpbuf& operator = (ftpbuf&); + public: + ftpbuf (std::ostream* out = 0); + + replycodea get_response (); + const char* reply_code () const { return replycode; } + + replycodea help () { return send_cmd ("HELP"); } + replycodea noop () { return send_cmd ("NOOP"); } + replycodea quit () { return send_cmd ("QUIT"); } + replycodea abort () { return send_cmd ("ABOR"); } + replycodea user (const char* name) {return send_cmd ("USER", name);} + replycodea passwd (const char* pw) {return send_cmd ("PASS", pw); } + replycodea acct (const char* ac) {return send_cmd ("ACCT", ac);} + replycodea cd (const char* dir); + replycodea useraddr (sockinetaddr sa); + replycodea useraddr (const char* host, int portno); + replycodea server_port (int portno); + replycodea rep_type (reptype rt); + replycodea file_stru (filestru fs); + replycodea trans_mode (transmode tm); + + // service commands + replycodea getfile (const char* rpath, const char* lpath); + replycodea list (const char* lpath=0, int justnames = 0); + replycodea putfile (const char* lpath, const char* rpath); + replycodea putfile (const char* lpath); + replycodea append (const char* lpath, const char* rpath); + replycodea allocate (int numbytes); + replycodea restart (int marker); + replycodea rename (const char* rpath, const char* newrpath); + replycodea rmfile (const char* rpath); + replycodea rmdir (const char* rpath); + replycodea mkdir (const char* rpath); + replycodea pwd () { return send_cmd ("PWD"); } + replycodea system () { return send_cmd ("SYST"); } + replycodea status () { return send_cmd ("STAT"); } + + virtual void serve_clients (int portno = -1); + virtual const char* rfc_name () const { return "ftp"; } + virtual const char* rfc_doc () const { return "rfc959"; } + }; + +protected: + ftp (): std::ios (0) {} + +public: + ftp (std::ostream* out); + ~ftp () { delete std::ios::rdbuf (); std::ios::init (0); } + + + ftpbuf* rdbuf () { return (ftpbuf*) protocol::rdbuf (); } + ftpbuf* operator -> () { return rdbuf (); } +}; + +#endif // !FTP_H diff --git a/gdcm/Utilities/socketxx/socket++/local.h b/gdcm/Utilities/socketxx/socket++/local.h new file mode 100644 index 0000000..d8661cf --- /dev/null +++ b/gdcm/Utilities/socketxx/socket++/local.h @@ -0,0 +1,136 @@ +#ifdef _WIN32 +# include +# include + + +#else + +#ifdef _S_LIBGXX +# include +# include +# include +#else +# include +# include +# include +#endif + +EXTERN_C_BEGIN +#ifdef HAVE_STRING_H +# include +#else +# ifdef HAVE_MEMORY_H +# include +# endif +#endif + +#ifdef _ALL_SOURCE +# define _BSD 44 // AIX +# include +# ifndef _POSIX_SOURCE +# define _POSIX_SOURCE +# endif +# undef _ALL_SOURCE +#endif + +#include +#ifdef HAVE_SYS_WAIT +# include +#endif +#include +#include + +#ifndef SA_RESTART +# define SA_RESTART 0 +#endif + +EXTERN_C_END + +#if defined (__sun__) && !defined (__svr4__) && defined (_S_LIBGXX) +// libg++-2.6.x has stopped providing prototypes for the following +// for sunos 4.1.x + +extern "C" { + int socketpair (int domain, int typ, int protocol, int* sockpair); + int socket (int domain, int typ, int protocol); + int bind (int sock, void* addr, int addrlen); + int connect (int sock, void* addr, int addrlen); + int listen (int sock, int num); + int accept (int sock, void* addr, int* addrlen); + + int recv (int sock, void* buf, int buflen, int msgflag); + int recvfrom (int sock, void* buf, int buflen, int msgflag, + void* addr, int* addrlen); + int send (int sock, void* buf, int buflen, int msgflag); + int sendto (int sock, void* buf, int buflen, int msgflag, + void* addr, int addrlen); + + int recvmsg (int sock, struct msghdr* msg, int msgflag); + int sendmsg (int sock, struct msghdr* msg, int msgflag); + + int select (int sock, void* rd, void* wr, void* ex, struct timeval* tv); + + int getsockopt (int sock, int level, int option, void* val, int* vallen); + int setsockopt (int sock, int level, int option, void* val, int vallen); + + int getsockname (int sock, void* addr, int* addrlen); + int getpeername (int sock, void* addr, int* addrlen); + + int ioctl (int sock, int flag, void* arg); + pid_t vfork (); +} +#endif + +#if !defined (__linux__) // LN +extern "C" int shutdown (int, int); // they have forgotten this +#else +# include +#endif + +// does not have a prototype for inet_addr () and gethostname() +//extern "C" unsigned long inet_addr (const char*); + +// arpa/in.h does not provide a protype for the following +//extern "C" char* inet_ntoa (in_addr ina); + +#if !(defined (__linux__) || defined(__FreeBSD__) || defined(__sun__)) +// extern "C" int gethostname (char* hostname, size_t len); +// the above breaks on some old MacOSX system where prototype is: +// extern "C" int gethostname (char* hostname, int len); +#if !(defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__APPLE__)) + extern char* SYS_SIGLIST []; +#endif +#endif + +#ifdef __osf__ + extern "C" { + int select (int, fd_set*, fd_set*, fd_set*, timeval*); + unsigned short ntohs (unsigned short); + unsigned short htons (unsigned short); + unsigned long ntohl (unsigned long); + unsigned long htonl (unsigned long); + } +#endif + +#ifndef SYS_ERRLIST_DECLARED + extern char* SYS_ERRLIST []; +#endif +#undef SYS_ERRLIST_DECLARED + +typedef RETSIGTYPE (*sighnd) (SIGHND_ARGTYPE); + +#endif // WIN32 + +#if defined(WIN32) && defined(GDCM_BUILD_SHARED_LIBS) +#ifdef socketxx_EXPORTS +#define MY_API __declspec(dllexport) +#else +#define MY_API __declspec(dllimport) +#endif +#else +#if __GNUC__ >= 4 +#define MY_API __attribute__ ((visibility ("default"))) +#else +#define MY_API +#endif +#endif diff --git a/gdcm/Utilities/socketxx/socket++/pipestream.cpp b/gdcm/Utilities/socketxx/socket++/pipestream.cpp new file mode 100644 index 0000000..034777b --- /dev/null +++ b/gdcm/Utilities/socketxx/socket++/pipestream.cpp @@ -0,0 +1,157 @@ +// pipestream.cpp -*- C++ -*- socket library +// Copyright (C) 2002 Herbert Straub +// +// pipestream.C -*- C++ -*- socket library +// Copyright (C) 1992-1996 Gnanasekaran Swaminathan +// +// Permission is granted to use at your own risk and distribute this software +// in source and binary forms provided the above copyright notice and this +// paragraph are preserved on all copies. This software is provided "as is" +// with no express or implied warranty. +// +// Version: 12Jan97 1.11 +// 2002-07-28 Version 1.2 (C) Herbert Straub +// Eliminating sorry_about_global_temp inititialisation. This don't work +// in combination with NewsCache. My idea is: initializing the classes with (0) +// and in the second step call ios::init (sockbuf *) and iosockstream::init ... +// The constructors of ipipestream, opipestream and iopipestream are changed. + + +#include + +#include +#include // ios +using namespace std; + +#ifdef _WIN32 +# include +# include +# include +#else +# include +# include +# include +# include +#endif + +// environ is not given a declaration in sun's +#ifndef __APPLE__ +extern char** environ; +#else +#include +#endif //__APPLE__ + +// child closes s2 and uses s1 +// parent closes s1 and uses s2 + +enum domain { af_unix = 1 }; + +iopipestream* iopipestream::head = 0; + +static sockbuf* createpipestream (const char* cmd, int mode) +{ + int sockets[2]; +#ifndef WIN32 + //FIXME!!! this code needs to work + if (::socketpair (af_unix, sockbuf::sock_stream, 0, sockets) == -1) + throw sockerr (errno); + + pid_t pid = ::vfork (); + if (pid == -1) throw sockerr (errno); + + if (pid == 0) { + // child process + if (::close (sockets[1]) == -1) throw sockerr (errno); + + if ((mode & ios::in) && ::dup2 (sockets[0], 1) == -1) + throw sockerr (errno); + if ((mode & ios::out) && ::dup2 (sockets[0], 0) == -1) + throw sockerr (errno); + if (::close (sockets[0]) == -1) throw sockerr (errno); + + const char* argv[4]; + argv[0] = "/bin/sh"; + argv[1] = "-c"; + argv[2] = cmd; + argv[3] = 0; +#ifndef __APPLE__ + execve ("/bin/sh", (char**) argv, environ); +#else + execve("/bin/sh", (char**)argv, *_NSGetEnviron()); +#endif + throw sockerr (errno); + } +#endif //wow, none of that above code works for windows at all + // parent process + if (::close (sockets[0]) == -1) throw sockerr (errno); + + sockbuf* s = new sockbuf (sockbuf::sockdesc(sockets[1])); + if (!(mode & ios::out)) s->shutdown (sockbuf::shut_write); + if (!(mode & ios::in)) s->shutdown (sockbuf::shut_read); + return s; +} + +ipipestream::ipipestream (const char* cmd) + : ios (0), isockstream(0) +{ + sockbuf *t = createpipestream (cmd, ios::in); + + ios::init (t); + isockstream::init (t); +} + +opipestream::opipestream (const char* cmd) + : ios (0), osockstream(0) +{ + sockbuf *t = createpipestream (cmd, ios::out); + + ios::init (t); + osockstream::init (t); +} + +iopipestream::iopipestream (const char* cmd) + : ios (0), iosockstream(0), + cpid (-1), next (0) +{ + sockbuf *t = createpipestream (cmd, ios::in|ios::out); + + ios::init (t); + iosockstream::init (t); +} + +iopipestream::iopipestream(sockbuf::type ty, int proto) + : ios (0), iosockstream(NULL), cpid (-1), next (head) // probably NULL is not a good idea //LN +{ +#ifndef WIN32 + if (::socketpair(af_unix, ty, proto, sp) == -1) + throw sockerr (errno); + head = this; +#endif +} + +#ifndef WIN32 +pid_t iopipestream::fork () +{ + pid_t pid = ::fork (); // donot use vfork here + if (pid == -1) throw sockerr (errno); + + if (pid > 0) { + // parent process + while (head) { + if (::close (head->sp[1]) == -1) throw sockerr (errno); + head->cpid = pid; + head->init (new sockbuf (sockbuf::sockdesc(head->sp[0]))); + head = head->next; + } + } else { + // child process + while (head) { + if (::close (head->sp[0]) == -1) throw sockerr (errno); + head->cpid = 0; + head->init (new sockbuf (sockbuf::sockdesc(head->sp[1]))); + head = head->next; + } + } + return pid; +} +#endif diff --git a/gdcm/Utilities/socketxx/socket++/pipestream.h b/gdcm/Utilities/socketxx/socket++/pipestream.h new file mode 100644 index 0000000..d146552 --- /dev/null +++ b/gdcm/Utilities/socketxx/socket++/pipestream.h @@ -0,0 +1,64 @@ +// pipestream.h -*- C++ -*- socket library +// Copyright (C) 1992-1996 Gnanasekaran Swaminathan +// +// Permission is granted to use at your own risk and distribute this software +// in source and binary forms provided the above copyright notice and this +// paragraph are preserved on all copies. This software is provided "as is" +// with no express or implied warranty. +// +// Version: 12Jan97 1.11 + +#ifndef _PIPESTREAM_H +#define _PIPESTREAM_H + +#include + +class ipipestream: public isockstream { +protected: +// ipipestream (): std::ios (0) {} +public: + ipipestream (const char* cmd); + ~ipipestream () { delete std::ios::rdbuf (); } +}; + +class opipestream: public osockstream { +protected: +// opipestream (): std::ios(0) {} +public: + opipestream (const char* cmd); + ~opipestream () { delete std::ios::rdbuf (); } +}; + +class iopipestream: public iosockstream { +private: + iopipestream(const iopipestream& sp); // no defintion provided + iopipestream& operator = (iopipestream&); // no definition provided + +protected: + int sp[2]; // socket pair + + // if iopipstream (sockbuf::type, int) created this object, + // then cpid is significant. Otherwise it is set to -1. + // cpid is child pid if this is parent + // cpid is 0 if this is child +#ifdef _WIN32 + typedef int pid_t; +#endif + pid_t cpid; + iopipestream* next; // next in the chain. Used only by + // iopipstream (sockbuf::type, int) + + static iopipestream* head; // list to take care of by fork() + +public: + iopipestream(sockbuf::type ty=sockbuf::sock_stream, int proto=0); + iopipestream(const char* cmd); + ~iopipestream () { delete std::ios::rdbuf (); } + + pid_t pid () const { return cpid; } // returns cpid +#ifndef WIN32 + static pid_t fork(); // sets cpid of all iopipestream* in the head +#endif +}; + +#endif // _PIPESTREAM_H diff --git a/gdcm/Utilities/socketxx/socket++/protocol.cpp b/gdcm/Utilities/socketxx/socket++/protocol.cpp new file mode 100644 index 0000000..da53103 --- /dev/null +++ b/gdcm/Utilities/socketxx/socket++/protocol.cpp @@ -0,0 +1,53 @@ +// protocol.h -*- C++ -*- socket library +// Copyright (C) 1992-1996 Gnanasekaran Swaminathan +// +// Permission is granted to use at your own risk and distribute this software +// in source and binary forms provided the above copyright notice and this +// paragraph are preserved on all copies. This software is provided "as is" +// with no express or implied warranty. +// +// Version: 12Jan97 1.11 + +#include +#include + +#ifdef WIN32 +#ifndef EPROTONOSUPPORT +# define EPROTONOSUPPORT WSAEPROTONOSUPPORT +#endif +#endif + +const char* protocol::protocolbuf::protocol_name () const +{ + const char* ret = ""; + if (pn == protocol::tcp) + ret = "tcp"; + if (pn == protocol::udp) + ret = "udp"; + return ret; +} + +void protocol::protocolbuf::connect () +{ + if (pn == protocol::nil) throw sockerr (EPROTONOSUPPORT); + sockinetbuf::connect (localhost (), rfc_name (), protocol_name ()); +} + +void protocol::protocolbuf::connect (unsigned long addr) + // addr is in host byte order +{ + if (pn == protocol::nil) throw sockerr (EPROTONOSUPPORT); + sockinetbuf::connect (addr, rfc_name (), protocol_name ()); +} + +void protocol::protocolbuf::connect (const char* host) +{ + if (pn == protocol::nil) throw sockerr (EPROTONOSUPPORT); + sockinetbuf::connect (host, rfc_name (), protocol_name ()); +} + +void protocol::protocolbuf::connect (const char* host, int portno) +{ + if (pn == protocol::nil) throw sockerr (EPROTONOSUPPORT); + sockinetbuf::connect (host, portno); +} diff --git a/gdcm/Utilities/socketxx/socket++/protocol.h b/gdcm/Utilities/socketxx/socket++/protocol.h new file mode 100644 index 0000000..01ad07b --- /dev/null +++ b/gdcm/Utilities/socketxx/socket++/protocol.h @@ -0,0 +1,53 @@ +// protocol.h -*- C++ -*- socket library +// Copyright (C) 1992-1996 Gnanasekaran Swaminathan +// +// Permission is granted to use at your own risk and distribute this software +// in source and binary forms provided the above copyright notice and this +// paragraph are preserved on all copies. This software is provided "as is" +// with no express or implied warranty. +// +// Version: 12Jan97 1.11 + +#ifndef PROTOCOL_H +#define PROTOCOL_H + +#include + +class MY_API protocol: public iosockstream { +public: + enum p_name { + nil = 0, + tcp = sockbuf::sock_stream, + udp = sockbuf::sock_dgram + }; + + class MY_API protocolbuf: public sockinetbuf { + private: + p_name pn; + + void bind (sockAddr& sa) { sockbuf::bind (sa); } + void connect (sockAddr& sa) { sockbuf::connect (sa); } + + public: + protocolbuf (sockinetbuf& si): sockinetbuf (si), pn (protocol::nil) {} + protocolbuf (p_name pname) + : sockinetbuf ((sockbuf::type) pname, 0), pn (pname) {} + + + void bind () { serve_clients (); } + void connect (); + void connect (unsigned long addr); + void connect (const char* host); + void connect (const char* host, int portno); + + const char* protocol_name () const; + + virtual void serve_clients (int portno = -1) = 0; + virtual const char* rfc_name () const = 0; + virtual const char* rfc_doc () const = 0; + }; + + protocol (): std::ios (0), iosockstream(NULL) {} // NULL seems like a very bad idea +}; + +#endif // PROTOCOL_H diff --git a/gdcm/Utilities/socketxx/socket++/sig.cpp b/gdcm/Utilities/socketxx/socket++/sig.cpp new file mode 100644 index 0000000..d5bcdfd --- /dev/null +++ b/gdcm/Utilities/socketxx/socket++/sig.cpp @@ -0,0 +1,221 @@ +// socket++ library. sig.C +// Copyright (C) 1992-1996 Gnanasekaran Swaminathan +// +// Permission is granted to use at your own risk and distribute this software +// in source and binary forms provided the above copyright notice and this +// paragraph are preserved on all copies. This software is provided "as is" +// with no express or implied warranty. + +#include +#include + +//explicit template instantiation. +typedef sig::phnd phnd; +typedef sig::phndlist phndlist; +//template class list; +//template class map >; + +//static sigerr se; //commended out by Herbert Straub +// Change all se to sigerr + +siginit siginit::init; +sig& sig::nal = *siginit::init.s; + +typedef void (*sighnd_type) (int); + +extern "C" { + static void sighandler (int signo) { + sig::nal.kill (signo); + } +} + +sig::hnd::hnd (int s) + : signo (s) +{ + sig::nal.set (signo, this); +} + +sig::hnd::~hnd () +{ + sig::nal.unset (signo, this); +} + +bool sig::set (int signo, sig::hnd* hnd) +{ + if (hnd == 0) return false; + + phndlist& v = smap [signo]; + + if (v.empty ()) { +#ifndef WIN32 + struct sigaction sa; + if (sigaction (signo, 0, &sa) == -1) throw sigerr(); + if (sa.sa_handler != sighnd_type (&sighandler)) { + // setting for the first time + sa.sa_handler = (void(*)(int)) sighnd_type (&sighandler); + if (sigemptyset (&sa.sa_mask) == -1) throw sigerr(); + sa.sa_flags = 0; + if (sigaction (signo, &sa, 0) == -1) throw sigerr(); + } +#endif //windows does not define sigaction + //basically, this is a way to handle some kind of error that can't exist on windows. + //see http://svn.haxx.se/dev/archive-2004-01/0685.shtml + v.push_back (hnd); + return true; + } + + phndlist::iterator j = find (v.begin(), v.end (), hnd); + if (j == v.end ()) { + v.push_back (hnd); + return true; + } + return false; +} + +bool sig::unset (int signo, sig::hnd* hnd) +{ + if (hnd == 0) return false; + + phndlist& v = smap [signo]; + + phndlist::iterator j = find (v.begin(), v.end (), hnd); + if (j != v.end ()) { + v.erase (j); + return true; + } + + return false; +} + +void sig::unset (int signo) +{ + phndlist& v = smap [signo]; + v.erase (v.begin (), v.end ()); +#ifndef WIN32 + struct sigaction sa; + if (sigaction (signo, 0, &sa) == -1) throw sigerr(); + if (sa.sa_handler == sighnd_type (&sighandler)) { + sa.sa_handler = (void(*)(int)) sighnd_type (SIG_DFL); + if (sigemptyset (&sa.sa_mask) == -1) throw sigerr(); + sa.sa_flags = 0; + if (sigaction (signo, &sa, 0) == -1) throw sigerr(); + } +#endif //windows does not define sigaction +} + +void sig::mask (int signo) const +{ +#ifndef WIN32 + sigset_t s; + if (sigemptyset (&s) == -1) throw sigerr(); + if (sigaddset (&s, signo) == -1) throw sigerr(); + + if (sigprocmask (SIG_BLOCK, &s, 0) == -1) throw sigerr(); +#endif //windows does not define sigset_t +} + +void sig::unmask (int signo) const +{ +#ifndef WIN32 + sigset_t s; + if (sigemptyset (&s) == -1) throw sigerr(); + if (sigaddset (&s, signo) == -1) throw sigerr(); + + if (sigprocmask (SIG_UNBLOCK, &s, 0) == -1) throw sigerr(); +#endif //windows does not define sigset_t +} + +void sig::mask (int siga, int sigb) const +{ +#ifndef WIN32 + struct sigaction sa; + if (sigaction (siga, 0, &sa) == -1) throw sigerr(); + if (sa.sa_handler != sighnd_type (&sighandler)) { + sa.sa_handler = (void(*)(int)) sighnd_type (&sighandler); + if (sigemptyset (&sa.sa_mask) == -1) throw sigerr(); + sa.sa_flags = 0; + } + if (sigaddset (&sa.sa_mask, sigb) == -1) throw sigerr(); + if (sigaction (siga, &sa, 0) == -1) throw sigerr(); +#endif //windows does not define sigaction +} + +void sig::unmask (int siga, int sigb) const +{ +#ifndef WIN32 + struct sigaction sa; + if (sigaction (siga, 0, &sa) == -1) throw sigerr(); + if (sa.sa_handler != sighnd_type (&sighandler)) { + sa.sa_handler = (void(*)(int)) sighnd_type (&sighandler); + if (sigemptyset (&sa.sa_mask) == -1) throw sigerr(); + sa.sa_flags = 0; + } else { + if (sigdelset (&sa.sa_mask, sigb) == -1) throw sigerr(); + } + if (sigaction (siga, &sa, 0) == -1) throw sigerr(); +#endif //windows does not define sigaction +} + +void sig::sysresume (int signo, bool set) const +{ +#ifndef WIN32 + struct sigaction sa; + if (sigaction (signo, 0, &sa) == -1) throw sigerr(); + if (sa.sa_handler != sighnd_type (&sighandler)) { + sa.sa_handler = (void(*)(int)) sighnd_type (&sighandler); + if (sigemptyset (&sa.sa_mask) == -1) throw sigerr(); + sa.sa_flags = 0; + } + +#if !(defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__sun__) || defined(__linux__) || defined(__APPLE__)) +// Early SunOS versions may have SA_INTERRUPT. I can't confirm. + if (set == false) + sa.sa_flags |= SA_INTERRUPT; + else + sa.sa_flags &= ~SA_INTERRUPT; + if (sigaction (signo, &sa, 0) == -1) throw sigerr(); +#endif +#endif //windows does not define sigaction + +} + +struct procsig { + int signo; + procsig (int s): signo (s) {} + void operator () (phnd& ph) { (*ph) (signo); } +}; + +void sig::kill (int signo) +{ + phndlist& v = smap [signo]; + + // struct procsig used to be here // LN + + for_each (v.begin (), v.end (), procsig (signo)); +} + +sigset_t sig::pending () const +{ +#ifndef WIN32 + sigset_t s; + if (sigemptyset (&s) == -1) throw sigerr(); + if (sigpending (&s) == -1) throw sigerr(); + return s; +#else + return true;//is this the right behavior for windows? +#endif //windows does not define sigset_t +} + +bool sig::ispending (int signo) const +{ +#ifndef WIN32 + sigset_t s = pending (); + switch (sigismember (&s, signo)) { + case 0: return false; + case 1: return true; + } + throw sigerr(); +#else + return true;//is this the right behavior for windows? +#endif //windows does not define sigset_t +} diff --git a/gdcm/Utilities/socketxx/socket++/sig.h b/gdcm/Utilities/socketxx/socket++/sig.h new file mode 100644 index 0000000..83a1e85 --- /dev/null +++ b/gdcm/Utilities/socketxx/socket++/sig.h @@ -0,0 +1,140 @@ +// socket++ library. sig.h +// Copyright (C) 1992-1996 Gnanasekaran Swaminathan +// +// Permission is granted to use at your own risk and distribute this software +// in source and binary forms provided the above copyright notice and this +// paragraph are preserved on all copies. This software is provided "as is" +// with no express or implied warranty. + +#ifndef SIG_H +#define SIG_H + +#include +#include +#include +#ifndef WIN32 +#include + +#else +#include +#include +#endif + +//from http://bugs.scribus.net/view.php?id=2213 +#ifndef sigset_t + #define sigset_t int +#endif +#ifndef sigemptyset + #define sigemptyset(sig) +#endif +#ifndef sigaddset + #define sigaddset( set, sig) +#endif +#ifndef sigprocmask + #define sigprocmask(a, b, c) +#endif + +// all signal handlers must be derived from +// class sig::hnd. class signal will +// maintain a list of pointers to sig::hnd +// objects for a signal. If a signal occurs, +// all sig::hnds associated with the +// signal are invoked. + +// sig::hnd object will insert itself into +// the signal handler list for a signo. Its +// dtor will delete the signal handler object +// from the signal handler list for a signo. +// Thus if a user wants to add a signal handler, +// all that needs to be done is to simply +// instantiate the signal handler object, +// and if the user wants to remove the signal +// handler, all that needs to done is to +// delete the object and its dtor will remove +// itself from the signal handler list. + +// Note: you cannot mix sig with other means +// of setting signal handlers. + +class sig; +class siginit; +class sigerr {}; + +class sig { +public: + friend class siginit; + + class hnd { + int signo; + public: + hnd (int signo); + virtual ~hnd (); + virtual void operator () (int s) = 0; + }; + + typedef hnd* phnd; + typedef std::list phndlist; + typedef std::map > sigmap; +private: + sigmap smap; + + sig () {} + ~sig () {} +public: + + // add signal handler h for signal signo + // return true on success. false otherwise. + bool set (int signo, hnd* h); + + // remove signal handler h for signal signo + // return true on success. false otherwise. + // Note: the user needs to delete h. + bool unset (int signo, hnd* h); + + // remove all signal handers for signal signo + void unset (int signo); + + // mask signal signo. Prevent signo from being seen + // by our process. Note: not all signals can be + // blocked. + void mask (int signo) const; + + // block signal signo_b when inside a signo_a handler + // Note: the process will see signo_b once signo_a handler + // is finished + void mask (int signo_a, int signo_b) const; + + // unmask signal signo. Enable signo to be seen by + // our process. + void unmask (int signo) const; + + // unblock signal signo_b when inside a signo_a handler + void unmask (int signo_a, int signo_b) const; + + // is signal signo pending? + bool ispending (int signo) const; + + // set of signals pending + sigset_t pending () const; + + // make some system calls to terminate after they are + // interrupted (set == false). Otherwise resume system + // call (set == true). Not available on all systems. + void sysresume (int signo, bool set) const; + + // process a software signal signo + void kill (int signo); + + static sig& nal; // sig::nal is the only object of class sig +}; + +class siginit { + friend class sig; + static siginit init; + sig* s; +public: + siginit (): s (0) { if (this == &init) s = new sig; } + ~siginit () { if (this == &init) delete s; } +}; + +#endif // SIG_H diff --git a/gdcm/Utilities/socketxx/socket++/smtp.cpp b/gdcm/Utilities/socketxx/socket++/smtp.cpp new file mode 100644 index 0000000..2400bfa --- /dev/null +++ b/gdcm/Utilities/socketxx/socket++/smtp.cpp @@ -0,0 +1,174 @@ +// smtp.C -*- C++ -*- socket library +// Copyright (C) 1992-1996 Gnanasekaran Swaminathan +// +// Permission is granted to use at your own risk and distribute this software +// in source and binary forms provided the above copyright notice and this +// paragraph are preserved on all copies. This software is provided "as is" +// with no express or implied warranty. +// +// Version: 12Jan97 1.11 + +#include + +#include +#include +#include +#ifndef WIN32 +#include +#endif +#include +#include + +using namespace std; + +void smtp::smtpbuf::get_response () + // get all the response that one can get and send all of them to o +{ + // if o is 0, then we trash data. + while (underflow () != EOF) { + int n = in_avail (); + if (n < 5) + continue; + + // data is of this form: 221 repsonse or 221-response + char* q = gptr (); + char* p = q; + + // zap upto + for (int i = 2; i <= n; i++, p++) + if (*p == '\r' && *(p+1) == '\n') { + if (o) + o->write (q, i); + gbump (i); + break; + } + + if (q [3] != '-') + break; + } +} + +void smtp::smtpbuf::send_cmd (const char* cmd, const char* s, const char* p) +{ + xsputn (cmd, ::strlen (cmd)); + if (s) + xsputn (s, ::strlen (s)); + if (p) + xsputn (p, ::strlen (p)); + xsputn ("\r\n", 2); + sync (); + + if (o) + get_response (); +} + +void smtp::smtpbuf::helo () +{ + if (o) + get_response (); + send_cmd ("HELO ", localhost ()); +} + +void smtp::smtpbuf::mail (const char* reverse_path) +{ + if (reverse_path) + send_cmd ("MAIL FROM:<", reverse_path, ">"); + else + send_cmd ("MAIL FROM:<>"); +} + +void smtp::smtpbuf::rcpt (const char* forward_path) +{ + if (forward_path) + send_cmd ("RCPT TO:<", forward_path, ">"); +} + +void smtp::smtpbuf::help (const char* s) +{ + send_cmd ("HELP ", s); +} + +void smtp::smtpbuf::send_buf (const char* buf, int len) +{ + if (buf == 0 || len <= 0) + return; + + // send line by line + const unsigned char* p = (const unsigned char*) buf; + + if (*p == '.') + sputc ((unsigned int) '.'); + + for (int i = 0; i < len; i++, p++) { + if (*p == '\n') { + sputc ((unsigned int) '\r'); + sputc (*p); + if (*(p+1) == '.') + sputc ((unsigned int) '.'); + } else + sputc (*p); + } +} + +void smtp::smtpbuf::data (const char* buf, int len) +{ + data (); + send_buf (buf, len); + xsputn ("\r\n.\r\n", 5); + sync (); + + if (o) + get_response (); +} + +void smtp::smtpbuf::data (const char* filename) +{ + data (); + + int fd = 0; + char buf [1024]; + int rcnt; + + if (filename == 0 || (fd = ::open (filename, O_RDONLY )) == -1) + fd = 0; + + while ((rcnt = ::read (fd, buf, 1024)) > 0) + send_buf (buf, rcnt); + + xsputn ("\r\n.\r\n", 5); + sync (); + + if (o) + get_response (); +} + +int smtp::get_response (char* buf, int len) + // same as get line except what it returns + // return 1 if output continues after this line + // return 0 if output has terminated +{ + if (len < 8) { + this->getline (buf, len); + return 0; + } + + buf [3] = 0; + this->getline (buf, len); + return buf [3] == '-'; +} + +ostream& operator << (ostream& o, smtp& s) +{ + char buf [1024]; + int cont = 1; + while (cont) { + cont = s.get_response (buf, 1024); + o << buf << endl; + } + return o; +} + + +void smtp::smtpbuf::serve_clients (int portno) +{ +} diff --git a/gdcm/Utilities/socketxx/socket++/smtp.h b/gdcm/Utilities/socketxx/socket++/smtp.h new file mode 100644 index 0000000..510f6b6 --- /dev/null +++ b/gdcm/Utilities/socketxx/socket++/smtp.h @@ -0,0 +1,69 @@ +// smtp.h -*- C++ -*- socket library +// Copyright (C) 1992-1996 Gnanasekaran Swaminathan +// +// Permission is granted to use at your own risk and distribute this software +// in source and binary forms provided the above copyright notice and this +// paragraph are preserved on all copies. This software is provided "as is" +// with no express or implied warranty. +// +// Version: 12Jan97 1.11 + +#ifndef SMTP_H +#define SMTP_H + +#include + +class smtp: public protocol { + public: + class smtpbuf : public protocol::protocolbuf { + std::ostream* o; // send all the responses to o + + void send_cmd (const char* cmd, const char* s = 0, + const char* p = 0); + void get_response (); + + smtpbuf (smtpbuf&); + smtpbuf& operator = (smtpbuf&); + public: + smtpbuf (std::ostream* out = 0) + : protocol::protocolbuf (protocol::tcp), o (out) {} + + void send_buf (const char* buf, int buflen); + + void helo (); + void quit () { send_cmd ("QUIT"); } + void turn () { send_cmd ("TURN"); } + void rset () { send_cmd ("RSET"); } + void noop () { send_cmd ("NOOP"); } + void vrfy (const char* s) { send_cmd ("VRFY ", s); } + void expn (const char* s) { send_cmd ("EXPN ", s); } + + void data () { send_cmd ("DATA"); } + void data (const char* buf, int buflen); + void data (const char* filename); // filename = 0 => stdin + + void mail (const char* reverse_path); + void rcpt (const char* forward_path); + void help (const char* s = 0); + + virtual void serve_clients (int portno = -1); + virtual const char* rfc_name () const { return "smtp"; } + virtual const char* rfc_doc () const { return "rfc821"; } + }; + +protected: + smtp(): std::ios (0) {} + +public: + smtp (std::ostream* out): std::ios (0) { std::ios::init (new smtpbuf (out)); } + ~smtp () { delete std::ios::rdbuf (); std::ios::init (0); } + + int get_response (char* buf, int len); + + smtpbuf* rdbuf () { return (smtpbuf*) protocol::rdbuf (); } + smtpbuf* operator -> () { return rdbuf (); } +}; + +extern std::ostream& operator << (std::ostream& o, smtp& s); + +#endif // SMTP_H diff --git a/gdcm/Utilities/socketxx/socket++/sockinet.cpp b/gdcm/Utilities/socketxx/socket++/sockinet.cpp new file mode 100644 index 0000000..0dc1bf7 --- /dev/null +++ b/gdcm/Utilities/socketxx/socket++/sockinet.cpp @@ -0,0 +1,437 @@ +// sockinet.C -*- C++ -*- socket library +// Copyright (C) 2002 Herbert Straub +// +// Copyright (C) 1992-1996 Gnanasekaran Swaminathan +// +// Permission is granted to use at your own risk and distribute this software +// in source and binary forms provided the above copyright notice and this +// paragraph are preserved on all copies. This software is provided "as is" +// with no express or implied warranty. +// +// Version: 12Jan97 1.11 +// 2002-07-25 Version 1.2 (C) Herbert Straub +// Adding improved Error Handling in sockerr class +// sockinetaddr::setport if the first character of the port parameter is a +// digit, then the parameter is interpreted as a number +// 2002-07-28 Version 1.2 (C) Herbert Straub +// Eliminating sorry_about_global_temp inititialisation. This don't work +// in combination with NewsCache. My idea is: initializing the classes with (0) +// and in the second step call ios::init (sockinetbuf *) and iosockstream::init ... +// The constructors of isockinet, osockinet and iosockinet are changed. + +#include "sockinet.h" +#include "config.h" + +#if defined(__CYGWIN__) || !defined(WIN32) + EXTERN_C_BEGIN +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include + EXTERN_C_END +#else +#ifndef EADDRNOTAVAIL +# define EADDRNOTAVAIL WSAEADDRNOTAVAIL +#endif +#ifndef EADDRINUSE +# define EADDRINUSE WSAEADDRINUSE +#endif +#ifndef ENOPROTOOPT +# define ENOPROTOOPT WSAENOPROTOOPT +#endif +#endif // !WIN32 + +#ifndef INADDR_NONE +#define INADDR_NONE ((in_addr_t) 0xffffffff) +#endif + +// Do not include anything below that define. That should in no case change any forward decls in +// system headers ... +#if (defined(__APPLE__)&&(__GNUC__<3)) || (defined(WIN32)&&!defined(__CYGWIN__)) || \ + (!defined(__APPLE__) && !defined(WIN32) && !defined(__GNUC__) && !defined(_XOPEN_SOURCE_EXTENDED) && !defined(__FreeBSD__)) +#define socklen_t int +#endif + +// need add throw() under Linux when compile with aggressive warning +// void herror(const char*) throw(); + +sockinetaddr::sockinetaddr () +{ + sin_family = sockinetbuf::af_inet; + sin_addr.s_addr = htonl(INADDR_ANY); + sin_port = 0; +} + +sockinetaddr::sockinetaddr(unsigned long addr_, int port_no) +// addr and port_no are in host byte order +{ + sin_family = sockinetbuf::af_inet; + sin_addr.s_addr = htonl(addr_); + sin_port = htons(port_no); +} + +sockinetaddr::sockinetaddr(unsigned long addr_, const char* sn, const char* pn) +// addr is in host byte order +{ + sin_family = sockinetbuf::af_inet; + sin_addr.s_addr = htonl (addr_); // Added by cgay@cs.uoregon.edu May 29, 1993 + setport(sn, pn); +} + +sockinetaddr::sockinetaddr (const char* host_name, int port_no) +// port_no is in host byte order +{ + setaddr(host_name); + sin_port = htons(port_no); +} + +sockinetaddr::sockinetaddr(const char* hn, const char* sn, const char* pn) +{ + setaddr(hn); + setport(sn, pn); +} + +sockinetaddr::sockinetaddr (const sockinetaddr& sina):sockAddr(sina),sockaddr_in(sina) +{ + sin_family = sockinetbuf::af_inet; + sin_addr.s_addr = sina.sin_addr.s_addr; + sin_port = sina.sin_port; +} + +void sockinetaddr::setport(const char* sn, const char* pn) +{ + if (isdigit (*sn)) { + sin_port = htons(atoi(sn)); + } else { + servent* sp = getservbyname(sn, pn); + if (sp == 0) throw sockerr (EADDRNOTAVAIL, "sockinetaddr::setport"); + sin_port = sp->s_port; + } +} + +int sockinetaddr::getport () const +{ + return ntohs (sin_port); +} + +void sockinetaddr::setaddr(const char* host_name) +{ + if ( (sin_addr.s_addr = inet_addr(host_name)) == INADDR_NONE) { + hostent* hp = gethostbyname(host_name); + if (hp == 0) throw sockerr (EADDRNOTAVAIL, "sockinetaddr::setaddr"); + memcpy(&sin_addr, hp->h_addr, hp->h_length); + sin_family = hp->h_addrtype; + } else + sin_family = sockinetbuf::af_inet; +} + +const char* sockinetaddr::gethostname () const +{ + if (sin_addr.s_addr == htonl(INADDR_ANY)) { + static char hostname[64]; + if (::gethostname(hostname, 63) == -1) return ""; + return hostname; + } + + hostent* hp = gethostbyaddr((const char*) &sin_addr, + sizeof(sin_addr), + family()); + if (hp == 0) return ""; + if (hp->h_name) return hp->h_name; + return ""; +} + +sockinetbuf::sockinetbuf (const sockbuf::sockdesc& sd_) + : sockbuf (sd_.sock) +{} + +sockinetbuf::sockinetbuf(sockbuf::type ty, int proto) + : sockbuf (af_inet, ty, proto) +{} + +sockinetaddr sockinetbuf::localaddr() const +{ + sockinetaddr sin; + socklen_t len = sin.size(); + if (::getsockname(rep->sock, sin.addr (), &len) == -1) + throw sockerr (errno, "sockinetbuf::localaddr"); + return sin; +} + +int sockinetbuf::localport() const +{ + sockinetaddr sin = localaddr(); + if (sin.family() != af_inet) return -1; + return sin.getport(); +} + +const char* sockinetbuf::localhost() const +{ + sockinetaddr sin = localaddr(); + if (sin.family() != af_inet) return ""; + return sin.gethostname(); +} + +sockinetaddr sockinetbuf::peeraddr() const +{ + sockinetaddr sin; + socklen_t len = sin.size(); + if (::getpeername(rep->sock, sin.addr (), &len) == -1) + throw sockerr (errno, "sockinetbuf::peeraddr"); + return sin; +} + +int sockinetbuf::peerport() const +{ + sockinetaddr sin = peeraddr(); + if (sin.family() != af_inet) return -1; + return sin.getport(); +} + +const char* sockinetbuf::peerhost() const +{ + sockinetaddr sin = peeraddr(); + if (sin.family() != af_inet) return ""; + return sin.gethostname(); +} + +void sockinetbuf::bind_until_success (int portno) +// a. bind to (INADDR_ANY, portno) +// b. if success return +// c. if failure and errno is EADDRINUSE, portno++ and go to step a. +{ + for (;;) { + try { + bind (portno++); + } + catch (sockerr e) { +// if (e.errno () != EADDRINUSE) throw; + if (e.serrno () != EADDRINUSE) throw; // LN + continue; + } + break; + } +} + +void sockinetbuf::bind (sockAddr& sa) +{ + sockbuf::bind (sa); +} + +void sockinetbuf::bind (int port_no) +{ + sockinetaddr sa ((long unsigned int) // LN + INADDR_ANY, port_no); + bind (sa); +} + +void sockinetbuf::bind (unsigned long addr, int port_no) +// address and portno are in host byte order +{ + sockinetaddr sa (addr, port_no); + bind (sa); +} + +void sockinetbuf::bind (const char* host_name, int port_no) +{ + sockinetaddr sa (host_name, port_no); + bind (sa); +} + +void sockinetbuf::bind (unsigned long addr, + const char* service_name, + const char* protocol_name) +{ + sockinetaddr sa (addr, service_name, protocol_name); + bind (sa); +} + +void sockinetbuf::bind (const char* host_name, + const char* service_name, + const char* protocol_name) +{ + sockinetaddr sa (host_name, service_name, protocol_name); + bind (sa); +} + +void sockinetbuf::connect (sockAddr& sa) +{ + sockbuf::connect (sa); +} + +void sockinetbuf::connect (unsigned long addr, int port_no) +// address and portno are in host byte order +{ + sockinetaddr sa (addr, port_no); + connect (sa); +} + +void sockinetbuf::connect (const char* host_name, int port_no) +{ + sockinetaddr sa (host_name, port_no); + connect (sa); +} + +void sockinetbuf::connect (unsigned long addr, + const char* service_name, + const char* protocol_name) +{ + sockinetaddr sa (addr, service_name, protocol_name); + connect (sa); +} + +void sockinetbuf::connect (const char* host_name, + const char* service_name, + const char* protocol_name) +{ + sockinetaddr sa (host_name, service_name, protocol_name); + connect (sa); +} + +sockbuf::sockdesc sockinetbuf::accept () +{ + return sockbuf::accept (); +} + +sockbuf::sockdesc sockinetbuf::accept (sockAddr& sa) +{ + return sockbuf::accept (sa); +} + +sockbuf::sockdesc sockinetbuf::accept (unsigned long addr, + int port_no) +{ + sockinetaddr sa (addr, port_no); + return accept (sa); +} + +sockbuf::sockdesc sockinetbuf::accept (const char* host_name, + int port_no) +{ + sockinetaddr sa (host_name, port_no); + return accept (sa); +} + +bool sockinetbuf::tcpnodelay () const +{ + struct protoent* proto = getprotobyname ("tcp"); + if (proto == 0) throw sockerr (ENOPROTOOPT, "sockinetbuf::tcpnodelay"); + + int old = 0; + getopt (TCP_NODELAY, &old, sizeof (old), proto->p_proto); + return old!=0; +} + +bool sockinetbuf::tcpnodelay (bool set) const +{ + struct protoent* proto = getprotobyname ("tcp"); + if (proto == 0) throw sockerr (ENOPROTOOPT, "sockinetbuf::tcpnodelay"); + + int old = 0; + int opt = set; + getopt (TCP_NODELAY, &old, sizeof (old), proto->p_proto); + setopt (TCP_NODELAY, &opt, sizeof (opt), proto->p_proto); + return old!=0; +} + +isockinet::isockinet (const sockbuf::sockdesc& sd) + : std::ios(0), isockstream(0) +{ + sockinetbuf *t = new sockinetbuf (sd); + + std::ios::init (t); + isockstream::init (t); +} + +isockinet::isockinet (sockbuf::type ty, int proto) + : std::ios (0), isockstream(0) +{ + sockinetbuf *t = new sockinetbuf (ty, proto); + + std::ios::init (t); + isockstream::init (t); +} + +isockinet::isockinet (const sockinetbuf& sb) + : std::ios (0), isockstream(0) +{ + sockinetbuf *t = new sockinetbuf (sb); + + std::ios::init (t); + isockstream::init (t); +} + +isockinet::~isockinet () +{ + delete std::ios::rdbuf (); +} + +osockinet::osockinet (const sockbuf::sockdesc& sd) + : std::ios (0), osockstream(0) +{ + sockinetbuf *t = new sockinetbuf (sd); + + std::ios::init (t); + osockstream::init (t); +} + +osockinet::osockinet (sockbuf::type ty, int proto) + : std::ios (0), osockstream(0) +{ + sockinetbuf *t = new sockinetbuf (ty, proto); + + std::ios::init (t); + osockstream::init (t); +} + +osockinet::osockinet (const sockinetbuf& sb) + : std::ios (0), osockstream(0) +{ + sockinetbuf *t = new sockinetbuf (sb); + + std::ios::init (t); + osockstream::init (t); +} + +osockinet::~osockinet () +{ + delete std::ios::rdbuf (); +} + +iosockinet::iosockinet (const sockbuf::sockdesc& sd) + : std::ios (0), iosockstream(0) +{ + sockinetbuf *t = new sockinetbuf(sd); + + std::ios::init (t); + iosockstream::init (t); +} + +iosockinet::iosockinet (sockbuf::type ty, int proto) + : std::ios (0), iosockstream (0) +{ + sockinetbuf *t = new sockinetbuf (ty, proto); + + std::ios::init (t); + iosockstream::init (t); +} + +iosockinet::iosockinet (const sockinetbuf& sb) + : std::ios (0), iosockstream(0) +{ + sockinetbuf *t = new sockinetbuf (sb); + + std::ios::init (t); + iosockstream::init (t); +} + +iosockinet::~iosockinet () +{ + delete std::ios::rdbuf (); +} diff --git a/gdcm/Utilities/socketxx/socket++/sockinet.h b/gdcm/Utilities/socketxx/socket++/sockinet.h new file mode 100644 index 0000000..cdaa261 --- /dev/null +++ b/gdcm/Utilities/socketxx/socket++/sockinet.h @@ -0,0 +1,138 @@ +// sockinet.h -*- C++ -*- socket library +// Copyright (C) 1992-1996 Gnanasekaran Swaminathan +// +// Permission is granted to use at your own risk and distribute this software +// in source and binary forms provided the above copyright notice and this +// paragraph are preserved on all copies. This software is provided "as is" +// with no express or implied warranty. +// +// Version: 12Jan97 1.11 + +#ifndef _SOCKINET_H +#define _SOCKINET_H + +#include "config.h" +#include "sockstream.h" + +#if defined(__CYGWIN__) || !defined(WIN32) +# include +#endif // !WIN32 + +class sockinetaddr: public sockAddr, public sockaddr_in +{ + protected: + void setport (const char* sn, const char* pn="tcp"); + void setaddr (const char* hn); + + public: + ~sockinetaddr () {} + sockinetaddr (); + sockinetaddr (unsigned long addr, int port_no=0); + sockinetaddr (const char* host_name, int port_no=0); + sockinetaddr (unsigned long addr, + const char* service_name, + const char* protocol_name="tcp"); + sockinetaddr (const char* host_name, + const char* service_name, + const char* protocol_name="tcp"); + sockinetaddr (const sockinetaddr& sina); + + operator void* () const { return addr_in (); } + + sockaddr_in* addr_in () const { return (sockaddr_in*) this; } + int size () const { return sizeof (sockaddr_in); } + int family() const { return sin_family; } + sockaddr* addr () const { return (sockaddr*) addr_in (); } + + int getport () const; + const char* gethostname() const; +}; + +class MY_API sockinetbuf: public sockbuf +{ + public: + enum domain { af_inet = AF_INET }; + + sockinetbuf (const sockbuf::sockdesc& sd); + sockinetbuf (const sockinetbuf& si): sockbuf (si) {} + sockinetbuf (sockbuf::type ty, int proto=0); + //sockinetbuf& operator=(const sockinetbuf& si); + ~sockinetbuf () {} + + sockinetaddr localaddr() const; + int localport() const; + const char* localhost() const; + + sockinetaddr peeraddr() const; + int peerport() const; + const char* peerhost() const; + + void bind_until_success (int portno); + + virtual void bind (sockAddr& sa); + void bind (int port_no=0); // addr is assumed to be INADDR_ANY + // and thus defaults to local host + + void bind (unsigned long addr, int port_no); + void bind (const char* host_name, int port_no=0); + void bind (unsigned long addr, + const char* service_name, + const char* protocol_name="tcp"); + void bind (const char* host_name, + const char* service_name, + const char* protocol_name="tcp"); + + virtual void connect (sockAddr& sa); + void connect (unsigned long addr, int port_no); + void connect (const char* host_name, int port_no); + void connect (unsigned long addr, + const char* service_name, + const char* protocol_name="tcp"); + void connect (const char* host_name, + const char* service_name, + const char* protocol_name="tcp"); + + virtual sockdesc accept (); + virtual sockdesc accept (sockAddr& sa); + sockdesc accept (unsigned long addr, int port_no); + sockdesc accept (const char* host_name, int port_no); + + bool tcpnodelay () const; + bool tcpnodelay (bool set) const; +}; + +class MY_API isockinet: public isockstream +{ + public: + isockinet (const sockbuf::sockdesc& sd); + isockinet (const sockinetbuf& sb); + isockinet (sockbuf::type ty=sockbuf::sock_stream, int proto=0); + ~isockinet (); + + sockinetbuf* rdbuf () { return (sockinetbuf*)std::ios::rdbuf (); } + sockinetbuf* operator -> () { return rdbuf (); } +}; + +class osockinet: public osockstream +{ + public: + osockinet (const sockbuf::sockdesc& sd); + osockinet (const sockinetbuf& sb); + osockinet (sockbuf::type ty=sockbuf::sock_stream, int proto=0); + ~osockinet (); + + sockinetbuf* rdbuf () { return (sockinetbuf*)std::ios::rdbuf (); } +}; + +class MY_API iosockinet: public iosockstream +{ + public: + iosockinet (const sockbuf::sockdesc& sd); + iosockinet (const sockinetbuf& sb); + iosockinet (sockbuf::type ty=sockbuf::sock_stream, int proto=0); + ~iosockinet (); + + sockinetbuf* rdbuf () { return (sockinetbuf*)std::ios::rdbuf (); } +}; + +#endif // _SOCKINET_H diff --git a/gdcm/Utilities/socketxx/socket++/sockstream.cpp b/gdcm/Utilities/socketxx/socket++/sockstream.cpp new file mode 100644 index 0000000..695d624 --- /dev/null +++ b/gdcm/Utilities/socketxx/socket++/sockstream.cpp @@ -0,0 +1,1093 @@ +// sockstream.C -*- C++ -*- socket library +// Copyright (C) 2002 Herbert Straub for my changes, see ChangeLog. +// +// Copyright (C) 1992-1996 Gnanasekaran Swaminathan +// +// Permission is granted to use at your own risk and distribute this software +// in source and binary forms provided the above copyright notice and this +// paragraph are preserved on all copies. This software is provided "as is" +// with no express or implied warranty. +// +// Version: 12Jan97 1.11 +// +// You can simultaneously read and write into +// a sockbuf just like you can listen and talk +// through a telephone. Hence, the read and the +// write buffers are different. That is, they do not +// share the same memory. +// +// Read: +// gptr() points to the start of the get area. +// The unread chars are gptr() - egptr(). +// base() points to the read buffer +// +// eback() is set to base() so that pbackfail() +// is called only when there is no place to +// putback a char. And pbackfail() always returns EOF. +// +// Write: +// pptr() points to the start of the put area +// The unflushed chars are pbase() - pptr() +// pbase() points to the write buffer. +// epptr() points to the end of the write buffer. +// +// Output is flushed whenever one of the following conditions +// holds: +// (1) pptr() == epptr() +// (2) EOF is written +// (3) linebuffered and '\n' is written +// +// Unbuffered: +// Input buffer size is assumed to be of size 1 and output +// buffer is of size 0. That is, egptr() <= base()+1 and +// epptr() == pbase(). +// +// Version: 1.2 2002-07-25 Herbert Straub +// Improved Error Handling - extending the sockerr class by cOperation + + +#include "sockstream.h" +#include +#include +#include +#include + +#if defined(__CYGWIN__) || !defined(WIN32) +extern "C" { +# include +# include +# include +# include +# include +} +#else +# if (_MSC_VER >= 1400) +# include +# endif +#ifndef EWOULDBLOCK +# define EWOULDBLOCK WSAEWOULDBLOCK +#endif +#ifndef EINPROGRESS +# define EINPROGRESS WSAEINPROGRESS +#endif +#ifndef EALREADY +# define EALREADY WSAEALREADY +#endif +#ifndef ENOTSOCK +# define ENOTSOCK WSAENOTSOCK +#endif +#ifndef EDESTADDRREQ +# define EDESTADDRREQ WSAEDESTADDRREQ +#endif +#ifndef EMSGSIZE +# define EMSGSIZE WSAEMSGSIZE +#endif +#ifndef EPROTOTYPE +# define EPROTOTYPE WSAEPROTOTYPE +#endif +#ifndef ENOPROTOOPT +# define ENOPROTOOPT WSAENOPROTOOPT +#endif +#ifndef EPROTONOSUPPORT +# define EPROTONOSUPPORT WSAEPROTONOSUPPORT +#endif +#ifndef ESOCKTNOSUPPORT +# define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT +#endif +#ifndef EOPNOTSUPP +# define EOPNOTSUPP WSAEOPNOTSUPP +#endif +#ifndef EPFNOSUPPORT +# define EPFNOSUPPORT WSAEPFNOSUPPORT +#endif +#ifndef EAFNOSUPPORT +# define EAFNOSUPPORT WSAEAFNOSUPPORT +#endif +#ifndef EADDRINUSE +# define EADDRINUSE WSAEADDRINUSE +#endif +#ifndef EADDRNOTAVAIL +# define EADDRNOTAVAIL WSAEADDRNOTAVAIL +#endif +#ifndef ENETDOWN +# define ENETDOWN WSAENETDOWN +#endif +#ifndef ENETUNREACH +# define ENETUNREACH WSAENETUNREACH +#endif +#ifndef ENETRESET +# define ENETRESET WSAENETRESET +#endif +#ifndef ECONNABORTED +# define ECONNABORTED WSAECONNABORTED +#endif +#ifndef ECONNRESET +# define ECONNRESET WSAECONNRESET +#endif +#ifndef ENOBUFS +# define ENOBUFS WSAENOBUFS +#endif +#ifndef EISCONN +# define EISCONN WSAEISCONN +#endif +#ifndef ENOTCONN +# define ENOTCONN WSAENOTCONN +#endif +#ifndef ESHUTDOWN +# define ESHUTDOWN WSAESHUTDOWN +#endif +#ifndef ETOOMANYREFS +# define ETOOMANYREFS WSAETOOMANYREFS +#endif +#ifndef ETIMEDOUT +# define ETIMEDOUT WSAETIMEDOUT +#endif +#ifndef ECONNREFUSED +# define ECONNREFUSED WSAECONNREFUSED +#endif +#ifndef ELOOP +# define ELOOP WSAELOOP +#endif +#ifndef EHOSTDOWN +# define EHOSTDOWN WSAEHOSTDOWN +#endif +#ifndef EHOSTUNREACH +# define EHOSTUNREACH WSAEHOSTUNREACH +#endif +#ifndef EPROCLIM +# define EPROCLIM WSAEPROCLIM +#endif +#ifndef EUSERS +# define EUSERS WSAEUSERS +#endif +#ifndef EDQUOT +# define EDQUOT WSAEDQUOT +#endif +#ifndef EISCONN +# define EISCONN WSAEISCONN +#endif +#ifndef ENOTCONN +# define ENOTCONN WSAENOTCONN +#endif +#ifndef ECONNRESET +# define ECONNRESET WSAECONNRESET +#endif +#ifndef ECONNREFUSED +# define ECONNREFUSED WSAECONNREFUSED +#endif +#ifndef ETIMEDOUT +# define ETIMEDOUT WSAETIMEDOUT +#endif +#ifndef EADDRINUSE +# define EADDRINUSE WSAEADDRINUSE +#endif +#ifndef EADDRNOTAVAIL +# define EADDRNOTAVAIL WSAEADDRNOTAVAIL +#endif + +#endif // !WIN32 + +#ifdef __sun +#include +#include +#endif + + +#ifndef BUFSIZ +# define BUFSIZ 1024 +#endif + +#ifdef FD_ZERO +# undef FD_ZERO // bzero causes so much trouble to us +#endif +#define FD_ZERO(p) (memset ((p), 0, sizeof *(p))) + +// Do not include anything below that define. That should in no case change any forward decls in +// system headers ... +#if (defined(__APPLE__)&&(__GNUC__<3)) || (defined(WIN32)&&!defined(__CYGWIN__)) || \ + (!defined(__APPLE__) && !defined(WIN32) && !defined(__GNUC__) && !defined(_XOPEN_SOURCE_EXTENDED) && !defined(__FreeBSD__)) +#define socklen_t int +#endif + +const char* sockerr::errstr () const +{ +#if defined(__CYGWIN__) || !defined(WIN32) + return strerror(err); +#else + return 0; // TODO +#endif +} + +bool sockerr::io () const +// recoverable io error. +{ + switch (err) { + case EWOULDBLOCK: + case EINPROGRESS: + case EALREADY: + return true; + } + return false; +} + +bool sockerr::arg () const +// recoverable argument error. +{ + switch (err) { + case ENOTSOCK: + case EDESTADDRREQ: + case EMSGSIZE: + case EPROTOTYPE: + case ENOPROTOOPT: + case EPROTONOSUPPORT: + case ESOCKTNOSUPPORT: + case EOPNOTSUPP: + case EPFNOSUPPORT: + case EAFNOSUPPORT: + case EADDRINUSE: + case EADDRNOTAVAIL: + return true; + } + return false; +} + +bool sockerr::op () const +// operational error encountered +{ + switch (err) { + case ENETDOWN: + case ENETUNREACH: + case ENETRESET: + case ECONNABORTED: + case ECONNRESET: + case ENOBUFS: + case EISCONN: + case ENOTCONN: + case ESHUTDOWN: + case ETOOMANYREFS: + case ETIMEDOUT: + case ECONNREFUSED: + case ELOOP: + case ENAMETOOLONG: + case EHOSTDOWN: + case EHOSTUNREACH: + case ENOTEMPTY: +# if !defined(__linux__) && !defined(__sun) && !defined(__hpux)// LN + case EPROCLIM: +# endif + case EUSERS: + case EDQUOT: + return true; + } + return false; +} + +bool sockerr::conn () const +// return true if err is EISCONN, ENOTCONN, ECONNRESET, ECONNREFUSED, +// ETIMEDOUT, or EPIPE +{ + switch (err) { + case EISCONN: + case ENOTCONN: + case ECONNRESET: + case ECONNREFUSED: + case ETIMEDOUT: + case EPIPE: + return true; + } + return false; +} + +bool sockerr::addr () const +// return true if err is EADDRINUSE or EADDRNOTAVAIL +{ + switch (err) { + case EADDRINUSE: + case EADDRNOTAVAIL: + return true; + } + return false; +} + +bool sockerr::benign () const +// return true if err is EINTR, EWOULDBLOCK, or EAGAIN +{ + switch (err) { + case EINTR: + case EWOULDBLOCK: +#if defined(EAGAIN) && (EAGAIN != EWOULDBLOCK) + case EAGAIN: +#endif + return true; + } + return false; +} + +sockbuf::sockbuf (const sockbuf::sockdesc& thesd) +// : rep (new sockbuf::sockcnt (sd.sock)) +{ + rep = new sockbuf::sockcnt (thesd.sock); + char_type* gbuf = new char_type [BUFSIZ]; + char_type* pbuf = new char_type [BUFSIZ]; + setg (gbuf, gbuf + BUFSIZ, gbuf + BUFSIZ); + setp (pbuf, pbuf + BUFSIZ); + rep->gend = gbuf + BUFSIZ; + rep->pend = pbuf + BUFSIZ; +} + +sockbuf::sockbuf (int domain, sockbuf::type st, int proto) + : rep (0) +{ +#if defined(WIN32) && !defined(__CYGWIN__) + WORD version = MAKEWORD(1,1); + WSADATA wsaData; + WSAStartup(version, &wsaData); +#endif + SOCKET soc = ::socket (domain, st, proto); + + if (soc == static_cast(SOCKET_ERROR)) +#if defined(__CYGWIN__) || !defined(WIN32) + throw sockerr (errno, "sockbuf::sockbuf"); +#else + throw sockerr(WSAGetLastError(), "sockbuf::sockbuf"); +#endif + + rep = new sockbuf::sockcnt (soc); + + char_type* gbuf = new char_type [BUFSIZ]; + char_type* pbuf = new char_type [BUFSIZ]; + setg (gbuf, gbuf + BUFSIZ, gbuf + BUFSIZ); + setp (pbuf, pbuf + BUFSIZ); + rep->gend = gbuf + BUFSIZ; + rep->pend = pbuf + BUFSIZ; +} + +sockbuf::sockbuf (const sockbuf& sb) +: +std::streambuf(), +//streambuf (sb), +rep (sb.rep) +{ + // the streambuf::streambuf (const streambuf&) is assumed + // to haved handled pbase () and gbase () correctly. + + rep->cnt++; +} + +/*sockbuf& sockbuf::operator = (const sockbuf& sb) +{ + if (this != &sb && rep != sb.rep && rep->sock != sb.rep->sock) { + streambuf::operator = (sb); + this->sockbuf::~sockbuf(); + + // the streambuf::operator = (const streambuf&) is assumed + // to have handled pbase () and gbase () correctly. + rep = sb.rep; + rep->cnt++; + } + return *this; +}*/ + +sockbuf::~sockbuf () +{ + overflow (eof); // flush write buffer + if (--rep->cnt == 0) { + delete [] pbase (); + delete [] eback (); +#if defined(__CYGWIN__) || !defined(WIN32) + int c = close (rep->sock); +#else + int c = closesocket(rep->sock); +#endif + delete rep; + if (c == SOCKET_ERROR) +#if defined(__CYGWIN__) || !defined(WIN32) + throw sockerr (errno, "sockbuf::~sockbuf", sockname.text.c_str()); +#else + throw sockerr(WSAGetLastError(), "sockbuf::~sockbuf", sockname.text.c_str()); +#endif + } +} + +bool sockbuf::is_open () const +// if socket is still connected to the peer, return true +// else return false +{ + return false; +} + +int sockbuf::sync () +// we never return -1 because we throw sockerr +// exception in the event of an error. +{ + if (pptr () && pbase () < pptr () && pptr () <= epptr ()) + { + // we have some data to flush + try { + write (pbase (), pptr () - pbase ()); + } + catch (int wlen) + { + // write was not completely successful + std::stringstream sb; + std::string err ("sockbuf::sync"); + err += "(" + sockname.text + ")"; + if (wlen) { + // reposition unwritten chars + char* pto = pbase (); + char* pfrom = pbase () + wlen; + int len = pptr () - pbase () - wlen; + while (pfrom < pptr ()) *pto++ = *pfrom++; + setp (pbase (), (char_type*) rep->pend); + pbump (len); + sb << " wlen=(" << wlen << ")"; + err += sb.rdbuf()->str(); + } + throw sockerr (errno, err.c_str ()); + } + + setp (pbase (), (char_type*) rep->pend); + } + + // we cannot restore input data back to the socket stream + // thus we do not do anything on the input stream + + return 0; +} + +std::streamsize sockbuf::showmanyc () +// return the number of chars in the input sequence +{ + if (gptr () && gptr () < egptr ()) + return egptr () - gptr (); + return 0; +} + +sockbuf::int_type sockbuf::underflow () +{ + if (gptr () == 0) + return eof; // input stream has been disabled + + if (gptr () < egptr ()) + return (unsigned char) *gptr (); // eof is a -ve number; make it + // unsigned to be diff from eof + + int rlen = read (eback (), (char*) rep->gend - (char*) eback ()); + + if (rlen == 0) + return eof; + + setg (eback (), eback (), eback () + rlen); + return (unsigned char) *gptr (); +} + +sockbuf::int_type sockbuf::uflow () +{ + int_type ret = underflow (); + if (ret == eof) + return eof; + + gbump (1); + return ret; +} + +std::streamsize sockbuf::xsgetn (char_type* s, std::streamsize n) +{ + std::streamsize rval = showmanyc (); + if (rval >= n) { + memcpy (s, gptr (), (size_t)(n * sizeof (char_type))); + gbump ((int)n); + return n; + } + + memcpy (s, gptr (), (size_t)(rval * sizeof (char_type))); + gbump ((int)rval); + + if (underflow () != eof) + return rval + xsgetn (s + rval, n - rval); + + return rval; +} + +sockbuf::int_type sockbuf::pbackfail (int) +{ + return eof; +} + +sockbuf::int_type sockbuf::overflow (sockbuf::int_type c) +// if pbase () == 0, no write is allowed and thus return eof. +// if c == eof, we sync the output and return 0. +// if pptr () == epptr (), buffer is full and thus sync the output, +// insert c into buffer, and return c. +// In all cases, if error happens, throw exception. +{ + if (pbase () == 0) + return eof; + + if (c == eof) + return sync (); + + if (pptr () == epptr ()) + sync (); + *pptr () = (char_type)c; + pbump (1); + return c; +} + +std::streamsize sockbuf::xsputn (const char_type* s, std::streamsize n) +{ + std::streamsize wval = epptr () - pptr (); + if (n <= wval) { + memcpy (pptr (), s, (size_t)(n * sizeof (char_type))); + pbump ((int)n); + return n; + } + + memcpy (pptr (), s, (size_t)(wval * sizeof (char_type))); + pbump ((int)wval); + + if (overflow () != eof) + return wval + xsputn (s + wval, n - wval); + + return wval; +} + +void sockbuf::bind (sockAddr& sa) +{ + if (::bind (rep->sock, sa.addr (), sa.size ()) == -1) + throw sockerr (errno, "sockbuf::bind", sockname.text.c_str()); +} + +void sockbuf::connect (sockAddr& sa) +{ + if (::connect(rep->sock, sa.addr (), sa.size()) == -1) + throw sockerr (errno, "sockbuf::connect", sockname.text.c_str()); +} + +void sockbuf::listen (int num) +{ + if (::listen (rep->sock, num) == -1) + throw sockerr (errno, "sockbuf::listen", sockname.text.c_str()); +} + +sockbuf::sockdesc sockbuf::accept (sockAddr& sa) +{ + socklen_t len = sa.size (); + int soc = -1; + if ((int)(soc = ::accept (rep->sock, sa.addr (), + &len)) == -1) + throw sockerr (errno, "sockbuf::sockdesc", sockname.text.c_str()); + return sockdesc (soc); +} + +sockbuf::sockdesc sockbuf::accept () +{ + int soc = -1; + if ((int)(soc = ::accept (rep->sock, 0, 0)) == -1) + throw sockerr (errno, "sockbuf::sockdesc", sockname.text.c_str()); + return sockdesc (soc); +} + +int sockbuf::read (void* buf, int len) +{ + if (rep->rtmo != -1 && is_readready (rep->rtmo)==0) { + throw sockerr (ETIMEDOUT, "sockbuf::read", sockname.text.c_str()); + } + + if (rep->oob && atmark ()) + throw sockoob (); + + int rval = 0; + //if ((rval = ::read (rep->sock, (char*) buf, len)) == -1) + if ((rval = ::recv (rep->sock, (char*) buf, len, 0)) == -1) + throw sockerr (errno, "sockbuf::read", sockname.text.c_str()); + return rval; +} + +int sockbuf::recv (void* buf, int len, int msgf) +{ + if (rep->rtmo != -1 && is_readready (rep->rtmo)==0) + throw sockerr (ETIMEDOUT, "sockbuf::recv", sockname.text.c_str()); + + if (rep->oob && atmark ()) + throw sockoob (); + + int rval = 0; + if ((rval = ::recv (rep->sock, (char*) buf, len, msgf)) == -1) + throw sockerr (errno, "sockbuf::recv", sockname.text.c_str()); + return rval; +} + +int sockbuf::recvfrom (sockAddr& sa, void* buf, int len, int msgf) +{ + if (rep->rtmo != -1 && is_readready (rep->rtmo)==0) + throw sockerr (ETIMEDOUT, "sockbuf::recvfrom", sockname.text.c_str()); + + if (rep->oob && atmark ()) + throw sockoob (); + + int rval = 0; + socklen_t __sa_len = sa.size (); + + if ((rval = ::recvfrom (rep->sock, (char*) buf, len, + msgf, sa.addr (), &__sa_len)) == -1) + throw sockerr (errno, "sockbuf::recvfrom", sockname.text.c_str()); + return rval; +} + +int sockbuf::write(const void* buf, int len) +// upon error, write throws the number of bytes writen so far instead +// of sockerr. +{ + if (rep->stmo != -1 && is_writeready (rep->stmo)==0) + throw sockerr (ETIMEDOUT, "sockbuf::write", sockname.text.c_str()); + + int wlen=0; + while(len>0) { + //int wval = ::write (rep->sock, (char*) buf, len); + int wval = ::send (rep->sock, (char*) buf, len, 0); + //assert( wval > 0 ); + if (wval == -1) throw wlen; + len -= wval; + wlen += wval; + } + return wlen; // == len if every thing is all right +} + +int sockbuf::send (const void* buf, int len, int msgf) +// upon error, write throws the number of bytes writen so far instead +// of sockerr. +{ + if (rep->stmo != -1 && is_writeready (rep->stmo)==0) + throw sockerr (ETIMEDOUT, "sockbuf::send", sockname.text.c_str()); + + int wlen=0; + while(len>0) { + int wval = ::send (rep->sock, (char*) buf, len, msgf); + if (wval == -1) throw wlen; + len -= wval; + wlen += wval; + } + return wlen; +} + +int sockbuf::sendto (sockAddr& sa, const void* buf, int len, int msgf) +// upon error, write throws the number of bytes writen so far instead +// of sockerr. +{ + if (rep->stmo != -1 && is_writeready (rep->stmo)==0) + throw sockerr (ETIMEDOUT, "sockbuf::sendto", sockname.text.c_str()); + + int wlen=0; + while(len>0) { + int wval = ::sendto (rep->sock, (char*) buf, len, msgf, + sa.addr (), sa.size()); + if (wval == -1) throw wlen; + len -= wval; + wlen += wval; + } + return wlen; +} + +#if !defined(__linux__) && !defined(WIN32) +// does not have sendmsg or recvmsg + +int sockbuf::recvmsg (msghdr* msg, int msgf) +{ + if (rep->rtmo != -1 && is_readready (rep->rtmo)==0) + throw sockerr (ETIMEDOUT, "sockbuf::recvmsg", sockname.text.c_str()); + + if (rep->oob && atmark ()) + throw sockoob (); + + int rval = ::recvmsg(rep->sock, msg, msgf); + if (rval == -1) throw sockerr (errno, "sockbuf::recvmsg", sockname.text.c_str()); + return rval; +} + +int sockbuf::sendmsg (msghdr* msg, int msgf) +// upon error, write throws the number of bytes writen so far instead +// of sockerr. +{ + if (rep->stmo != -1 && is_writeready (rep->stmo)==0) + throw sockerr (ETIMEDOUT, "sockbuf::sendmsg", sockname.text.c_str()); + + int wlen = ::sendmsg (rep->sock, msg, msgf); + if (wlen == -1) throw 0; + return wlen; +} +#endif // !__linux__ && !WIN32 + +int sockbuf::sendtimeout (int wp) +{ + int oldstmo = rep->stmo; + rep->stmo = (wp < 0) ? -1: wp; + return oldstmo; +} + +int sockbuf::recvtimeout (int wp) +{ + int oldrtmo = rep->rtmo; + rep->rtmo = (wp < 0) ? -1: wp; + return oldrtmo; +} + +int sockbuf::is_readready (int wp_sec, int wp_usec) const +{ + fd_set fds; + FD_ZERO (&fds); + FD_SET (rep->sock, &fds); + + timeval tv; + tv.tv_sec = wp_sec; + tv.tv_usec = wp_usec; + + int ret = select ((int)(rep->sock)+1, &fds, 0, 0, (wp_sec == -1) ? 0: &tv); + if (ret == -1) throw sockerr (errno, "sockbuf::is_readready", sockname.text.c_str()); + return ret; +} + +int sockbuf::is_writeready (int wp_sec, int wp_usec) const +{ + fd_set fds; + FD_ZERO (&fds); + FD_SET (rep->sock, &fds); + + timeval tv; + tv.tv_sec = wp_sec; + tv.tv_usec = wp_usec; + + int ret = select ((int)(rep->sock)+1, 0, &fds, 0, (wp_sec == -1) ? 0: &tv); + if (ret == -1) throw sockerr (errno, "sockbuf::is_writeready", sockname.text.c_str()); + return ret; +} + +int sockbuf::is_exceptionpending (int wp_sec, int wp_usec) const +{ + fd_set fds; + FD_ZERO (&fds); + FD_SET (rep->sock, &fds); + + timeval tv; + tv.tv_sec = wp_sec; + tv.tv_usec = wp_usec; + + int ret = select ((int)(rep->sock)+1, 0, 0, &fds, (wp_sec == -1) ? 0: &tv); + if (ret == -1) throw sockerr (errno, "sockbuf::is_exceptionpending", sockname.text.c_str()); + return ret; +} + +void sockbuf::shutdown (shuthow sh) +{ + switch (sh) { + case shut_read: + delete [] eback (); + setg (0, 0, 0); + break; + case shut_write: + delete [] pbase (); + setp (0, 0); + break; + case shut_readwrite: + shutdown (shut_read); + shutdown (shut_write); + break; + } + if (::shutdown(rep->sock, sh) == -1) throw sockerr (errno, "sockbuf::shutdown", sockname.text.c_str()); +} + +int sockbuf::getopt (int op, void* buf, int len, int thelevel) const +{ + socklen_t salen = len; + if (::getsockopt (rep->sock, thelevel, op, (char*) buf, &salen) == -1) + throw sockerr (errno, "sockbuf::getopt", sockname.text.c_str()); + return len; +} + +void sockbuf::setopt (int op, void* buf, int len, int thelevel) const +{ + if (::setsockopt (rep->sock, thelevel, op, (char*) buf, len) == -1) + throw sockerr (errno, "sockbuf::setopt", sockname.text.c_str()); +} + +sockbuf::type sockbuf::gettype () const +{ + int ty=0; + getopt (so_type, &ty, sizeof (ty)); + return sockbuf::type(ty); +} + +int sockbuf::clearerror () const +{ + int err=0; + getopt (so_error, &err, sizeof (err)); + return err; +} + +bool sockbuf::debug () const +{ + int old = 0; + getopt (so_debug, &old, sizeof (old)); + return old!=0; +} + +bool sockbuf::debug (bool set) const +{ + int old=0; + int opt = set; + getopt (so_debug, &old, sizeof (old)); + setopt (so_debug, &opt, sizeof (opt)); + return old!=0; +} + +bool sockbuf::reuseaddr () const +{ + int old = 0; + getopt (so_reuseaddr, &old, sizeof (old)); + return old!=0; +} + +bool sockbuf::reuseaddr (bool set) const +{ + int old=0; + int opt = set; + getopt (so_reuseaddr, &old, sizeof (old)); + setopt (so_reuseaddr, &opt, sizeof (opt)); + return old!=0; +} + +bool sockbuf::keepalive () const +{ + int old = 0; + getopt (so_keepalive, &old, sizeof (old)); + return old!=0; +} + +bool sockbuf::keepalive (bool set) const +{ + int old=0; + int opt = set; + getopt (so_keepalive, &old, sizeof (old)); + setopt (so_keepalive, &opt, sizeof (opt)); + return old!=0; +} + +bool sockbuf::dontroute () const +{ + int old = 0; + getopt (so_dontroute, &old, sizeof (old)); + return old!=0; +} + +bool sockbuf::dontroute (bool set) const +{ + int old = 0; + int opt = set; + getopt (so_dontroute, &old, sizeof (old)); + setopt (so_dontroute, &opt, sizeof (opt)); + return old!=0; +} + +bool sockbuf::broadcast () const +{ + int old=0; + getopt (so_broadcast, &old, sizeof (old)); + return old!=0; +} + +bool sockbuf::broadcast (bool set) const +{ + int old = 0; + int opt = set; + getopt (so_broadcast, &old, sizeof (old)); + setopt (so_broadcast, &opt, sizeof (opt)); + return old!=0; +} + +bool sockbuf::oobinline () const +{ + int old=0; + getopt (so_oobinline, &old, sizeof (old)); + return old!=0; +} + +bool sockbuf::oobinline (bool set) const +{ + int old = 0; + int opt = set; + getopt (so_oobinline, &old, sizeof (old)); + setopt (so_oobinline, &opt, sizeof (opt)); + return old!=0; +} + +bool sockbuf::oob (bool b) +{ + bool old = rep->oob; + rep->oob = b; + return old; +} + +sockbuf::socklinger sockbuf::linger () const +{ + socklinger old (0, 0); + getopt (so_linger, &old, sizeof (old)); + return old; +} + +sockbuf::socklinger sockbuf::linger (sockbuf::socklinger opt) const +{ + socklinger old (0, 0); + getopt (so_linger, &old, sizeof (old)); + setopt (so_linger, &opt, sizeof (opt)); + return old; +} + +int sockbuf::sendbufsz () const +{ + int old=0; + getopt (so_sndbuf, &old, sizeof (old)); + return old; +} + +int sockbuf::sendbufsz (int sz) const +{ + int old=0; + getopt (so_sndbuf, &old, sizeof (old)); + setopt (so_sndbuf, &sz, sizeof (sz)); + return old; +} + +int sockbuf::recvbufsz () const +{ + int old=0; + getopt (so_rcvbuf, &old, sizeof (old)); + return old; +} + +int sockbuf::recvbufsz (int sz) const +{ + int old=0; + getopt (so_rcvbuf, &old, sizeof (old)); + setopt (so_rcvbuf, &sz, sizeof (sz)); + return old; +} + +bool sockbuf::atmark () const +// return true, if the read pointer for socket points to an +// out of band data +{ +#if !defined(WIN32) || defined(__CYGWIN__) + int arg; + if (::ioctl (rep->sock, SIOCATMARK, &arg) == -1) + throw sockerr (errno, "sockbuf::atmark", sockname.text.c_str()); +#else + unsigned long arg = 0; + if (::ioctlsocket(rep->sock, SIOCATMARK, &arg) == SOCKET_ERROR) + throw sockerr (WSAGetLastError(), "sockbuf::atmark", sockname.text.c_str()); +#endif // !WIN32 + return arg!=0; +} + +//#if !defined(WIN32) +#if !(defined(__CYGWIN__) || defined(WIN32)) +int sockbuf::pgrp () const +// return the process group id that would receive SIGIO and SIGURG +// signals +{ + int arg; + if (::ioctl (rep->sock, SIOCGPGRP, &arg) == -1) + throw sockerr (errno, "sockbuf::pgrp", sockname.text.c_str()); + return arg; +} + +int sockbuf::pgrp (int new_pgrp) const +// set the process group id that would receive SIGIO and SIGURG signals. +// return the old pgrp +{ + int old = pgrp (); + if (::ioctl (rep->sock, SIOCSPGRP, &new_pgrp) == -1) + throw sockerr (errno, "sockbuf::pgrp", sockname.text.c_str()); + return old; +} + +void sockbuf::closeonexec (bool set) const +// if set is true, set close on exec flag +// else clear close on exec flag +{ +#if !defined( __sgi) && !defined(__hpux) + if (set) { + if (::ioctl (rep->sock, FIOCLEX, 0) == -1) + throw sockerr (errno, "sockbuf::closeonexec", sockname.text.c_str()); + } else { + if (::ioctl (rep->sock, FIONCLEX, 0) == -1) + throw sockerr (errno, "sockbuf::closeonexec", sockname.text.c_str()); + } +#endif +} +#endif // !WIN32 + +long sockbuf::nread () const +// return how many chars are available for reading in the recvbuf of +// the socket. +{ + long arg; +#if defined(__CYGWIN__) || !defined(WIN32) + if (::ioctl (rep->sock, FIONREAD, &arg) == -1) + throw sockerr (errno, "sockbuf::nread", sockname.text.c_str()); +#else + if (::ioctlsocket (rep->sock, FIONREAD, (unsigned long *) &arg) == SOCKET_ERROR) + throw sockerr (WSAGetLastError(), "sockbuf::nread", sockname.text.c_str()); +#endif // !WIN32 + return arg; +} + +long sockbuf::howmanyc () +// return how many chars are available for reading in the input buffer +// and the recvbuf of the socket. +{ + std::streamsize theShowMany = showmanyc(); + assert (theShowMany < INT_MAX); + return (long)theShowMany + nread (); +} + +void sockbuf::nbio (bool set) const +// if set is true, set socket to non-blocking io. Henceforth, any +// write or read operation will not wait if write or read would block. +// The read or write operation will result throwing a sockerr +// exception with errno set to EWOULDBLOCK. +{ +#if defined(__CYGWIN__) || !defined(WIN32) + int arg = set; + if (::ioctl (rep->sock, FIONBIO, &arg) == -1) + throw sockerr (errno, "sockbuf::nbio", sockname.text.c_str()); +#else + unsigned long arg = (set)?1:0; + if (::ioctlsocket (rep->sock, FIONBIO, &arg) == -1) + throw sockerr (WSAGetLastError(), "sockbuf::nbio", sockname.text.c_str()); +#endif // !WIN32 +} + +#if defined(__CYGWIN__) || !defined(WIN32) +void sockbuf::async (bool set) const +// if set is true, set socket for asynchronous io. If any io is +// possible on the socket, the process will get SIGIO +{ + int arg = set; + if (::ioctl (rep->sock, FIOASYNC, &arg) == -1) + throw sockerr (errno, "sockbuf::async", sockname.text.c_str()); +} +#endif // !WIN32 + +osockstream& crlf (osockstream& o) +{ + o << "\r\n"; + o.rdbuf ()->pubsync (); + return o; +} + +osockstream& lfcr (osockstream& o) +{ + o << "\n\r"; + o.rdbuf ()->pubsync (); + return o; +} diff --git a/gdcm/Utilities/socketxx/socket++/sockstream.h b/gdcm/Utilities/socketxx/socket++/sockstream.h new file mode 100644 index 0000000..4d821a2 --- /dev/null +++ b/gdcm/Utilities/socketxx/socket++/sockstream.h @@ -0,0 +1,379 @@ +// sockstream.h -*- C++ -*- socket library +// Copyright (C) 2002 Herbert Straub +// +// Copyright (C) 1992-1996 Gnanasekaran Swaminathan +// +// Permission is granted to use at your own risk and distribute this software +// in source and binary forms provided the above copyright notice and this +// paragraph are preserved on all copies. This software is provided "as is" +// with no express or implied warranty. +// +// Version: 12Jan97 1.11 +// +// Version: 1.2 2002-07-25 Herbert Straub +// Improved Error Handling - extending the sockerr class by cOperation +// 2003-03-06 Herbert Straub +// adding sockbuf::getname und setname (sockname) +// sockbuf methods throw method name + sockname + +#ifndef _SOCKSTREAM_H +#define _SOCKSTREAM_H + +#include "config.h" + +#include // must be ANSI compatible +#include // must be ANSI compatible +//#include +#include +#include +#include +#include +//#include +#if defined(__CYGWIN__) || !defined(WIN32) +# include +# include +# include +# define SOCKET int +# define SOCKET_ERROR -1 +#else +# include +# include +# include +#ifdef _MSC_VER +# pragma comment(lib, "Wininet") +#endif +#endif + + +#if defined(__linux__) || defined(__CYGWIN__) +# define MSG_MAXIOVLEN 16 +#endif // __linux__ + +//this class gets rid of the C4251 warning by internalizing the string. +//that way, if something else links to this library (and it should!), no linker conflicts should happen +//see http://www.unknownroad.com/rtfm/VisualStudio/warningC4251.html +class StringWrapper { +public: + std::string text; +}; + +// socket exception classes +class MY_API sockerr : public std::exception +{ + int err; + StringWrapper text; + public: + sockerr (int e, const char *theop = NULL): err (e) + { + if (theop != NULL) + { + text.text = theop; + } + } + sockerr (int e, const char *theop, const char *specification) : err (e) + { + if (theop != NULL) + text.text = theop; + if (specification != NULL) + { + text.text += "("; + text.text += specification; + text.text += ")"; + } + } + sockerr (int e, const std::string &theoperation): err (e) + { + text.text = theoperation; + } + sockerr (const sockerr &O): std::exception(O) + { + err = O.err; + text = O.text; + } + virtual ~sockerr() throw() {} + + const char* what () const throw() { return "sockerr"; } + const char* operation () const { return text.text.c_str(); } + +// int errno () const { return err; } + int serrno () const { return err; } // LN + const char* errstr () const; + bool error (int eno) const { return eno == err; } + + bool io () const; // non-blocking and interrupt io recoverable error. + bool arg () const; // incorrect argument supplied. recoverable error. + bool op () const; // operational error. recovery difficult. + + bool conn () const; // connection error + bool addr () const; // address error + bool benign () const; // recoverable read/write error like EINTR etc. +}; + +class sockoob +{ + public: + const char* what () const { return "sockoob"; } +}; + +// socket address classes +struct sockaddr; + +class sockAddr +{ + public: + virtual ~sockAddr() {} + virtual operator void* () const =0; + operator sockaddr* () const { return addr (); } + virtual int size() const =0; + virtual int family() const =0; + virtual sockaddr* addr () const =0; +}; + +struct msghdr; + +// socket buffer class +class MY_API sockbuf: public std::streambuf +{ + public: + enum type { + sock_stream = SOCK_STREAM, + sock_dgram = SOCK_DGRAM, + sock_raw = SOCK_RAW, + sock_rdm = SOCK_RDM, + sock_seqpacket = SOCK_SEQPACKET + }; + enum option { + so_debug = SO_DEBUG, + so_reuseaddr = SO_REUSEADDR, + so_keepalive = SO_KEEPALIVE, + so_dontroute = SO_DONTROUTE, + so_broadcast = SO_BROADCAST, + so_linger = SO_LINGER, + so_oobinline = SO_OOBINLINE, + so_sndbuf = SO_SNDBUF, + so_rcvbuf = SO_RCVBUF, + so_error = SO_ERROR, + so_type = SO_TYPE + }; + enum level { + sol_socket = SOL_SOCKET + }; + enum msgflag { + msg_oob = MSG_OOB, + msg_peek = MSG_PEEK, + msg_dontroute = MSG_DONTROUTE + +#if !(defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__APPLE__)) + ,msg_maxiovlen = MSG_MAXIOVLEN +#endif + }; + enum shuthow { + shut_read, + shut_write, + shut_readwrite + }; + enum { somaxconn = SOMAXCONN }; + struct socklinger { + int l_onoff; // option on/off + int l_linger; // linger time + + socklinger (int a, int b): l_onoff (a), l_linger (b) {} + }; + + typedef char char_type; + typedef std::streampos pos_type; + typedef std::streamoff off_type; + typedef int int_type; + typedef int seekdir; + // const int_type eof = EOF; + enum { eof = EOF }; // LN + + struct sockdesc { + int sock; + sockdesc (int d): sock (d) {} + }; + + protected: + struct sockcnt { + SOCKET sock; + int cnt; + int stmo; // -1==block, 0==poll, >0 == waiting time in secs + int rtmo; // -1==block, 0==poll, >0 == waiting time in secs + bool oob; // check for out-of-band byte while reading + void* gend; // end of input buffer + void* pend; // end of output buffer + + sockcnt(SOCKET s): + sock(s), cnt(1), stmo (-1), rtmo (-1), oob (false), + gend (0), pend (0) {} + }; + + sockcnt* rep; // counts the # refs to sock + StringWrapper sockname; // name of sockbuf - Herbert Straub + +#if 0 + virtual sockbuf* setbuf (char_type* s, int_type* n); + virtual pos_type seekoff (off_type off, + seekdir way, + ios::openmode which = ios::in|ios::out); + virtual pos_type seekpos (pos_type sp, + ios::openmode which = ios::in|ios::out); +#endif + + virtual int sync (); + + virtual std::streamsize showmanyc (); + virtual std::streamsize xsgetn (char_type* s, std::streamsize n); + virtual int_type underflow (); + virtual int_type uflow (); + + virtual int_type pbackfail (int_type c = eof); + + virtual std::streamsize xsputn (const char_type* s, std::streamsize n); + virtual int_type overflow (int_type c = eof); + + public: + sockbuf (const sockdesc& sd); + sockbuf (int domain, type, int proto); + sockbuf (const sockbuf&); +// sockbuf& operator = (const sockbuf&); + virtual ~sockbuf (); + + SOCKET sd () const { return rep->sock; } + int pubsync () { return sync (); } + virtual bool is_open () const; + + virtual void bind (sockAddr&); + virtual void connect (sockAddr&); + + void listen (int num=somaxconn); + virtual sockdesc accept(); + virtual sockdesc accept(sockAddr& sa); + + int read(void* buf, int len); + int recv (void* buf, int len, int msgf=0); + int recvfrom(sockAddr& sa, void* buf, int len, int msgf=0); + +#if !defined(__linux__) && !defined(WIN32) + int recvmsg(msghdr* msg, int msgf=0); + int sendmsg(msghdr* msg, int msgf=0); +#endif + + int write(const void* buf, int len); + int send(const void* buf, int len, int msgf=0); + int sendto (sockAddr& sa, const void* buf, int len, int msgf=0); + + int sendtimeout (int wp=-1); + int recvtimeout (int wp=-1); + int is_readready (int wp_sec, int wp_usec=0) const; + int is_writeready (int wp_sec, int wp_usec=0) const; + int is_exceptionpending (int wp_sec, int wp_usec=0) const; + + void shutdown (shuthow sh); + + int getopt(int op, void* buf, int len, + int level=sol_socket) const; + void setopt(int op, void* buf, int len, + int level=sol_socket) const; + + type gettype () const; + int clearerror () const; + bool debug () const; + bool debug (bool set) const; + bool reuseaddr () const; + bool reuseaddr (bool set) const; + bool keepalive () const; + bool keepalive (bool set) const; + bool dontroute () const; + bool dontroute (bool set) const; + bool broadcast () const; + bool broadcast (bool set) const; + bool oobinline () const; + bool oobinline (bool set) const; + bool oob () const { return rep->oob; } + bool oob (bool b); + int sendbufsz () const; + int sendbufsz (int sz) const; + int recvbufsz () const; + int recvbufsz (int sz) const; + socklinger linger() const; + socklinger linger(socklinger opt) const; + socklinger linger(int onoff, int tm) const + { return linger (socklinger (onoff, tm)); } + + bool atmark() const; + long nread() const; + long howmanyc(); + void nbio(bool set=true) const; + inline void setname(const char *name); + inline void setname(const std::string &name); + inline const std::string& getname(); + +#if defined(__CYGWIN__) || !defined(WIN32) + void async(bool set=true) const; +#endif +#if !defined(WIN32) + int pgrp() const; + int pgrp(int new_pgrp) const; + void closeonexec(bool set=true) const; +#endif +}; + +class MY_API isockstream: public std::istream +{ + protected: + //isockstream (): istream(rdbuf()), ios (0) {} + + public: + isockstream(sockbuf* sb): std::ios (sb) , std::istream(sb) {} + virtual ~isockstream () {} + + sockbuf* rdbuf () { return (sockbuf*)std::ios::rdbuf(); } + sockbuf* operator -> () { return rdbuf(); } +}; + +class osockstream: public std::ostream +{ + protected: + //osockstream (): ostream(static_cast<>rdbuf()), ios (0) {} + public: + osockstream(sockbuf* sb): std::ios (sb) , std::ostream(sb) {} + virtual ~osockstream () {} + sockbuf* rdbuf () { return (sockbuf*)std::ios::rdbuf(); } + sockbuf* operator -> () { return rdbuf(); } +}; + +class MY_API iosockstream: public std::iostream +{ + protected: + iosockstream (); + public: + iosockstream(sockbuf* sb): std::ios(sb), std::iostream(sb) {} + virtual ~iosockstream () {} + + sockbuf* rdbuf () { return (sockbuf*)std::ios::rdbuf(); } + sockbuf* operator -> () { return rdbuf(); } +}; + +// manipulators +extern osockstream& crlf (osockstream&); +extern osockstream& lfcr (osockstream&); + +// inline + +void sockbuf::setname (const char *name) +{ + sockname.text = name; +} + +void sockbuf::setname (const std::string &name) +{ + sockname.text = name; +} + +const std::string& sockbuf::getname () +{ + return sockname.text; +} + +#endif // _SOCKSTREAM_H diff --git a/gdcm/Utilities/socketxx/socket++/sockunix.cpp b/gdcm/Utilities/socketxx/socket++/sockunix.cpp new file mode 100644 index 0000000..6380d1a --- /dev/null +++ b/gdcm/Utilities/socketxx/socket++/sockunix.cpp @@ -0,0 +1,172 @@ +// sockunix.cpp -*- C++ -*- socket library +// Copyright (C) 2002 Herbert Straub +// +// sockunix.C -*- C++ -*- socket library +// Copyright (C) 1992-1996 Gnanasekaran Swaminathan +// +// Permission is granted to use at your own risk and distribute this software +// in source and binary forms provided the above copyright notice and this +// paragraph are preserved on all copies. This software is provided "as is" +// with no express or implied warranty. +// +// Version: 12Jan97 1.11 +// 2002-07-28 Version 1.2 (C) Herbert Straub +// Eliminating sorry_about_global_temp inititialisation. This don't work +// in combination with NewsCache. My idea is: initializing the classes with (0) +// and in the second step call ios::init (sockinetbuf *) and iosockstream::init ... +// The constructors of isockunix, osockunix and iosockunix are changed. + +//#include +//using namespace std; + +#include +#include +#include + +sockunixaddr::sockunixaddr (const char* path) +{ + sun_family = sockunixbuf::af_unix; + ::strcpy (sun_path, path); +} + +sockunixaddr::sockunixaddr (const sockunixaddr& suna) +{ + sun_family = sockunixbuf::af_unix; + ::strcpy (sun_path, suna.sun_path); +} + +sockunixbuf::sockunixbuf (const sockbuf::sockdesc& sd) + : sockbuf (sd.sock) +{} + +sockunixbuf::sockunixbuf (const sockunixbuf& su) + : sockbuf (su) +{} + +sockunixbuf::sockunixbuf (sockbuf::type ty, int proto) + : sockbuf (af_unix, ty, proto) +{} + +/*sockunixbuf& sockunixbuf::operator = (const sockunixbuf& su) +{ + sockbuf::operator = (su); + return *this; +}*/ + +void sockunixbuf::bind (sockAddr& sa) +{ + sockbuf::bind (sa); +} + +void sockunixbuf::bind (const char* path) +{ + sockunixaddr sa (path); + bind (sa); +} + +void sockunixbuf::connect (sockAddr& sa) +{ + sockbuf::connect (sa); +} + +void sockunixbuf::connect (const char* path) +{ + sockunixaddr sa (path); + connect (sa); +} + +isockunix::isockunix (const sockbuf::sockdesc& sd) + : ios (0), isockstream(0) +{ + sockunixbuf *t = new sockunixbuf (sd); + + ios::init (t); + isockstream::init (t); +} + +isockunix::isockunix (sockbuf::type ty, int proto) + : ios (0), isockstream(0) +{ + sockunixbuf *t = new sockunixbuf (ty, proto); + + ios::init (t); + isockstream::init (t); +} + +isockunix::isockunix (const sockunixbuf& sb) + : ios (0), isockstream(0) +{ + sockunixbuf *t = new sockunixbuf (sb); + + ios::init (t); + isockstream::init (t); +} + +isockunix::~isockunix () +{ + delete ios::rdbuf (); +} + +osockunix::osockunix (const sockbuf::sockdesc& sd) + : ios (0), osockstream(0) +{ + sockunixbuf *t = new sockunixbuf (sd); + + ios::init (t); + osockstream::init (t); +} + +osockunix::osockunix (sockbuf::type ty, int proto) + : ios (0), osockstream(0) +{ + sockunixbuf *t = new sockunixbuf (ty, proto); + + ios::init (t); + osockstream::init (t); +} + +osockunix::osockunix (const sockunixbuf& sb) + : ios (0), osockstream(0) +{ + sockunixbuf *t= new sockunixbuf (sb); + + ios::init (t); + osockstream::init (t); +} + +osockunix::~osockunix () +{ + delete ios::rdbuf (); +} + +iosockunix::iosockunix (const sockbuf::sockdesc& sd) + : ios (0), iosockstream(0) +{ + sockunixbuf *t = new sockunixbuf (sd); + + ios::init (t); + iosockstream::init (t); +} + +iosockunix::iosockunix (sockbuf::type ty, int proto) + : ios (0), iosockstream(0) +{ + sockunixbuf *t = new sockunixbuf (ty, proto); + + ios::init (t); + iosockstream::init (t); +} + +iosockunix::iosockunix (const sockunixbuf& sb) + : ios (0), iosockstream(0) +{ + sockunixbuf *t = new sockunixbuf (sb); + + ios::init (t); + iosockstream::init (t); +} + +iosockunix::~iosockunix () +{ + delete ios::rdbuf (); +} diff --git a/gdcm/Utilities/socketxx/socket++/sockunix.h b/gdcm/Utilities/socketxx/socket++/sockunix.h new file mode 100644 index 0000000..f85a2e9 --- /dev/null +++ b/gdcm/Utilities/socketxx/socket++/sockunix.h @@ -0,0 +1,83 @@ +// sockunix.h -*- C++ -*- socket library +// Copyright (C) 1992-1996 Gnanasekaran Swaminathan +// +// Permission is granted to use at your own risk and distribute this software +// in source and binary forms provided the above copyright notice and this +// paragraph are preserved on all copies. This software is provided "as is" +// with no express or implied warranty. +// +// Version: 12Jan97 1.11 + +#ifndef _SOCKUNIX_H +#define _SOCKUNIX_H + +#include +#include + +class sockunixaddr: public sockAddr, public sockaddr_un { +public: + ~sockunixaddr () {} + sockunixaddr (const char* path); + sockunixaddr (const sockunixaddr& suna); + operator void* () const { return addr_un (); } + + sockaddr_un* addr_un () const { return (sockaddr_un*)this; } + int size () const { return sizeof (sockaddr_un); } + int family () const { return sun_family; } + sockaddr* addr() const {return (sockaddr*) addr_un (); } +}; + +class sockunixbuf: public sockbuf { +public: + enum domain { af_unix = AF_UNIX }; + + sockunixbuf (const sockbuf::sockdesc& sd); + sockunixbuf (const sockunixbuf& su); + sockunixbuf (sockbuf::type ty, int proto=0); +// sockunixbuf& operator = (const sockunixbuf& su); + ~sockunixbuf () {} + + virtual void bind (sockAddr& sa); + void bind (const char* path); + + virtual void connect (sockAddr& sa); + void connect (const char* path); +}; + +class isockunix: public isockstream +{ +public: + isockunix (const sockbuf::sockdesc& sd); + isockunix (const sockunixbuf& sb); + isockunix (sockbuf::type ty=sockbuf::sock_stream, + int proto=0); + ~isockunix(); + + sockunixbuf* operator -> () { return (sockunixbuf*)rdbuf (); } +}; + +class osockunix: public osockstream +{ +public: + osockunix (const sockbuf::sockdesc& sd); + osockunix (const sockunixbuf& sb); + osockunix (sockbuf::type ty=sockbuf::sock_stream, + int proto=0); + ~osockunix (); + + sockunixbuf* operator -> () { return (sockunixbuf*)rdbuf (); } +}; + +class iosockunix: public iosockstream +{ +public: + iosockunix (const sockbuf::sockdesc& sd); + iosockunix (const sockunixbuf& sb); + iosockunix (sockbuf::type ty=sockbuf::sock_stream, + int proto=0); + ~iosockunix (); + + sockunixbuf* operator -> () { return (sockunixbuf*)rdbuf (); } +}; + +#endif // _SOCKUNIX_H diff --git a/gdcm/Utilities/wxWidgets/CMakeLists.txt b/gdcm/Utilities/wxWidgets/CMakeLists.txt new file mode 100644 index 0000000..a9b546a --- /dev/null +++ b/gdcm/Utilities/wxWidgets/CMakeLists.txt @@ -0,0 +1,67 @@ +cmake_minimum_required(VERSION 2.8.9) + +project(WXGDCM) +# wxWidgets stuff changed a lot within the 2.4.2 to 2.4.3 +# I wonder if this has something to do with adding features on a stable branch? + +#----------------------------------------------------------------------------- +find_package(VTK REQUIRED) +include(${VTK_USE_FILE}) + +if(WIN32) + set(GUI_EXECUTABLE WIN32) +else() + if(APPLE) + set(GUI_EXECUTABLE MACOSX_BUNDLE) + if(VTK_USE_COCOA) + set_source_files_properties( + wxVTKRenderWindowInteractor.cxx + PROPERTIES COMPILE_FLAGS "-ObjC++") + endif() + else() + # Ok X11 for sure, but just check: + if(NOT VTK_USE_X) + message(FATAL_ERROR "You need to have VTK_USE_X") + endif() + # See also: + # FindGTK.cmake update + # http://www.cmake.org/Bug/bug.php?op=show&bugid=3582 + #find_package(GTK REQUIRED) + #include_directories(${GTK_INCLUDE_DIR} + # #/usr/lib/wx/include/gtk-2.4/ + #) + find_package(PkgConfig) + pkg_check_modules (GTK2 gtk+-2.0) + #message("${GTK2_INCLUDE_DIRS}") + include_directories(${GTK2_INCLUDE_DIRS}) + link_libraries(${GTK2_LIBRARIES}) + + # Can I require all my user to have the gl lib on linux, even if they do not really need it... + set(WXGLCANVASLIBS "gl") + endif() +endif() + +# wxWidgets is required to build the project +# For GTK we need a couple of stuff: +# gl: GLCanvas +# adv: wxSashLayoutWindow and such... +find_package(wxWidgets COMPONENTS base core adv ${WXGLCANVASLIBS}) + +if(wxWidgets_FOUND) + include( ${wxWidgets_USE_FILE} ) +endif() + +include_directories( + ${GDCM_BINARY_DIR}/Source/Common # gdcmConfigure.h + ${GDCM_SOURCE_DIR}/Source/Common + ${GDCM_SOURCE_DIR}/Utilities/VTK +) + +add_executable(wxGDCM main.cpp wxGDCMFrame.cpp wxGDCMFrameBase.cpp wxVTKRenderWindowInteractor.cxx) +target_link_libraries(wxGDCM vtkRendering ${wxWidgets_LIBRARIES} vtkgdcm) +install(TARGETS wxGDCM + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib/static + ${CPACK_NAMELINK_TYPE} + ) diff --git a/gdcm/Utilities/wxWidgets/Copyright.txt b/gdcm/Utilities/wxWidgets/Copyright.txt new file mode 100644 index 0000000..a4c072b --- /dev/null +++ b/gdcm/Utilities/wxWidgets/Copyright.txt @@ -0,0 +1,17 @@ +/*========================================================================= + + Program: Visualization Toolkit + Module: $RCSfile: wxVTKRenderWindowInteractor.h,v $ + Language: C++ + Date: $Date: 2008/08/10 22:58:28 $ + Version: $Revision: 1.21 $ + + Copyright (c) 1993-2002 Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ diff --git a/gdcm/Utilities/wxWidgets/MyDialog.cpp b/gdcm/Utilities/wxWidgets/MyDialog.cpp new file mode 100644 index 0000000..52d6d14 --- /dev/null +++ b/gdcm/Utilities/wxWidgets/MyDialog.cpp @@ -0,0 +1,30 @@ +// -*- C++ -*- generated by wxGlade 0.4.1 on Mon Aug 28 23:13:14 2006 + +#include "MyDialog.h" + + +MyDialog::MyDialog(wxWindow* parent, int id, const wxString& title, const wxPoint& pos, const wxSize& size, long style): + wxDialog(parent, id, title, pos, size, wxDEFAULT_DIALOG_STYLE) +{ + // begin wxGlade: MyDialog::MyDialog + + set_properties(); + do_layout(); + // end wxGlade +} + + +void MyDialog::set_properties() +{ + // begin wxGlade: MyDialog::set_properties + SetTitle(wxT("About Dialog")); + // end wxGlade +} + + +void MyDialog::do_layout() +{ + // begin wxGlade: MyDialog::do_layout + Layout(); + // end wxGlade +} diff --git a/gdcm/Utilities/wxWidgets/MyDialog.h b/gdcm/Utilities/wxWidgets/MyDialog.h new file mode 100644 index 0000000..4aad2ed --- /dev/null +++ b/gdcm/Utilities/wxWidgets/MyDialog.h @@ -0,0 +1,32 @@ +// -*- C++ -*- generated by wxGlade 0.4.1 on Mon Aug 28 23:13:14 2006 + +#include +#include + +#ifndef MYDIALOG_H +#define MYDIALOG_H + +// begin wxGlade: ::dependencies +// end wxGlade + + +class MyDialog: public wxDialog { +public: + // begin wxGlade: MyDialog::ids + // end wxGlade + + MyDialog(wxWindow* parent, int id, const wxString& title, const wxPoint& pos=wxDefaultPosition, const wxSize& size=wxDefaultSize, long style=wxDEFAULT_DIALOG_STYLE); + +private: + // begin wxGlade: MyDialog::methods + void set_properties(); + void do_layout(); + // end wxGlade + +protected: + // begin wxGlade: MyDialog::attributes + // end wxGlade +}; // wxGlade: end class + + +#endif // MYDIALOG_H diff --git a/gdcm/Utilities/wxWidgets/main.cpp b/gdcm/Utilities/wxWidgets/main.cpp new file mode 100644 index 0000000..9247e03 --- /dev/null +++ b/gdcm/Utilities/wxWidgets/main.cpp @@ -0,0 +1,23 @@ +// -*- C++ -*- generated by wxGlade 0.4.1 on Sat Aug 19 15:23:11 2006 + +#include +#include +#include "wxGDCMFrame.h" + + + +class wxGDCMApp: public wxApp { +public: + bool OnInit(); +}; + +IMPLEMENT_APP(wxGDCMApp) + +bool wxGDCMApp::OnInit() +{ + wxInitAllImageHandlers(); + wxGDCMFrame* TopFrame = new wxGDCMFrame(0, -1, wxT("")); + SetTopWindow(TopFrame); + TopFrame->Show(); + return true; +} diff --git a/gdcm/Utilities/wxWidgets/wxGDCMFrame.cpp b/gdcm/Utilities/wxWidgets/wxGDCMFrame.cpp new file mode 100644 index 0000000..f7e4376 --- /dev/null +++ b/gdcm/Utilities/wxWidgets/wxGDCMFrame.cpp @@ -0,0 +1,112 @@ +// -*- C++ -*- generated by wxGlade 0.4.1 on Sat Aug 19 15:28:55 2006 + +#include "wxGDCMFrame.h" +#include "wxVTKRenderWindowInteractor.h" +#include "vtkImageViewer2.h" +#include "vtkImageViewer.h" +#include "vtkGDCMImageReader.h" +#include "vtkImageColorViewer.h" +#include "vtkImageData.h" +#include "vtkTesting.h" +#include "vtkTestUtilities.h" +#include "vtkPNGReader.h" +#include "vtkRenderer.h" + +BEGIN_EVENT_TABLE( wxGDCMFrame, wxGDCMFrameBase ) + EVT_MENU(wxID_OPEN, wxGDCMFrame::OnOpen) + EVT_MENU(wxID_HELP, wxGDCMFrame::OnAbout) + EVT_MENU(wxID_EXIT, wxGDCMFrame::OnQuit) + EVT_CLOSE( wxGDCMFrame::OnCloseFrame) +END_EVENT_TABLE( ); + + +wxGDCMFrame::wxGDCMFrame(wxWindow* parent, int id, const wxString& title, const wxPoint& pos, const wxSize& size, long style): + wxGDCMFrameBase(parent, id, title, pos, size, wxDEFAULT_FRAME_STYLE) +{ + + imageViewer = vtkImageColorViewer::New(); + //imageViewer = vtkImageViewer::New(); + //imageViewer->SetupInteractor( NULL ); + //imageViewer->SetRenderWindow( VTKWindow->GetRenderWindow() ); + //imageViewer->SetInput( vtkImageData::New() ); + char* fname = vtkTestUtilities::ExpandDataFileName(0, 0, "Data/fullhead15.png"); + + //# Image pipeline +vtkPNGReader* + reader = vtkPNGReader::New(); + reader->SetDataSpacing (0.8, 0.8, 1.5); + reader->SetFileName ( fname ); + delete[] fname; + imageViewer->SetInput ( reader->GetOutput()); + + imageViewer->SetupInteractor( VTKWindow ); + int s[2]={200,200}; + imageViewer->SetSize( s ); + Reader = vtkGDCMImageReader::New(); + directory = wxT( "" ); +} + +wxGDCMFrame::~wxGDCMFrame() +{ + //VTKWindow->Delete(); + imageViewer->Delete(); + Reader->Delete(); +} + + +void wxGDCMFrame::OnCloseFrame( wxCloseEvent& event ) +{ + std::cerr << "Close" << std::endl; + Destroy(); +} + +void wxGDCMFrame::OnOpen(wxCommandEvent& event) +{ + std::cerr << "Open" << std::endl; + wxString filemask = wxT("DICOM files (*.dcm)|*.dcm"); + wxFileDialog* dialog = new wxFileDialog( this, wxT("Open DICOM"), directory, + filename, filemask, wxOPEN ); + dialog->CentreOnParent(); + if ( dialog->ShowModal() == wxID_OK ) + { + directory = dialog->GetDirectory(); + filename = dialog->GetFilename(); + std::cerr << "Dir: " << directory.fn_str() << std::endl; + std::cerr << "File: " << filename.fn_str() << std::endl; + //wxString fn = dialog->GetFilename(); + //std::cerr << "fn: " << fn.fn_str() << std::endl; + std::string fn = (const char*)directory.fn_str(); + fn += "/"; + fn += (const char *)filename.fn_str(); + Reader->SetFileName( fn.c_str() ); + Reader->Update(); + Reader->GetOutput()->Print( std::cout ); + //imageViewer->SetInputConnection( Reader->GetOutputPort(0) ); + imageViewer->SetInput( Reader->GetOutput(0) ); + imageViewer->Modified(); + imageViewer->GetRenderer()->ResetCameraClippingRange(); + + imageViewer->Render(); + } + dialog->Close(); + dialog->Destroy(); +} + +void wxGDCMFrame::OnQuit( wxCommandEvent& event ) +{ + std::cerr << "Quit" << std::endl; + Close(true); +} + +void wxGDCMFrame::OnAbout(wxCommandEvent& WXUNUSED(event)) +{ + wxMessageBox( _T("This is the about box for wxGDCM"), _T("About wxGDCM")); +/* + wxMessageDialog* msgDialog = new wxMessageDialog( this, wxString( + text.c_str(), wxConvUTF8 ), wxString( title.c_str(), wxConvUTF8 ), wxOK ); + msgDialog->ShowModal(); + msgDialog->Close(); + msgDialog->Destroy(); +*/ + +} diff --git a/gdcm/Utilities/wxWidgets/wxGDCMFrame.h b/gdcm/Utilities/wxWidgets/wxGDCMFrame.h new file mode 100644 index 0000000..ac72d97 --- /dev/null +++ b/gdcm/Utilities/wxWidgets/wxGDCMFrame.h @@ -0,0 +1,31 @@ +#ifndef WXGDCMFRAME_H +#define WXGDCMFRAME_H + +#include "wxGDCMFrameBase.h" +class vtkImageColorViewer; +class vtkImageViewer; +class vtkGDCMImageReader; +class wxGDCMFrame: public wxGDCMFrameBase +{ +public: + wxGDCMFrame(wxWindow* parent, int id, const wxString& title, const wxPoint& pos=wxDefaultPosition, const wxSize& size=wxDefaultSize, long style=wxDEFAULT_FRAME_STYLE); + ~wxGDCMFrame(); + + + void OnQuit( wxCommandEvent& event ); + void OnOpen(wxCommandEvent& event); + void OnAbout(wxCommandEvent& event); + void OnCloseFrame( wxCloseEvent& event ); + +private: + wxString directory; + wxString filename; + vtkImageColorViewer *imageViewer; + //vtkImageViewer *imageViewer; + vtkGDCMImageReader *Reader; + + DECLARE_EVENT_TABLE( ); +}; // wxGlade: end class + + +#endif // WXGDCMFRAME_H diff --git a/gdcm/Utilities/wxWidgets/wxGDCMFrameBase.cpp b/gdcm/Utilities/wxWidgets/wxGDCMFrameBase.cpp new file mode 100644 index 0000000..a7efc74 --- /dev/null +++ b/gdcm/Utilities/wxWidgets/wxGDCMFrameBase.cpp @@ -0,0 +1,79 @@ +// -*- C++ -*- generated by wxGlade 0.4.1 on Mon Aug 28 23:13:14 2006 + +#include "wxGDCMFrameBase.h" +#include "wxVTKRenderWindowInteractor.h" + + +wxGDCMFrameBase::wxGDCMFrameBase(wxWindow* parent, int id, const wxString& title, const wxPoint& pos, const wxSize& size, long style): + wxFrame(parent, id, title, pos, size, wxDEFAULT_FRAME_STYLE) +{ + // begin wxGlade: wxGDCMFrameBase::wxGDCMFrameBase + Notebook = new wxNotebook(this, -1, wxDefaultPosition, wxDefaultSize, 0); + TopFrameMenubar = new wxMenuBar(); + SetMenuBar(TopFrameMenubar); + wxMenu* wxglade_tmp_menu_1 = new wxMenu(); + wxglade_tmp_menu_1->Append(wxID_OPEN, wxT("&Open...\tCtrl+o"), wxT("Open DICOM file"), wxITEM_NORMAL); + wxglade_tmp_menu_1->Append(wxNewId(), wxT("&Rewrite...\tCtrl+r"), wxT("Rewrite DICOM file"), wxITEM_NORMAL); + wxglade_tmp_menu_1->Append(wxNewId(), wxT("&Save...\tCtrl+s"), wxT("Save DICOM File"), wxITEM_NORMAL); + wxglade_tmp_menu_1->AppendSeparator(); + wxglade_tmp_menu_1->Append(wxID_EXIT, wxT("E&xit...\tCtrl+x"), wxT("Exit app"), wxITEM_NORMAL); + TopFrameMenubar->Append(wxglade_tmp_menu_1, wxT("File")); + wxMenu* wxglade_tmp_menu_2 = new wxMenu(); + TopFrameMenubar->Append(wxglade_tmp_menu_2, wxT("Tools")); + wxMenu* wxglade_tmp_menu_3 = new wxMenu(); + wxglade_tmp_menu_3->Append(wxID_HELP, wxT("&About...\tCtrl+a"), wxT("About Dialog"), wxITEM_NORMAL); + TopFrameMenubar->Append(wxglade_tmp_menu_3, wxT("Help")); + TopFrameStatusbar = CreateStatusBar(1, 0); + TopFrameToolbar = new wxToolBar(this, -1, wxDefaultPosition, wxDefaultSize, wxTB_HORIZONTAL|wxTB_TEXT); + SetToolBar(TopFrameToolbar); + TopFrameToolbar->AddTool(wxNewId(), wxT("tool"), wxNullBitmap, wxNullBitmap, wxITEM_NORMAL, wxT(""), wxT("")); + TopFrameToolbar->AddSeparator(); + TopFrameToolbar->AddTool(wxNewId(), wxT("tool"), wxNullBitmap, wxNullBitmap, wxITEM_NORMAL, wxT(""), wxT("")); + TopFrameToolbar->AddSeparator(); + TopFrameToolbar->AddTool(wxNewId(), wxT("tool"), wxNullBitmap, wxNullBitmap, wxITEM_NORMAL, wxT(""), wxT("")); + TopFrameToolbar->Realize(); + TreeCtrl = new wxTreeCtrl(this, -1, wxDefaultPosition, wxDefaultSize, wxTR_HAS_BUTTONS|wxTR_NO_LINES|wxTR_DEFAULT_STYLE|wxSUNKEN_BORDER); + ListCtrl = new wxListCtrl(this, -1, wxDefaultPosition, wxDefaultSize, wxLC_REPORT|wxSUNKEN_BORDER); + VTKWindow = new wxVTKRenderWindowInteractor(Notebook, -1); + Grid = new wxGrid(Notebook, -1); + + set_properties(); + do_layout(); + // end wxGlade +} + + +void wxGDCMFrameBase::set_properties() +{ + // begin wxGlade: wxGDCMFrameBase::set_properties + SetTitle(wxT("wxGDCM")); + SetSize(wxSize(725, 565)); + int TopFrameStatusbar_widths[] = { -1 }; + TopFrameStatusbar->SetStatusWidths(1, TopFrameStatusbar_widths); + const wxString TopFrameStatusbar_fields[] = { + wxT("frame_1_statusbar") + }; + for(int i = 0; i < TopFrameStatusbar->GetFieldsCount(); ++i) { + TopFrameStatusbar->SetStatusText(TopFrameStatusbar_fields[i], i); + } + Grid->CreateGrid(10, 3); + // end wxGlade +} + + +void wxGDCMFrameBase::do_layout() +{ + // begin wxGlade: wxGDCMFrameBase::do_layout + wxBoxSizer* Sizer = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* sizer_1 = new wxBoxSizer(wxVERTICAL); + sizer_1->Add(TreeCtrl, 1, wxEXPAND, 0); + sizer_1->Add(ListCtrl, 1, wxEXPAND, 0); + Sizer->Add(sizer_1, 1, wxEXPAND, 0); + Notebook->AddPage(VTKWindow, wxT("View")); + Notebook->AddPage(Grid, wxT("DICOM Tags")); + Sizer->Add(Notebook, 1, wxEXPAND, 0); + SetAutoLayout(true); + SetSizer(Sizer); + Layout(); + // end wxGlade +} diff --git a/gdcm/Utilities/wxWidgets/wxGDCMFrameBase.h b/gdcm/Utilities/wxWidgets/wxGDCMFrameBase.h new file mode 100644 index 0000000..3f303b5 --- /dev/null +++ b/gdcm/Utilities/wxWidgets/wxGDCMFrameBase.h @@ -0,0 +1,45 @@ +// -*- C++ -*- generated by wxGlade 0.4.1 on Mon Aug 28 23:13:14 2006 + +#include +#include + +#ifndef WXGDCMFRAMEBASE_H +#define WXGDCMFRAMEBASE_H + +// begin wxGlade: ::dependencies +#include +#include +#include +#include +// end wxGlade + + +class wxVTKRenderWindowInteractor; +class wxGDCMFrameBase: public wxFrame { +public: + // begin wxGlade: wxGDCMFrameBase::ids + // end wxGlade + + wxGDCMFrameBase(wxWindow* parent, int id, const wxString& title, const wxPoint& pos=wxDefaultPosition, const wxSize& size=wxDefaultSize, long style=wxDEFAULT_FRAME_STYLE); + +private: + // begin wxGlade: wxGDCMFrameBase::methods + void set_properties(); + void do_layout(); + // end wxGlade + +protected: + // begin wxGlade: wxGDCMFrameBase::attributes + wxMenuBar* TopFrameMenubar; + wxStatusBar* TopFrameStatusbar; + wxToolBar* TopFrameToolbar; + wxTreeCtrl* TreeCtrl; + wxListCtrl* ListCtrl; + wxVTKRenderWindowInteractor* VTKWindow; + wxGrid* Grid; + wxNotebook* Notebook; + // end wxGlade +}; // wxGlade: end class + + +#endif // WXGDCMFRAMEBASE_H diff --git a/gdcm/Utilities/wxWidgets/wxVTKRenderWindowInteractor.cxx b/gdcm/Utilities/wxWidgets/wxVTKRenderWindowInteractor.cxx new file mode 100644 index 0000000..69f6110 --- /dev/null +++ b/gdcm/Utilities/wxWidgets/wxVTKRenderWindowInteractor.cxx @@ -0,0 +1,811 @@ +/*========================================================================= + + Program: Visualization Toolkit + Module: $RCSfile: wxVTKRenderWindowInteractor.cxx,v $ + Language: C++ + Date: $Date: 2008/08/25 00:27:39 $ + Version: $Revision: 1.42 $ + + Copyright (c) 1993-2002 Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#include + +#include "wxVTKRenderWindowInteractor.h" + +//This is needed for vtk 3.1 : +#ifndef VTK_MAJOR_VERSION +# include "vtkVersion.h" +#endif + +#if VTK_MAJOR_VERSION > 4 || (VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 0) +# include "vtkCommand.h" +#else +# include "vtkInteractorStyle.h" +#endif +#include "vtkDebugLeaks.h" + +#ifdef __WXMAC__ +#ifdef __WXCOCOA__ +#include "vtkCocoaRenderWindow.h" +#else +#include "vtkCarbonRenderWindow.h" +#endif +#endif + +//Keep this for compatibilty reason, this was introduced in wxGTK 2.4.0 +#if (!wxCHECK_VERSION(2, 4, 0)) +wxWindow* wxGetTopLevelParent(wxWindow *win) +{ + while ( win && !win->IsTopLevel() ) + win = win->GetParent(); + return win; +} +#endif + +// To access objc calls on cocoa +#ifdef __WXCOCOA__ +#ifdef VTK_USE_COCOA +#import +// This trick is no longer need in VTK CVS, should get rid of that: +#define id Id +#else +#error Build mismatch you need both wxWidgets and VTK to be configure against Cocoa to work +#endif //VTK_USE_COCOA +#endif //__WXCOCOA__ + +#ifdef __WXGTK__ +# include // GDK_WINDOW_XWINDOW is found here in wxWidgets 2.8.0 +# include "gdk/gdkprivate.h" +#if wxCHECK_VERSION(2, 8, 0) +#ifdef __WXGTK20__ +#include +#else +#include +#endif +#else +#include +#endif +#define GetXWindow(wxwin) (wxwin)->m_wxwindow ? \ + GDK_WINDOW_XWINDOW(GTK_PIZZA((wxwin)->m_wxwindow)->bin_window) : \ + GDK_WINDOW_XWINDOW((wxwin)->m_widget->window) +#endif + +#ifdef __WXX11__ +#include "wx/x11/privx.h" +#define GetXWindow(wxwin) ((Window)(wxwin)->GetHandle()) +#endif + + +//For more info on this class please go to: +//http://wxvtk.sf.net +//This hack is for some buggy wxGTK version: +#if wxCHECK_VERSION(2, 3, 2) && !wxCHECK_VERSION(2, 4, 1) && defined(__WXGTK__) +# define WX_USE_X_CAPTURE 0 +#else +# define WX_USE_X_CAPTURE 1 +#endif + +#define ID_wxVTKRenderWindowInteractor_TIMER 1001 + +#if defined(__WXGTK__) && defined(USE_WXGLCANVAS) +IMPLEMENT_DYNAMIC_CLASS(wxVTKRenderWindowInteractor, wxGLCanvas) +#else +IMPLEMENT_DYNAMIC_CLASS(wxVTKRenderWindowInteractor, wxWindow) +#endif //__WXGTK__ + +//--------------------------------------------------------------------------- +#if defined(__WXGTK__) && defined(USE_WXGLCANVAS) +BEGIN_EVENT_TABLE(wxVTKRenderWindowInteractor, wxGLCanvas) +#else +BEGIN_EVENT_TABLE(wxVTKRenderWindowInteractor, wxWindow) +#endif //__WXGTK__ + //refresh window by doing a Render + EVT_PAINT (wxVTKRenderWindowInteractor::OnPaint) + EVT_ERASE_BACKGROUND(wxVTKRenderWindowInteractor::OnEraseBackground) + EVT_MOTION (wxVTKRenderWindowInteractor::OnMotion) + + //Bind the events to the event converters + EVT_LEFT_DOWN (wxVTKRenderWindowInteractor::OnButtonDown) + EVT_MIDDLE_DOWN (wxVTKRenderWindowInteractor::OnButtonDown) + EVT_RIGHT_DOWN (wxVTKRenderWindowInteractor::OnButtonDown) + EVT_LEFT_UP (wxVTKRenderWindowInteractor::OnButtonUp) + EVT_MIDDLE_UP (wxVTKRenderWindowInteractor::OnButtonUp) + EVT_RIGHT_UP (wxVTKRenderWindowInteractor::OnButtonUp) +#if !(VTK_MAJOR_VERSION == 3 && VTK_MINOR_VERSION == 1) + EVT_ENTER_WINDOW(wxVTKRenderWindowInteractor::OnEnter) + EVT_LEAVE_WINDOW(wxVTKRenderWindowInteractor::OnLeave) + EVT_MOUSEWHEEL (wxVTKRenderWindowInteractor::OnMouseWheel) +#if wxCHECK_VERSION(2, 8, 0) + EVT_MOUSE_CAPTURE_LOST(wxVTKRenderWindowInteractor::OnMouseCaptureLost) +#endif + EVT_KEY_DOWN (wxVTKRenderWindowInteractor::OnKeyDown) + EVT_KEY_UP (wxVTKRenderWindowInteractor::OnKeyUp) + EVT_CHAR (wxVTKRenderWindowInteractor::OnChar) +#endif + EVT_TIMER (ID_wxVTKRenderWindowInteractor_TIMER, wxVTKRenderWindowInteractor::OnTimer) + EVT_SIZE (wxVTKRenderWindowInteractor::OnSize) +END_EVENT_TABLE() + +vtkCxxRevisionMacro(wxVTKRenderWindowInteractor, "$Revision: 1.42 $") +vtkInstantiatorNewMacro(wxVTKRenderWindowInteractor) + +//--------------------------------------------------------------------------- +#if defined(__WXGTK__) && defined(USE_WXGLCANVAS) +#if (wxCHECK_VERSION(2, 8, 0)) +wxVTKRenderWindowInteractor::wxVTKRenderWindowInteractor() : wxGLCanvas(0, -1, wxDefaultPosition), vtkRenderWindowInteractor() +#else +wxVTKRenderWindowInteractor::wxVTKRenderWindowInteractor() : wxGLCanvas(), vtkRenderWindowInteractor() +#endif +#else +wxVTKRenderWindowInteractor::wxVTKRenderWindowInteractor() : wxWindow(), vtkRenderWindowInteractor() +#endif //__WXGTK__ + , timer(this, ID_wxVTKRenderWindowInteractor_TIMER) + , ActiveButton(wxEVT_NULL) + , RenderAllowed(0) + , Stereo(0) + , Handle(0) + , Created(true) + , RenderWhenDisabled(1) + , UseCaptureMouse(0) +{ +#ifdef VTK_DEBUG_LEAKS + vtkDebugLeaks::ConstructClass("wxVTKRenderWindowInteractor"); +#endif + this->RenderWindow = NULL; + this->SetRenderWindow(vtkRenderWindow::New()); + this->RenderWindow->Delete(); +} +//--------------------------------------------------------------------------- +wxVTKRenderWindowInteractor::wxVTKRenderWindowInteractor(wxWindow *parent, + wxWindowID id, + const wxPoint &pos, + const wxSize &size, + long style, + const wxString &name) +#if defined(__WXGTK__) && defined(USE_WXGLCANVAS) + : wxGLCanvas(parent, id, pos, size, style, name), vtkRenderWindowInteractor() +#else + : wxWindow(parent, id, pos, size, style, name), vtkRenderWindowInteractor() +#endif //__WXGTK__ + , timer(this, ID_wxVTKRenderWindowInteractor_TIMER) + , ActiveButton(wxEVT_NULL) + , RenderAllowed(0) + , Stereo(0) + , Handle(0) + , Created(true) + , RenderWhenDisabled(1) + , UseCaptureMouse(0) +{ +#ifdef VTK_DEBUG_LEAKS + vtkDebugLeaks::ConstructClass("wxVTKRenderWindowInteractor"); +#endif + this->RenderWindow = NULL; + this->SetRenderWindow(vtkRenderWindow::New()); + this->RenderWindow->Delete(); +#ifdef __WXMAC__ + // On Mac (Carbon) we don't get notified of the initial window size with an EVT_SIZE event, + // so we update the size information of the interactor/renderwindow here + this->UpdateSize(size.x, size.y); +#endif +} +//--------------------------------------------------------------------------- +wxVTKRenderWindowInteractor::~wxVTKRenderWindowInteractor() +{ + SetRenderWindow(NULL); + SetInteractorStyle(NULL); +} +//--------------------------------------------------------------------------- +wxVTKRenderWindowInteractor * wxVTKRenderWindowInteractor::New() +{ + // we don't make use of the objectfactory, because we're not registered + return new wxVTKRenderWindowInteractor; +} +//--------------------------------------------------------------------------- +void wxVTKRenderWindowInteractor::Initialize() +{ + int *size = RenderWindow->GetSize(); + // enable everything and start rendering + Enable(); + //RenderWindow->Start(); + + // set the size in the render window interactor + Size[0] = size[0]; + Size[1] = size[1]; + + // this is initialized + Initialized = 1; +} +//--------------------------------------------------------------------------- +void wxVTKRenderWindowInteractor::Enable() +{ + // if already enabled then done + if (Enabled) + return; + + // that's it + Enabled = 1; +#if defined(__WXGTK__) && defined(USE_WXGLCANVAS) + SetCurrent(); +#endif + Modified(); +} +//--------------------------------------------------------------------------- +bool wxVTKRenderWindowInteractor::Enable(bool enable) +{ +#if defined(__WXGTK__) && defined(USE_WXGLCANVAS) + return wxGLCanvas::Enable(enable); +#else + return wxWindow::Enable(enable); +#endif +} +//--------------------------------------------------------------------------- +void wxVTKRenderWindowInteractor::Disable() +{ + // if already disabled then done + if (!Enabled) + return; + + // that's it (we can't remove the event handler like it should be...) + Enabled = 0; + Modified(); +} +//--------------------------------------------------------------------------- +void wxVTKRenderWindowInteractor::Start() +{ + // the interactor cannot control the event loop + vtkErrorMacro( << "wxVTKRenderWindowInteractor::Start() " + "interactor cannot control event loop."); +} +//--------------------------------------------------------------------------- +void wxVTKRenderWindowInteractor::UpdateSize(int x, int y) +{ + if( RenderWindow ) + { + // if the size changed tell render window + if ( x != Size[0] || y != Size[1] ) + { + // adjust our (vtkRenderWindowInteractor size) + Size[0] = x; + Size[1] = y; + // and our RenderWindow's size + RenderWindow->SetSize(x, y); + } + } +} +//--------------------------------------------------------------------------- +int wxVTKRenderWindowInteractor::CreateTimer(int WXUNUSED(timertype)) +{ + // it's a one shot timer + if (!timer.Start(10, TRUE)) + assert(false); + + return 1; + +} +//--------------------------------------------------------------------------- +int wxVTKRenderWindowInteractor::DestroyTimer() +{ + // do nothing + return 1; +} +//--------------------------------------------------------------------------- +void wxVTKRenderWindowInteractor::OnTimer(wxTimerEvent& WXUNUSED(event)) +{ + if (!Enabled) + return; + +#if VTK_MAJOR_VERSION > 4 || (VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 0) + // new style + InvokeEvent(vtkCommand::TimerEvent, NULL); +#else + // old style + InteractorStyle->OnTimer(); +#endif +} + +//--------------------------------------------------------------------------- +// NOTE on implementation: +// Bad luck you ended up in the only tricky place of this code. +// A few note, wxWidgets still refuse to provide such convenient method +// so I have to maintain it myself, eventhough this is completely integrated +// in wxPython... +// Anyway if this happen to break for you then compare to a recent version of wxPython +// and look for the function long wxPyGetWinHandle(wxWindow* win) +// in wxPython/src/helpers.cpp +long wxVTKRenderWindowInteractor::GetHandleHack() +{ + //helper function to hide the MSW vs GTK stuff + long handle_tmp = 0; + +// __WXMSW__ is for Win32 +//__WXMAC__ stands for using Carbon C-headers, using either the CarbonLib/CFM or the native Mach-O builds (which then also use the latest features available) +// __WXGTK__ is for both gtk 1.2.x and gtk 2.x +#if defined(__WXMSW__) || defined(__WXMAC__) + handle_tmp = (long)this->GetHandle(); +#endif //__WXMSW__ + +//__WXCOCOA__ stands for using the objective-c Cocoa API +#ifdef __WXCOCOA__ + // Here is how to find the NSWindow + wxTopLevelWindow* toplevel = dynamic_cast( + wxGetTopLevelParent( this ) ); + if (toplevel != NULL ) + { + handle_tmp = (long)toplevel->GetNSWindow(); + } + // The NSView will be deducted from + // [(NSWindow*)Handle contentView] + // if only I knew how to write that in c++ +#endif //__WXCOCOA__ + + // Find and return the actual X-Window. +#if defined(__WXGTK__) || defined(__WXX11__) + return (long)GetXWindow(this); +#endif + +//#ifdef __WXMOTIF__ +// handle_tmp = (long)this->GetXWindow(); +//#endif + + return handle_tmp; +} +//--------------------------------------------------------------------------- +void wxVTKRenderWindowInteractor::OnPaint(wxPaintEvent& WXUNUSED(event)) +{ + //must always be here + wxPaintDC pDC(this); + + //do it here rather than in the cstor: this is safer. + if(!Handle) + { + Handle = GetHandleHack(); + RenderWindow->SetWindowId(reinterpret_cast(Handle)); +// Cocoa +// this->GetNSView() <-> DisplayId +// this->GetTopLevel()->GetNSWindow() <-> WindowId +#ifdef __WXMSW__ + RenderWindow->SetParentId(reinterpret_cast(this->GetParent()->GetHWND())); +#endif //__WXMSW__ + } + // get vtk to render to the wxWindows + Render(); +#ifdef __WXMAC__ + // This solves a problem with repainting after a window resize + // See also: http://sourceforge.net/mailarchive/forum.php?thread_id=31690967&forum_id=41789 +#ifdef __WXCOCOA__ + vtkCocoaRenderWindow * rwin = vtkCocoaRenderWindow::SafeDownCast(RenderWindow); + if( rwin ) + { + rwin->UpdateContext(); + } +#else + vtkCarbonRenderWindow* rwin = vtkCarbonRenderWindow::SafeDownCast(RenderWindow); + if( rwin ) + { + rwin->UpdateGLRegion(); + } +#endif +#endif +} +//--------------------------------------------------------------------------- +void wxVTKRenderWindowInteractor::OnEraseBackground(wxEraseEvent &event) +{ + //turn off background erase to reduce flickering on MSW + event.Skip(false); +} +//--------------------------------------------------------------------------- +void wxVTKRenderWindowInteractor::OnSize(wxSizeEvent& WXUNUSED(event)) +{ + int w, h; + GetClientSize(&w, &h); + UpdateSize(w, h); + + if (!Enabled) + { + return; + } + +#if VTK_MAJOR_VERSION > 4 || (VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 0) + InvokeEvent(vtkCommand::ConfigureEvent, NULL); +#endif + //this will check for Handle + //Render(); +} +//--------------------------------------------------------------------------- +void wxVTKRenderWindowInteractor::OnMotion(wxMouseEvent &event) +{ + if (!Enabled) + { + return; + } +#if VTK_MAJOR_VERSION > 4 || (VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 0) + SetEventInformationFlipY(event.GetX(), event.GetY(), + event.ControlDown(), event.ShiftDown(), '\0', 0, NULL); + + InvokeEvent(vtkCommand::MouseMoveEvent, NULL); +#else + InteractorStyle->OnMouseMove(event.ControlDown(), event.ShiftDown(), + event.GetX(), Size[1] - event.GetY() - 1); +#endif +} +//--------------------------------------------------------------------------- +#if !(VTK_MAJOR_VERSION == 3 && VTK_MINOR_VERSION == 1) +void wxVTKRenderWindowInteractor::OnEnter(wxMouseEvent &event) +{ + if (!Enabled) + { + return; + } + +#if VTK_MAJOR_VERSION > 4 || (VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 0) + // new style + SetEventInformationFlipY(event.GetX(), event.GetY(), + event.ControlDown(), event.ShiftDown(), '\0', 0, NULL); + + InvokeEvent(vtkCommand::EnterEvent, NULL); +#else + // old style + InteractorStyle->OnEnter(event.ControlDown(), event.ShiftDown(), + event.GetX(), Size[1] - event.GetY() - 1); +#endif +} +//--------------------------------------------------------------------------- +void wxVTKRenderWindowInteractor::OnLeave(wxMouseEvent &event) +{ + if (!Enabled) + { + return; + } + +#if VTK_MAJOR_VERSION > 4 || (VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 0) + // new style + SetEventInformationFlipY(event.GetX(), event.GetY(), + event.ControlDown(), event.ShiftDown(), '\0', 0, NULL); + + InvokeEvent(vtkCommand::LeaveEvent, NULL); +#else + // old style + InteractorStyle->OnLeave(event.ControlDown(), event.ShiftDown(), + event.GetX(), Size[1] - event.GetY() - 1); +#endif +} +//--------------------------------------------------------------------------- +void wxVTKRenderWindowInteractor::OnKeyDown(wxKeyEvent &event) +{ + if (!Enabled) + { + return; + } + +#if VTK_MAJOR_VERSION > 4 || (VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 0) + // new style + int keycode = event.GetKeyCode(); + char key = '\0'; + if (((unsigned int)keycode) < 256) + { + // TODO: Unicode in non-Unicode mode ?? + key = (char)keycode; + } + + // we don't get a valid mouse position inside the key event on every platform + // so we retrieve the mouse position explicitly and pass it along + wxPoint mousePos = ScreenToClient(wxGetMousePosition()); + SetEventInformationFlipY(mousePos.x, mousePos.y, + event.ControlDown(), event.ShiftDown(), key, 0, NULL); + InvokeEvent(vtkCommand::KeyPressEvent, NULL); +#else + InteractorStyle->OnKeyDown(event.ControlDown(), event.ShiftDown(), + event.GetKeyCode(), 1); +#endif + event.Skip(); +} +//--------------------------------------------------------------------------- +void wxVTKRenderWindowInteractor::OnKeyUp(wxKeyEvent &event) +{ + if (!Enabled) + { + return; + } + +#if VTK_MAJOR_VERSION > 4 || (VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 0) + // new style + int keycode = event.GetKeyCode(); + char key = '\0'; + if (((unsigned int)keycode) < 256) + { + // TODO: Unicode in non-Unicode mode ?? + key = (char)keycode; + } + + // we don't get a valid mouse position inside the key event on every platform + // so we retrieve the mouse position explicitly and pass it along + wxPoint mousePos = ScreenToClient(wxGetMousePosition()); + SetEventInformationFlipY(mousePos.x, mousePos.y, + event.ControlDown(), event.ShiftDown(), key, 0, NULL); + InvokeEvent(vtkCommand::KeyReleaseEvent, NULL); +#else + InteractorStyle->OnKeyUp(event.ControlDown(), event.ShiftDown(), + event.GetKeyCode(), 1); +#endif + event.Skip(); +} +#endif //!(VTK_MAJOR_VERSION == 3 && VTK_MINOR_VERSION == 1) + //--------------------------------------------------------------------------- +void wxVTKRenderWindowInteractor::OnChar(wxKeyEvent &event) +{ + if (!Enabled) + { + return; + } + +#if VTK_MAJOR_VERSION > 4 || (VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 0) + // new style + int keycode = event.GetKeyCode(); + char key = '\0'; + if (((unsigned int)keycode) < 256) + { + // TODO: Unicode in non-Unicode mode ?? + key = (char)keycode; + } + + // we don't get a valid mouse position inside the key event on every platform + // so we retrieve the mouse position explicitly and pass it along + wxPoint mousePos = ScreenToClient(wxGetMousePosition()); + SetEventInformationFlipY(mousePos.x, mousePos.y, + event.ControlDown(), event.ShiftDown(), key, 0, NULL); + InvokeEvent(vtkCommand::CharEvent, NULL); +#endif + event.Skip(); +} +//--------------------------------------------------------------------------- +void wxVTKRenderWindowInteractor::OnButtonDown(wxMouseEvent &event) +{ + if (!Enabled || (ActiveButton != wxEVT_NULL)) + { + return; + } + ActiveButton = event.GetEventType(); + + // On Mac (Carbon) and Windows we don't automatically get the focus when + // you click inside the window + // we therefore set the focus explicitly + // Apparently we need that on linux (GTK) too: + this->SetFocus(); + +#if VTK_MAJOR_VERSION > 4 || (VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 0) + SetEventInformationFlipY(event.GetX(), event.GetY(), + event.ControlDown(), event.ShiftDown(), '\0', 0, NULL); +#endif + + if(event.RightDown()) + { +#if VTK_MAJOR_VERSION > 4 || (VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 0) + // new style + InvokeEvent(vtkCommand::RightButtonPressEvent, NULL); +#else + // old style + InteractorStyle->OnRightButtonDown(event.ControlDown(), event.ShiftDown(), + event.GetX(), Size[1] - event.GetY() - 1); +#endif + } + else if(event.LeftDown()) + { +#if VTK_MAJOR_VERSION > 4 || (VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 0) + // new style + InvokeEvent(vtkCommand::LeftButtonPressEvent, NULL); +#else + // old style + InteractorStyle->OnLeftButtonDown(event.ControlDown(), event.ShiftDown(), + event.GetX(), Size[1] - event.GetY() - 1); +#endif + } + else if(event.MiddleDown()) + { +#if VTK_MAJOR_VERSION > 4 || (VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 0) + // new style + InvokeEvent(vtkCommand::MiddleButtonPressEvent, NULL); +#else + // old style + InteractorStyle->OnMiddleButtonDown(event.ControlDown(), event.ShiftDown(), + event.GetX(), Size[1] - event.GetY() - 1); +#endif + } + //save the button and capture mouse until the button is released + //Only if : + //1. it is possible (WX_USE_X_CAPTURE) + //2. user decided to. + if ((ActiveButton != wxEVT_NULL) && WX_USE_X_CAPTURE && UseCaptureMouse) + { + CaptureMouse(); + } +} +//--------------------------------------------------------------------------- +void wxVTKRenderWindowInteractor::OnButtonUp(wxMouseEvent &event) +{ + //EVT_xxx_DOWN == EVT_xxx_UP - 1 + //This is only needed if two mouse buttons are pressed at the same time. + //In wxWindows 2.4 and later: better use of wxMOUSE_BTN_RIGHT or + //wxEVT_COMMAND_RIGHT_CLICK + if (!Enabled || (ActiveButton != (event.GetEventType()-1))) + { + return; + } + + // See report by Shang Mu / Kerry Loux on wxVTK mailing list + this->SetFocus(); + +#if VTK_MAJOR_VERSION > 4 || (VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 0) + SetEventInformationFlipY(event.GetX(), event.GetY(), + event.ControlDown(), event.ShiftDown(), '\0', 0, NULL); +#endif + + if(ActiveButton == wxEVT_RIGHT_DOWN) + { +#if VTK_MAJOR_VERSION > 4 || (VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 0) + // new style + InvokeEvent(vtkCommand::RightButtonReleaseEvent, NULL); +#else + // old style + InteractorStyle->OnRightButtonUp(event.ControlDown(), event.ShiftDown(), + event.GetX(), Size[1] - event.GetY() - 1); +#endif + } + else if(ActiveButton == wxEVT_LEFT_DOWN) + { +#if VTK_MAJOR_VERSION > 4 || (VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 0) + // new style + InvokeEvent(vtkCommand::LeftButtonReleaseEvent, NULL); +#else + // old style + InteractorStyle->OnLeftButtonUp(event.ControlDown(), event.ShiftDown(), + event.GetX(), Size[1] - event.GetY() - 1); +#endif + } + else if(ActiveButton == wxEVT_MIDDLE_DOWN) + { +#if VTK_MAJOR_VERSION > 4 || (VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 0) + // new style + InvokeEvent(vtkCommand::MiddleButtonReleaseEvent, NULL); +#else + // old style + InteractorStyle->OnMiddleButtonUp(event.ControlDown(), event.ShiftDown(), + event.GetX(), Size[1] - event.GetY() - 1); +#endif + } + //if the ActiveButton is realeased, then release mouse capture + if ((ActiveButton != wxEVT_NULL) && WX_USE_X_CAPTURE && UseCaptureMouse) + { + ReleaseMouse(); + } + ActiveButton = wxEVT_NULL; +} +//--------------------------------------------------------------------------- +void wxVTKRenderWindowInteractor::OnMouseWheel(wxMouseEvent& event) +{ +// Mouse wheel was only added after VTK 4.4 (I think...) +#if VTK_MAJOR_VERSION > 4 || (VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 2) + // new style + //Set vtk event information ... The numebr of wheel rotations is stored in + //the x varible. y varible is zero + SetEventInformationFlipY(event.GetX() , event.GetY(), + event.ControlDown(), event.ShiftDown(), '\0', 0, NULL); + if(event.GetWheelRotation() > 0) + { + //Send event to VTK + InvokeEvent(vtkCommand::MouseWheelForwardEvent, NULL); + } + else + { + //Send event to VTK + InvokeEvent(vtkCommand::MouseWheelBackwardEvent, NULL); + } +#endif + +} + +//--------------------------------------------------------------------------- +#if wxCHECK_VERSION(2, 8, 0) +void wxVTKRenderWindowInteractor::OnMouseCaptureLost(wxMouseCaptureLostEvent& event) +{ + if (ActiveButton != wxEVT_NULL) + { + //Maybe also invoke the button release event here + } + // Reset ActiveButton so that + // 1. we do not process mouse button up events any more, + // 2. the next button down event will be processed and call CaptureMouse(). + // Otherwise ReleaseMouse() will be called + // without a previous CaptureMouse(). + ActiveButton = wxEVT_NULL; +} +#endif + +//--------------------------------------------------------------------------- +void wxVTKRenderWindowInteractor::Render() +{ + RenderAllowed = 1; + if (!RenderWhenDisabled) + { + //the user doesn't want us to render when the toplevel frame + //is disabled - first find the top level parent + wxWindow *topParent = wxGetTopLevelParent(this); + if (topParent) + { + //if it exists, check whether it's enabled + //if it's not enabeld, RenderAllowed will be false + RenderAllowed = topParent->IsEnabled(); + } + } + + if (RenderAllowed) + { + if(Handle && (Handle == GetHandleHack()) ) + { + RenderWindow->Render(); + } +#if VTK_MAJOR_VERSION > 4 || (VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 2) + else if(GetHandleHack()) + { + //this means the user has reparented us; let's adapt to the + //new situation by doing the WindowRemap dance + //store the new situation + Handle = GetHandleHack(); + RenderWindow->SetNextWindowId(reinterpret_cast(Handle)); + RenderWindow->WindowRemap(); + RenderWindow->Render(); + } +#endif + } +} +//--------------------------------------------------------------------------- +void wxVTKRenderWindowInteractor::SetRenderWhenDisabled(int newValue) +{ + //Change value of __RenderWhenDisabled ivar. + //If __RenderWhenDisabled is false (the default), this widget will not + //call Render() on the RenderWindow if the top level frame (i.e. the + //containing frame) has been disabled. + + //This prevents recursive rendering during wxSafeYield() calls. + //wxSafeYield() can be called during the ProgressMethod() callback of + //a VTK object to have progress bars and other GUI elements updated - + //it does this by disabling all windows (disallowing user-input to + //prevent re-entrancy of code) and then handling all outstanding + //GUI events. + + //However, this often triggers an OnPaint() method for wxVTKRWIs, + //resulting in a Render(), resulting in Update() being called whilst + //still in progress. + + RenderWhenDisabled = (bool)newValue; +} +//--------------------------------------------------------------------------- +// +// Set the variable that indicates that we want a stereo capable window +// be created. This method can only be called before a window is realized. +// +void wxVTKRenderWindowInteractor::SetStereo(int capable) +{ + if (Stereo != capable) + { + Stereo = capable; + RenderWindow->StereoCapableWindowOn(); + RenderWindow->SetStereoTypeToCrystalEyes(); + Modified(); + } +} + +//--------------------------------------------------------------------------- +// +// +void wxVTKRenderWindowInteractor::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os, indent); +} diff --git a/gdcm/Utilities/wxWidgets/wxVTKRenderWindowInteractor.h b/gdcm/Utilities/wxWidgets/wxVTKRenderWindowInteractor.h new file mode 100644 index 0000000..ead4444 --- /dev/null +++ b/gdcm/Utilities/wxWidgets/wxVTKRenderWindowInteractor.h @@ -0,0 +1,177 @@ +/*========================================================================= + + Program: Visualization Toolkit + Module: $RCSfile: wxVTKRenderWindowInteractor.h,v $ + Language: C++ + Date: $Date: 2008/08/10 22:58:28 $ + Version: $Revision: 1.21 $ + + Copyright (c) 1993-2002 Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +// .NAME wxVTKRenderWindowInteractor - class to enable VTK to render to +// and interact with wxWindow. +// .SECTION Description +// wxVTKRenderWindowInteractor provide a VTK widget for wxWindow. This class +// was completely rewrote to have the 'Look & Feel' of the python version: +// wxVTKRenderWindowInteractor.py +// .SECTION Caveats +// - There is a know bug that prevent this class to works for more info see +// WX_USE_X_CAPTURE. This bug only affect wxGTK from 2.3.2 to wxGTK 2.4.0. +// - Furthermore this class is tempated over either wxWindows or wxGLCanvas, +// in wxWindows 2.3.1 and earlier, the wxGLCanvas had scroll bars, you can avoid +// this effect by playing with WX_BASE_CLASS at your risk (you might end up with +// lot of flickering.) +// - This class might not be easily readable as it tried to work with VTK 3.2 +// and 4.x. This class doesn't support reparenting with VTK 4.2 and earlier. +// .SECTION see also +// wxVTKRenderWindowInteractor.py wxVTKRenderWindow.py + +#ifndef _wxVTKRenderWindowInteractor_h_ +#define _wxVTKRenderWindowInteractor_h_ + +// For compilers that support precompilation, includes "wx/wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ +# pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include +#endif + +#include +#include + +// vtk includes +#include "vtkRenderWindowInteractor.h" +#include "vtkRenderWindow.h" + +// Apparently since wxGTK 2.8.0 one can finally use wxWindow (just as in any +// other port): +// MM: tested on 2008/04/08: experienced some heavy flickering with wx-widget 2.6.0 +// using a wxWindow instead of wxGLCanvas fixed the symptoms +//#if (!wxCHECK_VERSION(2, 6, 0)) +#if (!wxCHECK_VERSION(2, 8, 0)) +#define USE_WXGLCANVAS +#endif + +#if defined(__WXGTK__) && defined(USE_WXGLCANVAS) +# if wxUSE_GLCANVAS +# include +# else +# error "problem of wxGLCanvas, you need to build wxWidgets with opengl" +# endif //wxUSE_GLCANVAS +#endif //__WXGTK__ + +// Motif version (renamed into wxX11 for wxWindow 2.4 and newer) +#if defined(__WXMOTIF__) +# error This GUI is not supported by wxVTKRenderWindowInteractor for now +#endif + +// wx forward declarations +class wxPaintEvent; +class wxMouseEvent; +class wxTimerEvent; +class wxKeyEvent; +class wxSizeEvent; + +#if defined(__WXGTK__) && defined(USE_WXGLCANVAS) +class wxVTKRenderWindowInteractor : public wxGLCanvas, public vtkRenderWindowInteractor +#else +class wxVTKRenderWindowInteractor : public wxWindow, public vtkRenderWindowInteractor +#endif //__WXGTK__ +{ + DECLARE_DYNAMIC_CLASS(wxVTKRenderWindowInteractor) + + public: + //constructors + wxVTKRenderWindowInteractor(); + + wxVTKRenderWindowInteractor(wxWindow *parent, + wxWindowID id, + const wxPoint &pos = wxDefaultPosition, + const wxSize &size = wxDefaultSize, + long style = wxWANTS_CHARS | wxNO_FULL_REPAINT_ON_RESIZE, + const wxString &name = wxPanelNameStr); + vtkTypeRevisionMacro(wxVTKRenderWindowInteractor,vtkRenderWindowInteractor); + static wxVTKRenderWindowInteractor * New(); + void PrintSelf(ostream& os, vtkIndent indent); + + //destructor + ~wxVTKRenderWindowInteractor(); + + // vtkRenderWindowInteractor overrides + void Initialize(); + void Enable(); + bool Enable(bool enable); + void Disable(); + void Start(); + void UpdateSize(int x, int y); + int CreateTimer(int timertype); + int DestroyTimer(); + void TerminateApp() {}; + + // event handlers + void OnPaint(wxPaintEvent &event); + void OnEraseBackground (wxEraseEvent& event); + void OnMotion(wxMouseEvent &event); + + void OnButtonDown(wxMouseEvent &event); + void OnButtonUp(wxMouseEvent &event); +#if !(VTK_MAJOR_VERSION == 3 && VTK_MINOR_VERSION == 1) + void OnEnter(wxMouseEvent &event); + void OnLeave(wxMouseEvent &event); + void OnMouseWheel(wxMouseEvent& event); +#if wxCHECK_VERSION(2, 8, 0) + void OnMouseCaptureLost(wxMouseCaptureLostEvent& event); +#endif + void OnKeyDown(wxKeyEvent &event); + void OnKeyUp(wxKeyEvent &event); + void OnChar(wxKeyEvent &event); +#endif + void OnTimer(wxTimerEvent &event); + void OnSize(wxSizeEvent &event); + + void Render(); + void SetRenderWhenDisabled(int newValue); + + // Description: + // Prescribe that the window be created in a stereo-capable mode. This + // method must be called before the window is realized. Default if off. + vtkGetMacro(Stereo,int); + vtkBooleanMacro(Stereo,int); + virtual void SetStereo(int capable); + + // Description: + // As CaptureMouse could be a problem sometimes on a window box + // This method allow to set or not the CaptureMouse. + // This method actually will works only if WX_USE_X_CAPTURE was set to 1 + vtkSetMacro(UseCaptureMouse,int); + vtkBooleanMacro(UseCaptureMouse,int); + + protected: + wxTimer timer; + int ActiveButton; + int RenderAllowed; + long GetHandleHack(); + int Stereo; + + private: + long Handle; + bool Created; + int RenderWhenDisabled; + int UseCaptureMouse; + + DECLARE_EVENT_TABLE() +}; + +#endif //_wxVTKRenderWindowInteractor_h_ diff --git a/gdcm/Utilities/wxWidgets/wxgdcm.wxg b/gdcm/Utilities/wxWidgets/wxgdcm.wxg new file mode 100644 index 0000000..97762f1 --- /dev/null +++ b/gdcm/Utilities/wxWidgets/wxgdcm.wxg @@ -0,0 +1,180 @@ + + + + + + + wxGDCM + 1 + 1 + 1 + 725, 565 + + + + + + wxID_OPEN + OpenName + Open DICOM file + OpenEvt + + + + RewriteName + Rewrite DICOM file + RewriteEvt + + + + SaveName + Save DICOM File + SaveEvt + + + + --- + --- + + + + wxID_EXIT + ExitName + Exit app + ExitEvt + + + + + + + + wxID_HELP + AboutName + About Dialog + AboutEvt + + + + + + + frame_1_statusbar + + + + + + + + + 0 + + + + + + + --- + + 0 + --- + + --- + --- + + + + + 0 + + + + + + + --- + + 0 + --- + + --- + --- + + + + + 0 + + + + + + + + + wxHORIZONTAL + + wxEXPAND + 0 + + + wxVERTICAL + + wxEXPAND + 0 + + + + + + + wxEXPAND + 0 + + + + + + + + + wxEXPAND + 0 + + + + + View + DICOM Tags + + + + $parent + $id + + + + 10 + + A + B + C + + wxGrid.wxGridSelectCells + 1 + 1 + 1 + 1 + 1 + 1 + + + + + + + + About Dialog + + diff --git a/gdcm/Wrapping/CMakeLists.txt b/gdcm/Wrapping/CMakeLists.txt new file mode 100644 index 0000000..89e0f3f --- /dev/null +++ b/gdcm/Wrapping/CMakeLists.txt @@ -0,0 +1,20 @@ +# python +if(GDCM_WRAP_PYTHON) + subdirs(Python) +endif() +# java +if(GDCM_WRAP_JAVA) + subdirs(Java) +endif() +# php +if(GDCM_WRAP_PHP) + subdirs(PHP) +endif() +# perl +if(GDCM_WRAP_PERL) + subdirs(Perl) +endif() +# C# +if(GDCM_WRAP_CSHARP) +# subdirs(Csharp) +endif() diff --git a/gdcm/Wrapping/Csharp/AssemblyInfo.cs.in b/gdcm/Wrapping/Csharp/AssemblyInfo.cs.in new file mode 100644 index 0000000..f66c5bc --- /dev/null +++ b/gdcm/Wrapping/Csharp/AssemblyInfo.cs.in @@ -0,0 +1,76 @@ +#region License +/*========================================================================= + + BSD License [http://www.opensource.org/licenses/bsd-license.php] + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither name of Mathieu Malaterre, or CREATIS, nor the names of any + contributors (CNRS, INSERM, UCB, Universite Lyon I), may be used to + endorse or promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=========================================================================*/ +#endregion License + +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following +// attributes. +// +// change them to the information which is associated with the assembly +// you compile. + +[assembly: AssemblyTitle("GDCM Framework Binding For .NET")] +[assembly: AssemblyDescription("GDCM Framework Binding For .NET")] +[assembly: AssemblyConfiguration("Retail")] +[assembly: AssemblyCompany("GDCM -- http://gdcm.sourceforge.net")] +[assembly: AssemblyProduct("gdcm-sharp.dll")] +[assembly: AssemblyDefaultAlias("gdcm-sharp")] +[assembly: AssemblyCopyright("Copyright ©2006-2011 Mathieu Malaterre. All rights reserved.")] +[assembly: AssemblyTrademark("GDCM -- http://gdcm.sourceforge.net")] +[assembly: AssemblyCulture("")] + +// The assembly version has following format : +// +// Major.Minor.Build.Revision +// +// You can specify all values by your own or you can build default build and revision +// numbers with the '*' character (the default): + +[assembly: AssemblyVersion("@GDCM_API_VERSION@")] +[assembly: AssemblyFileVersion("@GDCM_API_VERSION@")] +[assembly: AssemblyInformationalVersion("@GDCM_API_VERSION@")] + +// The following attributes specify the key for the sign of your assembly. See the +// .NET Framework documentation for more information about signing. +// This is not required, if you don't want signing let these attributes like they're. +[assembly: AssemblyDelaySign(false)] +// http://msdn.microsoft.com/en-us/library/6f05ezxy(VS.80).aspx +[assembly: AssemblyKeyFile("key.snk")] +//[assembly: AssemblyKeyFile("")] +//[assembly: AssemblyKeyName("GDCM Key")] +//[assembly: AssemblyKeyName("")] diff --git a/gdcm/Wrapping/Csharp/CMakeLists.txt b/gdcm/Wrapping/Csharp/CMakeLists.txt new file mode 100644 index 0000000..321a1b7 --- /dev/null +++ b/gdcm/Wrapping/Csharp/CMakeLists.txt @@ -0,0 +1,214 @@ +# TODO: +# http://www.disconnectd.com/?p=21 + +# C# Cmd line options: +# http://msdn.microsoft.com/en-us/library/ms379563(VS.80).aspx +# http://msdn.microsoft.com/en-us/library/aa288436(VS.71).aspx +# http://msdn.microsoft.com/en-us/library/aa288481(VS.71).aspx + +find_package(SWIG REQUIRED) +mark_as_advanced(SWIG_DIR SWIG_EXECUTABLE SWIG_VERSION) +include(${SWIG_USE_FILE}) + +include_directories( + "${GDCM_BINARY_DIR}/Source/Common" + "${GDCM_SOURCE_DIR}/Source/Common" + "${GDCM_SOURCE_DIR}/Source/DataStructureAndEncodingDefinition" + "${GDCM_SOURCE_DIR}/Source/InformationObjectDefinition" + "${GDCM_SOURCE_DIR}/Source/MediaStorageAndFileFormat" + "${GDCM_SOURCE_DIR}/Source/DataDictionary" + "${GDCM_SOURCE_DIR}/Source/MessageExchangeDefinition" + #${CMAKE_CURRENT_SOURCE_DIR} +) + +set_source_files_properties(gdcm.i PROPERTIES CPLUSPLUS ON) + +# See sf.net bug #2895067 +set(CMAKE_SWIG_FLAGS "-namespace gdcm -dllimport gdcmsharpglue") +separate_arguments(CMAKE_SWIG_FLAGS) +# libgdksharpglue.so +SWIG_ADD_MODULE(gdcmsharpglue csharp gdcm.i) +SWIG_LINK_LIBRARIES(gdcmsharpglue gdcmMSFF + gdcmMEXD +) +set_target_properties(${SWIG_MODULE_gdcmsharpglue_REAL_NAME} PROPERTIES LINK_INTERFACE_LIBRARIES "") +set_property(TARGET ${SWIG_MODULE_gdcmsharpglue_REAL_NAME} PROPERTY NO_SONAME 1) + +# Module are always place in the library destination but for poor win32 user I +# decided to place them right next to the other dlls +if(NOT GDCM_INSTALL_NO_LIBRARIES) + install(TARGETS ${SWIG_MODULE_gdcmsharpglue_REAL_NAME} + RUNTIME DESTINATION ${GDCM_INSTALL_BIN_DIR} COMPONENT Applications + LIBRARY DESTINATION ${GDCM_INSTALL_LIB_DIR} COMPONENT Libraries + ARCHIVE DESTINATION ${GDCM_INSTALL_LIB_DIR} COMPONENT DebugDevel + ${CPACK_NAMELINK_TYPE} + ) +endif() + + +##if(UNIX) +## find_package(MONO REQUIRED) +#find_package(CSharp REQUIRED) +#include(${CSharp_USE_FILE}) +# +# configure_file( +# ${CMAKE_CURRENT_SOURCE_DIR}/AssemblyInfo.cs.in +# ${CMAKE_CURRENT_BINARY_DIR}/AssemblyInfo.cs +# @ONLY) +## add_custom_command( +## OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/gdcm-sharp.dll +## # $(CSC) /t:library /out:mapscript_csharp.dll *.cs config/AssemblyInfo.cs +## COMMAND ${MCS_EXECUTABLE} ARGS "/t:library" "/out:gdcm-sharp.dll" "*.cs" ${CMAKE_CURRENT_BINARY_DIR}/AssemblyInfo.cs +## WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} +## DEPENDS "${swig_generated_file_fullname}" +## ${CMAKE_CURRENT_BINARY_DIR}/AssemblyInfo.cs +## COMMENT "mcs *.cs" +## ) +# +## building HelloWorld: +##$(CSC) /r:mapscript_csharp.dll /out:shpdump.exe examples/shpdump.cs +## Cannot use glob since files are not generated yet... +##file(GLOB bla "${CMAKE_CURRENT_BINARY_DIR}/*.cs") +#CSHARP_ADD_LIBRARY(gdcm-sharp ${CMAKE_CURRENT_BINARY_DIR}/AssemblyInfo.cs \"*.cs\") +#add_custom_target(CSharp_gdcm_sharp ALL +# DEPENDS ${SWIG_MODULE_gdcmsharpglue_REAL_NAME} +# ) +# +## For some reason csc v1.1.4322 does not like full path, so I need to locally copy it to the binary dir +#if(WIN32) +# configure_file( +# ${CMAKE_CURRENT_SOURCE_DIR}/HelloWorld.cs +# ${CMAKE_CURRENT_BINARY_DIR}/HelloWorld.cs +# ) +#endif() +##CSHARP_ADD_EXECUTABLE(HelloWorld HelloWorld.cs) +##CSHARP_LINK_LIBRARIES(HelloWorld gdcm-sharp) +##add_custom_target(CSHARP_EXECUTABLE_HelloWorld ALL +## DEPENDS +## ${CMAKE_CURRENT_BINARY_DIR}/gdcm-sharp.dll +## # CSharp_gdcm_csharp +## ) +# +# +# +## $ export MONO_LOG_LEVEL="debug"; export MONO_LOG_MASK="dll" +## $ export LD_LIBRARY_PATH=/home/mmalaterre/Projects/gdcm/debug-gcc43/Wrapping/Csharp/:/home/mmalaterre/Projects/gdcm/debug-gcc43/bin +##add_custom_target(GDCMCSharp ALL +## DEPENDS +## ${CMAKE_CURRENT_BINARY_DIR}/gdcm-sharp.dll +## ${CMAKE_CURRENT_BINARY_DIR}/HelloWorld.exe +## COMMENT "building gdcm-sharp.dll" +##) +# +#if(BUILD_TESTING) +# add_test(HelloWorldCSharp ${CMAKE_CSHARP_INTERPRETER} ${CMAKE_CURRENT_BINARY_DIR}/HelloWorld.exe ${GDCM_DATA_ROOT}/test.acr) +#endif() +# +##endif() + +set(OLDSTYLECSHARP 1) + +if(OLDSTYLECSHARP) + configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/AssemblyInfo.cs.in + ${CMAKE_CURRENT_BINARY_DIR}/AssemblyInfo.cs + @ONLY) + configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/key.snk + ${CMAKE_CURRENT_BINARY_DIR}/key.snk + COPYONLY) + +# From Mirco Bauer on debian-cli +# Hm? You wrote the C# binding for gdcm? Using C# in the lib name is +# very wrong in all cases. The CIL bytecode can be used by any language +# that targets the CLI. To give some examples: VB.NET, Boo, Nemerle (yes, +# those are all in debian already :)). +# +# There is a common prefix of nFOO (like nunit or nant) and for +# bindings even more common is the suffix of FOO-sharp (not -csharp) +# like gtk-sharp, gnome-sharp, evolution-sharp. +# +# /usr/lib/mono/gtk-sharp/gtk-sharp.dll +# /usr/lib/mono/gtk-sharp/gdk-sharp.dll +# /usr/lib/mono/gtk-sharp/atk-sharp.dll + + add_custom_command( + #OUTPUT ${GDCM_LIBRARY_DIR}/gdcm-sharp.dll + OUTPUT ${GDCM_LIBRARY_DIR}/gdcm-sharp.dll + COMMAND ${CMAKE_CSHARP_COMPILER} ARGS "/t:library" "/doc:${GDCM_LIBRARY_DIR}/gdcm-sharp.dll.xml" "/out:${GDCM_LIBRARY_DIR}/gdcm-sharp.dll" "*.cs" +#${CMAKE_CURRENT_BINARY_DIR}/AssemblyInfo.cs + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS "${swig_generated_file_fullname}" + ${CMAKE_CURRENT_BINARY_DIR}/AssemblyInfo.cs + COMMENT "csc *.cs" + ) + +if(BUILD_EXAMPLES) +# building HelloCSharpWorld: + add_custom_command( + OUTPUT ${GDCM_EXECUTABLE_DIR}/HelloCsharpWorld.exe + COMMAND ${CMAKE_CSHARP_COMPILER} ARGS "/r:${GDCM_LIBRARY_DIR}/gdcm-sharp.dll" "/out:${GDCM_EXECUTABLE_DIR}/HelloCsharpWorld.exe" ${CMAKE_CURRENT_SOURCE_DIR}/HelloCsharpWorld.cs + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + DEPENDS ${GDCM_LIBRARY_DIR}/gdcm-sharp.dll + ${CMAKE_CURRENT_SOURCE_DIR}/HelloCsharpWorld.cs + COMMENT "Create HelloCsharpWorld.exe" + ) +endif() + +# This config file is only a mono thingy anyway +# add_custom_command( +# OUTPUT ${GDCM_LIBRARY_DIR}/gdcm-sharp.dll.config +# COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/gdcm-sharp.dll.config ${GDCM_LIBRARY_DIR} +# DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/gdcm-sharp.dll.config +# COMMENT "Copying gdcm-sharp.dll.config" +# ) + + +#if(WIN32) +# configure_file( +# ${CMAKE_CURRENT_SOURCE_DIR}/HelloWorld.cs +# ${CMAKE_CURRENT_BINARY_DIR}/HelloWorld.cs +# ) +#endif() + +# $ export MONO_LOG_LEVEL="debug"; export MONO_LOG_MASK="dll" +# $ export LD_LIBRARY_PATH=/home/mmalaterre/Projects/gdcm/debug-gcc43/Wrapping/Csharp/:/home/mmalaterre/Projects/gdcm/debug-gcc43/bin +add_custom_target(GDCMCSharp ALL + DEPENDS + ${GDCM_LIBRARY_DIR}/gdcm-sharp.dll + #${GDCM_LIBRARY_DIR}/gdcm-sharp.dll.config + COMMENT "building gdcm-sharp.dll" +) + +if(BUILD_EXAMPLES) +add_custom_target(GDCMCSharpExample ALL + DEPENDS + ${GDCM_EXECUTABLE_DIR}/HelloCsharpWorld.exe + COMMENT "building HelloCsharpWorld.exe" +) +#add_dependencies(GDCMCSharpExample +# GDCMCSharp) + +endif() + + + +else() +endif() + +# Cannot do test here as CTest has not yet been included. Simply construct example and hope someone else +# will call the test for us... +#if(BUILD_TESTING) +# add_test(HelloWorldCSharp ${CMAKE_CSHARP_INTERPRETER} ${GDCM_EXECUTABLE_DIR}/HelloWorld.exe ${GDCM_DATA_ROOT}/012345.002.050.dcm) +#endif() + +if(NOT GDCM_INSTALL_NO_LIBRARIES) + install_swig_module(gdcmsharpglue CSharp) + set(GDCM_LIBRARY_DIR2 ${LIBRARY_OUTPUT_PATH}/\${BUILD_TYPE}) + # because gdcm-sharp.dll is constructed with custom commands, it need the + # install(FILES signature: + install(FILES + ${GDCM_LIBRARY_DIR2}/gdcm-sharp.dll + DESTINATION ${GDCM_INSTALL_CSHARPMODULE_DIR} COMPONENT CSharpModule + ) +endif() diff --git a/gdcm/Wrapping/Csharp/HelloCsharpWorld.cs b/gdcm/Wrapping/Csharp/HelloCsharpWorld.cs new file mode 100644 index 0000000..aa8327b --- /dev/null +++ b/gdcm/Wrapping/Csharp/HelloCsharpWorld.cs @@ -0,0 +1,57 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +using System; +using gdcm; + +public class HelloWorld +{ + public static int Main(string[] args) + { + System.Console.WriteLine("Hello World !"); + //gdcm.Reader reader2; + string filename = args[0]; + System.Console.WriteLine( "Reading: " + filename ); + Reader reader = new Reader(); + reader.SetFileName( filename ); + bool ret = reader.Read(); + if( !ret ) + { + //throw new Exception("Could not read: " + filename ); + return 1; + } + //std::cout << reader.GetFile() + Tag t = new Tag(0x10,0x10); + System.Console.WriteLine( "out:" + t.toString() ); + System.Console.WriteLine( "out:" + reader.GetFile().GetDataSet().toString() ); + + Anonymizer ano = new Anonymizer(); + ano.SetFile( reader.GetFile() ); + ano.RemovePrivateTags(); + ano.RemoveGroupLength(); + ano.Replace( t, "GDCM^Csharp^Test^Hello^World" ); + + Writer writer = new Writer(); + writer.SetFileName( "testcs.dcm" ); + writer.SetFile( ano.GetFile() ); + ret = writer.Write(); + if( !ret ) + { + //throw new Exception("Could not read: " + filename ); + return 1; + } + + return 0; + } +} diff --git a/gdcm/Wrapping/Csharp/Notes.txt b/gdcm/Wrapping/Csharp/Notes.txt new file mode 100644 index 0000000..825adfb --- /dev/null +++ b/gdcm/Wrapping/Csharp/Notes.txt @@ -0,0 +1,9 @@ +http://pragmatic.oreilly.com/pub/a/oreilly/dotnet/news/programmingCsharp_0801.html + +http://msdn.microsoft.com/en-us/library/yyaad03b(VS.80).aspx + +http://msdn.microsoft.com/en-us/magazine/cc301520.aspx + +http://cplus.about.com/ + +http://andymcm.com/csharpfaq.htm diff --git a/gdcm/Wrapping/Csharp/docstrings.i b/gdcm/Wrapping/Csharp/docstrings.i new file mode 100644 index 0000000..f67a682 --- /dev/null +++ b/gdcm/Wrapping/Csharp/docstrings.i @@ -0,0 +1,10007 @@ + +// File: index.xml + +// File: classgdcm_1_1AES.xml +%typemap("csclassmodifiers") gdcm::AES " /**C++ includes: gdcmAES.h */ +public class"; + +%csmethodmodifiers gdcm::AES::AES " /** gdcm::AES::AES() */ public"; + +%csmethodmodifiers gdcm::AES::CryptCbc " /** bool +gdcm::AES::CryptCbc(int mode, unsigned int length, char iv[16], const +char *input, char *output) const + +AES-CBC buffer encryption/decryption. + +Parameters: +----------- + +mode: ENCRYPT or DECRYPT + +length: length of the input data + +iv: initialization vector (updated after use) + +input: buffer holding the input data + +output: buffer holding the output data + +false on error (invalid key, or length not multiple 16) + +*/ public"; + +%csmethodmodifiers gdcm::AES::CryptCfb128 " /** bool +gdcm::AES::CryptCfb128(int mode, unsigned int length, unsigned int +&iv_off, char iv[16], const char *input, char *output) const + +AES-CFB128 buffer encryption/decryption. + +Parameters: +----------- + +mode: ENCRYPT or DECRYPT + +length: length of the input data + +iv_off: offset in IV (updated after use) + +iv: initialization vector (updated after use) + +input: buffer holding the input data + +output: buffer holding the output data + +false on error (invalid key) + +*/ public"; + +%csmethodmodifiers gdcm::AES::CryptEcb " /** bool +gdcm::AES::CryptEcb(int mode, const char input[16], char output[16]) +const + +AES-ECB block encryption/decryption. + +Parameters: +----------- + +mode: ENCRYPT or DECRYPT + +input: 16-byte input block + +output: 16-byte output block + +false on error (invalid key) + +*/ public"; + +%csmethodmodifiers gdcm::AES::SetkeyDec " /** bool +gdcm::AES::SetkeyDec(const char *key, unsigned int keysize) + +AES key schedule (decryption). + +Parameters: +----------- + +key: decryption key + +keysize: must be 16, 24 or 32 + +false on error (wrong keysize, key null) + +*/ public"; + +%csmethodmodifiers gdcm::AES::SetkeyEnc " /** bool +gdcm::AES::SetkeyEnc(const char *key, unsigned int keysize) + +AES key schedule (encryption). + +Parameters: +----------- + +key: encryption key + +keysize: must be 16, 24 or 32 + +false on error (wrong keysize, key null) + +*/ public"; + +%csmethodmodifiers gdcm::AES::~AES " /** gdcm::AES::~AES() */ +public"; + + +// File: classstd_1_1allocator.xml +%typemap("csclassmodifiers") std::allocator " /** STL class. + +*/ public class"; + + +// File: classgdcm_1_1Anonymizer.xml +%typemap("csclassmodifiers") gdcm::Anonymizer " /**C++ includes: +gdcmAnonymizer.h */ public class"; + +%csmethodmodifiers gdcm::Anonymizer::Anonymizer " /** +gdcm::Anonymizer::Anonymizer() */ public"; + +%csmethodmodifiers +gdcm::Anonymizer::BasicApplicationLevelConfidentialityProfile " /** +bool +gdcm::Anonymizer::BasicApplicationLevelConfidentialityProfile(bool +deidentify=true) + +PS 3.15 / E.1.1 De-Identifier An Application may claim conformance to +the Basic Application Level Confidentiality Profile as a deidentifier +if it protects all Attributes that might be used by unauthorized +entities to identify the patient. NOT THREAD SAFE + +*/ public"; + +%csmethodmodifiers gdcm::Anonymizer::Empty " /** bool +gdcm::Anonymizer::Empty(Tag const &t) + +Make Tag t empty (if not found tag will be created) Warning: does not +handle SQ element + +*/ public"; + +%csmethodmodifiers gdcm::Anonymizer::GetFile " /** File& +gdcm::Anonymizer::GetFile() */ public"; + +%csmethodmodifiers gdcm::Anonymizer::GetX509 " /** const X509* +gdcm::Anonymizer::GetX509() const */ public"; + +%csmethodmodifiers gdcm::Anonymizer::Remove " /** bool +gdcm::Anonymizer::Remove(Tag const &t) + +remove a tag (even a SQ can be removed) + +*/ public"; + +%csmethodmodifiers gdcm::Anonymizer::RemoveGroupLength " /** bool +gdcm::Anonymizer::RemoveGroupLength() + +Main function that loop over all elements and remove group length. + +*/ public"; + +%csmethodmodifiers gdcm::Anonymizer::RemovePrivateTags " /** bool +gdcm::Anonymizer::RemovePrivateTags() + +Main function that loop over all elements and remove private tags. + +*/ public"; + +%csmethodmodifiers gdcm::Anonymizer::RemoveRetired " /** bool +gdcm::Anonymizer::RemoveRetired() + +Main function that loop over all elements and remove retired element. + +*/ public"; + +%csmethodmodifiers gdcm::Anonymizer::Replace " /** bool +gdcm::Anonymizer::Replace(Tag const &t, const char *value, VL const +&vl) + +when the value contains , it is a good idea to specify the length. +This function is required when dealing with VRBINARY tag + +*/ public"; + +%csmethodmodifiers gdcm::Anonymizer::Replace " /** bool +gdcm::Anonymizer::Replace(Tag const &t, const char *value) + +Replace tag with another value, if tag is not found it will be +created: WARNING: this function can only execute if tag is a VRASCII + +*/ public"; + +%csmethodmodifiers gdcm::Anonymizer::SetFile " /** void +gdcm::Anonymizer::SetFile(const File &f) + +Set/Get File. + +*/ public"; + +%csmethodmodifiers gdcm::Anonymizer::SetX509 " /** void +gdcm::Anonymizer::SetX509(X509 *x509) + +Set/Get AES key that will be used to encrypt the dataset within +BasicApplicationLevelConfidentialityProfile Warning: set is done by +copy (not reference) + +*/ public"; + +%csmethodmodifiers gdcm::Anonymizer::~Anonymizer " /** +gdcm::Anonymizer::~Anonymizer() */ public"; + + +// File: classgdcm_1_1ApplicationEntity.xml +%typemap("csclassmodifiers") gdcm::ApplicationEntity " /** +ApplicationEntity AE Application Entity + +A string of characters that identifies an Application Entity with +leading and trailing spaces (20H) being non-significant. A value +consisting solely of spaces shall not be used. + +Default Character Repertoire excluding character code 5CH (the +BACKSLASH \\\\ in ISO-IR 6), and control characters LF, FF, CR and +ESC. + +16 bytes maximum. + +C++ includes: gdcmApplicationEntity.h */ public class"; + +%csmethodmodifiers gdcm::ApplicationEntity::IsValid " /** bool +gdcm::ApplicationEntity::IsValid() const */ public"; + +%csmethodmodifiers gdcm::ApplicationEntity::Print " /** void +gdcm::ApplicationEntity::Print(std::ostream &os) const */ public"; + +%csmethodmodifiers gdcm::ApplicationEntity::SetBlob " /** void +gdcm::ApplicationEntity::SetBlob(const std::vector< char > &v) */ +public"; + +%csmethodmodifiers gdcm::ApplicationEntity::Squeeze " /** void +gdcm::ApplicationEntity::Squeeze() */ public"; + + +// File: classgdcm_1_1ASN1.xml +%typemap("csclassmodifiers") gdcm::ASN1 " /**C++ includes: gdcmASN1.h +*/ public class"; + +%csmethodmodifiers gdcm::ASN1::ASN1 " /** gdcm::ASN1::ASN1() */ +public"; + +%csmethodmodifiers gdcm::ASN1::TestPBKDF2 " /** int +gdcm::ASN1::TestPBKDF2() */ public"; + +%csmethodmodifiers gdcm::ASN1::~ASN1 " /** gdcm::ASN1::~ASN1() */ +public"; + + +// File: classgdcm_1_1Attribute.xml +%typemap("csclassmodifiers") gdcm::Attribute " /** Attribute class +This class use template metaprograming tricks to let the user know +when the template instanciation does not match the public dictionary. + +Typical example that compile is: Attribute<0x0008,0x9007> a = +{\"ORIGINAL\",\"PRIMARY\",\"T1\",\"NONE\"}; + +Examples that will NOT compile are: + +Attribute<0x0018,0x1182, VR::IS, VM::VM1> fd1 = {}; // not enough +parameters Attribute<0x0018,0x1182, VR::IS, VM::VM2> fd2 = {0,1,2}; // +too many initializers Attribute<0x0018,0x1182, VR::IS, VM::VM3> fd3 = +{0,1,2}; // VM3 is not valid Attribute<0x0018,0x1182, VR::UL, VM::VM2> +fd3 = {0,1}; // UL is not valid VR + +C++ includes: gdcmAttribute.h */ public class"; + +%csmethodmodifiers gdcm::Attribute::GDCM_STATIC_ASSERT " /** +gdcm::Attribute< Group, Element, TVR, TVM +>::GDCM_STATIC_ASSERT(((((VR::VRType) TVR &VR::VR_VM1)&&((VM::VMType) +TVM==VM::VM1))||!((VR::VRType) TVR &VR::VR_VM1))) */ public"; + +%csmethodmodifiers gdcm::Attribute::GDCM_STATIC_ASSERT " /** +gdcm::Attribute< Group, Element, TVR, TVM +>::GDCM_STATIC_ASSERT(((VM::VMType) TVM &(VM::VMType)(TagToType< +Group, Element >::VMType))) */ public"; + +%csmethodmodifiers gdcm::Attribute::GDCM_STATIC_ASSERT " /** +gdcm::Attribute< Group, Element, TVR, TVM +>::GDCM_STATIC_ASSERT(((VR::VRType) TVR &(VR::VRType)(TagToType< +Group, Element >::VRType))) */ public"; + +%csmethodmodifiers gdcm::Attribute::GetAsDataElement " /** +DataElement gdcm::Attribute< Group, Element, TVR, TVM +>::GetAsDataElement() const */ public"; + +%csmethodmodifiers gdcm::Attribute::GetNumberOfValues " /** unsigned +int gdcm::Attribute< Group, Element, TVR, TVM >::GetNumberOfValues() +const */ public"; + +%csmethodmodifiers gdcm::Attribute::GetValue " /** ArrayType const& +gdcm::Attribute< Group, Element, TVR, TVM >::GetValue(unsigned int +idx=0) const */ public"; + +%csmethodmodifiers gdcm::Attribute::GetValue " /** ArrayType& +gdcm::Attribute< Group, Element, TVR, TVM >::GetValue(unsigned int +idx=0) */ public"; + +%csmethodmodifiers gdcm::Attribute::GetValues " /** const ArrayType* +gdcm::Attribute< Group, Element, TVR, TVM >::GetValues() const */ +public"; + +%csmethodmodifiers gdcm::Attribute::Print " /** void gdcm::Attribute< +Group, Element, TVR, TVM >::Print(std::ostream &os) const */ public"; + +%csmethodmodifiers gdcm::Attribute::Set " /** void gdcm::Attribute< +Group, Element, TVR, TVM >::Set(DataSet const &ds) */ public"; + +%csmethodmodifiers gdcm::Attribute::SetFromDataElement " /** void +gdcm::Attribute< Group, Element, TVR, TVM +>::SetFromDataElement(DataElement const &de) */ public"; + +%csmethodmodifiers gdcm::Attribute::SetValue " /** void +gdcm::Attribute< Group, Element, TVR, TVM >::SetValue(ArrayType v, +unsigned int idx=0) */ public"; + +%csmethodmodifiers gdcm::Attribute::SetValues " /** void +gdcm::Attribute< Group, Element, TVR, TVM >::SetValues(const ArrayType +*array, unsigned int numel=VMType) */ public"; + + +// File: classgdcm_1_1Attribute_3_01Group_00_01Element_00_01TVR_00_01VM_1_1VM1__n_01_4.xml +%typemap("csclassmodifiers") gdcm::Attribute< Group, Element, TVR, +VM::VM1_n > " /**C++ includes: gdcmAttribute.h */ public class"; + +%csmethodmodifiers gdcm::Attribute< Group, Element, TVR, VM::VM1_n +>::Attribute " /** gdcm::Attribute< Group, Element, TVR, VM::VM1_n +>::Attribute() */ public"; + +%csmethodmodifiers gdcm::Attribute< Group, Element, TVR, VM::VM1_n +>::GDCM_STATIC_ASSERT " /** gdcm::Attribute< Group, Element, TVR, +VM::VM1_n >::GDCM_STATIC_ASSERT(((((VR::VRType) TVR +&VR::VR_VM1)&&((VM::VMType) TagToType< Group, Element +>::VMType==VM::VM1))||!((VR::VRType) TVR &VR::VR_VM1))) */ public"; + +%csmethodmodifiers gdcm::Attribute< Group, Element, TVR, VM::VM1_n +>::GDCM_STATIC_ASSERT " /** gdcm::Attribute< Group, Element, TVR, +VM::VM1_n >::GDCM_STATIC_ASSERT((VM::VM1_n &(VM::VMType)(TagToType< +Group, Element >::VMType))) */ public"; + +%csmethodmodifiers gdcm::Attribute< Group, Element, TVR, VM::VM1_n +>::GDCM_STATIC_ASSERT " /** gdcm::Attribute< Group, Element, TVR, +VM::VM1_n >::GDCM_STATIC_ASSERT(((VR::VRType) TVR +&(VR::VRType)(TagToType< Group, Element >::VRType))) */ public"; + +%csmethodmodifiers gdcm::Attribute< Group, Element, TVR, VM::VM1_n +>::GetAsDataElement " /** DataElement gdcm::Attribute< Group, Element, +TVR, VM::VM1_n >::GetAsDataElement() const */ public"; + +%csmethodmodifiers gdcm::Attribute< Group, Element, TVR, VM::VM1_n +>::GetNumberOfValues " /** unsigned int gdcm::Attribute< Group, +Element, TVR, VM::VM1_n >::GetNumberOfValues() const */ public"; + +%csmethodmodifiers gdcm::Attribute< Group, Element, TVR, VM::VM1_n +>::GetValue " /** ArrayType const& gdcm::Attribute< Group, Element, +TVR, VM::VM1_n >::GetValue(unsigned int idx=0) const */ public"; + +%csmethodmodifiers gdcm::Attribute< Group, Element, TVR, VM::VM1_n +>::GetValue " /** ArrayType& gdcm::Attribute< Group, Element, TVR, +VM::VM1_n >::GetValue(unsigned int idx=0) */ public"; + +%csmethodmodifiers gdcm::Attribute< Group, Element, TVR, VM::VM1_n +>::GetValues " /** const ArrayType* gdcm::Attribute< Group, Element, +TVR, VM::VM1_n >::GetValues() const */ public"; + +%csmethodmodifiers gdcm::Attribute< Group, Element, TVR, VM::VM1_n +>::Print " /** void gdcm::Attribute< Group, Element, TVR, VM::VM1_n +>::Print(std::ostream &os) const */ public"; + +%csmethodmodifiers gdcm::Attribute< Group, Element, TVR, VM::VM1_n +>::SetFromDataElement " /** void gdcm::Attribute< Group, Element, TVR, +VM::VM1_n >::SetFromDataElement(DataElement const &de) */ public"; + +%csmethodmodifiers gdcm::Attribute< Group, Element, TVR, VM::VM1_n +>::SetNumberOfValues " /** void gdcm::Attribute< Group, Element, TVR, +VM::VM1_n >::SetNumberOfValues(unsigned int numel) */ public"; + +%csmethodmodifiers gdcm::Attribute< Group, Element, TVR, VM::VM1_n +>::SetValue " /** void gdcm::Attribute< Group, Element, TVR, VM::VM1_n +>::SetValue(ArrayType v) */ public"; + +%csmethodmodifiers gdcm::Attribute< Group, Element, TVR, VM::VM1_n +>::SetValue " /** void gdcm::Attribute< Group, Element, TVR, VM::VM1_n +>::SetValue(unsigned int idx, ArrayType v) */ public"; + +%csmethodmodifiers gdcm::Attribute< Group, Element, TVR, VM::VM1_n +>::SetValues " /** void gdcm::Attribute< Group, Element, TVR, +VM::VM1_n >::SetValues(const ArrayType *array, unsigned int numel, +bool own=false) */ public"; + +%csmethodmodifiers gdcm::Attribute< Group, Element, TVR, VM::VM1_n +>::~Attribute " /** gdcm::Attribute< Group, Element, TVR, VM::VM1_n +>::~Attribute() */ public"; + + +// File: classgdcm_1_1Attribute_3_01Group_00_01Element_00_01TVR_00_01VM_1_1VM2__2n_01_4.xml +%typemap("csclassmodifiers") gdcm::Attribute< Group, Element, TVR, +VM::VM2_2n > " /**C++ includes: gdcmAttribute.h */ public class"; + + +// File: classgdcm_1_1Attribute_3_01Group_00_01Element_00_01TVR_00_01VM_1_1VM2__n_01_4.xml +%typemap("csclassmodifiers") gdcm::Attribute< Group, Element, TVR, +VM::VM2_n > " /**C++ includes: gdcmAttribute.h */ public class"; + +%csmethodmodifiers gdcm::Attribute< Group, Element, TVR, VM::VM2_n +>::GetVM " /** VM gdcm::Attribute< Group, Element, TVR, VM::VM2_n +>::GetVM() const */ public"; + + +// File: classgdcm_1_1Attribute_3_01Group_00_01Element_00_01TVR_00_01VM_1_1VM3__3n_01_4.xml +%typemap("csclassmodifiers") gdcm::Attribute< Group, Element, TVR, +VM::VM3_3n > " /**C++ includes: gdcmAttribute.h */ public class"; + + +// File: classgdcm_1_1Attribute_3_01Group_00_01Element_00_01TVR_00_01VM_1_1VM3__n_01_4.xml +%typemap("csclassmodifiers") gdcm::Attribute< Group, Element, TVR, +VM::VM3_n > " /**C++ includes: gdcmAttribute.h */ public class"; + + +// File: classgdcm_1_1AudioCodec.xml +%typemap("csclassmodifiers") gdcm::AudioCodec " /** AudioCodec. + +C++ includes: gdcmAudioCodec.h */ public class"; + +%csmethodmodifiers gdcm::AudioCodec::AudioCodec " /** +gdcm::AudioCodec::AudioCodec() */ public"; + +%csmethodmodifiers gdcm::AudioCodec::CanCode " /** bool +gdcm::AudioCodec::CanCode(TransferSyntax const &) const + +Return whether this coder support this transfer syntax (can code it). + +*/ public"; + +%csmethodmodifiers gdcm::AudioCodec::CanDecode " /** bool +gdcm::AudioCodec::CanDecode(TransferSyntax const &) const + +Return whether this decoder support this transfer syntax (can decode +it). + +*/ public"; + +%csmethodmodifiers gdcm::AudioCodec::Decode " /** bool +gdcm::AudioCodec::Decode(DataElement const &is, DataElement &os) + +Decode. + +*/ public"; + +%csmethodmodifiers gdcm::AudioCodec::~AudioCodec " /** +gdcm::AudioCodec::~AudioCodec() */ public"; + + +// File: classstd_1_1auto__ptr.xml +%typemap("csclassmodifiers") std::auto_ptr " /** STL class. + +*/ public class"; + + +// File: classstd_1_1bad__alloc.xml +%typemap("csclassmodifiers") std::bad_alloc " /** STL class. + +*/ public class"; + + +// File: classstd_1_1bad__cast.xml +%typemap("csclassmodifiers") std::bad_cast " /** STL class. + +*/ public class"; + + +// File: classstd_1_1bad__exception.xml +%typemap("csclassmodifiers") std::bad_exception " /** STL class. + +*/ public class"; + + +// File: classstd_1_1bad__typeid.xml +%typemap("csclassmodifiers") std::bad_typeid " /** STL class. + +*/ public class"; + + +// File: classgdcm_1_1Base64.xml +%typemap("csclassmodifiers") gdcm::Base64 " /**C++ includes: +gdcmBase64.h */ public class"; + +%csmethodmodifiers gdcm::Base64::Base64 " /** gdcm::Base64::Base64() +*/ public"; + +%csmethodmodifiers gdcm::Base64::~Base64 " /** +gdcm::Base64::~Base64() */ public"; + + +// File: classstd_1_1basic__fstream.xml +%typemap("csclassmodifiers") std::basic_fstream " /** STL class. + +*/ public class"; + + +// File: classstd_1_1basic__ifstream.xml +%typemap("csclassmodifiers") std::basic_ifstream " /** STL class. + +*/ public class"; + + +// File: classstd_1_1basic__ios.xml +%typemap("csclassmodifiers") std::basic_ios " /** STL class. + +*/ public class"; + + +// File: classstd_1_1basic__iostream.xml +%typemap("csclassmodifiers") std::basic_iostream " /** STL class. + +*/ public class"; + + +// File: classstd_1_1basic__istream.xml +%typemap("csclassmodifiers") std::basic_istream " /** STL class. + +*/ public class"; + + +// File: classstd_1_1basic__istringstream.xml +%typemap("csclassmodifiers") std::basic_istringstream " /** STL class. + +*/ public class"; + + +// File: classstd_1_1basic__ofstream.xml +%typemap("csclassmodifiers") std::basic_ofstream " /** STL class. + +*/ public class"; + + +// File: classstd_1_1basic__ostream.xml +%typemap("csclassmodifiers") std::basic_ostream " /** STL class. + +*/ public class"; + + +// File: classstd_1_1basic__ostringstream.xml +%typemap("csclassmodifiers") std::basic_ostringstream " /** STL class. + +*/ public class"; + + +// File: classstd_1_1basic__string.xml +%typemap("csclassmodifiers") std::basic_string " /** STL class. + +*/ public class"; + + +// File: classstd_1_1basic__string_1_1const__iterator.xml +%typemap("csclassmodifiers") std::basic_string::const_iterator " /** +STL iterator class. + +*/ public class"; + + +// File: classstd_1_1basic__string_1_1const__reverse__iterator.xml +%typemap("csclassmodifiers") std::basic_string::const_reverse_iterator +" /** STL iterator class. + +*/ public class"; + + +// File: classstd_1_1basic__string_1_1iterator.xml +%typemap("csclassmodifiers") std::basic_string::iterator " /** STL +iterator class. + +*/ public class"; + + +// File: classstd_1_1basic__string_1_1reverse__iterator.xml +%typemap("csclassmodifiers") std::basic_string::reverse_iterator " /** +STL iterator class. + +*/ public class"; + + +// File: classstd_1_1basic__stringstream.xml +%typemap("csclassmodifiers") std::basic_stringstream " /** STL class. + +*/ public class"; + + +// File: classzlib__stream_1_1basic__unzip__streambuf.xml +%typemap("csclassmodifiers") zlib_stream::basic_unzip_streambuf " /** +A stream decorator that takes compressed input and unzips it to a +istream. + +The class wraps up the deflate method of the zlib library +1.1.4http://www.gzip.org/zlib/ + +C++ includes: zipstreamimpl.h */ public class"; + +%csmethodmodifiers +zlib_stream::basic_unzip_streambuf::basic_unzip_streambuf " /** +zlib_stream::basic_unzip_streambuf< charT, traits +>::basic_unzip_streambuf(istream_reference istream, int window_size, +size_t read_buffer_size, size_t input_buffer_size) + +Construct a unzip stream More info on the following parameters can be +found in the zlib documentation. + +*/ public"; + +%csmethodmodifiers zlib_stream::basic_unzip_streambuf::get_crc " /** +unsigned long zlib_stream::basic_unzip_streambuf< charT, traits +>::get_crc(void) const */ public"; + +%csmethodmodifiers zlib_stream::basic_unzip_streambuf::get_in_size " +/** long zlib_stream::basic_unzip_streambuf< charT, traits +>::get_in_size(void) const */ public"; + +%csmethodmodifiers zlib_stream::basic_unzip_streambuf::get_istream " +/** istream_reference zlib_stream::basic_unzip_streambuf< charT, +traits >::get_istream(void) + +returns the compressed input istream + +*/ public"; + +%csmethodmodifiers zlib_stream::basic_unzip_streambuf::get_out_size " +/** long zlib_stream::basic_unzip_streambuf< charT, traits +>::get_out_size(void) const */ public"; + +%csmethodmodifiers zlib_stream::basic_unzip_streambuf::get_zerr " /** +int zlib_stream::basic_unzip_streambuf< charT, traits +>::get_zerr(void) const */ public"; + +%csmethodmodifiers zlib_stream::basic_unzip_streambuf::get_zip_stream +" /** z_stream& zlib_stream::basic_unzip_streambuf< charT, traits +>::get_zip_stream(void) */ public"; + +%csmethodmodifiers zlib_stream::basic_unzip_streambuf::underflow " +/** int_type zlib_stream::basic_unzip_streambuf< charT, traits +>::underflow(void) */ public"; + +%csmethodmodifiers +zlib_stream::basic_unzip_streambuf::~basic_unzip_streambuf " /** +zlib_stream::basic_unzip_streambuf< charT, traits +>::~basic_unzip_streambuf(void) */ public"; + + +// File: classzlib__stream_1_1basic__zip__istream.xml +%typemap("csclassmodifiers") zlib_stream::basic_zip_istream " /**C++ +includes: zipstreamimpl.h */ public class"; + +%csmethodmodifiers zlib_stream::basic_zip_istream::basic_zip_istream +" /** zlib_stream::basic_zip_istream< charT, traits +>::basic_zip_istream(istream_reference istream, int window_size=-15, +size_t read_buffer_size=zstream_default_buffer_size, size_t +input_buffer_size=zstream_default_buffer_size) */ public"; + +%csmethodmodifiers zlib_stream::basic_zip_istream::check_crc " /** +bool zlib_stream::basic_zip_istream< charT, traits >::check_crc(void) +*/ public"; + +%csmethodmodifiers zlib_stream::basic_zip_istream::check_data_size " +/** bool zlib_stream::basic_zip_istream< charT, traits +>::check_data_size(void) const */ public"; + +%csmethodmodifiers zlib_stream::basic_zip_istream::get_gzip_crc " /** +long zlib_stream::basic_zip_istream< charT, traits +>::get_gzip_crc(void) const */ public"; + +%csmethodmodifiers zlib_stream::basic_zip_istream::get_gzip_data_size +" /** long zlib_stream::basic_zip_istream< charT, traits +>::get_gzip_data_size(void) const */ public"; + +%csmethodmodifiers zlib_stream::basic_zip_istream::is_gzip " /** bool +zlib_stream::basic_zip_istream< charT, traits >::is_gzip(void) const +*/ public"; + + +// File: classzlib__stream_1_1basic__zip__ostream.xml +%typemap("csclassmodifiers") zlib_stream::basic_zip_ostream " /**C++ +includes: zipstreamimpl.h */ public class"; + +%csmethodmodifiers zlib_stream::basic_zip_ostream::basic_zip_ostream +" /** zlib_stream::basic_zip_ostream< charT, traits +>::basic_zip_ostream(ostream_reference ostream, bool is_gzip=false, +int level=Z_DEFAULT_COMPRESSION, EStrategy strategy=DefaultStrategy, +int window_size=-15, int memory_level=8, size_t +buffer_size=zstream_default_buffer_size) */ public"; + +%csmethodmodifiers zlib_stream::basic_zip_ostream::finished " /** +void zlib_stream::basic_zip_ostream< charT, traits >::finished(void) +*/ public"; + +%csmethodmodifiers zlib_stream::basic_zip_ostream::is_gzip " /** bool +zlib_stream::basic_zip_ostream< charT, traits >::is_gzip(void) const +*/ public"; + +%csmethodmodifiers zlib_stream::basic_zip_ostream::zflush " /** +basic_zip_ostream& zlib_stream::basic_zip_ostream< +charT, traits >::zflush(void) */ public"; + +%csmethodmodifiers zlib_stream::basic_zip_ostream::~basic_zip_ostream +" /** zlib_stream::basic_zip_ostream< charT, traits +>::~basic_zip_ostream(void) */ public"; + + +// File: classzlib__stream_1_1basic__zip__streambuf.xml +%typemap("csclassmodifiers") zlib_stream::basic_zip_streambuf " /** A +stream decorator that takes raw input and zips it to a ostream. + +The class wraps up the inflate method of the zlib library +1.1.4http://www.gzip.org/zlib/ + +C++ includes: zipstreamimpl.h */ public class"; + +%csmethodmodifiers +zlib_stream::basic_zip_streambuf::basic_zip_streambuf " /** +zlib_stream::basic_zip_streambuf< charT, traits +>::basic_zip_streambuf(ostream_reference ostream, int level, EStrategy +strategy, int window_size, int memory_level, size_t buffer_size) */ +public"; + +%csmethodmodifiers zlib_stream::basic_zip_streambuf::flush " /** +std::streamsize zlib_stream::basic_zip_streambuf< charT, traits +>::flush(void) */ public"; + +%csmethodmodifiers zlib_stream::basic_zip_streambuf::get_crc " /** +unsigned long zlib_stream::basic_zip_streambuf< charT, traits +>::get_crc(void) const */ public"; + +%csmethodmodifiers zlib_stream::basic_zip_streambuf::get_in_size " +/** unsigned long zlib_stream::basic_zip_streambuf< charT, traits +>::get_in_size(void) const */ public"; + +%csmethodmodifiers zlib_stream::basic_zip_streambuf::get_ostream " +/** ostream_reference zlib_stream::basic_zip_streambuf< charT, traits +>::get_ostream(void) const */ public"; + +%csmethodmodifiers zlib_stream::basic_zip_streambuf::get_out_size " +/** long zlib_stream::basic_zip_streambuf< charT, traits +>::get_out_size(void) const */ public"; + +%csmethodmodifiers zlib_stream::basic_zip_streambuf::get_zerr " /** +int zlib_stream::basic_zip_streambuf< charT, traits >::get_zerr(void) +const */ public"; + +%csmethodmodifiers zlib_stream::basic_zip_streambuf::overflow " /** +int_type zlib_stream::basic_zip_streambuf< charT, traits +>::overflow(int_type c) */ public"; + +%csmethodmodifiers zlib_stream::basic_zip_streambuf::sync " /** int +zlib_stream::basic_zip_streambuf< charT, traits >::sync(void) */ +public"; + +%csmethodmodifiers +zlib_stream::basic_zip_streambuf::~basic_zip_streambuf " /** +zlib_stream::basic_zip_streambuf< charT, traits +>::~basic_zip_streambuf(void) */ public"; + + +// File: classgdcm_1_1BasicOffsetTable.xml +%typemap("csclassmodifiers") gdcm::BasicOffsetTable " /** Class to +represent a BasicOffsetTable. + +C++ includes: gdcmBasicOffsetTable.h */ public class"; + +%csmethodmodifiers gdcm::BasicOffsetTable::BasicOffsetTable " /** +gdcm::BasicOffsetTable::BasicOffsetTable() */ public"; + +%csmethodmodifiers gdcm::BasicOffsetTable::Read " /** std::istream& +gdcm::BasicOffsetTable::Read(std::istream &is) */ public"; + + +// File: classgdcm_1_1Bitmap.xml +%typemap("csclassmodifiers") gdcm::Bitmap " /** Bitmap class A bitmap +based image. Used as parent for both IconImage and the main Pixel Data +Image It does not contains any World Space information (IPP, IOP). + +C++ includes: gdcmBitmap.h */ public class"; + +%csmethodmodifiers gdcm::Bitmap::AreOverlaysInPixelData " /** virtual +bool gdcm::Bitmap::AreOverlaysInPixelData() const */ public"; + +%csmethodmodifiers gdcm::Bitmap::Bitmap " /** gdcm::Bitmap::Bitmap() +*/ public"; + +%csmethodmodifiers gdcm::Bitmap::Clear " /** void +gdcm::Bitmap::Clear() */ public"; + +%csmethodmodifiers gdcm::Bitmap::GetBuffer " /** bool +gdcm::Bitmap::GetBuffer(char *buffer) const + +Acces the raw data. + +*/ public"; + +%csmethodmodifiers gdcm::Bitmap::GetBufferLength " /** unsigned long +gdcm::Bitmap::GetBufferLength() const + +Return the length of the image after decompression WARNING for palette +color: It will NOT take into account the Palette Color thus you need +to multiply this length by 3 if computing the size of equivalent RGB +image + +*/ public"; + +%csmethodmodifiers gdcm::Bitmap::GetColumns " /** unsigned int +gdcm::Bitmap::GetColumns() const */ public"; + +%csmethodmodifiers gdcm::Bitmap::GetDataElement " /** DataElement& +gdcm::Bitmap::GetDataElement() */ public"; + +%csmethodmodifiers gdcm::Bitmap::GetDataElement " /** const +DataElement& gdcm::Bitmap::GetDataElement() const */ public"; + +%csmethodmodifiers gdcm::Bitmap::GetDimension " /** unsigned int +gdcm::Bitmap::GetDimension(unsigned int idx) const */ public"; + +%csmethodmodifiers gdcm::Bitmap::GetDimensions " /** const unsigned +int* gdcm::Bitmap::GetDimensions() const + +Return the dimension of the pixel data, first dimension (x), then 2nd +(y), then 3rd (z)... + +*/ public"; + +%csmethodmodifiers gdcm::Bitmap::GetLUT " /** LookupTable& +gdcm::Bitmap::GetLUT() */ public"; + +%csmethodmodifiers gdcm::Bitmap::GetLUT " /** const LookupTable& +gdcm::Bitmap::GetLUT() const */ public"; + +%csmethodmodifiers gdcm::Bitmap::GetNeedByteSwap " /** bool +gdcm::Bitmap::GetNeedByteSwap() const */ public"; + +%csmethodmodifiers gdcm::Bitmap::GetNumberOfDimensions " /** unsigned +int gdcm::Bitmap::GetNumberOfDimensions() const + +Return the number of dimension of the pixel data bytes; for example 2 +for a 2D matrices of values. + +*/ public"; + +%csmethodmodifiers gdcm::Bitmap::GetPhotometricInterpretation " /** +const PhotometricInterpretation& +gdcm::Bitmap::GetPhotometricInterpretation() const + +return the photometric interpretation + +*/ public"; + +%csmethodmodifiers gdcm::Bitmap::GetPixelFormat " /** PixelFormat& +gdcm::Bitmap::GetPixelFormat() */ public"; + +%csmethodmodifiers gdcm::Bitmap::GetPixelFormat " /** const +PixelFormat& gdcm::Bitmap::GetPixelFormat() const + +Get/Set PixelFormat. + +*/ public"; + +%csmethodmodifiers gdcm::Bitmap::GetPlanarConfiguration " /** +unsigned int gdcm::Bitmap::GetPlanarConfiguration() const + +return the planar configuration + +*/ public"; + +%csmethodmodifiers gdcm::Bitmap::GetRows " /** unsigned int +gdcm::Bitmap::GetRows() const */ public"; + +%csmethodmodifiers gdcm::Bitmap::GetTransferSyntax " /** const +TransferSyntax& gdcm::Bitmap::GetTransferSyntax() const */ public"; + +%csmethodmodifiers gdcm::Bitmap::IsEmpty " /** bool +gdcm::Bitmap::IsEmpty() const */ public"; + +%csmethodmodifiers gdcm::Bitmap::IsLossy " /** bool +gdcm::Bitmap::IsLossy() const + +Return whether or not the image was compressed using a lossy +compressor or not Transfer Syntax alone is not sufficient to detect +that. Warning if the image contains an invalid stream, the return code +is also 'false' So this call return true only when the following +combination is true: 1. The image can succefully be read 2. The image +is indeed lossy + +*/ public"; + +%csmethodmodifiers gdcm::Bitmap::Print " /** void +gdcm::Bitmap::Print(std::ostream &) const */ public"; + +%csmethodmodifiers gdcm::Bitmap::SetColumns " /** void +gdcm::Bitmap::SetColumns(unsigned int col) */ public"; + +%csmethodmodifiers gdcm::Bitmap::SetDataElement " /** void +gdcm::Bitmap::SetDataElement(DataElement const &de) */ public"; + +%csmethodmodifiers gdcm::Bitmap::SetDimension " /** void +gdcm::Bitmap::SetDimension(unsigned int idx, unsigned int dim) */ +public"; + +%csmethodmodifiers gdcm::Bitmap::SetDimensions " /** void +gdcm::Bitmap::SetDimensions(const unsigned int dims[3]) */ public"; + +%csmethodmodifiers gdcm::Bitmap::SetLossyFlag " /** void +gdcm::Bitmap::SetLossyFlag(bool f) */ public"; + +%csmethodmodifiers gdcm::Bitmap::SetLUT " /** void +gdcm::Bitmap::SetLUT(LookupTable const &lut) + +Set/Get LUT. + +*/ public"; + +%csmethodmodifiers gdcm::Bitmap::SetNeedByteSwap " /** void +gdcm::Bitmap::SetNeedByteSwap(bool b) */ public"; + +%csmethodmodifiers gdcm::Bitmap::SetNumberOfDimensions " /** void +gdcm::Bitmap::SetNumberOfDimensions(unsigned int dim) */ public"; + +%csmethodmodifiers gdcm::Bitmap::SetPhotometricInterpretation " /** +void +gdcm::Bitmap::SetPhotometricInterpretation(PhotometricInterpretation +const &pi) */ public"; + +%csmethodmodifiers gdcm::Bitmap::SetPixelFormat " /** void +gdcm::Bitmap::SetPixelFormat(PixelFormat const &pf) */ public"; + +%csmethodmodifiers gdcm::Bitmap::SetPlanarConfiguration " /** void +gdcm::Bitmap::SetPlanarConfiguration(unsigned int pc) */ public"; + +%csmethodmodifiers gdcm::Bitmap::SetRows " /** void +gdcm::Bitmap::SetRows(unsigned int rows) */ public"; + +%csmethodmodifiers gdcm::Bitmap::SetTransferSyntax " /** void +gdcm::Bitmap::SetTransferSyntax(TransferSyntax const &ts) + +Transfer syntax. + +*/ public"; + +%csmethodmodifiers gdcm::Bitmap::~Bitmap " /** +gdcm::Bitmap::~Bitmap() */ public"; + + +// File: classstd_1_1bitset.xml +%typemap("csclassmodifiers") std::bitset " /** STL class. + +*/ public class"; + + +// File: classgdcm_1_1ByteBuffer.xml +%typemap("csclassmodifiers") gdcm::ByteBuffer " /** ByteBuffer. + +Detailled description here looks like a std::streambuf or std::filebuf +class with the get and peek pointer + +C++ includes: gdcmByteBuffer.h */ public class"; + +%csmethodmodifiers gdcm::ByteBuffer::ByteBuffer " /** +gdcm::ByteBuffer::ByteBuffer() */ public"; + +%csmethodmodifiers gdcm::ByteBuffer::Get " /** char* +gdcm::ByteBuffer::Get(int len) */ public"; + +%csmethodmodifiers gdcm::ByteBuffer::GetStart " /** const char* +gdcm::ByteBuffer::GetStart() const */ public"; + +%csmethodmodifiers gdcm::ByteBuffer::ShiftEnd " /** void +gdcm::ByteBuffer::ShiftEnd(int len) */ public"; + +%csmethodmodifiers gdcm::ByteBuffer::UpdatePosition " /** void +gdcm::ByteBuffer::UpdatePosition() */ public"; + + +// File: classgdcm_1_1ByteSwap.xml +%typemap("csclassmodifiers") gdcm::ByteSwap " /** ByteSwap. + +Perform machine dependent byte swaping (Little Endian, Big Endian, Bad +Little Endian, Bad Big Endian). TODO: bswap_32 / bswap_64 ... + +C++ includes: gdcmByteSwap.h */ public class"; + + +// File: classgdcm_1_1ByteSwapFilter.xml +%typemap("csclassmodifiers") gdcm::ByteSwapFilter " /** +ByteSwapFilter In place byte-swapping of a dataset FIXME: FL status ?? + +C++ includes: gdcmByteSwapFilter.h */ public class"; + +%csmethodmodifiers gdcm::ByteSwapFilter::ByteSwap " /** bool +gdcm::ByteSwapFilter::ByteSwap() */ public"; + +%csmethodmodifiers gdcm::ByteSwapFilter::ByteSwapFilter " /** +gdcm::ByteSwapFilter::ByteSwapFilter(DataSet &ds) */ public"; + +%csmethodmodifiers gdcm::ByteSwapFilter::SetByteSwapTag " /** void +gdcm::ByteSwapFilter::SetByteSwapTag(bool b) */ public"; + +%csmethodmodifiers gdcm::ByteSwapFilter::~ByteSwapFilter " /** +gdcm::ByteSwapFilter::~ByteSwapFilter() */ public"; + + +// File: classgdcm_1_1ByteValue.xml +%typemap("csclassmodifiers") gdcm::ByteValue " /** Class to represent +binary value (array of bytes). + +C++ includes: gdcmByteValue.h */ public class"; + +%csmethodmodifiers gdcm::ByteValue::ByteValue " /** +gdcm::ByteValue::ByteValue(std::vector< char > &v) */ public"; + +%csmethodmodifiers gdcm::ByteValue::ByteValue " /** +gdcm::ByteValue::ByteValue(const char *array=0, VL const &vl=0) */ +public"; + +%csmethodmodifiers gdcm::ByteValue::Clear " /** void +gdcm::ByteValue::Clear() */ public"; + +%csmethodmodifiers gdcm::ByteValue::Fill " /** void +gdcm::ByteValue::Fill(char c) */ public"; + +%csmethodmodifiers gdcm::ByteValue::GetBuffer " /** bool +gdcm::ByteValue::GetBuffer(char *buffer, unsigned long length) const +*/ public"; + +%csmethodmodifiers gdcm::ByteValue::GetLength " /** VL +gdcm::ByteValue::GetLength() const */ public"; + +%csmethodmodifiers gdcm::ByteValue::GetPointer " /** const char* +gdcm::ByteValue::GetPointer() const */ public"; + +%csmethodmodifiers gdcm::ByteValue::IsEmpty " /** bool +gdcm::ByteValue::IsEmpty() const */ public"; + +%csmethodmodifiers gdcm::ByteValue::IsPrintable " /** bool +gdcm::ByteValue::IsPrintable(VL length) const + +Checks whether a 'ByteValue' is printable or not (in order to avoid +corrupting the terminal of invocation when printing) I dont think this +function is working since it does not handle UNICODE or character +set... + +*/ public"; + +%csmethodmodifiers gdcm::ByteValue::PrintASCII " /** void +gdcm::ByteValue::PrintASCII(std::ostream &os, VL maxlength) const */ +public"; + +%csmethodmodifiers gdcm::ByteValue::PrintGroupLength " /** void +gdcm::ByteValue::PrintGroupLength(std::ostream &os) */ public"; + +%csmethodmodifiers gdcm::ByteValue::PrintHex " /** void +gdcm::ByteValue::PrintHex(std::ostream &os, VL maxlength) const */ +public"; + +%csmethodmodifiers gdcm::ByteValue::Read " /** std::istream& +gdcm::ByteValue::Read(std::istream &is) */ public"; + +%csmethodmodifiers gdcm::ByteValue::Read " /** std::istream& +gdcm::ByteValue::Read(std::istream &is) */ public"; + +%csmethodmodifiers gdcm::ByteValue::SetLength " /** void +gdcm::ByteValue::SetLength(VL vl) */ public"; + +%csmethodmodifiers gdcm::ByteValue::Write " /** std::ostream const& +gdcm::ByteValue::Write(std::ostream &os) const */ public"; + +%csmethodmodifiers gdcm::ByteValue::Write " /** std::ostream const& +gdcm::ByteValue::Write(std::ostream &os) const */ public"; + +%csmethodmodifiers gdcm::ByteValue::WriteBuffer " /** bool +gdcm::ByteValue::WriteBuffer(std::ostream &os) const */ public"; + +%csmethodmodifiers gdcm::ByteValue::~ByteValue " /** +gdcm::ByteValue::~ByteValue() */ public"; + + +// File: classgdcm_1_1Codec.xml +%typemap("csclassmodifiers") gdcm::Codec " /** Codec class. + +C++ includes: gdcmCodec.h */ public class"; + + +// File: classgdcm_1_1Coder.xml +%typemap("csclassmodifiers") gdcm::Coder " /** Coder. + +C++ includes: gdcmCoder.h */ public class"; + +%csmethodmodifiers gdcm::Coder::CanCode " /** virtual bool +gdcm::Coder::CanCode(TransferSyntax const &) const =0 + +Return whether this coder support this transfer syntax (can code it). + +*/ public"; + +%csmethodmodifiers gdcm::Coder::Code " /** virtual bool +gdcm::Coder::Code(DataElement const &in, DataElement &out) + +Code. + +*/ public"; + +%csmethodmodifiers gdcm::Coder::~Coder " /** virtual +gdcm::Coder::~Coder() */ public"; + + +// File: classstd_1_1complex.xml +%typemap("csclassmodifiers") std::complex " /** STL class. + +*/ public class"; + + +// File: classgdcm_1_1ConstCharWrapper.xml +%typemap("csclassmodifiers") gdcm::ConstCharWrapper " /**C++ includes: +gdcmConstCharWrapper.h */ public class"; + +%csmethodmodifiers gdcm::ConstCharWrapper::ConstCharWrapper " /** +gdcm::ConstCharWrapper::ConstCharWrapper(const char *i=0) */ public"; + + +// File: classgdcm_1_1CP246ExplicitDataElement.xml +%typemap("csclassmodifiers") gdcm::CP246ExplicitDataElement " /** +Class to read/write a DataElement as CP246Explicit Data Element. + +Some system are producing SQ, declare them as UN, but encode the SQ as +'Explicit' instead of Implicit + +C++ includes: gdcmCP246ExplicitDataElement.h */ public class"; + +%csmethodmodifiers gdcm::CP246ExplicitDataElement::GetLength " /** VL +gdcm::CP246ExplicitDataElement::GetLength() const */ public"; + +%csmethodmodifiers gdcm::CP246ExplicitDataElement::Read " /** +std::istream& gdcm::CP246ExplicitDataElement::Read(std::istream &is) +*/ public"; + +%csmethodmodifiers gdcm::CP246ExplicitDataElement::ReadWithLength " +/** std::istream& +gdcm::CP246ExplicitDataElement::ReadWithLength(std::istream &is, VL +&length) */ public"; + + +// File: classgdcm_1_1CSAElement.xml +%typemap("csclassmodifiers") gdcm::CSAElement " /** Class to represent +a CSA Element. + +C++ includes: gdcmCSAElement.h */ public class"; + +%csmethodmodifiers gdcm::CSAElement::CSAElement " /** +gdcm::CSAElement::CSAElement(const CSAElement &_val) */ public"; + +%csmethodmodifiers gdcm::CSAElement::CSAElement " /** +gdcm::CSAElement::CSAElement(unsigned int kf=0) */ public"; + +%csmethodmodifiers gdcm::CSAElement::GetByteValue " /** const +ByteValue* gdcm::CSAElement::GetByteValue() const */ public"; + +%csmethodmodifiers gdcm::CSAElement::GetKey " /** unsigned int +gdcm::CSAElement::GetKey() const + +Set/Get Key. + +*/ public"; + +%csmethodmodifiers gdcm::CSAElement::GetName " /** const char* +gdcm::CSAElement::GetName() const + +Set/Get Name. + +*/ public"; + +%csmethodmodifiers gdcm::CSAElement::GetNoOfItems " /** unsigned int +gdcm::CSAElement::GetNoOfItems() const + +Set/Get NoOfItems. + +*/ public"; + +%csmethodmodifiers gdcm::CSAElement::GetSyngoDT " /** unsigned int +gdcm::CSAElement::GetSyngoDT() const + +Set/Get SyngoDT. + +*/ public"; + +%csmethodmodifiers gdcm::CSAElement::GetValue " /** Value& +gdcm::CSAElement::GetValue() */ public"; + +%csmethodmodifiers gdcm::CSAElement::GetValue " /** Value const& +gdcm::CSAElement::GetValue() const + +Set/Get Value (bytes array, SQ of items, SQ of fragments):. + +*/ public"; + +%csmethodmodifiers gdcm::CSAElement::GetVM " /** const VM& +gdcm::CSAElement::GetVM() const + +Set/Get VM. + +*/ public"; + +%csmethodmodifiers gdcm::CSAElement::GetVR " /** VR const& +gdcm::CSAElement::GetVR() const + +Set/Get VR. + +*/ public"; + +%csmethodmodifiers gdcm::CSAElement::IsEmpty " /** bool +gdcm::CSAElement::IsEmpty() const */ public"; + +%csmethodmodifiers gdcm::CSAElement::SetByteValue " /** void +gdcm::CSAElement::SetByteValue(const char *array, VL length) */ +public"; + +%csmethodmodifiers gdcm::CSAElement::SetKey " /** void +gdcm::CSAElement::SetKey(unsigned int key) */ public"; + +%csmethodmodifiers gdcm::CSAElement::SetName " /** void +gdcm::CSAElement::SetName(const char *name) */ public"; + +%csmethodmodifiers gdcm::CSAElement::SetNoOfItems " /** void +gdcm::CSAElement::SetNoOfItems(unsigned int items) */ public"; + +%csmethodmodifiers gdcm::CSAElement::SetSyngoDT " /** void +gdcm::CSAElement::SetSyngoDT(unsigned int syngodt) */ public"; + +%csmethodmodifiers gdcm::CSAElement::SetValue " /** void +gdcm::CSAElement::SetValue(Value const &vl) */ public"; + +%csmethodmodifiers gdcm::CSAElement::SetVM " /** void +gdcm::CSAElement::SetVM(const VM &vm) */ public"; + +%csmethodmodifiers gdcm::CSAElement::SetVR " /** void +gdcm::CSAElement::SetVR(VR const &vr) */ public"; + + +// File: classgdcm_1_1CSAHeader.xml +%typemap("csclassmodifiers") gdcm::CSAHeader " /** Class for +CSAHeader. + +SIEMENS store private information in tag (0x0029,0x10,\"SIEMENS CSA +HEADER\") this class is meant for user wishing to access values stored +within this private attribute. There are basically two main 'format' +for this attribute : SV10/NOMAGIC and DATASET_FORMAT SV10 and NOMAGIC +are from a user prospective identical, see CSAHeader.xml for possible +name / value stored in this format. DATASET_FORMAT is in fact simply +just another DICOM dataset (implicit) with -currently unknown- value. +This can be only be printer for now. + +WARNING: : Everything you do with this code is at your own risk, +since decoding process was not written from specification documents. +: the API of this class might change. + +: MrEvaProtocol in 29,1020 contains ^M that would be nice to get rid +of on UNIX system... + +also 5.1.3.2.4.1 MEDCOM History Information and 5.1.4.3 CSA Non-Image +Module inhttp://tamsinfo.toshiba.com/docrequest/pdf/E.Soft_v2.0.pdf + +C++ includes: gdcmCSAHeader.h */ public class"; + +%csmethodmodifiers gdcm::CSAHeader::CSAHeader " /** +gdcm::CSAHeader::CSAHeader() */ public"; + +%csmethodmodifiers gdcm::CSAHeader::FindCSAElementByName " /** bool +gdcm::CSAHeader::FindCSAElementByName(const char *name) + +Return true if the CSA element matching 'name' is found or not +WARNING: Case Sensitive + +*/ public"; + +%csmethodmodifiers gdcm::CSAHeader::GetCSAElementByName " /** const +CSAElement& gdcm::CSAHeader::GetCSAElementByName(const char *name) + +Return the CSAElement corresponding to name 'name' WARNING: Case +Sensitive + +*/ public"; + +%csmethodmodifiers gdcm::CSAHeader::GetDataSet " /** const DataSet& +gdcm::CSAHeader::GetDataSet() const + +Return the DataSet output (use only if Format == DATASET_FORMAT ). + +*/ public"; + +%csmethodmodifiers gdcm::CSAHeader::GetFormat " /** CSAHeaderType +gdcm::CSAHeader::GetFormat() const + +return the format of the CSAHeader SV10 and NOMAGIC are equivalent. + +*/ public"; + +%csmethodmodifiers gdcm::CSAHeader::GetInterfile " /** const char* +gdcm::CSAHeader::GetInterfile() const + +Return the string output (use only if Format == Interfile). + +*/ public"; + +%csmethodmodifiers gdcm::CSAHeader::LoadFromDataElement " /** bool +gdcm::CSAHeader::LoadFromDataElement(DataElement const &de) + +Decode the CSAHeader from element 'de'. + +*/ public"; + +%csmethodmodifiers gdcm::CSAHeader::Print " /** void +gdcm::CSAHeader::Print(std::ostream &os) const + +Print the CSAHeader (use only if Format == SV10 or NOMAGIC). + +*/ public"; + +%csmethodmodifiers gdcm::CSAHeader::Read " /** std::istream& +gdcm::CSAHeader::Read(std::istream &is) */ public"; + +%csmethodmodifiers gdcm::CSAHeader::Write " /** const std::ostream& +gdcm::CSAHeader::Write(std::ostream &os) const */ public"; + +%csmethodmodifiers gdcm::CSAHeader::~CSAHeader " /** +gdcm::CSAHeader::~CSAHeader() */ public"; + + +// File: classgdcm_1_1CSAHeaderDict.xml +%typemap("csclassmodifiers") gdcm::CSAHeaderDict " /** Class to +represent a map of CSAHeaderDictEntry. + +C++ includes: gdcmCSAHeaderDict.h */ public class"; + +%csmethodmodifiers gdcm::CSAHeaderDict::AddCSAHeaderDictEntry " /** +void gdcm::CSAHeaderDict::AddCSAHeaderDictEntry(const +CSAHeaderDictEntry &de) */ public"; + +%csmethodmodifiers gdcm::CSAHeaderDict::Begin " /** ConstIterator +gdcm::CSAHeaderDict::Begin() const */ public"; + +%csmethodmodifiers gdcm::CSAHeaderDict::CSAHeaderDict " /** +gdcm::CSAHeaderDict::CSAHeaderDict() */ public"; + +%csmethodmodifiers gdcm::CSAHeaderDict::End " /** ConstIterator +gdcm::CSAHeaderDict::End() const */ public"; + +%csmethodmodifiers gdcm::CSAHeaderDict::GetCSAHeaderDictEntry " /** +const CSAHeaderDictEntry& +gdcm::CSAHeaderDict::GetCSAHeaderDictEntry(const char *name) const */ +public"; + +%csmethodmodifiers gdcm::CSAHeaderDict::IsEmpty " /** bool +gdcm::CSAHeaderDict::IsEmpty() const */ public"; + + +// File: classgdcm_1_1CSAHeaderDictEntry.xml +%typemap("csclassmodifiers") gdcm::CSAHeaderDictEntry " /** Class to +represent an Entry in the Dict Does not really exist within the DICOM +definition, just a way to minimize storage and have a mapping from +gdcm::Tag to the needed information. + +bla TODO FIXME: Need a PublicCSAHeaderDictEntry...indeed +CSAHeaderDictEntry has a notion of retired which does not exist in +PrivateCSAHeaderDictEntry... + +See: gdcm::Dict + +C++ includes: gdcmCSAHeaderDictEntry.h */ public class"; + +%csmethodmodifiers gdcm::CSAHeaderDictEntry::CSAHeaderDictEntry " /** +gdcm::CSAHeaderDictEntry::CSAHeaderDictEntry(const char *name=\"\", VR +const &vr=VR::INVALID, VM const &vm=VM::VM0, const char *desc=\"\") +*/ public"; + +%csmethodmodifiers gdcm::CSAHeaderDictEntry::GetDescription " /** +const char* gdcm::CSAHeaderDictEntry::GetDescription() const + +Set/Get Description. + +*/ public"; + +%csmethodmodifiers gdcm::CSAHeaderDictEntry::GetName " /** const +char* gdcm::CSAHeaderDictEntry::GetName() const + +Set/Get Name. + +*/ public"; + +%csmethodmodifiers gdcm::CSAHeaderDictEntry::GetVM " /** const VM& +gdcm::CSAHeaderDictEntry::GetVM() const + +Set/Get VM. + +*/ public"; + +%csmethodmodifiers gdcm::CSAHeaderDictEntry::GetVR " /** const VR& +gdcm::CSAHeaderDictEntry::GetVR() const + +Set/Get VR. + +*/ public"; + +%csmethodmodifiers gdcm::CSAHeaderDictEntry::SetDescription " /** +void gdcm::CSAHeaderDictEntry::SetDescription(const char *desc) */ +public"; + +%csmethodmodifiers gdcm::CSAHeaderDictEntry::SetName " /** void +gdcm::CSAHeaderDictEntry::SetName(const char *name) */ public"; + +%csmethodmodifiers gdcm::CSAHeaderDictEntry::SetVM " /** void +gdcm::CSAHeaderDictEntry::SetVM(VM const &vm) */ public"; + +%csmethodmodifiers gdcm::CSAHeaderDictEntry::SetVR " /** void +gdcm::CSAHeaderDictEntry::SetVR(const VR &vr) */ public"; + + +// File: classgdcm_1_1CSAHeaderDictException.xml +%typemap("csclassmodifiers") gdcm::CSAHeaderDictException " /**C++ +includes: gdcmCSAHeaderDict.h */ public class"; + + +// File: classgdcm_1_1Curve.xml +%typemap("csclassmodifiers") gdcm::Curve " /** Curve class to handle +element 50xx,3000 Curve Data WARNING: This is deprecated and lastly +defined in PS 3.3 - 2004. + +Examples: GE_DLX-8-MONO2-Multiframe-Jpeg_Lossless.dcm + +GE_DLX-8-MONO2-Multiframe.dcm + +gdcmSampleData/Philips_Medical_Images/integris_HV_5000/xa_integris.dcm + +TOSHIBA-CurveData[1-3].dcm + +C++ includes: gdcmCurve.h */ public class"; + +%csmethodmodifiers gdcm::Curve::Curve " /** gdcm::Curve::Curve(Curve +const &ov) */ public"; + +%csmethodmodifiers gdcm::Curve::Curve " /** gdcm::Curve::Curve() */ +public"; + +%csmethodmodifiers gdcm::Curve::Decode " /** void +gdcm::Curve::Decode(std::istream &is, std::ostream &os) */ public"; + +%csmethodmodifiers gdcm::Curve::GetAsPoints " /** void +gdcm::Curve::GetAsPoints(float *array) const */ public"; + +%csmethodmodifiers gdcm::Curve::GetDataValueRepresentation " /** +unsigned short gdcm::Curve::GetDataValueRepresentation() const */ +public"; + +%csmethodmodifiers gdcm::Curve::GetDimensions " /** unsigned short +gdcm::Curve::GetDimensions() const */ public"; + +%csmethodmodifiers gdcm::Curve::GetGroup " /** unsigned short +gdcm::Curve::GetGroup() const */ public"; + +%csmethodmodifiers gdcm::Curve::GetNumberOfPoints " /** unsigned +short gdcm::Curve::GetNumberOfPoints() const */ public"; + +%csmethodmodifiers gdcm::Curve::GetTypeOfData " /** const char* +gdcm::Curve::GetTypeOfData() const */ public"; + +%csmethodmodifiers gdcm::Curve::GetTypeOfDataDescription " /** const +char* gdcm::Curve::GetTypeOfDataDescription() const */ public"; + +%csmethodmodifiers gdcm::Curve::IsEmpty " /** bool +gdcm::Curve::IsEmpty() const */ public"; + +%csmethodmodifiers gdcm::Curve::Print " /** void +gdcm::Curve::Print(std::ostream &) const */ public"; + +%csmethodmodifiers gdcm::Curve::SetCurve " /** void +gdcm::Curve::SetCurve(const char *array, unsigned int length) */ +public"; + +%csmethodmodifiers gdcm::Curve::SetCurveDescription " /** void +gdcm::Curve::SetCurveDescription(const char *curvedescription) */ +public"; + +%csmethodmodifiers gdcm::Curve::SetDataValueRepresentation " /** void +gdcm::Curve::SetDataValueRepresentation(unsigned short +datavaluerepresentation) */ public"; + +%csmethodmodifiers gdcm::Curve::SetDimensions " /** void +gdcm::Curve::SetDimensions(unsigned short dimensions) */ public"; + +%csmethodmodifiers gdcm::Curve::SetGroup " /** void +gdcm::Curve::SetGroup(unsigned short group) */ public"; + +%csmethodmodifiers gdcm::Curve::SetNumberOfPoints " /** void +gdcm::Curve::SetNumberOfPoints(unsigned short numberofpoints) */ +public"; + +%csmethodmodifiers gdcm::Curve::SetTypeOfData " /** void +gdcm::Curve::SetTypeOfData(const char *typeofdata) */ public"; + +%csmethodmodifiers gdcm::Curve::Update " /** void +gdcm::Curve::Update(const DataElement &de) */ public"; + +%csmethodmodifiers gdcm::Curve::~Curve " /** gdcm::Curve::~Curve() +*/ public"; + + +// File: classgdcm_1_1DataElement.xml +%typemap("csclassmodifiers") gdcm::DataElement " /** Class to +represent a Data Element either Implicit or Explicit. + +DATA ELEMENT: A unit of information as defined by a single entry in +the data dictionary. An encoded Information Object Definition ( IOD) +Attribute that is composed of, at a minimum, three fields: a Data +Element Tag, a Value Length, and a Value Field. For some specific +Transfer Syntaxes, a Data Element also contains a VR Field where the +Value Representation of that Data Element is specified explicitly. + +C++ includes: gdcmDataElement.h */ public class"; + +%csmethodmodifiers gdcm::DataElement::Clear " /** void +gdcm::DataElement::Clear() */ public"; + +%csmethodmodifiers gdcm::DataElement::DataElement " /** +gdcm::DataElement::DataElement(const DataElement &_val) */ public"; + +%csmethodmodifiers gdcm::DataElement::DataElement " /** +gdcm::DataElement::DataElement(const Tag &t=Tag(0), const VL &vl=0, +const VR &vr=VR::INVALID) */ public"; + +%csmethodmodifiers gdcm::DataElement::Empty " /** void +gdcm::DataElement::Empty() */ public"; + +%csmethodmodifiers gdcm::DataElement::GetByteValue " /** ByteValue* +gdcm::DataElement::GetByteValue() */ public"; + +%csmethodmodifiers gdcm::DataElement::GetByteValue " /** const +ByteValue* gdcm::DataElement::GetByteValue() const + +Return the Value of DataElement as a ByteValue (if possible) WARNING: +: You need to check for NULL return value + +*/ public"; + +%csmethodmodifiers gdcm::DataElement::GetLength " /** VL +gdcm::DataElement::GetLength() const */ public"; + +%csmethodmodifiers gdcm::DataElement::GetSequenceOfFragments " /** +const SequenceOfFragments* gdcm::DataElement::GetSequenceOfFragments() +const + +Return the Value of DataElement as a Sequence Of Fragments (if +possible) WARNING: : You need to check for NULL return value + +*/ public"; + +%csmethodmodifiers gdcm::DataElement::GetSequenceOfItems " /** +SequenceOfItems* gdcm::DataElement::GetSequenceOfItems() */ public"; + +%csmethodmodifiers gdcm::DataElement::GetSequenceOfItems " /** const +SequenceOfItems* gdcm::DataElement::GetSequenceOfItems() const + +Return the Value of DataElement as a Sequence Of Items (if possible) +WARNING: : You need to check for NULL return value + +: In some case a Value could not have been recognized as a +SequenceOfItems in those case the return of the function will be NULL, +while the Value would be a valid SequenceOfItems, in those case prefer +GetValueAsSQ. In which case the code internally trigger an assert to +warn developper. + +*/ public"; + +%csmethodmodifiers gdcm::DataElement::GetTag " /** Tag& +gdcm::DataElement::GetTag() */ public"; + +%csmethodmodifiers gdcm::DataElement::GetTag " /** const Tag& +gdcm::DataElement::GetTag() const + +Get Tag. + +*/ public"; + +%csmethodmodifiers gdcm::DataElement::GetValue " /** Value& +gdcm::DataElement::GetValue() */ public"; + +%csmethodmodifiers gdcm::DataElement::GetValue " /** Value const& +gdcm::DataElement::GetValue() const + +Set/Get Value (bytes array, SQ of items, SQ of fragments):. + +*/ public"; + +%csmethodmodifiers gdcm::DataElement::GetValueAsSQ " /** +SmartPointer gdcm::DataElement::GetValueAsSQ() const + +Interpret the Value stored in the DataElement. This is more robust +(but also more expensive) to call this function rather than the +simpliest form: GetSequenceOfItems() It also return NULL when the +Value is NOT of type SequenceOfItems WARNING: in case +GetSequenceOfItems() succeed the function return this value, otherwise +it creates a new SequenceOfItems, you should handle that in your case, +for instance: SmartPointer sqi = de.GetValueAsSQ(); + +*/ public"; + +%csmethodmodifiers gdcm::DataElement::GetVL " /** const VL& +gdcm::DataElement::GetVL() const + +Get VL. + +*/ public"; + +%csmethodmodifiers gdcm::DataElement::GetVR " /** VR const& +gdcm::DataElement::GetVR() const + +Get VR do not set VR::SQ on bytevalue data element + +*/ public"; + +%csmethodmodifiers gdcm::DataElement::IsEmpty " /** bool +gdcm::DataElement::IsEmpty() const + +Check if Data Element is empty. + +*/ public"; + +%csmethodmodifiers gdcm::DataElement::IsUndefinedLength " /** bool +gdcm::DataElement::IsUndefinedLength() const + +return if Value Length if of undefined length + +*/ public"; + +%csmethodmodifiers gdcm::DataElement::Read " /** std::istream& +gdcm::DataElement::Read(std::istream &is) */ public"; + +%csmethodmodifiers gdcm::DataElement::ReadOrSkip " /** std::istream& +gdcm::DataElement::ReadOrSkip(std::istream &is, std::set< Tag > const +&skiptags) */ public"; + +%csmethodmodifiers gdcm::DataElement::ReadWithLength " /** +std::istream& gdcm::DataElement::ReadWithLength(std::istream &is, VL +&length) */ public"; + +%csmethodmodifiers gdcm::DataElement::SetByteValue " /** void +gdcm::DataElement::SetByteValue(const char *array, VL length) + +Set the byte value WARNING: user need to read DICOM standard for an +understanding of: even padding vs space padding By default even +padding is achieved using regardless of the of VR + +*/ public"; + +%csmethodmodifiers gdcm::DataElement::SetTag " /** void +gdcm::DataElement::SetTag(const Tag &t) + +Set Tag Use with cautious (need to match Part 6) + +*/ public"; + +%csmethodmodifiers gdcm::DataElement::SetValue " /** void +gdcm::DataElement::SetValue(Value const &vl) + +WARNING: you need to set the ValueLengthField explicitely + +*/ public"; + +%csmethodmodifiers gdcm::DataElement::SetVL " /** void +gdcm::DataElement::SetVL(const VL &vl) + +Set VL Use with cautious (need to match Part 6), advanced user only +See: SetByteValue + +*/ public"; + +%csmethodmodifiers gdcm::DataElement::SetVLToUndefined " /** void +gdcm::DataElement::SetVLToUndefined() */ public"; + +%csmethodmodifiers gdcm::DataElement::SetVR " /** void +gdcm::DataElement::SetVR(VR const &vr) + +Set VR Use with cautious (need to match Part 6), advanced user only vr +is a VR::VRALL (not a dual one such as OB_OW) + +*/ public"; + +%csmethodmodifiers gdcm::DataElement::Write " /** const std::ostream& +gdcm::DataElement::Write(std::ostream &os) const */ public"; + + +// File: classgdcm_1_1DataElementException.xml +%typemap("csclassmodifiers") gdcm::DataElementException " /**C++ +includes: gdcmDataSet.h */ public class"; + + +// File: classgdcm_1_1DataSet.xml +%typemap("csclassmodifiers") gdcm::DataSet " /** Class to represent a +Data Set (which contains Data Elements) A Data Set represents an +instance of a real world Information Object. + +DATA SET: Exchanged information consisting of a structured set of +Attribute values directly or indirectly related to Information +Objects. The value of each Attribute in a Data Set is expressed as a +Data Element. A collection of Data Elements ordered by increasing Data +Element Tag number that is an encoding of the values of Attributes of +a real world object. + +Implementation note. If one do: DataSet ds; ds.SetLength(0); +ds.Read(is); setting length to 0 actually means try to read is as if +it was a root DataSet. Other value are undefined (nested dataset with +undefined length) or defined length (different from 0) means nested +dataset with defined length. TODO: a DataSet DOES NOT have a TS +type... a file does ! + +C++ includes: gdcmDataSet.h */ public class"; + +%csmethodmodifiers gdcm::DataSet::Begin " /** Iterator +gdcm::DataSet::Begin() */ public"; + +%csmethodmodifiers gdcm::DataSet::Begin " /** ConstIterator +gdcm::DataSet::Begin() const */ public"; + +%csmethodmodifiers gdcm::DataSet::Clear " /** void +gdcm::DataSet::Clear() */ public"; + +%csmethodmodifiers gdcm::DataSet::ComputeGroupLength " /** unsigned +int gdcm::DataSet::ComputeGroupLength(Tag const &tag) const */ +public"; + +%csmethodmodifiers gdcm::DataSet::End " /** Iterator +gdcm::DataSet::End() */ public"; + +%csmethodmodifiers gdcm::DataSet::End " /** ConstIterator +gdcm::DataSet::End() const */ public"; + +%csmethodmodifiers gdcm::DataSet::FindDataElement " /** bool +gdcm::DataSet::FindDataElement(const Tag &t) const */ public"; + +%csmethodmodifiers gdcm::DataSet::FindDataElement " /** bool +gdcm::DataSet::FindDataElement(const PrivateTag &t) const + +Look up if private tag 't' is present in the dataset:. + +*/ public"; + +%csmethodmodifiers gdcm::DataSet::FindNextDataElement " /** const +DataElement& gdcm::DataSet::FindNextDataElement(const Tag &t) const +*/ public"; + +%csmethodmodifiers gdcm::DataSet::GetDataElement " /** const +DataElement& gdcm::DataSet::GetDataElement(const PrivateTag &t) const + +Return the dataelement. + +*/ public"; + +%csmethodmodifiers gdcm::DataSet::GetDataElement " /** const +DataElement& gdcm::DataSet::GetDataElement(const Tag &t) const + +Return the DataElement with Tag 't' WARNING: : This only search at +the 'root level' of the DataSet + +*/ public"; + +%csmethodmodifiers gdcm::DataSet::GetDES " /** DataElementSet& +gdcm::DataSet::GetDES() */ public"; + +%csmethodmodifiers gdcm::DataSet::GetDES " /** const DataElementSet& +gdcm::DataSet::GetDES() const */ public"; + +%csmethodmodifiers gdcm::DataSet::GetLength " /** VL +gdcm::DataSet::GetLength() const */ public"; + +%csmethodmodifiers gdcm::DataSet::GetPrivateCreator " /** std::string +gdcm::DataSet::GetPrivateCreator(const Tag &t) const + +Return the private creator of the private tag 't':. + +*/ public"; + +%csmethodmodifiers gdcm::DataSet::Insert " /** void +gdcm::DataSet::Insert(const DataElement &de) + +Insert a DataElement in the DataSet. WARNING: : Tag need to be >= 0x8 +to be considered valid data element + +*/ public"; + +%csmethodmodifiers gdcm::DataSet::IsEmpty " /** bool +gdcm::DataSet::IsEmpty() const + +Returns if the dataset is empty. + +*/ public"; + +%csmethodmodifiers gdcm::DataSet::Print " /** void +gdcm::DataSet::Print(std::ostream &os, std::string const &indent=\"\") +const */ public"; + +%csmethodmodifiers gdcm::DataSet::Read " /** std::istream& +gdcm::DataSet::Read(std::istream &is) */ public"; + +%csmethodmodifiers gdcm::DataSet::ReadNested " /** std::istream& +gdcm::DataSet::ReadNested(std::istream &is) */ public"; + +%csmethodmodifiers gdcm::DataSet::ReadUpToTag " /** std::istream& +gdcm::DataSet::ReadUpToTag(std::istream &is, const Tag &t, std::set< +Tag > const &skiptags) */ public"; + +%csmethodmodifiers gdcm::DataSet::ReadUpToTagWithLength " /** +std::istream& gdcm::DataSet::ReadUpToTagWithLength(std::istream &is, +const Tag &t, VL &length) */ public"; + +%csmethodmodifiers gdcm::DataSet::ReadWithLength " /** std::istream& +gdcm::DataSet::ReadWithLength(std::istream &is, VL &length) */ +public"; + +%csmethodmodifiers gdcm::DataSet::Remove " /** SizeType +gdcm::DataSet::Remove(const Tag &tag) + +Completely remove a dataelement from the dataset. + +*/ public"; + +%csmethodmodifiers gdcm::DataSet::Replace " /** void +gdcm::DataSet::Replace(const DataElement &de) + +Replace a dataelement with another one. + +*/ public"; + +%csmethodmodifiers gdcm::DataSet::Size " /** unsigned int +gdcm::DataSet::Size() const */ public"; + +%csmethodmodifiers gdcm::DataSet::Write " /** std::ostream const& +gdcm::DataSet::Write(std::ostream &os) const */ public"; + + +// File: classgdcm_1_1DataSetHelper.xml +%typemap("csclassmodifiers") gdcm::DataSetHelper " /** DataSetHelper +(internal class, not intended for user level). + +C++ includes: gdcmDataSetHelper.h */ public class"; + + +// File: classgdcm_1_1Decoder.xml +%typemap("csclassmodifiers") gdcm::Decoder " /** Decoder. + +C++ includes: gdcmDecoder.h */ public class"; + +%csmethodmodifiers gdcm::Decoder::CanDecode " /** virtual bool +gdcm::Decoder::CanDecode(TransferSyntax const &) const =0 + +Return whether this decoder support this transfer syntax (can decode +it). + +*/ public"; + +%csmethodmodifiers gdcm::Decoder::Decode " /** virtual bool +gdcm::Decoder::Decode(DataElement const &is, DataElement &os) + +Decode. + +*/ public"; + +%csmethodmodifiers gdcm::Decoder::~Decoder " /** virtual +gdcm::Decoder::~Decoder() */ public"; + + +// File: classgdcm_1_1DefinedTerms.xml +%typemap("csclassmodifiers") gdcm::DefinedTerms " /** Defined Terms +are used when the specified explicit Values may be extended by +implementors to include additional new Values. These new Values shall +be specified in the Conformance Statement (see PS 3.2) and shall not +have the same meaning as currently defined Values in this standard. A +Data Element with Defined Terms that does not contain a Value +equivalent to one of the Values currently specified in this standard +shall not be considered to have an invalid value. Note: Interpretation +Type ID (4008,0210) is an example of a Data Element having Defined +Terms. It is defined to have a Value that may be one of the set of +standard Values; REPORT or AMENDMENT (see PS 3.3). Because this Data +Element has Defined Terms other Interpretation Type IDs may be defined +by the implementor. + +C++ includes: gdcmDefinedTerms.h */ public class"; + +%csmethodmodifiers gdcm::DefinedTerms::DefinedTerms " /** +gdcm::DefinedTerms::DefinedTerms() */ public"; + + +// File: classgdcm_1_1Defs.xml +%typemap("csclassmodifiers") gdcm::Defs " /** FIXME I do not like the +name 'Defs'. + +bla + +C++ includes: gdcmDefs.h */ public class"; + +%csmethodmodifiers gdcm::Defs::Defs " /** gdcm::Defs::Defs() */ +public"; + +%csmethodmodifiers gdcm::Defs::GetIODs " /** IODs& +gdcm::Defs::GetIODs() */ public"; + +%csmethodmodifiers gdcm::Defs::GetIODs " /** const IODs& +gdcm::Defs::GetIODs() const */ public"; + +%csmethodmodifiers gdcm::Defs::GetMacros " /** Macros& +gdcm::Defs::GetMacros() */ public"; + +%csmethodmodifiers gdcm::Defs::GetMacros " /** const Macros& +gdcm::Defs::GetMacros() const */ public"; + +%csmethodmodifiers gdcm::Defs::GetModules " /** Modules& +gdcm::Defs::GetModules() */ public"; + +%csmethodmodifiers gdcm::Defs::GetModules " /** const Modules& +gdcm::Defs::GetModules() const */ public"; + +%csmethodmodifiers gdcm::Defs::GetTypeFromTag " /** Type +gdcm::Defs::GetTypeFromTag(const File &file, const Tag &tag) const */ +public"; + +%csmethodmodifiers gdcm::Defs::IsEmpty " /** bool +gdcm::Defs::IsEmpty() const */ public"; + +%csmethodmodifiers gdcm::Defs::Verify " /** bool +gdcm::Defs::Verify(const DataSet &ds) const */ public"; + +%csmethodmodifiers gdcm::Defs::Verify " /** bool +gdcm::Defs::Verify(const File &file) const */ public"; + +%csmethodmodifiers gdcm::Defs::~Defs " /** gdcm::Defs::~Defs() */ +public"; + + +// File: classgdcm_1_1DeltaEncodingCodec.xml +%typemap("csclassmodifiers") gdcm::DeltaEncodingCodec " /** +DeltaEncodingCodec compression used by some private vendor. + +C++ includes: gdcmDeltaEncodingCodec.h */ public class"; + +%csmethodmodifiers gdcm::DeltaEncodingCodec::CanDecode " /** bool +gdcm::DeltaEncodingCodec::CanDecode(TransferSyntax const &ts) */ +public"; + +%csmethodmodifiers gdcm::DeltaEncodingCodec::Decode " /** bool +gdcm::DeltaEncodingCodec::Decode(DataElement const &is, DataElement +&os) + +Decode. + +*/ public"; + +%csmethodmodifiers gdcm::DeltaEncodingCodec::DeltaEncodingCodec " /** +gdcm::DeltaEncodingCodec::DeltaEncodingCodec() */ public"; + +%csmethodmodifiers gdcm::DeltaEncodingCodec::~DeltaEncodingCodec " +/** gdcm::DeltaEncodingCodec::~DeltaEncodingCodec() */ public"; + + +// File: classstd_1_1deque.xml +%typemap("csclassmodifiers") std::deque " /** STL class. + +*/ public class"; + + +// File: classstd_1_1deque_1_1const__iterator.xml +%typemap("csclassmodifiers") std::deque::const_iterator " /** STL +iterator class. + +*/ public class"; + + +// File: classstd_1_1deque_1_1const__reverse__iterator.xml +%typemap("csclassmodifiers") std::deque::const_reverse_iterator " /** +STL iterator class. + +*/ public class"; + + +// File: classstd_1_1deque_1_1iterator.xml +%typemap("csclassmodifiers") std::deque::iterator " /** STL iterator +class. + +*/ public class"; + + +// File: classstd_1_1deque_1_1reverse__iterator.xml +%typemap("csclassmodifiers") std::deque::reverse_iterator " /** STL +iterator class. + +*/ public class"; + + +// File: classgdcm_1_1DICOMDIR.xml +%typemap("csclassmodifiers") gdcm::DICOMDIR " /** DICOMDIR. + +C++ includes: gdcmDICOMDIR.h */ public class"; + +%csmethodmodifiers gdcm::DICOMDIR::DICOMDIR " /** +gdcm::DICOMDIR::DICOMDIR(const FileSet &fs) */ public"; + +%csmethodmodifiers gdcm::DICOMDIR::DICOMDIR " /** +gdcm::DICOMDIR::DICOMDIR() */ public"; + + +// File: classgdcm_1_1Dict.xml +%typemap("csclassmodifiers") gdcm::Dict " /** Class to represent a map +of DictEntry. + +bla TODO FIXME: For Element == 0x0 need to return Name = Group Length +ValueRepresentation = UL ValueMultiplicity = 1 + +C++ includes: gdcmDict.h */ public class"; + +%csmethodmodifiers gdcm::Dict::AddDictEntry " /** void +gdcm::Dict::AddDictEntry(const Tag &tag, const DictEntry &de) */ +public"; + +%csmethodmodifiers gdcm::Dict::Begin " /** ConstIterator +gdcm::Dict::Begin() const */ public"; + +%csmethodmodifiers gdcm::Dict::Dict " /** gdcm::Dict::Dict() */ +public"; + +%csmethodmodifiers gdcm::Dict::End " /** ConstIterator +gdcm::Dict::End() const */ public"; + +%csmethodmodifiers gdcm::Dict::GetDictEntry " /** const DictEntry& +gdcm::Dict::GetDictEntry(const Tag &tag) const */ public"; + +%csmethodmodifiers gdcm::Dict::GetDictEntryByName " /** const +DictEntry& gdcm::Dict::GetDictEntryByName(const char *name, Tag &tag) +const + +Inefficient way of looking up tag by name. Technically DICOM does not +garantee uniqueness (and Curve / Overlay are there to prove it). But +most of the time name is in fact uniq and can be uniquely link to a +tag + +*/ public"; + +%csmethodmodifiers gdcm::Dict::IsEmpty " /** bool +gdcm::Dict::IsEmpty() const */ public"; + + +// File: classgdcm_1_1DictConverter.xml +%typemap("csclassmodifiers") gdcm::DictConverter " /** Class to +convert a .dic file into something else: CXX code : embeded dict into +shared lib (DICT_DEFAULT) + +Debug mode (DICT_DEBUG) + +XML dict (DICT_XML). + +C++ includes: gdcmDictConverter.h */ public class"; + +%csmethodmodifiers gdcm::DictConverter::Convert " /** void +gdcm::DictConverter::Convert() */ public"; + +%csmethodmodifiers gdcm::DictConverter::DictConverter " /** +gdcm::DictConverter::DictConverter() */ public"; + +%csmethodmodifiers gdcm::DictConverter::GetDictName " /** const +std::string& gdcm::DictConverter::GetDictName() const */ public"; + +%csmethodmodifiers gdcm::DictConverter::GetInputFilename " /** const +std::string& gdcm::DictConverter::GetInputFilename() const */ +public"; + +%csmethodmodifiers gdcm::DictConverter::GetOutputFilename " /** const +std::string& gdcm::DictConverter::GetOutputFilename() const */ +public"; + +%csmethodmodifiers gdcm::DictConverter::GetOutputType " /** int +gdcm::DictConverter::GetOutputType() const */ public"; + +%csmethodmodifiers gdcm::DictConverter::SetDictName " /** void +gdcm::DictConverter::SetDictName(const char *name) */ public"; + +%csmethodmodifiers gdcm::DictConverter::SetInputFileName " /** void +gdcm::DictConverter::SetInputFileName(const char *filename) */ +public"; + +%csmethodmodifiers gdcm::DictConverter::SetOutputFileName " /** void +gdcm::DictConverter::SetOutputFileName(const char *filename) */ +public"; + +%csmethodmodifiers gdcm::DictConverter::SetOutputType " /** void +gdcm::DictConverter::SetOutputType(int type) */ public"; + +%csmethodmodifiers gdcm::DictConverter::~DictConverter " /** +gdcm::DictConverter::~DictConverter() */ public"; + + +// File: classgdcm_1_1DictEntry.xml +%typemap("csclassmodifiers") gdcm::DictEntry " /** Class to represent +an Entry in the Dict Does not really exist within the DICOM +definition, just a way to minimize storage and have a mapping from +gdcm::Tag to the needed information. + +bla TODO FIXME: Need a PublicDictEntry...indeed DictEntry has a notion +of retired which does not exist in PrivateDictEntry... + +See: gdcm::Dict + +C++ includes: gdcmDictEntry.h */ public class"; + +%csmethodmodifiers gdcm::DictEntry::DictEntry " /** +gdcm::DictEntry::DictEntry(const char *name=\"\", VR const +&vr=VR::INVALID, VM const &vm=VM::VM0, bool ret=false) */ public"; + +%csmethodmodifiers gdcm::DictEntry::GetKeyword " /** const char* +gdcm::DictEntry::GetKeyword() const + +same as GetName but without spaces + +*/ public"; + +%csmethodmodifiers gdcm::DictEntry::GetName " /** const char* +gdcm::DictEntry::GetName() const + +Set/Get Name. + +*/ public"; + +%csmethodmodifiers gdcm::DictEntry::GetRetired " /** bool +gdcm::DictEntry::GetRetired() const + +Set/Get Retired flag. + +*/ public"; + +%csmethodmodifiers gdcm::DictEntry::GetVM " /** const VM& +gdcm::DictEntry::GetVM() const + +Set/Get VM. + +*/ public"; + +%csmethodmodifiers gdcm::DictEntry::GetVR " /** const VR& +gdcm::DictEntry::GetVR() const + +Set/Get VR. + +*/ public"; + +%csmethodmodifiers gdcm::DictEntry::IsUnique " /** bool +gdcm::DictEntry::IsUnique() const + +Return whether the name of the DataElement can be considered to be +unique. As of 2008 all elements name were unique (except the +expclitely 'XX' ones) + +*/ public"; + +%csmethodmodifiers gdcm::DictEntry::SetElementXX " /** void +gdcm::DictEntry::SetElementXX(bool v) + +Set whether element is shared in multiple elements (Source Image IDs +typically). + +*/ public"; + +%csmethodmodifiers gdcm::DictEntry::SetGroupXX " /** void +gdcm::DictEntry::SetGroupXX(bool v) + +Set whether element is shared in multiple groups (Curve/Overlay +typically). + +*/ public"; + +%csmethodmodifiers gdcm::DictEntry::SetName " /** void +gdcm::DictEntry::SetName(const char *name) */ public"; + +%csmethodmodifiers gdcm::DictEntry::SetRetired " /** void +gdcm::DictEntry::SetRetired(bool retired) */ public"; + +%csmethodmodifiers gdcm::DictEntry::SetVM " /** void +gdcm::DictEntry::SetVM(VM const &vm) */ public"; + +%csmethodmodifiers gdcm::DictEntry::SetVR " /** void +gdcm::DictEntry::SetVR(const VR &vr) */ public"; + + +// File: classgdcm_1_1DictPrinter.xml +%typemap("csclassmodifiers") gdcm::DictPrinter " /** DictPrinter +class. + +C++ includes: gdcmDictPrinter.h */ public class"; + +%csmethodmodifiers gdcm::DictPrinter::DictPrinter " /** +gdcm::DictPrinter::DictPrinter() */ public"; + +%csmethodmodifiers gdcm::DictPrinter::Print " /** void +gdcm::DictPrinter::Print(std::ostream &os) */ public"; + +%csmethodmodifiers gdcm::DictPrinter::~DictPrinter " /** +gdcm::DictPrinter::~DictPrinter() */ public"; + + +// File: classgdcm_1_1Dicts.xml +%typemap("csclassmodifiers") gdcm::Dicts " /** Class to manipulate the +sum of knowledge (all the dict user load). + +bla + +C++ includes: gdcmDicts.h */ public class"; + +%csmethodmodifiers gdcm::Dicts::Dicts " /** gdcm::Dicts::Dicts() */ +public"; + +%csmethodmodifiers gdcm::Dicts::GetCSAHeaderDict " /** const +CSAHeaderDict& gdcm::Dicts::GetCSAHeaderDict() const */ public"; + +%csmethodmodifiers gdcm::Dicts::GetDictEntry " /** const DictEntry& +gdcm::Dicts::GetDictEntry(const Tag &tag, const char *owner=NULL) +const */ public"; + +%csmethodmodifiers gdcm::Dicts::GetPrivateDict " /** const +PrivateDict& gdcm::Dicts::GetPrivateDict() const */ public"; + +%csmethodmodifiers gdcm::Dicts::GetPublicDict " /** const Dict& +gdcm::Dicts::GetPublicDict() const */ public"; + +%csmethodmodifiers gdcm::Dicts::IsEmpty " /** bool +gdcm::Dicts::IsEmpty() const */ public"; + +%csmethodmodifiers gdcm::Dicts::~Dicts " /** gdcm::Dicts::~Dicts() +*/ public"; + + +// File: classgdcm_1_1DirectionCosines.xml +%typemap("csclassmodifiers") gdcm::DirectionCosines " /** class to +handle DirectionCosines + +C++ includes: gdcmDirectionCosines.h */ public class"; + +%csmethodmodifiers gdcm::DirectionCosines::ComputeDistAlongNormal " +/** double gdcm::DirectionCosines::ComputeDistAlongNormal(const double +ipp[3]) const */ public"; + +%csmethodmodifiers gdcm::DirectionCosines::Cross " /** void +gdcm::DirectionCosines::Cross(double z[3]) const + +Compute Cross product. + +*/ public"; + +%csmethodmodifiers gdcm::DirectionCosines::CrossDot " /** double +gdcm::DirectionCosines::CrossDot(DirectionCosines const &dc) const */ +public"; + +%csmethodmodifiers gdcm::DirectionCosines::DirectionCosines " /** +gdcm::DirectionCosines::DirectionCosines(const double dircos[6]) */ +public"; + +%csmethodmodifiers gdcm::DirectionCosines::DirectionCosines " /** +gdcm::DirectionCosines::DirectionCosines() */ public"; + +%csmethodmodifiers gdcm::DirectionCosines::Dot " /** double +gdcm::DirectionCosines::Dot() const + +Compute Dot. + +*/ public"; + +%csmethodmodifiers gdcm::DirectionCosines::IsValid " /** bool +gdcm::DirectionCosines::IsValid() const + +Return whether or not this is a valid direction cosines. + +*/ public"; + +%csmethodmodifiers gdcm::DirectionCosines::Normalize " /** void +gdcm::DirectionCosines::Normalize() + +Normalize in-place. + +*/ public"; + +%csmethodmodifiers gdcm::DirectionCosines::Print " /** void +gdcm::DirectionCosines::Print(std::ostream &) const + +Print. + +*/ public"; + +%csmethodmodifiers gdcm::DirectionCosines::SetFromString " /** bool +gdcm::DirectionCosines::SetFromString(const char *str) */ public"; + +%csmethodmodifiers gdcm::DirectionCosines::~DirectionCosines " /** +gdcm::DirectionCosines::~DirectionCosines() */ public"; + + +// File: classgdcm_1_1Directory.xml +%typemap("csclassmodifiers") gdcm::Directory " /** Class for +manipulation directories. + +This implementation provide a cross platform implementation for +manipulating directores: basically traversing directories and +harvesting files + +will not take into account unix type hidden file recursive option will +not look into UNIX type hidden directory (those starting with a '.') + +Since python or C# provide there own equivalent implementation, in +which case gdcm::Directory does not make much sense. + +C++ includes: gdcmDirectory.h */ public class"; + +%csmethodmodifiers gdcm::Directory::Directory " /** +gdcm::Directory::Directory() */ public"; + +%csmethodmodifiers gdcm::Directory::GetDirectories " /** +FilenamesType const& gdcm::Directory::GetDirectories() const + +Return the Directories traversed. + +*/ public"; + +%csmethodmodifiers gdcm::Directory::GetFilenames " /** FilenamesType +const& gdcm::Directory::GetFilenames() const + +Set/Get the file names within the directory. + +*/ public"; + +%csmethodmodifiers gdcm::Directory::GetToplevel " /** FilenameType +const& gdcm::Directory::GetToplevel() const + +Get the name of the toplevel directory. + +*/ public"; + +%csmethodmodifiers gdcm::Directory::Load " /** unsigned int +gdcm::Directory::Load(FilenameType const &name, bool recursive=false) + +construct a list of filenames and subdirectory beneath directory: name +WARNING: : hidden file and hidden directory are not loaded. + +*/ public"; + +%csmethodmodifiers gdcm::Directory::Print " /** void +gdcm::Directory::Print(std::ostream &os=std::cout) + +Print. + +*/ public"; + +%csmethodmodifiers gdcm::Directory::~Directory " /** +gdcm::Directory::~Directory() */ public"; + + +// File: classstd_1_1domain__error.xml +%typemap("csclassmodifiers") std::domain_error " /** STL class. + +*/ public class"; + + +// File: classgdcm_1_1DummyValueGenerator.xml +%typemap("csclassmodifiers") gdcm::DummyValueGenerator " /** Class for +generating dummy value. + +bla + +C++ includes: gdcmDummyValueGenerator.h */ public class"; + + +// File: classgdcm_1_1Dumper.xml +%typemap("csclassmodifiers") gdcm::Dumper " /** Codec class. + +Use it to simply dump value read from the file. No interpretation is +done. But it is real fast ! Almost no overhead + +C++ includes: gdcmDumper.h */ public class"; + +%csmethodmodifiers gdcm::Dumper::Dumper " /** gdcm::Dumper::Dumper() +*/ public"; + +%csmethodmodifiers gdcm::Dumper::~Dumper " /** +gdcm::Dumper::~Dumper() */ public"; + + +// File: classgdcm_1_1Element.xml +%typemap("csclassmodifiers") gdcm::Element " /** Element class. + +TODO + +C++ includes: gdcmElement.h */ public class"; + +%csmethodmodifiers gdcm::Element::GetLength " /** unsigned long +gdcm::Element< TVR, TVM >::GetLength() const */ public"; + +%csmethodmodifiers gdcm::Element::GetValue " /** VRToType::Type& +gdcm::Element< TVR, TVM >::GetValue(unsigned int idx=0) */ public"; + +%csmethodmodifiers gdcm::Element::GetValue " /** const +VRToType::Type& gdcm::Element< TVR, TVM >::GetValue(unsigned int +idx=0) const */ public"; + +%csmethodmodifiers gdcm::Element::GetValues " /** const +VRToType::Type* gdcm::Element< TVR, TVM >::GetValues() const */ +public"; + +%csmethodmodifiers gdcm::Element::Print " /** void gdcm::Element< +TVR, TVM >::Print(std::ostream &_os) const */ public"; + +%csmethodmodifiers gdcm::Element::Read " /** void gdcm::Element< TVR, +TVM >::Read(std::istream &_is) */ public"; + +%csmethodmodifiers gdcm::Element::Set " /** void gdcm::Element< TVR, +TVM >::Set(Value const &v) */ public"; + +%csmethodmodifiers gdcm::Element::SetFromDataElement " /** void +gdcm::Element< TVR, TVM >::SetFromDataElement(DataElement const &de) +*/ public"; + +%csmethodmodifiers gdcm::Element::SetValue " /** void gdcm::Element< +TVR, TVM >::SetValue(typename VRToType< TVR >::Type v, unsigned int +idx=0) */ public"; + +%csmethodmodifiers gdcm::Element::Write " /** void gdcm::Element< +TVR, TVM >::Write(std::ostream &_os) const */ public"; + + +// File: classgdcm_1_1Element_3_01TVR_00_01VM_1_1VM1__n_01_4.xml +%typemap("csclassmodifiers") gdcm::Element< TVR, VM::VM1_n > " /**C++ +includes: gdcmElement.h */ public class"; + +%csmethodmodifiers gdcm::Element< TVR, VM::VM1_n >::Element " /** +gdcm::Element< TVR, VM::VM1_n >::Element(const Element &_val) */ +public"; + +%csmethodmodifiers gdcm::Element< TVR, VM::VM1_n >::Element " /** +gdcm::Element< TVR, VM::VM1_n >::Element() */ public"; + +%csmethodmodifiers gdcm::Element< TVR, VM::VM1_n >::GetAsDataElement +" /** DataElement gdcm::Element< TVR, VM::VM1_n >::GetAsDataElement() +const */ public"; + +%csmethodmodifiers gdcm::Element< TVR, VM::VM1_n >::GetLength " /** +unsigned long gdcm::Element< TVR, VM::VM1_n >::GetLength() const */ +public"; + +%csmethodmodifiers gdcm::Element< TVR, VM::VM1_n >::GetValue " /** +VRToType::Type& gdcm::Element< TVR, VM::VM1_n +>::GetValue(unsigned int idx=0) */ public"; + +%csmethodmodifiers gdcm::Element< TVR, VM::VM1_n >::GetValue " /** +const VRToType::Type& gdcm::Element< TVR, VM::VM1_n +>::GetValue(unsigned int idx=0) const */ public"; + +%csmethodmodifiers gdcm::Element< TVR, VM::VM1_n >::Print " /** void +gdcm::Element< TVR, VM::VM1_n >::Print(std::ostream &_os) const */ +public"; + +%csmethodmodifiers gdcm::Element< TVR, VM::VM1_n >::Read " /** void +gdcm::Element< TVR, VM::VM1_n >::Read(std::istream &_is) */ public"; + +%csmethodmodifiers gdcm::Element< TVR, VM::VM1_n >::Set " /** void +gdcm::Element< TVR, VM::VM1_n >::Set(Value const &v) */ public"; + +%csmethodmodifiers gdcm::Element< TVR, VM::VM1_n >::SetArray " /** +void gdcm::Element< TVR, VM::VM1_n >::SetArray(const Type *array, +unsigned long len, bool save=false) */ public"; + +%csmethodmodifiers gdcm::Element< TVR, VM::VM1_n >::SetLength " /** +void gdcm::Element< TVR, VM::VM1_n >::SetLength(unsigned long len) */ +public"; + +%csmethodmodifiers gdcm::Element< TVR, VM::VM1_n >::SetValue " /** +void gdcm::Element< TVR, VM::VM1_n >::SetValue(typename VRToType< TVR +>::Type v, unsigned int idx=0) */ public"; + +%csmethodmodifiers gdcm::Element< TVR, VM::VM1_n >::Write " /** void +gdcm::Element< TVR, VM::VM1_n >::Write(std::ostream &_os) const */ +public"; + +%csmethodmodifiers gdcm::Element< TVR, VM::VM1_n >::WriteASCII " /** +void gdcm::Element< TVR, VM::VM1_n >::WriteASCII(std::ostream &os) +const */ public"; + +%csmethodmodifiers gdcm::Element< TVR, VM::VM1_n >::~Element " /** +gdcm::Element< TVR, VM::VM1_n >::~Element() */ public"; + + +// File: classgdcm_1_1Element_3_01TVR_00_01VM_1_1VM2__2n_01_4.xml +%typemap("csclassmodifiers") gdcm::Element< TVR, VM::VM2_2n > " /**C++ +includes: gdcmElement.h */ public class"; + +%csmethodmodifiers gdcm::Element< TVR, VM::VM2_2n >::SetLength " /** +void gdcm::Element< TVR, VM::VM2_2n >::SetLength(int len) */ public"; + + +// File: classgdcm_1_1Element_3_01TVR_00_01VM_1_1VM2__n_01_4.xml +%typemap("csclassmodifiers") gdcm::Element< TVR, VM::VM2_n > " /**C++ +includes: gdcmElement.h */ public class"; + +%csmethodmodifiers gdcm::Element< TVR, VM::VM2_n >::SetLength " /** +void gdcm::Element< TVR, VM::VM2_n >::SetLength(int len) */ public"; + + +// File: classgdcm_1_1Element_3_01TVR_00_01VM_1_1VM3__3n_01_4.xml +%typemap("csclassmodifiers") gdcm::Element< TVR, VM::VM3_3n > " /**C++ +includes: gdcmElement.h */ public class"; + +%csmethodmodifiers gdcm::Element< TVR, VM::VM3_3n >::SetLength " /** +void gdcm::Element< TVR, VM::VM3_3n >::SetLength(int len) */ public"; + + +// File: classgdcm_1_1Element_3_01TVR_00_01VM_1_1VM3__n_01_4.xml +%typemap("csclassmodifiers") gdcm::Element< TVR, VM::VM3_n > " /**C++ +includes: gdcmElement.h */ public class"; + +%csmethodmodifiers gdcm::Element< TVR, VM::VM3_n >::SetLength " /** +void gdcm::Element< TVR, VM::VM3_n >::SetLength(int len) */ public"; + + +// File: classgdcm_1_1Element_3_01VR_1_1AS_00_01VM_1_1VM5_01_4.xml +%typemap("csclassmodifiers") gdcm::Element< VR::AS, VM::VM5 > " /**C++ +includes: gdcmElement.h */ public class"; + +%csmethodmodifiers gdcm::Element< VR::AS, VM::VM5 >::GetLength " /** +unsigned long gdcm::Element< VR::AS, VM::VM5 >::GetLength() const */ +public"; + +%csmethodmodifiers gdcm::Element< VR::AS, VM::VM5 >::Print " /** void +gdcm::Element< VR::AS, VM::VM5 >::Print(std::ostream &_os) const */ +public"; + + +// File: classgdcm_1_1Element_3_01VR_1_1OB_00_01VM_1_1VM1_01_4.xml +%typemap("csclassmodifiers") gdcm::Element< VR::OB, VM::VM1 > " /**C++ +includes: gdcmElement.h */ public class"; + + +// File: classgdcm_1_1Element_3_01VR_1_1OW_00_01VM_1_1VM1_01_4.xml +%typemap("csclassmodifiers") gdcm::Element< VR::OW, VM::VM1 > " /**C++ +includes: gdcmElement.h */ public class"; + + +// File: classgdcm_1_1EncapsulatedDocument.xml +%typemap("csclassmodifiers") gdcm::EncapsulatedDocument " /** +EncapsulatedDocument. + +C++ includes: gdcmEncapsulatedDocument.h */ public class"; + +%csmethodmodifiers gdcm::EncapsulatedDocument::EncapsulatedDocument " +/** gdcm::EncapsulatedDocument::EncapsulatedDocument() */ public"; + + +// File: classgdcm_1_1EncodingImplementation_3_01VR_1_1VRASCII_01_4.xml +%typemap("csclassmodifiers") gdcm::EncodingImplementation< VR::VRASCII +> " /**C++ includes: gdcmElement.h */ public class"; + +%csmethodmodifiers gdcm::EncodingImplementation< VR::VRASCII >::Write +" /** void gdcm::EncodingImplementation< VR::VRASCII >::Write(const +double *data, unsigned long length, std::ostream &_os) */ public"; + +%csmethodmodifiers gdcm::EncodingImplementation< VR::VRASCII >::Write +" /** void gdcm::EncodingImplementation< VR::VRASCII >::Write(const +float *data, unsigned long length, std::ostream &_os) */ public"; + + +// File: classgdcm_1_1EncodingImplementation_3_01VR_1_1VRBINARY_01_4.xml +%typemap("csclassmodifiers") gdcm::EncodingImplementation< +VR::VRBINARY > " /**C++ includes: gdcmElement.h */ public class"; + + +// File: classgdcm_1_1EnumeratedValues.xml +%typemap("csclassmodifiers") gdcm::EnumeratedValues " /** Enumerated +Values are used when the specified explicit Values are the only Values +allowed for a Data Element. A Data Element with Enumerated Values that +does not have a Value equivalent to one of the Values specified in +this standard has an invalid value within the scope of a specific +Information Object/SOP Class definition. Note: 1. Patient Sex (0010, +0040) is an example of a Data Element having Enumerated Values. It is +defined to have a Value that is either \"M, \"F, or \"O (see PS 3.3). +No other Value shall be given to this Data Element. 2. Future +modifications of this standard may add to the set of allowed values +for Data Elements with Enumerated Values. Such additions by themselves +may or may not require a change in SOP Class UIDs, depending on the +semantics of the Data Element. + +C++ includes: gdcmEnumeratedValues.h */ public class"; + +%csmethodmodifiers gdcm::EnumeratedValues::EnumeratedValues " /** +gdcm::EnumeratedValues::EnumeratedValues() */ public"; + + +// File: classstd_1_1exception.xml +%typemap("csclassmodifiers") std::exception " /** STL class. + +*/ public class"; + + +// File: classgdcm_1_1Exception.xml +%typemap("csclassmodifiers") gdcm::Exception " /** Exception. + +Standard exception handling object. + +C++ includes: gdcmException.h */ public class"; + +%csmethodmodifiers gdcm::Exception::Exception " /** +gdcm::Exception::Exception(const char *desc=\"None\", const char +*file=__FILE__, unsigned int lineNumber=__LINE__, const char +*loc=\"\") */ public"; + +%csmethodmodifiers gdcm::Exception::GetDescription " /** const char* +gdcm::Exception::GetDescription() const + +Return the Description. + +*/ public"; + +%csmethodmodifiers gdcm::Exception::what " /** const char* +gdcm::Exception::what() const throw () what implementation + +*/ public"; + +%csmethodmodifiers gdcm::Exception::~Exception " /** virtual +gdcm::Exception::~Exception() throw () */ public"; + + +// File: classgdcm_1_1ExplicitDataElement.xml +%typemap("csclassmodifiers") gdcm::ExplicitDataElement " /** Class to +read/write a DataElement as Explicit Data Element. + +bla + +C++ includes: gdcmExplicitDataElement.h */ public class"; + +%csmethodmodifiers gdcm::ExplicitDataElement::GetLength " /** VL +gdcm::ExplicitDataElement::GetLength() const */ public"; + +%csmethodmodifiers gdcm::ExplicitDataElement::Read " /** +std::istream& gdcm::ExplicitDataElement::Read(std::istream &is) */ +public"; + +%csmethodmodifiers gdcm::ExplicitDataElement::ReadWithLength " /** +std::istream& gdcm::ExplicitDataElement::ReadWithLength(std::istream +&is, VL &length) */ public"; + +%csmethodmodifiers gdcm::ExplicitDataElement::Write " /** const +std::ostream& gdcm::ExplicitDataElement::Write(std::ostream &os) const +*/ public"; + + +// File: classgdcm_1_1ExplicitImplicitDataElement.xml +%typemap("csclassmodifiers") gdcm::ExplicitImplicitDataElement " /** +Class to read/write a DataElement as ExplicitImplicit Data Element. + +This only happen for some Philips images Should I derive from +ExplicitDataElement instead ? This is the class that is the closest +the GDCM1.x parser. At each element we try first to read it as +explicit, if this fails, then we try again as an implicit element. + +C++ includes: gdcmExplicitImplicitDataElement.h */ public class"; + +%csmethodmodifiers gdcm::ExplicitImplicitDataElement::GetLength " /** +VL gdcm::ExplicitImplicitDataElement::GetLength() const */ public"; + +%csmethodmodifiers gdcm::ExplicitImplicitDataElement::Read " /** +std::istream& gdcm::ExplicitImplicitDataElement::Read(std::istream +&is) */ public"; + +%csmethodmodifiers gdcm::ExplicitImplicitDataElement::ReadWithLength +" /** std::istream& +gdcm::ExplicitImplicitDataElement::ReadWithLength(std::istream &is, VL +&length) */ public"; + + +// File: classgdcm_1_1Fiducials.xml +%typemap("csclassmodifiers") gdcm::Fiducials " /** Fiducials. + +C++ includes: gdcmFiducials.h */ public class"; + +%csmethodmodifiers gdcm::Fiducials::Fiducials " /** +gdcm::Fiducials::Fiducials() */ public"; + + +// File: classgdcm_1_1File.xml +%typemap("csclassmodifiers") gdcm::File " /** a DICOM File See PS 3.10 +File: A File is an ordered string of zero or more bytes, where the +first byte is at the beginning of the file and the last byte at the +end of the File. Files are identified by a unique File ID and may by +written, read and/or deleted. + +C++ includes: gdcmFile.h */ public class"; + +%csmethodmodifiers gdcm::File::File " /** gdcm::File::File() */ +public"; + +%csmethodmodifiers gdcm::File::GetDataSet " /** DataSet& +gdcm::File::GetDataSet() */ public"; + +%csmethodmodifiers gdcm::File::GetDataSet " /** const DataSet& +gdcm::File::GetDataSet() const */ public"; + +%csmethodmodifiers gdcm::File::GetHeader " /** FileMetaInformation& +gdcm::File::GetHeader() */ public"; + +%csmethodmodifiers gdcm::File::GetHeader " /** const +FileMetaInformation& gdcm::File::GetHeader() const */ public"; + +%csmethodmodifiers gdcm::File::Read " /** std::istream& +gdcm::File::Read(std::istream &is) */ public"; + +%csmethodmodifiers gdcm::File::SetDataSet " /** void +gdcm::File::SetDataSet(const DataSet &ds) */ public"; + +%csmethodmodifiers gdcm::File::SetHeader " /** void +gdcm::File::SetHeader(const FileMetaInformation &fmi) */ public"; + +%csmethodmodifiers gdcm::File::Write " /** std::ostream const& +gdcm::File::Write(std::ostream &os) const */ public"; + +%csmethodmodifiers gdcm::File::~File " /** gdcm::File::~File() */ +public"; + + +// File: classgdcm_1_1FileExplicitFilter.xml +%typemap("csclassmodifiers") gdcm::FileExplicitFilter " /**C++ +includes: gdcmFileExplicitFilter.h */ public class"; + +%csmethodmodifiers gdcm::FileExplicitFilter::Change " /** bool +gdcm::FileExplicitFilter::Change() + +Set FMI Transfer Syntax. + +Change + +*/ public"; + +%csmethodmodifiers gdcm::FileExplicitFilter::FileExplicitFilter " /** +gdcm::FileExplicitFilter::FileExplicitFilter() */ public"; + +%csmethodmodifiers gdcm::FileExplicitFilter::GetFile " /** File& +gdcm::FileExplicitFilter::GetFile() */ public"; + +%csmethodmodifiers gdcm::FileExplicitFilter::SetChangePrivateTags " +/** void gdcm::FileExplicitFilter::SetChangePrivateTags(bool b) + +Decide whether or not to VR'ify private tags. + +*/ public"; + +%csmethodmodifiers gdcm::FileExplicitFilter::SetFile " /** void +gdcm::FileExplicitFilter::SetFile(const File &f) + +Set/Get File. + +*/ public"; + +%csmethodmodifiers gdcm::FileExplicitFilter::SetRecomputeItemLength " +/** void gdcm::FileExplicitFilter::SetRecomputeItemLength(bool b) + +By default set Sequence & Item length to Undefined to avoid +recomputing length:. + +*/ public"; + +%csmethodmodifiers +gdcm::FileExplicitFilter::SetRecomputeSequenceLength " /** void +gdcm::FileExplicitFilter::SetRecomputeSequenceLength(bool b) */ +public"; + +%csmethodmodifiers gdcm::FileExplicitFilter::SetUseVRUN " /** void +gdcm::FileExplicitFilter::SetUseVRUN(bool b) + +When VR=16bits in explicit but Implicit has a 32bits length, use +VR=UN. + +*/ public"; + +%csmethodmodifiers gdcm::FileExplicitFilter::~FileExplicitFilter " +/** gdcm::FileExplicitFilter::~FileExplicitFilter() */ public"; + + +// File: classgdcm_1_1FileMetaInformation.xml +%typemap("csclassmodifiers") gdcm::FileMetaInformation " /** Class to +represent a File Meta Information. + +FileMetaInformation is a Explicit Structured Set. Whenever the file +contains an ImplicitDataElement DataSet, a conversion will take place. +Todo If user adds an element with group != 0x0002 it will be +written... Definition: The File Meta Information includes identifying +information on the encapsulated Data Set. This header consists of a +128 byte File Preamble, followed by a 4 byte DICOM prefix, followed by +the File Meta Elements shown in Table 7.1-1. This header shall be +present in every DICOM file. + +C++ includes: gdcmFileMetaInformation.h */ public class"; + +%csmethodmodifiers gdcm::FileMetaInformation::FileMetaInformation " +/** gdcm::FileMetaInformation::FileMetaInformation(FileMetaInformation +const &fmi) */ public"; + +%csmethodmodifiers gdcm::FileMetaInformation::FileMetaInformation " +/** gdcm::FileMetaInformation::FileMetaInformation() */ public"; + +%csmethodmodifiers gdcm::FileMetaInformation::FillFromDataSet " /** +void gdcm::FileMetaInformation::FillFromDataSet(DataSet const &ds) + +Construct a FileMetaInformation from an already existing DataSet:. + +*/ public"; + +%csmethodmodifiers +gdcm::FileMetaInformation::GetDataSetTransferSyntax " /** const +TransferSyntax& gdcm::FileMetaInformation::GetDataSetTransferSyntax() +const */ public"; + +%csmethodmodifiers gdcm::FileMetaInformation::GetMediaStorage " /** +MediaStorage gdcm::FileMetaInformation::GetMediaStorage() const */ +public"; + +%csmethodmodifiers gdcm::FileMetaInformation::GetMetaInformationTS " +/** TransferSyntax::NegociatedType +gdcm::FileMetaInformation::GetMetaInformationTS() const */ public"; + +%csmethodmodifiers gdcm::FileMetaInformation::GetPreamble " /** +Preamble& gdcm::FileMetaInformation::GetPreamble() */ public"; + +%csmethodmodifiers gdcm::FileMetaInformation::GetPreamble " /** const +Preamble& gdcm::FileMetaInformation::GetPreamble() const + +Get Preamble. + +*/ public"; + +%csmethodmodifiers gdcm::FileMetaInformation::Insert " /** void +gdcm::FileMetaInformation::Insert(const DataElement &de) + +Insert a DataElement in the DataSet. WARNING: : Tag need to be >= 0x8 +to be considered valid data element + +*/ public"; + +%csmethodmodifiers gdcm::FileMetaInformation::IsValid " /** bool +gdcm::FileMetaInformation::IsValid() const */ public"; + +%csmethodmodifiers gdcm::FileMetaInformation::Read " /** +std::istream& gdcm::FileMetaInformation::Read(std::istream &is) + +Read. + +*/ public"; + +%csmethodmodifiers gdcm::FileMetaInformation::ReadCompat " /** +std::istream& gdcm::FileMetaInformation::ReadCompat(std::istream &is) +*/ public"; + +%csmethodmodifiers gdcm::FileMetaInformation::Replace " /** void +gdcm::FileMetaInformation::Replace(const DataElement &de) + +Replace a dataelement with another one. + +*/ public"; + +%csmethodmodifiers +gdcm::FileMetaInformation::SetDataSetTransferSyntax " /** void +gdcm::FileMetaInformation::SetDataSetTransferSyntax(const +TransferSyntax &ts) */ public"; + +%csmethodmodifiers gdcm::FileMetaInformation::SetPreamble " /** void +gdcm::FileMetaInformation::SetPreamble(const Preamble &p) */ public"; + +%csmethodmodifiers gdcm::FileMetaInformation::Write " /** +std::ostream& gdcm::FileMetaInformation::Write(std::ostream &os) const + +Write. + +*/ public"; + +%csmethodmodifiers gdcm::FileMetaInformation::~FileMetaInformation " +/** gdcm::FileMetaInformation::~FileMetaInformation() */ public"; + + +// File: classgdcm_1_1Filename.xml +%typemap("csclassmodifiers") gdcm::Filename " /** Class to manipulate +file name's. + +OS independant representation of a filename (to query path, name and +extension from a filename) + +C++ includes: gdcmFilename.h */ public class"; + +%csmethodmodifiers gdcm::Filename::Filename " /** +gdcm::Filename::Filename(const char *filename=\"\") */ public"; + +%csmethodmodifiers gdcm::Filename::GetExtension " /** const char* +gdcm::Filename::GetExtension() + +return only the extension part of a filename + +*/ public"; + +%csmethodmodifiers gdcm::Filename::GetFileName " /** const char* +gdcm::Filename::GetFileName() const + +Return the full filename. + +*/ public"; + +%csmethodmodifiers gdcm::Filename::GetName " /** const char* +gdcm::Filename::GetName() + +return only the name part of a filename + +*/ public"; + +%csmethodmodifiers gdcm::Filename::GetPath " /** const char* +gdcm::Filename::GetPath() + +Return only the path component of a filename. + +*/ public"; + +%csmethodmodifiers gdcm::Filename::IsEmpty " /** bool +gdcm::Filename::IsEmpty() const + +return whether the filename is empty + +*/ public"; + +%csmethodmodifiers gdcm::Filename::IsIdentical " /** bool +gdcm::Filename::IsIdentical(Filename const &fn) const */ public"; + +%csmethodmodifiers gdcm::Filename::ToUnixSlashes " /** const char* +gdcm::Filename::ToUnixSlashes() + +Convert backslash (windows style) to UNIX style slash. + +*/ public"; + + +// File: classgdcm_1_1FilenameGenerator.xml +%typemap("csclassmodifiers") gdcm::FilenameGenerator " /** +FilenameGenerator. + +class to generate filenames based on a pattern (C-style) + +Output will be: + +for i = 0, number of filenames: outfilename[i] = prefix + (pattern % +i) + +where pattern % i means C-style snprintf of Pattern using value 'i' + +C++ includes: gdcmFilenameGenerator.h */ public class"; + +%csmethodmodifiers gdcm::FilenameGenerator::FilenameGenerator " /** +gdcm::FilenameGenerator::FilenameGenerator() */ public"; + +%csmethodmodifiers gdcm::FilenameGenerator::Generate " /** bool +gdcm::FilenameGenerator::Generate() + +Generate (return success). + +*/ public"; + +%csmethodmodifiers gdcm::FilenameGenerator::GetFilename " /** const +char* gdcm::FilenameGenerator::GetFilename(unsigned int n) const + +Get a particular filename (call after Generate). + +*/ public"; + +%csmethodmodifiers gdcm::FilenameGenerator::GetFilenames " /** +FilenamesType const& gdcm::FilenameGenerator::GetFilenames() const + +Return all filenames. + +*/ public"; + +%csmethodmodifiers gdcm::FilenameGenerator::GetNumberOfFilenames " +/** unsigned int gdcm::FilenameGenerator::GetNumberOfFilenames() const +*/ public"; + +%csmethodmodifiers gdcm::FilenameGenerator::GetPattern " /** const +char* gdcm::FilenameGenerator::GetPattern() const */ public"; + +%csmethodmodifiers gdcm::FilenameGenerator::GetPrefix " /** const +char* gdcm::FilenameGenerator::GetPrefix() const */ public"; + +%csmethodmodifiers gdcm::FilenameGenerator::SetNumberOfFilenames " +/** void gdcm::FilenameGenerator::SetNumberOfFilenames(unsigned int +nfiles) + +Set/Get the number of filenames to generate. + +*/ public"; + +%csmethodmodifiers gdcm::FilenameGenerator::SetPattern " /** void +gdcm::FilenameGenerator::SetPattern(const char *pattern) + +Set/Get pattern. + +*/ public"; + +%csmethodmodifiers gdcm::FilenameGenerator::SetPrefix " /** void +gdcm::FilenameGenerator::SetPrefix(const char *prefix) + +Set/Get prefix. + +*/ public"; + +%csmethodmodifiers gdcm::FilenameGenerator::~FilenameGenerator " /** +gdcm::FilenameGenerator::~FilenameGenerator() */ public"; + + +// File: classgdcm_1_1FileSet.xml +%typemap("csclassmodifiers") gdcm::FileSet " /** File-set: A File-set +is a collection of DICOM Files (and possibly non- DICOM Files) that +share a common naming space within which File IDs are unique. + +C++ includes: gdcmFileSet.h */ public class"; + +%csmethodmodifiers gdcm::FileSet::AddFile " /** bool +gdcm::FileSet::AddFile(const char *filename) + +Add a file 'filename' to the list of files. Return true on success, +false in case filename could not be found on system. + +*/ public"; + +%csmethodmodifiers gdcm::FileSet::AddFile " /** void +gdcm::FileSet::AddFile(File const &) + +Deprecated . Does nothing + +*/ public"; + +%csmethodmodifiers gdcm::FileSet::FileSet " /** +gdcm::FileSet::FileSet() */ public"; + +%csmethodmodifiers gdcm::FileSet::GetFiles " /** FilesType const& +gdcm::FileSet::GetFiles() const */ public"; + +%csmethodmodifiers gdcm::FileSet::SetFiles " /** void +gdcm::FileSet::SetFiles(FilesType const &files) */ public"; + + +// File: classgdcm_1_1FileWithName.xml +%typemap("csclassmodifiers") gdcm::FileWithName " /** SerieHelper. + +Backward only class do not use in newer code + +C++ includes: gdcmSerieHelper.h */ public class"; + +%csmethodmodifiers gdcm::FileWithName::FileWithName " /** +gdcm::FileWithName::FileWithName(File &f) */ public"; + + +// File: classgdcm_1_1Fragment.xml +%typemap("csclassmodifiers") gdcm::Fragment " /** Class to represent a +Fragment. + +C++ includes: gdcmFragment.h */ public class"; + +%csmethodmodifiers gdcm::Fragment::Fragment " /** +gdcm::Fragment::Fragment() */ public"; + +%csmethodmodifiers gdcm::Fragment::GetLength " /** VL +gdcm::Fragment::GetLength() const */ public"; + +%csmethodmodifiers gdcm::Fragment::Read " /** std::istream& +gdcm::Fragment::Read(std::istream &is) */ public"; + +%csmethodmodifiers gdcm::Fragment::Write " /** std::ostream& +gdcm::Fragment::Write(std::ostream &os) const */ public"; + + +// File: classstd_1_1fstream.xml +%typemap("csclassmodifiers") std::fstream " /** STL class. + +*/ public class"; + + +// File: classitk_1_1GDCMImageIO2.xml +%typemap("csclassmodifiers") itk::GDCMImageIO2 " /** ImageIO class for +reading and writing DICOM V3.0 and ACR/NEMA (V1.0 & V2.0) images This +class is only an adaptor to the gdcm library (currently gdcm 2.0 is +used):. + +http://gdcm.sourceforge.net + +WARNING: this class is deprecated, as gdcm 2.x has been integrated in +ITK starting ITK 3.12 + +C++ includes: itkGDCMImageIO2.h */ public class"; + +%csmethodmodifiers itk::GDCMImageIO2::CanReadFile " /** virtual bool +itk::GDCMImageIO2::CanReadFile(const char *) + +Determine the file type. Returns true if this ImageIO can read the +file specified. + +*/ public"; + +%csmethodmodifiers itk::GDCMImageIO2::CanWriteFile " /** virtual bool +itk::GDCMImageIO2::CanWriteFile(const char *) + +Determine the file type. Returns true if this ImageIO can write the +file specified. GDCM triggers on \".dcm\" and \".dicom\". + +*/ public"; + +%csmethodmodifiers itk::GDCMImageIO2::GetBodyPart " /** void +itk::GDCMImageIO2::GetBodyPart(char *part) */ public"; + +%csmethodmodifiers itk::GDCMImageIO2::GetInstitution " /** void +itk::GDCMImageIO2::GetInstitution(char *ins) */ public"; + +%csmethodmodifiers itk::GDCMImageIO2::GetManufacturer " /** void +itk::GDCMImageIO2::GetManufacturer(char *manu) */ public"; + +%csmethodmodifiers itk::GDCMImageIO2::GetModality " /** void +itk::GDCMImageIO2::GetModality(char *modality) */ public"; + +%csmethodmodifiers itk::GDCMImageIO2::GetModel " /** void +itk::GDCMImageIO2::GetModel(char *model) */ public"; + +%csmethodmodifiers itk::GDCMImageIO2::GetNumberOfSeriesInStudy " /** +void itk::GDCMImageIO2::GetNumberOfSeriesInStudy(char *series) */ +public"; + +%csmethodmodifiers itk::GDCMImageIO2::GetNumberOfStudyRelatedSeries " +/** void itk::GDCMImageIO2::GetNumberOfStudyRelatedSeries(char +*series) */ public"; + +%csmethodmodifiers itk::GDCMImageIO2::GetPatientAge " /** void +itk::GDCMImageIO2::GetPatientAge(char *age) */ public"; + +%csmethodmodifiers itk::GDCMImageIO2::GetPatientDOB " /** void +itk::GDCMImageIO2::GetPatientDOB(char *dob) */ public"; + +%csmethodmodifiers itk::GDCMImageIO2::GetPatientID " /** void +itk::GDCMImageIO2::GetPatientID(char *id) */ public"; + +%csmethodmodifiers itk::GDCMImageIO2::GetPatientName " /** void +itk::GDCMImageIO2::GetPatientName(char *name) + +Convenience methods to query patient information and scanner +information. These methods are here for compatibility with the +DICOMImageIO2 class. + +*/ public"; + +%csmethodmodifiers itk::GDCMImageIO2::GetPatientSex " /** void +itk::GDCMImageIO2::GetPatientSex(char *sex) */ public"; + +%csmethodmodifiers itk::GDCMImageIO2::GetScanOptions " /** void +itk::GDCMImageIO2::GetScanOptions(char *options) */ public"; + +%csmethodmodifiers itk::GDCMImageIO2::GetStudyDate " /** void +itk::GDCMImageIO2::GetStudyDate(char *date) */ public"; + +%csmethodmodifiers itk::GDCMImageIO2::GetStudyDescription " /** void +itk::GDCMImageIO2::GetStudyDescription(char *desc) */ public"; + +%csmethodmodifiers itk::GDCMImageIO2::GetStudyID " /** void +itk::GDCMImageIO2::GetStudyID(char *id) */ public"; + +%csmethodmodifiers itk::GDCMImageIO2::GetValueFromTag " /** bool +itk::GDCMImageIO2::GetValueFromTag(const std::string &tag, std::string +&value) + +More general method to retrieve an arbitrary DICOM value based on a +DICOM Tag (eg \"0123|4567\"). WARNING: You need to use the lower case +for hex 0x[a-f], for instance: \"0020|000d\" instead of \"0020|000D\" +(the latter won't work) + +*/ public"; + +%csmethodmodifiers itk::GDCMImageIO2::itkBooleanMacro " /** +itk::GDCMImageIO2::itkBooleanMacro(LoadPrivateTags) */ public"; + +%csmethodmodifiers itk::GDCMImageIO2::itkBooleanMacro " /** +itk::GDCMImageIO2::itkBooleanMacro(LoadSequences) */ public"; + +%csmethodmodifiers itk::GDCMImageIO2::itkBooleanMacro " /** +itk::GDCMImageIO2::itkBooleanMacro(KeepOriginalUID) */ public"; + +%csmethodmodifiers itk::GDCMImageIO2::itkGetEnumMacro " /** +itk::GDCMImageIO2::itkGetEnumMacro(CompressionType, TCompressionType) +*/ public"; + +%csmethodmodifiers itk::GDCMImageIO2::itkGetMacro " /** +itk::GDCMImageIO2::itkGetMacro(LoadPrivateTags, bool) */ public"; + +%csmethodmodifiers itk::GDCMImageIO2::itkGetMacro " /** +itk::GDCMImageIO2::itkGetMacro(LoadSequences, bool) */ public"; + +%csmethodmodifiers itk::GDCMImageIO2::itkGetMacro " /** +itk::GDCMImageIO2::itkGetMacro(KeepOriginalUID, bool) */ public"; + +%csmethodmodifiers itk::GDCMImageIO2::itkGetMacro " /** +itk::GDCMImageIO2::itkGetMacro(RescaleIntercept, double) */ public"; + +%csmethodmodifiers itk::GDCMImageIO2::itkGetMacro " /** +itk::GDCMImageIO2::itkGetMacro(RescaleSlope, double) + +Macro to access Rescale Slope and Rescale Intercept. Which are needed +to rescale properly image when needed. User then need to Always check +those value when access value from the DICOM header + +*/ public"; + +%csmethodmodifiers itk::GDCMImageIO2::itkGetStringMacro " /** +itk::GDCMImageIO2::itkGetStringMacro(FrameOfReferenceInstanceUID) */ +public"; + +%csmethodmodifiers itk::GDCMImageIO2::itkGetStringMacro " /** +itk::GDCMImageIO2::itkGetStringMacro(SeriesInstanceUID) */ public"; + +%csmethodmodifiers itk::GDCMImageIO2::itkGetStringMacro " /** +itk::GDCMImageIO2::itkGetStringMacro(StudyInstanceUID) + +Access the generated DICOM UID's. + +*/ public"; + +%csmethodmodifiers itk::GDCMImageIO2::itkGetStringMacro " /** +itk::GDCMImageIO2::itkGetStringMacro(UIDPrefix) + +Macro to access the DICOM UID prefix. By default this is the ITK root +id. This default can be overriden if the exam is for example part of +an existing study. + +*/ public"; + +%csmethodmodifiers itk::GDCMImageIO2::itkNewMacro " /** +itk::GDCMImageIO2::itkNewMacro(Self) + +Method for creation through the object factory. + +*/ public"; + +%csmethodmodifiers itk::GDCMImageIO2::itkSetEnumMacro " /** +itk::GDCMImageIO2::itkSetEnumMacro(CompressionType, TCompressionType) +*/ public"; + +%csmethodmodifiers itk::GDCMImageIO2::itkSetMacro " /** +itk::GDCMImageIO2::itkSetMacro(LoadPrivateTags, bool) + +Parse any private tags in the DICOM file. Defaults to the value of +LoadPrivateTagsDefault. Loading DICOM files is faster when private +tags are not needed. + +*/ public"; + +%csmethodmodifiers itk::GDCMImageIO2::itkSetMacro " /** +itk::GDCMImageIO2::itkSetMacro(LoadSequences, bool) + +Parse any sequences in the DICOM file. Defaults to the value of +LoadSequencesDefault. Loading DICOM files is faster when sequences are +not needed. + +*/ public"; + +%csmethodmodifiers itk::GDCMImageIO2::itkSetMacro " /** +itk::GDCMImageIO2::itkSetMacro(MaxSizeLoadEntry, long) + +A DICOM file can contains multiple binary stream that can be very long +For example an Overlay on the image. Most of the time user do not want +to load this binary structure in memory since it can consume lot of +memory. Therefore any field that is bigger than the default value +0xfff is discarded and just seek'd This method allow advanced user to +force the reading of such field + +*/ public"; + +%csmethodmodifiers itk::GDCMImageIO2::itkSetMacro " /** +itk::GDCMImageIO2::itkSetMacro(KeepOriginalUID, bool) + +Preserve the original DICOM UID of the input files + +*/ public"; + +%csmethodmodifiers itk::GDCMImageIO2::itkSetStringMacro " /** +itk::GDCMImageIO2::itkSetStringMacro(UIDPrefix) */ public"; + +%csmethodmodifiers itk::GDCMImageIO2::itkTypeMacro " /** +itk::GDCMImageIO2::itkTypeMacro(GDCMImageIO2, Superclass) + +Run-time type information (and related methods). + +*/ public"; + +%csmethodmodifiers itk::GDCMImageIO2::Read " /** virtual void +itk::GDCMImageIO2::Read(void *buffer) + +Reads the data from disk into the memory buffer provided. + +*/ public"; + +%csmethodmodifiers itk::GDCMImageIO2::ReadImageInformation " /** +virtual void itk::GDCMImageIO2::ReadImageInformation() + +Set the spacing and dimesion information for the current filename. + +*/ public"; + +%csmethodmodifiers itk::GDCMImageIO2::Write " /** virtual void +itk::GDCMImageIO2::Write(const void *buffer) + +Writes the data to disk from the memory buffer provided. Make sure +that the IORegion has been set properly. + +*/ public"; + +%csmethodmodifiers itk::GDCMImageIO2::WriteImageInformation " /** +virtual void itk::GDCMImageIO2::WriteImageInformation() + +Writes the spacing and dimentions of the image. Assumes SetFileName +has been called with a valid file name. + +*/ public"; + + +// File: classgdcm_1_1Global.xml +%typemap("csclassmodifiers") gdcm::Global " /** Global. + +Global should be included in any translation unit that will use Dict +or that implements the singleton pattern. It makes sure that the Dict +singleton is created before and destroyed after all other singletons +in GDCM. + +C++ includes: gdcmGlobal.h */ public class"; + +%csmethodmodifiers gdcm::Global::Append " /** bool +gdcm::Global::Append(const char *path) + +Append path at the end of the path list WARNING: not thread safe ! + +*/ public"; + +%csmethodmodifiers gdcm::Global::GetDefs " /** Defs const& +gdcm::Global::GetDefs() const + +retrieve the default/internal (Part 3) You need to explicitely call +LoadResourcesFiles before + +*/ public"; + +%csmethodmodifiers gdcm::Global::GetDicts " /** Dicts const& +gdcm::Global::GetDicts() const + +retrieve the default/internal dicts (Part 6) This dict is filled up at +load time + +*/ public"; + +%csmethodmodifiers gdcm::Global::Global " /** gdcm::Global::Global() +*/ public"; + +%csmethodmodifiers gdcm::Global::LoadResourcesFiles " /** bool +gdcm::Global::LoadResourcesFiles() + +Load all internal XML files, ressource path need to have been set +before calling this member function (see Append/Prepend members func) +WARNING: not thread safe ! + +*/ public"; + +%csmethodmodifiers gdcm::Global::Prepend " /** bool +gdcm::Global::Prepend(const char *path) + +Prepend path at the begining of the path list WARNING: not thread +safe ! + +*/ public"; + +%csmethodmodifiers gdcm::Global::~Global " /** +gdcm::Global::~Global() */ public"; + + +// File: classgdcm_1_1GroupDict.xml +%typemap("csclassmodifiers") gdcm::GroupDict " /** Class to represent +the mapping from group number to its abbreviation and name. + +Should I rewrite this class to use a std::map instead of std::vector +for problem of memory consumption ? + +C++ includes: gdcmGroupDict.h */ public class"; + +%csmethodmodifiers gdcm::GroupDict::GetAbbreviation " /** std::string +const& gdcm::GroupDict::GetAbbreviation(uint16_t num) const */ +public"; + +%csmethodmodifiers gdcm::GroupDict::GetName " /** std::string const& +gdcm::GroupDict::GetName(uint16_t num) const */ public"; + +%csmethodmodifiers gdcm::GroupDict::GroupDict " /** +gdcm::GroupDict::GroupDict() */ public"; + +%csmethodmodifiers gdcm::GroupDict::Size " /** unsigned long +gdcm::GroupDict::Size() const */ public"; + +%csmethodmodifiers gdcm::GroupDict::~GroupDict " /** +gdcm::GroupDict::~GroupDict() */ public"; + + +// File: classgdcm_1_1HAVEGE.xml +%typemap("csclassmodifiers") gdcm::HAVEGE " /**C++ includes: +gdcmHAVEGE.h */ public class"; + +%csmethodmodifiers gdcm::HAVEGE::HAVEGE " /** gdcm::HAVEGE::HAVEGE() +*/ public"; + +%csmethodmodifiers gdcm::HAVEGE::Rand " /** int gdcm::HAVEGE::Rand() + +HAVEGE rand function. + +A random int + +*/ public"; + +%csmethodmodifiers gdcm::HAVEGE::~HAVEGE " /** +gdcm::HAVEGE::~HAVEGE() */ public"; + + +// File: classstd_1_1ifstream.xml +%typemap("csclassmodifiers") std::ifstream " /** STL class. + +*/ public class"; + + +// File: classgdcm_1_1Image.xml +%typemap("csclassmodifiers") gdcm::Image " /** Image. + +This is the container for an Image in the general sense. From this +container you should be able to request information like: Origin + +Dimension + +PixelFormat ... But also to retrieve the image as a raw buffer (char +*) Since we have to deal with both RAW data and JPEG stream (which +internally encode all the above information) this API might seems +redundant. One way to solve that would be to subclass gdcm::Image with +gdcm::JPEGImage which would from the stream extract the header info +and fill it to please gdcm::Image...well except origin for instance + +Basically you can see it as a storage for the PixelData element. +However it was also used for MRSpectroscopy object (as proof of +concept) + +C++ includes: gdcmImage.h */ public class"; + +%csmethodmodifiers gdcm::Image::GetDirectionCosines " /** double +gdcm::Image::GetDirectionCosines(unsigned int idx) const */ public"; + +%csmethodmodifiers gdcm::Image::GetDirectionCosines " /** const +double* gdcm::Image::GetDirectionCosines() const + +Return a 6-tuples specifying the direction cosines A default value of +(1,0,0,0,1,0) will be return when the direction cosines was not +specified. + +*/ public"; + +%csmethodmodifiers gdcm::Image::GetIntercept " /** double +gdcm::Image::GetIntercept() const */ public"; + +%csmethodmodifiers gdcm::Image::GetOrigin " /** double +gdcm::Image::GetOrigin(unsigned int idx) const */ public"; + +%csmethodmodifiers gdcm::Image::GetOrigin " /** const double* +gdcm::Image::GetOrigin() const + +Return a 3-tuples specifying the origin Will return (0,0,0) if the +origin was not specified. + +*/ public"; + +%csmethodmodifiers gdcm::Image::GetSlope " /** double +gdcm::Image::GetSlope() const */ public"; + +%csmethodmodifiers gdcm::Image::GetSpacing " /** double +gdcm::Image::GetSpacing(unsigned int idx) const */ public"; + +%csmethodmodifiers gdcm::Image::GetSpacing " /** const double* +gdcm::Image::GetSpacing() const + +Return a 3-tuples specifying the spacing NOTE: 3rd value can be an +aribtrary 1 value when the spacing was not specified (ex. 2D image). +WARNING: when the spacing is not specifier, a default value of 1 will +be returned + +*/ public"; + +%csmethodmodifiers gdcm::Image::GetSwapCode " /** SwapCode +gdcm::Image::GetSwapCode() const + +DEPRECATED DO NOT USE. + +*/ public"; + +%csmethodmodifiers gdcm::Image::Image " /** gdcm::Image::Image() */ +public"; + +%csmethodmodifiers gdcm::Image::Print " /** void +gdcm::Image::Print(std::ostream &os) const + +print + +*/ public"; + +%csmethodmodifiers gdcm::Image::SetDirectionCosines " /** void +gdcm::Image::SetDirectionCosines(unsigned int idx, double dircos) */ +public"; + +%csmethodmodifiers gdcm::Image::SetDirectionCosines " /** void +gdcm::Image::SetDirectionCosines(const double *dircos) */ public"; + +%csmethodmodifiers gdcm::Image::SetDirectionCosines " /** void +gdcm::Image::SetDirectionCosines(const float *dircos) */ public"; + +%csmethodmodifiers gdcm::Image::SetIntercept " /** void +gdcm::Image::SetIntercept(double intercept) + +intercept + +*/ public"; + +%csmethodmodifiers gdcm::Image::SetOrigin " /** void +gdcm::Image::SetOrigin(unsigned int idx, double ori) */ public"; + +%csmethodmodifiers gdcm::Image::SetOrigin " /** void +gdcm::Image::SetOrigin(const double *ori) */ public"; + +%csmethodmodifiers gdcm::Image::SetOrigin " /** void +gdcm::Image::SetOrigin(const float *ori) */ public"; + +%csmethodmodifiers gdcm::Image::SetSlope " /** void +gdcm::Image::SetSlope(double slope) + +slope + +*/ public"; + +%csmethodmodifiers gdcm::Image::SetSpacing " /** void +gdcm::Image::SetSpacing(unsigned int idx, double spacing) */ public"; + +%csmethodmodifiers gdcm::Image::SetSpacing " /** void +gdcm::Image::SetSpacing(const double *spacing) */ public"; + +%csmethodmodifiers gdcm::Image::SetSwapCode " /** void +gdcm::Image::SetSwapCode(SwapCode sc) */ public"; + +%csmethodmodifiers gdcm::Image::~Image " /** gdcm::Image::~Image() +*/ public"; + + +// File: classgdcm_1_1ImageApplyLookupTable.xml +%typemap("csclassmodifiers") gdcm::ImageApplyLookupTable " /** +ImageApplyLookupTable class It applies the LUT the PixelData (only +PALETTE_COLOR images) Output will be a PhotometricInterpretation=RGB +image. + +C++ includes: gdcmImageApplyLookupTable.h */ public class"; + +%csmethodmodifiers gdcm::ImageApplyLookupTable::Apply " /** bool +gdcm::ImageApplyLookupTable::Apply() + +Apply. + +*/ public"; + +%csmethodmodifiers gdcm::ImageApplyLookupTable::ImageApplyLookupTable +" /** gdcm::ImageApplyLookupTable::ImageApplyLookupTable() */ +public"; + +%csmethodmodifiers +gdcm::ImageApplyLookupTable::~ImageApplyLookupTable " /** +gdcm::ImageApplyLookupTable::~ImageApplyLookupTable() */ public"; + + +// File: classgdcm_1_1ImageChangePhotometricInterpretation.xml +%typemap("csclassmodifiers") +gdcm::ImageChangePhotometricInterpretation " /** +ImageChangePhotometricInterpretation class Class to change the +Photometric Interpetation of an input DICOM. + +C++ includes: gdcmImageChangePhotometricInterpretation.h */ public +class"; + +%csmethodmodifiers gdcm::ImageChangePhotometricInterpretation::Change +" /** bool gdcm::ImageChangePhotometricInterpretation::Change() + +Change. + +*/ public"; + +%csmethodmodifiers +gdcm::ImageChangePhotometricInterpretation::GetPhotometricInterpretation +" /** const PhotometricInterpretation& +gdcm::ImageChangePhotometricInterpretation::GetPhotometricInterpretation() +const */ public"; + +%csmethodmodifiers +gdcm::ImageChangePhotometricInterpretation::ImageChangePhotometricInterpretation +" /** +gdcm::ImageChangePhotometricInterpretation::ImageChangePhotometricInterpretation() +*/ public"; + +%csmethodmodifiers +gdcm::ImageChangePhotometricInterpretation::SetPhotometricInterpretation +" /** void +gdcm::ImageChangePhotometricInterpretation::SetPhotometricInterpretation(PhotometricInterpretation +const &pi) + +Set/Get requested PhotometricInterpretation. + +*/ public"; + +%csmethodmodifiers +gdcm::ImageChangePhotometricInterpretation::~ImageChangePhotometricInterpretation +" /** +gdcm::ImageChangePhotometricInterpretation::~ImageChangePhotometricInterpretation() +*/ public"; + + +// File: classgdcm_1_1ImageChangePlanarConfiguration.xml +%typemap("csclassmodifiers") gdcm::ImageChangePlanarConfiguration " +/** ImageChangePlanarConfiguration class Class to change the Planar +configuration of an input DICOM By default it will change into the +more usual reprensentation: PlanarConfiguration = 0. + +C++ includes: gdcmImageChangePlanarConfiguration.h */ public class"; + +%csmethodmodifiers gdcm::ImageChangePlanarConfiguration::Change " /** +bool gdcm::ImageChangePlanarConfiguration::Change() + +Change. + +*/ public"; + +%csmethodmodifiers +gdcm::ImageChangePlanarConfiguration::GetPlanarConfiguration " /** +unsigned int +gdcm::ImageChangePlanarConfiguration::GetPlanarConfiguration() const +*/ public"; + +%csmethodmodifiers +gdcm::ImageChangePlanarConfiguration::ImageChangePlanarConfiguration " +/** +gdcm::ImageChangePlanarConfiguration::ImageChangePlanarConfiguration() +*/ public"; + +%csmethodmodifiers +gdcm::ImageChangePlanarConfiguration::SetPlanarConfiguration " /** +void +gdcm::ImageChangePlanarConfiguration::SetPlanarConfiguration(unsigned +int pc) + +Set/Get requested PlanarConfigation. + +*/ public"; + +%csmethodmodifiers +gdcm::ImageChangePlanarConfiguration::~ImageChangePlanarConfiguration +" /** +gdcm::ImageChangePlanarConfiguration::~ImageChangePlanarConfiguration() +*/ public"; + + +// File: classgdcm_1_1ImageChangeTransferSyntax.xml +%typemap("csclassmodifiers") gdcm::ImageChangeTransferSyntax " /** +ImageChangeTransferSyntax class Class to change the transfer syntax of +an input DICOM. + +If only Force param is set but no input TransferSyntax is set, it is +assumed that user only wants to inspect encapsulated stream (advanced +dev. option). + +C++ includes: gdcmImageChangeTransferSyntax.h */ public class"; + +%csmethodmodifiers gdcm::ImageChangeTransferSyntax::Change " /** bool +gdcm::ImageChangeTransferSyntax::Change() + +Change. + +*/ public"; + +%csmethodmodifiers gdcm::ImageChangeTransferSyntax::GetTransferSyntax +" /** const TransferSyntax& +gdcm::ImageChangeTransferSyntax::GetTransferSyntax() const + +Get Transfer Syntax. + +*/ public"; + +%csmethodmodifiers +gdcm::ImageChangeTransferSyntax::ImageChangeTransferSyntax " /** +gdcm::ImageChangeTransferSyntax::ImageChangeTransferSyntax() */ +public"; + +%csmethodmodifiers +gdcm::ImageChangeTransferSyntax::SetCompressIconImage " /** void +gdcm::ImageChangeTransferSyntax::SetCompressIconImage(bool b) + +Decide whether or not to also compress the Icon Image using the same +Transfer Syntax Default is to simply decompress icon image + +*/ public"; + +%csmethodmodifiers gdcm::ImageChangeTransferSyntax::SetForce " /** +void gdcm::ImageChangeTransferSyntax::SetForce(bool f) + +When target Transfer Syntax is identical to input target syntax, no +operation is actually done This is an issue when someone wants to +recompress using GDCM internal implementation a JPEG (for example) +image + +*/ public"; + +%csmethodmodifiers gdcm::ImageChangeTransferSyntax::SetTransferSyntax +" /** void gdcm::ImageChangeTransferSyntax::SetTransferSyntax(const +TransferSyntax &ts) + +Set target Transfer Syntax. + +*/ public"; + +%csmethodmodifiers gdcm::ImageChangeTransferSyntax::SetUserCodec " +/** void gdcm::ImageChangeTransferSyntax::SetUserCodec(ImageCodec *ic) +*/ public"; + +%csmethodmodifiers +gdcm::ImageChangeTransferSyntax::~ImageChangeTransferSyntax " /** +gdcm::ImageChangeTransferSyntax::~ImageChangeTransferSyntax() */ +public"; + + +// File: classgdcm_1_1ImageCodec.xml +%typemap("csclassmodifiers") gdcm::ImageCodec " /** ImageCodec. + +Main codec, this is a central place for all implementation + +C++ includes: gdcmImageCodec.h */ public class"; + +%csmethodmodifiers gdcm::ImageCodec::CanDecode " /** bool +gdcm::ImageCodec::CanDecode(TransferSyntax const &) const + +Return whether this decoder support this transfer syntax (can decode +it). + +*/ public"; + +%csmethodmodifiers gdcm::ImageCodec::Decode " /** bool +gdcm::ImageCodec::Decode(DataElement const &is, DataElement &os) + +Decode. + +*/ public"; + +%csmethodmodifiers gdcm::ImageCodec::GetDimensions " /** const +unsigned int* gdcm::ImageCodec::GetDimensions() const */ public"; + +%csmethodmodifiers gdcm::ImageCodec::GetHeaderInfo " /** virtual bool +gdcm::ImageCodec::GetHeaderInfo(std::istream &is, TransferSyntax &ts) +*/ public"; + +%csmethodmodifiers gdcm::ImageCodec::GetLUT " /** const LookupTable& +gdcm::ImageCodec::GetLUT() const */ public"; + +%csmethodmodifiers gdcm::ImageCodec::GetNeedByteSwap " /** bool +gdcm::ImageCodec::GetNeedByteSwap() const */ public"; + +%csmethodmodifiers gdcm::ImageCodec::GetPhotometricInterpretation " +/** const PhotometricInterpretation& +gdcm::ImageCodec::GetPhotometricInterpretation() const */ public"; + +%csmethodmodifiers gdcm::ImageCodec::GetPixelFormat " /** const +PixelFormat& gdcm::ImageCodec::GetPixelFormat() const */ public"; + +%csmethodmodifiers gdcm::ImageCodec::GetPlanarConfiguration " /** +unsigned int gdcm::ImageCodec::GetPlanarConfiguration() const */ +public"; + +%csmethodmodifiers gdcm::ImageCodec::ImageCodec " /** +gdcm::ImageCodec::ImageCodec() */ public"; + +%csmethodmodifiers gdcm::ImageCodec::IsLossy " /** bool +gdcm::ImageCodec::IsLossy() const */ public"; + +%csmethodmodifiers gdcm::ImageCodec::SetDimensions " /** void +gdcm::ImageCodec::SetDimensions(const unsigned int *d) */ public"; + +%csmethodmodifiers gdcm::ImageCodec::SetLUT " /** void +gdcm::ImageCodec::SetLUT(LookupTable const &lut) */ public"; + +%csmethodmodifiers gdcm::ImageCodec::SetNeedByteSwap " /** void +gdcm::ImageCodec::SetNeedByteSwap(bool b) */ public"; + +%csmethodmodifiers gdcm::ImageCodec::SetNeedOverlayCleanup " /** void +gdcm::ImageCodec::SetNeedOverlayCleanup(bool b) */ public"; + +%csmethodmodifiers gdcm::ImageCodec::SetNumberOfDimensions " /** void +gdcm::ImageCodec::SetNumberOfDimensions(unsigned int dim) */ public"; + +%csmethodmodifiers gdcm::ImageCodec::SetPhotometricInterpretation " +/** void +gdcm::ImageCodec::SetPhotometricInterpretation(PhotometricInterpretation +const &pi) */ public"; + +%csmethodmodifiers gdcm::ImageCodec::SetPixelFormat " /** virtual +void gdcm::ImageCodec::SetPixelFormat(PixelFormat const &pf) */ +public"; + +%csmethodmodifiers gdcm::ImageCodec::SetPlanarConfiguration " /** +void gdcm::ImageCodec::SetPlanarConfiguration(unsigned int pc) */ +public"; + +%csmethodmodifiers gdcm::ImageCodec::~ImageCodec " /** +gdcm::ImageCodec::~ImageCodec() */ public"; + + +// File: classgdcm_1_1ImageConverter.xml +%typemap("csclassmodifiers") gdcm::ImageConverter " /** Image +Converter. + +This is the class used to convert from on gdcm::Image to another This +is typically used to convert let say YBR JPEG compressed gdcm::Image +to a RAW RGB gdcm::Image. So that the buffer can be directly pass to +third party application. This filter is application level and not +integrated directly in GDCM + +C++ includes: gdcmImageConverter.h */ public class"; + +%csmethodmodifiers gdcm::ImageConverter::Convert " /** void +gdcm::ImageConverter::Convert() */ public"; + +%csmethodmodifiers gdcm::ImageConverter::GetOuput " /** const Image& +gdcm::ImageConverter::GetOuput() const */ public"; + +%csmethodmodifiers gdcm::ImageConverter::ImageConverter " /** +gdcm::ImageConverter::ImageConverter() */ public"; + +%csmethodmodifiers gdcm::ImageConverter::SetInput " /** void +gdcm::ImageConverter::SetInput(Image const &input) */ public"; + +%csmethodmodifiers gdcm::ImageConverter::~ImageConverter " /** +gdcm::ImageConverter::~ImageConverter() */ public"; + + +// File: classgdcm_1_1ImageFragmentSplitter.xml +%typemap("csclassmodifiers") gdcm::ImageFragmentSplitter " /** +ImageFragmentSplitter class For single frame image, DICOM standard +allow splitting the frame into multiple fragments. + +C++ includes: gdcmImageFragmentSplitter.h */ public class"; + +%csmethodmodifiers gdcm::ImageFragmentSplitter::GetFragmentSizeMax " +/** unsigned int gdcm::ImageFragmentSplitter::GetFragmentSizeMax() +const */ public"; + +%csmethodmodifiers gdcm::ImageFragmentSplitter::ImageFragmentSplitter +" /** gdcm::ImageFragmentSplitter::ImageFragmentSplitter() */ +public"; + +%csmethodmodifiers gdcm::ImageFragmentSplitter::SetForce " /** void +gdcm::ImageFragmentSplitter::SetForce(bool f) + +When file already has all it's segment < FragmentSizeMax there is not +need to run the filter. Unless the user explicitly say 'force' +recomputation ! + +*/ public"; + +%csmethodmodifiers gdcm::ImageFragmentSplitter::SetFragmentSizeMax " +/** void gdcm::ImageFragmentSplitter::SetFragmentSizeMax(unsigned int +fragsize) + +FragmentSizeMax needs to be an even number. + +*/ public"; + +%csmethodmodifiers gdcm::ImageFragmentSplitter::Split " /** bool +gdcm::ImageFragmentSplitter::Split() + +Split. + +*/ public"; + +%csmethodmodifiers +gdcm::ImageFragmentSplitter::~ImageFragmentSplitter " /** +gdcm::ImageFragmentSplitter::~ImageFragmentSplitter() */ public"; + + +// File: classgdcm_1_1ImageHelper.xml +%typemap("csclassmodifiers") gdcm::ImageHelper " /** ImageHelper +(internal class, not intended for user level). + +Helper for writing World images in DICOM. DICOM has a 'template' +approach to image where MR Image Storage are distinct object from +Enhanced MR Image Storage. For example the Pixel Spacing in one object +is not at the same position (ie Tag) as in the other this class is the +central (read: fragile) place where all the dispatching is done from a +unified view of a world image (typically VTK or ITK point of view) +down to the low level DICOM point of view. + +WARNING: : do not expect the API of this class to be maintained at +any point, since as Modalities are added the API might have to be +augmented or behavior changed to cope with new modalities. + +C++ includes: gdcmImageHelper.h */ public class"; + + +// File: classgdcm_1_1ImageReader.xml +%typemap("csclassmodifiers") gdcm::ImageReader " /** ImageReader. + +its role is to convert the DICOM DataSet into a gdcm::Image +representation By default it is also loading the lookup table and +overlay when found as they impact the rendering or the image See PS +3.3-2008, Table C.7-11b IMAGE PIXEL MACRO ATTRIBUTES for the list of +attribute that belong to what gdcm calls a 'Image' + +C++ includes: gdcmImageReader.h */ public class"; + +%csmethodmodifiers gdcm::ImageReader::GetImage " /** Image& +gdcm::ImageReader::GetImage() */ public"; + +%csmethodmodifiers gdcm::ImageReader::GetImage " /** const Image& +gdcm::ImageReader::GetImage() const + +Return the read image. + +*/ public"; + +%csmethodmodifiers gdcm::ImageReader::ImageReader " /** +gdcm::ImageReader::ImageReader() */ public"; + +%csmethodmodifiers gdcm::ImageReader::Read " /** bool +gdcm::ImageReader::Read() + +Read the DICOM image. There are two reason for failure: 1. The input +filename is not DICOM 2. The input DICOM file does not contains an +Image. + +*/ public"; + +%csmethodmodifiers gdcm::ImageReader::~ImageReader " /** +gdcm::ImageReader::~ImageReader() */ public"; + + +// File: classgdcm_1_1ImageToImageFilter.xml +%typemap("csclassmodifiers") gdcm::ImageToImageFilter " /** +ImageToImageFilter class Super class for all filter taking an image +and producing an output image. + +C++ includes: gdcmImageToImageFilter.h */ public class"; + +%csmethodmodifiers gdcm::ImageToImageFilter::GetOutput " /** const +Image& gdcm::ImageToImageFilter::GetOutput() const + +Get Output image. + +*/ public"; + +%csmethodmodifiers gdcm::ImageToImageFilter::ImageToImageFilter " /** +gdcm::ImageToImageFilter::ImageToImageFilter() */ public"; + +%csmethodmodifiers gdcm::ImageToImageFilter::~ImageToImageFilter " +/** gdcm::ImageToImageFilter::~ImageToImageFilter() */ public"; + + +// File: classgdcm_1_1ImageWriter.xml +%typemap("csclassmodifiers") gdcm::ImageWriter " /** ImageWriter. + +C++ includes: gdcmImageWriter.h */ public class"; + +%csmethodmodifiers gdcm::ImageWriter::GetImage " /** Image& +gdcm::ImageWriter::GetImage() */ public"; + +%csmethodmodifiers gdcm::ImageWriter::GetImage " /** const Image& +gdcm::ImageWriter::GetImage() const + +Set/Get Image to be written It will overwrite anything Image infos +found in DataSet (see parent class to see how to pass dataset) + +*/ public"; + +%csmethodmodifiers gdcm::ImageWriter::ImageWriter " /** +gdcm::ImageWriter::ImageWriter() */ public"; + +%csmethodmodifiers gdcm::ImageWriter::Write " /** bool +gdcm::ImageWriter::Write() + +Write. + +*/ public"; + +%csmethodmodifiers gdcm::ImageWriter::~ImageWriter " /** +gdcm::ImageWriter::~ImageWriter() */ public"; + + +// File: classgdcm_1_1ImplicitDataElement.xml +%typemap("csclassmodifiers") gdcm::ImplicitDataElement " /** Class to +represent an *Implicit VR* Data Element. + +bla + +C++ includes: gdcmImplicitDataElement.h */ public class"; + +%csmethodmodifiers gdcm::ImplicitDataElement::GetLength " /** VL +gdcm::ImplicitDataElement::GetLength() const */ public"; + +%csmethodmodifiers gdcm::ImplicitDataElement::Read " /** +std::istream& gdcm::ImplicitDataElement::Read(std::istream &is) */ +public"; + +%csmethodmodifiers gdcm::ImplicitDataElement::ReadWithLength " /** +std::istream& gdcm::ImplicitDataElement::ReadWithLength(std::istream +&is, VL &length) */ public"; + +%csmethodmodifiers gdcm::ImplicitDataElement::Write " /** const +std::ostream& gdcm::ImplicitDataElement::Write(std::ostream &os) const +*/ public"; + + +// File: classstd_1_1invalid__argument.xml +%typemap("csclassmodifiers") std::invalid_argument " /** STL class. + +*/ public class"; + + +// File: classgdcm_1_1IOD.xml +%typemap("csclassmodifiers") gdcm::IOD " /**C++ includes: gdcmIOD.h */ +public class"; + +%csmethodmodifiers gdcm::IOD::AddIODEntry " /** void +gdcm::IOD::AddIODEntry(const IODEntry &iode) */ public"; + +%csmethodmodifiers gdcm::IOD::Clear " /** void gdcm::IOD::Clear() */ +public"; + +%csmethodmodifiers gdcm::IOD::GetIODEntry " /** const IODEntry& +gdcm::IOD::GetIODEntry(unsigned int idx) const */ public"; + +%csmethodmodifiers gdcm::IOD::GetNumberOfIODs " /** unsigned int +gdcm::IOD::GetNumberOfIODs() const */ public"; + +%csmethodmodifiers gdcm::IOD::IOD " /** gdcm::IOD::IOD() */ public"; + + +// File: classgdcm_1_1IODEntry.xml +%typemap("csclassmodifiers") gdcm::IODEntry " /** Class for +representing a IODEntry. + +A.1.3 IOD Module Table and Functional Group Macro Table This Section +of each IOD defines in a tabular form the Modules comprising the IOD. +The following information must be specified for each Module in the +table: The name of the Module or Functional Group + +A reference to the Section in Annex C which defines the Module or +Functional Group + +The usage of the Module or Functional Group; whether it is: + +Mandatory (see A.1.3.1) , abbreviated M + +Conditional (see A.1.3.2) , abbreviated C + +User Option (see A.1.3.3) , abbreviated U The Modules referenced are +defined in Annex C. A.1.3.1 MANDATORY MODULES For each IOD, Mandatory +Modules shall be supported per the definitions, semantics and +requirements defined in Annex C. PS 3.3 - 2008 Page 96 + +Standard - A.1.3.2 CONDITIONAL MODULES Conditional Modules are +Mandatory Modules if specific conditions are met. If the specified +conditions are not met, this Module shall not be supported; that is, +no information defined in that Module shall be sent. A.1.3.3 USER +OPTION MODULES User Option Modules may or may not be supported. If an +optional Module is supported, the Attribute Types specified in the +Modules in Annex C shall be supported. + +See: DictEntry + +C++ includes: gdcmIODEntry.h */ public class"; + +%csmethodmodifiers gdcm::IODEntry::GetIE " /** const char* +gdcm::IODEntry::GetIE() const */ public"; + +%csmethodmodifiers gdcm::IODEntry::GetName " /** const char* +gdcm::IODEntry::GetName() const */ public"; + +%csmethodmodifiers gdcm::IODEntry::GetRef " /** const char* +gdcm::IODEntry::GetRef() const */ public"; + +%csmethodmodifiers gdcm::IODEntry::GetUsage " /** const char* +gdcm::IODEntry::GetUsage() const */ public"; + +%csmethodmodifiers gdcm::IODEntry::GetUsageType " /** +Usage::UsageType gdcm::IODEntry::GetUsageType() const */ public"; + +%csmethodmodifiers gdcm::IODEntry::IODEntry " /** +gdcm::IODEntry::IODEntry(const char *name=\"\", const char *ref=\"\", +const char *usag=\"\") */ public"; + +%csmethodmodifiers gdcm::IODEntry::SetIE " /** void +gdcm::IODEntry::SetIE(const char *ie) */ public"; + +%csmethodmodifiers gdcm::IODEntry::SetName " /** void +gdcm::IODEntry::SetName(const char *name) */ public"; + +%csmethodmodifiers gdcm::IODEntry::SetRef " /** void +gdcm::IODEntry::SetRef(const char *ref) */ public"; + +%csmethodmodifiers gdcm::IODEntry::SetUsage " /** void +gdcm::IODEntry::SetUsage(const char *usag) */ public"; + + +// File: classgdcm_1_1IODs.xml +%typemap("csclassmodifiers") gdcm::IODs " /** Class for representing a +IODs. + +bla + +See: IOD + +C++ includes: gdcmIODs.h */ public class"; + +%csmethodmodifiers gdcm::IODs::AddIOD " /** void +gdcm::IODs::AddIOD(const char *name, const IOD &module) */ public"; + +%csmethodmodifiers gdcm::IODs::Clear " /** void gdcm::IODs::Clear() +*/ public"; + +%csmethodmodifiers gdcm::IODs::GetIOD " /** const IOD& +gdcm::IODs::GetIOD(const char *name) const */ public"; + +%csmethodmodifiers gdcm::IODs::IODs " /** gdcm::IODs::IODs() */ +public"; + + +// File: classstd_1_1ios.xml +%typemap("csclassmodifiers") std::ios " /** STL class. + +*/ public class"; + + +// File: classstd_1_1ios__base.xml +%typemap("csclassmodifiers") std::ios_base " /** STL class. + +*/ public class"; + + +// File: classstd_1_1ios__base_1_1failure.xml +%typemap("csclassmodifiers") std::ios_base::failure " /** STL class. + +*/ public class"; + + +// File: classgdcm_1_1IPPSorter.xml +%typemap("csclassmodifiers") gdcm::IPPSorter " /** IPPSorter +Implement a simple Image Position ( Patient) sorter, along the Image +Orientation ( Patient) direction. This algorithm does NOT support +duplicate and will FAIL in case of duplicate IPP. + +WARNING: See special note for SetZSpacingTolerance when computing the +ZSpacing from the IPP of each DICOM files (default tolerance for +consistant spacing is: 1e-6mm) + +C++ includes: gdcmIPPSorter.h */ public class"; + +%csmethodmodifiers gdcm::IPPSorter::GetZSpacing " /** double +gdcm::IPPSorter::GetZSpacing() const + +Read-only function to provide access to the computed value for the +Z-Spacing The ComputeZSpacing must have been set to true before +execution of sort algorithm. Call this function *after* calling +Sort(); Z-Spacing will be 0 on 2 occasions: Sorting simply failed, +potentially duplicate IPP => ZSpacing = 0 + +ZSpacing could not be computed (Z-Spacing is not constant, or +ZTolerance is too low) + +*/ public"; + +%csmethodmodifiers gdcm::IPPSorter::GetZSpacingTolerance " /** double +gdcm::IPPSorter::GetZSpacingTolerance() const */ public"; + +%csmethodmodifiers gdcm::IPPSorter::IPPSorter " /** +gdcm::IPPSorter::IPPSorter() */ public"; + +%csmethodmodifiers gdcm::IPPSorter::SetComputeZSpacing " /** void +gdcm::IPPSorter::SetComputeZSpacing(bool b) + +Functions related to Z-Spacing computation Set to true when sort +algorithm should also perform a regular Z-Spacing computation using +the Image Position ( Patient) Potential reason for failure: 1. ALL +slices are taken into account, if one slice if missing then ZSpacing +will be set to 0 since the spacing will not be found to be regular +along the Series + +*/ public"; + +%csmethodmodifiers gdcm::IPPSorter::SetZSpacingTolerance " /** void +gdcm::IPPSorter::SetZSpacingTolerance(double tol) + +2. Another reason for failure is that that Z-Spacing is only slightly +changing (eg 1e-3) along the serie, a human can determine that this is +ok and change the tolerance from its default value: 1e-6 + +*/ public"; + +%csmethodmodifiers gdcm::IPPSorter::Sort " /** virtual bool +gdcm::IPPSorter::Sort(std::vector< std::string > const &filenames) + +Main entry point to the sorter. It will execute the filter, option +should be set before running this function (SetZSpacingTolerance, ...) +Return value indicate if sorting could be achived. Warning this does +*NOT* imply that spacing is consistant, it only means the file are +sorted according to IPP You should check if ZSpacing is 0 or not to +deduce if file are actually a 3D volume + +*/ public"; + +%csmethodmodifiers gdcm::IPPSorter::~IPPSorter " /** +gdcm::IPPSorter::~IPPSorter() */ public"; + + +// File: classstd_1_1istream.xml +%typemap("csclassmodifiers") std::istream " /** STL class. + +*/ public class"; + + +// File: classstd_1_1istringstream.xml +%typemap("csclassmodifiers") std::istringstream " /** STL class. + +*/ public class"; + + +// File: classgdcm_1_1Item.xml +%typemap("csclassmodifiers") gdcm::Item " /** Class to represent an +Item A component of the value of a Data Element that is of Value +Representation Sequence of Items. An Item contains a Data Set . See PS +3.5 7.5.1 Item Encoding Rules Each Item of a Data Element of VR SQ +shall be encoded as a DICOM Standart Data Element with a specific Data +Element Tag of Value (FFFE,E000). The Item Tag is followed by a 4 byte +Item Length field encoded in one of the following two ways Explicit/ +Implicit. + +ITEM: A component of the Value of a Data Element that is of Value +Representation Sequence of Items. An Item contains a Data Set. + +C++ includes: gdcmItem.h */ public class"; + +%csmethodmodifiers gdcm::Item::Clear " /** void gdcm::Item::Clear() +*/ public"; + +%csmethodmodifiers gdcm::Item::FindDataElement " /** bool +gdcm::Item::FindDataElement(const Tag &t) const */ public"; + +%csmethodmodifiers gdcm::Item::GetDataElement " /** const +DataElement& gdcm::Item::GetDataElement(const Tag &t) const */ +public"; + +%csmethodmodifiers gdcm::Item::GetLength " /** VL +gdcm::Item::GetLength() const */ public"; + +%csmethodmodifiers gdcm::Item::GetNestedDataSet " /** DataSet& +gdcm::Item::GetNestedDataSet() */ public"; + +%csmethodmodifiers gdcm::Item::GetNestedDataSet " /** const DataSet& +gdcm::Item::GetNestedDataSet() const */ public"; + +%csmethodmodifiers gdcm::Item::InsertDataElement " /** void +gdcm::Item::InsertDataElement(const DataElement &de) */ public"; + +%csmethodmodifiers gdcm::Item::Item " /** gdcm::Item::Item(Item const +&val) */ public"; + +%csmethodmodifiers gdcm::Item::Item " /** gdcm::Item::Item() */ +public"; + +%csmethodmodifiers gdcm::Item::Read " /** std::istream& +gdcm::Item::Read(std::istream &is) */ public"; + +%csmethodmodifiers gdcm::Item::SetNestedDataSet " /** void +gdcm::Item::SetNestedDataSet(const DataSet &nested) */ public"; + +%csmethodmodifiers gdcm::Item::Write " /** const std::ostream& +gdcm::Item::Write(std::ostream &os) const */ public"; + + +// File: classgdcm_1_1JPEG12Codec.xml +%typemap("csclassmodifiers") gdcm::JPEG12Codec " /** Class to do JPEG +12bits (lossy & lossless). + +internal class + +C++ includes: gdcmJPEG12Codec.h */ public class"; + +%csmethodmodifiers gdcm::JPEG12Codec::Decode " /** bool +gdcm::JPEG12Codec::Decode(std::istream &is, std::ostream &os) */ +public"; + +%csmethodmodifiers gdcm::JPEG12Codec::GetHeaderInfo " /** bool +gdcm::JPEG12Codec::GetHeaderInfo(std::istream &is, TransferSyntax &ts) +*/ public"; + +%csmethodmodifiers gdcm::JPEG12Codec::InternalCode " /** bool +gdcm::JPEG12Codec::InternalCode(const char *input, unsigned long len, +std::ostream &os) */ public"; + +%csmethodmodifiers gdcm::JPEG12Codec::JPEG12Codec " /** +gdcm::JPEG12Codec::JPEG12Codec() */ public"; + +%csmethodmodifiers gdcm::JPEG12Codec::~JPEG12Codec " /** +gdcm::JPEG12Codec::~JPEG12Codec() */ public"; + + +// File: classgdcm_1_1JPEG16Codec.xml +%typemap("csclassmodifiers") gdcm::JPEG16Codec " /** Class to do JPEG +16bits (lossless). + +internal class + +C++ includes: gdcmJPEG16Codec.h */ public class"; + +%csmethodmodifiers gdcm::JPEG16Codec::Decode " /** bool +gdcm::JPEG16Codec::Decode(std::istream &is, std::ostream &os) */ +public"; + +%csmethodmodifiers gdcm::JPEG16Codec::GetHeaderInfo " /** bool +gdcm::JPEG16Codec::GetHeaderInfo(std::istream &is, TransferSyntax &ts) +*/ public"; + +%csmethodmodifiers gdcm::JPEG16Codec::InternalCode " /** bool +gdcm::JPEG16Codec::InternalCode(const char *input, unsigned long len, +std::ostream &os) */ public"; + +%csmethodmodifiers gdcm::JPEG16Codec::JPEG16Codec " /** +gdcm::JPEG16Codec::JPEG16Codec() */ public"; + +%csmethodmodifiers gdcm::JPEG16Codec::~JPEG16Codec " /** +gdcm::JPEG16Codec::~JPEG16Codec() */ public"; + + +// File: classgdcm_1_1JPEG2000Codec.xml +%typemap("csclassmodifiers") gdcm::JPEG2000Codec " /** Class to do +JPEG 2000. + +the class will produce JPC (JPEG 2000 codestream), since some private +implementor are using full jp2 file the decoder tolerate jp2 input +this is an implementation of an ImageCodec + +C++ includes: gdcmJPEG2000Codec.h */ public class"; + +%csmethodmodifiers gdcm::JPEG2000Codec::CanCode " /** bool +gdcm::JPEG2000Codec::CanCode(TransferSyntax const &ts) const + +Return whether this coder support this transfer syntax (can code it). + +*/ public"; + +%csmethodmodifiers gdcm::JPEG2000Codec::CanDecode " /** bool +gdcm::JPEG2000Codec::CanDecode(TransferSyntax const &ts) const + +Return whether this decoder support this transfer syntax (can decode +it). + +*/ public"; + +%csmethodmodifiers gdcm::JPEG2000Codec::Code " /** bool +gdcm::JPEG2000Codec::Code(DataElement const &in, DataElement &out) + +Code. + +*/ public"; + +%csmethodmodifiers gdcm::JPEG2000Codec::Decode " /** bool +gdcm::JPEG2000Codec::Decode(DataElement const &is, DataElement &os) + +Decode. + +*/ public"; + +%csmethodmodifiers gdcm::JPEG2000Codec::GetHeaderInfo " /** virtual +bool gdcm::JPEG2000Codec::GetHeaderInfo(std::istream &is, +TransferSyntax &ts) */ public"; + +%csmethodmodifiers gdcm::JPEG2000Codec::GetQuality " /** double +gdcm::JPEG2000Codec::GetQuality(unsigned int idx=0) const */ public"; + +%csmethodmodifiers gdcm::JPEG2000Codec::GetRate " /** double +gdcm::JPEG2000Codec::GetRate(unsigned int idx=0) const */ public"; + +%csmethodmodifiers gdcm::JPEG2000Codec::JPEG2000Codec " /** +gdcm::JPEG2000Codec::JPEG2000Codec() */ public"; + +%csmethodmodifiers gdcm::JPEG2000Codec::SetNumberOfResolutions " /** +void gdcm::JPEG2000Codec::SetNumberOfResolutions(unsigned int nres) +*/ public"; + +%csmethodmodifiers gdcm::JPEG2000Codec::SetQuality " /** void +gdcm::JPEG2000Codec::SetQuality(unsigned int idx, double q) */ +public"; + +%csmethodmodifiers gdcm::JPEG2000Codec::SetRate " /** void +gdcm::JPEG2000Codec::SetRate(unsigned int idx, double rate) */ +public"; + +%csmethodmodifiers gdcm::JPEG2000Codec::SetReversible " /** void +gdcm::JPEG2000Codec::SetReversible(bool res) */ public"; + +%csmethodmodifiers gdcm::JPEG2000Codec::SetTileSize " /** void +gdcm::JPEG2000Codec::SetTileSize(unsigned int tx, unsigned int ty) */ +public"; + +%csmethodmodifiers gdcm::JPEG2000Codec::~JPEG2000Codec " /** +gdcm::JPEG2000Codec::~JPEG2000Codec() */ public"; + + +// File: classgdcm_1_1JPEG8Codec.xml +%typemap("csclassmodifiers") gdcm::JPEG8Codec " /** Class to do JPEG +8bits (lossy & lossless). + +internal class + +C++ includes: gdcmJPEG8Codec.h */ public class"; + +%csmethodmodifiers gdcm::JPEG8Codec::Decode " /** bool +gdcm::JPEG8Codec::Decode(std::istream &is, std::ostream &os) */ +public"; + +%csmethodmodifiers gdcm::JPEG8Codec::GetHeaderInfo " /** bool +gdcm::JPEG8Codec::GetHeaderInfo(std::istream &is, TransferSyntax &ts) +*/ public"; + +%csmethodmodifiers gdcm::JPEG8Codec::InternalCode " /** bool +gdcm::JPEG8Codec::InternalCode(const char *input, unsigned long len, +std::ostream &os) */ public"; + +%csmethodmodifiers gdcm::JPEG8Codec::JPEG8Codec " /** +gdcm::JPEG8Codec::JPEG8Codec() */ public"; + +%csmethodmodifiers gdcm::JPEG8Codec::~JPEG8Codec " /** +gdcm::JPEG8Codec::~JPEG8Codec() */ public"; + + +// File: classgdcm_1_1JPEGCodec.xml +%typemap("csclassmodifiers") gdcm::JPEGCodec " /** JPEG codec Class to +do JPEG (8bits, 12bits, 16bits lossy & lossless). It redispatch in +between the different codec implementation: gdcm::JPEG8Codec, +gdcm::JPEG12Codec & gdcm::JPEG16Codec It also support inconsistency in +between DICOM header and JPEG compressed stream ImageCodec +implementation for the JPEG case. + +Things you should know if you ever want to dive into DICOM/JPEG world +(among other): + +http://groups.google.com/group/comp.protocols.dicom/browse_thread/thread/625e46919f2080e1 + +http://groups.google.com/group/comp.protocols.dicom/browse_thread/thread/75fdfccc65a6243 + +http://groups.google.com/group/comp.protocols.dicom/browse_thread/thread/2d525ef6a2f093ed + +http://groups.google.com/group/comp.protocols.dicom/browse_thread/thread/6b93af410f8c921f + +C++ includes: gdcmJPEGCodec.h */ public class"; + +%csmethodmodifiers gdcm::JPEGCodec::CanCode " /** bool +gdcm::JPEGCodec::CanCode(TransferSyntax const &ts) const + +Return whether this coder support this transfer syntax (can code it). + +*/ public"; + +%csmethodmodifiers gdcm::JPEGCodec::CanDecode " /** bool +gdcm::JPEGCodec::CanDecode(TransferSyntax const &ts) const + +Return whether this decoder support this transfer syntax (can decode +it). + +*/ public"; + +%csmethodmodifiers gdcm::JPEGCodec::Code " /** bool +gdcm::JPEGCodec::Code(DataElement const &in, DataElement &out) + +Compress into JPEG. + +*/ public"; + +%csmethodmodifiers gdcm::JPEGCodec::ComputeOffsetTable " /** void +gdcm::JPEGCodec::ComputeOffsetTable(bool b) + +Compute the offset table:. + +*/ public"; + +%csmethodmodifiers gdcm::JPEGCodec::Decode " /** bool +gdcm::JPEGCodec::Decode(DataElement const &is, DataElement &os) + +Decode. + +*/ public"; + +%csmethodmodifiers gdcm::JPEGCodec::GetHeaderInfo " /** virtual bool +gdcm::JPEGCodec::GetHeaderInfo(std::istream &is, TransferSyntax &ts) +*/ public"; + +%csmethodmodifiers gdcm::JPEGCodec::GetLossless " /** bool +gdcm::JPEGCodec::GetLossless() const */ public"; + +%csmethodmodifiers gdcm::JPEGCodec::GetQuality " /** double +gdcm::JPEGCodec::GetQuality() const */ public"; + +%csmethodmodifiers gdcm::JPEGCodec::JPEGCodec " /** +gdcm::JPEGCodec::JPEGCodec() */ public"; + +%csmethodmodifiers gdcm::JPEGCodec::SetLossless " /** void +gdcm::JPEGCodec::SetLossless(bool l) */ public"; + +%csmethodmodifiers gdcm::JPEGCodec::SetPixelFormat " /** void +gdcm::JPEGCodec::SetPixelFormat(PixelFormat const &pf) */ public"; + +%csmethodmodifiers gdcm::JPEGCodec::SetQuality " /** void +gdcm::JPEGCodec::SetQuality(double q) */ public"; + +%csmethodmodifiers gdcm::JPEGCodec::~JPEGCodec " /** +gdcm::JPEGCodec::~JPEGCodec() */ public"; + + +// File: classgdcm_1_1JPEGLSCodec.xml +%typemap("csclassmodifiers") gdcm::JPEGLSCodec " /** JPEG-LS. + +codec that implement the JPEG-LS compression this is an implementation +of ImageCodec for JPEG-LS It uses the CharLS JPEG-LS implementation + +C++ includes: gdcmJPEGLSCodec.h */ public class"; + +%csmethodmodifiers gdcm::JPEGLSCodec::CanCode " /** bool +gdcm::JPEGLSCodec::CanCode(TransferSyntax const &ts) const + +Return whether this coder support this transfer syntax (can code it). + +*/ public"; + +%csmethodmodifiers gdcm::JPEGLSCodec::CanDecode " /** bool +gdcm::JPEGLSCodec::CanDecode(TransferSyntax const &ts) const + +Return whether this decoder support this transfer syntax (can decode +it). + +*/ public"; + +%csmethodmodifiers gdcm::JPEGLSCodec::Code " /** bool +gdcm::JPEGLSCodec::Code(DataElement const &in, DataElement &out) + +Code. + +*/ public"; + +%csmethodmodifiers gdcm::JPEGLSCodec::Decode " /** bool +gdcm::JPEGLSCodec::Decode(DataElement const &is, DataElement &os) + +Decode. + +*/ public"; + +%csmethodmodifiers gdcm::JPEGLSCodec::GetBufferLength " /** unsigned +long gdcm::JPEGLSCodec::GetBufferLength() const */ public"; + +%csmethodmodifiers gdcm::JPEGLSCodec::GetHeaderInfo " /** bool +gdcm::JPEGLSCodec::GetHeaderInfo(std::istream &is, TransferSyntax &ts) +*/ public"; + +%csmethodmodifiers gdcm::JPEGLSCodec::JPEGLSCodec " /** +gdcm::JPEGLSCodec::JPEGLSCodec() */ public"; + +%csmethodmodifiers gdcm::JPEGLSCodec::SetBufferLength " /** void +gdcm::JPEGLSCodec::SetBufferLength(unsigned long l) */ public"; + +%csmethodmodifiers gdcm::JPEGLSCodec::~JPEGLSCodec " /** +gdcm::JPEGLSCodec::~JPEGLSCodec() */ public"; + + +// File: classstd_1_1length__error.xml +%typemap("csclassmodifiers") std::length_error " /** STL class. + +*/ public class"; + + +// File: classstd_1_1list.xml +%typemap("csclassmodifiers") std::list " /** STL class. + +*/ public class"; + + +// File: classstd_1_1list_1_1const__iterator.xml +%typemap("csclassmodifiers") std::list::const_iterator " /** STL +iterator class. + +*/ public class"; + + +// File: classstd_1_1list_1_1const__reverse__iterator.xml +%typemap("csclassmodifiers") std::list::const_reverse_iterator " /** +STL iterator class. + +*/ public class"; + + +// File: classstd_1_1list_1_1iterator.xml +%typemap("csclassmodifiers") std::list::iterator " /** STL iterator +class. + +*/ public class"; + + +// File: classstd_1_1list_1_1reverse__iterator.xml +%typemap("csclassmodifiers") std::list::reverse_iterator " /** STL +iterator class. + +*/ public class"; + + +// File: classgdcm_1_1LO.xml +%typemap("csclassmodifiers") gdcm::LO " /** LO. + +TODO + +C++ includes: gdcmLO.h */ public class"; + +%csmethodmodifiers gdcm::LO::IsValid " /** bool gdcm::LO::IsValid() +const */ public"; + +%csmethodmodifiers gdcm::LO::LO " /** gdcm::LO::LO(const Superclass +&s, size_type pos=0, size_type n=npos) */ public"; + +%csmethodmodifiers gdcm::LO::LO " /** gdcm::LO::LO(const value_type +*s, size_type n) */ public"; + +%csmethodmodifiers gdcm::LO::LO " /** gdcm::LO::LO(const value_type +*s) */ public"; + +%csmethodmodifiers gdcm::LO::LO " /** gdcm::LO::LO() */ public"; + + +// File: classstd_1_1logic__error.xml +%typemap("csclassmodifiers") std::logic_error " /** STL class. + +*/ public class"; + + +// File: classgdcm_1_1LookupTable.xml +%typemap("csclassmodifiers") gdcm::LookupTable " /** LookupTable +class. + +C++ includes: gdcmLookupTable.h */ public class"; + +%csmethodmodifiers gdcm::LookupTable::Allocate " /** void +gdcm::LookupTable::Allocate(unsigned short bitsample=8) + +Allocate the LUT. + +*/ public"; + +%csmethodmodifiers gdcm::LookupTable::Clear " /** void +gdcm::LookupTable::Clear() + +Clear the LUT. + +*/ public"; + +%csmethodmodifiers gdcm::LookupTable::Decode " /** void +gdcm::LookupTable::Decode(std::istream &is, std::ostream &os) const + +Decode the LUT. + +*/ public"; + +%csmethodmodifiers gdcm::LookupTable::GetBitSample " /** unsigned +short gdcm::LookupTable::GetBitSample() const + +return the bit sample + +*/ public"; + +%csmethodmodifiers gdcm::LookupTable::GetBufferAsRGBA " /** bool +gdcm::LookupTable::GetBufferAsRGBA(unsigned char *rgba) const + +return the LUT as RGBA buffer + +*/ public"; + +%csmethodmodifiers gdcm::LookupTable::GetLUT " /** void +gdcm::LookupTable::GetLUT(LookupTableType type, unsigned char *array, +unsigned int &length) const */ public"; + +%csmethodmodifiers gdcm::LookupTable::GetLUTDescriptor " /** void +gdcm::LookupTable::GetLUTDescriptor(LookupTableType type, unsigned +short &length, unsigned short &subscript, unsigned short &bitsize) +const */ public"; + +%csmethodmodifiers gdcm::LookupTable::GetLUTLength " /** unsigned int +gdcm::LookupTable::GetLUTLength(LookupTableType type) const */ +public"; + +%csmethodmodifiers gdcm::LookupTable::GetPointer " /** const unsigned +char* gdcm::LookupTable::GetPointer() const + +return a raw pointer to the LUT + +*/ public"; + +%csmethodmodifiers gdcm::LookupTable::InitializeBlueLUT " /** void +gdcm::LookupTable::InitializeBlueLUT(unsigned short length, unsigned +short subscript, unsigned short bitsize) */ public"; + +%csmethodmodifiers gdcm::LookupTable::InitializeGreenLUT " /** void +gdcm::LookupTable::InitializeGreenLUT(unsigned short length, unsigned +short subscript, unsigned short bitsize) */ public"; + +%csmethodmodifiers gdcm::LookupTable::InitializeLUT " /** void +gdcm::LookupTable::InitializeLUT(LookupTableType type, unsigned short +length, unsigned short subscript, unsigned short bitsize) + +Generic interface:. + +*/ public"; + +%csmethodmodifiers gdcm::LookupTable::InitializeRedLUT " /** void +gdcm::LookupTable::InitializeRedLUT(unsigned short length, unsigned +short subscript, unsigned short bitsize) + +RED / GREEN / BLUE specific:. + +*/ public"; + +%csmethodmodifiers gdcm::LookupTable::LookupTable " /** +gdcm::LookupTable::LookupTable(LookupTable const &lut) */ public"; + +%csmethodmodifiers gdcm::LookupTable::LookupTable " /** +gdcm::LookupTable::LookupTable() */ public"; + +%csmethodmodifiers gdcm::LookupTable::Print " /** void +gdcm::LookupTable::Print(std::ostream &) const */ public"; + +%csmethodmodifiers gdcm::LookupTable::SetBlueLUT " /** void +gdcm::LookupTable::SetBlueLUT(const unsigned char *blue, unsigned int +length) */ public"; + +%csmethodmodifiers gdcm::LookupTable::SetGreenLUT " /** void +gdcm::LookupTable::SetGreenLUT(const unsigned char *green, unsigned +int length) */ public"; + +%csmethodmodifiers gdcm::LookupTable::SetLUT " /** virtual void +gdcm::LookupTable::SetLUT(LookupTableType type, const unsigned char +*array, unsigned int length) */ public"; + +%csmethodmodifiers gdcm::LookupTable::SetRedLUT " /** void +gdcm::LookupTable::SetRedLUT(const unsigned char *red, unsigned int +length) */ public"; + +%csmethodmodifiers gdcm::LookupTable::WriteBufferAsRGBA " /** bool +gdcm::LookupTable::WriteBufferAsRGBA(const unsigned char *rgba) + +Write the LUT as RGBA. + +*/ public"; + +%csmethodmodifiers gdcm::LookupTable::~LookupTable " /** +gdcm::LookupTable::~LookupTable() */ public"; + + +// File: classstd_1_1map.xml +%typemap("csclassmodifiers") std::map " /** STL class. + +*/ public class"; + + +// File: classstd_1_1map_1_1const__iterator.xml +%typemap("csclassmodifiers") std::map::const_iterator " /** STL +iterator class. + +*/ public class"; + + +// File: classstd_1_1map_1_1const__reverse__iterator.xml +%typemap("csclassmodifiers") std::map::const_reverse_iterator " /** +STL iterator class. + +*/ public class"; + + +// File: classstd_1_1map_1_1iterator.xml +%typemap("csclassmodifiers") std::map::iterator " /** STL iterator +class. + +*/ public class"; + + +// File: classstd_1_1map_1_1reverse__iterator.xml +%typemap("csclassmodifiers") std::map::reverse_iterator " /** STL +iterator class. + +*/ public class"; + + +// File: classgdcm_1_1MD5.xml +%typemap("csclassmodifiers") gdcm::MD5 " /**C++ includes: gdcmMD5.h */ +public class"; + +%csmethodmodifiers gdcm::MD5::MD5 " /** gdcm::MD5::MD5() */ public"; + +%csmethodmodifiers gdcm::MD5::~MD5 " /** gdcm::MD5::~MD5() */ +public"; + + +// File: classgdcm_1_1MediaStorage.xml +%typemap("csclassmodifiers") gdcm::MediaStorage " /** MediaStorage. + +FIXME There should not be any notion of Image and/or PDF at that point +Only the codec can answer yes I support this Media Storage or not... +For instance an ImageCodec will answer yes to most of them while a +PDFCodec will answer only for the Encapsulated PDF + +C++ includes: gdcmMediaStorage.h */ public class"; + +%csmethodmodifiers gdcm::MediaStorage::GetModality " /** const char* +gdcm::MediaStorage::GetModality() const */ public"; + +%csmethodmodifiers gdcm::MediaStorage::GetString " /** const char* +gdcm::MediaStorage::GetString() const */ public"; + +%csmethodmodifiers gdcm::MediaStorage::GuessFromModality " /** void +gdcm::MediaStorage::GuessFromModality(const char *modality, unsigned +int dimension=2) */ public"; + +%csmethodmodifiers gdcm::MediaStorage::IsUndefined " /** bool +gdcm::MediaStorage::IsUndefined() const */ public"; + +%csmethodmodifiers gdcm::MediaStorage::MediaStorage " /** +gdcm::MediaStorage::MediaStorage(MSType type=MS_END) */ public"; + +%csmethodmodifiers gdcm::MediaStorage::SetFromDataSet " /** bool +gdcm::MediaStorage::SetFromDataSet(DataSet const &ds) + +Advanced user only (functions should be protected level...) Those +function are lower level than SetFromFile + +*/ public"; + +%csmethodmodifiers gdcm::MediaStorage::SetFromFile " /** bool +gdcm::MediaStorage::SetFromFile(File const &file) + +Attempt to set the MediaStorage from a file: WARNING: When no +MediaStorage & Modality are found BUT a PixelData element is found +then MediaStorage is set to the default SecondaryCaptureImageStorage +(return value is false in this case) + +*/ public"; + +%csmethodmodifiers gdcm::MediaStorage::SetFromHeader " /** bool +gdcm::MediaStorage::SetFromHeader(FileMetaInformation const &fmi) */ +public"; + +%csmethodmodifiers gdcm::MediaStorage::SetFromModality " /** bool +gdcm::MediaStorage::SetFromModality(DataSet const &ds) */ public"; + + +// File: classgdcm_1_1Module.xml +%typemap("csclassmodifiers") gdcm::Module " /** Class for representing +a Module. + +bla Module: A set of Attributes within an Information Entity or +Normalized IOD which are logically related to each other. + +See: Dict + +C++ includes: gdcmModule.h */ public class"; + +%csmethodmodifiers gdcm::Module::AddModuleEntry " /** void +gdcm::Module::AddModuleEntry(const Tag &tag, const ModuleEntry +&module) */ public"; + +%csmethodmodifiers gdcm::Module::Begin " /** Iterator +gdcm::Module::Begin() */ public"; + +%csmethodmodifiers gdcm::Module::Begin " /** ConstIterator +gdcm::Module::Begin() const */ public"; + +%csmethodmodifiers gdcm::Module::Clear " /** void +gdcm::Module::Clear() */ public"; + +%csmethodmodifiers gdcm::Module::End " /** Iterator +gdcm::Module::End() */ public"; + +%csmethodmodifiers gdcm::Module::End " /** ConstIterator +gdcm::Module::End() const */ public"; + +%csmethodmodifiers gdcm::Module::FindModuleEntry " /** bool +gdcm::Module::FindModuleEntry(const Tag &tag) const */ public"; + +%csmethodmodifiers gdcm::Module::GetModuleEntry " /** const +ModuleEntry& gdcm::Module::GetModuleEntry(const Tag &tag) const */ +public"; + +%csmethodmodifiers gdcm::Module::GetName " /** const char* +gdcm::Module::GetName() const */ public"; + +%csmethodmodifiers gdcm::Module::Module " /** gdcm::Module::Module() +*/ public"; + +%csmethodmodifiers gdcm::Module::SetName " /** void +gdcm::Module::SetName(const char *name) */ public"; + +%csmethodmodifiers gdcm::Module::Verify " /** bool +gdcm::Module::Verify(const DataSet &ds, Usage const &usage) const */ +public"; + + +// File: classgdcm_1_1ModuleEntry.xml +%typemap("csclassmodifiers") gdcm::ModuleEntry " /** Class for +representing a ModuleEntry. + +bla + +See: DictEntry + +C++ includes: gdcmModuleEntry.h */ public class"; + +%csmethodmodifiers gdcm::ModuleEntry::GetDescription " /** const +Description& gdcm::ModuleEntry::GetDescription() const */ public"; + +%csmethodmodifiers gdcm::ModuleEntry::GetName " /** const char* +gdcm::ModuleEntry::GetName() const */ public"; + +%csmethodmodifiers gdcm::ModuleEntry::GetType " /** const Type& +gdcm::ModuleEntry::GetType() const */ public"; + +%csmethodmodifiers gdcm::ModuleEntry::ModuleEntry " /** +gdcm::ModuleEntry::ModuleEntry(const char *name=\"\", const char +*type=\"3\", const char *description=\"\") */ public"; + +%csmethodmodifiers gdcm::ModuleEntry::SetDescription " /** void +gdcm::ModuleEntry::SetDescription(const char *d) */ public"; + +%csmethodmodifiers gdcm::ModuleEntry::SetName " /** void +gdcm::ModuleEntry::SetName(const char *name) */ public"; + +%csmethodmodifiers gdcm::ModuleEntry::SetType " /** void +gdcm::ModuleEntry::SetType(const Type &type) */ public"; + +%csmethodmodifiers gdcm::ModuleEntry::~ModuleEntry " /** virtual +gdcm::ModuleEntry::~ModuleEntry() */ public"; + + +// File: classgdcm_1_1Modules.xml +%typemap("csclassmodifiers") gdcm::Modules " /** Class for +representing a Modules. + +bla + +See: Module + +C++ includes: gdcmModules.h */ public class"; + +%csmethodmodifiers gdcm::Modules::AddModule " /** void +gdcm::Modules::AddModule(const char *ref, const Module &module) */ +public"; + +%csmethodmodifiers gdcm::Modules::Clear " /** void +gdcm::Modules::Clear() */ public"; + +%csmethodmodifiers gdcm::Modules::GetModule " /** const Module& +gdcm::Modules::GetModule(const char *name) const */ public"; + +%csmethodmodifiers gdcm::Modules::IsEmpty " /** bool +gdcm::Modules::IsEmpty() const */ public"; + +%csmethodmodifiers gdcm::Modules::Modules " /** +gdcm::Modules::Modules() */ public"; + + +// File: classstd_1_1multimap.xml +%typemap("csclassmodifiers") std::multimap " /** STL class. + +*/ public class"; + + +// File: classstd_1_1multimap_1_1const__iterator.xml +%typemap("csclassmodifiers") std::multimap::const_iterator " /** STL +iterator class. + +*/ public class"; + + +// File: classstd_1_1multimap_1_1const__reverse__iterator.xml +%typemap("csclassmodifiers") std::multimap::const_reverse_iterator " +/** STL iterator class. + +*/ public class"; + + +// File: classstd_1_1multimap_1_1iterator.xml +%typemap("csclassmodifiers") std::multimap::iterator " /** STL +iterator class. + +*/ public class"; + + +// File: classstd_1_1multimap_1_1reverse__iterator.xml +%typemap("csclassmodifiers") std::multimap::reverse_iterator " /** STL +iterator class. + +*/ public class"; + + +// File: classstd_1_1multiset.xml +%typemap("csclassmodifiers") std::multiset " /** STL class. + +*/ public class"; + + +// File: classstd_1_1multiset_1_1const__iterator.xml +%typemap("csclassmodifiers") std::multiset::const_iterator " /** STL +iterator class. + +*/ public class"; + + +// File: classstd_1_1multiset_1_1const__reverse__iterator.xml +%typemap("csclassmodifiers") std::multiset::const_reverse_iterator " +/** STL iterator class. + +*/ public class"; + + +// File: classstd_1_1multiset_1_1iterator.xml +%typemap("csclassmodifiers") std::multiset::iterator " /** STL +iterator class. + +*/ public class"; + + +// File: classstd_1_1multiset_1_1reverse__iterator.xml +%typemap("csclassmodifiers") std::multiset::reverse_iterator " /** STL +iterator class. + +*/ public class"; + + +// File: classgdcm_1_1NestedModuleEntries.xml +%typemap("csclassmodifiers") gdcm::NestedModuleEntries " /** Class for +representing a NestedModuleEntries. + +bla + +See: ModuleEntry + +C++ includes: gdcmNestedModuleEntries.h */ public class"; + +%csmethodmodifiers gdcm::NestedModuleEntries::AddModuleEntry " /** +void gdcm::NestedModuleEntries::AddModuleEntry(const ModuleEntry &me) +*/ public"; + +%csmethodmodifiers gdcm::NestedModuleEntries::GetModuleEntry " /** +ModuleEntry& gdcm::NestedModuleEntries::GetModuleEntry(unsigned int +idx) */ public"; + +%csmethodmodifiers gdcm::NestedModuleEntries::GetModuleEntry " /** +const ModuleEntry& gdcm::NestedModuleEntries::GetModuleEntry(unsigned +int idx) const */ public"; + +%csmethodmodifiers +gdcm::NestedModuleEntries::GetNumberOfModuleEntries " /** unsigned int +gdcm::NestedModuleEntries::GetNumberOfModuleEntries() */ public"; + +%csmethodmodifiers gdcm::NestedModuleEntries::NestedModuleEntries " +/** gdcm::NestedModuleEntries::NestedModuleEntries(const char +*name=\"\", const char *type=\"3\", const char *description=\"\") */ +public"; + + +// File: classgdcm_1_1Object.xml +%typemap("csclassmodifiers") gdcm::Object " /** Object. + +main superclass for object that want to use SmartPointer invasive ref +counting system + +See: SmartPointer + +C++ includes: gdcmObject.h */ public class"; + +%csmethodmodifiers gdcm::Object::Object " /** +gdcm::Object::Object(const Object &) + +Special requirement for copy/cstor, assigment operator. + +*/ public"; + +%csmethodmodifiers gdcm::Object::Object " /** gdcm::Object::Object() +*/ public"; + +%csmethodmodifiers gdcm::Object::Print " /** virtual void +gdcm::Object::Print(std::ostream &) const */ public"; + +%csmethodmodifiers gdcm::Object::~Object " /** virtual +gdcm::Object::~Object() */ public"; + + +// File: classstd_1_1ofstream.xml +%typemap("csclassmodifiers") std::ofstream " /** STL class. + +*/ public class"; + + +// File: classgdcm_1_1Orientation.xml +%typemap("csclassmodifiers") gdcm::Orientation " /** class to handle +Orientation + +C++ includes: gdcmOrientation.h */ public class"; + +%csmethodmodifiers gdcm::Orientation::Orientation " /** +gdcm::Orientation::Orientation() */ public"; + +%csmethodmodifiers gdcm::Orientation::Print " /** void +gdcm::Orientation::Print(std::ostream &) const + +Print. + +*/ public"; + +%csmethodmodifiers gdcm::Orientation::~Orientation " /** +gdcm::Orientation::~Orientation() */ public"; + + +// File: classstd_1_1ostream.xml +%typemap("csclassmodifiers") std::ostream " /** STL class. + +*/ public class"; + + +// File: classstd_1_1ostringstream.xml +%typemap("csclassmodifiers") std::ostringstream " /** STL class. + +*/ public class"; + + +// File: classstd_1_1out__of__range.xml +%typemap("csclassmodifiers") std::out_of_range " /** STL class. + +*/ public class"; + + +// File: classstd_1_1overflow__error.xml +%typemap("csclassmodifiers") std::overflow_error " /** STL class. + +*/ public class"; + + +// File: classgdcm_1_1Overlay.xml +%typemap("csclassmodifiers") gdcm::Overlay " /** Overlay class. + +see AreOverlaysInPixelData Todo Is there actually any way to recognize +an overlay ? On images with multiple overlay I do not see any way to +differenciate them (other than the group tag). Example: + +C++ includes: gdcmOverlay.h */ public class"; + +%csmethodmodifiers gdcm::Overlay::Decode " /** void +gdcm::Overlay::Decode(std::istream &is, std::ostream &os) */ public"; + +%csmethodmodifiers gdcm::Overlay::Decompress " /** void +gdcm::Overlay::Decompress(std::ostream &os) const */ public"; + +%csmethodmodifiers gdcm::Overlay::GetBitPosition " /** unsigned short +gdcm::Overlay::GetBitPosition() const + +return bit position + +*/ public"; + +%csmethodmodifiers gdcm::Overlay::GetBitsAllocated " /** unsigned +short gdcm::Overlay::GetBitsAllocated() const + +return bits allocated + +*/ public"; + +%csmethodmodifiers gdcm::Overlay::GetBuffer " /** bool +gdcm::Overlay::GetBuffer(char *buffer) const */ public"; + +%csmethodmodifiers gdcm::Overlay::GetColumns " /** unsigned short +gdcm::Overlay::GetColumns() const + +get columns + +*/ public"; + +%csmethodmodifiers gdcm::Overlay::GetDescription " /** const char* +gdcm::Overlay::GetDescription() const + +get description + +*/ public"; + +%csmethodmodifiers gdcm::Overlay::GetGroup " /** unsigned short +gdcm::Overlay::GetGroup() const + +Get Group number. + +*/ public"; + +%csmethodmodifiers gdcm::Overlay::GetOrigin " /** const signed short* +gdcm::Overlay::GetOrigin() const + +get origin + +*/ public"; + +%csmethodmodifiers gdcm::Overlay::GetOverlayData " /** const +ByteValue& gdcm::Overlay::GetOverlayData() const */ public"; + +%csmethodmodifiers gdcm::Overlay::GetRows " /** unsigned short +gdcm::Overlay::GetRows() const + +get rows + +*/ public"; + +%csmethodmodifiers gdcm::Overlay::GetType " /** const char* +gdcm::Overlay::GetType() const + +get type + +*/ public"; + +%csmethodmodifiers gdcm::Overlay::GetUnpackBuffer " /** bool +gdcm::Overlay::GetUnpackBuffer(unsigned char *buffer) const */ +public"; + +%csmethodmodifiers gdcm::Overlay::GrabOverlayFromPixelData " /** bool +gdcm::Overlay::GrabOverlayFromPixelData(DataSet const &ds) */ +public"; + +%csmethodmodifiers gdcm::Overlay::IsEmpty " /** bool +gdcm::Overlay::IsEmpty() const */ public"; + +%csmethodmodifiers gdcm::Overlay::IsInPixelData " /** void +gdcm::Overlay::IsInPixelData(bool b) */ public"; + +%csmethodmodifiers gdcm::Overlay::IsInPixelData " /** bool +gdcm::Overlay::IsInPixelData() const */ public"; + +%csmethodmodifiers gdcm::Overlay::IsZero " /** bool +gdcm::Overlay::IsZero() const + +return true if all bits are set to 0 + +*/ public"; + +%csmethodmodifiers gdcm::Overlay::Overlay " /** +gdcm::Overlay::Overlay(Overlay const &ov) */ public"; + +%csmethodmodifiers gdcm::Overlay::Overlay " /** +gdcm::Overlay::Overlay() */ public"; + +%csmethodmodifiers gdcm::Overlay::Print " /** void +gdcm::Overlay::Print(std::ostream &) const + +Print. + +*/ public"; + +%csmethodmodifiers gdcm::Overlay::SetBitPosition " /** void +gdcm::Overlay::SetBitPosition(unsigned short bitposition) + +set bit position + +*/ public"; + +%csmethodmodifiers gdcm::Overlay::SetBitsAllocated " /** void +gdcm::Overlay::SetBitsAllocated(unsigned short bitsallocated) + +set bits allocated + +*/ public"; + +%csmethodmodifiers gdcm::Overlay::SetColumns " /** void +gdcm::Overlay::SetColumns(unsigned short columns) + +set columns + +*/ public"; + +%csmethodmodifiers gdcm::Overlay::SetDescription " /** void +gdcm::Overlay::SetDescription(const char *description) + +set description + +*/ public"; + +%csmethodmodifiers gdcm::Overlay::SetFrameOrigin " /** void +gdcm::Overlay::SetFrameOrigin(unsigned short frameorigin) + +set frame origin + +*/ public"; + +%csmethodmodifiers gdcm::Overlay::SetGroup " /** void +gdcm::Overlay::SetGroup(unsigned short group) + +Set Group number. + +*/ public"; + +%csmethodmodifiers gdcm::Overlay::SetNumberOfFrames " /** void +gdcm::Overlay::SetNumberOfFrames(unsigned int numberofframes) + +set number of frames + +*/ public"; + +%csmethodmodifiers gdcm::Overlay::SetOrigin " /** void +gdcm::Overlay::SetOrigin(const signed short *origin) + +set origin + +*/ public"; + +%csmethodmodifiers gdcm::Overlay::SetOverlay " /** void +gdcm::Overlay::SetOverlay(const char *array, unsigned int length) + +set overlay from byte array + length + +*/ public"; + +%csmethodmodifiers gdcm::Overlay::SetRows " /** void +gdcm::Overlay::SetRows(unsigned short rows) + +set rows + +*/ public"; + +%csmethodmodifiers gdcm::Overlay::SetType " /** void +gdcm::Overlay::SetType(const char *type) + +set type + +*/ public"; + +%csmethodmodifiers gdcm::Overlay::Update " /** void +gdcm::Overlay::Update(const DataElement &de) + +Update overlay from data element de:. + +*/ public"; + +%csmethodmodifiers gdcm::Overlay::~Overlay " /** +gdcm::Overlay::~Overlay() */ public"; + + +// File: classgdcm_1_1ParseException.xml +%typemap("csclassmodifiers") gdcm::ParseException " /** Standard +exception handling object. + +C++ includes: gdcmParseException.h */ public class"; + +%csmethodmodifiers gdcm::ParseException::GetLastElement " /** const +DataElement& gdcm::ParseException::GetLastElement() const */ public"; + +%csmethodmodifiers gdcm::ParseException::ParseException " /** +gdcm::ParseException::ParseException() */ public"; + +%csmethodmodifiers gdcm::ParseException::SetLastElement " /** void +gdcm::ParseException::SetLastElement(DataElement &de) + +Equivalence operator. + +*/ public"; + +%csmethodmodifiers gdcm::ParseException::~ParseException " /** +virtual gdcm::ParseException::~ParseException() throw () */ public"; + + +// File: classgdcm_1_1Parser.xml +%typemap("csclassmodifiers") gdcm::Parser " /** Parser ala XML_Parser +from expat (SAX). + +Detailled description here Simple API for DICOM + +C++ includes: gdcmParser.h */ public class"; + +%csmethodmodifiers gdcm::Parser::GetCurrentByteIndex " /** unsigned +long gdcm::Parser::GetCurrentByteIndex() const */ public"; + +%csmethodmodifiers gdcm::Parser::GetErrorCode " /** ErrorType +gdcm::Parser::GetErrorCode() const */ public"; + +%csmethodmodifiers gdcm::Parser::GetUserData " /** void* +gdcm::Parser::GetUserData() const */ public"; + +%csmethodmodifiers gdcm::Parser::Parse " /** bool +gdcm::Parser::Parse(const char *s, int len, bool isFinal) */ public"; + +%csmethodmodifiers gdcm::Parser::Parser " /** gdcm::Parser::Parser() +*/ public"; + +%csmethodmodifiers gdcm::Parser::SetElementHandler " /** void +gdcm::Parser::SetElementHandler(StartElementHandler start, +EndElementHandler end) */ public"; + +%csmethodmodifiers gdcm::Parser::SetUserData " /** void +gdcm::Parser::SetUserData(void *userData) */ public"; + +%csmethodmodifiers gdcm::Parser::~Parser " /** +gdcm::Parser::~Parser() */ public"; + + +// File: classgdcm_1_1Patient.xml +%typemap("csclassmodifiers") gdcm::Patient " /** See PS 3.3 - 2007 +DICOM MODEL OF THE REAL-WORLD, p 54. + +C++ includes: gdcmPatient.h */ public class"; + +%csmethodmodifiers gdcm::Patient::Patient " /** +gdcm::Patient::Patient() */ public"; + + +// File: classgdcm_1_1PDBElement.xml +%typemap("csclassmodifiers") gdcm::PDBElement " /** Class to represent +a PDB Element. + +C++ includes: gdcmPDBElement.h */ public class"; + +%csmethodmodifiers gdcm::PDBElement::GetName " /** const char* +gdcm::PDBElement::GetName() const + +Set/Get Name. + +*/ public"; + +%csmethodmodifiers gdcm::PDBElement::GetValue " /** const char* +gdcm::PDBElement::GetValue() const + +Set/Get Value. + +*/ public"; + +%csmethodmodifiers gdcm::PDBElement::PDBElement " /** +gdcm::PDBElement::PDBElement() */ public"; + +%csmethodmodifiers gdcm::PDBElement::SetName " /** void +gdcm::PDBElement::SetName(const char *name) */ public"; + +%csmethodmodifiers gdcm::PDBElement::SetValue " /** void +gdcm::PDBElement::SetValue(const char *value) */ public"; + + +// File: classgdcm_1_1PDBHeader.xml +%typemap("csclassmodifiers") gdcm::PDBHeader " /** Class for +PDBHeader. + +GEMS MR Image have an Attribute (0025,1b,GEMS_SERS_01) which store the +Acquisition parameter of the MR Image. It is compressed and can +therefore not be used as is. This class de- encapsulated the Protocol +Data Block and allow users to query element by name. + +WARNING: : Everything you do with this code is at your own risk, +since decoding process was not written from specification documents. +: the API of this class might change. + +C++ includes: gdcmPDBHeader.h */ public class"; + +%csmethodmodifiers gdcm::PDBHeader::FindPDBElementByName " /** bool +gdcm::PDBHeader::FindPDBElementByName(const char *name) + +Return true if the PDB element matching name is found or not. + +*/ public"; + +%csmethodmodifiers gdcm::PDBHeader::GetPDBElementByName " /** const +PDBElement& gdcm::PDBHeader::GetPDBElementByName(const char *name) + +Lookup in the PDB header if a PDB element match the name 'name': +WARNING: Case Sensitive + +*/ public"; + +%csmethodmodifiers gdcm::PDBHeader::LoadFromDataElement " /** bool +gdcm::PDBHeader::LoadFromDataElement(DataElement const &de) + +Load the PDB Header from a DataElement of a DataSet. + +*/ public"; + +%csmethodmodifiers gdcm::PDBHeader::PDBHeader " /** +gdcm::PDBHeader::PDBHeader() */ public"; + +%csmethodmodifiers gdcm::PDBHeader::Print " /** void +gdcm::PDBHeader::Print(std::ostream &os) const + +Print. + +*/ public"; + +%csmethodmodifiers gdcm::PDBHeader::~PDBHeader " /** +gdcm::PDBHeader::~PDBHeader() */ public"; + + +// File: classgdcm_1_1PDFCodec.xml +%typemap("csclassmodifiers") gdcm::PDFCodec " /** PDFCodec class. + +C++ includes: gdcmPDFCodec.h */ public class"; + +%csmethodmodifiers gdcm::PDFCodec::CanCode " /** bool +gdcm::PDFCodec::CanCode(TransferSyntax const &) const + +Return whether this coder support this transfer syntax (can code it). + +*/ public"; + +%csmethodmodifiers gdcm::PDFCodec::CanDecode " /** bool +gdcm::PDFCodec::CanDecode(TransferSyntax const &) const + +Return whether this decoder support this transfer syntax (can decode +it). + +*/ public"; + +%csmethodmodifiers gdcm::PDFCodec::Decode " /** bool +gdcm::PDFCodec::Decode(DataElement const &is, DataElement &os) + +Decode. + +*/ public"; + +%csmethodmodifiers gdcm::PDFCodec::PDFCodec " /** +gdcm::PDFCodec::PDFCodec() */ public"; + +%csmethodmodifiers gdcm::PDFCodec::~PDFCodec " /** +gdcm::PDFCodec::~PDFCodec() */ public"; + + +// File: classgdcm_1_1PersonName.xml +%typemap("csclassmodifiers") gdcm::PersonName " /** PersonName class. + +C++ includes: gdcmPersonName.h */ public class"; + +%csmethodmodifiers gdcm::PersonName::GetMaxLength " /** unsigned int +gdcm::PersonName::GetMaxLength() const */ public"; + +%csmethodmodifiers gdcm::PersonName::GetNumberOfComponents " /** +unsigned int gdcm::PersonName::GetNumberOfComponents() const */ +public"; + +%csmethodmodifiers gdcm::PersonName::Print " /** void +gdcm::PersonName::Print(std::ostream &os) const */ public"; + +%csmethodmodifiers gdcm::PersonName::SetBlob " /** void +gdcm::PersonName::SetBlob(const std::vector< char > &v) */ public"; + +%csmethodmodifiers gdcm::PersonName::SetComponents " /** void +gdcm::PersonName::SetComponents(const char *components[]) */ public"; + +%csmethodmodifiers gdcm::PersonName::SetComponents " /** void +gdcm::PersonName::SetComponents(const char *comp1=\"\", const char +*comp2=\"\", const char *comp3=\"\", const char *comp4=\"\", const +char *comp5=\"\") */ public"; + + +// File: classgdcm_1_1PhotometricInterpretation.xml +%typemap("csclassmodifiers") gdcm::PhotometricInterpretation " /** +Class to represent an PhotometricInterpretation. + +C++ includes: gdcmPhotometricInterpretation.h */ public class"; + +%csmethodmodifiers +gdcm::PhotometricInterpretation::GetSamplesPerPixel " /** unsigned +short gdcm::PhotometricInterpretation::GetSamplesPerPixel() const + +return the value for Sample Per Pixel associated with a particular +Photometric Interpretation + +*/ public"; + +%csmethodmodifiers gdcm::PhotometricInterpretation::GetString " /** +const char* gdcm::PhotometricInterpretation::GetString() const */ +public"; + +%csmethodmodifiers gdcm::PhotometricInterpretation::IsLossless " /** +bool gdcm::PhotometricInterpretation::IsLossless() const */ public"; + +%csmethodmodifiers gdcm::PhotometricInterpretation::IsLossy " /** +bool gdcm::PhotometricInterpretation::IsLossy() const */ public"; + +%csmethodmodifiers gdcm::PhotometricInterpretation::IsSameColorSpace +" /** bool +gdcm::PhotometricInterpretation::IsSameColorSpace(PhotometricInterpretation +const &pi) const */ public"; + +%csmethodmodifiers +gdcm::PhotometricInterpretation::PhotometricInterpretation " /** +gdcm::PhotometricInterpretation::PhotometricInterpretation(PIType +pi=UNKNOW) */ public"; + + +// File: classgdcm_1_1PixelFormat.xml +%typemap("csclassmodifiers") gdcm::PixelFormat " /** PixelFormat. + +By default the Pixel Type will be instanciated with the following +parameters: SamplesPerPixel : 1 + +BitsAllocated : 8 + +BitsStored : 8 + +HighBit : 7 + +PixelRepresentation : 0 + +C++ includes: gdcmPixelFormat.h */ public class"; + +%csmethodmodifiers gdcm::PixelFormat::GetBitsAllocated " /** unsigned +short gdcm::PixelFormat::GetBitsAllocated() const + +BitsAllocated. + +*/ public"; + +%csmethodmodifiers gdcm::PixelFormat::GetBitsStored " /** unsigned +short gdcm::PixelFormat::GetBitsStored() const + +BitsStored. + +*/ public"; + +%csmethodmodifiers gdcm::PixelFormat::GetHighBit " /** unsigned short +gdcm::PixelFormat::GetHighBit() const + +HighBit. + +*/ public"; + +%csmethodmodifiers gdcm::PixelFormat::GetMax " /** int64_t +gdcm::PixelFormat::GetMax() const + +return the max possible of the pixel + +*/ public"; + +%csmethodmodifiers gdcm::PixelFormat::GetMin " /** int64_t +gdcm::PixelFormat::GetMin() const + +return the min possible of the pixel + +*/ public"; + +%csmethodmodifiers gdcm::PixelFormat::GetPixelRepresentation " /** +unsigned short gdcm::PixelFormat::GetPixelRepresentation() const + +PixelRepresentation. + +*/ public"; + +%csmethodmodifiers gdcm::PixelFormat::GetPixelSize " /** uint8_t +gdcm::PixelFormat::GetPixelSize() const + +return the size of the pixel This is the number of words it would take +to store one pixel WARNING: the return value takes into account the +SamplesPerPixel + +in the rare case when BitsAllocated == 12, the function assume word +padding and value returned will be identical as if BitsAllocated == 16 + +*/ public"; + +%csmethodmodifiers gdcm::PixelFormat::GetSamplesPerPixel " /** +unsigned short gdcm::PixelFormat::GetSamplesPerPixel() const + +Samples Per Pixel. + +*/ public"; + +%csmethodmodifiers gdcm::PixelFormat::GetScalarType " /** ScalarType +gdcm::PixelFormat::GetScalarType() const + +ScalarType does not take into account the sample per pixel. + +*/ public"; + +%csmethodmodifiers gdcm::PixelFormat::GetScalarTypeAsString " /** +const char* gdcm::PixelFormat::GetScalarTypeAsString() const */ +public"; + +%csmethodmodifiers gdcm::PixelFormat::PixelFormat " /** +gdcm::PixelFormat::PixelFormat(ScalarType st) */ public"; + +%csmethodmodifiers gdcm::PixelFormat::PixelFormat " /** +gdcm::PixelFormat::PixelFormat(unsigned short samplesperpixel=1, +unsigned short bitsallocated=8, unsigned short bitsstored=8, unsigned +short highbit=7, unsigned short pixelrepresentation=0) */ public"; + +%csmethodmodifiers gdcm::PixelFormat::Print " /** void +gdcm::PixelFormat::Print(std::ostream &os) const + +Print. + +*/ public"; + +%csmethodmodifiers gdcm::PixelFormat::SetBitsAllocated " /** void +gdcm::PixelFormat::SetBitsAllocated(unsigned short ba) */ public"; + +%csmethodmodifiers gdcm::PixelFormat::SetBitsStored " /** void +gdcm::PixelFormat::SetBitsStored(unsigned short bs) */ public"; + +%csmethodmodifiers gdcm::PixelFormat::SetHighBit " /** void +gdcm::PixelFormat::SetHighBit(unsigned short hb) */ public"; + +%csmethodmodifiers gdcm::PixelFormat::SetPixelRepresentation " /** +void gdcm::PixelFormat::SetPixelRepresentation(unsigned short pr) */ +public"; + +%csmethodmodifiers gdcm::PixelFormat::SetSamplesPerPixel " /** void +gdcm::PixelFormat::SetSamplesPerPixel(unsigned short spp) */ public"; + +%csmethodmodifiers gdcm::PixelFormat::SetScalarType " /** void +gdcm::PixelFormat::SetScalarType(ScalarType st) */ public"; + +%csmethodmodifiers gdcm::PixelFormat::~PixelFormat " /** +gdcm::PixelFormat::~PixelFormat() */ public"; + + +// File: classgdcm_1_1Pixmap.xml +%typemap("csclassmodifiers") gdcm::Pixmap " /** Pixmap class A bitmap +based image. Used as parent for both IconImage and the main Pixel Data +Image It does not contains any World Space information (IPP, IOP). + +C++ includes: gdcmPixmap.h */ public class"; + +%csmethodmodifiers gdcm::Pixmap::AreOverlaysInPixelData " /** bool +gdcm::Pixmap::AreOverlaysInPixelData() const + +returns if Overlays are stored in the unused bit of the pixel data: + +*/ public"; + +%csmethodmodifiers gdcm::Pixmap::GetCurve " /** const Curve& +gdcm::Pixmap::GetCurve(unsigned int i=0) const */ public"; + +%csmethodmodifiers gdcm::Pixmap::GetCurve " /** Curve& +gdcm::Pixmap::GetCurve(unsigned int i=0) + +Curve: group 50xx. + +*/ public"; + +%csmethodmodifiers gdcm::Pixmap::GetIconImage " /** IconImage& +gdcm::Pixmap::GetIconImage() */ public"; + +%csmethodmodifiers gdcm::Pixmap::GetIconImage " /** const IconImage& +gdcm::Pixmap::GetIconImage() const + +Set/Get Icon Image. + +*/ public"; + +%csmethodmodifiers gdcm::Pixmap::GetNumberOfCurves " /** unsigned int +gdcm::Pixmap::GetNumberOfCurves() const */ public"; + +%csmethodmodifiers gdcm::Pixmap::GetNumberOfOverlays " /** unsigned +int gdcm::Pixmap::GetNumberOfOverlays() const */ public"; + +%csmethodmodifiers gdcm::Pixmap::GetOverlay " /** const Overlay& +gdcm::Pixmap::GetOverlay(unsigned int i=0) const */ public"; + +%csmethodmodifiers gdcm::Pixmap::GetOverlay " /** Overlay& +gdcm::Pixmap::GetOverlay(unsigned int i=0) + +Overlay: group 60xx. + +*/ public"; + +%csmethodmodifiers gdcm::Pixmap::Pixmap " /** gdcm::Pixmap::Pixmap() +*/ public"; + +%csmethodmodifiers gdcm::Pixmap::Print " /** void +gdcm::Pixmap::Print(std::ostream &) const */ public"; + +%csmethodmodifiers gdcm::Pixmap::SetNumberOfCurves " /** void +gdcm::Pixmap::SetNumberOfCurves(unsigned int n) */ public"; + +%csmethodmodifiers gdcm::Pixmap::SetNumberOfOverlays " /** void +gdcm::Pixmap::SetNumberOfOverlays(unsigned int n) */ public"; + +%csmethodmodifiers gdcm::Pixmap::~Pixmap " /** +gdcm::Pixmap::~Pixmap() */ public"; + + +// File: classgdcm_1_1PixmapReader.xml +%typemap("csclassmodifiers") gdcm::PixmapReader " /** PixmapReader. + +its role is to convert the DICOM DataSet into a gdcm::Pixmap +representation By default it is also loading the lookup table and +overlay when found as they impact the rendering or the image See PS +3.3-2008, Table C.7-11b IMAGE PIXEL MACRO ATTRIBUTES for the list of +attribute that belong to what gdcm calls a 'Pixmap' + +C++ includes: gdcmPixmapReader.h */ public class"; + +%csmethodmodifiers gdcm::PixmapReader::GetPixmap " /** Pixmap& +gdcm::PixmapReader::GetPixmap() */ public"; + +%csmethodmodifiers gdcm::PixmapReader::GetPixmap " /** const Pixmap& +gdcm::PixmapReader::GetPixmap() const + +Return the read image. + +*/ public"; + +%csmethodmodifiers gdcm::PixmapReader::PixmapReader " /** +gdcm::PixmapReader::PixmapReader() */ public"; + +%csmethodmodifiers gdcm::PixmapReader::Read " /** bool +gdcm::PixmapReader::Read() + +Read the DICOM image. There are two reason for failure: 1. The input +filename is not DICOM 2. The input DICOM file does not contains an +Pixmap. + +*/ public"; + +%csmethodmodifiers gdcm::PixmapReader::~PixmapReader " /** +gdcm::PixmapReader::~PixmapReader() */ public"; + + +// File: classgdcm_1_1PixmapToPixmapFilter.xml +%typemap("csclassmodifiers") gdcm::PixmapToPixmapFilter " /** +PixmapToPixmapFilter class Super class for all filter taking an image +and producing an output image. + +C++ includes: gdcmPixmapToPixmapFilter.h */ public class"; + +%csmethodmodifiers gdcm::PixmapToPixmapFilter::GetOutput " /** const +Pixmap& gdcm::PixmapToPixmapFilter::GetOutput() const + +Get Output image. + +*/ public"; + +%csmethodmodifiers gdcm::PixmapToPixmapFilter::PixmapToPixmapFilter " +/** gdcm::PixmapToPixmapFilter::PixmapToPixmapFilter() */ public"; + +%csmethodmodifiers gdcm::PixmapToPixmapFilter::SetInput " /** void +gdcm::PixmapToPixmapFilter::SetInput(const Pixmap &image) + +Set input image. + +*/ public"; + +%csmethodmodifiers gdcm::PixmapToPixmapFilter::~PixmapToPixmapFilter +" /** gdcm::PixmapToPixmapFilter::~PixmapToPixmapFilter() */ public"; + + +// File: classgdcm_1_1PixmapWriter.xml +%typemap("csclassmodifiers") gdcm::PixmapWriter " /** PixmapWriter. + +C++ includes: gdcmPixmapWriter.h */ public class"; + +%csmethodmodifiers gdcm::PixmapWriter::GetImage " /** virtual Pixmap& +gdcm::PixmapWriter::GetImage() */ public"; + +%csmethodmodifiers gdcm::PixmapWriter::GetImage " /** virtual const +Pixmap& gdcm::PixmapWriter::GetImage() const + +Set/Get Pixmap to be written It will overwrite anything Pixmap infos +found in DataSet (see parent class to see how to pass dataset) + +*/ public"; + +%csmethodmodifiers gdcm::PixmapWriter::GetPixmap " /** Pixmap& +gdcm::PixmapWriter::GetPixmap() */ public"; + +%csmethodmodifiers gdcm::PixmapWriter::GetPixmap " /** const Pixmap& +gdcm::PixmapWriter::GetPixmap() const */ public"; + +%csmethodmodifiers gdcm::PixmapWriter::PixmapWriter " /** +gdcm::PixmapWriter::PixmapWriter() */ public"; + +%csmethodmodifiers gdcm::PixmapWriter::SetImage " /** virtual void +gdcm::PixmapWriter::SetImage(Pixmap const &img) */ public"; + +%csmethodmodifiers gdcm::PixmapWriter::SetPixmap " /** void +gdcm::PixmapWriter::SetPixmap(Pixmap const &img) */ public"; + +%csmethodmodifiers gdcm::PixmapWriter::Write " /** bool +gdcm::PixmapWriter::Write() + +Write. + +*/ public"; + +%csmethodmodifiers gdcm::PixmapWriter::~PixmapWriter " /** +gdcm::PixmapWriter::~PixmapWriter() */ public"; + + +// File: classgdcm_1_1PKCS7.xml +%typemap("csclassmodifiers") gdcm::PKCS7 " /**C++ includes: +gdcmPKCS7.h */ public class"; + +%csmethodmodifiers gdcm::PKCS7::Decrypt " /** bool +gdcm::PKCS7::Decrypt(char *output, size_t &outlen, const char *array, +size_t len) const */ public"; + +%csmethodmodifiers gdcm::PKCS7::Encrypt " /** bool +gdcm::PKCS7::Encrypt(char *output, size_t &outlen, const char *array, +size_t len) const */ public"; + +%csmethodmodifiers gdcm::PKCS7::GetCertificate " /** const X509* +gdcm::PKCS7::GetCertificate() const */ public"; + +%csmethodmodifiers gdcm::PKCS7::GetCipherType " /** CipherTypes +gdcm::PKCS7::GetCipherType() const */ public"; + +%csmethodmodifiers gdcm::PKCS7::PKCS7 " /** gdcm::PKCS7::PKCS7() */ +public"; + +%csmethodmodifiers gdcm::PKCS7::SetCertificate " /** void +gdcm::PKCS7::SetCertificate(X509 *cert) */ public"; + +%csmethodmodifiers gdcm::PKCS7::SetCipherType " /** void +gdcm::PKCS7::SetCipherType(CipherTypes type) */ public"; + +%csmethodmodifiers gdcm::PKCS7::~PKCS7 " /** gdcm::PKCS7::~PKCS7() +*/ public"; + + +// File: classgdcm_1_1PNMCodec.xml +%typemap("csclassmodifiers") gdcm::PNMCodec " /** Class to do PNM PNM +is the Portable anymap file format. The main web page can be found +at:http://netpbm.sourceforge.net/. + +Only support P5 & P6 PNM file (binary grayscale and binary rgb) + +C++ includes: gdcmPNMCodec.h */ public class"; + +%csmethodmodifiers gdcm::PNMCodec::CanCode " /** bool +gdcm::PNMCodec::CanCode(TransferSyntax const &ts) const + +Return whether this coder support this transfer syntax (can code it). + +*/ public"; + +%csmethodmodifiers gdcm::PNMCodec::CanDecode " /** bool +gdcm::PNMCodec::CanDecode(TransferSyntax const &ts) const + +Return whether this decoder support this transfer syntax (can decode +it). + +*/ public"; + +%csmethodmodifiers gdcm::PNMCodec::GetBufferLength " /** unsigned +long gdcm::PNMCodec::GetBufferLength() const */ public"; + +%csmethodmodifiers gdcm::PNMCodec::GetHeaderInfo " /** bool +gdcm::PNMCodec::GetHeaderInfo(std::istream &is, TransferSyntax &ts) +*/ public"; + +%csmethodmodifiers gdcm::PNMCodec::PNMCodec " /** +gdcm::PNMCodec::PNMCodec() */ public"; + +%csmethodmodifiers gdcm::PNMCodec::Read " /** bool +gdcm::PNMCodec::Read(const char *filename, DataElement &out) const */ +public"; + +%csmethodmodifiers gdcm::PNMCodec::SetBufferLength " /** void +gdcm::PNMCodec::SetBufferLength(unsigned long l) */ public"; + +%csmethodmodifiers gdcm::PNMCodec::Write " /** bool +gdcm::PNMCodec::Write(const char *filename, const DataElement &out) +const */ public"; + +%csmethodmodifiers gdcm::PNMCodec::~PNMCodec " /** +gdcm::PNMCodec::~PNMCodec() */ public"; + + +// File: classgdcm_1_1Preamble.xml +%typemap("csclassmodifiers") gdcm::Preamble " /** DICOM Preamble (Part +10). + +C++ includes: gdcmPreamble.h */ public class"; + +%csmethodmodifiers gdcm::Preamble::Clear " /** void +gdcm::Preamble::Clear() */ public"; + +%csmethodmodifiers gdcm::Preamble::Create " /** void +gdcm::Preamble::Create() */ public"; + +%csmethodmodifiers gdcm::Preamble::GetInternal " /** const char* +gdcm::Preamble::GetInternal() const */ public"; + +%csmethodmodifiers gdcm::Preamble::IsEmpty " /** bool +gdcm::Preamble::IsEmpty() const */ public"; + +%csmethodmodifiers gdcm::Preamble::Preamble " /** +gdcm::Preamble::Preamble(Preamble const &preamble) */ public"; + +%csmethodmodifiers gdcm::Preamble::Preamble " /** +gdcm::Preamble::Preamble() */ public"; + +%csmethodmodifiers gdcm::Preamble::Print " /** void +gdcm::Preamble::Print(std::ostream &os) const */ public"; + +%csmethodmodifiers gdcm::Preamble::Read " /** std::istream& +gdcm::Preamble::Read(std::istream &is) */ public"; + +%csmethodmodifiers gdcm::Preamble::Remove " /** void +gdcm::Preamble::Remove() */ public"; + +%csmethodmodifiers gdcm::Preamble::Valid " /** void +gdcm::Preamble::Valid() */ public"; + +%csmethodmodifiers gdcm::Preamble::Write " /** std::ostream const& +gdcm::Preamble::Write(std::ostream &os) const */ public"; + +%csmethodmodifiers gdcm::Preamble::~Preamble " /** +gdcm::Preamble::~Preamble() */ public"; + + +// File: classgdcm_1_1Printer.xml +%typemap("csclassmodifiers") gdcm::Printer " /** Printer class. + +C++ includes: gdcmPrinter.h */ public class"; + +%csmethodmodifiers gdcm::Printer::GetPrintStyle " /** PrintStyles +gdcm::Printer::GetPrintStyle() const */ public"; + +%csmethodmodifiers gdcm::Printer::Print " /** void +gdcm::Printer::Print(std::ostream &os) */ public"; + +%csmethodmodifiers gdcm::Printer::Printer " /** +gdcm::Printer::Printer() */ public"; + +%csmethodmodifiers gdcm::Printer::SetColor " /** void +gdcm::Printer::SetColor(bool c) */ public"; + +%csmethodmodifiers gdcm::Printer::SetFile " /** void +gdcm::Printer::SetFile(File const &f) */ public"; + +%csmethodmodifiers gdcm::Printer::SetStyle " /** void +gdcm::Printer::SetStyle(PrintStyles ps) */ public"; + +%csmethodmodifiers gdcm::Printer::~Printer " /** +gdcm::Printer::~Printer() */ public"; + + +// File: classstd_1_1priority__queue.xml +%typemap("csclassmodifiers") std::priority_queue " /** STL class. + +*/ public class"; + + +// File: classgdcm_1_1PrivateDict.xml +%typemap("csclassmodifiers") gdcm::PrivateDict " /** Private Dict. + +C++ includes: gdcmDict.h */ public class"; + +%csmethodmodifiers gdcm::PrivateDict::AddDictEntry " /** void +gdcm::PrivateDict::AddDictEntry(const PrivateTag &tag, const DictEntry +&de) */ public"; + +%csmethodmodifiers gdcm::PrivateDict::GetDictEntry " /** const +DictEntry& gdcm::PrivateDict::GetDictEntry(const PrivateTag &tag) +const */ public"; + +%csmethodmodifiers gdcm::PrivateDict::IsEmpty " /** bool +gdcm::PrivateDict::IsEmpty() const */ public"; + +%csmethodmodifiers gdcm::PrivateDict::PrintXML " /** void +gdcm::PrivateDict::PrintXML() const */ public"; + +%csmethodmodifiers gdcm::PrivateDict::PrivateDict " /** +gdcm::PrivateDict::PrivateDict() */ public"; + +%csmethodmodifiers gdcm::PrivateDict::~PrivateDict " /** +gdcm::PrivateDict::~PrivateDict() */ public"; + + +// File: classgdcm_1_1PrivateTag.xml +%typemap("csclassmodifiers") gdcm::PrivateTag " /** Class to represent +a Private DICOM Data Element ( Attribute) Tag (Group, Element, Owner). + +private tag have element value in: [0x10,0xff], for instance +0x0009,0x0000 is NOT a private tag + +C++ includes: gdcmPrivateTag.h */ public class"; + +%csmethodmodifiers gdcm::PrivateTag::GetOwner " /** const char* +gdcm::PrivateTag::GetOwner() const */ public"; + +%csmethodmodifiers gdcm::PrivateTag::PrivateTag " /** +gdcm::PrivateTag::PrivateTag(uint16_t group=0, uint16_t element=0, +const char *owner=\"\") */ public"; + +%csmethodmodifiers gdcm::PrivateTag::SetOwner " /** void +gdcm::PrivateTag::SetOwner(const char *owner) */ public"; + + +// File: classgdcm_1_1PVRGCodec.xml +%typemap("csclassmodifiers") gdcm::PVRGCodec " /** PVRGCodec. + +pvrg is a broken implementation of the JPEG standard. It is known to +have a bug in the 16bits lossless implementation of the standard. In +an ideal world, you should not need this codec at all. But to support +some broken file such as: + +PHILIPS_Gyroscan-12-Jpeg_Extended_Process_2_4.dcm + +we have to... + +C++ includes: gdcmPVRGCodec.h */ public class"; + +%csmethodmodifiers gdcm::PVRGCodec::CanCode " /** bool +gdcm::PVRGCodec::CanCode(TransferSyntax const &ts) const + +Return whether this coder support this transfer syntax (can code it). + +*/ public"; + +%csmethodmodifiers gdcm::PVRGCodec::CanDecode " /** bool +gdcm::PVRGCodec::CanDecode(TransferSyntax const &ts) const + +Return whether this decoder support this transfer syntax (can decode +it). + +*/ public"; + +%csmethodmodifiers gdcm::PVRGCodec::Code " /** bool +gdcm::PVRGCodec::Code(DataElement const &in, DataElement &out) + +Code. + +*/ public"; + +%csmethodmodifiers gdcm::PVRGCodec::Decode " /** bool +gdcm::PVRGCodec::Decode(DataElement const &is, DataElement &os) + +Decode. + +*/ public"; + +%csmethodmodifiers gdcm::PVRGCodec::PVRGCodec " /** +gdcm::PVRGCodec::PVRGCodec() */ public"; + +%csmethodmodifiers gdcm::PVRGCodec::~PVRGCodec " /** +gdcm::PVRGCodec::~PVRGCodec() */ public"; + + +// File: classgdcm_1_1PythonFilter.xml +%typemap("csclassmodifiers") gdcm::PythonFilter " /** PythonFilter +PythonFilter is the class that make gdcm2.x looks more like gdcm1 and +transform the binary blob contained in a DataElement into a string, +typically this is a nice feature to have for wrapped language. + +C++ includes: gdcmPythonFilter.h */ public class"; + +%csmethodmodifiers gdcm::PythonFilter::GetFile " /** const File& +gdcm::PythonFilter::GetFile() const */ public"; + +%csmethodmodifiers gdcm::PythonFilter::GetFile " /** File& +gdcm::PythonFilter::GetFile() */ public"; + +%csmethodmodifiers gdcm::PythonFilter::PythonFilter " /** +gdcm::PythonFilter::PythonFilter() */ public"; + +%csmethodmodifiers gdcm::PythonFilter::SetDicts " /** void +gdcm::PythonFilter::SetDicts(const Dicts &dicts) */ public"; + +%csmethodmodifiers gdcm::PythonFilter::SetFile " /** void +gdcm::PythonFilter::SetFile(const File &f) */ public"; + +%csmethodmodifiers gdcm::PythonFilter::ToPyObject " /** PyObject* +gdcm::PythonFilter::ToPyObject(const Tag &t) const */ public"; + +%csmethodmodifiers gdcm::PythonFilter::UseDictAlways " /** void +gdcm::PythonFilter::UseDictAlways(bool use) */ public"; + +%csmethodmodifiers gdcm::PythonFilter::~PythonFilter " /** +gdcm::PythonFilter::~PythonFilter() */ public"; + + +// File: classstd_1_1queue.xml +%typemap("csclassmodifiers") std::queue " /** STL class. + +*/ public class"; + + +// File: classstd_1_1range__error.xml +%typemap("csclassmodifiers") std::range_error " /** STL class. + +*/ public class"; + + +// File: classgdcm_1_1RAWCodec.xml +%typemap("csclassmodifiers") gdcm::RAWCodec " /** RAWCodec class. + +C++ includes: gdcmRAWCodec.h */ public class"; + +%csmethodmodifiers gdcm::RAWCodec::CanCode " /** bool +gdcm::RAWCodec::CanCode(TransferSyntax const &ts) const + +Return whether this coder support this transfer syntax (can code it). + +*/ public"; + +%csmethodmodifiers gdcm::RAWCodec::CanDecode " /** bool +gdcm::RAWCodec::CanDecode(TransferSyntax const &ts) const + +Return whether this decoder support this transfer syntax (can decode +it). + +*/ public"; + +%csmethodmodifiers gdcm::RAWCodec::Code " /** bool +gdcm::RAWCodec::Code(DataElement const &in, DataElement &out) + +Code. + +*/ public"; + +%csmethodmodifiers gdcm::RAWCodec::Decode " /** bool +gdcm::RAWCodec::Decode(DataElement const &is, DataElement &os) + +Decode. + +*/ public"; + +%csmethodmodifiers gdcm::RAWCodec::GetHeaderInfo " /** bool +gdcm::RAWCodec::GetHeaderInfo(std::istream &is, TransferSyntax &ts) +*/ public"; + +%csmethodmodifiers gdcm::RAWCodec::RAWCodec " /** +gdcm::RAWCodec::RAWCodec() */ public"; + +%csmethodmodifiers gdcm::RAWCodec::~RAWCodec " /** +gdcm::RAWCodec::~RAWCodec() */ public"; + + +// File: classgdcm_1_1Reader.xml +%typemap("csclassmodifiers") gdcm::Reader " /** Reader ala DOM +(Document Object Model). + +This class is a non-validating reader, it will only performs well- +formedness check only, and to some extent catch known error (non well- +formed document). + +Detailled description here + +A DataSet DOES NOT contains group 0x0002 + +This is really a DataSet reader. This will not make sure the dataset +conform to any IOD at all. This is a completely different step. The +reasoning was that user could control the IOD there lib would handle +and thus we would not be able to read a DataSet if the IOD was not +found Instead we separate the reading from the validation. + +NOTE: From GDCM1.x. Users will realize that one feature is missing +from this DOM implementation. In GDCM 1.x user used to be able to +control the size of the Value to be read. By default it was 0xfff. The +main author of GDCM2 thought this was too dangerous and harmful and +therefore this feature did not make it into GDCM2 + +WARNING: GDCM will not produce warning for unorder (non-alphabetical +order). See gdcm::Writer for more info + +C++ includes: gdcmReader.h */ public class"; + +%csmethodmodifiers gdcm::Reader::GetFile " /** File& +gdcm::Reader::GetFile() */ public"; + +%csmethodmodifiers gdcm::Reader::GetFile " /** const File& +gdcm::Reader::GetFile() const */ public"; + +%csmethodmodifiers gdcm::Reader::Read " /** virtual bool +gdcm::Reader::Read() */ public"; + +%csmethodmodifiers gdcm::Reader::Reader " /** gdcm::Reader::Reader() +*/ public"; + +%csmethodmodifiers gdcm::Reader::ReadUpToTag " /** bool +gdcm::Reader::ReadUpToTag(const Tag &tag, std::set< Tag > const +&skiptags) */ public"; + +%csmethodmodifiers gdcm::Reader::SetFile " /** void +gdcm::Reader::SetFile(File &file) */ public"; + +%csmethodmodifiers gdcm::Reader::SetFileName " /** void +gdcm::Reader::SetFileName(const char *filename) */ public"; + +%csmethodmodifiers gdcm::Reader::SetStream " /** void +gdcm::Reader::SetStream(std::istream &input_stream) */ public"; + +%csmethodmodifiers gdcm::Reader::~Reader " /** virtual +gdcm::Reader::~Reader() */ public"; + + +// File: classgdcm_1_1Rescaler.xml +%typemap("csclassmodifiers") gdcm::Rescaler " /** Rescale class. + +WARNING: internally any time a floating point value is found either +in the Rescale Slope or the Rescale Intercept it is assumed that the +best matching output pixel type if FLOAT64 in previous implementation +it was FLOAT32. Because VR:DS is closer to a 64bits floating point +type FLOAT64 is thus a best matching pixel type for the floating point +transformation. + +handle floating point transformation back and forth to integer +properly (no loss) + +C++ includes: gdcmRescaler.h */ public class"; + +%csmethodmodifiers gdcm::Rescaler::ComputeInterceptSlopePixelType " +/** PixelFormat::ScalarType +gdcm::Rescaler::ComputeInterceptSlopePixelType() + +Compute the Pixel Format of the output data Used for direct +transformation + +*/ public"; + +%csmethodmodifiers gdcm::Rescaler::ComputePixelTypeFromMinMax " /** +PixelFormat gdcm::Rescaler::ComputePixelTypeFromMinMax() + +Compute the Pixel Format of the output data Used for inverse +transformation + +*/ public"; + +%csmethodmodifiers gdcm::Rescaler::InverseRescale " /** bool +gdcm::Rescaler::InverseRescale(char *out, const char *in, size_t n) + +Inverse transform. + +*/ public"; + +%csmethodmodifiers gdcm::Rescaler::Rescale " /** bool +gdcm::Rescaler::Rescale(char *out, const char *in, size_t n) + +Direct transform. + +*/ public"; + +%csmethodmodifiers gdcm::Rescaler::Rescaler " /** +gdcm::Rescaler::Rescaler() */ public"; + +%csmethodmodifiers gdcm::Rescaler::SetIntercept " /** void +gdcm::Rescaler::SetIntercept(double i) + +Set Intercept: used for both direct&inverse transformation. + +*/ public"; + +%csmethodmodifiers gdcm::Rescaler::SetMinMaxForPixelType " /** void +gdcm::Rescaler::SetMinMaxForPixelType(double min, double max) + +Set target interval for output data. A best match will be computed (if +possible) Used for inverse transformation + +*/ public"; + +%csmethodmodifiers gdcm::Rescaler::SetPixelFormat " /** void +gdcm::Rescaler::SetPixelFormat(PixelFormat const &pf) + +Set Pixel Format of input data. + +*/ public"; + +%csmethodmodifiers gdcm::Rescaler::SetSlope " /** void +gdcm::Rescaler::SetSlope(double s) + +Set Slope: user for both direct&inverse transformation. + +*/ public"; + +%csmethodmodifiers gdcm::Rescaler::~Rescaler " /** +gdcm::Rescaler::~Rescaler() */ public"; + + +// File: classgdcm_1_1RLECodec.xml +%typemap("csclassmodifiers") gdcm::RLECodec " /** Class to do RLE. + +ANSI X3.9 A.4.2 RLE Compression Annex G defines a RLE Compression +Transfer Syntax. This transfer Syntax is identified by the UID value +\"1.2.840.10008.1.2.5\". If the object allows multi-frame images in +the pixel data field, then each frame shall be encoded separately. +Each frame shall be encoded in one and only one Fragment (see PS +3.5.8.2). + +C++ includes: gdcmRLECodec.h */ public class"; + +%csmethodmodifiers gdcm::RLECodec::CanCode " /** bool +gdcm::RLECodec::CanCode(TransferSyntax const &ts) const + +Return whether this coder support this transfer syntax (can code it). + +*/ public"; + +%csmethodmodifiers gdcm::RLECodec::CanDecode " /** bool +gdcm::RLECodec::CanDecode(TransferSyntax const &ts) const + +Return whether this decoder support this transfer syntax (can decode +it). + +*/ public"; + +%csmethodmodifiers gdcm::RLECodec::Code " /** bool +gdcm::RLECodec::Code(DataElement const &in, DataElement &out) + +Code. + +*/ public"; + +%csmethodmodifiers gdcm::RLECodec::Decode " /** bool +gdcm::RLECodec::Decode(DataElement const &is, DataElement &os) + +Decode. + +*/ public"; + +%csmethodmodifiers gdcm::RLECodec::GetBufferLength " /** unsigned +long gdcm::RLECodec::GetBufferLength() const */ public"; + +%csmethodmodifiers gdcm::RLECodec::GetHeaderInfo " /** bool +gdcm::RLECodec::GetHeaderInfo(std::istream &is, TransferSyntax &ts) +*/ public"; + +%csmethodmodifiers gdcm::RLECodec::RLECodec " /** +gdcm::RLECodec::RLECodec() */ public"; + +%csmethodmodifiers gdcm::RLECodec::SetBufferLength " /** void +gdcm::RLECodec::SetBufferLength(unsigned long l) */ public"; + +%csmethodmodifiers gdcm::RLECodec::SetLength " /** void +gdcm::RLECodec::SetLength(unsigned long l) */ public"; + +%csmethodmodifiers gdcm::RLECodec::~RLECodec " /** +gdcm::RLECodec::~RLECodec() */ public"; + + +// File: classgdcm_1_1RSA.xml +%typemap("csclassmodifiers") gdcm::RSA " /**C++ includes: gdcmRSA.h */ +public class"; + +%csmethodmodifiers gdcm::RSA::CheckPrivkey " /** int +gdcm::RSA::CheckPrivkey() const + +Check a private RSA key. + +Parameters: +----------- + +ctx: RSA context to be checked + +0 if successful, or an POLARSSL_ERR_RSA_XXX error code + +*/ public"; + +%csmethodmodifiers gdcm::RSA::CheckPubkey " /** int +gdcm::RSA::CheckPubkey() const + +Check a public RSA key. + +Parameters: +----------- + +ctx: RSA context to be checked + +0 if successful, or an POLARSSL_ERR_RSA_XXX error code + +*/ public"; + +%csmethodmodifiers gdcm::RSA::GetLenkey " /** unsigned int +gdcm::RSA::GetLenkey() const + +Return the length of the key:. + +*/ public"; + +%csmethodmodifiers gdcm::RSA::Pkcs1Decrypt " /** int +gdcm::RSA::Pkcs1Decrypt(int mode, unsigned int &olen, const char +*input, char *output, unsigned int output_max_len) + +Do an RSA operation, then remove the message padding. + +Parameters: +----------- + +ctx: RSA context + +mode: RSA_PUBLIC or RSA_PRIVATE + +input: buffer holding the encrypted data + +output: buffer that will hold the plaintext + +olen: will contain the plaintext length + +output_max_len: maximum length of the output buffer + +0 if successful, or an POLARSSL_ERR_RSA_XXX error code + +The output buffer must be as large as the size of ctx->N (eg. 128 +bytes if RSA-1024 is used) otherwise an error is thrown. + +*/ public"; + +%csmethodmodifiers gdcm::RSA::Pkcs1Encrypt " /** int +gdcm::RSA::Pkcs1Encrypt(int mode, unsigned int ilen, const char +*input, char *output) const + +Add the message padding, then do an RSA operation. + +Parameters: +----------- + +ctx: RSA context + +mode: RSA_PUBLIC or RSA_PRIVATE + +ilen: contains the plaintext length + +input: buffer holding the data to be encrypted + +output: buffer that will hold the ciphertext + +0 if successful, or an XYSSL_ERR_RSA_XXX error code + +The output buffer must be as large as the size of ctx->N (eg. 128 +bytes if RSA-1024 is used). + +*/ public"; + +%csmethodmodifiers gdcm::RSA::RSA " /** gdcm::RSA::RSA() */ public"; + +%csmethodmodifiers gdcm::RSA::X509ParseKey " /** int +gdcm::RSA::X509ParseKey(const char *buf, unsigned int buflen, const +char *pwd=0, unsigned int pwdlen=0) + +Parse a private RSA key. + +Parameters: +----------- + +rsa: RSA context to be initialized + +buf: input buffer + +buflen: size of the buffer + +pwd: password for decryption (optional) + +pwdlen: size of the password + +0 if successful, or a specific X509 error code + +*/ public"; + +%csmethodmodifiers gdcm::RSA::X509ParseKeyfile " /** int +gdcm::RSA::X509ParseKeyfile(const char *path, const char *password=0) + +Load and parse a private RSA key. + +Parameters: +----------- + +rsa: RSA context to be initialized + +path: filename to read the private key from + +pwd: password to decrypt the file (can be NULL) + +0 if successful, or a specific X509 error code + +*/ public"; + +%csmethodmodifiers gdcm::RSA::X509WriteKeyfile " /** int +gdcm::RSA::X509WriteKeyfile(const char *path, int format=OUTPUT_PEM) +*/ public"; + +%csmethodmodifiers gdcm::RSA::~RSA " /** gdcm::RSA::~RSA() */ +public"; + + +// File: classstd_1_1runtime__error.xml +%typemap("csclassmodifiers") std::runtime_error " /** STL class. + +*/ public class"; + + +// File: classgdcm_1_1Scanner.xml +%typemap("csclassmodifiers") gdcm::Scanner " /** Scanner. + +Todo This filter is dealing with both VRASCII and VRBINARY element, +thanks to the help of gdcm::StringFilter + +WARNING: : IMPORTANT In case of file where tags are not ordered, the +output will be garbage + +: implementation details. All values are stored in a std::set of +std::string. Then the *address* of the cstring underlying the +std::string is used in the std::map + +C++ includes: gdcmScanner.h */ public class"; + +%csmethodmodifiers gdcm::Scanner::AddSkipTag " /** void +gdcm::Scanner::AddSkipTag(Tag const &t) + +Add a tag that will need to be skipped. Those are root level skip +tags. + +*/ public"; + +%csmethodmodifiers gdcm::Scanner::AddTag " /** void +gdcm::Scanner::AddTag(Tag const &t) + +Add a tag that will need to be read. Those are root level skip tags. + +*/ public"; + +%csmethodmodifiers gdcm::Scanner::Begin " /** ConstIterator +gdcm::Scanner::Begin() const */ public"; + +%csmethodmodifiers gdcm::Scanner::ClearSkipTags " /** void +gdcm::Scanner::ClearSkipTags() */ public"; + +%csmethodmodifiers gdcm::Scanner::ClearTags " /** void +gdcm::Scanner::ClearTags() */ public"; + +%csmethodmodifiers gdcm::Scanner::End " /** ConstIterator +gdcm::Scanner::End() const */ public"; + +%csmethodmodifiers gdcm::Scanner::GetFilenames " /** +Directory::FilenamesType const& gdcm::Scanner::GetFilenames() const +*/ public"; + +%csmethodmodifiers gdcm::Scanner::GetKeys " /** +Directory::FilenamesType gdcm::Scanner::GetKeys() const + +Return the list of filename that are key in the internal map, which +means those filename were properly parsed + +*/ public"; + +%csmethodmodifiers gdcm::Scanner::GetMapping " /** TagToValue const& +gdcm::Scanner::GetMapping(const char *filename) const + +Get the std::map mapping filenames to value for file 'filename'. + +*/ public"; + +%csmethodmodifiers gdcm::Scanner::GetMappings " /** MappingType +const& gdcm::Scanner::GetMappings() const + +Mappings are the mapping from a particular tag to the map, mapping +filename to value:. + +*/ public"; + +%csmethodmodifiers gdcm::Scanner::GetValue " /** const char* +gdcm::Scanner::GetValue(const char *filename, Tag const &t) const + +Retrieve the value found for tag: t associated with file: filename +This is meant for a single short call. If multiple calls (multiple +tags) should be done, prefer the GetMapping function, and then reuse +the TagToValue hash table. WARNING: Tag 't' should have been added +via AddTag() prior to the Scan() call ! + +*/ public"; + +%csmethodmodifiers gdcm::Scanner::GetValues " /** ValuesType +gdcm::Scanner::GetValues(Tag const &t) const + +Get all the values found (in lexicographic order) associated with Tag +'t'. + +*/ public"; + +%csmethodmodifiers gdcm::Scanner::GetValues " /** ValuesType const& +gdcm::Scanner::GetValues() const + +Get all the values found (in lexicographic order). + +*/ public"; + +%csmethodmodifiers gdcm::Scanner::IsKey " /** bool +gdcm::Scanner::IsKey(const char *filename) const + +Check if filename is a key in the Mapping table. returns true only of +file can be found, which means the file was indeed a DICOM file that +could be processed + +*/ public"; + +%csmethodmodifiers gdcm::Scanner::Print " /** void +gdcm::Scanner::Print(std::ostream &os) const + +Print result. + +*/ public"; + +%csmethodmodifiers gdcm::Scanner::Scan " /** bool +gdcm::Scanner::Scan(Directory::FilenamesType const &filenames) + +Start the scan ! + +*/ public"; + +%csmethodmodifiers gdcm::Scanner::Scanner " /** +gdcm::Scanner::Scanner() */ public"; + +%csmethodmodifiers gdcm::Scanner::~Scanner " /** +gdcm::Scanner::~Scanner() */ public"; + + +// File: structgdcm_1_1Scanner_1_1ltstr.xml +%typemap("csclassmodifiers") gdcm::Scanner::ltstr " /**C++ includes: +gdcmScanner.h */ public class"; + + +// File: classgdcm_1_1SegmentedPaletteColorLookupTable.xml +%typemap("csclassmodifiers") gdcm::SegmentedPaletteColorLookupTable " +/** SegmentedPaletteColorLookupTable class. + +C++ includes: gdcmSegmentedPaletteColorLookupTable.h */ public class"; + +%csmethodmodifiers gdcm::SegmentedPaletteColorLookupTable::Print " +/** void gdcm::SegmentedPaletteColorLookupTable::Print(std::ostream &) +const */ public"; + +%csmethodmodifiers +gdcm::SegmentedPaletteColorLookupTable::SegmentedPaletteColorLookupTable +" /** +gdcm::SegmentedPaletteColorLookupTable::SegmentedPaletteColorLookupTable() +*/ public"; + +%csmethodmodifiers gdcm::SegmentedPaletteColorLookupTable::SetLUT " +/** void +gdcm::SegmentedPaletteColorLookupTable::SetLUT(LookupTableType type, +const unsigned char *array, unsigned int length) + +Initialize a SegmentedPaletteColorLookupTable. + +*/ public"; + +%csmethodmodifiers +gdcm::SegmentedPaletteColorLookupTable::~SegmentedPaletteColorLookupTable +" /** +gdcm::SegmentedPaletteColorLookupTable::~SegmentedPaletteColorLookupTable() +*/ public"; + + +// File: classgdcm_1_1SequenceOfFragments.xml +%typemap("csclassmodifiers") gdcm::SequenceOfFragments " /** Class to +represent a Sequence Of Fragments. + +Todo I do not enforce that Sequence of Fragments ends with a SQ end +del + +C++ includes: gdcmSequenceOfFragments.h */ public class"; + +%csmethodmodifiers gdcm::SequenceOfFragments::AddFragment " /** void +gdcm::SequenceOfFragments::AddFragment(Fragment const &item) + +Appends a Fragment to the already added ones. + +*/ public"; + +%csmethodmodifiers gdcm::SequenceOfFragments::Clear " /** void +gdcm::SequenceOfFragments::Clear() */ public"; + +%csmethodmodifiers gdcm::SequenceOfFragments::ComputeByteLength " /** +unsigned long gdcm::SequenceOfFragments::ComputeByteLength() const */ +public"; + +%csmethodmodifiers gdcm::SequenceOfFragments::ComputeLength " /** VL +gdcm::SequenceOfFragments::ComputeLength() const */ public"; + +%csmethodmodifiers gdcm::SequenceOfFragments::GetBuffer " /** bool +gdcm::SequenceOfFragments::GetBuffer(char *buffer, unsigned long +length) const */ public"; + +%csmethodmodifiers gdcm::SequenceOfFragments::GetFragBuffer " /** +bool gdcm::SequenceOfFragments::GetFragBuffer(unsigned int fragNb, +char *buffer, unsigned long &length) const */ public"; + +%csmethodmodifiers gdcm::SequenceOfFragments::GetFragment " /** const +Fragment& gdcm::SequenceOfFragments::GetFragment(unsigned int num) +const */ public"; + +%csmethodmodifiers gdcm::SequenceOfFragments::GetLength " /** VL +gdcm::SequenceOfFragments::GetLength() const + +Returns the SQ length, as read from disk. + +*/ public"; + +%csmethodmodifiers gdcm::SequenceOfFragments::GetNumberOfFragments " +/** unsigned int gdcm::SequenceOfFragments::GetNumberOfFragments() +const */ public"; + +%csmethodmodifiers gdcm::SequenceOfFragments::GetTable " /** +BasicOffsetTable& gdcm::SequenceOfFragments::GetTable() */ public"; + +%csmethodmodifiers gdcm::SequenceOfFragments::GetTable " /** const +BasicOffsetTable& gdcm::SequenceOfFragments::GetTable() const */ +public"; + +%csmethodmodifiers gdcm::SequenceOfFragments::Print " /** void +gdcm::SequenceOfFragments::Print(std::ostream &os) const */ public"; + +%csmethodmodifiers gdcm::SequenceOfFragments::Read " /** +std::istream& gdcm::SequenceOfFragments::Read(std::istream &is) */ +public"; + +%csmethodmodifiers gdcm::SequenceOfFragments::SequenceOfFragments " +/** gdcm::SequenceOfFragments::SequenceOfFragments() + +constructor (UndefinedLength by default) + +*/ public"; + +%csmethodmodifiers gdcm::SequenceOfFragments::SetLength " /** void +gdcm::SequenceOfFragments::SetLength(VL length) + +Sets the actual SQ length. + +*/ public"; + +%csmethodmodifiers gdcm::SequenceOfFragments::Write " /** +std::ostream const& gdcm::SequenceOfFragments::Write(std::ostream &os) +const */ public"; + +%csmethodmodifiers gdcm::SequenceOfFragments::WriteBuffer " /** bool +gdcm::SequenceOfFragments::WriteBuffer(std::ostream &os) const */ +public"; + + +// File: classgdcm_1_1SequenceOfItems.xml +%typemap("csclassmodifiers") gdcm::SequenceOfItems " /** Class to +represent a Sequence Of Items (value representation : SQ) a Value +Representation for Data Elements that contains a sequence of Data +Sets. + +Sequence of Item allows for Nested Data Sets. + +See PS 3.5, 7.4.6 Data Element Type Within a Sequence SEQUENCE OF +ITEMS (VALUE REPRESENTATION SQ) A Value Representation for Data +Elements that contain a sequence of Data Sets. Sequence of Items +allows for Nested Data Sets. + +C++ includes: gdcmSequenceOfItems.h */ public class"; + +%csmethodmodifiers gdcm::SequenceOfItems::AddItem " /** void +gdcm::SequenceOfItems::AddItem(Item const &item) + +Appends an Item to the already added ones. + +*/ public"; + +%csmethodmodifiers gdcm::SequenceOfItems::Begin " /** ConstIterator +gdcm::SequenceOfItems::Begin() const */ public"; + +%csmethodmodifiers gdcm::SequenceOfItems::Begin " /** Iterator +gdcm::SequenceOfItems::Begin() */ public"; + +%csmethodmodifiers gdcm::SequenceOfItems::Clear " /** void +gdcm::SequenceOfItems::Clear() */ public"; + +%csmethodmodifiers gdcm::SequenceOfItems::ComputeLength " /** VL +gdcm::SequenceOfItems::ComputeLength() const */ public"; + +%csmethodmodifiers gdcm::SequenceOfItems::End " /** ConstIterator +gdcm::SequenceOfItems::End() const */ public"; + +%csmethodmodifiers gdcm::SequenceOfItems::End " /** Iterator +gdcm::SequenceOfItems::End() */ public"; + +%csmethodmodifiers gdcm::SequenceOfItems::FindDataElement " /** bool +gdcm::SequenceOfItems::FindDataElement(const Tag &t) const */ +public"; + +%csmethodmodifiers gdcm::SequenceOfItems::GetItem " /** Item& +gdcm::SequenceOfItems::GetItem(unsigned int position) */ public"; + +%csmethodmodifiers gdcm::SequenceOfItems::GetItem " /** const Item& +gdcm::SequenceOfItems::GetItem(unsigned int position) const */ +public"; + +%csmethodmodifiers gdcm::SequenceOfItems::GetLength " /** VL +gdcm::SequenceOfItems::GetLength() const + +Returns the SQ length, as read from disk. + +*/ public"; + +%csmethodmodifiers gdcm::SequenceOfItems::GetNumberOfItems " /** +unsigned int gdcm::SequenceOfItems::GetNumberOfItems() const */ +public"; + +%csmethodmodifiers gdcm::SequenceOfItems::IsUndefinedLength " /** +bool gdcm::SequenceOfItems::IsUndefinedLength() const + +return if Value Length if of undefined length + +*/ public"; + +%csmethodmodifiers gdcm::SequenceOfItems::Print " /** void +gdcm::SequenceOfItems::Print(std::ostream &os) const */ public"; + +%csmethodmodifiers gdcm::SequenceOfItems::Read " /** std::istream& +gdcm::SequenceOfItems::Read(std::istream &is) */ public"; + +%csmethodmodifiers gdcm::SequenceOfItems::SequenceOfItems " /** +gdcm::SequenceOfItems::SequenceOfItems() + +constructor (UndefinedLength by default) + +*/ public"; + +%csmethodmodifiers gdcm::SequenceOfItems::SetLength " /** void +gdcm::SequenceOfItems::SetLength(VL length) + +Sets the actual SQ length. + +*/ public"; + +%csmethodmodifiers gdcm::SequenceOfItems::SetLengthToUndefined " /** +void gdcm::SequenceOfItems::SetLengthToUndefined() */ public"; + +%csmethodmodifiers gdcm::SequenceOfItems::Write " /** std::ostream +const& gdcm::SequenceOfItems::Write(std::ostream &os) const */ +public"; + + +// File: classgdcm_1_1SerieHelper.xml +%typemap("csclassmodifiers") gdcm::SerieHelper " /** DO NOT USE this +class, it is only a temporary solution for ITK migration from GDCM 1.x +to GDCM 2.x It will disapear soon, you've been warned. + +Instead see gdcm::ImageHelper or gdcm::IPPSorter + +C++ includes: gdcmSerieHelper.h */ public class"; + +%csmethodmodifiers gdcm::SerieHelper::AddRestriction " /** void +gdcm::SerieHelper::AddRestriction(uint16_t group, uint16_t elem, +std::string const &value, int op) */ public"; + +%csmethodmodifiers gdcm::SerieHelper::AddRestriction " /** void +gdcm::SerieHelper::AddRestriction(const std::string &tag) */ public"; + +%csmethodmodifiers gdcm::SerieHelper::Clear " /** void +gdcm::SerieHelper::Clear() */ public"; + +%csmethodmodifiers +gdcm::SerieHelper::CreateDefaultUniqueSeriesIdentifier " /** void +gdcm::SerieHelper::CreateDefaultUniqueSeriesIdentifier() */ public"; + +%csmethodmodifiers gdcm::SerieHelper::CreateUniqueSeriesIdentifier " +/** std::string gdcm::SerieHelper::CreateUniqueSeriesIdentifier(File +*inFile) */ public"; + +%csmethodmodifiers gdcm::SerieHelper::GetFirstSingleSerieUIDFileSet " +/** FileList* gdcm::SerieHelper::GetFirstSingleSerieUIDFileSet() */ +public"; + +%csmethodmodifiers gdcm::SerieHelper::GetNextSingleSerieUIDFileSet " +/** FileList* gdcm::SerieHelper::GetNextSingleSerieUIDFileSet() */ +public"; + +%csmethodmodifiers gdcm::SerieHelper::OrderFileList " /** void +gdcm::SerieHelper::OrderFileList(FileList *fileSet) */ public"; + +%csmethodmodifiers gdcm::SerieHelper::SerieHelper " /** +gdcm::SerieHelper::SerieHelper() */ public"; + +%csmethodmodifiers gdcm::SerieHelper::SetDirectory " /** void +gdcm::SerieHelper::SetDirectory(std::string const &dir, bool +recursive=false) */ public"; + +%csmethodmodifiers gdcm::SerieHelper::SetLoadMode " /** void +gdcm::SerieHelper::SetLoadMode(int) */ public"; + +%csmethodmodifiers gdcm::SerieHelper::SetUseSeriesDetails " /** void +gdcm::SerieHelper::SetUseSeriesDetails(bool useSeriesDetails) */ +public"; + +%csmethodmodifiers gdcm::SerieHelper::~SerieHelper " /** +gdcm::SerieHelper::~SerieHelper() */ public"; + + +// File: structgdcm_1_1SerieHelper_1_1Rule.xml + + +// File: classgdcm_1_1Series.xml +%typemap("csclassmodifiers") gdcm::Series " /** Series. + +C++ includes: gdcmSeries.h */ public class"; + +%csmethodmodifiers gdcm::Series::Series " /** gdcm::Series::Series() +*/ public"; + + +// File: classstd_1_1set.xml +%typemap("csclassmodifiers") std::set " /** STL class. + +*/ public class"; + + +// File: classstd_1_1set_1_1const__iterator.xml +%typemap("csclassmodifiers") std::set::const_iterator " /** STL +iterator class. + +*/ public class"; + + +// File: classstd_1_1set_1_1const__reverse__iterator.xml +%typemap("csclassmodifiers") std::set::const_reverse_iterator " /** +STL iterator class. + +*/ public class"; + + +// File: classstd_1_1set_1_1iterator.xml +%typemap("csclassmodifiers") std::set::iterator " /** STL iterator +class. + +*/ public class"; + + +// File: classstd_1_1set_1_1reverse__iterator.xml +%typemap("csclassmodifiers") std::set::reverse_iterator " /** STL +iterator class. + +*/ public class"; + + +// File: classgdcm_1_1SHA1.xml +%typemap("csclassmodifiers") gdcm::SHA1 " /**C++ includes: gdcmSHA1.h +*/ public class"; + +%csmethodmodifiers gdcm::SHA1::SHA1 " /** gdcm::SHA1::SHA1() */ +public"; + +%csmethodmodifiers gdcm::SHA1::~SHA1 " /** gdcm::SHA1::~SHA1() */ +public"; + + +// File: classgdcm_1_1SmartPointer.xml +%typemap("csclassmodifiers") gdcm::SmartPointer " /** Class for Smart +Pointer. + +Will only work for subclass of gdcm::Object See tr1/shared_ptr for a +more general approach (not invasive) include { +shared_ptr b(new Bla); } Class partly based on post by Bill +Hubauer:http://groups.google.com/group/comp.lang.c++/msg/173ddc38a827a930 + +See: http://www.davethehat.com/articles/smartp.htm and +itk::SmartPointer + +C++ includes: gdcmSmartPointer.h */ public class"; + +%csmethodmodifiers gdcm::SmartPointer::GetPointer " /** ObjectType* +gdcm::SmartPointer< ObjectType >::GetPointer() const + +Explicit function to retrieve the pointer. + +*/ public"; + +%csmethodmodifiers gdcm::SmartPointer::SmartPointer " /** +gdcm::SmartPointer< ObjectType >::SmartPointer(ObjectType const &p) +*/ public"; + +%csmethodmodifiers gdcm::SmartPointer::SmartPointer " /** +gdcm::SmartPointer< ObjectType >::SmartPointer(ObjectType *p) */ +public"; + +%csmethodmodifiers gdcm::SmartPointer::SmartPointer " /** +gdcm::SmartPointer< ObjectType >::SmartPointer(const SmartPointer< +ObjectType > &p) */ public"; + +%csmethodmodifiers gdcm::SmartPointer::SmartPointer " /** +gdcm::SmartPointer< ObjectType >::SmartPointer() */ public"; + +%csmethodmodifiers gdcm::SmartPointer::~SmartPointer " /** +gdcm::SmartPointer< ObjectType >::~SmartPointer() */ public"; + + +// File: classgdcm_1_1SOPClassUIDToIOD.xml +%typemap("csclassmodifiers") gdcm::SOPClassUIDToIOD " /** Class +convert a class uid into IOD. + +C++ includes: gdcmSOPClassUIDToIOD.h */ public class"; + + +// File: classgdcm_1_1Sorter.xml +%typemap("csclassmodifiers") gdcm::Sorter " /**C++ includes: +gdcmSorter.h */ public class"; + +%csmethodmodifiers gdcm::Sorter::AddSelect " /** bool +gdcm::Sorter::AddSelect(Tag const &tag, const char *value) + +UNSUPPORTED FOR NOW. + +*/ public"; + +%csmethodmodifiers gdcm::Sorter::GetFilenames " /** const +std::vector& gdcm::Sorter::GetFilenames() const + +Return the list of filenames as sorted by the specific algorithm used. +Empty by default (before Sort() is called) + +*/ public"; + +%csmethodmodifiers gdcm::Sorter::Print " /** void +gdcm::Sorter::Print(std::ostream &os) const + +Print. + +*/ public"; + +%csmethodmodifiers gdcm::Sorter::SetSortFunction " /** void +gdcm::Sorter::SetSortFunction(SortFunction f) */ public"; + +%csmethodmodifiers gdcm::Sorter::Sort " /** virtual bool +gdcm::Sorter::Sort(std::vector< std::string > const &filenames) + +Typically the output of gdcm::Directory::GetFilenames(). + +*/ public"; + +%csmethodmodifiers gdcm::Sorter::Sorter " /** gdcm::Sorter::Sorter() +*/ public"; + +%csmethodmodifiers gdcm::Sorter::StableSort " /** virtual bool +gdcm::Sorter::StableSort(std::vector< std::string > const &filenames) +*/ public"; + +%csmethodmodifiers gdcm::Sorter::~Sorter " /** virtual +gdcm::Sorter::~Sorter() */ public"; + + +// File: classgdcm_1_1Spacing.xml +%typemap("csclassmodifiers") gdcm::Spacing " /** Class for Spacing. + +See PS 3.3-2008, Table C.7-11b IMAGE PIXEL MACRO ATTRIBUTES + +Ratio of the vertical size and horizontal size of the pixels in the +image specified by a pair of integer values where the first value is +the vertical pixel size, and the second value is the horizontal pixel +size. Required if the aspect ratio values do not have a ratio of 1:1 +and the physical pixel spacing is not specified by Pixel Spacing +(0028,0030), or Imager Pixel Spacing (0018,1164) or Nominal Scanned +Pixel Spacing (0018,2010), either for the entire Image or per-frame in +a Functional Group Macro. See C.7.6.3.1.7. + +PS 3.3-2008 10.7.1.3 Pixel Spacing Value Order and Valid Values All +pixel spacing related attributes shall have non-zero values, except +when there is only a single row or column or pixel of data present, in +which case the corresponding value may be zero. + +Ref:http://apps.sourceforge.net/mediawiki/gdcm/index.php?title=Imager_Pixel_Spacing + +C++ includes: gdcmSpacing.h */ public class"; + +%csmethodmodifiers gdcm::Spacing::Spacing " /** +gdcm::Spacing::Spacing() */ public"; + +%csmethodmodifiers gdcm::Spacing::~Spacing " /** +gdcm::Spacing::~Spacing() */ public"; + + +// File: classgdcm_1_1Spectroscopy.xml +%typemap("csclassmodifiers") gdcm::Spectroscopy " /** Spectroscopy +class. + +C++ includes: gdcmSpectroscopy.h */ public class"; + +%csmethodmodifiers gdcm::Spectroscopy::Spectroscopy " /** +gdcm::Spectroscopy::Spectroscopy() */ public"; + + +// File: classgdcm_1_1SplitMosaicFilter.xml +%typemap("csclassmodifiers") gdcm::SplitMosaicFilter " /** +SplitMosaicFilter class Class to reshuffle bytes for a SIEMENS Mosaic +image. + +C++ includes: gdcmSplitMosaicFilter.h */ public class"; + +%csmethodmodifiers gdcm::SplitMosaicFilter::GetFile " /** const File& +gdcm::SplitMosaicFilter::GetFile() const */ public"; + +%csmethodmodifiers gdcm::SplitMosaicFilter::GetFile " /** File& +gdcm::SplitMosaicFilter::GetFile() */ public"; + +%csmethodmodifiers gdcm::SplitMosaicFilter::GetImage " /** Image& +gdcm::SplitMosaicFilter::GetImage() */ public"; + +%csmethodmodifiers gdcm::SplitMosaicFilter::GetImage " /** const +Image& gdcm::SplitMosaicFilter::GetImage() const */ public"; + +%csmethodmodifiers gdcm::SplitMosaicFilter::SetFile " /** void +gdcm::SplitMosaicFilter::SetFile(const File &f) */ public"; + +%csmethodmodifiers gdcm::SplitMosaicFilter::SetImage " /** void +gdcm::SplitMosaicFilter::SetImage(const Image &image) */ public"; + +%csmethodmodifiers gdcm::SplitMosaicFilter::Split " /** bool +gdcm::SplitMosaicFilter::Split() + +Split the SIEMENS MOSAIC image. + +*/ public"; + +%csmethodmodifiers gdcm::SplitMosaicFilter::SplitMosaicFilter " /** +gdcm::SplitMosaicFilter::SplitMosaicFilter() */ public"; + +%csmethodmodifiers gdcm::SplitMosaicFilter::~SplitMosaicFilter " /** +gdcm::SplitMosaicFilter::~SplitMosaicFilter() */ public"; + + +// File: classstd_1_1stack.xml +%typemap("csclassmodifiers") std::stack " /** STL class. + +*/ public class"; + + +// File: structgdcm_1_1static__assert__test.xml +%typemap("csclassmodifiers") gdcm::static_assert_test " /**C++ +includes: gdcmStaticAssert.h */ public class"; + + +// File: structgdcm_1_1STATIC__ASSERTION__FAILURE_3_01true_01_4.xml +%typemap("csclassmodifiers") gdcm::STATIC_ASSERTION_FAILURE< true > " +/**C++ includes: gdcmStaticAssert.h */ public class"; + + +// File: classgdcm_1_1String.xml +%typemap("csclassmodifiers") gdcm::String " /** String. + +TDelimiter template parameter is used to separate multiple String (VM1 +>) TMaxLength is only a hint. Noone actually respect the max length +TPadChar is the string padding (0 or space) + +C++ includes: gdcmString.h */ public class"; + +%csmethodmodifiers gdcm::String::IsValid " /** bool gdcm::String< +TDelimiter, TMaxLength, TPadChar >::IsValid() const + +return if string is valid + +*/ public"; + +%csmethodmodifiers gdcm::String::String " /** gdcm::String< +TDelimiter, TMaxLength, TPadChar >::String(const std::string &s, +size_type pos=0, size_type n=npos) */ public"; + +%csmethodmodifiers gdcm::String::String " /** gdcm::String< +TDelimiter, TMaxLength, TPadChar >::String(const value_type *s, +size_type n) */ public"; + +%csmethodmodifiers gdcm::String::String " /** gdcm::String< +TDelimiter, TMaxLength, TPadChar >::String(const value_type *s) */ +public"; + +%csmethodmodifiers gdcm::String::String " /** gdcm::String< +TDelimiter, TMaxLength, TPadChar >::String() + +String constructors. + +*/ public"; + +%csmethodmodifiers gdcm::String::Trim " /** std::string gdcm::String< +TDelimiter, TMaxLength, TPadChar >::Trim() const + +Trim function is required to return a std::string object, otherwise we +could not create a gdcm::String object with an odd number of bytes... + +*/ public"; + + +// File: classstd_1_1string.xml +%typemap("csclassmodifiers") std::string " /** STL class. + +*/ public class"; + + +// File: classstd_1_1string_1_1const__iterator.xml +%typemap("csclassmodifiers") std::string::const_iterator " /** STL +iterator class. + +*/ public class"; + + +// File: classstd_1_1string_1_1const__reverse__iterator.xml +%typemap("csclassmodifiers") std::string::const_reverse_iterator " /** +STL iterator class. + +*/ public class"; + + +// File: classstd_1_1string_1_1iterator.xml +%typemap("csclassmodifiers") std::string::iterator " /** STL iterator +class. + +*/ public class"; + + +// File: classstd_1_1string_1_1reverse__iterator.xml +%typemap("csclassmodifiers") std::string::reverse_iterator " /** STL +iterator class. + +*/ public class"; + + +// File: classgdcm_1_1StringFilter.xml +%typemap("csclassmodifiers") gdcm::StringFilter " /** StringFilter +StringFilter is the class that make gdcm2.x looks more like gdcm1 and +transform the binary blob contained in a DataElement into a string, +typically this is a nice feature to have for wrapped language. + +C++ includes: gdcmStringFilter.h */ public class"; + +%csmethodmodifiers gdcm::StringFilter::FromString " /** std::string +gdcm::StringFilter::FromString(const Tag &t, const char *value, VL +const &vl) */ public"; + +%csmethodmodifiers gdcm::StringFilter::GetFile " /** const File& +gdcm::StringFilter::GetFile() const */ public"; + +%csmethodmodifiers gdcm::StringFilter::GetFile " /** File& +gdcm::StringFilter::GetFile() */ public"; + +%csmethodmodifiers gdcm::StringFilter::SetDicts " /** void +gdcm::StringFilter::SetDicts(const Dicts &dicts) + +Allow user to pass in there own dicts. + +*/ public"; + +%csmethodmodifiers gdcm::StringFilter::SetFile " /** void +gdcm::StringFilter::SetFile(const File &f) + +Set/Get File. + +*/ public"; + +%csmethodmodifiers gdcm::StringFilter::StringFilter " /** +gdcm::StringFilter::StringFilter() */ public"; + +%csmethodmodifiers gdcm::StringFilter::ToString " /** std::string +gdcm::StringFilter::ToString(const Tag &t) const + +Convert to string the ByteValue contained in a DataElement. + +*/ public"; + +%csmethodmodifiers gdcm::StringFilter::ToStringPair " /** +std::pair +gdcm::StringFilter::ToStringPair(const Tag &t) const + +Convert to string the ByteValue contained in a DataElement the +returned elements are: pair.first : the name as found in the +dictionary of DataElement pari.second : the value encoded into a +string (US,UL...) are properly converted + +*/ public"; + +%csmethodmodifiers gdcm::StringFilter::UseDictAlways " /** void +gdcm::StringFilter::UseDictAlways(bool) */ public"; + +%csmethodmodifiers gdcm::StringFilter::~StringFilter " /** +gdcm::StringFilter::~StringFilter() */ public"; + + +// File: classstd_1_1stringstream.xml +%typemap("csclassmodifiers") std::stringstream " /** STL class. + +*/ public class"; + + +// File: classgdcm_1_1Study.xml +%typemap("csclassmodifiers") gdcm::Study " /** Study. + +C++ includes: gdcmStudy.h */ public class"; + +%csmethodmodifiers gdcm::Study::Study " /** gdcm::Study::Study() */ +public"; + + +// File: classgdcm_1_1SwapCode.xml +%typemap("csclassmodifiers") gdcm::SwapCode " /** SwapCode +representation. + +C++ includes: gdcmSwapCode.h */ public class"; + +%csmethodmodifiers gdcm::SwapCode::SwapCode " /** +gdcm::SwapCode::SwapCode(SwapCodeType sc=Unknown) */ public"; + + +// File: classgdcm_1_1SwapperDoOp.xml +%typemap("csclassmodifiers") gdcm::SwapperDoOp " /**C++ includes: +gdcmSwapper.h */ public class"; + + +// File: classgdcm_1_1SwapperNoOp.xml +%typemap("csclassmodifiers") gdcm::SwapperNoOp " /**C++ includes: +gdcmSwapper.h */ public class"; + + +// File: classgdcm_1_1System.xml +%typemap("csclassmodifiers") gdcm::System " /** Class to do system +operation. + +OS independant functionalities + +C++ includes: gdcmSystem.h */ public class"; + + +// File: classgdcm_1_1Table.xml +%typemap("csclassmodifiers") gdcm::Table " /** Table. + +C++ includes: gdcmTable.h */ public class"; + +%csmethodmodifiers gdcm::Table::GetTableEntry " /** const TableEntry& +gdcm::Table::GetTableEntry(const Tag &tag) const */ public"; + +%csmethodmodifiers gdcm::Table::InsertEntry " /** void +gdcm::Table::InsertEntry(Tag const &tag, TableEntry const &te) */ +public"; + +%csmethodmodifiers gdcm::Table::Table " /** gdcm::Table::Table() */ +public"; + +%csmethodmodifiers gdcm::Table::~Table " /** gdcm::Table::~Table() +*/ public"; + + +// File: classgdcm_1_1TableEntry.xml +%typemap("csclassmodifiers") gdcm::TableEntry " /** TableEntry. + +C++ includes: gdcmTableEntry.h */ public class"; + +%csmethodmodifiers gdcm::TableEntry::TableEntry " /** +gdcm::TableEntry::TableEntry(const char *attribute=0, Type const +&type=Type(), const char *des=0) */ public"; + +%csmethodmodifiers gdcm::TableEntry::~TableEntry " /** +gdcm::TableEntry::~TableEntry() */ public"; + + +// File: classgdcm_1_1TableReader.xml +%typemap("csclassmodifiers") gdcm::TableReader " /** Class for +representing a TableReader. + +This class is an empty shell meant to be derived + +C++ includes: gdcmTableReader.h */ public class"; + +%csmethodmodifiers gdcm::TableReader::CharacterDataHandler " /** +virtual void gdcm::TableReader::CharacterDataHandler(const char *data, +int length) */ public"; + +%csmethodmodifiers gdcm::TableReader::EndElement " /** virtual void +gdcm::TableReader::EndElement(const char *name) */ public"; + +%csmethodmodifiers gdcm::TableReader::GetDefs " /** const Defs& +gdcm::TableReader::GetDefs() const */ public"; + +%csmethodmodifiers gdcm::TableReader::GetFilename " /** const char* +gdcm::TableReader::GetFilename() */ public"; + +%csmethodmodifiers gdcm::TableReader::HandleIOD " /** void +gdcm::TableReader::HandleIOD(const char **atts) */ public"; + +%csmethodmodifiers gdcm::TableReader::HandleIODEntry " /** void +gdcm::TableReader::HandleIODEntry(const char **atts) */ public"; + +%csmethodmodifiers gdcm::TableReader::HandleMacro " /** void +gdcm::TableReader::HandleMacro(const char **atts) */ public"; + +%csmethodmodifiers gdcm::TableReader::HandleMacroEntry " /** void +gdcm::TableReader::HandleMacroEntry(const char **atts) */ public"; + +%csmethodmodifiers gdcm::TableReader::HandleMacroEntryDescription " +/** void gdcm::TableReader::HandleMacroEntryDescription(const char +**atts) */ public"; + +%csmethodmodifiers gdcm::TableReader::HandleModule " /** void +gdcm::TableReader::HandleModule(const char **atts) */ public"; + +%csmethodmodifiers gdcm::TableReader::HandleModuleEntry " /** void +gdcm::TableReader::HandleModuleEntry(const char **atts) */ public"; + +%csmethodmodifiers gdcm::TableReader::HandleModuleEntryDescription " +/** void gdcm::TableReader::HandleModuleEntryDescription(const char +**atts) */ public"; + +%csmethodmodifiers gdcm::TableReader::Read " /** int +gdcm::TableReader::Read() */ public"; + +%csmethodmodifiers gdcm::TableReader::SetFilename " /** void +gdcm::TableReader::SetFilename(const char *filename) */ public"; + +%csmethodmodifiers gdcm::TableReader::StartElement " /** virtual void +gdcm::TableReader::StartElement(const char *name, const char **atts) +*/ public"; + +%csmethodmodifiers gdcm::TableReader::TableReader " /** +gdcm::TableReader::TableReader(Defs &defs) */ public"; + +%csmethodmodifiers gdcm::TableReader::~TableReader " /** virtual +gdcm::TableReader::~TableReader() */ public"; + + +// File: classgdcm_1_1Tag.xml +%typemap("csclassmodifiers") gdcm::Tag " /** Class to represent a +DICOM Data Element ( Attribute) Tag (Group, Element). Basically an +uint32_t which can also be expressed as two uint16_t (group and +element). + +DATA ELEMENT TAG: A unique identifier for a Data Element composed of +an ordered pair of numbers (a Group Number followed by an Element +Number). GROUP NUMBER: The first number in the ordered pair of numbers +that makes up a Data Element Tag. ELEMENT NUMBER: The second number in +the ordered pair of numbers that makes up a Data Element Tag. + +C++ includes: gdcmTag.h */ public class"; + +%csmethodmodifiers gdcm::Tag::GetElement " /** uint16_t +gdcm::Tag::GetElement() const + +Returns the 'Element number' of the given Tag. + +*/ public"; + +%csmethodmodifiers gdcm::Tag::GetElementTag " /** uint32_t +gdcm::Tag::GetElementTag() const + +Returns the full tag value of the given Tag. + +*/ public"; + +%csmethodmodifiers gdcm::Tag::GetGroup " /** uint16_t +gdcm::Tag::GetGroup() const + +Returns the 'Group number' of the given Tag. + +*/ public"; + +%csmethodmodifiers gdcm::Tag::GetLength " /** uint32_t +gdcm::Tag::GetLength() const + +return the length of tag (read: size on disk) + +*/ public"; + +%csmethodmodifiers gdcm::Tag::GetPrivateCreator " /** Tag +gdcm::Tag::GetPrivateCreator() const + +Return the Private Creator Data Element tag of a private data element. + +*/ public"; + +%csmethodmodifiers gdcm::Tag::IsGroupLength " /** bool +gdcm::Tag::IsGroupLength() const + +return whether the tag correspond to a group length tag: + +*/ public"; + +%csmethodmodifiers gdcm::Tag::IsGroupXX " /** bool +gdcm::Tag::IsGroupXX(const Tag &t) const + +e.g 6002,3000 belong to groupXX: 6000,3000 + +*/ public"; + +%csmethodmodifiers gdcm::Tag::IsIllegal " /** bool +gdcm::Tag::IsIllegal() const + +return if the tag is considered to be an illegal tag + +*/ public"; + +%csmethodmodifiers gdcm::Tag::IsPrivate " /** bool +gdcm::Tag::IsPrivate() const + +PRIVATE DATA ELEMENT: Additional Data Element, defined by an +implementor, to communicate information that is not contained in +Standard Data Elements. Private Data elements have odd Group Numbers. + +*/ public"; + +%csmethodmodifiers gdcm::Tag::IsPrivateCreator " /** bool +gdcm::Tag::IsPrivateCreator() const + +Returns if tag is a Private Creator (xxxx,00yy), where xxxx is odd +number and yy in [0x10,0xFF]. + +*/ public"; + +%csmethodmodifiers gdcm::Tag::IsPublic " /** bool +gdcm::Tag::IsPublic() const + +STANDARD DATA ELEMENT: A Data Element defined in the DICOM Standard, +and therefore listed in the DICOM Data Element Dictionary in PS 3.6. +Is the Tag from the Public dict...well the implementation is buggy it +does not prove the element is indeed in the dict... + +*/ public"; + +%csmethodmodifiers gdcm::Tag::PrintAsPipeSeparatedString " /** +std::string gdcm::Tag::PrintAsPipeSeparatedString() const + +Print as a pipe separated string (GDCM 1.x compat only). Do not use in +newer code See: ReadFromPipeSeparatedString + +*/ public"; + +%csmethodmodifiers gdcm::Tag::Read " /** std::istream& +gdcm::Tag::Read(std::istream &is) + +Read a tag from binary representation. + +*/ public"; + +%csmethodmodifiers gdcm::Tag::ReadFromCommaSeparatedString " /** bool +gdcm::Tag::ReadFromCommaSeparatedString(const char *str) + +Read from a comma separated string. This is a highly user oriented +function, the string should be formated as: 1234,5678 to specify the +tag (0x1234,0x5678) The notation comes from the DICOM standard, and is +handy to use from a command line program + +*/ public"; + +%csmethodmodifiers gdcm::Tag::ReadFromPipeSeparatedString " /** bool +gdcm::Tag::ReadFromPipeSeparatedString(const char *str) + +Read from a pipe separated string (GDCM 1.x compat only). Do not use +in newer code See: ReadFromCommaSeparatedString + +*/ public"; + +%csmethodmodifiers gdcm::Tag::SetElement " /** void +gdcm::Tag::SetElement(uint16_t element) + +Sets the 'Element number' of the given Tag. + +*/ public"; + +%csmethodmodifiers gdcm::Tag::SetElementTag " /** void +gdcm::Tag::SetElementTag(uint32_t tag) + +Sets the full tag value of the given Tag. + +*/ public"; + +%csmethodmodifiers gdcm::Tag::SetElementTag " /** void +gdcm::Tag::SetElementTag(uint16_t group, uint16_t element) + +Sets the 'Group number' & 'Element number' of the given Tag. + +*/ public"; + +%csmethodmodifiers gdcm::Tag::SetGroup " /** void +gdcm::Tag::SetGroup(uint16_t group) + +Sets the 'Group number' of the given Tag. + +*/ public"; + +%csmethodmodifiers gdcm::Tag::SetPrivateCreator " /** void +gdcm::Tag::SetPrivateCreator(Tag const &t) + +Set private creator:. + +*/ public"; + +%csmethodmodifiers gdcm::Tag::Tag " /** gdcm::Tag::Tag(const Tag +&_val) */ public"; + +%csmethodmodifiers gdcm::Tag::Tag " /** gdcm::Tag::Tag(uint32_t +tag=0) + +Constructor with 1*uint32_t Prefer the cstor that takes two uint16_t. + +*/ public"; + +%csmethodmodifiers gdcm::Tag::Tag " /** gdcm::Tag::Tag(uint16_t +group, uint16_t element) + +Constructor with 2*uint16_t. + +*/ public"; + +%csmethodmodifiers gdcm::Tag::Write " /** const std::ostream& +gdcm::Tag::Write(std::ostream &os) const + +Write a tag in binary rep. + +*/ public"; + + +// File: classgdcm_1_1TagPath.xml +%typemap("csclassmodifiers") gdcm::TagPath " /** class to handle a +path of tag. + +Any Resemblance to Existing XPath is Purely Coincidental + +C++ includes: gdcmTagPath.h */ public class"; + +%csmethodmodifiers gdcm::TagPath::ConstructFromString " /** bool +gdcm::TagPath::ConstructFromString(const char *path) + +\"/0018,0018/\"... No space allowed, comma is use to separate tag +group from tag element and slash is used to separate tag return false +if invalid + +*/ public"; + +%csmethodmodifiers gdcm::TagPath::ConstructFromTagList " /** bool +gdcm::TagPath::ConstructFromTagList(Tag const *l, unsigned int n) + +Construct from a list of tags. + +*/ public"; + +%csmethodmodifiers gdcm::TagPath::Print " /** void +gdcm::TagPath::Print(std::ostream &) const */ public"; + +%csmethodmodifiers gdcm::TagPath::Push " /** bool +gdcm::TagPath::Push(unsigned int itemnum) */ public"; + +%csmethodmodifiers gdcm::TagPath::Push " /** bool +gdcm::TagPath::Push(Tag const &t) */ public"; + +%csmethodmodifiers gdcm::TagPath::TagPath " /** +gdcm::TagPath::TagPath() */ public"; + +%csmethodmodifiers gdcm::TagPath::~TagPath " /** +gdcm::TagPath::~TagPath() */ public"; + + +// File: classgdcm_1_1Testing.xml +%typemap("csclassmodifiers") gdcm::Testing " /** class for testing + +this class is used for the nightly regression system for GDCM It makes +heavily use of md5 computation + +See: gdcm::MD5 class for md5 computation + +C++ includes: gdcmTesting.h */ public class"; + +%csmethodmodifiers gdcm::Testing::Print " /** void +gdcm::Testing::Print(std::ostream &os=std::cout) + +Print. + +*/ public"; + +%csmethodmodifiers gdcm::Testing::Testing " /** +gdcm::Testing::Testing() */ public"; + +%csmethodmodifiers gdcm::Testing::~Testing " /** +gdcm::Testing::~Testing() */ public"; + + +// File: classgdcm_1_1Trace.xml +%typemap("csclassmodifiers") gdcm::Trace " /** Trace. + +Debug / Warning and Error are encapsulated in this class + +C++ includes: gdcmTrace.h */ public class"; + +%csmethodmodifiers gdcm::Trace::Trace " /** gdcm::Trace::Trace() */ +public"; + +%csmethodmodifiers gdcm::Trace::~Trace " /** gdcm::Trace::~Trace() +*/ public"; + + +// File: classgdcm_1_1TransferSyntax.xml +%typemap("csclassmodifiers") gdcm::TransferSyntax " /** Class to +manipulate Transfer Syntax. + +TRANSFER SYNTAX (Standard and Private): A set of encoding rules that +allow Application Entities to unambiguously negotiate the encoding +techniques (e.g., Data Element structure, byte ordering, compression) +they are able to support, thereby allowing these Application Entities +to communicate. Todo : The implementation is completely retarded -> +see gdcm::UIDs for a replacement We need: IsSupported We need +preprocess of raw/xml file We need GetFullName() Need a notion of +Private Syntax. As defined in Ps 3.5. Section 9.2 + +C++ includes: gdcmTransferSyntax.h */ public class"; + +%csmethodmodifiers gdcm::TransferSyntax::GetNegociatedType " /** +NegociatedType gdcm::TransferSyntax::GetNegociatedType() const */ +public"; + +%csmethodmodifiers gdcm::TransferSyntax::GetString " /** const char* +gdcm::TransferSyntax::GetString() const */ public"; + +%csmethodmodifiers gdcm::TransferSyntax::GetSwapCode " /** SwapCode +gdcm::TransferSyntax::GetSwapCode() const */ public"; + +%csmethodmodifiers gdcm::TransferSyntax::IsEncapsulated " /** bool +gdcm::TransferSyntax::IsEncapsulated() const */ public"; + +%csmethodmodifiers gdcm::TransferSyntax::IsEncoded " /** bool +gdcm::TransferSyntax::IsEncoded() const */ public"; + +%csmethodmodifiers gdcm::TransferSyntax::IsExplicit " /** bool +gdcm::TransferSyntax::IsExplicit() const */ public"; + +%csmethodmodifiers gdcm::TransferSyntax::IsImplicit " /** bool +gdcm::TransferSyntax::IsImplicit() const */ public"; + +%csmethodmodifiers gdcm::TransferSyntax::IsLossless " /** bool +gdcm::TransferSyntax::IsLossless() const */ public"; + +%csmethodmodifiers gdcm::TransferSyntax::IsLossy " /** bool +gdcm::TransferSyntax::IsLossy() const + +Return whether the Transfer Syntax contains a lossy or lossless +Encapsulated stream WARNING: IsLossy is NOT !IsLossless since JPEG +2000 Transfer Syntax is dual the stream can be either lossy or +lossless compressed. + +*/ public"; + +%csmethodmodifiers gdcm::TransferSyntax::IsValid " /** bool +gdcm::TransferSyntax::IsValid() const */ public"; + +%csmethodmodifiers gdcm::TransferSyntax::TransferSyntax " /** +gdcm::TransferSyntax::TransferSyntax(TSType +type=ImplicitVRLittleEndian) */ public"; + + +// File: classgdcm_1_1Type.xml +%typemap("csclassmodifiers") gdcm::Type " /** Type. + +PS 3.5 7.4 DATA ELEMENT TYPE 7.4.1 TYPE 1 REQUIRED DATA ELEMENTS 7.4.2 +TYPE 1C CONDITIONAL DATA ELEMENTS 7.4.3 TYPE 2 REQUIRED DATA ELEMENTS +7.4.4 TYPE 2C CONDITIONAL DATA ELEMENTS 7.4.5 TYPE 3 OPTIONAL DATA +ELEMENTS The intent of Type 2 Data Elements is to allow a zero length +to be conveyed when the operator or application does not know its +value or has a specific reason for not specifying its value. It is the +intent that the device should support these Data Elements. + +C++ includes: gdcmType.h */ public class"; + +%csmethodmodifiers gdcm::Type::Type " /** gdcm::Type::Type(TypeType +type=UNKNOWN) */ public"; + + +// File: structgdcm_1_1UI.xml +%typemap("csclassmodifiers") gdcm::UI " /**C++ includes: gdcmVR.h */ +public class"; + + +// File: classgdcm_1_1UIDGenerator.xml +%typemap("csclassmodifiers") gdcm::UIDGenerator " /** Class for +generating unique UID. + +bla Usage: When constructing a Series or Study UID, user *has* to keep +around the UID, otherwise the UID Generator will simply forget the +value and create a new UID. + +C++ includes: gdcmUIDGenerator.h */ public class"; + +%csmethodmodifiers gdcm::UIDGenerator::Generate " /** const char* +gdcm::UIDGenerator::Generate() + +Internally uses a std::string, so two calls have the same pointer ! +save into a std::string In summary do not write code like that: const +char *uid1 = uid.Generate(); const char *uid2 = uid.Generate(); since +uid1 == uid2 + +*/ public"; + +%csmethodmodifiers gdcm::UIDGenerator::UIDGenerator " /** +gdcm::UIDGenerator::UIDGenerator() + +By default the root of a UID is a GDCM Root... + +*/ public"; + + +// File: classgdcm_1_1UIDs.xml +%typemap("csclassmodifiers") gdcm::UIDs " /** all known uids + +C++ includes: gdcmUIDs.h */ public class"; + +%csmethodmodifiers gdcm::UIDs::GetName " /** const char* +gdcm::UIDs::GetName() const + +When object is Initialize function return the well known name +associated with uid return NULL when not initialized + +*/ public"; + +%csmethodmodifiers gdcm::UIDs::GetString " /** const char* +gdcm::UIDs::GetString() const + +When object is Initialize function return the uid return NULL when not +initialized + +*/ public"; + +%csmethodmodifiers gdcm::UIDs::SetFromUID " /** bool +gdcm::UIDs::SetFromUID(const char *str) + +Initialize object from a string (a uid number) return false on error, +and internal state is set to 0 + +*/ public"; + + +// File: classstd_1_1underflow__error.xml +%typemap("csclassmodifiers") std::underflow_error " /** STL class. + +*/ public class"; + + +// File: classgdcm_1_1UNExplicitDataElement.xml +%typemap("csclassmodifiers") gdcm::UNExplicitDataElement " /** Class +to read/write a DataElement as UNExplicit Data Element. + +bla + +C++ includes: gdcmUNExplicitDataElement.h */ public class"; + +%csmethodmodifiers gdcm::UNExplicitDataElement::GetLength " /** VL +gdcm::UNExplicitDataElement::GetLength() const */ public"; + +%csmethodmodifiers gdcm::UNExplicitDataElement::Read " /** +std::istream& gdcm::UNExplicitDataElement::Read(std::istream &is) */ +public"; + +%csmethodmodifiers gdcm::UNExplicitDataElement::ReadWithLength " /** +std::istream& gdcm::UNExplicitDataElement::ReadWithLength(std::istream +&is, VL &length) */ public"; + + +// File: classgdcm_1_1UNExplicitImplicitDataElement.xml +%typemap("csclassmodifiers") gdcm::UNExplicitImplicitDataElement " /** +Class to read/write a DataElement as ExplicitImplicit Data Element +This class gather two known bugs: 1. GDCM 1.2.0 would rewrite VR=UN +Value Length on 2 bytes instead of 4 bytes 2. GDCM 1.2.0 would also +rewrite DataElement as Implicit when the VR would not be known this +would only happen in some very rare cases. gdcm 2.X design could +handle bug #1 or #2 exclusively, this class can now handle file which +have both issues. See: gdcmData/TheralysGDCM120Bug.dcm. + +C++ includes: gdcmUNExplicitImplicitDataElement.h */ public class"; + +%csmethodmodifiers gdcm::UNExplicitImplicitDataElement::GetLength " +/** VL gdcm::UNExplicitImplicitDataElement::GetLength() const */ +public"; + +%csmethodmodifiers gdcm::UNExplicitImplicitDataElement::Read " /** +std::istream& gdcm::UNExplicitImplicitDataElement::Read(std::istream +&is) */ public"; + + +// File: classgdcm_1_1Unpacker12Bits.xml +%typemap("csclassmodifiers") gdcm::Unpacker12Bits " /** Pack/Unpack 12 +bits pixel into 16bits You can only pack an even number of 16bits, +which means a multiple of 4 (expressed in bytes) + +You can only unpack a multiple of 3 bytes. + +C++ includes: gdcmUnpacker12Bits.h */ public class"; + + +// File: classgdcm_1_1Usage.xml +%typemap("csclassmodifiers") gdcm::Usage " /** Usage. + +A.1.3 IOD Module Table and Functional Group Macro Table This Section +of each IOD defines in a tabular form the Modules comprising the IOD. +The following information must be specified for each Module in the +table: The name of the Module or Functional Group + +A reference to the Section in Annex C which defines the Module or +Functional Group + +The usage of the Module or Functional Group; whether it is: + +Mandatory (see A.1.3.1) , abbreviated M + +Conditional (see A.1.3.2) , abbreviated C + +User Option (see A.1.3.3) , abbreviated U The Modules referenced are +defined in Annex C. A.1.3.1 MANDATORY MODULES For each IOD, Mandatory +Modules shall be supported per the definitions, semantics and +requirements defined in Annex C. + +A.1.3.2 CONDITIONAL MODULES Conditional Modules are Mandatory Modules +if specific conditions are met. If the specified conditions are not +met, this Module shall not be supported; that is, no information +defined in that Module shall be sent. A.1.3.3 USER OPTION MODULES User +Option Modules may or may not be supported. If an optional Module is +supported, the Attribute Types specified in the Modules in Annex C +shall be supported. + +C++ includes: gdcmUsage.h */ public class"; + +%csmethodmodifiers gdcm::Usage::Usage " /** +gdcm::Usage::Usage(UsageType type=Invalid) */ public"; + + +// File: classstd_1_1valarray.xml +%typemap("csclassmodifiers") std::valarray " /** STL class. + +*/ public class"; + + +// File: classgdcm_1_1Validate.xml +%typemap("csclassmodifiers") gdcm::Validate " /** Validate class. + +C++ includes: gdcmValidate.h */ public class"; + +%csmethodmodifiers gdcm::Validate::GetValidatedFile " /** const File& +gdcm::Validate::GetValidatedFile() */ public"; + +%csmethodmodifiers gdcm::Validate::SetFile " /** void +gdcm::Validate::SetFile(File const &f) */ public"; + +%csmethodmodifiers gdcm::Validate::Validate " /** +gdcm::Validate::Validate() */ public"; + +%csmethodmodifiers gdcm::Validate::Validation " /** void +gdcm::Validate::Validation() */ public"; + +%csmethodmodifiers gdcm::Validate::~Validate " /** +gdcm::Validate::~Validate() */ public"; + + +// File: classgdcm_1_1Value.xml +%typemap("csclassmodifiers") gdcm::Value " /** Class to represent the +value of a Data Element. + +VALUE: A component of a Value Field. A Value Field may consist of one +or more of these components. + +C++ includes: gdcmValue.h */ public class"; + +%csmethodmodifiers gdcm::Value::Clear " /** virtual void +gdcm::Value::Clear()=0 */ public"; + +%csmethodmodifiers gdcm::Value::GetLength " /** virtual VL +gdcm::Value::GetLength() const =0 */ public"; + +%csmethodmodifiers gdcm::Value::SetLength " /** virtual void +gdcm::Value::SetLength(VL l)=0 */ public"; + +%csmethodmodifiers gdcm::Value::Value " /** gdcm::Value::Value() */ +public"; + +%csmethodmodifiers gdcm::Value::~Value " /** gdcm::Value::~Value() +*/ public"; + + +// File: classgdcm_1_1ValueIO.xml +%typemap("csclassmodifiers") gdcm::ValueIO " /** Class to represent +the value of a Data Element. + +VALUE: A component of a Value Field. A Value Field may consist of one +or more of these components. + +C++ includes: gdcmValueIO.h */ public class"; + + +// File: classstd_1_1vector.xml +%typemap("csclassmodifiers") std::vector " /** STL class. + +*/ public class"; + + +// File: classstd_1_1vector_1_1const__iterator.xml +%typemap("csclassmodifiers") std::vector::const_iterator " /** STL +iterator class. + +*/ public class"; + + +// File: classstd_1_1vector_1_1const__reverse__iterator.xml +%typemap("csclassmodifiers") std::vector::const_reverse_iterator " /** +STL iterator class. + +*/ public class"; + + +// File: classstd_1_1vector_1_1iterator.xml +%typemap("csclassmodifiers") std::vector::iterator " /** STL iterator +class. + +*/ public class"; + + +// File: classstd_1_1vector_1_1reverse__iterator.xml +%typemap("csclassmodifiers") std::vector::reverse_iterator " /** STL +iterator class. + +*/ public class"; + + +// File: classgdcm_1_1Version.xml +%typemap("csclassmodifiers") gdcm::Version " /** major/minor and build +version + +C++ includes: gdcmVersion.h */ public class"; + + +// File: classgdcm_1_1VL.xml +%typemap("csclassmodifiers") gdcm::VL " /** Value Length. + +WARNING: this is a 4bytes value ! Do not try to use it for 2bytes +value length + +C++ includes: gdcmVL.h */ public class"; + +%csmethodmodifiers gdcm::VL::GetLength " /** VL gdcm::VL::GetLength() +const */ public"; + +%csmethodmodifiers gdcm::VL::IsOdd " /** bool gdcm::VL::IsOdd() const +*/ public"; + +%csmethodmodifiers gdcm::VL::IsUndefined " /** bool +gdcm::VL::IsUndefined() const */ public"; + +%csmethodmodifiers gdcm::VL::Read " /** std::istream& +gdcm::VL::Read(std::istream &is) */ public"; + +%csmethodmodifiers gdcm::VL::Read16 " /** std::istream& +gdcm::VL::Read16(std::istream &is) */ public"; + +%csmethodmodifiers gdcm::VL::SetToUndefined " /** void +gdcm::VL::SetToUndefined() */ public"; + +%csmethodmodifiers gdcm::VL::VL " /** gdcm::VL::VL(uint32_t vl=0) */ +public"; + +%csmethodmodifiers gdcm::VL::Write " /** const std::ostream& +gdcm::VL::Write(std::ostream &os) const */ public"; + +%csmethodmodifiers gdcm::VL::Write16 " /** const std::ostream& +gdcm::VL::Write16(std::ostream &os) const */ public"; + + +// File: classgdcm_1_1VM.xml +%typemap("csclassmodifiers") gdcm::VM " /** Value Multiplicity +Looking at the DICOMV3 dict only there is very few cases: 1 2 3 4 5 6 +8 16 24 1-2 1-3 1-8 1-32 1-99 1-n 2-2n 2-n 3-3n 3-n. + +Some private dict define some more: 4-4n 1-4 1-5 256 9 3-4 + +even more: + +7-7n 10 18 12 35 47_47n 30_30n 28 + +6-6n + +C++ includes: gdcmVM.h */ public class"; + +%csmethodmodifiers gdcm::VM::Compatible " /** bool +gdcm::VM::Compatible(VM const &vm) const + +WARNING: Implementation deficiency The Compatible function is poorly +implemented, the reference vm should be coming from the dictionary, +while the passed in value is the value guess from the file. + +*/ public"; + +%csmethodmodifiers gdcm::VM::GetLength " /** unsigned int +gdcm::VM::GetLength() const */ public"; + +%csmethodmodifiers gdcm::VM::VM " /** gdcm::VM::VM(VMType type=VM0) +*/ public"; + + +// File: classgdcm_1_1VR.xml +%typemap("csclassmodifiers") gdcm::VR " /** VR class This is adapted +from DICOM standard The biggest difference is the INVALID VR and the +composite one that differ from standard (more like an addition) This +allow us to represent all the possible case express in the DICOMV3 +dict. + +VALUE REPRESENTATION ( VR) Specifies the data type and format of the +Value(s) contained in the Value Field of a Data Element. VALUE +REPRESENTATION FIELD: The field where the Value Representation of a +Data Element is stored in the encoding of a Data Element structure +with explicit VR. + +C++ includes: gdcmVR.h */ public class"; + +%csmethodmodifiers gdcm::VR::Compatible " /** bool +gdcm::VR::Compatible(VR const &vr) const */ public"; + +%csmethodmodifiers gdcm::VR::GetLength " /** int +gdcm::VR::GetLength() const */ public"; + +%csmethodmodifiers gdcm::VR::GetSize " /** unsigned int +gdcm::VR::GetSize() const */ public"; + +%csmethodmodifiers gdcm::VR::GetSizeof " /** unsigned int +gdcm::VR::GetSizeof() const */ public"; + +%csmethodmodifiers gdcm::VR::IsDual " /** bool gdcm::VR::IsDual() +const */ public"; + +%csmethodmodifiers gdcm::VR::IsVRFile " /** bool gdcm::VR::IsVRFile() +const */ public"; + +%csmethodmodifiers gdcm::VR::Read " /** std::istream& +gdcm::VR::Read(std::istream &is) */ public"; + +%csmethodmodifiers gdcm::VR::VR " /** gdcm::VR::VR(VRType vr=INVALID) +*/ public"; + +%csmethodmodifiers gdcm::VR::Write " /** const std::ostream& +gdcm::VR::Write(std::ostream &os) const */ public"; + + +// File: classgdcm_1_1VR16ExplicitDataElement.xml +%typemap("csclassmodifiers") gdcm::VR16ExplicitDataElement " /** Class +to read/write a DataElement as Explicit Data Element. + +This class support 16 bits when finding an unkown VR: For instance: +Siemens_CT_Sensation64_has_VR_RT.dcm + +C++ includes: gdcmVR16ExplicitDataElement.h */ public class"; + +%csmethodmodifiers gdcm::VR16ExplicitDataElement::GetLength " /** VL +gdcm::VR16ExplicitDataElement::GetLength() const */ public"; + +%csmethodmodifiers gdcm::VR16ExplicitDataElement::Read " /** +std::istream& gdcm::VR16ExplicitDataElement::Read(std::istream &is) +*/ public"; + +%csmethodmodifiers gdcm::VR16ExplicitDataElement::ReadWithLength " +/** std::istream& +gdcm::VR16ExplicitDataElement::ReadWithLength(std::istream &is, VL +&length) */ public"; + + +// File: classgdcm_1_1VRVLSize_3_010_01_4.xml +%typemap("csclassmodifiers") gdcm::VRVLSize< 0 > " /**C++ includes: +gdcmAttribute.h */ public class"; + + +// File: classgdcm_1_1VRVLSize_3_011_01_4.xml +%typemap("csclassmodifiers") gdcm::VRVLSize< 1 > " /**C++ includes: +gdcmAttribute.h */ public class"; + + +// File: classvtkGDCMImageReader.xml +%typemap("csclassmodifiers") vtkGDCMImageReader " /**C++ includes: +vtkGDCMImageReader.h */ public class"; + +%csmethodmodifiers vtkGDCMImageReader::CanReadFile " /** virtual int +vtkGDCMImageReader::CanReadFile(const char *fname) */ public"; + +%csmethodmodifiers vtkGDCMImageReader::GetDescriptiveName " /** +virtual const char* vtkGDCMImageReader::GetDescriptiveName() */ +public"; + +%csmethodmodifiers vtkGDCMImageReader::GetFileExtensions " /** +virtual const char* vtkGDCMImageReader::GetFileExtensions() */ +public"; + +%csmethodmodifiers vtkGDCMImageReader::GetIconImage " /** +vtkImageData* vtkGDCMImageReader::GetIconImage() */ public"; + +%csmethodmodifiers vtkGDCMImageReader::GetOverlay " /** vtkImageData* +vtkGDCMImageReader::GetOverlay(int i) */ public"; + +%csmethodmodifiers vtkGDCMImageReader::PrintSelf " /** virtual void +vtkGDCMImageReader::PrintSelf(ostream &os, vtkIndent indent) */ +public"; + +%csmethodmodifiers vtkGDCMImageReader::SetCurve " /** virtual void +vtkGDCMImageReader::SetCurve(vtkPolyData *pd) */ public"; + +%csmethodmodifiers vtkGDCMImageReader::SetFileNames " /** virtual +void vtkGDCMImageReader::SetFileNames(vtkStringArray *) */ public"; + +%csmethodmodifiers vtkGDCMImageReader::vtkBooleanMacro " /** int +vtkGDCMImageReader::vtkBooleanMacro(ApplyYBRToRGB, int) */ public"; + +%csmethodmodifiers vtkGDCMImageReader::vtkBooleanMacro " /** +vtkGDCMImageReader::vtkBooleanMacro(ApplyLookupTable, int) */ +public"; + +%csmethodmodifiers vtkGDCMImageReader::vtkBooleanMacro " /** +vtkGDCMImageReader::vtkBooleanMacro(LossyFlag, int) */ public"; + +%csmethodmodifiers vtkGDCMImageReader::vtkBooleanMacro " /** +vtkGDCMImageReader::vtkBooleanMacro(LoadIconImage, int) */ public"; + +%csmethodmodifiers vtkGDCMImageReader::vtkBooleanMacro " /** +vtkGDCMImageReader::vtkBooleanMacro(LoadOverlays, int) */ public"; + +%csmethodmodifiers vtkGDCMImageReader::vtkGetMacro " /** +vtkGDCMImageReader::vtkGetMacro(Scale, double) */ public"; + +%csmethodmodifiers vtkGDCMImageReader::vtkGetMacro " /** +vtkGDCMImageReader::vtkGetMacro(Shift, double) */ public"; + +%csmethodmodifiers vtkGDCMImageReader::vtkGetMacro " /** +vtkGDCMImageReader::vtkGetMacro(PlanarConfiguration, int) */ public"; + +%csmethodmodifiers vtkGDCMImageReader::vtkGetMacro " /** +vtkGDCMImageReader::vtkGetMacro(ImageFormat, int) */ public"; + +%csmethodmodifiers vtkGDCMImageReader::vtkGetMacro " /** +vtkGDCMImageReader::vtkGetMacro(ApplyYBRToRGB, int) +vtkSetMacro(ApplyYBRToRGB */ public"; + +%csmethodmodifiers vtkGDCMImageReader::vtkGetMacro " /** +vtkGDCMImageReader::vtkGetMacro(ApplyLookupTable, int) */ public"; + +%csmethodmodifiers vtkGDCMImageReader::vtkGetMacro " /** +vtkGDCMImageReader::vtkGetMacro(NumberOfIconImages, int) */ public"; + +%csmethodmodifiers vtkGDCMImageReader::vtkGetMacro " /** +vtkGDCMImageReader::vtkGetMacro(NumberOfOverlays, int) */ public"; + +%csmethodmodifiers vtkGDCMImageReader::vtkGetMacro " /** +vtkGDCMImageReader::vtkGetMacro(LossyFlag, int) */ public"; + +%csmethodmodifiers vtkGDCMImageReader::vtkGetMacro " /** +vtkGDCMImageReader::vtkGetMacro(LoadIconImage, int) */ public"; + +%csmethodmodifiers vtkGDCMImageReader::vtkGetMacro " /** +vtkGDCMImageReader::vtkGetMacro(LoadOverlays, int) */ public"; + +%csmethodmodifiers vtkGDCMImageReader::vtkGetObjectMacro " /** +vtkGDCMImageReader::vtkGetObjectMacro(Curve, vtkPolyData) */ public"; + +%csmethodmodifiers vtkGDCMImageReader::vtkGetObjectMacro " /** +vtkGDCMImageReader::vtkGetObjectMacro(FileNames, vtkStringArray) */ +public"; + +%csmethodmodifiers vtkGDCMImageReader::vtkGetObjectMacro " /** +vtkGDCMImageReader::vtkGetObjectMacro(MedicalImageProperties, +vtkMedicalImageProperties) */ public"; + +%csmethodmodifiers vtkGDCMImageReader::vtkGetObjectMacro " /** +vtkGDCMImageReader::vtkGetObjectMacro(DirectionCosines, vtkMatrix4x4) +*/ public"; + +%csmethodmodifiers vtkGDCMImageReader::vtkGetVector3Macro " /** +vtkGDCMImageReader::vtkGetVector3Macro(ImagePositionPatient, double) +*/ public"; + +%csmethodmodifiers vtkGDCMImageReader::vtkGetVector6Macro " /** +vtkGDCMImageReader::vtkGetVector6Macro(ImageOrientationPatient, +double) */ public"; + +%csmethodmodifiers vtkGDCMImageReader::vtkSetMacro " /** +vtkGDCMImageReader::vtkSetMacro(ApplyLookupTable, int) */ public"; + +%csmethodmodifiers vtkGDCMImageReader::vtkSetMacro " /** +vtkGDCMImageReader::vtkSetMacro(LossyFlag, int) */ public"; + +%csmethodmodifiers vtkGDCMImageReader::vtkSetMacro " /** +vtkGDCMImageReader::vtkSetMacro(LoadIconImage, int) */ public"; + +%csmethodmodifiers vtkGDCMImageReader::vtkSetMacro " /** +vtkGDCMImageReader::vtkSetMacro(LoadOverlays, int) */ public"; + +%csmethodmodifiers vtkGDCMImageReader::vtkTypeRevisionMacro " /** +vtkGDCMImageReader::vtkTypeRevisionMacro(vtkGDCMImageReader, +vtkMedicalImageReader2) */ public"; + + +// File: classvtkGDCMImageWriter.xml +%typemap("csclassmodifiers") vtkGDCMImageWriter " /**C++ includes: +vtkGDCMImageWriter.h */ public class"; + +%csmethodmodifiers vtkGDCMImageWriter::GetDescriptiveName " /** +virtual const char* vtkGDCMImageWriter::GetDescriptiveName() */ +public"; + +%csmethodmodifiers vtkGDCMImageWriter::GetFileExtensions " /** +virtual const char* vtkGDCMImageWriter::GetFileExtensions() */ +public"; + +%csmethodmodifiers vtkGDCMImageWriter::PrintSelf " /** virtual void +vtkGDCMImageWriter::PrintSelf(ostream &os, vtkIndent indent) */ +public"; + +%csmethodmodifiers vtkGDCMImageWriter::SetDirectionCosines " /** +virtual void vtkGDCMImageWriter::SetDirectionCosines(vtkMatrix4x4 +*matrix) */ public"; + +%csmethodmodifiers vtkGDCMImageWriter::SetFileNames " /** virtual +void vtkGDCMImageWriter::SetFileNames(vtkStringArray *) */ public"; + +%csmethodmodifiers vtkGDCMImageWriter::SetMedicalImageProperties " +/** virtual void +vtkGDCMImageWriter::SetMedicalImageProperties(vtkMedicalImageProperties +*) */ public"; + +%csmethodmodifiers vtkGDCMImageWriter::vtkBooleanMacro " /** +vtkGDCMImageWriter::vtkBooleanMacro(FileLowerLeft, int) */ public"; + +%csmethodmodifiers vtkGDCMImageWriter::vtkBooleanMacro " /** +vtkGDCMImageWriter::vtkBooleanMacro(LossyFlag, int) */ public"; + +%csmethodmodifiers vtkGDCMImageWriter::vtkGetMacro " /** +vtkGDCMImageWriter::vtkGetMacro(FileLowerLeft, int) */ public"; + +%csmethodmodifiers vtkGDCMImageWriter::vtkGetMacro " /** +vtkGDCMImageWriter::vtkGetMacro(ImageFormat, int) */ public"; + +%csmethodmodifiers vtkGDCMImageWriter::vtkGetMacro " /** +vtkGDCMImageWriter::vtkGetMacro(Scale, double) */ public"; + +%csmethodmodifiers vtkGDCMImageWriter::vtkGetMacro " /** +vtkGDCMImageWriter::vtkGetMacro(Shift, double) */ public"; + +%csmethodmodifiers vtkGDCMImageWriter::vtkGetMacro " /** +vtkGDCMImageWriter::vtkGetMacro(LossyFlag, int) */ public"; + +%csmethodmodifiers vtkGDCMImageWriter::vtkGetObjectMacro " /** +vtkGDCMImageWriter::vtkGetObjectMacro(DirectionCosines, vtkMatrix4x4) +*/ public"; + +%csmethodmodifiers vtkGDCMImageWriter::vtkGetObjectMacro " /** +vtkGDCMImageWriter::vtkGetObjectMacro(FileNames, vtkStringArray) */ +public"; + +%csmethodmodifiers vtkGDCMImageWriter::vtkGetObjectMacro " /** +vtkGDCMImageWriter::vtkGetObjectMacro(MedicalImageProperties, +vtkMedicalImageProperties) */ public"; + +%csmethodmodifiers vtkGDCMImageWriter::vtkSetMacro " /** +vtkGDCMImageWriter::vtkSetMacro(PlanarConfiguration, int) */ public"; + +%csmethodmodifiers vtkGDCMImageWriter::vtkSetMacro " /** +vtkGDCMImageWriter::vtkSetMacro(FileLowerLeft, int) */ public"; + +%csmethodmodifiers vtkGDCMImageWriter::vtkSetMacro " /** +vtkGDCMImageWriter::vtkSetMacro(ImageFormat, int) */ public"; + +%csmethodmodifiers vtkGDCMImageWriter::vtkSetMacro " /** +vtkGDCMImageWriter::vtkSetMacro(Scale, double) */ public"; + +%csmethodmodifiers vtkGDCMImageWriter::vtkSetMacro " /** +vtkGDCMImageWriter::vtkSetMacro(Shift, double) */ public"; + +%csmethodmodifiers vtkGDCMImageWriter::vtkSetMacro " /** +vtkGDCMImageWriter::vtkSetMacro(LossyFlag, int) */ public"; + +%csmethodmodifiers vtkGDCMImageWriter::vtkTypeRevisionMacro " /** +vtkGDCMImageWriter::vtkTypeRevisionMacro(vtkGDCMImageWriter, +vtkImageWriter) */ public"; + +%csmethodmodifiers vtkGDCMImageWriter::Write " /** virtual void +vtkGDCMImageWriter::Write() */ public"; + + +// File: classvtkGDCMPolyDataReader.xml +%typemap("csclassmodifiers") vtkGDCMPolyDataReader " /**C++ includes: +vtkGDCMPolyDataReader.h */ public class"; + +%csmethodmodifiers vtkGDCMPolyDataReader::PrintSelf " /** virtual +void vtkGDCMPolyDataReader::PrintSelf(ostream &os, vtkIndent indent) +*/ public"; + +%csmethodmodifiers vtkGDCMPolyDataReader::vtkGetObjectMacro " /** +vtkGDCMPolyDataReader::vtkGetObjectMacro(MedicalImageProperties, +vtkMedicalImageProperties) */ public"; + +%csmethodmodifiers vtkGDCMPolyDataReader::vtkGetStringMacro " /** +vtkGDCMPolyDataReader::vtkGetStringMacro(FileName) */ public"; + +%csmethodmodifiers vtkGDCMPolyDataReader::vtkSetStringMacro " /** +vtkGDCMPolyDataReader::vtkSetStringMacro(FileName) */ public"; + +%csmethodmodifiers vtkGDCMPolyDataReader::vtkTypeRevisionMacro " /** +vtkGDCMPolyDataReader::vtkTypeRevisionMacro(vtkGDCMPolyDataReader, +vtkPolyDataAlgorithm) */ public"; + + +// File: classvtkGDCMThreadedImageReader.xml +%typemap("csclassmodifiers") vtkGDCMThreadedImageReader " /**C++ +includes: vtkGDCMThreadedImageReader.h */ public class"; + +%csmethodmodifiers vtkGDCMThreadedImageReader::PrintSelf " /** +virtual void vtkGDCMThreadedImageReader::PrintSelf(ostream &os, +vtkIndent indent) */ public"; + +%csmethodmodifiers vtkGDCMThreadedImageReader::vtkBooleanMacro " /** +vtkGDCMThreadedImageReader::vtkBooleanMacro(UseShiftScale, int) */ +public"; + +%csmethodmodifiers vtkGDCMThreadedImageReader::vtkGetMacro " /** +vtkGDCMThreadedImageReader::vtkGetMacro(UseShiftScale, int) */ +public"; + +%csmethodmodifiers vtkGDCMThreadedImageReader::vtkSetMacro " /** +vtkGDCMThreadedImageReader::vtkSetMacro(UseShiftScale, int) */ +public"; + +%csmethodmodifiers vtkGDCMThreadedImageReader::vtkSetMacro " /** +vtkGDCMThreadedImageReader::vtkSetMacro(Scale, double) */ public"; + +%csmethodmodifiers vtkGDCMThreadedImageReader::vtkSetMacro " /** +vtkGDCMThreadedImageReader::vtkSetMacro(Shift, double) */ public"; + +%csmethodmodifiers vtkGDCMThreadedImageReader::vtkTypeRevisionMacro " +/** +vtkGDCMThreadedImageReader::vtkTypeRevisionMacro(vtkGDCMThreadedImageReader, +vtkGDCMImageReader) */ public"; + + +// File: classvtkGDCMThreadedImageReader2.xml +%typemap("csclassmodifiers") vtkGDCMThreadedImageReader2 " /**C++ +includes: vtkGDCMThreadedImageReader2.h */ public class"; + +%csmethodmodifiers vtkGDCMThreadedImageReader2::GetFileName " /** +virtual const char* vtkGDCMThreadedImageReader2::GetFileName(int i=0) +*/ public"; + +%csmethodmodifiers vtkGDCMThreadedImageReader2::PrintSelf " /** +virtual void vtkGDCMThreadedImageReader2::PrintSelf(ostream &os, +vtkIndent indent) */ public"; + +%csmethodmodifiers vtkGDCMThreadedImageReader2::SetFileName " /** +virtual void vtkGDCMThreadedImageReader2::SetFileName(const char +*filename) */ public"; + +%csmethodmodifiers vtkGDCMThreadedImageReader2::SetFileNames " /** +virtual void vtkGDCMThreadedImageReader2::SetFileNames(vtkStringArray +*) */ public"; + +%csmethodmodifiers vtkGDCMThreadedImageReader2::SplitExtent " /** int +vtkGDCMThreadedImageReader2::SplitExtent(int splitExt[6], int +startExt[6], int num, int total) */ public"; + +%csmethodmodifiers vtkGDCMThreadedImageReader2::vtkBooleanMacro " /** +vtkGDCMThreadedImageReader2::vtkBooleanMacro(UseShiftScale, int) */ +public"; + +%csmethodmodifiers vtkGDCMThreadedImageReader2::vtkBooleanMacro " /** +vtkGDCMThreadedImageReader2::vtkBooleanMacro(LoadOverlays, int) */ +public"; + +%csmethodmodifiers vtkGDCMThreadedImageReader2::vtkBooleanMacro " /** +vtkGDCMThreadedImageReader2::vtkBooleanMacro(FileLowerLeft, int) */ +public"; + +%csmethodmodifiers vtkGDCMThreadedImageReader2::vtkGetMacro " /** +vtkGDCMThreadedImageReader2::vtkGetMacro(UseShiftScale, int) */ +public"; + +%csmethodmodifiers vtkGDCMThreadedImageReader2::vtkGetMacro " /** +vtkGDCMThreadedImageReader2::vtkGetMacro(Scale, double) */ public"; + +%csmethodmodifiers vtkGDCMThreadedImageReader2::vtkGetMacro " /** +vtkGDCMThreadedImageReader2::vtkGetMacro(Shift, double) */ public"; + +%csmethodmodifiers vtkGDCMThreadedImageReader2::vtkGetMacro " /** +vtkGDCMThreadedImageReader2::vtkGetMacro(LoadOverlays, int) */ +public"; + +%csmethodmodifiers vtkGDCMThreadedImageReader2::vtkGetMacro " /** +vtkGDCMThreadedImageReader2::vtkGetMacro(NumberOfScalarComponents, +int) */ public"; + +%csmethodmodifiers vtkGDCMThreadedImageReader2::vtkGetMacro " /** +vtkGDCMThreadedImageReader2::vtkGetMacro(DataScalarType, int) */ +public"; + +%csmethodmodifiers vtkGDCMThreadedImageReader2::vtkGetMacro " /** +vtkGDCMThreadedImageReader2::vtkGetMacro(NumberOfOverlays, int) */ +public"; + +%csmethodmodifiers vtkGDCMThreadedImageReader2::vtkGetMacro " /** +vtkGDCMThreadedImageReader2::vtkGetMacro(FileLowerLeft, int) */ +public"; + +%csmethodmodifiers vtkGDCMThreadedImageReader2::vtkGetObjectMacro " +/** vtkGDCMThreadedImageReader2::vtkGetObjectMacro(FileNames, +vtkStringArray) */ public"; + +%csmethodmodifiers vtkGDCMThreadedImageReader2::vtkGetVector3Macro " +/** vtkGDCMThreadedImageReader2::vtkGetVector3Macro(DataSpacing, +double) */ public"; + +%csmethodmodifiers vtkGDCMThreadedImageReader2::vtkGetVector3Macro " +/** vtkGDCMThreadedImageReader2::vtkGetVector3Macro(DataOrigin, +double) */ public"; + +%csmethodmodifiers vtkGDCMThreadedImageReader2::vtkGetVector6Macro " +/** vtkGDCMThreadedImageReader2::vtkGetVector6Macro(DataExtent, int) +*/ public"; + +%csmethodmodifiers vtkGDCMThreadedImageReader2::vtkSetMacro " /** +vtkGDCMThreadedImageReader2::vtkSetMacro(UseShiftScale, int) */ +public"; + +%csmethodmodifiers vtkGDCMThreadedImageReader2::vtkSetMacro " /** +vtkGDCMThreadedImageReader2::vtkSetMacro(Scale, double) */ public"; + +%csmethodmodifiers vtkGDCMThreadedImageReader2::vtkSetMacro " /** +vtkGDCMThreadedImageReader2::vtkSetMacro(Shift, double) */ public"; + +%csmethodmodifiers vtkGDCMThreadedImageReader2::vtkSetMacro " /** +vtkGDCMThreadedImageReader2::vtkSetMacro(LoadOverlays, int) */ +public"; + +%csmethodmodifiers vtkGDCMThreadedImageReader2::vtkSetMacro " /** +vtkGDCMThreadedImageReader2::vtkSetMacro(NumberOfScalarComponents, +int) */ public"; + +%csmethodmodifiers vtkGDCMThreadedImageReader2::vtkSetMacro " /** +vtkGDCMThreadedImageReader2::vtkSetMacro(DataScalarType, int) */ +public"; + +%csmethodmodifiers vtkGDCMThreadedImageReader2::vtkSetMacro " /** +vtkGDCMThreadedImageReader2::vtkSetMacro(FileLowerLeft, int) */ +public"; + +%csmethodmodifiers vtkGDCMThreadedImageReader2::vtkSetVector3Macro " +/** vtkGDCMThreadedImageReader2::vtkSetVector3Macro(DataSpacing, +double) */ public"; + +%csmethodmodifiers vtkGDCMThreadedImageReader2::vtkSetVector3Macro " +/** vtkGDCMThreadedImageReader2::vtkSetVector3Macro(DataOrigin, +double) */ public"; + +%csmethodmodifiers vtkGDCMThreadedImageReader2::vtkSetVector6Macro " +/** vtkGDCMThreadedImageReader2::vtkSetVector6Macro(DataExtent, int) +*/ public"; + +%csmethodmodifiers vtkGDCMThreadedImageReader2::vtkTypeRevisionMacro +" /** +vtkGDCMThreadedImageReader2::vtkTypeRevisionMacro(vtkGDCMThreadedImageReader2, +vtkThreadedImageAlgorithm) */ public"; + + +// File: classvtkImageColorViewer.xml +%typemap("csclassmodifiers") vtkImageColorViewer " /**C++ includes: +vtkImageColorViewer.h */ public class"; + +%csmethodmodifiers vtkImageColorViewer::AddInput " /** virtual void +vtkImageColorViewer::AddInput(vtkImageData *input) */ public"; + +%csmethodmodifiers vtkImageColorViewer::AddInputConnection " /** +virtual void +vtkImageColorViewer::AddInputConnection(vtkAlgorithmOutput *input) */ +public"; + +%csmethodmodifiers vtkImageColorViewer::GetColorLevel " /** virtual +double vtkImageColorViewer::GetColorLevel() */ public"; + +%csmethodmodifiers vtkImageColorViewer::GetColorWindow " /** virtual +double vtkImageColorViewer::GetColorWindow() */ public"; + +%csmethodmodifiers vtkImageColorViewer::GetInput " /** virtual +vtkImageData* vtkImageColorViewer::GetInput() */ public"; + +%csmethodmodifiers vtkImageColorViewer::GetOffScreenRendering " /** +virtual int vtkImageColorViewer::GetOffScreenRendering() */ public"; + +%csmethodmodifiers vtkImageColorViewer::GetOverlayVisibility " /** +double vtkImageColorViewer::GetOverlayVisibility() */ public"; + +%csmethodmodifiers vtkImageColorViewer::GetPosition " /** virtual +int* vtkImageColorViewer::GetPosition() */ public"; + +%csmethodmodifiers vtkImageColorViewer::GetSize " /** virtual int* +vtkImageColorViewer::GetSize() */ public"; + +%csmethodmodifiers vtkImageColorViewer::GetSliceMax " /** virtual int +vtkImageColorViewer::GetSliceMax() */ public"; + +%csmethodmodifiers vtkImageColorViewer::GetSliceMin " /** virtual int +vtkImageColorViewer::GetSliceMin() */ public"; + +%csmethodmodifiers vtkImageColorViewer::GetSliceRange " /** virtual +int* vtkImageColorViewer::GetSliceRange() */ public"; + +%csmethodmodifiers vtkImageColorViewer::GetSliceRange " /** virtual +void vtkImageColorViewer::GetSliceRange(int &min, int &max) */ +public"; + +%csmethodmodifiers vtkImageColorViewer::GetSliceRange " /** virtual +void vtkImageColorViewer::GetSliceRange(int range[2]) */ public"; + +%csmethodmodifiers vtkImageColorViewer::GetWindowName " /** virtual +const char* vtkImageColorViewer::GetWindowName() */ public"; + +%csmethodmodifiers vtkImageColorViewer::PrintSelf " /** void +vtkImageColorViewer::PrintSelf(ostream &os, vtkIndent indent) */ +public"; + +%csmethodmodifiers vtkImageColorViewer::Render " /** virtual void +vtkImageColorViewer::Render(void) */ public"; + +%csmethodmodifiers vtkImageColorViewer::SetColorLevel " /** virtual +void vtkImageColorViewer::SetColorLevel(double s) */ public"; + +%csmethodmodifiers vtkImageColorViewer::SetColorWindow " /** virtual +void vtkImageColorViewer::SetColorWindow(double s) */ public"; + +%csmethodmodifiers vtkImageColorViewer::SetDisplayId " /** virtual +void vtkImageColorViewer::SetDisplayId(void *a) */ public"; + +%csmethodmodifiers vtkImageColorViewer::SetInput " /** virtual void +vtkImageColorViewer::SetInput(vtkImageData *in) */ public"; + +%csmethodmodifiers vtkImageColorViewer::SetInputConnection " /** +virtual void +vtkImageColorViewer::SetInputConnection(vtkAlgorithmOutput *input) */ +public"; + +%csmethodmodifiers vtkImageColorViewer::SetOffScreenRendering " /** +virtual void vtkImageColorViewer::SetOffScreenRendering(int) */ +public"; + +%csmethodmodifiers vtkImageColorViewer::SetOverlayVisibility " /** +void vtkImageColorViewer::SetOverlayVisibility(double vis) */ +public"; + +%csmethodmodifiers vtkImageColorViewer::SetParentId " /** virtual +void vtkImageColorViewer::SetParentId(void *a) */ public"; + +%csmethodmodifiers vtkImageColorViewer::SetPosition " /** virtual +void vtkImageColorViewer::SetPosition(int a[2]) */ public"; + +%csmethodmodifiers vtkImageColorViewer::SetPosition " /** virtual +void vtkImageColorViewer::SetPosition(int a, int b) */ public"; + +%csmethodmodifiers vtkImageColorViewer::SetRenderer " /** virtual +void vtkImageColorViewer::SetRenderer(vtkRenderer *arg) */ public"; + +%csmethodmodifiers vtkImageColorViewer::SetRenderWindow " /** virtual +void vtkImageColorViewer::SetRenderWindow(vtkRenderWindow *arg) */ +public"; + +%csmethodmodifiers vtkImageColorViewer::SetSize " /** virtual void +vtkImageColorViewer::SetSize(int a[2]) */ public"; + +%csmethodmodifiers vtkImageColorViewer::SetSize " /** virtual void +vtkImageColorViewer::SetSize(int a, int b) */ public"; + +%csmethodmodifiers vtkImageColorViewer::SetSlice " /** virtual void +vtkImageColorViewer::SetSlice(int s) */ public"; + +%csmethodmodifiers vtkImageColorViewer::SetSliceOrientation " /** +virtual void vtkImageColorViewer::SetSliceOrientation(int orientation) +*/ public"; + +%csmethodmodifiers vtkImageColorViewer::SetSliceOrientationToXY " /** +virtual void vtkImageColorViewer::SetSliceOrientationToXY() */ +public"; + +%csmethodmodifiers vtkImageColorViewer::SetSliceOrientationToXZ " /** +virtual void vtkImageColorViewer::SetSliceOrientationToXZ() */ +public"; + +%csmethodmodifiers vtkImageColorViewer::SetSliceOrientationToYZ " /** +virtual void vtkImageColorViewer::SetSliceOrientationToYZ() */ +public"; + +%csmethodmodifiers vtkImageColorViewer::SetupInteractor " /** virtual +void vtkImageColorViewer::SetupInteractor(vtkRenderWindowInteractor *) +*/ public"; + +%csmethodmodifiers vtkImageColorViewer::SetWindowId " /** virtual +void vtkImageColorViewer::SetWindowId(void *a) */ public"; + +%csmethodmodifiers vtkImageColorViewer::UpdateDisplayExtent " /** +virtual void vtkImageColorViewer::UpdateDisplayExtent() */ public"; + +%csmethodmodifiers vtkImageColorViewer::VTK_LEGACY " /** +vtkImageColorViewer::VTK_LEGACY(void SetZSlice(int)) */ public"; + +%csmethodmodifiers vtkImageColorViewer::VTK_LEGACY " /** +vtkImageColorViewer::VTK_LEGACY(int GetZSlice()) */ public"; + +%csmethodmodifiers vtkImageColorViewer::VTK_LEGACY " /** +vtkImageColorViewer::VTK_LEGACY(int GetWholeZMax()) */ public"; + +%csmethodmodifiers vtkImageColorViewer::VTK_LEGACY " /** +vtkImageColorViewer::VTK_LEGACY(int GetWholeZMin()) */ public"; + +%csmethodmodifiers vtkImageColorViewer::vtkBooleanMacro " /** +vtkImageColorViewer::vtkBooleanMacro(OffScreenRendering, int) */ +public"; + +%csmethodmodifiers vtkImageColorViewer::vtkGetMacro " /** +vtkImageColorViewer::vtkGetMacro(Slice, int) */ public"; + +%csmethodmodifiers vtkImageColorViewer::vtkGetMacro " /** +vtkImageColorViewer::vtkGetMacro(SliceOrientation, int) */ public"; + +%csmethodmodifiers vtkImageColorViewer::vtkGetObjectMacro " /** +vtkImageColorViewer::vtkGetObjectMacro(InteractorStyle, +vtkInteractorStyleImage) */ public"; + +%csmethodmodifiers vtkImageColorViewer::vtkGetObjectMacro " /** +vtkImageColorViewer::vtkGetObjectMacro(WindowLevel, +vtkImageMapToWindowLevelColors2) */ public"; + +%csmethodmodifiers vtkImageColorViewer::vtkGetObjectMacro " /** +vtkImageColorViewer::vtkGetObjectMacro(ImageActor, vtkImageActor) */ +public"; + +%csmethodmodifiers vtkImageColorViewer::vtkGetObjectMacro " /** +vtkImageColorViewer::vtkGetObjectMacro(Renderer, vtkRenderer) */ +public"; + +%csmethodmodifiers vtkImageColorViewer::vtkGetObjectMacro " /** +vtkImageColorViewer::vtkGetObjectMacro(RenderWindow, vtkRenderWindow) +*/ public"; + +%csmethodmodifiers vtkImageColorViewer::vtkTypeRevisionMacro " /** +vtkImageColorViewer::vtkTypeRevisionMacro(vtkImageColorViewer, +vtkObject) */ public"; + + +// File: classvtkImageMapToColors16.xml +%typemap("csclassmodifiers") vtkImageMapToColors16 " /**C++ includes: +vtkImageMapToColors16.h */ public class"; + +%csmethodmodifiers vtkImageMapToColors16::GetMTime " /** virtual +unsigned long vtkImageMapToColors16::GetMTime() */ public"; + +%csmethodmodifiers vtkImageMapToColors16::PrintSelf " /** void +vtkImageMapToColors16::PrintSelf(ostream &os, vtkIndent indent) */ +public"; + +%csmethodmodifiers vtkImageMapToColors16::SetLookupTable " /** +virtual void vtkImageMapToColors16::SetLookupTable(vtkScalarsToColors +*) */ public"; + +%csmethodmodifiers vtkImageMapToColors16::SetOutputFormatToLuminance +" /** void vtkImageMapToColors16::SetOutputFormatToLuminance() */ +public"; + +%csmethodmodifiers +vtkImageMapToColors16::SetOutputFormatToLuminanceAlpha " /** void +vtkImageMapToColors16::SetOutputFormatToLuminanceAlpha() */ public"; + +%csmethodmodifiers vtkImageMapToColors16::SetOutputFormatToRGB " /** +void vtkImageMapToColors16::SetOutputFormatToRGB() */ public"; + +%csmethodmodifiers vtkImageMapToColors16::SetOutputFormatToRGBA " /** +void vtkImageMapToColors16::SetOutputFormatToRGBA() */ public"; + +%csmethodmodifiers vtkImageMapToColors16::vtkBooleanMacro " /** +vtkImageMapToColors16::vtkBooleanMacro(PassAlphaToOutput, int) */ +public"; + +%csmethodmodifiers vtkImageMapToColors16::vtkGetMacro " /** +vtkImageMapToColors16::vtkGetMacro(PassAlphaToOutput, int) */ +public"; + +%csmethodmodifiers vtkImageMapToColors16::vtkGetMacro " /** +vtkImageMapToColors16::vtkGetMacro(ActiveComponent, int) */ public"; + +%csmethodmodifiers vtkImageMapToColors16::vtkGetMacro " /** +vtkImageMapToColors16::vtkGetMacro(OutputFormat, int) */ public"; + +%csmethodmodifiers vtkImageMapToColors16::vtkGetObjectMacro " /** +vtkImageMapToColors16::vtkGetObjectMacro(LookupTable, +vtkScalarsToColors) */ public"; + +%csmethodmodifiers vtkImageMapToColors16::vtkSetMacro " /** +vtkImageMapToColors16::vtkSetMacro(PassAlphaToOutput, int) */ +public"; + +%csmethodmodifiers vtkImageMapToColors16::vtkSetMacro " /** +vtkImageMapToColors16::vtkSetMacro(ActiveComponent, int) */ public"; + +%csmethodmodifiers vtkImageMapToColors16::vtkSetMacro " /** +vtkImageMapToColors16::vtkSetMacro(OutputFormat, int) */ public"; + +%csmethodmodifiers vtkImageMapToColors16::vtkTypeRevisionMacro " /** +vtkImageMapToColors16::vtkTypeRevisionMacro(vtkImageMapToColors16, +vtkThreadedImageAlgorithm) */ public"; + + +// File: classvtkImageMapToWindowLevelColors2.xml +%typemap("csclassmodifiers") vtkImageMapToWindowLevelColors2 " /**C++ +includes: vtkImageMapToWindowLevelColors2.h */ public class"; + +%csmethodmodifiers vtkImageMapToWindowLevelColors2::PrintSelf " /** +void vtkImageMapToWindowLevelColors2::PrintSelf(ostream &os, vtkIndent +indent) */ public"; + +%csmethodmodifiers vtkImageMapToWindowLevelColors2::vtkGetMacro " /** +vtkImageMapToWindowLevelColors2::vtkGetMacro(Level, double) */ +public"; + +%csmethodmodifiers vtkImageMapToWindowLevelColors2::vtkGetMacro " /** +vtkImageMapToWindowLevelColors2::vtkGetMacro(Window, double) */ +public"; + +%csmethodmodifiers vtkImageMapToWindowLevelColors2::vtkSetMacro " /** +vtkImageMapToWindowLevelColors2::vtkSetMacro(Level, double) */ +public"; + +%csmethodmodifiers vtkImageMapToWindowLevelColors2::vtkSetMacro " /** +vtkImageMapToWindowLevelColors2::vtkSetMacro(Window, double) */ +public"; + +%csmethodmodifiers +vtkImageMapToWindowLevelColors2::vtkTypeRevisionMacro " /** +vtkImageMapToWindowLevelColors2::vtkTypeRevisionMacro(vtkImageMapToWindowLevelColors2, +vtkImageMapToColors) */ public"; + + +// File: classvtkImagePlanarComponentsToComponents.xml +%typemap("csclassmodifiers") vtkImagePlanarComponentsToComponents " +/**C++ includes: vtkImagePlanarComponentsToComponents.h */ public +class"; + +%csmethodmodifiers vtkImagePlanarComponentsToComponents::PrintSelf " +/** void vtkImagePlanarComponentsToComponents::PrintSelf(ostream &os, +vtkIndent indent) */ public"; + +%csmethodmodifiers +vtkImagePlanarComponentsToComponents::vtkTypeRevisionMacro " /** +vtkImagePlanarComponentsToComponents::vtkTypeRevisionMacro(vtkImagePlanarComponentsToComponents, +vtkImageAlgorithm) */ public"; + + +// File: classvtkImageRGBToYBR.xml +%typemap("csclassmodifiers") vtkImageRGBToYBR " /**C++ includes: +vtkImageRGBToYBR.h */ public class"; + +%csmethodmodifiers vtkImageRGBToYBR::PrintSelf " /** void +vtkImageRGBToYBR::PrintSelf(ostream &os, vtkIndent indent) */ +public"; + +%csmethodmodifiers vtkImageRGBToYBR::vtkTypeRevisionMacro " /** +vtkImageRGBToYBR::vtkTypeRevisionMacro(vtkImageRGBToYBR, +vtkThreadedImageAlgorithm) */ public"; + + +// File: classvtkImageYBRToRGB.xml +%typemap("csclassmodifiers") vtkImageYBRToRGB " /**C++ includes: +vtkImageYBRToRGB.h */ public class"; + +%csmethodmodifiers vtkImageYBRToRGB::PrintSelf " /** void +vtkImageYBRToRGB::PrintSelf(ostream &os, vtkIndent indent) */ +public"; + +%csmethodmodifiers vtkImageYBRToRGB::vtkTypeRevisionMacro " /** +vtkImageYBRToRGB::vtkTypeRevisionMacro(vtkImageYBRToRGB, +vtkThreadedImageAlgorithm) */ public"; + + +// File: classvtkLookupTable16.xml +%typemap("csclassmodifiers") vtkLookupTable16 " /**C++ includes: +vtkLookupTable16.h */ public class"; + +%csmethodmodifiers vtkLookupTable16::Build " /** void +vtkLookupTable16::Build() */ public"; + +%csmethodmodifiers vtkLookupTable16::GetPointer " /** unsigned short* +vtkLookupTable16::GetPointer(const vtkIdType id) */ public"; + +%csmethodmodifiers vtkLookupTable16::PrintSelf " /** void +vtkLookupTable16::PrintSelf(ostream &os, vtkIndent indent) */ +public"; + +%csmethodmodifiers vtkLookupTable16::SetNumberOfTableValues " /** +void vtkLookupTable16::SetNumberOfTableValues(vtkIdType number) */ +public"; + +%csmethodmodifiers vtkLookupTable16::vtkTypeRevisionMacro " /** +vtkLookupTable16::vtkTypeRevisionMacro(vtkLookupTable16, +vtkLookupTable) */ public"; + +%csmethodmodifiers vtkLookupTable16::WritePointer " /** unsigned char +* vtkLookupTable16::WritePointer(const vtkIdType id, const int number) +*/ public"; + + +// File: classgdcm_1_1Waveform.xml +%typemap("csclassmodifiers") gdcm::Waveform " /** Waveform class. + +C++ includes: gdcmWaveform.h */ public class"; + +%csmethodmodifiers gdcm::Waveform::Waveform " /** +gdcm::Waveform::Waveform() */ public"; + + +// File: classstd_1_1wfstream.xml +%typemap("csclassmodifiers") std::wfstream " /** STL class. + +*/ public class"; + + +// File: classstd_1_1wifstream.xml +%typemap("csclassmodifiers") std::wifstream " /** STL class. + +*/ public class"; + + +// File: classstd_1_1wios.xml +%typemap("csclassmodifiers") std::wios " /** STL class. + +*/ public class"; + + +// File: classstd_1_1wistream.xml +%typemap("csclassmodifiers") std::wistream " /** STL class. + +*/ public class"; + + +// File: classstd_1_1wistringstream.xml +%typemap("csclassmodifiers") std::wistringstream " /** STL class. + +*/ public class"; + + +// File: classstd_1_1wofstream.xml +%typemap("csclassmodifiers") std::wofstream " /** STL class. + +*/ public class"; + + +// File: classstd_1_1wostream.xml +%typemap("csclassmodifiers") std::wostream " /** STL class. + +*/ public class"; + + +// File: classstd_1_1wostringstream.xml +%typemap("csclassmodifiers") std::wostringstream " /** STL class. + +*/ public class"; + + +// File: classgdcm_1_1Writer.xml +%typemap("csclassmodifiers") gdcm::Writer " /** Writer ala DOM +(Document Object Model) This class is a non-validating writer, it will +only performs well- formedness check only. + +Detailled description here To avoid GDCM being yet another broken +DICOM lib we try to be user level and avoid writing illegal stuff (odd +length, non-zero value for Item start/end length ...) Therefore you +cannot (well unless you are really smart) write DICOM with even length +tag. All the checks are consider basics: Correct Meta Information +Header (see gdcm::FileMetaInformation) + +Zero value for Item Length (0xfffe, 0xe00d/0xe0dd) + +Even length for any elements + +Alphabetical order for elements (garanteed by design of internals) + +32bits VR will be rewritten with 00 + +WARNING: gdcm::Writer cannot write a DataSet if no SOP Instance UID +(0008,0018) is found + +C++ includes: gdcmWriter.h */ public class"; + +%csmethodmodifiers gdcm::Writer::CheckFileMetaInformationOff " /** +void gdcm::Writer::CheckFileMetaInformationOff() */ public"; + +%csmethodmodifiers gdcm::Writer::CheckFileMetaInformationOn " /** +void gdcm::Writer::CheckFileMetaInformationOn() */ public"; + +%csmethodmodifiers gdcm::Writer::GetFile " /** File& +gdcm::Writer::GetFile() */ public"; + +%csmethodmodifiers gdcm::Writer::SetCheckFileMetaInformation " /** +void gdcm::Writer::SetCheckFileMetaInformation(bool b) + +Undocumented function, do not use (= leave default). + +*/ public"; + +%csmethodmodifiers gdcm::Writer::SetFile " /** void +gdcm::Writer::SetFile(const File &f) + +Set/Get the DICOM file ( DataSet + Header). + +*/ public"; + +%csmethodmodifiers gdcm::Writer::SetFileName " /** void +gdcm::Writer::SetFileName(const char *filename) + +Set the filename of DICOM file to write:. + +*/ public"; + +%csmethodmodifiers gdcm::Writer::SetStream " /** void +gdcm::Writer::SetStream(std::ostream &output_stream) + +Set user ostream buffer. + +*/ public"; + +%csmethodmodifiers gdcm::Writer::Write " /** virtual bool +gdcm::Writer::Write() + +Main function to tell the writer to write. + +*/ public"; + +%csmethodmodifiers gdcm::Writer::Writer " /** gdcm::Writer::Writer() +*/ public"; + +%csmethodmodifiers gdcm::Writer::~Writer " /** virtual +gdcm::Writer::~Writer() */ public"; + + +// File: classstd_1_1wstring.xml +%typemap("csclassmodifiers") std::wstring " /** STL class. + +*/ public class"; + + +// File: classstd_1_1wstring_1_1const__iterator.xml +%typemap("csclassmodifiers") std::wstring::const_iterator " /** STL +iterator class. + +*/ public class"; + + +// File: classstd_1_1wstring_1_1const__reverse__iterator.xml +%typemap("csclassmodifiers") std::wstring::const_reverse_iterator " +/** STL iterator class. + +*/ public class"; + + +// File: classstd_1_1wstring_1_1iterator.xml +%typemap("csclassmodifiers") std::wstring::iterator " /** STL iterator +class. + +*/ public class"; + + +// File: classstd_1_1wstring_1_1reverse__iterator.xml +%typemap("csclassmodifiers") std::wstring::reverse_iterator " /** STL +iterator class. + +*/ public class"; + + +// File: classstd_1_1wstringstream.xml +%typemap("csclassmodifiers") std::wstringstream " /** STL class. + +*/ public class"; + + +// File: classgdcm_1_1X509.xml +%typemap("csclassmodifiers") gdcm::X509 " /**C++ includes: gdcmX509.h +*/ public class"; + +%csmethodmodifiers gdcm::X509::GetNumberOfRecipients " /** unsigned +int gdcm::X509::GetNumberOfRecipients() const */ public"; + +%csmethodmodifiers gdcm::X509::ParseCertificateFile " /** bool +gdcm::X509::ParseCertificateFile(const char *filename) */ public"; + +%csmethodmodifiers gdcm::X509::ParseKeyFile " /** bool +gdcm::X509::ParseKeyFile(const char *filename) */ public"; + +%csmethodmodifiers gdcm::X509::X509 " /** gdcm::X509::X509() */ +public"; + +%csmethodmodifiers gdcm::X509::~X509 " /** gdcm::X509::~X509() */ +public"; + + +// File: classgdcm_1_1XMLDictReader.xml +%typemap("csclassmodifiers") gdcm::XMLDictReader " /** Class for +representing a XMLDictReader. + +bla Will read the DICOMV3.xml file + +C++ includes: gdcmXMLDictReader.h */ public class"; + +%csmethodmodifiers gdcm::XMLDictReader::CharacterDataHandler " /** +void gdcm::XMLDictReader::CharacterDataHandler(const char *data, int +length) */ public"; + +%csmethodmodifiers gdcm::XMLDictReader::EndElement " /** void +gdcm::XMLDictReader::EndElement(const char *name) */ public"; + +%csmethodmodifiers gdcm::XMLDictReader::GetDict " /** const Dict& +gdcm::XMLDictReader::GetDict() */ public"; + +%csmethodmodifiers gdcm::XMLDictReader::StartElement " /** void +gdcm::XMLDictReader::StartElement(const char *name, const char **atts) +*/ public"; + +%csmethodmodifiers gdcm::XMLDictReader::XMLDictReader " /** +gdcm::XMLDictReader::XMLDictReader() */ public"; + +%csmethodmodifiers gdcm::XMLDictReader::~XMLDictReader " /** +gdcm::XMLDictReader::~XMLDictReader() */ public"; + + +// File: classgdcm_1_1XMLPrivateDictReader.xml +%typemap("csclassmodifiers") gdcm::XMLPrivateDictReader " /** Class +for representing a XMLPrivateDictReader. + +bla Will read the Private.xml file + +C++ includes: gdcmXMLPrivateDictReader.h */ public class"; + +%csmethodmodifiers gdcm::XMLPrivateDictReader::CharacterDataHandler " +/** void gdcm::XMLPrivateDictReader::CharacterDataHandler(const char +*data, int length) */ public"; + +%csmethodmodifiers gdcm::XMLPrivateDictReader::EndElement " /** void +gdcm::XMLPrivateDictReader::EndElement(const char *name) */ public"; + +%csmethodmodifiers gdcm::XMLPrivateDictReader::GetPrivateDict " /** +const PrivateDict& gdcm::XMLPrivateDictReader::GetPrivateDict() */ +public"; + +%csmethodmodifiers gdcm::XMLPrivateDictReader::StartElement " /** +void gdcm::XMLPrivateDictReader::StartElement(const char *name, const +char **atts) */ public"; + +%csmethodmodifiers gdcm::XMLPrivateDictReader::XMLPrivateDictReader " +/** gdcm::XMLPrivateDictReader::XMLPrivateDictReader() */ public"; + +%csmethodmodifiers gdcm::XMLPrivateDictReader::~XMLPrivateDictReader +" /** gdcm::XMLPrivateDictReader::~XMLPrivateDictReader() */ public"; + + +// File: namespacegdcm.xml +%csmethodmodifiers gdcm::terminal::to_string " std::string +gdcm::to_string(Float data) */ public"; + +%csmethodmodifiers gdcm::terminal::TYPETOENCODING " +gdcm::TYPETOENCODING(SQ, VRBINARY, unsigned char) TYPETOENCODING(UN +*/ public"; + + +// File: namespacegdcm_1_1terminal.xml +%csmethodmodifiers gdcm::terminal::setattribute " GDCM_EXPORT +std::string gdcm::terminal::setattribute(Attribute att) */ public"; + +%csmethodmodifiers gdcm::terminal::setbgcolor " GDCM_EXPORT +std::string gdcm::terminal::setbgcolor(Color c) */ public"; + +%csmethodmodifiers gdcm::terminal::setfgcolor " GDCM_EXPORT +std::string gdcm::terminal::setfgcolor(Color c) */ public"; + +%csmethodmodifiers gdcm::terminal::setmode " GDCM_EXPORT void +gdcm::terminal::setmode(Mode m) */ public"; + + +// File: namespaceitk.xml + + +// File: namespaceopenssl.xml + + +// File: namespacestd.xml + + +// File: namespacezlib__stream.xml +%csmethodmodifiers zlib_stream::detail::isGZip " bool +zlib_stream::isGZip(std::istream &is) + +A typedef for basic_zip_ostream. + +A typedef for basic_zip_istream Helper function to check +whether stream is compressed or not. + +*/ public"; + + +// File: namespacezlib__stream_1_1detail.xml + + +// File: gdcm2vtk_8man.xml + + +// File: gdcmAES_8h.xml + + +// File: gdcmanon_8man.xml + + +// File: gdcmAnonymizer_8h.xml + + +// File: gdcmApplicationEntity_8h.xml + + +// File: gdcmASN1_8h.xml + + +// File: gdcmAttribute_8h.xml + + +// File: gdcmAudioCodec_8h.xml + + +// File: gdcmBase64_8h.xml + + +// File: gdcmBasicOffsetTable_8h.xml + + +// File: gdcmBitmap_8h.xml + + +// File: gdcmByteBuffer_8h.xml + + +// File: gdcmByteSwap_8h.xml + + +// File: gdcmByteSwapFilter_8h.xml + + +// File: gdcmByteValue_8h.xml + + +// File: gdcmCodec_8h.xml + + +// File: gdcmCoder_8h.xml + + +// File: gdcmConstCharWrapper_8h.xml + + +// File: gdcmconv_8man.xml + + +// File: gdcmCP246ExplicitDataElement_8h.xml + + +// File: gdcmCSAElement_8h.xml + + +// File: gdcmCSAHeader_8h.xml + + +// File: gdcmCSAHeaderDict_8h.xml + + +// File: gdcmCSAHeaderDictEntry_8h.xml + + +// File: gdcmCurve_8h.xml + + +// File: gdcmDataElement_8h.xml + + +// File: gdcmDataSet_8h.xml + + +// File: gdcmDataSetHelper_8h.xml + + +// File: gdcmDecoder_8h.xml + + +// File: gdcmDefinedTerms_8h.xml + + +// File: gdcmDeflateStream_8h.xml + + +// File: gdcmDefs_8h.xml + + +// File: gdcmDeltaEncodingCodec_8h.xml + + +// File: gdcmDICOMDIR_8h.xml + + +// File: gdcmDict_8h.xml + + +// File: gdcmDictConverter_8h.xml + + +// File: gdcmDictEntry_8h.xml + + +// File: gdcmDictPrinter_8h.xml + + +// File: gdcmDicts_8h.xml + + +// File: gdcmDirectionCosines_8h.xml + + +// File: gdcmDirectory_8h.xml + + +// File: gdcmDummyValueGenerator_8h.xml + + +// File: gdcmdump_8man.xml + + +// File: gdcmDumper_8h.xml + + +// File: gdcmElement_8h.xml + + +// File: gdcmEncapsulatedDocument_8h.xml + + +// File: gdcmEnumeratedValues_8h.xml + + +// File: gdcmException_8h.xml + + +// File: gdcmExplicitDataElement_8h.xml + + +// File: gdcmExplicitImplicitDataElement_8h.xml + + +// File: gdcmFiducials_8h.xml + + +// File: gdcmFile_8h.xml + + +// File: gdcmFileExplicitFilter_8h.xml + + +// File: gdcmFileMetaInformation_8h.xml + + +// File: gdcmFilename_8h.xml + + +// File: gdcmFilenameGenerator_8h.xml + + +// File: gdcmFileSet_8h.xml + + +// File: gdcmFragment_8h.xml + + +// File: gdcmGlobal_8h.xml + + +// File: gdcmGroupDict_8h.xml + + +// File: gdcmHAVEGE_8h.xml + + +// File: gdcmIconImage_8h.xml + + +// File: gdcmImage_8h.xml + + +// File: gdcmImageApplyLookupTable_8h.xml + + +// File: gdcmImageChangePhotometricInterpretation_8h.xml + + +// File: gdcmImageChangePlanarConfiguration_8h.xml + + +// File: gdcmImageChangeTransferSyntax_8h.xml + + +// File: gdcmImageCodec_8h.xml + + +// File: gdcmImageConverter_8h.xml + + +// File: gdcmImageFragmentSplitter_8h.xml + + +// File: gdcmImageHelper_8h.xml + + +// File: gdcmImageReader_8h.xml + + +// File: gdcmImageToImageFilter_8h.xml + + +// File: gdcmImageWriter_8h.xml + + +// File: gdcmimg_8man.xml + + +// File: gdcmImplicitDataElement_8h.xml + + +// File: gdcminfo_8man.xml + + +// File: gdcmIOD_8h.xml + + +// File: gdcmIODEntry_8h.xml + + +// File: gdcmIODs_8h.xml + + +// File: gdcmIPPSorter_8h.xml + + +// File: gdcmItem_8h.xml + + +// File: gdcmJPEG12Codec_8h.xml + + +// File: gdcmJPEG16Codec_8h.xml + + +// File: gdcmJPEG2000Codec_8h.xml + + +// File: gdcmJPEG8Codec_8h.xml + + +// File: gdcmJPEGCodec_8h.xml + + +// File: gdcmJPEGLSCodec_8h.xml + + +// File: gdcmLO_8h.xml + + +// File: gdcmLookupTable_8h.xml + + +// File: gdcmMD5_8h.xml + + +// File: gdcmMediaStorage_8h.xml + + +// File: gdcmModule_8h.xml + + +// File: gdcmModuleEntry_8h.xml + + +// File: gdcmModules_8h.xml + + +// File: gdcmNestedModuleEntries_8h.xml + + +// File: gdcmObject_8h.xml + + +// File: gdcmOrientation_8h.xml + + +// File: gdcmOverlay_8h.xml + + +// File: gdcmParseException_8h.xml + + +// File: gdcmParser_8h.xml + + +// File: gdcmPatient_8h.xml + + +// File: gdcmPDBElement_8h.xml + + +// File: gdcmPDBHeader_8h.xml + + +// File: gdcmpdf_8man.xml + + +// File: gdcmPDFCodec_8h.xml + + +// File: gdcmPersonName_8h.xml + + +// File: gdcmPhotometricInterpretation_8h.xml + + +// File: gdcmPixelFormat_8h.xml + + +// File: gdcmPixmap_8h.xml + + +// File: gdcmPixmapReader_8h.xml + + +// File: gdcmPixmapToPixmapFilter_8h.xml + + +// File: gdcmPixmapWriter_8h.xml + + +// File: gdcmPKCS7_8h.xml + + +// File: gdcmPNMCodec_8h.xml + + +// File: gdcmPreamble_8h.xml + + +// File: gdcmPrinter_8h.xml + + +// File: gdcmPrivateTag_8h.xml + + +// File: gdcmPVRGCodec_8h.xml + + +// File: gdcmPythonFilter_8h.xml + + +// File: gdcmraw_8man.xml + + +// File: gdcmRAWCodec_8h.xml + + +// File: gdcmReader_8h.xml + + +// File: gdcmRescaler_8h.xml + + +// File: gdcmRLECodec_8h.xml + + +// File: gdcmRSA_8h.xml + + +// File: gdcmScanner_8h.xml + + +// File: gdcmscanner_8man.xml + + +// File: gdcmSegmentedPaletteColorLookupTable_8h.xml + + +// File: gdcmSequenceOfFragments_8h.xml + + +// File: gdcmSequenceOfItems_8h.xml + + +// File: gdcmSerieHelper_8h.xml + + +// File: gdcmSeries_8h.xml + + +// File: gdcmSHA1_8h.xml + + +// File: gdcmSmartPointer_8h.xml + + +// File: gdcmSOPClassUIDToIOD_8h.xml + + +// File: gdcmSorter_8h.xml + + +// File: gdcmSpacing_8h.xml + + +// File: gdcmSpectroscopy_8h.xml + + +// File: gdcmSplitMosaicFilter_8h.xml + + +// File: gdcmStaticAssert_8h.xml + + +// File: gdcmString_8h.xml + + +// File: gdcmStringFilter_8h.xml + + +// File: gdcmStudy_8h.xml + + +// File: gdcmSwapCode_8h.xml + + +// File: gdcmSwapper_8h.xml + + +// File: gdcmSystem_8h.xml + + +// File: gdcmTable_8h.xml + + +// File: gdcmTableEntry_8h.xml + + +// File: gdcmTableReader_8h.xml + + +// File: gdcmTag_8h.xml + + +// File: gdcmTagPath_8h.xml + + +// File: gdcmtar_8man.xml + + +// File: gdcmTerminal_8h.xml + + +// File: gdcmTesting_8h.xml + + +// File: gdcmTrace_8h.xml + + +// File: gdcmTransferSyntax_8h.xml + + +// File: gdcmType_8h.xml + + +// File: gdcmTypes_8h.xml + + +// File: gdcmUIDGenerator_8h.xml + + +// File: gdcmUIDs_8h.xml + + +// File: gdcmUNExplicitDataElement_8h.xml + + +// File: gdcmUNExplicitImplicitDataElement_8h.xml + + +// File: gdcmUnpacker12Bits_8h.xml + + +// File: gdcmUsage_8h.xml + + +// File: gdcmValidate_8h.xml + + +// File: gdcmValue_8h.xml + + +// File: gdcmValueIO_8h.xml + + +// File: gdcmVersion_8h.xml + + +// File: gdcmviewer_8man.xml + + +// File: gdcmVL_8h.xml + + +// File: gdcmVM_8h.xml + + +// File: gdcmVR_8h.xml + + +// File: gdcmVR16ExplicitDataElement_8h.xml + + +// File: gdcmWaveform_8h.xml + + +// File: gdcmWin32_8h.xml + + +// File: gdcmWriter_8h.xml + + +// File: gdcmX509_8h.xml + + +// File: gdcmXMLDictReader_8h.xml + + +// File: gdcmXMLPrivateDictReader_8h.xml + + +// File: itkGDCMImageIO2_8h.xml + + +// File: README_8txt.xml + + +// File: vtkGDCMImageReader_8h.xml + + +// File: vtkGDCMImageWriter_8h.xml + + +// File: vtkGDCMPolyDataReader_8h.xml + + +// File: vtkGDCMThreadedImageReader_8h.xml + + +// File: vtkGDCMThreadedImageReader2_8h.xml + + +// File: vtkImageColorViewer_8h.xml + + +// File: vtkImageMapToColors16_8h.xml + + +// File: vtkImageMapToWindowLevelColors2_8h.xml + + +// File: vtkImagePlanarComponentsToComponents_8h.xml + + +// File: vtkImageRGBToYBR_8h.xml + + +// File: vtkImageYBRToRGB_8h.xml + + +// File: vtkLookupTable16_8h.xml + + +// File: zipstreamimpl_8h.xml + + +// File: gdcm2vtk.xml + + +// File: gdcmanon.xml + + +// File: gdcmconv.xml + + +// File: gdcmdump.xml + + +// File: gdcmimg.xml + + +// File: gdcminfo.xml + + +// File: gdcmpdf.xml + + +// File: gdcmraw.xml + + +// File: gdcmscanner.xml + + +// File: gdcmtar.xml + + +// File: gdcmviewer.xml + + +// File: todo.xml + + +// File: deprecated.xml + + +// File: dir_2f925b9d7bdbc7cb71effd7da9c163ec.xml + + +// File: dir_47bd3784b8141d2b2b57bce8132141f0.xml + + +// File: dir_e1b815c71b4736e0245897636405935d.xml + + +// File: dir_1dd5d3a73373a39d9f89a45b28af9882.xml + + +// File: dir_98f95006cf3d01c03f5f1dcd2796cea1.xml + + +// File: dir_475b1e2b8823f4954ce71ff73c30d053.xml + + +// File: dir_7ab25f9b685d07ed13e36a824772d506.xml + + +// File: dir_a588aec3e82fcf93c169e09facea5e45.xml + + +// File: dir_4aa7a2573b912138c18e1d44a1da3f20.xml + + +// File: dir_f6cd53f06c8d451cb23b075f1b152ad4.xml + + +// File: dir_c6ef5dad3eb4614ee3542d4c8cc27653.xml + + +// File: dir_abed4454057e3046a7830aeb372c696f.xml + + +// File: dir_4abd1d05a373ee18e10fafc144268c02.xml + + +// File: dir_4a9b39e6c7867f3f2bccc1f0ae75dad7.xml + + +// File: DecompressImage_8cs-example.xml + + +// File: DecompressJPEGFile_8cs-example.xml + + +// File: ManipulateFile_8cs-example.xml + + +// File: PatchFile_8cxx-example.xml + + +// File: ScanDirectory_8cs-example.xml + + +// File: TestByteSwap_8cxx-example.xml + + +// File: TestCSharpFilter_8cs-example.xml + + +// File: TestReader_8cxx-example.xml + + +// File: TestReader_8py-example.xml + + +// File: indexpage.xml diff --git a/gdcm/Wrapping/Csharp/doxy2swig.py b/gdcm/Wrapping/Csharp/doxy2swig.py new file mode 100644 index 0000000..ac636a4 --- /dev/null +++ b/gdcm/Wrapping/Csharp/doxy2swig.py @@ -0,0 +1,460 @@ +#!/usr/bin/env python +"""Doxygen XML to SWIG docstring converter. + +Usage: + + doxy2swig.py [options] input.xml output.i + +Converts Doxygen generated XML files into a file containing docstrings +that can be used by SWIG-1.3.x. Note that you need to get SWIG +version > 1.3.23 or use Robin Dunn's docstring patch to be able to use +the resulting output. + +input.xml is your doxygen generated XML file and output.i is where the +output will be written (the file will be clobbered). + +Code can be found at prabhu's page: + +http://www.aero.iitb.ac.in/~prabhu/software/code/python/doxy2swig.py + +Ref: +http://www.enricozini.org/2007/tips/swig-doxygen-docstring.html +http://internetducttape.com/2007/03/20/automatic_documentation_python_doxygen/ +""" +###################################################################### +# +# This code is implemented using Mark Pilgrim's code as a guideline: +# http://www.faqs.org/docs/diveintopython/kgp_divein.html +# +# Author: Prabhu Ramachandran +# License: BSD style +# +# Thanks: +# Johan Hake: the include_function_definition feature +# Bill Spotz: bug reports and testing. +# +###################################################################### + +from xml.dom import minidom +import re +import textwrap +import sys +import types +import os.path +import optparse + + +def my_open_read(source): + if hasattr(source, "read"): + return source + else: + return open(source) + +def my_open_write(dest): + if hasattr(dest, "write"): + return dest + else: + return open(dest, 'w') + + +class Doxy2SWIG: + """Converts Doxygen generated XML files into a file containing + docstrings that can be used by SWIG-1.3.x that have support for + feature("docstring"). Once the data is parsed it is stored in + self.pieces. + + """ + + def __init__(self, src, include_function_definition=True, quiet=False): + """Initialize the instance given a source object. `src` can + be a file or filename. If you do not want to include function + definitions from doxygen then set + `include_function_definition` to `False`. This is handy since + this allows you to use the swig generated function definition + using %feature("autodoc", [0,1]). + + """ + f = my_open_read(src) + self.my_dir = os.path.dirname(f.name) + self.xmldoc = minidom.parse(f).documentElement + f.close() + + self.pieces = [] + self.pieces.append('\n// File: %s\n'%\ + os.path.basename(f.name)) + + self.space_re = re.compile(r'\s+') + self.lead_spc = re.compile(r'^(%feature\S+\s+\S+\s*?)"\s+(\S)') + self.multi = 0 + self.ignores = ['inheritancegraph', 'param', 'listofallmembers', + 'innerclass', 'name', 'declname', 'incdepgraph', + 'invincdepgraph', 'programlisting', 'type', + 'references', 'referencedby', 'location', + 'collaborationgraph', 'reimplements', + 'reimplementedby', 'derivedcompoundref', + 'basecompoundref'] + #self.generics = [] + self.include_function_definition = include_function_definition + if not include_function_definition: + self.ignores.append('argsstring') + + self.quiet = quiet + + + def generate(self): + """Parses the file set in the initialization. The resulting + data is stored in `self.pieces`. + + """ + self.parse(self.xmldoc) + + def parse(self, node): + """Parse a given node. This function in turn calls the + `parse_` functions which handle the respective + nodes. + + """ + pm = getattr(self, "parse_%s"%node.__class__.__name__) + pm(node) + + def parse_Document(self, node): + self.parse(node.documentElement) + + def parse_Text(self, node): + txt = node.data + txt = txt.replace('\\', r'\\\\') + txt = txt.replace('"', r'\"') + # ignore pure whitespace + m = self.space_re.match(txt) + if m and len(m.group()) == len(txt): + pass + else: + self.add_text(textwrap.fill(txt, break_long_words=False)) + + def parse_Element(self, node): + """Parse an `ELEMENT_NODE`. This calls specific + `do_` handers for different elements. If no handler + is available the `generic_parse` method is called. All + tagNames specified in `self.ignores` are simply ignored. + + """ + name = node.tagName + ignores = self.ignores + if name in ignores: + return + attr = "do_%s" % name + if hasattr(self, attr): + handlerMethod = getattr(self, attr) + handlerMethod(node) + else: + self.generic_parse(node) + #if name not in self.generics: self.generics.append(name) + + def parse_Comment(self, node): + """Parse a `COMMENT_NODE`. This does nothing for now.""" + return + + def add_text(self, value): + """Adds text corresponding to `value` into `self.pieces`.""" + if type(value) in (types.ListType, types.TupleType): + self.pieces.extend(value) + else: + self.pieces.append(value) + + def get_specific_nodes(self, node, names): + """Given a node and a sequence of strings in `names`, return a + dictionary containing the names as keys and child + `ELEMENT_NODEs`, that have a `tagName` equal to the name. + + """ + nodes = [(x.tagName, x) for x in node.childNodes \ + if x.nodeType == x.ELEMENT_NODE and \ + x.tagName in names] + return dict(nodes) + + def generic_parse(self, node, pad=0): + """A Generic parser for arbitrary tags in a node. + + Parameters: + + - node: A node in the DOM. + - pad: `int` (default: 0) + + If 0 the node data is not padded with newlines. If 1 it + appends a newline after parsing the childNodes. If 2 it + pads before and after the nodes are processed. Defaults to + 0. + + """ + npiece = 0 + if pad: + npiece = len(self.pieces) + if pad == 2: + self.add_text('\n') + for n in node.childNodes: + self.parse(n) + if pad: + if len(self.pieces) > npiece: + self.add_text('\n') + + def space_parse(self, node): + self.add_text(' ') + self.generic_parse(node) + + do_ref = space_parse + do_emphasis = space_parse + do_bold = space_parse + do_computeroutput = space_parse + do_formula = space_parse + + def do_compoundname(self, node): + self.add_text('\n\n') + data = node.firstChild.data + #self.add_text('%%feature("docstring") %s "\n'%data) + self.add_text('%%typemap("csclassmodifiers") %s "\n/**'%data) + + def do_compounddef(self, node): + kind = node.attributes['kind'].value + if kind in ('class', 'struct'): + prot = node.attributes['prot'].value + if prot <> 'public': + return + names = ('compoundname', 'briefdescription', + 'detaileddescription', 'includes') + first = self.get_specific_nodes(node, names) + for n in names: + if first.has_key(n): + self.parse(first[n]) + #self.add_text(['";','\n']) + self.add_text(['*/ public class";','\n']) + for n in node.childNodes: + if n not in first.values(): + self.parse(n) + elif kind in ('file', 'namespace'): + nodes = node.getElementsByTagName('sectiondef') + for n in nodes: + self.parse(n) + + def do_includes(self, node): + self.add_text('C++ includes: ') + self.generic_parse(node, pad=1) + + def do_parameterlist(self, node): + text='unknown' + for key, val in node.attributes.items(): + if key == 'kind': + if val == 'param': text = 'Parameters' + elif val == 'exception': text = 'Exceptions' + else: text = val + break + self.add_text(['\n', '\n', text, ':', '\n']) + self.generic_parse(node, pad=1) + + def do_para(self, node): + self.add_text('\n') + self.generic_parse(node, pad=1) + + def do_parametername(self, node): + self.add_text('\n') + try: + data=node.firstChild.data + except AttributeError: # perhaps a tag in it + data=node.firstChild.firstChild.data + if data.find('Exception') != -1: + self.add_text(data) + else: + self.add_text("%s: "%data) + + def do_parameterdefinition(self, node): + self.generic_parse(node, pad=1) + + def do_detaileddescription(self, node): + self.generic_parse(node, pad=1) + + def do_briefdescription(self, node): + self.generic_parse(node, pad=1) + + def do_memberdef(self, node): + prot = node.attributes['prot'].value + id = node.attributes['id'].value + kind = node.attributes['kind'].value + tmp = node.parentNode.parentNode.parentNode + compdef = tmp.getElementsByTagName('compounddef')[0] + cdef_kind = compdef.attributes['kind'].value + + if prot == 'public': + first = self.get_specific_nodes(node, ('definition', 'name')) + name = first['name'].firstChild.data + if name[:8] == 'operator': # Don't handle operators yet. + return + + if not first.has_key('definition') or \ + kind in ['variable', 'typedef']: + return + + if self.include_function_definition: + defn = first['definition'].firstChild.data + else: + defn = "" + self.add_text('\n') + #self.add_text('%feature("docstring") ') + self.add_text('%csmethodmodifiers ') + + anc = node.parentNode.parentNode + if cdef_kind in ('file', 'namespace'): + ns_node = anc.getElementsByTagName('innernamespace') + if not ns_node and cdef_kind == 'namespace': + ns_node = anc.getElementsByTagName('compoundname') + if ns_node: + ns = ns_node[0].firstChild.data + self.add_text(' %s::%s "\n%s'%(ns, name, defn)) + else: + self.add_text(' %s "\n%s'%(name, defn)) + elif cdef_kind in ('class', 'struct'): + # Get the full function name. + anc_node = anc.getElementsByTagName('compoundname') + cname = anc_node[0].firstChild.data + self.add_text(' %s::%s "\n/**\n%s'%(cname, name, defn)) + + for n in node.childNodes: + if n not in first.values(): + self.parse(n) + self.add_text([' */\npublic";', '\n']) + + def do_definition(self, node): + data = node.firstChild.data + self.add_text('%s "\n%s'%(data, data)) + + def do_sectiondef(self, node): + kind = node.attributes['kind'].value + if kind in ('public-func', 'func', 'user-defined', ''): + self.generic_parse(node) + + def do_header(self, node): + """For a user defined section def a header field is present + which should not be printed as such, so we comment it in the + output.""" + data = node.firstChild.data + self.add_text('\n/*\n %s \n*/\n'%data) + # If our immediate sibling is a 'description' node then we + # should comment that out also and remove it from the parent + # node's children. + parent = node.parentNode + idx = parent.childNodes.index(node) + if len(parent.childNodes) >= idx + 2: + nd = parent.childNodes[idx+2] + if nd.nodeName == 'description': + nd = parent.removeChild(nd) + self.add_text('\n/*') + self.generic_parse(nd) + self.add_text('\n*/\n') + + def do_simplesect(self, node): + kind = node.attributes['kind'].value + if kind in ('date', 'rcs', 'version'): + pass + elif kind == 'warning': + self.add_text(['\n', 'WARNING: ']) + self.generic_parse(node) + elif kind == 'see': + self.add_text('\n') + self.add_text('See: ') + self.generic_parse(node) + else: + self.generic_parse(node) + + def do_argsstring(self, node): + self.generic_parse(node, pad=1) + + def do_member(self, node): + kind = node.attributes['kind'].value + refid = node.attributes['refid'].value + if kind == 'function' and refid[:9] == 'namespace': + self.generic_parse(node) + + def do_doxygenindex(self, node): + self.multi = 1 + comps = node.getElementsByTagName('compound') + for c in comps: + refid = c.attributes['refid'].value + fname = refid + '.xml' + if not os.path.exists(fname): + fname = os.path.join(self.my_dir, fname) + if not self.quiet: + print "parsing file: %s"%fname + p = Doxy2SWIG(fname, self.include_function_definition, self.quiet) + p.generate() + self.pieces.extend(self.clean_pieces(p.pieces)) + + def write(self, fname): + o = my_open_write(fname) + if self.multi: + o.write("".join(self.pieces)) + else: + o.write("".join(self.clean_pieces(self.pieces))) + o.close() + + def clean_pieces(self, pieces): + """Cleans the list of strings given as `pieces`. It replaces + multiple newlines by a maximum of 2 and returns a new list. + It also wraps the paragraphs nicely. + + """ + ret = [] + count = 0 + for i in pieces: + if i == '\n': + count = count + 1 + else: + if i == '";': + if count: + ret.append('\n') + elif count > 2: + ret.append('\n\n') + elif count: + ret.append('\n'*count) + count = 0 + ret.append(i) + + _data = "".join(ret) + ret = [] + for i in _data.split('\n\n'): + if i == 'Parameters:' or i == 'Exceptions:': + ret.extend([i, '\n-----------', '\n\n']) + elif i.find('// File:') > -1: # leave comments alone. + ret.extend([i, '\n']) + else: + _tmp = textwrap.fill(i.strip(), break_long_words=False) + _tmp = self.lead_spc.sub(r'\1"\2', _tmp) + ret.extend([_tmp, '\n\n']) + return ret + + +def convert(input, output, include_function_definition=True, quiet=False): + p = Doxy2SWIG(input, include_function_definition, quiet) + p.generate() + p.write(output) + +def main(): + usage = __doc__ + parser = optparse.OptionParser(usage) + parser.add_option("-n", '--no-function-definition', + action='store_true', + default=False, + dest='func_def', + help='do not include doxygen function definitions') + parser.add_option("-q", '--quiet', + action='store_true', + default=False, + dest='quiet', + help='be quiet and minimise output') + + options, args = parser.parse_args() + if len(args) != 2: + parser.error("error: no input and output specified") + + convert(args[0], args[1], not options.func_def, options.quiet) + + +if __name__ == '__main__': + main() diff --git a/gdcm/Wrapping/Csharp/gdcm.i b/gdcm/Wrapping/Csharp/gdcm.i new file mode 100644 index 0000000..cc4a3d9 --- /dev/null +++ b/gdcm/Wrapping/Csharp/gdcm.i @@ -0,0 +1,836 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +// See docs: +// http://www.swig.org/Doc1.3/CSharp.html +// http://www.swig.org/Doc1.3/SWIGPlus.html +// The main difference with this wrapping is that gdcm.System is now renamed +// to gdcm.PosixEmulation. I could not figure out a way to preserve gdcm.System +// as swig by default flatten all namespace and gdcm.System would conflict +// with .NET 'System' namespace... fix welcome to get back gdcm.System +// until then gdcm.PosixEmulation will remain the recommended way to access +// gdcm.System API from C# + +// Some good reference: +// https://code.crt.realtors.org/projects/librets/browser/librets/trunk/project/swig/librets.i?rev=729 +// http://vcielka.darksun.sk/~jnx/download/asterisk/minisip-trunk/libminisip-swig/source/minisip.i +// http://www.mono-project.com/Interop_with_Native_Libraries +// http://msdn.microsoft.com/en-us/magazine/cc301501.aspx +// http://www.codeproject.com/KB/cs/unmanage.aspx +// http://www.gamedev.net/community/forums/mod/journal/journal.asp?jn=458883&reply_id=3221347 +// http://msdn.microsoft.com/en-us/magazine/cc164193.aspx + +/* +> I want to wrap C++ code in C#. Is there a way to instruct swig to insert +> a +> series of "using" statements for each C# source file that gets generated? + + +%pragma(csharp) moduleimports=%{ +using System; +using System.Runtime.InteropServices; +using System.Diagnostics; +using My.Own.Namespace; +%} + +%pragma(csharp) imclassimports=%{ +using System; +using System.Runtime.InteropServices; +using My.Own.Namespace; +%} +*/ + +/* +In order to get documentation on member function and class, one can do (SWIG 1.3.39): + +%csmethodmodifiers gdcm::Tag::GetGroup " + /// + /// This is the GetGroup func + /// + public"; +%typemap(csclassmodifiers) gdcm::Tag "/// coucou class +public class"; +*/ + +%module(docstring="A DICOM library",directors=1) gdcm +#pragma SWIG nowarn=302,303,312,362,383,389,401,503,504,509,510,514,516 + +// There is something funky with swig 1.3.33, one cannot simply test defined(SWIGCSHARP) +// I need to redefine it myself... seems to be solved in later revision +#if defined(SWIGCSHARP) +%{ +#define SWIGCSHARP +%} +#endif + +%{ +#include "gdcmTypes.h" +#include "gdcmASN1.h" +#include "gdcmSmartPointer.h" +#include "gdcmSwapCode.h" +#include "gdcmEvent.h" +#include "gdcmProgressEvent.h" +#include "gdcmAnonymizeEvent.h" +#include "gdcmDirectory.h" +#ifdef GDCM_BUILD_TESTING +#include "gdcmTesting.h" +#endif +#include "gdcmObject.h" +#include "gdcmPixelFormat.h" +#include "gdcmMediaStorage.h" +#include "gdcmTag.h" +#include "gdcmPrivateTag.h" +#include "gdcmVL.h" +#include "gdcmVR.h" +#include "gdcmVM.h" +#include "gdcmObject.h" +#include "gdcmValue.h" +#include "gdcmByteValue.h" +#include "gdcmDataElement.h" +#include "gdcmItem.h" +#include "gdcmSequenceOfItems.h" +#include "gdcmDataSet.h" +//#include "gdcmString.h" +//#include "gdcmCodeString.h" +#include "gdcmPreamble.h" +#include "gdcmFile.h" +#include "gdcmBitmap.h" +#include "gdcmIconImage.h" +#include "gdcmPixmap.h" +#include "gdcmImage.h" +#include "gdcmFragment.h" +#include "gdcmCSAHeader.h" +#include "gdcmPDBHeader.h" +#include "gdcmSequenceOfFragments.h" +#include "gdcmTransferSyntax.h" +#include "gdcmBasicOffsetTable.h" +//#include "gdcmLO.h" +#include "gdcmCSAElement.h" +#include "gdcmPDBElement.h" +#include "gdcmFileSet.h" + +#include "gdcmReader.h" +#include "gdcmPixmapReader.h" +#include "gdcmImageReader.h" +#include "gdcmWriter.h" +#include "gdcmPixmapWriter.h" +#include "gdcmImageWriter.h" +#include "gdcmStringFilter.h" +#include "gdcmGlobal.h" +#include "gdcmDicts.h" +#include "gdcmDict.h" +#include "gdcmCSAHeaderDict.h" +#include "gdcmDictEntry.h" +#include "gdcmCSAHeaderDictEntry.h" +#include "gdcmUIDGenerator.h" +#include "gdcmUUIDGenerator.h" +//#include "gdcmConstCharWrapper.h" +#include "gdcmScanner.h" +#include "gdcmAttribute.h" +#include "gdcmSubject.h" +#include "gdcmCommand.h" +#include "gdcmAnonymizer.h" +#include "gdcmFileAnonymizer.h" +#include "gdcmFileStreamer.h" +#include "gdcmSystem.h" +#include "gdcmTrace.h" +#include "gdcmUIDs.h" +#include "gdcmSorter.h" +#include "gdcmIPPSorter.h" +#include "gdcmSpectroscopy.h" +#include "gdcmPrinter.h" +#include "gdcmXMLPrinter.h" +#include "gdcmDumper.h" +#include "gdcmOrientation.h" +#include "gdcmFiducials.h" +#include "gdcmWaveform.h" +#include "gdcmPersonName.h" +#include "gdcmCurve.h" +#include "gdcmDICOMDIR.h" +#include "gdcmValidate.h" +#include "gdcmApplicationEntity.h" +#include "gdcmDictPrinter.h" +#include "gdcmFilenameGenerator.h" +#include "gdcmVersion.h" +#include "gdcmFilename.h" +#include "gdcmEnumeratedValues.h" +#include "gdcmPatient.h" +#include "gdcmStudy.h" +#include "gdcmUsage.h" +#include "gdcmMacroEntry.h" +#include "gdcmModuleEntry.h" +#include "gdcmNestedModuleEntries.h" +#include "gdcmMacro.h" +#include "gdcmMacros.h" +#include "gdcmModule.h" +#include "gdcmModules.h" +#include "gdcmDefs.h" +#include "gdcmIOD.h" +#include "gdcmIODs.h" +#include "gdcmTableEntry.h" +#include "gdcmDefinedTerms.h" +#include "gdcmSeries.h" +#include "gdcmIODEntry.h" +#include "gdcmRescaler.h" +#include "gdcmSegmentedPaletteColorLookupTable.h" +#include "gdcmUnpacker12Bits.h" +#include "gdcmDirectionCosines.h" +#include "gdcmTagPath.h" +#include "gdcmBitmapToBitmapFilter.h" +#include "gdcmPixmapToPixmapFilter.h" +#include "gdcmImageToImageFilter.h" +#include "gdcmSOPClassUIDToIOD.h" +#include "gdcmCoder.h" +#include "gdcmDecoder.h" +#include "gdcmCodec.h" +#include "gdcmImageCodec.h" +#include "gdcmJPEGCodec.h" +#include "gdcmJPEGLSCodec.h" +#include "gdcmJPEG2000Codec.h" +#include "gdcmPNMCodec.h" +#include "gdcmImageChangeTransferSyntax.h" +#include "gdcmFileChangeTransferSyntax.h" +#include "gdcmImageApplyLookupTable.h" +#include "gdcmSplitMosaicFilter.h" +#include "gdcmImageChangePhotometricInterpretation.h" +#include "gdcmImageChangePlanarConfiguration.h" +#include "gdcmImageFragmentSplitter.h" +#include "gdcmDataSetHelper.h" +#include "gdcmFileExplicitFilter.h" +#include "gdcmImageHelper.h" +#include "gdcmMD5.h" +#include "gdcmDummyValueGenerator.h" +#include "gdcmSHA1.h" +#include "gdcmBase64.h" +#include "gdcmCryptographicMessageSyntax.h" +#include "gdcmCryptoFactory.h" +#include "gdcmSpacing.h" +#include "gdcmIconImageGenerator.h" +#include "gdcmIconImageFilter.h" + +#include "gdcmSimpleSubjectWatcher.h" +#include "gdcmDICOMDIRGenerator.h" +#include "gdcmFileDerivation.h" + +#include "gdcmQueryBase.h" +#include "gdcmQueryFactory.h" +#include "gdcmBaseRootQuery.h" +#include "gdcmPresentationContext.h" +#include "gdcmPresentationContextGenerator.h" +#include "gdcmCompositeNetworkFunctions.h" +#include "gdcmServiceClassUser.h" + +#include "gdcmStreamImageReader.h" + +#include "gdcmRegion.h" +#include "gdcmBoxRegion.h" +#include "gdcmImageRegionReader.h" +#include "gdcmJSON.h" + +using namespace gdcm; +%} + +//%include "docstrings.i" + +// swig need to know what are uint16_t, uint8_t... +%include "stdint.i" + +// gdcm does not use std::string in its interface, but we do need it for the +// %extend (see below) +%include "std_string.i" +%include "std_set.i" +%include "std_vector.i" +%include "std_pair.i" +%include "std_map.i" +%include "exception.i" + +// operator= is not needed in python AFAIK +%ignore operator=; // Ignore = everywhere. +%ignore operator++; // Ignore + +%define EXTEND_CLASS_PRINT_GENERAL(classfuncname,classname) +%extend classname +{ + const char *classfuncname() { + static std::string buffer; + std::ostringstream os; + os << *self; + buffer = os.str(); + return buffer.c_str(); + } +}; +%enddef + +#if defined(SWIGCSHARP) +%define EXTEND_CLASS_PRINT(classname) +EXTEND_CLASS_PRINT_GENERAL(toString,classname) +%enddef +#endif + +//%feature("autodoc", "1") +%include "gdcmConfigure.h" +//%include "gdcmTypes.h" +//%include "gdcmWin32.h" +// I cannot include gdcmWin32.h without gdcmTypes.h, first. But gdcmTypes.h needs to know _MSC_VER at swig time... +#define GDCM_EXPORT +%include "gdcmLegacyMacro.h" + +// The following must be define early on as gdcmVL.h get included real early +%rename(GetValueLength) gdcm::VL::operator uint32_t; +//%csmethodmodifiers gdcm::VL::GetValueLength "private" +//%csmethodmodifiers GetValueLength "private" +//%rename(GetValue) VL::operator uint32_t (); +// public static implicit operator int( MyType a ) +// { +// return a.value; +// } +%include "gdcmSwapCode.h" + +//%feature("director") Event; +//%feature("director") AnyEvent; +%include "gdcmEvent.h" + +%include "gdcmPixelFormat.h" +EXTEND_CLASS_PRINT(gdcm::PixelFormat) +%include "gdcmMediaStorage.h" +EXTEND_CLASS_PRINT(gdcm::MediaStorage) +//%rename(__getitem__) gdcm::Tag::operator[]; +//%rename(this ) gdcm::Tag::operator[]; +%include "gdcmTag.h" +EXTEND_CLASS_PRINT(gdcm::Tag) +%include "gdcmPrivateTag.h" +EXTEND_CLASS_PRINT(gdcm::PrivateTag) + +%include "gdcmProgressEvent.h" +%extend gdcm::ProgressEvent { + static ProgressEvent *Cast(Event *event) { + return dynamic_cast(event); + } +}; +//%feature("director") AnonymizeEvent; +%include "gdcmAnonymizeEvent.h" +%extend gdcm::AnonymizeEvent { + static AnonymizeEvent *Cast(Event *event) { + return dynamic_cast(event); + } +}; + +%include "gdcmVL.h" +EXTEND_CLASS_PRINT(gdcm::VL) +%extend gdcm::VL +{ +%typemap(cscode) VL +%{ + public static implicit operator uint( VL vl ) + { + return vl.GetValueLength(); + } +%} +} +%csmethodmodifiers gdcm::VL::GetValueLength "private" + +%include "gdcmVR.h" +EXTEND_CLASS_PRINT(gdcm::VR) +%include "gdcmVM.h" +EXTEND_CLASS_PRINT(gdcm::VM) +//%template (FilenameType) std::string; +%template (FilenamesType) std::vector; +%include "gdcmDirectory.h" +EXTEND_CLASS_PRINT(gdcm::Directory) +%include "gdcmObject.h" +%include "gdcmValue.h" +EXTEND_CLASS_PRINT(gdcm::Value) +// Array marshaling for arrays of primitives +%define %cs_marshal_array(TYPE, CSTYPE) + %typemap(ctype) TYPE[] "void*" + %typemap(imtype, inattributes="[MarshalAs(UnmanagedType.LPArray)]") TYPE[] "CSTYPE[]" + %typemap(cstype) TYPE[] "CSTYPE[]" + %typemap(in) TYPE[] %{ $1 = (TYPE*)$input; %} + %typemap(csin) TYPE[] "$csinput" +%enddef + +// The following macro invocations allow you to pass arrays of primitive +// types. Arrays of other things such as System.Drawing.Point are also +// possible. +%cs_marshal_array(bool, bool) +%cs_marshal_array(char, byte) +%cs_marshal_array(short, short) +%cs_marshal_array(unsigned short, ushort) +%cs_marshal_array(int, int) +%cs_marshal_array(unsigned int, uint) +%cs_marshal_array(long, int) +%cs_marshal_array(unsigned long, uint) +%cs_marshal_array(long long, long) +%cs_marshal_array(unsigned long long, ulong) +%cs_marshal_array(float, float) +%cs_marshal_array(double, double) + + +// %clear commands should be unnecessary, but do it just-in-case +%clear char* buffer; +%clear unsigned char* buffer; + +%apply char[] { char* buffer } +%ignore gdcm::ByteValue::WriteBuffer(std::ostream &os) const; +//%ignore gdcm::ByteValue::GetPointer() const; +//%ignore gdcm::ByteValue::GetBuffer(char *buffer, unsigned long length) const; +%include "gdcmByteValue.h" +EXTEND_CLASS_PRINT(gdcm::ByteValue) +%clear char* buffer; + +%apply char[] { const char* array } + +%include "gdcmASN1.h" +%include "gdcmSmartPointer.h" +%template(SmartPtrSQ) gdcm::SmartPointer; +%template(SmartPtrFrag) gdcm::SmartPointer; +%include "gdcmDataElement.h" +EXTEND_CLASS_PRINT(gdcm::DataElement) + +%clear const char* array; +%extend gdcm::DataElement +{ + void SetArray(unsigned char array[], unsigned int nitems) { + $self->SetByteValue((char*)array, nitems * sizeof(unsigned char) ); + } + void SetArray(char array[], unsigned int nitems) { + $self->SetByteValue((char*)array, nitems * sizeof(char) ); + } + void SetArray(unsigned short array[], unsigned int nitems) { + $self->SetByteValue((char*)array, nitems * sizeof(unsigned short) ); + } + void SetArray(short array[], unsigned int nitems) { + $self->SetByteValue((char*)array, nitems * sizeof(short) ); + } + void SetArray(float array[], unsigned int nitems) { + $self->SetByteValue((char*)array, nitems * sizeof(float) ); + } + void SetArray(double array[], unsigned int nitems) { + $self->SetByteValue((char*)array, nitems * sizeof(double) ); + } +}; + +%include "gdcmItem.h" +EXTEND_CLASS_PRINT(gdcm::Item) +/* + The following line is very important it properly convert : +SWIGTYPE_p_std__vectorT_int_t__size_type -> uint +*/ +%template() std::vector< gdcm::Item >; +%include "gdcmSequenceOfItems.h" +EXTEND_CLASS_PRINT(gdcm::SequenceOfItems) +%rename (CSharpDataSet) SWIGDataSet; +%rename (CSharpTagToValue) SWIGTagToValue; +%include "gdcmDataSet.h" +EXTEND_CLASS_PRINT(gdcm::DataSet) +//%include "gdcmString.h" +//%include "gdcmTransferSyntax.h" +%include "gdcmPhotometricInterpretation.h" +EXTEND_CLASS_PRINT(gdcm::PhotometricInterpretation) +%include "gdcmObject.h" +%apply char[] { char* thebuffer } +%apply char[] { const char* inputbuffer } +%apply char[] { char* outputbuffer } +%ignore gdcm::LookupTable::GetLUT(LookupTableType type, unsigned char *array, unsigned int &length) const; +%include "gdcmLookupTable.h" +%extend gdcm::LookupTable +{ + unsigned int GetLUT(LookupTableType type, char *thebuffer) const { + unsigned int length = 0; + self->GetLUT( type, (unsigned char*)thebuffer, length); + return length; + } +}; +%clear char* thebuffer; +%clear char* inputbuffer; +%clear char* outputbuffer; +EXTEND_CLASS_PRINT(gdcm::LookupTable) +%include "gdcmOverlay.h" +EXTEND_CLASS_PRINT(gdcm::Overlay) +//%include "gdcmVR.h" +//%template (DataElementSet) std::set; +%include "gdcmPreamble.h" +EXTEND_CLASS_PRINT(gdcm::Preamble) +%include "gdcmTransferSyntax.h" +EXTEND_CLASS_PRINT(gdcm::TransferSyntax) +%include "gdcmFileMetaInformation.h" +EXTEND_CLASS_PRINT(gdcm::FileMetaInformation) + +//%template(File) gdcm::SmartPointer; +//%ignore gdcm::File; + +%include "gdcmFile.h" +EXTEND_CLASS_PRINT(gdcm::File) +//%include "gdcm_arrays_csharp.i" + +%apply char[] { char* buffer } +%apply unsigned int[] { unsigned int dims[2] } +%apply unsigned int[] { unsigned int dims[3] } + +//%apply byte OUTPUT[] { char* buffer } ; +//%ignore gdcm::Pixmap::GetBuffer(char*) const; +//%apply byte FIXED[] { char *buffer } +//%csmethodmodifiers gdcm::Pixmap::GetBuffer "public unsafe"; +//%define %cs_marshal_array(TYPE, CSTYPE) +// %typemap(ctype) TYPE[] "void*" +// %typemap(imtype, inattributes="[MarshalAs(UnmanagedType.LPArray)]") TYPE[] "CSTYPE[]" +// %typemap(cstype) TYPE[] "CSTYPE[]" +// %typemap(in) TYPE[] %{ $1 = (TYPE*)$input; %} +// %typemap(csin) TYPE[] "$csinput" +//%enddef +//%cs_marshal_array(char, byte) +%include "gdcmBitmap.h" +EXTEND_CLASS_PRINT(gdcm::Bitmap) +%extend gdcm::Bitmap +{ + bool GetArray(unsigned char buffer[]) const { + assert( $self->GetPixelFormat() == PixelFormat::UINT8 ); + return $self->GetBuffer((char*)buffer); + } + bool GetArray(char buffer[]) const { + assert( $self->GetPixelFormat() == PixelFormat::INT8 ); + return $self->GetBuffer((char*)buffer); + } + bool GetArray(unsigned short buffer[]) const { + assert( $self->GetPixelFormat() == PixelFormat::UINT16 ); + return $self->GetBuffer((char*)buffer); + } + bool GetArray(short buffer[]) const { + assert( $self->GetPixelFormat() == PixelFormat::INT16 ); + return $self->GetBuffer((char*)buffer); + } + bool GetArray(float buffer[]) const { + assert( $self->GetPixelFormat() == PixelFormat::FLOAT32 ); + return $self->GetBuffer((char*)buffer); + } + bool GetArray(double buffer[]) const { + assert( $self->GetPixelFormat() == PixelFormat::FLOAT64 ); + return $self->GetBuffer((char*)buffer); + } +}; +%clear char* buffer; +%clear unsigned int* dims; + +%include "gdcmIconImage.h" +EXTEND_CLASS_PRINT(gdcm::IconImage) +%include "gdcmPixmap.h" +EXTEND_CLASS_PRINT(gdcm::Pixmap) + +%include "gdcmImage.h" +EXTEND_CLASS_PRINT(gdcm::Image) +%include "gdcmFragment.h" +EXTEND_CLASS_PRINT(gdcm::Fragment) +%include "gdcmPDBElement.h" +EXTEND_CLASS_PRINT(gdcm::PDBElement) +%include "gdcmPDBHeader.h" +EXTEND_CLASS_PRINT(gdcm::PDBHeader) +%include "gdcmCSAElement.h" +EXTEND_CLASS_PRINT(gdcm::CSAElement) +%include "gdcmCSAHeader.h" +EXTEND_CLASS_PRINT(gdcm::CSAHeader) +%include "gdcmSequenceOfFragments.h" +EXTEND_CLASS_PRINT(gdcm::SequenceOfFragments) +%include "gdcmBasicOffsetTable.h" +EXTEND_CLASS_PRINT(gdcm::BasicOffsetTable) +//%include "gdcmLO.h" +%include "gdcmFileSet.h" +EXTEND_CLASS_PRINT(gdcm::FileSet) + +%include "gdcmGlobal.h" +EXTEND_CLASS_PRINT(gdcm::Global) + +%include "gdcmDictEntry.h" +EXTEND_CLASS_PRINT(gdcm::DictEntry) +%include "gdcmCSAHeaderDictEntry.h" +EXTEND_CLASS_PRINT(gdcm::CSAHeaderDictEntry) + +%include "gdcmDict.h" +EXTEND_CLASS_PRINT(gdcm::Dict) +%include "gdcmCSAHeaderDict.h" +EXTEND_CLASS_PRINT(gdcm::CSAHeaderDictEntry) +%include "gdcmDicts.h" +EXTEND_CLASS_PRINT(gdcm::Dicts) + +%template (TagSetType) std::set; +%ignore gdcm::Reader::SetStream; +%include "gdcmReader.h" +//EXTEND_CLASS_PRINT(gdcm::Reader) +%include "gdcmPixmapReader.h" +//EXTEND_CLASS_PRINT(gdcm::PixmapReader) +%include "gdcmImageReader.h" +//EXTEND_CLASS_PRINT(gdcm::ImageReader) +%include "gdcmWriter.h" +//EXTEND_CLASS_PRINT(gdcm::Writer) +%include "gdcmPixmapWriter.h" +//EXTEND_CLASS_PRINT(gdcm::PixmapWriter) +%include "gdcmImageWriter.h" +//EXTEND_CLASS_PRINT(gdcm::ImageWriter) +%template (PairString) std::pair; +//%template (MyM) std::map; +%include "gdcmStringFilter.h" +//EXTEND_CLASS_PRINT(gdcm::StringFilter) +%include "gdcmUIDGenerator.h" +//EXTEND_CLASS_PRINT(gdcm::UIDGenerator) +%include "gdcmUUIDGenerator.h" +//EXTEND_CLASS_PRINT(gdcm::UUIDGenerator) +%template (ValuesType) std::set; +%rename (CSharpTagToValue) SWIGTagToValue; +#define GDCM_STATIC_ASSERT(x) +%include "gdcmAttribute.h" +%include "gdcmSubject.h" +%include "gdcmCommand.h" + +%template(SmartPtrScan) gdcm::SmartPointer; +%include "gdcmScanner.h" +EXTEND_CLASS_PRINT(gdcm::Scanner) + +%template(SmartPtrAno) gdcm::SmartPointer; +//%ignore gdcm::Anonymizer::Anonymizer; + + +//%template(Anonymizer) gdcm::SmartPointer; +// +//%ignore gdcm::Anonymizer; +//%feature("unref") Anonymizer "coucou $this->Delete();" +// http://www.swig.org/Doc1.3/SWIGPlus.html#SWIGPlus%5Fnn34 +%include "gdcmAnonymizer.h" +%apply char[] { char* value_data } +%include "gdcmFileAnonymizer.h" +%clear char* value_data; + +%apply char[] { char* array } +%template(SmartPtrFStreamer) gdcm::SmartPointer; +%include "gdcmFileStreamer.h" +%clear char* array; + +//EXTEND_CLASS_PRINT(gdcm::Anonymizer) +//%extend gdcm::Anonymizer +//{ +//%typemap(cscode) gdcm::Anonymizer +//%{ +// public Anonymizer() : this(gdcmPINVOKE.Anonymizer_New(), false) { +// } +//%} +//}; + +// System is a namespace in C#, need to rename to something different +%rename (PosixEmulation) System; +%include "gdcmSystem.h" +//EXTEND_CLASS_PRINT(gdcm::System) + +%include "gdcmTrace.h" +//EXTEND_CLASS_PRINT(gdcm::Trace) +%include "gdcmUIDs.h" +EXTEND_CLASS_PRINT(gdcm::UIDs) +//%feature("director") gdcm::IPPSorter; + +//////////////////////////////////////////////////////////////////////////// +// cs_callback is used to marshall callbacks. It allows a C# function to +// be passed to C++ as a function pointer through P/Invoke, which has the +// ability to make unmanaged-to-managed thunks. It does NOT allow you to +// pass C++ function pointers to C#. +// +// I would have liked to support FastDelegate<...> as the C++ argument +// type; this would have involved the cs_callback2 macro... but it turns +// out not to work under default project settings because .NET functions +// use the __stdcall calling convention, but FastDelegate uses the default +// convention which tends to be something else (__fastcall?). So nevermind. +// +// Anyway, to use this macro you need to declare the function pointer type +// TYPE in the appropriate header file (including the calling convention), +// declare a delegate named after CSTYPE in your C# project, and use this +// macro in your .i file. Here is an example: +// +// in C++ header file (%include this header in your .i file): +// typedef void (__stdcall *Callback)(PCWSTR); +// void Foo(Callback c); +// +// in C# code: +// public delegate void CppCallback([MarshalAs(UnmanagedType.LPWStr)] string message); +// +// in your .i file: +// %cs_callback(Callback, CppCallback) +// +// Remember to invoke %cs_callback before any code involving Callback. +%define %cs_callback(TYPE, CSTYPE) + %typemap(ctype) TYPE, TYPE& "void*" + %typemap(in) TYPE %{ $1 = (TYPE)$input; %} + %typemap(in) TYPE& %{ $1 = (TYPE*)&$input; %} + %typemap(imtype, out="IntPtr") TYPE, TYPE& "CSTYPE" + %typemap(cstype, out="IntPtr") TYPE, TYPE& "CSTYPE" + %typemap(csin) TYPE, TYPE& "$csinput" +%enddef +%define %cs_callback2(TYPE, CTYPE, CSTYPE) + %typemap(ctype) TYPE "CTYPE" + %typemap(in) TYPE %{ $1 = (TYPE)$input; %} + %typemap(imtype, out="IntPtr") TYPE "CSTYPE" + %typemap(cstype, out="IntPtr") TYPE "CSTYPE" + %typemap(csin) TYPE "$csinput" +%enddef + +%cs_callback(Sorter::SortFunction, Sorter::CppSortFunction) + +%include "gdcmSorter.h" +EXTEND_CLASS_PRINT(gdcm::Sorter) +%include "gdcmIPPSorter.h" +EXTEND_CLASS_PRINT(gdcm::IPPSorter) +%include "gdcmSpectroscopy.h" +//EXTEND_CLASS_PRINT(gdcm::Spectroscopy) +%include "gdcmPrinter.h" +//EXTEND_CLASS_PRINT(gdcm::Printer) +%include "gdcmXMLPrinter.h" +//EXTEND_CLASS_PRINT(gdcm::XMLPrinter) +%include "gdcmDumper.h" +//EXTEND_CLASS_PRINT(gdcm::Dumper) +%include "gdcmOrientation.h" +EXTEND_CLASS_PRINT(gdcm::Orientation) +%include "gdcmDirectionCosines.h" +EXTEND_CLASS_PRINT(gdcm::DirectionCosines) + +%include "gdcmFiducials.h" +%include "gdcmWaveform.h" +%include "gdcmPersonName.h" +%include "gdcmCurve.h" +%include "gdcmDICOMDIR.h" +%include "gdcmValidate.h" +%include "gdcmApplicationEntity.h" +%include "gdcmDictPrinter.h" +%include "gdcmFilenameGenerator.h" +%include "gdcmVersion.h" +EXTEND_CLASS_PRINT(gdcm::Version) +%include "gdcmFilename.h" +%include "gdcmEnumeratedValues.h" +%include "gdcmPatient.h" +%include "gdcmStudy.h" +%include "gdcmUsage.h" +%include "gdcmMacroEntry.h" +%include "gdcmModuleEntry.h" +EXTEND_CLASS_PRINT(gdcm::ModuleEntry) +%include "gdcmNestedModuleEntries.h" +%include "gdcmMacro.h" +%include "gdcmMacros.h" +%include "gdcmModule.h" +%include "gdcmModules.h" +%include "gdcmDefs.h" +%include "gdcmIOD.h" +%include "gdcmIODs.h" +%include "gdcmTableEntry.h" +%include "gdcmDefinedTerms.h" +%include "gdcmSeries.h" +%include "gdcmIODEntry.h" + +%apply char[] { char* out } +%apply char[] { char* in } +%include "gdcmRescaler.h" +//EXTEND_CLASS_PRINT(gdcm::Rescaler) +%extend gdcm::Rescaler +{ + bool Rescale(double out[], const short in[], size_t n) { + return $self->Rescale((char*)out, (char*)in, n); + } +} +%clear char* out; +%clear char* in; + +%include "gdcmSegmentedPaletteColorLookupTable.h" +%include "gdcmUnpacker12Bits.h" + +%include "gdcmConfigure.h" +#ifdef GDCM_BUILD_TESTING +%include "gdcmTesting.h" +%ignore gdcm::Testing::ComputeMD5(const char *, const unsigned long , char []); +%ignore gdcm::Testing::ComputeFileMD5(const char*, char []); +%extend gdcm::Testing +{ + static const char *ComputeFileMD5(const char *filename) { + static char buffer[33]; + gdcm::Testing::ComputeFileMD5(filename, buffer); + return buffer; + } +}; +#endif +%include "gdcmTagPath.h" +%include "gdcmBitmapToBitmapFilter.h" +%include "gdcmPixmapToPixmapFilter.h" +//%ignore gdcm::ImageToImageFilter::GetOutput() const; +%include "gdcmImageToImageFilter.h" +%include "gdcmSOPClassUIDToIOD.h" +//%feature("director") Coder; +//%include "gdcmCoder.h" +//%feature("director") Decoder; +//%include "gdcmDecoder.h" +//%feature("director") Codec; +//%include "gdcmCodec.h" +%feature("director") ImageCodec; +%include "gdcmImageCodec.h" +%include "gdcmJPEGCodec.h" +%include "gdcmJPEGLSCodec.h" +%include "gdcmJPEG2000Codec.h" +%include "gdcmPNMCodec.h" +%include "gdcmImageChangeTransferSyntax.h" +%template(SmartPtrFCTS) gdcm::SmartPointer; +%include "gdcmFileChangeTransferSyntax.h" +%include "gdcmImageApplyLookupTable.h" +%include "gdcmSplitMosaicFilter.h" +%include "gdcmImageChangePhotometricInterpretation.h" +%include "gdcmImageChangePlanarConfiguration.h" +%include "gdcmImageFragmentSplitter.h" +%include "gdcmDataSetHelper.h" +%include "gdcmFileExplicitFilter.h" +%template (DoubleArrayType) std::vector; +%template (UShortArrayType) std::vector; +%template (UIntArrayType) std::vector; +%include "gdcmImageHelper.h" +%include "gdcmMD5.h" +%include "gdcmDummyValueGenerator.h" +%include "gdcmSHA1.h" +%include "gdcmBase64.h" +%include "gdcmCryptographicMessageSyntax.h" +%include "gdcmCryptoFactory.h" +%include "gdcmSpacing.h" +%include "gdcmIconImageGenerator.h" +%include "gdcmIconImageFilter.h" + +%feature("director") SimpleSubjectWatcher; +%include "gdcmSimpleSubjectWatcher.h" +%include "gdcmDICOMDIRGenerator.h" +%include "gdcmFileDerivation.h" + +// MEXD: +%template(DataSetArrayType) std::vector< gdcm::DataSet >; +%template(FileArrayType) std::vector< gdcm::File >; +%template(PresentationContextArrayType) std::vector< gdcm::PresentationContext >; +%template(KeyValuePairType) std::pair< gdcm::Tag, std::string>; +%template(KeyValuePairArrayType) std::vector< std::pair< gdcm::Tag, std::string> >; +%template(TagArrayType) std::vector< gdcm::Tag >; +%include "gdcmQueryBase.h" +%include "gdcmBaseRootQuery.h" +%include "gdcmQueryFactory.h" +%template(CharSetArrayType) std::vector< gdcm::ECharSet >; +%include "gdcmCompositeNetworkFunctions.h" +%include "gdcmPresentationContext.h" +//EXTEND_CLASS_PRINT(gdcm::PresentationContext) +%include "gdcmPresentationContextGenerator.h" +typedef int64_t time_t; // FIXME +%include "gdcmServiceClassUser.h" +%apply char[] { char* inReadBuffer } +%include "gdcmStreamImageReader.h" +%clear char* inReadBuffer; +%include "gdcmRegion.h" +EXTEND_CLASS_PRINT(gdcm::Region) +%include "gdcmBoxRegion.h" +EXTEND_CLASS_PRINT(gdcm::BoxRegion) +%apply char[] { char* inreadbuffer } +%include "gdcmImageRegionReader.h" +%clear char* inreadbuffer; +%include "gdcmJSON.h" diff --git a/gdcm/Wrapping/Csharp/gdcm_arrays_csharp.i b/gdcm/Wrapping/Csharp/gdcm_arrays_csharp.i new file mode 100644 index 0000000..b2a68c0 --- /dev/null +++ b/gdcm/Wrapping/Csharp/gdcm_arrays_csharp.i @@ -0,0 +1,139 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * arrays_csharp.i + * + * This file contains a two approaches to marshaling arrays. The first uses + * default p/invoke marshaling and the second uses pinning of the arrays. + * + * Default marshaling approach + * ---------------------------- + * Array typemaps using default p/invoke marshaling. The data is copied to a separately + * allocated buffer when passing over the managed-native boundary. + * + * There are separate typemaps for in, out and inout arrays to enable avoiding + * unnecessary copying. + * + * Example usage: + * + * %include "arrays_csharp.i" + * %apply int INPUT[] { int* sourceArray } + * %apply int OUTPUT[] { int* targetArray } + * void myArrayCopy( int* sourceArray, int* targetArray, int nitems ); + * + * %apply int INOUT[] { int* array1, int *array2 } + * void myArraySwap( int* array1, int* array2, int nitems ); + * + * If handling large arrays you should consider using the pinning array typemaps + * described next. + * + * Pinning approach + * ---------------- + * Array typemaps using pinning. These typemaps pin the managed array given + * as parameter and pass a pointer to it to the c/c++ side. This is very + * efficient as no copying is done (unlike in the default array marshaling), + * but it makes garbage collection more difficult. When considering using + * these typemaps, think carefully whether you have callbacks that may cause + * the control to re-enter the managed side from within the call (and produce + * garbage for the gc) or whether other threads may produce enough garbage to + * trigger gc while the call is being executed. In those cases it may be + * wiser to use the default marshaling typemaps. + * + * Please note that when using fixed arrays, you have to mark your corresponding + * module class method unsafe using + * %csmethodmodifiers "public unsafe" + * (the visibility of the method is up to you). + * + * Example usage: + * + * %include "arrays_csharp.i" + * %apply int FIXED[] { int* sourceArray, int *targetArray } + * %csmethodmodifiers myArrayCopy "public unsafe"; + * void myArrayCopy( int *sourceArray, int* targetArray, int nitems ); + * + * ----------------------------------------------------------------------------- */ + +%define CSHARP_ARRAYS( CTYPE, CSTYPE ) + +// input only arrays + +%typemap(ctype) CTYPE INPUT[] "CTYPE*" +%typemap(cstype) CTYPE INPUT[] "CSTYPE[]" +%typemap(imtype, inattributes="[In, MarshalAs(UnmanagedType.LPArray)]") CTYPE INPUT[] "CSTYPE[]" +%typemap(csin) CTYPE INPUT[] "$csinput" + +%typemap(in) CTYPE INPUT[] "$1 = $input;" +%typemap(freearg) CTYPE INPUT[] "" +%typemap(argout) CTYPE INPUT[] "" + +// output only arrays + +%typemap(ctype) CTYPE OUTPUT[] "CTYPE*" +%typemap(cstype) CTYPE OUTPUT[] "CSTYPE[]" +%typemap(imtype, inattributes="[Out, MarshalAs(UnmanagedType.LPArray)]") CTYPE OUTPUT[] "CSTYPE[]" +%typemap(csin) CTYPE OUTPUT[] "$csinput" + +%typemap(in) CTYPE OUTPUT[] "$1 = $input;" +%typemap(freearg) CTYPE OUTPUT[] "" +%typemap(argout) CTYPE OUTPUT[] "" + +// inout arrays + +%typemap(ctype) CTYPE INOUT[] "CTYPE*" +%typemap(cstype) CTYPE INOUT[] "CSTYPE[]" +%typemap(imtype, inattributes="[In, Out, MarshalAs(UnmanagedType.LPArray)]") CTYPE INOUT[] "CSTYPE[]" +%typemap(csin) CTYPE INOUT[] "$csinput" + +%typemap(in) CTYPE INOUT[] "$1 = $input;" +%typemap(freearg) CTYPE INOUT[] "" +%typemap(argout) CTYPE INOUT[] "" + +%enddef // CSHARP_ARRAYS + +CSHARP_ARRAYS(signed char, sbyte) +CSHARP_ARRAYS(unsigned char, byte) +CSHARP_ARRAYS(short, short) +CSHARP_ARRAYS(unsigned short, ushort) +CSHARP_ARRAYS(int, int) +CSHARP_ARRAYS(unsigned int, uint) +// FIXME - on Unix 64 bit, long is 8 bytes but is 4 bytes on Windows 64 bit. +// How can this be handled sensibly? +// See e.g. http://www.xml.com/ldd/chapter/book/ch10.html +CSHARP_ARRAYS(long, int) +CSHARP_ARRAYS(unsigned long, uint) +CSHARP_ARRAYS(long long, long) +CSHARP_ARRAYS(unsigned long long, ulong) +CSHARP_ARRAYS(float, float) +CSHARP_ARRAYS(double, double) + + +%define CSHARP_ARRAYS_FIXED( CTYPE, CSTYPE ) + +%typemap(ctype) CTYPE FIXED[] "CTYPE*" +%typemap(imtype) CTYPE FIXED[] "IntPtr" +%typemap(cstype) CTYPE FIXED[] "CSTYPE[]" +%typemap(csin, + pre= " fixed ( CSTYPE* swig_ptrTo_$csinput = $csinput ) {", + terminator=" }") + CTYPE FIXED[] "(IntPtr)swig_ptrTo_$csinput" + +%typemap(in) CTYPE FIXED[] "$1 = $input;" +%typemap(freearg) CTYPE FIXED[] "" +%typemap(argout) CTYPE FIXED[] "" + + +%enddef // CSHARP_ARRAYS_FIXED + +CSHARP_ARRAYS_FIXED(signed char, sbyte) +CSHARP_ARRAYS_FIXED(unsigned char, byte) +CSHARP_ARRAYS_FIXED(short, short) +CSHARP_ARRAYS_FIXED(unsigned short, ushort) +CSHARP_ARRAYS_FIXED(int, int) +CSHARP_ARRAYS_FIXED(unsigned int, uint) +CSHARP_ARRAYS_FIXED(long, int) +CSHARP_ARRAYS_FIXED(unsigned long, uint) +CSHARP_ARRAYS_FIXED(long long, long) +CSHARP_ARRAYS_FIXED(unsigned long long, ulong) +CSHARP_ARRAYS_FIXED(float, float) +CSHARP_ARRAYS_FIXED(double, double) diff --git a/gdcm/Wrapping/Csharp/key.snk b/gdcm/Wrapping/Csharp/key.snk new file mode 100644 index 0000000000000000000000000000000000000000..bda8ac6a2c2340bf70a393ce52c0aa8aea4c0e2f GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONaL00016`OgC3;;%No0iA4La!f|Ve3!{xjv|Ue zEdpc`Zt)u$Gxi~B;#~!`w0<2j{XTQ43Ebm{<(}o@YPA~Jp)hE+g2i7{Mev8vE)anq z(TYWRJ0_LQi$MR2vV4$H67z!Oyhx@K)uZAzd38yIG*=d_Dh3*vxw)BA&Xf9~3Gt0m&#nbIZ{?Rh0?aj99VRN>rnDZ>WI^b}GP%@* z7HGRJZm6eEe?y7k*2#gUsb<3TRvCa8ZI%qLs+}*Lit}S<%Wnj{?lsIz6<+Gl+ z4x#JzHG|rV+LW;CfFKVsQ;LD*^(xi##rWi}5Yt0liGGOZ-jdx;Eq8Tb4l%lal*PeT zc=Vv%d*x~IrAu$FDB+r3uc}1`2T<$BJ6o^ + * + * The C# wrapper is made to look and feel like a C# System.Collections.Generic.ISet<>. + * + * Using this wrapper is fairly simple. For example, to create a set of integers use: + * + * %include + * %template(SetInt) std::set + * + * Notes: + * 1) IEnumerable<> is implemented in the proxy class which is useful for using LINQ with + * C++ std::set wrappers. + * + * Warning: heavy macro usage in this file. Use swig -E to get a sane view on the real file contents! + * ----------------------------------------------------------------------------- */ + +%{ +#include +#include +#include +%} + +/* V is the C++ value type */ +%define SWIG_STD_SET_INTERNAL(V) + +%typemap(csinterfaces) std::set< V > "IDisposable \n#if SWIG_DOTNET_3\n , System.Collections.Generic.ISet<$typemap(cstype, V)>\n#endif\n"; +%typemap(cscode) std::set %{ + + public $typemap(cstype, V) this[$typemap(cstype, V) key] { + get { + return getitem(key); + } + + set { + setitem(value); + } + } + +// public bool TryGetValue($typemap(cstype, V) value) { +// if (this.ContainsKey(key)) { +// value = this[key]; +// return true; +// } +// value = default($typemap(cstype, T)); +// return false; +// } + + public int Count { + get { + return (int)size(); + } + } + + public bool IsReadOnly { + get { + return false; + } + } + +%} + + public: + set(); + set(const set< V > &other); + + typedef V value_type; + typedef size_t size_type; + size_type size() const; + bool empty() const; + %rename(Clear) clear; + void clear(); + %extend { + const value_type& getitem(const value_type& val) throw (std::out_of_range) { + std::set< V >::iterator iter = $self->find(val); + if (iter != $self->end()) + return *iter; + else + throw std::out_of_range("key not found"); + } + + void setitem(const value_type& x) { + (*$self).insert(x); + } + + bool Contains(const value_type& val) { + std::set< V >::iterator iter = $self->find(val); + return iter != $self->end(); + } + + void Add(const value_type& val) throw (std::out_of_range) { + std::set< V >::iterator iter = $self->find(val); + if (iter != $self->end()) + throw std::out_of_range("key already exists"); + $self->insert(val); + } + + bool Remove(const value_type& val) { + std::set< V >::iterator iter = $self->find(val); + if (iter != $self->end()) { + $self->erase(iter); + return true; + } + return false; + } + + // create_iterator_begin(), get_next_key() and destroy_iterator work together to provide a collection of keys to C# + %apply void *VOID_INT_PTR { std::set< V >::iterator *create_iterator_begin } + %apply void *VOID_INT_PTR { std::set< V >::iterator *swigiterator } + + std::set< V >::iterator *create_iterator_begin() { + return new std::set< V >::iterator($self->begin()); + } + + const value_type& get_next_key(std::set< V >::iterator *swigiterator) { + std::set< V >::iterator iter = *swigiterator; + swigiterator++; + return *iter; + } + + void destroy_iterator(std::set< V >::iterator *swigiterator) { + delete swigiterator; + } + } + + +%enddef + +%csmethodmodifiers std::set::size "private" +%csmethodmodifiers std::set::getitem "private" +%csmethodmodifiers std::set::setitem "private" +%csmethodmodifiers std::set::create_iterator_begin "private" +%csmethodmodifiers std::set::get_next_key "private" +%csmethodmodifiers std::set::destroy_iterator "private" + +// Default implementation +namespace std { + template class set { + SWIG_STD_SET_INTERNAL(V) + }; +} diff --git a/gdcm/Wrapping/Java/CMakeLists.txt b/gdcm/Wrapping/Java/CMakeLists.txt new file mode 100644 index 0000000..349f118 --- /dev/null +++ b/gdcm/Wrapping/Java/CMakeLists.txt @@ -0,0 +1,102 @@ +# TODO: +# SWIG is really a pain in the neck to use, a better alternative is Py++ which is using +# gccxml for the C++ parser and allow a full ANSI C++ support +find_package(SWIG REQUIRED) +include(${SWIG_USE_FILE}) +option(GDCM_AUTOLOAD_GDCMJNI "Automatically load gdcmjni" ON) + +include_directories( + "${GDCM_BINARY_DIR}/Source/Common" + "${GDCM_SOURCE_DIR}/Source/Common" + "${GDCM_SOURCE_DIR}/Source/DataStructureAndEncodingDefinition" + "${GDCM_SOURCE_DIR}/Source/InformationObjectDefinition" + "${GDCM_SOURCE_DIR}/Source/MediaStorageAndFileFormat" + "${GDCM_SOURCE_DIR}/Source/DataDictionary" + "${GDCM_SOURCE_DIR}/Source/MessageExchangeDefinition" +) + +# $ export JAVA_HOME=/usr/lib/j2sdk1.6-sun/ +# $ export JAVA_HOME=/usr/lib/jvm/java-1.5.0-sun/ +find_package(Java 1.5 REQUIRED) # javac, jar +find_package(JNI REQUIRED) +include_directories( + ${JNI_INCLUDE_DIRS} + ) +set_source_files_properties(gdcm.i PROPERTIES CPLUSPLUS ON) +#include(${GDCM_SOURCE_DIR}/CMake/UseSWIGExtra.cmake) + +set(GDCM_JAVA_HOME ${CMAKE_CURRENT_BINARY_DIR}/java/gdcm) +file(MAKE_DIRECTORY ${GDCM_JAVA_HOME}) +set(CMAKE_SWIG_OUTDIR "${GDCM_JAVA_HOME}") + +set(CMAKE_SWIG_FLAGS "-package gdcm") +separate_arguments(CMAKE_SWIG_FLAGS) +# http://www.debian.org/doc/packaging-manuals/java-policy/x105.html +SWIG_ADD_MODULE(gdcmjni java gdcm.i) +SWIG_LINK_LIBRARIES(gdcmjni gdcmMSFF + gdcmMEXD + # There is no real point in linking explicitely to jni libraries. This is a java module + # it could contains undefined symbols after all. + #${JNI_LIBRARIES} +) +set_target_properties(${SWIG_MODULE_gdcmjni_REAL_NAME} PROPERTIES LINK_INTERFACE_LIBRARIES "") +set_property(TARGET ${SWIG_MODULE_gdcmjni_REAL_NAME} PROPERTY NO_SONAME 1) + +# swig-java dummy run: +# the following execute_process is a dummy run and generate all *.java files in a directory +# we can then glob all *.java to build rules in case the java wrapper becomes broken +#execute_process(COMMAND ${SWIG_EXECUTABLE} +# -java +# -I${GDCM_BINARY_DIR}/Source/Common +# -I${GDCM_SOURCE_DIR}/Source/Common +# -I${GDCM_SOURCE_DIR}/Source/DataStructureAndEncodingDefinition +# -I${GDCM_SOURCE_DIR}/Source/MediaStorageAndFileFormat +# -I${GDCM_SOURCE_DIR}/Source/DataDictionary +# -c++ +# -o dummy.o +# ${CMAKE_CURRENT_SOURCE_DIR}/gdcm.i +# WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} +# RESULT_VARIABLE res +#) +#message("res:${res}") +#file(GLOB javafiles "${CMAKE_CURRENT_BINARY_DIR}/*.java") +#message("javafile:${javafiles}") + +if(CMAKE_COMPILER_IS_GNUCXX) + # http://www.swig.org/Doc2.0/Java.html#Java_typemaps_c_to_java_types + set_source_files_properties( + ${swig_generated_file_fullname} + PROPERTIES COMPILE_FLAGS "-fno-strict-aliasing") +endif() + +add_custom_command( + OUTPUT ${LIBRARY_OUTPUT_PATH}/gdcm.jar +# 1. run the custom command only when the gdcmJAVA_wrap.cxx has been generated +# (which means all *.java should be there) Some compiler are picky about Java +# version. For instance covariant return type was only added to Java 5, so to +# please compiler such as ecj (Eclipse Java Compiler 0.894_R34x) explicitly +# state we want 1.5 version to compile gdcm::ImageToImageFilter::GetOutput() +# const as covariant return type + COMMAND ${Java_JAVAC_EXECUTABLE} ARGS -source 1.5 -target 1.5 "gdcm/*.java" #${javafiles} +# 2. now that the *.class have been generated construct the jar file. We can +# only rely on the gdcm.java / gdcm.class to build dependencie, I am pretty +# sure it will break parallel builds... oh well + COMMAND ${Java_JAR_EXECUTABLE} ARGS cvf ${LIBRARY_OUTPUT_PATH}/gdcm.jar gdcm/*.class + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/java + DEPENDS "${swig_generated_file_fullname}" + COMMENT "javac *.java; jar cvf -> gdcm.jar" +) + +# 3. ok now add the target +add_custom_target(GDCMJavaJar ALL + DEPENDS ${LIBRARY_OUTPUT_PATH}/gdcm.jar + COMMENT "building gdcm.jar" +) + +if(NOT GDCM_INSTALL_NO_LIBRARIES) + install_swig_module(gdcmjni Java) + # because gdcm.jar is constructed with custom commands, it need the INSTALL(FILES signature: + install(FILES ${LIBRARY_OUTPUT_PATH}/gdcm.jar + DESTINATION ${GDCM_INSTALL_JARMODULE_DIR} COMPONENT JavaModule + ) +endif() diff --git a/gdcm/Wrapping/Java/gdcm.i b/gdcm/Wrapping/Java/gdcm.i new file mode 100644 index 0000000..90edb5c --- /dev/null +++ b/gdcm/Wrapping/Java/gdcm.i @@ -0,0 +1,854 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +// See docs: +// http://www.swig.org/Doc1.3/Java.html +// http://www.swig.org/Doc1.3/SWIGPlus.html#SWIGPlus + +%module(docstring="A DICOM library",directors=1) gdcm +#pragma SWIG nowarn=302,303,312,325,362,383,389,401,503,504,509,510,514,516 + +// There is something funky with swig 1.3.33, one cannot simply test defined(SWIGCSHARP) +// I need to redefine it myself... seems to be solved in later revision +#if defined(SWIGJAVA) +%{ +#define SWIGJAVA +%} +#endif + +%{ +#include "gdcmTypes.h" +#include "gdcmASN1.h" +#include "gdcmSmartPointer.h" +#include "gdcmSwapCode.h" +#include "gdcmEvent.h" +#include "gdcmProgressEvent.h" +#include "gdcmAnonymizeEvent.h" +#include "gdcmDirectory.h" +#ifdef GDCM_BUILD_TESTING +#include "gdcmTesting.h" +#endif +#include "gdcmObject.h" +#include "gdcmPixelFormat.h" +#include "gdcmMediaStorage.h" +#include "gdcmTag.h" +#include "gdcmPrivateTag.h" +#include "gdcmVL.h" +#include "gdcmVR.h" +#include "gdcmVM.h" +#include "gdcmObject.h" +#include "gdcmValue.h" +#include "gdcmByteValue.h" +#include "gdcmDataElement.h" +#include "gdcmItem.h" +#include "gdcmSequenceOfItems.h" +#include "gdcmDataSet.h" +//#include "gdcmString.h" +//#include "gdcmCodeString.h" +#include "gdcmPreamble.h" +#include "gdcmFile.h" +#include "gdcmBitmap.h" +#include "gdcmIconImage.h" +#include "gdcmPixmap.h" +#include "gdcmImage.h" +#include "gdcmFragment.h" +#include "gdcmCSAHeader.h" +#include "gdcmPDBHeader.h" +#include "gdcmSequenceOfFragments.h" +#include "gdcmTransferSyntax.h" +#include "gdcmBasicOffsetTable.h" +//#include "gdcmLO.h" +#include "gdcmCSAElement.h" +#include "gdcmPDBElement.h" +#include "gdcmFileSet.h" + +#include "gdcmReader.h" +#include "gdcmPixmapReader.h" +#include "gdcmImageReader.h" +#include "gdcmWriter.h" +#include "gdcmPixmapWriter.h" +#include "gdcmImageWriter.h" +#include "gdcmStringFilter.h" +#include "gdcmGlobal.h" +#include "gdcmDicts.h" +#include "gdcmDict.h" +#include "gdcmCSAHeaderDict.h" +#include "gdcmDictEntry.h" +#include "gdcmCSAHeaderDictEntry.h" +#include "gdcmUIDGenerator.h" +#include "gdcmUUIDGenerator.h" +//#include "gdcmConstCharWrapper.h" +#include "gdcmScanner.h" +#include "gdcmAttribute.h" +#include "gdcmSubject.h" +#include "gdcmCommand.h" +#include "gdcmAnonymizer.h" +#include "gdcmFileAnonymizer.h" +#include "gdcmFileStreamer.h" +#include "gdcmSystem.h" +#include "gdcmTrace.h" +#include "gdcmUIDs.h" +#include "gdcmSorter.h" +#include "gdcmIPPSorter.h" +#include "gdcmSpectroscopy.h" +#include "gdcmPrinter.h" +#include "gdcmXMLPrinter.h" +#include "gdcmDumper.h" +#include "gdcmOrientation.h" +#include "gdcmFiducials.h" +#include "gdcmWaveform.h" +#include "gdcmPersonName.h" +#include "gdcmCurve.h" +#include "gdcmDICOMDIR.h" +#include "gdcmValidate.h" +#include "gdcmApplicationEntity.h" +#include "gdcmDictPrinter.h" +#include "gdcmFilenameGenerator.h" +#include "gdcmVersion.h" +#include "gdcmFilename.h" +#include "gdcmEnumeratedValues.h" +#include "gdcmPatient.h" +#include "gdcmStudy.h" +#include "gdcmUsage.h" +#include "gdcmMacroEntry.h" +#include "gdcmModuleEntry.h" +#include "gdcmNestedModuleEntries.h" +#include "gdcmMacro.h" +#include "gdcmMacros.h" +#include "gdcmModule.h" +#include "gdcmModules.h" +#include "gdcmDefs.h" +#include "gdcmIOD.h" +#include "gdcmIODs.h" +#include "gdcmTableEntry.h" +#include "gdcmDefinedTerms.h" +#include "gdcmSeries.h" +#include "gdcmIODEntry.h" +#include "gdcmRescaler.h" +#include "gdcmSegmentedPaletteColorLookupTable.h" +#include "gdcmUnpacker12Bits.h" +#include "gdcmDirectionCosines.h" +#include "gdcmTagPath.h" +#include "gdcmBitmapToBitmapFilter.h" +#include "gdcmPixmapToPixmapFilter.h" +#include "gdcmImageToImageFilter.h" +#include "gdcmSOPClassUIDToIOD.h" +#include "gdcmCoder.h" +#include "gdcmDecoder.h" +#include "gdcmCodec.h" +#include "gdcmImageCodec.h" +#include "gdcmJPEGCodec.h" +#include "gdcmJPEGLSCodec.h" +#include "gdcmJPEG2000Codec.h" +#include "gdcmPNMCodec.h" +#include "gdcmImageChangeTransferSyntax.h" +#include "gdcmFileChangeTransferSyntax.h" +#include "gdcmImageApplyLookupTable.h" +#include "gdcmSplitMosaicFilter.h" +#include "gdcmImageChangePhotometricInterpretation.h" +#include "gdcmImageChangePlanarConfiguration.h" +#include "gdcmImageFragmentSplitter.h" +#include "gdcmDataSetHelper.h" +#include "gdcmFileExplicitFilter.h" +#include "gdcmImageHelper.h" +#include "gdcmMD5.h" +#include "gdcmDummyValueGenerator.h" +#include "gdcmSHA1.h" +#include "gdcmBase64.h" +#include "gdcmCryptographicMessageSyntax.h" +#include "gdcmCryptoFactory.h" +#include "gdcmSpacing.h" +#include "gdcmIconImageGenerator.h" +#include "gdcmIconImageFilter.h" + +#include "gdcmSimpleSubjectWatcher.h" +#include "gdcmDICOMDIRGenerator.h" +#include "gdcmFileDerivation.h" + +#include "gdcmQueryBase.h" +#include "gdcmQueryFactory.h" +#include "gdcmBaseRootQuery.h" +#include "gdcmPresentationContext.h" +#include "gdcmPresentationContextGenerator.h" +#include "gdcmCompositeNetworkFunctions.h" +#include "gdcmServiceClassUser.h" + +#include "gdcmStreamImageReader.h" + +#include "gdcmRegion.h" +#include "gdcmBoxRegion.h" +#include "gdcmImageRegionReader.h" +#include "gdcmJSON.h" + +using namespace gdcm; +%} + +// swig need to know what are uint16_t, uint8_t... +%include "stdint.i" + +// gdcm does not use std::string in its interface, but we do need it for the +// %extend (see below) +%include "std_string.i" +%include "std_set.i" +%include "std_vector.i" +%include "std_pair.i" +%include "std_map.i" +%include "exception.i" + +//%include "enumtypesafe.swg" // optional as typesafe enums are the default +//%javaconst(1); + +// operator= is not needed in python AFAIK +%ignore operator=; // Ignore = everywhere. +%ignore operator++; // Ignore + +%define EXTEND_CLASS_PRINT_GENERAL(classfuncname,classname) +%extend classname +{ + const char *classfuncname() { + static std::string buffer; + std::ostringstream os; + os << *self; + buffer = os.str(); + return buffer.c_str(); + } +}; +%enddef + +#if defined(SWIGJAVA) +%define EXTEND_CLASS_PRINT(classname) +// Remove Print( ostream & os ) +//%ignore classname::Print +EXTEND_CLASS_PRINT_GENERAL(toString,classname) +%enddef +#endif + +//%feature("autodoc", "1") +%include "gdcmConfigure.h" + +// http://www.swig.org/Doc1.3/Java.html#imclass_pragmas +// Need to be located *after* gdcmConfigure.h +#ifdef GDCM_AUTOLOAD_GDCMJNI +%pragma(java) jniclasscode=%{ + static { + try { + System.loadLibrary("gdcmjni"); + } catch (UnsatisfiedLinkError e) { + System.err.println("Native code library failed to load. \n" + e); + System.exit(1); + } + } +%} +#endif + + +//%include "gdcmTypes.h" +//%include "gdcmWin32.h" +// I cannot include gdcmWin32.h without gdcmTypes.h, first. But gdcmTypes.h needs to know _MSC_VER at swig time... +#define GDCM_EXPORT +%include "gdcmLegacyMacro.h" + +%include "gdcmSwapCode.h" + +//%feature("director") Event; +//%feature("director") AnyEvent; +%include "gdcmEvent.h" + +%include "gdcmPixelFormat.h" +EXTEND_CLASS_PRINT(gdcm::PixelFormat) + +//%include "enums.swg" +//%typemap(javain) enum SWIGTYPE "$javainput.ordinal()" +//%typemap(javaout) enum SWIGTYPE { +// return $javaclassname.class.getEnumConstants()[$jnicall]; +// } +//%typemap(javabody) enum SWIGTYPE "" +%rename(GetType) gdcm::MediaStorage::operator MSType () const; + +%include "gdcmMediaStorage.h" +//%clear enum SWIGTYPE; +//%extend gdcm::MediaStorage +//{ +//%typemap(javacode) MediaStorage +//%{ +// // For some reason the default equals operator is bogus, provide one ourself +// public boolean equals(Object obj) +// { +// MSType type = (MSType)obj; +// if( type == GetType() ) +// { +// return true; +// } +// return false; +// } +//%} +//}; + +//%include "enumtypesafe.swg" // optional as typesafe enums are the default + +EXTEND_CLASS_PRINT(gdcm::MediaStorage) +//%rename(__getitem__) gdcm::Tag::operator[]; +//%rename(this ) gdcm::Tag::operator[]; +%include "gdcmTag.h" +EXTEND_CLASS_PRINT(gdcm::Tag) +%include "gdcmPrivateTag.h" +EXTEND_CLASS_PRINT(gdcm::PrivateTag) + +%include "gdcmProgressEvent.h" +%extend gdcm::ProgressEvent { + static ProgressEvent *Cast(Event *event) { + return dynamic_cast(event); + } +}; +//%feature("director") AnonymizeEvent; +%include "gdcmAnonymizeEvent.h" +%extend gdcm::AnonymizeEvent { + static AnonymizeEvent *Cast(Event *event) { + return dynamic_cast(event); + } +}; + +%include "gdcmVL.h" +EXTEND_CLASS_PRINT(gdcm::VL) +%include "gdcmVR.h" +EXTEND_CLASS_PRINT(gdcm::VR) +%include "gdcmVM.h" +EXTEND_CLASS_PRINT(gdcm::VM) +//%template (FilenameType) std::string; +%template (FilenamesType) std::vector; +%include "gdcmDirectory.h" +EXTEND_CLASS_PRINT(gdcm::Directory) +//%clear FilenameType; +%clear FilenamesType; +%include "gdcmObject.h" +%include "gdcmValue.h" +EXTEND_CLASS_PRINT(gdcm::Value) +// Array marshaling for arrays of primitives +// http://www.swig.org/Doc2.0/Java.html#Java_unbounded_c_arrays + +// %clear commands should be unnecessary, but do it just-in-case +%clear char* buffer; +%clear unsigned char* buffer; + +%include "arrays_java.i" + +%ignore gdcm::ByteValue::WriteBuffer(std::ostream &os) const; +%ignore gdcm::ByteValue::GetPointer() const; +%ignore gdcm::ByteValue::GetBuffer(char *buffer, unsigned long length) const; +%apply signed char[] { signed char* buffer } +%include "gdcmByteValue.h" +%extend gdcm::ByteValue +{ + bool GetBuffer(signed char *buffer, unsigned long length) const { + return self->GetBuffer((char*)buffer, length); + } +}; +EXTEND_CLASS_PRINT(gdcm::ByteValue) +%clear signed char* buffer; + + +%apply char[] { const char* array } + +%include "gdcmASN1.h" +%include "gdcmSmartPointer.h" +%template(SmartPtrSQ) gdcm::SmartPointer; +%template(SmartPtrFrag) gdcm::SmartPointer; +%ignore gdcm::DataElement::SetByteValue(const char *array, VL length); +%include "gdcmDataElement.h" +EXTEND_CLASS_PRINT(gdcm::DataElement) + +%clear const char* array; +%extend gdcm::DataElement +{ + /** + * Replace SetByteValue + */ + // http://docs.oracle.com/javase/specs/jls/se7/html/jls-10.html#jls-10.7 + // Arrays must be indexed by int values; short, byte, or char values may also be + // used as index values because they are subjected to unary numeric promotion + // (§5.6.1) and become int values. + // An attempt to access an array component with a long index value results in a + // compile-time error. + void SetArray(signed char array[], unsigned int nitems) { + $self->SetByteValue((char*)array, (uint32_t)(nitems * sizeof(signed char)) ); + } + void SetArray(signed short array[], unsigned int nitems) { + $self->SetByteValue((char*)array, (uint32_t)(nitems * sizeof(signed short)) ); + } + void SetArray(signed int array[], unsigned int nitems) { + $self->SetByteValue((char*)array, (uint32_t)(nitems * sizeof(signed int)) ); + } + void SetArray(float array[], unsigned int nitems) { + $self->SetByteValue((char*)array, (uint32_t)(nitems * sizeof(float)) ); + } + void SetArray(double array[], unsigned int nitems) { + $self->SetByteValue((char*)array, (uint32_t)(nitems * sizeof(double)) ); + } +}; + +%include "gdcmItem.h" +EXTEND_CLASS_PRINT(gdcm::Item) +/* +*/ +%template() std::vector< gdcm::Item >; +%include "gdcmSequenceOfItems.h" +EXTEND_CLASS_PRINT(gdcm::SequenceOfItems) +%rename (JavaDataSet) SWIGDataSet; +%rename (JavaTagToValue) SWIGTagToValue; +%include "gdcmDataSet.h" +//namespace std { +// //struct lttag +// // { +// // bool operator()(const gdcm::DataElement &s1, +// // const gdcm::DataElement &s2) const +// // { +// // return s1.GetTag() < s2.GetTag(); +// // } +// // }; +// +// //%template(DataElementSet) gdcm::DataSet::DataElementSet; +// %template(DataElementSet) set; +//} +EXTEND_CLASS_PRINT(gdcm::DataSet) +%include "gdcmPhotometricInterpretation.h" +EXTEND_CLASS_PRINT(gdcm::PhotometricInterpretation) +%include "gdcmObject.h" +%apply signed char[] { signed char* array } +%ignore gdcm::LookupTable::GetLUT(LookupTableType type, unsigned char *array, unsigned int &length) const; +%include "gdcmLookupTable.h" +%extend gdcm::LookupTable +{ + unsigned int GetLUT(LookupTableType type, signed char *array) const { + unsigned int length = 0; + self->GetLUT( type, (unsigned char*)array, length); + return length; + } +}; +EXTEND_CLASS_PRINT(gdcm::LookupTable) +%include "gdcmOverlay.h" +EXTEND_CLASS_PRINT(gdcm::Overlay) +//%include "gdcmVR.h" +//%template (DataElementSet) std::set; +%include "gdcmPreamble.h" +EXTEND_CLASS_PRINT(gdcm::Preamble) +%include "gdcmTransferSyntax.h" +EXTEND_CLASS_PRINT(gdcm::TransferSyntax) +%include "gdcmFileMetaInformation.h" +EXTEND_CLASS_PRINT(gdcm::FileMetaInformation) + +//%template(File) gdcm::SmartPointer; +//%ignore gdcm::File; + +%include "gdcmFile.h" +EXTEND_CLASS_PRINT(gdcm::File) +//%include "gdcm_arrays_csharp.i" + +%apply signed char[] { signed char* buffer } +%apply unsigned int[] { unsigned int dims[3] } + +//%apply byte OUTPUT[] { char* buffer } ; +//%ignore gdcm::Pixmap::GetBuffer(char*) const; +//%apply byte FIXED[] { char *buffer } +//%csmethodmodifiers gdcm::Pixmap::GetBuffer "public unsafe"; +//%define %cs_marshal_array(TYPE, CSTYPE) +// %typemap(ctype) TYPE[] "void*" +// %typemap(imtype, inattributes="[MarshalAs(UnmanagedType.LPArray)]") TYPE[] "CSTYPE[]" +// %typemap(cstype) TYPE[] "CSTYPE[]" +// %typemap(in) TYPE[] %{ $1 = (TYPE*)$input; %} +// %typemap(csin) TYPE[] "$csinput" +//%enddef +//%cs_marshal_array(char, byte) +%ignore gdcm::Bitmap::GetBuffer(char* buffer) const; +%include "gdcmBitmap.h" +EXTEND_CLASS_PRINT(gdcm::Bitmap) +%extend gdcm::Bitmap +{ + bool GetBuffer(signed char *buffer) const { + return self->GetBuffer((char*)buffer); + } + // There is no such thing as unsigned type in java + // so we only wrap the signed API, and hope user understand what to do + bool GetArray(signed char buffer[]) const { + return $self->GetBuffer((char*)buffer); + } + bool GetArray(short buffer[]) const { + return $self->GetBuffer((char*)buffer); + } + bool GetArray(int buffer[]) const { // is int always 32bits in Java ? + return $self->GetBuffer((char*)buffer); + } + bool GetArray(float buffer[]) const { + assert( $self->GetPixelFormat() == PixelFormat::FLOAT32 ); + return $self->GetBuffer((char*)buffer); + } + bool GetArray(double buffer[]) const { + assert( $self->GetPixelFormat() == PixelFormat::FLOAT64 ); + return $self->GetBuffer((char*)buffer); + } +}; +%clear signed char* buffer; +%clear unsigned int* dims; + +%include "gdcmIconImage.h" +EXTEND_CLASS_PRINT(gdcm::IconImage) +%include "gdcmPixmap.h" +EXTEND_CLASS_PRINT(gdcm::Pixmap) + +%include "gdcmImage.h" +EXTEND_CLASS_PRINT(gdcm::Image) +%include "gdcmFragment.h" +EXTEND_CLASS_PRINT(gdcm::Fragment) +%include "gdcmPDBElement.h" +EXTEND_CLASS_PRINT(gdcm::PDBElement) +%include "gdcmPDBHeader.h" +EXTEND_CLASS_PRINT(gdcm::PDBHeader) +%include "gdcmCSAElement.h" +EXTEND_CLASS_PRINT(gdcm::CSAElement) +%include "gdcmCSAHeader.h" +EXTEND_CLASS_PRINT(gdcm::CSAHeader) +%include "gdcmSequenceOfFragments.h" +EXTEND_CLASS_PRINT(gdcm::SequenceOfFragments) +%include "gdcmBasicOffsetTable.h" +EXTEND_CLASS_PRINT(gdcm::BasicOffsetTable) +//%include "gdcmLO.h" +%include "gdcmFileSet.h" +EXTEND_CLASS_PRINT(gdcm::FileSet) + +%include "gdcmGlobal.h" +EXTEND_CLASS_PRINT(gdcm::Global) + +%include "gdcmDictEntry.h" +EXTEND_CLASS_PRINT(gdcm::DictEntry) +%include "gdcmCSAHeaderDictEntry.h" +EXTEND_CLASS_PRINT(gdcm::CSAHeaderDictEntry) + +%template(DictEntryTagPairType) std::pair< gdcm::DictEntry, gdcm::Tag>; +%include "gdcmDict.h" +EXTEND_CLASS_PRINT(gdcm::Dict) +%include "gdcmCSAHeaderDict.h" +EXTEND_CLASS_PRINT(gdcm::CSAHeaderDictEntry) +%include "gdcmDicts.h" +EXTEND_CLASS_PRINT(gdcm::Dicts) + +#if 0 +jstring JNU_NewStringNative(JNIEnv *env, const char *str) + { + jstring result; + jbyteArray bytes = 0; + int len; + if (env->EnsureLocalCapacity(2) < 0) { + return NULL; /* out of memory error */ + } + len = strlen(str); + bytes = (*env)->NewByteArray(env, len); + if (bytes != NULL) { + (*env)->SetByteArrayRegion(env, bytes, 0, len, + (jbyte *)str); + result = (*env)->NewObject(env, Class_java_lang_String, + MID_String_init, bytes); + (*env)->DeleteLocalRef(env, bytes); + return result; + } /* else fall through */ + return NULL; +} +#endif + +// http://java.sun.com/docs/books/jni/html/pitfalls.html#12400 + +%{ +void + JNU_ThrowByName(JNIEnv *env, const char *name, const char *msg) + { + jclass cls = env->FindClass(name); + /* if cls is NULL, an exception has already been thrown */ + if (cls != NULL) { + env->ThrowNew(cls, msg); + } + /* free the local ref */ + env->DeleteLocalRef(cls); + } + +char *JNU_GetStringNativeChars(JNIEnv *env, jstring jstr) + { + if (jstr == NULL) { + return NULL; + } + jbyteArray bytes = 0; + jthrowable exc; + char *result = 0; + if (env->EnsureLocalCapacity(2) < 0) { + return 0; /* out of memory error */ + } + jclass Class_java_lang_String = env->FindClass("java/lang/String"); + jmethodID MID_String_getBytes = env->GetMethodID( + Class_java_lang_String, "getBytes", "()[B"); + bytes = (jbyteArray) env->CallObjectMethod(jstr, + MID_String_getBytes); + exc = env->ExceptionOccurred(); + if (!exc) { + jint len = env->GetArrayLength(bytes); + result = (char *)malloc(len + 1); + if (result == 0) { + JNU_ThrowByName(env, "java/lang/OutOfMemoryError", + 0); + env->DeleteLocalRef(bytes); + return 0; + } + env->GetByteArrayRegion(bytes, 0, len, + (jbyte *)result); + result[len] = 0; /* NULL-terminate */ + } else { + env->DeleteLocalRef(exc); + } + env->DeleteLocalRef(bytes); + return result; + } +%} + +%typemap(in) const char *filename_native { +$1 = JNU_GetStringNativeChars(jenv, $input); +} +%typemap(freearg, noblock=1) const char *filename_native { if ($1) free($1); } + +%template (TagSetType) std::set; +%ignore gdcm::Reader::SetStream; +%include "gdcmReader.h" +//EXTEND_CLASS_PRINT(gdcm::Reader) +%include "gdcmPixmapReader.h" +//EXTEND_CLASS_PRINT(gdcm::PixmapReader) +%include "gdcmImageReader.h" +//EXTEND_CLASS_PRINT(gdcm::ImageReader) +%include "gdcmWriter.h" +//EXTEND_CLASS_PRINT(gdcm::Writer) +%include "gdcmPixmapWriter.h" +//EXTEND_CLASS_PRINT(gdcm::PixmapWriter) +%include "gdcmImageWriter.h" +//EXTEND_CLASS_PRINT(gdcm::ImageWriter) +%template (PairString) std::pair; +//%template (MyM) std::map; +%include "gdcmStringFilter.h" +//EXTEND_CLASS_PRINT(gdcm::StringFilter) +%include "gdcmUIDGenerator.h" +//EXTEND_CLASS_PRINT(gdcm::UIDGenerator) +%include "gdcmUUIDGenerator.h" +//EXTEND_CLASS_PRINT(gdcm::UUIDGenerator) +%template (ValuesType) std::set; +%rename (JavaTagToValue) SWIGTagToValue; +#define GDCM_STATIC_ASSERT(x) +%include "gdcmAttribute.h" +%include "gdcmSubject.h" +%include "gdcmCommand.h" + +%template(SmartPtrScan) gdcm::SmartPointer; +%include "gdcmScanner.h" +EXTEND_CLASS_PRINT(gdcm::Scanner) + +%template(SmartPtrAno) gdcm::SmartPointer; +//%ignore gdcm::Anonymizer::Anonymizer; + + +//%template(Anonymizer) gdcm::SmartPointer; +// +//%ignore gdcm::Anonymizer; +//%feature("unref") Anonymizer "coucou $this->Delete();" +// http://www.swig.org/Doc1.3/SWIGPlus.html#SWIGPlus%5Fnn34 +%include "gdcmAnonymizer.h" +%include "gdcmFileAnonymizer.h" +%apply char[] { char* array } +%template(SmartPtrFStreamer) gdcm::SmartPointer; +%include "gdcmFileStreamer.h" +%clear char* array; + +//EXTEND_CLASS_PRINT(gdcm::Anonymizer) + +// System is a namespace in C#, need to rename to something different +%rename (PosixEmulation) System; +%include "gdcmSystem.h" +//EXTEND_CLASS_PRINT(gdcm::System) + +%include "gdcmTrace.h" +//EXTEND_CLASS_PRINT(gdcm::Trace) +%include "gdcmUIDs.h" +EXTEND_CLASS_PRINT(gdcm::UIDs) +//%feature("director") gdcm::IPPSorter; +%include "gdcmSorter.h" +EXTEND_CLASS_PRINT(gdcm::Sorter) +%include "gdcmIPPSorter.h" +EXTEND_CLASS_PRINT(gdcm::IPPSorter) +%include "gdcmSpectroscopy.h" +//EXTEND_CLASS_PRINT(gdcm::Spectroscopy) +%include "gdcmPrinter.h" +//EXTEND_CLASS_PRINT(gdcm::Printer) +%include "gdcmXMLPrinter.h" +//EXTEND_CLASS_PRINT(gdcm::XMLPrinter) +%include "gdcmDumper.h" +//EXTEND_CLASS_PRINT(gdcm::Dumper) +%include "gdcmOrientation.h" +EXTEND_CLASS_PRINT(gdcm::Orientation) +%include "gdcmDirectionCosines.h" +EXTEND_CLASS_PRINT(gdcm::DirectionCosines) + +%include "gdcmFiducials.h" +%include "gdcmWaveform.h" +%include "gdcmPersonName.h" +%include "gdcmCurve.h" +%include "gdcmDICOMDIR.h" +%include "gdcmValidate.h" +%include "gdcmApplicationEntity.h" +%include "gdcmDictPrinter.h" +%include "gdcmFilenameGenerator.h" +%include "gdcmVersion.h" +EXTEND_CLASS_PRINT(gdcm::Version) +%include "gdcmFilename.h" +%include "gdcmEnumeratedValues.h" +%include "gdcmPatient.h" +%include "gdcmStudy.h" +%include "gdcmUsage.h" +%include "gdcmMacroEntry.h" +%include "gdcmModuleEntry.h" +EXTEND_CLASS_PRINT(gdcm::ModuleEntry) +%include "gdcmNestedModuleEntries.h" +%include "gdcmMacro.h" +%include "gdcmMacros.h" +%include "gdcmModule.h" +%include "gdcmModules.h" +%include "gdcmDefs.h" +%include "gdcmIOD.h" +%include "gdcmIODs.h" +%include "gdcmTableEntry.h" +%include "gdcmDefinedTerms.h" +%include "gdcmSeries.h" +%include "gdcmIODEntry.h" + +%apply signed char[] { signed char* outbuffer } +%apply signed char[] { signed char* inbuffer } +%include "gdcmRescaler.h" +//EXTEND_CLASS_PRINT(gdcm::Rescaler) +%extend gdcm::Rescaler +{ + bool Rescale(signed char *outbuffer, const signed char *inbuffer, size_t n) { + return self->Rescale((char*)outbuffer, (const char*)inbuffer, n); + } + bool InverseRescale(char *outbuffer, const char *inbuffer, size_t n) { + return self->InverseRescale((char*)outbuffer, (const char*)inbuffer, n); + } +}; +%clear signed char* outbuffer; +%clear signed char* inbuffer; + +%include "gdcmSegmentedPaletteColorLookupTable.h" +%include "gdcmUnpacker12Bits.h" + +%include "gdcmConfigure.h" +#ifdef GDCM_BUILD_TESTING +%include "gdcmTesting.h" +%ignore gdcm::Testing::ComputeMD5(const char *, const unsigned long , char []); +%ignore gdcm::Testing::ComputeFileMD5(const char*, char []); +%extend gdcm::Testing +{ + static const char *ComputeFileMD5(const char *filename) { + static char buffer[33]; + gdcm::Testing::ComputeFileMD5(filename, buffer); + return buffer; + } +}; +#endif +%include "gdcmTagPath.h" +%include "gdcmBitmapToBitmapFilter.h" +%include "gdcmPixmapToPixmapFilter.h" +%include "gdcmImageToImageFilter.h" +%include "gdcmSOPClassUIDToIOD.h" +//%feature("director") Coder; +//%include "gdcmCoder.h" +//%feature("director") Decoder; +//%include "gdcmDecoder.h" +//%feature("director") Codec; +//%include "gdcmCodec.h" +%feature("director") ImageCodec; +%include "gdcmImageCodec.h" +%include "gdcmJPEGCodec.h" +%include "gdcmJPEGLSCodec.h" +%include "gdcmJPEG2000Codec.h" +%include "gdcmPNMCodec.h" +%include "gdcmImageChangeTransferSyntax.h" +%template(SmartPtrFCTS) gdcm::SmartPointer; +%include "gdcmFileChangeTransferSyntax.h" +%include "gdcmImageApplyLookupTable.h" +%include "gdcmSplitMosaicFilter.h" +%include "gdcmImageChangePhotometricInterpretation.h" +%include "gdcmImageChangePlanarConfiguration.h" +%include "gdcmImageFragmentSplitter.h" +%include "gdcmDataSetHelper.h" +%include "gdcmFileExplicitFilter.h" +%template (DoubleArrayType) std::vector; +%template (UShortArrayType) std::vector; +%template (UIntArrayType) std::vector; +%include "gdcmImageHelper.h" +%include "gdcmMD5.h" +%include "gdcmDummyValueGenerator.h" +%include "gdcmSHA1.h" +%include "gdcmBase64.h" +%include "gdcmCryptographicMessageSyntax.h" +%include "gdcmCryptoFactory.h" +%include "gdcmSpacing.h" +%include "gdcmIconImageGenerator.h" +%include "gdcmIconImageFilter.h" + +%feature("director") SimpleSubjectWatcher; +%include "gdcmSimpleSubjectWatcher.h" +%include "gdcmDICOMDIRGenerator.h" +%include "gdcmFileDerivation.h" + +// MEXD: +%template(DataSetArrayType) std::vector< gdcm::DataSet >; +%template(FileArrayType) std::vector< gdcm::File >; +%template(PresentationContextArrayType) std::vector< gdcm::PresentationContext >; +%template(KeyValuePairType) std::pair< gdcm::Tag, std::string>; +%template(KeyValuePairArrayType) std::vector< std::pair< gdcm::Tag, std::string> >; +%template(TagArrayType) std::vector< gdcm::Tag >; +%include "gdcmQueryBase.h" +%include "gdcmBaseRootQuery.h" +%include "gdcmQueryFactory.h" +%template(CharSetArrayType) std::vector< gdcm::ECharSet >; +%include "gdcmCompositeNetworkFunctions.h" +%include "gdcmPresentationContext.h" +//EXTEND_CLASS_PRINT(gdcm::PresentationContext) +%include "gdcmPresentationContextGenerator.h" +typedef int64_t time_t; // FIXME +%include "gdcmServiceClassUser.h" +%ignore gdcm::StreamImageReader::Read(char* inReadBuffer, const std::size_t& inBufferLength); +%apply signed char[] { signed char* inReadBuffer } +%include "gdcmStreamImageReader.h" +%extend gdcm::StreamImageReader +{ + bool Read(signed char* inReadBuffer, size_t inBufferLength) { + return self->Read((char*)inReadBuffer, inBufferLength); + } +} +%clear signed char* inReadBuffer; +%include "gdcmRegion.h" +EXTEND_CLASS_PRINT(gdcm::Region) +%include "gdcmBoxRegion.h" +EXTEND_CLASS_PRINT(gdcm::BoxRegion) +%ignore gdcm::ImageRegionReader::ReadIntoBuffer(char *inreadbuffer, size_t buflen); +%apply signed char[] { signed char* inreadbuffer } +%include "gdcmImageRegionReader.h" +%extend gdcm::ImageRegionReader +{ + bool ReadIntoBuffer(signed char *inreadbuffer, size_t buflen) { + return self->ReadIntoBuffer((char*)inreadbuffer, buflen); + } +}; +//EXTEND_CLASS_PRINT(gdcm::ImageRegionReader) +%clear signed char* inreadbuffer; +%include "gdcmJSON.h" diff --git a/gdcm/Wrapping/Java/main.java b/gdcm/Wrapping/Java/main.java new file mode 100644 index 0000000..ffa9470 --- /dev/null +++ b/gdcm/Wrapping/Java/main.java @@ -0,0 +1,37 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +// This example illustrates how C++ classes can be used from Java using SWIG. +// The Java class gets mapped onto the C++ class and behaves as if it is a Java class. + +public class main { + static { + try { + System.loadLibrary("gdcm"); + } catch (UnsatisfiedLinkError e) { + System.err.println("Native code library failed to load. See the chapter on Dynamic Linking Problems in the SWIG Java documentation for help.\n" + e); + System.exit(1); + } + } + + public static void main(String argv[]) + { + // ----- Object creation ----- + System.out.println( "Creating some objects:" ); + Reader r = new Reader(); + UIDGenerator uid = new UIDGenerator(); + String s = uid.Generate(); + System.out.println( uid.Generate() ); + System.out.println( "Goodbye" ); + } +} diff --git a/gdcm/Wrapping/Java/std_set.i b/gdcm/Wrapping/Java/std_set.i new file mode 100644 index 0000000..e4877f4 --- /dev/null +++ b/gdcm/Wrapping/Java/std_set.i @@ -0,0 +1,73 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* ----------------------------------------------------------------------------- + * std_set.i + * + * SWIG typemaps for std::set + * ----------------------------------------------------------------------------- */ + +%include + +// ------------------------------------------------------------------------ +// std::set +// ------------------------------------------------------------------------ + +%{ +#include +#include +#include +%} + +// exported class + +namespace std { + + template class set { + // add typemaps here + public: + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef V value_type; + set(); + set(const set &); + + unsigned int size() const; + bool empty() const; + void clear(); + %extend { + const V& get(const V& key) throw (std::out_of_range) { + std::set::iterator i = self->find(key); + if (i != self->end()) + return *i; + else + throw std::out_of_range("key not found"); + } + void insert(const V& key) { // Do NOT call this function 'set' ! + self->insert(key); + } + void del(const V& key) throw (std::out_of_range) { + std::set::iterator i = self->find(key); + if (i != self->end()) + self->erase(i); + else + throw std::out_of_range("key not found"); + } + bool has_key(const V& key) { + std::set::iterator i = self->find(key); + return i != self->end(); + } + } + }; + +} diff --git a/gdcm/Wrapping/PHP/CMakeLists.txt b/gdcm/Wrapping/PHP/CMakeLists.txt new file mode 100644 index 0000000..0f91205 --- /dev/null +++ b/gdcm/Wrapping/PHP/CMakeLists.txt @@ -0,0 +1,91 @@ +# Required: +# sudo apt-get install php5-dev +find_package(SWIG REQUIRED) +include(${SWIG_USE_FILE}) + +include_directories( + "${GDCM_BINARY_DIR}/Source/Common" + "${GDCM_SOURCE_DIR}/Source/Common" + "${GDCM_SOURCE_DIR}/Source/DataStructureAndEncodingDefinition" + "${GDCM_SOURCE_DIR}/Source/InformationObjectDefinition" + "${GDCM_SOURCE_DIR}/Source/MediaStorageAndFileFormat" + "${GDCM_SOURCE_DIR}/Source/DataDictionary" + "${GDCM_SOURCE_DIR}/Source/MessageExchangeDefinition" +) + +#find_package(PHP4 REQUIRED) +find_package(PHP5 REQUIRED) + +include_directories( + ${PHP4_INCLUDE_PATH} + ${PHP5_INCLUDE_PATH} +) + +set_source_files_properties(gdcm.i PROPERTIES CPLUSPLUS ON) + +# Some old swig 1.3 did not support this option: +#set(CMAKE_SWIG_OUTDIR "${CMAKE_CURRENT_BINARY_DIR}") + +# swig expect a name like that: php_gdcm.so +SWIG_ADD_MODULE(php_gdcm php gdcm.i) +SWIG_LINK_LIBRARIES(php_gdcm gdcmMSFF gdcmMEXD) +# warning, by default there are undefined symbols in the generated php/gdcm module +# one would need to actually link to : /usr/lib/apache2/modules/libphp5.so +# I do not believe this is correct, instead make sure that +# CMAKE_MODULE_LINKER_FLAGS = -Wl,--no-undefined +# will make gdcm fails to compile: +# with something like undefined reference to `zend_error' +set_property(TARGET ${SWIG_MODULE_php_gdcm_REAL_NAME} PROPERTY NO_SONAME 1) + +set_target_properties(${SWIG_MODULE_php_gdcm_REAL_NAME} PROPERTIES LINK_INTERFACE_LIBRARIES "") +# Remove 'lib' prefix :no-op on windows and valid for UNIX based syste +set_target_properties(${SWIG_MODULE_php_gdcm_REAL_NAME} PROPERTIES PREFIX "") + +# For some reason the php glue module name is odd using swig 1.3.40, it is php_gdcm on windows +# while simply gdcm on other unix system: +# ... +# if (!dl('php_gdcm.dll')) return; +# } else { +# // PHP_SHLIB_SUFFIX gives 'dylib' on MacOS X but modules are 'so'. +# if (PHP_SHLIB_SUFFIX === 'dylib') { +# if (!dl('gdcm.so')) return; +# } else { +# if (!dl('gdcm.'.PHP_SHLIB_SUFFIX)) return; +# ... +if(UNIX) + set_target_properties(${SWIG_MODULE_php_gdcm_REAL_NAME} PROPERTIES OUTPUT_NAME "gdcm") +endif() + +# See gdcm bug #3175803 +# This is fixed in SWIG 2.0.2: +# http://sourceforge.net/tracker/?func=detail&atid=101645&aid=3166423&group_id=1645 +if(${SWIG_VERSION} LESS 2.0.2) + add_custom_command(TARGET ${SWIG_MODULE_php_gdcm_REAL_NAME} + PRE_BUILD + COMMAND sed -i -e 's/zend_error_noreturn/zend_error/g' "${swig_generated_file_fullname}" + COMMENT "Patching zend_error_noreturn into zend_error" + ) +endif() + +# Let's copy gdcm.php into the bin dir: +add_custom_command( + OUTPUT ${LIBRARY_OUTPUT_PATH}/gdcm.php + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/gdcm.php ${LIBRARY_OUTPUT_PATH}/gdcm.php + DEPENDS "${swig_generated_file_fullname}" + COMMENT "copying gdcm.php" +) +add_custom_target(GDCMPHP ALL + DEPENDS ${LIBRARY_OUTPUT_PATH}/gdcm.php + COMMENT "building gdcm.php" +) + +# Module are always place in the library destination +# but for poor win32 user I decided to place them +# right next to the other dlls +if(NOT GDCM_INSTALL_NO_LIBRARIES) + install_swig_module(php_gdcm PHP) + # because gdcm.php is constructed with custom commands, it need the install(FILES signature: + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/gdcm.php + DESTINATION ${GDCM_INSTALL_LIB_DIR} COMPONENT PHPModule + ) +endif() diff --git a/gdcm/Wrapping/PHP/gdcm.i b/gdcm/Wrapping/PHP/gdcm.i new file mode 100644 index 0000000..2ad83f2 --- /dev/null +++ b/gdcm/Wrapping/PHP/gdcm.i @@ -0,0 +1,695 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +// See docs: +// http://www.swig.org/Doc1.3/Php.html +// http://www.swig.org/Doc1.3/SWIGPlus.html#SWIGPlus + +%module(docstring="A DICOM library",directors=1) gdcm +#pragma SWIG nowarn=302,303,312,362,383,389,401,503,504,509,510,514,516,842 + +#if defined(SWIGPHP) +%{ +#define SWIGPHP +%} +#endif + +%{ +#include "gdcmTypes.h" +#include "gdcmASN1.h" +#include "gdcmSmartPointer.h" +#include "gdcmSwapCode.h" +#include "gdcmEvent.h" +#include "gdcmProgressEvent.h" +#include "gdcmAnonymizeEvent.h" +#include "gdcmDirectory.h" +#ifdef GDCM_BUILD_TESTING +#include "gdcmTesting.h" +#endif +#include "gdcmObject.h" +#include "gdcmPixelFormat.h" +#include "gdcmMediaStorage.h" +#include "gdcmTag.h" +#include "gdcmPrivateTag.h" +#include "gdcmVL.h" +#include "gdcmVR.h" +#include "gdcmVM.h" +#include "gdcmObject.h" +#include "gdcmValue.h" +#include "gdcmByteValue.h" +#include "gdcmDataElement.h" +#include "gdcmItem.h" +#include "gdcmSequenceOfItems.h" +#include "gdcmDataSet.h" +//#include "gdcmString.h" +//#include "gdcmCodeString.h" +#include "gdcmPreamble.h" +#include "gdcmFile.h" +#include "gdcmBitmap.h" +#include "gdcmIconImage.h" +#include "gdcmPixmap.h" +#include "gdcmImage.h" +#include "gdcmFragment.h" +#include "gdcmCSAHeader.h" +#include "gdcmPDBHeader.h" +#include "gdcmSequenceOfFragments.h" +#include "gdcmTransferSyntax.h" +#include "gdcmBasicOffsetTable.h" +//#include "gdcmLO.h" +#include "gdcmCSAElement.h" +#include "gdcmPDBElement.h" +#include "gdcmFileSet.h" + +#include "gdcmReader.h" +#include "gdcmPixmapReader.h" +#include "gdcmImageReader.h" +#include "gdcmWriter.h" +#include "gdcmPixmapWriter.h" +#include "gdcmImageWriter.h" +#include "gdcmStringFilter.h" +#include "gdcmGlobal.h" +#include "gdcmDicts.h" +#include "gdcmDict.h" +#include "gdcmCSAHeaderDict.h" +#include "gdcmDictEntry.h" +#include "gdcmCSAHeaderDictEntry.h" +#include "gdcmUIDGenerator.h" +#include "gdcmUUIDGenerator.h" +//#include "gdcmConstCharWrapper.h" +#include "gdcmScanner.h" +#include "gdcmAttribute.h" +#include "gdcmSubject.h" +#include "gdcmCommand.h" +#include "gdcmAnonymizer.h" +#include "gdcmFileAnonymizer.h" +#include "gdcmFileStreamer.h" +#include "gdcmSystem.h" +#include "gdcmTrace.h" +#include "gdcmUIDs.h" +#include "gdcmSorter.h" +#include "gdcmIPPSorter.h" +#include "gdcmSpectroscopy.h" +#include "gdcmPrinter.h" +#include "gdcmXMLPrinter.h" +#include "gdcmDumper.h" +#include "gdcmOrientation.h" +#include "gdcmFiducials.h" +#include "gdcmWaveform.h" +#include "gdcmPersonName.h" +#include "gdcmCurve.h" +#include "gdcmDICOMDIR.h" +#include "gdcmValidate.h" +#include "gdcmApplicationEntity.h" +#include "gdcmDictPrinter.h" +#include "gdcmFilenameGenerator.h" +#include "gdcmVersion.h" +#include "gdcmFilename.h" +#include "gdcmEnumeratedValues.h" +#include "gdcmPatient.h" +#include "gdcmStudy.h" +#include "gdcmUsage.h" +#include "gdcmMacroEntry.h" +#include "gdcmModuleEntry.h" +#include "gdcmNestedModuleEntries.h" +#include "gdcmMacro.h" +#include "gdcmMacros.h" +#include "gdcmModule.h" +#include "gdcmModules.h" +#include "gdcmDefs.h" +#include "gdcmIOD.h" +#include "gdcmIODs.h" +#include "gdcmTableEntry.h" +#include "gdcmDefinedTerms.h" +#include "gdcmSeries.h" +#include "gdcmIODEntry.h" +#include "gdcmRescaler.h" +#include "gdcmSegmentedPaletteColorLookupTable.h" +#include "gdcmUnpacker12Bits.h" +#include "gdcmDirectionCosines.h" +#include "gdcmTagPath.h" +#include "gdcmBitmapToBitmapFilter.h" +#include "gdcmPixmapToPixmapFilter.h" +#include "gdcmImageToImageFilter.h" +#include "gdcmSOPClassUIDToIOD.h" +#include "gdcmCoder.h" +#include "gdcmDecoder.h" +#include "gdcmCodec.h" +#include "gdcmImageCodec.h" +#include "gdcmJPEGCodec.h" +#include "gdcmJPEGLSCodec.h" +#include "gdcmJPEG2000Codec.h" +#include "gdcmPNMCodec.h" +#include "gdcmImageChangeTransferSyntax.h" +#include "gdcmFileChangeTransferSyntax.h" +#include "gdcmImageApplyLookupTable.h" +#include "gdcmSplitMosaicFilter.h" +#include "gdcmImageChangePhotometricInterpretation.h" +#include "gdcmImageChangePlanarConfiguration.h" +#include "gdcmImageFragmentSplitter.h" +#include "gdcmDataSetHelper.h" +#include "gdcmFileExplicitFilter.h" +#include "gdcmImageHelper.h" +#include "gdcmMD5.h" +#include "gdcmDummyValueGenerator.h" +#include "gdcmSHA1.h" +#include "gdcmBase64.h" +#include "gdcmCryptographicMessageSyntax.h" +#include "gdcmCryptoFactory.h" +#include "gdcmSpacing.h" +#include "gdcmIconImageGenerator.h" +#include "gdcmIconImageFilter.h" + +#include "gdcmSimpleSubjectWatcher.h" +#include "gdcmDICOMDIRGenerator.h" +#include "gdcmFileDerivation.h" + +#include "gdcmQueryBase.h" +#include "gdcmQueryFactory.h" +#include "gdcmBaseRootQuery.h" +#include "gdcmPresentationContext.h" +#include "gdcmPresentationContextGenerator.h" +#include "gdcmCompositeNetworkFunctions.h" +#include "gdcmServiceClassUser.h" + +#include "gdcmStreamImageReader.h" + +#include "gdcmRegion.h" +#include "gdcmBoxRegion.h" +#include "gdcmImageRegionReader.h" + +using namespace gdcm; +%} + +//%include "docstrings.i" + +// swig need to know what are uint16_t, uint8_t... +%include "stdint.i" + +// gdcm does not use std::string in its interface, but we do need it for the +// %extend (see below) +%include "std_string.i" +//%include "std_set.i" +%include "std_vector.i" +%include "std_pair.i" +%include "std_map.i" +%include "exception.i" + +// operator= is not needed in python AFAIK +%ignore operator=; // Ignore = everywhere. +%ignore operator++; // Ignore + +%define EXTEND_CLASS_PRINT_GENERAL(classfuncname,classname) +%extend classname +{ + const char *classfuncname() { + static std::string buffer; + std::ostringstream os; + os << *self; + buffer = os.str(); + return buffer.c_str(); + } +}; +%enddef + +#if defined(SWIGPHP) +%define EXTEND_CLASS_PRINT(classname) +EXTEND_CLASS_PRINT_GENERAL(__toString,classname) +%enddef +#endif + +//%feature("autodoc", "1") +%include "gdcmConfigure.h" +//%include "gdcmTypes.h" +//%include "gdcmWin32.h" +// I cannot include gdcmWin32.h without gdcmTypes.h, first. But gdcmTypes.h needs to know _MSC_VER at swig time... +#define GDCM_EXPORT +%include "gdcmLegacyMacro.h" + +// The following must be define early on as gdcmVL.h get included real early +%rename(GetValueLength) gdcm::VL::operator uint32_t; +//%csmethodmodifiers gdcm::VL::GetValueLength "private" +//%csmethodmodifiers GetValueLength "private" +//%rename(GetValue) VL::operator uint32_t (); +// public static implicit operator int( MyType a ) +// { +// return a.value; +// } +%include "gdcmSwapCode.h" + +//%feature("director") Event; +//%feature("director") AnyEvent; +%include "gdcmEvent.h" + +%include "gdcmPixelFormat.h" +EXTEND_CLASS_PRINT(gdcm::PixelFormat) +%include "gdcmMediaStorage.h" +EXTEND_CLASS_PRINT(gdcm::MediaStorage) +//%rename(__getitem__) gdcm::Tag::operator[]; +//%rename(this ) gdcm::Tag::operator[]; +%include "gdcmTag.h" +EXTEND_CLASS_PRINT(gdcm::Tag) +%include "gdcmPrivateTag.h" +EXTEND_CLASS_PRINT(gdcm::PrivateTag) + +%include "gdcmProgressEvent.h" +//%feature("director") AnonymizeEvent; +%include "gdcmAnonymizeEvent.h" + +%include "gdcmVL.h" +EXTEND_CLASS_PRINT(gdcm::VL) +%include "gdcmVR.h" +EXTEND_CLASS_PRINT(gdcm::VR) +%include "gdcmVM.h" +EXTEND_CLASS_PRINT(gdcm::VM) +//%template (FilenameType) std::string; +%template (FilenamesType) std::vector; +%include "gdcmDirectory.h" +EXTEND_CLASS_PRINT(gdcm::Directory) +%include "gdcmObject.h" +%include "gdcmValue.h" +EXTEND_CLASS_PRINT(gdcm::Value) +// Array marshaling for arrays of primitives + + + + +%apply char[] { char* buffer } +%ignore gdcm::ByteValue::WriteBuffer(std::ostream &os) const; +//%ignore gdcm::ByteValue::GetPointer() const; +//%ignore gdcm::ByteValue::GetBuffer(char *buffer, unsigned long length) const; +%include "gdcmByteValue.h" +EXTEND_CLASS_PRINT(gdcm::ByteValue) +%clear char* buffer; + +%apply char[] { const char* array } + +%include "gdcmASN1.h" +%include "gdcmSmartPointer.h" +%template(SmartPtrSQ) gdcm::SmartPointer; +%template(SmartPtrFrag) gdcm::SmartPointer; +%include "gdcmDataElement.h" +EXTEND_CLASS_PRINT(gdcm::DataElement) + +%clear const char* array; +%extend gdcm::DataElement +{ + void SetArray(unsigned char array[], unsigned int nitems) { + $self->SetByteValue((char*)array, nitems * sizeof(unsigned char) ); + } + void SetArray(char array[], unsigned int nitems) { + $self->SetByteValue((char*)array, nitems * sizeof(char) ); + } + void SetArray(unsigned short array[], unsigned int nitems) { + $self->SetByteValue((char*)array, nitems * sizeof(unsigned short) ); + } + void SetArray(short array[], unsigned int nitems) { + $self->SetByteValue((char*)array, nitems * sizeof(short) ); + } + void SetArray(float array[], unsigned int nitems) { + $self->SetByteValue((char*)array, nitems * sizeof(float) ); + } + void SetArray(double array[], unsigned int nitems) { + $self->SetByteValue((char*)array, nitems * sizeof(double) ); + } +}; + +%include "gdcmItem.h" +EXTEND_CLASS_PRINT(gdcm::Item) +/* + The following line is very important it properly convert : +SWIGTYPE_p_std__vectorT_int_t__size_type -> uint +*/ +%template() std::vector< gdcm::Item >; +%include "gdcmSequenceOfItems.h" +EXTEND_CLASS_PRINT(gdcm::SequenceOfItems) +%rename (PHPDataSet) SWIGDataSet; +%rename (PHPTagToValue) SWIGTagToValue; +%include "gdcmDataSet.h" +EXTEND_CLASS_PRINT(gdcm::DataSet) +//%include "gdcmString.h" +//%include "gdcmCodeString.h" +//%include "gdcmTransferSyntax.h" +%include "gdcmPhotometricInterpretation.h" +EXTEND_CLASS_PRINT(gdcm::PhotometricInterpretation) +%include "gdcmObject.h" +%include "gdcmLookupTable.h" +EXTEND_CLASS_PRINT(gdcm::LookupTable) +%include "gdcmOverlay.h" +EXTEND_CLASS_PRINT(gdcm::Overlay) +//%include "gdcmVR.h" +//%template (DataElementSet) std::set; +%include "gdcmPreamble.h" +EXTEND_CLASS_PRINT(gdcm::Preamble) +%include "gdcmTransferSyntax.h" +EXTEND_CLASS_PRINT(gdcm::TransferSyntax) +%include "gdcmFileMetaInformation.h" +EXTEND_CLASS_PRINT(gdcm::FileMetaInformation) + +//%template(File) gdcm::SmartPointer; +//%ignore gdcm::File; + +%include "gdcmFile.h" +EXTEND_CLASS_PRINT(gdcm::File) +//%include "gdcm_arrays_csharp.i" + +%apply char[] { char* buffer } +%apply unsigned int[] { unsigned int dims[2] } +%apply unsigned int[] { unsigned int dims[3] } + +//%apply byte OUTPUT[] { char* buffer } ; +//%ignore gdcm::Pixmap::GetBuffer(char*) const; +//%apply byte FIXED[] { char *buffer } +//%csmethodmodifiers gdcm::Pixmap::GetBuffer "public unsafe"; +//%define %cs_marshal_array(TYPE, CSTYPE) +// %typemap(ctype) TYPE[] "void*" +// %typemap(imtype, inattributes="[MarshalAs(UnmanagedType.LPArray)]") TYPE[] "CSTYPE[]" +// %typemap(cstype) TYPE[] "CSTYPE[]" +// %typemap(in) TYPE[] %{ $1 = (TYPE*)$input; %} +// %typemap(csin) TYPE[] "$csinput" +//%enddef +//%cs_marshal_array(char, byte) +%include "gdcmBitmap.h" +EXTEND_CLASS_PRINT(gdcm::Bitmap) + +%include "gdcmIconImage.h" +EXTEND_CLASS_PRINT(gdcm::IconImage) +%include "gdcmPixmap.h" +EXTEND_CLASS_PRINT(gdcm::Pixmap) + +%include "gdcmImage.h" +EXTEND_CLASS_PRINT(gdcm::Image) +%include "gdcmFragment.h" +EXTEND_CLASS_PRINT(gdcm::Fragment) +%include "gdcmPDBElement.h" +EXTEND_CLASS_PRINT(gdcm::PDBElement) +%include "gdcmPDBHeader.h" +EXTEND_CLASS_PRINT(gdcm::PDBHeader) +%include "gdcmCSAElement.h" +EXTEND_CLASS_PRINT(gdcm::CSAElement) +%include "gdcmCSAHeader.h" +EXTEND_CLASS_PRINT(gdcm::CSAHeader) +%include "gdcmSequenceOfFragments.h" +EXTEND_CLASS_PRINT(gdcm::SequenceOfFragments) +%include "gdcmBasicOffsetTable.h" +EXTEND_CLASS_PRINT(gdcm::BasicOffsetTable) +//%include "gdcmLO.h" +%include "gdcmFileSet.h" +EXTEND_CLASS_PRINT(gdcm::FileSet) + +%include "gdcmGlobal.h" +EXTEND_CLASS_PRINT(gdcm::Global) + +%include "gdcmDictEntry.h" +EXTEND_CLASS_PRINT(gdcm::DictEntry) +%include "gdcmCSAHeaderDictEntry.h" +EXTEND_CLASS_PRINT(gdcm::CSAHeaderDictEntry) + +%include "gdcmDict.h" +EXTEND_CLASS_PRINT(gdcm::Dict) +%include "gdcmCSAHeaderDict.h" +EXTEND_CLASS_PRINT(gdcm::CSAHeaderDictEntry) +%include "gdcmDicts.h" +EXTEND_CLASS_PRINT(gdcm::Dicts) + +//%template (TagSetType) std::set; +%ignore gdcm::Reader::SetStream; +%include "gdcmReader.h" +//EXTEND_CLASS_PRINT(gdcm::Reader) +%include "gdcmPixmapReader.h" +//EXTEND_CLASS_PRINT(gdcm::PixmapReader) +%include "gdcmImageReader.h" +//EXTEND_CLASS_PRINT(gdcm::ImageReader) +%include "gdcmWriter.h" +//EXTEND_CLASS_PRINT(gdcm::Writer) +%include "gdcmPixmapWriter.h" +//EXTEND_CLASS_PRINT(gdcm::PixmapWriter) +%include "gdcmImageWriter.h" +//EXTEND_CLASS_PRINT(gdcm::ImageWriter) +%template (PairString) std::pair; +//%template (MyM) std::map; +%include "gdcmStringFilter.h" +//EXTEND_CLASS_PRINT(gdcm::StringFilter) +%include "gdcmUIDGenerator.h" +//EXTEND_CLASS_PRINT(gdcm::UIDGenerator) +%include "gdcmUUIDGenerator.h" +//EXTEND_CLASS_PRINT(gdcm::UUIDGenerator) +//%template (ValuesType) std::set; +%rename (CSharpTagToValue) SWIGTagToValue; +#define GDCM_STATIC_ASSERT(x) +%include "gdcmAttribute.h" +%include "gdcmSubject.h" +%include "gdcmCommand.h" + +%template(SmartPtrScan) gdcm::SmartPointer; +%include "gdcmScanner.h" +EXTEND_CLASS_PRINT(gdcm::Scanner) + +%template(SmartPtrAno) gdcm::SmartPointer; +//%ignore gdcm::Anonymizer::Anonymizer; + + +//%template(Anonymizer) gdcm::SmartPointer; +// +//%ignore gdcm::Anonymizer; +//%feature("unref") Anonymizer "coucou $this->Delete();" +// http://www.swig.org/Doc1.3/SWIGPlus.html#SWIGPlus%5Fnn34 +%include "gdcmAnonymizer.h" +%apply char[] { char* value_data } +%include "gdcmFileAnonymizer.h" +%clear char* value_data; + +%apply char[] { char* array } +%template(SmartPtrFStreamer) gdcm::SmartPointer; +%include "gdcmFileStreamer.h" +%clear char* array; + +//EXTEND_CLASS_PRINT(gdcm::Anonymizer) +//%extend gdcm::Anonymizer +//{ +//%typemap(cscode) gdcm::Anonymizer +//%{ +// public Anonymizer() : this(gdcmPINVOKE.Anonymizer_New(), false) { +// } +//%} +//}; + +// System is a namespace in C#, need to rename to something different +%rename (PosixEmulation) System; +%include "gdcmSystem.h" +//EXTEND_CLASS_PRINT(gdcm::System) + +%include "gdcmTrace.h" +//EXTEND_CLASS_PRINT(gdcm::Trace) +%include "gdcmUIDs.h" +EXTEND_CLASS_PRINT(gdcm::UIDs) +//%feature("director") gdcm::IPPSorter; + +//////////////////////////////////////////////////////////////////////////// +// cs_callback is used to marshall callbacks. It allows a C# function to +// be passed to C++ as a function pointer through P/Invoke, which has the +// ability to make unmanaged-to-managed thunks. It does NOT allow you to +// pass C++ function pointers to C#. +// +// I would have liked to support FastDelegate<...> as the C++ argument +// type; this would have involved the cs_callback2 macro... but it turns +// out not to work under default project settings because .NET functions +// use the __stdcall calling convention, but FastDelegate uses the default +// convention which tends to be something else (__fastcall?). So nevermind. +// +// Anyway, to use this macro you need to declare the function pointer type +// TYPE in the appropriate header file (including the calling convention), +// declare a delegate named after CSTYPE in your C# project, and use this +// macro in your .i file. Here is an example: +// +// in C++ header file (%include this header in your .i file): +// typedef void (__stdcall *Callback)(PCWSTR); +// void Foo(Callback c); +// +// in C# code: +// public delegate void CppCallback([MarshalAs(UnmanagedType.LPWStr)] string message); +// +// in your .i file: +// %cs_callback(Callback, CppCallback) +// +// Remember to invoke %cs_callback before any code involving Callback. +%define %cs_callback(TYPE, CSTYPE) + %typemap(ctype) TYPE, TYPE& "void*" + %typemap(in) TYPE %{ $1 = (TYPE)$input; %} + %typemap(in) TYPE& %{ $1 = (TYPE*)&$input; %} + %typemap(imtype, out="IntPtr") TYPE, TYPE& "CSTYPE" + %typemap(cstype, out="IntPtr") TYPE, TYPE& "CSTYPE" + %typemap(csin) TYPE, TYPE& "$csinput" +%enddef +%define %cs_callback2(TYPE, CTYPE, CSTYPE) + %typemap(ctype) TYPE "CTYPE" + %typemap(in) TYPE %{ $1 = (TYPE)$input; %} + %typemap(imtype, out="IntPtr") TYPE "CSTYPE" + %typemap(cstype, out="IntPtr") TYPE "CSTYPE" + %typemap(csin) TYPE "$csinput" +%enddef + +%cs_callback(Sorter::SortFunction, Sorter::CppSortFunction) + +%include "gdcmSorter.h" +EXTEND_CLASS_PRINT(gdcm::Sorter) +%include "gdcmIPPSorter.h" +EXTEND_CLASS_PRINT(gdcm::IPPSorter) +%include "gdcmSpectroscopy.h" +//EXTEND_CLASS_PRINT(gdcm::Spectroscopy) +%include "gdcmPrinter.h" +//EXTEND_CLASS_PRINT(gdcm::Printer) +%include "gdcmXMLPrinter.h" +//EXTEND_CLASS_PRINT(gdcm::XMLPrinter) +%include "gdcmDumper.h" +//EXTEND_CLASS_PRINT(gdcm::Dumper) +%include "gdcmOrientation.h" +EXTEND_CLASS_PRINT(gdcm::Orientation) +%include "gdcmDirectionCosines.h" +EXTEND_CLASS_PRINT(gdcm::DirectionCosines) + +%include "gdcmFiducials.h" +%include "gdcmWaveform.h" +%include "gdcmPersonName.h" +%include "gdcmCurve.h" +%include "gdcmDICOMDIR.h" +%include "gdcmValidate.h" +%include "gdcmApplicationEntity.h" +%include "gdcmDictPrinter.h" +%include "gdcmFilenameGenerator.h" +%include "gdcmVersion.h" +EXTEND_CLASS_PRINT(gdcm::Version) +%include "gdcmFilename.h" +%include "gdcmEnumeratedValues.h" +%include "gdcmPatient.h" +%include "gdcmStudy.h" +%include "gdcmUsage.h" +%include "gdcmMacroEntry.h" +%include "gdcmModuleEntry.h" +EXTEND_CLASS_PRINT(gdcm::ModuleEntry) +%include "gdcmNestedModuleEntries.h" +%include "gdcmMacro.h" +%include "gdcmMacros.h" +%include "gdcmModule.h" +%include "gdcmModules.h" +%include "gdcmDefs.h" +%include "gdcmIOD.h" +%include "gdcmIODs.h" +%include "gdcmTableEntry.h" +%include "gdcmDefinedTerms.h" +%include "gdcmSeries.h" +%include "gdcmIODEntry.h" + +%apply char[] { char* out } +%apply char[] { char* in } +%include "gdcmRescaler.h" +//EXTEND_CLASS_PRINT(gdcm::Rescaler) +%extend gdcm::Rescaler +{ + bool Rescale(double out[], const short in[], size_t n) { + return $self->Rescale((char*)out, (char*)in, n); + } +} +%clear char* out; +%clear char* in; + +%include "gdcmSegmentedPaletteColorLookupTable.h" +%include "gdcmUnpacker12Bits.h" + +%include "gdcmConfigure.h" +#ifdef GDCM_BUILD_TESTING +%include "gdcmTesting.h" +%ignore gdcm::Testing::ComputeMD5(const char *, const unsigned long , char []); +%ignore gdcm::Testing::ComputeFileMD5(const char*, char []); +%extend gdcm::Testing +{ + static const char *ComputeFileMD5(const char *filename) { + static char buffer[33]; + gdcm::Testing::ComputeFileMD5(filename, buffer); + return buffer; + } +}; +#endif +%include "gdcmTagPath.h" +%include "gdcmBitmapToBitmapFilter.h" +%include "gdcmPixmapToPixmapFilter.h" +//%ignore gdcm::ImageToImageFilter::GetOutput() const; +%include "gdcmImageToImageFilter.h" +%include "gdcmSOPClassUIDToIOD.h" +//%feature("director") Coder; +//%include "gdcmCoder.h" +//%feature("director") Decoder; +//%include "gdcmDecoder.h" +//%feature("director") Codec; +//%include "gdcmCodec.h" +%feature("director") ImageCodec; +%include "gdcmImageCodec.h" +%include "gdcmJPEGCodec.h" +%include "gdcmJPEGLSCodec.h" +%include "gdcmJPEG2000Codec.h" +%include "gdcmPNMCodec.h" +%include "gdcmImageChangeTransferSyntax.h" +%template(SmartPtrFCTS) gdcm::SmartPointer; +%include "gdcmFileChangeTransferSyntax.h" +%include "gdcmImageApplyLookupTable.h" +%include "gdcmSplitMosaicFilter.h" +%include "gdcmImageChangePhotometricInterpretation.h" +%include "gdcmImageChangePlanarConfiguration.h" +%include "gdcmImageFragmentSplitter.h" +%include "gdcmDataSetHelper.h" +%include "gdcmFileExplicitFilter.h" +%template (DoubleArrayType) std::vector; +%template (UShortArrayType) std::vector; +%template (UIntArrayType) std::vector; +%include "gdcmImageHelper.h" +%include "gdcmMD5.h" +%include "gdcmDummyValueGenerator.h" +%include "gdcmSHA1.h" +//%include "gdcmBase64.h" +%include "gdcmCryptographicMessageSyntax.h" +%include "gdcmCryptoFactory.h" +%include "gdcmSpacing.h" +%include "gdcmIconImageGenerator.h" +%include "gdcmIconImageFilter.h" + +%feature("director") SimpleSubjectWatcher; +%include "gdcmSimpleSubjectWatcher.h" +%include "gdcmDICOMDIRGenerator.h" +%include "gdcmFileDerivation.h" + +// MEXD: +%template(DataSetArrayType) std::vector< gdcm::DataSet >; +%template(FileArrayType) std::vector< gdcm::File >; +%template(PresentationContextArrayType) std::vector< gdcm::PresentationContext >; +%template(KeyValuePairType) std::pair< gdcm::Tag, std::string>; +%template(KeyValuePairArrayType) std::vector< std::pair< gdcm::Tag, std::string> >; +%template(TagArrayType) std::vector< gdcm::Tag >; +%include "gdcmQueryBase.h" +%include "gdcmBaseRootQuery.h" +%include "gdcmQueryFactory.h" +%template(CharSetArrayType) std::vector< gdcm::ECharSet >; +%include "gdcmCompositeNetworkFunctions.h" +%include "gdcmPresentationContext.h" +//EXTEND_CLASS_PRINT(gdcm::PresentationContext) +%include "gdcmPresentationContextGenerator.h" +typedef int64_t time_t; // FIXME +%include "gdcmServiceClassUser.h" +%apply char[] { char* inReadBuffer } +%include "gdcmStreamImageReader.h" +%clear char* inReadBuffer; +%include "gdcmRegion.h" +EXTEND_CLASS_PRINT(gdcm::Region) +%include "gdcmBoxRegion.h" +EXTEND_CLASS_PRINT(gdcm::BoxRegion) +%apply char[] { char* inreadbuffer } +%include "gdcmImageRegionReader.h" +%clear char* inreadbuffer; diff --git a/gdcm/Wrapping/Perl/CMakeLists.txt b/gdcm/Wrapping/Perl/CMakeLists.txt new file mode 100644 index 0000000..b4a097a --- /dev/null +++ b/gdcm/Wrapping/Perl/CMakeLists.txt @@ -0,0 +1,59 @@ +# Required: +# sudo apt-get install libperl-dev + +# http://www.swig.org/Doc2.0/Perl5.html +find_package(SWIG REQUIRED) +include(${SWIG_USE_FILE}) + +include_directories( + "${GDCM_BINARY_DIR}/Source/Common" + "${GDCM_SOURCE_DIR}/Source/Common" + "${GDCM_SOURCE_DIR}/Source/DataStructureAndEncodingDefinition" + "${GDCM_SOURCE_DIR}/Source/InformationObjectDefinition" + "${GDCM_SOURCE_DIR}/Source/MediaStorageAndFileFormat" + "${GDCM_SOURCE_DIR}/Source/DataDictionary" +) + +find_package(PerlLibs REQUIRED) +include_directories( + ${PERL_INCLUDE_PATH} +) + +set_source_files_properties(gdcm.i PROPERTIES CPLUSPLUS ON) + +# TODO check convetion for perl module name: +SWIG_ADD_MODULE(perl_gdcm perl gdcm.i) +SWIG_LINK_LIBRARIES(perl_gdcm gdcmMSFF) + +#set_target_properties(${SWIG_MODULE_perl_gdcm_REAL_NAME} PROPERTIES LINK_INTERFACE_LIBRARIES "") +# Remove 'lib' prefix :no-op on windows and valid for UNIX based syste +set_target_properties(${SWIG_MODULE_perl_gdcm_REAL_NAME} PROPERTIES PREFIX "") +set_property(TARGET ${SWIG_MODULE_perl_gdcm_REAL_NAME} PROPERTY NO_SONAME 1) + +if(UNIX) + set_target_properties(${SWIG_MODULE_perl_gdcm_REAL_NAME} PROPERTIES OUTPUT_NAME "gdcm") +endif() + + +# Let's copy gdcm.pm into the bin dir: +#add_custom_command( +# OUTPUT ${LIBRARY_OUTPUT_PATH}/gdcm.pm +# COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/gdcm.php ${LIBRARY_OUTPUT_PATH}/gdcm.pm +# DEPENDS "${swig_generated_file_fullname}" +# COMMENT "copying gdcm.pm" +#) +#add_custom_target(GDCMPERL ALL +# DEPENDS ${LIBRARY_OUTPUT_PATH}/gdcm.pm +# COMMENT "building gdcm.pm" +#) + +# Module are always place in the library destination +# but for poor win32 user I decided to place them +# right next to the other dlls +if(NOT GDCM_INSTALL_NO_LIBRARIES) + install_swig_module(perl_gdcm Perl) + # because gdcm.pm is constructed with custom commands, it need the install(FILES signature: + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/gdcm.pm + DESTINATION ${GDCM_INSTALL_LIB_DIR} COMPONENT PerlModule + ) +endif() diff --git a/gdcm/Wrapping/Perl/gdcm.i b/gdcm/Wrapping/Perl/gdcm.i new file mode 100644 index 0000000..bc017d4 --- /dev/null +++ b/gdcm/Wrapping/Perl/gdcm.i @@ -0,0 +1,622 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +// See docs: +// http://www.swig.org/Doc1.3/Php.html +// http://www.swig.org/Doc1.3/SWIGPlus.html#SWIGPlus + +%module(docstring="A DICOM library",directors=1) gdcm +#pragma SWIG nowarn=302,303,312,362,383,389,401,503,504,509,510,514,516,842 + +#if defined(SWIGPERL) +%{ +#define SWIGPERL +%} +#endif + + +%{ +// http://www.swig.org/Doc2.0/Perl5.html#Perl5_nn9 +#undef New + +#include "gdcmTypes.h" +#include "gdcmASN1.h" +#include "gdcmSmartPointer.h" +#include "gdcmSwapCode.h" +#include "gdcmEvent.h" +#include "gdcmProgressEvent.h" +#include "gdcmAnonymizeEvent.h" +#include "gdcmDirectory.h" +#include "gdcmTesting.h" +#include "gdcmObject.h" +#include "gdcmPixelFormat.h" +#include "gdcmMediaStorage.h" +#include "gdcmTag.h" +#include "gdcmPrivateTag.h" +#include "gdcmVL.h" +#include "gdcmVR.h" +#include "gdcmVM.h" +#include "gdcmObject.h" +#include "gdcmValue.h" +#include "gdcmByteValue.h" +#include "gdcmDataElement.h" +#include "gdcmItem.h" +#include "gdcmSequenceOfItems.h" +#include "gdcmDataSet.h" +//#include "gdcmString.h" +//#include "gdcmCodeString.h" +#include "gdcmPreamble.h" +#include "gdcmFile.h" +#include "gdcmBitmap.h" +#include "gdcmPixmap.h" +#include "gdcmImage.h" +#include "gdcmIconImage.h" +#include "gdcmFragment.h" +#include "gdcmCSAHeader.h" +#include "gdcmPDBHeader.h" +#include "gdcmSequenceOfFragments.h" +#include "gdcmTransferSyntax.h" +#include "gdcmBasicOffsetTable.h" +//#include "gdcmLO.h" +#include "gdcmCSAElement.h" +#include "gdcmPDBElement.h" +#include "gdcmFileSet.h" + +#include "gdcmReader.h" +#include "gdcmPixmapReader.h" +#include "gdcmImageReader.h" +#include "gdcmWriter.h" +#include "gdcmPixmapWriter.h" +#include "gdcmImageWriter.h" +#include "gdcmStringFilter.h" +#include "gdcmGlobal.h" +#include "gdcmDicts.h" +#include "gdcmDict.h" +#include "gdcmCSAHeaderDict.h" +#include "gdcmDictEntry.h" +#include "gdcmCSAHeaderDictEntry.h" +#include "gdcmUIDGenerator.h" +//#include "gdcmConstCharWrapper.h" +#include "gdcmScanner.h" +#include "gdcmAttribute.h" +#include "gdcmSubject.h" +#include "gdcmCommand.h" +#include "gdcmAnonymizer.h" +#include "gdcmSystem.h" +#include "gdcmTrace.h" +#include "gdcmUIDs.h" +#include "gdcmSorter.h" +#include "gdcmIPPSorter.h" +#include "gdcmSpectroscopy.h" +#include "gdcmPrinter.h" +#include "gdcmDumper.h" +#include "gdcmOrientation.h" +#include "gdcmFiducials.h" +#include "gdcmWaveform.h" +#include "gdcmPersonName.h" +#include "gdcmIconImage.h" +#include "gdcmCurve.h" +#include "gdcmDICOMDIR.h" +#include "gdcmValidate.h" +#include "gdcmApplicationEntity.h" +#include "gdcmDictPrinter.h" +#include "gdcmFilenameGenerator.h" +#include "gdcmVersion.h" +#include "gdcmFilename.h" +#include "gdcmEnumeratedValues.h" +#include "gdcmPatient.h" +#include "gdcmStudy.h" +#include "gdcmUsage.h" +#include "gdcmMacroEntry.h" +#include "gdcmModuleEntry.h" +#include "gdcmNestedModuleEntries.h" +#include "gdcmMacro.h" +#include "gdcmMacros.h" +#include "gdcmModule.h" +#include "gdcmModules.h" +#include "gdcmDefs.h" +#include "gdcmIOD.h" +#include "gdcmIODs.h" +#include "gdcmTableEntry.h" +#include "gdcmDefinedTerms.h" +#include "gdcmSeries.h" +#include "gdcmIODEntry.h" +#include "gdcmRescaler.h" +#include "gdcmSegmentedPaletteColorLookupTable.h" +#include "gdcmUnpacker12Bits.h" +//#include "gdcmPythonFilter.h" +#include "gdcmDirectionCosines.h" +#include "gdcmTagPath.h" +#include "gdcmPixmapToPixmapFilter.h" +#include "gdcmImageToImageFilter.h" +#include "gdcmSOPClassUIDToIOD.h" +#include "gdcmCoder.h" +#include "gdcmDecoder.h" +#include "gdcmCodec.h" +#include "gdcmImageCodec.h" +#include "gdcmJPEGCodec.h" +#include "gdcmJPEGLSCodec.h" +#include "gdcmJPEG2000Codec.h" +#include "gdcmPNMCodec.h" +#include "gdcmImageChangeTransferSyntax.h" +#include "gdcmImageApplyLookupTable.h" +#include "gdcmSplitMosaicFilter.h" +//#include "gdcmImageChangePhotometricInterpretation.h" +#include "gdcmImageChangePlanarConfiguration.h" +#include "gdcmImageFragmentSplitter.h" +#include "gdcmDataSetHelper.h" +#include "gdcmFileExplicitFilter.h" +#include "gdcmImageHelper.h" +#include "gdcmMD5.h" +#include "gdcmDummyValueGenerator.h" +#include "gdcmSHA1.h" +#include "gdcmBase64.h" +#include "gdcmCryptographicMessageSyntax.h" +#include "gdcmSpacing.h" +#include "gdcmSimpleSubjectWatcher.h" +#include "gdcmDICOMDIRGenerator.h" +#include "gdcmFileDerivation.h" + +using namespace gdcm; +%} + +//%include "docstrings.i" + +// swig need to know what are uint16_t, uint8_t... +%include "stdint.i" + +// gdcm does not use std::string in its interface, but we do need it for the +// %extend (see below) +%include "std_string.i" +//%include "std_set.i" +%include "std_vector.i" +%include "std_pair.i" +%include "std_map.i" +%include "exception.i" + +// operator= is not needed in python AFAIK +%ignore operator=; // Ignore = everywhere. +%ignore operator++; // Ignore + +%define EXTEND_CLASS_PRINT_GENERAL(classfuncname,classname) +%extend classname +{ + const char *classfuncname() { + static std::string buffer; + std::ostringstream os; + os << *self; + buffer = os.str(); + return buffer.c_str(); + } +}; +%enddef + +#if defined(SWIGPERL) +%define EXTEND_CLASS_PRINT(classname) +EXTEND_CLASS_PRINT_GENERAL(toString,classname) +%enddef +#endif + +//%feature("autodoc", "1") +%include "gdcmConfigure.h" +//%include "gdcmTypes.h" +//%include "gdcmWin32.h" +// I cannot include gdcmWin32.h without gdcmTypes.h, first. But gdcmTypes.h needs to know _MSC_VER at swig time... +#define GDCM_EXPORT +%include "gdcmLegacyMacro.h" + +// The following must be define early on as gdcmVL.h get included real early +%rename(GetValueLength) gdcm::VL::operator uint32_t; +//%csmethodmodifiers gdcm::VL::GetValueLength "private" +//%csmethodmodifiers GetValueLength "private" +//%rename(GetValue) VL::operator uint32_t (); +// public static implicit operator int( MyType a ) +// { +// return a.value; +// } +%include "gdcmSwapCode.h" + +//%feature("director") Event; +//%feature("director") AnyEvent; +%include "gdcmEvent.h" + +%include "gdcmPixelFormat.h" +EXTEND_CLASS_PRINT(gdcm::PixelFormat) +%include "gdcmMediaStorage.h" +EXTEND_CLASS_PRINT(gdcm::MediaStorage) +//%rename(__getitem__) gdcm::Tag::operator[]; +//%rename(this ) gdcm::Tag::operator[]; +%include "gdcmTag.h" +EXTEND_CLASS_PRINT(gdcm::Tag) +%include "gdcmPrivateTag.h" +EXTEND_CLASS_PRINT(gdcm::PrivateTag) + +%include "gdcmProgressEvent.h" +//%feature("director") AnonymizeEvent; +%include "gdcmAnonymizeEvent.h" + +%include "gdcmVL.h" +EXTEND_CLASS_PRINT(gdcm::VL) + +%include "gdcmVR.h" +EXTEND_CLASS_PRINT(gdcm::VR) +%include "gdcmVM.h" +EXTEND_CLASS_PRINT(gdcm::VM) +//%template (FilenameType) std::string; +%template (FilenamesType) std::vector; +%include "gdcmDirectory.h" +EXTEND_CLASS_PRINT(gdcm::Directory) +%include "gdcmObject.h" +%include "gdcmValue.h" +EXTEND_CLASS_PRINT(gdcm::Value) +// Array marshaling for arrays of primitives + + + + +%apply char[] { char* buffer } +%ignore gdcm::ByteValue::WriteBuffer(std::ostream &os) const; +//%ignore gdcm::ByteValue::GetPointer() const; +//%ignore gdcm::ByteValue::GetBuffer(char *buffer, unsigned long length) const; +%include "gdcmByteValue.h" +EXTEND_CLASS_PRINT(gdcm::ByteValue) +%clear char* buffer; + + +%apply char[] { const char* array } + +%include "gdcmASN1.h" +%include "gdcmSmartPointer.h" +%template(SmartPtrSQ) gdcm::SmartPointer; +%template(SmartPtrFrag) gdcm::SmartPointer; +%include "gdcmDataElement.h" +EXTEND_CLASS_PRINT(gdcm::DataElement) + +%clear const char* array; +%extend gdcm::DataElement +{ + void SetArray(unsigned char array[], unsigned int nitems) { + $self->SetByteValue((char*)array, nitems * sizeof(unsigned char) ); + } + void SetArray(char array[], unsigned int nitems) { + $self->SetByteValue((char*)array, nitems * sizeof(char) ); + } + void SetArray(unsigned short array[], unsigned int nitems) { + $self->SetByteValue((char*)array, nitems * sizeof(unsigned short) ); + } + void SetArray(short array[], unsigned int nitems) { + $self->SetByteValue((char*)array, nitems * sizeof(short) ); + } + void SetArray(float array[], unsigned int nitems) { + $self->SetByteValue((char*)array, nitems * sizeof(float) ); + } + void SetArray(double array[], unsigned int nitems) { + $self->SetByteValue((char*)array, nitems * sizeof(double) ); + } +}; + +%include "gdcmItem.h" +EXTEND_CLASS_PRINT(gdcm::Item) +/* + The following line is very important it properly convert : +SWIGTYPE_p_std__vectorT_int_t__size_type -> uint +*/ +%template() std::vector< gdcm::Item >; +%include "gdcmSequenceOfItems.h" +EXTEND_CLASS_PRINT(gdcm::SequenceOfItems) +%rename (PHPDataSet) SWIGDataSet; +%rename (PHPTagToValue) SWIGTagToValue; +%include "gdcmDataSet.h" +EXTEND_CLASS_PRINT(gdcm::DataSet) +//%include "gdcmString.h" +//%include "gdcmTransferSyntax.h" +%include "gdcmPhotometricInterpretation.h" +EXTEND_CLASS_PRINT(gdcm::PhotometricInterpretation) +%include "gdcmObject.h" +%include "gdcmLookupTable.h" +EXTEND_CLASS_PRINT(gdcm::LookupTable) +%include "gdcmOverlay.h" +EXTEND_CLASS_PRINT(gdcm::Overlay) +//%include "gdcmVR.h" +//%template (DataElementSet) std::set; +%include "gdcmPreamble.h" +EXTEND_CLASS_PRINT(gdcm::Preamble) +%include "gdcmTransferSyntax.h" +EXTEND_CLASS_PRINT(gdcm::TransferSyntax) +%include "gdcmFileMetaInformation.h" +EXTEND_CLASS_PRINT(gdcm::FileMetaInformation) + +//%template(File) gdcm::SmartPointer; +//%ignore gdcm::File; + +%include "gdcmFile.h" +EXTEND_CLASS_PRINT(gdcm::File) +//%include "gdcm_arrays_csharp.i" + +%apply char[] { char* buffer } +%apply unsigned int[] { unsigned int dims[3] } + +//%apply byte OUTPUT[] { char* buffer } ; +//%ignore gdcm::Pixmap::GetBuffer(char*) const; +//%apply byte FIXED[] { char *buffer } +//%csmethodmodifiers gdcm::Pixmap::GetBuffer "public unsafe"; +//%define %cs_marshal_array(TYPE, CSTYPE) +// %typemap(ctype) TYPE[] "void*" +// %typemap(imtype, inattributes="[MarshalAs(UnmanagedType.LPArray)]") TYPE[] "CSTYPE[]" +// %typemap(cstype) TYPE[] "CSTYPE[]" +// %typemap(in) TYPE[] %{ $1 = (TYPE*)$input; %} +// %typemap(csin) TYPE[] "$csinput" +//%enddef +//%cs_marshal_array(char, byte) +%include "gdcmBitmap.h" +EXTEND_CLASS_PRINT(gdcm::Bitmap) + +%include "gdcmPixmap.h" +EXTEND_CLASS_PRINT(gdcm::Pixmap) + +%include "gdcmImage.h" +EXTEND_CLASS_PRINT(gdcm::Image) +%include "gdcmIconImage.h" +EXTEND_CLASS_PRINT(gdcm::IconImage) +%include "gdcmFragment.h" +EXTEND_CLASS_PRINT(gdcm::Fragment) +%include "gdcmPDBElement.h" +EXTEND_CLASS_PRINT(gdcm::PDBElement) +%include "gdcmPDBHeader.h" +EXTEND_CLASS_PRINT(gdcm::PDBHeader) +%include "gdcmCSAElement.h" +EXTEND_CLASS_PRINT(gdcm::CSAElement) +%include "gdcmCSAHeader.h" +EXTEND_CLASS_PRINT(gdcm::CSAHeader) +%include "gdcmSequenceOfFragments.h" +EXTEND_CLASS_PRINT(gdcm::SequenceOfFragments) +%include "gdcmBasicOffsetTable.h" +EXTEND_CLASS_PRINT(gdcm::BasicOffsetTable) +//%include "gdcmLO.h" +%include "gdcmFileSet.h" +EXTEND_CLASS_PRINT(gdcm::FileSet) + +//%include "gdcmGlobal.h" +//EXTEND_CLASS_PRINT(gdcm::Global) + +%include "gdcmDictEntry.h" +EXTEND_CLASS_PRINT(gdcm::DictEntry) +%include "gdcmCSAHeaderDictEntry.h" +EXTEND_CLASS_PRINT(gdcm::CSAHeaderDictEntry) + +%include "gdcmDict.h" +EXTEND_CLASS_PRINT(gdcm::Dict) +%include "gdcmCSAHeaderDict.h" +EXTEND_CLASS_PRINT(gdcm::CSAHeaderDictEntry) +%include "gdcmDicts.h" +EXTEND_CLASS_PRINT(gdcm::Dicts) +%include "gdcmReader.h" +//EXTEND_CLASS_PRINT(gdcm::Reader) +%include "gdcmPixmapReader.h" +//EXTEND_CLASS_PRINT(gdcm::PixmapReader) +%include "gdcmImageReader.h" +//EXTEND_CLASS_PRINT(gdcm::ImageReader) +%include "gdcmWriter.h" +//EXTEND_CLASS_PRINT(gdcm::Writer) +%include "gdcmPixmapWriter.h" +//EXTEND_CLASS_PRINT(gdcm::PixmapWriter) +%include "gdcmImageWriter.h" +//EXTEND_CLASS_PRINT(gdcm::ImageWriter) +%template (PairString) std::pair; +//%template (MyM) std::map; +%include "gdcmStringFilter.h" +//EXTEND_CLASS_PRINT(gdcm::StringFilter) +%include "gdcmUIDGenerator.h" +//%template (ValuesType) std::set; +%rename (CSharpTagToValue) SWIGTagToValue; +%include "gdcmScanner.h" +EXTEND_CLASS_PRINT(gdcm::Scanner) +#define GDCM_STATIC_ASSERT(x) +%include "gdcmAttribute.h" +%include "gdcmSubject.h" +%include "gdcmCommand.h" +%template(SmartPtrAno) gdcm::SmartPointer; +//%ignore gdcm::Anonymizer::Anonymizer; + + +//%template(Anonymizer) gdcm::SmartPointer; +// +//%ignore gdcm::Anonymizer; +//%feature("unref") Anonymizer "coucou $this->Delete();" +// http://www.swig.org/Doc1.3/SWIGPlus.html#SWIGPlus%5Fnn34 +%include "gdcmAnonymizer.h" + + +//EXTEND_CLASS_PRINT(gdcm::Anonymizer) +//%extend gdcm::Anonymizer +//{ +//%typemap(cscode) gdcm::Anonymizer +//%{ +// public Anonymizer() : this(gdcmPINVOKE.Anonymizer_New(), false) { +// } +//%} +//}; + +// System is a namespace in C#, need to rename to something different +%rename (PosixEmulation) System; +%include "gdcmSystem.h" +//EXTEND_CLASS_PRINT(gdcm::System) + +%include "gdcmTrace.h" +//EXTEND_CLASS_PRINT(gdcm::Trace) +%include "gdcmUIDs.h" +EXTEND_CLASS_PRINT(gdcm::UIDs) +//%feature("director") gdcm::IPPSorter; + +//////////////////////////////////////////////////////////////////////////// +// cs_callback is used to marshall callbacks. It allows a C# function to +// be passed to C++ as a function pointer through P/Invoke, which has the +// ability to make unmanaged-to-managed thunks. It does NOT allow you to +// pass C++ function pointers to C#. +// +// I would have liked to support FastDelegate<...> as the C++ argument +// type; this would have involved the cs_callback2 macro... but it turns +// out not to work under default project settings because .NET functions +// use the __stdcall calling convention, but FastDelegate uses the default +// convention which tends to be something else (__fastcall?). So nevermind. +// +// Anyway, to use this macro you need to declare the function pointer type +// TYPE in the appropriate header file (including the calling convention), +// declare a delegate named after CSTYPE in your C# project, and use this +// macro in your .i file. Here is an example: +// +// in C++ header file (%include this header in your .i file): +// typedef void (__stdcall *Callback)(PCWSTR); +// void Foo(Callback c); +// +// in C# code: +// public delegate void CppCallback([MarshalAs(UnmanagedType.LPWStr)] string message); +// +// in your .i file: +// %cs_callback(Callback, CppCallback) +// +// Remember to invoke %cs_callback before any code involving Callback. +%define %cs_callback(TYPE, CSTYPE) + %typemap(ctype) TYPE, TYPE& "void*" + %typemap(in) TYPE %{ $1 = (TYPE)$input; %} + %typemap(in) TYPE& %{ $1 = (TYPE*)&$input; %} + %typemap(imtype, out="IntPtr") TYPE, TYPE& "CSTYPE" + %typemap(cstype, out="IntPtr") TYPE, TYPE& "CSTYPE" + %typemap(csin) TYPE, TYPE& "$csinput" +%enddef +%define %cs_callback2(TYPE, CTYPE, CSTYPE) + %typemap(ctype) TYPE "CTYPE" + %typemap(in) TYPE %{ $1 = (TYPE)$input; %} + %typemap(imtype, out="IntPtr") TYPE "CSTYPE" + %typemap(cstype, out="IntPtr") TYPE "CSTYPE" + %typemap(csin) TYPE "$csinput" +%enddef + +%cs_callback(Sorter::SortFunction, Sorter::CppSortFunction) + +%include "gdcmSorter.h" +EXTEND_CLASS_PRINT(gdcm::Sorter) +%include "gdcmIPPSorter.h" +EXTEND_CLASS_PRINT(gdcm::IPPSorter) +%include "gdcmSpectroscopy.h" +//EXTEND_CLASS_PRINT(gdcm::Spectroscopy) +%include "gdcmPrinter.h" +//EXTEND_CLASS_PRINT(gdcm::Printer) +%include "gdcmDumper.h" +//EXTEND_CLASS_PRINT(gdcm::Dumper) +%include "gdcmOrientation.h" +EXTEND_CLASS_PRINT(gdcm::Orientation) +%include "gdcmDirectionCosines.h" +EXTEND_CLASS_PRINT(gdcm::DirectionCosines) + +%include "gdcmFiducials.h" +%include "gdcmWaveform.h" +%include "gdcmPersonName.h" +%include "gdcmIconImage.h" +%include "gdcmCurve.h" +%include "gdcmDICOMDIR.h" +%include "gdcmValidate.h" +%include "gdcmApplicationEntity.h" +%include "gdcmDictPrinter.h" +%include "gdcmFilenameGenerator.h" +%include "gdcmVersion.h" +EXTEND_CLASS_PRINT(gdcm::Version) +%include "gdcmFilename.h" +%include "gdcmEnumeratedValues.h" +%include "gdcmPatient.h" +%include "gdcmStudy.h" +%include "gdcmUsage.h" +%include "gdcmMacroEntry.h" +%include "gdcmModuleEntry.h" +EXTEND_CLASS_PRINT(gdcm::ModuleEntry) +%include "gdcmNestedModuleEntries.h" +%include "gdcmMacro.h" +%include "gdcmMacros.h" +%include "gdcmModule.h" +%include "gdcmModules.h" +%include "gdcmDefs.h" +%include "gdcmIOD.h" +%include "gdcmIODs.h" +%include "gdcmTableEntry.h" +%include "gdcmDefinedTerms.h" +%include "gdcmSeries.h" +%include "gdcmIODEntry.h" + +%apply char[] { char* out } +%apply char[] { char* in } +%include "gdcmRescaler.h" +//EXTEND_CLASS_PRINT(gdcm::Rescaler) +%extend gdcm::Rescaler +{ + bool Rescale(double out[], const short in[], size_t n) { + return $self->Rescale((char*)out, (char*)in, n); + } +} +%clear char* out; +%clear char* in; + +%include "gdcmSegmentedPaletteColorLookupTable.h" +%include "gdcmUnpacker12Bits.h" + +%include "gdcmConfigure.h" +#ifdef GDCM_BUILD_TESTING +%include "gdcmTesting.h" +%ignore gdcm::Testing::ComputeMD5(const char *, const unsigned long , char []); +%ignore gdcm::Testing::ComputeFileMD5(const char*, char []); +%extend gdcm::Testing +{ + static const char *ComputeFileMD5(const char *filename) { + static char buffer[33]; + gdcm::Testing::ComputeFileMD5(filename, buffer); + return buffer; + } +}; +#endif +//%include "gdcmPythonFilter.h" +%include "gdcmTagPath.h" +%include "gdcmPixmapToPixmapFilter.h" +%include "gdcmImageToImageFilter.h" +%include "gdcmSOPClassUIDToIOD.h" +//%feature("director") Coder; +//%include "gdcmCoder.h" +//%feature("director") Decoder; +//%include "gdcmDecoder.h" +//%feature("director") Codec; +//%include "gdcmCodec.h" +%feature("director") ImageCodec; +%include "gdcmImageCodec.h" +%include "gdcmJPEGCodec.h" +%include "gdcmJPEGLSCodec.h" +%include "gdcmJPEG2000Codec.h" +%include "gdcmPNMCodec.h" +%include "gdcmImageChangeTransferSyntax.h" +%include "gdcmImageApplyLookupTable.h" +%include "gdcmSplitMosaicFilter.h" +//%include "gdcmImageChangePhotometricInterpretation.h" +%include "gdcmImageChangePlanarConfiguration.h" +%include "gdcmImageFragmentSplitter.h" +%include "gdcmDataSetHelper.h" +%include "gdcmFileExplicitFilter.h" +%template (DoubleType) std::vector; +%include "gdcmImageHelper.h" +%include "gdcmMD5.h" +%include "gdcmDummyValueGenerator.h" +%include "gdcmSHA1.h" +//%include "gdcmBase64.h" +%include "gdcmCryptographicMessageSyntax.h" +%include "gdcmSpacing.h" + +%feature("director") SimpleSubjectWatcher; +%include "gdcmSimpleSubjectWatcher.h" +%include "gdcmDICOMDIRGenerator.h" +%include "gdcmFileDerivation.h" diff --git a/gdcm/Wrapping/Python/.NoDartCoverage b/gdcm/Wrapping/Python/.NoDartCoverage new file mode 100644 index 0000000..3c99729 --- /dev/null +++ b/gdcm/Wrapping/Python/.NoDartCoverage @@ -0,0 +1 @@ +# do not do coverage in this directory diff --git a/gdcm/Wrapping/Python/CMakeLists.txt b/gdcm/Wrapping/Python/CMakeLists.txt new file mode 100644 index 0000000..b1bcdb4 --- /dev/null +++ b/gdcm/Wrapping/Python/CMakeLists.txt @@ -0,0 +1,151 @@ +# Try to rebuild wrapping a little more often: +include_regular_expression("^(gdcm).*$") +# TODO: +# SWIG is really a pain in the neck to use, a better alternative is Py++ which is using +# gccxml for the C++ parser and allow a full ANSI C++ support +# Note gcc has some issue with RTTI stuff: +# http://groups.google.com/group/comp.lang.c++.moderated/browse_thread/thread/ac889a7d9eac902f +# http://gcc.gnu.org/ml/gcc-help/2007-10/msg00239.html +# http://wiki.python.org/moin/boost.python/CrossExtensionModuleDependencies +# http://www.boost-consulting.com/writing/bpl.html +# http://gcc.gnu.org/ml/gcc/2002-05/msg00866.html +# http://mail.python.org/pipermail/c++-sig/2002-May/001021.html +# http://mail.python.org/pipermail/python-dev/2002-May/023923.html + +# 2.0.5 is required here to solve the issue with wrapping of vector::size_type +# see full thread at: +# http://sourceforge.net/mailarchive/message.php?msg_id=29217941 +# 2.0.5 cannot be used because of the error +# error: invalid initialization of reference of type 'ptrdiff_t& {aka int&}' from expression of type 'long int' +# http://sourceforge.net/mailarchive/message.php?msg_id=29294773 +# 2.0.6 cannot be used because of a serious typemap bug in 2.0.5 +# http://sourceforge.net/mailarchive/message.php?msg_id=29305946 +find_package(SWIG 2.0.7 REQUIRED) +mark_as_advanced(SWIG_DIR SWIG_EXECUTABLE SWIG_VERSION) +include(${SWIG_USE_FILE}) + +# +# Do not cover this lib +# +configure_file (${CMAKE_CURRENT_SOURCE_DIR}/.NoDartCoverage + ${CMAKE_CURRENT_BINARY_DIR}/.NoDartCoverage) + +# Note: +# python -c "from struct import pack; print pack('5b', (41*len('99')), pow(8,2)+20, 4900**0.5, range(78)[-1], 10)" + +include_directories( + "${GDCM_BINARY_DIR}/Source/Common" + "${GDCM_SOURCE_DIR}/Source/Common" + "${GDCM_SOURCE_DIR}/Source/DataStructureAndEncodingDefinition" + "${GDCM_SOURCE_DIR}/Source/InformationObjectDefinition" + "${GDCM_SOURCE_DIR}/Source/MediaStorageAndFileFormat" + "${GDCM_SOURCE_DIR}/Source/DataDictionary" + "${GDCM_SOURCE_DIR}/Source/MessageExchangeDefinition" + ${CMAKE_CURRENT_SOURCE_DIR} +) + +find_package(PythonInterp REQUIRED) +find_package(PythonLibs REQUIRED) +# TODO Need to check consistency python interp and python libs... +mark_as_advanced(PYTHON_LIBRARY PYTHON_INCLUDE_PATH) +# Lamest excuse ever: +# http://mail.python.org/pipermail/python-list/2002-April/141189.html +# So here come craziest hack ever, since I cannot control the output of swig, +# I need to fake a Python.h file only for MSVC compilers...insane ! +if(MSVC) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Python.h.in + ${CMAKE_CURRENT_BINARY_DIR}/Python.h @ONLY + ) + include_directories( ${CMAKE_CURRENT_BINARY_DIR} ) +else() +# just plain including pyconfig.h is working...until one crazy python dev decide otherwise... + include_directories( + ${PYTHON_INCLUDE_PATH} + ) +endif() +set_source_files_properties(gdcmswig.i PROPERTIES CPLUSPLUS ON) + +set(GDCM_PYTHON_IMPLEMENTATION_NAME gdcmswig) +set(MODULE_NAME gdcmswig) +# BUG: DO NOT USE -interface flag it is NOT supported in cmake and in cmake > 2.6 will cause infinite rebuild +# Ref: http://www.cmake.org/pipermail/cmake/2008-August/023237.html +# UseSWIG and -interface flag (was: Re: CMake 2.6.1 available for download) +if(${PYTHON_VERSION_MAJOR} EQUAL 3) + # http://swig.org/Doc2.0/SWIGDocumentation.html#Python_python3support + set(CMAKE_SWIG_FLAGS "-py3") +endif() +# TODO: PythonInterp and PythonLibs are not working together well +# see: http://bugs.debian.org/677598 +#message(${PYTHONLIBS_VERSION_STRING}) +#message(${PYTHON_VERSION_MAJOR}) +#separate_arguments(CMAKE_SWIG_FLAGS) + +# While trying to get rid of the compilation warning in swig generated c++ code, I thought I could +# simply do the following: +#set(CMAKE_CXX_FLAGS "") +# well no, you cannot, it get rid of some important flags, and make the _gdcm.so incompatible with +# the other gdcm lib. bad !!! +#set (SWIG_MODULE_${MODULE_NAME}_EXTRA_DEPS ${SWIG_MODULE_${MODULE_NAME}_EXTRA_DEPS} ${CMAKE_CURRENT_SOURCE_DIR}/docstrings.i) +SWIG_ADD_MODULE(${GDCM_PYTHON_IMPLEMENTATION_NAME} python gdcmswig.i gdcmPythonFilter.cxx) +SWIG_LINK_LIBRARIES(${GDCM_PYTHON_IMPLEMENTATION_NAME} gdcmMEXD gdcmMSFF gdcmIOD) +# Apparently on my UNIX, python module (/usr/lib/pyshared/pythonX.Y/*/*.so) do not explicitely +# link to python libraries...Leave default to always link to python libraries since +# this is required at least on Apple & Win32, but leave the option to advanced user to explicitely +# refuse linking to python libs (set GDCM_NO_PYTHON_LIBS_LINKING to ON): +if(NOT GDCM_NO_PYTHON_LIBS_LINKING) + SWIG_LINK_LIBRARIES(${GDCM_PYTHON_IMPLEMENTATION_NAME} ${PYTHON_LIBRARY}) +endif() +set_property(TARGET ${SWIG_MODULE_${GDCM_PYTHON_IMPLEMENTATION_NAME}_REAL_NAME} PROPERTY NO_SONAME 1) + +# Python extension modules on Windows must have the extension ".pyd" +# instead of ".dll" as of Python 2.5. Older python versions do support +# this suffix. +# http://docs.python.org/whatsnew/ports.html#SECTION0001510000000000000000 +# +# Windows: .dll is no longer supported as a filename extension for extension modules. +# .pyd is now the only filename extension that will be searched for. +# +if(WIN32 AND NOT CYGWIN) + set_target_properties(${SWIG_MODULE_${GDCM_PYTHON_IMPLEMENTATION_NAME}_REAL_NAME} PROPERTIES SUFFIX ".pyd") + # shared libs on windows needs to be fully resolved + SWIG_LINK_LIBRARIES(${GDCM_PYTHON_IMPLEMENTATION_NAME} ${PYTHON_LIBRARIES}) +endif() +set_target_properties(${SWIG_MODULE_${GDCM_PYTHON_IMPLEMENTATION_NAME}_REAL_NAME} PROPERTIES LINK_INTERFACE_LIBRARIES "") + +# swig generates a _gdcm.so and a gdcm.py, we need to copy gdcm.py to the proper place: +# gdcm.py is the interface name != implementation name, so we need to keep 'gdcm', so that 'import gdcm' +# from a python script always work +add_custom_command( + TARGET ${SWIG_MODULE_${GDCM_PYTHON_IMPLEMENTATION_NAME}_REAL_NAME} + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/gdcmswig.py ${LIBRARY_OUTPUT_PATH}/${CMAKE_CFG_INTDIR} + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/gdcm.py ${LIBRARY_OUTPUT_PATH}/${CMAKE_CFG_INTDIR} + DEPENDS ${swig_generated_file_fullname} ${CMAKE_CURRENT_BINARY_DIR}/gdcmswig.py ${CMAKE_CURRENT_SOURCE_DIR}/gdcm.py + COMMENT "Copy gdcmswig.py into ${LIBRARY_OUTPUT_PATH}" +) + +#Module are always place in the library destination +#but for poor win32 user I decided to place them +# right next to the other dlls +if(NOT GDCM_INSTALL_NO_LIBRARIES) + install_swig_module(${GDCM_PYTHON_IMPLEMENTATION_NAME} Python) + # the python file is not a dev file, but part of the gdcm module... + install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/gdcmswig.py + ${CMAKE_CURRENT_SOURCE_DIR}/gdcm.py + DESTINATION ${GDCM_INSTALL_PYTHONMODULE_DIR} COMPONENT PythonModule + ) +endif() + +# Test that will try to load any class in the target language: python +# it make sure swig was not broken accidentally +if(BUILD_TESTING) + ADD_PYTHON_TEST(TestWrapPython TestWrap.py ${GDCM_SOURCE_DIR}/Source) + if(GDCM_DOCUMENTATION) + ADD_PYTHON_TEST(TestDoxy2SWIGPython doxy2swig.py ${GDCM_BINARY_DIR}/Utilities/doxygen/xml/index.xml ${GDCM_BINARY_DIR}/generated_docstrings.i) + endif() +endif() + +# TODO +# python -c "from distutils import sysconfig; print sysconfig.get_python_lib()" +# /usr/lib/python2.4/site-packages diff --git a/gdcm/Wrapping/Python/Python.h.in b/gdcm/Wrapping/Python/Python.h.in new file mode 100644 index 0000000..e083115 --- /dev/null +++ b/gdcm/Wrapping/Python/Python.h.in @@ -0,0 +1,53 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMPYTHON_H +#define GDCMPYTHON_H + +/* The following file was 'inspired by vtkPython.h only push to the next limit + * rename it to Python.h since we do not control swig generated file + * and have the hand generated file use full path to include Python.h +*/ +/* Undefine macros that Python.h defines to avoid redefinition warning. */ +#undef _POSIX_C_SOURCE +#undef _POSIX_THREADS + +#include "gdcmType.h" + +/* + Use the real python debugging library if it is provided. + Otherwise use the "documented" trick involving checking for _DEBUG + and undefined that symbol while we include Python headers. + Update: this method does not fool Microsoft Visual C++ 8 anymore; two + of its header files (crtdefs.h and use_ansi.h) check if _DEBUG was set + or not, and set flags accordingly (_CRT_MANIFEST_RETAIL, + _CRT_MANIFEST_DEBUG, _CRT_MANIFEST_INCONSISTENT). The next time the + check is performed in the same compilation unit, and the flags are found, + and error is triggered. Let's prevent that by setting _CRT_NOFORCE_MANIFEST. +*/ +#if defined(GDCM_WINDOWS_PYTHON_DEBUGGABLE) +# include "@PYTHON_INCLUDE_PATH@/Python.h" +#else +# ifdef _DEBUG +# undef _DEBUG +# if defined(_MSC_VER) && _MSC_VER >= 1400 +# define _CRT_NOFORCE_MANIFEST 1 +# endif +# include "@PYTHON_INCLUDE_PATH@/Python.h" +# define _DEBUG +# else +# include "@PYTHON_INCLUDE_PATH@/Python.h" +# endif +#endif + +#endif diff --git a/gdcm/Wrapping/Python/TestWrap.py b/gdcm/Wrapping/Python/TestWrap.py new file mode 100644 index 0000000..a77bf0a --- /dev/null +++ b/gdcm/Wrapping/Python/TestWrap.py @@ -0,0 +1,216 @@ +#!/usr/bin/env python +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +# Loop over all .h file, extract the name since by convention this is the name +# of the class, and then try to load that name in the python shell + +import sys,os,stat +import gdcm + +blacklist = ( +"_j2k" # :) +"_jp2" # :) +"treamimpl" # :) +"TestDriver" +# DataStructureAndEncodingDefinition +"ByteBuffer" # WTF ? +"ExplicitDataElement" +"CP246ExplicitDataElement" +"ImplicitDataElement" +"Element" +"ValueIO" +"ParseException" +"ByteSwapFilter" +"ExplicitImplicitDataElement" +"UNExplicitDataElement" +"UNExplicitImplicitDataElement" +"Attribute" +"VR16ExplicitDataElement" +"LO" # issue with swig +"String" +"CodeString" +"Parser" +"TagToVR" + +# DataDict: +"TagToType" +"GroupDict" +"DictConverter" +# Information thingy : +"MacroEntry" +"XMLDictReader" +"TableReader" +"Table" +"XMLPrivateDictReader" +# Common +"LegacyMacro" +"Swapper" +"SmartPointer" +"Win32" +"StaticAssert" +"DeflateStream" +"Types" +"Exception" +"ByteSwap" +"Terminal" +"CryptoFactory" +"CAPICryptoFactory" +"CAPICryptographicMessageSyntax" +"FileNameEvent" +"OpenSSLCryptoFactory" +"OpenSSLCryptographicMessageSyntax" +"OpenSSLP7CryptoFactory" +"OpenSSLP7CryptographicMessageSyntax" +# MediaStorageAndFileFormat +"TagKeywords" +"ConstCharWrapper" +"ImageConverter" +"SerieHelper" +# Do not expose low level jpeg implementation detail +"JPEG8Codec" +"JPEG12Codec" +"JPEG16Codec" +"JPEG2000Codec" +# segment +"Segment" +"SegmentHelper" +"SegmentReader" +"SegmentWriter" +#mesh +"MeshPrimitive" +# surface +"Surface" +"SurfaceHelper" +"SurfaceReader" +"SurfaceWriter" +# For now remove the codec part: +"ImageCodec" +"DeltaEncodingCodec" +"RLECodec" +"RAWCodec" +"AudioCodec" +"EncapsulatedDocument" +"JPEGCodec" +"PVRGCodec" +"KAKADUCodec" +"JPEGLSCodec" +"PNMCodec" +"PGXCodec" +"PDFCodec" +"Decoder" +"Coder" +"ImageChangePhotometricInterpretation" +"IconImage" # FIXME +"StreamImageReader" +"StreamImageWriter" +"IconImageFilter" +"IconImageGenerator" +"DirectoryHelper" +"DataEvent" +"DataSetEvent" +# MEXD +"ApplicationContext" +"AAssociateRJPDU" +"AAssociateACPDU" +"ULBasicCallback" +"ULActionDT" +"ULActionAA" +"QueryPatient" +"ULActionAE" +"ImplementationVersionNameSub" +"NetworkStateID" +"AReleaseRQPDU" +"MoveStudyRootQuery" +"ULConnectionCallback" +"NetworkEvents" +"QueryImage" +"ULEvent" +"PresentationContextRQ" +"PDataTFPDU" +"PresentationContextAC" +"DIMSE" +"PresentationContextGenerator" +"AAssociateRQPDU" +"ImplementationUIDSub" +"ULConnection" +"PresentationContext" +"QueryStudy" +"MovePatientRootQuery" +"CEchoMessages" +"QueryFactory" +"ULConnectionManager" +"ULConnectionInfo" +"MaximumLengthSub" +"TransferSyntaxSub" +"ARTIMTimer" +"AbstractSyntax" +"CFindMessages" +"AsynchronousOperationsWindowSub" +"ImplementationClassUIDSub" +"UserInformation" +"CMoveMessages" +"PDUFactory" +"CStoreMessages" +"FindStudyRootQuery" +"AAbortPDU" +"BaseCompositeMessage" +"ULActionAR" +"AReleaseRPPDU" +"ULTransitionTable" +"PresentationDataValue" +"BasePDU" +"QuerySeries" +"ULAction" +"ULWritingCallback" +"CompositeMessageFactory" +"CommandDataSet" +"RoleSelectionSub" +"SOPClassExtendedNegociationSub" +"FindPatientRootQuery" +"ServiceClassApplicationInformation" +) + +def processonedir(dirname): + gdcmclasses = dir(gdcm) + subtotal = 0 + for file in os.listdir(dirname): + #print file[-2:] + if file[-2:] != '.h': continue + #print file[4:-2] + gdcmclass = file[4:-2] + if gdcmclass in gdcmclasses: + print("ok:", gdcmclass) + else: + if not gdcmclass in blacklist: + print("not wrapped:",gdcmclass) + subtotal += 1 + return subtotal + +if __name__ == "__main__": + dirname = os.sys.argv[1] + + total = 0 + for d in os.listdir(dirname): + if d == '.svn': continue + pathname = os.path.join(dirname, d) + #print "pathname:",pathname + #print os.stat(pathname) + mode = os.stat(pathname)[stat.ST_MODE] + if stat.S_ISDIR(mode): + print("processing directory:", pathname) + total += processonedir(pathname) + + print("number of class not wrap:%d"%total) + sys.exit(total) diff --git a/gdcm/Wrapping/Python/docstrings.i b/gdcm/Wrapping/Python/docstrings.i new file mode 100644 index 0000000..caf81b9 --- /dev/null +++ b/gdcm/Wrapping/Python/docstrings.i @@ -0,0 +1,15050 @@ + +// File: index.xml + +// File: classgdcm_1_1network_1_1AAbortPDU.xml +%feature("docstring") gdcm::network::AAbortPDU " + +AAbortPDU Table 9-26 A-ABORT PDU FIELDS. + +C++ includes: gdcmAAbortPDU.h "; + +%feature("docstring") gdcm::network::AAbortPDU::AAbortPDU "gdcm::network::AAbortPDU::AAbortPDU() "; + +%feature("docstring") gdcm::network::AAbortPDU::IsLastFragment "bool +gdcm::network::AAbortPDU::IsLastFragment() const "; + +%feature("docstring") gdcm::network::AAbortPDU::Print "void +gdcm::network::AAbortPDU::Print(std::ostream &os) const "; + +%feature("docstring") gdcm::network::AAbortPDU::Read "std::istream& +gdcm::network::AAbortPDU::Read(std::istream &is) "; + +%feature("docstring") gdcm::network::AAbortPDU::Size "size_t +gdcm::network::AAbortPDU::Size() const "; + +%feature("docstring") gdcm::network::AAbortPDU::Write "const +std::ostream& gdcm::network::AAbortPDU::Write(std::ostream &os) const +"; + + +// File: classgdcm_1_1network_1_1AAssociateACPDU.xml +%feature("docstring") gdcm::network::AAssociateACPDU " + +AAssociateACPDU Table 9-17 ASSOCIATE-AC PDU fields. + +C++ includes: gdcmAAssociateACPDU.h "; + +%feature("docstring") gdcm::network::AAssociateACPDU::AAssociateACPDU +"gdcm::network::AAssociateACPDU::AAssociateACPDU() "; + +%feature("docstring") +gdcm::network::AAssociateACPDU::AddPresentationContextAC "void +gdcm::network::AAssociateACPDU::AddPresentationContextAC(PresentationContextAC +const &pcac) "; + +%feature("docstring") +gdcm::network::AAssociateACPDU::GetNumberOfPresentationContextAC "SizeType +gdcm::network::AAssociateACPDU::GetNumberOfPresentationContextAC() +const "; + +%feature("docstring") +gdcm::network::AAssociateACPDU::GetPresentationContextAC "const +PresentationContextAC& +gdcm::network::AAssociateACPDU::GetPresentationContextAC(SizeType i) +"; + +%feature("docstring") +gdcm::network::AAssociateACPDU::GetUserInformation "const +UserInformation& gdcm::network::AAssociateACPDU::GetUserInformation() +const "; + +%feature("docstring") gdcm::network::AAssociateACPDU::InitFromRQ "void gdcm::network::AAssociateACPDU::InitFromRQ(AAssociateRQPDU const +&rqpdu) "; + +%feature("docstring") gdcm::network::AAssociateACPDU::IsLastFragment +"bool gdcm::network::AAssociateACPDU::IsLastFragment() const "; + +%feature("docstring") gdcm::network::AAssociateACPDU::Print "void +gdcm::network::AAssociateACPDU::Print(std::ostream &os) const "; + +%feature("docstring") gdcm::network::AAssociateACPDU::Read "std::istream& gdcm::network::AAssociateACPDU::Read(std::istream &is) +"; + +%feature("docstring") gdcm::network::AAssociateACPDU::Size "SizeType +gdcm::network::AAssociateACPDU::Size() const "; + +%feature("docstring") gdcm::network::AAssociateACPDU::Write "const +std::ostream& gdcm::network::AAssociateACPDU::Write(std::ostream &os) +const "; + + +// File: classgdcm_1_1network_1_1AAssociateRJPDU.xml +%feature("docstring") gdcm::network::AAssociateRJPDU " + +AAssociateRJPDU Table 9-21 ASSOCIATE-RJ PDU FIELDS. + +C++ includes: gdcmAAssociateRJPDU.h "; + +%feature("docstring") gdcm::network::AAssociateRJPDU::AAssociateRJPDU +"gdcm::network::AAssociateRJPDU::AAssociateRJPDU() "; + +%feature("docstring") gdcm::network::AAssociateRJPDU::IsLastFragment +"bool gdcm::network::AAssociateRJPDU::IsLastFragment() const "; + +%feature("docstring") gdcm::network::AAssociateRJPDU::Print "void +gdcm::network::AAssociateRJPDU::Print(std::ostream &os) const "; + +%feature("docstring") gdcm::network::AAssociateRJPDU::Read "std::istream& gdcm::network::AAssociateRJPDU::Read(std::istream &is) +"; + +%feature("docstring") gdcm::network::AAssociateRJPDU::Size "size_t +gdcm::network::AAssociateRJPDU::Size() const "; + +%feature("docstring") gdcm::network::AAssociateRJPDU::Write "const +std::ostream& gdcm::network::AAssociateRJPDU::Write(std::ostream &os) +const "; + + +// File: classgdcm_1_1network_1_1AAssociateRQPDU.xml +%feature("docstring") gdcm::network::AAssociateRQPDU " + +AAssociateRQPDU Table 9-11 ASSOCIATE-RQ PDU fields. + +C++ includes: gdcmAAssociateRQPDU.h "; + +%feature("docstring") gdcm::network::AAssociateRQPDU::AAssociateRQPDU +"gdcm::network::AAssociateRQPDU::AAssociateRQPDU() "; + +%feature("docstring") gdcm::network::AAssociateRQPDU::AAssociateRQPDU +"gdcm::network::AAssociateRQPDU::AAssociateRQPDU(const +AAssociateRQPDU &pdu) "; + +%feature("docstring") +gdcm::network::AAssociateRQPDU::AddPresentationContext "void +gdcm::network::AAssociateRQPDU::AddPresentationContext(PresentationContextRQ +const &pc) "; + +%feature("docstring") +gdcm::network::AAssociateRQPDU::GetCalledAETitle "std::string +gdcm::network::AAssociateRQPDU::GetCalledAETitle() const "; + +%feature("docstring") +gdcm::network::AAssociateRQPDU::GetCallingAETitle "std::string +gdcm::network::AAssociateRQPDU::GetCallingAETitle() const "; + +%feature("docstring") +gdcm::network::AAssociateRQPDU::GetNumberOfPresentationContext "SizeType +gdcm::network::AAssociateRQPDU::GetNumberOfPresentationContext() const +"; + +%feature("docstring") +gdcm::network::AAssociateRQPDU::GetPresentationContext "PresentationContextRQ const& +gdcm::network::AAssociateRQPDU::GetPresentationContext(SizeType i) +const "; + +%feature("docstring") +gdcm::network::AAssociateRQPDU::GetPresentationContextByAbstractSyntax +"const PresentationContextRQ* +gdcm::network::AAssociateRQPDU::GetPresentationContextByAbstractSyntax(AbstractSyntax +const &as) const "; + +%feature("docstring") +gdcm::network::AAssociateRQPDU::GetPresentationContextByID "const +PresentationContextRQ* +gdcm::network::AAssociateRQPDU::GetPresentationContextByID(uint8_t i) +const "; + +%feature("docstring") +gdcm::network::AAssociateRQPDU::GetPresentationContexts "PresentationContextArrayType const& +gdcm::network::AAssociateRQPDU::GetPresentationContexts() "; + +%feature("docstring") gdcm::network::AAssociateRQPDU::IsLastFragment +"bool gdcm::network::AAssociateRQPDU::IsLastFragment() const "; + +%feature("docstring") gdcm::network::AAssociateRQPDU::Print "void +gdcm::network::AAssociateRQPDU::Print(std::ostream &os) const + +This function will initialize an AAssociateACPDU from the fields in +the AAssociateRQPDU structure "; + +%feature("docstring") gdcm::network::AAssociateRQPDU::Read "std::istream& gdcm::network::AAssociateRQPDU::Read(std::istream &is) +"; + +%feature("docstring") +gdcm::network::AAssociateRQPDU::SetCalledAETitle "void +gdcm::network::AAssociateRQPDU::SetCalledAETitle(const char +calledaetitle[16]) + +Set the Called AE Title. "; + +%feature("docstring") +gdcm::network::AAssociateRQPDU::SetCallingAETitle "void +gdcm::network::AAssociateRQPDU::SetCallingAETitle(const char +callingaetitle[16]) + +Set the Calling AE Title. "; + +%feature("docstring") gdcm::network::AAssociateRQPDU::Size "size_t +gdcm::network::AAssociateRQPDU::Size() const "; + +%feature("docstring") gdcm::network::AAssociateRQPDU::Write "const +std::ostream& gdcm::network::AAssociateRQPDU::Write(std::ostream &os) +const "; + + +// File: classgdcm_1_1AbortEvent.xml +%feature("docstring") gdcm::AbortEvent "C++ includes: gdcmEvent.h "; + + +// File: classgdcm_1_1network_1_1AbstractSyntax.xml +%feature("docstring") gdcm::network::AbstractSyntax " + +AbstractSyntax Table 9-14 ABSTRACT SYNTAX SUB-ITEM FIELDS. + +C++ includes: gdcmAbstractSyntax.h "; + +%feature("docstring") gdcm::network::AbstractSyntax::AbstractSyntax "gdcm::network::AbstractSyntax::AbstractSyntax() "; + +%feature("docstring") gdcm::network::AbstractSyntax::GetAsDataElement +"DataElement gdcm::network::AbstractSyntax::GetAsDataElement() const +"; + +%feature("docstring") gdcm::network::AbstractSyntax::GetName "const +char* gdcm::network::AbstractSyntax::GetName() const "; + +%feature("docstring") gdcm::network::AbstractSyntax::Print "void +gdcm::network::AbstractSyntax::Print(std::ostream &os) const "; + +%feature("docstring") gdcm::network::AbstractSyntax::Read "std::istream& gdcm::network::AbstractSyntax::Read(std::istream &is) "; + +%feature("docstring") gdcm::network::AbstractSyntax::SetName "void +gdcm::network::AbstractSyntax::SetName(const char *name) "; + +%feature("docstring") gdcm::network::AbstractSyntax::SetNameFromUID "void gdcm::network::AbstractSyntax::SetNameFromUID(UIDs::TSName +tsname) "; + +%feature("docstring") gdcm::network::AbstractSyntax::Size "size_t +gdcm::network::AbstractSyntax::Size() const "; + +%feature("docstring") gdcm::network::AbstractSyntax::Write "const +std::ostream& gdcm::network::AbstractSyntax::Write(std::ostream &os) +const "; + + +// File: classstd_1_1allocator.xml +%feature("docstring") std::allocator " + +STL class. "; + + +// File: classgdcm_1_1AnonymizeEvent.xml +%feature("docstring") gdcm::AnonymizeEvent " + +AnonymizeEvent Special type of event triggered during the +Anonymization process. + +See: Anonymizer + +C++ includes: gdcmAnonymizeEvent.h "; + +%feature("docstring") gdcm::AnonymizeEvent::AnonymizeEvent "gdcm::AnonymizeEvent::AnonymizeEvent(Tag const &tag=0) "; + +%feature("docstring") gdcm::AnonymizeEvent::AnonymizeEvent "gdcm::AnonymizeEvent::AnonymizeEvent(const Self &s) "; + +%feature("docstring") gdcm::AnonymizeEvent::~AnonymizeEvent "virtual +gdcm::AnonymizeEvent::~AnonymizeEvent() "; + +%feature("docstring") gdcm::AnonymizeEvent::CheckEvent "virtual bool +gdcm::AnonymizeEvent::CheckEvent(const ::gdcm::Event *e) const "; + +%feature("docstring") gdcm::AnonymizeEvent::GetEventName "virtual +const char* gdcm::AnonymizeEvent::GetEventName() const + +Return the StringName associated with the event. "; + +%feature("docstring") gdcm::AnonymizeEvent::GetTag "Tag const& +gdcm::AnonymizeEvent::GetTag() const "; + +%feature("docstring") gdcm::AnonymizeEvent::MakeObject "virtual +::gdcm::Event* gdcm::AnonymizeEvent::MakeObject() const + +Create an Event of this type This method work as a Factory for +creating events of each particular type. "; + +%feature("docstring") gdcm::AnonymizeEvent::SetTag "void +gdcm::AnonymizeEvent::SetTag(const Tag &t) "; + + +// File: classgdcm_1_1Anonymizer.xml +%feature("docstring") gdcm::Anonymizer " + +Anonymizer This class is a multi purpose anonymizer. It can work in 2 +mode: Full (irreversible) anonymizer (aka dumb mode) + +reversible de-identifier/re-identifier (aka smart mode). This +implements the Basic Application Level Confidentiality Profile, DICOM +PS 3.15-2009. + +1. dumb mode This is a dumb anonymizer implementation. All it allows +user is simple operation such as: + +Tag based functions: complete removal of DICOM attribute (Remove) + +make a tag empty, ie make it's length 0 (Empty) + +replace with another string-based value (Replace) + +DataSet based functions: Remove all group length attribute from a +DICOM dataset (Group Length element are deprecated, DICOM 2008) + +Remove all private attributes + +Remove all retired attributes + +All function calls actually execute the user specified request. +Previous implementation were calling a general Anonymize function but +traversing a std::set is O(n) operation, while a simple user specified +request is O(log(n)) operation. So 'm' user interaction is O(m*log(n)) +which is < O(n) complexity. + +2. smart mode this mode implements the Basic Application Level +Confidentiality Profile (DICOM PS 3.15-2008) In this case, it is +extremely important to use the same gdcm::Anonymizer class when +anonymizing a FileSet. Once the gdcm::Anonymizer is destroyed its +memory of known (already processed) UIDs will be lost. which will make +the anonymizer behaves incorrectly for attributes such as Series UID +Study UID where user want some consistency. When attribute is Type 1 / +Type 1C, a dummy generator will take in the existing value and produce +a dummy value (a sha1 representation). sha1 algorithm is considered to +be cryptographically strong (compared to md5sum) so that we meet the +following two conditions: Produce the same dummy value for the same +input value + +do not provide an easy way to retrieve the original value from the +sha1 generated value + +This class implement the Subject/Observer pattern trigger the +following event: AnonymizeEvent + +IterationEvent + +StartEvent + +EndEvent + +See: CryptographicMessageSyntax + +C++ includes: gdcmAnonymizer.h "; + +%feature("docstring") gdcm::Anonymizer::Anonymizer "gdcm::Anonymizer::Anonymizer() "; + +%feature("docstring") gdcm::Anonymizer::~Anonymizer "gdcm::Anonymizer::~Anonymizer() "; + +%feature("docstring") +gdcm::Anonymizer::BasicApplicationLevelConfidentialityProfile "bool +gdcm::Anonymizer::BasicApplicationLevelConfidentialityProfile(bool +deidentify=true) + +PS 3.15 / E.1.1 De-Identifier An Application may claim conformance to +the Basic Application Level Confidentiality Profile as a deidentifier +if it protects all Attributes that might be used by unauthorized +entities to identify the patient. NOT THREAD SAFE "; + +%feature("docstring") gdcm::Anonymizer::Empty "bool +gdcm::Anonymizer::Empty(Tag const &t) + +Make Tag t empty (if not found tag will be created) Warning: does not +handle SQ element "; + +%feature("docstring") gdcm::Anonymizer::GetCryptographicMessageSyntax +"const CryptographicMessageSyntax* +gdcm::Anonymizer::GetCryptographicMessageSyntax() const "; + +%feature("docstring") gdcm::Anonymizer::GetFile "File& +gdcm::Anonymizer::GetFile() "; + +%feature("docstring") gdcm::Anonymizer::Remove "bool +gdcm::Anonymizer::Remove(Tag const &t) + +remove a tag (even a SQ can be removed) Return code is false when tag +t cannot be found "; + +%feature("docstring") gdcm::Anonymizer::RemoveGroupLength "bool +gdcm::Anonymizer::RemoveGroupLength() + +Main function that loop over all elements and remove group length. "; + +%feature("docstring") gdcm::Anonymizer::RemovePrivateTags "bool +gdcm::Anonymizer::RemovePrivateTags() + +Main function that loop over all elements and remove private tags. "; + +%feature("docstring") gdcm::Anonymizer::RemoveRetired "bool +gdcm::Anonymizer::RemoveRetired() + +Main function that loop over all elements and remove retired element. +"; + +%feature("docstring") gdcm::Anonymizer::Replace "bool +gdcm::Anonymizer::Replace(Tag const &t, const char *value, VL const +&vl) + +when the value contains , it is a good idea to specify the length. +This function is required when dealing with VRBINARY tag "; + +%feature("docstring") gdcm::Anonymizer::Replace "bool +gdcm::Anonymizer::Replace(Tag const &t, const char *value) + +Replace tag with another value, if tag is not found it will be +created: WARNING: this function can only execute if tag is a VRASCII +"; + +%feature("docstring") gdcm::Anonymizer::SetCryptographicMessageSyntax +"void +gdcm::Anonymizer::SetCryptographicMessageSyntax(CryptographicMessageSyntax +*cms) + +Set/Get CMS key that will be used to encrypt the dataset within +BasicApplicationLevelConfidentialityProfile. "; + +%feature("docstring") gdcm::Anonymizer::SetFile "void +gdcm::Anonymizer::SetFile(const File &f) + +Set/Get File. "; + + +// File: classgdcm_1_1AnyEvent.xml +%feature("docstring") gdcm::AnyEvent "C++ includes: gdcmEvent.h "; + + +// File: classgdcm_1_1network_1_1ApplicationContext.xml +%feature("docstring") gdcm::network::ApplicationContext " + +ApplicationContext Table 9-12 APPLICATION CONTEXT ITEM FIELDS Looks +like Application Context can only be 64 bytes at max (see Figure 9-1 / +PS 3.8 - 2009 ). + +C++ includes: gdcmApplicationContext.h "; + +%feature("docstring") +gdcm::network::ApplicationContext::ApplicationContext "gdcm::network::ApplicationContext::ApplicationContext() "; + +%feature("docstring") gdcm::network::ApplicationContext::GetName "const char* gdcm::network::ApplicationContext::GetName() const "; + +%feature("docstring") gdcm::network::ApplicationContext::Print "void +gdcm::network::ApplicationContext::Print(std::ostream &os) const "; + +%feature("docstring") gdcm::network::ApplicationContext::Read "std::istream& gdcm::network::ApplicationContext::Read(std::istream +&is) "; + +%feature("docstring") gdcm::network::ApplicationContext::SetName "void gdcm::network::ApplicationContext::SetName(const char *name) "; + +%feature("docstring") gdcm::network::ApplicationContext::Size "size_t gdcm::network::ApplicationContext::Size() const "; + +%feature("docstring") gdcm::network::ApplicationContext::Write "const std::ostream& +gdcm::network::ApplicationContext::Write(std::ostream &os) const "; + + +// File: classgdcm_1_1ApplicationEntity.xml +%feature("docstring") gdcm::ApplicationEntity " + +ApplicationEntity AE Application Entity + +A string of characters that identifies an Application Entity with +leading and trailing spaces (20H) being non-significant. A value +consisting solely of spaces shall not be used. + +Default Character Repertoire excluding character code 5CH (the +BACKSLASH \\\\ in ISO-IR 6), and control characters LF, FF, CR and +ESC. + +16 bytes maximum. + +C++ includes: gdcmApplicationEntity.h "; + +%feature("docstring") gdcm::ApplicationEntity::IsValid "bool +gdcm::ApplicationEntity::IsValid() const "; + +%feature("docstring") gdcm::ApplicationEntity::Print "void +gdcm::ApplicationEntity::Print(std::ostream &os) const "; + +%feature("docstring") gdcm::ApplicationEntity::SetBlob "void +gdcm::ApplicationEntity::SetBlob(const std::vector< char > &v) "; + +%feature("docstring") gdcm::ApplicationEntity::Squeeze "void +gdcm::ApplicationEntity::Squeeze() "; + + +// File: classgdcm_1_1network_1_1AReleaseRPPDU.xml +%feature("docstring") gdcm::network::AReleaseRPPDU " + +AReleaseRPPDU Table 9-25 A-RELEASE-RP PDU fields. + +C++ includes: gdcmAReleaseRPPDU.h "; + +%feature("docstring") gdcm::network::AReleaseRPPDU::AReleaseRPPDU "gdcm::network::AReleaseRPPDU::AReleaseRPPDU() "; + +%feature("docstring") gdcm::network::AReleaseRPPDU::IsLastFragment "bool gdcm::network::AReleaseRPPDU::IsLastFragment() const "; + +%feature("docstring") gdcm::network::AReleaseRPPDU::Print "void +gdcm::network::AReleaseRPPDU::Print(std::ostream &os) const "; + +%feature("docstring") gdcm::network::AReleaseRPPDU::Read "std::istream& gdcm::network::AReleaseRPPDU::Read(std::istream &is) "; + +%feature("docstring") gdcm::network::AReleaseRPPDU::Size "size_t +gdcm::network::AReleaseRPPDU::Size() const "; + +%feature("docstring") gdcm::network::AReleaseRPPDU::Write "const +std::ostream& gdcm::network::AReleaseRPPDU::Write(std::ostream &os) +const "; + + +// File: classgdcm_1_1network_1_1AReleaseRQPDU.xml +%feature("docstring") gdcm::network::AReleaseRQPDU " + +AReleaseRQPDU Table 9-24 A-RELEASE-RQ PDU FIELDS. + +C++ includes: gdcmAReleaseRQPDU.h "; + +%feature("docstring") gdcm::network::AReleaseRQPDU::AReleaseRQPDU "gdcm::network::AReleaseRQPDU::AReleaseRQPDU() "; + +%feature("docstring") gdcm::network::AReleaseRQPDU::IsLastFragment "bool gdcm::network::AReleaseRQPDU::IsLastFragment() const "; + +%feature("docstring") gdcm::network::AReleaseRQPDU::Print "void +gdcm::network::AReleaseRQPDU::Print(std::ostream &os) const "; + +%feature("docstring") gdcm::network::AReleaseRQPDU::Read "std::istream& gdcm::network::AReleaseRQPDU::Read(std::istream &is) "; + +%feature("docstring") gdcm::network::AReleaseRQPDU::Size "size_t +gdcm::network::AReleaseRQPDU::Size() const "; + +%feature("docstring") gdcm::network::AReleaseRQPDU::Write "const +std::ostream& gdcm::network::AReleaseRQPDU::Write(std::ostream &os) +const "; + + +// File: classgdcm_1_1network_1_1ARTIMTimer.xml +%feature("docstring") gdcm::network::ARTIMTimer " + +ARTIMTimer This file contains the code for the ARTIM timer. + +Basically, the ARTIM timer will just get the wall time when it's +started, and then can be queried for the current time, and then can be +stopped (ie, the start time reset). + +Because we're trying to do this without threading, we should be able +to 'start' the ARTIM timer by this mechanism, and then when waiting +for a particular response, tight loop that with sleep calls and +determinations of when the ARTIM timer has reached its peak. As such, +this isn't a strict 'timer' in the traditional sense of the word, but +more of a time keeper. + +There can be only one ARTIM timer per connection. + +C++ includes: gdcmARTIMTimer.h "; + +%feature("docstring") gdcm::network::ARTIMTimer::ARTIMTimer "gdcm::network::ARTIMTimer::ARTIMTimer() "; + +%feature("docstring") gdcm::network::ARTIMTimer::GetElapsedTime "double gdcm::network::ARTIMTimer::GetElapsedTime() const "; + +%feature("docstring") gdcm::network::ARTIMTimer::GetHasExpired "bool +gdcm::network::ARTIMTimer::GetHasExpired() const "; + +%feature("docstring") gdcm::network::ARTIMTimer::GetTimeout "double +gdcm::network::ARTIMTimer::GetTimeout() const "; + +%feature("docstring") gdcm::network::ARTIMTimer::SetTimeout "void +gdcm::network::ARTIMTimer::SetTimeout(double inTimeout) "; + +%feature("docstring") gdcm::network::ARTIMTimer::Start "void +gdcm::network::ARTIMTimer::Start() "; + +%feature("docstring") gdcm::network::ARTIMTimer::Stop "void +gdcm::network::ARTIMTimer::Stop() "; + + +// File: classgdcm_1_1ASN1.xml +%feature("docstring") gdcm::ASN1 " + +Class for ASN1. + +C++ includes: gdcmASN1.h "; + +%feature("docstring") gdcm::ASN1::ASN1 "gdcm::ASN1::ASN1() "; + +%feature("docstring") gdcm::ASN1::~ASN1 "gdcm::ASN1::~ASN1() "; + + +// File: classgdcm_1_1network_1_1AsynchronousOperationsWindowSub.xml +%feature("docstring") gdcm::network::AsynchronousOperationsWindowSub " + +AsynchronousOperationsWindowSub PS 3.7 Table D.3-7 ASYNCHRONOUS +OPERATIONS WINDOW SUB-ITEM FIELDS (A-ASSOCIATE- RQ). + +C++ includes: gdcmAsynchronousOperationsWindowSub.h "; + +%feature("docstring") +gdcm::network::AsynchronousOperationsWindowSub::AsynchronousOperationsWindowSub +"gdcm::network::AsynchronousOperationsWindowSub::AsynchronousOperationsWindowSub() +"; + +%feature("docstring") +gdcm::network::AsynchronousOperationsWindowSub::Print "void +gdcm::network::AsynchronousOperationsWindowSub::Print(std::ostream +&os) const "; + +%feature("docstring") +gdcm::network::AsynchronousOperationsWindowSub::Read "std::istream& +gdcm::network::AsynchronousOperationsWindowSub::Read(std::istream &is) +"; + +%feature("docstring") +gdcm::network::AsynchronousOperationsWindowSub::Size "size_t +gdcm::network::AsynchronousOperationsWindowSub::Size() const "; + +%feature("docstring") +gdcm::network::AsynchronousOperationsWindowSub::Write "const +std::ostream& +gdcm::network::AsynchronousOperationsWindowSub::Write(std::ostream +&os) const "; + + +// File: classgdcm_1_1Attribute.xml +%feature("docstring") gdcm::Attribute " + +Attribute class This class use template metaprograming tricks to let +the user know when the template instanciation does not match the +public dictionary. + +Typical example that compile is: Attribute<0x0008,0x9007> a = +{\"ORIGINAL\",\"PRIMARY\",\"T1\",\"NONE\"}; + +Examples that will NOT compile are: + +Attribute<0x0018,0x1182, VR::IS, VM::VM1> fd1 = {}; // not enough +parameters Attribute<0x0018,0x1182, VR::IS, VM::VM2> fd2 = {0,1,2}; // +too many initializers Attribute<0x0018,0x1182, VR::IS, VM::VM3> fd3 = +{0,1,2}; // VM3 is not valid Attribute<0x0018,0x1182, VR::UL, VM::VM2> +fd3 = {0,1}; // UL is not valid VR + +C++ includes: gdcmAttribute.h "; + +%feature("docstring") gdcm::Attribute::GDCM_STATIC_ASSERT "gdcm::Attribute< Group, Element, TVR, TVM +>::GDCM_STATIC_ASSERT(((VR::VRType) TVR &(VR::VRType)(TagToType< +Group, Element >::VRType))) "; + +%feature("docstring") gdcm::Attribute::GDCM_STATIC_ASSERT "gdcm::Attribute< Group, Element, TVR, TVM +>::GDCM_STATIC_ASSERT(((VM::VMType) TVM &(VM::VMType)(TagToType< +Group, Element >::VMType))) "; + +%feature("docstring") gdcm::Attribute::GDCM_STATIC_ASSERT "gdcm::Attribute< Group, Element, TVR, TVM +>::GDCM_STATIC_ASSERT(((((VR::VRType) TVR &VR::VR_VM1)&&((VM::VMType) +TVM==VM::VM1))||!((VR::VRType) TVR &VR::VR_VM1))) "; + +%feature("docstring") gdcm::Attribute::GetAsDataElement "DataElement +gdcm::Attribute< Group, Element, TVR, TVM >::GetAsDataElement() const +"; + +%feature("docstring") gdcm::Attribute::GetNumberOfValues "unsigned +int gdcm::Attribute< Group, Element, TVR, TVM >::GetNumberOfValues() +const "; + +%feature("docstring") gdcm::Attribute::GetValue "ArrayType& +gdcm::Attribute< Group, Element, TVR, TVM >::GetValue(unsigned int +idx=0) "; + +%feature("docstring") gdcm::Attribute::GetValue "ArrayType const& +gdcm::Attribute< Group, Element, TVR, TVM >::GetValue(unsigned int +idx=0) const "; + +%feature("docstring") gdcm::Attribute::GetValues "const ArrayType* +gdcm::Attribute< Group, Element, TVR, TVM >::GetValues() const "; + +%feature("docstring") gdcm::Attribute::Print "void gdcm::Attribute< +Group, Element, TVR, TVM >::Print(std::ostream &os) const "; + +%feature("docstring") gdcm::Attribute::Set "void gdcm::Attribute< +Group, Element, TVR, TVM >::Set(DataSet const &ds) "; + +%feature("docstring") gdcm::Attribute::SetFromDataElement "void +gdcm::Attribute< Group, Element, TVR, TVM +>::SetFromDataElement(DataElement const &de) "; + +%feature("docstring") gdcm::Attribute::SetFromDataSet "void +gdcm::Attribute< Group, Element, TVR, TVM >::SetFromDataSet(DataSet +const &ds) "; + +%feature("docstring") gdcm::Attribute::SetValue "void +gdcm::Attribute< Group, Element, TVR, TVM >::SetValue(ArrayType v, +unsigned int idx=0) "; + +%feature("docstring") gdcm::Attribute::SetValues "void +gdcm::Attribute< Group, Element, TVR, TVM >::SetValues(const ArrayType +*array, unsigned int numel=VMType) "; + + +// File: classgdcm_1_1Attribute_3_01Group_00_01Element_00_01TVR_00_01VM_1_1VM1_01_4.xml +%feature("docstring") gdcm::Attribute< Group, Element, TVR, VM::VM1 > +" C++ includes: gdcmAttribute.h "; + +%feature("docstring") gdcm::Attribute< Group, Element, TVR, VM::VM1 +>::GDCM_STATIC_ASSERT " gdcm::Attribute< Group, Element, TVR, VM::VM1 +>::GDCM_STATIC_ASSERT(VMToLength< VM::VM1 >::Length==1) "; + +%feature("docstring") gdcm::Attribute< Group, Element, TVR, VM::VM1 +>::GDCM_STATIC_ASSERT " gdcm::Attribute< Group, Element, TVR, VM::VM1 +>::GDCM_STATIC_ASSERT(((VR::VRType) TVR &(VR::VRType)(TagToType< +Group, Element >::VRType))) "; + +%feature("docstring") gdcm::Attribute< Group, Element, TVR, VM::VM1 +>::GDCM_STATIC_ASSERT " gdcm::Attribute< Group, Element, TVR, VM::VM1 +>::GDCM_STATIC_ASSERT(((((VR::VRType) TVR &VR::VR_VM1)&&((VM::VMType) +VM::VM1==VM::VM1))||!((VR::VRType) TVR &VR::VR_VM1))) "; + +%feature("docstring") gdcm::Attribute< Group, Element, TVR, VM::VM1 +>::GDCM_STATIC_ASSERT " gdcm::Attribute< Group, Element, TVR, VM::VM1 +>::GDCM_STATIC_ASSERT(((VM::VMType) VM::VM1 &(VM::VMType)(TagToType< +Group, Element >::VMType))) "; + +%feature("docstring") gdcm::Attribute< Group, Element, TVR, VM::VM1 +>::GetAsDataElement " DataElement gdcm::Attribute< Group, Element, +TVR, VM::VM1 >::GetAsDataElement() const "; + +%feature("docstring") gdcm::Attribute< Group, Element, TVR, VM::VM1 +>::GetNumberOfValues " unsigned int gdcm::Attribute< Group, Element, +TVR, VM::VM1 >::GetNumberOfValues() const "; + +%feature("docstring") gdcm::Attribute< Group, Element, TVR, VM::VM1 +>::GetValue " ArrayType& gdcm::Attribute< Group, Element, TVR, VM::VM1 +>::GetValue() "; + +%feature("docstring") gdcm::Attribute< Group, Element, TVR, VM::VM1 +>::GetValue " ArrayType const& gdcm::Attribute< Group, Element, TVR, +VM::VM1 >::GetValue() const "; + +%feature("docstring") gdcm::Attribute< Group, Element, TVR, VM::VM1 +>::GetValues " const ArrayType* gdcm::Attribute< Group, Element, TVR, +VM::VM1 >::GetValues() const "; + +%feature("docstring") gdcm::Attribute< Group, Element, TVR, VM::VM1 +>::Print " void gdcm::Attribute< Group, Element, TVR, VM::VM1 +>::Print(std::ostream &os) const "; + +%feature("docstring") gdcm::Attribute< Group, Element, TVR, VM::VM1 +>::Set " void gdcm::Attribute< Group, Element, TVR, VM::VM1 +>::Set(DataSet const &ds) "; + +%feature("docstring") gdcm::Attribute< Group, Element, TVR, VM::VM1 +>::SetFromDataElement " void gdcm::Attribute< Group, Element, TVR, +VM::VM1 >::SetFromDataElement(DataElement const &de) "; + +%feature("docstring") gdcm::Attribute< Group, Element, TVR, VM::VM1 +>::SetFromDataSet " void gdcm::Attribute< Group, Element, TVR, VM::VM1 +>::SetFromDataSet(DataSet const &ds) "; + +%feature("docstring") gdcm::Attribute< Group, Element, TVR, VM::VM1 +>::SetValue " void gdcm::Attribute< Group, Element, TVR, VM::VM1 +>::SetValue(ArrayType v) "; + + +// File: classgdcm_1_1Attribute_3_01Group_00_01Element_00_01TVR_00_01VM_1_1VM1__3_01_4.xml +%feature("docstring") gdcm::Attribute< Group, Element, TVR, VM::VM1_3 +> " C++ includes: gdcmAttribute.h "; + +%feature("docstring") gdcm::Attribute< Group, Element, TVR, VM::VM1_3 +>::GetVM " VM gdcm::Attribute< Group, Element, TVR, VM::VM1_3 +>::GetVM() const "; + + +// File: classgdcm_1_1Attribute_3_01Group_00_01Element_00_01TVR_00_01VM_1_1VM1__8_01_4.xml +%feature("docstring") gdcm::Attribute< Group, Element, TVR, VM::VM1_8 +> " C++ includes: gdcmAttribute.h "; + +%feature("docstring") gdcm::Attribute< Group, Element, TVR, VM::VM1_8 +>::GetVM " VM gdcm::Attribute< Group, Element, TVR, VM::VM1_8 +>::GetVM() const "; + + +// File: classgdcm_1_1Attribute_3_01Group_00_01Element_00_01TVR_00_01VM_1_1VM1__n_01_4.xml +%feature("docstring") gdcm::Attribute< Group, Element, TVR, VM::VM1_n +> " C++ includes: gdcmAttribute.h "; + +%feature("docstring") gdcm::Attribute< Group, Element, TVR, VM::VM1_n +>::Attribute " gdcm::Attribute< Group, Element, TVR, VM::VM1_n +>::Attribute() "; + +%feature("docstring") gdcm::Attribute< Group, Element, TVR, VM::VM1_n +>::~Attribute " gdcm::Attribute< Group, Element, TVR, VM::VM1_n +>::~Attribute() "; + +%feature("docstring") gdcm::Attribute< Group, Element, TVR, VM::VM1_n +>::GDCM_STATIC_ASSERT " gdcm::Attribute< Group, Element, TVR, +VM::VM1_n >::GDCM_STATIC_ASSERT((VM::VM1_n &(VM::VMType)(TagToType< +Group, Element >::VMType))) "; + +%feature("docstring") gdcm::Attribute< Group, Element, TVR, VM::VM1_n +>::GDCM_STATIC_ASSERT " gdcm::Attribute< Group, Element, TVR, +VM::VM1_n >::GDCM_STATIC_ASSERT(((VR::VRType) TVR +&(VR::VRType)(TagToType< Group, Element >::VRType))) "; + +%feature("docstring") gdcm::Attribute< Group, Element, TVR, VM::VM1_n +>::GDCM_STATIC_ASSERT " gdcm::Attribute< Group, Element, TVR, +VM::VM1_n >::GDCM_STATIC_ASSERT(((((VR::VRType) TVR +&VR::VR_VM1)&&((VM::VMType) TagToType< Group, Element +>::VMType==VM::VM1))||!((VR::VRType) TVR &VR::VR_VM1))) "; + +%feature("docstring") gdcm::Attribute< Group, Element, TVR, VM::VM1_n +>::GetAsDataElement " DataElement gdcm::Attribute< Group, Element, +TVR, VM::VM1_n >::GetAsDataElement() const "; + +%feature("docstring") gdcm::Attribute< Group, Element, TVR, VM::VM1_n +>::GetNumberOfValues " unsigned int gdcm::Attribute< Group, Element, +TVR, VM::VM1_n >::GetNumberOfValues() const "; + +%feature("docstring") gdcm::Attribute< Group, Element, TVR, VM::VM1_n +>::GetValue " ArrayType& gdcm::Attribute< Group, Element, TVR, +VM::VM1_n >::GetValue(unsigned int idx=0) "; + +%feature("docstring") gdcm::Attribute< Group, Element, TVR, VM::VM1_n +>::GetValue " ArrayType const& gdcm::Attribute< Group, Element, TVR, +VM::VM1_n >::GetValue(unsigned int idx=0) const "; + +%feature("docstring") gdcm::Attribute< Group, Element, TVR, VM::VM1_n +>::GetValues " const ArrayType* gdcm::Attribute< Group, Element, TVR, +VM::VM1_n >::GetValues() const "; + +%feature("docstring") gdcm::Attribute< Group, Element, TVR, VM::VM1_n +>::Print " void gdcm::Attribute< Group, Element, TVR, VM::VM1_n +>::Print(std::ostream &os) const "; + +%feature("docstring") gdcm::Attribute< Group, Element, TVR, VM::VM1_n +>::Set " void gdcm::Attribute< Group, Element, TVR, VM::VM1_n +>::Set(DataSet const &ds) "; + +%feature("docstring") gdcm::Attribute< Group, Element, TVR, VM::VM1_n +>::SetFromDataElement " void gdcm::Attribute< Group, Element, TVR, +VM::VM1_n >::SetFromDataElement(DataElement const &de) "; + +%feature("docstring") gdcm::Attribute< Group, Element, TVR, VM::VM1_n +>::SetFromDataSet " void gdcm::Attribute< Group, Element, TVR, +VM::VM1_n >::SetFromDataSet(DataSet const &ds) "; + +%feature("docstring") gdcm::Attribute< Group, Element, TVR, VM::VM1_n +>::SetNumberOfValues " void gdcm::Attribute< Group, Element, TVR, +VM::VM1_n >::SetNumberOfValues(unsigned int numel) "; + +%feature("docstring") gdcm::Attribute< Group, Element, TVR, VM::VM1_n +>::SetValue " void gdcm::Attribute< Group, Element, TVR, VM::VM1_n +>::SetValue(unsigned int idx, ArrayType v) "; + +%feature("docstring") gdcm::Attribute< Group, Element, TVR, VM::VM1_n +>::SetValue " void gdcm::Attribute< Group, Element, TVR, VM::VM1_n +>::SetValue(ArrayType v) "; + +%feature("docstring") gdcm::Attribute< Group, Element, TVR, VM::VM1_n +>::SetValues " void gdcm::Attribute< Group, Element, TVR, VM::VM1_n +>::SetValues(const ArrayType *array, unsigned int numel, bool +own=false) "; + + +// File: classgdcm_1_1Attribute_3_01Group_00_01Element_00_01TVR_00_01VM_1_1VM2__2n_01_4.xml +%feature("docstring") gdcm::Attribute< Group, Element, TVR, VM::VM2_2n +> " C++ includes: gdcmAttribute.h "; + + +// File: classgdcm_1_1Attribute_3_01Group_00_01Element_00_01TVR_00_01VM_1_1VM2__n_01_4.xml +%feature("docstring") gdcm::Attribute< Group, Element, TVR, VM::VM2_n +> " C++ includes: gdcmAttribute.h "; + +%feature("docstring") gdcm::Attribute< Group, Element, TVR, VM::VM2_n +>::GetVM " VM gdcm::Attribute< Group, Element, TVR, VM::VM2_n +>::GetVM() const "; + + +// File: classgdcm_1_1Attribute_3_01Group_00_01Element_00_01TVR_00_01VM_1_1VM3__3n_01_4.xml +%feature("docstring") gdcm::Attribute< Group, Element, TVR, VM::VM3_3n +> " C++ includes: gdcmAttribute.h "; + + +// File: classgdcm_1_1Attribute_3_01Group_00_01Element_00_01TVR_00_01VM_1_1VM3__n_01_4.xml +%feature("docstring") gdcm::Attribute< Group, Element, TVR, VM::VM3_n +> " C++ includes: gdcmAttribute.h "; + + +// File: classgdcm_1_1AudioCodec.xml +%feature("docstring") gdcm::AudioCodec " + +AudioCodec. + +C++ includes: gdcmAudioCodec.h "; + +%feature("docstring") gdcm::AudioCodec::AudioCodec "gdcm::AudioCodec::AudioCodec() "; + +%feature("docstring") gdcm::AudioCodec::~AudioCodec "gdcm::AudioCodec::~AudioCodec() "; + +%feature("docstring") gdcm::AudioCodec::CanCode "bool +gdcm::AudioCodec::CanCode(TransferSyntax const &) const "; + +%feature("docstring") gdcm::AudioCodec::CanDecode "bool +gdcm::AudioCodec::CanDecode(TransferSyntax const &) const + +Return whether this decoder support this transfer syntax (can decode +it). "; + +%feature("docstring") gdcm::AudioCodec::Decode "bool +gdcm::AudioCodec::Decode(DataElement const &is, DataElement &os) + +Decode. "; + + +// File: classstd_1_1auto__ptr.xml +%feature("docstring") std::auto_ptr " + +STL class. "; + + +// File: classstd_1_1bad__alloc.xml +%feature("docstring") std::bad_alloc " + +STL class. "; + + +// File: classstd_1_1bad__cast.xml +%feature("docstring") std::bad_cast " + +STL class. "; + + +// File: classstd_1_1bad__exception.xml +%feature("docstring") std::bad_exception " + +STL class. "; + + +// File: classstd_1_1bad__typeid.xml +%feature("docstring") std::bad_typeid " + +STL class. "; + + +// File: classgdcm_1_1Base64.xml +%feature("docstring") gdcm::Base64 " + +Class for Base64. + +C++ includes: gdcmBase64.h "; + +%feature("docstring") gdcm::Base64::Base64 "gdcm::Base64::Base64() +"; + + +// File: classgdcm_1_1network_1_1BaseCompositeMessage.xml +%feature("docstring") gdcm::network::BaseCompositeMessage " + +BaseCompositeMessage The Composite events described in section +3.7-2009 of the DICOM standard all use their own messages. These +messages are constructed using Presentation Data Values, from section +3.8-2009 of the standard, and then fill in appropriate values in their +datasets. + +So, for the five composites: C-ECHO + +C-FIND + +C-MOVE + +C-GET + +C-STORE there are a series of messages. However, all of these messages +are obtained as part of a PDataPDU, and all have to be placed there. +Therefore, since they all have shared functionality and construction +tropes, that will be put into a base class. Further, the base class +will be then returned by the factory class, gdcmCompositePDUFactory. +This is an abstract class. It cannot be instantiated on its own. + +C++ includes: gdcmBaseCompositeMessage.h "; + +%feature("docstring") +gdcm::network::BaseCompositeMessage::ConstructPDV "virtual +std::vector +gdcm::network::BaseCompositeMessage::ConstructPDV(const ULConnection +&inConnection, const BaseRootQuery *inRootQuery)=0 "; + + +// File: classgdcm_1_1network_1_1BasePDU.xml +%feature("docstring") gdcm::network::BasePDU " + +BasePDU base class for PDUs. + +all PDUs start with the first ten bytes as specified: 01 PDU type 02 +reserved 3-6 PDU Length (unsigned) 7-10 variable + +on some, 7-10 are split (7-8 as protocol version in Associate-RQ, for +instance, while associate-rj splits those four bytes differently). + +Also common to all the PDUs is their ability to read and write to a +stream. + +So, let's just get them all bunched together into one (abstract) +class, shall we? + +Why? 1) so that the ULEvent can have the PDU stored in it, since the +event takes PDUs and not other class structures (other class +structures get converted into PDUs) 2) to make reading PDUs in the +event loop cleaner + +C++ includes: gdcmBasePDU.h "; + +%feature("docstring") gdcm::network::BasePDU::~BasePDU "virtual +gdcm::network::BasePDU::~BasePDU() "; + +%feature("docstring") gdcm::network::BasePDU::IsLastFragment "virtual bool gdcm::network::BasePDU::IsLastFragment() const =0 "; + +%feature("docstring") gdcm::network::BasePDU::Print "virtual void +gdcm::network::BasePDU::Print(std::ostream &os) const =0 "; + +%feature("docstring") gdcm::network::BasePDU::Read "virtual +std::istream& gdcm::network::BasePDU::Read(std::istream &is)=0 "; + +%feature("docstring") gdcm::network::BasePDU::Size "virtual size_t +gdcm::network::BasePDU::Size() const =0 "; + +%feature("docstring") gdcm::network::BasePDU::Write "virtual const +std::ostream& gdcm::network::BasePDU::Write(std::ostream &os) const =0 +"; + + +// File: classgdcm_1_1BaseRootQuery.xml +%feature("docstring") gdcm::BaseRootQuery " + +BaseRootQuery contains: a baseclass which will produce a dataset for +c-find and c-move with patient/study root. + +This class contains the functionality used in patient c-find and +c-move queries. PatientRootQuery and StudyRootQuery derive from this +class. + +Namely: 1) list all tags associated with a particular query type 2) +produce a query dataset via tag association + +Eventually, it can be used to validate a particular dataset type. + +The dataset held by this object (or, really, one of its derivates) +should be passed to a c-find or c-move query. + +C++ includes: gdcmBaseRootQuery.h "; + +%feature("docstring") gdcm::BaseRootQuery::~BaseRootQuery "virtual +gdcm::BaseRootQuery::~BaseRootQuery() "; + +%feature("docstring") gdcm::BaseRootQuery::AddQueryDataSet "void +gdcm::BaseRootQuery::AddQueryDataSet(const DataSet &ds) "; + +%feature("docstring") gdcm::BaseRootQuery::GetAbstractSyntaxUID "virtual UIDs::TSName gdcm::BaseRootQuery::GetAbstractSyntaxUID() const +=0 "; + +%feature("docstring") gdcm::BaseRootQuery::GetQueryDataSet "DataSet +const& gdcm::BaseRootQuery::GetQueryDataSet() const + +Set/Get the internal representation of the query as a DataSet. "; + +%feature("docstring") gdcm::BaseRootQuery::GetQueryDataSet "DataSet& +gdcm::BaseRootQuery::GetQueryDataSet() "; + +%feature("docstring") gdcm::BaseRootQuery::GetQueryLevelFromQueryRoot +"EQueryLevel +gdcm::BaseRootQuery::GetQueryLevelFromQueryRoot(ERootType roottype) "; + +%feature("docstring") gdcm::BaseRootQuery::GetTagListByLevel "virtual std::vector gdcm::BaseRootQuery::GetTagListByLevel(const +EQueryLevel &inQueryLevel)=0 + +this function will return all tags at a given query level, so that +they maybe selected for searching. The boolean forFind is true if the +query is a find query, or false for a move query. "; + +%feature("docstring") gdcm::BaseRootQuery::InitializeDataSet "virtual void gdcm::BaseRootQuery::InitializeDataSet(const EQueryLevel +&inQueryLevel)=0 + +this function sets tag 8,52 to the appropriate value based on query +level also fills in the right unique tags, as per the standard's +requirements should allow for connection with dcmtk "; + +%feature("docstring") gdcm::BaseRootQuery::Print "void +gdcm::BaseRootQuery::Print(std::ostream &os) const "; + +%feature("docstring") gdcm::BaseRootQuery::SetSearchParameter "void +gdcm::BaseRootQuery::SetSearchParameter(const Tag &inTag, const +std::string &inValue) "; + +%feature("docstring") gdcm::BaseRootQuery::SetSearchParameter "void +gdcm::BaseRootQuery::SetSearchParameter(const std::string &inKeyword, +const std::string &inValue) "; + +%feature("docstring") gdcm::BaseRootQuery::ValidateQuery "virtual +bool gdcm::BaseRootQuery::ValidateQuery(bool inStrict=true) const =0 + +have to be able to ensure that 0x8,0x52 is set (which will be true if +InitializeDataSet is called...) that the level is appropriate (ie, not +setting PATIENT for a study query that the tags in the query match the +right level (either required, unique, optional) by default, this +function checks to see if the query is for finding, which is more +permissive than for moving. For moving, only the unique tags are +allowed. 10 Jan 2011: adding in the 'strict' mode. according to the +standard (at least, how I've read it), only tags for a particular +level should be allowed in a particular query (ie, just series level +tags in a series level query). However, it seems that dcm4chee doesn't +share that interpretation. So, if 'inStrict' is false, then tags from +the current level and all higher levels are now considered valid. So, +if you're doing a non-strict series-level query, tags from the patient +and study level can be passed along as well. "; + +%feature("docstring") gdcm::BaseRootQuery::WriteHelpFile "const +std::ostream& gdcm::BaseRootQuery::WriteHelpFile(std::ostream &os) "; + +%feature("docstring") gdcm::BaseRootQuery::WriteQuery "bool +gdcm::BaseRootQuery::WriteQuery(const std::string &inFileName) "; + + +// File: classstd_1_1basic__fstream.xml +%feature("docstring") std::basic_fstream " + +STL class. "; + + +// File: classstd_1_1basic__ifstream.xml +%feature("docstring") std::basic_ifstream " + +STL class. "; + + +// File: classstd_1_1basic__ios.xml +%feature("docstring") std::basic_ios " + +STL class. "; + + +// File: classstd_1_1basic__iostream.xml +%feature("docstring") std::basic_iostream " + +STL class. "; + + +// File: classstd_1_1basic__istream.xml +%feature("docstring") std::basic_istream " + +STL class. "; + + +// File: classstd_1_1basic__istringstream.xml +%feature("docstring") std::basic_istringstream " + +STL class. "; + + +// File: classstd_1_1basic__ofstream.xml +%feature("docstring") std::basic_ofstream " + +STL class. "; + + +// File: classstd_1_1basic__ostream.xml +%feature("docstring") std::basic_ostream " + +STL class. "; + + +// File: classstd_1_1basic__ostringstream.xml +%feature("docstring") std::basic_ostringstream " + +STL class. "; + + +// File: classstd_1_1basic__string.xml +%feature("docstring") std::basic_string " + +STL class. "; + + +// File: classstd_1_1basic__stringstream.xml +%feature("docstring") std::basic_stringstream " + +STL class. "; + + +// File: structgdcm_1_1SegmentHelper_1_1BasicCodedEntry.xml +%feature("docstring") gdcm::SegmentHelper::BasicCodedEntry " + +This structure defines a basic coded entry with all of its attributes. + +See: PS 3.3 section 8.8. + +C++ includes: gdcmSegmentHelper.h "; + +%feature("docstring") +gdcm::SegmentHelper::BasicCodedEntry::BasicCodedEntry "gdcm::SegmentHelper::BasicCodedEntry::BasicCodedEntry() + +Constructor. "; + +%feature("docstring") +gdcm::SegmentHelper::BasicCodedEntry::BasicCodedEntry "gdcm::SegmentHelper::BasicCodedEntry::BasicCodedEntry(const char +*a_CV, const char *a_CSD, const char *a_CM) + +constructor which defines type 1 attributes. "; + +%feature("docstring") +gdcm::SegmentHelper::BasicCodedEntry::BasicCodedEntry "gdcm::SegmentHelper::BasicCodedEntry::BasicCodedEntry(const char +*a_CV, const char *a_CSD, const char *a_CSV, const char *a_CM) + +constructor which defines attributes. "; + +%feature("docstring") gdcm::SegmentHelper::BasicCodedEntry::IsEmpty "bool gdcm::SegmentHelper::BasicCodedEntry::IsEmpty(const bool +checkOptionalAttributes=false) const + +Check if each attibutes of the basic coded entry is defined. + +Parameters: +----------- + +checkOptionalAttributes: Check also type 1C attributes. "; + + +// File: classgdcm_1_1BasicOffsetTable.xml +%feature("docstring") gdcm::BasicOffsetTable " + +Class to represent a BasicOffsetTable. + +C++ includes: gdcmBasicOffsetTable.h "; + +%feature("docstring") gdcm::BasicOffsetTable::BasicOffsetTable "gdcm::BasicOffsetTable::BasicOffsetTable() "; + +%feature("docstring") gdcm::BasicOffsetTable::Read "std::istream& +gdcm::BasicOffsetTable::Read(std::istream &is) "; + + +// File: classgdcm_1_1Bitmap.xml +%feature("docstring") gdcm::Bitmap " + +Bitmap class A bitmap based image. Used as parent for both IconImage +and the main Pixel Data Image It does not contains any World Space +information (IPP, IOP). + +C++ includes: gdcmBitmap.h "; + +%feature("docstring") gdcm::Bitmap::Bitmap "gdcm::Bitmap::Bitmap() +"; + +%feature("docstring") gdcm::Bitmap::~Bitmap "gdcm::Bitmap::~Bitmap() +"; + +%feature("docstring") gdcm::Bitmap::AreOverlaysInPixelData "virtual +bool gdcm::Bitmap::AreOverlaysInPixelData() const "; + +%feature("docstring") gdcm::Bitmap::Clear "void +gdcm::Bitmap::Clear() "; + +%feature("docstring") gdcm::Bitmap::GetBuffer "bool +gdcm::Bitmap::GetBuffer(char *buffer) const + +Acces the raw data. "; + +%feature("docstring") gdcm::Bitmap::GetBufferLength "unsigned long +gdcm::Bitmap::GetBufferLength() const + +Return the length of the image after decompression WARNING for palette +color: It will NOT take into account the Palette Color thus you need +to multiply this length by 3 if computing the size of equivalent RGB +image "; + +%feature("docstring") gdcm::Bitmap::GetColumns "unsigned int +gdcm::Bitmap::GetColumns() const "; + +%feature("docstring") gdcm::Bitmap::GetDataElement "DataElement& +gdcm::Bitmap::GetDataElement() "; + +%feature("docstring") gdcm::Bitmap::GetDataElement "const +DataElement& gdcm::Bitmap::GetDataElement() const "; + +%feature("docstring") gdcm::Bitmap::GetDimension "unsigned int +gdcm::Bitmap::GetDimension(unsigned int idx) const "; + +%feature("docstring") gdcm::Bitmap::GetDimensions "const unsigned +int* gdcm::Bitmap::GetDimensions() const + +Return the dimension of the pixel data, first dimension (x), then 2nd +(y), then 3rd (z)... "; + +%feature("docstring") gdcm::Bitmap::GetLUT "const LookupTable& +gdcm::Bitmap::GetLUT() const "; + +%feature("docstring") gdcm::Bitmap::GetLUT "LookupTable& +gdcm::Bitmap::GetLUT() "; + +%feature("docstring") gdcm::Bitmap::GetNeedByteSwap "bool +gdcm::Bitmap::GetNeedByteSwap() const "; + +%feature("docstring") gdcm::Bitmap::GetNumberOfDimensions "unsigned +int gdcm::Bitmap::GetNumberOfDimensions() const + +Return the number of dimension of the pixel data bytes; for example 2 +for a 2D matrices of values. "; + +%feature("docstring") gdcm::Bitmap::GetPhotometricInterpretation "const PhotometricInterpretation& +gdcm::Bitmap::GetPhotometricInterpretation() const + +return the photometric interpretation "; + +%feature("docstring") gdcm::Bitmap::GetPixelFormat "PixelFormat& +gdcm::Bitmap::GetPixelFormat() "; + +%feature("docstring") gdcm::Bitmap::GetPixelFormat "const +PixelFormat& gdcm::Bitmap::GetPixelFormat() const + +Get/Set PixelFormat. "; + +%feature("docstring") gdcm::Bitmap::GetPlanarConfiguration "unsigned +int gdcm::Bitmap::GetPlanarConfiguration() const + +return the planar configuration "; + +%feature("docstring") gdcm::Bitmap::GetRows "unsigned int +gdcm::Bitmap::GetRows() const "; + +%feature("docstring") gdcm::Bitmap::GetTransferSyntax "const +TransferSyntax& gdcm::Bitmap::GetTransferSyntax() const "; + +%feature("docstring") gdcm::Bitmap::IsEmpty "bool +gdcm::Bitmap::IsEmpty() const "; + +%feature("docstring") gdcm::Bitmap::IsLossy "bool +gdcm::Bitmap::IsLossy() const + +Return whether or not the image was compressed using a lossy +compressor or not. "; + +%feature("docstring") gdcm::Bitmap::IsTransferSyntaxCompatible "bool +gdcm::Bitmap::IsTransferSyntaxCompatible(TransferSyntax const &ts) +const "; + +%feature("docstring") gdcm::Bitmap::Print "void +gdcm::Bitmap::Print(std::ostream &) const "; + +%feature("docstring") gdcm::Bitmap::SetColumns "void +gdcm::Bitmap::SetColumns(unsigned int col) "; + +%feature("docstring") gdcm::Bitmap::SetDataElement "void +gdcm::Bitmap::SetDataElement(DataElement const &de) "; + +%feature("docstring") gdcm::Bitmap::SetDimension "void +gdcm::Bitmap::SetDimension(unsigned int idx, unsigned int dim) "; + +%feature("docstring") gdcm::Bitmap::SetDimensions "void +gdcm::Bitmap::SetDimensions(const unsigned int dims[3]) "; + +%feature("docstring") gdcm::Bitmap::SetLossyFlag "void +gdcm::Bitmap::SetLossyFlag(bool f) + +Specifically set that the image was compressed using a lossy +compression mechanism. "; + +%feature("docstring") gdcm::Bitmap::SetLUT "void +gdcm::Bitmap::SetLUT(LookupTable const &lut) + +Set/Get LUT. "; + +%feature("docstring") gdcm::Bitmap::SetNeedByteSwap "void +gdcm::Bitmap::SetNeedByteSwap(bool b) "; + +%feature("docstring") gdcm::Bitmap::SetNumberOfDimensions "void +gdcm::Bitmap::SetNumberOfDimensions(unsigned int dim) "; + +%feature("docstring") gdcm::Bitmap::SetPhotometricInterpretation "void +gdcm::Bitmap::SetPhotometricInterpretation(PhotometricInterpretation +const &pi) "; + +%feature("docstring") gdcm::Bitmap::SetPixelFormat "void +gdcm::Bitmap::SetPixelFormat(PixelFormat const &pf) "; + +%feature("docstring") gdcm::Bitmap::SetPlanarConfiguration "void +gdcm::Bitmap::SetPlanarConfiguration(unsigned int pc) + +WARNING: you need to call SetPixelFormat first (before +SetPlanarConfiguration) for consistency checking "; + +%feature("docstring") gdcm::Bitmap::SetRows "void +gdcm::Bitmap::SetRows(unsigned int rows) "; + +%feature("docstring") gdcm::Bitmap::SetTransferSyntax "void +gdcm::Bitmap::SetTransferSyntax(TransferSyntax const &ts) + +Transfer syntax. "; + + +// File: classgdcm_1_1BitmapToBitmapFilter.xml +%feature("docstring") gdcm::BitmapToBitmapFilter " + +BitmapToBitmapFilter class Super class for all filter taking an image +and producing an output image. + +C++ includes: gdcmBitmapToBitmapFilter.h "; + +%feature("docstring") +gdcm::BitmapToBitmapFilter::BitmapToBitmapFilter "gdcm::BitmapToBitmapFilter::BitmapToBitmapFilter() "; + +%feature("docstring") +gdcm::BitmapToBitmapFilter::~BitmapToBitmapFilter "gdcm::BitmapToBitmapFilter::~BitmapToBitmapFilter() "; + +%feature("docstring") gdcm::BitmapToBitmapFilter::GetOutput "const +Bitmap& gdcm::BitmapToBitmapFilter::GetOutput() const + +Get Output image. "; + +%feature("docstring") gdcm::BitmapToBitmapFilter::GetOutputAsBitmap "const Bitmap& gdcm::BitmapToBitmapFilter::GetOutputAsBitmap() const "; + +%feature("docstring") gdcm::BitmapToBitmapFilter::SetInput "void +gdcm::BitmapToBitmapFilter::SetInput(const Bitmap &image) + +Set input image. "; + + +// File: classstd_1_1bitset.xml +%feature("docstring") std::bitset " + +STL class. "; + + +// File: classgdcm_1_1BoxRegion.xml +%feature("docstring") gdcm::BoxRegion " + +Class for manipulation box region This is a very simple implementation +of the Region class. It only support 3D box type region. It assumes +the 3D Box does not have a tilt Origin is as (0,0,0). + +C++ includes: gdcmBoxRegion.h "; + +%feature("docstring") gdcm::BoxRegion::BoxRegion "gdcm::BoxRegion::BoxRegion() "; + +%feature("docstring") gdcm::BoxRegion::BoxRegion "gdcm::BoxRegion::BoxRegion(const BoxRegion &) + +copy/cstor and al. "; + +%feature("docstring") gdcm::BoxRegion::~BoxRegion "gdcm::BoxRegion::~BoxRegion() "; + +%feature("docstring") gdcm::BoxRegion::Area "size_t +gdcm::BoxRegion::Area() const + +compute the area "; + +%feature("docstring") gdcm::BoxRegion::Clone "Region* +gdcm::BoxRegion::Clone() const "; + +%feature("docstring") gdcm::BoxRegion::ComputeBoundingBox "BoxRegion +gdcm::BoxRegion::ComputeBoundingBox() + +Return the Axis-Aligned minimum bounding box for all regions. "; + +%feature("docstring") gdcm::BoxRegion::Empty "bool +gdcm::BoxRegion::Empty() const + +return whether this domain is empty: "; + +%feature("docstring") gdcm::BoxRegion::GetXMax "unsigned int +gdcm::BoxRegion::GetXMax() const "; + +%feature("docstring") gdcm::BoxRegion::GetXMin "unsigned int +gdcm::BoxRegion::GetXMin() const + +Get domain. "; + +%feature("docstring") gdcm::BoxRegion::GetYMax "unsigned int +gdcm::BoxRegion::GetYMax() const "; + +%feature("docstring") gdcm::BoxRegion::GetYMin "unsigned int +gdcm::BoxRegion::GetYMin() const "; + +%feature("docstring") gdcm::BoxRegion::GetZMax "unsigned int +gdcm::BoxRegion::GetZMax() const "; + +%feature("docstring") gdcm::BoxRegion::GetZMin "unsigned int +gdcm::BoxRegion::GetZMin() const "; + +%feature("docstring") gdcm::BoxRegion::IsValid "bool +gdcm::BoxRegion::IsValid() const + +return whether this is valid domain "; + +%feature("docstring") gdcm::BoxRegion::Print "void +gdcm::BoxRegion::Print(std::ostream &os=std::cout) const + +Print. "; + +%feature("docstring") gdcm::BoxRegion::SetDomain "void +gdcm::BoxRegion::SetDomain(unsigned int xmin, unsigned int xmax, +unsigned int ymin, unsigned int ymax, unsigned int zmin, unsigned int +zmax) + +Set domain. "; + + +// File: classgdcm_1_1ByteBuffer.xml +%feature("docstring") gdcm::ByteBuffer " + +ByteBuffer. + +Detailled description here looks like a std::streambuf or std::filebuf +class with the get and peek pointer + +C++ includes: gdcmByteBuffer.h "; + +%feature("docstring") gdcm::ByteBuffer::ByteBuffer "gdcm::ByteBuffer::ByteBuffer() "; + +%feature("docstring") gdcm::ByteBuffer::Get "char* +gdcm::ByteBuffer::Get(int len) "; + +%feature("docstring") gdcm::ByteBuffer::GetStart "const char* +gdcm::ByteBuffer::GetStart() const "; + +%feature("docstring") gdcm::ByteBuffer::ShiftEnd "void +gdcm::ByteBuffer::ShiftEnd(int len) "; + +%feature("docstring") gdcm::ByteBuffer::UpdatePosition "void +gdcm::ByteBuffer::UpdatePosition() "; + + +// File: classgdcm_1_1ByteSwap.xml +%feature("docstring") gdcm::ByteSwap " + +ByteSwap. + +Perform machine dependent byte swaping (Little Endian, Big Endian, Bad +Little Endian, Bad Big Endian). TODO: bswap_32 / bswap_64 ... + +C++ includes: gdcmByteSwap.h "; + + +// File: classgdcm_1_1ByteSwapFilter.xml +%feature("docstring") gdcm::ByteSwapFilter " + +ByteSwapFilter In place byte-swapping of a dataset FIXME: FL status ?? + +C++ includes: gdcmByteSwapFilter.h "; + +%feature("docstring") gdcm::ByteSwapFilter::ByteSwapFilter "gdcm::ByteSwapFilter::ByteSwapFilter(DataSet &ds) "; + +%feature("docstring") gdcm::ByteSwapFilter::~ByteSwapFilter "gdcm::ByteSwapFilter::~ByteSwapFilter() "; + +%feature("docstring") gdcm::ByteSwapFilter::ByteSwap "bool +gdcm::ByteSwapFilter::ByteSwap() "; + +%feature("docstring") gdcm::ByteSwapFilter::SetByteSwapTag "void +gdcm::ByteSwapFilter::SetByteSwapTag(bool b) "; + + +// File: classgdcm_1_1ByteValue.xml +%feature("docstring") gdcm::ByteValue " + +Class to represent binary value (array of bytes). + +C++ includes: gdcmByteValue.h "; + +%feature("docstring") gdcm::ByteValue::ByteValue "gdcm::ByteValue::ByteValue(const char *array=0, VL const &vl=0) "; + +%feature("docstring") gdcm::ByteValue::ByteValue "gdcm::ByteValue::ByteValue(std::vector< char > &v) + +WARNING: casting to uint32_t "; + +%feature("docstring") gdcm::ByteValue::~ByteValue "gdcm::ByteValue::~ByteValue() "; + +%feature("docstring") gdcm::ByteValue::Clear "void +gdcm::ByteValue::Clear() "; + +%feature("docstring") gdcm::ByteValue::Fill "void +gdcm::ByteValue::Fill(char c) "; + +%feature("docstring") gdcm::ByteValue::GetBuffer "bool +gdcm::ByteValue::GetBuffer(char *buffer, unsigned long length) const +"; + +%feature("docstring") gdcm::ByteValue::GetLength "VL +gdcm::ByteValue::GetLength() const "; + +%feature("docstring") gdcm::ByteValue::GetPointer "const char* +gdcm::ByteValue::GetPointer() const "; + +%feature("docstring") gdcm::ByteValue::IsEmpty "bool +gdcm::ByteValue::IsEmpty() const "; + +%feature("docstring") gdcm::ByteValue::IsPrintable "bool +gdcm::ByteValue::IsPrintable(VL length) const + +Checks whether a 'ByteValue' is printable or not (in order to avoid +corrupting the terminal of invocation when printing) I dont think this +function is working since it does not handle UNICODE or character +set... "; + +%feature("docstring") gdcm::ByteValue::PrintASCII "void +gdcm::ByteValue::PrintASCII(std::ostream &os, VL maxlength) const "; + +%feature("docstring") gdcm::ByteValue::PrintASCIIXML "void +gdcm::ByteValue::PrintASCIIXML(std::ostream &os) const "; + +%feature("docstring") gdcm::ByteValue::PrintGroupLength "void +gdcm::ByteValue::PrintGroupLength(std::ostream &os) "; + +%feature("docstring") gdcm::ByteValue::PrintHex "void +gdcm::ByteValue::PrintHex(std::ostream &os, VL maxlength) const "; + +%feature("docstring") gdcm::ByteValue::PrintHexXML "void +gdcm::ByteValue::PrintHexXML(std::ostream &os) const "; + +%feature("docstring") gdcm::ByteValue::PrintPNXML "void +gdcm::ByteValue::PrintPNXML(std::ostream &os) const + +To Print Values in Native DICOM format "; + +%feature("docstring") gdcm::ByteValue::Read "std::istream& +gdcm::ByteValue::Read(std::istream &is) "; + +%feature("docstring") gdcm::ByteValue::Read "std::istream& +gdcm::ByteValue::Read(std::istream &is) "; + +%feature("docstring") gdcm::ByteValue::SetLength "void +gdcm::ByteValue::SetLength(VL vl) "; + +%feature("docstring") gdcm::ByteValue::Write "std::ostream const& +gdcm::ByteValue::Write(std::ostream &os) const "; + +%feature("docstring") gdcm::ByteValue::Write "std::ostream const& +gdcm::ByteValue::Write(std::ostream &os) const "; + +%feature("docstring") gdcm::ByteValue::WriteBuffer "bool +gdcm::ByteValue::WriteBuffer(std::ostream &os) const "; + + +// File: classgdcm_1_1CAPICryptoFactory.xml +%feature("docstring") gdcm::CAPICryptoFactory "C++ includes: +gdcmCAPICryptoFactory.h "; + +%feature("docstring") gdcm::CAPICryptoFactory::CAPICryptoFactory "gdcm::CAPICryptoFactory::CAPICryptoFactory(CryptoLib id) "; + +%feature("docstring") gdcm::CAPICryptoFactory::CreateCMSProvider "CryptographicMessageSyntax* +gdcm::CAPICryptoFactory::CreateCMSProvider() "; + + +// File: classgdcm_1_1CAPICryptographicMessageSyntax.xml +%feature("docstring") gdcm::CAPICryptographicMessageSyntax "C++ +includes: gdcmCAPICryptographicMessageSyntax.h "; + +%feature("docstring") +gdcm::CAPICryptographicMessageSyntax::CAPICryptographicMessageSyntax "gdcm::CAPICryptographicMessageSyntax::CAPICryptographicMessageSyntax() +"; + +%feature("docstring") +gdcm::CAPICryptographicMessageSyntax::~CAPICryptographicMessageSyntax +"gdcm::CAPICryptographicMessageSyntax::~CAPICryptographicMessageSyntax() +"; + +%feature("docstring") gdcm::CAPICryptographicMessageSyntax::Decrypt "bool gdcm::CAPICryptographicMessageSyntax::Decrypt(char *output, +size_t &outlen, const char *array, size_t len) const + +decrypt content from a CMS envelopedData structure "; + +%feature("docstring") gdcm::CAPICryptographicMessageSyntax::Encrypt "bool gdcm::CAPICryptographicMessageSyntax::Encrypt(char *output, +size_t &outlen, const char *array, size_t len) const + +create a CMS envelopedData structure "; + +%feature("docstring") +gdcm::CAPICryptographicMessageSyntax::GetCipherType "CipherTypes +gdcm::CAPICryptographicMessageSyntax::GetCipherType() const "; + +%feature("docstring") +gdcm::CAPICryptographicMessageSyntax::GetInitialized "bool +gdcm::CAPICryptographicMessageSyntax::GetInitialized() const "; + +%feature("docstring") +gdcm::CAPICryptographicMessageSyntax::ParseCertificateFile "bool +gdcm::CAPICryptographicMessageSyntax::ParseCertificateFile(const char +*filename) "; + +%feature("docstring") +gdcm::CAPICryptographicMessageSyntax::ParseKeyFile "bool +gdcm::CAPICryptographicMessageSyntax::ParseKeyFile(const char +*filename) "; + +%feature("docstring") +gdcm::CAPICryptographicMessageSyntax::SetCipherType "void +gdcm::CAPICryptographicMessageSyntax::SetCipherType(CipherTypes type) +"; + +%feature("docstring") +gdcm::CAPICryptographicMessageSyntax::SetPassword "bool +gdcm::CAPICryptographicMessageSyntax::SetPassword(const char *pass, +size_t passLen) "; + + +// File: classgdcm_1_1network_1_1CEchoRQ.xml +%feature("docstring") gdcm::network::CEchoRQ " + +CEchoRQ this file defines the messages for the cecho action. + +C++ includes: gdcmCEchoMessages.h "; + +%feature("docstring") gdcm::network::CEchoRQ::ConstructPDV "std::vector +gdcm::network::CEchoRQ::ConstructPDV(const ULConnection &inConnection, +const BaseRootQuery *inRootQuery) "; + + +// File: classgdcm_1_1network_1_1CEchoRSP.xml +%feature("docstring") gdcm::network::CEchoRSP " + +CEchoRSP this file defines the messages for the cecho action. + +C++ includes: gdcmCEchoMessages.h "; + +%feature("docstring") gdcm::network::CEchoRSP::ConstructPDVByDataSet +"std::vector +gdcm::network::CEchoRSP::ConstructPDVByDataSet(const DataSet +*inDataSet) "; + + +// File: classgdcm_1_1network_1_1CFind.xml +%feature("docstring") gdcm::network::CFind " + +PS 3.4 - 2009 Table B.2-1 C-STORE STATUS + +C++ includes: gdcmDIMSE.h "; + + +// File: classgdcm_1_1network_1_1CFindCancelRQ.xml +%feature("docstring") gdcm::network::CFindCancelRQ " + +CFindCancelRQ this file defines the messages for the cfind action. + +C++ includes: gdcmCFindMessages.h "; + +%feature("docstring") +gdcm::network::CFindCancelRQ::ConstructPDVByDataSet "std::vector +gdcm::network::CFindCancelRQ::ConstructPDVByDataSet(const DataSet +*inDataSet) "; + + +// File: classgdcm_1_1network_1_1CFindRQ.xml +%feature("docstring") gdcm::network::CFindRQ " + +CFindRQ this file defines the messages for the cfind action. + +C++ includes: gdcmCFindMessages.h "; + +%feature("docstring") gdcm::network::CFindRQ::ConstructPDV "std::vector +gdcm::network::CFindRQ::ConstructPDV(const ULConnection &inConnection, +const BaseRootQuery *inRootQuery) "; + + +// File: classgdcm_1_1network_1_1CFindRSP.xml +%feature("docstring") gdcm::network::CFindRSP " + +CFindRSP this file defines the messages for the cfind action. + +C++ includes: gdcmCFindMessages.h "; + +%feature("docstring") gdcm::network::CFindRSP::ConstructPDVByDataSet +"std::vector +gdcm::network::CFindRSP::ConstructPDVByDataSet(const DataSet +*inDataSet) "; + + +// File: classgdcm_1_1network_1_1CMoveCancelRq.xml +%feature("docstring") gdcm::network::CMoveCancelRq "C++ includes: +gdcmCMoveMessages.h "; + +%feature("docstring") +gdcm::network::CMoveCancelRq::ConstructPDVByDataSet "std::vector +gdcm::network::CMoveCancelRq::ConstructPDVByDataSet(const DataSet +*inDataSet) "; + + +// File: classgdcm_1_1network_1_1CMoveRQ.xml +%feature("docstring") gdcm::network::CMoveRQ " + +CMoveRQ this file defines the messages for the cmove action. + +C++ includes: gdcmCMoveMessages.h "; + +%feature("docstring") gdcm::network::CMoveRQ::ConstructPDV "std::vector +gdcm::network::CMoveRQ::ConstructPDV(const ULConnection &inConnection, +const BaseRootQuery *inRootQuery) "; + + +// File: classgdcm_1_1network_1_1CMoveRSP.xml +%feature("docstring") gdcm::network::CMoveRSP " + +CMoveRSP this file defines the messages for the cmove action. + +C++ includes: gdcmCMoveMessages.h "; + +%feature("docstring") gdcm::network::CMoveRSP::ConstructPDVByDataSet +"std::vector +gdcm::network::CMoveRSP::ConstructPDVByDataSet(const DataSet +*inDataSet) "; + + +// File: classgdcm_1_1Codec.xml +%feature("docstring") gdcm::Codec " + +Codec class. + +C++ includes: gdcmCodec.h "; + + +// File: classgdcm_1_1Coder.xml +%feature("docstring") gdcm::Coder " + +Coder. + +C++ includes: gdcmCoder.h "; + +%feature("docstring") gdcm::Coder::~Coder "virtual +gdcm::Coder::~Coder() "; + +%feature("docstring") gdcm::Coder::CanCode "virtual bool +gdcm::Coder::CanCode(TransferSyntax const &) const =0 + +Return whether this coder support this transfer syntax (can code it). +"; + +%feature("docstring") gdcm::Coder::Code "virtual bool +gdcm::Coder::Code(DataElement const &in_, DataElement &out_) + +Code. "; + + +// File: classgdcm_1_1CodeString.xml +%feature("docstring") gdcm::CodeString " + +CodeString This is an implementation of DICOM VR: CS The cstor will +properly Trim so that operator== is correct. + +the cstor of CodeString will Trim the string on the fly so as to +remove the extra leading and ending spaces. However it will not +perform validation on the fly ( CodeString obj can contains invalid +char such as lower cases). This design was chosen to be a little +tolerant to broken DICOM implementation, and thus allow user to +compare lower case CS from there input file without the need to first +rewrite them to get rid of invalid character (validation is a +different operation from searching, querying). + +WARNING: when writing out DICOM file it is highly recommended to +perform the IsValid() call, at least to check that the length of the +string match the definition in the standard. + +C++ includes: gdcmCodeString.h "; + +%feature("docstring") gdcm::CodeString::CodeString "gdcm::CodeString::CodeString() + +CodeString constructors. "; + +%feature("docstring") gdcm::CodeString::CodeString "gdcm::CodeString::CodeString(const value_type *s) "; + +%feature("docstring") gdcm::CodeString::CodeString "gdcm::CodeString::CodeString(const InternalClass &s, size_type pos=0, +size_type n=InternalClass::npos) "; + +%feature("docstring") gdcm::CodeString::CodeString "gdcm::CodeString::CodeString(const value_type *s, size_type n) "; + +%feature("docstring") gdcm::CodeString::GetAsString "std::string +gdcm::CodeString::GetAsString() const + +Return the full code string as std::string. "; + +%feature("docstring") gdcm::CodeString::IsValid "bool +gdcm::CodeString::IsValid() const + +Check if CodeString obj is correct.. "; + +%feature("docstring") gdcm::CodeString::Size "size_type +gdcm::CodeString::Size() const + +Return the size of the string. "; + + +// File: classgdcm_1_1Command.xml +%feature("docstring") gdcm::Command " + +Command superclass for callback/observer methods. + +See: Subject + +C++ includes: gdcmCommand.h "; + +%feature("docstring") gdcm::Command::Execute "virtual void +gdcm::Command::Execute(Subject *caller, const Event &event)=0 + +Abstract method that defines the action to be taken by the command. "; + +%feature("docstring") gdcm::Command::Execute "virtual void +gdcm::Command::Execute(const Subject *caller, const Event &event)=0 + +Abstract method that defines the action to be taken by the command. +This variant is expected to be used when requests comes from a const +Object "; + + +// File: classgdcm_1_1CommandDataSet.xml +%feature("docstring") gdcm::CommandDataSet " + +Class to represent a Command DataSet. + +See: DataSet + +C++ includes: gdcmCommandDataSet.h "; + +%feature("docstring") gdcm::CommandDataSet::CommandDataSet "gdcm::CommandDataSet::CommandDataSet() "; + +%feature("docstring") gdcm::CommandDataSet::~CommandDataSet "gdcm::CommandDataSet::~CommandDataSet() "; + +%feature("docstring") gdcm::CommandDataSet::Insert "void +gdcm::CommandDataSet::Insert(const DataElement &de) + +Insert a DataElement in the DataSet. WARNING: : Tag need to be >= 0x8 +to be considered valid data element "; + +%feature("docstring") gdcm::CommandDataSet::Read "std::istream& +gdcm::CommandDataSet::Read(std::istream &is) + +Read. "; + +%feature("docstring") gdcm::CommandDataSet::Replace "void +gdcm::CommandDataSet::Replace(const DataElement &de) + +Replace a dataelement with another one. "; + +%feature("docstring") gdcm::CommandDataSet::Write "std::ostream& +gdcm::CommandDataSet::Write(std::ostream &os) const + +Write. "; + + +// File: classstd_1_1complex.xml +%feature("docstring") std::complex " + +STL class. "; + + +// File: classgdcm_1_1network_1_1CompositeMessageFactory.xml +%feature("docstring") gdcm::network::CompositeMessageFactory " + +CompositeMessageFactory This class constructs PDataPDUs, but that have +been specifically constructed for the composite DICOM services +(C-Echo, C-Find, C-Get, C-Move, and C-Store). It will also handle +parsing the incoming data to determine which of the CompositePDUs the +incoming data is, and so therefore allowing the scu to determine what +to do with incoming data (if acting as a storescp server, for +instance). + +C++ includes: gdcmCompositeMessageFactory.h "; + + +// File: classgdcm_1_1CompositeNetworkFunctions.xml +%feature("docstring") gdcm::CompositeNetworkFunctions " + +Composite Network Functions These functions provide a generic API to +the DICOM functions implemented in GDCM. Advanced users can use this +code as a template for building their own versions of these functions +(for instance, to provide progress bars or some other way of handling +returned query information), but for most users, these functions +should be sufficient to interface with a PACS to a local machine. Note +that these functions are not contained within a static class or some +other class-style interface, because multiple connections can be +instantiated in the same program. The DICOM standard is much more +function oriented rather than class oriented in this instance, so the +design of this API reflects that functional approach. These functions +implements the following SCU operations: + +C-ECHO SCU + +C-FIND SCU + +C-STORE SCU + +C-MOVE SCU (+internal C-STORE SCP) + +C++ includes: gdcmCompositeNetworkFunctions.h "; + + +// File: classstd_1_1basic__string_1_1const__iterator.xml +%feature("docstring") std::basic_string::const_iterator " + +STL iterator class. "; + + +// File: classstd_1_1wstring_1_1const__iterator.xml +%feature("docstring") std::wstring::const_iterator " + +STL iterator class. "; + + +// File: classstd_1_1string_1_1const__iterator.xml +%feature("docstring") std::string::const_iterator " + +STL iterator class. "; + + +// File: classstd_1_1deque_1_1const__iterator.xml +%feature("docstring") std::deque::const_iterator " + +STL iterator class. "; + + +// File: classstd_1_1list_1_1const__iterator.xml +%feature("docstring") std::list::const_iterator " + +STL iterator class. "; + + +// File: classstd_1_1map_1_1const__iterator.xml +%feature("docstring") std::map::const_iterator " + +STL iterator class. "; + + +// File: classstd_1_1multimap_1_1const__iterator.xml +%feature("docstring") std::multimap::const_iterator " + +STL iterator class. "; + + +// File: classstd_1_1set_1_1const__iterator.xml +%feature("docstring") std::set::const_iterator " + +STL iterator class. "; + + +// File: classstd_1_1multiset_1_1const__iterator.xml +%feature("docstring") std::multiset::const_iterator " + +STL iterator class. "; + + +// File: classstd_1_1vector_1_1const__iterator.xml +%feature("docstring") std::vector::const_iterator " + +STL iterator class. "; + + +// File: classstd_1_1basic__string_1_1const__reverse__iterator.xml +%feature("docstring") std::basic_string::const_reverse_iterator " + +STL iterator class. "; + + +// File: classstd_1_1string_1_1const__reverse__iterator.xml +%feature("docstring") std::string::const_reverse_iterator " + +STL iterator class. "; + + +// File: classstd_1_1wstring_1_1const__reverse__iterator.xml +%feature("docstring") std::wstring::const_reverse_iterator " + +STL iterator class. "; + + +// File: classstd_1_1deque_1_1const__reverse__iterator.xml +%feature("docstring") std::deque::const_reverse_iterator " + +STL iterator class. "; + + +// File: classstd_1_1list_1_1const__reverse__iterator.xml +%feature("docstring") std::list::const_reverse_iterator " + +STL iterator class. "; + + +// File: classstd_1_1map_1_1const__reverse__iterator.xml +%feature("docstring") std::map::const_reverse_iterator " + +STL iterator class. "; + + +// File: classstd_1_1multimap_1_1const__reverse__iterator.xml +%feature("docstring") std::multimap::const_reverse_iterator " + +STL iterator class. "; + + +// File: classstd_1_1set_1_1const__reverse__iterator.xml +%feature("docstring") std::set::const_reverse_iterator " + +STL iterator class. "; + + +// File: classstd_1_1multiset_1_1const__reverse__iterator.xml +%feature("docstring") std::multiset::const_reverse_iterator " + +STL iterator class. "; + + +// File: classstd_1_1vector_1_1const__reverse__iterator.xml +%feature("docstring") std::vector::const_reverse_iterator " + +STL iterator class. "; + + +// File: classgdcm_1_1ConstCharWrapper.xml +%feature("docstring") gdcm::ConstCharWrapper " + +Do not use me. + +C++ includes: gdcmConstCharWrapper.h "; + +%feature("docstring") gdcm::ConstCharWrapper::ConstCharWrapper "gdcm::ConstCharWrapper::ConstCharWrapper(const char *i=0) "; + + +// File: classgdcm_1_1CP246ExplicitDataElement.xml +%feature("docstring") gdcm::CP246ExplicitDataElement " + +Class to read/write a DataElement as CP246Explicit Data Element. + +Some system are producing SQ, declare them as UN, but encode the SQ as +'Explicit' instead of Implicit + +C++ includes: gdcmCP246ExplicitDataElement.h "; + +%feature("docstring") gdcm::CP246ExplicitDataElement::GetLength "VL +gdcm::CP246ExplicitDataElement::GetLength() const "; + +%feature("docstring") gdcm::CP246ExplicitDataElement::Read "std::istream& gdcm::CP246ExplicitDataElement::Read(std::istream &is) +"; + +%feature("docstring") gdcm::CP246ExplicitDataElement::ReadPreValue "std::istream& +gdcm::CP246ExplicitDataElement::ReadPreValue(std::istream &is) "; + +%feature("docstring") gdcm::CP246ExplicitDataElement::ReadValue "std::istream& gdcm::CP246ExplicitDataElement::ReadValue(std::istream +&is) "; + +%feature("docstring") gdcm::CP246ExplicitDataElement::ReadWithLength +"std::istream& +gdcm::CP246ExplicitDataElement::ReadWithLength(std::istream &is, VL +&length) "; + + +// File: classgdcm_1_1CryptoFactory.xml +%feature("docstring") gdcm::CryptoFactory " + +Class to do handle the crypto factory. + +GDCM needs to access in a platform independant way the user specified +crypto engine. It can be: CAPI (windows only) + +OPENSSL (portable) + +OPENSSLP7 (portable) By default the factory will try: CAPI if on +windows OPENSSL if possible OPENSSLP7 when older OpenSSL is used. + +C++ includes: gdcmCryptoFactory.h "; + +%feature("docstring") gdcm::CryptoFactory::CreateCMSProvider "virtual CryptographicMessageSyntax* +gdcm::CryptoFactory::CreateCMSProvider()=0 "; + + +// File: classgdcm_1_1CryptographicMessageSyntax.xml +%feature("docstring") gdcm::CryptographicMessageSyntax "C++ includes: +gdcmCryptographicMessageSyntax.h "; + +%feature("docstring") +gdcm::CryptographicMessageSyntax::CryptographicMessageSyntax "gdcm::CryptographicMessageSyntax::CryptographicMessageSyntax() "; + +%feature("docstring") +gdcm::CryptographicMessageSyntax::~CryptographicMessageSyntax "virtual +gdcm::CryptographicMessageSyntax::~CryptographicMessageSyntax() "; + +%feature("docstring") gdcm::CryptographicMessageSyntax::Decrypt "virtual bool gdcm::CryptographicMessageSyntax::Decrypt(char *output, +size_t &outlen, const char *array, size_t len) const =0 + +decrypt content from a CMS envelopedData structure "; + +%feature("docstring") gdcm::CryptographicMessageSyntax::Encrypt "virtual bool gdcm::CryptographicMessageSyntax::Encrypt(char *output, +size_t &outlen, const char *array, size_t len) const =0 + +create a CMS envelopedData structure "; + +%feature("docstring") gdcm::CryptographicMessageSyntax::GetCipherType +"virtual CipherTypes +gdcm::CryptographicMessageSyntax::GetCipherType() const =0 "; + +%feature("docstring") +gdcm::CryptographicMessageSyntax::ParseCertificateFile "virtual bool +gdcm::CryptographicMessageSyntax::ParseCertificateFile(const char +*filename)=0 "; + +%feature("docstring") gdcm::CryptographicMessageSyntax::ParseKeyFile +"virtual bool gdcm::CryptographicMessageSyntax::ParseKeyFile(const +char *filename)=0 "; + +%feature("docstring") gdcm::CryptographicMessageSyntax::SetCipherType +"virtual void +gdcm::CryptographicMessageSyntax::SetCipherType(CipherTypes type)=0 "; + +%feature("docstring") gdcm::CryptographicMessageSyntax::SetPassword "virtual bool gdcm::CryptographicMessageSyntax::SetPassword(const char +*pass, size_t passLen)=0 "; + + +// File: classgdcm_1_1CSAElement.xml +%feature("docstring") gdcm::CSAElement " + +Class to represent a CSA Element. + +See: CSAHeader + +C++ includes: gdcmCSAElement.h "; + +%feature("docstring") gdcm::CSAElement::CSAElement "gdcm::CSAElement::CSAElement(unsigned int kf=0) "; + +%feature("docstring") gdcm::CSAElement::CSAElement "gdcm::CSAElement::CSAElement(const CSAElement &_val) "; + +%feature("docstring") gdcm::CSAElement::GetByteValue "const +ByteValue* gdcm::CSAElement::GetByteValue() const + +Return the Value of CSAElement as a ByteValue (if possible) WARNING: +: You need to check for NULL return value "; + +%feature("docstring") gdcm::CSAElement::GetKey "unsigned int +gdcm::CSAElement::GetKey() const + +Set/Get Key. "; + +%feature("docstring") gdcm::CSAElement::GetName "const char* +gdcm::CSAElement::GetName() const + +Set/Get Name. "; + +%feature("docstring") gdcm::CSAElement::GetNoOfItems "unsigned int +gdcm::CSAElement::GetNoOfItems() const + +Set/Get NoOfItems. "; + +%feature("docstring") gdcm::CSAElement::GetSyngoDT "unsigned int +gdcm::CSAElement::GetSyngoDT() const + +Set/Get SyngoDT. "; + +%feature("docstring") gdcm::CSAElement::GetValue "Value const& +gdcm::CSAElement::GetValue() const + +Set/Get Value (bytes array, SQ of items, SQ of fragments): "; + +%feature("docstring") gdcm::CSAElement::GetValue "Value& +gdcm::CSAElement::GetValue() "; + +%feature("docstring") gdcm::CSAElement::GetVM "const VM& +gdcm::CSAElement::GetVM() const + +Set/Get VM. "; + +%feature("docstring") gdcm::CSAElement::GetVR "VR const& +gdcm::CSAElement::GetVR() const + +Set/Get VR. "; + +%feature("docstring") gdcm::CSAElement::IsEmpty "bool +gdcm::CSAElement::IsEmpty() const + +Check if CSA Element is empty. "; + +%feature("docstring") gdcm::CSAElement::SetByteValue "void +gdcm::CSAElement::SetByteValue(const char *array, VL length) + +Set. "; + +%feature("docstring") gdcm::CSAElement::SetKey "void +gdcm::CSAElement::SetKey(unsigned int key) "; + +%feature("docstring") gdcm::CSAElement::SetName "void +gdcm::CSAElement::SetName(const char *name) "; + +%feature("docstring") gdcm::CSAElement::SetNoOfItems "void +gdcm::CSAElement::SetNoOfItems(unsigned int items) "; + +%feature("docstring") gdcm::CSAElement::SetSyngoDT "void +gdcm::CSAElement::SetSyngoDT(unsigned int syngodt) "; + +%feature("docstring") gdcm::CSAElement::SetValue "void +gdcm::CSAElement::SetValue(Value const &vl) "; + +%feature("docstring") gdcm::CSAElement::SetVM "void +gdcm::CSAElement::SetVM(const VM &vm) "; + +%feature("docstring") gdcm::CSAElement::SetVR "void +gdcm::CSAElement::SetVR(VR const &vr) "; + + +// File: classgdcm_1_1CSAHeader.xml +%feature("docstring") gdcm::CSAHeader " + +Class for CSAHeader. + +SIEMENS store private information in tag (0x0029,0x10,\"SIEMENS CSA +HEADER\") this class is meant for user wishing to access values stored +within this private attribute. There are basically two main 'format' +for this attribute : SV10/NOMAGIC and DATASET_FORMAT SV10 and NOMAGIC +are from a user prospective identical, see CSAHeader.xml for possible +name / value stored in this format. DATASET_FORMAT is in fact simply +just another DICOM dataset (implicit) with -currently unknown- value. +This can be only be printed for now. + +WARNING: Everything you do with this code is at your own risk, since +decoding process was not written from specification documents. + +the API of this class might change. Todo MrEvaProtocol in 29,1020 +contains ^M that would be nice to get rid of on UNIX system... + +See: PDBHeader External references: 5.1.3.2.4.1 MEDCOM History +Information and 5.1.4.3 CSA Non-Image Module +inhttp://tamsinfo.toshiba.com/docrequest/pdf/E.Soft_v2.0.pdf + +C++ includes: gdcmCSAHeader.h "; + +%feature("docstring") gdcm::CSAHeader::CSAHeader "gdcm::CSAHeader::CSAHeader() "; + +%feature("docstring") gdcm::CSAHeader::~CSAHeader "gdcm::CSAHeader::~CSAHeader() "; + +%feature("docstring") gdcm::CSAHeader::FindCSAElementByName "bool +gdcm::CSAHeader::FindCSAElementByName(const char *name) + +Return true if the CSA element matching 'name' is found or not +WARNING: Case Sensitive "; + +%feature("docstring") gdcm::CSAHeader::GetCSAElementByName "const +CSAElement& gdcm::CSAHeader::GetCSAElementByName(const char *name) + +Return the CSAElement corresponding to name 'name' WARNING: Case +Sensitive "; + +%feature("docstring") gdcm::CSAHeader::GetDataSet "const DataSet& +gdcm::CSAHeader::GetDataSet() const + +Return the DataSet output (use only if Format == DATASET_FORMAT ). "; + +%feature("docstring") gdcm::CSAHeader::GetFormat "CSAHeaderType +gdcm::CSAHeader::GetFormat() const + +return the format of the CSAHeader SV10 and NOMAGIC are equivalent. "; + +%feature("docstring") gdcm::CSAHeader::GetInterfile "const char* +gdcm::CSAHeader::GetInterfile() const + +Return the string output (use only if Format == Interfile). "; + +%feature("docstring") gdcm::CSAHeader::LoadFromDataElement "bool +gdcm::CSAHeader::LoadFromDataElement(DataElement const &de) + +Decode the CSAHeader from element 'de'. "; + +%feature("docstring") gdcm::CSAHeader::Print "void +gdcm::CSAHeader::Print(std::ostream &os) const + +Print the CSAHeader (use only if Format == SV10 or NOMAGIC). "; + +%feature("docstring") gdcm::CSAHeader::Read "std::istream& +gdcm::CSAHeader::Read(std::istream &is) "; + +%feature("docstring") gdcm::CSAHeader::Write "const std::ostream& +gdcm::CSAHeader::Write(std::ostream &os) const "; + + +// File: classgdcm_1_1CSAHeaderDict.xml +%feature("docstring") gdcm::CSAHeaderDict " + +Class to represent a map of CSAHeaderDictEntry. + +C++ includes: gdcmCSAHeaderDict.h "; + +%feature("docstring") gdcm::CSAHeaderDict::CSAHeaderDict "gdcm::CSAHeaderDict::CSAHeaderDict() "; + +%feature("docstring") gdcm::CSAHeaderDict::AddCSAHeaderDictEntry "void gdcm::CSAHeaderDict::AddCSAHeaderDictEntry(const +CSAHeaderDictEntry &de) "; + +%feature("docstring") gdcm::CSAHeaderDict::Begin "ConstIterator +gdcm::CSAHeaderDict::Begin() const "; + +%feature("docstring") gdcm::CSAHeaderDict::End "ConstIterator +gdcm::CSAHeaderDict::End() const "; + +%feature("docstring") gdcm::CSAHeaderDict::GetCSAHeaderDictEntry "const CSAHeaderDictEntry& +gdcm::CSAHeaderDict::GetCSAHeaderDictEntry(const char *name) const "; + +%feature("docstring") gdcm::CSAHeaderDict::IsEmpty "bool +gdcm::CSAHeaderDict::IsEmpty() const "; + + +// File: classgdcm_1_1CSAHeaderDictEntry.xml +%feature("docstring") gdcm::CSAHeaderDictEntry " + +Class to represent an Entry in the Dict Does not really exist within +the DICOM definition, just a way to minimize storage and have a +mapping from gdcm::Tag to the needed information. + +bla TODO FIXME: Need a PublicCSAHeaderDictEntry...indeed +CSAHeaderDictEntry has a notion of retired which does not exist in +PrivateCSAHeaderDictEntry... + +See: gdcm::Dict + +C++ includes: gdcmCSAHeaderDictEntry.h "; + +%feature("docstring") gdcm::CSAHeaderDictEntry::CSAHeaderDictEntry "gdcm::CSAHeaderDictEntry::CSAHeaderDictEntry(const char *name=\"\", VR +const &vr=VR::INVALID, VM const &vm=VM::VM0, const char *desc=\"\") "; + +%feature("docstring") gdcm::CSAHeaderDictEntry::GetDescription "const char* gdcm::CSAHeaderDictEntry::GetDescription() const + +Set/Get Description. "; + +%feature("docstring") gdcm::CSAHeaderDictEntry::GetName "const char* +gdcm::CSAHeaderDictEntry::GetName() const + +Set/Get Name. "; + +%feature("docstring") gdcm::CSAHeaderDictEntry::GetVM "const VM& +gdcm::CSAHeaderDictEntry::GetVM() const + +Set/Get VM. "; + +%feature("docstring") gdcm::CSAHeaderDictEntry::GetVR "const VR& +gdcm::CSAHeaderDictEntry::GetVR() const + +Set/Get VR. "; + +%feature("docstring") gdcm::CSAHeaderDictEntry::SetDescription "void +gdcm::CSAHeaderDictEntry::SetDescription(const char *desc) "; + +%feature("docstring") gdcm::CSAHeaderDictEntry::SetName "void +gdcm::CSAHeaderDictEntry::SetName(const char *name) "; + +%feature("docstring") gdcm::CSAHeaderDictEntry::SetVM "void +gdcm::CSAHeaderDictEntry::SetVM(VM const &vm) "; + +%feature("docstring") gdcm::CSAHeaderDictEntry::SetVR "void +gdcm::CSAHeaderDictEntry::SetVR(const VR &vr) "; + + +// File: classgdcm_1_1CSAHeaderDictException.xml +%feature("docstring") gdcm::CSAHeaderDictException "C++ includes: +gdcmCSAHeaderDict.h "; + + +// File: classgdcm_1_1network_1_1CStoreRQ.xml +%feature("docstring") gdcm::network::CStoreRQ " + +CStoreRQ this file defines the messages for the cecho action. + +C++ includes: gdcmCStoreMessages.h "; + +%feature("docstring") gdcm::network::CStoreRQ::ConstructPDV "std::vector +gdcm::network::CStoreRQ::ConstructPDV(const ULConnection +&inConnection, const File &file) "; + + +// File: classgdcm_1_1network_1_1CStoreRSP.xml +%feature("docstring") gdcm::network::CStoreRSP " + +CStoreRSP this file defines the messages for the cecho action. + +C++ includes: gdcmCStoreMessages.h "; + +%feature("docstring") gdcm::network::CStoreRSP::ConstructPDV "std::vector +gdcm::network::CStoreRSP::ConstructPDV(const DataSet *inDataSet, const +BasePDU *inPC) "; + + +// File: classgdcm_1_1Curve.xml +%feature("docstring") gdcm::Curve " + +Curve class to handle element 50xx,3000 Curve Data WARNING: This is +deprecated and lastly defined in PS 3.3 - 2004. + +Examples: GE_DLX-8-MONO2-Multiframe-Jpeg_Lossless.dcm + +GE_DLX-8-MONO2-Multiframe.dcm + +gdcmSampleData/Philips_Medical_Images/integris_HV_5000/xa_integris.dcm + +TOSHIBA-CurveData[1-3].dcm + +C++ includes: gdcmCurve.h "; + +%feature("docstring") gdcm::Curve::Curve "gdcm::Curve::Curve() "; + +%feature("docstring") gdcm::Curve::Curve "gdcm::Curve::Curve(Curve +const &ov) "; + +%feature("docstring") gdcm::Curve::~Curve "gdcm::Curve::~Curve() "; + +%feature("docstring") gdcm::Curve::Decode "void +gdcm::Curve::Decode(std::istream &is, std::ostream &os) "; + +%feature("docstring") gdcm::Curve::GetAsPoints "void +gdcm::Curve::GetAsPoints(float *array) const "; + +%feature("docstring") gdcm::Curve::GetCurveDataDescriptor "std::vector const& +gdcm::Curve::GetCurveDataDescriptor() const "; + +%feature("docstring") gdcm::Curve::GetDataValueRepresentation "unsigned short gdcm::Curve::GetDataValueRepresentation() const "; + +%feature("docstring") gdcm::Curve::GetDimensions "unsigned short +gdcm::Curve::GetDimensions() const "; + +%feature("docstring") gdcm::Curve::GetGroup "unsigned short +gdcm::Curve::GetGroup() const "; + +%feature("docstring") gdcm::Curve::GetNumberOfPoints "unsigned short +gdcm::Curve::GetNumberOfPoints() const "; + +%feature("docstring") gdcm::Curve::GetTypeOfData "const char* +gdcm::Curve::GetTypeOfData() const "; + +%feature("docstring") gdcm::Curve::GetTypeOfDataDescription "const +char* gdcm::Curve::GetTypeOfDataDescription() const "; + +%feature("docstring") gdcm::Curve::IsEmpty "bool +gdcm::Curve::IsEmpty() const "; + +%feature("docstring") gdcm::Curve::Print "void +gdcm::Curve::Print(std::ostream &) const "; + +%feature("docstring") gdcm::Curve::SetCoordinateStartValue "void +gdcm::Curve::SetCoordinateStartValue(unsigned short v) "; + +%feature("docstring") gdcm::Curve::SetCoordinateStepValue "void +gdcm::Curve::SetCoordinateStepValue(unsigned short v) "; + +%feature("docstring") gdcm::Curve::SetCurve "void +gdcm::Curve::SetCurve(const char *array, unsigned int length) "; + +%feature("docstring") gdcm::Curve::SetCurveDataDescriptor "void +gdcm::Curve::SetCurveDataDescriptor(const uint16_t *values, size_t +num) "; + +%feature("docstring") gdcm::Curve::SetCurveDescription "void +gdcm::Curve::SetCurveDescription(const char *curvedescription) "; + +%feature("docstring") gdcm::Curve::SetDataValueRepresentation "void +gdcm::Curve::SetDataValueRepresentation(unsigned short +datavaluerepresentation) "; + +%feature("docstring") gdcm::Curve::SetDimensions "void +gdcm::Curve::SetDimensions(unsigned short dimensions) "; + +%feature("docstring") gdcm::Curve::SetGroup "void +gdcm::Curve::SetGroup(unsigned short group) "; + +%feature("docstring") gdcm::Curve::SetNumberOfPoints "void +gdcm::Curve::SetNumberOfPoints(unsigned short numberofpoints) "; + +%feature("docstring") gdcm::Curve::SetTypeOfData "void +gdcm::Curve::SetTypeOfData(const char *typeofdata) "; + +%feature("docstring") gdcm::Curve::Update "void +gdcm::Curve::Update(const DataElement &de) "; + + +// File: classgdcm_1_1DataElement.xml +%feature("docstring") gdcm::DataElement " + +Class to represent a Data Element either Implicit or Explicit. + +DATA ELEMENT: A unit of information as defined by a single entry in +the data dictionary. An encoded Information Object Definition ( IOD) +Attribute that is composed of, at a minimum, three fields: a Data +Element Tag, a Value Length, and a Value Field. For some specific +Transfer Syntaxes, a Data Element also contains a VR Field where the +Value Representation of that Data Element is specified explicitly. + +Design: A DataElement in GDCM always store VL ( Value Length) on a 32 +bits integer even when VL is 16 bits + +A DataElement always store the VR even for Implicit TS, in which case +VR is defaulted to VR::INVALID + +For Item start/end (See 0xfffe tags), Value is NULL + +See: ExplicitDataElement ImplicitDataElement + +C++ includes: gdcmDataElement.h "; + +%feature("docstring") gdcm::DataElement::DataElement "gdcm::DataElement::DataElement(const Tag &t=Tag(0), const VL &vl=0, +const VR &vr=VR::INVALID) "; + +%feature("docstring") gdcm::DataElement::DataElement "gdcm::DataElement::DataElement(const DataElement &_val) "; + +%feature("docstring") gdcm::DataElement::Clear "void +gdcm::DataElement::Clear() + +Clear Data Element (make Value empty and invalidate Tag & VR). "; + +%feature("docstring") gdcm::DataElement::Empty "void +gdcm::DataElement::Empty() + +Make Data Element empty (no Value). "; + +%feature("docstring") gdcm::DataElement::GetByteValue "const +ByteValue* gdcm::DataElement::GetByteValue() const + +Return the Value of DataElement as a ByteValue (if possible) WARNING: +: You need to check for NULL return value "; + +%feature("docstring") gdcm::DataElement::GetLength "VL +gdcm::DataElement::GetLength() const "; + +%feature("docstring") gdcm::DataElement::GetSequenceOfFragments "const SequenceOfFragments* gdcm::DataElement::GetSequenceOfFragments() +const + +Return the Value of DataElement as a Sequence Of Fragments (if +possible) WARNING: : You need to check for NULL return value "; + +%feature("docstring") gdcm::DataElement::GetSequenceOfItems "const +SequenceOfItems* gdcm::DataElement::GetSequenceOfItems() const + +Return the Value of DataElement as a Sequence Of Items (if possible) +WARNING: : You need to check for NULL return value + +: In some case a Value could not have been recognized as a +SequenceOfItems in those case the return of the function will be NULL, +while the Value would be a valid SequenceOfItems, in those case prefer +GetValueAsSQ. In which case the code internally trigger an assert to +warn developper. When in doubt do not use this function and prefer +GetValueAsSQ() Deprecated Replaced by DataElement::GetValueAsSQ() as +of GDCM 2.2. "; + +%feature("docstring") gdcm::DataElement::GetSequenceOfItems "SequenceOfItems* gdcm::DataElement::GetSequenceOfItems() "; + +%feature("docstring") gdcm::DataElement::GetTag "const Tag& +gdcm::DataElement::GetTag() const + +Get Tag. "; + +%feature("docstring") gdcm::DataElement::GetTag "Tag& +gdcm::DataElement::GetTag() "; + +%feature("docstring") gdcm::DataElement::GetValue "Value const& +gdcm::DataElement::GetValue() const + +Set/Get Value (bytes array, SQ of items, SQ of fragments): "; + +%feature("docstring") gdcm::DataElement::GetValue "Value& +gdcm::DataElement::GetValue() "; + +%feature("docstring") gdcm::DataElement::GetValueAsSQ "SmartPointer gdcm::DataElement::GetValueAsSQ() const + +Interpret the Value stored in the DataElement. This is more robust +(but also more expensive) to call this function rather than the +simpliest form: GetSequenceOfItems() It also return NULL when the +Value is NOT of type SequenceOfItems WARNING: in case +GetSequenceOfItems() succeed the function return this value, otherwise +it creates a new SequenceOfItems, you should handle that in your case, +for instance: SmartPointer sqi = de.GetValueAsSQ(); +"; + +%feature("docstring") gdcm::DataElement::GetVL "const VL& +gdcm::DataElement::GetVL() const + +Get VL. "; + +%feature("docstring") gdcm::DataElement::GetVL "VL& +gdcm::DataElement::GetVL() "; + +%feature("docstring") gdcm::DataElement::GetVR "VR const& +gdcm::DataElement::GetVR() const + +Get VR do not set VR::SQ on bytevalue data element "; + +%feature("docstring") gdcm::DataElement::IsEmpty "bool +gdcm::DataElement::IsEmpty() const + +Check if Data Element is empty. "; + +%feature("docstring") gdcm::DataElement::IsUndefinedLength "bool +gdcm::DataElement::IsUndefinedLength() const + +return if Value Length if of undefined length "; + +%feature("docstring") gdcm::DataElement::Read "std::istream& +gdcm::DataElement::Read(std::istream &is) "; + +%feature("docstring") gdcm::DataElement::ReadOrSkip "std::istream& +gdcm::DataElement::ReadOrSkip(std::istream &is, std::set< Tag > const +&skiptags) "; + +%feature("docstring") gdcm::DataElement::ReadPreValue "std::istream& +gdcm::DataElement::ReadPreValue(std::istream &is, std::set< Tag > +const &skiptags) "; + +%feature("docstring") gdcm::DataElement::ReadValue "std::istream& +gdcm::DataElement::ReadValue(std::istream &is, std::set< Tag > const +&skiptags) "; + +%feature("docstring") gdcm::DataElement::ReadWithLength "std::istream& gdcm::DataElement::ReadWithLength(std::istream &is, VL +&length) "; + +%feature("docstring") gdcm::DataElement::SetByteValue "void +gdcm::DataElement::SetByteValue(const char *array, VL length) + +Set the byte value WARNING: user need to read DICOM standard for an +understanding of: even padding vs space padding By default even +padding is achieved using regardless of the of VR "; + +%feature("docstring") gdcm::DataElement::SetTag "void +gdcm::DataElement::SetTag(const Tag &t) + +Set Tag Use with cautious (need to match Part 6) "; + +%feature("docstring") gdcm::DataElement::SetValue "void +gdcm::DataElement::SetValue(Value const &vl) + +WARNING: you need to set the ValueLengthField explicitely "; + +%feature("docstring") gdcm::DataElement::SetVL "void +gdcm::DataElement::SetVL(const VL &vl) + +Set VL Use with cautious (need to match Part 6), advanced user only +See: SetByteValue "; + +%feature("docstring") gdcm::DataElement::SetVLToUndefined "void +gdcm::DataElement::SetVLToUndefined() "; + +%feature("docstring") gdcm::DataElement::SetVR "void +gdcm::DataElement::SetVR(VR const &vr) + +Set VR Use with cautious (need to match Part 6), advanced user only vr +is a VR::VRALL (not a dual one such as OB_OW) "; + +%feature("docstring") gdcm::DataElement::Write "const std::ostream& +gdcm::DataElement::Write(std::ostream &os) const "; + + +// File: classgdcm_1_1DataElementException.xml +%feature("docstring") gdcm::DataElementException "C++ includes: +gdcmDataSet.h "; + + +// File: classgdcm_1_1DataEvent.xml +%feature("docstring") gdcm::DataEvent " + +DataEvent. + +C++ includes: gdcmDataEvent.h "; + +%feature("docstring") gdcm::DataEvent::DataEvent "gdcm::DataEvent::DataEvent(const char *bytes=0, size_t len=0) "; + +%feature("docstring") gdcm::DataEvent::DataEvent "gdcm::DataEvent::DataEvent(const Self &s) "; + +%feature("docstring") gdcm::DataEvent::~DataEvent "virtual +gdcm::DataEvent::~DataEvent() "; + +%feature("docstring") gdcm::DataEvent::CheckEvent "virtual bool +gdcm::DataEvent::CheckEvent(const ::gdcm::Event *e) const "; + +%feature("docstring") gdcm::DataEvent::GetData "const char* +gdcm::DataEvent::GetData() const "; + +%feature("docstring") gdcm::DataEvent::GetDataLength "size_t +gdcm::DataEvent::GetDataLength() const "; + +%feature("docstring") gdcm::DataEvent::GetEventName "virtual const +char* gdcm::DataEvent::GetEventName() const + +Return the StringName associated with the event. "; + +%feature("docstring") gdcm::DataEvent::MakeObject "virtual +::gdcm::Event* gdcm::DataEvent::MakeObject() const + +Create an Event of this type This method work as a Factory for +creating events of each particular type. "; + +%feature("docstring") gdcm::DataEvent::SetData "void +gdcm::DataEvent::SetData(const char *bytes, size_t len) "; + + +// File: classgdcm_1_1DataSet.xml +%feature("docstring") gdcm::DataSet " + +Class to represent a Data Set (which contains Data Elements) A Data +Set represents an instance of a real world Information Object. + +DATA SET: Exchanged information consisting of a structured set of +Attribute values directly or indirectly related to Information +Objects. The value of each Attribute in a Data Set is expressed as a +Data Element. A collection of Data Elements ordered by increasing Data +Element Tag number that is an encoding of the values of Attributes of +a real world object. + +Implementation note. If one do: DataSet ds; ds.SetLength(0); +ds.Read(is); setting length to 0 actually means try to read is as if +it was a root DataSet. Other value are undefined (nested dataset with +undefined length) or defined length (different from 0) means nested +dataset with defined length. + +WARNING: a DataSet does not have a Transfer Syntax type, only a File +does. + +C++ includes: gdcmDataSet.h "; + +%feature("docstring") gdcm::DataSet::Begin "ConstIterator +gdcm::DataSet::Begin() const "; + +%feature("docstring") gdcm::DataSet::Begin "Iterator +gdcm::DataSet::Begin() "; + +%feature("docstring") gdcm::DataSet::Clear "void +gdcm::DataSet::Clear() "; + +%feature("docstring") gdcm::DataSet::ComputeGroupLength "unsigned +int gdcm::DataSet::ComputeGroupLength(Tag const &tag) const "; + +%feature("docstring") gdcm::DataSet::End "Iterator +gdcm::DataSet::End() "; + +%feature("docstring") gdcm::DataSet::End "ConstIterator +gdcm::DataSet::End() const "; + +%feature("docstring") gdcm::DataSet::FindDataElement "bool +gdcm::DataSet::FindDataElement(const PrivateTag &t) const + +Look up if private tag 't' is present in the dataset: "; + +%feature("docstring") gdcm::DataSet::FindDataElement "bool +gdcm::DataSet::FindDataElement(const Tag &t) const "; + +%feature("docstring") gdcm::DataSet::FindNextDataElement "const +DataElement& gdcm::DataSet::FindNextDataElement(const Tag &t) const "; + +%feature("docstring") gdcm::DataSet::GetDataElement "const +DataElement& gdcm::DataSet::GetDataElement(const Tag &t) const + +Return the DataElement with Tag 't' WARNING: : This only search at +the 'root level' of the DataSet "; + +%feature("docstring") gdcm::DataSet::GetDataElement "const +DataElement& gdcm::DataSet::GetDataElement(const PrivateTag &t) const + +Return the dataelement. "; + +%feature("docstring") gdcm::DataSet::GetDES "const DataElementSet& +gdcm::DataSet::GetDES() const "; + +%feature("docstring") gdcm::DataSet::GetDES "DataElementSet& +gdcm::DataSet::GetDES() "; + +%feature("docstring") gdcm::DataSet::GetLength "VL +gdcm::DataSet::GetLength() const "; + +%feature("docstring") gdcm::DataSet::GetMediaStorage "MediaStorage +gdcm::DataSet::GetMediaStorage() const "; + +%feature("docstring") gdcm::DataSet::GetPrivateCreator "std::string +gdcm::DataSet::GetPrivateCreator(const Tag &t) const + +Return the private creator of the private tag 't': "; + +%feature("docstring") gdcm::DataSet::Insert "void +gdcm::DataSet::Insert(const DataElement &de) + +Insert a DataElement in the DataSet. WARNING: : Tag need to be >= 0x8 +to be considered valid data element "; + +%feature("docstring") gdcm::DataSet::IsEmpty "bool +gdcm::DataSet::IsEmpty() const + +Returns if the dataset is empty. "; + +%feature("docstring") gdcm::DataSet::Print "void +gdcm::DataSet::Print(std::ostream &os, std::string const &indent=\"\") +const "; + +%feature("docstring") gdcm::DataSet::Read "std::istream& +gdcm::DataSet::Read(std::istream &is) "; + +%feature("docstring") gdcm::DataSet::ReadNested "std::istream& +gdcm::DataSet::ReadNested(std::istream &is) "; + +%feature("docstring") gdcm::DataSet::ReadSelectedTags "std::istream& +gdcm::DataSet::ReadSelectedTags(std::istream &is, const std::set< Tag +> &tags) "; + +%feature("docstring") gdcm::DataSet::ReadSelectedTagsWithLength "std::istream& gdcm::DataSet::ReadSelectedTagsWithLength(std::istream +&is, const std::set< Tag > &tags, VL &length) "; + +%feature("docstring") gdcm::DataSet::ReadUpToTag "std::istream& +gdcm::DataSet::ReadUpToTag(std::istream &is, const Tag &t, std::set< +Tag > const &skiptags) "; + +%feature("docstring") gdcm::DataSet::ReadUpToTagWithLength "std::istream& gdcm::DataSet::ReadUpToTagWithLength(std::istream &is, +const Tag &t, VL &length) "; + +%feature("docstring") gdcm::DataSet::ReadWithLength "std::istream& +gdcm::DataSet::ReadWithLength(std::istream &is, VL &length) "; + +%feature("docstring") gdcm::DataSet::Remove "SizeType +gdcm::DataSet::Remove(const Tag &tag) + +Completely remove a dataelement from the dataset. "; + +%feature("docstring") gdcm::DataSet::Replace "void +gdcm::DataSet::Replace(const DataElement &de) + +Replace a dataelement with another one. "; + +%feature("docstring") gdcm::DataSet::ReplaceEmpty "void +gdcm::DataSet::ReplaceEmpty(const DataElement &de) + +Only replace a DICOM attribute when it is missing or empty. "; + +%feature("docstring") gdcm::DataSet::Size "SizeType +gdcm::DataSet::Size() const "; + +%feature("docstring") gdcm::DataSet::Write "std::ostream const& +gdcm::DataSet::Write(std::ostream &os) const "; + + +// File: classgdcm_1_1DataSetEvent.xml +%feature("docstring") gdcm::DataSetEvent " + +DataSetEvent Special type of event triggered during the DataSet +store/move process. + +See: + +C++ includes: gdcmDataSetEvent.h "; + +%feature("docstring") gdcm::DataSetEvent::DataSetEvent "gdcm::DataSetEvent::DataSetEvent(DataSet const *ds=NULL) "; + +%feature("docstring") gdcm::DataSetEvent::DataSetEvent "gdcm::DataSetEvent::DataSetEvent(const Self &s) "; + +%feature("docstring") gdcm::DataSetEvent::~DataSetEvent "virtual +gdcm::DataSetEvent::~DataSetEvent() "; + +%feature("docstring") gdcm::DataSetEvent::CheckEvent "virtual bool +gdcm::DataSetEvent::CheckEvent(const ::gdcm::Event *e) const "; + +%feature("docstring") gdcm::DataSetEvent::GetDataSet "DataSet const& +gdcm::DataSetEvent::GetDataSet() const "; + +%feature("docstring") gdcm::DataSetEvent::GetEventName "virtual +const char* gdcm::DataSetEvent::GetEventName() const + +Return the StringName associated with the event. "; + +%feature("docstring") gdcm::DataSetEvent::MakeObject "virtual +::gdcm::Event* gdcm::DataSetEvent::MakeObject() const + +Create an Event of this type This method work as a Factory for +creating events of each particular type. "; + + +// File: classgdcm_1_1DataSetHelper.xml +%feature("docstring") gdcm::DataSetHelper " + +DataSetHelper (internal class, not intended for user level). + +C++ includes: gdcmDataSetHelper.h "; + + +// File: classgdcm_1_1Decoder.xml +%feature("docstring") gdcm::Decoder " + +Decoder. + +C++ includes: gdcmDecoder.h "; + +%feature("docstring") gdcm::Decoder::~Decoder "virtual +gdcm::Decoder::~Decoder() "; + +%feature("docstring") gdcm::Decoder::CanDecode "virtual bool +gdcm::Decoder::CanDecode(TransferSyntax const &) const =0 + +Return whether this decoder support this transfer syntax (can decode +it). "; + +%feature("docstring") gdcm::Decoder::Decode "virtual bool +gdcm::Decoder::Decode(DataElement const &, DataElement &) + +Decode. "; + + +// File: classgdcm_1_1DefinedTerms.xml +%feature("docstring") gdcm::DefinedTerms " + +Defined Terms are used when the specified explicit Values may be +extended by implementors to include additional new Values. These new +Values shall be specified in the Conformance Statement (see PS 3.2) +and shall not have the same meaning as currently defined Values in +this standard. A Data Element with Defined Terms that does not contain +a Value equivalent to one of the Values currently specified in this +standard shall not be considered to have an invalid value. Note: +Interpretation Type ID (4008,0210) is an example of a Data Element +having Defined Terms. It is defined to have a Value that may be one of +the set of standard Values; REPORT or AMENDMENT (see PS 3.3). Because +this Data Element has Defined Terms other Interpretation Type IDs may +be defined by the implementor. + +C++ includes: gdcmDefinedTerms.h "; + +%feature("docstring") gdcm::DefinedTerms::DefinedTerms "gdcm::DefinedTerms::DefinedTerms() "; + + +// File: classgdcm_1_1Defs.xml +%feature("docstring") gdcm::Defs " + +FIXME I do not like the name 'Defs'. + +bla + +C++ includes: gdcmDefs.h "; + +%feature("docstring") gdcm::Defs::Defs "gdcm::Defs::Defs() "; + +%feature("docstring") gdcm::Defs::~Defs "gdcm::Defs::~Defs() "; + +%feature("docstring") gdcm::Defs::GetIODFromFile "const IOD& +gdcm::Defs::GetIODFromFile(const File &file) const "; + +%feature("docstring") gdcm::Defs::GetIODs "IODs& +gdcm::Defs::GetIODs() "; + +%feature("docstring") gdcm::Defs::GetIODs "const IODs& +gdcm::Defs::GetIODs() const "; + +%feature("docstring") gdcm::Defs::GetMacros "const Macros& +gdcm::Defs::GetMacros() const + +Users should not directly use Macro. Macro are simply a way for DICOM +WG to re-use Tables. Macros are conviently wraped within Modules. See +gdcm::Module API directly "; + +%feature("docstring") gdcm::Defs::GetMacros "Macros& +gdcm::Defs::GetMacros() "; + +%feature("docstring") gdcm::Defs::GetModules "const Modules& +gdcm::Defs::GetModules() const "; + +%feature("docstring") gdcm::Defs::GetModules "Modules& +gdcm::Defs::GetModules() "; + +%feature("docstring") gdcm::Defs::GetTypeFromTag "Type +gdcm::Defs::GetTypeFromTag(const File &file, const Tag &tag) const "; + +%feature("docstring") gdcm::Defs::IsEmpty "bool +gdcm::Defs::IsEmpty() const "; + +%feature("docstring") gdcm::Defs::Verify "bool +gdcm::Defs::Verify(const DataSet &ds) const "; + +%feature("docstring") gdcm::Defs::Verify "bool +gdcm::Defs::Verify(const File &file) const "; + + +// File: classgdcm_1_1DeltaEncodingCodec.xml +%feature("docstring") gdcm::DeltaEncodingCodec " + +DeltaEncodingCodec compression used by some private vendor. + +C++ includes: gdcmDeltaEncodingCodec.h "; + +%feature("docstring") gdcm::DeltaEncodingCodec::DeltaEncodingCodec "gdcm::DeltaEncodingCodec::DeltaEncodingCodec() "; + +%feature("docstring") gdcm::DeltaEncodingCodec::~DeltaEncodingCodec "gdcm::DeltaEncodingCodec::~DeltaEncodingCodec() "; + +%feature("docstring") gdcm::DeltaEncodingCodec::CanDecode "bool +gdcm::DeltaEncodingCodec::CanDecode(TransferSyntax const &ts) "; + +%feature("docstring") gdcm::DeltaEncodingCodec::Decode "bool +gdcm::DeltaEncodingCodec::Decode(DataElement const &is, DataElement +&os) + +Decode. "; + + +// File: classstd_1_1deque.xml +%feature("docstring") std::deque " + +STL class. "; + + +// File: classgdcm_1_1DICOMDIR.xml +%feature("docstring") gdcm::DICOMDIR " + +DICOMDIR class. + +Structured for handling DICOMDIR + +C++ includes: gdcmDICOMDIR.h "; + +%feature("docstring") gdcm::DICOMDIR::DICOMDIR "gdcm::DICOMDIR::DICOMDIR() "; + +%feature("docstring") gdcm::DICOMDIR::DICOMDIR "gdcm::DICOMDIR::DICOMDIR(const FileSet &fs) "; + + +// File: classgdcm_1_1DICOMDIRGenerator.xml +%feature("docstring") gdcm::DICOMDIRGenerator " + +DICOMDIRGenerator class This is a STD-GEN-CD DICOMDIR generator. ref: +PS 3.11-2008 Annex D (Normative) - General Purpose CD-R and DVD +Interchange Profiles. + +PS 3.11 - 2008 / D.3.2 Physical Medium And Medium Format The STD-GEN- +CD and STD-GEN-SEC-CD application profiles require the 120 mm CD-R +physical medium with the ISO/IEC 9660 Media Format, as defined in +PS3.12. See also PS 3.12 - 2008 / Annex F 120mm CD-R Medium +(Normative) and PS 3.10 - 2008 / 8 DICOM File Service / 8.1 FILE-SET + +WARNING: : PS 3.11 - 2008 / D.3.1 SOP Classes and Transfer Syntaxes +Composite Image & Stand-alone Storage are required to be stored as +Explicit VR Little Endian Uncompressed (1.2.840.10008.1.2.1). When a +DICOM file is found using another Transfer Syntax the generator will +simply stops. + +Input files should be Explicit VR Little Endian + +filenames should be valid VR::CS value (16 bytes, upper case ...) + +Bug : There is a current limitation of not handling Referenced SOP +Class UID / Referenced SOP Instance UID simply because the +gdcm::Scanner does not allow us See PS 3.11 / Table D.3-2 STD-GEN +Additional DICOMDIR Keys + +C++ includes: gdcmDICOMDIRGenerator.h "; + +%feature("docstring") gdcm::DICOMDIRGenerator::DICOMDIRGenerator "gdcm::DICOMDIRGenerator::DICOMDIRGenerator() "; + +%feature("docstring") gdcm::DICOMDIRGenerator::~DICOMDIRGenerator "gdcm::DICOMDIRGenerator::~DICOMDIRGenerator() "; + +%feature("docstring") gdcm::DICOMDIRGenerator::Generate "bool +gdcm::DICOMDIRGenerator::Generate() + +Main function to generate the DICOMDIR. "; + +%feature("docstring") gdcm::DICOMDIRGenerator::GetFile "File& +gdcm::DICOMDIRGenerator::GetFile() "; + +%feature("docstring") gdcm::DICOMDIRGenerator::SetDescriptor "void +gdcm::DICOMDIRGenerator::SetDescriptor(const char *d) + +Set the File Set ID. WARNING: this need to be a valid VR::CS value "; + +%feature("docstring") gdcm::DICOMDIRGenerator::SetFile "void +gdcm::DICOMDIRGenerator::SetFile(const File &f) + +Set/Get file. The DICOMDIR file will be valid once a call to Generate +has been done. "; + +%feature("docstring") gdcm::DICOMDIRGenerator::SetFilenames "void +gdcm::DICOMDIRGenerator::SetFilenames(FilenamesType const &fns) + +Set the list of filenames from which the DICOMDIR should be generated +from. "; + +%feature("docstring") gdcm::DICOMDIRGenerator::SetRootDirectory "void gdcm::DICOMDIRGenerator::SetRootDirectory(FilenameType const +&root) + +Set the root directory from which the filenames should be considered. +"; + + +// File: classgdcm_1_1Dict.xml +%feature("docstring") gdcm::Dict " + +Class to represent a map of DictEntry. + +bla TODO FIXME: For Element == 0x0 need to return Name = Group Length +ValueRepresentation = UL ValueMultiplicity = 1 + +C++ includes: gdcmDict.h "; + +%feature("docstring") gdcm::Dict::Dict "gdcm::Dict::Dict() "; + +%feature("docstring") gdcm::Dict::AddDictEntry "void +gdcm::Dict::AddDictEntry(const Tag &tag, const DictEntry &de) "; + +%feature("docstring") gdcm::Dict::Begin "ConstIterator +gdcm::Dict::Begin() const "; + +%feature("docstring") gdcm::Dict::End "ConstIterator +gdcm::Dict::End() const "; + +%feature("docstring") gdcm::Dict::GetDictEntry "const DictEntry& +gdcm::Dict::GetDictEntry(const Tag &tag) const "; + +%feature("docstring") gdcm::Dict::GetDictEntryByKeyword "const +DictEntry& gdcm::Dict::GetDictEntryByKeyword(const char *keyword, Tag +&tag) const + +Lookup DictEntry by keyword. Even if DICOM standard defines keyword as +being unique. The lookup table is built on Tag. Therefore looking up a +DictEntry by Keyword is more inefficient than looking up by Tag. "; + +%feature("docstring") gdcm::Dict::GetDictEntryByName "const +DictEntry& gdcm::Dict::GetDictEntryByName(const char *name, Tag &tag) +const + +Inefficient way of looking up tag by name. Technically DICOM does not +garantee uniqueness (and Curve / Overlay are there to prove it). But +most of the time name is in fact uniq and can be uniquely link to a +tag "; + +%feature("docstring") gdcm::Dict::GetKeywordFromTag "const char* +gdcm::Dict::GetKeywordFromTag(Tag const &tag) const + +Function to return the Keyword from a Tag. "; + +%feature("docstring") gdcm::Dict::IsEmpty "bool +gdcm::Dict::IsEmpty() const "; + + +// File: classgdcm_1_1DictConverter.xml +%feature("docstring") gdcm::DictConverter " + +Class to convert a .dic file into something else: CXX code : embeded +dict into shared lib (DICT_DEFAULT) + +Debug mode (DICT_DEBUG) + +XML dict (DICT_XML). + +C++ includes: gdcmDictConverter.h "; + +%feature("docstring") gdcm::DictConverter::DictConverter "gdcm::DictConverter::DictConverter() "; + +%feature("docstring") gdcm::DictConverter::~DictConverter "gdcm::DictConverter::~DictConverter() "; + +%feature("docstring") gdcm::DictConverter::Convert "void +gdcm::DictConverter::Convert() "; + +%feature("docstring") gdcm::DictConverter::GetDictName "const +std::string& gdcm::DictConverter::GetDictName() const "; + +%feature("docstring") gdcm::DictConverter::GetInputFilename "const +std::string& gdcm::DictConverter::GetInputFilename() const "; + +%feature("docstring") gdcm::DictConverter::GetOutputFilename "const +std::string& gdcm::DictConverter::GetOutputFilename() const "; + +%feature("docstring") gdcm::DictConverter::GetOutputType "int +gdcm::DictConverter::GetOutputType() const "; + +%feature("docstring") gdcm::DictConverter::SetDictName "void +gdcm::DictConverter::SetDictName(const char *name) "; + +%feature("docstring") gdcm::DictConverter::SetInputFileName "void +gdcm::DictConverter::SetInputFileName(const char *filename) "; + +%feature("docstring") gdcm::DictConverter::SetOutputFileName "void +gdcm::DictConverter::SetOutputFileName(const char *filename) "; + +%feature("docstring") gdcm::DictConverter::SetOutputType "void +gdcm::DictConverter::SetOutputType(int type) "; + + +// File: classgdcm_1_1DictEntry.xml +%feature("docstring") gdcm::DictEntry " + +Class to represent an Entry in the Dict Does not really exist within +the DICOM definition, just a way to minimize storage and have a +mapping from gdcm::Tag to the needed information. + +bla TODO FIXME: Need a PublicDictEntry...indeed DictEntry has a notion +of retired which does not exist in PrivateDictEntry... + +See: gdcm::Dict + +C++ includes: gdcmDictEntry.h "; + +%feature("docstring") gdcm::DictEntry::DictEntry "gdcm::DictEntry::DictEntry(const char *name=\"\", const char +*keyword=\"\", VR const &vr=VR::INVALID, VM const &vm=VM::VM0, bool +ret=false) "; + +%feature("docstring") gdcm::DictEntry::GetKeyword "const char* +gdcm::DictEntry::GetKeyword() const + +same as GetName but without spaces... "; + +%feature("docstring") gdcm::DictEntry::GetName "const char* +gdcm::DictEntry::GetName() const + +Set/Get Name. "; + +%feature("docstring") gdcm::DictEntry::GetRetired "bool +gdcm::DictEntry::GetRetired() const + +Set/Get Retired flag. "; + +%feature("docstring") gdcm::DictEntry::GetVM "const VM& +gdcm::DictEntry::GetVM() const + +Set/Get VM. "; + +%feature("docstring") gdcm::DictEntry::GetVR "const VR& +gdcm::DictEntry::GetVR() const + +Set/Get VR. "; + +%feature("docstring") gdcm::DictEntry::IsUnique "bool +gdcm::DictEntry::IsUnique() const + +Return whether the name of the DataElement can be considered to be +unique. As of 2008 all elements name were unique (except the +expclitely 'XX' ones) "; + +%feature("docstring") gdcm::DictEntry::SetElementXX "void +gdcm::DictEntry::SetElementXX(bool v) + +Set whether element is shared in multiple elements (Source Image IDs +typically). "; + +%feature("docstring") gdcm::DictEntry::SetGroupXX "void +gdcm::DictEntry::SetGroupXX(bool v) + +Set whether element is shared in multiple groups (Curve/Overlay +typically). "; + +%feature("docstring") gdcm::DictEntry::SetKeyword "void +gdcm::DictEntry::SetKeyword(const char *keyword) "; + +%feature("docstring") gdcm::DictEntry::SetName "void +gdcm::DictEntry::SetName(const char *name) "; + +%feature("docstring") gdcm::DictEntry::SetRetired "void +gdcm::DictEntry::SetRetired(bool retired) "; + +%feature("docstring") gdcm::DictEntry::SetVM "void +gdcm::DictEntry::SetVM(VM const &vm) "; + +%feature("docstring") gdcm::DictEntry::SetVR "void +gdcm::DictEntry::SetVR(const VR &vr) "; + + +// File: classgdcm_1_1DictPrinter.xml +%feature("docstring") gdcm::DictPrinter " + +DictPrinter class. + +C++ includes: gdcmDictPrinter.h "; + +%feature("docstring") gdcm::DictPrinter::DictPrinter "gdcm::DictPrinter::DictPrinter() "; + +%feature("docstring") gdcm::DictPrinter::~DictPrinter "gdcm::DictPrinter::~DictPrinter() "; + +%feature("docstring") gdcm::DictPrinter::Print "void +gdcm::DictPrinter::Print(std::ostream &os) + +Print. "; + + +// File: classgdcm_1_1Dicts.xml +%feature("docstring") gdcm::Dicts " + +Class to manipulate the sum of knowledge (all the dict user load). + +bla + +C++ includes: gdcmDicts.h "; + +%feature("docstring") gdcm::Dicts::Dicts "gdcm::Dicts::Dicts() "; + +%feature("docstring") gdcm::Dicts::~Dicts "gdcm::Dicts::~Dicts() "; + +%feature("docstring") gdcm::Dicts::GetCSAHeaderDict "const +CSAHeaderDict& gdcm::Dicts::GetCSAHeaderDict() const "; + +%feature("docstring") gdcm::Dicts::GetDictEntry "const DictEntry& +gdcm::Dicts::GetDictEntry(const PrivateTag &tag) const "; + +%feature("docstring") gdcm::Dicts::GetDictEntry "const DictEntry& +gdcm::Dicts::GetDictEntry(const Tag &tag, const char *owner=NULL) +const + +works for both public and private dicts: owner is null for public dict +WARNING: owner need to be set to appropriate owner for call to work. +see "; + +%feature("docstring") gdcm::Dicts::GetPrivateDict "PrivateDict& +gdcm::Dicts::GetPrivateDict() "; + +%feature("docstring") gdcm::Dicts::GetPrivateDict "const +PrivateDict& gdcm::Dicts::GetPrivateDict() const "; + +%feature("docstring") gdcm::Dicts::GetPublicDict "const Dict& +gdcm::Dicts::GetPublicDict() const "; + +%feature("docstring") gdcm::Dicts::IsEmpty "bool +gdcm::Dicts::IsEmpty() const "; + + +// File: classgdcm_1_1network_1_1DIMSE.xml +%feature("docstring") gdcm::network::DIMSE " + +DIMSE PS 3.7 - 2009 Annex E Command Dictionary (Normative) E.1 +REGISTRY OF DICOM COMMAND ELEMENTS Table E.1-1 COMMAND FIELDS (PART +1). + +C++ includes: gdcmDIMSE.h "; + + +// File: classgdcm_1_1DirectionCosines.xml +%feature("docstring") gdcm::DirectionCosines " + +class to handle DirectionCosines + +C++ includes: gdcmDirectionCosines.h "; + +%feature("docstring") gdcm::DirectionCosines::DirectionCosines "gdcm::DirectionCosines::DirectionCosines() "; + +%feature("docstring") gdcm::DirectionCosines::DirectionCosines "gdcm::DirectionCosines::DirectionCosines(const double dircos[6]) "; + +%feature("docstring") gdcm::DirectionCosines::~DirectionCosines "gdcm::DirectionCosines::~DirectionCosines() "; + +%feature("docstring") gdcm::DirectionCosines::ComputeDistAlongNormal +"double gdcm::DirectionCosines::ComputeDistAlongNormal(const double +ipp[3]) const + +Compute the distance along the normal. "; + +%feature("docstring") gdcm::DirectionCosines::Cross "void +gdcm::DirectionCosines::Cross(double z[3]) const + +Compute Cross product. "; + +%feature("docstring") gdcm::DirectionCosines::CrossDot "double +gdcm::DirectionCosines::CrossDot(DirectionCosines const &dc) const + +Compute the Dot product of the two cross vector of both +DirectionCosines object. "; + +%feature("docstring") gdcm::DirectionCosines::Dot "double +gdcm::DirectionCosines::Dot() const + +Compute Dot. "; + +%feature("docstring") gdcm::DirectionCosines::IsValid "bool +gdcm::DirectionCosines::IsValid() const + +Return whether or not this is a valid direction cosines. "; + +%feature("docstring") gdcm::DirectionCosines::Normalize "void +gdcm::DirectionCosines::Normalize() + +Normalize in-place. "; + +%feature("docstring") gdcm::DirectionCosines::Print "void +gdcm::DirectionCosines::Print(std::ostream &) const + +Print. "; + +%feature("docstring") gdcm::DirectionCosines::SetFromString "bool +gdcm::DirectionCosines::SetFromString(const char *str) + +Initialize from string str. It requires 6 floating point separated by +a backslash character. "; + + +// File: classgdcm_1_1Directory.xml +%feature("docstring") gdcm::Directory " + +Class for manipulation directories. + +This implementation provide a cross platform implementation for +manipulating directores: basically traversing directories and +harvesting files + +will not take into account unix type hidden file recursive option will +not look into UNIX type hidden directory (those starting with a '.') + +Since python or C# provide there own equivalent implementation, in +which case gdcm::Directory does not make much sense. + +C++ includes: gdcmDirectory.h "; + +%feature("docstring") gdcm::Directory::Directory "gdcm::Directory::Directory() "; + +%feature("docstring") gdcm::Directory::~Directory "gdcm::Directory::~Directory() "; + +%feature("docstring") gdcm::Directory::GetDirectories "FilenamesType +const& gdcm::Directory::GetDirectories() const + +Return the Directories traversed. "; + +%feature("docstring") gdcm::Directory::GetFilenames "FilenamesType +const& gdcm::Directory::GetFilenames() const + +Set/Get the file names within the directory. "; + +%feature("docstring") gdcm::Directory::GetToplevel "FilenameType +const& gdcm::Directory::GetToplevel() const + +Get the name of the toplevel directory. "; + +%feature("docstring") gdcm::Directory::Load "unsigned int +gdcm::Directory::Load(FilenameType const &name, bool recursive=false) + +construct a list of filenames and subdirectory beneath directory: name +WARNING: : hidden file and hidden directory are not loaded. "; + +%feature("docstring") gdcm::Directory::Print "void +gdcm::Directory::Print(std::ostream &os=std::cout) const + +Print. "; + + +// File: classgdcm_1_1DirectoryHelper.xml +%feature("docstring") gdcm::DirectoryHelper " + +DirectoryHelper this class is designed to help mitigate some of the +commonly performed operations on directories. namely: 1) the ability +to determine the number of series in a directory by what type of +series is present 2) the ability to find all ct series in a directory +3) the ability to find all mr series in a directory 4) to load a set +of DataSets from a series that's already been sorted by the IPP sorter +5) For rtstruct stuff, you need to know the sopinstanceuid of each z +plane, so there's a retrieval function for that 6) then a few other +functions for rtstruct writeouts. + +C++ includes: gdcmDirectoryHelper.h "; + + +// File: classstd_1_1domain__error.xml +%feature("docstring") std::domain_error " + +STL class. "; + + +// File: classgdcm_1_1DummyValueGenerator.xml +%feature("docstring") gdcm::DummyValueGenerator " + +Class for generating dummy value. + +See: Anonymizer + +C++ includes: gdcmDummyValueGenerator.h "; + + +// File: classgdcm_1_1Dumper.xml +%feature("docstring") gdcm::Dumper " + +Codec class. + +Use it to simply dump value read from the file. No interpretation is +done. But it is real fast ! Almost no overhead + +C++ includes: gdcmDumper.h "; + +%feature("docstring") gdcm::Dumper::Dumper "gdcm::Dumper::Dumper() +"; + +%feature("docstring") gdcm::Dumper::~Dumper "gdcm::Dumper::~Dumper() +"; + + +// File: classgdcm_1_1Element.xml +%feature("docstring") gdcm::Element " + +Element class. + +TODO + +C++ includes: gdcmElement.h "; + +%feature("docstring") gdcm::Element::GetAsDataElement "DataElement +gdcm::Element< TVR, TVM >::GetAsDataElement() const "; + +%feature("docstring") gdcm::Element::GetLength "unsigned long +gdcm::Element< TVR, TVM >::GetLength() const "; + +%feature("docstring") gdcm::Element::GetValue "const +VRToType::Type& gdcm::Element< TVR, TVM >::GetValue(unsigned int +idx=0) const "; + +%feature("docstring") gdcm::Element::GetValue "VRToType::Type& +gdcm::Element< TVR, TVM >::GetValue(unsigned int idx=0) "; + +%feature("docstring") gdcm::Element::GetValues "const +VRToType::Type* gdcm::Element< TVR, TVM >::GetValues() const "; + +%feature("docstring") gdcm::Element::Print "void gdcm::Element< TVR, +TVM >::Print(std::ostream &_os) const "; + +%feature("docstring") gdcm::Element::Read "void gdcm::Element< TVR, +TVM >::Read(std::istream &_is) "; + +%feature("docstring") gdcm::Element::Set "void gdcm::Element< TVR, +TVM >::Set(Value const &v) "; + +%feature("docstring") gdcm::Element::SetFromDataElement "void +gdcm::Element< TVR, TVM >::SetFromDataElement(DataElement const &de) +"; + +%feature("docstring") gdcm::Element::SetValue "void gdcm::Element< +TVR, TVM >::SetValue(typename VRToType< TVR >::Type v, unsigned int +idx=0) "; + +%feature("docstring") gdcm::Element::Write "void gdcm::Element< TVR, +TVM >::Write(std::ostream &_os) const "; + + +// File: classgdcm_1_1Element_3_01TVR_00_01VM_1_1VM1__2_01_4.xml +%feature("docstring") gdcm::Element< TVR, VM::VM1_2 > " C++ includes: +gdcmElement.h "; + +%feature("docstring") gdcm::Element< TVR, VM::VM1_2 >::SetLength " +void gdcm::Element< TVR, VM::VM1_2 >::SetLength(int len) "; + + +// File: classgdcm_1_1Element_3_01TVR_00_01VM_1_1VM1__n_01_4.xml +%feature("docstring") gdcm::Element< TVR, VM::VM1_n > " C++ includes: +gdcmElement.h "; + +%feature("docstring") gdcm::Element< TVR, VM::VM1_n >::Element " +gdcm::Element< TVR, VM::VM1_n >::Element() "; + +%feature("docstring") gdcm::Element< TVR, VM::VM1_n >::Element " +gdcm::Element< TVR, VM::VM1_n >::Element(const Element &_val) "; + +%feature("docstring") gdcm::Element< TVR, VM::VM1_n >::~Element " +gdcm::Element< TVR, VM::VM1_n >::~Element() "; + +%feature("docstring") gdcm::Element< TVR, VM::VM1_n +>::GetAsDataElement " DataElement gdcm::Element< TVR, VM::VM1_n +>::GetAsDataElement() const "; + +%feature("docstring") gdcm::Element< TVR, VM::VM1_n >::GetLength " +unsigned long gdcm::Element< TVR, VM::VM1_n >::GetLength() const "; + +%feature("docstring") gdcm::Element< TVR, VM::VM1_n >::GetValue " +VRToType::Type& gdcm::Element< TVR, VM::VM1_n +>::GetValue(unsigned int idx=0) "; + +%feature("docstring") gdcm::Element< TVR, VM::VM1_n >::GetValue " +const VRToType::Type& gdcm::Element< TVR, VM::VM1_n +>::GetValue(unsigned int idx=0) const "; + +%feature("docstring") gdcm::Element< TVR, VM::VM1_n >::Print " void +gdcm::Element< TVR, VM::VM1_n >::Print(std::ostream &_os) const "; + +%feature("docstring") gdcm::Element< TVR, VM::VM1_n >::Read " void +gdcm::Element< TVR, VM::VM1_n >::Read(std::istream &_is) "; + +%feature("docstring") gdcm::Element< TVR, VM::VM1_n >::Set " void +gdcm::Element< TVR, VM::VM1_n >::Set(Value const &v) "; + +%feature("docstring") gdcm::Element< TVR, VM::VM1_n >::SetArray " +void gdcm::Element< TVR, VM::VM1_n >::SetArray(const Type *array, +unsigned long len, bool save=false) "; + +%feature("docstring") gdcm::Element< TVR, VM::VM1_n +>::SetFromDataElement " void gdcm::Element< TVR, VM::VM1_n +>::SetFromDataElement(DataElement const &de) "; + +%feature("docstring") gdcm::Element< TVR, VM::VM1_n >::SetLength " +void gdcm::Element< TVR, VM::VM1_n >::SetLength(unsigned long len) "; + +%feature("docstring") gdcm::Element< TVR, VM::VM1_n >::SetValue " +void gdcm::Element< TVR, VM::VM1_n >::SetValue(typename VRToType< TVR +>::Type v, unsigned int idx=0) "; + +%feature("docstring") gdcm::Element< TVR, VM::VM1_n >::Write " void +gdcm::Element< TVR, VM::VM1_n >::Write(std::ostream &_os) const "; + +%feature("docstring") gdcm::Element< TVR, VM::VM1_n >::WriteASCII " +void gdcm::Element< TVR, VM::VM1_n >::WriteASCII(std::ostream &os) +const "; + + +// File: classgdcm_1_1Element_3_01TVR_00_01VM_1_1VM2__2n_01_4.xml +%feature("docstring") gdcm::Element< TVR, VM::VM2_2n > " C++ includes: +gdcmElement.h "; + +%feature("docstring") gdcm::Element< TVR, VM::VM2_2n >::SetLength " +void gdcm::Element< TVR, VM::VM2_2n >::SetLength(int len) "; + + +// File: classgdcm_1_1Element_3_01TVR_00_01VM_1_1VM2__n_01_4.xml +%feature("docstring") gdcm::Element< TVR, VM::VM2_n > " C++ includes: +gdcmElement.h "; + +%feature("docstring") gdcm::Element< TVR, VM::VM2_n >::SetLength " +void gdcm::Element< TVR, VM::VM2_n >::SetLength(int len) "; + + +// File: classgdcm_1_1Element_3_01TVR_00_01VM_1_1VM3__3n_01_4.xml +%feature("docstring") gdcm::Element< TVR, VM::VM3_3n > " C++ includes: +gdcmElement.h "; + +%feature("docstring") gdcm::Element< TVR, VM::VM3_3n >::SetLength " +void gdcm::Element< TVR, VM::VM3_3n >::SetLength(int len) "; + + +// File: classgdcm_1_1Element_3_01TVR_00_01VM_1_1VM3__n_01_4.xml +%feature("docstring") gdcm::Element< TVR, VM::VM3_n > " C++ includes: +gdcmElement.h "; + +%feature("docstring") gdcm::Element< TVR, VM::VM3_n >::SetLength " +void gdcm::Element< TVR, VM::VM3_n >::SetLength(int len) "; + + +// File: classgdcm_1_1Element_3_01VR_1_1AS_00_01VM_1_1VM5_01_4.xml +%feature("docstring") gdcm::Element< VR::AS, VM::VM5 > " C++ includes: +gdcmElement.h "; + +%feature("docstring") gdcm::Element< VR::AS, VM::VM5 >::GetLength " +unsigned long gdcm::Element< VR::AS, VM::VM5 >::GetLength() const "; + +%feature("docstring") gdcm::Element< VR::AS, VM::VM5 >::Print " void +gdcm::Element< VR::AS, VM::VM5 >::Print(std::ostream &_os) const "; + + +// File: classgdcm_1_1Element_3_01VR_1_1OB_00_01VM_1_1VM1_01_4.xml +%feature("docstring") gdcm::Element< VR::OB, VM::VM1 > " C++ includes: +gdcmElement.h "; + + +// File: classgdcm_1_1Element_3_01VR_1_1OW_00_01VM_1_1VM1_01_4.xml +%feature("docstring") gdcm::Element< VR::OW, VM::VM1 > " C++ includes: +gdcmElement.h "; + + +// File: classgdcm_1_1ElementDisableCombinations.xml +%feature("docstring") gdcm::ElementDisableCombinations " + +A class which is used to produce compile errors for an invalid +combination of template parameters. + +Invalid combinations have specialized declarations with no definition. + +C++ includes: gdcmElement.h "; + + +// File: classgdcm_1_1ElementDisableCombinations_3_01VR_1_1OB_00_01VM_1_1VM1__n_01_4.xml +%feature("docstring") gdcm::ElementDisableCombinations< VR::OB, +VM::VM1_n > " C++ includes: gdcmElement.h "; + + +// File: classgdcm_1_1ElementDisableCombinations_3_01VR_1_1OW_00_01VM_1_1VM1__n_01_4.xml +%feature("docstring") gdcm::ElementDisableCombinations< VR::OW, +VM::VM1_n > " C++ includes: gdcmElement.h "; + + +// File: classgdcm_1_1EncapsulatedDocument.xml +%feature("docstring") gdcm::EncapsulatedDocument " + +EncapsulatedDocument. + +C++ includes: gdcmEncapsulatedDocument.h "; + +%feature("docstring") +gdcm::EncapsulatedDocument::EncapsulatedDocument "gdcm::EncapsulatedDocument::EncapsulatedDocument() "; + + +// File: classgdcm_1_1EncodingImplementation_3_01VR_1_1VRASCII_01_4.xml +%feature("docstring") gdcm::EncodingImplementation< VR::VRASCII > " +C++ includes: gdcmElement.h "; + +%feature("docstring") gdcm::EncodingImplementation< VR::VRASCII +>::Write " void gdcm::EncodingImplementation< VR::VRASCII +>::Write(const float *data, unsigned long length, std::ostream &_os) +"; + +%feature("docstring") gdcm::EncodingImplementation< VR::VRASCII +>::Write " void gdcm::EncodingImplementation< VR::VRASCII +>::Write(const double *data, unsigned long length, std::ostream &_os) +"; + + +// File: classgdcm_1_1EncodingImplementation_3_01VR_1_1VRBINARY_01_4.xml +%feature("docstring") gdcm::EncodingImplementation< VR::VRBINARY > " +C++ includes: gdcmElement.h "; + + +// File: classgdcm_1_1EndEvent.xml +%feature("docstring") gdcm::EndEvent "C++ includes: gdcmEvent.h "; + + +// File: classgdcm_1_1EnumeratedValues.xml +%feature("docstring") gdcm::EnumeratedValues " + +Element. A Data Element with Enumerated Values that does not have a +Value equivalent to one of the Values specified in this standard has +an invalid value within the scope of a specific Information Object/SOP +Class definition. Note: 1. Patient Sex (0010, 0040) is an example of a +Data Element having Enumerated Values. It is defined to have a Value +that is either \"M\", \"F\", or \"O\" (see PS 3.3). No other Value +shall be given to this Data Element. 2. Future modifications of this +standard may add to the set of allowed values for Data Elements with +Enumerated Values. Such additions by themselves may or may not require +a change in SOP Class UIDs, depending on the semantics of the Data +Element. + +C++ includes: gdcmEnumeratedValues.h "; + +%feature("docstring") gdcm::EnumeratedValues::EnumeratedValues "gdcm::EnumeratedValues::EnumeratedValues() "; + + +// File: classgdcm_1_1Event.xml +%feature("docstring") gdcm::Event " + +superclass for callback/observer methods + +See: Command Subject + +C++ includes: gdcmEvent.h "; + +%feature("docstring") gdcm::Event::Event "gdcm::Event::Event() "; + +%feature("docstring") gdcm::Event::Event "gdcm::Event::Event(const +Event &) "; + +%feature("docstring") gdcm::Event::~Event "virtual +gdcm::Event::~Event() "; + +%feature("docstring") gdcm::Event::CheckEvent "virtual bool +gdcm::Event::CheckEvent(const Event *) const =0 + +Check if given event matches or derives from this event. "; + +%feature("docstring") gdcm::Event::GetEventName "virtual const char* +gdcm::Event::GetEventName(void) const =0 + +Return the StringName associated with the event. "; + +%feature("docstring") gdcm::Event::MakeObject "virtual Event* +gdcm::Event::MakeObject() const =0 + +Create an Event of this type This method work as a Factory for +creating events of each particular type. "; + +%feature("docstring") gdcm::Event::Print "virtual void +gdcm::Event::Print(std::ostream &os) const + +Print Event information. This method can be overridden by specific +Event subtypes. The default is to print out the type of the event. "; + + +// File: classgdcm_1_1Exception.xml +%feature("docstring") gdcm::Exception " + +Exception. + +Standard exception handling object. Its copy-constructor and +assignment operator are generated by the compiler. + +C++ includes: gdcmException.h "; + +%feature("docstring") gdcm::Exception::Exception "gdcm::Exception::Exception(const char *desc=\"None\", const char +*file=__FILE__, unsigned int lineNumber=__LINE__, const char +*func=\"\") + +Explicit constructor, initializing the description and the text +returned by what(). The last parameter is ignored for the time being. +It may be used to specify the function where the exception was thrown. +"; + +%feature("docstring") gdcm::Exception::~Exception "virtual +gdcm::Exception::~Exception() throw ()"; + +%feature("docstring") gdcm::Exception::GetDescription "const char* +gdcm::Exception::GetDescription() const + +Return the Description. "; + +%feature("docstring") gdcm::Exception::what "const char* +gdcm::Exception::what() const throw () what implementation "; + + +// File: classstd_1_1exception.xml +%feature("docstring") std::exception " + +STL class. "; + + +// File: classgdcm_1_1ExitEvent.xml +%feature("docstring") gdcm::ExitEvent "C++ includes: gdcmEvent.h "; + + +// File: classgdcm_1_1ExplicitDataElement.xml +%feature("docstring") gdcm::ExplicitDataElement " + +Class to read/write a DataElement as Explicit Data Element. + +bla + +C++ includes: gdcmExplicitDataElement.h "; + +%feature("docstring") gdcm::ExplicitDataElement::GetLength "VL +gdcm::ExplicitDataElement::GetLength() const "; + +%feature("docstring") gdcm::ExplicitDataElement::Read "std::istream& +gdcm::ExplicitDataElement::Read(std::istream &is) "; + +%feature("docstring") gdcm::ExplicitDataElement::ReadPreValue "std::istream& gdcm::ExplicitDataElement::ReadPreValue(std::istream +&is) "; + +%feature("docstring") gdcm::ExplicitDataElement::ReadValue "std::istream& gdcm::ExplicitDataElement::ReadValue(std::istream &is) +"; + +%feature("docstring") gdcm::ExplicitDataElement::ReadWithLength "std::istream& gdcm::ExplicitDataElement::ReadWithLength(std::istream +&is, VL &length) "; + +%feature("docstring") gdcm::ExplicitDataElement::Write "const +std::ostream& gdcm::ExplicitDataElement::Write(std::ostream &os) const +"; + + +// File: classgdcm_1_1ExplicitImplicitDataElement.xml +%feature("docstring") gdcm::ExplicitImplicitDataElement " + +Class to read/write a DataElement as ExplicitImplicit Data Element. + +This only happen for some Philips images Should I derive from +ExplicitDataElement instead ? This is the class that is the closest +the GDCM1.x parser. At each element we try first to read it as +explicit, if this fails, then we try again as an implicit element. + +C++ includes: gdcmExplicitImplicitDataElement.h "; + +%feature("docstring") gdcm::ExplicitImplicitDataElement::GetLength "VL gdcm::ExplicitImplicitDataElement::GetLength() const "; + +%feature("docstring") gdcm::ExplicitImplicitDataElement::Read "std::istream& gdcm::ExplicitImplicitDataElement::Read(std::istream +&is) "; + +%feature("docstring") gdcm::ExplicitImplicitDataElement::ReadPreValue +"std::istream& +gdcm::ExplicitImplicitDataElement::ReadPreValue(std::istream &is) "; + +%feature("docstring") gdcm::ExplicitImplicitDataElement::ReadValue "std::istream& +gdcm::ExplicitImplicitDataElement::ReadValue(std::istream &is) "; + +%feature("docstring") +gdcm::ExplicitImplicitDataElement::ReadWithLength "std::istream& +gdcm::ExplicitImplicitDataElement::ReadWithLength(std::istream &is, VL +&length) "; + + +// File: classstd_1_1ios__base_1_1failure.xml +%feature("docstring") std::ios_base::failure " + +STL class. "; + + +// File: classgdcm_1_1Fiducials.xml +%feature("docstring") gdcm::Fiducials " + +Fiducials. + +C++ includes: gdcmFiducials.h "; + +%feature("docstring") gdcm::Fiducials::Fiducials "gdcm::Fiducials::Fiducials() "; + + +// File: classgdcm_1_1File.xml +%feature("docstring") gdcm::File " + +a DICOM File See PS 3.10 File: A File is an ordered string of zero or +more bytes, where the first byte is at the beginning of the file and +the last byte at the end of the File. Files are identified by a unique +File ID and may by written, read and/or deleted. + +See: Reader Writer + +C++ includes: gdcmFile.h "; + +%feature("docstring") gdcm::File::File "gdcm::File::File() "; + +%feature("docstring") gdcm::File::~File "gdcm::File::~File() "; + +%feature("docstring") gdcm::File::GetDataSet "const DataSet& +gdcm::File::GetDataSet() const + +Get Data Set. "; + +%feature("docstring") gdcm::File::GetDataSet "DataSet& +gdcm::File::GetDataSet() + +Get Data Set. "; + +%feature("docstring") gdcm::File::GetHeader "const +FileMetaInformation& gdcm::File::GetHeader() const + +Get File Meta Information. "; + +%feature("docstring") gdcm::File::GetHeader "FileMetaInformation& +gdcm::File::GetHeader() + +Get File Meta Information. "; + +%feature("docstring") gdcm::File::Read "std::istream& +gdcm::File::Read(std::istream &is) + +Read. "; + +%feature("docstring") gdcm::File::SetDataSet "void +gdcm::File::SetDataSet(const DataSet &ds) + +Set Data Set. "; + +%feature("docstring") gdcm::File::SetHeader "void +gdcm::File::SetHeader(const FileMetaInformation &fmi) + +Set File Meta Information. "; + +%feature("docstring") gdcm::File::Write "std::ostream const& +gdcm::File::Write(std::ostream &os) const + +Write. "; + + +// File: classgdcm_1_1FileAnonymizer.xml +%feature("docstring") gdcm::FileAnonymizer " + +FileAnonymizer. + +This Anonymizer is a file-based Anonymizer. It requires a valid DICOM +file and will use the Value Length to skip over any information. + +It will not load the data into memory and should consume much less +memory than gdcm::Anonymizer + +caveats: This class will NOT work with unordered attributes in a DICOM +File. + +This class does neither recompute nor update the Group Length element. + +This class currently does not update the File Meta Information header + +C++ includes: gdcmFileAnonymizer.h "; + +%feature("docstring") gdcm::FileAnonymizer::FileAnonymizer "gdcm::FileAnonymizer::FileAnonymizer() "; + +%feature("docstring") gdcm::FileAnonymizer::~FileAnonymizer "gdcm::FileAnonymizer::~FileAnonymizer() "; + +%feature("docstring") gdcm::FileAnonymizer::Empty "void +gdcm::FileAnonymizer::Empty(Tag const &t) + +Make Tag t empty Warning: does not handle SQ element "; + +%feature("docstring") gdcm::FileAnonymizer::Remove "void +gdcm::FileAnonymizer::Remove(Tag const &t) + +remove a tag (even a SQ can be removed) "; + +%feature("docstring") gdcm::FileAnonymizer::Replace "void +gdcm::FileAnonymizer::Replace(Tag const &t, const char *value) + +Replace tag with another value, if tag is not found it will be +created: WARNING: this function can only execute if tag is a VRASCII +WARNING: Do not ever try to write a value in a SQ Data Element ! "; + +%feature("docstring") gdcm::FileAnonymizer::Replace "void +gdcm::FileAnonymizer::Replace(Tag const &t, const char *value, VL +const &vl) + +when the value contains , it is a good idea to specify the length. +This function is required when dealing with VRBINARY tag "; + +%feature("docstring") gdcm::FileAnonymizer::SetInputFileName "void +gdcm::FileAnonymizer::SetInputFileName(const char *filename_native) + +Set input filename. "; + +%feature("docstring") gdcm::FileAnonymizer::SetOutputFileName "void +gdcm::FileAnonymizer::SetOutputFileName(const char *filename_native) + +Set output filename. "; + +%feature("docstring") gdcm::FileAnonymizer::Write "bool +gdcm::FileAnonymizer::Write() + +Write the output file. "; + + +// File: classgdcm_1_1FileDerivation.xml +%feature("docstring") gdcm::FileDerivation " + +FileDerivation class See PS 3.16 - 2008 For the list of Code Value +that can be used for in Derivation Code Sequence. + +URL:http://medical.nema.org/medical/dicom/2008/08_16pu.pdf + +DICOM Part 16 has two Context Groups CID 7202 and CID 7203 which +contain a set of codes defining reason for a source image reference +(ie. reason code for referenced image sequence) and a coded +description of the deriation applied to the new image data from the +original. Both these context groups are extensible. + +File Derivation is compulsary when creating a lossy derived image. + +C++ includes: gdcmFileDerivation.h "; + +%feature("docstring") gdcm::FileDerivation::FileDerivation "gdcm::FileDerivation::FileDerivation() "; + +%feature("docstring") gdcm::FileDerivation::~FileDerivation "gdcm::FileDerivation::~FileDerivation() "; + +%feature("docstring") gdcm::FileDerivation::AddReference "bool +gdcm::FileDerivation::AddReference(const char *referencedsopclassuid, +const char *referencedsopinstanceuid) + +Create the proper reference. Need to pass the original SOP Class UID +and the original SOP Instance UID, so that those value can be used as +Reference. WARNING: referencedsopclassuid and +referencedsopinstanceuid needs to be padded. This is not compatible +with how ByteValue->GetPointer works. "; + +%feature("docstring") gdcm::FileDerivation::Derive "bool +gdcm::FileDerivation::Derive() + +Change. "; + +%feature("docstring") gdcm::FileDerivation::GetFile "File& +gdcm::FileDerivation::GetFile() "; + +%feature("docstring") gdcm::FileDerivation::GetFile "const File& +gdcm::FileDerivation::GetFile() const "; + +%feature("docstring") +gdcm::FileDerivation::SetDerivationCodeSequenceCodeValue "void +gdcm::FileDerivation::SetDerivationCodeSequenceCodeValue(unsigned int +codevalue) + +Specify the Derivation Code Sequence Code Value. Eg 113040. "; + +%feature("docstring") gdcm::FileDerivation::SetDerivationDescription +"void gdcm::FileDerivation::SetDerivationDescription(const char *dd) + +Specify the Derivation Description. Eg \"lossy conversion\". "; + +%feature("docstring") gdcm::FileDerivation::SetFile "void +gdcm::FileDerivation::SetFile(const File &f) + +Set/Get File. "; + +%feature("docstring") +gdcm::FileDerivation::SetPurposeOfReferenceCodeSequenceCodeValue "void +gdcm::FileDerivation::SetPurposeOfReferenceCodeSequenceCodeValue(unsigned +int codevalue) + +Specify the Purpose Of Reference Code Value. Eg. 121320. "; + + +// File: classgdcm_1_1FileExplicitFilter.xml +%feature("docstring") gdcm::FileExplicitFilter " + +FileExplicitFilter class After changing a file from Implicit to +Explicit representation (see ImageChangeTransferSyntax) one operation +is to make sure the VR of each DICOM attribute are accurate and do +match the one from PS 3.6. Indeed when a file is written in Implicit +reprensentation, the VR is not stored directly in the file. + +WARNING: changing an implicit dataset to an explicit dataset is NOT a +trivial task of simply changing the VR to the dict one: One has to +make sure SQ is properly set + +One has to recompute the explicit length SQ + +One has to make sure that VR is valid for the encoding + +One has to make sure that VR 16bits can store the original value +length + +C++ includes: gdcmFileExplicitFilter.h "; + +%feature("docstring") gdcm::FileExplicitFilter::FileExplicitFilter "gdcm::FileExplicitFilter::FileExplicitFilter() "; + +%feature("docstring") gdcm::FileExplicitFilter::~FileExplicitFilter "gdcm::FileExplicitFilter::~FileExplicitFilter() "; + +%feature("docstring") gdcm::FileExplicitFilter::Change "bool +gdcm::FileExplicitFilter::Change() + +Set FMI Transfer Syntax. + +Change "; + +%feature("docstring") gdcm::FileExplicitFilter::GetFile "File& +gdcm::FileExplicitFilter::GetFile() "; + +%feature("docstring") gdcm::FileExplicitFilter::SetChangePrivateTags +"void gdcm::FileExplicitFilter::SetChangePrivateTags(bool b) + +Decide whether or not to VR'ify private tags. "; + +%feature("docstring") gdcm::FileExplicitFilter::SetFile "void +gdcm::FileExplicitFilter::SetFile(const File &f) + +Set/Get File. "; + +%feature("docstring") +gdcm::FileExplicitFilter::SetRecomputeItemLength "void +gdcm::FileExplicitFilter::SetRecomputeItemLength(bool b) + +By default set Sequence & Item length to Undefined to avoid +recomputing length: "; + +%feature("docstring") +gdcm::FileExplicitFilter::SetRecomputeSequenceLength "void +gdcm::FileExplicitFilter::SetRecomputeSequenceLength(bool b) "; + +%feature("docstring") gdcm::FileExplicitFilter::SetUseVRUN "void +gdcm::FileExplicitFilter::SetUseVRUN(bool b) + +When VR=16bits in explicit but Implicit has a 32bits length, use +VR=UN. "; + + +// File: classgdcm_1_1FileMetaInformation.xml +%feature("docstring") gdcm::FileMetaInformation " + +Class to represent a File Meta Information. + +FileMetaInformation is a Explicit Structured Set. Whenever the file +contains an ImplicitDataElement DataSet, a conversion will take place. + +Definition: The File Meta Information includes identifying information +on the encapsulated Data Set. This header consists of a 128 byte File +Preamble, followed by a 4 byte DICOM prefix, followed by the File Meta +Elements shown in Table 7.1-1. This header shall be present in every +DICOM file. + +See: Writer Reader + +C++ includes: gdcmFileMetaInformation.h "; + +%feature("docstring") gdcm::FileMetaInformation::FileMetaInformation +"gdcm::FileMetaInformation::FileMetaInformation() "; + +%feature("docstring") gdcm::FileMetaInformation::FileMetaInformation +"gdcm::FileMetaInformation::FileMetaInformation(FileMetaInformation +const &fmi) "; + +%feature("docstring") gdcm::FileMetaInformation::~FileMetaInformation +"gdcm::FileMetaInformation::~FileMetaInformation() "; + +%feature("docstring") gdcm::FileMetaInformation::FillFromDataSet "void gdcm::FileMetaInformation::FillFromDataSet(DataSet const &ds) + +Construct a FileMetaInformation from an already existing DataSet: "; + +%feature("docstring") +gdcm::FileMetaInformation::GetDataSetTransferSyntax "const +TransferSyntax& gdcm::FileMetaInformation::GetDataSetTransferSyntax() +const "; + +%feature("docstring") gdcm::FileMetaInformation::GetFullLength "VL +gdcm::FileMetaInformation::GetFullLength() const "; + +%feature("docstring") gdcm::FileMetaInformation::GetMediaStorage "MediaStorage gdcm::FileMetaInformation::GetMediaStorage() const "; + +%feature("docstring") gdcm::FileMetaInformation::GetMetaInformationTS +"TransferSyntax::NegociatedType +gdcm::FileMetaInformation::GetMetaInformationTS() const "; + +%feature("docstring") gdcm::FileMetaInformation::GetPreamble "const +Preamble& gdcm::FileMetaInformation::GetPreamble() const + +Get Preamble. "; + +%feature("docstring") gdcm::FileMetaInformation::GetPreamble "Preamble& gdcm::FileMetaInformation::GetPreamble() "; + +%feature("docstring") gdcm::FileMetaInformation::Insert "void +gdcm::FileMetaInformation::Insert(const DataElement &de) + +Insert a DataElement in the DataSet. WARNING: : Tag need to be >= 0x8 +to be considered valid data element "; + +%feature("docstring") gdcm::FileMetaInformation::IsValid "bool +gdcm::FileMetaInformation::IsValid() const "; + +%feature("docstring") gdcm::FileMetaInformation::Read "std::istream& +gdcm::FileMetaInformation::Read(std::istream &is) + +Read. "; + +%feature("docstring") gdcm::FileMetaInformation::ReadCompat "std::istream& gdcm::FileMetaInformation::ReadCompat(std::istream &is) +"; + +%feature("docstring") gdcm::FileMetaInformation::Replace "void +gdcm::FileMetaInformation::Replace(const DataElement &de) + +Replace a dataelement with another one. "; + +%feature("docstring") +gdcm::FileMetaInformation::SetDataSetTransferSyntax "void +gdcm::FileMetaInformation::SetDataSetTransferSyntax(const +TransferSyntax &ts) "; + +%feature("docstring") gdcm::FileMetaInformation::SetPreamble "void +gdcm::FileMetaInformation::SetPreamble(const Preamble &p) "; + +%feature("docstring") gdcm::FileMetaInformation::Write "std::ostream& gdcm::FileMetaInformation::Write(std::ostream &os) const + +Write. "; + + +// File: classgdcm_1_1Filename.xml +%feature("docstring") gdcm::Filename " + +Class to manipulate file name's. + +OS independant representation of a filename (to query path, name and +extension from a filename) + +C++ includes: gdcmFilename.h "; + +%feature("docstring") gdcm::Filename::Filename "gdcm::Filename::Filename(const char *filename=\"\") "; + +%feature("docstring") gdcm::Filename::EndWith "bool +gdcm::Filename::EndWith(const char ending[]) const + +Does the filename ends with a particular string ? "; + +%feature("docstring") gdcm::Filename::GetExtension "const char* +gdcm::Filename::GetExtension() + +return only the extension part of a filename "; + +%feature("docstring") gdcm::Filename::GetFileName "const char* +gdcm::Filename::GetFileName() const + +Return the full filename. "; + +%feature("docstring") gdcm::Filename::GetName "const char* +gdcm::Filename::GetName() + +return only the name part of a filename "; + +%feature("docstring") gdcm::Filename::GetPath "const char* +gdcm::Filename::GetPath() + +Return only the path component of a filename. "; + +%feature("docstring") gdcm::Filename::IsEmpty "bool +gdcm::Filename::IsEmpty() const + +return whether the filename is empty "; + +%feature("docstring") gdcm::Filename::IsIdentical "bool +gdcm::Filename::IsIdentical(Filename const &fn) const "; + +%feature("docstring") gdcm::Filename::ToUnixSlashes "const char* +gdcm::Filename::ToUnixSlashes() + +Convert backslash (windows style) to UNIX style slash. "; + +%feature("docstring") gdcm::Filename::ToWindowsSlashes "const char* +gdcm::Filename::ToWindowsSlashes() + +Convert foward slash (UNIX style) to windows style slash. "; + + +// File: classgdcm_1_1FileNameEvent.xml +%feature("docstring") gdcm::FileNameEvent " + +FileNameEvent Special type of event triggered during processing of +FileSet. + +See: AnyEvent + +C++ includes: gdcmFileNameEvent.h "; + +%feature("docstring") gdcm::FileNameEvent::FileNameEvent "gdcm::FileNameEvent::FileNameEvent(const char *s=\"\") "; + +%feature("docstring") gdcm::FileNameEvent::FileNameEvent "gdcm::FileNameEvent::FileNameEvent(const Self &s) "; + +%feature("docstring") gdcm::FileNameEvent::~FileNameEvent "virtual +gdcm::FileNameEvent::~FileNameEvent() "; + +%feature("docstring") gdcm::FileNameEvent::CheckEvent "virtual bool +gdcm::FileNameEvent::CheckEvent(const ::gdcm::Event *e) const "; + +%feature("docstring") gdcm::FileNameEvent::GetEventName "virtual +const char* gdcm::FileNameEvent::GetEventName() const + +Return the StringName associated with the event. "; + +%feature("docstring") gdcm::FileNameEvent::GetFileName "const char* +gdcm::FileNameEvent::GetFileName() const "; + +%feature("docstring") gdcm::FileNameEvent::MakeObject "virtual +::gdcm::Event* gdcm::FileNameEvent::MakeObject() const + +Create an Event of this type This method work as a Factory for +creating events of each particular type. "; + +%feature("docstring") gdcm::FileNameEvent::SetFileName "void +gdcm::FileNameEvent::SetFileName(const char *f) "; + + +// File: classgdcm_1_1FilenameGenerator.xml +%feature("docstring") gdcm::FilenameGenerator " + +FilenameGenerator. + +class to generate filenames based on a pattern (C-style) + +Output will be: + +for i = 0, number of filenames: outfilename[i] = prefix + (pattern % +i) + +where pattern % i means C-style snprintf of Pattern using value 'i' + +C++ includes: gdcmFilenameGenerator.h "; + +%feature("docstring") gdcm::FilenameGenerator::FilenameGenerator "gdcm::FilenameGenerator::FilenameGenerator() "; + +%feature("docstring") gdcm::FilenameGenerator::~FilenameGenerator "gdcm::FilenameGenerator::~FilenameGenerator() "; + +%feature("docstring") gdcm::FilenameGenerator::Generate "bool +gdcm::FilenameGenerator::Generate() + +Generate (return success). "; + +%feature("docstring") gdcm::FilenameGenerator::GetFilename "const +char* gdcm::FilenameGenerator::GetFilename(SizeType n) const + +Get a particular filename (call after Generate). "; + +%feature("docstring") gdcm::FilenameGenerator::GetFilenames "FilenamesType const& gdcm::FilenameGenerator::GetFilenames() const + +Return all filenames. "; + +%feature("docstring") gdcm::FilenameGenerator::GetNumberOfFilenames "SizeType gdcm::FilenameGenerator::GetNumberOfFilenames() const "; + +%feature("docstring") gdcm::FilenameGenerator::GetPattern "const +char* gdcm::FilenameGenerator::GetPattern() const "; + +%feature("docstring") gdcm::FilenameGenerator::GetPrefix "const +char* gdcm::FilenameGenerator::GetPrefix() const "; + +%feature("docstring") gdcm::FilenameGenerator::SetNumberOfFilenames "void gdcm::FilenameGenerator::SetNumberOfFilenames(SizeType nfiles) + +Set/Get the number of filenames to generate. "; + +%feature("docstring") gdcm::FilenameGenerator::SetPattern "void +gdcm::FilenameGenerator::SetPattern(const char *pattern) + +Set/Get pattern. "; + +%feature("docstring") gdcm::FilenameGenerator::SetPrefix "void +gdcm::FilenameGenerator::SetPrefix(const char *prefix) + +Set/Get prefix. "; + + +// File: classgdcm_1_1FileSet.xml +%feature("docstring") gdcm::FileSet " + +File-set: A File-set is a collection of DICOM Files (and possibly non- +DICOM Files) that share a common naming space within which File IDs +are unique. + +C++ includes: gdcmFileSet.h "; + +%feature("docstring") gdcm::FileSet::FileSet "gdcm::FileSet::FileSet() "; + +%feature("docstring") gdcm::FileSet::AddFile "void +gdcm::FileSet::AddFile(File const &) + +Deprecated . Does nothing "; + +%feature("docstring") gdcm::FileSet::AddFile "bool +gdcm::FileSet::AddFile(const char *filename) + +Add a file 'filename' to the list of files. Return true on success, +false in case filename could not be found on system. "; + +%feature("docstring") gdcm::FileSet::GetFiles "FilesType const& +gdcm::FileSet::GetFiles() const "; + +%feature("docstring") gdcm::FileSet::SetFiles "void +gdcm::FileSet::SetFiles(FilesType const &files) "; + + +// File: classgdcm_1_1FileWithName.xml +%feature("docstring") gdcm::FileWithName " + +FileWithName. + +Backward only class do not use in newer code + +C++ includes: gdcmSerieHelper.h "; + +%feature("docstring") gdcm::FileWithName::FileWithName "gdcm::FileWithName::FileWithName(File &f) "; + + +// File: classgdcm_1_1FindPatientRootQuery.xml +%feature("docstring") gdcm::FindPatientRootQuery " + +PatientRootQuery contains: the class which will produce a dataset for +c-find with patient root. + +C++ includes: gdcmFindPatientRootQuery.h "; + +%feature("docstring") +gdcm::FindPatientRootQuery::FindPatientRootQuery "gdcm::FindPatientRootQuery::FindPatientRootQuery() "; + +%feature("docstring") +gdcm::FindPatientRootQuery::GetAbstractSyntaxUID "UIDs::TSName +gdcm::FindPatientRootQuery::GetAbstractSyntaxUID() const "; + +%feature("docstring") gdcm::FindPatientRootQuery::GetTagListByLevel "std::vector gdcm::FindPatientRootQuery::GetTagListByLevel(const +EQueryLevel &inQueryLevel) + +this function will return all tags at a given query level, so that +they maybe selected for searching. The boolean forFind is true if the +query is a find query, or false for a move query. "; + +%feature("docstring") gdcm::FindPatientRootQuery::InitializeDataSet "void gdcm::FindPatientRootQuery::InitializeDataSet(const EQueryLevel +&inQueryLevel) + +this function sets tag 8,52 to the appropriate value based on query +level also fills in the right unique tags, as per the standard's +requirements should allow for connection with dcmtk "; + +%feature("docstring") gdcm::FindPatientRootQuery::ValidateQuery "bool gdcm::FindPatientRootQuery::ValidateQuery(bool inStrict=true) +const + +have to be able to ensure that 0x8,0x52 is set (which will be true if +InitializeDataSet is called...) that the level is appropriate (ie, not +setting PATIENT for a study query that the tags in the query match the +right level (either required, unique, optional) by default, this +function checks to see if the query is for finding, which is more +permissive than for moving. For moving, only the unique tags are +allowed. 10 Jan 2011: adding in the 'strict' mode. according to the +standard (at least, how I've read it), only tags for a particular +level should be allowed in a particular query (ie, just series level +tags in a series level query). However, it seems that dcm4chee doesn't +share that interpretation. So, if 'inStrict' is false, then tags from +the current level and all higher levels are now considered valid. So, +if you're doing a non-strict series-level query, tags from the patient +and study level can be passed along as well. "; + + +// File: classgdcm_1_1FindStudyRootQuery.xml +%feature("docstring") gdcm::FindStudyRootQuery " + +FindStudyRootQuery contains: the class which will produce a dataset +for C-FIND with study root. + +C++ includes: gdcmFindStudyRootQuery.h "; + +%feature("docstring") gdcm::FindStudyRootQuery::FindStudyRootQuery "gdcm::FindStudyRootQuery::FindStudyRootQuery() "; + +%feature("docstring") gdcm::FindStudyRootQuery::GetAbstractSyntaxUID +"UIDs::TSName gdcm::FindStudyRootQuery::GetAbstractSyntaxUID() const +"; + +%feature("docstring") gdcm::FindStudyRootQuery::GetTagListByLevel "std::vector gdcm::FindStudyRootQuery::GetTagListByLevel(const +EQueryLevel &inQueryLevel) + +this function will return all tags at a given query level, so that +they maybe selected for searching. The boolean forFind is true if the +query is a find query, or false for a move query. "; + +%feature("docstring") gdcm::FindStudyRootQuery::InitializeDataSet "void gdcm::FindStudyRootQuery::InitializeDataSet(const EQueryLevel +&inQueryLevel) + +this function sets tag 8,52 to the appropriate value based on query +level also fills in the right unique tags, as per the standard's +requirements should allow for connection with dcmtk "; + +%feature("docstring") gdcm::FindStudyRootQuery::ValidateQuery "bool +gdcm::FindStudyRootQuery::ValidateQuery(bool inStrict=true) const + +have to be able to ensure that (0008,0052) is set that the level is +appropriate (ie, not setting PATIENT for a study query that the tags +in the query match the right level (either required, unique, optional) +"; + + +// File: classgdcm_1_1Fragment.xml +%feature("docstring") gdcm::Fragment " + +Class to represent a Fragment. + +C++ includes: gdcmFragment.h "; + +%feature("docstring") gdcm::Fragment::Fragment "gdcm::Fragment::Fragment() "; + +%feature("docstring") gdcm::Fragment::GetLength "VL +gdcm::Fragment::GetLength() const "; + +%feature("docstring") gdcm::Fragment::Read "std::istream& +gdcm::Fragment::Read(std::istream &is) "; + +%feature("docstring") gdcm::Fragment::ReadBacktrack "std::istream& +gdcm::Fragment::ReadBacktrack(std::istream &is) "; + +%feature("docstring") gdcm::Fragment::ReadPreValue "std::istream& +gdcm::Fragment::ReadPreValue(std::istream &is) "; + +%feature("docstring") gdcm::Fragment::ReadValue "std::istream& +gdcm::Fragment::ReadValue(std::istream &is) "; + +%feature("docstring") gdcm::Fragment::Write "std::ostream& +gdcm::Fragment::Write(std::ostream &os) const "; + + +// File: classstd_1_1fstream.xml +%feature("docstring") std::fstream " + +STL class. "; + + +// File: classgdcm_1_1Global.xml +%feature("docstring") gdcm::Global " + +Global. + +Global should be included in any translation unit that will use Dict +or that implements the singleton pattern. It makes sure that the Dict +singleton is created before and destroyed after all other singletons +in GDCM. + +C++ includes: gdcmGlobal.h "; + +%feature("docstring") gdcm::Global::Global "gdcm::Global::Global() +"; + +%feature("docstring") gdcm::Global::~Global "gdcm::Global::~Global() +"; + +%feature("docstring") gdcm::Global::Append "bool +gdcm::Global::Append(const char *path) + +Append path at the end of the path list WARNING: not thread safe ! "; + +%feature("docstring") gdcm::Global::GetDefs "Defs const& +gdcm::Global::GetDefs() const + +retrieve the default/internal (Part 3) You need to explicitely call +LoadResourcesFiles before "; + +%feature("docstring") gdcm::Global::GetDicts "Dicts& +gdcm::Global::GetDicts() "; + +%feature("docstring") gdcm::Global::GetDicts "Dicts const& +gdcm::Global::GetDicts() const + +retrieve the default/internal dicts (Part 6) This dict is filled up at +load time "; + +%feature("docstring") gdcm::Global::LoadResourcesFiles "bool +gdcm::Global::LoadResourcesFiles() + +Load all internal XML files, ressource path need to have been set +before calling this member function (see Append/Prepend members func) +WARNING: not thread safe ! "; + +%feature("docstring") gdcm::Global::Prepend "bool +gdcm::Global::Prepend(const char *path) + +Prepend path at the begining of the path list WARNING: not thread +safe ! "; + + +// File: classgdcm_1_1GroupDict.xml +%feature("docstring") gdcm::GroupDict " + +Class to represent the mapping from group number to its abbreviation +and name. + +Should I rewrite this class to use a std::map instead of std::vector +for problem of memory consumption ? + +C++ includes: gdcmGroupDict.h "; + +%feature("docstring") gdcm::GroupDict::GroupDict "gdcm::GroupDict::GroupDict() "; + +%feature("docstring") gdcm::GroupDict::~GroupDict "gdcm::GroupDict::~GroupDict() "; + +%feature("docstring") gdcm::GroupDict::GetAbbreviation "std::string +const& gdcm::GroupDict::GetAbbreviation(uint16_t num) const "; + +%feature("docstring") gdcm::GroupDict::GetName "std::string const& +gdcm::GroupDict::GetName(uint16_t num) const "; + +%feature("docstring") gdcm::GroupDict::Size "size_t +gdcm::GroupDict::Size() const "; + + +// File: classgdcm_1_1IconImageFilter.xml +%feature("docstring") gdcm::IconImageFilter " + +IconImageFilter This filter will extract icons from a gdcm::File This +filter will loop over all known sequence (public and private) that may +contains an IconImage and retrieve them. The filter will fails with a +value of false if no icon can be found Since it handle both public and +private icon type, one should not assume the icon is in uncompress +form, some private vendor store private icon in JPEG8/JPEG12. + +Implementation details: This filter supports the following Icons: +(0088,0200) Icon Image Sequence + +(0009,10,GEIIS) GE IIS Thumbnail Sequence + +(6003,10,GEMS_Ultrasound_ImageGroup_001) GEMS Image Thumbnail Sequence + +(0055,30,VEPRO VIF 3.0 DATA) Icon Data + +(0055,30,VEPRO VIM 5.0 DATA) ICONDATA2 + +WARNING: the icon stored in those private attribute do not conform to +definition of Icon Image Sequence (do not simply copy/paste). For +example some private icon can be expressed as 12bits pixel, while the +DICOM standard only allow 8bits icons. + +See: ImageReader + +C++ includes: gdcmIconImageFilter.h "; + +%feature("docstring") gdcm::IconImageFilter::IconImageFilter "gdcm::IconImageFilter::IconImageFilter() "; + +%feature("docstring") gdcm::IconImageFilter::~IconImageFilter "gdcm::IconImageFilter::~IconImageFilter() "; + +%feature("docstring") gdcm::IconImageFilter::Extract "bool +gdcm::IconImageFilter::Extract() + +Extract all Icon found in File. "; + +%feature("docstring") gdcm::IconImageFilter::GetFile "File& +gdcm::IconImageFilter::GetFile() "; + +%feature("docstring") gdcm::IconImageFilter::GetFile "const File& +gdcm::IconImageFilter::GetFile() const "; + +%feature("docstring") gdcm::IconImageFilter::GetIconImage "IconImage& gdcm::IconImageFilter::GetIconImage(unsigned int i) const +"; + +%feature("docstring") gdcm::IconImageFilter::GetNumberOfIconImages "unsigned int gdcm::IconImageFilter::GetNumberOfIconImages() const + +Retrieve extract IconImage (need to call Extract first). "; + +%feature("docstring") gdcm::IconImageFilter::SetFile "void +gdcm::IconImageFilter::SetFile(const File &f) + +Set/Get File. "; + + +// File: classgdcm_1_1IconImageGenerator.xml +%feature("docstring") gdcm::IconImageGenerator " + +IconImageGenerator This filter will generate a valid Icon from the +Pixel Data element (an instance of gdcm::Pixmap). To generate a valid +Icon, one is only allowed the following Photometric Interpretation: +MONOCHROME1 + +MONOCHROME2 + +PALETTE_COLOR. + +The Pixel Bits Allocated is restricted to 8bits, therefore 16 bits +image needs to be rescaled. By default the filter will use the full +scalar range of 16bits image to rescale to unsigned 8bits. This may +not be ideal for some situation, in which case the API SetPixelMinMax +can be used to overwrite the default min,max interval used. + +See: ImageReader + +C++ includes: gdcmIconImageGenerator.h "; + +%feature("docstring") gdcm::IconImageGenerator::IconImageGenerator "gdcm::IconImageGenerator::IconImageGenerator() "; + +%feature("docstring") gdcm::IconImageGenerator::~IconImageGenerator "gdcm::IconImageGenerator::~IconImageGenerator() "; + +%feature("docstring") gdcm::IconImageGenerator::AutoPixelMinMax "void gdcm::IconImageGenerator::AutoPixelMinMax(bool b) + +Instead of explicitely specifying the min/max value for the rescale +operation, let the internal mechanism compute the min/max of icon and +rescale to best appropriate. "; + +%feature("docstring") +gdcm::IconImageGenerator::ConvertRGBToPaletteColor "void +gdcm::IconImageGenerator::ConvertRGBToPaletteColor(bool b) + +Converting from RGB to PALETTE_COLOR can be a slow operation. However +DICOM standard requires that color icon be described as palette. Set +this boolean to false only if you understand the consequences. true, +false generates invalid Icon Image Sequence "; + +%feature("docstring") gdcm::IconImageGenerator::Generate "bool +gdcm::IconImageGenerator::Generate() + +Generate Icon. "; + +%feature("docstring") gdcm::IconImageGenerator::GetIconImage "const +IconImage& gdcm::IconImageGenerator::GetIconImage() const + +Retrieve generated Icon. "; + +%feature("docstring") gdcm::IconImageGenerator::GetPixmap "const +Pixmap& gdcm::IconImageGenerator::GetPixmap() const "; + +%feature("docstring") gdcm::IconImageGenerator::GetPixmap "Pixmap& +gdcm::IconImageGenerator::GetPixmap() "; + +%feature("docstring") gdcm::IconImageGenerator::SetOutputDimensions "void gdcm::IconImageGenerator::SetOutputDimensions(const unsigned int +dims[2]) + +Set Target dimension of output Icon. "; + +%feature("docstring") gdcm::IconImageGenerator::SetOutsideValuePixel +"void gdcm::IconImageGenerator::SetOutsideValuePixel(double v) + +Set a pixel value that should be discarded. This happen typically for +CT image, where a pixel has been used to pad outside the image (see +Pixel Padding Value). Requires AutoPixelMinMax(true) "; + +%feature("docstring") gdcm::IconImageGenerator::SetPixelMinMax "void +gdcm::IconImageGenerator::SetPixelMinMax(double min, double max) + +Override default min/max to compute best rescale for 16bits -> 8bits +downscale. Typically those value can be read from the +SmallestImagePixelValue LargestImagePixelValue DICOM attribute. "; + +%feature("docstring") gdcm::IconImageGenerator::SetPixmap "void +gdcm::IconImageGenerator::SetPixmap(const Pixmap &p) + +Set/Get File. "; + + +// File: classstd_1_1ifstream.xml +%feature("docstring") std::ifstream " + +STL class. "; + + +// File: structgdcm_1_1ignore__char.xml +%feature("docstring") gdcm::ignore_char "C++ includes: gdcmElement.h +"; + +%feature("docstring") gdcm::ignore_char::ignore_char "gdcm::ignore_char::ignore_char(char c) "; + + +// File: classgdcm_1_1Image.xml +%feature("docstring") gdcm::Image " + +Image This is the container for an Image in the general sense. From +this container you should be able to request information like: Origin + +Dimension + +PixelFormat ... But also to retrieve the image as a raw buffer (char +*) Since we have to deal with both RAW data and JPEG stream (which +internally encode all the above information) this API might seems +redundant. One way to solve that would be to subclass gdcm::Image with +gdcm::JPEGImage which would from the stream extract the header info +and fill it to please gdcm::Image...well except origin for instance. + +Basically you can see it as a storage for the Pixel Data element +(7fe0,0010). + +WARNING: This class does some heuristics to guess the Spacing but is +not compatible with DICOM CP-586. In case of doubt use PixmapReader +instead + +See: ImageReader PixmapReader + +C++ includes: gdcmImage.h "; + +%feature("docstring") gdcm::Image::Image "gdcm::Image::Image() "; + +%feature("docstring") gdcm::Image::~Image "gdcm::Image::~Image() "; + +%feature("docstring") gdcm::Image::GetDirectionCosines "const +double* gdcm::Image::GetDirectionCosines() const + +Return a 6-tuples specifying the direction cosines A default value of +(1,0,0,0,1,0) will be return when the direction cosines was not +specified. "; + +%feature("docstring") gdcm::Image::GetDirectionCosines "double +gdcm::Image::GetDirectionCosines(unsigned int idx) const "; + +%feature("docstring") gdcm::Image::GetIntercept "double +gdcm::Image::GetIntercept() const "; + +%feature("docstring") gdcm::Image::GetOrigin "double +gdcm::Image::GetOrigin(unsigned int idx) const "; + +%feature("docstring") gdcm::Image::GetOrigin "const double* +gdcm::Image::GetOrigin() const + +Return a 3-tuples specifying the origin Will return (0,0,0) if the +origin was not specified. "; + +%feature("docstring") gdcm::Image::GetSlope "double +gdcm::Image::GetSlope() const "; + +%feature("docstring") gdcm::Image::GetSpacing "double +gdcm::Image::GetSpacing(unsigned int idx) const "; + +%feature("docstring") gdcm::Image::GetSpacing "const double* +gdcm::Image::GetSpacing() const + +Return a 3-tuples specifying the spacing NOTE: 3rd value can be an +aribtrary 1 value when the spacing was not specified (ex. 2D image). +WARNING: when the spacing is not specifier, a default value of 1 will +be returned "; + +%feature("docstring") gdcm::Image::Print "void +gdcm::Image::Print(std::ostream &os) const + +print "; + +%feature("docstring") gdcm::Image::SetDirectionCosines "void +gdcm::Image::SetDirectionCosines(const float *dircos) "; + +%feature("docstring") gdcm::Image::SetDirectionCosines "void +gdcm::Image::SetDirectionCosines(const double *dircos) "; + +%feature("docstring") gdcm::Image::SetDirectionCosines "void +gdcm::Image::SetDirectionCosines(unsigned int idx, double dircos) "; + +%feature("docstring") gdcm::Image::SetIntercept "void +gdcm::Image::SetIntercept(double intercept) + +intercept "; + +%feature("docstring") gdcm::Image::SetOrigin "void +gdcm::Image::SetOrigin(const double *ori) "; + +%feature("docstring") gdcm::Image::SetOrigin "void +gdcm::Image::SetOrigin(const float *ori) "; + +%feature("docstring") gdcm::Image::SetOrigin "void +gdcm::Image::SetOrigin(unsigned int idx, double ori) "; + +%feature("docstring") gdcm::Image::SetSlope "void +gdcm::Image::SetSlope(double slope) + +slope "; + +%feature("docstring") gdcm::Image::SetSpacing "void +gdcm::Image::SetSpacing(const double *spacing) "; + +%feature("docstring") gdcm::Image::SetSpacing "void +gdcm::Image::SetSpacing(unsigned int idx, double spacing) "; + + +// File: classgdcm_1_1ImageApplyLookupTable.xml +%feature("docstring") gdcm::ImageApplyLookupTable " + +ImageApplyLookupTable class It applies the LUT the PixelData (only +PALETTE_COLOR images) Output will be a PhotometricInterpretation=RGB +image. + +C++ includes: gdcmImageApplyLookupTable.h "; + +%feature("docstring") +gdcm::ImageApplyLookupTable::ImageApplyLookupTable "gdcm::ImageApplyLookupTable::ImageApplyLookupTable() "; + +%feature("docstring") +gdcm::ImageApplyLookupTable::~ImageApplyLookupTable "gdcm::ImageApplyLookupTable::~ImageApplyLookupTable() "; + +%feature("docstring") gdcm::ImageApplyLookupTable::Apply "bool +gdcm::ImageApplyLookupTable::Apply() + +Apply. "; + + +// File: classgdcm_1_1ImageChangePhotometricInterpretation.xml +%feature("docstring") gdcm::ImageChangePhotometricInterpretation " + +ImageChangePhotometricInterpretation class Class to change the +Photometric Interpetation of an input DICOM. + +C++ includes: gdcmImageChangePhotometricInterpretation.h "; + +%feature("docstring") +gdcm::ImageChangePhotometricInterpretation::ImageChangePhotometricInterpretation +"gdcm::ImageChangePhotometricInterpretation::ImageChangePhotometricInterpretation() +"; + +%feature("docstring") +gdcm::ImageChangePhotometricInterpretation::~ImageChangePhotometricInterpretation +"gdcm::ImageChangePhotometricInterpretation::~ImageChangePhotometricInterpretation() +"; + +%feature("docstring") +gdcm::ImageChangePhotometricInterpretation::Change "bool +gdcm::ImageChangePhotometricInterpretation::Change() + +Change. "; + +%feature("docstring") +gdcm::ImageChangePhotometricInterpretation::GetPhotometricInterpretation +"const PhotometricInterpretation& +gdcm::ImageChangePhotometricInterpretation::GetPhotometricInterpretation() +const "; + +%feature("docstring") +gdcm::ImageChangePhotometricInterpretation::SetPhotometricInterpretation +"void +gdcm::ImageChangePhotometricInterpretation::SetPhotometricInterpretation(PhotometricInterpretation +const &pi) + +Set/Get requested PhotometricInterpretation. "; + + +// File: classgdcm_1_1ImageChangePlanarConfiguration.xml +%feature("docstring") gdcm::ImageChangePlanarConfiguration " + +ImageChangePlanarConfiguration class Class to change the Planar +configuration of an input DICOM By default it will change into the +more usual reprensentation: PlanarConfiguration = 0. + +C++ includes: gdcmImageChangePlanarConfiguration.h "; + +%feature("docstring") +gdcm::ImageChangePlanarConfiguration::ImageChangePlanarConfiguration "gdcm::ImageChangePlanarConfiguration::ImageChangePlanarConfiguration() +"; + +%feature("docstring") +gdcm::ImageChangePlanarConfiguration::~ImageChangePlanarConfiguration +"gdcm::ImageChangePlanarConfiguration::~ImageChangePlanarConfiguration() +"; + +%feature("docstring") gdcm::ImageChangePlanarConfiguration::Change "bool gdcm::ImageChangePlanarConfiguration::Change() + +Change. "; + +%feature("docstring") +gdcm::ImageChangePlanarConfiguration::GetPlanarConfiguration "unsigned int +gdcm::ImageChangePlanarConfiguration::GetPlanarConfiguration() const +"; + +%feature("docstring") +gdcm::ImageChangePlanarConfiguration::SetPlanarConfiguration "void +gdcm::ImageChangePlanarConfiguration::SetPlanarConfiguration(unsigned +int pc) + +Set/Get requested PlanarConfigation. "; + + +// File: classgdcm_1_1ImageChangeTransferSyntax.xml +%feature("docstring") gdcm::ImageChangeTransferSyntax " + +ImageChangeTransferSyntax class Class to change the transfer syntax of +an input DICOM. + +If only Force param is set but no input TransferSyntax is set, it is +assumed that user only wants to inspect encapsulated stream (advanced +dev. option). + +When using UserCodec it is very important that the TransferSyntax (as +set in SetTransferSyntax) is actually understood by UserCodec (ie. +UserCodec->CanCode( TransferSyntax ) ). Otherwise the behavior is to +use a default codec. + +See: JPEGCodec JPEGLSCodec JPEG2000Codec + +C++ includes: gdcmImageChangeTransferSyntax.h "; + +%feature("docstring") +gdcm::ImageChangeTransferSyntax::ImageChangeTransferSyntax "gdcm::ImageChangeTransferSyntax::ImageChangeTransferSyntax() "; + +%feature("docstring") +gdcm::ImageChangeTransferSyntax::~ImageChangeTransferSyntax "gdcm::ImageChangeTransferSyntax::~ImageChangeTransferSyntax() "; + +%feature("docstring") gdcm::ImageChangeTransferSyntax::Change "bool +gdcm::ImageChangeTransferSyntax::Change() + +Change. "; + +%feature("docstring") +gdcm::ImageChangeTransferSyntax::GetTransferSyntax "const +TransferSyntax& gdcm::ImageChangeTransferSyntax::GetTransferSyntax() +const + +Get Transfer Syntax. "; + +%feature("docstring") +gdcm::ImageChangeTransferSyntax::SetCompressIconImage "void +gdcm::ImageChangeTransferSyntax::SetCompressIconImage(bool b) + +Decide whether or not to also compress the Icon Image using the same +Transfer Syntax Default is to simply decompress icon image "; + +%feature("docstring") gdcm::ImageChangeTransferSyntax::SetForce "void gdcm::ImageChangeTransferSyntax::SetForce(bool f) + +When target Transfer Syntax is identical to input target syntax, no +operation is actually done This is an issue when someone wants to +recompress using GDCM internal implementation a JPEG (for example) +image "; + +%feature("docstring") +gdcm::ImageChangeTransferSyntax::SetTransferSyntax "void +gdcm::ImageChangeTransferSyntax::SetTransferSyntax(const +TransferSyntax &ts) + +Set target Transfer Syntax. "; + +%feature("docstring") gdcm::ImageChangeTransferSyntax::SetUserCodec "void gdcm::ImageChangeTransferSyntax::SetUserCodec(ImageCodec *ic) + +Allow user to specify exactly which codec to use. this is needed to +specify special qualities or compression option. WARNING: is the +codec 'ic' is not compatible with the TransferSyntax requested, it +will not be used. It is the user responsability to check that +UserCodec->CanCode( TransferSyntax ) "; + + +// File: classgdcm_1_1ImageCodec.xml +%feature("docstring") gdcm::ImageCodec " + +ImageCodec. + +Main codec, this is a central place for all implementation + +C++ includes: gdcmImageCodec.h "; + +%feature("docstring") gdcm::ImageCodec::ImageCodec "gdcm::ImageCodec::ImageCodec() "; + +%feature("docstring") gdcm::ImageCodec::~ImageCodec "gdcm::ImageCodec::~ImageCodec() "; + +%feature("docstring") gdcm::ImageCodec::CanCode "bool +gdcm::ImageCodec::CanCode(TransferSyntax const &) const "; + +%feature("docstring") gdcm::ImageCodec::CanDecode "bool +gdcm::ImageCodec::CanDecode(TransferSyntax const &) const + +Return whether this decoder support this transfer syntax (can decode +it). "; + +%feature("docstring") gdcm::ImageCodec::Decode "bool +gdcm::ImageCodec::Decode(DataElement const &is_, DataElement &os) + +Decode. "; + +%feature("docstring") gdcm::ImageCodec::GetDimensions "const +unsigned int* gdcm::ImageCodec::GetDimensions() const "; + +%feature("docstring") gdcm::ImageCodec::GetHeaderInfo "virtual bool +gdcm::ImageCodec::GetHeaderInfo(std::istream &is_, TransferSyntax &ts) +"; + +%feature("docstring") gdcm::ImageCodec::GetLossyFlag "bool +gdcm::ImageCodec::GetLossyFlag() const "; + +%feature("docstring") gdcm::ImageCodec::GetLUT "const LookupTable& +gdcm::ImageCodec::GetLUT() const "; + +%feature("docstring") gdcm::ImageCodec::GetNeedByteSwap "bool +gdcm::ImageCodec::GetNeedByteSwap() const "; + +%feature("docstring") gdcm::ImageCodec::GetNumberOfDimensions "unsigned int gdcm::ImageCodec::GetNumberOfDimensions() const "; + +%feature("docstring") gdcm::ImageCodec::GetPhotometricInterpretation +"const PhotometricInterpretation& +gdcm::ImageCodec::GetPhotometricInterpretation() const "; + +%feature("docstring") gdcm::ImageCodec::GetPixelFormat "const +PixelFormat& gdcm::ImageCodec::GetPixelFormat() const "; + +%feature("docstring") gdcm::ImageCodec::GetPixelFormat "PixelFormat& +gdcm::ImageCodec::GetPixelFormat() "; + +%feature("docstring") gdcm::ImageCodec::GetPlanarConfiguration "unsigned int gdcm::ImageCodec::GetPlanarConfiguration() const "; + +%feature("docstring") gdcm::ImageCodec::IsLossy "bool +gdcm::ImageCodec::IsLossy() const "; + +%feature("docstring") gdcm::ImageCodec::SetDimensions "void +gdcm::ImageCodec::SetDimensions(const std::vector< unsigned int > &d) +"; + +%feature("docstring") gdcm::ImageCodec::SetDimensions "void +gdcm::ImageCodec::SetDimensions(const unsigned int d[3]) "; + +%feature("docstring") gdcm::ImageCodec::SetLossyFlag "void +gdcm::ImageCodec::SetLossyFlag(bool l) "; + +%feature("docstring") gdcm::ImageCodec::SetLUT "void +gdcm::ImageCodec::SetLUT(LookupTable const &lut) "; + +%feature("docstring") gdcm::ImageCodec::SetNeedByteSwap "void +gdcm::ImageCodec::SetNeedByteSwap(bool b) "; + +%feature("docstring") gdcm::ImageCodec::SetNeedOverlayCleanup "void +gdcm::ImageCodec::SetNeedOverlayCleanup(bool b) "; + +%feature("docstring") gdcm::ImageCodec::SetNumberOfDimensions "void +gdcm::ImageCodec::SetNumberOfDimensions(unsigned int dim) "; + +%feature("docstring") gdcm::ImageCodec::SetPhotometricInterpretation +"void +gdcm::ImageCodec::SetPhotometricInterpretation(PhotometricInterpretation +const &pi) "; + +%feature("docstring") gdcm::ImageCodec::SetPixelFormat "virtual void +gdcm::ImageCodec::SetPixelFormat(PixelFormat const &pf) "; + +%feature("docstring") gdcm::ImageCodec::SetPlanarConfiguration "void +gdcm::ImageCodec::SetPlanarConfiguration(unsigned int pc) "; + + +// File: classgdcm_1_1ImageConverter.xml +%feature("docstring") gdcm::ImageConverter " + +Image Converter. + +This is the class used to convert from on gdcm::Image to another This +is typically used to convert let say YBR JPEG compressed gdcm::Image +to a RAW RGB gdcm::Image. So that the buffer can be directly pass to +third party application. This filter is application level and not +integrated directly in GDCM + +C++ includes: gdcmImageConverter.h "; + +%feature("docstring") gdcm::ImageConverter::ImageConverter "gdcm::ImageConverter::ImageConverter() "; + +%feature("docstring") gdcm::ImageConverter::~ImageConverter "gdcm::ImageConverter::~ImageConverter() "; + +%feature("docstring") gdcm::ImageConverter::Convert "void +gdcm::ImageConverter::Convert() "; + +%feature("docstring") gdcm::ImageConverter::GetOuput "const Image& +gdcm::ImageConverter::GetOuput() const "; + +%feature("docstring") gdcm::ImageConverter::SetInput "void +gdcm::ImageConverter::SetInput(Image const &input) "; + + +// File: classgdcm_1_1ImageFragmentSplitter.xml +%feature("docstring") gdcm::ImageFragmentSplitter " + +ImageFragmentSplitter class For single frame image, DICOM standard +allow splitting the frame into multiple fragments. + +C++ includes: gdcmImageFragmentSplitter.h "; + +%feature("docstring") +gdcm::ImageFragmentSplitter::ImageFragmentSplitter "gdcm::ImageFragmentSplitter::ImageFragmentSplitter() "; + +%feature("docstring") +gdcm::ImageFragmentSplitter::~ImageFragmentSplitter "gdcm::ImageFragmentSplitter::~ImageFragmentSplitter() "; + +%feature("docstring") gdcm::ImageFragmentSplitter::GetFragmentSizeMax +"unsigned int gdcm::ImageFragmentSplitter::GetFragmentSizeMax() const +"; + +%feature("docstring") gdcm::ImageFragmentSplitter::SetForce "void +gdcm::ImageFragmentSplitter::SetForce(bool f) + +When file already has all it's segment < FragmentSizeMax there is not +need to run the filter. Unless the user explicitly say 'force' +recomputation ! "; + +%feature("docstring") gdcm::ImageFragmentSplitter::SetFragmentSizeMax +"void gdcm::ImageFragmentSplitter::SetFragmentSizeMax(unsigned int +fragsize) + +FragmentSizeMax needs to be an even number. "; + +%feature("docstring") gdcm::ImageFragmentSplitter::Split "bool +gdcm::ImageFragmentSplitter::Split() + +Split. "; + + +// File: classgdcm_1_1ImageHelper.xml +%feature("docstring") gdcm::ImageHelper " + +ImageHelper (internal class, not intended for user level). + +Helper for writing World images in DICOM. DICOM has a 'template' +approach to image where MR Image Storage are distinct object from +Enhanced MR Image Storage. For example the Pixel Spacing in one object +is not at the same position (ie Tag) as in the other this class is the +central (read: fragile) place where all the dispatching is done from a +unified view of a world image (typically VTK or ITK point of view) +down to the low level DICOM point of view. + +WARNING: : do not expect the API of this class to be maintained at +any point, since as Modalities are added the API might have to be +augmented or behavior changed to cope with new modalities. + +C++ includes: gdcmImageHelper.h "; + + +// File: classgdcm_1_1ImageReader.xml +%feature("docstring") gdcm::ImageReader " + +ImageReader. + +its role is to convert the DICOM DataSet into a gdcm::Image +representation Image is different from Pixmap has it has a position +and a direction in Space. + +See: Image + +C++ includes: gdcmImageReader.h "; + +%feature("docstring") gdcm::ImageReader::ImageReader "gdcm::ImageReader::ImageReader() "; + +%feature("docstring") gdcm::ImageReader::~ImageReader "virtual +gdcm::ImageReader::~ImageReader() "; + +%feature("docstring") gdcm::ImageReader::GetImage "const Image& +gdcm::ImageReader::GetImage() const + +Return the read image. "; + +%feature("docstring") gdcm::ImageReader::GetImage "Image& +gdcm::ImageReader::GetImage() "; + +%feature("docstring") gdcm::ImageReader::Read "virtual bool +gdcm::ImageReader::Read() + +Read the DICOM image. There are two reason for failure: 1. The input +filename is not DICOM 2. The input DICOM file does not contains an +Image. "; + + +// File: classgdcm_1_1ImageRegionReader.xml +%feature("docstring") gdcm::ImageRegionReader " + +ImageRegionReader. + +See: ImageReader + +C++ includes: gdcmImageRegionReader.h "; + +%feature("docstring") gdcm::ImageRegionReader::ImageRegionReader "gdcm::ImageRegionReader::ImageRegionReader() "; + +%feature("docstring") gdcm::ImageRegionReader::~ImageRegionReader "gdcm::ImageRegionReader::~ImageRegionReader() "; + +%feature("docstring") gdcm::ImageRegionReader::ComputeBufferLength "size_t gdcm::ImageRegionReader::ComputeBufferLength() const + +Explicit call which will compute the minimal buffer length that can +hold the whole uncompressed image as defined by Region `region`. 0 +upon error "; + +%feature("docstring") gdcm::ImageRegionReader::GetRegion "Region +const& gdcm::ImageRegionReader::GetRegion() const "; + +%feature("docstring") gdcm::ImageRegionReader::ReadInformation "bool +gdcm::ImageRegionReader::ReadInformation() + +Read meta information (not Pixel Data) from the DICOM file. false upon +error "; + +%feature("docstring") gdcm::ImageRegionReader::ReadIntoBuffer "bool +gdcm::ImageRegionReader::ReadIntoBuffer(char *inreadbuffer, size_t +buflen) + +Read into buffer: false upon error "; + +%feature("docstring") gdcm::ImageRegionReader::SetRegion "void +gdcm::ImageRegionReader::SetRegion(Region const ®ion) + +Set/Get Region to be read. "; + + +// File: classgdcm_1_1ImageToImageFilter.xml +%feature("docstring") gdcm::ImageToImageFilter " + +ImageToImageFilter class Super class for all filter taking an image +and producing an output image. + +C++ includes: gdcmImageToImageFilter.h "; + +%feature("docstring") gdcm::ImageToImageFilter::ImageToImageFilter "gdcm::ImageToImageFilter::ImageToImageFilter() "; + +%feature("docstring") gdcm::ImageToImageFilter::~ImageToImageFilter "gdcm::ImageToImageFilter::~ImageToImageFilter() "; + +%feature("docstring") gdcm::ImageToImageFilter::GetInput "Image& +gdcm::ImageToImageFilter::GetInput() "; + +%feature("docstring") gdcm::ImageToImageFilter::GetOutput "const +Image& gdcm::ImageToImageFilter::GetOutput() const + +Get Output image. "; + + +// File: classgdcm_1_1ImageWriter.xml +%feature("docstring") gdcm::ImageWriter " + +ImageWriter. + +C++ includes: gdcmImageWriter.h "; + +%feature("docstring") gdcm::ImageWriter::ImageWriter "gdcm::ImageWriter::ImageWriter() "; + +%feature("docstring") gdcm::ImageWriter::~ImageWriter "gdcm::ImageWriter::~ImageWriter() "; + +%feature("docstring") gdcm::ImageWriter::GetImage "Image& +gdcm::ImageWriter::GetImage() "; + +%feature("docstring") gdcm::ImageWriter::GetImage "const Image& +gdcm::ImageWriter::GetImage() const + +Set/Get Image to be written It will overwrite anything Image infos +found in DataSet (see parent class to see how to pass dataset) "; + +%feature("docstring") gdcm::ImageWriter::Write "bool +gdcm::ImageWriter::Write() + +Write. "; + + +// File: classgdcm_1_1network_1_1ImplementationClassUIDSub.xml +%feature("docstring") gdcm::network::ImplementationClassUIDSub " + +ImplementationClassUIDSub PS 3.7 Table D.3-1 IMPLEMENTATION CLASS UID +SUB-ITEM FIELDS (A-ASSOCIATE-RQ). + +C++ includes: gdcmImplementationClassUIDSub.h "; + +%feature("docstring") +gdcm::network::ImplementationClassUIDSub::ImplementationClassUIDSub "gdcm::network::ImplementationClassUIDSub::ImplementationClassUIDSub() +"; + +%feature("docstring") gdcm::network::ImplementationClassUIDSub::Print +"void gdcm::network::ImplementationClassUIDSub::Print(std::ostream +&os) const "; + +%feature("docstring") gdcm::network::ImplementationClassUIDSub::Read +"std::istream& +gdcm::network::ImplementationClassUIDSub::Read(std::istream &is) "; + +%feature("docstring") gdcm::network::ImplementationClassUIDSub::Size +"size_t gdcm::network::ImplementationClassUIDSub::Size() const "; + +%feature("docstring") gdcm::network::ImplementationClassUIDSub::Write +"const std::ostream& +gdcm::network::ImplementationClassUIDSub::Write(std::ostream &os) +const "; + + +// File: classgdcm_1_1network_1_1ImplementationUIDSub.xml +%feature("docstring") gdcm::network::ImplementationUIDSub " + +ImplementationUIDSub Table D.3-2 IMPLEMENTATION UID SUB-ITEM FIELDS (A +-ASSOCIATE-AC). + +C++ includes: gdcmImplementationUIDSub.h "; + +%feature("docstring") +gdcm::network::ImplementationUIDSub::ImplementationUIDSub "gdcm::network::ImplementationUIDSub::ImplementationUIDSub() "; + +%feature("docstring") gdcm::network::ImplementationUIDSub::Write "const std::ostream& +gdcm::network::ImplementationUIDSub::Write(std::ostream &os) const "; + + +// File: classgdcm_1_1network_1_1ImplementationVersionNameSub.xml +%feature("docstring") gdcm::network::ImplementationVersionNameSub " + +ImplementationVersionNameSub Table D.3-3 IMPLEMENTATION VERSION NAME +SUB-ITEM FIELDS (A-ASSOCIATE-RQ). + +C++ includes: gdcmImplementationVersionNameSub.h "; + +%feature("docstring") +gdcm::network::ImplementationVersionNameSub::ImplementationVersionNameSub +"gdcm::network::ImplementationVersionNameSub::ImplementationVersionNameSub() +"; + +%feature("docstring") +gdcm::network::ImplementationVersionNameSub::Print "void +gdcm::network::ImplementationVersionNameSub::Print(std::ostream &os) +const "; + +%feature("docstring") +gdcm::network::ImplementationVersionNameSub::Read "std::istream& +gdcm::network::ImplementationVersionNameSub::Read(std::istream &is) "; + +%feature("docstring") +gdcm::network::ImplementationVersionNameSub::Size "size_t +gdcm::network::ImplementationVersionNameSub::Size() const "; + +%feature("docstring") +gdcm::network::ImplementationVersionNameSub::Write "const +std::ostream& +gdcm::network::ImplementationVersionNameSub::Write(std::ostream &os) +const "; + + +// File: classgdcm_1_1ImplicitDataElement.xml +%feature("docstring") gdcm::ImplicitDataElement " + +Class to represent an *Implicit VR* Data Element. + +bla + +C++ includes: gdcmImplicitDataElement.h "; + +%feature("docstring") gdcm::ImplicitDataElement::GetLength "VL +gdcm::ImplicitDataElement::GetLength() const "; + +%feature("docstring") gdcm::ImplicitDataElement::Read "std::istream& +gdcm::ImplicitDataElement::Read(std::istream &is) "; + +%feature("docstring") gdcm::ImplicitDataElement::ReadPreValue "std::istream& gdcm::ImplicitDataElement::ReadPreValue(std::istream +&is) "; + +%feature("docstring") gdcm::ImplicitDataElement::ReadValue "std::istream& gdcm::ImplicitDataElement::ReadValue(std::istream &is) +"; + +%feature("docstring") gdcm::ImplicitDataElement::ReadWithLength "std::istream& gdcm::ImplicitDataElement::ReadWithLength(std::istream +&is, VL &length) "; + +%feature("docstring") gdcm::ImplicitDataElement::Write "const +std::ostream& gdcm::ImplicitDataElement::Write(std::ostream &os) const +"; + + +// File: classgdcm_1_1InitializeEvent.xml +%feature("docstring") gdcm::InitializeEvent "C++ includes: +gdcmEvent.h "; + + +// File: classstd_1_1invalid__argument.xml +%feature("docstring") std::invalid_argument " + +STL class. "; + + +// File: classgdcm_1_1IOD.xml +%feature("docstring") gdcm::IOD " + +Class for representing a IOD. + +bla + +See: Dict + +C++ includes: gdcmIOD.h "; + +%feature("docstring") gdcm::IOD::IOD "gdcm::IOD::IOD() "; + +%feature("docstring") gdcm::IOD::AddIODEntry "void +gdcm::IOD::AddIODEntry(const IODEntry &iode) "; + +%feature("docstring") gdcm::IOD::Clear "void gdcm::IOD::Clear() "; + +%feature("docstring") gdcm::IOD::GetIODEntry "const IODEntry& +gdcm::IOD::GetIODEntry(SizeType idx) const "; + +%feature("docstring") gdcm::IOD::GetNumberOfIODs "SizeType +gdcm::IOD::GetNumberOfIODs() const "; + +%feature("docstring") gdcm::IOD::GetTypeFromTag "Type +gdcm::IOD::GetTypeFromTag(const Defs &defs, const Tag &tag) const "; + + +// File: classgdcm_1_1IODEntry.xml +%feature("docstring") gdcm::IODEntry " + +Class for representing a IODEntry. + +A.1.3 IOD Module Table and Functional Group Macro Table This Section +of each IOD defines in a tabular form the Modules comprising the IOD. +The following information must be specified for each Module in the +table: The name of the Module or Functional Group + +A reference to the Section in Annex C which defines the Module or +Functional Group + +The usage of the Module or Functional Group; whether it is: + +Mandatory (see A.1.3.1) , abbreviated M + +Conditional (see A.1.3.2) , abbreviated C + +User Option (see A.1.3.3) , abbreviated U The Modules referenced are +defined in Annex C. A.1.3.1 MANDATORY MODULES For each IOD, Mandatory +Modules shall be supported per the definitions, semantics and +requirements defined in Annex C. PS 3.3 - 2008 Page 96 + +Standard - A.1.3.2 CONDITIONAL MODULES Conditional Modules are +Mandatory Modules if specific conditions are met. If the specified +conditions are not met, this Module shall not be supported; that is, +no information defined in that Module shall be sent. A.1.3.3 USER +OPTION MODULES User Option Modules may or may not be supported. If an +optional Module is supported, the Attribute Types specified in the +Modules in Annex C shall be supported. + +See: DictEntry + +C++ includes: gdcmIODEntry.h "; + +%feature("docstring") gdcm::IODEntry::IODEntry "gdcm::IODEntry::IODEntry(const char *name=\"\", const char *ref=\"\", +const char *usag=\"\") "; + +%feature("docstring") gdcm::IODEntry::GetIE "const char* +gdcm::IODEntry::GetIE() const "; + +%feature("docstring") gdcm::IODEntry::GetName "const char* +gdcm::IODEntry::GetName() const "; + +%feature("docstring") gdcm::IODEntry::GetRef "const char* +gdcm::IODEntry::GetRef() const "; + +%feature("docstring") gdcm::IODEntry::GetUsage "const char* +gdcm::IODEntry::GetUsage() const "; + +%feature("docstring") gdcm::IODEntry::GetUsageType "Usage::UsageType +gdcm::IODEntry::GetUsageType() const "; + +%feature("docstring") gdcm::IODEntry::SetIE "void +gdcm::IODEntry::SetIE(const char *ie) "; + +%feature("docstring") gdcm::IODEntry::SetName "void +gdcm::IODEntry::SetName(const char *name) "; + +%feature("docstring") gdcm::IODEntry::SetRef "void +gdcm::IODEntry::SetRef(const char *ref) "; + +%feature("docstring") gdcm::IODEntry::SetUsage "void +gdcm::IODEntry::SetUsage(const char *usag) "; + + +// File: classgdcm_1_1IODs.xml +%feature("docstring") gdcm::IODs " + +Class for representing a IODs. + +bla + +See: IOD + +C++ includes: gdcmIODs.h "; + +%feature("docstring") gdcm::IODs::IODs "gdcm::IODs::IODs() "; + +%feature("docstring") gdcm::IODs::AddIOD "void +gdcm::IODs::AddIOD(const char *name, const IOD &module) "; + +%feature("docstring") gdcm::IODs::Begin "IODMapTypeConstIterator +gdcm::IODs::Begin() const "; + +%feature("docstring") gdcm::IODs::Clear "void gdcm::IODs::Clear() "; + +%feature("docstring") gdcm::IODs::End "IODMapTypeConstIterator +gdcm::IODs::End() const "; + +%feature("docstring") gdcm::IODs::GetIOD "const IOD& +gdcm::IODs::GetIOD(const char *name) const "; + + +// File: classstd_1_1ios.xml +%feature("docstring") std::ios " + +STL class. "; + + +// File: classstd_1_1ios__base.xml +%feature("docstring") std::ios_base " + +STL class. "; + + +// File: classgdcm_1_1IPPSorter.xml +%feature("docstring") gdcm::IPPSorter " + +IPPSorter Implement a simple Image Position ( Patient) sorter, along +the Image Orientation ( Patient) direction. This algorithm does NOT +support duplicate and will FAIL in case of duplicate IPP. + +WARNING: See special note for SetZSpacingTolerance when computing the +ZSpacing from the IPP of each DICOM files (default tolerance for +consistant spacing is: 1e-6mm) For more information on Spacing, and +how it is defined in DICOM, advanced users may refers to: + +http://gdcm.sourceforge.net/wiki/index.php/Imager_Pixel_Spacing + +Bug There are currently a couple of bugs in this implementation: + +Gantry Tilt is not considered + +C++ includes: gdcmIPPSorter.h "; + +%feature("docstring") gdcm::IPPSorter::IPPSorter "gdcm::IPPSorter::IPPSorter() "; + +%feature("docstring") gdcm::IPPSorter::~IPPSorter "gdcm::IPPSorter::~IPPSorter() "; + +%feature("docstring") gdcm::IPPSorter::GetDirectionCosinesTolerance "double gdcm::IPPSorter::GetDirectionCosinesTolerance() const "; + +%feature("docstring") gdcm::IPPSorter::GetZSpacing "double +gdcm::IPPSorter::GetZSpacing() const + +Read-only function to provide access to the computed value for the +Z-Spacing The ComputeZSpacing must have been set to true before +execution of sort algorithm. Call this function *after* calling +Sort(); Z-Spacing will be 0 on 2 occasions: Sorting simply failed, +potentially duplicate IPP => ZSpacing = 0 + +ZSpacing could not be computed (Z-Spacing is not constant, or +ZTolerance is too low) "; + +%feature("docstring") gdcm::IPPSorter::GetZSpacingTolerance "double +gdcm::IPPSorter::GetZSpacingTolerance() const "; + +%feature("docstring") gdcm::IPPSorter::SetComputeZSpacing "void +gdcm::IPPSorter::SetComputeZSpacing(bool b) + +Functions related to Z-Spacing computation Set to true when sort +algorithm should also perform a regular Z-Spacing computation using +the Image Position ( Patient) Potential reason for failure: 1. ALL +slices are taken into account, if one slice if missing then ZSpacing +will be set to 0 since the spacing will not be found to be regular +along the Series "; + +%feature("docstring") gdcm::IPPSorter::SetDirectionCosinesTolerance "void gdcm::IPPSorter::SetDirectionCosinesTolerance(double tol) + +Sometimes IOP along a series is slightly changing for example: +\"0.999081\\\\\\\\0.0426953\\\\\\\\0.00369272\\\\\\\\-0.0419025\\\\\\\\0.955059\\\\\\\\0.293439\", +\"0.999081\\\\\\\\0.0426953\\\\\\\\0.00369275\\\\\\\\-0.0419025\\\\\\\\0.955059\\\\\\\\0.293439\", +\"0.999081\\\\\\\\0.0426952\\\\\\\\0.00369272\\\\\\\\-0.0419025\\\\\\\\0.955059\\\\\\\\0.293439\", +We need an API to define the tolerance which is allowed. Internally +the cross vector of each direction cosines is computed. The tolerance +then define the the distance in between 1. to the dot product of those +cross vectors. In a perfect world this dot product is of course 1.0 +which imply a DirectionCosines tolerance of exactly 0.0 (default). "; + +%feature("docstring") gdcm::IPPSorter::SetDropDuplicatePositions "void gdcm::IPPSorter::SetDropDuplicatePositions(bool b) + +Makes the IPPSorter ignore multiple images located at the same +position. Only the first occurence will be kept. +DropDuplicatePositions defaults to false. "; + +%feature("docstring") gdcm::IPPSorter::SetZSpacingTolerance "void +gdcm::IPPSorter::SetZSpacingTolerance(double tol) + +2. Another reason for failure is that that Z-Spacing is only slightly +changing (eg 1e-3) along the serie, a human can determine that this is +ok and change the tolerance from its default value: 1e-6 "; + +%feature("docstring") gdcm::IPPSorter::Sort "virtual bool +gdcm::IPPSorter::Sort(std::vector< std::string > const &filenames) + +Main entry point to the sorter. It will execute the filter, option +should be set before running this function (SetZSpacingTolerance, ...) +Return value indicate if sorting could be achived. Warning this does +*NOT* imply that spacing is consistant, it only means the file are +sorted according to IPP You should check if ZSpacing is 0 or not to +deduce if file are actually a 3D volume "; + + +// File: classstd_1_1istream.xml +%feature("docstring") std::istream " + +STL class. "; + + +// File: classstd_1_1istringstream.xml +%feature("docstring") std::istringstream " + +STL class. "; + + +// File: classgdcm_1_1Item.xml +%feature("docstring") gdcm::Item " + +Class to represent an Item A component of the value of a Data Element +that is of Value Representation Sequence of Items. An Item contains a +Data Set . See PS 3.5 7.5.1 Item Encoding Rules Each Item of a Data +Element of VR SQ shall be encoded as a DICOM Standart Data Element +with a specific Data Element Tag of Value (FFFE,E000). The Item Tag is +followed by a 4 byte Item Length field encoded in one of the following +two ways Explicit/ Implicit. + +ITEM: A component of the Value of a Data Element that is of Value +Representation Sequence of Items. An Item contains a Data Set. + +C++ includes: gdcmItem.h "; + +%feature("docstring") gdcm::Item::Item "gdcm::Item::Item() "; + +%feature("docstring") gdcm::Item::Item "gdcm::Item::Item(Item const +&val) "; + +%feature("docstring") gdcm::Item::Clear "void gdcm::Item::Clear() + +Clear Data Element (make Value empty and invalidate Tag & VR). "; + +%feature("docstring") gdcm::Item::FindDataElement "bool +gdcm::Item::FindDataElement(const Tag &t) const "; + +%feature("docstring") gdcm::Item::GetDataElement "const DataElement& +gdcm::Item::GetDataElement(const Tag &t) const "; + +%feature("docstring") gdcm::Item::GetLength "VL +gdcm::Item::GetLength() const "; + +%feature("docstring") gdcm::Item::GetNestedDataSet "DataSet& +gdcm::Item::GetNestedDataSet() "; + +%feature("docstring") gdcm::Item::GetNestedDataSet "const DataSet& +gdcm::Item::GetNestedDataSet() const "; + +%feature("docstring") gdcm::Item::InsertDataElement "void +gdcm::Item::InsertDataElement(const DataElement &de) "; + +%feature("docstring") gdcm::Item::Read "std::istream& +gdcm::Item::Read(std::istream &is) "; + +%feature("docstring") gdcm::Item::SetNestedDataSet "void +gdcm::Item::SetNestedDataSet(const DataSet &nested) "; + +%feature("docstring") gdcm::Item::Write "const std::ostream& +gdcm::Item::Write(std::ostream &os) const "; + + +// File: classgdcm_1_1IterationEvent.xml +%feature("docstring") gdcm::IterationEvent "C++ includes: gdcmEvent.h +"; + + +// File: classstd_1_1basic__string_1_1iterator.xml +%feature("docstring") std::basic_string::iterator " + +STL iterator class. "; + + +// File: classstd_1_1string_1_1iterator.xml +%feature("docstring") std::string::iterator " + +STL iterator class. "; + + +// File: classstd_1_1wstring_1_1iterator.xml +%feature("docstring") std::wstring::iterator " + +STL iterator class. "; + + +// File: classstd_1_1deque_1_1iterator.xml +%feature("docstring") std::deque::iterator " + +STL iterator class. "; + + +// File: classstd_1_1list_1_1iterator.xml +%feature("docstring") std::list::iterator " + +STL iterator class. "; + + +// File: classstd_1_1map_1_1iterator.xml +%feature("docstring") std::map::iterator " + +STL iterator class. "; + + +// File: classstd_1_1multimap_1_1iterator.xml +%feature("docstring") std::multimap::iterator " + +STL iterator class. "; + + +// File: classstd_1_1set_1_1iterator.xml +%feature("docstring") std::set::iterator " + +STL iterator class. "; + + +// File: classstd_1_1multiset_1_1iterator.xml +%feature("docstring") std::multiset::iterator " + +STL iterator class. "; + + +// File: classstd_1_1vector_1_1iterator.xml +%feature("docstring") std::vector::iterator " + +STL iterator class. "; + + +// File: classgdcm_1_1JPEG12Codec.xml +%feature("docstring") gdcm::JPEG12Codec " + +Class to do JPEG 12bits (lossy & lossless). + +internal class + +C++ includes: gdcmJPEG12Codec.h "; + +%feature("docstring") gdcm::JPEG12Codec::JPEG12Codec "gdcm::JPEG12Codec::JPEG12Codec() "; + +%feature("docstring") gdcm::JPEG12Codec::~JPEG12Codec "gdcm::JPEG12Codec::~JPEG12Codec() "; + +%feature("docstring") gdcm::JPEG12Codec::DecodeByStreams "bool +gdcm::JPEG12Codec::DecodeByStreams(std::istream &is, std::ostream &os) +"; + +%feature("docstring") gdcm::JPEG12Codec::GetHeaderInfo "bool +gdcm::JPEG12Codec::GetHeaderInfo(std::istream &is, TransferSyntax &ts) +"; + +%feature("docstring") gdcm::JPEG12Codec::InternalCode "bool +gdcm::JPEG12Codec::InternalCode(const char *input, unsigned long len, +std::ostream &os) "; + + +// File: classgdcm_1_1JPEG16Codec.xml +%feature("docstring") gdcm::JPEG16Codec " + +Class to do JPEG 16bits (lossless). + +internal class + +C++ includes: gdcmJPEG16Codec.h "; + +%feature("docstring") gdcm::JPEG16Codec::JPEG16Codec "gdcm::JPEG16Codec::JPEG16Codec() "; + +%feature("docstring") gdcm::JPEG16Codec::~JPEG16Codec "gdcm::JPEG16Codec::~JPEG16Codec() "; + +%feature("docstring") gdcm::JPEG16Codec::DecodeByStreams "bool +gdcm::JPEG16Codec::DecodeByStreams(std::istream &is, std::ostream &os) +"; + +%feature("docstring") gdcm::JPEG16Codec::GetHeaderInfo "bool +gdcm::JPEG16Codec::GetHeaderInfo(std::istream &is, TransferSyntax &ts) +"; + +%feature("docstring") gdcm::JPEG16Codec::InternalCode "bool +gdcm::JPEG16Codec::InternalCode(const char *input, unsigned long len, +std::ostream &os) "; + + +// File: classgdcm_1_1JPEG2000Codec.xml +%feature("docstring") gdcm::JPEG2000Codec " + +Class to do JPEG 2000. + +the class will produce JPC (JPEG 2000 codestream), since some private +implementor are using full jp2 file the decoder tolerate jp2 input +this is an implementation of an ImageCodec + +C++ includes: gdcmJPEG2000Codec.h "; + +%feature("docstring") gdcm::JPEG2000Codec::JPEG2000Codec "gdcm::JPEG2000Codec::JPEG2000Codec() "; + +%feature("docstring") gdcm::JPEG2000Codec::~JPEG2000Codec "gdcm::JPEG2000Codec::~JPEG2000Codec() "; + +%feature("docstring") gdcm::JPEG2000Codec::CanCode "bool +gdcm::JPEG2000Codec::CanCode(TransferSyntax const &ts) const "; + +%feature("docstring") gdcm::JPEG2000Codec::CanDecode "bool +gdcm::JPEG2000Codec::CanDecode(TransferSyntax const &ts) const + +Return whether this decoder support this transfer syntax (can decode +it). "; + +%feature("docstring") gdcm::JPEG2000Codec::Code "bool +gdcm::JPEG2000Codec::Code(DataElement const &in, DataElement &out) "; + +%feature("docstring") gdcm::JPEG2000Codec::Decode "bool +gdcm::JPEG2000Codec::Decode(DataElement const &is, DataElement &os) + +Decode. "; + +%feature("docstring") gdcm::JPEG2000Codec::GetHeaderInfo "virtual +bool gdcm::JPEG2000Codec::GetHeaderInfo(std::istream &is, +TransferSyntax &ts) "; + +%feature("docstring") gdcm::JPEG2000Codec::GetQuality "double +gdcm::JPEG2000Codec::GetQuality(unsigned int idx=0) const "; + +%feature("docstring") gdcm::JPEG2000Codec::GetRate "double +gdcm::JPEG2000Codec::GetRate(unsigned int idx=0) const "; + +%feature("docstring") gdcm::JPEG2000Codec::SetNumberOfResolutions "void gdcm::JPEG2000Codec::SetNumberOfResolutions(unsigned int nres) "; + +%feature("docstring") gdcm::JPEG2000Codec::SetQuality "void +gdcm::JPEG2000Codec::SetQuality(unsigned int idx, double q) "; + +%feature("docstring") gdcm::JPEG2000Codec::SetRate "void +gdcm::JPEG2000Codec::SetRate(unsigned int idx, double rate) "; + +%feature("docstring") gdcm::JPEG2000Codec::SetReversible "void +gdcm::JPEG2000Codec::SetReversible(bool res) "; + +%feature("docstring") gdcm::JPEG2000Codec::SetTileSize "void +gdcm::JPEG2000Codec::SetTileSize(unsigned int tx, unsigned int ty) "; + + +// File: classgdcm_1_1JPEG8Codec.xml +%feature("docstring") gdcm::JPEG8Codec " + +Class to do JPEG 8bits (lossy & lossless). + +internal class + +C++ includes: gdcmJPEG8Codec.h "; + +%feature("docstring") gdcm::JPEG8Codec::JPEG8Codec "gdcm::JPEG8Codec::JPEG8Codec() "; + +%feature("docstring") gdcm::JPEG8Codec::~JPEG8Codec "gdcm::JPEG8Codec::~JPEG8Codec() "; + +%feature("docstring") gdcm::JPEG8Codec::DecodeByStreams "bool +gdcm::JPEG8Codec::DecodeByStreams(std::istream &is, std::ostream &os) +"; + +%feature("docstring") gdcm::JPEG8Codec::GetHeaderInfo "bool +gdcm::JPEG8Codec::GetHeaderInfo(std::istream &is, TransferSyntax &ts) +"; + +%feature("docstring") gdcm::JPEG8Codec::InternalCode "bool +gdcm::JPEG8Codec::InternalCode(const char *input, unsigned long len, +std::ostream &os) "; + + +// File: classgdcm_1_1JPEGCodec.xml +%feature("docstring") gdcm::JPEGCodec " + +JPEG codec Class to do JPEG (8bits, 12bits, 16bits lossy & lossless). +It redispatch in between the different codec implementation: +gdcm::JPEG8Codec, gdcm::JPEG12Codec & gdcm::JPEG16Codec It also +support inconsistency in between DICOM header and JPEG compressed +stream ImageCodec implementation for the JPEG case. + +Things you should know if you ever want to dive into DICOM/JPEG world +(among other): + +http://groups.google.com/group/comp.protocols.dicom/browse_thread/thread/625e46919f2080e1 + +http://groups.google.com/group/comp.protocols.dicom/browse_thread/thread/75fdfccc65a6243 + +http://groups.google.com/group/comp.protocols.dicom/browse_thread/thread/2d525ef6a2f093ed + +http://groups.google.com/group/comp.protocols.dicom/browse_thread/thread/6b93af410f8c921f + +C++ includes: gdcmJPEGCodec.h "; + +%feature("docstring") gdcm::JPEGCodec::JPEGCodec "gdcm::JPEGCodec::JPEGCodec() "; + +%feature("docstring") gdcm::JPEGCodec::~JPEGCodec "gdcm::JPEGCodec::~JPEGCodec() "; + +%feature("docstring") gdcm::JPEGCodec::CanCode "bool +gdcm::JPEGCodec::CanCode(TransferSyntax const &ts) const "; + +%feature("docstring") gdcm::JPEGCodec::CanDecode "bool +gdcm::JPEGCodec::CanDecode(TransferSyntax const &ts) const + +Return whether this decoder support this transfer syntax (can decode +it). "; + +%feature("docstring") gdcm::JPEGCodec::Code "bool +gdcm::JPEGCodec::Code(DataElement const &in, DataElement &out) + +Compress into JPEG. "; + +%feature("docstring") gdcm::JPEGCodec::ComputeOffsetTable "void +gdcm::JPEGCodec::ComputeOffsetTable(bool b) + +Compute the offset table: "; + +%feature("docstring") gdcm::JPEGCodec::Decode "bool +gdcm::JPEGCodec::Decode(DataElement const &is, DataElement &os) + +Decode. "; + +%feature("docstring") gdcm::JPEGCodec::GetHeaderInfo "virtual bool +gdcm::JPEGCodec::GetHeaderInfo(std::istream &is, TransferSyntax &ts) +"; + +%feature("docstring") gdcm::JPEGCodec::GetLossless "bool +gdcm::JPEGCodec::GetLossless() const "; + +%feature("docstring") gdcm::JPEGCodec::GetQuality "double +gdcm::JPEGCodec::GetQuality() const "; + +%feature("docstring") gdcm::JPEGCodec::SetLossless "void +gdcm::JPEGCodec::SetLossless(bool l) "; + +%feature("docstring") gdcm::JPEGCodec::SetPixelFormat "void +gdcm::JPEGCodec::SetPixelFormat(PixelFormat const &pf) "; + +%feature("docstring") gdcm::JPEGCodec::SetQuality "void +gdcm::JPEGCodec::SetQuality(double q) "; + + +// File: classgdcm_1_1JPEGLSCodec.xml +%feature("docstring") gdcm::JPEGLSCodec " + +JPEG-LS. + +codec that implement the JPEG-LS compression this is an implementation +of ImageCodec for JPEG-LS It uses the CharLS JPEG-LS +implementationhttp://charls.codeplex.com + +C++ includes: gdcmJPEGLSCodec.h "; + +%feature("docstring") gdcm::JPEGLSCodec::JPEGLSCodec "gdcm::JPEGLSCodec::JPEGLSCodec() "; + +%feature("docstring") gdcm::JPEGLSCodec::~JPEGLSCodec "gdcm::JPEGLSCodec::~JPEGLSCodec() "; + +%feature("docstring") gdcm::JPEGLSCodec::CanCode "bool +gdcm::JPEGLSCodec::CanCode(TransferSyntax const &ts) const "; + +%feature("docstring") gdcm::JPEGLSCodec::CanDecode "bool +gdcm::JPEGLSCodec::CanDecode(TransferSyntax const &ts) const + +Return whether this decoder support this transfer syntax (can decode +it). "; + +%feature("docstring") gdcm::JPEGLSCodec::Code "bool +gdcm::JPEGLSCodec::Code(DataElement const &in, DataElement &out) "; + +%feature("docstring") gdcm::JPEGLSCodec::Decode "bool +gdcm::JPEGLSCodec::Decode(DataElement const &in, char *outBuffer, +size_t inBufferLength, uint32_t inXMin, uint32_t inXMax, uint32_t +inYMin, uint32_t inYMax, uint32_t inZMin, uint32_t inZMax) "; + +%feature("docstring") gdcm::JPEGLSCodec::Decode "bool +gdcm::JPEGLSCodec::Decode(DataElement const &is, DataElement &os) + +Decode. "; + +%feature("docstring") gdcm::JPEGLSCodec::GetBufferLength "unsigned +long gdcm::JPEGLSCodec::GetBufferLength() const "; + +%feature("docstring") gdcm::JPEGLSCodec::GetHeaderInfo "bool +gdcm::JPEGLSCodec::GetHeaderInfo(std::istream &is, TransferSyntax &ts) +"; + +%feature("docstring") gdcm::JPEGLSCodec::GetLossless "bool +gdcm::JPEGLSCodec::GetLossless() const "; + +%feature("docstring") gdcm::JPEGLSCodec::SetBufferLength "void +gdcm::JPEGLSCodec::SetBufferLength(unsigned long l) "; + +%feature("docstring") gdcm::JPEGLSCodec::SetLossless "void +gdcm::JPEGLSCodec::SetLossless(bool l) "; + +%feature("docstring") gdcm::JPEGLSCodec::SetLossyError "void +gdcm::JPEGLSCodec::SetLossyError(int error) + +[0-3] generally "; + + +// File: classgdcm_1_1KAKADUCodec.xml +%feature("docstring") gdcm::KAKADUCodec " + +KAKADUCodec. + +C++ includes: gdcmKAKADUCodec.h "; + +%feature("docstring") gdcm::KAKADUCodec::KAKADUCodec "gdcm::KAKADUCodec::KAKADUCodec() "; + +%feature("docstring") gdcm::KAKADUCodec::~KAKADUCodec "gdcm::KAKADUCodec::~KAKADUCodec() "; + +%feature("docstring") gdcm::KAKADUCodec::CanCode "bool +gdcm::KAKADUCodec::CanCode(TransferSyntax const &ts) const "; + +%feature("docstring") gdcm::KAKADUCodec::CanDecode "bool +gdcm::KAKADUCodec::CanDecode(TransferSyntax const &ts) const + +Return whether this decoder support this transfer syntax (can decode +it). "; + +%feature("docstring") gdcm::KAKADUCodec::Code "bool +gdcm::KAKADUCodec::Code(DataElement const &in, DataElement &out) "; + +%feature("docstring") gdcm::KAKADUCodec::Decode "bool +gdcm::KAKADUCodec::Decode(DataElement const &is, DataElement &os) + +Decode. "; + + +// File: classstd_1_1length__error.xml +%feature("docstring") std::length_error " + +STL class. "; + + +// File: classstd_1_1list.xml +%feature("docstring") std::list " + +STL class. "; + + +// File: classgdcm_1_1LO.xml +%feature("docstring") gdcm::LO " + +LO. + +TODO + +C++ includes: gdcmLO.h "; + +%feature("docstring") gdcm::LO::LO "gdcm::LO::LO() "; + +%feature("docstring") gdcm::LO::LO "gdcm::LO::LO(const value_type +*s) "; + +%feature("docstring") gdcm::LO::LO "gdcm::LO::LO(const Superclass +&s, size_type pos=0, size_type n=npos) "; + +%feature("docstring") gdcm::LO::LO "gdcm::LO::LO(const value_type +*s, size_type n) "; + +%feature("docstring") gdcm::LO::IsValid "bool gdcm::LO::IsValid() +const "; + + +// File: classstd_1_1logic__error.xml +%feature("docstring") std::logic_error " + +STL class. "; + + +// File: classgdcm_1_1LookupTable.xml +%feature("docstring") gdcm::LookupTable " + +LookupTable class. + +C++ includes: gdcmLookupTable.h "; + +%feature("docstring") gdcm::LookupTable::LookupTable "gdcm::LookupTable::LookupTable() "; + +%feature("docstring") gdcm::LookupTable::LookupTable "gdcm::LookupTable::LookupTable(LookupTable const &lut) "; + +%feature("docstring") gdcm::LookupTable::~LookupTable "gdcm::LookupTable::~LookupTable() "; + +%feature("docstring") gdcm::LookupTable::Allocate "void +gdcm::LookupTable::Allocate(unsigned short bitsample=8) + +Allocate the LUT. "; + +%feature("docstring") gdcm::LookupTable::Clear "void +gdcm::LookupTable::Clear() + +Clear the LUT. "; + +%feature("docstring") gdcm::LookupTable::Decode "void +gdcm::LookupTable::Decode(std::istream &is, std::ostream &os) const + +Decode the LUT. "; + +%feature("docstring") gdcm::LookupTable::Decode "bool +gdcm::LookupTable::Decode(char *outputbuffer, size_t outlen, const +char *inputbuffer, size_t inlen) const + +Decode the LUT outputbuffer will contains the RGB decoded PALETTE +COLOR input image of size inlen the outputbuffer should be at least 3 +times the size of inlen "; + +%feature("docstring") gdcm::LookupTable::GetBitSample "unsigned +short gdcm::LookupTable::GetBitSample() const + +return the bit sample "; + +%feature("docstring") gdcm::LookupTable::GetBufferAsRGBA "bool +gdcm::LookupTable::GetBufferAsRGBA(unsigned char *rgba) const + +return the LUT as RGBA buffer "; + +%feature("docstring") gdcm::LookupTable::GetLUT "void +gdcm::LookupTable::GetLUT(LookupTableType type, unsigned char *array, +unsigned int &length) const "; + +%feature("docstring") gdcm::LookupTable::GetLUTDescriptor "void +gdcm::LookupTable::GetLUTDescriptor(LookupTableType type, unsigned +short &length, unsigned short &subscript, unsigned short &bitsize) +const "; + +%feature("docstring") gdcm::LookupTable::GetLUTLength "unsigned int +gdcm::LookupTable::GetLUTLength(LookupTableType type) const "; + +%feature("docstring") gdcm::LookupTable::GetPointer "const unsigned +char* gdcm::LookupTable::GetPointer() const + +return a raw pointer to the LUT "; + +%feature("docstring") gdcm::LookupTable::InitializeBlueLUT "void +gdcm::LookupTable::InitializeBlueLUT(unsigned short length, unsigned +short subscript, unsigned short bitsize) "; + +%feature("docstring") gdcm::LookupTable::Initialized "bool +gdcm::LookupTable::Initialized() const + +return whether the LUT has been initialized "; + +%feature("docstring") gdcm::LookupTable::InitializeGreenLUT "void +gdcm::LookupTable::InitializeGreenLUT(unsigned short length, unsigned +short subscript, unsigned short bitsize) "; + +%feature("docstring") gdcm::LookupTable::InitializeLUT "void +gdcm::LookupTable::InitializeLUT(LookupTableType type, unsigned short +length, unsigned short subscript, unsigned short bitsize) + +Generic interface: "; + +%feature("docstring") gdcm::LookupTable::InitializeRedLUT "void +gdcm::LookupTable::InitializeRedLUT(unsigned short length, unsigned +short subscript, unsigned short bitsize) + +RED / GREEN / BLUE specific: "; + +%feature("docstring") gdcm::LookupTable::Print "void +gdcm::LookupTable::Print(std::ostream &) const "; + +%feature("docstring") gdcm::LookupTable::SetBlueLUT "void +gdcm::LookupTable::SetBlueLUT(const unsigned char *blue, unsigned int +length) "; + +%feature("docstring") gdcm::LookupTable::SetGreenLUT "void +gdcm::LookupTable::SetGreenLUT(const unsigned char *green, unsigned +int length) "; + +%feature("docstring") gdcm::LookupTable::SetLUT "virtual void +gdcm::LookupTable::SetLUT(LookupTableType type, const unsigned char +*array, unsigned int length) "; + +%feature("docstring") gdcm::LookupTable::SetRedLUT "void +gdcm::LookupTable::SetRedLUT(const unsigned char *red, unsigned int +length) "; + +%feature("docstring") gdcm::LookupTable::WriteBufferAsRGBA "bool +gdcm::LookupTable::WriteBufferAsRGBA(const unsigned char *rgba) + +Write the LUT as RGBA. "; + + +// File: structgdcm_1_1Scanner_1_1ltstr.xml +%feature("docstring") gdcm::Scanner::ltstr "C++ includes: +gdcmScanner.h "; + + +// File: classgdcm_1_1Macro.xml +%feature("docstring") gdcm::Macro " + +Class for representing a Macro. + +Attribute Macro: a set of Attributes that are described in a single +table that is referenced by multiple Module or other tables. + +See: Module + +C++ includes: gdcmMacro.h "; + +%feature("docstring") gdcm::Macro::Macro "gdcm::Macro::Macro() "; + +%feature("docstring") gdcm::Macro::AddMacroEntry "void +gdcm::Macro::AddMacroEntry(const Tag &tag, const MacroEntry &module) + +Will add a ModuleEntry direcly at root-level. See Macro for nested- +included level. "; + +%feature("docstring") gdcm::Macro::Clear "void gdcm::Macro::Clear() +"; + +%feature("docstring") gdcm::Macro::FindMacroEntry "bool +gdcm::Macro::FindMacroEntry(const Tag &tag) const + +Find or Get a ModuleEntry. ModuleEntry are either search are root- +level or within nested-macro included in module. "; + +%feature("docstring") gdcm::Macro::GetMacroEntry "const MacroEntry& +gdcm::Macro::GetMacroEntry(const Tag &tag) const "; + +%feature("docstring") gdcm::Macro::GetName "const char* +gdcm::Macro::GetName() const "; + +%feature("docstring") gdcm::Macro::SetName "void +gdcm::Macro::SetName(const char *name) "; + +%feature("docstring") gdcm::Macro::Verify "bool +gdcm::Macro::Verify(const DataSet &ds, Usage const &usage) const "; + + +// File: classgdcm_1_1Macros.xml +%feature("docstring") gdcm::Macros " + +Class for representing a Modules. + +bla + +See: Module + +C++ includes: gdcmMacros.h "; + +%feature("docstring") gdcm::Macros::Macros "gdcm::Macros::Macros() +"; + +%feature("docstring") gdcm::Macros::AddMacro "void +gdcm::Macros::AddMacro(const char *ref, const Macro &module) "; + +%feature("docstring") gdcm::Macros::Clear "void +gdcm::Macros::Clear() "; + +%feature("docstring") gdcm::Macros::GetMacro "const Macro& +gdcm::Macros::GetMacro(const char *name) const "; + +%feature("docstring") gdcm::Macros::IsEmpty "bool +gdcm::Macros::IsEmpty() const "; + + +// File: classstd_1_1map.xml +%feature("docstring") std::map " + +STL class. "; + + +// File: classgdcm_1_1network_1_1MaximumLengthSub.xml +%feature("docstring") gdcm::network::MaximumLengthSub " + +MaximumLengthSub Annex D Table D.1-1 MAXIMUM LENGTH SUB-ITEM FIELDS (A +-ASSOCIATE-RQ). + +or + +Table D.1-2 Maximum length sub-item fields (A-ASSOCIATE-AC) + +C++ includes: gdcmMaximumLengthSub.h "; + +%feature("docstring") +gdcm::network::MaximumLengthSub::MaximumLengthSub "gdcm::network::MaximumLengthSub::MaximumLengthSub() "; + +%feature("docstring") +gdcm::network::MaximumLengthSub::GetMaximumLength "uint32_t +gdcm::network::MaximumLengthSub::GetMaximumLength() const "; + +%feature("docstring") gdcm::network::MaximumLengthSub::Print "void +gdcm::network::MaximumLengthSub::Print(std::ostream &os) const "; + +%feature("docstring") gdcm::network::MaximumLengthSub::Read "std::istream& gdcm::network::MaximumLengthSub::Read(std::istream &is) +"; + +%feature("docstring") +gdcm::network::MaximumLengthSub::SetMaximumLength "void +gdcm::network::MaximumLengthSub::SetMaximumLength(uint32_t +maximumlength) "; + +%feature("docstring") gdcm::network::MaximumLengthSub::Size "size_t +gdcm::network::MaximumLengthSub::Size() const "; + +%feature("docstring") gdcm::network::MaximumLengthSub::Write "const +std::ostream& gdcm::network::MaximumLengthSub::Write(std::ostream &os) +const "; + + +// File: classgdcm_1_1MD5.xml +%feature("docstring") gdcm::MD5 " + +Class for MD5. + +WARNING: this class is able to pick from two implementations: 1. a +lightweight md5 implementation (when GDCM_BUILD_TESTING is turned ON) +2. the one from OpenSSL (when GDCM_USE_SYSTEM_OPENSSL is turned ON) + +In all other cases it will return an error + +C++ includes: gdcmMD5.h "; + +%feature("docstring") gdcm::MD5::MD5 "gdcm::MD5::MD5() "; + +%feature("docstring") gdcm::MD5::~MD5 "gdcm::MD5::~MD5() "; + + +// File: classgdcm_1_1MediaStorage.xml +%feature("docstring") gdcm::MediaStorage " + +MediaStorage. + +FIXME There should not be any notion of Image and/or PDF at that point +Only the codec can answer yes I support this Media Storage or not... +For instance an ImageCodec will answer yes to most of them while a +PDFCodec will answer only for the Encapsulated PDF + +See: UIDs + +C++ includes: gdcmMediaStorage.h "; + +%feature("docstring") gdcm::MediaStorage::MediaStorage "gdcm::MediaStorage::MediaStorage(MSType type=MS_END) "; + +%feature("docstring") gdcm::MediaStorage::GetModality "const char* +gdcm::MediaStorage::GetModality() const "; + +%feature("docstring") gdcm::MediaStorage::GetModalityDimension "unsigned int gdcm::MediaStorage::GetModalityDimension() const "; + +%feature("docstring") gdcm::MediaStorage::GetString "const char* +gdcm::MediaStorage::GetString() const + +Return the Media String of the object. "; + +%feature("docstring") gdcm::MediaStorage::GuessFromModality "void +gdcm::MediaStorage::GuessFromModality(const char *modality, unsigned +int dimension=2) "; + +%feature("docstring") gdcm::MediaStorage::IsUndefined "bool +gdcm::MediaStorage::IsUndefined() const "; + +%feature("docstring") gdcm::MediaStorage::SetFromDataSet "bool +gdcm::MediaStorage::SetFromDataSet(DataSet const &ds) + +Advanced user only (functions should be protected level...) Those +function are lower level than SetFromFile "; + +%feature("docstring") gdcm::MediaStorage::SetFromFile "bool +gdcm::MediaStorage::SetFromFile(File const &file) + +Attempt to set the MediaStorage from afile: WARNING: When no +MediaStorage & Modality are found BUT a PixelData element is found +then MediaStorage is set to the default SecondaryCaptureImageStorage +(return value is false in this case) "; + +%feature("docstring") gdcm::MediaStorage::SetFromHeader "bool +gdcm::MediaStorage::SetFromHeader(FileMetaInformation const &fmi) "; + +%feature("docstring") gdcm::MediaStorage::SetFromModality "bool +gdcm::MediaStorage::SetFromModality(DataSet const &ds) "; + + +// File: classgdcm_1_1MemberCommand.xml +%feature("docstring") gdcm::MemberCommand " + +Command subclass that calls a pointer to a member function. + +MemberCommand calls a pointer to a member function with the same +arguments as Execute on Command. + +C++ includes: gdcmCommand.h "; + +%feature("docstring") gdcm::MemberCommand::Execute "virtual void +gdcm::MemberCommand< T >::Execute(Subject *caller, const Event &event) + +Invoke the member function. "; + +%feature("docstring") gdcm::MemberCommand::Execute "virtual void +gdcm::MemberCommand< T >::Execute(const Subject *caller, const Event +&event) + +Invoke the member function with a const object. "; + +%feature("docstring") gdcm::MemberCommand::SetCallbackFunction "void +gdcm::MemberCommand< T >::SetCallbackFunction(T *object, +TMemberFunctionPointer memberFunction) + +Run-time type information (and related methods). Set the callback +function along with the object that it will be invoked on. "; + +%feature("docstring") gdcm::MemberCommand::SetCallbackFunction "void +gdcm::MemberCommand< T >::SetCallbackFunction(T *object, +TConstMemberFunctionPointer memberFunction) "; + + +// File: classgdcm_1_1MeshPrimitive.xml +%feature("docstring") gdcm::MeshPrimitive " + +This class defines surface mesh primitives. It is designed from +surface mesh primitives macro. + +See: PS 3.3 C.27.4 + +C++ includes: gdcmMeshPrimitive.h "; + +%feature("docstring") gdcm::MeshPrimitive::MeshPrimitive "gdcm::MeshPrimitive::MeshPrimitive() "; + +%feature("docstring") gdcm::MeshPrimitive::~MeshPrimitive "virtual +gdcm::MeshPrimitive::~MeshPrimitive() "; + +%feature("docstring") gdcm::MeshPrimitive::AddPrimitiveData "void +gdcm::MeshPrimitive::AddPrimitiveData(DataElement const &de) "; + +%feature("docstring") gdcm::MeshPrimitive::GetNumberOfPrimitivesData +"unsigned int gdcm::MeshPrimitive::GetNumberOfPrimitivesData() const +"; + +%feature("docstring") gdcm::MeshPrimitive::GetPrimitiveData "DataElement& gdcm::MeshPrimitive::GetPrimitiveData() "; + +%feature("docstring") gdcm::MeshPrimitive::GetPrimitiveData "const +DataElement& gdcm::MeshPrimitive::GetPrimitiveData() const "; + +%feature("docstring") gdcm::MeshPrimitive::GetPrimitiveData "const +DataElement& gdcm::MeshPrimitive::GetPrimitiveData(const unsigned int +idx) const "; + +%feature("docstring") gdcm::MeshPrimitive::GetPrimitiveData "DataElement& gdcm::MeshPrimitive::GetPrimitiveData(const unsigned int +idx) "; + +%feature("docstring") gdcm::MeshPrimitive::GetPrimitivesData "const +PrimitivesData& gdcm::MeshPrimitive::GetPrimitivesData() const "; + +%feature("docstring") gdcm::MeshPrimitive::GetPrimitivesData "PrimitivesData& gdcm::MeshPrimitive::GetPrimitivesData() "; + +%feature("docstring") gdcm::MeshPrimitive::GetPrimitiveType "MPType +gdcm::MeshPrimitive::GetPrimitiveType() const "; + +%feature("docstring") gdcm::MeshPrimitive::SetPrimitiveData "void +gdcm::MeshPrimitive::SetPrimitiveData(const unsigned int idx, +DataElement const &de) "; + +%feature("docstring") gdcm::MeshPrimitive::SetPrimitiveData "void +gdcm::MeshPrimitive::SetPrimitiveData(DataElement const &de) "; + +%feature("docstring") gdcm::MeshPrimitive::SetPrimitivesData "void +gdcm::MeshPrimitive::SetPrimitivesData(PrimitivesData const &DEs) "; + +%feature("docstring") gdcm::MeshPrimitive::SetPrimitiveType "void +gdcm::MeshPrimitive::SetPrimitiveType(const MPType type) "; + + +// File: classgdcm_1_1ModifiedEvent.xml +%feature("docstring") gdcm::ModifiedEvent "C++ includes: gdcmEvent.h +"; + + +// File: classgdcm_1_1Module.xml +%feature("docstring") gdcm::Module " + +Class for representing a Module. + +Module: A set of Attributes within an Information Entity or Normalized +IOD which are logically related to each other. + +See: Macro + +C++ includes: gdcmModule.h "; + +%feature("docstring") gdcm::Module::Module "gdcm::Module::Module() +"; + +%feature("docstring") gdcm::Module::AddMacro "void +gdcm::Module::AddMacro(const char *include) "; + +%feature("docstring") gdcm::Module::AddModuleEntry "void +gdcm::Module::AddModuleEntry(const Tag &tag, const ModuleEntry +&module) + +Will add a ModuleEntry direcly at root-level. See Macro for nested- +included level. "; + +%feature("docstring") gdcm::Module::Clear "void +gdcm::Module::Clear() "; + +%feature("docstring") gdcm::Module::FindModuleEntryInMacros "bool +gdcm::Module::FindModuleEntryInMacros(Macros const ¯os, const Tag +&tag) const + +Find or Get a ModuleEntry. ModuleEntry are either search are root- +level or within nested-macro included in module. "; + +%feature("docstring") gdcm::Module::GetModuleEntryInMacros "const +ModuleEntry& gdcm::Module::GetModuleEntryInMacros(Macros const +¯os, const Tag &tag) const "; + +%feature("docstring") gdcm::Module::GetName "const char* +gdcm::Module::GetName() const "; + +%feature("docstring") gdcm::Module::SetName "void +gdcm::Module::SetName(const char *name) "; + +%feature("docstring") gdcm::Module::Verify "bool +gdcm::Module::Verify(const DataSet &ds, Usage const &usage) const "; + + +// File: classgdcm_1_1ModuleEntry.xml +%feature("docstring") gdcm::ModuleEntry " + +Class for representing a ModuleEntry. + +bla + +See: DictEntry + +C++ includes: gdcmModuleEntry.h "; + +%feature("docstring") gdcm::ModuleEntry::ModuleEntry "gdcm::ModuleEntry::ModuleEntry(const char *name=\"\", const char +*type=\"3\", const char *description=\"\") "; + +%feature("docstring") gdcm::ModuleEntry::~ModuleEntry "virtual +gdcm::ModuleEntry::~ModuleEntry() "; + +%feature("docstring") gdcm::ModuleEntry::GetDescription "const +Description& gdcm::ModuleEntry::GetDescription() const "; + +%feature("docstring") gdcm::ModuleEntry::GetName "const char* +gdcm::ModuleEntry::GetName() const "; + +%feature("docstring") gdcm::ModuleEntry::GetType "const Type& +gdcm::ModuleEntry::GetType() const "; + +%feature("docstring") gdcm::ModuleEntry::SetDescription "void +gdcm::ModuleEntry::SetDescription(const char *d) "; + +%feature("docstring") gdcm::ModuleEntry::SetName "void +gdcm::ModuleEntry::SetName(const char *name) "; + +%feature("docstring") gdcm::ModuleEntry::SetType "void +gdcm::ModuleEntry::SetType(const Type &type) "; + + +// File: classgdcm_1_1Modules.xml +%feature("docstring") gdcm::Modules " + +Class for representing a Modules. + +bla + +See: Module + +C++ includes: gdcmModules.h "; + +%feature("docstring") gdcm::Modules::Modules "gdcm::Modules::Modules() "; + +%feature("docstring") gdcm::Modules::AddModule "void +gdcm::Modules::AddModule(const char *ref, const Module &module) "; + +%feature("docstring") gdcm::Modules::Clear "void +gdcm::Modules::Clear() "; + +%feature("docstring") gdcm::Modules::GetModule "const Module& +gdcm::Modules::GetModule(const char *name) const "; + +%feature("docstring") gdcm::Modules::IsEmpty "bool +gdcm::Modules::IsEmpty() const "; + + +// File: classgdcm_1_1MovePatientRootQuery.xml +%feature("docstring") gdcm::MovePatientRootQuery " + +MovePatientRootQuery contains: the class which will produce a dataset +for c-move with patient root. + +C++ includes: gdcmMovePatientRootQuery.h "; + +%feature("docstring") +gdcm::MovePatientRootQuery::MovePatientRootQuery "gdcm::MovePatientRootQuery::MovePatientRootQuery() "; + +%feature("docstring") +gdcm::MovePatientRootQuery::GetAbstractSyntaxUID "UIDs::TSName +gdcm::MovePatientRootQuery::GetAbstractSyntaxUID() const "; + +%feature("docstring") gdcm::MovePatientRootQuery::GetTagListByLevel "std::vector gdcm::MovePatientRootQuery::GetTagListByLevel(const +EQueryLevel &inQueryLevel) + +this function will return all tags at a given query level, so that +they maybe selected for searching. The boolean forFind is true if the +query is a find query, or false for a move query. "; + +%feature("docstring") gdcm::MovePatientRootQuery::InitializeDataSet "void gdcm::MovePatientRootQuery::InitializeDataSet(const EQueryLevel +&inQueryLevel) + +this function sets tag 8,52 to the appropriate value based on query +level also fills in the right unique tags, as per the standard's +requirements should allow for connection with dcmtk "; + +%feature("docstring") gdcm::MovePatientRootQuery::ValidateQuery "bool gdcm::MovePatientRootQuery::ValidateQuery(bool inStrict=true) +const + +have to be able to ensure that 0x8,0x52 is set (which will be true if +InitializeDataSet is called...) that the level is appropriate (ie, not +setting PATIENT for a study query that the tags in the query match the +right level (either required, unique, optional) by default, this +function checks to see if the query is for finding, which is more +permissive than for moving. For moving, only the unique tags are +allowed. 10 Jan 2011: adding in the 'strict' mode. according to the +standard (at least, how I've read it), only tags for a particular +level should be allowed in a particular query (ie, just series level +tags in a series level query). However, it seems that dcm4chee doesn't +share that interpretation. So, if 'inStrict' is false, then tags from +the current level and all higher levels are now considered valid. So, +if you're doing a non-strict series-level query, tags from the patient +and study level can be passed along as well. "; + + +// File: classgdcm_1_1MoveStudyRootQuery.xml +%feature("docstring") gdcm::MoveStudyRootQuery " + +MoveStudyRootQuery contains: the class which will produce a dataset +for C-MOVE with study root. + +C++ includes: gdcmMoveStudyRootQuery.h "; + +%feature("docstring") gdcm::MoveStudyRootQuery::MoveStudyRootQuery "gdcm::MoveStudyRootQuery::MoveStudyRootQuery() "; + +%feature("docstring") gdcm::MoveStudyRootQuery::GetAbstractSyntaxUID +"UIDs::TSName gdcm::MoveStudyRootQuery::GetAbstractSyntaxUID() const +"; + +%feature("docstring") gdcm::MoveStudyRootQuery::GetTagListByLevel "std::vector gdcm::MoveStudyRootQuery::GetTagListByLevel(const +EQueryLevel &inQueryLevel) + +this function will return all tags at a given query level, so that +they maybe selected for searching. The boolean forFind is true if the +query is a find query, or false for a move query. "; + +%feature("docstring") gdcm::MoveStudyRootQuery::InitializeDataSet "void gdcm::MoveStudyRootQuery::InitializeDataSet(const EQueryLevel +&inQueryLevel) + +this function sets tag 8,52 to the appropriate value based on query +level also fills in the right unique tags, as per the standard's +requirements should allow for connection with dcmtk "; + +%feature("docstring") gdcm::MoveStudyRootQuery::ValidateQuery "bool +gdcm::MoveStudyRootQuery::ValidateQuery(bool inStrict=true) const + +have to be able to ensure that 0x8,0x52 is set (which will be true if +InitializeDataSet is called...) that the level is appropriate (ie, not +setting PATIENT for a study query that the tags in the query match the +right level (either required, unique, optional) by default, this +function checks to see if the query is for finding, which is more +permissive than for moving. For moving, only the unique tags are +allowed. 10 Jan 2011: adding in the 'strict' mode. according to the +standard (at least, how I've read it), only tags for a particular +level should be allowed in a particular query (ie, just series level +tags in a series level query). However, it seems that dcm4chee doesn't +share that interpretation. So, if 'inStrict' is false, then tags from +the current level and all higher levels are now considered valid. So, +if you're doing a non-strict series-level query, tags from the patient +and study level can be passed along as well. "; + + +// File: classstd_1_1multimap.xml +%feature("docstring") std::multimap " + +STL class. "; + + +// File: classstd_1_1multiset.xml +%feature("docstring") std::multiset " + +STL class. "; + + +// File: classgdcm_1_1NestedModuleEntries.xml +%feature("docstring") gdcm::NestedModuleEntries " + +Class for representing a NestedModuleEntries. + +bla + +See: ModuleEntry + +C++ includes: gdcmNestedModuleEntries.h "; + +%feature("docstring") gdcm::NestedModuleEntries::NestedModuleEntries +"gdcm::NestedModuleEntries::NestedModuleEntries(const char +*name=\"\", const char *type=\"3\", const char *description=\"\") "; + +%feature("docstring") gdcm::NestedModuleEntries::AddModuleEntry "void gdcm::NestedModuleEntries::AddModuleEntry(const ModuleEntry &me) +"; + +%feature("docstring") gdcm::NestedModuleEntries::GetModuleEntry "ModuleEntry& gdcm::NestedModuleEntries::GetModuleEntry(SizeType idx) +"; + +%feature("docstring") gdcm::NestedModuleEntries::GetModuleEntry "const ModuleEntry& gdcm::NestedModuleEntries::GetModuleEntry(SizeType +idx) const "; + +%feature("docstring") +gdcm::NestedModuleEntries::GetNumberOfModuleEntries "SizeType +gdcm::NestedModuleEntries::GetNumberOfModuleEntries() "; + + +// File: classgdcm_1_1NoEvent.xml +%feature("docstring") gdcm::NoEvent " + +Define some common GDCM events + +C++ includes: gdcmEvent.h "; + + +// File: classgdcm_1_1Object.xml +%feature("docstring") gdcm::Object " + +Object. + +main superclass for object that want to use SmartPointer invasive ref +counting system + +See: SmartPointer + +C++ includes: gdcmObject.h "; + +%feature("docstring") gdcm::Object::Object "gdcm::Object::Object() +"; + +%feature("docstring") gdcm::Object::Object "gdcm::Object::Object(const Object &) + +Special requirement for copy/cstor, assigment operator. "; + +%feature("docstring") gdcm::Object::~Object "virtual +gdcm::Object::~Object() "; + +%feature("docstring") gdcm::Object::Print "virtual void +gdcm::Object::Print(std::ostream &) const "; + + +// File: classstd_1_1ofstream.xml +%feature("docstring") std::ofstream " + +STL class. "; + + +// File: classgdcm_1_1OpenSSLCryptoFactory.xml +%feature("docstring") gdcm::OpenSSLCryptoFactory "C++ includes: +gdcmOpenSSLCryptoFactory.h "; + +%feature("docstring") +gdcm::OpenSSLCryptoFactory::OpenSSLCryptoFactory "gdcm::OpenSSLCryptoFactory::OpenSSLCryptoFactory(CryptoLib id) "; + +%feature("docstring") gdcm::OpenSSLCryptoFactory::CreateCMSProvider "CryptographicMessageSyntax* +gdcm::OpenSSLCryptoFactory::CreateCMSProvider() "; + + +// File: classgdcm_1_1OpenSSLCryptographicMessageSyntax.xml +%feature("docstring") gdcm::OpenSSLCryptographicMessageSyntax "C++ +includes: gdcmOpenSSLCryptographicMessageSyntax.h "; + +%feature("docstring") +gdcm::OpenSSLCryptographicMessageSyntax::OpenSSLCryptographicMessageSyntax +"gdcm::OpenSSLCryptographicMessageSyntax::OpenSSLCryptographicMessageSyntax() +"; + +%feature("docstring") +gdcm::OpenSSLCryptographicMessageSyntax::~OpenSSLCryptographicMessageSyntax +"gdcm::OpenSSLCryptographicMessageSyntax::~OpenSSLCryptographicMessageSyntax() +"; + +%feature("docstring") +gdcm::OpenSSLCryptographicMessageSyntax::Decrypt "bool +gdcm::OpenSSLCryptographicMessageSyntax::Decrypt(char *output, size_t +&outlen, const char *array, size_t len) const + +decrypt content from a PKCS#7 envelopedData structure "; + +%feature("docstring") +gdcm::OpenSSLCryptographicMessageSyntax::Encrypt "bool +gdcm::OpenSSLCryptographicMessageSyntax::Encrypt(char *output, size_t +&outlen, const char *array, size_t len) const + +create a CMS envelopedData structure "; + +%feature("docstring") +gdcm::OpenSSLCryptographicMessageSyntax::GetCipherType "CipherTypes +gdcm::OpenSSLCryptographicMessageSyntax::GetCipherType() const "; + +%feature("docstring") +gdcm::OpenSSLCryptographicMessageSyntax::ParseCertificateFile "bool +gdcm::OpenSSLCryptographicMessageSyntax::ParseCertificateFile(const +char *filename) "; + +%feature("docstring") +gdcm::OpenSSLCryptographicMessageSyntax::ParseKeyFile "bool +gdcm::OpenSSLCryptographicMessageSyntax::ParseKeyFile(const char +*filename) "; + +%feature("docstring") +gdcm::OpenSSLCryptographicMessageSyntax::SetCipherType "void +gdcm::OpenSSLCryptographicMessageSyntax::SetCipherType(CipherTypes +type) + +Set Cipher Type. Default is: AES256_CIPHER "; + +%feature("docstring") +gdcm::OpenSSLCryptographicMessageSyntax::SetPassword "bool +gdcm::OpenSSLCryptographicMessageSyntax::SetPassword(const char *pass, +size_t passLen) "; + + +// File: classgdcm_1_1OpenSSLP7CryptoFactory.xml +%feature("docstring") gdcm::OpenSSLP7CryptoFactory "C++ includes: +gdcmOpenSSLP7CryptoFactory.h "; + +%feature("docstring") +gdcm::OpenSSLP7CryptoFactory::OpenSSLP7CryptoFactory "gdcm::OpenSSLP7CryptoFactory::OpenSSLP7CryptoFactory(CryptoLib id) "; + +%feature("docstring") gdcm::OpenSSLP7CryptoFactory::CreateCMSProvider +"CryptographicMessageSyntax* +gdcm::OpenSSLP7CryptoFactory::CreateCMSProvider() "; + + +// File: classgdcm_1_1OpenSSLP7CryptographicMessageSyntax.xml +%feature("docstring") gdcm::OpenSSLP7CryptographicMessageSyntax " + +Class for CryptographicMessageSyntax encryption. This is just a simple +wrapper around openssl PKCS7_encrypt functionalities. + +See online +documentationhttp://www.openssl.org/docs/crypto/PKCS7_encrypt.html + +C++ includes: gdcmOpenSSLP7CryptographicMessageSyntax.h "; + +%feature("docstring") +gdcm::OpenSSLP7CryptographicMessageSyntax::OpenSSLP7CryptographicMessageSyntax +"gdcm::OpenSSLP7CryptographicMessageSyntax::OpenSSLP7CryptographicMessageSyntax() +"; + +%feature("docstring") +gdcm::OpenSSLP7CryptographicMessageSyntax::~OpenSSLP7CryptographicMessageSyntax +"gdcm::OpenSSLP7CryptographicMessageSyntax::~OpenSSLP7CryptographicMessageSyntax() +"; + +%feature("docstring") +gdcm::OpenSSLP7CryptographicMessageSyntax::Decrypt "bool +gdcm::OpenSSLP7CryptographicMessageSyntax::Decrypt(char *output, +size_t &outlen, const char *array, size_t len) const + +decrypt content from a PKCS#7 envelopedData structure "; + +%feature("docstring") +gdcm::OpenSSLP7CryptographicMessageSyntax::Encrypt "bool +gdcm::OpenSSLP7CryptographicMessageSyntax::Encrypt(char *output, +size_t &outlen, const char *array, size_t len) const + +create a PKCS#7 envelopedData structure "; + +%feature("docstring") +gdcm::OpenSSLP7CryptographicMessageSyntax::GetCipherType "CipherTypes +gdcm::OpenSSLP7CryptographicMessageSyntax::GetCipherType() const "; + +%feature("docstring") +gdcm::OpenSSLP7CryptographicMessageSyntax::ParseCertificateFile "bool +gdcm::OpenSSLP7CryptographicMessageSyntax::ParseCertificateFile(const +char *filename) "; + +%feature("docstring") +gdcm::OpenSSLP7CryptographicMessageSyntax::ParseKeyFile "bool +gdcm::OpenSSLP7CryptographicMessageSyntax::ParseKeyFile(const char +*filename) "; + +%feature("docstring") +gdcm::OpenSSLP7CryptographicMessageSyntax::SetCipherType "void +gdcm::OpenSSLP7CryptographicMessageSyntax::SetCipherType(CipherTypes +type) + +Set Cipher Type. Default is: AES256_CIPHER "; + +%feature("docstring") +gdcm::OpenSSLP7CryptographicMessageSyntax::SetPassword "bool +gdcm::OpenSSLP7CryptographicMessageSyntax::SetPassword(const char *, +size_t) "; + + +// File: classgdcm_1_1Orientation.xml +%feature("docstring") gdcm::Orientation " + +class to handle Orientation + +C++ includes: gdcmOrientation.h "; + +%feature("docstring") gdcm::Orientation::Orientation "gdcm::Orientation::Orientation() "; + +%feature("docstring") gdcm::Orientation::~Orientation "gdcm::Orientation::~Orientation() "; + +%feature("docstring") gdcm::Orientation::Print "void +gdcm::Orientation::Print(std::ostream &) const + +Print. "; + + +// File: classstd_1_1ostream.xml +%feature("docstring") std::ostream " + +STL class. "; + + +// File: classstd_1_1ostringstream.xml +%feature("docstring") std::ostringstream " + +STL class. "; + + +// File: classstd_1_1out__of__range.xml +%feature("docstring") std::out_of_range " + +STL class. "; + + +// File: classstd_1_1overflow__error.xml +%feature("docstring") std::overflow_error " + +STL class. "; + + +// File: classgdcm_1_1Overlay.xml +%feature("docstring") gdcm::Overlay " + +Overlay class. + +see AreOverlaysInPixelData Todo Is there actually any way to recognize +an overlay ? On images with multiple overlay I do not see any way to +differenciate them (other than the group tag). + +Example: + +C++ includes: gdcmOverlay.h "; + +%feature("docstring") gdcm::Overlay::Overlay "gdcm::Overlay::Overlay() "; + +%feature("docstring") gdcm::Overlay::Overlay "gdcm::Overlay::Overlay(Overlay const &ov) "; + +%feature("docstring") gdcm::Overlay::~Overlay "gdcm::Overlay::~Overlay() "; + +%feature("docstring") gdcm::Overlay::Decode "void +gdcm::Overlay::Decode(std::istream &is, std::ostream &os) + +Do not use. "; + +%feature("docstring") gdcm::Overlay::Decompress "void +gdcm::Overlay::Decompress(std::ostream &os) const + +Decode the internal OverlayData (packed bits) into unpacked +representation. "; + +%feature("docstring") gdcm::Overlay::GetBitPosition "unsigned short +gdcm::Overlay::GetBitPosition() const + +return bit position "; + +%feature("docstring") gdcm::Overlay::GetBitsAllocated "unsigned +short gdcm::Overlay::GetBitsAllocated() const + +return bits allocated "; + +%feature("docstring") gdcm::Overlay::GetBuffer "bool +gdcm::Overlay::GetBuffer(char *buffer) const + +Get the raw (packed bits) Overlay Data: "; + +%feature("docstring") gdcm::Overlay::GetColumns "unsigned short +gdcm::Overlay::GetColumns() const + +get columns "; + +%feature("docstring") gdcm::Overlay::GetDescription "const char* +gdcm::Overlay::GetDescription() const + +get description "; + +%feature("docstring") gdcm::Overlay::GetGroup "unsigned short +gdcm::Overlay::GetGroup() const + +Get Group number. "; + +%feature("docstring") gdcm::Overlay::GetOrigin "const signed short* +gdcm::Overlay::GetOrigin() const + +get origin "; + +%feature("docstring") gdcm::Overlay::GetOverlayData "const +ByteValue& gdcm::Overlay::GetOverlayData() const + +Return the Overlay Data as ByteValue: Not thread safe "; + +%feature("docstring") gdcm::Overlay::GetRows "unsigned short +gdcm::Overlay::GetRows() const + +get rows "; + +%feature("docstring") gdcm::Overlay::GetType "const char* +gdcm::Overlay::GetType() const + +get type "; + +%feature("docstring") gdcm::Overlay::GetTypeAsEnum "OverlayType +gdcm::Overlay::GetTypeAsEnum() const "; + +%feature("docstring") gdcm::Overlay::GetUnpackBuffer "bool +gdcm::Overlay::GetUnpackBuffer(char *buffer, size_t len) const + +Retrieve the unpack buffer for Overlay. This is an error if the size +if below GetUnpackBufferLength() "; + +%feature("docstring") gdcm::Overlay::GetUnpackBuffer "bool +gdcm::Overlay::GetUnpackBuffer(unsigned char *buffer) const + +Do not use. "; + +%feature("docstring") gdcm::Overlay::GetUnpackBufferLength "size_t +gdcm::Overlay::GetUnpackBufferLength() const + +Retrieve the size of the buffer needed to hold the Overlay as +specified by Col & Row parameters "; + +%feature("docstring") gdcm::Overlay::GrabOverlayFromPixelData "bool +gdcm::Overlay::GrabOverlayFromPixelData(DataSet const &ds) "; + +%feature("docstring") gdcm::Overlay::IsEmpty "bool +gdcm::Overlay::IsEmpty() const + +Return whether or not the Overlay is empty: "; + +%feature("docstring") gdcm::Overlay::IsInPixelData "bool +gdcm::Overlay::IsInPixelData() const + +return if the Overlay is stored in the pixel data or not "; + +%feature("docstring") gdcm::Overlay::IsInPixelData "void +gdcm::Overlay::IsInPixelData(bool b) + +Set wether or no the OverlayData is in the Pixel Data: "; + +%feature("docstring") gdcm::Overlay::IsZero "bool +gdcm::Overlay::IsZero() const + +return true if all bits are set to 0 "; + +%feature("docstring") gdcm::Overlay::Print "void +gdcm::Overlay::Print(std::ostream &) const + +Print. "; + +%feature("docstring") gdcm::Overlay::SetBitPosition "void +gdcm::Overlay::SetBitPosition(unsigned short bitposition) + +set bit position "; + +%feature("docstring") gdcm::Overlay::SetBitsAllocated "void +gdcm::Overlay::SetBitsAllocated(unsigned short bitsallocated) + +set bits allocated "; + +%feature("docstring") gdcm::Overlay::SetColumns "void +gdcm::Overlay::SetColumns(unsigned short columns) + +set columns "; + +%feature("docstring") gdcm::Overlay::SetDescription "void +gdcm::Overlay::SetDescription(const char *description) + +set description "; + +%feature("docstring") gdcm::Overlay::SetFrameOrigin "void +gdcm::Overlay::SetFrameOrigin(unsigned short frameorigin) + +set frame origin "; + +%feature("docstring") gdcm::Overlay::SetGroup "void +gdcm::Overlay::SetGroup(unsigned short group) + +Set Group number. "; + +%feature("docstring") gdcm::Overlay::SetNumberOfFrames "void +gdcm::Overlay::SetNumberOfFrames(unsigned int numberofframes) + +set number of frames "; + +%feature("docstring") gdcm::Overlay::SetOrigin "void +gdcm::Overlay::SetOrigin(const signed short origin[2]) + +set origin "; + +%feature("docstring") gdcm::Overlay::SetOverlay "void +gdcm::Overlay::SetOverlay(const char *array, size_t length) + +set overlay from byte array + length "; + +%feature("docstring") gdcm::Overlay::SetRows "void +gdcm::Overlay::SetRows(unsigned short rows) + +set rows "; + +%feature("docstring") gdcm::Overlay::SetType "void +gdcm::Overlay::SetType(const char *type) + +set type "; + +%feature("docstring") gdcm::Overlay::Update "void +gdcm::Overlay::Update(const DataElement &de) + +Update overlay from data element de: "; + + +// File: classgdcm_1_1ParseException.xml +%feature("docstring") gdcm::ParseException " + +ParseException Standard exception handling object. + +C++ includes: gdcmParseException.h "; + +%feature("docstring") gdcm::ParseException::ParseException "gdcm::ParseException::ParseException() "; + +%feature("docstring") gdcm::ParseException::~ParseException "virtual +gdcm::ParseException::~ParseException() throw ()"; + +%feature("docstring") gdcm::ParseException::GetLastElement "const +DataElement& gdcm::ParseException::GetLastElement() const "; + +%feature("docstring") gdcm::ParseException::SetLastElement "void +gdcm::ParseException::SetLastElement(DataElement &de) + +Equivalence operator. "; + + +// File: classgdcm_1_1Parser.xml +%feature("docstring") gdcm::Parser " + +Parser ala XML_Parser from expat (SAX). + +Detailled description here Simple API for DICOM + +C++ includes: gdcmParser.h "; + +%feature("docstring") gdcm::Parser::Parser "gdcm::Parser::Parser() +"; + +%feature("docstring") gdcm::Parser::~Parser "gdcm::Parser::~Parser() +"; + +%feature("docstring") gdcm::Parser::GetCurrentByteIndex "unsigned +long gdcm::Parser::GetCurrentByteIndex() const "; + +%feature("docstring") gdcm::Parser::GetErrorCode "ErrorType +gdcm::Parser::GetErrorCode() const "; + +%feature("docstring") gdcm::Parser::GetUserData "void* +gdcm::Parser::GetUserData() const "; + +%feature("docstring") gdcm::Parser::Parse "bool +gdcm::Parser::Parse(const char *s, int len, bool isFinal) "; + +%feature("docstring") gdcm::Parser::SetElementHandler "void +gdcm::Parser::SetElementHandler(StartElementHandler start, +EndElementHandler end) "; + +%feature("docstring") gdcm::Parser::SetUserData "void +gdcm::Parser::SetUserData(void *userData) "; + + +// File: classgdcm_1_1Patient.xml +%feature("docstring") gdcm::Patient " + +See PS 3.3 - 2007 DICOM MODEL OF THE REAL-WORLD, p 54. + +C++ includes: gdcmPatient.h "; + +%feature("docstring") gdcm::Patient::Patient "gdcm::Patient::Patient() "; + + +// File: classgdcm_1_1network_1_1PDataTFPDU.xml +%feature("docstring") gdcm::network::PDataTFPDU " + +PDataTFPDU Table 9-22 P-DATA-TF PDU FIELDS. + +C++ includes: gdcmPDataTFPDU.h "; + +%feature("docstring") gdcm::network::PDataTFPDU::PDataTFPDU "gdcm::network::PDataTFPDU::PDataTFPDU() "; + +%feature("docstring") +gdcm::network::PDataTFPDU::AddPresentationDataValue "void +gdcm::network::PDataTFPDU::AddPresentationDataValue(PresentationDataValue +const &pdv) "; + +%feature("docstring") +gdcm::network::PDataTFPDU::GetNumberOfPresentationDataValues "SizeType +gdcm::network::PDataTFPDU::GetNumberOfPresentationDataValues() const +"; + +%feature("docstring") +gdcm::network::PDataTFPDU::GetPresentationDataValue "PresentationDataValue const& +gdcm::network::PDataTFPDU::GetPresentationDataValue(SizeType i) const +"; + +%feature("docstring") gdcm::network::PDataTFPDU::IsLastFragment "bool gdcm::network::PDataTFPDU::IsLastFragment() const "; + +%feature("docstring") gdcm::network::PDataTFPDU::Print "void +gdcm::network::PDataTFPDU::Print(std::ostream &os) const "; + +%feature("docstring") gdcm::network::PDataTFPDU::Read "std::istream& +gdcm::network::PDataTFPDU::Read(std::istream &is) "; + +%feature("docstring") gdcm::network::PDataTFPDU::Size "size_t +gdcm::network::PDataTFPDU::Size() const "; + +%feature("docstring") gdcm::network::PDataTFPDU::Write "const +std::ostream& gdcm::network::PDataTFPDU::Write(std::ostream &os) const +"; + + +// File: classgdcm_1_1PDBElement.xml +%feature("docstring") gdcm::PDBElement " + +Class to represent a PDB Element. + +See: PDBHeader + +C++ includes: gdcmPDBElement.h "; + +%feature("docstring") gdcm::PDBElement::PDBElement "gdcm::PDBElement::PDBElement() "; + +%feature("docstring") gdcm::PDBElement::GetName "const char* +gdcm::PDBElement::GetName() const + +Set/Get Name. "; + +%feature("docstring") gdcm::PDBElement::GetValue "const char* +gdcm::PDBElement::GetValue() const + +Set/Get Value. "; + +%feature("docstring") gdcm::PDBElement::SetName "void +gdcm::PDBElement::SetName(const char *name) "; + +%feature("docstring") gdcm::PDBElement::SetValue "void +gdcm::PDBElement::SetValue(const char *value) "; + + +// File: classgdcm_1_1PDBHeader.xml +%feature("docstring") gdcm::PDBHeader " + +Class for PDBHeader. + +GEMS MR Image have an Attribute (0025,1b,GEMS_SERS_01) which store the +Acquisition parameter of the MR Image. It is compressed and can +therefore not be used as is. This class de- encapsulated the Protocol +Data Block and allow users to query element by name. + +WARNING: Everything you do with this code is at your own risk, since +decoding process was not written from specification documents. + +: the API of this class might change. + +See: CSAHeader + +C++ includes: gdcmPDBHeader.h "; + +%feature("docstring") gdcm::PDBHeader::PDBHeader "gdcm::PDBHeader::PDBHeader() "; + +%feature("docstring") gdcm::PDBHeader::~PDBHeader "gdcm::PDBHeader::~PDBHeader() "; + +%feature("docstring") gdcm::PDBHeader::FindPDBElementByName "bool +gdcm::PDBHeader::FindPDBElementByName(const char *name) + +Return true if the PDB element matching name is found or not. "; + +%feature("docstring") gdcm::PDBHeader::GetPDBElementByName "const +PDBElement& gdcm::PDBHeader::GetPDBElementByName(const char *name) + +Lookup in the PDB header if a PDB element match the name 'name': +WARNING: Case Sensitive "; + +%feature("docstring") gdcm::PDBHeader::LoadFromDataElement "bool +gdcm::PDBHeader::LoadFromDataElement(DataElement const &de) + +Load the PDB Header from a DataElement of a DataSet. "; + +%feature("docstring") gdcm::PDBHeader::Print "void +gdcm::PDBHeader::Print(std::ostream &os) const + +Print. "; + + +// File: classgdcm_1_1PDFCodec.xml +%feature("docstring") gdcm::PDFCodec " + +PDFCodec class. + +C++ includes: gdcmPDFCodec.h "; + +%feature("docstring") gdcm::PDFCodec::PDFCodec "gdcm::PDFCodec::PDFCodec() "; + +%feature("docstring") gdcm::PDFCodec::~PDFCodec "gdcm::PDFCodec::~PDFCodec() "; + +%feature("docstring") gdcm::PDFCodec::CanCode "bool +gdcm::PDFCodec::CanCode(TransferSyntax const &) const "; + +%feature("docstring") gdcm::PDFCodec::CanDecode "bool +gdcm::PDFCodec::CanDecode(TransferSyntax const &) const + +Return whether this decoder support this transfer syntax (can decode +it). "; + +%feature("docstring") gdcm::PDFCodec::Decode "bool +gdcm::PDFCodec::Decode(DataElement const &is, DataElement &os) + +Decode. "; + + +// File: classgdcm_1_1network_1_1PDUFactory.xml +%feature("docstring") gdcm::network::PDUFactory " + +PDUFactory basically, given an initial byte, construct the appropriate +PDU. This way, the event loop doesn't have to know about all the +different PDU types. + +C++ includes: gdcmPDUFactory.h "; + + +// File: classgdcm_1_1PersonName.xml +%feature("docstring") gdcm::PersonName " + +PersonName class. + +C++ includes: gdcmPersonName.h "; + +%feature("docstring") gdcm::PersonName::GetMaxLength "unsigned int +gdcm::PersonName::GetMaxLength() const "; + +%feature("docstring") gdcm::PersonName::GetNumberOfComponents "unsigned int gdcm::PersonName::GetNumberOfComponents() const "; + +%feature("docstring") gdcm::PersonName::Print "void +gdcm::PersonName::Print(std::ostream &os) const "; + +%feature("docstring") gdcm::PersonName::SetBlob "void +gdcm::PersonName::SetBlob(const std::vector< char > &v) "; + +%feature("docstring") gdcm::PersonName::SetComponents "void +gdcm::PersonName::SetComponents(const char *components[]) "; + +%feature("docstring") gdcm::PersonName::SetComponents "void +gdcm::PersonName::SetComponents(const char *comp1=\"\", const char +*comp2=\"\", const char *comp3=\"\", const char *comp4=\"\", const +char *comp5=\"\") "; + + +// File: classgdcm_1_1PGXCodec.xml +%feature("docstring") gdcm::PGXCodec " + +Class to do PGX See PGX as used in JPEG 2000 implementation and +reference images. + +C++ includes: gdcmPGXCodec.h "; + +%feature("docstring") gdcm::PGXCodec::PGXCodec "gdcm::PGXCodec::PGXCodec() "; + +%feature("docstring") gdcm::PGXCodec::~PGXCodec "gdcm::PGXCodec::~PGXCodec() "; + +%feature("docstring") gdcm::PGXCodec::CanCode "bool +gdcm::PGXCodec::CanCode(TransferSyntax const &ts) const "; + +%feature("docstring") gdcm::PGXCodec::CanDecode "bool +gdcm::PGXCodec::CanDecode(TransferSyntax const &ts) const + +Return whether this decoder support this transfer syntax (can decode +it). "; + +%feature("docstring") gdcm::PGXCodec::GetHeaderInfo "bool +gdcm::PGXCodec::GetHeaderInfo(std::istream &is, TransferSyntax &ts) "; + +%feature("docstring") gdcm::PGXCodec::Read "bool +gdcm::PGXCodec::Read(const char *filename, DataElement &out) const "; + +%feature("docstring") gdcm::PGXCodec::Write "bool +gdcm::PGXCodec::Write(const char *filename, const DataElement &out) +const "; + + +// File: classgdcm_1_1PhotometricInterpretation.xml +%feature("docstring") gdcm::PhotometricInterpretation " + +Class to represent an PhotometricInterpretation. + +C++ includes: gdcmPhotometricInterpretation.h "; + +%feature("docstring") +gdcm::PhotometricInterpretation::PhotometricInterpretation "gdcm::PhotometricInterpretation::PhotometricInterpretation(PIType +pi=UNKNOW) "; + +%feature("docstring") +gdcm::PhotometricInterpretation::GetSamplesPerPixel "unsigned short +gdcm::PhotometricInterpretation::GetSamplesPerPixel() const + +return the value for Sample Per Pixel associated with a particular +Photometric Interpretation "; + +%feature("docstring") gdcm::PhotometricInterpretation::GetString "const char* gdcm::PhotometricInterpretation::GetString() const "; + +%feature("docstring") gdcm::PhotometricInterpretation::GetType "PIType gdcm::PhotometricInterpretation::GetType() const "; + +%feature("docstring") gdcm::PhotometricInterpretation::IsLossless "bool gdcm::PhotometricInterpretation::IsLossless() const "; + +%feature("docstring") gdcm::PhotometricInterpretation::IsLossy "bool +gdcm::PhotometricInterpretation::IsLossy() const "; + +%feature("docstring") +gdcm::PhotometricInterpretation::IsSameColorSpace "bool +gdcm::PhotometricInterpretation::IsSameColorSpace(PhotometricInterpretation +const &pi) const "; + + +// File: classgdcm_1_1PixelFormat.xml +%feature("docstring") gdcm::PixelFormat " + +PixelFormat. + +By default the Pixel Type will be instanciated with the following +parameters: SamplesPerPixel : 1 + +BitsAllocated : 8 + +BitsStored : 8 + +HighBit : 7 + +PixelRepresentation : 0 + +C++ includes: gdcmPixelFormat.h "; + +%feature("docstring") gdcm::PixelFormat::PixelFormat "gdcm::PixelFormat::PixelFormat(unsigned short samplesperpixel=1, +unsigned short bitsallocated=8, unsigned short bitsstored=8, unsigned +short highbit=7, unsigned short pixelrepresentation=0) "; + +%feature("docstring") gdcm::PixelFormat::PixelFormat "gdcm::PixelFormat::PixelFormat(ScalarType st) "; + +%feature("docstring") gdcm::PixelFormat::~PixelFormat "gdcm::PixelFormat::~PixelFormat() "; + +%feature("docstring") gdcm::PixelFormat::GetBitsAllocated "unsigned +short gdcm::PixelFormat::GetBitsAllocated() const + +BitsAllocated see Tag (0028,0100) US Bits Allocated. "; + +%feature("docstring") gdcm::PixelFormat::GetBitsStored "unsigned +short gdcm::PixelFormat::GetBitsStored() const + +BitsStored see Tag (0028,0101) US Bits Stored. "; + +%feature("docstring") gdcm::PixelFormat::GetHighBit "unsigned short +gdcm::PixelFormat::GetHighBit() const + +HighBit see Tag (0028,0102) US High Bit. "; + +%feature("docstring") gdcm::PixelFormat::GetMax "int64_t +gdcm::PixelFormat::GetMax() const + +return the max possible of the pixel "; + +%feature("docstring") gdcm::PixelFormat::GetMin "int64_t +gdcm::PixelFormat::GetMin() const + +return the min possible of the pixel "; + +%feature("docstring") gdcm::PixelFormat::GetPixelRepresentation "unsigned short gdcm::PixelFormat::GetPixelRepresentation() const + +PixelRepresentation: 0 or 1, see Tag (0028,0103) US Pixel +Representation. "; + +%feature("docstring") gdcm::PixelFormat::GetPixelSize "uint8_t +gdcm::PixelFormat::GetPixelSize() const + +return the size of the pixel This is the number of words it would take +to store one pixel WARNING: the return value takes into account the +SamplesPerPixel + +in the rare case when BitsAllocated == 12, the function assume word +padding and value returned will be identical as if BitsAllocated == 16 +"; + +%feature("docstring") gdcm::PixelFormat::GetSamplesPerPixel "unsigned short gdcm::PixelFormat::GetSamplesPerPixel() const + +Samples Per Pixel see (0028,0002) US Samples Per Pixel DICOM - only +allows 1, 3 and 4 as valid value. Other value are undefined behavior. +"; + +%feature("docstring") gdcm::PixelFormat::GetScalarType "ScalarType +gdcm::PixelFormat::GetScalarType() const + +ScalarType does not take into account the sample per pixel. "; + +%feature("docstring") gdcm::PixelFormat::GetScalarTypeAsString "const char* gdcm::PixelFormat::GetScalarTypeAsString() const "; + +%feature("docstring") gdcm::PixelFormat::IsValid "bool +gdcm::PixelFormat::IsValid() const + +return IsValid "; + +%feature("docstring") gdcm::PixelFormat::Print "void +gdcm::PixelFormat::Print(std::ostream &os) const + +Print. "; + +%feature("docstring") gdcm::PixelFormat::SetBitsAllocated "void +gdcm::PixelFormat::SetBitsAllocated(unsigned short ba) "; + +%feature("docstring") gdcm::PixelFormat::SetBitsStored "void +gdcm::PixelFormat::SetBitsStored(unsigned short bs) "; + +%feature("docstring") gdcm::PixelFormat::SetHighBit "void +gdcm::PixelFormat::SetHighBit(unsigned short hb) "; + +%feature("docstring") gdcm::PixelFormat::SetPixelRepresentation "void gdcm::PixelFormat::SetPixelRepresentation(unsigned short pr) "; + +%feature("docstring") gdcm::PixelFormat::SetSamplesPerPixel "void +gdcm::PixelFormat::SetSamplesPerPixel(unsigned short spp) "; + +%feature("docstring") gdcm::PixelFormat::SetScalarType "void +gdcm::PixelFormat::SetScalarType(ScalarType st) + +Set PixelFormat based only on the ScalarType WARNING: : You need to +call SetScalarType *before* SetSamplesPerPixel "; + + +// File: classgdcm_1_1Pixmap.xml +%feature("docstring") gdcm::Pixmap " + +Pixmap class A bitmap based image. Used as parent for both IconImage +and the main Pixel Data Image It does not contains any World Space +information (IPP, IOP). + +See: PixmapReader + +C++ includes: gdcmPixmap.h "; + +%feature("docstring") gdcm::Pixmap::Pixmap "gdcm::Pixmap::Pixmap() +"; + +%feature("docstring") gdcm::Pixmap::~Pixmap "gdcm::Pixmap::~Pixmap() +"; + +%feature("docstring") gdcm::Pixmap::AreOverlaysInPixelData "bool +gdcm::Pixmap::AreOverlaysInPixelData() const + +returns if Overlays are stored in the unused bit of the pixel data: "; + +%feature("docstring") gdcm::Pixmap::GetCurve "Curve& +gdcm::Pixmap::GetCurve(size_t i=0) + +Curve: group 50xx. "; + +%feature("docstring") gdcm::Pixmap::GetCurve "const Curve& +gdcm::Pixmap::GetCurve(size_t i=0) const "; + +%feature("docstring") gdcm::Pixmap::GetIconImage "IconImage& +gdcm::Pixmap::GetIconImage() "; + +%feature("docstring") gdcm::Pixmap::GetIconImage "const IconImage& +gdcm::Pixmap::GetIconImage() const + +Set/Get Icon Image. "; + +%feature("docstring") gdcm::Pixmap::GetNumberOfCurves "size_t +gdcm::Pixmap::GetNumberOfCurves() const "; + +%feature("docstring") gdcm::Pixmap::GetNumberOfOverlays "size_t +gdcm::Pixmap::GetNumberOfOverlays() const "; + +%feature("docstring") gdcm::Pixmap::GetOverlay "Overlay& +gdcm::Pixmap::GetOverlay(size_t i=0) + +Overlay: group 60xx. "; + +%feature("docstring") gdcm::Pixmap::GetOverlay "const Overlay& +gdcm::Pixmap::GetOverlay(size_t i=0) const "; + +%feature("docstring") gdcm::Pixmap::Print "void +gdcm::Pixmap::Print(std::ostream &) const "; + +%feature("docstring") gdcm::Pixmap::RemoveOverlay "void +gdcm::Pixmap::RemoveOverlay(size_t i) "; + +%feature("docstring") gdcm::Pixmap::SetIconImage "void +gdcm::Pixmap::SetIconImage(IconImage const &ii) "; + +%feature("docstring") gdcm::Pixmap::SetNumberOfCurves "void +gdcm::Pixmap::SetNumberOfCurves(size_t n) "; + +%feature("docstring") gdcm::Pixmap::SetNumberOfOverlays "void +gdcm::Pixmap::SetNumberOfOverlays(size_t n) "; + + +// File: classgdcm_1_1PixmapReader.xml +%feature("docstring") gdcm::PixmapReader " + +PixmapReader. + +its role is to convert the DICOM DataSet into a gdcm::Pixmap +representation By default it is also loading the lookup table and +overlay when found as they impact the rendering or the image See PS +3.3-2008, Table C.7-11b IMAGE PIXEL MACRO ATTRIBUTES for the list of +attribute that belong to what gdcm calls a 'Pixmap' + +WARNING: the API ReadUpToTag and ReadSelectedTag + +See: Pixmap + +C++ includes: gdcmPixmapReader.h "; + +%feature("docstring") gdcm::PixmapReader::PixmapReader "gdcm::PixmapReader::PixmapReader() "; + +%feature("docstring") gdcm::PixmapReader::~PixmapReader "virtual +gdcm::PixmapReader::~PixmapReader() "; + +%feature("docstring") gdcm::PixmapReader::GetPixmap "const Pixmap& +gdcm::PixmapReader::GetPixmap() const + +Return the read image (need to call Read() first). "; + +%feature("docstring") gdcm::PixmapReader::GetPixmap "Pixmap& +gdcm::PixmapReader::GetPixmap() "; + +%feature("docstring") gdcm::PixmapReader::Read "virtual bool +gdcm::PixmapReader::Read() + +Read the DICOM image. There are two reason for failure: 1. The input +filename is not DICOM 2. The input DICOM file does not contains an +Pixmap. "; + + +// File: classgdcm_1_1PixmapToPixmapFilter.xml +%feature("docstring") gdcm::PixmapToPixmapFilter " + +PixmapToPixmapFilter class Super class for all filter taking an image +and producing an output image. + +C++ includes: gdcmPixmapToPixmapFilter.h "; + +%feature("docstring") +gdcm::PixmapToPixmapFilter::PixmapToPixmapFilter "gdcm::PixmapToPixmapFilter::PixmapToPixmapFilter() "; + +%feature("docstring") +gdcm::PixmapToPixmapFilter::~PixmapToPixmapFilter "gdcm::PixmapToPixmapFilter::~PixmapToPixmapFilter() "; + +%feature("docstring") gdcm::PixmapToPixmapFilter::GetInput "Pixmap& +gdcm::PixmapToPixmapFilter::GetInput() "; + +%feature("docstring") gdcm::PixmapToPixmapFilter::GetOutput "const +Pixmap& gdcm::PixmapToPixmapFilter::GetOutput() const + +Get Output image. "; + +%feature("docstring") gdcm::PixmapToPixmapFilter::GetOutputAsPixmap "const Pixmap& gdcm::PixmapToPixmapFilter::GetOutputAsPixmap() const "; + + +// File: classgdcm_1_1PixmapWriter.xml +%feature("docstring") gdcm::PixmapWriter " + +PixmapWriter This class will takes two inputs: 1. The DICOM DataSet 2. +The Image input It will override any info from the Image over the +DataSet. + +For instance when one read in a lossy compressed image and write out +as unencapsulated (ie implicitely lossless) then some attribute are +definitely needed to mark this dataset as Lossy (typically 0028,2114) + +C++ includes: gdcmPixmapWriter.h "; + +%feature("docstring") gdcm::PixmapWriter::PixmapWriter "gdcm::PixmapWriter::PixmapWriter() "; + +%feature("docstring") gdcm::PixmapWriter::~PixmapWriter "gdcm::PixmapWriter::~PixmapWriter() "; + +%feature("docstring") gdcm::PixmapWriter::GetImage "virtual const +Pixmap& gdcm::PixmapWriter::GetImage() const + +Set/Get Pixmap to be written It will overwrite anything Pixmap infos +found in DataSet (see parent class to see how to pass dataset) "; + +%feature("docstring") gdcm::PixmapWriter::GetImage "virtual Pixmap& +gdcm::PixmapWriter::GetImage() "; + +%feature("docstring") gdcm::PixmapWriter::GetPixmap "Pixmap& +gdcm::PixmapWriter::GetPixmap() "; + +%feature("docstring") gdcm::PixmapWriter::GetPixmap "const Pixmap& +gdcm::PixmapWriter::GetPixmap() const "; + +%feature("docstring") gdcm::PixmapWriter::SetImage "virtual void +gdcm::PixmapWriter::SetImage(Pixmap const &img) "; + +%feature("docstring") gdcm::PixmapWriter::SetPixmap "void +gdcm::PixmapWriter::SetPixmap(Pixmap const &img) "; + +%feature("docstring") gdcm::PixmapWriter::Write "bool +gdcm::PixmapWriter::Write() + +Write. "; + + +// File: classgdcm_1_1PNMCodec.xml +%feature("docstring") gdcm::PNMCodec " + +Class to do PNM PNM is the Portable anymap file format. The main web +page can be found at:http://netpbm.sourceforge.net/. + +Only support P5 & P6 PNM file (binary grayscale and binary rgb) + +C++ includes: gdcmPNMCodec.h "; + +%feature("docstring") gdcm::PNMCodec::PNMCodec "gdcm::PNMCodec::PNMCodec() "; + +%feature("docstring") gdcm::PNMCodec::~PNMCodec "gdcm::PNMCodec::~PNMCodec() "; + +%feature("docstring") gdcm::PNMCodec::CanCode "bool +gdcm::PNMCodec::CanCode(TransferSyntax const &ts) const "; + +%feature("docstring") gdcm::PNMCodec::CanDecode "bool +gdcm::PNMCodec::CanDecode(TransferSyntax const &ts) const + +Return whether this decoder support this transfer syntax (can decode +it). "; + +%feature("docstring") gdcm::PNMCodec::GetBufferLength "unsigned long +gdcm::PNMCodec::GetBufferLength() const "; + +%feature("docstring") gdcm::PNMCodec::GetHeaderInfo "bool +gdcm::PNMCodec::GetHeaderInfo(std::istream &is, TransferSyntax &ts) "; + +%feature("docstring") gdcm::PNMCodec::Read "bool +gdcm::PNMCodec::Read(const char *filename, DataElement &out) const "; + +%feature("docstring") gdcm::PNMCodec::SetBufferLength "void +gdcm::PNMCodec::SetBufferLength(unsigned long l) "; + +%feature("docstring") gdcm::PNMCodec::Write "bool +gdcm::PNMCodec::Write(const char *filename, const DataElement &out) +const "; + + +// File: classgdcm_1_1Preamble.xml +%feature("docstring") gdcm::Preamble " + +DICOM Preamble (Part 10). + +C++ includes: gdcmPreamble.h "; + +%feature("docstring") gdcm::Preamble::Preamble "gdcm::Preamble::Preamble() "; + +%feature("docstring") gdcm::Preamble::Preamble "gdcm::Preamble::Preamble(Preamble const &) "; + +%feature("docstring") gdcm::Preamble::~Preamble "gdcm::Preamble::~Preamble() "; + +%feature("docstring") gdcm::Preamble::Clear "void +gdcm::Preamble::Clear() "; + +%feature("docstring") gdcm::Preamble::Create "void +gdcm::Preamble::Create() "; + +%feature("docstring") gdcm::Preamble::GetInternal "const char* +gdcm::Preamble::GetInternal() const "; + +%feature("docstring") gdcm::Preamble::GetLength "VL +gdcm::Preamble::GetLength() const "; + +%feature("docstring") gdcm::Preamble::IsEmpty "bool +gdcm::Preamble::IsEmpty() const "; + +%feature("docstring") gdcm::Preamble::Print "void +gdcm::Preamble::Print(std::ostream &os) const "; + +%feature("docstring") gdcm::Preamble::Read "std::istream& +gdcm::Preamble::Read(std::istream &is) "; + +%feature("docstring") gdcm::Preamble::Remove "void +gdcm::Preamble::Remove() "; + +%feature("docstring") gdcm::Preamble::Valid "void +gdcm::Preamble::Valid() "; + +%feature("docstring") gdcm::Preamble::Write "std::ostream const& +gdcm::Preamble::Write(std::ostream &os) const "; + + +// File: classgdcm_1_1PresentationContext.xml +%feature("docstring") gdcm::PresentationContext " + +PresentationContext. + +See: PresentationContextAC PresentationContextRQ + +C++ includes: gdcmPresentationContext.h "; + +%feature("docstring") gdcm::PresentationContext::PresentationContext +"gdcm::PresentationContext::PresentationContext() "; + +%feature("docstring") gdcm::PresentationContext::PresentationContext +"gdcm::PresentationContext::PresentationContext(UIDs::TSName asname, +UIDs::TSName +tsname=UIDs::ImplicitVRLittleEndianDefaultTransferSyntaxforDICOM) + +Initialize Presentation Context with AbstractSyntax set to asname and +with a single TransferSyntax set to tsname (default to Implicit VR +LittleEndian when not specified ). "; + +%feature("docstring") gdcm::PresentationContext::AddTransferSyntax "void gdcm::PresentationContext::AddTransferSyntax(const char *tsstr) +"; + +%feature("docstring") gdcm::PresentationContext::GetAbstractSyntax "const char* gdcm::PresentationContext::GetAbstractSyntax() const "; + +%feature("docstring") +gdcm::PresentationContext::GetNumberOfTransferSyntaxes "SizeType +gdcm::PresentationContext::GetNumberOfTransferSyntaxes() const "; + +%feature("docstring") +gdcm::PresentationContext::GetPresentationContextID "uint8_t +gdcm::PresentationContext::GetPresentationContextID() const "; + +%feature("docstring") gdcm::PresentationContext::GetTransferSyntax "const char* gdcm::PresentationContext::GetTransferSyntax(SizeType i) +const "; + +%feature("docstring") gdcm::PresentationContext::Print "void +gdcm::PresentationContext::Print(std::ostream &os) const "; + +%feature("docstring") gdcm::PresentationContext::SetAbstractSyntax "void gdcm::PresentationContext::SetAbstractSyntax(const char *as) "; + +%feature("docstring") +gdcm::PresentationContext::SetPresentationContextID "void +gdcm::PresentationContext::SetPresentationContextID(uint8_t id) "; + + +// File: classgdcm_1_1network_1_1PresentationContextAC.xml +%feature("docstring") gdcm::network::PresentationContextAC " + +PresentationContextAC Table 9-18 PRESENTATION CONTEXT ITEM FIELDS. + +See: PresentationContext + +C++ includes: gdcmPresentationContextAC.h "; + +%feature("docstring") +gdcm::network::PresentationContextAC::PresentationContextAC "gdcm::network::PresentationContextAC::PresentationContextAC() "; + +%feature("docstring") +gdcm::network::PresentationContextAC::GetPresentationContextID "uint8_t +gdcm::network::PresentationContextAC::GetPresentationContextID() const +"; + +%feature("docstring") gdcm::network::PresentationContextAC::GetReason +"uint8_t gdcm::network::PresentationContextAC::GetReason() const "; + +%feature("docstring") +gdcm::network::PresentationContextAC::GetTransferSyntax "TransferSyntaxSub const& +gdcm::network::PresentationContextAC::GetTransferSyntax() const "; + +%feature("docstring") gdcm::network::PresentationContextAC::Print "void gdcm::network::PresentationContextAC::Print(std::ostream &os) +const "; + +%feature("docstring") gdcm::network::PresentationContextAC::Read "std::istream& gdcm::network::PresentationContextAC::Read(std::istream +&is) "; + +%feature("docstring") +gdcm::network::PresentationContextAC::SetPresentationContextID "void +gdcm::network::PresentationContextAC::SetPresentationContextID(uint8_t +id) "; + +%feature("docstring") gdcm::network::PresentationContextAC::SetReason +"void gdcm::network::PresentationContextAC::SetReason(uint8_t r) "; + +%feature("docstring") +gdcm::network::PresentationContextAC::SetTransferSyntax "void +gdcm::network::PresentationContextAC::SetTransferSyntax(TransferSyntaxSub +const &ts) "; + +%feature("docstring") gdcm::network::PresentationContextAC::Size "size_t gdcm::network::PresentationContextAC::Size() const "; + +%feature("docstring") gdcm::network::PresentationContextAC::Write "const std::ostream& +gdcm::network::PresentationContextAC::Write(std::ostream &os) const "; + + +// File: classgdcm_1_1PresentationContextGenerator.xml +%feature("docstring") gdcm::PresentationContextGenerator " + +PresentationContextGenerator This class is responsible for generating +the proper PresentationContext that will be used in subsequent +operation during a DICOM Query/Retrieve association. The step of the +association is very sensible as special care need to be taken to +explicitly define what instance are going to be send and how they are +encoded. + +For example a PresentationContext will express that negotiation +requires that CT Image Storage are send using JPEG Lossless, while US +Image Storage are sent using RLE Transfer Syntax. + +Two very different API are exposed one which will always default to +little endian transfer syntax see GenerateFromUID() This API is used +for C-ECHO, C-FIND and C-MOVE (SCU). Another API: +GenerateFromFilenames() is used for C-STORE (SCU) as it will loop over +all filenames argument to detect the actual encoding. and therefore +find the proper encoding to be used. + +Two modes are available. The default mode +(SetMergeModeToAbstractSyntax) append PresentationContext (one +AbstractSyntax and one TransferSyntax), as long a they are different. +Eg MR Image Storage/JPEG2000 and MR Image Storage/JPEGLossless would +be considered different. the other mode SetMergeModeToTransferSyntax +merge any new TransferSyntax to the already existing +PresentationContext in order to re-use the same AbstractSyntax. + +See: PresentationContext + +C++ includes: gdcmPresentationContextGenerator.h "; + +%feature("docstring") +gdcm::PresentationContextGenerator::PresentationContextGenerator "gdcm::PresentationContextGenerator::PresentationContextGenerator() "; + +%feature("docstring") +gdcm::PresentationContextGenerator::GenerateFromFilenames "bool +gdcm::PresentationContextGenerator::GenerateFromFilenames(const +Directory::FilenamesType &files) + +Generate the PresentationContext array from a File-Set. File specified +needs to be valid DICOM files. Used for C-STORE operations "; + +%feature("docstring") +gdcm::PresentationContextGenerator::GenerateFromUID "bool +gdcm::PresentationContextGenerator::GenerateFromUID(UIDs::TSName +asname) + +Generate the PresentationContext array from a UID (eg. +VerificationSOPClass). "; + +%feature("docstring") +gdcm::PresentationContextGenerator::GetPresentationContexts "PresentationContextArrayType const& +gdcm::PresentationContextGenerator::GetPresentationContexts() "; + +%feature("docstring") +gdcm::PresentationContextGenerator::SetDefaultTransferSyntax "void +gdcm::PresentationContextGenerator::SetDefaultTransferSyntax(const +TransferSyntax &ts) + +Not implemented for now. GDCM internally uses Implicit Little Endian. +"; + +%feature("docstring") +gdcm::PresentationContextGenerator::SetMergeModeToAbstractSyntax "void +gdcm::PresentationContextGenerator::SetMergeModeToAbstractSyntax() "; + +%feature("docstring") +gdcm::PresentationContextGenerator::SetMergeModeToTransferSyntax "void +gdcm::PresentationContextGenerator::SetMergeModeToTransferSyntax() "; + + +// File: classgdcm_1_1network_1_1PresentationContextRQ.xml +%feature("docstring") gdcm::network::PresentationContextRQ " + +PresentationContextRQ Table 9-13 PRESENTATION CONTEXT ITEM FIELDS. + +See: PresentationContextAC + +C++ includes: gdcmPresentationContextRQ.h "; + +%feature("docstring") +gdcm::network::PresentationContextRQ::PresentationContextRQ "gdcm::network::PresentationContextRQ::PresentationContextRQ() "; + +%feature("docstring") +gdcm::network::PresentationContextRQ::PresentationContextRQ "gdcm::network::PresentationContextRQ::PresentationContextRQ(UIDs::TSName +asname, UIDs::TSName +tsname=UIDs::ImplicitVRLittleEndianDefaultTransferSyntaxforDICOM) + +Initialize Presentation Context with AbstractSyntax set to asname and +with a single TransferSyntax set to tsname (dfault to Implicit VR +LittleEndian when not specified ). "; + +%feature("docstring") +gdcm::network::PresentationContextRQ::PresentationContextRQ "gdcm::network::PresentationContextRQ::PresentationContextRQ(const +PresentationContext &pc) "; + +%feature("docstring") +gdcm::network::PresentationContextRQ::AddTransferSyntax "void +gdcm::network::PresentationContextRQ::AddTransferSyntax(TransferSyntaxSub +const &ts) "; + +%feature("docstring") +gdcm::network::PresentationContextRQ::GetAbstractSyntax "AbstractSyntax& +gdcm::network::PresentationContextRQ::GetAbstractSyntax() "; + +%feature("docstring") +gdcm::network::PresentationContextRQ::GetAbstractSyntax "AbstractSyntax const& +gdcm::network::PresentationContextRQ::GetAbstractSyntax() const "; + +%feature("docstring") +gdcm::network::PresentationContextRQ::GetNumberOfTransferSyntaxes "SizeType +gdcm::network::PresentationContextRQ::GetNumberOfTransferSyntaxes() +const "; + +%feature("docstring") +gdcm::network::PresentationContextRQ::GetPresentationContextID "uint8_t +gdcm::network::PresentationContextRQ::GetPresentationContextID() const +"; + +%feature("docstring") +gdcm::network::PresentationContextRQ::GetTransferSyntax "TransferSyntaxSub const& +gdcm::network::PresentationContextRQ::GetTransferSyntax(SizeType i) +const "; + +%feature("docstring") +gdcm::network::PresentationContextRQ::GetTransferSyntax "TransferSyntaxSub& +gdcm::network::PresentationContextRQ::GetTransferSyntax(SizeType i) "; + +%feature("docstring") +gdcm::network::PresentationContextRQ::GetTransferSyntaxes "std::vector const& +gdcm::network::PresentationContextRQ::GetTransferSyntaxes() const "; + +%feature("docstring") gdcm::network::PresentationContextRQ::Print "void gdcm::network::PresentationContextRQ::Print(std::ostream &os) +const "; + +%feature("docstring") gdcm::network::PresentationContextRQ::Read "std::istream& gdcm::network::PresentationContextRQ::Read(std::istream +&is) "; + +%feature("docstring") +gdcm::network::PresentationContextRQ::SetAbstractSyntax "void +gdcm::network::PresentationContextRQ::SetAbstractSyntax(AbstractSyntax +const &as) "; + +%feature("docstring") +gdcm::network::PresentationContextRQ::SetPresentationContextID "void +gdcm::network::PresentationContextRQ::SetPresentationContextID(uint8_t +id) "; + +%feature("docstring") gdcm::network::PresentationContextRQ::Size "size_t gdcm::network::PresentationContextRQ::Size() const "; + +%feature("docstring") gdcm::network::PresentationContextRQ::Write "const std::ostream& +gdcm::network::PresentationContextRQ::Write(std::ostream &os) const "; + + +// File: classgdcm_1_1network_1_1PresentationDataValue.xml +%feature("docstring") gdcm::network::PresentationDataValue " + +PresentationDataValue Table 9-23 PRESENTATION-DATA-VALUE ITEM FIELDS. + +C++ includes: gdcmPresentationDataValue.h "; + +%feature("docstring") +gdcm::network::PresentationDataValue::PresentationDataValue "gdcm::network::PresentationDataValue::PresentationDataValue() "; + +%feature("docstring") gdcm::network::PresentationDataValue::GetBlob "const std::string& gdcm::network::PresentationDataValue::GetBlob() +const "; + +%feature("docstring") +gdcm::network::PresentationDataValue::GetIsCommand "bool +gdcm::network::PresentationDataValue::GetIsCommand() const "; + +%feature("docstring") +gdcm::network::PresentationDataValue::GetIsLastFragment "bool +gdcm::network::PresentationDataValue::GetIsLastFragment() const "; + +%feature("docstring") +gdcm::network::PresentationDataValue::GetMessageHeader "uint8_t +gdcm::network::PresentationDataValue::GetMessageHeader() const "; + +%feature("docstring") +gdcm::network::PresentationDataValue::GetPresentationContextID "uint8_t +gdcm::network::PresentationDataValue::GetPresentationContextID() const +"; + +%feature("docstring") gdcm::network::PresentationDataValue::Print "void gdcm::network::PresentationDataValue::Print(std::ostream &os) +const "; + +%feature("docstring") gdcm::network::PresentationDataValue::Read "std::istream& gdcm::network::PresentationDataValue::Read(std::istream +&is) "; + +%feature("docstring") gdcm::network::PresentationDataValue::ReadInto +"std::istream& +gdcm::network::PresentationDataValue::ReadInto(std::istream &is, +std::ostream &os) "; + +%feature("docstring") gdcm::network::PresentationDataValue::SetBlob "void gdcm::network::PresentationDataValue::SetBlob(const std::string +&partialblob) "; + +%feature("docstring") +gdcm::network::PresentationDataValue::SetCommand "void +gdcm::network::PresentationDataValue::SetCommand(bool inCommand) "; + +%feature("docstring") +gdcm::network::PresentationDataValue::SetDataSet "void +gdcm::network::PresentationDataValue::SetDataSet(const DataSet &ds) + +Set DataSet. Write DataSet in implicit. WARNING: size of dataset +should be below maxpdusize "; + +%feature("docstring") +gdcm::network::PresentationDataValue::SetLastFragment "void +gdcm::network::PresentationDataValue::SetLastFragment(bool inLast) "; + +%feature("docstring") +gdcm::network::PresentationDataValue::SetMessageHeader "void +gdcm::network::PresentationDataValue::SetMessageHeader(uint8_t +messageheader) "; + +%feature("docstring") +gdcm::network::PresentationDataValue::SetPresentationContextID "void +gdcm::network::PresentationDataValue::SetPresentationContextID(uint8_t +id) "; + +%feature("docstring") gdcm::network::PresentationDataValue::Size "size_t gdcm::network::PresentationDataValue::Size() const "; + +%feature("docstring") gdcm::network::PresentationDataValue::Write "const std::ostream& +gdcm::network::PresentationDataValue::Write(std::ostream &os) const "; + + +// File: classgdcm_1_1Printer.xml +%feature("docstring") gdcm::Printer " + +Printer class. + +C++ includes: gdcmPrinter.h "; + +%feature("docstring") gdcm::Printer::Printer "gdcm::Printer::Printer() "; + +%feature("docstring") gdcm::Printer::~Printer "gdcm::Printer::~Printer() "; + +%feature("docstring") gdcm::Printer::GetPrintStyle "PrintStyles +gdcm::Printer::GetPrintStyle() const + +Get PrintStyle value. "; + +%feature("docstring") gdcm::Printer::Print "void +gdcm::Printer::Print(std::ostream &os) + +Print. "; + +%feature("docstring") gdcm::Printer::PrintDataSet "void +gdcm::Printer::PrintDataSet(const DataSet &ds, std::ostream &os, const +std::string &s=\"\") + +Print an individual dataset. "; + +%feature("docstring") gdcm::Printer::SetColor "void +gdcm::Printer::SetColor(bool c) + +Set color mode or not. "; + +%feature("docstring") gdcm::Printer::SetFile "void +gdcm::Printer::SetFile(File const &f) + +Set file. "; + +%feature("docstring") gdcm::Printer::SetStyle "void +gdcm::Printer::SetStyle(PrintStyles ps) + +Set PrintStyle value. "; + + +// File: classstd_1_1priority__queue.xml +%feature("docstring") std::priority_queue " + +STL class. "; + + +// File: classgdcm_1_1PrivateDict.xml +%feature("docstring") gdcm::PrivateDict " + +Private Dict. + +C++ includes: gdcmDict.h "; + +%feature("docstring") gdcm::PrivateDict::PrivateDict "gdcm::PrivateDict::PrivateDict() "; + +%feature("docstring") gdcm::PrivateDict::~PrivateDict "gdcm::PrivateDict::~PrivateDict() "; + +%feature("docstring") gdcm::PrivateDict::AddDictEntry "void +gdcm::PrivateDict::AddDictEntry(const PrivateTag &tag, const DictEntry +&de) "; + +%feature("docstring") gdcm::PrivateDict::FindDictEntry "bool +gdcm::PrivateDict::FindDictEntry(const PrivateTag &tag) const "; + +%feature("docstring") gdcm::PrivateDict::GetDictEntry "const +DictEntry& gdcm::PrivateDict::GetDictEntry(const PrivateTag &tag) +const "; + +%feature("docstring") gdcm::PrivateDict::IsEmpty "bool +gdcm::PrivateDict::IsEmpty() const "; + +%feature("docstring") gdcm::PrivateDict::PrintXML "void +gdcm::PrivateDict::PrintXML() const "; + +%feature("docstring") gdcm::PrivateDict::RemoveDictEntry "bool +gdcm::PrivateDict::RemoveDictEntry(const PrivateTag &tag) + +Remove entry 'tag'. Return true on success (element was found and +remove). return false if element was not found. "; + + +// File: classgdcm_1_1PrivateTag.xml +%feature("docstring") gdcm::PrivateTag " + +Class to represent a Private DICOM Data Element ( Attribute) Tag +(Group, Element, Owner). + +private tag have element value in: [0x10,0xff], for instance +0x0009,0x0000 is NOT a private tag + +C++ includes: gdcmPrivateTag.h "; + +%feature("docstring") gdcm::PrivateTag::PrivateTag "gdcm::PrivateTag::PrivateTag(uint16_t group=0, uint16_t element=0, +const char *owner=\"\") "; + +%feature("docstring") gdcm::PrivateTag::GetOwner "const char* +gdcm::PrivateTag::GetOwner() const "; + +%feature("docstring") gdcm::PrivateTag::ReadFromCommaSeparatedString +"bool gdcm::PrivateTag::ReadFromCommaSeparatedString(const char *str) + +Read PrivateTag from a string. Element number will be truncated to +8bits. Eg: \"1234,5678,GDCM\" is private tag: (1234,78,\"GDCM\") "; + +%feature("docstring") gdcm::PrivateTag::SetOwner "void +gdcm::PrivateTag::SetOwner(const char *owner) "; + + +// File: classgdcm_1_1ProgressEvent.xml +%feature("docstring") gdcm::ProgressEvent " + +ProgressEvent Special type of event triggered during. + +See: AnyEvent + +C++ includes: gdcmProgressEvent.h "; + +%feature("docstring") gdcm::ProgressEvent::ProgressEvent "gdcm::ProgressEvent::ProgressEvent(double p=0) "; + +%feature("docstring") gdcm::ProgressEvent::ProgressEvent "gdcm::ProgressEvent::ProgressEvent(const Self &s) "; + +%feature("docstring") gdcm::ProgressEvent::~ProgressEvent "virtual +gdcm::ProgressEvent::~ProgressEvent() "; + +%feature("docstring") gdcm::ProgressEvent::CheckEvent "virtual bool +gdcm::ProgressEvent::CheckEvent(const ::gdcm::Event *e) const "; + +%feature("docstring") gdcm::ProgressEvent::GetEventName "virtual +const char* gdcm::ProgressEvent::GetEventName() const + +Return the StringName associated with the event. "; + +%feature("docstring") gdcm::ProgressEvent::GetProgress "double +gdcm::ProgressEvent::GetProgress() const "; + +%feature("docstring") gdcm::ProgressEvent::MakeObject "virtual +::gdcm::Event* gdcm::ProgressEvent::MakeObject() const + +Create an Event of this type This method work as a Factory for +creating events of each particular type. "; + +%feature("docstring") gdcm::ProgressEvent::SetProgress "void +gdcm::ProgressEvent::SetProgress(double p) "; + + +// File: classgdcm_1_1PVRGCodec.xml +%feature("docstring") gdcm::PVRGCodec " + +PVRGCodec. + +pvrg is a broken implementation of the JPEG standard. It is known to +have a bug in the 16bits lossless implementation of the standard. In +an ideal world, you should not need this codec at all. But to support +some broken file such as: + +PHILIPS_Gyroscan-12-Jpeg_Extended_Process_2_4.dcm + +we have to... + +C++ includes: gdcmPVRGCodec.h "; + +%feature("docstring") gdcm::PVRGCodec::PVRGCodec "gdcm::PVRGCodec::PVRGCodec() "; + +%feature("docstring") gdcm::PVRGCodec::~PVRGCodec "gdcm::PVRGCodec::~PVRGCodec() "; + +%feature("docstring") gdcm::PVRGCodec::CanCode "bool +gdcm::PVRGCodec::CanCode(TransferSyntax const &ts) const "; + +%feature("docstring") gdcm::PVRGCodec::CanDecode "bool +gdcm::PVRGCodec::CanDecode(TransferSyntax const &ts) const + +Return whether this decoder support this transfer syntax (can decode +it). "; + +%feature("docstring") gdcm::PVRGCodec::Code "bool +gdcm::PVRGCodec::Code(DataElement const &in, DataElement &out) "; + +%feature("docstring") gdcm::PVRGCodec::Decode "bool +gdcm::PVRGCodec::Decode(DataElement const &is, DataElement &os) + +Decode. "; + + +// File: classgdcm_1_1PythonFilter.xml +%feature("docstring") gdcm::PythonFilter " + +PythonFilter PythonFilter is the class that make gdcm2.x looks more +like gdcm1 and transform the binary blob contained in a DataElement +into a string, typically this is a nice feature to have for wrapped +language. + +C++ includes: gdcmPythonFilter.h "; + +%feature("docstring") gdcm::PythonFilter::PythonFilter "gdcm::PythonFilter::PythonFilter() "; + +%feature("docstring") gdcm::PythonFilter::~PythonFilter "gdcm::PythonFilter::~PythonFilter() "; + +%feature("docstring") gdcm::PythonFilter::GetFile "const File& +gdcm::PythonFilter::GetFile() const "; + +%feature("docstring") gdcm::PythonFilter::GetFile "File& +gdcm::PythonFilter::GetFile() "; + +%feature("docstring") gdcm::PythonFilter::SetDicts "void +gdcm::PythonFilter::SetDicts(const Dicts &dicts) "; + +%feature("docstring") gdcm::PythonFilter::SetFile "void +gdcm::PythonFilter::SetFile(const File &f) "; + +%feature("docstring") gdcm::PythonFilter::ToPyObject "PyObject* +gdcm::PythonFilter::ToPyObject(const Tag &t) const "; + +%feature("docstring") gdcm::PythonFilter::UseDictAlways "void +gdcm::PythonFilter::UseDictAlways(bool use) "; + + +// File: classgdcm_1_1QueryBase.xml +%feature("docstring") gdcm::QueryBase " + +QueryBase contains: the base class for constructing a query dataset +for a C-FIND and a C-MOVE. + +There are four levels of C-FIND and C-MOVE query: Patient + +Study + +Series + +Image Each one has its own required and optional tags. This class +provides an interface for getting those tags. This is an interface +class. + +See 3.4 C 6.1 and 3.4 C 6.2 for the patient and study root query +types. These sections define the tags allowed by a particular query. +The caller must pass in which root type they want, patient or study. A +third root type, Modality Worklist Query, isn't yet supported. + +This class (or rather it's derived classes) will be held in the +RootQuery types. These query types actually make the dataset, and will +use this dataset to list the required, unique, and optional tags for +each type of query. This design is somewhat overly complicated, but is +kept so that if we ever wanted to try to guess the query type from the +given tags, we could do so. + +C++ includes: gdcmQueryBase.h "; + +%feature("docstring") gdcm::QueryBase::~QueryBase "virtual +gdcm::QueryBase::~QueryBase() "; + +%feature("docstring") gdcm::QueryBase::GetAllRequiredTags "std::vector gdcm::QueryBase::GetAllRequiredTags(const ERootType +&inRootType) const + +In order to validate a query dataset we need to check that there +exists at least one required (or unique) key "; + +%feature("docstring") gdcm::QueryBase::GetAllTags "std::vector +gdcm::QueryBase::GetAllTags(const ERootType &inRootType) const + +In order to validate a query dataset, just check for the presence of a +tag, not it's requirement level in the spec "; + +%feature("docstring") gdcm::QueryBase::GetHierachicalSearchTags "virtual std::vector +gdcm::QueryBase::GetHierachicalSearchTags(const ERootType &inRootType) +const =0 + +Return all Unique Key for a particular Query Root type (from the same +level and above). "; + +%feature("docstring") gdcm::QueryBase::GetName "virtual const char* +gdcm::QueryBase::GetName() const =0 "; + +%feature("docstring") gdcm::QueryBase::GetOptionalTags "virtual +std::vector gdcm::QueryBase::GetOptionalTags(const ERootType +&inRootType) const =0 "; + +%feature("docstring") gdcm::QueryBase::GetQueryLevel "virtual +DataElement gdcm::QueryBase::GetQueryLevel() const =0 "; + +%feature("docstring") gdcm::QueryBase::GetRequiredTags "virtual +std::vector gdcm::QueryBase::GetRequiredTags(const ERootType +&inRootType) const =0 "; + +%feature("docstring") gdcm::QueryBase::GetUniqueTags "virtual +std::vector gdcm::QueryBase::GetUniqueTags(const ERootType +&inRootType) const =0 "; + + +// File: classgdcm_1_1QueryFactory.xml +%feature("docstring") gdcm::QueryFactory " + +QueryFactory.h. + +contains: a class to produce a query based off of user-entered +information Essentially, this class is used to construct a query +based off of user input (typically from the command line; if in code +directly, the query itself could just be instantiated) + +In theory, could also be used as the interface to validate incoming +datasets as belonging to a particular query style + +C++ includes: gdcmQueryFactory.h "; + + +// File: classgdcm_1_1QueryImage.xml +%feature("docstring") gdcm::QueryImage " + +QueryImage contains: class to construct an image-based query for +C-FIND and C-MOVE. + +C++ includes: gdcmQueryImage.h "; + +%feature("docstring") gdcm::QueryImage::GetHierachicalSearchTags "std::vector gdcm::QueryImage::GetHierachicalSearchTags(const +ERootType &inRootType) const + +Return all Unique Key for a particular Query Root type (from the same +level and above). "; + +%feature("docstring") gdcm::QueryImage::GetName "const char* +gdcm::QueryImage::GetName() const "; + +%feature("docstring") gdcm::QueryImage::GetOptionalTags "std::vector gdcm::QueryImage::GetOptionalTags(const ERootType +&inRootType) const "; + +%feature("docstring") gdcm::QueryImage::GetQueryLevel "DataElement +gdcm::QueryImage::GetQueryLevel() const "; + +%feature("docstring") gdcm::QueryImage::GetRequiredTags "std::vector gdcm::QueryImage::GetRequiredTags(const ERootType +&inRootType) const "; + +%feature("docstring") gdcm::QueryImage::GetUniqueTags "std::vector gdcm::QueryImage::GetUniqueTags(const ERootType +&inRootType) const "; + + +// File: classgdcm_1_1QueryPatient.xml +%feature("docstring") gdcm::QueryPatient " + +QueryPatient contains: class to construct a patient-based query for +c-find and c-move. + +C++ includes: gdcmQueryPatient.h "; + +%feature("docstring") gdcm::QueryPatient::GetHierachicalSearchTags "std::vector gdcm::QueryPatient::GetHierachicalSearchTags(const +ERootType &inRootType) const + +Return all Unique Key for a particular Query Root type (from the same +level and above). "; + +%feature("docstring") gdcm::QueryPatient::GetName "const char* +gdcm::QueryPatient::GetName() const "; + +%feature("docstring") gdcm::QueryPatient::GetOptionalTags "std::vector gdcm::QueryPatient::GetOptionalTags(const ERootType +&inRootType) const "; + +%feature("docstring") gdcm::QueryPatient::GetQueryLevel "DataElement +gdcm::QueryPatient::GetQueryLevel() const "; + +%feature("docstring") gdcm::QueryPatient::GetRequiredTags "std::vector gdcm::QueryPatient::GetRequiredTags(const ERootType +&inRootType) const "; + +%feature("docstring") gdcm::QueryPatient::GetUniqueTags "std::vector gdcm::QueryPatient::GetUniqueTags(const ERootType +&inRootType) const "; + + +// File: classgdcm_1_1QuerySeries.xml +%feature("docstring") gdcm::QuerySeries " + +QuerySeries contains: class to construct a series-based query for +c-find and c-move. + +C++ includes: gdcmQuerySeries.h "; + +%feature("docstring") gdcm::QuerySeries::GetHierachicalSearchTags "std::vector gdcm::QuerySeries::GetHierachicalSearchTags(const +ERootType &inRootType) const + +Return all Unique Key for a particular Query Root type (from the same +level and above). "; + +%feature("docstring") gdcm::QuerySeries::GetName "const char* +gdcm::QuerySeries::GetName() const "; + +%feature("docstring") gdcm::QuerySeries::GetOptionalTags "std::vector gdcm::QuerySeries::GetOptionalTags(const ERootType +&inRootType) const "; + +%feature("docstring") gdcm::QuerySeries::GetQueryLevel "DataElement +gdcm::QuerySeries::GetQueryLevel() const "; + +%feature("docstring") gdcm::QuerySeries::GetRequiredTags "std::vector gdcm::QuerySeries::GetRequiredTags(const ERootType +&inRootType) const "; + +%feature("docstring") gdcm::QuerySeries::GetUniqueTags "std::vector gdcm::QuerySeries::GetUniqueTags(const ERootType +&inRootType) const "; + + +// File: classgdcm_1_1QueryStudy.xml +%feature("docstring") gdcm::QueryStudy " + +QueryStudy.h contains: class to construct a study-based query for +C-FIND and C-MOVE. + +C++ includes: gdcmQueryStudy.h "; + +%feature("docstring") gdcm::QueryStudy::GetHierachicalSearchTags "std::vector gdcm::QueryStudy::GetHierachicalSearchTags(const +ERootType &inRootType) const + +Return all Unique Key for a particular Query Root type (from the same +level and above). "; + +%feature("docstring") gdcm::QueryStudy::GetName "const char* +gdcm::QueryStudy::GetName() const "; + +%feature("docstring") gdcm::QueryStudy::GetOptionalTags "std::vector gdcm::QueryStudy::GetOptionalTags(const ERootType +&inRootType) const "; + +%feature("docstring") gdcm::QueryStudy::GetQueryLevel "DataElement +gdcm::QueryStudy::GetQueryLevel() const "; + +%feature("docstring") gdcm::QueryStudy::GetRequiredTags "std::vector gdcm::QueryStudy::GetRequiredTags(const ERootType +&inRootType) const "; + +%feature("docstring") gdcm::QueryStudy::GetUniqueTags "std::vector gdcm::QueryStudy::GetUniqueTags(const ERootType +&inRootType) const "; + + +// File: classstd_1_1queue.xml +%feature("docstring") std::queue " + +STL class. "; + + +// File: classstd_1_1range__error.xml +%feature("docstring") std::range_error " + +STL class. "; + + +// File: classgdcm_1_1RAWCodec.xml +%feature("docstring") gdcm::RAWCodec " + +RAWCodec class. + +C++ includes: gdcmRAWCodec.h "; + +%feature("docstring") gdcm::RAWCodec::RAWCodec "gdcm::RAWCodec::RAWCodec() "; + +%feature("docstring") gdcm::RAWCodec::~RAWCodec "gdcm::RAWCodec::~RAWCodec() "; + +%feature("docstring") gdcm::RAWCodec::CanCode "bool +gdcm::RAWCodec::CanCode(TransferSyntax const &ts) const "; + +%feature("docstring") gdcm::RAWCodec::CanDecode "bool +gdcm::RAWCodec::CanDecode(TransferSyntax const &ts) const + +Return whether this decoder support this transfer syntax (can decode +it). "; + +%feature("docstring") gdcm::RAWCodec::Code "bool +gdcm::RAWCodec::Code(DataElement const &in, DataElement &out) "; + +%feature("docstring") gdcm::RAWCodec::Decode "bool +gdcm::RAWCodec::Decode(DataElement const &is, DataElement &os) + +Decode. "; + +%feature("docstring") gdcm::RAWCodec::DecodeBytes "bool +gdcm::RAWCodec::DecodeBytes(const char *inBytes, size_t +inBufferLength, char *outBytes, size_t inOutBufferLength) + +Used by the ImageStreamReader-- converts a read in buffer into one +with the proper encodings. "; + +%feature("docstring") gdcm::RAWCodec::GetHeaderInfo "bool +gdcm::RAWCodec::GetHeaderInfo(std::istream &is, TransferSyntax &ts) "; + + +// File: classgdcm_1_1Reader.xml +%feature("docstring") gdcm::Reader " + +Reader ala DOM (Document Object Model). + +This class is a non-validating reader, it will only performs well- +formedness check only, and to some extent catch known error (non well- +formed document). + +Detailled description here + +A DataSet DOES NOT contains group 0x0002 (see FileMetaInformation) + +This is really a DataSet reader. This will not make sure the dataset +conform to any IOD at all. This is a completely different step. The +reasoning was that user could control the IOD there lib would handle +and thus we would not be able to read a DataSet if the IOD was not +found Instead we separate the reading from the validation. + +From GDCM1.x. Users will realize that one feature is missing from this +DOM implementation. In GDCM 1.x user used to be able to control the +size of the Value to be read. By default it was 0xfff. The main author +of GDCM2 thought this was too dangerous and harmful and therefore this +feature did not make it into GDCM2 + +WARNING: GDCM will not produce warning for unorder (non-alphabetical +order). + +See: Writer FileMetaInformation DataSet File + +C++ includes: gdcmReader.h "; + +%feature("docstring") gdcm::Reader::Reader "gdcm::Reader::Reader() +"; + +%feature("docstring") gdcm::Reader::~Reader "virtual +gdcm::Reader::~Reader() "; + +%feature("docstring") gdcm::Reader::CanRead "bool +gdcm::Reader::CanRead() const + +Test whether this is a DICOM file WARNING: need to call either +SetFileName or SetStream first "; + +%feature("docstring") gdcm::Reader::GetFile "const File& +gdcm::Reader::GetFile() const + +Set/Get File. "; + +%feature("docstring") gdcm::Reader::GetFile "File& +gdcm::Reader::GetFile() + +Set/Get File. "; + +%feature("docstring") gdcm::Reader::Read "virtual bool +gdcm::Reader::Read() + +Main function to read a file. "; + +%feature("docstring") gdcm::Reader::ReadSelectedTags "bool +gdcm::Reader::ReadSelectedTags(std::set< Tag > const &tags) + +Will only read the specified selected tags. "; + +%feature("docstring") gdcm::Reader::ReadUpToTag "bool +gdcm::Reader::ReadUpToTag(const Tag &tag, std::set< Tag > const +&skiptags=std::set< Tag >()) + +Will read only up to Tag + +Parameters: +----------- + +tag: and skipping any tag specified in + +skiptags: "; + +%feature("docstring") gdcm::Reader::SetFile "void +gdcm::Reader::SetFile(File &file) + +Set/Get File. "; + +%feature("docstring") gdcm::Reader::SetFileName "void +gdcm::Reader::SetFileName(const char *filename_native) + +Set the filename to open. This will create a std::ifstream internally +See SetStream if you are dealing with different std::istream object "; + +%feature("docstring") gdcm::Reader::SetStream "void +gdcm::Reader::SetStream(std::istream &input_stream) + +Set the open-ed stream directly. "; + + +// File: classgdcm_1_1Region.xml +%feature("docstring") gdcm::Region " + +Class for manipulation region. + +C++ includes: gdcmRegion.h "; + +%feature("docstring") gdcm::Region::Region "gdcm::Region::Region() +"; + +%feature("docstring") gdcm::Region::~Region "virtual +gdcm::Region::~Region() "; + +%feature("docstring") gdcm::Region::Area "virtual size_t +gdcm::Region::Area() const =0 + +compute the area "; + +%feature("docstring") gdcm::Region::Clone "virtual Region* +gdcm::Region::Clone() const =0 "; + +%feature("docstring") gdcm::Region::ComputeBoundingBox "virtual +BoxRegion gdcm::Region::ComputeBoundingBox()=0 + +Return the Axis-Aligned minimum bounding box for all regions. "; + +%feature("docstring") gdcm::Region::Empty "virtual bool +gdcm::Region::Empty() const =0 + +return whether this domain is empty: "; + +%feature("docstring") gdcm::Region::IsValid "virtual bool +gdcm::Region::IsValid() const =0 + +return whether this is valid domain "; + +%feature("docstring") gdcm::Region::Print "virtual void +gdcm::Region::Print(std::ostream &os=std::cout) const + +Print. "; + + +// File: classgdcm_1_1Rescaler.xml +%feature("docstring") gdcm::Rescaler " + +Rescale class This class is meant to apply the linear transform of +Stored Pixel Value to Real World Value. This is mostly found in CT or +PET dataset, where the value are stored using one type, but need to be +converted to another scale using a linear transform. There are +basically two cases: In CT: the linear transform is generally integer +based. E.g. the Stored Pixel Type is unsigned short 12bits, but to get +Hounsfield unit, one need to apply the linear transform: \\\\[ RWV = +1. * SV - 1024 \\\\] So the best scalar to store the Real World Value +will be 16 bits signed type. + +In PET: the linear transform is generally floating point based. Since +the dynamic range can be quite high, the Rescale Slope / Rescale +Intercept can be changing throughout the Series. So it is important to +read all linear transform and deduce the best Pixel Type only at the +end (when all the images to be read have been parsed). + +WARNING: Internally any time a floating point value is found either +in the Rescale Slope or the Rescale Intercept it is assumed that the +best matching output pixel type is FLOAT64 (in previous implementation +it was FLOAT32). Because VR:DS is closer to a 64bits floating point +type FLOAT64 is thus a best matching pixel type for the floating point +transformation. Example: Let say input is FLOAT64, and we want UINT16 +as ouput, we would do: + +handle floating point transformation back and forth to integer +properly (no loss) + +See: Unpacker12Bits + +C++ includes: gdcmRescaler.h "; + +%feature("docstring") gdcm::Rescaler::Rescaler "gdcm::Rescaler::Rescaler() "; + +%feature("docstring") gdcm::Rescaler::~Rescaler "gdcm::Rescaler::~Rescaler() "; + +%feature("docstring") gdcm::Rescaler::ComputeInterceptSlopePixelType +"PixelFormat::ScalarType +gdcm::Rescaler::ComputeInterceptSlopePixelType() + +Compute the Pixel Format of the output data Used for direct +transformation "; + +%feature("docstring") gdcm::Rescaler::ComputePixelTypeFromMinMax "PixelFormat gdcm::Rescaler::ComputePixelTypeFromMinMax() + +Compute the Pixel Format of the output data Used for inverse +transformation "; + +%feature("docstring") gdcm::Rescaler::GetIntercept "double +gdcm::Rescaler::GetIntercept() const "; + +%feature("docstring") gdcm::Rescaler::GetSlope "double +gdcm::Rescaler::GetSlope() const "; + +%feature("docstring") gdcm::Rescaler::InverseRescale "bool +gdcm::Rescaler::InverseRescale(char *out, const char *in, size_t n) + +Inverse transform. "; + +%feature("docstring") gdcm::Rescaler::Rescale "bool +gdcm::Rescaler::Rescale(char *out, const char *in, size_t n) + +Direct transform. "; + +%feature("docstring") gdcm::Rescaler::SetIntercept "void +gdcm::Rescaler::SetIntercept(double i) + +Set Intercept: used for both direct&inverse transformation. "; + +%feature("docstring") gdcm::Rescaler::SetMinMaxForPixelType "void +gdcm::Rescaler::SetMinMaxForPixelType(double min, double max) + +Set target interval for output data. A best match will be computed (if +possible) Used for inverse transformation "; + +%feature("docstring") gdcm::Rescaler::SetPixelFormat "void +gdcm::Rescaler::SetPixelFormat(PixelFormat const &pf) + +Set Pixel Format of input data. "; + +%feature("docstring") gdcm::Rescaler::SetSlope "void +gdcm::Rescaler::SetSlope(double s) + +Set Slope: user for both direct&inverse transformation. "; + +%feature("docstring") gdcm::Rescaler::SetTargetPixelType "void +gdcm::Rescaler::SetTargetPixelType(PixelFormat const &targetst) + +By default (when UseTargetPixelType is false), a best matching Target +Pixel Type is computed. However user can override this auto selection +by switching UseTargetPixelType:true and also specifying the specifix +Target Pixel Type "; + +%feature("docstring") gdcm::Rescaler::SetUseTargetPixelType "void +gdcm::Rescaler::SetUseTargetPixelType(bool b) + +Override default behavior of Rescale. "; + + +// File: classstd_1_1map_1_1reverse__iterator.xml +%feature("docstring") std::map::reverse_iterator " + +STL iterator class. "; + + +// File: classstd_1_1multiset_1_1reverse__iterator.xml +%feature("docstring") std::multiset::reverse_iterator " + +STL iterator class. "; + + +// File: classstd_1_1multimap_1_1reverse__iterator.xml +%feature("docstring") std::multimap::reverse_iterator " + +STL iterator class. "; + + +// File: classstd_1_1list_1_1reverse__iterator.xml +%feature("docstring") std::list::reverse_iterator " + +STL iterator class. "; + + +// File: classstd_1_1deque_1_1reverse__iterator.xml +%feature("docstring") std::deque::reverse_iterator " + +STL iterator class. "; + + +// File: classstd_1_1wstring_1_1reverse__iterator.xml +%feature("docstring") std::wstring::reverse_iterator " + +STL iterator class. "; + + +// File: classstd_1_1set_1_1reverse__iterator.xml +%feature("docstring") std::set::reverse_iterator " + +STL iterator class. "; + + +// File: classstd_1_1vector_1_1reverse__iterator.xml +%feature("docstring") std::vector::reverse_iterator " + +STL iterator class. "; + + +// File: classstd_1_1string_1_1reverse__iterator.xml +%feature("docstring") std::string::reverse_iterator " + +STL iterator class. "; + + +// File: classstd_1_1basic__string_1_1reverse__iterator.xml +%feature("docstring") std::basic_string::reverse_iterator " + +STL iterator class. "; + + +// File: classgdcm_1_1RLECodec.xml +%feature("docstring") gdcm::RLECodec " + +Class to do RLE. + +ANSI X3.9 A.4.2 RLE Compression Annex G defines a RLE Compression +Transfer Syntax. This transfer Syntax is identified by the UID value +\"1.2.840.10008.1.2.5\". If the object allows multi-frame images in +the pixel data field, then each frame shall be encoded separately. +Each frame shall be encoded in one and only one Fragment (see PS +3.5.8.2). + +C++ includes: gdcmRLECodec.h "; + +%feature("docstring") gdcm::RLECodec::RLECodec "gdcm::RLECodec::RLECodec() "; + +%feature("docstring") gdcm::RLECodec::~RLECodec "gdcm::RLECodec::~RLECodec() "; + +%feature("docstring") gdcm::RLECodec::CanCode "bool +gdcm::RLECodec::CanCode(TransferSyntax const &ts) const "; + +%feature("docstring") gdcm::RLECodec::CanDecode "bool +gdcm::RLECodec::CanDecode(TransferSyntax const &ts) const + +Return whether this decoder support this transfer syntax (can decode +it). "; + +%feature("docstring") gdcm::RLECodec::Code "bool +gdcm::RLECodec::Code(DataElement const &in, DataElement &out) "; + +%feature("docstring") gdcm::RLECodec::Decode "bool +gdcm::RLECodec::Decode(DataElement const &is, DataElement &os) + +Decode. "; + +%feature("docstring") gdcm::RLECodec::GetBufferLength "unsigned long +gdcm::RLECodec::GetBufferLength() const "; + +%feature("docstring") gdcm::RLECodec::GetHeaderInfo "bool +gdcm::RLECodec::GetHeaderInfo(std::istream &is, TransferSyntax &ts) "; + +%feature("docstring") gdcm::RLECodec::SetBufferLength "void +gdcm::RLECodec::SetBufferLength(unsigned long l) "; + +%feature("docstring") gdcm::RLECodec::SetLength "void +gdcm::RLECodec::SetLength(unsigned long l) "; + + +// File: classgdcm_1_1network_1_1RoleSelectionSub.xml +%feature("docstring") gdcm::network::RoleSelectionSub " + +RoleSelectionSub PS 3.7 Table D.3-9 SCP/SCU ROLE SELECTION SUB-ITEM +FIELDS (A-ASSOCIATE-RQ). + +C++ includes: gdcmRoleSelectionSub.h "; + +%feature("docstring") +gdcm::network::RoleSelectionSub::RoleSelectionSub "gdcm::network::RoleSelectionSub::RoleSelectionSub() "; + +%feature("docstring") gdcm::network::RoleSelectionSub::Print "void +gdcm::network::RoleSelectionSub::Print(std::ostream &os) const "; + +%feature("docstring") gdcm::network::RoleSelectionSub::Read "std::istream& gdcm::network::RoleSelectionSub::Read(std::istream &is) +"; + +%feature("docstring") gdcm::network::RoleSelectionSub::SetTuple "void gdcm::network::RoleSelectionSub::SetTuple(const char *uid, +uint8_t scurole, uint8_t scprole) "; + +%feature("docstring") gdcm::network::RoleSelectionSub::Size "size_t +gdcm::network::RoleSelectionSub::Size() const "; + +%feature("docstring") gdcm::network::RoleSelectionSub::Write "const +std::ostream& gdcm::network::RoleSelectionSub::Write(std::ostream &os) +const "; + + +// File: structgdcm_1_1SerieHelper_1_1Rule.xml + + +// File: classstd_1_1runtime__error.xml +%feature("docstring") std::runtime_error " + +STL class. "; + + +// File: classgdcm_1_1Scanner.xml +%feature("docstring") gdcm::Scanner " + +Scanner This filter is meant for quickly browsing a FileSet (a set of +files on disk). Special consideration are taken so as to read the +mimimum amount of information in each file in order to retrieve the +user specified set of DICOM Attribute. + +This filter is dealing with both VRASCII and VRBINARY element, thanks +to the help of gdcm::StringFilter + +WARNING: IMPORTANT In case of file where tags are not ordered +(illegal as per DICOM specification), the output will be missing +information + +implementation details. All values are stored in a std::set of +std::string. Then the address of the cstring underlying the +std::string is used in the std::map. This class implement the +Subject/Observer pattern trigger the following events: ProgressEvent + +StartEvent + +EndEvent + +C++ includes: gdcmScanner.h "; + +%feature("docstring") gdcm::Scanner::Scanner "gdcm::Scanner::Scanner() "; + +%feature("docstring") gdcm::Scanner::~Scanner "gdcm::Scanner::~Scanner() "; + +%feature("docstring") gdcm::Scanner::AddPrivateTag "void +gdcm::Scanner::AddPrivateTag(PrivateTag const &t) "; + +%feature("docstring") gdcm::Scanner::AddSkipTag "void +gdcm::Scanner::AddSkipTag(Tag const &t) + +Add a tag that will need to be skipped. Those are root level skip +tags. "; + +%feature("docstring") gdcm::Scanner::AddTag "void +gdcm::Scanner::AddTag(Tag const &t) + +Add a tag that will need to be read. Those are root level skip tags. +"; + +%feature("docstring") gdcm::Scanner::Begin "ConstIterator +gdcm::Scanner::Begin() const "; + +%feature("docstring") gdcm::Scanner::ClearSkipTags "void +gdcm::Scanner::ClearSkipTags() "; + +%feature("docstring") gdcm::Scanner::ClearTags "void +gdcm::Scanner::ClearTags() "; + +%feature("docstring") gdcm::Scanner::End "ConstIterator +gdcm::Scanner::End() const "; + +%feature("docstring") gdcm::Scanner::GetAllFilenamesFromTagToValue "Directory::FilenamesType +gdcm::Scanner::GetAllFilenamesFromTagToValue(Tag const &t, const char +*valueref) const + +Will loop over all files and return a vector of std::strings of +filenames where value match the reference value 'valueref' "; + +%feature("docstring") gdcm::Scanner::GetFilenameFromTagToValue "const char* gdcm::Scanner::GetFilenameFromTagToValue(Tag const &t, +const char *valueref) const + +Will loop over all files and return the first file where value match +the reference value 'valueref' "; + +%feature("docstring") gdcm::Scanner::GetFilenames "Directory::FilenamesType const& gdcm::Scanner::GetFilenames() const "; + +%feature("docstring") gdcm::Scanner::GetKeys "Directory::FilenamesType gdcm::Scanner::GetKeys() const + +Return the list of filename that are key in the internal map, which +means those filename were properly parsed "; + +%feature("docstring") gdcm::Scanner::GetMapping "TagToValue const& +gdcm::Scanner::GetMapping(const char *filename) const + +Get the std::map mapping filenames to value for file 'filename'. "; + +%feature("docstring") gdcm::Scanner::GetMappingFromTagToValue "TagToValue const& gdcm::Scanner::GetMappingFromTagToValue(Tag const +&t, const char *value) const + +See GetFilenameFromTagToValue(). This is simply +GetFilenameFromTagToValue followed. "; + +%feature("docstring") gdcm::Scanner::GetMappings "MappingType const& +gdcm::Scanner::GetMappings() const + +Mappings are the mapping from a particular tag to the map, mapping +filename to value: "; + +%feature("docstring") gdcm::Scanner::GetOrderedValues "Directory::FilenamesType gdcm::Scanner::GetOrderedValues(Tag const &t) +const + +Get all the values found (in a vector) associated with Tag 't' This +function is identical to GetValues, but is accessible from the wrapped +layer (python, C#, java) "; + +%feature("docstring") gdcm::Scanner::GetValue "const char* +gdcm::Scanner::GetValue(const char *filename, Tag const &t) const + +Retrieve the value found for tag: t associated withfile: filename This +is meant for a single short call. If multiple calls (multiple tags) +should be done, prefer the GetMapping function, and then reuse the +TagToValue hash table. WARNING: Tag 't' should have been added via +AddTag() prior to the Scan() call ! "; + +%feature("docstring") gdcm::Scanner::GetValues "ValuesType const& +gdcm::Scanner::GetValues() const + +Get all the values found (in lexicographic order). "; + +%feature("docstring") gdcm::Scanner::GetValues "ValuesType +gdcm::Scanner::GetValues(Tag const &t) const + +Get all the values found (in lexicographic order) associated with Tag +'t'. "; + +%feature("docstring") gdcm::Scanner::IsKey "bool +gdcm::Scanner::IsKey(const char *filename) const + +Check if filename is a key in the Mapping table. returns true only of +file can be found, which means the file was indeed a DICOM file that +could be processed "; + +%feature("docstring") gdcm::Scanner::Print "void +gdcm::Scanner::Print(std::ostream &os) const + +Print result. "; + +%feature("docstring") gdcm::Scanner::Scan "bool +gdcm::Scanner::Scan(Directory::FilenamesType const &filenames) + +Start the scan ! "; + + +// File: classgdcm_1_1Segment.xml +%feature("docstring") gdcm::Segment " + +This class defines a segment. It mainly contains attributes of group +0x0062. In addition, it can be associated with surface. + +See: PS 3.3 C.8.20.2 and C.8.23 + +C++ includes: gdcmSegment.h "; + +%feature("docstring") gdcm::Segment::Segment "gdcm::Segment::Segment() "; + +%feature("docstring") gdcm::Segment::~Segment "virtual +gdcm::Segment::~Segment() "; + +%feature("docstring") gdcm::Segment::AddSurface "void +gdcm::Segment::AddSurface(SmartPointer< Surface > surface) "; + +%feature("docstring") gdcm::Segment::GetAnatomicRegion "SegmentHelper::BasicCodedEntry const& +gdcm::Segment::GetAnatomicRegion() const "; + +%feature("docstring") gdcm::Segment::GetAnatomicRegion "SegmentHelper::BasicCodedEntry& gdcm::Segment::GetAnatomicRegion() "; + +%feature("docstring") gdcm::Segment::GetPropertyCategory "SegmentHelper::BasicCodedEntry& gdcm::Segment::GetPropertyCategory() +"; + +%feature("docstring") gdcm::Segment::GetPropertyCategory "SegmentHelper::BasicCodedEntry const& +gdcm::Segment::GetPropertyCategory() const "; + +%feature("docstring") gdcm::Segment::GetPropertyType "SegmentHelper::BasicCodedEntry& gdcm::Segment::GetPropertyType() "; + +%feature("docstring") gdcm::Segment::GetPropertyType "SegmentHelper::BasicCodedEntry const& gdcm::Segment::GetPropertyType() +const "; + +%feature("docstring") gdcm::Segment::GetSegmentAlgorithmName "const +char* gdcm::Segment::GetSegmentAlgorithmName() const "; + +%feature("docstring") gdcm::Segment::GetSegmentAlgorithmType "ALGOType gdcm::Segment::GetSegmentAlgorithmType() const "; + +%feature("docstring") gdcm::Segment::GetSegmentDescription "const +char* gdcm::Segment::GetSegmentDescription() const "; + +%feature("docstring") gdcm::Segment::GetSegmentLabel "const char* +gdcm::Segment::GetSegmentLabel() const "; + +%feature("docstring") gdcm::Segment::GetSegmentNumber "unsigned +short gdcm::Segment::GetSegmentNumber() const "; + +%feature("docstring") gdcm::Segment::GetSurface "SmartPointer< +Surface > gdcm::Segment::GetSurface(const unsigned int idx=0) const "; + +%feature("docstring") gdcm::Segment::GetSurfaceCount "unsigned long +gdcm::Segment::GetSurfaceCount() "; + +%feature("docstring") gdcm::Segment::GetSurfaces "SurfaceVector& +gdcm::Segment::GetSurfaces() "; + +%feature("docstring") gdcm::Segment::GetSurfaces "SurfaceVector +const& gdcm::Segment::GetSurfaces() const "; + +%feature("docstring") gdcm::Segment::SetAnatomicRegion "void +gdcm::Segment::SetAnatomicRegion(SegmentHelper::BasicCodedEntry const +&BSE) "; + +%feature("docstring") gdcm::Segment::SetPropertyCategory "void +gdcm::Segment::SetPropertyCategory(SegmentHelper::BasicCodedEntry +const &BSE) "; + +%feature("docstring") gdcm::Segment::SetPropertyType "void +gdcm::Segment::SetPropertyType(SegmentHelper::BasicCodedEntry const +&BSE) "; + +%feature("docstring") gdcm::Segment::SetSegmentAlgorithmName "void +gdcm::Segment::SetSegmentAlgorithmName(const char *name) "; + +%feature("docstring") gdcm::Segment::SetSegmentAlgorithmType "void +gdcm::Segment::SetSegmentAlgorithmType(ALGOType type) "; + +%feature("docstring") gdcm::Segment::SetSegmentAlgorithmType "void +gdcm::Segment::SetSegmentAlgorithmType(const char *typeStr) "; + +%feature("docstring") gdcm::Segment::SetSegmentDescription "void +gdcm::Segment::SetSegmentDescription(const char *description) "; + +%feature("docstring") gdcm::Segment::SetSegmentLabel "void +gdcm::Segment::SetSegmentLabel(const char *label) "; + +%feature("docstring") gdcm::Segment::SetSegmentNumber "void +gdcm::Segment::SetSegmentNumber(const unsigned short num) "; + +%feature("docstring") gdcm::Segment::SetSurfaceCount "void +gdcm::Segment::SetSurfaceCount(const unsigned long nb) "; + + +// File: classgdcm_1_1SegmentedPaletteColorLookupTable.xml +%feature("docstring") gdcm::SegmentedPaletteColorLookupTable " + +SegmentedPaletteColorLookupTable class. + +C++ includes: gdcmSegmentedPaletteColorLookupTable.h "; + +%feature("docstring") +gdcm::SegmentedPaletteColorLookupTable::SegmentedPaletteColorLookupTable +"gdcm::SegmentedPaletteColorLookupTable::SegmentedPaletteColorLookupTable() +"; + +%feature("docstring") +gdcm::SegmentedPaletteColorLookupTable::~SegmentedPaletteColorLookupTable +"gdcm::SegmentedPaletteColorLookupTable::~SegmentedPaletteColorLookupTable() +"; + +%feature("docstring") gdcm::SegmentedPaletteColorLookupTable::Print "void gdcm::SegmentedPaletteColorLookupTable::Print(std::ostream &) +const "; + +%feature("docstring") gdcm::SegmentedPaletteColorLookupTable::SetLUT +"void gdcm::SegmentedPaletteColorLookupTable::SetLUT(LookupTableType +type, const unsigned char *array, unsigned int length) + +Initialize a SegmentedPaletteColorLookupTable. "; + + +// File: classgdcm_1_1SegmentReader.xml +%feature("docstring") gdcm::SegmentReader " + +This class defines a segment reader. It reads attributes of group +0x0062. + +See: PS 3.3 C.8.20.2 and C.8.23 + +C++ includes: gdcmSegmentReader.h "; + +%feature("docstring") gdcm::SegmentReader::SegmentReader "gdcm::SegmentReader::SegmentReader() "; + +%feature("docstring") gdcm::SegmentReader::~SegmentReader "virtual +gdcm::SegmentReader::~SegmentReader() "; + +%feature("docstring") gdcm::SegmentReader::GetSegments "const +SegmentVector gdcm::SegmentReader::GetSegments() const "; + +%feature("docstring") gdcm::SegmentReader::GetSegments "SegmentVector gdcm::SegmentReader::GetSegments() "; + +%feature("docstring") gdcm::SegmentReader::Read "virtual bool +gdcm::SegmentReader::Read() + +Read. "; + + +// File: classgdcm_1_1SegmentWriter.xml +%feature("docstring") gdcm::SegmentWriter " + +This class defines a segment writer. It writes attributes of group +0x0062. + +See: PS 3.3 C.8.20.2 and C.8.23 + +C++ includes: gdcmSegmentWriter.h "; + +%feature("docstring") gdcm::SegmentWriter::SegmentWriter "gdcm::SegmentWriter::SegmentWriter() "; + +%feature("docstring") gdcm::SegmentWriter::~SegmentWriter "virtual +gdcm::SegmentWriter::~SegmentWriter() "; + +%feature("docstring") gdcm::SegmentWriter::AddSegment "void +gdcm::SegmentWriter::AddSegment(SmartPointer< Segment > segment) "; + +%feature("docstring") gdcm::SegmentWriter::GetNumberOfSegments "unsigned int gdcm::SegmentWriter::GetNumberOfSegments() const "; + +%feature("docstring") gdcm::SegmentWriter::GetSegment "SmartPointer< +Segment > gdcm::SegmentWriter::GetSegment(const unsigned int idx=0) +const "; + +%feature("docstring") gdcm::SegmentWriter::GetSegments "SegmentVector& gdcm::SegmentWriter::GetSegments() "; + +%feature("docstring") gdcm::SegmentWriter::GetSegments "const +SegmentVector& gdcm::SegmentWriter::GetSegments() const "; + +%feature("docstring") gdcm::SegmentWriter::SetNumberOfSegments "void +gdcm::SegmentWriter::SetNumberOfSegments(const unsigned int size) "; + +%feature("docstring") gdcm::SegmentWriter::SetSegments "void +gdcm::SegmentWriter::SetSegments(SegmentVector &segments) "; + +%feature("docstring") gdcm::SegmentWriter::Write "bool +gdcm::SegmentWriter::Write() + +Write. "; + + +// File: classgdcm_1_1SequenceOfFragments.xml +%feature("docstring") gdcm::SequenceOfFragments " + +Class to represent a Sequence Of Fragments. + +Todo I do not enforce that Sequence of Fragments ends with a SQ end +del + +C++ includes: gdcmSequenceOfFragments.h "; + +%feature("docstring") gdcm::SequenceOfFragments::SequenceOfFragments +"gdcm::SequenceOfFragments::SequenceOfFragments() + +constructor (UndefinedLength by default) "; + +%feature("docstring") gdcm::SequenceOfFragments::AddFragment "void +gdcm::SequenceOfFragments::AddFragment(Fragment const &item) + +Appends a Fragment to the already added ones. "; + +%feature("docstring") gdcm::SequenceOfFragments::Begin "Iterator +gdcm::SequenceOfFragments::Begin() "; + +%feature("docstring") gdcm::SequenceOfFragments::Begin "ConstIterator gdcm::SequenceOfFragments::Begin() const "; + +%feature("docstring") gdcm::SequenceOfFragments::Clear "void +gdcm::SequenceOfFragments::Clear() + +Clear. "; + +%feature("docstring") gdcm::SequenceOfFragments::ComputeByteLength "unsigned long gdcm::SequenceOfFragments::ComputeByteLength() const "; + +%feature("docstring") gdcm::SequenceOfFragments::ComputeLength "VL +gdcm::SequenceOfFragments::ComputeLength() const "; + +%feature("docstring") gdcm::SequenceOfFragments::End "ConstIterator +gdcm::SequenceOfFragments::End() const "; + +%feature("docstring") gdcm::SequenceOfFragments::End "Iterator +gdcm::SequenceOfFragments::End() "; + +%feature("docstring") gdcm::SequenceOfFragments::GetBuffer "bool +gdcm::SequenceOfFragments::GetBuffer(char *buffer, unsigned long +length) const "; + +%feature("docstring") gdcm::SequenceOfFragments::GetFragBuffer "bool +gdcm::SequenceOfFragments::GetFragBuffer(unsigned int fragNb, char +*buffer, unsigned long &length) const "; + +%feature("docstring") gdcm::SequenceOfFragments::GetFragment "const +Fragment& gdcm::SequenceOfFragments::GetFragment(SizeType num) const +"; + +%feature("docstring") gdcm::SequenceOfFragments::GetLength "VL +gdcm::SequenceOfFragments::GetLength() const + +Returns the SQ length, as read from disk. "; + +%feature("docstring") gdcm::SequenceOfFragments::GetNumberOfFragments +"SizeType gdcm::SequenceOfFragments::GetNumberOfFragments() const "; + +%feature("docstring") gdcm::SequenceOfFragments::GetTable "const +BasicOffsetTable& gdcm::SequenceOfFragments::GetTable() const "; + +%feature("docstring") gdcm::SequenceOfFragments::GetTable "BasicOffsetTable& gdcm::SequenceOfFragments::GetTable() "; + +%feature("docstring") gdcm::SequenceOfFragments::Print "void +gdcm::SequenceOfFragments::Print(std::ostream &os) const "; + +%feature("docstring") gdcm::SequenceOfFragments::Read "std::istream& +gdcm::SequenceOfFragments::Read(std::istream &is) "; + +%feature("docstring") gdcm::SequenceOfFragments::ReadPreValue "std::istream& gdcm::SequenceOfFragments::ReadPreValue(std::istream +&is) "; + +%feature("docstring") gdcm::SequenceOfFragments::ReadValue "std::istream& gdcm::SequenceOfFragments::ReadValue(std::istream &is) +"; + +%feature("docstring") gdcm::SequenceOfFragments::SetLength "void +gdcm::SequenceOfFragments::SetLength(VL length) + +Sets the actual SQ length. "; + +%feature("docstring") gdcm::SequenceOfFragments::Write "std::ostream +const& gdcm::SequenceOfFragments::Write(std::ostream &os) const "; + +%feature("docstring") gdcm::SequenceOfFragments::WriteBuffer "bool +gdcm::SequenceOfFragments::WriteBuffer(std::ostream &os) const "; + + +// File: classgdcm_1_1SequenceOfItems.xml +%feature("docstring") gdcm::SequenceOfItems " + +Class to represent a Sequence Of Items (value representation : SQ) a +Value Representation for Data Elements that contains a sequence of +Data Sets. + +Sequence of Item allows for Nested Data Sets. + +See PS 3.5, 7.4.6 Data Element Type Within a Sequence SEQUENCE OF +ITEMS (VALUE REPRESENTATION SQ) A Value Representation for Data +Elements that contain a sequence of Data Sets. Sequence of Items +allows for Nested Data Sets. + +C++ includes: gdcmSequenceOfItems.h "; + +%feature("docstring") gdcm::SequenceOfItems::SequenceOfItems "gdcm::SequenceOfItems::SequenceOfItems() + +constructor (UndefinedLength by default) "; + +%feature("docstring") gdcm::SequenceOfItems::AddItem "void +gdcm::SequenceOfItems::AddItem(Item const &item) + +Appends an Item to the already added ones. "; + +%feature("docstring") gdcm::SequenceOfItems::Begin "Iterator +gdcm::SequenceOfItems::Begin() "; + +%feature("docstring") gdcm::SequenceOfItems::Begin "ConstIterator +gdcm::SequenceOfItems::Begin() const "; + +%feature("docstring") gdcm::SequenceOfItems::Clear "void +gdcm::SequenceOfItems::Clear() "; + +%feature("docstring") gdcm::SequenceOfItems::ComputeLength "VL +gdcm::SequenceOfItems::ComputeLength() const "; + +%feature("docstring") gdcm::SequenceOfItems::End "ConstIterator +gdcm::SequenceOfItems::End() const "; + +%feature("docstring") gdcm::SequenceOfItems::End "Iterator +gdcm::SequenceOfItems::End() "; + +%feature("docstring") gdcm::SequenceOfItems::FindDataElement "bool +gdcm::SequenceOfItems::FindDataElement(const Tag &t) const "; + +%feature("docstring") gdcm::SequenceOfItems::GetItem "Item& +gdcm::SequenceOfItems::GetItem(SizeType position) "; + +%feature("docstring") gdcm::SequenceOfItems::GetItem "const Item& +gdcm::SequenceOfItems::GetItem(SizeType position) const "; + +%feature("docstring") gdcm::SequenceOfItems::GetLength "VL +gdcm::SequenceOfItems::GetLength() const + +Returns the SQ length, as read from disk. "; + +%feature("docstring") gdcm::SequenceOfItems::GetNumberOfItems "SizeType gdcm::SequenceOfItems::GetNumberOfItems() const "; + +%feature("docstring") gdcm::SequenceOfItems::IsUndefinedLength "bool +gdcm::SequenceOfItems::IsUndefinedLength() const + +return if Value Length if of undefined length "; + +%feature("docstring") gdcm::SequenceOfItems::Print "void +gdcm::SequenceOfItems::Print(std::ostream &os) const "; + +%feature("docstring") gdcm::SequenceOfItems::Read "std::istream& +gdcm::SequenceOfItems::Read(std::istream &is) "; + +%feature("docstring") gdcm::SequenceOfItems::SetLength "void +gdcm::SequenceOfItems::SetLength(VL length) + +Sets the actual SQ length. "; + +%feature("docstring") gdcm::SequenceOfItems::SetLengthToUndefined "void gdcm::SequenceOfItems::SetLengthToUndefined() + +Properly set the Sequence of Item to be undefined length. "; + +%feature("docstring") gdcm::SequenceOfItems::SetNumberOfItems "void +gdcm::SequenceOfItems::SetNumberOfItems(SizeType n) "; + +%feature("docstring") gdcm::SequenceOfItems::Write "std::ostream +const& gdcm::SequenceOfItems::Write(std::ostream &os) const "; + + +// File: classgdcm_1_1SerieHelper.xml +%feature("docstring") gdcm::SerieHelper " + +SerieHelper DO NOT USE this class, it is only a temporary solution for +ITK migration from GDCM 1.x to GDCM 2.x It will disapear soon, you've +been warned. + +Instead see gdcm::ImageHelper or gdcm::IPPSorter + +C++ includes: gdcmSerieHelper.h "; + +%feature("docstring") gdcm::SerieHelper::SerieHelper "gdcm::SerieHelper::SerieHelper() "; + +%feature("docstring") gdcm::SerieHelper::~SerieHelper "gdcm::SerieHelper::~SerieHelper() "; + +%feature("docstring") gdcm::SerieHelper::AddRestriction "void +gdcm::SerieHelper::AddRestriction(const std::string &tag) "; + +%feature("docstring") gdcm::SerieHelper::AddRestriction "void +gdcm::SerieHelper::AddRestriction(uint16_t group, uint16_t elem, +std::string const &value, int op) "; + +%feature("docstring") gdcm::SerieHelper::Clear "void +gdcm::SerieHelper::Clear() "; + +%feature("docstring") +gdcm::SerieHelper::CreateDefaultUniqueSeriesIdentifier "void +gdcm::SerieHelper::CreateDefaultUniqueSeriesIdentifier() "; + +%feature("docstring") gdcm::SerieHelper::CreateUniqueSeriesIdentifier +"std::string gdcm::SerieHelper::CreateUniqueSeriesIdentifier(File +*inFile) "; + +%feature("docstring") +gdcm::SerieHelper::GetFirstSingleSerieUIDFileSet "FileList* +gdcm::SerieHelper::GetFirstSingleSerieUIDFileSet() "; + +%feature("docstring") gdcm::SerieHelper::GetNextSingleSerieUIDFileSet +"FileList* gdcm::SerieHelper::GetNextSingleSerieUIDFileSet() "; + +%feature("docstring") gdcm::SerieHelper::OrderFileList "void +gdcm::SerieHelper::OrderFileList(FileList *fileSet) "; + +%feature("docstring") gdcm::SerieHelper::SetDirectory "void +gdcm::SerieHelper::SetDirectory(std::string const &dir, bool +recursive=false) "; + +%feature("docstring") gdcm::SerieHelper::SetLoadMode "void +gdcm::SerieHelper::SetLoadMode(int) "; + +%feature("docstring") gdcm::SerieHelper::SetUseSeriesDetails "void +gdcm::SerieHelper::SetUseSeriesDetails(bool useSeriesDetails) "; + + +// File: classgdcm_1_1Series.xml +%feature("docstring") gdcm::Series " + +Series. + +C++ includes: gdcmSeries.h "; + +%feature("docstring") gdcm::Series::Series "gdcm::Series::Series() +"; + + +// File: classgdcm_1_1network_1_1ServiceClassApplicationInformation.xml +%feature("docstring") +gdcm::network::ServiceClassApplicationInformation " + +PS 3.4 Table B.3-1 SERVICE-CLASS-APPLICATION-INFORMATION (A-ASSOCIATE- +RQ) + +C++ includes: gdcmServiceClassApplicationInformation.h "; + +%feature("docstring") +gdcm::network::ServiceClassApplicationInformation::ServiceClassApplicationInformation +"gdcm::network::ServiceClassApplicationInformation::ServiceClassApplicationInformation() +"; + +%feature("docstring") +gdcm::network::ServiceClassApplicationInformation::Print "void +gdcm::network::ServiceClassApplicationInformation::Print(std::ostream +&os) const "; + +%feature("docstring") +gdcm::network::ServiceClassApplicationInformation::Read "std::istream& +gdcm::network::ServiceClassApplicationInformation::Read(std::istream +&is) "; + +%feature("docstring") +gdcm::network::ServiceClassApplicationInformation::SetTuple "void +gdcm::network::ServiceClassApplicationInformation::SetTuple(uint8_t +levelofsupport, uint8_t levelofdigitalsig, uint8_t elementcoercion) "; + +%feature("docstring") +gdcm::network::ServiceClassApplicationInformation::Size "size_t +gdcm::network::ServiceClassApplicationInformation::Size() const "; + +%feature("docstring") +gdcm::network::ServiceClassApplicationInformation::Write "const +std::ostream& +gdcm::network::ServiceClassApplicationInformation::Write(std::ostream +&os) const "; + + +// File: classgdcm_1_1ServiceClassUser.xml +%feature("docstring") gdcm::ServiceClassUser " + +ServiceClassUser. + +C++ includes: gdcmServiceClassUser.h "; + +%feature("docstring") gdcm::ServiceClassUser::ServiceClassUser "gdcm::ServiceClassUser::ServiceClassUser() + +Construct a SCU with default: hostname = localhost + +port = 104 "; + +%feature("docstring") gdcm::ServiceClassUser::~ServiceClassUser "gdcm::ServiceClassUser::~ServiceClassUser() "; + +%feature("docstring") gdcm::ServiceClassUser::GetAETitle "const +char* gdcm::ServiceClassUser::GetAETitle() const "; + +%feature("docstring") gdcm::ServiceClassUser::GetCalledAETitle "const char* gdcm::ServiceClassUser::GetCalledAETitle() const "; + +%feature("docstring") gdcm::ServiceClassUser::GetTimeout "double +gdcm::ServiceClassUser::GetTimeout() const "; + +%feature("docstring") gdcm::ServiceClassUser::InitializeConnection "bool gdcm::ServiceClassUser::InitializeConnection() + +Will try to connect This will setup the actual timeout used during the +whole connection time. Need to call SetTimeout first "; + +%feature("docstring") +gdcm::ServiceClassUser::IsPresentationContextAccepted "bool +gdcm::ServiceClassUser::IsPresentationContextAccepted(const +PresentationContext &pc) const + +Return if the passed in presentation was accepted during association +negotiation. "; + +%feature("docstring") gdcm::ServiceClassUser::SendEcho "bool +gdcm::ServiceClassUser::SendEcho() + +C-ECHO. "; + +%feature("docstring") gdcm::ServiceClassUser::SendFind "bool +gdcm::ServiceClassUser::SendFind(const BaseRootQuery *query, +std::vector< DataSet > &retDatasets) + +C-FIND a query, return result are in retDatasets. "; + +%feature("docstring") gdcm::ServiceClassUser::SendMove "bool +gdcm::ServiceClassUser::SendMove(const BaseRootQuery *query, const +char *outputdir) + +Execute a C-MOVE, based on query, return files are written in +outputdir. "; + +%feature("docstring") gdcm::ServiceClassUser::SendMove "bool +gdcm::ServiceClassUser::SendMove(const BaseRootQuery *query, +std::vector< DataSet > &retDatasets) + +Execute a C-MOVE, based on query, returned dataset are Implicit. "; + +%feature("docstring") gdcm::ServiceClassUser::SendMove "bool +gdcm::ServiceClassUser::SendMove(const BaseRootQuery *query, +std::vector< File > &retFile) + +Execute a C-MOVE, based on query, returned Files are stored in vector. +"; + +%feature("docstring") gdcm::ServiceClassUser::SendStore "bool +gdcm::ServiceClassUser::SendStore(const char *filename) + +Execute a C-STORE on file on disk, named filename. "; + +%feature("docstring") gdcm::ServiceClassUser::SendStore "bool +gdcm::ServiceClassUser::SendStore(File const &file) + +Execute a C-STORE on a File, the transfer syntax used for the query is +based on the file. "; + +%feature("docstring") gdcm::ServiceClassUser::SendStore "bool +gdcm::ServiceClassUser::SendStore(DataSet const &ds) + +Execute a C-STORE on a DataSet, the transfer syntax used will be +Implicit. "; + +%feature("docstring") gdcm::ServiceClassUser::SetAETitle "void +gdcm::ServiceClassUser::SetAETitle(const char *aetitle) + +set calling ae title "; + +%feature("docstring") gdcm::ServiceClassUser::SetCalledAETitle "void +gdcm::ServiceClassUser::SetCalledAETitle(const char *aetitle) + +set called ae title "; + +%feature("docstring") gdcm::ServiceClassUser::SetHostname "void +gdcm::ServiceClassUser::SetHostname(const char *hostname) + +Set the name of the called hostname (hostname or IP address). "; + +%feature("docstring") gdcm::ServiceClassUser::SetPort "void +gdcm::ServiceClassUser::SetPort(uint16_t port) + +Set port of remote host (called application). "; + +%feature("docstring") gdcm::ServiceClassUser::SetPortSCP "void +gdcm::ServiceClassUser::SetPortSCP(uint16_t portscp) + +Set the port for any incoming C-STORE-SCP operation (typically in a +return of C-MOVE). "; + +%feature("docstring") gdcm::ServiceClassUser::SetPresentationContexts +"void gdcm::ServiceClassUser::SetPresentationContexts(std::vector< +PresentationContext > const &pcs) + +Set the Presentation Context used for the Association. "; + +%feature("docstring") gdcm::ServiceClassUser::SetTimeout "void +gdcm::ServiceClassUser::SetTimeout(double t) + +set/get Timeout "; + +%feature("docstring") gdcm::ServiceClassUser::StartAssociation "bool +gdcm::ServiceClassUser::StartAssociation() + +Start the association. Need to call SetPresentationContexts before. "; + +%feature("docstring") gdcm::ServiceClassUser::StopAssociation "bool +gdcm::ServiceClassUser::StopAssociation() + +Stop the running association. "; + + +// File: classstd_1_1set.xml +%feature("docstring") std::set " + +STL class. "; + + +// File: classgdcm_1_1SHA1.xml +%feature("docstring") gdcm::SHA1 " + +Class for SHA1. + +WARNING: this class is able to pick from one implementation: 1. the +one from OpenSSL (when GDCM_USE_SYSTEM_OPENSSL is turned ON) + +In all other cases it will return an error + +C++ includes: gdcmSHA1.h "; + +%feature("docstring") gdcm::SHA1::SHA1 "gdcm::SHA1::SHA1() "; + +%feature("docstring") gdcm::SHA1::~SHA1 "gdcm::SHA1::~SHA1() "; + + +// File: classgdcm_1_1SimpleMemberCommand.xml +%feature("docstring") gdcm::SimpleMemberCommand " + +Command subclass that calls a pointer to a member function. + +SimpleMemberCommand calls a pointer to a member function with no +arguments. + +C++ includes: gdcmCommand.h "; + +%feature("docstring") gdcm::SimpleMemberCommand::Execute "virtual +void gdcm::SimpleMemberCommand< T >::Execute(Subject *, const Event &) + +Invoke the callback function. "; + +%feature("docstring") gdcm::SimpleMemberCommand::Execute "virtual +void gdcm::SimpleMemberCommand< T >::Execute(const Subject *, const +Event &) + +Abstract method that defines the action to be taken by the command. +This variant is expected to be used when requests comes from a const +Object "; + +%feature("docstring") gdcm::SimpleMemberCommand::SetCallbackFunction +"void gdcm::SimpleMemberCommand< T >::SetCallbackFunction(T *object, +TMemberFunctionPointer memberFunction) + +Specify the callback function. "; + + +// File: classgdcm_1_1SimpleSubjectWatcher.xml +%feature("docstring") gdcm::SimpleSubjectWatcher " + +SimpleSubjectWatcher This is a typical Subject Watcher class. It will +observe all events. + +C++ includes: gdcmSimpleSubjectWatcher.h "; + +%feature("docstring") +gdcm::SimpleSubjectWatcher::SimpleSubjectWatcher "gdcm::SimpleSubjectWatcher::SimpleSubjectWatcher(Subject *s, const +char *comment=\"\") "; + +%feature("docstring") +gdcm::SimpleSubjectWatcher::~SimpleSubjectWatcher "virtual +gdcm::SimpleSubjectWatcher::~SimpleSubjectWatcher() "; + + +// File: classgdcm_1_1SmartPointer.xml +%feature("docstring") gdcm::SmartPointer " + +Class for Smart Pointer. + +Will only work for subclass of gdcm::Object See tr1/shared_ptr for a +more general approach (not invasive) include { +shared_ptr b(new Bla); } Class partly based on post by Bill +Hubauer:http://groups.google.com/group/comp.lang.c++/msg/173ddc38a827a930 + +See: http://www.davethehat.com/articles/smartp.htm and +itk::SmartPointer + +C++ includes: gdcmSmartPointer.h "; + +%feature("docstring") gdcm::SmartPointer::SmartPointer "gdcm::SmartPointer< ObjectType >::SmartPointer() "; + +%feature("docstring") gdcm::SmartPointer::SmartPointer "gdcm::SmartPointer< ObjectType >::SmartPointer(const SmartPointer< +ObjectType > &p) "; + +%feature("docstring") gdcm::SmartPointer::SmartPointer "gdcm::SmartPointer< ObjectType >::SmartPointer(ObjectType const &p) "; + +%feature("docstring") gdcm::SmartPointer::SmartPointer "gdcm::SmartPointer< ObjectType >::SmartPointer(ObjectType *p) "; + +%feature("docstring") gdcm::SmartPointer::~SmartPointer "gdcm::SmartPointer< ObjectType >::~SmartPointer() "; + +%feature("docstring") gdcm::SmartPointer::GetPointer "ObjectType* +gdcm::SmartPointer< ObjectType >::GetPointer() const + +Explicit function to retrieve the pointer. "; + + +// File: classgdcm_1_1network_1_1SOPClassExtendedNegociationSub.xml +%feature("docstring") gdcm::network::SOPClassExtendedNegociationSub " + +SOPClassExtendedNegociationSub PS 3.7 Table D.3-11 SOP CLASS EXTENDED +NEGOTIATION SUB-ITEM FIELDS (A-ASSOCIATE-RQ and A-ASSOCIATE-AC). + +C++ includes: gdcmSOPClassExtendedNegociationSub.h "; + +%feature("docstring") +gdcm::network::SOPClassExtendedNegociationSub::SOPClassExtendedNegociationSub +"gdcm::network::SOPClassExtendedNegociationSub::SOPClassExtendedNegociationSub() +"; + +%feature("docstring") +gdcm::network::SOPClassExtendedNegociationSub::Print "void +gdcm::network::SOPClassExtendedNegociationSub::Print(std::ostream &os) +const "; + +%feature("docstring") +gdcm::network::SOPClassExtendedNegociationSub::Read "std::istream& +gdcm::network::SOPClassExtendedNegociationSub::Read(std::istream &is) +"; + +%feature("docstring") +gdcm::network::SOPClassExtendedNegociationSub::SetTuple "void +gdcm::network::SOPClassExtendedNegociationSub::SetTuple(const char +*uid, uint8_t levelofsupport=3, uint8_t levelofdigitalsig=0, uint8_t +elementcoercion=2) "; + +%feature("docstring") +gdcm::network::SOPClassExtendedNegociationSub::Size "size_t +gdcm::network::SOPClassExtendedNegociationSub::Size() const "; + +%feature("docstring") +gdcm::network::SOPClassExtendedNegociationSub::Write "const +std::ostream& +gdcm::network::SOPClassExtendedNegociationSub::Write(std::ostream &os) +const "; + + +// File: classgdcm_1_1SOPClassUIDToIOD.xml +%feature("docstring") gdcm::SOPClassUIDToIOD " + +Class convert a class SOP Class UID into IOD. + +Reference PS 3.4 Table B.5-1 STANDARD SOP CLASSES + +C++ includes: gdcmSOPClassUIDToIOD.h "; + + +// File: classgdcm_1_1Sorter.xml +%feature("docstring") gdcm::Sorter " + +Sorter General class to do sorting using a custom function You simply +need to provide a function of type: Sorter::SortFunction. + +WARNING: implementation details. For now there is no cache mechanism. +Which means that everytime you call Sort, all files specified as input +paramater are *read* + +See: Scanner + +C++ includes: gdcmSorter.h "; + +%feature("docstring") gdcm::Sorter::Sorter "gdcm::Sorter::Sorter() +"; + +%feature("docstring") gdcm::Sorter::~Sorter "virtual +gdcm::Sorter::~Sorter() "; + +%feature("docstring") gdcm::Sorter::AddSelect "bool +gdcm::Sorter::AddSelect(Tag const &tag, const char *value) + +UNSUPPORTED FOR NOW. "; + +%feature("docstring") gdcm::Sorter::GetFilenames "const +std::vector& gdcm::Sorter::GetFilenames() const + +Return the list of filenames as sorted by the specific algorithm used. +Empty by default (before Sort() is called) "; + +%feature("docstring") gdcm::Sorter::Print "void +gdcm::Sorter::Print(std::ostream &os) const + +Print. "; + +%feature("docstring") gdcm::Sorter::SetSortFunction "void +gdcm::Sorter::SetSortFunction(SortFunction f) "; + +%feature("docstring") gdcm::Sorter::Sort "virtual bool +gdcm::Sorter::Sort(std::vector< std::string > const &filenames) + +Typically the output of gdcm::Directory::GetFilenames(). "; + +%feature("docstring") gdcm::Sorter::StableSort "virtual bool +gdcm::Sorter::StableSort(std::vector< std::string > const &filenames) +"; + + +// File: classgdcm_1_1Spacing.xml +%feature("docstring") gdcm::Spacing " + +Class for Spacing. + +It all began with a mail to WG6: + +Subject: Imager Pixel Spacing vs Pixel Spacing Body: [Apologies for +the duplicate post, namely to David Clunie & OFFIS team] + +I have been trying to understand CP-586 in the following two cases: + +On the one hand: DISCIMG/IMAGES/CRIMAGE taken +fromhttp://dclunie.com/images/pixelspacingtestimages.zip + +And on the other hand: +http://gdcm.sourceforge.net/thingies/cr_pixelspacing.dcm + +If I understand correctly the CP, one is required to use Pixel Spacing +for measurement ('true size' print) instead of Imager Pixel Spacing, +since the two attributes are present and Pixel Spacing is different +from Imager Pixel Spacing. + +If this is correct, then the test data DISCIMG/IMAGES/CRIMAGE is +incorrect. If this is incorrect (ie. I need to use Imager Pixel +Spacing), then the display of cr_pixelspacing.dcm for measurement will +be incorrect. + +Could someone please let me know what am I missing here? I could not +find any information in any header that would allow me to +differentiate those. + +Thank you for your time, + +Ref:http://lists.nema.org/scripts/lyris.pl?sub=488573&id=400720477 See +PS 3.3-2008, Table C.7-11b IMAGE PIXEL MACRO ATTRIBUTES + +Ratio of the vertical size and horizontal size of the pixels in the +image specified by a pair of integer values where the first value is +the vertical pixel size, and the second value is the horizontal pixel +size. Required if the aspect ratio values do not have a ratio of 1:1 +and the physical pixel spacing is not specified by Pixel Spacing +(0028,0030), or Imager Pixel Spacing (0018,1164) or Nominal Scanned +Pixel Spacing (0018,2010), either for the entire Image or per-frame in +a Functional Group Macro. See C.7.6.3.1.7. + +PS 3.3-2008 10.7.1.3 Pixel Spacing Value Order and Valid Values All +pixel spacing related attributes shall have non-zero values, except +when there is only a single row or column or pixel of data present, in +which case the corresponding value may be zero. + +Ref:http://gdcm.sourceforge.net/wiki/index.php/Imager_Pixel_Spacing + +C++ includes: gdcmSpacing.h "; + +%feature("docstring") gdcm::Spacing::Spacing "gdcm::Spacing::Spacing() "; + +%feature("docstring") gdcm::Spacing::~Spacing "gdcm::Spacing::~Spacing() "; + + +// File: classgdcm_1_1Spectroscopy.xml +%feature("docstring") gdcm::Spectroscopy " + +Spectroscopy class. + +C++ includes: gdcmSpectroscopy.h "; + +%feature("docstring") gdcm::Spectroscopy::Spectroscopy "gdcm::Spectroscopy::Spectroscopy() "; + + +// File: classgdcm_1_1SplitMosaicFilter.xml +%feature("docstring") gdcm::SplitMosaicFilter " + +SplitMosaicFilter class Class to reshuffle bytes for a SIEMENS Mosaic +image Siemens CSA Image Header CSA:= Common Siemens Architecture, +sometimes also known as Common syngo Architecture. + +C++ includes: gdcmSplitMosaicFilter.h "; + +%feature("docstring") gdcm::SplitMosaicFilter::SplitMosaicFilter "gdcm::SplitMosaicFilter::SplitMosaicFilter() "; + +%feature("docstring") gdcm::SplitMosaicFilter::~SplitMosaicFilter "gdcm::SplitMosaicFilter::~SplitMosaicFilter() "; + +%feature("docstring") +gdcm::SplitMosaicFilter::ComputeMOSAICDimensions "bool +gdcm::SplitMosaicFilter::ComputeMOSAICDimensions(unsigned int dims[3]) + +Compute the new dimensions according to private information stored in +the MOSAIC header. "; + +%feature("docstring") gdcm::SplitMosaicFilter::GetFile "File& +gdcm::SplitMosaicFilter::GetFile() "; + +%feature("docstring") gdcm::SplitMosaicFilter::GetFile "const File& +gdcm::SplitMosaicFilter::GetFile() const "; + +%feature("docstring") gdcm::SplitMosaicFilter::GetImage "Image& +gdcm::SplitMosaicFilter::GetImage() "; + +%feature("docstring") gdcm::SplitMosaicFilter::GetImage "const +Image& gdcm::SplitMosaicFilter::GetImage() const "; + +%feature("docstring") gdcm::SplitMosaicFilter::SetFile "void +gdcm::SplitMosaicFilter::SetFile(const File &f) "; + +%feature("docstring") gdcm::SplitMosaicFilter::SetImage "void +gdcm::SplitMosaicFilter::SetImage(const Image &image) "; + +%feature("docstring") gdcm::SplitMosaicFilter::Split "bool +gdcm::SplitMosaicFilter::Split() + +Split the SIEMENS MOSAIC image. "; + + +// File: classstd_1_1stack.xml +%feature("docstring") std::stack " + +STL class. "; + + +// File: classgdcm_1_1StartEvent.xml +%feature("docstring") gdcm::StartEvent "C++ includes: gdcmEvent.h "; + + +// File: structgdcm_1_1static__assert__test.xml +%feature("docstring") gdcm::static_assert_test "C++ includes: +gdcmStaticAssert.h "; + + +// File: structgdcm_1_1STATIC__ASSERTION__FAILURE_3_01true_01_4.xml +%feature("docstring") gdcm::STATIC_ASSERTION_FAILURE< true > " C++ +includes: gdcmStaticAssert.h "; + + +// File: classgdcm_1_1StreamImageReader.xml +%feature("docstring") gdcm::StreamImageReader " + +StreamImageReader. + +its role is to convert the DICOM DataSet into a gdcm::Image +representation via an ITK streaming (ie, multithreaded) interface +Image is different from Pixmap has it has a position and a direction +in Space. Currently, this class is thread safe in that it can read a +single extent in a single thread. Multiple versions can be used for +multiple extents/threads. + +See: Image + +C++ includes: gdcmStreamImageReader.h "; + +%feature("docstring") gdcm::StreamImageReader::StreamImageReader "gdcm::StreamImageReader::StreamImageReader() "; + +%feature("docstring") gdcm::StreamImageReader::~StreamImageReader "virtual gdcm::StreamImageReader::~StreamImageReader() "; + +%feature("docstring") gdcm::StreamImageReader::CanReadImage "bool +gdcm::StreamImageReader::CanReadImage() const + +Only RAW images are currently readable by the stream reader. As more +streaming codecs are added, then this function will be updated to +reflect those changes. Calling this function prior to reading will +ensure that only streamable files are streamed. Make sure to call +ReadImageInformation prior to calling this function. "; + +%feature("docstring") gdcm::StreamImageReader::DefinePixelExtent "void gdcm::StreamImageReader::DefinePixelExtent(uint16_t inXMin, +uint16_t inXMax, uint16_t inYMin, uint16_t inYMax, uint16_t inZMin=0, +uint16_t inZMax=1) + +Defines an image extent for the Read function. DICOM states that an +image can have no more than 2^16 pixels per edge (as of 2009) In this +case, the pixel extents ignore the direction cosines entirely, and +assumes that the origin of the image is at location 0,0 (regardless of +the definition in space per the tags). So, if the first 100 pixels of +the first row are to be read in, this function should be called with +DefinePixelExtent(0, 100, 0, 1), regardless of pixel size or +orientation. "; + +%feature("docstring") +gdcm::StreamImageReader::DefineProperBufferLength "uint32_t +gdcm::StreamImageReader::DefineProperBufferLength() const + +Paying attention to the pixel format and so forth, define the proper +buffer length for the user. The return amount is in bytes. Call this +function to determine the size of the char* buffer that will need to +be passed in to ReadImageSubregion(). If the return is 0, then that +means that the pixel extent was not defined prior "; + +%feature("docstring") +gdcm::StreamImageReader::GetDimensionsValueForResolution "std::vector +gdcm::StreamImageReader::GetDimensionsValueForResolution(unsigned int) +"; + +%feature("docstring") gdcm::StreamImageReader::GetFile "File const& +gdcm::StreamImageReader::GetFile() const + +Returns the dataset read by ReadImageInformation Couple this with the +ImageHelper to get statistics about the image, like pixel extent, to +be able to initialize buffers for reading "; + +%feature("docstring") gdcm::StreamImageReader::Read "bool +gdcm::StreamImageReader::Read(char *inReadBuffer, const std::size_t +&inBufferLength) + +Read the DICOM image. There are three reasons for failure: 1. The +extent is not set 2. the conversion from char* to std::ostream +(internally) fails 3. the given buffer isn't large enough to +accommodate the desired pixel extent. This method has been implemented +to look similar to the metaimageio in itk MUST have an extent defined, +or else Read will return false. If no particular extent is required, +use ImageReader instead. "; + +%feature("docstring") gdcm::StreamImageReader::ReadImageInformation "virtual bool gdcm::StreamImageReader::ReadImageInformation() + +Set the spacing and dimension information for the set filename. +returns false if the file is not initialized or not an image, with the +pixel (7fe0,0010) tag. "; + +%feature("docstring") gdcm::StreamImageReader::SetFileName "void +gdcm::StreamImageReader::SetFileName(const char *inFileName) + +One of either SetFileName or SetStream must be called prior to any +other functions. These initialize an internal Reader class to be able +to get non-pixel image information. "; + +%feature("docstring") gdcm::StreamImageReader::SetStream "void +gdcm::StreamImageReader::SetStream(std::istream &inStream) "; + + +// File: classgdcm_1_1StreamImageWriter.xml +%feature("docstring") gdcm::StreamImageWriter " + +StreamImageReader. + +its role is to convert the DICOM DataSet into a gdcm::Image +representation via an ITK streaming (ie, multithreaded) interface +Image is different from Pixmap has it has a position and a direction +in Space. Currently, this class is threadsafe in that it can read a +single extent in a single thread. Multiple versions can be used for +multiple extents/threads. + +See: Image + +C++ includes: gdcmStreamImageWriter.h "; + +%feature("docstring") gdcm::StreamImageWriter::StreamImageWriter "gdcm::StreamImageWriter::StreamImageWriter() "; + +%feature("docstring") gdcm::StreamImageWriter::~StreamImageWriter "virtual gdcm::StreamImageWriter::~StreamImageWriter() "; + +%feature("docstring") gdcm::StreamImageWriter::CanWriteFile "bool +gdcm::StreamImageWriter::CanWriteFile() const + +This function determines if a file can even be written using the +streaming writer unlike the reader, can be called before +WriteImageInformation, but must be called after SetFile. "; + +%feature("docstring") gdcm::StreamImageWriter::DefinePixelExtent "void gdcm::StreamImageWriter::DefinePixelExtent(uint16_t inXMin, +uint16_t inXMax, uint16_t inYMin, uint16_t inYMax, uint16_t inZMin=0, +uint16_t inZMax=1) + +Defines an image extent for the Read function. DICOM states that an +image can have no more than 2^16 pixels per edge (as of 2009) In this +case, the pixel extents ignore the direction cosines entirely, and +assumes that the origin of the image is at location 0,0 (regardless of +the definition in space per the tags). So, if the first 100 pixels of +the first row are to be read in, this function should be called with +DefinePixelExtent(0, 100, 0, 1), regardless of pixel size or +orientation. 15 nov 2010: added z dimension, defaults to being 1 plane +large "; + +%feature("docstring") +gdcm::StreamImageWriter::DefineProperBufferLength "uint32_t +gdcm::StreamImageWriter::DefineProperBufferLength() + +Paying attention to the pixel format and so forth, define the proper +buffer length for the user. The return amount is in bytes. If the +return is 0, then that means that the pixel extent was not defined +prior this return is for RAW inputs which are then encoded by the +writer, but are used to ensure that the writer gets the proper buffer +size "; + +%feature("docstring") gdcm::StreamImageWriter::SetFile "void +gdcm::StreamImageWriter::SetFile(const File &inFile) + +Set the image information to be written to disk that is everything but +the pixel information: (7fe0,0010) PixelData "; + +%feature("docstring") gdcm::StreamImageWriter::SetFileName "void +gdcm::StreamImageWriter::SetFileName(const char *inFileName) + +One of either SetFileName or SetStream must be called prior to any +other functions. These initialize an internal Reader class to be able +to get non-pixel image information. "; + +%feature("docstring") gdcm::StreamImageWriter::SetStream "void +gdcm::StreamImageWriter::SetStream(std::ostream &inStream) "; + +%feature("docstring") gdcm::StreamImageWriter::Write "bool +gdcm::StreamImageWriter::Write(void *inWriteBuffer, const std::size_t +&inBufferLength) + +Read the DICOM image. There are three reasons for failure: 1. The +extent is not set 2. the conversion from void* to std::ostream +(internally) fails 3. the given buffer isn't large enough to +accomodate the desired pixel extent. This method has been implemented +to look similar to the metaimageio in itk MUST have an extent defined, +or else Read will return false. If no particular extent is required, +use ImageReader instead. "; + +%feature("docstring") gdcm::StreamImageWriter::WriteImageInformation +"virtual bool gdcm::StreamImageWriter::WriteImageInformation() + +Write the header information to disk, and a bunch of zeros for the +actual pixel information Of course, if we're doing a non-compressed +format, that works but if it's compressed, we have to force the +ordering of chunks that are written. "; + + +// File: classgdcm_1_1String.xml +%feature("docstring") gdcm::String " + +String. + +TDelimiter template parameter is used to separate multiple String (VM1 +>) TMaxLength is only a hint. Noone actually respect the max length +TPadChar is the string padding (0 or space) + +C++ includes: gdcmString.h "; + +%feature("docstring") gdcm::String::String "gdcm::String< +TDelimiter, TMaxLength, TPadChar >::String() + +String constructors. "; + +%feature("docstring") gdcm::String::String "gdcm::String< +TDelimiter, TMaxLength, TPadChar >::String(const value_type *s) "; + +%feature("docstring") gdcm::String::String "gdcm::String< +TDelimiter, TMaxLength, TPadChar >::String(const std::string &s, +size_type pos=0, size_type n=npos) "; + +%feature("docstring") gdcm::String::String "gdcm::String< +TDelimiter, TMaxLength, TPadChar >::String(const value_type *s, +size_type n) "; + +%feature("docstring") gdcm::String::IsValid "bool gdcm::String< +TDelimiter, TMaxLength, TPadChar >::IsValid() const + +return if string is valid "; + +%feature("docstring") gdcm::String::Trim "std::string gdcm::String< +TDelimiter, TMaxLength, TPadChar >::Trim() const + +Trim function is required to return a std::string object, otherwise we +could not create a gdcm::String object with an odd number of bytes... +"; + +%feature("docstring") gdcm::String::Truncate "gdcm::String gdcm::String< +TDelimiter, TMaxLength, TPadChar >::Truncate() const "; + + +// File: classstd_1_1string.xml +%feature("docstring") std::string " + +STL class. "; + + +// File: classgdcm_1_1StringFilter.xml +%feature("docstring") gdcm::StringFilter " + +StringFilter StringFilter is the class that make gdcm2.x looks more +like gdcm1 and transform the binary blob contained in a DataElement +into a string, typically this is a nice feature to have for wrapped +language. + +C++ includes: gdcmStringFilter.h "; + +%feature("docstring") gdcm::StringFilter::StringFilter "gdcm::StringFilter::StringFilter() "; + +%feature("docstring") gdcm::StringFilter::~StringFilter "gdcm::StringFilter::~StringFilter() "; + +%feature("docstring") gdcm::StringFilter::ExecuteQuery "bool +gdcm::StringFilter::ExecuteQuery(std::string const &query, std::string +&value) const + +Execute the XPATH query to find a value (as string) return false when +attribute is not found (or an error in the XPATH query) You need to +make sure that your XPATH query is syntatically correct "; + +%feature("docstring") gdcm::StringFilter::FromString "std::string +gdcm::StringFilter::FromString(const Tag &t, const char *value, size_t +len) "; + +%feature("docstring") gdcm::StringFilter::FromString "std::string +gdcm::StringFilter::FromString(const Tag &t, const char *value, VL +const &vl) + +DEPRECATED: NEVER USE IT. "; + +%feature("docstring") gdcm::StringFilter::GetFile "File& +gdcm::StringFilter::GetFile() "; + +%feature("docstring") gdcm::StringFilter::GetFile "const File& +gdcm::StringFilter::GetFile() const "; + +%feature("docstring") gdcm::StringFilter::SetDicts "void +gdcm::StringFilter::SetDicts(const Dicts &dicts) + +Allow user to pass in there own dicts. "; + +%feature("docstring") gdcm::StringFilter::SetFile "void +gdcm::StringFilter::SetFile(const File &f) + +Set/Get File. "; + +%feature("docstring") gdcm::StringFilter::ToString "std::string +gdcm::StringFilter::ToString(const Tag &t) const + +Convert to string the ByteValue contained in a DataElement. "; + +%feature("docstring") gdcm::StringFilter::ToStringPair "std::pair +gdcm::StringFilter::ToStringPair(const Tag &t) const + +Convert to string the ByteValue contained in a DataElement the +returned elements are: pair.first : the name as found in the +dictionary of DataElement pari.second : the value encoded into a +string (US,UL...) are properly converted "; + +%feature("docstring") gdcm::StringFilter::UseDictAlways "void +gdcm::StringFilter::UseDictAlways(bool) "; + + +// File: classstd_1_1stringstream.xml +%feature("docstring") std::stringstream " + +STL class. "; + + +// File: classgdcm_1_1Study.xml +%feature("docstring") gdcm::Study " + +Study. + +C++ includes: gdcmStudy.h "; + +%feature("docstring") gdcm::Study::Study "gdcm::Study::Study() "; + + +// File: classgdcm_1_1Subject.xml +%feature("docstring") gdcm::Subject " + +Subject. + +See: Command Event + +C++ includes: gdcmSubject.h "; + +%feature("docstring") gdcm::Subject::Subject "gdcm::Subject::Subject() "; + +%feature("docstring") gdcm::Subject::~Subject "gdcm::Subject::~Subject() "; + +%feature("docstring") gdcm::Subject::AddObserver "unsigned long +gdcm::Subject::AddObserver(const Event &event, Command *) const "; + +%feature("docstring") gdcm::Subject::AddObserver "unsigned long +gdcm::Subject::AddObserver(const Event &event, Command *) + +Allow people to add/remove/invoke observers (callbacks) to any GDCM +object. This is an implementation of the subject/observer design +pattern. An observer is added by specifying an event to respond to and +an gdcm::Command to execute. It returns an unsigned long tag which can +be used later to remove the event or retrieve the command. The memory +for the Command becomes the responsibility of this object, so don't +pass the same instance of a command to two different objects "; + +%feature("docstring") gdcm::Subject::GetCommand "Command* +gdcm::Subject::GetCommand(unsigned long tag) + +Get the command associated with the given tag. NOTE: This returns a +pointer to a Command, but it is safe to asign this to a +Command::Pointer. Since Command inherits from LightObject, at this +point in the code, only a pointer or a reference to the Command can be +used. "; + +%feature("docstring") gdcm::Subject::HasObserver "bool +gdcm::Subject::HasObserver(const Event &event) const + +Return true if an observer is registered for this event. "; + +%feature("docstring") gdcm::Subject::InvokeEvent "void +gdcm::Subject::InvokeEvent(const Event &) const + +Call Execute on all the Commands observing this event id. The actions +triggered by this call doesn't modify this object. "; + +%feature("docstring") gdcm::Subject::InvokeEvent "void +gdcm::Subject::InvokeEvent(const Event &) + +Call Execute on all the Commands observing this event id. "; + +%feature("docstring") gdcm::Subject::RemoveAllObservers "void +gdcm::Subject::RemoveAllObservers() + +Remove all observers . "; + +%feature("docstring") gdcm::Subject::RemoveObserver "void +gdcm::Subject::RemoveObserver(unsigned long tag) + +Remove the observer with this tag value. "; + + +// File: classgdcm_1_1Surface.xml +%feature("docstring") gdcm::Surface " + +This class defines a SURFACE IE. This members are taken from required +surface mesh module attributes. + +See: PS 3.3 A.1.2.18 , A.57 and C.27 + +C++ includes: gdcmSurface.h "; + +%feature("docstring") gdcm::Surface::Surface "gdcm::Surface::Surface() "; + +%feature("docstring") gdcm::Surface::~Surface "virtual +gdcm::Surface::~Surface() "; + +%feature("docstring") gdcm::Surface::GetAlgorithmFamily "SegmentHelper::BasicCodedEntry& gdcm::Surface::GetAlgorithmFamily() "; + +%feature("docstring") gdcm::Surface::GetAlgorithmFamily "SegmentHelper::BasicCodedEntry const& +gdcm::Surface::GetAlgorithmFamily() const "; + +%feature("docstring") gdcm::Surface::GetAlgorithmName "const char* +gdcm::Surface::GetAlgorithmName() const "; + +%feature("docstring") gdcm::Surface::GetAlgorithmVersion "const +char* gdcm::Surface::GetAlgorithmVersion() const "; + +%feature("docstring") gdcm::Surface::GetAxisOfRotation "const float* +gdcm::Surface::GetAxisOfRotation() const + +Pointer is null if undefined "; + +%feature("docstring") gdcm::Surface::GetCenterOfRotation "const +float* gdcm::Surface::GetCenterOfRotation() const + +Pointer is null if undefined "; + +%feature("docstring") gdcm::Surface::GetFiniteVolume "STATES +gdcm::Surface::GetFiniteVolume() const "; + +%feature("docstring") gdcm::Surface::GetManifold "STATES +gdcm::Surface::GetManifold() const "; + +%feature("docstring") gdcm::Surface::GetMaximumPointDistance "float +gdcm::Surface::GetMaximumPointDistance() const "; + +%feature("docstring") gdcm::Surface::GetMeanPointDistance "float +gdcm::Surface::GetMeanPointDistance() const "; + +%feature("docstring") gdcm::Surface::GetMeshPrimitive "MeshPrimitive +const& gdcm::Surface::GetMeshPrimitive() const "; + +%feature("docstring") gdcm::Surface::GetMeshPrimitive "MeshPrimitive& gdcm::Surface::GetMeshPrimitive() "; + +%feature("docstring") gdcm::Surface::GetNumberOfSurfacePoints "unsigned long gdcm::Surface::GetNumberOfSurfacePoints() const "; + +%feature("docstring") gdcm::Surface::GetNumberOfVectors "unsigned +long gdcm::Surface::GetNumberOfVectors() const "; + +%feature("docstring") gdcm::Surface::GetPointCoordinatesData "DataElement& gdcm::Surface::GetPointCoordinatesData() "; + +%feature("docstring") gdcm::Surface::GetPointCoordinatesData "const +DataElement& gdcm::Surface::GetPointCoordinatesData() const "; + +%feature("docstring") gdcm::Surface::GetPointPositionAccuracy "const +float* gdcm::Surface::GetPointPositionAccuracy() const + +Pointer is null if undefined "; + +%feature("docstring") gdcm::Surface::GetPointsBoundingBoxCoordinates +"const float* gdcm::Surface::GetPointsBoundingBoxCoordinates() const + +Pointer is null if undefined "; + +%feature("docstring") gdcm::Surface::GetProcessingAlgorithm "SegmentHelper::BasicCodedEntry const& +gdcm::Surface::GetProcessingAlgorithm() const "; + +%feature("docstring") gdcm::Surface::GetProcessingAlgorithm "SegmentHelper::BasicCodedEntry& +gdcm::Surface::GetProcessingAlgorithm() "; + +%feature("docstring") gdcm::Surface::GetRecommendedDisplayCIELabValue +"const unsigned short* +gdcm::Surface::GetRecommendedDisplayCIELabValue() const "; + +%feature("docstring") gdcm::Surface::GetRecommendedDisplayCIELabValue +"unsigned short gdcm::Surface::GetRecommendedDisplayCIELabValue(const +unsigned int idx) const "; + +%feature("docstring") +gdcm::Surface::GetRecommendedDisplayGrayscaleValue "unsigned short +gdcm::Surface::GetRecommendedDisplayGrayscaleValue() const "; + +%feature("docstring") +gdcm::Surface::GetRecommendedPresentationOpacity "float +gdcm::Surface::GetRecommendedPresentationOpacity() const "; + +%feature("docstring") gdcm::Surface::GetRecommendedPresentationType "VIEWType gdcm::Surface::GetRecommendedPresentationType() const "; + +%feature("docstring") gdcm::Surface::GetSurfaceComments "const char* +gdcm::Surface::GetSurfaceComments() const "; + +%feature("docstring") gdcm::Surface::GetSurfaceNumber "unsigned long +gdcm::Surface::GetSurfaceNumber() const "; + +%feature("docstring") gdcm::Surface::GetSurfaceProcessing "bool +gdcm::Surface::GetSurfaceProcessing() const "; + +%feature("docstring") gdcm::Surface::GetSurfaceProcessingDescription +"const char* gdcm::Surface::GetSurfaceProcessingDescription() const +"; + +%feature("docstring") gdcm::Surface::GetSurfaceProcessingRatio "float gdcm::Surface::GetSurfaceProcessingRatio() const "; + +%feature("docstring") gdcm::Surface::GetVectorAccuracy "const float* +gdcm::Surface::GetVectorAccuracy() const "; + +%feature("docstring") gdcm::Surface::GetVectorCoordinateData "const +DataElement& gdcm::Surface::GetVectorCoordinateData() const "; + +%feature("docstring") gdcm::Surface::GetVectorCoordinateData "DataElement& gdcm::Surface::GetVectorCoordinateData() "; + +%feature("docstring") gdcm::Surface::GetVectorDimensionality "unsigned short gdcm::Surface::GetVectorDimensionality() const "; + +%feature("docstring") gdcm::Surface::SetAlgorithmFamily "void +gdcm::Surface::SetAlgorithmFamily(SegmentHelper::BasicCodedEntry const +&BSE) "; + +%feature("docstring") gdcm::Surface::SetAlgorithmName "void +gdcm::Surface::SetAlgorithmName(const char *str) "; + +%feature("docstring") gdcm::Surface::SetAlgorithmVersion "void +gdcm::Surface::SetAlgorithmVersion(const char *str) "; + +%feature("docstring") gdcm::Surface::SetAxisOfRotation "void +gdcm::Surface::SetAxisOfRotation(const float *axis) "; + +%feature("docstring") gdcm::Surface::SetCenterOfRotation "void +gdcm::Surface::SetCenterOfRotation(const float *center) "; + +%feature("docstring") gdcm::Surface::SetFiniteVolume "void +gdcm::Surface::SetFiniteVolume(STATES state) "; + +%feature("docstring") gdcm::Surface::SetManifold "void +gdcm::Surface::SetManifold(STATES state) "; + +%feature("docstring") gdcm::Surface::SetMaximumPointDistance "void +gdcm::Surface::SetMaximumPointDistance(float maximum) "; + +%feature("docstring") gdcm::Surface::SetMeanPointDistance "void +gdcm::Surface::SetMeanPointDistance(float average) "; + +%feature("docstring") gdcm::Surface::SetMeshPrimitive "void +gdcm::Surface::SetMeshPrimitive(MeshPrimitive &mp) "; + +%feature("docstring") gdcm::Surface::SetNumberOfSurfacePoints "void +gdcm::Surface::SetNumberOfSurfacePoints(const unsigned long nb) "; + +%feature("docstring") gdcm::Surface::SetNumberOfVectors "void +gdcm::Surface::SetNumberOfVectors(const unsigned long nb) "; + +%feature("docstring") gdcm::Surface::SetPointCoordinatesData "void +gdcm::Surface::SetPointCoordinatesData(DataElement const &de) "; + +%feature("docstring") gdcm::Surface::SetPointPositionAccuracy "void +gdcm::Surface::SetPointPositionAccuracy(const float *accuracies) "; + +%feature("docstring") gdcm::Surface::SetPointsBoundingBoxCoordinates +"void gdcm::Surface::SetPointsBoundingBoxCoordinates(const float +*coordinates) "; + +%feature("docstring") gdcm::Surface::SetProcessingAlgorithm "void +gdcm::Surface::SetProcessingAlgorithm(SegmentHelper::BasicCodedEntry +const &BSE) "; + +%feature("docstring") gdcm::Surface::SetRecommendedDisplayCIELabValue +"void gdcm::Surface::SetRecommendedDisplayCIELabValue(const +std::vector< unsigned short > &vl) "; + +%feature("docstring") gdcm::Surface::SetRecommendedDisplayCIELabValue +"void gdcm::Surface::SetRecommendedDisplayCIELabValue(const unsigned +short vl, const unsigned int idx=0) "; + +%feature("docstring") gdcm::Surface::SetRecommendedDisplayCIELabValue +"void gdcm::Surface::SetRecommendedDisplayCIELabValue(const unsigned +short vl[3]) "; + +%feature("docstring") +gdcm::Surface::SetRecommendedDisplayGrayscaleValue "void +gdcm::Surface::SetRecommendedDisplayGrayscaleValue(const unsigned +short vl) "; + +%feature("docstring") +gdcm::Surface::SetRecommendedPresentationOpacity "void +gdcm::Surface::SetRecommendedPresentationOpacity(const float opacity) +"; + +%feature("docstring") gdcm::Surface::SetRecommendedPresentationType "void gdcm::Surface::SetRecommendedPresentationType(VIEWType type) "; + +%feature("docstring") gdcm::Surface::SetSurfaceComments "void +gdcm::Surface::SetSurfaceComments(const char *comment) "; + +%feature("docstring") gdcm::Surface::SetSurfaceNumber "void +gdcm::Surface::SetSurfaceNumber(const unsigned long nb) "; + +%feature("docstring") gdcm::Surface::SetSurfaceProcessing "void +gdcm::Surface::SetSurfaceProcessing(bool b) "; + +%feature("docstring") gdcm::Surface::SetSurfaceProcessingDescription +"void gdcm::Surface::SetSurfaceProcessingDescription(const char +*description) "; + +%feature("docstring") gdcm::Surface::SetSurfaceProcessingRatio "void +gdcm::Surface::SetSurfaceProcessingRatio(const float ratio) "; + +%feature("docstring") gdcm::Surface::SetVectorAccuracy "void +gdcm::Surface::SetVectorAccuracy(const float *accuracy) "; + +%feature("docstring") gdcm::Surface::SetVectorCoordinateData "void +gdcm::Surface::SetVectorCoordinateData(DataElement const &de) "; + +%feature("docstring") gdcm::Surface::SetVectorDimensionality "void +gdcm::Surface::SetVectorDimensionality(const unsigned short dim) "; + + +// File: classgdcm_1_1SurfaceHelper.xml +%feature("docstring") gdcm::SurfaceHelper " + +SurfaceHelper Helper class for Surface object. + +C++ includes: gdcmSurfaceHelper.h "; + + +// File: classgdcm_1_1SurfaceReader.xml +%feature("docstring") gdcm::SurfaceReader " + +This class defines a SURFACE IE reader. It reads surface mesh module +attributes. + +See: PS 3.3 A.1.2.18 , A.57 and C.27 + +C++ includes: gdcmSurfaceReader.h "; + +%feature("docstring") gdcm::SurfaceReader::SurfaceReader "gdcm::SurfaceReader::SurfaceReader() "; + +%feature("docstring") gdcm::SurfaceReader::~SurfaceReader "virtual +gdcm::SurfaceReader::~SurfaceReader() "; + +%feature("docstring") gdcm::SurfaceReader::GetNumberOfSurfaces "unsigned long gdcm::SurfaceReader::GetNumberOfSurfaces() const "; + +%feature("docstring") gdcm::SurfaceReader::Read "virtual bool +gdcm::SurfaceReader::Read() + +Read. "; + + +// File: classgdcm_1_1SurfaceWriter.xml +%feature("docstring") gdcm::SurfaceWriter " + +This class defines a SURFACE IE writer. It writes surface mesh module +attributes. + +See: PS 3.3 A.1.2.18 , A.57 and C.27 + +C++ includes: gdcmSurfaceWriter.h "; + +%feature("docstring") gdcm::SurfaceWriter::SurfaceWriter "gdcm::SurfaceWriter::SurfaceWriter() "; + +%feature("docstring") gdcm::SurfaceWriter::~SurfaceWriter "virtual +gdcm::SurfaceWriter::~SurfaceWriter() "; + +%feature("docstring") gdcm::SurfaceWriter::GetNumberOfSurfaces "unsigned long gdcm::SurfaceWriter::GetNumberOfSurfaces() "; + +%feature("docstring") gdcm::SurfaceWriter::SetNumberOfSurfaces "void +gdcm::SurfaceWriter::SetNumberOfSurfaces(const unsigned long nb) "; + +%feature("docstring") gdcm::SurfaceWriter::Write "bool +gdcm::SurfaceWriter::Write() + +Write. "; + + +// File: classgdcm_1_1SwapCode.xml +%feature("docstring") gdcm::SwapCode " + +SwapCode representation. + +C++ includes: gdcmSwapCode.h "; + +%feature("docstring") gdcm::SwapCode::SwapCode "gdcm::SwapCode::SwapCode(SwapCodeType sc=Unknown) "; + + +// File: classgdcm_1_1SwapperDoOp.xml +%feature("docstring") gdcm::SwapperDoOp "C++ includes: gdcmSwapper.h +"; + + +// File: classgdcm_1_1SwapperNoOp.xml +%feature("docstring") gdcm::SwapperNoOp "C++ includes: gdcmSwapper.h +"; + + +// File: classgdcm_1_1System.xml +%feature("docstring") gdcm::System " + +Class to do system operation. + +OS independent functionalities + +C++ includes: gdcmSystem.h "; + + +// File: classgdcm_1_1Table.xml +%feature("docstring") gdcm::Table " + +Table. + +C++ includes: gdcmTable.h "; + +%feature("docstring") gdcm::Table::Table "gdcm::Table::Table() "; + +%feature("docstring") gdcm::Table::~Table "gdcm::Table::~Table() "; + +%feature("docstring") gdcm::Table::GetTableEntry "const TableEntry& +gdcm::Table::GetTableEntry(const Tag &tag) const "; + +%feature("docstring") gdcm::Table::InsertEntry "void +gdcm::Table::InsertEntry(Tag const &tag, TableEntry const &te) "; + + +// File: classgdcm_1_1TableEntry.xml +%feature("docstring") gdcm::TableEntry " + +TableEntry. + +C++ includes: gdcmTableEntry.h "; + +%feature("docstring") gdcm::TableEntry::TableEntry "gdcm::TableEntry::TableEntry(const char *attribute=0, Type const +&type=Type(), const char *des=0) "; + +%feature("docstring") gdcm::TableEntry::~TableEntry "gdcm::TableEntry::~TableEntry() "; + + +// File: classgdcm_1_1TableReader.xml +%feature("docstring") gdcm::TableReader " + +Class for representing a TableReader. + +This class is an empty shell meant to be derived + +C++ includes: gdcmTableReader.h "; + +%feature("docstring") gdcm::TableReader::TableReader "gdcm::TableReader::TableReader(Defs &defs) "; + +%feature("docstring") gdcm::TableReader::~TableReader "virtual +gdcm::TableReader::~TableReader() "; + +%feature("docstring") gdcm::TableReader::CharacterDataHandler "virtual void gdcm::TableReader::CharacterDataHandler(const char *data, +int length) "; + +%feature("docstring") gdcm::TableReader::EndElement "virtual void +gdcm::TableReader::EndElement(const char *name) "; + +%feature("docstring") gdcm::TableReader::GetDefs "const Defs& +gdcm::TableReader::GetDefs() const "; + +%feature("docstring") gdcm::TableReader::GetFilename "const char* +gdcm::TableReader::GetFilename() "; + +%feature("docstring") gdcm::TableReader::HandleIOD "void +gdcm::TableReader::HandleIOD(const char **atts) "; + +%feature("docstring") gdcm::TableReader::HandleIODEntry "void +gdcm::TableReader::HandleIODEntry(const char **atts) "; + +%feature("docstring") gdcm::TableReader::HandleMacro "void +gdcm::TableReader::HandleMacro(const char **atts) "; + +%feature("docstring") gdcm::TableReader::HandleMacroEntry "void +gdcm::TableReader::HandleMacroEntry(const char **atts) "; + +%feature("docstring") gdcm::TableReader::HandleMacroEntryDescription +"void gdcm::TableReader::HandleMacroEntryDescription(const char +**atts) "; + +%feature("docstring") gdcm::TableReader::HandleModule "void +gdcm::TableReader::HandleModule(const char **atts) "; + +%feature("docstring") gdcm::TableReader::HandleModuleEntry "void +gdcm::TableReader::HandleModuleEntry(const char **atts) "; + +%feature("docstring") gdcm::TableReader::HandleModuleEntryDescription +"void gdcm::TableReader::HandleModuleEntryDescription(const char +**atts) "; + +%feature("docstring") gdcm::TableReader::HandleModuleInclude "void +gdcm::TableReader::HandleModuleInclude(const char **atts) "; + +%feature("docstring") gdcm::TableReader::Read "int +gdcm::TableReader::Read() "; + +%feature("docstring") gdcm::TableReader::SetFilename "void +gdcm::TableReader::SetFilename(const char *filename) "; + +%feature("docstring") gdcm::TableReader::StartElement "virtual void +gdcm::TableReader::StartElement(const char *name, const char **atts) +"; + + +// File: classgdcm_1_1network_1_1TableRow.xml +%feature("docstring") gdcm::network::TableRow "C++ includes: +gdcmULTransitionTable.h "; + +%feature("docstring") gdcm::network::TableRow::TableRow "gdcm::network::TableRow::TableRow() "; + +%feature("docstring") gdcm::network::TableRow::~TableRow "gdcm::network::TableRow::~TableRow() "; + + +// File: classgdcm_1_1Tag.xml +%feature("docstring") gdcm::Tag " + +Class to represent a DICOM Data Element ( Attribute) Tag (Group, +Element). Basically an uint32_t which can also be expressed as two +uint16_t (group and element). + +DATA ELEMENT TAG: A unique identifier for a Data Element composed of +an ordered pair of numbers (a Group Number followed by an Element +Number). GROUP NUMBER: The first number in the ordered pair of numbers +that makes up a Data Element Tag. ELEMENT NUMBER: The second number in +the ordered pair of numbers that makes up a Data Element Tag. + +C++ includes: gdcmTag.h "; + +%feature("docstring") gdcm::Tag::Tag "gdcm::Tag::Tag(uint16_t group, +uint16_t element) + +Constructor with 2*uint16_t. "; + +%feature("docstring") gdcm::Tag::Tag "gdcm::Tag::Tag(uint32_t tag=0) + +Constructor with 1*uint32_t Prefer the cstor that takes two uint16_t. +"; + +%feature("docstring") gdcm::Tag::Tag "gdcm::Tag::Tag(const Tag +&_val) "; + +%feature("docstring") gdcm::Tag::GetElement "uint16_t +gdcm::Tag::GetElement() const + +Returns the 'Element number' of the given Tag. "; + +%feature("docstring") gdcm::Tag::GetElementTag "uint32_t +gdcm::Tag::GetElementTag() const + +Returns the full tag value of the given Tag. "; + +%feature("docstring") gdcm::Tag::GetGroup "uint16_t +gdcm::Tag::GetGroup() const + +Returns the 'Group number' of the given Tag. "; + +%feature("docstring") gdcm::Tag::GetLength "uint32_t +gdcm::Tag::GetLength() const + +return the length of tag (read: size on disk) "; + +%feature("docstring") gdcm::Tag::GetPrivateCreator "Tag +gdcm::Tag::GetPrivateCreator() const + +Return the Private Creator Data Element tag of a private data element. +"; + +%feature("docstring") gdcm::Tag::IsGroupLength "bool +gdcm::Tag::IsGroupLength() const + +return whether the tag correspond to a group length tag: "; + +%feature("docstring") gdcm::Tag::IsGroupXX "bool +gdcm::Tag::IsGroupXX(const Tag &t) const + +e.g 6002,3000 belong to groupXX: 6000,3000 "; + +%feature("docstring") gdcm::Tag::IsIllegal "bool +gdcm::Tag::IsIllegal() const + +return if the tag is considered to be an illegal tag "; + +%feature("docstring") gdcm::Tag::IsPrivate "bool +gdcm::Tag::IsPrivate() const + +PRIVATE DATA ELEMENT: Additional Data Element, defined by an +implementor, to communicate information that is not contained in +Standard Data Elements. Private Data elements have odd Group Numbers. +"; + +%feature("docstring") gdcm::Tag::IsPrivateCreator "bool +gdcm::Tag::IsPrivateCreator() const + +Returns if tag is a Private Creator (xxxx,00yy), where xxxx is odd +number and yy in [0x10,0xFF] "; + +%feature("docstring") gdcm::Tag::IsPublic "bool +gdcm::Tag::IsPublic() const + +STANDARD DATA ELEMENT: A Data Element defined in the DICOM Standard, +and therefore listed in the DICOM Data Element Dictionary in PS 3.6. +Is the Tag from the Public dict...well the implementation is buggy it +does not prove the element is indeed in the dict... "; + +%feature("docstring") gdcm::Tag::PrintAsPipeSeparatedString "std::string gdcm::Tag::PrintAsPipeSeparatedString() const + +Print as a pipe separated string (GDCM 1.x compat only). Do not use in +newer code See: ReadFromPipeSeparatedString "; + +%feature("docstring") gdcm::Tag::Read "std::istream& +gdcm::Tag::Read(std::istream &is) + +Read a tag from binary representation. "; + +%feature("docstring") gdcm::Tag::ReadFromCommaSeparatedString "bool +gdcm::Tag::ReadFromCommaSeparatedString(const char *str) + +Read from a comma separated string. This is a highly user oriented +function, the string should be formated as: 1234,5678 to specify the +tag (0x1234,0x5678) The notation comes from the DICOM standard, and is +handy to use from a command line program "; + +%feature("docstring") gdcm::Tag::ReadFromContinuousString "bool +gdcm::Tag::ReadFromContinuousString(const char *str) + +Read From XML formatted tag value eg. tag = \"12345678\" It comes in +useful when reading tag values from XML file(in NativeDICOMModel) "; + +%feature("docstring") gdcm::Tag::ReadFromPipeSeparatedString "bool +gdcm::Tag::ReadFromPipeSeparatedString(const char *str) + +Read from a pipe separated string (GDCM 1.x compat only). Do not use +in newer code See: ReadFromCommaSeparatedString "; + +%feature("docstring") gdcm::Tag::SetElement "void +gdcm::Tag::SetElement(uint16_t element) + +Sets the 'Element number' of the given Tag. "; + +%feature("docstring") gdcm::Tag::SetElementTag "void +gdcm::Tag::SetElementTag(uint16_t group, uint16_t element) + +Sets the 'Group number' & 'Element number' of the given Tag. "; + +%feature("docstring") gdcm::Tag::SetElementTag "void +gdcm::Tag::SetElementTag(uint32_t tag) + +Sets the full tag value of the given Tag. "; + +%feature("docstring") gdcm::Tag::SetGroup "void +gdcm::Tag::SetGroup(uint16_t group) + +Sets the 'Group number' of the given Tag. "; + +%feature("docstring") gdcm::Tag::SetPrivateCreator "void +gdcm::Tag::SetPrivateCreator(Tag const &t) + +Set private creator: "; + +%feature("docstring") gdcm::Tag::Write "const std::ostream& +gdcm::Tag::Write(std::ostream &os) const + +Write a tag in binary rep. "; + + +// File: classgdcm_1_1TagPath.xml +%feature("docstring") gdcm::TagPath " + +class to handle a path of tag. + +Any Resemblance to Existing XPath is Purely +Coincidentalftp://medical.nema.org/medical/dicom/supps/sup118_pc.pdf + +C++ includes: gdcmTagPath.h "; + +%feature("docstring") gdcm::TagPath::TagPath "gdcm::TagPath::TagPath() "; + +%feature("docstring") gdcm::TagPath::~TagPath "gdcm::TagPath::~TagPath() "; + +%feature("docstring") gdcm::TagPath::ConstructFromString "bool +gdcm::TagPath::ConstructFromString(const char *path) + +\"/0018,0018/\"... No space allowed, comma is use to separate tag +group from tag element and slash is used to separate tag return false +if invalid "; + +%feature("docstring") gdcm::TagPath::ConstructFromTagList "bool +gdcm::TagPath::ConstructFromTagList(Tag const *l, unsigned int n) + +Construct from a list of tags. "; + +%feature("docstring") gdcm::TagPath::Print "void +gdcm::TagPath::Print(std::ostream &) const "; + +%feature("docstring") gdcm::TagPath::Push "bool +gdcm::TagPath::Push(unsigned int itemnum) "; + +%feature("docstring") gdcm::TagPath::Push "bool +gdcm::TagPath::Push(Tag const &t) "; + + +// File: classgdcm_1_1Testing.xml +%feature("docstring") gdcm::Testing " + +class for testing + +this class is used for the nightly regression system for GDCM It makes +heavily use of md5 computation + +See: gdcm::MD5 class for md5 computation + +C++ includes: gdcmTesting.h "; + +%feature("docstring") gdcm::Testing::Testing "gdcm::Testing::Testing() "; + +%feature("docstring") gdcm::Testing::~Testing "gdcm::Testing::~Testing() "; + +%feature("docstring") gdcm::Testing::Print "void +gdcm::Testing::Print(std::ostream &os=std::cout) + +Print. "; + + +// File: classgdcm_1_1Trace.xml +%feature("docstring") gdcm::Trace " + +Trace. + +Debug / Warning and Error are encapsulated in this class by default +the Trace class will redirect any debug/warning/error to std::cerr. +Unless SetStream was specified with another (open) stream or +SetStreamToFile was specified to a writable file on the system. + +WARNING: All string messages are removed during compilation time when +compiled with CMAKE_BUILD_TYPE being set to either: Release + +MinSizeRel It is recommended to compile with RelWithDebInfo and/or +Debug during prototyping of applications. + +C++ includes: gdcmTrace.h "; + +%feature("docstring") gdcm::Trace::Trace "gdcm::Trace::Trace() "; + +%feature("docstring") gdcm::Trace::~Trace "gdcm::Trace::~Trace() "; + + +// File: classgdcm_1_1TransferSyntax.xml +%feature("docstring") gdcm::TransferSyntax " + +Class to manipulate Transfer Syntax. + +TRANSFER SYNTAX (Standard and Private): A set of encoding rules that +allow Application Entities to unambiguously negotiate the encoding +techniques (e.g., Data Element structure, byte ordering, compression) +they are able to support, thereby allowing these Application Entities +to communicate. Todo : The implementation is completely retarded -> +see gdcm::UIDs for a replacement We need: IsSupported We need +preprocess of raw/xml file We need GetFullName() + +Need a notion of Private Syntax. As defined in PS 3.5. Section 9.2 + +See: UIDs + +C++ includes: gdcmTransferSyntax.h "; + +%feature("docstring") gdcm::TransferSyntax::TransferSyntax "gdcm::TransferSyntax::TransferSyntax(TSType +type=ImplicitVRLittleEndian) "; + +%feature("docstring") gdcm::TransferSyntax::CanStoreLossy "bool +gdcm::TransferSyntax::CanStoreLossy() const + +return if TransFer Syntax Allow storing of Lossy Pixel Data "; + +%feature("docstring") gdcm::TransferSyntax::GetNegociatedType "NegociatedType gdcm::TransferSyntax::GetNegociatedType() const "; + +%feature("docstring") gdcm::TransferSyntax::GetString "const char* +gdcm::TransferSyntax::GetString() const "; + +%feature("docstring") gdcm::TransferSyntax::GetSwapCode "SwapCode +gdcm::TransferSyntax::GetSwapCode() const + +Deprecated Return the SwapCode associated with the Transfer Syntax. Be +careful with the special GE private syntax the DataSet is written in +little endian but the Pixel Data is in Big Endian. "; + +%feature("docstring") gdcm::TransferSyntax::IsEncapsulated "bool +gdcm::TransferSyntax::IsEncapsulated() const "; + +%feature("docstring") gdcm::TransferSyntax::IsEncoded "bool +gdcm::TransferSyntax::IsEncoded() const "; + +%feature("docstring") gdcm::TransferSyntax::IsExplicit "bool +gdcm::TransferSyntax::IsExplicit() const "; + +%feature("docstring") gdcm::TransferSyntax::IsImplicit "bool +gdcm::TransferSyntax::IsImplicit() const "; + +%feature("docstring") gdcm::TransferSyntax::IsLossless "bool +gdcm::TransferSyntax::IsLossless() const + +Return if the transfer syntax algorithm is a lossless algorithm "; + +%feature("docstring") gdcm::TransferSyntax::IsLossy "bool +gdcm::TransferSyntax::IsLossy() const + +Return if the transfer syntax algorithm is a lossy algorithm "; + +%feature("docstring") gdcm::TransferSyntax::IsValid "bool +gdcm::TransferSyntax::IsValid() const "; + + +// File: classgdcm_1_1network_1_1TransferSyntaxSub.xml +%feature("docstring") gdcm::network::TransferSyntaxSub " + +TransferSyntaxSub Table 9-15 TRANSFER SYNTAX SUB-ITEM FIELDS. + +TODO what is the goal of : + +Table 9-19 TRANSFER SYNTAX SUB-ITEM FIELDS + +C++ includes: gdcmTransferSyntaxSub.h "; + +%feature("docstring") +gdcm::network::TransferSyntaxSub::TransferSyntaxSub "gdcm::network::TransferSyntaxSub::TransferSyntaxSub() "; + +%feature("docstring") gdcm::network::TransferSyntaxSub::GetName "const char* gdcm::network::TransferSyntaxSub::GetName() const "; + +%feature("docstring") gdcm::network::TransferSyntaxSub::Print "void +gdcm::network::TransferSyntaxSub::Print(std::ostream &os) const "; + +%feature("docstring") gdcm::network::TransferSyntaxSub::Read "std::istream& gdcm::network::TransferSyntaxSub::Read(std::istream &is) +"; + +%feature("docstring") gdcm::network::TransferSyntaxSub::SetName "void gdcm::network::TransferSyntaxSub::SetName(const char *name) "; + +%feature("docstring") +gdcm::network::TransferSyntaxSub::SetNameFromUID "void +gdcm::network::TransferSyntaxSub::SetNameFromUID(UIDs::TSName tsname) +"; + +%feature("docstring") gdcm::network::TransferSyntaxSub::Size "size_t +gdcm::network::TransferSyntaxSub::Size() const "; + +%feature("docstring") gdcm::network::TransferSyntaxSub::Write "const +std::ostream& gdcm::network::TransferSyntaxSub::Write(std::ostream +&os) const "; + + +// File: structgdcm_1_1network_1_1Transition.xml +%feature("docstring") gdcm::network::Transition "C++ includes: +gdcmULTransitionTable.h "; + +%feature("docstring") gdcm::network::Transition::Transition "gdcm::network::Transition::Transition() "; + +%feature("docstring") gdcm::network::Transition::Transition "gdcm::network::Transition::Transition(int inEndState, ULAction +*inAction) "; + +%feature("docstring") gdcm::network::Transition::~Transition "gdcm::network::Transition::~Transition() "; + + +// File: classgdcm_1_1Type.xml +%feature("docstring") gdcm::Type " + +Type. + +PS 3.5 7.4 DATA ELEMENT TYPE 7.4.1 TYPE 1 REQUIRED DATA ELEMENTS 7.4.2 +TYPE 1C CONDITIONAL DATA ELEMENTS 7.4.3 TYPE 2 REQUIRED DATA ELEMENTS +7.4.4 TYPE 2C CONDITIONAL DATA ELEMENTS 7.4.5 TYPE 3 OPTIONAL DATA +ELEMENTS The intent of Type 2 Data Elements is to allow a zero length +to be conveyed when the operator or application does not know its +value or has a specific reason for not specifying its value. It is the +intent that the device should support these Data Elements. + +C++ includes: gdcmType.h "; + +%feature("docstring") gdcm::Type::Type "gdcm::Type::Type(TypeType +type=UNKNOWN) "; + + +// File: structgdcm_1_1UI.xml +%feature("docstring") gdcm::UI "C++ includes: gdcmVR.h "; + + +// File: classgdcm_1_1UIDGenerator.xml +%feature("docstring") gdcm::UIDGenerator " + +Class for generating unique UID. + +bla Usage: When constructing a Series or Study UID, user *has* to keep +around the UID, otherwise the UID Generator will simply forget the +value and create a new UID. + +C++ includes: gdcmUIDGenerator.h "; + +%feature("docstring") gdcm::UIDGenerator::UIDGenerator "gdcm::UIDGenerator::UIDGenerator() + +By default the root of a UID is a GDCM Root... "; + +%feature("docstring") gdcm::UIDGenerator::Generate "const char* +gdcm::UIDGenerator::Generate() + +Internally uses a std::string, so two calls have the same pointer ! +save into a std::string In summary do not write code like that: const +char *uid1 = uid.Generate(); const char *uid2 = uid.Generate(); since +uid1 == uid2 "; + + +// File: classgdcm_1_1UIDs.xml +%feature("docstring") gdcm::UIDs " + +all known uids + +C++ includes: gdcmUIDs.h "; + +%feature("docstring") gdcm::UIDs::GetName "const char* +gdcm::UIDs::GetName() const + +When object is Initialize function return the well known name +associated with uid return NULL when not initialized "; + +%feature("docstring") gdcm::UIDs::GetString "const char* +gdcm::UIDs::GetString() const + +When object is Initialize function return the uid return NULL when not +initialized "; + +%feature("docstring") gdcm::UIDs::SetFromUID "bool +gdcm::UIDs::SetFromUID(const char *str) + +Initialize object from a string (a uid number) return false on error, +and internal state is set to 0 "; + + +// File: classgdcm_1_1network_1_1ULAction.xml +%feature("docstring") gdcm::network::ULAction " + +ULAction A ULConnection in a given ULState can perform certain +ULActions. This base class provides the interface for running those +ULActions on a given ULConnection. + +Essentially, the ULConnectionManager will take this object, determined +from the current ULState of the ULConnection, and pass the +ULConnection object to the ULAction. The ULAction will then invoke +whatever necessary commands are required by a given action. + +The result of a ULAction is a ULEvent (ie, what happened as a result +of the action). + +This ULEvent is passed to the ULState, so that the transition to the +next state can occur. + +Actions are associated with Payloads-- be thos filestreams, AETitles +to establish connections, whatever. The actual parameters that the +user will pass via an action will come through a Payload object, which +should, in itself, be some gdcm-based object (but not all objects can +be payloads; sending a single dataelement as a payload isn't +meaningful). As such, each action has its own particular payload. + +For the sake of keeping files together, both the particular payload +class and the action class will be defined in the same header file. +Payloads should JUST be data (or streams), NO METHODS. + +Some actions perform changes that should raise events on the local +system, and some actions perform changes that will require waiting for +events from the remote system. + +Therefore, this base action has been modified so that those events are +set by each action. When the event loop runs an action, it will then +test to see if a local event was raised by the action, and if so, +perform the appropriate subsequent action. If the action requires +waiting for a response from the remote system, then the event loop +will sit there (presumably with the ARTIM timer running) and wait for +a response from the remote system. Once a response is obtained, then +the the rest of the state transitions can happen. + +C++ includes: gdcmULAction.h "; + +%feature("docstring") gdcm::network::ULAction::ULAction "gdcm::network::ULAction::ULAction() "; + +%feature("docstring") gdcm::network::ULAction::~ULAction "virtual +gdcm::network::ULAction::~ULAction() "; + +%feature("docstring") gdcm::network::ULAction::PerformAction "virtual EStateID gdcm::network::ULAction::PerformAction(Subject *s, +ULEvent &inEvent, ULConnection &inConnection, bool +&outWaitingForEvent, EEventID &outRaisedEvent)=0 "; + + +// File: classgdcm_1_1network_1_1ULActionAA1.xml +%feature("docstring") gdcm::network::ULActionAA1 "C++ includes: +gdcmULActionAA.h "; + +%feature("docstring") gdcm::network::ULActionAA1::PerformAction "EStateID gdcm::network::ULActionAA1::PerformAction(Subject *s, ULEvent +&inEvent, ULConnection &inConnection, bool &outWaitingForEvent, +EEventID &outRaisedEvent) "; + + +// File: classgdcm_1_1network_1_1ULActionAA2.xml +%feature("docstring") gdcm::network::ULActionAA2 "C++ includes: +gdcmULActionAA.h "; + +%feature("docstring") gdcm::network::ULActionAA2::PerformAction "EStateID gdcm::network::ULActionAA2::PerformAction(Subject *s, ULEvent +&inEvent, ULConnection &inConnection, bool &outWaitingForEvent, +EEventID &outRaisedEvent) "; + + +// File: classgdcm_1_1network_1_1ULActionAA3.xml +%feature("docstring") gdcm::network::ULActionAA3 "C++ includes: +gdcmULActionAA.h "; + +%feature("docstring") gdcm::network::ULActionAA3::PerformAction "EStateID gdcm::network::ULActionAA3::PerformAction(Subject *s, ULEvent +&inEvent, ULConnection &inConnection, bool &outWaitingForEvent, +EEventID &outRaisedEvent) "; + + +// File: classgdcm_1_1network_1_1ULActionAA4.xml +%feature("docstring") gdcm::network::ULActionAA4 "C++ includes: +gdcmULActionAA.h "; + +%feature("docstring") gdcm::network::ULActionAA4::PerformAction "EStateID gdcm::network::ULActionAA4::PerformAction(Subject *s, ULEvent +&inEvent, ULConnection &inConnection, bool &outWaitingForEvent, +EEventID &outRaisedEvent) "; + + +// File: classgdcm_1_1network_1_1ULActionAA5.xml +%feature("docstring") gdcm::network::ULActionAA5 "C++ includes: +gdcmULActionAA.h "; + +%feature("docstring") gdcm::network::ULActionAA5::PerformAction "EStateID gdcm::network::ULActionAA5::PerformAction(Subject *s, ULEvent +&inEvent, ULConnection &inConnection, bool &outWaitingForEvent, +EEventID &outRaisedEvent) "; + + +// File: classgdcm_1_1network_1_1ULActionAA6.xml +%feature("docstring") gdcm::network::ULActionAA6 "C++ includes: +gdcmULActionAA.h "; + +%feature("docstring") gdcm::network::ULActionAA6::PerformAction "EStateID gdcm::network::ULActionAA6::PerformAction(Subject *s, ULEvent +&inEvent, ULConnection &inConnection, bool &outWaitingForEvent, +EEventID &outRaisedEvent) "; + + +// File: classgdcm_1_1network_1_1ULActionAA7.xml +%feature("docstring") gdcm::network::ULActionAA7 "C++ includes: +gdcmULActionAA.h "; + +%feature("docstring") gdcm::network::ULActionAA7::PerformAction "EStateID gdcm::network::ULActionAA7::PerformAction(Subject *s, ULEvent +&inEvent, ULConnection &inConnection, bool &outWaitingForEvent, +EEventID &outRaisedEvent) "; + + +// File: classgdcm_1_1network_1_1ULActionAA8.xml +%feature("docstring") gdcm::network::ULActionAA8 "C++ includes: +gdcmULActionAA.h "; + +%feature("docstring") gdcm::network::ULActionAA8::PerformAction "EStateID gdcm::network::ULActionAA8::PerformAction(Subject *s, ULEvent +&inEvent, ULConnection &inConnection, bool &outWaitingForEvent, +EEventID &outRaisedEvent) "; + + +// File: classgdcm_1_1network_1_1ULActionAE1.xml +%feature("docstring") gdcm::network::ULActionAE1 "C++ includes: +gdcmULActionAE.h "; + +%feature("docstring") gdcm::network::ULActionAE1::PerformAction "EStateID gdcm::network::ULActionAE1::PerformAction(Subject *s, ULEvent +&inEvent, ULConnection &inConnection, bool &outWaitingForEvent, +EEventID &outRaisedEvent) "; + + +// File: classgdcm_1_1network_1_1ULActionAE2.xml +%feature("docstring") gdcm::network::ULActionAE2 "C++ includes: +gdcmULActionAE.h "; + +%feature("docstring") gdcm::network::ULActionAE2::PerformAction "EStateID gdcm::network::ULActionAE2::PerformAction(Subject *s, ULEvent +&inEvent, ULConnection &inConnection, bool &outWaitingForEvent, +EEventID &outRaisedEvent) "; + + +// File: classgdcm_1_1network_1_1ULActionAE3.xml +%feature("docstring") gdcm::network::ULActionAE3 "C++ includes: +gdcmULActionAE.h "; + +%feature("docstring") gdcm::network::ULActionAE3::PerformAction "EStateID gdcm::network::ULActionAE3::PerformAction(Subject *s, ULEvent +&inEvent, ULConnection &inConnection, bool &outWaitingForEvent, +EEventID &outRaisedEvent) "; + + +// File: classgdcm_1_1network_1_1ULActionAE4.xml +%feature("docstring") gdcm::network::ULActionAE4 "C++ includes: +gdcmULActionAE.h "; + +%feature("docstring") gdcm::network::ULActionAE4::PerformAction "EStateID gdcm::network::ULActionAE4::PerformAction(Subject *s, ULEvent +&inEvent, ULConnection &inConnection, bool &outWaitingForEvent, +EEventID &outRaisedEvent) "; + + +// File: classgdcm_1_1network_1_1ULActionAE5.xml +%feature("docstring") gdcm::network::ULActionAE5 "C++ includes: +gdcmULActionAE.h "; + +%feature("docstring") gdcm::network::ULActionAE5::PerformAction "EStateID gdcm::network::ULActionAE5::PerformAction(Subject *s, ULEvent +&inEvent, ULConnection &inConnection, bool &outWaitingForEvent, +EEventID &outRaisedEvent) "; + + +// File: classgdcm_1_1network_1_1ULActionAE6.xml +%feature("docstring") gdcm::network::ULActionAE6 "C++ includes: +gdcmULActionAE.h "; + +%feature("docstring") gdcm::network::ULActionAE6::PerformAction "EStateID gdcm::network::ULActionAE6::PerformAction(Subject *s, ULEvent +&inEvent, ULConnection &inConnection, bool &outWaitingForEvent, +EEventID &outRaisedEvent) "; + + +// File: classgdcm_1_1network_1_1ULActionAE7.xml +%feature("docstring") gdcm::network::ULActionAE7 "C++ includes: +gdcmULActionAE.h "; + +%feature("docstring") gdcm::network::ULActionAE7::PerformAction "EStateID gdcm::network::ULActionAE7::PerformAction(Subject *s, ULEvent +&inEvent, ULConnection &inConnection, bool &outWaitingForEvent, +EEventID &outRaisedEvent) "; + + +// File: classgdcm_1_1network_1_1ULActionAE8.xml +%feature("docstring") gdcm::network::ULActionAE8 "C++ includes: +gdcmULActionAE.h "; + +%feature("docstring") gdcm::network::ULActionAE8::PerformAction "EStateID gdcm::network::ULActionAE8::PerformAction(Subject *s, ULEvent +&inEvent, ULConnection &inConnection, bool &outWaitingForEvent, +EEventID &outRaisedEvent) "; + + +// File: classgdcm_1_1network_1_1ULActionAR1.xml +%feature("docstring") gdcm::network::ULActionAR1 "C++ includes: +gdcmULActionAR.h "; + +%feature("docstring") gdcm::network::ULActionAR1::PerformAction "EStateID gdcm::network::ULActionAR1::PerformAction(Subject *s, ULEvent +&inEvent, ULConnection &inConnection, bool &outWaitingForEvent, +EEventID &outRaisedEvent) "; + + +// File: classgdcm_1_1network_1_1ULActionAR10.xml +%feature("docstring") gdcm::network::ULActionAR10 "C++ includes: +gdcmULActionAR.h "; + +%feature("docstring") gdcm::network::ULActionAR10::PerformAction "EStateID gdcm::network::ULActionAR10::PerformAction(Subject *s, +ULEvent &inEvent, ULConnection &inConnection, bool +&outWaitingForEvent, EEventID &outRaisedEvent) "; + + +// File: classgdcm_1_1network_1_1ULActionAR2.xml +%feature("docstring") gdcm::network::ULActionAR2 "C++ includes: +gdcmULActionAR.h "; + +%feature("docstring") gdcm::network::ULActionAR2::PerformAction "EStateID gdcm::network::ULActionAR2::PerformAction(Subject *s, ULEvent +&inEvent, ULConnection &inConnection, bool &outWaitingForEvent, +EEventID &outRaisedEvent) "; + + +// File: classgdcm_1_1network_1_1ULActionAR3.xml +%feature("docstring") gdcm::network::ULActionAR3 "C++ includes: +gdcmULActionAR.h "; + +%feature("docstring") gdcm::network::ULActionAR3::PerformAction "EStateID gdcm::network::ULActionAR3::PerformAction(Subject *s, ULEvent +&inEvent, ULConnection &inConnection, bool &outWaitingForEvent, +EEventID &outRaisedEvent) "; + + +// File: classgdcm_1_1network_1_1ULActionAR4.xml +%feature("docstring") gdcm::network::ULActionAR4 "C++ includes: +gdcmULActionAR.h "; + +%feature("docstring") gdcm::network::ULActionAR4::PerformAction "EStateID gdcm::network::ULActionAR4::PerformAction(Subject *s, ULEvent +&inEvent, ULConnection &inConnection, bool &outWaitingForEvent, +EEventID &outRaisedEvent) "; + + +// File: classgdcm_1_1network_1_1ULActionAR5.xml +%feature("docstring") gdcm::network::ULActionAR5 "C++ includes: +gdcmULActionAR.h "; + +%feature("docstring") gdcm::network::ULActionAR5::PerformAction "EStateID gdcm::network::ULActionAR5::PerformAction(Subject *s, ULEvent +&inEvent, ULConnection &inConnection, bool &outWaitingForEvent, +EEventID &outRaisedEvent) "; + + +// File: classgdcm_1_1network_1_1ULActionAR6.xml +%feature("docstring") gdcm::network::ULActionAR6 "C++ includes: +gdcmULActionAR.h "; + +%feature("docstring") gdcm::network::ULActionAR6::PerformAction "EStateID gdcm::network::ULActionAR6::PerformAction(Subject *s, ULEvent +&inEvent, ULConnection &inConnection, bool &outWaitingForEvent, +EEventID &outRaisedEvent) "; + + +// File: classgdcm_1_1network_1_1ULActionAR7.xml +%feature("docstring") gdcm::network::ULActionAR7 "C++ includes: +gdcmULActionAR.h "; + +%feature("docstring") gdcm::network::ULActionAR7::PerformAction "EStateID gdcm::network::ULActionAR7::PerformAction(Subject *s, ULEvent +&inEvent, ULConnection &inConnection, bool &outWaitingForEvent, +EEventID &outRaisedEvent) "; + + +// File: classgdcm_1_1network_1_1ULActionAR8.xml +%feature("docstring") gdcm::network::ULActionAR8 "C++ includes: +gdcmULActionAR.h "; + +%feature("docstring") gdcm::network::ULActionAR8::PerformAction "EStateID gdcm::network::ULActionAR8::PerformAction(Subject *s, ULEvent +&inEvent, ULConnection &inConnection, bool &outWaitingForEvent, +EEventID &outRaisedEvent) "; + + +// File: classgdcm_1_1network_1_1ULActionAR9.xml +%feature("docstring") gdcm::network::ULActionAR9 "C++ includes: +gdcmULActionAR.h "; + +%feature("docstring") gdcm::network::ULActionAR9::PerformAction "EStateID gdcm::network::ULActionAR9::PerformAction(Subject *s, ULEvent +&inEvent, ULConnection &inConnection, bool &outWaitingForEvent, +EEventID &outRaisedEvent) "; + + +// File: classgdcm_1_1network_1_1ULActionDT1.xml +%feature("docstring") gdcm::network::ULActionDT1 "C++ includes: +gdcmULActionDT.h "; + +%feature("docstring") gdcm::network::ULActionDT1::PerformAction "EStateID gdcm::network::ULActionDT1::PerformAction(Subject *s, ULEvent +&inEvent, ULConnection &inConnection, bool &outWaitingForEvent, +EEventID &outRaisedEvent) "; + + +// File: classgdcm_1_1network_1_1ULActionDT2.xml +%feature("docstring") gdcm::network::ULActionDT2 "C++ includes: +gdcmULActionDT.h "; + +%feature("docstring") gdcm::network::ULActionDT2::PerformAction "EStateID gdcm::network::ULActionDT2::PerformAction(Subject *s, ULEvent +&inEvent, ULConnection &inConnection, bool &outWaitingForEvent, +EEventID &outRaisedEvent) "; + + +// File: classgdcm_1_1network_1_1ULBasicCallback.xml +%feature("docstring") gdcm::network::ULBasicCallback " + +ULBasicCallback This is the most basic of callbacks for how the +ULConnectionManager handles incoming datasets. DataSets are just +concatenated to the mDataSets vector, and the result can be pulled out +of the vector by later code. Alternatives to this method include +progress updates, saving to disk, etc. This class is NOT THREAD SAFE. +Access the dataset vector after the entire set of datasets has been +returned by the ULConnectionManager. + +C++ includes: gdcmULBasicCallback.h "; + +%feature("docstring") gdcm::network::ULBasicCallback::ULBasicCallback +"gdcm::network::ULBasicCallback::ULBasicCallback() "; + +%feature("docstring") +gdcm::network::ULBasicCallback::~ULBasicCallback "virtual +gdcm::network::ULBasicCallback::~ULBasicCallback() "; + +%feature("docstring") gdcm::network::ULBasicCallback::GetDataSets "std::vector const& +gdcm::network::ULBasicCallback::GetDataSets() const "; + +%feature("docstring") gdcm::network::ULBasicCallback::GetResponses "std::vector const& +gdcm::network::ULBasicCallback::GetResponses() const "; + +%feature("docstring") gdcm::network::ULBasicCallback::HandleDataSet "virtual void gdcm::network::ULBasicCallback::HandleDataSet(const +DataSet &inDataSet) "; + +%feature("docstring") gdcm::network::ULBasicCallback::HandleResponse +"virtual void gdcm::network::ULBasicCallback::HandleResponse(const +DataSet &inDataSet) "; + + +// File: classgdcm_1_1network_1_1ULConnection.xml +%feature("docstring") gdcm::network::ULConnection " + +ULConnection This is the class that contains the socket to another +machine, and passes data through itself, as well as maintaining a +sense of state. + +The ULConnectionManager tells the ULConnection what data can actually +be sent. + +This class is done this way so that it can be eventually be replaced +with a ULSecureConnection, if such a protocol is warranted, so that +all data that passes through can be managed through a secure +connection. For now, this class provides a simple pass-through +mechanism to the socket itself. + +So, for instance, a gdcm object will be passes to this object, and it +will then get passed along the connection, if that connection is in +the proper state to do so. + +For right now, this class is not directly intended to be inherited +from, but the potential for future ULSecureConnection warrants the +addition, rather than having everything be managed from within the +ULConnectionManager (or this class) without a wrapper. + +C++ includes: gdcmULConnection.h "; + +%feature("docstring") gdcm::network::ULConnection::ULConnection "gdcm::network::ULConnection::ULConnection(const ULConnectionInfo +&inUserInformation) "; + +%feature("docstring") gdcm::network::ULConnection::~ULConnection "virtual gdcm::network::ULConnection::~ULConnection() "; + +%feature("docstring") +gdcm::network::ULConnection::AddAcceptedPresentationContext "void +gdcm::network::ULConnection::AddAcceptedPresentationContext(const +PresentationContextAC &inPC) "; + +%feature("docstring") gdcm::network::ULConnection::FindContext "PresentationContextRQ gdcm::network::ULConnection::FindContext(const +DataElement &de) const "; + +%feature("docstring") +gdcm::network::ULConnection::GetAcceptedPresentationContexts "std::vector const& +gdcm::network::ULConnection::GetAcceptedPresentationContexts() const +"; + +%feature("docstring") +gdcm::network::ULConnection::GetAcceptedPresentationContexts "std::vector& +gdcm::network::ULConnection::GetAcceptedPresentationContexts() "; + +%feature("docstring") gdcm::network::ULConnection::GetConnectionInfo +"const ULConnectionInfo& +gdcm::network::ULConnection::GetConnectionInfo() const "; + +%feature("docstring") gdcm::network::ULConnection::GetMaxPDUSize "uint32_t gdcm::network::ULConnection::GetMaxPDUSize() const "; + +%feature("docstring") +gdcm::network::ULConnection::GetPresentationContextACByID "const +PresentationContextAC* +gdcm::network::ULConnection::GetPresentationContextACByID(uint8_t id) +const "; + +%feature("docstring") +gdcm::network::ULConnection::GetPresentationContextIDFromPresentationContext +"uint8_t +gdcm::network::ULConnection::GetPresentationContextIDFromPresentationContext(PresentationContextRQ +const &pc) const + +return 0 upon error "; + +%feature("docstring") +gdcm::network::ULConnection::GetPresentationContextRQByID "const +PresentationContextRQ* +gdcm::network::ULConnection::GetPresentationContextRQByID(uint8_t id) +const "; + +%feature("docstring") +gdcm::network::ULConnection::GetPresentationContexts "std::vector const& +gdcm::network::ULConnection::GetPresentationContexts() const "; + +%feature("docstring") gdcm::network::ULConnection::GetProtocol "std::iostream* gdcm::network::ULConnection::GetProtocol() "; + +%feature("docstring") gdcm::network::ULConnection::GetState "EStateID gdcm::network::ULConnection::GetState() const "; + +%feature("docstring") gdcm::network::ULConnection::GetTimer "ARTIMTimer& gdcm::network::ULConnection::GetTimer() "; + +%feature("docstring") +gdcm::network::ULConnection::InitializeConnection "bool +gdcm::network::ULConnection::InitializeConnection() + +used to establish scu connections "; + +%feature("docstring") +gdcm::network::ULConnection::InitializeIncomingConnection "bool +gdcm::network::ULConnection::InitializeIncomingConnection() + +used to establish scp connections "; + +%feature("docstring") gdcm::network::ULConnection::SetMaxPDUSize "void gdcm::network::ULConnection::SetMaxPDUSize(uint32_t inSize) "; + +%feature("docstring") +gdcm::network::ULConnection::SetPresentationContexts "void +gdcm::network::ULConnection::SetPresentationContexts(const +std::vector< PresentationContextRQ > &inContexts) "; + +%feature("docstring") +gdcm::network::ULConnection::SetPresentationContexts "void +gdcm::network::ULConnection::SetPresentationContexts(const +std::vector< PresentationContext > &inContexts) "; + +%feature("docstring") gdcm::network::ULConnection::SetState "void +gdcm::network::ULConnection::SetState(const EStateID &inState) "; + +%feature("docstring") gdcm::network::ULConnection::StopProtocol "void gdcm::network::ULConnection::StopProtocol() "; + + +// File: classgdcm_1_1network_1_1ULConnectionCallback.xml +%feature("docstring") gdcm::network::ULConnectionCallback " + +When a dataset comes back from a query/move/etc, the result can either +be stored entirely in memory, or could be stored on disk. This class +provides a mechanism to indicate what the ULConnectionManager should +do with datasets that are produced through query results. The +ULConnectionManager will call the HandleDataSet function during the +course of receiving datasets. Particular implementations should fill +in what that function does, including updating progress, etc. NOTE: +since cmove requires that multiple event loops be employed, the +callback function MUST set mHandledDataSet to true. otherwise, the +cmove event loop handler will not know data was received, and proceed +to end the loop prematurely. + +C++ includes: gdcmULConnectionCallback.h "; + +%feature("docstring") +gdcm::network::ULConnectionCallback::ULConnectionCallback "gdcm::network::ULConnectionCallback::ULConnectionCallback() "; + +%feature("docstring") +gdcm::network::ULConnectionCallback::~ULConnectionCallback "virtual +gdcm::network::ULConnectionCallback::~ULConnectionCallback() "; + +%feature("docstring") +gdcm::network::ULConnectionCallback::DataSetHandles "bool +gdcm::network::ULConnectionCallback::DataSetHandles() const "; + +%feature("docstring") +gdcm::network::ULConnectionCallback::HandleDataSet "virtual void +gdcm::network::ULConnectionCallback::HandleDataSet(const DataSet +&inDataSet)=0 "; + +%feature("docstring") +gdcm::network::ULConnectionCallback::HandleResponse "virtual void +gdcm::network::ULConnectionCallback::HandleResponse(const DataSet +&inDataSet)=0 "; + +%feature("docstring") +gdcm::network::ULConnectionCallback::ResetHandledDataSet "void +gdcm::network::ULConnectionCallback::ResetHandledDataSet() "; + + +// File: classgdcm_1_1network_1_1ULConnectionInfo.xml +%feature("docstring") gdcm::network::ULConnectionInfo " + +ULConnectionInfo this class contains all the information about a +particular connection as established by the user. That is, it's: User +Information Calling AE Title Called AE Title IP address/computer name +IP Port A connection must be established with this information, that's +subsequently placed into various primitives for actual communication. + +C++ includes: gdcmULConnectionInfo.h "; + +%feature("docstring") +gdcm::network::ULConnectionInfo::ULConnectionInfo "gdcm::network::ULConnectionInfo::ULConnectionInfo() "; + +%feature("docstring") +gdcm::network::ULConnectionInfo::GetCalledAETitle "const char* +gdcm::network::ULConnectionInfo::GetCalledAETitle() const "; + +%feature("docstring") +gdcm::network::ULConnectionInfo::GetCalledComputerName "std::string +gdcm::network::ULConnectionInfo::GetCalledComputerName() const "; + +%feature("docstring") +gdcm::network::ULConnectionInfo::GetCalledIPAddress "unsigned long +gdcm::network::ULConnectionInfo::GetCalledIPAddress() const "; + +%feature("docstring") +gdcm::network::ULConnectionInfo::GetCalledIPPort "int +gdcm::network::ULConnectionInfo::GetCalledIPPort() const "; + +%feature("docstring") +gdcm::network::ULConnectionInfo::GetCallingAETitle "const char* +gdcm::network::ULConnectionInfo::GetCallingAETitle() const "; + +%feature("docstring") +gdcm::network::ULConnectionInfo::GetMaxPDULength "unsigned long +gdcm::network::ULConnectionInfo::GetMaxPDULength() const "; + +%feature("docstring") gdcm::network::ULConnectionInfo::Initialize "bool gdcm::network::ULConnectionInfo::Initialize(UserInformation const +&inUserInformation, const char *inCalledAETitle, const char +*inCallingAETitle, unsigned long inCalledIPAddress, int +inCalledIPPort, std::string inCalledComputerName) "; + +%feature("docstring") +gdcm::network::ULConnectionInfo::SetMaxPDULength "void +gdcm::network::ULConnectionInfo::SetMaxPDULength(unsigned long +inMaxPDULength) "; + + +// File: classgdcm_1_1network_1_1ULConnectionManager.xml +%feature("docstring") gdcm::network::ULConnectionManager " + +ULConnectionManager The ULConnectionManager performs actions on the +ULConnection given inputs from the user and from the state of what's +going on around the connection (ie, timeouts of the ARTIM timer, +responses from the peer across the connection, etc). + +Its inputs are ULEvents, and it performs ULActions. + +C++ includes: gdcmULConnectionManager.h "; + +%feature("docstring") +gdcm::network::ULConnectionManager::ULConnectionManager "gdcm::network::ULConnectionManager::ULConnectionManager() "; + +%feature("docstring") +gdcm::network::ULConnectionManager::~ULConnectionManager "gdcm::network::ULConnectionManager::~ULConnectionManager() "; + +%feature("docstring") +gdcm::network::ULConnectionManager::BreakConnection "bool +gdcm::network::ULConnectionManager::BreakConnection(const double +&inTimeout) "; + +%feature("docstring") +gdcm::network::ULConnectionManager::BreakConnectionNow "void +gdcm::network::ULConnectionManager::BreakConnectionNow() "; + +%feature("docstring") +gdcm::network::ULConnectionManager::EstablishConnection "bool +gdcm::network::ULConnectionManager::EstablishConnection(const +std::string &inAETitle, const std::string &inConnectAETitle, const +std::string &inComputerName, long inIPAddress, uint16_t inConnectPort, +double inTimeout, std::vector< PresentationContext > const &pcVector) + +returns true if a connection of the given AETitle (ie, 'this' program) +is able to connect to the given AETitle and Port in a certain amount +of time providing the connection type will establish the proper +exchange syntax with a server; if a different functionality is +required, a different connection should be established. returns false +if the connection type is 'move'-- have to give a return port for move +to work as specified. "; + +%feature("docstring") +gdcm::network::ULConnectionManager::EstablishConnectionMove "bool +gdcm::network::ULConnectionManager::EstablishConnectionMove(const +std::string &inAETitle, const std::string &inConnectAETitle, const +std::string &inComputerName, long inIPAddress, uint16_t inConnectPort, +double inTimeout, uint16_t inReturnPort, std::vector< +PresentationContext > const &pcVector) + +returns true for above reasons, but contains the special 'move' port +"; + +%feature("docstring") gdcm::network::ULConnectionManager::SendEcho "std::vector +gdcm::network::ULConnectionManager::SendEcho() "; + +%feature("docstring") gdcm::network::ULConnectionManager::SendFind "std::vector +gdcm::network::ULConnectionManager::SendFind(const BaseRootQuery +*inRootQuery) "; + +%feature("docstring") gdcm::network::ULConnectionManager::SendFind "void gdcm::network::ULConnectionManager::SendFind(const BaseRootQuery +*inRootQuery, ULConnectionCallback *inCallback) "; + +%feature("docstring") gdcm::network::ULConnectionManager::SendMove "bool gdcm::network::ULConnectionManager::SendMove(const BaseRootQuery +*inRootQuery, ULConnectionCallback *inCallback) + +return false upon error "; + +%feature("docstring") gdcm::network::ULConnectionManager::SendMove "std::vector +gdcm::network::ULConnectionManager::SendMove(const BaseRootQuery +*inRootQuery) "; + +%feature("docstring") gdcm::network::ULConnectionManager::SendStore "std::vector +gdcm::network::ULConnectionManager::SendStore(const File &file) "; + +%feature("docstring") gdcm::network::ULConnectionManager::SendStore "void gdcm::network::ULConnectionManager::SendStore(const File &file, +ULConnectionCallback *inCallback) + +callback based API "; + + +// File: classgdcm_1_1network_1_1ULEvent.xml +%feature("docstring") gdcm::network::ULEvent " + +ULEvent base class for network events. + +An event consists of the event ID and the data associated with that +event. + +Note that once a PDU is created, it is now the responsibility of the +associated event to destroy it! + +C++ includes: gdcmULEvent.h "; + +%feature("docstring") gdcm::network::ULEvent::ULEvent "gdcm::network::ULEvent::ULEvent(const EEventID &inEventID, +std::vector< BasePDU * > const &inBasePDU) "; + +%feature("docstring") gdcm::network::ULEvent::ULEvent "gdcm::network::ULEvent::ULEvent(const EEventID &inEventID, BasePDU +*inBasePDU) "; + +%feature("docstring") gdcm::network::ULEvent::~ULEvent "gdcm::network::ULEvent::~ULEvent() "; + +%feature("docstring") gdcm::network::ULEvent::GetEvent "EEventID +gdcm::network::ULEvent::GetEvent() const "; + +%feature("docstring") gdcm::network::ULEvent::GetPDUs "std::vector const& gdcm::network::ULEvent::GetPDUs() const +"; + +%feature("docstring") gdcm::network::ULEvent::SetEvent "void +gdcm::network::ULEvent::SetEvent(const EEventID &inEvent) "; + +%feature("docstring") gdcm::network::ULEvent::SetPDU "void +gdcm::network::ULEvent::SetPDU(std::vector< BasePDU * > const &inPDU) +"; + + +// File: classgdcm_1_1network_1_1ULTransitionTable.xml +%feature("docstring") gdcm::network::ULTransitionTable " + +ULTransitionTable The transition table of all the ULEvents, new +ULActions, and ULStates. + +Based roughly on the solutions in player2.cpp in the boost examples +and this so question:http://stackoverflow.com/questions/1647631/c +-state-machine-design + +The transition table is constructed of TableRows. Each row is based on +an event, and an event handler in the TransitionTable object takes a +given event, and then finds the given row. + +Then, given the current state of the connection, determines the +appropriate action to take and then the state to transition to next. + +C++ includes: gdcmULTransitionTable.h "; + +%feature("docstring") +gdcm::network::ULTransitionTable::ULTransitionTable "gdcm::network::ULTransitionTable::ULTransitionTable() "; + +%feature("docstring") gdcm::network::ULTransitionTable::HandleEvent "void gdcm::network::ULTransitionTable::HandleEvent(Subject *s, ULEvent +&inEvent, ULConnection &inConnection, bool &outWaitingForEvent, +EEventID &outRaisedEvent) const "; + +%feature("docstring") gdcm::network::ULTransitionTable::PrintTable "void gdcm::network::ULTransitionTable::PrintTable() const "; + + +// File: classgdcm_1_1network_1_1ULWritingCallback.xml +%feature("docstring") gdcm::network::ULWritingCallback "C++ includes: +gdcmULWritingCallback.h "; + +%feature("docstring") +gdcm::network::ULWritingCallback::ULWritingCallback "gdcm::network::ULWritingCallback::ULWritingCallback() "; + +%feature("docstring") +gdcm::network::ULWritingCallback::~ULWritingCallback "virtual +gdcm::network::ULWritingCallback::~ULWritingCallback() "; + +%feature("docstring") gdcm::network::ULWritingCallback::HandleDataSet +"virtual void gdcm::network::ULWritingCallback::HandleDataSet(const +DataSet &inDataSet) "; + +%feature("docstring") +gdcm::network::ULWritingCallback::HandleResponse "virtual void +gdcm::network::ULWritingCallback::HandleResponse(const DataSet +&inDataSet) "; + +%feature("docstring") gdcm::network::ULWritingCallback::SetDirectory +"void gdcm::network::ULWritingCallback::SetDirectory(const +std::string &inDirectoryName) + +provide the directory into which all files are written. "; + + +// File: classstd_1_1underflow__error.xml +%feature("docstring") std::underflow_error " + +STL class. "; + + +// File: classgdcm_1_1UNExplicitDataElement.xml +%feature("docstring") gdcm::UNExplicitDataElement " + +Class to read/write a DataElement as UNExplicit Data Element. + +bla + +C++ includes: gdcmUNExplicitDataElement.h "; + +%feature("docstring") gdcm::UNExplicitDataElement::GetLength "VL +gdcm::UNExplicitDataElement::GetLength() const "; + +%feature("docstring") gdcm::UNExplicitDataElement::Read "std::istream& gdcm::UNExplicitDataElement::Read(std::istream &is) "; + +%feature("docstring") gdcm::UNExplicitDataElement::ReadPreValue "std::istream& gdcm::UNExplicitDataElement::ReadPreValue(std::istream +&is) "; + +%feature("docstring") gdcm::UNExplicitDataElement::ReadValue "std::istream& gdcm::UNExplicitDataElement::ReadValue(std::istream &is) +"; + +%feature("docstring") gdcm::UNExplicitDataElement::ReadWithLength "std::istream& gdcm::UNExplicitDataElement::ReadWithLength(std::istream +&is, VL &length) "; + + +// File: classgdcm_1_1UNExplicitImplicitDataElement.xml +%feature("docstring") gdcm::UNExplicitImplicitDataElement " + +Class to read/write a DataElement as ExplicitImplicit Data Element +This class gather two known bugs: 1. GDCM 1.2.0 would rewrite VR=UN +Value Length on 2 bytes instead of 4 bytes 2. GDCM 1.2.0 would also +rewrite DataElement as Implicit when the VR would not be known this +would only happen in some very rare cases. gdcm 2.X design could +handle bug #1 or #2 exclusively, this class can now handle file which +have both issues. See: gdcmData/TheralysGDCM120Bug.dcm. + +C++ includes: gdcmUNExplicitImplicitDataElement.h "; + +%feature("docstring") gdcm::UNExplicitImplicitDataElement::GetLength +"VL gdcm::UNExplicitImplicitDataElement::GetLength() const "; + +%feature("docstring") gdcm::UNExplicitImplicitDataElement::Read "std::istream& gdcm::UNExplicitImplicitDataElement::Read(std::istream +&is) "; + +%feature("docstring") +gdcm::UNExplicitImplicitDataElement::ReadPreValue "std::istream& +gdcm::UNExplicitImplicitDataElement::ReadPreValue(std::istream &is) "; + +%feature("docstring") gdcm::UNExplicitImplicitDataElement::ReadValue +"std::istream& +gdcm::UNExplicitImplicitDataElement::ReadValue(std::istream &is) "; + + +// File: classgdcm_1_1Unpacker12Bits.xml +%feature("docstring") gdcm::Unpacker12Bits " + +Pack/Unpack 12 bits pixel into 16bits. + +You can only pack an even number of 16bits, which means a multiple of +4 (expressed in bytes) + +You can only unpack a multiple of 3 bytes This class has no purpose +in general purpose DICOM implementation. However to be able to cope +with some early ACR-NEMA file generated by a well-known private +vendor, one would need to unpack 12bits Stored Pixel Value into a more +standard 16bits Stored Pixel Value. + +See: Rescaler + +C++ includes: gdcmUnpacker12Bits.h "; + + +// File: classgdcm_1_1Usage.xml +%feature("docstring") gdcm::Usage " + +Usage. + +A.1.3 IOD Module Table and Functional Group Macro Table This Section +of each IOD defines in a tabular form the Modules comprising the IOD. +The following information must be specified for each Module in the +table: The name of the Module or Functional Group + +A reference to the Section in Annex C which defines the Module or +Functional Group + +The usage of the Module or Functional Group; whether it is: + +Mandatory (see A.1.3.1) , abbreviated M + +Conditional (see A.1.3.2) , abbreviated C + +User Option (see A.1.3.3) , abbreviated U The Modules referenced are +defined in Annex C. A.1.3.1 MANDATORY MODULES For each IOD, Mandatory +Modules shall be supported per the definitions, semantics and +requirements defined in Annex C. + +A.1.3.2 CONDITIONAL MODULES Conditional Modules are Mandatory Modules +if specific conditions are met. If the specified conditions are not +met, this Module shall not be supported; that is, no information +defined in that Module shall be sent. A.1.3.3 USER OPTION MODULES User +Option Modules may or may not be supported. If an optional Module is +supported, the Attribute Types specified in the Modules in Annex C +shall be supported. + +C++ includes: gdcmUsage.h "; + +%feature("docstring") gdcm::Usage::Usage "gdcm::Usage::Usage(UsageType type=Invalid) "; + + +// File: classgdcm_1_1UserEvent.xml +%feature("docstring") gdcm::UserEvent "C++ includes: gdcmEvent.h "; + + +// File: classgdcm_1_1network_1_1UserInformation.xml +%feature("docstring") gdcm::network::UserInformation " + +UserInformation Table 9-16 USER INFORMATION ITEM FIELDS. + +TODO what is the goal of : + +Table 9-20 USER INFORMATION ITEM FIELDS + +C++ includes: gdcmUserInformation.h "; + +%feature("docstring") gdcm::network::UserInformation::UserInformation +"gdcm::network::UserInformation::UserInformation() "; + +%feature("docstring") +gdcm::network::UserInformation::~UserInformation "gdcm::network::UserInformation::~UserInformation() "; + +%feature("docstring") +gdcm::network::UserInformation::GetMaximumLengthSub "MaximumLengthSub& +gdcm::network::UserInformation::GetMaximumLengthSub() "; + +%feature("docstring") +gdcm::network::UserInformation::GetMaximumLengthSub "const +MaximumLengthSub& +gdcm::network::UserInformation::GetMaximumLengthSub() const "; + +%feature("docstring") gdcm::network::UserInformation::Print "void +gdcm::network::UserInformation::Print(std::ostream &os) const "; + +%feature("docstring") gdcm::network::UserInformation::Read "std::istream& gdcm::network::UserInformation::Read(std::istream &is) +"; + +%feature("docstring") gdcm::network::UserInformation::Size "size_t +gdcm::network::UserInformation::Size() const "; + +%feature("docstring") gdcm::network::UserInformation::Write "const +std::ostream& gdcm::network::UserInformation::Write(std::ostream &os) +const "; + + +// File: classgdcm_1_1UUIDGenerator.xml +%feature("docstring") gdcm::UUIDGenerator " + +Class for generating unique UUID generate DCE 1.1 uid. + +C++ includes: gdcmUUIDGenerator.h "; + +%feature("docstring") gdcm::UUIDGenerator::Generate "const char* +gdcm::UUIDGenerator::Generate() + +Return the generated uuid NOT THREAD SAFE "; + + +// File: classstd_1_1valarray.xml +%feature("docstring") std::valarray " + +STL class. "; + + +// File: classgdcm_1_1Validate.xml +%feature("docstring") gdcm::Validate " + +Validate class. + +C++ includes: gdcmValidate.h "; + +%feature("docstring") gdcm::Validate::Validate "gdcm::Validate::Validate() "; + +%feature("docstring") gdcm::Validate::~Validate "gdcm::Validate::~Validate() "; + +%feature("docstring") gdcm::Validate::GetValidatedFile "const File& +gdcm::Validate::GetValidatedFile() "; + +%feature("docstring") gdcm::Validate::SetFile "void +gdcm::Validate::SetFile(File const &f) "; + +%feature("docstring") gdcm::Validate::Validation "void +gdcm::Validate::Validation() "; + + +// File: classgdcm_1_1Value.xml +%feature("docstring") gdcm::Value " + +Class to represent the value of a Data Element. + +VALUE: A component of a Value Field. A Value Field may consist of one +or more of these components. + +C++ includes: gdcmValue.h "; + +%feature("docstring") gdcm::Value::Value "gdcm::Value::Value() "; + +%feature("docstring") gdcm::Value::~Value "gdcm::Value::~Value() "; + +%feature("docstring") gdcm::Value::Clear "virtual void +gdcm::Value::Clear()=0 "; + +%feature("docstring") gdcm::Value::GetLength "virtual VL +gdcm::Value::GetLength() const =0 "; + +%feature("docstring") gdcm::Value::SetLength "virtual void +gdcm::Value::SetLength(VL l)=0 "; + + +// File: classgdcm_1_1ValueIO.xml +%feature("docstring") gdcm::ValueIO " + +Class to dispatch template calls. + +C++ includes: gdcmValueIO.h "; + + +// File: classstd_1_1vector.xml +%feature("docstring") std::vector " + +STL class. "; + + +// File: classgdcm_1_1Version.xml +%feature("docstring") gdcm::Version " + +major/minor and build version + +C++ includes: gdcmVersion.h "; + +%feature("docstring") gdcm::Version::Version "gdcm::Version::Version() "; + +%feature("docstring") gdcm::Version::~Version "gdcm::Version::~Version() "; + +%feature("docstring") gdcm::Version::Print "void +gdcm::Version::Print(std::ostream &os=std::cout) const "; + + +// File: classgdcm_1_1VL.xml +%feature("docstring") gdcm::VL " + +Value Length. + +WARNING: this is a 4bytes value ! Do not try to use it for 2bytes +value length + +C++ includes: gdcmVL.h "; + +%feature("docstring") gdcm::VL::VL "gdcm::VL::VL(uint32_t vl=0) "; + +%feature("docstring") gdcm::VL::GetLength "VL gdcm::VL::GetLength() +const "; + +%feature("docstring") gdcm::VL::IsOdd "bool gdcm::VL::IsOdd() const + +Return whether or not the VL is odd or not. "; + +%feature("docstring") gdcm::VL::IsUndefined "bool +gdcm::VL::IsUndefined() const "; + +%feature("docstring") gdcm::VL::Read "std::istream& +gdcm::VL::Read(std::istream &is) "; + +%feature("docstring") gdcm::VL::Read16 "std::istream& +gdcm::VL::Read16(std::istream &is) "; + +%feature("docstring") gdcm::VL::SetToUndefined "void +gdcm::VL::SetToUndefined() "; + +%feature("docstring") gdcm::VL::Write "const std::ostream& +gdcm::VL::Write(std::ostream &os) const "; + +%feature("docstring") gdcm::VL::Write16 "const std::ostream& +gdcm::VL::Write16(std::ostream &os) const "; + + +// File: classgdcm_1_1VM.xml +%feature("docstring") gdcm::VM " + +Value Multiplicity Looking at the DICOMV3 dict only there is very few +cases: 1 2 3 4 5 6 8 16 24 1-2 1-3 1-8 1-32 1-99 1-n 2-2n 2-n 3-3n +3-n. + +Some private dict define some more: 4-4n 1-4 1-5 256 9 3-4 + +even more: + +7-7n 10 18 12 35 47_47n 30_30n 28 + +6-6n + +C++ includes: gdcmVM.h "; + +%feature("docstring") gdcm::VM::VM "gdcm::VM::VM(VMType type=VM0) "; + +%feature("docstring") gdcm::VM::Compatible "bool +gdcm::VM::Compatible(VM const &vm) const + +WARNING: Implementation deficiency The Compatible function is poorly +implemented, the reference vm should be coming from the dictionary, +while the passed in value is the value guess from the file. "; + +%feature("docstring") gdcm::VM::GetLength "unsigned int +gdcm::VM::GetLength() const "; + + +// File: classgdcm_1_1VR.xml +%feature("docstring") gdcm::VR " + +VR class This is adapted from DICOM standard The biggest difference is +the INVALID VR and the composite one that differ from standard (more +like an addition) This allow us to represent all the possible case +express in the DICOMV3 dict. + +VALUE REPRESENTATION ( VR) Specifies the data type and format of the +Value(s) contained in the Value Field of a Data Element. VALUE +REPRESENTATION FIELD: The field where the Value Representation of a +Data Element is stored in the encoding of a Data Element structure +with explicit VR. + +C++ includes: gdcmVR.h "; + +%feature("docstring") gdcm::VR::VR "gdcm::VR::VR(VRType vr=INVALID) +"; + +%feature("docstring") gdcm::VR::Compatible "bool +gdcm::VR::Compatible(VR const &vr) const "; + +%feature("docstring") gdcm::VR::GetLength "int gdcm::VR::GetLength() +const "; + +%feature("docstring") gdcm::VR::GetSize "unsigned int +gdcm::VR::GetSize() const "; + +%feature("docstring") gdcm::VR::GetSizeof "unsigned int +gdcm::VR::GetSizeof() const "; + +%feature("docstring") gdcm::VR::IsDual "bool gdcm::VR::IsDual() +const "; + +%feature("docstring") gdcm::VR::IsVRFile "bool gdcm::VR::IsVRFile() +const "; + +%feature("docstring") gdcm::VR::Read "std::istream& +gdcm::VR::Read(std::istream &is) "; + +%feature("docstring") gdcm::VR::Write "const std::ostream& +gdcm::VR::Write(std::ostream &os) const "; + + +// File: classgdcm_1_1VR16ExplicitDataElement.xml +%feature("docstring") gdcm::VR16ExplicitDataElement " + +Class to read/write a DataElement as Explicit Data Element. + +This class support 16 bits when finding an unkown VR: For instance: +Siemens_CT_Sensation64_has_VR_RT.dcm + +C++ includes: gdcmVR16ExplicitDataElement.h "; + +%feature("docstring") gdcm::VR16ExplicitDataElement::GetLength "VL +gdcm::VR16ExplicitDataElement::GetLength() const "; + +%feature("docstring") gdcm::VR16ExplicitDataElement::Read "std::istream& gdcm::VR16ExplicitDataElement::Read(std::istream &is) "; + +%feature("docstring") gdcm::VR16ExplicitDataElement::ReadPreValue "std::istream& gdcm::VR16ExplicitDataElement::ReadPreValue(std::istream +&is) "; + +%feature("docstring") gdcm::VR16ExplicitDataElement::ReadValue "std::istream& gdcm::VR16ExplicitDataElement::ReadValue(std::istream +&is) "; + +%feature("docstring") gdcm::VR16ExplicitDataElement::ReadWithLength "std::istream& +gdcm::VR16ExplicitDataElement::ReadWithLength(std::istream &is, VL +&length) "; + + +// File: classgdcm_1_1VRVLSize_3_010_01_4.xml +%feature("docstring") gdcm::VRVLSize< 0 > " C++ includes: +gdcmAttribute.h "; + + +// File: classgdcm_1_1VRVLSize_3_011_01_4.xml +%feature("docstring") gdcm::VRVLSize< 1 > " C++ includes: +gdcmAttribute.h "; + + +// File: classvtkGDCMImageReader.xml +%feature("docstring") vtkGDCMImageReader "C++ includes: +vtkGDCMImageReader.h "; + +%feature("docstring") vtkGDCMImageReader::CanReadFile "virtual int +vtkGDCMImageReader::CanReadFile(const char *fname) "; + +%feature("docstring") vtkGDCMImageReader::GetDescriptiveName "virtual const char* vtkGDCMImageReader::GetDescriptiveName() "; + +%feature("docstring") vtkGDCMImageReader::GetFileExtensions "virtual +const char* vtkGDCMImageReader::GetFileExtensions() "; + +%feature("docstring") vtkGDCMImageReader::GetIconImage "vtkImageData* vtkGDCMImageReader::GetIconImage() "; + +%feature("docstring") vtkGDCMImageReader::GetOverlay "vtkImageData* +vtkGDCMImageReader::GetOverlay(int i) "; + +%feature("docstring") vtkGDCMImageReader::PrintSelf "virtual void +vtkGDCMImageReader::PrintSelf(ostream &os, vtkIndent indent) "; + +%feature("docstring") vtkGDCMImageReader::SetCurve "virtual void +vtkGDCMImageReader::SetCurve(vtkPolyData *pd) "; + +%feature("docstring") vtkGDCMImageReader::SetFileNames "virtual void +vtkGDCMImageReader::SetFileNames(vtkStringArray *) "; + +%feature("docstring") vtkGDCMImageReader::SetMedicalImageProperties "virtual void +vtkGDCMImageReader::SetMedicalImageProperties(vtkMedicalImageProperties +*pd) "; + +%feature("docstring") vtkGDCMImageReader::vtkBooleanMacro "vtkGDCMImageReader::vtkBooleanMacro(LoadIconImage, int) "; + +%feature("docstring") vtkGDCMImageReader::vtkBooleanMacro "vtkGDCMImageReader::vtkBooleanMacro(LossyFlag, int) "; + +%feature("docstring") vtkGDCMImageReader::vtkBooleanMacro "vtkGDCMImageReader::vtkBooleanMacro(LoadOverlays, int) "; + +%feature("docstring") vtkGDCMImageReader::vtkBooleanMacro "vtkGDCMImageReader::vtkBooleanMacro(ApplyLookupTable, int) "; + +%feature("docstring") vtkGDCMImageReader::vtkBooleanMacro "int +vtkGDCMImageReader::vtkBooleanMacro(ApplyYBRToRGB, int) "; + +%feature("docstring") vtkGDCMImageReader::vtkGetMacro "vtkGDCMImageReader::vtkGetMacro(ImageFormat, int) "; + +%feature("docstring") vtkGDCMImageReader::vtkGetMacro "vtkGDCMImageReader::vtkGetMacro(LoadOverlays, int) "; + +%feature("docstring") vtkGDCMImageReader::vtkGetMacro "vtkGDCMImageReader::vtkGetMacro(NumberOfIconImages, int) "; + +%feature("docstring") vtkGDCMImageReader::vtkGetMacro "vtkGDCMImageReader::vtkGetMacro(Scale, double) "; + +%feature("docstring") vtkGDCMImageReader::vtkGetMacro "vtkGDCMImageReader::vtkGetMacro(LossyFlag, int) "; + +%feature("docstring") vtkGDCMImageReader::vtkGetMacro "vtkGDCMImageReader::vtkGetMacro(NumberOfOverlays, int) "; + +%feature("docstring") vtkGDCMImageReader::vtkGetMacro "vtkGDCMImageReader::vtkGetMacro(Shift, double) "; + +%feature("docstring") vtkGDCMImageReader::vtkGetMacro "vtkGDCMImageReader::vtkGetMacro(ApplyLookupTable, int) "; + +%feature("docstring") vtkGDCMImageReader::vtkGetMacro "vtkGDCMImageReader::vtkGetMacro(PlanarConfiguration, int) "; + +%feature("docstring") vtkGDCMImageReader::vtkGetMacro "vtkGDCMImageReader::vtkGetMacro(ApplyYBRToRGB, int) +vtkSetMacro(ApplyYBRToRGB "; + +%feature("docstring") vtkGDCMImageReader::vtkGetMacro "vtkGDCMImageReader::vtkGetMacro(LoadIconImage, int) "; + +%feature("docstring") vtkGDCMImageReader::vtkGetObjectMacro "vtkGDCMImageReader::vtkGetObjectMacro(Curve, vtkPolyData) "; + +%feature("docstring") vtkGDCMImageReader::vtkGetObjectMacro "vtkGDCMImageReader::vtkGetObjectMacro(MedicalImageProperties, +vtkMedicalImageProperties) "; + +%feature("docstring") vtkGDCMImageReader::vtkGetObjectMacro "vtkGDCMImageReader::vtkGetObjectMacro(FileNames, vtkStringArray) "; + +%feature("docstring") vtkGDCMImageReader::vtkGetObjectMacro "vtkGDCMImageReader::vtkGetObjectMacro(DirectionCosines, vtkMatrix4x4) +"; + +%feature("docstring") vtkGDCMImageReader::vtkGetVector3Macro "vtkGDCMImageReader::vtkGetVector3Macro(ImagePositionPatient, double) +"; + +%feature("docstring") vtkGDCMImageReader::vtkGetVector6Macro "vtkGDCMImageReader::vtkGetVector6Macro(ImageOrientationPatient, +double) "; + +%feature("docstring") vtkGDCMImageReader::vtkSetMacro "vtkGDCMImageReader::vtkSetMacro(LoadOverlays, int) "; + +%feature("docstring") vtkGDCMImageReader::vtkSetMacro "vtkGDCMImageReader::vtkSetMacro(ApplyLookupTable, int) "; + +%feature("docstring") vtkGDCMImageReader::vtkSetMacro "vtkGDCMImageReader::vtkSetMacro(LoadIconImage, int) "; + +%feature("docstring") vtkGDCMImageReader::vtkSetMacro "vtkGDCMImageReader::vtkSetMacro(LossyFlag, int) "; + +%feature("docstring") vtkGDCMImageReader::vtkTypeRevisionMacro "vtkGDCMImageReader::vtkTypeRevisionMacro(vtkGDCMImageReader, +vtkMedicalImageReader2) "; + + +// File: classvtkGDCMImageWriter.xml +%feature("docstring") vtkGDCMImageWriter "C++ includes: +vtkGDCMImageWriter.h "; + +%feature("docstring") vtkGDCMImageWriter::GetDescriptiveName "virtual const char* vtkGDCMImageWriter::GetDescriptiveName() "; + +%feature("docstring") vtkGDCMImageWriter::GetFileExtensions "virtual +const char* vtkGDCMImageWriter::GetFileExtensions() "; + +%feature("docstring") vtkGDCMImageWriter::PrintSelf "virtual void +vtkGDCMImageWriter::PrintSelf(ostream &os, vtkIndent indent) "; + +%feature("docstring") vtkGDCMImageWriter::SetDirectionCosines "virtual void vtkGDCMImageWriter::SetDirectionCosines(vtkMatrix4x4 +*matrix) "; + +%feature("docstring") +vtkGDCMImageWriter::SetDirectionCosinesFromImageOrientationPatient "virtual void +vtkGDCMImageWriter::SetDirectionCosinesFromImageOrientationPatient(const +double dircos[6]) "; + +%feature("docstring") vtkGDCMImageWriter::SetFileNames "virtual void +vtkGDCMImageWriter::SetFileNames(vtkStringArray *) "; + +%feature("docstring") vtkGDCMImageWriter::SetMedicalImageProperties "virtual void +vtkGDCMImageWriter::SetMedicalImageProperties(vtkMedicalImageProperties +*) "; + +%feature("docstring") vtkGDCMImageWriter::vtkBooleanMacro "vtkGDCMImageWriter::vtkBooleanMacro(LossyFlag, int) "; + +%feature("docstring") vtkGDCMImageWriter::vtkBooleanMacro "vtkGDCMImageWriter::vtkBooleanMacro(FileLowerLeft, int) "; + +%feature("docstring") vtkGDCMImageWriter::vtkGetMacro "vtkGDCMImageWriter::vtkGetMacro(Shift, double) "; + +%feature("docstring") vtkGDCMImageWriter::vtkGetMacro "vtkGDCMImageWriter::vtkGetMacro(CompressionType, int) "; + +%feature("docstring") vtkGDCMImageWriter::vtkGetMacro "vtkGDCMImageWriter::vtkGetMacro(Scale, double) "; + +%feature("docstring") vtkGDCMImageWriter::vtkGetMacro "vtkGDCMImageWriter::vtkGetMacro(ImageFormat, int) "; + +%feature("docstring") vtkGDCMImageWriter::vtkGetMacro "vtkGDCMImageWriter::vtkGetMacro(FileLowerLeft, int) "; + +%feature("docstring") vtkGDCMImageWriter::vtkGetMacro "vtkGDCMImageWriter::vtkGetMacro(LossyFlag, int) "; + +%feature("docstring") vtkGDCMImageWriter::vtkGetMacro "vtkGDCMImageWriter::vtkGetMacro(PlanarConfiguration, int) "; + +%feature("docstring") vtkGDCMImageWriter::vtkGetObjectMacro "vtkGDCMImageWriter::vtkGetObjectMacro(FileNames, vtkStringArray) "; + +%feature("docstring") vtkGDCMImageWriter::vtkGetObjectMacro "vtkGDCMImageWriter::vtkGetObjectMacro(DirectionCosines, vtkMatrix4x4) +"; + +%feature("docstring") vtkGDCMImageWriter::vtkGetObjectMacro "vtkGDCMImageWriter::vtkGetObjectMacro(MedicalImageProperties, +vtkMedicalImageProperties) "; + +%feature("docstring") vtkGDCMImageWriter::vtkGetStringMacro "vtkGDCMImageWriter::vtkGetStringMacro(StudyUID) "; + +%feature("docstring") vtkGDCMImageWriter::vtkGetStringMacro "vtkGDCMImageWriter::vtkGetStringMacro(SeriesUID) "; + +%feature("docstring") vtkGDCMImageWriter::vtkSetMacro "vtkGDCMImageWriter::vtkSetMacro(PlanarConfiguration, int) "; + +%feature("docstring") vtkGDCMImageWriter::vtkSetMacro "vtkGDCMImageWriter::vtkSetMacro(CompressionType, int) "; + +%feature("docstring") vtkGDCMImageWriter::vtkSetMacro "vtkGDCMImageWriter::vtkSetMacro(Shift, double) "; + +%feature("docstring") vtkGDCMImageWriter::vtkSetMacro "vtkGDCMImageWriter::vtkSetMacro(FileLowerLeft, int) "; + +%feature("docstring") vtkGDCMImageWriter::vtkSetMacro "vtkGDCMImageWriter::vtkSetMacro(ImageFormat, int) "; + +%feature("docstring") vtkGDCMImageWriter::vtkSetMacro "vtkGDCMImageWriter::vtkSetMacro(Scale, double) "; + +%feature("docstring") vtkGDCMImageWriter::vtkSetMacro "vtkGDCMImageWriter::vtkSetMacro(LossyFlag, int) "; + +%feature("docstring") vtkGDCMImageWriter::vtkSetStringMacro "vtkGDCMImageWriter::vtkSetStringMacro(SeriesUID) "; + +%feature("docstring") vtkGDCMImageWriter::vtkSetStringMacro "vtkGDCMImageWriter::vtkSetStringMacro(StudyUID) "; + +%feature("docstring") vtkGDCMImageWriter::vtkTypeRevisionMacro "vtkGDCMImageWriter::vtkTypeRevisionMacro(vtkGDCMImageWriter, +vtkImageWriter) "; + +%feature("docstring") vtkGDCMImageWriter::Write "virtual void +vtkGDCMImageWriter::Write() "; + + +// File: classvtkGDCMMedicalImageProperties.xml +%feature("docstring") vtkGDCMMedicalImageProperties "C++ includes: +vtkGDCMMedicalImageProperties.h "; + +%feature("docstring") vtkGDCMMedicalImageProperties::Clear "virtual +void vtkGDCMMedicalImageProperties::Clear() "; + +%feature("docstring") vtkGDCMMedicalImageProperties::PrintSelf "void +vtkGDCMMedicalImageProperties::PrintSelf(ostream &os, vtkIndent +indent) "; + +%feature("docstring") +vtkGDCMMedicalImageProperties::vtkTypeRevisionMacro "vtkGDCMMedicalImageProperties::vtkTypeRevisionMacro(vtkGDCMMedicalImageProperties, +vtkMedicalImageProperties) "; + + +// File: classvtkGDCMPolyDataReader.xml +%feature("docstring") vtkGDCMPolyDataReader "C++ includes: +vtkGDCMPolyDataReader.h "; + +%feature("docstring") vtkGDCMPolyDataReader::PrintSelf "virtual void +vtkGDCMPolyDataReader::PrintSelf(ostream &os, vtkIndent indent) "; + +%feature("docstring") vtkGDCMPolyDataReader::vtkGetObjectMacro "vtkGDCMPolyDataReader::vtkGetObjectMacro(MedicalImageProperties, +vtkMedicalImageProperties) "; + +%feature("docstring") vtkGDCMPolyDataReader::vtkGetObjectMacro "vtkGDCMPolyDataReader::vtkGetObjectMacro(RTStructSetProperties, +vtkRTStructSetProperties) "; + +%feature("docstring") vtkGDCMPolyDataReader::vtkGetStringMacro "vtkGDCMPolyDataReader::vtkGetStringMacro(FileName) "; + +%feature("docstring") vtkGDCMPolyDataReader::vtkSetStringMacro "vtkGDCMPolyDataReader::vtkSetStringMacro(FileName) "; + +%feature("docstring") vtkGDCMPolyDataReader::vtkTypeRevisionMacro "vtkGDCMPolyDataReader::vtkTypeRevisionMacro(vtkGDCMPolyDataReader, +vtkPolyDataAlgorithm) "; + + +// File: classvtkGDCMPolyDataWriter.xml +%feature("docstring") vtkGDCMPolyDataWriter "C++ includes: +vtkGDCMPolyDataWriter.h "; + +%feature("docstring") vtkGDCMPolyDataWriter::InitializeRTStructSet "void vtkGDCMPolyDataWriter::InitializeRTStructSet(vtkStdString +inDirectory, vtkStdString inStructLabel, vtkStdString inStructName, +vtkStringArray *inROINames, vtkStringArray *inROIAlgorithmName, +vtkStringArray *inROIType) "; + +%feature("docstring") vtkGDCMPolyDataWriter::PrintSelf "virtual void +vtkGDCMPolyDataWriter::PrintSelf(ostream &os, vtkIndent indent) "; + +%feature("docstring") +vtkGDCMPolyDataWriter::SetMedicalImageProperties "virtual void +vtkGDCMPolyDataWriter::SetMedicalImageProperties(vtkMedicalImageProperties +*pd) "; + +%feature("docstring") vtkGDCMPolyDataWriter::SetNumberOfInputPorts "void vtkGDCMPolyDataWriter::SetNumberOfInputPorts(int n) "; + +%feature("docstring") vtkGDCMPolyDataWriter::SetRTStructSetProperties +"virtual void +vtkGDCMPolyDataWriter::SetRTStructSetProperties(vtkRTStructSetProperties +*pd) "; + +%feature("docstring") vtkGDCMPolyDataWriter::vtkTypeRevisionMacro "vtkGDCMPolyDataWriter::vtkTypeRevisionMacro(vtkGDCMPolyDataWriter, +vtkPolyDataWriter) "; + + +// File: classvtkGDCMTesting.xml +%feature("docstring") vtkGDCMTesting "C++ includes: vtkGDCMTesting.h +"; + +%feature("docstring") vtkGDCMTesting::PrintSelf "void +vtkGDCMTesting::PrintSelf(ostream &os, vtkIndent indent) "; + +%feature("docstring") vtkGDCMTesting::vtkTypeRevisionMacro "vtkGDCMTesting::vtkTypeRevisionMacro(vtkGDCMTesting, vtkObject) "; + + +// File: classvtkGDCMThreadedImageReader.xml +%feature("docstring") vtkGDCMThreadedImageReader "C++ includes: +vtkGDCMThreadedImageReader.h "; + +%feature("docstring") vtkGDCMThreadedImageReader::PrintSelf "virtual +void vtkGDCMThreadedImageReader::PrintSelf(ostream &os, vtkIndent +indent) "; + +%feature("docstring") vtkGDCMThreadedImageReader::vtkBooleanMacro "vtkGDCMThreadedImageReader::vtkBooleanMacro(UseShiftScale, int) "; + +%feature("docstring") vtkGDCMThreadedImageReader::vtkGetMacro "vtkGDCMThreadedImageReader::vtkGetMacro(UseShiftScale, int) "; + +%feature("docstring") vtkGDCMThreadedImageReader::vtkSetMacro "vtkGDCMThreadedImageReader::vtkSetMacro(UseShiftScale, int) "; + +%feature("docstring") vtkGDCMThreadedImageReader::vtkSetMacro "vtkGDCMThreadedImageReader::vtkSetMacro(Scale, double) "; + +%feature("docstring") vtkGDCMThreadedImageReader::vtkSetMacro "vtkGDCMThreadedImageReader::vtkSetMacro(Shift, double) "; + +%feature("docstring") +vtkGDCMThreadedImageReader::vtkTypeRevisionMacro "vtkGDCMThreadedImageReader::vtkTypeRevisionMacro(vtkGDCMThreadedImageReader, +vtkGDCMImageReader) "; + + +// File: classvtkGDCMThreadedImageReader2.xml +%feature("docstring") vtkGDCMThreadedImageReader2 "C++ includes: +vtkGDCMThreadedImageReader2.h "; + +%feature("docstring") vtkGDCMThreadedImageReader2::GetFileName "virtual const char* vtkGDCMThreadedImageReader2::GetFileName(int i=0) +"; + +%feature("docstring") vtkGDCMThreadedImageReader2::PrintSelf "virtual void vtkGDCMThreadedImageReader2::PrintSelf(ostream &os, +vtkIndent indent) "; + +%feature("docstring") vtkGDCMThreadedImageReader2::SetFileName "virtual void vtkGDCMThreadedImageReader2::SetFileName(const char +*filename) "; + +%feature("docstring") vtkGDCMThreadedImageReader2::SetFileNames "virtual void vtkGDCMThreadedImageReader2::SetFileNames(vtkStringArray +*) "; + +%feature("docstring") vtkGDCMThreadedImageReader2::SplitExtent "int +vtkGDCMThreadedImageReader2::SplitExtent(int splitExt[6], int +startExt[6], int num, int total) "; + +%feature("docstring") vtkGDCMThreadedImageReader2::vtkBooleanMacro "vtkGDCMThreadedImageReader2::vtkBooleanMacro(FileLowerLeft, int) "; + +%feature("docstring") vtkGDCMThreadedImageReader2::vtkBooleanMacro "vtkGDCMThreadedImageReader2::vtkBooleanMacro(LoadOverlays, int) "; + +%feature("docstring") vtkGDCMThreadedImageReader2::vtkBooleanMacro "vtkGDCMThreadedImageReader2::vtkBooleanMacro(UseShiftScale, int) "; + +%feature("docstring") vtkGDCMThreadedImageReader2::vtkGetMacro "vtkGDCMThreadedImageReader2::vtkGetMacro(DataScalarType, int) "; + +%feature("docstring") vtkGDCMThreadedImageReader2::vtkGetMacro "vtkGDCMThreadedImageReader2::vtkGetMacro(NumberOfScalarComponents, +int) "; + +%feature("docstring") vtkGDCMThreadedImageReader2::vtkGetMacro "vtkGDCMThreadedImageReader2::vtkGetMacro(UseShiftScale, int) "; + +%feature("docstring") vtkGDCMThreadedImageReader2::vtkGetMacro "vtkGDCMThreadedImageReader2::vtkGetMacro(LoadOverlays, int) "; + +%feature("docstring") vtkGDCMThreadedImageReader2::vtkGetMacro "vtkGDCMThreadedImageReader2::vtkGetMacro(FileLowerLeft, int) "; + +%feature("docstring") vtkGDCMThreadedImageReader2::vtkGetMacro "vtkGDCMThreadedImageReader2::vtkGetMacro(NumberOfOverlays, int) "; + +%feature("docstring") vtkGDCMThreadedImageReader2::vtkGetMacro "vtkGDCMThreadedImageReader2::vtkGetMacro(Shift, double) "; + +%feature("docstring") vtkGDCMThreadedImageReader2::vtkGetMacro "vtkGDCMThreadedImageReader2::vtkGetMacro(Scale, double) "; + +%feature("docstring") vtkGDCMThreadedImageReader2::vtkGetObjectMacro +"vtkGDCMThreadedImageReader2::vtkGetObjectMacro(FileNames, +vtkStringArray) "; + +%feature("docstring") vtkGDCMThreadedImageReader2::vtkGetVector3Macro +"vtkGDCMThreadedImageReader2::vtkGetVector3Macro(DataOrigin, double) +"; + +%feature("docstring") vtkGDCMThreadedImageReader2::vtkGetVector3Macro +"vtkGDCMThreadedImageReader2::vtkGetVector3Macro(DataSpacing, double) +"; + +%feature("docstring") vtkGDCMThreadedImageReader2::vtkGetVector6Macro +"vtkGDCMThreadedImageReader2::vtkGetVector6Macro(DataExtent, int) "; + +%feature("docstring") vtkGDCMThreadedImageReader2::vtkSetMacro "vtkGDCMThreadedImageReader2::vtkSetMacro(LoadOverlays, int) "; + +%feature("docstring") vtkGDCMThreadedImageReader2::vtkSetMacro "vtkGDCMThreadedImageReader2::vtkSetMacro(Scale, double) "; + +%feature("docstring") vtkGDCMThreadedImageReader2::vtkSetMacro "vtkGDCMThreadedImageReader2::vtkSetMacro(DataScalarType, int) "; + +%feature("docstring") vtkGDCMThreadedImageReader2::vtkSetMacro "vtkGDCMThreadedImageReader2::vtkSetMacro(UseShiftScale, int) "; + +%feature("docstring") vtkGDCMThreadedImageReader2::vtkSetMacro "vtkGDCMThreadedImageReader2::vtkSetMacro(Shift, double) "; + +%feature("docstring") vtkGDCMThreadedImageReader2::vtkSetMacro "vtkGDCMThreadedImageReader2::vtkSetMacro(NumberOfScalarComponents, +int) "; + +%feature("docstring") vtkGDCMThreadedImageReader2::vtkSetMacro "vtkGDCMThreadedImageReader2::vtkSetMacro(FileLowerLeft, int) "; + +%feature("docstring") vtkGDCMThreadedImageReader2::vtkSetVector3Macro +"vtkGDCMThreadedImageReader2::vtkSetVector3Macro(DataSpacing, double) +"; + +%feature("docstring") vtkGDCMThreadedImageReader2::vtkSetVector3Macro +"vtkGDCMThreadedImageReader2::vtkSetVector3Macro(DataOrigin, double) +"; + +%feature("docstring") vtkGDCMThreadedImageReader2::vtkSetVector6Macro +"vtkGDCMThreadedImageReader2::vtkSetVector6Macro(DataExtent, int) "; + +%feature("docstring") +vtkGDCMThreadedImageReader2::vtkTypeRevisionMacro "vtkGDCMThreadedImageReader2::vtkTypeRevisionMacro(vtkGDCMThreadedImageReader2, +vtkThreadedImageAlgorithm) "; + + +// File: classvtkImageColorViewer.xml +%feature("docstring") vtkImageColorViewer "C++ includes: +vtkImageColorViewer.h "; + +%feature("docstring") vtkImageColorViewer::AddInput "virtual void +vtkImageColorViewer::AddInput(vtkImageData *input) "; + +%feature("docstring") vtkImageColorViewer::AddInputConnection "virtual void +vtkImageColorViewer::AddInputConnection(vtkAlgorithmOutput *input) "; + +%feature("docstring") vtkImageColorViewer::GetColorLevel "virtual +double vtkImageColorViewer::GetColorLevel() "; + +%feature("docstring") vtkImageColorViewer::GetColorWindow "virtual +double vtkImageColorViewer::GetColorWindow() "; + +%feature("docstring") vtkImageColorViewer::GetInput "virtual +vtkImageData* vtkImageColorViewer::GetInput() "; + +%feature("docstring") vtkImageColorViewer::GetOffScreenRendering "virtual int vtkImageColorViewer::GetOffScreenRendering() "; + +%feature("docstring") vtkImageColorViewer::GetOverlayVisibility "double vtkImageColorViewer::GetOverlayVisibility() "; + +%feature("docstring") vtkImageColorViewer::GetPosition "virtual int* +vtkImageColorViewer::GetPosition() "; + +%feature("docstring") vtkImageColorViewer::GetSize "virtual int* +vtkImageColorViewer::GetSize() "; + +%feature("docstring") vtkImageColorViewer::GetSliceMax "virtual int +vtkImageColorViewer::GetSliceMax() "; + +%feature("docstring") vtkImageColorViewer::GetSliceMin "virtual int +vtkImageColorViewer::GetSliceMin() "; + +%feature("docstring") vtkImageColorViewer::GetSliceRange "virtual +void vtkImageColorViewer::GetSliceRange(int range[2]) "; + +%feature("docstring") vtkImageColorViewer::GetSliceRange "virtual +void vtkImageColorViewer::GetSliceRange(int &min, int &max) "; + +%feature("docstring") vtkImageColorViewer::GetSliceRange "virtual +int* vtkImageColorViewer::GetSliceRange() "; + +%feature("docstring") vtkImageColorViewer::GetWindowName "virtual +const char* vtkImageColorViewer::GetWindowName() "; + +%feature("docstring") vtkImageColorViewer::PrintSelf "void +vtkImageColorViewer::PrintSelf(ostream &os, vtkIndent indent) "; + +%feature("docstring") vtkImageColorViewer::Render "virtual void +vtkImageColorViewer::Render(void) "; + +%feature("docstring") vtkImageColorViewer::SetColorLevel "virtual +void vtkImageColorViewer::SetColorLevel(double s) "; + +%feature("docstring") vtkImageColorViewer::SetColorWindow "virtual +void vtkImageColorViewer::SetColorWindow(double s) "; + +%feature("docstring") vtkImageColorViewer::SetDisplayId "virtual +void vtkImageColorViewer::SetDisplayId(void *a) "; + +%feature("docstring") vtkImageColorViewer::SetInput "virtual void +vtkImageColorViewer::SetInput(vtkImageData *in) "; + +%feature("docstring") vtkImageColorViewer::SetInputConnection "virtual void +vtkImageColorViewer::SetInputConnection(vtkAlgorithmOutput *input) "; + +%feature("docstring") vtkImageColorViewer::SetOffScreenRendering "virtual void vtkImageColorViewer::SetOffScreenRendering(int) "; + +%feature("docstring") vtkImageColorViewer::SetOverlayVisibility "void vtkImageColorViewer::SetOverlayVisibility(double vis) "; + +%feature("docstring") vtkImageColorViewer::SetParentId "virtual void +vtkImageColorViewer::SetParentId(void *a) "; + +%feature("docstring") vtkImageColorViewer::SetPosition "virtual void +vtkImageColorViewer::SetPosition(int a, int b) "; + +%feature("docstring") vtkImageColorViewer::SetPosition "virtual void +vtkImageColorViewer::SetPosition(int a[2]) "; + +%feature("docstring") vtkImageColorViewer::SetRenderer "virtual void +vtkImageColorViewer::SetRenderer(vtkRenderer *arg) "; + +%feature("docstring") vtkImageColorViewer::SetRenderWindow "virtual +void vtkImageColorViewer::SetRenderWindow(vtkRenderWindow *arg) "; + +%feature("docstring") vtkImageColorViewer::SetSize "virtual void +vtkImageColorViewer::SetSize(int a, int b) "; + +%feature("docstring") vtkImageColorViewer::SetSize "virtual void +vtkImageColorViewer::SetSize(int a[2]) "; + +%feature("docstring") vtkImageColorViewer::SetSlice "virtual void +vtkImageColorViewer::SetSlice(int s) "; + +%feature("docstring") vtkImageColorViewer::SetSliceOrientation "virtual void vtkImageColorViewer::SetSliceOrientation(int orientation) +"; + +%feature("docstring") vtkImageColorViewer::SetSliceOrientationToXY "virtual void vtkImageColorViewer::SetSliceOrientationToXY() "; + +%feature("docstring") vtkImageColorViewer::SetSliceOrientationToXZ "virtual void vtkImageColorViewer::SetSliceOrientationToXZ() "; + +%feature("docstring") vtkImageColorViewer::SetSliceOrientationToYZ "virtual void vtkImageColorViewer::SetSliceOrientationToYZ() "; + +%feature("docstring") vtkImageColorViewer::SetupInteractor "virtual +void vtkImageColorViewer::SetupInteractor(vtkRenderWindowInteractor *) +"; + +%feature("docstring") vtkImageColorViewer::SetWindowId "virtual void +vtkImageColorViewer::SetWindowId(void *a) "; + +%feature("docstring") vtkImageColorViewer::UpdateDisplayExtent "virtual void vtkImageColorViewer::UpdateDisplayExtent() "; + +%feature("docstring") vtkImageColorViewer::VTK_LEGACY "vtkImageColorViewer::VTK_LEGACY(int GetWholeZMax()) "; + +%feature("docstring") vtkImageColorViewer::VTK_LEGACY "vtkImageColorViewer::VTK_LEGACY(int GetWholeZMin()) "; + +%feature("docstring") vtkImageColorViewer::VTK_LEGACY "vtkImageColorViewer::VTK_LEGACY(int GetZSlice()) "; + +%feature("docstring") vtkImageColorViewer::VTK_LEGACY "vtkImageColorViewer::VTK_LEGACY(void SetZSlice(int)) "; + +%feature("docstring") vtkImageColorViewer::vtkBooleanMacro "vtkImageColorViewer::vtkBooleanMacro(OffScreenRendering, int) "; + +%feature("docstring") vtkImageColorViewer::vtkGetMacro "vtkImageColorViewer::vtkGetMacro(Slice, int) "; + +%feature("docstring") vtkImageColorViewer::vtkGetMacro "vtkImageColorViewer::vtkGetMacro(SliceOrientation, int) "; + +%feature("docstring") vtkImageColorViewer::vtkGetObjectMacro "vtkImageColorViewer::vtkGetObjectMacro(WindowLevel, +vtkImageMapToWindowLevelColors2) "; + +%feature("docstring") vtkImageColorViewer::vtkGetObjectMacro "vtkImageColorViewer::vtkGetObjectMacro(InteractorStyle, +vtkInteractorStyleImage) "; + +%feature("docstring") vtkImageColorViewer::vtkGetObjectMacro "vtkImageColorViewer::vtkGetObjectMacro(Renderer, vtkRenderer) "; + +%feature("docstring") vtkImageColorViewer::vtkGetObjectMacro "vtkImageColorViewer::vtkGetObjectMacro(RenderWindow, vtkRenderWindow) +"; + +%feature("docstring") vtkImageColorViewer::vtkGetObjectMacro "vtkImageColorViewer::vtkGetObjectMacro(ImageActor, vtkImageActor) "; + +%feature("docstring") vtkImageColorViewer::vtkTypeRevisionMacro "vtkImageColorViewer::vtkTypeRevisionMacro(vtkImageColorViewer, +vtkObject) "; + + +// File: classvtkImageMapToColors16.xml +%feature("docstring") vtkImageMapToColors16 "C++ includes: +vtkImageMapToColors16.h "; + +%feature("docstring") vtkImageMapToColors16::GetMTime "virtual +unsigned long vtkImageMapToColors16::GetMTime() "; + +%feature("docstring") vtkImageMapToColors16::PrintSelf "void +vtkImageMapToColors16::PrintSelf(ostream &os, vtkIndent indent) "; + +%feature("docstring") vtkImageMapToColors16::SetLookupTable "virtual +void vtkImageMapToColors16::SetLookupTable(vtkScalarsToColors *) "; + +%feature("docstring") +vtkImageMapToColors16::SetOutputFormatToLuminance "void +vtkImageMapToColors16::SetOutputFormatToLuminance() "; + +%feature("docstring") +vtkImageMapToColors16::SetOutputFormatToLuminanceAlpha "void +vtkImageMapToColors16::SetOutputFormatToLuminanceAlpha() "; + +%feature("docstring") vtkImageMapToColors16::SetOutputFormatToRGB "void vtkImageMapToColors16::SetOutputFormatToRGB() "; + +%feature("docstring") vtkImageMapToColors16::SetOutputFormatToRGBA "void vtkImageMapToColors16::SetOutputFormatToRGBA() "; + +%feature("docstring") vtkImageMapToColors16::vtkBooleanMacro "vtkImageMapToColors16::vtkBooleanMacro(PassAlphaToOutput, int) "; + +%feature("docstring") vtkImageMapToColors16::vtkGetMacro "vtkImageMapToColors16::vtkGetMacro(ActiveComponent, int) "; + +%feature("docstring") vtkImageMapToColors16::vtkGetMacro "vtkImageMapToColors16::vtkGetMacro(PassAlphaToOutput, int) "; + +%feature("docstring") vtkImageMapToColors16::vtkGetMacro "vtkImageMapToColors16::vtkGetMacro(OutputFormat, int) "; + +%feature("docstring") vtkImageMapToColors16::vtkGetObjectMacro "vtkImageMapToColors16::vtkGetObjectMacro(LookupTable, +vtkScalarsToColors) "; + +%feature("docstring") vtkImageMapToColors16::vtkSetMacro "vtkImageMapToColors16::vtkSetMacro(PassAlphaToOutput, int) "; + +%feature("docstring") vtkImageMapToColors16::vtkSetMacro "vtkImageMapToColors16::vtkSetMacro(OutputFormat, int) "; + +%feature("docstring") vtkImageMapToColors16::vtkSetMacro "vtkImageMapToColors16::vtkSetMacro(ActiveComponent, int) "; + +%feature("docstring") vtkImageMapToColors16::vtkTypeRevisionMacro "vtkImageMapToColors16::vtkTypeRevisionMacro(vtkImageMapToColors16, +vtkThreadedImageAlgorithm) "; + + +// File: classvtkImageMapToWindowLevelColors2.xml +%feature("docstring") vtkImageMapToWindowLevelColors2 "C++ includes: +vtkImageMapToWindowLevelColors2.h "; + +%feature("docstring") vtkImageMapToWindowLevelColors2::PrintSelf "void vtkImageMapToWindowLevelColors2::PrintSelf(ostream &os, vtkIndent +indent) "; + +%feature("docstring") vtkImageMapToWindowLevelColors2::vtkGetMacro "vtkImageMapToWindowLevelColors2::vtkGetMacro(Window, double) "; + +%feature("docstring") vtkImageMapToWindowLevelColors2::vtkGetMacro "vtkImageMapToWindowLevelColors2::vtkGetMacro(Level, double) "; + +%feature("docstring") vtkImageMapToWindowLevelColors2::vtkSetMacro "vtkImageMapToWindowLevelColors2::vtkSetMacro(Window, double) "; + +%feature("docstring") vtkImageMapToWindowLevelColors2::vtkSetMacro "vtkImageMapToWindowLevelColors2::vtkSetMacro(Level, double) "; + +%feature("docstring") +vtkImageMapToWindowLevelColors2::vtkTypeRevisionMacro "vtkImageMapToWindowLevelColors2::vtkTypeRevisionMacro(vtkImageMapToWindowLevelColors2, +vtkImageMapToColors) "; + + +// File: classvtkImagePlanarComponentsToComponents.xml +%feature("docstring") vtkImagePlanarComponentsToComponents "C++ +includes: vtkImagePlanarComponentsToComponents.h "; + +%feature("docstring") vtkImagePlanarComponentsToComponents::PrintSelf +"void vtkImagePlanarComponentsToComponents::PrintSelf(ostream &os, +vtkIndent indent) "; + +%feature("docstring") +vtkImagePlanarComponentsToComponents::vtkTypeRevisionMacro "vtkImagePlanarComponentsToComponents::vtkTypeRevisionMacro(vtkImagePlanarComponentsToComponents, +vtkImageAlgorithm) "; + + +// File: classvtkImageRGBToYBR.xml +%feature("docstring") vtkImageRGBToYBR "C++ includes: +vtkImageRGBToYBR.h "; + +%feature("docstring") vtkImageRGBToYBR::PrintSelf "void +vtkImageRGBToYBR::PrintSelf(ostream &os, vtkIndent indent) "; + +%feature("docstring") vtkImageRGBToYBR::vtkTypeRevisionMacro "vtkImageRGBToYBR::vtkTypeRevisionMacro(vtkImageRGBToYBR, +vtkThreadedImageAlgorithm) "; + + +// File: classvtkImageYBRToRGB.xml +%feature("docstring") vtkImageYBRToRGB "C++ includes: +vtkImageYBRToRGB.h "; + +%feature("docstring") vtkImageYBRToRGB::PrintSelf "void +vtkImageYBRToRGB::PrintSelf(ostream &os, vtkIndent indent) "; + +%feature("docstring") vtkImageYBRToRGB::vtkTypeRevisionMacro "vtkImageYBRToRGB::vtkTypeRevisionMacro(vtkImageYBRToRGB, +vtkThreadedImageAlgorithm) "; + + +// File: classvtkLookupTable16.xml +%feature("docstring") vtkLookupTable16 "C++ includes: +vtkLookupTable16.h "; + +%feature("docstring") vtkLookupTable16::Build "void +vtkLookupTable16::Build() "; + +%feature("docstring") vtkLookupTable16::GetPointer "unsigned short* +vtkLookupTable16::GetPointer(const vtkIdType id) "; + +%feature("docstring") vtkLookupTable16::PrintSelf "void +vtkLookupTable16::PrintSelf(ostream &os, vtkIndent indent) "; + +%feature("docstring") vtkLookupTable16::SetNumberOfTableValues "void +vtkLookupTable16::SetNumberOfTableValues(vtkIdType number) "; + +%feature("docstring") vtkLookupTable16::vtkTypeRevisionMacro "vtkLookupTable16::vtkTypeRevisionMacro(vtkLookupTable16, +vtkLookupTable) "; + +%feature("docstring") vtkLookupTable16::WritePointer "unsigned char +* vtkLookupTable16::WritePointer(const vtkIdType id, const int number) +"; + + +// File: classvtkRTStructSetProperties.xml +%feature("docstring") vtkRTStructSetProperties "C++ includes: +vtkRTStructSetProperties.h "; + +%feature("docstring") +vtkRTStructSetProperties::AddContourReferencedFrameOfReference "void +vtkRTStructSetProperties::AddContourReferencedFrameOfReference(vtkIdType +pdnum, const char *classuid, const char *instanceuid) "; + +%feature("docstring") +vtkRTStructSetProperties::AddReferencedFrameOfReference "void +vtkRTStructSetProperties::AddReferencedFrameOfReference(const char +*classuid, const char *instanceuid) "; + +%feature("docstring") vtkRTStructSetProperties::AddStructureSetROI "void vtkRTStructSetProperties::AddStructureSetROI(int roinumber, const +char *refframerefuid, const char *roiname, const char +*ROIGenerationAlgorithm, const char *ROIDescription=0) "; + +%feature("docstring") +vtkRTStructSetProperties::AddStructureSetROIObservation "void +vtkRTStructSetProperties::AddStructureSetROIObservation(int refnumber, +int observationnumber, const char *rtroiinterpretedtype, const char +*roiinterpreter, const char *roiobservationlabel=0) "; + +%feature("docstring") vtkRTStructSetProperties::Clear "virtual void +vtkRTStructSetProperties::Clear() "; + +%feature("docstring") vtkRTStructSetProperties::DeepCopy "virtual +void vtkRTStructSetProperties::DeepCopy(vtkRTStructSetProperties *p) +"; + +%feature("docstring") +vtkRTStructSetProperties::GetContourReferencedFrameOfReferenceClassUID +"const char* +vtkRTStructSetProperties::GetContourReferencedFrameOfReferenceClassUID(vtkIdType +pdnum, vtkIdType id) "; + +%feature("docstring") +vtkRTStructSetProperties::GetContourReferencedFrameOfReferenceInstanceUID +"const char* +vtkRTStructSetProperties::GetContourReferencedFrameOfReferenceInstanceUID(vtkIdType +pdnum, vtkIdType id) "; + +%feature("docstring") +vtkRTStructSetProperties::GetNumberOfContourReferencedFrameOfReferences +"vtkIdType +vtkRTStructSetProperties::GetNumberOfContourReferencedFrameOfReferences() +"; + +%feature("docstring") +vtkRTStructSetProperties::GetNumberOfContourReferencedFrameOfReferences +"vtkIdType +vtkRTStructSetProperties::GetNumberOfContourReferencedFrameOfReferences(vtkIdType +pdnum) "; + +%feature("docstring") +vtkRTStructSetProperties::GetNumberOfReferencedFrameOfReferences "vtkIdType +vtkRTStructSetProperties::GetNumberOfReferencedFrameOfReferences() "; + +%feature("docstring") +vtkRTStructSetProperties::GetNumberOfStructureSetROIs "vtkIdType +vtkRTStructSetProperties::GetNumberOfStructureSetROIs() "; + +%feature("docstring") +vtkRTStructSetProperties::GetReferencedFrameOfReferenceClassUID "const char* +vtkRTStructSetProperties::GetReferencedFrameOfReferenceClassUID(vtkIdType +id) "; + +%feature("docstring") +vtkRTStructSetProperties::GetReferencedFrameOfReferenceInstanceUID "const char* +vtkRTStructSetProperties::GetReferencedFrameOfReferenceInstanceUID(vtkIdType +id) "; + +%feature("docstring") +vtkRTStructSetProperties::GetStructureSetObservationNumber "int +vtkRTStructSetProperties::GetStructureSetObservationNumber(vtkIdType +id) "; + +%feature("docstring") +vtkRTStructSetProperties::GetStructureSetROIDescription "const char* +vtkRTStructSetProperties::GetStructureSetROIDescription(vtkIdType id) +"; + +%feature("docstring") +vtkRTStructSetProperties::GetStructureSetROIGenerationAlgorithm "const char* +vtkRTStructSetProperties::GetStructureSetROIGenerationAlgorithm(vtkIdType) +"; + +%feature("docstring") +vtkRTStructSetProperties::GetStructureSetROIName "const char* +vtkRTStructSetProperties::GetStructureSetROIName(vtkIdType) "; + +%feature("docstring") +vtkRTStructSetProperties::GetStructureSetROINumber "int +vtkRTStructSetProperties::GetStructureSetROINumber(vtkIdType id) "; + +%feature("docstring") +vtkRTStructSetProperties::GetStructureSetROIObservationLabel "const +char* +vtkRTStructSetProperties::GetStructureSetROIObservationLabel(vtkIdType +id) "; + +%feature("docstring") +vtkRTStructSetProperties::GetStructureSetROIRefFrameRefUID "const +char* +vtkRTStructSetProperties::GetStructureSetROIRefFrameRefUID(vtkIdType) +"; + +%feature("docstring") +vtkRTStructSetProperties::GetStructureSetRTROIInterpretedType "const +char* +vtkRTStructSetProperties::GetStructureSetRTROIInterpretedType(vtkIdType +id) "; + +%feature("docstring") vtkRTStructSetProperties::PrintSelf "void +vtkRTStructSetProperties::PrintSelf(ostream &os, vtkIndent indent) "; + +%feature("docstring") vtkRTStructSetProperties::vtkGetStringMacro "vtkRTStructSetProperties::vtkGetStringMacro(StructureSetDate) "; + +%feature("docstring") vtkRTStructSetProperties::vtkGetStringMacro "vtkRTStructSetProperties::vtkGetStringMacro(SeriesInstanceUID) "; + +%feature("docstring") vtkRTStructSetProperties::vtkGetStringMacro "vtkRTStructSetProperties::vtkGetStringMacro(ReferenceFrameOfReferenceUID) +"; + +%feature("docstring") vtkRTStructSetProperties::vtkGetStringMacro "vtkRTStructSetProperties::vtkGetStringMacro(StructureSetTime) "; + +%feature("docstring") vtkRTStructSetProperties::vtkGetStringMacro "vtkRTStructSetProperties::vtkGetStringMacro(StructureSetLabel) "; + +%feature("docstring") vtkRTStructSetProperties::vtkGetStringMacro "vtkRTStructSetProperties::vtkGetStringMacro(StudyInstanceUID) "; + +%feature("docstring") vtkRTStructSetProperties::vtkGetStringMacro "vtkRTStructSetProperties::vtkGetStringMacro(SOPInstanceUID) "; + +%feature("docstring") vtkRTStructSetProperties::vtkGetStringMacro "vtkRTStructSetProperties::vtkGetStringMacro(ReferenceSeriesInstanceUID) +"; + +%feature("docstring") vtkRTStructSetProperties::vtkGetStringMacro "vtkRTStructSetProperties::vtkGetStringMacro(StructureSetName) "; + +%feature("docstring") vtkRTStructSetProperties::vtkSetStringMacro "vtkRTStructSetProperties::vtkSetStringMacro(StudyInstanceUID) "; + +%feature("docstring") vtkRTStructSetProperties::vtkSetStringMacro "vtkRTStructSetProperties::vtkSetStringMacro(ReferenceFrameOfReferenceUID) +"; + +%feature("docstring") vtkRTStructSetProperties::vtkSetStringMacro "vtkRTStructSetProperties::vtkSetStringMacro(ReferenceSeriesInstanceUID) +"; + +%feature("docstring") vtkRTStructSetProperties::vtkSetStringMacro "vtkRTStructSetProperties::vtkSetStringMacro(StructureSetName) "; + +%feature("docstring") vtkRTStructSetProperties::vtkSetStringMacro "vtkRTStructSetProperties::vtkSetStringMacro(SeriesInstanceUID) "; + +%feature("docstring") vtkRTStructSetProperties::vtkSetStringMacro "vtkRTStructSetProperties::vtkSetStringMacro(StructureSetTime) "; + +%feature("docstring") vtkRTStructSetProperties::vtkSetStringMacro "vtkRTStructSetProperties::vtkSetStringMacro(StructureSetLabel) "; + +%feature("docstring") vtkRTStructSetProperties::vtkSetStringMacro "vtkRTStructSetProperties::vtkSetStringMacro(SOPInstanceUID) "; + +%feature("docstring") vtkRTStructSetProperties::vtkSetStringMacro "vtkRTStructSetProperties::vtkSetStringMacro(StructureSetDate) "; + +%feature("docstring") vtkRTStructSetProperties::vtkTypeRevisionMacro +"vtkRTStructSetProperties::vtkTypeRevisionMacro(vtkRTStructSetProperties, +vtkObject) "; + + +// File: classgdcm_1_1Waveform.xml +%feature("docstring") gdcm::Waveform " + +Waveform class. + +C++ includes: gdcmWaveform.h "; + +%feature("docstring") gdcm::Waveform::Waveform "gdcm::Waveform::Waveform() "; + + +// File: classstd_1_1wfstream.xml +%feature("docstring") std::wfstream " + +STL class. "; + + +// File: classstd_1_1wifstream.xml +%feature("docstring") std::wifstream " + +STL class. "; + + +// File: classstd_1_1wios.xml +%feature("docstring") std::wios " + +STL class. "; + + +// File: classstd_1_1wistream.xml +%feature("docstring") std::wistream " + +STL class. "; + + +// File: classstd_1_1wistringstream.xml +%feature("docstring") std::wistringstream " + +STL class. "; + + +// File: classstd_1_1wofstream.xml +%feature("docstring") std::wofstream " + +STL class. "; + + +// File: classstd_1_1wostream.xml +%feature("docstring") std::wostream " + +STL class. "; + + +// File: classstd_1_1wostringstream.xml +%feature("docstring") std::wostringstream " + +STL class. "; + + +// File: classgdcm_1_1Writer.xml +%feature("docstring") gdcm::Writer " + +Writer ala DOM (Document Object Model) This class is a non-validating +writer, it will only performs well- formedness check only. + +Detailled description here To avoid GDCM being yet another broken +DICOM lib we try to be user level and avoid writing illegal stuff (odd +length, non-zero value for Item start/end length ...) Therefore you +cannot (well unless you are really smart) write DICOM with even length +tag. All the checks are consider basics: Correct Meta Information +Header (see gdcm::FileMetaInformation) + +Zero value for Item Length (0xfffe, 0xe00d/0xe0dd) + +Even length for any elements + +Alphabetical order for elements (garanteed by design of internals) + +32bits VR will be rewritten with 00 + +WARNING: gdcm::Writer cannot write a DataSet if no SOP Instance UID +(0008,0018) is found, unless a DICOMDIR is being written out + +See: Reader DataSet File + +C++ includes: gdcmWriter.h "; + +%feature("docstring") gdcm::Writer::Writer "gdcm::Writer::Writer() +"; + +%feature("docstring") gdcm::Writer::~Writer "virtual +gdcm::Writer::~Writer() "; + +%feature("docstring") gdcm::Writer::CheckFileMetaInformationOff "void gdcm::Writer::CheckFileMetaInformationOff() "; + +%feature("docstring") gdcm::Writer::CheckFileMetaInformationOn "void +gdcm::Writer::CheckFileMetaInformationOn() "; + +%feature("docstring") gdcm::Writer::GetFile "File& +gdcm::Writer::GetFile() "; + +%feature("docstring") gdcm::Writer::SetCheckFileMetaInformation "void gdcm::Writer::SetCheckFileMetaInformation(bool b) + +Undocumented function, do not use (= leave default). "; + +%feature("docstring") gdcm::Writer::SetFile "void +gdcm::Writer::SetFile(const File &f) + +Set/Get the DICOM file ( DataSet + Header). "; + +%feature("docstring") gdcm::Writer::SetFileName "void +gdcm::Writer::SetFileName(const char *filename_native) + +Set the filename of DICOM file to write: "; + +%feature("docstring") gdcm::Writer::SetStream "void +gdcm::Writer::SetStream(std::ostream &output_stream) + +Set user ostream buffer. "; + +%feature("docstring") gdcm::Writer::Write "virtual bool +gdcm::Writer::Write() + +Main function to tell the writer to write. "; + + +// File: classstd_1_1wstring.xml +%feature("docstring") std::wstring " + +STL class. "; + + +// File: classstd_1_1wstringstream.xml +%feature("docstring") std::wstringstream " + +STL class. "; + + +// File: classgdcm_1_1XMLDictReader.xml +%feature("docstring") gdcm::XMLDictReader " + +Class for representing a XMLDictReader. + +bla Will read the DICOMV3.xml file + +C++ includes: gdcmXMLDictReader.h "; + +%feature("docstring") gdcm::XMLDictReader::XMLDictReader "gdcm::XMLDictReader::XMLDictReader() "; + +%feature("docstring") gdcm::XMLDictReader::~XMLDictReader "gdcm::XMLDictReader::~XMLDictReader() "; + +%feature("docstring") gdcm::XMLDictReader::CharacterDataHandler "void gdcm::XMLDictReader::CharacterDataHandler(const char *data, int +length) "; + +%feature("docstring") gdcm::XMLDictReader::EndElement "void +gdcm::XMLDictReader::EndElement(const char *name) "; + +%feature("docstring") gdcm::XMLDictReader::GetDict "const Dict& +gdcm::XMLDictReader::GetDict() "; + +%feature("docstring") gdcm::XMLDictReader::StartElement "void +gdcm::XMLDictReader::StartElement(const char *name, const char **atts) +"; + + +// File: classgdcm_1_1XMLPrinter.xml +%feature("docstring") gdcm::XMLPrinter "C++ includes: +gdcmXMLPrinter.h "; + +%feature("docstring") gdcm::XMLPrinter::XMLPrinter "gdcm::XMLPrinter::XMLPrinter() "; + +%feature("docstring") gdcm::XMLPrinter::~XMLPrinter "gdcm::XMLPrinter::~XMLPrinter() "; + +%feature("docstring") gdcm::XMLPrinter::GetPrintStyle "PrintStyles +gdcm::XMLPrinter::GetPrintStyle() const "; + +%feature("docstring") gdcm::XMLPrinter::HandleBulkData "virtual void +gdcm::XMLPrinter::HandleBulkData(const char *uuid, const +TransferSyntax &ts, const char *bulkdata, size_t bulklen) + +Virtual function mecanism to allow application programmer to override +the default mecanism for BulkData handling. By default GDCM will +simply discard the BulkData and only write the UUID "; + +%feature("docstring") gdcm::XMLPrinter::Print "void +gdcm::XMLPrinter::Print(std::ostream &os) "; + +%feature("docstring") gdcm::XMLPrinter::PrintDataSet "void +gdcm::XMLPrinter::PrintDataSet(const DataSet &ds, const TransferSyntax +&ts, std::ostream &os) "; + +%feature("docstring") gdcm::XMLPrinter::SetFile "void +gdcm::XMLPrinter::SetFile(File const &f) "; + +%feature("docstring") gdcm::XMLPrinter::SetStyle "void +gdcm::XMLPrinter::SetStyle(PrintStyles ps) "; + + +// File: classgdcm_1_1XMLPrivateDictReader.xml +%feature("docstring") gdcm::XMLPrivateDictReader " + +Class for representing a XMLPrivateDictReader. + +bla Will read the Private.xml file + +C++ includes: gdcmXMLPrivateDictReader.h "; + +%feature("docstring") +gdcm::XMLPrivateDictReader::XMLPrivateDictReader "gdcm::XMLPrivateDictReader::XMLPrivateDictReader() "; + +%feature("docstring") +gdcm::XMLPrivateDictReader::~XMLPrivateDictReader "gdcm::XMLPrivateDictReader::~XMLPrivateDictReader() "; + +%feature("docstring") +gdcm::XMLPrivateDictReader::CharacterDataHandler "void +gdcm::XMLPrivateDictReader::CharacterDataHandler(const char *data, int +length) "; + +%feature("docstring") gdcm::XMLPrivateDictReader::EndElement "void +gdcm::XMLPrivateDictReader::EndElement(const char *name) "; + +%feature("docstring") gdcm::XMLPrivateDictReader::GetPrivateDict "const PrivateDict& gdcm::XMLPrivateDictReader::GetPrivateDict() "; + +%feature("docstring") gdcm::XMLPrivateDictReader::StartElement "void +gdcm::XMLPrivateDictReader::StartElement(const char *name, const char +**atts) "; + + +// File: namespacegdcm.xml +%feature("docstring") gdcm::network::backslash "ignore_char const +gdcm::backslash('\\\\\\\\') "; + +%feature("docstring") gdcm::network::GetVRFromTag "VR::VRType +gdcm::GetVRFromTag(Tag const &tag) "; + +%feature("docstring") gdcm::network::to_string "std::string +gdcm::to_string(Float data) "; + +%feature("docstring") gdcm::network::TYPETOENCODING "gdcm::TYPETOENCODING(SQ, VRBINARY, unsigned char) TYPETOENCODING(UN "; + + +// File: namespacegdcm_1_1network.xml +%feature("docstring") gdcm::network::GetStateIndex "int +gdcm::network::GetStateIndex(EStateID inState) "; + + +// File: namespacegdcm_1_1SegmentHelper.xml + + +// File: namespacegdcm_1_1terminal.xml +%feature("docstring") gdcm::terminal::setattribute "GDCM_EXPORT +std::string gdcm::terminal::setattribute(Attribute att) "; + +%feature("docstring") gdcm::terminal::setbgcolor "GDCM_EXPORT +std::string gdcm::terminal::setbgcolor(Color c) "; + +%feature("docstring") gdcm::terminal::setfgcolor "GDCM_EXPORT +std::string gdcm::terminal::setfgcolor(Color c) "; + +%feature("docstring") gdcm::terminal::setmode "GDCM_EXPORT void +gdcm::terminal::setmode(Mode m) "; + + +// File: namespacestd.xml + + +// File: gdcm2pnm_8man.xml + + +// File: gdcm2vtk_8man.xml + + +// File: gdcmAAbortPDU_8h.xml + + +// File: gdcmAAssociateACPDU_8h.xml + + +// File: gdcmAAssociateRJPDU_8h.xml + + +// File: gdcmAAssociateRQPDU_8h.xml + + +// File: gdcmAbstractSyntax_8h.xml + + +// File: gdcmanon_8man.xml + + +// File: gdcmAnonymizeEvent_8h.xml + + +// File: gdcmAnonymizer_8h.xml + + +// File: gdcmApplicationContext_8h.xml + + +// File: gdcmApplicationEntity_8h.xml + + +// File: gdcmAReleaseRPPDU_8h.xml + + +// File: gdcmAReleaseRQPDU_8h.xml + + +// File: gdcmARTIMTimer_8h.xml + + +// File: gdcmASN1_8h.xml + + +// File: gdcmAsynchronousOperationsWindowSub_8h.xml + + +// File: gdcmAttribute_8h.xml + + +// File: gdcmAudioCodec_8h.xml + + +// File: gdcmBase64_8h.xml + + +// File: gdcmBaseCompositeMessage_8h.xml + + +// File: gdcmBasePDU_8h.xml + + +// File: gdcmBaseRootQuery_8h.xml + + +// File: gdcmBasicOffsetTable_8h.xml + + +// File: gdcmBitmap_8h.xml + + +// File: gdcmBitmapToBitmapFilter_8h.xml + + +// File: gdcmBoxRegion_8h.xml + + +// File: gdcmByteBuffer_8h.xml + + +// File: gdcmByteSwap_8h.xml + + +// File: gdcmByteSwapFilter_8h.xml + + +// File: gdcmByteValue_8h.xml + + +// File: gdcmCAPICryptoFactory_8h.xml + + +// File: gdcmCAPICryptographicMessageSyntax_8h.xml + + +// File: gdcmCEchoMessages_8h.xml + + +// File: gdcmCFindMessages_8h.xml + + +// File: gdcmCMoveMessages_8h.xml + + +// File: gdcmCodec_8h.xml + + +// File: gdcmCoder_8h.xml + + +// File: gdcmCodeString_8h.xml + + +// File: gdcmCommand_8h.xml + + +// File: gdcmCommandDataSet_8h.xml + + +// File: gdcmCompositeMessageFactory_8h.xml + + +// File: gdcmCompositeNetworkFunctions_8h.xml + + +// File: gdcmConstCharWrapper_8h.xml + + +// File: gdcmconv_8man.xml + + +// File: gdcmCP246ExplicitDataElement_8h.xml + + +// File: gdcmCryptoFactory_8h.xml + + +// File: gdcmCryptographicMessageSyntax_8h.xml + + +// File: gdcmCSAElement_8h.xml + + +// File: gdcmCSAHeader_8h.xml + + +// File: gdcmCSAHeaderDict_8h.xml + + +// File: gdcmCSAHeaderDictEntry_8h.xml + + +// File: gdcmCStoreMessages_8h.xml + + +// File: gdcmCurve_8h.xml + + +// File: gdcmDataElement_8h.xml + + +// File: gdcmDataEvent_8h.xml + + +// File: gdcmDataSet_8h.xml + + +// File: gdcmDataSetEvent_8h.xml + + +// File: gdcmDataSetHelper_8h.xml + + +// File: gdcmDecoder_8h.xml + + +// File: gdcmDefinedTerms_8h.xml + + +// File: gdcmDeflateStream_8h.xml + + +// File: gdcmDefs_8h.xml + + +// File: gdcmDeltaEncodingCodec_8h.xml + + +// File: gdcmDICOMDIR_8h.xml + + +// File: gdcmDICOMDIRGenerator_8h.xml + + +// File: gdcmDict_8h.xml + + +// File: gdcmDictConverter_8h.xml + + +// File: gdcmDictEntry_8h.xml + + +// File: gdcmDictPrinter_8h.xml + + +// File: gdcmDicts_8h.xml + + +// File: gdcmdiff_8man.xml + + +// File: gdcmDIMSE_8h.xml + + +// File: gdcmDirectionCosines_8h.xml + + +// File: gdcmDirectory_8h.xml + + +// File: gdcmDirectoryHelper_8h.xml + + +// File: gdcmDummyValueGenerator_8h.xml + + +// File: gdcmdump_8man.xml + + +// File: gdcmDumper_8h.xml + + +// File: gdcmElement_8h.xml + + +// File: gdcmEncapsulatedDocument_8h.xml + + +// File: gdcmEnumeratedValues_8h.xml + + +// File: gdcmEvent_8h.xml + + +// File: gdcmException_8h.xml + + +// File: gdcmExplicitDataElement_8h.xml + + +// File: gdcmExplicitImplicitDataElement_8h.xml + + +// File: gdcmFiducials_8h.xml + + +// File: gdcmFile_8h.xml + + +// File: gdcmFileAnonymizer_8h.xml + + +// File: gdcmFileDerivation_8h.xml + + +// File: gdcmFileExplicitFilter_8h.xml + + +// File: gdcmFileMetaInformation_8h.xml + + +// File: gdcmFilename_8h.xml + + +// File: gdcmFileNameEvent_8h.xml + + +// File: gdcmFilenameGenerator_8h.xml + + +// File: gdcmFileSet_8h.xml + + +// File: gdcmFindPatientRootQuery_8h.xml + + +// File: gdcmFindStudyRootQuery_8h.xml + + +// File: gdcmFragment_8h.xml + + +// File: gdcmgendir_8man.xml + + +// File: gdcmGlobal_8h.xml + + +// File: gdcmGroupDict_8h.xml + + +// File: gdcmIconImage_8h.xml + + +// File: gdcmIconImageFilter_8h.xml + + +// File: gdcmIconImageGenerator_8h.xml + + +// File: gdcmImage_8h.xml + + +// File: gdcmImageApplyLookupTable_8h.xml + + +// File: gdcmImageChangePhotometricInterpretation_8h.xml + + +// File: gdcmImageChangePlanarConfiguration_8h.xml + + +// File: gdcmImageChangeTransferSyntax_8h.xml + + +// File: gdcmImageCodec_8h.xml + + +// File: gdcmImageConverter_8h.xml + + +// File: gdcmImageFragmentSplitter_8h.xml + + +// File: gdcmImageHelper_8h.xml + + +// File: gdcmImageReader_8h.xml + + +// File: gdcmImageRegionReader_8h.xml + + +// File: gdcmImageToImageFilter_8h.xml + + +// File: gdcmImageWriter_8h.xml + + +// File: gdcmimg_8man.xml + + +// File: gdcmImplementationClassUIDSub_8h.xml + + +// File: gdcmImplementationUIDSub_8h.xml + + +// File: gdcmImplementationVersionNameSub_8h.xml + + +// File: gdcmImplicitDataElement_8h.xml + + +// File: gdcminfo_8man.xml + + +// File: gdcmIOD_8h.xml + + +// File: gdcmIODEntry_8h.xml + + +// File: gdcmIODs_8h.xml + + +// File: gdcmIPPSorter_8h.xml + + +// File: gdcmItem_8h.xml + + +// File: gdcmJPEG12Codec_8h.xml + + +// File: gdcmJPEG16Codec_8h.xml + + +// File: gdcmJPEG2000Codec_8h.xml + + +// File: gdcmJPEG8Codec_8h.xml + + +// File: gdcmJPEGCodec_8h.xml + + +// File: gdcmJPEGLSCodec_8h.xml + + +// File: gdcmKAKADUCodec_8h.xml + + +// File: gdcmLegacyMacro_8h.xml + + +// File: gdcmLO_8h.xml + + +// File: gdcmLookupTable_8h.xml + + +// File: gdcmMacro_8h.xml + + +// File: gdcmMacroEntry_8h.xml + + +// File: gdcmMacros_8h.xml + + +// File: gdcmMaximumLengthSub_8h.xml + + +// File: gdcmMD5_8h.xml + + +// File: gdcmMediaStorage_8h.xml + + +// File: gdcmMeshPrimitive_8h.xml + + +// File: gdcmModule_8h.xml + + +// File: gdcmModuleEntry_8h.xml + + +// File: gdcmModules_8h.xml + + +// File: gdcmMovePatientRootQuery_8h.xml + + +// File: gdcmMoveStudyRootQuery_8h.xml + + +// File: gdcmNestedModuleEntries_8h.xml + + +// File: gdcmNetworkEvents_8h.xml + + +// File: gdcmNetworkStateID_8h.xml + + +// File: gdcmObject_8h.xml + + +// File: gdcmOpenSSLCryptoFactory_8h.xml + + +// File: gdcmOpenSSLCryptographicMessageSyntax_8h.xml + + +// File: gdcmOpenSSLP7CryptoFactory_8h.xml + + +// File: gdcmOpenSSLP7CryptographicMessageSyntax_8h.xml + + +// File: gdcmOrientation_8h.xml + + +// File: gdcmOverlay_8h.xml + + +// File: gdcmParseException_8h.xml + + +// File: gdcmParser_8h.xml + + +// File: gdcmPatient_8h.xml + + +// File: gdcmPDataTFPDU_8h.xml + + +// File: gdcmPDBElement_8h.xml + + +// File: gdcmPDBHeader_8h.xml + + +// File: gdcmpdf_8man.xml + + +// File: gdcmPDFCodec_8h.xml + + +// File: gdcmPDUFactory_8h.xml + + +// File: gdcmPersonName_8h.xml + + +// File: gdcmPGXCodec_8h.xml + + +// File: gdcmPhotometricInterpretation_8h.xml + + +// File: gdcmPixelFormat_8h.xml + + +// File: gdcmPixmap_8h.xml + + +// File: gdcmPixmapReader_8h.xml + + +// File: gdcmPixmapToPixmapFilter_8h.xml + + +// File: gdcmPixmapWriter_8h.xml + + +// File: gdcmPNMCodec_8h.xml + + +// File: gdcmPreamble_8h.xml + + +// File: gdcmPresentationContext_8h.xml + + +// File: gdcmPresentationContextAC_8h.xml + + +// File: gdcmPresentationContextGenerator_8h.xml + + +// File: gdcmPresentationContextRQ_8h.xml + + +// File: gdcmPresentationDataValue_8h.xml + + +// File: gdcmPrinter_8h.xml + + +// File: gdcmPrivateTag_8h.xml + + +// File: gdcmProgressEvent_8h.xml + + +// File: gdcmPVRGCodec_8h.xml + + +// File: gdcmPythonFilter_8h.xml + + +// File: gdcmQueryBase_8h.xml + + +// File: gdcmQueryFactory_8h.xml + + +// File: gdcmQueryImage_8h.xml + + +// File: gdcmQueryPatient_8h.xml + + +// File: gdcmQuerySeries_8h.xml + + +// File: gdcmQueryStudy_8h.xml + + +// File: gdcmraw_8man.xml + + +// File: gdcmRAWCodec_8h.xml + + +// File: gdcmReader_8h.xml + + +// File: gdcmRegion_8h.xml + + +// File: gdcmRescaler_8h.xml + + +// File: gdcmRLECodec_8h.xml + + +// File: gdcmRoleSelectionSub_8h.xml + + +// File: gdcmScanner_8h.xml + + +// File: gdcmscanner_8man.xml + + +// File: gdcmscu_8man.xml + + +// File: gdcmSegment_8h.xml + + +// File: gdcmSegmentedPaletteColorLookupTable_8h.xml + + +// File: gdcmSegmentHelper_8h.xml + + +// File: gdcmSegmentReader_8h.xml + + +// File: gdcmSegmentWriter_8h.xml + + +// File: gdcmSequenceOfFragments_8h.xml + + +// File: gdcmSequenceOfItems_8h.xml + + +// File: gdcmSerieHelper_8h.xml + + +// File: gdcmSeries_8h.xml + + +// File: gdcmServiceClassApplicationInformation_8h.xml + + +// File: gdcmServiceClassUser_8h.xml + + +// File: gdcmSHA1_8h.xml + + +// File: gdcmSimpleSubjectWatcher_8h.xml + + +// File: gdcmSmartPointer_8h.xml + + +// File: gdcmSOPClassExtendedNegociationSub_8h.xml + + +// File: gdcmSOPClassUIDToIOD_8h.xml + + +// File: gdcmSorter_8h.xml + + +// File: gdcmSpacing_8h.xml + + +// File: gdcmSpectroscopy_8h.xml + + +// File: gdcmSplitMosaicFilter_8h.xml + + +// File: gdcmStaticAssert_8h.xml + + +// File: gdcmStreamImageReader_8h.xml + + +// File: gdcmStreamImageWriter_8h.xml + + +// File: gdcmString_8h.xml + + +// File: gdcmStringFilter_8h.xml + + +// File: gdcmStudy_8h.xml + + +// File: gdcmSubject_8h.xml + + +// File: gdcmSurface_8h.xml + + +// File: gdcmSurfaceHelper_8h.xml + + +// File: gdcmSurfaceReader_8h.xml + + +// File: gdcmSurfaceWriter_8h.xml + + +// File: gdcmSwapCode_8h.xml + + +// File: gdcmSwapper_8h.xml + + +// File: gdcmSystem_8h.xml + + +// File: gdcmTable_8h.xml + + +// File: gdcmTableEntry_8h.xml + + +// File: gdcmTableReader_8h.xml + + +// File: gdcmTag_8h.xml + + +// File: gdcmTagPath_8h.xml + + +// File: gdcmTagToVR_8h.xml + + +// File: gdcmtar_8man.xml + + +// File: gdcmTerminal_8h.xml + + +// File: gdcmTestDriver_8h.xml + + +// File: gdcmTesting_8h.xml + + +// File: gdcmTrace_8h.xml + + +// File: gdcmTransferSyntax_8h.xml + + +// File: gdcmTransferSyntaxSub_8h.xml + + +// File: gdcmType_8h.xml + + +// File: gdcmTypes_8h.xml + + +// File: gdcmUIDGenerator_8h.xml + + +// File: gdcmUIDs_8h.xml + + +// File: gdcmULAction_8h.xml + + +// File: gdcmULActionAA_8h.xml + + +// File: gdcmULActionAE_8h.xml + + +// File: gdcmULActionAR_8h.xml + + +// File: gdcmULActionDT_8h.xml + + +// File: gdcmULBasicCallback_8h.xml + + +// File: gdcmULConnection_8h.xml + + +// File: gdcmULConnectionCallback_8h.xml + + +// File: gdcmULConnectionInfo_8h.xml + + +// File: gdcmULConnectionManager_8h.xml + + +// File: gdcmULEvent_8h.xml + + +// File: gdcmULTransitionTable_8h.xml + + +// File: gdcmULWritingCallback_8h.xml + + +// File: gdcmUNExplicitDataElement_8h.xml + + +// File: gdcmUNExplicitImplicitDataElement_8h.xml + + +// File: gdcmUnpacker12Bits_8h.xml + + +// File: gdcmUsage_8h.xml + + +// File: gdcmUserInformation_8h.xml + + +// File: gdcmUUIDGenerator_8h.xml + + +// File: gdcmValidate_8h.xml + + +// File: gdcmValue_8h.xml + + +// File: gdcmValueIO_8h.xml + + +// File: gdcmVersion_8h.xml + + +// File: gdcmviewer_8man.xml + + +// File: gdcmVL_8h.xml + + +// File: gdcmVM_8h.xml + + +// File: gdcmVR_8h.xml + + +// File: gdcmVR16ExplicitDataElement_8h.xml + + +// File: gdcmWaveform_8h.xml + + +// File: gdcmWin32_8h.xml + + +// File: gdcmWriter_8h.xml + + +// File: gdcmxml_8man.xml + + +// File: gdcmXMLDictReader_8h.xml + + +// File: gdcmXMLPrinter_8h.xml + + +// File: gdcmXMLPrivateDictReader_8h.xml + + +// File: README_8txt.xml + + +// File: TestsList_8txt.xml + + +// File: vtkGDCMImageReader_8h.xml + + +// File: vtkGDCMImageWriter_8h.xml + + +// File: vtkGDCMMedicalImageProperties_8h.xml + + +// File: vtkGDCMPolyDataReader_8h.xml + + +// File: vtkGDCMPolyDataWriter_8h.xml + + +// File: vtkGDCMTesting_8h.xml + + +// File: vtkGDCMThreadedImageReader_8h.xml + + +// File: vtkGDCMThreadedImageReader2_8h.xml + + +// File: vtkImageColorViewer_8h.xml + + +// File: vtkImageMapToColors16_8h.xml + + +// File: vtkImageMapToWindowLevelColors2_8h.xml + + +// File: vtkImagePlanarComponentsToComponents_8h.xml + + +// File: vtkImageRGBToYBR_8h.xml + + +// File: vtkImageYBRToRGB_8h.xml + + +// File: vtkLookupTable16_8h.xml + + +// File: vtkRTStructSetProperties_8h.xml + + +// File: gdcm2pnm.xml + + +// File: gdcm2vtk.xml + + +// File: gdcmanon.xml + + +// File: gdcmconv.xml + + +// File: gdcmdiff.xml + + +// File: gdcmdump.xml + + +// File: gdcmgendir.xml + + +// File: gdcmimg.xml + + +// File: gdcminfo.xml + + +// File: gdcmpdf.xml + + +// File: gdcmraw.xml + + +// File: gdcmscanner.xml + + +// File: gdcmscu.xml + + +// File: gdcmtar.xml + + +// File: gdcmviewer.xml + + +// File: gdcmxml.xml + + +// File: todo.xml + + +// File: deprecated.xml + + +// File: bug.xml + + +// File: dir_3b280b22421f3362d92ffa30d059aaaa.xml + + +// File: dir_a3c96c079bff2fe9c8e4725d2b26912d.xml + + +// File: dir_5821d7030b183b442c40459bf6367538.xml + + +// File: dir_69b53ea3d321de415621b2ca57e0e4fe.xml + + +// File: dir_c01104cbda0fc13b21364a944e5e102c.xml + + +// File: dir_40f3bda27b133a39a571bf8b0f61701e.xml + + +// File: dir_833d14ff42fced14a88347852a76002f.xml + + +// File: dir_c66df8ccb29e0a15f96c642801015235.xml + + +// File: dir_c5f60bc67b3910a04e3caf5bdaf0147c.xml + + +// File: dir_0cda718670c95f7392b1f0e0da723281.xml + + +// File: dir_a6d25b859930d6f3062a57fd328b9ae7.xml + + +// File: dir_ef500e673ae59461a62abc5e23d68eb0.xml + + +// File: dir_8d9b278262feae29032d95522fcac58a.xml + + +// File: dir_b855106db6d41307d62438e9f06f31b7.xml + + +// File: AWTMedical3_8java-example.xml + + +// File: BasicAnonymizer_8cs-example.xml + + +// File: BasicImageAnonymizer_8cs-example.xml + + +// File: CastConvertPhilips_8py-example.xml + + +// File: ChangeSequenceUltrasound_8cxx-example.xml + + +// File: CheckBigEndianBug_8cxx-example.xml + + +// File: ClinicalTrialAnnotate_8cxx-example.xml + + +// File: ClinicalTrialIdentificationWorkflow_8cs-example.xml + + +// File: CompressImage_8cxx-example.xml + + +// File: CompressLossyJPEG_8cs-example.xml + + +// File: Convert16BitsTo8Bits_8cxx-example.xml + + +// File: ConvertMPL_8py-example.xml + + +// File: ConvertMultiFrameToSingleFrame_8cxx-example.xml + + +// File: ConvertNumpy_8py-example.xml + + +// File: ConvertPIL_8py-example.xml + + +// File: ConvertRGBToLuminance_8cxx-example.xml + + +// File: ConvertSingleBitTo8Bits_8cxx-example.xml + + +// File: ConvertToQImage_8cxx-example.xml + + +// File: CreateARGBImage_8cxx-example.xml + + +// File: CreateCMYKImage_8cxx-example.xml + + +// File: CreateJPIPDataSet_8cxx-example.xml + + +// File: CreateRAWStorage_8py-example.xml + + +// File: csa2img_8cxx-example.xml + + +// File: CStoreQtProgress_8cxx-example.xml + + +// File: DecompressImage_8cs-example.xml + + +// File: DecompressImage_8java-example.xml + + +// File: DecompressImage_8py-example.xml + + +// File: DecompressImageMultiframe_8cs-example.xml + + +// File: DecompressJPEGFile_8cs-example.xml + + +// File: DecompressPixmap_8java-example.xml + + +// File: DiffFile_8cxx-example.xml + + +// File: DiscriminateVolume_8cxx-example.xml + + +// File: DumbAnonymizer_8py-example.xml + + +// File: DumpADAC_8cxx-example.xml + + +// File: DumpExamCard_8cxx-example.xml + + +// File: DumpGEMSMovieGroup_8cxx-example.xml + + +// File: DumpImageHeaderInfo_8cxx-example.xml + + +// File: DumpToSQLITE3_8cxx-example.xml + + +// File: DuplicatePCDE_8cxx-example.xml + + +// File: ELSCINT1WaveToText_8cxx-example.xml + + +// File: EncapsulateFileInRawData_8cxx-example.xml + + +// File: ExtractEncapsulatedFile_8cs-example.xml + + +// File: ExtractEncryptedContent_8cxx-example.xml + + +// File: ExtractIconFromFile_8cxx-example.xml + + +// File: ExtractImageRegion_8cs-example.xml + + +// File: ExtractImageRegionWithLUT_8cs-example.xml + + +// File: Extracting_All_Resolution_8cxx-example.xml + + +// File: ExtractOneFrame_8cs-example.xml + + +// File: Fake_Image_Using_Stream_Image_Writer_8cxx-example.xml + + +// File: FileAnonymize_8cs-example.xml + + +// File: FileAnonymize_8java-example.xml + + +// File: FindAllPatientName_8py-example.xml + + +// File: FixBrokenJ2K_8cxx-example.xml + + +// File: FixCommaBug_8py-example.xml + + +// File: FixJAIBugJPEGLS_8cxx-example.xml + + +// File: gdcmorthoplanes_8cxx-example.xml + + +// File: gdcmreslice_8cxx-example.xml + + +// File: gdcmrtionplan_8cxx-example.xml + + +// File: gdcmrtplan_8cxx-example.xml + + +// File: gdcmscene_8cxx-example.xml + + +// File: gdcmtexture_8cxx-example.xml + + +// File: gdcmvolume_8cxx-example.xml + + +// File: GenAllVR_8cxx-example.xml + + +// File: GenerateDICOMDIR_8cs-example.xml + + +// File: GenerateRTSTRUCT_8cxx-example.xml + + +// File: GenerateStandardSOPClasses_8cxx-example.xml + + +// File: GenFakeIdentifyFile_8cxx-example.xml + + +// File: GenFakeImage_8cxx-example.xml + + +// File: GenLongSeqs_8cxx-example.xml + + +// File: GenSeqs_8cxx-example.xml + + +// File: GetArray_8cs-example.xml + + +// File: GetJPEGSamplePrecision_8cxx-example.xml + + +// File: GetPortionCSAHeader_8py-example.xml + + +// File: GetSequenceUltrasound_8cxx-example.xml + + +// File: GetSubSequenceData_8cxx-example.xml + + +// File: headsq2dcm_8py-example.xml + + +// File: HelloActiviz_8cs-example.xml + + +// File: HelloActiviz2_8cs-example.xml + + +// File: HelloActiviz3_8cs-example.xml + + +// File: HelloActiviz4_8cs-example.xml + + +// File: HelloActiviz5_8cs-example.xml + + +// File: HelloSimple_8java-example.xml + + +// File: HelloVizWorld_8cxx-example.xml + + +// File: HelloVTKWorld_8cs-example.xml + + +// File: HelloVTKWorld_8java-example.xml + + +// File: HelloVTKWorld2_8cs-example.xml + + +// File: HelloWorld_8cxx-example.xml + + +// File: HelloWorld_8py-example.xml + + +// File: iU22tomultisc_8cxx-example.xml + + +// File: LargeVRDSExplicit_8cxx-example.xml + + +// File: MagnifyFile_8cxx-example.xml + + +// File: ManipulateFile_8cs-example.xml + + +// File: ManipulateFile_8py-example.xml + + +// File: ManipulateSequence_8py-example.xml + + +// File: MergeFile_8py-example.xml + + +// File: MergeTwoFiles_8cxx-example.xml + + +// File: MetaImageMD5Activiz_8cs-example.xml + + +// File: MIPViewer_8java-example.xml + + +// File: MpegVideoInfo_8cs-example.xml + + +// File: MPRViewer_8java-example.xml + + +// File: MPRViewer2_8java-example.xml + + +// File: MrProtocol_8cxx-example.xml + + +// File: NewSequence_8cs-example.xml + + +// File: NewSequence_8py-example.xml + + +// File: offscreenimage_8cxx-example.xml + + +// File: PatchFile_8cxx-example.xml + + +// File: PhilipsPrivateRescaleInterceptSlope_8py-example.xml + + +// File: PlaySound_8py-example.xml + + +// File: pmsct_rgb1_8cxx-example.xml + + +// File: PrivateDict_8py-example.xml + + +// File: PublicDict_8cxx-example.xml + + +// File: ReadAndDumpDICOMDIR_8cxx-example.xml + + +// File: ReadAndDumpDICOMDIR_8py-example.xml + + +// File: ReadAndPrintAttributes_8cxx-example.xml + + +// File: ReadExplicitLengthSQIVR_8cxx-example.xml + + +// File: ReadFiles_8java-example.xml + + +// File: ReadGEMSSDO_8cxx-example.xml + + +// File: ReadMultiTimesException_8cxx-example.xml + + +// File: ReadSeriesIntoVTK_8java-example.xml + + +// File: ReadUTF8QtDir_8cxx-example.xml + + +// File: RefCounting_8cs-example.xml + + +// File: ReformatFile_8cs-example.xml + + +// File: RemovePrivateTags_8py-example.xml + + +// File: RescaleImage_8cs-example.xml + + +// File: reslicesphere_8cxx-example.xml + + +// File: ReWriteSCAsMR_8py-example.xml + + +// File: rle2img_8cxx-example.xml + + +// File: rtstructapp_8cxx-example.xml + + +// File: ScanDirectory_8cs-example.xml + + +// File: ScanDirectory_8java-example.xml + + +// File: ScanDirectory_8py-example.xml + + +// File: SendFileSCU_8cs-example.xml + + +// File: SimplePrint_8cs-example.xml + + +// File: SimplePrintPatientName_8cs-example.xml + + +// File: SimpleScanner_8cxx-example.xml + + +// File: SortImage_8cxx-example.xml + + +// File: SortImage_8py-example.xml + + +// File: SortImage2_8cs-example.xml + + +// File: StandardizeFiles_8cs-example.xml + + +// File: StreamImageReaderTest_8cxx-example.xml + + +// File: TestByteSwap_8cxx-example.xml + + +// File: TestReader_8cxx-example.xml + + +// File: TestReader_8py-example.xml + + +// File: threadgdcm_8cxx-example.xml + + +// File: TraverseModules_8cxx-example.xml + + +// File: uid_unique_8cxx-example.xml + + +// File: VolumeSorter_8cxx-example.xml + + +// File: WriteBuffer_8py-example.xml + + +// File: indexpage.xml + diff --git a/gdcm/Wrapping/Python/doxy2swig.py b/gdcm/Wrapping/Python/doxy2swig.py new file mode 100644 index 0000000..d8962f0 --- /dev/null +++ b/gdcm/Wrapping/Python/doxy2swig.py @@ -0,0 +1,457 @@ +#!/usr/bin/env python +"""Doxygen XML to SWIG docstring converter. + +Usage: + + doxy2swig.py [options] input.xml output.i + +Converts Doxygen generated XML files into a file containing docstrings +that can be used by SWIG-1.3.x. Note that you need to get SWIG +version > 1.3.23 or use Robin Dunn's docstring patch to be able to use +the resulting output. + +input.xml is your doxygen generated XML file and output.i is where the +output will be written (the file will be clobbered). + +Code can be found at prabhu's page: + +http://www.aero.iitb.ac.in/~prabhu/software/code/python/doxy2swig.py + +Ref: +http://www.enricozini.org/2007/tips/swig-doxygen-docstring.html +http://internetducttape.com/2007/03/20/automatic_documentation_python_doxygen/ +""" +###################################################################### +# +# This code is implemented using Mark Pilgrim's code as a guideline: +# http://www.faqs.org/docs/diveintopython/kgp_divein.html +# +# Author: Prabhu Ramachandran +# License: BSD style +# +# Thanks: +# Johan Hake: the include_function_definition feature +# Bill Spotz: bug reports and testing. +# +###################################################################### + +from xml.dom import minidom +import re +import textwrap +import sys +import types +import os.path +import optparse + + +def my_open_read(source): + if hasattr(source, "read"): + return source + else: + return open(source) + +def my_open_write(dest): + if hasattr(dest, "write"): + return dest + else: + return open(dest, 'w') + + +class Doxy2SWIG: + """Converts Doxygen generated XML files into a file containing + docstrings that can be used by SWIG-1.3.x that have support for + feature("docstring"). Once the data is parsed it is stored in + self.pieces. + + """ + + def __init__(self, src, include_function_definition=True, quiet=False): + """Initialize the instance given a source object. `src` can + be a file or filename. If you do not want to include function + definitions from doxygen then set + `include_function_definition` to `False`. This is handy since + this allows you to use the swig generated function definition + using %feature("autodoc", [0,1]). + + """ + f = my_open_read(src) + self.my_dir = os.path.dirname(f.name) + self.xmldoc = minidom.parse(f).documentElement + f.close() + + self.pieces = [] + self.pieces.append('\n// File: %s\n'%\ + os.path.basename(f.name)) + + self.space_re = re.compile(r'\s+') + self.lead_spc = re.compile(r'^(%feature\S+\s+\S+\s*?)"\s+(\S)') + self.multi = 0 + self.ignores = ['inheritancegraph', 'param', 'listofallmembers', + 'innerclass', 'name', 'declname', 'incdepgraph', + 'invincdepgraph', 'programlisting', 'type', + 'references', 'referencedby', 'location', + 'collaborationgraph', 'reimplements', + 'reimplementedby', 'derivedcompoundref', + 'basecompoundref'] + #self.generics = [] + self.include_function_definition = include_function_definition + if not include_function_definition: + self.ignores.append('argsstring') + + self.quiet = quiet + + + def generate(self): + """Parses the file set in the initialization. The resulting + data is stored in `self.pieces`. + + """ + self.parse(self.xmldoc) + + def parse(self, node): + """Parse a given node. This function in turn calls the + `parse_` functions which handle the respective + nodes. + + """ + pm = getattr(self, "parse_%s"%node.__class__.__name__) + pm(node) + + def parse_Document(self, node): + self.parse(node.documentElement) + + def parse_Text(self, node): + txt = node.data + txt = txt.replace('\\', r'\\\\') + txt = txt.replace('"', r'\"') + # ignore pure whitespace + m = self.space_re.match(txt) + if m and len(m.group()) == len(txt): + pass + else: + self.add_text(textwrap.fill(txt, break_long_words=False)) + + def parse_Element(self, node): + """Parse an `ELEMENT_NODE`. This calls specific + `do_` handers for different elements. If no handler + is available the `generic_parse` method is called. All + tagNames specified in `self.ignores` are simply ignored. + + """ + name = node.tagName + ignores = self.ignores + if name in ignores: + return + attr = "do_%s" % name + if hasattr(self, attr): + handlerMethod = getattr(self, attr) + handlerMethod(node) + else: + self.generic_parse(node) + #if name not in self.generics: self.generics.append(name) + + def parse_Comment(self, node): + """Parse a `COMMENT_NODE`. This does nothing for now.""" + return + + def add_text(self, value): + """Adds text corresponding to `value` into `self.pieces`.""" + if type(value) in (types.ListType, types.TupleType): + self.pieces.extend(value) + else: + self.pieces.append(value) + + def get_specific_nodes(self, node, names): + """Given a node and a sequence of strings in `names`, return a + dictionary containing the names as keys and child + `ELEMENT_NODEs`, that have a `tagName` equal to the name. + + """ + nodes = [(x.tagName, x) for x in node.childNodes \ + if x.nodeType == x.ELEMENT_NODE and \ + x.tagName in names] + return dict(nodes) + + def generic_parse(self, node, pad=0): + """A Generic parser for arbitrary tags in a node. + + Parameters: + + - node: A node in the DOM. + - pad: `int` (default: 0) + + If 0 the node data is not padded with newlines. If 1 it + appends a newline after parsing the childNodes. If 2 it + pads before and after the nodes are processed. Defaults to + 0. + + """ + npiece = 0 + if pad: + npiece = len(self.pieces) + if pad == 2: + self.add_text('\n') + for n in node.childNodes: + self.parse(n) + if pad: + if len(self.pieces) > npiece: + self.add_text('\n') + + def space_parse(self, node): + self.add_text(' ') + self.generic_parse(node) + + do_ref = space_parse + do_emphasis = space_parse + do_bold = space_parse + do_computeroutput = space_parse + do_formula = space_parse + + def do_compoundname(self, node): + self.add_text('\n\n') + data = node.firstChild.data + self.add_text('%%feature("docstring") %s "\n'%data) + + def do_compounddef(self, node): + kind = node.attributes['kind'].value + if kind in ('class', 'struct'): + prot = node.attributes['prot'].value + if prot <> 'public': + return + names = ('compoundname', 'briefdescription', + 'detaileddescription', 'includes') + first = self.get_specific_nodes(node, names) + for n in names: + if first.has_key(n): + self.parse(first[n]) + self.add_text(['";','\n']) + for n in node.childNodes: + if n not in first.values(): + self.parse(n) + elif kind in ('file', 'namespace'): + nodes = node.getElementsByTagName('sectiondef') + for n in nodes: + self.parse(n) + + def do_includes(self, node): + self.add_text('C++ includes: ') + self.generic_parse(node, pad=1) + + def do_parameterlist(self, node): + text='unknown' + for key, val in node.attributes.items(): + if key == 'kind': + if val == 'param': text = 'Parameters' + elif val == 'exception': text = 'Exceptions' + else: text = val + break + self.add_text(['\n', '\n', text, ':', '\n']) + self.generic_parse(node, pad=1) + + def do_para(self, node): + self.add_text('\n') + self.generic_parse(node, pad=1) + + def do_parametername(self, node): + self.add_text('\n') + try: + data=node.firstChild.data + except AttributeError: # perhaps a tag in it + data=node.firstChild.firstChild.data + if data.find('Exception') != -1: + self.add_text(data) + else: + self.add_text("%s: "%data) + + def do_parameterdefinition(self, node): + self.generic_parse(node, pad=1) + + def do_detaileddescription(self, node): + self.generic_parse(node, pad=1) + + def do_briefdescription(self, node): + self.generic_parse(node, pad=1) + + def do_memberdef(self, node): + prot = node.attributes['prot'].value + id = node.attributes['id'].value + kind = node.attributes['kind'].value + tmp = node.parentNode.parentNode.parentNode + compdef = tmp.getElementsByTagName('compounddef')[0] + cdef_kind = compdef.attributes['kind'].value + + if prot == 'public': + first = self.get_specific_nodes(node, ('definition', 'name')) + name = first['name'].firstChild.data + if name[:8] == 'operator': # Don't handle operators yet. + return + + if not first.has_key('definition') or \ + kind in ['variable', 'typedef']: + return + + if self.include_function_definition: + defn = first['definition'].firstChild.data + else: + defn = "" + self.add_text('\n') + self.add_text('%feature("docstring") ') + + anc = node.parentNode.parentNode + if cdef_kind in ('file', 'namespace'): + ns_node = anc.getElementsByTagName('innernamespace') + if not ns_node and cdef_kind == 'namespace': + ns_node = anc.getElementsByTagName('compoundname') + if ns_node: + ns = ns_node[0].firstChild.data + self.add_text(' %s::%s "\n%s'%(ns, name, defn)) + else: + self.add_text(' %s "\n%s'%(name, defn)) + elif cdef_kind in ('class', 'struct'): + # Get the full function name. + anc_node = anc.getElementsByTagName('compoundname') + cname = anc_node[0].firstChild.data + self.add_text(' %s::%s "\n%s'%(cname, name, defn)) + + for n in node.childNodes: + if n not in first.values(): + self.parse(n) + self.add_text(['";', '\n']) + + def do_definition(self, node): + data = node.firstChild.data + self.add_text('%s "\n%s'%(data, data)) + + def do_sectiondef(self, node): + kind = node.attributes['kind'].value + if kind in ('public-func', 'func', 'user-defined', ''): + self.generic_parse(node) + + def do_header(self, node): + """For a user defined section def a header field is present + which should not be printed as such, so we comment it in the + output.""" + data = node.firstChild.data + self.add_text('\n/*\n %s \n*/\n'%data) + # If our immediate sibling is a 'description' node then we + # should comment that out also and remove it from the parent + # node's children. + parent = node.parentNode + idx = parent.childNodes.index(node) + if len(parent.childNodes) >= idx + 2: + nd = parent.childNodes[idx+2] + if nd.nodeName == 'description': + nd = parent.removeChild(nd) + self.add_text('\n/*') + self.generic_parse(nd) + self.add_text('\n*/\n') + + def do_simplesect(self, node): + kind = node.attributes['kind'].value + if kind in ('date', 'rcs', 'version'): + pass + elif kind == 'warning': + self.add_text(['\n', 'WARNING: ']) + self.generic_parse(node) + elif kind == 'see': + self.add_text('\n') + self.add_text('See: ') + self.generic_parse(node) + else: + self.generic_parse(node) + + def do_argsstring(self, node): + self.generic_parse(node, pad=1) + + def do_member(self, node): + kind = node.attributes['kind'].value + refid = node.attributes['refid'].value + if kind == 'function' and refid[:9] == 'namespace': + self.generic_parse(node) + + def do_doxygenindex(self, node): + self.multi = 1 + comps = node.getElementsByTagName('compound') + for c in comps: + refid = c.attributes['refid'].value + fname = refid + '.xml' + if not os.path.exists(fname): + fname = os.path.join(self.my_dir, fname) + if not self.quiet: + print "parsing file: %s"%fname + p = Doxy2SWIG(fname, self.include_function_definition, self.quiet) + p.generate() + self.pieces.extend(self.clean_pieces(p.pieces)) + + def write(self, fname): + o = my_open_write(fname) + if self.multi: + o.write("".join(self.pieces)) + else: + o.write("".join(self.clean_pieces(self.pieces))) + o.close() + + def clean_pieces(self, pieces): + """Cleans the list of strings given as `pieces`. It replaces + multiple newlines by a maximum of 2 and returns a new list. + It also wraps the paragraphs nicely. + + """ + ret = [] + count = 0 + for i in pieces: + if i == '\n': + count = count + 1 + else: + if i == '";': + if count: + ret.append('\n') + elif count > 2: + ret.append('\n\n') + elif count: + ret.append('\n'*count) + count = 0 + ret.append(i) + + _data = "".join(ret) + ret = [] + for i in _data.split('\n\n'): + if i == 'Parameters:' or i == 'Exceptions:': + ret.extend([i, '\n-----------', '\n\n']) + elif i.find('// File:') > -1: # leave comments alone. + ret.extend([i, '\n']) + else: + _tmp = textwrap.fill(i.strip(), break_long_words=False) + _tmp = self.lead_spc.sub(r'\1"\2', _tmp) + ret.extend([_tmp, '\n\n']) + return ret + + +def convert(input, output, include_function_definition=True, quiet=False): + p = Doxy2SWIG(input, include_function_definition, quiet) + p.generate() + p.write(output) + +def main(): + usage = __doc__ + parser = optparse.OptionParser(usage) + parser.add_option("-n", '--no-function-definition', + action='store_true', + default=False, + dest='func_def', + help='do not include doxygen function definitions') + parser.add_option("-q", '--quiet', + action='store_true', + default=False, + dest='quiet', + help='be quiet and minimise output') + + options, args = parser.parse_args() + if len(args) != 2: + parser.error("error: no input and output specified") + + convert(args[0], args[1], not options.func_def, options.quiet) + + +if __name__ == '__main__': + main() diff --git a/gdcm/Wrapping/Python/gdcm.pth.in b/gdcm/Wrapping/Python/gdcm.pth.in new file mode 100644 index 0000000..f599eea --- /dev/null +++ b/gdcm/Wrapping/Python/gdcm.pth.in @@ -0,0 +1 @@ +@subdir@ diff --git a/gdcm/Wrapping/Python/gdcm.py b/gdcm/Wrapping/Python/gdcm.py new file mode 100644 index 0000000..fd7ee0d --- /dev/null +++ b/gdcm/Wrapping/Python/gdcm.py @@ -0,0 +1,84 @@ +############################################################################ +# +# Program: GDCM (Grassroots DICOM). A DICOM library +# +# Copyright (c) 2006-2011 Mathieu Malaterre +# All rights reserved. +# See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even +# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the above copyright notice for more information. +# +############################################################################ + +""" This module loads all the classes from the GDCM library into +its namespace. This is a required module.""" + +# warning: when loading 'import gdcm', if a gdcm.so is to be found in the same +# directory as a gdcm.py file, then there will be conflict. This will happen +# in the case of a user wrapping to PHP and Python at the same time. + +import os +import sys + +# This file is a thin wrapper to the swig generated python module. It allows us +# to do a couple of things: +# 1. do the RTLD_GLOBAL thingy on GNU system (with GNU compiler) before loading +# the compiled python module +# 2. Load some secret path using directly the locate of this gdcm.py file. +# a. If the gdcm.py is installed in a normal installation then we can deduce +# where the Part3.xml can be found. This is the 'non frozen' case +# b. Is the python executable is frozen then assume that everything is at +# the same level and look for Part3.xml +# at the same level as the frozen application is (see py2exe for more info) +# 3. Finally this is also a good time to look up the env var and if +# GDCM_RESOURCES_PATH is set, then fill the 'resource manager' via the +# Global.Prepend interface. + +def main_is_frozen(): + return hasattr(sys, "frozen") + +if os.name == 'posix': + # extremely important ! + # http://gcc.gnu.org/faq.html#dso + # http://mail.python.org/pipermail/python-dev/2002-May/023923.html + # http://wiki.python.org/moin/boost.python/CrossExtensionModuleDependencies + # http://mail.python.org/pipermail/cplusplus-sig/2005-August/009135.html + orig_dlopen_flags = sys.getdlopenflags() + try: + import dl + except ImportError: + # are we on AMD64 ? + try: + import DLFCN as dl + except ImportError: + #print "Could not import dl" + dl = None + if dl: + #print "dl was imported" + #sys.setdlopenflags(dl.RTLD_LAZY|dl.RTLD_GLOBAL) + sys.setdlopenflags(dl.RTLD_NOW|dl.RTLD_GLOBAL) + from gdcmswig import * + # revert: + sys.setdlopenflags(orig_dlopen_flags) + del dl + del orig_dlopen_flags +else: + from gdcmswig import * + +# To finish up with module loading let's do some more stuff, like path to resource init: +if main_is_frozen(): + Global.GetInstance().Prepend( os.path.dirname(sys.executable) ) +else: + Global.GetInstance().Prepend( os.path.dirname(__file__) + "/../../../" + GDCM_INSTALL_DATA_DIR + "/XML/" ) + +# Do it afterward so that it comes in first in the list +try: + Global.GetInstance().Prepend( os.environ["GDCM_RESOURCES_PATH"] ) +except: + pass + +# bye bye +# once the process dies, the changed environment dies with it. +del os,sys diff --git a/gdcm/Wrapping/Python/gdcmPythonFilter.cxx b/gdcm/Wrapping/Python/gdcmPythonFilter.cxx new file mode 100644 index 0000000..9c6400f --- /dev/null +++ b/gdcm/Wrapping/Python/gdcmPythonFilter.cxx @@ -0,0 +1,285 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "gdcmPythonFilter.h" +#include "gdcmGlobal.h" +#include "gdcmElement.h" +#include "gdcmByteValue.h" +#include "gdcmAttribute.h" +#include "gdcmVR.h" + +#include + +namespace gdcm +{ +// Py_BuildValue: +// http://www.python.org/doc/1.5.2p2/ext/buildValue.html + +PythonFilter::PythonFilter():F(new File) +{ +} +//----------------------------------------------------------------------------- +PythonFilter::~PythonFilter() +{ +} + +void PythonFilter::SetDicts(const Dicts &dicts) +{ + assert(0); // FIXME +} + +static const char *PythonTypesFromVR[] = { +0, // "??", // 0 +"s", // "AE", // 1 +"s", // "AS", // 2 +"(ii)", // "AT", // 3 +"s", // "CS", // 4 +"s", // "DA", // 5 +"s", // "DS", // 6 +"s", // "DT", // 7 +"d", // "FD", // 8 +"d", // "FL", // 9 +"i", // "IS", // 10 +"s", // "LO", // 11 +"s", // "LT", // 12 +"s", // "OB", // 13 +"d", // "OF", // 14 +"s", // "OW", // 15 +"s", // "PN", // 16 +"s", // "SH", // 17 +"i", // "SL", // 18 +"s", // "SQ", // 19 +"i", // "SS", // 20 +"s", // "ST", // 21 +"s", // "TM", // 22 +"s", // "UI", // 23 +"i", // "UL", // 24 +"s", // "UN", // 25 +"i", // "US", // 26 +"s", // "UT", // 27 +}; +const char *GetPythonTypeFromVR(VR const &vr) +{ +// return PythonTypesFromVR[ (int)vr ]; + const char *s; + switch(vr) + { + case VR::INVALID: + s = 0; + break; + case VR::AE: + s = "s"; + break; + case VR::AS: + s = "s"; + break; + case VR::AT: + s = "(ii)"; + break; + case VR::CS: + s = "s"; + break; + case VR::DA: + s = "s"; + break; + case VR::DS: + s = "d"; + break; + case VR::DT: + s = "s"; + break; + case VR::FD: + s = "d"; + break; + case VR::FL: + s = "d"; + break; + case VR::IS: + s = "i"; + break; + case VR::LO: + s = "s"; + break; + case VR::LT: + s = "s"; + break; + case VR::OB: + s = "s"; + break; + case VR::OF: + s = "d"; + break; + case VR::OW: + s = "s"; + break; + case VR::PN: + s = "s"; + break; + case VR::SH: + s = "s"; + break; + case VR::SL: + s = "i"; + break; + case VR::SQ: + s = "s"; + break; + case VR::SS: + s = "i"; + break; + case VR::ST: + s = "s"; + break; + case VR::TM: + s = "s"; + break; + case VR::UI: + s = "s"; + break; + case VR::UL: + s = "i"; + break; + case VR::UN: + s = "s"; + break; + case VR::US: + s = "i"; + break; + case VR::UT: + s = "s"; + break; + default: + assert( 0 ); + s = 0; + } + return s; +} + +template ::Type*/ > +PyObject *DataElementToPyObject(DataElement const &de, VR const &vr) +{ + const ByteValue *bv = de.GetByteValue(); + std::string s( bv->GetPointer(), bv->GetLength() ); + s.resize( std::min( s.size(), strlen( s.c_str() ) ) ); // strlen is garantee to be lower or equal to ::size() + // http://www.python.org/doc/current/ext/buildValue.html + // http://mail.python.org/pipermail/python-list/2002-April/137612.html + unsigned int count; + if( vr & VR::VRASCII ) + count = VM::GetNumberOfElementsFromArray(bv->GetPointer(), bv->GetLength()); + else /*( vr & VR::VRASCII ) */ + count = bv->GetLength() / vr.GetSize(); + const char *ptype = GetPythonTypeFromVR( vr ); +//std::cout << "DEBUG:" << ptype << std::endl; + Element el; + //el.SetLength( count * sizeof(typename Element::Type) ); + el.Set( de.GetValue() ); + PyObject *o; + if( count == 0 ) + { + o = 0; + } + else if( count == 1 ) + { + helper s = el[0]; + o = Py_BuildValue((char*)ptype, s); + } + else + { + + PyObject* tuple = PyTuple_New(count); + + for (int i = 0; i < count; i++) { + //double rVal = data[i]; + //PyTuple_SetItem(tuple, i, Py_BuildValue("d", rVal)); + helper s = el[i]; + //PyTuple_SetItem(tuple, i, Py_BuildValue("s", s)); + PyTuple_SetItem(tuple, i, Py_BuildValue((char*)ptype, s)); + } + o = tuple; + } + + + Py_INCREF(o); + return o; +} + +PyObject *PythonFilter::ToPyObject(const Tag& t) const +{ + const Global &g = GlobalInstance; + const Dicts &dicts = g.GetDicts(); + const DataSet &ds = GetFile().GetDataSet(); + if( ds.IsEmpty() || !ds.FindDataElement(t) ) + { + gdcmWarningMacro( "DataSet is empty or does not contains tag:" ); + return 0; + } + if( t.IsPrivate() ) + { + return 0; + } + + const DataElement &de = ds.GetDataElement( t ); + assert( de.GetTag().IsPublic() ); + const DictEntry &entry = dicts.GetDictEntry(de.GetTag()); + if( entry.GetVR() == VR::INVALID ) + { + // FIXME This is a public element we do not support... + //throw Exception(); + return 0; + } + + VR vr = entry.GetVR(); + VM vm = entry.GetVM(); + // If Explicit override with coded VR: + if( de.GetVR() != VR::INVALID && de.GetVR() != VR::UN ) + { + vr = de.GetVR(); + } + assert( vr != VR::UN && vr != VR::INVALID ); + //std::cerr << "Found " << vr << " for " << de.GetTag() << std::endl; + //if( VR::IsASCII( vr ) ) + { + //assert( vr & VR::VRASCII ); + if( de.IsEmpty() ) + { + return 0; + } + else + { + PyObject *o; + switch(vr) + { + case VR::CS: + o = DataElementToPyObject(de, vr); + break; + case VR::DS: + o = DataElementToPyObject(de, vr); + break; + case VR::SH: + o = DataElementToPyObject(de, vr); + break; + case VR::US: + o = DataElementToPyObject(de, vr); + break; + } + return o; + } + } + + PyObject *o = Py_BuildValue("s", "unhandled" ); + Py_INCREF(o); + + return o; +} + +} diff --git a/gdcm/Wrapping/Python/gdcmPythonFilter.h b/gdcm/Wrapping/Python/gdcmPythonFilter.h new file mode 100644 index 0000000..2874aeb --- /dev/null +++ b/gdcm/Wrapping/Python/gdcmPythonFilter.h @@ -0,0 +1,55 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#ifndef GDCMPYTHONFILTER_H +#define GDCMPYTHONFILTER_H + +#include + +#include "gdcmDataElement.h" +#include "gdcmDicts.h" +#include "gdcmFile.h" + +namespace gdcm +{ + +/** + * \brief PythonFilter + * PythonFilter is the class that make gdcm2.x looks more like gdcm1 and transform the binary blob + * contained in a DataElement into a string, typically this is a nice feature to have for wrapped language + */ +class GDCM_EXPORT PythonFilter +{ +public: + PythonFilter(); + ~PythonFilter(); + + void UseDictAlways(bool use) {} + + // Allow user to pass in there own dicts + void SetDicts(const Dicts &dicts); + + // Convert to string the ByteValue contained in a DataElement + PyObject *ToPyObject(const Tag& t) const; + + void SetFile(const File& f) { F = f; } + File &GetFile() { return *F; } + const File &GetFile() const { return *F; } + +private: + SmartPointer F; +}; + +} // end namespace gdcm + +#endif //GDCMPYTHONFILTER_H diff --git a/gdcm/Wrapping/Python/gdcmswig.i b/gdcm/Wrapping/Python/gdcmswig.i new file mode 100644 index 0000000..b290737 --- /dev/null +++ b/gdcm/Wrapping/Python/gdcmswig.i @@ -0,0 +1,787 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +// See docs: +// http://www.swig.org/Doc1.3/Python.html +// http://www.swig.org/Doc1.3/SWIGPlus.html#SWIGPlus +// cstring_output_allocate_size: +// http://www.swig.org/Doc1.3/Library.html +// http://www.geocities.com/foetsch/python/extending_python.htm +// http://www.ddj.com/cpp/184401747 +// http://www.ddj.com/article/printableArticle.jhtml;jsessionid=VM4IXCQG5KM10QSNDLRSKH0CJUNN2JVN?articleID=184401747&dept_url=/cpp/ +// http://matt.eifelle.com/2008/11/04/exposing-an-array-interface-with-swig-for-a-cc-structure/ + +%module(docstring="A DICOM library",directors=1) gdcmswig +// http://www.swig.org/Doc1.3/Warnings.html +// "There is no option to suppress all SWIG warning messages." +#pragma SWIG nowarn=302,303,312,362,383,389,401,503,504,509,510,514,516 +%{ +#include // ptrdiff_t +#include "gdcmTypes.h" +#include "gdcmASN1.h" +#include "gdcmSmartPointer.h" +#include "gdcmSwapCode.h" +#include "gdcmEvent.h" +#include "gdcmProgressEvent.h" +#include "gdcmAnonymizeEvent.h" +#include "gdcmDirectory.h" +#ifdef GDCM_BUILD_TESTING +#include "gdcmTesting.h" +#endif +#include "gdcmObject.h" +#include "gdcmPixelFormat.h" +#include "gdcmMediaStorage.h" +#include "gdcmTag.h" +#include "gdcmPrivateTag.h" +#include "gdcmVL.h" +#include "gdcmVR.h" +#include "gdcmVM.h" +#include "gdcmObject.h" +#include "gdcmValue.h" +#include "gdcmByteValue.h" +#include "gdcmDataElement.h" +#include "gdcmItem.h" +#include "gdcmSequenceOfItems.h" +#include "gdcmDataSet.h" +//#include "gdcmString.h" +//#include "gdcmCodeString.h" +#include "gdcmPreamble.h" +#include "gdcmFile.h" +#include "gdcmBitmap.h" +#include "gdcmIconImage.h" +#include "gdcmPixmap.h" +#include "gdcmImage.h" +#include "gdcmFragment.h" +#include "gdcmCSAHeader.h" +#include "gdcmPDBHeader.h" +#include "gdcmSequenceOfFragments.h" +#include "gdcmTransferSyntax.h" +#include "gdcmBasicOffsetTable.h" +//#include "gdcmLO.h" +#include "gdcmCSAElement.h" +#include "gdcmPDBElement.h" +#include "gdcmFileSet.h" + +#include "gdcmReader.h" +#include "gdcmPixmapReader.h" +#include "gdcmImageReader.h" +#include "gdcmWriter.h" +#include "gdcmPixmapWriter.h" +#include "gdcmImageWriter.h" +#include "gdcmStringFilter.h" +#include "gdcmGlobal.h" +#include "gdcmDicts.h" +#include "gdcmDict.h" +#include "gdcmCSAHeaderDict.h" +#include "gdcmDictEntry.h" +#include "gdcmCSAHeaderDictEntry.h" +#include "gdcmUIDGenerator.h" +#include "gdcmUUIDGenerator.h" +//#include "gdcmConstCharWrapper.h" +#include "gdcmScanner.h" +#include "gdcmAttribute.h" +#include "gdcmSubject.h" +#include "gdcmCommand.h" +#include "gdcmAnonymizer.h" +#include "gdcmFileAnonymizer.h" +#include "gdcmFileStreamer.h" +#include "gdcmSystem.h" +#include "gdcmTrace.h" +#include "gdcmUIDs.h" +#include "gdcmSorter.h" +#include "gdcmIPPSorter.h" +#include "gdcmSpectroscopy.h" +#include "gdcmPrinter.h" +#include "gdcmXMLPrinter.h" +#include "gdcmDumper.h" +#include "gdcmOrientation.h" +#include "gdcmFiducials.h" +#include "gdcmWaveform.h" +#include "gdcmPersonName.h" +#include "gdcmCurve.h" +#include "gdcmDICOMDIR.h" +#include "gdcmValidate.h" +#include "gdcmApplicationEntity.h" +#include "gdcmDictPrinter.h" +#include "gdcmFilenameGenerator.h" +#include "gdcmVersion.h" +#include "gdcmFilename.h" +#include "gdcmEnumeratedValues.h" +#include "gdcmPatient.h" +#include "gdcmStudy.h" +#include "gdcmUsage.h" +#include "gdcmMacroEntry.h" +#include "gdcmModuleEntry.h" +#include "gdcmNestedModuleEntries.h" +#include "gdcmMacro.h" +#include "gdcmMacros.h" +#include "gdcmModule.h" +#include "gdcmModules.h" +#include "gdcmDefs.h" +#include "gdcmIOD.h" +#include "gdcmIODs.h" +#include "gdcmTableEntry.h" +#include "gdcmDefinedTerms.h" +#include "gdcmSeries.h" +#include "gdcmIODEntry.h" +#include "gdcmRescaler.h" +#include "gdcmSegmentedPaletteColorLookupTable.h" +#include "gdcmUnpacker12Bits.h" +#include "gdcmPythonFilter.h" +#include "gdcmDirectionCosines.h" +#include "gdcmTagPath.h" +#include "gdcmBitmapToBitmapFilter.h" +#include "gdcmPixmapToPixmapFilter.h" +#include "gdcmImageToImageFilter.h" +#include "gdcmSOPClassUIDToIOD.h" +#include "gdcmCoder.h" +#include "gdcmDecoder.h" +#include "gdcmCodec.h" +#include "gdcmImageCodec.h" +#include "gdcmJPEGCodec.h" +#include "gdcmJPEGLSCodec.h" +#include "gdcmJPEG2000Codec.h" +#include "gdcmPNMCodec.h" +#include "gdcmImageChangeTransferSyntax.h" +#include "gdcmFileChangeTransferSyntax.h" +#include "gdcmImageApplyLookupTable.h" +#include "gdcmSplitMosaicFilter.h" +#include "gdcmImageChangePhotometricInterpretation.h" +#include "gdcmImageChangePlanarConfiguration.h" +#include "gdcmImageFragmentSplitter.h" +#include "gdcmDataSetHelper.h" +#include "gdcmFileExplicitFilter.h" +#include "gdcmImageHelper.h" +#include "gdcmMD5.h" +#include "gdcmDummyValueGenerator.h" +#include "gdcmSHA1.h" +#include "gdcmBase64.h" +#include "gdcmCryptographicMessageSyntax.h" +#include "gdcmCryptoFactory.h" +#include "gdcmSpacing.h" +#include "gdcmIconImageGenerator.h" +#include "gdcmIconImageFilter.h" + +#include "gdcmSimpleSubjectWatcher.h" +#include "gdcmDICOMDIRGenerator.h" +#include "gdcmFileDerivation.h" + +#include "gdcmQueryBase.h" +#include "gdcmQueryFactory.h" +#include "gdcmBaseRootQuery.h" +#include "gdcmPresentationContext.h" +#include "gdcmPresentationContextGenerator.h" +#include "gdcmCompositeNetworkFunctions.h" +#include "gdcmServiceClassUser.h" + +#include "gdcmStreamImageReader.h" + +#include "gdcmRegion.h" +#include "gdcmBoxRegion.h" +#include "gdcmImageRegionReader.h" +#include "gdcmJSON.h" + +using namespace gdcm; +%} + +//%insert("runtime") %{ +//#include "myheader.h" +//%} + +%include "docstrings.i" + +// swig need to know what are uint16_t, uint8_t... +%include "stdint.i" +//typedef int gdcm::DataSet::SizeType; // FIXME +//%include "typemaps.i" + +// gdcm does not use std::string in its interface, but we do need it for the +// %extend (see below) +%include "std_string.i" +%include "std_set.i" +%include "std_vector.i" +%include "std_pair.i" +%include "std_map.i" +%include "exception.i" + +// operator= is not needed in python AFAIK +%ignore operator=; // Ignore = everywhere. +%ignore operator++; // Ignore + +%define EXTEND_CLASS_PRINT_GENERAL(classfuncname,classname) +%extend classname +{ + const char *classfuncname() { + static std::string buffer; + std::ostringstream os; + os << *self; + buffer = os.str(); + return buffer.c_str(); + } +}; +%enddef + +#if defined(SWIGPYTHON) +%define EXTEND_CLASS_PRINT(classname) +EXTEND_CLASS_PRINT_GENERAL(__str__,classname) +%enddef +#endif + +//%feature("autodoc", "1") +%include "gdcmConfigure.h" +//%include "gdcmTypes.h" +//%include "gdcmWin32.h" +// I cannot include gdcmWin32.h without gdcmTypes.h, first. But gdcmTypes.h needs to know _MSC_VER at swig time... +#define GDCM_EXPORT +%include "gdcmLegacyMacro.h" +%rename(__add__) gdcm::VL::operator+=; +%include "gdcmSwapCode.h" + +//%feature("director") Event; +//%feature("director") AnyEvent; +%include "gdcmEvent.h" + +%include "gdcmPixelFormat.h" +EXTEND_CLASS_PRINT(gdcm::PixelFormat) +%include "gdcmMediaStorage.h" +EXTEND_CLASS_PRINT(gdcm::MediaStorage) +%rename(__getitem__) gdcm::Tag::operator[]; +//%rename(__getattr__) gdcm::Tag::operator[]; +%include "gdcmTag.h" +EXTEND_CLASS_PRINT(gdcm::Tag) +%include "gdcmPrivateTag.h" +EXTEND_CLASS_PRINT(gdcm::PrivateTag) + +%include "gdcmProgressEvent.h" +%extend gdcm::ProgressEvent { + static ProgressEvent *Cast(Event *event) { + return dynamic_cast(event); + } +}; +//%feature("director") AnonymizeEvent; +%include "gdcmAnonymizeEvent.h" +%extend gdcm::AnonymizeEvent { + static AnonymizeEvent *Cast(Event *event) { + return dynamic_cast(event); + } +}; + +%include "gdcmVL.h" +EXTEND_CLASS_PRINT(gdcm::VL) +//%typemap(out) int +//{ +// $result = SWIG_NewPointerObj($1,SWIGTYPE_p_gdcm__VL,0); +//} +%include "gdcmVR.h" +EXTEND_CLASS_PRINT(gdcm::VR) +%include "gdcmVM.h" +EXTEND_CLASS_PRINT(gdcm::VM) +//%template (FilenameType) std::string; +%template (FilenamesType) std::vector; +%include "gdcmDirectory.h" +EXTEND_CLASS_PRINT(gdcm::Directory) +//%clear FilenameType; +%clear FilenamesType; +%include "gdcmObject.h" +%include "gdcmValue.h" +EXTEND_CLASS_PRINT(gdcm::Value) +%ignore gdcm::ByteValue::WriteBuffer(std::ostream &os) const; +%ignore gdcm::ByteValue::GetPointer() const; +%ignore gdcm::ByteValue::GetBuffer(char *buffer, unsigned long length) const; +%include "gdcmByteValue.h" +EXTEND_CLASS_PRINT(gdcm::ByteValue) +%extend gdcm::ByteValue +{ + std::string WriteBuffer() const { + std::ostringstream os; + self->WriteBuffer(os); + return os.str(); + } + std::string GetBuffer() const { + std::ostringstream os; + self->WriteBuffer(os); + return os.str(); + } + std::string GetBuffer(unsigned long length) const { + std::ostringstream os; + self->WriteBuffer(os); + std::string copy( os.str().c_str(), length); + return copy; + } +}; +%include "gdcmASN1.h" +%include "gdcmSmartPointer.h" +%template(SmartPtrSQ) gdcm::SmartPointer; +%template(SmartPtrFrag) gdcm::SmartPointer; +%include "gdcmDataElement.h" +EXTEND_CLASS_PRINT(gdcm::DataElement) +%include "gdcmItem.h" +EXTEND_CLASS_PRINT(gdcm::Item) +%template() std::vector< gdcm::Item >; +%include "gdcmSequenceOfItems.h" +EXTEND_CLASS_PRINT(gdcm::SequenceOfItems) +%rename (PythonDataSet) SWIGDataSet; +%rename (PythonTagToValue) SWIGTagToValue; +%include "gdcmDataSet.h" +//namespace std { +// //struct lttag +// // { +// // bool operator()(const gdcm::DataElement &s1, +// // const gdcm::DataElement &s2) const +// // { +// // return s1.GetTag() < s2.GetTag(); +// // } +// // }; +// +// //%template(DataElementSet) gdcm::DataSet::DataElementSet; +// %template(DataElementSet) set; +//} +EXTEND_CLASS_PRINT(gdcm::DataSet) +//%include "gdcmString.h" +//%include "gdcmCodeString.h" +//%include "gdcmTransferSyntax.h" +%include "gdcmPhotometricInterpretation.h" +EXTEND_CLASS_PRINT(gdcm::PhotometricInterpretation) +%include "gdcmObject.h" +%include "gdcmLookupTable.h" +EXTEND_CLASS_PRINT(gdcm::LookupTable) +%include "gdcmOverlay.h" +EXTEND_CLASS_PRINT(gdcm::Overlay) +//%include "gdcmVR.h" +//%rename(DataElementSetPython) std::set; +//%rename(DataElementSetPython2) DataSet::DataElementSet; +%template (DataElementSet) std::set; +//%rename (SetString2) gdcm::DataElementSet; +%include "gdcmPreamble.h" +EXTEND_CLASS_PRINT(gdcm::Preamble) +%include "gdcmTransferSyntax.h" +EXTEND_CLASS_PRINT(gdcm::TransferSyntax) +%include "gdcmFileMetaInformation.h" +EXTEND_CLASS_PRINT(gdcm::FileMetaInformation) +%include "gdcmFile.h" +EXTEND_CLASS_PRINT(gdcm::File) +//%newobject gdcm::Image::GetBuffer; +%include "cstring.i" +%typemap(out) const unsigned int *GetDimensions { + int i; + int n = arg1->GetNumberOfDimensions(); + $result = PyList_New(n); + for (i = 0; i < n; i++) { + PyObject *o = PyInt_FromLong((long) $1[i]); + PyList_SetItem($result,i,o); + } +} +// Grab a 3 element array as a Python 3-tuple +%typemap(in) const unsigned int dims[3] (unsigned int temp[3]) { // temp[3] becomes a local variable + int i; + if (PyTuple_Check($input)) { + if (!PyArg_ParseTuple($input,"iii",temp,temp+1,temp+2)) { + PyErr_SetString(PyExc_TypeError,"tuple must have 3 elements"); + return NULL; + } + $1 = &temp[0]; + } else { + PyErr_SetString(PyExc_TypeError,"expected a tuple."); + return NULL; + } +} +%ignore gdcm::Bitmap::GetBuffer(char*) const; +%include "gdcmBitmap.h" +%clear const unsigned int dims[3]; +EXTEND_CLASS_PRINT(gdcm::Bitmap) +%extend gdcm::Bitmap +{ + // http://mail.python.org/pipermail/python-list/2006-January/361540.html + %cstring_output_allocate_size(char **buffer, unsigned int *size, free(*$1) ); + void GetBuffer(char **buffer, unsigned int *size) { + *size = self->GetBufferLength(); + *buffer = (char*)malloc(*size); + self->GetBuffer(*buffer); + } +}; +%include "gdcmIconImage.h" +EXTEND_CLASS_PRINT(gdcm::IconImage) +%include "gdcmPixmap.h" +EXTEND_CLASS_PRINT(gdcm::Pixmap) +%typemap(out) const double *GetOrigin, const double *GetSpacing { + int i; + $result = PyList_New(3); + for (i = 0; i < 3; i++) { + PyObject *o = PyFloat_FromDouble((double) $1[i]); + PyList_SetItem($result,i,o); + } +} +%typemap(out) const double *GetDirectionCosines { + int i; + $result = PyList_New(6); + for (i = 0; i < 6; i++) { + PyObject *o = PyFloat_FromDouble((double) $1[i]); + PyList_SetItem($result,i,o); + } +} +%include "gdcmImage.h" +EXTEND_CLASS_PRINT(gdcm::Image) +%include "gdcmFragment.h" +EXTEND_CLASS_PRINT(gdcm::Fragment) +%include "gdcmPDBElement.h" +EXTEND_CLASS_PRINT(gdcm::PDBElement) +%include "gdcmPDBHeader.h" +EXTEND_CLASS_PRINT(gdcm::PDBHeader) +%include "gdcmCSAElement.h" +EXTEND_CLASS_PRINT(gdcm::CSAElement) +%include "gdcmCSAHeader.h" +EXTEND_CLASS_PRINT(gdcm::CSAHeader) +%include "gdcmSequenceOfFragments.h" +EXTEND_CLASS_PRINT(gdcm::SequenceOfFragments) +%include "gdcmBasicOffsetTable.h" +EXTEND_CLASS_PRINT(gdcm::BasicOffsetTable) +//%include "gdcmLO.h" +%include "gdcmFileSet.h" +EXTEND_CLASS_PRINT(gdcm::FileSet) + +%include "gdcmGlobal.h" +EXTEND_CLASS_PRINT(gdcm::Global) + +%include "gdcmDictEntry.h" +EXTEND_CLASS_PRINT(gdcm::DictEntry) +%include "gdcmCSAHeaderDictEntry.h" +EXTEND_CLASS_PRINT(gdcm::CSAHeaderDictEntry) + +%template(DictEntryTagPairType) std::pair< gdcm::DictEntry, gdcm::Tag>; +%include "gdcmDict.h" +EXTEND_CLASS_PRINT(gdcm::Dict) +%extend gdcm::Dict +{ + std::pair GetDictEntryByKeyword(const char *keyword) const { + std::pair ret; + ret.first = self->GetDictEntryByKeyword(keyword, ret.second); + return ret; + } +} +%ignore gdcm::Dict::GetDictEntryByKeyword(const char *keyword, Tag & tag) const; +%include "gdcmCSAHeaderDict.h" +EXTEND_CLASS_PRINT(gdcm::CSAHeaderDictEntry) +%include "gdcmDicts.h" +EXTEND_CLASS_PRINT(gdcm::Dicts) + +%template (TagSetType) std::set; +%ignore gdcm::Reader::SetStream; +%exception ReadFooBar { + try { + $action + } catch (std::exception &e) { + PyErr_SetString(PyExc_IndexError, const_cast(e.what())); + return false; + } catch ( ... ) { + PyErr_SetString(PyExc_IndexError, "foobarstuff"); + return false; + } +} +%include "gdcmReader.h" +//EXTEND_CLASS_PRINT(gdcm::Reader) +%include "gdcmPixmapReader.h" +//EXTEND_CLASS_PRINT(gdcm::PixmapReader) +%include "gdcmImageReader.h" +//EXTEND_CLASS_PRINT(gdcm::ImageReader) +%include "gdcmWriter.h" +//EXTEND_CLASS_PRINT(gdcm::Writer) +%include "gdcmPixmapWriter.h" +//EXTEND_CLASS_PRINT(gdcm::PixmapWriter) +%include "gdcmImageWriter.h" +//EXTEND_CLASS_PRINT(gdcm::ImageWriter) +%template (PairString) std::pair; +//%template (MyM) std::map; +%include "gdcmStringFilter.h" +//EXTEND_CLASS_PRINT(gdcm::StringFilter) +%include "gdcmUIDGenerator.h" +//EXTEND_CLASS_PRINT(gdcm::UIDGenerator) +%include "gdcmUUIDGenerator.h" +//EXTEND_CLASS_PRINT(gdcm::UUIDGenerator) +//%include "gdcmConstCharWrapper.h" +//%{ +// typedef char * PString; // copied to wrapper code +//%} +//%template (FilenameToValue) std::map; +//%template (FilenameToValue) std::map; +//%template (FilenameToValue) std::map; +//%template (MappingType) std::map; +//%template (StringArray) std::vector; +%template (ValuesType) std::set; +%rename (PythonTagToValue) SWIGTagToValue; +//%template (TagToValue) std::map; +//%template (TagToValue) std::map; +//%template (stdFilenameToValue) std::map; +//namespace gdcm +//{ +// class FilenameToValue : public std::map +// { +// void foo(); +// }; +//} +#define GDCM_STATIC_ASSERT(x) +%include "gdcmAttribute.h" +%include "gdcmSubject.h" +%include "gdcmCommand.h" + +%template(SmartPtrScan) gdcm::SmartPointer; +%include "gdcmScanner.h" +EXTEND_CLASS_PRINT(gdcm::Scanner) + +%template(SmartPtrAno) gdcm::SmartPointer; +//%ignore gdcm::Anonymizer::Anonymizer; + + +//%template(Anonymizer) gdcm::SmartPointer; +// +//%ignore gdcm::Anonymizer; +//%feature("unref") Anonymizer "coucou $this->Delete();" +// http://www.swig.org/Doc1.3/SWIGPlus.html#SWIGPlus%5Fnn34 +%include "gdcmAnonymizer.h" +%apply char[] { char* value_data } +%include "gdcmFileAnonymizer.h" +%clear char* value_data; + +%apply char[] { char* array } +%template(SmartPtrFStreamer) gdcm::SmartPointer; +%include "gdcmFileStreamer.h" +%clear char* array; + +//EXTEND_CLASS_PRINT(gdcm::Anonymizer) +%include "gdcmSystem.h" +//EXTEND_CLASS_PRINT(gdcm::System) + +%include "gdcmTrace.h" +//EXTEND_CLASS_PRINT(gdcm::Trace) +%include "gdcmUIDs.h" +EXTEND_CLASS_PRINT(gdcm::UIDs) +//%feature("director") gdcm::IPPSorter; + +%{ +static bool callback_helper(gdcm::DataSet const & ds1, gdcm::DataSet const & ds2) +{ + PyObject *func, *arglist, *result; + func = 0; //(PyObject *)data; + if (!(arglist = Py_BuildValue("()"))) { + /* fail */ + assert(0); + } + result = PyEval_CallObject(func, arglist); + Py_DECREF(arglist); + if (result && result != Py_None) { + PyErr_SetString(PyExc_TypeError, + "Callback function should return nothing"); + Py_DECREF(result); + /* fail */ + assert(0); + } else if (!result) { + /* fail: a Python exception was raised */ + assert(0); + } + return true; +} +%} +//%{ +//static void callback_decref(void *data) +//{ +// /* Lose the reference to the Python callback */ +// Py_DECREF(data); +//} +//%} +%typemap(in) (gdcm::Sorter::SortFunction f) { + if (!PyCallable_Check($input)) { + PyErr_SetString(PyExc_TypeError, "Need a callable object!"); + SWIG_fail; + } + $1 = callback_helper; +// $2 = (void *)$input; +// $2 = callback_decref; +// $3 = (void *)$input; + /* Keep a reference to the Python callback */ + Py_INCREF($input); +} + +%include "gdcmSorter.h" +EXTEND_CLASS_PRINT(gdcm::Sorter) +%include "gdcmIPPSorter.h" +EXTEND_CLASS_PRINT(gdcm::IPPSorter) +%include "gdcmSpectroscopy.h" +//EXTEND_CLASS_PRINT(gdcm::Spectroscopy) +%include "gdcmPrinter.h" +//EXTEND_CLASS_PRINT(gdcm::Printer) +%include "gdcmXMLPrinter.h" +//EXTEND_CLASS_PRINT(gdcm::XMLPrinter) +%include "gdcmDumper.h" +//EXTEND_CLASS_PRINT(gdcm::Dumper) + +// Grab a 6 element array as a Python 6-tuple +%typemap(in) const double dircos[6] (double temp[6]) { // temp[6] becomes a local variable + int i; + if (PyTuple_Check($input) /*|| PyList_Check($input)*/) { + if (!PyArg_ParseTuple($input,"dddddd",temp,temp+1,temp+2,temp+3,temp+4,temp+5)) { + PyErr_SetString(PyExc_TypeError,"list must have 6 elements"); + return NULL; + } + $1 = &temp[0]; + } else { + PyErr_SetString(PyExc_TypeError,"expected a list."); + return NULL; + } +} +%include "gdcmOrientation.h" +EXTEND_CLASS_PRINT(gdcm::Orientation) +//%typemap(argout) double z[3] { // temp[6] becomes a local variable +// int i; +// $result = PyList_New(3); +// for (i = 0; i < 3; i++) { +// PyObject *o = PyFloat_FromDouble((double) $1[i]); +// PyList_SetItem($result,i,o); +// } +//} +//%typemap(in,numinputs=0) double z[3] (double temp[3]) { +// $1[0] = temp[0]; +// $1[1] = temp[1]; +// $1[2] = temp[2]; +//} +%include "gdcmDirectionCosines.h" +EXTEND_CLASS_PRINT(gdcm::DirectionCosines) +//%clear const double dircos[6]; + +%include "gdcmFiducials.h" +%include "gdcmWaveform.h" +%include "gdcmPersonName.h" +%include "gdcmCurve.h" +%include "gdcmDICOMDIR.h" +%include "gdcmValidate.h" +%include "gdcmApplicationEntity.h" +%include "gdcmDictPrinter.h" +%include "gdcmFilenameGenerator.h" +%include "gdcmVersion.h" +EXTEND_CLASS_PRINT(gdcm::Version) +%include "gdcmFilename.h" +%include "gdcmEnumeratedValues.h" +%include "gdcmPatient.h" +%include "gdcmStudy.h" +%include "gdcmUsage.h" +%include "gdcmMacroEntry.h" +%include "gdcmModuleEntry.h" +EXTEND_CLASS_PRINT(gdcm::ModuleEntry) +%include "gdcmNestedModuleEntries.h" +%include "gdcmMacro.h" +%include "gdcmMacros.h" +%include "gdcmModule.h" +%include "gdcmModules.h" +%include "gdcmDefs.h" +%include "gdcmIOD.h" +%include "gdcmIODs.h" +%include "gdcmTableEntry.h" +%include "gdcmDefinedTerms.h" +%include "gdcmSeries.h" +%include "gdcmIODEntry.h" +%include "gdcmRescaler.h" +%include "gdcmSegmentedPaletteColorLookupTable.h" +%include "gdcmUnpacker12Bits.h" + +%include "gdcmConfigure.h" +#ifdef GDCM_BUILD_TESTING +%include "gdcmTesting.h" +%ignore gdcm::Testing::ComputeMD5(const char *, const unsigned long , char []); +%ignore gdcm::Testing::ComputeFileMD5(const char*, char []); +%extend gdcm::Testing +{ + //static const char *ComputeMD5(const char *buffer) { + // static char buffer[33]; + // gdcm::Testing::ComputeFileMD5(filename, buffer); + // return buffer; + //} + static const char *ComputeFileMD5(const char *filename) { + static char buffer[33]; + gdcm::Testing::ComputeFileMD5(filename, buffer); + return buffer; + } +}; +#endif +%include "gdcmPythonFilter.h" +%include "gdcmTagPath.h" +%include "gdcmBitmapToBitmapFilter.h" +%include "gdcmPixmapToPixmapFilter.h" +%include "gdcmImageToImageFilter.h" +%include "gdcmSOPClassUIDToIOD.h" +//%feature("director") Coder; +//%include "gdcmCoder.h" +//%feature("director") Decoder; +//%include "gdcmDecoder.h" +//%feature("director") Codec; +//%include "gdcmCodec.h" +%feature("director") ImageCodec; +%include "gdcmImageCodec.h" +%include "gdcmJPEGCodec.h" +%include "gdcmJPEGLSCodec.h" +%include "gdcmJPEG2000Codec.h" +%include "gdcmPNMCodec.h" +%include "gdcmImageChangeTransferSyntax.h" +%template(SmartPtrFCTS) gdcm::SmartPointer; +%include "gdcmFileChangeTransferSyntax.h" +%include "gdcmImageApplyLookupTable.h" +%include "gdcmSplitMosaicFilter.h" +%include "gdcmImageChangePhotometricInterpretation.h" +%include "gdcmImageChangePlanarConfiguration.h" +%include "gdcmImageFragmentSplitter.h" +%include "gdcmDataSetHelper.h" +%include "gdcmFileExplicitFilter.h" +%template (DoubleArrayType) std::vector; +%template (UShortArrayType) std::vector; +%template (UIntArrayType) std::vector; +%include "gdcmImageHelper.h" +%include "gdcmMD5.h" +%include "gdcmDummyValueGenerator.h" +%include "gdcmSHA1.h" +%include "gdcmBase64.h" +%include "gdcmCryptographicMessageSyntax.h" +%include "gdcmCryptoFactory.h" +%include "gdcmSpacing.h" +%include "gdcmIconImageGenerator.h" +%include "gdcmIconImageFilter.h" + +%feature("director") SimpleSubjectWatcher; +%include "gdcmSimpleSubjectWatcher.h" +%include "gdcmDICOMDIRGenerator.h" +%include "gdcmFileDerivation.h" + +// MEXD: +%template(DataSetArrayType) std::vector< gdcm::DataSet >; +%template(FileArrayType) std::vector< gdcm::File >; +%template(PresentationContextArrayType) std::vector< gdcm::PresentationContext >; +%template(KeyValuePairType) std::pair< gdcm::Tag, std::string>; +%template(KeyValuePairArrayType) std::vector< std::pair< gdcm::Tag, std::string> >; +%template(TagArrayType) std::vector< gdcm::Tag >; +%include "gdcmQueryBase.h" +%include "gdcmBaseRootQuery.h" +%include "gdcmQueryFactory.h" +%template(CharSetArrayType) std::vector< gdcm::ECharSet >; +%include "gdcmCompositeNetworkFunctions.h" +%include "gdcmPresentationContext.h" +//EXTEND_CLASS_PRINT(gdcm::PresentationContext) +%include "gdcmPresentationContextGenerator.h" +typedef int64_t time_t; // FIXME +%include "gdcmServiceClassUser.h" +%apply char[] { char* inReadBuffer } +%include "gdcmStreamImageReader.h" +%clear char* inReadBuffer; +%include "gdcmRegion.h" +EXTEND_CLASS_PRINT(gdcm::Region) +%include "gdcmBoxRegion.h" +EXTEND_CLASS_PRINT(gdcm::BoxRegion) +%apply char[] { char* inreadbuffer } +%include "gdcmImageRegionReader.h" +%clear char* inreadbuffer; +%include "gdcmJSON.h" diff --git a/gdcm/Wrapping/SWIGCommon/gdcmcommon.i b/gdcm/Wrapping/SWIGCommon/gdcmcommon.i new file mode 100644 index 0000000..8794bce --- /dev/null +++ b/gdcm/Wrapping/SWIGCommon/gdcmcommon.i @@ -0,0 +1,814 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +// See docs: +// http://www.swig.org/Doc1.3/Python.html +// http://www.swig.org/Doc1.3/SWIGPlus.html#SWIGPlus +// cstring_output_allocate_size: +// http://www.swig.org/Doc1.3/Library.html +// http://www.geocities.com/foetsch/python/extending_python.htm +// http://www.ddj.com/cpp/184401747 +// http://www.ddj.com/article/printableArticle.jhtml;jsessionid=VM4IXCQG5KM10QSNDLRSKH0CJUNN2JVN?articleID=184401747&dept_url=/cpp/ +// http://matt.eifelle.com/2008/11/04/exposing-an-array-interface-with-swig-for-a-cc-structure/ + +%module(directors="1",docstring="A DICOM library") gdcmswig +#pragma SWIG nowarn=504,510 +%{ +#include "gdcmTypes.h" +#include "gdcmSmartPointer.h" +#include "gdcmSwapCode.h" +#include "gdcmDirectory.h" +#include "gdcmTesting.h" +#include "gdcmObject.h" +#include "gdcmPixelFormat.h" +#include "gdcmMediaStorage.h" +#include "gdcmTag.h" +#include "gdcmPrivateTag.h" +#include "gdcmVL.h" +#include "gdcmVR.h" +#include "gdcmVM.h" +#include "gdcmObject.h" +#include "gdcmValue.h" +#include "gdcmByteValue.h" +#include "gdcmDataElement.h" +#include "gdcmItem.h" +#include "gdcmSequenceOfItems.h" +#include "gdcmDataSet.h" +//#include "gdcmString.h" +#include "gdcmPreamble.h" +#include "gdcmFile.h" +#include "gdcmBitmap.h" +#include "gdcmPixmap.h" +#include "gdcmImage.h" +#include "gdcmIconImage.h" +#include "gdcmFragment.h" +#include "gdcmCSAHeader.h" +#include "gdcmPDBHeader.h" +#include "gdcmSequenceOfFragments.h" +#include "gdcmTransferSyntax.h" +#include "gdcmBasicOffsetTable.h" +//#include "gdcmLO.h" +#include "gdcmCSAElement.h" +#include "gdcmPDBElement.h" +#include "gdcmFileSet.h" + +#include "gdcmReader.h" +#include "gdcmPixmapReader.h" +#include "gdcmImageReader.h" +#include "gdcmWriter.h" +#include "gdcmPixmapWriter.h" +#include "gdcmImageWriter.h" +#include "gdcmStringFilter.h" +#include "gdcmGlobal.h" +#include "gdcmDicts.h" +#include "gdcmDict.h" +#include "gdcmCSAHeaderDict.h" +#include "gdcmDictEntry.h" +#include "gdcmCSAHeaderDictEntry.h" +#include "gdcmUIDGenerator.h" +//#include "gdcmConstCharWrapper.h" +#include "gdcmScanner.h" +#include "gdcmAttribute.h" +#include "gdcmAnonymizer.h" +#include "gdcmSystem.h" +#include "gdcmTrace.h" +#include "gdcmUIDs.h" +#include "gdcmSorter.h" +#include "gdcmIPPSorter.h" +#include "gdcmSpectroscopy.h" +#include "gdcmPrinter.h" +#include "gdcmDumper.h" +#include "gdcmOrientation.h" +#include "gdcmFiducials.h" +#include "gdcmWaveform.h" +#include "gdcmPersonName.h" +#include "gdcmIconImage.h" +#include "gdcmCurve.h" +#include "gdcmDICOMDIR.h" +#include "gdcmValidate.h" +#include "gdcmApplicationEntity.h" +#include "gdcmDictPrinter.h" +#include "gdcmFilenameGenerator.h" +#include "gdcmVersion.h" +#include "gdcmFilename.h" +#include "gdcmEnumeratedValues.h" +#include "gdcmPatient.h" +#include "gdcmStudy.h" +#include "gdcmModule.h" +#include "gdcmModules.h" +#include "gdcmDefs.h" +#include "gdcmIOD.h" +#include "gdcmIODs.h" +#include "gdcmTableEntry.h" +#include "gdcmDefinedTerms.h" +#include "gdcmSeries.h" +#include "gdcmModuleEntry.h" +#include "gdcmNestedModuleEntries.h" +#include "gdcmIODEntry.h" +#include "gdcmRescaler.h" +#include "gdcmSegmentedPaletteColorLookupTable.h" +#include "gdcmUnpacker12Bits.h" +#include "gdcmPythonFilter.h" +#include "gdcmDirectionCosines.h" +#include "gdcmTagPath.h" +#include "gdcmPixmapToPixmapFilter.h" +#include "gdcmImageToImageFilter.h" +#include "gdcmSOPClassUIDToIOD.h" +#include "gdcmImageChangeTransferSyntax.h" +#include "gdcmImageApplyLookupTable.h" +#include "gdcmSplitMosaicFilter.h" +//#include "gdcmImageChangePhotometricInterpretation.h" +#include "gdcmImageChangePlanarConfiguration.h" +#include "gdcmImageFragmentSplitter.h" +#include "gdcmDataSetHelper.h" +#include "gdcmFileExplicitFilter.h" +#include "gdcmImageHelper.h" +#include "gdcmMD5.h" +#include "gdcmDummyValueGenerator.h" +#include "gdcmSHA1.h" +//#include "gdcmBase64.h" +#include "gdcmSpacing.h" + +using namespace gdcm; +%} + +//%insert("runtime") %{ +//#include "myheader.h" +//%} + +%include "docstrings.i" + +// swig need to know what are uint16_t, uint8_t... +%include "stdint.i" +//typedef int gdcm::DataSet::SizeType; // FIXME +//%include "typemaps.i" + +// gdcm does not use std::string in its interface, but we do need it for the +// %extend (see below) +%include "std_string.i" +%include "std_set.i" +%include "std_vector.i" +%include "std_pair.i" +%include "std_map.i" +%include "exception.i" + +// operator= is not needed in python AFAIK +%ignore operator=; // Ignore = everywhere. +%ignore operator++; // Ignore + +//%feature("autodoc", "1") +//%include "gdcmTypes.h" // define GDCM_EXPORT so need to be the first one... +#define GDCM_EXPORT +%rename(__add__) gdcm::VL::operator+=; +%include "gdcmSwapCode.h" +%include "gdcmPixelFormat.h" +%extend gdcm::PixelFormat +{ + const char *__str__() { + static std::string buffer; + std::ostringstream os; + os << *self; + buffer = os.str(); + return buffer.c_str(); + } +}; +%include "gdcmMediaStorage.h" +%rename(__getitem__) gdcm::Tag::operator[]; +//%rename(__getattr__) gdcm::Tag::operator[]; +%include "gdcmTag.h" +%extend gdcm::Tag +{ + const char *__str__() { + static std::string buffer; + std::ostringstream os; + os << *self; + buffer = os.str(); + return buffer.c_str(); + } +}; +%include "gdcmPrivateTag.h" +%extend gdcm::PrivateTag +{ + const char *__str__() { + static std::string buffer; + std::ostringstream os; + os << *self; + buffer = os.str(); + return buffer.c_str(); + } +}; +%include "gdcmVL.h" +%extend gdcm::VL +{ + const char *__str__() { + static std::string buffer; + std::ostringstream os; + os << *self; + buffer = os.str(); + return buffer.c_str(); + } +}; +//%typemap(out) int +//{ +// $result = SWIG_NewPointerObj($1,SWIGTYPE_p_gdcm__VL,0); +//} +%include "gdcmVR.h" +%extend gdcm::VR +{ + const char *__str__() { + static std::string buffer; + std::ostringstream os; + os << *self; + buffer = os.str(); + return buffer.c_str(); + } +}; +%include "gdcmVM.h" +//%template (FilenameType) std::string; +%template (FilenamesType) std::vector; +%include "gdcmDirectory.h" +%extend gdcm::Directory +{ + const char *__str__() { + static std::string buffer; + std::stringstream s; + self->Print(s); + buffer = s.str(); + return buffer.c_str(); + } +}; +%include "gdcmObject.h" +%include "gdcmValue.h" +%extend gdcm::Value +{ + const char *__str__() { + static std::string buffer; + std::ostringstream os; + os << *self; + buffer = os.str(); + return buffer.c_str(); + } +}; +%ignore gdcm::ByteValue::WriteBuffer(std::ostream &os) const; +%ignore gdcm::ByteValue::GetPointer() const; +%ignore gdcm::ByteValue::GetBuffer(char *buffer, unsigned long length) const; +%include "gdcmByteValue.h" +%extend gdcm::ByteValue +{ + const char *__str__() const { + static std::string buffer; + std::ostringstream os; + os << *self; + buffer = os.str(); + return buffer.c_str(); + } + std::string WriteBuffer() const { + std::ostringstream os; + self->WriteBuffer(os); + return os.str(); + } + std::string GetBuffer() const { + std::ostringstream os; + self->WriteBuffer(os); + return os.str(); + } + std::string GetBuffer(unsigned long length) const { + std::ostringstream os; + self->WriteBuffer(os); + std::string copy( os.str().c_str(), length); + return copy; + } +}; +%include "gdcmSmartPointer.h" +%template(SmartPtrSQ) gdcm::SmartPointer; +%template(SmartPtrFrag) gdcm::SmartPointer; +%include "gdcmDataElement.h" +%extend gdcm::DataElement +{ + const char *__str__() { + static std::string buffer; + std::ostringstream os; + os << *self; + buffer = os.str(); + return buffer.c_str(); + } +}; +%include "gdcmItem.h" +%extend gdcm::Item +{ + const char *__str__() { + static std::string buffer; + std::ostringstream os; + os << *self; + buffer = os.str(); + return buffer.c_str(); + } +}; +%include "gdcmSequenceOfItems.h" +%extend gdcm::SequenceOfItems +{ + const char *__str__() { + static std::string buffer; + std::ostringstream os; + os << *self; + buffer = os.str(); + return buffer.c_str(); + } +}; +%rename (PythonDataSet) SWIGDataSet; +%rename (PythonTagToValue) SWIGTagToValue; +%include "gdcmDataSet.h" +//namespace std { +// //struct lttag +// // { +// // bool operator()(const gdcm::DataElement &s1, +// // const gdcm::DataElement &s2) const +// // { +// // return s1.GetTag() < s2.GetTag(); +// // } +// // }; +// +// //%template(DataElementSet) gdcm::DataSet::DataElementSet; +// %template(DataElementSet) set; +//} +%extend gdcm::DataSet +{ + const char *__str__() { + static std::string buffer; + std::stringstream s; + self->Print(s); + buffer = s.str(); + return buffer.c_str(); + } +}; +//%include "gdcmString.h" +//%include "gdcmTransferSyntax.h" +%include "gdcmPhotometricInterpretation.h" +%include "gdcmObject.h" +%include "gdcmLookupTable.h" +%include "gdcmOverlay.h" +//%include "gdcmVR.h" +//%rename(DataElementSetPython) std::set; +//%rename(DataElementSetPython2) DataSet::DataElementSet; +%template (DataElementSet) std::set; +//%rename (SetString2) gdcm::DataElementSet; +%include "gdcmPreamble.h" +%include "gdcmTransferSyntax.h" +%extend gdcm::TransferSyntax +{ + const char *__str__() { + static std::string buffer; + std::ostringstream os; + os << *self; + buffer = os.str(); + return buffer.c_str(); + } +}; +%include "gdcmFileMetaInformation.h" +%extend gdcm::FileMetaInformation +{ + const char *__str__() { + static std::string buffer; + std::ostringstream os; + os << *self; + buffer = os.str(); + return buffer.c_str(); + } +}; +%include "gdcmFile.h" +%extend gdcm::File +{ + const char *__str__() { + static std::string buffer; + std::ostringstream os; + os << *self; + buffer = os.str(); + return buffer.c_str(); + } +}; +//%newobject gdcm::Image::GetBuffer; +%include "cstring.i" +%typemap(out) const unsigned int *GetDimensions { + int i; + int n = arg1->GetNumberOfDimensions(); + $result = PyList_New(n); + for (i = 0; i < n; i++) { + PyObject *o = PyInt_FromLong((long) $1[i]); + PyList_SetItem($result,i,o); + } +} +// Grab a 3 element array as a Python 3-tuple +%typemap(in) const unsigned int dims[3] (unsigned int temp[3]) { // temp[3] becomes a local variable + int i; + if (PyTuple_Check($input)) { + if (!PyArg_ParseTuple($input,"iii",temp,temp+1,temp+2)) { + PyErr_SetString(PyExc_TypeError,"tuple must have 3 elements"); + return NULL; + } + $1 = &temp[0]; + } else { + PyErr_SetString(PyExc_TypeError,"expected a tuple."); + return NULL; + } +} +%ignore gdcm::Bitmap::GetBuffer(char*) const; +%include "gdcmBitmap.h" +%clear const unsigned int dims[3]; +%extend gdcm::Bitmap +{ + // http://mail.python.org/pipermail/python-list/2006-January/361540.html + %cstring_output_allocate_size(char **buffer, unsigned int *size, free(*$1) ); + void GetBuffer(char **buffer, unsigned int *size) { + *size = self->GetBufferLength(); + *buffer = (char*)malloc(*size); + self->GetBuffer(*buffer); + } + + const char *__str__() { + static std::string buffer; + std::stringstream s; + self->Print(s); + buffer = s.str(); + return buffer.c_str(); + } + +}; +%include "gdcmPixmap.h" +%extend gdcm::Pixmap +{ + const char *__str__() { + static std::string buffer; + std::stringstream s; + self->Print(s); + buffer = s.str(); + return buffer.c_str(); + } +}; + +%typemap(out) const double *GetOrigin, const double *GetSpacing { + int i; + $result = PyList_New(3); + for (i = 0; i < 3; i++) { + PyObject *o = PyFloat_FromDouble((double) $1[i]); + PyList_SetItem($result,i,o); + } +} +%typemap(out) const double *GetDirectionCosines { + int i; + $result = PyList_New(6); + for (i = 0; i < 6; i++) { + PyObject *o = PyFloat_FromDouble((double) $1[i]); + PyList_SetItem($result,i,o); + } +} +%include "gdcmImage.h" +%extend gdcm::Image +{ + const char *__str__() { + static std::string buffer; + std::stringstream s; + self->Print(s); + buffer = s.str(); + return buffer.c_str(); + } +}; +%include "gdcmIconImage.h" +%include "gdcmFragment.h" +%include "gdcmPDBElement.h" +%extend gdcm::PDBElement +{ + const char *__str__() { + static std::string buffer; + std::ostringstream os; + os << *self; + buffer = os.str(); + return buffer.c_str(); + } +}; +%include "gdcmPDBHeader.h" +%extend gdcm::PDBHeader +{ + const char *__str__() { + static std::string buffer; + std::stringstream s; + self->Print(s); + buffer = s.str(); + return buffer.c_str(); + } +}; +%include "gdcmCSAElement.h" +%extend gdcm::CSAElement +{ + const char *__str__() { + static std::string buffer; + std::ostringstream os; + os << *self; + buffer = os.str(); + return buffer.c_str(); + } +}; +%include "gdcmCSAHeader.h" +%extend gdcm::CSAHeader +{ + const char *__str__() { + static std::string buffer; + std::stringstream s; + self->Print(s); + buffer = s.str(); + return buffer.c_str(); + } +}; +%include "gdcmSequenceOfFragments.h" +%include "gdcmBasicOffsetTable.h" +//%include "gdcmLO.h" +%include "gdcmFileSet.h" + +%include "gdcmGlobal.h" + +%include "gdcmDictEntry.h" +%extend gdcm::DictEntry +{ + const char *__str__() { + static std::string buffer; + std::ostringstream os; + os << *self; + buffer = os.str(); + return buffer.c_str(); + } +}; +%include "gdcmCSAHeaderDictEntry.h" +%extend gdcm::CSAHeaderDictEntry +{ + const char *__str__() { + static std::string buffer; + std::ostringstream os; + os << *self; + buffer = os.str(); + return buffer.c_str(); + } +}; + +%include "gdcmDict.h" +%include "gdcmCSAHeaderDict.h" +%include "gdcmDicts.h" + +%exception ReadFooBar { + try { + $action + } catch (std::exception &e) { + PyErr_SetString(PyExc_IndexError, const_cast(e.what())); + return false; + } catch ( ... ) { + PyErr_SetString(PyExc_IndexError, "foobarstuff"); + return false; + } +} +%include "gdcmReader.h" +%include "gdcmPixmapReader.h" +%include "gdcmImageReader.h" +%include "gdcmWriter.h" +%include "gdcmPixmapWriter.h" +%include "gdcmImageWriter.h" +%template (PairString) std::pair; +//%template (MyM) std::map; +%include "gdcmStringFilter.h" +%include "gdcmUIDGenerator.h" +//%include "gdcmConstCharWrapper.h" +//%{ +// typedef char * PString; // copied to wrapper code +//%} +//%template (FilenameToValue) std::map; +//%template (FilenameToValue) std::map; +//%template (FilenameToValue) std::map; +//%template (MappingType) std::map; +//%template (StringArray) std::vector; +%template (ValuesType) std::set; +//%template (TagToValue) std::map; +//%template (TagToValue) std::map; +%include "gdcmScanner.h" +%extend gdcm::Scanner +{ + const char *__str__() { + static std::string buffer; + std::stringstream s; + self->Print(s); + buffer = s.str(); + return buffer.c_str(); + } +}; +//%template (stdFilenameToValue) std::map; +//namespace gdcm +//{ +// class FilenameToValue : public std::map +// { +// void foo(); +// }; +//} +#define GDCM_STATIC_ASSERT(x) +%include "gdcmAttribute.h" +%include "gdcmAnonymizer.h" +%include "gdcmSystem.h" +%include "gdcmTrace.h" +%include "gdcmUIDs.h" +//%feature("director") gdcm::IPPSorter; + +%{ +static bool callback_helper(gdcm::DataSet const & ds1, gdcm::DataSet const & ds2) +{ + PyObject *func, *arglist, *result; + func = 0; //(PyObject *)data; + if (!(arglist = Py_BuildValue("()"))) { + /* fail */ + assert(0); + } + result = PyEval_CallObject(func, arglist); + Py_DECREF(arglist); + if (result && result != Py_None) { + PyErr_SetString(PyExc_TypeError, + "Callback function should return nothing"); + Py_DECREF(result); + /* fail */ + assert(0); + } else if (!result) { + /* fail: a Python exception was raised */ + assert(0); + } + return true; +} +%} +//%{ +//static void callback_decref(void *data) +//{ +// /* Lose the reference to the Python callback */ +// Py_DECREF(data); +//} +//%} +%typemap(in) (gdcm::Sorter::SortFunction f) { + if (!PyCallable_Check($input)) { + PyErr_SetString(PyExc_TypeError, "Need a callable object!"); + SWIG_fail; + } + $1 = callback_helper; +// $2 = (void *)$input; +// $2 = callback_decref; +// $3 = (void *)$input; + /* Keep a reference to the Python callback */ + Py_INCREF($input); +} + +%include "gdcmSorter.h" +%extend gdcm::Sorter +{ + const char *__str__() { + static std::string buffer; + std::stringstream s; + self->Print(s); + buffer = s.str(); + return buffer.c_str(); + } +}; +%include "gdcmIPPSorter.h" +%include "gdcmSpectroscopy.h" +%include "gdcmPrinter.h" +%include "gdcmDumper.h" + +// Grab a 6 element array as a Python 6-tuple +%typemap(in) const double dircos[6] (double temp[6]) { // temp[6] becomes a local variable + int i; + if (PyTuple_Check($input) /*|| PyList_Check($input)*/) { + if (!PyArg_ParseTuple($input,"dddddd",temp,temp+1,temp+2,temp+3,temp+4,temp+5)) { + PyErr_SetString(PyExc_TypeError,"list must have 6 elements"); + return NULL; + } + $1 = &temp[0]; + } else { + PyErr_SetString(PyExc_TypeError,"expected a list."); + return NULL; + } +} +%include "gdcmOrientation.h" +%extend gdcm::Orientation +{ + const char *__str__() { + static std::string buffer; + std::stringstream s; + self->Print(s); + buffer = s.str(); + return buffer.c_str(); + } +}; +//%typemap(argout) double z[3] { // temp[6] becomes a local variable +// int i; +// $result = PyList_New(3); +// for (i = 0; i < 3; i++) { +// PyObject *o = PyFloat_FromDouble((double) $1[i]); +// PyList_SetItem($result,i,o); +// } +//} +//%typemap(in,numinputs=0) double z[3] (double temp[3]) { +// $1[0] = temp[0]; +// $1[1] = temp[1]; +// $1[2] = temp[2]; +//} +%include "gdcmDirectionCosines.h" +%extend gdcm::DirectionCosines +{ + const char *__str__() { + static std::string buffer; + std::stringstream s; + self->Print(s); + buffer = s.str(); + return buffer.c_str(); + } +}; +//%clear const double dircos[6]; + +%include "gdcmFiducials.h" +%include "gdcmWaveform.h" +%include "gdcmPersonName.h" +%include "gdcmIconImage.h" +%include "gdcmCurve.h" +%include "gdcmDICOMDIR.h" +%include "gdcmValidate.h" +%include "gdcmApplicationEntity.h" +%include "gdcmDictPrinter.h" +%include "gdcmFilenameGenerator.h" +%include "gdcmVersion.h" +%include "gdcmFilename.h" +%include "gdcmEnumeratedValues.h" +%include "gdcmPatient.h" +%include "gdcmStudy.h" +%include "gdcmModuleEntry.h" +%extend gdcm::ModuleEntry +{ + const char *__str__() { + static std::string buffer; + std::ostringstream os; + os << *self; + buffer = os.str(); + return buffer.c_str(); + } +}; +%include "gdcmNestedModuleEntries.h" +%include "gdcmModule.h" +%include "gdcmModules.h" +%include "gdcmDefs.h" +%include "gdcmIOD.h" +%include "gdcmIODs.h" +%include "gdcmTableEntry.h" +%include "gdcmDefinedTerms.h" +%include "gdcmSeries.h" +%include "gdcmIODEntry.h" +%include "gdcmRescaler.h" +%include "gdcmSegmentedPaletteColorLookupTable.h" +%include "gdcmUnpacker12Bits.h" + +%include "gdcmConfigure.h" +#ifdef GDCM_BUILD_TESTING +%include "gdcmTesting.h" +%ignore gdcm::Testing::ComputeMD5(const char *, const unsigned long , char []); +%ignore gdcm::Testing::ComputeFileMD5(const char*, char []); +%extend gdcm::Testing +{ + //static const char *ComputeMD5(const char *buffer) { + // static char buffer[33]; + // gdcm::Testing::ComputeFileMD5(filename, buffer); + // return buffer; + //} + static const char *ComputeFileMD5(const char *filename) { + static char buffer[33]; + gdcm::Testing::ComputeFileMD5(filename, buffer); + return buffer; + } +}; +#endif +%include "gdcmPythonFilter.h" +%include "gdcmTagPath.h" +%include "gdcmPixmapToPixmapFilter.h" +%include "gdcmImageToImageFilter.h" +%include "gdcmSOPClassUIDToIOD.h" +%include "gdcmImageChangeTransferSyntax.h" +%include "gdcmImageApplyLookupTable.h" +%include "gdcmSplitMosaicFilter.h" +//%include "gdcmImageChangePhotometricInterpretation.h" +%include "gdcmImageChangePlanarConfiguration.h" +%include "gdcmImageFragmentSplitter.h" +%include "gdcmDataSetHelper.h" +%include "gdcmFileExplicitFilter.h" +%template (DoubleType) std::vector; +%include "gdcmImageHelper.h" +%include "gdcmMD5.h" +%include "gdcmDummyValueGenerator.h" +%include "gdcmSHA1.h" +//%include "gdcmBase64.h" +%include "gdcmSpacing.h" diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..b48f94e --- /dev/null +++ b/main.cpp @@ -0,0 +1,11 @@ +#include "mainwindow.h" +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + MainWindow w; + w.show(); + + return a.exec(); +} diff --git a/mainwindow.cpp b/mainwindow.cpp new file mode 100644 index 0000000..1c1e287 --- /dev/null +++ b/mainwindow.cpp @@ -0,0 +1,1923 @@ +#include "mainwindow.h" +#include "ui_mainwindow.h" + + +/* ------------------------------------------------- */ +/* --------- MainWindow ---------------------------- */ +/* ------------------------------------------------- */ +MainWindow::MainWindow(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::MainWindow) +{ + logfile.setFileName("output.log"); + logfile.open(QIODevice::WriteOnly | QIODevice::Text); + + idfile.setFileName("idmap.log"); + idfile.open(QIODevice::Append | QIODevice::Text); + + WriteLog("Entering MainWindow()"); + ui->setupUi(this); + this->showMaximized(); + qsrand(QTime::currentTime().msec()); + + numNetConn = 0; + + numFilesFound = 0; + numBytesFound = 0; + numAnonErrors = 0; + numBytesSentSuccess = 0; + numBytesSentFail = 0; + numBytesSentTotal = 0; + numFilesSentSuccess = 0; + numFilesSentFail = 0; + numFilesSentTotal = 0; + numBytesLastSend = 0; + numFilesLastSend = 0; + + networkManager = new QNetworkAccessManager(this); + isUploading = false; + + PopulateModality(); + PopulateConnectionList(); + SetBuildDate(); + + ui->cmbProxyType->addItem("(Select Proxy Type...)", ""); + ui->cmbProxyType->addItem("Default", "default"); + ui->cmbProxyType->addItem("Socks5", "socks5"); + ui->cmbProxyType->addItem("Http", "http"); + ui->cmbProxyType->addItem("HttpCaching", "httpcaching"); + ui->cmbProxyType->addItem("FtpCaching", "ftpcaching"); + + SetTempDir(); + WriteLog("Leaving MainWindow()"); +} + + +/* ------------------------------------------------- */ +/* --------- ~MainWindow --------------------------- */ +/* ------------------------------------------------- */ +MainWindow::~MainWindow() +{ + delete ui; + logfile.close(); + idfile.close(); +} + + +/* ------------------------------------------------- */ +/* --------- SetBuildDate -------------------------- */ +/* ------------------------------------------------- */ +void MainWindow::SetBuildDate() { + QLabel *statusLabel = new QLabel(this); // create objects for the status bar label + statusLabel->setText("Build date: " + QString::fromLocal8Bit(__DATE__)); // set text for the label + ui->statusBar->addPermanentWidget(statusLabel); // add the control to the status bar +} + + +/* ------------------------------------------------- */ +/* --------- PopulateModality ---------------------- */ +/* ------------------------------------------------- */ +void MainWindow::PopulateModality() { + WriteLog("Entering PopulateModality()"); + ui->cmbModality->addItem("(Select Modality...)", ""); + ui->cmbModality->addItem("All DICOM", "DICOM"); + ui->cmbModality->addItem("MR (DICOM)","MR"); + ui->cmbModality->addItem("MR (Non-DICOM: .hdr .img .nii .nii.gz)","NIFTI"); + ui->cmbModality->addItem("CT (DICOM)","CT"); + ui->cmbModality->addItem("PET (DICOM)","PET"); + ui->cmbModality->addItem("Phillips Imaging (.par/.rec)", "PARREC"); + ui->cmbModality->addItem("EEG (.cnt .dat .3dd)", "EEG"); + ui->cmbModality->addItem("Eye Tracking", "ET"); + ui->cmbModality->addItem("VIDEO (.wmv .avi .mpg .mpeg .mp4 .mkv)", "VIDEO"); + WriteLog("Leaving PopulateModality()"); +} + + +/* ------------------------------------------------- */ +/* --------- PopulateConnectionList ---------------- */ +/* ------------------------------------------------- */ +void MainWindow::PopulateConnectionList(){ + WriteLog("Entering PopulateConnectionList()"); + ui->lstConn->clear(); + QFile file("connections.txt"); + file.open(QIODevice::ReadOnly | QIODevice::Text); + QTextStream in(&file); + QList< QStringList > lists; + QString line; + do { + line = in.readLine(); + lists << line.split("\t"); + } while (!line.isNull()); + + QString connName; + for ( int row = 0; row < lists.size(); ++row ) { + if (lists[row].size() > 2) { + connName = lists[row][0] + ',' + lists[row][1] + ',' + lists[row][2]; + ui->lstConn->addItem(connName); + } + } + WriteLog("Leaving PopulateConnectionList()"); +} + + +/* ------------------------------------------------- */ +/* --------- on_btnExit_clicked -------------------- */ +/* ------------------------------------------------- */ +void MainWindow::on_btnExit_clicked() +{ + exit(0); +} + + +/* ------------------------------------------------- */ +/* --------- on_pushButton_clicked ----------------- */ +/* ------------------------------------------------- */ +void MainWindow::on_pushButton_clicked() +{ + QString server = ui->txtServer->text().trimmed(); + QString username = ui->txtUsername->text().trimmed(); + QString password = ui->txtPassword->text().trimmed(); + + QByteArray phash = QCryptographicHash::hash(password.toUtf8(), QCryptographicHash::Sha1); + + QFile file("connections.txt"); + file.open(QIODevice::Append | QIODevice::Text); + QTextStream out(&file); + out << server << "\t" << username << "\t" << phash.toHex().toUpper() << endl; + file.close(); + + PopulateConnectionList(); + +} + + +/* ------------------------------------------------- */ +/* --------- on_btnTestConn_clicked ---------------- */ +/* ------------------------------------------------- */ +/* test the specified connection */ +void MainWindow::on_btnTestConn_clicked() +{ + WriteLog("Caling SetProxy() in on_btnTestConn_clicked()..."); + networkManager->setProxy(GetProxy()); + WriteLog("Done caling SetProxy() in on_btnTestConn_clicked()..."); + + if (GetConnectionParms(connServer, connUsername, connPassword)) { + /* set the hourglass cursor */ + QApplication::setOverrideCursor(Qt::WaitCursor); + + /* prepare the form to be sent */ + QUrl url; + QByteArray postData; + url.setUrl(connServer + "/api.php"); + QNetworkRequest request(url); + request.setHeader(QNetworkRequest::ContentTypeHeader,"application/x-www-form-urlencoded"); + postData.append('u').append("=").append(connUsername).append("&"); + postData.append('p').append("=").append(connPassword); + + WriteLog("about to send the test POST in on_btnTestConn_clicked()"); + /* submit the POST request and setup the reply/error handlers */ + //networkManager = new QNetworkAccessManager(this); + QNetworkReply* reply = networkManager->post(request, postData); + numNetConn++; + connect(reply, SIGNAL(finished()), this, SLOT(onGetReply())); + + /* restore the regular cursor */ + QApplication::restoreOverrideCursor(); + } +} + + +/* ------------------------------------------------- */ +/* --------- onGetReply ---------------------------- */ +/* ------------------------------------------------- */ +void MainWindow::onGetReply() +{ + WriteLog("Entering onGetReply()"); + QNetworkReply* reply = qobject_cast(sender()); + QString response; + + /* check if there was a reply */ + if (reply) { + /* and check if there was an error along with the reply */ + if (reply->error() == QNetworkReply::NoError) { + const int available = reply->bytesAvailable(); + if (available > 0) { + const QByteArray buffer(reply->readAll()); + response = QString::fromUtf8(buffer); + } + } else { + response = tr("Error: %1 status: %2").arg(reply->errorString(), reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toString()); + } + + reply->deleteLater(); + } + + /* check for empty reply */ + if (response.trimmed().isEmpty()) + response = tr("Unable to retrieve POST response"); + + /* if it starts with 'Welcome' its just an authentication check */ + WriteLog("OnGetReply(" + response + ")"); + if (response.left(7) == "Welcome") + ShowMessageBox(response); + else { + WriteLog(response); + } + //ui->txtLog->append(response); + + WriteLog("Leaving OnGetReply()"); +} + + +/* ------------------------------------------------- */ +/* --------- onGetReplyUpload ---------------------- */ +/* ------------------------------------------------- */ +void MainWindow::onGetReplyUpload() +{ + WriteLog("Entering onGetReplyUpload()"); + isUploading = false; + + WriteLog(QString("(Z) numFilesSentTotal: [%1] numFilesSentSuccess: [%2] numFilesSentFail: [%3]").arg(numFilesSentTotal).arg(numFilesSentSuccess).arg(numFilesSentFail)); + + //qDebug() << "numNetConn (A): " << numNetConn; + QNetworkReply* reply = qobject_cast(sender()); + + QString response; + if (reply) { + if (reply->error() == QNetworkReply::NoError) { + const int available = reply->bytesAvailable(); + if (available > 0) { + const QByteArray buffer(reply->readAll()); + response = QString::fromUtf8(buffer); + } + } else { + response = tr("Error: %1 status: %2").arg(reply->errorString(), reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toString()); + } + + reply->deleteLater(); + } + + if (response.trimmed().isEmpty()) { + response = tr("Unable to retrieve POST response"); + } + + WriteLog("OnGetReplyUpload(" + response + ")"); + //ui->txtLog->append(response); + + WriteLog(QString("(Z1) numFilesSentTotal: [%1] numFilesSentSuccess: [%2] numFilesSentFail: [%3]").arg(numFilesSentTotal).arg(numFilesSentSuccess).arg(numFilesSentFail)); + + /* set the last sent statistics */ + numFilesSentSuccess += numFilesLastSend; + numBytesSentSuccess += numBytesLastSend; + numFilesLastSend = 0; + numBytesLastSend = 0; + ui->lblUploadFilesSentSuccess->setText(QString("%1").arg(numFilesSentSuccess)); + //emit complete(response); + numNetConn--; + WriteLog(QString("numNetConn (B): %1").arg(numNetConn)); + + QBrush colorGreen(Qt::green); + for (int i=0;itableFiles->item(ii,1)->setForeground(colorGreen); + ui->tableFiles->item(ii,1)->setText("Upload success"); + } + + WriteLog(QString("(Z2) numFilesSentTotal: [%1] numFilesSentSuccess: [%2] numFilesSentFail: [%3]").arg(numFilesSentTotal).arg(numFilesSentSuccess).arg(numFilesSentFail)); + + WriteLog("Leaving onGetReplyUpload()"); +} + + +/* ------------------------------------------------- */ +/* --------- onNetworkError ------------------------ */ +/* ------------------------------------------------- */ +void MainWindow::onNetworkError(QNetworkReply::NetworkError networkError) +{ + WriteLog("Entering onNetworkError()"); + + QNetworkReply* reply = qobject_cast(sender()); + WriteLog("Error [" + reply->errorString() + "]"); + + /* if this function is called, the last queued network request should be finished */ + isUploading = false; + numNetConn--; + + WriteLog(QString("(E) numFilesSentTotal: [%1] numFilesSentSuccess: [%2] numFilesSentFail: [%3]").arg(numFilesSentTotal).arg(numFilesSentSuccess).arg(numFilesSentFail)); + + /* update the upload stats and reset the counts for the last upload */ + numBytesSentFail += numBytesLastSend; + numFilesSentFail += numFilesLastSend; + numFilesLastSend = 0; + numBytesLastSend = 0; + //qDebug() << err.errorString(); + + QBrush colorRed(Qt::red); + for (int i=0;itableFiles->item(ii,1)->setForeground(colorRed); + ui->tableFiles->item(ii,1)->setText("Upload fail"); + } + + WriteLog(QString("(F) numFilesSentTotal: [%1] numFilesSentSuccess: [%2] numFilesSentFail: [%3]").arg(numFilesSentTotal).arg(numFilesSentSuccess).arg(numFilesSentFail)); + + ui->lblUploadFilesSentFail->setText(QString("%1").arg(numFilesSentFail)); + + WriteLog("Leaving onNetworkError()"); +} + +/* ------------------------------------------------- */ +/* --------- on_btnSelectDataDir_clicked ----------- */ +/* ------------------------------------------------- */ +void MainWindow::on_btnSelectDataDir_clicked() +{ + QString dir = QFileDialog::getExistingDirectory(this, tr("Open Directory"), "", QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); + ui->txtDataDir->setText(dir); +} + + +/* ------------------------------------------------- */ +/* --------- on_btnSearch_clicked ------------------ */ +/* ------------------------------------------------- */ +void MainWindow::on_btnSearch_clicked() +{ + /* disable the upload button */ + ui->btnUploadAll->setEnabled(false); + + QApplication::setOverrideCursor(Qt::WaitCursor); + scanDirIter(QDir(ui->txtDataDir->text())); + QApplication::restoreOverrideCursor(); + + /* enable the upload */ + ui->btnUploadAll->setEnabled(true); +} + + +/* ------------------------------------------------- */ +/* --------- scanDirIter --------------------------- */ +/* ------------------------------------------------- */ +void MainWindow::scanDirIter(QDir dir) +{ + QVariant modality = ui->cmbModality->currentData(); + QString fullfile; + QDirIterator iterator(dir.absolutePath(), QDirIterator::Subdirectories); + QString fileModality; + QString fileType; + QString filePatientID; + + elapsedFileSearchTime.start(); + startFileSearchTime = QDateTime::currentDateTime(); + ui->lblFileStartTime->setText(startFileSearchTime.toString(Qt::TextDate)); + + /* iterate through all files in the parent directory */ + while (iterator.hasNext()) { + iterator.next(); + if (!iterator.fileInfo().isDir()) { + fullfile = iterator.filePath(); + /* check the file type */ + GetFileType(fullfile, fileType, fileModality, filePatientID); + if (fileType == "DICOM") { + if (modality == "DICOM") { + AddFoundFile(&iterator,fullfile,fileType,fileModality, filePatientID); + } + else { + if (modality == fileModality) { + AddFoundFile(&iterator,fullfile,fileType,modality.toString(), filePatientID); + } + } + } + if ((fileType == "PARREC") && (modality == "PARREC")) { + AddFoundFile(&iterator,fullfile,fileType,fileModality, filePatientID); + } + if ((fileType == "EEG") && (modality == "EEG")) { + AddFoundFile(&iterator,fullfile,fileType,fileModality, filePatientID); + } + if ((fileType == "NIFTI") && (modality == "NIFTI")) { + AddFoundFile(&iterator,fullfile,fileType,fileModality, filePatientID); + } + } + } +} + + +/* ------------------------------------------------- */ +/* --------- GetFileType --------------------------- */ +/* ------------------------------------------------- */ +void MainWindow::GetFileType(QString f, QString &fileType, QString &fileModality, QString &filePatientID) +{ + fileModality = QString(""); + //qDebug("%s",f.toStdString().c_str()); + gdcm::Reader r; + r.SetFileName(f.toStdString().c_str()); + if (r.Read()) { + //qDebug("%s is a DICOM file",f.toStdString().c_str()); + fileType = QString("DICOM"); + gdcm::StringFilter sf; + sf = gdcm::StringFilter(); + sf.SetFile(r.GetFile()); + std::string s; + + /* get modality */ + s = sf.ToString(gdcm::Tag(0x0008,0x0060)); + fileModality = QString(s.c_str()); + + /* get patientID */ + s = sf.ToString(gdcm::Tag(0x0010,0x0020)); + filePatientID = QString(s.c_str()); + } + else { + /* check if EEG, and Polhemus */ + if ((f.toLower().endsWith(".cnt")) || (f.toLower().endsWith(".dat")) || (f.toLower().endsWith(".3dd"))) { + fileType = "EEG"; + fileModality = "EEG"; + QFileInfo fn = QFileInfo(f); + QStringList parts = fn.baseName().split("_"); + filePatientID = parts[0]; + } + /* check if MR (Non-DICOM) analyze or nifti */ + else if ((f.toLower().endsWith(".nii")) || (f.toLower().endsWith(".nii.gz")) || (f.toLower().endsWith(".hdr")) || (f.toLower().endsWith(".img"))) { + //WriteLog("Found an analyze or Nifti image"); + fileType = "NIFTI"; + fileModality = "NIFTI"; + QFileInfo fn = QFileInfo(f); + QStringList parts = fn.baseName().split("_"); + filePatientID = parts[0]; + } + /* check if par/rec */ + else if (f.endsWith(".par")) { + fileType = "PARREC"; + fileModality = "PARREC"; + + QFile inputFile(f); + if (inputFile.open(QIODevice::ReadOnly)) + { + QTextStream in(&inputFile); + while ( !in.atEnd() ) + { + QString line = in.readLine(); + if (line.contains("Patient name")) { + QStringList parts = line.split(":",QString::SkipEmptyParts); + filePatientID = parts[1].trimmed(); + } + if (line.contains("MRSERIES")) { + fileModality = "MR"; + } + } + inputFile.close(); + } + } + else { + fileType = "Unknown"; + } + } +} + + +/* ------------------------------------------------- */ +/* --------- GetDicomModality ---------------------- */ +/* ------------------------------------------------- */ +QString MainWindow::GetDicomModality(QString f) +{ + gdcm::Reader r; + r.SetFileName(f.toStdString().c_str()); + if (!r.CanRead()) { + return "NONDICOM"; + } + gdcm::StringFilter sf; + sf = gdcm::StringFilter(); + sf.SetFile(r.GetFile()); + std::string s = sf.ToString(gdcm::Tag(0x0008,0x0060)); + + QString qs = s.c_str(); + + return qs; +} + + +/* ------------------------------------------------- */ +/* --------- AddFoundFile -------------------------- */ +/* ------------------------------------------------- */ +bool MainWindow::AddFoundFile(QDirIterator *it, QString f, QString fType, QString modality, QString filePatientID) +{ + qint64 size = 0; + QString sSize, cDate; + QFileInfo info; + + /* add this file to the main list */ + files << f; + + /* check if its a .par/.rec so the real size can calculated */ + if (fType == "PARREC") { + QString recfile = it->filePath(); + //QString parfile = it->filePath(); + + //WriteLog(QString(".par file path: [%1]").arg(parfile)); + + recfile.replace(".par",".rec"); + WriteLog(QString(".rec file path: [%1]").arg(recfile)); + + QFile rec(recfile); + //QFile par(parfile); + qint64 recsize = rec.size(); + //qint64 parsize = par.size(); + size += recsize; + + //WriteLog(QString("Old filesize: [%1], New filesize [%2]").arg(s2, s1)); + } + info = it->fileInfo(); + size += info.size(); + cDate = info.created().toString(); + sSize = humanReadableSize(size); + + const int currentRow = ui->tableFiles->rowCount(); + ui->tableFiles->setRowCount(currentRow + 1); + + ui->tableFiles->setItem(currentRow, 0, new QTableWidgetItem(f)); + ui->tableFiles->setItem(currentRow, 1, new QTableWidgetItem("Readable")); + ui->tableFiles->setItem(currentRow, 2, new QTableWidgetItem(fType)); + ui->tableFiles->setItem(currentRow, 3, new QTableWidgetItem(modality)); + ui->tableFiles->setItem(currentRow, 4, new QTableWidgetItem(filePatientID)); + ui->tableFiles->setItem(currentRow, 5, new QTableWidgetItem(cDate)); + ui->tableFiles->setItem(currentRow, 6, new QTableWidgetItem(sSize)); + ui->tableFiles->setItem(currentRow, 7, new QTableWidgetItem(QString("%1").arg(size))); + + numFilesFound++; + numBytesFound += size; + + ui->lblFileCount->setText(QString("Found %1 files").arg(ui->tableFiles->rowCount())); + + ui->lblFileBytesFound->setText(humanReadableSize(numBytesFound)); + ui->lblNumFilesFound->setText(QString("%1").arg(numFilesFound)); + + ui->lblFileElapsedTime->setText(QString("%1").arg(timeConversion(elapsedFileSearchTime.elapsed()))); + + /* check to see if the filename is in the correct format */ + if (ui->cmbModality->currentData() == "EEG") { + QString filebasename = QFileInfo(f).baseName(); + QStringList parts = filebasename.split("_"); + + WriteLog(QString("FileBaseName: %1 Number of parts: %2").arg(filebasename, parts.count())); + + if ((parts.count() != 5) && (parts.count() != 6)) { + /* color the line red */ + QBrush colorRed(Qt::red); + ui->tableFiles->item(ui->tableFiles->rowCount()-1,0)->setForeground(colorRed); + ui->tableFiles->item(ui->tableFiles->rowCount()-1,1)->setText("Invalid filename"); + ui->tableFiles->item(ui->tableFiles->rowCount()-1,1)->setToolTip("Filename should be in the format S1234ABC_YYYYMMDDHHMISS_task_operator_series_filenum.ext"); + } + } + + ui->tableFiles->scrollToBottom(); + qApp->processEvents(); + + return true; +} + + +/* ------------------------------------------------- */ +/* --------- on_btnTmpDir_clicked ------------------ */ +/* ------------------------------------------------- */ +void MainWindow::on_btnTmpDir_clicked() +{ + QString dir = QFileDialog::getExistingDirectory(this, tr("Open Directory"), "", QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); + ui->txtTmpDir->setText(dir); +} + + +/* ------------------------------------------------- */ +/* --------- on_btnUploadAll_clicked --------------- */ +/* ------------------------------------------------- */ +void MainWindow::on_btnUploadAll_clicked() +{ + networkManager->setProxy(GetProxy()); + + WriteLog("Entering on_btnUploadAll_clicked()"); + if (ui->lstConn->selectedItems().length() < 1) { + ShowMessageBox("No connection selected"); + return; + } + + /* check the fields before attempting to upload */ + if (ui->cmbInstanceID->currentData() == "") { + ShowMessageBox("Instance ID is blank"); + ui->cmbInstanceID->setFocus(); + return; + } + if (ui->cmbProjectID->currentData() == "") { + ShowMessageBox("Project ID is blank"); + ui->cmbProjectID->setFocus(); + return; + } + if (ui->cmbSiteID->currentData() == "") { + ShowMessageBox("Site ID is blank"); + ui->cmbSiteID->setFocus(); + return; + } + /* check if there is a temp dir specified (if needed) */ + if ((ui->chkRemovePatientBirthDate->isChecked() || ui->chkReplacePatientBirthDate->isChecked() || ui->chkReplacePatientID->isChecked() || ui->chkReplacePatientName->isChecked()) && (ui->txtTmpDir->text() == "")) { + ShowMessageBox("Temp dir is blank"); + ui->txtTmpDir->setFocus(); + return; + } + + ui->lblStatus->setText("Starting upload transaction"); + elapsedUploadTime.start(); + startUploadTime = QDateTime::currentDateTime(); + ui->lblUploadStart->setText(startUploadTime.toString(Qt::TextDate)); + + QApplication::setOverrideCursor(Qt::WaitCursor); + QString modality = ui->cmbModality->currentData().toString(); + bool isDICOM = false; + bool isPARREC = false; + bool isNIFTI = false; + + /* if its a DICOM file, create a tmp directory to anonymize it */ + if ((modality == "DICOM") || (modality == "MR") || (modality == "CT") || (modality == "PET") || (modality == "SPECT") || (modality == "US")) { + isDICOM = true; + } + if (modality == "PARREC") { + isPARREC = true; + } + if (modality == "NIFTI") { + isNIFTI = true; + } + + QVector fileList; + + /* start a transaction */ + StartTransaction(); + + /* wait for a valid transaction number */ + while (transactionNumber <= 0) { + QTest::qWait(100); + } + + /* this will anonymize and then upload all of the files in the list */ + int rowCount = ui->tableFiles->rowCount(); + int currentUploadSize = 0; + ui->progTotal->setRange(0,rowCount); + for (int i=0; itableFiles->item(i,7)->text().toInt(); + + //int numUploadsPerPOST; + //if (modality == "EEG") { + // numUploadsPerPOST = 5; + //} + //else { + // numUploadsPerPOST = 100; + //} + ui->lblStatus->setText("Preparing file"); + + int compareSize; + if ((i+1) < rowCount) { + compareSize = currentUploadSize + ui->tableFiles->item(i+1,7)->text().toInt(); + } + else { + compareSize = currentUploadSize; + } + if ((compareSize > 500000000) || (fileList.size() >= 100)) { + //if (fileList.length() >= numUploadsPerPOST) { + //qDebug() << fileList.length(); + AnonymizeAndUpload(fileList, isDICOM, isPARREC); + /* clear the list */ + fileList.clear(); + currentUploadSize = 0; + } + + ui->progTotal->setValue(i+1); + qApp->processEvents(); + } + /* anonymize and upload the remaining files */ + AnonymizeAndUpload(fileList, isDICOM, isPARREC); + + /* end the transaction */ + EndTransaction(); + ui->lblStatus->setText("Ending upload transaction"); + + QApplication::restoreOverrideCursor(); + WriteLog("Leaving on_btnUploadAll_clicked()"); +} + + +/* ------------------------------------------------- */ +/* --------- AnonymizeAndUpload -------------------- */ +/* ------------------------------------------------- */ +void MainWindow::AnonymizeAndUpload(QVector list, bool isDICOM, bool isPARREC) +{ + lastUploadList = list; + + WriteLog("Entering AnonymizeAndUpload()"); + QStringList uploadList; + QString tmpDir = ""; + + /* if its a DICOM or PARREC file, create a tmp directory to anonymize it */ + if (isDICOM || isPARREC) { + /* create a temp directory */ + tmpDir = ui->txtTmpDir->text() + "/" + GenerateRandomString(15); + QDir dir; + dir.mkpath(tmpDir); + WriteLog(QString("Creating tmpDir [%1]").arg(tmpDir.toStdString().c_str())); + } + + //ui->txtLog->append(QString("Anonymizing %1 files...").arg(list.size())); + WriteLog(QString("in AnonymizeAndUpload: got list of size %1").arg(list.size())); + + /* loop through the list of table row numbers, and try to anonymize (if DICOM) and then upload the file */ + ui->progAnon->setRange(0,list.size()); + for (int i=0; i< list.size(); i++) { + int ii = list[i]; + QString f = ui->tableFiles->item(ii,0)->text(); + QString newFilePath; + QString newPathPar; + QString newPathRec; + + /* update the elapsed time */ + ui->lblUploadElapsed->setText(QString("%1").arg(timeConversion(elapsedUploadTime.elapsed()))); + + ui->lblStatus->setText("Anonymizing"); + + if (isDICOM) { + /* copy file to temp dir */ + newFilePath = tmpDir + "/" + GenerateRandomString(15) + ".dcm"; + QFile::copy(f,newFilePath); + //qDebug("Copying [%s] to [%s]", f.toStdString().c_str(), newFilePath.toStdString().c_str()); + /* add this filepath to the list of files to be uploaded */ + uploadList << newFilePath; + } + else if (isPARREC) { + /* copy file to temp dir */ + newFilePath = tmpDir + "/" + GenerateRandomString(15); + newPathPar = newFilePath + ".par"; + newPathRec = newFilePath + ".rec"; + QString f2 = f; + f2.replace(".par",".rec"); + //qDebug("f [%s] , f2 [%s]", f.toStdString().c_str(), f2.toStdString().c_str()); + //qDebug("newPathPar [%s] , newPathRec [%s]", newPathPar.toStdString().c_str(), newPathRec.toStdString().c_str()); + + QFile::copy(f,newPathPar); + //qDebug("Copying [%s] to [%s]", f.toStdString().c_str(), newPathPar.toStdString().c_str()); + QFile::copy(f2,newPathRec); + //qDebug("Copying [%s] to [%s]", f2.toStdString().c_str(), newPathRec.toStdString().c_str()); + + /* add these filepaths to the list of files to be uploaded */ + uploadList << newPathPar; + uploadList << newPathRec; + } + else { + newFilePath = f; + /* add this filepath to the list of files to be uploaded */ + uploadList << newFilePath; + } + + ui->tableFiles->setCurrentCell(ii,0); + //qDebug("Inside AnonymizeAndUpload loop [%d]",ii); + + if (isDICOM) { + gdcm::Reader r; + gdcm::File file; + gdcm::StringFilter sf; + gdcm::DataSet ds; + r.SetFileName(newFilePath.toStdString().c_str()); + r.Read(); + sf = gdcm::StringFilter(); + sf.SetFile(r.GetFile()); + file = r.GetFile(); + ds = file.GetDataSet(); + + sf = gdcm::StringFilter(); + sf.SetFile(r.GetFile()); + std::vector empty_tags; + std::vector remove_tags; + std::vector< std::pair > replace_tags_value; + + /* check if the patient name should be replaced */ + if (ui->chkReplacePatientName->isChecked()) { + std::string s = sf.ToString(gdcm::Tag(0x0010,0x0010)); + QString tagVal = s.c_str(); + tagVal = tagVal.trimmed(); + tagVal = tagVal.toLower(); + + QByteArray hash = QCryptographicHash::hash(tagVal.toUtf8(), QCryptographicHash::Sha1); + QString newTagVal = hash.toHex().toUpper(); + WriteLog(QString("Replacing DICOM PatientName [%1] with [%2]").arg(tagVal.toStdString().c_str()).arg(newTagVal.toStdString().c_str())); + + gdcm::Tag tag; + tag.ReadFromCommaSeparatedString("0010,0010"); + replace_tags_value.push_back( std::make_pair(tag, newTagVal.toStdString().c_str()) ); + } + + /* check if the patient ID should be replaced */ + if (ui->chkReplacePatientID->isChecked()) { + std::string s = sf.ToString(gdcm::Tag(0x0010,0x0020)); + QString tagVal = s.c_str(); + QString tagValOrig = tagVal; + tagVal = tagVal.trimmed(); + tagVal = tagVal.toLower(); + + QByteArray hash = QCryptographicHash::hash(tagVal.toUtf8(), QCryptographicHash::Sha1); + QString newTagVal = hash.toHex().toUpper(); + + WriteLog(QString("Replacing DICOM PatientID [%1] with [%2]").arg(tagVal.toStdString().c_str()).arg(newTagVal.toStdString().c_str())); + //qDebug("Replacing %s with %s",tagVal.toStdString().c_str(),newTagVal.toStdString().c_str()); + + gdcm::Tag tag; + tag.ReadFromCommaSeparatedString("0010,0020"); + replace_tags_value.push_back( std::make_pair(tag, newTagVal.toStdString().c_str()) ); + + QTextStream out(&idfile); + out << "Orig ID: [" << tagValOrig << "] New ID: [" << newTagVal << "]" << endl; + } + + /* check if the patient birthdate should be replaced */ + if (ui->chkReplacePatientBirthDate->isChecked()) { + std::string s = sf.ToString(gdcm::Tag(0x0010,0x0030)); + QString tagVal = s.c_str(); + tagVal = tagVal.trimmed(); + int year; + if (tagVal.length() == 8) { + year = tagVal.left(4).toInt(); + } + else if (tagVal.contains(":")) { + QStringList parts = tagVal.split(":"); + year = parts[0].toInt(); + } + else if (tagVal.contains("-")) { + QStringList parts = tagVal.split("-"); + year = parts[0].toInt(); + } + else { + QDate dob; + dob.fromString(tagVal); + year = dob.year(); + } + + QString newTagVal = QString::number(year) + "-00-00"; + + //qDebug("Replacing [%s] with [%s]",tagVal.toStdString().c_str(),newTagVal.toStdString().c_str()); + WriteLog(QString("Replacing DICOM PatientBirthDate [%1] with [%2]").arg(tagVal.toStdString().c_str()).arg(newTagVal.toStdString().c_str())); + + gdcm::Tag tag; + tag.ReadFromCommaSeparatedString("0010,0030"); + replace_tags_value.push_back( std::make_pair(tag, newTagVal.toStdString().c_str()) ); + } + + /* check if the patient birthdate should be removed */ + if (ui->chkRemovePatientBirthDate->isChecked()) { + QString newTagVal = "0000-00-00"; + + //qDebug("Removed birthdate"); + + gdcm::Tag tag; + tag.ReadFromCommaSeparatedString("0010,0030"); + replace_tags_value.push_back( std::make_pair(tag, newTagVal.toStdString().c_str()) ); + } + + ui->tableFiles->setCurrentCell(ii,0); + //ui->tableFiles->scrollTo(i); + gdcm::Anonymizer anon; + if (AnonymizeOneFileDumb(anon,newFilePath.toStdString().c_str(),newFilePath.toStdString().c_str(),empty_tags,remove_tags,replace_tags_value,false)) { + ui->tableFiles->setItem(ii,1,new QTableWidgetItem("Anonymized")); + } + else { + ui->tableFiles->setItem(ii,1,new QTableWidgetItem("Error anonymizing")); + } + } + if (isPARREC) { + /* get the Patient Name */ + //QByteArray fileData; + //QString text; + //QString newPatientID, oldPatientID; + //QFile inputFile(newPathPar); + //WriteLog(QString("Attempting to anonymize [%1]").arg(inputFile.fileName())); + //if (inputFile.open(QIODevice::ReadOnly | QIODevice::Text)) + //{ + //fileData = inputFile.readAll(); // read all the data into the byte array + //text = fileData; // add to text string for easy string replace + + // WriteLog("About to parse through the lines"); + //WriteLog(QString("file contents [%1]").arg(fileData)); + // QTextStream in(&inputFile); + //QString fileData = in.readAll(); + //WriteLog(QString("File contents [%1]").arg(fileData)); + // while ( !in.atEnd() ) + // { + //WriteLog("Hi"); + // QString line = in.readLine(); + //WriteLog(QString("Checking line [%1] for 'Patient name'").arg(line)); + // if (line.contains("Patient name")) { + //WriteLog(QString("The matching 'Patient name' line [%1]").arg(line)); + // QStringList parts = line.split(":",QString::SkipEmptyParts); + // oldPatientID = parts[1].trimmed(); + // oldPatientID = oldPatientID.toLower(); + // break; + // } + // } + // inputFile.close(); + //} + //else { + // WriteLog(QString("Could not open [%1]").arg(inputFile.fileName())); + //} + + /* encrypt the patient name */ + //QByteArray hash = QCryptographicHash::hash(oldPatientID.toUtf8(), QCryptographicHash::Sha1); + //newPatientID = hash.toHex().toUpper(); + + /* replace the patient name */ + //QByteArray fileData; + //QFile f(newPathPar); + //f.open(QFile::ReadWrite | QFile::Text); // open for read and write + //QTextStream in(&f); + //QString text = in.readAll(); // read all the data into the byte array + //QString text(fileData); // add to text string for easy string replace + //qDebug("Replacing [%s] with [%s] in file [%s]", oldPatientID.toStdString().c_str(), newPatientID.toStdString().c_str(), newPathPar.toStdString().c_str()); + //WriteLog(QString("Replacing PARREC PatientID [%1] with [%2]").arg(oldPatientID.toStdString().c_str()).arg(newPatientID.toStdString().c_str())); + + //QTextStream out(&idfile); + //out << "Orig ID: [" << oldPatientID << "] New ID: [" << newPatientID << "]" << endl; + + //WriteLog(QString("File BEFORE replacing [%1]").arg(text)); + //text.replace(oldPatientID, newPatientID,Qt::CaseInsensitive); // replace text in string + //WriteLog(QString("File AFTER replacing [%1]").arg(text)); + + /* write the whole string out to a file again */ + //f.seek(0); // go to the beginning of the file + //f.write(text.toUtf8()); // write the new text back to the file + //f.close(); // close the file handle. + + /* rename the file */ + } + ui->progAnon->setValue(i+1); + qApp->processEvents(); + } + + /* go through the list of files to be uploaded, and upload them as one big batch */ + totalUploaded += UploadFileList(uploadList); + + /* wait for everything to finish before deleting the directory */ + //while (numNetConn > 0) { + while (isUploading) { + QTest::qWait(1000); + } + + /* delete the temp directory */ + if (tmpDir != "") { + QDir dir(tmpDir); + WriteLog("Attempting to remove tmpDir [" + tmpDir + "]"); + if (!dir.removeRecursively()) { + WriteLog("Unable to remove [" + tmpDir + "] ... the drive will fill up with junk soon"); + } + else { + WriteLog("Successfully deleted [" + tmpDir + "]"); + } + } + + WriteLog("Leaving AnonymizeAndUpload()"); +} + + +/* ------------------------------------------------- */ +/* --------- AnonymizeOneFileDumb ------------------ */ +/* ------------------------------------------------- */ +/* borrowed from gdcmanon.cxx */ +bool MainWindow::AnonymizeOneFileDumb(gdcm::Anonymizer &anon, const char *filename, const char *outfilename, std::vector const &empty_tags, std::vector const &remove_tags, std::vector< std::pair > const & replace_tags, bool continuemode) +{ + + //qDebug("Anonymizing one file [%s]", filename); + + gdcm::Reader reader; + reader.SetFileName( filename ); + if( !reader.Read() ) { + numAnonErrors++; + ui->lblNumAnonErrors->setText(QString("%1").arg(numAnonErrors)); + std::cerr << "Could not read : " << filename << std::endl; + if( continuemode ) { + std::cerr << "Skipping from anonymization process (continue mode)." << std::endl; + return true; + } + else + { + std::cerr << "Check [--continue] option for skipping files." << std::endl; + return false; + } + } + gdcm::File &file = reader.GetFile(); + + anon.SetFile( file ); + + if( empty_tags.empty() && replace_tags.empty() && remove_tags.empty() ) { + std::cerr << "No operation to be done." << std::endl; + return false; + } + + std::vector::const_iterator it = empty_tags.begin(); + bool success = true; + for(; it != empty_tags.end(); ++it) { + success = success && anon.Empty( *it ); + } + it = remove_tags.begin(); + for(; it != remove_tags.end(); ++it) { + success = success && anon.Remove( *it ); + } + + std::vector< std::pair >::const_iterator it2 = replace_tags.begin(); + for(; it2 != replace_tags.end(); ++it2) { + success = success && anon.Replace( it2->first, it2->second.c_str() ); + } + + gdcm::Writer writer; + writer.SetFileName( outfilename ); + writer.SetFile( file ); + if( !writer.Write() ) { + numAnonErrors++; + ui->lblNumAnonErrors->setText(QString("%1").arg(numAnonErrors)); + std::cerr << "Could not Write : " << outfilename << std::endl; + if( strcmp(filename,outfilename) != 0 ) { + gdcm::System::RemoveFile( outfilename ); + } + else + { + std::cerr << "gdcmanon just corrupted: " << filename << " for you (data lost)." << std::endl; + } + return false; + } + return success; +} + + +/* ------------------------------------------------- */ +/* --------- GetConnectionParms -------------------- */ +/* ------------------------------------------------- */ +bool MainWindow::GetConnectionParms(QString &s, QString &u, QString &p) +{ + QStringList connItems; + QString connStr; + + /* check if any connections exist */ + if (ui->lstConn->count() < 1) { + ui->lblConnMessage->setText("No connections setup"); + return false; + } + /* check if any connections are selected */ + connStr = ui->lstConn->currentItem()->text(); + if (connStr.trimmed() == "") { + ui->lblConnMessage->setText("No connection selected"); + return false; + } + + connStr = ui->lstConn->currentItem()->text(); + connItems << connStr.split(","); + s = connItems[0]; + u = connItems[1]; + p = connItems[2]; + + return true; +} + + +/* ------------------------------------------------- */ +/* --------- UploadFileList ------------------------ */ +/* ------------------------------------------------- */ +int MainWindow::UploadFileList(QStringList list) +{ + WriteLog("Entering UploadFileList()"); + //ui->txtLog->append(QString("Uploading %1 files...").arg(list.size())); + QString modality = ui->cmbModality->currentData().toString(); + + if (!GetConnectionParms(connServer, connUsername, connPassword)) { + return 0; + } + + numFilesSentTotal += list.count(); + /* set the last sent statistics */ + numFilesLastSend = list.count(); + numBytesLastSend = list.count(); + + QUrl url(connServer + "/api.php"); + QNetworkRequest request(url); + + QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType); + + QHttpPart loginPart; + /* username */ + loginPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"u\"")); + loginPart.setBody(connUsername.toLatin1()); + multiPart->append(loginPart); + /* password */ + loginPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"p\"")); + loginPart.setBody(connPassword.toLatin1()); + multiPart->append(loginPart); + /* action */ + loginPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"action\"")); + if (modality == "PARREC") { loginPart.setBody("UploadNonDICOM"); } + else if (modality == "EEG") { loginPart.setBody("UploadNonDICOM"); } + else { loginPart.setBody("UploadDICOM"); } + multiPart->append(loginPart); + /* instanceid */ + loginPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"instanceid\"")); + loginPart.setBody(ui->cmbInstanceID->currentData().toString().toLatin1()); + multiPart->append(loginPart); + /* projectid */ + loginPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"projectid\"")); + loginPart.setBody(ui->cmbProjectID->currentData().toString().toLatin1()); + multiPart->append(loginPart); + /* siteid */ + loginPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"siteid\"")); + loginPart.setBody(ui->cmbSiteID->currentData().toString().toLatin1()); + multiPart->append(loginPart); + /* equipment */ + loginPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"equipmentid\"")); + loginPart.setBody(ui->cmbEquipmentID->currentData().toString().toLatin1()); + multiPart->append(loginPart); + /* transaction number */ + loginPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"transactionid\"")); + loginPart.setBody(QString::number(transactionNumber).toLatin1()); + multiPart->append(loginPart); + WriteLog("TransactionID: " + QString::number(transactionNumber).toLatin1()); + /* matchIDOnly */ + loginPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"matchidonly\"")); + if (ui->chkMatchIDOnly->isChecked()) + loginPart.setBody("1"); + else + loginPart.setBody("0"); + multiPart->append(loginPart); + /* dataformat */ + loginPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"dataformat\"")); + if (modality == "DICOM") { loginPart.setBody("dicom"); } + else if (modality == "PARREC") { loginPart.setBody("parrec"); } + else if (modality == "EEG") { loginPart.setBody("eeg"); } + else if (modality == "NIFTI") { loginPart.setBody("nifti"); } + else { loginPart.setBody(""); } + multiPart->append(loginPart); + + /* loop through the list of files */ + ui->progUpload->setRange(0,100); + for (int i=0;ifileName() + "\"")); + + file->open(QIODevice::ReadOnly); + filePart.setBodyDevice(file); + file->setParent(multiPart); // we cannot delete the file now, so delete it with the multiPart + multiPart->append(filePart); + } + + while (isUploading) { + //qDebug("Waiting for current transfers to stop. numNetConn: [%d]", numNetConn); + //QTest::qWait(1000); + //#ifdef _WIN32_ + // _sleep(1); + //#elif __linux + // sleep(1); + //#endif + ui->lblStatus->setText("Waiting for response from server"); + QTest::qWait(1000); + } + + //networkManager = new QNetworkAccessManager(this); + QNetworkReply* reply = networkManager->post(request, multiPart); + multiPart->setParent(reply); // delete the multiPart with the reply + numNetConn++; + isUploading = true; + connect(reply, SIGNAL(finished()), this, SLOT(onGetReplyUpload())); + connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onNetworkError(QNetworkReply::NetworkError))); + connect(reply, SIGNAL(uploadProgress(qint64, qint64)), SLOT(progressChanged(qint64, qint64))); + + WriteLog(QString("Finished queueing %1 files for upload...").arg(list.size())); + //ui->txtLog->append(QString("Finished queueing %1 files for upload...").arg(list.size())); + + /* update the elapsed time */ + ui->lblUploadElapsed->setText(QString("%1").arg(timeConversion(elapsedUploadTime.elapsed()))); + + uploadTime.start(); + WriteLog("Leaving UploadFileList()"); + return list.size(); +} + + +/* ------------------------------------------------- */ +/* --------- progressChanged ----------------------- */ +/* ------------------------------------------------- */ +void MainWindow::progressChanged(qint64 a, qint64 b) +{ + if (b > 0) { + //qDebug() << "Uploading " << a << "/" << b << "%" << (double)a/(double)b*100.0; + ui->progUpload->setValue(((double)a/(double)b)*100.0); + qApp->processEvents(); + } + // calculate the download speed + double speed = a * 1000.0 / uploadTime.elapsed(); + QString unit; + if (speed < 1024) { + unit = "bytes/sec"; + } else if (speed < 1024*1024) { + speed /= 1024; + unit = "kB/s"; + } else { + speed /= 1024*1024; + unit = "MB/s"; + } + ui->lblUploadSpeed->setText(QString::fromLatin1("%1 %2").arg(speed, 3, 'f', 1).arg(unit)); + /* update the elapsed time */ + ui->lblUploadElapsed->setText(QString("%1").arg(timeConversion(elapsedUploadTime.elapsed()))); + + ui->lblStatus->setText("Uploading..."); +} + + +/* ------------------------------------------------- */ +/* --------- GenerateRandomString ------------------ */ +/* ------------------------------------------------- */ +QString MainWindow::GenerateRandomString(int len) +{ + const QString possibleCharacters("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); + + QString randomString; + for(int i=0; ichkRemovePatientBirthDate->isChecked() || ui->chkReplacePatientBirthDate->isChecked() || ui->chkReplacePatientID->isChecked() || ui->chkReplacePatientName->isChecked()) { + ui->txtTmpDir->setEnabled(true); + //#ifdef W_OS_WIN32 + ui->txtTmpDir->setText("C:/temp"); + //#endif + //#ifdef W_OS_LINUX + // ui->txtTmpDir->setText("/tmp"); + //#endif + } + else { + ui->txtTmpDir->setDisabled(true); + } +} + + +void MainWindow::on_chkReplacePatientName_clicked() { SetTempDir(); } +void MainWindow::on_chkReplacePatientID_clicked() { SetTempDir(); } +void MainWindow::on_chkReplacePatientBirthDate_clicked() { SetTempDir(); } +void MainWindow::on_chkRemovePatientBirthDate_clicked() { SetTempDir(); } + + +/* ------------------------------------------------- */ +/* --------- on_lstConn_clicked -------------------- */ +/* ------------------------------------------------- */ +void MainWindow::on_lstConn_clicked(const QModelIndex &index) +{ + index; + ui->lblConnMessage->setText(""); +} + + +/* ------------------------------------------------- */ +/* --------- on_btnRemoveConn_clicked -------------- */ +/* ------------------------------------------------- */ +void MainWindow::on_btnRemoveConn_clicked() +{ + qDeleteAll(ui->lstConn->selectedItems()); +} + + +/* ------------------------------------------------- */ +/* --------- on_btnLoadInstanceIDs_clicked --------- */ +/* ------------------------------------------------- */ +void MainWindow::on_btnLoadInstanceIDs_clicked() +{ + networkManager->setProxy(GetProxy()); + /* get list of instances through the API */ + + if (ui->lstConn->count() < 1) { + ShowMessageBox("No connections available"); + } + else if (ui->lstConn->selectedItems().length() < 1) { + ShowMessageBox("No connection selected"); + } + else { + QApplication::setOverrideCursor(Qt::WaitCursor); + if (GetConnectionParms(connServer, connUsername, connPassword)) { + QUrl url(connServer + "/api.php"); + QNetworkRequest request(url); + QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType); + QHttpPart loginPart; + /* username */ + loginPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"u\"")); + loginPart.setBody(connUsername.toLatin1()); multiPart->append(loginPart); + /* password */ + loginPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"p\"")); + loginPart.setBody(connPassword.toLatin1()); multiPart->append(loginPart); + /* action */ + loginPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"action\"")); + loginPart.setBody("getInstanceList"); multiPart->append(loginPart); + + //networkManager = new QNetworkAccessManager(this); + QNetworkReply* reply = networkManager->post(request, multiPart); + multiPart->setParent(reply); // delete the multiPart with the reply + connect(reply, SIGNAL(finished()), this, SLOT(onGetReplyInstanceList())); + QApplication::restoreOverrideCursor(); + } + } +} + + +/* ------------------------------------------------- */ +/* --------- on_btnLoadProjectIDs_clicked ---------- */ +/* ------------------------------------------------- */ +void MainWindow::on_btnLoadProjectIDs_clicked() +{ + networkManager->setProxy(GetProxy()); + /* get list of instances through the API */ + if (ui->lstConn->count() < 1) { + ShowMessageBox("No connections available"); + } + else if (ui->lstConn->selectedItems().length() < 1) { + ShowMessageBox("No connection selected"); + } + else { + QApplication::setOverrideCursor(Qt::WaitCursor); + if (GetConnectionParms(connServer, connUsername, connPassword)) { + QUrl url(connServer + "/api.php"); + QNetworkRequest request(url); + QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType); + QHttpPart loginPart; + /* username */ + loginPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"u\"")); + loginPart.setBody(connUsername.toLatin1()); multiPart->append(loginPart); + /* password */ + loginPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"p\"")); + loginPart.setBody(connPassword.toLatin1()); multiPart->append(loginPart); + /* action */ + loginPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"action\"")); + loginPart.setBody("getProjectList"); multiPart->append(loginPart); + /* instance */ + loginPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"instance\"")); + loginPart.setBody(ui->cmbInstanceID->currentData().toString().toLatin1()); multiPart->append(loginPart); + + //networkManager = new QNetworkAccessManager(this); + QNetworkReply* reply = networkManager->post(request, multiPart); + multiPart->setParent(reply); // delete the multiPart with the reply + connect(reply, SIGNAL(finished()), this, SLOT(onGetReplyProjectList())); + QApplication::restoreOverrideCursor(); + } + } +} + + +/* ------------------------------------------------- */ +/* --------- on_btnLoadSiteIDs_clicked ------------- */ +/* ------------------------------------------------- */ +void MainWindow::on_btnLoadSiteIDs_clicked() +{ + networkManager->setProxy(GetProxy()); + /* get list of instances through the API */ + + if (ui->lstConn->count() < 1) { + ShowMessageBox("No connections available"); + } + else if (ui->lstConn->selectedItems().length() < 1) { + ShowMessageBox("No connection selected"); + } + else { + QApplication::setOverrideCursor(Qt::WaitCursor); + if (GetConnectionParms(connServer, connUsername, connPassword)) { + QUrl url(connServer + "/api.php"); + QNetworkRequest request(url); + QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType); + QHttpPart loginPart; + /* username */ + loginPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"u\"")); + loginPart.setBody(connUsername.toLatin1()); multiPart->append(loginPart); + /* password */ + loginPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"p\"")); + loginPart.setBody(connPassword.toLatin1()); multiPart->append(loginPart); + /* action */ + loginPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"action\"")); + loginPart.setBody("getSiteList"); multiPart->append(loginPart); + /* instance */ + loginPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"instance\"")); + loginPart.setBody(ui->cmbInstanceID->currentData().toString().toLatin1()); multiPart->append(loginPart); + + //networkManager = new QNetworkAccessManager(this); + QNetworkReply* reply = networkManager->post(request, multiPart); + multiPart->setParent(reply); // delete the multiPart with the reply + connect(reply, SIGNAL(finished()), this, SLOT(onGetReplySiteList())); + QApplication::restoreOverrideCursor(); + } + } +} + + +/* ------------------------------------------------- */ +/* --------- on_btnLoadEquipmentIDs_clicked -------- */ +/* ------------------------------------------------- */ +void MainWindow::on_btnLoadEquipmentIDs_clicked() +{ + networkManager->setProxy(GetProxy()); + /* get list of instances through the API */ + + if (ui->lstConn->count() < 1) { + ShowMessageBox("No connections available"); + } + else if (ui->lstConn->selectedItems().length() < 1) { + ShowMessageBox("No connection selected"); + } + else { + QApplication::setOverrideCursor(Qt::WaitCursor); + if (GetConnectionParms(connServer, connUsername, connPassword)) { + QUrl url(connServer + "/api.php"); + QNetworkRequest request(url); + QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType); + QHttpPart loginPart; + /* username */ + loginPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"u\"")); + loginPart.setBody(connUsername.toLatin1()); multiPart->append(loginPart); + /* password */ + loginPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"p\"")); + loginPart.setBody(connPassword.toLatin1()); multiPart->append(loginPart); + /* action */ + loginPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"action\"")); + loginPart.setBody("getEquipmentList"); multiPart->append(loginPart); + + //networkManager = new QNetworkAccessManager(this); + QNetworkReply* reply = networkManager->post(request, multiPart); + multiPart->setParent(reply); // delete the multiPart with the reply + connect(reply, SIGNAL(finished()), this, SLOT(onGetReplyEquipmentList())); + QApplication::restoreOverrideCursor(); + } + } + +} + + +/* ------------------------------------------------- */ +/* --------- onGetReplyInstanceList ---------------- */ +/* ------------------------------------------------- */ +void MainWindow::onGetReplyInstanceList() +{ + //qDebug() << "numNetConn (A): " << numNetConn; + QNetworkReply* reply = qobject_cast(sender()); + + QString response; + if (reply) { + if (reply->error() == QNetworkReply::NoError) { + const int available = reply->bytesAvailable(); + if (available > 0) { + const QByteArray buffer(reply->readAll()); + response = QString::fromUtf8(buffer); + } + } else { + response = tr("Error: %1 status: %2").arg(reply->errorString(), reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toString()); + } + reply->deleteLater(); + } + + if (response.trimmed().isEmpty()) { response = tr("No instances available"); } + //ui->txtLog->append(response + "\n"); + + QStringList listItems; + ui->cmbInstanceID->clear(); + listItems << response.split(","); + + for (int i=0; i 1) { + ui->cmbInstanceID->addItem(QString(parts[0] + " - " + parts[1]), parts[0]); + } + else { + ui->cmbInstanceID->addItem(parts[0], parts[0]); + } + } +} + + +/* ------------------------------------------------- */ +/* --------- onGetReplyProjectList ----------------- */ +/* ------------------------------------------------- */ +void MainWindow::onGetReplyProjectList() +{ + //qDebug() << "numNetConn (A): " << numNetConn; + QNetworkReply* reply = qobject_cast(sender()); + + QString response; + if (reply) { + if (reply->error() == QNetworkReply::NoError) { + const int available = reply->bytesAvailable(); + if (available > 0) { + const QByteArray buffer(reply->readAll()); + response = QString::fromUtf8(buffer); + } + } else { + response = tr("Error: %1 status: %2").arg(reply->errorString(), reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toString()); + } + reply->deleteLater(); + } + + if (response.trimmed().isEmpty()) { response = tr("No projects within this instance"); } + //ui->txtLog->append(response + "\n"); + + /* parse the returned string and populate the drop down menu */ + QStringList listItems; + ui->cmbProjectID->clear(); + listItems << response.split(","); + + for (int i=0; i 1) { + ui->cmbProjectID->addItem(QString(parts[0] + " - " + parts[1]), parts[0]); + } + else { + ui->cmbProjectID->addItem(parts[0], parts[0]); + } + } +} + + +/* ------------------------------------------------- */ +/* --------- onGetReplySiteList -------------------- */ +/* ------------------------------------------------- */ +void MainWindow::onGetReplySiteList() +{ + //qDebug() << "numNetConn (A): " << numNetConn; + QNetworkReply* reply = qobject_cast(sender()); + + QString response; + if (reply) { + if (reply->error() == QNetworkReply::NoError) { + const int available = reply->bytesAvailable(); + if (available > 0) { + const QByteArray buffer(reply->readAll()); + response = QString::fromUtf8(buffer); + } + } else { + response = tr("Error: %1 status: %2").arg(reply->errorString(), reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toString()); + } + reply->deleteLater(); + } + + if (response.trimmed().isEmpty()) { response = tr("No sites available"); } + //ui->txtLog->append(response + "\n"); + + /* parse the returned string and populate the drop down menu */ + QStringList listItems; + ui->cmbSiteID->clear(); + listItems << response.split(","); + + for (int i=0; i 1) { + ui->cmbSiteID->addItem(QString(parts[0] + " - " + parts[1]), parts[0]); + } + else { + ui->cmbSiteID->addItem(parts[0], parts[0]); + } + } +} + + +/* ------------------------------------------------- */ +/* --------- onGetReplyEquipmentList --------------- */ +/* ------------------------------------------------- */ +void MainWindow::onGetReplyEquipmentList() +{ + //qDebug() << "numNetConn (A): " << numNetConn; + QNetworkReply* reply = qobject_cast(sender()); + + QString response; + if (reply) { + if (reply->error() == QNetworkReply::NoError) { + const int available = reply->bytesAvailable(); + if (available > 0) { + const QByteArray buffer(reply->readAll()); + response = QString::fromUtf8(buffer); + } + } else { + response = tr("Error: %1 status: %2").arg(reply->errorString(), reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toString()); + } + reply->deleteLater(); + } + + if (response.trimmed().isEmpty()) { response = tr("No equipment available"); } + WriteLog(response); + + /* parse the returned string and populate the drop down menu */ + QStringList listItems; + ui->cmbEquipmentID->clear(); + listItems << response.split(","); + + for (int i=0; i 1) { + ui->cmbEquipmentID->addItem(QString(parts[0] + " - " + parts[1]), parts[0]); + } + else { + ui->cmbEquipmentID->addItem(parts[0], parts[0]); + } + } +} + + +/* ------------------------------------------------- */ +/* --------- StartTransaction ---------------------- */ +/* ------------------------------------------------- */ +void MainWindow::StartTransaction() +{ + WriteLog("Entering StartTransaction()"); + networkManager->setProxy(GetProxy()); + /* get list of instances through the API */ + + transactionNumber = 0; + + if (ui->lstConn->count() < 1) { + ShowMessageBox("No connections available"); + } + else if (ui->lstConn->selectedItems().length() < 1) { + ShowMessageBox("No connection selected"); + } + else { + QApplication::setOverrideCursor(Qt::WaitCursor); + if (GetConnectionParms(connServer, connUsername, connPassword)) { + QUrl url(connServer + "/api.php"); + QNetworkRequest request(url); + QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType); + QHttpPart loginPart; + /* username */ + loginPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"u\"")); + loginPart.setBody(connUsername.toLatin1()); multiPart->append(loginPart); + /* password */ + loginPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"p\"")); + loginPart.setBody(connPassword.toLatin1()); multiPart->append(loginPart); + /* action */ + loginPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"action\"")); + loginPart.setBody("startTransaction"); multiPart->append(loginPart); + + //networkManager = new QNetworkAccessManager(this); + QNetworkReply* reply = networkManager->post(request, multiPart); + multiPart->setParent(reply); // delete the multiPart with the reply + connect(reply, SIGNAL(finished()), this, SLOT(onGetReplyStartTransaction())); + QApplication::restoreOverrideCursor(); + } + } + WriteLog("Leaving StartTransaction()"); +} + + +/* ------------------------------------------------- */ +/* --------- onGetReplyStartTransaction ------------ */ +/* ------------------------------------------------- */ +void MainWindow::onGetReplyStartTransaction() +{ + //qDebug() << "numNetConn (A): " << numNetConn; + QNetworkReply* reply = qobject_cast(sender()); + + QString response; + if (reply) { + if (reply->error() == QNetworkReply::NoError) { + const int available = reply->bytesAvailable(); + if (available > 0) { + const QByteArray buffer(reply->readAll()); + response = QString::fromUtf8(buffer); + } + } else { + response = tr("Error: %1 status: %2").arg(reply->errorString(), reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toString()); + } + reply->deleteLater(); + } + + if (response.trimmed().isEmpty()) { response = tr("Did not get a transaction number"); } + else { + transactionNumber = response.trimmed().toInt(); + } + if (transactionNumber < 0) { + WriteLog("transaction number was negative"); + } + WriteLog("The following is the response from the starttransaction thing"); + WriteLog(response); +} + + +/* ------------------------------------------------- */ +/* --------- EndTransaction ------------------------ */ +/* ------------------------------------------------- */ +void MainWindow::EndTransaction() +{ + networkManager->setProxy(GetProxy()); + /* get list of instances through the API */ + + if (ui->lstConn->count() < 1) { + ShowMessageBox("No connections available"); + } + else if (ui->lstConn->selectedItems().length() < 1) { + ShowMessageBox("No connection selected"); + } + else { + QApplication::setOverrideCursor(Qt::WaitCursor); + if (GetConnectionParms(connServer, connUsername, connPassword)) { + QUrl url(connServer + "/api.php"); + QNetworkRequest request(url); + QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType); + QHttpPart loginPart; + /* username */ + loginPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"u\"")); + loginPart.setBody(connUsername.toLatin1()); multiPart->append(loginPart); + /* password */ + loginPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"p\"")); + loginPart.setBody(connPassword.toLatin1()); multiPart->append(loginPart); + /* action */ + loginPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"action\"")); + loginPart.setBody("endTransaction"); multiPart->append(loginPart); + /* transaction number */ + loginPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"transactionid\"")); + loginPart.setBody(QString::number(transactionNumber).toLatin1()); multiPart->append(loginPart); + + //networkManager = new QNetworkAccessManager(this); + QNetworkReply* reply = networkManager->post(request, multiPart); + multiPart->setParent(reply); // delete the multiPart with the reply + connect(reply, SIGNAL(finished()), this, SLOT(onGetReplyEndTransaction())); + QApplication::restoreOverrideCursor(); + } + } +} + + +/* ------------------------------------------------- */ +/* --------- onGetReplyEndTransaction ------------ */ +/* ------------------------------------------------- */ +void MainWindow::onGetReplyEndTransaction() +{ + //qDebug() << "numNetConn (A): " << numNetConn; + QNetworkReply* reply = qobject_cast(sender()); + + QString response; + if (reply) { + if (reply->error() == QNetworkReply::NoError) { + const int available = reply->bytesAvailable(); + if (available > 0) { + const QByteArray buffer(reply->readAll()); + response = QString::fromUtf8(buffer); + } + } else { + response = tr("Error: %1 status: %2").arg(reply->errorString(), reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toString()); + } + reply->deleteLater(); + } + + if (response.trimmed().isEmpty()) { response = tr("No equipment available"); } + WriteLog(response); + +} + + +/* ------------------------------------------------- */ +/* --------- on_cmbInstanceID_currentIndexChanged -- */ +/* ------------------------------------------------- */ +void MainWindow::on_cmbInstanceID_currentIndexChanged(int index) +{ + index; + on_btnLoadProjectIDs_clicked(); +} + + +/* ------------------------------------------------- */ +/* --------- ShowMessageBox ------------------------ */ +/* ------------------------------------------------- */ +void MainWindow::ShowMessageBox(QString msg) { + QMessageBox msgBox; + msgBox.setText(msg); + msgBox.exec(); +} + + +/* ------------------------------------------------- */ +/* --------- timeConversion ------------------------ */ +/* ------------------------------------------------- */ +QString MainWindow::timeConversion(int msecs) +{ + QString formattedTime; + + int hours = msecs/(1000*60*60); + int minutes = (msecs-(hours*1000*60*60))/(1000*60); + int seconds = (msecs-(minutes*1000*60)-(hours*1000*60*60))/1000; + int milliseconds = msecs-(seconds*1000)-(minutes*1000*60)-(hours*1000*60*60); + + formattedTime.append(QString("%1").arg(hours, 2, 10, QLatin1Char('0')) + ":" + + QString( "%1" ).arg(minutes, 2, 10, QLatin1Char('0')) + ":" + + QString( "%1" ).arg(seconds, 2, 10, QLatin1Char('0')) + ":" + + QString( "%1" ).arg(milliseconds, 3, 10, QLatin1Char('0'))); + + return formattedTime; +} + + +/* ------------------------------------------------- */ +/* --------- humanReadableSize --------------------- */ +/* ------------------------------------------------- */ +QString MainWindow::humanReadableSize(quint64 intSize) +{ + QString unit; + double size; + if (intSize < 1024 * 1024) { + size = 1. + intSize / 1024.; + unit = QObject::tr("kB"); + } else if (intSize < 1024 * 1024 * 1024) { + size = 1. + intSize / 1024. / 1024.; + unit = QObject::tr("MB"); + } else { + size = 1. + intSize / 1024. / 1024. / 1024.; + unit = QObject::tr("GB"); + } + size = qRound(size * 10) / 10.0; + return QString::fromLatin1("%L1 %2").arg(size, 0, 'g', 4).arg(unit); +} + + +/* ------------------------------------------------- */ +/* --------- on_btnRemoveSelected_clicked ---------- */ +/* ------------------------------------------------- */ +void MainWindow::on_btnRemoveSelected_clicked() +{ + + QSet selectedRows; //we use a set to prevent doubles + QList itemList = ui->tableFiles->selectedItems(); + QTableWidgetItem * item; + foreach(item, itemList) + selectedRows.insert(item->row()); + + /* get a list, and sort it big to small */ + QList rows = selectedRows.toList(); + qSort(rows.begin(), rows.end(), qGreater()); + + /* now actually do the removing */ + foreach(int row, rows) + ui->tableFiles->removeRow(row); +} + + + +void MainWindow::on_chkUseProxy_clicked() +{ + //SetProxy(); +} + + +/* ------------------------------------------------- */ +/* --------- GetProxy ------------------------------ */ +/* ------------------------------------------------- */ +QNetworkProxy MainWindow::GetProxy() +{ + QNetworkProxy proxy; + if (ui->chkUseProxy->isChecked()) { + QVariant proxyType = ui->cmbProxyType->currentData(); + + if (proxyType == "") { proxy.setType(QNetworkProxy::NoProxy); } + if (proxyType == "default") { proxy.setType(QNetworkProxy::DefaultProxy); } + if (proxyType == "socks5") { proxy.setType(QNetworkProxy::Socks5Proxy); } + if (proxyType == "http") { proxy.setType(QNetworkProxy::HttpProxy); } + if (proxyType == "httpcaching") { proxy.setType(QNetworkProxy::HttpCachingProxy); } + if (proxyType == "ftpcaching") { proxy.setType(QNetworkProxy::FtpCachingProxy); } + + proxy.setHostName(ui->proxyHostname->text()); + proxy.setPort(ui->proxyPort->value()); + proxy.setUser(ui->proxyUsername->text()); + proxy.setPassword(ui->proxyPassword->text()); + //WriteLog("About to set the proxy"); + //QNetworkProxy::setApplicationProxy(proxy); + //WriteLog("Proxy should be set"); + } + else { + // QNetworkProxy proxy; + proxy.setType(QNetworkProxy::NoProxy); + //WriteLog("About to unset the proxy"); + //QNetworkProxy::setApplicationProxy(proxy); + //WriteLog("Proxy should be unset"); + } + return proxy; +} + + +/* ------------------------------------------------- */ +/* --------- WriteLog ------------------------------ */ +/* ------------------------------------------------- */ +void MainWindow::WriteLog(QString msg) +{ + /* print to file and to the log window */ + QTextStream out(&logfile); + out << "[" << QTime::currentTime().toString() << "] " << msg << endl; + qDebug() << msg; +} diff --git a/mainwindow.h b/mainwindow.h new file mode 100644 index 0000000..8774d65 --- /dev/null +++ b/mainwindow.h @@ -0,0 +1,173 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "gdcmReader.h" +#include "gdcmWriter.h" +#include "gdcmAttribute.h" +#include "gdcmStringFilter.h" +#include "gdcmAnonymizer.h" +#include +#include +#include +#include + +#ifdef _WIN32_ + #include +#elif __linux + #include +#endif + +/* this supposedly will make the program run on WinXP */ +//#include +//Q_IMPORT_PLUGIN (QWindowsIntegrationPlugin) + +namespace Ui { +class MainWindow; +} + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(QWidget *parent = 0); + ~MainWindow(); + void SetBuildDate(); + void PopulateModality(); + + void PopulateConnectionList(); + void scanDirIter(QDir dir); + void GetFileType(QString f, QString &fileType, QString &fileModality, QString &filePatientID); + bool GetConnectionParms(QString &s, QString &u, QString &p); + QString GetDicomModality(QString f); + bool AddFoundFile(QDirIterator *it, QString f, QString fType, QString modality, QString filePatientID); + QString GenerateRandomString(int len); + void AnonymizeAndUpload(QVector list, bool isDICOM, bool isPARREC); + bool AnonymizeOneFileDumb(gdcm::Anonymizer &anon, const char *filename, const char *outfilename, std::vector const &empty_tags, std::vector const &remove_tags, std::vector< std::pair > const & replace_tags, bool continuemode = false); + int UploadFileList(QStringList list); + void SetTempDir(); + void ShowMessageBox(QString msg); + QString timeConversion(int msecs); + QString humanReadableSize(quint64 intSize); + + void StartTransaction(); + void EndTransaction(); + + QNetworkProxy GetProxy(); + void WriteLog(QString msg); + + QNetworkAccessManager *networkManager; + + QVector lastUploadList; + + QString connServer; + QString connUsername; + QString connPassword; + + QStringList files; + + int totalUploaded; + + int numNetConn; + bool isUploading; + + QDateTime startFileSearchTime; + QTime elapsedFileSearchTime; + int numFilesFound; + qint64 numBytesFound; + + QDateTime startUploadTime; + QTime uploadTime; + QTime elapsedUploadTime; + int numAnonErrors; + qint64 numBytesSentSuccess; + qint64 numBytesSentFail; + qint64 numBytesSentTotal; + qint64 numFilesSentSuccess; + qint64 numFilesSentFail; + qint64 numFilesSentTotal; + int numBytesLastSend; /* number of bytes sent in last upload attempt */ + int numFilesLastSend; /* number of files sent in last upload attempt */ + + int transactionNumber; /* the transaction number to use during the current upload */ + + QFile logfile; /* the logfile */ + QFile idfile; /* the file containing IDs */ + +private slots: + void progressChanged(qint64 a, qint64 b); + + //void uploadError(QNetworkReply::NetworkError err); + + void on_btnExit_clicked(); + + void on_pushButton_clicked(); + + void on_btnTestConn_clicked(); + + void onGetReply(); + void onGetReplyUpload(); + void onNetworkError(QNetworkReply::NetworkError networkError); + + void onGetReplyInstanceList(); + void onGetReplyProjectList(); + void onGetReplySiteList(); + void onGetReplyEquipmentList(); + void onGetReplyStartTransaction(); + void onGetReplyEndTransaction(); + + void on_btnSelectDataDir_clicked(); + + void on_btnSearch_clicked(); + + void on_btnTmpDir_clicked(); + + void on_btnUploadAll_clicked(); + + void on_chkReplacePatientName_clicked(); + + void on_chkReplacePatientID_clicked(); + + void on_chkReplacePatientBirthDate_clicked(); + + void on_chkRemovePatientBirthDate_clicked(); + + void on_lstConn_clicked(const QModelIndex &index); + + void on_btnRemoveConn_clicked(); + + void on_btnLoadInstanceIDs_clicked(); + + void on_btnLoadProjectIDs_clicked(); + + void on_btnLoadSiteIDs_clicked(); + + void on_cmbInstanceID_currentIndexChanged(int index); + + void on_btnRemoveSelected_clicked(); + + void on_btnLoadEquipmentIDs_clicked(); + + void on_chkUseProxy_clicked(); + +private: + Ui::MainWindow *ui; +}; + +#endif // MAINWINDOW_H diff --git a/mainwindow.ui b/mainwindow.ui new file mode 100644 index 0000000..9980aa8 --- /dev/null +++ b/mainwindow.ui @@ -0,0 +1,1970 @@ + + + MainWindow + + + + 0 + 0 + 865 + 848 + + + + NiDB Uploader + + + + C:/projects/NiDBUploader/squirrel1.pngC:/projects/NiDBUploader/squirrel1.png + + + + + 0 + 0 + + + + + 6 + + + 9 + + + + + + 75 + true + + + + Data Selection + + + + 1 + + + 1 + + + 1 + + + 1 + + + + + + + + 50 + false + + + + Modality + + + + + + + + 0 + 0 + + + + + 50 + false + + + + + + + + + 50 + false + + + + Data Directory: + + + + + + + + 50 + false + + + + select a data directory + + + + + + + + 0 + 0 + + + + + 23 + 16777215 + + + + + 50 + false + + + + Click to select directory + + + ... + + + true + + + + + + + + 50 + false + + + + Search for files matching the specified modality + + + Search + + + true + + + false + + + + + + + + + + + + + + 255 + 0 + 0 + + + + + + + + + 255 + 0 + 0 + + + + + + + + + 120 + 120 + 120 + + + + + + + + + 50 + false + + + + Make sure the UIDs specified below actually exist on the server! + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + 0 + + + + + + + + + + 0 + 0 + 127 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + + + 0 + 0 + 127 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + + + 120 + 120 + 120 + + + + + + + 120 + 120 + 120 + + + + + + + 120 + 120 + 120 + + + + + + + + + 50 + false + + + + Found 0 files + + + + + + + true + + + QAbstractItemView::SelectRows + + + true + + + Qt::DotLine + + + true + + + false + + + 8 + + + 120 + + + 19 + + + + File + + + + 75 + true + + + + + + Status + + + + + Type + + + + + Modality + + + + + ID + + + + + File Date + + + + + File Size + + + + + Bytes + + + + + + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 100 + 16777215 + + + + + 50 + false + + + + Remove Selected + + + + + + + + + + + + + + 0 + + + + + 0 + + + 0 + + + 0 + + + + + + 75 + true + false + + + + NiDB Server Connection + + + + 6 + + + 1 + + + 1 + + + 1 + + + 1 + + + + + 1 + + + QLayout::SetDefaultConstraint + + + 0 + + + 0 + + + + + + + + 50 + false + + + + Connection List + + + + + + + + 0 + 0 + + + + + 50 + false + + + + Remove + + + + + + + + 0 + 0 + + + + + 100 + 16777215 + + + + + 50 + false + + + + Test Connection + + + true + + + + + + + + + + 0 + 0 + + + + + 0 + 40 + + + + + 1000 + 70 + + + + + 50 + false + + + + + + + + + 0 + 0 + + + + + + + + + 255 + 0 + 0 + + + + + + + + + 255 + 0 + 0 + + + + + + + + + 120 + 120 + 120 + + + + + + + + + 50 + false + + + + QFrame::NoFrame + + + ConnectionMessage: + + + + + + + + + 1 + + + QLayout::SetDefaultConstraint + + + + + 6 + + + QLayout::SetDefaultConstraint + + + 0 + + + + + + 0 + 0 + + + + + 50 + false + + + + Server + + + + + + + + 50 + false + + + + http:// + + + true + + + + + + + + + 1 + + + 0 + + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + + 50 + false + + + + Username + + + + + + + + 50 + false + + + + + + + + + + + + + 0 + 0 + + + + + 50 + false + + + + Password + + + + + + + + 50 + false + + + + QLineEdit::Password + + + + + + + + + + 0 + 0 + + + + + 50 + false + + + + <-- Add + + + true + + + + + + + + + 1 + + + 0 + + + + + + 50 + false + + + + Hostname + + + + + + + + 50 + false + + + + + + + + + 50 + false + + + + Port + + + + + + + + 50 + false + + + + 999999 + + + 8080 + + + + + + + + 50 + false + + + + Username + + + + + + + + 50 + false + + + + + + + + + 50 + false + + + + Password + + + + + + + + 50 + false + + + + Qt::ImhNoPredictiveText|Qt::ImhSensitiveData + + + + + + + + 50 + false + + + + Use proxy + + + + + + + + 50 + false + + + + + + + + + + + + + 0 + + + 0 + + + 9 + + + + + + 0 + 0 + + + + + 75 + true + + + + false + + + Anonymization (DICOM only) + + + false + + + false + + + + 0 + + + QLayout::SetMinimumSize + + + 1 + + + 1 + + + 1 + + + 1 + + + + + + 50 + false + + + + For DICOM only. Replaces PatientName with SHA1(PatientName) + + + Replace PatientName (0010,0010) + + + true + + + + + + + + 50 + false + + + + For DICOM only. Replaces PatientID with SHA1(PatientID) + + + Replace PatientID (0010,0020) + + + false + + + + + + + + 50 + false + + + + For DICOM only. Replaces PatientBirthDate with year only + + + Replace PatientBirthDate (0010,0030) + + + false + + + + + + + + 50 + false + + + + Remove PatientBirthDate + + + + + + + 6 + + + + + + 16777215 + 20 + + + + + 50 + false + + + + Temp directory + + + + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + + 50 + false + + + + + + + + + 0 + 0 + + + + + 23 + 16777215 + + + + + 50 + false + + + + ... + + + + + + + + + + 16777215 + 16777215 + + + + + + + + + 102 + 102 + 102 + + + + + + + 0 + 0 + 0 + + + + + + + + + 102 + 102 + 102 + + + + + + + 0 + 0 + 0 + + + + + + + + + 120 + 120 + 120 + + + + + + + 120 + 120 + 120 + + + + + + + + + 50 + false + + + + Use "C:temp" on Windows, "/tmp" on Linux + + + + + + + + + + + 75 + true + + + + Destination + + + + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + + + 0 + + + + + + 50 + false + + + + Match by ID only + + + true + + + + + + + + + + + + 50 + false + + + + Instance + + + + + + + + 0 + 0 + + + + + 50 + false + + + + + + + + + 23 + 16777215 + + + + + 50 + false + + + + Load instance list + + + ... + + + false + + + + + + + + + + + + 50 + false + + + + Project + + + + + + + + 0 + 0 + + + + + 50 + false + + + + + + + + + 23 + 16777215 + + + + + 50 + false + + + + Load project list + + + ... + + + + + + + + + + + + 50 + false + + + + Site + + + + + + + + 0 + 0 + + + + + 50 + false + + + + + + + + + 23 + 16777215 + + + + + 50 + false + + + + Load site list + + + ... + + + + + + + + + 0 + + + + + + 50 + false + + + + Equipment + + + + + + + + 0 + 0 + + + + + 50 + false + + + + + + + + + 23 + 16777215 + + + + + 50 + false + + + + ... + + + + + + + + + Qt::Vertical + + + QSizePolicy::MinimumExpanding + + + + 20 + 2 + + + + + + + + + + + + + + + 1 + + + 0 + + + + + + 16777215 + 15 + + + + 0 + + + Qt::AlignCenter + + + Total %p% + + + + + + + + 16777215 + 15 + + + + Anonymization + + + 0 + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + Anonymization %p% + + + + + + + + 16777215 + 15 + + + + 0 + + + Qt::AlignCenter + + + Upload %p% + + + + + + + QFormLayout::AllNonFixedFieldsGrow + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 3 + + + + + Number files found + + + + + + + 0 + + + + + + + + 75 + true + + + + File search start time + + + + + + + 00:00:00 + + + + + + + + 75 + true + + + + File search elapsed time + + + + + + + HH:MM:SS.ms + + + 00:00:00 + + + + + + + + 75 + true + + + + File search bytes found + + + + + + + 0 + + + + + + + Anonymization errors + + + + + + + + + + + + 170 + 0 + 0 + + + + + + + + + 170 + 0 + 0 + + + + + + + + + 120 + 120 + 120 + + + + + + + + 0 + + + + + + + Upload start time + + + + + + + 00:00:00 + + + + + + + Upload elapsed time + + + + + + + HH:MM:SS.ms + + + 00:00:00 + + + + + + + Upload files sent (success) + + + + + + + 0 + + + + + + + Upload files sent (fail) + + + + + + + + + + + + 170 + 0 + 0 + + + + + + + + + 170 + 0 + 0 + + + + + + + + + 120 + 120 + 120 + + + + + + + + 0 + + + + + + + Upload speed + + + + + + + 0 + + + + + + + + + + 0 + 0 + + + + + 11 + + + + Status... + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + + + + + + + Exit + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Cancel + + + + + + + Qt::Horizontal + + + QSizePolicy::Preferred + + + + 40 + 20 + + + + + + + + Uploads and anonymizes if necessary + + + Upload + + + true + + + + + + + + + + + 0 + 0 + 865 + 21 + + + + + + + + + diff --git a/mainwindow_2.cpp b/mainwindow_2.cpp new file mode 100644 index 0000000..909ff47 --- /dev/null +++ b/mainwindow_2.cpp @@ -0,0 +1,706 @@ +#include "mainwindow.h" +#include "ui_mainwindow.h" + +MainWindow::MainWindow(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::MainWindow) +{ + ui->setupUi(this); + this->showMaximized(); + qsrand(QTime::currentTime().msec()); + + PopulateModality(); + PopulateConnectionList(); + + #ifdef W_OS_WIN32 + ui->txtTmpDir->setText("C:/temp"); + #elifdef W_OS_LINUX + ui->txtTmpDir->setText("/tmp"); + #endif + +} + +MainWindow::~MainWindow() +{ + delete ui; +} + + +/* ------------------------------------------------- */ +/* --------- PopulateModality ---------------------- */ +/* ------------------------------------------------- */ +void MainWindow::PopulateModality() { + ui->cmbModality->addItem("All DICOM", "DICOM"); + ui->cmbModality->addItem("MR","MR"); + ui->cmbModality->addItem("CT","CT"); + ui->cmbModality->addItem("PET","PET"); + ui->cmbModality->addItem("SPECT","SPECT"); + ui->cmbModality->addItem("EEG (.cnt)", "EEG"); + ui->cmbModality->addItem("Eye Tracking", "ET"); + ui->cmbModality->addItem("VIDEO (.wmv .avi .mpg .mpeg .mp4 .mkv)", "VIDEO"); +} + + +/* ------------------------------------------------- */ +/* --------- PopulateConnectionList ---------------- */ +/* ------------------------------------------------- */ +void MainWindow::PopulateConnectionList(){ + ui->lstConn->clear(); + QFile file("connections.txt"); + file.open(QIODevice::ReadOnly | QIODevice::Text); + QTextStream in(&file); + QList< QStringList > lists; + QString line; + do { + line = in.readLine(); + lists << line.split("\t"); + } while (!line.isNull()); + + QString connName; + for ( int row = 0; row < lists.size(); ++row ) { + if (lists[row].size() > 2) { + connName = lists[row][0] + ',' + lists[row][1] + ',' + lists[row][2]; + ui->lstConn->addItem(connName); + } + } +} + + +/* ------------------------------------------------- */ +/* --------- on_btnExit_clicked -------------------- */ +/* ------------------------------------------------- */ +void MainWindow::on_btnExit_clicked() +{ + exit(0); +} + + +/* ------------------------------------------------- */ +/* --------- on_pushButton_clicked ----------------- */ +/* ------------------------------------------------- */ +void MainWindow::on_pushButton_clicked() +{ + QString server = ui->txtServer->text(); + QString username = ui->txtUsername->text(); + QString password = ui->txtPassword->text(); + + QFile file("connections.txt"); + file.open(QIODevice::Append | QIODevice::Text); + QTextStream out(&file); + out << server << "\t" << username << "\t" << password << endl; + file.close(); + + PopulateConnectionList(); + +} + + +/* ------------------------------------------------- */ +/* --------- on_btnTestConn_clicked ---------------- */ +/* ------------------------------------------------- */ +void MainWindow::on_btnTestConn_clicked() +{ + QStringList connItems; + QString connStr; + + if (ui->lstConn->count() < 1) { + return; + } + connStr = ui->lstConn->currentItem()->text(); + connItems << connStr.split(","); + connServer = connItems[0]; + connUsername = connItems[1]; + connPassword = connItems[2]; + + /* set the hourglass cursor */ + QApplication::setOverrideCursor(Qt::WaitCursor); + + QUrl url; + QByteArray postData; + + url.setUrl(connServer + "/api.php"); + QNetworkRequest request(url); + request.setHeader(QNetworkRequest::ContentTypeHeader,"application/x-www-form-urlencoded"); + + postData.append('u').append("=").append(connUsername).append("&"); + postData.append('p').append("=").append(connPassword); + + QNetworkAccessManager *networkManager = new QNetworkAccessManager(this); + //networkManager.post(request,postData); + //connect(networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(serviceRequestFinished(QNetworkReply*))); + QNetworkReply* reply = networkManager->post(request, postData); + bool ok = connect(reply, SIGNAL(finished()), this, SLOT(onGetReply())); + + /* restore the regular cursor */ + QApplication::restoreOverrideCursor(); +} + + +/* ------------------------------------------------- */ +/* --------- onGetReply ---------------------------- */ +/* ------------------------------------------------- */ +void MainWindow::onGetReply() + { + QNetworkReply* reply = qobject_cast(sender()); + + QString response; + if (reply) { + if (reply->error() == QNetworkReply::NoError) { + const int available = reply->bytesAvailable(); + if (available > 0) { + const QByteArray buffer(reply->readAll()); + response = QString::fromUtf8(buffer); + } + } else { + response = tr("Error: %1 status: %2").arg(reply->errorString(), reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toString()); + } + + reply->deleteLater(); + } + + if (response.trimmed().isEmpty()) { + response = tr("Unable to retrieve post response"); + } + + qDebug() << "OnGetReply(" << response << ")"; + //QMessageBox msg; + //msg.setText(response); + //msg.exec(); + //emit complete(response); +} + + +/* ------------------------------------------------- */ +/* --------- on_btnSelectDataDir_clicked ----------- */ +/* ------------------------------------------------- */ +void MainWindow::on_btnSelectDataDir_clicked() +{ + QString dir = QFileDialog::getExistingDirectory(this, tr("Open Directory"), "", QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); + ui->txtDataDir->setText(dir); +} + + +/* ------------------------------------------------- */ +/* --------- on_btnSearch_clicked ------------------ */ +/* ------------------------------------------------- */ +void MainWindow::on_btnSearch_clicked() +{ + QApplication::setOverrideCursor(Qt::WaitCursor); + scanDirIter(QDir(ui->txtDataDir->text())); + QApplication::restoreOverrideCursor(); +} + + +/* ------------------------------------------------- */ +/* --------- scanDirIter --------------------------- */ +/* ------------------------------------------------- */ +void MainWindow::scanDirIter(QDir dir) +{ + QVariant modality = ui->cmbModality->currentData(); + QString fullfile; + QDirIterator iterator(dir.absolutePath(), QDirIterator::Subdirectories); + QString fileModality; + QString fileType; + QString filePatientID; + + //QProgressDialog progress("Scanning for files...", "Cancel", 0, 100, this); + //progress.setWindowModality(Qt::WindowModal); + + //int numFiles = 0; + //bool getFileModality = false; + //if (ui->chkGetModality->isChecked()) { + // getFileModality = true; + //} + + /* iterate through all files */ + while (iterator.hasNext()) { + iterator.next(); + if (!iterator.fileInfo().isDir()) { + //QElapsedTimer timer; + //timer.start(); + //QString filename = iterator.fileName(); + //qDebug() << filename; + fullfile = iterator.filePath(); + //qDebug() << fullfile; + /* check the file type */ + GetFileType(fullfile, fileType, fileModality, filePatientID); + if (fileType == "DICOM") { + //fileModality = ""; + //if (getFileModality) + // fileModality = GetDicomModality(fullfile); + + if (modality == "DICOM") { + AddFoundFile(&iterator,fullfile,fileType,fileModality, filePatientID); + } + else { + //fileModality = GetDicomModality(fullfile); + if (modality == fileModality) { + AddFoundFile(&iterator,fullfile,fileType,modality.toString(), filePatientID); + } + } + } + } + } + //progress.setValue(100); +} + + +/* ------------------------------------------------- */ +/* --------- GetFileType --------------------------- */ +/* ------------------------------------------------- */ +void MainWindow::GetFileType(QString f, QString &fileType, QString &fileModality, QString &filePatientID) +{ + fileModality = QString(""); + //qDebug("%s",f.toStdString().c_str()); + gdcm::Reader r; + r.SetFileName(f.toStdString().c_str()); + if (r.Read()) { + //qDebug("%s is a DICOM file",f.toStdString().c_str()); + fileType = QString("DICOM"); + gdcm::StringFilter sf; + sf = gdcm::StringFilter(); + sf.SetFile(r.GetFile()); + std::string s; + + /* get modality */ + s = sf.ToString(gdcm::Tag(0x0008,0x0060)); + fileModality = QString(s.c_str()); + + /* get patientID */ + s = sf.ToString(gdcm::Tag(0x0010,0x0020)); + filePatientID = QString(s.c_str()); + } + else { + //QFile file(f); + //file.open(QIODevice::ReadOnly); + //qDebug("%s",file.errorString().toStdString().c_str()); + //qDebug("[%s] is not a DICOM file",f.toStdString().c_str()); + if (f.endsWith(".cnt")) { + fileType = "EEG"; + } + else { + fileType = "Unknown"; + } + } +} + + +/* ------------------------------------------------- */ +/* --------- GetDicomModality ---------------------- */ +/* ------------------------------------------------- */ +QString MainWindow::GetDicomModality(QString f) +{ + gdcm::Reader r; + r.SetFileName(f.toStdString().c_str()); + if (!r.CanRead()) { + return "NONDICOM"; + } + gdcm::StringFilter sf; + sf = gdcm::StringFilter(); + sf.SetFile(r.GetFile()); + std::string s = sf.ToString(gdcm::Tag(0x0008,0x0060)); + + QString qs = s.c_str(); + + return qs; +} + + +/* ------------------------------------------------- */ +/* --------- AddFoundFile -------------------------- */ +/* ------------------------------------------------- */ +bool MainWindow::AddFoundFile(QDirIterator *it, QString f, QString fType, QString modality, QString filePatientID) +{ + qint64 size; + QString sSize, cDate; + QFileInfo info; + + files << f; + info = it->fileInfo(); + size = info.size(); + cDate = info.created().toString(); + sSize = QString::number(size/1024) + " kB"; + + const int currentRow = ui->tableFiles->rowCount(); + ui->tableFiles->setRowCount(currentRow + 1); + + ui->tableFiles->setItem(currentRow, 0, new QTableWidgetItem(f)); + ui->tableFiles->setItem(currentRow, 1, new QTableWidgetItem("readable")); + ui->tableFiles->setItem(currentRow, 2, new QTableWidgetItem(fType)); + ui->tableFiles->setItem(currentRow, 3, new QTableWidgetItem(modality)); + ui->tableFiles->setItem(currentRow, 4, new QTableWidgetItem(filePatientID)); + ui->tableFiles->setItem(currentRow, 5, new QTableWidgetItem(cDate)); + ui->tableFiles->setItem(currentRow, 6, new QTableWidgetItem(sSize)); + + ui->lblFileCount->setText(QString("Found %1 files").arg(ui->tableFiles->rowCount())); + ui->tableFiles->scrollToBottom(); + qApp->processEvents(); + + return true; +} + + +/* ------------------------------------------------- */ +/* --------- on_btnTmpDir_clicked ------------------ */ +/* ------------------------------------------------- */ +void MainWindow::on_btnTmpDir_clicked() +{ + QString dir = QFileDialog::getExistingDirectory(this, tr("Open Directory"), "", QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); + ui->txtTmpDir->setText(dir); +} + + +/* ------------------------------------------------- */ +/* --------- on_btnUploadAll_clicked --------------- */ +/* ------------------------------------------------- */ +void MainWindow::on_btnUploadAll_clicked() +{ + QApplication::setOverrideCursor(Qt::WaitCursor); + QString modality = ui->cmbModality->currentData().toString(); + QString tmpDir = ""; + bool isDICOM = false; + + /* if its a DICOM file, create a tmp directory to anonymize it */ + if ((modality == "DICOM") || (modality == "MR") || (modality == "CT") || (modality == "PET") || (modality == "SPECT") || (modality == "US")) { + isDICOM = true; + /* create a temp directory */ + tmpDir = ui->txtTmpDir->text() + "/" + GenerateRandomString(15); + QDir dir; + dir.mkpath(tmpDir); + qDebug("Creating tmpDir [%s]", tmpDir.toStdString().c_str()); + } + + QVector fileList; + + /* this will anonymize and then upload all of the files in the list */ + int rowCount = ui->tableFiles->rowCount(); + for (int i=0; i= 100) { + qDebug() << fileList.length(); + AnonymizeAndUpload(fileList, isDICOM, tmpDir); + /* clear the list */ + fileList.clear(); + } + + qApp->processEvents(); + } + /* anonymize and upload the remaining files */ + AnonymizeAndUpload(fileList, isDICOM, tmpDir); + + /* delete the temp directory */ + if (tmpDir != "") { + QDir dir(tmpDir); + dir.removeRecursively(); + } + + QApplication::restoreOverrideCursor(); +} + + +/* ------------------------------------------------- */ +/* --------- AnonymizeAndUpload -------------------- */ +/* ------------------------------------------------- */ +void MainWindow::AnonymizeAndUpload(QVector list, bool isDICOM, QString tmpDir) +{ + QStringList uploadList; + + qDebug("in AnonymizeAndUpload: got list of size %d", list.size()); + + /* loop through the list of table row numbers, and try to anonymize (if DICOM) and then upload the file */ + for (int i=0; i< list.size(); i++) { + QString f = ui->tableFiles->item(i,0)->text(); + QString newFilePath; + + if (isDICOM) { + /* copy file to temp dir */ + newFilePath = tmpDir + "/" + GenerateRandomString(15) + ".dcm"; + QFile::copy(f,newFilePath); + qDebug("Copying [%s] to [%s]", f.toStdString().c_str(), newFilePath.toStdString().c_str()); + } + else { + newFilePath = f; + } + + /* add this filepath to the list of files to be uploaded */ + uploadList << newFilePath; + + ui->tableFiles->setCurrentCell(i,0); + qDebug("Inside AnonymizeAndUpload loop [%d]",i); + + if (isDICOM) { + gdcm::Reader r; + gdcm::File file; + gdcm::StringFilter sf; + gdcm::DataSet ds; + r.SetFileName(newFilePath.toStdString().c_str()); + r.Read(); + sf = gdcm::StringFilter(); + sf.SetFile(r.GetFile()); + file = r.GetFile(); + ds = file.GetDataSet(); + + sf = gdcm::StringFilter(); + sf.SetFile(r.GetFile()); + std::vector empty_tags; + std::vector remove_tags; + std::vector< std::pair > replace_tags_value; + + /* check if the patient name should be replaced */ + if (ui->chkReplacePatientName->isChecked()) { + std::string s = sf.ToString(gdcm::Tag(0x0010,0x0010)); + QString tagVal = s.c_str(); + tagVal = tagVal.trimmed(); + + QByteArray hash = QCryptographicHash::hash(tagVal.toUtf8(), QCryptographicHash::Sha1); + QString newTagVal = hash.toHex().toUpper(); + //qDebug("Replacing %s with %s",tagVal.toStdString().c_str(),newTagVal.toStdString().c_str()); + + gdcm::Tag tag; + tag.ReadFromCommaSeparatedString("0010,0010"); + replace_tags_value.push_back( std::make_pair(tag, newTagVal.toStdString().c_str()) ); + } + + /* check if the patient ID should be replaced */ + if (ui->chkReplacePatientID->isChecked()) { + std::string s = sf.ToString(gdcm::Tag(0x0010,0x0020)); + QString tagVal = s.c_str(); + tagVal = tagVal.trimmed(); + + QByteArray hash = QCryptographicHash::hash(tagVal.toUtf8(), QCryptographicHash::Sha1); + QString newTagVal = hash.toHex().toUpper(); + + //qDebug("Replacing %s with %s",tagVal.toStdString().c_str(),newTagVal.toStdString().c_str()); + + gdcm::Tag tag; + tag.ReadFromCommaSeparatedString("0010,0020"); + replace_tags_value.push_back( std::make_pair(tag, newTagVal.toStdString().c_str()) ); + } + + /* check if the patient birthdate should be replaced */ + if (ui->chkReplacePatientBirthDate->isChecked()) { + std::string s = sf.ToString(gdcm::Tag(0x0010,0x0030)); + QString tagVal = s.c_str(); + tagVal = tagVal.trimmed(); + int year; + if (tagVal.length() == 8) { + year = tagVal.left(4).toInt(); + } + else if (tagVal.contains(":")) { + QStringList parts = tagVal.split(":"); + year = parts[0].toInt(); + } + else if (tagVal.contains("-")) { + QStringList parts = tagVal.split("-"); + year = parts[0].toInt(); + } + else { + QDate dob; + dob.fromString(tagVal); + year = dob.year(); + } + + QString newTagVal = QString::number(year) + "-00-00"; + + //qDebug("Replacing %s with %s",tagVal.toStdString().c_str(),newTagVal.toStdString().c_str()); + + gdcm::Tag tag; + tag.ReadFromCommaSeparatedString("0010,0030"); + replace_tags_value.push_back( std::make_pair(tag, newTagVal.toStdString().c_str()) ); + } + + /* check if the patient birthdate should be removed */ + if (ui->chkRemovePatientBirthDate->isChecked()) { + //gdcm::Attribute<0x0010,0x0030> tag; + //tag.SetValue("0000-00-00"); + QString newTagVal = "0000-00-00"; + + //qDebug("Removed birthdate"); + + gdcm::Tag tag; + tag.ReadFromCommaSeparatedString("0010,0030"); + replace_tags_value.push_back( std::make_pair(tag, newTagVal.toStdString().c_str()) ); + } + + ui->tableFiles->setCurrentCell(i,0); + //ui->tableFiles->scrollTo(i); + gdcm::Anonymizer anon; + if (AnonymizeOneFileDumb(anon,newFilePath.toStdString().c_str(),newFilePath.toStdString().c_str(),empty_tags,remove_tags,replace_tags_value,false)) { + ui->tableFiles->setItem(i,1,new QTableWidgetItem("Anonymized")); + } + else { + ui->tableFiles->setItem(i,1,new QTableWidgetItem("Anon - Error")); + } + } + } + + /* go through the list of files to be uploaded, and upload them as one big batch */ + UploadFileList(uploadList); +} + + +/* ------------------------------------------------- */ +/* --------- AnonymizeOneFileDumb ------------------ */ +/* ------------------------------------------------- */ +/* borrowed from gdcmanon.cxx */ +bool MainWindow::AnonymizeOneFileDumb(gdcm::Anonymizer &anon, const char *filename, const char *outfilename, std::vector const &empty_tags, std::vector const &remove_tags, std::vector< std::pair > const & replace_tags, bool continuemode) +{ + + qDebug("Anonymizing one file [%s]", filename); + + gdcm::Reader reader; + reader.SetFileName( filename ); + if( !reader.Read() ) { + std::cerr << "Could not read : " << filename << std::endl; + if( continuemode ) { + std::cerr << "Skipping from anonymization process (continue mode)." << std::endl; + return true; + } + else + { + std::cerr << "Check [--continue] option for skipping files." << std::endl; + return false; + } + } + gdcm::File &file = reader.GetFile(); + + anon.SetFile( file ); + + if( empty_tags.empty() && replace_tags.empty() && remove_tags.empty() ) { + std::cerr << "No operation to be done." << std::endl; + return false; + } + + std::vector::const_iterator it = empty_tags.begin(); + bool success = true; + for(; it != empty_tags.end(); ++it) { + success = success && anon.Empty( *it ); + } + it = remove_tags.begin(); + for(; it != remove_tags.end(); ++it) { + success = success && anon.Remove( *it ); + } + + std::vector< std::pair >::const_iterator it2 = replace_tags.begin(); + for(; it2 != replace_tags.end(); ++it2) { + success = success && anon.Replace( it2->first, it2->second.c_str() ); + } + + gdcm::Writer writer; + writer.SetFileName( outfilename ); + writer.SetFile( file ); + if( !writer.Write() ) { + std::cerr << "Could not Write : " << outfilename << std::endl; + if( strcmp(filename,outfilename) != 0 ) { + gdcm::System::RemoveFile( outfilename ); + } + else + { + std::cerr << "gdcmanon just corrupted: " << filename << " for you (data lost)." << std::endl; + } + return false; + } + return success; +} + + +/* ------------------------------------------------- */ +/* --------- UploadFileList ------------------------ */ +/* ------------------------------------------------- */ +QString MainWindow::UploadFileList(QStringList list) +{ + QStringList connItems; + QString connStr; + + if (ui->lstConn->count() < 1) { + return "Nothing to upload"; + } + connStr = ui->lstConn->currentItem()->text(); + connItems << connStr.split(","); + connServer = connItems[0]; + connUsername = connItems[1]; + connPassword = connItems[2]; + + QUrl url(connServer + "/api.php"); + QNetworkRequest request(url); + + QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType); + + QHttpPart loginPart; + /* username */ + loginPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"u\"")); + loginPart.setBody(connUsername.toLatin1()); + multiPart->append(loginPart); + /* password */ + loginPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"p\"")); + loginPart.setBody(connPassword.toLatin1()); + multiPart->append(loginPart); + /* action */ + loginPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"action\"")); + loginPart.setBody("UploadDICOM"); + multiPart->append(loginPart); + + /* loop through the list of files */ + for (int i=0;iappend(previewPathPart); + //continue; + //QString preview_name = "preview.jpg"; + + QFile *file = new QFile(filepath); + QHttpPart filePart; + //filePart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg")); + filePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"files[]\"; filename=\""+ file->fileName() + "\"")); + + if (!file->exists()) { + //emit error(tr("Upload Error. File does not exist: ") + preview_path); + //return; + } + file->open(QIODevice::ReadOnly); + filePart.setBodyDevice(file); + file->setParent(multiPart); // we cannot delete the file now, so delete it with the multiPart + + multiPart->append(filePart); + } + + QNetworkAccessManager *networkManager = new QNetworkAccessManager(this); + QNetworkReply* reply = networkManager->post(request, multiPart); + multiPart->setParent(reply); // delete the multiPart with the reply + connect(reply, SIGNAL(finished()), this, SLOT(onGetReply())); + //connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT (uploadError(QNetworkReply::NetworkError))); + connect(reply, SIGNAL(uploadProgress(qint64, qint64)), this, SLOT (uploadProgress(qint64, qint64))); + + //while (reply->isRunning()) { + //} + return "hi"; +} + + +void MainWindow::uploadProgress(qint64 a, qint64 b) +{ + qDebug() << "Uploading " << a << "/" << b << "%" << (double)a/(double)b*100.0; +} + +/* ------------------------------------------------- */ +/* --------- GenerateRandomString ------------------ */ +/* ------------------------------------------------- */ +QString MainWindow::GenerateRandomString(int len) +{ + const QString possibleCharacters("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); + + QString randomString; + for(int i=0; isetupUi(this); + this->showMaximized(); + qsrand(QTime::currentTime().msec()); + + PopulateModality(); + PopulateConnectionList(); + +} + +MainWindow::~MainWindow() +{ + delete ui; +} + + +/* ------------------------------------------------- */ +/* --------- PopulateModality ---------------------- */ +/* ------------------------------------------------- */ +void MainWindow::PopulateModality() { + ui->cmbModality->addItem("All DICOM", "DICOM"); + ui->cmbModality->addItem("MR","MR"); + ui->cmbModality->addItem("CT","CT"); + ui->cmbModality->addItem("PET","PET"); + ui->cmbModality->addItem("SPECT","SPECT"); + ui->cmbModality->addItem("EEG (.cnt)", "EEG"); + ui->cmbModality->addItem("Eye Tracking", "ET"); + ui->cmbModality->addItem("VIDEO (.wmv .avi .mpg .mpeg .mp4 .mkv)", "VIDEO"); +} + + +/* ------------------------------------------------- */ +/* --------- PopulateConnectionList ---------------- */ +/* ------------------------------------------------- */ +void MainWindow::PopulateConnectionList(){ + ui->lstConn->clear(); + QFile file("connections.txt"); + file.open(QIODevice::ReadOnly | QIODevice::Text); + QTextStream in(&file); + QList< QStringList > lists; + QString line; + do { + line = in.readLine(); + lists << line.split("\t"); + } while (!line.isNull()); + + QString connName; + for ( int row = 0; row < lists.size(); ++row ) { + if (lists[row].size() > 2) { + connName = lists[row][0] + ',' + lists[row][1] + ',' + lists[row][2]; + ui->lstConn->addItem(connName); + } + } +} + + +/* ------------------------------------------------- */ +/* --------- on_btnExit_clicked -------------------- */ +/* ------------------------------------------------- */ +void MainWindow::on_btnExit_clicked() +{ + exit(0); +} + + +/* ------------------------------------------------- */ +/* --------- on_pushButton_clicked ----------------- */ +/* ------------------------------------------------- */ +void MainWindow::on_pushButton_clicked() +{ + QString server = ui->txtServer->text(); + QString username = ui->txtUsername->text(); + QString password = ui->txtPassword->text(); + + QFile file("connections.txt"); + file.open(QIODevice::Append | QIODevice::Text); + QTextStream out(&file); + out << server << "\t" << username << "\t" << password << endl; + file.close(); + + PopulateConnectionList(); + +} + + +/* ------------------------------------------------- */ +/* --------- on_btnTestConn_clicked ---------------- */ +/* ------------------------------------------------- */ +void MainWindow::on_btnTestConn_clicked() +{ + QStringList connItems; + QString connStr; + + if (ui->lstConn->count() < 1) { + return; + } + connStr = ui->lstConn->currentItem()->text(); + connItems << connStr.split(","); + connServer = connItems[0]; + connUsername = connItems[1]; + connPassword = connItems[2]; + + /* set the hourglass cursor */ + QApplication::setOverrideCursor(Qt::WaitCursor); + + QUrl url; + QByteArray postData; + + url.setUrl(connServer + "/api.php"); + QNetworkRequest request(url); + request.setHeader(QNetworkRequest::ContentTypeHeader,"application/x-www-form-urlencoded"); + + postData.append('u').append("=").append(connUsername).append("&"); + postData.append('p').append("=").append(connPassword); + + QNetworkAccessManager *networkManager = new QNetworkAccessManager(this); + //networkManager.post(request,postData); + //connect(networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(serviceRequestFinished(QNetworkReply*))); + QNetworkReply* reply = networkManager->post(request, postData); + bool ok = connect(reply, SIGNAL(finished()), this, SLOT(onGetReply())); + + /* restore the regular cursor */ + QApplication::restoreOverrideCursor(); +} + + +/* ------------------------------------------------- */ +/* --------- onGetReply ---------------------------- */ +/* ------------------------------------------------- */ +void MainWindow::onGetReply() + { + QNetworkReply* reply = qobject_cast(sender()); + + QString response; + if (reply) { + if (reply->error() == QNetworkReply::NoError) { + const int available = reply->bytesAvailable(); + if (available > 0) { + const QByteArray buffer(reply->readAll()); + response = QString::fromUtf8(buffer); + } + } else { + response = tr("Error: %1 status: %2").arg(reply->errorString(), reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toString()); + qDebug() << response; + } + + reply->deleteLater(); + } + + if (response.trimmed().isEmpty()) { + response = tr("Unable to retrieve post response"); + } + + QMessageBox msg; + msg.setText(response); + msg.exec(); + //emit complete(response); +} + + +/* ------------------------------------------------- */ +/* --------- on_btnSelectDataDir_clicked ----------- */ +/* ------------------------------------------------- */ +void MainWindow::on_btnSelectDataDir_clicked() +{ + QString dir = QFileDialog::getExistingDirectory(this, tr("Open Directory"), "", QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); + ui->txtDataDir->setText(dir); +} + + +/* ------------------------------------------------- */ +/* --------- on_btnSearch_clicked ------------------ */ +/* ------------------------------------------------- */ +void MainWindow::on_btnSearch_clicked() +{ + QApplication::setOverrideCursor(Qt::WaitCursor); + scanDirIter(QDir(ui->txtDataDir->text())); + QApplication::restoreOverrideCursor(); +} + + +/* ------------------------------------------------- */ +/* --------- scanDirIter --------------------------- */ +/* ------------------------------------------------- */ +void MainWindow::scanDirIter(QDir dir) +{ + QVariant modality = ui->cmbModality->currentData(); + QString fullfile; + QDirIterator iterator(dir.absolutePath(), QDirIterator::Subdirectories); + QString fileModality; + QString fileType; + QString filePatientID; + + //QProgressDialog progress("Scanning for files...", "Cancel", 0, 100, this); + //progress.setWindowModality(Qt::WindowModal); + + //int numFiles = 0; + //bool getFileModality = false; + //if (ui->chkGetModality->isChecked()) { + // getFileModality = true; + //} + + /* iterate through all files */ + while (iterator.hasNext()) { + iterator.next(); + if (!iterator.fileInfo().isDir()) { + //QElapsedTimer timer; + //timer.start(); + //QString filename = iterator.fileName(); + //qDebug() << filename; + fullfile = iterator.filePath(); + //qDebug() << fullfile; + /* check the file type */ + GetFileType(fullfile, fileType, fileModality, filePatientID); + if (fileType == "DICOM") { + //fileModality = ""; + //if (getFileModality) + // fileModality = GetDicomModality(fullfile); + + if (modality == "DICOM") { + AddFoundFile(&iterator,fullfile,fileType,fileModality, filePatientID); + } + else { + //fileModality = GetDicomModality(fullfile); + if (modality == fileModality) { + AddFoundFile(&iterator,fullfile,fileType,modality.toString(), filePatientID); + } + } + } + } + } + //progress.setValue(100); +} + + +/* ------------------------------------------------- */ +/* --------- GetFileType --------------------------- */ +/* ------------------------------------------------- */ +void MainWindow::GetFileType(QString f, QString &fileType, QString &fileModality, QString &filePatientID) +{ + fileModality = QString(""); + //qDebug("%s",f.toStdString().c_str()); + gdcm::Reader r; + r.SetFileName(f.toStdString().c_str()); + if (r.Read()) { + //qDebug("%s is a DICOM file",f.toStdString().c_str()); + fileType = QString("DICOM"); + gdcm::StringFilter sf; + sf = gdcm::StringFilter(); + sf.SetFile(r.GetFile()); + std::string s; + + /* get modality */ + s = sf.ToString(gdcm::Tag(0x0008,0x0060)); + fileModality = QString(s.c_str()); + + /* get patientID */ + s = sf.ToString(gdcm::Tag(0x0010,0x0020)); + filePatientID = QString(s.c_str()); + } + else { + //QFile file(f); + //file.open(QIODevice::ReadOnly); + //qDebug("%s",file.errorString().toStdString().c_str()); + //qDebug("[%s] is not a DICOM file",f.toStdString().c_str()); + if (f.endsWith(".cnt")) { + fileType = "EEG"; + } + else { + fileType = "Unknown"; + } + } +} + + +/* ------------------------------------------------- */ +/* --------- GetDicomModality ---------------------- */ +/* ------------------------------------------------- */ +QString MainWindow::GetDicomModality(QString f) +{ + gdcm::Reader r; + r.SetFileName(f.toStdString().c_str()); + if (!r.CanRead()) { + return "NONDICOM"; + } + gdcm::StringFilter sf; + sf = gdcm::StringFilter(); + sf.SetFile(r.GetFile()); + std::string s = sf.ToString(gdcm::Tag(0x0008,0x0060)); + + QString qs = s.c_str(); + + return qs; +} + + +/* ------------------------------------------------- */ +/* --------- AddFoundFile -------------------------- */ +/* ------------------------------------------------- */ +bool MainWindow::AddFoundFile(QDirIterator *it, QString f, QString fType, QString modality, QString filePatientID) +{ + qint64 size; + QString sSize, cDate; + QFileInfo info; + + files << f; + info = it->fileInfo(); + size = info.size(); + cDate = info.created().toString(); + sSize = QString::number(size/1024) + " kB"; + + const int currentRow = ui->tableFiles->rowCount(); + ui->tableFiles->setRowCount(currentRow + 1); + + ui->tableFiles->setItem(currentRow, 0, new QTableWidgetItem(f)); + ui->tableFiles->setItem(currentRow, 1, new QTableWidgetItem("readable")); + ui->tableFiles->setItem(currentRow, 2, new QTableWidgetItem(fType)); + ui->tableFiles->setItem(currentRow, 3, new QTableWidgetItem(modality)); + ui->tableFiles->setItem(currentRow, 4, new QTableWidgetItem(filePatientID)); + ui->tableFiles->setItem(currentRow, 5, new QTableWidgetItem(cDate)); + ui->tableFiles->setItem(currentRow, 6, new QTableWidgetItem(sSize)); + + ui->lblFileCount->setText(QString("Found %1 files").arg(ui->tableFiles->rowCount())); + ui->tableFiles->scrollToBottom(); + qApp->processEvents(); + + return true; +} + + +/* ------------------------------------------------- */ +/* --------- on_btnTmpDir_clicked ------------------ */ +/* ------------------------------------------------- */ +void MainWindow::on_btnTmpDir_clicked() +{ + QString dir = QFileDialog::getExistingDirectory(this, tr("Open Directory"), "", QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); + ui->txtTmpDir->setText(dir); +} + + +/* ------------------------------------------------- */ +/* --------- on_btnUploadAll_clicked --------------- */ +/* ------------------------------------------------- */ +void MainWindow::on_btnUploadAll_clicked() +{ + QApplication::setOverrideCursor(Qt::WaitCursor); + QString modality = ui->cmbModality->currentData().toString(); + QString tmpDir = ""; + bool isDICOM = false; + + /* if its a DICOM file, create a tmp directory to anonymize it */ + if ((modality == "DICOM") || (modality == "MR") || (modality == "CT") || (modality == "PET") || (modality == "SPECT") || (modality == "US")) { + isDICOM = true; + /* create a temp directory */ + tmpDir = ui->txtTmpDir->text() + "/" + GenerateRandomString(15); + QDir dir; + dir.mkpath(tmpDir); + qDebug("Creating tmpDir [%s]", tmpDir.toStdString().c_str()); + } + + QVector fileList; + + /* this will anonymize and then upload all of the files in the list */ + int rowCount = ui->tableFiles->rowCount(); + for (int i=0; i= 100) { + AnonymizeAndUpload(fileList, isDICOM, tmpDir); + /* clear the list */ + fileList.empty(); + } + + qApp->processEvents(); + } + /* anonymize and upload the remaining files */ + AnonymizeAndUpload(fileList, isDICOM, tmpDir); + + /* delete the temp directory */ + if (tmpDir != "") { + //QDir dir(tmpDir); + //dir.removeRecursively(); + } + + QApplication::restoreOverrideCursor(); +} + + +/* ------------------------------------------------- */ +/* --------- AnonymizeAndUpload -------------------- */ +/* ------------------------------------------------- */ +void MainWindow::AnonymizeAndUpload(QVector list, bool isDICOM, QString tmpDir) +{ + QStringList uploadList; + + /* loop through the list of table row numbers, and try to anonymize (if DICOM) and then upload the file */ + for (int i=0; i< list.size(); i++) { + QString f = ui->tableFiles->item(i,0)->text(); + QString newFilePath; + bool success = true; + + if (isDICOM) { + /* copy file to temp dir */ + newFilePath = tmpDir + "/" + GenerateRandomString(15) + ".dcm"; + QFile::copy(f,newFilePath); + qDebug("Copying [%s] to [%s]", f.toStdString().c_str(), newFilePath.toStdString().c_str()); + } + else { + newFilePath = f; + } + + /* add this filepath to the list of files to be uploaded */ + uploadList << newFilePath; + + ui->tableFiles->setCurrentCell(i,0); + qDebug("0"); + + if (isDICOM) { + qDebug("1"); + gdcm::Reader r; + r.SetFileName(newFilePath.toStdString().c_str()); + if (r.CanRead()) { + qDebug("2"); + bool fileChanged = false; + gdcm::File file; + gdcm::StringFilter sf; + gdcm::DataSet ds; + qDebug("3"); + + if ((ui->chkReplacePatientName->isChecked()) || (ui->chkReplacePatientID->isChecked()) || (ui->chkReplacePatientBirthDate->isChecked()) || (ui->chkRemovePatientBirthDate->isChecked())) { + r.Read(); + sf = gdcm::StringFilter(); + sf.SetFile(r.GetFile()); + file = r.GetFile(); + ds = file.GetDataSet(); + } + qDebug("4"); + /* check if the patient name should be replaced */ + if (ui->chkReplacePatientName->isChecked()) { + std::string s = sf.ToString(gdcm::Tag(0x0010,0x0010)); + QString tagVal = s.c_str(); + tagVal = tagVal.trimmed(); + + QByteArray hash = QCryptographicHash::hash(tagVal.toUtf8(), QCryptographicHash::Sha1); + QString newTagVal = hash.toHex().toUpper(); + + // The output of gdcm::Reader is a gdcm::File + // Contruct a static(*) type for Image Comments : + gdcm::Attribute<0x0010,0x0010> tag; + tag.SetValue(newTagVal.toStdString().c_str()); + // Now replace the Image Comments from the dataset with our: + ds.Replace( tag.GetAsDataElement() ); + qDebug("Replacing %s with %s",tagVal.toStdString().c_str(),newTagVal.toStdString().c_str()); + fileChanged = true; + } + qDebug("5"); + + /* check if the patient ID should be replaced */ + if (ui->chkReplacePatientID->isChecked()) { + //gdcm::StringFilter sf; + //sf = gdcm::StringFilter(); + //sf.SetFile(r.GetFile()); + std::string s = sf.ToString(gdcm::Tag(0x0010,0x0020)); + QString tagVal = s.c_str(); + tagVal = tagVal.trimmed(); + + QByteArray hash = QCryptographicHash::hash(tagVal.toUtf8(), QCryptographicHash::Sha1); + QString newTagVal = hash.toHex().toUpper(); + + // The output of gdcm::Reader is a gdcm::File + //file = r.GetFile(); + //gdcm::DataSet &ds = file.GetDataSet(); + // Contruct a static(*) type for Image Comments : + gdcm::Attribute<0x0010,0x0020> tag; + tag.SetValue(newTagVal.toStdString().c_str()); + // Now replace the Image Comments from the dataset with our: + ds.Replace( tag.GetAsDataElement() ); + qDebug("Replacing %s with %s",tagVal.toStdString().c_str(),newTagVal.toStdString().c_str()); + fileChanged = true; + } + + qDebug("6"); + /* check if the patient birthdate should be replaced */ + if (ui->chkReplacePatientBirthDate->isChecked()) { + //gdcm::StringFilter sf; + //sf = gdcm::StringFilter(); + //sf.SetFile(r.GetFile()); + std::string s = sf.ToString(gdcm::Tag(0x0010,0x0030)); + QString tagVal = s.c_str(); + tagVal = tagVal.trimmed(); + int year; + if (tagVal.length() == 8) { + year = tagVal.left(4).toInt(); + } + else if (tagVal.contains(":")) { + QStringList parts = tagVal.split(":"); + year = parts[0].toInt(); + } + else if (tagVal.contains("-")) { + QStringList parts = tagVal.split("-"); + year = parts[0].toInt(); + } + else { + QDate dob; + dob.fromString(tagVal); + year = dob.year(); + } + + QString newTagVal = QString::number(year) + "-00-00"; + + // The output of gdcm::Reader is a gdcm::File + //file = r.GetFile(); + //gdcm::DataSet &ds = file.GetDataSet(); + // Contruct a static(*) type for Image Comments : + gdcm::Attribute<0x0010,0x0030> tag; + tag.SetValue(newTagVal.toStdString().c_str()); + // Now replace the Image Comments from the dataset with our: + ds.Replace( tag.GetAsDataElement() ); + qDebug("Replacing %s with %s",tagVal.toStdString().c_str(),newTagVal.toStdString().c_str()); + fileChanged = true; + } + qDebug("7"); + + /* check if the patient birthdate should be removed */ + if (ui->chkRemovePatientBirthDate->isChecked()) { + //file = r.GetFile(); + //gdcm::DataSet &ds = file.GetDataSet(); + // Contruct a static(*) type for Image Comments : + gdcm::Attribute<0x0010,0x0020> tag; + tag.SetValue("0000-00-00"); + // Now replace the Image Comments from the dataset with our: + ds.Replace( tag.GetAsDataElement() ); + qDebug("Removed birthdate"); + fileChanged = true; + } + qDebug("8"); + + //if (1 == 2) { + if (fileChanged) { + // Write the modified DataSet back to disk + qDebug("A"); + gdcm::Writer writer; + qDebug("B"); + writer.CheckFileMetaInformationOff(); // Do not attempt to reconstruct the file meta to preserve the file as close to the original as possible. + qDebug("C"); + writer.SetFileName( QString(newFilePath + "b").toStdString().c_str() ); + qDebug("D"); + writer.SetFile( file ); + qDebug("E"); + if( !writer.Write() ) { + qDebug("F"); + std::cerr << "Could not write: " << newFilePath.toStdString().c_str() << std::endl; + success = false; + } + qDebug("G"); + ui->tableFiles->setItem(i,1,new QTableWidgetItem("anonymized")); + qDebug("H"); + } + qDebug("9"); + } // end if isDICOM + qDebug("10"); + + /* go through the list of files to be uploaded, and upload them as one big batch */ + } + } +} + + +/* ------------------------------------------------- */ +/* --------- GenerateRandomString ------------------ */ +/* ------------------------------------------------- */ +QString MainWindow::GenerateRandomString(int len) +{ + const QString possibleCharacters("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); + + QString randomString; + for(int i=0; i

    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 XJ@ImU>(xYI{DQ71Z9tImrJDnXP!O literal 0 HcmV?d00001 diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libs/png/png.h b/gdcm/Utilities/gdcmopenjpeg-v1/libs/png/png.h new file mode 100644 index 0000000..805be12 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libs/png/png.h @@ -0,0 +1,2699 @@ + +/* png.h - header file for PNG reference library + * + * libpng version 1.4.4 - September 23, 2010 + * Copyright (c) 1998-2010 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license (See LICENSE, below) + * + * Authors and maintainers: + * libpng versions 0.71, May 1995, through 0.88, January 1996: Guy Schalnat + * libpng versions 0.89c, June 1996, through 0.96, May 1997: Andreas Dilger + * libpng versions 0.97, January 1998, through 1.4.4 - September 23, 2010: Glenn + * See also "Contributing Authors", below. + * + * Note about libpng version numbers: + * + * Due to various miscommunications, unforeseen code incompatibilities + * and occasional factors outside the authors' control, version numbering + * on the library has not always been consistent and straightforward. + * The following table summarizes matters since version 0.89c, which was + * the first widely used release: + * + * source png.h png.h shared-lib + * version string int version + * ------- ------ ----- ---------- + * 0.89c "1.0 beta 3" 0.89 89 1.0.89 + * 0.90 "1.0 beta 4" 0.90 90 0.90 [should have been 2.0.90] + * 0.95 "1.0 beta 5" 0.95 95 0.95 [should have been 2.0.95] + * 0.96 "1.0 beta 6" 0.96 96 0.96 [should have been 2.0.96] + * 0.97b "1.00.97 beta 7" 1.00.97 97 1.0.1 [should have been 2.0.97] + * 0.97c 0.97 97 2.0.97 + * 0.98 0.98 98 2.0.98 + * 0.99 0.99 98 2.0.99 + * 0.99a-m 0.99 99 2.0.99 + * 1.00 1.00 100 2.1.0 [100 should be 10000] + * 1.0.0 (from here on, the 100 2.1.0 [100 should be 10000] + * 1.0.1 png.h string is 10001 2.1.0 + * 1.0.1a-e identical to the 10002 from here on, the shared library + * 1.0.2 source version) 10002 is 2.V where V is the source code + * 1.0.2a-b 10003 version, except as noted. + * 1.0.3 10003 + * 1.0.3a-d 10004 + * 1.0.4 10004 + * 1.0.4a-f 10005 + * 1.0.5 (+ 2 patches) 10005 + * 1.0.5a-d 10006 + * 1.0.5e-r 10100 (not source compatible) + * 1.0.5s-v 10006 (not binary compatible) + * 1.0.6 (+ 3 patches) 10006 (still binary incompatible) + * 1.0.6d-f 10007 (still binary incompatible) + * 1.0.6g 10007 + * 1.0.6h 10007 10.6h (testing xy.z so-numbering) + * 1.0.6i 10007 10.6i + * 1.0.6j 10007 2.1.0.6j (incompatible with 1.0.0) + * 1.0.7beta11-14 DLLNUM 10007 2.1.0.7beta11-14 (binary compatible) + * 1.0.7beta15-18 1 10007 2.1.0.7beta15-18 (binary compatible) + * 1.0.7rc1-2 1 10007 2.1.0.7rc1-2 (binary compatible) + * 1.0.7 1 10007 (still compatible) + * 1.0.8beta1-4 1 10008 2.1.0.8beta1-4 + * 1.0.8rc1 1 10008 2.1.0.8rc1 + * 1.0.8 1 10008 2.1.0.8 + * 1.0.9beta1-6 1 10009 2.1.0.9beta1-6 + * 1.0.9rc1 1 10009 2.1.0.9rc1 + * 1.0.9beta7-10 1 10009 2.1.0.9beta7-10 + * 1.0.9rc2 1 10009 2.1.0.9rc2 + * 1.0.9 1 10009 2.1.0.9 + * 1.0.10beta1 1 10010 2.1.0.10beta1 + * 1.0.10rc1 1 10010 2.1.0.10rc1 + * 1.0.10 1 10010 2.1.0.10 + * 1.0.11beta1-3 1 10011 2.1.0.11beta1-3 + * 1.0.11rc1 1 10011 2.1.0.11rc1 + * 1.0.11 1 10011 2.1.0.11 + * 1.0.12beta1-2 2 10012 2.1.0.12beta1-2 + * 1.0.12rc1 2 10012 2.1.0.12rc1 + * 1.0.12 2 10012 2.1.0.12 + * 1.1.0a-f - 10100 2.1.1.0a-f (branch abandoned) + * 1.2.0beta1-2 2 10200 2.1.2.0beta1-2 + * 1.2.0beta3-5 3 10200 3.1.2.0beta3-5 + * 1.2.0rc1 3 10200 3.1.2.0rc1 + * 1.2.0 3 10200 3.1.2.0 + * 1.2.1beta1-4 3 10201 3.1.2.1beta1-4 + * 1.2.1rc1-2 3 10201 3.1.2.1rc1-2 + * 1.2.1 3 10201 3.1.2.1 + * 1.2.2beta1-6 12 10202 12.so.0.1.2.2beta1-6 + * 1.0.13beta1 10 10013 10.so.0.1.0.13beta1 + * 1.0.13rc1 10 10013 10.so.0.1.0.13rc1 + * 1.2.2rc1 12 10202 12.so.0.1.2.2rc1 + * 1.0.13 10 10013 10.so.0.1.0.13 + * 1.2.2 12 10202 12.so.0.1.2.2 + * 1.2.3rc1-6 12 10203 12.so.0.1.2.3rc1-6 + * 1.2.3 12 10203 12.so.0.1.2.3 + * 1.2.4beta1-3 13 10204 12.so.0.1.2.4beta1-3 + * 1.0.14rc1 13 10014 10.so.0.1.0.14rc1 + * 1.2.4rc1 13 10204 12.so.0.1.2.4rc1 + * 1.0.14 10 10014 10.so.0.1.0.14 + * 1.2.4 13 10204 12.so.0.1.2.4 + * 1.2.5beta1-2 13 10205 12.so.0.1.2.5beta1-2 + * 1.0.15rc1-3 10 10015 10.so.0.1.0.15rc1-3 + * 1.2.5rc1-3 13 10205 12.so.0.1.2.5rc1-3 + * 1.0.15 10 10015 10.so.0.1.0.15 + * 1.2.5 13 10205 12.so.0.1.2.5 + * 1.2.6beta1-4 13 10206 12.so.0.1.2.6beta1-4 + * 1.0.16 10 10016 10.so.0.1.0.16 + * 1.2.6 13 10206 12.so.0.1.2.6 + * 1.2.7beta1-2 13 10207 12.so.0.1.2.7beta1-2 + * 1.0.17rc1 10 10017 12.so.0.1.0.17rc1 + * 1.2.7rc1 13 10207 12.so.0.1.2.7rc1 + * 1.0.17 10 10017 12.so.0.1.0.17 + * 1.2.7 13 10207 12.so.0.1.2.7 + * 1.2.8beta1-5 13 10208 12.so.0.1.2.8beta1-5 + * 1.0.18rc1-5 10 10018 12.so.0.1.0.18rc1-5 + * 1.2.8rc1-5 13 10208 12.so.0.1.2.8rc1-5 + * 1.0.18 10 10018 12.so.0.1.0.18 + * 1.2.8 13 10208 12.so.0.1.2.8 + * 1.2.9beta1-3 13 10209 12.so.0.1.2.9beta1-3 + * 1.2.9beta4-11 13 10209 12.so.0.9[.0] + * 1.2.9rc1 13 10209 12.so.0.9[.0] + * 1.2.9 13 10209 12.so.0.9[.0] + * 1.2.10beta1-7 13 10210 12.so.0.10[.0] + * 1.2.10rc1-2 13 10210 12.so.0.10[.0] + * 1.2.10 13 10210 12.so.0.10[.0] + * 1.4.0beta1-5 14 10400 14.so.0.0[.0] + * 1.2.11beta1-4 13 10211 12.so.0.11[.0] + * 1.4.0beta7-8 14 10400 14.so.0.0[.0] + * 1.2.11 13 10211 12.so.0.11[.0] + * 1.2.12 13 10212 12.so.0.12[.0] + * 1.4.0beta9-14 14 10400 14.so.0.0[.0] + * 1.2.13 13 10213 12.so.0.13[.0] + * 1.4.0beta15-36 14 10400 14.so.0.0[.0] + * 1.4.0beta37-87 14 10400 14.so.14.0[.0] + * 1.4.0rc01 14 10400 14.so.14.0[.0] + * 1.4.0beta88-109 14 10400 14.so.14.0[.0] + * 1.4.0rc02-08 14 10400 14.so.14.0[.0] + * 1.4.0 14 10400 14.so.14.0[.0] + * 1.4.1beta01-03 14 10401 14.so.14.1[.0] + * 1.4.1rc01 14 10401 14.so.14.1[.0] + * 1.4.1beta04-12 14 10401 14.so.14.1[.0] + * 1.4.1rc02-04 14 10401 14.so.14.1[.0] + * 1.4.1 14 10401 14.so.14.1[.0] + * 1.4.2beta01 14 10402 14.so.14.2[.0] + * 1.4.2rc02-06 14 10402 14.so.14.2[.0] + * 1.4.2 14 10402 14.so.14.2[.0] + * 1.4.3beta01-05 14 10403 14.so.14.3[.0] + * 1.4.3rc01-03 14 10403 14.so.14.3[.0] + * 1.4.3 14 10403 14.so.14.3[.0] + * 1.4.4beta01-08 14 10404 14.so.14.4[.0] + * 1.4.4rc01-06 14 10404 14.so.14.4[.0] + * + * Henceforth the source version will match the shared-library major + * and minor numbers; the shared-library major version number will be + * used for changes in backward compatibility, as it is intended. The + * PNG_LIBPNG_VER macro, which is not used within libpng but is available + * for applications, is an unsigned integer of the form xyyzz corresponding + * to the source version x.y.z (leading zeros in y and z). Beta versions + * were given the previous public release number plus a letter, until + * version 1.0.6j; from then on they were given the upcoming public + * release number plus "betaNN" or "rcN". + * + * Binary incompatibility exists only when applications make direct access + * to the info_ptr or png_ptr members through png.h, and the compiled + * application is loaded with a different version of the library. + * + * DLLNUM will change each time there are forward or backward changes + * in binary compatibility (e.g., when a new feature is added). + * + * See libpng.txt or libpng.3 for more information. The PNG specification + * is available as a W3C Recommendation and as an ISO Specification, + * defines should NOT be changed. + */ +#define PNG_INFO_gAMA 0x0001 +#define PNG_INFO_sBIT 0x0002 +#define PNG_INFO_cHRM 0x0004 +#define PNG_INFO_PLTE 0x0008 +#define PNG_INFO_tRNS 0x0010 +#define PNG_INFO_bKGD 0x0020 +#define PNG_INFO_hIST 0x0040 +#define PNG_INFO_pHYs 0x0080 +#define PNG_INFO_oFFs 0x0100 +#define PNG_INFO_tIME 0x0200 +#define PNG_INFO_pCAL 0x0400 +#define PNG_INFO_sRGB 0x0800 /* GR-P, 0.96a */ +#define PNG_INFO_iCCP 0x1000 /* ESR, 1.0.6 */ +#define PNG_INFO_sPLT 0x2000 /* ESR, 1.0.6 */ +#define PNG_INFO_sCAL 0x4000 /* ESR, 1.0.6 */ +#define PNG_INFO_IDAT 0x8000L /* ESR, 1.0.6 */ + +/* This is used for the transformation routines, as some of them + * change these values for the row. It also should enable using + * the routines for other purposes. + */ +typedef struct png_row_info_struct +{ + png_uint_32 width; /* width of row */ + png_size_t rowbytes; /* number of bytes in row */ + png_byte color_type; /* color type of row */ + png_byte bit_depth; /* bit depth of row */ + png_byte channels; /* number of channels (1, 2, 3, or 4) */ + png_byte pixel_depth; /* bits per pixel (depth * channels) */ +} png_row_info; + +typedef png_row_info FAR * png_row_infop; +typedef png_row_info FAR * FAR * png_row_infopp; + +/* These are the function types for the I/O functions and for the functions + * that allow the user to override the default I/O functions with his or her + * own. The png_error_ptr type should match that of user-supplied warning + * and error functions, while the png_rw_ptr type should match that of the + * user read/write data functions. + */ +typedef struct png_struct_def png_struct; +typedef png_struct FAR * png_structp; + +typedef void (PNGAPI *png_error_ptr) PNGARG((png_structp, png_const_charp)); +typedef void (PNGAPI *png_rw_ptr) PNGARG((png_structp, png_bytep, png_size_t)); +typedef void (PNGAPI *png_flush_ptr) PNGARG((png_structp)); +typedef void (PNGAPI *png_read_status_ptr) PNGARG((png_structp, png_uint_32, + int)); +typedef void (PNGAPI *png_write_status_ptr) PNGARG((png_structp, png_uint_32, + int)); + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED +typedef void (PNGAPI *png_progressive_info_ptr) PNGARG((png_structp, + png_infop)); +typedef void (PNGAPI *png_progressive_end_ptr) PNGARG((png_structp, png_infop)); +typedef void (PNGAPI *png_progressive_row_ptr) PNGARG((png_structp, png_bytep, + png_uint_32, int)); +#endif + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) +typedef void (PNGAPI *png_user_transform_ptr) PNGARG((png_structp, + png_row_infop, png_bytep)); +#endif + +#ifdef PNG_USER_CHUNKS_SUPPORTED +typedef int (PNGAPI *png_user_chunk_ptr) PNGARG((png_structp, + png_unknown_chunkp)); +#endif +#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED +typedef void (PNGAPI *png_unknown_chunk_ptr) PNGARG((png_structp)); +#endif +#ifdef PNG_SETJMP_SUPPORTED +/* This must match the function definition in , and the + * application must include this before png.h to obtain the definition + * of jmp_buf. + */ +typedef void (PNGAPI *png_longjmp_ptr) PNGARG((jmp_buf, int)); +#endif + +/* Transform masks for the high-level interface */ +#define PNG_TRANSFORM_IDENTITY 0x0000 /* read and write */ +#define PNG_TRANSFORM_STRIP_16 0x0001 /* read only */ +#define PNG_TRANSFORM_STRIP_ALPHA 0x0002 /* read only */ +#define PNG_TRANSFORM_PACKING 0x0004 /* read and write */ +#define PNG_TRANSFORM_PACKSWAP 0x0008 /* read and write */ +#define PNG_TRANSFORM_EXPAND 0x0010 /* read only */ +#define PNG_TRANSFORM_INVERT_MONO 0x0020 /* read and write */ +#define PNG_TRANSFORM_SHIFT 0x0040 /* read and write */ +#define PNG_TRANSFORM_BGR 0x0080 /* read and write */ +#define PNG_TRANSFORM_SWAP_ALPHA 0x0100 /* read and write */ +#define PNG_TRANSFORM_SWAP_ENDIAN 0x0200 /* read and write */ +#define PNG_TRANSFORM_INVERT_ALPHA 0x0400 /* read and write */ +#define PNG_TRANSFORM_STRIP_FILLER 0x0800 /* write only */ +/* Added to libpng-1.2.34 */ +#define PNG_TRANSFORM_STRIP_FILLER_BEFORE PNG_TRANSFORM_STRIP_FILLER +#define PNG_TRANSFORM_STRIP_FILLER_AFTER 0x1000 /* write only */ +/* Added to libpng-1.4.0 */ +#define PNG_TRANSFORM_GRAY_TO_RGB 0x2000 /* read only */ + +/* Flags for MNG supported features */ +#define PNG_FLAG_MNG_EMPTY_PLTE 0x01 +#define PNG_FLAG_MNG_FILTER_64 0x04 +#define PNG_ALL_MNG_FEATURES 0x05 + +typedef png_voidp (*png_malloc_ptr) PNGARG((png_structp, png_alloc_size_t)); +typedef void (*png_free_ptr) PNGARG((png_structp, png_voidp)); + +/* The structure that holds the information to read and write PNG files. + * The only people who need to care about what is inside of this are the + * people who will be modifying the library for their own special needs. + * It should NOT be accessed directly by an application, except to store + * the jmp_buf. + */ + +struct png_struct_def +{ +#ifdef PNG_SETJMP_SUPPORTED + jmp_buf jmpbuf PNG_DEPSTRUCT; /* used in png_error */ + png_longjmp_ptr longjmp_fn PNG_DEPSTRUCT;/* setjmp non-local goto + function. */ +#endif + png_error_ptr error_fn PNG_DEPSTRUCT; /* function for printing + errors and aborting */ + png_error_ptr warning_fn PNG_DEPSTRUCT; /* function for printing + warnings */ + png_voidp error_ptr PNG_DEPSTRUCT; /* user supplied struct for + error functions */ + png_rw_ptr write_data_fn PNG_DEPSTRUCT; /* function for writing + output data */ + png_rw_ptr read_data_fn PNG_DEPSTRUCT; /* function for reading + input data */ + png_voidp io_ptr PNG_DEPSTRUCT; /* ptr to application struct + for I/O functions */ + +#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED + png_user_transform_ptr read_user_transform_fn PNG_DEPSTRUCT; /* user read + transform */ +#endif + +#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED + png_user_transform_ptr write_user_transform_fn PNG_DEPSTRUCT; /* user write + transform */ +#endif + +/* These were added in libpng-1.0.2 */ +#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) + png_voidp user_transform_ptr PNG_DEPSTRUCT; /* user supplied struct + for user transform */ + png_byte user_transform_depth PNG_DEPSTRUCT; /* bit depth of user + transformed pixels */ + png_byte user_transform_channels PNG_DEPSTRUCT; /* channels in user + transformed pixels */ +#endif +#endif + + png_uint_32 mode PNG_DEPSTRUCT; /* tells us where we are in + the PNG file */ + png_uint_32 flags PNG_DEPSTRUCT; /* flags indicating various + things to libpng */ + png_uint_32 transformations PNG_DEPSTRUCT; /* which transformations + to perform */ + + z_stream zstream PNG_DEPSTRUCT; /* pointer to decompression + structure (below) */ + png_bytep zbuf PNG_DEPSTRUCT; /* buffer for zlib */ + png_size_t zbuf_size PNG_DEPSTRUCT; /* size of zbuf */ + int zlib_level PNG_DEPSTRUCT; /* holds zlib compression level */ + int zlib_method PNG_DEPSTRUCT; /* holds zlib compression method */ + int zlib_window_bits PNG_DEPSTRUCT; /* holds zlib compression window + bits */ + int zlib_mem_level PNG_DEPSTRUCT; /* holds zlib compression memory + level */ + int zlib_strategy PNG_DEPSTRUCT; /* holds zlib compression + strategy */ + + png_uint_32 width PNG_DEPSTRUCT; /* width of image in pixels */ + png_uint_32 height PNG_DEPSTRUCT; /* height of image in pixels */ + png_uint_32 num_rows PNG_DEPSTRUCT; /* number of rows in current pass */ + png_uint_32 usr_width PNG_DEPSTRUCT; /* width of row at start of write */ + png_size_t rowbytes PNG_DEPSTRUCT; /* size of row in bytes */ +#if 0 /* Replaced with the following in libpng-1.4.1 */ + png_size_t irowbytes PNG_DEPSTRUCT; +#endif +/* Added in libpng-1.4.1 */ +#ifdef PNG_USER_LIMITS_SUPPORTED + /* Total memory that a zTXt, sPLT, iTXt, iCCP, or unknown chunk + * can occupy when decompressed. 0 means unlimited. + * We will change the typedef from png_size_t to png_alloc_size_t + * in libpng-1.6.0 + */ + png_alloc_size_t user_chunk_malloc_max PNG_DEPSTRUCT; +#endif + png_uint_32 iwidth PNG_DEPSTRUCT; /* width of current interlaced + row in pixels */ + png_uint_32 row_number PNG_DEPSTRUCT; /* current row in interlace pass */ + png_bytep prev_row PNG_DEPSTRUCT; /* buffer to save previous + (unfiltered) row */ + png_bytep row_buf PNG_DEPSTRUCT; /* buffer to save current + (unfiltered) row */ + png_bytep sub_row PNG_DEPSTRUCT; /* buffer to save "sub" row + when filtering */ + png_bytep up_row PNG_DEPSTRUCT; /* buffer to save "up" row + when filtering */ + png_bytep avg_row PNG_DEPSTRUCT; /* buffer to save "avg" row + when filtering */ + png_bytep paeth_row PNG_DEPSTRUCT; /* buffer to save "Paeth" row + when filtering */ + png_row_info row_info PNG_DEPSTRUCT; /* used for transformation + routines */ + + png_uint_32 idat_size PNG_DEPSTRUCT; /* current IDAT size for read */ + png_uint_32 crc PNG_DEPSTRUCT; /* current chunk CRC value */ + png_colorp palette PNG_DEPSTRUCT; /* palette from the input file */ + png_uint_16 num_palette PNG_DEPSTRUCT; /* number of color entries in + palette */ + png_uint_16 num_trans PNG_DEPSTRUCT; /* number of transparency values */ + png_byte chunk_name[5] PNG_DEPSTRUCT; /* null-terminated name of current + chunk */ + png_byte compression PNG_DEPSTRUCT; /* file compression type + (always 0) */ + png_byte filter PNG_DEPSTRUCT; /* file filter type (always 0) */ + png_byte interlaced PNG_DEPSTRUCT; /* PNG_INTERLACE_NONE, + PNG_INTERLACE_ADAM7 */ + png_byte pass PNG_DEPSTRUCT; /* current interlace pass (0 - 6) */ + png_byte do_filter PNG_DEPSTRUCT; /* row filter flags (see + PNG_FILTER_ below ) */ + png_byte color_type PNG_DEPSTRUCT; /* color type of file */ + png_byte bit_depth PNG_DEPSTRUCT; /* bit depth of file */ + png_byte usr_bit_depth PNG_DEPSTRUCT; /* bit depth of users row */ + png_byte pixel_depth PNG_DEPSTRUCT; /* number of bits per pixel */ + png_byte channels PNG_DEPSTRUCT; /* number of channels in file */ + png_byte usr_channels PNG_DEPSTRUCT; /* channels at start of write */ + png_byte sig_bytes PNG_DEPSTRUCT; /* magic bytes read/written from + start of file */ + +#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) + png_uint_16 filler PNG_DEPSTRUCT; /* filler bytes for pixel + expansion */ +#endif + +#ifdef PNG_bKGD_SUPPORTED + png_byte background_gamma_type PNG_DEPSTRUCT; +# ifdef PNG_FLOATING_POINT_SUPPORTED + float background_gamma PNG_DEPSTRUCT; +# endif + png_color_16 background PNG_DEPSTRUCT; /* background color in + screen gamma space */ +#ifdef PNG_READ_GAMMA_SUPPORTED + png_color_16 background_1 PNG_DEPSTRUCT; /* background normalized + to gamma 1.0 */ +#endif +#endif /* PNG_bKGD_SUPPORTED */ + +#ifdef PNG_WRITE_FLUSH_SUPPORTED + png_flush_ptr output_flush_fn PNG_DEPSTRUCT; /* Function for flushing + output */ + png_uint_32 flush_dist PNG_DEPSTRUCT; /* how many rows apart to flush, + 0 - no flush */ + png_uint_32 flush_rows PNG_DEPSTRUCT; /* number of rows written since + last flush */ +#endif + +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + int gamma_shift PNG_DEPSTRUCT; /* number of "insignificant" bits + 16-bit gamma */ +#ifdef PNG_FLOATING_POINT_SUPPORTED + float gamma PNG_DEPSTRUCT; /* file gamma value */ + float screen_gamma PNG_DEPSTRUCT; /* screen gamma value + (display_exponent) */ +#endif +#endif + +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + png_bytep gamma_table PNG_DEPSTRUCT; /* gamma table for 8-bit + depth files */ + png_bytep gamma_from_1 PNG_DEPSTRUCT; /* converts from 1.0 to screen */ + png_bytep gamma_to_1 PNG_DEPSTRUCT; /* converts from file to 1.0 */ + png_uint_16pp gamma_16_table PNG_DEPSTRUCT; /* gamma table for 16-bit + depth files */ + png_uint_16pp gamma_16_from_1 PNG_DEPSTRUCT; /* converts from 1.0 to + screen */ + png_uint_16pp gamma_16_to_1 PNG_DEPSTRUCT; /* converts from file to 1.0 */ +#endif + +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_sBIT_SUPPORTED) + png_color_8 sig_bit PNG_DEPSTRUCT; /* significant bits in each + available channel */ +#endif + +#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) + png_color_8 shift PNG_DEPSTRUCT; /* shift for significant bit + tranformation */ +#endif + +#if defined(PNG_tRNS_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) \ + || defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + png_bytep trans_alpha PNG_DEPSTRUCT; /* alpha values for + paletted files */ + png_color_16 trans_color PNG_DEPSTRUCT; /* transparent color for + non-paletted files */ +#endif + + png_read_status_ptr read_row_fn PNG_DEPSTRUCT; /* called after each + row is decoded */ + png_write_status_ptr write_row_fn PNG_DEPSTRUCT; /* called after each + row is encoded */ +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED + png_progressive_info_ptr info_fn PNG_DEPSTRUCT; /* called after header + data fully read */ + png_progressive_row_ptr row_fn PNG_DEPSTRUCT; /* called after each + prog. row is decoded */ + png_progressive_end_ptr end_fn PNG_DEPSTRUCT; /* called after image + is complete */ + png_bytep save_buffer_ptr PNG_DEPSTRUCT; /* current location in + save_buffer */ + png_bytep save_buffer PNG_DEPSTRUCT; /* buffer for previously + read data */ + png_bytep current_buffer_ptr PNG_DEPSTRUCT; /* current location in + current_buffer */ + png_bytep current_buffer PNG_DEPSTRUCT; /* buffer for recently + used data */ + png_uint_32 push_length PNG_DEPSTRUCT; /* size of current input + chunk */ + png_uint_32 skip_length PNG_DEPSTRUCT; /* bytes to skip in + input data */ + png_size_t save_buffer_size PNG_DEPSTRUCT; /* amount of data now + in save_buffer */ + png_size_t save_buffer_max PNG_DEPSTRUCT; /* total size of + save_buffer */ + png_size_t buffer_size PNG_DEPSTRUCT; /* total amount of + available input data */ + png_size_t current_buffer_size PNG_DEPSTRUCT; /* amount of data now + in current_buffer */ + int process_mode PNG_DEPSTRUCT; /* what push library + is currently doing */ + int cur_palette PNG_DEPSTRUCT; /* current push library + palette index */ + +# ifdef PNG_TEXT_SUPPORTED + png_size_t current_text_size PNG_DEPSTRUCT; /* current size of + text input data */ + png_size_t current_text_left PNG_DEPSTRUCT; /* how much text left + to read in input */ + png_charp current_text PNG_DEPSTRUCT; /* current text chunk + buffer */ + png_charp current_text_ptr PNG_DEPSTRUCT; /* current location + in current_text */ +# endif /* PNG_PROGRESSIVE_READ_SUPPORTED && PNG_TEXT_SUPPORTED */ + +#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ + +#if defined(__TURBOC__) && !defined(_Windows) && !defined(__FLAT__) +/* For the Borland special 64K segment handler */ + png_bytepp offset_table_ptr PNG_DEPSTRUCT; + png_bytep offset_table PNG_DEPSTRUCT; + png_uint_16 offset_table_number PNG_DEPSTRUCT; + png_uint_16 offset_table_count PNG_DEPSTRUCT; + png_uint_16 offset_table_count_free PNG_DEPSTRUCT; +#endif + +#ifdef PNG_READ_QUANTIZE_SUPPORTED + png_bytep palette_lookup PNG_DEPSTRUCT; /* lookup table for quantizing */ + png_bytep quantize_index PNG_DEPSTRUCT; /* index translation for palette + files */ +#endif + +#if defined(PNG_READ_QUANTIZE_SUPPORTED) || defined(PNG_hIST_SUPPORTED) + png_uint_16p hist PNG_DEPSTRUCT; /* histogram */ +#endif + +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + png_byte heuristic_method PNG_DEPSTRUCT; /* heuristic for row + filter selection */ + png_byte num_prev_filters PNG_DEPSTRUCT; /* number of weights + for previous rows */ + png_bytep prev_filters PNG_DEPSTRUCT; /* filter type(s) of + previous row(s) */ + png_uint_16p filter_weights PNG_DEPSTRUCT; /* weight(s) for previous + line(s) */ + png_uint_16p inv_filter_weights PNG_DEPSTRUCT; /* 1/weight(s) for + previous line(s) */ + png_uint_16p filter_costs PNG_DEPSTRUCT; /* relative filter + calculation cost */ + png_uint_16p inv_filter_costs PNG_DEPSTRUCT; /* 1/relative filter + calculation cost */ +#endif + +#ifdef PNG_TIME_RFC1123_SUPPORTED + png_charp time_buffer PNG_DEPSTRUCT; /* String to hold RFC 1123 time text */ +#endif + +/* New members added in libpng-1.0.6 */ + + png_uint_32 free_me PNG_DEPSTRUCT; /* flags items libpng is + responsible for freeing */ + +#ifdef PNG_USER_CHUNKS_SUPPORTED + png_voidp user_chunk_ptr PNG_DEPSTRUCT; + png_user_chunk_ptr read_user_chunk_fn PNG_DEPSTRUCT; /* user read + chunk handler */ +#endif + +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + int num_chunk_list PNG_DEPSTRUCT; + png_bytep chunk_list PNG_DEPSTRUCT; +#endif + +/* New members added in libpng-1.0.3 */ +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED + png_byte rgb_to_gray_status PNG_DEPSTRUCT; + /* These were changed from png_byte in libpng-1.0.6 */ + png_uint_16 rgb_to_gray_red_coeff PNG_DEPSTRUCT; + png_uint_16 rgb_to_gray_green_coeff PNG_DEPSTRUCT; + png_uint_16 rgb_to_gray_blue_coeff PNG_DEPSTRUCT; +#endif + +/* New member added in libpng-1.0.4 (renamed in 1.0.9) */ +#if defined(PNG_MNG_FEATURES_SUPPORTED) || \ + defined(PNG_READ_EMPTY_PLTE_SUPPORTED) || \ + defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) +/* Changed from png_byte to png_uint_32 at version 1.2.0 */ + png_uint_32 mng_features_permitted PNG_DEPSTRUCT; +#endif + +/* New member added in libpng-1.0.7 */ +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + png_fixed_point int_gamma PNG_DEPSTRUCT; +#endif + +/* New member added in libpng-1.0.9, ifdef'ed out in 1.0.12, enabled in 1.2.0 */ +#ifdef PNG_MNG_FEATURES_SUPPORTED + png_byte filter_type PNG_DEPSTRUCT; +#endif + +/* New members added in libpng-1.2.0 */ + +/* New members added in libpng-1.0.2 but first enabled by default in 1.2.0 */ +#ifdef PNG_USER_MEM_SUPPORTED + png_voidp mem_ptr PNG_DEPSTRUCT; /* user supplied struct for + mem functions */ + png_malloc_ptr malloc_fn PNG_DEPSTRUCT; /* function for + allocating memory */ + png_free_ptr free_fn PNG_DEPSTRUCT; /* function for + freeing memory */ +#endif + +/* New member added in libpng-1.0.13 and 1.2.0 */ + png_bytep big_row_buf PNG_DEPSTRUCT; /* buffer to save current + (unfiltered) row */ + +#ifdef PNG_READ_QUANTIZE_SUPPORTED +/* The following three members were added at version 1.0.14 and 1.2.4 */ + png_bytep quantize_sort PNG_DEPSTRUCT; /* working sort array */ + png_bytep index_to_palette PNG_DEPSTRUCT; /* where the original + index currently is + in the palette */ + png_bytep palette_to_index PNG_DEPSTRUCT; /* which original index + points to this + palette color */ +#endif + +/* New members added in libpng-1.0.16 and 1.2.6 */ + png_byte compression_type PNG_DEPSTRUCT; + +#ifdef PNG_USER_LIMITS_SUPPORTED + png_uint_32 user_width_max PNG_DEPSTRUCT; + png_uint_32 user_height_max PNG_DEPSTRUCT; + /* Added in libpng-1.4.0: Total number of sPLT, text, and unknown + * chunks that can be stored (0 means unlimited). + */ + png_uint_32 user_chunk_cache_max PNG_DEPSTRUCT; +#endif + +/* New member added in libpng-1.0.25 and 1.2.17 */ +#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED + /* Storage for unknown chunk that the library doesn't recognize. */ + png_unknown_chunk unknown_chunk PNG_DEPSTRUCT; +#endif + +/* New members added in libpng-1.2.26 */ + png_uint_32 old_big_row_buf_size PNG_DEPSTRUCT; + png_uint_32 old_prev_row_size PNG_DEPSTRUCT; + +/* New member added in libpng-1.2.30 */ + png_charp chunkdata PNG_DEPSTRUCT; /* buffer for reading chunk data */ + +#ifdef PNG_IO_STATE_SUPPORTED +/* New member added in libpng-1.4.0 */ + png_uint_32 io_state PNG_DEPSTRUCT; +#endif +}; + + +/* This triggers a compiler error in png.c, if png.c and png.h + * do not agree upon the version number. + */ +typedef png_structp version_1_4_4; + +typedef png_struct FAR * FAR * png_structpp; + +/* Here are the function definitions most commonly used. This is not + * the place to find out how to use libpng. See libpng.txt for the + * full explanation, see example.c for the summary. This just provides + * a simple one line description of the use of each function. + */ + +/* Returns the version number of the library */ +PNG_EXPORT(png_uint_32,png_access_version_number) PNGARG((void)); + +/* Tell lib we have already handled the first magic bytes. + * Handling more than 8 bytes from the beginning of the file is an error. + */ +PNG_EXPORT(void,png_set_sig_bytes) PNGARG((png_structp png_ptr, + int num_bytes)); + +/* Check sig[start] through sig[start + num_to_check - 1] to see if it's a + * PNG file. Returns zero if the supplied bytes match the 8-byte PNG + * signature, and non-zero otherwise. Having num_to_check == 0 or + * start > 7 will always fail (ie return non-zero). + */ +PNG_EXPORT(int,png_sig_cmp) PNGARG((png_bytep sig, png_size_t start, + png_size_t num_to_check)); + +/* Simple signature checking function. This is the same as calling + * png_check_sig(sig, n) := !png_sig_cmp(sig, 0, n). + */ +#define png_check_sig(sig,n) !png_sig_cmp((sig), 0, (n)) + +/* Allocate and initialize png_ptr struct for reading, and any other memory. */ +PNG_EXPORT(png_structp,png_create_read_struct) + PNGARG((png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn)) PNG_ALLOCATED; + +/* Allocate and initialize png_ptr struct for writing, and any other memory */ +PNG_EXPORT(png_structp,png_create_write_struct) + PNGARG((png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn)) PNG_ALLOCATED; + +PNG_EXPORT(png_size_t,png_get_compression_buffer_size) + PNGARG((png_structp png_ptr)); + +PNG_EXPORT(void,png_set_compression_buffer_size) + PNGARG((png_structp png_ptr, png_size_t size)); + +/* Moved from pngconf.h in 1.4.0 and modified to ensure setjmp/longjmp + * match up. + */ +#ifdef PNG_SETJMP_SUPPORTED +/* This function returns the jmp_buf built in to *png_ptr. It must be + * supplied with an appropriate 'longjmp' function to use on that jmp_buf + * unless the default error function is overridden in which case NULL is + * acceptable. The size of the jmp_buf is checked against the actual size + * allocated by the library - the call will return NULL on a mismatch + * indicating an ABI mismatch. + */ +PNG_EXPORT(jmp_buf*, png_set_longjmp_fn) + PNGARG((png_structp png_ptr, png_longjmp_ptr longjmp_fn, size_t + jmp_buf_size)); +# define png_jmpbuf(png_ptr) \ + (*png_set_longjmp_fn((png_ptr), longjmp, sizeof (jmp_buf))) +#else +# define png_jmpbuf(png_ptr) \ + (LIBPNG_WAS_COMPILED_WITH__PNG_NO_SETJMP) +#endif + +#ifdef PNG_READ_SUPPORTED +/* Reset the compression stream */ +PNG_EXPORT(int,png_reset_zstream) PNGARG((png_structp png_ptr)); +#endif + +/* New functions added in libpng-1.0.2 (not enabled by default until 1.2.0) */ +#ifdef PNG_USER_MEM_SUPPORTED +PNG_EXPORT(png_structp,png_create_read_struct_2) + PNGARG((png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, + png_malloc_ptr malloc_fn, png_free_ptr free_fn)) PNG_ALLOCATED; +PNG_EXPORT(png_structp,png_create_write_struct_2) + PNGARG((png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, + png_malloc_ptr malloc_fn, png_free_ptr free_fn)) PNG_ALLOCATED; +#endif + +/* Write the PNG file signature. */ +PNG_EXPORT(void,png_write_sig) PNGARG((png_structp png_ptr)); + +/* Write a PNG chunk - size, type, (optional) data, CRC. */ +PNG_EXPORT(void,png_write_chunk) PNGARG((png_structp png_ptr, + png_bytep chunk_name, png_bytep data, png_size_t length)); + +/* Write the start of a PNG chunk - length and chunk name. */ +PNG_EXPORT(void,png_write_chunk_start) PNGARG((png_structp png_ptr, + png_bytep chunk_name, png_uint_32 length)); + +/* Write the data of a PNG chunk started with png_write_chunk_start(). */ +PNG_EXPORT(void,png_write_chunk_data) PNGARG((png_structp png_ptr, + png_bytep data, png_size_t length)); + +/* Finish a chunk started with png_write_chunk_start() (includes CRC). */ +PNG_EXPORT(void,png_write_chunk_end) PNGARG((png_structp png_ptr)); + +/* Allocate and initialize the info structure */ +PNG_EXPORT(png_infop,png_create_info_struct) + PNGARG((png_structp png_ptr)) PNG_ALLOCATED; + +PNG_EXPORT(void,png_info_init_3) PNGARG((png_infopp info_ptr, + png_size_t png_info_struct_size)); + +/* Writes all the PNG information before the image. */ +PNG_EXPORT(void,png_write_info_before_PLTE) PNGARG((png_structp png_ptr, + png_infop info_ptr)); +PNG_EXPORT(void,png_write_info) PNGARG((png_structp png_ptr, + png_infop info_ptr)); + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read the information before the actual image data. */ +PNG_EXPORT(void,png_read_info) PNGARG((png_structp png_ptr, + png_infop info_ptr)); +#endif + +#ifdef PNG_TIME_RFC1123_SUPPORTED +PNG_EXPORT(png_charp,png_convert_to_rfc1123) + PNGARG((png_structp png_ptr, png_timep ptime)); +#endif + +#ifdef PNG_CONVERT_tIME_SUPPORTED +/* Convert from a struct tm to png_time */ +PNG_EXPORT(void,png_convert_from_struct_tm) PNGARG((png_timep ptime, + struct tm FAR * ttime)); + +/* Convert from time_t to png_time. Uses gmtime() */ +PNG_EXPORT(void,png_convert_from_time_t) PNGARG((png_timep ptime, + time_t ttime)); +#endif /* PNG_CONVERT_tIME_SUPPORTED */ + +#ifdef PNG_READ_EXPAND_SUPPORTED +/* Expand data to 24-bit RGB, or 8-bit grayscale, with alpha if available. */ +PNG_EXPORT(void,png_set_expand) PNGARG((png_structp png_ptr)); +PNG_EXPORT(void,png_set_expand_gray_1_2_4_to_8) PNGARG((png_structp + png_ptr)); +PNG_EXPORT(void,png_set_palette_to_rgb) PNGARG((png_structp png_ptr)); +PNG_EXPORT(void,png_set_tRNS_to_alpha) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) +/* Use blue, green, red order for pixels. */ +PNG_EXPORT(void,png_set_bgr) PNGARG((png_structp png_ptr)); +#endif + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED +/* Expand the grayscale to 24-bit RGB if necessary. */ +PNG_EXPORT(void,png_set_gray_to_rgb) PNGARG((png_structp png_ptr)); +#endif + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED +/* Reduce RGB to grayscale. */ +#ifdef PNG_FLOATING_POINT_SUPPORTED +PNG_EXPORT(void,png_set_rgb_to_gray) PNGARG((png_structp png_ptr, + int error_action, double red, double green )); +#endif +PNG_EXPORT(void,png_set_rgb_to_gray_fixed) PNGARG((png_structp png_ptr, + int error_action, png_fixed_point red, png_fixed_point green )); +PNG_EXPORT(png_byte,png_get_rgb_to_gray_status) PNGARG((png_structp + png_ptr)); +#endif + +PNG_EXPORT(void,png_build_grayscale_palette) PNGARG((int bit_depth, + png_colorp palette)); + +#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED +PNG_EXPORT(void,png_set_strip_alpha) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \ + defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED) +PNG_EXPORT(void,png_set_swap_alpha) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) || \ + defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) +PNG_EXPORT(void,png_set_invert_alpha) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) +/* Add a filler byte to 8-bit Gray or 24-bit RGB images. */ +PNG_EXPORT(void,png_set_filler) PNGARG((png_structp png_ptr, + png_uint_32 filler, int flags)); +/* The values of the PNG_FILLER_ defines should NOT be changed */ +#define PNG_FILLER_BEFORE 0 +#define PNG_FILLER_AFTER 1 +/* Add an alpha byte to 8-bit Gray or 24-bit RGB images. */ +PNG_EXPORT(void,png_set_add_alpha) PNGARG((png_structp png_ptr, + png_uint_32 filler, int flags)); +#endif /* PNG_READ_FILLER_SUPPORTED || PNG_WRITE_FILLER_SUPPORTED */ + +#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) +/* Swap bytes in 16-bit depth files. */ +PNG_EXPORT(void,png_set_swap) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED) +/* Use 1 byte per pixel in 1, 2, or 4-bit depth files. */ +PNG_EXPORT(void,png_set_packing) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_PACKSWAP_SUPPORTED) || \ + defined(PNG_WRITE_PACKSWAP_SUPPORTED) +/* Swap packing order of pixels in bytes. */ +PNG_EXPORT(void,png_set_packswap) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) +/* Converts files to legal bit depths. */ +PNG_EXPORT(void,png_set_shift) PNGARG((png_structp png_ptr, + png_color_8p true_bits)); +#endif + +#if defined(PNG_READ_INTERLACING_SUPPORTED) || \ + defined(PNG_WRITE_INTERLACING_SUPPORTED) +/* Have the code handle the interlacing. Returns the number of passes. */ +PNG_EXPORT(int,png_set_interlace_handling) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED) +/* Invert monochrome files */ +PNG_EXPORT(void,png_set_invert_mono) PNGARG((png_structp png_ptr)); +#endif + +#ifdef PNG_READ_BACKGROUND_SUPPORTED +/* Handle alpha and tRNS by replacing with a background color. */ +#ifdef PNG_FLOATING_POINT_SUPPORTED +PNG_EXPORT(void,png_set_background) PNGARG((png_structp png_ptr, + png_color_16p background_color, int background_gamma_code, + int need_expand, double background_gamma)); +#endif +#define PNG_BACKGROUND_GAMMA_UNKNOWN 0 +#define PNG_BACKGROUND_GAMMA_SCREEN 1 +#define PNG_BACKGROUND_GAMMA_FILE 2 +#define PNG_BACKGROUND_GAMMA_UNIQUE 3 +#endif + +#ifdef PNG_READ_16_TO_8_SUPPORTED +/* Strip the second byte of information from a 16-bit depth file. */ +PNG_EXPORT(void,png_set_strip_16) PNGARG((png_structp png_ptr)); +#endif + +#ifdef PNG_READ_QUANTIZE_SUPPORTED +/* Turn on quantizing, and reduce the palette to the number of colors + * available. Prior to libpng-1.4.2, this was png_set_dither(). + */ +PNG_EXPORT(void,png_set_quantize) PNGARG((png_structp png_ptr, + png_colorp palette, int num_palette, int maximum_colors, + png_uint_16p histogram, int full_quantize)); +#endif +/* This migration aid will be removed from libpng-1.5.0 */ +#define png_set_dither png_set_quantize + +#ifdef PNG_READ_GAMMA_SUPPORTED +/* Handle gamma correction. Screen_gamma=(display_exponent) */ +#ifdef PNG_FLOATING_POINT_SUPPORTED +PNG_EXPORT(void,png_set_gamma) PNGARG((png_structp png_ptr, + double screen_gamma, double default_file_gamma)); +#endif +#endif + + +#ifdef PNG_WRITE_FLUSH_SUPPORTED +/* Set how many lines between output flushes - 0 for no flushing */ +PNG_EXPORT(void,png_set_flush) PNGARG((png_structp png_ptr, int nrows)); +/* Flush the current PNG output buffer */ +PNG_EXPORT(void,png_write_flush) PNGARG((png_structp png_ptr)); +#endif + +/* Optional update palette with requested transformations */ +PNG_EXPORT(void,png_start_read_image) PNGARG((png_structp png_ptr)); + +/* Optional call to update the users info structure */ +PNG_EXPORT(void,png_read_update_info) PNGARG((png_structp png_ptr, + png_infop info_ptr)); + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read one or more rows of image data. */ +PNG_EXPORT(void,png_read_rows) PNGARG((png_structp png_ptr, + png_bytepp row, png_bytepp display_row, png_uint_32 num_rows)); +#endif + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read a row of data. */ +PNG_EXPORT(void,png_read_row) PNGARG((png_structp png_ptr, + png_bytep row, + png_bytep display_row)); +#endif + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read the whole image into memory at once. */ +PNG_EXPORT(void,png_read_image) PNGARG((png_structp png_ptr, + png_bytepp image)); +#endif + +/* Write a row of image data */ +PNG_EXPORT(void,png_write_row) PNGARG((png_structp png_ptr, + png_bytep row)); + +/* Write a few rows of image data */ +PNG_EXPORT(void,png_write_rows) PNGARG((png_structp png_ptr, + png_bytepp row, png_uint_32 num_rows)); + +/* Write the image data */ +PNG_EXPORT(void,png_write_image) PNGARG((png_structp png_ptr, + png_bytepp image)); + +/* Write the end of the PNG file. */ +PNG_EXPORT(void,png_write_end) PNGARG((png_structp png_ptr, + png_infop info_ptr)); + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read the end of the PNG file. */ +PNG_EXPORT(void,png_read_end) PNGARG((png_structp png_ptr, + png_infop info_ptr)); +#endif + +/* Free any memory associated with the png_info_struct */ +PNG_EXPORT(void,png_destroy_info_struct) PNGARG((png_structp png_ptr, + png_infopp info_ptr_ptr)); + +/* Free any memory associated with the png_struct and the png_info_structs */ +PNG_EXPORT(void,png_destroy_read_struct) PNGARG((png_structpp + png_ptr_ptr, png_infopp info_ptr_ptr, png_infopp end_info_ptr_ptr)); + +/* Free any memory associated with the png_struct and the png_info_structs */ +PNG_EXPORT(void,png_destroy_write_struct) + PNGARG((png_structpp png_ptr_ptr, png_infopp info_ptr_ptr)); + +/* Set the libpng method of handling chunk CRC errors */ +PNG_EXPORT(void,png_set_crc_action) PNGARG((png_structp png_ptr, + int crit_action, int ancil_action)); + +/* Values for png_set_crc_action() to say how to handle CRC errors in + * ancillary and critical chunks, and whether to use the data contained + * therein. Note that it is impossible to "discard" data in a critical + * chunk. For versions prior to 0.90, the action was always error/quit, + * whereas in version 0.90 and later, the action for CRC errors in ancillary + * chunks is warn/discard. These values should NOT be changed. + * + * value action:critical action:ancillary + */ +#define PNG_CRC_DEFAULT 0 /* error/quit warn/discard data */ +#define PNG_CRC_ERROR_QUIT 1 /* error/quit error/quit */ +#define PNG_CRC_WARN_DISCARD 2 /* (INVALID) warn/discard data */ +#define PNG_CRC_WARN_USE 3 /* warn/use data warn/use data */ +#define PNG_CRC_QUIET_USE 4 /* quiet/use data quiet/use data */ +#define PNG_CRC_NO_CHANGE 5 /* use current value use current value */ + +/* These functions give the user control over the scan-line filtering in + * libpng and the compression methods used by zlib. These functions are + * mainly useful for testing, as the defaults should work with most users. + * Those users who are tight on memory or want faster performance at the + * expense of compression can modify them. See the compression library + * header file (zlib.h) for an explination of the compression functions. + */ + +/* Set the filtering method(s) used by libpng. Currently, the only valid + * value for "method" is 0. + */ +PNG_EXPORT(void,png_set_filter) PNGARG((png_structp png_ptr, int method, + int filters)); + +/* Flags for png_set_filter() to say which filters to use. The flags + * are chosen so that they don't conflict with real filter types + * below, in case they are supplied instead of the #defined constants. + * These values should NOT be changed. + */ +#define PNG_NO_FILTERS 0x00 +#define PNG_FILTER_NONE 0x08 +#define PNG_FILTER_SUB 0x10 +#define PNG_FILTER_UP 0x20 +#define PNG_FILTER_AVG 0x40 +#define PNG_FILTER_PAETH 0x80 +#define PNG_ALL_FILTERS (PNG_FILTER_NONE | PNG_FILTER_SUB | PNG_FILTER_UP | \ + PNG_FILTER_AVG | PNG_FILTER_PAETH) + +/* Filter values (not flags) - used in pngwrite.c, pngwutil.c for now. + * These defines should NOT be changed. + */ +#define PNG_FILTER_VALUE_NONE 0 +#define PNG_FILTER_VALUE_SUB 1 +#define PNG_FILTER_VALUE_UP 2 +#define PNG_FILTER_VALUE_AVG 3 +#define PNG_FILTER_VALUE_PAETH 4 +#define PNG_FILTER_VALUE_LAST 5 + +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* EXPERIMENTAL */ +/* The "heuristic_method" is given by one of the PNG_FILTER_HEURISTIC_ + * defines, either the default (minimum-sum-of-absolute-differences), or + * the experimental method (weighted-minimum-sum-of-absolute-differences). + * + * Weights are factors >= 1.0, indicating how important it is to keep the + * filter type consistent between rows. Larger numbers mean the current + * filter is that many times as likely to be the same as the "num_weights" + * previous filters. This is cumulative for each previous row with a weight. + * There needs to be "num_weights" values in "filter_weights", or it can be + * NULL if the weights aren't being specified. Weights have no influence on + * the selection of the first row filter. Well chosen weights can (in theory) + * improve the compression for a given image. + * + * Costs are factors >= 1.0 indicating the relative decoding costs of a + * filter type. Higher costs indicate more decoding expense, and are + * therefore less likely to be selected over a filter with lower computational + * costs. There needs to be a value in "filter_costs" for each valid filter + * type (given by PNG_FILTER_VALUE_LAST), or it can be NULL if you aren't + * setting the costs. Costs try to improve the speed of decompression without + * unduly increasing the compressed image size. + * + * A negative weight or cost indicates the default value is to be used, and + * values in the range [0.0, 1.0) indicate the value is to remain unchanged. + * The default values for both weights and costs are currently 1.0, but may + * change if good general weighting/cost heuristics can be found. If both + * the weights and costs are set to 1.0, this degenerates the WEIGHTED method + * to the UNWEIGHTED method, but with added encoding time/computation. + */ +#ifdef PNG_FLOATING_POINT_SUPPORTED +PNG_EXPORT(void,png_set_filter_heuristics) PNGARG((png_structp png_ptr, + int heuristic_method, int num_weights, png_doublep filter_weights, + png_doublep filter_costs)); +#endif +#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */ + +/* Heuristic used for row filter selection. These defines should NOT be + * changed. + */ +#define PNG_FILTER_HEURISTIC_DEFAULT 0 /* Currently "UNWEIGHTED" */ +#define PNG_FILTER_HEURISTIC_UNWEIGHTED 1 /* Used by libpng < 0.95 */ +#define PNG_FILTER_HEURISTIC_WEIGHTED 2 /* Experimental feature */ +#define PNG_FILTER_HEURISTIC_LAST 3 /* Not a valid value */ + +/* Set the library compression level. Currently, valid values range from + * 0 - 9, corresponding directly to the zlib compression levels 0 - 9 + * (0 - no compression, 9 - "maximal" compression). Note that tests have + * shown that zlib compression levels 3-6 usually perform as well as level 9 + * for PNG images, and do considerably fewer caclulations. In the future, + * these values may not correspond directly to the zlib compression levels. + */ +PNG_EXPORT(void,png_set_compression_level) PNGARG((png_structp png_ptr, + int level)); + +PNG_EXPORT(void,png_set_compression_mem_level) + PNGARG((png_structp png_ptr, int mem_level)); + +PNG_EXPORT(void,png_set_compression_strategy) + PNGARG((png_structp png_ptr, int strategy)); + +PNG_EXPORT(void,png_set_compression_window_bits) + PNGARG((png_structp png_ptr, int window_bits)); + +PNG_EXPORT(void,png_set_compression_method) PNGARG((png_structp png_ptr, + int method)); + +/* These next functions are called for input/output, memory, and error + * handling. They are in the file pngrio.c, pngwio.c, and pngerror.c, + * and call standard C I/O routines such as fread(), fwrite(), and + * fprintf(). These functions can be made to use other I/O routines + * at run time for those applications that need to handle I/O in a + * different manner by calling png_set_???_fn(). See libpng.txt for + * more information. + */ + +#ifdef PNG_STDIO_SUPPORTED +/* Initialize the input/output for the PNG file to the default functions. */ +PNG_EXPORT(void,png_init_io) PNGARG((png_structp png_ptr, + png_FILE_p fp)); +#endif + +/* Replace the (error and abort), and warning functions with user + * supplied functions. If no messages are to be printed you must still + * write and use replacement functions. The replacement error_fn should + * still do a longjmp to the last setjmp location if you are using this + * method of error handling. If error_fn or warning_fn is NULL, the + * default function will be used. + */ + +PNG_EXPORT(void,png_set_error_fn) PNGARG((png_structp png_ptr, + png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warning_fn)); + +/* Return the user pointer associated with the error functions */ +PNG_EXPORT(png_voidp,png_get_error_ptr) PNGARG((png_structp png_ptr)); + +/* Replace the default data output functions with a user supplied one(s). + * If buffered output is not used, then output_flush_fn can be set to NULL. + * If PNG_WRITE_FLUSH_SUPPORTED is not defined at libpng compile time + * output_flush_fn will be ignored (and thus can be NULL). + * It is probably a mistake to use NULL for output_flush_fn if + * write_data_fn is not also NULL unless you have built libpng with + * PNG_WRITE_FLUSH_SUPPORTED undefined, because in this case libpng's + * default flush function, which uses the standard *FILE structure, will + * be used. + */ +PNG_EXPORT(void,png_set_write_fn) PNGARG((png_structp png_ptr, + png_voidp io_ptr, png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn)); + +/* Replace the default data input function with a user supplied one. */ +PNG_EXPORT(void,png_set_read_fn) PNGARG((png_structp png_ptr, + png_voidp io_ptr, png_rw_ptr read_data_fn)); + +/* Return the user pointer associated with the I/O functions */ +PNG_EXPORT(png_voidp,png_get_io_ptr) PNGARG((png_structp png_ptr)); + +PNG_EXPORT(void,png_set_read_status_fn) PNGARG((png_structp png_ptr, + png_read_status_ptr read_row_fn)); + +PNG_EXPORT(void,png_set_write_status_fn) PNGARG((png_structp png_ptr, + png_write_status_ptr write_row_fn)); + +#ifdef PNG_USER_MEM_SUPPORTED +/* Replace the default memory allocation functions with user supplied one(s). */ +PNG_EXPORT(void,png_set_mem_fn) PNGARG((png_structp png_ptr, + png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn)); +/* Return the user pointer associated with the memory functions */ +PNG_EXPORT(png_voidp,png_get_mem_ptr) PNGARG((png_structp png_ptr)); +#endif + +#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED +PNG_EXPORT(void,png_set_read_user_transform_fn) PNGARG((png_structp + png_ptr, png_user_transform_ptr read_user_transform_fn)); +#endif + +#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED +PNG_EXPORT(void,png_set_write_user_transform_fn) PNGARG((png_structp + png_ptr, png_user_transform_ptr write_user_transform_fn)); +#endif + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) +PNG_EXPORT(void,png_set_user_transform_info) PNGARG((png_structp + png_ptr, png_voidp user_transform_ptr, int user_transform_depth, + int user_transform_channels)); +/* Return the user pointer associated with the user transform functions */ +PNG_EXPORT(png_voidp,png_get_user_transform_ptr) + PNGARG((png_structp png_ptr)); +#endif + +#ifdef PNG_USER_CHUNKS_SUPPORTED +PNG_EXPORT(void,png_set_read_user_chunk_fn) PNGARG((png_structp png_ptr, + png_voidp user_chunk_ptr, png_user_chunk_ptr read_user_chunk_fn)); +PNG_EXPORT(png_voidp,png_get_user_chunk_ptr) PNGARG((png_structp + png_ptr)); +#endif + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED +/* Sets the function callbacks for the push reader, and a pointer to a + * user-defined structure available to the callback functions. + */ +PNG_EXPORT(void,png_set_progressive_read_fn) PNGARG((png_structp png_ptr, + png_voidp progressive_ptr, + png_progressive_info_ptr info_fn, png_progressive_row_ptr row_fn, + png_progressive_end_ptr end_fn)); + +/* Returns the user pointer associated with the push read functions */ +PNG_EXPORT(png_voidp,png_get_progressive_ptr) + PNGARG((png_structp png_ptr)); + +/* Function to be called when data becomes available */ +PNG_EXPORT(void,png_process_data) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_bytep buffer, png_size_t buffer_size)); + +/* Function that combines rows. Not very much different than the + * png_combine_row() call. Is this even used????? + */ +PNG_EXPORT(void,png_progressive_combine_row) PNGARG((png_structp png_ptr, + png_bytep old_row, png_bytep new_row)); +#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ + +PNG_EXPORT(png_voidp,png_malloc) PNGARG((png_structp png_ptr, + png_alloc_size_t size)) PNG_ALLOCATED; +/* Added at libpng version 1.4.0 */ +PNG_EXPORT(png_voidp,png_calloc) PNGARG((png_structp png_ptr, + png_alloc_size_t size)) PNG_ALLOCATED; + +/* Added at libpng version 1.2.4 */ +PNG_EXPORT(png_voidp,png_malloc_warn) PNGARG((png_structp png_ptr, + png_alloc_size_t size)) PNG_ALLOCATED; + +/* Frees a pointer allocated by png_malloc() */ +PNG_EXPORT(void,png_free) PNGARG((png_structp png_ptr, png_voidp ptr)); + +/* Free data that was allocated internally */ +PNG_EXPORT(void,png_free_data) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 free_me, int num)); +/* Reassign responsibility for freeing existing data, whether allocated + * by libpng or by the application */ +PNG_EXPORT(void,png_data_freer) PNGARG((png_structp png_ptr, + png_infop info_ptr, int freer, png_uint_32 mask)); +/* Assignments for png_data_freer */ +#define PNG_DESTROY_WILL_FREE_DATA 1 +#define PNG_SET_WILL_FREE_DATA 1 +#define PNG_USER_WILL_FREE_DATA 2 +/* Flags for png_ptr->free_me and info_ptr->free_me */ +#define PNG_FREE_HIST 0x0008 +#define PNG_FREE_ICCP 0x0010 +#define PNG_FREE_SPLT 0x0020 +#define PNG_FREE_ROWS 0x0040 +#define PNG_FREE_PCAL 0x0080 +#define PNG_FREE_SCAL 0x0100 +#define PNG_FREE_UNKN 0x0200 +#define PNG_FREE_LIST 0x0400 +#define PNG_FREE_PLTE 0x1000 +#define PNG_FREE_TRNS 0x2000 +#define PNG_FREE_TEXT 0x4000 +#define PNG_FREE_ALL 0x7fff +#define PNG_FREE_MUL 0x4220 /* PNG_FREE_SPLT|PNG_FREE_TEXT|PNG_FREE_UNKN */ + +#ifdef PNG_USER_MEM_SUPPORTED +PNG_EXPORT(png_voidp,png_malloc_default) PNGARG((png_structp png_ptr, + png_alloc_size_t size)) PNG_ALLOCATED; +PNG_EXPORT(void,png_free_default) PNGARG((png_structp png_ptr, + png_voidp ptr)); +#endif + +#ifndef PNG_NO_ERROR_TEXT +/* Fatal error in PNG image of libpng - can't continue */ +PNG_EXPORT(void,png_error) PNGARG((png_structp png_ptr, + png_const_charp error_message)) PNG_NORETURN; + +/* The same, but the chunk name is prepended to the error string. */ +PNG_EXPORT(void,png_chunk_error) PNGARG((png_structp png_ptr, + png_const_charp error_message)) PNG_NORETURN; + +#else +/* Fatal error in PNG image of libpng - can't continue */ +PNG_EXPORT(void,png_err) PNGARG((png_structp png_ptr)) PNG_NORETURN; +#endif + +/* Non-fatal error in libpng. Can continue, but may have a problem. */ +PNG_EXPORT(void,png_warning) PNGARG((png_structp png_ptr, + png_const_charp warning_message)); + +/* Non-fatal error in libpng, chunk name is prepended to message. */ +PNG_EXPORT(void,png_chunk_warning) PNGARG((png_structp png_ptr, + png_const_charp warning_message)); + +#ifdef PNG_BENIGN_ERRORS_SUPPORTED +/* Benign error in libpng. Can continue, but may have a problem. + * User can choose whether to handle as a fatal error or as a warning. */ +PNG_EXPORT(void,png_benign_error) PNGARG((png_structp png_ptr, + png_const_charp warning_message)); + +/* Same, chunk name is prepended to message. */ +PNG_EXPORT(void,png_chunk_benign_error) PNGARG((png_structp png_ptr, + png_const_charp warning_message)); + +PNG_EXPORT(void,png_set_benign_errors) PNGARG((png_structp + png_ptr, int allowed)); +#endif + +/* The png_set_ functions are for storing values in the png_info_struct. + * Similarly, the png_get_ calls are used to read values from the + * png_info_struct, either storing the parameters in the passed variables, or + * setting pointers into the png_info_struct where the data is stored. The + * png_get_ functions return a non-zero value if the data was available + * in info_ptr, or return zero and do not change any of the parameters if the + * data was not available. + * + * These functions should be used instead of directly accessing png_info + * to avoid problems with future changes in the size and internal layout of + * png_info_struct. + */ +/* Returns "flag" if chunk data is valid in info_ptr. */ +PNG_EXPORT(png_uint_32,png_get_valid) PNGARG((png_structp png_ptr, +png_infop info_ptr, png_uint_32 flag)); + +/* Returns number of bytes needed to hold a transformed row. */ +PNG_EXPORT(png_size_t,png_get_rowbytes) PNGARG((png_structp png_ptr, +png_infop info_ptr)); + +#ifdef PNG_INFO_IMAGE_SUPPORTED +/* Returns row_pointers, which is an array of pointers to scanlines that was + * returned from png_read_png(). + */ +PNG_EXPORT(png_bytepp,png_get_rows) PNGARG((png_structp png_ptr, +png_infop info_ptr)); +/* Set row_pointers, which is an array of pointers to scanlines for use + * by png_write_png(). + */ +PNG_EXPORT(void,png_set_rows) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_bytepp row_pointers)); +#endif + +/* Returns number of color channels in image. */ +PNG_EXPORT(png_byte,png_get_channels) PNGARG((png_structp png_ptr, +png_infop info_ptr)); + +#ifdef PNG_EASY_ACCESS_SUPPORTED +/* Returns image width in pixels. */ +PNG_EXPORT(png_uint_32, png_get_image_width) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +/* Returns image height in pixels. */ +PNG_EXPORT(png_uint_32, png_get_image_height) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +/* Returns image bit_depth. */ +PNG_EXPORT(png_byte, png_get_bit_depth) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +/* Returns image color_type. */ +PNG_EXPORT(png_byte, png_get_color_type) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +/* Returns image filter_type. */ +PNG_EXPORT(png_byte, png_get_filter_type) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +/* Returns image interlace_type. */ +PNG_EXPORT(png_byte, png_get_interlace_type) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +/* Returns image compression_type. */ +PNG_EXPORT(png_byte, png_get_compression_type) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +/* Returns image resolution in pixels per meter, from pHYs chunk data. */ +PNG_EXPORT(png_uint_32, png_get_pixels_per_meter) PNGARG((png_structp +png_ptr, png_infop info_ptr)); +PNG_EXPORT(png_uint_32, png_get_x_pixels_per_meter) PNGARG((png_structp +png_ptr, png_infop info_ptr)); +PNG_EXPORT(png_uint_32, png_get_y_pixels_per_meter) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +/* Returns pixel aspect ratio, computed from pHYs chunk data. */ +#ifdef PNG_FLOATING_POINT_SUPPORTED +PNG_EXPORT(float, png_get_pixel_aspect_ratio) PNGARG((png_structp +png_ptr, png_infop info_ptr)); +#endif + +/* Returns image x, y offset in pixels or microns, from oFFs chunk data. */ +PNG_EXPORT(png_int_32, png_get_x_offset_pixels) PNGARG((png_structp +png_ptr, png_infop info_ptr)); +PNG_EXPORT(png_int_32, png_get_y_offset_pixels) PNGARG((png_structp +png_ptr, png_infop info_ptr)); +PNG_EXPORT(png_int_32, png_get_x_offset_microns) PNGARG((png_structp +png_ptr, png_infop info_ptr)); +PNG_EXPORT(png_int_32, png_get_y_offset_microns) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +#endif /* PNG_EASY_ACCESS_SUPPORTED */ + +/* Returns pointer to signature string read from PNG header */ +PNG_EXPORT(png_bytep,png_get_signature) PNGARG((png_structp png_ptr, +png_infop info_ptr)); + +#ifdef PNG_bKGD_SUPPORTED +PNG_EXPORT(png_uint_32,png_get_bKGD) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_color_16p *background)); +#endif + +#ifdef PNG_bKGD_SUPPORTED +PNG_EXPORT(void,png_set_bKGD) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_color_16p background)); +#endif + +#ifdef PNG_cHRM_SUPPORTED +#ifdef PNG_FLOATING_POINT_SUPPORTED +PNG_EXPORT(png_uint_32,png_get_cHRM) PNGARG((png_structp png_ptr, + png_infop info_ptr, double *white_x, double *white_y, double *red_x, + double *red_y, double *green_x, double *green_y, double *blue_x, + double *blue_y)); +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED +PNG_EXPORT(png_uint_32,png_get_cHRM_fixed) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_fixed_point *int_white_x, png_fixed_point + *int_white_y, png_fixed_point *int_red_x, png_fixed_point *int_red_y, + png_fixed_point *int_green_x, png_fixed_point *int_green_y, png_fixed_point + *int_blue_x, png_fixed_point *int_blue_y)); +#endif +#endif + +#ifdef PNG_cHRM_SUPPORTED +#ifdef PNG_FLOATING_POINT_SUPPORTED +PNG_EXPORT(void,png_set_cHRM) PNGARG((png_structp png_ptr, + png_infop info_ptr, double white_x, double white_y, double red_x, + double red_y, double green_x, double green_y, double blue_x, double blue_y)); +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED +PNG_EXPORT(void,png_set_cHRM_fixed) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_fixed_point int_white_x, png_fixed_point int_white_y, + png_fixed_point int_red_x, png_fixed_point int_red_y, png_fixed_point + int_green_x, png_fixed_point int_green_y, png_fixed_point int_blue_x, + png_fixed_point int_blue_y)); +#endif +#endif + +#ifdef PNG_gAMA_SUPPORTED +#ifdef PNG_FLOATING_POINT_SUPPORTED +PNG_EXPORT(png_uint_32,png_get_gAMA) PNGARG((png_structp png_ptr, + png_infop info_ptr, double *file_gamma)); +#endif +PNG_EXPORT(png_uint_32,png_get_gAMA_fixed) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_fixed_point *int_file_gamma)); +#endif + +#ifdef PNG_gAMA_SUPPORTED +#ifdef PNG_FLOATING_POINT_SUPPORTED +PNG_EXPORT(void,png_set_gAMA) PNGARG((png_structp png_ptr, + png_infop info_ptr, double file_gamma)); +#endif +PNG_EXPORT(void,png_set_gAMA_fixed) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_fixed_point int_file_gamma)); +#endif + +#ifdef PNG_hIST_SUPPORTED +PNG_EXPORT(png_uint_32,png_get_hIST) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_16p *hist)); +#endif + +#ifdef PNG_hIST_SUPPORTED +PNG_EXPORT(void,png_set_hIST) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_16p hist)); +#endif + +PNG_EXPORT(png_uint_32,png_get_IHDR) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 *width, png_uint_32 *height, + int *bit_depth, int *color_type, int *interlace_method, + int *compression_method, int *filter_method)); + +PNG_EXPORT(void,png_set_IHDR) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 width, png_uint_32 height, int bit_depth, + int color_type, int interlace_method, int compression_method, + int filter_method)); + +#ifdef PNG_oFFs_SUPPORTED +PNG_EXPORT(png_uint_32,png_get_oFFs) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_int_32 *offset_x, png_int_32 *offset_y, + int *unit_type)); +#endif + +#ifdef PNG_oFFs_SUPPORTED +PNG_EXPORT(void,png_set_oFFs) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_int_32 offset_x, png_int_32 offset_y, + int unit_type)); +#endif + +#ifdef PNG_pCAL_SUPPORTED +PNG_EXPORT(png_uint_32,png_get_pCAL) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_charp *purpose, png_int_32 *X0, png_int_32 *X1, + int *type, int *nparams, png_charp *units, png_charpp *params)); +#endif + +#ifdef PNG_pCAL_SUPPORTED +PNG_EXPORT(void,png_set_pCAL) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_charp purpose, png_int_32 X0, png_int_32 X1, + int type, int nparams, png_charp units, png_charpp params)); +#endif + +#ifdef PNG_pHYs_SUPPORTED +PNG_EXPORT(png_uint_32,png_get_pHYs) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type)); +#endif + +#ifdef PNG_pHYs_SUPPORTED +PNG_EXPORT(void,png_set_pHYs) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 res_x, png_uint_32 res_y, int unit_type)); +#endif + +PNG_EXPORT(png_uint_32,png_get_PLTE) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_colorp *palette, int *num_palette)); + +PNG_EXPORT(void,png_set_PLTE) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_colorp palette, int num_palette)); + +#ifdef PNG_sBIT_SUPPORTED +PNG_EXPORT(png_uint_32,png_get_sBIT) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_color_8p *sig_bit)); +#endif + +#ifdef PNG_sBIT_SUPPORTED +PNG_EXPORT(void,png_set_sBIT) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_color_8p sig_bit)); +#endif + +#ifdef PNG_sRGB_SUPPORTED +PNG_EXPORT(png_uint_32,png_get_sRGB) PNGARG((png_structp png_ptr, + png_infop info_ptr, int *intent)); +#endif + +#ifdef PNG_sRGB_SUPPORTED +PNG_EXPORT(void,png_set_sRGB) PNGARG((png_structp png_ptr, + png_infop info_ptr, int intent)); +PNG_EXPORT(void,png_set_sRGB_gAMA_and_cHRM) PNGARG((png_structp png_ptr, + png_infop info_ptr, int intent)); +#endif + +#ifdef PNG_iCCP_SUPPORTED +PNG_EXPORT(png_uint_32,png_get_iCCP) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_charpp name, int *compression_type, + png_charpp profile, png_uint_32 *proflen)); + /* Note to maintainer: profile should be png_bytepp */ +#endif + +#ifdef PNG_iCCP_SUPPORTED +PNG_EXPORT(void,png_set_iCCP) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_charp name, int compression_type, + png_charp profile, png_uint_32 proflen)); + /* Note to maintainer: profile should be png_bytep */ +#endif + +#ifdef PNG_sPLT_SUPPORTED +PNG_EXPORT(png_uint_32,png_get_sPLT) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_sPLT_tpp entries)); +#endif + +#ifdef PNG_sPLT_SUPPORTED +PNG_EXPORT(void,png_set_sPLT) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_sPLT_tp entries, int nentries)); +#endif + +#ifdef PNG_TEXT_SUPPORTED +/* png_get_text also returns the number of text chunks in *num_text */ +PNG_EXPORT(png_uint_32,png_get_text) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_textp *text_ptr, int *num_text)); +#endif + +/* Note while png_set_text() will accept a structure whose text, + * language, and translated keywords are NULL pointers, the structure + * returned by png_get_text will always contain regular + * zero-terminated C strings. They might be empty strings but + * they will never be NULL pointers. + */ + +#ifdef PNG_TEXT_SUPPORTED +PNG_EXPORT(void,png_set_text) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_textp text_ptr, int num_text)); +#endif + +#ifdef PNG_tIME_SUPPORTED +PNG_EXPORT(png_uint_32,png_get_tIME) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_timep *mod_time)); +#endif + +#ifdef PNG_tIME_SUPPORTED +PNG_EXPORT(void,png_set_tIME) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_timep mod_time)); +#endif + +#ifdef PNG_tRNS_SUPPORTED +PNG_EXPORT(png_uint_32,png_get_tRNS) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_bytep *trans_alpha, int *num_trans, + png_color_16p *trans_color)); +#endif + +#ifdef PNG_tRNS_SUPPORTED +PNG_EXPORT(void,png_set_tRNS) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_bytep trans_alpha, int num_trans, + png_color_16p trans_color)); +#endif + +#ifdef PNG_tRNS_SUPPORTED +#endif + +#ifdef PNG_sCAL_SUPPORTED +#ifdef PNG_FLOATING_POINT_SUPPORTED +PNG_EXPORT(png_uint_32,png_get_sCAL) PNGARG((png_structp png_ptr, + png_infop info_ptr, int *unit, double *width, double *height)); +#else +#ifdef PNG_FIXED_POINT_SUPPORTED +PNG_EXPORT(png_uint_32,png_get_sCAL_s) PNGARG((png_structp png_ptr, + png_infop info_ptr, int *unit, png_charpp swidth, png_charpp sheight)); +#endif +#endif +#endif /* PNG_sCAL_SUPPORTED */ + +#ifdef PNG_sCAL_SUPPORTED +#ifdef PNG_FLOATING_POINT_SUPPORTED +PNG_EXPORT(void,png_set_sCAL) PNGARG((png_structp png_ptr, + png_infop info_ptr, int unit, double width, double height)); +#else +#ifdef PNG_FIXED_POINT_SUPPORTED +PNG_EXPORT(void,png_set_sCAL_s) PNGARG((png_structp png_ptr, + png_infop info_ptr, int unit, png_charp swidth, png_charp sheight)); +#endif +#endif +#endif /* PNG_sCAL_SUPPORTED || PNG_WRITE_sCAL_SUPPORTED */ + +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED +/* Provide a list of chunks and how they are to be handled, if the built-in + handling or default unknown chunk handling is not desired. Any chunks not + listed will be handled in the default manner. The IHDR and IEND chunks + must not be listed. + keep = 0: follow default behaviour + = 1: do not keep + = 2: keep only if safe-to-copy + = 3: keep even if unsafe-to-copy +*/ +PNG_EXPORT(void, png_set_keep_unknown_chunks) PNGARG((png_structp + png_ptr, int keep, png_bytep chunk_list, int num_chunks)); +PNG_EXPORT(int,png_handle_as_unknown) PNGARG((png_structp png_ptr, png_bytep + chunk_name)); +#endif +#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED +PNG_EXPORT(void, png_set_unknown_chunks) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_unknown_chunkp unknowns, int num_unknowns)); +PNG_EXPORT(void, png_set_unknown_chunk_location) + PNGARG((png_structp png_ptr, png_infop info_ptr, int chunk, int location)); +PNG_EXPORT(png_uint_32,png_get_unknown_chunks) PNGARG((png_structp + png_ptr, png_infop info_ptr, png_unknown_chunkpp entries)); +#endif + +/* Png_free_data() will turn off the "valid" flag for anything it frees. + * If you need to turn it off for a chunk that your application has freed, + * you can use png_set_invalid(png_ptr, info_ptr, PNG_INFO_CHNK); + */ +PNG_EXPORT(void, png_set_invalid) PNGARG((png_structp png_ptr, + png_infop info_ptr, int mask)); + +#ifdef PNG_INFO_IMAGE_SUPPORTED +/* The "params" pointer is currently not used and is for future expansion. */ +PNG_EXPORT(void, png_read_png) PNGARG((png_structp png_ptr, + png_infop info_ptr, + int transforms, + png_voidp params)); +PNG_EXPORT(void, png_write_png) PNGARG((png_structp png_ptr, + png_infop info_ptr, + int transforms, + png_voidp params)); +#endif + +PNG_EXPORT(png_charp,png_get_copyright) PNGARG((png_structp png_ptr)); +PNG_EXPORT(png_charp,png_get_header_ver) PNGARG((png_structp png_ptr)); +PNG_EXPORT(png_charp,png_get_header_version) PNGARG((png_structp + png_ptr)); +PNG_EXPORT(png_charp,png_get_libpng_ver) PNGARG((png_structp png_ptr)); + +#ifdef PNG_MNG_FEATURES_SUPPORTED +PNG_EXPORT(png_uint_32,png_permit_mng_features) PNGARG((png_structp + png_ptr, png_uint_32 mng_features_permitted)); +#endif + +/* For use in png_set_keep_unknown, added to version 1.2.6 */ +#define PNG_HANDLE_CHUNK_AS_DEFAULT 0 +#define PNG_HANDLE_CHUNK_NEVER 1 +#define PNG_HANDLE_CHUNK_IF_SAFE 2 +#define PNG_HANDLE_CHUNK_ALWAYS 3 + +/* Strip the prepended error numbers ("#nnn ") from error and warning + * messages before passing them to the error or warning handler. + */ +#ifdef PNG_ERROR_NUMBERS_SUPPORTED +PNG_EXPORT(void,png_set_strip_error_numbers) PNGARG((png_structp + png_ptr, png_uint_32 strip_mode)); +#endif + +/* Added in libpng-1.2.6 */ +#ifdef PNG_SET_USER_LIMITS_SUPPORTED +PNG_EXPORT(void,png_set_user_limits) PNGARG((png_structp + png_ptr, png_uint_32 user_width_max, png_uint_32 user_height_max)); +PNG_EXPORT(png_uint_32,png_get_user_width_max) PNGARG((png_structp + png_ptr)); +PNG_EXPORT(png_uint_32,png_get_user_height_max) PNGARG((png_structp + png_ptr)); +/* Added in libpng-1.4.0 */ +PNG_EXPORT(void,png_set_chunk_cache_max) PNGARG((png_structp + png_ptr, png_uint_32 user_chunk_cache_max)); +PNG_EXPORT(png_uint_32,png_get_chunk_cache_max) + PNGARG((png_structp png_ptr)); +/* Added in libpng-1.4.1 */ +PNG_EXPORT(void,png_set_chunk_malloc_max) PNGARG((png_structp + png_ptr, png_alloc_size_t user_chunk_cache_max)); +PNG_EXPORT(png_alloc_size_t,png_get_chunk_malloc_max) + PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_INCH_CONVERSIONS) && defined(PNG_FLOATING_POINT_SUPPORTED) +PNG_EXPORT(png_uint_32,png_get_pixels_per_inch) PNGARG((png_structp png_ptr, +png_infop info_ptr)); + +PNG_EXPORT(png_uint_32,png_get_x_pixels_per_inch) PNGARG((png_structp png_ptr, +png_infop info_ptr)); + +PNG_EXPORT(png_uint_32,png_get_y_pixels_per_inch) PNGARG((png_structp png_ptr, +png_infop info_ptr)); + +PNG_EXPORT(float,png_get_x_offset_inches) PNGARG((png_structp png_ptr, +png_infop info_ptr)); + +PNG_EXPORT(float,png_get_y_offset_inches) PNGARG((png_structp png_ptr, +png_infop info_ptr)); + +#ifdef PNG_pHYs_SUPPORTED +PNG_EXPORT(png_uint_32,png_get_pHYs_dpi) PNGARG((png_structp png_ptr, +png_infop info_ptr, png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type)); +#endif /* PNG_pHYs_SUPPORTED */ +#endif /* PNG_INCH_CONVERSIONS && PNG_FLOATING_POINT_SUPPORTED */ + +/* Added in libpng-1.4.0 */ +#ifdef PNG_IO_STATE_SUPPORTED +PNG_EXPORT(png_uint_32,png_get_io_state) PNGARG((png_structp png_ptr)); + +PNG_EXPORT(png_bytep,png_get_io_chunk_name) + PNGARG((png_structp png_ptr)); + +/* The flags returned by png_get_io_state() are the following: */ +#define PNG_IO_NONE 0x0000 /* no I/O at this moment */ +#define PNG_IO_READING 0x0001 /* currently reading */ +#define PNG_IO_WRITING 0x0002 /* currently writing */ +#define PNG_IO_SIGNATURE 0x0010 /* currently at the file signature */ +#define PNG_IO_CHUNK_HDR 0x0020 /* currently at the chunk header */ +#define PNG_IO_CHUNK_DATA 0x0040 /* currently at the chunk data */ +#define PNG_IO_CHUNK_CRC 0x0080 /* currently at the chunk crc */ +#define PNG_IO_MASK_OP 0x000f /* current operation: reading/writing */ +#define PNG_IO_MASK_LOC 0x00f0 /* current location: sig/hdr/data/crc */ +#endif /* ?PNG_IO_STATE_SUPPORTED */ + +/* Maintainer: Put new public prototypes here ^, in libpng.3, and project + * defs + */ + +#ifdef PNG_READ_COMPOSITE_NODIV_SUPPORTED +/* With these routines we avoid an integer divide, which will be slower on + * most machines. However, it does take more operations than the corresponding + * divide method, so it may be slower on a few RISC systems. There are two + * shifts (by 8 or 16 bits) and an addition, versus a single integer divide. + * + * Note that the rounding factors are NOT supposed to be the same! 128 and + * 32768 are correct for the NODIV code; 127 and 32767 are correct for the + * standard method. + * + * [Optimized code by Greg Roelofs and Mark Adler...blame us for bugs. :-) ] + */ + + /* fg and bg should be in `gamma 1.0' space; alpha is the opacity */ + +# define png_composite(composite, fg, alpha, bg) \ + { png_uint_16 temp = (png_uint_16)((png_uint_16)(fg) \ + * (png_uint_16)(alpha) \ + + (png_uint_16)(bg)*(png_uint_16)(255 \ + - (png_uint_16)(alpha)) + (png_uint_16)128); \ + (composite) = (png_byte)((temp + (temp >> 8)) >> 8); } + +# define png_composite_16(composite, fg, alpha, bg) \ + { png_uint_32 temp = (png_uint_32)((png_uint_32)(fg) \ + * (png_uint_32)(alpha) \ + + (png_uint_32)(bg)*(png_uint_32)(65535L \ + - (png_uint_32)(alpha)) + (png_uint_32)32768L); \ + (composite) = (png_uint_16)((temp + (temp >> 16)) >> 16); } + +#else /* Standard method using integer division */ + +# define png_composite(composite, fg, alpha, bg) \ + (composite) = (png_byte)(((png_uint_16)(fg) * (png_uint_16)(alpha) + \ + (png_uint_16)(bg) * (png_uint_16)(255 - (png_uint_16)(alpha)) + \ + (png_uint_16)127) / 255) + +# define png_composite_16(composite, fg, alpha, bg) \ + (composite) = (png_uint_16)(((png_uint_32)(fg) * (png_uint_32)(alpha) + \ + (png_uint_32)(bg)*(png_uint_32)(65535L - (png_uint_32)(alpha)) + \ + (png_uint_32)32767) / (png_uint_32)65535L) +#endif /* PNG_READ_COMPOSITE_NODIV_SUPPORTED */ + +#ifdef PNG_USE_READ_MACROS +/* Inline macros to do direct reads of bytes from the input buffer. + * The png_get_int_32() routine assumes we are using two's complement + * format for negative values, which is almost certainly true. + */ +# define png_get_uint_32(buf) \ + (((png_uint_32)(*(buf)) << 24) + \ + ((png_uint_32)(*((buf) + 1)) << 16) + \ + ((png_uint_32)(*((buf) + 2)) << 8) + \ + ((png_uint_32)(*((buf) + 3)))) +# define png_get_uint_16(buf) \ + (((png_uint_32)(*(buf)) << 8) + \ + ((png_uint_32)(*((buf) + 1)))) +# define png_get_int_32(buf) \ + ((png_int_32)((*(buf) & 0x80) \ + ? -((png_int_32)((png_get_uint_32(buf) ^ 0xffffffff)+1)) \ + : (png_int_32)png_get_uint_32(buf))) +#else +PNG_EXPORT(png_uint_32,png_get_uint_32) PNGARG((png_bytep buf)); +PNG_EXPORT(png_uint_16,png_get_uint_16) PNGARG((png_bytep buf)); +#ifdef PNG_GET_INT_32_SUPPORTED +PNG_EXPORT(png_int_32,png_get_int_32) PNGARG((png_bytep buf)); +#endif +#endif +PNG_EXPORT(png_uint_32,png_get_uint_31) + PNGARG((png_structp png_ptr, png_bytep buf)); +/* No png_get_int_16 -- may be added if there's a real need for it. */ + +/* Place a 32-bit number into a buffer in PNG byte order (big-endian). */ +PNG_EXPORT(void,png_save_uint_32) + PNGARG((png_bytep buf, png_uint_32 i)); +PNG_EXPORT(void,png_save_int_32) + PNGARG((png_bytep buf, png_int_32 i)); + +/* Place a 16-bit number into a buffer in PNG byte order. + * The parameter is declared unsigned int, not png_uint_16, + * just to avoid potential problems on pre-ANSI C compilers. + */ +PNG_EXPORT(void,png_save_uint_16) + PNGARG((png_bytep buf, unsigned int i)); +/* No png_save_int_16 -- may be added if there's a real need for it. */ + +/* ************************************************************************* */ + +/* Various modes of operation. Note that after an init, mode is set to + * zero automatically when the structure is created. + */ +#define PNG_HAVE_IHDR 0x01 +#define PNG_HAVE_PLTE 0x02 +#define PNG_HAVE_IDAT 0x04 +#define PNG_AFTER_IDAT 0x08 /* Have complete zlib datastream */ +#define PNG_HAVE_IEND 0x10 +#define PNG_HAVE_gAMA 0x20 +#define PNG_HAVE_cHRM 0x40 + +#ifdef __cplusplus +} +#endif + +#endif /* PNG_VERSION_INFO_ONLY */ +/* Do not put anything past this line */ +#endif /* PNG_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libs/png/pngconf.h b/gdcm/Utilities/gdcmopenjpeg-v1/libs/png/pngconf.h new file mode 100644 index 0000000..41b13e9 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libs/png/pngconf.h @@ -0,0 +1,1540 @@ + +/* pngconf.h - machine configurable file for libpng + * + * libpng version 1.4.4 - September 23, 2010 + * For conditions of distribution and use, see copyright notice in png.h + * Copyright (c) 1998-2010 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + */ + +/* Any machine specific code is near the front of this file, so if you + * are configuring libpng for a machine, you may want to read the section + * starting here down to where it starts to typedef png_color, png_text, + * and png_info. + */ + +#ifndef PNGCONF_H +#define PNGCONF_H + +#ifndef PNG_NO_LIMITS_H +# include +#endif + +/* Added at libpng-1.2.9 */ + +/* config.h is created by and PNG_CONFIGURE_LIBPNG is set by the "configure" + * script. + */ +#ifdef PNG_CONFIGURE_LIBPNG +# ifdef HAVE_CONFIG_H +# include "config.h" +# endif +#endif + +/* + * Added at libpng-1.2.8 + * + * PNG_USER_CONFIG has to be defined on the compiler command line. This + * includes the resource compiler for Windows DLL configurations. + */ +#ifdef PNG_USER_CONFIG +# include "pngusr.h" +# ifndef PNG_USER_PRIVATEBUILD +# define PNG_USER_PRIVATEBUILD +# endif +#endif + +/* + * If you create a private DLL you should define in "pngusr.h" the following: + * #define PNG_USER_PRIVATEBUILD + * e.g. #define PNG_USER_PRIVATEBUILD "Build by MyCompany for xyz reasons." + * #define PNG_USER_DLLFNAME_POSTFIX + * e.g. // private DLL "libpng14gx.dll" + * #define PNG_USER_DLLFNAME_POSTFIX "gx" + * + * The following macros are also at your disposal if you want to complete the + * DLL VERSIONINFO structure. + * - PNG_USER_VERSIONINFO_COMMENTS + * - PNG_USER_VERSIONINFO_COMPANYNAME + * - PNG_USER_VERSIONINFO_LEGALTRADEMARKS + */ + +#ifdef __STDC__ +# ifdef SPECIALBUILD +# pragma message("PNG_LIBPNG_SPECIALBUILD (and deprecated SPECIALBUILD)\ + are now LIBPNG reserved macros. Use PNG_USER_PRIVATEBUILD instead.") +# endif + +# ifdef PRIVATEBUILD +# pragma message("PRIVATEBUILD is deprecated.\ + Use PNG_USER_PRIVATEBUILD instead.") +# define PNG_USER_PRIVATEBUILD PRIVATEBUILD +# endif +#endif /* __STDC__ */ + +/* End of material added to libpng-1.2.8 */ + +#ifndef PNG_VERSION_INFO_ONLY + +/* This is the size of the compression buffer, and thus the size of + * an IDAT chunk. Make this whatever size you feel is best for your + * machine. One of these will be allocated per png_struct. When this + * is full, it writes the data to the disk, and does some other + * calculations. Making this an extremely small size will slow + * the library down, but you may want to experiment to determine + * where it becomes significant, if you are concerned with memory + * usage. Note that zlib allocates at least 32Kb also. For readers, + * this describes the size of the buffer available to read the data in. + * Unless this gets smaller than the size of a row (compressed), + * it should not make much difference how big this is. + */ + +#ifndef PNG_ZBUF_SIZE +# define PNG_ZBUF_SIZE 8192 +#endif + +/* Enable if you want a write-only libpng */ + +#ifndef PNG_NO_READ_SUPPORTED +# define PNG_READ_SUPPORTED +#endif + +/* Enable if you want a read-only libpng */ + +#ifndef PNG_NO_WRITE_SUPPORTED +# define PNG_WRITE_SUPPORTED +#endif + +/* Enabled in 1.4.0. */ +#ifdef PNG_ALLOW_BENIGN_ERRORS +# define png_benign_error png_warning +# define png_chunk_benign_error png_chunk_warning +#else +# ifndef PNG_BENIGN_ERRORS_SUPPORTED +# define png_benign_error png_error +# define png_chunk_benign_error png_chunk_error +# endif +#endif + +/* Added at libpng version 1.4.0 */ +#if !defined(PNG_NO_WARNINGS) && !defined(PNG_WARNINGS_SUPPORTED) +# define PNG_WARNINGS_SUPPORTED +#endif + +/* Added at libpng version 1.4.0 */ +#if !defined(PNG_NO_ERROR_TEXT) && !defined(PNG_ERROR_TEXT_SUPPORTED) +# define PNG_ERROR_TEXT_SUPPORTED +#endif + +/* Added at libpng version 1.4.0 */ +#if !defined(PNG_NO_CHECK_cHRM) && !defined(PNG_CHECK_cHRM_SUPPORTED) +# define PNG_CHECK_cHRM_SUPPORTED +#endif + +/* Added at libpng version 1.4.0 */ +#if !defined(PNG_NO_ALIGNED_MEMORY) && !defined(PNG_ALIGNED_MEMORY_SUPPORTED) +# define PNG_ALIGNED_MEMORY_SUPPORTED +#endif + +/* Enabled by default in 1.2.0. You can disable this if you don't need to + support PNGs that are embedded in MNG datastreams */ +#ifndef PNG_NO_MNG_FEATURES +# ifndef PNG_MNG_FEATURES_SUPPORTED +# define PNG_MNG_FEATURES_SUPPORTED +# endif +#endif + +/* Added at libpng version 1.4.0 */ +#ifndef PNG_NO_FLOATING_POINT_SUPPORTED +# ifndef PNG_FLOATING_POINT_SUPPORTED +# define PNG_FLOATING_POINT_SUPPORTED +# endif +#endif + +/* Added at libpng-1.4.0beta49 for testing (this test is no longer used + in libpng and png_calloc() is always present) + */ +#define PNG_CALLOC_SUPPORTED + +/* If you are running on a machine where you cannot allocate more + * than 64K of memory at once, uncomment this. While libpng will not + * normally need that much memory in a chunk (unless you load up a very + * large file), zlib needs to know how big of a chunk it can use, and + * libpng thus makes sure to check any memory allocation to verify it + * will fit into memory. +#define PNG_MAX_MALLOC_64K + */ +#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K) +# define PNG_MAX_MALLOC_64K +#endif + +/* Special munging to support doing things the 'cygwin' way: + * 'Normal' png-on-win32 defines/defaults: + * PNG_BUILD_DLL -- building dll + * PNG_USE_DLL -- building an application, linking to dll + * (no define) -- building static library, or building an + * application and linking to the static lib + * 'Cygwin' defines/defaults: + * PNG_BUILD_DLL -- (ignored) building the dll + * (no define) -- (ignored) building an application, linking to the dll + * PNG_STATIC -- (ignored) building the static lib, or building an + * application that links to the static lib. + * ALL_STATIC -- (ignored) building various static libs, or building an + * application that links to the static libs. + * Thus, + * a cygwin user should define either PNG_BUILD_DLL or PNG_STATIC, and + * this bit of #ifdefs will define the 'correct' config variables based on + * that. If a cygwin user *wants* to define 'PNG_USE_DLL' that's okay, but + * unnecessary. + * + * Also, the precedence order is: + * ALL_STATIC (since we can't #undef something outside our namespace) + * PNG_BUILD_DLL + * PNG_STATIC + * (nothing) == PNG_USE_DLL + * + * CYGWIN (2002-01-20): The preceding is now obsolete. With the advent + * of auto-import in binutils, we no longer need to worry about + * __declspec(dllexport) / __declspec(dllimport) and friends. Therefore, + * we don't need to worry about PNG_STATIC or ALL_STATIC when it comes + * to __declspec() stuff. However, we DO need to worry about + * PNG_BUILD_DLL and PNG_STATIC because those change some defaults + * such as CONSOLE_IO. + */ +#ifdef __CYGWIN__ +# ifdef ALL_STATIC +# ifdef PNG_BUILD_DLL +# undef PNG_BUILD_DLL +# endif +# ifdef PNG_USE_DLL +# undef PNG_USE_DLL +# endif +# ifdef PNG_DLL +# undef PNG_DLL +# endif +# ifndef PNG_STATIC +# define PNG_STATIC +# endif +# else +# ifdef PNG_BUILD_DLL +# ifdef PNG_STATIC +# undef PNG_STATIC +# endif +# ifdef PNG_USE_DLL +# undef PNG_USE_DLL +# endif +# ifndef PNG_DLL +# define PNG_DLL +# endif +# else +# ifdef PNG_STATIC +# ifdef PNG_USE_DLL +# undef PNG_USE_DLL +# endif +# ifdef PNG_DLL +# undef PNG_DLL +# endif +# else +# ifndef PNG_USE_DLL +# define PNG_USE_DLL +# endif +# ifndef PNG_DLL +# define PNG_DLL +# endif +# endif +# endif +# endif +#endif + +/* This protects us against compilers that run on a windowing system + * and thus don't have or would rather us not use the stdio types: + * stdin, stdout, and stderr. The only one currently used is stderr + * in png_error() and png_warning(). #defining PNG_NO_CONSOLE_IO will + * prevent these from being compiled and used. #defining PNG_NO_STDIO + * will also prevent these, plus will prevent the entire set of stdio + * macros and functions (FILE *, printf, etc.) from being compiled and used, + * unless (PNG_DEBUG > 0) has been #defined. + * + * #define PNG_NO_CONSOLE_IO + * #define PNG_NO_STDIO + */ + +#ifdef _WIN32_WCE +# define PNG_NO_CONSOLE_IO +# define PNG_NO_STDIO +# define PNG_NO_TIME_RFC1123 +# ifdef PNG_DEBUG +# undef PNG_DEBUG +# endif +#endif + +#if !defined(PNG_NO_STDIO) && !defined(PNG_STDIO_SUPPORTED) +# define PNG_STDIO_SUPPORTED +#endif + +#ifdef PNG_BUILD_DLL +# if !defined(PNG_CONSOLE_IO_SUPPORTED) && !defined(PNG_NO_CONSOLE_IO) +# define PNG_NO_CONSOLE_IO +# endif +#endif + +# ifdef PNG_NO_STDIO +# ifndef PNG_NO_CONSOLE_IO +# define PNG_NO_CONSOLE_IO +# endif +# ifdef PNG_DEBUG +# if (PNG_DEBUG > 0) +# include +# endif +# endif +# else +# include +# endif + +#if !(defined PNG_NO_CONSOLE_IO) && !defined(PNG_CONSOLE_IO_SUPPORTED) +# define PNG_CONSOLE_IO_SUPPORTED +#endif + +/* This macro protects us against machines that don't have function + * prototypes (ie K&R style headers). If your compiler does not handle + * function prototypes, define this macro and use the included ansi2knr. + * I've always been able to use _NO_PROTO as the indicator, but you may + * need to drag the empty declaration out in front of here, or change the + * ifdef to suit your own needs. + */ +#ifndef PNGARG + +#ifdef OF /* zlib prototype munger */ +# define PNGARG(arglist) OF(arglist) +#else + +#ifdef _NO_PROTO +# define PNGARG(arglist) () +#else +# define PNGARG(arglist) arglist +#endif /* _NO_PROTO */ + +#endif /* OF */ + +#endif /* PNGARG */ + +/* Try to determine if we are compiling on a Mac. Note that testing for + * just __MWERKS__ is not good enough, because the Codewarrior is now used + * on non-Mac platforms. + */ +#ifndef MACOS +# if (defined(__MWERKS__) && defined(macintosh)) || defined(applec) || \ + defined(THINK_C) || defined(__SC__) || defined(TARGET_OS_MAC) +# define MACOS +# endif +#endif + +/* Enough people need this for various reasons to include it here */ +#if !defined(MACOS) && !defined(RISCOS) +# include +#endif + +/* PNG_SETJMP_NOT_SUPPORTED and PNG_NO_SETJMP_SUPPORTED are deprecated. */ +#if !defined(PNG_NO_SETJMP) && \ + !defined(PNG_SETJMP_NOT_SUPPORTED) && !defined(PNG_NO_SETJMP_SUPPORTED) +# define PNG_SETJMP_SUPPORTED +#endif + +#ifdef PNG_SETJMP_SUPPORTED +/* This is an attempt to force a single setjmp behaviour on Linux. If + * the X config stuff didn't define _BSD_SOURCE we wouldn't need this. + * + * You can bypass this test if you know that your application uses exactly + * the same setjmp.h that was included when libpng was built. Only define + * PNG_SKIP_SETJMP_CHECK while building your application, prior to the + * application's '#include "png.h"'. Don't define PNG_SKIP_SETJMP_CHECK + * while building a separate libpng library for general use. + */ + +# ifndef PNG_SKIP_SETJMP_CHECK +# ifdef __linux__ +# ifdef _BSD_SOURCE +# define PNG_SAVE_BSD_SOURCE +# undef _BSD_SOURCE +# endif +# ifdef _SETJMP_H + /* If you encounter a compiler error here, see the explanation + * near the end of INSTALL. + */ + __pngconf.h__ in libpng already includes setjmp.h; + __dont__ include it again.; +# endif +# endif /* __linux__ */ +# endif /* PNG_SKIP_SETJMP_CHECK */ + + /* Include setjmp.h for error handling */ +# include + +# ifdef __linux__ +# ifdef PNG_SAVE_BSD_SOURCE +# ifdef _BSD_SOURCE +# undef _BSD_SOURCE +# endif +# define _BSD_SOURCE +# undef PNG_SAVE_BSD_SOURCE +# endif +# endif /* __linux__ */ +#endif /* PNG_SETJMP_SUPPORTED */ + +#ifdef BSD +# include +#else +# include +#endif + +/* Other defines for things like memory and the like can go here. */ + +/* This controls how fine the quantizing gets. As this allocates + * a largish chunk of memory (32K), those who are not as concerned + * with quantizing quality can decrease some or all of these. + */ + +/* Prior to libpng-1.4.2, these were PNG_DITHER_*_BITS + * These migration aids will be removed from libpng-1.5.0. + */ +#ifdef PNG_DITHER_RED_BITS +# define PNG_QUANTIZE_RED_BITS PNG_DITHER_RED_BITS +#endif +#ifdef PNG_DITHER_GREEN_BITS +# define PNG_QUANTIZE_GREEN_BITS PNG_DITHER_GREEN_BITS +#endif +#ifdef PNG_DITHER_BLUE_BITS +# define PNG_QUANTIZE_BLUE_BITS PNG_DITHER_BLUE_BITS +#endif + +#ifndef PNG_QUANTIZE_RED_BITS +# define PNG_QUANTIZE_RED_BITS 5 +#endif +#ifndef PNG_QUANTIZE_GREEN_BITS +# define PNG_QUANTIZE_GREEN_BITS 5 +#endif +#ifndef PNG_QUANTIZE_BLUE_BITS +# define PNG_QUANTIZE_BLUE_BITS 5 +#endif + +/* This controls how fine the gamma correction becomes when you + * are only interested in 8 bits anyway. Increasing this value + * results in more memory being used, and more pow() functions + * being called to fill in the gamma tables. Don't set this value + * less then 8, and even that may not work (I haven't tested it). + */ + +#ifndef PNG_MAX_GAMMA_8 +# define PNG_MAX_GAMMA_8 11 +#endif + +/* This controls how much a difference in gamma we can tolerate before + * we actually start doing gamma conversion. + */ +#ifndef PNG_GAMMA_THRESHOLD +# define PNG_GAMMA_THRESHOLD 0.05 +#endif + +/* The following uses const char * instead of char * for error + * and warning message functions, so some compilers won't complain. + * If you do not want to use const, define PNG_NO_CONST. + */ + +#ifndef PNG_CONST +# ifndef PNG_NO_CONST +# define PNG_CONST const +# else +# define PNG_CONST +# endif +#endif + +/* The following defines give you the ability to remove code from the + * library that you will not be using. I wish I could figure out how to + * automate this, but I can't do that without making it seriously hard + * on the users. So if you are not using an ability, change the #define + * to an #undef, or pass in PNG_NO_feature and that part of the library + * will not be compiled. + + * If your linker can't find a function, you may want to make sure the + * ability is defined here. Some of these depend upon some others being + * defined. I haven't figured out all the interactions here, so you may + * have to experiment awhile to get everything to compile. If you are + * creating or using a shared library, you probably shouldn't touch this, + * as it will affect the size of the structures, and this will cause bad + * things to happen if the library and/or application ever change. + */ + +/* Any features you will not be using can be undef'ed here */ + +/* GR-P, 0.96a: Set "*TRANSFORMS_SUPPORTED as default but allow user + * to turn it off with PNG_NO_READ|WRITE_TRANSFORMS on the compile line, + * then pick and choose which ones to define without having to edit this + * file. It is safe to use the PNG_NO_READ|WRITE_TRANSFORMS + * if you only want to have a png-compliant reader/writer but don't need + * any of the extra transformations. This saves about 80 kbytes in a + * typical installation of the library. (PNG_NO_* form added in version + * 1.0.1c, for consistency; PNG_*_TRANSFORMS_NOT_SUPPORTED deprecated in + * 1.4.0) + */ + +/* Ignore attempt to turn off both floating and fixed point support */ +#if !defined(PNG_FLOATING_POINT_SUPPORTED) || \ + !defined(PNG_NO_FIXED_POINT_SUPPORTED) +# define PNG_FIXED_POINT_SUPPORTED +#endif + +#ifdef PNG_READ_SUPPORTED + +/* PNG_READ_TRANSFORMS_NOT_SUPPORTED is deprecated. */ +#if !defined(PNG_READ_TRANSFORMS_NOT_SUPPORTED) && \ + !defined(PNG_NO_READ_TRANSFORMS) +# define PNG_READ_TRANSFORMS_SUPPORTED +#endif + +#ifdef PNG_READ_TRANSFORMS_SUPPORTED +# ifndef PNG_NO_READ_EXPAND +# define PNG_READ_EXPAND_SUPPORTED +# endif +# ifndef PNG_NO_READ_SHIFT +# define PNG_READ_SHIFT_SUPPORTED +# endif +# ifndef PNG_NO_READ_PACK +# define PNG_READ_PACK_SUPPORTED +# endif +# ifndef PNG_NO_READ_BGR +# define PNG_READ_BGR_SUPPORTED +# endif +# ifndef PNG_NO_READ_SWAP +# define PNG_READ_SWAP_SUPPORTED +# endif +# ifndef PNG_NO_READ_PACKSWAP +# define PNG_READ_PACKSWAP_SUPPORTED +# endif +# ifndef PNG_NO_READ_INVERT +# define PNG_READ_INVERT_SUPPORTED +# endif +# ifndef PNG_NO_READ_QUANTIZE + /* Prior to libpng-1.4.0 this was PNG_READ_DITHER_SUPPORTED */ +# ifndef PNG_NO_READ_DITHER /* This migration aid will be removed */ +# define PNG_READ_QUANTIZE_SUPPORTED +# endif +# endif +# ifndef PNG_NO_READ_BACKGROUND +# define PNG_READ_BACKGROUND_SUPPORTED +# endif +# ifndef PNG_NO_READ_16_TO_8 +# define PNG_READ_16_TO_8_SUPPORTED +# endif +# ifndef PNG_NO_READ_FILLER +# define PNG_READ_FILLER_SUPPORTED +# endif +# ifndef PNG_NO_READ_GAMMA +# define PNG_READ_GAMMA_SUPPORTED +# endif +# ifndef PNG_NO_READ_GRAY_TO_RGB +# define PNG_READ_GRAY_TO_RGB_SUPPORTED +# endif +# ifndef PNG_NO_READ_SWAP_ALPHA +# define PNG_READ_SWAP_ALPHA_SUPPORTED +# endif +# ifndef PNG_NO_READ_INVERT_ALPHA +# define PNG_READ_INVERT_ALPHA_SUPPORTED +# endif +# ifndef PNG_NO_READ_STRIP_ALPHA +# define PNG_READ_STRIP_ALPHA_SUPPORTED +# endif +# ifndef PNG_NO_READ_USER_TRANSFORM +# define PNG_READ_USER_TRANSFORM_SUPPORTED +# endif +# ifndef PNG_NO_READ_RGB_TO_GRAY +# define PNG_READ_RGB_TO_GRAY_SUPPORTED +# endif +#endif /* PNG_READ_TRANSFORMS_SUPPORTED */ + +/* PNG_PROGRESSIVE_READ_NOT_SUPPORTED is deprecated. */ +#if !defined(PNG_NO_PROGRESSIVE_READ) && \ + !defined(PNG_PROGRESSIVE_READ_NOT_SUPPORTED) /* if you don't do progressive */ +# define PNG_PROGRESSIVE_READ_SUPPORTED /* reading. This is not talking */ +#endif /* about interlacing capability! You'll */ + /* still have interlacing unless you change the following define: */ + +#define PNG_READ_INTERLACING_SUPPORTED /* required for PNG-compliant decoders */ + +/* PNG_NO_SEQUENTIAL_READ_SUPPORTED is deprecated. */ +#if !defined(PNG_NO_SEQUENTIAL_READ) && \ + !defined(PNG_SEQUENTIAL_READ_SUPPORTED) && \ + !defined(PNG_NO_SEQUENTIAL_READ_SUPPORTED) +# define PNG_SEQUENTIAL_READ_SUPPORTED +#endif + +#ifndef PNG_NO_READ_COMPOSITE_NODIV +# ifndef PNG_NO_READ_COMPOSITED_NODIV /* libpng-1.0.x misspelling */ +# define PNG_READ_COMPOSITE_NODIV_SUPPORTED /* well tested on Intel, SGI */ +# endif +#endif + +#if !defined(PNG_NO_GET_INT_32) || defined(PNG_READ_oFFS_SUPPORTED) || \ + defined(PNG_READ_pCAL_SUPPORTED) +# ifndef PNG_GET_INT_32_SUPPORTED +# define PNG_GET_INT_32_SUPPORTED +# endif +#endif + +#endif /* PNG_READ_SUPPORTED */ + +#ifdef PNG_WRITE_SUPPORTED + +/* PNG_WRITE_TRANSFORMS_NOT_SUPPORTED is deprecated. */ +#if !defined(PNG_WRITE_TRANSFORMS_NOT_SUPPORTED) && \ + !defined(PNG_NO_WRITE_TRANSFORMS) +# define PNG_WRITE_TRANSFORMS_SUPPORTED +#endif + +#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED +# ifndef PNG_NO_WRITE_SHIFT +# define PNG_WRITE_SHIFT_SUPPORTED +# endif +# ifndef PNG_NO_WRITE_PACK +# define PNG_WRITE_PACK_SUPPORTED +# endif +# ifndef PNG_NO_WRITE_BGR +# define PNG_WRITE_BGR_SUPPORTED +# endif +# ifndef PNG_NO_WRITE_SWAP +# define PNG_WRITE_SWAP_SUPPORTED +# endif +# ifndef PNG_NO_WRITE_PACKSWAP +# define PNG_WRITE_PACKSWAP_SUPPORTED +# endif +# ifndef PNG_NO_WRITE_INVERT +# define PNG_WRITE_INVERT_SUPPORTED +# endif +# ifndef PNG_NO_WRITE_FILLER +# define PNG_WRITE_FILLER_SUPPORTED /* same as WRITE_STRIP_ALPHA */ +# endif +# ifndef PNG_NO_WRITE_SWAP_ALPHA +# define PNG_WRITE_SWAP_ALPHA_SUPPORTED +# endif +# ifndef PNG_NO_WRITE_INVERT_ALPHA +# define PNG_WRITE_INVERT_ALPHA_SUPPORTED +# endif +# ifndef PNG_NO_WRITE_USER_TRANSFORM +# define PNG_WRITE_USER_TRANSFORM_SUPPORTED +# endif +#endif /* PNG_WRITE_TRANSFORMS_SUPPORTED */ + +#if !defined(PNG_NO_WRITE_INTERLACING_SUPPORTED) && \ + !defined(PNG_WRITE_INTERLACING_SUPPORTED) + /* This is not required for PNG-compliant encoders, but can cause + * trouble if left undefined + */ +# define PNG_WRITE_INTERLACING_SUPPORTED +#endif + +#if !defined(PNG_NO_WRITE_WEIGHTED_FILTER) && \ + !defined(PNG_WRITE_WEIGHTED_FILTER) && \ + defined(PNG_FLOATING_POINT_SUPPORTED) +# define PNG_WRITE_WEIGHTED_FILTER_SUPPORTED +#endif + +#ifndef PNG_NO_WRITE_FLUSH +# define PNG_WRITE_FLUSH_SUPPORTED +#endif + +#if !defined(PNG_NO_SAVE_INT_32) || defined(PNG_WRITE_oFFS_SUPPORTED) || \ + defined(PNG_WRITE_pCAL_SUPPORTED) +# ifndef PNG_SAVE_INT_32_SUPPORTED +# define PNG_SAVE_INT_32_SUPPORTED +# endif +#endif + +#endif /* PNG_WRITE_SUPPORTED */ + +#define PNG_NO_ERROR_NUMBERS + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) +# ifndef PNG_NO_USER_TRANSFORM_PTR +# define PNG_USER_TRANSFORM_PTR_SUPPORTED +# endif +#endif + +#if defined(PNG_STDIO_SUPPORTED) && !defined(PNG_TIME_RFC1123_SUPPORTED) +# define PNG_TIME_RFC1123_SUPPORTED +#endif + +/* This adds extra functions in pngget.c for accessing data from the + * info pointer (added in version 0.99) + * png_get_image_width() + * png_get_image_height() + * png_get_bit_depth() + * png_get_color_type() + * png_get_compression_type() + * png_get_filter_type() + * png_get_interlace_type() + * png_get_pixel_aspect_ratio() + * png_get_pixels_per_meter() + * png_get_x_offset_pixels() + * png_get_y_offset_pixels() + * png_get_x_offset_microns() + * png_get_y_offset_microns() + */ +#if !defined(PNG_NO_EASY_ACCESS) && !defined(PNG_EASY_ACCESS_SUPPORTED) +# define PNG_EASY_ACCESS_SUPPORTED +#endif + +/* Added at libpng-1.2.0 */ +#if !defined(PNG_NO_USER_MEM) && !defined(PNG_USER_MEM_SUPPORTED) +# define PNG_USER_MEM_SUPPORTED +#endif + +/* Added at libpng-1.2.6 */ +#ifndef PNG_NO_SET_USER_LIMITS +# ifndef PNG_SET_USER_LIMITS_SUPPORTED +# define PNG_SET_USER_LIMITS_SUPPORTED +# endif + /* Feature added at libpng-1.4.0, this flag added at 1.4.1 */ +# ifndef PNG_SET_CHUNK_CACHE_LIMIT_SUPPORTED +# define PNG_SET_CHUNK_CACHE_LIMIT_SUPPORTED +# endif + /* Feature added at libpng-1.4.1, this flag added at 1.4.1 */ +# ifndef PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED +# define PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED +# endif +#endif + +/* Added at libpng-1.2.43 */ +#ifndef PNG_USER_LIMITS_SUPPORTED +# ifndef PNG_NO_USER_LIMITS +# define PNG_USER_LIMITS_SUPPORTED +# endif +#endif + +/* Added at libpng-1.0.16 and 1.2.6. To accept all valid PNGs no matter + * how large, set these two limits to 0x7fffffffL + */ +#ifndef PNG_USER_WIDTH_MAX +# define PNG_USER_WIDTH_MAX 1000000L +#endif +#ifndef PNG_USER_HEIGHT_MAX +# define PNG_USER_HEIGHT_MAX 1000000L +#endif + +/* Added at libpng-1.2.43. To accept all valid PNGs no matter + * how large, set these two limits to 0. + */ +#ifndef PNG_USER_CHUNK_CACHE_MAX +# define PNG_USER_CHUNK_CACHE_MAX 0 +#endif + +/* Added at libpng-1.2.43 */ +#ifndef PNG_USER_CHUNK_MALLOC_MAX +# define PNG_USER_CHUNK_MALLOC_MAX 0 +#endif + +/* Added at libpng-1.4.0 */ +#if !defined(PNG_NO_IO_STATE) && !defined(PNG_IO_STATE_SUPPORTED) +# define PNG_IO_STATE_SUPPORTED +#endif + +#ifndef PNG_LITERAL_SHARP +# define PNG_LITERAL_SHARP 0x23 +#endif +#ifndef PNG_LITERAL_LEFT_SQUARE_BRACKET +# define PNG_LITERAL_LEFT_SQUARE_BRACKET 0x5b +#endif +#ifndef PNG_LITERAL_RIGHT_SQUARE_BRACKET +# define PNG_LITERAL_RIGHT_SQUARE_BRACKET 0x5d +#endif +#ifndef PNG_STRING_NEWLINE +#define PNG_STRING_NEWLINE "\n" +#endif + +/* These are currently experimental features, define them if you want */ + +/* Very little testing */ +/* +#ifdef PNG_READ_SUPPORTED +# ifndef PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED +# define PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED +# endif +#endif +*/ + +/* This is only for PowerPC big-endian and 680x0 systems */ +/* some testing */ +/* +#ifndef PNG_READ_BIG_ENDIAN_SUPPORTED +# define PNG_READ_BIG_ENDIAN_SUPPORTED +#endif +*/ + +#if !defined(PNG_NO_USE_READ_MACROS) && !defined(PNG_USE_READ_MACROS) +# define PNG_USE_READ_MACROS +#endif + +/* Buggy compilers (e.g., gcc 2.7.2.2) need PNG_NO_POINTER_INDEXING */ + +#if !defined(PNG_NO_POINTER_INDEXING) && \ + !defined(PNG_POINTER_INDEXING_SUPPORTED) +# define PNG_POINTER_INDEXING_SUPPORTED +#endif + + +/* Any chunks you are not interested in, you can undef here. The + * ones that allocate memory may be expecially important (hIST, + * tEXt, zTXt, tRNS, pCAL). Others will just save time and make png_info + * a bit smaller. + */ + +/* The size of the png_text structure changed in libpng-1.0.6 when + * iTXt support was added. iTXt support was turned off by default through + * libpng-1.2.x, to support old apps that malloc the png_text structure + * instead of calling png_set_text() and letting libpng malloc it. It + * was turned on by default in libpng-1.4.0. + */ + +/* PNG_READ_ANCILLARY_CHUNKS_NOT_SUPPORTED is deprecated. */ +#if defined(PNG_READ_SUPPORTED) && \ + !defined(PNG_READ_ANCILLARY_CHUNKS_NOT_SUPPORTED) && \ + !defined(PNG_NO_READ_ANCILLARY_CHUNKS) +# define PNG_READ_ANCILLARY_CHUNKS_SUPPORTED +#endif + +/* PNG_WRITE_ANCILLARY_CHUNKS_NOT_SUPPORTED is deprecated. */ +#if defined(PNG_WRITE_SUPPORTED) && \ + !defined(PNG_WRITE_ANCILLARY_CHUNKS_NOT_SUPPORTED) && \ + !defined(PNG_NO_WRITE_ANCILLARY_CHUNKS) +# define PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED +#endif + +#ifdef PNG_READ_ANCILLARY_CHUNKS_SUPPORTED + +#ifdef PNG_NO_READ_TEXT +# define PNG_NO_READ_iTXt +# define PNG_NO_READ_tEXt +# define PNG_NO_READ_zTXt +#endif + +#ifndef PNG_NO_READ_bKGD +# define PNG_READ_bKGD_SUPPORTED +# define PNG_bKGD_SUPPORTED +#endif +#ifndef PNG_NO_READ_cHRM +# define PNG_READ_cHRM_SUPPORTED +# define PNG_cHRM_SUPPORTED +#endif +#ifndef PNG_NO_READ_gAMA +# define PNG_READ_gAMA_SUPPORTED +# define PNG_gAMA_SUPPORTED +#endif +#ifndef PNG_NO_READ_hIST +# define PNG_READ_hIST_SUPPORTED +# define PNG_hIST_SUPPORTED +#endif +#ifndef PNG_NO_READ_iCCP +# define PNG_READ_iCCP_SUPPORTED +# define PNG_iCCP_SUPPORTED +#endif +#ifndef PNG_NO_READ_iTXt +# ifndef PNG_READ_iTXt_SUPPORTED +# define PNG_READ_iTXt_SUPPORTED +# endif +# ifndef PNG_iTXt_SUPPORTED +# define PNG_iTXt_SUPPORTED +# endif +#endif +#ifndef PNG_NO_READ_oFFs +# define PNG_READ_oFFs_SUPPORTED +# define PNG_oFFs_SUPPORTED +#endif +#ifndef PNG_NO_READ_pCAL +# define PNG_READ_pCAL_SUPPORTED +# define PNG_pCAL_SUPPORTED +#endif +#ifndef PNG_NO_READ_sCAL +# define PNG_READ_sCAL_SUPPORTED +# define PNG_sCAL_SUPPORTED +#endif +#ifndef PNG_NO_READ_pHYs +# define PNG_READ_pHYs_SUPPORTED +# define PNG_pHYs_SUPPORTED +#endif +#ifndef PNG_NO_READ_sBIT +# define PNG_READ_sBIT_SUPPORTED +# define PNG_sBIT_SUPPORTED +#endif +#ifndef PNG_NO_READ_sPLT +# define PNG_READ_sPLT_SUPPORTED +# define PNG_sPLT_SUPPORTED +#endif +#ifndef PNG_NO_READ_sRGB +# define PNG_READ_sRGB_SUPPORTED +# define PNG_sRGB_SUPPORTED +#endif +#ifndef PNG_NO_READ_tEXt +# define PNG_READ_tEXt_SUPPORTED +# define PNG_tEXt_SUPPORTED +#endif +#ifndef PNG_NO_READ_tIME +# define PNG_READ_tIME_SUPPORTED +# define PNG_tIME_SUPPORTED +#endif +#ifndef PNG_NO_READ_tRNS +# define PNG_READ_tRNS_SUPPORTED +# define PNG_tRNS_SUPPORTED +#endif +#ifndef PNG_NO_READ_zTXt +# define PNG_READ_zTXt_SUPPORTED +# define PNG_zTXt_SUPPORTED +#endif +#ifndef PNG_NO_READ_OPT_PLTE +# define PNG_READ_OPT_PLTE_SUPPORTED /* only affects support of the */ +#endif /* optional PLTE chunk in RGB and RGBA images */ +#if defined(PNG_READ_iTXt_SUPPORTED) || defined(PNG_READ_tEXt_SUPPORTED) || \ + defined(PNG_READ_zTXt_SUPPORTED) +# define PNG_READ_TEXT_SUPPORTED +# define PNG_TEXT_SUPPORTED +#endif + +#endif /* PNG_READ_ANCILLARY_CHUNKS_SUPPORTED */ + +#ifndef PNG_NO_READ_UNKNOWN_CHUNKS +# ifndef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED +# define PNG_READ_UNKNOWN_CHUNKS_SUPPORTED +# endif +# ifndef PNG_UNKNOWN_CHUNKS_SUPPORTED +# define PNG_UNKNOWN_CHUNKS_SUPPORTED +# endif +# ifndef PNG_READ_USER_CHUNKS_SUPPORTED +# define PNG_READ_USER_CHUNKS_SUPPORTED +# endif +#endif +#ifndef PNG_NO_READ_USER_CHUNKS +# ifndef PNG_READ_USER_CHUNKS_SUPPORTED +# define PNG_READ_USER_CHUNKS_SUPPORTED +# endif +# ifndef PNG_USER_CHUNKS_SUPPORTED +# define PNG_USER_CHUNKS_SUPPORTED +# endif +#endif +#ifndef PNG_NO_HANDLE_AS_UNKNOWN +# ifndef PNG_HANDLE_AS_UNKNOWN_SUPPORTED +# define PNG_HANDLE_AS_UNKNOWN_SUPPORTED +# endif +#endif + +#ifdef PNG_WRITE_SUPPORTED +#ifdef PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED + +#ifdef PNG_NO_WRITE_TEXT +# define PNG_NO_WRITE_iTXt +# define PNG_NO_WRITE_tEXt +# define PNG_NO_WRITE_zTXt +#endif +#ifndef PNG_NO_WRITE_bKGD +# define PNG_WRITE_bKGD_SUPPORTED +# ifndef PNG_bKGD_SUPPORTED +# define PNG_bKGD_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_cHRM +# define PNG_WRITE_cHRM_SUPPORTED +# ifndef PNG_cHRM_SUPPORTED +# define PNG_cHRM_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_gAMA +# define PNG_WRITE_gAMA_SUPPORTED +# ifndef PNG_gAMA_SUPPORTED +# define PNG_gAMA_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_hIST +# define PNG_WRITE_hIST_SUPPORTED +# ifndef PNG_hIST_SUPPORTED +# define PNG_hIST_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_iCCP +# define PNG_WRITE_iCCP_SUPPORTED +# ifndef PNG_iCCP_SUPPORTED +# define PNG_iCCP_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_iTXt +# ifndef PNG_WRITE_iTXt_SUPPORTED +# define PNG_WRITE_iTXt_SUPPORTED +# endif +# ifndef PNG_iTXt_SUPPORTED +# define PNG_iTXt_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_oFFs +# define PNG_WRITE_oFFs_SUPPORTED +# ifndef PNG_oFFs_SUPPORTED +# define PNG_oFFs_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_pCAL +# define PNG_WRITE_pCAL_SUPPORTED +# ifndef PNG_pCAL_SUPPORTED +# define PNG_pCAL_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_sCAL +# define PNG_WRITE_sCAL_SUPPORTED +# ifndef PNG_sCAL_SUPPORTED +# define PNG_sCAL_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_pHYs +# define PNG_WRITE_pHYs_SUPPORTED +# ifndef PNG_pHYs_SUPPORTED +# define PNG_pHYs_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_sBIT +# define PNG_WRITE_sBIT_SUPPORTED +# ifndef PNG_sBIT_SUPPORTED +# define PNG_sBIT_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_sPLT +# define PNG_WRITE_sPLT_SUPPORTED +# ifndef PNG_sPLT_SUPPORTED +# define PNG_sPLT_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_sRGB +# define PNG_WRITE_sRGB_SUPPORTED +# ifndef PNG_sRGB_SUPPORTED +# define PNG_sRGB_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_tEXt +# define PNG_WRITE_tEXt_SUPPORTED +# ifndef PNG_tEXt_SUPPORTED +# define PNG_tEXt_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_tIME +# define PNG_WRITE_tIME_SUPPORTED +# ifndef PNG_tIME_SUPPORTED +# define PNG_tIME_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_tRNS +# define PNG_WRITE_tRNS_SUPPORTED +# ifndef PNG_tRNS_SUPPORTED +# define PNG_tRNS_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_zTXt +# define PNG_WRITE_zTXt_SUPPORTED +# ifndef PNG_zTXt_SUPPORTED +# define PNG_zTXt_SUPPORTED +# endif +#endif +#if defined(PNG_WRITE_iTXt_SUPPORTED) || defined(PNG_WRITE_tEXt_SUPPORTED) || \ + defined(PNG_WRITE_zTXt_SUPPORTED) +# define PNG_WRITE_TEXT_SUPPORTED +# ifndef PNG_TEXT_SUPPORTED +# define PNG_TEXT_SUPPORTED +# endif +#endif + +#ifdef PNG_WRITE_tIME_SUPPORTED +# ifndef PNG_NO_CONVERT_tIME +# ifndef _WIN32_WCE +/* The "tm" structure is not supported on WindowsCE */ +# ifndef PNG_CONVERT_tIME_SUPPORTED +# define PNG_CONVERT_tIME_SUPPORTED +# endif +# endif +# endif +#endif + +#endif /* PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED */ + +#ifndef PNG_NO_WRITE_FILTER +# ifndef PNG_WRITE_FILTER_SUPPORTED +# define PNG_WRITE_FILTER_SUPPORTED +# endif +#endif + +#ifndef PNG_NO_WRITE_UNKNOWN_CHUNKS +# define PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED +# ifndef PNG_UNKNOWN_CHUNKS_SUPPORTED +# define PNG_UNKNOWN_CHUNKS_SUPPORTED +# endif +#endif +#ifndef PNG_NO_HANDLE_AS_UNKNOWN +# ifndef PNG_HANDLE_AS_UNKNOWN_SUPPORTED +# define PNG_HANDLE_AS_UNKNOWN_SUPPORTED +# endif +#endif +#endif /* PNG_WRITE_SUPPORTED */ + +/* Turn this off to disable png_read_png() and + * png_write_png() and leave the row_pointers member + * out of the info structure. + */ +#ifndef PNG_NO_INFO_IMAGE +# define PNG_INFO_IMAGE_SUPPORTED +#endif + +/* Need the time information for converting tIME chunks */ +#ifdef PNG_CONVERT_tIME_SUPPORTED + /* "time.h" functions are not supported on WindowsCE */ +# include +#endif + +/* Some typedefs to get us started. These should be safe on most of the + * common platforms. The typedefs should be at least as large as the + * numbers suggest (a png_uint_32 must be at least 32 bits long), but they + * don't have to be exactly that size. Some compilers dislike passing + * unsigned shorts as function parameters, so you may be better off using + * unsigned int for png_uint_16. + */ + +#if defined(INT_MAX) && (INT_MAX > 0x7ffffffeL) +typedef unsigned int png_uint_32; +typedef int png_int_32; +#else +typedef unsigned long png_uint_32; +typedef long png_int_32; +#endif +typedef unsigned short png_uint_16; +typedef short png_int_16; +typedef unsigned char png_byte; + +#ifdef PNG_NO_SIZE_T + typedef unsigned int png_size_t; +#else + typedef size_t png_size_t; +#endif +#define png_sizeof(x) (sizeof (x)) + +/* The following is needed for medium model support. It cannot be in the + * pngpriv.h header. Needs modification for other compilers besides + * MSC. Model independent support declares all arrays and pointers to be + * large using the far keyword. The zlib version used must also support + * model independent data. As of version zlib 1.0.4, the necessary changes + * have been made in zlib. The USE_FAR_KEYWORD define triggers other + * changes that are needed. (Tim Wegner) + */ + +/* Separate compiler dependencies (problem here is that zlib.h always + * defines FAR. (SJT) + */ +#ifdef __BORLANDC__ +# if defined(__LARGE__) || defined(__HUGE__) || defined(__COMPACT__) +# define LDATA 1 +# else +# define LDATA 0 +# endif + /* GRR: why is Cygwin in here? Cygwin is not Borland C... */ +# if !defined(__WIN32__) && !defined(__FLAT__) && !defined(__CYGWIN__) +# define PNG_MAX_MALLOC_64K +# if (LDATA != 1) +# ifndef FAR +# define FAR __far +# endif +# define USE_FAR_KEYWORD +# endif /* LDATA != 1 */ + /* Possibly useful for moving data out of default segment. + * Uncomment it if you want. Could also define FARDATA as + * const if your compiler supports it. (SJT) +# define FARDATA FAR + */ +# endif /* __WIN32__, __FLAT__, __CYGWIN__ */ +#endif /* __BORLANDC__ */ + + +/* Suggest testing for specific compiler first before testing for + * FAR. The Watcom compiler defines both __MEDIUM__ and M_I86MM, + * making reliance oncertain keywords suspect. (SJT) + */ + +/* MSC Medium model */ +#ifdef FAR +# ifdef M_I86MM +# define USE_FAR_KEYWORD +# define FARDATA FAR +# include +# endif +#endif + +/* SJT: default case */ +#ifndef FAR +# define FAR +#endif + +/* At this point FAR is always defined */ +#ifndef FARDATA +# define FARDATA +#endif + +/* Typedef for floating-point numbers that are converted + to fixed-point with a multiple of 100,000, e.g., int_gamma */ +typedef png_int_32 png_fixed_point; + +/* Add typedefs for pointers */ +typedef void FAR * png_voidp; +typedef png_byte FAR * png_bytep; +typedef png_uint_32 FAR * png_uint_32p; +typedef png_int_32 FAR * png_int_32p; +typedef png_uint_16 FAR * png_uint_16p; +typedef png_int_16 FAR * png_int_16p; +typedef PNG_CONST char FAR * png_const_charp; +typedef char FAR * png_charp; +typedef png_fixed_point FAR * png_fixed_point_p; + +#ifndef PNG_NO_STDIO +typedef FILE * png_FILE_p; +#endif + +#ifdef PNG_FLOATING_POINT_SUPPORTED +typedef double FAR * png_doublep; +#endif + +/* Pointers to pointers; i.e. arrays */ +typedef png_byte FAR * FAR * png_bytepp; +typedef png_uint_32 FAR * FAR * png_uint_32pp; +typedef png_int_32 FAR * FAR * png_int_32pp; +typedef png_uint_16 FAR * FAR * png_uint_16pp; +typedef png_int_16 FAR * FAR * png_int_16pp; +typedef PNG_CONST char FAR * FAR * png_const_charpp; +typedef char FAR * FAR * png_charpp; +typedef png_fixed_point FAR * FAR * png_fixed_point_pp; +#ifdef PNG_FLOATING_POINT_SUPPORTED +typedef double FAR * FAR * png_doublepp; +#endif + +/* Pointers to pointers to pointers; i.e., pointer to array */ +typedef char FAR * FAR * FAR * png_charppp; + +/* Define PNG_BUILD_DLL if the module being built is a Windows + * LIBPNG DLL. + * + * Define PNG_USE_DLL if you want to *link* to the Windows LIBPNG DLL. + * It is equivalent to Microsoft predefined macro _DLL that is + * automatically defined when you compile using the share + * version of the CRT (C Run-Time library) + * + * The cygwin mods make this behavior a little different: + * Define PNG_BUILD_DLL if you are building a dll for use with cygwin + * Define PNG_STATIC if you are building a static library for use with cygwin, + * -or- if you are building an application that you want to link to the + * static library. + * PNG_USE_DLL is defined by default (no user action needed) unless one of + * the other flags is defined. + */ + +#if !defined(PNG_DLL) && (defined(PNG_BUILD_DLL) || defined(PNG_USE_DLL)) +# define PNG_DLL +#endif + +/* If you define PNGAPI, e.g., with compiler option "-DPNGAPI=__stdcall", + * you may get warnings regarding the linkage of png_zalloc and png_zfree. + * Don't ignore those warnings; you must also reset the default calling + * convention in your compiler to match your PNGAPI, and you must build + * zlib and your applications the same way you build libpng. + */ + +#ifdef __CYGWIN__ +# undef PNGAPI +# define PNGAPI __cdecl +# undef PNG_IMPEXP +# define PNG_IMPEXP +#endif + +#ifdef __WATCOMC__ +# ifndef PNGAPI +# define PNGAPI +# endif +#endif + +#if defined(__MINGW32__) && !defined(PNG_MODULEDEF) +# ifndef PNG_NO_MODULEDEF +# define PNG_NO_MODULEDEF +# endif +#endif + +#if !defined(PNG_IMPEXP) && defined(PNG_BUILD_DLL) && !defined(PNG_NO_MODULEDEF) +# define PNG_IMPEXP +#endif + +#if defined(PNG_DLL) || defined(_DLL) || defined(__DLL__ ) || \ + (( defined(_Windows) || defined(_WINDOWS) || \ + defined(WIN32) || defined(_WIN32) || defined(__WIN32__) )) + +# ifndef PNGAPI +# if defined(__GNUC__) || (defined (_MSC_VER) && (_MSC_VER >= 800)) +# define PNGAPI __cdecl +# else +# define PNGAPI _cdecl +# endif +# endif + +# if !defined(PNG_IMPEXP) && (!defined(PNG_DLL) || \ + 0 /* WINCOMPILER_WITH_NO_SUPPORT_FOR_DECLIMPEXP */) +# define PNG_IMPEXP +# endif + +# ifndef PNG_IMPEXP + +# define PNG_EXPORT_TYPE1(type,symbol) PNG_IMPEXP type PNGAPI symbol +# define PNG_EXPORT_TYPE2(type,symbol) type PNG_IMPEXP PNGAPI symbol + + /* Borland/Microsoft */ +# if defined(_MSC_VER) || defined(__BORLANDC__) +# if (_MSC_VER >= 800) || (__BORLANDC__ >= 0x500) +# define PNG_EXPORT PNG_EXPORT_TYPE1 +# else +# define PNG_EXPORT PNG_EXPORT_TYPE2 +# ifdef PNG_BUILD_DLL +# define PNG_IMPEXP __export +# else +# define PNG_IMPEXP /*__import */ /* doesn't exist AFAIK in VC++ */ +# endif /* Exists in Borland C++ for + C++ classes (== huge) */ +# endif +# endif + +# ifndef PNG_IMPEXP +# ifdef PNG_BUILD_DLL +# define PNG_IMPEXP __declspec(dllexport) +# else +# define PNG_IMPEXP __declspec(dllimport) +# endif +# endif +# endif /* PNG_IMPEXP */ +#else /* !(DLL || non-cygwin WINDOWS) */ +# if (defined(__IBMC__) || defined(__IBMCPP__)) && defined(__OS2__) +# ifndef PNGAPI +# define PNGAPI _System +# endif +# else +# if 0 /* ... other platforms, with other meanings */ +# endif +# endif +#endif + +#ifndef PNGAPI +# define PNGAPI +#endif +#ifndef PNG_IMPEXP +# define PNG_IMPEXP +#endif + +#ifdef PNG_BUILDSYMS +# ifndef PNG_EXPORT +# define PNG_EXPORT(type,symbol) PNG_FUNCTION_EXPORT symbol END +# endif +#endif + +#ifndef PNG_EXPORT +# define PNG_EXPORT(type,symbol) PNG_IMPEXP type PNGAPI symbol +#endif + +#define PNG_USE_LOCAL_ARRAYS /* Not used in libpng, defined for legacy apps */ + +/* Support for compiler specific function attributes. These are used + * so that where compiler support is available incorrect use of API + * functions in png.h will generate compiler warnings. + * + * Added at libpng-1.2.41. + */ + +#ifndef PNG_NO_PEDANTIC_WARNINGS +# ifndef PNG_PEDANTIC_WARNINGS_SUPPORTED +# define PNG_PEDANTIC_WARNINGS_SUPPORTED +# endif +#endif + +#ifdef PNG_PEDANTIC_WARNINGS_SUPPORTED +/* Support for compiler specific function attributes. These are used + * so that where compiler support is available incorrect use of API + * functions in png.h will generate compiler warnings. Added at libpng + * version 1.2.41. + */ +# ifdef __GNUC__ +# ifndef PNG_USE_RESULT +# define PNG_USE_RESULT __attribute__((__warn_unused_result__)) +# endif +# ifndef PNG_NORETURN +# define PNG_NORETURN __attribute__((__noreturn__)) +# endif +# ifndef PNG_ALLOCATED +# define PNG_ALLOCATED __attribute__((__malloc__)) +# endif + + /* This specifically protects structure members that should only be + * accessed from within the library, therefore should be empty during + * a library build. + */ +# ifndef PNG_DEPRECATED +# define PNG_DEPRECATED __attribute__((__deprecated__)) +# endif +# ifndef PNG_DEPSTRUCT +# define PNG_DEPSTRUCT __attribute__((__deprecated__)) +# endif +# ifndef PNG_PRIVATE +# if 0 /* Doesn't work so we use deprecated instead*/ +# define PNG_PRIVATE \ + __attribute__((warning("This function is not exported by libpng."))) +# else +# define PNG_PRIVATE \ + __attribute__((__deprecated__)) +# endif +# endif /* PNG_PRIVATE */ +# endif /* __GNUC__ */ +#endif /* PNG_PEDANTIC_WARNINGS */ + +#ifndef PNG_DEPRECATED +# define PNG_DEPRECATED /* Use of this function is deprecated */ +#endif +#ifndef PNG_USE_RESULT +# define PNG_USE_RESULT /* The result of this function must be checked */ +#endif +#ifndef PNG_NORETURN +# define PNG_NORETURN /* This function does not return */ +#endif +#ifndef PNG_ALLOCATED +# define PNG_ALLOCATED /* The result of the function is new memory */ +#endif +#ifndef PNG_DEPSTRUCT +# define PNG_DEPSTRUCT /* Access to this struct member is deprecated */ +#endif +#ifndef PNG_PRIVATE +# define PNG_PRIVATE /* This is a private libpng function */ +#endif + +/* Users may want to use these so they are not private. Any library + * functions that are passed far data must be model-independent. + */ + +/* memory model/platform independent fns */ +#ifndef PNG_ABORT +# if (defined(_Windows) || defined(_WINDOWS) || defined(_WINDOWS_)) +# define PNG_ABORT() ExitProcess(0) +# else +# define PNG_ABORT() abort() +# endif +#endif + +#ifdef USE_FAR_KEYWORD +/* Use this to make far-to-near assignments */ +# define CHECK 1 +# define NOCHECK 0 +# define CVT_PTR(ptr) (png_far_to_near(png_ptr,ptr,CHECK)) +# define CVT_PTR_NOCHECK(ptr) (png_far_to_near(png_ptr,ptr,NOCHECK)) +# define png_strcpy _fstrcpy +# define png_strncpy _fstrncpy /* Added to v 1.2.6 */ +# define png_strlen _fstrlen +# define png_memcmp _fmemcmp /* SJT: added */ +# define png_memcpy _fmemcpy +# define png_memset _fmemset +# define png_sprintf sprintf +#else +# if (defined(_Windows) || defined(_WINDOWS) || defined(_WINDOWS_)) +# /* Favor Windows over C runtime fns */ +# define CVT_PTR(ptr) (ptr) +# define CVT_PTR_NOCHECK(ptr) (ptr) +# define png_strcpy lstrcpyA +# define png_strncpy lstrcpynA +# define png_strlen lstrlenA +# define png_memcmp memcmp +# define png_memcpy CopyMemory +# define png_memset memset +# define png_sprintf wsprintfA +# else +# define CVT_PTR(ptr) (ptr) +# define CVT_PTR_NOCHECK(ptr) (ptr) +# define png_strcpy strcpy +# define png_strncpy strncpy /* Added to v 1.2.6 */ +# define png_strlen strlen +# define png_memcmp memcmp /* SJT: added */ +# define png_memcpy memcpy +# define png_memset memset +# define png_sprintf sprintf +# endif +#endif + +#ifndef PNG_NO_SNPRINTF +# ifdef _MSC_VER +# define png_snprintf _snprintf /* Added to v 1.2.19 */ +# define png_snprintf2 _snprintf +# define png_snprintf6 _snprintf +# else +# define png_snprintf snprintf /* Added to v 1.2.19 */ +# define png_snprintf2 snprintf +# define png_snprintf6 snprintf +# endif +#else + /* You don't have or don't want to use snprintf(). Caution: Using + * sprintf instead of snprintf exposes your application to accidental + * or malevolent buffer overflows. If you don't have snprintf() + * as a general rule you should provide one (you can get one from + * Portable OpenSSH). + */ +# define png_snprintf(s1,n,fmt,x1) png_sprintf(s1,fmt,x1) +# define png_snprintf2(s1,n,fmt,x1,x2) png_sprintf(s1,fmt,x1,x2) +# define png_snprintf6(s1,n,fmt,x1,x2,x3,x4,x5,x6) \ + png_sprintf(s1,fmt,x1,x2,x3,x4,x5,x6) +#endif + +/* png_alloc_size_t is guaranteed to be no smaller than png_size_t, + * and no smaller than png_uint_32. Casts from png_size_t or png_uint_32 + * to png_alloc_size_t are not necessary; in fact, it is recommended + * not to use them at all so that the compiler can complain when something + * turns out to be problematic. + * Casts in the other direction (from png_alloc_size_t to png_size_t or + * png_uint_32) should be explicitly applied; however, we do not expect + * to encounter practical situations that require such conversions. + */ +#if defined(__TURBOC__) && !defined(__FLAT__) + typedef unsigned long png_alloc_size_t; +#else +# if defined(_MSC_VER) && defined(MAXSEG_64K) + typedef unsigned long png_alloc_size_t; +# else + /* This is an attempt to detect an old Windows system where (int) is + * actually 16 bits, in that case png_malloc must have an argument with a + * bigger size to accomodate the requirements of the library. + */ +# if (defined(_Windows) || defined(_WINDOWS) || defined(_WINDOWS_)) && \ + (!defined(INT_MAX) || INT_MAX <= 0x7ffffffeL) + typedef DWORD png_alloc_size_t; +# else + typedef png_size_t png_alloc_size_t; +# endif +# endif +#endif +/* End of memory model/platform independent support */ + +/* Just a little check that someone hasn't tried to define something + * contradictory. + */ +#if (PNG_ZBUF_SIZE > 65536L) && defined(PNG_MAX_MALLOC_64K) +# undef PNG_ZBUF_SIZE +# define PNG_ZBUF_SIZE 65536L +#endif + + +/* Added at libpng-1.2.8 */ +#endif /* PNG_VERSION_INFO_ONLY */ + +#endif /* PNGCONF_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libs/png/zconf.h b/gdcm/Utilities/gdcmopenjpeg-v1/libs/png/zconf.h new file mode 100644 index 0000000..03a9431 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libs/png/zconf.h @@ -0,0 +1,332 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + */ +#ifdef Z_PREFIX +# define deflateInit_ z_deflateInit_ +# define deflate z_deflate +# define deflateEnd z_deflateEnd +# define inflateInit_ z_inflateInit_ +# define inflate z_inflate +# define inflateEnd z_inflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateSetDictionary z_deflateSetDictionary +# define deflateCopy z_deflateCopy +# define deflateReset z_deflateReset +# define deflateParams z_deflateParams +# define deflateBound z_deflateBound +# define deflatePrime z_deflatePrime +# define inflateInit2_ z_inflateInit2_ +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateCopy z_inflateCopy +# define inflateReset z_inflateReset +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# define uncompress z_uncompress +# define adler32 z_adler32 +# define crc32 z_crc32 +# define get_crc_table z_get_crc_table +# define zError z_zError + +# define alloc_func z_alloc_func +# define free_func z_free_func +# define in_func z_in_func +# define out_func z_out_func +# define Byte z_Byte +# define uInt z_uInt +# define uLong z_uLong +# define Bytef z_Bytef +# define charf z_charf +# define intf z_intf +# define uIntf z_uIntf +# define uLongf z_uLongf +# define voidpf z_voidpf +# define voidp z_voidp +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */ +# include /* for off_t */ +# include /* for SEEK_* and off_t */ +# ifdef VMS +# include /* for off_t */ +# endif +# define z_off_t off_t +#endif +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif +#ifndef z_off_t +# define z_off_t long +#endif + +#if defined(__OS400__) +# define NO_vsnprintf +#endif + +#if defined(__MVS__) +# define NO_vsnprintf +# ifdef FAR +# undef FAR +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) +# pragma map(deflateInit_,"DEIN") +# pragma map(deflateInit2_,"DEIN2") +# pragma map(deflateEnd,"DEEND") +# pragma map(deflateBound,"DEBND") +# pragma map(inflateInit_,"ININ") +# pragma map(inflateInit2_,"ININ2") +# pragma map(inflateEnd,"INEND") +# pragma map(inflateSync,"INSY") +# pragma map(inflateSetDictionary,"INSEDI") +# pragma map(compressBound,"CMBND") +# pragma map(inflate_table,"INTABL") +# pragma map(inflate_fast,"INFA") +# pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libs/png/zlib.h b/gdcm/Utilities/gdcmopenjpeg-v1/libs/png/zlib.h new file mode 100644 index 0000000..0228179 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/libs/png/zlib.h @@ -0,0 +1,1357 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.3, July 18th, 2005 + + Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.2.3" +#define ZLIB_VERNUM 0x1230 + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed + data. This version of the library supports only one compression method + (deflation) but other algorithms will be added later and will have the same + stream interface. + + Compression can be done in a single step if the buffers are large + enough (for example if an input file is mmap'ed), or can be done by + repeated calls of the compression function. In the latter case, the + application must provide more input and/or consume the output + (providing more output space) before each call. + + The compressed data format used by default by the in-memory functions is + the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped + around a deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + This library can optionally read and write gzip streams in memory as well. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never + crash even in case of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total nb of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total nb of bytes output so far */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: binary or text */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + gzip header information passed to and from zlib routines. See RFC 1952 + for more details on the meanings of these fields. +*/ +typedef struct gz_header_s { + int text; /* true if compressed data believed to be text */ + uLong time; /* modification time */ + int xflags; /* extra flags (not used when writing a gzip file) */ + int os; /* operating system */ + Bytef *extra; /* pointer to extra field or Z_NULL if none */ + uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ + uInt extra_max; /* space at extra (only when reading header) */ + Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ + uInt name_max; /* space at name (only when reading header) */ + Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ + uInt comm_max; /* space at comment (only when reading header) */ + int hcrc; /* true if there was or will be a header crc */ + int done; /* true when done reading gzip header (not used + when writing a gzip file) */ +} gz_header; + +typedef gz_header FAR *gz_headerp; + +/* + The application must update next_in and avail_in when avail_in has + dropped to zero. It must update next_out and avail_out when avail_out + has dropped to zero. The application must initialize zalloc, zfree and + opaque before calling the init function. All other fields are set by the + compression library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this + if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, + pointers returned by zalloc for objects of exactly 65536 bytes *must* + have their offset normalized to zero. The default allocation function + provided by this library ensures this (see zutil.c). To reduce memory + requirements and avoid any allocation of 64K objects, at the expense of + compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or + progress reports. After compression, total_in holds the total size of + the uncompressed data and may be saved for use in the decompressor + (particularly if the decompressor wants to decompress everything in + a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +/* Allowed flush values; see deflate() and inflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative + * values are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_FIXED 4 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_TEXT 1 +#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ +#define Z_UNKNOWN 2 +/* Possible values of the data_type field (though see inflate()) */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is + not compatible with the zlib.h header file used by the application. + This check is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. + If zalloc and zfree are set to Z_NULL, deflateInit updates them to + use default allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at + all (the input data is simply copied a block at a time). + Z_DEFAULT_COMPRESSION requests a default compromise between speed and + compression (currently equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if level is not a valid compression level, + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). + msg is set to null if there is no error message. deflateInit does not + perform any compression: this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce some + output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). + Some output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating avail_in or avail_out accordingly; avail_out + should never be zero before the call. The application can consume the + compressed output when it wants, for example when the output buffer is full + (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK + and with zero avail_out, it must be called again after making room in the + output buffer because there might be more output pending. + + Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to + decide how much data to accumualte before producing output, in order to + maximize compression. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In particular + avail_in is zero after the call if enough output space has been provided + before the call.) Flushing may degrade compression for some compression + algorithms and so it should be used only when necessary. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six to avoid repeated flush markers due to + avail_out == 0 on return. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there + was enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the + stream are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least + the value returned by deflateBound (see below). If deflate does not return + Z_STREAM_END, then it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so far (that is, total_in bytes). + + deflate() may update strm->data_type if it can make a good guess about + the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered + binary. This field is only for information purposes and does not affect + the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not + fatal, and deflate() can be called again with more input and more output + space to continue compressing. +*/ + + +ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, + msg may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the exact + value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller. msg is set to null if there is no error + message. inflateInit does not perform any decompression apart from reading + the zlib header if present: this will be done by inflate(). (So next_in and + avail_in may be modified, but next_out and avail_out are unchanged.) +*/ + + +ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing + will resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there + is no more input data or no more space in the output buffer (see below + about the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating the next_* and avail_* values accordingly. + The application can consume the uncompressed output when it wants, for + example when the output buffer is full (avail_out == 0), or after each + call of inflate(). If inflate returns Z_OK and with zero avail_out, it + must be called again after making room in the output buffer because there + might be more output pending. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, + Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() stop + if and when it gets to the next deflate block boundary. When decoding the + zlib or gzip format, this will cause inflate() to return immediately after + the header and before the first block. When doing a raw inflate, inflate() + will go ahead and process the first block, and will return when it gets to + the end of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + Also to assist in this, on return inflate() will set strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 + if inflate() is currently decoding the last block in the deflate stream, + plus 128 if inflate() returned immediately after decoding an end-of-block + code or decoding the complete header up to just before the first byte of the + deflate stream. The end-of-block will not be indicated until all of the + uncompressed data from that block has been written to strm->next_out. The + number of unused bits may in general be greater than seven, except when + bit 7 of data_type is set, in which case the number of unused bits will be + less than eight. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step + (a single call of inflate), the parameter flush should be set to + Z_FINISH. In this case all pending input is processed and all pending + output is flushed; avail_out must be large enough to hold all the + uncompressed data. (The size of the uncompressed data may have been saved + by the compressor for this purpose.) The next operation on this stream must + be inflateEnd to deallocate the decompression state. The use of Z_FINISH + is never required, but can be used to inform inflate that a faster approach + may be used for the single inflate() call. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the only effect of the flush parameter in this implementation + is on the return value of inflate(), as noted below, or when it returns early + because Z_BLOCK is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm->adler to the adler32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the adler32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed adler32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() will decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically. Any information + contained in the gzip header is not retained, so applications that need that + information should instead use raw inflate, see inflateInit2() below, or + inflateBack() and perform their own processing of the gzip header and + trailer. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect check + value), Z_STREAM_ERROR if the stream structure was inconsistent (for example + if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory, + Z_BUF_ERROR if no progress is possible or if there was not enough room in the + output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may then + call inflateSync() to look for a good compression block if a partial recovery + of the data is desired. +*/ + + +ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by + the caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute an adler32 check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), + no header crc, and the operating system will be set to 255 (unknown). If a + gzip stream is being written, strm->adler is a crc32 instead of an adler32. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but + is slow and reduces compression ratio; memLevel=9 uses maximum memory + for optimal speed. The default value is 8. See zconf.h for total memory + usage as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as + Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy + parameter only affects the compression ratio but not the correctness of the + compressed output even if it is not set appropriately. Z_FIXED prevents the + use of dynamic Huffman codes, allowing for a simpler decoder for special + applications. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid + method). msg is set to null if there is no error message. deflateInit2 does + not perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. This function must be called + immediately after deflateInit, deflateInit2 or deflateReset, before any + call of deflate. The compressor and decompressor must use exactly the same + dictionary (see inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size in + deflate or deflate2. Thus the strings most likely to be useful should be + put at the end of the dictionary, not at the front. In addition, the + current implementation of deflate will use at most the window size minus + 262 bytes of the provided dictionary. + + Upon return of this function, strm->adler is set to the adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) If a raw deflate was requested, then the + adler32 value is not computed and strm->adler is not set. + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if the compression method is bsort). deflateSetDictionary does not + perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and + can consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. + The stream will keep the same compression level and any other attributes + that may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different + strategy. If the compression level is changed, the input available so far + is compressed with the old level (and may be flushed); the new level will + take effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to + be compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR + if strm->avail_out was zero. +*/ + +ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, + int good_length, + int max_lazy, + int nice_length, + int max_chain)); +/* + Fine tune deflate's internal compression parameters. This should only be + used by someone who understands the algorithm used by zlib's deflate for + searching for the best matching string, and even then only by the most + fanatic optimizer trying to squeeze out the last compressed bit for their + specific input data. Read the deflate.c source code for the meaning of the + max_lazy, good_length, nice_length, and max_chain parameters. + + deflateTune() can be called after deflateInit() or deflateInit2(), and + returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. + */ + +ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, + uLong sourceLen)); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() + or deflateInit2(). This would be used to allocate an output buffer + for deflation in a single pass, and so would be called before deflate(). +*/ + +ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the + bits leftover from a previous deflate stream when appending to it. As such, + this function can only be used for raw deflate, and must be used before the + first deflate() call after a deflateInit2() or deflateReset(). bits must be + less than or equal to 16, and that many of the least significant bits of + value will be inserted in the output. + + deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, + gz_headerp head)); +/* + deflateSetHeader() provides gzip header information for when a gzip + stream is requested by deflateInit2(). deflateSetHeader() may be called + after deflateInit2() or deflateReset() and before the first call of + deflate(). The text, time, os, extra field, name, and comment information + in the provided gz_header structure are written to the gzip header (xflag is + ignored -- the extra flags are set according to the compression level). The + caller must assure that, if not Z_NULL, name and comment are terminated with + a zero byte, and that if extra is not Z_NULL, that extra_len bytes are + available there. If hcrc is true, a gzip header crc is included. Note that + the current versions of the command-line version of gzip (up through version + 1.3.x) do not support header crc's, and will report that it is a "multi-part + gzip file" and give up. + + If deflateSetHeader is not used, the default gzip header has text false, + the time set to zero, and os set to 255, with no extra, name, or comment + fields. The gzip header is returned to the default state by deflateReset(). + + deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an adler32 or a crc32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is + a crc32 instead of an adler32. + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as a null strm). msg + is set to null if there is no error message. inflateInit2 does not perform + any decompression apart from reading the zlib header if present: this will + be done by inflate(). (So next_in and avail_in may be modified, but next_out + and avail_out are unchanged.) +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate, + if that call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the adler32 value returned by that call of inflate. + The compressor and decompressor must use exactly the same dictionary (see + deflateSetDictionary). For raw inflate, this function can be called + immediately after inflateInit2() or inflateReset() and before any call of + inflate() to set the dictionary. The application must insure that the + dictionary that was used for compression is provided. + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a full flush point (see above the + description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR + if no more input was provided, Z_DATA_ERROR if no flush point has been found, + or Z_STREAM_ERROR if the stream structure was inconsistent. In the success + case, the application may save the current current value of total_in which + indicates where valid compressed data was found. In the error case, the + application may repeatedly call inflateSync, providing more input each time, + until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. + The stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + This function inserts bits in the inflate input stream. The intent is + that this function is used to start inflating at a bit position in the + middle of a byte. The provided bits will be used before any bytes are used + from next_in. This function should only be used with raw inflate, and + should be used before the first inflate() call after inflateInit2() or + inflateReset(). bits must be less than or equal to 16, and that many of the + least significant bits of value will be inserted in the input. + + inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, + gz_headerp head)); +/* + inflateGetHeader() requests that gzip header information be stored in the + provided gz_header structure. inflateGetHeader() may be called after + inflateInit2() or inflateReset(), and before the first call of inflate(). + As inflate() processes the gzip stream, head->done is zero until the header + is completed, at which time head->done is set to one. If a zlib stream is + being decoded, then head->done is set to -1 to indicate that there will be + no gzip header information forthcoming. Note that Z_BLOCK can be used to + force inflate() to return immediately after header processing is complete + and before any actual data is decompressed. + + The text, time, xflags, and os fields are filled in with the gzip header + contents. hcrc is set to true if there is a header CRC. (The header CRC + was valid if done is set to one.) If extra is not Z_NULL, then extra_max + contains the maximum number of bytes to write to extra. Once done is true, + extra_len contains the actual extra field length, and extra contains the + extra field, or that field truncated if extra_max is less than extra_len. + If name is not Z_NULL, then up to name_max characters are written there, + terminated with a zero unless the length is greater than name_max. If + comment is not Z_NULL, then up to comm_max characters are written there, + terminated with a zero unless the length is greater than comm_max. When + any of extra, name, or comment are not Z_NULL and the respective field is + not present in the header, then that field is set to Z_NULL to signal its + absence. This allows the use of deflateSetHeader() with the returned + structure to duplicate the header. However if those fields are set to + allocated memory, then the application will need to save those pointers + elsewhere so that they can be eventually freed. + + If inflateGetHeader is not used, then the header information is simply + discarded. The header is always checked for validity, including the header + CRC if present. inflateReset() will reset the process to discard the header + information. The application would need to call inflateGetHeader() again to + retrieve the header from the next gzip stream. + + inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, + unsigned char FAR *window)); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the paramaters are invalid, Z_MEM_ERROR if the internal state could not + be allocated, or Z_VERSION_ERROR if the version of the library does not + match the version of the header file. +*/ + +typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); +typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); + +ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is more efficient than inflate() for + file i/o applications in that it avoids copying between the output and the + sliding window by simply making the window itself the output buffer. This + function trusts the application to not change the output buffer passed by + the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free + the allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects + only the raw deflate stream to decompress. This is different from the + normal behavior of inflate(), which expects either a zlib or gzip header and + trailer around the deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero--buf is ignored in that + case--and inflateBack() will return a buffer error. inflateBack() will call + out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() + should return zero on success, or non-zero on failure. If out() returns + non-zero, inflateBack() will return with an error. Neither in() nor out() + are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format + error in the deflate stream (in which case strm->msg is set to indicate the + nature of the error), or Z_STREAM_ERROR if the stream was not properly + initialized. In the case of Z_BUF_ERROR, an input or output error can be + distinguished using strm->next_in which will be Z_NULL only if in() returned + an error. If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to + out() returning non-zero. (in() will always be called before out(), so + strm->next_in is assured to be defined if out() returns non-zero.) Note + that inflateBack() cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + + + /* utility functions */ + +/* + The following utility functions are implemented on top of the + basic stream-oriented functions. To simplify the interface, some + default options are assumed (compression level and memory usage, + standard memory allocation functions). The source code of these + utility functions can easily be modified if you need special options. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be at least the value returned + by compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + This function can be used to compress a whole file at once if the + input file is mmap'ed. + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before + a compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. +*/ + + +typedef voidp gzFile; + +ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); +/* + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb") but can also include a compression level + ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for + Huffman only compression as in "wb1h", or 'R' for run-length encoding + as in "wb1R". (See the description of deflateInit2 for more information + about the strategy parameter.) + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. + + gzopen returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). */ + +ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +/* + gzdopen() associates a gzFile with the file descriptor fd. File + descriptors are obtained from calls like open, dup, creat, pipe or + fileno (in the file has been previously opened with fopen). + The mode parameter is as in gzopen. + The next call of gzclose on the returned gzFile will also close the + file descriptor fd, just like fclose(fdopen(fd), mode) closes the file + descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). + gzdopen returns NULL if there was insufficient memory to allocate + the (de)compression state. +*/ + +ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. + If the input file was not in gzip format, gzread copies the given number + of bytes into the buffer. + gzread returns the number of uncompressed bytes actually read (0 for + end of file, -1 for error). */ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + voidpc buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes actually written + (0 in case of error). +*/ + +ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). The number of + uncompressed bytes written is limited to 4095. The caller should assure that + this limit is not exceeded. If it is exceeded, then gzprintf() will return + return an error (0) with nothing written. In this case, there may also be a + buffer overflow with unpredictable consequences, which is possible only if + zlib was compiled with the insecure functions sprintf() or vsprintf() + because the secure snprintf() or vsnprintf() functions were not available. +*/ + +ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or + a newline character is read and transferred to buf, or an end-of-file + condition is encountered. The string is then terminated with a null + character. + gzgets returns buf, or Z_NULL in case of error. +*/ + +ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ + +ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +/* + Push one character back onto the stream to be read again later. + Only one character of push-back is allowed. gzungetc() returns the + character pushed, or -1 on failure. gzungetc() will fail if a + character has been pushed but not read yet, or if c is -1. The pushed + character will be discarded if the stream is repositioned with gzseek() + or gzrewind(). +*/ + +ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. The return value is the zlib + error number (see function gzerror below). gzflush returns Z_OK if + the flush parameter is Z_FINISH and all output could be flushed. + gzflush should be called only when strictly necessary because it can + degrade compression. +*/ + +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t offset, int whence)); +/* + Sets the starting position for the next gzread or gzwrite on the + given compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); +/* + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ + +ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); +/* + Returns 1 if file is being read directly without decompression, otherwise + zero. +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. The return value is the zlib + error number (see function gzerror below). +*/ + +ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ + +ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +/* + Clears the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the + compression library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is NULL, this function returns + the required initial value for the checksum. + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, + z_off_t len2)); +/* + Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 + and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for + each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of + seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running CRC-32 with the bytes buf[0..len-1] and return the + updated CRC-32. If buf is NULL, this function returns the required initial + value for the for the crc. Pre- and post-conditioning (one's complement) is + performed within this function so it shouldn't be done by the application. + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + +ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); + +/* + Combine two CRC-32 check values into one. For two sequences of bytes, + seq1 and seq2 with lengths len1 and len2, CRC-32 check values were + calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 + check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and + len2. +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size)); +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) +#define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, sizeof(z_stream)) + + +#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) + struct internal_state {int dummy;}; /* hack for buggy compilers */ +#endif + +ZEXTERN const char * ZEXPORT zError OF((int)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z)); +ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/libs/png/zlib.lib b/gdcm/Utilities/gdcmopenjpeg-v1/libs/png/zlib.lib new file mode 100644 index 0000000000000000000000000000000000000000..f534e8f1cb171f38ef2ccc140ba23a60a7934962 GIT binary patch literal 240696 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 literal 0 HcmV?d00001 diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/ltmain.sh b/gdcm/Utilities/gdcmopenjpeg-v1/ltmain.sh new file mode 100644 index 0000000..be43f41 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/ltmain.sh @@ -0,0 +1,8750 @@ +# Generated from ltmain.m4sh. + +# libtool (GNU libtool) 2.2.8 +# Written by Gordon Matzigkeit , 1996 + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, +# 2007, 2008, 2009, 2010 Free Software Foundation, Inc. +# This is free software; see the source for copying conditions. There is NO +# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +# GNU Libtool is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from http://www.gnu.org/licenses/gpl.html, +# or obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +# Usage: $progname [OPTION]... [MODE-ARG]... +# +# Provide generalized library-building support services. +# +# --config show all configuration variables +# --debug enable verbose shell tracing +# -n, --dry-run display commands without modifying any files +# --features display basic configuration information and exit +# --mode=MODE use operation mode MODE +# --preserve-dup-deps don't remove duplicate dependency libraries +# --quiet, --silent don't print informational messages +# --no-quiet, --no-silent +# print informational messages (default) +# --tag=TAG use configuration variables from tag TAG +# -v, --verbose print more informational messages than default +# --no-verbose don't print the extra informational messages +# --version print version information +# -h, --help, --help-all print short, long, or detailed help message +# +# MODE must be one of the following: +# +# clean remove files from the build directory +# compile compile a source file into a libtool object +# execute automatically set library path, then run a program +# finish complete the installation of libtool libraries +# install install libraries or executables +# link create a library or an executable +# uninstall remove libraries from an installed directory +# +# MODE-ARGS vary depending on the MODE. When passed as first option, +# `--mode=MODE' may be abbreviated as `MODE' or a unique abbreviation of that. +# Try `$progname --help --mode=MODE' for a more detailed description of MODE. +# +# When reporting a bug, please describe a test case to reproduce it and +# include the following information: +# +# host-triplet: $host +# shell: $SHELL +# compiler: $LTCC +# compiler flags: $LTCFLAGS +# linker: $LD (gnu? $with_gnu_ld) +# $progname: (GNU libtool) 2.2.8 +# automake: $automake_version +# autoconf: $autoconf_version +# +# Report bugs to . + +PROGRAM=libtool +PACKAGE=libtool +VERSION=2.2.8 +TIMESTAMP="" +package_revision=1.3169 + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac +fi +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +$1 +_LTECHO_EOF' +} + +# NLS nuisances: We save the old values to restore during execute mode. +lt_user_locale= +lt_safe_locale= +for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES +do + eval "if test \"\${$lt_var+set}\" = set; then + save_$lt_var=\$$lt_var + $lt_var=C + export $lt_var + lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\" + lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\" + fi" +done +LC_ALL=C +LANGUAGE=C +export LANGUAGE LC_ALL + +$lt_unset CDPATH + + + + + + +# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh +# is ksh but when the shell is invoked as "sh" and the current value of +# the _XPG environment variable is not equal to 1 (one), the special +# positional parameter $0, within a function call, is the name of the +# function. +progpath="$0" + + + +: ${CP="cp -f"} +test "${ECHO+set}" = set || ECHO=${as_echo-'printf %s\n'} +: ${EGREP="grep -E"} +: ${FGREP="grep -F"} +: ${GREP="grep"} +: ${LN_S="ln -s"} +: ${MAKE="make"} +: ${MKDIR="mkdir"} +: ${MV="mv -f"} +: ${RM="rm -f"} +: ${SED="sed"} +: ${SHELL="${CONFIG_SHELL-/bin/sh}"} +: ${Xsed="$SED -e 1s/^X//"} + +# Global variables: +EXIT_SUCCESS=0 +EXIT_FAILURE=1 +EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing. +EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake. + +exit_status=$EXIT_SUCCESS + +# Make sure IFS has a sensible default +lt_nl=' +' +IFS=" $lt_nl" + +dirname="s,/[^/]*$,," +basename="s,^.*/,," + +# func_dirname_and_basename file append nondir_replacement +# perform func_basename and func_dirname in a single function +# call: +# dirname: Compute the dirname of FILE. If nonempty, +# add APPEND to the result, otherwise set result +# to NONDIR_REPLACEMENT. +# value returned in "$func_dirname_result" +# basename: Compute filename of FILE. +# value retuned in "$func_basename_result" +# Implementation must be kept synchronized with func_dirname +# and func_basename. For efficiency, we do not delegate to +# those functions but instead duplicate the functionality here. +func_dirname_and_basename () +{ + # Extract subdirectory from the argument. + func_dirname_result=`$ECHO "${1}" | $SED -e "$dirname"` + if test "X$func_dirname_result" = "X${1}"; then + func_dirname_result="${3}" + else + func_dirname_result="$func_dirname_result${2}" + fi + func_basename_result=`$ECHO "${1}" | $SED -e "$basename"` +} + +# Generated shell functions inserted here. + +# These SED scripts presuppose an absolute path with a trailing slash. +pathcar='s,^/\([^/]*\).*$,\1,' +pathcdr='s,^/[^/]*,,' +removedotparts=':dotsl + s@/\./@/@g + t dotsl + s,/\.$,/,' +collapseslashes='s@/\{1,\}@/@g' +finalslash='s,/*$,/,' + +# func_normal_abspath PATH +# Remove doubled-up and trailing slashes, "." path components, +# and cancel out any ".." path components in PATH after making +# it an absolute path. +# value returned in "$func_normal_abspath_result" +func_normal_abspath () +{ + # Start from root dir and reassemble the path. + func_normal_abspath_result= + func_normal_abspath_tpath=$1 + func_normal_abspath_altnamespace= + case $func_normal_abspath_tpath in + "") + # Empty path, that just means $cwd. + func_stripname '' '/' "`pwd`" + func_normal_abspath_result=$func_stripname_result + return + ;; + # The next three entries are used to spot a run of precisely + # two leading slashes without using negated character classes; + # we take advantage of case's first-match behaviour. + ///*) + # Unusual form of absolute path, do nothing. + ;; + //*) + # Not necessarily an ordinary path; POSIX reserves leading '//' + # and for example Cygwin uses it to access remote file shares + # over CIFS/SMB, so we conserve a leading double slash if found. + func_normal_abspath_altnamespace=/ + ;; + /*) + # Absolute path, do nothing. + ;; + *) + # Relative path, prepend $cwd. + func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath + ;; + esac + # Cancel out all the simple stuff to save iterations. We also want + # the path to end with a slash for ease of parsing, so make sure + # there is one (and only one) here. + func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$removedotparts" -e "$collapseslashes" -e "$finalslash"` + while :; do + # Processed it all yet? + if test "$func_normal_abspath_tpath" = / ; then + # If we ascended to the root using ".." the result may be empty now. + if test -z "$func_normal_abspath_result" ; then + func_normal_abspath_result=/ + fi + break + fi + func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$pathcar"` + func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$pathcdr"` + # Figure out what to do with it + case $func_normal_abspath_tcomponent in + "") + # Trailing empty path component, ignore it. + ;; + ..) + # Parent dir; strip last assembled component from result. + func_dirname "$func_normal_abspath_result" + func_normal_abspath_result=$func_dirname_result + ;; + *) + # Actual path component, append it. + func_normal_abspath_result=$func_normal_abspath_result/$func_normal_abspath_tcomponent + ;; + esac + done + # Restore leading double-slash if one was found on entry. + func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result +} + +# func_relative_path SRCDIR DSTDIR +# generates a relative path from SRCDIR to DSTDIR, with a trailing +# slash if non-empty, suitable for immediately appending a filename +# without needing to append a separator. +# value returned in "$func_relative_path_result" +func_relative_path () +{ + func_relative_path_result= + func_normal_abspath "$1" + func_relative_path_tlibdir=$func_normal_abspath_result + func_normal_abspath "$2" + func_relative_path_tbindir=$func_normal_abspath_result + + # Ascend the tree starting from libdir + while :; do + # check if we have found a prefix of bindir + case $func_relative_path_tbindir in + $func_relative_path_tlibdir) + # found an exact match + func_relative_path_tcancelled= + break + ;; + $func_relative_path_tlibdir*) + # found a matching prefix + func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir" + func_relative_path_tcancelled=$func_stripname_result + if test -z "$func_relative_path_result"; then + func_relative_path_result=. + fi + break + ;; + *) + func_dirname $func_relative_path_tlibdir + func_relative_path_tlibdir=${func_dirname_result} + if test "x$func_relative_path_tlibdir" = x ; then + # Have to descend all the way to the root! + func_relative_path_result=../$func_relative_path_result + func_relative_path_tcancelled=$func_relative_path_tbindir + break + fi + func_relative_path_result=../$func_relative_path_result + ;; + esac + done + + # Now calculate path; take care to avoid doubling-up slashes. + func_stripname '' '/' "$func_relative_path_result" + func_relative_path_result=$func_stripname_result + func_stripname '/' '/' "$func_relative_path_tcancelled" + if test "x$func_stripname_result" != x ; then + func_relative_path_result=${func_relative_path_result}/${func_stripname_result} + fi + + # Normalisation. If bindir is libdir, return empty string, + # else relative path ending with a slash; either way, target + # file name can be directly appended. + if test ! -z "$func_relative_path_result"; then + func_stripname './' '' "$func_relative_path_result/" + func_relative_path_result=$func_stripname_result + fi +} + +# The name of this program: +func_dirname_and_basename "$progpath" +progname=$func_basename_result + +# Make sure we have an absolute path for reexecution: +case $progpath in + [\\/]*|[A-Za-z]:\\*) ;; + *[\\/]*) + progdir=$func_dirname_result + progdir=`cd "$progdir" && pwd` + progpath="$progdir/$progname" + ;; + *) + save_IFS="$IFS" + IFS=: + for progdir in $PATH; do + IFS="$save_IFS" + test -x "$progdir/$progname" && break + done + IFS="$save_IFS" + test -n "$progdir" || progdir=`pwd` + progpath="$progdir/$progname" + ;; +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed="${SED}"' -e 1s/^X//' +sed_quote_subst='s/\([`"$\\]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\(["`\\]\)/\\\1/g' + +# Re-`\' parameter expansions in output of double_quote_subst that were +# `\'-ed in input to the same. If an odd number of `\' preceded a '$' +# in input to double_quote_subst, that '$' was protected from expansion. +# Since each input `\' is now two `\'s, look for any number of runs of +# four `\'s followed by two `\'s and then a '$'. `\' that '$'. +bs='\\' +bs2='\\\\' +bs4='\\\\\\\\' +dollar='\$' +sed_double_backslash="\ + s/$bs4/&\\ +/g + s/^$bs2$dollar/$bs&/ + s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g + s/\n//g" + +# Standard options: +opt_dry_run=false +opt_help=false +opt_quiet=false +opt_verbose=false +opt_warning=: + +# func_echo arg... +# Echo program name prefixed message, along with the current mode +# name if it has been set yet. +func_echo () +{ + $ECHO "$progname${mode+: }$mode: $*" +} + +# func_verbose arg... +# Echo program name prefixed message in verbose mode only. +func_verbose () +{ + $opt_verbose && func_echo ${1+"$@"} + + # A bug in bash halts the script if the last line of a function + # fails when set -e is in force, so we need another command to + # work around that: + : +} + +# func_echo_all arg... +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "$*" +} + +# func_error arg... +# Echo program name prefixed message to standard error. +func_error () +{ + $ECHO "$progname${mode+: }$mode: "${1+"$@"} 1>&2 +} + +# func_warning arg... +# Echo program name prefixed warning message to standard error. +func_warning () +{ + $opt_warning && $ECHO "$progname${mode+: }$mode: warning: "${1+"$@"} 1>&2 + + # bash bug again: + : +} + +# func_fatal_error arg... +# Echo program name prefixed message to standard error, and exit. +func_fatal_error () +{ + func_error ${1+"$@"} + exit $EXIT_FAILURE +} + +# func_fatal_help arg... +# Echo program name prefixed message to standard error, followed by +# a help hint, and exit. +func_fatal_help () +{ + func_error ${1+"$@"} + func_fatal_error "$help" +} +help="Try \`$progname --help' for more information." ## default + + +# func_grep expression filename +# Check whether EXPRESSION matches any line of FILENAME, without output. +func_grep () +{ + $GREP "$1" "$2" >/dev/null 2>&1 +} + + +# func_mkdir_p directory-path +# Make sure the entire path to DIRECTORY-PATH is available. +func_mkdir_p () +{ + my_directory_path="$1" + my_dir_list= + + if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then + + # Protect directory names starting with `-' + case $my_directory_path in + -*) my_directory_path="./$my_directory_path" ;; + esac + + # While some portion of DIR does not yet exist... + while test ! -d "$my_directory_path"; do + # ...make a list in topmost first order. Use a colon delimited + # list incase some portion of path contains whitespace. + my_dir_list="$my_directory_path:$my_dir_list" + + # If the last portion added has no slash in it, the list is done + case $my_directory_path in */*) ;; *) break ;; esac + + # ...otherwise throw away the child directory and loop + my_directory_path=`$ECHO "$my_directory_path" | $SED -e "$dirname"` + done + my_dir_list=`$ECHO "$my_dir_list" | $SED 's,:*$,,'` + + save_mkdir_p_IFS="$IFS"; IFS=':' + for my_dir in $my_dir_list; do + IFS="$save_mkdir_p_IFS" + # mkdir can fail with a `File exist' error if two processes + # try to create one of the directories concurrently. Don't + # stop in that case! + $MKDIR "$my_dir" 2>/dev/null || : + done + IFS="$save_mkdir_p_IFS" + + # Bail out if we (or some other process) failed to create a directory. + test -d "$my_directory_path" || \ + func_fatal_error "Failed to create \`$1'" + fi +} + + +# func_mktempdir [string] +# Make a temporary directory that won't clash with other running +# libtool processes, and avoids race conditions if possible. If +# given, STRING is the basename for that directory. +func_mktempdir () +{ + my_template="${TMPDIR-/tmp}/${1-$progname}" + + if test "$opt_dry_run" = ":"; then + # Return a directory name, but don't create it in dry-run mode + my_tmpdir="${my_template}-$$" + else + + # If mktemp works, use that first and foremost + my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null` + + if test ! -d "$my_tmpdir"; then + # Failing that, at least try and use $RANDOM to avoid a race + my_tmpdir="${my_template}-${RANDOM-0}$$" + + save_mktempdir_umask=`umask` + umask 0077 + $MKDIR "$my_tmpdir" + umask $save_mktempdir_umask + fi + + # If we're not in dry-run mode, bomb out on failure + test -d "$my_tmpdir" || \ + func_fatal_error "cannot create temporary directory \`$my_tmpdir'" + fi + + $ECHO "$my_tmpdir" +} + + +# func_quote_for_eval arg +# Aesthetically quote ARG to be evaled later. +# This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT +# is double-quoted, suitable for a subsequent eval, whereas +# FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters +# which are still active within double quotes backslashified. +func_quote_for_eval () +{ + case $1 in + *[\\\`\"\$]*) + func_quote_for_eval_unquoted_result=`$ECHO "$1" | $SED "$sed_quote_subst"` ;; + *) + func_quote_for_eval_unquoted_result="$1" ;; + esac + + case $func_quote_for_eval_unquoted_result in + # Double-quote args containing shell metacharacters to delay + # word splitting, command substitution and and variable + # expansion for a subsequent eval. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\"" + ;; + *) + func_quote_for_eval_result="$func_quote_for_eval_unquoted_result" + esac +} + + +# func_quote_for_expand arg +# Aesthetically quote ARG to be evaled later; same as above, +# but do not quote variable references. +func_quote_for_expand () +{ + case $1 in + *[\\\`\"]*) + my_arg=`$ECHO "$1" | $SED \ + -e "$double_quote_subst" -e "$sed_double_backslash"` ;; + *) + my_arg="$1" ;; + esac + + case $my_arg in + # Double-quote args containing shell metacharacters to delay + # word splitting and command substitution for a subsequent eval. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + my_arg="\"$my_arg\"" + ;; + esac + + func_quote_for_expand_result="$my_arg" +} + + +# func_show_eval cmd [fail_exp] +# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is +# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP +# is given, then evaluate it. +func_show_eval () +{ + my_cmd="$1" + my_fail_exp="${2-:}" + + ${opt_silent-false} || { + func_quote_for_expand "$my_cmd" + eval "func_echo $func_quote_for_expand_result" + } + + if ${opt_dry_run-false}; then :; else + eval "$my_cmd" + my_status=$? + if test "$my_status" -eq 0; then :; else + eval "(exit $my_status); $my_fail_exp" + fi + fi +} + + +# func_show_eval_locale cmd [fail_exp] +# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is +# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP +# is given, then evaluate it. Use the saved locale for evaluation. +func_show_eval_locale () +{ + my_cmd="$1" + my_fail_exp="${2-:}" + + ${opt_silent-false} || { + func_quote_for_expand "$my_cmd" + eval "func_echo $func_quote_for_expand_result" + } + + if ${opt_dry_run-false}; then :; else + eval "$lt_user_locale + $my_cmd" + my_status=$? + eval "$lt_safe_locale" + if test "$my_status" -eq 0; then :; else + eval "(exit $my_status); $my_fail_exp" + fi + fi +} + + + +# func_version +# Echo version message to standard output and exit. +func_version () +{ + $SED -n '/(C)/!b go + :more + /\./!{ + N + s/\n# // + b more + } + :go + /^# '$PROGRAM' (GNU /,/# warranty; / { + s/^# // + s/^# *$// + s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/ + p + }' < "$progpath" + exit $? +} + +# func_usage +# Echo short help message to standard output and exit. +func_usage () +{ + $SED -n '/^# Usage:/,/^# *.*--help/ { + s/^# // + s/^# *$// + s/\$progname/'$progname'/ + p + }' < "$progpath" + echo + $ECHO "run \`$progname --help | more' for full usage" + exit $? +} + +# func_help [NOEXIT] +# Echo long help message to standard output and exit, +# unless 'noexit' is passed as argument. +func_help () +{ + $SED -n '/^# Usage:/,/# Report bugs to/ { + s/^# // + s/^# *$// + s*\$progname*'$progname'* + s*\$host*'"$host"'* + s*\$SHELL*'"$SHELL"'* + s*\$LTCC*'"$LTCC"'* + s*\$LTCFLAGS*'"$LTCFLAGS"'* + s*\$LD*'"$LD"'* + s/\$with_gnu_ld/'"$with_gnu_ld"'/ + s/\$automake_version/'"`(automake --version) 2>/dev/null |$SED 1q`"'/ + s/\$autoconf_version/'"`(autoconf --version) 2>/dev/null |$SED 1q`"'/ + p + }' < "$progpath" + ret=$? + if test -z "$1"; then + exit $ret + fi +} + +# func_missing_arg argname +# Echo program name prefixed message to standard error and set global +# exit_cmd. +func_missing_arg () +{ + func_error "missing argument for $1." + exit_cmd=exit +} + +exit_cmd=: + + + + + + +magic="%%%MAGIC variable%%%" +magic_exe="%%%MAGIC EXE variable%%%" + +# Global variables. +# $mode is unset +nonopt= +execute_dlfiles= +preserve_args= +lo2o="s/\\.lo\$/.${objext}/" +o2lo="s/\\.${objext}\$/.lo/" +extracted_archives= +extracted_serial=0 + +opt_dry_run=false +opt_duplicate_deps=false +opt_silent=false +opt_debug=: + +# If this variable is set in any of the actions, the command in it +# will be execed at the end. This prevents here-documents from being +# left over by shells. +exec_cmd= + +# func_fatal_configuration arg... +# Echo program name prefixed message to standard error, followed by +# a configuration failure hint, and exit. +func_fatal_configuration () +{ + func_error ${1+"$@"} + func_error "See the $PACKAGE documentation for more information." + func_fatal_error "Fatal configuration error." +} + + +# func_config +# Display the configuration for all the tags in this script. +func_config () +{ + re_begincf='^# ### BEGIN LIBTOOL' + re_endcf='^# ### END LIBTOOL' + + # Default configuration. + $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath" + + # Now print the configurations for the tags. + for tagname in $taglist; do + $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath" + done + + exit $? +} + +# func_features +# Display the features supported by this script. +func_features () +{ + echo "host: $host" + if test "$build_libtool_libs" = yes; then + echo "enable shared libraries" + else + echo "disable shared libraries" + fi + if test "$build_old_libs" = yes; then + echo "enable static libraries" + else + echo "disable static libraries" + fi + + exit $? +} + +# func_enable_tag tagname +# Verify that TAGNAME is valid, and either flag an error and exit, or +# enable the TAGNAME tag. We also add TAGNAME to the global $taglist +# variable here. +func_enable_tag () +{ + # Global variable: + tagname="$1" + + re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$" + re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$" + sed_extractcf="/$re_begincf/,/$re_endcf/p" + + # Validate tagname. + case $tagname in + *[!-_A-Za-z0-9,/]*) + func_fatal_error "invalid tag name: $tagname" + ;; + esac + + # Don't test for the "default" C tag, as we know it's + # there but not specially marked. + case $tagname in + CC) ;; + *) + if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then + taglist="$taglist $tagname" + + # Evaluate the configuration. Be careful to quote the path + # and the sed script, to avoid splitting on whitespace, but + # also don't use non-portable quotes within backquotes within + # quotes we have to do it in 2 steps: + extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"` + eval "$extractedcf" + else + func_error "ignoring unknown tag $tagname" + fi + ;; + esac +} + +# Parse options once, thoroughly. This comes as soon as possible in +# the script to make things like `libtool --version' happen quickly. +{ + + # Shorthand for --mode=foo, only valid as the first argument + case $1 in + clean|clea|cle|cl) + shift; set dummy --mode clean ${1+"$@"}; shift + ;; + compile|compil|compi|comp|com|co|c) + shift; set dummy --mode compile ${1+"$@"}; shift + ;; + execute|execut|execu|exec|exe|ex|e) + shift; set dummy --mode execute ${1+"$@"}; shift + ;; + finish|finis|fini|fin|fi|f) + shift; set dummy --mode finish ${1+"$@"}; shift + ;; + install|instal|insta|inst|ins|in|i) + shift; set dummy --mode install ${1+"$@"}; shift + ;; + link|lin|li|l) + shift; set dummy --mode link ${1+"$@"}; shift + ;; + uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) + shift; set dummy --mode uninstall ${1+"$@"}; shift + ;; + esac + + # Parse non-mode specific arguments: + while test "$#" -gt 0; do + opt="$1" + shift + + case $opt in + --config) func_config ;; + + --debug) preserve_args="$preserve_args $opt" + func_echo "enabling shell trace mode" + opt_debug='set -x' + $opt_debug + ;; + + -dlopen) test "$#" -eq 0 && func_missing_arg "$opt" && break + execute_dlfiles="$execute_dlfiles $1" + shift + ;; + + --dry-run | -n) opt_dry_run=: ;; + --features) func_features ;; + --finish) mode="finish" ;; + + --mode) test "$#" -eq 0 && func_missing_arg "$opt" && break + case $1 in + # Valid mode arguments: + clean) ;; + compile) ;; + execute) ;; + finish) ;; + install) ;; + link) ;; + relink) ;; + uninstall) ;; + + # Catch anything else as an error + *) func_error "invalid argument for $opt" + exit_cmd=exit + break + ;; + esac + + mode="$1" + shift + ;; + + --preserve-dup-deps) + opt_duplicate_deps=: ;; + + --quiet|--silent) preserve_args="$preserve_args $opt" + opt_silent=: + opt_verbose=false + ;; + + --no-quiet|--no-silent) + preserve_args="$preserve_args $opt" + opt_silent=false + ;; + + --verbose| -v) preserve_args="$preserve_args $opt" + opt_silent=false + opt_verbose=: + ;; + + --no-verbose) preserve_args="$preserve_args $opt" + opt_verbose=false + ;; + + --tag) test "$#" -eq 0 && func_missing_arg "$opt" && break + preserve_args="$preserve_args $opt $1" + func_enable_tag "$1" # tagname is set here + shift + ;; + + # Separate optargs to long options: + -dlopen=*|--mode=*|--tag=*) + func_opt_split "$opt" + set dummy "$func_opt_split_opt" "$func_opt_split_arg" ${1+"$@"} + shift + ;; + + -\?|-h) func_usage ;; + --help) opt_help=: ;; + --help-all) opt_help=': help-all' ;; + --version) func_version ;; + + -*) func_fatal_help "unrecognized option \`$opt'" ;; + + *) nonopt="$opt" + break + ;; + esac + done + + + case $host in + *cygwin* | *mingw* | *pw32* | *cegcc*) + # don't eliminate duplications in $postdeps and $predeps + opt_duplicate_compiler_generated_deps=: + ;; + *) + opt_duplicate_compiler_generated_deps=$opt_duplicate_deps + ;; + esac + + # Having warned about all mis-specified options, bail out if + # anything was wrong. + $exit_cmd $EXIT_FAILURE +} + +# func_check_version_match +# Ensure that we are using m4 macros, and libtool script from the same +# release of libtool. +func_check_version_match () +{ + if test "$package_revision" != "$macro_revision"; then + if test "$VERSION" != "$macro_version"; then + if test -z "$macro_version"; then + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, but the +$progname: definition of this LT_INIT comes from an older release. +$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION +$progname: and run autoconf again. +_LT_EOF + else + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, but the +$progname: definition of this LT_INIT comes from $PACKAGE $macro_version. +$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION +$progname: and run autoconf again. +_LT_EOF + fi + else + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, +$progname: but the definition of this LT_INIT comes from revision $macro_revision. +$progname: You should recreate aclocal.m4 with macros from revision $package_revision +$progname: of $PACKAGE $VERSION and run autoconf again. +_LT_EOF + fi + + exit $EXIT_MISMATCH + fi +} + + +## ----------- ## +## Main. ## +## ----------- ## + +$opt_help || { + # Sanity checks first: + func_check_version_match + + if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then + func_fatal_configuration "not configured to build any kind of library" + fi + + test -z "$mode" && func_fatal_error "error: you must specify a MODE." + + + # Darwin sucks + eval std_shrext=\"$shrext_cmds\" + + + # Only execute mode is allowed to have -dlopen flags. + if test -n "$execute_dlfiles" && test "$mode" != execute; then + func_error "unrecognized option \`-dlopen'" + $ECHO "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Change the help message to a mode-specific one. + generic_help="$help" + help="Try \`$progname --help --mode=$mode' for more information." +} + + +# func_lalib_p file +# True iff FILE is a libtool `.la' library or `.lo' object file. +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_lalib_p () +{ + test -f "$1" && + $SED -e 4q "$1" 2>/dev/null \ + | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 +} + +# func_lalib_unsafe_p file +# True iff FILE is a libtool `.la' library or `.lo' object file. +# This function implements the same check as func_lalib_p without +# resorting to external programs. To this end, it redirects stdin and +# closes it afterwards, without saving the original file descriptor. +# As a safety measure, use it only where a negative result would be +# fatal anyway. Works if `file' does not exist. +func_lalib_unsafe_p () +{ + lalib_p=no + if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then + for lalib_p_l in 1 2 3 4 + do + read lalib_p_line + case "$lalib_p_line" in + \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;; + esac + done + exec 0<&5 5<&- + fi + test "$lalib_p" = yes +} + +# func_ltwrapper_script_p file +# True iff FILE is a libtool wrapper script +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_script_p () +{ + func_lalib_p "$1" +} + +# func_ltwrapper_executable_p file +# True iff FILE is a libtool wrapper executable +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_executable_p () +{ + func_ltwrapper_exec_suffix= + case $1 in + *.exe) ;; + *) func_ltwrapper_exec_suffix=.exe ;; + esac + $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1 +} + +# func_ltwrapper_scriptname file +# Assumes file is an ltwrapper_executable +# uses $file to determine the appropriate filename for a +# temporary ltwrapper_script. +func_ltwrapper_scriptname () +{ + func_ltwrapper_scriptname_result="" + if func_ltwrapper_executable_p "$1"; then + func_dirname_and_basename "$1" "" "." + func_stripname '' '.exe' "$func_basename_result" + func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper" + fi +} + +# func_ltwrapper_p file +# True iff FILE is a libtool wrapper script or wrapper executable +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_p () +{ + func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1" +} + + +# func_execute_cmds commands fail_cmd +# Execute tilde-delimited COMMANDS. +# If FAIL_CMD is given, eval that upon failure. +# FAIL_CMD may read-access the current command in variable CMD! +func_execute_cmds () +{ + $opt_debug + save_ifs=$IFS; IFS='~' + for cmd in $1; do + IFS=$save_ifs + eval cmd=\"$cmd\" + func_show_eval "$cmd" "${2-:}" + done + IFS=$save_ifs +} + + +# func_source file +# Source FILE, adding directory component if necessary. +# Note that it is not necessary on cygwin/mingw to append a dot to +# FILE even if both FILE and FILE.exe exist: automatic-append-.exe +# behavior happens only for exec(3), not for open(2)! Also, sourcing +# `FILE.' does not work on cygwin managed mounts. +func_source () +{ + $opt_debug + case $1 in + */* | *\\*) . "$1" ;; + *) . "./$1" ;; + esac +} + + +# func_infer_tag arg +# Infer tagged configuration to use if any are available and +# if one wasn't chosen via the "--tag" command line option. +# Only attempt this if the compiler in the base compile +# command doesn't match the default compiler. +# arg is usually of the form 'gcc ...' +func_infer_tag () +{ + $opt_debug + if test -n "$available_tags" && test -z "$tagname"; then + CC_quoted= + for arg in $CC; do + func_quote_for_eval "$arg" + CC_quoted="$CC_quoted $func_quote_for_eval_result" + done + CC_expanded=`func_echo_all $CC` + CC_quoted_expanded=`func_echo_all $CC_quoted` + case $@ in + # Blanks in the command may have been stripped by the calling shell, + # but not from the CC environment variable when configure was run. + " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ + " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;; + # Blanks at the start of $base_compile will cause this to fail + # if we don't check for them as well. + *) + for z in $available_tags; do + if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then + # Evaluate the configuration. + eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" + CC_quoted= + for arg in $CC; do + # Double-quote args containing other shell metacharacters. + func_quote_for_eval "$arg" + CC_quoted="$CC_quoted $func_quote_for_eval_result" + done + CC_expanded=`func_echo_all $CC` + CC_quoted_expanded=`func_echo_all $CC_quoted` + case "$@ " in + " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ + " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) + # The compiler in the base compile command matches + # the one in the tagged configuration. + # Assume this is the tagged configuration we want. + tagname=$z + break + ;; + esac + fi + done + # If $tagname still isn't set, then no tagged configuration + # was found and let the user know that the "--tag" command + # line option must be used. + if test -z "$tagname"; then + func_echo "unable to infer tagged configuration" + func_fatal_error "specify a tag with \`--tag'" +# else +# func_verbose "using $tagname tagged configuration" + fi + ;; + esac + fi +} + + + +# func_write_libtool_object output_name pic_name nonpic_name +# Create a libtool object file (analogous to a ".la" file), +# but don't create it if we're doing a dry run. +func_write_libtool_object () +{ + write_libobj=${1} + if test "$build_libtool_libs" = yes; then + write_lobj=\'${2}\' + else + write_lobj=none + fi + + if test "$build_old_libs" = yes; then + write_oldobj=\'${3}\' + else + write_oldobj=none + fi + + $opt_dry_run || { + cat >${write_libobj}T <?"'"'"' &()|`$[]' \ + && func_warning "libobj name \`$libobj' may not contain shell special characters." + func_dirname_and_basename "$obj" "/" "" + objname="$func_basename_result" + xdir="$func_dirname_result" + lobj=${xdir}$objdir/$objname + + test -z "$base_compile" && \ + func_fatal_help "you must specify a compilation command" + + # Delete any leftover library objects. + if test "$build_old_libs" = yes; then + removelist="$obj $lobj $libobj ${libobj}T" + else + removelist="$lobj $libobj ${libobj}T" + fi + + # On Cygwin there's no "real" PIC flag so we must build both object types + case $host_os in + cygwin* | mingw* | pw32* | os2* | cegcc*) + pic_mode=default + ;; + esac + if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then + # non-PIC code in shared libraries is not supported + pic_mode=default + fi + + # Calculate the filename of the output object if compiler does + # not support -o with -c + if test "$compiler_c_o" = no; then + output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.${objext} + lockfile="$output_obj.lock" + else + output_obj= + need_locks=no + lockfile= + fi + + # Lock this critical section if it is needed + # We use this script file to make the link, it avoids creating a new file + if test "$need_locks" = yes; then + until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do + func_echo "Waiting for $lockfile to be removed" + sleep 2 + done + elif test "$need_locks" = warn; then + if test -f "$lockfile"; then + $ECHO "\ +*** ERROR, $lockfile exists and contains: +`cat $lockfile 2>/dev/null` + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + removelist="$removelist $output_obj" + $ECHO "$srcfile" > "$lockfile" + fi + + $opt_dry_run || $RM $removelist + removelist="$removelist $lockfile" + trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 + + if test -n "$fix_srcfile_path"; then + eval srcfile=\"$fix_srcfile_path\" + fi + func_quote_for_eval "$srcfile" + qsrcfile=$func_quote_for_eval_result + + # Only build a PIC object if we are building libtool libraries. + if test "$build_libtool_libs" = yes; then + # Without this assignment, base_compile gets emptied. + fbsd_hideous_sh_bug=$base_compile + + if test "$pic_mode" != no; then + command="$base_compile $qsrcfile $pic_flag" + else + # Don't build PIC code + command="$base_compile $qsrcfile" + fi + + func_mkdir_p "$xdir$objdir" + + if test -z "$output_obj"; then + # Place PIC objects in $objdir + command="$command -o $lobj" + fi + + func_show_eval_locale "$command" \ + 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE' + + if test "$need_locks" = warn && + test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then + $ECHO "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed, then go on to compile the next one + if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then + func_show_eval '$MV "$output_obj" "$lobj"' \ + 'error=$?; $opt_dry_run || $RM $removelist; exit $error' + fi + + # Allow error messages only from the first compilation. + if test "$suppress_opt" = yes; then + suppress_output=' >/dev/null 2>&1' + fi + fi + + # Only build a position-dependent object if we build old libraries. + if test "$build_old_libs" = yes; then + if test "$pic_mode" != yes; then + # Don't build PIC code + command="$base_compile $qsrcfile$pie_flag" + else + command="$base_compile $qsrcfile $pic_flag" + fi + if test "$compiler_c_o" = yes; then + command="$command -o $obj" + fi + + # Suppress compiler output if we already did a PIC compilation. + command="$command$suppress_output" + func_show_eval_locale "$command" \ + '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' + + if test "$need_locks" = warn && + test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then + $ECHO "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed + if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then + func_show_eval '$MV "$output_obj" "$obj"' \ + 'error=$?; $opt_dry_run || $RM $removelist; exit $error' + fi + fi + + $opt_dry_run || { + func_write_libtool_object "$libobj" "$objdir/$objname" "$objname" + + # Unlock the critical section if it was locked + if test "$need_locks" != no; then + removelist=$lockfile + $RM "$lockfile" + fi + } + + exit $EXIT_SUCCESS +} + +$opt_help || { + test "$mode" = compile && func_mode_compile ${1+"$@"} +} + +func_mode_help () +{ + # We need to display help for each of the modes. + case $mode in + "") + # Generic help is extracted from the usage comments + # at the start of this file. + func_help + ;; + + clean) + $ECHO \ +"Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE... + +Remove files from the build directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, object or program, all the files associated +with it are deleted. Otherwise, only FILE itself is deleted using RM." + ;; + + compile) + $ECHO \ +"Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE + +Compile a source file into a libtool library object. + +This mode accepts the following additional options: + + -o OUTPUT-FILE set the output file name to OUTPUT-FILE + -no-suppress do not suppress compiler output for multiple passes + -prefer-pic try to build PIC objects only + -prefer-non-pic try to build non-PIC objects only + -shared do not build a \`.o' file suitable for static linking + -static only build a \`.o' file suitable for static linking + -Wc,FLAG pass FLAG directly to the compiler + +COMPILE-COMMAND is a command to be used in creating a \`standard' object file +from the given SOURCEFILE. + +The output file name is determined by removing the directory component from +SOURCEFILE, then substituting the C source code suffix \`.c' with the +library object suffix, \`.lo'." + ;; + + execute) + $ECHO \ +"Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]... + +Automatically set library path, then run a program. + +This mode accepts the following additional options: + + -dlopen FILE add the directory containing FILE to the library path + +This mode sets the library path environment variable according to \`-dlopen' +flags. + +If any of the ARGS are libtool executable wrappers, then they are translated +into their corresponding uninstalled binary, and any of their required library +directories are added to the library path. + +Then, COMMAND is executed, with ARGS as arguments." + ;; + + finish) + $ECHO \ +"Usage: $progname [OPTION]... --mode=finish [LIBDIR]... + +Complete the installation of libtool libraries. + +Each LIBDIR is a directory that contains libtool libraries. + +The commands that this mode executes may require superuser privileges. Use +the \`--dry-run' option if you just want to see what would be executed." + ;; + + install) + $ECHO \ +"Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND... + +Install executables or libraries. + +INSTALL-COMMAND is the installation command. The first component should be +either the \`install' or \`cp' program. + +The following components of INSTALL-COMMAND are treated specially: + + -inst-prefix-dir PREFIX-DIR Use PREFIX-DIR as a staging area for installation + +The rest of the components are interpreted as arguments to that command (only +BSD-compatible install options are recognized)." + ;; + + link) + $ECHO \ +"Usage: $progname [OPTION]... --mode=link LINK-COMMAND... + +Link object files or libraries together to form another library, or to +create an executable program. + +LINK-COMMAND is a command using the C compiler that you would use to create +a program from several object files. + +The following components of LINK-COMMAND are treated specially: + + -all-static do not do any dynamic linking at all + -avoid-version do not add a version suffix if possible + -bindir BINDIR specify path to binaries directory (for systems where + libraries must be found in the PATH setting at runtime) + -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime + -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols + -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) + -export-symbols SYMFILE + try to export only the symbols listed in SYMFILE + -export-symbols-regex REGEX + try to export only the symbols matching REGEX + -LLIBDIR search LIBDIR for required installed libraries + -lNAME OUTPUT-FILE requires the installed library libNAME + -module build a library that can dlopened + -no-fast-install disable the fast-install mode + -no-install link a not-installable executable + -no-undefined declare that a library does not refer to external symbols + -o OUTPUT-FILE create OUTPUT-FILE from the specified objects + -objectlist FILE Use a list of object files found in FILE to specify objects + -precious-files-regex REGEX + don't remove output files matching REGEX + -release RELEASE specify package release information + -rpath LIBDIR the created library will eventually be installed in LIBDIR + -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries + -shared only do dynamic linking of libtool libraries + -shrext SUFFIX override the standard shared library file extension + -static do not do any dynamic linking of uninstalled libtool libraries + -static-libtool-libs + do not do any dynamic linking of libtool libraries + -version-info CURRENT[:REVISION[:AGE]] + specify library version info [each variable defaults to 0] + -weak LIBNAME declare that the target provides the LIBNAME interface + -Wc,FLAG + -Xcompiler FLAG pass linker-specific FLAG directly to the compiler + -Wl,FLAG + -Xlinker FLAG pass linker-specific FLAG directly to the linker + -XCClinker FLAG pass link-specific FLAG to the compiler driver (CC) + +All other options (arguments beginning with \`-') are ignored. + +Every other argument is treated as a filename. Files ending in \`.la' are +treated as uninstalled libtool libraries, other files are standard or library +object files. + +If the OUTPUT-FILE ends in \`.la', then a libtool library is created, +only library objects (\`.lo' files) may be specified, and \`-rpath' is +required, except when creating a convenience library. + +If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created +using \`ar' and \`ranlib', or on Windows using \`lib'. + +If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file +is created, otherwise an executable program is created." + ;; + + uninstall) + $ECHO \ +"Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... + +Remove libraries from an installation directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, all the files associated with it are deleted. +Otherwise, only FILE itself is deleted using RM." + ;; + + *) + func_fatal_help "invalid operation mode \`$mode'" + ;; + esac + + echo + $ECHO "Try \`$progname --help' for more information about other modes." +} + +# Now that we've collected a possible --mode arg, show help if necessary +if $opt_help; then + if test "$opt_help" = :; then + func_mode_help + else + { + func_help noexit + for mode in compile link execute install finish uninstall clean; do + func_mode_help + done + } | sed -n '1p; 2,$s/^Usage:/ or: /p' + { + func_help noexit + for mode in compile link execute install finish uninstall clean; do + echo + func_mode_help + done + } | + sed '1d + /^When reporting/,/^Report/{ + H + d + } + $x + /information about other modes/d + /more detailed .*MODE/d + s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/' + fi + exit $? +fi + + +# func_mode_execute arg... +func_mode_execute () +{ + $opt_debug + # The first argument is the command name. + cmd="$nonopt" + test -z "$cmd" && \ + func_fatal_help "you must specify a COMMAND" + + # Handle -dlopen flags immediately. + for file in $execute_dlfiles; do + test -f "$file" \ + || func_fatal_help "\`$file' is not a file" + + dir= + case $file in + *.la) + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$file" \ + || func_fatal_help "\`$lib' is not a valid libtool archive" + + # Read the libtool library. + dlname= + library_names= + func_source "$file" + + # Skip this library if it cannot be dlopened. + if test -z "$dlname"; then + # Warn if it was a shared library. + test -n "$library_names" && \ + func_warning "\`$file' was not linked with \`-export-dynamic'" + continue + fi + + func_dirname "$file" "" "." + dir="$func_dirname_result" + + if test -f "$dir/$objdir/$dlname"; then + dir="$dir/$objdir" + else + if test ! -f "$dir/$dlname"; then + func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" + fi + fi + ;; + + *.lo) + # Just add the directory containing the .lo file. + func_dirname "$file" "" "." + dir="$func_dirname_result" + ;; + + *) + func_warning "\`-dlopen' is ignored for non-libtool libraries and objects" + continue + ;; + esac + + # Get the absolute pathname. + absdir=`cd "$dir" && pwd` + test -n "$absdir" && dir="$absdir" + + # Now add the directory to shlibpath_var. + if eval "test -z \"\$$shlibpath_var\""; then + eval "$shlibpath_var=\"\$dir\"" + else + eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" + fi + done + + # This variable tells wrapper scripts just to set shlibpath_var + # rather than running their programs. + libtool_execute_magic="$magic" + + # Check if any of the arguments is a wrapper script. + args= + for file + do + case $file in + -* | *.la | *.lo ) ;; + *) + # Do a test to see if this is really a libtool program. + if func_ltwrapper_script_p "$file"; then + func_source "$file" + # Transform arg to wrapped name. + file="$progdir/$program" + elif func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + func_source "$func_ltwrapper_scriptname_result" + # Transform arg to wrapped name. + file="$progdir/$program" + fi + ;; + esac + # Quote arguments (to preserve shell metacharacters). + func_quote_for_eval "$file" + args="$args $func_quote_for_eval_result" + done + + if test "X$opt_dry_run" = Xfalse; then + if test -n "$shlibpath_var"; then + # Export the shlibpath_var. + eval "export $shlibpath_var" + fi + + # Restore saved environment variables + for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES + do + eval "if test \"\${save_$lt_var+set}\" = set; then + $lt_var=\$save_$lt_var; export $lt_var + else + $lt_unset $lt_var + fi" + done + + # Now prepare to actually exec the command. + exec_cmd="\$cmd$args" + else + # Display what would be done. + if test -n "$shlibpath_var"; then + eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\"" + echo "export $shlibpath_var" + fi + $ECHO "$cmd$args" + exit $EXIT_SUCCESS + fi +} + +test "$mode" = execute && func_mode_execute ${1+"$@"} + + +# func_mode_finish arg... +func_mode_finish () +{ + $opt_debug + libdirs="$nonopt" + admincmds= + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + for dir + do + libdirs="$libdirs $dir" + done + + for libdir in $libdirs; do + if test -n "$finish_cmds"; then + # Do each command in the finish commands. + func_execute_cmds "$finish_cmds" 'admincmds="$admincmds +'"$cmd"'"' + fi + if test -n "$finish_eval"; then + # Do the single finish_eval. + eval cmds=\"$finish_eval\" + $opt_dry_run || eval "$cmds" || admincmds="$admincmds + $cmds" + fi + done + fi + + # Exit here if they wanted silent mode. + $opt_silent && exit $EXIT_SUCCESS + + echo "----------------------------------------------------------------------" + echo "Libraries have been installed in:" + for libdir in $libdirs; do + $ECHO " $libdir" + done + echo + echo "If you ever happen to want to link against installed libraries" + echo "in a given directory, LIBDIR, you must either use libtool, and" + echo "specify the full pathname of the library, or use the \`-LLIBDIR'" + echo "flag during linking and do at least one of the following:" + if test -n "$shlibpath_var"; then + echo " - add LIBDIR to the \`$shlibpath_var' environment variable" + echo " during execution" + fi + if test -n "$runpath_var"; then + echo " - add LIBDIR to the \`$runpath_var' environment variable" + echo " during linking" + fi + if test -n "$hardcode_libdir_flag_spec"; then + libdir=LIBDIR + eval flag=\"$hardcode_libdir_flag_spec\" + + $ECHO " - use the \`$flag' linker flag" + fi + if test -n "$admincmds"; then + $ECHO " - have your system administrator run these commands:$admincmds" + fi + if test -f /etc/ld.so.conf; then + echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" + fi + echo + + echo "See any operating system documentation about shared libraries for" + case $host in + solaris2.[6789]|solaris2.1[0-9]) + echo "more information, such as the ld(1), crle(1) and ld.so(8) manual" + echo "pages." + ;; + *) + echo "more information, such as the ld(1) and ld.so(8) manual pages." + ;; + esac + echo "----------------------------------------------------------------------" + exit $EXIT_SUCCESS +} + +test "$mode" = finish && func_mode_finish ${1+"$@"} + + +# func_mode_install arg... +func_mode_install () +{ + $opt_debug + # There may be an optional sh(1) argument at the beginning of + # install_prog (especially on Windows NT). + if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || + # Allow the use of GNU shtool's install command. + case $nonopt in *shtool*) :;; *) false;; esac; then + # Aesthetically quote it. + func_quote_for_eval "$nonopt" + install_prog="$func_quote_for_eval_result " + arg=$1 + shift + else + install_prog= + arg=$nonopt + fi + + # The real first argument should be the name of the installation program. + # Aesthetically quote it. + func_quote_for_eval "$arg" + install_prog="$install_prog$func_quote_for_eval_result" + install_shared_prog=$install_prog + case " $install_prog " in + *[\\\ /]cp\ *) install_cp=: ;; + *) install_cp=false ;; + esac + + # We need to accept at least all the BSD install flags. + dest= + files= + opts= + prev= + install_type= + isdir=no + stripme= + no_mode=: + for arg + do + arg2= + if test -n "$dest"; then + files="$files $dest" + dest=$arg + continue + fi + + case $arg in + -d) isdir=yes ;; + -f) + if $install_cp; then :; else + prev=$arg + fi + ;; + -g | -m | -o) + prev=$arg + ;; + -s) + stripme=" -s" + continue + ;; + -*) + ;; + *) + # If the previous option needed an argument, then skip it. + if test -n "$prev"; then + if test "x$prev" = x-m && test -n "$install_override_mode"; then + arg2=$install_override_mode + no_mode=false + fi + prev= + else + dest=$arg + continue + fi + ;; + esac + + # Aesthetically quote the argument. + func_quote_for_eval "$arg" + install_prog="$install_prog $func_quote_for_eval_result" + if test -n "$arg2"; then + func_quote_for_eval "$arg2" + fi + install_shared_prog="$install_shared_prog $func_quote_for_eval_result" + done + + test -z "$install_prog" && \ + func_fatal_help "you must specify an install program" + + test -n "$prev" && \ + func_fatal_help "the \`$prev' option requires an argument" + + if test -n "$install_override_mode" && $no_mode; then + if $install_cp; then :; else + func_quote_for_eval "$install_override_mode" + install_shared_prog="$install_shared_prog -m $func_quote_for_eval_result" + fi + fi + + if test -z "$files"; then + if test -z "$dest"; then + func_fatal_help "no file or destination specified" + else + func_fatal_help "you must specify a destination" + fi + fi + + # Strip any trailing slash from the destination. + func_stripname '' '/' "$dest" + dest=$func_stripname_result + + # Check to see that the destination is a directory. + test -d "$dest" && isdir=yes + if test "$isdir" = yes; then + destdir="$dest" + destname= + else + func_dirname_and_basename "$dest" "" "." + destdir="$func_dirname_result" + destname="$func_basename_result" + + # Not a directory, so check to see that there is only one file specified. + set dummy $files; shift + test "$#" -gt 1 && \ + func_fatal_help "\`$dest' is not a directory" + fi + case $destdir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + for file in $files; do + case $file in + *.lo) ;; + *) + func_fatal_help "\`$destdir' must be an absolute directory name" + ;; + esac + done + ;; + esac + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + staticlibs= + future_libdirs= + current_libdirs= + for file in $files; do + + # Do each installation. + case $file in + *.$libext) + # Do the static libraries later. + staticlibs="$staticlibs $file" + ;; + + *.la) + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$file" \ + || func_fatal_help "\`$file' is not a valid libtool archive" + + library_names= + old_library= + relink_command= + func_source "$file" + + # Add the libdir to current_libdirs if it is the destination. + if test "X$destdir" = "X$libdir"; then + case "$current_libdirs " in + *" $libdir "*) ;; + *) current_libdirs="$current_libdirs $libdir" ;; + esac + else + # Note the libdir as a future libdir. + case "$future_libdirs " in + *" $libdir "*) ;; + *) future_libdirs="$future_libdirs $libdir" ;; + esac + fi + + func_dirname "$file" "/" "" + dir="$func_dirname_result" + dir="$dir$objdir" + + if test -n "$relink_command"; then + # Determine the prefix the user has applied to our future dir. + inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"` + + # Don't allow the user to place us outside of our expected + # location b/c this prevents finding dependent libraries that + # are installed to the same prefix. + # At present, this check doesn't affect windows .dll's that + # are installed into $libdir/../bin (currently, that works fine) + # but it's something to keep an eye on. + test "$inst_prefix_dir" = "$destdir" && \ + func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir" + + if test -n "$inst_prefix_dir"; then + # Stick the inst_prefix_dir data into the link command. + relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` + else + relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"` + fi + + func_warning "relinking \`$file'" + func_show_eval "$relink_command" \ + 'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"' + fi + + # See the names of the shared library. + set dummy $library_names; shift + if test -n "$1"; then + realname="$1" + shift + + srcname="$realname" + test -n "$relink_command" && srcname="$realname"T + + # Install the shared library and build the symlinks. + func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \ + 'exit $?' + tstripme="$stripme" + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + case $realname in + *.dll.a) + tstripme="" + ;; + esac + ;; + esac + if test -n "$tstripme" && test -n "$striplib"; then + func_show_eval "$striplib $destdir/$realname" 'exit $?' + fi + + if test "$#" -gt 0; then + # Delete the old symlinks, and create new ones. + # Try `ln -sf' first, because the `ln' binary might depend on + # the symlink we replace! Solaris /bin/ln does not understand -f, + # so we also need to try rm && ln -s. + for linkname + do + test "$linkname" != "$realname" \ + && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })" + done + fi + + # Do each command in the postinstall commands. + lib="$destdir/$realname" + func_execute_cmds "$postinstall_cmds" 'exit $?' + fi + + # Install the pseudo-library for information purposes. + func_basename "$file" + name="$func_basename_result" + instname="$dir/$name"i + func_show_eval "$install_prog $instname $destdir/$name" 'exit $?' + + # Maybe install the static library, too. + test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library" + ;; + + *.lo) + # Install (i.e. copy) a libtool object. + + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + func_basename "$file" + destfile="$func_basename_result" + destfile="$destdir/$destfile" + fi + + # Deduce the name of the destination old-style object file. + case $destfile in + *.lo) + func_lo2o "$destfile" + staticdest=$func_lo2o_result + ;; + *.$objext) + staticdest="$destfile" + destfile= + ;; + *) + func_fatal_help "cannot copy a libtool object to \`$destfile'" + ;; + esac + + # Install the libtool object if requested. + test -n "$destfile" && \ + func_show_eval "$install_prog $file $destfile" 'exit $?' + + # Install the old object if enabled. + if test "$build_old_libs" = yes; then + # Deduce the name of the old-style object file. + func_lo2o "$file" + staticobj=$func_lo2o_result + func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?' + fi + exit $EXIT_SUCCESS + ;; + + *) + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + func_basename "$file" + destfile="$func_basename_result" + destfile="$destdir/$destfile" + fi + + # If the file is missing, and there is a .exe on the end, strip it + # because it is most likely a libtool script we actually want to + # install + stripped_ext="" + case $file in + *.exe) + if test ! -f "$file"; then + func_stripname '' '.exe' "$file" + file=$func_stripname_result + stripped_ext=".exe" + fi + ;; + esac + + # Do a test to see if this is really a libtool program. + case $host in + *cygwin* | *mingw*) + if func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + wrapper=$func_ltwrapper_scriptname_result + else + func_stripname '' '.exe' "$file" + wrapper=$func_stripname_result + fi + ;; + *) + wrapper=$file + ;; + esac + if func_ltwrapper_script_p "$wrapper"; then + notinst_deplibs= + relink_command= + + func_source "$wrapper" + + # Check the variables that should have been set. + test -z "$generated_by_libtool_version" && \ + func_fatal_error "invalid libtool wrapper script \`$wrapper'" + + finalize=yes + for lib in $notinst_deplibs; do + # Check to see that each library is installed. + libdir= + if test -f "$lib"; then + func_source "$lib" + fi + libfile="$libdir/"`$ECHO "$lib" | $SED 's%^.*/%%g'` ### testsuite: skip nested quoting test + if test -n "$libdir" && test ! -f "$libfile"; then + func_warning "\`$lib' has not been installed in \`$libdir'" + finalize=no + fi + done + + relink_command= + func_source "$wrapper" + + outputname= + if test "$fast_install" = no && test -n "$relink_command"; then + $opt_dry_run || { + if test "$finalize" = yes; then + tmpdir=`func_mktempdir` + func_basename "$file$stripped_ext" + file="$func_basename_result" + outputname="$tmpdir/$file" + # Replace the output file specification. + relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'` + + $opt_silent || { + func_quote_for_expand "$relink_command" + eval "func_echo $func_quote_for_expand_result" + } + if eval "$relink_command"; then : + else + func_error "error: relink \`$file' with the above command before installing it" + $opt_dry_run || ${RM}r "$tmpdir" + continue + fi + file="$outputname" + else + func_warning "cannot relink \`$file'" + fi + } + else + # Install the binary that we compiled earlier. + file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"` + fi + fi + + # remove .exe since cygwin /usr/bin/install will append another + # one anyway + case $install_prog,$host in + */usr/bin/install*,*cygwin*) + case $file:$destfile in + *.exe:*.exe) + # this is ok + ;; + *.exe:*) + destfile=$destfile.exe + ;; + *:*.exe) + func_stripname '' '.exe' "$destfile" + destfile=$func_stripname_result + ;; + esac + ;; + esac + func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?' + $opt_dry_run || if test -n "$outputname"; then + ${RM}r "$tmpdir" + fi + ;; + esac + done + + for file in $staticlibs; do + func_basename "$file" + name="$func_basename_result" + + # Set up the ranlib parameters. + oldlib="$destdir/$name" + + func_show_eval "$install_prog \$file \$oldlib" 'exit $?' + + if test -n "$stripme" && test -n "$old_striplib"; then + func_show_eval "$old_striplib $oldlib" 'exit $?' + fi + + # Do each command in the postinstall commands. + func_execute_cmds "$old_postinstall_cmds" 'exit $?' + done + + test -n "$future_libdirs" && \ + func_warning "remember to run \`$progname --finish$future_libdirs'" + + if test -n "$current_libdirs"; then + # Maybe just do a dry run. + $opt_dry_run && current_libdirs=" -n$current_libdirs" + exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs' + else + exit $EXIT_SUCCESS + fi +} + +test "$mode" = install && func_mode_install ${1+"$@"} + + +# func_generate_dlsyms outputname originator pic_p +# Extract symbols from dlprefiles and create ${outputname}S.o with +# a dlpreopen symbol table. +func_generate_dlsyms () +{ + $opt_debug + my_outputname="$1" + my_originator="$2" + my_pic_p="${3-no}" + my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'` + my_dlsyms= + + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + if test -n "$NM" && test -n "$global_symbol_pipe"; then + my_dlsyms="${my_outputname}S.c" + else + func_error "not configured to extract global symbols from dlpreopened files" + fi + fi + + if test -n "$my_dlsyms"; then + case $my_dlsyms in + "") ;; + *.c) + # Discover the nlist of each of the dlfiles. + nlist="$output_objdir/${my_outputname}.nm" + + func_show_eval "$RM $nlist ${nlist}S ${nlist}T" + + # Parse the name list into a source file. + func_verbose "creating $output_objdir/$my_dlsyms" + + $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\ +/* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */ +/* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */ + +#ifdef __cplusplus +extern \"C\" { +#endif + +#if defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4)) +#pragma GCC diagnostic ignored \"-Wstrict-prototypes\" +#endif + +/* External symbol declarations for the compiler. */\ +" + + if test "$dlself" = yes; then + func_verbose "generating symbol list for \`$output'" + + $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist" + + # Add our own program objects to the symbol list. + progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP` + for progfile in $progfiles; do + func_verbose "extracting global C symbols from \`$progfile'" + $opt_dry_run || eval "$NM $progfile | $global_symbol_pipe >> '$nlist'" + done + + if test -n "$exclude_expsyms"; then + $opt_dry_run || { + eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + } + fi + + if test -n "$export_symbols_regex"; then + $opt_dry_run || { + eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + } + fi + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + export_symbols="$output_objdir/$outputname.exp" + $opt_dry_run || { + $RM $export_symbols + eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' + case $host in + *cygwin* | *mingw* | *cegcc* ) + eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' + ;; + esac + } + else + $opt_dry_run || { + eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' + eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + case $host in + *cygwin* | *mingw* | *cegcc* ) + eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' + ;; + esac + } + fi + fi + + for dlprefile in $dlprefiles; do + func_verbose "extracting global C symbols from \`$dlprefile'" + func_basename "$dlprefile" + name="$func_basename_result" + $opt_dry_run || { + eval '$ECHO ": $name " >> "$nlist"' + eval "$NM $dlprefile 2>/dev/null | $global_symbol_pipe >> '$nlist'" + } + done + + $opt_dry_run || { + # Make sure we have at least an empty file. + test -f "$nlist" || : > "$nlist" + + if test -n "$exclude_expsyms"; then + $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T + $MV "$nlist"T "$nlist" + fi + + # Try sorting and uniquifying the output. + if $GREP -v "^: " < "$nlist" | + if sort -k 3 /dev/null 2>&1; then + sort -k 3 + else + sort +2 + fi | + uniq > "$nlist"S; then + : + else + $GREP -v "^: " < "$nlist" > "$nlist"S + fi + + if test -f "$nlist"S; then + eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"' + else + echo '/* NONE */' >> "$output_objdir/$my_dlsyms" + fi + + echo >> "$output_objdir/$my_dlsyms" "\ + +/* The mapping between symbol names and symbols. */ +typedef struct { + const char *name; + void *address; +} lt_dlsymlist; +" + case $host in + *cygwin* | *mingw* | *cegcc* ) + echo >> "$output_objdir/$my_dlsyms" "\ +/* DATA imports from DLLs on WIN32 con't be const, because + runtime relocations are performed -- see ld's documentation + on pseudo-relocs. */" + lt_dlsym_const= ;; + *osf5*) + echo >> "$output_objdir/$my_dlsyms" "\ +/* This system does not cope well with relocations in const data */" + lt_dlsym_const= ;; + *) + lt_dlsym_const=const ;; + esac + + echo >> "$output_objdir/$my_dlsyms" "\ +extern $lt_dlsym_const lt_dlsymlist +lt_${my_prefix}_LTX_preloaded_symbols[]; +$lt_dlsym_const lt_dlsymlist +lt_${my_prefix}_LTX_preloaded_symbols[] = +{\ + { \"$my_originator\", (void *) 0 }," + + case $need_lib_prefix in + no) + eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms" + ;; + *) + eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms" + ;; + esac + echo >> "$output_objdir/$my_dlsyms" "\ + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt_${my_prefix}_LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif\ +" + } # !$opt_dry_run + + pic_flag_for_symtable= + case "$compile_command " in + *" -static "*) ;; + *) + case $host in + # compiling the symbol table file with pic_flag works around + # a FreeBSD bug that causes programs to crash when -lm is + # linked before any other PIC object. But we must not use + # pic_flag when linking with -static. The problem exists in + # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. + *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) + pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;; + *-*-hpux*) + pic_flag_for_symtable=" $pic_flag" ;; + *) + if test "X$my_pic_p" != Xno; then + pic_flag_for_symtable=" $pic_flag" + fi + ;; + esac + ;; + esac + symtab_cflags= + for arg in $LTCFLAGS; do + case $arg in + -pie | -fpie | -fPIE) ;; + *) symtab_cflags="$symtab_cflags $arg" ;; + esac + done + + # Now compile the dynamic symbol file. + func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?' + + # Clean up the generated files. + func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"' + + # Transform the symbol file into the correct name. + symfileobj="$output_objdir/${my_outputname}S.$objext" + case $host in + *cygwin* | *mingw* | *cegcc* ) + if test -f "$output_objdir/$my_outputname.def"; then + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` + else + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` + fi + ;; + *) + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` + ;; + esac + ;; + *) + func_fatal_error "unknown suffix for \`$my_dlsyms'" + ;; + esac + else + # We keep going just in case the user didn't refer to + # lt_preloaded_symbols. The linker will fail if global_symbol_pipe + # really was required. + + # Nullify the symbol file. + compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"` + fi +} + +# func_win32_libid arg +# return the library type of file 'arg' +# +# Need a lot of goo to handle *both* DLLs and import libs +# Has to be a shell function in order to 'eat' the argument +# that is supplied when $file_magic_command is called. +# Despite the name, also deal with 64 bit binaries. +func_win32_libid () +{ + $opt_debug + win32_libid_type="unknown" + win32_fileres=`file -L $1 2>/dev/null` + case $win32_fileres in + *ar\ archive\ import\ library*) # definitely import + win32_libid_type="x86 archive import" + ;; + *ar\ archive*) # could be an import, or static + # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD. + if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | + $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then + win32_nmres=`eval $NM -f posix -A $1 | + $SED -n -e ' + 1,100{ + / I /{ + s,.*,import, + p + q + } + }'` + case $win32_nmres in + import*) win32_libid_type="x86 archive import";; + *) win32_libid_type="x86 archive static";; + esac + fi + ;; + *DLL*) + win32_libid_type="x86 DLL" + ;; + *executable*) # but shell scripts are "executable" too... + case $win32_fileres in + *MS\ Windows\ PE\ Intel*) + win32_libid_type="x86 DLL" + ;; + esac + ;; + esac + $ECHO "$win32_libid_type" +} + + + +# func_extract_an_archive dir oldlib +func_extract_an_archive () +{ + $opt_debug + f_ex_an_ar_dir="$1"; shift + f_ex_an_ar_oldlib="$1" + if test "$lock_old_archive_extraction" = yes; then + lockfile=$f_ex_an_ar_oldlib.lock + until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do + func_echo "Waiting for $lockfile to be removed" + sleep 2 + done + fi + func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \ + 'stat=$?; rm -f "$lockfile"; exit $stat' + if test "$lock_old_archive_extraction" = yes; then + $opt_dry_run || rm -f "$lockfile" + fi + if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then + : + else + func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" + fi +} + + +# func_extract_archives gentop oldlib ... +func_extract_archives () +{ + $opt_debug + my_gentop="$1"; shift + my_oldlibs=${1+"$@"} + my_oldobjs="" + my_xlib="" + my_xabs="" + my_xdir="" + + for my_xlib in $my_oldlibs; do + # Extract the objects. + case $my_xlib in + [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;; + *) my_xabs=`pwd`"/$my_xlib" ;; + esac + func_basename "$my_xlib" + my_xlib="$func_basename_result" + my_xlib_u=$my_xlib + while :; do + case " $extracted_archives " in + *" $my_xlib_u "*) + func_arith $extracted_serial + 1 + extracted_serial=$func_arith_result + my_xlib_u=lt$extracted_serial-$my_xlib ;; + *) break ;; + esac + done + extracted_archives="$extracted_archives $my_xlib_u" + my_xdir="$my_gentop/$my_xlib_u" + + func_mkdir_p "$my_xdir" + + case $host in + *-darwin*) + func_verbose "Extracting $my_xabs" + # Do not bother doing anything if just a dry run + $opt_dry_run || { + darwin_orig_dir=`pwd` + cd $my_xdir || exit $? + darwin_archive=$my_xabs + darwin_curdir=`pwd` + darwin_base_archive=`basename "$darwin_archive"` + darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true` + if test -n "$darwin_arches"; then + darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'` + darwin_arch= + func_verbose "$darwin_base_archive has multiple architectures $darwin_arches" + for darwin_arch in $darwin_arches ; do + func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}" + $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}" + cd "unfat-$$/${darwin_base_archive}-${darwin_arch}" + func_extract_an_archive "`pwd`" "${darwin_base_archive}" + cd "$darwin_curdir" + $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" + done # $darwin_arches + ## Okay now we've a bunch of thin objects, gotta fatten them up :) + darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u` + darwin_file= + darwin_files= + for darwin_file in $darwin_filelist; do + darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP` + $LIPO -create -output "$darwin_file" $darwin_files + done # $darwin_filelist + $RM -rf unfat-$$ + cd "$darwin_orig_dir" + else + cd $darwin_orig_dir + func_extract_an_archive "$my_xdir" "$my_xabs" + fi # $darwin_arches + } # !$opt_dry_run + ;; + *) + func_extract_an_archive "$my_xdir" "$my_xabs" + ;; + esac + my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP` + done + + func_extract_archives_result="$my_oldobjs" +} + + +# func_emit_wrapper [arg=no] +# +# Emit a libtool wrapper script on stdout. +# Don't directly open a file because we may want to +# incorporate the script contents within a cygwin/mingw +# wrapper executable. Must ONLY be called from within +# func_mode_link because it depends on a number of variables +# set therein. +# +# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR +# variable will take. If 'yes', then the emitted script +# will assume that the directory in which it is stored is +# the $objdir directory. This is a cygwin/mingw-specific +# behavior. +func_emit_wrapper () +{ + func_emit_wrapper_arg1=${1-no} + + $ECHO "\ +#! $SHELL + +# $output - temporary wrapper script for $objdir/$outputname +# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION +# +# The $output program cannot be directly executed until all the libtool +# libraries that it depends on are installed. +# +# This wrapper script should never be moved out of the build directory. +# If it is, it will not operate correctly. + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +sed_quote_subst='$sed_quote_subst' + +# Be Bourne compatible +if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac +fi +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +relink_command=\"$relink_command\" + +# This environment variable determines our operation mode. +if test \"\$libtool_install_magic\" = \"$magic\"; then + # install mode needs the following variables: + generated_by_libtool_version='$macro_version' + notinst_deplibs='$notinst_deplibs' +else + # When we are sourced in execute mode, \$file and \$ECHO are already set. + if test \"\$libtool_execute_magic\" != \"$magic\"; then + file=\"\$0\"" + + qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"` + $ECHO "\ + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$1 +_LTECHO_EOF' +} + ECHO=\"$qECHO\" + fi + +# Very basic option parsing. These options are (a) specific to +# the libtool wrapper, (b) are identical between the wrapper +# /script/ and the wrapper /executable/ which is used only on +# windows platforms, and (c) all begin with the string "--lt-" +# (application programs are unlikely to have options which match +# this pattern). +# +# There are only two supported options: --lt-debug and +# --lt-dump-script. There is, deliberately, no --lt-help. +# +# The first argument to this parsing function should be the +# script's $0 value, followed by "$@". +lt_option_debug= +func_parse_lt_options () +{ + lt_script_arg0=\$0 + shift + for lt_opt + do + case \"\$lt_opt\" in + --lt-debug) lt_option_debug=1 ;; + --lt-dump-script) + lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\` + test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=. + lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\` + cat \"\$lt_dump_D/\$lt_dump_F\" + exit 0 + ;; + --lt-*) + \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2 + exit 1 + ;; + esac + done + + # Print the debug banner immediately: + if test -n \"\$lt_option_debug\"; then + echo \"${outputname}:${output}:\${LINENO}: libtool wrapper (GNU $PACKAGE$TIMESTAMP) $VERSION\" 1>&2 + fi +} + +# Used when --lt-debug. Prints its arguments to stdout +# (redirection is the responsibility of the caller) +func_lt_dump_args () +{ + lt_dump_args_N=1; + for lt_arg + do + \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[\$lt_dump_args_N]: \$lt_arg\" + lt_dump_args_N=\`expr \$lt_dump_args_N + 1\` + done +} + +# Core function for launching the target application +func_exec_program_core () +{ +" + case $host in + # Backslashes separate directories on plain windows + *-*-mingw | *-*-os2* | *-cegcc*) + $ECHO "\ + if test -n \"\$lt_option_debug\"; then + \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir\\\\\$program\" 1>&2 + func_lt_dump_args \${1+\"\$@\"} 1>&2 + fi + exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} +" + ;; + + *) + $ECHO "\ + if test -n \"\$lt_option_debug\"; then + \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir/\$program\" 1>&2 + func_lt_dump_args \${1+\"\$@\"} 1>&2 + fi + exec \"\$progdir/\$program\" \${1+\"\$@\"} +" + ;; + esac + $ECHO "\ + \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 + exit 1 +} + +# A function to encapsulate launching the target application +# Strips options in the --lt-* namespace from \$@ and +# launches target application with the remaining arguments. +func_exec_program () +{ + for lt_wr_arg + do + case \$lt_wr_arg in + --lt-*) ;; + *) set x \"\$@\" \"\$lt_wr_arg\"; shift;; + esac + shift + done + func_exec_program_core \${1+\"\$@\"} +} + + # Parse options + func_parse_lt_options \"\$0\" \${1+\"\$@\"} + + # Find the directory that this script lives in. + thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\` + test \"x\$thisdir\" = \"x\$file\" && thisdir=. + + # Follow symbolic links until we get to the real thisdir. + file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\` + while test -n \"\$file\"; do + destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\` + + # If there was a directory component, then change thisdir. + if test \"x\$destdir\" != \"x\$file\"; then + case \"\$destdir\" in + [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; + *) thisdir=\"\$thisdir/\$destdir\" ;; + esac + fi + + file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\` + file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\` + done + + # Usually 'no', except on cygwin/mingw when embedded into + # the cwrapper. + WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1 + if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then + # special case for '.' + if test \"\$thisdir\" = \".\"; then + thisdir=\`pwd\` + fi + # remove .libs from thisdir + case \"\$thisdir\" in + *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;; + $objdir ) thisdir=. ;; + esac + fi + + # Try to get the absolute directory name. + absdir=\`cd \"\$thisdir\" && pwd\` + test -n \"\$absdir\" && thisdir=\"\$absdir\" +" + + if test "$fast_install" = yes; then + $ECHO "\ + program=lt-'$outputname'$exeext + progdir=\"\$thisdir/$objdir\" + + if test ! -f \"\$progdir/\$program\" || + { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ + test \"X\$file\" != \"X\$progdir/\$program\"; }; then + + file=\"\$\$-\$program\" + + if test ! -d \"\$progdir\"; then + $MKDIR \"\$progdir\" + else + $RM \"\$progdir/\$file\" + fi" + + $ECHO "\ + + # relink executable if necessary + if test -n \"\$relink_command\"; then + if relink_command_output=\`eval \$relink_command 2>&1\`; then : + else + $ECHO \"\$relink_command_output\" >&2 + $RM \"\$progdir/\$file\" + exit 1 + fi + fi + + $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || + { $RM \"\$progdir/\$program\"; + $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; } + $RM \"\$progdir/\$file\" + fi" + else + $ECHO "\ + program='$outputname' + progdir=\"\$thisdir/$objdir\" +" + fi + + $ECHO "\ + + if test -f \"\$progdir/\$program\"; then" + + # Export our shlibpath_var if we have one. + if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then + $ECHO "\ + # Add our own library path to $shlibpath_var + $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" + + # Some systems cannot cope with colon-terminated $shlibpath_var + # The second colon is a workaround for a bug in BeOS R4 sed + $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\` + + export $shlibpath_var +" + fi + + # fixup the dll searchpath if we need to. + if test -n "$dllsearchpath"; then + $ECHO "\ + # Add the dll search path components to the executable PATH + PATH=$dllsearchpath:\$PATH +" + fi + + $ECHO "\ + if test \"\$libtool_execute_magic\" != \"$magic\"; then + # Run the actual program with our arguments. + func_exec_program \${1+\"\$@\"} + fi + else + # The program doesn't exist. + \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2 + \$ECHO \"This script is just a wrapper for \$program.\" 1>&2 + \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2 + exit 1 + fi +fi\ +" +} + + +# func_to_host_path arg +# +# Convert paths to host format when used with build tools. +# Intended for use with "native" mingw (where libtool itself +# is running under the msys shell), or in the following cross- +# build environments: +# $build $host +# mingw (msys) mingw [e.g. native] +# cygwin mingw +# *nix + wine mingw +# where wine is equipped with the `winepath' executable. +# In the native mingw case, the (msys) shell automatically +# converts paths for any non-msys applications it launches, +# but that facility isn't available from inside the cwrapper. +# Similar accommodations are necessary for $host mingw and +# $build cygwin. Calling this function does no harm for other +# $host/$build combinations not listed above. +# +# ARG is the path (on $build) that should be converted to +# the proper representation for $host. The result is stored +# in $func_to_host_path_result. +func_to_host_path () +{ + func_to_host_path_result="$1" + if test -n "$1"; then + case $host in + *mingw* ) + lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' + case $build in + *mingw* ) # actually, msys + # awkward: cmd appends spaces to result + func_to_host_path_result=`( cmd //c echo "$1" ) 2>/dev/null | + $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"` + ;; + *cygwin* ) + func_to_host_path_result=`cygpath -w "$1" | + $SED -e "$lt_sed_naive_backslashify"` + ;; + * ) + # Unfortunately, winepath does not exit with a non-zero + # error code, so we are forced to check the contents of + # stdout. On the other hand, if the command is not + # found, the shell will set an exit code of 127 and print + # *an error message* to stdout. So we must check for both + # error code of zero AND non-empty stdout, which explains + # the odd construction: + func_to_host_path_tmp1=`winepath -w "$1" 2>/dev/null` + if test "$?" -eq 0 && test -n "${func_to_host_path_tmp1}"; then + func_to_host_path_result=`$ECHO "$func_to_host_path_tmp1" | + $SED -e "$lt_sed_naive_backslashify"` + else + # Allow warning below. + func_to_host_path_result= + fi + ;; + esac + if test -z "$func_to_host_path_result" ; then + func_error "Could not determine host path corresponding to" + func_error " \`$1'" + func_error "Continuing, but uninstalled executables may not work." + # Fallback: + func_to_host_path_result="$1" + fi + ;; + esac + fi +} +# end: func_to_host_path + +# func_to_host_pathlist arg +# +# Convert pathlists to host format when used with build tools. +# See func_to_host_path(), above. This function supports the +# following $build/$host combinations (but does no harm for +# combinations not listed here): +# $build $host +# mingw (msys) mingw [e.g. native] +# cygwin mingw +# *nix + wine mingw +# +# Path separators are also converted from $build format to +# $host format. If ARG begins or ends with a path separator +# character, it is preserved (but converted to $host format) +# on output. +# +# ARG is a pathlist (on $build) that should be converted to +# the proper representation on $host. The result is stored +# in $func_to_host_pathlist_result. +func_to_host_pathlist () +{ + func_to_host_pathlist_result="$1" + if test -n "$1"; then + case $host in + *mingw* ) + lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' + # Remove leading and trailing path separator characters from + # ARG. msys behavior is inconsistent here, cygpath turns them + # into '.;' and ';.', and winepath ignores them completely. + func_stripname : : "$1" + func_to_host_pathlist_tmp1=$func_stripname_result + case $build in + *mingw* ) # Actually, msys. + # Awkward: cmd appends spaces to result. + func_to_host_pathlist_result=` + ( cmd //c echo "$func_to_host_pathlist_tmp1" ) 2>/dev/null | + $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"` + ;; + *cygwin* ) + func_to_host_pathlist_result=`cygpath -w -p "$func_to_host_pathlist_tmp1" | + $SED -e "$lt_sed_naive_backslashify"` + ;; + * ) + # unfortunately, winepath doesn't convert pathlists + func_to_host_pathlist_result="" + func_to_host_pathlist_oldIFS=$IFS + IFS=: + for func_to_host_pathlist_f in $func_to_host_pathlist_tmp1 ; do + IFS=$func_to_host_pathlist_oldIFS + if test -n "$func_to_host_pathlist_f" ; then + func_to_host_path "$func_to_host_pathlist_f" + if test -n "$func_to_host_path_result" ; then + if test -z "$func_to_host_pathlist_result" ; then + func_to_host_pathlist_result="$func_to_host_path_result" + else + func_append func_to_host_pathlist_result ";$func_to_host_path_result" + fi + fi + fi + done + IFS=$func_to_host_pathlist_oldIFS + ;; + esac + if test -z "$func_to_host_pathlist_result"; then + func_error "Could not determine the host path(s) corresponding to" + func_error " \`$1'" + func_error "Continuing, but uninstalled executables may not work." + # Fallback. This may break if $1 contains DOS-style drive + # specifications. The fix is not to complicate the expression + # below, but for the user to provide a working wine installation + # with winepath so that path translation in the cross-to-mingw + # case works properly. + lt_replace_pathsep_nix_to_dos="s|:|;|g" + func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp1" |\ + $SED -e "$lt_replace_pathsep_nix_to_dos"` + fi + # Now, add the leading and trailing path separators back + case "$1" in + :* ) func_to_host_pathlist_result=";$func_to_host_pathlist_result" + ;; + esac + case "$1" in + *: ) func_append func_to_host_pathlist_result ";" + ;; + esac + ;; + esac + fi +} +# end: func_to_host_pathlist + +# func_emit_cwrapperexe_src +# emit the source code for a wrapper executable on stdout +# Must ONLY be called from within func_mode_link because +# it depends on a number of variable set therein. +func_emit_cwrapperexe_src () +{ + cat < +#include +#ifdef _MSC_VER +# include +# include +# include +#else +# include +# include +# ifdef __CYGWIN__ +# include +# endif +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +/* declarations of non-ANSI functions */ +#if defined(__MINGW32__) +# ifdef __STRICT_ANSI__ +int _putenv (const char *); +# endif +#elif defined(__CYGWIN__) +# ifdef __STRICT_ANSI__ +char *realpath (const char *, char *); +int putenv (char *); +int setenv (const char *, const char *, int); +# endif +/* #elif defined (other platforms) ... */ +#endif + +/* portability defines, excluding path handling macros */ +#if defined(_MSC_VER) +# define setmode _setmode +# define stat _stat +# define chmod _chmod +# define getcwd _getcwd +# define putenv _putenv +# define S_IXUSR _S_IEXEC +# ifndef _INTPTR_T_DEFINED +# define _INTPTR_T_DEFINED +# define intptr_t int +# endif +#elif defined(__MINGW32__) +# define setmode _setmode +# define stat _stat +# define chmod _chmod +# define getcwd _getcwd +# define putenv _putenv +#elif defined(__CYGWIN__) +# define HAVE_SETENV +# define FOPEN_WB "wb" +/* #elif defined (other platforms) ... */ +#endif + +#if defined(PATH_MAX) +# define LT_PATHMAX PATH_MAX +#elif defined(MAXPATHLEN) +# define LT_PATHMAX MAXPATHLEN +#else +# define LT_PATHMAX 1024 +#endif + +#ifndef S_IXOTH +# define S_IXOTH 0 +#endif +#ifndef S_IXGRP +# define S_IXGRP 0 +#endif + +/* path handling portability macros */ +#ifndef DIR_SEPARATOR +# define DIR_SEPARATOR '/' +# define PATH_SEPARATOR ':' +#endif + +#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ + defined (__OS2__) +# define HAVE_DOS_BASED_FILE_SYSTEM +# define FOPEN_WB "wb" +# ifndef DIR_SEPARATOR_2 +# define DIR_SEPARATOR_2 '\\' +# endif +# ifndef PATH_SEPARATOR_2 +# define PATH_SEPARATOR_2 ';' +# endif +#endif + +#ifndef DIR_SEPARATOR_2 +# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) +#else /* DIR_SEPARATOR_2 */ +# define IS_DIR_SEPARATOR(ch) \ + (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) +#endif /* DIR_SEPARATOR_2 */ + +#ifndef PATH_SEPARATOR_2 +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) +#else /* PATH_SEPARATOR_2 */ +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) +#endif /* PATH_SEPARATOR_2 */ + +#ifndef FOPEN_WB +# define FOPEN_WB "w" +#endif +#ifndef _O_BINARY +# define _O_BINARY 0 +#endif + +#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) +#define XFREE(stale) do { \ + if (stale) { free ((void *) stale); stale = 0; } \ +} while (0) + +#if defined(LT_DEBUGWRAPPER) +static int lt_debug = 1; +#else +static int lt_debug = 0; +#endif + +const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */ + +void *xmalloc (size_t num); +char *xstrdup (const char *string); +const char *base_name (const char *name); +char *find_executable (const char *wrapper); +char *chase_symlinks (const char *pathspec); +int make_executable (const char *path); +int check_executable (const char *path); +char *strendzap (char *str, const char *pat); +void lt_debugprintf (const char *file, int line, const char *fmt, ...); +void lt_fatal (const char *file, int line, const char *message, ...); +static const char *nonnull (const char *s); +static const char *nonempty (const char *s); +void lt_setenv (const char *name, const char *value); +char *lt_extend_str (const char *orig_value, const char *add, int to_end); +void lt_update_exe_path (const char *name, const char *value); +void lt_update_lib_path (const char *name, const char *value); +char **prepare_spawn (char **argv); +void lt_dump_script (FILE *f); +EOF + + cat <= 0) + && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) + return 1; + else + return 0; +} + +int +make_executable (const char *path) +{ + int rval = 0; + struct stat st; + + lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n", + nonempty (path)); + if ((!path) || (!*path)) + return 0; + + if (stat (path, &st) >= 0) + { + rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR); + } + return rval; +} + +/* Searches for the full path of the wrapper. Returns + newly allocated full path name if found, NULL otherwise + Does not chase symlinks, even on platforms that support them. +*/ +char * +find_executable (const char *wrapper) +{ + int has_slash = 0; + const char *p; + const char *p_next; + /* static buffer for getcwd */ + char tmp[LT_PATHMAX + 1]; + int tmp_len; + char *concat_name; + + lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n", + nonempty (wrapper)); + + if ((wrapper == NULL) || (*wrapper == '\0')) + return NULL; + + /* Absolute path? */ +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':') + { + concat_name = xstrdup (wrapper); + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } + else + { +#endif + if (IS_DIR_SEPARATOR (wrapper[0])) + { + concat_name = xstrdup (wrapper); + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + } +#endif + + for (p = wrapper; *p; p++) + if (*p == '/') + { + has_slash = 1; + break; + } + if (!has_slash) + { + /* no slashes; search PATH */ + const char *path = getenv ("PATH"); + if (path != NULL) + { + for (p = path; *p; p = p_next) + { + const char *q; + size_t p_len; + for (q = p; *q; q++) + if (IS_PATH_SEPARATOR (*q)) + break; + p_len = q - p; + p_next = (*q == '\0' ? q : q + 1); + if (p_len == 0) + { + /* empty path: current directory */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", + nonnull (strerror (errno))); + tmp_len = strlen (tmp); + concat_name = + XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + } + else + { + concat_name = + XMALLOC (char, p_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, p, p_len); + concat_name[p_len] = '/'; + strcpy (concat_name + p_len + 1, wrapper); + } + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } + } + /* not found in PATH; assume curdir */ + } + /* Relative path | not found in path: prepend cwd */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", + nonnull (strerror (errno))); + tmp_len = strlen (tmp); + concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + return NULL; +} + +char * +chase_symlinks (const char *pathspec) +{ +#ifndef S_ISLNK + return xstrdup (pathspec); +#else + char buf[LT_PATHMAX]; + struct stat s; + char *tmp_pathspec = xstrdup (pathspec); + char *p; + int has_symlinks = 0; + while (strlen (tmp_pathspec) && !has_symlinks) + { + lt_debugprintf (__FILE__, __LINE__, + "checking path component for symlinks: %s\n", + tmp_pathspec); + if (lstat (tmp_pathspec, &s) == 0) + { + if (S_ISLNK (s.st_mode) != 0) + { + has_symlinks = 1; + break; + } + + /* search backwards for last DIR_SEPARATOR */ + p = tmp_pathspec + strlen (tmp_pathspec) - 1; + while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) + p--; + if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) + { + /* no more DIR_SEPARATORS left */ + break; + } + *p = '\0'; + } + else + { + lt_fatal (__FILE__, __LINE__, + "error accessing file \"%s\": %s", + tmp_pathspec, nonnull (strerror (errno))); + } + } + XFREE (tmp_pathspec); + + if (!has_symlinks) + { + return xstrdup (pathspec); + } + + tmp_pathspec = realpath (pathspec, buf); + if (tmp_pathspec == 0) + { + lt_fatal (__FILE__, __LINE__, + "could not follow symlinks for %s", pathspec); + } + return xstrdup (tmp_pathspec); +#endif +} + +char * +strendzap (char *str, const char *pat) +{ + size_t len, patlen; + + assert (str != NULL); + assert (pat != NULL); + + len = strlen (str); + patlen = strlen (pat); + + if (patlen <= len) + { + str += len - patlen; + if (strcmp (str, pat) == 0) + *str = '\0'; + } + return str; +} + +void +lt_debugprintf (const char *file, int line, const char *fmt, ...) +{ + va_list args; + if (lt_debug) + { + (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line); + va_start (args, fmt); + (void) vfprintf (stderr, fmt, args); + va_end (args); + } +} + +static void +lt_error_core (int exit_status, const char *file, + int line, const char *mode, + const char *message, va_list ap) +{ + fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode); + vfprintf (stderr, message, ap); + fprintf (stderr, ".\n"); + + if (exit_status >= 0) + exit (exit_status); +} + +void +lt_fatal (const char *file, int line, const char *message, ...) +{ + va_list ap; + va_start (ap, message); + lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap); + va_end (ap); +} + +static const char * +nonnull (const char *s) +{ + return s ? s : "(null)"; +} + +static const char * +nonempty (const char *s) +{ + return (s && !*s) ? "(empty)" : nonnull (s); +} + +void +lt_setenv (const char *name, const char *value) +{ + lt_debugprintf (__FILE__, __LINE__, + "(lt_setenv) setting '%s' to '%s'\n", + nonnull (name), nonnull (value)); + { +#ifdef HAVE_SETENV + /* always make a copy, for consistency with !HAVE_SETENV */ + char *str = xstrdup (value); + setenv (name, str, 1); +#else + int len = strlen (name) + 1 + strlen (value) + 1; + char *str = XMALLOC (char, len); + sprintf (str, "%s=%s", name, value); + if (putenv (str) != EXIT_SUCCESS) + { + XFREE (str); + } +#endif + } +} + +char * +lt_extend_str (const char *orig_value, const char *add, int to_end) +{ + char *new_value; + if (orig_value && *orig_value) + { + int orig_value_len = strlen (orig_value); + int add_len = strlen (add); + new_value = XMALLOC (char, add_len + orig_value_len + 1); + if (to_end) + { + strcpy (new_value, orig_value); + strcpy (new_value + orig_value_len, add); + } + else + { + strcpy (new_value, add); + strcpy (new_value + add_len, orig_value); + } + } + else + { + new_value = xstrdup (add); + } + return new_value; +} + +void +lt_update_exe_path (const char *name, const char *value) +{ + lt_debugprintf (__FILE__, __LINE__, + "(lt_update_exe_path) modifying '%s' by prepending '%s'\n", + nonnull (name), nonnull (value)); + + if (name && *name && value && *value) + { + char *new_value = lt_extend_str (getenv (name), value, 0); + /* some systems can't cope with a ':'-terminated path #' */ + int len = strlen (new_value); + while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1])) + { + new_value[len-1] = '\0'; + } + lt_setenv (name, new_value); + XFREE (new_value); + } +} + +void +lt_update_lib_path (const char *name, const char *value) +{ + lt_debugprintf (__FILE__, __LINE__, + "(lt_update_lib_path) modifying '%s' by prepending '%s'\n", + nonnull (name), nonnull (value)); + + if (name && *name && value && *value) + { + char *new_value = lt_extend_str (getenv (name), value, 0); + lt_setenv (name, new_value); + XFREE (new_value); + } +} + +EOF + case $host_os in + mingw*) + cat <<"EOF" + +/* Prepares an argument vector before calling spawn(). + Note that spawn() does not by itself call the command interpreter + (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") : + ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&v); + v.dwPlatformId == VER_PLATFORM_WIN32_NT; + }) ? "cmd.exe" : "command.com"). + Instead it simply concatenates the arguments, separated by ' ', and calls + CreateProcess(). We must quote the arguments since Win32 CreateProcess() + interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a + special way: + - Space and tab are interpreted as delimiters. They are not treated as + delimiters if they are surrounded by double quotes: "...". + - Unescaped double quotes are removed from the input. Their only effect is + that within double quotes, space and tab are treated like normal + characters. + - Backslashes not followed by double quotes are not special. + - But 2*n+1 backslashes followed by a double quote become + n backslashes followed by a double quote (n >= 0): + \" -> " + \\\" -> \" + \\\\\" -> \\" + */ +#define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" +#define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" +char ** +prepare_spawn (char **argv) +{ + size_t argc; + char **new_argv; + size_t i; + + /* Count number of arguments. */ + for (argc = 0; argv[argc] != NULL; argc++) + ; + + /* Allocate new argument vector. */ + new_argv = XMALLOC (char *, argc + 1); + + /* Put quoted arguments into the new argument vector. */ + for (i = 0; i < argc; i++) + { + const char *string = argv[i]; + + if (string[0] == '\0') + new_argv[i] = xstrdup ("\"\""); + else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL) + { + int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL); + size_t length; + unsigned int backslashes; + const char *s; + char *quoted_string; + char *p; + + length = 0; + backslashes = 0; + if (quote_around) + length++; + for (s = string; *s != '\0'; s++) + { + char c = *s; + if (c == '"') + length += backslashes + 1; + length++; + if (c == '\\') + backslashes++; + else + backslashes = 0; + } + if (quote_around) + length += backslashes + 1; + + quoted_string = XMALLOC (char, length + 1); + + p = quoted_string; + backslashes = 0; + if (quote_around) + *p++ = '"'; + for (s = string; *s != '\0'; s++) + { + char c = *s; + if (c == '"') + { + unsigned int j; + for (j = backslashes + 1; j > 0; j--) + *p++ = '\\'; + } + *p++ = c; + if (c == '\\') + backslashes++; + else + backslashes = 0; + } + if (quote_around) + { + unsigned int j; + for (j = backslashes; j > 0; j--) + *p++ = '\\'; + *p++ = '"'; + } + *p = '\0'; + + new_argv[i] = quoted_string; + } + else + new_argv[i] = (char *) string; + } + new_argv[argc] = NULL; + + return new_argv; +} +EOF + ;; + esac + + cat <<"EOF" +void lt_dump_script (FILE* f) +{ +EOF + func_emit_wrapper yes | + $SED -e 's/\([\\"]\)/\\\1/g' \ + -e 's/^/ fputs ("/' -e 's/$/\\n", f);/' + + cat <<"EOF" +} +EOF +} +# end: func_emit_cwrapperexe_src + +# func_win32_import_lib_p ARG +# True if ARG is an import lib, as indicated by $file_magic_cmd +func_win32_import_lib_p () +{ + $opt_debug + case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in + *import*) : ;; + *) false ;; + esac +} + +# func_mode_link arg... +func_mode_link () +{ + $opt_debug + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + # It is impossible to link a dll without this setting, and + # we shouldn't force the makefile maintainer to figure out + # which system we are compiling for in order to pass an extra + # flag for every libtool invocation. + # allow_undefined=no + + # FIXME: Unfortunately, there are problems with the above when trying + # to make a dll which has undefined symbols, in which case not + # even a static library is built. For now, we need to specify + # -no-undefined on the libtool link line when we can be certain + # that all symbols are satisfied, otherwise we get a static library. + allow_undefined=yes + ;; + *) + allow_undefined=yes + ;; + esac + libtool_args=$nonopt + base_compile="$nonopt $@" + compile_command=$nonopt + finalize_command=$nonopt + + compile_rpath= + finalize_rpath= + compile_shlibpath= + finalize_shlibpath= + convenience= + old_convenience= + deplibs= + old_deplibs= + compiler_flags= + linker_flags= + dllsearchpath= + lib_search_path=`pwd` + inst_prefix_dir= + new_inherited_linker_flags= + + avoid_version=no + bindir= + dlfiles= + dlprefiles= + dlself=no + export_dynamic=no + export_symbols= + export_symbols_regex= + generated= + libobjs= + ltlibs= + module=no + no_install=no + objs= + non_pic_objects= + precious_files_regex= + prefer_static_libs=no + preload=no + prev= + prevarg= + release= + rpath= + xrpath= + perm_rpath= + temp_rpath= + thread_safe=no + vinfo= + vinfo_number=no + weak_libs= + single_module="${wl}-single_module" + func_infer_tag $base_compile + + # We need to know -static, to get the right output filenames. + for arg + do + case $arg in + -shared) + test "$build_libtool_libs" != yes && \ + func_fatal_configuration "can not build a shared library" + build_old_libs=no + break + ;; + -all-static | -static | -static-libtool-libs) + case $arg in + -all-static) + if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then + func_warning "complete static linking is impossible in this configuration" + fi + if test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=yes + ;; + -static) + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=built + ;; + -static-libtool-libs) + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=yes + ;; + esac + build_libtool_libs=no + build_old_libs=yes + break + ;; + esac + done + + # See if our shared archives depend on static archives. + test -n "$old_archive_from_new_cmds" && build_old_libs=yes + + # Go through the arguments, transforming them on the way. + while test "$#" -gt 0; do + arg="$1" + shift + func_quote_for_eval "$arg" + qarg=$func_quote_for_eval_unquoted_result + func_append libtool_args " $func_quote_for_eval_result" + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case $prev in + output) + func_append compile_command " @OUTPUT@" + func_append finalize_command " @OUTPUT@" + ;; + esac + + case $prev in + bindir) + bindir="$arg" + prev= + continue + ;; + dlfiles|dlprefiles) + if test "$preload" = no; then + # Add the symbol object into the linking commands. + func_append compile_command " @SYMFILE@" + func_append finalize_command " @SYMFILE@" + preload=yes + fi + case $arg in + *.la | *.lo) ;; # We handle these cases below. + force) + if test "$dlself" = no; then + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + self) + if test "$prev" = dlprefiles; then + dlself=yes + elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then + dlself=yes + else + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + *) + if test "$prev" = dlfiles; then + dlfiles="$dlfiles $arg" + else + dlprefiles="$dlprefiles $arg" + fi + prev= + continue + ;; + esac + ;; + expsyms) + export_symbols="$arg" + test -f "$arg" \ + || func_fatal_error "symbol file \`$arg' does not exist" + prev= + continue + ;; + expsyms_regex) + export_symbols_regex="$arg" + prev= + continue + ;; + framework) + case $host in + *-*-darwin*) + case "$deplibs " in + *" $qarg.ltframework "*) ;; + *) deplibs="$deplibs $qarg.ltframework" # this is fixed later + ;; + esac + ;; + esac + prev= + continue + ;; + inst_prefix) + inst_prefix_dir="$arg" + prev= + continue + ;; + objectlist) + if test -f "$arg"; then + save_arg=$arg + moreargs= + for fil in `cat "$save_arg"` + do +# moreargs="$moreargs $fil" + arg=$fil + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if func_lalib_unsafe_p "$arg"; then + pic_object= + non_pic_object= + + # Read the .lo file + func_source "$arg" + + if test -z "$pic_object" || + test -z "$non_pic_object" || + test "$pic_object" = none && + test "$non_pic_object" = none; then + func_fatal_error "cannot find name of object for \`$arg'" + fi + + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + dlfiles="$dlfiles $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + dlprefiles="$dlprefiles $pic_object" + prev= + fi + + # A PIC object. + func_append libobjs " $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + func_append non_pic_objects " $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object="$pic_object" + func_append non_pic_objects " $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if $opt_dry_run; then + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + func_lo2o "$arg" + pic_object=$xdir$objdir/$func_lo2o_result + non_pic_object=$xdir$func_lo2o_result + func_append libobjs " $pic_object" + func_append non_pic_objects " $non_pic_object" + else + func_fatal_error "\`$arg' is not a valid libtool object" + fi + fi + done + else + func_fatal_error "link input file \`$arg' does not exist" + fi + arg=$save_arg + prev= + continue + ;; + precious_regex) + precious_files_regex="$arg" + prev= + continue + ;; + release) + release="-$arg" + prev= + continue + ;; + rpath | xrpath) + # We need an absolute path. + case $arg in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + func_fatal_error "only absolute run-paths are allowed" + ;; + esac + if test "$prev" = rpath; then + case "$rpath " in + *" $arg "*) ;; + *) rpath="$rpath $arg" ;; + esac + else + case "$xrpath " in + *" $arg "*) ;; + *) xrpath="$xrpath $arg" ;; + esac + fi + prev= + continue + ;; + shrext) + shrext_cmds="$arg" + prev= + continue + ;; + weak) + weak_libs="$weak_libs $arg" + prev= + continue + ;; + xcclinker) + linker_flags="$linker_flags $qarg" + compiler_flags="$compiler_flags $qarg" + prev= + func_append compile_command " $qarg" + func_append finalize_command " $qarg" + continue + ;; + xcompiler) + compiler_flags="$compiler_flags $qarg" + prev= + func_append compile_command " $qarg" + func_append finalize_command " $qarg" + continue + ;; + xlinker) + linker_flags="$linker_flags $qarg" + compiler_flags="$compiler_flags $wl$qarg" + prev= + func_append compile_command " $wl$qarg" + func_append finalize_command " $wl$qarg" + continue + ;; + *) + eval "$prev=\"\$arg\"" + prev= + continue + ;; + esac + fi # test -n "$prev" + + prevarg="$arg" + + case $arg in + -all-static) + if test -n "$link_static_flag"; then + # See comment for -static flag below, for more details. + func_append compile_command " $link_static_flag" + func_append finalize_command " $link_static_flag" + fi + continue + ;; + + -allow-undefined) + # FIXME: remove this flag sometime in the future. + func_fatal_error "\`-allow-undefined' must not be used because it is the default" + ;; + + -avoid-version) + avoid_version=yes + continue + ;; + + -bindir) + prev=bindir + continue + ;; + + -dlopen) + prev=dlfiles + continue + ;; + + -dlpreopen) + prev=dlprefiles + continue + ;; + + -export-dynamic) + export_dynamic=yes + continue + ;; + + -export-symbols | -export-symbols-regex) + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + func_fatal_error "more than one -exported-symbols argument is not allowed" + fi + if test "X$arg" = "X-export-symbols"; then + prev=expsyms + else + prev=expsyms_regex + fi + continue + ;; + + -framework) + prev=framework + continue + ;; + + -inst-prefix-dir) + prev=inst_prefix + continue + ;; + + # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* + # so, if we see these flags be careful not to treat them like -L + -L[A-Z][A-Z]*:*) + case $with_gcc/$host in + no/*-*-irix* | /*-*-irix*) + func_append compile_command " $arg" + func_append finalize_command " $arg" + ;; + esac + continue + ;; + + -L*) + func_stripname '-L' '' "$arg" + dir=$func_stripname_result + if test -z "$dir"; then + if test "$#" -gt 0; then + func_fatal_error "require no space between \`-L' and \`$1'" + else + func_fatal_error "need path for \`-L' option" + fi + fi + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + absdir=`cd "$dir" && pwd` + test -z "$absdir" && \ + func_fatal_error "cannot determine absolute directory name of \`$dir'" + dir="$absdir" + ;; + esac + case "$deplibs " in + *" -L$dir "*) ;; + *) + deplibs="$deplibs -L$dir" + lib_search_path="$lib_search_path $dir" + ;; + esac + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$dir:"*) ;; + ::) dllsearchpath=$dir;; + *) dllsearchpath="$dllsearchpath:$dir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + ::) dllsearchpath=$testbindir;; + *) dllsearchpath="$dllsearchpath:$testbindir";; + esac + ;; + esac + continue + ;; + + -l*) + if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*) + # These systems don't actually have a C or math library (as such) + continue + ;; + *-*-os2*) + # These systems don't actually have a C library (as such) + test "X$arg" = "X-lc" && continue + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + test "X$arg" = "X-lc" && continue + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C and math libraries are in the System framework + deplibs="$deplibs System.ltframework" + continue + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + test "X$arg" = "X-lc" && continue + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + test "X$arg" = "X-lc" && continue + ;; + esac + elif test "X$arg" = "X-lc_r"; then + case $host in + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc_r directly, use -pthread flag. + continue + ;; + esac + fi + deplibs="$deplibs $arg" + continue + ;; + + -module) + module=yes + continue + ;; + + # Tru64 UNIX uses -model [arg] to determine the layout of C++ + # classes, name mangling, and exception handling. + # Darwin uses the -arch flag to determine output architecture. + -model|-arch|-isysroot) + compiler_flags="$compiler_flags $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + prev=xcompiler + continue + ;; + + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads) + compiler_flags="$compiler_flags $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + case "$new_inherited_linker_flags " in + *" $arg "*) ;; + * ) new_inherited_linker_flags="$new_inherited_linker_flags $arg" ;; + esac + continue + ;; + + -multi_module) + single_module="${wl}-multi_module" + continue + ;; + + -no-fast-install) + fast_install=no + continue + ;; + + -no-install) + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) + # The PATH hackery in wrapper scripts is required on Windows + # and Darwin in order for the loader to find any dlls it needs. + func_warning "\`-no-install' is ignored for $host" + func_warning "assuming \`-no-fast-install' instead" + fast_install=no + ;; + *) no_install=yes ;; + esac + continue + ;; + + -no-undefined) + allow_undefined=no + continue + ;; + + -objectlist) + prev=objectlist + continue + ;; + + -o) prev=output ;; + + -precious-files-regex) + prev=precious_regex + continue + ;; + + -release) + prev=release + continue + ;; + + -rpath) + prev=rpath + continue + ;; + + -R) + prev=xrpath + continue + ;; + + -R*) + func_stripname '-R' '' "$arg" + dir=$func_stripname_result + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + func_fatal_error "only absolute run-paths are allowed" + ;; + esac + case "$xrpath " in + *" $dir "*) ;; + *) xrpath="$xrpath $dir" ;; + esac + continue + ;; + + -shared) + # The effects of -shared are defined in a previous loop. + continue + ;; + + -shrext) + prev=shrext + continue + ;; + + -static | -static-libtool-libs) + # The effects of -static are defined in a previous loop. + # We used to do the same as -all-static on platforms that + # didn't have a PIC flag, but the assumption that the effects + # would be equivalent was wrong. It would break on at least + # Digital Unix and AIX. + continue + ;; + + -thread-safe) + thread_safe=yes + continue + ;; + + -version-info) + prev=vinfo + continue + ;; + + -version-number) + prev=vinfo + vinfo_number=yes + continue + ;; + + -weak) + prev=weak + continue + ;; + + -Wc,*) + func_stripname '-Wc,' '' "$arg" + args=$func_stripname_result + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + func_quote_for_eval "$flag" + arg="$arg $func_quote_for_eval_result" + compiler_flags="$compiler_flags $func_quote_for_eval_result" + done + IFS="$save_ifs" + func_stripname ' ' '' "$arg" + arg=$func_stripname_result + ;; + + -Wl,*) + func_stripname '-Wl,' '' "$arg" + args=$func_stripname_result + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + func_quote_for_eval "$flag" + arg="$arg $wl$func_quote_for_eval_result" + compiler_flags="$compiler_flags $wl$func_quote_for_eval_result" + linker_flags="$linker_flags $func_quote_for_eval_result" + done + IFS="$save_ifs" + func_stripname ' ' '' "$arg" + arg=$func_stripname_result + ;; + + -Xcompiler) + prev=xcompiler + continue + ;; + + -Xlinker) + prev=xlinker + continue + ;; + + -XCClinker) + prev=xcclinker + continue + ;; + + # -msg_* for osf cc + -msg_*) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + + # Flags to be passed through unchanged, with rationale: + # -64, -mips[0-9] enable 64-bit mode for the SGI compiler + # -r[0-9][0-9]* specify processor for the SGI compiler + # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler + # +DA*, +DD* enable 64-bit mode for the HP compiler + # -q* compiler args for the IBM compiler + # -m*, -t[45]*, -txscale* architecture-specific flags for GCC + # -F/path path to uninstalled frameworks, gcc on darwin + # -p, -pg, --coverage, -fprofile-* profiling flags for GCC + # @file GCC response files + # -tp=* Portland pgcc target processor selection + -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ + -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + func_append compile_command " $arg" + func_append finalize_command " $arg" + compiler_flags="$compiler_flags $arg" + continue + ;; + + # Some other compiler flag. + -* | +*) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + + *.$objext) + # A standard object. + objs="$objs $arg" + ;; + + *.lo) + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if func_lalib_unsafe_p "$arg"; then + pic_object= + non_pic_object= + + # Read the .lo file + func_source "$arg" + + if test -z "$pic_object" || + test -z "$non_pic_object" || + test "$pic_object" = none && + test "$non_pic_object" = none; then + func_fatal_error "cannot find name of object for \`$arg'" + fi + + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + dlfiles="$dlfiles $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + dlprefiles="$dlprefiles $pic_object" + prev= + fi + + # A PIC object. + func_append libobjs " $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + func_append non_pic_objects " $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object="$pic_object" + func_append non_pic_objects " $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if $opt_dry_run; then + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + func_lo2o "$arg" + pic_object=$xdir$objdir/$func_lo2o_result + non_pic_object=$xdir$func_lo2o_result + func_append libobjs " $pic_object" + func_append non_pic_objects " $non_pic_object" + else + func_fatal_error "\`$arg' is not a valid libtool object" + fi + fi + ;; + + *.$libext) + # An archive. + deplibs="$deplibs $arg" + old_deplibs="$old_deplibs $arg" + continue + ;; + + *.la) + # A libtool-controlled library. + + if test "$prev" = dlfiles; then + # This library was specified with -dlopen. + dlfiles="$dlfiles $arg" + prev= + elif test "$prev" = dlprefiles; then + # The library was specified with -dlpreopen. + dlprefiles="$dlprefiles $arg" + prev= + else + deplibs="$deplibs $arg" + fi + continue + ;; + + # Some other compiler argument. + *) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + esac # arg + + # Now actually substitute the argument into the commands. + if test -n "$arg"; then + func_append compile_command " $arg" + func_append finalize_command " $arg" + fi + done # argument parsing loop + + test -n "$prev" && \ + func_fatal_help "the \`$prevarg' option requires an argument" + + if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then + eval arg=\"$export_dynamic_flag_spec\" + func_append compile_command " $arg" + func_append finalize_command " $arg" + fi + + oldlibs= + # calculate the name of the file, without its directory + func_basename "$output" + outputname="$func_basename_result" + libobjs_save="$libobjs" + + if test -n "$shlibpath_var"; then + # get the directories listed in $shlibpath_var + eval shlib_search_path=\`\$ECHO \"\${$shlibpath_var}\" \| \$SED \'s/:/ /g\'\` + else + shlib_search_path= + fi + eval sys_lib_search_path=\"$sys_lib_search_path_spec\" + eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" + + func_dirname "$output" "/" "" + output_objdir="$func_dirname_result$objdir" + # Create the object directory. + func_mkdir_p "$output_objdir" + + # Determine the type of output + case $output in + "") + func_fatal_help "you must specify an output file" + ;; + *.$libext) linkmode=oldlib ;; + *.lo | *.$objext) linkmode=obj ;; + *.la) linkmode=lib ;; + *) linkmode=prog ;; # Anything else should be a program. + esac + + specialdeplibs= + + libs= + # Find all interdependent deplibs by searching for libraries + # that are linked more than once (e.g. -la -lb -la) + for deplib in $deplibs; do + if $opt_duplicate_deps ; then + case "$libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + libs="$libs $deplib" + done + + if test "$linkmode" = lib; then + libs="$predeps $libs $compiler_lib_search_path $postdeps" + + # Compute libraries that are listed more than once in $predeps + # $postdeps and mark them as special (i.e., whose duplicates are + # not to be eliminated). + pre_post_deps= + if $opt_duplicate_compiler_generated_deps; then + for pre_post_dep in $predeps $postdeps; do + case "$pre_post_deps " in + *" $pre_post_dep "*) specialdeplibs="$specialdeplibs $pre_post_deps" ;; + esac + pre_post_deps="$pre_post_deps $pre_post_dep" + done + fi + pre_post_deps= + fi + + deplibs= + newdependency_libs= + newlib_search_path= + need_relink=no # whether we're linking any uninstalled libtool libraries + notinst_deplibs= # not-installed libtool libraries + notinst_path= # paths that contain not-installed libtool libraries + + case $linkmode in + lib) + passes="conv dlpreopen link" + for file in $dlfiles $dlprefiles; do + case $file in + *.la) ;; + *) + func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file" + ;; + esac + done + ;; + prog) + compile_deplibs= + finalize_deplibs= + alldeplibs=no + newdlfiles= + newdlprefiles= + passes="conv scan dlopen dlpreopen link" + ;; + *) passes="conv" + ;; + esac + + for pass in $passes; do + # The preopen pass in lib mode reverses $deplibs; put it back here + # so that -L comes before libs that need it for instance... + if test "$linkmode,$pass" = "lib,link"; then + ## FIXME: Find the place where the list is rebuilt in the wrong + ## order, and fix it there properly + tmp_deplibs= + for deplib in $deplibs; do + tmp_deplibs="$deplib $tmp_deplibs" + done + deplibs="$tmp_deplibs" + fi + + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan"; then + libs="$deplibs" + deplibs= + fi + if test "$linkmode" = prog; then + case $pass in + dlopen) libs="$dlfiles" ;; + dlpreopen) libs="$dlprefiles" ;; + link) libs="$deplibs %DEPLIBS% $dependency_libs" ;; + esac + fi + if test "$linkmode,$pass" = "lib,dlpreopen"; then + # Collect and forward deplibs of preopened libtool libs + for lib in $dlprefiles; do + # Ignore non-libtool-libs + dependency_libs= + case $lib in + *.la) func_source "$lib" ;; + esac + + # Collect preopened libtool deplibs, except any this library + # has declared as weak libs + for deplib in $dependency_libs; do + func_basename "$deplib" + deplib_base=$func_basename_result + case " $weak_libs " in + *" $deplib_base "*) ;; + *) deplibs="$deplibs $deplib" ;; + esac + done + done + libs="$dlprefiles" + fi + if test "$pass" = dlopen; then + # Collect dlpreopened libraries + save_deplibs="$deplibs" + deplibs= + fi + + for deplib in $libs; do + lib= + found=no + case $deplib in + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads) + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + compiler_flags="$compiler_flags $deplib" + if test "$linkmode" = lib ; then + case "$new_inherited_linker_flags " in + *" $deplib "*) ;; + * ) new_inherited_linker_flags="$new_inherited_linker_flags $deplib" ;; + esac + fi + fi + continue + ;; + -l*) + if test "$linkmode" != lib && test "$linkmode" != prog; then + func_warning "\`-l' is ignored for archives/objects" + continue + fi + func_stripname '-l' '' "$deplib" + name=$func_stripname_result + if test "$linkmode" = lib; then + searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" + else + searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" + fi + for searchdir in $searchdirs; do + for search_ext in .la $std_shrext .so .a; do + # Search the libtool library + lib="$searchdir/lib${name}${search_ext}" + if test -f "$lib"; then + if test "$search_ext" = ".la"; then + found=yes + else + found=no + fi + break 2 + fi + done + done + if test "$found" != yes; then + # deplib doesn't seem to be a libtool library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + else # deplib is a libtool library + # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, + # We need to do some special things here, and not later. + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $deplib "*) + if func_lalib_p "$lib"; then + library_names= + old_library= + func_source "$lib" + for l in $old_library $library_names; do + ll="$l" + done + if test "X$ll" = "X$old_library" ; then # only static version available + found=no + func_dirname "$lib" "" "." + ladir="$func_dirname_result" + lib=$ladir/$old_library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + fi + fi + ;; + *) ;; + esac + fi + fi + ;; # -l + *.ltframework) + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + if test "$linkmode" = lib ; then + case "$new_inherited_linker_flags " in + *" $deplib "*) ;; + * ) new_inherited_linker_flags="$new_inherited_linker_flags $deplib" ;; + esac + fi + fi + continue + ;; + -L*) + case $linkmode in + lib) + deplibs="$deplib $deplibs" + test "$pass" = conv && continue + newdependency_libs="$deplib $newdependency_libs" + func_stripname '-L' '' "$deplib" + newlib_search_path="$newlib_search_path $func_stripname_result" + ;; + prog) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + if test "$pass" = scan; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + func_stripname '-L' '' "$deplib" + newlib_search_path="$newlib_search_path $func_stripname_result" + ;; + *) + func_warning "\`-L' is ignored for archives/objects" + ;; + esac # linkmode + continue + ;; # -L + -R*) + if test "$pass" = link; then + func_stripname '-R' '' "$deplib" + dir=$func_stripname_result + # Make sure the xrpath contains only unique directories. + case "$xrpath " in + *" $dir "*) ;; + *) xrpath="$xrpath $dir" ;; + esac + fi + deplibs="$deplib $deplibs" + continue + ;; + *.la) lib="$deplib" ;; + *.$libext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + case $linkmode in + lib) + # Linking convenience modules into shared libraries is allowed, + # but linking other static libraries is non-portable. + case " $dlpreconveniencelibs " in + *" $deplib "*) ;; + *) + valid_a_lib=no + case $deplibs_check_method in + match_pattern*) + set dummy $deplibs_check_method; shift + match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` + if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \ + | $EGREP "$match_pattern_regex" > /dev/null; then + valid_a_lib=yes + fi + ;; + pass_all) + valid_a_lib=yes + ;; + esac + if test "$valid_a_lib" != yes; then + echo + $ECHO "*** Warning: Trying to link with static lib archive $deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have" + echo "*** because the file extensions .$libext of this argument makes me believe" + echo "*** that it is just a static archive that I should not use here." + else + echo + $ECHO "*** Warning: Linking the shared library $output against the" + $ECHO "*** static library $deplib is not portable!" + deplibs="$deplib $deplibs" + fi + ;; + esac + continue + ;; + prog) + if test "$pass" != link; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + continue + ;; + esac # linkmode + ;; # *.$libext + *.lo | *.$objext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + elif test "$linkmode" = prog; then + if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then + # If there is no dlopen support or we're linking statically, + # we need to preload. + newdlprefiles="$newdlprefiles $deplib" + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + newdlfiles="$newdlfiles $deplib" + fi + fi + continue + ;; + %DEPLIBS%) + alldeplibs=yes + continue + ;; + esac # case $deplib + + if test "$found" = yes || test -f "$lib"; then : + else + func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'" + fi + + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$lib" \ + || func_fatal_error "\`$lib' is not a valid libtool archive" + + func_dirname "$lib" "" "." + ladir="$func_dirname_result" + + dlname= + dlopen= + dlpreopen= + libdir= + library_names= + old_library= + inherited_linker_flags= + # If the library was installed with an old release of libtool, + # it will not redefine variables installed, or shouldnotlink + installed=yes + shouldnotlink=no + avoidtemprpath= + + + # Read the .la file + func_source "$lib" + + # Convert "-framework foo" to "foo.ltframework" + if test -n "$inherited_linker_flags"; then + tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'` + for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do + case " $new_inherited_linker_flags " in + *" $tmp_inherited_linker_flag "*) ;; + *) new_inherited_linker_flags="$new_inherited_linker_flags $tmp_inherited_linker_flag";; + esac + done + fi + dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan" || + { test "$linkmode" != prog && test "$linkmode" != lib; }; then + test -n "$dlopen" && dlfiles="$dlfiles $dlopen" + test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen" + fi + + if test "$pass" = conv; then + # Only check for convenience libraries + deplibs="$lib $deplibs" + if test -z "$libdir"; then + if test -z "$old_library"; then + func_fatal_error "cannot find name of link library for \`$lib'" + fi + # It is a libtool convenience library, so add in its objects. + convenience="$convenience $ladir/$objdir/$old_library" + old_convenience="$old_convenience $ladir/$objdir/$old_library" + elif test "$linkmode" != prog && test "$linkmode" != lib; then + func_fatal_error "\`$lib' is not a convenience library" + fi + tmp_libs= + for deplib in $dependency_libs; do + deplibs="$deplib $deplibs" + if $opt_duplicate_deps ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done + continue + fi # $pass = conv + + + # Get the name of the library we link against. + linklib= + for l in $old_library $library_names; do + linklib="$l" + done + if test -z "$linklib"; then + func_fatal_error "cannot find name of link library for \`$lib'" + fi + + # This library was specified with -dlopen. + if test "$pass" = dlopen; then + if test -z "$libdir"; then + func_fatal_error "cannot -dlopen a convenience library: \`$lib'" + fi + if test -z "$dlname" || + test "$dlopen_support" != yes || + test "$build_libtool_libs" = no; then + # If there is no dlname, no dlopen support or we're linking + # statically, we need to preload. We also need to preload any + # dependent libraries so libltdl's deplib preloader doesn't + # bomb out in the load deplibs phase. + dlprefiles="$dlprefiles $lib $dependency_libs" + else + newdlfiles="$newdlfiles $lib" + fi + continue + fi # $pass = dlopen + + # We need an absolute path. + case $ladir in + [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; + *) + abs_ladir=`cd "$ladir" && pwd` + if test -z "$abs_ladir"; then + func_warning "cannot determine absolute directory name of \`$ladir'" + func_warning "passing it literally to the linker, although it might fail" + abs_ladir="$ladir" + fi + ;; + esac + func_basename "$lib" + laname="$func_basename_result" + + # Find the relevant object directory and library name. + if test "X$installed" = Xyes; then + if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then + func_warning "library \`$lib' was moved." + dir="$ladir" + absdir="$abs_ladir" + libdir="$abs_ladir" + else + dir="$libdir" + absdir="$libdir" + fi + test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes + else + if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then + dir="$ladir" + absdir="$abs_ladir" + # Remove this search path later + notinst_path="$notinst_path $abs_ladir" + else + dir="$ladir/$objdir" + absdir="$abs_ladir/$objdir" + # Remove this search path later + notinst_path="$notinst_path $abs_ladir" + fi + fi # $installed = yes + func_stripname 'lib' '.la' "$laname" + name=$func_stripname_result + + # This library was specified with -dlpreopen. + if test "$pass" = dlpreopen; then + if test -z "$libdir" && test "$linkmode" = prog; then + func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'" + fi + # Prefer using a static library (so that no silly _DYNAMIC symbols + # are required to link). + if test -n "$old_library"; then + newdlprefiles="$newdlprefiles $dir/$old_library" + # Keep a list of preopened convenience libraries to check + # that they are being used correctly in the link pass. + test -z "$libdir" && \ + dlpreconveniencelibs="$dlpreconveniencelibs $dir/$old_library" + # Otherwise, use the dlname, so that lt_dlopen finds it. + elif test -n "$dlname"; then + newdlprefiles="$newdlprefiles $dir/$dlname" + else + newdlprefiles="$newdlprefiles $dir/$linklib" + fi + fi # $pass = dlpreopen + + if test -z "$libdir"; then + # Link the convenience library + if test "$linkmode" = lib; then + deplibs="$dir/$old_library $deplibs" + elif test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$dir/$old_library $compile_deplibs" + finalize_deplibs="$dir/$old_library $finalize_deplibs" + else + deplibs="$lib $deplibs" # used for prog,scan pass + fi + continue + fi + + + if test "$linkmode" = prog && test "$pass" != link; then + newlib_search_path="$newlib_search_path $ladir" + deplibs="$lib $deplibs" + + linkalldeplibs=no + if test "$link_all_deplibs" != no || test -z "$library_names" || + test "$build_libtool_libs" = no; then + linkalldeplibs=yes + fi + + tmp_libs= + for deplib in $dependency_libs; do + case $deplib in + -L*) func_stripname '-L' '' "$deplib" + newlib_search_path="$newlib_search_path $func_stripname_result" + ;; + esac + # Need to link against all dependency_libs? + if test "$linkalldeplibs" = yes; then + deplibs="$deplib $deplibs" + else + # Need to hardcode shared library paths + # or/and link against static libraries + newdependency_libs="$deplib $newdependency_libs" + fi + if $opt_duplicate_deps ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done # for deplib + continue + fi # $linkmode = prog... + + if test "$linkmode,$pass" = "prog,link"; then + if test -n "$library_names" && + { { test "$prefer_static_libs" = no || + test "$prefer_static_libs,$installed" = "built,yes"; } || + test -z "$old_library"; }; then + # We need to hardcode the library path + if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then + # Make sure the rpath contains only unique directories. + case "$temp_rpath:" in + *"$absdir:"*) ;; + *) temp_rpath="$temp_rpath$absdir:" ;; + esac + fi + + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) compile_rpath="$compile_rpath $absdir" + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" + esac + ;; + esac + fi # $linkmode,$pass = prog,link... + + if test "$alldeplibs" = yes && + { test "$deplibs_check_method" = pass_all || + { test "$build_libtool_libs" = yes && + test -n "$library_names"; }; }; then + # We only need to search for static libraries + continue + fi + fi + + link_static=no # Whether the deplib will be linked statically + use_static_libs=$prefer_static_libs + if test "$use_static_libs" = built && test "$installed" = yes; then + use_static_libs=no + fi + if test -n "$library_names" && + { test "$use_static_libs" = no || test -z "$old_library"; }; then + case $host in + *cygwin* | *mingw* | *cegcc*) + # No point in relinking DLLs because paths are not encoded + notinst_deplibs="$notinst_deplibs $lib" + need_relink=no + ;; + *) + if test "$installed" = no; then + notinst_deplibs="$notinst_deplibs $lib" + need_relink=yes + fi + ;; + esac + # This is a shared library + + # Warn about portability, can't link against -module's on some + # systems (darwin). Don't bleat about dlopened modules though! + dlopenmodule="" + for dlpremoduletest in $dlprefiles; do + if test "X$dlpremoduletest" = "X$lib"; then + dlopenmodule="$dlpremoduletest" + break + fi + done + if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then + echo + if test "$linkmode" = prog; then + $ECHO "*** Warning: Linking the executable $output against the loadable module" + else + $ECHO "*** Warning: Linking the shared library $output against the loadable module" + fi + $ECHO "*** $linklib is not portable!" + fi + if test "$linkmode" = lib && + test "$hardcode_into_libs" = yes; then + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) compile_rpath="$compile_rpath $absdir" + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" + esac + ;; + esac + fi + + if test -n "$old_archive_from_expsyms_cmds"; then + # figure out the soname + set dummy $library_names + shift + realname="$1" + shift + libname=`eval "\\$ECHO \"$libname_spec\""` + # use dlname if we got it. it's perfectly good, no? + if test -n "$dlname"; then + soname="$dlname" + elif test -n "$soname_spec"; then + # bleh windows + case $host in + *cygwin* | mingw* | *cegcc*) + func_arith $current - $age + major=$func_arith_result + versuffix="-$major" + ;; + esac + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + + # Make a new name for the extract_expsyms_cmds to use + soroot="$soname" + func_basename "$soroot" + soname="$func_basename_result" + func_stripname 'lib' '.dll' "$soname" + newlib=libimp-$func_stripname_result.a + + # If the library has no export list, then create one now + if test -f "$output_objdir/$soname-def"; then : + else + func_verbose "extracting exported symbol list from \`$soname'" + func_execute_cmds "$extract_expsyms_cmds" 'exit $?' + fi + + # Create $newlib + if test -f "$output_objdir/$newlib"; then :; else + func_verbose "generating import library for \`$soname'" + func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?' + fi + # make sure the library variables are pointing to the new library + dir=$output_objdir + linklib=$newlib + fi # test -n "$old_archive_from_expsyms_cmds" + + if test "$linkmode" = prog || test "$mode" != relink; then + add_shlibpath= + add_dir= + add= + lib_linked=yes + case $hardcode_action in + immediate | unsupported) + if test "$hardcode_direct" = no; then + add="$dir/$linklib" + case $host in + *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;; + *-*-sysv4*uw2*) add_dir="-L$dir" ;; + *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ + *-*-unixware7*) add_dir="-L$dir" ;; + *-*-darwin* ) + # if the lib is a (non-dlopened) module then we can not + # link against it, someone is ignoring the earlier warnings + if /usr/bin/file -L $add 2> /dev/null | + $GREP ": [^:]* bundle" >/dev/null ; then + if test "X$dlopenmodule" != "X$lib"; then + $ECHO "*** Warning: lib $linklib is a module, not a shared library" + if test -z "$old_library" ; then + echo + echo "*** And there doesn't seem to be a static archive available" + echo "*** The link will probably fail, sorry" + else + add="$dir/$old_library" + fi + elif test -n "$old_library"; then + add="$dir/$old_library" + fi + fi + esac + elif test "$hardcode_minus_L" = no; then + case $host in + *-*-sunos*) add_shlibpath="$dir" ;; + esac + add_dir="-L$dir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = no; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + relink) + if test "$hardcode_direct" = yes && + test "$hardcode_direct_absolute" = no; then + add="$dir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$dir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + add_dir="$add_dir -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + *) lib_linked=no ;; + esac + + if test "$lib_linked" != yes; then + func_fatal_configuration "unsupported hardcode properties" + fi + + if test -n "$add_shlibpath"; then + case :$compile_shlibpath: in + *":$add_shlibpath:"*) ;; + *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;; + esac + fi + if test "$linkmode" = prog; then + test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" + test -n "$add" && compile_deplibs="$add $compile_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + if test "$hardcode_direct" != yes && + test "$hardcode_minus_L" != yes && + test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; + esac + fi + fi + fi + + if test "$linkmode" = prog || test "$mode" = relink; then + add_shlibpath= + add_dir= + add= + # Finalize command for both is simple: just hardcode it. + if test "$hardcode_direct" = yes && + test "$hardcode_direct_absolute" = no; then + add="$libdir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$libdir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; + esac + add="-l$name" + elif test "$hardcode_automatic" = yes; then + if test -n "$inst_prefix_dir" && + test -f "$inst_prefix_dir$libdir/$linklib" ; then + add="$inst_prefix_dir$libdir/$linklib" + else + add="$libdir/$linklib" + fi + else + # We cannot seem to hardcode it, guess we'll fake it. + add_dir="-L$libdir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + add_dir="$add_dir -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + fi + + if test "$linkmode" = prog; then + test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" + test -n "$add" && finalize_deplibs="$add $finalize_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + fi + fi + elif test "$linkmode" = prog; then + # Here we assume that one of hardcode_direct or hardcode_minus_L + # is not unsupported. This is valid on all known static and + # shared platforms. + if test "$hardcode_direct" != unsupported; then + test -n "$old_library" && linklib="$old_library" + compile_deplibs="$dir/$linklib $compile_deplibs" + finalize_deplibs="$dir/$linklib $finalize_deplibs" + else + compile_deplibs="-l$name -L$dir $compile_deplibs" + finalize_deplibs="-l$name -L$dir $finalize_deplibs" + fi + elif test "$build_libtool_libs" = yes; then + # Not a shared library + if test "$deplibs_check_method" != pass_all; then + # We're trying link a shared library against a static one + # but the system doesn't support it. + + # Just print a warning and add the library to dependency_libs so + # that the program can be linked against the static library. + echo + $ECHO "*** Warning: This system can not link to static lib archive $lib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have." + if test "$module" = yes; then + echo "*** But as you try to build a module library, libtool will still create " + echo "*** a static module, that should work as long as the dlopening application" + echo "*** is linked with the -dlopen flag to resolve symbols at runtime." + if test -z "$global_symbol_pipe"; then + echo + echo "*** However, this would only work if libtool was able to extract symbol" + echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + echo "*** not find such a program. So, this module is probably useless." + echo "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + else + deplibs="$dir/$old_library $deplibs" + link_static=yes + fi + fi # link shared/static library? + + if test "$linkmode" = lib; then + if test -n "$dependency_libs" && + { test "$hardcode_into_libs" != yes || + test "$build_old_libs" = yes || + test "$link_static" = yes; }; then + # Extract -R from dependency_libs + temp_deplibs= + for libdir in $dependency_libs; do + case $libdir in + -R*) func_stripname '-R' '' "$libdir" + temp_xrpath=$func_stripname_result + case " $xrpath " in + *" $temp_xrpath "*) ;; + *) xrpath="$xrpath $temp_xrpath";; + esac;; + *) temp_deplibs="$temp_deplibs $libdir";; + esac + done + dependency_libs="$temp_deplibs" + fi + + newlib_search_path="$newlib_search_path $absdir" + # Link against this library + test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" + # ... and its dependency_libs + tmp_libs= + for deplib in $dependency_libs; do + newdependency_libs="$deplib $newdependency_libs" + if $opt_duplicate_deps ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done + + if test "$link_all_deplibs" != no; then + # Add the search paths of all dependency libraries + for deplib in $dependency_libs; do + path= + case $deplib in + -L*) path="$deplib" ;; + *.la) + func_dirname "$deplib" "" "." + dir="$func_dirname_result" + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + func_warning "cannot determine absolute directory name of \`$dir'" + absdir="$dir" + fi + ;; + esac + if $GREP "^installed=no" $deplib > /dev/null; then + case $host in + *-*-darwin*) + depdepl= + eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` + if test -n "$deplibrary_names" ; then + for tmp in $deplibrary_names ; do + depdepl=$tmp + done + if test -f "$absdir/$objdir/$depdepl" ; then + depdepl="$absdir/$objdir/$depdepl" + darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` + if test -z "$darwin_install_name"; then + darwin_install_name=`${OTOOL64} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` + fi + compiler_flags="$compiler_flags ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}" + linker_flags="$linker_flags -dylib_file ${darwin_install_name}:${depdepl}" + path= + fi + fi + ;; + *) + path="-L$absdir/$objdir" + ;; + esac + else + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + test -z "$libdir" && \ + func_fatal_error "\`$deplib' is not a valid libtool archive" + test "$absdir" != "$libdir" && \ + func_warning "\`$deplib' seems to be moved" + + path="-L$absdir" + fi + ;; + esac + case " $deplibs " in + *" $path "*) ;; + *) deplibs="$path $deplibs" ;; + esac + done + fi # link_all_deplibs != no + fi # linkmode = lib + done # for deplib in $libs + if test "$pass" = link; then + if test "$linkmode" = "prog"; then + compile_deplibs="$new_inherited_linker_flags $compile_deplibs" + finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs" + else + compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + fi + fi + dependency_libs="$newdependency_libs" + if test "$pass" = dlpreopen; then + # Link the dlpreopened libraries before other libraries + for deplib in $save_deplibs; do + deplibs="$deplib $deplibs" + done + fi + if test "$pass" != dlopen; then + if test "$pass" != conv; then + # Make sure lib_search_path contains only unique directories. + lib_search_path= + for dir in $newlib_search_path; do + case "$lib_search_path " in + *" $dir "*) ;; + *) lib_search_path="$lib_search_path $dir" ;; + esac + done + newlib_search_path= + fi + + if test "$linkmode,$pass" != "prog,link"; then + vars="deplibs" + else + vars="compile_deplibs finalize_deplibs" + fi + for var in $vars dependency_libs; do + # Add libraries to $var in reverse order + eval tmp_libs=\"\$$var\" + new_libs= + for deplib in $tmp_libs; do + # FIXME: Pedantically, this is the right thing to do, so + # that some nasty dependency loop isn't accidentally + # broken: + #new_libs="$deplib $new_libs" + # Pragmatically, this seems to cause very few problems in + # practice: + case $deplib in + -L*) new_libs="$deplib $new_libs" ;; + -R*) ;; + *) + # And here is the reason: when a library appears more + # than once as an explicit dependence of a library, or + # is implicitly linked in more than once by the + # compiler, it is considered special, and multiple + # occurrences thereof are not removed. Compare this + # with having the same library being listed as a + # dependency of multiple other libraries: in this case, + # we know (pedantically, we assume) the library does not + # need to be listed more than once, so we keep only the + # last copy. This is not always right, but it is rare + # enough that we require users that really mean to play + # such unportable linking tricks to link the library + # using -Wl,-lname, so that libtool does not consider it + # for duplicate removal. + case " $specialdeplibs " in + *" $deplib "*) new_libs="$deplib $new_libs" ;; + *) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$deplib $new_libs" ;; + esac + ;; + esac + ;; + esac + done + tmp_libs= + for deplib in $new_libs; do + case $deplib in + -L*) + case " $tmp_libs " in + *" $deplib "*) ;; + *) tmp_libs="$tmp_libs $deplib" ;; + esac + ;; + *) tmp_libs="$tmp_libs $deplib" ;; + esac + done + eval $var=\"$tmp_libs\" + done # for var + fi + # Last step: remove runtime libs from dependency_libs + # (they stay in deplibs) + tmp_libs= + for i in $dependency_libs ; do + case " $predeps $postdeps $compiler_lib_search_path " in + *" $i "*) + i="" + ;; + esac + if test -n "$i" ; then + tmp_libs="$tmp_libs $i" + fi + done + dependency_libs=$tmp_libs + done # for pass + if test "$linkmode" = prog; then + dlfiles="$newdlfiles" + fi + if test "$linkmode" = prog || test "$linkmode" = lib; then + dlprefiles="$newdlprefiles" + fi + + case $linkmode in + oldlib) + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + func_warning "\`-dlopen' is ignored for archives" + fi + + case " $deplibs" in + *\ -l* | *\ -L*) + func_warning "\`-l' and \`-L' are ignored for archives" ;; + esac + + test -n "$rpath" && \ + func_warning "\`-rpath' is ignored for archives" + + test -n "$xrpath" && \ + func_warning "\`-R' is ignored for archives" + + test -n "$vinfo" && \ + func_warning "\`-version-info/-version-number' is ignored for archives" + + test -n "$release" && \ + func_warning "\`-release' is ignored for archives" + + test -n "$export_symbols$export_symbols_regex" && \ + func_warning "\`-export-symbols' is ignored for archives" + + # Now set the variables for building old libraries. + build_libtool_libs=no + oldlibs="$output" + objs="$objs$old_deplibs" + ;; + + lib) + # Make sure we only generate libraries of the form `libNAME.la'. + case $outputname in + lib*) + func_stripname 'lib' '.la' "$outputname" + name=$func_stripname_result + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + ;; + *) + test "$module" = no && \ + func_fatal_help "libtool library \`$output' must begin with \`lib'" + + if test "$need_lib_prefix" != no; then + # Add the "lib" prefix for modules if required + func_stripname '' '.la' "$outputname" + name=$func_stripname_result + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + else + func_stripname '' '.la' "$outputname" + libname=$func_stripname_result + fi + ;; + esac + + if test -n "$objs"; then + if test "$deplibs_check_method" != pass_all; then + func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs" + else + echo + $ECHO "*** Warning: Linking the shared library $output against the non-libtool" + $ECHO "*** objects $objs is not portable!" + libobjs="$libobjs $objs" + fi + fi + + test "$dlself" != no && \ + func_warning "\`-dlopen self' is ignored for libtool libraries" + + set dummy $rpath + shift + test "$#" -gt 1 && \ + func_warning "ignoring multiple \`-rpath's for a libtool library" + + install_libdir="$1" + + oldlibs= + if test -z "$rpath"; then + if test "$build_libtool_libs" = yes; then + # Building a libtool convenience library. + # Some compilers have problems with a `.al' extension so + # convenience libraries should have the same extension an + # archive normally would. + oldlibs="$output_objdir/$libname.$libext $oldlibs" + build_libtool_libs=convenience + build_old_libs=yes + fi + + test -n "$vinfo" && \ + func_warning "\`-version-info/-version-number' is ignored for convenience libraries" + + test -n "$release" && \ + func_warning "\`-release' is ignored for convenience libraries" + else + + # Parse the version information argument. + save_ifs="$IFS"; IFS=':' + set dummy $vinfo 0 0 0 + shift + IFS="$save_ifs" + + test -n "$7" && \ + func_fatal_help "too many parameters to \`-version-info'" + + # convert absolute version numbers to libtool ages + # this retains compatibility with .la files and attempts + # to make the code below a bit more comprehensible + + case $vinfo_number in + yes) + number_major="$1" + number_minor="$2" + number_revision="$3" + # + # There are really only two kinds -- those that + # use the current revision as the major version + # and those that subtract age and use age as + # a minor version. But, then there is irix + # which has an extra 1 added just for fun + # + case $version_type in + darwin|linux|osf|windows|none) + func_arith $number_major + $number_minor + current=$func_arith_result + age="$number_minor" + revision="$number_revision" + ;; + freebsd-aout|freebsd-elf|qnx|sunos) + current="$number_major" + revision="$number_minor" + age="0" + ;; + irix|nonstopux) + func_arith $number_major + $number_minor + current=$func_arith_result + age="$number_minor" + revision="$number_minor" + lt_irix_increment=no + ;; + esac + ;; + no) + current="$1" + revision="$2" + age="$3" + ;; + esac + + # Check that each of the things are valid numbers. + case $current in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "CURRENT \`$current' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + case $revision in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "REVISION \`$revision' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + case $age in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "AGE \`$age' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + if test "$age" -gt "$current"; then + func_error "AGE \`$age' is greater than the current interface number \`$current'" + func_fatal_error "\`$vinfo' is not valid version information" + fi + + # Calculate the version variables. + major= + versuffix= + verstring= + case $version_type in + none) ;; + + darwin) + # Like Linux, but with the current version available in + # verstring for coding it into the library header + func_arith $current - $age + major=.$func_arith_result + versuffix="$major.$age.$revision" + # Darwin ld doesn't like 0 for these options... + func_arith $current + 1 + minor_current=$func_arith_result + xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision" + verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" + ;; + + freebsd-aout) + major=".$current" + versuffix=".$current.$revision"; + ;; + + freebsd-elf) + major=".$current" + versuffix=".$current" + ;; + + irix | nonstopux) + if test "X$lt_irix_increment" = "Xno"; then + func_arith $current - $age + else + func_arith $current - $age + 1 + fi + major=$func_arith_result + + case $version_type in + nonstopux) verstring_prefix=nonstopux ;; + *) verstring_prefix=sgi ;; + esac + verstring="$verstring_prefix$major.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$revision + while test "$loop" -ne 0; do + func_arith $revision - $loop + iface=$func_arith_result + func_arith $loop - 1 + loop=$func_arith_result + verstring="$verstring_prefix$major.$iface:$verstring" + done + + # Before this point, $major must not contain `.'. + major=.$major + versuffix="$major.$revision" + ;; + + linux) + func_arith $current - $age + major=.$func_arith_result + versuffix="$major.$age.$revision" + ;; + + osf) + func_arith $current - $age + major=.$func_arith_result + versuffix=".$current.$age.$revision" + verstring="$current.$age.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$age + while test "$loop" -ne 0; do + func_arith $current - $loop + iface=$func_arith_result + func_arith $loop - 1 + loop=$func_arith_result + verstring="$verstring:${iface}.0" + done + + # Make executables depend on our current version. + verstring="$verstring:${current}.0" + ;; + + qnx) + major=".$current" + versuffix=".$current" + ;; + + sunos) + major=".$current" + versuffix=".$current.$revision" + ;; + + windows) + # Use '-' rather than '.', since we only want one + # extension on DOS 8.3 filesystems. + func_arith $current - $age + major=$func_arith_result + versuffix="-$major" + ;; + + *) + func_fatal_configuration "unknown library version type \`$version_type'" + ;; + esac + + # Clear the version info if we defaulted, and they specified a release. + if test -z "$vinfo" && test -n "$release"; then + major= + case $version_type in + darwin) + # we can't check for "0.0" in archive_cmds due to quoting + # problems, so we reset it completely + verstring= + ;; + *) + verstring="0.0" + ;; + esac + if test "$need_version" = no; then + versuffix= + else + versuffix=".0.0" + fi + fi + + # Remove version info from name if versioning should be avoided + if test "$avoid_version" = yes && test "$need_version" = no; then + major= + versuffix= + verstring="" + fi + + # Check to see if the archive will have undefined symbols. + if test "$allow_undefined" = yes; then + if test "$allow_undefined_flag" = unsupported; then + func_warning "undefined symbols not allowed in $host shared libraries" + build_libtool_libs=no + build_old_libs=yes + fi + else + # Don't allow undefined symbols. + allow_undefined_flag="$no_undefined_flag" + fi + + fi + + func_generate_dlsyms "$libname" "$libname" "yes" + libobjs="$libobjs $symfileobj" + test "X$libobjs" = "X " && libobjs= + + if test "$mode" != relink; then + # Remove our outputs, but don't remove object files since they + # may have been created when compiling PIC objects. + removelist= + tempremovelist=`$ECHO "$output_objdir/*"` + for p in $tempremovelist; do + case $p in + *.$objext | *.gcno) + ;; + $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) + if test "X$precious_files_regex" != "X"; then + if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 + then + continue + fi + fi + removelist="$removelist $p" + ;; + *) ;; + esac + done + test -n "$removelist" && \ + func_show_eval "${RM}r \$removelist" + fi + + # Now set the variables for building old libraries. + if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then + oldlibs="$oldlibs $output_objdir/$libname.$libext" + + # Transform .lo files to .o files. + oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; $lo2o" | $NL2SP` + fi + + # Eliminate all temporary directories. + #for path in $notinst_path; do + # lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"` + # deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"` + # dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"` + #done + + if test -n "$xrpath"; then + # If the user specified any rpath flags, then add them. + temp_xrpath= + for libdir in $xrpath; do + temp_xrpath="$temp_xrpath -R$libdir" + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" ;; + esac + done + if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then + dependency_libs="$temp_xrpath $dependency_libs" + fi + fi + + # Make sure dlfiles contains only unique files that won't be dlpreopened + old_dlfiles="$dlfiles" + dlfiles= + for lib in $old_dlfiles; do + case " $dlprefiles $dlfiles " in + *" $lib "*) ;; + *) dlfiles="$dlfiles $lib" ;; + esac + done + + # Make sure dlprefiles contains only unique files + old_dlprefiles="$dlprefiles" + dlprefiles= + for lib in $old_dlprefiles; do + case "$dlprefiles " in + *" $lib "*) ;; + *) dlprefiles="$dlprefiles $lib" ;; + esac + done + + if test "$build_libtool_libs" = yes; then + if test -n "$rpath"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*) + # these systems don't actually have a c library (as such)! + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C library is in the System framework + deplibs="$deplibs System.ltframework" + ;; + *-*-netbsd*) + # Don't link with libc until the a.out ld.so is fixed. + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + ;; + *) + # Add libc to deplibs on all other systems if necessary. + if test "$build_libtool_need_lc" = "yes"; then + deplibs="$deplibs -lc" + fi + ;; + esac + fi + + # Transform deplibs into only deplibs that can be linked in shared. + name_save=$name + libname_save=$libname + release_save=$release + versuffix_save=$versuffix + major_save=$major + # I'm not sure if I'm treating the release correctly. I think + # release should show up in the -l (ie -lgmp5) so we don't want to + # add it in twice. Is that correct? + release="" + versuffix="" + major="" + newdeplibs= + droppeddeps=no + case $deplibs_check_method in + pass_all) + # Don't check for shared/static. Everything works. + # This might be a little naive. We might want to check + # whether the library exists or not. But this is on + # osf3 & osf4 and I'm not really sure... Just + # implementing what was already the behavior. + newdeplibs=$deplibs + ;; + test_compile) + # This code stresses the "libraries are programs" paradigm to its + # limits. Maybe even breaks it. We compile a program, linking it + # against the deplibs as a proxy for the library. Then we can check + # whether they linked in statically or dynamically with ldd. + $opt_dry_run || $RM conftest.c + cat > conftest.c </dev/null` + for potent_lib in $potential_libs; do + # Follow soft links. + if ls -lLd "$potent_lib" 2>/dev/null | + $GREP " -> " >/dev/null; then + continue + fi + # The statement above tries to avoid entering an + # endless loop below, in case of cyclic links. + # We might still enter an endless loop, since a link + # loop can be closed while we follow links, + # but so what? + potlib="$potent_lib" + while test -h "$potlib" 2>/dev/null; do + potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` + case $potliblink in + [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; + *) potlib=`$ECHO "$potlib" | $SED 's,[^/]*$,,'`"$potliblink";; + esac + done + if eval $file_magic_cmd \"\$potlib\" 2>/dev/null | + $SED -e 10q | + $EGREP "$file_magic_regex" > /dev/null; then + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + echo + $ECHO "*** Warning: linker path does not have real file for library $a_deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have" + echo "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $ECHO "*** with $libname but no candidates were found. (...for file magic test)" + else + $ECHO "*** with $libname and none of the candidates passed a file format test" + $ECHO "*** using a file magic. Last file checked: $potlib" + fi + fi + ;; + *) + # Add a -L argument. + newdeplibs="$newdeplibs $a_deplib" + ;; + esac + done # Gone through all deplibs. + ;; + match_pattern*) + set dummy $deplibs_check_method; shift + match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` + for a_deplib in $deplibs; do + case $a_deplib in + -l*) + func_stripname -l '' "$a_deplib" + name=$func_stripname_result + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $a_deplib "*) + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + ;; + esac + fi + if test -n "$a_deplib" ; then + libname=`eval "\\$ECHO \"$libname_spec\""` + for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do + potential_libs=`ls $i/$libname[.-]* 2>/dev/null` + for potent_lib in $potential_libs; do + potlib="$potent_lib" # see symlink-check above in file_magic test + if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \ + $EGREP "$match_pattern_regex" > /dev/null; then + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + echo + $ECHO "*** Warning: linker path does not have real file for library $a_deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have" + echo "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)" + else + $ECHO "*** with $libname and none of the candidates passed a file format test" + $ECHO "*** using a regex pattern. Last file checked: $potlib" + fi + fi + ;; + *) + # Add a -L argument. + newdeplibs="$newdeplibs $a_deplib" + ;; + esac + done # Gone through all deplibs. + ;; + none | unknown | *) + newdeplibs="" + tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'` + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + for i in $predeps $postdeps ; do + # can't use Xsed below, because $i might contain '/' + tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s,$i,,"` + done + fi + case $tmp_deplibs in + *[!\ \ ]*) + echo + if test "X$deplibs_check_method" = "Xnone"; then + echo "*** Warning: inter-library dependencies are not supported in this platform." + else + echo "*** Warning: inter-library dependencies are not known to be supported." + fi + echo "*** All declared inter-library dependencies are being dropped." + droppeddeps=yes + ;; + esac + ;; + esac + versuffix=$versuffix_save + major=$major_save + release=$release_save + libname=$libname_save + name=$name_save + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library with the System framework + newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'` + ;; + esac + + if test "$droppeddeps" = yes; then + if test "$module" = yes; then + echo + echo "*** Warning: libtool could not satisfy all declared inter-library" + $ECHO "*** dependencies of module $libname. Therefore, libtool will create" + echo "*** a static module, that should work as long as the dlopening" + echo "*** application is linked with the -dlopen flag." + if test -z "$global_symbol_pipe"; then + echo + echo "*** However, this would only work if libtool was able to extract symbol" + echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + echo "*** not find such a program. So, this module is probably useless." + echo "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + else + echo "*** The inter-library dependencies that have been dropped here will be" + echo "*** automatically added whenever a program is linked with this library" + echo "*** or is declared to -dlopen it." + + if test "$allow_undefined" = no; then + echo + echo "*** Since this library must not contain undefined symbols," + echo "*** because either the platform does not support them or" + echo "*** it was explicitly requested with -no-undefined," + echo "*** libtool will only create a static version of it." + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + fi + fi + # Done checking deplibs! + deplibs=$newdeplibs + fi + # Time to change all our "foo.ltframework" stuff back to "-framework foo" + case $host in + *-*-darwin*) + newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + ;; + esac + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $deplibs " in + *" -L$path/$objdir "*) + new_libs="$new_libs -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$new_libs $deplib" ;; + esac + ;; + *) new_libs="$new_libs $deplib" ;; + esac + done + deplibs="$new_libs" + + # All the library-specific variables (install_libdir is set above). + library_names= + old_library= + dlname= + + # Test again, we may have decided not to build it any more + if test "$build_libtool_libs" = yes; then + if test "$hardcode_into_libs" = yes; then + # Hardcode the library paths + hardcode_libdirs= + dep_rpath= + rpath="$finalize_rpath" + test "$mode" != relink && rpath="$compile_rpath$rpath" + for libdir in $rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + dep_rpath="$dep_rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + if test -n "$hardcode_libdir_flag_spec_ld"; then + eval dep_rpath=\"$hardcode_libdir_flag_spec_ld\" + else + eval dep_rpath=\"$hardcode_libdir_flag_spec\" + fi + fi + if test -n "$runpath_var" && test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" + fi + test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" + fi + + shlibpath="$finalize_shlibpath" + test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath" + if test -n "$shlibpath"; then + eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" + fi + + # Get the real and link names of the library. + eval shared_ext=\"$shrext_cmds\" + eval library_names=\"$library_names_spec\" + set dummy $library_names + shift + realname="$1" + shift + + if test -n "$soname_spec"; then + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + if test -z "$dlname"; then + dlname=$soname + fi + + lib="$output_objdir/$realname" + linknames= + for link + do + linknames="$linknames $link" + done + + # Use standard objects if they are pic + test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP` + test "X$libobjs" = "X " && libobjs= + + delfiles= + if test -n "$export_symbols" && test -n "$include_expsyms"; then + $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp" + export_symbols="$output_objdir/$libname.uexp" + delfiles="$delfiles $export_symbols" + fi + + orig_export_symbols= + case $host_os in + cygwin* | mingw* | cegcc*) + if test -n "$export_symbols" && test -z "$export_symbols_regex"; then + # exporting using user supplied symfile + if test "x`$SED 1q $export_symbols`" != xEXPORTS; then + # and it's NOT already a .def file. Must figure out + # which of the given symbols are data symbols and tag + # them as such. So, trigger use of export_symbols_cmds. + # export_symbols gets reassigned inside the "prepare + # the list of exported symbols" if statement, so the + # include_expsyms logic still works. + orig_export_symbols="$export_symbols" + export_symbols= + always_export_symbols=yes + fi + fi + ;; + esac + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then + func_verbose "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $opt_dry_run || $RM $export_symbols + cmds=$export_symbols_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + func_len " $cmd" + len=$func_len_result + if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + func_show_eval "$cmd" 'exit $?' + skipped_export=false + else + # The command line is too long to execute in one step. + func_verbose "using reloadable object file for export list..." + skipped_export=: + # Break out early, otherwise skipped_export may be + # set to false by a later but shorter cmd. + break + fi + done + IFS="$save_ifs" + if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then + func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + func_show_eval '$MV "${export_symbols}T" "$export_symbols"' + fi + fi + fi + + if test -n "$export_symbols" && test -n "$include_expsyms"; then + tmp_export_symbols="$export_symbols" + test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" + $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' + fi + + if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then + # The given exports_symbols file has to be filtered, so filter it. + func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" + # FIXME: $output_objdir/$libname.filter potentially contains lots of + # 's' commands which not all seds can handle. GNU sed should be fine + # though. Also, the filter scales superlinearly with the number of + # global variables. join(1) would be nice here, but unfortunately + # isn't a blessed tool. + $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter + delfiles="$delfiles $export_symbols $output_objdir/$libname.filter" + export_symbols=$output_objdir/$libname.def + $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols + fi + + tmp_deplibs= + for test_deplib in $deplibs; do + case " $convenience " in + *" $test_deplib "*) ;; + *) + tmp_deplibs="$tmp_deplibs $test_deplib" + ;; + esac + done + deplibs="$tmp_deplibs" + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec" && + test "$compiler_needs_object" = yes && + test -z "$libobjs"; then + # extract the archives, so we have objects to list. + # TODO: could optimize this to just extract one archive. + whole_archive_flag_spec= + fi + if test -n "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + test "X$libobjs" = "X " && libobjs= + else + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $convenience + libobjs="$libobjs $func_extract_archives_result" + test "X$libobjs" = "X " && libobjs= + fi + fi + + if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then + eval flag=\"$thread_safe_flag_spec\" + linker_flags="$linker_flags $flag" + fi + + # Make a backup of the uninstalled library when relinking + if test "$mode" = relink; then + $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $? + fi + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + eval test_cmds=\"$module_expsym_cmds\" + cmds=$module_expsym_cmds + else + eval test_cmds=\"$module_cmds\" + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + eval test_cmds=\"$archive_expsym_cmds\" + cmds=$archive_expsym_cmds + else + eval test_cmds=\"$archive_cmds\" + cmds=$archive_cmds + fi + fi + + if test "X$skipped_export" != "X:" && + func_len " $test_cmds" && + len=$func_len_result && + test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + : + else + # The command line is too long to link in one step, link piecewise + # or, if using GNU ld and skipped_export is not :, use a linker + # script. + + # Save the value of $output and $libobjs because we want to + # use them later. If we have whole_archive_flag_spec, we + # want to use save_libobjs as it was before + # whole_archive_flag_spec was expanded, because we can't + # assume the linker understands whole_archive_flag_spec. + # This may have to be revisited, in case too many + # convenience libraries get linked in and end up exceeding + # the spec. + if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + fi + save_output=$output + func_basename "$output" + output_la=$func_basename_result + + # Clear the reloadable object creation command queue and + # initialize k to one. + test_cmds= + concat_cmds= + objlist= + last_robj= + k=1 + + if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then + output=${output_objdir}/${output_la}.lnkscript + func_verbose "creating GNU ld script: $output" + echo 'INPUT (' > $output + for obj in $save_libobjs + do + $ECHO "$obj" >> $output + done + echo ')' >> $output + delfiles="$delfiles $output" + elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then + output=${output_objdir}/${output_la}.lnk + func_verbose "creating linker input file list: $output" + : > $output + set x $save_libobjs + shift + firstobj= + if test "$compiler_needs_object" = yes; then + firstobj="$1 " + shift + fi + for obj + do + $ECHO "$obj" >> $output + done + delfiles="$delfiles $output" + output=$firstobj\"$file_list_spec$output\" + else + if test -n "$save_libobjs"; then + func_verbose "creating reloadable object files..." + output=$output_objdir/$output_la-${k}.$objext + eval test_cmds=\"$reload_cmds\" + func_len " $test_cmds" + len0=$func_len_result + len=$len0 + + # Loop over the list of objects to be linked. + for obj in $save_libobjs + do + func_len " $obj" + func_arith $len + $func_len_result + len=$func_arith_result + if test "X$objlist" = X || + test "$len" -lt "$max_cmd_len"; then + func_append objlist " $obj" + else + # The command $test_cmds is almost too long, add a + # command to the queue. + if test "$k" -eq 1 ; then + # The first file doesn't have a previous command to add. + reload_objs=$objlist + eval concat_cmds=\"$reload_cmds\" + else + # All subsequent reloadable object files will link in + # the last one created. + reload_objs="$objlist $last_robj" + eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\" + fi + last_robj=$output_objdir/$output_la-${k}.$objext + func_arith $k + 1 + k=$func_arith_result + output=$output_objdir/$output_la-${k}.$objext + objlist=" $obj" + func_len " $last_robj" + func_arith $len0 + $func_len_result + len=$func_arith_result + fi + done + # Handle the remaining objects by creating one last + # reloadable object file. All subsequent reloadable object + # files will link in the last one created. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + reload_objs="$objlist $last_robj" + eval concat_cmds=\"\${concat_cmds}$reload_cmds\" + if test -n "$last_robj"; then + eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\" + fi + delfiles="$delfiles $output" + + else + output= + fi + + if ${skipped_export-false}; then + func_verbose "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $opt_dry_run || $RM $export_symbols + libobjs=$output + # Append the command to create the export file. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\" + if test -n "$last_robj"; then + eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" + fi + fi + + test -n "$save_libobjs" && + func_verbose "creating a temporary reloadable object file: $output" + + # Loop through the commands generated above and execute them. + save_ifs="$IFS"; IFS='~' + for cmd in $concat_cmds; do + IFS="$save_ifs" + $opt_silent || { + func_quote_for_expand "$cmd" + eval "func_echo $func_quote_for_expand_result" + } + $opt_dry_run || eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + ( cd "$output_objdir" && \ + $RM "${realname}T" && \ + $MV "${realname}U" "$realname" ) + fi + + exit $lt_exit + } + done + IFS="$save_ifs" + + if test -n "$export_symbols_regex" && ${skipped_export-false}; then + func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + func_show_eval '$MV "${export_symbols}T" "$export_symbols"' + fi + fi + + if ${skipped_export-false}; then + if test -n "$export_symbols" && test -n "$include_expsyms"; then + tmp_export_symbols="$export_symbols" + test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" + $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' + fi + + if test -n "$orig_export_symbols"; then + # The given exports_symbols file has to be filtered, so filter it. + func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" + # FIXME: $output_objdir/$libname.filter potentially contains lots of + # 's' commands which not all seds can handle. GNU sed should be fine + # though. Also, the filter scales superlinearly with the number of + # global variables. join(1) would be nice here, but unfortunately + # isn't a blessed tool. + $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter + delfiles="$delfiles $export_symbols $output_objdir/$libname.filter" + export_symbols=$output_objdir/$libname.def + $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols + fi + fi + + libobjs=$output + # Restore the value of output. + output=$save_output + + if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + test "X$libobjs" = "X " && libobjs= + fi + # Expand the library linking commands again to reset the + # value of $libobjs for piecewise linking. + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + cmds=$module_expsym_cmds + else + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + cmds=$archive_expsym_cmds + else + cmds=$archive_cmds + fi + fi + fi + + if test -n "$delfiles"; then + # Append the command to remove temporary files to $cmds. + eval cmds=\"\$cmds~\$RM $delfiles\" + fi + + # Add any objects from preloaded convenience libraries + if test -n "$dlprefiles"; then + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $dlprefiles + libobjs="$libobjs $func_extract_archives_result" + test "X$libobjs" = "X " && libobjs= + fi + + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $opt_silent || { + func_quote_for_expand "$cmd" + eval "func_echo $func_quote_for_expand_result" + } + $opt_dry_run || eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + ( cd "$output_objdir" && \ + $RM "${realname}T" && \ + $MV "${realname}U" "$realname" ) + fi + + exit $lt_exit + } + done + IFS="$save_ifs" + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $? + + if test -n "$convenience"; then + if test -z "$whole_archive_flag_spec"; then + func_show_eval '${RM}r "$gentop"' + fi + fi + + exit $EXIT_SUCCESS + fi + + # Create links to the real library. + for linkname in $linknames; do + if test "$realname" != "$linkname"; then + func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?' + fi + done + + # If -module or -export-dynamic was specified, set the dlname. + if test "$module" = yes || test "$export_dynamic" = yes; then + # On all known operating systems, these are identical. + dlname="$soname" + fi + fi + ;; + + obj) + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + func_warning "\`-dlopen' is ignored for objects" + fi + + case " $deplibs" in + *\ -l* | *\ -L*) + func_warning "\`-l' and \`-L' are ignored for objects" ;; + esac + + test -n "$rpath" && \ + func_warning "\`-rpath' is ignored for objects" + + test -n "$xrpath" && \ + func_warning "\`-R' is ignored for objects" + + test -n "$vinfo" && \ + func_warning "\`-version-info' is ignored for objects" + + test -n "$release" && \ + func_warning "\`-release' is ignored for objects" + + case $output in + *.lo) + test -n "$objs$old_deplibs" && \ + func_fatal_error "cannot build library object \`$output' from non-libtool objects" + + libobj=$output + func_lo2o "$libobj" + obj=$func_lo2o_result + ;; + *) + libobj= + obj="$output" + ;; + esac + + # Delete the old objects. + $opt_dry_run || $RM $obj $libobj + + # Objects from convenience libraries. This assumes + # single-version convenience libraries. Whenever we create + # different ones for PIC/non-PIC, this we'll have to duplicate + # the extraction. + reload_conv_objs= + gentop= + # reload_cmds runs $LD directly, so let us get rid of + # -Wl from whole_archive_flag_spec and hope we can get by with + # turning comma into space.. + wl= + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" + reload_conv_objs=$reload_objs\ `$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'` + else + gentop="$output_objdir/${obj}x" + generated="$generated $gentop" + + func_extract_archives $gentop $convenience + reload_conv_objs="$reload_objs $func_extract_archives_result" + fi + fi + + # Create the old-style object. + reload_objs="$objs$old_deplibs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; /\.lib$/d; $lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test + + output="$obj" + func_execute_cmds "$reload_cmds" 'exit $?' + + # Exit if we aren't doing a library object file. + if test -z "$libobj"; then + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + exit $EXIT_SUCCESS + fi + + if test "$build_libtool_libs" != yes; then + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + # Create an invalid libtool object if no PIC, so that we don't + # accidentally link it into a program. + # $show "echo timestamp > $libobj" + # $opt_dry_run || eval "echo timestamp > $libobj" || exit $? + exit $EXIT_SUCCESS + fi + + if test -n "$pic_flag" || test "$pic_mode" != default; then + # Only do commands if we really have different PIC objects. + reload_objs="$libobjs $reload_conv_objs" + output="$libobj" + func_execute_cmds "$reload_cmds" 'exit $?' + fi + + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + exit $EXIT_SUCCESS + ;; + + prog) + case $host in + *cygwin*) func_stripname '' '.exe' "$output" + output=$func_stripname_result.exe;; + esac + test -n "$vinfo" && \ + func_warning "\`-version-info' is ignored for programs" + + test -n "$release" && \ + func_warning "\`-release' is ignored for programs" + + test "$preload" = yes \ + && test "$dlopen_support" = unknown \ + && test "$dlopen_self" = unknown \ + && test "$dlopen_self_static" = unknown && \ + func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support." + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library is the System framework + compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'` + finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'` + ;; + esac + + case $host in + *-*-darwin*) + # Don't allow lazy linking, it breaks C++ global constructors + # But is supposedly fixed on 10.4 or later (yay!). + if test "$tagname" = CXX ; then + case ${MACOSX_DEPLOYMENT_TARGET-10.0} in + 10.[0123]) + compile_command="$compile_command ${wl}-bind_at_load" + finalize_command="$finalize_command ${wl}-bind_at_load" + ;; + esac + fi + # Time to change all our "foo.ltframework" stuff back to "-framework foo" + compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + ;; + esac + + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $compile_deplibs " in + *" -L$path/$objdir "*) + new_libs="$new_libs -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $compile_deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$new_libs $deplib" ;; + esac + ;; + *) new_libs="$new_libs $deplib" ;; + esac + done + compile_deplibs="$new_libs" + + + compile_command="$compile_command $compile_deplibs" + finalize_command="$finalize_command $finalize_deplibs" + + if test -n "$rpath$xrpath"; then + # If the user specified any rpath flags, then add them. + for libdir in $rpath $xrpath; do + # This is the magic to use -rpath. + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" ;; + esac + done + fi + + # Now hardcode the library paths + rpath= + hardcode_libdirs= + for libdir in $compile_rpath $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + rpath="$rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$libdir:"*) ;; + ::) dllsearchpath=$libdir;; + *) dllsearchpath="$dllsearchpath:$libdir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + ::) dllsearchpath=$testbindir;; + *) dllsearchpath="$dllsearchpath:$testbindir";; + esac + ;; + esac + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + compile_rpath="$rpath" + + rpath= + hardcode_libdirs= + for libdir in $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + rpath="$rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$finalize_perm_rpath " in + *" $libdir "*) ;; + *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + finalize_rpath="$rpath" + + if test -n "$libobjs" && test "$build_old_libs" = yes; then + # Transform all the library objects into standard objects. + compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP` + finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP` + fi + + func_generate_dlsyms "$outputname" "@PROGRAM@" "no" + + # template prelinking step + if test -n "$prelink_cmds"; then + func_execute_cmds "$prelink_cmds" 'exit $?' + fi + + wrappers_required=yes + case $host in + *cegcc* | *mingw32ce*) + # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway. + wrappers_required=no + ;; + *cygwin* | *mingw* ) + if test "$build_libtool_libs" != yes; then + wrappers_required=no + fi + ;; + *) + if test "$need_relink" = no || test "$build_libtool_libs" != yes; then + wrappers_required=no + fi + ;; + esac + if test "$wrappers_required" = no; then + # Replace the output file specification. + compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'` + link_command="$compile_command$compile_rpath" + + # We have no uninstalled library dependencies, so finalize right now. + exit_status=0 + func_show_eval "$link_command" 'exit_status=$?' + + # Delete the generated files. + if test -f "$output_objdir/${outputname}S.${objext}"; then + func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"' + fi + + exit $exit_status + fi + + if test -n "$compile_shlibpath$finalize_shlibpath"; then + compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" + fi + if test -n "$finalize_shlibpath"; then + finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" + fi + + compile_var= + finalize_var= + if test -n "$runpath_var"; then + if test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + compile_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + if test -n "$finalize_perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $finalize_perm_rpath; do + rpath="$rpath$dir:" + done + finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + fi + + if test "$no_install" = yes; then + # We don't need to create a wrapper script. + link_command="$compile_var$compile_command$compile_rpath" + # Replace the output file specification. + link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'` + # Delete the old output file. + $opt_dry_run || $RM $output + # Link the executable and exit + func_show_eval "$link_command" 'exit $?' + exit $EXIT_SUCCESS + fi + + if test "$hardcode_action" = relink; then + # Fast installation is not supported + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + + func_warning "this platform does not like uninstalled shared libraries" + func_warning "\`$output' will be relinked during installation" + else + if test "$fast_install" != no; then + link_command="$finalize_var$compile_command$finalize_rpath" + if test "$fast_install" = yes; then + relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'` + else + # fast_install is set to needless + relink_command= + fi + else + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + fi + fi + + # Replace the output file specification. + link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` + + # Delete the old output files. + $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname + + func_show_eval "$link_command" 'exit $?' + + # Now create the wrapper script. + func_verbose "creating $output" + + # Quote the relink command for shipping. + if test -n "$relink_command"; then + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + func_quote_for_eval "$var_value" + relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" + fi + done + relink_command="(cd `pwd`; $relink_command)" + relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` + fi + + # Only actually do things if not in dry run mode. + $opt_dry_run || { + # win32 will think the script is a binary if it has + # a .exe suffix, so we strip it off here. + case $output in + *.exe) func_stripname '' '.exe' "$output" + output=$func_stripname_result ;; + esac + # test for cygwin because mv fails w/o .exe extensions + case $host in + *cygwin*) + exeext=.exe + func_stripname '' '.exe' "$outputname" + outputname=$func_stripname_result ;; + *) exeext= ;; + esac + case $host in + *cygwin* | *mingw* ) + func_dirname_and_basename "$output" "" "." + output_name=$func_basename_result + output_path=$func_dirname_result + cwrappersource="$output_path/$objdir/lt-$output_name.c" + cwrapper="$output_path/$output_name.exe" + $RM $cwrappersource $cwrapper + trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 + + func_emit_cwrapperexe_src > $cwrappersource + + # The wrapper executable is built using the $host compiler, + # because it contains $host paths and files. If cross- + # compiling, it, like the target executable, must be + # executed on the $host or under an emulation environment. + $opt_dry_run || { + $LTCC $LTCFLAGS -o $cwrapper $cwrappersource + $STRIP $cwrapper + } + + # Now, create the wrapper script for func_source use: + func_ltwrapper_scriptname $cwrapper + $RM $func_ltwrapper_scriptname_result + trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15 + $opt_dry_run || { + # note: this script will not be executed, so do not chmod. + if test "x$build" = "x$host" ; then + $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result + else + func_emit_wrapper no > $func_ltwrapper_scriptname_result + fi + } + ;; + * ) + $RM $output + trap "$RM $output; exit $EXIT_FAILURE" 1 2 15 + + func_emit_wrapper no > $output + chmod +x $output + ;; + esac + } + exit $EXIT_SUCCESS + ;; + esac + + # See if we need to build an old-fashioned archive. + for oldlib in $oldlibs; do + + if test "$build_libtool_libs" = convenience; then + oldobjs="$libobjs_save $symfileobj" + addlibs="$convenience" + build_libtool_libs=no + else + if test "$build_libtool_libs" = module; then + oldobjs="$libobjs_save" + build_libtool_libs=no + else + oldobjs="$old_deplibs $non_pic_objects" + if test "$preload" = yes && test -f "$symfileobj"; then + oldobjs="$oldobjs $symfileobj" + fi + fi + addlibs="$old_convenience" + fi + + if test -n "$addlibs"; then + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $addlibs + oldobjs="$oldobjs $func_extract_archives_result" + fi + + # Do each command in the archive commands. + if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then + cmds=$old_archive_from_new_cmds + else + + # Add any objects from preloaded convenience libraries + if test -n "$dlprefiles"; then + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $dlprefiles + oldobjs="$oldobjs $func_extract_archives_result" + fi + + # POSIX demands no paths to be encoded in archives. We have + # to avoid creating archives with duplicate basenames if we + # might have to extract them afterwards, e.g., when creating a + # static archive out of a convenience library, or when linking + # the entirety of a libtool archive into another (currently + # not supported by libtool). + if (for obj in $oldobjs + do + func_basename "$obj" + $ECHO "$func_basename_result" + done | sort | sort -uc >/dev/null 2>&1); then + : + else + echo "copying selected object files to avoid basename conflicts..." + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + func_mkdir_p "$gentop" + save_oldobjs=$oldobjs + oldobjs= + counter=1 + for obj in $save_oldobjs + do + func_basename "$obj" + objbase="$func_basename_result" + case " $oldobjs " in + " ") oldobjs=$obj ;; + *[\ /]"$objbase "*) + while :; do + # Make sure we don't pick an alternate name that also + # overlaps. + newobj=lt$counter-$objbase + func_arith $counter + 1 + counter=$func_arith_result + case " $oldobjs " in + *[\ /]"$newobj "*) ;; + *) if test ! -f "$gentop/$newobj"; then break; fi ;; + esac + done + func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" + oldobjs="$oldobjs $gentop/$newobj" + ;; + *) oldobjs="$oldobjs $obj" ;; + esac + done + fi + eval cmds=\"$old_archive_cmds\" + + func_len " $cmds" + len=$func_len_result + if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + cmds=$old_archive_cmds + else + # the command line is too long to link in one step, link in parts + func_verbose "using piecewise archive linking..." + save_RANLIB=$RANLIB + RANLIB=: + objlist= + concat_cmds= + save_oldobjs=$oldobjs + oldobjs= + # Is there a better way of finding the last object in the list? + for obj in $save_oldobjs + do + last_oldobj=$obj + done + eval test_cmds=\"$old_archive_cmds\" + func_len " $test_cmds" + len0=$func_len_result + len=$len0 + for obj in $save_oldobjs + do + func_len " $obj" + func_arith $len + $func_len_result + len=$func_arith_result + func_append objlist " $obj" + if test "$len" -lt "$max_cmd_len"; then + : + else + # the above command should be used before it gets too long + oldobjs=$objlist + if test "$obj" = "$last_oldobj" ; then + RANLIB=$save_RANLIB + fi + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\" + objlist= + len=$len0 + fi + done + RANLIB=$save_RANLIB + oldobjs=$objlist + if test "X$oldobjs" = "X" ; then + eval cmds=\"\$concat_cmds\" + else + eval cmds=\"\$concat_cmds~\$old_archive_cmds\" + fi + fi + fi + func_execute_cmds "$cmds" 'exit $?' + done + + test -n "$generated" && \ + func_show_eval "${RM}r$generated" + + # Now create the libtool archive. + case $output in + *.la) + old_library= + test "$build_old_libs" = yes && old_library="$libname.$libext" + func_verbose "creating $output" + + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + func_quote_for_eval "$var_value" + relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" + fi + done + # Quote the link command for shipping. + relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" + relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` + if test "$hardcode_automatic" = yes ; then + relink_command= + fi + + # Only create the output if not a dry run. + $opt_dry_run || { + for installed in no yes; do + if test "$installed" = yes; then + if test -z "$install_libdir"; then + break + fi + output="$output_objdir/$outputname"i + # Replace all uninstalled libtool libraries with the installed ones + newdependency_libs= + for deplib in $dependency_libs; do + case $deplib in + *.la) + func_basename "$deplib" + name="$func_basename_result" + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + test -z "$libdir" && \ + func_fatal_error "\`$deplib' is not a valid libtool archive" + newdependency_libs="$newdependency_libs $libdir/$name" + ;; + *) newdependency_libs="$newdependency_libs $deplib" ;; + esac + done + dependency_libs="$newdependency_libs" + newdlfiles= + + for lib in $dlfiles; do + case $lib in + *.la) + func_basename "$lib" + name="$func_basename_result" + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + test -z "$libdir" && \ + func_fatal_error "\`$lib' is not a valid libtool archive" + newdlfiles="$newdlfiles $libdir/$name" + ;; + *) newdlfiles="$newdlfiles $lib" ;; + esac + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + *.la) + # Only pass preopened files to the pseudo-archive (for + # eventual linking with the app. that links it) if we + # didn't already link the preopened objects directly into + # the library: + func_basename "$lib" + name="$func_basename_result" + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + test -z "$libdir" && \ + func_fatal_error "\`$lib' is not a valid libtool archive" + newdlprefiles="$newdlprefiles $libdir/$name" + ;; + esac + done + dlprefiles="$newdlprefiles" + else + newdlfiles= + for lib in $dlfiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + newdlfiles="$newdlfiles $abs" + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + newdlprefiles="$newdlprefiles $abs" + done + dlprefiles="$newdlprefiles" + fi + $RM $output + # place dlname in correct position for cygwin + # In fact, it would be nice if we could use this code for all target + # systems that can't hard-code library paths into their executables + # and that have no shared library path variable independent of PATH, + # but it turns out we can't easily determine that from inspecting + # libtool variables, so we have to hard-code the OSs to which it + # applies here; at the moment, that means platforms that use the PE + # object format with DLL files. See the long comment at the top of + # tests/bindir.at for full details. + tdlname=$dlname + case $host,$output,$installed,$module,$dlname in + *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) + # If a -bindir argument was supplied, place the dll there. + if test "x$bindir" != x ; + then + func_relative_path "$install_libdir" "$bindir" + tdlname=$func_relative_path_result$dlname + else + # Otherwise fall back on heuristic. + tdlname=../bin/$dlname + fi + ;; + esac + $ECHO > $output "\ +# $outputname - a libtool library file +# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='$tdlname' + +# Names of this library. +library_names='$library_names' + +# The name of the static archive. +old_library='$old_library' + +# Linker flags that can not go in dependency_libs. +inherited_linker_flags='$new_inherited_linker_flags' + +# Libraries that this one depends upon. +dependency_libs='$dependency_libs' + +# Names of additional weak libraries provided by this library +weak_library_names='$weak_libs' + +# Version information for $libname. +current=$current +age=$age +revision=$revision + +# Is this an already installed library? +installed=$installed + +# Should we warn about portability when linking against -modules? +shouldnotlink=$module + +# Files to dlopen/dlpreopen +dlopen='$dlfiles' +dlpreopen='$dlprefiles' + +# Directory that this library needs to be installed in: +libdir='$install_libdir'" + if test "$installed" = no && test "$need_relink" = yes; then + $ECHO >> $output "\ +relink_command=\"$relink_command\"" + fi + done + } + + # Do a symbolic link so that the libtool archive can be found in + # LD_LIBRARY_PATH before the program is installed. + func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?' + ;; + esac + exit $EXIT_SUCCESS +} + +{ test "$mode" = link || test "$mode" = relink; } && + func_mode_link ${1+"$@"} + + +# func_mode_uninstall arg... +func_mode_uninstall () +{ + $opt_debug + RM="$nonopt" + files= + rmforce= + exit_status=0 + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + for arg + do + case $arg in + -f) RM="$RM $arg"; rmforce=yes ;; + -*) RM="$RM $arg" ;; + *) files="$files $arg" ;; + esac + done + + test -z "$RM" && \ + func_fatal_help "you must specify an RM program" + + rmdirs= + + origobjdir="$objdir" + for file in $files; do + func_dirname "$file" "" "." + dir="$func_dirname_result" + if test "X$dir" = X.; then + objdir="$origobjdir" + else + objdir="$dir/$origobjdir" + fi + func_basename "$file" + name="$func_basename_result" + test "$mode" = uninstall && objdir="$dir" + + # Remember objdir for removal later, being careful to avoid duplicates + if test "$mode" = clean; then + case " $rmdirs " in + *" $objdir "*) ;; + *) rmdirs="$rmdirs $objdir" ;; + esac + fi + + # Don't error if the file doesn't exist and rm -f was used. + if { test -L "$file"; } >/dev/null 2>&1 || + { test -h "$file"; } >/dev/null 2>&1 || + test -f "$file"; then + : + elif test -d "$file"; then + exit_status=1 + continue + elif test "$rmforce" = yes; then + continue + fi + + rmfiles="$file" + + case $name in + *.la) + # Possibly a libtool archive, so verify it. + if func_lalib_p "$file"; then + func_source $dir/$name + + # Delete the libtool libraries and symlinks. + for n in $library_names; do + rmfiles="$rmfiles $objdir/$n" + done + test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library" + + case "$mode" in + clean) + case " $library_names " in + # " " in the beginning catches empty $dlname + *" $dlname "*) ;; + *) rmfiles="$rmfiles $objdir/$dlname" ;; + esac + test -n "$libdir" && rmfiles="$rmfiles $objdir/$name $objdir/${name}i" + ;; + uninstall) + if test -n "$library_names"; then + # Do each command in the postuninstall commands. + func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' + fi + + if test -n "$old_library"; then + # Do each command in the old_postuninstall commands. + func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' + fi + # FIXME: should reinstall the best remaining shared library. + ;; + esac + fi + ;; + + *.lo) + # Possibly a libtool object, so verify it. + if func_lalib_p "$file"; then + + # Read the .lo file + func_source $dir/$name + + # Add PIC object to the list of files to remove. + if test -n "$pic_object" && + test "$pic_object" != none; then + rmfiles="$rmfiles $dir/$pic_object" + fi + + # Add non-PIC object to the list of files to remove. + if test -n "$non_pic_object" && + test "$non_pic_object" != none; then + rmfiles="$rmfiles $dir/$non_pic_object" + fi + fi + ;; + + *) + if test "$mode" = clean ; then + noexename=$name + case $file in + *.exe) + func_stripname '' '.exe' "$file" + file=$func_stripname_result + func_stripname '' '.exe' "$name" + noexename=$func_stripname_result + # $file with .exe has already been added to rmfiles, + # add $file without .exe + rmfiles="$rmfiles $file" + ;; + esac + # Do a test to see if this is a libtool program. + if func_ltwrapper_p "$file"; then + if func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + relink_command= + func_source $func_ltwrapper_scriptname_result + rmfiles="$rmfiles $func_ltwrapper_scriptname_result" + else + relink_command= + func_source $dir/$noexename + fi + + # note $name still contains .exe if it was in $file originally + # as does the version of $file that was added into $rmfiles + rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}" + if test "$fast_install" = yes && test -n "$relink_command"; then + rmfiles="$rmfiles $objdir/lt-$name" + fi + if test "X$noexename" != "X$name" ; then + rmfiles="$rmfiles $objdir/lt-${noexename}.c" + fi + fi + fi + ;; + esac + func_show_eval "$RM $rmfiles" 'exit_status=1' + done + objdir="$origobjdir" + + # Try to remove the ${objdir}s in the directories where we deleted files + for dir in $rmdirs; do + if test -d "$dir"; then + func_show_eval "rmdir $dir >/dev/null 2>&1" + fi + done + + exit $exit_status +} + +{ test "$mode" = uninstall || test "$mode" = clean; } && + func_mode_uninstall ${1+"$@"} + +test -z "$mode" && { + help="$generic_help" + func_fatal_help "you must specify a MODE" +} + +test -z "$exec_cmd" && \ + func_fatal_help "invalid operation mode \`$mode'" + +if test -n "$exec_cmd"; then + eval exec "$exec_cmd" + exit $EXIT_FAILURE +fi + +exit $exit_status + + +# The TAGs below are defined such that we never get into a situation +# in which we disable both kinds of libraries. Given conflicting +# choices, we go for a static library, that is the most portable, +# since we can't tell whether shared libraries were disabled because +# the user asked for that or because the platform doesn't support +# them. This is particularly important on AIX, because we don't +# support having both static and shared libraries enabled at the same +# time on that platform, so we default to a shared-only configuration. +# If a disable-shared tag is given, we'll fallback to a static-only +# configuration. But we'll never go from static-only to shared-only. + +# ### BEGIN LIBTOOL TAG CONFIG: disable-shared +build_libtool_libs=no +build_old_libs=yes +# ### END LIBTOOL TAG CONFIG: disable-shared + +# ### BEGIN LIBTOOL TAG CONFIG: disable-static +build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` +# ### END LIBTOOL TAG CONFIG: disable-static + +# Local Variables: +# mode:shell-script +# sh-indentation:2 +# End: +# vi:sw=2 + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/missing b/gdcm/Utilities/gdcmopenjpeg-v1/missing new file mode 100644 index 0000000..28055d2 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/missing @@ -0,0 +1,376 @@ +#! /bin/sh +# Common stub for a few missing GNU programs while installing. + +scriptversion=2009-04-28.21; # UTC + +# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006, +# 2008, 2009 Free Software Foundation, Inc. +# Originally by Fran,cois Pinard , 1996. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +if test $# -eq 0; then + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 +fi + +run=: +sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p' +sed_minuso='s/.* -o \([^ ]*\).*/\1/p' + +# In the cases where this matters, `missing' is being run in the +# srcdir already. +if test -f configure.ac; then + configure_ac=configure.ac +else + configure_ac=configure.in +fi + +msg="missing on your system" + +case $1 in +--run) + # Try to run requested program, and just exit if it succeeds. + run= + shift + "$@" && exit 0 + # Exit code 63 means version mismatch. This often happens + # when the user try to use an ancient version of a tool on + # a file that requires a minimum version. In this case we + # we should proceed has if the program had been absent, or + # if --run hadn't been passed. + if test $? = 63; then + run=: + msg="probably too old" + fi + ;; + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an +error status if there is no known handling for PROGRAM. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + --run try to run the given command, and emulate it if it fails + +Supported PROGRAM values: + aclocal touch file \`aclocal.m4' + autoconf touch file \`configure' + autoheader touch file \`config.h.in' + autom4te touch the output file, or create a stub one + automake touch all \`Makefile.in' files + bison create \`y.tab.[ch]', if possible, from existing .[ch] + flex create \`lex.yy.c', if possible, from existing .c + help2man touch the output file + lex create \`lex.yy.c', if possible, from existing .c + makeinfo touch the output file + tar try tar, gnutar, gtar, then tar without non-portable flags + yacc create \`y.tab.[ch]', if possible, from existing .[ch] + +Version suffixes to PROGRAM as well as the prefixes \`gnu-', \`gnu', and +\`g' are ignored when checking the name. + +Send bug reports to ." + exit $? + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing $scriptversion (GNU Automake)" + exit $? + ;; + + -*) + echo 1>&2 "$0: Unknown \`$1' option" + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 + ;; + +esac + +# normalize program name to check for. +program=`echo "$1" | sed ' + s/^gnu-//; t + s/^gnu//; t + s/^g//; t'` + +# Now exit if we have it, but it failed. Also exit now if we +# don't have it and --version was passed (most likely to detect +# the program). This is about non-GNU programs, so use $1 not +# $program. +case $1 in + lex*|yacc*) + # Not GNU programs, they don't have --version. + ;; + + tar*) + if test -n "$run"; then + echo 1>&2 "ERROR: \`tar' requires --run" + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + exit 1 + fi + ;; + + *) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + # Could not run --version or --help. This is probably someone + # running `$TOOL --version' or `$TOOL --help' to check whether + # $TOOL exists and not knowing $TOOL uses missing. + exit 1 + fi + ;; +esac + +# If it does not exist, or fails to run (possibly an outdated version), +# try to emulate it. +case $program in + aclocal*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acinclude.m4' or \`${configure_ac}'. You might want + to install the \`Automake' and \`Perl' packages. Grab them from + any GNU archive site." + touch aclocal.m4 + ;; + + autoconf*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`${configure_ac}'. You might want to install the + \`Autoconf' and \`GNU m4' packages. Grab them from any GNU + archive site." + touch configure + ;; + + autoheader*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acconfig.h' or \`${configure_ac}'. You might want + to install the \`Autoconf' and \`GNU m4' packages. Grab them + from any GNU archive site." + files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` + test -z "$files" && files="config.h" + touch_files= + for f in $files; do + case $f in + *:*) touch_files="$touch_files "`echo "$f" | + sed -e 's/^[^:]*://' -e 's/:.*//'`;; + *) touch_files="$touch_files $f.in";; + esac + done + touch $touch_files + ;; + + automake*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. + You might want to install the \`Automake' and \`Perl' packages. + Grab them from any GNU archive site." + find . -type f -name Makefile.am -print | + sed 's/\.am$/.in/' | + while read f; do touch "$f"; done + ;; + + autom4te*) + echo 1>&2 "\ +WARNING: \`$1' is needed, but is $msg. + You might have modified some files without having the + proper tools for further handling them. + You can get \`$1' as part of \`Autoconf' from any GNU + archive site." + + file=`echo "$*" | sed -n "$sed_output"` + test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo "#! /bin/sh" + echo "# Created by GNU Automake missing as a replacement of" + echo "# $ $@" + echo "exit 0" + chmod +x $file + exit 1 + fi + ;; + + bison*|yacc*) + echo 1>&2 "\ +WARNING: \`$1' $msg. You should only need it if + you modified a \`.y' file. You may need the \`Bison' package + in order for those modifications to take effect. You can get + \`Bison' from any GNU archive site." + rm -f y.tab.c y.tab.h + if test $# -ne 1; then + eval LASTARG="\${$#}" + case $LASTARG in + *.y) + SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` + if test -f "$SRCFILE"; then + cp "$SRCFILE" y.tab.c + fi + SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` + if test -f "$SRCFILE"; then + cp "$SRCFILE" y.tab.h + fi + ;; + esac + fi + if test ! -f y.tab.h; then + echo >y.tab.h + fi + if test ! -f y.tab.c; then + echo 'main() { return 0; }' >y.tab.c + fi + ;; + + lex*|flex*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.l' file. You may need the \`Flex' package + in order for those modifications to take effect. You can get + \`Flex' from any GNU archive site." + rm -f lex.yy.c + if test $# -ne 1; then + eval LASTARG="\${$#}" + case $LASTARG in + *.l) + SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` + if test -f "$SRCFILE"; then + cp "$SRCFILE" lex.yy.c + fi + ;; + esac + fi + if test ! -f lex.yy.c; then + echo 'main() { return 0; }' >lex.yy.c + fi + ;; + + help2man*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a dependency of a manual page. You may need the + \`Help2man' package in order for those modifications to take + effect. You can get \`Help2man' from any GNU archive site." + + file=`echo "$*" | sed -n "$sed_output"` + test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo ".ab help2man is required to generate this page" + exit $? + fi + ;; + + makeinfo*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.texi' or \`.texinfo' file, or any other file + indirectly affecting the aspect of the manual. The spurious + call might also be the consequence of using a buggy \`make' (AIX, + DU, IRIX). You might want to install the \`Texinfo' package or + the \`GNU make' package. Grab either from any GNU archive site." + # The file to touch is that specified with -o ... + file=`echo "$*" | sed -n "$sed_output"` + test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` + if test -z "$file"; then + # ... or it is the one specified with @setfilename ... + infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` + file=`sed -n ' + /^@setfilename/{ + s/.* \([^ ]*\) *$/\1/ + p + q + }' $infile` + # ... or it is derived from the source name (dir/f.texi becomes f.info) + test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info + fi + # If the file does not exist, the user really needs makeinfo; + # let's fail without touching anything. + test -f $file || exit 1 + touch $file + ;; + + tar*) + shift + + # We have already tried tar in the generic part. + # Look for gnutar/gtar before invocation to avoid ugly error + # messages. + if (gnutar --version > /dev/null 2>&1); then + gnutar "$@" && exit 0 + fi + if (gtar --version > /dev/null 2>&1); then + gtar "$@" && exit 0 + fi + firstarg="$1" + if shift; then + case $firstarg in + *o*) + firstarg=`echo "$firstarg" | sed s/o//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + case $firstarg in + *h*) + firstarg=`echo "$firstarg" | sed s/h//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + fi + + echo 1>&2 "\ +WARNING: I can't seem to be able to run \`tar' with the given arguments. + You may want to install GNU tar or Free paxutils, or check the + command line arguments." + exit 1 + ;; + + *) + echo 1>&2 "\ +WARNING: \`$1' is needed, and is $msg. + You might have modified some files without having the + proper tools for further handling them. Check the \`README' file, + it often tells you about the needed prerequisites for installing + this package. You may also peek at any GNU archive site, in case + some other package would contain this missing \`$1' program." + exit 1 + ;; +esac + +exit 0 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/mj2/CMakeLists.txt b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/CMakeLists.txt new file mode 100644 index 0000000..eb5cca3 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/CMakeLists.txt @@ -0,0 +1,87 @@ +# Makefile for the MJ2 codecs of the OpenJPEG library: frames_to_mj2, mj2_to_frames, extract_j2k_from_mj2 and wrap_j2k_in_mj2 + +set(common_SRCS "") +if(DONT_HAVE_GETOPT) + set(common_SRCS ${OPENJPEG_SOURCE_DIR}/common/getopt.c) +endif() + +# While mj2 executables do not use the API correctly, we do not link with the library but rather compile the sources files. +set(OPJ_SRCS +${OPENJPEG_SOURCE_DIR}/libopenjpeg/bio.c +${OPENJPEG_SOURCE_DIR}/libopenjpeg/cio.c +${OPENJPEG_SOURCE_DIR}/libopenjpeg/dwt.c +${OPENJPEG_SOURCE_DIR}/libopenjpeg/event.c +${OPENJPEG_SOURCE_DIR}/libopenjpeg/image.c +${OPENJPEG_SOURCE_DIR}/libopenjpeg/j2k.c +${OPENJPEG_SOURCE_DIR}/libopenjpeg/j2k_lib.c +${OPENJPEG_SOURCE_DIR}/libopenjpeg/jp2.c +${OPENJPEG_SOURCE_DIR}/libopenjpeg/jpt.c +${OPENJPEG_SOURCE_DIR}/libopenjpeg/mct.c +${OPENJPEG_SOURCE_DIR}/libopenjpeg/mqc.c +${OPENJPEG_SOURCE_DIR}/libopenjpeg/openjpeg.c +${OPENJPEG_SOURCE_DIR}/libopenjpeg/pi.c +${OPENJPEG_SOURCE_DIR}/libopenjpeg/raw.c +${OPENJPEG_SOURCE_DIR}/libopenjpeg/t1.c +${OPENJPEG_SOURCE_DIR}/libopenjpeg/t2.c +${OPENJPEG_SOURCE_DIR}/libopenjpeg/tcd.c +${OPENJPEG_SOURCE_DIR}/libopenjpeg/tgt.c +) + +set(MJ2_SRCS mj2.c mj2_convert.c) + +if(WIN32) + add_definitions(-DOPJ_STATIC) +endif() + +# Headers file are located here: +include_directories( + ${OPENJPEG_SOURCE_DIR}/libopenjpeg + ${OPENJPEG_SOURCE_DIR}/common + ${LCMS_INCLUDE_DIR} + ) + +add_executable(frames_to_mj2 + frames_to_mj2.c + ${common_SRCS} + ${OPJ_SRCS} + ${MJ2_SRCS} + ) +target_link_libraries(frames_to_mj2 ${LCMS_LIB}) +if(UNIX) + target_link_libraries(frames_to_mj2 m) +endif() + +add_executable(mj2_to_frames + mj2_to_frames.c + ${common_SRCS} + ${OPJ_SRCS} + ${MJ2_SRCS} + ${OPENJPEG_SOURCE_DIR}/common/color.c + ) +target_link_libraries(mj2_to_frames ${LCMS_LIB}) +if(UNIX) + target_link_libraries(mj2_to_frames m) +endif() + +add_executable(extract_j2k_from_mj2 + extract_j2k_from_mj2.c + ${OPJ_SRCS} + ${MJ2_SRCS} + ) +target_link_libraries(extract_j2k_from_mj2 ${LCMS_LIB}) +if(UNIX) + target_link_libraries(extract_j2k_from_mj2 m) +endif() + +add_executable(wrap_j2k_in_mj2 + wrap_j2k_in_mj2.c + ${OPJ_SRCS} + ${MJ2_SRCS} + ) +target_link_libraries(wrap_j2k_in_mj2 ${LCMS_LIB}) +if(UNIX) + target_link_libraries(wrap_j2k_in_mj2 m) +endif() + +install(TARGETS frames_to_mj2 mj2_to_frames extract_j2k_from_mj2 wrap_j2k_in_mj2 + DESTINATION bin) diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/mj2/MJ2_Extractor.dsp b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/MJ2_Extractor.dsp new file mode 100644 index 0000000..c63a004 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/MJ2_Extractor.dsp @@ -0,0 +1,196 @@ +# Microsoft Developer Studio Project File - Name="MJ2_Extractor" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=MJ2_Extractor - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "MJ2_Extractor.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "MJ2_Extractor.mak" CFG="MJ2_Extractor - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "MJ2_Extractor - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "MJ2_Extractor - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "MJ2_Extractor - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "../libopenjpeg" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "OPJ_STATIC" /YX /FD /c +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /nodefaultlib:"libcmt" +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "MJ2_Extractor - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "MJ2_Extractor___Win32_Debug" +# PROP BASE Intermediate_Dir "MJ2_Extractor___Win32_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "MJ2_Extractor___Win32_Debug" +# PROP Intermediate_Dir "MJ2_Extractor___Win32_Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MT /W3 /Gm /GX /ZI /Od /I "../libopenjpeg" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "OPJ_STATIC" /FR /YX /FD /GZ /c +# ADD BASE RSC /l 0x809 /d "_DEBUG" +# ADD RSC /l 0x809 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /nodefaultlib:"libcmt" /pdbtype:sept +# SUBTRACT LINK32 /pdb:none + +!ENDIF + +# Begin Target + +# Name "MJ2_Extractor - Win32 Release" +# Name "MJ2_Extractor - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\extract_j2k_from_mj2.c +# End Source File +# Begin Source File + +SOURCE=.\mj2.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\mj2.h +# End Source File +# End Group +# Begin Group "OpenJPEG Header Files" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\libopenjpeg\bio.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\cio.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\dwt.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\event.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\fix.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\image.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\int.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\j2k.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\j2k_lib.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\jp2.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\jpt.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\mct.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\mqc.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\openjpeg.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\opj_includes.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\pi.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\raw.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\t1.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\t2.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\tcd.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\tgt.h +# End Source File +# End Group +# End Target +# End Project diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/mj2/MJ2_Extractor.dsw b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/MJ2_Extractor.dsw new file mode 100644 index 0000000..f111c2b --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/MJ2_Extractor.dsw @@ -0,0 +1,44 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "LibOpenJPEG"="..\LibOpenJPEG.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "MJ2_Extractor"=".\MJ2_Extractor.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name LibOpenJPEG + End Project Dependency +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/mj2/MJ2_Extractor.sln b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/MJ2_Extractor.sln new file mode 100644 index 0000000..85d55a4 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/MJ2_Extractor.sln @@ -0,0 +1,29 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MJ2_Extractor", "MJ2_Extractor.vcproj", "{BCBEB12A-B691-4B14-9DC5-193BCD01183D}" + ProjectSection(ProjectDependencies) = postProject + {4F27AA53-4181-4A1A-8238-3931B0A41048} = {4F27AA53-4181-4A1A-8238-3931B0A41048} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LibOpenJPEG", "..\LibOpenJPEG.vcproj", "{4F27AA53-4181-4A1A-8238-3931B0A41048}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {BCBEB12A-B691-4B14-9DC5-193BCD01183D}.Debug|Win32.ActiveCfg = Debug|Win32 + {BCBEB12A-B691-4B14-9DC5-193BCD01183D}.Debug|Win32.Build.0 = Debug|Win32 + {BCBEB12A-B691-4B14-9DC5-193BCD01183D}.Release|Win32.ActiveCfg = Release|Win32 + {BCBEB12A-B691-4B14-9DC5-193BCD01183D}.Release|Win32.Build.0 = Release|Win32 + {4F27AA53-4181-4A1A-8238-3931B0A41048}.Debug|Win32.ActiveCfg = Debug|Win32 + {4F27AA53-4181-4A1A-8238-3931B0A41048}.Debug|Win32.Build.0 = Debug|Win32 + {4F27AA53-4181-4A1A-8238-3931B0A41048}.Release|Win32.ActiveCfg = Release|Win32 + {4F27AA53-4181-4A1A-8238-3931B0A41048}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/mj2/MJ2_Extractor.vcproj b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/MJ2_Extractor.vcproj new file mode 100644 index 0000000..e4ea2b9 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/MJ2_Extractor.vcproj @@ -0,0 +1,354 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/mj2/MJ2_Wrapper.dsp b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/MJ2_Wrapper.dsp new file mode 100644 index 0000000..809b80b --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/MJ2_Wrapper.dsp @@ -0,0 +1,195 @@ +# Microsoft Developer Studio Project File - Name="MJ2_Wrapper" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=MJ2_Wrapper - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "MJ2_Wrapper.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "MJ2_Wrapper.mak" CFG="MJ2_Wrapper - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "MJ2_Wrapper - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "MJ2_Wrapper - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "MJ2_Wrapper - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "../libopenjpeg" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "OPJ_STATIC" /FR /YX /FD /c +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "MJ2_Wrapper - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "MJ2_Wrapper___Win32_Debug" +# PROP BASE Intermediate_Dir "MJ2_Wrapper___Win32_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "MJ2_Wrapper___Win32_Debug" +# PROP Intermediate_Dir "MJ2_Wrapper___Win32_Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MT /W3 /Gm /GX /ZI /Od /I "../libopenjpeg" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "OPJ_STATIC" /FR /YX /FD /GZ /c +# ADD BASE RSC /l 0x809 /d "_DEBUG" +# ADD RSC /l 0x809 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /nodefaultlib:"libcmt" /pdbtype:sept +# SUBTRACT LINK32 /pdb:none + +!ENDIF + +# Begin Target + +# Name "MJ2_Wrapper - Win32 Release" +# Name "MJ2_Wrapper - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\mj2.c +# End Source File +# Begin Source File + +SOURCE=.\wrap_j2k_in_mj2.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\mj2.h +# End Source File +# End Group +# Begin Group "OpenJPEG Header Files" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\libopenjpeg\bio.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\cio.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\dwt.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\event.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\fix.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\image.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\int.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\j2k.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\j2k_lib.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\jp2.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\jpt.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\mct.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\mqc.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\openjpeg.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\opj_includes.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\pi.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\raw.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\t1.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\t2.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\tcd.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\tgt.h +# End Source File +# End Group +# End Target +# End Project diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/mj2/MJ2_Wrapper.dsw b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/MJ2_Wrapper.dsw new file mode 100644 index 0000000..5c5a208 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/MJ2_Wrapper.dsw @@ -0,0 +1,44 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "LibOpenJPEG"="..\LibOpenJPEG.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "MJ2_Wrapper"=".\MJ2_Wrapper.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name LibOpenJPEG + End Project Dependency +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/mj2/MJ2_Wrapper.sln b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/MJ2_Wrapper.sln new file mode 100644 index 0000000..bf7eec7 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/MJ2_Wrapper.sln @@ -0,0 +1,29 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MJ2_Wrapper", "MJ2_Wrapper.vcproj", "{87C98B26-E658-4992-8810-201C3CE67011}" + ProjectSection(ProjectDependencies) = postProject + {4F27AA53-4181-4A1A-8238-3931B0A41048} = {4F27AA53-4181-4A1A-8238-3931B0A41048} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LibOpenJPEG", "..\LibOpenJPEG.vcproj", "{4F27AA53-4181-4A1A-8238-3931B0A41048}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {87C98B26-E658-4992-8810-201C3CE67011}.Debug|Win32.ActiveCfg = Debug|Win32 + {87C98B26-E658-4992-8810-201C3CE67011}.Debug|Win32.Build.0 = Debug|Win32 + {87C98B26-E658-4992-8810-201C3CE67011}.Release|Win32.ActiveCfg = Release|Win32 + {87C98B26-E658-4992-8810-201C3CE67011}.Release|Win32.Build.0 = Release|Win32 + {4F27AA53-4181-4A1A-8238-3931B0A41048}.Debug|Win32.ActiveCfg = Debug|Win32 + {4F27AA53-4181-4A1A-8238-3931B0A41048}.Debug|Win32.Build.0 = Debug|Win32 + {4F27AA53-4181-4A1A-8238-3931B0A41048}.Release|Win32.ActiveCfg = Release|Win32 + {4F27AA53-4181-4A1A-8238-3931B0A41048}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/mj2/MJ2_Wrapper.vcproj b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/MJ2_Wrapper.vcproj new file mode 100644 index 0000000..310dbdb --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/MJ2_Wrapper.vcproj @@ -0,0 +1,353 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/mj2/extract_j2k_from_mj2.c b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/extract_j2k_from_mj2.c new file mode 100644 index 0000000..5c1441a --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/extract_j2k_from_mj2.c @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2003-2007, Francois-Olivier Devaux + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + +#include "openjpeg.h" +#include "../libopenjpeg/j2k.h" +#include "../libopenjpeg/jp2.h" +#include "mj2.h" + +/* -------------------------------------------------------------------------- */ + +/** +sample error callback expecting a FILE* client object +*/ +void error_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[ERROR] %s", msg); +} +/** +sample warning callback expecting a FILE* client object +*/ +void warning_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[WARNING] %s", msg); +} +/** +sample debug callback expecting a FILE* client object +*/ +void info_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[INFO] %s", msg); +} + +/* -------------------------------------------------------------------------- */ + + +int main(int argc, char *argv[]) { + opj_dinfo_t* dinfo; + opj_event_mgr_t event_mgr; /* event manager */ + int tnum; + unsigned int snum; + opj_mj2_t *movie; + mj2_tk_t *track; + mj2_sample_t *sample; + unsigned char* frame_codestream; + FILE *file, *outfile; + char outfilename[50]; + mj2_dparameters_t parameters; + + if (argc != 3) { + printf("Usage: %s mj2filename output_location\n",argv[0]); + printf("Example: %s foreman.mj2 output/foreman\n",argv[0]); + return 1; + } + + file = fopen(argv[1], "rb"); + + if (!file) { + fprintf(stderr, "failed to open %s for reading\n", argv[1]); + return 1; + } + + /* + configure the event callbacks (not required) + setting of each callback is optionnal + */ + memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); + event_mgr.error_handler = error_callback; + event_mgr.warning_handler = warning_callback; + event_mgr.info_handler = info_callback; + + /* get a MJ2 decompressor handle */ + dinfo = mj2_create_decompress(); + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr); + + /* setup the decoder decoding parameters using user parameters */ + movie = (opj_mj2_t*) dinfo->mj2_handle; + mj2_setup_decoder((opj_mj2_t*)dinfo->mj2_handle, ¶meters); + + if (mj2_read_struct(file, movie)) // Creating the movie structure + return 1; + + // Decode first video track + tnum = 0; + while (movie->tk[tnum].track_type != 0) + tnum ++; + + track = &movie->tk[tnum]; + + fprintf(stdout,"Extracting %d frames from file...\n",track->num_samples); + + for (snum=0; snum < track->num_samples; snum++) + { + sample = &track->sample[snum]; + frame_codestream = (unsigned char*) malloc (sample->sample_size-8); // Skipping JP2C marker + fseek(file,sample->offset+8,SEEK_SET); + fread(frame_codestream,sample->sample_size-8,1, file); // Assuming that jp and ftyp markers size do + + sprintf(outfilename,"%s_%05d.j2k",argv[2],snum); + outfile = fopen(outfilename, "wb"); + if (!outfile) { + fprintf(stderr, "failed to open %s for writing\n",outfilename); + return 1; + } + fwrite(frame_codestream,sample->sample_size-8,1,outfile); + fclose(outfile); + free(frame_codestream); + } + fclose(file); + fprintf(stdout, "%d frames correctly extracted\n", snum); + + /* free remaining structures */ + if(dinfo) { + mj2_destroy_decompress((opj_mj2_t*)dinfo->mj2_handle); + } + + return 0; +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/mj2/frames_to_mj2.c b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/frames_to_mj2.c new file mode 100644 index 0000000..6b1fd53 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/frames_to_mj2.c @@ -0,0 +1,806 @@ +/* +* Copyright (c) 2003-2004, François-Olivier Devaux +* Copyright (c) 2002-2004, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include + +#include "openjpeg.h" +#include "../libopenjpeg/j2k_lib.h" +#include "../libopenjpeg/j2k.h" +#include "../libopenjpeg/jp2.h" +#include "../libopenjpeg/cio.h" +#include "mj2.h" +#include "mj2_convert.h" +#include "getopt.h" + +/** +Size of memory first allocated for MOOV box +*/ +#define TEMP_BUF 10000 + +/* -------------------------------------------------------------------------- */ + +/** +sample error callback expecting a FILE* client object +*/ +void error_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[ERROR] %s", msg); +} +/** +sample warning callback expecting a FILE* client object +*/ +void warning_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[WARNING] %s", msg); +} +/** +sample debug callback expecting a FILE* client object +*/ +void info_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[INFO] %s", msg); +} + +/* -------------------------------------------------------------------------- */ + + +void help_display() +{ + fprintf(stdout,"HELP for frames_to_mj2\n----\n\n"); + fprintf(stdout,"- the -h option displays this help information on screen\n\n"); + + + fprintf(stdout,"List of parameters for the MJ2 encoder:\n"); + fprintf(stdout,"\n"); + fprintf(stdout,"REMARKS:\n"); + fprintf(stdout,"---------\n"); + fprintf(stdout,"\n"); + fprintf + (stdout,"The markers written to the main_header are : SOC SIZ COD QCD COM.\n"); + fprintf + (stdout,"COD and QCD never appear in the tile_header.\n"); + fprintf(stdout,"\n"); + fprintf(stdout,"By default:\n"); + fprintf(stdout,"------------\n"); + fprintf(stdout,"\n"); + fprintf(stdout," * Lossless\n"); + fprintf(stdout," * 1 tile\n"); + fprintf(stdout," * Size of precinct : 2^15 x 2^15 (means 1 precinct)\n"); + fprintf(stdout," * Size of code-block : 64 x 64\n"); + fprintf(stdout," * Number of resolutions: 6\n"); + fprintf(stdout," * No SOP marker in the codestream\n"); + fprintf(stdout," * No EPH marker in the codestream\n"); + fprintf(stdout," * No sub-sampling in x or y direction\n"); + fprintf(stdout," * No mode switch activated\n"); + fprintf(stdout," * Progression order: LRCP\n"); + fprintf(stdout," * No index file\n"); + fprintf(stdout," * No ROI upshifted\n"); + fprintf(stdout," * No offset of the origin of the image\n"); + fprintf(stdout," * No offset of the origin of the tiles\n"); + fprintf(stdout," * Reversible DWT 5-3\n"); + fprintf(stdout,"\n"); + fprintf(stdout,"Parameters:\n"); + fprintf(stdout,"------------\n"); + fprintf(stdout,"\n"); + fprintf + (stdout,"Required Parameters (except with -h):\n"); + fprintf + (stdout,"-i : source file (-i source.yuv) \n"); + fprintf + (stdout,"-o : destination file (-o dest.mj2) \n"); + fprintf + (stdout,"Optional Parameters:\n"); + fprintf(stdout,"-h : display the help information \n"); + fprintf(stdout,"-r : different compression ratios for successive layers (-r 20,10,5)\n "); + fprintf(stdout," - The rate specified for each quality level is the desired \n"); + fprintf(stdout," compression factor.\n"); + fprintf(stdout," Example: -r 20,10,1 means quality 1: compress 20x, \n"); + fprintf(stdout," quality 2: compress 10x and quality 3: compress lossless\n"); + fprintf(stdout," (options -r and -q cannot be used together)\n "); + + fprintf(stdout,"-q : different psnr for successive layers (-q 30,40,50) \n "); + + fprintf(stdout," (options -r and -q cannot be used together)\n "); + + fprintf(stdout,"-n : number of resolutions (-n 3) \n"); + fprintf(stdout,"-b : size of code block (-b 32,32) \n"); + fprintf(stdout,"-c : size of precinct (-c 128,128) \n"); + fprintf(stdout,"-t : size of tile (-t 512,512) \n"); + fprintf + (stdout,"-p : progression order (-p LRCP) [LRCP, RLCP, RPCL, PCRL, CPRL] \n"); + fprintf + (stdout,"-s : subsampling factor (-s 2,2) [-s X,Y] \n"); + fprintf(stdout," Remark: subsampling bigger than 2 can produce error\n"); + fprintf + (stdout,"-SOP : write SOP marker before each packet \n"); + fprintf + (stdout,"-EPH : write EPH marker after each header packet \n"); + fprintf + (stdout,"-M : mode switch (-M 3) [1=BYPASS(LAZY) 2=RESET 4=RESTART(TERMALL)\n"); + fprintf + (stdout," 8=VSC 16=ERTERM(SEGTERM) 32=SEGMARK(SEGSYM)] \n"); + fprintf + (stdout," Indicate multiple modes by adding their values. \n"); + fprintf + (stdout," ex: RESTART(4) + RESET(2) + SEGMARK(32) = -M 38\n"); + fprintf + (stdout,"-ROI : c=%%d,U=%%d : quantization indices upshifted \n"); + fprintf + (stdout," for component c=%%d [%%d = 0,1,2]\n"); + fprintf + (stdout," with a value of U=%%d [0 <= %%d <= 37] (i.e. -ROI:c=0,U=25) \n"); + fprintf + (stdout,"-d : offset of the origin of the image (-d 150,300) \n"); + fprintf + (stdout,"-T : offset of the origin of the tiles (-T 100,75) \n"); + fprintf(stdout,"-I : use the irreversible DWT 9-7 (-I) \n"); + fprintf(stdout,"-W : image width, height and the dx and dy subsampling \n"); + fprintf(stdout," of the Cb and Cr components for YUV files \n"); + fprintf(stdout," (default is '352,288,2,2' for CIF format's 352x288 and 4:2:0)\n"); + fprintf(stdout,"-F : video frame rate (set to 25 by default)\n"); + + fprintf(stdout,"\n"); + fprintf(stdout,"IMPORTANT:\n"); + fprintf(stdout,"-----------\n"); + fprintf(stdout,"\n"); + fprintf(stdout,"The index file has the structure below:\n"); + fprintf(stdout,"---------------------------------------\n"); + fprintf(stdout,"\n"); + fprintf(stdout,"Image_height Image_width\n"); + fprintf(stdout,"progression order\n"); + fprintf(stdout,"Tiles_size_X Tiles_size_Y\n"); + fprintf(stdout,"Components_nb\n"); + fprintf(stdout,"Layers_nb\n"); + fprintf(stdout,"decomposition_levels\n"); + fprintf(stdout,"[Precincts_size_X_res_Nr Precincts_size_Y_res_Nr]...\n"); + fprintf(stdout," [Precincts_size_X_res_0 Precincts_size_Y_res_0]\n"); + fprintf(stdout,"Main_header_end_position\n"); + fprintf(stdout,"Codestream_size\n"); + fprintf(stdout,"Tile_0 start_pos end_Theader end_pos TotalDisto NumPix MaxMSE\n"); + fprintf(stdout,"Tile_1 '' '' '' '' '' ''\n"); + fprintf(stdout,"...\n"); + fprintf(stdout,"Tile_Nt '' '' '' '' '' ''\n"); + fprintf(stdout,"Tpacket_0 Tile layer res. comp. prec. start_pos end_pos disto\n"); + fprintf(stdout,"...\n"); + fprintf(stdout,"Tpacket_Np '' '' '' '' '' '' '' ''\n"); + + fprintf(stdout,"MaxDisto\n"); + + fprintf(stdout,"TotalDisto\n\n"); +} + +int give_progression(char progression[4]) +{ + if (progression[0] == 'L' && progression[1] == 'R' + && progression[2] == 'C' && progression[3] == 'P') { + return 0; + } else { + if (progression[0] == 'R' && progression[1] == 'L' + && progression[2] == 'C' && progression[3] == 'P') { + return 1; + } else { + if (progression[0] == 'R' && progression[1] == 'P' + && progression[2] == 'C' && progression[3] == 'L') { + return 2; + } else { + if (progression[0] == 'P' && progression[1] == 'C' + && progression[2] == 'R' && progression[3] == 'L') { + return 3; + } else { + if (progression[0] == 'C' && progression[1] == 'P' + && progression[2] == 'R' && progression[3] == 'L') { + return 4; + } else { + return -1; + } + } + } + } + } +} + + + + +int main(int argc, char **argv) +{ + mj2_cparameters_t mj2_parameters; /* MJ2 compression parameters */ + opj_cparameters_t *j2k_parameters; /* J2K compression parameters */ + opj_event_mgr_t event_mgr; /* event manager */ + opj_cio_t *cio; + int value; + opj_mj2_t *movie; + opj_image_t *img; + int i, j; + char *s, S1, S2, S3; + unsigned char *buf; + int x1, y1, len; + long mdat_initpos, offset; + FILE *mj2file; + int sampleno; + opj_cinfo_t* cinfo; + bool bSuccess; + int numframes; + double total_time = 0; + + /* default value */ + /* ------------- */ + mj2_parameters.Dim[0] = 0; + mj2_parameters.Dim[1] = 0; + mj2_parameters.w = 352; // CIF default value + mj2_parameters.h = 288; // CIF default value + mj2_parameters.CbCr_subsampling_dx = 2; // CIF default value + mj2_parameters.CbCr_subsampling_dy = 2; // CIF default value + mj2_parameters.frame_rate = 25; + /* + configure the event callbacks (not required) + setting of each callback is optionnal + */ + memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); + event_mgr.error_handler = error_callback; + event_mgr.warning_handler = warning_callback; + event_mgr.info_handler = NULL; + + /* set J2K encoding parameters to default values */ + opj_set_default_encoder_parameters(&mj2_parameters.j2k_parameters); + j2k_parameters = &mj2_parameters.j2k_parameters; + + /* Create comment for codestream */ + if(j2k_parameters->cp_comment == NULL) { + const char comment[] = "Created by OpenJPEG version "; + const size_t clen = strlen(comment); + const char *version = opj_version(); + j2k_parameters->cp_comment = (char*)malloc(clen+strlen(version)+1); + sprintf(j2k_parameters->cp_comment,"%s%s", comment, version); + } + + mj2_parameters.decod_format = 0; + mj2_parameters.cod_format = 0; + + while (1) { + int c = getopt(argc, argv, + "i:o:r:q:f:t:n:c:b:p:s:d:P:S:E:M:R:T:C:I:W:F:h"); + if (c == -1) + break; + switch (c) { + case 'i': /* IN fill */ + { + char *infile = optarg; + s = optarg; + while (*s) { + s++; + } + s--; + S3 = *s; + s--; + S2 = *s; + s--; + S1 = *s; + + if ((S1 == 'y' && S2 == 'u' && S3 == 'v') + || (S1 == 'Y' && S2 == 'U' && S3 == 'V')) { + mj2_parameters.decod_format = YUV_DFMT; + } + else { + fprintf(stderr, + "!! Unrecognized format for infile : %c%c%c [accept only *.yuv] !!\n\n", + S1, S2, S3); + return 1; + } + strncpy(mj2_parameters.infile, infile, sizeof(mj2_parameters.infile)-1); + } + break; + /* ----------------------------------------------------- */ + case 'o': /* OUT fill */ + { + char *outfile = optarg; + while (*outfile) { + outfile++; + } + outfile--; + S3 = *outfile; + outfile--; + S2 = *outfile; + outfile--; + S1 = *outfile; + + outfile = optarg; + + if ((S1 == 'm' && S2 == 'j' && S3 == '2') + || (S1 == 'M' && S2 == 'J' && S3 == '2')) + mj2_parameters.cod_format = MJ2_CFMT; + else { + fprintf(stderr, + "Unknown output format image *.%c%c%c [only *.mj2]!! \n", + S1, S2, S3); + return 1; + } + strncpy(mj2_parameters.outfile, outfile, sizeof(mj2_parameters.outfile)-1); + } + break; + /* ----------------------------------------------------- */ + case 'r': /* rates rates/distorsion */ + { + float rate; + s = optarg; + while (sscanf(s, "%f", &rate) == 1) { + j2k_parameters->tcp_rates[j2k_parameters->tcp_numlayers] = rate * 2; + j2k_parameters->tcp_numlayers++; + while (*s && *s != ',') { + s++; + } + if (!*s) + break; + s++; + } + j2k_parameters->cp_disto_alloc = 1; + } + break; + /* ----------------------------------------------------- */ + case 'q': /* add fixed_quality */ + s = optarg; + while (sscanf(s, "%f", &j2k_parameters->tcp_distoratio[j2k_parameters->tcp_numlayers]) == 1) { + j2k_parameters->tcp_numlayers++; + while (*s && *s != ',') { + s++; + } + if (!*s) + break; + s++; + } + j2k_parameters->cp_fixed_quality = 1; + break; + /* dda */ + /* ----------------------------------------------------- */ + case 'f': /* mod fixed_quality (before : -q) */ + { + int *row = NULL, *col = NULL; + int numlayers = 0, numresolution = 0, matrix_width = 0; + + s = optarg; + sscanf(s, "%d", &numlayers); + s++; + if (numlayers > 9) + s++; + + j2k_parameters->tcp_numlayers = numlayers; + numresolution = j2k_parameters->numresolution; + matrix_width = numresolution * 3; + j2k_parameters->cp_matrice = (int *) malloc(numlayers * matrix_width * sizeof(int)); + s = s + 2; + + for (i = 0; i < numlayers; i++) { + row = &j2k_parameters->cp_matrice[i * matrix_width]; + col = row; + j2k_parameters->tcp_rates[i] = 1; + sscanf(s, "%d,", &col[0]); + s += 2; + if (col[0] > 9) + s++; + col[1] = 0; + col[2] = 0; + for (j = 1; j < numresolution; j++) { + col += 3; + sscanf(s, "%d,%d,%d", &col[0], &col[1], &col[2]); + s += 6; + if (col[0] > 9) + s++; + if (col[1] > 9) + s++; + if (col[2] > 9) + s++; + } + if (i < numlayers - 1) + s++; + } + j2k_parameters->cp_fixed_alloc = 1; + } + break; + /* ----------------------------------------------------- */ + case 't': /* tiles */ + sscanf(optarg, "%d,%d", &j2k_parameters->cp_tdx, &j2k_parameters->cp_tdy); + j2k_parameters->tile_size_on = true; + break; + /* ----------------------------------------------------- */ + case 'n': /* resolution */ + sscanf(optarg, "%d", &j2k_parameters->numresolution); + break; + /* ----------------------------------------------------- */ + case 'c': /* precinct dimension */ + { + char sep; + int res_spec = 0; + + char *s = optarg; + do { + sep = 0; + sscanf(s, "[%d,%d]%c", &j2k_parameters->prcw_init[res_spec], + &j2k_parameters->prch_init[res_spec], &sep); + j2k_parameters->csty |= 0x01; + res_spec++; + s = strpbrk(s, "]") + 2; + } + while (sep == ','); + j2k_parameters->res_spec = res_spec; + } + break; + + /* ----------------------------------------------------- */ + case 'b': /* code-block dimension */ + { + int cblockw_init = 0, cblockh_init = 0; + sscanf(optarg, "%d,%d", &cblockw_init, &cblockh_init); + if (cblockw_init * cblockh_init > 4096 || cblockw_init > 1024 + || cblockw_init < 4 || cblockh_init > 1024 || cblockh_init < 4) { + fprintf(stderr, + "!! Size of code_block error (option -b) !!\n\nRestriction :\n" + " * width*height<=4096\n * 4<=width,height<= 1024\n\n"); + return 1; + } + j2k_parameters->cblockw_init = cblockw_init; + j2k_parameters->cblockh_init = cblockh_init; + } + break; + /* ----------------------------------------------------- */ + case 'p': /* progression order */ + { + char progression[4]; + + strncpy(progression, optarg, 4); + j2k_parameters->prog_order = give_progression(progression); + if (j2k_parameters->prog_order == -1) { + fprintf(stderr, "Unrecognized progression order " + "[LRCP, RLCP, RPCL, PCRL, CPRL] !!\n"); + return 1; + } + } + break; + /* ----------------------------------------------------- */ + case 's': /* subsampling factor */ + { + if (sscanf(optarg, "%d,%d", &j2k_parameters->subsampling_dx, + &j2k_parameters->subsampling_dy) != 2) { + fprintf(stderr, "'-s' sub-sampling argument error ! [-s dx,dy]\n"); + return 1; + } + } + break; + /* ----------------------------------------------------- */ + case 'd': /* coordonnate of the reference grid */ + { + if (sscanf(optarg, "%d,%d", &j2k_parameters->image_offset_x0, + &j2k_parameters->image_offset_y0) != 2) { + fprintf(stderr, "-d 'coordonnate of the reference grid' argument " + "error !! [-d x0,y0]\n"); + return 1; + } + } + break; + /* ----------------------------------------------------- */ + case 'h': /* Display an help description */ + help_display(); + return 0; + break; + /* ----------------------------------------------------- */ + case 'P': /* POC */ + { + int numpocs = 0; /* number of progression order change (POC) default 0 */ + opj_poc_t *POC = NULL; /* POC : used in case of Progression order change */ + + char *s = optarg; + POC = j2k_parameters->POC; + + while (sscanf(s, "T%d=%d,%d,%d,%d,%d,%4s", &POC[numpocs].tile, + &POC[numpocs].resno0, &POC[numpocs].compno0, + &POC[numpocs].layno1, &POC[numpocs].resno1, + &POC[numpocs].compno1, POC[numpocs].progorder) == 7) { + POC[numpocs].prg1 = give_progression(POC[numpocs].progorder); + numpocs++; + while (*s && *s != '/') { + s++; + } + if (!*s) { + break; + } + s++; + } + j2k_parameters->numpocs = numpocs; + } + break; + /* ------------------------------------------------------ */ + case 'S': /* SOP marker */ + j2k_parameters->csty |= 0x02; + break; + /* ------------------------------------------------------ */ + case 'E': /* EPH marker */ + j2k_parameters->csty |= 0x04; + break; + /* ------------------------------------------------------ */ + case 'M': /* Mode switch pas tous au point !! */ + if (sscanf(optarg, "%d", &value) == 1) { + for (i = 0; i <= 5; i++) { + int cache = value & (1 << i); + if (cache) + j2k_parameters->mode |= (1 << i); + } + } + break; + /* ------------------------------------------------------ */ + case 'R': /* ROI */ + { + if (sscanf(optarg, "OI:c=%d,U=%d", &j2k_parameters->roi_compno, + &j2k_parameters->roi_shift) != 2) { + fprintf(stderr, "ROI error !! [-ROI:c='compno',U='shift']\n"); + return 1; + } + } + break; + /* ------------------------------------------------------ */ + case 'T': /* Tile offset */ + { + if (sscanf(optarg, "%d,%d", &j2k_parameters->cp_tx0, &j2k_parameters->cp_ty0) != 2) { + fprintf(stderr, "-T 'tile offset' argument error !! [-T X0,Y0]"); + return 1; + } + } + break; + /* ------------------------------------------------------ */ + case 'C': /* Add a comment */ + { + j2k_parameters->cp_comment = (char*)malloc(strlen(optarg) + 1); + if(j2k_parameters->cp_comment) { + strcpy(j2k_parameters->cp_comment, optarg); + } + } + break; + /* ------------------------------------------------------ */ + case 'I': /* reversible or not */ + { + j2k_parameters->irreversible = 1; + } + break; + /* ------------------------------------------------------ */ + case 'W': /* Width and Height and Cb and Cr subsampling in case of YUV format files */ + if (sscanf + (optarg, "%d,%d,%d,%d", &mj2_parameters.w, &mj2_parameters.h, &mj2_parameters.CbCr_subsampling_dx, + &mj2_parameters.CbCr_subsampling_dy) != 4) { + fprintf(stderr, "-W argument error"); + return 1; + } + break; + /* ------------------------------------------------------ */ + case 'F': /* Video frame rate */ + if (sscanf(optarg, "%d", &mj2_parameters.frame_rate) != 1) { + fprintf(stderr, "-F argument error"); + return 1; + } + break; + /* ------------------------------------------------------ */ + default: + return 1; + } + } + + /* Error messages */ + /* -------------- */ + if (!mj2_parameters.cod_format || !mj2_parameters.decod_format) { + fprintf(stderr, + "Usage: %s -i yuv-file -o mj2-file (+ options)\n",argv[0]); + return 1; + } + + if ((j2k_parameters->cp_disto_alloc || j2k_parameters->cp_fixed_alloc || j2k_parameters->cp_fixed_quality) + && (!(j2k_parameters->cp_disto_alloc ^ j2k_parameters->cp_fixed_alloc ^ j2k_parameters->cp_fixed_quality))) { + fprintf(stderr, "Error: options -r -q and -f cannot be used together !!\n"); + return 1; + } /* mod fixed_quality */ + + /* if no rate entered, lossless by default */ + if (j2k_parameters->tcp_numlayers == 0) { + j2k_parameters->tcp_rates[0] = 0; /* MOD antonin : losslessbug */ + j2k_parameters->tcp_numlayers++; + j2k_parameters->cp_disto_alloc = 1; + } + + if((j2k_parameters->cp_tx0 > j2k_parameters->image_offset_x0) || (j2k_parameters->cp_ty0 > j2k_parameters->image_offset_y0)) { + fprintf(stderr, + "Error: Tile offset dimension is unnappropriate --> TX0(%d)<=IMG_X0(%d) TYO(%d)<=IMG_Y0(%d) \n", + j2k_parameters->cp_tx0, j2k_parameters->image_offset_x0, j2k_parameters->cp_ty0, j2k_parameters->image_offset_y0); + return 1; + } + + for (i = 0; i < j2k_parameters->numpocs; i++) { + if (j2k_parameters->POC[i].prg == -1) { + fprintf(stderr, + "Unrecognized progression order in option -P (POC n %d) [LRCP, RLCP, RPCL, PCRL, CPRL] !!\n", + i + 1); + } + } + + if (j2k_parameters->cp_tdx > mj2_parameters.Dim[0] || j2k_parameters->cp_tdy > mj2_parameters.Dim[1]) { + fprintf(stderr, + "Error: Tile offset dimension is unnappropriate --> TX0(%d)<=IMG_X0(%d) TYO(%d)<=IMG_Y0(%d) \n", + j2k_parameters->cp_tdx, mj2_parameters.Dim[0], j2k_parameters->cp_tdy, mj2_parameters.Dim[1]); + return 1; + } + + /* to respect profile - 0 */ + /* ---------------------- */ + + x1 = !mj2_parameters.Dim[0] ? (mj2_parameters.w - 1) * j2k_parameters->subsampling_dx + + 1 : mj2_parameters.Dim[0] + (mj2_parameters.w - 1) * j2k_parameters->subsampling_dx + 1; + y1 = !mj2_parameters.Dim[1] ? (mj2_parameters.h - 1) * j2k_parameters->subsampling_dy + + 1 : mj2_parameters.Dim[1] + (mj2_parameters.h - 1) * j2k_parameters->subsampling_dy + 1; + mj2_parameters.numcomps = 3; /* Because YUV files only have 3 components */ + mj2_parameters.prec = 8; /* Because in YUV files, components have 8-bit depth */ + + j2k_parameters->tcp_mct = 0; + + mj2file = fopen(mj2_parameters.outfile, "wb"); + + if (!mj2file) { + fprintf(stderr, "failed to open %s for writing\n", argv[2]); + return 1; + } + + /* get a MJ2 decompressor handle */ + cinfo = mj2_create_compress(); + movie = (opj_mj2_t*)cinfo->mj2_handle; + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)cinfo, &event_mgr, stderr); + + /* setup encoder parameters */ + mj2_setup_encoder(movie, &mj2_parameters); + + movie->tk[0].num_samples = yuv_num_frames(&movie->tk[0],mj2_parameters.infile); + if (movie->tk[0].num_samples == -1) { + return 1; + } + + // One sample per chunk + movie->tk[0].chunk = (mj2_chunk_t*) malloc(movie->tk[0].num_samples * sizeof(mj2_chunk_t)); + movie->tk[0].sample = (mj2_sample_t*) malloc(movie->tk[0].num_samples * sizeof(mj2_sample_t)); + + if (mj2_init_stdmovie(movie)) { + fprintf(stderr, "Error with movie initialization"); + return 1; + }; + + // Writing JP, FTYP and MDAT boxes + buf = (unsigned char*) malloc (300 * sizeof(unsigned char)); // Assuming that the JP and FTYP + // boxes won't be longer than 300 bytes + cio = opj_cio_open((opj_common_ptr)movie->cinfo, buf, 300); + mj2_write_jp(cio); + mj2_write_ftyp(movie, cio); + mdat_initpos = cio_tell(cio); + cio_skip(cio, 4); + cio_write(cio, MJ2_MDAT, 4); + fwrite(buf,cio_tell(cio),1,mj2file); + offset = cio_tell(cio); + opj_cio_close(cio); + free(buf); + + for (i = 0; i < movie->num_stk + movie->num_htk + movie->num_vtk; i++) { + if (movie->tk[i].track_type != 0) { + fprintf(stderr, "Unable to write sound or hint tracks\n"); + } else { + mj2_tk_t *tk; + int buflen = 0; + + tk = &movie->tk[i]; + tk->num_chunks = tk->num_samples; + numframes = tk->num_samples; + + fprintf(stderr, "Video Track number %d\n", i + 1); + + img = mj2_image_create(tk, j2k_parameters); + buflen = 2 * (tk->w * tk->h * 8); + buf = (unsigned char *) malloc(buflen*sizeof(unsigned char)); + + for (sampleno = 0; sampleno < numframes; sampleno++) { + double init_time = opj_clock(); + double elapsed_time; + if (yuvtoimage(tk, img, sampleno, j2k_parameters, mj2_parameters.infile)) { + fprintf(stderr, "Error with frame number %d in YUV file\n", sampleno); + return 1; + } + + /* setup the encoder parameters using the current image and user parameters */ + opj_setup_encoder(cinfo, j2k_parameters, img); + + cio = opj_cio_open((opj_common_ptr)movie->cinfo, buf, buflen); + + cio_skip(cio, 4); + cio_write(cio, JP2_JP2C, 4); // JP2C + + /* encode the image */ + bSuccess = opj_encode(cinfo, cio, img, NULL); + if (!bSuccess) { + opj_cio_close(cio); + fprintf(stderr, "failed to encode image\n"); + return 1; + } + + len = cio_tell(cio) - 8; + cio_seek(cio, 0); + cio_write(cio, len+8,4); + opj_cio_close(cio); + tk->sample[sampleno].sample_size = len+8; + tk->sample[sampleno].offset = offset; + tk->chunk[sampleno].offset = offset; // There is one sample per chunk + fwrite(buf, 1, len+8, mj2file); + offset += len+8; + elapsed_time = opj_clock()-init_time; + fprintf(stderr, "Frame number %d/%d encoded in %.2f mseconds\n", sampleno + 1, numframes, elapsed_time*1000); + total_time += elapsed_time; + + } + /* free buffer data */ + free(buf); + /* free image data */ + opj_image_destroy(img); + } + } + + fseek(mj2file, mdat_initpos, SEEK_SET); + + buf = (unsigned char*) malloc(4*sizeof(unsigned char)); + + // Init a cio to write box length variable in a little endian way + cio = opj_cio_open(NULL, buf, 4); + cio_write(cio, offset - mdat_initpos, 4); + fwrite(buf, 4, 1, mj2file); + fseek(mj2file,0,SEEK_END); + free(buf); + + // Writing MOOV box + buf = (unsigned char*) malloc ((TEMP_BUF+numframes*20) * sizeof(unsigned char)); + cio = opj_cio_open(movie->cinfo, buf, (TEMP_BUF+numframes*20)); + mj2_write_moov(movie, cio); + fwrite(buf,cio_tell(cio),1,mj2file); + free(buf); + + fprintf(stdout,"Total encoding time: %.2f s for %d frames (%.1f fps)\n", total_time, numframes, (float)numframes/total_time); + + // Ending program + + fclose(mj2file); + /* free remaining compression structures */ + mj2_destroy_compress(movie); + free(cinfo); + /* free user parameters structure */ + if(j2k_parameters->cp_comment) free(j2k_parameters->cp_comment); + if(j2k_parameters->cp_matrice) free(j2k_parameters->cp_matrice); + opj_cio_close(cio); + + return 0; +} + + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/mj2/frames_to_mj2.dsp b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/frames_to_mj2.dsp new file mode 100644 index 0000000..03b9b88 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/frames_to_mj2.dsp @@ -0,0 +1,212 @@ +# Microsoft Developer Studio Project File - Name="frames_to_mj2" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=frames_to_mj2 - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "frames_to_mj2.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "frames_to_mj2.mak" CFG="frames_to_mj2 - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "frames_to_mj2 - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "frames_to_mj2 - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "frames_to_mj2 - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "../libopenjpeg" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "OPJ_STATIC" /FR /YX /FD /c +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# SUBTRACT LINK32 /pdb:none /incremental:yes /debug + +!ELSEIF "$(CFG)" == "frames_to_mj2 - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "frames_to_mj2___Win32_Debug0" +# PROP BASE Intermediate_Dir "frames_to_mj2___Win32_Debug0" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "frames_to_mj2___Win32_Debug0" +# PROP Intermediate_Dir "frames_to_mj2___Win32_Debug0" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MT /W3 /Gm /GX /ZI /Od /I "../libopenjpeg" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "OPJ_STATIC" /FR /YX /FD /GZ /c +# ADD BASE RSC /l 0x809 /d "_DEBUG" +# ADD RSC /l 0x809 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /nodefaultlib:"libcmt" /pdbtype:sept +# SUBTRACT LINK32 /pdb:none + +!ENDIF + +# Begin Target + +# Name "frames_to_mj2 - Win32 Release" +# Name "frames_to_mj2 - Win32 Debug" +# Begin Group "MJ2" + +# PROP Default_Filter "" +# Begin Group "MJ2 Header Files" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\mj2.h +# End Source File +# Begin Source File + +SOURCE=.\mj2_convert.h +# End Source File +# End Group +# Begin Group "MJ2 Source Files" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\frames_to_mj2.c +# End Source File +# Begin Source File + +SOURCE=.\compat\getopt.c +# End Source File +# Begin Source File + +SOURCE=.\mj2.c +# End Source File +# Begin Source File + +SOURCE=.\mj2_convert.c +# End Source File +# End Group +# End Group +# Begin Group "Libopenjpeg Header files" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\libopenjpeg\bio.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\cio.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\dwt.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\event.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\fix.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\image.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\int.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\j2k.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\j2k_lib.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\jp2.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\jpt.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\mct.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\mqc.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\openjpeg.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\opj_includes.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\pi.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\raw.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\t1.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\t2.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\tcd.h +# End Source File +# Begin Source File + +SOURCE=..\libopenjpeg\tgt.h +# End Source File +# End Group +# End Target +# End Project diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/mj2/frames_to_mj2.dsw b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/frames_to_mj2.dsw new file mode 100644 index 0000000..64eedeb --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/frames_to_mj2.dsw @@ -0,0 +1,44 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "frames_to_mj2"=".\frames_to_mj2.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name LibOpenJPEG + End Project Dependency +}}} + +############################################################################### + +Project: "LibOpenJPEG"="..\LibOpenJPEG.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/mj2/frames_to_mj2.sln b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/frames_to_mj2.sln new file mode 100644 index 0000000000000000000000000000000000000000..f62e33dc28310e3481cebc013182f6db78196f0c GIT binary patch literal 1508 zcmbW1-)@^Q6vlU3B;EnBn@*~cArPF4USKe-rgn=KX}g(JkzgWM1V{YoO`0d$MIWiJ z(8CfE+)f=0SN1vfIX{2?%=4coUAq;FQdTmnjh~`wlH8cpO)8`@lX+7MSs1a%`Gpb7 za+SauURG^zVqvUnpI_~9F!pq9TFQIAsL#y}q2VNClpsRg0NHkg5s7RYVI1IaVnfz- zw&oY((lE0!S@G(wmUpXr$GmtIupSm`sM^LiZs?DRM=4^CJw`4eAtGbnLvic{o*T0W zzOAWiXM2trumJM;ej4#LFH&AC1h3l8YgyI%6znT_wxZVES`$q0O3Wi?uvhIFM>RY-N>EUgC UlPL!i#lg*t{j + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/mj2/meta_out.c b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/meta_out.c new file mode 100644 index 0000000..ff80b5e --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/meta_out.c @@ -0,0 +1,2181 @@ +/* meta_out.c */ +/* Dump MJ2, JP2 metadata (partial so far) to xml file */ +/* Callable from mj2_to_metadata */ +/* Contributed to Open JPEG by Glenn Pearson, contract software developer, U.S. National Library of Medicine. + +The base code in this file was developed by the author as part of a video archiving +project for the U.S. National Library of Medicine, Bethesda, MD. +It is the policy of NLM (and U.S. government) to not assert copyright. + +A non-exclusive copy of this code has been contributed to the Open JPEG project. +Except for copyright, inclusion of the code within Open JPEG for distribution and use +can be bound by the Open JPEG open-source license and disclaimer, expressed elsewhere. +*/ + +#include /* for time functions */ + +#include "../libopenjpeg/opj_includes.h" +#include "mj2.h" + +#include +#include "meta_out.h" + +static BOOL notes = TRUE; +static BOOL sampletables = FALSE; +static BOOL raw = TRUE; +static BOOL derived = TRUE; + +opj_tcp_t *j2k_default_tcp; + +/* Forwards */ +int xml_write_overall_header(FILE *file, FILE *xmlout, opj_mj2_t * movie, unsigned int sampleframe, opj_event_mgr_t *event_mgr); +int xml_write_moov(FILE *file, FILE *xmlout, opj_mj2_t * movie, unsigned int sampleframe, opj_event_mgr_t *event_mgr); + +void uint_to_chars(unsigned int value, char* buf); + +void xml_write_trak(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum, unsigned int sampleframe, opj_event_mgr_t *event_mgr); +void xml_write_tkhd(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum); +void xml_write_udta(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum); +void xml_write_mdia(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum); +void xml_write_stbl(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum); + +void UnixTimeToFileTime(time_t t, LPFILETIME pft); +void UnixTimeToSystemTime(time_t t, LPSYSTEMTIME pst); +void xml_time_out(FILE* xmlout, time_t t); + +void int16_to_3packedchars(short int value, char* buf); + +void xml_write_moov_udta(FILE* xmlout, opj_mj2_t * movie); +void xml_write_free_and_skip(FILE* xmlout, opj_mj2_t * movie); +void xml_write_uuid(FILE* xmlout, opj_mj2_t * movie); + +int xml_out_frame(FILE* file, FILE* xmlout, mj2_sample_t *sample, unsigned int snum, opj_event_mgr_t *event_mgr); + +void xml_out_frame_siz(FILE* xmlout, opj_image_t *img, opj_cp_t *cp); +void xml_out_frame_cod(FILE* xmlout, opj_tcp_t *tcp); +void xml_out_frame_coc(FILE* xmlout, opj_tcp_t *tcp, int numcomps); /* opj_image_t *img); */ +BOOL same_component_style(opj_tccp_t *tccp1, opj_tccp_t *tccp2); +void xml_out_frame_qcd(FILE* xmlout, opj_tcp_t *tcp); +void xml_out_frame_qcc(FILE* xmlout, opj_tcp_t *tcp, int numcomps); /* opj_image_t *img); */ +BOOL same_component_quantization(opj_tccp_t *tccp1, opj_tccp_t *tccp2); +void xml_out_frame_rgn(FILE* xmlout, opj_tcp_t *tcp, int numcomps);/* opj_image_t *img);*/ +void xml_out_frame_poc(FILE* xmlout, opj_tcp_t *tcp); +void xml_out_frame_ppm(FILE* xmlout, opj_cp_t *cp); +void xml_out_frame_ppt(FILE* xmlout, opj_tcp_t *tcp); +void xml_out_frame_tlm(FILE* xmlout); /* j2k_default_tcp is passed globally */ /* NO-OP. TLM NOT SAVED IN DATA STRUCTURE */ +void xml_out_frame_plm(FILE* xmlout); /* j2k_default_tcp is passed globally */ /* NO-OP. PLM NOT SAVED IN DATA STRUCTURE. opt in main; can be used in conjunction with PLT */ +void xml_out_frame_plt(FILE* xmlout, opj_tcp_t *tcp); /* NO-OP. PLM NOT SAVED IN DATA STRUCTURE. opt in main; can be used in conjunction with PLT */ +void xml_out_frame_crg(FILE* xmlout); /* j2k_default_tcp is passed globally */ /* opt in main; */ +void xml_out_frame_com(FILE* xmlout, opj_tcp_t *tcp); /* NO-OP. COM NOT SAVED IN DATA STRUCTURE */ /* opt in main; */ +void xml_out_dump_hex(FILE* xmlout, char *data, int data_len, char* s); +void xml_out_dump_hex_and_ascii(FILE* xmlout, char *data, int data_len, char* s); +void xml_out_frame_jp2h(FILE* xmlout, opj_jp2_t *jp2_struct); +#ifdef NOTYET +/* Shown with cp, extended, as data structure... but it could be a new different one */ +void xml_out_frame_jp2i(FILE* xmlout, opj_cp_t *cp);/* IntellectualProperty 'jp2i' (no restrictions on location) */ +void xml_out_frame_xml(FILE* xmlout, opj_cp_t *cp); /* XML 'xml\040' (0x786d6c20). Can appear multiply */ +void xml_out_frame_uuid(FILE* xmlout, opj_cp_t *cp); /* UUID 'uuid' (top level only) */ +void xml_out_frame_uinf(FILE* xmlout, opj_cp_t *cp); /* UUIDInfo 'uinf', includes UUIDList 'ulst' and URL 'url\40' */ +void xml_out_frame_unknown_type(FILE* xmlout, opj_cp_t *cp); +#endif + + +void xml_write_init(BOOL n, BOOL t, BOOL r, BOOL d) +{ + /* Init file globals */ + notes = n; + sampletables = t; + raw = r; + derived = d; +} + +int xml_write_struct(FILE* file, FILE *xmlout, opj_mj2_t * movie, unsigned int sampleframe, char* stringDTD, opj_event_mgr_t *event_mgr) { + + if(stringDTD != NULL) + { + fprintf(xmlout,"\n"); + /* stringDTD is known to start with "SYSTEM " or "PUBLIC " */ + /* typical: SYSTEM mj2_to_metadata.dtd */ + stringDTD[6] = '\0'; /* Break into two strings at space, so quotes can be inserted. */ + fprintf(xmlout,"\n", stringDTD, stringDTD+7); + stringDTD[6] = ' '; /* restore for sake of debugger or memory allocator */ + } else + fprintf(xmlout,"\n"); + + fprintf(xmlout, "\n"); + xml_write_overall_header(file, xmlout, movie, sampleframe, event_mgr); + fprintf(xmlout, ""); + return 0; +} + +/* ------------- */ + +int xml_write_overall_header(FILE *file, FILE *xmlout, opj_mj2_t * movie, unsigned int sampleframe, opj_event_mgr_t *event_mgr) +{ + int i; + char buf[5]; + buf[4] = '\0'; + + fprintf(xmlout, " \n"); + // Called after structure initialized by mj2_read_ftyp + fprintf(xmlout, " \n"); + uint_to_chars(movie->brand, buf); + fprintf(xmlout, " %s\n", buf); /* 4 character; BR */ + fprintf(xmlout, " %u\n", movie->minversion); /* 4 char; MinV */ + fprintf(xmlout, " \n",movie->num_cl); + for (i = movie->num_cl - 1; i > -1; i--) /* read routine stored in reverse order, so let's undo damage */ + { + uint_to_chars(movie->cl[i], buf); + fprintf(xmlout, " %s\n", buf); /*4 characters, each CLi */ + } + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + xml_write_moov(file, xmlout, movie, sampleframe, event_mgr); + // To come? // This is the container for media data that can also be accessed through track structures, + // so is redundant, and simply not of interest as metadata + // // Allows incremental build up of movie. Probably not in Simple Profile + xml_write_free_and_skip(xmlout, movie); /* NO OP so far */ /* May be a place where user squirrels metadata */ + xml_write_uuid(xmlout, movie); /* NO OP so far */ /* May be a place where user squirrels metadata */ + return 0; +} + +/* ------------- */ + +int xml_write_moov(FILE *file, FILE *xmlout, opj_mj2_t * movie, unsigned int sampleframe, opj_event_mgr_t *event_mgr) +{ + unsigned int tnum; + mj2_tk_t *track; + + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + if(raw) + fprintf(xmlout, " %u\n", movie->creation_time); + if(notes) + fprintf(xmlout, " \n"); + /* 2082844800 = seconds between 1/1/04 and 1/1/70 */ + /* There's still a time zone offset problem not solved... but spec is ambigous as to whether stored time + should be local or UTC */ + if(derived) { + fprintf(xmlout, " "); + xml_time_out(xmlout, movie->creation_time - 2082844800); + fprintf(xmlout,"\n"); + } + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + if(raw) + fprintf(xmlout, " %u\n", movie->modification_time); + if(derived) { + fprintf(xmlout, " "); + xml_time_out(xmlout, movie->modification_time - 2082844800); + fprintf(xmlout,"\n"); + } + fprintf(xmlout, " \n"); + fprintf(xmlout, " %d\n", movie->timescale); + if(notes) + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); /* Rate to play presentation (default = 0x00010000) */ + if(notes) { + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } + if(raw) + fprintf(xmlout, " 0x%08x\n", movie->rate); + if(derived) + fprintf(xmlout, " %12.6f\n", (double)movie->rate/(double)0x00010000); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + if(raw) + fprintf(xmlout, " %u\n", movie->duration); + if(derived) + fprintf(xmlout, " %12.3f\n", (double)movie->duration/(double)movie->timescale); // Make this double later to get fractional seconds + fprintf(xmlout, " \n"); +#ifdef CURRENTSTRUCT + movie->volume = movie->volume << 8; +#endif + fprintf(xmlout, " \n"); + if(notes) { + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } + if(raw) + fprintf(xmlout, " 0x%04x\n", movie->volume); + if(derived) + fprintf(xmlout, " %6.3f\n", (double)movie->volume/(double)0x0100); + fprintf(xmlout, " \n"); +#ifdef CURRENTSTRUCT + if(notes) + fprintf(xmlout, " \n"); + movie->volume = movie->volume >> 8; +#endif + /* Transformation matrix for video */ + fprintf(xmlout, " \n"); + if(notes) { + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } + fprintf(xmlout, " 0x%08x\n", movie->trans_matrix[0]); + fprintf(xmlout, " 0x%08x\n", movie->trans_matrix[1]); + fprintf(xmlout, " 0x%08x\n", movie->trans_matrix[2]); + fprintf(xmlout, " 0x%08x\n", movie->trans_matrix[3]); + fprintf(xmlout, " 0x%08x\n", movie->trans_matrix[4]); + fprintf(xmlout, " 0x%08x\n", movie->trans_matrix[5]); + fprintf(xmlout, " 0x%08x\n", movie->trans_matrix[6]); + fprintf(xmlout, " 0x%08x\n", movie->trans_matrix[7]); + fprintf(xmlout, " 0x%08x\n", movie->trans_matrix[8]); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n", movie->num_vtk); + fprintf(xmlout, " \n", movie->num_stk); + fprintf(xmlout, " %d\n", movie->num_htk); + if(notes) + fprintf(xmlout, " \n"); + /* See Part 3 Amend 2 Section 4.2 for relation of MJ2 to Part 12 Sections 7 and 10 hints */ + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + /* Idea for the future: It would be possible to add code to verify that the file values: + 1) are legal and self-consistent + 2) comply with particular JP2 and/or MJ2 profiles. + This could be reported here as additional XML elements */ + + // Find first video track + tnum = 0; + while (movie->tk[tnum].track_type != 0) + tnum ++; + + track = &(movie->tk[tnum]); + // For now, output info on first video track + xml_write_trak(file, xmlout, track, tnum, sampleframe, event_mgr); + + // to come: // possibly not in Simple Profile + xml_write_moov_udta(xmlout, movie); /* NO OP so far */ /* contains */ + fprintf(xmlout, " \n"); + return 0; +} + +/* --------------- */ + +void uint_to_chars(unsigned int value, char* buf) +{ + /* buf is at least char[5] */ + int i; + for (i = 3; i >= 0; i--) + { + buf[i] = (value & 0x000000ff); + value = (value >> 8); + } + buf[4] = '\0'; /* Precautionary */ +} + +/* ------------- */ + +/* WINDOWS SPECIFIC */ + +void UnixTimeToFileTime(time_t t, LPFILETIME pft) +{ + /* Windows specific. From MS Q167296 */ + /* 'time_t' represents seconds since midnight January 1, 1970 UTC (coordinated universal time). */ + /* 64-bit FILETIME structure represents the number of 100-nanosecond intervals since January 1, 1601 UTC (coordinate universal time). */ + LONGLONG ll; /* LONGLONG is a 64-bit value. */ + ll = Int32x32To64(t, 10000000) + 116444736000000000; + pft->dwLowDateTime = (DWORD)ll; + /* pft->dwLowDateTime = (DWORD)(0x00000000ffffffff & ll); */ + pft->dwHighDateTime = (DWORD)(ll >> 32); +} +// Once the UNIX time is converted to a FILETIME structure, +// other Win32 time formats can be easily obtained by using Win32 functions such +// as FileTimeToSystemTime() and FileTimeToDosDateTime(). + +/* ------------- */ + +void UnixTimeToSystemTime(time_t t, LPSYSTEMTIME pst) +{ + /* Windows specific */ + FILETIME ft; + UnixTimeToFileTime(t, &ft); + FileTimeToLocalFileTime( &ft, &ft ); /* Adjust from UTC to local time zone */ + FileTimeToSystemTime(&ft, pst); +} + +/* ------------- */ + +void xml_time_out(FILE* xmlout, time_t t) +{ + /* Windows specific */ + SYSTEMTIME st; + char szLocalDate[255], szLocalTime[255]; + UnixTimeToSystemTime( t, &st ); + GetDateFormat( LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, szLocalDate, 255 ); + GetTimeFormat( LOCALE_USER_DEFAULT, 0, &st, NULL, szLocalTime, 255 ); + fprintf(xmlout, "%s %s", szLocalDate, szLocalTime ); +} + +/* END WINDOWS SPECIFIC */ + +/* ------------- */ + +void xml_write_moov_udta(FILE* xmlout, opj_mj2_t * movie) { + /* Compare with xml_write_udta */ +#ifdef NOTYET + /* NO-OP so far. Optional UserData 'udta' (zero or one in moov or each trak) + can contain multiple Copyright 'cprt' with different language codes */ + /* There may be nested non-standard boxes within udta */ + IMAGINE movie->udta, movie->copyright_count, movie->copyright_language[i] (array of 16bit ints), movie->copyright_notice[i] (array of buffers) + PROBABLY ALSO NEED movie->udta_len or special handler for non-standard boxes + char buf[5]; + int i; + + if(movie->udta != 1) + return; /* Not present */ + + fprintf(xmlout, " \n"); + for(i = 0; i < movie->copyright_count; i++) { + fprintf(xmlout, " Instance=\"%d\">\n", i+1); + int16_to_3packedchars((short int)movie->copyright_languages[i], buf); + fprintf(xmlout, " %s\n", buf); /* 3 chars */ + fprintf(xmlout, " %s\n",movie->copyright_notices[i]); + fprintf(xmlout, " \n", i+1); + } + /* TO DO: Non-standard boxes */ + fprintf(xmlout, " \n"); +#endif +} + +void xml_write_free_and_skip(FILE* xmlout, opj_mj2_t * movie) { +#ifdef NOTYET + /* NO-OP so far. There can be zero or more instances of free and/or skip + at the top level of the file. This may be a place where the user squirrel's metadata. + Let's assume unstructured, and do a dump */ + IMAGINE movie->free_and_skip, movie->free_and_skip_count, movie->free_and_skip_content[i] (array of buffers), + movie->free_and_skip_len[i] (array of ints), movie->is_skip[i] (array of BOOL) + int i; + + if(movie->free_and_skip != 1) + return; /* Not present */ + + for(i = 0; i < movie->free_and_skip_count; i++) { + if(movie->is_skip[i]) + fprintf(xmlout, " \n"); + else + fprintf(xmlout, " \n"); + + xml_out_dump_hex_and_ascii(xmlout, movie->free_and_skip_contents[i], movie->free_and_skip_len[i]); + + if(movie->is_skip[i]) + fprintf(xmlout, " \n"); + else + fprintf(xmlout, " \n"); + } +#endif +} + +void xml_write_uuid(FILE* xmlout, opj_mj2_t * movie) { +/* Univeral Unique IDs of 16 bytes. */ +#ifdef NOTYET + /* NO-OP so far. There can be zero or more instances of private uuid boxes in a file. + This function supports the top level of the file, but uuid may be elsewhere [not yet supported]. + This may be a place where the user squirrel's metadata. Let's assume unstructured, and do a dump */ + IMAGINE movie->uuid, movie->uuid_count, movie->uuid_content[i] (array of buffers), + movie->uuid_len[i] (array of ints), movie->uuid_type[i] (array of 17-byte (16+null termination) buffers) + int i; + + if(movie->uuid != 1) + return; /* Not present */ + + for(i = 0; i < movie->uuid_count; i++) { + fprintf(xmlout, " \n", movie->uuid_type[i]); + // See Part III section 5.2.1, 6.1, 6.2 + xml_out_dump_hex_and_ascii(xmlout, movie->uuid_contents[i], movie->uuid_len[i]); + fprintf(xmlout, " \n"); + } +#endif +} + +/* ------------- */ + +void xml_write_trak(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum, unsigned int sampleframe, opj_event_mgr_t *event_mgr) +{ + fprintf(xmlout, " \n", tnum); + xml_write_tkhd(file, xmlout, track, tnum); + // TO DO: TrackReferenceContainer 'tref' just used in hint track + // TO DO: EditListContainer 'edts', contains EditList 'elst' with media-time, segment-duration, media-rate + xml_write_mdia(file, xmlout, track, tnum); + xml_write_udta(file, xmlout, track, tnum); // NO-OP so far. Optional UserData 'udta', can contain multiple Copyright 'cprt' + + if(track->track_type==0) { /* Only do for visual track */ + /* sampleframe is from user option -f. 1 = first frame */ + /* sampleframe of 0 is a user requests: no jp2 header */ + /* Treat out-of-bounds values in the same way */ + if(sampleframe > 0 && sampleframe <= track->num_samples) + { + mj2_sample_t *sample; + unsigned int snum; + + snum = sampleframe-1; + // Someday maybe do a smart range scan... for (snum=0; snum < track->num_samples; snum++){ + // fprintf(stdout,"Frame %d: ",snum+1); + sample = &track->sample[snum]; + if(xml_out_frame(file, xmlout, sample, snum, event_mgr)) + return; /* Not great error handling here */ + } + } + fprintf(xmlout, " \n"); +} + +/* ------------- */ + +void xml_write_tkhd(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum) +{ + fprintf(xmlout, " \n"); + if(notes) { + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } + fprintf(xmlout, " %u\n", track->track_ID); + if(track->track_type==0) /* For visual track */ + { + fprintf(xmlout, " %d\n", track->layer); + if(notes) + fprintf(xmlout," \n"); + } + if(track->track_type!=0) /* volume irrelevant for visual track */ + { +#ifdef CURRENTSTRUCT + track->volume = track->volume << 8; +#endif + fprintf(xmlout, " \n"); + if(notes) { + fprintf(xmlout," \n"); + fprintf(xmlout," \n"); + } + if(raw) + fprintf(xmlout," 0x%04x\n", track->volume); + if(derived) + fprintf(xmlout," %6.3f\n", (double)track->volume/(double)0x0100); + fprintf(xmlout, " \n"); +#ifdef CURRENTSTRUCT + if(notes) + fprintf(xmlout, " \n"); + track->volume = track->volume >> 8; +#endif + } + if(track->track_type==0) + { + /* Transformation matrix for video */ + fprintf(xmlout, " \n"); + if(notes) { + fprintf(xmlout," \n"); + fprintf(xmlout," \n"); + } + fprintf(xmlout, " 0x%08x\n", track->trans_matrix[0]); + fprintf(xmlout, " 0x%08x\n", track->trans_matrix[1]); + fprintf(xmlout, " 0x%08x\n", track->trans_matrix[2]); + fprintf(xmlout, " 0x%08x\n", track->trans_matrix[3]); + fprintf(xmlout, " 0x%08x\n", track->trans_matrix[4]); + fprintf(xmlout, " 0x%08x\n", track->trans_matrix[5]); + fprintf(xmlout, " 0x%08x\n", track->trans_matrix[6]); + fprintf(xmlout, " 0x%08x\n", track->trans_matrix[7]); + fprintf(xmlout, " 0x%08x\n", track->trans_matrix[8]); + fprintf(xmlout, " \n"); + } +#ifdef CURRENTSTRUCT + track->w = track->w << 16; + track->h = track->h << 16; +#endif + if(notes) { + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } + fprintf(xmlout, " \n"); + if(raw) + fprintf(xmlout, " 0x%08x\n", track->w); + if(derived) + fprintf(xmlout, " %12.6f\n", (double)track->w/(double)0x00010000); /* Rate to play presentation (default = 0x00010000) */ + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + if(raw) + fprintf(xmlout, " 0x%08x\n", track->h); + if(derived) + fprintf(xmlout, " %12.6f\n", (double)track->h/(double)0x00010000); /* Rate to play presentation (default = 0x00010000) */ + fprintf(xmlout, " \n"); +#ifdef CURRENTSTRUCT + if(notes) { + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } + track->w = track->w >> 16; + track->h = track->h >> 16; +#endif + fprintf(xmlout, " \n"); +} + +/* ------------- */ + +void xml_write_udta(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum) { + /* NO-OP so far. Optional UserData 'udta' (zero or one in moov or each trak) + can contain multiple Copyright 'cprt' with different language codes */ + /* There may be nested non-standard boxes within udta */ +#ifdef NOTYET + IMAGINE track->udta, track->copyright_count, track->copyright_language[i] (array of 16bit ints), track->copyright_notice[i] (array of buffers) + PROBABLY ALSO NEED track->udta_len or special handler for non-standard boxes + char buf[5]; + int i; + + if(track->udta != 1) + return; /* Not present */ + + fprintf(xmlout, " \n"); + for(i = 0; i < track->copyright_count; i++) { + fprintf(xmlout, " Instance=\"%d\">\n", i+1); + int16_to_3packedchars((short int)track->copyright_languages[i], buf); + fprintf(xmlout, " %s\n", buf); /* 3 chars */ + fprintf(xmlout, " %s\n",track->copyright_notices[i]); + fprintf(xmlout, " \n", i+1); + } + /* TO DO: Non-standard boxes */ + fprintf(xmlout, " \n"); +#endif +} + +/* ------------- */ + +void xml_write_mdia(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum) +{ + char buf[5]; + int i, k; + buf[4] = '\0'; + + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + if(raw) + fprintf(xmlout, " %u\n", track->creation_time); + if(notes) + fprintf(xmlout, " \n"); + /* 2082844800 = seconds between 1/1/04 and 1/1/70 */ + /* There's still a time zone offset problem not solved... but spec is ambigous as to whether stored time + should be local or UTC */ + if(derived) { + fprintf(xmlout, " "); + xml_time_out(xmlout, track->creation_time - 2082844800); + fprintf(xmlout,"\n"); + } + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + if(raw) + fprintf(xmlout, " %u\n", track->modification_time); + if(derived) { + fprintf(xmlout, " "); + xml_time_out(xmlout, track->modification_time - 2082844800); + fprintf(xmlout,"\n"); + } + fprintf(xmlout, " \n"); + fprintf(xmlout, " %d\n", track->timescale); + if(notes) + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + if(raw) + fprintf(xmlout, " %u\n", track->duration); + if(derived) + fprintf(xmlout, " %12.3f\n", (double)track->duration/(double)track->timescale); // Make this double later to get fractional seconds + fprintf(xmlout, " \n"); + int16_to_3packedchars((short int)track->language, buf); + fprintf(xmlout, " %s\n", buf); /* 3 chars */ + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + switch(track->track_type) + { + case 0: + fprintf(xmlout, " video media track\n"); break; + case 1: + fprintf(xmlout, " Sound\n"); break; + case 2: + fprintf(xmlout, " Hint\n"); break; + } + if(notes) { + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + switch(track->track_type) + { + case 0: + fprintf(xmlout, " \n"); + fprintf(xmlout, " 0x%02x\n", track->graphicsmode); + if(notes) { + fprintf(xmlout," \n"); + fprintf(xmlout," \n"); + fprintf(xmlout," \n"); + fprintf(xmlout," \n"); +/* fprintf(xmlout," \n"); This was evidently dropped upon amendment */ + fprintf(xmlout," \n"); + fprintf(xmlout," \n"); + } + fprintf(xmlout, " \n"); + fprintf(xmlout, " 0x%02x\n", track->opcolor[0]); + fprintf(xmlout, " 0x%02x\n",track->opcolor[1]); + fprintf(xmlout, " 0x%02x\n",track->opcolor[2]); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + break; + case 1: + fprintf(xmlout, " \n"); +#ifdef CURRENTSTRUCT + track->balance = track->balance << 8; +#endif + fprintf(xmlout, " \n"); + if(notes) { + fprintf(xmlout," \n"); + fprintf(xmlout," \n"); + fprintf(xmlout," \n"); + } + if(raw) + fprintf(xmlout," 0x%04x\n", track->balance); + if(derived) + fprintf(xmlout," %6.3f\n", (double)track->balance/(double)0x0100); + fprintf(xmlout, " \n"); +#ifdef CURRENTSTRUCT + if(notes) + fprintf(xmlout," \n"); + track->balance = track->balance >> 8; +#endif + fprintf(xmlout, " \n"); + break; + case 2: + fprintf(xmlout, " \n"); + fprintf(xmlout, " %d\n", track->maxPDUsize); + if(notes) + fprintf(xmlout," \n"); + fprintf(xmlout, " %d\n", track->avgPDUsize); + if(notes) + fprintf(xmlout," \n"); + fprintf(xmlout, " %d\n", track->maxbitrate); + if(notes) + fprintf(xmlout," \n"); + fprintf(xmlout, " %d\n", track->avgbitrate); + if(notes) + fprintf(xmlout," \n"); + fprintf(xmlout, " %d\n", track->slidingavgbitrate); + if(notes) + fprintf(xmlout," \n"); + fprintf(xmlout, " \n"); + break; + } + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n", track->num_url, track->num_urn); // table w. flags, URLs, URNs + // Data structure does not distinguish between single URL, single URN, or DREF table or URLs & URNs. + // We could infer those, but for now just present everything as a DREF table. + if(notes) + fprintf(xmlout, " \n"); + for(k = 0; k < track->num_url; k++) { + fprintf(xmlout, " \n"); // table w. flags, URLs, URNs + if(notes) + fprintf(xmlout," \n"); + for(i = 0; i < 4; i++) { + uint_to_chars(track->url[track->num_url].location[i], buf); + fprintf(xmlout, " %s\n"); + } + fprintf(xmlout, " \n"); // table w. flags, URLs, URNs + } + for(k = 0; k < track->num_urn; k++) { + fprintf(xmlout," \n"); // table w. flags, URLs, URNs + // Only the first 16 bytes are recorded in the data structure currently. + if(notes) + fprintf(xmlout," \n"); + fprintf(xmlout, " "); + for(i = 0; i < 4; i++) { + uint_to_chars(track->urn[track->num_urn].name[i], buf); + fprintf(xmlout,"%s", buf); + } + fprintf(xmlout, "\n"); + fprintf(xmlout, " "); + for(i = 0; i < 4; i++) { + uint_to_chars(track->urn[track->num_urn].location[i], buf); + fprintf(xmlout,"%s"); + } + fprintf(xmlout, "\n"); + fprintf(xmlout, " \n"); + } + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + + xml_write_stbl(file, xmlout, track, tnum); /* SampleTable */ + + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); +} + +/* ------------- */ + +void xml_write_stbl(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum) +{ + char buf[5], buf33[33]; + int i, len; + buf[4] = '\0'; + + fprintf(xmlout, " \n"); + if(notes) + fprintf(xmlout, " \n"); + switch(track->track_type) + { + case 0: + // There could be multiple instances of this, but "entry_count" is just a local at read-time. + // And it's used wrong, too, as count of just visual type, when it's really all 3 types. + // This is referred to as "smj2" within mj2.c + fprintf(xmlout, " \n"); + if(notes) { + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } + /* No shifting required. If CURRENTSTRUCT gets changed, then may need to revisit treatment of these */ + fprintf(xmlout, " %d\n", track->w); + fprintf(xmlout, " %d\n", track->h); +// Horizresolution and vertresolution don't require shifting, already stored right in CURRENTSTRUCT + if(notes) { + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } + fprintf(xmlout, " \n"); + if(raw) + fprintf(xmlout, " 0x%08x\n", track->horizresolution); + if(derived) + fprintf(xmlout, " %12.6f\n", (double)track->horizresolution/(double)0x00010000); /* Rate to play presentation (default = 0x00010000) */ + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + if(raw) + fprintf(xmlout, " 0x%08x\n", track->vertresolution); + if(derived) + fprintf(xmlout, " %12.6f\n", (double)track->vertresolution/(double)0x00010000); /* Rate to play presentation (default = 0x00010000) */ + fprintf(xmlout, " \n"); + + buf33[0] = '\0'; + for(i = 0; i < 8; i++) { + uint_to_chars((unsigned int)track->compressorname[i], buf); + strcat(buf33, buf); /* This loads up (4 * 8) + 1 chars, but trailing ones are usually junk */ + } + len = (int)buf33[0]; /* First byte has string length in bytes. There may be garbage beyond it. */ + buf33[len+1] = '\0'; /* Suppress it */ + fprintf(xmlout, " %s\n", buf33+1); /* Start beyond first byte */ + if(notes) { + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } + fprintf(xmlout, " 0x%02x\n",track->depth); + if(notes) { + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } + + xml_out_frame_jp2h(xmlout, &(track->jp2_struct)); /* JP2 Header */ + + /* Following subboxes are optional */ + fprintf(xmlout, " \n"); + fprintf(xmlout, " %d\n", (unsigned int)track->fieldcount); /* uchar as 1 byte uint */ + if(notes) + fprintf(xmlout, " \n"); + fprintf(xmlout, " %d\n", (unsigned int)track->fieldorder); /* uchar as 1 byte uint */ + if(notes) { + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } + fprintf(xmlout, " \n"); + + fprintf(xmlout, " \n",track->num_br); + for (i = 0; i < track->num_br; i++) /* read routine stored in reverse order, so let's undo damage */ + { + uint_to_chars(track->br[i], buf); + fprintf(xmlout, " %s\n", buf); /*4 characters, each CLi */ + } + fprintf(xmlout, " \n"); + + fprintf(xmlout, " \n",track->num_jp2x); + for (i = 0; i < track->num_jp2x; i++) + { // We'll probably need better formatting than this + fprintf(xmlout, " 0x%02x\n", track->jp2xdata[i]); /* Each entry is single byte */ + } + fprintf(xmlout, " \n"); + + fprintf(xmlout, " \n"); /* These values are all 1 byte */ + if(notes) + fprintf(xmlout, " \n"); + fprintf(xmlout, " %d\n", track->hsub); + fprintf(xmlout, " %d\n", track->vsub); + fprintf(xmlout, " %d\n", track->hoff); + fprintf(xmlout, " %d\n", track->voff); + if(notes) { + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } + fprintf(xmlout, " \n"); /* These values are all 1 byte */ + + fprintf(xmlout, " \n"); /* Part III Appx. 2 */ + fprintf(xmlout, " %u\n", (unsigned int)track->or_fieldcount); /* uchar as 1-byte uint */ + if(notes) + fprintf(xmlout, " \n"); + fprintf(xmlout, " %u\n", (unsigned int)track->or_fieldorder); /* uchar as 1-byte uint */ + if(notes) { + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + break; + case 1: case 2: + if(notes) + fprintf(xmlout, " \n"); break; + } + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " %d\n", track->num_samples); + if(notes) + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n", track->num_tts); + for (i = 0; i < track->num_tts; i++) { + fprintf(xmlout, " \n", + i+1, track->tts[i].sample_count, track->tts[i].sample_delta); + } + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + + fprintf(xmlout, " \n", track->num_samplestochunk); + for (i = 0; i < track->num_samplestochunk; i++) { + fprintf(xmlout, " %u\n",track->sampletochunk[i].first_chunk); /* 4 bytes */ + fprintf(xmlout, " %u\n",track->sampletochunk[i].samples_per_chunk); /* 4 bytes */ + fprintf(xmlout, " %u\n",track->sampletochunk[i].sample_descr_idx); /* 4 bytes */ + } + fprintf(xmlout, " \n"); + // After reading this info in, track->num_chunks is calculated and a decompressed table established internally. + + fprintf(xmlout, " \n"); + if(track->same_sample_size) { + // all values in track->sample[i].sample_size are equal. Grab the first one. + fprintf(xmlout, " %u\n", track->sample[0].sample_size); + if(notes) { + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } + } else { + fprintf(xmlout, " 0\n"); + if(notes) + if(sampletables) + fprintf(xmlout," \n"); + else + fprintf(xmlout," \n"); + fprintf(xmlout, " %u\n", track->num_samples); + if(sampletables) + for (i = 0; i < (int)track->num_samples; i++) { + fprintf(xmlout, " %u\n", i+1, track->sample[i].sample_size); + } + } + fprintf(xmlout, " \n"); + + fprintf(xmlout, " \n"); + // Structure not yet - Variant ChunkLargeOffset 'co64' + fprintf(xmlout, " %u\n", track->num_chunks); + if(notes) { + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } + if(sampletables) + for (i = 0; i < (int)track->num_chunks; i++) + fprintf(xmlout, " %u\n", i+1, track->chunk[i].offset); + fprintf(xmlout, " \n"); + + fprintf(xmlout, " \n"); +} + +/* ------------- */ + +int xml_out_frame(FILE* file, FILE* xmlout, mj2_sample_t *sample, unsigned int snum, opj_event_mgr_t *event_mgr) +{ + opj_dparameters_t parameters; /* decompression parameters */ + opj_image_t *img; + opj_cp_t *cp; + int i; + int numcomps; + unsigned char* frame_codestream; + opj_dinfo_t* dinfo = NULL; /* handle to a decompressor */ + opj_cio_t *cio = NULL; + opj_j2k_t *j2k; + + /* JPEG 2000 compressed image data */ + + /* get a decoder handle */ + dinfo = opj_create_decompress(CODEC_J2K); + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)dinfo, event_mgr, stderr); + + /* setup the decoder decoding parameters using the current image and user parameters */ + parameters.cp_limit_decoding = DECODE_ALL_BUT_PACKETS; + opj_setup_decoder(dinfo, ¶meters); + + frame_codestream = (unsigned char*) malloc (sample->sample_size-8); /* Skipping JP2C marker */ + if(frame_codestream == NULL) + return 1; + + fseek(file,sample->offset+8,SEEK_SET); + fread(frame_codestream,sample->sample_size-8,1, file); /* Assuming that jp and ftyp markers size do */ + + /* open a byte stream */ + cio = opj_cio_open((opj_common_ptr)dinfo, frame_codestream, sample->sample_size-8); + + /* Decode J2K to image: */ + img = opj_decode(dinfo, cio); + if (!img) { + fprintf(stderr, "ERROR -> j2k_to_image: failed to decode image!\n"); + opj_destroy_decompress(dinfo); + opj_cio_close(cio); + return 1; + } + + j2k = (opj_j2k_t*)dinfo->j2k_handle; + j2k_default_tcp = j2k->default_tcp; + cp = j2k->cp; + + numcomps = img->numcomps; + /* Alignments: " < To help maintain xml pretty-printing */ + fprintf(xmlout, " \n", snum+1); + fprintf(xmlout, " \n"); + /* There can be multiple codestreams; a particular image is entirely within a single codestream */ + /* TO DO: A frame can be represented by two I-guess-contigious codestreams if its interleaved. */ + fprintf(xmlout, " \n"); + /* "cp" stands for "coding parameter"; "tcp" is tile coding parameters, "tccp" is tile-component coding parameters */ + xml_out_frame_siz(xmlout, img, cp); /* reqd in main */ + xml_out_frame_cod(xmlout, j2k_default_tcp); /* reqd in main */ + xml_out_frame_coc(xmlout, j2k_default_tcp, numcomps); /* opt in main, at most 1 per component */ + xml_out_frame_qcd(xmlout, j2k_default_tcp); /* reqd in main */ + xml_out_frame_qcc(xmlout, j2k_default_tcp, numcomps); /* opt in main, at most 1 per component */ + xml_out_frame_rgn(xmlout, j2k_default_tcp, numcomps); /* opt, at most 1 per component */ + xml_out_frame_poc(xmlout, j2k_default_tcp); /* opt (but reqd in main or tile for any progression order changes) */ + /* Next four get j2k_default_tcp passed globally: */ +#ifdef SUPPRESS_FOR_NOW + xml_out_frame_ppm(xmlout, cp); /* opt (but either PPM or PPT [distributed in tile headers] or codestream packet header reqd) */ +#endif + xml_out_frame_tlm(xmlout); /* NO-OP. TLM NOT SAVED IN DATA STRUCTURE */ /* opt */ + xml_out_frame_plm(xmlout); /* NO-OP. PLM NOT SAVED IN DATA STRUCTURE */ /* opt in main; can be used in conjunction with PLT */ + xml_out_frame_crg(xmlout); /* NO-OP. CRG NOT SAVED IN DATA STRUCTURE */ /* opt in main; */ + xml_out_frame_com(xmlout, j2k_default_tcp); /* NO-OP. COM NOT SAVED IN DATA STRUCTURE */ /* opt in main; */ + + fprintf(xmlout, " \n"); + + /* TO DO: all the tile headers (sigh) */ + fprintf(xmlout, " \n", cp->tileno_size); /* size of the vector tileno */ + for(i = 0; i < cp->tileno_size; i++) { /* I think cp->tileno_size will be same number as (cp->tw * cp->th) or as global j2k_curtileno */ + // Standard seems to use zero-based # for tile-part. + fprintf(xmlout, " \n", i, cp->tileno[i]); /* ID number of the tiles present in the codestream */ + fprintf(xmlout, " \n"); + /* All markers in tile-part headers (between SOT and SOD) are optional, unless structure requires. */ + if(i == 0) { + xml_out_frame_cod(xmlout, &(cp->tcps[i])); /* No more than 1 per tile */ + xml_out_frame_coc(xmlout, &(cp->tcps[i]), numcomps); /* No more than 1 per component */ + xml_out_frame_qcd(xmlout, &(cp->tcps[i])); /* No more than 1 per tile */ + xml_out_frame_qcc(xmlout, &(cp->tcps[i]), numcomps); /* No more than 1 per component */ + xml_out_frame_rgn(xmlout, &(cp->tcps[i]), numcomps); /* No more than 1 per component */ + } + xml_out_frame_poc(xmlout, &(cp->tcps[i])); /* Reqd only if any progression order changes different from main POC */ +#ifdef SUPPRESS_FOR_NOW + xml_out_frame_ppt(xmlout, &(cp->tcps[i])); /* Either PPT [distributed in tile headers] or PPM or codestream packet header reqd. */ +#endif + xml_out_frame_plt(xmlout, &(cp->tcps[i])); /* NO-OP. PLT NOT SAVED IN DATA STRUCTURE */ /* Can be used in conjunction with main's PLM */ + xml_out_frame_com(xmlout, &(cp->tcps[i])); /* NO-OP. COM NOT SAVED IN DATA STRUCTURE */ + /* opj_tcp_t * cp->tcps; "tile coding parameters" */ + /* Maybe not: fprintf(xmlout, " <>%d, cp->matrice[i]; */ /* Fixed layer */ + fprintf(xmlout, " \n"); + if(notes) + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } + fprintf(xmlout, " \n"); /* size of the vector tileno */ + +#ifdef NOTYET + IMAGINE the cp object has data to support the following... but we could use an new different data structure instead + /* I'm unclear if the span of the original fread(frame_codestream...) included the following items if they're trailing. */ + /* ALSO TO DO, BUT DATA STRUCTURE DOESN'T HANDLE YET: boxes (anywhere in file except before the Filetype box): */ + xml_out_frame_jp2i(xmlout, &cp); /* IntellectualProperty 'jp2i' (no restrictions on location) */ + xml_out_frame_xml(xmlout, &cp); /* XML 'xml\040' (0x786d6c20). Can appear multiply */ + xml_out_frame_uuid(xmlout, &cp); /* UUID 'uuid' (top level only) */ + xml_out_frame_uinf(xmlout, &cp); /* UUIDInfo 'uinf', includes UUIDList 'ulst' and URL 'url\40' */ +#endif + + fprintf(xmlout, " \n"); + + /* Extra commentary: */ + if(notes) { + fprintf(xmlout, " \n"); + if (((img->numcomps == 3) && (img->comps[0].dx == img->comps[1].dx / 2) + && (img->comps[0].dx == img->comps[2].dx / 2 ) && (img->comps[0].dx == 1)) + || (img->numcomps == 1)) { + fprintf(xmlout, " \n"); + } + else if ((img->numcomps == 3) && + (img->comps[0].dx == 1) && (img->comps[1].dx == 1)&& + (img->comps[2].dx == 1)) {// If YUV 4:4:4 input --> to bmp + fprintf(xmlout, " \n"); + } + else { + fprintf(xmlout, " \n"); + } + } + + opj_destroy_decompress(dinfo); + opj_cio_close(cio); + free(frame_codestream); + + return 0; +} + +/* ------------- */ + +void int16_to_3packedchars(short int value, char* buf) +{ + /* This is to retrieve the 3-letter ASCII language code */ + /* Each char is packed into 5 bits, as difference from 0x60 */ + int i; + for (i = 2; i >= 0; i--) + { + buf[i] = (value & 0x001f) + 0x60; + value = (value >>5); + } + buf[3] = '\0'; +} + +/* ------------- */ + +void xml_out_frame_siz(FILE* xmlout, opj_image_t *img, opj_cp_t *cp) +{ + opj_image_comp_t *comp; + int i; + + fprintf(xmlout, " \n"); + // This is similar to j2k.c's j2k_dump_image. + // Not of interest: Lsiz, Rsiz + fprintf(xmlout, " %d\n", img->x1); + fprintf(xmlout, " %d\n", img->y1); + if(notes) + fprintf(xmlout, " \n"); + fprintf(xmlout, " %d\n", img->x0); + fprintf(xmlout, " %d\n", img->y0); + if(notes) + fprintf(xmlout, " \n"); + fprintf(xmlout, " %d\n", cp->tdx); + fprintf(xmlout, " %d\n", cp->tdy); + if(notes) + fprintf(xmlout, " \n"); + fprintf(xmlout, " %d\n", cp->tx0); + fprintf(xmlout, " %d\n", cp->ty0); + if(notes) + fprintf(xmlout, " \n"); + fprintf(xmlout, " %d\n", img->numcomps); + if(notes) { + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + //fprintf(xmlout," \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } + + for (i = 0; i < img->numcomps; i++) {/* image-components */ + comp = &(img->comps[i]); + fprintf(xmlout, " \n", i+1); + fprintf(xmlout, " \n"); + if(raw) + fprintf(xmlout," 0x%02x\n", (comp->sgnd << 7) & (comp->prec - 1)); + if(derived) { + fprintf(xmlout," %d\n", comp->sgnd); + fprintf(xmlout," %d\n", comp->prec); + } + fprintf(xmlout, " \n"); + fprintf(xmlout, " %d\n", comp->dx); + fprintf(xmlout, " %d\n", comp->dy); + fprintf(xmlout, " %d\n", comp->w); + fprintf(xmlout, " %d\n", comp->h); + /* Rest of these aren't calculated when SIZ is read: + fprintf(xmlout, " %d\n", comp->x0); + fprintf(xmlout, " %d\n", comp->y0); + if(notes) + fprintf(xmlout," \n"); + fprintf(xmlout, " %d\n", comp->bpp); + fprintf(xmlout, " %d\n", comp->resno_decoded); */ + // SUPPRESS: n/a to mj2_to_metadata. fprintf(xmlout," %dfactor); + /* factor = number of division by 2 of the out image compare to the original size of image */ + // TO DO comp->data: int *data; /* image-component data */ + + fprintf(xmlout, " \n"); + } + fprintf(xmlout, " \n"); +} + +/* ------------- */ + +void xml_out_frame_cod(FILE* xmlout, opj_tcp_t *tcp) +{ +/* Could be called with tcp = &j2k_default_tcp; +/* Or, for tile-part header, with &j2k_cp->tcps[j2k_curtileno] +/* Alignment for main:" < < < < To help maintain xml pretty-printing */ +/* Alignment for tile:" < < < To help maintain xml pretty-printing */ + opj_tccp_t *tccp; + int i; + char spaces[13] = " "; /* 12 spaces if tilepart*/ + char* s = spaces; + if(tcp == j2k_default_tcp) { + s++;s++; /* shorten s to 10 spaces if main */ + } + tccp = &(tcp->tccps[0]); + + fprintf(xmlout, "%s\n",s); /* Required in main header */ + /* Not retained or of interest: Lcod */ + fprintf(xmlout, "%s 0x%02x\n", s, tcp->csty); /* 1 byte */ + if(notes) { + fprintf(xmlout, "%s \n",s); + fprintf(xmlout, "%s \n",s); + fprintf(xmlout, "%s \n",s); + fprintf(xmlout, "%s \n",s); + fprintf(xmlout, "%s \n",s); + } + fprintf(xmlout, "%s \n",s); + fprintf(xmlout, "%s %d\n", s, tcp->prg); /* 1 byte, SGcod (A) */ + if(notes) { + fprintf(xmlout, "%s \n",s); + fprintf(xmlout, "%s \n",s); + fprintf(xmlout, "%s \n",s); + } + fprintf(xmlout, "%s %d\n", s, tcp->numlayers); /* 2 bytes, SGcod (B) */ + fprintf(xmlout, "%s %d\n", s, tcp->mct); /* 1 byte, SGcod (C). More or less boolean */ + if(notes) + fprintf(xmlout, "%s \n",s); + fprintf(xmlout, "%s \n",s); + /* This code will compile only if declaration of j2k_default_tcp is changed from static (to implicit extern) in j2k.c */ + fprintf(xmlout, "%s \n",s); + /* Internal data structure tccp defines separate defaults for each component, but they all get the same values */ + /* So we only have to report the first component's values here. */ + /* Compare j2k_read_cox(...) */ + fprintf(xmlout, "%s %d\n", s, tccp->numresolutions - 1); /* 1 byte, SPcox (D) */ + fprintf(xmlout, "%s %d\n", s, tccp->cblkw - 2); /* 1 byte, SPcox (E) */ + fprintf(xmlout, "%s %d\n", s, tccp->cblkh - 2); /* 1 byte, SPcox (F) */ + if(notes) { + fprintf(xmlout, "%s \n",s); + fprintf(xmlout, "%s \n", s); + } + fprintf(xmlout, "%s 0x%02x\n", s, tccp->cblksty); /* 1 byte, SPcox (G) */ + if(notes) { + fprintf(xmlout, "%s \n",s); + fprintf(xmlout, "%s \n",s); + fprintf(xmlout, "%s \n",s); + fprintf(xmlout, "%s \n",s); + fprintf(xmlout, "%s \n",s); + fprintf(xmlout, "%s \n",s); + fprintf(xmlout, "%s \n",s); + } + fprintf(xmlout, "%s %d\n", s, tccp->qmfbid); /* 1 byte, SPcox (H) */ + if(notes) + fprintf(xmlout, "%s \n",s); + if (tccp->csty & J2K_CP_CSTY_PRT) { + fprintf(xmlout, "%s \n",s); /* 1 byte, SPcox (I_i) */ + if(notes) + fprintf(xmlout, "%s \n",s); + for (i = 0; i < tccp->numresolutions; i++) { + fprintf(xmlout, "%s \n", s, i); + if(raw) + fprintf(xmlout,"%s 0x%02x\n", s, (tccp->prch[i] << 4) | tccp->prcw[i]); /* packed into 1 byte, SPcox (G) */ + if(derived) { + fprintf(xmlout,"%s %d\n", s, tccp->prcw[i]); + fprintf(xmlout,"%s %d\n", s, tccp->prch[i]); + } + fprintf(xmlout, "%s \n", s, i); + } + fprintf(xmlout, "%s \n",s); /* 1 byte, SPcox (I_i) */ + } + fprintf(xmlout, "%s \n",s); + fprintf(xmlout, "%s\n",s); +} + +/* ------------- */ + +void xml_out_frame_coc(FILE* xmlout, opj_tcp_t *tcp, int numcomps) /* Optional in main & tile-part headers */ +{ +/* Uses global j2k_default_tcp */ + opj_tccp_t *tccp, *firstcomp_tccp; + int i, compno; + char spaces[13] = " "; /* 12 spaces if tilepart*/ + char* s = spaces; + if(tcp == j2k_default_tcp) { + s++;s++; /* shorten s to 10 spaces if main */ + } + + firstcomp_tccp = &(tcp->tccps[0]); + /* Internal data structure tccp defines separate defaults for each component, set from main */ + /* default, then selectively overwritten. */ + /* Compare j2k_read_cox(...) */ + /* We don't really know which was the default, and which were not */ + /* Let's pretend that [0] is the default and all others are not */ + if(notes) { + fprintf(xmlout, "%s\n", s); + if(tcp == j2k_default_tcp) + fprintf(xmlout, "%s\n", s); + else + fprintf(xmlout, "%s\n", s); + } + for (compno = 1; compno < numcomps; compno++) /* spec says components are zero-based */ + { + tccp = &tcp->tccps[compno]; + if(same_component_style(firstcomp_tccp, tccp)) + continue; + +/* Alignments: " < < < < < To help maintain xml pretty-printing */ + fprintf(xmlout, "%s\n", s); /* Optional in main header, at most 1 per component */ + if(notes) + fprintf(xmlout, "%s \n", s); + /* Overrides the main COD for the specific component */ + /* Not retained or of interest: Lcod */ + fprintf(xmlout, "%s 0x%02x\n", s, tccp->csty); /* 1 byte */ + if(notes) { + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + } + fprintf(xmlout, "%s %d\n", s, compno); /* 1 or 2 bytes */ + /* Unfortunately compo isn't retained in j2k_read_coc: compno = cio_read(j2k_img->numcomps <= 256 ? 1 : 2); /* Ccoc */ + /*if(j2k_img_numcomps <=256) + component is 1 byte + else + compno is 2 byte */ + + /* This code will compile only if declaration of j2k_default_tcp is changed from static (to implicit extern) in j2k.c */ + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s %d\n", s, tccp->numresolutions - 1); /* 1 byte, SPcox (D) */ + fprintf(xmlout, "%s %d\n", s, tccp->cblkw - 2); /* 1 byte, SPcox (E) */ + fprintf(xmlout, "%s %d\n", s, tccp->cblkh - 2); /* 1 byte, SPcox (F) */ + if(notes) { + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + } + fprintf(xmlout, "%s 0x%02x\n", s, tccp->cblksty); /* 1 byte, SPcox (G) */ + if(notes) { + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + } + fprintf(xmlout, "%s %d\n", s, tccp->qmfbid); /* 1 byte, SPcox (H) */ + if(notes) + fprintf(xmlout, "%s \n", s); + if (tccp->csty & J2K_CP_CSTY_PRT) { + fprintf(xmlout, "%s \n", s); /* 1 byte, SPcox (I_i) */ + if(notes) + fprintf(xmlout, "%s \n", s); + for (i = 0; i < tccp->numresolutions-1; i++) { /* subtract 1 to get # of decomposition levels */ + fprintf(xmlout, "%s \n", s, i); + if(raw) + fprintf(xmlout,"%s 0x%02x\n", s, (tccp->prch[i] << 4) | tccp->prcw[i]); /* packed into 1 byte, SPcox (G) */ + if(derived) { + fprintf(xmlout,"%s %d\n", s, tccp->prcw[i]); + fprintf(xmlout,"%s %d\n", s, tccp->prch[i]); + } + fprintf(xmlout, "%s \n", s, i); + } + fprintf(xmlout, "%s \n", s); /* 1 byte, SPcox (I_i) */ + } + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s\n", s); + } +} + +/* ------------- */ + +BOOL same_component_style(opj_tccp_t *tccp1, opj_tccp_t *tccp2) +{ + int i; + + if(tccp1->numresolutions != tccp2->numresolutions) + return FALSE; + if(tccp1->cblkw != tccp2->cblkw) + return FALSE; + if(tccp1->cblkh != tccp2->cblkh) + return FALSE; + if(tccp1->cblksty != tccp2->cblksty) + return FALSE; + if(tccp1->csty != tccp2->csty) + return FALSE; + + if (tccp1->csty & J2K_CP_CSTY_PRT) { + for (i = 0; i < tccp1->numresolutions; i++) { + if(tccp1->prcw[i] != tccp2->prcw[i] || tccp1->prch[i] != tccp2->prch[i]) + return FALSE; + } + } + return TRUE; +} + +/* ------------- */ + +void xml_out_frame_qcd(FILE* xmlout, opj_tcp_t *tcp) +{ + /* This code will compile only if declaration of j2k_default_tcp is changed from static (to implicit extern) in j2k.c */ + opj_tccp_t *tccp; + int bandno, numbands; + char spaces[13] = " "; /* 12 spaces if tilepart*/ + char* s = spaces; + if(tcp == j2k_default_tcp) { + s++;s++; /* shorten s to 10 spaces if main */ + } + + /* Compare j2k_read_qcx */ + fprintf(xmlout, "%s\n", s); /* Required in main header, single occurrence */ + tccp = &(tcp->tccps[0]); + /* Not retained or of interest: Lqcd */ + fprintf(xmlout, "%s \n", s); /* 1 byte */ + if(notes) + fprintf(xmlout, "%s \n", s); + if(raw) + fprintf(xmlout, "%s 0x%02x\n", s, (tccp->numgbits) << 5 | tccp->qntsty); + if(derived) + fprintf(xmlout, "%s %d\n", s, tccp->qntsty); + if(notes) { + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + } + if(derived) + fprintf(xmlout, "%s %d\n", s, tccp->numgbits); + if(notes) + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + + /* Problem: numbands in some cases is calculated from len, which is not retained or available here at this time */ + /* So we'll just dump all internal values */ + /* We could calculate it, but I'm having trouble believing the length equations in the standard */ + + fprintf(xmlout, "%s \n", s); + switch(tccp->qntsty) { + case J2K_CCP_QNTSTY_NOQNT: /* no quantization */ + /* This is what standard says, but I don't believe it: len = 4 + (3*decomp); */ + numbands = J2K_MAXBANDS; /* should be: numbands = len - 1; */ + /* Better: IMAGINE numbands = tccp->stepsize_numbands; */ + /* Instead look for first zero exponent, quit there. Adequate? */ + fprintf(xmlout, "%s \n", s); + if(notes) { + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + } + for (bandno = 0; bandno < numbands; bandno++) { + if(tccp->stepsizes[bandno].expn == 0) + break; /* Remove when we have real numbands */ + fprintf(xmlout, "%s \n", s, bandno); + if(raw) + fprintf(xmlout,"%s 0x%02x\n", s, tccp->stepsizes[bandno].expn << 3); + if(derived) + fprintf(xmlout,"%s %d\n", s, tccp->stepsizes[bandno].expn); + fprintf(xmlout, "%s \n", s); + } + fprintf(xmlout, "%s \n", s); + break; + case J2K_CCP_QNTSTY_SIQNT: /* scalar quantization derived */ + /* This is what standard says. Should I believe it:: len = 5; + /* numbands = 1; */ + fprintf(xmlout, "%s \n", s); + if(notes) + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + if(notes) + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + } + + for (bandno = 1; bandno < J2K_MAXBANDS; bandno++) { + if(tccp->stepsizes[bandno].expn == 0) + break; + + fprintf(xmlout, "%s %d\n", s, bandno, tccp->stepsizes[bandno].expn); + } + + fprintf(xmlout, "%s \n", s); + break; + + default: /* J2K_CCP_QNTSTY_SEQNT */ /* scalar quantization expounded */ + /* This is what standard says, but should I believe it: len = 5 + 6*decomp; */ + numbands = J2K_MAXBANDS; /* should be: (len - 1) / 2;*/ + /* Better: IMAGINE numbands = tccp->stepsize_numbands; */ + fprintf(xmlout, "%s \n", s); + if(notes) { + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + } + for (bandno = 0; bandno < numbands; bandno++) { + if(tccp->stepsizes[bandno].expn == 0 && tccp->stepsizes[bandno].mant == 0) + break; /* Remove when we have real numbands */ + + fprintf(xmlout, "%s \n", s, bandno); + if(raw) + fprintf(xmlout,"%s 0x%02x\n", s, (tccp->stepsizes[bandno].expn << 11) | tccp->stepsizes[bandno].mant); + if(derived) { + fprintf(xmlout,"%s %d\n", s, tccp->stepsizes[bandno].expn); + fprintf(xmlout,"%s %d\n", s, tccp->stepsizes[bandno].mant); + } + fprintf(xmlout, "%s \n", s); + } + fprintf(xmlout, "%s \n", s); + break; + } /* switch */ + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s\n", s); + +/* Alignments: " < < < < < To help maintain xml pretty-printing */ +} + +/* ------------- */ + +void xml_out_frame_qcc(FILE* xmlout, opj_tcp_t *tcp, int numcomps) +{ +/* Uses global j2k_default_tcp */ + /* This code will compile only if declaration of j2k_default_tcp is changed from static (to implicit extern) in j2k.c */ + opj_tccp_t *tccp, *firstcomp_tccp; + int bandno, numbands; + int compno; + char spaces[13] = " "; /* 12 spaces if tilepart*/ + char* s = spaces; + if(tcp == j2k_default_tcp) { + s++;s++; /* shorten s to 10 spaces if main */ + } + + firstcomp_tccp = &(tcp->tccps[0]); + /* Internal data structure tccp defines separate defaults for each component, set from main */ + /* default, then selectively overwritten. */ + /* Compare j2k_read_qcx(...) */ + /* We don't really know which was the default, and which were not */ + /* Let's pretend that [0] is the default and all others are not */ + if(notes) { + fprintf(xmlout, "%s\n", s); + if(tcp == j2k_default_tcp) + fprintf(xmlout, "%s\n", s); + else + fprintf(xmlout, "%s\n", s); + } + for (compno = 1; compno < numcomps; compno++) /* spec says components are zero-based */ + { + tccp = &(tcp->tccps[compno]); + if(same_component_quantization(firstcomp_tccp, tccp)) + continue; + + /* Compare j2k_read_qcx */ + fprintf(xmlout, "%s\n", s, compno); /* Required in main header, single occurrence */ + tccp = &j2k_default_tcp->tccps[0]; + /* Not retained or perhaps of interest: Lqcd It maybe can be calculated. */ + fprintf(xmlout, "%s \n", s); /* 1 byte */ + if(notes) + fprintf(xmlout, "%s \n", s); + if(raw) + fprintf(xmlout, "%s 0x%02x\n", s, (tccp->numgbits) << 5 | tccp->qntsty); + if(derived) + fprintf(xmlout, "%s %d\n", s, tccp->qntsty); + if(notes) { + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + } + if(derived) + fprintf(xmlout, "%s %d\n", s, tccp->numgbits); + if(notes) + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + + /* Problem: numbands in some cases is calculated from len, which is not retained or available here at this time */ + /* So we'll just dump all internal values */ + fprintf(xmlout, "%s \n", s); + switch(tccp->qntsty) { + case J2K_CCP_QNTSTY_NOQNT: + numbands = J2K_MAXBANDS; /* should be: numbands = len - 1; */ + /* Better: IMAGINE numbands = tccp->stepsize_numbands; */ + + /* Instead look for first zero exponent, quit there. Adequate? */ + fprintf(xmlout, "%s \n", s); + if(notes) { + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + } + for (bandno = 0; bandno < numbands; bandno++) { + if(tccp->stepsizes[bandno].expn == 0) + break; /* Remove this once we have real numbands */ + fprintf(xmlout, "%s \n", s, bandno); + if(raw) + fprintf(xmlout,"%s 0x%02x\n", s, tccp->stepsizes[bandno].expn << 3); + if(derived) + fprintf(xmlout,"%s %d\n", s, tccp->stepsizes[bandno].expn); + fprintf(xmlout, "%s \n", s); + } + fprintf(xmlout, "%s \n", s); + break; + case J2K_CCP_QNTSTY_SIQNT: + /* numbands = 1; */ + fprintf(xmlout, "%s \n", s); + if(notes) + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + if(notes) + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + } + + for (bandno = 1; bandno < J2K_MAXBANDS; bandno++) { + if(tccp->stepsizes[bandno].expn == 0) + break; + + fprintf(xmlout, "%s %d\n", s, bandno, tccp->stepsizes[bandno].expn); + } + fprintf(xmlout, "%s \n", s); + break; + + default: /* J2K_CCP_QNTSTY_SEQNT */ + numbands = J2K_MAXBANDS; /* should be: (len - 1) / 2;*/ + /* Better: IMAGINE numbands = tccp->stepsize_numbands; */ + fprintf(xmlout, "%s \n", s); + if(notes) { + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s \n", s); + } + for (bandno = 0; bandno < numbands; bandno++) { + if(tccp->stepsizes[bandno].expn == 0 && tccp->stepsizes[bandno].mant == 0) + break; /* Remove this once we have real numbands count */ + fprintf(xmlout, "%s \n", s, bandno); + if(raw) + fprintf(xmlout,"%s 0x%02x\n", s, (tccp->stepsizes[bandno].expn << 11) | tccp->stepsizes[bandno].mant); + if(derived) { + fprintf(xmlout,"%s %d\n", s, tccp->stepsizes[bandno].expn); + fprintf(xmlout,"%s %d\n", s, tccp->stepsizes[bandno].mant); + } + fprintf(xmlout, "%s \n", s); + } + fprintf(xmlout, "%s \n", s); + break; + } /* switch */ + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s\n", s); + } +/* Alignments: " < < < < < To help maintain xml pretty-printing */ +} + +/* ------------- */ + +BOOL same_component_quantization(opj_tccp_t *tccp1, opj_tccp_t *tccp2) +{ + int bandno, numbands; + + if(tccp1->qntsty != tccp2->qntsty) + return FALSE; + if(tccp1->numgbits != tccp2->numgbits) + return FALSE; + + switch(tccp1->qntsty) { + case J2K_CCP_QNTSTY_NOQNT: + numbands = J2K_MAXBANDS; /* should be: numbands = len - 1; */ + /* Instead look for first zero exponent, quit there. Adequate? */ + for (bandno = 0; bandno < numbands; bandno++) { + if(tccp1->stepsizes[bandno].expn == 0) + break; + if(tccp1->stepsizes[bandno].expn != tccp2->stepsizes[bandno].expn) + return FALSE; + } + break; + case J2K_CCP_QNTSTY_SIQNT: + /* numbands = 1; */ + if(tccp1->stepsizes[0].expn != tccp2->stepsizes[0].expn || tccp1->stepsizes[0].mant != tccp2->stepsizes[0].mant) + return FALSE; + /* Don't need to check remainder, since they are calculated from [0] */ + break; + + default: /* J2K_CCP_QNTSTY_SEQNT */ + numbands = J2K_MAXBANDS; /* should be: (len - 1) / 2;*/ + /* This comparison may cause us problems with trailing junk values. */ + for (bandno = 0; bandno < numbands; bandno++) { + if(tccp1->stepsizes[bandno].expn != tccp2->stepsizes[bandno].expn || tccp1->stepsizes[bandno].mant != tccp2->stepsizes[bandno].mant); + return FALSE; + } + break; + } /* switch */ + return TRUE; +} + +/* ------------- */ + +void xml_out_frame_rgn(FILE* xmlout, opj_tcp_t *tcp, int numcomps) +{ + int compno, SPrgn; + /* MJ2 files can have regions of interest if hybridized with JPX Part II */ + char spaces[13] = " "; /* 12 spaces if tilepart*/ + char* s = spaces; + if(tcp == j2k_default_tcp) { + s++;s++; /* shorten s to 10 spaces if main */ + } + + for(compno = 0; compno < numcomps; compno++) { + SPrgn = tcp->tccps[compno].roishift; /* 1 byte; SPrgn */ + if(SPrgn == 0) + continue; /* Yet another kludge */ + + fprintf(xmlout, "%s\n", s); /* Optional in main header, at most 1 per component */ + if(notes) + fprintf(xmlout, "%s\n", s); + /* Not retained or of interest: Lrgd */ + fprintf(xmlout, "%s 0\n", s); /* 1 byte */ + if(notes) + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "%s %d\n", s, compno); /* 1 or 2 bytes */ + fprintf(xmlout, "%s %d\n", s, SPrgn); /* 1 byte */ + if(notes) + fprintf(xmlout, "%s \n", s); + fprintf(xmlout, "POC != 1) + return; /* Not present */ + + fprintf(xmlout, "%s\n", s); /* Optional in main header, at most 1 per component */ + /* j2k_read_poc seems to allow accumulation of default pocs from multiple POC segments, but does + the spec really allow that? */ + /* 2 bytes, not retained; Lpoc */ + /* I probably didn't get this dump precisely right. */ + for (i = 0; i < tcp->numpocs; i++) { + poc = &tcp->pocs[i]; + fprintf(xmlout, "%s \n", s, i+1); + fprintf(xmlout, "%S %d\n", s, poc->resno0); /* 1 byte, RSpoc_i */ + if(notes) + fprintf(xmlout,"%s \n", s); + fprintf(xmlout, "%s %d\n", s, poc->compno0);/* j2k_img->numcomps <= 256 ? 1 byte : 2 bytes; CSpoc_i */ + if(notes) + fprintf(xmlout,"%s \n", s); + fprintf(xmlout, "%s %d\n", s, poc->layno1); /* int_min(cio_read(2), tcp->numlayers); /* 2 bytes; LYEpoc_i */ + if(notes) + fprintf(xmlout,"%s \n", s); + fprintf(xmlout, "%s %d\n", s, poc->resno1); /*int_min(cio_read(1), tccp->numresolutions); /* REpoc_i */ + if(notes) + fprintf(xmlout,"%s \n", s); + fprintf(xmlout, "%s %d\n", s, poc->compno1); /* int_min(cio_read(j2k_img->numcomps <= 256 ? 1 : 2), j2k_img->numcomps); /* CEpoc_i */ + if(notes) + fprintf(xmlout,"%s \n", s); + fprintf(xmlout, "%s %d\n", s, poc->prg); /* 1 byte Ppoc_i */ + if(notes) { + fprintf(xmlout,"%s \n", s); + fprintf(xmlout,"%s \n", s); + fprintf(xmlout,"%s \n", s); + } + fprintf(xmlout, "%s \n", s); + } + fprintf(xmlout, "%sppm != 1) + return; /* Not present */ +/* Main header uses indent of 10 spaces */ + fprintf(xmlout, " \n"); /* Optional in main header, but if not, must be in PPT or codestream */ + /* 2 bytes Lppm not saved */ + if(notes) { + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } + + /* 1 byte, not retained ; Zppm is sequence # of this PPM header */ + /* 4 bytes, possibly overwritten multiple times in j2k_cp->ppm_previous: Nppm */ + /* Use j symbol for index instead of i, to make comparable with j2k_read_ppm */ + /* Not real clear whether to use ppm->store or ppm_len as upper bound */ + fprintf(xmlout, " \n"); + xml_out_dump_hex(xmlout, cp->ppm_data, cp->ppm_len); + /* Dump packet headers 1 byte at a time: lppm[i][j] */ + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); /* Optional in main header, but if not, must be in PPT or codestream */ +} + +/* ------------- */ + +void xml_out_frame_ppt(FILE *xmlout, opj_tcp_t *tcp) { /* For tile-part header, not main (which uses PPM instead). */ +/* Either the PPM or PPT is required if the packet headers are not distributed in the bit stream */ +/* Use of PPM and PPT are mutually exclusive. */ +/* Compare j2k_read_ppt() */ + int j; + + if(tcp->ppt != 1) + return; /* Not present */ + + /* Tile-part indents are 12 spaces */ + fprintf(xmlout, " \n"); /* Optional in main header, but if not, must be in PPT or codestream */ + /* 2 bytes Lppm not saved */ + if(notes) { + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } + + /* 1 byte, not retained ; Zppt is sequence # of this PPT header */ + /* 4 bytes, possibly overwritten multiple times in j2k_cp->ppt_previous: Nppt */ + /* Use j symbol for index instead of i, to make comparable with j2k_read_ppt */ + /* Not real clear whether to use ppt->store or ppt_len as upper bound */ + fprintf(xmlout, " \n"); + xml_out_dump_hex(xmlout, tcp->ppt_data, tcp->ppt_len); + /* Dump packet headers 1 byte at a time: lppt[i][j] */ + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); /* Optional in tile-part header, but if not, must be in PPM or codestream */ +} +#endif SUPPRESS_FOR_NOW + +/* ------------- */ + +void xml_out_frame_tlm(FILE* xmlout) { /* opt, main header only. May be multiple. */ +/* Compare j2k_read_tlm()... which doesn't retain anything! */ +/* Plan: Since this is only called from main header, not tilepart, use global j2k_default_tcp rather than parameter */ +/* Main header indents are 10 spaces */ +} + +/* ------------- */ + +void xml_out_frame_plm(FILE* xmlout) { /* opt, main header only; can be used in conjunction with tile-part's PLT */ +/* NO-OP. PLM NOT SAVED IN DATA STRUCTURE */ + /* Compare j2k_read_plm()... which doesn't retain anything! */ +/* Plan: Since this is only called from main header, not tilepart, use global j2k_default_tcp rather than parameter */ +/* Main header indents are 10 spaces */ +} + +/* ------------- */ + +void xml_out_frame_plt(FILE* xmlout, opj_tcp_t *tcp) { /* opt, tile-part headers only; can be used in conjunction with main header's PLM */ +/* NO-OP. PLT NOT SAVED IN DATA STRUCTURE */ + /* Compare j2k_read_plt()... which doesn't retain anything! */ +/* Tile-part header indents are 12 spaces */ +} + +/* ------------- */ + +void xml_out_frame_crg(FILE* xmlout) { /* NO-OP. CRG NOT SAVED IN DATA STRUCTURE */ /* opt, main header only; */ +/* Compare j2k_read_crg()... which doesn't retain anything! */ +/* Plan: Since this is only called from main header, not tilepart, use global j2k_default_tcp rather than parameter */ +#ifdef NOTYET + THIS PSEUDOCODE IMAGINES THESE EXIST: j2k_default_tcp->crg, j2k_default_tcp->crg_i, j2k_default_tcp->crg_xcrg*, j2k_default_tcp->crg_ycrg* + (POSSIBLY DON'T NEED crg_i, CAN GET NUMBER OR COMPONENTS FROM ELSEWHERE) + if(j2k_default_tcp->crg != 1 || j2k_default_tcp->crg_i == 0) + return; /* Not present */ + +/* Main header indents are 10 spaces */ + fprintf(xmlout, " \n", j2k_default_tcp->crg_i); + if(notes) { + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } + /* This isn't the most compact form of table, but is OK when number of components is small, as is likely. */ + for (i = 0; i < j2k_default_tcp->crg_i; i++) { + fprintf(xmlout, " \n", i+1); + fprintf(xmlout, " \n"); + if(raw) + fprintf(xmlout," %d\n", j2k_default_tcp->crg_xcrg[i]); + if(derived) { + /* Calculate n * 100%/65536; 4 digits after decimal point is sufficiently accurate */ + fprintf(xmlout," %.4f\n", ((double)j2k_default_tcp->crg_xcrg[i])/655.36); + /* We could do another calculation that include XRsiz[i]; maybe later. */ + } + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + if(raw) + fprintf(xmlout," %d\n", j2k_default_tcp->crg_ycrg[i]); + if(derived) { + fprintf(xmlout," %f\n", ((double)j2k_default_tcp->crg_ycrg[i])/655.36); + } + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } + + fprintf(xmlout, " \n"); + +#endif +} + +/* ------------- */ + +/* Regrettably from a metadata point of view, j2k_read_com() skips over any comments in main header or tile-part-header */ +void xml_out_frame_com(FILE* xmlout, opj_tcp_t *tcp) { /* NO-OP. COM NOT SAVED IN DATA STRUCTURE */ /* opt in main or tile-part headers; */ +/* Compare j2k_read_com()... which doesn't retain anything! */ +#ifdef NOTYET + char spaces[13] = " "; /* 12 spaces if tilepart*/ + char* s = spaces; + if(tcp == &j2k_default_tcp) { + s++;s++; /* shorten s to 10 spaces if main */ + } + THIS PSEUDOCODE IMAGINES THESE EXIST: tcp->com, tcp->com_len, tcp->com_data array + if(tcp->com != 1) + return; /* Not present */ + + fprintf(xmlout, "%s\n", s); /* Optional in main or tile-part header */ + xml_out_dump_hex_and_ascii(tcp->com_data, tcp->com_len, s); + fprintf(xmlout, "%s\n", s); +#endif +} + +void xml_out_dump_hex(FILE* xmlout, char *data, int data_len, char* s) { + /* s is a string of spaces for indent */ + int i; + + /* This is called when raw is true, or there is no appropriate derived form */ + fprintf(xmlout, "%s\n", s); + fprintf(xmlout, "%s ", s); /* Inadequate for pretty printing */ + for (i = 0; i < data_len; i++) { /* Dump packet headers */ + fprintf(xmlout, "%02x", data[i]); + } + fprintf(xmlout, "%s\n", s); +} + +/* Define this as an even number: */ +#define BYTES_PER_DUMP_LINE 40 +/* Current total width for Hex and ASCII is : 11 spaces lead + (3 * BPDL) + 2 spaces + BPDL */ +void xml_out_dump_hex_and_ascii(FILE* xmlout, char *data, int data_len, char* s) { + /* s is a string of spaces for indent */ + int i,j; + + if(raw) + xml_out_dump_hex(xmlout, data, data_len, s); + + if(derived) { + fprintf(xmlout, "%s\n", s); + for (i = 0; i < data_len; ) { + fprintf(xmlout,"%s ", s); /* Additional leading space added in loop */ + /* First column: hex */ + for (j = 0; j < BYTES_PER_DUMP_LINE; j++) /* Dump bytes */ + fprintf(xmlout," %02x", data[i+j]); + /* Space between columns... */ fprintf(xmlout, " "); + /* Second column: ASCII */ + for (j = 0; j < BYTES_PER_DUMP_LINE; j++, i++) { + if(isprint((int)data[i]) && i < data_len) + fprintf(xmlout,"%c", data[i]); + else + fprintf(xmlout," "); + } + /* If we also wanted to output UCS-2 Unicode as a third column, then entire document + must use fwprintf. Forget about it for now. As it stands, if data is UCS-2 format but still + the ASCII set, then we'll be able to read every other byte as ASCII in column 2. If + data is UTF-8 format but still ASCII, then we'll be able to read every byte as ASCII + in column 2. */ + } + fprintf(xmlout, "%s\n", s); + } +} + + +/* ------------- */ + +void xml_out_frame_jp2h(FILE* xmlout, opj_jp2_t *jp2_struct) { /* JP2 Header */ +/* Compare jp2_read_jp2h(opj_jp2_t * jp2_struct) */ + int i; + + fprintf(xmlout, " \n"); + +/* Compare jp2_read_ihdr(jp2_struct)) */ + fprintf(xmlout, " \n"); + fprintf(xmlout, " %d\n", jp2_struct->h); /* 4 bytes */ + fprintf(xmlout, " %d\n", jp2_struct->w); /* 4 bytes */ + if(notes) + fprintf(xmlout, " \n"); + fprintf(xmlout, " %d\n", jp2_struct->numcomps); /* 2 bytes */ + if(notes) + fprintf(xmlout, " \n"); /* 2 bytes */ + fprintf(xmlout, " \n"); /* 1 byte */ + if(jp2_struct->bpc == 255) { + fprintf(xmlout, " 0x%02x\n", jp2_struct->bpc); /* 1 byte */ + if(notes) + fprintf(xmlout, " \n"); + } else { /* Not 0xff */ + if(raw) { + fprintf(xmlout, " 0x%02x\n", jp2_struct->bpc); /* 1 byte */ + if(notes) + fprintf(xmlout," \n"); + } + if(derived) { + fprintf(xmlout, " %d\n", jp2_struct->bpc & 0x7f); + fprintf(xmlout, " %d\n", jp2_struct->bpc >> 7); + } + } + fprintf(xmlout, " \n"); + fprintf(xmlout, " %d\n", jp2_struct->C); /* 1 byte */ + if(notes) + fprintf(xmlout, " \n"); /* 2 bytes */ + fprintf(xmlout, " %d\n", jp2_struct->UnkC); /* 1 byte */ + if(notes) + fprintf(xmlout, " \n"); /* 1 byte */ + fprintf(xmlout, " %d\n", jp2_struct->IPR); /* 1 byte */ + if(notes) + fprintf(xmlout, " \n"); /* 2 bytes */ + fprintf(xmlout, " \n"); + + if (jp2_struct->bpc == 255) + { + fprintf(xmlout, " \n"); + if(notes) + fprintf(xmlout, " \n"); + /* Bits per pixel varies with components */ + /* Compare jp2_read_bpcc(jp2_struct) */ + for (i = 0; i < (int)jp2_struct->numcomps; i++) { + if(raw) + fprintf(xmlout," 0x%02x\n", jp2_struct->comps[i].bpcc); /* 1 byte */ + if(derived) { + fprintf(xmlout," %d\n", (jp2_struct->comps[i].bpcc & 0x7f)+1); + fprintf(xmlout," %d\n", jp2_struct->comps[i].bpcc >> 7); + } + } + fprintf(xmlout, " \n"); + } + + /* Compare jp2_read_colr(jp2_struct) */ + fprintf(xmlout, " \n"); + fprintf(xmlout, " %d\n", jp2_struct->meth); /* 1 byte */ + if(notes) { + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } + fprintf(xmlout, " %d\n", jp2_struct->precedence); /* 1 byte */ + if(notes) + fprintf(xmlout, " \n"); + fprintf(xmlout, " %d\n", jp2_struct->approx); /* 1 byte */ + if(notes) + fprintf(xmlout, " \n"); + + if (jp2_struct->meth == 1) { + fprintf(xmlout, " %d\n", jp2_struct->enumcs); /* 4 bytes */ + if(notes) { + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } + } + else + if(notes) + fprintf(xmlout, " \n"); + /* only 1 byte is read and nothing stored */ + fprintf(xmlout, " \n"); + + /* TO DO? No OpenJPEG support. + Palette 'pclr' + ComponentMapping 'cmap' + ChannelDefinition 'cdef' + Resolution 'res' + */ + fprintf(xmlout, " \n"); +} +/* ------------- */ + +#ifdef NOTYET +IMAGE these use cp structure, extended... but we could use a new data structure instead +void xml_out_frame_jp2i(FILE* xmlout, opj_cp_t *cp) { + /* IntellectualProperty 'jp2i' (no restrictions on location) */ + int i; + IMAGE cp->jp2i, cp->jp2i_count, cp->jp2i_data (array of chars), cp->cp2i_len (array of ints) + if(cp->jp2i != 1) + return; /* Not present */ + + for(i = 0; i < cp->jp2i_count; i++) + { + fprintf(xmlout, " \n"); + /* I think this can be anything, including binary, so do a dump */ + /* Is it better to indent or not indent this content? Indent is better for reading, but + worse for cut/paste. */ + xml_out_dump_hex_and_ascii(xmlout, cp->jp2i_data[i], cp->jp2i_len[i]); + fprintf(xmlout, " \n"); + } +} + +void xml_out_frame_xml(FILE* xmlout, opj_cp_t *cp) { + /* XML 'xml\040' (0x786d6c20). Can appear multiply, before or after jp2c codestreams */ + IMAGE cp->xml, cp->xml_count, cp->xml_data (array of chars) + MAYBE WE DON'T NEED cp->xml_len (array of ints) IF WE ASSUME xml_data IS NULL-TERMINATED. + ASSUME ASSUME EACH LINE IS ENDED BY \n. + int i; + if(cp->xml != 1) + return; /* Not present */ + + for(i = 0; i < cp->xml_count; i++) + { + fprintf(xmlout, " \n", i+1); + /* Is it better to indent or not indent this content? Indent is better for reading, but + worse for cut/paste. Being lazy, didn't indent here. */ + fprintf(xmlout,cp->xml_data[i]); /* May be multiple lines */ /* Could check if this is well-formed */ + fprintf(xmlout, " \n"); + } +} + +void xml_out_frame_uuid(FILE* xmlout, opj_cp_t *cp) { + /* UUID 'uuid' (top level only) */ + /* Part I 1.7.2 says: may appear multiply in JP2 file, anywhere except before File Type box */ + /* Part III 5.2.1 says: Private extensions shall be achieved through the 'uuid' type. */ + /* A UUID is a 16-byte value. There is a conventional string representation for it: + "0x12345678-9ABC-DEF0-1234-567890ABCDEF". Let's assume that is what is stored in uuid_value */ + + /* Part III 6.1 Any other MJ2 box type could be alternatively written as a 'uuid' box, with value given + as : 0xXXXXXXXX-0011-0010-8000-00AA00389B71, where the Xs are the boxtype in hex. However, + such a file is "not compliant; systems may choose to read [such] objects ... as equivalent to the box of + the same type, or not." Here, we choose not to. */ + int i; + IMAGE cp->uuid, cp->uuid_count, cp->uuid_value (array of uuids... let's say fixed-length strings) cp->uuid_data (array of char buffers), cp->uuid_len (array of ints) + if(cp->juuid != 1) + return; /* Not present */ + + for(i = 0; i < cp->uuid_count; i++) + { + fprintf(xmlout, " + fprintf(xmlout, " %s\n", cp->uuid_value[i]); + fprintf(xmlout, " \n"); + /* I think this can be anything, including binary, so do a dump */ + /* Is it better to indent or not indent this content? Indent is better for reading, but + worse for cut/paste. */ + xml_out_dump_hex_and_ascii(xmlout, cp->uuid_data[i], cp->uuid_len[i]); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } +} + +void xml_out_frame_uinf(FILE* xmlout, opj_cp_t *cp) { + /* UUIDInfo 'uinf', includes UUIDList 'ulst' and URL 'url\40' */ + /* Part I 1.7.3 says: may appear multiply in JP2 file, anywhere at the top level except before File Type box */ + /* So there may be multiple ulst's, and each can have multiple UUIDs listed (with a single URL) */ + /* This is not quite as vendor-specific as UUIDs, or at least is meant to be generally readable */ + /* Assume UUIDs stored in canonical string format */ + int i, j; + IMAGE cp->uinf, cp->uinf_count, cp->uinf_ulst_nu (array of ints) + cp->uinf_uuid (2 dimensional array of uuids... let's say fixed-length strings), + cp->uinf_url (array of char buffers) + + if(cp->uinf != 1) + return; /* Not present */ + + for(i = 0; i < cp->uuid_count; i++) + { + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n",cp->cp->uinf_ulst_nu[i]); + for(j = 0; j < cp->uinf_ulst_nu[i]; j++) + fprintf(xmlout, " %s\n", cp->uuif_uuid[i][j], j+1); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + /* Could add VERS and FLAG here */ + fprintf(xmlout, " \n"); + fprintf(xmlout, " %s",cp->uinf_url[i]); /* Probably single line, so indent works */ /* In theory, could check if this is well-formed, or good live link */ + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + fprintf(xmlout, " \n"); + } +} + +IMAGE these use cp structure, extended... but we could use a new data structure instead +void xml_out_frame_unknown_type(FILE* xmlout, opj_cp_t *cp) { + /* Part III 5.2.1 says "Type fields not defined here are reserved. Private extensions + shall be acieved through the 'uuid' type." [This implies an unknown + type would be an error, but then...] "Boxes not explicitly defined in this standard, + or otherwise unrecognized by a reader, may be ignored." + Also, it says "the following types are not and will not be used, or used only in + their existing sense, in future versions of this specification, to avoid conflict + with existing content using earlier pre-standard versions of this format: + clip, crgn, matt, kmat, pnot, ctab, load, imap; + track reference types tmcd, chap, sync,scpt, ssrc" + [But good luck figuring out the mapping.] + Part III Amend. 2 4.1 is stronger: "All these specifications [of this family, e.g., + JP2 Part I, ISO Base format (Part 12) leading to MP4, Quicktime, and possibly including + MJ2] require that readers ignore objects that are unrecognizable to them". + */ + int i; + IMAGE cp->unknown_type, cp->unknown_type_count, cp->unknown_type_boxtype (array of buf[5]s), cp->unknown_type_data (array of chars), cp->unknown_type_len (array of ints) + if(cp->unknown_type != 1) + return; /* Not present */ + + for(i = 0; i < cp->unknown_type_count; i++) + { + fprintf(xmlout, " \n", cp->unknown_type_boxtype[i]); + /* Can be anything, including binary, so do a dump */ + /* Is it better to indent or not indent this content? Indent is better for reading, but + worse for cut/paste. */ + xml_out_dump_hex_and_ascii(xmlout, cp->unknown_type_data[i], cp->unknown_type_len[i]); + fprintf(xmlout, " \n"); + } +} + +#endif diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/mj2/meta_out.h b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/meta_out.h new file mode 100644 index 0000000..293316d --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/meta_out.h @@ -0,0 +1,13 @@ +/* meta_out.h */ +/* Dump MJ2, JP2 metadata (partial so far) to xml file */ +/* Callable from mj2_to_metadata */ +/* Contributed to Open JPEG by Glenn Pearson, U.S. National Library of Medicine */ + +#define BOOL int +#define FALSE 0 +#define TRUE 1 + +void xml_write_init(BOOL n, BOOL t, BOOL r, BOOL d); + +int xml_write_struct(FILE *file, FILE *xmlout, opj_mj2_t * movie, unsigned int sampleframe, char* stringDTD, opj_event_mgr_t *event_mgr); + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2.c b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2.c new file mode 100644 index 0000000..01ee90c --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2.c @@ -0,0 +1,2911 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2003-2007, Francois-Olivier Devaux + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "../libopenjpeg/opj_includes.h" +#include "mj2.h" + +/** @defgroup JP2 JP2 - JPEG-2000 file format reader/writer */ +/*@{*/ + +/** @name Local static functions */ +/*@{*/ + +/** +Read box headers +@param cinfo Codec context info +@param cio Input stream +@param box +@return Returns true if successful, returns false otherwise +*/ +/*-- UNUSED +static bool jp2_read_boxhdr(opj_common_ptr cinfo, opj_cio_t *cio, opj_jp2_box_t *box); +--*/ +/* +* +* Read box headers +* +*/ + +int mj2_read_boxhdr(mj2_box_t * box, opj_cio_t *cio) +{ + box->init_pos = cio_tell(cio); + box->length = cio_read(cio, 4); + box->type = cio_read(cio, 4); + if (box->length == 1) { + if (cio_read(cio, 4) != 0) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Cannot handle box sizes higher than 2^32\n"); + return 1; + }; + box->length = cio_read(cio, 4); + if (box->length == 0) + box->length = cio_numbytesleft(cio) + 12; + } + else if (box->length == 0) { + box->length = cio_numbytesleft(cio) + 8; + } + return 0; +} + +/* +* +* Initialisation of a Standard Movie, given a simple movie structure defined by the user +* The movie will have one sample per chunk +* +* Arguments: opj_mj2_t * movie +* Several variables of "movie" must be defined in order to enable a correct execution of +* this function: +* - The number of tracks of each type (movie->num_vtk, movie->num_stk, movie->num_htk) +* - The memory for each must be allocated (movie->tk) +* - For each track: +* The track type (tk->track_type) +* The number of sample (tk->num_samples) +* The sample rate (tk->sample_rate) +* +*/ + +int mj2_init_stdmovie(opj_mj2_t * movie) +{ + int i; + unsigned int j; + time_t ltime; + + movie->brand = MJ2_MJ2; + movie->minversion = 0; + movie->num_cl = 2; + movie->cl = (unsigned int*) opj_malloc(movie->num_cl * sizeof(unsigned int)); + + movie->cl[0] = MJ2_MJ2; + movie->cl[1] = MJ2_MJ2S; + time(<ime); /* Time since 1/1/70 */ + movie->creation_time = (unsigned int) ltime + 2082844800; /* Seconds between 1/1/04 and 1/1/70 */ + movie->timescale = 1000; + + movie->rate = 1 << 16; /* Rate to play presentation (default = 0x00010000) */ + movie->volume = 1 << 8; /* Movie volume (default = 0x0100) */ + movie->trans_matrix[0] = 0x00010000; /* Transformation matrix for video */ + movie->trans_matrix[1] = 0; /* Unity is { 0x00010000,0,0,0,0x00010000,0,0,0,0x40000000 } */ + movie->trans_matrix[2] = 0; + movie->trans_matrix[3] = 0; + movie->trans_matrix[4] = 0x00010000; + movie->trans_matrix[5] = 0; + movie->trans_matrix[6] = 0; + movie->trans_matrix[7] = 0; + movie->trans_matrix[8] = 0x40000000; + movie->next_tk_id = 1; + + for (i = 0; i < movie->num_htk + movie->num_stk + movie->num_vtk; i++) { + mj2_tk_t *tk = &movie->tk[i]; + movie->next_tk_id++; + tk->jp2_struct.comps = NULL; + tk->jp2_struct.cl = NULL; + + if (tk->track_type == 0) { + if (tk->num_samples == 0) + return 1; + + tk->Dim[0] = 0; + tk->Dim[1] = 0; + + tk->timescale = 1000; /* Timescale = 1 ms */ + + tk->chunk[0].num_samples = 1; + tk->chunk[0].sample_descr_idx = 1; + + tk->same_sample_size = 0; + + tk->num_samplestochunk = 1; /* One sample per chunk */ + tk->sampletochunk = (mj2_sampletochunk_t*) opj_malloc(tk->num_samplestochunk * sizeof(mj2_sampletochunk_t)); + tk->sampletochunk[0].first_chunk = 1; + tk->sampletochunk[0].samples_per_chunk = 1; + tk->sampletochunk[0].sample_descr_idx = 1; + + if (tk->sample_rate == 0) { + opj_event_msg(tk->cinfo, EVT_ERROR, + "Error while initializing MJ2 movie: Sample rate of track %d must be different from zero\n", + tk->track_ID); + return 1; + } + + for (j = 0; j < tk->num_samples; j++) { + tk->sample[j].sample_delta = tk->timescale / tk->sample_rate; + } + + tk->num_tts = 1; + tk->tts = (mj2_tts_t*) opj_malloc(tk->num_tts * sizeof(mj2_tts_t)); + tk->tts[0].sample_count = tk->num_samples; + tk->tts[0].sample_delta = tk->timescale / tk->sample_rate; + + tk->horizresolution = 0x00480000; /* Horizontal resolution (typically 72) */ + tk->vertresolution = 0x00480000; /* Vertical resolution (typically 72) */ + tk->compressorname[0] = 0x0f4d6f74; /* Compressor Name[]: Motion JPEG2000 */ + tk->compressorname[1] = 0x696f6e20; + tk->compressorname[2] = 0x4a504547; + tk->compressorname[3] = 0x32303030; + tk->compressorname[4] = 0x00120000; + tk->compressorname[5] = 0; + tk->compressorname[6] = 0x00000042; + tk->compressorname[7] = 0x000000DC; + tk->num_url = 0; /* Number of URL */ + tk->num_urn = 0; /* Number of URN */ + tk->graphicsmode = 0; /* Graphicsmode */ + tk->opcolor[0] = 0; /* OpColor */ + tk->opcolor[1] = 0; /* OpColor */ + tk->opcolor[2] = 0; /* OpColor */ + tk->creation_time = movie->creation_time; /* Seconds between 1/1/04 and 1/1/70 */ + tk->language = 0; /* Language (undefined) */ + tk->layer = 0; + tk->volume = 1 << 8; /* Movie volume (default = 0x0100) */ + tk->trans_matrix[0] = 0x00010000; /* Transformation matrix for track */ + tk->trans_matrix[1] = 0; /* Unity is { 0x00010000,0,0,0,0x00010000,0,0,0,0x40000000 } */ + tk->trans_matrix[2] = 0; + tk->trans_matrix[3] = 0; + tk->trans_matrix[4] = 0x00010000; + tk->trans_matrix[5] = 0; + tk->trans_matrix[6] = 0; + tk->trans_matrix[7] = 0; + tk->trans_matrix[8] = 0x40000000; + tk->fieldcount = 1; + tk->fieldorder = 0; + tk->or_fieldcount = 1; + tk->or_fieldorder = 0; + tk->num_br = 2; + tk->br = (unsigned int*) opj_malloc(tk->num_br * sizeof(unsigned int)); + tk->br[0] = MJ2_JP2; + tk->br[1] = MJ2_J2P0; + tk->num_jp2x = 0; + tk->hsub = 2; /* 4:2:0 */ + tk->vsub = 2; /* 4:2:0 */ + tk->hoff = 0; + tk->voff = 0; + tk->visual_w = tk->w << 16; + tk->visual_h = tk->h << 16; + } + else { + tk->num_br = 0; + tk->jp2xdata = NULL; + } + } + return 0; +} + +/* +* Time To Sample box Decompact +* +*/ +void mj2_tts_decompact(mj2_tk_t * tk) +{ + int i, j; + tk->num_samples = 0; + for (i = 0; i < tk->num_tts; i++) { + tk->num_samples += tk->tts[i].sample_count; + } + + tk->sample = (mj2_sample_t*) opj_malloc(tk->num_samples * sizeof(mj2_sample_t)); + + for (i = 0; i < tk->num_tts; i++) { + for (j = 0; j < tk->tts[i].sample_count; j++) { + tk->sample[j].sample_delta = tk->tts[i].sample_delta; + } + } +} + +/* +* Sample To Chunk box Decompact +* +*/ +void mj2_stsc_decompact(mj2_tk_t * tk) +{ + int j, i; + unsigned int k; + int sampleno=0; + + if (tk->num_samplestochunk == 1) { + tk->num_chunks = + (unsigned int) ceil((double) tk->num_samples / + (double) tk->sampletochunk[0].samples_per_chunk); + tk->chunk = (mj2_chunk_t*) opj_malloc(tk->num_chunks * sizeof(mj2_chunk_t)); + for (k = 0; k < tk->num_chunks; k++) { + tk->chunk[k].num_samples = tk->sampletochunk[0].samples_per_chunk; + } + + } else { + tk->chunk = (mj2_chunk_t*) opj_malloc(tk->num_samples * sizeof(mj2_chunk_t)); + tk->num_chunks = 0; + for (i = 0; i < tk->num_samplestochunk -1 ; i++) { + for (j = tk->sampletochunk[i].first_chunk - 1; + j < tk->sampletochunk[i + 1].first_chunk - 1; j++) { + tk->chunk[j].num_samples = tk->sampletochunk[i].samples_per_chunk; + tk->num_chunks++; + sampleno += tk->chunk[j].num_samples; + } + } + tk->num_chunks += (int)(tk->num_samples - sampleno) / tk->sampletochunk[tk->num_samplestochunk - 1].samples_per_chunk; + for (k = tk->sampletochunk[tk->num_samplestochunk - 1].first_chunk - 1; + k < tk->num_chunks; k++) { + tk->chunk[k].num_samples = + tk->sampletochunk[tk->num_samplestochunk - 1].samples_per_chunk; + } + tk->chunk = (mj2_chunk_t*) + opj_realloc(tk->chunk, tk->num_chunks * sizeof(mj2_chunk_t)); + } + +} + + +/* +* Chunk offset box Decompact +* +*/ +void mj2_stco_decompact(mj2_tk_t * tk) +{ + int j; + unsigned int i; + int k = 0; + int intra_chunk_offset; + + for (i = 0; i < tk->num_chunks; i++) { + intra_chunk_offset = 0; + for (j = 0; j < tk->chunk[i].num_samples; j++) { + tk->sample[k].offset = intra_chunk_offset + tk->chunk[i].offset; + intra_chunk_offset += tk->sample[k].sample_size; + k++; + } + } +} + +/* +* Write the JP box +* +* JP Signature box +* +*/ +void mj2_write_jp(opj_cio_t *cio) +{ + mj2_box_t box; + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + + cio_write(cio, MJ2_JP, 4); /* JP */ + cio_write(cio, 0x0d0a870a, 4); /* 0x0d0a870a required in a JP box */ + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the JP box +* +* JPEG 2000 signature +* +*/ +int mj2_read_jp(opj_cio_t *cio) +{ + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); + if (MJ2_JP != box.type) { /* Check Marker */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected JP Marker\n"); + return 1; + } + if (0x0d0a870a != cio_read(cio, 4)) { /* read the 0x0d0a870a required in a JP box */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with JP Marker\n"); + return 1; + } + if (cio_tell(cio) - box.init_pos != box.length) { /* Check box length */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with JP Box size \n"); + return 1; + } + return 0; + +} + +/* +* Write the FTYP box +* +* File type box +* +*/ +void mj2_write_ftyp(opj_mj2_t * movie, opj_cio_t *cio) +{ + int i; + mj2_box_t box; + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + + cio_write(cio, MJ2_FTYP, 4); /* FTYP */ + cio_write(cio, movie->brand, 4); /* BR */ + cio_write(cio, movie->minversion, 4); /* MinV */ + + for (i = 0; i < movie->num_cl; i++) + cio_write(cio, movie->cl[i], 4); /* CL */ + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* Length */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the FTYP box +* +* File type box +* +*/ +int mj2_read_ftyp(opj_mj2_t * movie, opj_cio_t *cio) +{ + int i; + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); /* Box Size */ + if (MJ2_FTYP != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected FTYP Marker\n"); + return 1; + } + + movie->brand = cio_read(cio, 4); /* BR */ + movie->minversion = cio_read(cio, 4); /* MinV */ + movie->num_cl = (box.length - 16) / 4; + movie->cl = (unsigned int*) opj_malloc(movie->num_cl * sizeof(unsigned int)); + + for (i = movie->num_cl - 1; i > -1; i--) + movie->cl[i] = cio_read(cio, 4); /* CLi */ + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with FTYP Box\n"); + return 1; + } + return 0; +} + + +/* +* Write the STCO box +* +* Chunk Offset Box +* +*/ +void mj2_write_stco(mj2_tk_t * tk, opj_cio_t *cio) +{ + mj2_box_t box; + unsigned int i; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + cio_write(cio, MJ2_STCO, 4); /* STCO */ + + cio_write(cio, 0, 4); /* Version = 0, flags = 0 */ + + cio_write(cio, tk->num_chunks, 4); /* Entry Count */ + + for (i = 0; i < tk->num_chunks; i++) { + cio_write(cio, tk->chunk[i].offset, 4); /* Entry offset */ + } + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the STCO box +* +* Chunk Offset Box +* +*/ +int mj2_read_stco(mj2_tk_t * tk, opj_cio_t *cio) +{ + unsigned int i; + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); /* Box Size */ + if (MJ2_STCO != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected STCO Marker\n"); + return 1; + } + + if (0 != cio_read(cio, 1)) { /* Version = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Only Version 0 handled in STCO box\n"); + return 1; + } + + if (0 != cio_read(cio, 3)) { /* Flags = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with flag in STCO box. Expected flag 0\n"); + return 1; + } + + + if (cio_read(cio, 4) != tk->num_chunks) { + opj_event_msg(cio->cinfo, EVT_ERROR, + "Error in STCO box: expecting same amount of entry-count as chunks \n"); + } else { + for (i = 0; i < tk->num_chunks; i++) { + tk->chunk[i].offset = cio_read(cio, 4); /* Entry offset */ + } + } + + mj2_stco_decompact(tk); + + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with STCO Box size\n"); + return 1; + } + return 0; +} + +/* +* Write the STSZ box +* +* Sample size box +* +*/ +void mj2_write_stsz(mj2_tk_t * tk, opj_cio_t *cio) +{ + mj2_box_t box; + unsigned int i; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + cio_write(cio, MJ2_STSZ, 4); /* STSZ */ + + cio_write(cio, 0, 4); /* Version = 0, flags = 0 */ + + if (tk->same_sample_size == 1) { /* If they all have the same size */ + cio_write(cio, tk->sample[0].sample_size, 4); /* Size */ + + cio_write(cio, 1, 4); /* Entry count = 1 */ + } + + else { + cio_write(cio, 0, 4); /* Sample Size = 0 becase they all have different sizes */ + + cio_write(cio, tk->num_samples, 4); /* Sample Count */ + + for (i = 0; i < tk->num_samples; i++) { + cio_write(cio, tk->sample[i].sample_size, 4); + } + } + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the STSZ box +* +* Sample size box +* +*/ +int mj2_read_stsz(mj2_tk_t * tk, opj_cio_t *cio) +{ + int sample_size; + unsigned int i; + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); /* Box Size */ + if (MJ2_STSZ != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected STSZ Marker\n"); + return 1; + } + + + if (0 != cio_read(cio, 1)) { /* Version = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Only Version 0 handled in STSZ box\n"); + return 1; + } + + if (0 != cio_read(cio, 3)) { /* Flags = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with flag in STSZ box. Expected flag 0\n"); + return 1; + } + + sample_size = cio_read(cio, 4); + + if (sample_size != 0) { /* Samples do have the same size */ + tk->same_sample_size = 1; + for (i = 0; i < tk->num_samples; i++) { + tk->sample[i].sample_size = sample_size; + } + cio_skip(cio,4); /* Sample count = 1 */ + } else { + tk->same_sample_size = 0; + if (tk->num_samples != cio_read(cio, 4)) { /* Sample count */ + opj_event_msg(cio->cinfo, EVT_ERROR, + "Error in STSZ box. Expected that sample-count is number of samples in track\n"); + return 1; + } + for (i = 0; i < tk->num_samples; i++) { + tk->sample[i].sample_size = cio_read(cio, 4); /* Sample Size */ + } + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with STSZ Box size\n"); + return 1; + } + } + return 0; + +} + +/* +* Write the STSC box +* +* Sample to Chunk +* +*/ +void mj2_write_stsc(mj2_tk_t * tk, opj_cio_t *cio) +{ + int i; + mj2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + cio_write(cio, MJ2_STSC, 4); /* STSC */ + + cio_write(cio, 0, 4); /* Version = 0, flags = 0 */ + + cio_write(cio, tk->num_samplestochunk, 4); /* Entry Count */ + + for (i = 0; i < tk->num_samplestochunk; i++) { + cio_write(cio, tk->sampletochunk[i].first_chunk, 4); /* First Chunk */ + cio_write(cio, tk->sampletochunk[i].samples_per_chunk, 4); /* Samples per chunk */ + cio_write(cio, tk->sampletochunk[i].sample_descr_idx, 4); /* Samples description index */ + } + + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the STSC box +* +* Sample to Chunk +* +*/ +int mj2_read_stsc(mj2_tk_t * tk, opj_cio_t *cio) +{ + int i; + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); /* Box Size */ + if (MJ2_STSC != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected STSC Marker\n"); + return 1; + } + + + if (0 != cio_read(cio, 1)) { /* Version = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Only Version 0 handled in STSC box\n"); + return 1; + } + + if (0 != cio_read(cio, 3)) { /* Flags = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with flag in STSC box. Expected flag 0\n"); + return 1; + } + + tk->num_samplestochunk = cio_read(cio, 4); + + tk->sampletochunk = (mj2_sampletochunk_t*) opj_malloc(tk->num_samplestochunk * sizeof(mj2_sampletochunk_t)); + + for (i = 0; i < tk->num_samplestochunk; i++) { + tk->sampletochunk[i].first_chunk = cio_read(cio, 4); + tk->sampletochunk[i].samples_per_chunk = cio_read(cio, 4); + tk->sampletochunk[i].sample_descr_idx = cio_read(cio, 4); + } + + mj2_stsc_decompact(tk); /* decompact sample to chunk box */ + + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with STSC Box size\n"); + return 1; + } + return 0; +} + +/* +* Write the STTS box +* +* Time to Sample Box +* +*/ +void mj2_write_stts(mj2_tk_t * tk, opj_cio_t *cio) +{ + + int i; + mj2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + cio_write(cio, MJ2_STTS, 4); /* STTS */ + + cio_write(cio, 0, 4); /* Version = 0, flags = 0 */ + + cio_write(cio, tk->num_tts, 4); /* entry_count */ + for (i = 0; i < tk->num_tts; i++) { + cio_write(cio, tk->tts[i].sample_count, 4); /* Sample-count */ + cio_write(cio, tk->tts[i].sample_delta, 4); /* Sample-Delta */ + } + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the STTS box +* +* +* +*/ +int mj2_read_stts(mj2_tk_t * tk, opj_cio_t *cio) +{ + int i; + + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); + if (MJ2_STTS != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected STTS Marker\n"); + return 1; + } + + + if (0 != cio_read(cio, 1)) { /* Version = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Only Version 0 handled in STTS box\n"); + return 1; + } + + if (0 != cio_read(cio, 3)) { /* Flags = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with flag in STTS box. Expected flag 0\n"); + return 1; + } + + tk->num_tts = cio_read(cio, 4); + + tk->tts = (mj2_tts_t*) opj_malloc(tk->num_tts * sizeof(mj2_tts_t)); + + for (i = 0; i < tk->num_tts; i++) { + tk->tts[i].sample_count = cio_read(cio, 4); + tk->tts[i].sample_delta = cio_read(cio, 4); + } + + mj2_tts_decompact(tk); + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with STTS Box size\n"); + return 1; + } + return 0; +} + +/* +* Write the FIEL box +* +* Field coding Box +* +*/ +void mj2_write_fiel(mj2_tk_t * tk, opj_cio_t *cio) +{ + + mj2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + cio_write(cio, MJ2_FIEL, 4); /* STTS */ + + cio_write(cio, tk->fieldcount, 1); /* Field count */ + cio_write(cio, tk->fieldorder, 1); /* Field order */ + + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the FIEL box +* +* Field coding Box +* +*/ +int mj2_read_fiel(mj2_tk_t * tk, opj_cio_t *cio) +{ + + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); + if (MJ2_FIEL != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected FIEL Marker\n"); + return 1; + } + + + tk->fieldcount = cio_read(cio, 1); + tk->fieldorder = cio_read(cio, 1); + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with FIEL Box size\n"); + return 1; + } + return 0; +} + +/* +* Write the ORFO box +* +* Original Format Box +* +*/ +void mj2_write_orfo(mj2_tk_t * tk, opj_cio_t *cio) +{ + mj2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + cio_write(cio, MJ2_ORFO, 4); + + cio_write(cio, tk->or_fieldcount, 1); /* Original Field count */ + cio_write(cio, tk->or_fieldorder, 1); /* Original Field order */ + + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the ORFO box +* +* Original Format Box +* +*/ +int mj2_read_orfo(mj2_tk_t * tk, opj_cio_t *cio) +{ + + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); + if (MJ2_ORFO != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected ORFO Marker\n"); + return 1; + } + + + tk->or_fieldcount = cio_read(cio, 1); + tk->or_fieldorder = cio_read(cio, 1); + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with ORFO Box size\n"); + return 1; + } + return 0; +} + +/* +* Write the JP2P box +* +* MJP2 Profile Box +* +*/ +void mj2_write_jp2p(mj2_tk_t * tk, opj_cio_t *cio) +{ + + int i; + mj2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + cio_write(cio, MJ2_JP2P, 4); + + cio_write(cio, 0, 4); /* Version 0, flags =0 */ + + for (i = 0; i < tk->num_br; i++) { + cio_write(cio, tk->br[i], 4); + } + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the JP2P box +* +* MJP2 Profile Box +* +*/ +int mj2_read_jp2p(mj2_tk_t * tk, opj_cio_t *cio) +{ + int i; + + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); + if (MJ2_JP2P != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected JP2P Marker\n"); + return 1; + } + + if (0 != cio_read(cio, 1)) { /* Version = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Only Version 0 handled in JP2P box\n"); + return 1; + } + + if (0 != cio_read(cio, 3)) { /* Flags = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with flag in JP2P box. Expected flag 0\n"); + return 1; + } + + + tk->num_br = (box.length - 12) / 4; + tk->br = (unsigned int*) opj_malloc(tk->num_br * sizeof(unsigned int)); + + for (i = 0; i < tk->num_br; i++) { + tk->br[i] = cio_read(cio, 4); + } + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with JP2P Box size\n"); + return 1; + } + return 0; +} + +/* +* Write the JP2X box +* +* MJP2 Prefix Box +* +*/ +void mj2_write_jp2x(mj2_tk_t * tk, opj_cio_t *cio) +{ + + int i; + mj2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + cio_write(cio, MJ2_JP2X, 4); + + for (i = 0; i < tk->num_jp2x; i++) { + cio_write(cio, tk->jp2xdata[i], 1); + } + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the JP2X box +* +* MJP2 Prefix Box +* +*/ +int mj2_read_jp2x(mj2_tk_t * tk, opj_cio_t *cio) +{ + unsigned int i; + + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); + if (MJ2_JP2X != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected JP2X Marker\n"); + return 1; + } + + + tk->num_jp2x = (box.length - 8); + tk->jp2xdata = (unsigned char*) opj_malloc(tk->num_jp2x * sizeof(unsigned char)); + + for (i = 0; i < tk->num_jp2x; i++) { + tk->jp2xdata[i] = cio_read(cio, 1); + } + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with JP2X Box size\n"); + return 1; + } + return 0; +} + +/* +* Write the JSUB box +* +* MJP2 Subsampling Box +* +*/ +void mj2_write_jsub(mj2_tk_t * tk, opj_cio_t *cio) +{ + + mj2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + cio_write(cio, MJ2_JSUB, 4); + + cio_write(cio, tk->hsub, 1); + cio_write(cio, tk->vsub, 1); + cio_write(cio, tk->hoff, 1); + cio_write(cio, tk->voff, 1); + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the JSUB box +* +* MJP2 Subsampling Box +* +*/ +int mj2_read_jsub(mj2_tk_t * tk, opj_cio_t *cio) +{ + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); + if (MJ2_JSUB != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected JSUB Marker\n"); + return 1; + } + + tk->hsub = cio_read(cio, 1); + tk->vsub = cio_read(cio, 1); + tk->hoff = cio_read(cio, 1);; + tk->voff = cio_read(cio, 1); + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with JSUB Box size\n"); + return 1; + } + return 0; +} + +/* +* Write the SMJ2 box +* +* Visual Sample Entry Description +* +*/ +void mj2_write_smj2(mj2_tk_t * tk, opj_cio_t *cio) +{ + mj2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + cio_write(cio, MJ2_MJ2, 4); /* MJ2 */ + + cio_write(cio, 0, 4); /* Version = 0, flags = 0 */ + + cio_write(cio, 1, 4); + + cio_write(cio, 0, 2); /* Pre-defined */ + + cio_write(cio, 0, 2); /* Reserved */ + + cio_write(cio, 0, 4); /* Pre-defined */ + cio_write(cio, 0, 4); /* Pre-defined */ + cio_write(cio, 0, 4); /* Pre-defined */ + + cio_write(cio, tk->w, 2); /* Width */ + cio_write(cio, tk->h, 2); /* Height */ + + cio_write(cio, tk->horizresolution, 4); /* Horizontal resolution */ + cio_write(cio, tk->vertresolution, 4); /* Vertical resolution */ + + cio_write(cio, 0, 4); /* Reserved */ + + cio_write(cio, 1, 2); /* Pre-defined = 1 */ + + cio_write(cio, tk->compressorname[0], 4); /* Compressor Name */ + cio_write(cio, tk->compressorname[1], 4); + cio_write(cio, tk->compressorname[2], 4); + cio_write(cio, tk->compressorname[3], 4); + cio_write(cio, tk->compressorname[4], 4); + cio_write(cio, tk->compressorname[5], 4); + cio_write(cio, tk->compressorname[6], 4); + cio_write(cio, tk->compressorname[7], 4); + + cio_write(cio, tk->depth, 2); /* Depth */ + + cio_write(cio, 0xffff, 2); /* Pre-defined = -1 */ + + jp2_write_jp2h(&tk->jp2_struct, cio); + + mj2_write_fiel(tk, cio); + + if (tk->num_br != 0) + mj2_write_jp2p(tk, cio); + if (tk->num_jp2x != 0) + mj2_write_jp2x(tk, cio); + + mj2_write_jsub(tk, cio); + mj2_write_orfo(tk, cio); + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the SMJ2 box +* +* Visual Sample Entry Description +* +*/ +int mj2_read_smj2(opj_image_t * img, mj2_tk_t * tk, opj_cio_t *cio) +{ + mj2_box_t box; + mj2_box_t box2; + int i; + opj_jp2_color_t color; + + mj2_read_boxhdr(&box, cio); + + if (MJ2_MJ2 != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error in SMJ2 box: Expected MJ2 Marker\n"); + return 1; + } + + if (0 != cio_read(cio, 1)) { /* Version = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Only Version 0 handled in MJP2 box\n"); + return 1; + } + + if (0 != cio_read(cio, 3)) { /* Flags = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with flag in MJP2 box. Expected flag 0\n"); + return 1; + } + + cio_skip(cio,4); + + cio_skip(cio,2); /* Pre-defined */ + + cio_skip(cio,2); /* Reserved */ + + cio_skip(cio,4); /* Pre-defined */ + cio_skip(cio,4); /* Pre-defined */ + cio_skip(cio,4); /* Pre-defined */ + + tk->w = cio_read(cio, 2); /* Width */ + tk->h = cio_read(cio, 2); /* Height */ + + tk->horizresolution = cio_read(cio, 4); /* Horizontal resolution */ + tk->vertresolution = cio_read(cio, 4); /* Vertical resolution */ + + cio_skip(cio,4); /* Reserved */ + + cio_skip(cio,2); /* Pre-defined = 1 */ + + tk->compressorname[0] = cio_read(cio, 4); /* Compressor Name */ + tk->compressorname[1] = cio_read(cio, 4); + tk->compressorname[2] = cio_read(cio, 4); + tk->compressorname[3] = cio_read(cio, 4); + tk->compressorname[4] = cio_read(cio, 4); + tk->compressorname[5] = cio_read(cio, 4); + tk->compressorname[6] = cio_read(cio, 4); + tk->compressorname[7] = cio_read(cio, 4); + + tk->depth = cio_read(cio, 2); /* Depth */ + + /* Init std value */ + tk->num_jp2x = 0; + tk->fieldcount = 1; + tk->fieldorder = 0; + tk->or_fieldcount = 1; + tk->or_fieldorder = 0; + + cio_skip(cio,2); /* Pre-defined = -1 */ + memset(&color, 0, sizeof(opj_jp2_color_t)); + + if (!jp2_read_jp2h(&tk->jp2_struct, cio, &color)) { + opj_event_msg(tk->cinfo, EVT_ERROR, "Error reading JP2H Box\n"); + return 1; + } + + tk->jp2_struct.comps = (opj_jp2_comps_t*) opj_malloc(tk->jp2_struct.numcomps * sizeof(opj_jp2_comps_t)); + tk->jp2_struct.cl = (unsigned int*) opj_malloc(sizeof(unsigned int)); + + tk->num_br = 0; + tk->num_jp2x = 0; + + for (i = 0; cio_tell(cio) - box.init_pos < box.length; i++) { + mj2_read_boxhdr(&box2, cio); + cio_seek(cio, box2.init_pos); + switch (box2.type) { + case MJ2_FIEL: + if (mj2_read_fiel(tk, cio)) + return 1; + break; + + case MJ2_JP2P: + if (mj2_read_jp2p(tk, cio)) + return 1; + break; + + case MJ2_JP2X: + if (mj2_read_jp2x(tk, cio)) + return 1; + break; + + case MJ2_JSUB: + if (mj2_read_jsub(tk, cio)) + return 1; + break; + + case MJ2_ORFO: + if (mj2_read_orfo(tk, cio)) + return 1; + break; + + default: + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with MJP2 Box size\n"); + return 1; + break; + + } + } + return 0; +} + + +/* +* Write the STSD box +* +* Sample Description +* +*/ +void mj2_write_stsd(mj2_tk_t * tk, opj_cio_t *cio) +{ + mj2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + cio_write(cio, MJ2_STSD, 4); /* STSD */ + + cio_write(cio, 0, 4); /* Version = 0, flags = 0 */ + + cio_write(cio, 1, 4); /* entry_count = 1 (considering same JP2 headerboxes) */ + + if (tk->track_type == 0) { + mj2_write_smj2(tk, cio); + } else if (tk->track_type == 1) { + // Not implemented + } + if (tk->track_type == 2) { + // Not implemented + } + + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the STSD box +* +* Sample Description +* +*/ +int mj2_read_stsd(mj2_tk_t * tk, opj_image_t * img, opj_cio_t *cio) +{ + int i; + int entry_count, len_2skip; + + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); + + if (MJ2_STSD != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected STSD Marker\n"); + return 1; + } + + if (0 != cio_read(cio, 1)) { /* Version = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Only Version 0 handled in STSD box\n"); + return 1; + } + + if (0 != cio_read(cio, 3)) { /* Flags = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with flag in STSD box. Expected flag 0\n"); + return 1; + } + + entry_count = cio_read(cio, 4); + + if (tk->track_type == 0) { + for (i = 0; i < entry_count; i++) { + if (mj2_read_smj2(img, tk, cio)) + return 1; + } + } else if (tk->track_type == 1) { + len_2skip = cio_read(cio, 4); // Not implemented -> skipping box + cio_skip(cio,len_2skip - 4); + } else if (tk->track_type == 2) { + len_2skip = cio_read(cio, 4); // Not implemented -> skipping box + cio_skip(cio,len_2skip - 4); + } + + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with STSD Box size\n"); + return 1; + } + return 0; +} + +/* +* Write the STBL box +* +* Sample table box box +* +*/ +void mj2_write_stbl(mj2_tk_t * tk, opj_cio_t *cio) +{ + mj2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + cio_write(cio, MJ2_STBL, 4); /* STBL */ + + mj2_write_stsd(tk, cio); + mj2_write_stts(tk, cio); + mj2_write_stsc(tk, cio); + mj2_write_stsz(tk, cio); + mj2_write_stco(tk, cio); + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the STBL box +* +* Sample table box box +* +*/ +int mj2_read_stbl(mj2_tk_t * tk, opj_image_t * img, opj_cio_t *cio) +{ + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); + if (MJ2_STBL != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected STBL Marker\n"); + return 1; + } + + if (mj2_read_stsd(tk, img, cio)) + return 1; + if (mj2_read_stts(tk, cio)) + return 1; + if (mj2_read_stsc(tk, cio)) + return 1; + if (mj2_read_stsz(tk, cio)) + return 1; + if (mj2_read_stco(tk, cio)) + return 1; + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with STBL Box size\n"); + return 1; + } + return 0; +} + +/* +* Write the URL box +* +* URL box +* +*/ +void mj2_write_url(mj2_tk_t * tk, int url_num, opj_cio_t *cio) +{ + mj2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + cio_write(cio, MJ2_URL, 4); /* URL */ + + if (url_num == 0) + cio_write(cio, 1, 4); /* Version = 0, flags = 1 because stored in same file */ + else { + cio_write(cio, 0, 4); /* Version = 0, flags = 0 */ + cio_write(cio, tk->url[url_num - 1].location[0], 4); + cio_write(cio, tk->url[url_num - 1].location[1], 4); + cio_write(cio, tk->url[url_num - 1].location[2], 4); + cio_write(cio, tk->url[url_num - 1].location[3], 4); + } + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the URL box +* +* URL box +* +*/ +int mj2_read_url(mj2_tk_t * tk, int urn_num, opj_cio_t *cio) +{ + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); + if (MJ2_URL != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected URL Marker\n"); + return 1; + } + + if (0 != cio_read(cio, 1)) { /* Version = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Only Version 0 handled in URL box\n"); + return 1; + } + + if (1 != cio_read(cio, 3)) { /* If flags = 1 --> media data in file */ + tk->url[urn_num].location[0] = cio_read(cio, 4); + tk->url[urn_num].location[1] = cio_read(cio, 4); + tk->url[urn_num].location[2] = cio_read(cio, 4); + tk->url[urn_num].location[3] = cio_read(cio, 4); + } else { + tk->num_url--; + } + + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with URL Box size\n"); + return 1; + } + return 0; +} + +/* +* Write the URN box +* +* URN box +* +*/ +void mj2_write_urn(mj2_tk_t * tk, int urn_num, opj_cio_t *cio) +{ + mj2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + cio_write(cio, MJ2_URN, 4); /* URN */ + + cio_write(cio, 0, 4); /* Version = 0, flags = 0 */ + + cio_write(cio, tk->urn[urn_num].name[0], 4); + cio_write(cio, tk->urn[urn_num].name[1], 4); + cio_write(cio, tk->urn[urn_num].name[2], 4); + cio_write(cio, tk->urn[urn_num].name[3], 4); + cio_write(cio, tk->urn[urn_num].location[0], 4); + cio_write(cio, tk->urn[urn_num].location[1], 4); + cio_write(cio, tk->urn[urn_num].location[2], 4); + cio_write(cio, tk->urn[urn_num].location[3], 4); + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the URN box +* +* URN box +* +*/ +int mj2_read_urn(mj2_tk_t * tk, int urn_num, opj_cio_t *cio) +{ + + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); + if (MJ2_URN != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected URN Marker\n"); + return 1; + } + + if (0 != cio_read(cio, 1)) { /* Version = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Only Version 0 handled in URN box\n"); + return 1; + } + + if (1 != cio_read(cio, 3)) { /* If flags = 1 --> media data in file */ + tk->urn[urn_num].name[0] = cio_read(cio, 4); + tk->urn[urn_num].name[1] = cio_read(cio, 4); + tk->urn[urn_num].name[2] = cio_read(cio, 4); + tk->urn[urn_num].name[3] = cio_read(cio, 4); + tk->urn[urn_num].location[0] = cio_read(cio, 4); + tk->urn[urn_num].location[1] = cio_read(cio, 4); + tk->urn[urn_num].location[2] = cio_read(cio, 4); + tk->urn[urn_num].location[3] = cio_read(cio, 4); + } + + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with URN Box size\n"); + return 1; + } + return 0; +} + + +/* +* Write the DREF box +* +* Data reference box +* +*/ +void mj2_write_dref(mj2_tk_t * tk, opj_cio_t *cio) +{ + int i; + mj2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + cio_write(cio, MJ2_DREF, 4); /* DREF */ + + cio_write(cio, 0, 4); /* Version = 0, flags = 0 */ + + if (tk->num_url + tk->num_urn == 0) { /* Media data in same file */ + cio_write(cio, 1, 4); /* entry_count = 1 */ + mj2_write_url(tk, 0, cio); + } else { + cio_write(cio, tk->num_url + tk->num_urn, 4); /* entry_count */ + + for (i = 0; i < tk->num_url; i++) + mj2_write_url(tk, i + 1, cio); + + for (i = 0; i < tk->num_urn; i++) + mj2_write_urn(tk, i, cio); + } + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the DREF box +* +* Data reference box +* +*/ +int mj2_read_dref(mj2_tk_t * tk, opj_cio_t *cio) +{ + + int i; + int entry_count, marker; + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); + if (MJ2_DREF != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected DREF Marker\n"); + return 1; + } + + if (0 != cio_read(cio, 1)) { /* Version = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Only Version 0 handled in DREF box\n"); + return 1; + } + + if (0 != cio_read(cio, 3)) { /* Flags = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with flag in DREF box. Expected flag 0\n"); + return 1; + } + + entry_count = cio_read(cio, 4); + tk->num_url = 0; + tk->num_urn = 0; + + for (i = 0; i < entry_count; i++) { + cio_skip(cio,4); + marker = cio_read(cio, 4); + if (marker == MJ2_URL) { + cio_skip(cio,-8); + tk->num_url++; + if (mj2_read_url(tk, tk->num_url, cio)) + return 1; + } else if (marker == MJ2_URN) { + cio_skip(cio,-8); + tk->num_urn++; + if (mj2_read_urn(tk, tk->num_urn, cio)) + return 1; + } else { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with in DREF box. Expected URN or URL box\n"); + return 1; + } + + } + + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with DREF Box size\n"); + return 1; + } + return 0; +} + +/* +* Write the DINF box +* +* Data information box +* +*/ +void mj2_write_dinf(mj2_tk_t * tk, opj_cio_t *cio) +{ + mj2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + cio_write(cio, MJ2_DINF, 4); /* DINF */ + + mj2_write_dref(tk, cio); + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the DINF box +* +* Data information box +* +*/ +int mj2_read_dinf(mj2_tk_t * tk, opj_cio_t *cio) +{ + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); + if (MJ2_DINF != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected DINF Marker\n"); + return 1; + } + + if (mj2_read_dref(tk, cio)) + return 1; + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with DINF Box size\n"); + return 1; + } + return 0; +} + +/* +* Write the VMHD box +* +* Video Media information box +* +*/ +void mj2_write_vmhd(mj2_tk_t * tk, opj_cio_t *cio) +{ + mj2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + cio_write(cio, MJ2_VMHD, 4); /* VMHD */ + + cio_write(cio, 1, 4); /* Version = 0, flags = 1 */ + + cio_write(cio, tk->graphicsmode, 2); + cio_write(cio, tk->opcolor[0], 2); + cio_write(cio, tk->opcolor[1], 2); + cio_write(cio, tk->opcolor[2], 2); + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the VMHD box +* +* Video Media information box +* +*/ +int mj2_read_vmhd(mj2_tk_t * tk, opj_cio_t *cio) +{ + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); + if (MJ2_VMHD != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected VMHD Marker\n"); + return 1; + } + + if (0 != cio_read(cio, 1)) { /* Version = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Only Version 0 handled in VMHD box\n"); + return 1; + } + + if (1 != cio_read(cio, 3)) { /* Flags = 1 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with flag in VMHD box. Expected flag 1\n"); + return 1; + } + + tk->track_type = 0; + tk->graphicsmode = cio_read(cio, 2); + tk->opcolor[0] = cio_read(cio, 2); + tk->opcolor[1] = cio_read(cio, 2); + tk->opcolor[2] = cio_read(cio, 2); + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with VMHD Box size\n"); + return 1; + } + return 0; +} + +/* +* Write the SMHD box +* +* Sound Media information box +* +*/ +void mj2_write_smhd(mj2_tk_t * tk, opj_cio_t *cio) +{ + mj2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + cio_write(cio, MJ2_SMHD, 4); /* SMHD */ + + cio_write(cio, 0, 4); /* Version = 0, flags = 0 */ + + cio_write(cio, tk->balance, 2); + + cio_write(cio, 0, 2); /* Reserved */ + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the SMHD box +* +* Sound Media information box +* +*/ +int mj2_read_smhd(mj2_tk_t * tk, opj_cio_t *cio) +{ + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); + if (MJ2_SMHD != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected SMHD Marker\n"); + return 1; + } + + if (0 != cio_read(cio, 1)) { /* Version = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Only Version 0 handled in SMHD box\n"); + return 1; + } + + if (0 != cio_read(cio, 3)) { /* Flags = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with flag in SMHD box. Expected flag 0\n"); + return 1; + } + + tk->track_type = 1; + tk->balance = cio_read(cio, 2); + + /* Init variables to zero to avoid problems when freeeing memory + The values will possibly be overidded when decoding the track structure */ + tk->num_br = 0; + tk->num_url = 0; + tk->num_urn = 0; + tk->num_chunks = 0; + tk->num_tts = 0; + tk->num_samplestochunk = 0; + tk->num_samples = 0; + + cio_skip(cio,2); /* Reserved */ + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with SMHD Box size\n"); + return 1; + } + return 0; +} + +/* +* Write the HMHD box +* +* Hint Media information box +* +*/ +void mj2_write_hmhd(mj2_tk_t * tk, opj_cio_t *cio) +{ + mj2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + cio_write(cio, MJ2_HMHD, 4); /* HMHD */ + + cio_write(cio, 0, 4); /* Version = 0, flags = 0 */ + + cio_write(cio, tk->maxPDUsize, 2); + cio_write(cio, tk->avgPDUsize, 2); + cio_write(cio, tk->maxbitrate, 4); + cio_write(cio, tk->avgbitrate, 4); + cio_write(cio, tk->slidingavgbitrate, 4); + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the HMHD box +* +* Hint Media information box +* +*/ +int mj2_read_hmhd(mj2_tk_t * tk, opj_cio_t *cio) +{ + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); + if (MJ2_HMHD != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected HMHD Marker\n"); + return 1; + } + + if (0 != cio_read(cio, 1)) { /* Version = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Only Version 0 handled in HMHD box\n"); + return 1; + } + + if (0 != cio_read(cio, 3)) { /* Flags = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with flag in HMHD box. Expected flag 0\n"); + return 1; + } + + tk->track_type = 2; + tk->maxPDUsize = cio_read(cio, 2); + tk->avgPDUsize = cio_read(cio, 2); + tk->maxbitrate = cio_read(cio, 4); + tk->avgbitrate = cio_read(cio, 4); + tk->slidingavgbitrate = cio_read(cio, 4); + + /* Init variables to zero to avoid problems when freeeing memory + The values will possibly be overidded when decoding the track structure */ + tk->num_br = 0; + tk->num_url = 0; + tk->num_urn = 0; + tk->num_chunks = 0; + tk->num_tts = 0; + tk->num_samplestochunk = 0; + tk->num_samples = 0; + + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with HMHD Box size\n"); + return 1; + } + return 0; +} + +/* +* Write the MINF box +* +* Media information box +* +*/ +void mj2_write_minf(mj2_tk_t * tk, opj_cio_t *cio) +{ + mj2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + cio_write(cio, MJ2_MINF, 4); /* MINF */ + + if (tk->track_type == 0) { + mj2_write_vmhd(tk, cio); + } else if (tk->track_type == 1) { + mj2_write_smhd(tk, cio); + } else if (tk->track_type == 2) { + mj2_write_hmhd(tk, cio); + } + + mj2_write_dinf(tk, cio); + mj2_write_stbl(tk, cio); + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the MINF box +* +* Media information box +* +*/ +int mj2_read_minf(mj2_tk_t * tk, opj_image_t * img, opj_cio_t *cio) +{ + + unsigned int box_type; + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); + if (MJ2_MINF != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected MINF Marker\n"); + return 1; + } + + cio_skip(cio,4); + box_type = cio_read(cio, 4); + cio_skip(cio,-8); + + if (box_type == MJ2_VMHD) { + if (mj2_read_vmhd(tk, cio)) + return 1; + } else if (box_type == MJ2_SMHD) { + if (mj2_read_smhd(tk, cio)) + return 1; + } else if (box_type == MJ2_HMHD) { + if (mj2_read_hmhd(tk, cio)) + return 1; + } else { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error in MINF box expected vmhd, smhd or hmhd\n"); + return 1; + } + + if (mj2_read_dinf(tk, cio)) + return 1; + + if (mj2_read_stbl(tk, img, cio)) + return 1; + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with MINF Box size\n"); + return 1; + } + return 0; +} + +/* +* Write the HDLR box +* +* Handler reference box +* +*/ +void mj2_write_hdlr(mj2_tk_t * tk, opj_cio_t *cio) +{ + mj2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + cio_write(cio, MJ2_HDLR, 4); /* HDLR */ + + cio_write(cio, 0, 4); /* Version = 0, flags = 0 */ + + cio_write(cio, 0, 4); /* Predefine */ + + tk->name = 0; /* The track name is immediately determined by the track type */ + + if (tk->track_type == 0) { + tk->handler_type = 0x76696465; /* Handler type: vide */ + cio_write(cio, tk->handler_type, 4); + + cio_write(cio, 0, 4); + cio_write(cio, 0, 4); + cio_write(cio, 0, 4); /* Reserved */ + + cio_write(cio, 0x76696465, 4); + cio_write(cio, 0x6F206d65, 4); + cio_write(cio, 0x64696120, 4); + cio_write(cio, 0x74726163, 4); + cio_write(cio, 0x6b00, 2); /* String: video media track */ + } else if (tk->track_type == 1) { + tk->handler_type = 0x736F756E; /* Handler type: soun */ + cio_write(cio, tk->handler_type, 4); + + cio_write(cio, 0, 4); + cio_write(cio, 0, 4); + cio_write(cio, 0, 4); /* Reserved */ + + cio_write(cio, 0x536F756E, 4); + cio_write(cio, 0x6400, 2); /* String: Sound */ + } else if (tk->track_type == 2) { + tk->handler_type = 0x68696E74; /* Handler type: hint */ + cio_write(cio, tk->handler_type, 4); + + cio_write(cio, 0, 4); + cio_write(cio, 0, 4); + cio_write(cio, 0, 4); /* Reserved */ + + cio_write(cio, 0x48696E74, 4); + cio_write(cio, 0, 2); /* String: Hint */ + } + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the HDLR box +* +* Handler reference box +* +*/ +int mj2_read_hdlr(mj2_tk_t * tk, opj_cio_t *cio) +{ + int i; + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); + if (MJ2_HDLR != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected HDLR Marker\n"); + return 1; + } + + + if (0 != cio_read(cio, 1)) { /* Version = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Only Version 0 handled in HDLR box\n"); + return 1; + } + + if (0 != cio_read(cio, 3)) { /* Flags = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with flag in HDLR box. Expected flag 0\n"); + return 1; + } + + cio_skip(cio,4); /* Reserved */ + + tk->handler_type = cio_read(cio, 4); + cio_skip(cio,12); /* Reserved */ + + tk->name_size = box.length - 32; + + tk->name = (char*) opj_malloc(tk->name_size * sizeof(char)); + for (i = 0; i < tk->name_size; i++) { + tk->name[i] = cio_read(cio, 1); /* Name */ + } + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with HDLR Box size\n"); + return 1; + } + return 0; +} + +/* +* Write the MDHD box +* +* Media Header Box +* +*/ +void mj2_write_mdhd(mj2_tk_t * tk, opj_cio_t *cio) +{ + mj2_box_t box; + unsigned int i; + time_t ltime; + unsigned int modification_time; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + cio_write(cio, MJ2_MDHD, 4); /* MDHD */ + + cio_write(cio, 0, 4); /* Version = 0, flags = 0 */ + + cio_write(cio, tk->creation_time, 4); /* Creation Time */ + + time(<ime); /* Time since 1/1/70 */ + modification_time = (unsigned int)ltime + 2082844800; /* Seoonds between 1/1/04 and 1/1/70 */ + + cio_write(cio, modification_time, 4); /* Modification Time */ + + cio_write(cio, tk->timescale, 4); /* Timescale */ + + tk->duration = 0; + + for (i = 0; i < tk->num_samples; i++) + tk->duration += tk->sample[i].sample_delta; + + cio_write(cio, tk->duration, 4); /* Duration */ + + cio_write(cio, tk->language, 2); /* Language */ + + cio_write(cio, 0, 2); /* Predefined */ + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the MDHD box +* +* Media Header Box +* +*/ +int mj2_read_mdhd(mj2_tk_t * tk, opj_cio_t *cio) +{ + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); + if (!(MJ2_MHDR == box.type || MJ2_MDHD == box.type)) { // Kakadu writes MHDR instead of MDHD + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected MDHD Marker\n"); + return 1; + } + + if (0 != cio_read(cio, 1)) { /* Version = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Only Version 0 handled in MDHD box\n"); + return 1; + } + + if (0 != cio_read(cio, 3)) { /* Flags = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with flag in MDHD box. Expected flag 0\n"); + return 1; + } + + + tk->creation_time = cio_read(cio, 4); /* Creation Time */ + + tk->modification_time = cio_read(cio, 4); /* Modification Time */ + + tk->timescale = cio_read(cio, 4); /* Timescale */ + + tk->duration = cio_read(cio, 4); /* Duration */ + + tk->language = cio_read(cio, 2); /* Language */ + + cio_skip(cio,2); /* Predefined */ + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with MDHD Box size\n"); + return 1; + } + return 0; +} + +/* +* Write the MDIA box +* +* Media box +* +*/ +void mj2_write_mdia(mj2_tk_t * tk, opj_cio_t *cio) +{ + mj2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + cio_write(cio, MJ2_MDIA, 4); /* MDIA */ + + mj2_write_mdhd(tk, cio); + mj2_write_hdlr(tk, cio); + mj2_write_minf(tk, cio); + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the MDIA box +* +* Media box +* +*/ +int mj2_read_mdia(mj2_tk_t * tk, opj_image_t * img, opj_cio_t *cio) +{ + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); + if (MJ2_MDIA != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected MDIA Marker\n"); + return 1; + } + + if (mj2_read_mdhd(tk, cio)) + return 1; + if (mj2_read_hdlr(tk, cio)) + return 1; + if (mj2_read_minf(tk, img, cio)) + return 1; + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with MDIA Box size\n"); + return 1; + } + return 0; +} + +/* +* Write the TKHD box +* +* Track Header box +* +*/ +void mj2_write_tkhd(mj2_tk_t * tk, opj_cio_t *cio) +{ + mj2_box_t box; + unsigned int i; + time_t ltime; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + + cio_write(cio, MJ2_TKHD, 4); /* TKHD */ + + cio_write(cio, 3, 4); /* Version=0, flags=3 */ + + time(<ime); /* Time since 1/1/70 */ + tk->modification_time = (unsigned int)ltime + 2082844800; /* Seoonds between 1/1/04 and 1/1/70 */ + + cio_write(cio, tk->creation_time, 4); /* Creation Time */ + + cio_write(cio, tk->modification_time, 4); /* Modification Time */ + + cio_write(cio, tk->track_ID, 4); /* Track ID */ + + cio_write(cio, 0, 4); /* Reserved */ + + tk->duration = 0; + + for (i = 0; i < tk->num_samples; i++) + tk->duration += tk->sample[i].sample_delta; + + cio_write(cio, tk->duration, 4); /* Duration */ + + cio_write(cio, 0, 4); /* Reserved */ + cio_write(cio, 0, 4); /* Reserved */ + + cio_write(cio, tk->layer, 2); /* Layer */ + + cio_write(cio, 0, 2); /* Predefined */ + + cio_write(cio, tk->volume, 2); /* Volume */ + + cio_write(cio, 0, 2); /* Reserved */ + + cio_write(cio, tk->trans_matrix[0], 4); /* Transformation matrix for track */ + cio_write(cio, tk->trans_matrix[1], 4); + cio_write(cio, tk->trans_matrix[2], 4); + cio_write(cio, tk->trans_matrix[3], 4); + cio_write(cio, tk->trans_matrix[4], 4); + cio_write(cio, tk->trans_matrix[5], 4); + cio_write(cio, tk->trans_matrix[6], 4); + cio_write(cio, tk->trans_matrix[7], 4); + cio_write(cio, tk->trans_matrix[8], 4); + + cio_write(cio, tk->visual_w, 4); /* Video Visual Width */ + + cio_write(cio, tk->visual_h, 4); /* Video Visual Height */ + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the TKHD box +* +* Track Header box +* +*/ +int mj2_read_tkhd(mj2_tk_t * tk, opj_cio_t *cio) +{ + int flag; + + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); + + if (MJ2_TKHD != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected TKHD Marker\n"); + return 1; + } + + if (0 != cio_read(cio, 1)) { /* Version = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Only Version 0 handled in TKHD box\n"); + return 1; + } + + flag = cio_read(cio, 3); + + if (!(flag == 1 || flag == 2 || flag == 3 || flag == 4)) { /* Flags = 1,2,3 or 4 */ + opj_event_msg(cio->cinfo, EVT_ERROR, + "Error with flag in TKHD box: Expected flag 1,2,3 or 4\n"); + return 1; + } + + tk->creation_time = cio_read(cio, 4); /* Creation Time */ + + tk->modification_time = cio_read(cio, 4); /* Modification Time */ + + tk->track_ID = cio_read(cio, 4); /* Track ID */ + + cio_skip(cio,4); /* Reserved */ + + tk->duration = cio_read(cio, 4); /* Duration */ + + cio_skip(cio,8); /* Reserved */ + + tk->layer = cio_read(cio, 2); /* Layer */ + + cio_read(cio, 2); /* Predefined */ + + tk->volume = cio_read(cio, 2); /* Volume */ + + cio_skip(cio,2); /* Reserved */ + + tk->trans_matrix[0] = cio_read(cio, 4); /* Transformation matrix for track */ + tk->trans_matrix[1] = cio_read(cio, 4); + tk->trans_matrix[2] = cio_read(cio, 4); + tk->trans_matrix[3] = cio_read(cio, 4); + tk->trans_matrix[4] = cio_read(cio, 4); + tk->trans_matrix[5] = cio_read(cio, 4); + tk->trans_matrix[6] = cio_read(cio, 4); + tk->trans_matrix[7] = cio_read(cio, 4); + tk->trans_matrix[8] = cio_read(cio, 4); + + tk->visual_w = cio_read(cio, 4); /* Video Visual Width */ + + tk->visual_h = cio_read(cio, 4); /* Video Visual Height */ + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with TKHD Box size\n"); + return 1; + } + return 0; +} + +/* +* Write the TRAK box +* +* Track box +* +*/ +void mj2_write_trak(mj2_tk_t * tk, opj_cio_t *cio) +{ + mj2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + + cio_write(cio, MJ2_TRAK, 4); /* TRAK */ + + mj2_write_tkhd(tk, cio); + mj2_write_mdia(tk, cio); + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the TRAK box +* +* Track box +* +*/ +int mj2_read_trak(mj2_tk_t * tk, opj_image_t * img, opj_cio_t *cio) +{ + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); + if (MJ2_TRAK != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected TRAK Marker\n"); + return 1; + } + if (mj2_read_tkhd(tk, cio)) + return 1; + if (mj2_read_mdia(tk, img, cio)) + return 1; + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with TRAK Box\n"); + return 1; + } + return 0; +} + +/* +* Write the MVHD box +* +* Movie header Box +* +*/ +void mj2_write_mvhd(opj_mj2_t * movie, opj_cio_t *cio) +{ + int i; + mj2_box_t box; + unsigned j; + time_t ltime; + int max_tk_num = 0; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + cio_write(cio, MJ2_MVHD, 4); /* MVHD */ + + cio_write(cio, 0, 4); /* Version = 0, flags = 0 */ + + time(<ime); /* Time since 1/1/70 */ + movie->modification_time = (unsigned int)ltime + 2082844800; /* Seoonds between 1/1/04 and 1/1/70 */ + + cio_write(cio, movie->creation_time, 4); /* Creation Time */ + + cio_write(cio, movie->modification_time, 4); /* Modification Time */ + + cio_write(cio, movie->timescale, 4); /* Timescale */ + + movie->duration = 0; + + for (i = 0; i < (movie->num_stk + movie->num_htk + movie->num_vtk); i++) { + mj2_tk_t *tk = &movie->tk[i]; + + for (j = 0; j < tk->num_samples; j++) { + movie->duration += tk->sample[j].sample_delta; + } + } + + cio_write(cio, movie->duration, 4); + + cio_write(cio, movie->rate, 4); /* Rate to play presentation */ + + cio_write(cio, movie->volume, 2); /* Volume */ + + cio_write(cio, 0, 2); /* Reserved */ + cio_write(cio, 0, 4); /* Reserved */ + cio_write(cio, 0, 4); /* Reserved */ + + cio_write(cio, movie->trans_matrix[0], 4); /* Transformation matrix for video */ + cio_write(cio, movie->trans_matrix[1], 4); + cio_write(cio, movie->trans_matrix[2], 4); + cio_write(cio, movie->trans_matrix[3], 4); + cio_write(cio, movie->trans_matrix[4], 4); + cio_write(cio, movie->trans_matrix[5], 4); + cio_write(cio, movie->trans_matrix[6], 4); + cio_write(cio, movie->trans_matrix[7], 4); + cio_write(cio, movie->trans_matrix[8], 4); + + cio_write(cio, 0, 4); /* Pre-defined */ + cio_write(cio, 0, 4); /* Pre-defined */ + cio_write(cio, 0, 4); /* Pre-defined */ + cio_write(cio, 0, 4); /* Pre-defined */ + cio_write(cio, 0, 4); /* Pre-defined */ + cio_write(cio, 0, 4); /* Pre-defined */ + + + for (i = 0; i < movie->num_htk + movie->num_stk + movie->num_vtk; i++) { + if (max_tk_num < movie->tk[i].track_ID) + max_tk_num = movie->tk[i].track_ID; + } + + movie->next_tk_id = max_tk_num + 1; + + cio_write(cio, movie->next_tk_id, 4); /* ID of Next track to be added */ + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the MVHD box +* +* Movie header Box +* +*/ +int mj2_read_mvhd(opj_mj2_t * movie, opj_cio_t *cio) +{ + mj2_box_t box; + + mj2_read_boxhdr(&box, cio); + if (MJ2_MVHD != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected MVHD Marker\n"); + return 1; + } + + + if (0 != cio_read(cio, 4)) { /* Version = 0, flags = 0 */ + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Only Version 0 handled in MVHD box\n"); + } + + movie->creation_time = cio_read(cio, 4); /* Creation Time */ + + movie->modification_time = cio_read(cio, 4); /* Modification Time */ + + movie->timescale = cio_read(cio, 4); /* Timescale */ + + movie->duration = cio_read(cio, 4); /* Duration */ + + movie->rate = cio_read(cio, 4); /* Rate to play presentation */ + + movie->volume = cio_read(cio, 2); /* Volume */ + + cio_skip(cio,10); /* Reserved */ + + movie->trans_matrix[0] = cio_read(cio, 4); /* Transformation matrix for video */ + movie->trans_matrix[1] = cio_read(cio, 4); + movie->trans_matrix[2] = cio_read(cio, 4); + movie->trans_matrix[3] = cio_read(cio, 4); + movie->trans_matrix[4] = cio_read(cio, 4); + movie->trans_matrix[5] = cio_read(cio, 4); + movie->trans_matrix[6] = cio_read(cio, 4); + movie->trans_matrix[7] = cio_read(cio, 4); + movie->trans_matrix[8] = cio_read(cio, 4); + + cio_skip(cio,24); /* Pre-defined */ + + movie->next_tk_id = cio_read(cio, 4); /* ID of Next track to be added */ + + if (cio_tell(cio) - box.init_pos != box.length) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with MVHD Box Size\n"); + return 1; + } + return 0; +} + + +/* +* Write the MOOV box +* +* Movie Box +* +*/ +void mj2_write_moov(opj_mj2_t * movie, opj_cio_t *cio) +{ + int i; + mj2_box_t box; + + box.init_pos = cio_tell(cio); + cio_skip(cio,4); + cio_write(cio, MJ2_MOOV, 4); /* MOOV */ + + mj2_write_mvhd(movie, cio); + + for (i = 0; i < (movie->num_stk + movie->num_htk + movie->num_vtk); i++) { + mj2_write_trak(&movie->tk[i], cio); + } + + box.length = cio_tell(cio) - box.init_pos; + cio_seek(cio, box.init_pos); + cio_write(cio, box.length, 4); /* L */ + cio_seek(cio, box.init_pos + box.length); +} + +/* +* Read the MOOV box +* +* Movie Box +* +*/ +int mj2_read_moov(opj_mj2_t * movie, opj_image_t * img, opj_cio_t *cio) +{ + unsigned int i; + mj2_box_t box; + mj2_box_t box2; + + mj2_read_boxhdr(&box, cio); + if (MJ2_MOOV != box.type) { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error: Expected MOOV Marker\n"); + return 1; + } + + if (mj2_read_mvhd(movie, cio)) + return 1; + + movie->tk = (mj2_tk_t*) opj_malloc((movie->next_tk_id - 1) * sizeof(mj2_tk_t)); + + for (i = 0; cio_tell(cio) - box.init_pos < box.length; i++) { + mj2_tk_t *tk = &movie->tk[i]; + tk->cinfo = movie->cinfo; + mj2_read_boxhdr(&box2, cio); + if (box2.type == MJ2_TRAK) { + cio_seek(cio, box2.init_pos); + if (mj2_read_trak(tk, img, cio)) + return 1; + + if (tk->track_type == 0) { + movie->num_vtk++; + } else if (tk->track_type == 1) { + movie->num_stk++; + } else if (tk->track_type == 2) { + movie->num_htk++; + } + } else if (box2.type == MJ2_MVEX) { + cio_seek(cio, box2.init_pos); + cio_skip(cio,box2.length); + i--; + } else { + opj_event_msg(cio->cinfo, EVT_ERROR, "Error with MOOV Box: Expected TRAK or MVEX box\n"); + return 1; + } + } + return 0; +} + +int mj2_read_struct(FILE *file, opj_mj2_t *movie) { + mj2_box_t box; + opj_image_t img; + unsigned char * src; + int fsresult; + int foffset; + opj_cio_t *cio; + + /* open a byte stream for reading */ + src = (unsigned char*) opj_malloc(300 * sizeof(unsigned char)); + + /* Assuming that jp and ftyp markers size do + not exceed 300 bytes */ + fread(src,300,1, file); + + cio = opj_cio_open((opj_common_ptr)movie->cinfo, src, 300); + + if (mj2_read_jp(cio)) + return 1; + if (mj2_read_ftyp(movie, cio)) + return 1; + + fsresult = fseek(file,cio_tell(cio),SEEK_SET); + if( fsresult ) { + opj_event_msg(cio->cinfo, EVT_ERROR, "End of file reached while trying to read data after FTYP box\n" ); + return 1; + } + + foffset = cio_tell(cio); + + box.type = 0; + + fread(src,30,1,file); + cio = opj_cio_open((opj_common_ptr)movie->cinfo, src, 300); + mj2_read_boxhdr(&box, cio); + + while(box.type != MJ2_MOOV) { + + switch(box.type) + { + case MJ2_MDAT: + fsresult = fseek(file,foffset+box.length,SEEK_SET); + if( fsresult ) { + opj_event_msg(cio->cinfo, EVT_ERROR, "End of file reached while trying to read MDAT box\n" ); + return 1; + } + foffset += box.length; + break; + + case MJ2_MOOF: + fsresult = fseek(file,foffset+box.length,SEEK_SET); + if( fsresult ) { + opj_event_msg(cio->cinfo, EVT_ERROR, "End of file reached while trying to read MOOF box\n" ); + return 1; + } + foffset += box.length; + break; + case MJ2_FREE: + fsresult = fseek(file,foffset+box.length,SEEK_SET); + if( fsresult ) { + opj_event_msg(cio->cinfo, EVT_ERROR, "End of file reached while trying to read FREE box\n" ); + return 1; + } + foffset += box.length; + break; + case MJ2_SKIP: + fsresult = fseek(file,foffset+box.length,SEEK_SET); + if( fsresult ) { + opj_event_msg(cio->cinfo, EVT_ERROR, "End of file reached while trying to read SKIP box\n" ); + return 1; + } + foffset += box.length; + break; + default: + opj_event_msg(cio->cinfo, EVT_ERROR, "Unknown box in MJ2 stream\n"); + fsresult = fseek(file,foffset+box.length,SEEK_SET); + if( fsresult ) { + opj_event_msg(cio->cinfo, EVT_ERROR, "End of file reached while trying to read end of unknown box\n"); + return 1; + } + foffset += box.length; + break; + } + fsresult = fread(src,8,1,file); + if (fsresult != 1) { + opj_event_msg(cio->cinfo, EVT_ERROR, "MOOV box not found in file\n"); + return 1; + } + cio = opj_cio_open((opj_common_ptr)movie->cinfo, src, 8); + mj2_read_boxhdr(&box, cio); + } + + fseek(file,foffset,SEEK_SET); + src = (unsigned char*)opj_realloc(src,box.length); + fsresult = fread(src,box.length,1,file); + if (fsresult != 1) { + opj_event_msg(cio->cinfo, EVT_ERROR, "End of file reached while trying to read MOOV box\n"); + return 1; + } + + cio = opj_cio_open((opj_common_ptr)movie->cinfo, src, box.length); + + if (mj2_read_moov(movie, &img, cio)) + return 1; + + opj_free(src); + return 0; +} + +/* ----------------------------------------------------------------------- */ +/* MJ2 decoder interface */ +/* ----------------------------------------------------------------------- */ + +opj_dinfo_t* mj2_create_decompress() { + opj_mj2_t* mj2; + opj_dinfo_t *dinfo = (opj_dinfo_t*) opj_calloc(1, sizeof(opj_dinfo_t)); + if(!dinfo) return NULL; + + dinfo->is_decompressor = true; + + mj2 = (opj_mj2_t*) opj_calloc(1, sizeof(opj_mj2_t)); + dinfo->mj2_handle = mj2; + if(mj2) { + mj2->cinfo = (opj_common_ptr)dinfo; + } + mj2->j2k = j2k_create_decompress((opj_common_ptr)dinfo); + dinfo->j2k_handle = mj2->j2k; + + return dinfo; +} + +void mj2_setup_decoder(opj_mj2_t *movie, mj2_dparameters_t *mj2_parameters) { + movie->num_vtk=0; + movie->num_stk=0; + movie->num_htk=0; + + /* setup the J2K decoder parameters */ + j2k_setup_decoder((opj_j2k_t*)movie->cinfo->j2k_handle, + &mj2_parameters->j2k_parameters); + +} + +void mj2_destroy_decompress(opj_mj2_t *movie) { + if(movie) { + int i; + mj2_tk_t *tk=NULL; + + if (movie->cinfo->j2k_handle) + j2k_destroy_compress(movie->j2k); + + if (movie->num_cl != 0) + opj_free(movie->cl); + + for (i = 0; i < movie->num_vtk + movie->num_stk + movie->num_htk; i++) { + tk = &movie->tk[i]; + if (tk->name_size != 0) + opj_free(tk->name); + if (tk->track_type == 0) {// Video track + if (tk->jp2_struct.comps != 0) + opj_free(tk->jp2_struct.comps); + if (tk->jp2_struct.cl != 0) + opj_free(tk->jp2_struct.cl); + if (tk->num_jp2x != 0) + opj_free(tk->jp2xdata); + + } + if (tk->num_url != 0) + opj_free(tk->url); + if (tk->num_urn != 0) + opj_free(tk->urn); + if (tk->num_br != 0) + opj_free(tk->br); + if (tk->num_tts != 0) + opj_free(tk->tts); + if (tk->num_chunks != 0) + opj_free(tk->chunk); + if (tk->num_samplestochunk != 0) + opj_free(tk->sampletochunk); + if (tk->num_samples != 0) + opj_free(tk->sample); + } + + opj_free(movie->tk); + } + opj_free(movie); +} + +/* ----------------------------------------------------------------------- */ +/* MJ2 encoder interface */ +/* ----------------------------------------------------------------------- */ + + +opj_cinfo_t* mj2_create_compress() { + opj_mj2_t* mj2; + opj_cinfo_t *cinfo = (opj_cinfo_t*) opj_calloc(1, sizeof(opj_cinfo_t)); + if(!cinfo) return NULL; + + mj2 = (opj_mj2_t*) opj_calloc(1, sizeof(opj_mj2_t)); + cinfo->mj2_handle = mj2; + if(mj2) { + mj2->cinfo = (opj_common_ptr)cinfo; + } + + mj2->j2k = j2k_create_compress(mj2->cinfo); + cinfo->j2k_handle = mj2->j2k; + + return cinfo; +} + +void mj2_setup_encoder(opj_mj2_t *movie, mj2_cparameters_t *parameters) { + if(movie && parameters) { + opj_jp2_t *jp2_struct; + + movie->num_htk = 0; // No hint tracks + movie->num_stk = 0; // No sound tracks + movie->num_vtk = 1; // One video track + + movie->brand = MJ2_MJ2; // One brand: MJ2 + movie->num_cl = 2; // Two compatible brands: MJ2 and MJ2S + movie->cl = (unsigned int*) opj_malloc(movie->num_cl * sizeof(unsigned int)); + movie->cl[0] = MJ2_MJ2; + movie->cl[1] = MJ2_MJ2S; + movie->minversion = 0; // Minimum version: 0 + + movie->tk = (mj2_tk_t*) opj_malloc(sizeof(mj2_tk_t)); //Memory allocation for the video track + movie->tk[0].track_ID = 1; // Track ID = 1 + movie->tk[0].track_type = 0; // Video track + movie->tk[0].Dim[0] = parameters->Dim[0]; + movie->tk[0].Dim[1] = parameters->Dim[1]; + movie->tk[0].w = parameters->w; + movie->tk[0].h = parameters->h; + movie->tk[0].CbCr_subsampling_dx = parameters->CbCr_subsampling_dx; + movie->tk[0].CbCr_subsampling_dy = parameters->CbCr_subsampling_dy; + movie->tk[0].sample_rate = parameters->frame_rate; + movie->tk[0].name_size = 0; + movie->tk[0].chunk = (mj2_chunk_t*) opj_malloc(sizeof(mj2_chunk_t)); + movie->tk[0].sample = (mj2_sample_t*) opj_malloc(sizeof(mj2_sample_t)); + + jp2_struct = &movie->tk[0].jp2_struct; + jp2_struct->numcomps = 3; // NC + jp2_struct->comps = (opj_jp2_comps_t*) opj_malloc(jp2_struct->numcomps * sizeof(opj_jp2_comps_t)); + jp2_struct->precedence = 0; /* PRECEDENCE*/ + jp2_struct->approx = 0; /* APPROX*/ + jp2_struct->brand = JP2_JP2; /* BR */ + jp2_struct->minversion = 0; /* MinV */ + jp2_struct->numcl = 1; + jp2_struct->cl = (unsigned int*) opj_malloc(jp2_struct->numcl * sizeof(unsigned int)); + jp2_struct->cl[0] = JP2_JP2; /* CL0 : JP2 */ + jp2_struct->C = 7; /* C : Always 7*/ + jp2_struct->UnkC = 0; /* UnkC, colorspace specified in colr box*/ + jp2_struct->IPR = 0; /* IPR, no intellectual property*/ + jp2_struct->w = parameters->w; + jp2_struct->h = parameters->h; + jp2_struct->bpc = 7; + jp2_struct->meth = 1; + jp2_struct->enumcs = 18; // YUV + } +} + +void mj2_destroy_compress(opj_mj2_t *movie) { + if(movie) { + int i; + mj2_tk_t *tk=NULL; + + if (movie->cinfo->j2k_handle) { + j2k_destroy_compress(movie->j2k); + } + + if (movie->num_cl != 0) + opj_free(movie->cl); + + for (i = 0; i < movie->num_vtk + movie->num_stk + movie->num_htk; i++) { + tk = &movie->tk[i]; + if (tk->name_size != 0) + opj_free(tk->name); + if (tk->track_type == 0) {// Video track + if (tk->jp2_struct.comps != 0) + opj_free(tk->jp2_struct.comps); + if (tk->jp2_struct.cl != 0) + opj_free(tk->jp2_struct.cl); + if (tk->num_jp2x != 0) + opj_free(tk->jp2xdata); + + } + if (tk->num_url != 0) + opj_free(tk->url); + if (tk->num_urn != 0) + opj_free(tk->urn); + if (tk->num_br != 0) + opj_free(tk->br); + if (tk->num_tts != 0) + opj_free(tk->tts); + if (tk->num_chunks != 0) + opj_free(tk->chunk); + if (tk->num_samplestochunk != 0) + opj_free(tk->sampletochunk); + if (tk->num_samples != 0) + opj_free(tk->sample); + } + + opj_free(movie->tk); + } + opj_free(movie); +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2.h b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2.h new file mode 100644 index 0000000..97cf8ed --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2.h @@ -0,0 +1,391 @@ +/* +* Copyright (c) 2003-2004, François-Olivier Devaux +* Copyright (c) 2003-2004, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium +* All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MJ2_H +#define __MJ2_H +/** +@file mj2.h +@brief The Motion JPEG 2000 file format Reader/Writer (MJ22) + +*/ + +/** @defgroup MJ2 MJ2 - Motion JPEG 2000 file format reader/writer */ +/*@{*/ + +#define MJ2_JP 0x6a502020 +#define MJ2_FTYP 0x66747970 +#define MJ2_MJ2 0x6d6a7032 +#define MJ2_MJ2S 0x6d6a3273 +#define MJ2_MDAT 0x6d646174 +#define MJ2_MOOV 0x6d6f6f76 +#define MJ2_MVHD 0x6d766864 +#define MJ2_TRAK 0x7472616b +#define MJ2_TKHD 0x746b6864 +#define MJ2_MDIA 0x6d646961 +#define MJ2_MDHD 0x6d646864 +#define MJ2_MHDR 0x6d686472 +#define MJ2_HDLR 0x68646C72 +#define MJ2_MINF 0x6d696e66 +#define MJ2_VMHD 0x766d6864 +#define MJ2_SMHD 0x736d6864 +#define MJ2_HMHD 0x686d6864 +#define MJ2_DINF 0x64696e66 +#define MJ2_DREF 0x64726566 +#define MJ2_URL 0x75726c20 +#define MJ2_URN 0x75726e20 +#define MJ2_STBL 0x7374626c +#define MJ2_STSD 0x73747364 +#define MJ2_STTS 0x73747473 +#define MJ2_STSC 0x73747363 +#define MJ2_STSZ 0x7374737a +#define MJ2_STCO 0x7374636f +#define MJ2_MOOF 0x6d6f6f66 +#define MJ2_FREE 0x66726565 +#define MJ2_SKIP 0x736b6970 +#define MJ2_JP2C 0x6a703263 +#define MJ2_FIEL 0x6669656c +#define MJ2_JP2P 0x6a703270 +#define MJ2_JP2X 0x6a703278 +#define MJ2_JSUB 0x6a737562 +#define MJ2_ORFO 0x6f72666f +#define MJ2_MVEX 0x6d766578 +#define MJ2_JP2 0x6a703220 +#define MJ2_J2P0 0x4a325030 + +/** +Decompressed format used in parameters +YUV = 0 +*/ +#define YUV_DFMT 1 + +/** +Compressed format used in parameters +MJ2 = 0 +*/ +#define MJ2_CFMT 2 + + +/* ----------------------------------------------------------------------- */ + +/** +Time To Sample +*/ +typedef struct mj2_tts { + int sample_count; + int sample_delta; +} mj2_tts_t; + +/** +Chunk +*/ +typedef struct mj2_chunk { + int num_samples; + int sample_descr_idx; + int offset; +} mj2_chunk_t; + +/** +Sample to chunk +*/ +typedef struct mj2_sampletochunk { + int first_chunk; + int samples_per_chunk; + int sample_descr_idx; +} mj2_sampletochunk_t; + +/** +Sample +*/ +typedef struct mj2_sample { + unsigned int sample_size; + unsigned int offset; + unsigned int sample_delta; +} mj2_sample_t; + +/** +URL +*/ +typedef struct mj2_url { + int location[4]; +} mj2_url_t; + +/** +URN +*/ +typedef struct mj2_urn { + int name[2]; + int location[4]; +} mj2_urn_t; + +/** +Video Track Parameters +*/ +typedef struct mj2_tk { + /** codec context */ + opj_common_ptr cinfo; + int track_ID; + int track_type; + unsigned int creation_time; + unsigned int modification_time; + int duration; + int timescale; + int layer; + int volume; + int language; + int balance; + int maxPDUsize; + int avgPDUsize; + int maxbitrate; + int avgbitrate; + int slidingavgbitrate; + int graphicsmode; + int opcolor[3]; + int num_url; + mj2_url_t *url; + int num_urn; + mj2_urn_t *urn; + int Dim[2]; + int w; + int h; + int visual_w; + int visual_h; + int CbCr_subsampling_dx; + int CbCr_subsampling_dy; + int sample_rate; + int sample_description; + int horizresolution; + int vertresolution; + int compressorname[8]; + int depth; + unsigned char fieldcount; + unsigned char fieldorder; + unsigned char or_fieldcount; + unsigned char or_fieldorder; + int num_br; + unsigned int *br; + unsigned char num_jp2x; + unsigned char *jp2xdata; + unsigned char hsub; + unsigned char vsub; + unsigned char hoff; + unsigned char voff; + int trans_matrix[9]; + /** Number of samples */ + unsigned int num_samples; + int transorm; + int handler_type; + int name_size; + unsigned char same_sample_size; + int num_tts; + /** Time to sample */ + mj2_tts_t *tts; + unsigned int num_chunks; + mj2_chunk_t *chunk; + int num_samplestochunk; + mj2_sampletochunk_t *sampletochunk; + char *name; + opj_jp2_t jp2_struct; + /** Sample parameters */ + mj2_sample_t *sample; +} mj2_tk_t; + +/** +MJ2 box +*/ +typedef struct mj2_box { + int length; + int type; + int init_pos; +} mj2_box_t; + +/** +MJ2 Movie +*/ +typedef struct opj_mj2 { + /** codec context */ + opj_common_ptr cinfo; + /** handle to the J2K codec */ + opj_j2k_t *j2k; + unsigned int brand; + unsigned int minversion; + int num_cl; + unsigned int *cl; + unsigned int creation_time; + unsigned int modification_time; + int timescale; + unsigned int duration; + int rate; + int num_vtk; + int num_stk; + int num_htk; + int volume; + int trans_matrix[9]; + int next_tk_id; + /** Track Parameters */ + mj2_tk_t *tk; +} opj_mj2_t; + +/** +Decompression parameters +*/ +typedef struct mj2_dparameters { + /**@name command line encoder parameters (not used inside the library) */ + /*@{*/ + /** input file name */ + char infile[OPJ_PATH_LEN]; + /** output file name */ + char outfile[OPJ_PATH_LEN]; + /** J2K decompression parameters */ + opj_dparameters_t j2k_parameters; +} mj2_dparameters_t; + +/** +Compression parameters +*/ +typedef struct mj2_cparameters { + /**@name command line encoder parameters (not used inside the library) */ + /*@{*/ + /** J2K compression parameters */ + opj_cparameters_t j2k_parameters; + /** input file name */ + char infile[OPJ_PATH_LEN]; + /** output file name */ + char outfile[OPJ_PATH_LEN]; + /** input file format 0:MJ2 */ + int decod_format; + /** output file format 0:YUV */ + int cod_format; + /** Portion of the image coded */ + int Dim[2]; + /** YUV Frame width */ + int w; + /** YUV Frame height */ + int h; + /* Sample rate of YUV 4:4:4, 4:2:2 or 4:2:0 */ + int CbCr_subsampling_dx; + /* Sample rate of YUV 4:4:4, 4:2:2 or 4:2:0 */ + int CbCr_subsampling_dy; + /* Video Frame Rate */ + int frame_rate; + /* In YUV files, numcomps always considered as 3 */ + int numcomps; + /* In YUV files, precision always considered as 8 */ + int prec; +} mj2_cparameters_t; + + +/** @name Exported functions */ +/*@{*/ +/* ----------------------------------------------------------------------- */ +/** +Write the JP box +*/ +void mj2_write_jp(opj_cio_t *cio); +/** +Write the FTYP box +@param movie MJ2 movie +@param cio Output buffer stream +*/ +void mj2_write_ftyp(opj_mj2_t *movie, opj_cio_t *cio); +/** +Creates an MJ2 decompression structure +@return Returns a handle to a MJ2 decompressor if successful, returns NULL otherwise +*/ +opj_dinfo_t* mj2_create_decompress(); +/** +Destroy a MJ2 decompressor handle +@param movie MJ2 decompressor handle to destroy +*/ +void mj2_destroy_decompress(opj_mj2_t *movie); +/** +Setup the decoder decoding parameters using user parameters. +Decoding parameters are returned in mj2->j2k->cp. +@param movie MJ2 decompressor handle +@param parameters decompression parameters +*/ +void mj2_setup_decoder(opj_mj2_t *movie, mj2_dparameters_t *mj2_parameters); +/** +Decode an image from a JPEG-2000 file stream +@param movie MJ2 decompressor handle +@param cio Input buffer stream +@return Returns a decoded image if successful, returns NULL otherwise +*/ +opj_image_t* mj2_decode(opj_mj2_t *movie, opj_cio_t *cio); +/** +Creates a MJ2 compression structure +@return Returns a handle to a MJ2 compressor if successful, returns NULL otherwise +*/ +opj_cinfo_t* mj2_create_compress(); +/** +Destroy a MJ2 compressor handle +@param movie MJ2 compressor handle to destroy +*/ +void mj2_destroy_compress(opj_mj2_t *movie); +/** +Setup the encoder parameters using the current image and using user parameters. +Coding parameters are returned in mj2->j2k->cp. +@param movie MJ2 compressor handle +@param parameters compression parameters +*/ +void mj2_setup_encoder(opj_mj2_t *movie, mj2_cparameters_t *parameters); +/** +Encode an image into a JPEG-2000 file stream +@param movie MJ2 compressor handle +@param cio Output buffer stream +@param image Image to encode +@param index Name of the index file if required, NULL otherwise +@return Returns true if successful, returns false otherwise +*/ +bool mj2_encode(opj_mj2_t *movie, opj_cio_t *cio, opj_image_t *image, char *index); + +/** +Init a Standard MJ2 movie +@param movie MJ2 Movie +@return Returns 0 if successful, returns 1 otherwise +*/ +int mj2_init_stdmovie(opj_mj2_t *movie); +/** +Read the structure of an MJ2 file +@param File MJ2 input File +@param movie J2 movie structure +@return Returns 0 if successful, returns 1 otherwise +*/ +int mj2_read_struct(FILE *file, opj_mj2_t *mj2); +/** +Write the the MOOV box to an output buffer stream +@param movie MJ2 movie structure +@param cio Output buffer stream +*/ +void mj2_write_moov(opj_mj2_t *movie, opj_cio_t *cio); + + +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __MJ2_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_convert.c b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_convert.c new file mode 100644 index 0000000..3f4c2e7 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_convert.c @@ -0,0 +1,329 @@ +/* +* Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium +* Copyright (c) 2002-2007, Professor Benoit Macq +* Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "../libopenjpeg/opj_includes.h" +#include "mj2.h" + +/* ----------------------- */ +/* */ +/* */ +/* Count the number of frames */ +/* in a YUV file */ +/* */ +/* ----------------------- */ + +int yuv_num_frames(mj2_tk_t * tk, char *infile) +{ + int numimages, frame_size; + long end_of_f; + FILE *f; + + f = fopen(infile,"rb"); + if (!f) { + fprintf(stderr, "failed to open %s for reading\n",infile); + return -1; + } + + frame_size = (int) (tk->w * tk->h * (1.0 + (double) 2 / (double) (tk->CbCr_subsampling_dx * tk->CbCr_subsampling_dy))); /* Calculate frame size */ + + fseek(f, 0, SEEK_END); + end_of_f = ftell(f); /* Calculate file size */ + + if (end_of_f < frame_size) { + fprintf(stderr, + "YUV does not contains any frame of %d x %d size\n", tk->w, + tk->h); + return -1; + } + + numimages = end_of_f / frame_size; /* Calculate number of images */ + fclose(f); + + return numimages; +} + +// ----------------------- +// +// +// YUV to IMAGE +// +// ----------------------- + +opj_image_t *mj2_image_create(mj2_tk_t * tk, opj_cparameters_t *parameters) +{ + opj_image_cmptparm_t cmptparm[3]; + opj_image_t * img; + int i; + int numcomps = 3; + int subsampling_dx = parameters->subsampling_dx; + int subsampling_dy = parameters->subsampling_dy; + + /* initialize image components */ + memset(&cmptparm[0], 0, 3 * sizeof(opj_image_cmptparm_t)); + for(i = 0; i < numcomps; i++) { + cmptparm[i].prec = 8; + cmptparm[i].bpp = 8; + cmptparm[i].sgnd = 0; + cmptparm[i].dx = i ? subsampling_dx * tk->CbCr_subsampling_dx : subsampling_dx; + cmptparm[i].dy = i ? subsampling_dy * tk->CbCr_subsampling_dy : subsampling_dy; + cmptparm[i].w = tk->w; + cmptparm[i].h = tk->h; + } + /* create the image */ + img = opj_image_create(numcomps, cmptparm, CLRSPC_SRGB); + return img; +} + +char yuvtoimage(mj2_tk_t * tk, opj_image_t * img, int frame_num, opj_cparameters_t *parameters, char* infile) +{ + int i, compno; + int offset; + long end_of_f, position; + int numcomps = 3; + int subsampling_dx = parameters->subsampling_dx; + int subsampling_dy = parameters->subsampling_dy; + FILE *yuvfile; + + yuvfile = fopen(infile,"rb"); + if (!yuvfile) { + fprintf(stderr, "failed to open %s for readings\n",parameters->infile); + return 1; + } + + offset = (int) ((double) (frame_num * tk->w * tk->h) * (1.0 + + 1.0 * (double) 2 / (double) (tk->CbCr_subsampling_dx * tk->CbCr_subsampling_dy))); + fseek(yuvfile, 0, SEEK_END); + end_of_f = ftell(yuvfile); + fseek(yuvfile, sizeof(unsigned char) * offset, SEEK_SET); + position = ftell(yuvfile); + if (position >= end_of_f) { + fprintf(stderr, "Cannot reach frame number %d in yuv file !!\n", + frame_num); + fclose(yuvfile); + return 1; + } + + img->x0 = tk->Dim[0]; + img->y0 = tk->Dim[1]; + img->x1 = !tk->Dim[0] ? (tk->w - 1) * subsampling_dx + 1 : tk->Dim[0] + + (tk->w - 1) * subsampling_dx + 1; + img->y1 = !tk->Dim[1] ? (tk->h - 1) * subsampling_dy + 1 : tk->Dim[1] + + (tk->h - 1) * subsampling_dy + 1; + + for(compno = 0; compno < numcomps; compno++) { + for (i = 0; i < (tk->w * tk->h / (img->comps[compno].dx * img->comps[compno].dy)) + && !feof(yuvfile); i++) { + if (!fread(&img->comps[compno].data[i], 1, 1, yuvfile)) { + fprintf(stderr, "Error reading %s file !!\n", infile); + return 1; + } + } + } + fclose(yuvfile); + + return 0; +} + + + +// ----------------------- +// +// +// IMAGE to YUV +// +// ----------------------- + + +bool imagetoyuv(opj_image_t * img, char *outfile) +{ + FILE *f; + int i; + + if (img->numcomps == 3) { + if (img->comps[0].dx != img->comps[1].dx / 2 + || img->comps[1].dx != img->comps[2].dx) { + fprintf(stderr, + "Error with the input image components size: cannot create yuv file)\n"); + return false; + } + } else if (!(img->numcomps == 1)) { + fprintf(stderr, + "Error with the number of image components(must be one or three)\n"); + return false; + } + + f = fopen(outfile, "a+b"); + if (!f) { + fprintf(stderr, "failed to open %s for writing\n", outfile); + return false; + } + + + for (i = 0; i < (img->comps[0].w * img->comps[0].h); i++) { + unsigned char y; + y = img->comps[0].data[i]; + fwrite(&y, 1, 1, f); + } + + + if (img->numcomps == 3) { + for (i = 0; i < (img->comps[1].w * img->comps[1].h); i++) { + unsigned char cb; + cb = img->comps[1].data[i]; + fwrite(&cb, 1, 1, f); + } + + + for (i = 0; i < (img->comps[2].w * img->comps[2].h); i++) { + unsigned char cr; + cr = img->comps[2].data[i]; + fwrite(&cr, 1, 1, f); + } + } else if (img->numcomps == 1) { + for (i = 0; i < (img->comps[0].w * img->comps[0].h * 0.25); i++) { + unsigned char cb = 125; + fwrite(&cb, 1, 1, f); + } + + + for (i = 0; i < (img->comps[0].w * img->comps[0].h * 0.25); i++) { + unsigned char cr = 125; + fwrite(&cr, 1, 1, f); + } + } + fclose(f); + return true; +} + +// ----------------------- +// +// +// IMAGE to BMP +// +// ----------------------- + +int imagetobmp(opj_image_t * img, char *outfile) { + int w,wr,h,hr,i,pad; + FILE *f; + + if (img->numcomps == 3 && img->comps[0].dx == img->comps[1].dx + && img->comps[1].dx == img->comps[2].dx + && img->comps[0].dy == img->comps[1].dy + && img->comps[1].dy == img->comps[2].dy + && img->comps[0].prec == img->comps[1].prec + && img->comps[1].prec == img->comps[2].prec) { + /* -->> -->> -->> -->> + + 24 bits color + + <<-- <<-- <<-- <<-- */ + + f = fopen(outfile, "wb"); + if (!f) { + fprintf(stderr, "failed to open %s for writing\n", outfile); + return 1; + } + + w = img->comps[0].w; + wr = int_ceildivpow2(img->comps[0].w, img->comps[0].factor); + + h = img->comps[0].h; + hr = int_ceildivpow2(img->comps[0].h, img->comps[0].factor); + + fprintf(f, "BM"); + + /* FILE HEADER */ + /* ------------- */ + fprintf(f, "%c%c%c%c", + (unsigned char) (hr * wr * 3 + 3 * hr * (wr % 2) + + 54) & 0xff, + (unsigned char) ((hr * wr * 3 + 3 * hr * (wr % 2) + 54) + >> 8) & 0xff, + (unsigned char) ((hr * wr * 3 + 3 * hr * (wr % 2) + 54) + >> 16) & 0xff, + (unsigned char) ((hr * wr * 3 + 3 * hr * (wr % 2) + 54) + >> 24) & 0xff); + fprintf(f, "%c%c%c%c", (0) & 0xff, ((0) >> 8) & 0xff, + ((0) >> 16) & 0xff, ((0) >> 24) & 0xff); + fprintf(f, "%c%c%c%c", (54) & 0xff, ((54) >> 8) & 0xff, + ((54) >> 16) & 0xff, ((54) >> 24) & 0xff); + + /* INFO HEADER */ + /* ------------- */ + fprintf(f, "%c%c%c%c", (40) & 0xff, ((40) >> 8) & 0xff, + ((40) >> 16) & 0xff, ((40) >> 24) & 0xff); + fprintf(f, "%c%c%c%c", (unsigned char) ((wr) & 0xff), + (unsigned char) ((wr) >> 8) & 0xff, + (unsigned char) ((wr) >> 16) & 0xff, + (unsigned char) ((wr) >> 24) & 0xff); + fprintf(f, "%c%c%c%c", (unsigned char) ((hr) & 0xff), + (unsigned char) ((hr) >> 8) & 0xff, + (unsigned char) ((hr) >> 16) & 0xff, + (unsigned char) ((hr) >> 24) & 0xff); + fprintf(f, "%c%c", (1) & 0xff, ((1) >> 8) & 0xff); + fprintf(f, "%c%c", (24) & 0xff, ((24) >> 8) & 0xff); + fprintf(f, "%c%c%c%c", (0) & 0xff, ((0) >> 8) & 0xff, + ((0) >> 16) & 0xff, ((0) >> 24) & 0xff); + fprintf(f, "%c%c%c%c", + (unsigned char) (3 * hr * wr + + 3 * hr * (wr % 2)) & 0xff, + (unsigned char) ((hr * wr * 3 + 3 * hr * (wr % 2)) >> + 8) & 0xff, + (unsigned char) ((hr * wr * 3 + 3 * hr * (wr % 2)) >> + 16) & 0xff, + (unsigned char) ((hr * wr * 3 + 3 * hr * (wr % 2)) >> + 24) & 0xff); + fprintf(f, "%c%c%c%c", (7834) & 0xff, ((7834) >> 8) & 0xff, + ((7834) >> 16) & 0xff, ((7834) >> 24) & 0xff); + fprintf(f, "%c%c%c%c", (7834) & 0xff, ((7834) >> 8) & 0xff, + ((7834) >> 16) & 0xff, ((7834) >> 24) & 0xff); + fprintf(f, "%c%c%c%c", (0) & 0xff, ((0) >> 8) & 0xff, + ((0) >> 16) & 0xff, ((0) >> 24) & 0xff); + fprintf(f, "%c%c%c%c", (0) & 0xff, ((0) >> 8) & 0xff, + ((0) >> 16) & 0xff, ((0) >> 24) & 0xff); + + for (i = 0; i < wr * hr; i++) { + unsigned char R, G, B; + /* a modifier */ + // R = img->comps[0].data[w * h - ((i) / (w) + 1) * w + (i) % (w)]; + R = img->comps[0].data[w * hr - ((i) / (wr) + 1) * w + (i) % (wr)]; + // G = img->comps[1].data[w * h - ((i) / (w) + 1) * w + (i) % (w)]; + G = img->comps[1].data[w * hr - ((i) / (wr) + 1) * w + (i) % (wr)]; + // B = img->comps[2].data[w * h - ((i) / (w) + 1) * w + (i) % (w)]; + B = img->comps[2].data[w * hr - ((i) / (wr) + 1) * w + (i) % (wr)]; + fprintf(f, "%c%c%c", B, G, R); + + if ((i + 1) % wr == 0) { + for (pad = (3 * wr) % 4 ? 4 - (3 * wr) % 4 : 0; pad > 0; pad--) /* ADD */ + fprintf(f, "%c", 0); + } + } + fclose(f); + } + return 0; +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_convert.h b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_convert.h new file mode 100644 index 0000000..78e6c47 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_convert.h @@ -0,0 +1,45 @@ +/* +* Copyright (c) 2003-2004, François-Olivier Devaux +* Copyright (c) 2002-2004, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "mj2.h" + +#ifndef __MJ2_CONVERT_H +#define __MJ2_CONVERT_H + +int imagetoyuv(opj_image_t * img, char *outfile); + +int imagetobmp(opj_image_t * img, char *outfile); + +opj_image_t *mj2_image_create(mj2_tk_t * tk, opj_cparameters_t *parameters); + +char yuvtoimage(mj2_tk_t * tk, opj_image_t * img, int frame_num, opj_cparameters_t *parameters, char* infile); + +int yuv_num_frames(mj2_tk_t * tk, char *infile); + + +#endif diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_frames.c b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_frames.c new file mode 100644 index 0000000..63869ea --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_frames.c @@ -0,0 +1,250 @@ +/* +* Copyright (c) 2003-2004, François-Olivier Devaux +* Copyright (c) 2002-2004, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include + +#include "opj_config.h" +#include "openjpeg.h" +#include "../libopenjpeg/j2k_lib.h" +#include "../libopenjpeg/j2k.h" +#include "../libopenjpeg/jp2.h" +#include "mj2.h" +#include "mj2_convert.h" + +#ifdef HAVE_LIBLCMS2 +#include +#endif +#ifdef HAVE_LIBLCMS1 +#include +#endif +#include "color.h" +/* -------------------------------------------------------------------------- */ + +/** +sample error callback expecting a FILE* client object +*/ +void error_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[ERROR] %s", msg); +} +/** +sample warning callback expecting a FILE* client object +*/ +void warning_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[WARNING] %s", msg); +} +/** +sample debug callback expecting a FILE* client object +*/ +void info_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[INFO] %s", msg); +} + +/* -------------------------------------------------------------------------- */ + + +int main(int argc, char *argv[]) { + mj2_dparameters_t mj2_parameters; /* decompression parameters */ + opj_dinfo_t* dinfo; + opj_event_mgr_t event_mgr; /* event manager */ + opj_cio_t *cio = NULL; + unsigned int tnum, snum; + opj_mj2_t *movie; + mj2_tk_t *track; + mj2_sample_t *sample; + unsigned char* frame_codestream; + FILE *file, *outfile; + char outfilename[50]; + opj_image_t *img = NULL; + unsigned int max_codstrm_size = 0; + double total_time = 0; + unsigned int numframes = 0; + + if (argc != 3) { + printf("Usage: %s inputfile.mj2 outputfile.yuv\n",argv[0]); + return 1; + } + + file = fopen(argv[1], "rb"); + + if (!file) { + fprintf(stderr, "failed to open %s for reading\n", argv[1]); + return 1; + } + + // Checking output file + outfile = fopen(argv[2], "w"); + if (!file) { + fprintf(stderr, "failed to open %s for writing\n", argv[2]); + return 1; + } + fclose(outfile); + + /* + configure the event callbacks (not required) + setting of each callback is optionnal + */ + memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); + event_mgr.error_handler = error_callback; + event_mgr.warning_handler = warning_callback; + event_mgr.info_handler = NULL; + + /* get a MJ2 decompressor handle */ + dinfo = mj2_create_decompress(); + movie = (opj_mj2_t*)dinfo->mj2_handle; + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr); + + /* set J2K decoding parameters to default values */ + opj_set_default_decoder_parameters(&mj2_parameters.j2k_parameters); + + /* setup the decoder decoding parameters using user parameters */ + mj2_setup_decoder((opj_mj2_t*)dinfo->mj2_handle, &mj2_parameters); + + if (mj2_read_struct(file, movie)) // Creating the movie structure + return 1; + + // Decode first video track + for (tnum=0; tnum < (unsigned int)(movie->num_htk + movie->num_stk + movie->num_vtk); tnum++) { + if (movie->tk[tnum].track_type == 0) + break; + } + + if (movie->tk[tnum].track_type != 0) { + printf("Error. Movie does not contain any video track\n"); + return 1; + } + + track = &movie->tk[tnum]; + + // Output info on first video tracl + fprintf(stdout,"The first video track contains %d frames.\nWidth: %d, Height: %d \n\n", + track->num_samples, track->w, track->h); + + max_codstrm_size = track->sample[0].sample_size-8; + frame_codestream = (unsigned char*) malloc(max_codstrm_size * sizeof(unsigned char)); + + numframes = track->num_samples; + + for (snum=0; snum < numframes; snum++) + { + double init_time = opj_clock(); + double elapsed_time; + + sample = &track->sample[snum]; + if (sample->sample_size-8 > max_codstrm_size) { + max_codstrm_size = sample->sample_size-8; + if ((frame_codestream = (unsigned char*) + realloc(frame_codestream, max_codstrm_size)) == NULL) { + printf("Error reallocation memory\n"); + return 1; + }; + } + fseek(file,sample->offset+8,SEEK_SET); + fread(frame_codestream, sample->sample_size-8, 1, file); // Assuming that jp and ftyp markers size do + + /* open a byte stream */ + cio = opj_cio_open((opj_common_ptr)dinfo, frame_codestream, sample->sample_size-8); + + img = opj_decode(dinfo, cio); // Decode J2K to image + +#ifdef WANT_SYCC_TO_RGB + if(img->color_space == CLRSPC_SYCC) + { + color_sycc_to_rgb(img); + } +#endif + + if(img->icc_profile_buf) + { +#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + color_apply_icc_profile(img); +#endif + + free(img->icc_profile_buf); + img->icc_profile_buf = NULL; img->icc_profile_len = 0; + } + + if (((img->numcomps == 3) && (img->comps[0].dx == img->comps[1].dx / 2) + && (img->comps[0].dx == img->comps[2].dx / 2 ) && (img->comps[0].dx == 1)) + || (img->numcomps == 1)) { + + if (!imagetoyuv(img, argv[2])) // Convert image to YUV + return 1; + } + else if ((img->numcomps == 3) && + (img->comps[0].dx == 1) && (img->comps[1].dx == 1)&& + (img->comps[2].dx == 1))// If YUV 4:4:4 input --> to bmp + { + fprintf(stdout,"The frames will be output in a bmp format (output_1.bmp, ...)\n"); + sprintf(outfilename,"output_%d.bmp",snum); + if (imagetobmp(img, outfilename)) // Convert image to BMP + return 1; + + } + else { + fprintf(stdout,"Image component dimensions are unknown. Unable to output image\n"); + fprintf(stdout,"The frames will be output in a j2k file (output_1.j2k, ...)\n"); + + sprintf(outfilename,"output_%d.j2k",snum); + outfile = fopen(outfilename, "wb"); + if (!outfile) { + fprintf(stderr, "failed to open %s for writing\n",outfilename); + return 1; + } + fwrite(frame_codestream,sample->sample_size-8,1,outfile); + fclose(outfile); + } + /* close the byte stream */ + opj_cio_close(cio); + /* free image data structure */ + opj_image_destroy(img); + elapsed_time = opj_clock()-init_time; + fprintf(stderr, "Frame number %d/%d decoded in %.2f mseconds\n", snum + 1, numframes, elapsed_time*1000); + total_time += elapsed_time; + + } + + free(frame_codestream); + fclose(file); + + /* free remaining structures */ + if(dinfo) { + mj2_destroy_decompress((opj_mj2_t*)dinfo->mj2_handle); + } + free(dinfo); + + fprintf(stdout, "%d frame(s) correctly decompressed\n", snum); + fprintf(stdout,"Total decoding time: %.2f seconds (%.1f fps)\n", total_time, (float)numframes/total_time); + + return 0; +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_frames.dsp b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_frames.dsp new file mode 100644 index 0000000..7c9d6bc --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_frames.dsp @@ -0,0 +1,159 @@ +# Microsoft Developer Studio Project File - Name="mj2_to_frames" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=mj2_to_frames - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "mj2_to_frames.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "mj2_to_frames.mak" CFG="mj2_to_frames - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "mj2_to_frames - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "mj2_to_frames - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "mj2_to_frames - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "../libopenjpeg" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "OPJ_STATIC" /FR /YX /FD /c +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "mj2_to_frames - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "mj2_to_frames___Win32_Debug0" +# PROP BASE Intermediate_Dir "mj2_to_frames___Win32_Debug0" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "mj2_to_frames___Win32_Debug0" +# PROP Intermediate_Dir "mj2_to_frames___Win32_Debug0" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MT /W3 /Gm /GX /ZI /Od /I "../libopenjpeg" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "OPJ_STATIC" /FR /YX /FD /GZ /c +# SUBTRACT CPP /X +# ADD BASE RSC /l 0x809 /d "_DEBUG" +# ADD RSC /l 0x809 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /nodefaultlib:"libcmtd" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "mj2_to_frames - Win32 Release" +# Name "mj2_to_frames - Win32 Debug" +# Begin Group "MJ2" + +# PROP Default_Filter "" +# Begin Group "MJ2 Header Files" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\compat\getopt.h +# End Source File +# Begin Source File + +SOURCE=.\mj2.h +# End Source File +# Begin Source File + +SOURCE=.\mj2_convert.h +# End Source File +# End Group +# Begin Group "MJ2 Source Files" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\compat\getopt.c + +!IF "$(CFG)" == "mj2_to_frames - Win32 Release" + +!ELSEIF "$(CFG)" == "mj2_to_frames - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\mj2.c + +!IF "$(CFG)" == "mj2_to_frames - Win32 Release" + +!ELSEIF "$(CFG)" == "mj2_to_frames - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\mj2_convert.c + +!IF "$(CFG)" == "mj2_to_frames - Win32 Release" + +!ELSEIF "$(CFG)" == "mj2_to_frames - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\mj2_to_frames.c + +!IF "$(CFG)" == "mj2_to_frames - Win32 Release" + +!ELSEIF "$(CFG)" == "mj2_to_frames - Win32 Debug" + +!ENDIF + +# End Source File +# End Group +# End Group +# Begin Group "OpenJPEG Headers" + +# PROP Default_Filter "" +# End Group +# End Target +# End Project diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_frames.dsw b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_frames.dsw new file mode 100644 index 0000000..c424418 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_frames.dsw @@ -0,0 +1,44 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "LibOpenJPEG"="..\LibOpenJPEG.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "mj2_to_frames"=".\mj2_to_frames.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name LibOpenJPEG + End Project Dependency +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_frames.sln b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_frames.sln new file mode 100644 index 0000000..9f1977f --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_frames.sln @@ -0,0 +1,29 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mj2_to_frames", "mj2_to_frames.vcproj", "{64325EAD-A083-4C8E-B852-71006428881D}" + ProjectSection(ProjectDependencies) = postProject + {4F27AA53-4181-4A1A-8238-3931B0A41048} = {4F27AA53-4181-4A1A-8238-3931B0A41048} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LibOpenJPEG", "..\LibOpenJPEG.vcproj", "{4F27AA53-4181-4A1A-8238-3931B0A41048}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {64325EAD-A083-4C8E-B852-71006428881D}.Debug|Win32.ActiveCfg = Debug|Win32 + {64325EAD-A083-4C8E-B852-71006428881D}.Debug|Win32.Build.0 = Debug|Win32 + {64325EAD-A083-4C8E-B852-71006428881D}.Release|Win32.ActiveCfg = Release|Win32 + {64325EAD-A083-4C8E-B852-71006428881D}.Release|Win32.Build.0 = Release|Win32 + {4F27AA53-4181-4A1A-8238-3931B0A41048}.Debug|Win32.ActiveCfg = Debug|Win32 + {4F27AA53-4181-4A1A-8238-3931B0A41048}.Debug|Win32.Build.0 = Debug|Win32 + {4F27AA53-4181-4A1A-8238-3931B0A41048}.Release|Win32.ActiveCfg = Release|Win32 + {4F27AA53-4181-4A1A-8238-3931B0A41048}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_frames.vcproj b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_frames.vcproj new file mode 100644 index 0000000..2f83041 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_frames.vcproj @@ -0,0 +1,324 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_metadata.c b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_metadata.c new file mode 100644 index 0000000..90be620 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_metadata.c @@ -0,0 +1,312 @@ +/* mj2_to_metadata.c */ +/* Dump MJ2, JP2 metadata (partial so far) to xml file */ +/* Contributed to Open JPEG by Glenn Pearson, contract software developer, U.S. National Library of Medicine. + +The base code in this file was developed by the author as part of a video archiving +project for the U.S. National Library of Medicine, Bethesda, MD. +It is the policy of NLM (and U.S. government) to not assert copyright. + +A non-exclusive copy of this code has been contributed to the Open JPEG project. +Except for copyright, inclusion of the code within Open JPEG for distribution and use +can be bound by the Open JPEG open-source license and disclaimer, expressed elsewhere. +*/ + +#include "../libopenjpeg/opj_includes.h" +#include "mj2.h" + +#include "mj2_to_metadata.h" +#include +#include "getopt.h" + +/* -------------------------------------------------------------------------- */ + +/** +sample error callback expecting a FILE* client object +*/ +void error_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[ERROR] %s", msg); +} +/** +sample warning callback expecting a FILE* client object +*/ +void warning_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[WARNING] %s", msg); +} +/** +sample debug callback expecting a FILE* client object +*/ +void info_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[INFO] %s", msg); +} + +/* -------------------------------------------------------------------------- */ + + + +/* ------------- */ + +void help_display() +{ + /* "1234567890123456789012345678901234567890123456789012345678901234567890123456789" */ + fprintf(stdout," Help for the 'mj2_to_metadata' Program\n"); + fprintf(stdout," ======================================\n"); + fprintf(stdout,"The -h option displays this information on screen.\n\n"); + + fprintf(stdout,"mj2_to_metadata generates an XML file from a Motion JPEG 2000 file.\n"); + fprintf(stdout,"The generated XML shows the structural, but not (yet) curatorial,\n"); + fprintf(stdout,"metadata from the movie header and from the JPEG 2000 image and tile\n"); + fprintf(stdout,"headers of a sample frame. Excluded: low-level packed-bits image data.\n\n"); + + fprintf(stdout,"By Default\n"); + fprintf(stdout,"----------\n"); + fprintf(stdout,"The metadata includes the jp2 image and tile headers of the first frame.\n"); + fprintf(stdout,"\n"); + fprintf(stdout,"Metadata values are shown in 'raw' form (e.g., hexidecimal) as stored in the\n"); + fprintf(stdout,"file, and, if apt, in a 'derived' form that is more quickly grasped.\n"); + fprintf(stdout,"\n"); + fprintf(stdout,"Notes explaining the XML are embedded as terse comments. These include\n"); + fprintf(stdout," meaning of non-obvious tag abbreviations;\n"); + fprintf(stdout," range and precision of valid values;\n"); + fprintf(stdout," interpretations of values, such as enumerations; and\n"); + fprintf(stdout," current implementation limitations.\n"); + fprintf(stdout,"\n"); + fprintf(stdout,"The sample-size and chunk-offset tables, each with 1 row per frame, are not reported.\n"); + fprintf(stdout,"\n"); + fprintf(stdout,"The file is self-contained and no verification (e.g., against a DTD) is requested.\n"); + fprintf(stdout,"\n"); + fprintf(stdout,"Required Parameters (except with -h)\n"); + fprintf(stdout,"------------------------------------\n"); + fprintf(stdout,"[Caution: file strings that contain spaces should be wrapped with quotes.]\n"); + fprintf(stdout,"-i input.mj2 : where 'input' is any source file name or path.\n"); + fprintf(stdout," MJ2 files created with 'frames_to_mj2' are supported so far.\n"); + fprintf(stdout," These are silent, single-track, 'MJ2 Simple Profile' videos.\n"); + fprintf(stdout,"-o output.xml : where 'output' is any destination file name or path.\n"); + fprintf(stdout,"\n"); + fprintf(stdout,"Optional Parameters\n"); + fprintf(stdout,"-------------------\n"); + fprintf(stdout,"-h : Display this help information.\n"); + fprintf(stdout,"-n : Suppress all mj2_to_metadata notes.\n"); + fprintf(stdout,"-t : Include sample-size and chunk-offset tables.\n"); + fprintf(stdout,"-f n : where n > 0. Include jp2 header info for frame n [default=1].\n"); + fprintf(stdout,"-f 0 : No jp2 header info.\n"); + fprintf(stdout,"-r : Suppress all 'raw' data for which a 'derived' form exists.\n"); + fprintf(stdout,"-d : Suppress all 'derived' data.\n"); + fprintf(stdout," (If both -r and -d given, -r will be ignored.)\n"); + fprintf(stdout,"-v string : Verify against the DTD file located by the string.\n"); + fprintf(stdout," Prepend quoted 'string' with either SYSTEM or PUBLIC keyword.\n"); + fprintf(stdout," Thus, for the distributed DTD placed in the same directory as\n"); + fprintf(stdout," the output file: -v \"SYSTEM mj2_to_metadata.dtd\"\n"); + fprintf(stdout," \"PUBLIC\" is used with an access protocol (e.g., http:) + URL.\n"); + /* More to come */ + fprintf(stdout,"\n"); + /* "1234567890123456789012345678901234567890123456789012345678901234567890123456789" */ +} + +/* ------------- */ + +int main(int argc, char *argv[]) { + + opj_dinfo_t* dinfo; + opj_event_mgr_t event_mgr; /* event manager */ + + FILE *file, *xmlout; +/* char xmloutname[50]; */ + opj_mj2_t *movie; + + char* infile = 0; + char* outfile = 0; + char* s, S1, S2, S3; + int len; + unsigned int sampleframe = 1; /* First frame */ + char* stringDTD = NULL; + BOOL notes = TRUE; + BOOL sampletables = FALSE; + BOOL raw = TRUE; + BOOL derived = TRUE; + mj2_dparameters_t parameters; + + while (TRUE) { + /* ':' after letter means it takes an argument */ + int c = getopt(argc, argv, "i:o:f:v:hntrd"); + /* FUTURE: Reserve 'p' for pruning file (which will probably make -t redundant) */ + if (c == -1) + break; + switch (c) { + case 'i': /* IN file */ + infile = optarg; + s = optarg; + while (*s) { s++; } /* Run to filename end */ + s--; + S3 = *s; + s--; + S2 = *s; + s--; + S1 = *s; + + if ((S1 == 'm' && S2 == 'j' && S3 == '2') + || (S1 == 'M' && S2 == 'J' && S3 == '2')) { + break; + } + fprintf(stderr, "Input file name must have .mj2 extension, not .%c%c%c.\n", S1, S2, S3); + return 1; + + /* ----------------------------------------------------- */ + case 'o': /* OUT file */ + outfile = optarg; + while (*outfile) { outfile++; } /* Run to filename end */ + outfile--; + S3 = *outfile; + outfile--; + S2 = *outfile; + outfile--; + S1 = *outfile; + + outfile = optarg; + + if ((S1 == 'x' && S2 == 'm' && S3 == 'l') + || (S1 == 'X' && S2 == 'M' && S3 == 'L')) + break; + + fprintf(stderr, + "Output file name must have .xml extension, not .%c%c%c\n", S1, S2, S3); + return 1; + + /* ----------------------------------------------------- */ + case 'f': /* Choose sample frame. 0 = none */ + sscanf(optarg, "%u", &sampleframe); + break; + + /* ----------------------------------------------------- */ + case 'v': /* Verification by DTD. */ + stringDTD = optarg; + /* We will not insist upon last 3 chars being "dtd", since non-file + access protocol may be used. */ + if(strchr(stringDTD,'"') != NULL) { + fprintf(stderr, "-D's string must not contain any embedded double-quote characters.\n"); + return 1; + } + + if (strncmp(stringDTD,"PUBLIC ",7) == 0 || strncmp(stringDTD,"SYSTEM ",7) == 0) + break; + + fprintf(stderr, "-D's string must start with \"PUBLIC \" or \"SYSTEM \"\n"); + return 1; + + /* ----------------------------------------------------- */ + case 'n': /* Suppress comments */ + notes = FALSE; + break; + + /* ----------------------------------------------------- */ + case 't': /* Show sample size and chunk offset tables */ + sampletables = TRUE; + break; + + /* ----------------------------------------------------- */ + case 'h': /* Display an help description */ + help_display(); + return 0; + + /* ----------------------------------------------------- */ + case 'r': /* Suppress raw data */ + raw = FALSE; + break; + + /* ----------------------------------------------------- */ + case 'd': /* Suppress derived data */ + derived = FALSE; + break; + + /* ----------------------------------------------------- */ + default: + return 1; + } /* switch */ + } /* while */ + + if(!raw && !derived) + raw = TRUE; /* At least one of 'raw' and 'derived' must be true */ + + /* Error messages */ + /* -------------- */ + if (!infile || !outfile) { + fprintf(stderr,"Correct usage: mj2_to_metadata -i mj2-file -o xml-file (plus options)\n"); + return 1; + } + +/* was: + if (argc != 3) { + printf("Bad syntax: Usage: MJ2_to_metadata inputfile.mj2 outputfile.xml\n"); + printf("Example: MJ2_to_metadata foreman.mj2 foreman.xml\n"); + return 1; + } +*/ + len = strlen(infile); + if(infile[0] == ' ') + { + infile++; /* There may be a leading blank if user put space after -i */ + } + + file = fopen(infile, "rb"); /* was: argv[1] */ + + if (!file) { + fprintf(stderr, "Failed to open %s for reading.\n", infile); /* was: argv[1] */ + return 1; + } + + len = strlen(outfile); + if(outfile[0] == ' ') + { + outfile++; /* There may be a leading blank if user put space after -o */ + } + + // Checking output file + xmlout = fopen(outfile, "w"); /* was: argv[2] */ + if (!xmlout) { + fprintf(stderr, "Failed to open %s for writing.\n", outfile); /* was: argv[2] */ + return 1; + } + // Leave it open + + /* + configure the event callbacks (not required) + setting of each callback is optionnal + */ + memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); + event_mgr.error_handler = error_callback; + event_mgr.warning_handler = warning_callback; + event_mgr.info_handler = info_callback; + + /* get a MJ2 decompressor handle */ + dinfo = mj2_create_decompress(); + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr); + + /* setup the decoder decoding parameters using user parameters */ + movie = (opj_mj2_t*) dinfo->mj2_handle; + mj2_setup_decoder(dinfo->mj2_handle, ¶meters); + + if (mj2_read_struct(file, movie)) // Creating the movie structure + { + fclose(xmlout); + return 1; + } + + xml_write_init(notes, sampletables, raw, derived); + xml_write_struct(file, xmlout, movie, sampleframe, stringDTD, &event_mgr); + fclose(xmlout); + + fprintf(stderr,"Metadata correctly extracted to XML file \n");; + + /* free remaining structures */ + if(dinfo) { + mj2_destroy_decompress((opj_mj2_t*)dinfo->mj2_handle); + } + + return 0; +} + + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_metadata.dsp b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_metadata.dsp new file mode 100644 index 0000000..f1e7af2 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_metadata.dsp @@ -0,0 +1,140 @@ +# Microsoft Developer Studio Project File - Name="mj2_to_metadata" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=mj2_to_metadata - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "mj2_to_metadata.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "mj2_to_metadata.mak" CFG="mj2_to_metadata - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "mj2_to_metadata - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "mj2_to_metadata - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "mj2_to_metadata - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "../libopenjpeg" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "OPJ_STATIC" /YX /FD /c +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /nodefaultlib:"libcmtd" +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "mj2_to_metadata - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "mj2_to_metadata___Win32_Debug0" +# PROP BASE Intermediate_Dir "mj2_to_metadata___Win32_Debug0" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "mj2_to_metadata___Win32_Debug0" +# PROP Intermediate_Dir "mj2_to_metadata___Win32_Debug0" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "../libopenjpeg" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "OPJ_STATIC" /FR /YX /FD /GZ /c +# ADD BASE RSC /l 0x809 /d "_DEBUG" +# ADD RSC /l 0x809 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /nodefaultlib:"libcmtd" /pdbtype:sept +# SUBTRACT LINK32 /pdb:none + +!ENDIF + +# Begin Target + +# Name "mj2_to_metadata - Win32 Release" +# Name "mj2_to_metadata - Win32 Debug" +# Begin Group "MJ2" + +# PROP Default_Filter "" +# Begin Group "MJ2 Header Files" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\compat\getopt.h +# End Source File +# Begin Source File + +SOURCE=.\meta_out.h +# End Source File +# Begin Source File + +SOURCE=.\mj2.h +# End Source File +# Begin Source File + +SOURCE=.\mj2_convert.h +# End Source File +# Begin Source File + +SOURCE=.\mj2_to_metadata.h +# End Source File +# End Group +# Begin Group "MJ2 Source Files" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\compat\getopt.c +# End Source File +# Begin Source File + +SOURCE=.\meta_out.c +# End Source File +# Begin Source File + +SOURCE=.\mj2.c +# End Source File +# Begin Source File + +SOURCE=.\mj2_convert.c +# End Source File +# Begin Source File + +SOURCE=.\mj2_to_metadata.c +# End Source File +# End Group +# End Group +# End Target +# End Project diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_metadata.dsw b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_metadata.dsw new file mode 100644 index 0000000..8a2a230 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_metadata.dsw @@ -0,0 +1,44 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "LibOpenJPEG"="..\LibOpenJPEG.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "mj2_to_metadata"=".\mj2_to_metadata.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name LibOpenJPEG + End Project Dependency +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_metadata.dtd b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_metadata.dtd new file mode 100644 index 0000000..249de1a --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_metadata.dtd @@ -0,0 +1,425 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_metadata.h b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_metadata.h new file mode 100644 index 0000000..f4c3491 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_metadata.h @@ -0,0 +1,9 @@ +/* mj2_to_metadata.h */ +/* Dump MJ2, JP2 metadata (partial so far) to xml file */ +/* Contributed to Open JPEG by Glenn Pearson, U.S. National Library of Medicine */ + +#define BOOL int +#define FALSE 0 +#define TRUE 1 + +#include "meta_out.h" diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_metadata.sln b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_metadata.sln new file mode 100644 index 0000000..f579c53 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_metadata.sln @@ -0,0 +1,29 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mj2_to_metadata", "mj2_to_metadata.vcproj", "{69BE42AB-E7CE-4DA1-BBD2-39FEA2C91E0B}" + ProjectSection(ProjectDependencies) = postProject + {0B1B7713-35B6-40A7-9BFF-A7D0EB06A8BD} = {0B1B7713-35B6-40A7-9BFF-A7D0EB06A8BD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LibOpenJPEG", "..\LibOpenJPEG.vcproj", "{0B1B7713-35B6-40A7-9BFF-A7D0EB06A8BD}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {69BE42AB-E7CE-4DA1-BBD2-39FEA2C91E0B}.Debug|Win32.ActiveCfg = Debug|Win32 + {69BE42AB-E7CE-4DA1-BBD2-39FEA2C91E0B}.Debug|Win32.Build.0 = Debug|Win32 + {69BE42AB-E7CE-4DA1-BBD2-39FEA2C91E0B}.Release|Win32.ActiveCfg = Release|Win32 + {69BE42AB-E7CE-4DA1-BBD2-39FEA2C91E0B}.Release|Win32.Build.0 = Release|Win32 + {0B1B7713-35B6-40A7-9BFF-A7D0EB06A8BD}.Debug|Win32.ActiveCfg = Debug|Win32 + {0B1B7713-35B6-40A7-9BFF-A7D0EB06A8BD}.Debug|Win32.Build.0 = Debug|Win32 + {0B1B7713-35B6-40A7-9BFF-A7D0EB06A8BD}.Release|Win32.ActiveCfg = Release|Win32 + {0B1B7713-35B6-40A7-9BFF-A7D0EB06A8BD}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_metadata.vcproj b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_metadata.vcproj new file mode 100644 index 0000000..1ab1354 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_metadata.vcproj @@ -0,0 +1,349 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_metadata_Notes.doc b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/mj2_to_metadata_Notes.doc new file mode 100644 index 0000000000000000000000000000000000000000..05ccec2068dd5bff73cf83aab716406f6c1db099 GIT binary patch literal 35328 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 literal 0 HcmV?d00001 diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/mj2/readme.txt b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/readme.txt new file mode 100644 index 0000000..9419d2a --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/readme.txt @@ -0,0 +1,3 @@ +Attention : the motion jpeg 2000 files currently only work with OpenJPEG v0.97 that you can find here : + +http://www.openjpeg.org/openjpeg_v097.tar.gz \ No newline at end of file diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/mj2/wrap_j2k_in_mj2.c b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/wrap_j2k_in_mj2.c new file mode 100644 index 0000000..77b4959 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/mj2/wrap_j2k_in_mj2.c @@ -0,0 +1,371 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2003-2007, Francois-Olivier Devaux + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + +#include "openjpeg.h" +#include "../libopenjpeg/j2k.h" +#include "../libopenjpeg/jp2.h" +#include "../libopenjpeg/cio.h" +#include "mj2.h" + +static int int_ceildiv(int a, int b) { + return (a + b - 1) / b; +} + +/** +Size of memory first allocated for MOOV box +*/ +#define TEMP_BUF 10000 + + +/* -------------------------------------------------------------------------- */ + +/** +sample error callback expecting a FILE* client object +*/ +void error_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[ERROR] %s", msg); +} +/** +sample warning callback expecting a FILE* client object +*/ +void warning_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[WARNING] %s", msg); +} +/** +sample debug callback expecting a FILE* client object +*/ +void info_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[INFO] %s", msg); +} + +/* -------------------------------------------------------------------------- */ + + + +static void read_siz_marker(FILE *file, opj_image_t *image) +{ + int len,i; + char buf, buf2[2]; + unsigned char *siz_buffer; + opj_cio_t *cio; + + fseek(file, 0, SEEK_SET); + do { + fread(&buf,1,1, file); + if (buf==(char)0xff) + fread(&buf,1,1, file); + } + while (!(buf==(char)0x51)); + + fread(buf2,2,1,file); /* Lsiz */ + len = ((buf2[0])<<8) + buf2[1]; + + siz_buffer = (unsigned char*) malloc(len * sizeof(unsigned char)); + fread(siz_buffer,len, 1, file); + cio = opj_cio_open(NULL, siz_buffer, len); + + cio_read(cio, 2); /* Rsiz (capabilities) */ + image->x1 = cio_read(cio, 4); /* Xsiz */ + image->y1 = cio_read(cio, 4); /* Ysiz */ + image->x0 = cio_read(cio, 4); /* X0siz */ + image->y0 = cio_read(cio, 4); /* Y0siz */ + cio_skip(cio, 16); /* XTsiz, YTsiz, XT0siz, YT0siz */ + + image->numcomps = cio_read(cio,2); /* Csiz */ + image->comps = + (opj_image_comp_t *) malloc(image->numcomps * sizeof(opj_image_comp_t)); + + for (i = 0; i < image->numcomps; i++) { + int tmp; + tmp = cio_read(cio,1); /* Ssiz_i */ + image->comps[i].prec = (tmp & 0x7f) + 1; + image->comps[i].sgnd = tmp >> 7; + image->comps[i].dx = cio_read(cio,1); /* XRsiz_i */ + image->comps[i].dy = cio_read(cio,1); /* YRsiz_i */ + image->comps[i].resno_decoded = 0; /* number of resolution decoded */ + image->comps[i].factor = 0; /* reducing factor by component */ + } + fseek(file, 0, SEEK_SET); + opj_cio_close(cio); + free(siz_buffer); +} + +static void setparams(opj_mj2_t *movie, opj_image_t *image) { + int i, depth_0, depth, sign; + + movie->tk[0].sample_rate = 25; + movie->tk[0].w = int_ceildiv(image->x1 - image->x0, image->comps[0].dx); + movie->tk[0].h = int_ceildiv(image->y1 - image->y0, image->comps[0].dy); + mj2_init_stdmovie(movie); + + movie->tk[0].depth = image->comps[0].prec; + + if (image->numcomps==3) { + if ((image->comps[0].dx == 1) + && (image->comps[1].dx == 1) + && (image->comps[2].dx == 1)) + movie->tk[0].CbCr_subsampling_dx = 1; + else + if ((image->comps[0].dx == 1) + && (image->comps[1].dx == 2) + && (image->comps[2].dx == 2)) + movie->tk[0].CbCr_subsampling_dx = 2; + else + fprintf(stderr,"Image component sizes are incoherent\n"); + + if ((image->comps[0].dy == 1) + && (image->comps[1].dy == 1) + && (image->comps[2].dy == 1)) + movie->tk[0].CbCr_subsampling_dy = 1; + else + if ((image->comps[0].dy == 1) + && (image->comps[1].dy == 2) + && (image->comps[2].dy == 2)) + movie->tk[0].CbCr_subsampling_dy = 2; + else + fprintf(stderr,"Image component sizes are incoherent\n"); + } + + movie->tk[0].sample_rate = 25; + + movie->tk[0].jp2_struct.numcomps = image->numcomps; // NC + + /* Init Standard jp2 structure */ + + movie->tk[0].jp2_struct.comps = + (opj_jp2_comps_t *) malloc(movie->tk[0].jp2_struct.numcomps * sizeof(opj_jp2_comps_t)); + movie->tk[0].jp2_struct.precedence = 0; /* PRECEDENCE*/ + movie->tk[0].jp2_struct.approx = 0; /* APPROX*/ + movie->tk[0].jp2_struct.brand = JP2_JP2; /* BR */ + movie->tk[0].jp2_struct.minversion = 0; /* MinV */ + movie->tk[0].jp2_struct.numcl = 1; + movie->tk[0].jp2_struct.cl = (unsigned int *) malloc(movie->tk[0].jp2_struct.numcl * sizeof(int)); + movie->tk[0].jp2_struct.cl[0] = JP2_JP2; /* CL0 : JP2 */ + movie->tk[0].jp2_struct.C = 7; /* C : Always 7*/ + movie->tk[0].jp2_struct.UnkC = 0; /* UnkC, colorspace specified in colr box*/ + movie->tk[0].jp2_struct.IPR = 0; /* IPR, no intellectual property*/ + movie->tk[0].jp2_struct.w = int_ceildiv(image->x1 - image->x0, image->comps[0].dx); + movie->tk[0].jp2_struct.h = int_ceildiv(image->y1 - image->y0, image->comps[0].dy); + + depth_0 = image->comps[0].prec - 1; + sign = image->comps[0].sgnd; + movie->tk[0].jp2_struct.bpc = depth_0 + (sign << 7); + + for (i = 1; i < image->numcomps; i++) { + depth = image->comps[i].prec - 1; + sign = image->comps[i].sgnd; + if (depth_0 != depth) + movie->tk[0].jp2_struct.bpc = 255; + } + + for (i = 0; i < image->numcomps; i++) + movie->tk[0].jp2_struct.comps[i].bpcc = + image->comps[i].prec - 1 + (image->comps[i].sgnd << 7); + + if ((image->numcomps == 1 || image->numcomps == 3) + && (movie->tk[0].jp2_struct.bpc != 255)) + movie->tk[0].jp2_struct.meth = 1; + else + movie->tk[0].jp2_struct.meth = 2; + + if (image->numcomps == 1) + movie->tk[0].jp2_struct.enumcs = 17; // Grayscale + + else + if ((image->comps[0].dx == 1) + && (image->comps[1].dx == 1) + && (image->comps[2].dx == 1) + && (image->comps[0].dy == 1) + && (image->comps[1].dy == 1) + && (image->comps[2].dy == 1)) + movie->tk[0].jp2_struct.enumcs = 16; // RGB + + else + if ((image->comps[0].dx == 1) + && (image->comps[1].dx == 2) + && (image->comps[2].dx == 2) + && (image->comps[0].dy == 1) + && (image->comps[1].dy == 2) + && (image->comps[2].dy == 2)) + movie->tk[0].jp2_struct.enumcs = 18; // YUV + + else + movie->tk[0].jp2_struct.enumcs = 0; // Unkown profile */ +} + +int main(int argc, char *argv[]) { + opj_cinfo_t* cinfo; + opj_event_mgr_t event_mgr; /* event manager */ + unsigned int snum; + opj_mj2_t *movie; + mj2_sample_t *sample; + unsigned char* frame_codestream; + FILE *mj2file, *j2kfile; + char j2kfilename[50]; + unsigned char *buf; + int offset, mdat_initpos; + opj_image_t img; + opj_cio_t *cio; + mj2_cparameters_t parameters; + + if (argc != 3) { + printf("Usage: %s source_location mj2_filename\n",argv[0]); + printf("Example: %s input/input output.mj2\n",argv[0]); + return 1; + } + + mj2file = fopen(argv[2], "wb"); + + if (!mj2file) { + fprintf(stderr, "failed to open %s for writing\n", argv[2]); + return 1; + } + + /* + configure the event callbacks (not required) + setting of each callback is optionnal + */ + memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); + event_mgr.error_handler = error_callback; + event_mgr.warning_handler = warning_callback; + event_mgr.info_handler = info_callback; + + /* get a MJ2 decompressor handle */ + cinfo = mj2_create_compress(); + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)cinfo, &event_mgr, stderr); + + /* setup the decoder encoding parameters using user parameters */ + movie = (opj_mj2_t*) cinfo->mj2_handle; + mj2_setup_encoder((opj_mj2_t*)cinfo->mj2_handle, ¶meters); + + + /* Writing JP, FTYP and MDAT boxes + Assuming that the JP and FTYP boxes won't be longer than 300 bytes */ + + buf = (unsigned char*) malloc (300 * sizeof(unsigned char)); + cio = opj_cio_open(movie->cinfo, buf, 300); + mj2_write_jp(cio); + mj2_write_ftyp(movie, cio); + mdat_initpos = cio_tell(cio); + cio_skip(cio, 4); + cio_write(cio,MJ2_MDAT, 4); + fwrite(buf,cio_tell(cio),1,mj2file); + free(buf); + + // Insert each j2k codestream in a JP2C box + snum=0; + offset = 0; + while(1) + { + sample = &movie->tk[0].sample[snum]; + sprintf(j2kfilename,"%s_%05d.j2k",argv[1],snum); + j2kfile = fopen(j2kfilename, "rb"); + if (!j2kfile) { + if (snum==0) { // Could not open a single codestream + fprintf(stderr, "failed to open %s for reading\n",j2kfilename); + return 1; + } + else { // Tried to open a inexistant codestream + fprintf(stdout,"%d frames are being added to the MJ2 file\n",snum); + break; + } + } + + // Calculating offset for samples and chunks + offset += cio_tell(cio); + sample->offset = offset; + movie->tk[0].chunk[snum].offset = offset; // There will be one sample per chunk + + // Calculating sample size + fseek(j2kfile,0,SEEK_END); + sample->sample_size = ftell(j2kfile) + 8; // Sample size is codestream + JP2C box header + fseek(j2kfile,0,SEEK_SET); + + // Reading siz marker of j2k image for the first codestream + if (snum==0) + read_siz_marker(j2kfile, &img); + + // Writing JP2C box header + frame_codestream = (unsigned char*) malloc (sample->sample_size+8); + cio = opj_cio_open(movie->cinfo, frame_codestream, sample->sample_size); + cio_write(cio,sample->sample_size, 4); // Sample size + cio_write(cio,JP2_JP2C, 4); // JP2C + + // Writing codestream from J2K file to MJ2 file + fread(frame_codestream+8,sample->sample_size-8,1,j2kfile); + fwrite(frame_codestream,sample->sample_size,1,mj2file); + cio_skip(cio, sample->sample_size-8); + + // Ending loop + fclose(j2kfile); + snum++; + movie->tk[0].sample = (mj2_sample_t*) + realloc(movie->tk[0].sample, (snum+1) * sizeof(mj2_sample_t)); + movie->tk[0].chunk = (mj2_chunk_t*) + realloc(movie->tk[0].chunk, (snum+1) * sizeof(mj2_chunk_t)); + free(frame_codestream); + } + + // Writing the MDAT box length in header + offset += cio_tell(cio); + buf = (unsigned char*) malloc (4 * sizeof(unsigned char)); + cio = opj_cio_open(movie->cinfo, buf, 4); + cio_write(cio,offset-mdat_initpos,4); + fseek(mj2file,(long)mdat_initpos,SEEK_SET); + fwrite(buf,4,1,mj2file); + fseek(mj2file,0,SEEK_END); + free(buf); + + // Setting movie parameters + movie->tk[0].num_samples=snum; + movie->tk[0].num_chunks=snum; + setparams(movie, &img); + + // Writing MOOV box + buf = (unsigned char*) malloc ((TEMP_BUF+snum*20) * sizeof(unsigned char)); + cio = opj_cio_open(movie->cinfo, buf, (TEMP_BUF+snum*20)); + mj2_write_moov(movie, cio); + fwrite(buf,cio_tell(cio),1,mj2file); + + // Ending program + fclose(mj2file); + free(img.comps); + opj_cio_close(cio); + mj2_destroy_compress(movie); + + return 0; +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/openjpeg_mangle.h.in b/gdcm/Utilities/gdcmopenjpeg-v1/openjpeg_mangle.h.in new file mode 100644 index 0000000..c3e4044 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/openjpeg_mangle.h.in @@ -0,0 +1,151 @@ +/* This file was generated by CMake http://www.cmake.org */ + +#ifndef @MANGLE_PREFIX@_mangle_h +#define @MANGLE_PREFIX@_mangle_h + +/* + * This header file mangles all symbols exported from the openjpeg library. + * It is included in all files while building the openjpeg library. Due to + * namespace pollution, no openjpeg headers should be included in .h files in + * GDCM. + * + * The following command was used to obtain the symbol list: + * + * nm lib@MANGLE_PREFIX@.a | grep " [RT] " + */ + +#define bio_create @MANGLE_PREFIX@_bio_create +#define bio_destroy @MANGLE_PREFIX@_bio_destroy +#define bio_flush @MANGLE_PREFIX@_bio_flush +#define bio_inalign @MANGLE_PREFIX@_bio_inalign +#define bio_init_dec @MANGLE_PREFIX@_bio_init_dec +#define bio_init_enc @MANGLE_PREFIX@_bio_init_enc +#define bio_numbytes @MANGLE_PREFIX@_bio_numbytes +#define bio_read @MANGLE_PREFIX@_bio_read +#define bio_write @MANGLE_PREFIX@_bio_write +#define cio_bytein @MANGLE_PREFIX@_cio_bytein +#define cio_byteout @MANGLE_PREFIX@_cio_byteout +#define cio_getbp @MANGLE_PREFIX@_cio_getbp +#define cio_numbytesleft @MANGLE_PREFIX@_cio_numbytesleft +#define cio_read @MANGLE_PREFIX@_cio_read +#define cio_seek @MANGLE_PREFIX@_cio_seek +#define cio_skip @MANGLE_PREFIX@_cio_skip +#define cio_tell @MANGLE_PREFIX@_cio_tell +#define cio_write @MANGLE_PREFIX@_cio_write +#define opj_cio_close @MANGLE_PREFIX@_opj_cio_close +#define opj_cio_open @MANGLE_PREFIX@_opj_cio_open +#define dwt_calc_explicit_stepsizes @MANGLE_PREFIX@_dwt_calc_explicit_stepsizes +#define dwt_decode @MANGLE_PREFIX@_dwt_decode +#define dwt_decode_real @MANGLE_PREFIX@_dwt_decode_real +#define dwt_encode @MANGLE_PREFIX@_dwt_encode +#define dwt_encode_real @MANGLE_PREFIX@_dwt_encode_real +#define dwt_getgain @MANGLE_PREFIX@_dwt_getgain +#define dwt_getgain_real @MANGLE_PREFIX@_dwt_getgain_real +#define dwt_getnorm @MANGLE_PREFIX@_dwt_getnorm +#define dwt_getnorm_real @MANGLE_PREFIX@_dwt_getnorm_real +#define opj_event_msg @MANGLE_PREFIX@_opj_event_msg +#define opj_set_event_mgr @MANGLE_PREFIX@_opj_set_event_mgr +#define opj_image_create @MANGLE_PREFIX@_opj_image_create +#define opj_image_create0 @MANGLE_PREFIX@_opj_image_create0 +#define opj_image_destroy @MANGLE_PREFIX@_opj_image_destroy +#define j2k_create_compress @MANGLE_PREFIX@_j2k_create_compress +#define j2k_create_decompress @MANGLE_PREFIX@_j2k_create_decompress +#define j2k_decode @MANGLE_PREFIX@_j2k_decode +#define j2k_decode_jpt_stream @MANGLE_PREFIX@_j2k_decode_jpt_stream +#define j2k_destroy_compress @MANGLE_PREFIX@_j2k_destroy_compress +#define j2k_destroy_decompress @MANGLE_PREFIX@_j2k_destroy_decompress +#define j2k_dump_cp @MANGLE_PREFIX@_j2k_dump_cp +#define j2k_dump_image @MANGLE_PREFIX@_j2k_dump_image +#define j2k_encode @MANGLE_PREFIX@_j2k_encode +#define j2k_setup_decoder @MANGLE_PREFIX@_j2k_setup_decoder +#define j2k_setup_encoder @MANGLE_PREFIX@_j2k_setup_encoder +#define opj_clock @MANGLE_PREFIX@_opj_clock +#define opj_free @MANGLE_PREFIX@_opj_free +#define opj_malloc @MANGLE_PREFIX@_opj_malloc +#define opj_realloc @MANGLE_PREFIX@_opj_realloc +#define jp2_create_compress @MANGLE_PREFIX@_jp2_create_compress +#define jp2_create_decompress @MANGLE_PREFIX@_jp2_create_decompress +#define jp2_decode @MANGLE_PREFIX@_jp2_decode +#define jp2_destroy_compress @MANGLE_PREFIX@_jp2_destroy_compress +#define jp2_destroy_decompress @MANGLE_PREFIX@_jp2_destroy_decompress +#define jp2_encode @MANGLE_PREFIX@_jp2_encode +#define jp2_setup_decoder @MANGLE_PREFIX@_jp2_setup_decoder +#define jp2_setup_encoder @MANGLE_PREFIX@_jp2_setup_encoder +#define jpt_init_msg_header @MANGLE_PREFIX@_jpt_init_msg_header +#define jpt_read_msg_header @MANGLE_PREFIX@_jpt_read_msg_header +#define jpt_read_VBAS_info @MANGLE_PREFIX@_jpt_read_VBAS_info +#define jpt_reinit_msg_header @MANGLE_PREFIX@_jpt_reinit_msg_header +#define mct_decode @MANGLE_PREFIX@_mct_decode +#define mct_decode_real @MANGLE_PREFIX@_mct_decode_real +#define mct_encode @MANGLE_PREFIX@_mct_encode +#define mct_encode_real @MANGLE_PREFIX@_mct_encode_real +#define mct_getnorm @MANGLE_PREFIX@_mct_getnorm +#define mct_getnorm_real @MANGLE_PREFIX@_mct_getnorm_real +#define mqc_bypass_enc @MANGLE_PREFIX@_mqc_bypass_enc +#define mqc_bypass_flush_enc @MANGLE_PREFIX@_mqc_bypass_flush_enc +#define mqc_bypass_init_enc @MANGLE_PREFIX@_mqc_bypass_init_enc +#define mqc_create @MANGLE_PREFIX@_mqc_create +#define mqc_decode @MANGLE_PREFIX@_mqc_decode +#define mqc_destroy @MANGLE_PREFIX@_mqc_destroy +#define mqc_encode @MANGLE_PREFIX@_mqc_encode +#define mqc_erterm_enc @MANGLE_PREFIX@_mqc_erterm_enc +#define mqc_flush @MANGLE_PREFIX@_mqc_flush +#define mqc_init_dec @MANGLE_PREFIX@_mqc_init_dec +#define mqc_init_enc @MANGLE_PREFIX@_mqc_init_enc +#define mqc_numbytes @MANGLE_PREFIX@_mqc_numbytes +#define mqc_reset_enc @MANGLE_PREFIX@_mqc_reset_enc +#define mqc_resetstates @MANGLE_PREFIX@_mqc_resetstates +#define mqc_restart_enc @MANGLE_PREFIX@_mqc_restart_enc +#define mqc_restart_init_enc @MANGLE_PREFIX@_mqc_restart_init_enc +#define mqc_segmark_enc @MANGLE_PREFIX@_mqc_segmark_enc +#define mqc_setcurctx @MANGLE_PREFIX@_mqc_setcurctx +#define mqc_setstate @MANGLE_PREFIX@_mqc_setstate +#define opj_create_compress @MANGLE_PREFIX@_opj_create_compress +#define opj_create_decompress @MANGLE_PREFIX@_opj_create_decompress +#define opj_decode @MANGLE_PREFIX@_opj_decode +#define opj_destroy_compress @MANGLE_PREFIX@_opj_destroy_compress +#define opj_destroy_decompress @MANGLE_PREFIX@_opj_destroy_decompress +#define opj_encode @MANGLE_PREFIX@_opj_encode +#define opj_set_default_decoder_parameters @MANGLE_PREFIX@_opj_set_default_decoder_parameters +#define opj_set_default_encoder_parameters @MANGLE_PREFIX@_opj_set_default_encoder_parameters +#define opj_setup_decoder @MANGLE_PREFIX@_opj_setup_decoder +#define opj_setup_encoder @MANGLE_PREFIX@_opj_setup_encoder +#define opj_version @MANGLE_PREFIX@_opj_version +#define pi_create @MANGLE_PREFIX@_pi_create +#define pi_destroy @MANGLE_PREFIX@_pi_destroy +#define pi_next @MANGLE_PREFIX@_pi_next +#define raw_create @MANGLE_PREFIX@_raw_create +#define raw_decode @MANGLE_PREFIX@_raw_decode +#define raw_destroy @MANGLE_PREFIX@_raw_destroy +#define raw_init_dec @MANGLE_PREFIX@_raw_init_dec +#define raw_numbytes @MANGLE_PREFIX@_raw_numbytes +#define t1_create @MANGLE_PREFIX@_t1_create +#define t1_decode_cblks @MANGLE_PREFIX@_t1_decode_cblks +#define t1_destroy @MANGLE_PREFIX@_t1_destroy +#define t1_encode_cblks @MANGLE_PREFIX@_t1_encode_cblks +#define t2_create @MANGLE_PREFIX@_t2_create +#define t2_decode_packets @MANGLE_PREFIX@_t2_decode_packets +#define t2_destroy @MANGLE_PREFIX@_t2_destroy +#define t2_encode_packets @MANGLE_PREFIX@_t2_encode_packets +#define tcd_create @MANGLE_PREFIX@_tcd_create +#define tcd_decode_tile @MANGLE_PREFIX@_tcd_decode_tile +#define tcd_destroy @MANGLE_PREFIX@_tcd_destroy +#define tcd_dump @MANGLE_PREFIX@_tcd_dump +#define tcd_encode_tile @MANGLE_PREFIX@_tcd_encode_tile +#define tcd_free_decode @MANGLE_PREFIX@_tcd_free_decode +#define tcd_free_encode @MANGLE_PREFIX@_tcd_free_encode +#define tcd_init_encode @MANGLE_PREFIX@_tcd_init_encode +#define tcd_makelayer @MANGLE_PREFIX@_tcd_makelayer +#define tcd_makelayer_fixed @MANGLE_PREFIX@_tcd_makelayer_fixed +#define tcd_malloc_decode @MANGLE_PREFIX@_tcd_malloc_decode +#define tcd_malloc_encode @MANGLE_PREFIX@_tcd_malloc_encode +#define tcd_rateallocate @MANGLE_PREFIX@_tcd_rateallocate +#define tcd_rateallocate_fixed @MANGLE_PREFIX@_tcd_rateallocate_fixed +#define tgt_create @MANGLE_PREFIX@_tgt_create +#define tgt_decode @MANGLE_PREFIX@_tgt_decode +#define tgt_destroy @MANGLE_PREFIX@_tgt_destroy +#define tgt_encode @MANGLE_PREFIX@_tgt_encode +#define tgt_reset @MANGLE_PREFIX@_tgt_reset +#define tgt_setvalue @MANGLE_PREFIX@_tgt_setvalue + +#endif diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/opj_config.h.in b/gdcm/Utilities/gdcmopenjpeg-v1/opj_config.h.in new file mode 100644 index 0000000..f4d5dfb --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/opj_config.h.in @@ -0,0 +1,104 @@ +/* opj_config.h.in. Generated from configure.ac by autoheader. */ + +/* Define if building universal (internal helper macro) */ +#undef AC_APPLE_UNIVERSAL_BUILD + +/* Define to 1 if you have the header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */ +#undef HAVE_FSEEKO + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the `lcms' library (-llcms). */ +#undef HAVE_LIBLCMS + +/* define to 1 if you have lcms version 1.x */ +#undef HAVE_LIBLCMS1 + +/* define to 1 if you have lcms version 2.x */ +#undef HAVE_LIBLCMS2 + +/* define to 1 if you have libpng */ +#undef HAVE_LIBPNG + +/* define to 1 if you have libtiff */ +#undef HAVE_LIBTIFF + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#undef LT_OBJDIR + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Version number of package */ +#undef VERSION + +/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most + significant byte first (like Motorola and SPARC, unlike Intel). */ +#if defined AC_APPLE_UNIVERSAL_BUILD +# if defined __BIG_ENDIAN__ +# define WORDS_BIGENDIAN 1 +# endif +#else +# ifndef WORDS_BIGENDIAN +# undef WORDS_BIGENDIAN +# endif +#endif + +/* Number of bits in a file offset, on hosts where this is settable. */ +#undef _FILE_OFFSET_BITS + +/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */ +#undef _LARGEFILE_SOURCE + +/* Define for large files, on AIX-style hosts. */ +#undef _LARGE_FILES diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/opj_config.h.in.user b/gdcm/Utilities/gdcmopenjpeg-v1/opj_config.h.in.user new file mode 100644 index 0000000..f86ccce --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/opj_config.h.in.user @@ -0,0 +1,41 @@ +/* If you want to build the library manually without using + * 'configure' or 'CMake' + * then copy this file + * 'opj_config.h.in.user' + * to + * 'opj_config.h' + * + * Open 'opj_config.h' and change the file contents + * if you want to define something because you know you have + * BOTH installed the library AND the header file(s). + * Then e.g. write +#define HAVE_LIBPNG 1 + * + * + * The file 'opj_config.h' will be included in some source files. + * ==== YOU CAN NOT COMPILE WITHOUT IT. ==== + * === DO NOT FOREGET TO CHANGE 'config.nix' APPROPRIATELY. ==== +*/ + +/* DO NOT DEFINE BOTH VERSIONS OF LCMS */ +/* define to 1 if you have both liblcms and lcms.h installed */ +#undef HAVE_LIBLCMS1 +/* #define HAVE_LIBLCMS1 1 */ + +/* define to 1 if you have both liblcms2 and lcms2.h installed */ +#undef HAVE_LIBLCMS2 +/* #define HAVE_LIBLCMS2 1 */ + +/* define to 1 if you have both libpng and png.h installed */ +#undef HAVE_LIBPNG +/* #define HAVE_LIBPNG 1 */ + +/* define to 1 if you have both libtiff and tiff.h installed */ +#undef HAVE_LIBTIFF +/* #define HAVE_LIBTIFF 1 */ + +/*---------------- DO NOT CHANGE BELOW THIS LINE ----------------*/ +#define PACKAGE_URL "http://www.openjpeg.org/" +#define PACKAGE_BUGREPORT "http://code.google.com/p/openjpeg/" + +#define PACKAGE_VERSION "1.4.0" diff --git a/gdcm/Utilities/gdcmopenjpeg-v1/opj_configh.cmake.in b/gdcm/Utilities/gdcmopenjpeg-v1/opj_configh.cmake.in new file mode 100644 index 0000000..589d866 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v1/opj_configh.cmake.in @@ -0,0 +1,31 @@ +/* create config.h for CMake */ +/* + * here is where system comupted values get stored these values should only + * change when the target compile platform changes + */ + +/* what byte order */ +#ifndef __OPJ_CONFIGURE_H +#define __OPJ_CONFIGURE_H + +#cmakedefine CMAKE_WORDS_BIGENDIAN +#ifdef CMAKE_WORDS_BIGENDIAN + #define OPJ_BIG_ENDIAN +#else + #define OPJ_LITTLE_ENDIAN +#endif + +#define PACKAGE_VERSION "@PACKAGE_VERSION@" + +#cmakedefine HAVE_INTTYPES_H +#cmakedefine HAVE_MEMORY_H +#cmakedefine HAVE_STDINT_H +#cmakedefine HAVE_STDLIB_H +#cmakedefine HAVE_STRINGS_H +#cmakedefine HAVE_STRING_H +#cmakedefine HAVE_SYS_STAT_H +#cmakedefine HAVE_SYS_TYPES_H +#cmakedefine HAVE_UNISTD_H + + +#endif /* __OPJ_CONFIGURE_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/.NoDartCoverage b/gdcm/Utilities/gdcmopenjpeg-v2/.NoDartCoverage new file mode 100644 index 0000000..3c99729 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/.NoDartCoverage @@ -0,0 +1 @@ +# do not do coverage in this directory diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/CMake/CTestCustom.cmake.in b/gdcm/Utilities/gdcmopenjpeg-v2/CMake/CTestCustom.cmake.in new file mode 100644 index 0000000..6deac7e --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/CMake/CTestCustom.cmake.in @@ -0,0 +1,21 @@ +# +# For further details regarding this file, +# see http://www.vtk.org/Wiki/CMake_Testing_With_CTest#Customizing_CTest +# + +set (CTEST_CUSTOM_MAXIMUM_NUMBER_OF_ERRORS 50) +set (CTEST_CUSTOM_MAXIMUM_NUMBER_OF_WARNINGS 50) + +set(CTEST_CUSTOM_COVERAGE_EXCLUDE + ${CTEST_CUSTOM_COVERAGE_EXCLUDE} + + # Exclude files from the Testing directories + ".*/Testing/.*" + ) + +set(CTEST_CUSTOM_WARNING_EXCEPTION + ${CTEST_CUSTOM_WARNING_EXCEPTION} + + # Suppress warning caused by intentional messages about deprecation + ".*warning,.* is deprecated" +) diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/CMake/FindFreeImage.cmake b/gdcm/Utilities/gdcmopenjpeg-v2/CMake/FindFreeImage.cmake new file mode 100644 index 0000000..3c8bcb4 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/CMake/FindFreeImage.cmake @@ -0,0 +1,50 @@ +# +# Try to find the FreeImage library and include path. +# Once done this will define +# +# FREEIMAGE_FOUND +# FREEIMAGE_INCLUDE_PATH +# FREEIMAGE_LIBRARY +# + +if (WIN32) + find_path( FREEIMAGE_INCLUDE_PATH FreeImage.h + ${OPENJPEG_SOURCE_DIR}/libs/FreeImage + DOC "The directory where FreeImage.h resides") + find_library( FREEIMAGE_LIBRARY + NAMES FreeImage freeimage freeimage.s + PATHS + ${OPENJPEG_SOURCE_DIR}/libs/FreeImage + DOC "The FreeImage library") +else () + find_path( FREEIMAGE_INCLUDE_PATH FreeImage.h + /usr/include + /usr/local/include + /sw/include + /opt/local/include + DOC "The directory where FreeImage.h resides") + find_library( FREEIMAGE_LIBRARY + NAMES FreeImage freeimage + PATHS + /usr/lib64 + /usr/lib + /usr/local/lib64 + /usr/local/lib + /sw/lib + /opt/local/lib + DOC "The FreeImage library") +endif () + +set(FREEIMAGE_LIBRARIES ${FREEIMAGE_LIBRARY}) + +if (FREEIMAGE_INCLUDE_PATH AND FREEIMAGE_LIBRARY) + set( FREEIMAGE_FOUND TRUE CACHE BOOL "Set to TRUE if GLEW is found, FALSE otherwise") +else () + set( FREEIMAGE_FOUND FALSE CACHE BOOL "Set to TRUE if GLEW is found, FALSE otherwise") +endif () + +mark_as_advanced( + FREEIMAGE_FOUND + FREEIMAGE_LIBRARY + FREEIMAGE_LIBRARIES + FREEIMAGE_INCLUDE_PATH) diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/CMake/Free_CMakeImport.cmake b/gdcm/Utilities/gdcmopenjpeg-v2/CMake/Free_CMakeImport.cmake new file mode 100644 index 0000000..37f1ee6 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/CMake/Free_CMakeImport.cmake @@ -0,0 +1,3 @@ +set(CMAKE_MODULE_PATH "${OPENJPEG_SOURCE_DIR}/CMake") +find_package(FreeImage REQUIRED) +add_definitions ( -DFREEIMAGE_LIB ) diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/CMake/OpenJPEGConfig.cmake.in b/gdcm/Utilities/gdcmopenjpeg-v2/CMake/OpenJPEGConfig.cmake.in new file mode 100644 index 0000000..ce4a7c8 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/CMake/OpenJPEGConfig.cmake.in @@ -0,0 +1,48 @@ +#----------------------------------------------------------------------------- +# +# OPENJPEGConfig.cmake - CMake configuration file for external projects. +# +# This file is configured by OPENJPEG and used by the UseOPENJPEG.cmake +# module to load OPENJPEG's settings for an external project. +@OPENJPEG_CONFIG_INSTALL_ONLY@ +# The OPENJPEG version number. +set(OPENJPEG_MAJOR_VERSION "@OPENJPEG_VERSION_MAJOR@") +set(OPENJPEG_MINOR_VERSION "@OPENJPEG_VERSION_MINOR@") +set(OPENJPEG_BUILD_VERSION "@OPENJPEG_VERSION_BUILD@") + +# The libraries. +set(OPENJPEG_LIBRARIES "@OPENJPEG_LIBRARIES@") + +# The CMake macros dir. +set(OPENJPEG_CMAKE_DIR "@OPENJPEG_CMAKE_DIR_CONFIG@") + +# The configuration options. +set(OPENJPEG_BUILD_SHARED_LIBS "@OPENJPEG_BUILD_SHARED_LIBS@") + +# The "use" file. +set(OPENJPEG_USE_FILE "@OPENJPEG_USE_FILE_CONFIG@") + +get_filename_component(SELF_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) +if(EXISTS ${SELF_DIR}/OpenJPEGTargets.cmake) + # This is an install tree + include(${SELF_DIR}/OpenJPEGTargets.cmake) + get_filename_component(OPENJPEG_INCLUDE_ROOT "${SELF_DIR}/../../@OPENJPEG_INSTALL_INCLUDE_DIR@" ABSOLUTE) + set(OPENJPEG_INCLUDE_DIRS ${OPENJPEG_INCLUDE_ROOT}) + set(OPENJPEG_LIBRARIES openjpeg) + +else() + if(EXISTS ${SELF_DIR}/OpenJPEGExports.cmake) + # This is a build tree + set( OPENJPEG_INCLUDE_DIRS @OPENJPEG_INCLUDE_PATH@) + + include(${SELF_DIR}/OpenJPEGExports.cmake) + + else() + message(FATAL_ERROR "ooops") + endif() +endif() + +set(OPENJPEG_USE_FILE ${SELF_DIR}/UseOPENJPEG.cmake) + +# Backward compatible part: +set(OPENJPEG_FOUND TRUE) diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/CMake/mymachine_openjpeg.cmake b/gdcm/Utilities/gdcmopenjpeg-v2/CMake/mymachine_openjpeg.cmake new file mode 100644 index 0000000..7dca2ad --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/CMake/mymachine_openjpeg.cmake @@ -0,0 +1,50 @@ +cmake_minimum_required(VERSION 2.8.9) +# simply copy this file anywhere on your system and execute like this: +# ctest -S mymachine_openjpeg.cmake -V +# This will retrieve/compile/run tests/upload to cdash OpenJPEG +# results will be available at: http://my.cdash.org/index.php?project=OPENJPEG + +# Begin User inputs: +set( CTEST_SITE "mymachine" ) # generally the output of hostname +set( CTEST_DASHBOARD_ROOT "/tmp" ) # writable path +set( CTEST_CMAKE_GENERATOR "Unix Makefiles" ) # What is your compilation apps ? +set( CTEST_BUILD_CONFIGURATION Debug) # What type of build do you want ? +set( ENV{CFLAGS} "-Wall" ) # just for fun... + +# For testing we need to define the path to J2KP4files +# wget http://www.crc.ricoh.com/~gormish/jpeg2000conformance/j2kp4files_v1_5.zip +# unzip j2kp4files_v1_5.zip +set( CACHE_CONTENTS " +BUILD_TESTING:BOOL=TRUE +JPEG2000_CONFORMANCE_DATA_ROOT:PATH=${CTEST_SOURCE_DIRECTORY}/J2KP4files" ) +# End User inputs: + +# You do not need to change anything after that: +# 1. openjpeg specific: +set( CTEST_PROJECT_NAME "OPENJPEG" ) +set( CTEST_SOURCE_NAME OpenJPEG) +set( CTEST_BUILD_NAME "${CMAKE_SYSTEM}-${CTEST_CMAKE_GENERATOR}-${CTEST_BUILD_CONFIGURATION}") +set( CTEST_BINARY_NAME "${CTEST_SOURCE_NAME}-${CTEST_BUILD_NAME}") + +# 2. cdash/openjpeg specific: +# svn checkout http://openjpeg.googlecode.com/svn/trunk/ openjpeg-read-only +set( CTEST_SVN_URL "http://openjpeg.googlecode.com/svn/") +set( CTEST_UPDATE_COMMAND "svn") +#set( CTEST_CHECKOUT_COMMAND "${CTEST_UPDATE_COMMAND} co ${CTEST_SVN_URL}/trunk ${CTEST_SOURCE_NAME}") +set( CTEST_CHECKOUT_COMMAND "${CTEST_UPDATE_COMMAND} co ${CTEST_SVN_URL}/branches/v2 ${CTEST_SOURCE_NAME}") + +# 3. cmake specific: +set( CTEST_SOURCE_DIRECTORY "${CTEST_DASHBOARD_ROOT}/${CTEST_SOURCE_NAME}") +set( CTEST_BINARY_DIRECTORY "${CTEST_DASHBOARD_ROOT}/${CTEST_BINARY_NAME}") +set( CTEST_NOTES_FILES "${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}") + +ctest_empty_binary_directory( "${CTEST_BINARY_DIRECTORY}" ) +file(WRITE "${CTEST_BINARY_DIRECTORY}/CMakeCache.txt" "${CACHE_CONTENTS}") + +# Perform the Nightly build +ctest_start(Nightly) +ctest_update(SOURCE "${CTEST_SOURCE_DIRECTORY}") +ctest_configure(BUILD "${CTEST_BINARY_DIRECTORY}") +ctest_build(BUILD "${CTEST_BINARY_DIRECTORY}") +ctest_test(BUILD "${CTEST_BINARY_DIRECTORY}") +ctest_submit() diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/CMakeLists.txt b/gdcm/Utilities/gdcmopenjpeg-v2/CMakeLists.txt new file mode 100644 index 0000000..913459f --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/CMakeLists.txt @@ -0,0 +1,195 @@ +# Main CMakeLists.txt to build the OpenJPEG project using CMake (www.cmake.org) +# Written by Mathieu Malaterre + +# This CMake project will by default create a library called openjpeg +# But if you want to use this project within your own (CMake) project +# you will eventually like to prefix the library to avoid linking confusion +# For this purpose you can define a CMake var: OPENJPEG_NAMESPACE to whatever you like +# e.g.: +# set(OPENJPEG_NAMESPACE "GDCMOPENJPEG") +cmake_minimum_required(VERSION 2.8.9) + +if(NOT OPENJPEG_NAMESPACE) + set(OPENJPEG_NAMESPACE "OPENJPEG") + set(OPENJPEG_STANDALONE 1) +endif() +# In all cases: +string(TOLOWER ${OPENJPEG_NAMESPACE} OPENJPEG_LIBRARY_NAME) + +project(${OPENJPEG_NAMESPACE} C) + +# Do full dependency headers. +include_regular_expression("^.*$") + +#----------------------------------------------------------------------------- +# OPENJPEG version number, useful for packaging and doxygen doc: +set(OPENJPEG_VERSION_MAJOR 2) +set(OPENJPEG_VERSION_MINOR 0) +set(OPENJPEG_VERSION_BUILD 0) +set(OPENJPEG_VERSION + "${OPENJPEG_VERSION_MAJOR}.${OPENJPEG_VERSION_MINOR}.${OPENJPEG_VERSION_BUILD}") + +# This setting of SOVERSION assumes that any API change +# will increment either the minor or major version number of openjpeg +set(OPENJPEG_LIBRARY_PROPERTIES + VERSION "${OPENJPEG_VERSION_MAJOR}.${OPENJPEG_VERSION_MINOR}.${OPENJPEG_VERSION_BUILD}" + SOVERSION "${OPENJPEG_VERSION_MAJOR}.${OPENJPEG_VERSION_MINOR}" +) +# You will also need to define a value for the following variables: +# OPENJPEG_INSTALL_BIN_DIR - binary dir (executables) +# OPENJPEG_INSTALL_LIB_DIR - library dir (libs) +# OPENJPEG_INSTALL_DATA_DIR - share dir (say, examples, data, etc) +# OPENJPEG_INSTALL_INCLUDE_DIR - include dir (headers) + +# -------------------------------------------------------------------------- +# Install directories + +string(TOLOWER ${PROJECT_NAME} projectname) +set(subdir "${projectname}-${OPENJPEG_VERSION_MAJOR}.${OPENJPEG_VERSION_MINOR}") + +if(NOT OPENJPEG_INSTALL_BIN_DIR) + set(OPENJPEG_INSTALL_BIN_DIR "bin") +endif() + +if(NOT OPENJPEG_INSTALL_LIB_DIR) + set(OPENJPEG_INSTALL_LIB_DIR "lib") +endif() + +if(NOT OPENJPEG_INSTALL_DATA_DIR) + set(OPENJPEG_INSTALL_DATA_DIR "share/${subdir}") +endif() + +if(NOT OPENJPEG_INSTALL_INCLUDE_DIR) + set(OPENJPEG_INSTALL_INCLUDE_DIR "include/${subdir}") +endif() + +if(NOT OPENJPEG_INSTALL_DOC_DIR) + set(OPENJPEG_INSTALL_DOC_DIR "share/doc/${subdir}") +endif() + +if(NOT OPENJPEG_INSTALL_PACKAGE_DIR) + set(OPENJPEG_INSTALL_PACKAGE_DIR ${OPENJPEG_INSTALL_LIB_DIR}/${subdir} + CACHE INTERNAL "") +endif() + +#----------------------------------------------------------------------------- +# Test for some required system information. +include (${CMAKE_ROOT}/Modules/CMakeBackwardCompatibilityC.cmake) + +#----------------------------------------------------------------------------- +# Setup file for setting custom ctest vars +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/CMake/CTestCustom.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/CTestCustom.cmake + @ONLY + ) + +#----------------------------------------------------------------------------- +# OpenJPEG build configuration options. +#option(BUILD_SHARED_LIBS "Build OpenJPEG with shared libraries." OFF) +#option(ENABLE_PROFILING "Enable profiling for the library" OFF) + +#----------------------------------------------------------------------------- +#set (EXECUTABLE_OUTPUT_PATH ${OPENJPEG_BINARY_DIR}/bin CACHE PATH "Single output directory for building all executables.") +#set (LIBRARY_OUTPUT_PATH ${OPENJPEG_BINARY_DIR}/bin CACHE PATH "Single output directory for building all libraries.") +#mark_as_advanced(LIBRARY_OUTPUT_PATH EXECUTABLE_OUTPUT_PATH) + + +#----------------------------------------------------------------------------- +# For the codec... +#option(BUILD_EXAMPLES "Build the Examples (codec...)." OFF) + + +# configure name mangling to allow multiple libraries to coexist +# peacefully +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/openjpeg_mangle.h.in) +set(MANGLE_PREFIX ${OPENJPEG_LIBRARY_NAME}) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/openjpeg_mangle.h.in + ${CMAKE_CURRENT_BINARY_DIR}/openjpeg_mangle.h + @ONLY) +endif() + +#----------------------------------------------------------------------------- +# Configure files with settings for use by the build. +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/opj_configure.h.in + ${CMAKE_CURRENT_BINARY_DIR}/opj_configure.h) + +if(NOT OPENJPEG_INSTALL_NO_DEVELOPMENT) + install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/openjpeg_mangle.h + ${CMAKE_CURRENT_BINARY_DIR}/opj_configure.h + DESTINATION ${OPENJPEG_INSTALL_INCLUDE_DIR} COMPONENT Headers + ) +endif() + + +#----------------------------------------------------------------------------- +# Always build the library +include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR}) +subdirs( + libopenjpeg + ) +#----------------------------------------------------------------------------- +# Build example only if requested +if(BUILD_EXAMPLES) + # subdirs(codec) +endif() + +#----------------------------------------------------------------------------- +# For the documentation +option(BUILD_DOCUMENTATION "Build the doxygen documentation" OFF) +mark_as_advanced(BUILD_DOCUMENTATION) +if(BUILD_DOCUMENTATION) + subdirs(doc) +endif() + +#----------------------------------------------------------------------------- +# For openjpeg team if they ever want CDash+CMake +option(BUILD_TESTING "Build the tests." OFF) +if(BUILD_TESTING) + enable_testing() + include(CTest) +endif() + +#if(BUILD_TESTING) +#set(CMAKE_MODULE_PATH "${OPENJPEG_SOURCE_DIR}/CMake") +#find_package(FreeImage REQUIRED) +#include_directories( ${FREEIMAGE_INCLUDE_PATH} ) +# +# subdirs( +# test_V2_tile_handling +# test_Free_image_V2_tile_handling +# ) +#endif() + +# Adding test with dataset from: +# http://www.crc.ricoh.com/~gormish/jpeg2000conformance/ +# -> wget http://www.crc.ricoh.com/~gormish/jpeg2000conformance/j2kp4files_v1_5.zip +# http://www.jpeg.org/jpeg2000guide/testimages/testimages.html +#----------------------------------------------------------------------------- +# Adding JPEG2000_CONFORMANCE_DATA_ROOT +find_path(JPEG2000_CONFORMANCE_DATA_ROOT testimages.html + ${OPENJPEG_SOURCE_DIR}/../jpeg2000testimages + $ENV{JPEG2000_CONFORMANCE_DATA_ROOT} +) +mark_as_advanced(JPEG2000_CONFORMANCE_DATA_ROOT) + +#----------------------------------------------------------------------------- +# Compiler specific flags: +#if(CMAKE_COMPILER_IS_GNUCC) +# # For all builds, make sure openjpeg is std99 compliant: +# # set(CMAKE_C_FLAGS "-Wall -std=c99 ${CMAKE_C_FLAGS}") # FIXME: this setting prevented us from setting a coverage build. +# # Do not use ffast-math for all build, it would produce incorrect results, only set for release: +# set(CMAKE_C_FLAGS_RELEASE "-ffast-math ${CMAKE_C_FLAGS_RELEASE}") +#endif() + +# install all targets referenced as OPENJPEGTargets +install(EXPORT ${GDCM_TARGETS_NAME} DESTINATION ${OPENJPEG_INSTALL_PACKAGE_DIR}) +configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/CMake/OpenJPEGConfig.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/OpenJPEGConfig.cmake + @ONLY +) +install( FILES ${CMAKE_CURRENT_BINARY_DIR}/OpenJPEGConfig.cmake + DESTINATION ${OPENJPEG_INSTALL_PACKAGE_DIR} +) + diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/CTestConfig.cmake b/gdcm/Utilities/gdcmopenjpeg-v2/CTestConfig.cmake new file mode 100644 index 0000000..6d3866e --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/CTestConfig.cmake @@ -0,0 +1,7 @@ +set(CTEST_PROJECT_NAME "OPENJPEG") +set(CTEST_NIGHTLY_START_TIME "3:00:00 UTC") + +set(CTEST_DROP_METHOD "http") +set(CTEST_DROP_SITE "my.cdash.org") +set(CTEST_DROP_LOCATION "/submit.php?project=OPENJPEG") +set(CTEST_DROP_SITE_CDASH TRUE) diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/README.cmake b/gdcm/Utilities/gdcmopenjpeg-v2/README.cmake new file mode 100644 index 0000000..94f6e90 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/README.cmake @@ -0,0 +1,9 @@ +Basic instructions on how to build using CMake (CMake 2.4.5 or newer is required) + + svn co http://www.openjpeg.org/svn/trunk + cd trunk + mkdir bin + cd bin + cmake .. -DBUILD_EXAMPLES:BOOL=ON + make + ./bin/j2k_to_image diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/README.linux b/gdcm/Utilities/gdcmopenjpeg-v2/README.linux new file mode 100644 index 0000000..8dc8415 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/README.linux @@ -0,0 +1,33 @@ +Release Notes +-------------- +This version of the library has been tested under the following OS: +- RedHat Linux 9.0 + +You should be able to link progams with the -lopenjpeg option after the library is compiled and installed. +You can also statically link with libopenjpeg.a. +If you use a really old version of gcc and it chokes on the CRs in the file, you can type 'make dos2unix' +to run all of the files through dos2unix which converts CRLF to LF. This no longer appears to be required +for RedHat 7.3 or 9. + +Please let us know how this works for you under other Linux distributions or any other *nix. + +Installation +------------ +Note: You will need to have root privileges in order to install the library in +/usr/include and /usr/lib directories. +The installation process is as simple as this : +1) Enter the OpenJPEG directory +2) Build the distribution : +make +make install +3) Clean all files produced during the build process +make clean + +Simple codec compilation +------------------------ +Once you've built the library, you might want to test it with a basic codec. To do this, go to the codec directory and use one of the following commands to build an encoder and decoder respectively: + +gcc convert.c image_to_j2k.c -o image_to_j2k -lopenjpeg -I ../libopenjpeg/ -lm -ltiff +gcc convert.c j2k_to_image.c -o j2k_to_image -lopenjpeg -I ../libopenjpeg/ -lm -ltiff + +You should add '-L..' to those lines if you did not use the 'install' target (and the 'clean' target neither...). diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/README.msvc b/gdcm/Utilities/gdcmopenjpeg-v2/README.msvc new file mode 100644 index 0000000..7c33121 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/README.msvc @@ -0,0 +1,36 @@ +How to compile the library under MS VC++ 6.0 +-------------------------------------------- + +The library comes in two versions : +- a static library that can be linked against any C/C++ program +- a Dynamic Link Library (Windows DLL) that can be used in any C/C++ program and in most interpreted languages (e.g. VB, C#, ...). + +In order to compile the library version *or* the DLL version, you will have to : + +1) Open the MSVC workspace named LibOpenJPEG.dsw +2) Set the choosen target as the active project, that means : + a) Go to the Menu 'Build -> Set Active Configuration' + b) Choose one of the following configuration : + - DllOpenJPEG - Win32 Release => creates a DLL in release mode named OpenJPEG.dll + - DllOpenJPEG - Win32 Debug => creates a DLL in debug mode named OpenJPEGd.dll + - LibOpenJPEG - Win32 Release => creates a static library in release mode named LibOpenJPEG.lib + - LibOpenJPEG - Win32 Debug => creates a static library in debug mode named LibOpenJPEGd.lib +3) Build the project : Menu -> Build -> Rebuild All + +The build process will create a directory named 'dist' that will contain all you need in order to use the library. + +Simple codec compilation +------------------------ + +Once you've built the library, you might want to test it with a basic codec. To do this, go to the codec directory and use one of the following projects to build an encoder and decoder respectively: +- image_to_j2k.dsw +- j2k_to_image.dsw + +IMPORTANT NOTE : +---------------- + +The encoder and decoder samples are configured to use the static version of the library. A link to the LibOpenJPEG static project is included in these projects so that you can build both a codec and the library in a single pass. + +However, you MUST NOTE that in order to use LibOpenJPEG as a static library in your program, you NEED to add the following compiler directive to your project : OPJ_STATIC +Look at the menu 'Project -> Settings -> C/C++ tab -> preprocessor definition' to see how this is configured. +When using OpenJPEG as a DLL, this compiler directive MUST NOT be used. diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/README.osx b/gdcm/Utilities/gdcmopenjpeg-v2/README.osx new file mode 100644 index 0000000..d4eebc2 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/README.osx @@ -0,0 +1,26 @@ +Release Notes +-------------- +This version of the library has been tested under OSX 10.3 using gcc 3.3. + +While the makefiles will make a .dylib and a .a, it is recommended to simply staticly link with the .a file. + +Installation +------------ +Note: You will need to have root privileges in order to install the library in +/usr/include and /usr/lib directories. +The installation process is as simple as this : +1) Enter the OpenJPEG directory +2) Build the distribution : +make osx +make osxinstall +3) Clean all files produced during the build process +make osxclean + +Simple codec compilation +------------------------ +Once you've built the library, you might want to test it with a basic codec. To do this, go to the codec directory and either use the provided Makefile or use one of the following commands to build an encoder and decoder respectively: + +gcc index.c convert.c image_to_j2k.c -o image_to_j2k -lopenjpeg -I ../libopenjpeg/ -lm -ltiff +gcc index.c convert.c j2k_to_image.c -o j2k_to_image -lopenjpeg -I ../libopenjpeg/ -lm -ltiff + +You should add '-L..' to those lines if you did not use the 'install' target (and the 'clean' target neither...). diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/README.v2 b/gdcm/Utilities/gdcmopenjpeg-v2/README.v2 new file mode 100644 index 0000000..5ec6246 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/README.v2 @@ -0,0 +1,25 @@ +Preliminary notes +----------------- + +The Version 2 of openjpeg has been currently added as a branch on the repository. + +All the trunk has been copied and files that needed to change have been patched. In comparison with the trunk, the 'jp3d' directory has been removed because it's based on a modified version of libopenjpeg version 1 and there is no plan to make it reach the version 2 status. Idem with the 'indexer_JPIP', which is obsolete and should be rewritten from scratch. + +At the time of the branch creation, the following files and directories have been updated (or added) for version 2 : +* libopenjpeg/ +* codec/ +* test_Free_image_V2_tile_handling/ : a test program that uses libopenjpeg v2 and libfreeimage (see libs) to implement a basic codec. +* test_V2_tile_handling/ : a test program that generates a random image and (de)compresses it with libopenjpeg v2. +* CMakeLists.txt +* Free_CMakeImport.cmake +* opj_configure.h.in + +Other files and directories from the trunk (project files, jpwl/, OPJViewer/, ...) have also been copied in the branch and should be modified progressively to comply with v2. Check the Changelog for updates on this topic. + +Enjoy v2 and feel free to contribute ! + + +Instructions to compile v2 +-------------------------- + +to be added. diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/codec/CMakeLists.txt b/gdcm/Utilities/gdcmopenjpeg-v2/codec/CMakeLists.txt new file mode 100644 index 0000000..4780b1b --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/codec/CMakeLists.txt @@ -0,0 +1,94 @@ +# Build the demo app, small examples + +# First thing define the common source: +set(common_SRCS + convert.c + index.c +) + +# Then check if getopt is present: +include (${CMAKE_ROOT}/Modules/CheckIncludeFile.cmake) +set(DONT_HAVE_GETOPT 1) +if(UNIX) #I am pretty sure only *nix sys have this anyway + CHECK_INCLUDE_FILE("getopt.h" CMAKE_HAVE_GETOPT_H) + # Seems like we need the contrary: + if(CMAKE_HAVE_GETOPT_H) + set(DONT_HAVE_GETOPT 0) + endif() +endif() + +# If not getopt was found then add it to the lib: +if(DONT_HAVE_GETOPT) + add_definitions(-DDONT_HAVE_GETOPT) + set(common_SRCS + ${common_SRCS} + compat/getopt.c + ) +endif() + +# Headers file are located here: +include_directories( + ${OPENJPEG_SOURCE_DIR}/libopenjpeg + ) + +# Do the proper thing when building static...if only there was configured +# headers or def files instead +if(NOT BUILD_SHARED_LIBS) + add_definitions(-DOPJ_STATIC) +endif() + +find_package(TIFF REQUIRED) +find_package(PNG REQUIRED) +include_directories( ${PNG_INCLUDE_DIR} ) +include_directories( ${TIFF_INCLUDE_DIR} ) + +# Loop over all executables: +foreach(exe j2k_to_image image_to_j2k j2k_dump) + add_executable(${exe} ${exe}.c ${common_SRCS}) + target_link_libraries(${exe} ${OPJ_PREFIX}openjpeg ${TIFF_LIBRARIES} ${PNG_LIBRARIES}) + add_test(NAME ${exe} COMMAND ${EXECUTABLE_OUTPUT_PATH}/${exe}) + # calling those exe without option will make them fail always: + set_tests_properties(${exe} PROPERTIES WILL_FAIL TRUE) + # On unix you need to link to the math library: + if(UNIX) + target_link_libraries(${exe} m) + endif() + # Install exe + install(TARGETS ${exe} + EXPORT ${GDCM_TARGETS_NAME} + DESTINATION ${OPENJPEG_INSTALL_BIN_DIR} COMPONENT Applications + ) +endforeach() + +if(BUILD_TESTING) +# Do testing here, once we know the examples are being built: +file(GLOB_RECURSE OPENJPEG_DATA_IMAGES_GLOB + "${JPEG2000_CONFORMANCE_DATA_ROOT}/*.j2k" + "${JPEG2000_CONFORMANCE_DATA_ROOT}/*.j2c" + "${JPEG2000_CONFORMANCE_DATA_ROOT}/*.jp2" + ) + +foreach(filename ${OPENJPEG_DATA_IMAGES_GLOB}) + get_filename_component(filename_temp ${filename} NAME) + get_filename_component(filename_ext ${filename} EXT) + execute_process(COMMAND ${EXECUTABLE_OUTPUT_PATH}/j2k_dump -i ${filename} + OUTPUT_VARIABLE dump_success + OUTPUT_FILE ${CMAKE_CURRENT_BINARY_DIR}/${filename_temp}.dump + ERROR_QUIET + ) + if(dump_success) + file(READ ${CMAKE_CURRENT_BINARY_DIR}/${filename_temp}.dump numcomp_file) + string(REGEX REPLACE ".*numcomps=([0-9]+).*" "\\1" + numcomps "${numcomp_file}") + #message( "found:${output_variable} for ${filename_temp}" ) + endif() + add_test(NAME dump-${filename_temp} COMMAND ${EXECUTABLE_OUTPUT_PATH}/j2k_dump -i ${filename}) + foreach(codec_type ppm pgx bmp tif raw tga png) + add_test(NAME j2i-${filename_temp}-${codec_type} COMMAND ${EXECUTABLE_OUTPUT_PATH}/j2k_to_image -i ${filename} -o ${filename_temp}.${codec_type}) + add_test(NAME i2j-${filename_temp}-${codec_type} COMMAND ${EXECUTABLE_OUTPUT_PATH}/image_to_j2k -i ${filename_temp}.${codec_type} -o ${filename_temp}.${codec_type}${filename_ext}) + #if(UNIX) + # add_test(cmp-${filename_temp}-${codec_type} cmp ${filename} ${filename_temp}.${codec_type}${filename_ext}) + #endif() + endforeach() +endforeach() +endif() diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/codec/Makefile b/gdcm/Utilities/gdcmopenjpeg-v2/codec/Makefile new file mode 100644 index 0000000..14487a5 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/codec/Makefile @@ -0,0 +1,14 @@ +# Makefile for the main OpenJPEG codecs: j2k_to_image and image_to_j2k + +CFLAGS = -O3 -lstdc++ # -g -p -pg + +all: j2k_to_image image_to_j2k + +j2k_to_image: j2k_to_image.c ../libopenjpeg.a + gcc $(CFLAGS) compat/getopt.c index.c convert.c j2k_to_image.c -o j2k_to_image -L.. -lopenjpeg -I ../libopenjpeg/ -lm -ltiff + +image_to_j2k: image_to_j2k.c ../libopenjpeg.a + gcc $(CFLAGS) compat/getopt.c index.c convert.c image_to_j2k.c -o image_to_j2k -L.. -lopenjpeg -I ../libopenjpeg/ -lm -ltiff + +clean: + rm -f j2k_to_image image_to_j2k diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/codec/compat/getopt.c b/gdcm/Utilities/gdcmopenjpeg-v2/codec/compat/getopt.c new file mode 100644 index 0000000..aa98905 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/codec/compat/getopt.c @@ -0,0 +1,257 @@ +/* + * Copyright (c) 1987, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* last review : october 29th, 2002 */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)getopt.c 8.3 (Berkeley) 4/27/95"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include + +int opterr = 1, /* if error message should be printed */ + optind = 1, /* index into parent argv vector */ + optopt, /* character checked for validity */ + optreset; /* reset getopt */ +const char *optarg; /* argument associated with option */ + +typedef struct option +{ + const char *name; + int has_arg; + int *flag; + int val; +}option_t; + +#define BADCH (int)'?' +#define BADARG (int)':' +#define EMSG "" + + + +/* + * getopt -- + * Parse argc/argv argument vector. + */ +int getopt(int nargc, char *const *nargv, const char *ostr) { +# define __progname nargv[0] + static const char *place = EMSG; /* option letter processing */ + char *oli; /* option letter list index */ + + if (optreset || !*place) { /* update scanning pointer */ + optreset = 0; + if (optind >= nargc || *(place = nargv[optind]) != '-') { + place = EMSG; + return (-1); + } + if (place[1] && *++place == '-') { /* found "--" */ + ++optind; + place = EMSG; + return (-1); + } + } /* option letter okay? */ + if ((optopt = (int) *place++) == (int) ':' || + !(oli = strchr(ostr, optopt))) { + /* + * if the user didn't specify '-' as an option, + * assume it means -1. + */ + if (optopt == (int) '-') + return (-1); + if (!*place) + ++optind; + if (opterr && *ostr != ':') { + fprintf(stderr, + "%s: illegal option -- %c\n", __progname, optopt); + return (BADCH); + } + } + if (*++oli != ':') { /* don't need argument */ + optarg = NULL; + if (!*place) + ++optind; + } else { /* need an argument */ + if (*place) /* no white space */ + optarg = place; + else if (nargc <= ++optind) { /* no arg */ + place = EMSG; + if (*ostr == ':') + return (BADARG); + if (opterr) { + fprintf(stderr, + "%s: option requires an argument -- %c\n", + __progname, optopt); + return (BADCH); + } + } else /* white space */ + optarg = nargv[optind]; + place = EMSG; + ++optind; + } + return (optopt); /* dump back option letter */ +} + + +int getopt_long(int argc, char * const argv[], const char *optstring, +struct option *longopts, int totlen) { + static int lastidx,lastofs; + char *tmp; + int i,len; + char param = 1; + +again: + if (optind>argc || !argv[optind] || *argv[optind]!='-') + return -1; + + if (argv[optind][0]=='-' && argv[optind][1]==0) { + if(optind >= (argc - 1)){ /* no more input parameters */ + param = 0; + } + else{ /* more input parameters */ + if(argv[optind + 1][0] == '-'){ + param = 0; /* Missing parameter after '-' */ + } + else{ + param = 2; + } + } + } + + if (param == 0) { + ++optind; + return (BADCH); + } + + if (argv[optind][0]=='-') { /* long option */ + char* arg=argv[optind]+1; + const struct option* o; + o=longopts; + len=sizeof(longopts[0]); + + if (param > 1){ + arg = argv[optind+1]; + optind++; + } + else + arg = argv[optind]+1; + + if(strlen(arg)>1){ + for (i=0;iname,arg)) { /* match */ + if (o->has_arg == 0) { + if ((argv[optind+1])&&(!(argv[optind+1][0]=='-'))){ + fprintf(stderr,"%s: option does not require an argument. Ignoring %s\n",arg,argv[optind+1]); + ++optind; + } + }else{ + optarg=argv[optind+1]; + if(optarg){ + if (optarg[0] == '-'){ /* Has read next input parameter: No arg for current parameter */ + if (opterr) { + fprintf(stderr,"%s: option requires an argument\n",arg); + return (BADCH); + } + } + } + if (!optarg && o->has_arg==1) { /* no argument there */ + if (opterr) { + fprintf(stderr,"%s: option requires an argument \n",arg); + return (BADCH); + } + } + ++optind; + } + ++optind; + if (o->flag) + *(o->flag)=o->val; + else + return o->val; + return 0; + } + }//(end for)String not found in the list + fprintf(stderr,"Invalid option %s\n",arg); + ++optind; + return (BADCH); + }else{ /*Single character input parameter*/ + if (*optstring==':') return ':'; + if (lastidx!=optind) { + lastidx=optind; lastofs=0; + } + optopt=argv[optind][lastofs+1]; + if ((tmp=strchr(optstring,optopt))) {/*Found input parameter in list*/ + if (*tmp==0) { /* apparently, we looked for \0, i.e. end of argument */ + ++optind; + goto again; + } + if (tmp[1]==':') { /* argument expected */ + if (tmp[2]==':' || argv[optind][lastofs+2]) { /* "-foo", return "oo" as optarg */ + if (!*(optarg=argv[optind]+lastofs+2)) optarg=0; + goto found; + } + optarg=argv[optind+1]; + if(optarg){ + if (optarg[0] == '-'){ /* Has read next input parameter: No arg for current parameter */ + if (opterr) { + fprintf(stderr,"%s: option requires an argument\n",arg); + return (BADCH); + } + } + } + if (!optarg) { /* missing argument */ + if (opterr) { + fprintf(stderr,"%s: option requires an argument\n",arg); + return (BADCH); + } + } + ++optind; + }else {/*Argument not expected*/ + ++lastofs; + return optopt; + } +found: + ++optind; + return optopt; + } else { /* not found */ + fprintf(stderr,"Invalid option %s\n",arg); + ++optind; + return (BADCH); + }//end of not found + + }// end of single character + }//end '-' + fprintf(stderr,"Invalid option\n"); + ++optind; + return (BADCH);; +}//end function diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/codec/compat/getopt.h b/gdcm/Utilities/gdcmopenjpeg-v2/codec/compat/getopt.h new file mode 100644 index 0000000..94a8c10 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/codec/compat/getopt.h @@ -0,0 +1,29 @@ +/* last review : october 29th, 2002 */ + +#ifndef _GETOPT_H_ +#define _GETOPT_H_ + +typedef struct option +{ + const char *name; + int has_arg; + int *flag; + int val; +}option_t; + +#define NO_ARG 0 +#define REQ_ARG 1 +#define OPT_ARG 2 + +extern int opterr; +extern int optind; +extern int optopt; +extern int optreset; +extern char *optarg; + +extern int getopt(int nargc, char *const *nargv, const char *ostr); +extern int getopt_long(int argc, char * const argv[], const char *optstring, + const struct option *longopts, int totlen); + + +#endif /* _GETOPT_H_ */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/codec/convert.c b/gdcm/Utilities/gdcmopenjpeg-v2/codec/convert.c new file mode 100644 index 0000000..82f3104 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/codec/convert.c @@ -0,0 +1,2519 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2006-2007, Parvatha Elangovan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#ifdef WIN32 +#include "../libs/libtiff/tiffio.h" +#include "../libs/libpng/png.h" +#else +#include +#include +#endif /* WIN32 */ +#include "openjpeg.h" +#include "convert.h" + +/* + * Get logarithm of an integer and round downwards. + * + * log2(a) + */ +static int int_floorlog2(int a) { + int l; + for (l = 0; a > 1; l++) { + a >>= 1; + } + return l; +} + +/* + * Divide an integer by a power of 2 and round upwards. + * + * a divided by 2^b + */ +static int int_ceildivpow2(int a, int b) { + return (a + (1 << b) - 1) >> b; +} + +/* + * Divide an integer and round upwards. + * + * a divided by b + */ +static int int_ceildiv(int a, int b) { + return (a + b - 1) / b; +} + + +/* -->> -->> -->> -->> + + TGA IMAGE FORMAT + + <<-- <<-- <<-- <<-- */ + +// TGA header definition. +#pragma pack(push,1) // Pack structure byte aligned +typedef struct tga_header +{ + uint8 id_length; /* Image id field length */ + uint8 colour_map_type; /* Colour map type */ + uint8 image_type; /* Image type */ + /* + ** Colour map specification + */ + uint16 colour_map_index; /* First entry index */ + uint16 colour_map_length; /* Colour map length */ + uint8 colour_map_entry_size; /* Colour map entry size */ + /* + ** Image specification + */ + uint16 x_origin; /* x origin of image */ + uint16 y_origin; /* u origin of image */ + uint16 image_width; /* Image width */ + uint16 image_height; /* Image height */ + uint8 pixel_depth; /* Pixel depth */ + uint8 image_desc; /* Image descriptor */ +} tga_header; +#pragma pack(pop) // Return to normal structure packing alignment. + +int tga_readheader(FILE *fp, uint32 *bits_per_pixel, uint32 *width, uint32 *height, int *flip_image) +{ + int palette_size; + tga_header tga ; + + if (!bits_per_pixel || !width || !height || !flip_image) + return 0; + + // Read TGA header + fread((uint8*)&tga, sizeof(tga_header), 1, fp); + + *bits_per_pixel = tga.pixel_depth; + + *width = tga.image_width; + *height = tga.image_height ; + + // Ignore tga identifier, if present ... + if (tga.id_length) + { + uint8 *id = (uint8 *) malloc(tga.id_length); + fread(id, tga.id_length, 1, fp); + free(id); + } + + // Test for compressed formats ... not yet supported ... + // Note :- 9 - RLE encoded palettized. + // 10 - RLE encoded RGB. + if (tga.image_type > 8) + { + fprintf(stderr, "Sorry, compressed tga files are not currently supported.\n"); + return 0 ; + } + + *flip_image = !(tga.image_desc & 32); + + // Palettized formats are not yet supported, skip over the palette, if present ... + palette_size = tga.colour_map_length * (tga.colour_map_entry_size/8); + + if (palette_size>0) + { + fprintf(stderr, "File contains a palette - not yet supported."); + fseek(fp, palette_size, SEEK_CUR); + } + return 1; +} + +int tga_writeheader(FILE *fp, int bits_per_pixel, int width, int height, bool flip_image) +{ + tga_header tga; + + if (!bits_per_pixel || !width || !height) + return 0; + + memset(&tga, 0, sizeof(tga_header)); + + tga.pixel_depth = bits_per_pixel; + tga.image_width = width; + tga.image_height = height; + tga.image_type = 2; // Uncompressed. + tga.image_desc = 8; // 8 bits per component. + + if (flip_image) + tga.image_desc |= 32; + + // Write TGA header + fwrite((uint8*)&tga, sizeof(tga_header), 1, fp); + + return 1; +} + +opj_image_t* tgatoimage(const char *filename, opj_cparameters_t *parameters) { + FILE *f; + opj_image_t *image; + uint32 image_width, image_height, pixel_bit_depth; + uint32 x, y; + int flip_image=0; + opj_image_cmptparm_t cmptparm[4]; /* maximum 4 components */ + int numcomps; + OPJ_COLOR_SPACE color_space; + bool mono ; + bool save_alpha; + int subsampling_dx, subsampling_dy; + int i; + + f = fopen(filename, "rb"); + if (!f) { + fprintf(stderr, "Failed to open %s for reading !!\n", filename); + return 0; + } + + if (!tga_readheader(f, &pixel_bit_depth, &image_width, &image_height, &flip_image)) + return NULL; + + // We currently only support 24 & 32 bit tga's ... + if (!((pixel_bit_depth == 24) || (pixel_bit_depth == 32))) + return NULL; + + /* initialize image components */ + memset(&cmptparm[0], 0, 4 * sizeof(opj_image_cmptparm_t)); + + mono = (pixel_bit_depth == 8) || (pixel_bit_depth == 16); // Mono with & without alpha. + save_alpha = (pixel_bit_depth == 16) || (pixel_bit_depth == 32); // Mono with alpha, or RGB with alpha + + if (mono) { + color_space = CLRSPC_GRAY; + numcomps = save_alpha ? 2 : 1; + } + else { + numcomps = save_alpha ? 4 : 3; + color_space = CLRSPC_SRGB; + } + + subsampling_dx = parameters->subsampling_dx; + subsampling_dy = parameters->subsampling_dy; + + for (i = 0; i < numcomps; i++) { + cmptparm[i].prec = 8; + cmptparm[i].bpp = 8; + cmptparm[i].sgnd = 0; + cmptparm[i].dx = subsampling_dx; + cmptparm[i].dy = subsampling_dy; + cmptparm[i].w = image_width; + cmptparm[i].h = image_height; + } + + /* create the image */ + image = opj_image_create(numcomps, &cmptparm[0], color_space); + + if (!image) + return NULL; + + /* set image offset and reference grid */ + image->x0 = parameters->image_offset_x0; + image->y0 = parameters->image_offset_y0; + image->x1 = !image->x0 ? (image_width - 1) * subsampling_dx + 1 : image->x0 + (image_width - 1) * subsampling_dx + 1; + image->y1 = !image->y0 ? (image_height - 1) * subsampling_dy + 1 : image->y0 + (image_height - 1) * subsampling_dy + 1; + + /* set image data */ + for (y=0; y < image_height; y++) + { + int index; + + if (flip_image) + index = (image_height-y-1)*image_width; + else + index = y*image_width; + + if (numcomps==3) + { + for (x=0;xcomps[0].data[index]=r; + image->comps[1].data[index]=g; + image->comps[2].data[index]=b; + index++; + } + } + else if (numcomps==4) + { + for (x=0;xcomps[0].data[index]=r; + image->comps[1].data[index]=g; + image->comps[2].data[index]=b; + image->comps[3].data[index]=a; + index++; + } + } + else { + fprintf(stderr, "Currently unsupported bit depth : %s\n", filename); + } + } + return image; +} + +int imagetotga(opj_image_t * image, const char *outfile) { + int width, height, bpp, x, y; + bool write_alpha; + unsigned int i; + uint32 alpha_channel; + float r,g,b,a; + uint8 value; + float scale; + FILE *fdest; + + fdest = fopen(outfile, "wb"); + if (!fdest) { + fprintf(stderr, "ERROR -> failed to open %s for writing\n", outfile); + return 1; + } + + for (i = 0; i < image->numcomps-1; i++) { + if ((image->comps[0].dx != image->comps[i+1].dx) + ||(image->comps[0].dy != image->comps[i+1].dy) + ||(image->comps[0].prec != image->comps[i+1].prec)) { + fprintf(stderr, "Unable to create a tga file with such J2K image charateristics."); + return 1; + } + } + + width = image->comps[0].w; + height = image->comps[0].h; + + // Mono with alpha, or RGB with alpha. + write_alpha = (image->numcomps==2) || (image->numcomps==4); + + // Write TGA header + bpp = write_alpha ? 32 : 24; + if (!tga_writeheader(fdest, bpp, width , height, true)) + return 1; + + alpha_channel = image->numcomps-1; + + scale = 255.0f / (float)((1<comps[0].prec)-1); + + for (y=0; y < height; y++) { + uint32 index=y*width; + + for (x=0; x < width; x++, index++) { + r = (float)(image->comps[0].data[index]); + + if (image->numcomps>2) { + g = (float)(image->comps[1].data[index]); + b = (float)(image->comps[2].data[index]); + } + else {// Greyscale ... + g = r; + b = r; + } + + // TGA format writes BGR ... + value = (uint8)(b*scale); + fwrite(&value,1,1,fdest); + + value = (uint8)(g*scale); + fwrite(&value,1,1,fdest); + + value = (uint8)(r*scale); + fwrite(&value,1,1,fdest); + + if (write_alpha) { + a = (float)(image->comps[alpha_channel].data[index]); + value = (uint8)(a*scale); + fwrite(&value,1,1,fdest); + } + } + } + + return 0; +} + +/* -->> -->> -->> -->> + + BMP IMAGE FORMAT + + <<-- <<-- <<-- <<-- */ + +/* WORD defines a two byte word */ +typedef unsigned short int WORD; + +/* DWORD defines a four byte word */ +typedef unsigned long int DWORD; + +typedef struct { + WORD bfType; /* 'BM' for Bitmap (19776) */ + DWORD bfSize; /* Size of the file */ + WORD bfReserved1; /* Reserved : 0 */ + WORD bfReserved2; /* Reserved : 0 */ + DWORD bfOffBits; /* Offset */ +} BITMAPFILEHEADER_t; + +typedef struct { + DWORD biSize; /* Size of the structure in bytes */ + DWORD biWidth; /* Width of the image in pixels */ + DWORD biHeight; /* Heigth of the image in pixels */ + WORD biPlanes; /* 1 */ + WORD biBitCount; /* Number of color bits by pixels */ + DWORD biCompression; /* Type of encoding 0: none 1: RLE8 2: RLE4 */ + DWORD biSizeImage; /* Size of the image in bytes */ + DWORD biXpelsPerMeter; /* Horizontal (X) resolution in pixels/meter */ + DWORD biYpelsPerMeter; /* Vertical (Y) resolution in pixels/meter */ + DWORD biClrUsed; /* Number of color used in the image (0: ALL) */ + DWORD biClrImportant; /* Number of important color (0: ALL) */ +} BITMAPINFOHEADER_t; + +opj_image_t* bmptoimage(const char *filename, opj_cparameters_t *parameters) { + int subsampling_dx = parameters->subsampling_dx; + int subsampling_dy = parameters->subsampling_dy; + + int i, numcomps, w, h; + OPJ_COLOR_SPACE color_space; + opj_image_cmptparm_t cmptparm[3]; /* maximum of 3 components */ + opj_image_t * image = NULL; + + FILE *IN; + BITMAPFILEHEADER_t File_h; + BITMAPINFOHEADER_t Info_h; + unsigned char *RGB; + unsigned char *table_R, *table_G, *table_B; + unsigned int j, PAD = 0; + + int x, y, index; + int gray_scale = 1, not_end_file = 1; + + unsigned int line = 0, col = 0; + unsigned char v, v2; + DWORD W, H; + + IN = fopen(filename, "rb"); + if (!IN) { + fprintf(stderr, "Failed to open %s for reading !!\n", filename); + return 0; + } + + File_h.bfType = getc(IN); + File_h.bfType = (getc(IN) << 8) + File_h.bfType; + + if (File_h.bfType != 19778) { + fprintf(stderr,"Error, not a BMP file!\n"); + return 0; + } else { + /* FILE HEADER */ + /* ------------- */ + File_h.bfSize = getc(IN); + File_h.bfSize = (getc(IN) << 8) + File_h.bfSize; + File_h.bfSize = (getc(IN) << 16) + File_h.bfSize; + File_h.bfSize = (getc(IN) << 24) + File_h.bfSize; + + File_h.bfReserved1 = getc(IN); + File_h.bfReserved1 = (getc(IN) << 8) + File_h.bfReserved1; + + File_h.bfReserved2 = getc(IN); + File_h.bfReserved2 = (getc(IN) << 8) + File_h.bfReserved2; + + File_h.bfOffBits = getc(IN); + File_h.bfOffBits = (getc(IN) << 8) + File_h.bfOffBits; + File_h.bfOffBits = (getc(IN) << 16) + File_h.bfOffBits; + File_h.bfOffBits = (getc(IN) << 24) + File_h.bfOffBits; + + /* INFO HEADER */ + /* ------------- */ + + Info_h.biSize = getc(IN); + Info_h.biSize = (getc(IN) << 8) + Info_h.biSize; + Info_h.biSize = (getc(IN) << 16) + Info_h.biSize; + Info_h.biSize = (getc(IN) << 24) + Info_h.biSize; + + Info_h.biWidth = getc(IN); + Info_h.biWidth = (getc(IN) << 8) + Info_h.biWidth; + Info_h.biWidth = (getc(IN) << 16) + Info_h.biWidth; + Info_h.biWidth = (getc(IN) << 24) + Info_h.biWidth; + w = Info_h.biWidth; + + Info_h.biHeight = getc(IN); + Info_h.biHeight = (getc(IN) << 8) + Info_h.biHeight; + Info_h.biHeight = (getc(IN) << 16) + Info_h.biHeight; + Info_h.biHeight = (getc(IN) << 24) + Info_h.biHeight; + h = Info_h.biHeight; + + Info_h.biPlanes = getc(IN); + Info_h.biPlanes = (getc(IN) << 8) + Info_h.biPlanes; + + Info_h.biBitCount = getc(IN); + Info_h.biBitCount = (getc(IN) << 8) + Info_h.biBitCount; + + Info_h.biCompression = getc(IN); + Info_h.biCompression = (getc(IN) << 8) + Info_h.biCompression; + Info_h.biCompression = (getc(IN) << 16) + Info_h.biCompression; + Info_h.biCompression = (getc(IN) << 24) + Info_h.biCompression; + + Info_h.biSizeImage = getc(IN); + Info_h.biSizeImage = (getc(IN) << 8) + Info_h.biSizeImage; + Info_h.biSizeImage = (getc(IN) << 16) + Info_h.biSizeImage; + Info_h.biSizeImage = (getc(IN) << 24) + Info_h.biSizeImage; + + Info_h.biXpelsPerMeter = getc(IN); + Info_h.biXpelsPerMeter = (getc(IN) << 8) + Info_h.biXpelsPerMeter; + Info_h.biXpelsPerMeter = (getc(IN) << 16) + Info_h.biXpelsPerMeter; + Info_h.biXpelsPerMeter = (getc(IN) << 24) + Info_h.biXpelsPerMeter; + + Info_h.biYpelsPerMeter = getc(IN); + Info_h.biYpelsPerMeter = (getc(IN) << 8) + Info_h.biYpelsPerMeter; + Info_h.biYpelsPerMeter = (getc(IN) << 16) + Info_h.biYpelsPerMeter; + Info_h.biYpelsPerMeter = (getc(IN) << 24) + Info_h.biYpelsPerMeter; + + Info_h.biClrUsed = getc(IN); + Info_h.biClrUsed = (getc(IN) << 8) + Info_h.biClrUsed; + Info_h.biClrUsed = (getc(IN) << 16) + Info_h.biClrUsed; + Info_h.biClrUsed = (getc(IN) << 24) + Info_h.biClrUsed; + + Info_h.biClrImportant = getc(IN); + Info_h.biClrImportant = (getc(IN) << 8) + Info_h.biClrImportant; + Info_h.biClrImportant = (getc(IN) << 16) + Info_h.biClrImportant; + Info_h.biClrImportant = (getc(IN) << 24) + Info_h.biClrImportant; + + /* Read the data and store them in the OUT file */ + + if (Info_h.biBitCount == 24) { + numcomps = 3; + color_space = CLRSPC_SRGB; + /* initialize image components */ + memset(&cmptparm[0], 0, 3 * sizeof(opj_image_cmptparm_t)); + for(i = 0; i < numcomps; i++) { + cmptparm[i].prec = 8; + cmptparm[i].bpp = 8; + cmptparm[i].sgnd = 0; + cmptparm[i].dx = subsampling_dx; + cmptparm[i].dy = subsampling_dy; + cmptparm[i].w = w; + cmptparm[i].h = h; + } + /* create the image */ + image = opj_image_create(numcomps, &cmptparm[0], color_space); + if(!image) { + fclose(IN); + return NULL; + } + + /* set image offset and reference grid */ + image->x0 = parameters->image_offset_x0; + image->y0 = parameters->image_offset_y0; + image->x1 = !image->x0 ? (w - 1) * subsampling_dx + 1 : image->x0 + (w - 1) * subsampling_dx + 1; + image->y1 = !image->y0 ? (h - 1) * subsampling_dy + 1 : image->y0 + (h - 1) * subsampling_dy + 1; + + /* set image data */ + + /* Place the cursor at the beginning of the image information */ + fseek(IN, 0, SEEK_SET); + fseek(IN, File_h.bfOffBits, SEEK_SET); + + W = Info_h.biWidth; + H = Info_h.biHeight; + + /* PAD = 4 - (3 * W) % 4; */ + /* PAD = (PAD == 4) ? 0 : PAD; */ + PAD = (3 * W) % 4 ? 4 - (3 * W) % 4 : 0; + + RGB = (unsigned char *) malloc((3 * W + PAD) * H * sizeof(unsigned char)); + + fread(RGB, sizeof(unsigned char), (3 * W + PAD) * H, IN); + + index = 0; + + for(y = 0; y < (int)H; y++) { + unsigned char *scanline = RGB + (3 * W + PAD) * (H - 1 - y); + for(x = 0; x < (int)W; x++) { + unsigned char *pixel = &scanline[3 * x]; + image->comps[0].data[index] = pixel[2]; /* R */ + image->comps[1].data[index] = pixel[1]; /* G */ + image->comps[2].data[index] = pixel[0]; /* B */ + index++; + } + } + + free(RGB); + + } else if (Info_h.biBitCount == 8 && Info_h.biCompression == 0) { + table_R = (unsigned char *) malloc(256 * sizeof(unsigned char)); + table_G = (unsigned char *) malloc(256 * sizeof(unsigned char)); + table_B = (unsigned char *) malloc(256 * sizeof(unsigned char)); + + for (j = 0; j < Info_h.biClrUsed; j++) { + table_B[j] = getc(IN); + table_G[j] = getc(IN); + table_R[j] = getc(IN); + getc(IN); + if (table_R[j] != table_G[j] && table_R[j] != table_B[j] && table_G[j] != table_B[j]) + gray_scale = 0; + } + + /* Place the cursor at the beginning of the image information */ + fseek(IN, 0, SEEK_SET); + fseek(IN, File_h.bfOffBits, SEEK_SET); + + W = Info_h.biWidth; + H = Info_h.biHeight; + if (Info_h.biWidth % 2) + W++; + + numcomps = gray_scale ? 1 : 3; + color_space = gray_scale ? CLRSPC_GRAY : CLRSPC_SRGB; + /* initialize image components */ + memset(&cmptparm[0], 0, 3 * sizeof(opj_image_cmptparm_t)); + for(i = 0; i < numcomps; i++) { + cmptparm[i].prec = 8; + cmptparm[i].bpp = 8; + cmptparm[i].sgnd = 0; + cmptparm[i].dx = subsampling_dx; + cmptparm[i].dy = subsampling_dy; + cmptparm[i].w = w; + cmptparm[i].h = h; + } + /* create the image */ + image = opj_image_create(numcomps, &cmptparm[0], color_space); + if(!image) { + fclose(IN); + return NULL; + } + + /* set image offset and reference grid */ + image->x0 = parameters->image_offset_x0; + image->y0 = parameters->image_offset_y0; + image->x1 = !image->x0 ? (w - 1) * subsampling_dx + 1 : image->x0 + (w - 1) * subsampling_dx + 1; + image->y1 = !image->y0 ? (h - 1) * subsampling_dy + 1 : image->y0 + (h - 1) * subsampling_dy + 1; + + /* set image data */ + + RGB = (unsigned char *) malloc(W * H * sizeof(unsigned char)); + + fread(RGB, sizeof(unsigned char), W * H, IN); + if (gray_scale) { + index = 0; + for (j = 0; j < W * H; j++) { + if ((j % W < W - 1 && Info_h.biWidth % 2) || !(Info_h.biWidth % 2)) { + image->comps[0].data[index] = table_R[RGB[W * H - ((j) / (W) + 1) * W + (j) % (W)]]; + index++; + } + } + + } else { + index = 0; + for (j = 0; j < W * H; j++) { + if ((j % W < W - 1 && Info_h.biWidth % 2) || !(Info_h.biWidth % 2)) { + unsigned char pixel_index = RGB[W * H - ((j) / (W) + 1) * W + (j) % (W)]; + image->comps[0].data[index] = table_R[pixel_index]; + image->comps[1].data[index] = table_G[pixel_index]; + image->comps[2].data[index] = table_B[pixel_index]; + index++; + } + } + } + free(RGB); + free(table_R); + free(table_G); + free(table_B); + } else if (Info_h.biBitCount == 8 && Info_h.biCompression == 1) { + table_R = (unsigned char *) malloc(256 * sizeof(unsigned char)); + table_G = (unsigned char *) malloc(256 * sizeof(unsigned char)); + table_B = (unsigned char *) malloc(256 * sizeof(unsigned char)); + + for (j = 0; j < Info_h.biClrUsed; j++) { + table_B[j] = getc(IN); + table_G[j] = getc(IN); + table_R[j] = getc(IN); + getc(IN); + if (table_R[j] != table_G[j] && table_R[j] != table_B[j] && table_G[j] != table_B[j]) + gray_scale = 0; + } + + numcomps = gray_scale ? 1 : 3; + color_space = gray_scale ? CLRSPC_GRAY : CLRSPC_SRGB; + /* initialize image components */ + memset(&cmptparm[0], 0, 3 * sizeof(opj_image_cmptparm_t)); + for(i = 0; i < numcomps; i++) { + cmptparm[i].prec = 8; + cmptparm[i].bpp = 8; + cmptparm[i].sgnd = 0; + cmptparm[i].dx = subsampling_dx; + cmptparm[i].dy = subsampling_dy; + cmptparm[i].w = w; + cmptparm[i].h = h; + } + /* create the image */ + image = opj_image_create(numcomps, &cmptparm[0], color_space); + if(!image) { + fclose(IN); + return NULL; + } + + /* set image offset and reference grid */ + image->x0 = parameters->image_offset_x0; + image->y0 = parameters->image_offset_y0; + image->x1 = !image->x0 ? (w - 1) * subsampling_dx + 1 : image->x0 + (w - 1) * subsampling_dx + 1; + image->y1 = !image->y0 ? (h - 1) * subsampling_dy + 1 : image->y0 + (h - 1) * subsampling_dy + 1; + + /* set image data */ + + /* Place the cursor at the beginning of the image information */ + fseek(IN, 0, SEEK_SET); + fseek(IN, File_h.bfOffBits, SEEK_SET); + + RGB = (unsigned char *) malloc(Info_h.biWidth * Info_h.biHeight * sizeof(unsigned char)); + + while (not_end_file) { + v = getc(IN); + if (v) { + v2 = getc(IN); + for (i = 0; i < (int) v; i++) { + RGB[line * Info_h.biWidth + col] = v2; + col++; + } + } else { + v = getc(IN); + switch (v) { + case 0: + col = 0; + line++; + break; + case 1: + line++; + not_end_file = 0; + break; + case 2: + fprintf(stderr,"No Delta supported\n"); + opj_image_destroy(image); + fclose(IN); + return NULL; + default: + for (i = 0; i < v; i++) { + v2 = getc(IN); + RGB[line * Info_h.biWidth + col] = v2; + col++; + } + if (v % 2) + v2 = getc(IN); + break; + } + } + } + if (gray_scale) { + index = 0; + for (line = 0; line < Info_h.biHeight; line++) { + for (col = 0; col < Info_h.biWidth; col++) { + image->comps[0].data[index] = table_R[(int)RGB[(Info_h.biHeight - line - 1) * Info_h.biWidth + col]]; + index++; + } + } + } else { + index = 0; + for (line = 0; line < Info_h.biHeight; line++) { + for (col = 0; col < Info_h.biWidth; col++) { + unsigned char pixel_index = (int)RGB[(Info_h.biHeight - line - 1) * Info_h.biWidth + col]; + image->comps[0].data[index] = table_R[pixel_index]; + image->comps[1].data[index] = table_G[pixel_index]; + image->comps[2].data[index] = table_B[pixel_index]; + index++; + } + } + } + free(RGB); + free(table_R); + free(table_G); + free(table_B); + } else { + fprintf(stderr, + "Other system than 24 bits/pixels or 8 bits (no RLE coding) is not yet implemented [%d]\n", Info_h.biBitCount); + } + fclose(IN); + } + + return image; +} + +int imagetobmp(opj_image_t * image, const char *outfile) { + int w, h; + int i, pad; + FILE *fdest = NULL; + int adjustR, adjustG, adjustB; + + if (image->numcomps == 3 && image->comps[0].dx == image->comps[1].dx + && image->comps[1].dx == image->comps[2].dx + && image->comps[0].dy == image->comps[1].dy + && image->comps[1].dy == image->comps[2].dy + && image->comps[0].prec == image->comps[1].prec + && image->comps[1].prec == image->comps[2].prec) { + + /* -->> -->> -->> -->> + 24 bits color + <<-- <<-- <<-- <<-- */ + + fdest = fopen(outfile, "wb"); + if (!fdest) { + fprintf(stderr, "ERROR -> failed to open %s for writing\n", outfile); + return 1; + } + + w = image->comps[0].w; + h = image->comps[0].h; + + fprintf(fdest, "BM"); + + /* FILE HEADER */ + /* ------------- */ + fprintf(fdest, "%c%c%c%c", + (unsigned char) (h * w * 3 + 3 * h * (w % 2) + 54) & 0xff, + (unsigned char) ((h * w * 3 + 3 * h * (w % 2) + 54) >> 8) & 0xff, + (unsigned char) ((h * w * 3 + 3 * h * (w % 2) + 54) >> 16) & 0xff, + (unsigned char) ((h * w * 3 + 3 * h * (w % 2) + 54) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (0) & 0xff, ((0) >> 8) & 0xff, ((0) >> 16) & 0xff, ((0) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (54) & 0xff, ((54) >> 8) & 0xff,((54) >> 16) & 0xff, ((54) >> 24) & 0xff); + + /* INFO HEADER */ + /* ------------- */ + fprintf(fdest, "%c%c%c%c", (40) & 0xff, ((40) >> 8) & 0xff, ((40) >> 16) & 0xff, ((40) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (unsigned char) ((w) & 0xff), + (unsigned char) ((w) >> 8) & 0xff, + (unsigned char) ((w) >> 16) & 0xff, + (unsigned char) ((w) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (unsigned char) ((h) & 0xff), + (unsigned char) ((h) >> 8) & 0xff, + (unsigned char) ((h) >> 16) & 0xff, + (unsigned char) ((h) >> 24) & 0xff); + fprintf(fdest, "%c%c", (1) & 0xff, ((1) >> 8) & 0xff); + fprintf(fdest, "%c%c", (24) & 0xff, ((24) >> 8) & 0xff); + fprintf(fdest, "%c%c%c%c", (0) & 0xff, ((0) >> 8) & 0xff, ((0) >> 16) & 0xff, ((0) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (unsigned char) (3 * h * w + 3 * h * (w % 2)) & 0xff, + (unsigned char) ((h * w * 3 + 3 * h * (w % 2)) >> 8) & 0xff, + (unsigned char) ((h * w * 3 + 3 * h * (w % 2)) >> 16) & 0xff, + (unsigned char) ((h * w * 3 + 3 * h * (w % 2)) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (7834) & 0xff, ((7834) >> 8) & 0xff, ((7834) >> 16) & 0xff, ((7834) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (7834) & 0xff, ((7834) >> 8) & 0xff, ((7834) >> 16) & 0xff, ((7834) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (0) & 0xff, ((0) >> 8) & 0xff, ((0) >> 16) & 0xff, ((0) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (0) & 0xff, ((0) >> 8) & 0xff, ((0) >> 16) & 0xff, ((0) >> 24) & 0xff); + + if (image->comps[0].prec > 8) { + adjustR = image->comps[0].prec - 8; + printf("BMP CONVERSION: Truncating component 0 from %d bits to 8 bits\n", image->comps[0].prec); + } + else + adjustR = 0; + if (image->comps[1].prec > 8) { + adjustG = image->comps[1].prec - 8; + printf("BMP CONVERSION: Truncating component 1 from %d bits to 8 bits\n", image->comps[1].prec); + } + else + adjustG = 0; + if (image->comps[2].prec > 8) { + adjustB = image->comps[2].prec - 8; + printf("BMP CONVERSION: Truncating component 2 from %d bits to 8 bits\n", image->comps[2].prec); + } + else + adjustB = 0; + + for (i = 0; i < w * h; i++) { + unsigned char rc, gc, bc; + int r, g, b; + + r = image->comps[0].data[w * h - ((i) / (w) + 1) * w + (i) % (w)]; + r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0); + rc = (unsigned char) ((r >> adjustR)+((r >> (adjustR-1))%2)); + g = image->comps[1].data[w * h - ((i) / (w) + 1) * w + (i) % (w)]; + g += (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0); + gc = (unsigned char) ((g >> adjustG)+((g >> (adjustG-1))%2)); + b = image->comps[2].data[w * h - ((i) / (w) + 1) * w + (i) % (w)]; + b += (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0); + bc = (unsigned char) ((b >> adjustB)+((b >> (adjustB-1))%2)); + + fprintf(fdest, "%c%c%c", bc, gc, rc); + + if ((i + 1) % w == 0) { + for (pad = (3 * w) % 4 ? 4 - (3 * w) % 4 : 0; pad > 0; pad--) /* ADD */ + fprintf(fdest, "%c", 0); + } + } + fclose(fdest); + } else { /* Gray-scale */ + + /* -->> -->> -->> -->> + 8 bits non code (Gray scale) + <<-- <<-- <<-- <<-- */ + + fdest = fopen(outfile, "wb"); + w = image->comps[0].w; + h = image->comps[0].h; + + fprintf(fdest, "BM"); + + /* FILE HEADER */ + /* ------------- */ + fprintf(fdest, "%c%c%c%c", (unsigned char) (h * w + 54 + 1024 + h * (w % 2)) & 0xff, + (unsigned char) ((h * w + 54 + 1024 + h * (w % 2)) >> 8) & 0xff, + (unsigned char) ((h * w + 54 + 1024 + h * (w % 2)) >> 16) & 0xff, + (unsigned char) ((h * w + 54 + 1024 + w * (w % 2)) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (0) & 0xff, ((0) >> 8) & 0xff, ((0) >> 16) & 0xff, ((0) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (54 + 1024) & 0xff, ((54 + 1024) >> 8) & 0xff, + ((54 + 1024) >> 16) & 0xff, + ((54 + 1024) >> 24) & 0xff); + + /* INFO HEADER */ + /* ------------- */ + fprintf(fdest, "%c%c%c%c", (40) & 0xff, ((40) >> 8) & 0xff, ((40) >> 16) & 0xff, ((40) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (unsigned char) ((w) & 0xff), + (unsigned char) ((w) >> 8) & 0xff, + (unsigned char) ((w) >> 16) & 0xff, + (unsigned char) ((w) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (unsigned char) ((h) & 0xff), + (unsigned char) ((h) >> 8) & 0xff, + (unsigned char) ((h) >> 16) & 0xff, + (unsigned char) ((h) >> 24) & 0xff); + fprintf(fdest, "%c%c", (1) & 0xff, ((1) >> 8) & 0xff); + fprintf(fdest, "%c%c", (8) & 0xff, ((8) >> 8) & 0xff); + fprintf(fdest, "%c%c%c%c", (0) & 0xff, ((0) >> 8) & 0xff, ((0) >> 16) & 0xff, ((0) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (unsigned char) (h * w + h * (w % 2)) & 0xff, + (unsigned char) ((h * w + h * (w % 2)) >> 8) & 0xff, + (unsigned char) ((h * w + h * (w % 2)) >> 16) & 0xff, + (unsigned char) ((h * w + h * (w % 2)) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (7834) & 0xff, ((7834) >> 8) & 0xff, ((7834) >> 16) & 0xff, ((7834) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (7834) & 0xff, ((7834) >> 8) & 0xff, ((7834) >> 16) & 0xff, ((7834) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (256) & 0xff, ((256) >> 8) & 0xff, ((256) >> 16) & 0xff, ((256) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (256) & 0xff, ((256) >> 8) & 0xff, ((256) >> 16) & 0xff, ((256) >> 24) & 0xff); + + if (image->comps[0].prec > 8) { + adjustR = image->comps[0].prec - 8; + printf("BMP CONVERSION: Truncating component 0 from %d bits to 8 bits\n", image->comps[0].prec); + } + + for (i = 0; i < 256; i++) { + fprintf(fdest, "%c%c%c%c", i, i, i, 0); + } + + for (i = 0; i < w * h; i++) { + unsigned char rc; + int r; + + r = image->comps[0].data[w * h - ((i) / (w) + 1) * w + (i) % (w)]; + r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0); + rc = (unsigned char) ((r >> adjustR)+((r >> (adjustR-1))%2)); + + fprintf(fdest, "%c", rc); + + if ((i + 1) % w == 0) { + for (pad = w % 4 ? 4 - w % 4 : 0; pad > 0; pad--) /* ADD */ + fprintf(fdest, "%c", 0); + } + } + fclose(fdest); + } + + return 0; +} + +/* -->> -->> -->> -->> + +PGX IMAGE FORMAT + +<<-- <<-- <<-- <<-- */ + + +unsigned char readuchar(FILE * f) +{ + unsigned char c1; + fread(&c1, 1, 1, f); + return c1; +} + +unsigned short readushort(FILE * f, int bigendian) +{ + unsigned char c1, c2; + fread(&c1, 1, 1, f); + fread(&c2, 1, 1, f); + if (bigendian) + return (c1 << 8) + c2; + else + return (c2 << 8) + c1; +} + +unsigned int readuint(FILE * f, int bigendian) +{ + unsigned char c1, c2, c3, c4; + fread(&c1, 1, 1, f); + fread(&c2, 1, 1, f); + fread(&c3, 1, 1, f); + fread(&c4, 1, 1, f); + if (bigendian) + return (c1 << 24) + (c2 << 16) + (c3 << 8) + c4; + else + return (c4 << 24) + (c3 << 16) + (c2 << 8) + c1; +} + +opj_image_t* pgxtoimage(const char *filename, opj_cparameters_t *parameters) { + FILE *f = NULL; + int w, h, prec; + int i, numcomps, max; + OPJ_COLOR_SPACE color_space; + opj_image_cmptparm_t cmptparm; /* maximum of 1 component */ + opj_image_t * image = NULL; + + char endian1,endian2,sign; + char signtmp[32]; + + char temp[32]; + int bigendian; + opj_image_comp_t *comp = NULL; + + numcomps = 1; + color_space = CLRSPC_GRAY; + + memset(&cmptparm, 0, sizeof(opj_image_cmptparm_t)); + + max = 0; + + f = fopen(filename, "rb"); + if (!f) { + fprintf(stderr, "Failed to open %s for reading !\n", filename); + return NULL; + } + + fseek(f, 0, SEEK_SET); + fscanf(f, "PG%[ \t]%c%c%[ \t+-]%d%[ \t]%d%[ \t]%d",temp,&endian1,&endian2,signtmp,&prec,temp,&w,temp,&h); + + i=0; + sign='+'; + while (signtmp[i]!='\0') { + if (signtmp[i]=='-') sign='-'; + i++; + } + + fgetc(f); + if (endian1=='M' && endian2=='L') { + bigendian = 1; + } else if (endian2=='M' && endian1=='L') { + bigendian = 0; + } else { + fprintf(stderr, "Bad pgx header, please check input file\n"); + return NULL; + } + + /* initialize image component */ + + cmptparm.x0 = parameters->image_offset_x0; + cmptparm.y0 = parameters->image_offset_y0; + cmptparm.w = !cmptparm.x0 ? (w - 1) * parameters->subsampling_dx + 1 : cmptparm.x0 + (w - 1) * parameters->subsampling_dx + 1; + cmptparm.h = !cmptparm.y0 ? (h - 1) * parameters->subsampling_dy + 1 : cmptparm.y0 + (h - 1) * parameters->subsampling_dy + 1; + + if (sign == '-') { + cmptparm.sgnd = 1; + } else { + cmptparm.sgnd = 0; + } + cmptparm.prec = prec; + cmptparm.bpp = prec; + cmptparm.dx = parameters->subsampling_dx; + cmptparm.dy = parameters->subsampling_dy; + + /* create the image */ + image = opj_image_create(numcomps, &cmptparm, color_space); + if(!image) { + fclose(f); + return NULL; + } + /* set image offset and reference grid */ + image->x0 = cmptparm.x0; + image->y0 = cmptparm.x0; + image->x1 = cmptparm.w; + image->y1 = cmptparm.h; + + /* set image data */ + + comp = &image->comps[0]; + + for (i = 0; i < w * h; i++) { + int v; + if (comp->prec <= 8) { + if (!comp->sgnd) { + v = readuchar(f); + } else { + v = (char) readuchar(f); + } + } else if (comp->prec <= 16) { + if (!comp->sgnd) { + v = readushort(f, bigendian); + } else { + v = (short) readushort(f, bigendian); + } + } else { + if (!comp->sgnd) { + v = readuint(f, bigendian); + } else { + v = (int) readuint(f, bigendian); + } + } + if (v > max) + max = v; + comp->data[i] = v; + } + fclose(f); + //comp->bpp = int_floorlog2(max) + 1; + + return image; +} + +int imagetopgx(opj_image_t * image, const char *outfile) { + int w, h; + int i, j; + unsigned int compno; + FILE *fdest = NULL; + + for (compno = 0; compno < image->numcomps; compno++) { + opj_image_comp_t *comp = &image->comps[compno]; + char bname[256]; /* buffer for name */ + char *name = bname; /* pointer */ + int nbytes = 0; + const size_t olen = strlen(outfile); + const size_t dotpos = olen - 4; + const size_t total = dotpos + 1 + 1 + 4; /* '-' + '[1-3]' + '.pgx' */ + if( outfile[dotpos] != '.' ) { + /* `pgx` was recognized but there is no dot at expected position */ + fprintf(stderr, "ERROR -> Impossible happen." ); + return 1; + } + if( total > 256 ) { + name = (char*)malloc(total+1); + } + strncpy(name, outfile, dotpos); + if (image->numcomps > 1) { + sprintf(name+dotpos, "-%d.pgx", compno); + } else { + strcpy(name+dotpos, ".pgx"); + } + fdest = fopen(name, "wb"); + if (!fdest) { + fprintf(stderr, "ERROR -> failed to open %s for writing\n", name); + return 1; + } + /* dont need name anymore */ + if( total > 256 ) { + free(name); + } + + w = image->comps[compno].w; + h = image->comps[compno].h; + + fprintf(fdest, "PG ML %c %d %d %d\n", comp->sgnd ? '-' : '+', comp->prec, w, h); + if (comp->prec <= 8) { + nbytes = 1; + } else if (comp->prec <= 16) { + nbytes = 2; + } else { + nbytes = 4; + } + for (i = 0; i < w * h; i++) { + int v = image->comps[compno].data[i]; + for (j = nbytes - 1; j >= 0; j--) { + char byte = (char) (v >> (j * 8)); + fwrite(&byte, 1, 1, fdest); + } + } + fclose(fdest); + } + + return 0; +} + +/* -->> -->> -->> -->> + +PNM IMAGE FORMAT + +<<-- <<-- <<-- <<-- */ + +opj_image_t* pnmtoimage(const char *filename, opj_cparameters_t *parameters) { + int subsampling_dx = parameters->subsampling_dx; + int subsampling_dy = parameters->subsampling_dy; + + FILE *f = NULL; + int i, compno, numcomps, w, h; + OPJ_COLOR_SPACE color_space; + opj_image_cmptparm_t cmptparm[3]; /* maximum of 3 components */ + opj_image_t * image = NULL; + char value; + + f = fopen(filename, "rb"); + if (!f) { + fprintf(stderr, "Failed to open %s for reading !!\n", filename); + return 0; + } + + if (fgetc(f) != 'P') + return 0; + value = fgetc(f); + + switch(value) { + case '2': /* greyscale image type */ + case '5': + numcomps = 1; + color_space = CLRSPC_GRAY; + break; + + case '3': /* RGB image type */ + case '6': + numcomps = 3; + color_space = CLRSPC_SRGB; + break; + + default: + fclose(f); + return NULL; + } + + fgetc(f); + + /* skip comments */ + while(fgetc(f) == '#') while(fgetc(f) != '\n'); + + fseek(f, -1, SEEK_CUR); + fscanf(f, "%d %d\n255", &w, &h); + fgetc(f); /* */ + + /* initialize image components */ + memset(&cmptparm[0], 0, 3 * sizeof(opj_image_cmptparm_t)); + for(i = 0; i < numcomps; i++) { + cmptparm[i].prec = 8; + cmptparm[i].bpp = 8; + cmptparm[i].sgnd = 0; + cmptparm[i].dx = subsampling_dx; + cmptparm[i].dy = subsampling_dy; + cmptparm[i].w = w; + cmptparm[i].h = h; + } + /* create the image */ + image = opj_image_create(numcomps, &cmptparm[0], color_space); + if(!image) { + fclose(f); + return NULL; + } + + /* set image offset and reference grid */ + image->x0 = parameters->image_offset_x0; + image->y0 = parameters->image_offset_y0; + image->x1 = parameters->image_offset_x0 + (w - 1) * subsampling_dx + 1; + image->y1 = parameters->image_offset_y0 + (h - 1) * subsampling_dy + 1; + + /* set image data */ + + if ((value == '2') || (value == '3')) { /* ASCII */ + for (i = 0; i < w * h; i++) { + for(compno = 0; compno < numcomps; compno++) { + unsigned int index = 0; + fscanf(f, "%u", &index); + /* compno : 0 = GREY, (0, 1, 2) = (R, G, B) */ + image->comps[compno].data[i] = index; + } + } + } else if ((value == '5') || (value == '6')) { /* BINARY */ + for (i = 0; i < w * h; i++) { + for(compno = 0; compno < numcomps; compno++) { + unsigned char index = 0; + fread(&index, 1, 1, f); + /* compno : 0 = GREY, (0, 1, 2) = (R, G, B) */ + image->comps[compno].data[i] = index; + } + } + } + + fclose(f); + + return image; +} + +int imagetopnm(opj_image_t * image, const char *outfile) { + int w, wr, h, hr, max; + int i; + unsigned int compno; + int adjustR, adjustG, adjustB, adjustX; + FILE *fdest = NULL; + char S2; + const char *tmp = outfile; + + while (*tmp) { + tmp++; + } + tmp--; + tmp--; + S2 = *tmp; + + if (image->numcomps == 3 && image->comps[0].dx == image->comps[1].dx + && image->comps[1].dx == image->comps[2].dx + && image->comps[0].dy == image->comps[1].dy + && image->comps[1].dy == image->comps[2].dy + && image->comps[0].prec == image->comps[1].prec + && image->comps[1].prec == image->comps[2].prec + && S2 !='g' && S2 !='G') { + + fdest = fopen(outfile, "wb"); + if (!fdest) { + fprintf(stderr, "ERROR -> failed to open %s for writing\n", outfile); + return 1; + } + + w = int_ceildiv(image->x1 - image->x0, image->comps[0].dx); + wr = image->comps[0].w; + + h = int_ceildiv(image->y1 - image->y0, image->comps[0].dy); + hr = image->comps[0].h; + + max = image->comps[0].prec > 8 ? 255 : (1 << image->comps[0].prec) - 1; + + image->comps[0].x0 = int_ceildivpow2(image->comps[0].x0 - int_ceildiv(image->x0, image->comps[0].dx), image->comps[0].factor); + image->comps[0].y0 = int_ceildivpow2(image->comps[0].y0 - int_ceildiv(image->y0, image->comps[0].dy), image->comps[0].factor); + + fprintf(fdest, "P6\n%d %d\n%d\n", wr, hr, max); + + if (image->comps[0].prec > 8) { + adjustR = image->comps[0].prec - 8; + printf("PNM CONVERSION: Truncating component 0 from %d bits to 8 bits\n", image->comps[0].prec); + } + else + adjustR = 0; + if (image->comps[1].prec > 8) { + adjustG = image->comps[1].prec - 8; + printf("PNM CONVERSION: Truncating component 1 from %d bits to 8 bits\n", image->comps[1].prec); + } + else + adjustG = 0; + if (image->comps[2].prec > 8) { + adjustB = image->comps[2].prec - 8; + printf("PNM CONVERSION: Truncating component 2 from %d bits to 8 bits\n", image->comps[2].prec); + } + else + adjustB = 0; + + + for (i = 0; i < wr * hr; i++) { + int r, g, b; + unsigned char rc,gc,bc; + r = image->comps[0].data[i]; + r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0); + rc = (unsigned char) ((r >> adjustR)+((r >> (adjustR-1))%2)); + + g = image->comps[1].data[i]; + g += (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0); + gc = (unsigned char) ((g >> adjustG)+((g >> (adjustG-1))%2)); + + b = image->comps[2].data[i]; + b += (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0); + bc = (unsigned char) ((b >> adjustB)+((b >> (adjustB-1))%2)); + + fprintf(fdest, "%c%c%c", rc, gc, bc); + } + fclose(fdest); + + } else { + unsigned int ncomp=(S2=='g' || S2=='G')?1:image->numcomps; + if (image->numcomps > ncomp) { + fprintf(stderr,"WARNING -> [PGM files] Only the first component\n"); + fprintf(stderr," is written to the file\n"); + } + for (compno = 0; compno < ncomp; compno++) { + char name[256]; + if (ncomp > 1) { + sprintf(name, "%d.%s", compno, outfile); + } else { + sprintf(name, "%s", outfile); + } + + fdest = fopen(name, "wb"); + if (!fdest) { + fprintf(stderr, "ERROR -> failed to open %s for writing\n", name); + return 1; + } + + w = int_ceildiv(image->x1 - image->x0, image->comps[compno].dx); + wr = image->comps[compno].w; + + h = int_ceildiv(image->y1 - image->y0, image->comps[compno].dy); + hr = image->comps[compno].h; + + max = image->comps[compno].prec > 8 ? 255 : (1 << image->comps[compno].prec) - 1; + + image->comps[compno].x0 = int_ceildivpow2(image->comps[compno].x0 - int_ceildiv(image->x0, image->comps[compno].dx), image->comps[compno].factor); + image->comps[compno].y0 = int_ceildivpow2(image->comps[compno].y0 - int_ceildiv(image->y0, image->comps[compno].dy), image->comps[compno].factor); + + fprintf(fdest, "P5\n%d %d\n%d\n", wr, hr, max); + + if (image->comps[compno].prec > 8) { + adjustX = image->comps[0].prec - 8; + printf("PNM CONVERSION: Truncating component %d from %d bits to 8 bits\n",compno, image->comps[compno].prec); + } + else + adjustX = 0; + + for (i = 0; i < wr * hr; i++) { + int l; + unsigned char lc; + l = image->comps[compno].data[i]; + l += (image->comps[compno].sgnd ? 1 << (image->comps[compno].prec - 1) : 0); + lc = (unsigned char) ((l >> adjustX)+((l >> (adjustX-1))%2)); + fprintf(fdest, "%c", lc); + } + fclose(fdest); + } + } + + return 0; +} + +/* -->> -->> -->> -->> + + TIFF IMAGE FORMAT + + <<-- <<-- <<-- <<-- */ + +typedef struct tiff_infoheader{ + DWORD tiWidth; // Width of Image in pixel + DWORD tiHeight; // Height of Image in pixel + DWORD tiPhoto; // Photometric + WORD tiBps; // Bits per sample + WORD tiSf; // Sample Format + WORD tiSpp; // Sample per pixel 1-bilevel,gray scale , 2- RGB + WORD tiPC; // Planar config (1-Interleaved, 2-Planarcomp) +}tiff_infoheader_t; + +int imagetotif(opj_image_t * image, const char *outfile) { + int width, height, imgsize; + int bps,index,adjust = 0; + int last_i=0; + TIFF *tif; + tdata_t buf; + tstrip_t strip; + tsize_t strip_size; + + if (image->numcomps == 3 && image->comps[0].dx == image->comps[1].dx + && image->comps[1].dx == image->comps[2].dx + && image->comps[0].dy == image->comps[1].dy + && image->comps[1].dy == image->comps[2].dy + && image->comps[0].prec == image->comps[1].prec + && image->comps[1].prec == image->comps[2].prec) { + + /* -->> -->> -->> + RGB color + <<-- <<-- <<-- */ + + tif = TIFFOpen(outfile, "wb"); + if (!tif) { + fprintf(stderr, "ERROR -> failed to open %s for writing\n", outfile); + return 1; + } + + width = image->comps[0].w; + height = image->comps[0].h; + imgsize = width * height ; + bps = image->comps[0].prec; + /* Set tags */ + TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width); + TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height); + TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3); + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bps); + TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); + TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); + TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, 1); + + /* Get a buffer for the data */ + strip_size=TIFFStripSize(tif); + buf = _TIFFmalloc(strip_size); + index=0; + adjust = image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0; + for (strip = 0; strip < TIFFNumberOfStrips(tif); strip++) { + unsigned char *dat8; + int i, ssize; + ssize = TIFFStripSize(tif); + dat8 = (unsigned char*)buf; + if (image->comps[0].prec == 8){ + for (i=0; icomps[0].data[index]; + g = image->comps[1].data[index]; + b = image->comps[2].data[index]; + if (image->comps[0].sgnd){ + r += adjust; + g += adjust; + b += adjust; + } + dat8[i+0] = r ; // R + dat8[i+1] = g ; // G + dat8[i+2] = b ; // B + index++; + last_i = i+3; + }else + break; + } + if(last_i < ssize){ + for (i=last_i; icomps[0].data[index]; + g = image->comps[1].data[index]; + b = image->comps[2].data[index]; + if (image->comps[0].sgnd){ + r += adjust; + g += adjust; + b += adjust; + } + dat8[i+0] = r ; // R + if(i+1 comps[0].prec == 12){ + for (i=0; icomps[0].data[index]; + g = image->comps[1].data[index]; + b = image->comps[2].data[index]; + r1 = image->comps[0].data[index+1]; + g1 = image->comps[1].data[index+1]; + b1 = image->comps[2].data[index+1]; + if (image->comps[0].sgnd){ + r += adjust; + g += adjust; + b += adjust; + r1 += adjust; + g1 += adjust; + b1 += adjust; + } + dat8[i+0] = (r >> 4); + dat8[i+1] = ((r & 0x0f) << 4 )|((g >> 8)& 0x0f); + dat8[i+2] = g ; + dat8[i+3] = (b >> 4); + dat8[i+4] = ((b & 0x0f) << 4 )|((r1 >> 8)& 0x0f); + dat8[i+5] = r1; + dat8[i+6] = (g1 >> 4); + dat8[i+7] = ((g1 & 0x0f)<< 4 )|((b1 >> 8)& 0x0f); + dat8[i+8] = b1; + index+=2; + last_i = i+9; + }else + break; + } + if(last_i < ssize){ + for (i= last_i; icomps[0].data[index]; + g = image->comps[1].data[index]; + b = image->comps[2].data[index]; + r1 = image->comps[0].data[index+1]; + g1 = image->comps[1].data[index+1]; + b1 = image->comps[2].data[index+1]; + if (image->comps[0].sgnd){ + r += adjust; + g += adjust; + b += adjust; + r1 += adjust; + g1 += adjust; + b1 += adjust; + } + dat8[i+0] = (r >> 4); + if(i+1 > 8)& 0x0f); else break; + if(i+2 > 4); else break; + if(i+4 > 8)& 0x0f);else break; + if(i+5 > 4); else break; + if(i+7 > 8)& 0x0f);else break; + if(i+8 comps[0].prec == 16){ + for (i=0 ; icomps[0].data[index]; + g = image->comps[1].data[index]; + b = image->comps[2].data[index]; + if (image->comps[0].sgnd){ + r += adjust; + g += adjust; + b += adjust; + } + dat8[i+0] = r;//LSB + dat8[i+1] = (r >> 8);//MSB + dat8[i+2] = g; + dat8[i+3] = (g >> 8); + dat8[i+4] = b; + dat8[i+5] = (b >> 8); + index++; + last_i = i+6; + }else + break; + } + if(last_i < ssize){ + for (i=0 ; icomps[0].data[index]; + g = image->comps[1].data[index]; + b = image->comps[2].data[index]; + if (image->comps[0].sgnd){ + r += adjust; + g += adjust; + b += adjust; + } + dat8[i+0] = r;//LSB + if(i+1 > 8);else break;//MSB + if(i+2 > 8);else break; + if(i+4 > 8);else break; + index++; + }else + break; + } + } + }else{ + fprintf(stderr,"Bits=%d, Only 8,12,16 bits implemented\n",image->comps[0].prec); + fprintf(stderr,"Aborting\n"); + return 1; + } + TIFFWriteEncodedStrip(tif, strip, buf, strip_size); + } + _TIFFfree(buf); + TIFFClose(tif); + }else if (image->numcomps == 1){ + /* -->> -->> -->> + Black and White + <<-- <<-- <<-- */ + + tif = TIFFOpen(outfile, "wb"); + if (!tif) { + fprintf(stderr, "ERROR -> failed to open %s for writing\n", outfile); + return 1; + } + + width = image->comps[0].w; + height = image->comps[0].h; + imgsize = width * height; + bps = image->comps[0].prec; + + /* Set tags */ + TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width); + TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height); + TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1); + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bps); + TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); + TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); + TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, 1); + + /* Get a buffer for the data */ + strip_size = TIFFStripSize(tif); + buf = _TIFFmalloc(strip_size); + index = 0; + for (strip = 0; strip < TIFFNumberOfStrips(tif); strip++) { + unsigned char *dat8; + int i; + dat8 = (unsigned char*)buf; + if (image->comps[0].prec == 8){ + for (i=0; icomps[0].data[index]; + if (image->comps[0].sgnd){ + r += adjust; + } + dat8[i+0] = r; + index++; + }else + break; + } + }else if (image->comps[0].prec == 12){ + for (i = 0; icomps[0].data[index]; + r1 = image->comps[0].data[index+1]; + if (image->comps[0].sgnd){ + r += adjust; + r1 += adjust; + } + dat8[i+0] = (r >> 4); + dat8[i+1] = ((r & 0x0f) << 4 )|((r1 >> 8)& 0x0f); + dat8[i+2] = r1 ; + index+=2; + }else + break; + } + }else if (image->comps[0].prec == 16){ + for (i=0; icomps[0].data[index]; + if (image->comps[0].sgnd){ + r += adjust; + } + dat8[i+0] = r; + dat8[i+1] = r >> 8; + index++; + }else + break; + } + }else{ + fprintf(stderr,"TIFF file creation. Bits=%d, Only 8,12,16 bits implemented\n",image->comps[0].prec); + fprintf(stderr,"Aborting\n"); + return 1; + } + TIFFWriteEncodedStrip(tif, strip, buf, strip_size); + } + _TIFFfree(buf); + TIFFClose(tif); + }else{ + fprintf(stderr,"TIFF file creation. Bad color format. Only RGB & Grayscale has been implemented\n"); + fprintf(stderr,"Aborting\n"); + return 1; + } + return 0; +} + +opj_image_t* tiftoimage(const char *filename, opj_cparameters_t *parameters) +{ + int subsampling_dx = parameters->subsampling_dx; + int subsampling_dy = parameters->subsampling_dy; + TIFF *tif; + tiff_infoheader_t Info; + tdata_t buf; + tstrip_t strip; + tsize_t strip_size; + int j, numcomps, w, h,index; + OPJ_COLOR_SPACE color_space; + opj_image_cmptparm_t cmptparm[3]; + opj_image_t * image = NULL; + int imgsize = 0; + + tif = TIFFOpen(filename, "r"); + + if (!tif) { + fprintf(stderr, "Failed to open %s for reading\n", filename); + return 0; + } + + TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &Info.tiWidth); + TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &Info.tiHeight); + TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &Info.tiBps); + TIFFGetField(tif, TIFFTAG_SAMPLEFORMAT, &Info.tiSf); + TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &Info.tiSpp); + Info.tiPhoto = 0; + TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &Info.tiPhoto); + TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &Info.tiPC); + w= Info.tiWidth; + h= Info.tiHeight; + + if (Info.tiPhoto == 2) { + /* -->> -->> -->> + RGB color + <<-- <<-- <<-- */ + + numcomps = 3; + color_space = CLRSPC_SRGB; + /* initialize image components*/ + memset(&cmptparm[0], 0, 3 * sizeof(opj_image_cmptparm_t)); + for(j = 0; j < numcomps; j++) { + if (parameters->cp_cinema) { + cmptparm[j].prec = 12; + cmptparm[j].bpp = 12; + }else{ + cmptparm[j].prec = Info.tiBps; + cmptparm[j].bpp = Info.tiBps; + } + cmptparm[j].sgnd = 0; + cmptparm[j].dx = subsampling_dx; + cmptparm[j].dy = subsampling_dy; + cmptparm[j].w = w; + cmptparm[j].h = h; + } + /* create the image*/ + image = opj_image_create(numcomps, &cmptparm[0], color_space); + if(!image) { + TIFFClose(tif); + return NULL; + } + + /* set image offset and reference grid */ + image->x0 = parameters->image_offset_x0; + image->y0 = parameters->image_offset_y0; + image->x1 = !image->x0 ? (w - 1) * subsampling_dx + 1 : image->x0 + (w - 1) * subsampling_dx + 1; + image->y1 = !image->y0 ? (h - 1) * subsampling_dy + 1 : image->y0 + (h - 1) * subsampling_dy + 1; + + buf = _TIFFmalloc(TIFFStripSize(tif)); + strip_size=0; + strip_size=TIFFStripSize(tif); + index = 0; + imgsize = image->comps[0].w * image->comps[0].h ; + /* Read the Image components*/ + for (strip = 0; strip < TIFFNumberOfStrips(tif); strip++) { + unsigned char *dat8; + int i, ssize; + ssize = TIFFReadEncodedStrip(tif, strip, buf, strip_size); + dat8 = (unsigned char*)buf; + + if (Info.tiBps==12){ + for (i=0; icomps[0].data[index] = ( dat8[i+0]<<4 ) |(dat8[i+1]>>4); + image->comps[1].data[index] = ((dat8[i+1]& 0x0f)<< 8) | dat8[i+2]; + image->comps[2].data[index] = ( dat8[i+3]<<4) |(dat8[i+4]>>4); + image->comps[0].data[index+1] = ((dat8[i+4]& 0x0f)<< 8) | dat8[i+5]; + image->comps[1].data[index+1] = ( dat8[i+6] <<4) |(dat8[i+7]>>4); + image->comps[2].data[index+1] = ((dat8[i+7]& 0x0f)<< 8) | dat8[i+8]; + index+=2; + }else + break; + } + } + else if( Info.tiBps==16){ + for (i=0; icomps[0].data[index] = ( dat8[i+1] << 8 ) | dat8[i+0]; // R + image->comps[1].data[index] = ( dat8[i+3] << 8 ) | dat8[i+2]; // G + image->comps[2].data[index] = ( dat8[i+5] << 8 ) | dat8[i+4]; // B + if(parameters->cp_cinema){/* Rounding to 12 bits*/ + image->comps[0].data[index] = (image->comps[0].data[index] + 0x08) >> 4 ; + image->comps[1].data[index] = (image->comps[1].data[index] + 0x08) >> 4 ; + image->comps[2].data[index] = (image->comps[2].data[index] + 0x08) >> 4 ; + } + index++; + }else + break; + } + } + else if ( Info.tiBps==8){ + for (i=0; icomps[0].data[index] = dat8[i+0];// R + image->comps[1].data[index] = dat8[i+1];// G + image->comps[2].data[index] = dat8[i+2];// B + if(parameters->cp_cinema){/* Rounding to 12 bits*/ + image->comps[0].data[index] = image->comps[0].data[index] << 4 ; + image->comps[1].data[index] = image->comps[1].data[index] << 4 ; + image->comps[2].data[index] = image->comps[2].data[index] << 4 ; + } + index++; + }else + break; + } + } + else{ + fprintf(stderr,"TIFF file creation. Bits=%d, Only 8,12,16 bits implemented\n",Info.tiBps); + fprintf(stderr,"Aborting\n"); + return NULL; + } + } + + _TIFFfree(buf); + TIFFClose(tif); + }else if(Info.tiPhoto == 1) { + /* -->> -->> -->> + Black and White + <<-- <<-- <<-- */ + + numcomps = 1; + color_space = CLRSPC_GRAY; + /* initialize image components*/ + memset(&cmptparm[0], 0, sizeof(opj_image_cmptparm_t)); + cmptparm[0].prec = Info.tiBps; + cmptparm[0].bpp = Info.tiBps; + cmptparm[0].sgnd = 0; + cmptparm[0].dx = subsampling_dx; + cmptparm[0].dy = subsampling_dy; + cmptparm[0].w = w; + cmptparm[0].h = h; + + /* create the image*/ + image = opj_image_create(numcomps, &cmptparm[0], color_space); + if(!image) { + TIFFClose(tif); + return NULL; + } + /* set image offset and reference grid */ + image->x0 = parameters->image_offset_x0; + image->y0 = parameters->image_offset_y0; + image->x1 = !image->x0 ? (w - 1) * subsampling_dx + 1 : image->x0 + (w - 1) * subsampling_dx + 1; + image->y1 = !image->y0 ? (h - 1) * subsampling_dy + 1 : image->y0 + (h - 1) * subsampling_dy + 1; + + buf = _TIFFmalloc(TIFFStripSize(tif)); + strip_size = 0; + strip_size = TIFFStripSize(tif); + index = 0; + imgsize = image->comps[0].w * image->comps[0].h ; + /* Read the Image components*/ + for (strip = 0; strip < TIFFNumberOfStrips(tif); strip++) { + unsigned char *dat8; + int i, ssize; + ssize = TIFFReadEncodedStrip(tif, strip, buf, strip_size); + dat8 = (unsigned char*)buf; + + if (Info.tiBps==12){ + for (i=0; icomps[0].data[index] = ( dat8[i+0]<<4 ) |(dat8[i+1]>>4) ; + image->comps[0].data[index+1] = ((dat8[i+1]& 0x0f)<< 8) | dat8[i+2]; + index+=2; + }else + break; + } + } + else if( Info.tiBps==16){ + for (i=0; icomps[0].data[index] = ( dat8[i+1] << 8 ) | dat8[i+0]; + index++; + }else + break; + } + } + else if ( Info.tiBps==8){ + for (i=0; icomps[0].data[index] = dat8[i+0]; + index++; + }else + break; + } + } + else{ + fprintf(stderr,"TIFF file creation. Bits=%d, Only 8,12,16 bits implemented\n",Info.tiBps); + fprintf(stderr,"Aborting\n"); + return NULL; + } + } + + _TIFFfree(buf); + TIFFClose(tif); + }else{ + fprintf(stderr,"TIFF file creation. Bad color format. Only RGB & Grayscale has been implemented\n"); + fprintf(stderr,"Aborting\n"); + return NULL; + } + return image; +} + +/* -->> -->> -->> -->> + + RAW IMAGE FORMAT + + <<-- <<-- <<-- <<-- */ + +opj_image_t* rawtoimage(const char *filename, opj_cparameters_t *parameters, raw_cparameters_t *raw_cp) { + int subsampling_dx = parameters->subsampling_dx; + int subsampling_dy = parameters->subsampling_dy; + + FILE *f = NULL; + int i, compno, numcomps, w, h; + OPJ_COLOR_SPACE color_space; + opj_image_cmptparm_t *cmptparm; + opj_image_t * image = NULL; + unsigned short ch; + + if((! (raw_cp->rawWidth & raw_cp->rawHeight & raw_cp->rawComp & raw_cp->rawBitDepth)) == 0) + { + fprintf(stderr,"\nError: invalid raw image parameters\n"); + fprintf(stderr,"Please use the Format option -F:\n"); + fprintf(stderr,"-F rawWidth,rawHeight,rawComp,rawBitDepth,s/u (Signed/Unsigned)\n"); + fprintf(stderr,"Example: -i lena.raw -o lena.j2k -F 512,512,3,8,u\n"); + fprintf(stderr,"Aborting\n"); + return NULL; + } + + f = fopen(filename, "rb"); + if (!f) { + fprintf(stderr, "Failed to open %s for reading !!\n", filename); + fprintf(stderr,"Aborting\n"); + return NULL; + } + numcomps = raw_cp->rawComp; + color_space = CLRSPC_SRGB; + w = raw_cp->rawWidth; + h = raw_cp->rawHeight; + cmptparm = (opj_image_cmptparm_t*) malloc(numcomps * sizeof(opj_image_cmptparm_t)); + + /* initialize image components */ + memset(&cmptparm[0], 0, numcomps * sizeof(opj_image_cmptparm_t)); + for(i = 0; i < numcomps; i++) { + cmptparm[i].prec = raw_cp->rawBitDepth; + cmptparm[i].bpp = raw_cp->rawBitDepth; + cmptparm[i].sgnd = raw_cp->rawSigned; + cmptparm[i].dx = subsampling_dx; + cmptparm[i].dy = subsampling_dy; + cmptparm[i].w = w; + cmptparm[i].h = h; + } + /* create the image */ + image = opj_image_create(numcomps, &cmptparm[0], color_space); + if(!image) { + fclose(f); + return NULL; + } + /* set image offset and reference grid */ + image->x0 = parameters->image_offset_x0; + image->y0 = parameters->image_offset_y0; + image->x1 = parameters->image_offset_x0 + (w - 1) * subsampling_dx + 1; + image->y1 = parameters->image_offset_y0 + (h - 1) * subsampling_dy + 1; + + if(raw_cp->rawBitDepth <= 8) + { + unsigned char value = 0; + for(compno = 0; compno < numcomps; compno++) { + for (i = 0; i < w * h; i++) { + if (!fread(&value, 1, 1, f)) { + fprintf(stderr,"Error reading raw file. End of file probably reached.\n"); + return NULL; + } + image->comps[compno].data[i] = raw_cp->rawSigned?(char)value:value; + } + } + } + else if(raw_cp->rawBitDepth <= 16) + { + unsigned short value; + for(compno = 0; compno < numcomps; compno++) { + for (i = 0; i < w * h; i++) { + unsigned char temp; + if (!fread(&temp, 1, 1, f)) { + fprintf(stderr,"Error reading raw file. End of file probably reached.\n"); + return NULL; + } + value = temp << 8; + if (!fread(&temp, 1, 1, f)) { + fprintf(stderr,"Error reading raw file. End of file probably reached.\n"); + return NULL; + } + value += temp; + image->comps[compno].data[i] = raw_cp->rawSigned?(short)value:value; + } + } + } + else { + fprintf(stderr,"OpenJPEG cannot encode raw components with bit depth higher than 16 bits.\n"); + return NULL; + } + + if (fread(&ch, 1, 1, f)) { + fprintf(stderr,"Warning. End of raw file not reached... processing anyway\n"); + } + fclose(f); + + return image; +} + +int imagetoraw(opj_image_t * image, const char *outfile) +{ + FILE *rawFile = NULL; + unsigned int compno; + int w, h; + int line, row; + int *ptr; + + if((image->numcomps * image->x1 * image->y1) == 0) + { + fprintf(stderr,"\nError: invalid raw image parameters\n"); + return 1; + } + + rawFile = fopen(outfile, "wb"); + if (!rawFile) { + fprintf(stderr, "Failed to open %s for writing !!\n", outfile); + return 1; + } + + fprintf(stdout,"Raw image characteristics: %d components\n", image->numcomps); + + for(compno = 0; compno < image->numcomps; compno++) + { + fprintf(stdout,"Component %d characteristics: %dx%dx%d %s\n", compno, image->comps[compno].w, + image->comps[compno].h, image->comps[compno].prec, image->comps[compno].sgnd==1 ? "signed": "unsigned"); + + w = image->comps[compno].w; + h = image->comps[compno].h; + + if(image->comps[compno].prec <= 8) + { + if(image->comps[compno].sgnd == 1) + { + signed char curr; + int mask = (1 << image->comps[compno].prec) - 1; + ptr = image->comps[compno].data; + for (line = 0; line < h; line++) { + for(row = 0; row < w; row++) { + curr = (signed char) (*ptr & mask); + fwrite(&curr, sizeof(signed char), 1, rawFile); + ptr++; + } + } + } + else if(image->comps[compno].sgnd == 0) + { + unsigned char curr; + int mask = (1 << image->comps[compno].prec) - 1; + ptr = image->comps[compno].data; + for (line = 0; line < h; line++) { + for(row = 0; row < w; row++) { + curr = (unsigned char) (*ptr & mask); + fwrite(&curr, sizeof(unsigned char), 1, rawFile); + ptr++; + } + } + } + } + else if(image->comps[compno].prec <= 16) + { + if(image->comps[compno].sgnd == 1) + { + signed short int curr; + int mask = (1 << image->comps[compno].prec) - 1; + ptr = image->comps[compno].data; + for (line = 0; line < h; line++) { + for(row = 0; row < w; row++) { + unsigned char temp; + curr = (signed short int) (*ptr & mask); + temp = curr >> 8; + fwrite(&temp, 1, 1, rawFile); + temp = curr; + fwrite(&temp, 1, 1, rawFile); + ptr++; + } + } + } + else if(image->comps[compno].sgnd == 0) + { + unsigned short int curr; + int mask = (1 << image->comps[compno].prec) - 1; + ptr = image->comps[compno].data; + for (line = 0; line < h; line++) { + for(row = 0; row < w; row++) { + unsigned char temp; + curr = (unsigned short int) (*ptr & mask); + temp = curr >> 8; + fwrite(&temp, 1, 1, rawFile); + temp = curr; + fwrite(&temp, 1, 1, rawFile); + ptr++; + } + } + } + } + else if (image->comps[compno].prec <= 32) + { + fprintf(stderr,"More than 16 bits per component no handled yet\n"); + return 1; + } + else + { + fprintf(stderr,"Error: invalid precision: %d\n", image->comps[compno].prec); + return 1; + } + } + fclose(rawFile); + return 0; +} + +opj_image_t *pngtoimage(const char *read_idf, opj_cparameters_t * params) +#ifdef WIN32 +{ + printf("Error. PNG format is not yet handled under windows\n"); + return NULL; +} +#else +{ + png_bytep row; + png_structp png; + png_infop info; + double gamma, display_exponent; + int bit_depth, interlace_type, compression_type, filter_type; + int unit, pass, nr_passes; + png_uint_32 resx, resy; + unsigned int i, max, src_w; + png_uint_32 width, height; + int color_type, has_alpha; + unsigned char *png_buf, *s; + FILE *reader; +/* j2k: */ + opj_image_t *image; + opj_image_cmptparm_t cmptparm[4]; + int sub_dx, sub_dy; + unsigned int nr_comp; + int *r, *g, *b, *a; + + if ((reader = fopen(read_idf, "rb")) == NULL) { + fprintf(stderr, "pngtoimage: can not open %s\n", read_idf); + return NULL; + } + nr_passes = 0; + png_buf = NULL; + +/* libpng-VERSION/example.c: + * PC : screen_gamma = 2.2; + * Mac: screen_gamma = 1.7 or 1.0; +*/ + display_exponent = 2.2; + + if ((png = png_create_read_struct(PNG_LIBPNG_VER_STRING, + NULL, NULL, NULL)) == NULL) + goto fin; + if ((info = png_create_info_struct(png)) == NULL) + goto fin; + + if (setjmp(png_jmpbuf(png))) + goto fin; + + png_init_io(png, reader); + png_read_info(png, info); + + png_get_IHDR(png, info, &width, &height, + &bit_depth, &color_type, &interlace_type, + &compression_type, &filter_type); + + if (color_type == PNG_COLOR_TYPE_PALETTE) + png_set_expand(png); + else if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) + png_set_expand(png); + + if (png_get_valid(png, info, PNG_INFO_tRNS)) + png_set_expand(png); + + if (bit_depth == 16) + png_set_strip_16(png); + +/* GRAY => RGB; GRAY_ALPHA => RGBA +*/ + if (color_type == PNG_COLOR_TYPE_GRAY + || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { + png_set_gray_to_rgb(png); + color_type = + (color_type == PNG_COLOR_TYPE_GRAY ? PNG_COLOR_TYPE_RGB : + PNG_COLOR_TYPE_RGB_ALPHA); + } + if (!png_get_gAMA(png, info, &gamma)) + gamma = 0.45455; + + png_set_gamma(png, display_exponent, gamma); + + nr_passes = png_set_interlace_handling(png); + + png_read_update_info(png, info); + + png_get_pHYs(png, info, &resx, &resy, &unit); + + color_type = png_get_color_type(png, info); + + has_alpha = (color_type == PNG_COLOR_TYPE_RGB_ALPHA); + + if (has_alpha) + nr_comp = 4; + else + nr_comp = 3; + + src_w = width * nr_comp; + png_buf = (unsigned char *) malloc(src_w * height); + + if (nr_passes == 0) + nr_passes = 1; + + for (pass = 0; pass < nr_passes; pass++) { + s = png_buf; + + for (i = 0; i < height; i++) { +/* libpng.3: + * If you want the "sparkle" effect, just call png_read_rows() as + * normal, with the third parameter NULL. +*/ + png_read_rows(png, &s, NULL, 1); + + s += src_w; + } + } + memset(&cmptparm, 0, 4 * sizeof(opj_image_cmptparm_t)); + + sub_dx = params->subsampling_dx; + sub_dy = params->subsampling_dy; + + for (i = 0; i < nr_comp; ++i) { + cmptparm[i].prec = 8; + cmptparm[i].bpp = 8; + cmptparm[i].sgnd = 0; + cmptparm[i].dx = sub_dx; + cmptparm[i].dy = sub_dy; + cmptparm[i].w = width; + cmptparm[i].h = height; + } + + image = opj_image_create(nr_comp, &cmptparm[0], CLRSPC_SRGB); + + if (image == NULL) + goto fin; + + image->x0 = params->image_offset_x0; + image->y0 = params->image_offset_y0; + image->x1 = + params->image_offset_x0 + (width - 1) * sub_dx + 1 + image->x0; + image->y1 = + params->image_offset_y0 + (height - 1) * sub_dy + 1 + image->y0; + + r = image->comps[0].data; + g = image->comps[1].data; + b = image->comps[2].data; + a = image->comps[3].data; + s = png_buf; + + max = width * height; + + for (i = 0; i < max; ++i) { + *r++ = *s++; + *g++ = *s++; + *b++ = *s++; + + if (has_alpha) + *a++ = *s++; + } + + fin: + if (png) + png_destroy_read_struct(&png, &info, NULL); + if (png_buf) + free(png_buf); + + fclose(reader); + + return image; + +} /* pngtoimage() */ +#endif + +int imagetopng(opj_image_t * image, const char *write_idf) +#ifdef WIN32 +{ + printf("Error. PNG format is not yet handled under windows\n"); + return -1; +} +#else +{ + FILE *writer; + png_structp png_ptr; + png_infop info_ptr; + int *rs, *gs, *bs, *as; + unsigned char *row_buf, *d; + int fails, mono, graya, rgb, rgba; + int width, height, nr_colors, color_type; + int bit_depth, adjust, x, y; + png_color_8 sig_bit; + + writer = fopen(write_idf, "wb"); + + if (writer == NULL) + return 1; + + info_ptr = NULL; + fails = 1; + +/* Create and initialize the png_struct with the desired error handler + * functions. If you want to use the default stderr and longjump method, + * you can supply NULL for the last three parameters. We also check that + * the library version is compatible with the one used at compile time, + * in case we are using dynamically linked libraries. REQUIRED. +*/ + png_ptr = + png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); +/*png_voidp user_error_ptr, user_error_fn, user_warning_fn); */ + + if (png_ptr == NULL) + goto fin; + +/* Allocate/initialize the image information data. REQUIRED +*/ + info_ptr = png_create_info_struct(png_ptr); + + if (info_ptr == NULL) + goto fin; + +/* Set error handling. REQUIRED if you are not supplying your own + * error handling functions in the png_create_write_struct() call. +*/ + if (setjmp(png_jmpbuf(png_ptr))) + goto fin; + +/* I/O initialization functions is REQUIRED +*/ + png_init_io(png_ptr, writer); + +/* Set the image information here. Width and height are up to 2^31, + * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on + * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY, + * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB, + * or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or + * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST + * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. + * REQUIRED +*/ + png_set_compression_level(png_ptr, Z_BEST_COMPRESSION); + + mono = graya = rgb = rgba = adjust = 0; + + nr_colors = image->numcomps; + width = image->comps[0].w; + height = image->comps[0].h; + rs = image->comps[0].data; + + if (nr_colors == 2) { + graya = 1; + color_type = PNG_COLOR_TYPE_GRAY_ALPHA; + sig_bit.gray = image->comps[0].prec; + bit_depth = image->comps[0].prec; + as = image->comps[1].data; + } else if (nr_colors == 3) { + rgb = 1; + color_type = PNG_COLOR_TYPE_RGB; + sig_bit.red = image->comps[0].prec; + sig_bit.green = image->comps[1].prec; + sig_bit.blue = image->comps[2].prec; + bit_depth = image->comps[0].prec; + gs = image->comps[1].data; + bs = image->comps[2].data; + if (image->comps[0].sgnd) + adjust = 1 << (image->comps[0].prec - 1); + } else if (nr_colors == 4) { + rgb = rgba = 1; + color_type = PNG_COLOR_TYPE_RGB_ALPHA; + sig_bit.red = image->comps[0].prec; + sig_bit.green = image->comps[1].prec; + sig_bit.blue = image->comps[2].prec; + sig_bit.alpha = image->comps[3].prec; + bit_depth = image->comps[0].prec; + gs = image->comps[1].data; + bs = image->comps[2].data; + as = image->comps[3].data; + if (image->comps[0].sgnd) + adjust = 1 << (image->comps[0].prec - 1); + } else { + mono = 1; + color_type = PNG_COLOR_TYPE_GRAY; + sig_bit.gray = image->comps[0].prec; + bit_depth = image->comps[0].prec; + } + png_set_sBIT(png_ptr, info_ptr, &sig_bit); + + png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, + color_type, + PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + +#ifdef HIDDEN_CODE +/* Optional gamma chunk is strongly suggested if you have any guess + * as to the correct gamma of the image. +*/ + + if (gamma > 0.0) { + png_set_gAMA(png_ptr, info_ptr, gamma); + } +#endif /* HIDDEN_CODE */ +#ifdef HIDDEN_CODE + if (have_bg) { + png_color_16 background; + + background.red = bg_red; + background.green = bg_green; + background.blue = bg_blue; + + png_set_bKGD(png_ptr, info_ptr, &background); + } +#endif /* HIDDEN_CODE */ + png_write_info(png_ptr, info_ptr); + + png_set_packing(png_ptr); + + row_buf = (unsigned char *) malloc(width * nr_colors); + + for (y = 0; y < height; ++y) { + d = row_buf; + + for (x = 0; x < width; ++x) { + if (mono) { + *d++ = (unsigned char) *rs++; + } + if (graya) { + *d++ = (unsigned char) *rs++; + *d++ = (unsigned char) *as++; + } else if (rgb) { + *d++ = (unsigned char) (*rs++ + adjust); + *d++ = (unsigned char) (*gs++ + adjust); + *d++ = (unsigned char) (*bs++ + adjust); + + if (rgba) + *d++ = (unsigned char) (*as++ + adjust); + } + } /* for(x) */ + + png_write_row(png_ptr, row_buf); + + } /* for(y) */ + + png_write_end(png_ptr, info_ptr); + + fails = 0; + + fin: + + if (png_ptr) { + png_destroy_write_struct(&png_ptr, &info_ptr); + } + fclose(writer); + + return fails; +} +#endif diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/codec/convert.h b/gdcm/Utilities/gdcmopenjpeg-v2/codec/convert.h new file mode 100644 index 0000000..7d8670a --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/codec/convert.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __J2K_CONVERT_H +#define __J2K_CONVERT_H + +/**@name RAW image encoding parameters */ +/*@{*/ +typedef struct raw_cparameters { + /** width of the raw image */ + int rawWidth; + /** height of the raw image */ + int rawHeight; + /** components of the raw image */ + int rawComp; + /** bit depth of the raw image */ + int rawBitDepth; + /** signed/unsigned raw image */ + bool rawSigned; + /*@}*/ +} raw_cparameters_t; + +/* TGA conversion */ +opj_image_t* tgatoimage(const char *filename, opj_cparameters_t *parameters); +int imagetotga(opj_image_t * image, const char *outfile); + +/* BMP conversion */ +opj_image_t* bmptoimage(const char *filename, opj_cparameters_t *parameters); +int imagetobmp(opj_image_t *image, const char *outfile); + +/* TIFF to image conversion*/ +opj_image_t* tiftoimage(const char *filename, opj_cparameters_t *parameters); +int imagetotif(opj_image_t *image, const char *outfile); +/** +Load a single image component encoded in PGX file format +@param filename Name of the PGX file to load +@param parameters *List ?* +@return Returns a greyscale image if successful, returns NULL otherwise +*/ +opj_image_t* pgxtoimage(const char *filename, opj_cparameters_t *parameters); +int imagetopgx(opj_image_t *image, const char *outfile); + +opj_image_t* pnmtoimage(const char *filename, opj_cparameters_t *parameters); +int imagetopnm(opj_image_t *image, const char *outfile); + +/* RAW conversion */ +int imagetoraw(opj_image_t * image, const char *outfile); +opj_image_t* rawtoimage(const char *filename, opj_cparameters_t *parameters, raw_cparameters_t *raw_cp); + +#endif /* __J2K_CONVERT_H */ + diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/codec/dirent.h b/gdcm/Utilities/gdcmopenjpeg-v2/codec/dirent.h new file mode 100644 index 0000000..b0539fb --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/codec/dirent.h @@ -0,0 +1,677 @@ + +/* + * uce-dirent.h - operating system independent dirent implementation + * + * Copyright (C) 1998-2002 Toni Ronkko + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * ``Software''), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL TONI RONKKO BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * + * May 28 1998, Toni Ronkko + * + * $Id: uce-dirent.h,v 1.7 2002/05/13 10:48:35 tr Exp $ + * + * $Log: uce-dirent.h,v $ + * Revision 1.7 2002/05/13 10:48:35 tr + * embedded some source code directly to the header so that no source + * modules need to be included in the MS Visual C project using the + * interface, removed all the dependencies to other headers of the `uce' + * library so that the header can be made public + * + * Revision 1.6 2002/04/12 16:22:04 tr + * Unified Compiling Environment (UCE) replaced `std' library + * + * Revision 1.5 2001/07/20 16:33:40 tr + * moved to `std' library and re-named defines accordingly + * + * Revision 1.4 2001/07/10 16:47:18 tronkko + * revised comments + * + * Revision 1.3 2001/01/11 13:16:43 tr + * using ``uce-machine.h'' for finding out defines such as `FREEBSD' + * + * Revision 1.2 2000/10/08 16:00:41 tr + * copy of FreeBSD man page + * + * Revision 1.1 2000/07/10 05:53:16 tr + * Initial revision + * + * Revision 1.2 1998/07/19 18:29:14 tr + * Added error reporting capabilities and some asserts. + * + * Revision 1.1 1998/07/04 16:27:51 tr + * Initial revision + * + * + * MSVC 1.0 scans automatic dependencies incorrectly when your project + * contains this very header. The problem is that MSVC cannot handle + * include directives inside #if..#endif block those are never entered. + * Since this header ought to compile in many different operating systems, + * there had to be several conditional blocks that are compiled only in + * operating systems for what they were designed for. MSVC 1.0 cannot + * handle inclusion of sys/dir.h in a part that is compiled only in Apollo + * operating system. To fix the problem you need to insert DIR.H into + * SYSINCL.DAT located in MSVC\BIN directory and restart visual C++. + * Consult manuals for more informaton about the problem. + * + * Since many UNIX systems have dirent.h we assume to have one also. + * However, if your UNIX system does not have dirent.h you can download one + * for example at: http://ftp.uni-mannheim.de/ftp/GNU/dirent/dirent.tar.gz. + * You can also see if you have one of dirent.h, direct.h, dir.h, ndir.h, + * sys/dir.h and sys/ndir.h somewhere. Try defining HAVE_DIRENT_H, + * HAVE_DIRECT_H, HAVE_DIR_H, HAVE_NDIR_H, HAVE_SYS_DIR_H and + * HAVE_SYS_NDIR_H according to the files found. + */ +#ifndef DIRENT_H +#define DIRENT_H +#define DIRENT_H_INCLUDED + +/* find out platform */ +#if defined(MSDOS) /* MS-DOS */ +#elif defined(__MSDOS__) /* Turbo C/Borland */ +# define MSDOS +#elif defined(__DOS__) /* Watcom */ +# define MSDOS +#endif + +#if defined(WIN32) /* MS-Windows */ +#elif defined(__NT__) /* Watcom */ +# define WIN32 +#elif defined(_WIN32) /* Microsoft */ +# define WIN32 +#elif defined(__WIN32__) /* Borland */ +# define WIN32 +#endif + +/* + * See what kind of dirent interface we have unless autoconf has already + * determinated that. + */ +#if !defined(HAVE_DIRENT_H) && !defined(HAVE_DIRECT_H) && !defined(HAVE_SYS_DIR_H) && !defined(HAVE_NDIR_H) && !defined(HAVE_SYS_NDIR_H) && !defined(HAVE_DIR_H) +# if defined(_MSC_VER) /* Microsoft C/C++ */ + /* no dirent.h */ +# elif defined(__BORLANDC__) /* Borland C/C++ */ +# define HAVE_DIRENT_H +# define VOID_CLOSEDIR +# elif defined(__TURBOC__) /* Borland Turbo C */ + /* no dirent.h */ +# elif defined(__WATCOMC__) /* Watcom C/C++ */ +# define HAVE_DIRECT_H +# elif defined(__apollo) /* Apollo */ +# define HAVE_SYS_DIR_H +# elif defined(__hpux) /* HP-UX */ +# define HAVE_DIRENT_H +# elif (defined(__alpha) || defined(__alpha__)) && !defined(__linux__) /* Alpha OSF1 */ +# error "not implemented" +# elif defined(__sgi) /* Silicon Graphics */ +# define HAVE_DIRENT_H +# elif defined(sun) || defined(_sun) /* Sun Solaris */ +# define HAVE_DIRENT_H +# elif defined(__FreeBSD__) /* FreeBSD */ +# define HAVE_DIRENT_H +# elif defined(__linux__) /* Linux */ +# define HAVE_DIRENT_H +# elif defined(__GNUC__) /* GNU C/C++ */ +# define HAVE_DIRENT_H +# else +# error "not implemented" +# endif +#endif + +/* include proper interface headers */ +#if defined(HAVE_DIRENT_H) +# include +# ifdef FREEBSD +# define NAMLEN(dp) ((int)((dp)->d_namlen)) +# else +# define NAMLEN(dp) ((int)(strlen((dp)->d_name))) +# endif + +#elif defined(HAVE_NDIR_H) +# include +# define NAMLEN(dp) ((int)((dp)->d_namlen)) + +#elif defined(HAVE_SYS_NDIR_H) +# include +# define NAMLEN(dp) ((int)((dp)->d_namlen)) + +#elif defined(HAVE_DIRECT_H) +# include +# define NAMLEN(dp) ((int)((dp)->d_namlen)) + +#elif defined(HAVE_DIR_H) +# include +# define NAMLEN(dp) ((int)((dp)->d_namlen)) + +#elif defined(HAVE_SYS_DIR_H) +# include +# include +# ifndef dirent +# define dirent direct +# endif +# define NAMLEN(dp) ((int)((dp)->d_namlen)) + +#elif defined(MSDOS) || defined(WIN32) + + /* figure out type of underlaying directory interface to be used */ +# if defined(WIN32) +# define DIRENT_WIN32_INTERFACE +# elif defined(MSDOS) +# define DIRENT_MSDOS_INTERFACE +# else +# error "missing native dirent interface" +# endif + + /*** WIN32 specifics ***/ +# if defined(DIRENT_WIN32_INTERFACE) +# include +# if !defined(DIRENT_MAXNAMLEN) +# define DIRENT_MAXNAMLEN (MAX_PATH) +# endif + + + /*** MS-DOS specifics ***/ +# elif defined(DIRENT_MSDOS_INTERFACE) +# include + + /* Borland defines file length macros in dir.h */ +# if defined(__BORLANDC__) +# include +# if !defined(DIRENT_MAXNAMLEN) +# define DIRENT_MAXNAMLEN ((MAXFILE)+(MAXEXT)) +# endif +# if !defined(_find_t) +# define _find_t find_t +# endif + + /* Turbo C defines ffblk structure in dir.h */ +# elif defined(__TURBOC__) +# include +# if !defined(DIRENT_MAXNAMLEN) +# define DIRENT_MAXNAMLEN ((MAXFILE)+(MAXEXT)) +# endif +# define DIRENT_USE_FFBLK + + /* MSVC */ +# elif defined(_MSC_VER) +# if !defined(DIRENT_MAXNAMLEN) +# define DIRENT_MAXNAMLEN (12) +# endif + + /* Watcom */ +# elif defined(__WATCOMC__) +# if !defined(DIRENT_MAXNAMLEN) +# if defined(__OS2__) || defined(__NT__) +# define DIRENT_MAXNAMLEN (255) +# else +# define DIRENT_MAXNAMLEN (12) +# endif +# endif + +# endif +# endif + + /*** generic MS-DOS and MS-Windows stuff ***/ +# if !defined(NAME_MAX) && defined(DIRENT_MAXNAMLEN) +# define NAME_MAX DIRENT_MAXNAMLEN +# endif +# if NAME_MAX < DIRENT_MAXNAMLEN +# error "assertion failed: NAME_MAX >= DIRENT_MAXNAMLEN" +# endif + + + /* + * Substitute for real dirent structure. Note that `d_name' field is a + * true character array although we have it copied in the implementation + * dependent data. We could save some memory if we had declared `d_name' + * as a pointer refering the name within implementation dependent data. + * We have not done that since some code may rely on sizeof(d_name) to be + * something other than four. Besides, directory entries are typically so + * small that it takes virtually no time to copy them from place to place. + */ + typedef struct dirent { + char d_name[NAME_MAX + 1]; + + /*** Operating system specific part ***/ +# if defined(DIRENT_WIN32_INTERFACE) /*WIN32*/ + WIN32_FIND_DATA data; +# elif defined(DIRENT_MSDOS_INTERFACE) /*MSDOS*/ +# if defined(DIRENT_USE_FFBLK) + struct ffblk data; +# else + struct _find_t data; +# endif +# endif + } dirent; + + /* DIR substitute structure containing directory name. The name is + * essential for the operation of ``rewinndir'' function. */ + typedef struct DIR { + char *dirname; /* directory being scanned */ + dirent current; /* current entry */ + int dirent_filled; /* is current un-processed? */ + + /*** Operating system specific part ***/ +# if defined(DIRENT_WIN32_INTERFACE) + HANDLE search_handle; +# elif defined(DIRENT_MSDOS_INTERFACE) +# endif + } DIR; + +# ifdef __cplusplus +extern "C" { +# endif + +/* supply prototypes for dirent functions */ +static DIR *opendir (const char *dirname); +static struct dirent *readdir (DIR *dirp); +static int closedir (DIR *dirp); +static void rewinddir (DIR *dirp); + +/* + * Implement dirent interface as static functions so that the user does not + * need to change his project in any way to use dirent function. With this + * it is sufficient to include this very header from source modules using + * dirent functions and the functions will be pulled in automatically. + */ +#include +#include +#include +#include +#include + +/* use ffblk instead of _find_t if requested */ +#if defined(DIRENT_USE_FFBLK) +# define _A_ARCH (FA_ARCH) +# define _A_HIDDEN (FA_HIDDEN) +# define _A_NORMAL (0) +# define _A_RDONLY (FA_RDONLY) +# define _A_SUBDIR (FA_DIREC) +# define _A_SYSTEM (FA_SYSTEM) +# define _A_VOLID (FA_LABEL) +# define _dos_findnext(dest) findnext(dest) +# define _dos_findfirst(name,flags,dest) findfirst(name,dest,flags) +#endif + +static int _initdir (DIR *p); +static const char *_getdirname (const struct dirent *dp); +static void _setdirname (struct DIR *dirp); + +/* + * + * open directory stream for reading + * DIR *opendir (const char *dirname); + * + * Open named directory stream for read and return pointer to the + * internal working area that is used for retrieving individual directory + * entries. The internal working area has no fields of your interest. + * + * Returns a pointer to the internal working area or NULL in case the + * directory stream could not be opened. Global `errno' variable will set + * in case of error as follows: + * + *
    + * [EACESS |Permission denied. + * [EMFILE |Too many open files used by the process. + * [ENFILE |Too many open files in system. + * [ENOENT |Directory does not exist. + * [ENOMEM |Insufficient memory. + * [ENOTDIR |dirname does not refer to directory. This value is not + * reliable on MS-DOS and MS-Windows platforms. Many + * implementations return ENOENT even when the name refers to a + * file.] + *
    + * + */ +static DIR *opendir(const char *dirname) +{ + DIR *dirp; + assert (dirname != NULL); + + dirp = (DIR*)malloc (sizeof (struct DIR)); + if (dirp != NULL) { + char *p; + + /* allocate room for directory name */ + dirp->dirname = (char*) malloc (strlen (dirname) + 1 + strlen ("\\*.*")); + if (dirp->dirname == NULL) { + /* failed to duplicate directory name. errno set by malloc() */ + free (dirp); + return NULL; + } + /* Copy directory name while appending directory separator and "*.*". + * Directory separator is not appended if the name already ends with + * drive or directory separator. Directory separator is assumed to be + * '/' or '\' and drive separator is assumed to be ':'. */ + strcpy (dirp->dirname, dirname); + p = strchr (dirp->dirname, '\0'); + if (dirp->dirname < p && + *(p - 1) != '\\' && *(p - 1) != '/' && *(p - 1) != ':') + { + strcpy (p++, "\\"); + } +# ifdef DIRENT_WIN32_INTERFACE + strcpy (p, "*"); /*scan files with and without extension in win32*/ +# else + strcpy (p, "*.*"); /*scan files with and without extension in DOS*/ +# endif + + /* open stream */ + if (_initdir (dirp) == 0) { + /* initialization failed */ + free (dirp->dirname); + free (dirp); + return NULL; + } + } + return dirp; +} + + +/* + * + * read a directory entry + * struct dirent *readdir (DIR *dirp); + * + * Read individual directory entry and return pointer to a structure + * containing the name of the entry. Individual directory entries returned + * include normal files, sub-directories, pseudo-directories "." and ".." + * and also volume labels, hidden files and system files in MS-DOS and + * MS-Windows. You might want to use stat(2) function to determinate which + * one are you dealing with. Many dirent implementations already contain + * equivalent information in dirent structure but you cannot depend on + * this. + * + * The dirent structure contains several system dependent fields that + * generally have no interest to you. The only interesting one is char + * d_name[] that is also portable across different systems. The d_name + * field contains the name of the directory entry without leading path. + * While d_name is portable across different systems the actual storage + * capacity of d_name varies from system to system and there is no portable + * way to find out it at compile time as different systems define the + * capacity of d_name with different macros and some systems do not define + * capacity at all (besides actual declaration of the field). If you really + * need to find out storage capacity of d_name then you might want to try + * NAME_MAX macro. The NAME_MAX is defined in POSIX standard althought + * there are many MS-DOS and MS-Windows implementations those do not define + * it. There are also systems that declare d_name as "char d_name[1]" and + * then allocate suitable amount of memory at run-time. Thanks to Alain + * Decamps (Alain.Decamps@advalvas.be) for pointing it out to me. + * + * This all leads to the fact that it is difficult to allocate space + * for the directory names when the very same program is being compiled on + * number of operating systems. Therefore I suggest that you always + * allocate space for directory names dynamically. + * + * + * Returns a pointer to a structure containing name of the directory entry + * in `d_name' field or NULL if there was an error. In case of an error the + * global `errno' variable will set as follows: + * + * + * [EBADF |dir parameter refers to an invalid directory stream. This value + * is not set reliably on all implementations.] + *
    + *
    + */ +static struct dirent * +readdir (DIR *dirp) +{ + assert(dirp != NULL); + if (dirp == NULL) { + errno = EBADF; + return NULL; + } + +#if defined(DIRENT_WIN32_INTERFACE) + if (dirp->search_handle == INVALID_HANDLE_VALUE) { + /* directory stream was opened/rewound incorrectly or it ended normally */ + errno = EBADF; + return NULL; + } +#endif + + if (dirp->dirent_filled != 0) { + /* + * Directory entry has already been retrieved and there is no need to + * retrieve a new one. Directory entry will be retrieved in advance + * when the user calls readdir function for the first time. This is so + * because real dirent has separate functions for opening and reading + * the stream whereas Win32 and DOS dirents open the stream + * automatically when we retrieve the first file. Therefore, we have to + * save the first file when opening the stream and later we have to + * return the saved entry when the user tries to read the first entry. + */ + dirp->dirent_filled = 0; + } else { + /* fill in entry and return that */ +#if defined(DIRENT_WIN32_INTERFACE) + if (FindNextFile (dirp->search_handle, &dirp->current.data) == FALSE) { + /* Last file has been processed or an error occured */ + FindClose (dirp->search_handle); + dirp->search_handle = INVALID_HANDLE_VALUE; + errno = ENOENT; + return NULL; + } + +# elif defined(DIRENT_MSDOS_INTERFACE) + if (_dos_findnext (&dirp->current.data) != 0) { + /* _dos_findnext and findnext will set errno to ENOENT when no + * more entries could be retrieved. */ + return NULL; + } +# endif + + _setdirname (dirp); + assert (dirp->dirent_filled == 0); + } + return &dirp->current; +} + + +/* + * + * close directory stream. + * int closedir (DIR *dirp); + * + * Close directory stream opened by the `opendir' function. Close of + * directory stream invalidates the DIR structure as well as previously read + * dirent entry. + * + * The function typically returns 0 on success and -1 on failure but + * the function may be declared to return void on same systems. At least + * Borland C/C++ and some UNIX implementations use void as a return type. + * The dirent wrapper tries to define VOID_CLOSEDIR whenever closedir is + * known to return nothing. The very same definition is made by the GNU + * autoconf if you happen to use it. + * + * The global `errno' variable will set to EBADF in case of error. + * + */ +static int +closedir (DIR *dirp) +{ + int retcode = 0; + + /* make sure that dirp points to legal structure */ + assert (dirp != NULL); + if (dirp == NULL) { + errno = EBADF; + return -1; + } + + /* free directory name and search handles */ + if (dirp->dirname != NULL) free (dirp->dirname); + +#if defined(DIRENT_WIN32_INTERFACE) + if (dirp->search_handle != INVALID_HANDLE_VALUE) { + if (FindClose (dirp->search_handle) == FALSE) { + /* Unknown error */ + retcode = -1; + errno = EBADF; + } + } +#endif + + /* clear dirp structure to make sure that it cannot be used anymore*/ + memset (dirp, 0, sizeof (*dirp)); +# if defined(DIRENT_WIN32_INTERFACE) + dirp->search_handle = INVALID_HANDLE_VALUE; +# endif + + free (dirp); + return retcode; +} + + +/* + * + * rewind directory stream to the beginning + * void rewinddir (DIR *dirp); + * + * Rewind directory stream to the beginning so that the next call of + * readdir() returns the very first directory entry again. However, note + * that next call of readdir() may not return the same directory entry as it + * did in first time. The directory stream may have been affected by newly + * created files. + * + * Almost every dirent implementation ensure that rewinddir will update + * the directory stream to reflect any changes made to the directory entries + * since the previous ``opendir'' or ``rewinddir'' call. Keep an eye on + * this if your program depends on the feature. I know at least one dirent + * implementation where you are required to close and re-open the stream to + * see the changes. + * + * Returns nothing. If something went wrong while rewinding, you will + * notice it later when you try to retrieve the first directory entry. + */ +static void +rewinddir (DIR *dirp) +{ + /* make sure that dirp is legal */ + assert (dirp != NULL); + if (dirp == NULL) { + errno = EBADF; + return; + } + assert (dirp->dirname != NULL); + + /* close previous stream */ +#if defined(DIRENT_WIN32_INTERFACE) + if (dirp->search_handle != INVALID_HANDLE_VALUE) { + if (FindClose (dirp->search_handle) == FALSE) { + /* Unknown error */ + errno = EBADF; + } + } +#endif + + /* re-open previous stream */ + if (_initdir (dirp) == 0) { + /* initialization failed but we cannot deal with error. User will notice + * error later when she tries to retrieve first directory enty. */ + /*EMPTY*/; + } +} + + +/* + * Open native directory stream object and retrieve first file. + * Be sure to close previous stream before opening new one. + */ +static int +_initdir (DIR *dirp) +{ + assert (dirp != NULL); + assert (dirp->dirname != NULL); + dirp->dirent_filled = 0; + +# if defined(DIRENT_WIN32_INTERFACE) + /* Open stream and retrieve first file */ + dirp->search_handle = FindFirstFile (dirp->dirname, &dirp->current.data); + if (dirp->search_handle == INVALID_HANDLE_VALUE) { + /* something went wrong but we don't know what. GetLastError() could + * give us more information about the error, but then we should map + * the error code into errno. */ + errno = ENOENT; + return 0; + } + +# elif defined(DIRENT_MSDOS_INTERFACE) + if (_dos_findfirst (dirp->dirname, + _A_SUBDIR | _A_RDONLY | _A_ARCH | _A_SYSTEM | _A_HIDDEN, + &dirp->current.data) != 0) + { + /* _dos_findfirst and findfirst will set errno to ENOENT when no + * more entries could be retrieved. */ + return 0; + } +# endif + + /* initialize DIR and it's first entry */ + _setdirname (dirp); + dirp->dirent_filled = 1; + return 1; +} + + +/* + * Return implementation dependent name of the current directory entry. + */ +static const char * +_getdirname (const struct dirent *dp) +{ +#if defined(DIRENT_WIN32_INTERFACE) + return dp->data.cFileName; + +#elif defined(DIRENT_USE_FFBLK) + return dp->data.ff_name; + +#else + return dp->data.name; +#endif +} + + +/* + * Copy name of implementation dependent directory entry to the d_name field. + */ +static void +_setdirname (struct DIR *dirp) { + /* make sure that d_name is long enough */ + assert (strlen (_getdirname (&dirp->current)) <= NAME_MAX); + + strncpy (dirp->current.d_name, + _getdirname (&dirp->current), + NAME_MAX); + dirp->current.d_name[NAME_MAX] = '\0'; /*char d_name[NAME_MAX+1]*/ +} + +# ifdef __cplusplus +} +# endif +# define NAMLEN(dp) ((int)(strlen((dp)->d_name))) + +#else +# error "missing dirent interface" +#endif + + +#endif /*DIRENT_H*/ diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/codec/image_to_j2k.c b/gdcm/Utilities/gdcmopenjpeg-v2/codec/image_to_j2k.c new file mode 100644 index 0000000..02a19ed --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/codec/image_to_j2k.c @@ -0,0 +1,1797 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2006-2007, Parvatha Elangovan + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#define USE_OPJ_DEPRECATED +#include "openjpeg.h" +#include "compat/getopt.h" +#include "convert.h" +#include "dirent.h" +#include "index.h" + +#ifndef WIN32 +#include +#define _stricmp strcasecmp +#define _strnicmp strncasecmp +#endif + +/* ----------------------------------------------------------------------- */ + +#define J2K_CFMT 0 +#define JP2_CFMT 1 +#define JPT_CFMT 2 + +#define PXM_DFMT 10 +#define PGX_DFMT 11 +#define BMP_DFMT 12 +#define YUV_DFMT 13 +#define TIF_DFMT 14 +#define RAW_DFMT 15 +#define TGA_DFMT 16 +#define PNG_DFMT 17 +/* ----------------------------------------------------------------------- */ +#define CINEMA_24_CS 1302083 /*Codestream length for 24fps*/ +#define CINEMA_48_CS 651041 /*Codestream length for 48fps*/ +#define COMP_24_CS 1041666 /*Maximum size per color component for 2K & 4K @ 24fps*/ +#define COMP_48_CS 520833 /*Maximum size per color component for 2K @ 48fps*/ + +typedef struct dircnt{ + /** Buffer for holding images read from Directory*/ + char *filename_buf; + /** Pointer to the buffer*/ + char **filename; +}dircnt_t; + +typedef struct img_folder{ + /** The directory path of the folder containing input images*/ + char *imgdirpath; + /** Output format*/ + char *out_format; + /** Enable option*/ + char set_imgdir; + /** Enable Cod Format for output*/ + char set_out_format; + /** User specified rate stored in case of cinema option*/ + float *rates; +}img_fol_t; + +void encode_help_display() { + fprintf(stdout,"HELP\n----\n\n"); + fprintf(stdout,"- the -h option displays this help information on screen\n\n"); + +/* UniPG>> */ + fprintf(stdout,"List of parameters for the JPEG 2000 " +#ifdef USE_JPWL + "+ JPWL " +#endif /* USE_JPWL */ + "encoder:\n"); +/* <> */ +#ifdef USE_JPWL + fprintf(stdout," * No JPWL protection\n"); +#endif /* USE_JPWL */ +/* < \n"); + fprintf(stdout," Currently accepts PGM, PPM, PNM, PGX, BMP, TIF, RAW and TGA formats\n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-i : source file (-i source.pnm also *.pgm, *.ppm, *.bmp, *.tif, *.raw, *.tga) \n"); + fprintf(stdout," When using this option -o must be used\n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-o : destination file (-o dest.j2k or .jp2) \n"); + fprintf(stdout,"\n"); + fprintf(stdout,"Optional Parameters:\n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-h : display the help information \n "); + fprintf(stdout,"\n"); + fprintf(stdout,"-cinema2K : Digital Cinema 2K profile compliant codestream for 2K resolution.(-cinema2k 24 or 48) \n"); + fprintf(stdout," Need to specify the frames per second for a 2K resolution. Only 24 or 48 fps is allowed\n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-cinema4K : Digital Cinema 4K profile compliant codestream for 4K resolution \n"); + fprintf(stdout," Frames per second not required. Default value is 24fps\n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-r : different compression ratios for successive layers (-r 20,10,5)\n "); + fprintf(stdout," - The rate specified for each quality level is the desired \n"); + fprintf(stdout," compression factor.\n"); + fprintf(stdout," Example: -r 20,10,1 means quality 1: compress 20x, \n"); + fprintf(stdout," quality 2: compress 10x and quality 3: compress lossless\n"); + fprintf(stdout,"\n"); + fprintf(stdout," (options -r and -q cannot be used together)\n "); + fprintf(stdout,"\n"); + + fprintf(stdout,"-q : different psnr for successive layers (-q 30,40,50) \n "); + + fprintf(stdout," (options -r and -q cannot be used together)\n "); + + fprintf(stdout,"\n"); + fprintf(stdout,"-n : number of resolutions (-n 3) \n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-b : size of code block (-b 32,32) \n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-c : size of precinct (-c 128,128) \n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-t : size of tile (-t 512,512) \n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-p : progression order (-p LRCP) [LRCP, RLCP, RPCL, PCRL, CPRL] \n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-s : subsampling factor (-s 2,2) [-s X,Y] \n"); + fprintf(stdout," Remark: subsampling bigger than 2 can produce error\n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-POC : Progression order change (-POC T1=0,0,1,5,3,CPRL/T1=5,0,1,6,3,CPRL) \n"); + fprintf(stdout," Example: T1=0,0,1,5,3,CPRL \n"); + fprintf(stdout," : Ttilenumber=Resolution num start,Component num start,Layer num end,Resolution num end,Component num end,Progression order\n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-SOP : write SOP marker before each packet \n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-EPH : write EPH marker after each header packet \n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-M : mode switch (-M 3) [1=BYPASS(LAZY) 2=RESET 4=RESTART(TERMALL)\n"); + fprintf(stdout," 8=VSC 16=ERTERM(SEGTERM) 32=SEGMARK(SEGSYM)] \n"); + fprintf(stdout," Indicate multiple modes by adding their values. \n"); + fprintf(stdout," ex: RESTART(4) + RESET(2) + SEGMARK(32) = -M 38\n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-x : create an index file *.Idx (-x index_name.Idx) \n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-ROI : c=%%d,U=%%d : quantization indices upshifted \n"); + fprintf(stdout," for component c=%%d [%%d = 0,1,2]\n"); + fprintf(stdout," with a value of U=%%d [0 <= %%d <= 37] (i.e. -ROI c=0,U=25) \n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-d : offset of the origin of the image (-d 150,300) \n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-T : offset of the origin of the tiles (-T 100,75) \n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-I : use the irreversible DWT 9-7 (-I) \n"); + fprintf(stdout,"\n"); + fprintf(stdout,"-F : characteristics of the raw input image\n"); + fprintf(stdout," -F rawWidth,rawHeight,rawComp,rawBitDepth,s/u (Signed/Unsigned)\n"); + fprintf(stdout," Example: -i lena.raw -o lena.j2k -F 512,512,3,8,u\n"); + fprintf(stdout,"-m : use array-based MCT, values are coma separated, line by line\n"); + fprintf(stdout," no specific separators between lines, no space allowed between values\n"); + fprintf(stdout,"\n"); +/* UniPG>> */ +#ifdef USE_JPWL + fprintf(stdout,"-W : adoption of JPWL (Part 11) capabilities (-W params)\n"); + fprintf(stdout," The parameters can be written and repeated in any order:\n"); + fprintf(stdout," [h<=type>,s<=method>,a=,...\n"); + fprintf(stdout," ...,z=,g=,p<=type>]\n"); + fprintf(stdout,"\n"); + fprintf(stdout," h selects the header error protection (EPB): 'type' can be\n"); + fprintf(stdout," [0=none 1,absent=predefined 16=CRC-16 32=CRC-32 37-128=RS]\n"); + fprintf(stdout," if 'tilepart' is absent, it is for main and tile headers\n"); + fprintf(stdout," if 'tilepart' is present, it applies from that tile\n"); + fprintf(stdout," onwards, up to the next h<> spec, or to the last tilepart\n"); + fprintf(stdout," in the codestream (max. %d specs)\n", JPWL_MAX_NO_TILESPECS); + fprintf(stdout,"\n"); + fprintf(stdout," p selects the packet error protection (EEP/UEP with EPBs)\n"); + fprintf(stdout," to be applied to raw data: 'type' can be\n"); + fprintf(stdout," [0=none 1,absent=predefined 16=CRC-16 32=CRC-32 37-128=RS]\n"); + fprintf(stdout," if 'tilepart:pack' is absent, it is from tile 0, packet 0\n"); + fprintf(stdout," if 'tilepart:pack' is present, it applies from that tile\n"); + fprintf(stdout," and that packet onwards, up to the next packet spec\n"); + fprintf(stdout," or to the last packet in the last tilepart in the stream\n"); + fprintf(stdout," (max. %d specs)\n", JPWL_MAX_NO_PACKSPECS); + fprintf(stdout,"\n"); + fprintf(stdout," s enables sensitivity data insertion (ESD): 'method' can be\n"); + fprintf(stdout," [-1=NO ESD 0=RELATIVE ERROR 1=MSE 2=MSE REDUCTION 3=PSNR\n"); + fprintf(stdout," 4=PSNR INCREMENT 5=MAXERR 6=TSE 7=RESERVED]\n"); + fprintf(stdout," if 'tilepart' is absent, it is for main header only\n"); + fprintf(stdout," if 'tilepart' is present, it applies from that tile\n"); + fprintf(stdout," onwards, up to the next s<> spec, or to the last tilepart\n"); + fprintf(stdout," in the codestream (max. %d specs)\n", JPWL_MAX_NO_TILESPECS); + fprintf(stdout,"\n"); + fprintf(stdout," g determines the addressing mode: can be\n"); + fprintf(stdout," [0=PACKET 1=BYTE RANGE 2=PACKET RANGE]\n"); + fprintf(stdout,"\n"); + fprintf(stdout," a determines the size of data addressing: can be\n"); + fprintf(stdout," 2/4 bytes (small/large codestreams). If not set, auto-mode\n"); + fprintf(stdout,"\n"); + fprintf(stdout," z determines the size of sensitivity values: can be\n"); + fprintf(stdout," 1/2 bytes, for the transformed pseudo-floating point value\n"); + fprintf(stdout,"\n"); + fprintf(stdout," ex.:\n"); + fprintf(stdout," h,h0=64,h3=16,h5=32,p0=78,p0:24=56,p1,p3:0=0,p3:20=32,s=0,\n"); + fprintf(stdout," s0=6,s3=-1,a=0,g=1,z=1\n"); + fprintf(stdout," means\n"); + fprintf(stdout," predefined EPB in MH, rs(64,32) from TPH 0 to TPH 2,\n"); + fprintf(stdout," CRC-16 in TPH 3 and TPH 4, CRC-32 in remaining TPHs,\n"); + fprintf(stdout," UEP rs(78,32) for packets 0 to 23 of tile 0,\n"); + fprintf(stdout," UEP rs(56,32) for packs. 24 to the last of tilepart 0,\n"); + fprintf(stdout," UEP rs default for packets of tilepart 1,\n"); + fprintf(stdout," no UEP for packets 0 to 19 of tilepart 3,\n"); + fprintf(stdout," UEP CRC-32 for packs. 20 of tilepart 3 to last tilepart,\n"); + fprintf(stdout," relative sensitivity ESD for MH,\n"); + fprintf(stdout," TSE ESD from TPH 0 to TPH 2, byte range with automatic\n"); + fprintf(stdout," size of addresses and 1 byte for each sensitivity value\n"); + fprintf(stdout,"\n"); + fprintf(stdout," ex.:\n"); + fprintf(stdout," h,s,p\n"); + fprintf(stdout," means\n"); + fprintf(stdout," default protection to headers (MH and TPHs) as well as\n"); + fprintf(stdout," data packets, one ESD in MH\n"); + fprintf(stdout,"\n"); + fprintf(stdout," N.B.: use the following recommendations when specifying\n"); + fprintf(stdout," the JPWL parameters list\n"); + fprintf(stdout," - when you use UEP, always pair the 'p' option with 'h'\n"); + fprintf(stdout," \n"); +#endif /* USE_JPWL */ +/* <d_name)==0 || strcmp("..",content->d_name)==0 ) + continue; + num_images++; + } + return num_images; +} + +int load_images(dircnt_t *dirptr, char *imgdirpath){ + DIR *dir; + struct dirent* content; + int i = 0; + + /*Reading the input images from given input directory*/ + + dir= opendir(imgdirpath); + if(!dir){ + fprintf(stderr,"Could not open Folder %s\n",imgdirpath); + return 1; + }else { + fprintf(stderr,"Folder opened successfully\n"); + } + + while((content=readdir(dir))!=NULL){ + if(strcmp(".",content->d_name)==0 || strcmp("..",content->d_name)==0 ) + continue; + + strcpy(dirptr->filename[i],content->d_name); + i++; + } + return 0; +} + +int get_file_format(char *filename) { + unsigned int i; + static const char *extension[] = { + "pgx", "pnm", "pgm", "ppm", "bmp", "tif", "raw", "tga", "png", "j2k", "jp2", "j2c", "jpc" + }; + static const int format[] = { + PGX_DFMT, PXM_DFMT, PXM_DFMT, PXM_DFMT, BMP_DFMT, TIF_DFMT, RAW_DFMT, TGA_DFMT, PNG_DFMT, J2K_CFMT, JP2_CFMT, J2K_CFMT, J2K_CFMT + }; + char * ext = strrchr(filename, '.'); + if (ext == NULL) + return -1; + ext++; + for(i = 0; i < sizeof(format)/sizeof(*format); i++) { + if(_strnicmp(ext, extension[i], 3) == 0) { + return format[i]; + } + } + return -1; +} + +char * get_file_name(char *name){ + char *fname; + fname= (char*)malloc(OPJ_PATH_LEN*sizeof(char)); + fname= strtok(name,"."); + return fname; +} + +char get_next_file(int imageno,dircnt_t *dirptr,img_fol_t *img_fol, opj_cparameters_t *parameters){ + char image_filename[OPJ_PATH_LEN], infilename[OPJ_PATH_LEN],outfilename[OPJ_PATH_LEN],temp_ofname[OPJ_PATH_LEN]; + char *temp_p, temp1[OPJ_PATH_LEN]=""; + + strcpy(image_filename,dirptr->filename[imageno]); + fprintf(stderr,"File Number %d \"%s\"\n",imageno,image_filename); + parameters->decod_format = get_file_format(image_filename); + if (parameters->decod_format == -1) + return 1; + sprintf(infilename,"%s/%s",img_fol->imgdirpath,image_filename); + strncpy(parameters->infile, infilename, sizeof(infilename)); + + //Set output file + strcpy(temp_ofname,get_file_name(image_filename)); + while((temp_p = strtok(NULL,".")) != NULL){ + strcat(temp_ofname,temp1); + sprintf(temp1,".%s",temp_p); + } + if(img_fol->set_out_format==1){ + sprintf(outfilename,"%s/%s.%s",img_fol->imgdirpath,temp_ofname,img_fol->out_format); + strncpy(parameters->outfile, outfilename, sizeof(outfilename)); + } + return 0; +} + +static int initialise_4K_poc(opj_poc_t *POC, int numres){ + POC[0].tile = 1; + POC[0].resno0 = 0; + POC[0].compno0 = 0; + POC[0].layno1 = 1; + POC[0].resno1 = numres-1; + POC[0].compno1 = 3; + POC[0].prg1 = CPRL; + POC[1].tile = 1; + POC[1].resno0 = numres-1; + POC[1].compno0 = 0; + POC[1].layno1 = 1; + POC[1].resno1 = numres; + POC[1].compno1 = 3; + POC[1].prg1 = CPRL; + return 2; +} + +void cinema_parameters(opj_cparameters_t *parameters){ + parameters->tile_size_on = false; + parameters->cp_tdx=1; + parameters->cp_tdy=1; + + /*Tile part*/ + parameters->tp_flag = 'C'; + parameters->tp_on = 1; + + /*Tile and Image shall be at (0,0)*/ + parameters->cp_tx0 = 0; + parameters->cp_ty0 = 0; + parameters->image_offset_x0 = 0; + parameters->image_offset_y0 = 0; + + /*Codeblock size= 32*32*/ + parameters->cblockw_init = 32; + parameters->cblockh_init = 32; + parameters->csty |= 0x01; + + /*The progression order shall be CPRL*/ + parameters->prog_order = CPRL; + + /* No ROI */ + parameters->roi_compno = -1; + + parameters->subsampling_dx = 1; parameters->subsampling_dy = 1; + + /* 9-7 transform */ + parameters->irreversible = 1; + +} + +void cinema_setup_encoder(opj_cparameters_t *parameters,opj_image_t *image, img_fol_t *img_fol){ + int i; + float temp_rate; + + switch (parameters->cp_cinema){ + case CINEMA2K_24: + case CINEMA2K_48: + if(parameters->numresolution > 6){ + parameters->numresolution = 6; + } + if (!((image->comps[0].w == 2048) | (image->comps[0].h == 1080))){ + fprintf(stdout,"Image coordinates %d x %d is not 2K compliant.\nJPEG Digital Cinema Profile-3 " + "(2K profile) compliance requires that at least one of coordinates match 2048 x 1080\n", + image->comps[0].w,image->comps[0].h); + parameters->cp_rsiz = STD_RSIZ; + } + break; + + case CINEMA4K_24: + if(parameters->numresolution < 1){ + parameters->numresolution = 1; + }else if(parameters->numresolution > 7){ + parameters->numresolution = 7; + } + if (!((image->comps[0].w == 4096) | (image->comps[0].h == 2160))){ + fprintf(stdout,"Image coordinates %d x %d is not 4K compliant.\nJPEG Digital Cinema Profile-4" + "(4K profile) compliance requires that at least one of coordinates match 4096 x 2160\n", + image->comps[0].w,image->comps[0].h); + parameters->cp_rsiz = STD_RSIZ; + } + parameters->numpocs = initialise_4K_poc(parameters->POC,parameters->numresolution); + break; + default : + break; + } + + switch (parameters->cp_cinema){ + case CINEMA2K_24: + case CINEMA4K_24: + for(i=0 ; itcp_numlayers ; i++){ + temp_rate = 0 ; + if (img_fol->rates[i]== 0){ + parameters->tcp_rates[0]= ((float) (image->numcomps * image->comps[0].w * image->comps[0].h * image->comps[0].prec))/ + (CINEMA_24_CS * 8 * image->comps[0].dx * image->comps[0].dy); + }else{ + temp_rate =((float) (image->numcomps * image->comps[0].w * image->comps[0].h * image->comps[0].prec))/ + (img_fol->rates[i] * 8 * image->comps[0].dx * image->comps[0].dy); + if (temp_rate > CINEMA_24_CS ){ + parameters->tcp_rates[i]= ((float) (image->numcomps * image->comps[0].w * image->comps[0].h * image->comps[0].prec))/ + (CINEMA_24_CS * 8 * image->comps[0].dx * image->comps[0].dy); + }else{ + parameters->tcp_rates[i]= img_fol->rates[i]; + } + } + } + parameters->max_comp_size = COMP_24_CS; + break; + + case CINEMA2K_48: + for(i=0 ; itcp_numlayers ; i++){ + temp_rate = 0 ; + if (img_fol->rates[i]== 0){ + parameters->tcp_rates[0]= ((float) (image->numcomps * image->comps[0].w * image->comps[0].h * image->comps[0].prec))/ + (CINEMA_48_CS * 8 * image->comps[0].dx * image->comps[0].dy); + }else{ + temp_rate =((float) (image->numcomps * image->comps[0].w * image->comps[0].h * image->comps[0].prec))/ + (img_fol->rates[i] * 8 * image->comps[0].dx * image->comps[0].dy); + if (temp_rate > CINEMA_48_CS ){ + parameters->tcp_rates[0]= ((float) (image->numcomps * image->comps[0].w * image->comps[0].h * image->comps[0].prec))/ + (CINEMA_48_CS * 8 * image->comps[0].dx * image->comps[0].dy); + }else{ + parameters->tcp_rates[i]= img_fol->rates[i]; + } + } + } + parameters->max_comp_size = COMP_48_CS; + break; + default: + break; + } + parameters->cp_disto_alloc = 1; +} + +/* ------------------------------------------------------------------------------------ */ + +int parse_cmdline_encoder(int argc, char **argv, opj_cparameters_t *parameters, + img_fol_t *img_fol, raw_cparameters_t *raw_cp, char *indexfilename) { + int i, j,totlen; + option_t long_option[]={ + {"cinema2K",REQ_ARG, NULL ,'w'}, + {"cinema4K",NO_ARG, NULL ,'y'}, + {"ImgDir",REQ_ARG, NULL ,'z'}, + {"TP",REQ_ARG, NULL ,'v'}, + {"SOP",NO_ARG, NULL ,'S'}, + {"EPH",NO_ARG, NULL ,'E'}, + {"OutFor",REQ_ARG, NULL ,'O'}, + {"POC",REQ_ARG, NULL ,'P'}, + {"ROI",REQ_ARG, NULL ,'R'}, + }; + + /* parse the command line */ + const char optlist[] = "i:o:hr:q:n:b:c:t:p:s:SEM:x:R:d:T:If:P:C:F:m:" +#ifdef USE_JPWL + "W:" +#endif /* USE_JPWL */ + ; + + totlen=sizeof(long_option); + img_fol->set_out_format=0; + raw_cp->rawWidth = 0; + + while (1) { + int c = getopt_long(argc, argv, optlist,long_option,totlen); + if (c == -1) + break; + switch (c) { + case 'i': /* input file */ + { + char *infile = optarg; + parameters->decod_format = get_file_format(infile); + switch(parameters->decod_format) { + case PGX_DFMT: + case PXM_DFMT: + case BMP_DFMT: + case TIF_DFMT: + case RAW_DFMT: + case TGA_DFMT: + case PNG_DFMT: + break; + default: + fprintf(stderr, + "!! Unrecognized format for infile : %s " + "[accept only *.pnm, *.pgm, *.ppm, *.pgx, *.bmp, *.tif, *.raw or *.tga] !!\n\n", + infile); + return 1; + } + strncpy(parameters->infile, infile, sizeof(parameters->infile)-1); + } + break; + + /* ----------------------------------------------------- */ + + case 'o': /* output file */ + { + char *outfile = optarg; + parameters->cod_format = get_file_format(outfile); + switch(parameters->cod_format) { + case J2K_CFMT: + case JP2_CFMT: + break; + default: + fprintf(stderr, "Unknown output format image %s [only *.j2k, *.j2c or *.jp2]!! \n", outfile); + return 1; + } + strncpy(parameters->outfile, outfile, sizeof(parameters->outfile)-1); + } + break; + + /* ----------------------------------------------------- */ + case 'O': /* output format */ + { + char outformat[50]; + char *of = optarg; + sprintf(outformat,".%s",of); + img_fol->set_out_format = 1; + parameters->cod_format = get_file_format(outformat); + switch(parameters->cod_format) { + case J2K_CFMT: + case JP2_CFMT: + img_fol->out_format = optarg; + break; + default: + fprintf(stderr, "Unknown output format image [only j2k, j2c, jp2]!! \n"); + return 1; + } + } + break; + + + /* ----------------------------------------------------- */ + + + case 'r': /* rates rates/distorsion */ + { + char *s = optarg; + parameters->tcp_numlayers = 0; + while (sscanf(s, "%f", ¶meters->tcp_rates[parameters->tcp_numlayers]) == 1) { + parameters->tcp_numlayers++; + while (*s && *s != ',') { + s++; + } + if (!*s) + break; + s++; + } + parameters->cp_disto_alloc = 1; + } + break; + + /* ----------------------------------------------------- */ + + + case 'F': /* Raw image format parameters */ + { + char signo; + char *s = optarg; + if (sscanf(s, "%d,%d,%d,%d,%c", &raw_cp->rawWidth, &raw_cp->rawHeight, &raw_cp->rawComp, &raw_cp->rawBitDepth, &signo) == 5) { + if (signo == 's') { + raw_cp->rawSigned = true; + fprintf(stdout,"\nRaw file parameters: %d,%d,%d,%d Signed\n", raw_cp->rawWidth, raw_cp->rawHeight, raw_cp->rawComp, raw_cp->rawBitDepth); + } + else if (signo == 'u') { + raw_cp->rawSigned = false; + fprintf(stdout,"\nRaw file parameters: %d,%d,%d,%d Unsigned\n", raw_cp->rawWidth, raw_cp->rawHeight, raw_cp->rawComp, raw_cp->rawBitDepth); + } + else { + fprintf(stderr,"\nError: invalid raw image parameters: Unknown sign of raw file\n"); + fprintf(stderr,"Please use the Format option -F:\n"); + fprintf(stderr,"-F rawWidth,rawHeight,rawComp,rawBitDepth,s/u (Signed/Unsigned)\n"); + fprintf(stderr,"Example: -i lena.raw -o lena.j2k -F 512,512,3,8,u\n"); + fprintf(stderr,"Aborting\n"); + } + } + else { + fprintf(stderr,"\nError: invalid raw image parameters\n"); + fprintf(stderr,"Please use the Format option -F:\n"); + fprintf(stderr,"-F rawWidth,rawHeight,rawComp,rawBitDepth,s/u (Signed/Unsigned)\n"); + fprintf(stderr,"Example: -i lena.raw -o lena.j2k -F 512,512,3,8,u\n"); + fprintf(stderr,"Aborting\n"); + return 1; + } + } + break; + + /* ----------------------------------------------------- */ + + case 'q': /* add fixed_quality */ + { + char *s = optarg; + while (sscanf(s, "%f", ¶meters->tcp_distoratio[parameters->tcp_numlayers]) == 1) { + parameters->tcp_numlayers++; + while (*s && *s != ',') { + s++; + } + if (!*s) + break; + s++; + } + parameters->cp_fixed_quality = 1; + } + break; + + /* dda */ + /* ----------------------------------------------------- */ + + case 'f': /* mod fixed_quality (before : -q) */ + { + int *row = NULL, *col = NULL; + int numlayers = 0, numresolution = 0, matrix_width = 0; + + char *s = optarg; + sscanf(s, "%d", &numlayers); + s++; + if (numlayers > 9) + s++; + + parameters->tcp_numlayers = numlayers; + numresolution = parameters->numresolution; + matrix_width = numresolution * 3; + parameters->cp_matrice = (int *) malloc(numlayers * matrix_width * sizeof(int)); + s = s + 2; + + for (i = 0; i < numlayers; i++) { + row = ¶meters->cp_matrice[i * matrix_width]; + col = row; + parameters->tcp_rates[i] = 1; + sscanf(s, "%d,", &col[0]); + s += 2; + if (col[0] > 9) + s++; + col[1] = 0; + col[2] = 0; + for (j = 1; j < numresolution; j++) { + col += 3; + sscanf(s, "%d,%d,%d", &col[0], &col[1], &col[2]); + s += 6; + if (col[0] > 9) + s++; + if (col[1] > 9) + s++; + if (col[2] > 9) + s++; + } + if (i < numlayers - 1) + s++; + } + parameters->cp_fixed_alloc = 1; + } + break; + + /* ----------------------------------------------------- */ + + case 't': /* tiles */ + { + sscanf(optarg, "%d,%d", ¶meters->cp_tdx, ¶meters->cp_tdy); + parameters->tile_size_on = true; + } + break; + + /* ----------------------------------------------------- */ + + case 'n': /* resolution */ + { + sscanf(optarg, "%d", ¶meters->numresolution); + } + break; + + /* ----------------------------------------------------- */ + case 'c': /* precinct dimension */ + { + char sep; + int res_spec = 0; + + char *s = optarg; + do { + sep = 0; + sscanf(s, "[%d,%d]%c", ¶meters->prcw_init[res_spec], + ¶meters->prch_init[res_spec], &sep); + parameters->csty |= 0x01; + res_spec++; + s = strpbrk(s, "]") + 2; + } + while (sep == ','); + parameters->res_spec = res_spec; + } + break; + + /* ----------------------------------------------------- */ + + case 'b': /* code-block dimension */ + { + int cblockw_init = 0, cblockh_init = 0; + sscanf(optarg, "%d,%d", &cblockw_init, &cblockh_init); + if (cblockw_init * cblockh_init > 4096 || cblockw_init > 1024 + || cblockw_init < 4 || cblockh_init > 1024 || cblockh_init < 4) { + fprintf(stderr, + "!! Size of code_block error (option -b) !!\n\nRestriction :\n" + " * width*height<=4096\n * 4<=width,height<= 1024\n\n"); + return 1; + } + parameters->cblockw_init = cblockw_init; + parameters->cblockh_init = cblockh_init; + } + break; + + /* ----------------------------------------------------- */ + + case 'x': /* creation of index file */ + { + char *index = optarg; + strncpy(indexfilename, index, OPJ_PATH_LEN); + } + break; + + /* ----------------------------------------------------- */ + + case 'p': /* progression order */ + { + char progression[4]; + + strncpy(progression, optarg, 4); + parameters->prog_order = give_progression(progression); + if (parameters->prog_order == -1) { + fprintf(stderr, "Unrecognized progression order " + "[LRCP, RLCP, RPCL, PCRL, CPRL] !!\n"); + return 1; + } + } + break; + + /* ----------------------------------------------------- */ + + case 's': /* subsampling factor */ + { + if (sscanf(optarg, "%d,%d", ¶meters->subsampling_dx, + ¶meters->subsampling_dy) != 2) { + fprintf(stderr, "'-s' sub-sampling argument error ! [-s dx,dy]\n"); + return 1; + } + } + break; + + /* ----------------------------------------------------- */ + + case 'd': /* coordonnate of the reference grid */ + { + if (sscanf(optarg, "%d,%d", ¶meters->image_offset_x0, + ¶meters->image_offset_y0) != 2) { + fprintf(stderr, "-d 'coordonnate of the reference grid' argument " + "error !! [-d x0,y0]\n"); + return 1; + } + } + break; + + /* ----------------------------------------------------- */ + + case 'h': /* display an help description */ + encode_help_display(); + return 1; + + /* ----------------------------------------------------- */ + + case 'P': /* POC */ + { + int numpocs = 0; /* number of progression order change (POC) default 0 */ + opj_poc_t *POC = NULL; /* POC : used in case of Progression order change */ + + char *s = optarg; + POC = parameters->POC; + + while (sscanf(s, "T%d=%d,%d,%d,%d,%d,%4s", &POC[numpocs].tile, + &POC[numpocs].resno0, &POC[numpocs].compno0, + &POC[numpocs].layno1, &POC[numpocs].resno1, + &POC[numpocs].compno1, POC[numpocs].progorder) == 7) { + POC[numpocs].prg1 = give_progression(POC[numpocs].progorder); + numpocs++; + while (*s && *s != '/') { + s++; + } + if (!*s) { + break; + } + s++; + } + parameters->numpocs = numpocs; + } + break; + + /* ------------------------------------------------------ */ + + case 'S': /* SOP marker */ + { + parameters->csty |= 0x02; + } + break; + + /* ------------------------------------------------------ */ + + case 'E': /* EPH marker */ + { + parameters->csty |= 0x04; + } + break; + + /* ------------------------------------------------------ */ + + case 'M': /* Mode switch pas tous au point !! */ + { + int value = 0; + if (sscanf(optarg, "%d", &value) == 1) { + for (i = 0; i <= 5; i++) { + int cache = value & (1 << i); + if (cache) + parameters->mode |= (1 << i); + } + } + } + break; + + /* ------------------------------------------------------ */ + + case 'R': /* ROI */ + { + if (sscanf(optarg, "c=%d,U=%d", ¶meters->roi_compno, + ¶meters->roi_shift) != 2) { + fprintf(stderr, "ROI error !! [-ROI c='compno',U='shift']\n"); + return 1; + } + } + break; + + /* ------------------------------------------------------ */ + + case 'T': /* Tile offset */ + { + if (sscanf(optarg, "%d,%d", ¶meters->cp_tx0, ¶meters->cp_ty0) != 2) { + fprintf(stderr, "-T 'tile offset' argument error !! [-T X0,Y0]"); + return 1; + } + } + break; + + /* ------------------------------------------------------ */ + + case 'C': /* add a comment */ + { + parameters->cp_comment = (char*)malloc(strlen(optarg) + 1); + if(parameters->cp_comment) { + strcpy(parameters->cp_comment, optarg); + } + } + break; + + + /* ------------------------------------------------------ */ + + case 'I': /* reversible or not */ + { + parameters->irreversible = 1; + } + break; + + /* ------------------------------------------------------ */ + + case 'v': /* Tile part generation*/ + { + parameters->tp_flag = optarg[0]; + parameters->tp_on = 1; + } + break; + + /* ------------------------------------------------------ */ + + case 'z': /* Image Directory path */ + { + img_fol->imgdirpath = (char*)malloc(strlen(optarg) + 1); + strcpy(img_fol->imgdirpath,optarg); + img_fol->set_imgdir=1; + } + break; + + /* ------------------------------------------------------ */ + + case 'w': /* Digital Cinema 2K profile compliance*/ + { + int fps=0; + sscanf(optarg,"%d",&fps); + if(fps == 24){ + parameters->cp_cinema = CINEMA2K_24; + }else if(fps == 48 ){ + parameters->cp_cinema = CINEMA2K_48; + }else { + fprintf(stderr,"Incorrect value!! must be 24 or 48\n"); + return 1; + } + fprintf(stdout,"CINEMA 2K compliant codestream\n"); + parameters->cp_rsiz = CINEMA2K; + + } + break; + + /* ------------------------------------------------------ */ + + case 'y': /* Digital Cinema 4K profile compliance*/ + { + parameters->cp_cinema = CINEMA4K_24; + fprintf(stdout,"CINEMA 4K compliant codestream\n"); + parameters->cp_rsiz = CINEMA4K; + } + break; + + case 'm': /* output file */ + { + char *lFilename = optarg; + char * lMatrix; + char *lCurrentPtr ; + int lNbComp = 0; + int lTotalComp; + int lMctComp; + float * lCurrentDoublePtr; + float * lSpace; + int * l_int_ptr; + int i; + int lStrLen; + + FILE * lFile = fopen(lFilename,"r"); + if + (lFile == NULL) + { + return 1; + } + fseek(lFile,0,SEEK_END); + lStrLen = ftell(lFile); + fseek(lFile,0,SEEK_SET); + lMatrix = (char *) malloc(lStrLen + 1); + fread(lMatrix,lStrLen,1,lFile); + fclose(lFile); + lMatrix[lStrLen] = 0; + lCurrentPtr = lMatrix; + + // replace ',' by 0 + while + (*lCurrentPtr != 0 ) + { + if + (*lCurrentPtr == ' ') + { + *lCurrentPtr = 0; + ++lNbComp; + } + ++lCurrentPtr; + } + ++lNbComp; + lCurrentPtr = lMatrix; + + lNbComp = (int) (sqrt(4*lNbComp + 1)/2. - 0.5); + lMctComp = lNbComp * lNbComp; + lTotalComp = lMctComp + lNbComp; + lSpace = (float *) malloc(lTotalComp * sizeof(float)); + lCurrentDoublePtr = lSpace; + for + (i=0;i> */ +#ifdef USE_JPWL + /* ------------------------------------------------------ */ + + case 'W': /* JPWL capabilities switched on */ + { + char *token = NULL; + int hprot, pprot, sens, addr, size, range; + + /* we need to enable indexing */ + if (!indexfilename || !*indexfilename) { + strncpy(indexfilename, JPWL_PRIVATEINDEX_NAME, OPJ_PATH_LEN); + } + + /* search for different protection methods */ + + /* break the option in comma points and parse the result */ + token = strtok(optarg, ","); + while(token != NULL) { + + /* search header error protection method */ + if (*token == 'h') { + + static int tile = 0, tilespec = 0, lasttileno = 0; + + hprot = 1; /* predefined method */ + + if(sscanf(token, "h=%d", &hprot) == 1) { + /* Main header, specified */ + if (!((hprot == 0) || (hprot == 1) || (hprot == 16) || (hprot == 32) || + ((hprot >= 37) && (hprot <= 128)))) { + fprintf(stderr, "ERROR -> invalid main header protection method h = %d\n", hprot); + return 1; + } + parameters->jpwl_hprot_MH = hprot; + + } else if(sscanf(token, "h%d=%d", &tile, &hprot) == 2) { + /* Tile part header, specified */ + if (!((hprot == 0) || (hprot == 1) || (hprot == 16) || (hprot == 32) || + ((hprot >= 37) && (hprot <= 128)))) { + fprintf(stderr, "ERROR -> invalid tile part header protection method h = %d\n", hprot); + return 1; + } + if (tile < 0) { + fprintf(stderr, "ERROR -> invalid tile part number on protection method t = %d\n", tile); + return 1; + } + if (tilespec < JPWL_MAX_NO_TILESPECS) { + parameters->jpwl_hprot_TPH_tileno[tilespec] = lasttileno = tile; + parameters->jpwl_hprot_TPH[tilespec++] = hprot; + } + + } else if(sscanf(token, "h%d", &tile) == 1) { + /* Tile part header, unspecified */ + if (tile < 0) { + fprintf(stderr, "ERROR -> invalid tile part number on protection method t = %d\n", tile); + return 1; + } + if (tilespec < JPWL_MAX_NO_TILESPECS) { + parameters->jpwl_hprot_TPH_tileno[tilespec] = lasttileno = tile; + parameters->jpwl_hprot_TPH[tilespec++] = hprot; + } + + + } else if (!strcmp(token, "h")) { + /* Main header, unspecified */ + parameters->jpwl_hprot_MH = hprot; + + } else { + fprintf(stderr, "ERROR -> invalid protection method selection = %s\n", token); + return 1; + }; + + } + + /* search packet error protection method */ + if (*token == 'p') { + + static int pack = 0, tile = 0, packspec = 0; + + pprot = 1; /* predefined method */ + + if (sscanf(token, "p=%d", &pprot) == 1) { + /* Method for all tiles and all packets */ + if (!((pprot == 0) || (pprot == 1) || (pprot == 16) || (pprot == 32) || + ((pprot >= 37) && (pprot <= 128)))) { + fprintf(stderr, "ERROR -> invalid default packet protection method p = %d\n", pprot); + return 1; + } + parameters->jpwl_pprot_tileno[0] = 0; + parameters->jpwl_pprot_packno[0] = 0; + parameters->jpwl_pprot[0] = pprot; + + } else if (sscanf(token, "p%d=%d", &tile, &pprot) == 2) { + /* method specified from that tile on */ + if (!((pprot == 0) || (pprot == 1) || (pprot == 16) || (pprot == 32) || + ((pprot >= 37) && (pprot <= 128)))) { + fprintf(stderr, "ERROR -> invalid packet protection method p = %d\n", pprot); + return 1; + } + if (tile < 0) { + fprintf(stderr, "ERROR -> invalid tile part number on protection method p = %d\n", tile); + return 1; + } + if (packspec < JPWL_MAX_NO_PACKSPECS) { + parameters->jpwl_pprot_tileno[packspec] = tile; + parameters->jpwl_pprot_packno[packspec] = 0; + parameters->jpwl_pprot[packspec++] = pprot; + } + + } else if (sscanf(token, "p%d:%d=%d", &tile, &pack, &pprot) == 3) { + /* method fully specified from that tile and that packet on */ + if (!((pprot == 0) || (pprot == 1) || (pprot == 16) || (pprot == 32) || + ((pprot >= 37) && (pprot <= 128)))) { + fprintf(stderr, "ERROR -> invalid packet protection method p = %d\n", pprot); + return 1; + } + if (tile < 0) { + fprintf(stderr, "ERROR -> invalid tile part number on protection method p = %d\n", tile); + return 1; + } + if (pack < 0) { + fprintf(stderr, "ERROR -> invalid packet number on protection method p = %d\n", pack); + return 1; + } + if (packspec < JPWL_MAX_NO_PACKSPECS) { + parameters->jpwl_pprot_tileno[packspec] = tile; + parameters->jpwl_pprot_packno[packspec] = pack; + parameters->jpwl_pprot[packspec++] = pprot; + } + + } else if (sscanf(token, "p%d:%d", &tile, &pack) == 2) { + /* default method from that tile and that packet on */ + if (!((pprot == 0) || (pprot == 1) || (pprot == 16) || (pprot == 32) || + ((pprot >= 37) && (pprot <= 128)))) { + fprintf(stderr, "ERROR -> invalid packet protection method p = %d\n", pprot); + return 1; + } + if (tile < 0) { + fprintf(stderr, "ERROR -> invalid tile part number on protection method p = %d\n", tile); + return 1; + } + if (pack < 0) { + fprintf(stderr, "ERROR -> invalid packet number on protection method p = %d\n", pack); + return 1; + } + if (packspec < JPWL_MAX_NO_PACKSPECS) { + parameters->jpwl_pprot_tileno[packspec] = tile; + parameters->jpwl_pprot_packno[packspec] = pack; + parameters->jpwl_pprot[packspec++] = pprot; + } + + } else if (sscanf(token, "p%d", &tile) == 1) { + /* default from a tile on */ + if (tile < 0) { + fprintf(stderr, "ERROR -> invalid tile part number on protection method p = %d\n", tile); + return 1; + } + if (packspec < JPWL_MAX_NO_PACKSPECS) { + parameters->jpwl_pprot_tileno[packspec] = tile; + parameters->jpwl_pprot_packno[packspec] = 0; + parameters->jpwl_pprot[packspec++] = pprot; + } + + + } else if (!strcmp(token, "p")) { + /* all default */ + parameters->jpwl_pprot_tileno[0] = 0; + parameters->jpwl_pprot_packno[0] = 0; + parameters->jpwl_pprot[0] = pprot; + + } else { + fprintf(stderr, "ERROR -> invalid protection method selection = %s\n", token); + return 1; + }; + + } + + /* search sensitivity method */ + if (*token == 's') { + + static int tile = 0, tilespec = 0, lasttileno = 0; + + sens = 0; /* predefined: relative error */ + + if(sscanf(token, "s=%d", &sens) == 1) { + /* Main header, specified */ + if ((sens < -1) || (sens > 7)) { + fprintf(stderr, "ERROR -> invalid main header sensitivity method s = %d\n", sens); + return 1; + } + parameters->jpwl_sens_MH = sens; + + } else if(sscanf(token, "s%d=%d", &tile, &sens) == 2) { + /* Tile part header, specified */ + if ((sens < -1) || (sens > 7)) { + fprintf(stderr, "ERROR -> invalid tile part header sensitivity method s = %d\n", sens); + return 1; + } + if (tile < 0) { + fprintf(stderr, "ERROR -> invalid tile part number on sensitivity method t = %d\n", tile); + return 1; + } + if (tilespec < JPWL_MAX_NO_TILESPECS) { + parameters->jpwl_sens_TPH_tileno[tilespec] = lasttileno = tile; + parameters->jpwl_sens_TPH[tilespec++] = sens; + } + + } else if(sscanf(token, "s%d", &tile) == 1) { + /* Tile part header, unspecified */ + if (tile < 0) { + fprintf(stderr, "ERROR -> invalid tile part number on sensitivity method t = %d\n", tile); + return 1; + } + if (tilespec < JPWL_MAX_NO_TILESPECS) { + parameters->jpwl_sens_TPH_tileno[tilespec] = lasttileno = tile; + parameters->jpwl_sens_TPH[tilespec++] = hprot; + } + + } else if (!strcmp(token, "s")) { + /* Main header, unspecified */ + parameters->jpwl_sens_MH = sens; + + } else { + fprintf(stderr, "ERROR -> invalid sensitivity method selection = %s\n", token); + return 1; + }; + + parameters->jpwl_sens_size = 2; /* 2 bytes for default size */ + } + + /* search addressing size */ + if (*token == 'a') { + + + addr = 0; /* predefined: auto */ + + if(sscanf(token, "a=%d", &addr) == 1) { + /* Specified */ + if ((addr != 0) && (addr != 2) && (addr != 4)) { + fprintf(stderr, "ERROR -> invalid addressing size a = %d\n", addr); + return 1; + } + parameters->jpwl_sens_addr = addr; + + } else if (!strcmp(token, "a")) { + /* default */ + parameters->jpwl_sens_addr = addr; /* auto for default size */ + + } else { + fprintf(stderr, "ERROR -> invalid addressing selection = %s\n", token); + return 1; + }; + + } + + /* search sensitivity size */ + if (*token == 'z') { + + + size = 1; /* predefined: 1 byte */ + + if(sscanf(token, "z=%d", &size) == 1) { + /* Specified */ + if ((size != 0) && (size != 1) && (size != 2)) { + fprintf(stderr, "ERROR -> invalid sensitivity size z = %d\n", size); + return 1; + } + parameters->jpwl_sens_size = size; + + } else if (!strcmp(token, "a")) { + /* default */ + parameters->jpwl_sens_size = size; /* 1 for default size */ + + } else { + fprintf(stderr, "ERROR -> invalid size selection = %s\n", token); + return 1; + }; + + } + + /* search range method */ + if (*token == 'g') { + + + range = 0; /* predefined: 0 (packet) */ + + if(sscanf(token, "g=%d", &range) == 1) { + /* Specified */ + if ((range < 0) || (range > 3)) { + fprintf(stderr, "ERROR -> invalid sensitivity range method g = %d\n", range); + return 1; + } + parameters->jpwl_sens_range = range; + + } else if (!strcmp(token, "g")) { + /* default */ + parameters->jpwl_sens_range = range; + + } else { + fprintf(stderr, "ERROR -> invalid range selection = %s\n", token); + return 1; + }; + + } + + /* next token or bust */ + token = strtok(NULL, ","); + }; + + + /* some info */ + fprintf(stdout, "Info: JPWL capabilities enabled\n"); + parameters->jpwl_epc_on = true; + + } + break; +#endif /* USE_JPWL */ +/* < Command line not valid\n"); + return 1; + } + } + + /* check for possible errors */ + if (parameters->cp_cinema){ + if(parameters->tcp_numlayers > 1){ + parameters->cp_rsiz = STD_RSIZ; + fprintf(stdout,"Warning: DC profiles do not allow more than one quality layer. The codestream created will not be compliant with the DC profile\n"); + } + } + if(img_fol->set_imgdir == 1){ + if(!(parameters->infile[0] == 0)){ + fprintf(stderr, "Error: options -ImgDir and -i cannot be used together !!\n"); + return 1; + } + if(img_fol->set_out_format == 0){ + fprintf(stderr, "Error: When -ImgDir is used, -OutFor must be used !!\n"); + fprintf(stderr, "Only one format allowed! Valid formats are j2k and jp2!!\n"); + return 1; + } + if(!((parameters->outfile[0] == 0))){ + fprintf(stderr, "Error: options -ImgDir and -o cannot be used together !!\n"); + fprintf(stderr, "Specify OutputFormat using -OutFor !!\n"); + return 1; + } + }else{ + if((parameters->infile[0] == 0) || (parameters->outfile[0] == 0)) { + fprintf(stderr, "Error: One of the options; -i or -ImgDir must be specified\n"); + fprintf(stderr, "Error: When using -i; -o must be used\n"); + fprintf(stderr, "usage: image_to_j2k -i image-file -o j2k/jp2-file (+ options)\n"); + return 1; + } + } + + if (parameters->decod_format == RAW_DFMT && raw_cp->rawWidth == 0) { + fprintf(stderr,"\nError: invalid raw image parameters\n"); + fprintf(stderr,"Please use the Format option -F:\n"); + fprintf(stderr,"-F rawWidth,rawHeight,rawComp,rawBitDepth,s/u (Signed/Unsigned)\n"); + fprintf(stderr,"Example: -i lena.raw -o lena.j2k -F 512,512,3,8,u\n"); + fprintf(stderr,"Aborting\n"); + return 1; + } + + if ((parameters->cp_disto_alloc || parameters->cp_fixed_alloc || parameters->cp_fixed_quality) + && (!(parameters->cp_disto_alloc ^ parameters->cp_fixed_alloc ^ parameters->cp_fixed_quality))) { + fprintf(stderr, "Error: options -r -q and -f cannot be used together !!\n"); + return 1; + } /* mod fixed_quality */ + + /* if no rate entered, lossless by default */ + if (parameters->tcp_numlayers == 0) { + parameters->tcp_rates[0] = 0; /* MOD antonin : losslessbug */ + parameters->tcp_numlayers++; + parameters->cp_disto_alloc = 1; + } + + if((parameters->cp_tx0 > parameters->image_offset_x0) || (parameters->cp_ty0 > parameters->image_offset_y0)) { + fprintf(stderr, + "Error: Tile offset dimension is unnappropriate --> TX0(%d)<=IMG_X0(%d) TYO(%d)<=IMG_Y0(%d) \n", + parameters->cp_tx0, parameters->image_offset_x0, parameters->cp_ty0, parameters->image_offset_y0); + return 1; + } + + for (i = 0; i < parameters->numpocs; i++) { + if (parameters->POC[i].prg == -1) { + fprintf(stderr, + "Unrecognized progression order in option -P (POC n %d) [LRCP, RLCP, RPCL, PCRL, CPRL] !!\n", + i + 1); + } + } + + return 0; +} + +/* -------------------------------------------------------------------------- */ + +/** +sample error callback expecting a FILE* client object +*/ +void error_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[ERROR] %s", msg); +} +/** +sample warning callback expecting a FILE* client object +*/ +void warning_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[WARNING] %s", msg); +} +/** +sample debug callback expecting a FILE* client object +*/ +void info_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[INFO] %s", msg); +} + +/* -------------------------------------------------------------------------- */ + +int main(int argc, char **argv) { + bool bSuccess; + opj_cparameters_t parameters; /* compression parameters */ + img_fol_t img_fol; + opj_image_t *image = NULL; + int i,num_images; + int imageno; + dircnt_t *dirptr; + raw_cparameters_t raw_cp; + opj_codestream_info_t cstr_info; /* Codestream information structure */ + char indexfilename[OPJ_PATH_LEN]; /* index file name */ + opj_stream_t *cio = 00; + opj_codec_t* cinfo = 00; + FILE *f = NULL; + + /* + configure the event callbacks (not required) + setting of each callback is optionnal + */ + /* set encoding parameters to default values */ + opj_set_default_encoder_parameters(¶meters); + + /* Initialize indexfilename and img_fol */ + *indexfilename = 0; + memset(&img_fol,0,sizeof(img_fol_t)); + + /* parse input and get user encoding parameters */ + if(parse_cmdline_encoder(argc, argv, ¶meters,&img_fol, &raw_cp, indexfilename) == 1) { + return 1; + } + + if (parameters.cp_cinema){ + img_fol.rates = (float*)malloc(parameters.tcp_numlayers * sizeof(float)); + for(i=0; i< parameters.tcp_numlayers; i++){ + img_fol.rates[i] = parameters.tcp_rates[i]; + } + cinema_parameters(¶meters); + } + + /* Create comment for codestream */ + if(parameters.cp_comment == NULL) { + const char comment[] = "Created by OpenJPEG version "; + const size_t clen = strlen(comment); + const char *version = opj_version(); +/* UniPG>> */ +#ifdef USE_JPWL + parameters.cp_comment = (char*)malloc(clen+strlen(version)+11); + sprintf(parameters.cp_comment,"%s%s with JPWL", comment, version); +#else + parameters.cp_comment = (char*)malloc(clen+strlen(version)+1); + sprintf(parameters.cp_comment,"%s%s", comment, version); +#endif +/* <filename_buf = (char*)malloc(num_images*OPJ_PATH_LEN*sizeof(char)); // Stores at max 10 image file names + dirptr->filename = (char**) malloc(num_images*sizeof(char*)); + if(!dirptr->filename_buf){ + return 0; + } + for(i=0;ifilename[i] = dirptr->filename_buf + i*OPJ_PATH_LEN; + } + } + if(load_images(dirptr,img_fol.imgdirpath)==1){ + return 0; + } + if (num_images==0){ + fprintf(stdout,"Folder is empty\n"); + return 0; + } + }else{ + num_images=1; + } + /*Encoding image one by one*/ + for(imageno=0;imagenonumcomps == 3 ? 1 : 0; + + if(parameters.cp_cinema){ + cinema_setup_encoder(¶meters,image,&img_fol); + } + + /* encode the destination image */ + /* ---------------------------- */ + + + cinfo = parameters.cod_format == J2K_CFMT ? opj_create_compress(CODEC_J2K) : opj_create_compress(CODEC_JP2); + opj_setup_encoder(cinfo, ¶meters, image); + f = fopen(parameters.outfile, "wb"); + if + (! f) + { + fprintf(stderr, "failed to encode image\n"); + return 1; + } + /* open a byte stream for writing */ + /* allocate memory for all tiles */ + cio = opj_stream_create_default_file_stream(f,false); + if + (! cio) + { + return 1; + } + /* encode the image */ + /*if (*indexfilename) // If need to extract codestream information + bSuccess = opj_encode_with_info(cinfo, cio, image, &cstr_info); + else*/ + bSuccess = opj_start_compress(cinfo,image,cio); + bSuccess = bSuccess && opj_encode(cinfo, cio); + bSuccess = bSuccess && opj_end_compress(cinfo, cio); + + if + (!bSuccess) + { + opj_stream_destroy(cio); + fclose(f); + fprintf(stderr, "failed to encode image\n"); + return 1; + } + + fprintf(stderr,"Generated outfile %s\n",parameters.outfile); + /* close and free the byte stream */ + opj_stream_destroy(cio); + fclose(f); + + /* Write the index to disk */ + if (*indexfilename) { + bSuccess = write_index_file(&cstr_info, indexfilename); + if (bSuccess) { + fprintf(stderr, "Failed to output index file\n"); + } + } + + /* free remaining compression structures */ + opj_destroy_codec(cinfo); + if (*indexfilename) + opj_destroy_cstr_info(&cstr_info); + + /* free image data */ + opj_image_destroy(image); + } + + /* free user parameters structure */ + if(parameters.cp_comment) free(parameters.cp_comment); + if(parameters.cp_matrice) free(parameters.cp_matrice); + + return 0; +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/codec/index.c b/gdcm/Utilities/gdcmopenjpeg-v2/codec/index.c new file mode 100644 index 0000000..dd14596 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/codec/index.c @@ -0,0 +1,391 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2003-2007, Francois-Olivier Devaux + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include "openjpeg.h" +#include "index.h" + +/* ------------------------------------------------------------------------------------ */ + +/** +Write a structured index to a file +@param cstr_info Codestream information +@param index Index filename +@return Returns 0 if successful, returns 1 otherwise +*/ +int write_index_file(opj_codestream_info_t *cstr_info, char *index) { + int tileno, compno, layno, resno, precno, pack_nb, x, y; + FILE *stream = NULL; + double total_disto = 0; +/* UniPG>> */ + int tilepartno; + char disto_on, numpix_on; + +#ifdef USE_JPWL + if (!strcmp(index, JPWL_PRIVATEINDEX_NAME)) + return 0; +#endif /* USE_JPWL */ +/* <tile[0].distotile) + disto_on = 1; + else + disto_on = 0; + + if (cstr_info->tile[0].numpix) + numpix_on = 1; + else + numpix_on = 0; + + fprintf(stream, "%d %d\n", cstr_info->image_w, cstr_info->image_h); + fprintf(stream, "%d\n", cstr_info->prog); + fprintf(stream, "%d %d\n", cstr_info->tile_x, cstr_info->tile_y); + fprintf(stream, "%d %d\n", cstr_info->tw, cstr_info->th); + fprintf(stream, "%d\n", cstr_info->numcomps); + fprintf(stream, "%d\n", cstr_info->numlayers); + fprintf(stream, "%d\n", cstr_info->numdecompos[0]); /* based on component 0 */ + + for (resno = cstr_info->numdecompos[0]; resno >= 0; resno--) { + fprintf(stream, "[%d,%d] ", + (1 << cstr_info->tile[0].pdx[resno]), (1 << cstr_info->tile[0].pdx[resno])); /* based on tile 0 and component 0 */ + } + + fprintf(stream, "\n"); +/* UniPG>> */ + fprintf(stream, "%d\n", cstr_info->main_head_start); +/* <main_head_end); + fprintf(stream, "%d\n", cstr_info->codestream_size); + + fprintf(stream, "\nINFO ON TILES\n"); + fprintf(stream, "tileno start_pos end_hd end_tile nbparts"); + if (disto_on) + fprintf(stream," disto"); + if (numpix_on) + fprintf(stream," nbpix"); + if (disto_on && numpix_on) + fprintf(stream," disto/nbpix"); + fprintf(stream, "\n"); + + for (tileno = 0; tileno < cstr_info->tw * cstr_info->th; tileno++) { + fprintf(stream, "%4d %9d %9d %9d %9d", + cstr_info->tile[tileno].tileno, + cstr_info->tile[tileno].start_pos, + cstr_info->tile[tileno].end_header, + cstr_info->tile[tileno].end_pos, + cstr_info->tile[tileno].num_tps); + if (disto_on) + fprintf(stream," %9e", cstr_info->tile[tileno].distotile); + if (numpix_on) + fprintf(stream," %9d", cstr_info->tile[tileno].numpix); + if (disto_on && numpix_on) + fprintf(stream," %9e", cstr_info->tile[tileno].distotile / cstr_info->tile[tileno].numpix); + fprintf(stream, "\n"); + } + + for (tileno = 0; tileno < cstr_info->tw * cstr_info->th; tileno++) { + int start_pos, end_ph_pos, end_pos; + double disto = 0; + int max_numdecompos = 0; + pack_nb = 0; + + for (compno = 0; compno < cstr_info->numcomps; compno++) { + if (max_numdecompos < cstr_info->numdecompos[compno]) + max_numdecompos = cstr_info->numdecompos[compno]; + } + + fprintf(stream, "\nTILE %d DETAILS\n", tileno); + fprintf(stream, "part_nb tileno start_pack num_packs start_pos end_tph_pos end_pos\n"); + for (tilepartno = 0; tilepartno < cstr_info->tile[tileno].num_tps; tilepartno++) + fprintf(stream, "%4d %9d %9d %9d %9d %11d %9d\n", + tilepartno, tileno, + cstr_info->tile[tileno].tp[tilepartno].tp_start_pack, + cstr_info->tile[tileno].tp[tilepartno].tp_numpacks, + cstr_info->tile[tileno].tp[tilepartno].tp_start_pos, + cstr_info->tile[tileno].tp[tilepartno].tp_end_header, + cstr_info->tile[tileno].tp[tilepartno].tp_end_pos + ); + + if (cstr_info->prog == LRCP) { /* LRCP */ + fprintf(stream, "LRCP\npack_nb tileno layno resno compno precno start_pos end_ph_pos end_pos"); + if (disto_on) + fprintf(stream, " disto"); + fprintf(stream,"\n"); + + for (layno = 0; layno < cstr_info->numlayers; layno++) { + for (resno = 0; resno < max_numdecompos + 1; resno++) { + for (compno = 0; compno < cstr_info->numcomps; compno++) { + int prec_max; + if (resno > cstr_info->numdecompos[compno]) + break; + prec_max = cstr_info->tile[tileno].pw[resno] * cstr_info->tile[tileno].ph[resno]; + for (precno = 0; precno < prec_max; precno++) { + start_pos = cstr_info->tile[tileno].packet[pack_nb].start_pos; + end_ph_pos = cstr_info->tile[tileno].packet[pack_nb].end_ph_pos; + end_pos = cstr_info->tile[tileno].packet[pack_nb].end_pos; + disto = cstr_info->tile[tileno].packet[pack_nb].disto; + fprintf(stream, "%4d %6d %7d %5d %6d %6d %6d %6d %7d", + pack_nb, tileno, layno, resno, compno, precno, start_pos, end_ph_pos, end_pos); + if (disto_on) + fprintf(stream, " %8e", disto); + fprintf(stream, "\n"); + total_disto += disto; + pack_nb++; + } + } + } + } + } /* LRCP */ + + else if (cstr_info->prog == RLCP) { /* RLCP */ + fprintf(stream, "RLCP\npack_nb tileno resno layno compno precno start_pos end_ph_pos end_pos\n"); + if (disto_on) + fprintf(stream, " disto"); + fprintf(stream,"\n"); + + for (resno = 0; resno < max_numdecompos + 1; resno++) { + for (layno = 0; layno < cstr_info->numlayers; layno++) { + for (compno = 0; compno < cstr_info->numcomps; compno++) { + int prec_max; + if (resno > cstr_info->numdecompos[compno]) + break; + prec_max = cstr_info->tile[tileno].pw[resno] * cstr_info->tile[tileno].ph[resno]; + for (precno = 0; precno < prec_max; precno++) { + start_pos = cstr_info->tile[tileno].packet[pack_nb].start_pos; + end_ph_pos = cstr_info->tile[tileno].packet[pack_nb].end_ph_pos; + end_pos = cstr_info->tile[tileno].packet[pack_nb].end_pos; + disto = cstr_info->tile[tileno].packet[pack_nb].disto; + fprintf(stream, "%4d %6d %5d %7d %6d %6d %9d %9d %7d", + pack_nb, tileno, resno, layno, compno, precno, start_pos, end_ph_pos, end_pos); + if (disto_on) + fprintf(stream, " %8e", disto); + fprintf(stream, "\n"); + total_disto += disto; + pack_nb++; + } + } + } + } + } /* RLCP */ + + else if (cstr_info->prog == RPCL) { /* RPCL */ + + fprintf(stream, "RPCL\npack_nb tileno resno precno compno layno start_pos end_ph_pos end_pos"); + if (disto_on) + fprintf(stream, " disto"); + fprintf(stream,"\n"); + + for (resno = 0; resno < max_numdecompos + 1; resno++) { + int numprec = cstr_info->tile[tileno].pw[resno] * cstr_info->tile[tileno].ph[resno]; + for (precno = 0; precno < numprec; precno++) { + /* I suppose components have same XRsiz, YRsiz */ + int x0 = cstr_info->tile_Ox + tileno - (int)floor((float)tileno/(float)cstr_info->tw ) * cstr_info->tw * cstr_info->tile_x; + int y0 = cstr_info->tile_Ox + (int)floor( (float)tileno/(float)cstr_info->tw ) * cstr_info->tile_y; + int x1 = x0 + cstr_info->tile_x; + int y1 = y0 + cstr_info->tile_y; + for (compno = 0; compno < cstr_info->numcomps; compno++) { + int pcnx = cstr_info->tile[tileno].pw[resno]; + int pcx = (int) pow( 2, cstr_info->tile[tileno].pdx[resno] + cstr_info->numdecompos[compno] - resno ); + int pcy = (int) pow( 2, cstr_info->tile[tileno].pdy[resno] + cstr_info->numdecompos[compno] - resno ); + int precno_x = precno - (int) floor( (float)precno/(float)pcnx ) * pcnx; + int precno_y = (int) floor( (float)precno/(float)pcnx ); + if (resno > cstr_info->numdecompos[compno]) + break; + for(y = y0; y < y1; y++) { + if (precno_y*pcy == y ) { + for (x = x0; x < x1; x++) { + if (precno_x*pcx == x ) { + for (layno = 0; layno < cstr_info->numlayers; layno++) { + start_pos = cstr_info->tile[tileno].packet[pack_nb].start_pos; + end_ph_pos = cstr_info->tile[tileno].packet[pack_nb].end_ph_pos; + end_pos = cstr_info->tile[tileno].packet[pack_nb].end_pos; + disto = cstr_info->tile[tileno].packet[pack_nb].disto; + fprintf(stream, "%4d %6d %5d %6d %6d %7d %9d %9d %7d", + pack_nb, tileno, resno, precno, compno, layno, start_pos, end_ph_pos, end_pos); + if (disto_on) + fprintf(stream, " %8e", disto); + fprintf(stream, "\n"); + total_disto += disto; + pack_nb++; + } + } + }/* x = x0..x1 */ + } + } /* y = y0..y1 */ + } /* precno */ + } /* compno */ + } /* resno */ + } /* RPCL */ + + else if (cstr_info->prog == PCRL) { /* PCRL */ + /* I suppose components have same XRsiz, YRsiz */ + int x0 = cstr_info->tile_Ox + tileno - (int)floor( (float)tileno/(float)cstr_info->tw ) * cstr_info->tw * cstr_info->tile_x; + int y0 = cstr_info->tile_Ox + (int)floor( (float)tileno/(float)cstr_info->tw ) * cstr_info->tile_y; + int x1 = x0 + cstr_info->tile_x; + int y1 = y0 + cstr_info->tile_y; + + // Count the maximum number of precincts + int max_numprec = 0; + for (resno = 0; resno < max_numdecompos + 1; resno++) { + int numprec = cstr_info->tile[tileno].pw[resno] * cstr_info->tile[tileno].ph[resno]; + if (numprec > max_numprec) + max_numprec = numprec; + } + + fprintf(stream, "PCRL\npack_nb tileno precno compno resno layno start_pos end_ph_pos end_pos"); + if (disto_on) + fprintf(stream, " disto"); + fprintf(stream,"\n"); + + for (precno = 0; precno < max_numprec; precno++) { + for (compno = 0; compno < cstr_info->numcomps; compno++) { + for (resno = 0; resno < cstr_info->numdecompos[compno] + 1; resno++) { + int numprec = cstr_info->tile[tileno].pw[resno] * cstr_info->tile[tileno].ph[resno]; + int pcnx = cstr_info->tile[tileno].pw[resno]; + int pcx = (int) pow( 2, cstr_info->tile[tileno].pdx[resno] + cstr_info->numdecompos[compno] - resno ); + int pcy = (int) pow( 2, cstr_info->tile[tileno].pdy[resno] + cstr_info->numdecompos[compno] - resno ); + int precno_x = precno - (int) floor( (float)precno/(float)pcnx ) * pcnx; + int precno_y = (int) floor( (float)precno/(float)pcnx ); + if (precno >= numprec) + continue; + for(y = y0; y < y1; y++) { + if (precno_y*pcy == y ) { + for (x = x0; x < x1; x++) { + if (precno_x*pcx == x ) { + for (layno = 0; layno < cstr_info->numlayers; layno++) { + start_pos = cstr_info->tile[tileno].packet[pack_nb].start_pos; + end_ph_pos = cstr_info->tile[tileno].packet[pack_nb].end_ph_pos; + end_pos = cstr_info->tile[tileno].packet[pack_nb].end_pos; + disto = cstr_info->tile[tileno].packet[pack_nb].disto; + fprintf(stream, "%4d %6d %6d %6d %5d %7d %9d %9d %7d", + pack_nb, tileno, precno, compno, resno, layno, start_pos, end_ph_pos, end_pos); + if (disto_on) + fprintf(stream, " %8e", disto); + fprintf(stream, "\n"); + total_disto += disto; + pack_nb++; + } + } + }/* x = x0..x1 */ + } + } /* y = y0..y1 */ + } /* resno */ + } /* compno */ + } /* precno */ + } /* PCRL */ + + else { /* CPRL */ + // Count the maximum number of precincts + int max_numprec = 0; + for (resno = 0; resno < max_numdecompos + 1; resno++) { + int numprec = cstr_info->tile[tileno].pw[resno] * cstr_info->tile[tileno].ph[resno]; + if (numprec > max_numprec) + max_numprec = numprec; + } + + fprintf(stream, "CPRL\npack_nb tileno compno precno resno layno start_pos end_ph_pos end_pos"); + if (disto_on) + fprintf(stream, " disto"); + fprintf(stream,"\n"); + + for (compno = 0; compno < cstr_info->numcomps; compno++) { + /* I suppose components have same XRsiz, YRsiz */ + int x0 = cstr_info->tile_Ox + tileno - (int)floor( (float)tileno/(float)cstr_info->tw ) * cstr_info->tw * cstr_info->tile_x; + int y0 = cstr_info->tile_Ox + (int)floor( (float)tileno/(float)cstr_info->tw ) * cstr_info->tile_y; + int x1 = x0 + cstr_info->tile_x; + int y1 = y0 + cstr_info->tile_y; + + for (precno = 0; precno < max_numprec; precno++) { + for (resno = 0; resno < cstr_info->numdecompos[compno] + 1; resno++) { + int numprec = cstr_info->tile[tileno].pw[resno] * cstr_info->tile[tileno].ph[resno]; + int pcnx = cstr_info->tile[tileno].pw[resno]; + int pcx = (int) pow( 2, cstr_info->tile[tileno].pdx[resno] + cstr_info->numdecompos[compno] - resno ); + int pcy = (int) pow( 2, cstr_info->tile[tileno].pdy[resno] + cstr_info->numdecompos[compno] - resno ); + int precno_x = precno - (int) floor( (float)precno/(float)pcnx ) * pcnx; + int precno_y = (int) floor( (float)precno/(float)pcnx ); + if (precno >= numprec) + continue; + + for(y = y0; y < y1; y++) { + if (precno_y*pcy == y ) { + for (x = x0; x < x1; x++) { + if (precno_x*pcx == x ) { + for (layno = 0; layno < cstr_info->numlayers; layno++) { + start_pos = cstr_info->tile[tileno].packet[pack_nb].start_pos; + end_ph_pos = cstr_info->tile[tileno].packet[pack_nb].end_ph_pos; + end_pos = cstr_info->tile[tileno].packet[pack_nb].end_pos; + disto = cstr_info->tile[tileno].packet[pack_nb].disto; + fprintf(stream, "%4d %6d %6d %6d %5d %7d %9d %9d %7d", + pack_nb, tileno, compno, precno, resno, layno, start_pos, end_ph_pos, end_pos); + if (disto_on) + fprintf(stream, " %8e", disto); + fprintf(stream, "\n"); + total_disto += disto; + pack_nb++; + } + } + }/* x = x0..x1 */ + } + } /* y = y0..y1 */ + } /* resno */ + } /* precno */ + } /* compno */ + } /* CPRL */ + } /* tileno */ + + if (disto_on) { + fprintf(stream, "%8e\n", cstr_info->D_max); /* SE max */ + fprintf(stream, "%.8e\n", total_disto); /* SE totale */ + } +/* UniPG>> */ + /* print the markers' list */ + if (cstr_info->marknum) { + fprintf(stream, "\nMARKER LIST\n"); + fprintf(stream, "%d\n", cstr_info->marknum); + fprintf(stream, "type\tstart_pos length\n"); + for (x = 0; x < cstr_info->marknum; x++) + fprintf(stream, "%X\t%9d %9d\n", cstr_info->marker[x].type, cstr_info->marker[x].pos, cstr_info->marker[x].len); + } +/* < + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#define USE_OPJ_DEPRECATED +#include "openjpeg.h" +#include "j2k.h" +#include "jp2.h" +#include "compat/getopt.h" +#include "convert.h" +#include "dirent.h" +#include "index.h" + +#ifndef WIN32 +#include +#define _stricmp strcasecmp +#define _strnicmp strncasecmp +#endif + +/* ----------------------------------------------------------------------- */ + +#define J2K_CFMT 0 +#define JP2_CFMT 1 +#define JPT_CFMT 2 + +#define PXM_DFMT 10 +#define PGX_DFMT 11 +#define BMP_DFMT 12 +#define YUV_DFMT 13 +#define TIF_DFMT 14 +#define RAW_DFMT 15 +#define TGA_DFMT 16 + +/* ----------------------------------------------------------------------- */ + +typedef struct dircnt{ + /** Buffer for holding images read from Directory*/ + char *filename_buf; + /** Pointer to the buffer*/ + char **filename; +}dircnt_t; + + +typedef struct img_folder{ + /** The directory path of the folder containing input images*/ + char *imgdirpath; + /** Output format*/ + const char *out_format; + /** Enable option*/ + char set_imgdir; + /** Enable Cod Format for output*/ + char set_out_format; + +}img_fol_t; + +void decode_help_display() { + fprintf(stdout,"HELP\n----\n\n"); + fprintf(stdout,"- the -h option displays this help information on screen\n\n"); + +/* UniPG>> */ + fprintf(stdout,"List of parameters for the JPEG 2000 " +#ifdef USE_JPWL + "+ JPWL " +#endif /* USE_JPWL */ + "decoder:\n"); +/* <\n"); + fprintf(stdout," REQUIRED only if an Input image directory not specified\n"); + fprintf(stdout," Currently accepts J2K-files, JP2-files and JPT-files. The file type\n"); + fprintf(stdout," is identified based on its suffix.\n"); + fprintf(stdout,"\n"); +} + +/* -------------------------------------------------------------------------- */ + +int get_num_images(char *imgdirpath){ + DIR *dir; + struct dirent* content; + int num_images = 0; + + /*Reading the input images from given input directory*/ + + dir= opendir(imgdirpath); + if(!dir){ + fprintf(stderr,"Could not open Folder %s\n",imgdirpath); + return 0; + } + + while((content=readdir(dir))!=NULL){ + if(strcmp(".",content->d_name)==0 || strcmp("..",content->d_name)==0 ) + continue; + num_images++; + } + return num_images; +} + +int load_images(dircnt_t *dirptr, char *imgdirpath){ + DIR *dir; + struct dirent* content; + int i = 0; + + /*Reading the input images from given input directory*/ + + dir= opendir(imgdirpath); + if(!dir){ + fprintf(stderr,"Could not open Folder %s\n",imgdirpath); + return 1; + }else { + fprintf(stderr,"Folder opened successfully\n"); + } + + while((content=readdir(dir))!=NULL){ + if(strcmp(".",content->d_name)==0 || strcmp("..",content->d_name)==0 ) + continue; + + strcpy(dirptr->filename[i],content->d_name); + i++; + } + return 0; +} + +int get_file_format(char *filename) { + unsigned int i; + static const char *extension[] = {"pgx", "pnm", "pgm", "ppm", "bmp","tif", "raw", "tga", "j2k", "jp2", "jpt", "j2c", "jpc" }; + static const int format[] = { PGX_DFMT, PXM_DFMT, PXM_DFMT, PXM_DFMT, BMP_DFMT, TIF_DFMT, RAW_DFMT, TGA_DFMT, J2K_CFMT, JP2_CFMT, JPT_CFMT, J2K_CFMT, J2K_CFMT }; + char * ext = strrchr(filename, '.'); + if (ext == NULL) + return -1; + ext++; + if(ext) { + for(i = 0; i < sizeof(format)/sizeof(*format); i++) { + if(_strnicmp(ext, extension[i], 3) == 0) { + return format[i]; + } + } + } + + return -1; +} + +char get_next_file(int imageno,dircnt_t *dirptr,img_fol_t *img_fol, opj_dparameters_t *parameters){ + char image_filename[OPJ_PATH_LEN], infilename[OPJ_PATH_LEN],outfilename[OPJ_PATH_LEN],temp_ofname[OPJ_PATH_LEN]; + char *temp_p, temp1[OPJ_PATH_LEN]=""; + + strcpy(image_filename,dirptr->filename[imageno]); + fprintf(stderr,"File Number %d \"%s\"\n",imageno,image_filename); + parameters->decod_format = get_file_format(image_filename); + if (parameters->decod_format == -1) + return 1; + sprintf(infilename,"%s/%s",img_fol->imgdirpath,image_filename); + strncpy(parameters->infile, infilename, sizeof(infilename)); + + //Set output file + strcpy(temp_ofname,strtok(image_filename,".")); + while((temp_p = strtok(NULL,".")) != NULL){ + strcat(temp_ofname,temp1); + sprintf(temp1,".%s",temp_p); + } + if(img_fol->set_out_format==1){ + sprintf(outfilename,"%s/%s.%s",img_fol->imgdirpath,temp_ofname,img_fol->out_format); + strncpy(parameters->outfile, outfilename, sizeof(outfilename)); + } + return 0; +} + +/* -------------------------------------------------------------------------- */ +int parse_cmdline_decoder(int argc, char **argv, opj_dparameters_t *parameters,img_fol_t *img_fol, char *indexfilename) { + /* parse the command line */ + int totlen; + option_t long_option[]={ + {"ImgDir",REQ_ARG, NULL ,'y'}, + }; + + const char optlist[] = "i:h"; + totlen=sizeof(long_option); + img_fol->set_out_format = 0; + while (1) { + int c = getopt_long(argc, argv,optlist,long_option,totlen); + if (c == -1) + break; + switch (c) { + case 'i': /* input file */ + { + char *infile = optarg; + parameters->decod_format = get_file_format(infile); + switch(parameters->decod_format) { + case J2K_CFMT: + case JP2_CFMT: + case JPT_CFMT: + break; + default: + fprintf(stderr, + "!! Unrecognized format for infile : %s [accept only *.j2k, *.jp2, *.jpc or *.jpt] !!\n\n", + infile); + return 1; + } + strncpy(parameters->infile, infile, sizeof(parameters->infile)-1); + } + break; + + /* ----------------------------------------------------- */ + + case 'h': /* display an help description */ + decode_help_display(); + return 1; + + /* ------------------------------------------------------ */ + + case 'y': /* Image Directory path */ + { + img_fol->imgdirpath = (char*)malloc(strlen(optarg) + 1); + strcpy(img_fol->imgdirpath,optarg); + img_fol->set_imgdir=1; + } + break; + + /* ----------------------------------------------------- */ + + default: + fprintf(stderr,"WARNING -> this option is not valid \"-%c %s\"\n",c, optarg); + break; + } + } + + /* check for possible errors */ + if(img_fol->set_imgdir==1){ + if(!(parameters->infile[0]==0)){ + fprintf(stderr, "Error: options -ImgDir and -i cannot be used together !!\n"); + return 1; + } + if(img_fol->set_out_format == 0){ + fprintf(stderr, "Error: When -ImgDir is used, -OutFor must be used !!\n"); + fprintf(stderr, "Only one format allowed! Valid format PGM, PPM, PNM, PGX, BMP, TIF, RAW and TGA!!\n"); + return 1; + } + if(!((parameters->outfile[0] == 0))){ + fprintf(stderr, "Error: options -ImgDir and -o cannot be used together !!\n"); + return 1; + } + }else{ + if((parameters->infile[0] == 0) ) { + fprintf(stderr, "Error: One of the options -i or -ImgDir must be specified\n"); + fprintf(stderr, "usage: image_to_j2k -i *.j2k/jp2/j2c (+ options)\n"); + return 1; + } + } + + return 0; +} + +/* -------------------------------------------------------------------------- */ + +/** +sample error callback expecting a FILE* client object +*/ +void error_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[ERROR] %s", msg); +} +/** +sample warning callback expecting a FILE* client object +*/ +void warning_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[WARNING] %s", msg); +} +/** +sample debug callback expecting no client object +*/ +void info_callback(const char *msg, void *client_data) { + (void)client_data; + fprintf(stdout, "[INFO] %s", msg); +} + +/* -------------------------------------------------------------------------- */ + +int main(int argc, char *argv[]) +{ + int ret; + opj_dparameters_t parameters; /* decompression parameters */ + img_fol_t img_fol; + opj_image_t *image = NULL; + FILE *fsrc = NULL; + bool bResult; + int num_images; + int i,imageno; + dircnt_t *dirptr; + opj_codec_t* dinfo = NULL; /* handle to a decompressor */ + opj_stream_t *cio = NULL; + opj_codestream_info_t cstr_info; /* Codestream information structure */ + char indexfilename[OPJ_PATH_LEN]; /* index file name */ + OPJ_INT32 l_tile_x0,l_tile_y0; + OPJ_UINT32 l_tile_width,l_tile_height,l_nb_tiles_x,l_nb_tiles_y; + + /* configure the event callbacks (not required) */ + + /* set decoding parameters to default values */ + opj_set_default_decoder_parameters(¶meters); + + /* Initialize indexfilename and img_fol */ + *indexfilename = 0; + memset(&img_fol,0,sizeof(img_fol_t)); + + /* parse input and get user encoding parameters */ + if(parse_cmdline_decoder(argc, argv, ¶meters,&img_fol, indexfilename) == 1) { + return EXIT_FAILURE; + } + + /* Initialize reading of directory */ + if(img_fol.set_imgdir==1){ + num_images=get_num_images(img_fol.imgdirpath); + + dirptr=(dircnt_t*)malloc(sizeof(dircnt_t)); + if(dirptr){ + dirptr->filename_buf = (char*)malloc(num_images*OPJ_PATH_LEN*sizeof(char)); // Stores at max 10 image file names + dirptr->filename = (char**) malloc(num_images*sizeof(char*)); + + if(!dirptr->filename_buf){ + return EXIT_FAILURE; + } + for(i=0;ifilename[i] = dirptr->filename_buf + i*OPJ_PATH_LEN; + } + } + if(load_images(dirptr,img_fol.imgdirpath)==1){ + return EXIT_FAILURE; + } + if (num_images==0){ + fprintf(stdout,"Folder is empty\n"); + return EXIT_FAILURE; + } + }else{ + num_images=1; + } + + /*Encoding image one by one*/ + for(imageno = 0; imageno < num_images ; imageno++) + { + image = NULL; + fprintf(stderr,"\n"); + + if(img_fol.set_imgdir==1){ + if (get_next_file(imageno, dirptr,&img_fol, ¶meters)) { + fprintf(stderr,"skipping file...\n"); + continue; + } + } + + /* read the input file and put it in memory */ + /* ---------------------------------------- */ + fsrc = fopen(parameters.infile, "rb"); + if (!fsrc) { + fprintf(stderr, "ERROR -> failed to open %s for reading\n", parameters.infile); + return EXIT_FAILURE; + } + cio = opj_stream_create_default_file_stream(fsrc,true); + /* decode the code-stream */ + /* ---------------------- */ + + switch (parameters.decod_format) + { + case J2K_CFMT: + { + /* JPEG-2000 codestream */ + + /* get a decoder handle */ + dinfo = opj_create_decompress(CODEC_J2K); + break; + } + case JP2_CFMT: + { + /* JPEG 2000 compressed image data */ + /* get a decoder handle */ + dinfo = opj_create_decompress(CODEC_JP2); + break; + } + case JPT_CFMT: + { + /* JPEG 2000, JPIP */ + /* get a decoder handle */ + dinfo = opj_create_decompress(CODEC_JPT); + break; + } + default: + fprintf(stderr, "skipping file..\n"); + opj_stream_destroy(cio); + continue; + } + /* catch events using our callbacks and give a local context */ + + /* setup the decoder decoding parameters using user parameters */ + opj_setup_decoder(dinfo, ¶meters); + + /* decode the stream and fill the image structure */ + /* if (*indexfilename) // If need to extract codestream information + image = opj_decode_with_info(dinfo, cio, &cstr_info); + else + */ + bResult = opj_read_header( + dinfo, + &image, + &l_tile_x0, + &l_tile_y0, + &l_tile_width, + &l_tile_height, + &l_nb_tiles_x, + &l_nb_tiles_y, + cio); + //image = opj_decode(dinfo, cio); + //bResult = bResult && (image != 00); + //bResult = bResult && opj_end_decompress(dinfo,cio); + //if + // (!image) + //{ + // fprintf(stderr, "ERROR -> j2k_to_image: failed to decode image!\n"); + // opj_destroy_codec(dinfo); + // opj_stream_destroy(cio); + // fclose(fsrc); + // return EXIT_FAILURE; + //} + /* dump image */ + if(!image) + { + fprintf(stderr, "ERROR -> j2k_to_image: failed to read header\n"); + return EXIT_FAILURE; + } + j2k_dump_image(stdout, image); + + /* dump cp */ + //j2k_dump_cp(stdout, image, dinfo->m_codec); + + /* close the byte stream */ + opj_stream_destroy(cio); + fclose(fsrc); + /* Write the index to disk */ + if (*indexfilename) { + char bSuccess; + bSuccess = write_index_file(&cstr_info, indexfilename); + if (bSuccess) { + fprintf(stderr, "Failed to output index file\n"); + ret = EXIT_FAILURE; + } + } + + /* free remaining structures */ + if (dinfo) { + opj_destroy_codec(dinfo); + } + /* free codestream information structure */ + if (*indexfilename) + opj_destroy_cstr_info(&cstr_info); + /* free image data structure */ + opj_image_destroy(image); + + } + + return ret; +} +//end main diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/codec/j2k_to_image.c b/gdcm/Utilities/gdcmopenjpeg-v2/codec/j2k_to_image.c new file mode 100644 index 0000000..2d1635e --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/codec/j2k_to_image.c @@ -0,0 +1,769 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2006-2007, Parvatha Elangovan + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#define USE_OPJ_DEPRECATED +#include "openjpeg.h" +#include "compat/getopt.h" +#include "convert.h" +#include "dirent.h" +#include "index.h" + +#ifndef WIN32 +#include +#define _stricmp strcasecmp +#define _strnicmp strncasecmp +#endif + +/* ----------------------------------------------------------------------- */ + +#define J2K_CFMT 0 +#define JP2_CFMT 1 +#define JPT_CFMT 2 + +#define PXM_DFMT 10 +#define PGX_DFMT 11 +#define BMP_DFMT 12 +#define YUV_DFMT 13 +#define TIF_DFMT 14 +#define RAW_DFMT 15 +#define TGA_DFMT 16 +#define PNG_DFMT 17 +/* ----------------------------------------------------------------------- */ + +typedef struct dircnt{ + /** Buffer for holding images read from Directory*/ + char *filename_buf; + /** Pointer to the buffer*/ + char **filename; +}dircnt_t; + + +typedef struct img_folder{ + /** The directory path of the folder containing input images*/ + char *imgdirpath; + /** Output format*/ + const char *out_format; + /** Enable option*/ + char set_imgdir; + /** Enable Cod Format for output*/ + char set_out_format; + +}img_fol_t; + +void decode_help_display() { + fprintf(stdout,"HELP\n----\n\n"); + fprintf(stdout,"- the -h option displays this help information on screen\n\n"); + +/* UniPG>> */ + fprintf(stdout,"List of parameters for the JPEG 2000 " +#ifdef USE_JPWL + "+ JPWL " +#endif /* USE_JPWL */ + "decoder:\n"); +/* < \n"); + fprintf(stdout," Currently accepts PGM, PPM, PNM, PGX, BMP, TIF, RAW and TGA formats\n"); + fprintf(stdout," -i \n"); + fprintf(stdout," REQUIRED only if an Input image directory not specified\n"); + fprintf(stdout," Currently accepts J2K-files, JP2-files and JPT-files. The file type\n"); + fprintf(stdout," is identified based on its suffix.\n"); + fprintf(stdout," -o \n"); + fprintf(stdout," REQUIRED\n"); + fprintf(stdout," Currently accepts PGM, PPM, PNM, PGX, BMP, TIF, RAW and TGA files\n"); + fprintf(stdout," Binary data is written to the file (not ascii). If a PGX\n"); + fprintf(stdout," filename is given, there will be as many output files as there are\n"); + fprintf(stdout," components: an indice starting from 0 will then be appended to the\n"); + fprintf(stdout," output filename, just before the \"pgx\" extension. If a PGM filename\n"); + fprintf(stdout," is given and there are more than one component, only the first component\n"); + fprintf(stdout," will be written to the file.\n"); + fprintf(stdout," -r \n"); + fprintf(stdout," Set the number of highest resolution levels to be discarded. The\n"); + fprintf(stdout," image resolution is effectively divided by 2 to the power of the\n"); + fprintf(stdout," number of discarded levels. The reduce factor is limited by the\n"); + fprintf(stdout," smallest total number of decomposition levels among tiles.\n"); + fprintf(stdout," -l \n"); + fprintf(stdout," Set the maximum number of quality layers to decode. If there are\n"); + fprintf(stdout," less quality layers than the specified number, all the quality layers\n"); + fprintf(stdout," are decoded.\n"); + fprintf(stdout," -x \n"); + fprintf(stdout," Create an index file *.Idx (-x index_name.Idx) \n"); + fprintf(stdout,"\n"); +/* UniPG>> */ +#ifdef USE_JPWL + fprintf(stdout," -W \n"); + fprintf(stdout," Activates the JPWL correction capability, if the codestream complies.\n"); + fprintf(stdout," Options can be a comma separated list of tokens:\n"); + fprintf(stdout," c, c=numcomps\n"); + fprintf(stdout," numcomps is the number of expected components in the codestream\n"); + fprintf(stdout," (search of first EPB rely upon this, default is %d)\n", JPWL_EXPECTED_COMPONENTS); +#endif /* USE_JPWL */ +/* <d_name)==0 || strcmp("..",content->d_name)==0 ) + continue; + num_images++; + } + return num_images; +} + +int load_images(dircnt_t *dirptr, char *imgdirpath){ + DIR *dir; + struct dirent* content; + int i = 0; + + /*Reading the input images from given input directory*/ + + dir= opendir(imgdirpath); + if(!dir){ + fprintf(stderr,"Could not open Folder %s\n",imgdirpath); + return 1; + }else { + fprintf(stderr,"Folder opened successfully\n"); + } + + while((content=readdir(dir))!=NULL){ + if(strcmp(".",content->d_name)==0 || strcmp("..",content->d_name)==0 ) + continue; + + strcpy(dirptr->filename[i],content->d_name); + i++; + } + return 0; +} + +int get_file_format(char *filename) { + unsigned int i; + static const char *extension[] = {"pgx", "pnm", "pgm", "ppm", "bmp","tif", "raw", "tga", "png", "j2k", "jp2", "jpt", "j2c", "jpc" }; + static const int format[] = { PGX_DFMT, PXM_DFMT, PXM_DFMT, PXM_DFMT, BMP_DFMT, TIF_DFMT, RAW_DFMT, TGA_DFMT, PNG_DFMT, J2K_CFMT, JP2_CFMT, JPT_CFMT, J2K_CFMT, J2K_CFMT }; + char * ext = strrchr(filename, '.'); + if (ext == NULL) + return -1; + ext++; + if(ext) { + for(i = 0; i < sizeof(format)/sizeof(*format); i++) { + if(_strnicmp(ext, extension[i], 3) == 0) { + return format[i]; + } + } + } + + return -1; +} + +char get_next_file(int imageno,dircnt_t *dirptr,img_fol_t *img_fol, opj_dparameters_t *parameters){ + char image_filename[OPJ_PATH_LEN], infilename[OPJ_PATH_LEN],outfilename[OPJ_PATH_LEN],temp_ofname[OPJ_PATH_LEN]; + char *temp_p, temp1[OPJ_PATH_LEN]=""; + + strcpy(image_filename,dirptr->filename[imageno]); + fprintf(stderr,"File Number %d \"%s\"\n",imageno,image_filename); + parameters->decod_format = get_file_format(image_filename); + if (parameters->decod_format == -1) + return 1; + sprintf(infilename,"%s/%s",img_fol->imgdirpath,image_filename); + strncpy(parameters->infile, infilename, sizeof(infilename)); + + //Set output file + strcpy(temp_ofname,strtok(image_filename,".")); + while((temp_p = strtok(NULL,".")) != NULL){ + strcat(temp_ofname,temp1); + sprintf(temp1,".%s",temp_p); + } + if(img_fol->set_out_format==1){ + sprintf(outfilename,"%s/%s.%s",img_fol->imgdirpath,temp_ofname,img_fol->out_format); + strncpy(parameters->outfile, outfilename, sizeof(outfilename)); + } + return 0; +} + +/* -------------------------------------------------------------------------- */ +int parse_cmdline_decoder(int argc, char **argv, opj_dparameters_t *parameters,img_fol_t *img_fol, char *indexfilename) { + /* parse the command line */ + int totlen; + option_t long_option[]={ + {"ImgDir",REQ_ARG, NULL ,'y'}, + {"OutFor",REQ_ARG, NULL ,'O'}, + }; + + const char optlist[] = "i:o:r:l:hx:" + +/* UniPG>> */ +#ifdef USE_JPWL + "W:" +#endif /* USE_JPWL */ +/* <set_out_format = 0; + while (1) { + int c = getopt_long(argc, argv,optlist,long_option,totlen); + if (c == -1) + break; + switch (c) { + case 'i': /* input file */ + { + char *infile = optarg; + parameters->decod_format = get_file_format(infile); + switch(parameters->decod_format) { + case J2K_CFMT: + case JP2_CFMT: + case JPT_CFMT: + break; + default: + fprintf(stderr, + "!! Unrecognized format for infile : %s [accept only *.j2k, *.jp2, *.jpc or *.jpt] !!\n\n", + infile); + return 1; + } + strncpy(parameters->infile, infile, sizeof(parameters->infile)-1); + } + break; + + /* ----------------------------------------------------- */ + + case 'o': /* output file */ + { + char *outfile = optarg; + parameters->cod_format = get_file_format(outfile); + switch(parameters->cod_format) { + case PGX_DFMT: + case PXM_DFMT: + case BMP_DFMT: + case TIF_DFMT: + case RAW_DFMT: + case TGA_DFMT: + case PNG_DFMT: + break; + default: + fprintf(stderr, "Unknown output format image %s [only *.pnm, *.pgm, *.ppm, *.pgx, *.bmp, *.tif, *.raw or *.tga]!! \n", outfile); + return 1; + } + strncpy(parameters->outfile, outfile, sizeof(parameters->outfile)-1); + } + break; + + /* ----------------------------------------------------- */ + + case 'O': /* output format */ + { + char outformat[50]; + char *of = optarg; + sprintf(outformat,".%s",of); + img_fol->set_out_format = 1; + parameters->cod_format = get_file_format(outformat); + switch(parameters->cod_format) { + case PGX_DFMT: + img_fol->out_format = "pgx"; + break; + case PXM_DFMT: + img_fol->out_format = "ppm"; + break; + case BMP_DFMT: + img_fol->out_format = "bmp"; + break; + case TIF_DFMT: + img_fol->out_format = "tif"; + break; + case RAW_DFMT: + img_fol->out_format = "raw"; + break; + case TGA_DFMT: + img_fol->out_format = "raw"; + break; + case PNG_DFMT: + img_fol->out_format = "png"; + break; + default: + fprintf(stderr, "Unknown output format image %s [only *.pnm, *.pgm, *.ppm, *.pgx, *.bmp, *.tif, *.raw or *.tga]!! \n", outformat); + return 1; + break; + } + } + break; + + /* ----------------------------------------------------- */ + + + case 'r': /* reduce option */ + { + sscanf(optarg, "%d", ¶meters->cp_reduce); + } + break; + + /* ----------------------------------------------------- */ + + + case 'l': /* layering option */ + { + sscanf(optarg, "%d", ¶meters->cp_layer); + } + break; + + /* ----------------------------------------------------- */ + + case 'h': /* display an help description */ + decode_help_display(); + return 1; + + /* ------------------------------------------------------ */ + + case 'y': /* Image Directory path */ + { + img_fol->imgdirpath = (char*)malloc(strlen(optarg) + 1); + strcpy(img_fol->imgdirpath,optarg); + img_fol->set_imgdir=1; + } + break; + /* ----------------------------------------------------- */ + case 'x': /* Creation of index file */ + { + char *index = optarg; + strncpy(indexfilename, index, OPJ_PATH_LEN); + } + break; + /* ----------------------------------------------------- */ + /* UniPG>> */ +#ifdef USE_JPWL + + case 'W': /* activate JPWL correction */ + { + char *token = NULL; + + token = strtok(optarg, ","); + while(token != NULL) { + + /* search expected number of components */ + if (*token == 'c') { + + static int compno; + + compno = JPWL_EXPECTED_COMPONENTS; /* predefined no. of components */ + + if(sscanf(token, "c=%d", &compno) == 1) { + /* Specified */ + if ((compno < 1) || (compno > 256)) { + fprintf(stderr, "ERROR -> invalid number of components c = %d\n", compno); + return 1; + } + parameters->jpwl_exp_comps = compno; + + } else if (!strcmp(token, "c")) { + /* default */ + parameters->jpwl_exp_comps = compno; /* auto for default size */ + + } else { + fprintf(stderr, "ERROR -> invalid components specified = %s\n", token); + return 1; + }; + } + + /* search maximum number of tiles */ + if (*token == 't') { + + static int tileno; + + tileno = JPWL_MAXIMUM_TILES; /* maximum no. of tiles */ + + if(sscanf(token, "t=%d", &tileno) == 1) { + /* Specified */ + if ((tileno < 1) || (tileno > JPWL_MAXIMUM_TILES)) { + fprintf(stderr, "ERROR -> invalid number of tiles t = %d\n", tileno); + return 1; + } + parameters->jpwl_max_tiles = tileno; + + } else if (!strcmp(token, "t")) { + /* default */ + parameters->jpwl_max_tiles = tileno; /* auto for default size */ + + } else { + fprintf(stderr, "ERROR -> invalid tiles specified = %s\n", token); + return 1; + }; + } + + /* next token or bust */ + token = strtok(NULL, ","); + }; + parameters->jpwl_correct = true; + fprintf(stdout, "JPWL correction capability activated\n"); + fprintf(stdout, "- expecting %d components\n", parameters->jpwl_exp_comps); + } + break; +#endif /* USE_JPWL */ +/* < this option is not valid \"-%c %s\"\n",c, optarg); + break; + } + } + + /* check for possible errors */ + if(img_fol->set_imgdir==1){ + if(!(parameters->infile[0]==0)){ + fprintf(stderr, "Error: options -ImgDir and -i cannot be used together !!\n"); + return 1; + } + if(img_fol->set_out_format == 0){ + fprintf(stderr, "Error: When -ImgDir is used, -OutFor must be used !!\n"); + fprintf(stderr, "Only one format allowed! Valid format PGM, PPM, PNM, PGX, BMP, TIF, RAW and TGA!!\n"); + return 1; + } + if(!((parameters->outfile[0] == 0))){ + fprintf(stderr, "Error: options -ImgDir and -o cannot be used together !!\n"); + return 1; + } + }else{ + if((parameters->infile[0] == 0) || (parameters->outfile[0] == 0)) { + fprintf(stderr, "Error: One of the options -i or -ImgDir must be specified\n"); + fprintf(stderr, "Error: When using -i, -o must be used\n"); + fprintf(stderr, "usage: image_to_j2k -i *.j2k/jp2/j2c -o *.pgm/ppm/pnm/pgx/bmp/tif/raw/tga(+ options)\n"); + return 1; + } + } + + return 0; +} + +/* -------------------------------------------------------------------------- */ + +/** +sample error callback expecting a FILE* client object +*/ +void error_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[ERROR] %s", msg); +} +/** +sample warning callback expecting a FILE* client object +*/ +void warning_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[WARNING] %s", msg); +} +/** +sample debug callback expecting no client object +*/ +void info_callback(const char *msg, void *client_data) { + (void)client_data; + fprintf(stdout, "[INFO] %s", msg); +} + +/* -------------------------------------------------------------------------- */ + +int main(int argc, char **argv) +{ + int ret; + opj_dparameters_t parameters; /* decompression parameters */ + img_fol_t img_fol; + opj_image_t *image = NULL; + FILE *fsrc = NULL; + bool bResult; + int num_images; + int i,imageno; + dircnt_t *dirptr; + opj_codec_t* dinfo = NULL; /* handle to a decompressor */ + opj_stream_t *cio = NULL; + opj_codestream_info_t cstr_info; /* Codestream information structure */ + char indexfilename[OPJ_PATH_LEN]; /* index file name */ + OPJ_INT32 l_tile_x0,l_tile_y0; + OPJ_UINT32 l_tile_width,l_tile_height,l_nb_tiles_x,l_nb_tiles_y; + + /* configure the event callbacks (not required) */ + + /* set decoding parameters to default values */ + opj_set_default_decoder_parameters(¶meters); + + /* Initialize indexfilename and img_fol */ + *indexfilename = 0; + memset(&img_fol,0,sizeof(img_fol_t)); + + /* parse input and get user encoding parameters */ + if(parse_cmdline_decoder(argc, argv, ¶meters,&img_fol, indexfilename) == 1) { + return EXIT_FAILURE; + } + + /* Initialize reading of directory */ + if(img_fol.set_imgdir==1){ + num_images=get_num_images(img_fol.imgdirpath); + + dirptr=(dircnt_t*)malloc(sizeof(dircnt_t)); + if(dirptr){ + dirptr->filename_buf = (char*)malloc(num_images*OPJ_PATH_LEN*sizeof(char)); // Stores at max 10 image file names + dirptr->filename = (char**) malloc(num_images*sizeof(char*)); + + if(!dirptr->filename_buf){ + return EXIT_FAILURE; + } + for(i=0;ifilename[i] = dirptr->filename_buf + i*OPJ_PATH_LEN; + } + } + if(load_images(dirptr,img_fol.imgdirpath)==1){ + return EXIT_FAILURE; + } + if (num_images==0){ + fprintf(stdout,"Folder is empty\n"); + return EXIT_FAILURE; + } + }else{ + num_images=1; + } + + /*Encoding image one by one*/ + for(imageno = 0; imageno < num_images ; imageno++) + { + image = NULL; + fprintf(stderr,"\n"); + + if(img_fol.set_imgdir==1){ + if (get_next_file(imageno, dirptr,&img_fol, ¶meters)) { + fprintf(stderr,"skipping file...\n"); + continue; + } + } + + /* read the input file and put it in memory */ + /* ---------------------------------------- */ + fsrc = fopen(parameters.infile, "rb"); + if + (!fsrc) + { + fprintf(stderr, "ERROR -> failed to open %s for reading\n", parameters.infile); + return EXIT_FAILURE; + } + cio = opj_stream_create_default_file_stream(fsrc,true); + /* decode the code-stream */ + /* ---------------------- */ + + switch + (parameters.decod_format) + { + case J2K_CFMT: + { + /* JPEG-2000 codestream */ + + /* get a decoder handle */ + dinfo = opj_create_decompress(CODEC_J2K); + break; + } + case JP2_CFMT: + { + /* JPEG 2000 compressed image data */ + /* get a decoder handle */ + dinfo = opj_create_decompress(CODEC_JP2); + break; + } + case JPT_CFMT: + { + /* JPEG 2000, JPIP */ + /* get a decoder handle */ + dinfo = opj_create_decompress(CODEC_JPT); + break; + } + default: + fprintf(stderr, "skipping file..\n"); + opj_stream_destroy(cio); + continue; + } + /* catch events using our callbacks and give a local context */ + + /* setup the decoder decoding parameters using user parameters */ + opj_setup_decoder(dinfo, ¶meters); + + /* decode the stream and fill the image structure */ + /* if (*indexfilename) // If need to extract codestream information + image = opj_decode_with_info(dinfo, cio, &cstr_info); + else + */ + bResult = opj_read_header( + dinfo, + &image, + &l_tile_x0, + &l_tile_y0, + &l_tile_width, + &l_tile_height, + &l_nb_tiles_x, + &l_nb_tiles_y, + cio); + image = opj_decode(dinfo, cio); + bResult = bResult && (image != 00); + bResult = bResult && opj_end_decompress(dinfo,cio); + if + (!image) + { + fprintf(stderr, "ERROR -> j2k_to_image: failed to decode image!\n"); + opj_destroy_codec(dinfo); + opj_stream_destroy(cio); + fclose(fsrc); + return EXIT_FAILURE; + } + + /* close the byte stream */ + opj_stream_destroy(cio); + fclose(fsrc); + /* Write the index to disk */ + if (*indexfilename) { + char bSuccess; + bSuccess = write_index_file(&cstr_info, indexfilename); + if (bSuccess) { + fprintf(stderr, "Failed to output index file\n"); + ret = EXIT_FAILURE; + } + } + + /* create output image */ + /* ------------------- */ + switch (parameters.cod_format) { + case PXM_DFMT: /* PNM PGM PPM */ + if (imagetopnm(image, parameters.outfile)) { + fprintf(stdout,"Outfile %s not generated\n",parameters.outfile); + ret = EXIT_FAILURE; + } + else { + fprintf(stdout,"Generated Outfile %s\n",parameters.outfile); + ret = EXIT_SUCCESS; + } + break; + + case PGX_DFMT: /* PGX */ + if(imagetopgx(image, parameters.outfile)){ + fprintf(stdout,"Outfile %s not generated\n",parameters.outfile); + ret = EXIT_FAILURE; + } + else { + fprintf(stdout,"Generated Outfile %s\n",parameters.outfile); + ret = EXIT_SUCCESS; + } + break; + + case BMP_DFMT: /* BMP */ + if(imagetobmp(image, parameters.outfile)){ + fprintf(stdout,"Outfile %s not generated\n",parameters.outfile); + ret = EXIT_FAILURE; + } + else { + fprintf(stdout,"Generated Outfile %s\n",parameters.outfile); + ret = EXIT_SUCCESS; + } + break; + + case TIF_DFMT: /* TIFF */ + if(imagetotif(image, parameters.outfile)){ + fprintf(stdout,"Outfile %s not generated\n",parameters.outfile); + ret = EXIT_FAILURE; + } + else { + fprintf(stdout,"Generated Outfile %s\n",parameters.outfile); + ret = EXIT_SUCCESS; + } + break; + + case RAW_DFMT: /* RAW */ + if(imagetoraw(image, parameters.outfile)){ + fprintf(stdout,"Error generating raw file. Outfile %s not generated\n",parameters.outfile); + ret = EXIT_FAILURE; + } + else { + fprintf(stdout,"Successfully generated Outfile %s\n",parameters.outfile); + ret = EXIT_SUCCESS; + } + break; + + case TGA_DFMT: /* TGA */ + if(imagetotga(image, parameters.outfile)){ + fprintf(stdout,"Error generating tga file. Outfile %s not generated\n",parameters.outfile); + ret = EXIT_FAILURE; + } + else { + fprintf(stdout,"Successfully generated Outfile %s\n",parameters.outfile); + ret = EXIT_SUCCESS; + } + break; + + case PNG_DFMT: /* PNG */ + if(imagetopng(image, parameters.outfile)){ + fprintf(stdout,"Error generating png file. Outfile %s not generated\n",parameters.outfile); + } + else { + fprintf(stdout,"Successfully generated Outfile %s\n",parameters.outfile); + } + break; + + } + + /* free remaining structures */ + if + (dinfo) + { + opj_destroy_codec(dinfo); + } + /* free codestream information structure */ + if (*indexfilename) + opj_destroy_cstr_info(&cstr_info); + /* free image data structure */ + opj_image_destroy(image); + + } + return ret; +} +//end main diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/doc/CMakeLists.txt b/gdcm/Utilities/gdcmopenjpeg-v2/doc/CMakeLists.txt new file mode 100644 index 0000000..f3dce22 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/doc/CMakeLists.txt @@ -0,0 +1,12 @@ +find_package(Doxygen REQUIRED) + +# The Doxyfile.dox is poorly defined and produce output +# in the source dir +add_custom_target(doxygen +# By default doxygen target is added to the 'all' target. Project is small +# thus running doxygen is not too time consuming + ALL + ${DOXYGEN} + ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.dox + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} +) diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/doc/Doxyfile.dox b/gdcm/Utilities/gdcmopenjpeg-v2/doc/Doxyfile.dox new file mode 100644 index 0000000..f0aa478 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/doc/Doxyfile.dox @@ -0,0 +1,234 @@ +# Doxyfile 1.4.2 + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +PROJECT_NAME = OpenJPEG +PROJECT_NUMBER = +OUTPUT_DIRECTORY = ../ +CREATE_SUBDIRS = NO +OUTPUT_LANGUAGE = English +USE_WINDOWS_ENCODING = YES +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = NO +STRIP_FROM_PATH = C:// +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = YES +MULTILINE_CPP_IS_BRIEF = NO +DETAILS_AT_TOP = YES +INHERIT_DOCS = YES +DISTRIBUTE_GROUP_DOC = NO +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 8 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = YES +OPTIMIZE_OUTPUT_JAVA = NO +SUBGROUPING = YES +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = YES +EXTRACT_PRIVATE = YES +EXTRACT_STATIC = YES +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = NO +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_BY_SCOPE_NAME = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_DIRECTORIES = NO +FILE_VERSION_FILTER = +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = NO +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = ../libopenjpeg \ + ../jpwl +FILE_PATTERNS = *.h \ + *.c +RECURSIVE = NO +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = * +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +VERBATIM_HEADERS = YES +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = NO +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = ./html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = NO +TREEVIEW_WIDTH = 250 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = NO +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = USE_JPWL \ + USE_JPSEC +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = YES +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = NO +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = png +DOT_PATH = +DOTFILE_DIRS = +MAX_DOT_GRAPH_WIDTH = 1024 +MAX_DOT_GRAPH_HEIGHT = 1024 +MAX_DOT_GRAPH_DEPTH = 1000 +DOT_TRANSPARENT = NO +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/jpwl/CMakeLists.txt b/gdcm/Utilities/gdcmopenjpeg-v2/jpwl/CMakeLists.txt new file mode 100644 index 0000000..015df01 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/jpwl/CMakeLists.txt @@ -0,0 +1,54 @@ +# Makefile for the main JPWL OpenJPEG codecs: JPWL_ j2k_to_image and JPWL_image_to_j2k + +add_definitions(-DUSE_JPWL) + +set(OPJ_SRCS +../libopenjpeg/bio.c +../libopenjpeg/cio.c +../libopenjpeg/dwt.c +../libopenjpeg/event.c +../libopenjpeg/image.c +../libopenjpeg/j2k.c +../libopenjpeg/j2k_lib.c +../libopenjpeg/jp2.c +../libopenjpeg/jpt.c +../libopenjpeg/mct.c +../libopenjpeg/mqc.c +../libopenjpeg/openjpeg.c +../libopenjpeg/pi.c +../libopenjpeg/raw.c +../libopenjpeg/t1.c +../libopenjpeg/t2.c +../libopenjpeg/tcd.c +../libopenjpeg/tgt.c +) +set(JPWL_SRCS crc.c jpwl.c jpwl_lib.c rs.c) + +add_library(openjpeg_JPWL ${JPWL_SRCS} ${OPJ_SRCS}) + +# Do the proper thing when building static...if only there was configured +# headers or def files instead +#if(NOT BUILD_SHARED_LIBS) +# add_definitions(-DOPJ_STATIC) +#endif() + +include_directories( + ${OPENJPEG_SOURCE_DIR}/libopenjpeg + ) + +find_package(TIFF REQUIRED) + +add_executable(JPWL_j2k_to_image +../codec/convert.c ../codec/j2k_to_image.c +) +target_link_libraries(JPWL_j2k_to_image openjpeg_JPWL ${TIFF_LIBRARIES}) +if(UNIX) + target_link_libraries(JPWL_j2k_to_image m) +endif() + +add_executable(JPWL_image_to_j2k +../codec/convert.c ../codec/image_to_j2k.c) +target_link_libraries(JPWL_image_to_j2k openjpeg_JPWL ${TIFF_LIBRARIES}) +if(UNIX) + target_link_libraries(JPWL_image_to_j2k m) +endif() diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/jpwl/README.txt b/gdcm/Utilities/gdcmopenjpeg-v2/jpwl/README.txt new file mode 100644 index 0000000..e289e9e --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/jpwl/README.txt @@ -0,0 +1,136 @@ +=============================================================================== + JPEG2000 Part 11 (ISO/IEC 15444-11 JPWL) Software + + + + Version 20061213 +=============================================================================== + + + + + +1. Scope +============= + +This document describes the installation and use of the JPWL module in the framework of OpenJPEG library. + +This implementation has been developed from OpenJPEG implementation of JPEG2000 standard, and for this reason it is written in C language. + +If you find some bugs or if you have problems using the encoder/decoder, please send an e-mail to jpwl@diei.unipg.it + + +2. Installing the code +========================== + +The JPWL code is integrated with the standard OpenJPEG library and codecs: it is activated by setting the macro USE_JPWL to defined in the preprocessor configuration options of your preferred C compiler. + +2.1. Compiling the source code in Windows +------------------------------------------- + +The "jpwl" directory is already populated with a couple of Visual C++ 6.0 workspaces + + * JPWL_image_to_j2k.dsw - Creates the encoder with JPWL functionalities + * JPWL_j2k_to_image.dsw - Creates the decoder with JPWL functionalities + +2.2. Compiling the source code in Unix-like systems +----------------------------------------------------- + +Under linux, enter the jpwl directory and type "make clean" and "make". + + +3. Running the JPWL software +========================= + +The options available at the command line are exactly the same of the base OpenJPEG codecs. In addition, there is a "-W" switch that activates JPWL functionalities. + +3.1. JPWL Encoder +------------------- + +-W : adoption of JPWL (Part 11) capabilities (-W params) + The parameters can be written and repeated in any order: + [h<=type>,s<=method>,a=,z=,g=,... + ...,p<=type>] + + h selects the header error protection (EPB): 'type' can be + [0=none 1,absent=predefined 16=CRC-16 32=CRC-32 37-128=RS] + if 'tile' is absent, it applies to main and tile headers + if 'tile' is present, it applies from that tile + onwards, up to the next h spec, or to the last tile + in the codestream (max. 16 specs) + + p selects the packet error protection (EEP/UEP with EPBs) + to be applied to raw data: 'type' can be + [0=none 1,absent=predefined 16=CRC-16 32=CRC-32 37-128=RS] + if 'tile:pack' is absent, it starts from tile 0, packet 0 + if 'tile:pack' is present, it applies from that tile + and that packet onwards, up to the next packet spec + or to the last packet in the last tile in the codestream + (max. 16 specs) + + s enables sensitivity data insertion (ESD): 'method' can be + [-1=NO ESD 0=RELATIVE ERROR 1=MSE 2=MSE REDUCTION 3=PSNR + 4=PSNR INCREMENT 5=MAXERR 6=TSE 7=RESERVED] + if 'tile' is absent, it applies to main header only + if 'tile' is present, it applies from that tile + onwards, up to the next s spec, or to the last tile + in the codestream (max. 16 specs) + + g determines the addressing mode: can be + [0=PACKET 1=BYTE RANGE 2=PACKET RANGE] + + a determines the size of data addressing: can be + 2/4 bytes (small/large codestreams). If not set, auto-mode + + z determines the size of sensitivity values: can be + 1/2 bytes, for the transformed pseudo-floating point value + + ex.: + h,h0=64,h3=16,h5=32,p0=78,p0:24=56,p1,p3:0=0,p3:20=32,s=0,s0=6,s3=-1,a=0,g=1,z=1 + means + predefined EPB in MH, rs(64,32) from TPH 0 to TPH 2, + CRC-16 in TPH 3 and TPH 4, CRC-32 in remaining TPHs, + UEP rs(78,32) for packets 0 to 23 of tile 0, + UEP rs(56,32) for packets 24 to the last of tile 0, + UEP rs default for packets of tile 1, + no UEP for packets 0 to 19 of tile 3, + UEP CRC-32 for packets 20 of tile 3 to last tile, + relative sensitivity ESD for MH, + TSE ESD from TPH 0 to TPH 2, byte range with automatic + size of addresses and 1 byte for each sensitivity value + + ex.: + h,s,p + means + default protection to headers (MH and TPHs) as well as + data packets, one ESD in MH + + N.B.: use the following recommendations when specifying + the JPWL parameters list + - when you use UEP, always pair the 'p' option with 'h' + +3.2. JPWL Decoder +------------------- + + -W + Activates the JPWL correction capability, if the codestream complies. + Options can be a comma separated list of tokens: + c, c=numcomps + numcomps is the number of expected components in the codestream + (search of first EPB rely upon this, default is 3) + + +4. Known bugs and limitations +=============================== + +4.1. Bugs +----------- + +* It is not possible to save a JPWL encoded codestream using the wrapped file format (i.e. JP2): only raw file format (i.e. J2K) is working + +4.2. Limitations +------------------ + +* When specifying an UEP protection, you need to activate even TPH protection for those tiles where there is a protection of the packets +* RED insertion is not currently implemented at the decoder +* JPWL at entropy coding level is not implemented diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/jpwl/crc.c b/gdcm/Utilities/gdcmopenjpeg-v2/jpwl/crc.c new file mode 100644 index 0000000..4761317 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/jpwl/crc.c @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * Copyright (c) 2005-2006, Dept. of Electronic and Information Engineering, Universita' degli Studi di Perugia, Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef USE_JPWL + +#include "crc.h" + +/** +@file crc.c +@brief Functions used to compute the 16- and 32-bit CRC of byte arrays + +*/ + +/** file: CRC16.CPP + * + * CRC - Cyclic Redundancy Check (16-bit) + * + * A CRC-checksum is used to be sure, the data hasn't changed or is false. + * To create a CRC-checksum, initialise a check-variable (unsigned short), + * and set this to zero. Than call for every byte in the file (e.g.) the + * procedure updateCRC16 with this check-variable as the first parameter, + * and the byte as the second. At the end, the check-variable contains the + * CRC-checksum. + * + * implemented by Michael Neumann, 14.06.1998 + * + */ +const unsigned short CRC16_table[256] = { + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, + 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, + 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, + 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, + 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, + 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, + 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, + 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 +}; + +void updateCRC16(unsigned short *crc, unsigned char data) { + *crc = CRC16_table[(*crc >> 8) & 0xFF] ^ (*crc << 8) ^ data; +}; + + +/** file: CRC32.CPP + * + * CRC - Cyclic Redundancy Check (32-bit) + * + * A CRC-checksum is used to be sure, the data hasn't changed or is false. + * To create a CRC-checksum, initialise a check-variable (unsigned long), + * and set this to zero. Than call for every byte in the file (e.g.) the + * procedure updateCRC32 with this check-variable as the first parameter, + * and the byte as the second. At the end, the check-variable contains the + * CRC-checksum. + * + * implemented by Michael Neumann, 14.06.1998 + * + */ +const unsigned long CRC32_table[256] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + +void updateCRC32(unsigned long *crc, unsigned char data) { + *crc = CRC32_table[(unsigned char) *crc ^ data] ^ ((*crc >> 8) & 0x00FFFFFF); +}; + +#endif /* USE_JPWL */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/jpwl/crc.h b/gdcm/Utilities/gdcmopenjpeg-v2/jpwl/crc.h new file mode 100644 index 0000000..4d51119 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/jpwl/crc.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * Copyright (c) 2005-2006, Dept. of Electronic and Information Engineering, Universita' degli Studi di Perugia, Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef USE_JPWL + +/** +@file crc.h +@brief Functions used to compute the 16- and 32-bit CRC of byte arrays + +*/ + +#ifndef __CRC16_HEADER__ +#define __CRC16_HEADER__ + +/** file: CRC16.HPP + * + * CRC - Cyclic Redundancy Check (16-bit) + * + * A CRC-checksum is used to be sure, the data hasn't changed or is false. + * To create a CRC-checksum, initialise a check-variable (unsigned short), + * and set this to zero. Than call for every byte in the file (e.g.) the + * procedure updateCRC16 with this check-variable as the first parameter, + * and the byte as the second. At the end, the check-variable contains the + * CRC-checksum. + * + * implemented by Michael Neumann, 14.06.1998 + * + */ +void updateCRC16(unsigned short *, unsigned char); + +#endif /* __CRC16_HEADER__ */ + + +#ifndef __CRC32_HEADER__ +#define __CRC32_HEADER__ + +/** file: CRC32.HPP + * + * CRC - Cyclic Redundancy Check (32-bit) + * + * A CRC-checksum is used to be sure, the data hasn't changed or is false. + * To create a CRC-checksum, initialise a check-variable (unsigned short), + * and set this to zero. Than call for every byte in the file (e.g.) the + * procedure updateCRC32 with this check-variable as the first parameter, + * and the byte as the second. At the end, the check-variable contains the + * CRC-checksum. + * + * implemented by Michael Neumann, 14.06.1998 + * + */ +void updateCRC32(unsigned long *, unsigned char); + +#endif /* __CRC32_HEADER__ */ + + +#endif /* USE_JPWL */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/jpwl/jpwl.c b/gdcm/Utilities/gdcmopenjpeg-v2/jpwl/jpwl.c new file mode 100644 index 0000000..6595dd5 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/jpwl/jpwl.c @@ -0,0 +1,1356 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * Copyright (c) 2005-2006, Dept. of Electronic and Information Engineering, Universita' degli Studi di Perugia, Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "../libopenjpeg/opj_includes.h" + +#ifdef USE_JPWL + +/** @defgroup JPWL JPWL - JPEG-2000 Part11 (JPWL) codestream manager */ +/*@{*/ + +/** @name Local static variables */ +/*@{*/ + +/** number of JPWL prepared markers */ +static int jwmarker_num; +/** properties of JPWL markers to insert */ +static jpwl_marker_t jwmarker[JPWL_MAX_NO_MARKERS]; + +/*@}*/ + +/*@}*/ + +/** @name Local static functions */ +/*@{*/ + +/** create an EPC marker segment +@param j2k J2K compressor handle +@param esd_on true if ESD is activated +@param red_on true if RED is activated +@param epb_on true if EPB is activated +@param info_on true if informative techniques are activated +@return returns the freshly created EPC +*/ +jpwl_epc_ms_t *jpwl_epc_create(opj_j2k_t *j2k, bool esd_on, bool red_on, bool epb_on, bool info_on); + +/*@}*/ + +/** create an EPC marker segment +@param j2k J2K compressor handle +@param comps considered component (-1=average, 0/1/2/...=component no.) +@param addrm addressing mode (0=packet, 1=byte range, 2=packet range, 3=reserved) +@param ad_size size of addresses (2/4 bytes) +@param senst sensitivity type +@param se_size sensitivity values size (1/2 bytes) +@param tileno tile where this ESD lies (-1 means MH) +@param svalnum number of sensitivity values (if 0, they will be automatically filled) +@param sensval pointer to an array of sensitivity values (if NULL, they will be automatically filled) +@return returns the freshly created ESD +*/ +jpwl_esd_ms_t *jpwl_esd_create(opj_j2k_t *j2k, int comps, unsigned char addrm, unsigned char ad_size, + unsigned char senst, int se_size, int tileno, + unsigned long int svalnum, void *sensval); + +/** this function is used to compare two JPWL markers based on +their relevant wishlist position +@param arg1 pointer to first marker +@param arg2 pointer to second marker +@return 1 if arg1>arg2, 0 if arg1=arg2, -1 if arg1pos_correction = 0; + +} + +void j2k_add_marker(opj_codestream_info_t *cstr_info, unsigned short int type, int pos, int len) { + + if (!cstr_info) + return; + + /* expand the list? */ + if ((cstr_info->marknum + 1) > cstr_info->maxmarknum) { + cstr_info->maxmarknum = 100 + (int) ((float) cstr_info->maxmarknum * 1.0F); + cstr_info->marker = opj_realloc(cstr_info->marker, cstr_info->maxmarknum); + } + + /* add the marker */ + cstr_info->marker[cstr_info->marknum].type = type; + cstr_info->marker[cstr_info->marknum].pos = pos; + cstr_info->marker[cstr_info->marknum].len = len; + cstr_info->marknum++; + +} + +void jpwl_prepare_marks(opj_j2k_t *j2k, opj_cio_t *cio, opj_image_t *image) { + + unsigned short int socsiz_len = 0; + int ciopos = cio_tell(cio), soc_pos = j2k->cstr_info->main_head_start; + unsigned char *socp = NULL; + + int tileno, acc_tpno, tpno, tilespec, hprot, sens, pprot, packspec, lastileno, packno; + + jpwl_epb_ms_t *epb_mark; + jpwl_epc_ms_t *epc_mark; + jpwl_esd_ms_t *esd_mark; + + /* find (SOC + SIZ) length */ + /* I assume SIZ is always the first marker after SOC */ + cio_seek(cio, soc_pos + 4); + socsiz_len = (unsigned short int) cio_read(cio, 2) + 4; /* add the 2 marks length itself */ + cio_seek(cio, soc_pos + 0); + socp = cio_getbp(cio); /* pointer to SOC */ + + /* + EPC MS for Main Header: if we are here it's required + */ + /* create the EPC */ + if ((epc_mark = jpwl_epc_create( + j2k, + j2k->cp->esd_on, /* is ESD present? */ + j2k->cp->red_on, /* is RED present? */ + j2k->cp->epb_on, /* is EPB present? */ + false /* are informative techniques present? */ + ))) { + + /* Add this marker to the 'insertanda' list */ + if (epc_mark) { + jwmarker[jwmarker_num].id = J2K_MS_EPC; /* its type */ + jwmarker[jwmarker_num].m.epcmark = epc_mark; /* the EPC */ + jwmarker[jwmarker_num].pos = soc_pos + socsiz_len; /* after SIZ */ + jwmarker[jwmarker_num].dpos = (double) jwmarker[jwmarker_num].pos + 0.1; /* not so first */ + jwmarker[jwmarker_num].len = epc_mark->Lepc; /* its length */ + jwmarker[jwmarker_num].len_ready = true; /* ready */ + jwmarker[jwmarker_num].pos_ready = true; /* ready */ + jwmarker[jwmarker_num].parms_ready = false; /* not ready */ + jwmarker[jwmarker_num].data_ready = true; /* ready */ + jwmarker_num++; + }; + + opj_event_msg(j2k->cinfo, EVT_INFO, + "MH EPC : setting %s%s%s\n", + j2k->cp->esd_on ? "ESD, " : "", + j2k->cp->red_on ? "RED, " : "", + j2k->cp->epb_on ? "EPB, " : "" + ); + + } else { + /* ooops, problems */ + opj_event_msg(j2k->cinfo, EVT_ERROR, "Could not create MH EPC\n"); + }; + + /* + ESD MS for Main Header + */ + /* first of all, must MH have an ESD MS? */ + if (j2k->cp->esd_on && (j2k->cp->sens_MH >= 0)) { + + /* Create the ESD */ + if ((esd_mark = jpwl_esd_create( + j2k, /* this encoder handle */ + -1, /* we are averaging over all components */ + (unsigned char) j2k->cp->sens_range, /* range method */ + (unsigned char) j2k->cp->sens_addr, /* sensitivity addressing */ + (unsigned char) j2k->cp->sens_MH, /* sensitivity method */ + j2k->cp->sens_size, /* sensitivity size */ + -1, /* this ESD is in main header */ + 0 /*j2k->cstr_info->num*/, /* number of packets in codestream */ + NULL /*sensval*/ /* pointer to sensitivity data of packets */ + ))) { + + /* Add this marker to the 'insertanda' list */ + if (jwmarker_num < JPWL_MAX_NO_MARKERS) { + jwmarker[jwmarker_num].id = J2K_MS_ESD; /* its type */ + jwmarker[jwmarker_num].m.esdmark = esd_mark; /* the EPB */ + jwmarker[jwmarker_num].pos = soc_pos + socsiz_len; /* we choose to place it after SIZ */ + jwmarker[jwmarker_num].dpos = (double) jwmarker[jwmarker_num].pos + 0.2; /* not first at all! */ + jwmarker[jwmarker_num].len = esd_mark->Lesd; /* its length */ + jwmarker[jwmarker_num].len_ready = true; /* not ready, yet */ + jwmarker[jwmarker_num].pos_ready = true; /* ready */ + jwmarker[jwmarker_num].parms_ready = true; /* not ready */ + jwmarker[jwmarker_num].data_ready = false; /* not ready */ + jwmarker_num++; + } + + opj_event_msg(j2k->cinfo, EVT_INFO, + "MH ESDs: method %d\n", + j2k->cp->sens_MH + ); + + } else { + /* ooops, problems */ + opj_event_msg(j2k->cinfo, EVT_ERROR, "Could not create MH ESD\n"); + }; + + } + + /* + ESD MSs for Tile Part Headers + */ + /* cycle through tiles */ + sens = -1; /* default spec: no ESD */ + tilespec = 0; /* first tile spec */ + acc_tpno = 0; + for (tileno = 0; tileno < j2k->cstr_info->tw * j2k->cstr_info->th; tileno++) { + + opj_event_msg(j2k->cinfo, EVT_INFO, + "Tile %d has %d tile part(s)\n", + tileno, j2k->cstr_info->tile[tileno].num_tps + ); + + /* for every tile part in the tile */ + for (tpno = 0; tpno < j2k->cstr_info->tile[tileno].num_tps; tpno++, acc_tpno++) { + + int sot_len, Psot, Psotp, mm; + unsigned long sot_pos, post_sod_pos; + + unsigned long int left_THmarks_len; + + /******* sot_pos = j2k->cstr_info->tile[tileno].start_pos; */ + sot_pos = j2k->cstr_info->tile[tileno].tp[tpno].tp_start_pos; + cio_seek(cio, sot_pos + 2); + sot_len = cio_read(cio, 2); /* SOT Len */ + cio_skip(cio, 2); + Psotp = cio_tell(cio); + Psot = cio_read(cio, 4); /* tile length */ + + /******* post_sod_pos = j2k->cstr_info->tile[tileno].end_header + 1; */ + post_sod_pos = j2k->cstr_info->tile[tileno].tp[tpno].tp_end_header + 1; + left_THmarks_len = post_sod_pos - sot_pos; + + /* add all the lengths of the markers which are len-ready and stay within SOT and SOD */ + for (mm = 0; mm < jwmarker_num; mm++) { + if ((jwmarker[mm].pos >= sot_pos) && (jwmarker[mm].pos < post_sod_pos)) { + if (jwmarker[mm].len_ready) + left_THmarks_len += jwmarker[mm].len + 2; + else { + opj_event_msg(j2k->cinfo, EVT_ERROR, "MS %x in %f is not len-ready: could not set up TH EPB\n", + jwmarker[mm].id, jwmarker[mm].dpos); + exit(1); + } + } + } + + /******* if ((tilespec < JPWL_MAX_NO_TILESPECS) && (j2k->cp->sens_TPH_tileno[tilespec] == tileno)) */ + if ((tilespec < JPWL_MAX_NO_TILESPECS) && (j2k->cp->sens_TPH_tileno[tilespec] == acc_tpno)) + /* we got a specification from this tile onwards */ + sens = j2k->cp->sens_TPH[tilespec++]; + + /* must this TPH have an ESD MS? */ + if (j2k->cp->esd_on && (sens >= 0)) { + + /* Create the ESD */ + if ((esd_mark = jpwl_esd_create( + j2k, /* this encoder handle */ + -1, /* we are averaging over all components */ + (unsigned char) j2k->cp->sens_range, /* range method */ + (unsigned char) j2k->cp->sens_addr, /* sensitivity addressing size */ + (unsigned char) sens, /* sensitivity method */ + j2k->cp->sens_size, /* sensitivity value size */ + tileno, /* this ESD is in a tile */ + 0, /* number of packets in codestream */ + NULL /* pointer to sensitivity data of packets */ + ))) { + + /* Add this marker to the 'insertanda' list */ + if (jwmarker_num < JPWL_MAX_NO_MARKERS) { + jwmarker[jwmarker_num].id = J2K_MS_ESD; /* its type */ + jwmarker[jwmarker_num].m.esdmark = esd_mark; /* the EPB */ + /****** jwmarker[jwmarker_num].pos = j2k->cstr_info->tile[tileno].start_pos + sot_len + 2; */ /* after SOT */ + jwmarker[jwmarker_num].pos = j2k->cstr_info->tile[tileno].tp[tpno].tp_start_pos + sot_len + 2; /* after SOT */ + jwmarker[jwmarker_num].dpos = (double) jwmarker[jwmarker_num].pos + 0.2; /* not first at all! */ + jwmarker[jwmarker_num].len = esd_mark->Lesd; /* its length */ + jwmarker[jwmarker_num].len_ready = true; /* ready, yet */ + jwmarker[jwmarker_num].pos_ready = true; /* ready */ + jwmarker[jwmarker_num].parms_ready = true; /* not ready */ + jwmarker[jwmarker_num].data_ready = false; /* ready */ + jwmarker_num++; + } + + /* update Psot of the tile */ + cio_seek(cio, Psotp); + cio_write(cio, Psot + esd_mark->Lesd + 2, 4); + + opj_event_msg(j2k->cinfo, EVT_INFO, + /******* "TPH ESDs: tile %02d, method %d\n", */ + "TPH ESDs: tile %02d, part %02d, method %d\n", + /******* tileno, */ + tileno, tpno, + sens + ); + + } else { + /* ooops, problems */ + /***** opj_event_msg(j2k->cinfo, EVT_ERROR, "Could not create TPH ESD #%d\n", tileno); */ + opj_event_msg(j2k->cinfo, EVT_ERROR, "Could not create TPH ESD #%d,%d\n", tileno, tpno); + }; + + } + + } + + }; + + /* + EPB MS for Main Header + */ + /* first of all, must MH have an EPB MS? */ + if (j2k->cp->epb_on && (j2k->cp->hprot_MH > 0)) { + + int mm; + + /* position of SOT */ + unsigned int sot_pos = j2k->cstr_info->main_head_end + 1; + + /* how much space is there between end of SIZ and beginning of SOT? */ + int left_MHmarks_len = sot_pos - socsiz_len; + + /* add all the lengths of the markers which are len-ready and stay within SOC and SOT */ + for (mm = 0; mm < jwmarker_num; mm++) { + if ((jwmarker[mm].pos >=0) && (jwmarker[mm].pos < sot_pos)) { + if (jwmarker[mm].len_ready) + left_MHmarks_len += jwmarker[mm].len + 2; + else { + opj_event_msg(j2k->cinfo, EVT_ERROR, "MS %x in %f is not len-ready: could not set up MH EPB\n", + jwmarker[mm].id, jwmarker[mm].dpos); + exit(1); + } + } + } + + /* Create the EPB */ + if ((epb_mark = jpwl_epb_create( + j2k, /* this encoder handle */ + true, /* is it the latest? */ + true, /* is it packed? not for now */ + -1, /* we are in main header */ + 0, /* its index is 0 (first) */ + j2k->cp->hprot_MH, /* protection type parameters of data */ + socsiz_len, /* pre-data: only SOC+SIZ */ + left_MHmarks_len /* post-data: from SOC to SOT, and all JPWL markers within */ + ))) { + + /* Add this marker to the 'insertanda' list */ + if (jwmarker_num < JPWL_MAX_NO_MARKERS) { + jwmarker[jwmarker_num].id = J2K_MS_EPB; /* its type */ + jwmarker[jwmarker_num].m.epbmark = epb_mark; /* the EPB */ + jwmarker[jwmarker_num].pos = soc_pos + socsiz_len; /* after SIZ */ + jwmarker[jwmarker_num].dpos = (double) jwmarker[jwmarker_num].pos; /* first first first! */ + jwmarker[jwmarker_num].len = epb_mark->Lepb; /* its length */ + jwmarker[jwmarker_num].len_ready = true; /* ready */ + jwmarker[jwmarker_num].pos_ready = true; /* ready */ + jwmarker[jwmarker_num].parms_ready = true; /* ready */ + jwmarker[jwmarker_num].data_ready = false; /* not ready */ + jwmarker_num++; + } + + opj_event_msg(j2k->cinfo, EVT_INFO, + "MH EPB : prot. %d\n", + j2k->cp->hprot_MH + ); + + } else { + /* ooops, problems */ + opj_event_msg(j2k->cinfo, EVT_ERROR, "Could not create MH EPB\n"); + }; + } + + /* + EPB MSs for Tile Parts + */ + /* cycle through TPHs */ + hprot = j2k->cp->hprot_MH; /* default spec */ + tilespec = 0; /* first tile spec */ + lastileno = 0; + packspec = 0; + pprot = -1; + acc_tpno = 0; + for (tileno = 0; tileno < j2k->cstr_info->tw * j2k->cstr_info->th; tileno++) { + + opj_event_msg(j2k->cinfo, EVT_INFO, + "Tile %d has %d tile part(s)\n", + tileno, j2k->cstr_info->tile[tileno].num_tps + ); + + /* for every tile part in the tile */ + for (tpno = 0; tpno < j2k->cstr_info->tile[tileno].num_tps; tpno++, acc_tpno++) { + + int sot_len, Psot, Psotp, mm, epb_index = 0, prot_len = 0; + unsigned long sot_pos, post_sod_pos; + unsigned long int left_THmarks_len/*, epbs_len = 0*/; + int startpack = 0, stoppack = j2k->cstr_info->packno; + int first_tp_pack, last_tp_pack; + jpwl_epb_ms_t *tph_epb = NULL; + + /****** sot_pos = j2k->cstr_info->tile[tileno].start_pos; */ + sot_pos = j2k->cstr_info->tile[tileno].tp[tpno].tp_start_pos; + cio_seek(cio, sot_pos + 2); + sot_len = cio_read(cio, 2); /* SOT Len */ + cio_skip(cio, 2); + Psotp = cio_tell(cio); + Psot = cio_read(cio, 4); /* tile length */ + + /* a-priori length of the data dwelling between SOT and SOD */ + /****** post_sod_pos = j2k->cstr_info->tile[tileno].end_header + 1; */ + post_sod_pos = j2k->cstr_info->tile[tileno].tp[tpno].tp_end_header + 1; + left_THmarks_len = post_sod_pos - (sot_pos + sot_len + 2); + + /* add all the lengths of the JPWL markers which are len-ready and stay within SOT and SOD */ + for (mm = 0; mm < jwmarker_num; mm++) { + if ((jwmarker[mm].pos >= sot_pos) && (jwmarker[mm].pos < post_sod_pos)) { + if (jwmarker[mm].len_ready) + left_THmarks_len += jwmarker[mm].len + 2; + else { + opj_event_msg(j2k->cinfo, EVT_ERROR, "MS %x in %f is not len-ready: could not set up TH EPB\n", + jwmarker[mm].id, jwmarker[mm].dpos); + exit(1); + } + } + } + + /****** if ((tilespec < JPWL_MAX_NO_TILESPECS) && (j2k->cp->hprot_TPH_tileno[tilespec] == tileno)) */ + if ((tilespec < JPWL_MAX_NO_TILESPECS) && (j2k->cp->hprot_TPH_tileno[tilespec] == acc_tpno)) + /* we got a specification from this tile part onwards */ + hprot = j2k->cp->hprot_TPH[tilespec++]; + + /* must this TPH have an EPB MS? */ + if (j2k->cp->epb_on && (hprot > 0)) { + + /* Create the EPB */ + if ((epb_mark = jpwl_epb_create( + j2k, /* this encoder handle */ + false, /* is it the latest? in TPH, no for now (if huge data size in TPH, we'd need more) */ + true, /* is it packed? yes for now */ + tileno, /* we are in TPH */ + epb_index++, /* its index is 0 (first) */ + hprot, /* protection type parameters of following data */ + sot_len + 2, /* pre-data length: only SOT */ + left_THmarks_len /* post-data length: from SOT end to SOD inclusive */ + ))) { + + /* Add this marker to the 'insertanda' list */ + if (jwmarker_num < JPWL_MAX_NO_MARKERS) { + jwmarker[jwmarker_num].id = J2K_MS_EPB; /* its type */ + jwmarker[jwmarker_num].m.epbmark = epb_mark; /* the EPB */ + /****** jwmarker[jwmarker_num].pos = j2k->cstr_info->tile[tileno].start_pos + sot_len + 2; */ /* after SOT */ + jwmarker[jwmarker_num].pos = j2k->cstr_info->tile[tileno].tp[tpno].tp_start_pos + sot_len + 2; /* after SOT */ + jwmarker[jwmarker_num].dpos = (double) jwmarker[jwmarker_num].pos; /* first first first! */ + jwmarker[jwmarker_num].len = epb_mark->Lepb; /* its length */ + jwmarker[jwmarker_num].len_ready = true; /* ready */ + jwmarker[jwmarker_num].pos_ready = true; /* ready */ + jwmarker[jwmarker_num].parms_ready = true; /* ready */ + jwmarker[jwmarker_num].data_ready = false; /* not ready */ + jwmarker_num++; + } + + /* update Psot of the tile */ + Psot += epb_mark->Lepb + 2; + + opj_event_msg(j2k->cinfo, EVT_INFO, + /***** "TPH EPB : tile %02d, prot. %d\n", */ + "TPH EPB : tile %02d, part %02d, prot. %d\n", + /***** tileno, */ + tileno, tpno, + hprot + ); + + /* save this TPH EPB address */ + tph_epb = epb_mark; + + } else { + /* ooops, problems */ + /****** opj_event_msg(j2k->cinfo, EVT_ERROR, "Could not create TPH EPB #%d\n", tileno); */ + opj_event_msg(j2k->cinfo, EVT_ERROR, "Could not create TPH EPB in #%d,d\n", tileno, tpno); + }; + + } + + startpack = 0; + /* EPB MSs for UEP packet data protection in Tile Parts */ + /****** for (packno = 0; packno < j2k->cstr_info->num; packno++) { */ + /*first_tp_pack = (tpno > 0) ? (first_tp_pack + j2k->cstr_info->tile[tileno].tp[tpno - 1].tp_numpacks) : 0;*/ + first_tp_pack = j2k->cstr_info->tile[tileno].tp[tpno].tp_start_pack; + last_tp_pack = first_tp_pack + j2k->cstr_info->tile[tileno].tp[tpno].tp_numpacks - 1; + for (packno = 0; packno < j2k->cstr_info->tile[tileno].tp[tpno].tp_numpacks; packno++) { + + /******** if ((packspec < JPWL_MAX_NO_PACKSPECS) && + (j2k->cp->pprot_tileno[packspec] == tileno) && (j2k->cp->pprot_packno[packspec] == packno)) { */ + if ((packspec < JPWL_MAX_NO_PACKSPECS) && + (j2k->cp->pprot_tileno[packspec] == acc_tpno) && (j2k->cp->pprot_packno[packspec] == packno)) { + + /* we got a specification from this tile and packet onwards */ + /* print the previous spec */ + if (packno > 0) { + stoppack = packno - 1; + opj_event_msg(j2k->cinfo, EVT_INFO, + /***** "UEP EPBs: tile %02d, packs. %02d-%02d (B %d-%d), prot. %d\n", */ + "UEP EPBs: tile %02d, part %02d, packs. %02d-%02d (B %d-%d), prot. %d\n", + /***** tileno, */ + tileno, tpno, + startpack, + stoppack, + /***** j2k->cstr_info->tile[tileno].packet[startpack].start_pos, */ + j2k->cstr_info->tile[tileno].packet[first_tp_pack + startpack].start_pos, + /***** j2k->cstr_info->tile[tileno].packet[stoppack].end_pos, */ + j2k->cstr_info->tile[tileno].packet[first_tp_pack + stoppack].end_pos, + pprot); + + /***** prot_len = j2k->cstr_info->tile[tileno].packet[stoppack].end_pos + 1 - + j2k->cstr_info->tile[tileno].packet[startpack].start_pos; */ + prot_len = j2k->cstr_info->tile[tileno].packet[first_tp_pack + stoppack].end_pos + 1 - + j2k->cstr_info->tile[tileno].packet[first_tp_pack + startpack].start_pos; + + /* + particular case: if this is the last header and the last packet, + then it is better to protect even the EOC marker + */ + /****** if ((tileno == ((j2k->cstr_info->tw * j2k->cstr_info->th) - 1)) && + (stoppack == (j2k->cstr_info->num - 1))) */ + if ((tileno == ((j2k->cstr_info->tw * j2k->cstr_info->th) - 1)) && + (tpno == (j2k->cstr_info->tile[tileno].num_tps - 1)) && + (stoppack == last_tp_pack)) + /* add the EOC len */ + prot_len += 2; + + /* let's add the EPBs */ + Psot += jpwl_epbs_add( + j2k, /* J2K handle */ + jwmarker, /* pointer to JPWL markers list */ + &jwmarker_num, /* pointer to the number of current markers */ + false, /* latest */ + true, /* packed */ + false, /* inside MH */ + &epb_index, /* pointer to EPB index */ + pprot, /* protection type */ + /****** (double) (j2k->cstr_info->tile[tileno].start_pos + sot_len + 2) + 0.0001, */ /* position */ + (double) (j2k->cstr_info->tile[tileno].tp[tpno].tp_start_pos + sot_len + 2) + 0.0001, /* position */ + tileno, /* number of tile */ + 0, /* length of pre-data */ + prot_len /*4000*/ /* length of post-data */ + ); + } + + startpack = packno; + pprot = j2k->cp->pprot[packspec++]; + } + + //printf("Tile %02d, pack %02d ==> %d\n", tileno, packno, pprot); + + } + + /* we are at the end: print the remaining spec */ + stoppack = packno - 1; + if (pprot >= 0) { + + opj_event_msg(j2k->cinfo, EVT_INFO, + /**** "UEP EPBs: tile %02d, packs. %02d-%02d (B %d-%d), prot. %d\n", */ + "UEP EPBs: tile %02d, part %02d, packs. %02d-%02d (B %d-%d), prot. %d\n", + /**** tileno, */ + tileno, tpno, + startpack, + stoppack, + /***** j2k->image_info->tile[tileno].packet[startpack].start_pos, + j2k->image_info->tile[tileno].packet[stoppack].end_pos, */ + j2k->cstr_info->tile[tileno].packet[first_tp_pack + startpack].start_pos, + j2k->cstr_info->tile[tileno].packet[first_tp_pack + stoppack].end_pos, + pprot); + + /***** prot_len = j2k->cstr_info->tile[tileno].packet[stoppack].end_pos + 1 - + j2k->cstr_info->tile[tileno].packet[startpack].start_pos; */ + prot_len = j2k->cstr_info->tile[tileno].packet[first_tp_pack + stoppack].end_pos + 1 - + j2k->cstr_info->tile[tileno].packet[first_tp_pack + startpack].start_pos; + + /* + particular case: if this is the last header and the last packet, + then it is better to protect even the EOC marker + */ + /***** if ((tileno == ((j2k->cstr_info->tw * j2k->cstr_info->th) - 1)) && + (stoppack == (j2k->cstr_info->num - 1))) */ + if ((tileno == ((j2k->cstr_info->tw * j2k->cstr_info->th) - 1)) && + (tpno == (j2k->cstr_info->tile[tileno].num_tps - 1)) && + (stoppack == last_tp_pack)) + /* add the EOC len */ + prot_len += 2; + + /* let's add the EPBs */ + Psot += jpwl_epbs_add( + j2k, /* J2K handle */ + jwmarker, /* pointer to JPWL markers list */ + &jwmarker_num, /* pointer to the number of current markers */ + true, /* latest */ + true, /* packed */ + false, /* inside MH */ + &epb_index, /* pointer to EPB index */ + pprot, /* protection type */ + /***** (double) (j2k->cstr_info->tile[tileno].start_pos + sot_len + 2) + 0.0001,*/ /* position */ + (double) (j2k->cstr_info->tile[tileno].tp[tpno].tp_start_pos + sot_len + 2) + 0.0001, /* position */ + tileno, /* number of tile */ + 0, /* length of pre-data */ + prot_len /*4000*/ /* length of post-data */ + ); + } + + /* we can now check if the TPH EPB was really the last one */ + if (tph_epb && (epb_index == 1)) { + /* set the TPH EPB to be the last one in current header */ + tph_epb->Depb |= (unsigned char) ((true & 0x0001) << 6); + tph_epb = NULL; + } + + /* write back Psot */ + cio_seek(cio, Psotp); + cio_write(cio, Psot, 4); + + } + + }; + + /* reset the position */ + cio_seek(cio, ciopos); + +} + +void jpwl_dump_marks(opj_j2k_t *j2k, opj_cio_t *cio, opj_image_t *image) { + + int mm; + unsigned long int old_size = j2k->cstr_info->codestream_size; + unsigned long int new_size = old_size; + int /*ciopos = cio_tell(cio),*/ soc_pos = j2k->cstr_info->main_head_start; + unsigned char *jpwl_buf, *orig_buf; + unsigned long int orig_pos; + double epbcoding_time = 0.0, esdcoding_time = 0.0; + + /* Order JPWL markers according to their wishlist position */ + qsort((void *) jwmarker, (size_t) jwmarker_num, sizeof (jpwl_marker_t), jpwl_markcomp); + + /* compute markers total size */ + for (mm = 0; mm < jwmarker_num; mm++) { + /*printf("%x, %d, %.10f, %d long\n", jwmarker[mm].id, jwmarker[mm].pos, + jwmarker[mm].dpos, jwmarker[mm].len);*/ + new_size += jwmarker[mm].len + 2; + } + + /* allocate a new buffer of proper size */ + if (!(jpwl_buf = (unsigned char *) opj_malloc((size_t) (new_size + soc_pos) * sizeof(unsigned char)))) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "Could not allocate room for JPWL codestream buffer\n"); + exit(1); + }; + + /* copy the jp2 part, if any */ + orig_buf = jpwl_buf; + memcpy(jpwl_buf, cio->buffer, soc_pos); + jpwl_buf += soc_pos; + + /* cycle through markers */ + orig_pos = soc_pos + 0; /* start from the beginning */ + cio_seek(cio, soc_pos + 0); /* rewind the original */ + for (mm = 0; mm < jwmarker_num; mm++) { + + /* + need to copy a piece of the original codestream + if there is such + */ + memcpy(jpwl_buf, cio_getbp(cio), jwmarker[mm].pos - orig_pos); + jpwl_buf += jwmarker[mm].pos - orig_pos; + orig_pos = jwmarker[mm].pos; + cio_seek(cio, orig_pos); + + /* + then write down the marker + */ + switch (jwmarker[mm].id) { + + case J2K_MS_EPB: + jpwl_epb_write(j2k, jwmarker[mm].m.epbmark, jpwl_buf); + break; + + case J2K_MS_EPC: + jpwl_epc_write(j2k, jwmarker[mm].m.epcmark, jpwl_buf); + break; + + case J2K_MS_ESD: + jpwl_esd_write(j2k, jwmarker[mm].m.esdmark, jpwl_buf); + break; + + case J2K_MS_RED: + memset(jpwl_buf, 0, jwmarker[mm].len + 2); /* placeholder */ + break; + + default: + break; + }; + + /* we update the markers struct */ + if (j2k->cstr_info) + j2k->cstr_info->marker[j2k->cstr_info->marknum - 1].pos = (jpwl_buf - orig_buf); + + /* we set the marker dpos to the new position in the JPWL codestream */ + jwmarker[mm].dpos = (double) (jpwl_buf - orig_buf); + + /* advance JPWL buffer position */ + jpwl_buf += jwmarker[mm].len + 2; + + } + + /* finish remaining original codestream */ + memcpy(jpwl_buf, cio_getbp(cio), old_size - (orig_pos - soc_pos)); + jpwl_buf += old_size - (orig_pos - soc_pos); + cio_seek(cio, soc_pos + old_size); + + /* + update info file based on added markers + */ + if (!jpwl_update_info(j2k, jwmarker, jwmarker_num)) + opj_event_msg(j2k->cinfo, EVT_ERROR, "Could not update OPJ cstr_info structure\n"); + + /* now we need to repass some markers and fill their data fields */ + + /* first of all, DL and Pcrc in EPCs */ + for (mm = 0; mm < jwmarker_num; mm++) { + + /* find the EPCs */ + if (jwmarker[mm].id == J2K_MS_EPC) { + + int epc_pos = (int) jwmarker[mm].dpos, pp; + unsigned short int mycrc = 0x0000; + + /* fix and fill the DL field */ + jwmarker[mm].m.epcmark->DL = new_size; + orig_buf[epc_pos + 6] = (unsigned char) (jwmarker[mm].m.epcmark->DL >> 24); + orig_buf[epc_pos + 7] = (unsigned char) (jwmarker[mm].m.epcmark->DL >> 16); + orig_buf[epc_pos + 8] = (unsigned char) (jwmarker[mm].m.epcmark->DL >> 8); + orig_buf[epc_pos + 9] = (unsigned char) (jwmarker[mm].m.epcmark->DL >> 0); + + /* compute the CRC field (excluding itself) */ + for (pp = 0; pp < 4; pp++) + jpwl_updateCRC16(&mycrc, orig_buf[epc_pos + pp]); + for (pp = 6; pp < (jwmarker[mm].len + 2); pp++) + jpwl_updateCRC16(&mycrc, orig_buf[epc_pos + pp]); + + /* fix and fill the CRC */ + jwmarker[mm].m.epcmark->Pcrc = mycrc; + orig_buf[epc_pos + 4] = (unsigned char) (jwmarker[mm].m.epcmark->Pcrc >> 8); + orig_buf[epc_pos + 5] = (unsigned char) (jwmarker[mm].m.epcmark->Pcrc >> 0); + + } + } + + /* then, sensitivity data in ESDs */ + esdcoding_time = opj_clock(); + for (mm = 0; mm < jwmarker_num; mm++) { + + /* find the ESDs */ + if (jwmarker[mm].id == J2K_MS_ESD) { + + /* remember that they are now in a new position (dpos) */ + int esd_pos = (int) jwmarker[mm].dpos; + + jpwl_esd_fill(j2k, jwmarker[mm].m.esdmark, &orig_buf[esd_pos]); + + } + + } + esdcoding_time = opj_clock() - esdcoding_time; + if (j2k->cp->esd_on) + opj_event_msg(j2k->cinfo, EVT_INFO, "ESDs sensitivities computed in %f s\n", esdcoding_time); + + /* finally, RS or CRC parity in EPBs */ + epbcoding_time = opj_clock(); + for (mm = 0; mm < jwmarker_num; mm++) { + + /* find the EPBs */ + if (jwmarker[mm].id == J2K_MS_EPB) { + + /* remember that they are now in a new position (dpos) */ + int nn, accum_len; + + /* let's see how many EPBs are following this one, included itself */ + /* for this to work, we suppose that the markers are correctly ordered */ + /* and, overall, that they are in packed mode inside headers */ + accum_len = 0; + for (nn = mm; (nn < jwmarker_num) && (jwmarker[nn].id == J2K_MS_EPB) && + (jwmarker[nn].pos == jwmarker[mm].pos); nn++) + accum_len += jwmarker[nn].m.epbmark->Lepb + 2; + + /* fill the current (first) EPB with post-data starting from the computed position */ + jpwl_epb_fill(j2k, jwmarker[mm].m.epbmark, &orig_buf[(int) jwmarker[mm].dpos], + &orig_buf[(int) jwmarker[mm].dpos + accum_len]); + + /* fill the remaining EPBs in the header with post-data starting from the last position */ + for (nn = mm + 1; (nn < jwmarker_num) && (jwmarker[nn].id == J2K_MS_EPB) && + (jwmarker[nn].pos == jwmarker[mm].pos); nn++) + jpwl_epb_fill(j2k, jwmarker[nn].m.epbmark, &orig_buf[(int) jwmarker[nn].dpos], NULL); + + /* skip all the processed EPBs */ + mm = nn - 1; + } + + } + epbcoding_time = opj_clock() - epbcoding_time; + if (j2k->cp->epb_on) + opj_event_msg(j2k->cinfo, EVT_INFO, "EPBs redundancy computed in %f s\n", epbcoding_time); + + /* free original cio buffer and set it to the JPWL one */ + opj_free(cio->buffer); + cio->cinfo = cio->cinfo; /* no change */ + cio->openmode = cio->openmode; /* no change */ + cio->buffer = orig_buf; + cio->length = new_size + soc_pos; + cio->start = cio->buffer; + cio->end = cio->buffer + cio->length; + cio->bp = cio->buffer; + cio_seek(cio, soc_pos + new_size); + +} + + +void j2k_read_epc(opj_j2k_t *j2k) { + unsigned long int DL, Lepcp, Pcrcp, l; + unsigned short int Lepc, Pcrc = 0x0000; + unsigned char Pepc; + opj_cio_t *cio = j2k->cio; + char *ans1; + + /* Simply read the EPC parameters */ + Lepcp = cio_tell(cio); + Lepc = cio_read(cio, 2); + Pcrcp = cio_tell(cio); + cio_skip(cio, 2); /* Pcrc */ + DL = cio_read(cio, 4); + Pepc = cio_read(cio, 1); + + /* compute Pcrc */ + cio_seek(cio, Lepcp - 2); + + /* Marker */ + jpwl_updateCRC16(&Pcrc, (unsigned char) cio_read(cio, 1)); + jpwl_updateCRC16(&Pcrc, (unsigned char) cio_read(cio, 1)); + + /* Length */ + jpwl_updateCRC16(&Pcrc, (unsigned char) cio_read(cio, 1)); + jpwl_updateCRC16(&Pcrc, (unsigned char) cio_read(cio, 1)); + + /* skip Pcrc */ + cio_skip(cio, 2); + + /* read all remaining */ + for (l = 4; l < Lepc; l++) + jpwl_updateCRC16(&Pcrc, (unsigned char) cio_read(cio, 1)); + + /* check Pcrc with the result */ + cio_seek(cio, Pcrcp); + ans1 = (Pcrc == (unsigned short int) cio_read(cio, 2)) ? "crc-ok" : "crc-ko"; + + /* now we write them to screen */ + opj_event_msg(j2k->cinfo, EVT_INFO, + "EPC(%u,%d): %s, DL=%d%s %s %s\n", + Lepcp - 2, + Lepc, + ans1, + DL, /* data length this EPC is referring to */ + (Pepc & 0x10) ? ", esd" : "", /* ESD is present */ + (Pepc & 0x20) ? ", red" : "", /* RED is present */ + (Pepc & 0x40) ? ", epb" : ""); /* EPB is present */ + + cio_seek(cio, Lepcp + Lepc); +} + +void j2k_write_epc(opj_j2k_t *j2k) { + + unsigned long int DL, Lepcp, Pcrcp, l; + unsigned short int Lepc, Pcrc; + unsigned char Pepc; + + opj_cio_t *cio = j2k->cio; + + cio_write(cio, J2K_MS_EPC, 2); /* EPC */ + Lepcp = cio_tell(cio); + cio_skip(cio, 2); + + /* CRC-16 word of the EPC */ + Pcrc = 0x0000; /* initialize */ + Pcrcp = cio_tell(cio); + cio_write(cio, Pcrc, 2); /* Pcrc placeholder*/ + + /* data length of the EPC protection domain */ + DL = 0x00000000; /* we leave this set to 0, as if the information is not available */ + cio_write(cio, DL, 4); /* DL */ + + /* jpwl capabilities */ + Pepc = 0x00; + cio_write(cio, Pepc, 1); /* Pepc */ + + /* ID section */ + /* no ID's, as of now */ + + Lepc = (unsigned short) (cio_tell(cio) - Lepcp); + cio_seek(cio, Lepcp); + cio_write(cio, Lepc, 2); /* Lepc */ + + /* compute Pcrc */ + cio_seek(cio, Lepcp - 2); + + /* Marker */ + jpwl_updateCRC16(&Pcrc, (unsigned char) cio_read(cio, 1)); + jpwl_updateCRC16(&Pcrc, (unsigned char) cio_read(cio, 1)); + + /* Length */ + jpwl_updateCRC16(&Pcrc, (unsigned char) cio_read(cio, 1)); + jpwl_updateCRC16(&Pcrc, (unsigned char) cio_read(cio, 1)); + + /* skip Pcrc */ + cio_skip(cio, 2); + + /* read all remaining */ + for (l = 4; l < Lepc; l++) + jpwl_updateCRC16(&Pcrc, (unsigned char) cio_read(cio, 1)); + + /* fill Pcrc with the result */ + cio_seek(cio, Pcrcp); + cio_write(cio, Pcrc, 2); + + cio_seek(cio, Lepcp + Lepc); + + /* marker struct update */ + j2k_add_marker(j2k->cstr_info, J2K_MS_EPC, Lepcp - 2, Lepc + 2); + +} + +void j2k_read_epb(opj_j2k_t *j2k) { + unsigned long int LDPepb, Pepb; + unsigned short int Lepb; + unsigned char Depb; + char str1[25] = ""; + bool status; + static bool first_in_tph = true; + int type, pre_len, post_len; + static unsigned char *redund = NULL; + + opj_cio_t *cio = j2k->cio; + + /* B/W = 45, RGB = 51 */ + /* SIZ SIZ_FIELDS SIZ_COMPS FOLLOWING_MARKER */ + int skipnum = 2 + 38 + 3 * j2k->cp->exp_comps + 2; + + if (j2k->cp->correct) { + + /* go back to EPB marker value */ + cio_seek(cio, cio_tell(cio) - 2); + + /* we need to understand where we are */ + if (j2k->state == J2K_STATE_MH) { + /* we are in MH */ + type = 0; /* MH */ + pre_len = skipnum; /* SOC+SIZ */ + post_len = -1; /* auto */ + + } else if ((j2k->state == J2K_STATE_TPH) && first_in_tph) { + /* we are in TPH */ + type = 1; /* TPH */ + pre_len = 12; /* SOC+SIZ */ + first_in_tph = false; + post_len = -1; /* auto */ + + } else { + /* we are elsewhere */ + type = 2; /* other */ + pre_len = 0; /* nada */ + post_len = -1; /* auto */ + + } + + /* call EPB corrector */ + /*printf("before %x, ", redund);*/ + status = jpwl_epb_correct(j2k, /* J2K decompressor handle */ + cio->bp, /* pointer to EPB in codestream buffer */ + type, /* EPB type: MH */ + pre_len, /* length of pre-data */ + post_len, /* length of post-data: -1 means auto */ + NULL, /* do everything auto */ + &redund + ); + /*printf("after %x\n", redund);*/ + + /* Read the (possibly corrected) EPB parameters */ + cio_skip(cio, 2); + Lepb = cio_read(cio, 2); + Depb = cio_read(cio, 1); + LDPepb = cio_read(cio, 4); + Pepb = cio_read(cio, 4); + + if (!status) { + + opj_event_msg(j2k->cinfo, EVT_ERROR, "JPWL correction could not be performed\n"); + + /* advance to EPB endpoint */ + cio_skip(cio, Lepb + 2); + + return; + } + + /* last in current header? */ + if (Depb & 0x40) { + redund = NULL; /* reset the pointer to L4 buffer */ + first_in_tph = true; + } + + /* advance to EPB endpoint */ + cio_skip(cio, Lepb - 11); + + } else { + + /* Simply read the EPB parameters */ + Lepb = cio_read(cio, 2); + Depb = cio_read(cio, 1); + LDPepb = cio_read(cio, 4); + Pepb = cio_read(cio, 4); + + /* What does Pepb tells us about the protection method? */ + if (((Pepb & 0xF0000000) >> 28) == 0) + sprintf(str1, "pred"); /* predefined */ + else if (((Pepb & 0xF0000000) >> 28) == 1) + sprintf(str1, "crc-%lu", 16 * ((Pepb & 0x00000001) + 1)); /* CRC mode */ + else if (((Pepb & 0xF0000000) >> 28) == 2) + sprintf(str1, "rs(%lu,32)", (Pepb & 0x0000FF00) >> 8); /* RS mode */ + else if (Pepb == 0xFFFFFFFF) + sprintf(str1, "nometh"); /* RS mode */ + else + sprintf(str1, "unknown"); /* unknown */ + + /* Now we write them to screen */ + opj_event_msg(j2k->cinfo, EVT_INFO, + "EPB(%d): (%sl, %sp, %u), %lu, %s\n", + cio_tell(cio) - 13, + (Depb & 0x40) ? "" : "n", /* latest EPB or not? */ + (Depb & 0x80) ? "" : "n", /* packed or unpacked EPB? */ + (Depb & 0x3F), /* EPB index value */ + LDPepb, /*length of the data protected by the EPB */ + str1); /* protection method */ + + cio_skip(cio, Lepb - 11); + } +} + +void j2k_write_epb(opj_j2k_t *j2k) { + unsigned long int LDPepb, Pepb, Lepbp; + unsigned short int Lepb; + unsigned char Depb; + + opj_cio_t *cio = j2k->cio; + + cio_write(cio, J2K_MS_EPB, 2); /* EPB */ + Lepbp = cio_tell(cio); + cio_skip(cio, 2); + + /* EPB style */ + Depb = 0x00; /* test */ + cio_write(cio, Depb, 1); /* Depb */ + + /* length of the data to be protected by this EPB */ + LDPepb = 0x00000000; /* test */ + cio_write(cio, LDPepb, 4); /* LDPepb */ + + /* next error correction tool */ + Pepb = 0x00000000; /* test */ + cio_write(cio, Pepb, 4); /* Pepb */ + + /* EPB data */ + /* no data, as of now */ + + Lepb = (unsigned short) (cio_tell(cio) - Lepbp); + cio_seek(cio, Lepbp); + cio_write(cio, Lepb, 2); /* Lepb */ + + cio_seek(cio, Lepbp + Lepb); + + /* marker struct update */ + j2k_add_marker(j2k->cstr_info, J2K_MS_EPB, Lepbp - 2, Lepb + 2); +} + +void j2k_read_esd(opj_j2k_t *j2k) { + unsigned short int Lesd, Cesd; + unsigned char Pesd; + + int cesdsize = (j2k->image->numcomps >= 257) ? 2 : 1; + + char str1[4][4] = {"p", "br", "pr", "res"}; + char str2[8][8] = {"res", "mse", "mse-r", "psnr", "psnr-i", "maxerr", "tse", "res"}; + + opj_cio_t *cio = j2k->cio; + + /* Simply read the ESD parameters */ + Lesd = cio_read(cio, 2); + Cesd = cio_read(cio, cesdsize); + Pesd = cio_read(cio, 1); + + /* Now we write them to screen */ + opj_event_msg(j2k->cinfo, EVT_INFO, + "ESD(%d): c%d, %s, %s, %s, %s, %s\n", + cio_tell(cio) - (5 + cesdsize), + Cesd, /* component number for this ESD */ + str1[(Pesd & (unsigned char) 0xC0) >> 6], /* addressing mode */ + str2[(Pesd & (unsigned char) 0x38) >> 3], /* sensitivity type */ + ((Pesd & (unsigned char) 0x04) >> 2) ? "2Bs" : "1Bs", + ((Pesd & (unsigned char) 0x02) >> 1) ? "4Ba" : "2Ba", + (Pesd & (unsigned char) 0x01) ? "avgc" : ""); + + cio_skip(cio, Lesd - (3 + cesdsize)); +} + +void j2k_read_red(opj_j2k_t *j2k) { + unsigned short int Lred; + unsigned char Pred; + char str1[4][4] = {"p", "br", "pr", "res"}; + + opj_cio_t *cio = j2k->cio; + + /* Simply read the RED parameters */ + Lred = cio_read(cio, 2); + Pred = cio_read(cio, 1); + + /* Now we write them to screen */ + opj_event_msg(j2k->cinfo, EVT_INFO, + "RED(%d): %s, %dc, %s, %s\n", + cio_tell(cio) - 5, + str1[(Pred & (unsigned char) 0xC0) >> 6], /* addressing mode */ + (Pred & (unsigned char) 0x38) >> 3, /* corruption level */ + ((Pred & (unsigned char) 0x02) >> 1) ? "4Ba" : "2Ba", /* address range */ + (Pred & (unsigned char) 0x01) ? "errs" : "free"); /* error free? */ + + cio_skip(cio, Lred - 3); +} + +bool jpwl_check_tile(opj_j2k_t *j2k, opj_tcd_t *tcd, int tileno) { + +#ifdef oerhgierhgvhreit4u + /* + we navigate through the tile and find possible invalid parameters: + this saves a lot of crashes!!!!! + */ + int compno, resno, precno, /*layno,*/ bandno, blockno; + int numprecincts, numblocks; + + /* this is the selected tile */ + opj_tcd_tile_t *tile = &(tcd->tcd_image->tiles[tileno]); + + /* will keep the component */ + opj_tcd_tilecomp_t *comp = NULL; + + /* will keep the resolution */ + opj_tcd_resolution_t *res; + + /* will keep the subband */ + opj_tcd_band_t *band; + + /* will keep the precinct */ + opj_tcd_precinct_t *prec; + + /* will keep the codeblock */ + opj_tcd_cblk_t *block; + + /* check all tile components */ + for (compno = 0; compno < tile->numcomps; compno++) { + comp = &(tile->comps[compno]); + + /* check all component resolutions */ + for (resno = 0; resno < comp->numresolutions; resno++) { + res = &(comp->resolutions[resno]); + numprecincts = res->pw * res->ph; + + /* check all the subbands */ + for (bandno = 0; bandno < res->numbands; bandno++) { + band = &(res->bands[bandno]); + + /* check all the precincts */ + for (precno = 0; precno < numprecincts; precno++) { + prec = &(band->precincts[precno]); + numblocks = prec->ch * prec->cw; + + /* check all the codeblocks */ + for (blockno = 0; blockno < numblocks; blockno++) { + block = &(prec->cblks[blockno]); + + /* x-origin is invalid */ + if ((block->x0 < prec->x0) || (block->x0 > prec->x1)) { + opj_event_msg(j2k->cinfo, JPWL_ASSUME ? EVT_WARNING : EVT_ERROR, + "JPWL: wrong x-cord of block origin %d => x-prec is (%d, %d)\n", + block->x0, prec->x0, prec->x1); + if (!JPWL_ASSUME || JPWL_ASSUME) + return false; + }; + } + } + } + } + } + +#endif + + return true; +} + +/*@}*/ + +#endif /* USE_JPWL */ + + +#ifdef USE_JPSEC + +/** @defgroup JPSEC JPSEC - JPEG-2000 Part 8 (JPSEC) codestream manager */ +/*@{*/ + + +/** @name Local static functions */ +/*@{*/ + +void j2k_read_sec(opj_j2k_t *j2k) { + unsigned short int Lsec; + + opj_cio_t *cio = j2k->cio; + + /* Simply read the SEC length */ + Lsec = cio_read(cio, 2); + + /* Now we write them to screen */ + opj_event_msg(j2k->cinfo, EVT_INFO, + "SEC(%d)\n", + cio_tell(cio) - 2 + ); + + cio_skip(cio, Lsec - 2); +} + +void j2k_write_sec(opj_j2k_t *j2k) { + unsigned short int Lsec = 24; + int i; + + opj_cio_t *cio = j2k->cio; + + cio_write(cio, J2K_MS_SEC, 2); /* SEC */ + cio_write(cio, Lsec, 2); + + /* write dummy data */ + for (i = 0; i < Lsec - 2; i++) + cio_write(cio, 0, 1); +} + +void j2k_read_insec(opj_j2k_t *j2k) { + unsigned short int Linsec; + + opj_cio_t *cio = j2k->cio; + + /* Simply read the INSEC length */ + Linsec = cio_read(cio, 2); + + /* Now we write them to screen */ + opj_event_msg(j2k->cinfo, EVT_INFO, + "INSEC(%d)\n", + cio_tell(cio) - 2 + ); + + cio_skip(cio, Linsec - 2); +} + + +/*@}*/ + +/*@}*/ + +#endif /* USE_JPSEC */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/jpwl/jpwl.h b/gdcm/Utilities/gdcmopenjpeg-v2/jpwl/jpwl.h new file mode 100644 index 0000000..f273e5b --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/jpwl/jpwl.h @@ -0,0 +1,424 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * Copyright (c) 2005-2006, Dept. of Electronic and Information Engineering, Universita' degli Studi di Perugia, Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __JPWL_H +#define __JPWL_H + +#ifdef USE_JPWL + +#include "crc.h" +#include "rs.h" + +/** +@file jpwl.h +@brief The JPEG-2000 Part11 (JPWL) marker segments manager + +The functions in JPWL.C have for goal to read/write the markers added by JPWL. +*/ + +/** @defgroup JPWL JPWL - JPEG-2000 Part11 (JPWL) codestream manager */ +/*@{*/ + +/** +Assume a basic codestream structure, so you can resort better from uncorrected errors +*/ +#define JPWL_ASSUME true + +/** +EPB (Error Protection Block) Marker segment +*/ +typedef struct jpwl_epb_ms { + /**@name Private fields set by epb_create */ + /*@{*/ + /** is the latest in header? */ + bool latest; + /** is it in packed mode? */ + bool packed; + /** TH where this marker has been placed (-1 means MH) */ + int tileno; + /** index in current header (0-63) */ + unsigned char index; + /** error protection method [-1=absent 0=none 1=predefined 16=CRC-16 32=CRC-32 37-128=RS] */ + int hprot; + /** message word length of pre-data */ + int k_pre; + /** code word length of pre-data */ + int n_pre; + /** length of pre-data */ + int pre_len; + /** message word length of post-data */ + int k_post; + /** code word length of post-data */ + int n_post; + /** length of post-data */ + int post_len; + /*@}*/ + /**@name Marker segment fields */ + /*@{*/ + /** two bytes for the length of EPB MS, exluding the marker itself (11 to 65535 bytes) */ + unsigned short int Lepb; + /** single byte for the style */ + unsigned char Depb; + /** four bytes, from 0 to 2^31-1 */ + unsigned long int LDPepb; + /** four bytes, next error management method */ + unsigned long int Pepb; + /** EPB data, variable size */ + unsigned char *data; + /*@}*/ +} jpwl_epb_ms_t; + +/** +EPC (Error Protection Capability) Marker segment +*/ +typedef struct jpwl_epc_ms { + /** is ESD active? */ + bool esd_on; + /** is RED active? */ + bool red_on; + /** is EPB active? */ + bool epb_on; + /** are informative techniques active? */ + bool info_on; + /**@name Marker segment fields */ + /*@{*/ + /** two bytes for the length of EPC MS, exluding the marker itself (9 to 65535 bytes) */ + unsigned short int Lepc; + /** two bytes, CRC for the EPC, excluding Pcrc itself */ + unsigned short int Pcrc; + /** four bytes, the codestream length from SOC to EOC */ + unsigned long int DL; + /** one byte, signals JPWL techniques adoption */ + unsigned char Pepc; + /** EPC data, variable length */ + unsigned char *data; + /*@}*/ +} jpwl_epc_ms_t; + +/** +ESD (Error Sensitivity Descriptor) Marker segment +*/ +typedef struct jpwl_esd_ms { + /** codestream addressing mode [0=packet, 1=byte range, 2=packet range, 3=reserved] */ + unsigned char addrm; + /** size of codestream addresses [2/4 bytes] */ + unsigned char ad_size; + /** type of sensitivity + [0=relative error, 1=MSE, 2=MSE reduction, 3=PSNR, 4=PSNR increment, + 5=MAXERR (absolute peak error), 6=TSE (total squared error), 7=reserved */ + unsigned char senst; + /** size of sensitivity data (1/2 bytes) */ + unsigned char se_size; + /**@name Marker segment fields */ + /*@{*/ + /** two bytes for the length of ESD MS, exluding the marker itself (4 to 65535 bytes) */ + unsigned short int Lesd; + /** two bytes, component of error sensitivity */ + unsigned short int Cesd; + /** one byte, signals JPWL techniques adoption */ + unsigned char Pesd; + /** ESD data, variable length */ + unsigned char *data; + /*@}*/ + /**@name Fields set by esd_create (only internal use) */ + /*@{*/ + /** number of components in the image */ + int numcomps; + /** tile where this marker has been placed (-1 means MH) */ + int tileno; + /** number of sensitivity values */ + unsigned long int svalnum; + /** size of a single sensitivity pair (address+value) */ + size_t sensval_size; + /*@}*/ +} jpwl_esd_ms_t; + +/** +RED (Residual Error Descriptor) Marker segment +*/ +typedef struct jpwl_red_ms { + /** two bytes for the length of RED MS, exluding the marker itself (3 to 65535 bytes) */ + unsigned short int Lred; + /** one byte, signals JPWL techniques adoption */ + unsigned char Pred; + /** RED data, variable length */ + unsigned char *data; +} jpwl_red_ms_t; + +/** +Structure used to store JPWL markers temporary position and readyness +*/ +typedef struct jpwl_marker { + /** marker value (J2K_MS_EPC, etc.) */ + int id; + /** union keeping the pointer to the real marker struct */ + union jpwl_marks { + /** pointer to EPB marker */ + jpwl_epb_ms_t *epbmark; + /** pointer to EPC marker */ + jpwl_epc_ms_t *epcmark; + /** pointer to ESD marker */ + jpwl_esd_ms_t *esdmark; + /** pointer to RED marker */ + jpwl_red_ms_t *redmark; + } m; + /** position where the marker should go, in the pre-JPWL codestream */ + unsigned long int pos; + /** same as before, only written as a double, so we can sort it better */ + double dpos; + /** length of the marker segment (marker excluded) */ + unsigned short int len; + /** the marker length is ready or not? */ + bool len_ready; + /** the marker position is ready or not? */ + bool pos_ready; + /** the marker parameters are ready or not? */ + bool parms_ready; + /** are the written data ready or not */ + bool data_ready; +} jpwl_marker_t; + +/** +Encode according to JPWL specs +@param j2k J2K handle +@param cio codestream handle +@param image image handle +*/ +void jpwl_encode(opj_j2k_t *j2k, opj_cio_t *cio, opj_image_t *image); + +/** +Prepare the list of JPWL markers, after the Part 1 codestream +has been finalized (index struct is full) +@param j2k J2K handle +@param cio codestream handle +@param image image handle +*/ +void jpwl_prepare_marks(opj_j2k_t *j2k, opj_cio_t *cio, opj_image_t *image); + +/** +Dump the list of JPWL markers, after it has been prepared +@param j2k J2K handle +@param cio codestream handle +@param image image handle +*/ +void jpwl_dump_marks(opj_j2k_t *j2k, opj_cio_t *cio, opj_image_t *image); + +/** +Read the EPC marker (Error Protection Capability) +@param j2k J2K handle +*/ +void j2k_read_epc(opj_j2k_t *j2k); + +/** +Write the EPC marker (Error Protection Capability), BUT the DL field is always set to 0 +(this simplifies the management of EPBs and it is openly stated in the standard +as a possible value, mening that the information is not available) and the informative techniques +are not yet implemented +@param j2k J2K handle +*/ +void j2k_write_epc(opj_j2k_t *j2k); + +/** +Read the EPB marker (Error Protection Block) +@param j2k J2K handle +*/ +void j2k_read_epb(opj_j2k_t *j2k); + +/** +Write the EPB marker (Error Protection Block) +@param j2k J2K handle +*/ +void j2k_write_epb(opj_j2k_t *j2k); + +/** +Read the ESD marker (Error Sensitivity Descriptor) +@param j2k J2K handle +*/ +void j2k_read_esd(opj_j2k_t *j2k); + +/** +Read the RED marker (Residual Error Descriptor) +@param j2k J2K handle +*/ +void j2k_read_red(opj_j2k_t *j2k); + +/** create an EPB marker segment +@param j2k J2K compressor handle +@param latest it is the latest EPB in the header +@param packed EPB is in packed style +@param tileno tile number where the marker has been placed (-1 means MH) +@param idx current EPB running index +@param hprot applied protection type (-1/0,1,16,32,37-128) +@param pre_len length of pre-protected data +@param post_len length of post-protected data +@return returns the freshly created EPB +*/ +jpwl_epb_ms_t *jpwl_epb_create(opj_j2k_t *j2k, bool latest, bool packed, int tileno, int idx, int hprot, + unsigned long int pre_len, unsigned long int post_len); + +/** add a number of EPB marker segments +@param j2k J2K compressor handle +@param jwmarker pointer to the JPWL markers list +@param jwmarker_num pointer to the number of JPWL markers (gets updated) +@param latest it is the latest group of EPBs in the header +@param packed EPBs are in packed style +@param insideMH it is in the MH +@param idx pointer to the starting EPB running index (gets updated) +@param hprot applied protection type (-1/0,1,16,32,37-128) +@param place_pos place in original codestream where EPBs should go +@param tileno tile number of these EPBs +@param pre_len length of pre-protected data +@param post_len length of post-protected data +@return returns the length of all added markers +*/ +int jpwl_epbs_add(opj_j2k_t *j2k, jpwl_marker_t *jwmarker, int *jwmarker_num, + bool latest, bool packed, bool insideMH, int *idx, int hprot, + double place_pos, int tileno, + unsigned long int pre_len, unsigned long int post_len); + +/** add a number of ESD marker segments +@param j2k J2K compressor handle +@param jwmarker pointer to the JPWL markers list +@param jwmarker_num pointer to the number of JPWL markers (gets updated) +@param comps considered component (-1=average, 0/1/2/...=component no.) +@param addrm addressing mode (0=packet, 1=byte range, 2=packet range, 3=reserved) +@param ad_size size of addresses (2/4 bytes) +@param senst sensitivity type +@param se_size sensitivity values size (1/2 bytes) +@param place_pos place in original codestream where EPBs should go +@param tileno tile number of these EPBs +@return returns the length of all added markers +*/ +int jpwl_esds_add(opj_j2k_t *j2k, jpwl_marker_t *jwmarker, int *jwmarker_num, + int comps, unsigned char addrm, unsigned char ad_size, + unsigned char senst, unsigned char se_size, + double place_pos, int tileno); + +/** updates the information structure by modifying the positions and lengths +@param j2k J2K compressor handle +@param jwmarker pointer to JPWL markers list +@param jwmarker_num number of JPWL markers +@return returns true in case of success +*/ +bool jpwl_update_info(opj_j2k_t *j2k, jpwl_marker_t *jwmarker, int jwmarker_num); + + +bool jpwl_esd_fill(opj_j2k_t *j2k, jpwl_esd_ms_t *esdmark, unsigned char *buf); + +bool jpwl_epb_fill(opj_j2k_t *j2k, jpwl_epb_ms_t *epbmark, unsigned char *buf, unsigned char *post_buf); + +void j2k_add_marker(opj_codestream_info_t *cstr_info, unsigned short int type, int pos, int len); + +/** corrects the data in the JPWL codestream +@param j2k J2K compressor handle +@return true if correction is performed correctly +*/ +bool jpwl_correct(opj_j2k_t *j2k); + +/** corrects the data protected by an EPB +@param j2k J2K compressor handle +@param buffer pointer to the EPB position +@param type type of EPB: 0=MH, 1=TPH, 2=other, 3=auto +@param pre_len length of pre-data +@param post_len length of post_data +@param conn is a pointer to the length of all connected (packed) EPBs +@param L4_bufp is a pointer to the buffer pointer of redundancy data +@return returns true if correction could be succesfully performed +*/ +bool jpwl_epb_correct(opj_j2k_t *j2k, unsigned char *buffer, int type, int pre_len, int post_len, int *conn, + unsigned char **L4_bufp); + +/** check that a tile and its children have valid data +@param j2k J2K decompressor handle +@param tcd Tile decompressor handle +@param tileno number of the tile to check +*/ +bool jpwl_check_tile(opj_j2k_t *j2k, opj_tcd_t *tcd, int tileno); + +/** Macro functions for CRC computation */ + +/** +Computes the CRC-16, as stated in JPWL specs +@param CRC two bytes containing the CRC value (must be initialized with 0x0000) +@param DATA byte for which the CRC is computed; call this on every byte of the sequence +and get the CRC at the end +*/ +#define jpwl_updateCRC16(CRC, DATA) updateCRC16(CRC, DATA) + +/** +Computes the CRC-32, as stated in JPWL specs +@param CRC four bytes containing the CRC value (must be initialized with 0x00000000) +@param DATA byte for which the CRC is computed; call this on every byte of the sequence +and get the CRC at the end +*/ +#define jpwl_updateCRC32(CRC, DATA) updateCRC32(CRC, DATA) + +/** +Computes the minimum between two integers +@param a first integer to compare +@param b second integer to compare +@return returns the minimum integer between a and b +*/ +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif /* min */ + +/*@}*/ + +#endif /* USE_JPWL */ + +#ifdef USE_JPSEC + +/** @defgroup JPSEC JPSEC - JPEG-2000 Part 8 (JPSEC) codestream manager */ +/*@{*/ + +/** +Read the SEC marker (SEcured Codestream) +@param j2k J2K handle +*/ +void j2k_read_sec(opj_j2k_t *j2k); + +/** +Write the SEC marker (SEcured Codestream) +@param j2k J2K handle +*/ +void j2k_write_sec(opj_j2k_t *j2k); + +/** +Read the INSEC marker (SEcured Codestream) +@param j2k J2K handle +*/ +void j2k_read_insec(opj_j2k_t *j2k); + +/*@}*/ + +#endif /* USE_JPSEC */ + +#endif /* __JPWL_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/jpwl/jpwl_lib.c b/gdcm/Utilities/gdcmopenjpeg-v2/jpwl/jpwl_lib.c new file mode 100644 index 0000000..4c34343 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/jpwl/jpwl_lib.c @@ -0,0 +1,1796 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * Copyright (c) 2005-2006, Dept. of Electronic and Information Engineering, Universita' degli Studi di Perugia, Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef USE_JPWL + +#include "../libopenjpeg/opj_includes.h" +#include + +/** Minimum and maximum values for the double->pfp conversion */ +#define MIN_V1 0.0 +#define MAX_V1 17293822569102704640.0 +#define MIN_V2 0.000030517578125 +#define MAX_V2 131040.0 + +/** conversion between a double precision floating point +number and the corresponding pseudo-floating point used +to represent sensitivity values +@param V the double precision value +@param bytes the number of bytes of the representation +@return the pseudo-floating point value (cast accordingly) +*/ +unsigned short int jpwl_double_to_pfp(double V, int bytes); + +/** conversion between a pseudo-floating point used +to represent sensitivity values and the corresponding +double precision floating point number +@param em the pseudo-floating point value (cast accordingly) +@param bytes the number of bytes of the representation +@return the double precision value +*/ +double jpwl_pfp_to_double(unsigned short int em, int bytes); + + /*-------------------------------------------------------------*/ + +int jpwl_markcomp(const void *arg1, const void *arg2) +{ + /* Compare the two markers' positions */ + double diff = (((jpwl_marker_t *) arg1)->dpos - ((jpwl_marker_t *) arg2)->dpos); + + if (diff == 0.0) + return (0); + else if (diff < 0) + return (-1); + else + return (+1); +} + +int jpwl_epbs_add(opj_j2k_t *j2k, jpwl_marker_t *jwmarker, int *jwmarker_num, + bool latest, bool packed, bool insideMH, int *idx, int hprot, + double place_pos, int tileno, + unsigned long int pre_len, unsigned long int post_len) { + + jpwl_epb_ms_t *epb_mark = NULL; + + int k_pre, k_post, n_pre, n_post; + + unsigned long int L1, L2, dL4, max_postlen, epbs_len = 0; + + /* We find RS(n,k) for EPB parms and pre-data, if any */ + if (insideMH && (*idx == 0)) { + /* First EPB in MH */ + k_pre = 64; + n_pre = 160; + } else if (!insideMH && (*idx == 0)) { + /* First EPB in TH */ + k_pre = 25; + n_pre = 80; + } else { + /* Following EPBs in MH or TH */ + k_pre = 13; + n_pre = 40; + }; + + /* Find lengths, Figs. B3 and B4 */ + /* size of pre data: pre_buf(pre_len) + EPB(2) + Lepb(2) + Depb(1) + LDPepb(4) + Pepb(4) */ + L1 = pre_len + 13; + + /* size of pre-data redundancy */ + /* (redundancy per codeword) * (number of codewords, rounded up) */ + L2 = (n_pre - k_pre) * (unsigned long int) ceil((double) L1 / (double) k_pre); + + /* Find protection type for post data and its associated redundancy field length*/ + if ((hprot == 16) || (hprot == 32)) { + /* there is a CRC for post-data */ + k_post = post_len; + n_post = post_len + (hprot >> 3); + /*L3 = hprot >> 3;*/ /* 2 (CRC-16) or 4 (CRC-32) bytes */ + + } else if ((hprot >= 37) && (hprot <= 128)) { + /* there is a RS for post-data */ + k_post = 32; + n_post = hprot; + + } else { + /* Use predefined codes */ + n_post = n_pre; + k_post = k_pre; + }; + + /* Create the EPB(s) */ + while (post_len > 0) { + + /* maximum postlen in order to respect EPB size + (we use JPWL_MAXIMUM_EPB_ROOM instead of 65535 for keeping room for EPB parms)*/ + /* (message word size) * (number of containable parity words) */ + max_postlen = k_post * (unsigned long int) floor((double) JPWL_MAXIMUM_EPB_ROOM / (double) (n_post - k_post)); + + /* maximum postlen in order to respect EPB size */ + if (*idx == 0) + /* (we use (JPWL_MAXIMUM_EPB_ROOM - L2) instead of 65535 for keeping room for EPB parms + pre-data) */ + /* (message word size) * (number of containable parity words) */ + max_postlen = k_post * (unsigned long int) floor((double) (JPWL_MAXIMUM_EPB_ROOM - L2) / (double) (n_post - k_post)); + + else + /* (we use JPWL_MAXIMUM_EPB_ROOM instead of 65535 for keeping room for EPB parms) */ + /* (message word size) * (number of containable parity words) */ + max_postlen = k_post * (unsigned long int) floor((double) JPWL_MAXIMUM_EPB_ROOM / (double) (n_post - k_post)); + + /* null protection case */ + /* the max post length can be as large as the LDPepb field can host */ + if (hprot == 0) + max_postlen = INT_MAX; + + /* length to use */ + dL4 = min(max_postlen, post_len); + + if ((epb_mark = jpwl_epb_create( + j2k, /* this encoder handle */ + latest ? (dL4 < max_postlen) : false, /* is it the latest? */ + packed, /* is it packed? */ + tileno, /* we are in TPH */ + *idx, /* its index */ + hprot, /* protection type parameters of following data */ + 0, /* pre-data: nothing for now */ + dL4 /* post-data: the stub computed previously */ + ))) { + + /* Add this marker to the 'insertanda' list */ + if (*jwmarker_num < JPWL_MAX_NO_MARKERS) { + jwmarker[*jwmarker_num].id = J2K_MS_EPB; /* its type */ + jwmarker[*jwmarker_num].m.epbmark = epb_mark; /* the EPB */ + jwmarker[*jwmarker_num].pos = (int) place_pos; /* after SOT */ + jwmarker[*jwmarker_num].dpos = place_pos + 0.0000001 * (double)(*idx); /* not very first! */ + jwmarker[*jwmarker_num].len = epb_mark->Lepb; /* its length */ + jwmarker[*jwmarker_num].len_ready = true; /* ready */ + jwmarker[*jwmarker_num].pos_ready = true; /* ready */ + jwmarker[*jwmarker_num].parms_ready = true; /* ready */ + jwmarker[*jwmarker_num].data_ready = false; /* not ready */ + (*jwmarker_num)++; + } + + /* increment epb index */ + (*idx)++; + + /* decrease postlen */ + post_len -= dL4; + + /* increase the total length of EPBs */ + epbs_len += epb_mark->Lepb + 2; + + } else { + /* ooops, problems */ + opj_event_msg(j2k->cinfo, EVT_ERROR, "Could not create TPH EPB for UEP in tile %d\n", tileno); + }; + } + + return epbs_len; +} + + +jpwl_epb_ms_t *jpwl_epb_create(opj_j2k_t *j2k, bool latest, bool packed, int tileno, int idx, int hprot, + unsigned long int pre_len, unsigned long int post_len) { + + jpwl_epb_ms_t *epb = NULL; + /*unsigned short int data_len = 0;*/ + unsigned short int L2, L3; + unsigned long int L1, L4; + /*unsigned char *predata_in = NULL;*/ + + bool insideMH = (tileno == -1); + + /* Alloc space */ + if (!(epb = (jpwl_epb_ms_t *) opj_malloc((size_t) 1 * sizeof (jpwl_epb_ms_t)))) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "Could not allocate room for one EPB MS\n"); + return NULL; + }; + + /* We set RS(n,k) for EPB parms and pre-data, if any */ + if (insideMH && (idx == 0)) { + /* First EPB in MH */ + epb->k_pre = 64; + epb->n_pre = 160; + } else if (!insideMH && (idx == 0)) { + /* First EPB in TH */ + epb->k_pre = 25; + epb->n_pre = 80; + } else { + /* Following EPBs in MH or TH */ + epb->k_pre = 13; + epb->n_pre = 40; + }; + + /* Find lengths, Figs. B3 and B4 */ + /* size of pre data: pre_buf(pre_len) + EPB(2) + Lepb(2) + Depb(1) + LDPepb(4) + Pepb(4) */ + L1 = pre_len + 13; + epb->pre_len = pre_len; + + /* size of pre-data redundancy */ + /* (redundancy per codeword) * (number of codewords, rounded up) */ + L2 = (epb->n_pre - epb->k_pre) * (unsigned short int) ceil((double) L1 / (double) epb->k_pre); + + /* length of post-data */ + L4 = post_len; + epb->post_len = post_len; + + /* Find protection type for post data and its associated redundancy field length*/ + if ((hprot == 16) || (hprot == 32)) { + /* there is a CRC for post-data */ + epb->Pepb = 0x10000000 | ((unsigned long int) hprot >> 5); /* 0=CRC-16, 1=CRC-32 */ + epb->k_post = post_len; + epb->n_post = post_len + (hprot >> 3); + /*L3 = hprot >> 3;*/ /* 2 (CRC-16) or 4 (CRC-32) bytes */ + + } else if ((hprot >= 37) && (hprot <= 128)) { + /* there is a RS for post-data */ + epb->Pepb = 0x20000020 | (((unsigned long int) hprot & 0x000000FF) << 8); + epb->k_post = 32; + epb->n_post = hprot; + + } else if (hprot == 1) { + /* Use predefined codes */ + epb->Pepb = (unsigned long int) 0x00000000; + epb->n_post = epb->n_pre; + epb->k_post = epb->k_pre; + + } else if (hprot == 0) { + /* Placeholder EPB: only protects its parameters, no protection method */ + epb->Pepb = (unsigned long int) 0xFFFFFFFF; + epb->n_post = 1; + epb->k_post = 1; + + } else { + opj_event_msg(j2k->cinfo, EVT_ERROR, "Invalid protection value for EPB h = %d\n", hprot); + return NULL; + } + + epb->hprot = hprot; + + /* (redundancy per codeword) * (number of codewords, rounded up) */ + L3 = (epb->n_post - epb->k_post) * (unsigned short int) ceil((double) L4 / (double) epb->k_post); + + /* private fields */ + epb->tileno = tileno; + + /* Fill some fields of the EPB */ + + /* total length of the EPB MS (less the EPB marker itself): */ + /* Lepb(2) + Depb(1) + LDPepb(4) + Pepb(4) + pre_redundancy + post-redundancy */ + epb->Lepb = 11 + L2 + L3; + + /* EPB style */ + epb->Depb = ((packed & 0x0001) << 7) | ((latest & 0x0001) << 6) | (idx & 0x003F); + + /* length of data protected by EPB: */ + epb->LDPepb = L1 + L4; + + return epb; +} + +void jpwl_epb_write(opj_j2k_t *j2k, jpwl_epb_ms_t *epb, unsigned char *buf) { + + /* Marker */ + *(buf++) = (unsigned char) (J2K_MS_EPB >> 8); + *(buf++) = (unsigned char) (J2K_MS_EPB >> 0); + + /* Lepb */ + *(buf++) = (unsigned char) (epb->Lepb >> 8); + *(buf++) = (unsigned char) (epb->Lepb >> 0); + + /* Depb */ + *(buf++) = (unsigned char) (epb->Depb >> 0); + + /* LDPepb */ + *(buf++) = (unsigned char) (epb->LDPepb >> 24); + *(buf++) = (unsigned char) (epb->LDPepb >> 16); + *(buf++) = (unsigned char) (epb->LDPepb >> 8); + *(buf++) = (unsigned char) (epb->LDPepb >> 0); + + /* Pepb */ + *(buf++) = (unsigned char) (epb->Pepb >> 24); + *(buf++) = (unsigned char) (epb->Pepb >> 16); + *(buf++) = (unsigned char) (epb->Pepb >> 8); + *(buf++) = (unsigned char) (epb->Pepb >> 0); + + /* Data */ + /*memcpy(buf, epb->data, (size_t) epb->Lepb - 11);*/ + memset(buf, 0, (size_t) epb->Lepb - 11); + + /* update markers struct */ + j2k_add_marker(j2k->cstr_info, J2K_MS_EPB, -1, epb->Lepb + 2); + +}; + + +jpwl_epc_ms_t *jpwl_epc_create(opj_j2k_t *j2k, bool esd_on, bool red_on, bool epb_on, bool info_on) { + + jpwl_epc_ms_t *epc = NULL; + + /* Alloc space */ + if (!(epc = (jpwl_epc_ms_t *) opj_malloc((size_t) 1 * sizeof (jpwl_epc_ms_t)))) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "Could not allocate room for EPC MS\n"); + return NULL; + }; + + /* Set the EPC parameters */ + epc->esd_on = esd_on; + epc->epb_on = epb_on; + epc->red_on = red_on; + epc->info_on = info_on; + + /* Fill the EPC fields with default values */ + epc->Lepc = 9; + epc->Pcrc = 0x0000; + epc->DL = 0x00000000; + epc->Pepc = ((j2k->cp->esd_on & 0x0001) << 4) | ((j2k->cp->red_on & 0x0001) << 5) | + ((j2k->cp->epb_on & 0x0001) << 6) | ((j2k->cp->info_on & 0x0001) << 7); + + return (epc); +} + +bool jpwl_epb_fill(opj_j2k_t *j2k, jpwl_epb_ms_t *epb, unsigned char *buf, unsigned char *post_buf) { + + unsigned long int L1, L2, L3, L4; + int remaining; + unsigned long int P, NN_P; + + /* Operating buffer */ + static unsigned char codeword[NN], *parityword; + + unsigned char *L1_buf, *L2_buf; + /* these ones are static, since we need to keep memory of + the exact place from one call to the other */ + static unsigned char *L3_buf, *L4_buf; + + /* some consistency check */ + if (!buf) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "There is no operating buffer for EPBs\n"); + return false; + } + + if (!post_buf && !L4_buf) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "There is no operating buffer for EPBs data\n"); + return false; + } + + /* + * Compute parity bytes on pre-data, ALWAYS present (at least only for EPB parms) + */ + + /* Initialize RS structures */ + P = epb->n_pre - epb->k_pre; + NN_P = NN - P; + memset(codeword, 0, NN); + parityword = codeword + NN_P; + init_rs(NN_P); + + /* pre-data begins pre_len bytes before of EPB buf */ + L1_buf = buf - epb->pre_len; + L1 = epb->pre_len + 13; + + /* redundancy for pre-data begins immediately after EPB parms */ + L2_buf = buf + 13; + L2 = (epb->n_pre - epb->k_pre) * (unsigned short int) ceil((double) L1 / (double) epb->k_pre); + + /* post-data + the position of L4 buffer can be: + 1) passed as a parameter: in that case use it + 2) null: in that case use the previous (static) one + */ + if (post_buf) + L4_buf = post_buf; + L4 = epb->post_len; + + /* post-data redundancy begins immediately after pre-data redundancy */ + L3_buf = L2_buf + L2; + L3 = (epb->n_post - epb->k_post) * (unsigned short int) ceil((double) L4 / (double) epb->k_post); + + /* let's check whether EPB length is sufficient to contain all these data */ + if (epb->Lepb < (11 + L2 + L3)) + opj_event_msg(j2k->cinfo, EVT_ERROR, "There is no room in EPB data field for writing redundancy data\n"); + /*printf("Env. %d, nec. %d (%d + %d)\n", epb->Lepb - 11, L2 + L3, L2, L3);*/ + + /* Compute redundancy of pre-data message words */ + remaining = L1; + while (remaining) { + + /* copy message data into codeword buffer */ + if (remaining < epb->k_pre) { + /* the last message word is zero-padded */ + memset(codeword, 0, NN); + memcpy(codeword, L1_buf, remaining); + L1_buf += remaining; + remaining = 0; + + } else { + memcpy(codeword, L1_buf, epb->k_pre); + L1_buf += epb->k_pre; + remaining -= epb->k_pre; + + } + + /* Encode the buffer and obtain parity bytes */ + if (encode_rs(codeword, parityword)) + opj_event_msg(j2k->cinfo, EVT_WARNING, + "Possible encoding error in codeword @ position #%d\n", (L1_buf - buf) / epb->k_pre); + + /* copy parity bytes only in redundancy buffer */ + memcpy(L2_buf, parityword, P); + + /* advance parity buffer */ + L2_buf += P; + } + + /* + * Compute parity bytes on post-data, may be absent if there are no data + */ + /*printf("Hprot is %d (tileno=%d, k_pre=%d, n_pre=%d, k_post=%d, n_post=%d, pre_len=%d, post_len=%d)\n", + epb->hprot, epb->tileno, epb->k_pre, epb->n_pre, epb->k_post, epb->n_post, epb->pre_len, + epb->post_len);*/ + if (epb->hprot < 0) { + + /* there should be no EPB */ + + } else if (epb->hprot == 0) { + + /* no protection for the data */ + /* advance anyway */ + L4_buf += epb->post_len; + + } else if (epb->hprot == 16) { + + /* CRC-16 */ + unsigned short int mycrc = 0x0000; + + /* compute the CRC field (excluding itself) */ + remaining = L4; + while (remaining--) + jpwl_updateCRC16(&mycrc, *(L4_buf++)); + + /* write the CRC field */ + *(L3_buf++) = (unsigned char) (mycrc >> 8); + *(L3_buf++) = (unsigned char) (mycrc >> 0); + + } else if (epb->hprot == 32) { + + /* CRC-32 */ + unsigned long int mycrc = 0x00000000; + + /* compute the CRC field (excluding itself) */ + remaining = L4; + while (remaining--) + jpwl_updateCRC32(&mycrc, *(L4_buf++)); + + /* write the CRC field */ + *(L3_buf++) = (unsigned char) (mycrc >> 24); + *(L3_buf++) = (unsigned char) (mycrc >> 16); + *(L3_buf++) = (unsigned char) (mycrc >> 8); + *(L3_buf++) = (unsigned char) (mycrc >> 0); + + } else { + + /* RS */ + + /* Initialize RS structures */ + P = epb->n_post - epb->k_post; + NN_P = NN - P; + memset(codeword, 0, NN); + parityword = codeword + NN_P; + init_rs(NN_P); + + /* Compute redundancy of post-data message words */ + remaining = L4; + while (remaining) { + + /* copy message data into codeword buffer */ + if (remaining < epb->k_post) { + /* the last message word is zero-padded */ + memset(codeword, 0, NN); + memcpy(codeword, L4_buf, remaining); + L4_buf += remaining; + remaining = 0; + + } else { + memcpy(codeword, L4_buf, epb->k_post); + L4_buf += epb->k_post; + remaining -= epb->k_post; + + } + + /* Encode the buffer and obtain parity bytes */ + if (encode_rs(codeword, parityword)) + opj_event_msg(j2k->cinfo, EVT_WARNING, + "Possible encoding error in codeword @ position #%d\n", (L4_buf - buf) / epb->k_post); + + /* copy parity bytes only in redundancy buffer */ + memcpy(L3_buf, parityword, P); + + /* advance parity buffer */ + L3_buf += P; + } + + } + + return true; +} + + +bool jpwl_correct(opj_j2k_t *j2k) { + + opj_cio_t *cio = j2k->cio; + bool status; + static bool mh_done = false; + int mark_pos, id, len, skips, sot_pos; + unsigned long int Psot = 0; + + /* go back to marker position */ + mark_pos = cio_tell(cio) - 2; + cio_seek(cio, mark_pos); + + if ((j2k->state == J2K_STATE_MHSOC) && !mh_done) { + + int mark_val = 0, skipnum = 0; + + /* + COLOR IMAGE + first thing to do, if we are here, is to look whether + 51 (skipnum) positions ahead there is an EPB, in case of MH + */ + /* + B/W IMAGE + first thing to do, if we are here, is to look whether + 45 (skipnum) positions ahead there is an EPB, in case of MH + */ + /* SIZ SIZ_FIELDS SIZ_COMPS FOLLOWING_MARKER */ + skipnum = 2 + 38 + 3 * j2k->cp->exp_comps + 2; + if ((cio->bp + skipnum) < cio->end) { + + cio_skip(cio, skipnum); + + /* check that you are not going beyond the end of codestream */ + + /* call EPB corrector */ + status = jpwl_epb_correct(j2k, /* J2K decompressor handle */ + cio->bp, /* pointer to EPB in codestream buffer */ + 0, /* EPB type: MH */ + skipnum, /* length of pre-data */ + -1, /* length of post-data: -1 means auto */ + NULL, + NULL + ); + + /* read the marker value */ + mark_val = (*(cio->bp) << 8) | *(cio->bp + 1); + + if (status && (mark_val == J2K_MS_EPB)) { + /* we found it! */ + mh_done = true; + return true; + } + + /* Disable correction in case of missing or bad head EPB */ + /* We can't do better! */ + /* PATCHED: 2008-01-25 */ + /* MOVED UP: 2008-02-01 */ + if (!status) { + j2k->cp->correct = false; + opj_event_msg(j2k->cinfo, EVT_WARNING, "Couldn't find the MH EPB: disabling JPWL\n"); + } + + } + + } + + if (true /*(j2k->state == J2K_STATE_TPHSOT) || (j2k->state == J2K_STATE_TPH)*/) { + /* else, look if 12 positions ahead there is an EPB, in case of TPH */ + cio_seek(cio, mark_pos); + if ((cio->bp + 12) < cio->end) { + + cio_skip(cio, 12); + + /* call EPB corrector */ + status = jpwl_epb_correct(j2k, /* J2K decompressor handle */ + cio->bp, /* pointer to EPB in codestream buffer */ + 1, /* EPB type: TPH */ + 12, /* length of pre-data */ + -1, /* length of post-data: -1 means auto */ + NULL, + NULL + ); + if (status) + /* we found it! */ + return true; + } + } + + return false; + + /* for now, don't use this code */ + + /* else, look if here is an EPB, in case of other */ + if (mark_pos > 64) { + /* it cannot stay before the first MH EPB */ + cio_seek(cio, mark_pos); + cio_skip(cio, 0); + + /* call EPB corrector */ + status = jpwl_epb_correct(j2k, /* J2K decompressor handle */ + cio->bp, /* pointer to EPB in codestream buffer */ + 2, /* EPB type: TPH */ + 0, /* length of pre-data */ + -1, /* length of post-data: -1 means auto */ + NULL, + NULL + ); + if (status) + /* we found it! */ + return true; + } + + /* nope, no EPBs probably, or they are so damaged that we can give up */ + return false; + + return true; + + /* AN ATTEMPT OF PARSER */ + /* NOT USED ACTUALLY */ + + /* go to the beginning of the file */ + cio_seek(cio, 0); + + /* let's begin */ + j2k->state = J2K_STATE_MHSOC; + + /* cycle all over the markers */ + while (cio_tell(cio) < cio->length) { + + /* read the marker */ + mark_pos = cio_tell(cio); + id = cio_read(cio, 2); + + /* details */ + printf("Marker@%d: %X\n", cio_tell(cio) - 2, id); + + /* do an action in response to the read marker */ + switch (id) { + + /* short markers */ + + /* SOC */ + case J2K_MS_SOC: + j2k->state = J2K_STATE_MHSIZ; + len = 0; + skips = 0; + break; + + /* EOC */ + case J2K_MS_EOC: + j2k->state = J2K_STATE_MT; + len = 0; + skips = 0; + break; + + /* particular case of SOD */ + case J2K_MS_SOD: + len = Psot - (mark_pos - sot_pos) - 2; + skips = len; + break; + + /* long markers */ + + /* SOT */ + case J2K_MS_SOT: + j2k->state = J2K_STATE_TPH; + sot_pos = mark_pos; /* position of SOT */ + len = cio_read(cio, 2); /* read the length field */ + cio_skip(cio, 2); /* this field is unnecessary */ + Psot = cio_read(cio, 4); /* tile length */ + skips = len - 8; + break; + + /* remaining */ + case J2K_MS_SIZ: + j2k->state = J2K_STATE_MH; + /* read the length field */ + len = cio_read(cio, 2); + skips = len - 2; + break; + + /* remaining */ + default: + /* read the length field */ + len = cio_read(cio, 2); + skips = len - 2; + break; + + } + + /* skip to marker's end */ + cio_skip(cio, skips); + + } + + +} + +bool jpwl_epb_correct(opj_j2k_t *j2k, unsigned char *buffer, int type, int pre_len, int post_len, int *conn, + unsigned char **L4_bufp) { + + /* Operating buffer */ + unsigned char codeword[NN], *parityword; + + unsigned long int P, NN_P; + unsigned long int L1, L4; + int remaining, n_pre, k_pre, n_post, k_post; + + int status, tt; + + int orig_pos = cio_tell(j2k->cio); + + unsigned char *L1_buf, *L2_buf; + unsigned char *L3_buf, *L4_buf; + + unsigned long int LDPepb, Pepb; + unsigned short int Lepb; + unsigned char Depb; + char str1[25] = ""; + int myconn, errnum = 0; + bool errflag = false; + + opj_cio_t *cio = j2k->cio; + + /* check for common errors */ + if (!buffer) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "The EPB pointer is a NULL buffer\n"); + return false; + } + + /* set bignesses */ + L1 = pre_len + 13; + + /* pre-data correction */ + switch (type) { + + case 0: + /* MH EPB */ + k_pre = 64; + n_pre = 160; + break; + + case 1: + /* TPH EPB */ + k_pre = 25; + n_pre = 80; + break; + + case 2: + /* other EPBs */ + k_pre = 13; + n_pre = 40; + break; + + case 3: + /* automatic setup */ + opj_event_msg(j2k->cinfo, EVT_ERROR, "Auto. setup not yet implemented\n"); + return false; + break; + + default: + /* unknown type */ + opj_event_msg(j2k->cinfo, EVT_ERROR, "Unknown expected EPB type\n"); + return false; + break; + + } + + /* Initialize RS structures */ + P = n_pre - k_pre; + NN_P = NN - P; + tt = (int) floor((float) P / 2.0F); /* correction capability of the code */ + memset(codeword, 0, NN); + parityword = codeword + NN_P; + init_rs(NN_P); + + /* Correct pre-data message words */ + L1_buf = buffer - pre_len; + L2_buf = buffer + 13; + remaining = L1; + while (remaining) { + + /* always zero-pad codewords */ + /* (this is required, since after decoding the zeros in the long codeword + could change, and keep unchanged in subsequent calls) */ + memset(codeword, 0, NN); + + /* copy codeword buffer into message bytes */ + if (remaining < k_pre) + memcpy(codeword, L1_buf, remaining); + else + memcpy(codeword, L1_buf, k_pre); + + /* copy redundancy buffer in parity bytes */ + memcpy(parityword, L2_buf, P); + + /* Decode the buffer and possibly obtain corrected bytes */ + status = eras_dec_rs(codeword, NULL, 0); + if (status == -1) { + /*if (conn == NULL) + opj_event_msg(j2k->cinfo, EVT_WARNING, + "Possible decoding error in codeword @ position #%d\n", (L1_buf - buffer) / k_pre);*/ + errflag = true; + /* we can try to safely get out from the function: + if we are here, either this is not an EPB or the first codeword + is too damaged to be helpful */ + /*return false;*/ + + } else if (status == 0) { + /*if (conn == NULL) + opj_event_msg(j2k->cinfo, EVT_INFO, "codeword is correctly decoded\n");*/ + + } else if (status <= tt) { + /* it has corrected 0 <= errs <= tt */ + /*if (conn == NULL) + opj_event_msg(j2k->cinfo, EVT_WARNING, "%d errors corrected in codeword\n", status);*/ + errnum += status; + + } else { + /*if (conn == NULL) + opj_event_msg(j2k->cinfo, EVT_WARNING, "EPB correction capability exceeded\n"); + return false;*/ + errflag = true; + } + + + /* advance parity buffer */ + if ((status >= 0) && (status <= tt)) + /* copy back corrected parity only if all is OK */ + memcpy(L2_buf, parityword, P); + L2_buf += P; + + /* advance message buffer */ + if (remaining < k_pre) { + if ((status >= 0) && (status <= tt)) + /* copy back corrected data only if all is OK */ + memcpy(L1_buf, codeword, remaining); + L1_buf += remaining; + remaining = 0; + + } else { + if ((status >= 0) && (status <= tt)) + /* copy back corrected data only if all is OK */ + memcpy(L1_buf, codeword, k_pre); + L1_buf += k_pre; + remaining -= k_pre; + + } + } + + /* print summary */ + if (!conn) { + + /*if (errnum) + opj_event_msg(j2k->cinfo, EVT_INFO, "+ %d symbol errors corrected (Ps=%.1e)\n", errnum, + (float) errnum / ((float) n_pre * (float) L1 / (float) k_pre));*/ + if (errflag) { + /*opj_event_msg(j2k->cinfo, EVT_INFO, "+ there were unrecoverable errors\n");*/ + return false; + } + + } + + /* presumably, now, EPB parameters are correct */ + /* let's get them */ + + /* Simply read the EPB parameters */ + if (conn) + cio->bp = buffer; + cio_skip(cio, 2); /* the marker */ + Lepb = cio_read(cio, 2); + Depb = cio_read(cio, 1); + LDPepb = cio_read(cio, 4); + Pepb = cio_read(cio, 4); + + /* What does Pepb tells us about the protection method? */ + if (((Pepb & 0xF0000000) >> 28) == 0) + sprintf(str1, "pred"); /* predefined */ + else if (((Pepb & 0xF0000000) >> 28) == 1) + sprintf(str1, "crc-%lu", 16 * ((Pepb & 0x00000001) + 1)); /* CRC mode */ + else if (((Pepb & 0xF0000000) >> 28) == 2) + sprintf(str1, "rs(%lu,32)", (Pepb & 0x0000FF00) >> 8); /* RS mode */ + else if (Pepb == 0xFFFFFFFF) + sprintf(str1, "nometh"); /* RS mode */ + else + sprintf(str1, "unknown"); /* unknown */ + + /* Now we write them to screen */ + if (!conn && post_len) + opj_event_msg(j2k->cinfo, EVT_INFO, + "EPB(%d): (%sl, %sp, %u), %lu, %s\n", + cio_tell(cio) - 13, + (Depb & 0x40) ? "" : "n", /* latest EPB or not? */ + (Depb & 0x80) ? "" : "n", /* packed or unpacked EPB? */ + (Depb & 0x3F), /* EPB index value */ + LDPepb, /*length of the data protected by the EPB */ + str1); /* protection method */ + + + /* well, we need to investigate how long is the connected length of packed EPBs */ + myconn = Lepb + 2; + if ((Depb & 0x40) == 0) /* not latest in header */ + jpwl_epb_correct(j2k, /* J2K decompressor handle */ + buffer + Lepb + 2, /* pointer to next EPB in codestream buffer */ + 2, /* EPB type: should be of other type */ + 0, /* only EPB fields */ + 0, /* do not look after */ + &myconn, + NULL + ); + if (conn) + *conn += myconn; + + /*if (!conn) + printf("connected = %d\n", myconn);*/ + + /*cio_seek(j2k->cio, orig_pos); + return true;*/ + + /* post-data + the position of L4 buffer is at the end of currently connected EPBs + */ + if (!(L4_bufp)) + L4_buf = buffer + myconn; + else if (!(*L4_bufp)) + L4_buf = buffer + myconn; + else + L4_buf = *L4_bufp; + if (post_len == -1) + L4 = LDPepb - pre_len - 13; + else if (post_len == 0) + L4 = 0; + else + L4 = post_len; + + L3_buf = L2_buf; + + /* Do a further check here on the read parameters */ + if (L4 > (unsigned long) cio_numbytesleft(j2k->cio)) + /* overflow */ + return false; + + /* we are ready for decoding the remaining data */ + if (((Pepb & 0xF0000000) >> 28) == 1) { + /* CRC here */ + if ((16 * ((Pepb & 0x00000001) + 1)) == 16) { + + /* CRC-16 */ + unsigned short int mycrc = 0x0000, filecrc = 0x0000; + + /* compute the CRC field */ + remaining = L4; + while (remaining--) + jpwl_updateCRC16(&mycrc, *(L4_buf++)); + + /* read the CRC field */ + filecrc = *(L3_buf++) << 8; + filecrc |= *(L3_buf++); + + /* check the CRC field */ + if (mycrc == filecrc) { + if (conn == NULL) + opj_event_msg(j2k->cinfo, EVT_INFO, "- CRC is OK\n"); + } else { + if (conn == NULL) + opj_event_msg(j2k->cinfo, EVT_WARNING, "- CRC is KO (r=%d, c=%d)\n", filecrc, mycrc); + errflag = true; + } + } + + if ((16 * ((Pepb & 0x00000001) + 1)) == 32) { + + /* CRC-32 */ + unsigned long int mycrc = 0x00000000, filecrc = 0x00000000; + + /* compute the CRC field */ + remaining = L4; + while (remaining--) + jpwl_updateCRC32(&mycrc, *(L4_buf++)); + + /* read the CRC field */ + filecrc = *(L3_buf++) << 24; + filecrc |= *(L3_buf++) << 16; + filecrc |= *(L3_buf++) << 8; + filecrc |= *(L3_buf++); + + /* check the CRC field */ + if (mycrc == filecrc) { + if (conn == NULL) + opj_event_msg(j2k->cinfo, EVT_INFO, "- CRC is OK\n"); + } else { + if (conn == NULL) + opj_event_msg(j2k->cinfo, EVT_WARNING, "- CRC is KO (r=%d, c=%d)\n", filecrc, mycrc); + errflag = true; + } + } + + } else if (Pepb == 0xFFFFFFFF) { + /* no method */ + + /* advance without doing anything */ + remaining = L4; + while (remaining--) + L4_buf++; + + } else if ((((Pepb & 0xF0000000) >> 28) == 2) || (((Pepb & 0xF0000000) >> 28) == 0)) { + /* RS coding here */ + + if (((Pepb & 0xF0000000) >> 28) == 0) { + + k_post = k_pre; + n_post = n_pre; + + } else { + + k_post = 32; + n_post = (Pepb & 0x0000FF00) >> 8; + } + + /* Initialize RS structures */ + P = n_post - k_post; + NN_P = NN - P; + tt = (int) floor((float) P / 2.0F); /* again, correction capability */ + memset(codeword, 0, NN); + parityword = codeword + NN_P; + init_rs(NN_P); + + /* Correct post-data message words */ + /*L4_buf = buffer + Lepb + 2;*/ + L3_buf = L2_buf; + remaining = L4; + while (remaining) { + + /* always zero-pad codewords */ + /* (this is required, since after decoding the zeros in the long codeword + could change, and keep unchanged in subsequent calls) */ + memset(codeword, 0, NN); + + /* copy codeword buffer into message bytes */ + if (remaining < k_post) + memcpy(codeword, L4_buf, remaining); + else + memcpy(codeword, L4_buf, k_post); + + /* copy redundancy buffer in parity bytes */ + memcpy(parityword, L3_buf, P); + + /* Decode the buffer and possibly obtain corrected bytes */ + status = eras_dec_rs(codeword, NULL, 0); + if (status == -1) { + /*if (conn == NULL) + opj_event_msg(j2k->cinfo, EVT_WARNING, + "Possible decoding error in codeword @ position #%d\n", (L4_buf - (buffer + Lepb + 2)) / k_post);*/ + errflag = true; + + } else if (status == 0) { + /*if (conn == NULL) + opj_event_msg(j2k->cinfo, EVT_INFO, "codeword is correctly decoded\n");*/ + + } else if (status <= tt) { + /*if (conn == NULL) + opj_event_msg(j2k->cinfo, EVT_WARNING, "%d errors corrected in codeword\n", status);*/ + errnum += status; + + } else { + /*if (conn == NULL) + opj_event_msg(j2k->cinfo, EVT_WARNING, "EPB correction capability exceeded\n"); + return false;*/ + errflag = true; + } + + + /* advance parity buffer */ + if ((status >= 0) && (status <= tt)) + /* copy back corrected data only if all is OK */ + memcpy(L3_buf, parityword, P); + L3_buf += P; + + /* advance message buffer */ + if (remaining < k_post) { + if ((status >= 0) && (status <= tt)) + /* copy back corrected data only if all is OK */ + memcpy(L4_buf, codeword, remaining); + L4_buf += remaining; + remaining = 0; + + } else { + if ((status >= 0) && (status <= tt)) + /* copy back corrected data only if all is OK */ + memcpy(L4_buf, codeword, k_post); + L4_buf += k_post; + remaining -= k_post; + + } + } + } + + /* give back the L4_buf address */ + if (L4_bufp) + *L4_bufp = L4_buf; + + /* print summary */ + if (!conn) { + + if (errnum) + opj_event_msg(j2k->cinfo, EVT_INFO, "- %d symbol errors corrected (Ps=%.1e)\n", errnum, + (float) errnum / (float) LDPepb); + if (errflag) + opj_event_msg(j2k->cinfo, EVT_INFO, "- there were unrecoverable errors\n"); + + } + + cio_seek(j2k->cio, orig_pos); + + return true; +} + +void jpwl_epc_write(opj_j2k_t *j2k, jpwl_epc_ms_t *epc, unsigned char *buf) { + + /* Marker */ + *(buf++) = (unsigned char) (J2K_MS_EPC >> 8); + *(buf++) = (unsigned char) (J2K_MS_EPC >> 0); + + /* Lepc */ + *(buf++) = (unsigned char) (epc->Lepc >> 8); + *(buf++) = (unsigned char) (epc->Lepc >> 0); + + /* Pcrc */ + *(buf++) = (unsigned char) (epc->Pcrc >> 8); + *(buf++) = (unsigned char) (epc->Pcrc >> 0); + + /* DL */ + *(buf++) = (unsigned char) (epc->DL >> 24); + *(buf++) = (unsigned char) (epc->DL >> 16); + *(buf++) = (unsigned char) (epc->DL >> 8); + *(buf++) = (unsigned char) (epc->DL >> 0); + + /* Pepc */ + *(buf++) = (unsigned char) (epc->Pepc >> 0); + + /* Data */ + /*memcpy(buf, epc->data, (size_t) epc->Lepc - 9);*/ + memset(buf, 0, (size_t) epc->Lepc - 9); + + /* update markers struct */ + j2k_add_marker(j2k->cstr_info, J2K_MS_EPC, -1, epc->Lepc + 2); + +}; + +int jpwl_esds_add(opj_j2k_t *j2k, jpwl_marker_t *jwmarker, int *jwmarker_num, + int comps, unsigned char addrm, unsigned char ad_size, + unsigned char senst, unsigned char se_size, + double place_pos, int tileno) { + + return 0; +} + +jpwl_esd_ms_t *jpwl_esd_create(opj_j2k_t *j2k, int comp, unsigned char addrm, unsigned char ad_size, + unsigned char senst, unsigned char se_size, int tileno, + unsigned long int svalnum, void *sensval) { + + jpwl_esd_ms_t *esd = NULL; + + /* Alloc space */ + if (!(esd = (jpwl_esd_ms_t *) opj_malloc((size_t) 1 * sizeof (jpwl_esd_ms_t)))) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "Could not allocate room for ESD MS\n"); + return NULL; + }; + + /* if relative sensitivity, activate byte range mode */ + if (senst == 0) + addrm = 1; + + /* size of sensval's ... */ + if ((ad_size != 0) && (ad_size != 2) && (ad_size != 4)) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "Address size %d for ESD MS is forbidden\n", ad_size); + return NULL; + } + if ((se_size != 1) && (se_size != 2)) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "Sensitivity size %d for ESD MS is forbidden\n", se_size); + return NULL; + } + + /* ... depends on the addressing mode */ + switch (addrm) { + + /* packet mode */ + case (0): + ad_size = 0; /* as per the standard */ + esd->sensval_size = se_size; + break; + + /* byte range */ + case (1): + /* auto sense address size */ + if (ad_size == 0) + /* if there are more than 66% of (2^16 - 1) bytes, switch to 4 bytes + (we keep space for possible EPBs being inserted) */ + ad_size = (j2k->cstr_info->codestream_size > (1 * 65535 / 3)) ? 4 : 2; + esd->sensval_size = ad_size + ad_size + se_size; + break; + + /* packet range */ + case (2): + /* auto sense address size */ + if (ad_size == 0) + /* if there are more than 2^16 - 1 packets, switch to 4 bytes */ + ad_size = (j2k->cstr_info->packno > 65535) ? 4 : 2; + esd->sensval_size = ad_size + ad_size + se_size; + break; + + case (3): + opj_event_msg(j2k->cinfo, EVT_ERROR, "Address mode %d for ESD MS is unimplemented\n", addrm); + return NULL; + + default: + opj_event_msg(j2k->cinfo, EVT_ERROR, "Address mode %d for ESD MS is forbidden\n", addrm); + return NULL; + } + + /* set or unset sensitivity values */ + if (svalnum <= 0) { + + switch (senst) { + + /* just based on the portions of a codestream */ + case (0): + /* MH + no. of THs + no. of packets */ + svalnum = 1 + (j2k->cstr_info->tw * j2k->cstr_info->th) * (1 + j2k->cstr_info->packno); + break; + + /* all the ones that are based on the packets */ + default: + if (tileno < 0) + /* MH: all the packets and all the tiles info is written */ + svalnum = j2k->cstr_info->tw * j2k->cstr_info->th * j2k->cstr_info->packno; + else + /* TPH: only that tile info is written */ + svalnum = j2k->cstr_info->packno; + break; + + } + } + + /* fill private fields */ + esd->senst = senst; + esd->ad_size = ad_size; + esd->se_size = se_size; + esd->addrm = addrm; + esd->svalnum = svalnum; + esd->numcomps = j2k->image->numcomps; + esd->tileno = tileno; + + /* Set the ESD parameters */ + /* length, excluding data field */ + if (esd->numcomps < 257) + esd->Lesd = 4 + (unsigned short int) (esd->svalnum * esd->sensval_size); + else + esd->Lesd = 5 + (unsigned short int) (esd->svalnum * esd->sensval_size); + + /* component data field */ + if (comp >= 0) + esd->Cesd = comp; + else + /* we are averaging */ + esd->Cesd = 0; + + /* Pesd field */ + esd->Pesd = 0x00; + esd->Pesd |= (esd->addrm & 0x03) << 6; /* addressing mode */ + esd->Pesd |= (esd->senst & 0x07) << 3; /* sensitivity type */ + esd->Pesd |= ((esd->se_size >> 1) & 0x01) << 2; /* sensitivity size */ + esd->Pesd |= ((esd->ad_size >> 2) & 0x01) << 1; /* addressing size */ + esd->Pesd |= (comp < 0) ? 0x01 : 0x00; /* averaging components */ + + /* if pointer to sensval is NULL, we can fill data field by ourselves */ + if (!sensval) { + + /* old code moved to jpwl_esd_fill() */ + esd->data = NULL; + + } else { + /* we set the data field as the sensitivity values poinnter passed to the function */ + esd->data = (unsigned char *) sensval; + } + + return (esd); +} + +bool jpwl_esd_fill(opj_j2k_t *j2k, jpwl_esd_ms_t *esd, unsigned char *buf) { + + int i; + unsigned long int vv; + unsigned long int addr1 = 0L, addr2 = 0L; + double dvalue = 0.0, Omax2, tmp, TSE = 0.0, MSE, oldMSE = 0.0, PSNR, oldPSNR = 0.0; + unsigned short int pfpvalue; + unsigned long int addrmask = 0x00000000; + bool doneMH = false, doneTPH = false; + + /* sensitivity values in image info are as follows: + - for each tile, distotile is the starting distortion for that tile, sum of all components + - for each packet in a tile, disto is the distortion reduction caused by that packet to that tile + - the TSE for a single tile should be given by distotile - sum(disto) , for all components + - the MSE for a single tile is given by TSE / nbpix , for all components + - the PSNR for a single tile is given by 10*log10( Omax^2 / MSE) , for all components + (Omax is given by 2^bpp - 1 for unsigned images and by 2^(bpp - 1) - 1 for signed images + */ + + /* browse all components and find Omax */ + Omax2 = 0.0; + for (i = 0; i < j2k->image->numcomps; i++) { + tmp = pow(2.0, (double) (j2k->image->comps[i].sgnd ? + (j2k->image->comps[i].bpp - 1) : (j2k->image->comps[i].bpp))) - 1; + if (tmp > Omax2) + Omax2 = tmp; + } + Omax2 = Omax2 * Omax2; + + /* if pointer of esd->data is not null, simply write down all the values byte by byte */ + if (esd->data) { + for (i = 0; i < (int) esd->svalnum; i++) + *(buf++) = esd->data[i]; + return true; + } + + /* addressing mask */ + if (esd->ad_size == 2) + addrmask = 0x0000FFFF; /* two bytes */ + else + addrmask = 0xFFFFFFFF; /* four bytes */ + + /* set on precise point where sensitivity starts */ + if (esd->numcomps < 257) + buf += 6; + else + buf += 7; + + /* let's fill the data fields */ + for (vv = (esd->tileno < 0) ? 0 : (j2k->cstr_info->packno * esd->tileno); vv < esd->svalnum; vv++) { + + int thistile = vv / j2k->cstr_info->packno, thispacket = vv % j2k->cstr_info->packno; + + /* skip for the hack some lines below */ + if (thistile == j2k->cstr_info->tw * j2k->cstr_info->th) + break; + + /* starting tile distortion */ + if (thispacket == 0) { + TSE = j2k->cstr_info->tile[thistile].distotile; + oldMSE = TSE / j2k->cstr_info->tile[thistile].numpix; + oldPSNR = 10.0 * log10(Omax2 / oldMSE); + } + + /* TSE */ + TSE -= j2k->cstr_info->tile[thistile].packet[thispacket].disto; + + /* MSE */ + MSE = TSE / j2k->cstr_info->tile[thistile].numpix; + + /* PSNR */ + PSNR = 10.0 * log10(Omax2 / MSE); + + /* fill the address range */ + switch (esd->addrm) { + + /* packet mode */ + case (0): + /* nothing, there is none */ + break; + + /* byte range */ + case (1): + /* start address of packet */ + addr1 = (j2k->cstr_info->tile[thistile].packet[thispacket].start_pos) & addrmask; + /* end address of packet */ + addr2 = (j2k->cstr_info->tile[thistile].packet[thispacket].end_pos) & addrmask; + break; + + /* packet range */ + case (2): + /* not implemented here */ + opj_event_msg(j2k->cinfo, EVT_WARNING, "Addressing mode packet_range is not implemented\n"); + break; + + /* unknown addressing method */ + default: + /* not implemented here */ + opj_event_msg(j2k->cinfo, EVT_WARNING, "Unknown addressing mode\n"); + break; + + } + + /* hack for writing relative sensitivity of MH and TPHs */ + if ((esd->senst == 0) && (thispacket == 0)) { + + /* possible MH */ + if ((thistile == 0) && !doneMH) { + /* we have to manage MH addresses */ + addr1 = 0; /* start of MH */ + addr2 = j2k->cstr_info->main_head_end; /* end of MH */ + /* set special dvalue for this MH */ + dvalue = -10.0; + doneMH = true; /* don't come here anymore */ + vv--; /* wrap back loop counter */ + + } else if (!doneTPH) { + /* we have to manage TPH addresses */ + addr1 = j2k->cstr_info->tile[thistile].start_pos; + addr2 = j2k->cstr_info->tile[thistile].end_header; + /* set special dvalue for this TPH */ + dvalue = -1.0; + doneTPH = true; /* don't come here till the next tile */ + vv--; /* wrap back loop counter */ + } + + } else + doneTPH = false; /* reset TPH counter */ + + /* write the addresses to the buffer */ + switch (esd->ad_size) { + + case (0): + /* do nothing */ + break; + + case (2): + /* two bytes */ + *(buf++) = (unsigned char) (addr1 >> 8); + *(buf++) = (unsigned char) (addr1 >> 0); + *(buf++) = (unsigned char) (addr2 >> 8); + *(buf++) = (unsigned char) (addr2 >> 0); + break; + + case (4): + /* four bytes */ + *(buf++) = (unsigned char) (addr1 >> 24); + *(buf++) = (unsigned char) (addr1 >> 16); + *(buf++) = (unsigned char) (addr1 >> 8); + *(buf++) = (unsigned char) (addr1 >> 0); + *(buf++) = (unsigned char) (addr2 >> 24); + *(buf++) = (unsigned char) (addr2 >> 16); + *(buf++) = (unsigned char) (addr2 >> 8); + *(buf++) = (unsigned char) (addr2 >> 0); + break; + + default: + /* do nothing */ + break; + } + + + /* let's fill the value field */ + switch (esd->senst) { + + /* relative sensitivity */ + case (0): + /* we just write down the packet ordering */ + if (dvalue == -10) + /* MH */ + dvalue = MAX_V1 + 1000.0; /* this will cause pfpvalue set to 0xFFFF */ + else if (dvalue == -1) + /* TPH */ + dvalue = MAX_V1 + 1000.0; /* this will cause pfpvalue set to 0xFFFF */ + else + /* packet: first is most important, and then in decreasing order + down to the last, which counts for 1 */ + dvalue = jpwl_pfp_to_double((unsigned short) (j2k->cstr_info->packno - thispacket), esd->se_size); + break; + + /* MSE */ + case (1): + /* !!! WRONG: let's put here disto field of packets !!! */ + dvalue = MSE; + break; + + /* MSE reduction */ + case (2): + dvalue = oldMSE - MSE; + oldMSE = MSE; + break; + + /* PSNR */ + case (3): + dvalue = PSNR; + break; + + /* PSNR increase */ + case (4): + dvalue = PSNR - oldPSNR; + oldPSNR = PSNR; + break; + + /* MAXERR */ + case (5): + dvalue = 0.0; + opj_event_msg(j2k->cinfo, EVT_WARNING, "MAXERR sensitivity mode is not implemented\n"); + break; + + /* TSE */ + case (6): + dvalue = TSE; + break; + + /* reserved */ + case (7): + dvalue = 0.0; + opj_event_msg(j2k->cinfo, EVT_WARNING, "Reserved sensitivity mode is not implemented\n"); + break; + + default: + dvalue = 0.0; + break; + } + + /* compute the pseudo-floating point value */ + pfpvalue = jpwl_double_to_pfp(dvalue, esd->se_size); + + /* write the pfp value to the buffer */ + switch (esd->se_size) { + + case (1): + /* one byte */ + *(buf++) = (unsigned char) (pfpvalue >> 0); + break; + + case (2): + /* two bytes */ + *(buf++) = (unsigned char) (pfpvalue >> 8); + *(buf++) = (unsigned char) (pfpvalue >> 0); + break; + } + + } + + return true; +} + +void jpwl_esd_write(opj_j2k_t *j2k, jpwl_esd_ms_t *esd, unsigned char *buf) { + + /* Marker */ + *(buf++) = (unsigned char) (J2K_MS_ESD >> 8); + *(buf++) = (unsigned char) (J2K_MS_ESD >> 0); + + /* Lesd */ + *(buf++) = (unsigned char) (esd->Lesd >> 8); + *(buf++) = (unsigned char) (esd->Lesd >> 0); + + /* Cesd */ + if (esd->numcomps >= 257) + *(buf++) = (unsigned char) (esd->Cesd >> 8); + *(buf++) = (unsigned char) (esd->Cesd >> 0); + + /* Pesd */ + *(buf++) = (unsigned char) (esd->Pesd >> 0); + + /* Data */ + if (esd->numcomps < 257) + memset(buf, 0xAA, (size_t) esd->Lesd - 4); + /*memcpy(buf, esd->data, (size_t) esd->Lesd - 4);*/ + else + memset(buf, 0xAA, (size_t) esd->Lesd - 5); + /*memcpy(buf, esd->data, (size_t) esd->Lesd - 5);*/ + + /* update markers struct */ + j2k_add_marker(j2k->cstr_info, J2K_MS_ESD, -1, esd->Lesd + 2); + +} + +unsigned short int jpwl_double_to_pfp(double V, int bytes) { + + unsigned short int em, e, m; + + switch (bytes) { + + case (1): + + if (V < MIN_V1) { + e = 0x0000; + m = 0x0000; + } else if (V > MAX_V1) { + e = 0x000F; + m = 0x000F; + } else { + e = (unsigned short int) (floor(log(V) * 1.44269504088896) / 4.0); + m = (unsigned short int) (0.5 + (V / (pow(2.0, (double) (4 * e))))); + } + em = ((e & 0x000F) << 4) + (m & 0x000F); + break; + + case (2): + + if (V < MIN_V2) { + e = 0x0000; + m = 0x0000; + } else if (V > MAX_V2) { + e = 0x001F; + m = 0x07FF; + } else { + e = (unsigned short int) floor(log(V) * 1.44269504088896) + 15; + m = (unsigned short int) (0.5 + 2048.0 * ((V / (pow(2.0, (double) e - 15.0))) - 1.0)); + } + em = ((e & 0x001F) << 11) + (m & 0x07FF); + break; + + default: + + em = 0x0000; + break; + }; + + return em; +} + +double jpwl_pfp_to_double(unsigned short int em, int bytes) { + + double V; + + switch (bytes) { + + case 1: + V = (double) (em & 0x0F) * pow(2.0, (double) (em & 0xF0)); + break; + + case 2: + + V = pow(2.0, (double) ((em & 0xF800) >> 11) - 15.0) * (1.0 + (double) (em & 0x07FF) / 2048.0); + break; + + default: + V = 0.0; + break; + + } + + return V; + +} + +bool jpwl_update_info(opj_j2k_t *j2k, jpwl_marker_t *jwmarker, int jwmarker_num) { + + int mm; + unsigned long int addlen; + + opj_codestream_info_t *info = j2k->cstr_info; + int tileno, tpno, packno, numtiles = info->th * info->tw, numpacks = info->packno; + + if (!j2k || !jwmarker ) { + opj_event_msg(j2k->cinfo, EVT_ERROR, "J2K handle or JPWL markers list badly allocated\n"); + return false; + } + + /* main_head_end: how many markers are there before? */ + addlen = 0; + for (mm = 0; mm < jwmarker_num; mm++) + if (jwmarker[mm].pos < (unsigned long int) info->main_head_end) + addlen += jwmarker[mm].len + 2; + info->main_head_end += addlen; + + /* codestream_size: always increment with all markers */ + addlen = 0; + for (mm = 0; mm < jwmarker_num; mm++) + addlen += jwmarker[mm].len + 2; + info->codestream_size += addlen; + + /* navigate through all the tiles */ + for (tileno = 0; tileno < numtiles; tileno++) { + + /* start_pos: increment with markers before SOT */ + addlen = 0; + for (mm = 0; mm < jwmarker_num; mm++) + if (jwmarker[mm].pos < (unsigned long int) info->tile[tileno].start_pos) + addlen += jwmarker[mm].len + 2; + info->tile[tileno].start_pos += addlen; + + /* end_header: increment with markers before of it */ + addlen = 0; + for (mm = 0; mm < jwmarker_num; mm++) + if (jwmarker[mm].pos < (unsigned long int) info->tile[tileno].end_header) + addlen += jwmarker[mm].len + 2; + info->tile[tileno].end_header += addlen; + + /* end_pos: increment with markers before the end of this tile */ + /* code is disabled, since according to JPWL no markers can be beyond TPH */ + addlen = 0; + for (mm = 0; mm < jwmarker_num; mm++) + if (jwmarker[mm].pos < (unsigned long int) info->tile[tileno].end_pos) + addlen += jwmarker[mm].len + 2; + info->tile[tileno].end_pos += addlen; + + /* navigate through all the tile parts */ + for (tpno = 0; tpno < info->tile[tileno].num_tps; tpno++) { + + /* start_pos: increment with markers before SOT */ + addlen = 0; + for (mm = 0; mm < jwmarker_num; mm++) + if (jwmarker[mm].pos < (unsigned long int) info->tile[tileno].tp[tpno].tp_start_pos) + addlen += jwmarker[mm].len + 2; + info->tile[tileno].tp[tpno].tp_start_pos += addlen; + + /* end_header: increment with markers before of it */ + addlen = 0; + for (mm = 0; mm < jwmarker_num; mm++) + if (jwmarker[mm].pos < (unsigned long int) info->tile[tileno].tp[tpno].tp_end_header) + addlen += jwmarker[mm].len + 2; + info->tile[tileno].tp[tpno].tp_end_header += addlen; + + /* end_pos: increment with markers before the end of this tile part */ + addlen = 0; + for (mm = 0; mm < jwmarker_num; mm++) + if (jwmarker[mm].pos < (unsigned long int) info->tile[tileno].tp[tpno].tp_end_pos) + addlen += jwmarker[mm].len + 2; + info->tile[tileno].tp[tpno].tp_end_pos += addlen; + + } + + /* navigate through all the packets in this tile */ + for (packno = 0; packno < numpacks; packno++) { + + /* start_pos: increment with markers before the packet */ + /* disabled for the same reason as before */ + addlen = 0; + for (mm = 0; mm < jwmarker_num; mm++) + if (jwmarker[mm].pos <= (unsigned long int) info->tile[tileno].packet[packno].start_pos) + addlen += jwmarker[mm].len + 2; + info->tile[tileno].packet[packno].start_pos += addlen; + + /* end_ph_pos: increment with markers before the packet */ + /* disabled for the same reason as before */ + /*addlen = 0; + for (mm = 0; mm < jwmarker_num; mm++) + if (jwmarker[mm].pos < (unsigned long int) info->tile[tileno].packet[packno].end_ph_pos) + addlen += jwmarker[mm].len + 2;*/ + info->tile[tileno].packet[packno].end_ph_pos += addlen; + + /* end_pos: increment if marker is before the end of packet */ + /* disabled for the same reason as before */ + /*addlen = 0; + for (mm = 0; mm < jwmarker_num; mm++) + if (jwmarker[mm].pos < (unsigned long int) info->tile[tileno].packet[packno].end_pos) + addlen += jwmarker[mm].len + 2;*/ + info->tile[tileno].packet[packno].end_pos += addlen; + + } + } + + /* reorder the markers list */ + + return true; +} + +#endif /* USE_JPWL */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/jpwl/rs.c b/gdcm/Utilities/gdcmopenjpeg-v2/jpwl/rs.c new file mode 100644 index 0000000..9c2582d --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/jpwl/rs.c @@ -0,0 +1,594 @@ + /* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * Copyright (c) 2005-2006, Dept. of Electronic and Information Engineering, Universita' degli Studi di Perugia, Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef USE_JPWL + +/** +@file rs.c +@brief Functions used to compute the Reed-Solomon parity and check of byte arrays + +*/ + +/** + * Reed-Solomon coding and decoding + * Phil Karn (karn@ka9q.ampr.org) September 1996 + * + * This file is derived from the program "new_rs_erasures.c" by Robert + * Morelos-Zaragoza (robert@spectra.eng.hawaii.edu) and Hari Thirumoorthy + * (harit@spectra.eng.hawaii.edu), Aug 1995 + * + * I've made changes to improve performance, clean up the code and make it + * easier to follow. Data is now passed to the encoding and decoding functions + * through arguments rather than in global arrays. The decode function returns + * the number of corrected symbols, or -1 if the word is uncorrectable. + * + * This code supports a symbol size from 2 bits up to 16 bits, + * implying a block size of 3 2-bit symbols (6 bits) up to 65535 + * 16-bit symbols (1,048,560 bits). The code parameters are set in rs.h. + * + * Note that if symbols larger than 8 bits are used, the type of each + * data array element switches from unsigned char to unsigned int. The + * caller must ensure that elements larger than the symbol range are + * not passed to the encoder or decoder. + * + */ +#include +#include +#include "rs.h" + +/* This defines the type used to store an element of the Galois Field + * used by the code. Make sure this is something larger than a char if + * if anything larger than GF(256) is used. + * + * Note: unsigned char will work up to GF(256) but int seems to run + * faster on the Pentium. + */ +typedef int gf; + +/* Primitive polynomials - see Lin & Costello, Appendix A, + * and Lee & Messerschmitt, p. 453. + */ +#if(MM == 2)/* Admittedly silly */ +int Pp[MM+1] = { 1, 1, 1 }; + +#elif(MM == 3) +/* 1 + x + x^3 */ +int Pp[MM+1] = { 1, 1, 0, 1 }; + +#elif(MM == 4) +/* 1 + x + x^4 */ +int Pp[MM+1] = { 1, 1, 0, 0, 1 }; + +#elif(MM == 5) +/* 1 + x^2 + x^5 */ +int Pp[MM+1] = { 1, 0, 1, 0, 0, 1 }; + +#elif(MM == 6) +/* 1 + x + x^6 */ +int Pp[MM+1] = { 1, 1, 0, 0, 0, 0, 1 }; + +#elif(MM == 7) +/* 1 + x^3 + x^7 */ +int Pp[MM+1] = { 1, 0, 0, 1, 0, 0, 0, 1 }; + +#elif(MM == 8) +/* 1+x^2+x^3+x^4+x^8 */ +int Pp[MM+1] = { 1, 0, 1, 1, 1, 0, 0, 0, 1 }; + +#elif(MM == 9) +/* 1+x^4+x^9 */ +int Pp[MM+1] = { 1, 0, 0, 0, 1, 0, 0, 0, 0, 1 }; + +#elif(MM == 10) +/* 1+x^3+x^10 */ +int Pp[MM+1] = { 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1 }; + +#elif(MM == 11) +/* 1+x^2+x^11 */ +int Pp[MM+1] = { 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; + +#elif(MM == 12) +/* 1+x+x^4+x^6+x^12 */ +int Pp[MM+1] = { 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1 }; + +#elif(MM == 13) +/* 1+x+x^3+x^4+x^13 */ +int Pp[MM+1] = { 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; + +#elif(MM == 14) +/* 1+x+x^6+x^10+x^14 */ +int Pp[MM+1] = { 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1 }; + +#elif(MM == 15) +/* 1+x+x^15 */ +int Pp[MM+1] = { 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; + +#elif(MM == 16) +/* 1+x+x^3+x^12+x^16 */ +int Pp[MM+1] = { 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1 }; + +#else +#error "MM must be in range 2-16" +#endif + +/* Alpha exponent for the first root of the generator polynomial */ +#define B0 0 /* Different from the default 1 */ + +/* index->polynomial form conversion table */ +gf Alpha_to[NN + 1]; + +/* Polynomial->index form conversion table */ +gf Index_of[NN + 1]; + +/* No legal value in index form represents zero, so + * we need a special value for this purpose + */ +#define A0 (NN) + +/* Generator polynomial g(x) + * Degree of g(x) = 2*TT + * has roots @**B0, @**(B0+1), ... ,@^(B0+2*TT-1) + */ +/*gf Gg[NN - KK + 1];*/ +gf Gg[NN - 1]; + +/* Compute x % NN, where NN is 2**MM - 1, + * without a slow divide + */ +static /*inline*/ gf +modnn(int x) +{ + while (x >= NN) { + x -= NN; + x = (x >> MM) + (x & NN); + } + return x; +} + +/*#define min(a,b) ((a) < (b) ? (a) : (b))*/ + +#define CLEAR(a,n) {\ + int ci;\ + for(ci=(n)-1;ci >=0;ci--)\ + (a)[ci] = 0;\ + } + +#define COPY(a,b,n) {\ + int ci;\ + for(ci=(n)-1;ci >=0;ci--)\ + (a)[ci] = (b)[ci];\ + } +#define COPYDOWN(a,b,n) {\ + int ci;\ + for(ci=(n)-1;ci >=0;ci--)\ + (a)[ci] = (b)[ci];\ + } + +void init_rs(int k) +{ + KK = k; + if (KK >= NN) { + printf("KK must be less than 2**MM - 1\n"); + exit(1); + } + + generate_gf(); + gen_poly(); +} + +/* generate GF(2**m) from the irreducible polynomial p(X) in p[0]..p[m] + lookup tables: index->polynomial form alpha_to[] contains j=alpha**i; + polynomial form -> index form index_of[j=alpha**i] = i + alpha=2 is the primitive element of GF(2**m) + HARI's COMMENT: (4/13/94) alpha_to[] can be used as follows: + Let @ represent the primitive element commonly called "alpha" that + is the root of the primitive polynomial p(x). Then in GF(2^m), for any + 0 <= i <= 2^m-2, + @^i = a(0) + a(1) @ + a(2) @^2 + ... + a(m-1) @^(m-1) + where the binary vector (a(0),a(1),a(2),...,a(m-1)) is the representation + of the integer "alpha_to[i]" with a(0) being the LSB and a(m-1) the MSB. Thus for + example the polynomial representation of @^5 would be given by the binary + representation of the integer "alpha_to[5]". + Similarily, index_of[] can be used as follows: + As above, let @ represent the primitive element of GF(2^m) that is + the root of the primitive polynomial p(x). In order to find the power + of @ (alpha) that has the polynomial representation + a(0) + a(1) @ + a(2) @^2 + ... + a(m-1) @^(m-1) + we consider the integer "i" whose binary representation with a(0) being LSB + and a(m-1) MSB is (a(0),a(1),...,a(m-1)) and locate the entry + "index_of[i]". Now, @^index_of[i] is that element whose polynomial + representation is (a(0),a(1),a(2),...,a(m-1)). + NOTE: + The element alpha_to[2^m-1] = 0 always signifying that the + representation of "@^infinity" = 0 is (0,0,0,...,0). + Similarily, the element index_of[0] = A0 always signifying + that the power of alpha which has the polynomial representation + (0,0,...,0) is "infinity". + +*/ + +void +generate_gf(void) +{ + register int i, mask; + + mask = 1; + Alpha_to[MM] = 0; + for (i = 0; i < MM; i++) { + Alpha_to[i] = mask; + Index_of[Alpha_to[i]] = i; + /* If Pp[i] == 1 then, term @^i occurs in poly-repr of @^MM */ + if (Pp[i] != 0) + Alpha_to[MM] ^= mask; /* Bit-wise EXOR operation */ + mask <<= 1; /* single left-shift */ + } + Index_of[Alpha_to[MM]] = MM; + /* + * Have obtained poly-repr of @^MM. Poly-repr of @^(i+1) is given by + * poly-repr of @^i shifted left one-bit and accounting for any @^MM + * term that may occur when poly-repr of @^i is shifted. + */ + mask >>= 1; + for (i = MM + 1; i < NN; i++) { + if (Alpha_to[i - 1] >= mask) + Alpha_to[i] = Alpha_to[MM] ^ ((Alpha_to[i - 1] ^ mask) << 1); + else + Alpha_to[i] = Alpha_to[i - 1] << 1; + Index_of[Alpha_to[i]] = i; + } + Index_of[0] = A0; + Alpha_to[NN] = 0; +} + + +/* + * Obtain the generator polynomial of the TT-error correcting, length + * NN=(2**MM -1) Reed Solomon code from the product of (X+@**(B0+i)), i = 0, + * ... ,(2*TT-1) + * + * Examples: + * + * If B0 = 1, TT = 1. deg(g(x)) = 2*TT = 2. + * g(x) = (x+@) (x+@**2) + * + * If B0 = 0, TT = 2. deg(g(x)) = 2*TT = 4. + * g(x) = (x+1) (x+@) (x+@**2) (x+@**3) + */ +void +gen_poly(void) +{ + register int i, j; + + Gg[0] = Alpha_to[B0]; + Gg[1] = 1; /* g(x) = (X+@**B0) initially */ + for (i = 2; i <= NN - KK; i++) { + Gg[i] = 1; + /* + * Below multiply (Gg[0]+Gg[1]*x + ... +Gg[i]x^i) by + * (@**(B0+i-1) + x) + */ + for (j = i - 1; j > 0; j--) + if (Gg[j] != 0) + Gg[j] = Gg[j - 1] ^ Alpha_to[modnn((Index_of[Gg[j]]) + B0 + i - 1)]; + else + Gg[j] = Gg[j - 1]; + /* Gg[0] can never be zero */ + Gg[0] = Alpha_to[modnn((Index_of[Gg[0]]) + B0 + i - 1)]; + } + /* convert Gg[] to index form for quicker encoding */ + for (i = 0; i <= NN - KK; i++) + Gg[i] = Index_of[Gg[i]]; +} + + +/* + * take the string of symbols in data[i], i=0..(k-1) and encode + * systematically to produce NN-KK parity symbols in bb[0]..bb[NN-KK-1] data[] + * is input and bb[] is output in polynomial form. Encoding is done by using + * a feedback shift register with appropriate connections specified by the + * elements of Gg[], which was generated above. Codeword is c(X) = + * data(X)*X**(NN-KK)+ b(X) + */ +int +encode_rs(dtype *data, dtype *bb) +{ + register int i, j; + gf feedback; + + CLEAR(bb,NN-KK); + for (i = KK - 1; i >= 0; i--) { +#if (MM != 8) + if(data[i] > NN) + return -1; /* Illegal symbol */ +#endif + feedback = Index_of[data[i] ^ bb[NN - KK - 1]]; + if (feedback != A0) { /* feedback term is non-zero */ + for (j = NN - KK - 1; j > 0; j--) + if (Gg[j] != A0) + bb[j] = bb[j - 1] ^ Alpha_to[modnn(Gg[j] + feedback)]; + else + bb[j] = bb[j - 1]; + bb[0] = Alpha_to[modnn(Gg[0] + feedback)]; + } else { /* feedback term is zero. encoder becomes a + * single-byte shifter */ + for (j = NN - KK - 1; j > 0; j--) + bb[j] = bb[j - 1]; + bb[0] = 0; + } + } + return 0; +} + +/* + * Performs ERRORS+ERASURES decoding of RS codes. If decoding is successful, + * writes the codeword into data[] itself. Otherwise data[] is unaltered. + * + * Return number of symbols corrected, or -1 if codeword is illegal + * or uncorrectable. + * + * First "no_eras" erasures are declared by the calling program. Then, the + * maximum # of errors correctable is t_after_eras = floor((NN-KK-no_eras)/2). + * If the number of channel errors is not greater than "t_after_eras" the + * transmitted codeword will be recovered. Details of algorithm can be found + * in R. Blahut's "Theory ... of Error-Correcting Codes". + */ +int +eras_dec_rs(dtype *data, int *eras_pos, int no_eras) +{ + int deg_lambda, el, deg_omega; + int i, j, r; + gf u,q,tmp,num1,num2,den,discr_r; + gf recd[NN]; + /* Err+Eras Locator poly and syndrome poly */ + /*gf lambda[NN-KK + 1], s[NN-KK + 1]; + gf b[NN-KK + 1], t[NN-KK + 1], omega[NN-KK + 1]; + gf root[NN-KK], reg[NN-KK + 1], loc[NN-KK];*/ + gf lambda[NN + 1], s[NN + 1]; + gf b[NN + 1], t[NN + 1], omega[NN + 1]; + gf root[NN], reg[NN + 1], loc[NN]; + int syn_error, count; + + /* data[] is in polynomial form, copy and convert to index form */ + for (i = NN-1; i >= 0; i--){ +#if (MM != 8) + if(data[i] > NN) + return -1; /* Illegal symbol */ +#endif + recd[i] = Index_of[data[i]]; + } + /* first form the syndromes; i.e., evaluate recd(x) at roots of g(x) + * namely @**(B0+i), i = 0, ... ,(NN-KK-1) + */ + syn_error = 0; + for (i = 1; i <= NN-KK; i++) { + tmp = 0; + for (j = 0; j < NN; j++) + if (recd[j] != A0) /* recd[j] in index form */ + tmp ^= Alpha_to[modnn(recd[j] + (B0+i-1)*j)]; + syn_error |= tmp; /* set flag if non-zero syndrome => + * error */ + /* store syndrome in index form */ + s[i] = Index_of[tmp]; + } + if (!syn_error) { + /* + * if syndrome is zero, data[] is a codeword and there are no + * errors to correct. So return data[] unmodified + */ + return 0; + } + CLEAR(&lambda[1],NN-KK); + lambda[0] = 1; + if (no_eras > 0) { + /* Init lambda to be the erasure locator polynomial */ + lambda[1] = Alpha_to[eras_pos[0]]; + for (i = 1; i < no_eras; i++) { + u = eras_pos[i]; + for (j = i+1; j > 0; j--) { + tmp = Index_of[lambda[j - 1]]; + if(tmp != A0) + lambda[j] ^= Alpha_to[modnn(u + tmp)]; + } + } +#ifdef ERASURE_DEBUG + /* find roots of the erasure location polynomial */ + for(i=1;i<=no_eras;i++) + reg[i] = Index_of[lambda[i]]; + count = 0; + for (i = 1; i <= NN; i++) { + q = 1; + for (j = 1; j <= no_eras; j++) + if (reg[j] != A0) { + reg[j] = modnn(reg[j] + j); + q ^= Alpha_to[reg[j]]; + } + if (!q) { + /* store root and error location + * number indices + */ + root[count] = i; + loc[count] = NN - i; + count++; + } + } + if (count != no_eras) { + printf("\n lambda(x) is WRONG\n"); + return -1; + } +#ifndef NO_PRINT + printf("\n Erasure positions as determined by roots of Eras Loc Poly:\n"); + for (i = 0; i < count; i++) + printf("%d ", loc[i]); + printf("\n"); +#endif +#endif + } + for(i=0;i 0; j--) + if (reg[j] != A0) { + reg[j] = modnn(reg[j] + j); + q ^= Alpha_to[reg[j]]; + } + if (!q) { + /* store root (index-form) and error location number */ + root[count] = i; + loc[count] = NN - i; + count++; + } + } + +#ifdef DEBUG + printf("\n Final error positions:\t"); + for (i = 0; i < count; i++) + printf("%d ", loc[i]); + printf("\n"); +#endif + if (deg_lambda != count) { + /* + * deg(lambda) unequal to number of roots => uncorrectable + * error detected + */ + return -1; + } + /* + * Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo + * x**(NN-KK)). in index form. Also find deg(omega). + */ + deg_omega = 0; + for (i = 0; i < NN-KK;i++){ + tmp = 0; + j = (deg_lambda < i) ? deg_lambda : i; + for(;j >= 0; j--){ + if ((s[i + 1 - j] != A0) && (lambda[j] != A0)) + tmp ^= Alpha_to[modnn(s[i + 1 - j] + lambda[j])]; + } + if(tmp != 0) + deg_omega = i; + omega[i] = Index_of[tmp]; + } + omega[NN-KK] = A0; + + /* + * Compute error values in poly-form. num1 = omega(inv(X(l))), num2 = + * inv(X(l))**(B0-1) and den = lambda_pr(inv(X(l))) all in poly-form + */ + for (j = count-1; j >=0; j--) { + num1 = 0; + for (i = deg_omega; i >= 0; i--) { + if (omega[i] != A0) + num1 ^= Alpha_to[modnn(omega[i] + i * root[j])]; + } + num2 = Alpha_to[modnn(root[j] * (B0 - 1) + NN)]; + den = 0; + + /* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */ + for (i = min(deg_lambda,NN-KK-1) & ~1; i >= 0; i -=2) { + if(lambda[i+1] != A0) + den ^= Alpha_to[modnn(lambda[i+1] + i * root[j])]; + } + if (den == 0) { +#ifdef DEBUG + printf("\n ERROR: denominator = 0\n"); +#endif + return -1; + } + /* Apply error to data */ + if (num1 != 0) { + data[loc[j]] ^= Alpha_to[modnn(Index_of[num1] + Index_of[num2] + NN - Index_of[den])]; + } + } + return count; +} + + +#endif /* USE_JPWL */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/jpwl/rs.h b/gdcm/Utilities/gdcmopenjpeg-v2/jpwl/rs.h new file mode 100644 index 0000000..7e9c5d2 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/jpwl/rs.h @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Hervé Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * Copyright (c) 2005-2006, Dept. of Electronic and Information Engineering, Universita' degli Studi di Perugia, Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef USE_JPWL + +/** +@file rs.h +@brief Functions used to compute Reed-Solomon parity and check of byte arrays + +*/ + +#ifndef __RS_HEADER__ +#define __RS_HEADER__ + +/** Global definitions for Reed-Solomon encoder/decoder + * Phil Karn KA9Q, September 1996 + * + * The parameters MM and KK specify the Reed-Solomon code parameters. + * + * Set MM to be the size of each code symbol in bits. The Reed-Solomon + * block size will then be NN = 2**M - 1 symbols. Supported values are + * defined in rs.c. + * + * Set KK to be the number of data symbols in each block, which must be + * less than the block size. The code will then be able to correct up + * to NN-KK erasures or (NN-KK)/2 errors, or combinations thereof with + * each error counting as two erasures. + */ +#define MM 8 /* RS code over GF(2**MM) - change to suit */ +//static int KK; +int KK; + +/* Original code */ +/*#define KK 239*/ /* KK = number of information symbols */ + +#define NN ((1 << MM) - 1) + +#if (MM <= 8) +typedef unsigned char dtype; +#else +typedef unsigned int dtype; +#endif + +/** Initialization function */ +void init_rs(int); + +/** These two functions *must* be called in this order (e.g., + * by init_rs()) before any encoding/decoding + */ +void generate_gf(void); /* Generate Galois Field */ +void gen_poly(void); /* Generate generator polynomial */ + +/** Reed-Solomon encoding + * data[] is the input block, parity symbols are placed in bb[] + * bb[] may lie past the end of the data, e.g., for (255,223): + * encode_rs(&data[0],&data[223]); + */ +int encode_rs(dtype data[], dtype bb[]); + +/** Reed-Solomon erasures-and-errors decoding + * The received block goes into data[], and a list of zero-origin + * erasure positions, if any, goes in eras_pos[] with a count in no_eras. + * + * The decoder corrects the symbols in place, if possible and returns + * the number of corrected symbols. If the codeword is illegal or + * uncorrectible, the data array is unchanged and -1 is returned + */ +int eras_dec_rs(dtype data[], int eras_pos[], int no_eras); + +/** +Computes the minimum between two integers +@param a first integer to compare +@param b second integer to compare +@return returns the minimum integer between a and b +*/ +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif /* min */ + +#endif /* __RS_HEADER__ */ + + +#endif /* USE_JPWL */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/CMakeLists.txt b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/CMakeLists.txt new file mode 100644 index 0000000..3705098 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/CMakeLists.txt @@ -0,0 +1,90 @@ +include_regular_expression("^.*$") +# Defines the source code for the library +set(OPENJPEG_SRCS + tcd.c + bio.c + cio.c + dwt.c + event.c + image.c + j2k.c + j2k_lib.c + jp2.c + jpt.c + mct.c + mqc.c + openjpeg.c + pi.c + raw.c + t1.c + tgt.c + profile.c + invert.c + function_list.c + t2.c + bio.h + cio.h + dwt.h + event.h + image.h + j2k.h + j2k_lib.h + jp2.h + jpt.h + mct.h + mqc.h + openjpeg.h + pi.h + int.h + raw.h + t1.h + t2.h + tcd.h + tgt.h + profile.h + invert.h + function_list.h +) + +# Pass proper definition to preprocessor to generate shared lib +if(WIN32) + if(BUILD_SHARED_LIBS) + add_definitions(-DOPJ_EXPORTS) + else() + add_definitions(-DOPJ_STATIC) + endif() +endif() + +if(ENABLE_PROFILING) + add_definitions(-D_PROFILE) +endif() + +# Create the library +add_library(${OPENJPEG_LIBRARY_NAME} ${OPENJPEG_SRCS}) +set_target_properties(${OPENJPEG_LIBRARY_NAME} PROPERTIES + ${OPENJPEG_LIBRARY_PROPERTIES} LINK_INTERFACE_LIBRARIES "") +if(UNIX) + target_link_libraries(${OPENJPEG_LIBRARY_NAME} m) +endif() + + +# Install library +if(NOT OPENJPEG_INSTALL_NO_LIBRARIES) + install(TARGETS ${OPENJPEG_LIBRARY_NAME} + EXPORT ${GDCM_TARGETS_NAME} + RUNTIME DESTINATION ${OPENJPEG_INSTALL_BIN_DIR} COMPONENT Applications + LIBRARY DESTINATION ${OPENJPEG_INSTALL_LIB_DIR} COMPONENT Libraries + ARCHIVE DESTINATION ${OPENJPEG_INSTALL_LIB_DIR} COMPONENT DebugDevel + ) +endif() + +# Install includes files +if(NOT OPENJPEG_INSTALL_NO_DEVELOPMENT) + file(GLOB header_files "*.h") + install(FILES ${header_files} + DESTINATION ${OPENJPEG_INSTALL_INCLUDE_DIR} COMPONENT Headers + ) +endif() +#install(FILES openjpeg.h +# DESTINATION ${OPENJPEG_INSTALL_INCLUDE_DIR} COMPONENT Headers +#) diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/bio.c b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/bio.c new file mode 100644 index 0000000..b0d5462 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/bio.c @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "bio.h" +#include "opj_malloc.h" + +/** @defgroup BIO BIO - Individual bit input-output stream */ +/*@{*/ + +/** @name Local static functions */ +/*@{*/ + +/** +Write a bit +@param bio BIO handle +@param b Bit to write (0 or 1) +*/ +static void bio_putbit(opj_bio_t *bio, OPJ_UINT32 b); +/** +Read a bit +@param bio BIO handle +@return Returns the read bit +*/ +static OPJ_UINT32 bio_getbit(opj_bio_t *bio); +/** +Write a byte +@param bio BIO handle +@return Returns 0 if successful, returns 1 otherwise +*/ +static bool bio_byteout(opj_bio_t *bio); +/** +Read a byte +@param bio BIO handle +@return Returns 0 if successful, returns 1 otherwise +*/ +static bool bio_bytein(opj_bio_t *bio); + +/*@}*/ + +/*@}*/ + +/* +========================================================== + local functions +========================================================== +*/ + +static bool bio_byteout(opj_bio_t *bio) { + bio->buf = (bio->buf << 8) & 0xffff; + bio->ct = bio->buf == 0xff00 ? 7 : 8; + if (bio->bp >= bio->end) { + return true; + } + *bio->bp++ = bio->buf >> 8; + return false; +} + +static bool bio_bytein(opj_bio_t *bio) { + bio->buf = (bio->buf << 8) & 0xffff; + bio->ct = bio->buf == 0xff00 ? 7 : 8; + if (bio->bp >= bio->end) { + return true; + } + bio->buf |= *bio->bp++; + return false; +} + +static void bio_putbit(opj_bio_t *bio, OPJ_UINT32 b) { + if (bio->ct == 0) { + bio_byteout(bio); + } + bio->ct--; + bio->buf |= b << bio->ct; +} + +static OPJ_UINT32 bio_getbit(opj_bio_t *bio) { + if (bio->ct == 0) { + bio_bytein(bio); + } + bio->ct--; + return (bio->buf >> bio->ct) & 1; +} + +/* +========================================================== + Bit Input/Output interface +========================================================== +*/ + +opj_bio_t* bio_create(void) { + opj_bio_t *bio = (opj_bio_t*)opj_malloc(sizeof(opj_bio_t)); + return bio; +} + +void bio_destroy(opj_bio_t *bio) { + if(bio) { + opj_free(bio); + } +} + +OPJ_UINT32 bio_numbytes(opj_bio_t *bio) { + return (bio->bp - bio->start); +} + +void bio_init_enc(opj_bio_t *bio, OPJ_BYTE *bp, OPJ_UINT32 len) { + bio->start = bp; + bio->end = bp + len; + bio->bp = bp; + bio->buf = 0; + bio->ct = 8; +} + +void bio_init_dec(opj_bio_t *bio, OPJ_BYTE *bp, OPJ_UINT32 len) { + bio->start = bp; + bio->end = bp + len; + bio->bp = bp; + bio->buf = 0; + bio->ct = 0; +} + +void bio_write(opj_bio_t *bio, OPJ_UINT32 v, OPJ_UINT32 n) { + OPJ_UINT32 i; + for (i = n - 1; i != -1 ; --i) { + bio_putbit(bio, (v >> i) & 1); + } +} + +OPJ_UINT32 bio_read(opj_bio_t *bio, OPJ_UINT32 n) { + OPJ_UINT32 i, v; + v = 0; + for (i = n - 1; i != -1 ; --i) { + v += bio_getbit(bio) << i; + } + return v; +} + +bool bio_flush(opj_bio_t *bio) { + bio->ct = 0; + if (bio_byteout(bio)) { + return true; + } + if (bio->ct == 7) { + bio->ct = 0; + if (bio_byteout(bio)) { + return true; + } + } + return false; +} + +bool bio_inalign(opj_bio_t *bio) { + bio->ct = 0; + if ((bio->buf & 0xff) == 0xff) { + if (bio_bytein(bio)) { + return true; + } + bio->ct = 0; + } + return false; +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/bio.h b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/bio.h new file mode 100644 index 0000000..ecb873f --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/bio.h @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __BIO_H +#define __BIO_H +/** +@file bio.h +@brief Implementation of an individual bit input-output (BIO) + +The functions in BIO.C have for goal to realize an individual bit input - output. +*/ +#include "openjpeg.h" +/** @defgroup BIO BIO - Individual bit input-output stream */ +/*@{*/ + +/** +Individual bit input-output stream (BIO) +*/ +typedef struct opj_bio { + /** pointer to the start of the buffer */ + OPJ_BYTE *start; + /** pointer to the end of the buffer */ + OPJ_BYTE *end; + /** pointer to the present position in the buffer */ + OPJ_BYTE *bp; + /** temporary place where each byte is read or written */ + OPJ_UINT32 buf; + /** coder : number of bits free to write. decoder : number of bits read */ + OPJ_UINT32 ct; +} opj_bio_t; + +/** @name Exported functions */ +/*@{*/ +/* ----------------------------------------------------------------------- */ +/** +Create a new BIO handle +@return Returns a new BIO handle if successful, returns NULL otherwise +*/ +opj_bio_t* bio_create(void); +/** +Destroy a previously created BIO handle +@param bio BIO handle to destroy +*/ +void bio_destroy(opj_bio_t *bio); +/** +Number of bytes written. +@param bio BIO handle +@return Returns the number of bytes written +*/ +OPJ_UINT32 bio_numbytes(opj_bio_t *bio); +/** +Init encoder +@param bio BIO handle +@param bp Output buffer +@param len Output buffer length +*/ +void bio_init_enc(opj_bio_t *bio, OPJ_BYTE *bp, OPJ_UINT32 len); +/** +Init decoder +@param bio BIO handle +@param bp Input buffer +@param len Input buffer length +*/ +void bio_init_dec(opj_bio_t *bio, OPJ_BYTE *bp, OPJ_UINT32 len); +/** +Write bits +@param bio BIO handle +@param v Value of bits +@param n Number of bits to write +*/ +void bio_write(opj_bio_t *bio, OPJ_UINT32 v, OPJ_UINT32 n); +/** +Read bits +@param bio BIO handle +@param n Number of bits to read +@return Returns the corresponding read number +*/ +OPJ_UINT32 bio_read(opj_bio_t *bio, OPJ_UINT32 n); +/** +Flush bits +@param bio BIO handle +@return Returns 1 if successful, returns 0 otherwise +*/ +bool bio_flush(opj_bio_t *bio); +/** +Passes the ending bits (coming from flushing) +@param bio BIO handle +@return Returns 1 if successful, returns 0 otherwise +*/ +bool bio_inalign(opj_bio_t *bio); +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __BIO_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/cio.c b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/cio.c new file mode 100644 index 0000000..1d59312 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/cio.c @@ -0,0 +1,825 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "cio.h" +#include "opj_includes.h" +#include "opj_malloc.h" +#include "event.h" + +/* ----------------------------------------------------------------------- */ + + +/** + * Write some bytes to the given data buffer, this function is used in Big Endian cpus. + * @param p_buffer pointer the data buffer to write data to. + * @param p_value the value to write + * @param p_nb_bytes the number of bytes to write +*/ +void opj_write_bytes_BE (OPJ_BYTE * p_buffer, OPJ_UINT32 p_value, OPJ_UINT32 p_nb_bytes) +{ + const OPJ_BYTE * l_data_ptr = ((const OPJ_BYTE *) &p_value) + p_nb_bytes; + assert(p_nb_bytes > 0 && p_nb_bytes <= sizeof(OPJ_UINT32)); + memcpy(p_buffer,l_data_ptr,p_nb_bytes); +} + +/** + * Write some bytes to the given data buffer, this function is used in Little Endian cpus. + * @param p_buffer pointer the data buffer to write data to. + * @param p_value the value to write + * @param p_nb_bytes the number of bytes to write + * @return the number of bytes written or -1 if an error occured +*/ +void opj_write_bytes_LE (OPJ_BYTE * p_buffer, OPJ_UINT32 p_value, OPJ_UINT32 p_nb_bytes) +{ + const OPJ_BYTE * l_data_ptr = ((const OPJ_BYTE *) &p_value) + p_nb_bytes - 1; + OPJ_UINT32 i; + + assert(p_nb_bytes > 0 && p_nb_bytes <= sizeof(OPJ_UINT32)); + for + (i=0;i 0 && p_nb_bytes <= sizeof(OPJ_UINT32)); + *p_value = 0; + memcpy(l_data_ptr+4-p_nb_bytes,p_buffer,p_nb_bytes); +} + +/** + * Reads some bytes from the given data buffer, this function is used in Little Endian cpus. + * @param p_buffer pointer the data buffer to read data from. + * @param p_value pointer to the value that will store the data. + * @param p_nb_bytes the nb bytes to read. + * @return the number of bytes read or -1 if an error occured. + */ +void opj_read_bytes_LE(const OPJ_BYTE * p_buffer, OPJ_UINT32 * p_value, OPJ_UINT32 p_nb_bytes) +{ + OPJ_BYTE * l_data_ptr = ((OPJ_BYTE *) p_value) + p_nb_bytes-1; + OPJ_UINT32 i; + + assert(p_nb_bytes > 0 && p_nb_bytes <= sizeof(OPJ_UINT32)); + *p_value = 0; + for + (i=0;im_buffer_size = p_size; + l_stream->m_stored_data = (OPJ_BYTE *) opj_malloc(p_size); + if + (! l_stream->m_stored_data) + { + opj_free(l_stream); + return 00; + } + l_stream->m_current_data = l_stream->m_stored_data; + if + (l_is_input) + { + l_stream->m_status |= opj_stream_e_input; + l_stream->m_opj_skip = opj_stream_read_skip; + l_stream->m_opj_seek = opj_stream_read_seek; + } + else + { + l_stream->m_status |= opj_stream_e_output; + l_stream->m_opj_skip = opj_stream_write_skip; + l_stream->m_opj_seek = opj_stream_write_seek; + } + l_stream->m_read_fn = opj_stream_default_read; + l_stream->m_write_fn = opj_stream_default_write; + l_stream->m_skip_fn = opj_stream_default_skip; + l_stream->m_seek_fn = opj_stream_default_seek; + + return (opj_stream_t *) l_stream; +} + +/** + * Creates an abstract stream. This function does nothing except allocating memory and initializing the abstract stream. + * @return a stream object. +*/ +opj_stream_t* OPJ_CALLCONV opj_stream_default_create(bool l_is_input) +{ + return opj_stream_create(J2K_STREAM_CHUNK_SIZE,l_is_input); +} + +/** + * Destroys a stream created by opj_create_stream. This function does NOT close the abstract stream. If needed the user must + * close its own implementation of the stream. + */ +OPJ_API void OPJ_CALLCONV opj_stream_destroy(opj_stream_t* p_stream) +{ + opj_stream_private_t* l_stream = (opj_stream_private_t*) p_stream; + if + (l_stream) + { + opj_free(l_stream->m_stored_data); + l_stream->m_stored_data = 00; + opj_free(l_stream); + } + +} + +/** + * Sets the given function to be used as a read function. + * @param p_stream the stream to modify + * @param p_function the function to use a read function. +*/ +OPJ_API void OPJ_CALLCONV opj_stream_set_read_function(opj_stream_t* p_stream, opj_stream_read_fn p_function) +{ + opj_stream_private_t* l_stream = (opj_stream_private_t*) p_stream; + if + ((!l_stream) || (! (l_stream->m_status & opj_stream_e_input))) + { + return; + } + l_stream->m_read_fn = p_function; +} + +OPJ_API void OPJ_CALLCONV opj_stream_set_seek_function(opj_stream_t* p_stream, opj_stream_seek_fn p_function) +{ + opj_stream_private_t* l_stream = (opj_stream_private_t*) p_stream; + if + (!l_stream) + { + return; + } + l_stream->m_seek_fn = p_function; +} + +/** + * Sets the given function to be used as a write function. + * @param p_stream the stream to modify + * @param p_function the function to use a write function. +*/ +OPJ_API void OPJ_CALLCONV opj_stream_set_write_function(opj_stream_t* p_stream, opj_stream_write_fn p_function) +{ + opj_stream_private_t* l_stream = (opj_stream_private_t*) p_stream; + if + ((!l_stream )|| (! (l_stream->m_status & opj_stream_e_output))) + { + return; + } + l_stream->m_write_fn = p_function; +} + +/** + * Sets the given function to be used as a skip function. + * @param p_stream the stream to modify + * @param p_function the function to use a skip function. +*/ +OPJ_API void OPJ_CALLCONV opj_stream_set_skip_function(opj_stream_t* p_stream, opj_stream_skip_fn p_function) +{ + opj_stream_private_t* l_stream = (opj_stream_private_t*) p_stream; + if + (! l_stream) + { + return; + } + l_stream->m_skip_fn = p_function; +} + +/** + * Sets the given data to be used as a user data for the stream. + * @param p_stream the stream to modify + * @param p_data the data to set. +*/ +OPJ_API void OPJ_CALLCONV opj_stream_set_user_data(opj_stream_t* p_stream, void * p_data) +{ + opj_stream_private_t* l_stream = (opj_stream_private_t*) p_stream; + l_stream->m_user_data = p_data; +} + +/** + * Reads some bytes from the stream. + * @param p_stream the stream to read data from. + * @param p_buffer pointer to the data buffer that will receive the data. + * @param p_size number of bytes to read. + * @param p_event_mgr the user event manager to be notified of special events. + * @return the number of bytes read, or -1 if an error occured or if the stream is at the end. + */ +OPJ_UINT32 opj_stream_read_data (opj_stream_private_t * p_stream,OPJ_BYTE * p_buffer, OPJ_UINT32 p_size, opj_event_mgr_t * p_event_mgr) +{ + OPJ_UINT32 l_read_nb_bytes = 0; + if + (p_stream->m_bytes_in_buffer >= p_size) + { + memcpy(p_buffer,p_stream->m_current_data,p_size); + p_stream->m_current_data += p_size; + p_stream->m_bytes_in_buffer -= p_size; + l_read_nb_bytes += p_size; + p_stream->m_byte_offset += p_size; + return l_read_nb_bytes; + } + + // we are now in the case when the remaining data if not sufficient + if + (p_stream->m_status & opj_stream_e_end) + { + l_read_nb_bytes += p_stream->m_bytes_in_buffer; + memcpy(p_buffer,p_stream->m_current_data,p_stream->m_bytes_in_buffer); + p_stream->m_current_data += p_stream->m_bytes_in_buffer; + p_stream->m_byte_offset += p_stream->m_bytes_in_buffer; + p_stream->m_bytes_in_buffer = 0; + return l_read_nb_bytes ? l_read_nb_bytes : -1; + } + + // the flag is not set, we copy data and then do an actual read on the stream + if + (p_stream->m_bytes_in_buffer) + { + l_read_nb_bytes += p_stream->m_bytes_in_buffer; + memcpy(p_buffer,p_stream->m_current_data,p_stream->m_bytes_in_buffer); + p_stream->m_current_data = p_stream->m_stored_data; + p_buffer += p_stream->m_bytes_in_buffer; + p_size -= p_stream->m_bytes_in_buffer; + p_stream->m_byte_offset += p_stream->m_bytes_in_buffer; + p_stream->m_bytes_in_buffer = 0; + } + else + { + /* case where we are already at the end of the buffer + so reset the m_current_data to point to the start of the + stored buffer to get ready to read from disk*/ + p_stream->m_current_data = p_stream->m_stored_data; + } + + + while + (true) + { + // we should read less than a chunk -> read a chunk + if + (p_size < p_stream->m_buffer_size) + { + // we should do an actual read on the media + p_stream->m_bytes_in_buffer = p_stream->m_read_fn(p_stream->m_stored_data,p_stream->m_buffer_size,p_stream->m_user_data); + if + (p_stream->m_bytes_in_buffer == -1) + { + // end of stream + opj_event_msg(p_event_mgr, EVT_INFO, "Stream reached its end !\n"); + p_stream->m_bytes_in_buffer = 0; + p_stream->m_status |= opj_stream_e_end; + // end of stream + return l_read_nb_bytes ? l_read_nb_bytes : -1; + } + else if + (p_stream->m_bytes_in_buffer < p_size) + { + // not enough data + l_read_nb_bytes += p_stream->m_bytes_in_buffer; + memcpy(p_buffer,p_stream->m_current_data,p_stream->m_bytes_in_buffer); + p_stream->m_current_data = p_stream->m_stored_data; + p_buffer += p_stream->m_bytes_in_buffer; + p_size -= p_stream->m_bytes_in_buffer; + p_stream->m_byte_offset += p_stream->m_bytes_in_buffer; + p_stream->m_bytes_in_buffer = 0; + } + else + { + l_read_nb_bytes += p_size; + memcpy(p_buffer,p_stream->m_current_data,p_size); + p_stream->m_current_data += p_size; + p_stream->m_bytes_in_buffer -= p_size; + p_stream->m_byte_offset += p_size; + return l_read_nb_bytes; + } + } + else + { + // direct read on the dest buffer + p_stream->m_bytes_in_buffer = p_stream->m_read_fn(p_buffer,p_size,p_stream->m_user_data); + if + (p_stream->m_bytes_in_buffer == -1) + { + // end of stream + opj_event_msg(p_event_mgr, EVT_INFO, "Stream reached its end !\n"); + p_stream->m_bytes_in_buffer = 0; + p_stream->m_status |= opj_stream_e_end; + // end of stream + return l_read_nb_bytes ? l_read_nb_bytes : -1; + } + else if + (p_stream->m_bytes_in_buffer < p_size) + { + // not enough data + l_read_nb_bytes += p_stream->m_bytes_in_buffer; + p_stream->m_current_data = p_stream->m_stored_data; + p_buffer += p_stream->m_bytes_in_buffer; + p_size -= p_stream->m_bytes_in_buffer; + p_stream->m_byte_offset += p_stream->m_bytes_in_buffer; + p_stream->m_bytes_in_buffer = 0; + } + else + { + // we have read the exact size + l_read_nb_bytes += p_stream->m_bytes_in_buffer; + p_stream->m_byte_offset += p_stream->m_bytes_in_buffer; + p_stream->m_current_data = p_stream->m_stored_data; + p_stream->m_bytes_in_buffer = 0; + return l_read_nb_bytes; + } + } + } +} + +/** + * Writes some bytes from the stream. + * @param p_stream the stream to write data to. + * @param p_buffer pointer to the data buffer holds the data to be writtent. + * @param p_size number of bytes to write. + * @param p_event_mgr the user event manager to be notified of special events. + * @return the number of bytes writtent, or -1 if an error occured. + */ +OPJ_UINT32 opj_stream_write_data (opj_stream_private_t * p_stream,const OPJ_BYTE * p_buffer,OPJ_UINT32 p_size, opj_event_mgr_t * p_event_mgr) +{ + OPJ_UINT32 l_remaining_bytes = 0; + OPJ_UINT32 l_write_nb_bytes = 0; + + if + (p_stream->m_status & opj_stream_e_error) + { + return -1; + } + + while + (true) + { + l_remaining_bytes = p_stream->m_buffer_size - p_stream->m_bytes_in_buffer; + // we have more memory than required + if + (l_remaining_bytes >= p_size) + { + memcpy(p_stream->m_current_data,p_buffer,p_size); + p_stream->m_current_data += p_size; + p_stream->m_bytes_in_buffer += p_size; + l_write_nb_bytes += p_size; + p_stream->m_byte_offset += p_size; + return l_write_nb_bytes; + } + + // we copy data and then do an actual read on the stream + if + (l_remaining_bytes) + { + l_write_nb_bytes += l_remaining_bytes; + memcpy(p_stream->m_current_data,p_buffer,l_remaining_bytes); + p_stream->m_current_data = p_stream->m_stored_data; + p_buffer += l_remaining_bytes; + p_size -= l_remaining_bytes; + p_stream->m_bytes_in_buffer += l_remaining_bytes; + p_stream->m_byte_offset += l_remaining_bytes; + } + if + (! opj_stream_flush(p_stream, p_event_mgr)) + { + return -1; + } + } + +} + +/** + * Writes the content of the stream buffer to the stream. + * @param p_stream the stream to write data to. + * @param p_event_mgr the user event manager to be notified of special events. + * @return the number of bytes written, or -1 if an error occured. + */ +bool opj_stream_flush (opj_stream_private_t * p_stream, opj_event_mgr_t * p_event_mgr) +{ + // the number of bytes written on the media. + OPJ_UINT32 l_current_write_nb_bytes = 0; + p_stream->m_current_data = p_stream->m_stored_data; + + while + (p_stream->m_bytes_in_buffer) + { + // we should do an actual write on the media + l_current_write_nb_bytes = p_stream->m_write_fn(p_stream->m_current_data,p_stream->m_bytes_in_buffer,p_stream->m_user_data); + if + (l_current_write_nb_bytes == -1) + { + p_stream->m_status |= opj_stream_e_error; + opj_event_msg(p_event_mgr, EVT_INFO, "Error on writting stream!\n"); + return false; + } + p_stream->m_current_data += l_current_write_nb_bytes; + p_stream->m_bytes_in_buffer -= l_current_write_nb_bytes; + } + p_stream->m_current_data = p_stream->m_stored_data; + return true; +} + +/** + * Skips a number of bytes from the stream. + * @param p_stream the stream to skip data from. + * @param p_size the number of bytes to skip. + * @param p_event_mgr the user event manager to be notified of special events. + * @return the number of bytes skipped, or -1 if an error occured. + */ +OPJ_SIZE_T opj_stream_read_skip (opj_stream_private_t * p_stream, OPJ_SIZE_T p_size, opj_event_mgr_t * p_event_mgr) +{ + OPJ_SIZE_T l_skip_nb_bytes = 0; + OPJ_SIZE_T l_current_skip_nb_bytes = 0; + + if + (p_stream->m_bytes_in_buffer >= p_size) + { + p_stream->m_current_data += p_size; + p_stream->m_bytes_in_buffer -= p_size; + l_skip_nb_bytes += p_size; + p_stream->m_byte_offset += l_skip_nb_bytes; + return l_skip_nb_bytes; + } + + // we are now in the case when the remaining data if not sufficient + if + (p_stream->m_status & opj_stream_e_end) + { + l_skip_nb_bytes += p_stream->m_bytes_in_buffer; + p_stream->m_current_data += p_stream->m_bytes_in_buffer; + p_stream->m_bytes_in_buffer = 0; + p_stream->m_byte_offset += l_skip_nb_bytes; + return l_skip_nb_bytes ? l_skip_nb_bytes : (OPJ_SIZE_T) -1; + } + + // the flag is not set, we copy data and then do an actual skip on the stream + if + (p_stream->m_bytes_in_buffer) + { + l_skip_nb_bytes += p_stream->m_bytes_in_buffer; + p_stream->m_current_data = p_stream->m_stored_data; + p_size -= p_stream->m_bytes_in_buffer; + p_stream->m_bytes_in_buffer = 0; + } + + while + (p_size > 0) + { + // we should do an actual skip on the media + l_current_skip_nb_bytes = p_stream->m_skip_fn(p_size, p_stream->m_user_data); + if + (l_current_skip_nb_bytes == (OPJ_SIZE_T) -1) + { + opj_event_msg(p_event_mgr, EVT_INFO, "Stream reached its end !\n"); + p_stream->m_status |= opj_stream_e_end; + p_stream->m_byte_offset += l_skip_nb_bytes; + // end if stream + return l_skip_nb_bytes ? l_skip_nb_bytes : (OPJ_SIZE_T) -1; + } + p_size -= l_current_skip_nb_bytes; + l_skip_nb_bytes += l_current_skip_nb_bytes; + } + p_stream->m_byte_offset += l_skip_nb_bytes; + return l_skip_nb_bytes; +} + +/** + * Skips a number of bytes from the stream. + * @param p_stream the stream to skip data from. + * @param p_size the number of bytes to skip. + * @param p_event_mgr the user event manager to be notified of special events. + * @return the number of bytes skipped, or -1 if an error occured. + */ +OPJ_SIZE_T opj_stream_write_skip (opj_stream_private_t * p_stream, OPJ_SIZE_T p_size, opj_event_mgr_t * p_event_mgr) +{ + bool l_is_written = 0; + OPJ_SIZE_T l_current_skip_nb_bytes = 0; + OPJ_SIZE_T l_skip_nb_bytes = 0; + + if + (p_stream->m_status & opj_stream_e_error) + { + return (OPJ_SIZE_T) -1; + } + + // we should flush data + l_is_written = opj_stream_flush (p_stream, p_event_mgr); + if + (! l_is_written) + { + p_stream->m_status |= opj_stream_e_error; + p_stream->m_bytes_in_buffer = 0; + p_stream->m_current_data = p_stream->m_current_data; + return (OPJ_SIZE_T) -1; + } + // then skip + + while + (p_size > 0) + { + // we should do an actual skip on the media + l_current_skip_nb_bytes = p_stream->m_skip_fn(p_size, p_stream->m_user_data); + if + (l_current_skip_nb_bytes == (OPJ_SIZE_T)-1) + { + opj_event_msg(p_event_mgr, EVT_INFO, "Stream error!\n"); + p_stream->m_status |= opj_stream_e_error; + p_stream->m_byte_offset += l_skip_nb_bytes; + // end if stream + return l_skip_nb_bytes ? l_skip_nb_bytes : (OPJ_SIZE_T)-1; + } + p_size -= l_current_skip_nb_bytes; + l_skip_nb_bytes += l_current_skip_nb_bytes; + } + p_stream->m_byte_offset += l_skip_nb_bytes; + return l_skip_nb_bytes; +} + +/** + * Tells the byte offset on the stream (similar to ftell). + * + * @param p_stream the stream to get the information from. + * + * @return the current position o fthe stream. + */ +OPJ_SIZE_T opj_stream_tell (const opj_stream_private_t * p_stream) +{ + return p_stream->m_byte_offset; +} + +/** + * Skips a number of bytes from the stream. + * @param p_stream the stream to skip data from. + * @param p_size the number of bytes to skip. + * @param p_event_mgr the user event manager to be notified of special events. + * @return the number of bytes skipped, or -1 if an error occured. + */ +OPJ_SIZE_T opj_stream_skip (opj_stream_private_t * p_stream, OPJ_SIZE_T p_size, opj_event_mgr_t * p_event_mgr) +{ + return p_stream->m_opj_skip(p_stream,p_size,p_event_mgr); +} + + +/** + * Skips a number of bytes from the stream. + * @param p_stream the stream to skip data from. + * @param p_size the number of bytes to skip. + * @param p_event_mgr the user event manager to be notified of special events. + * @return the number of bytes skipped, or -1 if an error occured. + */ +bool opj_stream_read_seek (opj_stream_private_t * p_stream, OPJ_SIZE_T p_size, opj_event_mgr_t * p_event_mgr) +{ + p_stream->m_current_data = p_stream->m_stored_data; + p_stream->m_bytes_in_buffer = 0; + if + (! p_stream->m_seek_fn(p_size,p_stream->m_user_data)) + { + p_stream->m_status |= opj_stream_e_end; + return false; + } + else + { + // reset stream status + p_stream->m_status &= (~opj_stream_e_end); + p_stream->m_byte_offset = p_size; + + } + return true; +} + +/** + * Skips a number of bytes from the stream. + * @param p_stream the stream to skip data from. + * @param p_size the number of bytes to skip. + * @param p_event_mgr the user event manager to be notified of special events. + * @return the number of bytes skipped, or -1 if an error occured. + */ +bool opj_stream_write_seek (opj_stream_private_t * p_stream, OPJ_SIZE_T p_size, opj_event_mgr_t * p_event_mgr) +{ + if + (! opj_stream_flush(p_stream,p_event_mgr)) + { + p_stream->m_status |= opj_stream_e_error; + return false; + } + + p_stream->m_current_data = p_stream->m_stored_data; + p_stream->m_bytes_in_buffer = 0; + + if + (! p_stream->m_seek_fn(p_size,p_stream->m_user_data)) + { + p_stream->m_status |= opj_stream_e_error; + return false; + } + else + { + p_stream->m_byte_offset = p_size; + } + return true; +} + + +/** + * Seeks a number of bytes from the stream. + * @param p_stream the stream to skip data from. + * @param p_size the number of bytes to skip. + * @param p_event_mgr the user event manager to be notified of special events. + * @return true if the stream is seekable. + */ +bool opj_stream_seek (opj_stream_private_t * p_stream, OPJ_SIZE_T p_size, struct opj_event_mgr * p_event_mgr) +{ + return p_stream->m_opj_seek(p_stream,p_size,p_event_mgr); +} + +/** + * Tells if the given stream is seekable. + */ +bool opj_stream_has_seek (const opj_stream_private_t * p_stream) +{ + return p_stream->m_seek_fn != opj_stream_default_seek; +} + + + + + +OPJ_UINT32 opj_stream_default_read (void * p_buffer, OPJ_UINT32 p_nb_bytes, void * p_user_data) +{ + return (OPJ_UINT32) -1; +} +OPJ_UINT32 opj_stream_default_write (void * p_buffer, OPJ_UINT32 p_nb_bytes, void * p_user_data) +{ + return (OPJ_UINT32) -1; +} +OPJ_SIZE_T opj_stream_default_skip (OPJ_SIZE_T p_nb_bytes, void * p_user_data) +{ + return (OPJ_SIZE_T) -1; +} + +bool opj_stream_default_seek (OPJ_SIZE_T p_nb_bytes, void * p_user_data) +{ + return false; +} diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/cio.h b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/cio.h new file mode 100644 index 0000000..6c37857 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/cio.h @@ -0,0 +1,358 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __CIO_H +#define __CIO_H +/** +@file cio.h +@brief Implementation of a byte input-output process (CIO) + +The functions in CIO.C have for goal to realize a byte input / output process. +*/ + +/** @defgroup CIO CIO - byte input-output stream */ +/*@{*/ + +#include "openjpeg.h" +#include "opj_configure.h" +struct opj_event_mgr; +/** @name Exported functions (see also openjpeg.h) */ +/*@{*/ +/* ----------------------------------------------------------------------- */ + +#if defined(OPJ_BIG_ENDIAN) + #if !defined(OPJ_LITTLE_ENDIAN) + #define opj_write_bytes opj_write_bytes_BE + #define opj_read_bytes opj_read_bytes_BE + #define opj_write_double opj_write_double_BE + #define opj_read_double opj_read_double_BE + #define opj_write_float opj_write_float_BE + #define opj_read_float opj_read_float_BE + #else + #error "Either BIG_ENDIAN or LITTLE_ENDIAN must be #defined, but not both." + #endif +#else + #if defined(OPJ_LITTLE_ENDIAN) + #define opj_write_bytes opj_write_bytes_LE + #define opj_read_bytes opj_read_bytes_LE + #define opj_write_double opj_write_double_LE + #define opj_read_double opj_read_double_LE + #define opj_write_float opj_write_float_LE + #define opj_read_float opj_read_float_LE + #else + #error "Either BIG_ENDIAN or LITTLE_ENDIAN must be #defined, but not none." + #endif +#endif + + + +typedef enum +{ + opj_stream_e_output = 0x1, + opj_stream_e_input = 0x2, + opj_stream_e_end = 0x4, + opj_stream_e_error = 0x8 +} +opj_stream_flag ; + +/** +Byte input-output stream. +*/ +typedef struct opj_stream_private +{ + /** + * User data, be it files, ... The actual data depends on the type of the stream. + */ + void * m_user_data; + + /** + * Pointer to actual read function (NULL at the initialization of the cio. + */ + opj_stream_read_fn m_read_fn; + + /** + * Pointer to actual write function (NULL at the initialization of the cio. + */ + opj_stream_write_fn m_write_fn; + + /** + * Pointer to actual skip function (NULL at the initialization of the cio. + * There is no seek function to prevent from back and forth slow procedures. + */ + opj_stream_skip_fn m_skip_fn; + + /** + * Pointer to actual seek function (if available). + */ + opj_stream_seek_fn m_seek_fn; + + + + + /** + * Actual data stored into the stream if readed from. Data is read by chunk of fixed size. + * you should never access this data directly. + */ + OPJ_BYTE * m_stored_data; + + /** + * Pointer to the current read data. + */ + OPJ_BYTE * m_current_data; + + OPJ_SIZE_T (* m_opj_skip)(struct opj_stream_private * ,OPJ_SIZE_T , struct opj_event_mgr *); + + bool (* m_opj_seek) (struct opj_stream_private * , OPJ_SIZE_T , struct opj_event_mgr *); + + /** + * number of bytes containing in the buffer. + */ + OPJ_UINT32 m_bytes_in_buffer; + + /** + * The number of bytes read/written. + */ + OPJ_SIZE_T m_byte_offset; + + /** + * The size of the buffer. + */ + OPJ_UINT32 m_buffer_size; + + /** + * Flags to tell the status of the stream. + */ + OPJ_UINT32 m_status; + +} +opj_stream_private_t; + + +/** + * Write some bytes to the given data buffer, this function is used in Big Endian cpus. + * @param p_buffer pointer the data buffer to write data to. + * @param p_value the value to write + * @param p_nb_bytes the number of bytes to write +*/ +void opj_write_bytes_BE (OPJ_BYTE * p_buffer, OPJ_UINT32 p_value, OPJ_UINT32 p_nb_bytes); + +/** + * Reads some bytes from the given data buffer, this function is used in Big Endian cpus. + * @param p_buffer pointer the data buffer to read data from. + * @param p_value pointer to the value that will store the data. + * @param p_nb_bytes the nb bytes to read. + * @return the number of bytes read or -1 if an error occured. + */ +void opj_read_bytes_BE(const OPJ_BYTE * p_buffer, OPJ_UINT32 * p_value, OPJ_UINT32 p_nb_bytes); + +/** + * Write some bytes to the given data buffer, this function is used in Little Endian cpus. + * @param p_buffer pointer the data buffer to write data to. + * @param p_value the value to write + * @param p_nb_bytes the number of bytes to write + * @return the number of bytes written or -1 if an error occured +*/ +void opj_write_bytes_LE (OPJ_BYTE * p_buffer, OPJ_UINT32 p_value, OPJ_UINT32 p_nb_bytes); + +/** + * Reads some bytes from the given data buffer, this function is used in Little Endian cpus. + * @param p_buffer pointer the data buffer to read data from. + * @param p_value pointer to the value that will store the data. + * @param p_nb_bytes the nb bytes to read. + * @return the number of bytes read or -1 if an error occured. + */ +void opj_read_bytes_LE(const OPJ_BYTE * p_buffer, OPJ_UINT32 * p_value, OPJ_UINT32 p_nb_bytes); + + +/** + * Write some bytes to the given data buffer, this function is used in Little Endian cpus. + * @param p_buffer pointer the data buffer to write data to. + * @param p_value the value to write + */ +void opj_write_double_LE(OPJ_BYTE * p_buffer, OPJ_FLOAT64 p_value); + +/*** + * Write some bytes to the given data buffer, this function is used in Big Endian cpus. + * @param p_buffer pointer the data buffer to write data to. + * @param p_value the value to write + */ +void opj_write_double_BE(OPJ_BYTE * p_buffer, OPJ_FLOAT64 p_value); + +/** + * Reads some bytes from the given data buffer, this function is used in Little Endian cpus. + * @param p_buffer pointer the data buffer to read data from. + * @param p_value pointer to the value that will store the data. + */ +void opj_read_double_LE(const OPJ_BYTE * p_buffer, OPJ_FLOAT64 * p_value); + +/** + * Reads some bytes from the given data buffer, this function is used in Big Endian cpus. + * @param p_buffer pointer the data buffer to read data from. + * @param p_value pointer to the value that will store the data. + */ +void opj_read_double_BE(const OPJ_BYTE * p_buffer, OPJ_FLOAT64 * p_value); + +/** + * Reads some bytes from the given data buffer, this function is used in Little Endian cpus. + * @param p_buffer pointer the data buffer to read data from. + * @param p_value pointer to the value that will store the data. + */ +void opj_read_float_LE(const OPJ_BYTE * p_buffer, OPJ_FLOAT32 * p_value); + +/** + * Reads some bytes from the given data buffer, this function is used in Big Endian cpus. + * @param p_buffer pointer the data buffer to read data from. + * @param p_value pointer to the value that will store the data. + */ +void opj_read_float_BE(const OPJ_BYTE * p_buffer, OPJ_FLOAT32 * p_value); + +/** + * Write some bytes to the given data buffer, this function is used in Little Endian cpus. + * @param p_buffer pointer the data buffer to write data to. + * @param p_value the value to write + */ +void opj_write_float_LE(OPJ_BYTE * p_buffer, OPJ_FLOAT32 p_value); + +/*** + * Write some bytes to the given data buffer, this function is used in Big Endian cpus. + * @param p_buffer pointer the data buffer to write data to. + * @param p_value the value to write + */ +void opj_write_float_BE(OPJ_BYTE * p_buffer, OPJ_FLOAT32 p_value); + +/** + * Reads some bytes from the stream. + * @param p_stream the stream to read data from. + * @param p_buffer pointer to the data buffer that will receive the data. + * @param p_size number of bytes to read. + * @param p_event_mgr the user event manager to be notified of special events. + * @return the number of bytes read, or -1 if an error occured or if the stream is at the end. + */ +OPJ_UINT32 opj_stream_read_data (opj_stream_private_t * p_stream,OPJ_BYTE * p_buffer, OPJ_UINT32 p_size, struct opj_event_mgr * p_event_mgr); + +/** + * Writes some bytes to the stream. + * @param p_stream the stream to write data to. + * @param p_buffer pointer to the data buffer holds the data to be writtent. + * @param p_size number of bytes to write. + * @param p_event_mgr the user event manager to be notified of special events. + * @return the number of bytes writtent, or -1 if an error occured. + */ +OPJ_UINT32 opj_stream_write_data (opj_stream_private_t * p_stream,const OPJ_BYTE * p_buffer, OPJ_UINT32 p_size, struct opj_event_mgr * p_event_mgr); + +/** + * Writes the content of the stream buffer to the stream. + * @param p_stream the stream to write data to. + * @param p_event_mgr the user event manager to be notified of special events. + * @return true if the data could be flushed, false else. + */ +bool opj_stream_flush (opj_stream_private_t * p_stream, struct opj_event_mgr * p_event_mgr); + +/** + * Skips a number of bytes from the stream. + * @param p_stream the stream to skip data from. + * @param p_size the number of bytes to skip. + * @param p_event_mgr the user event manager to be notified of special events. + * @return the number of bytes skipped, or -1 if an error occured. + */ +OPJ_SIZE_T opj_stream_skip (opj_stream_private_t * p_stream,OPJ_SIZE_T p_size, struct opj_event_mgr * p_event_mgr); + +/** + * Tells the byte offset on the stream (similar to ftell). + * + * @param p_stream the stream to get the information from. + * + * @return the current position o fthe stream. + */ +OPJ_SIZE_T opj_stream_tell (const opj_stream_private_t * p_stream); + +/** + * Skips a number of bytes from the stream. + * @param p_stream the stream to skip data from. + * @param p_size the number of bytes to skip. + * @param p_event_mgr the user event manager to be notified of special events. + * @return the number of bytes skipped, or -1 if an error occured. + */ +OPJ_SIZE_T opj_stream_write_skip (opj_stream_private_t * p_stream, OPJ_SIZE_T p_size, struct opj_event_mgr * p_event_mgr); + +/** + * Skips a number of bytes from the stream. + * @param p_stream the stream to skip data from. + * @param p_size the number of bytes to skip. + * @param p_event_mgr the user event manager to be notified of special events. + * @return the number of bytes skipped, or -1 if an error occured. + */ +OPJ_SIZE_T opj_stream_read_skip (opj_stream_private_t * p_stream, OPJ_SIZE_T p_size, struct opj_event_mgr * p_event_mgr); + +/** + * Skips a number of bytes from the stream. + * @param p_stream the stream to skip data from. + * @param p_size the number of bytes to skip. + * @param p_event_mgr the user event manager to be notified of special events. + * @return the number of bytes skipped, or -1 if an error occured. + */ +bool opj_stream_read_seek (opj_stream_private_t * p_stream, OPJ_SIZE_T p_size, struct opj_event_mgr * p_event_mgr); + +/** + * Skips a number of bytes from the stream. + * @param p_stream the stream to skip data from. + * @param p_size the number of bytes to skip. + * @param p_event_mgr the user event manager to be notified of special events. + * @return the number of bytes skipped, or -1 if an error occured. + */ +bool opj_stream_write_seek (opj_stream_private_t * p_stream, OPJ_SIZE_T p_size, struct opj_event_mgr * p_event_mgr); + +/** + * Seeks a number of bytes from the stream. + * @param p_stream the stream to skip data from. + * @param p_size the number of bytes to skip. + * @param p_event_mgr the user event manager to be notified of special events. + * @return true if the stream is seekable. + */ +bool opj_stream_seek (opj_stream_private_t * p_stream, OPJ_SIZE_T p_size, struct opj_event_mgr * p_event_mgr); + +/** + * Tells if the given stream is seekable. + */ +bool opj_stream_has_seek (const opj_stream_private_t * p_stream); + +OPJ_UINT32 opj_stream_default_read (void * p_buffer, OPJ_UINT32 p_nb_bytes, void * p_user_data); +OPJ_UINT32 opj_stream_default_write (void * p_buffer, OPJ_UINT32 p_nb_bytes, void * p_user_data); +OPJ_SIZE_T opj_stream_default_skip (OPJ_SIZE_T p_nb_bytes, void * p_user_data); +bool opj_stream_default_seek (OPJ_SIZE_T p_nb_bytes, void * p_user_data); + +/* ----------------------------------------------------------------------- */ +/*@}*/ + +/*@}*/ + +#endif /* __CIO_H */ diff --git a/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/dwt.c b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/dwt.c new file mode 100644 index 0000000..86d28e6 --- /dev/null +++ b/gdcm/Utilities/gdcmopenjpeg-v2/libopenjpeg/dwt.c @@ -0,0 +1,873 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2007, Jonathan Ballard + * Copyright (c) 2007, Callum Lerwick + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef __SSE__ +#include +#endif + +#include "dwt.h" +#include "j2k.h" +#include "tcd.h" +#include "fix.h" +#include "opj_malloc.h" +#include "int.h" + +/** @defgroup DWT DWT - Implementation of a discrete wavelet transform */ +/*@{*/ + +#define WS(i) v->mem[(i)*2] +#define WD(i) v->mem[(1+(i)*2)] + +/** @name Local data structures */ +/*@{*/ + +typedef struct dwt_local { + OPJ_INT32* mem; + OPJ_INT32 dn; + OPJ_INT32 sn; + OPJ_INT32 cas; +} dwt_t; + +typedef union { + OPJ_FLOAT32 f[4]; +} v4; + +typedef struct v4dwt_local { + v4* wavelet ; + OPJ_INT32 dn ; + OPJ_INT32 sn ; + OPJ_INT32 cas ; +} v4dwt_t ; + +static const OPJ_FLOAT32 dwt_alpha = 1.586134342f; // 12994 +static const OPJ_FLOAT32 dwt_beta = 0.052980118f; // 434 +static const OPJ_FLOAT32 dwt_gamma = -0.882911075f; // -7233 +static const OPJ_FLOAT32 delta = -0.443506852f; // -3633 + +static const OPJ_FLOAT32 K = 1.230174105f; // 10078 +/* FIXME: What is this constant? */ +static const OPJ_FLOAT32 c13318 = 1.625732422f; + +/*@}*/ + +/** +Virtual function type for wavelet transform in 1-D +*/ +typedef void (*DWT1DFN)(dwt_t* v); + +/** @name Local static functions */ +/*@{*/ + +/** +Forward lazy transform (horizontal) +*/ +static void dwt_deinterleave_h(OPJ_INT32 *a, OPJ_INT32 *b, OPJ_INT32 dn, OPJ_INT32 sn, OPJ_INT32 cas); +/** +Forward lazy transform (vertical) +*/ +static void dwt_deinterleave_v(OPJ_INT32 *a, OPJ_INT32 *b, OPJ_INT32 dn, OPJ_INT32 sn, OPJ_INT32 x, OPJ_INT32 cas); +/** +Inverse lazy transform (horizontal) +*/ +static void dwt_interleave_h(dwt_t* h, OPJ_INT32 *a); +/** +Inverse lazy transform (vertical) +*/ +static void dwt_interleave_v(dwt_t* v, OPJ_INT32 *a, OPJ_INT32 x); +/** +Forward 5-3 wavelet transform in 1-D +*/ +static void dwt_encode_1(OPJ_INT32 *a, OPJ_INT32 dn, OPJ_INT32 sn, OPJ_INT32 cas); +/** +Inverse 5-3 wavelet transform in 1-D +*/ +static void dwt_decode_1(dwt_t *v); +/** +Forward 9-7 wavelet transform in 1-D +*/ +static void dwt_encode_1_real(OPJ_INT32 *a, OPJ_INT32 dn, OPJ_INT32 sn, OPJ_INT32 cas); +/** +Explicit calculation of the Quantization Stepsizes +*/ +static void dwt_encode_stepsize(OPJ_INT32 stepsize, OPJ_INT32 numbps, opj_stepsize_t *bandno_stepsize); +/** +Inverse wavelet transform in 2-D. +*/ +static bool dwt_decode_tile(opj_tcd_tilecomp_t* tilec, OPJ_UINT32 i, DWT1DFN fn); + +static OPJ_UINT32 dwt_max_resolution(opj_tcd_resolution_t* restrict r, OPJ_UINT32 i); + +static bool dwt_encode_procedure(opj_tcd_tilecomp_t * tilec,void (*p_function)(OPJ_INT32 *, OPJ_INT32,OPJ_INT32,OPJ_INT32) ); +/*@}*/ + +/*@}*/ + +#define S(i) a[(i)*2] +#define D(i) a[(1+(i)*2)] +#define S_(i) ((i)<0?S(0):((i)>=sn?S(sn-1):S(i))) +#define D_(i) ((i)<0?D(0):((i)>=dn?D(dn-1):D(i))) +/* new */ +#define SS_(i) ((i)<0?S(0):((i)>=dn?S(dn-1):S(i))) +#define DD_(i) ((i)<0?D(0):((i)>=sn?D(sn-1):D(i))) + +/*

    td zlFVX*B%|3N>*3p z1xA!PXk!jFKh>-Vch(}kzr&ZRF*0lbB2=0%p-eWqSHJ?rus~1E=q@a9W~KZmn*~;e zyZ?_CP{!X|7%tqOIg6WnToxCD1b$_7)a zXI5am<*DNU9_9*bvtHN?$4T3aCd05vrUfe zHoF7R;n7LiY@Dze$9CB41TxT0kdD|apQ>oi?K?pWj|IcWEt^eX(SHxxyyG;d-Nwb( zjb`EkAJ7we-j!De74!2{H+_;8%Gfp>!h3_Jq{F4l}f z)4*X=gFl-_+k%qKk_-Pw17qn0xpk5-FvoTncnVpQX4Me`mr~W^sPawG!o^^?)iUsj z8s;{9AGtR%kcB5{>(2Ac#(x0^(pyv5&N(!j_MK=m8l(CoYGE`SCvCK6Kmtaa1EW=F z#x&Dte?>LKevVpgMtcG0;c5S)(RfduE{w*p9Y(7n3%v-^5u;U7)!$L&tJ1<1VEBY( zwAm~wUm{6(gLmg(zJ|0P*CNg^oo6;H&3MG;4;{}&ICwdijV6O;=OAM^t!C>J6==!XEsKy`}dTR_hKh)xyX z{NG{pPeB4kKLxQ|tr-hVyZ;}m!C*hN+G6>0oQD_wkFngHC4faDmN~W~mIEx9_}tP@ zdVL8tzJM047JlaQ%Q_asUy}%C17@VmWr@StyNDA9*msB%zR@jq>ZZsRuKLDFk-O@@ zQgk1I;z1`x?$Q5Bkr*eE@jFmN&)|7)K24{%31CODll%98VEyw49Qf*N{gavW5H%}4 z94FmB{|yodl{$pV63wVLL*-|xw#5i7p@-`uF*2B6g6yJ8kR7-Lq1%}|kh#4}C?X!k zj@9A{L?AgrqlLoZS5SzH2qoJzqt#RrAAzC% z(1luUx^~66w?lJI_1j{m`rQB)Zv71=>4=zwU6KeShe?)`{;8lCF-efBdZ5a;+-4G1 z+Y_}g367ICNpFyVN!G(8XKTh;nz6#PN;+D=xi10OtkN&)yg$ypA>I%9^~Ea9w_0OW z*7e0IEgYheCwvzD>iKI}Z^wf;*ymAPMl7JXKO1ITBVb_xu?P7!eKotf3a?;R<^~(L zmh)s66X%eP27;V#t%el3TJx=;nxj!ehU8nlGaw3Bm<-2Bn=At)V6rn{vI{iheA8Yk zs=r8W`&72@1EExy5=7JF|Z^~9982yo%+euGUI63@+S z{w|OlHo2J$Pz;I@n{1-0QdIeFw%LT$PC_kgg5#uZG6f`HlMrlji)L&!Z88S9$Lisf691xJAR+xSrr$)8CPN8HE{u@mlcwK9lBQt^ zNmheoc;|0$`n?gSvx%)h;!bBH%{}Db(?AcN#BtJ|tOW^p@>Y0qm+8g;>Oj2?g*U8) zchOWs+(@IlsF*0Fj=IranG+;_M@>(45B>)farq$aK=o(TuY#m0fM_O@} z(`mjkpFPy|5b1h4u%IiBlh(BvB%tf<(DiXs*A|lfDa{#lk6V3KJOUYNC7GYnpb#l# zss>Y}vfGU8w$qa&<{4Z}949Si2N!cE#C+Nmb1CXTeHkxSpzuDYg`YMBk}$z73Ld5( znVuUkucyx>z^7SH>s5$Gjv+2gc+dG0fxKX&mDbIE=af81YMO>Po4{YRf%9gDV#1t5 zFwbk@7fC$kdDl&Wp{^|Gk*D{vlu6KQ6Xl{k@O9d`;|N9$g8_oiF+YD{%= z%(<=kFm~ulClQfV6A(#BK;$YX5s^m|5b2zN$kk3F-T9D_fQUN*k!zepC`~7}i4sM` zN`A7-jPZ?5dVP;bPfA2D)Yt_d%{6IW>!dk=(PSOlgt*QLF*p|DdMAWxLExqf@9;MO z0v+eA-w~HLfdo3v1BlCaHREkFE;m!PEiSi2oo~f?_-#bqJ}dIJM8)O1Xg$bUX=bn& z!+p`eRF+&Ex3#u8DN*<(rbMBekkTzqN)&^MDN+0;q;#v35(Q#nN)*HiDc$CzMA4X- z5=FA0#L~YKYpv~0dK8U`=}{!x=&=ZmL-TgfL=?UEJEG`LkU$h&fhhXS457PFhunD& zHQ6HRKAeX?Lu~vncbxe>fzN3wg*(n1+c9naiqiD`APvK997?HsxnQ2#40 zp5?{!1ZcD0i#Yd6didvvI9TuMH9YPC&9AKFpS%7%1{SZ+i)CVVPsY>>2r;*mRDs7X3ozc^MGC zPI?5$otfX60r3e31A2vkIy?0EuTN%hifrxtSJ6@IDzc1{fsPR@U@Tq*3%Ci#NxSI{ zkbs*u!A)Is@fhlxsDqaOj-{8T;M{YY-w zM?gLFa4G?DP|Hp4p)K6Q=BC~@H+9va!25vk_0}Uma8tU?O$_Km0^+qHtK)GL@!5+V@Qt*5s03^vUNBn#m68BPvSUfPwoc^cycQ|*-tn6n9e+aYS`j) zUVOoeFM07b3cF9gi8}ul=iULjx1Wv`IlO9veq?*)F!Vh&57fPRo%ss?J-DwJ9)Nfd zZ@h&2;rM=f@q<5Y9XgEZ6$|b`f*_i{wq7_4{Q!F5fjYvQSsl-t*qqg$Jo+Obe7f#E zS`YV$#9cz`4Qby*E?$&c*|_Xp=&79P?H1!xJ~OC5!ofHQ&#KFFe1VpgRT3?*i%K!a{LPFgp7YLg;x zU=KX)V(Qi#b)epd7kzor4~2K69v%*zSJ88bJG1B|)16t<3P$O^T%FoRqHQPaQ52-f z*(W1%=#&HbMn#%QLp487r(3oCLDq&xL&o>G|HnIVsI|4mujY?tkON47{YUd#YyW^T zy<;d;c$l(*(PmjP>Odf{Di#a|8Eg=$*b_>Fao`&r5veFh!?TU^%Lx0-{IQJlF#rbg z5EKpph6Iu3ke?PAjWnTvURJ`*mJKu#d# z=nYKoNbz8I9R(2g2aL2ct9;yeTgPO^@Dk>DyZz(@80j8AD`_OGsu? zG?}r4IZ2Sor;{=wGmgjdn_rKz2BZ2^E^s)V6qhsW@(JZWup790ze+X2JxT#-AXL z1FcQtPc&g#TgI1*<2HZm_$lJJ&L13KERI`O1jiTZ6M(&w zMFX5n0QT+^4R8tp*gHlvzyboWhkP`^LISV{b2PxI1Yi%-Xn@lI;24tC`~~DEKOxS` z-~&ektPF6DY6T+=EnZF*rWS+G#0hhu@6zARqWeG zyNJpPz8zjY6Q8WaS0QQGC-)YR;fXCwD7PC7v7J? z1SYFSQ>@7rqBgO~f~jV#oPn?R&BFIAZBFV5bM;VQ*gsiNE8;`R@-j43;ghjbn`w6d zeCgE|Rrnleb#cey#Q}U+-`ahaM-_;#vWSNS@mzdo7@Hzu_gkrtEUy%`qinTIs`D*G zd@enq>>Dho_3@!(`9d^s+1Wm$4%yeCEk<^}b1r1R!XkcYeBw;dYb~g&<3q{vmDFJ0 z4t$7d`x`Cf>*6Cb7F#W-&GDgRc~e3bw^_*B62jbJ!E8?mbGHSvGggQ`EQ`Qq(+8L# zSAnmv&c}z7g|CaSM=EOO*=m?>b1Z}^hOm|p+z5_BS)RcVA~g)*TMOZ9G*|eS$M%XZ z(STlIi^n|E;7bOX^3@GWfE_?XRU3T-Tu8!_D&w7&VPf~lko=SnxvW9f+Sh9B9jA4G z)!HvZTIz3f7(!MC;`^VC_=;wAE&Hy0?&5~!P5!!u8Umy5awA6+P=ZsA$&iA9rdDa) zQLO%4X&pXjjuseSvsettkZK(au=(oH489X}HZNr_p!t@~*nKq`TK*gxgYX@7_p6fF z69n2Sk|t?1UVNoWK}c~PZE1^PK~iPq3sq{RK1P-kk)(B zuONy|o}&bpmH(g~TP{2GVSD$cYTTGzc`0|&%sqQun#3@8WQ529vMg({yAqS$oi)1^ zHA!W}j}pZD3gT%N@t#iNlxAhQdjjIUIq}uxBJMX=XP0{@C+hO@(w!yFGkK}#_`Lr_nNm`4eALuMO2yAh;$ zLW)tmlnqPu;ZD^%nCiX+3`TO*1q%u?sIE*9#7_{!^DW|Iox}?n@zDv0kBcSF$e$?4 zPZ8uxE%L=q@)UNmT$q6TBu*Z&OZ^_P%ZSew#H$4HN{e`flXwv$J}m+9=?P?C0I$2? z^;5Xl<@q4bJJTFZqR%$ldQCe^rcA0jAyq&~<+r4&)+G9VeI$tzmMkw!AlD*ITE5~; zX>DgH-Cf#3NsT^jPmuw~wFvT!7WpNlG?I@C$p_s=mh0mZX4uOGcF@9ZBW&~w%4fir z<<_{^veLoLH2wp1)UTG1$oDt;Xu_hJD@}&s~UKN+%&4S=2i{K4JP~>Ep za`JTv2;RgAMs+w1*bP zVK#N5%d@{)xKA@7c)K-Sk(K8mLjxQ3`ShYlR-V(Oc5L<#nR1}+1x=b;-_l6i!kE-$ z@YxCD&(*XNLp{zU$Ri|e8at~RSKTF{K&oznd z*TIri3QtzFa|b0G`3FnY@0c|slSKBBepx=4fa;+mP*pnXe7ezzm+~**!UyA@6OcQM zt+oQogKXQJK&>r!evNHuUM(&Nnh#%Zj8+ zxZxS8VQDs9$kQ>hTlE^*`6knzP} zH%!Pl6f*Mc~HzI_Dsdj$b2vA zr8Tj8QMZY`s3TiWf77L3_w&^C>iOzL+KuXF^$qoN^%wPG?T)Owvfj?xm-T+uM_Jcr z@63KH`-AKQ+5aB;&WL>@LRUjhS9%{+(>;Ynt-+2}DVtNaq-;%jJmra$uT#ED`99@5 zb(OjXMAxYog7~HC73$UMM)i92Ms*XIY*DwVx2ZeSJJoyC`_*0QZuMdH5p|FHxcY?p zBt&>i{g=8|-49W|g)pnNHQGhm#o7k#ZtWiJW$ho@XWD-4QGKtzU%w^mj;x&!_5Q5g zLfj7^@cyg=Szl&-oplhR-;jM%_Ll5z*|%lyfExE^KajmE`;F{3q0rv!ce3|EtxurX z!R+s{Hx9jT=mSHa8T#*`Zw>p`uxCcRKH`lL{~Ynwh`l4;9zklqKjMQCACCBF#K$8( z8S&|e{~Phyhyx?O81dDJZ$^AO;`|4!KtxKMaU*{j&K3;4ykL6du97~{%Kl>K*F0{C0+GO7O z$6ye!^hY7+l2@~1`wxQ=Tg!K1FtoY6^N+!ZZRI;N7}{9g`Nv>t7qLp*CIqi9Vq_*6 zx*a=eY_4ki8dmbdPx*m?aM59;2kC)4rjd7tiGBx?KeKH4>%|Je;rHDvA)(V}4s7p8zPI>Gq> z(;fv^D5VuLxVlCHVSj6nk)#{QOSV4?P8gq>Ud4Z1rK8B71t%OpEq4Va3F{J$KMPJc zff`>uT9UTXXCZ8V7MySdH7$n@OX;nC+aJNfqz1)n19r$N&`SyyU_U3Z!Fq+Y!TKD& z!FrW#gY`Kj3l=prFQ~~KS=-pCtGz+ipbb!J8yY2Ju>?Y;EvI+TmQVq;qq$a{)XS+zi$Q_xpz}#84rhR0MWK3=!oilE% zWYl6NV4U0_8FQu4l2KWQ|BG@ZW6~5AU`)>{m=C&c)b=^{pLxL@2M>RI`GM;1 zFWY@~+TQdBe>W$`2Hw?tpB=_a&e-$vD;M@K9(rf5+CNQiOMirT!8ju5nyjE(%7d=m z7IaH%7MO%-vr0b{Skd0lzM!2=&;8BKEkU+vAK&6Vyyx)hA3!WviN4g2ozuC9FDmnX9pY-6)$*Qvc*i-x z=hDN;iCEJXv}o>_yGYwUab?ewE`F(t`_1n^Pv4y!P3%J6(87GSa!%_NAOBeQl`?J3 zwRhfJrKIO}O-gZd7q*dncl*6(25I@vi^=HTxe+KRY>^Hj*hb)~~GTGx4g@cfL6Gy}y6*LHe%bNW$lc zBc^%UGx@ijIQ8>0<_zC+>rG>?%1(cX!svI+P|d!}QV`DuoBzD$^}F7^_mse)XU|Ii zW@&m_pQOwSxf>f6F_IJ3pSq>!)C+&^-R`a!abw4x^f&q^MY72stY-v6nWq&ETKDFK z121t6Tzl4Od(wjgk|GEhajC{gUcRB>aecC{>F%FCT)*((gCD1NBuBC-(A3hlf{`58 zdFv&GFO(mUuKD;a=5hUcW>4-~Z#G^v{k-O7R++ z7ch#yeEQmw2RncM+R|$lF6=er{g2aAGm@g{Z*LE@1sTa{+NKM$bGyuV<-vx_AG@vB z^XWJI?l5)CJ<{YUo9hNlI&k7^D=(XK?RRaL&HVpsllv^bC*O>YhMLo>{Mc#{b0l#q ztdpWjQmB~CZ9|`6!XGNYggpCMY>}*H$UR50U3{?sp1XX-d~5ICw`h(gg+3jGpL&2} z(`alup2uJTmrD!g=6=tgaM*m>(f$#@mND2vsSMKLa6Dy}Qc0zREdqiGW8 z#s@tm6QC~uv>yZY5>YI8=3+(FMU#Eg2m1-`GXW=O!3V<_)p)Q=vjE$rD<*uP$zXB6 zNXUw9ke#xodjaePFqbtiB5MrjWdw?6TZF8$O_Pazdvn=##B*>zQ`mbjR(*h>X5(iO z&_=_@%3w{_G^OYCxX96{B}0L_$wVEg$$3D<-KLU8e^YC9xwx4OmZnl7W)}N^_b=dO zF{_?vV)z#&M42)SC>pN(G=@^m>C6w1K6x>*10W&%}VD1_TICm;{77K#KX28V2 z790y$tXf3^=H$5QTka9czd?9Kz+=kK(c}f1vPhE`LwVeBnpspjwdka(Xx}_A3P>A) z)R!50DWnSen{#UebrvMwhB`DM7m&LFSu%wZ$to;;pFu0{j`Z+J9)N~+m!#f|T$veH zx#cDGmb@!?Dw#JLuw{TPrAS<=$*UmgG>%bHPky#AD!F^#7z2!Rfl&wysV8n3QPM-F zi#GRhwB`NZ07(6qnY+PeLLi9LE#kh|f-JS6|EcL^$wnXz|J5e9k@rcy|GhI-$H3T$&kPX`nIap9C(QkXzsv zEHt9nJRU#$0X>JHR{^@6L1WkMaiim-oH7w83wz>c7b)T@>!CFF0BTClXAsr6GVKTk z%8ScNErq6W!44J!rM;IV%_N0ZX>!lyj1@p@w->J{X=!X}Yj5?}&^@M3v@{j!;8s5C zG#r12L1_tDd0v{_vw;(u)Lc7VU{^U1pX4LhzC}R15mMp%=}@Cvsjigi$`oBWQCG@! z)iVrH@4&O@*b<+pu7&^q#0A+e)EE1Wl?mkJVW{(7wMp#e1qW+8y-QIX7^xAsj%K zG{x9#enm;D^k)~{IioGMI}~XaoHn`5zakm0VGn!3iYP?cV}8-h$tlt@0Wdm2$d7h+ zM@)*HxotaaA1%7fqKGc1M=_WNWm2RL0g#)3L2fGcKo2&-pejhFNT&+;nRSbz=&8k% zXS!P;&9Yc=`Y>@)r6KNWksHW-eNv>;1i2~gOQXrnshW~1eMaqwvWTBkq?H0^)Tjh9 z7pF>FT~$TZMZsX(EL@%AF>@)jfyKj7?xp@}_CUH6qI;^iNo`WgOF*qOMOq+W=9erg zX^WDxZBYsOkzYVeX>5;bSF6gWq)2Cq_Tv&TIZlzv5lQ7mNp=4e=?p<1nRQZ>025fp z`a9)^s!?OugB_#BnkgcfBHcr#!ebZyrT{%;!3;&?01~1i%@N@}x4t15_@DFXc|xjD zV-l!cmLdfrlIKQAp35YEmL#7&wKyB1;UmMq$*mGwvJI1wQs`N62 zL~%4Hv2r?}B-|D}d0@ftW#7eu>7 z#3a@Q1GHHg3WW$Vgtz3oz=t*t_J-;922%jSm}wDW1gUBkuS)6M1w*c&hm&5XgbJBv zq}?BXe^}rT3;bb$KP>Qv1^z$wzB|5(D*b!rCO|?UgwO&4xid)yA`C)kA$pZiBGn+F z3x<#c2!sTaP*uDrAR;1`MMXuhBBG+MWvrm9YeCnwcinY$SJuMXJMZ^7W#-H+!d~|G z{-u7%Irr)9Jag{M+?n4a@OuP)kHGH{I9vqyJ9IU?pnPs-*S^2;{#v~CnBF!WcmV(C zWylZW-$Q)Vaoqq94kEB#SQ==bTq@pDt)Il`>7~g9sRWFEV{VIMnzz(P=xJ$5Z8EZO zh2zG|Zo@{VcTCaRaGpFoB4kKvi9I;g9++zPPvy@Fu}bwGrFu{6_*83fYOKe94Rw3l;2Djtl)9=cQn_j=<28WSbu7&6=y0HXDSqD%3Wt>DbBFm%!jsdFczaQ zmR1{o-W7kzUBHBF$cw zW-k%C2U+#djURr6+mq@Qo@!@Vnq00+0F}#?Me;1zGZ^+@l#yJ8xP`x^KGk1a(~jE9 z*+&u{e{_hY40fIiJHu)ADq-X#E0D(DUe<|>45zJM-EK1eIjiJs9D5k~d0?LmvoIc6 zn4+~$h4yvOzDB5?fzD0tSj{L!=uY9zWWpLRPL!g9DMjZ)_e|kCOu)xPO(=&6n_$Am zGh78*58AK7;7A(39x@)|M;A5gD&^vIigb7>H?8}7}i>&q{9C@UDi>KYW z9P@3oe74c@K@hHjA$14>#zZYR0~TBZ3$_aNO)?0bd_mainIVF3Ep#vSf`E^Sny?%u zTn`hrr`g+t6)UW+Y7n-2+MR8YLAU{itV9qnCThW1u;6A`aHCLvwv~-#xw;*0MWP(s zsHz0G=oYA41(g^RRT&PWqd@I0sNE^lhF1e-nX2lYk*aTl>hQUsgL=#pR=eV$O?i#*>A^_S6h=CTwtB6xl$sb9y{V=mOQ<3{)wfcZhC7@I>7ih~MGv5~_b zP#;zrz;;mYQyR!<=i+IKgAO4IN&~NTauGDmjIs6e9ftg!j#$FibKgp{@K(z#du*0? zOxz9Ro|(n_Z69)Pd=}oiK(AGB#>yG*w-d4;=0@%&=7~g^S#k@vWHKx%%d$_Emh2=; zdSpF2m7Uq-j&pB1ju+ByfEt*1>+{!J%Tn3zi)xR{*1T3OVp9Yi$mhexs z$)+h{PKbe}fqfo=rtSZ`m=a49O7%;4aWKpNTzIj>`8-QLTvW?uPb0KGgHOYjXyHNR z)4?oxnB{~hqkDqmh7Z&5IO$JMmR*=v)rFfkgv^`QMViMcVcu%Ryain#KL>(fBIat~2l4Md*`z@ zQyNIib`dm9=LqY+3;eyv9(#o|g5L&@)@_|l{yD9)(fj#d_I%Yt=is6gpB>V)W&w6+ z$jFA>8QIeA=jbgZo4>$9HRvmz}YOHQN^>`-iz7(fJHm&u}*~A@? zFU`EePxcT>rZ`jUiC5ht%;acBOXgh`@)*7g#BdVxL~51=_FjlULW6L!yL9qCvZ0fB zz$km8S9da1I=%PM`$JQ-B>n;zyeCN$?+U^5-&yk6n}H0n?|yC{<_X*P5VtQ6_T@JJWm0q=4OdopTV zP(y=&lSPbUFLCtDM!5JZ=!etNWy)AIJi>h-L}tJwmnuDo@|gc_#SzO)B&QD^_WWtk zJ`m&$Wmc(PZhaAy>Cm);aNqef7~`#B3X~q{D&Eo+P{7K|y8_eYTZ$^21CaK54%Hhy z;TgpmQ~Y%2iy*?DEQ)uI!ba+RY>NH}wn~MK%!$V)v{WIkp9f`J|EpF)0iB0{_D4X! z4B7`pK<7IL;ja4PW9Lf%-gEsIaZ{j*H_fIia3!2FDm9995fx9mLNDA~ppf%u^xwJR z!651h|FKMa+>{$(TasdgVqB7HoB}_b(F+meuM-b)J%apQu*CjGM0m0F1FP59&bs)e zNjc}DUS-d0aK51ua()O>8#D@k43_GRRNCdk&P@F*FB@x-Q?U0>Z8@_`g>%b3djAyr zCi*?7n~Hu4<`Wxxj{tjpJiWwEh8CRN8_^!2hrJc8W{L(HaX=!n#DQi}dra=AD zE`c;B8J>M(dHs|!3^@LqMHSwXUbv>bVXZHKcnJqTqFo9qMF5$NH_%G~L(d@rsU(1l zLAglI%lw?8ok&it##Qa45x>HDIXJN{QjX%SCs#oPil-RGlWEu)hMg{pXDcu$l55Di zbYJmwrsBC4a4S7-@zAy`zq4U=G@MK@Z(;8*P&%O-8I7VCP+nt4p_Yd@cCO#*U^pGg zbK?2=*8jXTe$H%Kgq~cbMv~oE^z9%6J1MMZw!h=#zpZTYvnmCVoFogC_K!{m%vO&! z=pV`==s*Us>UM+Ut9&=RwA)l<@w)KKV$Ma%Qhkz@LR(fv7Oxb)tWL4)Qk|5tXv2%z zX@3;8a~njUcDfoRb{APSyUD~Z2ECXQ0n#XCbJ>4uD6PeS6?LQXxt*)WJmJ1~H&<^! zeYRA852?@gsRsoA@%MImRW}>vBr$VLGUtyVK{PN=*qjF-0@1KwPOdb^0nEx%x1qU| zAAeMm`N591uRX|?2e~bnCu|GtnPJPZu%)N8<*_JRdP-Y>!G9DIbsH)!nQ{q?605azV&>$L^Cv4735P@h+M*l4|>_O6^mjQMLMI4T>(s&0t8NU#63V~fq zFIVGVJeBuk@&nQCEu6CH(u~D*T#}-UjYo)Fi+UEZy^G% zm7~5V81^aByYB#of*&wgW$sH9_oX1q%06TQN<3PrtD5UitOT1Ta?`?DBMXhwao!@Cix4OFTQDpHOasDT7Wix znh{A(i#fM&IwN<#DzFuf{RM?BmH4I$K31<&sa{(G4398RxL(sC0v^qTM>C{HZ2)s- z_&wrF@pQwQ5oamlN5)$I=|%+KUcMB|eS8ckmtrRIl?y)R+AMOd9l&r6^MqaN1QBp; z4qTfpUBit+5qr4V(ob)XqU@6@$(GLC7R(d2r5m?pE^MiiwseoOrApd@I>&zzdpNd% zQEZz>wq$lZ%|OdqVA%7ed35Om3i8OxMQY2MqIR4GhizGwCqT5UnXv`L zYgs)!0itEa5fHCs(IXk1`TmwQM{PQ)dr@uUSU)#wS#zVg(4F0JmESU z!Yx?}OPUP3K^jv8Fch3XHZ@3__yV9dnq9cUaGGMn!4?9WwcOujPXw%JrIEja3_r;u z2(N`$I#J2x(SeC;uXeJ81TbAm3vV{f&mbK}NqEVC!PT*@$>Q z)0<+b*gz*eexq;5gL?%zzX1Z&6S0a!_Bk^sr)|-OOMqXoZL6f_&JO9+q3>!=4E& zy8v`HCizq)HPC6biAZ_*OI6;o+uFz@vXye9v;=8X+$BX7RTJ2!~qD?7Qm6WHH6xq6FV1Wyuzp`4%fM8rOGxYI9!XDXhE z*k=xJg$RUb*HMJ%4v0XA>JXya4f{43qB{Xb4(`HW?P1NmEj!xXhPXtXZgOsq1?9IM z$;0~HBxC!3472@m>>R-3s3SR9`+DY z@G}tXJW6nR2$zSI$0_sAlHNy{KkiBC=Kw2u!pLU?`#pl+s7$VbcXg;5oBsp}e}Q-( zW5Q?Af<1gB`G!&2{vz@3RnFJZy-eiBkE<3u+;rJax_JH=xt2WLz0m$w;@KC2XT>L0 zzm(k@WAVHU9!fDc()Vr33w69m`{8@t3^a>aeUG>pKgT{7-i&|oDuzQv_fz~{fn8XZ zm?yj}-+~A%%cpQ){F7XhZvzJD?_zNN6l;x9h~EgOobl1mbT3tI;WK2+dmy)-j;PSs z?B301;&uuT!0xADbrMIlM;e=Vx^j+3qf^YuvRdAUfkn?6`OMl6xV6fCa6}tNC){Os z1r%)rO*7mJ!%FyB^7`+PL*Za2SI3P7o<602WOX?6xwokrQ8v}=VDvQQk&v{$H0^sJ zc|Kt=yG^G*`!5F~lBTm9|Ctng2nEP7<_YKc6No^Lm!tJQZ`jYtG#>yM3jWQ9PxnKV^m-RP=@>`;O%>XQ-D}N9HaIN@`I9@WKFM=adgnGY$Mx`K2>wA*$vXtO$ zV}%hOAg+WTNx~};2L;8&m^t{Fn0)Q%6$&p~K7KftMD8hPB!tWeC_h;F*T*WM65h9cg2>N z5=-Jq@g)XG;+R%}UgvkbHMYcz7!t!X0p#m6%4sH%O6SxEHpQ0MK8D1-bZALpmmZ=d zCV4xPmXxTs4d)HYf%6vo`(}*l3~(IXSqVbAdYZ;F-HH#b`H;?sHW;jTSo&{V9BTRc z4KF?xKjA|g<6BC>-1*el!50+25!>~c39pJTkR`ka_FP?Ou#%KT=#@~cgtMBAlO86~ z*wZlolF#A}x-J?!hO3b@n*WjH<^rPPz zrXM+_4CT^2oAE&7$gYt|7QAOT@32yPmzA0-?Pr&oL(i`=nm$v_RI^Iw~2^7 z?(0m`+w@o9o%a|>Wt^VusC3vKi3<**+B?ED=Y3);#=oM!P;c)97) z4~Bnx#Fg^zq~9rBP`E;peQz*E27T&jQ7=3l~CDY{AMGSNa}o z7XC_s7~)yR53ICLmBNk(GXGb@`bJp9z_%dNInvXcX!5~YgzvNyWA7V zyRQuAOIqE|*X-{%^fw~P0f#}A4N{0Wzg7J9br;q}oPRNS|6%gP_S)Zs*phb+FfwLB zvLK5%$Q@)9U(sK2kn`=;Pl7GZw}dUmzarM_hXRJf7v>2czDghhhp&w|e6=v`W~QBF z+PY~Ul1H$UDFiJ|=TNMpkt~r>M3klyDJQli(P$!Sr4mt#l2=aQ6KzSy5K(KBj%hK@ znx&Z_i_ye;i3mHyz!KaYA3(HJ*sts6;W0KZS@gRH7Khml9Fic*eJJjr7+? zh70!_e=14KG~EWT(W3M|v0fy@MDdDo8nr7{1BJ_JO*)*m^f&5M0*mMWwE)lVA;P9{ za$Bjaw=#0Mo#HY%>11-V9hQCf%gZF9ZErd(_cE803D_ZC2HLri_Gh5I3-@PW3Q6l| z`fo~cg*YCYR6m^ob}6@Y9145H049hQD6;4}huj%R--*G|9vSuWgf|4fqBCBlAJ zh~u$I^`{fVF{aaj1UjARZ&bNR+Sx?g)pWWr+K!A?;wlK&&4+Whc9psyuwpmP|Ny2N3R)FZuyJeN5Fs;M z8tJUeH{OS%S-CO7>78!!Hw&d|qLzeb#AsI^u8X)w8N`MsdjQZ!Czc1OnY%e&Mt2Tsq`o+73}Jx zZ&TN>!% zf5$xG{riOwf&KezJodph?OvvM(9=eMq2OXtYMXeT6U()x9n#VY`?Xg|T76AxS_Xeq)B?IIqL;a@cw;W^Y1)`8pXwUE!Y4Sa zB|~Ik0n>REq56V{Jw7Nox3E8H*$OCWZ{aDvhV=C}7252=0YrPPpzY+*UPrV8ScUZS zpxXgurr${D0#l7b3RyIeS#&e7ik95ML8RptK*^%!p1fO0%pk=gJ-cu)(e4tohDW=b zXb1C6jR(CQP-f8{LJw3#ArOTm>MkKl3B)}_Td2}z7Y-rXKMLBmo`U;`b_i3e7;`_M zs4?U-;Tn4sB2Z&BsIj4@eWGcfVA@5p()IxfdmiV*6MXm+AD-mHQ+)U{AD-sJGkkcK z5Bo7VMXZ|GBb<((%F^=!!1XY1{h&N zg`8O7goucb&4ncO`-utm{2We);N#m zEusNNm@rq)d?vh2L~|oec$c8_q~gN)a%PS3#J@*0zz7p++n&8p=gJ^&eCe+E9FA5(KQC*}7 z|0HNVRmHzBo0L>E&9tVPC&2c4Mj8&{1%IK1d`>U>3(ezmdb42YG(m$`=Y%T7953(- zm7C-8r;*SD5K30yF@Si6DXYGJlb%36<_WLfuOR}fcVb3~y;v^VZvb-^QzJgUku9|E z0LWiPMtqMM84)I%VaUeZq6UKhNEFLy_LHQb*AFTbzYxU=;TW7(P`?stB}Y+Q6x1O? zoyk%3Vm}3?B>{Do5QvwXDJY##XA2Zw4yK@z2(^j~O~#D5LT@WlD4G++Il>yh+!lli z3%Ph5qQaFzsMP|6Hw-GMR6?CAP8(bAs8$zAWQS_cU1(iXl^&Ca--BVC)33UNS(JMn0R3@P|a1_0lPC>ON z)P)>Hujf)w9SF6Nqv$nn3aTTaF5)P9J*$H1M5s+1MXy&=P+5e!n4{(GRbs^Lx97V5^RZv|Cbt$1X<{nbu-2lg`ZZfS#wyGIPlO9^eqy$3C*_b3gCyUR` zLcHjkhj@jz2=Q`G3Gv!Z4e>&48Cu2o(?Y!VT7`I_wGQ#BN)Pc8Y7^r1k`dy?(Kf^@ zAv46&-Y&#*+&;t;+9AZV*D=IX)hWdDk`>}f=p5n^?-JtSJto9s*)_xi*Db`O)E)MX z%WtBU)13kl$j8D@xb2t_fwnUlZRc{?c5(o7E?187SFq-j2XOw?JhsS2Q_&W(!6N82 z44Ujgdl2+m25sg+dlGaTgYrEalaNo)>ll=8sTlNFf^KKf6i-4gg6?3@R1eylpw}}f zf7T_FU=#EP2IZS&2JJ)88yU2fC*e4P-o&7-J!oHo-prus9<+dSxCrR2{}X{`M!`Dc03_>5%L6q%=9=}osfSdLF(m@?JvD63A{IvYe3jQ6hOK z5w$xTU^J2|P3sEQNEk&^7_a&67rKR|o#q9ho$kDU=vH?=AhgS!4-DPr&Ig5dyYs=J z+ueC#=ni*2By^`cFAnW-=fgsGx%1(nyZM}LSNLKIv+W9BLS);B&^<2w$j~3%c}eJA zK4)7RzG%br!rc%r@^BDG%@AJ(VLI-H`0@$U+et%w*@fw)G-ndc6GU^CK%${bK8Ut|sJ@ggjRu(cUF;4I!T*j*yoNBn|`;xrLDX33-J;;&>pDR}u1gLT(jE z91kS&8bZFnvZ)0AT0qfw9yYCqSmWUYyxH*7)4YFZA78|n4+uT(&Ig8`aOZ?tl4;aM}(ep=|_h4yYrIJ^L);l z4KHZkY=j)vY~-Apjhs`1k-BIubg||kd}Pf-_{f@v@R2nS;UjAv!bjFTgpaIw2p?JV z5I(ZzA$(!YL-@j)hwz0p4{0Yg4>4!WL&B+f>_hW-n6kf(k{ZazA{NafKu>!OUkC8` zB)up#ThsN{x~>mS)yhli8x~bG;cc;665eBNXki^cJ=FDqKn<^7QU^?cVRUVYuJ;GD ztf`@fcs)dN$3j2D$@z(qx6zH4PQu|`Lw65vSV5f^TJ1(0zd|#m>l>;XeN}~5#g`9TGIuWCY%g*F zcMMil5PqI3JS>D4XzO*cBwYTrqcBdKycfK zt!S$D+rA#SDBG!enF*JAdF|b)KwnMhIw4&A*2tCj_TPv@{+qlcC*o({y z=GH7{zBBuw^09omSv;<^@0)bhb zg<0)gvoa&~Z^3Vfbv+}}T8gl)rys_wj)tac)B_zLM=?PUbTTy6N@TnnY~h=gE{3*L zTSJ?X07}_l>&0}j*)gy^Tx>4P|tFyXT-9((nZgX7N*a0u~o5{Yk}tJT@c6N`Eeay6xU(> z3|DKNp;cASi>Syz*hs@tND7=|v_cb43Y;xIpCvx86d_oFF`y^u%UpR)hNjlHt~bCf zpLjj6+|cF|h_^awwrgDe)l}mV>*E492z82u&^Of$jOqTd2mvv(#&1n1# z7#prgiF|eFfs3Pzyv#LnGlCXjWMI1p$#r7fCdO;Uc#RmZ7UNbv>Q}lJZb62pO`oB- z!8`NihUN#$ioS~XMqfqOQeQ^n*Kc&K-4WR~^uSF}RkOT*f&WX=F4vTukt%sBxjD*0 zdA!r_bk*I?A_~#&v4SV*HU{q(0jFcg-3TWu8c`5>U=JXyi@K1z0AY3H7ERy@5y{6z zB=2`kxHpao_rx{f5r|i7QV%?4XqEl2{ddb$4?GlQ)q{YH^wB&F$Z#LTfzsjg3pAOg z9kd5Jiw>@VeTLTP*ZL^g(RhYWzynM`zgPnHLV&XA!cq!6E28p@h{~VcsQig}A0z%x z<6x=mJxI!jLdxHTl)t!Ao@Y{`)B7BQ$4c+JhK3EQ8pyZFOCRJ7K>ReX15#bvRN<$4 z1yFy$Uoy1frPcnB|BXc~X2{=zF{-b6;4MRA{m(76*Mw%j%)c61?VPz){)%{2kos%& zWoDA!@DG?tF_ZWrmy9o!O0B(*K022*8P~2i4Zd-70q?*URSWX=tH|3gV*D8+8g$?% z@%cwF{=nh-r^qYcmL5R8lLbj^`;IR_|AJXQz{hbi|BtwtKZx+C2I_%t&_R5Dehw0U z^gaW`pW-h7@h9W^_zC_Nek@|1xN-U_YMFf(KO0|1M)^PBW`S_!eHpdt^i)&s9b1^% zSmv`E$Yy{rgIq`wApY3uChfkXSJk1ou|3x0>tkf!zP^CwnA#*Cpo6ImFUL19rMOJN zTRzGM&N8(*<%=7AupW}Mq234YW@_^nHS2^>&1n5x(a_u|J)8fUx|y2|mWu7FAc&MTV^nyztBK z1W07WTEh;X2R&h`Uw(HkKhm_WJf@3lqeGgG`tYl635Y+WU6`|es&>pkpE;SPcCrtU zEhFsDM|)NcKFSP${PJ4?qFR9#G{ofJd<*%QG+2y-1bm?QJV1>71-w9v{rIRKhb6_o z@!K$PSxIfhJpcKyUI=u3ZGA)I;tKk@FHdiTTVYdA+ls!XRyTZpMO|HWEg0Ri!L5_% z|K>?a^=5l55J*a@6NW4jW33n$n(b)wo3ucDt`XyWG0qeCx#DxR7^}osDe!Z|=L#{- z7Gt@bzL>@Pb@nSJ<65~Z;+$hEi#kfI? z7l?7a7|$2uIx(&l;~FuZC&qKdxLS;1F`gsFRT!zh&laE0662X-Tq(vCVqA`q=$G*^ z&?M@vQPf?7TX&01t#nDlDfLYiO*Qp(-qORFMHZR+L}cz268|X1d&GFR81E9}9x>i2 z#yiA#yBK$i@isB;66396+$qLe#CS7CTDdog@kTM;Aja#(xI>KF#dw_qJ;A3^Ls-mg725>r`Y!~$DJ9BYE{etSsrpB2|D+~Je>&p-Y z<&9Kql`|WvYpW|7tAXp+w{M@t_}=)R79CQ~4Q>pcAH2}GHn=_bTJY20FTsn9*K*#; zxjgUcyl<_at;(d#c1Cg2lJin_r0h#MnDPxc&I_&u&-&m7@NN!X7TglNGI({6BHXKiNX`u^)vSyP)kcOHY`=2p<; z6RGb%Ml-LL!EhNDH0!$g2=IZ?)YLIB4mY5AIg*6aR4-@nW{l>Jrbr?tr*Q=XH)k|2 z9}|-XiKhQr;9ruyJj!OW;kbT<{esGW{R#?)6cqFwG^D=*#1w@yXwaZwaLAw`0|ztI z?3NTmT^pxQ{_^#4g}>g@>ZUhu8^8PN*X}c|vd6DoiHm=&T4;n@u|n5yhK2p7#+v{X z?cR}=wanmg5HTmZUZ81=pc|@X3{~S!bQOIxZ5t&?`Ol>ju_sg&elv2YuR?^WODEz_ z*oj|ZZ4QY;Cvrg8-D5QE-Uvrrc_I%)mj&A@miZkaI)v1wazzttC^Cl^%|u6>*HE!& zQT5F6HI)tZjrDVzf>UZ5msHdS%bJ!{)zl*;Soc$g&zw_JH?y*!PgQNL8N?M9&2Cz; zxVoyQR*p+h&MFD^ z+MQk9&`{sdP`$Xmp{WS1a?#=@t?jy`ehUipoAGWXjc(M;(8Bdg^;xK&tSPO-hYn?h zo8giT#$(yvUhHpg`kQ%g($ThSiYxW*f^u9Ts&1&OsO>Xf%g{p;FSzZ?LmyrG@A7Xh zdEo4fw=?fMYE3nDm9Sw{T}H&$2eHj*WU8D;53T9GY|RgsFWPct z*IlpNn)zU2sv1R@PP_Px;r1&9zkcw}+D~^4daq4p`{aa7Us_RBJ(rufKQQgr?nw=k z>OasA?K-FFnM@}!6Du2UVFS+Tq{YPkA+a-p*W=n8+sF(!yMyQrhL#r&n%%<$K|co<1}4KT9(++9ecT*j-yQhlxCK8-!yzVXquCs!sN>{c{xPkJZZ zQiG%DsY_}q7nao4*Eis6b+hE4riF*H4QIF_3v&k>Y4hm}T}#IeA%1$g*$p=>Gz$>V zFwRrb8S}2#Sa$}G-YHv8&r{gSDw>uwV4D<+^JC&H0%s5641yDP)|AvQ!ddDm1(WJ& z7~pD~-T@mAE&R_e_%k0oxy-_^T!sOhp&*jsChYaY*MXrEV@NTy$#o6&wY9_NFR5F& zLfiqDl$5LmweV)Hqi0vJJOY;Ro7$+1WId^~o^DCL3AH$SH^k(71J}{R1F%yLUrKyh z`iYWhKur1zO^{AX)wDT`dV-&NV)fGMhDN%_$Y)$lE|?wzQ}|r21Q+eOM_ftSvWmqe zH4W@0Bp>5HE$|$RZy{XUS6WV^cIoTxB;L3sx;nD%&nu`^OB#>fWGU z2f$tu<{1jKeKsN$I#!#dQ?NVOcT&Ea!sdbjhNbf`xPR z8x*N!#2~PI29{xx1(yc6mV%g}-ZmHv)6zMEmX50s3U%CceqIQ!CtNOE7~x#~NJpei zCl-OYPaAxJXK5MeBc^21B`9BM4mchhSAnB|aTNPF#5$;oWIE{tFeRf0ai&uwQ*qr2 zaZj#a$>p>s>++EcTl8LYCn0&VvgCzy$`@^^K1-Dr;4Twqq;s}tA!D(yL3<|fBLCoE$1%d!Li@v_&S0kUKcp=6tE4(m4YIsNY4?q$<1<` zN6ap;tQ5T0yS(X=w;#C_8M-|aK-{_$p2xxzb@ma*tI~C+f@wLJj%7@FJ|;4*f25kl z6T$JJtER8yD2N&6@nxVs1&3|E3Qq7*$4%v|N#Jr^u2GT;ZDs_!+jdfYbgx-78BDo2 zX43&gpV2yyK11^1-l6z>XHNy+%aX4Kd~?*m-v;o7x3VrohQ1^@xxRR;`>Tkn zJN{hhvVJC6mCVJ|dmGNjhIi2hWiv5r=}Ea_oq$sWC??~L3&3+y5Pw*3we-%CQAv7C z&W9F(=@sH!!&M%qaQ>Fcrp4f?G4N*tXB?TUO~5HNboQ9Xw6TpK{gvqVv%t`PZH~(l zbJ_G;2I{pr`16U&vYxa2#s+WenPBLXhd*I%*mjjArlLbpUye~LnT65YuP}gExN1GBY{R@>gmh`FXLI0*pe~8n^ z-p!V60BuP=-@Rz*t@BvUIBlGxUcZfCxd$wD%$#hMC2sF3-vp*0_LsCv($einCU?b& z-F#>>=r3~VkB_8}tLT_Z!T6)gI9f2q4D1h=fp%Umc_5yu(#CPV@eg2m1uXoKU!$_b z%0=i3&=+H;%=Z<`RQh2x^G4QH)kL?c`>zDk9bj6?f^`vR;=9SHEo+CXL41s@X;VS0 ze}ygUR!$#p!}^zNz_1<+r%8reR0Yw8kZs$*@C_K)c9k^zku${pUeJ0w$mjIYw6Vt)4aj=Q`z?FRE;d`se*`~N0$ToZcS0Vy{^ z3O6AXPfDcUm3M-#ZGWkKOgz50ihte%0jnT@E1ncjKwSR|?}mVXyB1U&RzO@+{(282 zO&cIhStum2LX4O9*7t(vNtb7NES^|}dD?y8D;Owst&PVQbGv=({b0V%Wxg~XbKIDH z_W%U68YHz}#|6av7CQ1lkgfn}9xLo!3TeE(dWVO=@-bNQ8OwbNOU$+N1JRcamh}4~ z>EpWb-os$r>oV>ajFhm*I(_01klKZs)}7h(x`2_g1;{{(8_m~w4@-*Ia1ne@dKeKCUIcg5 zN%*tfHDSAIg7|t7*M`$y2JcNn@#h`Yh9^`T4kzQv*TFt~82)(Cd!GxCUo_(C-|-gM z)(pp=Ye~PB{;kXCB`jw2UVax$T}R*#`yz+kXHQmFs1HUTSLHuH0M8$Z@ef>OuFH5B zmG6ECrg0YH&+b zgUjAHfnCjJ=lscr2Qrx{qd%qj$(mL&KSK}n%GPUoCZ%r<=thw;TxuY-;%oksUts<`*gHY3mVQALSK%D|Se33% zC`@Axg6VUYsXPPs;WxUPF!65IEuD*dA?PMK{5GG zGW7JhQNkt+FN-TB{Yyysmz2_3O3}5Np1CCzl})(3H4foNJJ$lq$zj|YQAlA+?##5H zNFW^EB{T1eSSHf6-pPxb<~LMVRLN&K;KXAFnDX%Za=K_bXaF7xfZt9)^|62h69A^F zX6{^xZN{-388%IOJPq-gJi4x_@RTKs=AaCVCoi3@ zCrzkXTwPmJSB?Aa8kSTx0Y3l%NYkDqYgw@j8X)b(`?m&mQDYJX%YkKJ0 zd+1N}(BJQ&f7?TE-BZu)si$c_1tHe6k1ruD+#76Z+P8ir4w$HDhB@gsoJ-RN_#!!? zhVJE~n`?PE)3m-mJitAf&@F9XOW8;|llh1Cq<KmaG3ISARcO{~}jEl&iPS)3ft* zJ5N78PamD9PtDV7^7LhS`bByA);#@|JpGS(`o28-aYh@J&^B5V+AF-71k3{L@U3XeqX>>(=nnX!!4T@!NVYn)rr2`i55g*g7eAs zkh3gWP&*-LYh;4ECzp$cL&0yCJUN3M4#o{1Usg#!hma?3xjjRnf-=~x8?El9hKjnz zxp)kZx4gG>AoP?rgf2g&c>Kr_!%N4NP8>J7Y?4P*&xmeFDl0B8Zfa_ngnJI~gdH5) zn0pX~BbmZ6_$=o1Wm zfuWye=$j0EyP@wf^u31uqM?6a=m!m5GxgS{evGN-oBBXgFE;g4OufO>H=Fu4Q{Q9i zkDB^^Q-90U|7q%9o4SsTaE{(NN6*XA`{w8;!gXrr<9eHP8<(mRK&?RkO7RtH`{3V zmw`NrU&UGFGAN<`x`|cJ{GMP|n!2)2z>N?HVe)5L8Vsqct;PihaabP6vXIQ^Oa8I zR(6JPE1MRj7Z#I;*pGRO61lPEwr|lK{s=EEj9a>~8G)sX7S3BFH+N#|*Ms|!)EPe@ zT(qbjH{;6=F`_MXh%~KhGH&3ltEXHvCAWbTSB9jN8?qEyH;63Uq>v^z1F<+xxKgvY zz6q@Fc&#gHB`w5uq?&V$O@VwUt^n^Xq#4B@ChN&BnuyrO=C zSh@9POwY>F^|r1#Xf~izuld3D{*I|9lTcOw#zLu4C2i8R7c4s8i zu}CtF$1#n6h`9+{7*FHr41rYRCo>HzV92vf&-G*o^HsGWi)px?dCQQ@0BU5}3{x3f z*i9b8h$V|h)>bcK_Tr~ND9W84vINW3#pVLrlIpg9PyB)?Ih>`9VI%zpB7iH?$s9P^ z1LCqX1E%0dus~`7T(D&T`b`2+f8P$jILC!!2256gxF$@%RHD)}P~lb}4)+)KtORVBDni~~m~=HO;9 z2Bar}k)rQ=AegvGj(~Wg69Dr7z}&_E))hdRfBO)4+pC3 zxMzn0Rd(Ew!+~n-aMKL~24w7xL#S{o5&`j>V#KZ<0Nl`&+yY<5S$KVm0vG)me^+&- z;Cem-W@*Yw!L@opsQ_^qo&kLe19vYlpl=D`#sru!E`|v>ZyQ6K0QzL$jBB(uoKGd7 zw+wM6pHW?)DK&-@@EoXy8E4rUFjY+m&h9gyyXtVElL6dShbx&3;I2AcsT3?hZ;{~& zBWKeTAg+mV;7|pK%T*jWLIL6$4hJSHKwMg4z|JZVR~ZTDt$ADr<*aG|a0QP8)d1is z8waW-h09MIs1_eChB2V8kKlSJ0sB#%u_cKc5*SrKl@<3L5YX!(xb)AcjG*R)3)lEL zaHs;rReTOq<>4wl2dYNnQak~@b}>>Y@ii6PmO)fr55eUUCToMHXvGx^4pdFSWeEoK zbsJnl;Xs^6bAy13Bn0&O2(IQbDqq{cWm^tZS#fQa0k^8=;2InUszJa-HV#y6#1%9S zR3n2cV+8cN7;ZjbRK7NZy9_u`Rf78nI8e0_HwzH3!1eci5$OVz6}N*hR$pJ*&VgQE z!ksl}3gdZG@Uc#_-y`sQ1b&ae?-BSt z0>4M#_Xr#|0;Pd_lS*~1w14ZlnO*yu&0Fdt^t803HW^vCh2h4`Zo@{VcTCaRlm_lg zDh=F^e-GfFgMSa=-$Q)V!`q>Uf%U@DK>K78NJRQcj9zbF8YoC5U^af7r~kU)=cQfm1H3wj`RbrEFct4&nT&r< ze?WH-@s1Sv7TjZ@42;kub@XyhNQHd%>Zl@^+8b~5z?jJEfXLGVcsd52j!LylQtc6` z_AudWf4?K6VmnfzI5NU@WSHUzGjuF84S=B-;~ILnoP_8taImy2)jl=VE={$^3rkO= zjO#mDf9tLgxybO1yxp|oa zcSpcojB(xljiRT#jDffF;B9rPU72cEq}t`F_AKG>Sbu7&6=y0HXDSqD%3Wt>DbBFm z%!jsdFczbHEeuwh9?lEU>cZmFL#2VUTguhNrfoT5XlY=ThoEVP(!k=h*lW(`aH@Zq z6ORp#8`DbcGt&5K>ub$VdxX{k?k}dLbVk~`;hQK=n}T==C*Va*;3|OS7>_K>F|-bZ z)-$1XMVh@V&0ZpO53=f^n^tjqQoX`c?JP@^%XJB$a=Efdo&|db!yb$>k`$Bhx74Tl zYirt3M?3pS!sCw)v6R8ib75yV&0ZypoMZ*k9>IIS@$*Eo20AynV>P1`p*w|fKbGdK@!~`&I+#*)K6K9%zQY83 zOw@#On6L>ZY)rE^q}l6*A+xPkB2it*fQ_C3&IUJ8>j4!_7-r$UkQc+M3Ydd2QFE$b z&ZRJCvoK_yj7S@b$hM#sHp!sPoA1k4(c&a zSp6EV{tl?$E!D3j^?5>lFY=X5Z(!gt-Tm(%sV{H9=harEbBbM;>+_%!K z5_^1>JvNIUjBqzPMK_E0+dkyp_$>6^$@u4tl{4ONCuBj)joeMl6Nxgjz68?!c*)&DW2{EuVu+Kx#wEce>(=XOsyw=&JLf*(G32+=Pcwgd>4q}B<6|K zEDP+t5P_Nv!pZK^$@|ELPT73FT1?g1olKQZ?>+SX&=f6+I@P$|YfMAy4YTNr>k^*) zV!-fbBG`vtm63gzCu|>n$wl_%!M+@6AAY2zSvg7)J~#>A?O_fD5I@V(oE+6&0B}2< zQP_hApP6TodH6Y&mfs`WPyNB6FW_BHVNXVlrzE05kVA}PFLCtDMz|g!$HT)ZI7}If zhDW#$gzy|pa;egrF^~E0RvfYPf%BgROY8$d-c61x)%#hW2b}{!7$5>)+?0~409sL* zq_h-YEDM~^gQ9epGr5IduqNqw_E`|!JO7IyCuA9Aju4!_V`EGtePn$htp5tu|3_Fq z#Q9Hz-E8fK5iQ;`bhNl;o(W&Wgd&)LF;NpLVM2;gVmCMJWWx>^wr221R#`0#M>Ez9 zzpxh>pPlbFEhKX{UjvtjQmW)YHP3nF%d=WjQsWzqz?qw*!*^e)0XLKNq^144kWh0>L^WMU`~=m zlJq40feyaHt|lwPaFUUX?J0fF%?zq-g;lqLf&i@*BPhTUfT2r>x0P@J2Oz9iC&Q4- zBgvDcK$&XJzSIdo?~W9wql`fy8U2+PcbESAq=A`5p(_Pans6RKcy?H*Y z=V`(B(CsNjsfa~bY{oH9biIZ*K{nQ`g*BUN*rs6z4ZFKov-mw7T7OT&>3(GE7SB`x zeSUoUh_xHOgy@frPam;<@jN+paKDV$dK-?(Di~*0*$QI2B`2TCs?eqk<4G-`GvkYw z%h<^^kk4dRa_)k}PbfwBufinXHmqLi!t7(@A16U#VfHbcUZmaWNq^14zRZZL$%uXi zH;kh=nOvNVM_HU8q z1j8;e>_WpHBuf@gQ_!43<~-@9W$hF(Q(^{EK}7`8D)RTB@a=xdwA%kil4%#J*vvYC zVi;P2-1M>Tte_5OGoJ3CN^btYvza!-!hN3IlPJ4)1B&coo^W;@h(LBHAiJj+_Bg{H zW7wl)b{{0IV|>{~mQl?FALpf+;*!)Ghc?YS9uZ**&iem0IdLk-J8N7-70?b@v4E=J za3Uk}cR2FHSwQ=7#R969!-@PKTfjE`UKXgT{y$srn3r!}eWz0O?FAIohk3%)_h*Pe z^({d4%{T11hFxXYb7b{BOSL>Eu2*ysQFatmWKQQsRMj(n$*gNB>_;K_S-)h~ zwf;AfpYuy*UF&}%`FWDeMe*z|r0l)`D6)%r!r6TdB9Ps)klmGrz1*;u8g`S+E}qz+ zIZOT7T^>KX3Mw+Y%OkS;hF>y^l)@gFT?KVG$#424v+OGDM2 zB9Ptf$nG}7zQ(Y(8upbkyI+ykt!{Q%q^^mdT?G}HgKHwP`?X&(%dWy6nF9rNILY7m zC9{fD*pEW;cO;pM;yKtsIrtt>8#cl^XCsL1d|N)GrXv&1Ouk>OKNhm)M-m&}SuVLuAVcr^^Jt1OKNhm+jaFPRmS!hRHz+mU20iYI0tC8j-~NDSr)C#D-jATci@F)tYQ ze#3s&u%DKR=}uaob#uV{*&ja#3Mw*E`y;ZO?U&4Qps+_qN=d5$PDEDdMPG_8%F6$lF59n*YU}?@*Kwqa2ZLwsZ>`x8*fMNejX08xO>(hu34WFk5@7EQbPDS9+>I#uAE{~`4Ka|cB0Yy47PdJ?;Ap+^t%o6)o!~WT@e>Cjx zWjaep>yN*Yxu03)aNq8Z6s<3OR2JILtO^41T1xn2zpUuY{1>uD`DH~%{=bklhGcPi z9$DQ)WXA%E$YP#wWG6!eBHJ2~O*8FO({5qf%}jAe#1zun!lc0AGz~u`>V0I#2Ja&~ z2&IBJ&ZQv*e2oD>)5<)`}fvo9Npn83lBbbmPS4|+PVt-$ zDB_8E!ttC95s2q8h-YWh?qu2>OuL92Jybua~Jv{gtGj^YM6grFd2Wig;q4a6A`51mc;Gc=j;uJk!oGZ9~Sh zjrxEpHBP*KRdcv79*RK} ziZcO40brhRD9(ilgrXRsILWj_rhU9=50RlbkF*}|4~6%Ug~Iztq2Onm@om%z#gB=C z@?yg7;oujk*)w#;@G7 z1C)2E_bO1ZEA3Zfl0VI~rcyOD@!KVeW|;Y>NszeIJHvFQG7~1yU$bx~Q*(@kZKmNTRGEjWM&tW0N&l060d-I-imyO}HD>tknL9 zNj^N_spmbWl%jMmQ3UcaPq@cC3=!zI4d^k8O}oytYfXEB>@kl3X*HS7f+OrPj}rZo z`1FxI<1wON8lOJ0XY3{VW%21Fd)PkEBTSDI+X~aEV@t=q3FJ=zJ4@J#S;?y6NusNZ zFJ877XR*m|0-++H%zO7{g`a{9mb9la$zN$&%hmpHmYILH1d0A|mgy`f8=NNkYZk6z zraVigoMUqHIEs_W{=j(D{_q@egr$?w{o#4won_41bE$S-5cJ{r{UHJs(H~xffc$e! zr25bkiRD2Zu!4swS2M?*s15osVF^Msekdk}#ovKdQclWA`>?G2{AUM`XMN%sa80&<@1NH;Q5B2r*& zWZMR><9*=gWP6t*Y1#)(`*YL&RL1B;AgzND?w>@aeC`k2 z!I*)Il12?uUEL?CeK2wbZiyJe1@l4Cc|5m!WJkk*tO-xU$>BXivQ$h>I@;_WH^-9PPm z_|B(g4t-7Vz6G2{@;M9lsttKHlY51E!d_K!uR6o4PC0gm9J^hP-Bx;4MOxeWz4AUX zue^`smA4n|5aC|LuG{mpLxiW*q?2=VPrHz(bGfIOC+z7W?r9!8&B?Ki96LM5?j}90 zBdytfPrZ-KQ|}|opAq4p^oZpT7SlUYEQ2|h;$B8PgVbtU zX>@mLEHh{p+tM^TPlm}3vhu?NU_tRt<1+;}j13uAaZ)+&tf^n5=j zYlWU57D?|Ti)1XhvQ(nwUqJFX3y(*L;;{ix!~^q$<8diOAReO-kCGgFM2gN0sGjk0m1}OA|lc7R7iiG0tfH z$hj?&@Q9p_%t)Md-IC`FgMISJJ>*Ii;9xBL!CuknX2Rz|=_%lSH z9_FGRs$>~FO^T~T*zw!~TF=>O$IoYZe-_C6TGIX;W*GMK;dws1z=yx^;YB|Dl@BlR z;blI&!iQJ+@EQivqZi{((L9p>20;0Xc=dSDHvz@D-I^S0e$EN#6r7-0sFo2n7vuk9 z@5QKJ~e8&;7aZ`<{DeCNqrC^|g!o+Esn+roMJpUwhznY`B8V`X?FS3d6*tN&gpAfb@AFy}>8f z`Q%!kT&=PHAsVFxKBdlXV0}c57yFcIG}=wtmao4@KPLH0oaMDiUVAF~Z^*;PPx#BH z)O)cH*};#Lc#%HEXa`MSUmi=xOuYC4{$0Er2Qg@ePVi$H*!_F;poh;%>mnXk{?+u$ zeBr21tx_L*T;@|2`H%|A#q>8jZwX7jFVR)Gglh7ZQY^kERhRmd1#DVTdo)nyvgany*Egukp#Neex=wyh2NJ5slJ1pR!s@ z^T*hJ;xV?La8ct1pR(c@(>#Ub|K=>OF{-7x8}jh68GmU`y*F9X+z$G<(ma*4ZZxL( zb-wUspIW7+`E@>JBTMrQJk76XX?_yADt}{XzJ+4Zl2l#mQ`Uiw$5PcEYxFdCvyBpt zdCJ9q+QqbjeEto-FzcLQ)0wi@+$($o0c8^KDxT)dE{8O~)(4~(}_g zTS;{%XhW_8Ch1)FKn14sy~y=FK6$rK-szLKYq{=4qqNVb?ACJKxOeuED?1tI#5TLM zh`nW(7O}S!Y4eP;4?WF0Z1c<;n}+nO4|p6PP;QQKQn{7bkkAG;P)?eST&MsW4}gvP zeDXa$`7WP)hsH)fG)jt3xkqEeIP&{b<9?rV2O5uMfg3>b4?D|SNB%&_!^cyp+as1C zZ-=Q5d3;|9|IRk7Y=ZDDjxREI*;SQ>)Y=|ENznz=r&OKI9LwA%8l$ zDi55mwm@j;g-VP=Gc9fci{nI2`NTNI)jKlsxY8!^O{6oGl z6C55BR2Y4Z0EveEgTC+~Qe6aXNOZs?o#^AC0*U^2B>F2p`6ZwHf=_-~$rAk?3c@sc{{l~GCax!(@;Yj94}mLrMNf2nSEn4d z$?>zHFaJGXm?=N!*pw4w0M?V0g41$0l#6f*WS`yAZ=OWldxrG zt2L`&ci^}RoUi$2lak?UfmwxtFUFL5zVf?lTqv}%B;@7RDS!b#BbrJd#YEG>>uXDZ|0{pUr&5((T#E^eY@YUY4i}bmqB*o*EG*&+XY>{-4M9Ste!>IqFx;WCjfFafpA8RdjPi|Jgr3= z8wb~*kl)fD=Jc&M+r`E~GW2aQ>oL$rVW79P_c?yv{$|!|;7uQ7N$I^7dZnXmShUpd z9&aKr&L1BZjJfMji(%1{SlmoyR~Yq44~rd8fnm`F!=jU4?%xd%$Vj?(9aR(grPdn|ggc=)s1?9+GWm8V5=@ymh+FIf`w#WklR!R>4BbRVbab z5uva6TJpbt)JD@@vnCcqizcV}-&Wr~(#I(>&i7p@Lbsuf<@xO>1vkC(dq{2GC+p4%1Dx?m6^L&0E>E(p*#AQ_6k6I*dHqr6` zm0e-fC!M&DKm`)_6eOpiTfxTrM`ZpmzKE3`TQUnmEd0`Za-_!KN}nO6oH65k-G>5p z2yHBnpG6@*&mZRWJa4vx<#96fykOR2pvO30|FsJ*n)MiX(FcWf`L*TuW$2N5v9ylO z$FGob&JRy(#>}gzMOx<(OMj=bD~$T2)B0VgKw1w+S{M4|0>3=iFQ1{M^?PWPM);L8 z^yGCXIx08%KFN=CmbZR8;{%c(QplAYY(b8B5CY zCa^*NCCL@|mC;m3iDLM6$5&`$iT@1>;R$}JScQVpw-;>YLt>CK(lBR+QYVLChNP^0EYs8vRhvb?F3vOjSc)|*c7QO5h}&|kExXC!JJ ze}Q0lsvkTth6WI&Tv(I%6%x3dp5zagkmlbAiP1c08sp%1f^wkw57rmGj-n8r7K;Ua zmFsLjk39;s#}?htWB#HRBa|~qcRiGGEaG@Fi}QAQnHlXuje6QHes&%|^T5Q+Uf?%y zdBB^a5C$~Q9zNoW$gvhA;R>Ui^eE4S3XJlZ808oE<@5dWbiaI#Hp<(eQ7ZQ<=fFC? zw@N(9+md|5C~rPM+xi`;b|gQ`C~wwpofX=X{A_1=>#Wd$@n5J zXjCp_!=r{JTNX*5?^otf9hSxT?|*q9!DfhT6v8!rsmeG*T;vbeX;tbBagkrCVy2hV z-|W142IME82F)wh#Kp83g7q=Z5EAvM^efZh2xf=|ZlU@R)A-HC5CoM7HRm-_0*BR( zm44$ilA31tqNt_G@*VtYefc`3A@+@Gib8MdyTD987uFuE z_90d0gGA%EMd_Efh@0|R(M@`X)P1L^BeN(kj0aJ;sS<6v8j$nYi4qG-=llhF!}Pv|+TY^@p#aL^_LL*DyNC2~m9ryOP?bk*F(-a?(k5 z0aPH#wj#-H^vhfP@@BuhNlUU)G)mk3%BEvXvY8~m!&%;%WMw43(^=k{WaT8k%URyK zT1Frbnr2bAoBhfbb5hRctrd7tc2Gd`ZebaBA&GBsM$y(lsX`%q zi(lGpO#WN_;eA?_n*6u=mEA1Ex6|M3yxW*5HDt=|er}$^nz)#j{H%{L`7fd#d;H2~ zp8U6~iON46V_aD3A*k$PZr?$<)S!0UyixXh z5-|TmgB+5x=z@ymz( z@|#*l-b$!P7^*toAJ#Kc^GBQf_d!-V!m>B^U98&@DA1_Z6x?p7;En_ev@FmR+-axa zt^^9S1l1JWZKvR#1PZjVqba!8PQiT%6llX*Q*ghXf(K&?_-yn(#a=-zVvlmtu|EhE zi2XN+{a1eZ3%~rCU;adk{o{oCg)#P@>9Mz({RCvCFD$WtGJygsaZlMPcshXsYv`V_ zQ*bDO0&DU-Yp3A31PZL_`@Efk7ZND24xkt96ucZ$z+?X{#r_r4BK9aJ9s9SS0B|0l8T~ed_!P`I8oi?R@#( zpKeaK2+*yrSI$M5(3S>(bvZY5r?iP@{1msRyw){jsb~9v)(nU{_vqC+(8dKVZMK)xm z;VctkS7*Ki3bY_<3jB5o0tpmo`K2k4>=XnOD9}QpDG1pq=owSM*Tm7pd@t03d6bi8 zJ{Ky${8?arNJu zVX;v<&`#;8$D&jVm5tIoJEen;MX44(8>RVnN>7g|<&m65kvs#nh$PBMM{+n+Ad(e` z=cYnpg@bZreKVn zg0Tq{Sf_z;b_$AP3OMr@67v&K3+7Qyn)zu^0p{m}`Nn`;ACNB!$Tb@CXA^3@k@<^s z<~6ff?$FpWJv&b%XL;Un4nU-OOUTYmfUGh8SIF^l7Ub!6$mbJvHl;zxfoc=MngESr*K||T7(njq{G<+6$t0e2?yprrc>5J<9EI3@10sZAze7BRV!De>(~$D_Q4F@A7BN6M=@{&Q3dG$C25$u9*8}q31M(|c3?3nWUN^?z?+IdHN}5L#bd4w3)b+6hUE^6a zb$uLNmDde49VVKdKrLuOIcb`nhYHa2FVOUUKz=tMza5bOsnPTTp}xyd)jKV3>ojQw zYm32)kd@wLl*aC~yp%wJMwX`FWjh70Bv7CY7EQscb_!mLDd5Y|heX`#s0DE-Cr#WD zr~q-_fVi&$@)rU5vw-}GM%>$k`h}6W&vfFfX1@bj=?e>S?Dd5C?OT>MIS`deF(!_lM6(H_+5cl7J{7XRoDIou#5%(pb{$eEVC!ILWY<*2M zT^%Qqvs|xz1rX^M3*%oWK-L)lE97`N3-UL1$loSF){^C~kmKbn$luu^e;-5UG5&*M z`~zwcW0aGQ@o!Lp7`K*+>N>^*8;z>a0@odPtCD0tt_wi`%oNOQ1P!TX9^|cRn;LgA9Q=lLB)ZY7rQe zlMc*Ks6b#wBQPT+xk!?SN%BxFFoon#ktHz0td+{J1c5Q7*YE^gJslxI;NRw3k--xT+$rM|&~!XmR+2z- zJd4Mpd2#~H@gyIQ<|$Uqv~Hb+N@ao}FjFWn(@=}RpqzAIWPFs4i@P0%%-c~jS!3A)BpYwB8N?MmE5P^p|};BF>yHw(4k4&|h| ztAYw}Hy7MhNb+n+j!1Hu#$7d`&St3Um3lv}Hk4P;aN8!LD*%Oe?=asU$Y%qZVwUoHUz@p#p3!0Gsn9xj~ZaB)L{&^D;7} z!NO3KOldGuT&GiPb#RHDf~5%*SSem+r(k&k1=b*6Zl~aim;%n`LSl0TYQZMTNwc{Y zD!}IDU~`!yFOlTSB>7T}&1=Y%B^EZtYHxn@z;#X4HaBl#^z2J5+$pbzpO?B(IU=)snnQV{-?gt}zm~S|`qG_D;x3 zYb?y~N}#|>+-^GsHz!bF4c#6)1-IB$-Wt=&*<4R-?n5ouL^)|T?}G}kc@x;YL6WbR zvT3XU-Ww~$F(thfc&|h#fkf~mHc^-`-5`Q{yfJ0*$aR6 zNb+t;-YLo3HGdA0Kf4Y7#6F?5)7~+|ujn$_L#x5$(O1}Djs!`4b=|NoQcN1$0bU~uwra`J7|!by~qcJf20 zfRiu4$>${bkR(4X$xmudenhB;7^=E!c{|y>!`G3$~dd=d>4>6_O zmAA;1A5jZeP)^#F-=PAod|Z7MXG#81lE2r??ntKmY+1?N8*1ST%1Qg;hYI-8JXj>VgR(0q3qko$%@>JK|AeJ> zXHeNbc^!gT4z(q$-QVNxMpq#i+~1A4`!%P?vzSJTBq>Cz5jTDo+n zbot)H(xr%yd$7#V)1|vZx{Qd)DxJ*f!n?$$%Sf9prgY&QzMo)1@m#V=UTO zx{O01-xCaTVv6z3(digZ{8z_R_a~ZQkS*H)#HGtC)`1 zsd)M?BOJ?*TU`LHj+W^2U_X}FGs%L!JooqyVf7D&2L#nB^_ZUiL8WgHlbOxCwYewdr<+om&1Z^)Mx67;`ckd=BuI8Rs*)R|-w4qr#|U&zcIOWWh6hqi zXA=Y`+?bFuwap>X6cj2@$j=LgxkGdD&g{^jU^w66&>)LLr!j}B2+iowiFi^?=DG9p zgW=Q2+KWgx_k^?P7$7a_?S2@GIbKJaaegbQZJ@F%jQXVK$V;FCNk1G(Ul^1Ng7V;? ze1?|vi_j>I2r30y(i@K@zLXkA1(h?7G3ggW9yVV_-Nsmw-cHAHCH)d;b+klJ`mrp~ z%gBP!#-tw?437`0Rcg|Y3o4^o(vRXvU(C8*PB0_jFn$wD!EGn`a%Xw# zVQ@Q0KH@B|k*6JCyp!Z-Im=s*D&0l$vx7<*OZ{2&H+EF%Zfcxk8M$`M=pz>&#l^qG zzgTrMv?7vwNcn~8pj7wDxA3N0si`8UOh*vdw#zsR-G)YGHW`{%#d7&}lAaz^B2-5^ zO)ZD?ORYN~!N$*BD1@tm(p=+QP!kN-YE|l7P!m+TzLEIfqXmb=*S3@8Iz@aSlxnZf#9`0G*U_63wfplz&iF!laZ7Nj623 zeF$ygdNWg8#PlOv50i@Na2gYf&dLE);wZV=VE7_}c@%FsuY=|@cOT=O67YJEX+Ym6 zPzcZ0L%K2H*^Fv>|UqJM`9%puD$hb#@s(V)CIC@<3Hkk`;C zH3gML$2f<)PV!ec%UkD=e~|nNXL;)!@&@GL_M6mgRZxktQKg?+`W97RX&K~prXSZJ zKg=Z54c;cSsI%?be5Nc_msy+P{0?-m;rt#7;j4nuO5Y%ccY*3o$FV0+LrhGuAtP67UcoP@XhBND99L^t7kJUkCF(1zBNSnTJ>OZrfTxlB4 zAET49f>E%ZvhUxj5+g$Q>tG4XK`({TQbRDeXrk?oB4IV9+K)nND< z!u%3%l~pY6Yz|N_!7rz_uSnDtMmg!x@FP@UG;GCaxG^Yi3Cf#;@+NIG{Dekndr;YQ zjHBUalHcJhZygQ4ko-<(dFyESmE?Ch%WD~^t*HMc`Q6U)))n|hzUoBqaD z)Zftv&i^2pTP$PFj-cZjbAOW7z2+75Cdhu|H-@SR$fIt1?sDz`F1w$tD2 zyt^1s8Ufv{amAXrm^K7iAL9^AryhHQ%4R+U@8%Z9t*Ez{hF~jnQg)JP-o2Fa8LAQ{ zrR+5g!A!J;?=>^UMYJ`yE%n~Q7SmLnkanoVfV(pozKak#;4PN;@$P z=-UN_@B=#gY%x`W3d^KCg=y>Zg=6-` zi}Ezf;1^g1hCcmN9F7lP6u;~;)17=Br+QU~!%LFEwH zpgcu?v-4hIrkqNqyc*=@@g^>&4Pw^EIEV*PkLQER0X~RdC2cnA=yRq)d>T3_&oByJ zqwG6fRl=l{=S_q7Otghx(?Z0jJ1(LPV*Gp;lt-g!Vek_V#&AH9@E=pp0ly@k>^ynGX zvCoh+slVB+t7AX*=hok{pQ}tUYoBbR-S}fs1`Ku#W-=I434`-#+!4J`;XDg%Y+Ou3 zA^+20n3H!-%&Ze4?_9GUqRHS<(yUE4t0iU(YLh1Fd{V0u)!5Q8)wCIh29w+JtcTG$ z1DbFf=ToA%l*%}J^#n%D9H_vE`3WQDhoJnQp!{u6{#qL`6=;-x2`c~5MvQU4GZ&4@ z*MBu){>w&870Lbr+1L*OD&HR4h|#8+>X-`U2W_zM8|E=h#}jrt;U!|`VfivNYjnu{Gy@GGpk@}98-}DP4mqf z=~n|!keP*~QD+7Zw49R3I3}#mKN*h~LleftQQ~wFm0e-fC%uYX4iy*^twK1pG$f~m zJhHUINW0e-Bw{cPCzhP%t zMXrqLQPM-ERV1d)HsZGGR@5n-VD*m>Dt*26|r%${SXVk7C%slZC$lrF}sx2^KUJypGB^eKnMP)^CRjWW66*pB<7tA^GHx++EB19cYxKkmAv@-nbI%LZj0Cud+VG zvi@e0l^|qYJuwwZwwCaGC5UNC7+6iyEjF4=Q-4ff!T@XfZY6!3BI8^i zpa|_l8%y)sP{@}evSwvhoU< z_Ku|ebZ!^=?8-4nr?QGZO~bC~l}mpJtrMZ09%?Guol`)6^7Dz@&ZwQ-423QzgbPD> z?l>eAE}*8a)I`rpyP=RjEEMK^bjLe0A4Q??2n!!Yy30cwn`h^ZWES_Jo})rif4x!T zV=v<)3+*Z&qrk`Bcs^p)Mm|O}?HUL+?E4AHV_{h7$06ji{m33wTurR z3gOYj$B0mPB=O;=rj+n7DoZFEz;?k@JX1k_sALDx9EklaR?1 zLh^VmldnQG%v!@=uEC2kA(qK`QyD|+Q7uh2X7aR9`0Nm?(ldElNSUlUnNR8mBj!Be#(N$Fod6*FJKwYGdT4Gws)s_9=QMBXTimyU1-Kv?+#6E}@WIhguf7 z%_xMYQ{>JLh0md;E!0Grd;<#k=Y_(YkDKt$%*TvS_yP+bGjx}SHulfXD`ggMrJgfG z(pbGwYq&>z5Ms`fvZe;Hyv^YL?p_cKn8-;Kg@o_;Y zTuOZ0Oid}_^Qe3a$|f*NChtXiyz*N~gDVW;lg{LapaPkEYF3dvS4-plWK4BPnG4eP z1#o-jjvS0B{G|!(VKn09QM{-E+|;bRI!4<;>Rf>|;v=!}LDuVW)Y7~v7T`~Q6}kKb zs#rQag+jP4B-MtbUReiNzv#VfNgg-q+08|m@E|jRD|;Fplv)_~pgQ2Q^5*lrjcGqb zO6P}kG5$%`{W(fC`rX0iv`kD#`)NA5HwQDuz0A(%jH>xE@NkY&!LUF9$A2C|a8cE* zSHFmAi;pj%3IT$@NeAdPs6c?$dWz&lA^GBvyg&=n>u3RwZ{S6`EMzh=e@Q63G(@$R zsWfT6^dTp>$>AljW(t-kZyAf=TcmJ#tWBeiF?E0zEg{;UJ|4P=rW$rz{^C$m!Cg61 z=#R2Ms~ww5vXnE2xkk2l$JRuiBA&dakh0t`jVz|*_$PXVn?kr>xil1BMm6uCM&UU6 z*N*T@#aB?x{te?db>_M_5bI!h}?AKi9lS$-uM@hLX~<)n@Hk{huSMy%G1 z_zHE>)gfiIW=D&3?djn+WZ%^YH{IZF5VM#qYsi*wxh*IsZOaebmKm8v@`jMSE+ntj zEc%Hox;7+vGY>Qsto94h(=b6OYmwZ`=xGo>NC5*^`zhIeCeckHX$pxp2+;ychihT+ zYCjTmwI7n$D?;!W61*-XO@rXjMj?7(I|spENpN#W*`T|vheFf!J4BSt8eJXJlucSW zGp(hvj^4CXuG8vL(pnavCVwOG_6NEmkx)*WH}NEvNVCA(O(FS)kbJ$yTMAmF?IEd) ziMQ+Rcyp8J4hwJFO}z2nNpD7iJ1xAK1v$aZNpM$4xyhNgG>9m>G+w~l4o#MLyMgnz zQ)}0F+eW;dgs$KXWtBJA7TR32LiM;5F+VL!5XDxaD4v=o%qXg1gp-~k3p|+%o-0 z0=Ws5HDwjmvuZR{uMkaPu1|DEEw)7+=Zq@4&O)OTE7Q;x$I2Yt$_RChXQd3)R^!17 zH@*~&4wTJ6Q#@toq1KtQhIB1gE=m_>Os=SkXmkNF19Y`=f!Ia5)IxhHQJjy4l8TEX zqpHuUsVlEHWmO~EhBnTc6{#~Q_p+>l@@2a6sH!|ySRo=OQ;}ZnL~*fN+t*Obthz$) zxLg%6sMl@3T9;aFFC~hr(7r8e42iQ)!o zs501pvc~-ldgsmdof*UqU23bnlqlZl2ywICd8ebyt-8z}N0~cxnSJp_w9`17&{<2l zah-)3XA3yin8&(66vv=unxTgIHdXIX!aCrHWtz%FVTdSBWF2BPti$(uhi}n5u5>~C zsQ4NU7!?M>`)Pz<*j2M{c2|eq5j2$4l^J@|q{Xl^v$Wo=vV>Ba54o)kthK$~+Qz1} zv)&b;%NDRF+lM&nT~HoLL#komH`*s&sZm8HtH(v_$h^hUn^%B{W2; zYK0XYS^W}Wg%CXxEf{QG9pdCHq1*(}JjE5tIvGntiYv%pMG4X=Y$fs8NPpvD(&AU1 zEWyR3KKBR@=CI85l~JsHYUTwU=>rgZS8v)A_C zmhdda)y|7)0rhQpyO`$Hv^Dn%G|!b|2IDK5Kr5QtE0mU%H5!MOhgK}n zCL|G73&uqQv*48-`0|(O73Pt1_|_XaC%Q7c!tezRbu7rLd!nli`Wse3(bWoO%`dGj zs;Hx7Q(qoMSGrdiRzppu+SaPlc=?uIVNzsXq^=$g8q}QR6{-v8l)@9evQNWGVy=MpJ}S+ps5JLhX_i%*gF4NAE6r@rkt0 zp;kFTt+0n`a)#QbL)~Z#wZ#c)vpv)%XQ;b$sM~F!_BlcAwTIf{40TY4dc+p$VJE1E z?4cfXhI&R=Dm&Katw4i&V83OGUe?4i8QPy=co_y)2$sY{jn8nOS3HhVA-RJ2A7$o|zS9W{fl5 zO*+&TTd2)WP@C+bHabJyr9<6r3$@P)YOg)i9%raWb*P7Jp&oLAde9!~erKo`b*SfT zp$<7gJ#7#5q%+hJ9qKJxs5hLTUblz(yED|MI@HIuP#-!$eP9puo-@>sI@Et`p}uv3 z`r01qOJ^t-ZYS_t07q@1{&0f&%^vDkXQ?sMFP-o~+`LHwx&+Q_47> zFt&82aA;F=++pf0Y@?fY*W*cFs}$UxDOJs#u9|zUZtgT&bEi6)JK5gcNeRrI;S;8v zeU90%O1jUOa-NMNWNu28uf5=MrKD8)+6gJRX;*kmHgvkqQ z^;>q}x|NH0+@yNEoWG_lQ(u>=^-FwwcNz8Z-Q{IIw!0MP>#7@UnW=MPrq-UBY6oUS z*QGve&h%Ta1)^&aL`^%&OTbTMX>}=XGwb)}MArfzHbHaolpzIyW{=QV0=O3YgsRd7 z6;-%bY1DeL&t`Lol-Q~gaidDi4eIL_wf=gQpv@{l*Qo?uqZ72omY~&61g)|sXoVv| z*AhXvHP5{qBDywO3HqBYLF?iO8bTw)waK2K4fX_yx581r$n3E?$~JGiogCe1@91{3 zqx$AebnS~Xm?DZ89a3ZQv>KZy)z`<>`h#kW9#doVs2ZaO^%&h}HJ!~y_c)n;m(_H} zoOp-XbbU4wT?ecodDu22N}Pv0B#+pKWWRk#Tpy}_f1vX4p8EQZTK~4n#}So}f2w@E zrt|TNEgvsA@$rH^AI~}R@s^d3H*NWNJ&q4Ph7a5G@rDB*KdF9y$6v*-bw9tb_46|) zKR>be^J7OpzkyrUHHaP?AZc6r`O?^ezlv_Zwls=<%MOYq<54H0{;)UdH%FtI`OQXA zj;Tgvt48%ujq0i!)ydYV4t|GiT|2*JTgOL88^38=XBZ*fEJjhFRipA$qxz{v_0f%z zZH?;XWK`JRsGy@!eJw^Am^vHA&;zt-+^CePs*xprzFWqmj!;Irm>;6k!1~krWy6nyetle^~I)oFRMSp(fsj#tPD%(Q5x1o!6Ujx`)%&f z6r;ascMQjLhj5(Z7>-H`N9=K+ z=$c~}jw)+7B0L;6H_R%W0yWDvP!~D|YPNl#=Eet#rJSqWDNqfLfx1Qw#9B2FSMxxK zEA;?0Sp&ePz2%MpSn3dfsAB-u`0ekDU1g>GN?ZQ$p+LJQ!>jDb5L4D$24Bj$cy6$V zzgtb%JJf`|P338y%G0fC!rr1L>^7aR8*Ta8;>g!#2fj8r^0mjBus1spxZ6tLF2|hR zVN2~!duq4aQA-oT?RH#>kLlbTuyVuZ*8Ps$C=T2_VCF_JJU@O#2Yb;L?0HA9XC1(v zaRz%|2YbgB?1&@SVF$1`ox#4EwjTar3-+5M*sl&?KRbhE z=wRsq%N~m*NLs*Y@of>XUwoSdOdA?wf_QYW9=2fJ9KpIcfOT>P>#c+JvIPq}f(0GG z0?uHk>tKUy!A^Aq8{h!e&lzmA4mQFTY`7y>p#xZfGuSj8Y>F*di6huV2e4viunTpt z*|uO2N3b#nuu^BR1v*%xEm*xH*hLOtHO^pbbg(OJ!B#qgUEu(Bxii@HI@l&#u#Jvj z8yvvaIfL!d!FJh#?QjI!<^Xn+GuVAP*xj~ZcRGUI?f|yW8SHT#>`_~=1CC((9l#W4 zuorZ&XKlfraRhtH0qhB9u){jo8@6DtJA(b)0qhlLun%>x_ie%6bp(6c0qmd7VBhLs zU)h3v;RyDb1K20dV1MXf|Fs4C#S!c$2e2QU!7?RnThL0fTdC6}r*mslbyl(>tKCt!A@}mlO4c%IfI?4 zgPmpzHpmg|R0psD&R}D7u#vW4MUG&@9KeP;gH6%FCfR~ba0DCg05;YcY^Dx2!xrp3 zN3e4pz|M9CtJJ|NY{6zbf<+v_%ACO#>R|J1!5SRF>Kwpooxz%Puw}MjOB}&2a{#;4 z8Em}{w$>JGjU(7<2e4JnU|V&t8*IU@cLcl60qk05uv>MoJ+@%G9l>@wfNggMdq4-f z*B0zz0 z!CrL$d)XQ6BOUAmTd?;W!QOEIJK_xXoeuW3E!dZiV4pjHed-MMyAJlNE!fYFVEE}L z+gtVDJA%1d1^MHkRQ@Wq2x^am+(F9*h}{=;1)VlPLeL)kPcyiv-OHl;X(t5*_0fXy zS$RrYFu{ixPzm`?Hnv_6EtnvOcwXBx43)I{!I{%U(a)k9hLu&1quAx94-2M_%Y9*VBMLCaH_-Xv=C zd4}Ae?dKW#1nr)sxbaBMjl0fMR8J?Xo|dSdPEwgDR@=v`?c>z;u__ZqIunJqOcXdW zG1!5LGaQ*1ZDnFa91}z6L6~cdJrko6G2vPWkLWqxeAV-M{_47jGvKP_47h4k2C7sB zO2Ghsj(5J50d^~Kx+4SU#4*6k7pK8b!v%_-?V{_#pyeYlk)X|Uyt!7MX2CGq=Xhm7 zyXSbbRi*LI@#feQTOPE19#RpEd%VZvGt)K@n0@NVbGyfTDeKi}T%$%~ts0H1)o5I$ zM&oil8cVIwV6$b^F&c{+3pmXyW=CnKiQD-ni`E))M&h{M&l(l z8ZW5Pcv6qXL2EQvdOzwIjROwR*zXvP=dICr)*-zQSp)L4E$`3Sv-^xayH7ch_-Z_f zNbgTo0zXuVdLKmb&zHVqOVklZq7FL{^`_&x^nrB;LbIIuk(HyWUH?_>`dPQ@2V1-T z<7n5n4t9O*XxA@RyC^+XyE=yWF0&1P6*EE_U+E#cU1nOyX_wg|WZh-*RjgUae$OVl zT8AuqOaouCYF9|LE1=tzZEKgu(XNvn?CS1lmt?go#+Q3EwRng!s;}D8zS; z!+5*9P?alC<%XzogH^dRRKN1!7yqXJsUe|!eoN>A809 za8GBNn>Y!WGv;#(U3IFZRl22fL&C7q1{^fN5AhL&=sx;nIF47S4&fuljk7D*K?dq2 z(kY-$bkzc-(!g~d3j$zPs4!RX*OVsp{W4CRYbhtrwS*HVF4oOhWKY<|u&#oA###MX zSYI+gTo8)?Xt(IP%`EJb5LlxNthNylT~~($^;8%A zGuY_0QSY@OBvg*7FRHAeLz48!U|@t~X(n#d51O(CJM zrn084q_(syGPI(B4IzDCTnCM~n8gsH^BT-;n?r(Xf?*_GYg8BeBwVy5f)5|I=|0@# z;KL2JK3t#BhaE;x?t@O8=-QdUhh26)Y&WX2`p{B1i5-t329 z4@9=-j~le}EfGIJSe8G%yk>4=RiwHh;%Tfd_e3hH>l-4Km5tT2Bh}OEFK(PWzfYe& z(<2pl8}XEvHbg2=PY0#QxxM>LudS=OFjCe~KYd4|uW=Nyo8UEn5iGw&NsGz*l|PKO^B(L3HO>={zZulckbQa$(5STjYia znM0VPD)A)ulwT0GSX|ZRRPsq~5B`@1sTBLC%c%jNmY#PBLRu&$LnU2K4Fc7TMY#JN zrc&&mE~f^9TKve4%UYNnAvsViQ@&zJsLRhT%%6_+VRl_{=O>IM0n3PCoR zVrq{GX=U#@LZ*1eq?Nb+=jg}lzL@djH4k2zd8F8kXko5z!`-jHGd^@b!B*4T|*0FO?5qkQXVL%B`FCN`{S;Mn!mE=q; zt8378?mcU!chBI(8RM^dxrO`9AHQt-U~)R^8!*@zk&CC+uK)O#+26RvTz=hc+e=(+ zbJLP?yncQy4(Du`)w`m)5@~mV{LbCyRV@7ONXw=_55K(fxwe;{l$6@aiYjbYxuyT; zxo62cx1H7D3*omw#hpjmE>2Em1CEkp3a1u#z2(rwYu`F0ZRTl(pPe(MZEbo|HqK`n zx!+StS3J=6o`oOIT=;J3J(qv}XxmGZ(`itdI&t;lvUY?2Hte0RPI>>OfB&oPeaWdr z%#laT^USC7ZXP}A%ZsM=dSv%a1OFCm`v9fU32kPzvCF0)1|n{K_>q6y{_b7pMt(kY zN!#z{wasjo6uq#!vSKDvdFJZ#w-ubf>bExa?r}LcG(OVyjZR6a#Idt;n8K+4f`YCq z-dxpXO-h%hOD=e%ZA0gz6vD>Ry4g(Sx~nT5%N`M~y5rXmSD*Kv`#)~mn4HS0NL5YU zLZ)(1^Brr3JU{je;o6VainCHLZ+kE~mG$iWT&8mFoRJf71peOD{W|=7&pp5V-1f5` zNjY9d`vRu%k568|@c!mszCQ2T^UiC1@&_NcP0vb7V`+VTq^^Of9OJ!lRWP^3#J}HP zvF_2ETR-O#-th(o51vstWJaID;vpl3jvY60#PA`5{e`2nH4o*{g9j8e&?%D*g9kL! z3?49{w4rRy*eR0-52zU;ENw2h#ok+Y38{FNi=(AQ!6kgBD;-ueWMuJ#!s5bFBW<)o zcTxG^0d$F69jUAzJfO5LGI#*irNIO0Rm}sq=Era_qbRi9a>Ap^v{lL!&wujegPC1_ zfBDjpOJ}_Fug2#yTI1kNtof5`iYgXF%7@idmD2qdv6gz}}>_;)yz zDGC{#c$bNd6=idAVP8YHN4WeDE??Ri@(Sd$nLN(KB#4+iouZ5HWHoaU#!%j;s0+&7 zapBMfeZ)>#B7JQ@?^aUU&{&6Epk2>@Q_p<#3{p=Idban{(Zp3X^CH75BXn^sENwxT zKe)97TJiEpSNxfSF4-f|<*5uYqr2XvZ!sNONq0Sj=p9^qS2vU&hWN0NnJ%%tSIo%K z#d8hfcXRPBJs>^?*EiK8GgBb$$~eO-OsI<#*J4h_F~Yj~Ox#O?=%OtA>41x_GFap4 z?iF*q?u;=wD-*}0_8nMVQ`>hKcfcb=pTzAENZ;kfpXKP%4G==cWTwBeqMCQnrF(H{ z9OWcL4?`Lk=}f*{lZQ!t2hOUCMD#ARc{uU{kfvX+IE`Fx(cPU*&N=atWbyz94aU^FFTxz>fjlvd)gVADL-@* zf9sYq2Au8o3e)H?=#tW^T3mhf9mr|(2+>P88!UWC2sP}gJh9Pd(- zi!LX(!k_D5XS0;gySd)+y1s**zj=kT=2YNlWxx%;2p2+n*Qa^c75V6u*;)|t8272! z0)`svGOhxf$BNn2EJd}PJIs4+I}N@5hF;N10H&mU-b(zwm6(~~8j~R|%5Z0RTooSI zi(c_JWaF9Hf|grD7fy=Q6JzX{b4p_m;==Q6*HCC14DzD=T=1dODH&pJhU?4>u^>Yn zmLb+=G@GB{x-mn1Jj3-=hU?V~@rw*`Ql{&p9KVw1-;*(;WN#Y(TZ+$-+(iVu2S zso7%2GMsW#SyKzDvCkq@ZLBTfVOlyKfV1FK^fe?O@|yzX%D6F`h6K!n<$31R_<%F8 zU=sS&!}Mq|F_4m(LD|tdD<$Izt#6)P>V7^AUFKoR>cCT1%y?Fpx5?bPvmyQf#5hni+t@3#^^Z{_}_m56lgk|DC#xCbBr6quA1EHHXJDAPS6kIKrpz#uBi zvc(&-#V4}GXS2n>BS>?70v{7aHe~)`IeVM{(8s{Wb*GC z13J2>~%{@|THxE`J6U`1dvIy%uru>{{x zj5O#L>a(kxPihlyM4u61{OJ$dnx}r#P5h{b2tNDy#nb%aFuyp(pAzw>WbE?mV-(8j zDi)|VuzA;`Pm-7IgsR(n;?HpCYu1uQl7`@-3~@c18(+_GKif@wr5k~~>l2sw#f&1p zRhbl-jo*)m)Txs(8~551EbNeI;eL=$idDCw{9KM8Oq_!is8^QwykC3~MmBiZo=2O_ zCsfqZ6iGV<-n|`ny5Kf+A0*??-NKyAX3a1~pW$_#nT?cjz33Oyg&cQn!<@QEX}R`0 z5kfQ-3%k2ZhJc;eC~Wtt`FI;wgWYFMH4a*DqGvhKSb#mPfX(f;mXIu|n5~T&+DftG zjG~?41D+JW(HsW$WtI+BIJU8Y zJxs(FuRYxTrW>PkoVLDj4=1Q9A5VwIDWj?z^2Rq-&BWLeJn6#Itx&1c1CR>=;_hzc zZCIqfECToG$3#rTxyLY3EpqyRB5s9fAC~B;!gVUSWUvjf4ULs$?oJ>C;VZ3F8EK*? zkkH}fe0|h|`KAG3jF{4{6nAMO$i;fh7#w>b!%i1Ec!)2p9~sD=&M`($VT=Y?_%w-F z1pBkrr-(MzWnh1exB_=ZcV-SvJrO#Pp4&Q%?))Mlp49vF%hmb}aj$1ou{2>z2OpPu z=Mdm16E~@3@n##kW;K*nxwG-B2XhwI)->RRDV{pA8s|s5lfUdH<4`;h1BJIUM_PLM zl-_rsmNQ@oA35;qlTDu5@FQ#Z!Na!&y1c@wKUb?Y;rCeWM~+#UF1#OW<36b{A0TJb zg|}m^dLGuR5=WTC$31k1j4_8}X_z0TdfJO#mtRymk8JH9B<0%qhX{iPg$}#un-DsL($|{G` zU2>MhL(u$+8q+NnqunhrTHq7nDi)Fo` ze&|B>RJ)#@YU|w^VFa1cip-$(R}X|fn)vS4B|Pu<4~xtyZLBm6KcT6);BtGSULo2Z zAxUk9xw)B-mWy3}%=IbhLiD7DD){4pf$kdEK0n_0cHH>aW21y+fi|{e+`+9X<)$BkWCC_`bJI?hY&g`4m%EQO1&jCK7Dp5Gx@% zoAuq1Qc^GjH&W^*vVM)cy@MQ*(JX@X!-aDqWpfLv@hGsNE>bZs!d&2U)e!jLRYTLy&6j;PL$Y7Sa<8yhua5@w zRtLjn?P)e}Kb|Vgn5R8SnNc=_?nZF`nz7j=RhXlaG<^Ip14Rhp_iWgyhwbPHIzWj! z+IqV6on>hyKCd#XM&IFGNy9sn*-DYobzsaccOgmO~;pC@S@*uTyJB89mZk0cSrGTHXS)iyLtEHv6%6zXb#?5jdGsbxG1`ZF==fb z91&@lfN8U4EUsDk0MWc}&bp@xTh#drb5|~AIlK95L2hNLa666Iagl~OHRXokIz(_U ziJ8X+L~LGCdCpP|T~0``PktF!_?8r~m2opp9vfC_+G!I`mYWu5brm|0GQVt2X&t@u zx?hc1!jDT;d*(0$+^@uDPk#N&N7y%f+MHzKP2bGw%k*lV1#=85te#1kYP6r$Mtp3p z!!HIs>A2l_F2S^qG^RN}U3gZT!DeCmKehfuPS((M+T}FXYR>$~0M#96H6NEk^bn=XDW-t2)YAi!$Ag6<{by9o zon56}398qLLDj`wvH2eZi!z^4n@!qtP1;RU@+7Xjf~PAEcAKE?|JVl_br&92U8rFD zA==X#_rRYp$N1+XYWcdUO5+g<_I&nt636;o+) z1t$*ETz{s?SvF5-KL*F=n%CHxkS-jxyKr%LWZez-0{Hz(oe6#;AYHgA?uwzi8y{V% zuA$+JOnEQ1AJJ!g^Yx10MS_*|<@*W!nz6y%8iCfstj%!hTabw+`#fFK)AbEwx^w63b zeD<%w{Zb4j_8DDz0I4sDy%=DsaFd#uv~kYG#<{<7$%ZF6 z0-mu7DZN9ux?&$93VYOtsh)-!kM?}UQ&a7!uBnzQ8yh_1CJe`?0l!110ftV2a*y_$ z)Pu*QkZ$nQH`dapr6T3jT~md=IQGqjTefc3^Zrz~YnPvuGTkoRm#4bUZrmHgQ(Mf2 zEwG3Ss1n>QTAv#o!ptR;|M%~I4E&FQ|1t1C2L8vu{}}im1OH>-e+>K;1I4cUQi?^P zxL>PTZM*l$Zhn$DOiWKtX`R^_AClYIw#U%n868uF*2S*-Q;J;=;Qxd8ui*bf_`jdO ziqWlrVbx+@v8%nC6q1lQn8}Oni(R>CRGAfZXKodWJ<&fk#1`G0A*oNGq(mB&RwSRA zCJ#uH`=yO7Zc|b$O2uNZSPV(0rAeoz-`JCw+IGZbak8DO3CJZ+bK&V|csepoE=rS!rO888 zXZx8Q8ENlGk-?E+x+6mkjxa;V0I5F=#jB&Ce-)E6VCfWCT9PJDOp}Y#W@P;A9uEntiDt0J#)u!8zIg`U_=3!2KWO!Vk zUL;?X&PQ7xX-@h98Vk7BPDAOU^rpf!6sI+wu?1A0-+*4ZupF<)Mzam-0H9t1)P?Et z{B*fd#U3ct0Gmc}dxBmVgI4CJYs0k>wc2oHOfG^wr@|h*YD^L*(Vu9Z>L)C3M>E=` z$3l;p9qLj7JD0-FXu7;uHFC1#NtIMVNWg2d7F+}iw!nhTDtv=RLMIamn`36EB-{Y(c`*|3HdzxE zz=Z8EVQad4qiV%Msk@Pctub`vMk@(BV93QF0k6qgum~3Hh6OuS_)DcM49g|$aKHt{ zV5boh)%iCAaxozBnk-~AiWvp4djY#gg^eyjos?~a-eZNn70}V8kOMr*Ny9Ja@V5hg zp9X(9!3R|MUgY^cz^|w6%=%PJMDY9$g2#tG2_9t?o-HBKKTypVl>%%IA;|Y~tcZ;q z_JHD0wjC6E7rQds>Frd+qJw>+m|N_6qm$l1#kMwEKhrW~p6RGdbUXL0xO0&_uCqL* zGhd9NJIKB4&V0V@P412BjLCHh{wrg&5}$7;bcULp+)b2|VVPNSGq+?4EGg+MPt+{g zLzVk@W8Cy715DL(c|2@>sLmJ^V8Ggwsd?J?(qKd9X^6aj1q^la~ zY*Z_euCzDjTXxmF@~+&xL1f8N5L{KH}*DEBZH{LanokN5EZCiyrP&>S{ghx3G2D$Dw;gcXaNITwm;E*4W}cM7FxwMm`xC&tiDPyGW(S4| z|JkVRlGSg;ssgm)U*1q$N$t7(AL)sqkQ`(jkk+ zdY3HfjVr#(3rNN7X0iR0&~1f~AoKyb_TD17t(VUx4N^z1($?El_-42d7D7L+;@A7(ccawFt8_&DdOu}}A1P*$n5TAA zIx#7&<9z9mLiX3*bZtuja&Yja#z*Qdr*|)_3*FomB@GODB7k z&M@IY9~mmZ(7nB2%$s4rT_$CDS*?0i%=RGRY_D>1%ws->dh&c;+(C&h1JUNzf`(M+ zd;#$ss`OXd$JyH5yrYxn8A@ z?uksETnAO*TyJ=QH(uV8H;_dEUosJ-Q!D~z=AdZ{q?A+QG4tXu@dXqijB1mCHVF|j zCd44GS-FjTPqREF9<2`M1mYIP5@>6j1UD-tv5h2n1oRZ6?c!ugFwQG|crB%O^ovdyrxSyy1cLmKGmtU}(RG6hn}bPBB`gkYZ;b#ZJ?b>kiaOgU#tg z3zW6)9@K>kSomr2k%pMNJjm-XZSeKyPK-^O5~B1Cmnk%kmD5;qg2o4ZW4oY2J8B~L?%GK5BD-Y~Bk20hOXp)ownJ2@ph)XRki6?nsilr+y#zrp%wK9lO6M;(#| z<)oA5Rj5GHj6u?j^2#H;@^CG6{!V}+5Y=tCsm-@L%5c2BoKl1Des*Rr_vT{FrC7gC z;-k?1c%UDxT*IjHAKbvPCt%7u`R< zuNNV|gGRi(%U|9n(X$OXoqvuue6Clm5(iMehR^XTXA{55R4BZ!7sb+zq5MNC?eeno zrnAxUFK99dWJ2JfUc4XC;&!uL;jpIyd=aCMT^YptKzxl9Ctmo09|Py{fHX}tfmFFj z6{@$TD&raLv2I$^zh@GTQg|!oKD405ig1 zZc8*>iLTlWP}m0%74?%iPS5j(&$n=TUOcC?5zsiD!8rZQZ16M)JVXY)6wj2C6VuUW z4O#k;KSq-p42@l70%!!AEXWpyV<9*A951Q5{y8W7d~bLL5&i|eb%m##K$d?C6&Qx) z$nu$9`2sD)zeBY&%d50ijXpT5%+eFr-~}SKELFLHX<%iRGe0Eg zYzTmT=N}VvHbla{^Un^Q?WKQ#G`NkN0JpzG1-PvQw-T1aG%!m?^&xG*a?&efYp6il zEJxZb^~zDNyx1!*^2!%`PPmOy;omruiZ|$R52H` zVUST*W6N2N?o8CrhotXgDNA9TAG?e-bn&tkBOIeZIhN&Mj)BhcA#+(*FNzpLy(pNG z^raz-Tzn|t+3Y(X7x9&f!8wP$WHNFVB6E#wc`#1wU@LN3=zgN(=ZCar=hD%Jq07`6 zrE|4sWXmX0uS$Y}7<_GYXzOu&$XH3PWxI#L_%g*53WX{M)_v`8~)8H^_s z7LIAO&?~k^Xzs?d2)(D(C9KFIf0yDXI#J|FA_|J$z`s^8uJZ-{wN~IWA=TLREWQsT zVdi@R|3=nOlu1fH1M!BkFZ%m<@mz`37p3kl&=*Lo3-rT9e3fEw8Txx^xiY4Yme9ag z+h{)+;H8~i&NNqLGD4$0;s~alv5LAtjIM+6>lEX9`WbhmD4|(7&xl77P{2TTY;t-( z79^0~Z$)}vr$pB((bZN~AAy$0dc|A^r?W}d!x}}>!y4tHX6?3D4D|0;<@(nmzcl?BP$KVDvb}yM> zED_ou0PQ?xt_H>;S1nr@6w$Jb?XmU3_N!#=5c56MW+(Q-nGy6EHfU7*9>rkP#}oAv z#E#>ov}EC;V1o0C9=U@i{ZHnAJ<99Y4rFRlnqr$2<9?rFo6;4dd5fjk1Eknw5Hi<7 z4NT0L6-YUzMx?;Cp9>+JW-+fHHYkIBA-3ns7Nzm~6@&3O89XR4$|d*{zm3>VK@|cB z*G&$f3XnhmJ&XW)&F9sjM?1#x|G_C{SWg&D7%u@dpGE~{|ogL zR?`4#K7tl!c-_pyhRJM_%rgLEY*r$VDUq$M`6<;C=>!o`fIXd9Kk5#=ClupJg;m*s z_k?0T$^!2(`m4sCVtMThLOlcw=*F1Ac$iek#bNE(W4Qxb?9@w(xA;Y^AyKzrA0z&x zVmw8{&q9sk1Ex^w2+zIM zO|(+<%93#GU1s9*0U!CQ3tzdtipgT+-_*DGL1~Z;kB-DNM-dVOW8+F zg!ERjFdnW&;>5*#To~^vk=GRSS?J#Cg`>1_lv2 z(U&&*ij$lLB>L-a$^qK(Xp}PF6WJT(g+zI~n=->|lyVN+ZP^>;MMU`xH{}ENDs#(y zqI@Ayev?IiigpJF!Aj<93jXqgIP#D+Kfj1zclcmm&kTDp!M^2#-JTit5`ul(2m3~5 z*rk9qU!vJPi|_o{XDl94m1hRsgtCj_bpA}<>XR6Vy#C(JNYDmcX>@~QEf2kOskrvnDhvTJSe(Wpe zrR!0R)*ETq$djPao_r$(djBoswUj-qIuSw?BT&guFvYFgACkv;{CbzB0 zqG@l|WYOeUb1j%NYu=2D__vDj6-l-ZKOAey`LXYqHE*Trz1lDKyqE`G$l$8CL`BV2m%x7o^%zJ?88XIX;5?jOOP6o_S=q3|BeKVh9 zV-Kff*U~`2Cujdr3`X}pAvT|!v5{;Oi5)O--QIQKCOtQvwq$ zQ0Gw;kw4vr_)9VND56Rj;xEPglj-&oH-x0pA>(5}HGkpSv1X5U{BZlXMw`PiS#@0X z2buSA5H(~KGp0R?A*ra@j2Z&shG9TYpbCb;b(0PAEJ(mGIqLA}0ctd)Mgyw2BkG@M z0o&(z@jNeHKoMyRVQI?;QzhKi5NYrId5GsHD7?f`UnbOQOnqq{`7|b~k%LrBV19BQ zkysLmw4kab5i_JNE?J66G5(YmcXAo0IhkTBNEw~z>R)L@^U{gt3Ze(NiFWZ5eVvGQ zQ6rn$MA97G$mk39LL7b80A* zERA(#thpbVK5r50u4?2TVwU|p5jh0xq#Xv#%geUBq!36Y@wNj>3j7CVlFkoT3!gc< zR46U(Mn-#^1orUC$Rius0Gp6{$R0{$-$^6uQ=xIuGmyM@1&=nsjds`?gc90W1oUZ{Ocplx_8^@WE= z#WmH?RaRv$tTfeZL+&>ZqQ7dafN}YRP+N*7$S0P$d9C?vOQ+Jho5vc*wm~RqPQX7? zh0yQoPOEjmwS$(EScq9?v7ds|_)uI|jRLaAXY`X+2A|_19#IXh^%o?MN0siX(Zi=o zcb_T-5&V)c(=^F0JkR(&RD)rE#l$fpMCm(Rn}={;^ki1rMYIe3zThA}U;Id*9tC=- zM%1T3FG~T|A=OxK#$`959;QbA(+W%T9ax$#!P^%R6QQ?i+?6~TIL_jG zGnOk411rDVekQ74wc^Xd`4kQ|)DFJw@(Uo~*r;msChPr5KgqGb;UZq78r+2cB|09v z^ihqzKD+es*`*&5{GBk<^fI%m!X4XJH5m3EOdO+#DD5FiuZSf15~Wtw7bqb*sS&JL zibX83(rnKn0oVLSx0D=kkAbWw2T+AE5Z6r}1KWTE#=v7R1|FqG<7zafMhB?T!>y4p z5A9IlAYQcPMLQIcA?Wz7k#LyjCs5jR*n@d-2%(Jh!*rn9QhzOd=L-Zn@uD*?y6_?& zMP#uUNnasb#$YGDjYcW3w0NBAZI64~V<)J_IB>L5;z06{0;uGE5nlvJRkWuMfWRU8{wYPSA5lV>~ISfod z6E6@Z(FTDF-;{OsF4?%_G|+yJ;|&*vYqJS4jjbD-R}{R=5=Odsg5NVmBp#*h~T&egkUejVa6^@?(=3>0%=N zu;{g~5?PMSdt~v64Cp8V8mUIMSp4(+fPA6|FC0yvv&97K5HjaTCJdv;+=Z~ZOc$0w zEp8s8{8~bIa|GUNAdjAh)*WnH4mZURj;*l384R59&44@v7siPyJ1!YY*OM`=M*XpL zJyDGeRwFlAqR)j)yi0>TcG4ZE?yI+tMXd7EF$Xu3-?>9ZKn8QLa0q3R{MZz~`$v(S zQ&g|rIF4;MOnoxh?RX;ZbSAQ}oEtlZxos@kBB!d6p_cC1!)82zz6v`@z|-L>vA4D3A#Q-jeJc;!FuKb7B{$Zr2?E{!l7`{ zf*c$xO;|ki4_&yLxvjK#Dl@?hkTQq3LLeNg@;RHg+Rn}r@YN(!m1++2(3<9>#anG! zSqyMG(E@5;(dWidU*-7;sG^6R0U*|COJIXI8$@bQ#X8q)A~03;DK&~ z32TO5h0}dlE)^J79bo~;Bdp)0NdQHTSMAQ$*w+79fEAgECxiUhOf^#GjM4m%W)8sO zwW`6|YIi21O^dA*L|}n5k2L>>YMjkF%L4p@fD3uCh!^@MS01}woFTmt}o;9Jr19dRMMih|? z*>LNe*35(T`OQG>?P;8Su6%C$yN>`rZ>ef7 zQRy^n5os>Yj<^}vk7m|^;-dt8sRg~1;V{|^EEKfh9w)eEE=}W?smA51sFM4G%P8YA z)m%pWI3qQ-lJwXNOqW;ON-$ts3C|q|oDdVjWKxC9OG!BHdA{(yTs0Vnr%1M}mb!!_ zvYEIowT19tsl~R9xY2?qX0p`N1nsjFqwTZQvjn$HHCY>TZ2U^qxXNd$D=kxHidQzn zQ)5??`ThxV|8LB9m1-~!&w&Ga{lfj|^{;>gdi_o4^*5-|>(uBqR^Q)>7HIJ=UTovV ztGsv}MdTJW{l?8y4(2~>YIhCN!vcD|ov+^BWe*o@2cCHgTHeJ|0%*Z3emx?Su1csf zzKRU@HlU34YGk!LXg8?F9afbH+6}6?T7*b4MK=zsv5l;^?<6)ifQ>bPhhulKhWAMB zHAI%3+DANFh>Vu|5l{?!%{hmbteR~lT4b$r|Fq4h_Z=PqoQ3Zn4}Pqd#^VEr2SMx~ z4}QFu#^XcqU`xS|a1nn%HMj{sc39Jq9k)+oRAauoZqqc^T750AMTqU-!>qgfr19R{eI{+2z`QvF=^y;0TmKEx>@=AyVXn(SdbgJ} zO>S|NX5|ub3@g;7=fE*x$YmkkcQJov>nAUPR1SV;Bq9{cNaSZfkx&*QLWPV(egP4j zecquO8!60x^U@@tUJIK%7h_JjfIZ*vUoQ|%+aE0y&Ib^`S^5tL$d#J^Bz6G{<=tr+=UfE>@M(Pu3= za!8J}r&pYD?Kw#DIPHtzxr%39Qo%@gI^{)jLUS%0uA6M6c3imEAlx=Jx>b$7Y{_>p zTEOEFUUc9^M_zQ|MQ0R|&s1|86BX;DciHoOdQe<=qiTi`esx`2@9HHD3lP-y@Lr zeppV6zVq9%mrjHU`VBWUOQrUmxg@Xytq}B^ZfKTMvOsGD{ec?!(5<~I8*W!2ge8;p zMB?BEQrA*hClVj2k&nG3?5y|3-boY?iBHtXr(P0vc6)R0B)Suc9d3M)!n_*rgEOQo zOZpy!_m&&amASm4r{Nle`?eR?PFP-<({Kw37gqm(aD7j&|CXL$R1=ogrYSF?FRB%p8X#2PL+nkGu z^S?85{*(*A4DB;n2G08^uFW|P&TKY(Brf9Ls|GXfQTQQzAZ)%%<<_@+vWt9hG{DFQ z$DsVbg^Xlk`IOgjC?Q*Wi}t|%?6hEJdf?8&bHx(6X*XgE<2VuJ1+ZM;+x*SKLVtf z501k{{6DI}j5`uPMD7tj*lqbh^o!l(gHZq@AC#g@^T9s$NUsm}5y|$!XyWYnfLmf8 ziTEsWJdtvY%0pU^+SfqxAhEG1bIxZ8%vPcdoS6^C;3EE$YB1xD#Sd@(|Jlk#!Y4nI z4^99W`CuH%Y(Cgm@jd3-8Ti{oO1$g*f|NwvR-7J@6EeVm>$( z7xCXz<5xDXDkly*Rj3C(v|eDl_U>8yX$;W-1{{a}gEWTGO`*poIcw6jCz*@80PBVueUojmMFTI+;>8?ZoQ)#V7VkczEnI$R6>0DJ2|9B*>^ZzRmlyxw#d*A#hr)X&)*jf> zxi<(m5xe0c#7B-;cJOFgyA&Gpp{!TtS#Qn)iM*M=N#+&_Q$V zPPf)@D}hJyr0}VEX%Gbtz42iX!BaKevyqH6r(4OzBYRiu3qlJQ!c`<$E;lE?)mYUG zO=DH|t;VWm=4#++9tcOIKRm26PhCxvnhQus$2SEcA6PfP4#ZQQ){#Ho+&~w`&NAuX zA{@rHi04T}IF8>Bdrd|L*o&c)Rq9juvF=*D2LhUs3%_1o2u{D3V-2L!%U(H}5Y=8)G zc2CVHB#G`!Q|)lg= zjAMM(IJ$8o3}i-lnxtsq52(nmRxXMm7d57god84{7a8c8jAT6-s6?pqEU8mMIv=AM z14-xS3Aw!%=?{YHcC@FLiF*eF30mdy#8-W*Z{tzC?6~Xr6l(BNq`#x=A+$ zlF%FB_-7ASPNiLIXMW&nNK3ZB4uc$x1ypW~2f)4}&@P(EZA{t7 z)lJ|G_bVm7CD_Jh(y=mT&F=vRId}2m2f`YISjGK#bmo=%h;GR1jBt6Mp7X*Dja_h^ z={`){l4x~Gk66HR-@fuA7?@)~!?}Is1U~(8)*QP5W1OIQ?_7KV2ZnU#;?q>(eo#)s z9f7Y=3+`O>hw;xK$5sHp;37U=Gs?&@zv2h2Bz{AQ;=jE39Yth<=DnfQo}SXZFxbRr zQ&X2soXRE}hu^RH2e_LPU>te_C{OT{{l@tVFvet`as0P+avE;qShschjU(Xz3b%ER zCzAwmZT{)Ht@9+R4N)y$l#rtKZJh_8-Z)9~t-^3y=gBOta?tF(t+S)Ek}+MY8jrt< zr!eFeKqhAVDN42w%|#X4sc1=jr=X8PwmiB%S@U)d^dmr64c~vZtVX9}Z{_)vo%4UnZnY~! zBMcHHm|89;TY<-CYsQ(Hs1oOsvo*7p24!<5D1B<*6kxqH?YZVvc@ z-aL!jXc#5LrFDSL9|6am?$eo=Jf+eBW)TR&b!Tcu9l5UWzR_p+X|(#KA#3Q%WUGe)&&L)c;11RG>%?9LeLH(l8%iYyXb7t;T*Q-h`HWoJXBJB3KYWhT6 z!d_K6h*Uh+9Z@OGn5T&<5m714JeNh3L)~Gn#^$q#DsgM+Vb786Aj+x`O*tKf0=PX7 z6Lg2AJ1m(vHbp4O-b|3LB!4&KV2Fm;oTnM{$VysU=Q)Go(>Q$PtS`$@5>Q$P#f=SJ2sIfH+wR~TtW|7Y+ zkS6TD67T)PjJk7PK~myAXjbdG4|)mW2{USDK-(lB?teD_Gzd1nS$wr-tf45Ypr7u**euj*7bUlNvgYoM%;|BV9x+5zxh}HAXAfSMOUfAReawbS1gWQb_a;Fx( zLyO*SrH?waMDEqhJK-<(wr=+%p&pG8E6Izq2=sn;_&uN*4{D-Hgx>?2c|QxkdqqOA z@&td`|3l0tXA`AOnt3~5@Nh6gux;+VW|M`Mee2&`Aenan177lCm<}(udu<@=bsj+6 zq`B|m<9AKro@whW?HurcKOWSKhsYo2($9c#&wf~bK1jgwn_>CKwCE#R6ccy$Ipov= zv_ziN%*QfWejyqmz+!^g;x_ryn(>S#s)Wg(*32!;tE&^ki^cl@~mP~pv{R|jS?1xELfCNnX zGEDlS7JXie{?jt)WoU_P)yx+ylVZ=&UJqT4MhI{P!ECckN;|HvYQ}3CtFli;Ue(NP z?DS_VD5anNyv|H|B`BHCbCWV?TYvMP+)&AI{R|kd?1x!y z0tuMqJ(%TPE&7fYeM^hJsYSP2##x2-$OllIriri$fA)4YYQcXEFV+&wXPUVk^7{`F zZ>F}-9en=Y-gO-D7Ha&;Y2=%8w^Oa>1siXHu(K^&TKui=*!CT7d+Zy{_?G*MZK1qR zw%Q1)#y50zCue>avH4Q-y}02skh0!j0d*l!{CmyVr4i)w*6#6_v<37fAYE^c1*Gx4 zCTh94!m%Hi%kL&m-Us;I$W|}l5AcU$Kl(+#heZF8R;0T$;|Ee<6H)x!zq`z3XZa74 zEXQD`)8O0Sb{bsUW_&Sa_kjDs%lw>~#hM=N_DlE>Nw`}>prp@V_>|1ywC^HdR*d)b z+Cld)3Gx91u^zz6kNv8}eJ!g_q z+WBuhq#KOJvqZylB+D&`K*W*k$Kpu#BiE7ab7|t|=tgs&_&JS>--5({9)v_p`BV^Y z@E*&u;IR|7=LuEFnMPr+$Fj|JgNgA1#DH&Q-3X9WFOhm*`HpOam@o>CZJZF>_wK~g z8OXm(N`J-DmlbC%b>5M-qRD8GZg4UJO=>(ox7P^gHPU_cPQb@mryrXV#+k8gEJL!?_G%jO$lKPhPwe8Q|jpH%U=Y-J3 zZ=guY6AbhvSZ6ZOS0qxS2I}H6(B>=#`WjTQI_yaO;2XLQ;^JFe#JlPS z57b@6$nzaj+fd^5Za)%)`!qK)&zkUjM~2Osa~cT{_|D)IMze=oEA5N0ndtr9V7*M=y(%ifo?>|zRgH%&#wO8$h-#tnZ<7o(baT2|4N+u?fCW$VUeI})-L>(L`D*$zducjugT{ZmKbUG{8uvKYcxhY?4(1mk<#M^SX- zg9L=bb(0NeaN&kRxWRgKkRCn8lCLMpHyp3}Vsaoc>|)1PyZG@H8X-V0UKA1N@w#~o zK(jqVn!;1sQm*x2dLP0lb7KVPk$lgSpgfYgAk^U^H7o$I6jMB~FkZPBGYW65z z_oVY1F0DzEvwc2*P)gk>?1&npIMB+nq8&kKqrGT3>}heJjme4@C$te>w3ZC*7ZTV0 z61zD{r#Xj9kyOYH#|!}ovy{OFvI6o~NdRzkI$#e@(fbW}dQcC`ov^s;y>$!goZ(0k z{kZI+^Un}~(_Tc+Bd_m^=8j0av5)?&l60w#tO;sU<-JR1&i~tE_<6--ejYoq7hOr6A#^dzpSSuADk7{Jw zGG2^D5t+otWq!}VNxE^eE~><)^hvro$?}VM`OXwJeHlmClSQj{U*Ut=^!v)k6ZnaG zBo`A{d|xYd3B5pZvX1Ks_-BrT-|QnLRM3KNB2dh+XxN=&%fM4D%O=mza|QGUtrLmL ziCz(;Z4hDa?2_?0m~;~`AR)np-0Otg+mCoV8zc~K^AK+r=+X1^=(&1y zt{$DEM;olbn+p&yJBJtNqKGWky*nKjz?9DJwEgCz^9go=9{Jw?;Z|pM*#Jy_u#&cE zfYTg`=Fs`EOL+XVBZ2v3ka>VHF41i;_zT$*ueQm^1`9y`rkjN%=LDTU z>+oM%8P5S9ww)p-KRmhYa8stem)~idV>ka~*rG;=@X0_1BG$CdO=xi=g!s^$kx&jB zT-<~%B0>qF)?cL7V(O4=>*Kt=E0|(K-ohb!NXa!^$&2@iWOjAg5a=a&$v%H&^Ct~dr^t&%VGOA zc&&iMSmH0&jTO{)E~B5p_)^`tlzy%xOL%N}xo)iV+3<3&4Xn(&T# z6>GSP8mu0S`Mf>VchqEuGE7ZthJQ7Q6@oz5;39stZg5)H{ta3wd#Jah;&}mPv?5?X z%y=CW(72k6c0FAO<12OJ3i^2y3Ca3g>{|N0ihlE4DF&*rWbLc2MVoOgHiBHQ3630z z8`5cOwI7w(9OK4wZ;lP67Tgfd6C66K*zUR+E@b7+GF?X2E9ZX9%aM8tz_qiK-IX{H%2*JXj`MSc#|LN5yIM}NAA(h>%q}~ z?)^BIcr!1aK;ix7&w6-*zAv;vl(&oWHeQm5-tP=eOIFOZzcb|d;r<*^h;72$1A(kV z?Be_Vl5Zi&@5h&9{X6Hk1I;?oM%28|juzf$M+;Ar0vr7Z8?qz(6A0!VXn)^6dU%08 z^!b#%rS-61t`|tIhxN!d@hQ$-2YE=)*epmuxaT$OHx1dQnHy~$nE@hq!lD3YTVpSi z8h3HVR?2vV>R!N{13{7c2|PK*Hmx-FnC>D^Be+L}e6-V9>Nba{{S4!)sAHR$+i_t$ zrbq79eUE~1ACaGZk2pCEzN0;-A#L(wZ%)4fcIMqM$-`Rl<9-9bMY24ud-wRg-;KD< z@+i&(U^dU*JtylVjkk%{T{N^6Z>E0q4t{%Sue8n&3|fCVo^qKI$TQKi>sQaTH{_iUwOPcrX+Kw7_t6E_NgHBxxv>EHU)YO|YcK3YI}Qh-5k)%`0>GL8y}=^u zU_!NzKtx=0aYw!I^)84LpNUquM2w-R30+cvR*}tht9`OKDFZS zR_B8sL+?shJM_rwdZZ9=6Wi zwD_>kLDa3@1)%fwBoV?f0y{>02Y{s(PLKD#j~H!!{ekQHJ-%wgGYgz3PcLk`^BDz9 zF{rYDISLoXm%5ubS&)X&9rURTO8z`*zGhM%P2#vGoV+>hOxC3fVg~^Q3GfjX>tNQ^ zj0U0VF`(_ZkI6aEl5;T0`LzxM@5N@;h&~Jm`=He>rqyr&|G(1eSkU%qH3C)4`lE1R z?84ElCq&q$XKrjaIjU4(^WMsAQbtIuaSW~iGZsbUbKTQP;y>%gFFMtJ4%*aBt-b`O zF6qU)jPbM6Og;+7er4tu4}vZ{3I>rvTq9i5!!Y(6<1!Ike1@5XDzr##v4myxj&kQ)HcjQOMtb=QiCk_L+!X^UG=Q#7J@9L6ddcf3dn&Y(O6P9 zy{5XJk&{6Vt+UZ82aZD92?^B860c7l5R^yRf{Y;4*)Ez4OCFADuY4fLrZ`kcgZvnJKnRn>cUT5)VYW&EUG|!flWLmi1(E)k`a?R2(Nas ze7>md4&j zP}kZ}S7nBhX8pkZ8Hr3;&q7UP|lZ(+B}mntY9 za#@qCwY}YXP=?lycI(0U(peQX9z)21PWe)KP36q`@~YZ~sWpkd)2h#&Suwr3lE7rv zTT*d|AqTqUOUcB{+0sRau=;t@MN;Y*w4k#oHj6{^r791D1A>7b`G;a?2nM?IQjP#R z$VL(^9a=tE$p<$YXWA;#j6_A1%N{%MiWwR+Iw;bt#M$ogq8;Yfa^Mg}nmL>08ZnGe z^#Q?Pfx;vR>bwkSN-mQ~RaycoD0c%-KDKpMqzSVs>gJXqfm%jRbtK|)M@1@aU_80) zQx9WfgQPiBk!HJPAt~iRz9N;(0v-40)hgI31aaa*oMMy#IT(xyu?7gS`g5@YeR;hc zg?QXxJr${JcHcD7dQf$rwCYGUi4P-*K_)1M)f5-GD1*pypf>@7xCdBhGE_)DM8PBh zE*`8L$jTB0!2`n{V;lC!Y_bd@+1*Bx0|PV2(JF{IE45?eI0)qmj4jMV$AVNta<<1w zG$6?GFhx3UmbYP%=v#quVf9mm)lX3{L_n7*qW)x2e-f{kC)h%qph!bqLL7~FkmWI1 zg*ZN&5OUx|MXDzEiCK;um7jVl2 z+@->?OL)7y$W~-N^O?()@VE(fYADWq4g%A^}VA09#Ma{2Gsr? zW``_b*80uEJJo8R8F-J91MBUsF8oM|QVwin+5|+5Hv|HAFtWpIYH1-s!90iu^E3o= zC=l2{K$P!Dbqo_>tp3{bwnLn!dtr(uNB3FBS$mH~Gt(%d2ms3^OMva2Y&h_Vwe<>so@ArDZcVP{t-S&AGtyP^_-Xlb2l$+B<= z5VMkXa~lB(s9C0F2dR{k+1iW3Qo(LSpp8mnt*fWEP`Q7`)KhigYal_OCJcd zR;9A3$%^V(iK;AU?Nz&rdc-*dg4Wh2(SGa3lnPmx zLv~lD9;;@UZOVa>s&sr}jyJkNjz{+}RT`B@%=Wn)vCW&uK)8xz#kfS0!qhur%7HSw z)#-1b%%)v|<18zBd%RGFC56Bc!98=&8-Zx0IhUPKJh;bm=GHhS+W4?A*xPw*ZA-Z+ zy!}VCQvaCb&jMCks8us+KQ*oMc>t_YC2%!QxPhy9!VO$067EV-f4Qi?Ow_LsVY*y| z=|Y4lUp>!LCHHnK>xc-N3sns3gA>y!U%4V+kt(rD%mqC4%UH5>0bWA*!)9SXbyY5= z6kX-VU5YrYsl|HS-buiSzeJ_^hNtRMRhpVeR=DcO92ngm;7SGW5=w3qMz}*5VS_Nj zdZGL(D9=|WH>lFFt~m;y&R>TpcUAH=<24j2*%w3WROzgK9$i=aEwUCMZ0*ehDJchT zMh#n}+cmdR&e6MjWWGu295}{_64@7kjIfBwQ^DOTsT(R(0mC*2?4y5doshvj_;h&nVH< z+2iMTRH@QC9sEF*CVOi>R;3fYuKzc%yz#O_mFm3n+fP;LBrn!ZV0mlaMU6LvzEq|0 zwaJPamQG!L?-Nk-O7&TWV3PxHqL)eYY1#v1DJ%!xpakKr_z2o~DSZfyy>flU2BYy6 z*eP^{Guc-Tyr)Vhu<^(x-F9g2Ve&RA&hZ%fE!50))$rJ7Yg$^@q89`b8lP)d@-kQ< z%F{%BxyI+$f=;2J(^JqfM12oU8dg_VTgR4~-Gwl^0M-PsDu^qhJuJ$6Q64JF zZldhUOZfoo^76%ZP|G@VlC{QXPJ0@kIsKV&=Jb2EnNt^Vo1LtliIb%&OmAwcXJwoW zw9=%rB%A{9bTLQ{R6Y;@Xw zHkKSND6tq98I5Lofk1Oj8edmI%O1X~qDZNaF{*^*Ku0DeW}uBsk2+|LO`Z;M@g}3C z@3+f=0|8T4jVVS&jo2~wh}S}hcS3?K8q%fg?BXHZlWA=t2M%KXz=|eOfo)EgH(G0$ zNn3>34k_DIk^}8ES}BgHX{b+I?(kW1t|no+YOfCY#LW6D2ghjX13As_CZIlTzm{b( z+8wGBUFl5Gm1gsimZdO@Bw{clQw{lrRw}{lTj>{5SBidJs z_En<&CXrfh5V~A1bh%FGa*b%eLg=*2PCZMs3=_hO(GiE$BxYj8#nwZ7Er$)>3(;W3 zhqW7l>P3xPV7cD{muVQ*-JAI23^}kulTLR({PoJ{7v1cLRG5&zc8q(xkIJqw@WJ(eKUbyuhj>=L~$BzjFq^s12P6<}0BdybMNkHa`g#=zN<_*ZDS`#@hpmD7y;yj-qTY>f4F3 ztti`YdV$uQUZ9nr*HYlM5d4}8emT57*i6)iM14@;1q3}=(31rG9?_rv5C;BT82G=U zzy0Q#Hw1naz`J=F{89Y=K_KrE$lnX(Z$4$Eg+#vPVVyrB>Xe9WZHa)u!XzCyFu%d@hLeX_uJQNGkN z9B9jd50K3&X3nf&^Khgt8;ftCe997x9g=~-N2GQZF|4tT(vTeLpl3>1p@Vh*xbij~ z#RH*BW`s_e5or57gbp%*2daFyZViBa90cJ6e)e>j-pB}u_3crhz}L6MX%u*FJYp{t zhS@R<1_f6R<>-U-j9KCsJ#*eF)1~R&?d1`=RO4Ml4cGZbgqRiWVxz)HfO%Jr$Lms^ zm(*w-YdB|~BL_;s%~LT35MG>7pyB~J4vgGOOSof-=>I2+{(lnh|MEoJG~-}InuEE_ zLpw^iRYsTW)u3=(QXC|os7qMaxu(yPbl)lWWL-MJ1;I9bk|KxA61lEM$aaR1?Q|jA zG+VYxxS~EbxH?(SH(yCxE(*r%ifn?HrwdMlCT*-v_scoME2kW&*4ZwWqa5!&wYoG% zT1Xua|0G2Y%_fIAYiyYMTA|+6qP$9|d4*7OrBL&7k%Cw7`rvY2A6&-k1D6W;r2>A5 zsK12Mljp-cd^&dl3*hWI@jPK6#DqOj;2UP=0(06lSM}5E4u`qAG}^iMQ0GP=H!dmoAs=V*fo2x^eW03*&T5sHKz?u*XzEsEo*SPgXcSD zZjnjeXGfcNqQ~Qu`uS^U^)~{CRToLAm&iqdd-ROs*4>VOh>&8P7;IpUuB$$qg@$P2 z1JhlQwF>j*>f~G&3$8WDdUrf|kZyBFh^J*E*Tv?8pyImRZi!&43F$}#K5WUsXLK4N zhqy6mXp)0lc!P}xlGK1MxKsFchbZ3=KHg^gcqGrm94V9INdbW5Xf65Yezdwg4vuQ!)GX?h;hX0mQ z3znbp7O2!>>EMGW-uI=l_N751A4;r^k1k&K7GAV3RmP`O)t=EnOS43{VOCW*Q9Y|Z znW(90m^D2yYfAk&4QI?LDk_?isK(DkxT+$Vs75{A$QbS0yJ*Vny4uqdmC5=kXI1ts z>QlrT`j*!xE0WcfQ?TQcsHjh%txr)=@7YyTr5_GF_>lSGrQr+1OOzYKtHXbWFI67W z?$@_yTeau3m$b|ETlF{fuk;V}CksB(A1%0};I4wr1uqu7W$ZNGGd?svGCnu%FEk5x z7QSEjN#W;(-xvN=xVYEFy)Nl>X|GgQC=_hlF02eHNj5CVS(Ec*&Qm$Na(3tZlrulP zAiM}%FA84*?kmD8!&il`311&38PMUQ2;UjLC%h^AK=|SCBjHEGo5N3rp9*gY zKOKG{ye<4{__grc;m^ZgK;nhUB4vqksj^&IqpVf7DX%JztIw#6hy(^(*zO^lS9%^c(b5`da;FeI4{&uiviUp>Ndh*6-Et z)9=?G)=m8t{Wbk{SYn61Q~$UAp8h^8@}d5b{)zrMtn;=0t^S?FC?WNYO0$Y+ry-IsR1y!*=Te{}z|$DST3W3h3evBY@Uc-`1;>@eOk z-i9CEg(u!;zW5m4_|;h4^TM9Xd#>oYs^^-XH}|}w=f<9Q_Pnd-Jw5O1`C!iW@bSXUg-;YdS-7R}>B46U|5^B4;q!$r7QR&Y za^Wk5TMPeHxUKNj!q*C4FWg@EX5o&)w+r8a*WZQTKP>#H@MC!YQ~3Xj!Y>QIF8rqO z+rsY<3%d{vzZCvf_}{|c3;!(qt8h=@yk7HrE$p?Z*Wz9mvM5=CI9b+fd9M|{F6*_j z*A>0m463Z1IlFgtRqa_Dq&<5OKhmISiHc93;;_Dbi^8t|`t*$z zqiR5LKUXC#(aQ%67!VHkD<05~H=Wjkj3`T`@`N9El*azr)bf_M?-;%D`Zpg`BjdK* zdz~b;Yk8nVZI@mv(Z_h%e{O?Q1(~~--<&P-xUq!M2`&nldLP^%DQ^%{R2ZJ%KJ6$; ztI12Q|7*^n z;Swb2i9@DLt)4ZdvTyIIni@5XDT)+L&c!{T)iqLdngl{aJ!8PI%wxbXJ_g`+1Me76 zUspK=0o+Nr05X_Zy)j84%69nRDxX4lpw;~3dy;(qCa z76<#B-dDzUHD2e2?vW>@YR{5CL}tWPc0U-(K{$?E}I69bL(? zG}QJj#~o9NI_&fJo+0JQN1t%<9Y5~*^zyIEf4c19^YV7KeQ>`yRnMxdX{bsFZnN3c zi}8~4H*b6Gl2*}&{=GBYAy2Jq`zY~(aYW$Fv;*%f9(eVxz&opQibc4xwklBp1?JXQ z*H5XhZK$in&sjKVO;*>=s%Nas&3hIeI%nZ;SIoTXnywqR-`@6-rm?CQW;%KKTSKDT z`~LO8yNkZrFyOs5ZQF;MB>GtuRf%a_#Fqn;|2i~SH@@}*dC!Imk}tG1n6^9>H;ra}5*?ly^8AUjSAP2I^zQ?s7F~Pi+HrxleVaE) z@%lNl@i1X>TJP#vH3+-YqW`|{l}DVa(kZtM$h&0 z{(a}9gTI!3FQ~p}XWR3eMiOU?38wnQvd*_Zf6j`x4r@O3$RS^zG@#6})c5nL-h0%UZ?ybJdQV?SzuYPRv8+W~T@5zZ@oa_S|&A53q?S zOFAtJc3OPyX`9<7J2r_RWW-(ijO69ZtDjVlHD=!Z+s8{!`SHO|+cq?fDSWLpRSOn8`vL5`qL8w^`WH$`&Un&Ra=*+8mO0)43g#_ zfTR8V)wj^yW7BA#M{3;x5A|Vu9@|h|c?S0Vac9S3xmhSINvT0>GMlQvL?LBjmaaaZ z2l%ibo*uWwPG++J;SADXmI?DS!i)p6J7I=_ z*{Y2M`9_ycsHnjM)z~X&Ml5M>1jpJDFb;b4Dz$zaBE&;%|pqu|0ymiBd2jS5}2^mX_@fJcCJYR)- z2`XoR#W1?*+~zTn^Qa61%kf&k)K+Ok zUb9fJll*5`ZlTCs6uEU*%L4U@WXZT8#~sI9MC#ngvAaibjc2{3)TPplyikbSpr|Vz z$dg;2g6CM~&Z(@gN#Hhz0N1LVlUdC{$s?>4_v4Fv#_p!BHOW1C-N&lKKQz zJV0t)WHA7Ouv~zv^f(uZI;r;*GLbqb)n^ibv22}WQzeBi^kJhGVM zUp*N3w7uDzdnC|$2E)X|cs@j{lU~FTR}TT=dq7NGPC*cyN)Zqw)@O3rXU|T|s&Z)9 z*1DPFZyOHOVm#}WdIk8Qz(bvw+)0M)pjl5@a}UqwxG#+a+M#e;XK#s+d1!kPiB`*4T#Srs*o zSrV!eyNS{$ne5Z9P4E^g=Rvw0>86%Q zW8IG(@@4N8yY>m^{`n)!!ePu_ z1VADKH3sEMSGFN$~& zP2w2_Zr7-g{*268=Srut28?<*;lMOQO1;RGxr)exIx4PY6-zVl%atA>qlnnWL)=p8 zFXYi&=_(e26f15s(d!FxrNcw0FC9|Oz%PY(xzc07dfWk9o@4R(9~i=(pOo4r6x^Iil2A)HwURruoKAvs1}fO(m~q^ z(CfVR2nD*ba6BR5jmN7n{*gv&8!^D4p>okTNaJ?7Qa2X!NxD;Z8eV7Q#Kl#J%Uo$< z8;YxPCt^#F8#mqos%1bo2gj9^mn4&Q#S=xG)e3fI#X*mJV~J!@7YEfBXy^cl?$hDRl+YWh+JexIX=dSD&4z>NCI!`ecrD z4{1530$aKXU~wHOodu+vklBsN?F=wuYVZ{2jM|zi_F^8c^{a?w<{xHq2Fp4srI~yR zw1+xL&~8>Gp5C=AwN8Y<^Hw%-`e8%pK&~(i1{et`VMwXz0-;}sClnUh>;*@mEjd#8 zS=P2ud1X1R9k^u81kxl5G_S8gk~_I)$WF}_H8_ZzhR47})?EVhTM{tDBi%)=9i2$dsI7AObr4V% z5-I0Cad$>($udf1<`kA6qK+^6*yF)Dl`|^p=$8_j;p*$QoAZQr|FqofL>`{0Kah7q z<5DZc+5Ow`b=x272|Ms!Qd9B3t;|1Qv@cs zO1&W1Ny1jl%vyGz6?gtnk=eS2a0oD~mJFE;wE+v8fz@BE0W*gp83u#&WT{Xy0E+}` z8@;0tW~*hys)pIN4f`_h9u{JwG7ERd_AP;!E3J2QpdM%|p_3BrUBaaqIF!$zweUKx=Vh;o%a&l@AgC>ms{r5i${Lcda zv%vo>@IMRu&jSCm!2c}pKMU;50%d^*@StY52XZMzn!2egof%DK70HhCSfgSoD4 zx52|&ACe=rDGNLpEDJn@e-GoIiGPpa-=n;gvB8MfM^m*ND+{y_5kdBAAcL3Nmj(JZ zr^@_PC~vh?7Eb+TaXhd~c9w)wfcK>rHy<87qItA`^Ju^3{F}CsGP!%1+#_;i^T-j+ z@mBC%Ie7o`U^NuL+o*Tt;N|Z|gMEZ1!(1zM^3EL+u&@#+RqWYruPg8QxG1P8N?s^Qh+5OQhovwHIC>jj}0khbK+@ zLer7ZbVT#$@aEB>&7*^bvi-b@jL59WaF-%OZAAvV6k%_>9tBQ^Lr|1i1>KuZj)tTY zAnCZ~(Xq{=WzD0bg`~%n$pg#eL6J$#BjYlp;w*4{@>JEjvD6^{DNYImCMnc=^&^FOLTG>2W(L7q-JbH>yc$C*Q z370aJE@diQ%9Pv6oZ?c3`DO;Vl|opQ)?3KY+vHRMwy{{}laDS7oY%tYUF`B8-Y}>v zaK6((mj{;xX6I(^a~_48d%HQ|M4@qg?(pcDxxBX(MP}sUTMlb*#(ofWr89H!7I*T~ zvT!Lr#Jnaao&;83NRD#f%$$L1e{ek)T<7LS=j28k1n&WnTJXl(_)_hO^<0OwIVacZ zt_`TQx+}BfKOoN$kO!q@NwP`mXUbFkq=oG$qn)=e=J8sGP{u*d`H(Y}8$DkLIX)7| zeH>r&lu{i?$W-n{^V&_oKl6O+sJ_(td)QL1B z7a=>PI*|wq9XpYWcICt`1n((AcZh(WO%LS#NBn+`ilJVt`ssiGmY^pd_5a)7;vqA_m-LgmA0^8KHy62-i7c2qWAG-e);Rz|W?Na5h9(3lUc5MsE^Q%#Cz)8)3D> z-MqxFl>Sj_;?a1?OZ&Gh` zM*J&I<6+Jn_^`q$!%Pc36Nx5$LLr~5_$|I(!C@9CUhT?WL!sl zQkZ=cdaQMYel~1Sd?HD5JC_94mchwb{mKGKw8F~t>+rHb1OG*nY`TQasiA*a;3=np zF5CY-n-WSAq531V*wr!mozSAe{I28TA)CVV{S+ym{f&GJod!2ZsR5+Zu8!6)%K;Ha zo5H0-221#m%;1Lje?ayubRv{Zu`fxLQe@VNsyh#lPVXE|bQYdgQEetV)7)HqI*5x` z)tQS|OyW)NY>CGqA>KTfc&B#;eGP;lBCg$rAHdf>`DKAGyV=1?m+g3iRu;(3w;SlP zHE)RgJ;T!iD|ICgp*HxOSF3!|&uo!(IK5#xIm=i3f^58`|eVtmW<>RtdtNnAH2W|?6h015P_FqAyhQu0BPp##2qM)TDYiq1nx zR7>e6_q;zSM+#D=Ds_M4dvF7HehEJO9al)chq!#WZnAuja`_4%pJvJT7|Ex(obbUw ztnDEV8Srs5nwnc)RN$0UiFN13XW~Ujyv=AZy61bL`Nz|>SPuq`hi#A`NFj#tBw_T( zhq)d{os=3v#$n8uH5|aF00_?j$?B@~A*L>Wug4LJ3g@(HGd%iDIQmtXClswrj+ozs zkuNA7pxCZ(rl*Z8oIrJU7RqTtVtLTfS zJHjrNHg*p+{IoKBAg0#i_k z#+3!NzFaj&p?>t;u>r2$vM}Y0}-;eu4U;wOF(|WaIEY?A4UG zC$|rR+yBJ(^?nyVFQM6rJk0#vDADk`f7Y72i^P4N<@; zFy~uZl_Wc|c!GmPe7YF$P;;8Fqs7B*tSKpUX$9?pKJMd<1Kn2PECh~4V}gqjeIODa zDP;-@15F}3^ABT^ohQS&D4XisQ{mhe%J688!aH<%nS5HATxsS&4X5w5ajB6DlP8Qe zN~EP?L-Eho?anEJXe1uFrzD9GpJBFCaFr2Ijpg~so?+xEkyd`+Fbb@n@^2?wqLn0h zhh|-ncQB_Z%|l2ou8v$|wt|9A&u#CMWR}t1tsQ41aNsAF3~JM~;>rru&vg7mCaZ&= zP&U<1v=r`C# zHeKR=mTQP*oZKB#jAAk)n;93mC2*LDEXpRvkv?u1SH4HGSj|o)R@2Exie}GdAGmI{ zo!F1|OF?sL<7g!k>?FpOVYtS%(2{rLGyEkxaP3sgv$ypc5ITU|irS>=bgt@pcw1wXe7`aPGV?7lbA`0Y1s$cHy~JOej(>5Mj^a z!ltkw$975vOHv{It3dX>btw??ib>O%iMWkFY zPlnIth2h6}Y-8dLR2vnFSn1Do9!Nl;0`$?-mFNs5I!%dIS(?31BF^;nmuXOBQ#eZx`+zWN zeHb$u!}t&wP~~G3W)%RPj#lpq_Zm|76Tletig`LSrM2d0@PmCuU=2#-Oa*@8`+TQS zOmZ|9f2GWv*ejy|w9@$J!1G3NtsT2F?JE}*^Gv&6bIE!9vVda(e*uc{53ZZ+pKm|{ z{%HsQoNc+~TN3nKsEw5u-Alms4^q2OYn~0$thX2F=L?t;f{C9)HvAD##`y}+vA2Pt z8#@rGsbn1slh46+hKp`3c?X#oNyBNORmLv8=++_M>rfS27&i0&5c6|A?wgm+{AXf5 zPq6{r>nIl+8lZ##YHR^X{R1pvb)!9iTamnsHF#mjEeQ6t}58%JYl zW5-e1CBQz!2WNahCJt=yvwX5lIOIS;8p|-fHI|aUn|l$(20=z)tbUy9MRCn@t@yay z9Us&#g4&YhGR3%Dh|`M1xh#8pWH*M3u0JwdA~})K+AB7n!e=(Sr74~fwfyGl;%!M} z)>+y+?Oe5R>&Ny?I6EE|^@!P52_5+l0mtq6* zR4=kR^NSL@CmpRnq1~fIHZazFk2ijwVr;Ui{ttWK0UuSd{eSQ71`STdR4G9zHWWj$kZ1}f8;VbPt0H1ASg?Sg=)>~tZAEy9ieN=7SfBdrAc6%E z3;e%lW^UUOmi77jy#MEu@FDkR=Ja#s%*@@pbNH6U^N1R{mlk&x`j*V8`5t4jbQGw$ z@3#tJN!OeJM8Rf}-uhz?xq?GUyZfOXJuIWOrTu}Hcwg`0=Rfd5i+>c(mB;zkyoE zp;g2$4ihEjdA&560rlQ-4D;}4HjEO`r$;v1*qK*oAd?? zZloWk5H3LfTYi`dddNE%)d^?*=^%l;Q;5v}hU$G?^}eclUskiskbKcsZ;F^C+KQk<<0j%5FpN8{39=^*bntK0K1*oN&L!L+fb1TdW}&-hvDl zDEeaL({LHiCK*0e-S4QOw`l{yb}>o%FsvsEuY-dAmU6c5b2ao12gDN|ycK}$BU9!a zB81L2^iF)B`9(Ol00Dg=fUI;h-OX7rON1`*k*i!z^3zf|4ZEiNtoO7(orn~cX3 zU#X$(Bm$?d`MzNZ@LXUEQ}Av|6zur~+eEV@%u;l=ZwCqTH-hJioAB((1%oQOu;Uz> z`p*Mc@lMslaL$j3(-LP;k{CJ9PGYSjlR6Q2-pM1WmLV0ypJ zEf*0zhX*c7c)(o>5*TntW5DfIy+5kn?^W+^)w@d{aF?MUGF*;}d%wjyXuFcyehnKp zyIUGJR}seVVHn@HgmEn}Lc0KAj7vNKLSi2*x9}$EwrDH7(6}T!-+xPLeS{k%R8}n zPxVvihhr1oL783r0gwZ_=qhm`L4{=tH;u1;&pc##d?l!zzdnCE#alm*K z&7Gy$^S-;61|zRZcK77hPRg&O%M2h3LM z(S#tueZoPq2_z6CeY8|*yBiM zkGIj}8ECZ!=PS?+lJ5{nQ#kPv8q+{G&vrqbyPZ*|$^&pa?h|(VhadsB&qQuGM)MYH zUZ3V2qIn1DA@C9U-N$K>FISz+65t?M!SZs|PG+T@%t{{vGjyCST*}~ZdVpF=F;qN^ zZ1yRjJY|{zs5^!O8us~*l^Fm0fi_FH)6Mgl9fJEX#N`7S{!Hu(;x^jK&D<1)hETj{ zzA+@$mjJ|A;2*EdrKdJr6NJjn{PE+8M{6Di_cg&iNgv44w>a*?Q#)E3ViLsCsu;S9 zPu48zwa>e-Y#)W(9zIQc(*lKKqEhgNQP=?r76yEK67rEYx^ccWK`gf4g;s0+{NAWWi&`<=v?thrCnFc=X} z7)rtODDZU5(f~RB0ENz@ilvnTDzcTLKs>T$!Dv#UPZXl}kfFmrYv5z~4^rU-;ZhpG z*}iF!Do75fFirEEq8YH({BMz&MxBsB^PNiS%fPh{IL;2*vH^FB=3#J7g0sB=VGcM` zN5dvqm+4~DgH18?#0rg0nmRNs!|FC##vl~5l0eJCN(@3%B8xxtLD?pPy~RQnFOh0J#E}6K zNF3*2yv)?RXKLOvH1BkM;B-VMVxkiQu$v)Rtt06BB2$uh`kC-J?j>(g;9;3F& zEfy6x0?bWyV5 zudo0j4-kaKmz-?8^+6McKJF79`h7tHLqC9_->i>#FUisjXP9&30)6b^+1Wgjw;y0U z3p4|a4|Oq(ltOL})}KoVl!PVpaS4||!o`|*k>)Jc__(zu1)64 zbeWN!mXORxlgyWCq4OvKKxO`J#6>i(b4+-CfByI!-{s+$#}ek{T4*5{>`C@r!TQ;E zZc3=ZV9aAqOaq(`Ioy^Vj3C3pfzvYsZW!^oLJI{spDSbYF(y?|;m{_P#$i+uXiweLGb0z12 zdoh8R5$~(D&|=Q}TH-wdZMck#DuTn}0?X{q_nC(!8Oz;^$}Sd?aS2Sx#*k#!GK=zo z$RcYjS}_oDpKzE@00|7l1qkySH1AS9t|y`yT2I0yv=r7bhvcnH2>y!mO=O@G0OPq; zbKk7lW1FKv1;n=giQI{RbuVKSFu&lP@Z#Gv&vH#Pi4PfX(?ZKMbcSxG-qh%b zg7u3x3@)M6vKm-BX-!B=XUJW_g}n1m2q5>V#`kKWyW z%6oMw5hPe#UX)yX4;i_d3yb@NEn3TkeFVZjqU_<|n3B zyVesd>Z|p(e*Nu!Al^cV{A-GLkGwgzFTRT>>0cM*U#N4jFUaX1@iu@E6gvl(&=d3o zkbhI*F{VF@Lbej8g#3H_tc<<=W-x_&?BHl!tx>yRhpQeYO{0qPimJ3a4QTNMD zAjnp&0o)X?)jXU}Gx2#!AC&m~ulO0wvrc18`a;0-j23!|EnrO^)&=Z(^4eSw3OxXg zHY9UkGLehD+G=81m$jxo1ZkVDEQ?vjmjL*uP*|2S+eI;X(kXrMoo!^6ktO4b*J&Om z)jX!PXDvxMpY9!=NB=}zoevTisWQH*wn2}mg=hoyzw=9wUoPMm6jG+Xi}+;`F78lI z?CqE4O2KV7>NIRXY+wPwvnGCDl#HA(b@7PRx$ZS|y(8EC2wiVyaqA?nQ}D?8O_0uN zpSrkoS#F3^qTYyLz(`w~TfC7hvKRuvBDha@q+JdYu*l_@LY~ttas}zRNeev(buOak z=9d@1E%;5T=t}C`tc5nA^YQ|c@Js~%&RjendMbzhq-E%K5B^-53#6sFgmg8KLYslX zQz32RUI7R+H9nGL$}7Gt2xTx8PZ(byEw2HxXNzXRk4U9_Ys;Xo1vG4e`-E+B6G*@& zx5Fl{Y2H_Kvn)e1#JQPYZp9_^8jUKZbhhtJQ}Sy)#al`8+X3TwQ!~MW_w7yA zbQOWVt-0Tb@}!o3`Sca$4Hj1PHP~y}S5B{`ubc+&AX(l(|Fy)%yuh_KM#in&CEjmv*cX#-XW|6 zjrnW9_Z<#}KG7)Le>fESMx*dgP{2y%W6kpkh0cQ}K?JuRP!AE1!-L>TIJh4L2?Y0D z2=34I$bJlM;Q0hD?ysyq_*(OPqp>E#2VZNUub2-$7x89&V59kVFqb?DN+A=#>Jo+= z#U)4>`fKcp?_16O#$^JeFi^znnNL9&&$n9K@^A;+KK((<4`Gk%qdJJ?DvQ}E?MJ*;x{kO6?f1iPOMwF&LUe1$=}ml`*t z(X(H3|E$?x2d5`9JeBK|cm}pTu@B4aTZr+`w#Q%>X=9(l+^1Dz<)> zVD^x+!X>lj^jEEt=?rPsH!S4LDR$xThv4fZoioQG9S;P@hI;$sS&LV?G?CL$%aW%L05 zrUFjXme{EG-8@7wo>u5Sv{|Yp9Pw1+9lI5Xq&~SZEo=-UY}B%R9GrG7x&gNz4ma{5 zrtx^K!NINE-i>PGjKi{VX9)4@VcOWh5jKABaJ0?PpZK z_Ib~0hmRoxX1+E#p0<>$J~c(+%Py8*KSQgB<+3kuhqV*m*567GLHNLib+6@L2Kf>Y z5mUlfXv8E1Vq)Fqpi@(V-=cYfQ!Y-)mSj0imgS>Tq#3+c4hm;TRKN$P_Q-g8Aj^Z% zrB|k7J+jm+%LCCmnH4_O5m19$bxBg1Lv|dE&eF!&tmY5MQT-Y8&Oxv2I0k(uqI}R| zS+ob*IOTDMAY%xXsxS&x97`UBX1jbK$mJV>u1NWYqcw(n;5W_SHyLn~^g?8&>Q1Km z39-4BN98&pHdonk5;|j91;sBTtx|1B=_k}kt5l*nTzJ@p3txfG7$%#6u1J%ej@H;F z3#96?at`X6OhMfni<8n}t~3V>d!7NcAUc#R&qK##6yq9OPxVt#GRt8`6{^F{7~VW< zmLFAIjR@dT1>zSO#Dju(5o*5yI~n2CNtPFi)&Z7QCe{qd;R^zOyX;HQ7a=>vJQHE5LHwHN#2M7h2Gotwp=9}b>Zr5G-%Gdsas&C6=*W!4 zod(p(=uon}A|{J}7|5$*!rW)TtceNppaFA#q!68Sn@!5nLv8{}MV*3*bHdl9vOEqg zCtF&WZqp2e$qZpJAyDoqk>wK@g4x0lel!sFpnF2a{K!%99Xc>7ECwH_8~m(px_q;{ z#lZHXV{#)^{S}h1q{Vn=Wb4>z*-{1NLoRE8^>#LTJ4WfvGJ3mYODF?qGlcBuiekmJ zs4q05s-byit-oki&HTEG*)^2}Mm3s{BZ?`(IeKPG0Y7T2Ejfa|bM6{&tKM6nO4 z9g0-e!0J<>l%Hurs`EwD%x*=ht8JzZF~i)BB}$qT;bE(5P zwMT_zDqD)m(p6NExrP#qF-yvhv?!9ShQ@82&Kz)Yz#SUuh>=@VwLJuMIusSo#^2dO ziXMg(T~(O2nF=zNHK0;5o-jLI&_hyD?pl?`qyBa?YAZ(cb%`Z>PgSb1NXxu%Ea!@& zj<`353h8`8x*?)}u;?Eot^@g1?r%ujH@39-ElAr(l|;2_+whZRw`#bKI{_=2+*qm= zs#5u^S*TrY@wDt1pi1_jP$(*$O!1S2q9+MOrwKPq6$+jp6dYwJI0C+>%GeR}FC`mU z9&Xp)916U=W;`d-91YRTRu|0{*9#@C z6W43`)p?cp`wDTrOk9_U>m}m4NR@cKQYQxbMWXQnab3u-^0|g(=7%e>hLR>s{5O_f zCPYc76w}UIIVI;Ug7VFR@-k4CSmwVmoH9?LY(#7lSkH^=MseN1uSx5~b*;FD_|^5K zxIV$J&d2%H@t6ppN5u$xM2xV9ME?W)D&J%1eYYx2ZKAs5X3{f<2@6$uH3zXJzi^m4 zjL?b5jVsO2iRfD)BE-l;%``aV+rmwzJL7&;nroTZD9y``d+j+^cHD>j=5Mm@rI3JJ zX-RO`PGPVe!XV!WgMBRw_LVT$m!kg*as6CeKNZ)H_*H(>FytFx%9iM~5Voz}U)Osq zBZqDJTIBk)4t=sCUo#dt z=K6FDYPQmfaJ0r(h-HG$Fz|7(G=7XGO~&}HnQyT=6 zYKSJW;b^S11`%}ZW&LqNQ8Cw(qA=71VVLnk;BgR`&pTtI83q`q3RO=Ls!kIWCJPFa z4AV}uQ&=EOdjd1<#4?K~g)jj@s!3eu2v!Y(RlUa7-L<0qY|(xeZ+F%RylQcs&98Em zA<|6Kq82~!WN;?@P&PTD`3#7QvelM$?zZW?9m5SC8ec>6g)t53QRLTX`OZ@&p6{{D zwm=9q&j^j?7ASF}!R*%xovs$wtHkw6alJxZFBjL#_*GtF=)SlG-4{jI{lX|g%achk zO3?D2g%S4R?dKt0nXPP-+qrS*?z~;-v_klOx$ygKA|7rPy53~ydP9T|+-XY>$xe3M z%m$Wa@xF|C(P$tq%6EblA15o3^X6E?qZ3Y-rWCRoiAjWoZOqB{0GBVz?~a9gZwy@L zdTs*eI&K2zGr|OGg^5DK6ptG6JrvHP2jr9G2atN3tub4|mQMF;(paPwBa*ubWuAZy z>Z|!kTZ3>zhJ?t&o5}S$Qoy`@Yh0 z_T6UB1hV4|3@!gTWN9JNwfa+*A2>7T9&!CnT)*X4#||O%H$v#IxzO^LhRZ+Kq&ZET zxUeN7j+p$)E(S|TZFBhC)h36}T}e4S%er#J4u~c;XAWPF9S}n7=T~{JVUZsrnBF9| zK>O@WWyjC(x_@3&_1jDB*aJHh3C9u6UAjzr4GKl%m~7WSJ{HB5l`E7> zl*`rS%1Y%AOEDV=jpp!uTYmC37;HzYrsyeIjm;srZuKmO>bJuHcR>BsFv1$oy`K9#|MWcUdD^oM26@HvhG&~+yXTGk zH}l`he1s4}AF1Vy%Nx`KBmla%Ia8<#z1=qveHx(=^ zxTWCMg5?Fb7py9{v*50Re-x}KxTl~)No7OboPIS`4Ri06sHTQfDw*Z42=pr~q=4cr z{i+%f6?6S)z~dOe$fN1j_S3JjrZ#uhY}SSk`vBu5P}>iKnT-nc_;J#I`HL*}hvgT8 zsi|iz$h&~av-I*?27`=CKS}uSl*i9xe^`Don5G4+r454_*45I@ZW#>Xn10&gzf(Sm zM7RBr4DI?C4H}?Weg+izh87hS4jDSo(ui9Oj3GmYC`!?w!GmzY&zbGWh_WpOT`d-BGOGbE`~`?eDGtvExH@RW)DSPf1MWbVG<=4_WCF$ILt z39bMzO<`~)Qbq}b6NV?af2B*(iZE3TIAMH(BT}d1=x*ze0VfTMS5;f9DI}>kuwahAs-{-*&XPcA zge`53jGi_}^0YZ3JZ&~LR!&C>tqU~H?^h{#M>h>B96ChuRy8z9-cxHN?@7`i$y+`f z|7R9S-jQR_JYfppCgcAC$vdjy&k6uD@Vq^(EHZDODDt*0VZ+R`z_UtkHq*J+-`LpD z*yx|r&=@GjR8Ti3Aaz{q9B@{VjEAlGswKv3h7@d=E3ZZTWKBy89z2*8Op+zK;yd8@ zUBG_#rQey4JOAu-M0TaQsc1$GCbY)-irRkFQigo&iI?8@!@)1E+c{(JwNIU&@j>Pj zf0|QGePwNPm0xh1Q`ef8H_Kky(_Ikm61A<}@PkX7#J7uSM9M>HX-D(`y!d|3Ul32i|-A(w8#NZatV%t#{2sA7m~}jAQ_BM=;f=m3O;m^SRf&+dpOI(PiJ9 zIyG}nYCUHrE**JlQ@5+Vp0D;j4rlGj~bvq2l}se5q$XIGs5!xLX* zHYY~1&R^HixPXxy+UCxyN?snnQ@ZJkYvftU7iT`37|AB~N*E(~cJ-J^I1}{VD+YGi z_voX)?92S7XF`fs(#n8Q{Nt;)&U&KFw{Ok8>Gab(^!oIR%+&0JC{{Ez`5Oa_YF~Y1$erfgnwOFLm`8Cuxc$RvOP@(U5^rZ<7CoW4 zrt<7jwG9n;w?s~IDUuW{VGGV+1y$*J@G?nKG7+7~ zX^+Pfs^C-r`>Hb>Qu=xm7$4Zo4pbZPlQ?{Z0{ANce{?n3=Q$I;3XicW>MQ*QhTw1s z)=R+$fH9GA*u*g=luj9l4~gpoHGu_&zWca&e$ar?9a0_x9`c&*&h#vNC{o+d=v$8U#Q-4SO-Bh|&1MGp z&_ro!sKriFN9e(|x#bwZegK34VB&OkmEZ0zf7V@2|IEbm(`!e%bZ>D!j~olM3T!HZ z8zu64s?^stCs5t!uc*>rv6O4j8`EDWlOz>q-`o9kx6f>NnV!#iBn3+AxMdMm{GfP^W#Cr+_QJ>3d@?_}&5_^I_P~A{vk+}rU$aayf zg@x8R=T%l$G}2$HtJ-2-Jiz1(G6aK7WTB~J>jS2BR996uXL7}SUXkn>I0x|W+hn$Ho=1e$%RLwGwRNsU8je+7zBBonX{{e$+@n9My3#Z z1RG+h((Mru+rx#8VtoUt9B_32U4yEQ%SVSR34J2i46<25`2H?7teE%kgi*M!J&D@c zLNY>aS2j~5sv4=%Rx-)(h6X%i3Lq^=9Zn0D(6#la)dH;+XthAA1zIi8YJpY@v|6Cm z0&!WO-0?WRzbKUtOq-S2qfl$pP97nrraC)hWZ^-;>dc&onzbXu~`yM zZ+xA9Xv!$>Q7PWRDc*r8{G5Duxtv!n_i-Pc;yx+`U$n=G&-hNh#wr=@p#q{F_c1B% zjmi9&vNl+BhmKAmFnqgHuMC3Qi*ig&nBcA#C6 zG0_znWl>~=p~!HHB23V6;4}z=;u=%XL;2)bNIDggPEPTjkm4;*@lFtu4l9?BE0;^$ zC#AS2M|Df7`{XdUoMdVfnvDC4sQxYda)L#jazmX77IlPQhJ%~kFJ+;V4Zlo-x+9=2 zt})eZA?V33$3xrM(AJ;gtxWM&qKXaeg~}bg|oxyrZPtvC!L7t-^53af;$tFQ6 z!C5{~TGWX$+WGOA$8H@$nG88Egq*=t??NHu6t^RF9UVOvJd%VArY^al(^UKqE!6ME zm!iA)BA`!&Sh&V#rbzB5f%{@`UnE$cip)*wxRc05bn<;y5@C^PCvwrAxA}bUrsF6U|m;#YSRw%_w!Mnz^2>wh|gj$HO3?kf^>b+h_ zQRnU~%+Z^;-)M3VU61<}G<;Uj@PQF-h9LDY06M~!zBjB2-1m{75yCK19 z!Tx-AHiqQ|ouptN^1*5=OEee%11uMUC9a9G31Hv$9?j&iX#E z4qga2u*ZGE>=$wN4}kssI{S->eQ&|OfHc1!?3dDVW@$1K5j200*e~YnaWB}jDTLMN z<&#P&7KZ@jYdLm{g&fv^@^H2sl>3!CGCCRkbc;y`>qNPz-0{wlMhD$yMp^pVrXhQ# zBb4ABT(|P9QQiqz-f>x?MADt4o|eV)Z9h_PLKc!M9rGC)r{D2>J1GlfR&zCRpNN&2 zB>&)&Oob$qv%DwhlB^*~^0L;^VVA)HB+29~+)u^-&jo!d z4J>yA&C-F+L>N7)j4vCG&wC>~hC9J&j1YM-n4AeFO-%ITl3$f zR`B58CCS0>4&t>>lvcykkdY0!GqQELBlk}&3?jz&M$Wer_;%!cJ2JlPx1DcBJ167W znRs^o6FhI{JdXs=E{rGiXQQ@jwthA*KAIkmoz$9(pH{}9m&PbAck#>J{6eD+jWlZ9 zJ$Yo}^rB~zLtV0Itar^OY}Bs3xRgjdU+GMlegODQ^gk*K=T8xDS4k}Nsdfy8}r_OK+5Ohru*=KNB$ z6{{rQlUzRBCoJDuE?;lRm!r$~49S;cal$9ZVQ&u!$$;z78OpKBiv}qfW&HBE@tJsT z5^p^^JbBr6Xnx#sj;{}c#tV{25Tp>p*gzP4vSF@uqp>0JCwy`&lxA&ZZRSy^sNG0h=A%H6)d?A z_x{mL&eo@ zV=&x}F%#O?QZFhlvVibLrOpfxjXHG{#-wia>eTy1rOxaYjXHJ2rf&4=)ceES`x7_! zK$!apnEQa@{ax|?D$G47^lL10{~pDlhRUG>QF;xLT~WJDAYzFtJq)lX9HhM@PC0@_-Xavey1d3Dj z%A&gLF(FxPY3w;$>UBj$HpC7^LpFL{j;PqCyP{zmy)FlPM3IE*v&X_HxF$07P_in8 zQP#sKZG=UJm&;{%3P*GB=_NFCw`s`)E%&;jb{i&WxfceC#@aAJ%e^iKpQ@liaWbql z5>~=BQ7eswm7ar@QdMt?Fx2txbTyRHqH$7N>U9?JseGKfLv%W(oubh(dUZPE-5Js8 zm==ph$LQ7ROf+4eu2KN7->y&x_6Pe7*JQB2*l(+;(_rdym>SnaO+6K+-UL&36n375 zg#kbJaTDGF(pP6#cwn_dK5nUH4^~VB6Y2<0Y&K@tSLlu{H?jYCE{95eoD??~on|E8 zs9ds;ISno+$KVp1W}I9Ktz1rl13D${fYafCEOnIk2-VwJ_}~nRiH zz-o6m0b0AU3^&xx`7^usfOvHtw_2R5dU|7bqIxve%gY~8FFm=$HBqlL!7E$gl>*i4 zQN4M>H}h;^9rA=Jr4KgUPT>pOg1F#~MCFQ;fsr9Y(HPLUvMz=+C$#$-$m z%=>?hp$xtMDnpqJ{whORIQ)f%GM1lzm7z=qf0dyu9GIc<4mHosKlD(I92o|esBuoc zvEn@HK#F8w_&X|tNO)u5VI>l65Ve32l|y1fHImEW8p_Z+dIUx?Fc6}u(E|KmW++1< zz6^}h9fxZu1OBfvl*!<)iYN<*m_wBuXe<^N9D1lm#;w66YJgDhVGY$t28O?*GKh@8 zLk-nP4hBY44lTg95P^|chifQ9@8}U2$-qE}sz#)t4EPvBHIhRHyvZN4MO)xR!dp1R zoK+*S4%biy{9k1#lR@;M8mYqJ8p^^U=1?Ur#!x*Et7>oJt7`VyGFH}aV`W{adi#lG zb?_o=a`6D4eMCG+4fTt%PHrKNqQbXe99L9?NCu`gqX`trzzjS65d-@$+dVj5jSP1r zN0l&=qaop6rIH~L-eJT>m_CrX1io?)Ic$~U)X219RD?(;83<9~BTZ&%WH{+k(r93G zjR@R6kr)I*gXq~nbjwGgnQ{(hXpX4zM&cPR4h`XWx*slw)Fc^yS}~A1X$+62#}wYO z9y|Xtq#GUzX}+T@+vXx{jDuGK(Q}jv~9F&;_!C!1G+Oq?`G_rq5A zaK~Jn3`{@7$H1_^%Xvze1+I?Y0z~D%B4FeIFa?a0fq@VeK9Yf9u}BMC6UzctDwa56 zp&w?&YvZSJ7;$8d(!+IgRI9W!F5_ch2o!0>>*BY-VZ_nly4e&kP74?aQQ@r-z@LK| z0!3P2X)FsATGFp2j#w%Ti=*q~r*Rl@WCVXyC9UFxJ?x8jUTE2hkqiuhBCSX-^F+(c4V03+@xP%e^20yL<+_j8?rPRd1PYm;2BYDq}+EzP60sk?62~ z761_T8I=wiHj+Z40Uz_N5mzWaa%Pl8BWLttPZ}RR8bN$d8jYUOOW*zB>*o7o*@SpU zW!ggMCt{OGa)#DX$r-&dY!XS&&^jtTqt~>_KV#X1V58ckFd}^z=^!doqc?h-M3OVK zj!MqxjbW2WdZfu=#Rn>B-BR?Yy2?=Ey<`ybwIHdOyRVCS0q+3(8l1` z7_^c=i`PGJih4{oG#SN(!sKG=BpYaL)CkELM4ADSszy;bB^sLS=%7kfsCcT^a4eM_ z8E6@3Ye`27>Yo}gr~uK)ut-Nc-OalFyBgvgLE>2JY<4CTvw@^{xJ7NK-lC>duBa)M zqw@3kV^krOsrn!aE%5uL*np9L{kSbLc zS{xxe2BXF58rd-fEp~?vg!^!=o7I1g;X;mKh8)M(<)CpS%f)s%xNtrdL(m*Le8kC) z62Q(FAVo3hai|m(*$&H&H7q+i+E^HA=g!StX1A;u@Bf>X6WWAVPS}|9TF#3(FXxO! zRRpz^3L;P`gm_CJgqJ_qViY{!1r9dmJeTuA&L(i!3?8q5*VdeEIdA2>o%3zZuAJRD zKjrMp`6Xwy`?mbe`CIZ|%6}#QwfwF5e_?q5I;-CPV?Cwbi7uy1=hWMO7>unvKm-|n zD!#2e0G&^7|6z1&;2DlB;(^?yVN>a4e21uw< zLThaRc2an2ZGhI=0IjtFT5ALRsS*}?Z2-3R$dH@f+4tTN6aTY(;M>mB(PwOH`oAg- z@RK4<7%_Op6x3^NV$}&RY)cD#DR>;d&x4Cm8zA^bTXvj1o|*umq84XFV>ihUzHh{? z6R@>D{Q9zuB%Lw_2j%~SL*nsBgMh25a6CLGTgJ&Y6$7+CmhQplr7;;O)z{Valj2Cn zt{?ETP^6%#+CUk_QLY;X=$(Y}Fi;$H6n)zsGGX1FA>nLkAW{LU=71lkv+IZ0-^CWU z!Ra{jBe*CTzuv}a^m6ij9pukIqN{UvcMx&@uE?pX+)I`J`=`|J7RTi42IB{hPhuN} zROux;6q^nnH;<@CVZ)7jt4}{YTyZ6I+I_0DB!dnjFCSAnam4tMCqn=GJJF%_|89@w zF_TU#A2oLTNVJk0TR0kjheA~+U|@hA18<~CPZI&uwwi@{U+gga1B~vW&c|OL4ebzz zYyO~8^ z{51j=k?5?b@8mfZm42(>?U~^J#UcW!(mW>cjGD?yR3@X*VxFka1>Z~l60u^HC5uH% zSx*-HRQE1a|1_*UFq(Bn_lFZht#h!y6BLn%F^N*_@p&m>0M|4pHT|4+&q zxISYO(d3G`elbj^G)(ZL;IAnAaXp(RTZe z3-IGS^-=^a9Hof^SX+x9u;ayBiyz=c{MO&@q^al2d%{qT8kgF z7C)d#p|$uyYw?5D;s@3WXDw_iT8kgxE5!6=)Yjq$t;G*oiys7^#nTIXBlXW0KNy8g z>QBlj?+*&;-&)Ulml{I?Dxqq?t zvajcwxZ~aXt-bB(tGH(GMB=+&K?7AD!0%t!Z`P8Qnil#YLL}5dK~aqPtIyi*=zu%I z|Cw+oSF}wr@4L2ZPtuPd07jaiM?jf!5{R>5h*rjSmb#vt<+LYX{F<`_J`<2wwoftd zJL@a~z)0&XCy|A?eq2`zV>?UTc)Z%n2XmBM&Jy@cWMbJd#k}vJvjhMmt+PCVT*ld0 zOv+pAEOn1?Ex&th-Lsq}@R`WO@`x1kzMakz0F1QG^2E4($-a*bcW{;ub~tZug1(#_ zw=X-3xZ{S+-*n071bsOrZeP-O^C{H1mYqfwu1V0BQ{(n!4;xGQhEabc=*www`%*Dk zVzPdBS+FKSU!D}VFLO8*zDpzC1Z@U-q%FeE7732NU$=DRKLO>;!#zTHL-IWU_=Wm!7jsMC@Vb*y(Zm(r06NRoQ~O6ZGZj zar^QZlO+tRCOHRX+3yg8 zBDYzmL$0Kimp#L@_k9s%-*Kd6PE65x>6CR|fkXStzOWgwWBqEb*J1ms`OyBd%nu0t zdtU$dxCH$*_t5^b3^T;Wnd8=q1smMKj8AbGm%rv6+FzF09lYi|^RM+>FSvsZ7UC6` zzvds>UzQ{Z8*W;7Yo7%DwcybHvaij4&0Do2L4TclXn)zKxQh#Szr}eSw!i*%Xn$E& z*05nx&n2z|{dL}<{bgC8AU1|>ee1mh{dNAK{bkSdU)=n`mkIi7;i3IySzf}1znphR zc7p!;`=R}1pQZiN?teZ(fAP;uk=l6v!)G#9cYwUdS@AiIF}E|cPci?< zx&FRL_jRyLXB~Bh;nP`g5gw(J3pp!pSjODW(7rAhx^k&lX<2h*7t5TMsxu6q(|AdR zL;KJ&7+})pPC3obH9UMDE+!2R?L&J8yY7|tS10PjONim2eQ2L{&i`q5l&5I%`EW^m zKD4hD-Z*{H#azR~_aUoKaA+S|7I^Ss`NA~~iTd!e_{jjQI^29`aNJSTD{yRi2wJiFe;e`t)?@QE&RGuM@ zacEhogW=#Giq|FTL#l=lhYu~&6QXqOw(a?e`tX|gd}v=&T>IwYor(JJIxr0TppwrV zw1c41DC`(}^OH=<0DLaf0oWP!CIH!jM}!V=gPjFsNj_KT05<{vpT+J?yoz}6Hjuyv zvA^SkSiOcgJL24ZKym+s1IckhxfDDBUm&JWJEyZl%&EfoMalf|^1h49p30Z-!u3=6 zq%$3X&PrlGl|PW7X8RmCx15OJJ=BYmi~mpnwGvPshiU+p22Mt~&}|B7+DhwlFN(&t2!hduP$r>o7?S42dpCuVB3UG zZ+{3R5C*9zfSaOv+p69q{q**S(c?~2LrFMy{i5VBe?NjwIO;KiK|SX*z>w#$KeXv= z`J6rYIACJ}qTDhpL-nQk=jhH9oS2RV)~xw5=-m4!ViC~&j2gDwx=#VpgYwYP#A3tI z;M236KBS%&sxXeEiL)L3J}y;v#52U6_4+!h^fKXk!pO98$;!L1Y+XJ~wK7?Nf<&fF zC!M2-B6|bpLX=B5F%)~}Leu*d+yJ`Pof(^rgyQTfM&w9*!I(p_A=ws&Ur9r9ofgW} z??r8a=YUw;o-Fq~?xwhKvk5nz&T1Grrqm(Hy$D>8*n$gQ-{4h=OK?(z#ma{Mdr^m) z-sG_K(IEajkF`<(>flR6r>)9$LH95PD`1>dB`6js=w zMAz>vv`ujqAE|n>$Y<{mh)t0gZjY_WcB1I;AOsRl4dLYl}CwsG}2hh}j!n8Jui z27_oVx-e5Aw|+?wygc-AoQ5&-zDAcpHju3Oa#<+tKrAapS$iVLSrm8L zsfKIzJ)?zk+o1CU?s54E7n_Gn#UN%T?U*gyvFC=pEz_YbMpQbK%&l|GKG6AZSbaZN z?^hyc8-ry0432bisVg_cUK zD3+J6CxG>Nv>05UM?3x}Z(n z$Do_NjcBgMvZ69z5y70!Qi92VocXJTL3h&YvkYGDrxcT?yB|qUOyF;tGm&Jh78yEJ zEiR@3*9(}Qp(_02-fdl-Q?;bw&CDoX<_m5~z6LRzm`#fHM?WP-;*{+>RuI;R@Uf^S z6h$h55=E?G0=qY14^t5!*hyI3Y8A$CtDD3az{J$WC=rC{cwA43iiId2AtPvIVd}nQHT_;u{%8p(Se+69ph7 zV34DM%3{70+7&a!=!9mZDcp+%2QOMP49%@YYg&ueNQ)h!)I)308u{u}z1l=;(VEtx zH8|i;mM|*5%aUeH4p<9Rv=*&#I{IYyLdgqfoJDK)8uevWNQ7; z*OF!1qIQT)SB04%NtO7al@=?|34kO|8p@PJ$ivFf1T31SIb~<2D$TLTO{CLYX--Sc zm|P)awoy)`M-0xgj4CnWNIg2-)u{ioA7?+3SUHi*WQPV>8=C8_g2@ggngVG~CfG<} zyfSeu5!YejdaSsjyvoSN#)d|eop3sa@*jc(3iW~_w zYKAWe_?ssB{Z)P=UQxaXCiveh$C46Wj^)<8`}5Z2ZO;2w-hsU5^B(T=Wd1Yxr=T>8 zqUNyTEGt=gmc0oVXxXZ~p=?vWQoc3{wOpz3QY}AdKWf+KT#>sj_paW%dS8*pC0P$i zo`*c|=6#;GKkrvabue#PACl`SNVYEjU-=vIpUr_3SWZlTg4_MgbYEmStd{u5caWmbgDh;6A|{~})@s)iUp1B!e@i;4<|3>|1Rv6}&f zg+qo6QIsKrhZORzmMgd9U@Gm@zO6L%hwbAJ9{9hj+!D-3#Jxk@5|2QP6Cq0I;{161!2fpT77{R#$}I)GVXz`6#b>Z#u6!P%r?qlRYvq>A zkh8M2a*N16@fPu^t*NUCH1(^NGUV3EEv=PXS}V7-R&M!kRBqvGj|};v#~)pg^Xd4m zH*ImWedPYNbN;U?xAe|tH62c9uBkkGGL>Gy8tJ5l#wux%BgvuQg#O|991)i5%iy{SkWiq6XdVoMfTdXKi+eJp9mh=nKseXmY(ZJN%W#hR9 zkk0RkUmJj_RcAOHp`LPERZh=RrBRIyb)#wp~o49mdymSc=V<>KH1UUnF?+-cs3x2kF53AQLzzG-~;PMAm(sq zoQ4kJEyaQrz@ad{tqssH( z<~A1Vv9Q#GB#d+}H{c7{*#xCDNyW$h5++%U>*-lsxXwkG|Xf|K;2w@xZzKu z3Q96|=)v7ES5g~havBDkRQX+1-l;m%duztTb0WAcyaX`Z(MmZN=Ia))M%|w}$bNzV2N6(O?;2!SW&Bx*1kF8x_RvD@c zkdP>bG4H3b^8$eJt{;rzI-d>|=5hA_M*3M$V+y0_gtg7=LB>N3d2Q2zx~RMoYmNm7ZSMyT{NSE=U& zkZ1zA=qmNLsQF$W~XGVCCR z_oyQ!2@{3G1v|WuF7Hg2x5AdEaXKe7SJVd(M$;;4*&IcYG#-Y-<=H9t^$m~}8q1Wy zcbb;q!W!OXiI|WUa-sh|757D1_|;vm&Tu(SQ^<|!KSd)T+#vHQt`B#^>!$*DN;mvc ztpxty1ZrzgBZvwGVZ7*7#hSR(!_EZGT$<}HMm!mu+pt!p;Wn5XYWr+pUX7Vg zt;QfiQaL|IPX8?m^0cBU4buiy+7r4UvZ@+HLNt9o47p|JCuz=IX%5Q1zr>_ugo>b1 zSPS%d3Z4j&AWPHbH93y-1JTe2L6D+w^i%7A{+VW2-_8V*J)f(gP6x2PUyN2`+5 zNQNth;eH5bsbhv2?)y2wd>@#);hurv_J$*a<)lVhK!nS?_8g$QG$b!F*js51OoC*v z7t9D1^L7%#+L*V;G~s?0(A+@793rQ`Y$A-UN1?kil!U7H*J9Fj@PIDhu{9_F%axboDZa5fpk6vo3pDUy+6}IUt_ZMjbS4nM|$n=K>8HRwb|7fP86P#f69?vx$+UY za=Ook9o_qH@+l$jLQt9S)@^sR4Kqdn2-G_W^)>^w$cAc*QDM!V7Xe`d5Ke;W9mx0; zrsHgAv{zt8<-uLZeb)A3ARdclW-q8JrJopqqFa??T_IdSShP6p&aejCu&j}>n499P z#en}9@WBm~tX%!m<)U%f&eU1%#Y<-izF~D*tLWXng!nxja83?@C2Nl}Em7&hF zp-!#Gpg-G=TEx{n`bwbQ?!m9s5WqVqjlS*xv)YA8aqB53^x2bCrpYXZdgzLAdk=pq+_*14sLuZ&vkz z1D(s~1n@-f+=@U=L;a)*d=}vk_#0`z#Jx6z%YNOBAoD!P^ufAJO8+cZ8e3mE!e5Kj z#KtOmyK=}&Z^HdqUbb6>oV#+Rk+e;s%3eK!O7sDAjRIk0SSotW$SER3(rC=85E|w*iOR2A_NtODf>uX4`aHB6(%1fs*g3RV-{Xpt+^-h&$z?}Xe zgQO+03)@*Kn2#L*dK~Dfs+l!Q?@i*pN3h;h>3LR}uzZrpnxklT?MoE*q|q7{qtVzE zBG2&}m6O@JDOLKG6-DGBfTbjxFA(n-w62!xrEW?CX_GG829C+n&B8R+ZG^=vf#%xE zLl#i&qL7L7Fe4u_=P|wdGb8q9M${opI}T#KFHjvvhGN!oEp?^y!ke%L|InY?VFb28 zJ;)vyZbB z4*3)gNtHe{dkxDs35X9E#Lqpz4@GSKjdMmd*H_ZG1mBk!-{sxWH=%UOK(xFJwNs^A zsAby7GHQ8^wahXCc07s-OTmr|a~=6wJm8p39~7czE$i74MZZr(8?Bg8i5NkeD&5HJ zNKd(}#W88Lq)IJUs&&1`f_QjyO>Na^eAr3L8Sc7CB81%}vmOiJ$b;avFx^@#ZR^^> zn9#gx7#6vScGyzz0!T@69!8DZJ7TKq+7-!ZN@ESSfCj%4gdnJ|YD-)>N8W=+^QIs$Hlct_jGzN<$0}5%C%gYSA*EBv^sh z^@%CWl!}?y`3L+}hAgyg6TTZJqzNzBn=GwlrmLBa5i@O2fc6~bU{i{eLCMl`6M}YS z(UNa%(R|l$yjpOXz1;Jg!kM3$Ln+EYdm)Y0dS&}AGrLfROR#Eis&ofS(k#)kj7H-! z8w8W3+2q#JDKmzT96fd-A96H>IN;kC`Oc~@XY5F7)Z9(#B+$!$ElK&#)C~61_6p0cQa0#dIPs8zr>#F=FS6KeVz`JMb+q9!zo<4@dcZlkbjAdKpt_+7 z&n6%z3&IlE^}kq!+4Z5Q;f-misiAf*ZDqO5da&gjCgPZL%@%!`GYbJmvmRRz&{wqn z`vsN{r7Y~?`hJsPR3s`W;1G7GT_Mxsf0o{S-MI1TFlkPgIr4v4K&TIbUC|9b^f}#2C~1% zBKkt;_J~!2wd8ZE^s$*Zjd5XJgSa|CV?$q^y2|u*C7}+F-*J8Uxw(kZgM_Cub<3QE1i`8DS_g z+@c5*bR0Mhf}ps@6tr#kHtpmQa%!rxLk150NMD`VbNI;gBa)>KLJNrOR^hz+oA&DYO72M*}Fb0JH}H z&Yb>^igAlmwFg?d>G)Z6NXfE08Gmj!}+ja%x4o?>_-!~ zAuqshbCT+Hs$N+f_Bz~t#v?n{{WiD{1;ioMce#ak58s79hc~-i%=I#k>AWQu zk63UPrW5xY=y3}_3$qOJB^zfvW(QpvE2TK6I+AZRIL=kbpZTR?{2N#n-zlC{?+dFch@l^6zsJ(F>s&U7r7J6|Or?W20 z4Yh+d`r*3V=;=6>vm8p{nyAsIK&dPk{Rq|DS@mWLy{4ASC%L<^bG|WhaL#*ich%EF zWlh7I`FZu8?kXJ{j8koopx>IWC!N%Ma;P)JT$Rkbph2dC4m)=D&R&NMDFw^uF&Lfr zeoL+i;$r6^-#zl?+`daLE|mr@xvZ2PeSUIqcS*A3nu@mZMZkuUPr;$kJycImD1Isw z@0z&cGoW}b6xUR*qI!D?#m_94XS&^1#q(58AC)y3isz{zH&dJ)>8<%ZqPPyDzE;p6SfpU4CdszB9I1t~1MZks%An&U*eqPNTPlwPBZ&rMR zxk1=N$o`ONfoHJlE>v+SGS2J8Q&kKdXm$#C5SGH}&0x(q;#himjtbsR$nlB?M`~MA zFx$$7il7cKPSg ztC3;08qHL}*E=NlpcuBgz7K4Lln&{(u~X)+0(58)Y_(0{$w~1|A~CNv+l78W;YVp- zi!RTkI5fWwfY5xD>KRQWug9N}Hl{T;smYHUrXUOATN1RKz(2Qt8bJu43D%IjM zNb-jO>8VuR71ju=Qayg&WQ@itHB`Yyqe+!U_1xP;D*?G44(z|8jy zk*>2kVvg!LM`cZhBj%`~I_3zIpw$tLjMBQ8967S#7f8KbtVI-GfXud@gxHbBk21dy zF9t@JJQ^LiV|y+;Is9KB;t8lzT*c?8o<<_O0WIt(ecB;-8p6)`Hg%yCEyfpHGFj|Q zYHm}Qomm&-v=QX&r;c-4aUnlPLODEV{fQ9S3=#;Dc?gkaJw#ZYnFVU7IgSu{3HUJ2 z%lz^xF7Cgnk$W1fU@;S#1S4z_7J09MQ0Q+WoS-?Xa2 z=Wr1qdM>+IEnZCOyiMv{th&#$4xvj_&l28b453TZ(0ObKMUzhRUCM^gyD`~vWMc@q z_oQL9za6Xn%W3gsn$8l+VJK|WAwpU50xGHbUcCG)LpIxYxlsK>QvGrj>2HbZxs;6Y zkx37+VfXvT1kFtLsRi~afz;pg%MbjrmtTIy#l2jO zxueD0h`sCTTqHnTv6nqv>}7AH0meqUaYq3bq<8K4UiNzA7=15mERpwtUuZdc%*Qh; z&Af%jGq;fA_5;eZQgz=JR#AlV4$qWU;$f-rS7LFSNN_YTvVC{4$o!3TeIcFCeDq4Z z5Cm>p%BQv80b%$?7v>K%vM4%;8_!*;L0ivxA!Y$Red2^ylf9nKVx>>RcA+qZtO-(% zMiE)!V==L3`|f4>IRMwPeojC{=;uNs)2|I~Jol>ZTdnE!e%13&-ejcL`_<5`EWI-6 zHQxh_J5}llErZ$r=)+lL`yOH)RJ+GwGi%mlWXweSo}OqwqQ@%Y34tW-IS%D#@PNQ( zBSaL>t5gJtZPTdkPw~U5hjXPuKk;$3r+2OaSJ03Q`-b1~)X|pD(->dR!xXO_;$>#b z?T<3^;LGWU@LESeM0hQeu?KIeN91{wW`=*No(D*pE@&~vSZP3E%PL_DK2;bSJXTeR z564m(1$_8XB_U)Z48?@AQBROSHfn=i*;A_b2|X22sUY`S6!~+>t6^G(0>z_jnAvzjjDHpZh`^mfs94CxL;C3&qJALThx!)7WHGcMWs4D zKp8?Po2`TMRn_yF%9@P9`KlV)%m$}Pm>w>Rhp3wGbry6~+{gWjAcdhtvl>Q1vP+5~feybYV5=P$gj8^k)W8|rH56Fi$KsoFK8HQyr=??)zFQNZqw(X{6=oVW0 zKbssOzlDK|({d28WcEZ6!n-;M4XEr7rvEoo&o&B!WAUej1tlKAf=8Up z3S)uf!r0j9+)9Awc}op#gc8^fGpid)hF(!26np%qZ(mDEI%n}~s^@iLJCgo%cwYPy zK{gH~5M=Kn$llSzYdqTA@2jDAAXT*Ot2M4B02Y!=_GNb!9^TAhr3Tu!me$HBtn zGntwSMitk>F7ob;y&R-R{;`;!JUY~Z}b?Pi8l8xHS|p! zF<1%M(5`5%@$DvqRuL`RT01H*41=xKrfa79U zL+tj1?K(^m`MivjCuX@rNq-i|!CBw_31`g#2{>yh_6Yk`?>^PLSM~m=dcW5lcMket zghqa8;+JMz+<&N{A6eetOTUeAI3InXKUfFr)`rTO_?rQ0K1uV)nsxQ^8=3iB;CUns zcYh=52V2;H>=YZ2cf|%|lh}YTer#YfPIQOt8wk?rBzyz%J)$aN1#uopd{6`?PfkgZ z^8KCUOVZp2Vx~hYaf~Z#{tFU|10tk3i*}JLE+Q7~Gy~AcVi8YT_>PBJnduwG+M1p& zwzAeKvRRe8AluhLqYpvwJ$DIX*0L4iCP7?_tXUmkS*= zPbP0NmJ1!V(C;idnDm;j6XSk4up{*5b3cPNrrXdySn)lD(=b{K*IfLxQY7a5E0{>d znVP2)h11nUdOyR`C;2Xn=e2g8d@M(9%ebwLhzhk}>+7OXwAs2VTZeIV{Yo!fIiyHe27!L@Mr~d3utq zZ>2x!<*DT)VHeF9R>q!#4}!2g#|n~&hg&JzbFhqXI}vkuaG&s0bT3FCyY<#ad2=+c zs(G_D{tb=beduxLX`vh~`eOStw%GoREw=wj;^hJGGvo81&vW6{PuVAo0W2byy9*bO z*xZ{B9y;+LIylDC#@-!sy;Il-1z>v`XSX*_0)6MQ%_Y_chhF5jogu>Q;>@E4ncmL5zsv{KLH#@ zFI1*f?`x#q=Y@LdbqLA9nR+9AI2lfEX^`DAc#_!E1e^QZY&zCLES8=CPK0?lE`j4I z;D9^k{Rz`N2NZC}0WeMfQ1lejF3+PHx_*(EJPp$V?uYVQ+kNK9;!78^vPZU^sZoC41GYj(TrqW~$6S>U`(Tf$H3yFQJ!l8sRF$zk*W< z)61xXjJR&{kb4~{AY&0^EHnk&Nem7R8HHdl*$Tut*xmpvIN3#AhKCy77UAEswlOtG z>kwO<_}&I0W4Q1xKJ|{Wr(P^QhLGU90i}-$S%7?h0JlYkik@Z#tvSpk#~vqYelqDN zXAc?xKjCg^VO%_smUxeP*eHqjE8*K16|pfaHhEQ>6ZDBA!Krjh?nR z_}yA^AaPR4Zsxr~oq0RfJdG=L8(Z^iV{4v|z(>JZA)PVxaYLrA{G&`Md?Ds$N~i?G z`It;?U`%aD8>OE``q>Ls*!=S;F7z=}^%<^Ee9nt6c=07KzCz(JIn9KhYmpaoux9)O zH+QbZo0=Tf;>}jvr=MKAENqxA##1bp2)1+{6!zMdeTh3IoNdU);aDisp*KW>FeJuLF0~d?|(VJ|H=6I7DjPXw_^k#&jWufTwP;^=- zdVy(}7HEg0X}n11MFuZgp@>w5Qr{9f8*?t*5-Oq+w}ein62}|MXnJA8W4d`o(_4aG zfXP>67r?v?R%ER~&!`k0!ee%|9ka0~J&O#C7s%pRK`1gO$4v!cPc1ujDGrh*a)?)d!J?3UDY;O9e$sj+ zgbV#*r=j_nc25S3d!~2ObG)Gh6PECKJSigF0ap%pa2d*q#Hw3HM?f)6w3z8a16<=K z3In2ni6W?Ea`wc9zBptJE^A%J1@f%Rase$s`MQkR`vgL!=(uijFv^dZQgy>BEatP()UlzJpOxaBWDxE+netzBF+3YeUAW5U$8ZX`$F^ zGH;AJUSl_i!@0}I$9RT)T}Wq;0|@e;<}Ik7XfUs2UJT#IIo=i4Fk5b30WTZg#uC7p z5sYi;YNCBAFhWbXZnBn!00p#k7qoO!D7r2by&)7`8;Y(mwKNp%pfrpZBT+=wJGHbS zq;Cv~DxswfA!EHmOSclIXHds~*bPEUYi%uU4CxGVG(kRXYUvPZ=_W`o7O=)TQ#Zy9 z<`wXAEv;#wrCW&h7+{2!aNT4rjROj3>1k+bODMWI6x|ex-Vuu4W@>3X+CgaoFDCM0 z5{k%!|HX_Jh8#4bZ8jw{HknuCagG`7Hix7b-|YF5#5tg6Jct(iF6G0n>E>S2#(99! z9}YzxNI9c9k$Yye^NGX*AVJG$K50JIki-Q<;<1ngXw7K%hq!F+8O;*XxC5Az&S+De zbe%IA7O{LrD{(_m0LQAO!HmY20{5G0H9WF9*B{f9VPq>AQ}m}MwXMq(4tCG>3lDj5Ze+`u33J zbXKJ2F5-#w)ozYbO@1<){7fg~liwOzz?w@)F+4Ek3D3cm!*g6VwI;usWW<4#_Sd*0 z?_g@X5O9rKvlb8ytXYRjrjq%%(07g)RXKM4_En>%10O@J>i)D3$;Pg)x2({|&;r6jjg( zuA8irD}Vwz$-s$^_d?MfS6BTdzkTXjc3ZNpne@N z8Xuv>4(eaHBJKyo;2J>bUxXsxV&24vNnDEkOJYwVQjzzFz~yOh9Lz7jYXTkWka73_ zin;yu#JKB_8mGyDXnDF85KgyebpM7*=JtOl2EGbeobr(W3fs$0xX!+;1Ec`sqk|#3 zkq{|5uAA%$8-N0ya2`D2+fejt(-StL8tmVOBCz6a9P^NucnoZ^@vUib*~gv} zYi8c(xt+SXo-o@_2-t&Th4f(VK2rZ3fCBfpZZh{OQP>k2Mu!sCp|EEhLtlg+HV8 z4AuC}1cQ{B4C}LmptWioVFbAt78nmmv~S$p+yr=DaFG%+n`nXE7YR_YNs7lR&kOL! zD#y?^R7xaluduZW!p>(Y6FYzt2}3JY&s0I;CH!Tmj$W*LA?OfnIjApiiFUVGPhVxY>1dzXu z3q4CU4u&Xv@(4>GgfM=#BQ}V`sWzlRlPGaJr+<6mYbUyTocT?{)?PIZQO?Gk8NMuM z^zXn_unVop*)~ z`5s*89aVM*`8~SspkickQ?(He_dWsp3er`*CGqnielq8`$NNVFq39UXO??mxl3lAG#R287dJ^^BiGPC6(_7gr27wxh9Z^r@g#@2MDm28i}ax zc*?M|czQyTc={vp+=JsXICRloavw6o&N|LJ(7po{S(D!vaeZPyZvhNC|1i z)87g3M4KeXg}lTOPg5dc@ib<|Q}zgPk|)=jO?I8}JPeWuxBXQ86f*Bo{B-!FW9etc zkO52ul8@<-#V4lMf>TxfG)s9r+@2~V;m#6@olX>F>KXOQn4G53gK3yqfQ4IrvlvfT zvgKvLX{yd}D!|F&h94LD0M+QOE*tWj&ciKzFu=%xuZdkS5J#BZmIg(m#KDIC1BtI@ z=*q-lv4r`03&J)~HG-s6YNONv;dT&HK{{HKvu&zsFoSCeIN?-cW-3zkAs$r~c~mu& zSjtFAA-Q52sx{A2)eu!@I9mZH3%8lL&TbGXQ-(5%2_aqsWX1DtbkVoe^fDs!viym54ACRil`><5~1K6g!() zH%wi}i6#?Ygeu3XHmhcYIY-qet7u_b^5mMt(5 zVdxbjR?3zu*hmd(#+VZba=cA6S;tXQ(bU^5pYNW#Bh^!NH z#A!(!aS(b%W;z{luBun5qDna8T-BJ#{Gx(8Vl{J_!PIrOXfhqKh$?5PHmjy1)~Nc0 zDq0+lSfd)V9FADaunr{zb*eF&5#%geV96YDxL_kSsOg9!2y%{1G}&aA8Vhs8I?ECN z;B0pWXu?k~RP|ai(rElNrhDg#vLt?r>0*vKUCg7dW6;(1Q)corQKio#Kdn;rY62Q7 zfViJBptDc~KgD&E{q%gGfS+EX4vSu-Mi;8l`KFUjK?}%Uz>BFUB8ydf$Kog+OUtLD zsI+#QPOX=6SHsdBPqEC0+_Z~am@VPuIBXZ!l|M+*WP0;W{xbgbO{tB5a!(h68e zF4D*xbTAe|3ES}g7On(Uo*e zB~Ul+O_3sf6!}~ii2yzWh{23kNv*KQ-DtkQx01wLz$L+TlO?&FOY$2eS!GJH1a-i^ zlo!i*u^dHY4cVNHfyiF-`ObmZ$}q(%qQe772I=Wl7KT+}f6DU;8x`}1KY?n6 zjfy$QpFp*eP_5-o%_fP0b*g@&DyqZ;vraYEnlphf6uXJd1Xpt=tQHacNnEa&oY*Z4 z@EQW#C&t}M8h2}GynW1%9j!tuhvz1~j!b+lDp~%1JudWH)X4Qt4%e&t2D3_VxL!4` zH#tnu)5f9LMn?Q^M0}0Szl+PlIK6dFoPDzphzN2_-+RrRZ`97^X;%O~Uq!)#m z>CO#|-+~RQzLD5p_lJp+VNueCI!VPbGsd1HG^BQw*@9P*kBG@ZA2{s3+&e9;kXGX z5LkY}aJ~Jp(Y^ zYVc|b--ES$YP*fl(f?W0LQ}xiWKF#S6wuTYNQxd)qg&PJBc{GyMGJU*jTf(@h-^!h z6um{QPdny(;}Hn&O^PT3kc@3C6R^^uU3OQI4%uDpbSP=px9zSX^Rc_ynNQNLyQyn| z2)0TG#y!TuH-X4gWa*zH)}$qpocGbe*b1Q>NzPLafhpmz6EsTrJh{#XZUk&@;|T0r z$3{RIo-*0`%@Q^b!VldD*$l@K+9{BQfTfJbK==_57CcFQxtCBs24S6<(I=>cvjL#V z&h|M_z}bGpuzbOEvoBEh-)2Tnz($Q^M)=|@&x~Gx2<|gnJ4n2*xFoo4vLyStBtJuv zS4>I1M;)*qAc1x|T!W0zoBij5Rn4^hM*@4DzZ;*iBkmJZrTm_zL{^RAPS zcYz5jypuxWMp7I<**KUFH3i4N35V-d4-gH+ofEE;IFDhkkueUTE8Gg#O*Y2wKmoUU z9y?)gn8rAaI^zxKjL+5lt+;sH=r%33i^v{H+3t8$lJ|!k;+(AHN4(ypx{se*Ksax1 z6Qmtr=TUIBQj*ahvcB~vWNii%ko9HA`nD-+bJQ7c^Wh3J)9nfI76|qT&~B2KKKBmN zxNfqVTXNE`f%G1ebOw>$W09uF<0Snak#5CFZ-}LPX;$m-6;CRNhH|()XzrpqWHF_~ltO&YanADo^AQa+?c>B4Xc@C3-oDo99-N zcMxybps#fc03HY-2!Cg6K5!KrP<4j5cQVA>C3pw@0MYMjgE>50xu>KXiK)s#c%VW>1?WVJ=fbDh`1HGzUbTy4aP`1UZt*K(xW^o zAz_Dr@*p#*g4OUa_7SLUDc&W4KWrAB%n6^%i}Q$9nr7G(Xz03L_*{^w>8&*aN&_1_ zp`ftq0@5?>W(tIXSR0LwCQTvy88(-3Ig@Q5q3HrNIZ!%66VE|%Xy|d0;Ql6!gw1GN z*kkHLJdi$>xN0fTnfy#cB{ou8YkC_E?3EIX>mhJkN8H~`D;N^=B0kgjM>!}XVv62O zYx~$&C4twnCEPHm=^=8% ziwP!`F>F7yjd4ukc$zC48f1stg)uH6nu^}>Pk7@}pnx}?jC`r57L908&Gg1)Xn`Qh zd2s~_Bch27{VcVAR5NUeu*MBQsosiQGn*LlAcMKy4MVBUp0EY;f9z)6 zS~mf0Oi`M7qC4 znns|L^Z+8giIc{4lSyykr1L@gRFm{Qr~~%)P=AD=T!;HP zF1U->OL!Czh;lIj*C zqCdq;vnQW3M95$>m)+usW1bd@%C>F!<2rmfu?GY}_g!ARhaxgXb5Nr^%Js>bf>KQ{ z(+Fq^gh`c0mD_zxV~mG93K;o zeDQi}HkV8W)K=Os6?4g6K=81`rxK>wPf*G3_I`#7eWqqyKuK7vg5mrebp}U6_mOz= zD5zT;eE}e0Rco#FrHS<`TolaKbdK-;2;X@g{dncc1gAKZO79fZ>dg~JA7 zmBh}EZZMG_c===f#9|=d?aB>8j_u3IJeF^q{0ypkrRLBBO(A&4klmRo-Vb0m^SywX z79T<{cLw71nqO>b9B%U~Y7wE~LQRg)hk*hSx(4CnLM>XYMdzA9s@o%D6riZQ2bq`aYy$GC+f0?AW7?Hz2bc+d{Zc~O z9@kup9dM;DrMly&-G|!9eCKNT$5c^kEKBBQrYo#whSdme1>kn;u{Ahh z#jZRG3j;=9qZOT{JAxyGqj zt7{Cc0P4?+0)oA|QRxcSYx)L_fUZt0j=tV*=EGql)8_!ri*XI>YB6ytRbOLvv8qo) zHBPW@(DaQY$UuUE@Se_tQEgns5XNpLxFWlP;u25wJ&GIxn1b6iopl&W9lRdq?4aLH zc!yCRrrhDU((k0Y5xBw#`m!D2&YzB*n&kPV6Dg*n)Px`gLS@T+`G}1MECE9?CAUS7CRg3XzDKdl%=s zyNG>tyNhGFYj&A}E^O>i!-f73>97P>D5j%`+?Rq??wSP;Yx*M^0o}(8XM34rMC%XR z&3p(v%H%62{P%m4QI3e))bjtC05$FxBzQ7vFdVbcz@}XG;K04aeFdsm2$+Kl-Ow=c z^Yzwol>Bfc3_bP3yCX2o3v1avQb{;`1&?U@qlB^wKiy8n&1-k41_Z-r^HD=M@cxEB z;b(E6fS;Aa&z{htkC}c}PwYIc8IM^$MkCw(Qpfp#X#ik6K{>aXk}V*Rr>TZ9{S-;M z5OrW0*G(QAmjDHrE(FutOpX^3scp$z9;qH)owl85U&?9Yy2-RJ_OmAK%TX73 z(HZh7VOUDFFKEWI$(Rz({gS4?tP#))!t=}!>U8dx>}KxVuaGRuI8o74;CorqS>tjv z8ZR=OT>R&$%N3}F>T%s<@mB%`RDU|e$NfHh9Uf?}LLG{$d9eybL5O@ zn=Jm#KmqYT$LG2~(xM+|(f73I9xeKgsfvFP*>@lZ56paL*Vv=c#;&!yyWR~X)_5NQ z=s^PFi@FVNAhD?X06_nT6^~fOZFB>P<=K0nZ-2QuaVvlz_TE1s_I99v*q`A>65jI2 zt^O?0{sg49;Z?6g2RWYT$a?p+L*L_(kWlOkQv35Zp!ojp-Z9h1;(l}+@iogA0Z{Oz zrZearsi3n6TK|$Tz62OZ^!cBV=nbHNMEfAow_5aTE&7!y*PCdGd~f|;5JTSfm3h47Z#D&9J^fxW~s}?B5-DUJN-(XGQ*J!YT#!Q`6W9Q$S-JMgrh$wxApa{f-T{Kjl; z=3;Ha6h)7sA=1po%`e%hMSe+S!~h!9yZ2idK;#(aKbmo*=Hvvpka1Cv71lXsKYm4I zE)L7d3fhMC>@ce`1E=0LY{+48&kfIJv+QordDM}an{lIe zAo5v+S8{6LxUk+a%&II692YhuQv=6`Vx1UA?WpHCk=|WJ=^gh&ijddpGyP&$D6J2%3 zmEJjwF~q^lj>i*8mw~&4^{yTRcM*0>ZiY~-8&Sw17JlWCNEXWA_HF0~mN^Q#hIQ6E zM7@~+_PJ_FN|S=I?u1-LGZ!R+E4@2s5CfAtr{SV|&3;jLyD`sthO zo{gJLHcwvXC!^HK99E4`GPNrxnLkrg>Ya>I-XEYu#&XDH{!C4&4=7=KBPXl}$Q4f^ z!s(VW{}nJb<57|$0+|kGJy#k_hJ$$#SF|a<1BY2<;pm?X2TdY^4^uD)4ztR_F@SJ< zfR7SmBqh3&-=&k=JgdT6Q0`D8Y5e!-{y~!cRKPQzvFF2qsM3RG1SLt)$M!2zIrIz% z%N?@dKQzb&5oyOniwk&`52;1Y0!bJ}jE{1Y) z_SmrA^&$M9P1Sy6t362p9yq21Hj_ZyVL(-&hxMMM#^EXPI#OYl1t1mHV!6qXyFTn` zQW*indTv;EY-_$Z`6*D z*H%=`G&{&rB8dAMnTo6oKx1L;%*u*7hE4`LwAP?iR!&9RxN_9X60eUp_sOFyMn+KA z8V63+OCE-5H-A9L`5S_!hWrgiZ3_NCZ<0lCJmAJwR+m;(&8Rl12Bn0LiGEgUs>MmE zj!8{bR?bFaDy^J@wgy_6WpP142^v$VY$}=>s%#2sQ>!eVVfxC2 z8Pe1V6?4l?b%A1Qs4G)}VlTF!7AA+1<@snBU-6gnkyU3`*Ot|}ys92;gX?F^D6e%O z4>GR;^2;sc34uIc!Y8+U{xrB(J6T>NYI`|q8CQR`IxZ0)4)hl9*H}<1lS9e!3N&!u z2QQ45yLn%Zwg$YD_c9h%TgX=>N6w)BZb7Y04kgQLs9~;y|Km;F-)wbWm%KA0ajONj zJ~@;u-;$EVomS`DQo`JA!E8zibDssXr6CjTOr4GGWV+m#PSVuL685jStqWy&6l%_K z)G*m5Ssli+4%iK&P$o-*Wce)C!LDH)4q6=!pm|Kmf`+4FKN>J9918DkDtvYqlfRi= zQuHoI!}!`#M{f#RjCNLz**h~wDxrADd5yEy_Eu}#B(0sS)($z+ypl?nB4nj=jx@Eh zbZ*_$vg-QjmF4*}Di+KwnORXvU@{vmi2|@8E8TOXc=_BKY58%iezCM%N}P@s47Q*} z;`kh?%tfHNPwAO+Jf;Sp(u0?B1kgS0G^?bls=U%YZ1)GGkyWW0zY9nc7SxN|A$L(NWt4z|2Wn10kQk zTLq=6q~f&n94r6v&HLiKf}{jSX_A9WJO3 z6V!)t>b@e;K0ve=i1z-xUFpl)<&(iBclM}*%OIsiCj_O@E(?xfwvv^+pj1*j6Ru}D z1y6^1x%rfpK0(RyaSL`F8?E`4*Esx2R(c05Cl&SNq?x`;=Ox1}%afB^?QDr>n<`YTX)IL9%1x=oz0oV~%?x(T*r5*1Fk|~LENEchf4KKkg6+q^HlLTax|lPg zeq5FxX`H#oEh9OGCKS7iQ}DeheB}+{D?5cEUl$5~O(^(PUN66BIqh>6X2+nFm0++9Qh|PY!ZXq`N`MQSK?C0wo z;xk1DQMTi7N;Zd6+HyFhjc9Kv%4VXJMJe%8{tZ0x8RJ*jZN`i`S^!()VlqW{`A|?A zQ-T%sf(9)=lka)bmV-fQT=jf+D)U3*K6)gz`VWhFj5}|=to-ivm!roVQJ88XAv3{I zLrD{yU?^#VlM_mo;K)jkkau4CjLl1Oo<%5{oX`o$3F%1*DM}v(-m9Oqq&f1G1Xc`^ zv;lk6iNE8G5Q?JorhciKWu;eAJ}K0|Uk3@_87O?`bnZLysgQvuZ~a5kbXSIT3h-6T zb%xF=F;krul4|EU#tA~qS=`5bX9}MiBg#?2_lAHD4{n8CU6})OcqqwCLaLUPp(#Xz zU{eI4^97-EEP*DbA~ZQEHsD&!ariD319FiVke7&ocCnzfP?T{|R`XJx1=@Uo%?L>o zO0ej0j3UYjWw|UQRa?sdm%68iqzZEh;A)r_l1eM<<72BUs^VU2$npiDMpA28nUh+n zvqL<&wT4>-IB-~1Rw`NN6cZTB>y*{PudWk*b*=ELt1UCEOr?qyDOIsNl`58j<>9pz zWu`71TY*a&*TX6%o3-1gDAzFWF0ZPqsIG!mX~YHiXnPV~PV@4uLbQ!Sv<*VETP)FT zYA71zkg~ikrD!*#5^Zg2(bhCB+Ip{O|2U>-JGjI8o)?b(oN)AKg`;m5j{USK9~0%n zyp->?9DPeF6>Ltaf=#JZa7Uw#ep};Ocp$Z--|uzw`SX<6;styaDgHu*x7p9%&) z5e)7X41QqQ>OBV@O5=hOQp!DztMy|yGm7$IT z?Kr$Yo5TCta(G{sfXn3VzE-^5m%-bWmb_j`=k-dOsBgjhDb0B)|7xlDP)I79KdiEZ z*4U2V^m8iLI2e++7Mwdx^sx+C{=w3tNV)kusVF{`r7ua71msLG@`UO*Hlf6PVZ}UI z`H$O}vT_&|Rb}N!_8d@0fq`vCG0Six#$`oPr7FII<*q-1WT2dGu{copRW@bO>?fRn z&*L(1SXQ^%>alZ!^hTxhi%BH{@h_PBX&);jIkD5qN%pr^DI2Y>E#Y^B#2m)fRL$Ta zLxqP75gt+`JY=x2_#jaZ~;UT994>?tM$N&L%itvzr!bAEBPv|2&q_^;pd{N(v z_fztCDXZ9!zkSA&I=&mO55PHAAEO%8s>8+AX zO2G)JJVa9|1#noh2PztPhz<-%JR~=ThxAk%ddNvBJmiE%Jmf^?Axx@4T%s9VqOh98 zLt>43h;NFp?770SlZ9o^5f(gKSay=I>_kyNL0I%m%c7%GneL2arsIQq1Q*{Nqt+sf zGHh8M=FqPdMJN=Wg@#n7EB2ahTm!W$%J@`+Y-}YcCD%pX0n9hx7mDF)c?I8Op3li!wdQu^VpTe4^0_5tv+YSz+*nDl7HP)~l-+j1 zkim_WO16o6sVa>wneJ}65x$4z^Gb`o6(m8b`wQ@bjl%jHg!R{REBkKYR#t8jUT~xE zf_1!Iz77=lT5wfk6cl9*<5Dc7NQPE)AmB0tKZLRCy(U|2Y15H-$jVxkHjb>2#y8%O z-ft1Uc!$N!ZH;jwD|aQs-$J=los>VJdQu;0d2?xmUrHPWdz;iWPd-4dlt-|lrSG!Fz=^?*=xakloIAM3+9tlFvP7T<3I>mh;lXJF;p{85##N#WS<*xHtEYh?Ol z-!G~(tfJO+3WrF_zF*0h4eDX6HX6Sl*jnTF12Z*#Kd_l*l2bIvdC&7S5R+v|^LRU7 zXdUr*ySdP6sYzpJmDI5tt0K)+lyprRA4gs}6V>EI2?^OL&oe2wp8M@4xeFXdc_$z8H1lPJ~w?+6K&s!`J#nWSXp1Y&po=!p{?YZ1~v zMsN(|`8?duVqFAJe!mnj11y;SsbG}hLabrJnnQ&(hj42ugN3-KTewd3;^JdPRt6^5 z`5>-yhX`!Q(tXu4fs_xx(O#q^ge;%obrwD*MtGcsj|m{0XdxV*9N}4BgxvdzJqXR? z0ZJto-#1&76{4KUOQl?>txTw`RH$tlZM3`&Kv`snDa(5OO{${QVK(?+*)qe+cck2QS|X`FVD{1rp^GAxBh_ z<;|$=<)}5yd!MB(mwoR~?YYdp@>7<+pTNjwn~a26x#biXm7uzy>FS4%qRq}`C6kpiI&^)`Qa;#ju*NrDRdvuJR45mYf@ePTnR@c zxf>6n4Du&UDyx{`sKf!7+%U^3{JJQ6^3vBM%~>#p#Z`T{(`oD;-38dx58&z>_WTv=wk!03l$EX`Pea7MXq z7SD5Uf*bi2rCAvJ?n&zX)T3boc8J5C`-f>^DURbEuKkDCkbEghMwrE9!7p2_1*FAv zulsmfugOX}>zd!NFQ!c1m!Dd49vxA_QaL-yWLGLmb4ZayJXvWOmd+?Ct)5On;^3r(S`SVKi^Lpj6hWx2@@sfB&>G`#oWUz2STd%yllWNMQOFy*e z(Dt&x%D`U(R|anmtPi{s_%3iba8>Y8^`F{y^)>ZH^=0)s?GEi7?Hg^cwk`ar_IP+r z_{Q*4;g`aD^!N3T^iT9p^{@0qGcfPVZWjye2hx5@`#J5hz~zCZ zps+l!0+dz-RtMGwZV22MAbJ}Dw*~GDY!2KLxIgf4U~Ay9z~h0Z0^0)51hxmB4g4#x zGw?>>O>p&Y;Jv{6fv*Dp7x)Go9t4j|f=h!}2CoWU6MQoCT$SDo4cgzeb=pnZE!sb{4cbQSR_!*(v`M>5yIb3$-K*WFJ*fRtdsy45 z8QQDb>)M;zTab9S_P+Kpr2a(vRQp`}3L5xM+o$c$F)8F-eX;lH9ddtdAR4%o(cUjeVKlxzEXch ze^q}?e_ek=e^Y-;-=)8;zoYNg_vr7!5+CRv!Wthldwd3qe64?@f2Z%$_v;7rAM}Iz zPx`<0L;5fJZ~9^Vh<;RGoO@aB<+)38m*y_Z{cG;>+$(ZdM-*eaH-jsWD?k&0h$lZ{8Ywm5icjRu$-JE-O?v~tpa_`N(Klj1h zf95`t+h$N{_1v11D$1(oZI&H~eAxpq3C#t79}K3VidEBk+$X=`1>rEbmqq_I z!#_L+ax44c_`~qjEo3!#`Uo)p%yTreO9q1>MgO(HKc7rrM|b~6JhVJHzkmOLD$wUX4XRSSvQPP<-`kPfi_oC>E3Qum2ob+*jniV#XCI8u3?2X2s*HOQ%Wg8K{9 zev?O33r;AX;LZfD<9g7Q{htLV3_vYACrDBmo|tp~XTb?0P}@9&{63dBp(M$I6NaGH z)!=RObq(R5;wbrRMP+$yL8z$U{IRvwGqDXgxBUDu6{WS+b=5QCfk_p0^(B>o@$vey zifWhyA$C&H`O_<^&M(bBsjRXx6hPRQqH!FwFRQ4OqBA5Q8sduJLz74Fp*(^k*K;Kt+M zLMb||`p?pb7WfP@si@%$GEU4Og2C$Pvq7@VthMKrD4S7h%WJA@;{}+L=3)uicA2l& z?0k7f2nx%`h|Q7`)$?R5FQrbCG80FScA`my%3SvM1ornt`kVc*@6XPQq*a9>xe)xW%V^*j(`*ETLK2B$n7%Ahaqf3sTzvS07bJyO`ZS$_XvL9<2sXC#i^RC%b6y247WbX${ zzuVmJqc+*?{Y_$hUP)Q`49?;!$~i}l_tj3Q-YXy7d};h&*+$b?EUk@OI5(d?J-BJ$ zqSj|#^?D2c?w`NQ-r6*rb#V-KrpQH;YF2;o%gpbUQA_`R&&Kgec7A%31h1Q4gU3zd zGft|gs)XB3i+=dvl!}Evyx(fsk#}Fe;-&0MS~dx7WyRczIM?T*w{tfw{_vi&JA5ns z7OuGe{p>|eLm9`zkxcYS#a-^&@t0M5PEMabpy=y!CuY}VG>OOg3?r9&V#)GHvmaXc z+4O}Ul{~cco2RocX&O!k%CxgqE-Gy|@cJPi?mKz!YhQkv{czJz!shTJCVAEiu{+Ng z`Q3$+PI&5$fAqV)NA{!SMt>?TH^(juL5zsJ{)wmFzW1XC&MQB(z=4EHKYm$1w zcV)$NhVt~47i=iJV8w53>-=L*yt)3V>~}gg2_+t+p2ZL*v}uK1mhWEC`D$P1Wfx6* zDm&h(NeICs){zY5b=OpE3k}!j-uLTgE2sSU$QRl5O+z`id~S8^LWZ(`^INYT^z!I$ zrN4c#N}iFnH2ayRp{!$1gfoMKg;46CfBU39q_4%JGDK`et!lyt(ifz&*-BMb0&4ATuyPhv|;lx7O`8O-|( z>x}DeNYy)|kK8dwZrwY;x{WI@DI0@St>o-k74dR*kcQDiPLeoGshpJfstf+iLf=WV zvJ`)hOy$WovYsXP&yrimY$Qb^3UMb9oKhDFTOTNH?S?;l(X$>soA=0+pKPP>o-cG& zJ`KpN+u^|nFfg*Hh(9ecZusDQ9Krw|+MToTNZ1ujT!ckL;#z4$mI4NRo4Wd1t3hdS zeMM#2@Y<4v?9LWPGPa_o9J|YOXq;oY0{h+Q+ZKsdqFWmNd;~0VtG$`>H<|Lut>ygI za!qUh^47}g*2>*&z@*$cOWq%lzXyi{1PyTJATfScNez3f-9_O22yk~u$Ddb-KntL* zX{{`8Ew64ZGrYcbLAkYN>x^OKH`Tb_hH$+d%>|CGSllGGNzhzo-_}YEL$S4u4=MzA z!7Taq9Ql_V`I~_9Z9rCo@&KT&bSQ+MF-)b4o+kr2&Xq`s&BSWPH<`*ori+@^KE|-E zhywxn2Pon)TM-;JS9Wque2@>!UlIDQGSIi&mnk32^flDS+g)W+iEgWe<4&TJMKNF- zn2A4)>*Pp|{9QoV7mzE1@@2q%l8t*v`Mio!a*a7j@ZWhVP!Dg7KcA7#TlH=2gYjUt zt!@19H>b`)f~j3;Jt9lOP#sz4)`b`Zw{v5zCcHspq8Dc^JjZAd788&p~k6<9_hg|CW_udkuyMLD+V z+z1PY0pTw+@xrEtYP z&wH&Jhh96;D}Pp2b7epqITn&zFH6#~aD36okvQqhd%wtgZyt}{x8j=h&SSkZq*pTF zaN{dxR+Yr-Ys(Q?{hcj@MdM+497spM0_J-e(uw|>_^eulSo5tYQX&nO^uN%RMgK8{ z6M9#a!FMX+3#H3iP*==DEbOOAty*zXeAtYcF>^?HUFn39nNngOu;YHI-(OZWw=6^I z*_r_3bk;*kM9`KY^=M6V605^zYi)gLTr~Nyoj;Y*)qXhXMQ4jpp9_v?s~j!3Ju$;< zZN^)VW33s|bKMDL@z@FFcr`$;ez+ebCFo8~hV&BYWFiJZzdmQy&z+9IEFrXQH)~^N zWgtU(Arqhzs;kP`^Q^!y8yNikEERGOo>X2-&$HklAZOub00Hc|HZkM) zCSyz}FP&9|?VmrkXgq7CTNZwQRswqyJ3!gr?B5ywHm&5WR&v``a&{}({{>SMhQ0wit#$Zy5X77B{NQ3-8y8DkS$H8fOHxZ9=7$#h=cM8p1--hHK zKlH32L&sC(+`!cF5$S8h*m1?fMvfkeS{ly&)vZaz%qt5kVJjZC5pFofp3KY{Qe_sP zXh5^qMIdI7m?6A6WY)r(>bT_(diqO6`?#l#(8Gk^)%6TUjU(`YKhtoP@c zfVl5x#%T`yB!fGDaF+jmmlU%$p<2 z+%%- zJkJ6~n$*>@7sl&^aYb$vMdK!5s3uy*=fV^L2$?2bAUcejIo)I5z~JHI(xjfrmDzB* zys#YVtcE)0H`Hf4rcaE0_drdP{wlB!fh{Ua7P6ruC1}7f7psj|&CQTDGN3r7V3+fg zqwQ;`(h2Y%JXC8cb{t%S-2Qm~R53M^>$gjj-V>U}If!2USTIb`cw%((<1^;sD~f_S z&l1wD(s)gLewvhN%E7YmG1#=NY^b5KGD;{qbf*DBN07@gca*ZoLo-@^367M)EHfcj zhIFfMeBo4@UBpd!DRB*S=s&{O!*-O%34L)M+#Kh9(I1d|nP%7$5{KjKD{<$c%yK(& zWf2xA@gsuA`RA2PW$(e`@4riveiaHToKQX3JEsrM$Mm@`pkdz3=Tm6P>9bucxqU0S zLo4~XRv065%vfJkU9+&ZV&*Ko^pU0@QoG`VKlTus6oc0h5Zrn%tt&6{D`sxPXJe*! z&+MQ``vaP15lu(G{r*k~jN_L1*RA*%B^3Lb`P#h`BIV9py9 zz+9Sig#Z|h<)3#9&8e!W^w+TDzzowPt7u<|IgvF^Ixx4vU}KpmYh!s9Wuo+Usx)aP zMf$=CQwI+nKJrXHdvZ~rfgPj)%2MrIryeiI7Ho}!>m>|z|sh>F2tE=kqI_*`dKD%$0&0Q zN2nP2Jy<}x%Thm#SlMMO$~ zYiq=#8Q2G5E_XzPAes%msA)Fb*GYo(Rh8w)7DP_imziFX4j?#TlW}qi;r%_#l$VZ- z@!^)ox~55O90GZV8w5&|emB{wtS?XI*wZtlnBSR^rAc`LCx$}GEV?#LQUqAhEbJK2 zF`mM*k{W)q&mEM?N@kU&Nfo96UFosyMDWA@rUi#q(Y-|4jwF|436?93PLuAXU^S*Z zKC8OS5vc}Y=(lxfq~TOBBtu$40Je`f=V_kYmL^*s_&??Q9JY|=qD743uUP=hkaGN# zqOplPLweFTzjRhfE&akfh|)}rne&NTPx0Cs=&6GMqUi4BpE9#qjIDxY5zZ%+q0#ZClPgyHZvaFBgR6DHf)+f?ru*qcc2aH$&~Aq zpNT<;oosoKCjH0ZtSMa&9y@?^1T0S5@#V+A%*}}zh$xgKvUN9|K=qe(k>;1yxdvd2 zsmL)B^?*_Q-Ijgih?*AoO7Q`R0Gxf={pbY6> zB)w~1if2esbK_|4bpASBq{Jl6$*x(Fna=Wt7z_CR5X720XXadUA4lx+^bj)LZqJ_L z6_89<^yWu@z6(1o1FXq+97CQVRU}=Ze$|cnL(~vQs$H_#LdZ&{?TA*-_4JcAXU{gGLifI zA{>wMM{n>({+K2masV`pvxWXP(6yy$lR>`Ylp&?jQUb#SnxOIFZw6qo@UVpGB&_n9 z>A+YITmDPOtTUvO{cKx{O{DgSYlV)A^aGzlM%TqlYEw)j8PX=(;$%{K$sIE}o?wvt z?Hv*{7yx-LjkNvD+@9wJ!>aiD0t;`}Z@;Sz3Xu}eqXBo7BrMu-GTxua zgO5?!OO*MJ-z~89X95ioK&%81D|@4C0j+Z&q#6uJl(eI1{%(O)5C_6M!YW0XFG^bZ zx4;@ilAERZmgMi;^WH}TahZh^QCZSny1XoOr2T#6?+t8$)QzA>27G*lnvz_$KxSh@ zN#^C=qetxybSCi!2b2Ss)qzk$4MEA*#lE8(ux{uEdWOq%sYRRf5`&mhIVb=7`#%l* zPXqtc!2dMxKMnj(1OL;&|1|JF4K%KSV&!3c#z!jdojD`BTVAMnOL>T#k>P8T)d{Ej zZp-dIcxdb6u;W&&JmM=>9>u?{_-EkXWBB(tFXhB~5MkAFtXOI9Cxiqf4`lFi`(hdTaLBLVJGBSW@aZT$a%y^Hdm8^}RdcKsjREP@gb!97NaG(y#O37y;}ldc z4&Zum!04Nf4-`(sKchElHxTfKw9(>Y!?_@aj-X`HIKenI9p6Y|pSdakt0&^~NGO}~ zjZ2a=ACjH{Nk^ndhowh{q(=t}VSBp;8IfF&VGcotSb_|82*Ma01xkIuD9V(K9?K@D zfzyfLbbNaBtn_GcdUTB7^mMYgJScK@dSrZ3vlK?o@tEaoTN-0Lt}iEBz%FMw#3{DK z8RHN~*kv%Nx$RP9oMYK#62u(>aZ#oew-Ki&yPN@OXF}TY^k`{%v?M(`H9a~-2t3Md znsSFQr4C_A9KuYsgqh+HhS_EosEr1*D9vwdVYJDKFrJxWgHJxKSh=L7Il9YEDA6FQ{GwstYrs^E0CLf_A@1HE7eP=h_qLg*Itpeug<* z>rrbCSEk8}!Otn+2c@Y=(n;dq6sLMiOWILHyX23k$E_XeG9G+h20jxR(M5vE2@xgZ zNqkXLN^~S96B)}Fx0{H6#v=1-bRn7xE=Tu?U<>6RQ&U6gXM_4OP+uZQpNq&%;zXK} zi4dIhET%Ipgqr40)94?g#}kMV5^e<}e}NKEHkE^m!NDEi;5I@2l1L7Q<>Gcyq9@tlHYZ6`7u*Swi$D@(Q%NQg zh$tYt8DuvJvWdm0i-eq{H+f0l4bq9r00;88ZZi2Locz5Yzr`fKl*oq#`4dR;Eg-*| z(wWt12t<(lJ|e%2lgG6n&!&*XVN~-;r4Y#>0C_IQE|JI~2b2f1bWlF2SjlQ8ML$BbTkX)3E56PSH`F_+*s0mBb5m;_>z*5^qc= z1Xudt~JTdX`|H_&DK z|4ygWB@S2p5mFrJ6x}bRs5ka^T2}NBeW5lk<*>hzeUNEzy_CSwWXU+t$(&|6Al&Go z!04jE5Z(9VMwqil+PiK|3VW`n4r%dqIoF46KX!qOpB8|7UnHy7VB=j@er z;q2koxn#`jVzS2}!QNsAd$YR$zY0WP5!X(|_v34yoMPqc?v}ICWjo%W7AqM!Rs&tO z<_(emPVuzBO5ha$6err`42x#wkbFjF4m8gHl30nOm*SolzrxEJnkj5*$jSlVSve-( z4cAYN3?fDsuOT41?LfCJr`wj%Wq;jtvs(HX&GtmI{hy%u4^FcqXm(&UAwL_nopbCD zcgJunDu2_`#{#3!N@Eno?Yy{y7c}ZnNuwsxoqHxe4*g7;(IJP%dgmPKjTPV0LPBw` z8|-m%X!iZ;JSdk0&1%V{>jXO{9sn?e#C21AmMQjOpnzfn5b}6a$VZ5WjyXJEEhO(e zo>(=7-gflkL1~hYBGu>dW&OCgNYJ1{KzQy}_d zfCrSpSPPEteOU{iG-?7MhD8nqB2TtKl6X1N=83o)%Ekj77@fGRa9`N?DL_pKD3_;= z#wNqT04@CwlEaQP4x#O!8J1$d1;%5cX#B`3BRw*K6L&ci&){bL=)A9QSoU=w|6eyO zdxyG?A|m{|%Kr|~dJmiw>%Rpe{j+#fy9kW9NHeaW7Jn%AJJC5Sq64(>NsT{MXVgb8}*csl&KG#MpQ@V-qG|8)u?^I6w@ZqyHWdNQC5hOdd-reC*vR)wwVsq-%=v zlI>`P5rgfdVDyNv-LztPy2Ey55nnKg?da4Mx1AJp*=~nQw%eh?05c39+IHak_GI@! ztVIwinq?e;?RKc5Ee|h~8u6l<&kJ;_u;o*N#qw-Y%3QrgF!DmzC&{4_zrfT22OMUH zIvSm7+%|Qx77+`f=;kewXx-`YYGHLY^a=Ar%dXTisGHX38 z=%&naYd9Cco9bMNzhW%Wlo-U67>u?Fifm&!szG)Iwc0@8SE0Mn!D;ROfuM1mx1yu7B9;@>1F!}jcjgfh zc^($2?Wt-ts`Q*-WRvjv7s%{pZ_H(Ee$K;;%(8KlPJ;%MqXrFazzB^@-tY=tu{j)0 z^DG-ui8Z8<6y(!Vk@qy%KK(f|jjf8pw%78&aXnQ;!BC zooTvViRpF#NVuf7LvsKJvT|Z4Qz%VrLBB{Ii(FEVCD@rHZW0vG@{#az&2P;o zuJI%jR|Sx6<)e&}+XhOf?3N;QVk<86KEX&nalpo>u$W~~g}$it9*n099l;8F=-R>PebOyRX!192(! zjkpLdHwh+?jX_XgINXyk{P)P8Cgk5_a&2Em+U7O^%H0~J2?>_-(v-IyparJ{b?!#b z9)qi}%@vdVzY_Vm2FO$Dc>n(w9X}6(6MXt9G<;vgwJ?HXQ12iJMaKYdawK~dC=kg8 zAd>YrBiU=H1I^cYv6B~Xpok3e2DJX}Siu9@o4m&^>d`L9(;b=2=zxx#PPRbS*S`o( zZwISWN!s_&Q!ffe3fX`~s4I+*Di|8nhnZD!U#ilF293fXu9%yJV#BHL`$ToHv*U=M zJ~Ak(M8^?9W3Z#+8PxFu>UcWuh~c7IUTw#Ky58{xvb&NX!~&M~8;!y#bLEK&^=X-!wp;GCG_dgk7IW zqa2CHVMfgkl}@RSMfO{eWx4-8TiLCdY__K!F&cVSRaaFgno; z6F;FEM*JB?k!c!?;Zj6!}1b zKv9WgVzwD2dZP}k^x;Kc6p;(P!+W+vyRbbU-lq^~mB)uEN+#@Ok+Y*`vW%g-Q3b^I zvMBEI;<@Ay1%T4y!ANy5a?o5bTuG|sJz>=MHJoPx67t*ugtOX(bACgdrxDKiaHk{_ z7)v|tP=BFYa6bM{Cn_~)F(@(H%;3T@z=@x$Or#^R;F*o@zTq^^PDetUZE;nH&$tMZuz=&iNSe z$N4z$|Ami{j1PSgdCI5;#N8{NYCC)Q?*$%B$XzQQuVv}&)50kV*$l)?i+gP}W^vu* zF*^w;FlH~qm`#{t_H5Ka-5~qsd5@B^_9WM+g$J}@4plMuO`rvWc_DS|Eq(MD=77ji*>}R zpnk1cC6)uLg2ojhb&2~zvFixoEcA`6aCTfB)Yk+>mFT!SXsmE_yq-E%P{-xGBVR|D zxErh^%)a(I0vUxw4?daeh&4g|`e4DeL7nk5hfuR!jAO4O9IE!NBPwk)$6QA=f@ZFb z=9uewx}cELUPo9}_B!J4L46&myap&5I8QAq^}h!r%g7X5U#<}EP$XNG zz#E;ho?aa<`Z6UY>uWLR=^MBEGR-9GYf0hhJJ0TGtK()<42xpSsBo={1k|-XJjuy!ylX{mLFpc zM)nJp8FSpy5hw)#}IXPiEU>Ze}y`@ywnpfQuS{bFPlpsGrNfyX5-}2?V)y;DN-VQ(G_}_ z9^WO7UgSp(KBDUv5b3;~DlaoCE`Ja`JyGimKu4bP z#>G?&S#k0Ih?S?31-sa*K|zU+a;Amvh^JS*QPAne?kJcOdyUyIedGQJqN#9MuK*5!32w@FI;D>AYykiwqPEN!Vv#oFtOMiCZ~NxNb=S#m$;y0NVGM zjt%(7NCRUs(zd=bp#uF~(pMW?k%}d|F$+}_d7KTmU(*Xa zPumk5t?wcnZK;Ez|3CJ=JU)sdeZPBVfIv7x068TyJ(EdV8RT||BDn}RK@LGhAS3~z zA;BCVuE&7KqN1X>h^`zW0*Zo)3ax_2s;lU_F6(-%$GW;+ta#t9@_pWVtItd#JN|zE zEqP1Xn;7J4>0T-tcojk@HAyi}u!`~)5dV^ea+hcK~zY{Xv3c>J`-W9U4 zsO*DK^q(|EWAeOOAD{Ox;tEp5hoa(RS4EgAJ|dC`?r@=BzePvU_A(xfT#I#za6Ec# z149v~Je&xd5K|WyPgQY)A9p%w``C8mkm5t6IF~dYl1H5WLMK&)Nz*S^8lwNEC;XorjN+HojCxcn;=eOH9bArT_Vh!4b79r2;K`bK<&a1jpc zN1$A@+&|HhSL^HqNO!E0U@wlZI?$SU6d1(o@(Lu%&Fv zXtre>vdphcE5@JGKA}N?A76KiiA^% z{kvrB^tR()WSyO znVu4`9E9zSIz1RPxlbc*pXN~$@N%>8CfuhJcR;grqZeZz@$0k!)D=zS&ca~4)lrH* zlSG5~`;f;FClt%|vq2sGfxFotC?B8KTGQKTqNuPDTc9Y?TWiJ-6sJkyYVkCU&Ueiv zN&cR29UUAWg>76q!=E8y+qQ_#7XDtxX51Q`Wl|p94V?Eun9cs+u zio-i;RLk>sM?zi=NqQ$OIxK^KS+;?O9Vd(VD-L`sQT)y!L&QSOF9NVTwo}^h&Rzhu z1fa7frqXliK0{FOQBMJ}4yAA-?o%G_&VvZJ@ffWn)>VsTnr>W%;%E=evm))P**jpF z4(DM^Lj+kNa6Xug9;n}F4NAQMU2gGg)bqNNe=h))-dpnoAhU5yAz)163qcG^!I-k8 z%OL`mo`!%4X|XIVcC2aa3e*75CAdVhwdh834BScKlck|6i=KR}!(wX?xeQE3Hfrnv zILEdXBW9Rv{Vk~U94#8*Hs;Yr*YxAK$Qo^Q&4`db)~dyi7a?^80qdt(YTTVuFd%k$ zC;_lFq90yKOfk&}0o%bKizO;PyF!ftQr_yk3ZwveHF3PxiO(hOBHR0ccMaN*6~0QN z(`{)+%;5)`!mc5{Lz3?vH(%GB6-7sgZ&OpgYr*GG!Lva02YBDgGo7l0)1Yp(n=K$F zkEjpHL5pnH6UzRch$hn#^oCNNXr1a1)Ax#)zE`-DK2vM-hvoNLF+Gr4_69c^I>1d7 z1?!0yf0KiL2b#RWnl2dDCS#D2@yoRJbfgGu`e2g2&P^QQA^R9j4%xfmY+(X@`KGA} zR)@UFEhe{FF?ip73u10|i;)vZQ#ACZ_ZGy^*N8Dg9H;5WlZ_ilD)%6sAw-YaNJKsz z_bGSytq_3@AIH!(Op6UMd;2yNL+u@;b{Gb<2XtOSpCtO)4ixJn3D;e?i{^OfQavR62s*d@dFm|9wIIz;=K-HdN;B~ zY*@q(6LFC}>TK8Zh7;=}D2Jm@)}kkAv;rj(OmQPdimN&zUtE173dGevqEMTl3%edA zo$j+^d5)ofh+_cYp&t!rDt(NU`g8zDx#9i@5oow&SWZmVVw1Gk1T8jBi;dA@C1xW& zLkOp8Xk2uK?Z{sC(zr85G$%su0o^EZfJ8^wE_&j#U^AwoX1mpkr?XSUPnV~V*Pa87 zJ{>-j1JT1Id9pPNOaixjwTLkR_q*vR#_pgo&T-Eg%t;Kti57yNhhTUH_bGekAVk13 zm%}r2wb*PeHcN}0p~YruvC~Y?{1qh8a<6A*Iy`e4keX?a<(ZejW|X7G_DrS2GxNwZ zFM~#})S?5VXZDk4=31Va4Q}}^4`Y_Y8)rD~S%bqfLhvgP4A0^Ls3;!+lY?=UG5V#s?w;cgHbwF zd^pr(P?ba|peP-Ds_!IJ7St^epU{9fdV@J?7o%47os7CEl@O-N@`l!ab-V>+46)LS zbEPWgQcFus;1;Hz+Pv1%q*^C7 zuT}NUKxK1YnTfh4URh|NtR&W^UMWYh7d-sJ;LA|ijLYVrs;SG)LTU3ZYe+X^!%Vvz%XU(@&NE#{k(GYb{BSyY>n zQ>p5PW>svnn71@bv%{j<-Ym^7i{`GTAi9`7o7}?;xrz8f#p(DUn`~>m%z8XZW;#lQ zZKqibQw782#6V+DzN(%o80-?k@TJA@8LB6io!7Kie1Zz}3Wvi7n+`v_mx*sduV%O_ zQ8Bfy+`&zQme8G%Wpa1OQp#vNWULLMwyRa!IZ15~tF~K~f)6IS9HIJp;%(*Cc+>ct zirU6`)s=(hSDm-0Y(Z5ykq;#Y_@zO6~tC$khLl*B|++euHlsGuKx^WubgIyTe!X zF+WxPBB6@b$uns_)yN!msi-rx;P;??C?rTKfYXLPD>Q@8pLW=m>GFc?&Kmo8792f)y9~_t^p>zclpKxI3 z7NB$rDb7eVadZnQlN;*rJr$28)pv}j5nn89QrBJ772?A!o~jOh06dX_`G@e;cY?ge z13)E>C;eccc`66#0G@)B7-N|qN%2c2v=Xn2bb z8j;*V1tF!%ku0gc{FXd+N=U)y85F!s0j7;nZlw-Q-dJa<)T- z@In=%_b-&!1@cYta)_rebsN&7C4 z*Yo9dsk}DuRb6D+eRhi$E>5ON^_|<2;WbUVfsAL>S4$sOU(#GBA@k6cH%YAPaixg9 zMgIF{`R|+Lzkeqq`34!uYh)x}FUzl!<*Q}+HIi=?U)4)2A0%4vfzNk2MaGimqVdw? z9=gKY53Xv-Wxs8vAE>^SLV2z{_G_P<>Z=dx-Gs9=6;6pu9dHuepQU{-$m^fv^*O%! z|0w_cw7fnkuTSt*eZ=y|LrMLyw?%*KONLAJJ>HU=_Wy#L9&5o(kGA9{?s5LtLR~TB z`u(qly3kzVe}%8UmqM9h&iHGnGZG)adeE}`#TINNC;JacksnEsAIj?oQuMzd8X|q~ zvS{Bs(z$P2D&7hy)3MuDTvb=eU!HM}%Wv48cdW<$-U2Gs_fL`jV4AIVW)N3nFqQ+) zmlDGlz`)7PXDwm)Bq@fETfl(9Ee)TcqG`B|#?x|Zji=>S8t0q=dG*Qb5n#d~sD5Ml z<*ODHsJxZ{&kO(T*{q)q(!@TryOIueZQ#3b~cRXf(1jdA7oA!SnK(xz;pfjdip z8S>hRuWColOj6rxNezPrf!5@gydkB>mMi)A1|BYIN21sY>FJIKWym_*^rTsSPG}m zqD0Nolp5(__X_)1&7CWHU`8~`lpHOUZTU-P-_!~n&`Dy_PFXCHO@BX4SuDWF(lz8< ze}4@tr1FJ}otf*sY<`i(oxD)vPF^6d`SLoFufCJ<$usJiCu!X2hg)tKrePwaeJ86O z==-m#I>dI5!#iekL_<%Pj-Fy^n5-$hCqcUwuI-9RW{pEbNUXOekejjJ zSGTMPUrBUS)52F($7x8RYZf%(8^lTL$24P9NsC5J^~TtC;bdQ>G-;k?(p(dG6O(3} zH4e;T(@~w(vPozBf=M%*G3m4xO)5`nQhR)vivky4T*GT&yLCJ5zK=qipUWS&r*d=N z#Nk`$gsoDZH>;xdoJRTrdu6b(rXq-Mveh?KR#!LHEU2uRReyftIZFo&7%;1{3jeGO zR^WriRVb$=e{4|y0kam@)t-$pzJAt{@<9Uz4iFWC@JToNisr1k%IeCp`byLd95A5& z;);37=WV)Wt_ZFQ{x*13Xnk-~@a5pg!JmRxhxUZ;k3126A^gYibK&bFTO%(=4n^LM zJeK`V?gT7V2O+TQEw_*4*y97hw{DOwYOVT!_-I{h= z+T&@TrG1^YB6vygGN@S@yb|hG2iFAG2G<3DA0(x>2Db#a1@8>r9lR&FJNQ6wZ}6eu z!@>Q*$AXUsp9nr1JP25?1wRaa6g&iYUjpD|p{qhyhpr9182U@-+t5DkN$n}^3++p7 zTX;`+Z}_qB zzrrQ2L|%{l18#XI@&VklJbOj<`s@waw`Xt7CMP|X{Z#fdaMj`L{n1CG2cv(DKAQ7t z&JS?hk(_n8FXjF%_wTuH=KeGHv)nIof6VF=0G{9!Kf2+P-zf<3#-=*KJ@6>nc_vrWP z_vyR!2lPGqUi~5cVSS&zUw>48T>pdql>SHk88p~)dZ+yI+C_`|S5?$5xl^HcN&1!i z`ITi2{Ra%7VC0hi6_hpL>xlS6rG9lZ-MaqtFR!YO%wHhN@PGj{I+42m2$}`>k{|x~ z>3{Y7i1>%&FF{jPBTA^F_*ME5tNV|jsXR{?p)7I@PdY!-ByR2Mii8NL0Wo)9qb%Dn+sA zWCKubbf==+JFpo#*$7m7EM&bx@3nFKvE<2ypelR;UHPhm+Yq9IOJfwTRn?Vsd0J84 zETjqx@CErrm9r*RmDknQ*UoPUo>o=gSXLdJ+R#{0Rf{IUn0Q*zta(*6v&skcuc)rp zg4h#LVh#9+V?|Z95}U6;P_b*s9hH2@9mPW~z7gpja_j5LXJPoQsvXe3T#1dYA2MM0 zFeO$|Td%~?X=ba6e6=tbD5ybG#(%QPZ%Eh&H4SASEu#1M*68Q(7JxImtgz!!^v`L1Ns9mBy zi0J8YT8G4uBRvwWuujJHIPv%K;_rU+cjg2BUptYJS7}xoG)H{#6+1uu7b+R*h$&a> z_~OWW*Z+IY*Vpa6Fyr;i2Y2x5x^*B^-41j-XpoKFbtLUz{$30n6&E>Sxv0HrAEnpEb4oLF;;<%GiJ8 z(!NVC{r-kUYuEL;^QAj7A4*MCy>!!=*S=a5duhNx4@Keq|I^7Y4=dsCBH z-+<089C^`ci`TsO-GWbj<1f4E?#)wunS-mb@;C3E(e2;LkJ(lCyq18YTWbR(}?!0AhmF>Rl(4(0brY6%N zGVRn=7nOGz`Mcsb51;V%3-7;^`9NwS(dLLFVR^>W@onSAethm}$M4^|aoF#2GWSpz z{i;0L?7LzJ5=zufkL>^3&bRJ8v+~<#ev|q6lFW=QDY+N8tE=V-k*BPheQUw&D}U@< zADGy0edGSjm%FDV5@$CS3W15p+=5;!U%9g9HU6HL|7Py~%!VE*2?WNnx&=by_19KC zrj6DY?fU-RRcC$i;Cq>ksfolVwrlH_36aBF-*!#@a})lp-1y#Vb$;4qnUAL?vR)iQ z5hBl7IA*dkt<{~Y26y{*_wMh$&HU)tlngJYyg*3&>4TTfez5h&FD<$8tg|}x{pWj` z=~*dBEUT}ttZNV=$A>mtnKP)(sRtjdy8h8^oeubvQK9USBj*(5&lxbPD1XeTNrk0j zOH1FS_!Cyn{LM|eSiPt$LmJ~wb*a_pD63eRTo8%1;M%Gr7xpeRXvTN&_6MC~Hv~XdKHRW&%sQH2P{&TNfr;3!Kh7oN_%#Ed7I9Hwe#xZqlZr=;D$OVF zh%eP6*~R@h3Zjui7napjV8tdoF8s(n`aEf9hz-44y6$;Pa^blAlEU$&<3<-cLu6@P z6-5Y*(`HM%z}Uzqn}JF6tLX(joE#l;iQ zAxkk<);BJuMPMbuk=si2Me0qqC{JI!#u8OjoIif@=z=k$OK8}2igL7<=$T>^cPNl1 zhZ*ER*?Mbi$rJKNjVqWqal+&Y`4h{k!M=zfA_r(JhXs0o@0^@Yg~RA2%i=pmaRKlr*aV z3RB+7l#liXr5{^feaGPU)E!&l(G+A(!zQyOb1PFW=mW~xpzJkg|JsuY>B5pxP>=b_%K8LuyAl3?mZG zWS+{=z9e zJAj&S-fWXLsr!B(1@TM}p9S}+z|?V}NuSh*H|B!=ZP1TpANo6DVoc^kxWRH^CcE&Y ze%T>3(QT)Go1yO|}KLw$q6@-A40z@h#Qt%zkWSRQ7UWFE~O0+v_@ zMd?mPXS7l~KFP#MUHS-7&j9raf`t@xly$r)>e>9^u!odP9`|=8(EQr0x!>4~NtzL+XK$`fkYge#rMx z$oDafz9G3HoIb5Av)ivdtBRitEiZOdl(`Ete61nhBe~;kLYgqs>Q7=kq7EcG;rXZF zet0KEIc6bs?d_c?dWxW~p>i^3@sq2|$}1PvR#%84+1v^1FfM~HVdF_E)>J|b4`HDA6OT)0 z6yg33P-6%K^?DwnnS;q$_=`+_aWTky!y)6)-fB!!JC4`HppFOqPU$lkOaBs(zXb9M zgk#`PZ{PYXwN&#>(R>}@1vr0fy;I2<%r$EaxMsowu-d1BrQ>xBi+bT0{7;P|jc&y( z$BYHbF0drtLibkFMECX$?$a*bM;+ZKVDwR^XzD_!UCWY0=kbU-iACKo1yX*1xrsL+ z%GV~R0}Yph`*eY*bNi^f`uOihFZsf33KlY@vIeNCY8IGh0DbJXZ5%tFoC$GXKz?`8 z?#GB&om$zDoOwkXOqpOflL1{e3-^QYD5r;L(6`;1ORABiV-9oa%Q_1z*MWugeJfZj zeazy~@*uJN#nSSFTg$|HK%t$<0YEf-uSnqYLuP-hJ|44gXEPp9v4;$ zahhRTE&UB8oXYzcUH>Z3)`NC7Mq8yL&abc%88W9yXr_jR%=P}+;2MQYR;Ok^F06LM z$647d597*Kt&l(}iS_Ki7tg`{Env*Wpe7jqEEp-Jm7J8&TC?%AF;lDrqKb7tgeT*P z!w@k7y8YWbsRuLE>oDHmmrM|4AWj)=S;n9m$hhcOMOla`DF7MQW|(4jG$+QwaW>1i zdNE{7K#ERYR`1JDJMK@$%BhJHLnr3XJs14fgMW_1aD#w)fY1tVSZ_kOA?)k;hh_v>5Na608;y{1YEVKr00>*c z%G9zYlsZrc;&?lSi5r)I_!L0_t=KZT0!HiT18|Jp3ymay+dg!C&-C2~S5hrp}YiGwbOoBj-b#fugwt&q z>W3NXk1*qnrgF@DRZ6O5SpWPjBs~vFrvOv{Vh|B5rsKO!Wrzif6mSDWDY^mzW??xs zliCvk(4Ino??>2!eNA*xk?l$sS)-dw9fw^7{%%qHwHtm>{os8COGhj`VIR^i>`hEH zcRj3z9n0W-*MjW>@M2|yq;Q{@M=1Fc$(mf7PGj1#)u3ITgTDq-xzID# zI?z7``otRm;O_ue4a>m7sx<=9f`RN0FfNMtu88=qiTKw5%uAM4Q_5uS%9%z3%dOo^ zIPl;f?_9@%MVSXtzK(s=@kpJY z6I|3MoMxTJ96#*<$M0fd!Gm86Yihdkd^(NiR^G4R=cD}siyIbV0aIcArdLU%A(;Mi->hxLwMa?vC$O%M$mZGCXdIqq=-?$J3=zoE zl-2DShjjo2I}6B{ajY{Cm{u}%V&Hz3!jqesZcGyUeaH<+mXi1i98kD4pv*6q8z!s; zU5qL|?JbaC+Y6>)nBvOGqB31MK(3gMWP8{UDOU-nD^HlEakDTO=+H`;U(XvtEaG`F zdj-0~5A?95S~|kiz}sShoDS5%iiZxEGxPK_EcK6xzL~Df3Y3hUFbY=u9eC1}r%12( zC5{cJAkdM$P~5nf_aj(657+6+$_(&~Ege%Zsd&PuDG+rR9FndaB;O*BkZTjnj-vQ2 zDjqX=3U+gaUK)o3n_S%qtu=;soh`T%M1ut~-~u{Mi56lEFR%+V{MK{fvc$4`dL$Yx!|;x-uX{x+jjB2&{$xbtp(BV#5mAt|+QH7L15y{DQH(u4-`u_5_tg zU%*IL-X;@@#*QL?Dv4_0xL2qQQden^s!qdFVN^{;Rap%l!3`dSnTzQT3HPTf_cx0TOJ$L} zQD3hfMW>WRzsZNuv|mf^+%LfMu7%}|Kzl?re(gXVe-2HwtgyG_`E3U6zs{+uog+6K zA&a!8CE#6*kQeyMIRJ>CKAK(B90ZODEGe5K-nyWO_a>w(6%skkD`scF zAdW}~ynum*21=_Hs=2k+Fh()Ec?Y}_Fp{rdpzbhr;Lwt)^C~L_4l_fnAx*i5uum?- zfxOBFtc(S68V7w!TDmed09Vgzq-6$;6M=1jP>bZ)>YqM_u&1YjE&ZDE#mlUkEz+aU zm?PTYL8jKmKpTc!Qde1N4W|nv!{7jqY9dI*s}TZEq$zWjm}h(Dl+UrpfmV{~YDX-I zrINEVj6k%eEB_)APwzc0V9h;c)i|>~zZPcT$pq}ZitLRi?Fg8X%sJp?bVJZ>caCF@ zk;827plF7`;U2ag>TN8?ghzHz#{&&JT&5ROh%1(-aiIoitYbzYhpAVN^DqLo*ah*PG51$4`+mS~z znbpFk4etx@q$^ng>d>M`r7QdVOUoCQ)zQB~fpb}cn5~nF;D;Z9g^q4(g;<7k#M5So z*@2B8KrR*TnNw9>zL>`toTry<%WnFb*f4a9MAFVl67=KLbmeuj-7~NU?&fwzvE_?F z$eyulW<|s|a%e0%R*X~)=#g@$vh`DUPFGHn8Z1$WI{IZuprV(uw7kB?876U#27}#I zTuF;{&zxX}v!#`WbR}kH zaEs>gTUnGuJE#ckl3>Lv4W`vvgO3&B{ERJtA0f?IbPhk;b7Xrt66R3PtR3+8R2Ee( z;?5$IDl;YN6TnG~np%pjhCnCCwWOLok&~lzWgz7&FV932Yc6`Gn872zu0&YOn~S0RDYmPEa0K3G!(b zR8K*57ji!xLJ2lt;~|)vU7@39A!?$eudF7Bk=t}qzo0x!60EldqBc0&q4<5|??2)u zl#6~>S%+*&2jHL_Q-r6XAeem~=$;2%PYbe0?SeD_nXrE(flEO+D*}Ml0SQ8AlFUWT ziNY(+vkt);vGk!Rqk|6hd9ZaceqK^pfvD>jTp&UdaxVgRuX1s;0dYhJ8-gNq8fr-g z2(AD@H^&hJsro#MgKJP1cGWR-c$ngeK?+KI?b?65b(|o`<2qbu8ry`U)0v5U(Zi^h z{qN8JJn%mc{Lcgb^T7W+@IMdy&jbJS!2dk(OCBioJ%HD+Dy4%v%+KsIKx^GjEmqUh z{hcy;;1t%D%wr2jbv!0b=~U`_&|m7?ga7y9e*^zNg#RDrtD4vZHKJIJm-@N}NFWiZ zBL%(MwbVDLEfr=Z0vVf>(qQ6eQ)8Rn&8sAyY`hA0c-xZLiEU#;+r|dBB2INmt9E$YOVN%8=-A6{>Z zYbr1PB})gv(s8hKOxsvV+gNeiSfMm_u-lL^$qgxS7*cE*Qs^*5038oaLjV-lW`X`v zn~VU`=|DQQZS2&xvC_7&i4y54)Z%J>bVl3g)TGT)5S{61mKnA+##G#2LT!O|In`lK zsb$VYhdHuc3Zc#2E=9&nt6ffmxy3LS*JjOaA?T@H#=+VJu(q;oth{ZktZi&g+t^vs z;PLLJsdN}q?l7jzVay!Mn6n(lh_+b>Z4&?%SMwdo=xzKlB+>cQ5v9Hh+nK#f+;--Q z{8HaVb_LybEA=f-Pu}NT2Df#0bK;4?;`;QG*tzN4+Xh4zrsEadx8gTlIPs(y=cZp? zbPcuBH9`7h%&lp84d5CCQeCI2neI_}YG=Ci*Nb@3+uBOWFKuk{=#S$y5;gNN+OrqV2e{Fiu1NXl>#J(Amm(5+#-=f4yYE2bWrVI>dWY2 z)zd8|9ps7Xpi%rqK zPKGMR#2y%2r{jNPym`mt?c^R1vxUvXeJWlSNVYMO=|D2IN9R^UzB9iEqqQD zLrZ;++ZA-%^}q8eu{6M+U%-mbdc;1FRx}!)^e{hesAP$cheQv70PMa#mXFbem zmI)C?yMq&o3Ke`u3!lCC5@MIYDqK_XFQH0=RMFB^y-H#Wdc`Vx$(GhoY*hB5+?-Q( z39q6T!^0V0#aPhGgvXSCx7-2m>|T%`h9E%1z0>i-cig(eD_H5a3s;0oed$?N z1>JV!is*mmcv@g3e#aryDXS#bA&cxYI%Hw&=fB1GeU4m=R}Jyq5k+a`6H`M*7I0@| znYf#-pIYcdLhoAE+XZ?%v);}^ulU=oH=~_j=%T(JhPmde1E4#)|K<0uq6j zJ~_!AM#vOoD!Gb+4=#!CfM&E4*7ZO;Chi3>jKqB^F)JMV07RfS1z}`g)5r%2Lw9`k zo$}QJiq5_S)inCCBmclh5;R{ix7$vfR{fANds4h2yz` z8gE^~06_)`j>m{2Hw*6CM}{Yg$T>op@PUi>~N5Wl|j*OgT~?DQ`grE1*x6y%qr4PMd4uM~q| zILt#uDh*3^(c=3E?D{Df`%zkSN>mLQKmM{s`Gy+uApePwOT!At9sK1%1s@PC1WsI2 z#aRNJtwJR+zx=@J=xCde;fMZTaQhgejRz!sG*q~=HBgNODqK@VH4&&f0ab@kEIkx! zE3r+Ab`BYBe;M0kqq7H_ksh*}{?sPb;(MpIVEW!Be*`rW?*e0{IFxc-QVFtsrs-WA zpUuqx|7k`C;Mu2Hu{8tUK}D+GITPOL4)1i6ewh{R88W*4vR`IL+w|d23NEC6-BUOT z6Y(V&t1a$;-O)r9eI$8~n~{l+hHZfkntV+vqEu zLabTwY$>^bsPc}5In{c02nw5u4Lm`UM0>asl=tRfEFW}v@kVNkrA`9;SeOXz%fX-sg3Uy5o|B*}6YS1GWP{*#B3R}m zz(zMoxIYKO6$rKw!TC;tK1}dH4n__T+(`r%NCLafF4D=<7fZLqV1;GVWDJv$?43vVh;ZLSu1Zh}iVJ=_qC|^AMjnlr#>w=zIi)6ULY>K70rw;KM2K;bhZ+l>0}gg^bBZ;Xsl0Pm`|WSz`u`%k-IS#O+ivROI_JLWW7k z-wNhlXj47P#(*PbW1eDTX2Y0Sq1YLr*i6%;r^%$bA!FuInDh*2jkzw9%1x8dc5}$2 z1EA5%L&g~tI>Ownc!eP1<`G2C6H!IT)2jrF2$@;Xu}|Y(W$NRRQ1)XBh0|l)Z+&7w zrz9xxCnsK$l98Dm@XyIeM0ROA#2y(U@k+AsMPl;SCxv8&=wHd;N~f1)APbvKFnDTkeE9@fEm@r7}i%47*rrED%Zc60-jrQ0W(kj0OeM+Eqd|ZMnN=r>pJRiIWYdQW`UU1`7+uK8rF9M=la7@>G3Q$kK0)MA1*3 zs}!S-M!aN(Y!b^I&O3aN)kKg;O-$sg1@Zvs+%d}5bBuaH(ZO?Ec0T$9FvpG$73NHx6V(_LFii3uS9ntgT z0fhv;I^IFS$qCzHj=LS*Bs}Pn5G+8&u2P~CDDqZNAa%x_zJ~7bzWx;Bw2M<8$LWnS zPP>u#8=FRv3|#a)XPg}46l4y%61X@vlj!cINM=2)z#I-rVtr3gu=Txhr{6@@)3VGR z9^Q_Pw7nsEvmGhOe~~77gYsC&X%Z=YQHal~uLwn#hv>8FH;L4sZp3Bcx^%>v&;(ty z2Cet4p~qT0vkr6dES_&Th-gwd7?c*f7tjgu%)=bY%v`_~3G^_-A*}g@bRyeL=~zsk zLJL{3m`+4JMD~Ju91)2Hbt1<@WG|{05|LO`CvrVR_QHA!5s8I$f<6l2KrdPm?!e-D zHW7)%b>euN$kBUaDAmPS+MnvVU&hyaCfJt7pA$&J`jFHg-{4_wX)qc3Q z1Ji+!vDF&mw^(IM?19Q$2Wh%4;BTo>FEB(z2qKb3z=|mL8h_m7aCxK;0(t12uF@3xlTt$ z_j=uA3ry;!agZS0gayp~>Ec{*dleae{5U`$T}(-WcCW1-l76WN)lF&?945{}A> zKkabIQ>6YZQ0PyGjQtj3o@toNT-?kCRWu9>=>d2?^){QH2X6COk=ffw9|yZoFT(x_ z=#VQz5esUTc=#xA%z*|p4enERLj^>jX%4^*&zKIVB;ZRiOdxAWyh;1;&sc^g2X02` zpMe&H2cJhH+a-_z`f?cX@O$UKH%`IL=$Z zD#m{vA$SEf2c+Jt_KA7Y*rNmjkjU0f}AE$SD_Hu z>_0-$w?sDk2|}l!p>D)G;<|Lihsb6{TU`S}E4;02mUUR!?6qzpnay%Yda~KoZqg)~ z{Tia+Kxf#&_!pvqe}{_bo}Thh>+R?oDLC_#h}Z@lc&UupcZrLO}Np&2ss2hlIQJ|sB-drvs-+^PM&uY5hu^T_Ym31 z^8q5_Tk2tVf=d4> zWD!~c%aW~t-QkqR%XlomzJ~Y%Ay2^GmUx#@DC^20VqnC}-)M)!*+qkjaqk%s#HR+zWftkL_Dw7gbi z;3FN@AgJ7rJm_RY zghpK)w0E4ThlAh^{0IbpW24M8gm*2T%|YoUJPQBK*3113VP#tPGU^akur%ccd<`NH zRy)vuoy-ROI~kFw8J&dpq1Ea4HwaIr%kSM>e(y|ve-l)CH_ak6{VwuO)WgJ?>LR|1m@W{cfNSYO%hi0f$i>4QocG*BG*!reiyWp3%B=Wc^5oAXK+uSA=}%=xP^J&okS7k* z^g&dj`Zz!0m=Z)j6v0WjPuWRrAOcQWkAtakEjCPx4Ke+ch8n1C%a?Rq^bx||j<}7U zq`|Q~AG|>G!7yPzwqp)w8$*P%FyQRZF@LX_=maL?BoK+yzls*mC!6rnRFU(sO?gz5 zNs97uE`n%>7f?|bi&ywZkR3y01zPlEO{${^O#BC40Ee?_n&?ULPPQA2 zSe0PBNLbekmC<3Ethac2qgbpjjwQuKXc+wzlSs5B3mHB_(?=5KEYcxB*qDPP1HVfB z70s0c5ooUQi0QFfY_t{|Wj0qXYM}RcT%r>-G$=RDU(h%Ln%FoS?P#S@Nm{8txQ&Tc zD~02egilT&p|0f+3lfHll~5_oJ-dUXshwC5uyp!&(mja*kSJgY?@S<%4MdSh_Xpu7 zZ?dMd?qT?sVN2tAlm<;=$B=WXKzJgkTnI(2fHuX3<~tf_aftFj8;&B;_$T2;KUFiv z!gpV#C52@^XF3_AO$cb}=Ai`!k07ajeKHw868EH(_Y8$U@~PUV<38oiJqjWaEqgH) zOxI#l%}^;padf6;OobKVoV9Z{9!-_Wqi4D!dS*JJM|dkNT5<*%Glr4lK4s(+8ToY> zmd-R`PeK`_m-1yYUry!A6kMX^nsKIpB>-U@IGBU%;FcU~88nrNXW(L#gOYdc?WF*c z+>J^EXvFV2!8D-&zo=o|_t9HwOnxJL>s+AbKMFM@F<MGC1;UKPDhal z?pe6e=WEfyeOS-Gv1<#7L>>_dAcZ!CsSuf1Twh)mj4u#k&jPC}#-j`E&`uYjZJVF8 z*UfGUY>o+R9syh6^xy#C`D;!xq_oWXD|}n9PvoH!Fb?dCU>3#SG`^NYl%pkvfcmAR zaxz2>HI2r%_8bn}mCmY+PGgue>>(YQPl{t5zH1{^u`HXO=X5uUzsMcC0| zlTq<1tr%|O6~ozX0BmM52c#tju!sQ6OB(bvT_=IOm^cgx`7KH??9e79Vm-4VC=Ka> zlD7%(>p5bdsh+s~v|B}|!AD^im-?4DFCsanf#YAqft8Xid8Sz^S4vAs&S>;h+Qk2W z99Ka-4!<#R_Wj}2oJHEb{XFpL)tXU3xg)8rh{P9(K72k&bj_rK1`}0dw8=ze154VQ ze*;;bVder9iDBkqLa@kb8&8~q-i)gRftl+}fon9qRue_$Jf+uY#$1sC3!qwjv9MzW zvAR4no8`cR&*fl&_jMXQ{PcRN&g-d52xpy^OcdF?ikiqPq~0s!QW8?1R0zdNQXvgq zA-^Rd4O*1#AmtpEvcQgPpD~a85s5d_z`hb}d9`$RB?)MBx?E=eb~ADt$mE4HQz@Rh z!2udk4`*8`=T#8s2+l;GRwB7wmE$OEUZQP*+1#r<@>co(8+o<^OnKKrUbKw;D9ZAd zX!=r36j|Z3L^H}n_$2d!7C%o!({+#p4_@y9Xd5g1c9(y0&cFKw`bNW7ETh}bJ zZ4xolQtk#10((7?488@((IB$Ty*i!k`a39@)(YBg#Erg8n-<7hs_ExZ4Bh0`&#mi9 z8gC|MKO#T3hg&75W%4i#vUCd>oBe~`Z;{pl@*9^DaX5hGWF_3|Y`bFi{E}lDV9&Sh%k8!@0 z2{tn;@38sX1EeR@aqx2<)NHnMmo10$ndWfN?EDh-@#NXg-L{;rg0eX|oCh^4=N^)C zznnV1rm53*1vyGgonPe0_OYhUfAG|KpN%2{Vo#nVT7q&?S4%u#^W=i(8+WcJc<5^v zf(NPMA=-1r-;^poWV3QJHD`1)soBFeKPOMk@fQnYnxtlr*!Pj z$cXs30a#uO4%mvHZi`?3%4X$W{FE)4tp6`XQ>Zm7`e|GAg#TVNb+cwgKWmGo2Jp0K z@}cB8@Q9kbvBt}%tdYjtKI9E5rc*`@vi&L`^E=8)WQzC#sY{+}IvS4>%O5!1lyat- zB~s2`AjiQ#`G8!#3SfPBW9tD7A9%3H3F)1bkX}p)DSmSbsN$DvggLn!&|#rEd?gRd zB3ZqNrjVDRSzoC|6XqC>jnBL*H2q30vS#utG$SEqa(g&g2$Y;9Y4NMX1p12GjA{^I zt5@*B4s-g(Z0OiCi?1RWuaYBq9#MzF-!wYBM$lH#Cg_!#eic!@K~(3;px#V_+X~vP z`bDd+_FDZGiN4xn^);G)t;gzXTDE$%u=;HXb2$BItj>yGr{!HsCcQ&QuG6B+86rG( zz&(H-y=2jS;aP0dTUq402TW6+KpQ9}Ld(BvfjHStT+!v@cesAS6_ADR{^4&~GzhqdrPZ`!X4C@#? z3f`#2)|<$_C1jg5V|_AY-x0FS9%RNw8Y0XX`JR#8`YVwAhmpMvhix%o{Y0>~X~vdh zuzn_3+bmdi-XI*dl^k}2Vc|YyhxxE}LOXs7Sa)f$J56MM6i0Vy#+}KK1yE`1@*p$r zayqOPNDyH=e+9BMM)m`c-DkpTORyf$jQf(oYDcghuwdDVl5p7lwvCo6dc*yCn&W!AlUxBPEBl98lA2VTfBUpdXjK`9} zI)-5V!GbkLjDD1u35PvF4(raaaG$cndNHgvfc1{v#2;8!3EF|zm2lrL(r7ffUtA^WRlypRl8m?}MKQeh+i1mv$4U`p6Ta*T+0 z5v8}$Z=_{{6k*^8e+BRy2HqYneN~ISYy!_EY_Ds^%gKQ2%>$3V%2STAWLy5AUA14ETQWD_ul#cPa1(p&evHXS!pP*E{cTxgB84~P#<1-pXMxY3@ z0q#>CMe-p6^HfhX!dIpt1%&lm&G;&rA%&v(BRnUVW;`Ra9Sw?!+pw5o5H}N0M;fPYh_}aO4!bXBlJb_A9Ve zFt*{q*24r=Nx*uCjULH>%_m^JEnvK7X5}8e$Yl!{7VcAa+1U*16u`;~$Bs3TokPg9 zuyJfMWYvUB^B^;_!j9#@B1RVa70Bus*>T~LSZ+8L4aXuTxO&vU`Ubu<@?|M5(f(oT zl(Zsl7@s#FtPc#!BHm}v2ZW6X!4y=H_@J=S9}O+eDOKQ%SC}3QEF(ev>>9l41&7v{ z&xjIv>wYUbFIEQOFWR{{pXeiDuF8aPD*O!!=|ERlA4CmxA<@KanGGslg@cWz6HL5? zjm6{hhJ^K@VUUTrA%kqthlGuoi4d>&8zvB5MAA+O8z+z{MlRI{2(d}Yhz9_l*m|+f zmtM@EhKBWF1Zp|{$udMXdpwn`AQGRB`;;T(vhZ_*OHlqVPj-6Ggnh(ao8yISW3NGplfHMyPhb$ z_FHBPM;OJ_{JakY+ZDI*t;BoJ3#d)kKo;5*_bIpOO%Q=L{WB~b9gdAMjlCJgQ1E*K zJ3buU-bp@&ucu${jS?Qo(Fg*;M2JaXVEA zlC31^ULqbVn4ws54%H) zJt9M^QUZRIC@W1zI%GXg6~d+`aOVy!R&0mXA3)&@Edl096e6^6pK@qD0}%+V9SE(e zaBP7YSI-il`=~kTJWV@l&MHR}F0k(z6a!`3&Y@O1z|e4?GPD;M+I~PgHyo=C#}=9B z{)`&vc#%LhdZT_3u$jO2um+riAT=6AjTui%T~S|8pkD%&zBC+d2uoT|)W1wp8X(0L z^*5MN-+|mzi|PaP3pl(6zypON{gq@wT#^2paNY$3=QV=!o3L>%L^^-QN|BCuzEA}7 z>uzz)1oIn2#rAU}347l}sR-tOkfsYg!OVurV7^FVdYdROGX3L_^$t}C*ze-b9n7rQ z4(5M>!Wqm0%=;)rFylVui1`R25X^fJF)PBcgc&Y}2+)2rm@}xARtT2@5yqy3-C|9H z`BG|#e={`Prwr{ghIRnZt_;UkhGUnT=srgcbbP^=uW*T8w4Rv$k)&J=DXy4aZ^m>Ncq@8Cm_2o+nQ9m-!LUz*C=3sx zT@4RJj`jZ}6Yh%jwc)%Q3FglPbFC)=85ZQzOubH0DgjWgGp*qW6qfp^LI|U8O1mSF z-6W8T^Mdrjb7uq!0j*Go2*iEL&71}ih`>LfnQsZlZZ_MvEde@UMj#zeG;Xncd9&~( zu+c+Z%c1y<9q#iskaOBGFx;mMtTO}Kf@Rd^aBPzaEEC00(1kBu`O*!S=pA8WlP4YySKcMYwZ4$#Kp>y6 z3O-0r`dm3Heor`WCpjzxX8j(g1&$wzv?wDOzfZ~tlZ^XZGVJ4NZW+<-VdD-si%*yH z!%<4+DUCN%`E2scR+qSw(?s5JLoU0+VHR2*earcxryO#}R_NH2HvE3!pyR1zvuq*? zn_&Dwm-yz;5;Bm|A~!~$_Jl1lICW*8qI275+C$6Q{=~M|#nzHC(*-Ah4cr5rz!4`% zy_^RhtY6^b;KOEl@IgHH-)r?4(`pwpIuM<9c!+}!J4y|Cw^J+(hC2PBaMTEUUc|P? zl4r*uJusJVqvyfG${>aiY6I@JUmo{}SJg05^@!6iUgO&Hsg8T;R7cVu9vC(%RwiIL z8pt7$EvCMv2IKp@U``}3`<#JkzwF6#rbOBWdDy150dPpOmf`!o^5Z0bf7tzs1t;bf zyh=foM-H`Vnhm_9J`xPbNGX7DqD+ z>Hb04_lxik@$;Y2RC>RwTiw-K^xB7mO?oX}b@`a+R%5~CfZe>`xkIzxkHQty2gOMT zr**RZANRJ;ID-CoSeP*$_jyl*b%r+y|BBv;90RN3qP4k7B19>Xt-txP78@>yv*}$Z zYjddyOUceV(I?jCni1xGq-)hwNIWR4 z|4p?0Z%ES1VZ)|zWJ`h_);lsT#5n(~_5v^(FC(nor~6(NQZFK@uZ5fWWg&Bk@kHuH zXgPj8d@+fB&9UeGcOi5+6+3X+X@?tUavD>fX^Wkmt?0v%A`mBx zKKdii(Z)AmF?Z^}ce8U;?FT!&@)$105022xivMgnAIq)pD6*aajs9~u`kycc9)56F zNL`lMM3Wg#h{9VzbJP6~gcGc;)^@N?=#E}T4fGU2`HwX}WW|q&KJqm2pDte^dI!CP z(P5j|`S~L#L_j`+8~sR_g@`qQ!2c}O`*hr=++2Tx2sGClXf9tQrbOg{k{3`6`tBAXqn2npsiOJneev!}_KjhozQh`Y%@0XMO_n%u!^HTh=* zrL)!KLiOh;LzCk^ z#pna3{W-&f4mb6tMmmB@Js6SoQpkrlzFfkUNp zr!^uhY2&fP-j)=+z-i{o7@^|Xf~PIn6?HkuUfVZebFA&tNm&%GH`n&TcrJOpy|Ww# zG~k#gX`#C-m)D{vxE+^h5hQmM)`EMia%sxw02O(9L>Kxxk^!#wm)fmzG{SA_raK3^ zP8M~72C?~)fg3$Lf^x~2dv8#+ei*jv={SKE;Bj$h)J0hkMr0gCcc3L z?|6a|r$87M(NCn37)l5&zx!Db^+yrhi~E$_I~XG1-hDXEd{QJf+;r~{6h}{q7{il| zmP4sBKVqCBMn!?i9-FMy#V}9-_KAFn^JO?+^7wKRUq;{(9gXSD^HwUnT?emoKM5W^ zoXx9$)`)O)to}~{w=tUHP9V|ZW8h1SKJs+X2=ZMKX!J2o#EyPz@;XPZaiT>>k!ah> zguR{X<-t%tzNy+0Qak?W)$(IJfp|1nMYkMBGR8%s#V#@SUWONmy-zV7oY7G(HhUYQ zdA3PlGxE{2{DjJWPcBAS*E5!4>H=aJ%+x%t44+62FNKgMtuTd5nHY%{Mm*cejwZG@ zjHeQgLfNmWJ+tDIo4WWkk~ujNEs8|f&<5%{Y*CM<@!yHb+Gw3YGK=gkDk3H;KBcML z(@E}>2*w?rjK`5o=Hy*jMh2VL=1v$st*L-BNx-xS8i16fWx!W7vCKwsv>+1QMEmJa zL@Q-rAl+U<=>?bNb7Q&uFTrob=3awX!|Cx?5QavlLX20!Mh;^JG#!vV%s~ z7ig~CicMu|lth&9k1|6cT7q{qVf=NvU#dkpCRZru9D3nVD#wFl`zhKPqFbH~R=Bbn z7x(_NBaWhH5)irnyoe}W`_E@aocqtSh?d_^$G;A>osx8_tAV^G(Oru|(PQgzqn{Bm zO2ialMzC|kU5n2ahBSf_hAhRUc|+zn3^|V(mJx%~9@a(g39@>OQ=fQ&&>WY^bN@?| z&xcB3-9@<3XS?F9xwsKc=NQv2CK)~*<6Fwp)uj-D>FRd8d!#%PD>J97%TOGhA2G_% zTblex_HtCh%fIEzl|)+A++=BiNvZ+SKf%4Xnn+}PUgyWRM{v8A!{7DiAtB+rToC}W|YDkzvs&>eA$SLu^6Jw z^D8)-Cc46{sBndJ^ddV#12oHcHbEF4S_d0{{5K7+n<0kW%}G)nHOFlz5|Mj5ZuAQy z(es-&KAuA%)2MMYetnY0-wFZ7`BvkH;};9)+o_o8MN8Y=!KAfX+8oJ(@#TVbhlkZp zFubftFjfebyTIbk(T`TO@R9>)(xL5ch!+nbcH$=Ql8DY)cahe{h=bb^&|a(<=dIYd z2aHCe70}7oYX6-DEDhGkwc5P`vVI9Q_I-38z|C&l=*y8mF-z2!*DNPkNZ_w^=n|a=tO*k6=S*_hfL6u489#&ya?t zXnXsS|4QMyn^|6@bmta%XdxKCN?7m;=%ULa$w_4z+J`bD9_tXS zcvkV72(*Y_m{oN>j z=1~G}44|Q;^=e_s+r-dPTNo_BZkucV%eMI^GEX>)t-CWqci`%fJWoQ*AV^R1>73D*YFzS7e=&i zp}`Yy-=RnZ+z+_XucypYJ~0r9&W}{>({Z12S{T52HKc_vAuYT)5?dFEt&PNPFf+qe zsEn?U7&l-7+{Pv=QPbjg2w!nhcnb}aT|lAV5iyvX9O>8)GC7;1ZCUXhBCw7jblY6q zc7O76+Z!_7iEX=!&EAk{o~<`ovrahO-15C!z&MsFZWgP|?ew=6-$}Ohm1;zd+5dwm z)OR{{J9dPH{mq`G-DWQC9o}*Y2D>$|)z4w1%PEop4-fU6;_p`2etxY%N1`=JZR z)9glT3gaFx42@vi6A_73gzoQlLUIhAO&dV$#)@#s2BYYCI!V~!l3?fTUJ1zA?-dPo zJh(h9xLZ`jP?17J^e1_)hQFU0{sbw_)$jvRsNWxPA5gG8>~LnwJ%CdfM>B}$B!eJb zxONDs+3j*nOR;Ucb|^`pEPXghxHl5r7{P9|++3PYbBD9H^VlQ8z}`yA1E;ak(Lu7} z4|>Dk6q5d6#MKH}@x7uIMxriyD>4xC@hY7g@+>!7!RxD3s|2wRaKjjay;2{UG;YuiYh}(I1Xr6n3_>y&2(+S?AhqG#RqRo9a87 z!%p?b5tPkN2nKH6jh#dmx}KOhsc52~OonZx5zr3VQ&EPA79&H- z6YWfhz(o5dCfYwlVvk2+k49qq%!&4NLiP0jvG?BbQ566G`0ieSVCaa1n%mvvigFl& zK!_q8MZi!5EGUNL0>Lzs3&nybO+-}e6{Lv@iUma%6#>OwvA=!WdqeELt-t4MW_E9P zZ|?~3{(V3HyzyaXcjndRIj?!mYi9TEa*aosOS>LbpNdAN-*%V z6OY*z$0s4dJi_Y#j19nD$wJ}a(T#WNgl$#MFV^>@Y$Gz zhd3DwZieL{4Ne}Lhq(A&V&+?Xvt4`%7jg3O+{qf~IWD%uK)cznXEDclu8S#=^`&7t z7fcD~V7Q)#DmVwOg>xu3(-L?As>k@`qUJf0EVq>WG@Us*;$5FT?QRlZdJm zm+`8aEcZdv(3*y7v?#1amKtQaH)ME+In+!5OvVpf$S}L+~G#UrjO|Pt|XX0dt zLo2;`E-S~NZG05Cb$N}cRmD&4vaXLyt+m)w>zLG9Wo0rNQ=xJ)+LBP2VObd^)?`#lQSCM! zxNzf3(3k?Usc1@u>~z$ohAft4`pVf^($teGs-h-b(AWxawNwD?c^1`NZz@@yjfM#o z=R`+VPp+vet9N)+1KNf(l$S^AY{FIMRS>?w5*`=A3ncust}i1K?$utF=ZV^0wpwP@ zMHb^iL1Ghc*?zf2walAJmY1S|+dgD&Eb6p<3EGluC+}q@TxAJg?k${A-C$8&>rExg zS5rfk&HnBt_A4yr8@-vCinSKiDsL)TUYSzGZ5H#olr$SHn%h&-+-=d^nQTOR6SJ|| zrpt}VmZqK}Eomagdax{yLe0sx8rHW-7Q+O_fCq9E%4BJfERSOhi5kZ6qs6cn&0|XD zB+rUHXuzzn0p8mLd}e3UzUiG)a7WQFp{~@%O+kz4Zj)njx6F}BC?0ZKW32U1tF^61 zYqr(eAxD~3Qt1FfRyyTKQ!7iW>Zg{~G)$|E7L-@asVbRXQA%Von=SDom?10Oa->+a zs#aQZ7^}ZfS|Y`dMGGdIYN_a+Bb7N6H1#Q=obFf}d`gg)asbpmwvy<{)bcNWv#US) zrP8Fex~S67n(A0|PHf~b+svWirxEt6QaKBNBCnv4l$Gu-Gesl0 z1^jiGP%;oo6y~SLs2-kJWM{8#g_1sG8)7L#(kA=K0B`l|fz@K1dGj zgY72@+ecZpAFq13>WK8_j83a$vQRR?QZhEZxRX+egT+xUOeqs(sSrNZ8saGy5CSyr z#HV`Te{y;|&P;8GuS)2z6#6TmpXa;f>4nZrC6o=wN+EUyFMT)Qqsofn^Ia$IuTtA% zP<_7T;(nQ+UuwF)PxkpP7LAKIu`*w62lw|W7piSpc>!;iXIYrVRB3Q&X|%q6Oih_R z`J(kmmg_vAt4-;;)#<0$T-OvMUzC;EF3@aKtfdeCWwgw|;NK+-zr*sR^0R$lm+L*t5|!6o9dx=L9FGn5U&72^Ent3D zB_war5_`hTB+5UgH{-X|3gHWiW(E>T!_sbBq6lhd=M-{+T#k|_2k7Crb#E2Ot-e5Bu2$Kn=;iD!S`tKIKEU?T21@3Z&`RagYij=n<6~4 z;0=3OLy0EMw5eoc!x!l$@RI9z*L+uqt}YkQTrQxwOh9v~pj#&BE)jG~#RR-q&@JKZ z@;nQw^E7EI zGTnJZwIQw0yHg0g-!kgHwEPdG;D5w2YO5wyl~gyBmz2gD>S*_F+h{+OR`#PQWbd?W z+n$#H@f7^eTDCn6+mKgRI*fWUt)SN#J=X>=dr7q?n;ulSxwT4JtT$LR+d>U((<=X!Qa6$tG(N- z0Sv9SX~iCvLTqQttn9S>T~hF?mRUKvG$~qFUs2=CWV@vmt9gr6`szG`?W6My_9&fY zuu1{yk=rP}M14N5myfWz5z?h0CH2wb2KMZXyE#(I0Iwbi<7|m$t}a#B&80Lqf;uAN zD_TrZdVm!VTcr7vJd{ZnN_eU*;R(MiD?N37c4bi`OV*_t(rq2AiY4`E3#k4HpzKHW z{n7$;j5kp7V5{Q;)AA3~`3{5k3K`Q7Z-L4<-FEmmR_Eu}V|Xc#gf_loISwefH*~T* zTu-}q8wC@GSJlSmQc5i{26kGloS;*(oxHKb?kg&6C=+F=D5sf*l0TG)%F}r%pJEw0 z8MB3-2ifv?zQvx1(W_0l0iTe*FQ=vK%c&{)!ZNF~tnsQyZP;{-&CsFAJ2CT-iZV}h z_k2;FXUF1PQ8`;+QEy>!c50P1DOB=PfU5LZG^E5LmJW-B78dhU8x~Jv7(D_~t{2_C z&W^#gqH?*wV3~!%Qe7&WZEiGpc))Y|CAu^wTIKb?U~&4cUzW1#m!{}CmY9`R$8Ywu z=EfA(P=9?d@GfOMBg&^m`J^bH;H7V;xZfe}xAU^eW1`$9%11@{h$y%6GGhx$+D6{b z?|t`)@*Z9)cZ(3c38C1BZQ@-b6yIt=y+&upTg7#>3AZvkc3vZ|vcivRi+G0_SVVlF zlOkE!pwqq&$xCTnMQsd^MiK$!Fbc)WogkQ78$CYpz)SG&V*IzUpl-!vS=q?xX{ksA z`*=2!bvpunbUI%cta!Ozmt2p=DB(kJ&uH01Zep+zvsuN$T9b#E*~QlLGE-WU2U&yZ zhN7BIhFdmi*+gmbtWM`~^wtPlbedqtibdxHdV+-w{=dXXyd_5BbukjJiAC{MF%qv> zZuVj-w0ApkX^ErtHxL!8&$5BSPE9i8jJI{#DqBlkOKgypAA~7;MfsgDX%A*iWwfMv zVlAE0`@R*`--z-nQGO}PFL)`xZ~4xV;v`6(ODylZDYq>?i1a)GdIUh`AC;WMWf{rT7 zhjz1EkpVa?YLe@=sA;Y7G;Q+zC2zkxw$-p)pL0UtL5?xRu%1j zUdmmpf#{Uh?(Rtz=Ab9GJX2P>=6dXC*ohWqZy+~KfTSMz3Wa6;gynsO<$Z+ZM+u92 zSr+%?GRXnOG-Ux)?tyxDv=#&uttrbca2ww{SE|OFB^1QjX^fa|4C^z5Wv7aAvM5gy z<#UBoxK=oIyHwM8UFQ2L&8^!YrTi$>a;_0 zn`Z=A&qK5=%Urjwp<9!Fq*l2{c7^xQ-OluweHNipR#vk$(j&LI1@=#y87;**g<~Tw z#uAT-S=@a_;JeG3$B$#)yWc_Ek%TOF_Q$-DeKakyPuqH|N-YC>Uo$z3EP0^VC z>)ygoMo6VaQ_5=2YN*1qkEp+)y38M~sIHGiD=QnSr$?)&)SuIE*6jTJ{3+22+(!Kf z9MKBY)0>Hrf}Z(PYU^rfsOqQ8DlN$GmCqUqrq;(wVil!R>Y_-q>!WDvm7m|Uwrra8 zeX|a2=lhrWFY;fauJEt&zv2JJ|Cj$#^%?bF>P^8rgLeh*32q4*!AFBn2OkUm9eg5q zZ|LpdN5L+Ai}i_h03|)_=YKCjScmO6XnfU*lirzs}ae z{15rJ`XBah^KbX>@bC1$?0?0-8y3Fp|J?tD|0`zcCF-T>)*ezks^zFps;FU#GU`)KaA+!c8%^KQ*spZ9#;3wbZ*y_EM=-q(5G=KYd) zQD9l{rr^!NmBCwrtAlHT>w>oi*9UJ4-VxluklO_8?hW1-+#I|=_yACR5IAlPJ{)`m zXl?_VPXu=X)n|gw2A>PQ5PUKCa`2Vl?%=Dz*Me^Z-weJLd^`9~@ZI2h!S{n70P#